From c03db74c4cc0ef6771e4420a93720437b927bdba Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:13:02 -0600 Subject: [PATCH 0001/1891] handle colon in .tool-versions (#7) Fixes #3 --- src/config/config_file/tool_versions.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 0d7aff929..02bc05e97 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -78,6 +78,11 @@ impl ToolVersions { let (line, post) = line.split_once('#').unwrap_or((line, "")); let mut parts = line.split_whitespace(); if let Some(plugin) = parts.next() { + // 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 tvp = ToolVersionPlugin { versions: parts.map(|v| v.to_string()).collect(), post: match post { @@ -160,7 +165,7 @@ pub(crate) mod tests { use std::fmt::Debug; use indoc::indoc; - use insta::assert_display_snapshot; + use insta::{assert_display_snapshot, assert_snapshot}; use pretty_assertions::assert_eq; use crate::dirs; @@ -193,6 +198,17 @@ pub(crate) mod tests { assert_eq!(tv.dump(), orig); } + #[test] + fn test_parse_colon() { + let orig = indoc! {" + ruby: 3.0.5 + "}; + let tv = ToolVersions::parse_str(orig).unwrap(); + assert_snapshot!(tv.dump(), @r###" + ruby 3.0.5 + "###); + } + #[derive(Debug)] pub struct MockToolVersions { pub path: PathBuf, From 3d5c172db0753d93a8d84a3d4bbe97a615bda0b3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:02:30 -0600 Subject: [PATCH 0002/1891] show better error message on url parse failure (#6) --- src/cli/mod.rs | 8 ++++ src/cli/plugins/install.rs | 46 +++++++++++++++---- ...all__test__plugin_install_invalid_url.snap | 5 ++ src/shorthand_repository.rs | 3 +- 4 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_invalid_url.snap diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 8f7833600..18ab55598 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -168,6 +168,7 @@ const AFTER_HELP: &str = indoc! {" mod test { use crate::config::settings::MissingRuntimeBehavior::AutoInstall; use crate::config::settings::Settings; + use crate::output::OutputStream; use crate::plugins::{Plugin, PluginName}; use super::*; @@ -195,4 +196,11 @@ mod test { }; Plugin::load_ensure_installed(&PluginName::from(name), &settings).unwrap(); } + + pub fn grep<'a>(output: &'a OutputStream, pattern: &str) -> Option<&'a str> { + output + .content + .split('\n') + .find(|line| line.contains(pattern)) + } } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 3360eb08f..f56796bef 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use color_eyre::eyre::{eyre, Result}; use url::Url; use crate::cli::command::Command; @@ -69,14 +69,14 @@ fn get_name_and_url( } fn get_name_from_url(url: &str) -> Result { - let name = Url::parse(url)? - .path_segments() - .unwrap() - .last() - .unwrap() - .to_string(); - - Ok(name.strip_prefix("asdf-").unwrap_or(&name).to_string()) + if let Ok(url) = Url::parse(url) { + if let Some(segments) = url.path_segments() { + let last = segments.last().unwrap_or_default(); + let name = last.strip_prefix("asdf-").unwrap_or(last); + return Ok(name.to_string()); + } + } + Err(eyre!("could not infer plugin name from url: {}", url)) } const AFTER_LONG_HELP: &str = r#" @@ -94,10 +94,38 @@ EXAMPLES: #[cfg(test)] mod test { + use insta::assert_display_snapshot; + use pretty_assertions::assert_str_eq; + use crate::assert_cli; + use crate::cli::test::{cli_run, grep}; + use crate::output::Output; #[test] fn test_plugin_install() { assert_cli!("plugin", "add", "nodejs"); } + + #[test] + fn test_plugin_install_url() { + assert_cli!( + "plugin", + "add", + "-f", + "https://github.com/jdxcode/asdf-nodejs" + ); + let Output { stdout, .. } = assert_cli!("plugin", "--urls"); + let line = grep(&stdout, "nodejs").unwrap(); + assert_str_eq!( + line, + "nodejs https://github.com/asdf-vm/asdf-nodejs.git" + ); + } + + #[test] + fn test_plugin_install_invalid_url() { + let args = ["rtx", "plugin", "add", "ruby:"].map(String::from).into(); + let err = cli_run(&args).unwrap_err(); + assert_display_snapshot!(err); + } } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_invalid_url.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_invalid_url.snap new file mode 100644 index 000000000..55ae85453 --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_invalid_url.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/plugins/install.rs +expression: err +--- +could not infer plugin name from url: ruby: diff --git a/src/shorthand_repository.rs b/src/shorthand_repository.rs index c474bffe1..952662131 100644 --- a/src/shorthand_repository.rs +++ b/src/shorthand_repository.rs @@ -65,11 +65,10 @@ impl ShorthandRepo { pub fn create_or_update(&self) -> Result<()> { self.ensure_created()?; if !self.changed_recently()? { - eprint!("rtx: Updating shorthand plugins repository..."); + eprintln!("rtx: Updating shorthand plugins repository..."); let git = self.get_git(); git.update(None)?; file::touch_dir(&self.repo_dir)?; - eprintln!(" done"); } Ok(()) From de6751a864372bde4434aab16d6f3cce3d89af7c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:46:56 -0600 Subject: [PATCH 0003/1891] fix legacy file cache (#15) before this would read the legacy file instead of the cache file. That was fine when I was using .node-version (since they had the same content) but Gemfiles do not --- src/cli/mod.rs | 2 +- src/plugins.rs | 24 +++++++++++++++++++++++- src/test.rs | 3 +++ test/fixtures/Gemfile | 6 ++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/Gemfile diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 18ab55598..9b0688873 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -165,7 +165,7 @@ const AFTER_HELP: &str = indoc! {" "}; #[cfg(test)] -mod test { +pub mod test { use crate::config::settings::MissingRuntimeBehavior::AutoInstall; use crate::config::settings::Settings; use crate::output::OutputStream; diff --git a/src/plugins.rs b/src/plugins.rs index e6cad2897..fcdc51c4c 100644 --- a/src/plugins.rs +++ b/src/plugins.rs @@ -423,7 +423,7 @@ impl Plugin { return Ok(None); } - Ok(Some(fs::read_to_string(legacy_file)?.trim().into())) + Ok(Some(fs::read_to_string(fp)?.trim().into())) } fn legacy_cache_file_path(&self, legacy_file: &Path) -> PathBuf { @@ -501,3 +501,25 @@ fn display_path(path: &Path) -> String { let home = dirs::HOME.to_string_lossy(); path.to_string_lossy().replace(home.as_ref(), "~") } + +#[cfg(test)] +mod test { + use pretty_assertions::assert_str_eq; + + use crate::assert_cli; + + use super::*; + + #[test] + fn test_legacy_gemfile() { + assert_cli!("plugin", "add", "ruby"); + let plugin = Plugin::load(&PluginName::from("ruby")).unwrap(); + let gemfile = env::HOME.join("fixtures/Gemfile"); + let version = plugin.parse_legacy_file(&gemfile).unwrap(); + assert_str_eq!(version, "3.0.5"); + + // do it again to test the cache + let version = plugin.parse_legacy_file(&gemfile).unwrap(); + assert_str_eq!(version, "3.0.5"); + } +} diff --git a/src/test.rs b/src/test.rs index f13910741..66295bee9 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,9 +1,12 @@ +use std::fs; + use crate::cmd; #[ctor::ctor] fn init() { std::env::set_var("NO_COLOR", "1"); env_logger::init(); + let _ = fs::remove_dir_all("test/data/legacy_cache"); if let Err(err) = cmd!( "git", "checkout", diff --git a/test/fixtures/Gemfile b/test/fixtures/Gemfile new file mode 100644 index 000000000..d4f092c28 --- /dev/null +++ b/test/fixtures/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +ruby "3.0.5" + +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } From beeea50b7c96b77faddc9fb67cab560a3c1d62ba Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:47:07 -0600 Subject: [PATCH 0004/1891] fix env on directory change (#13) Fixes #12 --- e2e/gopath/.tool-versions | 1 + e2e/gopath/18/.tool-versions | 1 + e2e/gopath/test_gopath | 20 +++++++ src/cli/env.rs | 8 +++ src/cli/hook_env.rs | 44 ++-------------- src/env.rs | 18 +++++++ src/env_diff.rs | 52 ++++++++++++++----- src/hook_env.rs | 48 +++++++++++++++++ src/runtimes.rs | 4 +- ...tx__env_diff__tests__from_bash_script.snap | 15 +++--- test/fixtures/exec-env | 4 +- 11 files changed, 155 insertions(+), 60 deletions(-) create mode 100644 e2e/gopath/.tool-versions create mode 100644 e2e/gopath/18/.tool-versions create mode 100755 e2e/gopath/test_gopath diff --git a/e2e/gopath/.tool-versions b/e2e/gopath/.tool-versions new file mode 100644 index 000000000..58b446162 --- /dev/null +++ b/e2e/gopath/.tool-versions @@ -0,0 +1 @@ +golang 1.19.5 diff --git a/e2e/gopath/18/.tool-versions b/e2e/gopath/18/.tool-versions new file mode 100644 index 000000000..bb46032ec --- /dev/null +++ b/e2e/gopath/18/.tool-versions @@ -0,0 +1 @@ +golang 1.18.10 diff --git a/e2e/gopath/test_gopath b/e2e/gopath/test_gopath new file mode 100755 index 000000000..5e20b3e98 --- /dev/null +++ b/e2e/gopath/test_gopath @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e +eval "$(rtx activate -s bash)" +_rtx_hook + +assert_gopath() { + local expected="$1" + if [[ "$GOPATH" != "$expected" ]]; then + echo "Invalid GOPATH: $GOPATH, expected: $expected" + exit 1 + fi +} + +rtx i golang@1.18.10 golang@1.19.5 && _rtx_hook +assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" +cd 18 && _rtx_hook +assert_gopath "$RTX_DATA_DIR/installs/golang/1.18.10/packages" +cd .. && _rtx_hook +assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" diff --git a/src/cli/env.rs b/src/cli/env.rs index e5305207b..0839c6aae 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -94,4 +94,12 @@ mod test { .as_ref() )); } + + #[test] + fn test_env_golang() { + assert_cli!("plugin", "add", "golang"); + assert_cli!("install", "golang"); + let Output { stdout, .. } = assert_cli!("env", "golang", "-s", "bash"); + assert!(stdout.content.contains("GOROOT=")); + } } diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 1a7d7b1c9..f72481abf 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::env; use color_eyre::eyre::Result; @@ -10,7 +9,7 @@ use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::hook_env::HookEnvWatches; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -use crate::{dirs, hook_env}; +use crate::{dirs, env, hook_env}; /// [internal] called by activate hook to update env vars directory change #[derive(Debug, clap::Args)] @@ -28,14 +27,14 @@ impl Command for HookEnv { config.settings.missing_runtime_behavior = Ignore; config.ensure_installed()?; - let current_env = self.clear_old_env(env::vars().collect(), out)?; + self.clear_old_env(out); let mut env: HashMap = config .env()? .iter() .map(|(k, v)| (k.to_string_lossy().into(), v.to_string_lossy().into())) .collect(); env.insert("__RTX_DIR".into(), dirs::CURRENT.to_string_lossy().into()); - let diff = EnvDiff::new(¤t_env, &env); + let diff = EnvDiff::new(&env::PRISTINE_ENV, &env); let mut patches = diff.to_patches(); patches.push(EnvDiffOperation::Add( "__RTX_DIFF".into(), @@ -81,46 +80,13 @@ impl HookEnv { output } - fn clear_old_env( - &self, - env: HashMap, - out: &mut Output, - ) -> Result> { - let patches = get_env_diff(&env)?.reverse().to_patches(); + fn clear_old_env(&self, out: &mut Output) { + let patches = env::__RTX_DIFF.reverse().to_patches(); let output = self.build_env_commands(&patches); out.stdout.write(output); - - Ok(apply_patches(&env, &patches)) - } -} - -fn get_env_diff(env: &HashMap) -> Result { - let json = env.get("__RTX_DIFF").cloned(); - match json { - Some(json) => Ok(EnvDiff::deserialize(&json)?), - None => Ok(EnvDiff::default()), } } -fn apply_patches( - env: &HashMap, - patches: &EnvDiffPatches, -) -> HashMap { - let mut new_env = env.clone(); - for patch in patches { - match patch { - EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { - new_env.insert(k.into(), v.into()); - } - EnvDiffOperation::Remove(k) => { - new_env.remove(k); - } - } - } - - new_env -} - #[cfg(test)] mod test { use crate::assert_cli; diff --git a/src/env.rs b/src/env.rs index 1f8a4a8c3..e2074e999 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,9 +1,13 @@ +use std::collections::HashMap; pub use std::env::*; use std::ffi::OsString; use std::path::PathBuf; use lazy_static::lazy_static; +use crate::env_diff::EnvDiff; +use crate::hook_env::get_pristine_env; + lazy_static! { pub static ref ARGS: Vec = args().collect(); pub static ref HOME: PathBuf = if cfg!(test) { @@ -72,6 +76,9 @@ lazy_static! { var("RTX_MISSING_RUNTIME_BEHAVIOR").ok() }; pub static ref __RTX_DIR: Option = var_os("__RTX_DIR").map(PathBuf::from); + pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); + pub static ref PRISTINE_ENV: HashMap = + get_pristine_env(&__RTX_DIFF, vars().collect()); pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String = if cfg!(test) { ".tool-versions".into() } else { @@ -79,6 +86,17 @@ lazy_static! { }; } +fn get_env_diff() -> EnvDiff { + let env = vars().collect::>(); + match env.get("__RTX_DIFF") { + Some(raw) => EnvDiff::deserialize(raw).unwrap_or_else(|err| { + warn!("Failed to deserialize __RTX_DIFF: {}", err); + EnvDiff::default() + }), + None => EnvDiff::default(), + } +} + fn var_is_true(key: &str) -> bool { match var(key) { Ok(v) => v == "true" || v == "1", diff --git a/src/env_diff.rs b/src/env_diff.rs index 15de0ce7a..a79c1a53f 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::fmt::Debug; use std::io::prelude::*; use std::path::Path; @@ -7,11 +8,12 @@ use color_eyre::eyre::Result; use flate2::write::GzDecoder; use flate2::write::GzEncoder; use flate2::Compression; +use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; use crate::{cmd, env}; -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Default, Serialize, Deserialize)] pub struct EnvDiff { #[serde(default)] pub old: HashMap, @@ -50,7 +52,7 @@ impl EnvDiff { } pub fn from_bash_script(script: &Path, env: HashMap) -> Result { - let mut cmd = cmd!( + let out = cmd!( "bash", "-c", indoc::formatdoc! {" @@ -58,27 +60,30 @@ impl EnvDiff { . {script} env ", script = script.display()} - ); - for (k, v) in env.iter() { - cmd = cmd.env(k, v); - } - let out = cmd.read()?; + ) + .full_env(&env) + .read()?; let mut additions = HashMap::new(); for line in out.lines() { let (k, v) = line.split_once('=').unwrap_or_default(); - if k == "_" || k == "SHLVL" || k == "PATH" || env.contains_key(k) { + if k == "_" || k == "SHLVL" || k == "PATH" { continue; } + if let Some(orig) = env.get(k) { + if v == orig { + continue; + } + } additions.insert(k.into(), v.into()); } Ok(Self::new(&env::vars().collect(), &additions)) } - pub fn deserialize(json: &str) -> Result { + pub fn deserialize(raw: &str) -> Result { let mut writer = Vec::new(); let mut decoder = GzDecoder::new(writer); - let bytes = BASE64_STANDARD_NO_PAD.decode(json)?; + let bytes = BASE64_STANDARD_NO_PAD.decode(raw)?; decoder.write_all(&bytes[..])?; writer = decoder.finish()?; Ok(rmp_serde::from_slice(&writer[..])?) @@ -117,6 +122,22 @@ impl EnvDiff { } } +impl Debug for EnvDiff { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let print_sorted = |hashmap: &HashMap| { + hashmap + .iter() + .map(|(k, v)| format!("{k}={v}")) + .sorted() + .collect::>() + }; + f.debug_struct("EnvDiff") + .field("old", &print_sorted(&self.old)) + .field("new", &print_sorted(&self.new)) + .finish() + } +} + #[cfg(test)] mod tests { use insta::assert_debug_snapshot; @@ -191,7 +212,14 @@ mod tests { #[test] fn test_from_bash_script() { let path = dirs::HOME.join("fixtures/exec-env"); - let ed = EnvDiff::from_bash_script(path.as_path(), HashMap::new()).unwrap(); - assert_debug_snapshot!(ed.to_patches()); + let orig = HashMap::from( + [ + ("UNMODIFIED_VAR", "unmodified"), + ("MODIFIED_VAR", "original"), + ] + .map(|(k, v)| (k.into(), v.into())), + ); + let ed = EnvDiff::from_bash_script(path.as_path(), orig).unwrap(); + assert_debug_snapshot!(ed); } } diff --git a/src/hook_env.rs b/src/hook_env.rs index 320debbc6..cd33a9fff 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -9,6 +9,7 @@ use flate2::write::GzDecoder; use flate2::write::GzEncoder; use flate2::Compression; +use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being @@ -26,6 +27,16 @@ pub fn should_exit_early(current_env: HashMap) -> bool { true } +/// this returns the environment as if __RTX_DIFF was reversed +/// putting the shell back into a state before hook-env was run +pub fn get_pristine_env( + rtx_diff: &EnvDiff, + orig_env: HashMap, +) -> HashMap { + let patches = rtx_diff.reverse().to_patches(); + apply_patches(&orig_env, &patches) +} + fn has_rf_path_changed(env: &HashMap) -> bool { if let Some(prev) = env.get("__RTX_DIR").map(PathBuf::from) { if prev == dirs::CURRENT.as_path() { @@ -70,6 +81,27 @@ pub fn deserialize_watches(raw: String) -> Result { Ok(rmp_serde::from_slice(&writer[..])?) } +fn apply_patches( + env: &HashMap, + patches: &EnvDiffPatches, +) -> HashMap { + let mut new_env = env.clone(); + for patch in patches { + match patch { + EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { + eprintln!("adding {k}"); + new_env.insert(k.into(), v.into()); + } + EnvDiffOperation::Remove(k) => { + eprintln!("removing {k}"); + new_env.remove(k); + } + } + } + + new_env +} + #[cfg(test)] mod test { use std::time::UNIX_EPOCH; @@ -122,4 +154,20 @@ mod test { &UNIX_EPOCH ); } + + #[test] + fn test_apply_patches() { + let mut env = HashMap::new(); + env.insert("foo".into(), "bar".into()); + env.insert("baz".into(), "qux".into()); + let patches = vec![ + EnvDiffOperation::Add("foo".into(), "bar".into()), + EnvDiffOperation::Change("baz".into(), "qux".into()), + EnvDiffOperation::Remove("quux".into()), + ]; + let new_env = apply_patches(&env, &patches); + assert_eq!(new_env.len(), 2); + assert_eq!(new_env.get("foo").unwrap(), "bar"); + assert_eq!(new_env.get("baz").unwrap(), "qux"); + } } diff --git a/src/runtimes.rs b/src/runtimes.rs index f39c3bdba..40ea21d8a 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -203,7 +203,9 @@ impl RuntimeVersion { if !self.is_installed() || !script.exists() { return Ok(HashMap::new()); } - let ed = EnvDiff::from_bash_script(&script, self.script_env())?; + let mut env: HashMap = env::PRISTINE_ENV.clone(); + env.extend(self.script_env()); + let ed = EnvDiff::from_bash_script(&script, env)?; let env = ed .to_patches() .into_iter() diff --git a/src/snapshots/rtx__env_diff__tests__from_bash_script.snap b/src/snapshots/rtx__env_diff__tests__from_bash_script.snap index 3df7ad165..450f20c59 100644 --- a/src/snapshots/rtx__env_diff__tests__from_bash_script.snap +++ b/src/snapshots/rtx__env_diff__tests__from_bash_script.snap @@ -1,10 +1,11 @@ --- source: src/env_diff.rs -expression: ed.to_patches() +expression: ed --- -[ - Add( - "CUSTOM_ENV", - "rtx_env", - ), -] +EnvDiff { + old: [], + new: [ + "ADDED_VAR=added", + "MODIFIED_VAR=modified", + ], +} diff --git a/test/fixtures/exec-env b/test/fixtures/exec-env index 654b6ede7..4d81e926a 100644 --- a/test/fixtures/exec-env +++ b/test/fixtures/exec-env @@ -1,3 +1,5 @@ #!/usr/bin/env bash -export CUSTOM_ENV=rtx_env +export UNMODIFIED_VAR="unmodified" +export MODIFIED_VAR="modified" +export ADDED_VAR="added" From 22324d8337e0a56add8d3d70aaa2d79e03e9c515 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:47:24 -0600 Subject: [PATCH 0005/1891] fix `rtx latest ruby` (#14) This was showing "truffleruby-" before --- src/cli/latest.rs | 11 ++++++++--- src/cli/snapshots/rtx__cli__local__test__local-4.snap | 9 --------- src/cli/snapshots/rtx__cli__local__test__local-5.snap | 9 --------- 3 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 src/cli/snapshots/rtx__cli__local__test__local-4.snap delete mode 100644 src/cli/snapshots/rtx__cli__local__test__local-5.snap diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 106f606c0..1c6e6006d 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -26,7 +26,7 @@ impl Command for Latest { let prefix = match self.runtime.version.as_str() { "latest" => match self.asdf_version { Some(version) => version, - None => "".to_string(), + None => "latest".to_string(), }, v => v.into(), }; @@ -58,15 +58,20 @@ mod test { #[test] fn test_latest() { - std::env::set_var("NO_COLOR", "1"); assert_cli!("plugins", "install", "nodejs"); let Output { stdout, .. } = assert_cli!("latest", "nodejs@12"); assert_display_snapshot!(stdout.content); } + #[test] + fn test_latest_ruby() { + assert_cli!("plugins", "install", "ruby"); + let Output { stdout, .. } = assert_cli!("latest", "ruby"); + assert!(stdout.content.starts_with("3.")); + } + #[test] fn test_latest_asdf_format() { - std::env::set_var("NO_COLOR", "1"); let Output { stdout, .. } = assert_cli!("latest", "nodejs", "12"); assert_display_snapshot!(stdout.content); } diff --git a/src/cli/snapshots/rtx__cli__local__test__local-4.snap b/src/cli/snapshots/rtx__cli__local__test__local-4.snap deleted file mode 100644 index d1d937051..000000000 --- a/src/cli/snapshots/rtx__cli__local__test__local-4.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: src/cli/local.rs -expression: stdout.content ---- -#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 -shfmt 2 # test comment -#nodejs 18.13.0 - diff --git a/src/cli/snapshots/rtx__cli__local__test__local-5.snap b/src/cli/snapshots/rtx__cli__local__test__local-5.snap deleted file mode 100644 index 4c06a4550..000000000 --- a/src/cli/snapshots/rtx__cli__local__test__local-5.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: src/cli/local.rs -expression: stdout.content ---- --> jq 1.6 (set by /Users/jdx/src/rtx/test/.tool-versions) - nodejs 18.0.0 (missing) (set by /Users/jdx/src/rtx/test/cwd/.node-version) --> shellcheck 0.9.0 (set by /Users/jdx/src/rtx/test/cwd/.tool-versions) --> shfmt 2.6.4 (set by /Users/jdx/src/rtx/test/cwd/.tool-versions) - From eef7cf5ad9563df997bc41651364a706556c8749 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 14:15:51 -0600 Subject: [PATCH 0006/1891] rename aliases -> alias (what it should have been) (#17) --- README.md | 2 +- src/cli/alias/ls.rs | 2 +- src/config/config_file/rtxrc.rs | 2 +- test/config/config.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c47fc892a..76ee68fdc 100644 --- a/README.md +++ b/README.md @@ -394,7 +394,7 @@ These can come from user config or from plugins in `bin/list-aliases`. For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: - [aliases.nodejs] + [alias.nodejs] lts = "18.0.0" Usage: ls [OPTIONS] diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 4ba71f75b..1d09bc52e 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -12,7 +12,7 @@ use crate::plugins::PluginName; /// /// For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: /// -/// [aliases.nodejs] +/// [alias.nodejs] /// lts = "18.0.0" #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 71c8b021c..b9dd0715e 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -100,7 +100,7 @@ impl RTXFile { "disable_plugin_short_name_repository" => { self.settings.disable_plugin_short_name_repository = Some(self.parse_bool(k, v)?) } - "aliases" => self.settings.aliases = Some(self.parse_aliases(v)?), + "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} _ => self.parse_plugin(k, v)?, }; diff --git a/test/config/config.toml b/test/config/config.toml index 0ed69203e..af1749ff1 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -5,5 +5,5 @@ disable_plugin_short_name_repository= false plugin_repository_last_check_duration = 20 plugin_autoupdate_last_check_duration = 20 -[aliases.shfmt] +[alias.shfmt] "my/alias" = '3.0' From bf3acf10347dec380d825acb434afd4a96d5b76f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 14:34:26 -0600 Subject: [PATCH 0007/1891] only add rtx to PATH if it is not already on it (#16) --- ...tx__cli__activate__test__activate_zsh.snap | 2 +- src/shell/bash.rs | 21 ++++++--- src/shell/fish.rs | 19 +++++--- src/shell/mod.rs | 10 ++++- .../rtx__shell__bash__tests__hook_init.snap | 6 +-- .../rtx__shell__fish__tests__hook_init.snap | 11 +++-- .../rtx__shell__zsh__tests__hook_init.snap | 6 +-- src/shell/zsh.rs | 43 +++++++++++-------- 8 files changed, 71 insertions(+), 47 deletions(-) diff --git a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap index 19b299c84..0b23fbdfe 100644 --- a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap @@ -2,7 +2,7 @@ source: src/cli/activate.rs expression: stdout.content --- -export PATH=":$PATH"; +export PATH=":$PATH" _rtx_hook() { trap -- '' SIGINT; eval "$("rtx" hook-env -s zsh)"; diff --git a/src/shell/bash.rs b/src/shell/bash.rs index f30f037ec..23f8eea18 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -1,16 +1,21 @@ -use crate::shell::Shell; -use indoc::formatdoc; use std::path::Path; +use indoc::formatdoc; + +use crate::shell::{is_dir_in_path, Shell}; + #[derive(Default)] pub struct Bash {} impl Shell for Bash { fn activate(&self, exe: &Path) -> String { - let dir = exe.parent().unwrap().display(); + let dir = exe.parent().unwrap(); let exe = exe.display(); - formatdoc! {r#" - export PATH="{dir}:$PATH"; + let mut out = String::new(); + if !is_dir_in_path(dir) { + out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); + } + out.push_str(&formatdoc! {r#" _rtx_hook() {{ local previous_exit_status=$?; trap -- '' SIGINT; @@ -21,7 +26,9 @@ impl Shell for Bash { if ! [[ "${{PROMPT_COMMAND:-}}" =~ _rtx_hook ]]; then PROMPT_COMMAND="_rtx_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" fi - "#} + "#}); + + out } fn deactivate(&self) -> String { @@ -49,7 +56,7 @@ mod tests { #[test] fn test_hook_init() { - insta::assert_snapshot!(Bash::default().activate(Path::new("rtx"))); + insta::assert_snapshot!(Bash::default().activate(Path::new("/some/dir/rtx"))); } #[test] diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 3ed5610e0..53b0b552d 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -2,22 +2,25 @@ use std::path::Path; use indoc::formatdoc; -use crate::shell::Shell; +use crate::shell::{is_dir_in_path, Shell}; #[derive(Default)] pub struct Fish {} impl Shell for Fish { fn activate(&self, exe: &Path) -> String { - let dir = exe.parent().unwrap().display(); + let dir = exe.parent().unwrap(); let exe = exe.display(); let description = "'Update rtx environment when changing directories'"; + let mut out = String::new(); + + if !is_dir_in_path(dir) { + out.push_str(&format!("fish_add_path -g {dir}\n", dir = dir.display())); + } // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_fish.go#L14-L36 - formatdoc! {r#" - fish_add_path -g {dir}; - + out.push_str(&formatdoc! {r#" function __rtx_env_eval --on-event fish_prompt --description {description}; {exe} hook-env -s fish | source; @@ -41,7 +44,9 @@ impl Shell for Fish { functions --erase __rtx_cd_hook; end; - "#} + "#}); + + out } fn deactivate(&self) -> String { @@ -71,7 +76,7 @@ mod tests { #[test] fn test_hook_init() { - insta::assert_snapshot!(Fish::default().activate(Path::new("rtx"))); + insta::assert_snapshot!(Fish::default().activate(Path::new("/some/dir/rtx"))); } #[test] diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 2f03a4525..04c88f207 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,6 +1,9 @@ use std::fmt::{Display, Formatter}; +use std::ops::Deref; use std::path::Path; +use crate::env; + mod bash; mod fish; mod zsh; @@ -14,7 +17,7 @@ pub enum ShellType { impl ShellType { pub fn load() -> Option { - let shell = std::env::var("SHELL").ok()?; + let shell = env::var("SHELL").ok()?; if shell.ends_with("bash") { Some(ShellType::Bash) } else if shell.ends_with("fish") { @@ -52,3 +55,8 @@ pub fn get_shell(shell: Option) -> Box { _ => panic!("no shell provided, use `--shell=zsh`"), } } + +pub fn is_dir_in_path(dir: &Path) -> bool { + let dir = dir.canonicalize().unwrap_or(dir.to_path_buf()); + env::split_paths(env::PATH.deref()).any(|p| p.canonicalize().unwrap_or(p) == dir) +} diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 6df416c31..948aded5c 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -1,12 +1,12 @@ --- source: src/shell/bash.rs -expression: "Bash::default().activate(Path::new(\"rtx\"))" +expression: "Bash::default().activate(Path::new(\"/some/dir/rtx\"))" --- -export PATH=":$PATH"; +export PATH="/some/dir:$PATH" _rtx_hook() { local previous_exit_status=$?; trap -- '' SIGINT; - eval "$("rtx" hook-env -s bash)"; + eval "$("/some/dir/rtx" hook-env -s bash)"; trap - SIGINT; return $previous_exit_status; }; diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 8e5c5eecd..7d3f51593 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -1,18 +1,17 @@ --- source: src/shell/fish.rs -expression: "Fish::default().activate(Path::new(\"rtx\"))" +expression: "Fish::default().activate(Path::new(\"/some/dir/rtx\"))" --- -fish_add_path -g ; - +fish_add_path -g /some/dir function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; - rtx hook-env -s fish | source; + /some/dir/rtx hook-env -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - rtx hook-env -s fish | source; + /some/dir/rtx hook-env -s fish | source; end; end; end; @@ -21,7 +20,7 @@ end; function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; if set -q __rtx_env_again; set -e __rtx_env_again; - rtx hook-env -s fish | source; + /some/dir/rtx hook-env -s fish | source; echo; end; diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 85c6e1913..8e7ca596c 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -1,11 +1,11 @@ --- source: src/shell/zsh.rs -expression: "Zsh::default().activate(Path::new(\"rtx\"))" +expression: "Zsh::default().activate(Path::new(\"/some/dir/rtx\"))" --- -export PATH=":$PATH"; +export PATH="/some/dir:$PATH" _rtx_hook() { trap -- '' SIGINT; - eval "$("rtx" hook-env -s zsh)"; + eval "$("/some/dir/rtx" hook-env -s zsh)"; trap - SIGINT; } typeset -ag precmd_functions; diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index c0a70e32d..8af76655a 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -3,34 +3,39 @@ use std::path::Path; use indoc::formatdoc; use crate::shell::bash::Bash; -use crate::shell::Shell; +use crate::shell::{is_dir_in_path, Shell}; #[derive(Default)] pub struct Zsh {} impl Shell for Zsh { fn activate(&self, exe: &Path) -> String { - let dir = exe.parent().unwrap().display(); + let dir = exe.parent().unwrap(); let exe = exe.display(); + let mut out = String::new(); // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_zsh.go#L10-L22 - formatdoc! {r#" - export PATH="{dir}:$PATH"; - _rtx_hook() {{ - trap -- '' SIGINT; - eval "$("{exe}" hook-env -s zsh)"; - trap - SIGINT; - }} - typeset -ag precmd_functions; - if [[ -z "${{precmd_functions[(r)_rtx_hook]+1}}" ]]; then - precmd_functions=( _rtx_hook ${{precmd_functions[@]}} ) - fi - typeset -ag chpwd_functions; - if [[ -z "${{chpwd_functions[(r)_rtx_hook]+1}}" ]]; then - chpwd_functions=( _rtx_hook ${{chpwd_functions[@]}} ) - fi - "#} + if !is_dir_in_path(dir) { + out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); + } + out.push_str(&formatdoc! {r#" + _rtx_hook() {{ + trap -- '' SIGINT; + eval "$("{exe}" hook-env -s zsh)"; + trap - SIGINT; + }} + typeset -ag precmd_functions; + if [[ -z "${{precmd_functions[(r)_rtx_hook]+1}}" ]]; then + precmd_functions=( _rtx_hook ${{precmd_functions[@]}} ) + fi + typeset -ag chpwd_functions; + if [[ -z "${{chpwd_functions[(r)_rtx_hook]+1}}" ]]; then + chpwd_functions=( _rtx_hook ${{chpwd_functions[@]}} ) + fi + "#}); + + out } fn deactivate(&self) -> String { @@ -54,7 +59,7 @@ mod tests { #[test] fn test_hook_init() { - insta::assert_snapshot!(Zsh::default().activate(Path::new("rtx"))); + insta::assert_snapshot!(Zsh::default().activate(Path::new("/some/dir/rtx"))); } #[test] From 86fd81040a6b8ab7b6e7d21e10e40eafd8afdda0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:53:54 -0600 Subject: [PATCH 0008/1891] settings management (#18) --- .github/workflows/rtx.yml | 53 +++++-- README.md | 145 +++++++++++++++++- src/cli/alias/ls.rs | 2 +- src/cli/local.rs | 8 +- src/cli/mod.rs | 11 ++ src/cli/render_help.rs | 54 ++++++- src/cli/settings/get.rs | 58 +++++++ src/cli/settings/ls.rs | 47 ++++++ src/cli/settings/mod.rs | 45 ++++++ src/cli/settings/set.rs | 99 ++++++++++++ ..._cli__settings__ls__test__settings_ls.snap | 11 ++ ...__settings__set__test__settings_set-2.snap | 11 ++ ...li__settings__set__test__settings_set.snap | 11 ++ src/cli/settings/unset.rs | 68 ++++++++ src/config/config_file/rtxrc.rs | 144 +++++++++++++++++ src/config/mod.rs | 22 +-- src/config/settings.rs | 54 ++++++- src/test.rs | 29 +++- 18 files changed, 830 insertions(+), 42 deletions(-) create mode 100644 src/cli/settings/get.rs create mode 100644 src/cli/settings/ls.rs create mode 100644 src/cli/settings/mod.rs create mode 100644 src/cli/settings/set.rs create mode 100644 src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap create mode 100644 src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap create mode 100644 src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap create mode 100644 src/cli/settings/unset.rs diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index c16a2131b..745a01e54 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -17,12 +17,19 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - - uses: taiki-e/install-action@just - - uses: fish-actions/install-fish@v1 - - name: Install zsh - run: sudo apt-get update; sudo apt-get install zsh - - run: just test-unit lint + - name: Rust Cache + uses: Swatinem/rust-cache@v2 + - name: Install just + uses: taiki-e/install-action@just + - name: just test-unit + uses: nick-fields/retry@v2 + env: + GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + with: + timeout_minutes: 10 + max_attempts: 3 + command: just test-unit + - run: just lint coverage: runs-on: ubuntu-latest @@ -32,10 +39,18 @@ jobs: options: --security-opt seccomp=unconfined steps: - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - - uses: taiki-e/install-action@just + - name: Rust Cache + uses: Swatinem/rust-cache@v2 + - name: Install just + uses: taiki-e/install-action@just - name: Generate code coverage - run: just test-coverage + uses: nick-fields/retry@v2 + env: + GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + with: + timeout_minutes: 10 + max_attempts: 3 + command: just test-coverage - name: Upload to codecov.io uses: codecov/codecov-action@v3 with: @@ -57,7 +72,8 @@ jobs: toolchain: stable target: ${{matrix.target}} override: true - - uses: Swatinem/rust-cache@v2 + - name: Rust Cache + uses: Swatinem/rust-cache@v2 with: { key: "${{matrix.target}}" } - uses: actions-rs/cargo@v1 with: @@ -89,7 +105,8 @@ jobs: toolchain: stable target: ${{matrix.target}} override: true - - uses: Swatinem/rust-cache@v2 + - name: Rust Cache + uses: Swatinem/rust-cache@v2 with: { key: "${{matrix.target}}" } - run: cargo build --release --target ${{matrix.target}} - run: scripts/build-tarball.sh ${{matrix.target}} @@ -106,9 +123,8 @@ jobs: needs: [ build-linux ] steps: - uses: actions/checkout@v3 - - uses: fish-actions/install-fish@v1 - - name: Install zsh - run: sudo apt-get update; sudo apt-get install zsh + - name: Install zsh/fish + run: sudo apt-get update; sudo apt-get install zsh fish - uses: actions/download-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu @@ -116,7 +132,14 @@ jobs: - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH - run: rtx -v - - run: ./e2e/run_all_tests + - name: Run e2e tests + uses: nick-fields/retry@v2 + env: + GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + with: + timeout_minutes: 20 + max_attempts: 3 + command: ./e2e/run_all_tests rpm: runs-on: ubuntu-22.04 needs: [ build-linux ] diff --git a/README.md b/README.md index 76ee68fdc..e41c78a22 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ v18.10.9 ``` > **Note** +> > `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not > already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). @@ -53,7 +54,9 @@ For more on how rtx compares to asdf, [see below](#comparison-to-asdf). The goal was to create a better front-end to asdf. It uses the same `.tool-versions` file that asdf uses. It's also compatible with idiomatic version -files like `.node-version` but you need to enable "legacy version file support" in the config. +files like `.node-version` and `.ruby-version`. See [Legacy Version Files](#legacy-version-files) below. + +Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). ### How it works @@ -86,6 +89,7 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin ## Installation > **Warning** +> > Regardless of the installation method, when uninstalling rtx, > remove `RTX_DATA_DIR` folder (usually `~/.local/share/rtx`) to fully clean up. @@ -155,6 +159,7 @@ sudo apt install -y rtx ``` > **Warning** +> > If you're on arm64 you'll need to run the following: > echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list @@ -225,6 +230,42 @@ jq 1.6 Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local) to create them automatically. See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. +### Legacy version files + +RTX supports "legacy version files" just like asdf. + +It's behind a config setting "legacy_version_file", but it's enabled by default (asdf defaults to disabled). +You can disable these with `rtx settings set legacy_version_file false`. There is a performance cost +to having these when they're parsed as it's performed by the plugin in `bin/parse-version-file`. However +these are [cached](#cache-behavior) so it's not a huge deal. You may not even notice. + +These are ideal for setting the runtime version of a project without forcing other developers to +use a specific tool like rtx/asdf. + +They support aliases, which means you can (finally) have an `.nvmrc` file with `lts/hydrogen` +and it will work in rtx _and_ nvm. This wasn't possible with asdf. + +Here are some of the supported legacy version files: + +| Plugin | "Legacy" (Idiomatic) Files | +| --------- | -------------------------------------------------- | +| crystal | `.crystal-version` | +| elixir | `.exenv-version` | +| golang | `.go-version`, `go.mod` | +| java | `.java-version` | +| nodejs | `.nvmrc`, `.node-version` | +| python | `.python-version` | +| ruby | `.ruby-version`, `Gemfile` | +| terraform | `.terraform-version`, `.packer-version`, `main.tf` | +| yarn | `.yvmrc` | + +> **Note** +> +> asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies +> that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" +> version files since they're version files not specific to asdf/rtx and can be used by other tools. +> (`.npmrc` being a notable exception, which is tied to a specific tool.) + ### Global config: `~/.config/rtx/config.toml` rtx can be configured in `~/.config/rtx/config.toml`. The following options are available (defaults shown): @@ -235,7 +276,7 @@ missing_runtime_behavior = 'prompt' # other options: 'ignore', 'warn', 'prompt', # plugins can read the versions files used by other version managers (if enabled by the plugin) # for example, .nvmrc in the case of nodejs's nvm -legacy_version_file = false # not enabled by default +legacy_version_file = true # enabled by default (different than asdf) # configure `rtx install` to always keep the downloaded archive always_keep_download = false # deleted after install by default @@ -257,6 +298,8 @@ my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node- # this can also be specified in a plugin (see below in "Aliases") ``` +These settings can also be managed with `rtx settings ls|get|set|unset`. + ### Environment variables rtx can also be configured via environment variables. The following options are available: @@ -318,6 +361,7 @@ echo "lts/fermium 14" ``` > **Note:** +> > Because this is rtx-specific functionality not currently used by asdf it isn't likely to be in any > plugin currently, but plugin authors can add this script without impacting asdf users. @@ -873,6 +917,97 @@ Examples: rtx plugins update # update all plugins rtx plugins update nodejs # update only nodejs +``` +### `rtx settings get` + +``` +Show a current setting + +This is the contents of a single entry in ~/.config/rtx/config.toml + +Note that aliases are also stored in this file +but managed separately with `rtx aliases get` + +Usage: get + +Arguments: + + The setting to show + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + $ rtx settings get legacy_version_file + true + +``` +### `rtx settings ls` + +``` +Show current settings + +This is the contents of ~/.config/rtx/config.toml + +Note that aliases are also stored in this file +but managed separately with `rtx aliases` + +Usage: ls + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + $ rtx settings + legacy_version_file = false + +``` +### `rtx settings set` + +``` +Add/update a setting + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: set + +Arguments: + + The setting to set + + + The value to set + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + $ rtx settings set legacy_version_file true + +``` +### `rtx settings unset` + +``` +Clears a setting + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: unset + +Arguments: + + The setting to remove + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + $ rtx settings unset legacy_version_file + ``` ### `rtx uninstall` @@ -1039,9 +1174,9 @@ cat ~/.local/share/rtx/installs/nodejs/18.13.0/.rtxconf.msgpack | msgpack-cli de ### Legacy File Cache -If enabled with `legacy_version_file = true` in `~/.config/rtx/config.toml`, rtx will read the legacy -filenames such as `.node-version` for [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs). -This leverages cache in 2 places where the plugin is called: +If enabled, rtx will read the legacy filenames such as `.node-version` for +[asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs). This leverages cache in 2 places where the +plugin is called: - [`list-legacy-filenames`](https://github.com/asdf-vm/asdf-nodejs/blob/master/bin/list-legacy-filenames) In every plugin I've seen this simply returns a static list of filenamed like ".nvmrc .node-version". diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 1d09bc52e..8b758be3d 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -54,7 +54,7 @@ mod test { #[test] fn test_alias_ls() { ensure_plugin_installed("shfmt"); - let Output { stdout, .. } = assert_cli!("aliases", "list"); + let Output { stdout, .. } = assert_cli!("aliases"); assert!(stdout.content.contains("my/alias")); } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 64b4e9f55..a07164d84 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -98,7 +98,9 @@ mod test { use std::fs; use insta::assert_snapshot; + use pretty_assertions::assert_str_eq; + use crate::cli::test::grep; use crate::output::Output; use crate::{assert_cli, dirs}; @@ -115,9 +117,11 @@ mod test { assert_snapshot!(stdout.content); let Output { stdout, .. } = assert_cli!("local", "--remove", "nodejs"); assert_snapshot!(stdout.content); - assert!(!stdout.content.contains(".node-version")); let Output { stdout, .. } = assert_cli!("ls", "--current"); - assert!(stdout.content.contains(".node-version")); + assert_str_eq!( + grep(&stdout, "nodejs").unwrap(), + " nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)" + ); fs::write(cf_path, orig).unwrap(); } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 9b0688873..1487ba4c2 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -26,6 +26,7 @@ mod local; mod ls; mod ls_remote; mod plugins; +mod settings; mod uninstall; mod version; mod r#where; @@ -57,6 +58,7 @@ pub enum Commands { Ls(ls::Ls), LsRemote(ls_remote::LsRemote), Plugins(plugins::Plugins), + Settings(settings::Settings), Uninstall(uninstall::Uninstall), Version(version::Version), Where(r#where::Where), @@ -84,6 +86,7 @@ impl Commands { Self::LsRemote(cmd) => cmd.run(config, out), Self::Local(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), + Self::Settings(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), Self::Version(cmd) => cmd.run(config, out), Self::Where(cmd) => cmd.run(config, out), @@ -189,6 +192,14 @@ pub mod test { }}; } + #[macro_export] + macro_rules! assert_cli_err { + ($($args:expr),+) => {{ + let args = &vec!["rtx".into(), $($args.into()),+]; + $crate::cli::test::cli_run(args).unwrap_err() + }}; + } + pub fn ensure_plugin_installed(name: &str) { let settings = Settings { missing_runtime_behavior: AutoInstall, diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index b2bea92e5..ffbc805b5 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -54,6 +54,7 @@ v18.10.9 ``` > **Note** +> > `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not > already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). @@ -71,7 +72,9 @@ For more on how rtx compares to asdf, [see below](#comparison-to-asdf). The goal was to create a better front-end to asdf. It uses the same `.tool-versions` file that asdf uses. It's also compatible with idiomatic version -files like `.node-version` but you need to enable "legacy version file support" in the config. +files like `.node-version` and `.ruby-version`. See [Legacy Version Files](#legacy-version-files) below. + +Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). ### How it works @@ -104,6 +107,7 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin ## Installation > **Warning** +> > Regardless of the installation method, when uninstalling rtx, > remove `RTX_DATA_DIR` folder (usually `~/.local/share/rtx`) to fully clean up. @@ -173,6 +177,7 @@ sudo apt install -y rtx ``` > **Warning** +> > If you're on arm64 you'll need to run the following: > echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list @@ -243,6 +248,42 @@ jq 1.6 Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local) to create them automatically. See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. +### Legacy version files + +RTX supports "legacy version files" just like asdf. + +It's behind a config setting "legacy_version_file", but it's enabled by default (asdf defaults to disabled). +You can disable these with `rtx settings set legacy_version_file false`. There is a performance cost +to having these when they're parsed as it's performed by the plugin in `bin/parse-version-file`. However +these are [cached](#cache-behavior) so it's not a huge deal. You may not even notice. + +These are ideal for setting the runtime version of a project without forcing other developers to +use a specific tool like rtx/asdf. + +They support aliases, which means you can (finally) have an `.nvmrc` file with `lts/hydrogen` +and it will work in rtx _and_ nvm. This wasn't possible with asdf. + +Here are some of the supported legacy version files: + +| Plugin | "Legacy" (Idiomatic) Files | +| --------- | -------------------------------------------------- | +| crystal | `.crystal-version` | +| elixir | `.exenv-version` | +| golang | `.go-version`, `go.mod` | +| java | `.java-version` | +| nodejs | `.nvmrc`, `.node-version` | +| python | `.python-version` | +| ruby | `.ruby-version`, `Gemfile` | +| terraform | `.terraform-version`, `.packer-version`, `main.tf` | +| yarn | `.yvmrc` | + +> **Note** +> +> asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies +> that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" +> version files since they're version files not specific to asdf/rtx and can be used by other tools. +> (`.npmrc` being a notable exception, which is tied to a specific tool.) + ### Global config: `~/.config/rtx/config.toml` rtx can be configured in `~/.config/rtx/config.toml`. The following options are available (defaults shown): @@ -253,7 +294,7 @@ missing_runtime_behavior = 'prompt' # other options: 'ignore', 'warn', 'prompt', # plugins can read the versions files used by other version managers (if enabled by the plugin) # for example, .nvmrc in the case of nodejs's nvm -legacy_version_file = false # not enabled by default +legacy_version_file = true # enabled by default (different than asdf) # configure `rtx install` to always keep the downloaded archive always_keep_download = false # deleted after install by default @@ -275,6 +316,8 @@ my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node- # this can also be specified in a plugin (see below in "Aliases") ``` +These settings can also be managed with `rtx settings ls|get|set|unset`. + ### Environment variables rtx can also be configured via environment variables. The following options are available: @@ -336,6 +379,7 @@ echo "lts/fermium 14" ``` > **Note:** +> > Because this is rtx-specific functionality not currently used by asdf it isn't likely to be in any > plugin currently, but plugin authors can add this script without impacting asdf users. @@ -534,9 +578,9 @@ cat ~/.local/share/rtx/installs/nodejs/18.13.0/.rtxconf.msgpack | msgpack-cli de ### Legacy File Cache -If enabled with `legacy_version_file = true` in `~/.config/rtx/config.toml`, rtx will read the legacy -filenames such as `.node-version` for [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs). -This leverages cache in 2 places where the plugin is called: +If enabled, rtx will read the legacy filenames such as `.node-version` for +[asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs). This leverages cache in 2 places where the +plugin is called: - [`list-legacy-filenames`](https://github.com/asdf-vm/asdf-nodejs/blob/master/bin/list-legacy-filenames) In every plugin I've seen this simply returns a static list of filenamed like ".nvmrc .node-version". diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs new file mode 100644 index 000000000..f3aea1a93 --- /dev/null +++ b/src/cli/settings/get.rs @@ -0,0 +1,58 @@ +use color_eyre::eyre::{eyre, Result}; +use indoc::indoc; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +/// Show a current setting +/// +/// This is the contents of a single entry in ~/.config/rtx/config.toml +/// +/// Note that aliases are also stored in this file +/// but managed separately with `rtx aliases get` +#[derive(Debug, clap::Args)] +#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +pub struct SettingsGet { + /// The setting to show + pub key: String, +} + +impl Command for SettingsGet { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + match config.settings.to_index_map().get(&self.key) { + Some(value) => Ok(rtxprintln!(out, "{}", value)), + None => Err(eyre!("Unknown setting: {}", self.key)), + } + } +} + +const AFTER_LONG_HELP: &str = indoc! {r#" + Examples: + $ rtx settings get legacy_version_file + true + "#}; + +#[cfg(test)] +mod test { + use insta::{assert_display_snapshot, assert_snapshot}; + + use crate::output::Output; + use crate::test::reset_config; + use crate::{assert_cli, assert_cli_err}; + + #[test] + fn test_settings_get() { + reset_config(); + let Output { stdout, .. } = assert_cli!("settings", "get", "legacy_version_file"); + assert_snapshot!(stdout.content, @r###" + true + "###); + } + + #[test] + fn test_settings_get_unknown() { + let err = assert_cli_err!("settings", "get", "unknown"); + assert_display_snapshot!(err, @"Unknown setting: unknown"); + } +} diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs new file mode 100644 index 000000000..dcd493d90 --- /dev/null +++ b/src/cli/settings/ls.rs @@ -0,0 +1,47 @@ +use color_eyre::eyre::Result; +use indoc::indoc; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +/// Show current settings +/// +/// This is the contents of ~/.config/rtx/config.toml +/// +/// Note that aliases are also stored in this file +/// but managed separately with `rtx aliases` +#[derive(Debug, clap::Args)] +#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +pub struct SettingsLs {} + +impl Command for SettingsLs { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + for (key, value) in config.settings.to_index_map() { + rtxprintln!(out, "{} = {}", key, value); + } + Ok(()) + } +} + +const AFTER_LONG_HELP: &str = indoc! {r#" + Examples: + $ rtx settings + legacy_version_file = false + "#}; + +#[cfg(test)] +mod test { + use insta::assert_snapshot; + + use crate::assert_cli; + use crate::output::Output; + use crate::test::reset_config; + + #[test] + fn test_settings_ls() { + reset_config(); + let Output { stdout, .. } = assert_cli!("settings"); + assert_snapshot!(stdout.content); + } +} diff --git a/src/cli/settings/mod.rs b/src/cli/settings/mod.rs new file mode 100644 index 000000000..2b440dc7b --- /dev/null +++ b/src/cli/settings/mod.rs @@ -0,0 +1,45 @@ +use clap::Subcommand; +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +mod get; +mod ls; +mod set; +mod unset; + +#[derive(Debug, clap::Args)] +#[clap(about = "Manage settings")] +pub struct Settings { + #[clap(subcommand)] + command: Option, +} + +#[derive(Debug, Subcommand)] +enum Commands { + Get(get::SettingsGet), + Ls(ls::SettingsLs), + Set(set::SettingsSet), + Unset(unset::SettingsUnset), +} + +impl Commands { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + match self { + Self::Get(cmd) => cmd.run(config, out), + Self::Ls(cmd) => cmd.run(config, out), + Self::Set(cmd) => cmd.run(config, out), + Self::Unset(cmd) => cmd.run(config, out), + } + } +} + +impl Command for Settings { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let cmd = self.command.unwrap_or(Commands::Ls(ls::SettingsLs {})); + + cmd.run(config, out) + } +} diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs new file mode 100644 index 000000000..60d983513 --- /dev/null +++ b/src/cli/settings/set.rs @@ -0,0 +1,99 @@ +use color_eyre::eyre::{eyre, Result}; +use indoc::indoc; + +use crate::cli::command::Command; +use crate::config::config_file::ConfigFile; +use crate::config::Config; +use crate::output::Output; + +/// Add/update a setting +/// +/// This modifies the contents of ~/.config/rtx/config.toml +#[derive(Debug, clap::Args)] +#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +pub struct SettingsSet { + /// The setting to set + pub key: String, + /// The value to set + pub value: String, +} + +impl Command for SettingsSet { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let mut rtxrc = config.rtxrc; + let value: toml_edit::Value = match self.key.as_str() { + "missing_runtime_behavior" => self.value.into(), + "always_keep_download" => parse_bool(&self.value)?, + "legacy_version_file" => parse_bool(&self.value)?, + "disable_plugin_short_name_repository" => parse_bool(&self.value)?, + "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, + "plugin_repository_last_check_duration" => parse_i64(&self.value)?, + _ => return Err(eyre!("Unknown setting: {}", self.key)), + }; + + rtxrc.update_setting(&self.key, value); + rtxrc.save() + } +} + +fn parse_bool(value: &str) -> Result { + match value { + "true" => Ok(true.into()), + "false" => Ok(false.into()), + _ => Err(eyre!("{} must be true or false", value)), + } +} + +fn parse_i64(value: &str) -> Result { + match value.parse::() { + Ok(value) => Ok(value.into()), + Err(_) => Err(eyre!("{} must be a number", value)), + } +} + +const AFTER_LONG_HELP: &str = indoc! {r#" + Examples: + $ rtx settings set legacy_version_file true + "#}; + +#[cfg(test)] +pub mod test { + use insta::assert_snapshot; + + use crate::assert_cli; + use crate::output::Output; + use crate::test::reset_config; + + #[test] + fn test_settings_set() { + reset_config(); + let Output { stdout, .. } = assert_cli!("settings"); + assert_snapshot!(stdout.content); + + assert_cli!("settings", "set", "missing_runtime_behavior", "warn"); + assert_cli!("settings", "set", "legacy_version_file", "false"); + assert_cli!("settings", "set", "always_keep_download", "true"); + assert_cli!( + "settings", + "set", + "disable_plugin_short_name_repository", + "true" + ); + assert_cli!( + "settings", + "set", + "plugin_autoupdate_last_check_duration", + "1" + ); + assert_cli!( + "settings", + "set", + "plugin_repository_last_check_duration", + "2" + ); + + let Output { stdout, .. } = assert_cli!("settings"); + assert_snapshot!(stdout.content); + reset_config(); + } +} diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap new file mode 100644 index 000000000..d2a4d7081 --- /dev/null +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap @@ -0,0 +1,11 @@ +--- +source: src/cli/settings/ls.rs +expression: stdout.content +--- +missing_runtime_behavior = autoinstall +always_keep_download = true +legacy_version_file = true +disable_plugin_short_name_repository = false +plugin_autoupdate_last_check_duration = 20 +plugin_repository_last_check_duration = 20 + diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap new file mode 100644 index 000000000..5690f3681 --- /dev/null +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap @@ -0,0 +1,11 @@ +--- +source: src/cli/settings/set.rs +expression: stdout.content +--- +missing_runtime_behavior = autoinstall +always_keep_download = true +legacy_version_file = false +disable_plugin_short_name_repository = true +plugin_autoupdate_last_check_duration = 1 +plugin_repository_last_check_duration = 2 + diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap new file mode 100644 index 000000000..c4cc31272 --- /dev/null +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap @@ -0,0 +1,11 @@ +--- +source: src/cli/settings/set.rs +expression: stdout.content +--- +missing_runtime_behavior = autoinstall +always_keep_download = true +legacy_version_file = true +disable_plugin_short_name_repository = false +plugin_autoupdate_last_check_duration = 20 +plugin_repository_last_check_duration = 20 + diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs new file mode 100644 index 000000000..3aba954c6 --- /dev/null +++ b/src/cli/settings/unset.rs @@ -0,0 +1,68 @@ +use color_eyre::eyre::Result; +use indoc::indoc; + +use crate::cli::command::Command; +use crate::config::config_file::ConfigFile; +use crate::config::Config; +use crate::output::Output; + +/// Clears a setting +/// +/// This modifies the contents of ~/.config/rtx/config.toml +#[derive(Debug, clap::Args)] +#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +pub struct SettingsUnset { + /// The setting to remove + pub key: String, +} + +impl Command for SettingsUnset { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let mut rtxrc = config.rtxrc; + rtxrc.remove_setting(&self.key); + rtxrc.save() + } +} + +const AFTER_LONG_HELP: &str = indoc! {r#" + Examples: + $ rtx settings unset legacy_version_file + "#}; + +#[cfg(test)] +mod test { + use insta::assert_snapshot; + + use crate::assert_cli; + use crate::output::Output; + use crate::test::reset_config; + + #[test] + fn test_settings_unset() { + reset_config(); + + let Output { stdout, .. } = assert_cli!("settings"); + assert_snapshot!(stdout.content, @r###" + missing_runtime_behavior = autoinstall + always_keep_download = true + legacy_version_file = true + disable_plugin_short_name_repository = false + plugin_autoupdate_last_check_duration = 20 + plugin_repository_last_check_duration = 20 + "###); + + assert_cli!("settings", "unset", "legacy_version_file"); + + let Output { stdout, .. } = assert_cli!("settings"); + assert_snapshot!(stdout.content, @r###" + missing_runtime_behavior = autoinstall + always_keep_download = true + legacy_version_file = true + disable_plugin_short_name_repository = false + plugin_autoupdate_last_check_duration = 20 + plugin_repository_last_check_duration = 20 + "###); + + reset_config(); + } +} diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index b9dd0715e..9cdd96e68 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -241,6 +241,58 @@ impl RTXFile { } } } + + pub fn update_setting>(&mut self, key: &str, value: V) { + let doc = self.get_or_create_edit(); + let key = key.split('.').collect::>(); + let mut table = doc.as_table_mut(); + for (i, k) in key.iter().enumerate() { + if i == key.len() - 1 { + table[k] = toml_edit::value(value); + break; + } else { + table = table + .entry(k) + .or_insert(toml_edit::table()) + .as_table_mut() + .unwrap(); + } + } + } + + pub fn remove_setting(&mut self, key: &str) { + let doc = self.get_or_create_edit(); + let key = key.split('.').collect::>(); + let mut table = doc.as_table_mut(); + for (i, k) in key.iter().enumerate() { + if i == key.len() - 1 { + table.remove(k); + break; + } else { + table = table + .entry(k) + .or_insert(toml_edit::table()) + .as_table_mut() + .unwrap(); + } + } + } + + pub fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { + let doc = self.get_or_create_edit(); + let aliases = doc + .as_table_mut() + .entry("aliases") + .or_insert(toml_edit::table()) + .as_table_mut() + .unwrap(); + let plugin_aliases = aliases + .entry(plugin) + .or_insert(toml_edit::table()) + .as_table_mut() + .unwrap(); + plugin_aliases[from] = toml_edit::value(to); + } } impl Display for RTXFile { @@ -459,4 +511,96 @@ nodejs=[true] assert_display_snapshot!(err, @"Invalid TOML: true"); } + + #[test] + fn test_update_setting() { + let mut f = tempfile::NamedTempFile::new().unwrap(); + writedoc!( + f, + r#" + legacy_version_file = true + [aliases.nodejs] + 18 = "18.0.0" + "# + ) + .unwrap(); + let mut cf = RTXFile::from_file(f.path()).unwrap(); + cf.update_setting("legacy_version_file", false); + cf.update_setting("something_else", "foo"); + cf.update_setting("something.nested.very.deeply", 123); + cf.update_setting("aliases.nodejs.20", "20.0.0"); + cf.update_setting("aliases.python.3", "3.9.0"); + assert_display_snapshot!(cf.dump(), @r###" + legacy_version_file = false + something_else = "foo" + [aliases.nodejs] + 18 = "18.0.0" + 20 = "20.0.0" + + [aliases.python] + 3 = "3.9.0" + + [something] + + [something.nested] + + [something.nested.very] + deeply = 123 + "###); + } + + #[test] + fn test_remove_setting() { + let mut f = tempfile::NamedTempFile::new().unwrap(); + writedoc!( + f, + r#" + [something] + + [something.nested] + other = "foo" + + [something.nested.very] + deeply = 123 + "# + ) + .unwrap(); + let mut cf = RTXFile::from_file(f.path()).unwrap(); + cf.remove_setting("something.nested.other"); + assert_display_snapshot!(cf.dump(), @r###" + [something] + + [something.nested] + + [something.nested.very] + deeply = 123 + "###); + } + + #[test] + fn test_set_alias() { + let mut f = tempfile::NamedTempFile::new().unwrap(); + writedoc!( + f, + r#" + [aliases.nodejs] + 16 = "16.0.0" + 18 = "18.0.0" + "# + ) + .unwrap(); + let mut cf = RTXFile::from_file(f.path()).unwrap(); + cf.set_alias("nodejs", "18", "18.0.1"); + cf.set_alias("nodejs", "20", "20.0.0"); + cf.set_alias("python", "3.10", "3.10.0"); + assert_display_snapshot!(cf.dump(), @r###" + [aliases.nodejs] + 16 = "16.0.0" + 18 = "18.0.1" + 20 = "20.0.0" + + [aliases.python] + "3.10" = "3.10.0" + "###); + } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 175320042..12bfcbda3 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -16,7 +16,7 @@ use crate::cli::args::runtime::RuntimeArg; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtxrc::RTXFile; use crate::config::config_file::ConfigFile; -use crate::config::settings::{Settings, SettingsBuilder}; +use crate::config::settings::Settings; use crate::config::toolset::Toolset; use crate::plugins::{Plugin, PluginName, PluginSource}; use crate::{dirs, env, file}; @@ -30,6 +30,7 @@ type AliasMap = IndexMap>; #[derive(Debug)] pub struct Config { pub settings: Settings, + pub rtxrc: RTXFile, pub ts: Toolset, pub config_files: Vec, pub aliases: AliasMap, @@ -37,7 +38,8 @@ pub struct Config { impl Config { pub fn load() -> Result { - let settings = load_settings()?; + let rtxrc = load_rtxrc()?; + let settings = rtxrc.settings(); let mut ts = Toolset::default(); load_installed_plugins(&mut ts)?; load_installed_runtimes(&mut ts)?; @@ -53,6 +55,7 @@ impl Config { ts, config_files, aliases, + rtxrc, }; debug!("{}", &config); @@ -141,20 +144,19 @@ impl Config { } } -fn load_settings() -> Result { +fn load_rtxrc() -> Result { let settings_path = dirs::CONFIG.join("config.toml"); - let settings = if !settings_path.exists() { + let rtxrc = if !settings_path.exists() { trace!("settings does not exist {:?}", settings_path); - SettingsBuilder::default().build() + RTXFile::init(&settings_path) } else { - let cf = RTXFile::from_file(&settings_path) + let rtxrc = RTXFile::from_file(&settings_path) .wrap_err_with(|| err_load_settings(&settings_path))?; - let settings = cf.settings(); - trace!("Settings: {:#?}", &settings); - settings + trace!("Settings: {:#?}", rtxrc.settings()); + rtxrc }; - Ok(settings) + Ok(rtxrc) } fn load_installed_plugins(ts: &mut Toolset) -> Result<()> { diff --git a/src/config/settings.rs b/src/config/settings.rs index eb2ec8279..c0cf9710b 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,3 +1,4 @@ +use std::fmt::{Display, Formatter}; use std::time::Duration; use indexmap::IndexMap; @@ -22,7 +23,7 @@ impl Default for Settings { Self { missing_runtime_behavior: MissingRuntimeBehavior::Prompt, always_keep_download: false, - legacy_version_file: false, + legacy_version_file: true, disable_plugin_short_name_repository: false, plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), plugin_repository_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), @@ -31,6 +32,37 @@ impl Default for Settings { } } +impl Settings { + pub fn to_index_map(&self) -> IndexMap { + let mut map = IndexMap::new(); + map.insert( + "missing_runtime_behavior".to_string(), + self.missing_runtime_behavior.to_string(), + ); + map.insert( + "always_keep_download".to_string(), + self.always_keep_download.to_string(), + ); + map.insert( + "legacy_version_file".to_string(), + self.legacy_version_file.to_string(), + ); + map.insert( + "disable_plugin_short_name_repository".to_string(), + self.disable_plugin_short_name_repository.to_string(), + ); + map.insert( + "plugin_autoupdate_last_check_duration".to_string(), + (self.plugin_autoupdate_last_check_duration.as_secs() / 60).to_string(), + ); + map.insert( + "plugin_repository_last_check_duration".to_string(), + (self.plugin_repository_last_check_duration.as_secs() / 60).to_string(), + ); + map + } +} + #[derive(Debug, Default, Clone)] pub struct SettingsBuilder { pub missing_runtime_behavior: Option, @@ -121,9 +153,21 @@ pub enum MissingRuntimeBehavior { Ignore, } +impl Display for MissingRuntimeBehavior { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + MissingRuntimeBehavior::AutoInstall => write!(f, "autoinstall"), + MissingRuntimeBehavior::Prompt => write!(f, "prompt"), + MissingRuntimeBehavior::Warn => write!(f, "warn"), + MissingRuntimeBehavior::Ignore => write!(f, "ignore"), + } + } +} + #[cfg(test)] mod tests { use super::*; + use crate::config::settings::MissingRuntimeBehavior::{AutoInstall, Ignore, Prompt, Warn}; #[test] fn test_settings_merge() { @@ -139,4 +183,12 @@ mod tests { Some(MissingRuntimeBehavior::AutoInstall) ); } + + #[test] + fn test_missing_runtime_behavior_display() { + assert_eq!(AutoInstall.to_string(), "autoinstall"); + assert_eq!(Prompt.to_string(), "prompt"); + assert_eq!(Warn.to_string(), "warn"); + assert_eq!(Ignore.to_string(), "ignore"); + } } diff --git a/src/test.rs b/src/test.rs index 66295bee9..90ac9bc9e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,20 +1,43 @@ use std::fs; -use crate::cmd; +use indoc::indoc; + +use crate::{cmd, env}; #[ctor::ctor] fn init() { - std::env::set_var("NO_COLOR", "1"); + env::set_var("NO_COLOR", "1"); env_logger::init(); let _ = fs::remove_dir_all("test/data/legacy_cache"); if let Err(err) = cmd!( "git", "checkout", "test/.tool-versions", - "test/cwd/.tool-versions" + "test/cwd/.tool-versions", + "test/config/config.toml" ) .run() { warn!("failed to reset test files: {}", err); } + + reset_config(); +} + +pub fn reset_config() { + fs::write( + env::HOME.join("config/config.toml"), + indoc! {r#" + missing_runtime_behavior= 'autoinstall' + always_keep_download= true + legacy_version_file= true + disable_plugin_short_name_repository= false + plugin_repository_last_check_duration = 20 + plugin_autoupdate_last_check_duration = 20 + + [alias.shfmt] + "my/alias" = '3.0' + "#}, + ) + .unwrap(); } From 4c50c5db15cbcd86ab19b8ee3806c05cd57968e5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:54:18 -0600 Subject: [PATCH 0009/1891] add /Cargo.lock to crate --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0128d82cd..253d24b50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] -include = ["src/**/*", "/LICENSE", "/README.md"] +include = ["src/**/*", "/LICENSE", "/README.md", "/Cargo.lock"] rust-version = "1.66.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 24b6ff99ee40b02aec7a11d0264413fab2ef5c7a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:58:55 -0600 Subject: [PATCH 0010/1891] chore: Release rtx-cli version 1.1.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab2036bb9..1bdabb8df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -999,7 +999,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.0.1" +version = "1.1.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 253d24b50..c00e0a123 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.0.1" +version = "1.1.0" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e41c78a22..377a860ad 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.0.1 +rtx 1.1.0 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 3483ff4e3..2c2f22b08 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.0.1 +Version: 1.1.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From af687dad078496fb38570f0585a78576159336a6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 16:08:41 -0600 Subject: [PATCH 0011/1891] remove debug statements --- src/hook_env.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hook_env.rs b/src/hook_env.rs index cd33a9fff..0a771dbc8 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -89,11 +89,9 @@ fn apply_patches( for patch in patches { match patch { EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { - eprintln!("adding {k}"); new_env.insert(k.into(), v.into()); } EnvDiffOperation::Remove(k) => { - eprintln!("removing {k}"); new_env.remove(k); } } From 9441bc22358be4892656e4aeca5b203f29dbf0c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 16:08:51 -0600 Subject: [PATCH 0012/1891] chore: Release rtx-cli version 1.1.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bdabb8df..59a08d181 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -999,7 +999,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.1.0" +version = "1.1.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index c00e0a123..4238b64c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.1.0" +version = "1.1.1" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 377a860ad..8be825f70 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.1.0 +rtx 1.1.1 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 2c2f22b08..ae5e4b4ad 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.1.0 +Version: 1.1.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From c0c47299d5cbe7d8ca27100fc6456d122d28268e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 18:50:04 -0600 Subject: [PATCH 0013/1891] direnv integration (#23) --- README.md | 59 ++++++++++++++- src/cli/activate.rs | 16 +++- src/cli/direnv/activate.rs | 40 ++++++++++ src/cli/direnv/envrc.rs | 75 +++++++++++++++++++ src/cli/direnv/mod.rs | 47 ++++++++++++ ...li__direnv__envrc__test__direnv_envrc.snap | 12 +++ src/cli/env.rs | 8 +- src/cli/exec.rs | 10 ++- src/cli/external.rs | 1 + src/cli/hook_env.rs | 1 + src/cli/mod.rs | 3 + src/cli/render_help.rs | 29 +++++++ src/config/mod.rs | 66 ++++++++-------- src/config/toolset.rs | 4 +- src/env.rs | 2 + src/ui/mod.rs | 4 +- 16 files changed, 330 insertions(+), 47 deletions(-) create mode 100644 src/cli/direnv/activate.rs create mode 100644 src/cli/direnv/envrc.rs create mode 100644 src/cli/direnv/mod.rs create mode 100644 src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap diff --git a/README.md b/README.md index 8be825f70..a64a87e51 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ $ echo 'eval "$(rtx activate -s zsh)"' >> ~/.zshrc $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` +> **Warning:** +> +> If you use [direnv](https://direnv.net), [see below](#direnv) for direnv-compatible setup. + Install a runtime and set it as the default: ```sh-session @@ -407,15 +411,15 @@ At some point it may be worth exploring an alternate plugin format that would be ``` Enables rtx to automatically modify runtimes when changing directory -This should go into your shell's rc file. Otherwise it will only -take effect in the current session. +This should go into your shell's rc file. +Otherwise, it will only take effect in the current session. (e.g. ~/.bashrc) Usage: activate [OPTIONS] Options: -s, --shell - Shell type to generate script for + Shell type to generate the script for [possible values: bash, fish, zsh] @@ -481,6 +485,30 @@ Examples: $ eval "$(rtx deactivate -s zsh)" $ rtx deactivate -s fish | source +``` +### `rtx direnv activate` + +``` +Output direnv function to use rtx inside direnv + +See https://github.com/jdxcode/rtx#direnv for more information + +Because this generates the legacy files based on currently installed plugins, +you should run this command after installing new plugins. Otherwise +direnv may not know to update environment variables when legacy file versions change. + +Usage: activate + +Options: + -h, --help + Print help (see a summary with '-h') + + +Examples: + $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh + $ echo 'use rtx' > .envrc + $ direnv allow + ``` ### `rtx doctor` @@ -1124,6 +1152,31 @@ That said, there are a lot of great things about asdf. It's the best multi-runti and I've really been impressed with the plugin system. Most of the design decisions the authors made were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. +## Direnv + +Direnv and rtx both manage environment variables based on directory. Because they both analyze +the current environment variables before and after their respective "hook" commands are run, they +can easily conflict and overwrite each other's environment variables (including, but not limited to, `PATH`). + +To avoid this, **don't** use `rtx activate` alongside direnv. Instead, call rtx from _within_ direnv +so that it can track the environment variables separately. + +To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: + +```sh-session +$ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh +# replace ~/.config with XDG_CONFIG_HOME if you've changed it +``` + +Now in your `.envrc` file add the following: + +```sh-session +use_rtx +``` + +Direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` +too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). + ## Cache Behavior rtx makes use of caching in many places in order to be efficient. The details about how long to keep diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 26b0deca0..5da704a32 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Result; +use indoc::indoc; use crate::cli::command::Command; use crate::config::Config; @@ -8,19 +9,27 @@ use crate::shell::{get_shell, ShellType}; /// Enables rtx to automatically modify runtimes when changing directory /// -/// This should go into your shell's rc file. Otherwise it will only -/// take effect in the current session. +/// This should go into your shell's rc file. +/// Otherwise, it will only take effect in the current session. /// (e.g. ~/.bashrc) #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Activate { - /// Shell type to generate script for + /// Shell type to generate the script for #[clap(long, short)] shell: Option, } impl Command for Activate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { + if !*env::RTX_DISABLE_DIRENV_WARNING && env::DIRENV_DIR.is_some() { + warn!(indoc! {r#" + `rtx activate` may conflict with direnv! + See https://github.com/jdxcode/rtx#direnv for more information. + Disable this warning with RTX_DISABLE_DIRENV_WARNING=1 + "#}); + } + let shell = get_shell(self.shell); let exe = if cfg!(test) { @@ -52,7 +61,6 @@ mod test { #[test] fn test_activate_zsh() { - std::env::set_var("NO_COLOR", "1"); let Output { stdout, .. } = assert_cli!("activate", "-s", "zsh"); assert_display_snapshot!(stdout.content); } diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs new file mode 100644 index 000000000..8f0ff10bc --- /dev/null +++ b/src/cli/direnv/activate.rs @@ -0,0 +1,40 @@ +use color_eyre::eyre::Result; +use indoc::indoc; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +/// Output direnv function to use rtx inside direnv +/// +/// See https://github.com/jdxcode/rtx#direnv for more information +/// +/// Because this generates the legacy files based on currently installed plugins, +/// you should run this command after installing new plugins. Otherwise +/// direnv may not know to update environment variables when legacy file versions change. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct DirenvActivate {} + +impl Command for DirenvActivate { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + rtxprintln!( + out, + indoc! {r#" + ### Do not edit. This was autogenerated by 'rtx direnv' ### + use_rtx() {{ + source_env "$(rtx direnv envrc "$@")" + }} + "#} + ); + + Ok(()) + } +} + +const AFTER_LONG_HELP: &str = r#" +Examples: + $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh + $ echo 'use rtx' > .envrc + $ direnv allow +"#; diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs new file mode 100644 index 000000000..ebcfaf150 --- /dev/null +++ b/src/cli/direnv/envrc.rs @@ -0,0 +1,75 @@ +use std::fs::{create_dir_all, File}; +use std::io::Write; +use std::ops::Deref; + +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::settings::MissingRuntimeBehavior::{AutoInstall, Warn}; +use crate::config::Config; +use crate::dirs; +use crate::hash::hash_to_str; +use crate::output::Output; + +/// [internal] This is an internal command that writes an envrc file +/// for direnv to consume. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, hide = true)] +pub struct Envrc {} + +impl Command for Envrc { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + if config.settings.missing_runtime_behavior == AutoInstall { + config.settings.missing_runtime_behavior = Warn; + } + config.ensure_installed()?; + let envrc_path = dirs::ROOT + .join("direnv") + .join(hash_to_str(dirs::CURRENT.deref()) + ".envrc"); + + // TODO: exit early if envrc_path exists and is up to date + create_dir_all(envrc_path.parent().unwrap())?; + let mut file = File::create(&envrc_path)?; + + writeln!( + file, + "### Do not edit. This was autogenerated by 'asdf direnv envrc' ###" + )?; + for cf in &config.config_files { + writeln!(file, "watch_file {}", cf.to_string_lossy())?; + } + for (k, v) in config.env()? { + writeln!( + file, + "export {}={}", + shell_escape::unix::escape(k.to_string_lossy()), + shell_escape::unix::escape(v.to_string_lossy()), + )?; + } + for path in &config.list_paths()? { + writeln!(file, "PATH_add {}", path.to_string_lossy())?; + } + + rtxprintln!(out, "{}", envrc_path.to_string_lossy()); + Ok(()) + } +} + +#[cfg(test)] +mod test { + use std::fs; + + use insta::assert_display_snapshot; + + use crate::assert_cli; + + use super::*; + + #[test] + fn test_direnv_envrc() { + let Output { stdout, .. } = assert_cli!("direnv", "envrc"); + let envrc = fs::read_to_string(stdout.content.trim()).unwrap(); + let envrc = envrc.replace(dirs::HOME.to_string_lossy().as_ref(), "~"); + assert_display_snapshot!(envrc); + } +} diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs new file mode 100644 index 000000000..57343bd0e --- /dev/null +++ b/src/cli/direnv/mod.rs @@ -0,0 +1,47 @@ +use clap::Subcommand; +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +mod activate; +mod envrc; + +/// Output direnv function to use rtx inside direnv +/// +/// See https://github.com/jdxcode/rtx#direnv for more information +/// +/// Because this generates the legacy files based on currently installed plugins, +/// you should run this command after installing new plugins. Otherwise +/// direnv may not know to update environment variables when legacy file versions change. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct Direnv { + #[clap(subcommand)] + command: Option, +} + +#[derive(Debug, Subcommand)] +enum Commands { + Envrc(envrc::Envrc), + Activate(activate::DirenvActivate), +} + +impl Commands { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + match self { + Self::Activate(cmd) => cmd.run(config, out), + Self::Envrc(cmd) => cmd.run(config, out), + } + } +} + +impl Command for Direnv { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let cmd = self + .command + .unwrap_or(Commands::Activate(activate::DirenvActivate {})); + cmd.run(config, out) + } +} diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap new file mode 100644 index 000000000..b0321f968 --- /dev/null +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap @@ -0,0 +1,12 @@ +--- +source: src/cli/direnv/envrc.rs +expression: envrc +--- +### Do not edit. This was autogenerated by 'asdf direnv envrc' ### +watch_file ~/cwd/.tool-versions +watch_file ~/cwd/.node-version +watch_file ~/.tool-versions +PATH_add ~/data/installs/shfmt/3.6.0/bin +PATH_add ~/data/installs/jq/1.6/bin +PATH_add ~/data/installs/shellcheck/0.9.0/bin + diff --git a/src/cli/env.rs b/src/cli/env.rs index 0839c6aae..422b7ab33 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,5 +1,4 @@ use color_eyre::eyre::Result; -use itertools::Itertools; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -32,11 +31,16 @@ impl Command for Env { config.ensure_installed()?; let shell = get_shell(self.shell); - for (k, v) in config.env()?.iter().sorted() { + for (k, v) in config.env()? { let k = k.to_string_lossy().to_string(); let v = v.to_string_lossy().to_string(); rtxprint!(out, "{}", shell.set_env(&k, &v)); } + rtxprintln!( + out, + "{}", + shell.set_env("PATH", config.path_env()?.to_string_lossy().as_ref()) + ); Ok(()) } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index e554064c2..7c38fa762 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -1,7 +1,7 @@ -use std::collections::HashMap; use std::ffi::OsString; use color_eyre::eyre::{eyre, Result}; +use indexmap::IndexMap; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -46,13 +46,15 @@ impl Command for Exec { config.ensure_installed()?; let (program, args) = parse_command(&env::SHELL, self.command, self.c); + let mut env = config.env()?; + env.insert("PATH".into(), config.path_env()?); - exec(program, args, config.env()?) + exec(program, args, env) } } #[cfg(not(test))] -fn exec(program: OsString, args: Vec, env: HashMap) -> Result<()> { +fn exec(program: OsString, args: Vec, env: IndexMap) -> Result<()> { for (k, v) in env.iter() { env::set_var(k, v); } @@ -61,7 +63,7 @@ fn exec(program: OsString, args: Vec, env: HashMap } #[cfg(test)] -fn exec(program: OsString, args: Vec, env: HashMap) -> Result<()> { +fn exec(program: OsString, args: Vec, env: IndexMap) -> Result<()> { let mut cmd = cmd::cmd(program, args); for (k, v) in env.iter() { cmd = cmd.env(k, v); diff --git a/src/cli/external.rs b/src/cli/external.rs index 2c76bb611..634abfe81 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -13,6 +13,7 @@ pub fn commands(config: &Config) -> Result> { .collect::>>>>()? .into_iter() .filter(|commands| !commands.is_empty()) + .filter(|commands| commands[0][0] != "direnv") .map(|commands| { clap::Command::new(commands[0][0].to_string()).subcommands(commands.into_iter().map( |cmd| { diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index f72481abf..347c55a90 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -33,6 +33,7 @@ impl Command for HookEnv { .iter() .map(|(k, v)| (k.to_string_lossy().into(), v.to_string_lossy().into())) .collect(); + env.insert("PATH".into(), config.path_env()?.to_string_lossy().into()); env.insert("__RTX_DIR".into(), dirs::CURRENT.to_string_lossy().into()); let diff = EnvDiff::new(&env::PRISTINE_ENV, &env); let mut patches = diff.to_patches(); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1487ba4c2..2bc96ca9f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -14,6 +14,7 @@ mod asdf; pub mod command; mod current; mod deactivate; +mod direnv; mod doctor; mod env; mod exec; @@ -47,6 +48,7 @@ pub enum Commands { Asdf(asdf::Asdf), Current(current::Current), Deactivate(deactivate::Deactivate), + Direnv(direnv::Direnv), Doctor(doctor::Doctor), Env(env::Env), Exec(exec::Exec), @@ -75,6 +77,7 @@ impl Commands { Self::Asdf(cmd) => cmd.run(config, out), Self::Current(cmd) => cmd.run(config, out), Self::Deactivate(cmd) => cmd.run(config, out), + Self::Direnv(cmd) => cmd.run(config, out), Self::Doctor(cmd) => cmd.run(config, out), Self::Env(cmd) => cmd.run(config, out), Self::Exec(cmd) => cmd.run(config, out), diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index ffbc805b5..1aa33847f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -44,6 +44,10 @@ $ echo 'eval "$(rtx activate -s zsh)"' >> ~/.zshrc $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` +> **Warning:** +> +> If you use [direnv](https://direnv.net), [see below](#direnv) for direnv-compatible setup. + Install a runtime and set it as the default: ```sh-session @@ -528,6 +532,31 @@ That said, there are a lot of great things about asdf. It's the best multi-runti and I've really been impressed with the plugin system. Most of the design decisions the authors made were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. +## Direnv + +Direnv and rtx both manage environment variables based on directory. Because they both analyze +the current environment variables before and after their respective "hook" commands are run, they +can easily conflict and overwrite each other's environment variables (including, but not limited to, `PATH`). + +To avoid this, **don't** use `rtx activate` alongside direnv. Instead, call rtx from _within_ direnv +so that it can track the environment variables separately. + +To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: + +```sh-session +$ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh +# replace ~/.config with XDG_CONFIG_HOME if you've changed it +``` + +Now in your `.envrc` file add the following: + +```sh-session +use_rtx +``` + +Direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` +too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). + ## Cache Behavior rtx makes use of caching in many places in order to be efficient. The details about how long to keep diff --git a/src/config/mod.rs b/src/config/mod.rs index 12bfcbda3..ccc23e335 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -63,20 +63,45 @@ impl Config { Ok(config) } - pub fn env(&self) -> Result> { - let mut env = HashMap::new(); - - let new_envs = self + pub fn env(&self) -> Result> { + let mut entries = self .ts .list_current_installed_versions() .into_par_iter() .map(|p| p.exec_env()) - .collect::>>>()?; - for new_env in new_envs { - env.extend(new_env); + .collect::>>>()? + .into_iter() + .flatten() + .collect_vec(); + entries.par_sort(); + Ok(entries.into_iter().collect()) + } + + pub fn list_paths(&self) -> Result> { + let paths = self + .ts + .list_current_installed_versions() + .into_par_iter() + .map(|rtv| rtv.list_bin_paths()) + .collect::>>>()? + .into_iter() + .flatten() + .collect::>(); + Ok(paths) + } + + pub fn path_env(&self) -> Result { + let mut paths = self.list_paths()?; + let default_path = String::new(); + let orig_path = env::PRISTINE_ENV.get("PATH").unwrap_or(&default_path); + for p in split_paths(orig_path) { + if p.starts_with(dirs::INSTALLS.deref()) { + // ignore existing install directories from previous runs + continue; + } + paths.push(p); } - env.insert("PATH".into(), self.build_env_path()?); - Ok(env) + Ok(join_paths(paths)?) } pub fn with_runtime_args(mut self, args: &[RuntimeArg]) -> Result { @@ -121,27 +146,6 @@ impl Config { } version } - - fn build_env_path(&self) -> Result { - let mut paths = self - .ts - .list_current_installed_versions() - .into_par_iter() - .map(|rtv| rtv.list_bin_paths()) - .collect::>>>()? - .into_iter() - .flatten() - .collect::>(); - - for p in split_paths(env::PATH.deref()) { - if p.starts_with(dirs::INSTALLS.deref()) { - // ignore existing install directories from previous runs - continue; - } - paths.push(p); - } - Ok(join_paths(paths)?) - } } fn load_rtxrc() -> Result { @@ -224,7 +228,7 @@ fn find_all_config_files(legacy_filenames: &HashMap) -> Vec< config_files.push(home_config); } - config_files + config_files.into_iter().unique().collect() } fn load_config_files( diff --git a/src/config/toolset.rs b/src/config/toolset.rs index ae59bba09..0106bcbb0 100644 --- a/src/config/toolset.rs +++ b/src/config/toolset.rs @@ -15,7 +15,7 @@ use crate::runtimes::RuntimeVersion; pub struct Toolset { pub plugins: HashMap>, installed_versions: HashMap>>, - current_versions: HashMap>, + current_versions: IndexMap>, current_versions_sources: HashMap, } @@ -164,7 +164,7 @@ impl Toolset { }) .collect::)>>>()? .into_iter() - .collect::>>(); + .collect::>>(); trace!("resolved versions: {:?}", self.current_versions); Ok(()) // if plugin.is_installed() { diff --git a/src/env.rs b/src/env.rs index e2074e999..bf6599b81 100644 --- a/src/env.rs +++ b/src/env.rs @@ -84,6 +84,8 @@ lazy_static! { } else { var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) }; + pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); + pub static ref RTX_DISABLE_DIRENV_WARNING: bool = var_is_true("RTX_DISABLE_DIRENV_WARNING"); } fn get_env_diff() -> EnvDiff { diff --git a/src/ui/mod.rs b/src/ui/mod.rs index c5d34f57c..a1237199b 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,5 +1,7 @@ pub mod prompt; pub fn is_tty() -> bool { - atty::is(atty::Stream::Stdin) && atty::is(atty::Stream::Stderr) + atty::is(atty::Stream::Stdin) + && atty::is(atty::Stream::Stderr) + && atty::is(atty::Stream::Stdout) } From 40b994c674ab6f56319ba067458a6e7b5e704a2e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 18:50:33 -0600 Subject: [PATCH 0014/1891] cargo update --- Cargo.lock | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59a08d181..67f7e03ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,9 +287,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b61a7545f753a88bcbe0a70de1fcc0221e10bfc752f576754fa91e663db1622e" +checksum = "322296e2f2e5af4270b54df9e85a02ff037e271af20ba3e7fe1575515dc840b8" dependencies = [ "cc", "cxxbridge-flags", @@ -299,9 +299,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f464457d494b5ed6905c63b0c4704842aba319084a0a3561cdc1359536b53200" +checksum = "017a1385b05d631e7875b1f151c9f012d37b53491e2a87f65bff5c262b2111d8" dependencies = [ "cc", "codespan-reporting", @@ -314,15 +314,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c7119ce3a3701ed81aca8410b9acf6fc399d2629d057b87e2efa4e63a3aaea" +checksum = "c26bbb078acf09bc1ecda02d4223f03bdd28bd4874edcb0379138efc499ce971" [[package]] name = "cxxbridge-macro" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e07508b90551e610910fa648a1878991d367064997a596135b86df30daf07e" +checksum = "357f40d1f06a24b60ae1fe122542c1fb05d28d32acb2aed064e84bc2ad1e252e" dependencies = [ "proc-macro2", "quote", @@ -370,9 +370,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encode_unicode" @@ -1075,9 +1075,6 @@ name = "serde" version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" -dependencies = [ - "serde_derive", -] [[package]] name = "serde_derive" @@ -1298,9 +1295,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729bfd096e40da9c001f778f5cdecbd2957929a24e10e5883d9392220a751581" +checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" dependencies = [ "indexmap", "nom8", From 35b87e5dd77db0cf7b80cbbecf2516088550f478 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 20:01:13 -0600 Subject: [PATCH 0015/1891] fix `rtx where` (#24) Fixes #22 --- README.md | 5 +-- src/cli/current.rs | 3 +- ...li__direnv__envrc__test__direnv_envrc.snap | 2 +- src/cli/env.rs | 4 +-- src/cli/ls.rs | 30 +++++++++--------- src/cli/uninstall.rs | 31 +++++++++++++++---- src/cli/where.rs | 30 +++++++++++++----- src/config/config_file/tool_versions.rs | 2 +- src/config/toolset.rs | 17 ++++++++++ src/runtimes.rs | 10 ------ test/cwd/.tool-versions | 2 +- 11 files changed, 91 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index a64a87e51..daa148bb3 100644 --- a/README.md +++ b/README.md @@ -1040,7 +1040,7 @@ Examples: ### `rtx uninstall` ``` -removes a runtime version +removes runtime versions Usage: uninstall ... @@ -1054,7 +1054,8 @@ Options: Examples: - $ rtx uninstall nodejs + $ rtx uninstall nodejs@18 # will uninstall ALL nodejs-18.x versions + $ rtx uninstall nodejs # will uninstall ALL nodejs versions ``` ### `rtx version` diff --git a/src/cli/current.rs b/src/cli/current.rs index 3d8bba3dd..6d6dd37c0 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -67,9 +67,10 @@ mod test { #[test] fn test_current_with_runtimes() { + assert_cli!("plugin", "add", "shfmt"); assert_cli!("install"); let Output { stdout, .. } = assert_cli!("current", "shfmt"); - let re = Regex::new(r"-> shfmt\s+3\.6\.0\s+").unwrap(); + let re = Regex::new(r"-> shfmt\s+3\.5\.2\s+").unwrap(); assert!(re.is_match(&stdout.content)); } } diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap index b0321f968..0b3065320 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap @@ -6,7 +6,7 @@ expression: envrc watch_file ~/cwd/.tool-versions watch_file ~/cwd/.node-version watch_file ~/.tool-versions -PATH_add ~/data/installs/shfmt/3.6.0/bin +PATH_add ~/data/installs/shfmt/3.5.2/bin PATH_add ~/data/installs/jq/1.6/bin PATH_add ~/data/installs/shellcheck/0.9.0/bin diff --git a/src/cli/env.rs b/src/cli/env.rs index 422b7ab33..f0158678b 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -66,7 +66,7 @@ mod test { let Output { stdout, .. } = assert_cli!("env", "-s", "bash"); assert!(stdout.content.contains( dirs::ROOT - .join("installs/shfmt/3.6.0/bin") + .join("installs/shfmt/3.5.2/bin") .to_string_lossy() .as_ref() )); @@ -80,7 +80,7 @@ mod test { assert!(stdout.content.contains( dirs::ROOT - .join("installs/shfmt/3.5.1/bin") + .join("installs/shfmt/3.5.2/bin") .to_string_lossy() .as_ref() )); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index ad85d889b..3c7792abe 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -89,18 +89,16 @@ fn get_runtime_list( config: &Config, plugin_flag: &Option, ) -> Result, Option)>> { - let mut versions: HashMap<(PluginName, String), Arc> = match plugin_flag { - Some(plugin) => config - .ts - .list_installed_versions() - .into_iter() - .filter(|rtv| &rtv.plugin.name == plugin) - .collect(), - None => config.ts.list_installed_versions(), - } - .into_iter() - .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv)) - .collect(); + let mut versions: HashMap<(PluginName, String), Arc> = config + .ts + .list_installed_versions() + .into_iter() + .filter(|rtv| match plugin_flag { + Some(plugin) => rtv.plugin.name == *plugin, + None => true, + }) + .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv)) + .collect(); let active = config .ts @@ -113,6 +111,10 @@ fn get_runtime_list( active .clone() .into_iter() + .filter(|((plugin_name, _), _)| match plugin_flag { + Some(plugin) => plugin_name == plugin, + None => true, + }) .collect::)>>(), ); @@ -163,9 +165,9 @@ mod test { let re = Regex::new(r" {3}shfmt\s+3\.5\.0\s+").unwrap(); assert!(re.is_match(&stdout.content)); - assert_cli!("uninstall", "shfmt@3.6.0"); + assert_cli!("uninstall", "shfmt@3.5.2"); let Output { stdout, .. } = assert_cli!("list"); - let re = Regex::new(r" {3}shfmt\s+3\.6\.0 \(missing\)\s+").unwrap(); + let re = Regex::new(r" {3}shfmt\s+3\.5\.2 \(missing\)\s+").unwrap(); assert!(re.is_match(&stdout.content)); } } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index b7f5d7dde..af291f6a9 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,14 +1,15 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; +use itertools::Itertools; use owo_colors::OwoColorize; use owo_colors::Stream; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; +use crate::errors::Error::VersionNotInstalled; use crate::output::Output; -use crate::runtimes::RuntimeVersion; -/// removes a runtime version +/// removes runtime versions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct Uninstall { @@ -18,7 +19,7 @@ pub struct Uninstall { } impl Command for Uninstall { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { let runtime_versions = self .runtime .iter() @@ -27,9 +28,26 @@ impl Command for Uninstall { "latest" => "", v => v, }; - RuntimeVersion::find_by_version_prefix(&a.plugin, prefix) + let prefix = config.resolve_alias(&a.plugin, prefix.to_string()); + let mut versions = config.ts.list_current_versions(); + versions.extend(config.ts.list_installed_versions()); + let versions = versions + .into_iter() + .filter(|rtv| rtv.plugin.name == a.plugin) + .filter(|rtv| rtv.version.starts_with(&prefix)) + .unique_by(|rtv| rtv.version.clone()) + .collect::>(); + + if versions.is_empty() { + Err(VersionNotInstalled(a.plugin.clone(), a.version.clone()))? + } else { + Ok(versions) + } }) - .collect::>>()?; + .collect::>>()? + .into_iter() + .flatten() + .collect_vec(); for rtv in runtime_versions { if !rtv.is_installed() { @@ -51,5 +69,6 @@ impl Command for Uninstall { const AFTER_LONG_HELP: &str = r#" Examples: - $ rtx uninstall nodejs + $ rtx uninstall nodejs@18 # will uninstall ALL nodejs-18.x versions + $ rtx uninstall nodejs # will uninstall ALL nodejs versions "#; diff --git a/src/cli/where.rs b/src/cli/where.rs index 6b1e838db..2cd2f5733 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -3,8 +3,8 @@ use color_eyre::eyre::Result; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; +use crate::errors::Error::VersionNotInstalled; use crate::output::Output; -use crate::runtimes::RuntimeVersion; /// Display the installation path for a runtime /// @@ -33,11 +33,20 @@ impl Command for Where { v => v.into(), }; - let prefix = config.resolve_alias(&self.runtime.plugin, prefix); - let rtv = RuntimeVersion::find_by_version_prefix(&self.runtime.plugin, &prefix)?; + let rtv = config + .ts + .find_by_prefix(&config.aliases, &self.runtime.plugin, prefix.as_str()); - rtxprintln!(out, "{}", rtv.install_path.to_string_lossy()); - Ok(()) + match rtv { + Some(rtv) => { + rtxprintln!(out, "{}", rtv.install_path.to_string_lossy()); + Ok(()) + } + None => Err(VersionNotInstalled( + self.runtime.plugin, + self.runtime.version, + ))?, + } } } @@ -49,10 +58,11 @@ Examples: #[cfg(test)] mod test { + use insta::assert_display_snapshot; use pretty_assertions::assert_str_eq; - use crate::assert_cli; use crate::dirs; + use crate::{assert_cli, assert_cli_err}; use super::*; @@ -63,7 +73,7 @@ mod test { let Output { stdout, .. } = assert_cli!("where", "shfmt"); assert_str_eq!( stdout.content.trim(), - dirs::ROOT.join("installs/shfmt/3.6.0").to_string_lossy() + dirs::ROOT.join("installs/shfmt/3.5.2").to_string_lossy() ); } @@ -77,4 +87,10 @@ mod test { dirs::ROOT.join("installs/shfmt/3.0.2").to_string_lossy() ); } + + #[test] + fn test_where_not_found() { + let err = assert_cli_err!("where", "shfmt@1111"); + assert_display_snapshot!(err, @"runtime version not installed: shfmt@1111"); + } } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 02bc05e97..1890da0d7 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -179,7 +179,7 @@ pub(crate) mod tests { assert_display_snapshot!(tv, @r###" #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 - shfmt 3.6.0 # test comment + shfmt 3.5.2 # test comment #nodejs 18.13.0 nodejs system "###); diff --git a/src/config/toolset.rs b/src/config/toolset.rs index 0106bcbb0..8b99d82eb 100644 --- a/src/config/toolset.rs +++ b/src/config/toolset.rs @@ -202,4 +202,21 @@ impl Toolset { pub fn get_source_for_plugin(&self, plugin: &PluginName) -> Option { self.current_versions_sources.get(plugin).cloned() } + + pub fn find_by_prefix( + &self, + aliases: &AliasMap, + plugin: &str, + prefix: &str, + ) -> Option> { + let default_aliases = IndexMap::new(); + let aliases = aliases.get(plugin).unwrap_or(&default_aliases); + let prefix = aliases.get(prefix).cloned().unwrap_or(prefix.to_string()); + + let mut versions = self.list_current_versions(); + versions.extend(self.list_installed_versions()); + versions + .into_iter() + .find(|rtv| rtv.plugin.name == plugin && rtv.version.starts_with(&prefix)) + } } diff --git a/src/runtimes.rs b/src/runtimes.rs index 40ea21d8a..e3c1c7033 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -54,16 +54,6 @@ impl RuntimeVersion { Ok(versions) } - pub fn find_by_version_prefix(plugin: &str, prefix: &str) -> Result { - let rtv = Self::list()? - .into_iter() - .rev() - .find(|rtv| rtv.plugin.name == plugin && rtv.version.starts_with(prefix)) - .ok_or_else(|| VersionNotInstalled(plugin.into(), prefix.into()))?; - - Ok(rtv) - } - pub fn install(&self, install_type: &str, config: &Config) -> Result<()> { debug!( "install {} {} {}", diff --git a/test/cwd/.tool-versions b/test/cwd/.tool-versions index 61455a3f0..c120066de 100644 --- a/test/cwd/.tool-versions +++ b/test/cwd/.tool-versions @@ -1,5 +1,5 @@ #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.6.0 # test comment +shfmt 3.5.2 # test comment #nodejs 18.13.0 nodejs system From 75703054f2a5ca1d69769a6b501082be771e3d20 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 20:01:47 -0600 Subject: [PATCH 0016/1891] chore: Release rtx-cli version 1.2.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67f7e03ae..43c98d552 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -999,7 +999,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.1.1" +version = "1.2.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 4238b64c2..1db89acf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.1.1" +version = "1.2.0" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index daa148bb3..b4a14bf15 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.1.1 +rtx 1.2.0 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ae5e4b4ad..57459cda2 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.1.1 +Version: 1.2.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 3b901fc537ff16cf5affa8c12fcc957daa978db1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 20:05:39 -0600 Subject: [PATCH 0017/1891] fix doc markdown --- README.md | 4 +++- src/cli/render_help.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b4a14bf15..8cf51e58a 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,9 @@ sudo apt install -y rtx > **Warning** > > If you're on arm64 you'll need to run the following: -> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> ``` +> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> ``` ### ~~dnf~~ (coming soon) diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1aa33847f..6229b8a9d 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -183,7 +183,9 @@ sudo apt install -y rtx > **Warning** > > If you're on arm64 you'll need to run the following: -> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> ``` +> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> ``` ### ~~dnf~~ (coming soon) From 3d787565aa91c2d195f403997fc8ad7cfb913676 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 20:14:05 -0600 Subject: [PATCH 0018/1891] chore: Release rtx-cli version 1.2.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43c98d552..d8f3fbc4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -999,7 +999,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.0" +version = "1.2.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 1db89acf1..4758dfbc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.0" +version = "1.2.1" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 8cf51e58a..e13cf2245 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.2.0 +rtx 1.2.1 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 57459cda2..573c2ab18 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.0 +Version: 1.2.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From b353574a2e882d6a25cac528521e2a06a2d7f6ac Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 20:28:28 -0600 Subject: [PATCH 0019/1891] yum/rpm/dnf are working --- README.md | 8 ++++---- packaging/rpm/rtx.repo | 1 - src/cli/render_help.rs | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e13cf2245..73193d8fa 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ $ curl https://github.com/jdxcode/rtx/releases/rtx-latest-macos-arm64.tar.xz | t $ mv rtx/bin/rtx /usr/local/bin ``` -### ~~apt~~ (coming soon) +### apt For installation on Ubuntu/Debian: @@ -169,7 +169,7 @@ sudo apt install -y rtx > echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` -### ~~dnf~~ (coming soon) +### dnf For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: @@ -179,11 +179,11 @@ dnf config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo dnf install -y rtx ``` -### ~~yum~~ (coming soon) +### yum ```sh-session yum install -y yum-utils -yum config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo +yum-config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo yum install -y rtx ``` diff --git a/packaging/rpm/rtx.repo b/packaging/rpm/rtx.repo index a77e7ad00..fe0f99c37 100644 --- a/packaging/rpm/rtx.repo +++ b/packaging/rpm/rtx.repo @@ -4,4 +4,3 @@ baseurl=https://rtx.jdxcode.com/rpm enabled=1 gpgcheck=1 gpgkey=http://rtx.jdxcode.com/gpg-key.pub -Footer diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 6229b8a9d..1b1f7b323 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -169,7 +169,7 @@ $ curl https://github.com/jdxcode/rtx/releases/rtx-latest-macos-arm64.tar.xz | t $ mv rtx/bin/rtx /usr/local/bin ``` -### ~~apt~~ (coming soon) +### apt For installation on Ubuntu/Debian: @@ -187,7 +187,7 @@ sudo apt install -y rtx > echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` -### ~~dnf~~ (coming soon) +### dnf For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: @@ -197,11 +197,11 @@ dnf config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo dnf install -y rtx ``` -### ~~yum~~ (coming soon) +### yum ```sh-session yum install -y yum-utils -yum config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo +yum-config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo yum install -y rtx ``` From 7b5c4de44b4435265a76c929e47ca01f5d92a6cd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 21:26:17 -0600 Subject: [PATCH 0020/1891] aur --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73193d8fa..6f9c03b25 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ For Alpine Linux: apk add rtx --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ ``` -### ~~aur~~ (coming soon) +### aur For Arch Linux: diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1b1f7b323..c8c2bbc9f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -213,7 +213,7 @@ For Alpine Linux: apk add rtx --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ ``` -### ~~aur~~ (coming soon) +### aur For Arch Linux: From 20e8065551da5cfe703e05b78c78f9f0247e0085 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 21:28:07 -0600 Subject: [PATCH 0021/1891] direnv styling --- README.md | 8 ++++---- src/cli/render_help.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6f9c03b25..ec6969bd4 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish > **Warning:** > -> If you use [direnv](https://direnv.net), [see below](#direnv) for direnv-compatible setup. +> If you use direnv, [see below](#direnv) for direnv-compatible setup. Install a runtime and set it as the default: @@ -1155,9 +1155,9 @@ That said, there are a lot of great things about asdf. It's the best multi-runti and I've really been impressed with the plugin system. Most of the design decisions the authors made were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. -## Direnv +## direnv -Direnv and rtx both manage environment variables based on directory. Because they both analyze +[direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze the current environment variables before and after their respective "hook" commands are run, they can easily conflict and overwrite each other's environment variables (including, but not limited to, `PATH`). @@ -1177,7 +1177,7 @@ Now in your `.envrc` file add the following: use_rtx ``` -Direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` +direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). ## Cache Behavior diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index c8c2bbc9f..fbe51f799 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -46,7 +46,7 @@ $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish > **Warning:** > -> If you use [direnv](https://direnv.net), [see below](#direnv) for direnv-compatible setup. +> If you use direnv, [see below](#direnv) for direnv-compatible setup. Install a runtime and set it as the default: @@ -534,9 +534,9 @@ That said, there are a lot of great things about asdf. It's the best multi-runti and I've really been impressed with the plugin system. Most of the design decisions the authors made were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. -## Direnv +## direnv -Direnv and rtx both manage environment variables based on directory. Because they both analyze +[direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze the current environment variables before and after their respective "hook" commands are run, they can easily conflict and overwrite each other's environment variables (including, but not limited to, `PATH`). @@ -556,7 +556,7 @@ Now in your `.envrc` file add the following: use_rtx ``` -Direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` +direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). ## Cache Behavior From 4e0e4f7a5162f60810d26d218f148357085385a4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 21:28:51 -0600 Subject: [PATCH 0022/1891] fixed direnv instructions --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ec6969bd4..097216892 100644 --- a/README.md +++ b/README.md @@ -1174,7 +1174,7 @@ $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh Now in your `.envrc` file add the following: ```sh-session -use_rtx +use rtx ``` direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index fbe51f799..14c4fc3de 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -553,7 +553,7 @@ $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh Now in your `.envrc` file add the following: ```sh-session -use_rtx +use rtx ``` direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` From 1d2b65b7a9dc9fe7f1edc10b41996af2ee3d6353 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 21:31:30 -0600 Subject: [PATCH 0023/1891] readme styling --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 097216892..59a817752 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ $ echo 'eval "$(rtx activate -s zsh)"' >> ~/.zshrc $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` -> **Warning:** +> **Warning** > > If you use direnv, [see below](#direnv) for direnv-compatible setup. diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 14c4fc3de..03bef7d48 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -44,7 +44,7 @@ $ echo 'eval "$(rtx activate -s zsh)"' >> ~/.zshrc $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` -> **Warning:** +> **Warning** > > If you use direnv, [see below](#direnv) for direnv-compatible setup. From 0f40f68cd7f1ba8bd58227a147b044266d927852 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 22:32:52 -0600 Subject: [PATCH 0024/1891] refactor osstring stuff --- src/cli/activate.rs | 9 --------- src/cli/direnv/envrc.rs | 4 ++-- src/cli/env.rs | 6 +++--- src/cli/exec.rs | 23 +++++++++++++++++++---- src/cli/hook_env.rs | 4 ++-- src/config/mod.rs | 8 ++++---- src/env.rs | 1 - src/runtimes.rs | 2 +- 8 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 5da704a32..d7aae7bcb 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,5 +1,4 @@ use color_eyre::eyre::Result; -use indoc::indoc; use crate::cli::command::Command; use crate::config::Config; @@ -22,14 +21,6 @@ pub struct Activate { impl Command for Activate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - if !*env::RTX_DISABLE_DIRENV_WARNING && env::DIRENV_DIR.is_some() { - warn!(indoc! {r#" - `rtx activate` may conflict with direnv! - See https://github.com/jdxcode/rtx#direnv for more information. - Disable this warning with RTX_DISABLE_DIRENV_WARNING=1 - "#}); - } - let shell = get_shell(self.shell); let exe = if cfg!(test) { diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index ebcfaf150..20d33271d 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -42,8 +42,8 @@ impl Command for Envrc { writeln!( file, "export {}={}", - shell_escape::unix::escape(k.to_string_lossy()), - shell_escape::unix::escape(v.to_string_lossy()), + shell_escape::unix::escape(k.into()), + shell_escape::unix::escape(v.into()), )?; } for path in &config.list_paths()? { diff --git a/src/cli/env.rs b/src/cli/env.rs index f0158678b..7561b5dba 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -32,14 +32,14 @@ impl Command for Env { let shell = get_shell(self.shell); for (k, v) in config.env()? { - let k = k.to_string_lossy().to_string(); - let v = v.to_string_lossy().to_string(); + let k = k.to_string(); + let v = v.to_string(); rtxprint!(out, "{}", shell.set_env(&k, &v)); } rtxprintln!( out, "{}", - shell.set_env("PATH", config.path_env()?.to_string_lossy().as_ref()) + shell.set_env("PATH", config.path_env()?.as_ref()) ); Ok(()) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 7c38fa762..68d02473f 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -1,6 +1,7 @@ -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use color_eyre::eyre::{eyre, Result}; +use duct::IntoExecutablePath; use indexmap::IndexMap; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; @@ -54,16 +55,30 @@ impl Command for Exec { } #[cfg(not(test))] -fn exec(program: OsString, args: Vec, env: IndexMap) -> Result<()> { +fn exec(program: T, args: U, env: IndexMap) -> Result<()> +where + T: IntoExecutablePath, + U: IntoIterator, + U::Item: Into, + E: AsRef, +{ for (k, v) in env.iter() { env::set_var(k, v); } + let args = args.into_iter().map(Into::into).collect::>(); + let program = program.to_executable(); let err = exec::Command::new(program.clone()).args(&args).exec(); - Err(eyre!("{:?} {}", program, err)) + Err(eyre!("{:?} {}", program.to_string_lossy(), err.to_string())) } #[cfg(test)] -fn exec(program: OsString, args: Vec, env: IndexMap) -> Result<()> { +fn exec(program: T, args: U, env: IndexMap) -> Result<()> +where + T: IntoExecutablePath, + U: IntoIterator, + U::Item: Into, + E: AsRef, +{ let mut cmd = cmd::cmd(program, args); for (k, v) in env.iter() { cmd = cmd.env(k, v); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 347c55a90..1579bc160 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -31,9 +31,9 @@ impl Command for HookEnv { let mut env: HashMap = config .env()? .iter() - .map(|(k, v)| (k.to_string_lossy().into(), v.to_string_lossy().into())) + .map(|(k, v)| (k.into(), v.into())) .collect(); - env.insert("PATH".into(), config.path_env()?.to_string_lossy().into()); + env.insert("PATH".into(), config.path_env()?.into()); env.insert("__RTX_DIR".into(), dirs::CURRENT.to_string_lossy().into()); let diff = EnvDiff::new(&env::PRISTINE_ENV, &env); let mut patches = diff.to_patches(); diff --git a/src/config/mod.rs b/src/config/mod.rs index ccc23e335..c21eaa90f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -63,13 +63,13 @@ impl Config { Ok(config) } - pub fn env(&self) -> Result> { + pub fn env(&self) -> Result> { let mut entries = self .ts .list_current_installed_versions() .into_par_iter() .map(|p| p.exec_env()) - .collect::>>>()? + .collect::>>>()? .into_iter() .flatten() .collect_vec(); @@ -90,7 +90,7 @@ impl Config { Ok(paths) } - pub fn path_env(&self) -> Result { + pub fn path_env(&self) -> Result { let mut paths = self.list_paths()?; let default_path = String::new(); let orig_path = env::PRISTINE_ENV.get("PATH").unwrap_or(&default_path); @@ -101,7 +101,7 @@ impl Config { } paths.push(p); } - Ok(join_paths(paths)?) + Ok(join_paths(paths)?.to_string_lossy().into()) } pub fn with_runtime_args(mut self, args: &[RuntimeArg]) -> Result { diff --git a/src/env.rs b/src/env.rs index bf6599b81..c0997fd6a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -85,7 +85,6 @@ lazy_static! { var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) }; pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); - pub static ref RTX_DISABLE_DIRENV_WARNING: bool = var_is_true("RTX_DISABLE_DIRENV_WARNING"); } fn get_env_diff() -> EnvDiff { diff --git a/src/runtimes.rs b/src/runtimes.rs index e3c1c7033..e94638d11 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -188,7 +188,7 @@ impl RuntimeVersion { Ok(()) } - pub fn exec_env(&self) -> Result> { + pub fn exec_env(&self) -> Result> { let script = self.plugin.plugin_path.join("bin/exec-env"); if !self.is_installed() || !script.exists() { return Ok(HashMap::new()); From 2ddd8c9a2b5634d16ceb2e9d931f0dadadcd4c32 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 22:33:49 -0600 Subject: [PATCH 0025/1891] refactor osstring stuff --- src/cli/hook_env.rs | 2 +- src/config/mod.rs | 2 +- src/runtimes.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 1579bc160..966028efb 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -33,7 +33,7 @@ impl Command for HookEnv { .iter() .map(|(k, v)| (k.into(), v.into())) .collect(); - env.insert("PATH".into(), config.path_env()?.into()); + env.insert("PATH".into(), config.path_env()?); env.insert("__RTX_DIR".into(), dirs::CURRENT.to_string_lossy().into()); let diff = EnvDiff::new(&env::PRISTINE_ENV, &env); let mut patches = diff.to_patches(); diff --git a/src/config/mod.rs b/src/config/mod.rs index c21eaa90f..da9695984 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::env::{join_paths, split_paths}; -use std::ffi::OsString; + use std::fmt::{Display, Formatter}; use std::ops::Deref; use std::path::{Path, PathBuf}; diff --git a/src/runtimes.rs b/src/runtimes.rs index e94638d11..faf465f62 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::error::Error; -use std::ffi::OsString; + use std::fmt; use std::fmt::{Display, Formatter}; use std::fs::{create_dir_all, remove_dir_all, File}; @@ -200,8 +200,8 @@ impl RuntimeVersion { .to_patches() .into_iter() .filter_map(|p| match p { - EnvDiffOperation::Add(key, value) => Some((key.into(), value.into())), - EnvDiffOperation::Change(key, value) => Some((key.into(), value.into())), + EnvDiffOperation::Add(key, value) => Some((key, value)), + EnvDiffOperation::Change(key, value) => Some((key, value)), _ => None, }) .collect(); From cfa2ca6da6150f244f1058e15a11842c40560978 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 27 Jan 2023 22:43:00 -0600 Subject: [PATCH 0026/1891] refactoring strings --- src/cli/hook_env.rs | 10 ++-------- src/env_diff.rs | 41 +++++++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 966028efb..7f9a367a8 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use color_eyre::eyre::Result; use crate::cli::command::Command; @@ -28,14 +26,10 @@ impl Command for HookEnv { config.ensure_installed()?; self.clear_old_env(out); - let mut env: HashMap = config - .env()? - .iter() - .map(|(k, v)| (k.into(), v.into())) - .collect(); + let mut env = config.env()?; env.insert("PATH".into(), config.path_env()?); env.insert("__RTX_DIR".into(), dirs::CURRENT.to_string_lossy().into()); - let diff = EnvDiff::new(&env::PRISTINE_ENV, &env); + let diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); patches.push(EnvDiffOperation::Add( "__RTX_DIFF".into(), diff --git a/src/env_diff.rs b/src/env_diff.rs index a79c1a53f..3e6e68e6a 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -31,19 +31,23 @@ pub enum EnvDiffOperation { pub type EnvDiffPatches = Vec; impl EnvDiff { - pub fn new(original: &HashMap, additions: &HashMap) -> EnvDiff { + pub fn new(original: &HashMap, additions: T) -> EnvDiff + where + T: IntoIterator, + { let mut diff = EnvDiff::default(); - for (key, new_val) in additions.iter() { - match original.get(key) { + for (key, new_val) in additions.into_iter() { + let key: String = key; + match original.get(&key) { Some(original_val) => { - if original_val != new_val { - diff.old.insert(key.into(), original_val.into()); - diff.new.insert(key.into(), new_val.into()); + if original_val != &new_val { + diff.old.insert(key.clone(), original_val.into()); + diff.new.insert(key, new_val); } } None => { - diff.new.insert(key.into(), new_val.into()); + diff.new.insert(key, new_val); } } } @@ -77,7 +81,7 @@ impl EnvDiff { } additions.insert(k.into(), v.into()); } - Ok(Self::new(&env::vars().collect(), &additions)) + Ok(Self::new(&env::vars().collect(), additions)) } pub fn deserialize(raw: &str) -> Result { @@ -140,6 +144,7 @@ impl Debug for EnvDiff { #[cfg(test)] mod tests { + use indexmap::indexmap; use insta::assert_debug_snapshot; use crate::dirs; @@ -148,13 +153,13 @@ mod tests { #[test] fn test_diff() { - let diff = EnvDiff::new(&new_from_hashmap(), &new_to_hashmap()); + let diff = EnvDiff::new(&new_from_hashmap(), new_to_hashmap()); assert_debug_snapshot!(diff.to_patches()); } #[test] fn test_reverse() { - let diff = EnvDiff::new(&new_from_hashmap(), &new_to_hashmap()); + let diff = EnvDiff::new(&new_from_hashmap(), new_to_hashmap()); let patches = diff.reverse().to_patches(); let to_remove = patches .iter() @@ -203,7 +208,7 @@ mod tests { #[test] fn test_serialize() { - let diff = EnvDiff::new(&new_from_hashmap(), &new_to_hashmap()); + let diff = EnvDiff::new(&new_from_hashmap(), new_to_hashmap()); let serialized = diff.serialize().unwrap(); let deserialized = EnvDiff::deserialize(&serialized).unwrap(); assert_debug_snapshot!(deserialized.to_patches()); @@ -212,13 +217,13 @@ mod tests { #[test] fn test_from_bash_script() { let path = dirs::HOME.join("fixtures/exec-env"); - let orig = HashMap::from( - [ - ("UNMODIFIED_VAR", "unmodified"), - ("MODIFIED_VAR", "original"), - ] - .map(|(k, v)| (k.into(), v.into())), - ); + let orig = indexmap! { + "UNMODIFIED_VAR" => "unmodified", + "MODIFIED_VAR" => "original", + } + .into_iter() + .map(|(k, v)| (k.into(), v.into())) + .collect::>(); let ed = EnvDiff::from_bash_script(path.as_path(), orig).unwrap(); assert_debug_snapshot!(ed); } From 81b3b57c1182ddd3306eab9bf273a0e2783e0def Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 06:29:40 -0600 Subject: [PATCH 0027/1891] use exec method for direnv (#26) --- .github/workflows/rtx.yml | 19 +++--- .tool-versions | 1 - Cargo.lock | 18 ++++++ Cargo.toml | 1 + e2e/run_all_tests | 1 + e2e/test_local | 2 - justfile | 10 +++- src/cli/activate.rs | 6 +- src/cli/alias/ls.rs | 5 +- src/cli/asdf.rs | 10 ++-- src/cli/current.rs | 10 ++-- src/cli/deactivate.rs | 6 +- src/cli/direnv/activate.rs | 3 +- src/cli/direnv/envrc.rs | 13 ++-- src/cli/direnv/exec.rs | 59 +++++++++++++++++++ src/cli/direnv/mod.rs | 3 + ...li__direnv__envrc__test__direnv_envrc.snap | 2 + src/cli/env.rs | 23 ++++---- src/cli/exec.rs | 6 +- src/cli/global.rs | 13 ++-- src/cli/latest.rs | 14 ++--- src/cli/local.rs | 18 +++--- src/cli/ls.rs | 12 ++-- src/cli/ls_remote.rs | 6 +- src/cli/mod.rs | 12 ++-- src/cli/plugins/install.rs | 14 ++--- src/cli/plugins/ls.rs | 34 +++++------ src/cli/plugins/ls_remote.rs | 5 +- ...ns__install__test__plugin_install_url.snap | 11 ++++ ...__uninstall__test__plugin_uninstall-2.snap | 3 +- ...ns__uninstall__test__plugin_uninstall.snap | 3 +- src/cli/plugins/uninstall.rs | 9 ++- src/cli/render_help.rs | 6 +- src/cli/settings/get.rs | 5 +- src/cli/settings/ls.rs | 6 +- src/cli/settings/set.rs | 10 ++-- ..._cli__settings__ls__test__settings_ls.snap | 3 +- ...__settings__set__test__settings_set-2.snap | 3 +- ...li__settings__set__test__settings_set.snap | 3 +- src/cli/settings/unset.rs | 10 ++-- ...tx__cli__activate__test__activate_zsh.snap | 3 +- ...cli__deactivate__test__deactivate_zsh.snap | 3 +- .../rtx__cli__global__test__global-2.snap | 3 +- .../rtx__cli__global__test__global-3.snap | 3 +- .../rtx__cli__global__test__global.snap | 3 +- .../rtx__cli__latest__test__latest.snap | 3 +- ...cli__latest__test__latest_asdf_format.snap | 3 +- .../rtx__cli__local__test__local-2.snap | 3 +- .../rtx__cli__local__test__local-3.snap | 3 +- .../rtx__cli__local__test__local.snap | 3 +- src/cli/where.rs | 10 ++-- src/config/toolset.rs | 13 ++-- src/env.rs | 1 + src/git.rs | 14 +++++ src/plugins.rs | 5 ++ src/test.rs | 14 ++++- test/.tool-versions | 1 + 57 files changed, 288 insertions(+), 198 deletions(-) create mode 100644 src/cli/direnv/exec.rs create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 745a01e54..27b44815d 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -16,12 +16,15 @@ jobs: unit: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 - name: Rust Cache uses: Swatinem/rust-cache@v2 + - name: Install direnv + run: sudo apt-get update; sudo apt-get install direnv - name: Install just uses: taiki-e/install-action@just - - name: just test-unit + - name: Run just test-unit uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} @@ -33,17 +36,19 @@ jobs: coverage: runs-on: ubuntu-latest - #if: false container: image: xd009642/tarpaulin:develop-nightly options: --security-opt seccomp=unconfined steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 - name: Rust Cache uses: Swatinem/rust-cache@v2 + - name: Install direnv + run: curl -sfL https://direnv.net/install.sh | bash - name: Install just uses: taiki-e/install-action@just - - name: Generate code coverage + - name: Run tests with coverage uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} @@ -123,8 +128,8 @@ jobs: needs: [ build-linux ] steps: - uses: actions/checkout@v3 - - name: Install zsh/fish - run: sudo apt-get update; sudo apt-get install zsh fish + - name: Install zsh/fish/direnv + run: sudo apt-get update; sudo apt-get install zsh fish direnv - uses: actions/download-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu diff --git a/.tool-versions b/.tool-versions index a775f9b91..c638108e3 100644 --- a/.tool-versions +++ b/.tool-versions @@ -2,5 +2,4 @@ shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 -nodejs system jq latest diff --git a/Cargo.lock b/Cargo.lock index d8f3fbc4e..7932e5d17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1028,6 +1028,7 @@ dependencies = [ "rmp-serde", "serde", "serde_derive", + "serde_json", "shell-escape", "simplelog", "tempfile", @@ -1058,6 +1059,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + [[package]] name = "scopeguard" version = "1.1.0" @@ -1087,6 +1094,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_spanned" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index 4758dfbc6..3824fd981 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ toml_edit = "0.18.0" url = "2.3.1" versions = "4.1.0" build-time = "0.1.2" +serde_json = "1.0.91" [target.'cfg(unix)'.dependencies] exec = "0.3.1" diff --git a/e2e/run_all_tests b/e2e/run_all_tests index 379b35dfa..777066559 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -4,6 +4,7 @@ set -euo pipefail export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="/tmp/rtx" export PATH="$PWD/target/debug:$PATH" +unset GOPATH rtx plugin add nodejs rtx plugin add shfmt diff --git a/e2e/test_local b/e2e/test_local index 983c877b6..7db1c2893 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -11,7 +11,6 @@ assert "rtx local -p" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 -nodejs system jq latest " @@ -19,7 +18,6 @@ assert "rtx local -p shfmt@3.5.0" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.5.0 # test comment #nodejs 18.13.0 -nodejs system jq latest " diff --git a/justfile b/justfile index 7ce9e1c8d..170a6fc43 100644 --- a/justfile +++ b/justfile @@ -17,7 +17,6 @@ alias t := test test: test-unit test-e2e test-setup: build - rtx install test-update-snapshots: test-setup cargo insta test --accept @@ -28,12 +27,17 @@ test-unit: test-setup test-e2e: test-setup build ./e2e/run_all_tests -test-coverage: test-setup - rtx --version +test-coverage: clean test-setup cargo +nightly tarpaulin \ --all-features --workspace \ --timeout 120 --out Xml --ignore-tests +clean: + cargo clean + rm -rf target + rm -rf *.profraw + rm -rf coverage + lint: cargo clippy cargo fmt --all -- --check diff --git a/src/cli/activate.rs b/src/cli/activate.rs index d7aae7bcb..210f2f7e7 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -48,11 +48,9 @@ mod test { use crate::assert_cli; - use super::*; - #[test] fn test_activate_zsh() { - let Output { stdout, .. } = assert_cli!("activate", "-s", "zsh"); - assert_display_snapshot!(stdout.content); + let stdout = assert_cli!("activate", "-s", "zsh"); + assert_display_snapshot!(stdout); } } diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 8b758be3d..32792cc12 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -49,12 +49,11 @@ const AFTER_LONG_HELP: &str = indoc! {r#" mod test { use crate::assert_cli; use crate::cli::test::ensure_plugin_installed; - use crate::output::Output; #[test] fn test_alias_ls() { ensure_plugin_installed("shfmt"); - let Output { stdout, .. } = assert_cli!("aliases"); - assert!(stdout.content.contains("my/alias")); + let stdout = assert_cli!("aliases"); + assert!(stdout.contains("my/alias")); } } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 6c534fba3..a2176cb0d 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -63,19 +63,17 @@ fn list_versions(out: &mut Output, args: &Vec) -> Result<()> { mod test { use crate::assert_cli; - use super::*; - #[test] fn test_fake_asdf() { - let Output { stdout, .. } = assert_cli!("asdf", "-v"); - assert!(stdout.content.starts_with("rtx ")); + let stdout = assert_cli!("asdf", "-v"); + assert!(stdout.starts_with("rtx ")); } #[test] fn test_fake_asdf_list() { assert_cli!("plugin", "install", "shfmt"); assert_cli!("install", "shfmt@2"); - let Output { stdout, .. } = assert_cli!("asdf", "list", "shfmt"); - assert!(stdout.content.contains('2')); + let stdout = assert_cli!("asdf", "list", "shfmt"); + assert!(stdout.contains('2')); } } diff --git a/src/cli/current.rs b/src/cli/current.rs index 6d6dd37c0..6e1ac8a20 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -54,23 +54,21 @@ mod test { use crate::assert_cli; - use super::*; - #[test] fn test_current() { assert_cli!("plugin", "add", "shellcheck"); assert_cli!("install"); - let Output { stdout, .. } = assert_cli!("current"); + let stdout = assert_cli!("current"); let re = Regex::new(r"-> shellcheck\s+0\.9\.0\s+").unwrap(); - assert!(re.is_match(&stdout.content)); + assert!(re.is_match(&stdout)); } #[test] fn test_current_with_runtimes() { assert_cli!("plugin", "add", "shfmt"); assert_cli!("install"); - let Output { stdout, .. } = assert_cli!("current", "shfmt"); + let stdout = assert_cli!("current", "shfmt"); let re = Regex::new(r"-> shfmt\s+3\.5\.2\s+").unwrap(); - assert!(re.is_match(&stdout.content)); + assert!(re.is_match(&stdout)); } } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 3aa0bcc5f..6bede6091 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -42,12 +42,10 @@ mod test { use crate::assert_cli; - use super::*; - #[test] fn test_deactivate_zsh() { std::env::set_var("NO_COLOR", "1"); - let Output { stdout, .. } = assert_cli!("deactivate", "-s", "zsh"); - assert_display_snapshot!(stdout.content); + let stdout = assert_cli!("deactivate", "-s", "zsh"); + assert_display_snapshot!(stdout); } } diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 8f0ff10bc..d3ea81ef3 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -20,10 +20,11 @@ impl Command for DirenvActivate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { rtxprintln!( out, + // source_env "$(rtx direnv envrc "$@")" indoc! {r#" ### Do not edit. This was autogenerated by 'rtx direnv' ### use_rtx() {{ - source_env "$(rtx direnv envrc "$@")" + direnv_load rtx direnv exec }} "#} ); diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 20d33271d..ee209775a 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -5,11 +5,11 @@ use std::ops::Deref; use color_eyre::eyre::Result; use crate::cli::command::Command; -use crate::config::settings::MissingRuntimeBehavior::{AutoInstall, Warn}; +use crate::config::settings::MissingRuntimeBehavior::{Prompt, Warn}; use crate::config::Config; -use crate::dirs; use crate::hash::hash_to_str; use crate::output::Output; +use crate::{dirs, env}; /// [internal] This is an internal command that writes an envrc file /// for direnv to consume. @@ -19,11 +19,11 @@ pub struct Envrc {} impl Command for Envrc { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - if config.settings.missing_runtime_behavior == AutoInstall { + if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } config.ensure_installed()?; - let envrc_path = dirs::ROOT + let envrc_path = env::RTX_TMP_DIR .join("direnv") .join(hash_to_str(dirs::CURRENT.deref()) + ".envrc"); @@ -67,8 +67,9 @@ mod test { #[test] fn test_direnv_envrc() { - let Output { stdout, .. } = assert_cli!("direnv", "envrc"); - let envrc = fs::read_to_string(stdout.content.trim()).unwrap(); + assert_cli!("install"); + let stdout = assert_cli!("direnv", "envrc"); + let envrc = fs::read_to_string(stdout.trim()).unwrap(); let envrc = envrc.replace(dirs::HOME.to_string_lossy().as_ref(), "~"); assert_display_snapshot!(envrc); } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs new file mode 100644 index 000000000..aecbbf9ea --- /dev/null +++ b/src/cli/direnv/exec.rs @@ -0,0 +1,59 @@ +use color_eyre::eyre::Result; +use serde_derive::Deserialize; + +use crate::cli::command::Command; +use crate::cmd; +use crate::config::settings::MissingRuntimeBehavior::{Prompt, Warn}; +use crate::config::Config; +use crate::output::Output; + +/// [internal] This is an internal command that writes an envrc file +/// for direnv to consume. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, hide = true)] +pub struct DirenvExec {} + +#[derive(Debug, Default, Deserialize)] +struct DirenvWatches { + #[serde(rename(deserialize = "DIRENV_WATCHES"))] + watches: String, +} + +impl Command for DirenvExec { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + if config.settings.missing_runtime_behavior == Prompt { + config.settings.missing_runtime_behavior = Warn; + } + config.ensure_installed()?; + let mut cmd = if cfg!(test) { + cmd!("env") + } else { + cmd!("direnv", "dump") + }; + + for (k, v) in config.env()? { + cmd = cmd.env(k, v); + } + cmd = cmd.env("PATH", config.path_env()?); + + let json = cmd!("direnv", "watch", "json", ".tool-versions").read()?; + let w: DirenvWatches = serde_json::from_str(&json)?; + cmd = cmd.env("DIRENV_WATCHES", w.watches); + + rtxprint!(out, "{}", cmd.read()?); + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::assert_cli; + use crate::cli::test::grep; + use pretty_assertions::assert_str_eq; + + #[test] + fn test_direnv_exec() { + let stdout = assert_cli!("direnv", "exec"); + assert_str_eq!(grep(stdout, "JDXCODE_TINY="), "JDXCODE_TINY=2.1.0"); + } +} diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index 57343bd0e..54115c3f1 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -7,6 +7,7 @@ use crate::output::Output; mod activate; mod envrc; +mod exec; /// Output direnv function to use rtx inside direnv /// @@ -25,6 +26,7 @@ pub struct Direnv { #[derive(Debug, Subcommand)] enum Commands { Envrc(envrc::Envrc), + Exec(exec::DirenvExec), Activate(activate::DirenvActivate), } @@ -33,6 +35,7 @@ impl Commands { match self { Self::Activate(cmd) => cmd.run(config, out), Self::Envrc(cmd) => cmd.run(config, out), + Self::Exec(cmd) => cmd.run(config, out), } } } diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap index 0b3065320..915c992ad 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap @@ -6,7 +6,9 @@ expression: envrc watch_file ~/cwd/.tool-versions watch_file ~/cwd/.node-version watch_file ~/.tool-versions +export JDXCODE_TINY=2.1.0 PATH_add ~/data/installs/shfmt/3.5.2/bin PATH_add ~/data/installs/jq/1.6/bin +PATH_add ~/data/installs/tiny/2.1.0/bin PATH_add ~/data/installs/shellcheck/0.9.0/bin diff --git a/src/cli/env.rs b/src/cli/env.rs index 7561b5dba..80eb57b27 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -56,15 +56,16 @@ Examples: #[cfg(test)] mod test { use crate::assert_cli; + use crate::cli::test::grep; use crate::dirs; - use crate::output::Output; + use pretty_assertions::assert_str_eq; #[test] fn test_env() { assert_cli!("plugin", "add", "shfmt"); assert_cli!("install"); - let Output { stdout, .. } = assert_cli!("env", "-s", "bash"); - assert!(stdout.content.contains( + let stdout = assert_cli!("env", "-s", "bash"); + assert!(stdout.contains( dirs::ROOT .join("installs/shfmt/3.5.2/bin") .to_string_lossy() @@ -76,9 +77,9 @@ mod test { fn test_env_with_runtime_arg() { assert_cli!("plugin", "add", "shfmt"); assert_cli!("install", "shfmt@3.5"); - let Output { stdout, .. } = assert_cli!("env", "shfmt@3.5", "-s", "bash"); + let stdout = assert_cli!("env", "shfmt@3.5", "-s", "bash"); - assert!(stdout.content.contains( + assert!(stdout.contains( dirs::ROOT .join("installs/shfmt/3.5.2/bin") .to_string_lossy() @@ -90,8 +91,8 @@ mod test { fn test_env_alias() { assert_cli!("plugin", "add", "shfmt"); assert_cli!("install", "shfmt@my/alias"); - let Output { stdout, .. } = assert_cli!("env", "shfmt@my/alias", "-s", "bash"); - assert!(stdout.content.contains( + let stdout = assert_cli!("env", "shfmt@my/alias", "-s", "bash"); + assert!(stdout.contains( dirs::ROOT .join("installs/shfmt/3.0.2") .to_string_lossy() @@ -100,10 +101,8 @@ mod test { } #[test] - fn test_env_golang() { - assert_cli!("plugin", "add", "golang"); - assert_cli!("install", "golang"); - let Output { stdout, .. } = assert_cli!("env", "golang", "-s", "bash"); - assert!(stdout.content.contains("GOROOT=")); + fn test_env_tiny() { + let stdout = assert_cli!("env", "tiny@1", "-s", "bash"); + assert_str_eq!(grep(stdout, "JDXCODE"), "export JDXCODE_TINY=1.0.1"); } } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 68d02473f..00cf8c72e 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -121,17 +121,13 @@ mod test { #[test] fn test_exec_ok() { - assert_cli!("plugin", "a", "jq"); - assert_cli!("install"); assert_cli!("exec", "--", "jq", "--version"); } #[test] fn test_exec_fail() { - assert_cli!("install"); - assert_cli!("install", "nodejs"); let _ = cli_run( - &vec!["rtx", "exec", "--", "node", "-e", "process.exit(1)"] + &vec!["rtx", "exec", "--", "jq", "-invalid"] .into_iter() .map(String::from) .collect::>(), diff --git a/src/cli/global.rs b/src/cli/global.rs index 03efb0d7d..4b7a51287 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -76,7 +76,6 @@ mod test { use insta::assert_snapshot; - use crate::output::Output; use crate::{assert_cli, dirs}; #[test] @@ -86,12 +85,12 @@ mod test { let _ = fs::remove_file(&cf_path); assert_cli!("install", "shfmt@2"); - let Output { stdout, .. } = assert_cli!("global", "shfmt@2"); - assert_snapshot!(stdout.content); - let Output { stdout, .. } = assert_cli!("global", "--fuzzy", "shfmt@2"); - assert_snapshot!(stdout.content); - let Output { stdout, .. } = assert_cli!("global", "--remove", "nodejs"); - assert_snapshot!(stdout.content); + let stdout = assert_cli!("global", "shfmt@2"); + assert_snapshot!(stdout); + let stdout = assert_cli!("global", "--fuzzy", "shfmt@2"); + assert_snapshot!(stdout); + let stdout = assert_cli!("global", "--remove", "nodejs"); + assert_snapshot!(stdout); if let Some(orig) = orig { fs::write(cf_path, orig).unwrap(); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 1c6e6006d..0f409edab 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -54,25 +54,23 @@ mod test { use crate::assert_cli; - use super::*; - #[test] fn test_latest() { assert_cli!("plugins", "install", "nodejs"); - let Output { stdout, .. } = assert_cli!("latest", "nodejs@12"); - assert_display_snapshot!(stdout.content); + let stdout = assert_cli!("latest", "nodejs@12"); + assert_display_snapshot!(stdout); } #[test] fn test_latest_ruby() { assert_cli!("plugins", "install", "ruby"); - let Output { stdout, .. } = assert_cli!("latest", "ruby"); - assert!(stdout.content.starts_with("3.")); + let stdout = assert_cli!("latest", "ruby"); + assert!(stdout.starts_with("3.")); } #[test] fn test_latest_asdf_format() { - let Output { stdout, .. } = assert_cli!("latest", "nodejs", "12"); - assert_display_snapshot!(stdout.content); + let stdout = assert_cli!("latest", "nodejs", "12"); + assert_display_snapshot!(stdout); } } diff --git a/src/cli/local.rs b/src/cli/local.rs index a07164d84..49f659fbb 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -101,7 +101,7 @@ mod test { use pretty_assertions::assert_str_eq; use crate::cli::test::grep; - use crate::output::Output; + use crate::{assert_cli, dirs}; #[test] @@ -111,15 +111,15 @@ mod test { assert_cli!("plugin", "add", "nodejs"); assert_cli!("install", "shfmt@2"); - let Output { stdout, .. } = assert_cli!("local", "shfmt@2"); - assert_snapshot!(stdout.content); - let Output { stdout, .. } = assert_cli!("local", "--fuzzy", "shfmt@2"); - assert_snapshot!(stdout.content); - let Output { stdout, .. } = assert_cli!("local", "--remove", "nodejs"); - assert_snapshot!(stdout.content); - let Output { stdout, .. } = assert_cli!("ls", "--current"); + let stdout = assert_cli!("local", "shfmt@2"); + assert_snapshot!(stdout); + let stdout = assert_cli!("local", "--fuzzy", "shfmt@2"); + assert_snapshot!(stdout); + let stdout = assert_cli!("local", "--remove", "nodejs"); + assert_snapshot!(stdout); + let stdout = assert_cli!("ls", "--current"); assert_str_eq!( - grep(&stdout, "nodejs").unwrap(), + grep(stdout, "nodejs"), " nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)" ); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 3c7792abe..dca52d336 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -153,21 +153,19 @@ mod test { use crate::assert_cli; - use super::*; - #[test] fn test_list() { assert_cli!("install"); assert_cli!("install", "shfmt@3.5.0"); - let Output { stdout, .. } = assert_cli!("list"); + let stdout = assert_cli!("list"); let re = Regex::new(r"-> shellcheck\s+0\.9\.0\s+").unwrap(); - assert!(re.is_match(&stdout.content)); + assert!(re.is_match(&stdout)); let re = Regex::new(r" {3}shfmt\s+3\.5\.0\s+").unwrap(); - assert!(re.is_match(&stdout.content)); + assert!(re.is_match(&stdout)); assert_cli!("uninstall", "shfmt@3.5.2"); - let Output { stdout, .. } = assert_cli!("list"); + let stdout = assert_cli!("list"); let re = Regex::new(r" {3}shfmt\s+3\.5\.2 \(missing\)\s+").unwrap(); - assert!(re.is_match(&stdout.content)); + assert!(re.is_match(&stdout)); } } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 4705e0989..29b503fb1 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -44,12 +44,10 @@ mod test { use crate::assert_cli; use crate::cli::test::ensure_plugin_installed; - use super::*; - #[test] fn test_list_remote() { ensure_plugin_installed("nodejs"); - let Output { stdout, .. } = assert_cli!("list-remote", "nodejs"); - assert!(stdout.content.contains("18.0.0")); + let stdout = assert_cli!("list-remote", "nodejs"); + assert!(stdout.contains("18.0.0")); } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2bc96ca9f..d8898d47b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -172,9 +172,11 @@ const AFTER_HELP: &str = indoc! {" #[cfg(test)] pub mod test { + use crate::config::settings::MissingRuntimeBehavior::AutoInstall; use crate::config::settings::Settings; - use crate::output::OutputStream; + use crate::dirs; + use crate::plugins::{Plugin, PluginName}; use super::*; @@ -191,7 +193,7 @@ pub mod test { macro_rules! assert_cli { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::test::cli_run(args).unwrap() + $crate::cli::test::cli_run(args).unwrap().stdout.content }}; } @@ -211,10 +213,12 @@ pub mod test { Plugin::load_ensure_installed(&PluginName::from(name), &settings).unwrap(); } - pub fn grep<'a>(output: &'a OutputStream, pattern: &str) -> Option<&'a str> { + pub fn grep(output: String, pattern: &str) -> String { output - .content .split('\n') .find(|line| line.contains(pattern)) + .map(|line| line.to_string()) + .unwrap_or_default() + .replace(dirs::HOME.to_string_lossy().as_ref(), "~") } } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index f56796bef..a3454e63c 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -94,12 +94,10 @@ EXAMPLES: #[cfg(test)] mod test { - use insta::assert_display_snapshot; - use pretty_assertions::assert_str_eq; + use insta::{assert_display_snapshot, assert_snapshot}; use crate::assert_cli; - use crate::cli::test::{cli_run, grep}; - use crate::output::Output; + use crate::cli::test::cli_run; #[test] fn test_plugin_install() { @@ -114,12 +112,8 @@ mod test { "-f", "https://github.com/jdxcode/asdf-nodejs" ); - let Output { stdout, .. } = assert_cli!("plugin", "--urls"); - let line = grep(&stdout, "nodejs").unwrap(); - assert_str_eq!( - line, - "nodejs https://github.com/asdf-vm/asdf-nodejs.git" - ); + let stdout = assert_cli!("plugin", "--urls"); + assert_snapshot!(stdout); } #[test] diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index e0876f5ee..a0d62b63f 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -5,7 +5,6 @@ use crate::cli::command::Command; use crate::cli::plugins::ls_remote::PluginsLsRemote; use crate::config::Config; use crate::output::Output; -use crate::shorthand_repository::ShorthandRepo; /// List installed plugins /// @@ -34,9 +33,7 @@ impl Command for PluginsLs { for plugin in config.ts.list_installed_plugins() { if self.urls { - let shr = ShorthandRepo::new(&config.settings); - let url = shr.lookup(&plugin.name)?; - rtxprintln!(out, "{:29} {}", plugin.name, url); + rtxprintln!(out, "{:29} {}", plugin.name, plugin.get_remote_url()?); } else { rtxprintln!(out, "{}", plugin.name); } @@ -63,31 +60,30 @@ const AFTER_LONG_HELP: &str = indoc! {r#" #[cfg(test)] mod test { use crate::assert_cli; - use crate::cli::test::ensure_plugin_installed; - use crate::output::Output; + use crate::cli::test::grep; + use pretty_assertions::assert_str_eq; #[test] fn test_plugin_list() { - ensure_plugin_installed("nodejs"); - let Output { stdout, .. } = assert_cli!("plugin", "list"); - assert!(stdout.content.contains("nodejs")); + let stdout = assert_cli!("plugin", "list"); + assert_str_eq!(grep(stdout, "nodejs"), "nodejs"); } #[test] fn test_plugin_list_urls() { - ensure_plugin_installed("nodejs"); - let Output { stdout, .. } = assert_cli!("plugin", "list", "--urls"); - assert!(stdout - .content - .contains("https://github.com/asdf-vm/asdf-nodejs.git")); + let stdout = assert_cli!("plugin", "list", "--urls"); + assert_str_eq!( + grep(stdout, "shfmt"), + "shfmt https://github.com/luizm/asdf-shfmt.git" + ); } #[test] fn test_plugin_list_all() { - ensure_plugin_installed("nodejs"); - let Output { stdout, .. } = assert_cli!("plugin", "list", "--all", "--urls"); - assert!(stdout - .content - .contains("https://github.com/asdf-vm/asdf-nodejs.git")); + let stdout = assert_cli!("plugin", "list", "--all", "--urls"); + assert_str_eq!( + grep(stdout, "zephyr"), + "zephyr https://github.com/nsaunders/asdf-zephyr.git" + ); } } diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 6b6ad2aa6..ddbe7a712 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -58,12 +58,11 @@ Examples: mod test { use crate::assert_cli; use crate::cli::test::ensure_plugin_installed; - use crate::output::Output; #[test] fn test_plugin_list_remote() { ensure_plugin_installed("nodejs"); - let Output { stdout, .. } = assert_cli!("plugin", "ls-remote"); - assert!(stdout.content.contains("nodejs")); + let stdout = assert_cli!("plugin", "ls-remote"); + assert!(stdout.contains("nodejs")); } } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap new file mode 100644 index 000000000..9af9072cd --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap @@ -0,0 +1,11 @@ +--- +source: src/cli/plugins/install.rs +expression: stdout +--- +jq https://github.com/azmcode/asdf-jq.git +nodejs https://github.com/jdxcode/asdf-nodejs +ruby https://github.com/asdf-vm/asdf-ruby.git +shellcheck https://github.com/luizm/asdf-shellcheck.git +shfmt https://github.com/luizm/asdf-shfmt.git +tiny https://github.com/jdxcode/asdf-tiny + diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap index 9f126b122..7cdc3496c 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap @@ -1,5 +1,4 @@ --- source: src/cli/plugins/uninstall.rs -expression: stdout.content +expression: stdout --- - diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap index b13c482b8..28674a18e 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap @@ -1,6 +1,5 @@ --- source: src/cli/plugins/uninstall.rs -expression: stdout.content +expression: stdout --- uninstalling plugin: nodejs - diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 392a0aaf5..6920ba04d 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -49,16 +49,15 @@ mod test { use crate::assert_cli; use crate::cli::test::ensure_plugin_installed; - use crate::output::Output; #[test] fn test_plugin_uninstall() { ensure_plugin_installed("nodejs"); - let Output { stdout, .. } = assert_cli!("plugin", "rm", "nodejs"); - assert_snapshot!(stdout.content); + let stdout = assert_cli!("plugin", "rm", "nodejs"); + assert_snapshot!(stdout); - let Output { stdout, .. } = assert_cli!("plugin", "rm", "nodejs"); - assert_snapshot!(stdout.content); + let stdout = assert_cli!("plugin", "rm", "nodejs"); + assert_snapshot!(stdout); } } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 03bef7d48..58e61a46e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -667,11 +667,9 @@ fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option mod tests { use crate::assert_cli; - use super::*; - #[test] fn test_render_help() { - let Output { stdout, .. } = assert_cli!("render-help"); - assert!(stdout.content.contains("Quickstart")); + let stdout = assert_cli!("render-help"); + assert!(stdout.contains("Quickstart")); } } diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index f3aea1a93..19d03ddbc 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -37,15 +37,14 @@ const AFTER_LONG_HELP: &str = indoc! {r#" mod test { use insta::{assert_display_snapshot, assert_snapshot}; - use crate::output::Output; use crate::test::reset_config; use crate::{assert_cli, assert_cli_err}; #[test] fn test_settings_get() { reset_config(); - let Output { stdout, .. } = assert_cli!("settings", "get", "legacy_version_file"); - assert_snapshot!(stdout.content, @r###" + let stdout = assert_cli!("settings", "get", "legacy_version_file"); + assert_snapshot!(stdout, @r###" true "###); } diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index dcd493d90..c13d93278 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -35,13 +35,13 @@ mod test { use insta::assert_snapshot; use crate::assert_cli; - use crate::output::Output; + use crate::test::reset_config; #[test] fn test_settings_ls() { reset_config(); - let Output { stdout, .. } = assert_cli!("settings"); - assert_snapshot!(stdout.content); + let stdout = assert_cli!("settings"); + assert_snapshot!(stdout); } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 60d983513..c1c38dd50 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -61,14 +61,14 @@ pub mod test { use insta::assert_snapshot; use crate::assert_cli; - use crate::output::Output; + use crate::test::reset_config; #[test] fn test_settings_set() { reset_config(); - let Output { stdout, .. } = assert_cli!("settings"); - assert_snapshot!(stdout.content); + let stdout = assert_cli!("settings"); + assert_snapshot!(stdout); assert_cli!("settings", "set", "missing_runtime_behavior", "warn"); assert_cli!("settings", "set", "legacy_version_file", "false"); @@ -92,8 +92,8 @@ pub mod test { "2" ); - let Output { stdout, .. } = assert_cli!("settings"); - assert_snapshot!(stdout.content); + let stdout = assert_cli!("settings"); + assert_snapshot!(stdout); reset_config(); } } diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap index d2a4d7081..20e5a2cf2 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap @@ -1,6 +1,6 @@ --- source: src/cli/settings/ls.rs -expression: stdout.content +expression: stdout --- missing_runtime_behavior = autoinstall always_keep_download = true @@ -8,4 +8,3 @@ legacy_version_file = true disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 plugin_repository_last_check_duration = 20 - diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap index 5690f3681..2b3e17b2f 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap @@ -1,6 +1,6 @@ --- source: src/cli/settings/set.rs -expression: stdout.content +expression: stdout --- missing_runtime_behavior = autoinstall always_keep_download = true @@ -8,4 +8,3 @@ legacy_version_file = false disable_plugin_short_name_repository = true plugin_autoupdate_last_check_duration = 1 plugin_repository_last_check_duration = 2 - diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap index c4cc31272..a4e7bdcea 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap @@ -1,6 +1,6 @@ --- source: src/cli/settings/set.rs -expression: stdout.content +expression: stdout --- missing_runtime_behavior = autoinstall always_keep_download = true @@ -8,4 +8,3 @@ legacy_version_file = true disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 plugin_repository_last_check_duration = 20 - diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 3aba954c6..8d1367da2 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -34,15 +34,15 @@ mod test { use insta::assert_snapshot; use crate::assert_cli; - use crate::output::Output; + use crate::test::reset_config; #[test] fn test_settings_unset() { reset_config(); - let Output { stdout, .. } = assert_cli!("settings"); - assert_snapshot!(stdout.content, @r###" + let stdout = assert_cli!("settings"); + assert_snapshot!(stdout, @r###" missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = true @@ -53,8 +53,8 @@ mod test { assert_cli!("settings", "unset", "legacy_version_file"); - let Output { stdout, .. } = assert_cli!("settings"); - assert_snapshot!(stdout.content, @r###" + let stdout = assert_cli!("settings"); + assert_snapshot!(stdout, @r###" missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = true diff --git a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap index 0b23fbdfe..49abb0aba 100644 --- a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap @@ -1,6 +1,6 @@ --- source: src/cli/activate.rs -expression: stdout.content +expression: stdout --- export PATH=":$PATH" _rtx_hook() { @@ -16,4 +16,3 @@ typeset -ag chpwd_functions; if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi - diff --git a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap index 4cbd11b51..543b4e5e5 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap @@ -1,6 +1,5 @@ --- source: src/cli/deactivate.rs -expression: stdout.content +expression: stdout --- unset _rtx_hook; - diff --git a/src/cli/snapshots/rtx__cli__global__test__global-2.snap b/src/cli/snapshots/rtx__cli__global__test__global-2.snap index fcce8aa36..f11c502dd 100644 --- a/src/cli/snapshots/rtx__cli__global__test__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__test__global-2.snap @@ -1,6 +1,5 @@ --- source: src/cli/global.rs -expression: stdout.content +expression: stdout --- shfmt 2 - diff --git a/src/cli/snapshots/rtx__cli__global__test__global-3.snap b/src/cli/snapshots/rtx__cli__global__test__global-3.snap index fcce8aa36..f11c502dd 100644 --- a/src/cli/snapshots/rtx__cli__global__test__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__test__global-3.snap @@ -1,6 +1,5 @@ --- source: src/cli/global.rs -expression: stdout.content +expression: stdout --- shfmt 2 - diff --git a/src/cli/snapshots/rtx__cli__global__test__global.snap b/src/cli/snapshots/rtx__cli__global__test__global.snap index 8f07ac09f..debfb3112 100644 --- a/src/cli/snapshots/rtx__cli__global__test__global.snap +++ b/src/cli/snapshots/rtx__cli__global__test__global.snap @@ -1,6 +1,5 @@ --- source: src/cli/global.rs -expression: stdout.content +expression: stdout --- shfmt 2.6.4 - diff --git a/src/cli/snapshots/rtx__cli__latest__test__latest.snap b/src/cli/snapshots/rtx__cli__latest__test__latest.snap index 2621fa915..77f286cc9 100644 --- a/src/cli/snapshots/rtx__cli__latest__test__latest.snap +++ b/src/cli/snapshots/rtx__cli__latest__test__latest.snap @@ -1,6 +1,5 @@ --- source: src/cli/latest.rs -expression: stdout.content +expression: stdout --- 12.22.12 - diff --git a/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap b/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap index 2621fa915..77f286cc9 100644 --- a/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap +++ b/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap @@ -1,6 +1,5 @@ --- source: src/cli/latest.rs -expression: stdout.content +expression: stdout --- 12.22.12 - diff --git a/src/cli/snapshots/rtx__cli__local__test__local-2.snap b/src/cli/snapshots/rtx__cli__local__test__local-2.snap index 12220a672..9bb147e50 100644 --- a/src/cli/snapshots/rtx__cli__local__test__local-2.snap +++ b/src/cli/snapshots/rtx__cli__local__test__local-2.snap @@ -1,10 +1,9 @@ --- source: src/cli/local.rs -expression: stdout.content +expression: stdout --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 2 # test comment #nodejs 18.13.0 nodejs system - diff --git a/src/cli/snapshots/rtx__cli__local__test__local-3.snap b/src/cli/snapshots/rtx__cli__local__test__local-3.snap index d1d937051..a2169959a 100644 --- a/src/cli/snapshots/rtx__cli__local__test__local-3.snap +++ b/src/cli/snapshots/rtx__cli__local__test__local-3.snap @@ -1,9 +1,8 @@ --- source: src/cli/local.rs -expression: stdout.content +expression: stdout --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 2 # test comment #nodejs 18.13.0 - diff --git a/src/cli/snapshots/rtx__cli__local__test__local.snap b/src/cli/snapshots/rtx__cli__local__test__local.snap index c9b0968cd..ec757848f 100644 --- a/src/cli/snapshots/rtx__cli__local__test__local.snap +++ b/src/cli/snapshots/rtx__cli__local__test__local.snap @@ -1,10 +1,9 @@ --- source: src/cli/local.rs -expression: stdout.content +expression: stdout --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 2.6.4 # test comment #nodejs 18.13.0 nodejs system - diff --git a/src/cli/where.rs b/src/cli/where.rs index 2cd2f5733..0e15480fe 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -64,15 +64,13 @@ mod test { use crate::dirs; use crate::{assert_cli, assert_cli_err}; - use super::*; - #[test] fn test_where() { assert_cli!("plugin", "add", "shfmt"); assert_cli!("install"); - let Output { stdout, .. } = assert_cli!("where", "shfmt"); + let stdout = assert_cli!("where", "shfmt"); assert_str_eq!( - stdout.content.trim(), + stdout.trim(), dirs::ROOT.join("installs/shfmt/3.5.2").to_string_lossy() ); } @@ -81,9 +79,9 @@ mod test { fn test_where_alias() { assert_cli!("plugin", "add", "shfmt"); assert_cli!("install", "shfmt@my/alias"); - let Output { stdout, .. } = assert_cli!("where", "shfmt@my/alias"); + let stdout = assert_cli!("where", "shfmt@my/alias"); assert_str_eq!( - stdout.content.trim(), + stdout.trim(), dirs::ROOT.join("installs/shfmt/3.0.2").to_string_lossy() ); } diff --git a/src/config/toolset.rs b/src/config/toolset.rs index 8b99d82eb..3923dc4af 100644 --- a/src/config/toolset.rs +++ b/src/config/toolset.rs @@ -73,20 +73,24 @@ impl Toolset { } pub fn list_plugins(&self) -> Vec> { - self.plugins.values().map(Arc::clone).collect() + self.plugins + .values() + .sorted_by_cached_key(|p| p.name.clone()) + .map(Arc::clone) + .collect() } pub fn list_installed_plugins(&self) -> Vec> { - self.plugins - .values() + self.list_plugins() + .into_iter() .filter(|p| p.is_installed()) - .map(Arc::clone) .collect() } pub fn list_current_plugins(&self) -> Vec> { self.current_versions .keys() + .sorted() .map(|p| self.find_plugin(p).unwrap()) .collect() } @@ -94,6 +98,7 @@ impl Toolset { pub fn list_installed_versions(&self) -> Vec> { self.installed_versions .iter() + .sorted_by_cached_key(|(plugin_name, _)| plugin_name.to_string()) .flat_map(|(_, versions)| versions.iter().map(|(_, rtv)| rtv.clone())) .collect() } diff --git a/src/env.rs b/src/env.rs index c0997fd6a..29bf6f73b 100644 --- a/src/env.rs +++ b/src/env.rs @@ -48,6 +48,7 @@ lazy_static! { .map(PathBuf::from) .unwrap_or_else(|| XDG_DATA_HOME.join("rtx")) }; + pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); pub static ref PATH: OsString = var_os("PATH").unwrap_or_default(); pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); pub static ref RTX_EXE: PathBuf = current_exe().unwrap_or_else(|_| "rtx".into()); diff --git a/src/git.rs b/src/git.rs index 2758918e5..a180cf8d3 100644 --- a/src/git.rs +++ b/src/git.rs @@ -73,6 +73,20 @@ impl Git { debug!("current sha for {}: {}", self.dir.display(), &sha); Ok(sha) } + + pub fn get_remote_url(&self) -> Result { + let url = cmd!( + "git", + "-C", + &self.dir, + "config", + "--get", + "remote.origin.url" + ) + .read()?; + debug!("remote url for {}: {}", self.dir.display(), &url); + Ok(url) + } } #[cfg(test)] diff --git a/src/plugins.rs b/src/plugins.rs index fcdc51c4c..51cbae052 100644 --- a/src/plugins.rs +++ b/src/plugins.rs @@ -93,6 +93,11 @@ impl Plugin { self.plugin_path.exists() } + pub fn get_remote_url(&self) -> Result { + let git = Git::new(self.plugin_path.to_path_buf()); + git.get_remote_url() + } + pub fn install(&self, repository: &String) -> Result<()> { debug!("install {} {:?}", self.name, repository); eprint!( diff --git a/src/test.rs b/src/test.rs index 90ac9bc9e..53d17b564 100644 --- a/src/test.rs +++ b/src/test.rs @@ -2,7 +2,7 @@ use std::fs; use indoc::indoc; -use crate::{cmd, env}; +use crate::{assert_cli, cmd, env}; #[ctor::ctor] fn init() { @@ -20,8 +20,18 @@ fn init() { { warn!("failed to reset test files: {}", err); } - reset_config(); + assert_cli!( + "plugin", + "install", + "tiny", + "https://github.com/jdxcode/asdf-tiny" + ); + assert_cli!("plugin", "install", "shellcheck"); + assert_cli!("plugin", "install", "shfmt"); + assert_cli!("plugin", "install", "nodejs"); + assert_cli!("plugin", "install", "jq"); + assert_cli!("install"); } pub fn reset_config() { diff --git a/test/.tool-versions b/test/.tool-versions index ed79d4100..5712a47c9 100644 --- a/test/.tool-versions +++ b/test/.tool-versions @@ -1,2 +1,3 @@ shfmt 2 jq 1.6 +tiny 2 From 0c354d7dda08f32013ac7d7736b877d9e2cd3345 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 07:12:38 -0600 Subject: [PATCH 0028/1891] added plugins symlink --- plugins/.gitignore | 1 + test/data/plugins | 1 + 2 files changed, 2 insertions(+) create mode 100644 plugins/.gitignore create mode 120000 test/data/plugins diff --git a/plugins/.gitignore b/plugins/.gitignore new file mode 100644 index 000000000..6f9139176 --- /dev/null +++ b/plugins/.gitignore @@ -0,0 +1 @@ +___* diff --git a/test/data/plugins b/test/data/plugins new file mode 120000 index 000000000..9aa30addd --- /dev/null +++ b/test/data/plugins @@ -0,0 +1 @@ +../../plugins \ No newline at end of file From d4ea7eee863b26ed47c337948b3df859ab75b298 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 07:19:17 -0600 Subject: [PATCH 0029/1891] added dummy plugin from asdf --- plugins/.gitignore | 2 +- plugins/dummy/LICENSE | 20 ++++++++++++++ plugins/dummy/bin/download | 3 +++ .../dummy/bin/get-version-from-legacy-file | 12 +++++++++ plugins/dummy/bin/help.overview | 10 +++++++ plugins/dummy/bin/install | 27 +++++++++++++++++++ plugins/dummy/bin/latest-stable | 10 +++++++ plugins/dummy/bin/list-all | 6 +++++ plugins/dummy/bin/list-legacy-filenames | 3 +++ plugins/dummy/bin/parse-legacy-file | 4 +++ plugins/dummy/bin/post-plugin-add | 3 +++ plugins/dummy/bin/post-plugin-update | 3 +++ plugins/dummy/bin/pre-plugin-remove | 3 +++ 13 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 plugins/dummy/LICENSE create mode 100755 plugins/dummy/bin/download create mode 100755 plugins/dummy/bin/get-version-from-legacy-file create mode 100755 plugins/dummy/bin/help.overview create mode 100755 plugins/dummy/bin/install create mode 100755 plugins/dummy/bin/latest-stable create mode 100755 plugins/dummy/bin/list-all create mode 100755 plugins/dummy/bin/list-legacy-filenames create mode 100755 plugins/dummy/bin/parse-legacy-file create mode 100755 plugins/dummy/bin/post-plugin-add create mode 100755 plugins/dummy/bin/post-plugin-update create mode 100755 plugins/dummy/bin/pre-plugin-remove diff --git a/plugins/.gitignore b/plugins/.gitignore index 6f9139176..72e8ffc0d 100644 --- a/plugins/.gitignore +++ b/plugins/.gitignore @@ -1 +1 @@ -___* +* diff --git a/plugins/dummy/LICENSE b/plugins/dummy/LICENSE new file mode 100644 index 000000000..d3084751c --- /dev/null +++ b/plugins/dummy/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Akash Manohar J + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/dummy/bin/download b/plugins/dummy/bin/download new file mode 100755 index 000000000..0fdcf0910 --- /dev/null +++ b/plugins/dummy/bin/download @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +exit 0 diff --git a/plugins/dummy/bin/get-version-from-legacy-file b/plugins/dummy/bin/get-version-from-legacy-file new file mode 100755 index 000000000..801739d37 --- /dev/null +++ b/plugins/dummy/bin/get-version-from-legacy-file @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +get_legacy_version() { + current_directory=$1 + version_file="$current_directory/.dummy-version" + + if [ -f "$version_file" ]; then + cat "$version_file" + fi +} + +get_legacy_version "$1" diff --git a/plugins/dummy/bin/help.overview b/plugins/dummy/bin/help.overview new file mode 100755 index 000000000..746761d5a --- /dev/null +++ b/plugins/dummy/bin/help.overview @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +echo "Dummy plugin documentation" +echo +echo "Dummy plugin is a plugin only used for unit tests" + +if [ -n "$ASDF_INSTALL_VERSION" ]; then + echo + echo "Details specific for version $ASDF_INSTALL_VERSION" +fi diff --git a/plugins/dummy/bin/install b/plugins/dummy/bin/install new file mode 100755 index 000000000..645f6ec6b --- /dev/null +++ b/plugins/dummy/bin/install @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# We want certain versions to fail installation for various reasons in the tests +check_dummy_versions() { + local bad_versions=" other-dummy " + if [[ "$bad_versions" == *" $ASDF_INSTALL_VERSION "* ]]; then + echo "Dummy couldn't install version: $ASDF_INSTALL_VERSION (on purpose)" + exit 1 + fi +} + +check_dummy_versions +mkdir -p "$ASDF_INSTALL_PATH" +env >"$ASDF_INSTALL_PATH/env" +echo "$ASDF_INSTALL_VERSION" >"$ASDF_INSTALL_PATH/version" + +# create the dummy executable +mkdir -p "$ASDF_INSTALL_PATH/bin" +cat <"$ASDF_INSTALL_PATH/bin/dummy" +echo This is Dummy ${ASDF_INSTALL_VERSION}! \$2 \$1 +EOF +chmod +x "$ASDF_INSTALL_PATH/bin/dummy" +mkdir -p "$ASDF_INSTALL_PATH/bin/subdir" +cat <"$ASDF_INSTALL_PATH/bin/subdir/other_bin" +echo This is Other Bin ${ASDF_INSTALL_VERSION}! \$2 \$1 +EOF +chmod +x "$ASDF_INSTALL_PATH/bin/subdir/other_bin" diff --git a/plugins/dummy/bin/latest-stable b/plugins/dummy/bin/latest-stable new file mode 100755 index 000000000..afe7d1ba4 --- /dev/null +++ b/plugins/dummy/bin/latest-stable @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +get_latest_stable() { + query=$1 + + version_list=(1.0.0 1.1.0 2.0.0) + printf "%s\n" "${version_list[@]}" | grep -E "^\s*$query" | tail -1 +} + +get_latest_stable "$1" diff --git a/plugins/dummy/bin/list-all b/plugins/dummy/bin/list-all new file mode 100755 index 000000000..efec9526d --- /dev/null +++ b/plugins/dummy/bin/list-all @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +versions_list=(1.0.0 1.1.0 2.0.0) +echo "${versions_list[@]}" +# Sending message to STD error to ensure that it is ignored +echo "ignore this error" >&2 diff --git a/plugins/dummy/bin/list-legacy-filenames b/plugins/dummy/bin/list-legacy-filenames new file mode 100755 index 000000000..ba4feb91b --- /dev/null +++ b/plugins/dummy/bin/list-legacy-filenames @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo ".dummy-version .dummyrc" diff --git a/plugins/dummy/bin/parse-legacy-file b/plugins/dummy/bin/parse-legacy-file new file mode 100755 index 000000000..8a8f13404 --- /dev/null +++ b/plugins/dummy/bin/parse-legacy-file @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# shellcheck disable=SC2020 +tr <"$1" -d "dummy-" diff --git a/plugins/dummy/bin/post-plugin-add b/plugins/dummy/bin/post-plugin-add new file mode 100755 index 000000000..8a57d87f2 --- /dev/null +++ b/plugins/dummy/bin/post-plugin-add @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "plugin add path=${ASDF_PLUGIN_PATH} source_url=${ASDF_PLUGIN_SOURCE_URL}" diff --git a/plugins/dummy/bin/post-plugin-update b/plugins/dummy/bin/post-plugin-update new file mode 100755 index 000000000..d0e216c65 --- /dev/null +++ b/plugins/dummy/bin/post-plugin-update @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "plugin updated path=${ASDF_PLUGIN_PATH} old git-ref=${ASDF_PLUGIN_PREV_REF} new git-ref=${ASDF_PLUGIN_POST_REF}" diff --git a/plugins/dummy/bin/pre-plugin-remove b/plugins/dummy/bin/pre-plugin-remove new file mode 100755 index 000000000..1226b2c3b --- /dev/null +++ b/plugins/dummy/bin/pre-plugin-remove @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "plugin-remove ${ASDF_PLUGIN_PATH}" From 623b986b8158aa42ec7f0254151136036530a6c0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:03:44 -0600 Subject: [PATCH 0030/1891] use the same version string for `rtx --version` and `rtx version` --- src/cli/mod.rs | 4 +--- src/cli/version.rs | 17 +++++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index d8898d47b..e98c4bee0 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -119,7 +119,7 @@ impl Cli { pub fn command() -> clap::Command { Commands::augment_subcommands( clap::Command::new("rtx") - .version(env!("CARGO_PKG_VERSION")) + .version(version::VERSION.to_string()) .about(env!("CARGO_PKG_DESCRIPTION")) .long_about(LONG_ABOUT) .arg_required_else_help(true) @@ -172,11 +172,9 @@ const AFTER_HELP: &str = indoc! {" #[cfg(test)] pub mod test { - use crate::config::settings::MissingRuntimeBehavior::AutoInstall; use crate::config::settings::Settings; use crate::dirs; - use crate::plugins::{Plugin, PluginName}; use super::*; diff --git a/src/cli/version.rs b/src/cli/version.rs index 924e63242..9f47736ef 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Result; +use lazy_static::lazy_static; use crate::build_time::BUILD_TIME; use crate::cli::command::Command; @@ -9,14 +10,18 @@ use crate::output::Output; #[clap(about = "Show rtx version", alias = "-v", alias = "v")] pub struct Version {} +lazy_static! { + pub static ref VERSION: String = format!( + "{} (built on {})", + env!("CARGO_PKG_VERSION"), + BUILD_TIME.format("%Y-%m-%d") + ); +} + impl Command for Version { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - rtxprintln!( - out, - "rtx {} (built on {})", - env!("CARGO_PKG_VERSION"), - BUILD_TIME.format("%Y-%m-%d") - ); + let v = VERSION.to_string(); + rtxprintln!(out, "{v}"); Ok(()) } } From cbfa81b294061396c16060c126c65eca698d2651 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:04:41 -0600 Subject: [PATCH 0031/1891] added /installs symlink --- installs | 1 + 1 file changed, 1 insertion(+) create mode 120000 installs diff --git a/installs b/installs new file mode 120000 index 000000000..fbd5b970e --- /dev/null +++ b/installs @@ -0,0 +1 @@ +test/data/installs \ No newline at end of file From 31d6ca5e1aa5a7beeb4d3d9fd2a425517dbf7b96 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 13:46:34 -0600 Subject: [PATCH 0032/1891] big plugins refactor (#29) * big plugins refactor this occurs if RTX_DATA_DIR uses a relative path * test --- Cargo.lock | 1 + Cargo.toml | 1 + README.md | 7 +- src/cli/asdf.rs | 5 +- src/cli/direnv/envrc.rs | 2 +- src/cli/direnv/exec.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/install.rs | 9 +- src/cli/ls.rs | 4 +- src/cli/mod.rs | 4 +- src/cli/plugins/install.rs | 3 +- src/cli/plugins/ls.rs | 11 +- src/cli/plugins/mod.rs | 2 +- ...ns__install__test__plugin_install_url.snap | 11 -- ...__uninstall__test__plugin_uninstall-2.snap | 1 + ...ns__uninstall__test__plugin_uninstall.snap | 1 + src/cli/plugins/update.rs | 29 +-- src/cli/settings/set.rs | 2 +- ..._cli__settings__ls__test__settings_ls.snap | 1 + ...__settings__set__test__settings_set-2.snap | 1 + ...li__settings__set__test__settings_set.snap | 1 + src/cli/settings/unset.rs | 2 +- ...tx__cli__activate__test__activate_zsh.snap | 1 + ...cli__deactivate__test__deactivate_zsh.snap | 1 + .../rtx__cli__global__test__global-2.snap | 1 + .../rtx__cli__global__test__global-3.snap | 1 + .../rtx__cli__global__test__global.snap | 1 + .../rtx__cli__latest__test__latest.snap | 1 + ...cli__latest__test__latest_asdf_format.snap | 1 + .../rtx__cli__local__test__local-2.snap | 1 + .../rtx__cli__local__test__local-3.snap | 1 + .../rtx__cli__local__test__local.snap | 1 + src/cli/version.rs | 17 +- src/cli/where.rs | 2 +- src/config/config_file/legacy_version.rs | 3 +- src/config/config_file/mod.rs | 2 +- src/config/config_file/rtxrc.rs | 2 +- src/config/config_file/tool_versions.rs | 3 +- src/config/mod.rs | 10 +- src/config/plugin_source.rs | 26 +++ src/config/toolset.rs | 4 +- src/env_diff.rs | 14 +- src/errors.rs | 23 ++- src/fake_asdf.rs | 71 +++++--- src/file.rs | 9 + src/git.rs | 26 ++- src/plugins/cache.rs | 32 ++++ src/{plugins.rs => plugins/mod.rs} | 172 +++++------------- src/plugins/script_manager.rs | 151 +++++++++++++++ src/{runtimes.rs => runtimes/mod.rs} | 137 ++++++-------- src/runtimes/runtime_conf.rs | 27 +++ src/shorthand_repository.rs | 2 +- src/test.rs | 3 + src/ui/mod.rs | 6 - src/ui/prompt.rs | 20 ++ 55 files changed, 547 insertions(+), 327 deletions(-) delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap create mode 100644 src/config/plugin_source.rs create mode 100644 src/plugins/cache.rs rename src/{plugins.rs => plugins/mod.rs} (73%) create mode 100644 src/plugins/script_manager.rs rename src/{runtimes.rs => runtimes/mod.rs} (70%) create mode 100644 src/runtimes/runtime_conf.rs diff --git a/Cargo.lock b/Cargo.lock index 7932e5d17..5c936784e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1021,6 +1021,7 @@ dependencies = [ "lazy_static", "log", "num_cpus", + "once_cell", "owo-colors", "pretty_assertions", "rayon", diff --git a/Cargo.toml b/Cargo.toml index 3824fd981..4d12a6367 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ url = "2.3.1" versions = "4.1.0" build-time = "0.1.2" serde_json = "1.0.91" +once_cell = "1.17.0" [target.'cfg(unix)'.dependencies] exec = "0.3.1" diff --git a/README.md b/README.md index 59a817752..3fdb50dfe 100644 --- a/README.md +++ b/README.md @@ -932,19 +932,22 @@ updates a plugin to the latest version note: this updates the plugin itself, not the runtime versions -Usage: update [PLUGIN]... +Usage: update [OPTIONS] [PLUGIN]... Arguments: [PLUGIN]... plugin(s) to update Options: + -a, --all + update all plugins + -h, --help Print help (see a summary with '-h') Examples: - rtx plugins update # update all plugins + rtx plugins update --all # update all plugins rtx plugins update nodejs # update only nodejs ``` diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index a2176cb0d..07d508679 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -61,12 +61,15 @@ fn list_versions(out: &mut Output, args: &Vec) -> Result<()> { #[cfg(test)] mod test { + use pretty_assertions::assert_str_eq; + use crate::assert_cli; + use crate::cli::version::VERSION; #[test] fn test_fake_asdf() { let stdout = assert_cli!("asdf", "-v"); - assert!(stdout.starts_with("rtx ")); + assert_str_eq!(stdout, VERSION.to_string() + "\n"); } #[test] diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index ee209775a..2ac2697f9 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -5,8 +5,8 @@ use std::ops::Deref; use color_eyre::eyre::Result; use crate::cli::command::Command; -use crate::config::settings::MissingRuntimeBehavior::{Prompt, Warn}; use crate::config::Config; +use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::hash::hash_to_str; use crate::output::Output; use crate::{dirs, env}; diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index aecbbf9ea..286ca79da 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -3,8 +3,8 @@ use serde_derive::Deserialize; use crate::cli::command::Command; use crate::cmd; -use crate::config::settings::MissingRuntimeBehavior::{Prompt, Warn}; use crate::config::Config; +use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::output::Output; /// [internal] This is an internal command that writes an envrc file diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 7f9a367a8..235cb8ca3 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,8 +1,8 @@ use color_eyre::eyre::Result; use crate::cli::command::Command; -use crate::config::settings::MissingRuntimeBehavior::Ignore; use crate::config::Config; +use crate::config::MissingRuntimeBehavior::Ignore; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::hook_env::HookEnvWatches; use crate::output::Output; diff --git a/src/cli/install.rs b/src/cli/install.rs index 4d936e563..ce1e2ca72 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -6,11 +6,12 @@ use owo_colors::{OwoColorize, Stream}; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; -use crate::config::settings::MissingRuntimeBehavior::AutoInstall; -use crate::config::settings::Settings; use crate::config::Config; +use crate::config::MissingRuntimeBehavior::AutoInstall; +use crate::config::Settings; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; +use crate::plugins::InstallType::Version; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; @@ -89,7 +90,7 @@ impl Install { rtv.to_string() .if_supports_color(Stream::Stderr, |t| t.cyan()) ); - rtv.install("version", &config)?; + rtv.install(Version, &config)?; } Ok(()) @@ -132,7 +133,7 @@ impl Install { rtv.to_string() .if_supports_color(Stream::Stderr, |t| t.cyan()) ); - rtv.install("version", &config)?; + rtv.install(Version, &config)?; } Ok(()) } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index dca52d336..25536b19a 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -8,9 +8,9 @@ use owo_colors::{OwoColorize, Stream}; use versions::Mess; use crate::cli::command::Command; -use crate::config::Config; +use crate::config::{Config, PluginSource}; use crate::output::Output; -use crate::plugins::{PluginName, PluginSource}; +use crate::plugins::PluginName; use crate::runtimes::RuntimeVersion; /// list installed runtime versions diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e98c4bee0..b61c2c98c 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -172,8 +172,8 @@ const AFTER_HELP: &str = indoc! {" #[cfg(test)] pub mod test { - use crate::config::settings::MissingRuntimeBehavior::AutoInstall; - use crate::config::settings::Settings; + use crate::config::MissingRuntimeBehavior::AutoInstall; + use crate::config::Settings; use crate::dirs; use crate::plugins::{Plugin, PluginName}; diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index a3454e63c..6bebd2bcd 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -98,6 +98,7 @@ mod test { use crate::assert_cli; use crate::cli::test::cli_run; + use crate::cli::test::grep; #[test] fn test_plugin_install() { @@ -113,7 +114,7 @@ mod test { "https://github.com/jdxcode/asdf-nodejs" ); let stdout = assert_cli!("plugin", "--urls"); - assert_snapshot!(stdout); + assert_snapshot!(grep(stdout, "nodejs"), @"nodejs https://github.com/jdxcode/asdf-nodejs"); } #[test] diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index a0d62b63f..2e532f41f 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -33,10 +33,12 @@ impl Command for PluginsLs { for plugin in config.ts.list_installed_plugins() { if self.urls { - rtxprintln!(out, "{:29} {}", plugin.name, plugin.get_remote_url()?); - } else { - rtxprintln!(out, "{}", plugin.name); + if let Some(url) = plugin.get_remote_url() { + rtxprintln!(out, "{:29} {}", plugin.name, url); + continue; + } } + rtxprintln!(out, "{}", plugin.name); } Ok(()) } @@ -59,9 +61,10 @@ const AFTER_LONG_HELP: &str = indoc! {r#" #[cfg(test)] mod test { + use pretty_assertions::assert_str_eq; + use crate::assert_cli; use crate::cli::test::grep; - use pretty_assertions::assert_str_eq; #[test] fn test_plugin_list() { diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 3b00c7d09..cd069c05b 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -36,7 +36,7 @@ enum Commands { Ls(ls::PluginsLs), LsRemote(ls_remote::PluginsLsRemote), Uninstall(uninstall::PluginsUninstall), - Update(update::PluginsUpdate), + Update(update::Update), } impl Commands { diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap deleted file mode 100644 index 9af9072cd..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_url.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: src/cli/plugins/install.rs -expression: stdout ---- -jq https://github.com/azmcode/asdf-jq.git -nodejs https://github.com/jdxcode/asdf-nodejs -ruby https://github.com/asdf-vm/asdf-ruby.git -shellcheck https://github.com/luizm/asdf-shellcheck.git -shfmt https://github.com/luizm/asdf-shfmt.git -tiny https://github.com/jdxcode/asdf-tiny - diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap index 7cdc3496c..e835030b3 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap @@ -2,3 +2,4 @@ source: src/cli/plugins/uninstall.rs expression: stdout --- + diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap index 28674a18e..083a54b0a 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap @@ -3,3 +3,4 @@ source: src/cli/plugins/uninstall.rs expression: stdout --- uninstalling plugin: nodejs + diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index f54da0a24..cebc1e7dc 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -13,16 +13,20 @@ use crate::plugins::Plugin; /// note: this updates the plugin itself, not the runtime versions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, alias = "upgrade", after_long_help = AFTER_LONG_HELP)] -pub struct PluginsUpdate { +pub struct Update { /// plugin(s) to update #[clap()] plugin: Option>, + + /// update all plugins + #[clap(long, short = 'a', conflicts_with = "plugin")] + all: bool, } -impl Command for PluginsUpdate { +impl Command for Update { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugins: Vec> = match self.plugin { - Some(plugins) => plugins + let plugins: Vec> = match (self.plugin, self.all) { + (Some(plugins), _) => plugins .into_iter() .map(|p| { config.ts.find_plugin(&p).ok_or_else(|| { @@ -33,7 +37,8 @@ impl Command for PluginsUpdate { }) }) .collect::>>>()?, - None => config.ts.list_installed_plugins(), + (_, true) => config.ts.list_installed_plugins(), + _ => Err(eyre!("no plugins specified"))?, }; for plugin in plugins { @@ -46,19 +51,21 @@ impl Command for PluginsUpdate { const AFTER_LONG_HELP: &str = r#" Examples: - rtx plugins update # update all plugins + rtx plugins update --all # update all plugins rtx plugins update nodejs # update only nodejs "#; #[cfg(test)] mod test { - use crate::assert_cli; - use crate::cli::test::ensure_plugin_installed; + use pretty_assertions::assert_str_eq; + + use crate::{assert_cli, assert_cli_err}; #[test] fn test_plugin_update() { - ensure_plugin_installed("nodejs"); - assert_cli!("plugin", "update"); - assert_cli!("plugin", "update", "nodejs"); + let err = assert_cli_err!("p", "update"); + assert_str_eq!(err.to_string(), "no plugins specified"); + assert_cli!("plugin", "update", "--all"); + assert_cli!("plugins", "update", "nodejs"); } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index c1c38dd50..9057941c4 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -10,7 +10,7 @@ use crate::output::Output; /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsSet { /// The setting to set pub key: String, diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap index 20e5a2cf2..d5212f3ba 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap @@ -8,3 +8,4 @@ legacy_version_file = true disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 plugin_repository_last_check_duration = 20 + diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap index 2b3e17b2f..5ff92839e 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap @@ -8,3 +8,4 @@ legacy_version_file = false disable_plugin_short_name_repository = true plugin_autoupdate_last_check_duration = 1 plugin_repository_last_check_duration = 2 + diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap index a4e7bdcea..5637d9bd5 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap @@ -8,3 +8,4 @@ legacy_version_file = true disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 plugin_repository_last_check_duration = 20 + diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 8d1367da2..ea6708d91 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -10,7 +10,7 @@ use crate::output::Output; /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(visible_aliases=["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsUnset { /// The setting to remove pub key: String, diff --git a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap index 49abb0aba..4aa4945ae 100644 --- a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap @@ -16,3 +16,4 @@ typeset -ag chpwd_functions; if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi + diff --git a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap index 543b4e5e5..037f20fee 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap @@ -3,3 +3,4 @@ source: src/cli/deactivate.rs expression: stdout --- unset _rtx_hook; + diff --git a/src/cli/snapshots/rtx__cli__global__test__global-2.snap b/src/cli/snapshots/rtx__cli__global__test__global-2.snap index f11c502dd..6652aca02 100644 --- a/src/cli/snapshots/rtx__cli__global__test__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__test__global-2.snap @@ -3,3 +3,4 @@ source: src/cli/global.rs expression: stdout --- shfmt 2 + diff --git a/src/cli/snapshots/rtx__cli__global__test__global-3.snap b/src/cli/snapshots/rtx__cli__global__test__global-3.snap index f11c502dd..6652aca02 100644 --- a/src/cli/snapshots/rtx__cli__global__test__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__test__global-3.snap @@ -3,3 +3,4 @@ source: src/cli/global.rs expression: stdout --- shfmt 2 + diff --git a/src/cli/snapshots/rtx__cli__global__test__global.snap b/src/cli/snapshots/rtx__cli__global__test__global.snap index debfb3112..cb4c9fc65 100644 --- a/src/cli/snapshots/rtx__cli__global__test__global.snap +++ b/src/cli/snapshots/rtx__cli__global__test__global.snap @@ -3,3 +3,4 @@ source: src/cli/global.rs expression: stdout --- shfmt 2.6.4 + diff --git a/src/cli/snapshots/rtx__cli__latest__test__latest.snap b/src/cli/snapshots/rtx__cli__latest__test__latest.snap index 77f286cc9..0144922f6 100644 --- a/src/cli/snapshots/rtx__cli__latest__test__latest.snap +++ b/src/cli/snapshots/rtx__cli__latest__test__latest.snap @@ -3,3 +3,4 @@ source: src/cli/latest.rs expression: stdout --- 12.22.12 + diff --git a/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap b/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap index 77f286cc9..0144922f6 100644 --- a/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap +++ b/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap @@ -3,3 +3,4 @@ source: src/cli/latest.rs expression: stdout --- 12.22.12 + diff --git a/src/cli/snapshots/rtx__cli__local__test__local-2.snap b/src/cli/snapshots/rtx__cli__local__test__local-2.snap index 9bb147e50..f3c8c33c1 100644 --- a/src/cli/snapshots/rtx__cli__local__test__local-2.snap +++ b/src/cli/snapshots/rtx__cli__local__test__local-2.snap @@ -7,3 +7,4 @@ shellcheck 0.9.0 shfmt 2 # test comment #nodejs 18.13.0 nodejs system + diff --git a/src/cli/snapshots/rtx__cli__local__test__local-3.snap b/src/cli/snapshots/rtx__cli__local__test__local-3.snap index a2169959a..b94ee7f22 100644 --- a/src/cli/snapshots/rtx__cli__local__test__local-3.snap +++ b/src/cli/snapshots/rtx__cli__local__test__local-3.snap @@ -6,3 +6,4 @@ expression: stdout shellcheck 0.9.0 shfmt 2 # test comment #nodejs 18.13.0 + diff --git a/src/cli/snapshots/rtx__cli__local__test__local.snap b/src/cli/snapshots/rtx__cli__local__test__local.snap index ec757848f..34c0c2f61 100644 --- a/src/cli/snapshots/rtx__cli__local__test__local.snap +++ b/src/cli/snapshots/rtx__cli__local__test__local.snap @@ -7,3 +7,4 @@ shellcheck 0.9.0 shfmt 2.6.4 # test comment #nodejs 18.13.0 nodejs system + diff --git a/src/cli/version.rs b/src/cli/version.rs index 9f47736ef..94baa62ae 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -28,20 +28,15 @@ impl Command for Version { #[cfg(test)] mod tests { - use crate::cli::Cli; + use insta::assert_snapshot; - use super::*; + use crate::assert_cli; #[test] fn test_version() { - let config = Config::load().unwrap(); - let mut out = Output::tracked(); - - Cli::new() - .run(config, &vec!["rtx".into(), "version".into()], &mut out) - .unwrap(); - - let expected = format!("rtx {}", env!("CARGO_PKG_VERSION")); - assert!(out.stdout.content.contains(&expected)); + let stdout = assert_cli!("version"); + assert_snapshot!(stdout, @r###" + 1.2.1 (built on 2023-01-28) + "###); } } diff --git a/src/cli/where.rs b/src/cli/where.rs index 0e15480fe..a9acd606b 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -89,6 +89,6 @@ mod test { #[test] fn test_where_not_found() { let err = assert_cli_err!("where", "shfmt@1111"); - assert_display_snapshot!(err, @"runtime version not installed: shfmt@1111"); + assert_display_snapshot!(err, @"[shfmt] version 1111 not installed: 1111"); } } diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index bd926d15c..87a673b28 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -6,7 +6,8 @@ use color_eyre::eyre::Result; use indexmap::IndexMap; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::plugins::{Plugin, PluginName, PluginSource}; +use crate::config::PluginSource; +use crate::plugins::{Plugin, PluginName}; #[derive(Debug)] pub struct LegacyVersionFile { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 93a6a6914..e03deb9b6 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -11,9 +11,9 @@ use tool_versions::ToolVersions; use crate::cli::args::runtime::RuntimeArg; use crate::config::Config; +use crate::config::PluginSource; use crate::env; use crate::errors::Error::VersionNotInstalled; -use crate::plugins::PluginSource; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 9cdd96e68..eff67a502 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -12,8 +12,8 @@ use toml::Value; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::{MissingRuntimeBehavior, Settings, SettingsBuilder}; use crate::config::AliasMap; +use crate::config::PluginSource; use crate::plugins::PluginName; -use crate::plugins::PluginSource; const ENV_SUGGESTION: &str = r#" [env] diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 1890da0d7..7ca832fef 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -8,7 +8,8 @@ use color_eyre::eyre::Result; use indexmap::IndexMap; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::plugins::{PluginName, PluginSource}; +use crate::config::PluginSource; +use crate::plugins::PluginName; // python 3.11.0 3.10.0 // shellcheck 0.9.0 diff --git a/src/config/mod.rs b/src/config/mod.rs index da9695984..d5381f499 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::env::{join_paths, split_paths}; - use std::fmt::{Display, Formatter}; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -12,17 +11,20 @@ use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; +pub use plugin_source::PluginSource; +pub use settings::{MissingRuntimeBehavior, Settings}; + use crate::cli::args::runtime::RuntimeArg; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtxrc::RTXFile; use crate::config::config_file::ConfigFile; -use crate::config::settings::Settings; use crate::config::toolset::Toolset; -use crate::plugins::{Plugin, PluginName, PluginSource}; +use crate::plugins::{Plugin, PluginName}; use crate::{dirs, env, file}; pub mod config_file; -pub mod settings; +pub mod plugin_source; +mod settings; mod toolset; type AliasMap = IndexMap>; diff --git a/src/config/plugin_source.rs b/src/config/plugin_source.rs new file mode 100644 index 000000000..b82366fd0 --- /dev/null +++ b/src/config/plugin_source.rs @@ -0,0 +1,26 @@ +use std::fmt::{Display, Formatter}; +use std::path::PathBuf; + +use crate::cli::args::runtime::RuntimeArg; +use crate::file::display_path; + +#[derive(Debug, Clone)] +pub enum PluginSource { + ToolVersions(PathBuf), + RtxRc(PathBuf), + LegacyVersionFile(PathBuf), + Argument(RuntimeArg), + Environment(String, String), +} + +impl Display for PluginSource { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + match self { + PluginSource::ToolVersions(path) => write!(f, "{}", display_path(path)), + PluginSource::RtxRc(path) => write!(f, "{}", display_path(path)), + PluginSource::LegacyVersionFile(path) => write!(f, "{}", display_path(path)), + PluginSource::Argument(arg) => write!(f, "--runtime {arg}"), + PluginSource::Environment(k, v) => write!(f, "{k}={v}"), + } + } +} diff --git a/src/config/toolset.rs b/src/config/toolset.rs index 3923dc4af..fcd1bbe1b 100644 --- a/src/config/toolset.rs +++ b/src/config/toolset.rs @@ -7,8 +7,8 @@ use itertools::Itertools; use rayon::prelude::*; use versions::Mess; -use crate::config::AliasMap; -use crate::plugins::{Plugin, PluginName, PluginSource}; +use crate::config::{AliasMap, PluginSource}; +use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; #[derive(Debug, Default)] diff --git a/src/env_diff.rs b/src/env_diff.rs index 3e6e68e6a..8ebfc1929 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::ffi::{OsStr, OsString}; use std::fmt::Debug; use std::io::prelude::*; use std::path::Path; @@ -55,7 +56,14 @@ impl EnvDiff { diff } - pub fn from_bash_script(script: &Path, env: HashMap) -> Result { + pub fn from_bash_script(script: &Path, env: T) -> Result + where + T: IntoIterator, + U: Into, + V: Into, + { + let env: HashMap = + env.into_iter().map(|(k, v)| (k.into(), v.into())).collect(); let out = cmd!( "bash", "-c", @@ -74,7 +82,7 @@ impl EnvDiff { if k == "_" || k == "SHLVL" || k == "PATH" { continue; } - if let Some(orig) = env.get(k) { + if let Some(orig) = env.get(OsStr::new(k)) { if v == orig { continue; } @@ -223,7 +231,7 @@ mod tests { } .into_iter() .map(|(k, v)| (k.into(), v.into())) - .collect::>(); + .collect::>(); let ed = EnvDiff::from_bash_script(path.as_path(), orig).unwrap(); assert_debug_snapshot!(ed); } diff --git a/src/errors.rs b/src/errors.rs index 577327119..4aa00293b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,11 +1,22 @@ +use std::process::ExitStatus; + use thiserror::Error; +use crate::plugins::PluginName; + #[derive(Error, Debug)] pub enum Error { - #[error("plugin not installed: {0}")] - PluginNotInstalled(String), - // #[error("No version found for: {0}@{1}")] - // VersionNotFound(String, String), - #[error("runtime version not installed: {0}@{1}")] - VersionNotInstalled(String, String), + #[error("[{0}] plugin not installed")] + PluginNotInstalled(PluginName), + #[error("[{0}] version {1} not installed: {1}")] + VersionNotInstalled(PluginName, String), + #[error("[{}] script exited with non-zero status: {}", .0, render_exit_status(.1))] + ScriptFailed(PluginName, Option), +} + +fn render_exit_status(exit_status: &Option) -> String { + match exit_status.and_then(|s| s.code()) { + Some(exit_status) => format!("exit code {exit_status}"), + None => "no exit status".into(), + } } diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 9e60544f1..707f2f932 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -1,49 +1,60 @@ -use color_eyre::eyre::Result; -use indoc::formatdoc; -use std::fs; use std::os::unix::fs::PermissionsExt; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; +use std::{fs, io}; -pub fn get_path(rtx_dir: &Path) -> PathBuf { - rtx_dir.join(".fake-asdf") -} +use indoc::formatdoc; +use once_cell::sync::OnceCell; + +use crate::env; -pub fn setup(path: &Path) -> Result<()> { - let asdf_bin = path.join("asdf"); - if !asdf_bin.exists() { - fs::create_dir_all(path)?; - fs::write( - &asdf_bin, - formatdoc! {r#" +fn setup() -> color_eyre::Result { + static SETUP: OnceCell = OnceCell::new(); + let path = SETUP.get_or_try_init(|| { + let path = env::RTX_DATA_DIR.join(".fake-asdf"); + let asdf_bin = path.join("asdf"); + if !asdf_bin.exists() { + fs::create_dir_all(&path)?; + fs::write( + &asdf_bin, + formatdoc! {r#" #!/bin/sh rtx="${{RTX_EXE:-rtx}}" "$rtx" asdf "$@" "#}, - )?; - let mut perms = asdf_bin.metadata()?.permissions(); - perms.set_mode(0o755); - fs::set_permissions(&asdf_bin, perms)?; - } - Ok(()) + )?; + let mut perms = asdf_bin.metadata()?.permissions(); + perms.set_mode(0o755); + fs::set_permissions(&asdf_bin, perms)?; + } + Ok::(path) + })?; + + Ok(path.clone()) +} + +pub fn get_path_with_fake_asdf() -> String { + let mut path = vec![]; + match setup() { + Ok(fake_asdf_path) => { + path.push(fake_asdf_path.to_string_lossy().to_string()); + } + Err(e) => { + warn!("Failed to setup fake asdf: {}", e); + } + }; + path.push(env::PATH.to_string_lossy().to_string()); + path.join(":") } #[cfg(test)] mod tests { - - use super::*; use std::fs; - use std::path::PathBuf; - #[test] - fn test_get_path() { - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); - assert_eq!(get_path(&path), path.join(".fake-asdf")); - } + use super::*; #[test] fn test_setup() { - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures/fake-asdf"); - setup(&path).unwrap(); + let path = setup().unwrap(); assert!(path.join("asdf").exists()); fs::remove_dir_all(&path).unwrap(); } diff --git a/src/file.rs b/src/file.rs index cc3aca53e..3efb55439 100644 --- a/src/file.rs +++ b/src/file.rs @@ -7,6 +7,15 @@ use filetime::{set_file_times, FileTime}; use crate::dirs; +pub fn basename(path: &Path) -> Option { + path.file_name().map(|f| f.to_string_lossy().to_string()) +} + +pub fn display_path(path: &Path) -> String { + let home = dirs::HOME.to_string_lossy(); + path.to_string_lossy().replace(home.as_ref(), "~") +} + pub fn changed_within(f: &Path, within: Duration) -> Result { let now = std::time::SystemTime::now(); let last_modified = f.metadata()?.modified()?; diff --git a/src/git.rs b/src/git.rs index a180cf8d3..b8b8a65f0 100644 --- a/src/git.rs +++ b/src/git.rs @@ -14,6 +14,10 @@ impl Git { Self { dir } } + pub fn is_repo(&self) -> bool { + self.dir.join(".git").is_dir() + } + pub fn remote_default_branch(&self) -> Result { let branch = cmd!( "git", @@ -74,8 +78,8 @@ impl Git { Ok(sha) } - pub fn get_remote_url(&self) -> Result { - let url = cmd!( + pub fn get_remote_url(&self) -> Option { + let res = cmd!( "git", "-C", &self.dir, @@ -83,9 +87,21 @@ impl Git { "--get", "remote.origin.url" ) - .read()?; - debug!("remote url for {}: {}", self.dir.display(), &url); - Ok(url) + .read(); + match res { + Ok(url) => { + debug!("remote url for {}: {}", self.dir.display(), &url); + Some(url) + } + Err(err) => { + warn!( + "failed to get remote url for {}: {}", + self.dir.display(), + err + ); + None + } + } } } diff --git a/src/plugins/cache.rs b/src/plugins/cache.rs new file mode 100644 index 000000000..d5de60bda --- /dev/null +++ b/src/plugins/cache.rs @@ -0,0 +1,32 @@ +use flate2::read::GzDecoder; +use flate2::write::GzEncoder; +use flate2::Compression; +use serde_derive::{Deserialize, Serialize}; +use std::fs::File; +use std::io::{Read, Write}; +use std::path::Path; + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct PluginCache { + pub versions: Vec, + pub legacy_filenames: Vec, + pub aliases: Vec<(String, String)>, +} + +impl PluginCache { + pub fn parse(path: &Path) -> color_eyre::Result { + trace!("reading plugin cache from {}", path.to_string_lossy()); + let mut gz = GzDecoder::new(File::open(path)?); + let mut bytes = Vec::new(); + gz.read_to_end(&mut bytes)?; + Ok(rmp_serde::from_slice(&bytes)?) + } + + pub fn write(&self, path: &Path) -> color_eyre::Result<()> { + trace!("writing plugin cache to {}", path.to_string_lossy()); + let mut gz = GzEncoder::new(File::create(path)?, Compression::fast()); + gz.write_all(&rmp_serde::to_vec_named(self)?[..])?; + + Ok(()) + } +} diff --git a/src/plugins.rs b/src/plugins/mod.rs similarity index 73% rename from src/plugins.rs rename to src/plugins/mod.rs index 51cbae052..b18b17dc8 100644 --- a/src/plugins.rs +++ b/src/plugins/mod.rs @@ -1,38 +1,37 @@ -use std::fmt::{Display, Formatter}; use std::fs; -use std::fs::{remove_file, File}; -use std::io::{Read, Write}; +use std::fs::remove_file; use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; use color_eyre::eyre::WrapErr; use color_eyre::eyre::{eyre, Result}; -use duct::Expression; -use flate2::read::GzDecoder; -use flate2::write::GzEncoder; -use flate2::Compression; use itertools::Itertools; use lazy_static::lazy_static; use owo_colors::{OwoColorize, Stream}; use regex::Regex; -use serde_derive::{Deserialize, Serialize}; use versions::Mess; -use crate::cli::args::runtime::RuntimeArg; +use cache::PluginCache; +pub use script_manager::{InstallType, Script, ScriptManager}; + use crate::cmd::cmd; -use crate::config::settings::{MissingRuntimeBehavior, Settings}; +use crate::config::{MissingRuntimeBehavior, Settings}; use crate::errors::Error::PluginNotInstalled; use crate::file::changed_within; use crate::git::Git; use crate::hash::hash_to_str; +use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::shorthand_repository::ShorthandRepo; -use crate::ui::prompt::prompt; -use crate::{dirs, env, file}; -use crate::{fake_asdf, ui}; +use crate::ui::prompt; +use crate::{dirs, file}; + +mod cache; +mod script_manager; pub type PluginName = String; +/// This represents a plugin installed to ~/.local/share/rtx/plugins #[derive(Debug, Clone)] pub struct Plugin { pub name: PluginName, @@ -41,15 +40,7 @@ pub struct Plugin { downloads_path: PathBuf, installs_path: PathBuf, cache: Option, -} - -#[derive(Debug, Clone)] -pub enum PluginSource { - ToolVersions(PathBuf), - RtxRc(PathBuf), - LegacyVersionFile(PathBuf), - Argument(RuntimeArg), - Environment(String, String), + script_man: ScriptManager, } impl Plugin { @@ -58,6 +49,7 @@ impl Plugin { Self { name: name.into(), cache_path: plugin_path.join(".rtxcache.msgpack.gz"), + script_man: ScriptManager::new(plugin_path.clone()), plugin_path, downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), @@ -93,7 +85,7 @@ impl Plugin { self.plugin_path.exists() } - pub fn get_remote_url(&self) -> Result { + pub fn get_remote_url(&self) -> Option { let git = Git::new(self.plugin_path.to_path_buf()); git.get_remote_url() } @@ -104,7 +96,6 @@ impl Plugin { "rtx: Installing plugin {}...", self.name.if_supports_color(Stream::Stderr, |t| t.cyan()) ); - fake_asdf::setup(&fake_asdf::get_path(dirs::ROOT.as_path()))?; if self.is_installed() { self.uninstall()?; @@ -129,7 +120,7 @@ impl Plugin { self.install(&repo)?; Ok(true) } - MissingRuntimeBehavior::Prompt => match prompt_for_install(&self.name) { + MissingRuntimeBehavior::Prompt => match prompt::prompt_for_install(&self.name) { true => { self.install(&repo)?; Ok(true) @@ -156,7 +147,16 @@ impl Plugin { } pub fn update(&self, gitref: Option) -> Result<()> { - let git = Git::new(self.plugin_path.to_path_buf()); + let plugin_path = self.plugin_path.to_path_buf(); + if plugin_path.is_symlink() { + warn!("Plugin: {} is a symlink, not updating", self.name); + return Ok(()); + } + let git = Git::new(plugin_path); + if !git.is_repo() { + warn!("Plugin {} is not a git repository not updating", self.name); + return Ok(()); + } // TODO: asdf_run_hook "pre_plugin_update" let (_pre, _post) = git.update(gitref)?; // TODO: asdf_run_hook "post_plugin_update" @@ -278,23 +278,14 @@ impl Plugin { exit(result.status.code().unwrap_or(1)); } - fn run_script(&self, script: &str, args: Vec) -> Result { - if !self.is_installed() { - return Err(PluginNotInstalled(self.name.clone()).into()); - } - Ok(cmd(self.plugin_path.join("bin").join(script), args) - .env("RTX", "1") - .env("RTX_EXE", env::RTX_EXE.as_path())) - } - fn fetch_remote_versions(&self) -> Result> { - let stdout = self - .run_script("list-all", vec![])? - .read() - .wrap_err_with(|| eyre!("error running list-all script for {}", self.name))?; - let versions = stdout.split_whitespace().map(|v| v.into()).collect(); - - Ok(versions) + Ok(self + .script_man + .cmd(Script::ListAll) + .read()? + .split_whitespace() + .map(|v| v.into()) + .collect()) } fn get_cache(&self) -> Result { @@ -356,31 +347,22 @@ impl Plugin { } fn fetch_legacy_filenames(&self) -> Result> { - if !self - .plugin_path - .join("bin") - .join("list-legacy-filenames") - .is_file() - { + if !self.script_man.script_exists(&Script::ListLegacyFilenames) { return Ok(vec![]); } - let stdout = self - .run_script("list-legacy-filenames", vec![])? - .read() - .wrap_err_with(|| eyre!("running list-legacy-filenames script for {}", self.name))?; - let versions = stdout.split_whitespace().map(|v| v.into()).collect(); - - Ok(versions) + Ok(self + .script_man + .read(Script::ListLegacyFilenames)? + .split_whitespace() + .map(|v| v.into()) + .collect()) } fn fetch_aliases(&self) -> Result> { - if !self.plugin_path.join("bin").join("list-aliases").is_file() { + if !self.script_man.script_exists(&Script::ListAliases) { return Ok(vec![]); } - let stdout = self - .run_script("list-aliases", vec![])? - .read() - .wrap_err_with(|| eyre!("running list-aliases script for {}", self.name))?; + let stdout = self.script_man.read(Script::ListAliases)?; let aliases = stdout .lines() .filter_map(|line| { @@ -404,17 +386,8 @@ impl Plugin { } trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); let legacy_version = self - .run_script( - "parse-legacy-file", - vec![legacy_file.to_string_lossy().into()], - )? - .read() - .wrap_err_with(|| { - eyre!( - "error parsing legacy file: {}", - legacy_file.to_string_lossy() - ) - })? + .script_man + .read(ParseLegacyFile(legacy_file.to_string_lossy().into()))? .trim() .to_string(); @@ -446,72 +419,17 @@ impl Plugin { } } -fn prompt_for_install(thing: &str) -> bool { - match ui::is_tty() { - true => { - eprint!( - "rtx: Would you like to install plugin {}? [Y/n] ", - thing.cyan() - ); - matches!(prompt().to_lowercase().as_str(), "" | "y" | "yes") - } - false => false, - } -} - impl PartialEq for Plugin { fn eq(&self, other: &Self) -> bool { self.name == other.name } } -#[derive(Debug, Serialize, Deserialize, Default, Clone)] -struct PluginCache { - versions: Vec, - legacy_filenames: Vec, - aliases: Vec<(String, String)>, -} - -impl PluginCache { - fn parse(path: &Path) -> Result { - trace!("reading plugin cache from {}", path.to_string_lossy()); - let mut gz = GzDecoder::new(File::open(path)?); - let mut bytes = Vec::new(); - gz.read_to_end(&mut bytes)?; - Ok(rmp_serde::from_slice(&bytes)?) - } - - fn write(&self, path: &Path) -> Result<()> { - trace!("writing plugin cache to {}", path.to_string_lossy()); - let mut gz = GzEncoder::new(File::create(path)?, Compression::fast()); - gz.write_all(&rmp_serde::to_vec_named(self)?[..])?; - - Ok(()) - } -} - -impl Display for PluginSource { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - match self { - PluginSource::ToolVersions(path) => write!(f, "{}", display_path(path)), - PluginSource::RtxRc(path) => write!(f, "{}", display_path(path)), - PluginSource::LegacyVersionFile(path) => write!(f, "{}", display_path(path)), - PluginSource::Argument(arg) => write!(f, "--runtime {arg}"), - PluginSource::Environment(k, v) => write!(f, "{k}={v}"), - } - } -} - -fn display_path(path: &Path) -> String { - let home = dirs::HOME.to_string_lossy(); - path.to_string_lossy().replace(home.as_ref(), "~") -} - #[cfg(test)] mod test { use pretty_assertions::assert_str_eq; - use crate::assert_cli; + use crate::{assert_cli, env}; use super::*; diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs new file mode 100644 index 000000000..5efd36464 --- /dev/null +++ b/src/plugins/script_manager.rs @@ -0,0 +1,151 @@ +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::path::PathBuf; +use std::process::Output; + +use color_eyre::eyre::{Context, Result}; +use duct::Expression; +use indexmap::{indexmap, IndexMap}; +use once_cell::sync::Lazy; + +use crate::cmd::cmd; +use crate::env; +use crate::errors::Error::ScriptFailed; +use crate::file::basename; + +#[derive(Debug, Clone)] +pub struct ScriptManager { + pub plugin_path: PathBuf, + pub plugin_name: String, + pub env: IndexMap, +} + +#[derive(Debug, Clone)] +pub enum Script { + // PreInstall, + // PostInstall, + // PreUninstall, + // PostUninstall, + + // Plugin + ListAll, + ListLegacyFilenames, + ListAliases, + ParseLegacyFile(String), + + // RuntimeVersion + Download(InstallType), + Install(InstallType), + Uninstall, + ListBinPaths, + // ExecEnv, +} + +impl fmt::Display for Script { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + // Plugin + Script::ListAll => write!(f, "list-all"), + Script::ListLegacyFilenames => write!(f, "list-legacy-filenames"), + Script::ListAliases => write!(f, "list-aliases"), + Script::ParseLegacyFile(_) => write!(f, "parse-legacy-file"), + + // RuntimeVersion + Script::Install(_) => write!(f, "install"), + Script::Uninstall => write!(f, "uninstall"), + Script::ListBinPaths => write!(f, "list-bin-paths"), + // Script::ExecEnv => write!(f, "exec-env"), + Script::Download(_) => write!(f, "download"), + } + } +} + +#[derive(Debug, Clone)] +pub enum InstallType { + Version, +} + +impl Display for InstallType { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + InstallType::Version => write!(f, "version"), + } + } +} + +static INITIAL_ENV: Lazy> = Lazy::new(|| { + (indexmap! { + "RTX_EXE" => env::RTX_EXE.to_string_lossy(), + }) + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect() +}); + +impl ScriptManager { + pub fn new(plugin_path: PathBuf) -> Self { + Self { + plugin_name: basename(&plugin_path).expect("invalid plugin path"), + env: INITIAL_ENV.clone(), + plugin_path, + } + } + + pub fn with_env(mut self, k: String, v: String) -> Self { + self.env.insert(k, v); + self + } + + pub fn with_envs(mut self, envs: I) -> Self + where + I: IntoIterator, + { + self.env.extend(envs); + self + } + + pub fn get_script_path(&self, script: &Script) -> PathBuf { + self.plugin_path.join("bin").join(script.to_string()) + } + + pub fn script_exists(&self, script: &Script) -> bool { + self.get_script_path(script).is_file() + } + + pub fn cmd(&self, script: Script) -> Expression { + let mut env = self.env.clone(); + let args = match &script { + Script::ParseLegacyFile(filename) => vec![filename.clone()], + Script::Install(install_type) | Script::Download(install_type) => { + env.insert("ASDF_INSTALL_TYPE".to_string(), install_type.to_string()); + vec![] + } + _ => vec![], + }; + let script_path = self.get_script_path(&script); + // if !script_path.exists() { + // return Err(PluginNotInstalled(self.plugin_name.clone()).into()); + // } + let mut cmd = cmd(&script_path, args); + for (k, v) in env.iter() { + cmd = cmd.env(k, v); + } + cmd + } + + pub fn run(&self, script: Script) -> Result<()> { + let cmd = self.cmd(script); + let Output { status, .. } = cmd.unchecked().run()?; + + match status.success() { + true => Ok(()), + false => Err(ScriptFailed(self.plugin_name.clone(), Some(status)).into()), + } + } + + pub fn read(&self, script: Script) -> Result { + self.cmd(script) + .read() + .with_context(|| ScriptFailed(self.plugin_name.clone(), None)) + } +} diff --git a/src/runtimes.rs b/src/runtimes/mod.rs similarity index 70% rename from src/runtimes.rs rename to src/runtimes/mod.rs index faf465f62..928ba6e60 100644 --- a/src/runtimes.rs +++ b/src/runtimes/mod.rs @@ -1,26 +1,28 @@ use std::collections::HashMap; use std::error::Error; - use std::fmt; use std::fmt::{Display, Formatter}; -use std::fs::{create_dir_all, remove_dir_all, File}; -use std::io::Write; +use std::fs::{create_dir_all, remove_dir_all}; use std::path::{Path, PathBuf}; use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; -use duct::Expression; use owo_colors::{OwoColorize, Stream}; -use serde_derive::{Deserialize, Serialize}; -use crate::config::settings::{MissingRuntimeBehavior, Settings}; +use runtime_conf::RuntimeConf; + use crate::config::Config; +use crate::config::{MissingRuntimeBehavior, Settings}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; -use crate::plugins::Plugin; +use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; use crate::ui::prompt; -use crate::{cmd, dirs, env, fake_asdf, file, ui}; +use crate::{dirs, env, fake_asdf, file}; + +mod runtime_conf; +/// These represent individual plugin@version pairs of runtimes +/// installed to ~/.local/share/rtx/runtimes #[derive(Debug, Clone)] pub struct RuntimeVersion { pub version: String, @@ -28,13 +30,21 @@ pub struct RuntimeVersion { pub install_path: PathBuf, download_path: PathBuf, runtime_conf_path: PathBuf, + script_man: ScriptManager, } impl RuntimeVersion { pub fn new(plugin: Arc, version: &str) -> Self { let install_path = dirs::INSTALLS.join(&plugin.name).join(version); + let download_path = dirs::DOWNLOADS.join(&plugin.name).join(version); Self { runtime_conf_path: install_path.join(".rtxconf.msgpack"), + script_man: build_script_man( + version, + &plugin.plugin_path, + &install_path, + &download_path, + ), download_path: dirs::DOWNLOADS.join(&plugin.name).join(version), install_path, version: version.into(), @@ -54,23 +64,22 @@ impl RuntimeVersion { Ok(versions) } - pub fn install(&self, install_type: &str, config: &Config) -> Result<()> { - debug!( - "install {} {} {}", - self.plugin.name, self.version, install_type - ); - + pub fn install(&self, install_type: InstallType, config: &Config) -> Result<()> { + let plugin = &self.plugin; let settings = &config.settings; + debug!("install {} {} {}", plugin.name, self.version, install_type); + if !self.plugin.ensure_installed(settings)? { return Err(PluginNotInstalled(self.plugin.name.clone()).into()); } - fake_asdf::setup(&fake_asdf::get_path(dirs::ROOT.as_path()))?; self.create_install_dirs()?; + let download = Script::Download(install_type.clone()); + let install = Script::Install(install_type); - if self.plugin.plugin_path.join("bin/download").is_file() { - self.run_script("download") - .env("ASDF_INSTALL_TYPE", install_type) + if self.script_man.script_exists(&download) { + self.script_man + .cmd(download) .stdout_to_stderr() .run() .map_err(|err| { @@ -79,8 +88,8 @@ impl RuntimeVersion { })?; } - self.run_script("install") - .env("ASDF_INSTALL_TYPE", install_type) + self.script_man + .cmd(install) .stdout_to_stderr() .run() .map_err(|err| { @@ -126,12 +135,12 @@ impl RuntimeVersion { } match config.settings.missing_runtime_behavior { MissingRuntimeBehavior::AutoInstall => { - self.install("version", config)?; + self.install(InstallType::Version, config)?; Ok(true) } MissingRuntimeBehavior::Prompt => { if prompt_for_install(&format!("{self}")) { - self.install("version", config)?; + self.install(InstallType::Version, config)?; Ok(true) } else { Ok(false) @@ -162,7 +171,7 @@ impl RuntimeVersion { pub fn uninstall(&self) -> Result<()> { debug!("uninstall {} {}", self.plugin.name, self.version); if self.plugin.plugin_path.join("bin/uninstall").exists() { - let err = self.run_script("uninstall").run(); + let err = self.script_man.run(Script::Uninstall); if err.is_err() { warn!("Failed to run uninstall script: {}", err.unwrap_err()); } @@ -193,9 +202,7 @@ impl RuntimeVersion { if !self.is_installed() || !script.exists() { return Ok(HashMap::new()); } - let mut env: HashMap = env::PRISTINE_ENV.clone(); - env.extend(self.script_env()); - let ed = EnvDiff::from_bash_script(&script, env)?; + let ed = EnvDiff::from_bash_script(&script, &self.script_man.env)?; let env = ed .to_patches() .into_iter() @@ -208,44 +215,10 @@ impl RuntimeVersion { Ok(env) } - fn run_script(&self, script: &str) -> Expression { - let mut cmd = cmd!(self.plugin.plugin_path.join("bin").join(script)); - for (k, v) in self.script_env() { - cmd = cmd.env(k, v); - } - cmd - } - - fn script_env(&self) -> HashMap { - let path = [ - fake_asdf::get_path(dirs::ROOT.as_path()).to_string_lossy(), - env::PATH.to_string_lossy(), - ] - .join(":"); - return HashMap::from([ - ("RTX".into(), "1".into()), - ( - "RTX_EXE".into(), - env::RTX_EXE.as_path().to_string_lossy().into(), - ), - ("PATH".into(), path), - ("ASDF_INSTALL_VERSION".into(), self.version.to_string()), - ( - "ASDF_INSTALL_PATH".into(), - self.install_path.to_string_lossy().into(), - ), - ( - "ASDF_DOWNLOAD_PATH".into(), - self.download_path.to_string_lossy().into(), - ), - ("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()), - ]); - } - fn get_bin_paths(&self) -> Result> { let list_bin_paths = self.plugin.plugin_path.join("bin/list-bin-paths"); if list_bin_paths.exists() { - let output = self.run_script("list-bin-paths").read()?; + let output = self.script_man.cmd(Script::ListBinPaths).read()?; Ok(output.split_whitespace().map(|e| e.into()).collect()) } else { Ok(vec!["bin".into()]) @@ -281,7 +254,7 @@ impl PartialEq for RuntimeVersion { } fn prompt_for_install(thing: &str) -> bool { - match ui::is_tty() { + match prompt::is_tty() { true => { eprint!( "rtx: Would you like to install {}? [Y/n] ", @@ -293,25 +266,23 @@ fn prompt_for_install(thing: &str) -> bool { } } -#[derive(Debug, Serialize, Deserialize, Default)] -struct RuntimeConf { - bin_paths: Vec, -} - -impl RuntimeConf { - fn parse(path: &Path) -> Result { - Ok(rmp_serde::from_read(File::open(path)?)?) - // let contents = std::fs::read_to_string(path) - // .wrap_err_with(|| format!("failed to read {}", path.to_string_lossy()))?; - // let conf: Self = toml::from_str(&contents) - // .wrap_err_with(|| format!("failed to from_file {}", path.to_string_lossy()))?; - - // Ok(conf) - } - - fn write(&self, path: &Path) -> Result<()> { - let bytes = rmp_serde::to_vec_named(self)?; - File::create(path)?.write_all(&bytes)?; - Ok(()) - } +fn build_script_man( + version: &str, + plugin_path: &Path, + install_path: &Path, + download_path: &Path, +) -> ScriptManager { + ScriptManager::new(plugin_path.to_path_buf()) + .with_envs(env::PRISTINE_ENV.clone()) + .with_env("PATH".into(), fake_asdf::get_path_with_fake_asdf()) + .with_env("ASDF_INSTALL_VERSION".into(), version.to_string()) + .with_env( + "ASDF_INSTALL_PATH".into(), + install_path.to_string_lossy().to_string(), + ) + .with_env( + "ASDF_DOWNLOAD_PATH".into(), + download_path.to_string_lossy().to_string(), + ) + .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()) } diff --git a/src/runtimes/runtime_conf.rs b/src/runtimes/runtime_conf.rs new file mode 100644 index 000000000..a427f24cf --- /dev/null +++ b/src/runtimes/runtime_conf.rs @@ -0,0 +1,27 @@ +use serde_derive::{Deserialize, Serialize}; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct RuntimeConf { + pub bin_paths: Vec, +} + +impl RuntimeConf { + pub fn parse(path: &Path) -> color_eyre::Result { + Ok(rmp_serde::from_read(File::open(path)?)?) + // let contents = std::fs::read_to_string(path) + // .wrap_err_with(|| format!("failed to read {}", path.to_string_lossy()))?; + // let conf: Self = toml::from_str(&contents) + // .wrap_err_with(|| format!("failed to from_file {}", path.to_string_lossy()))?; + + // Ok(conf) + } + + pub fn write(&self, path: &Path) -> color_eyre::Result<()> { + let bytes = rmp_serde::to_vec_named(self)?; + File::create(path)?.write_all(&bytes)?; + Ok(()) + } +} diff --git a/src/shorthand_repository.rs b/src/shorthand_repository.rs index 952662131..189b48686 100644 --- a/src/shorthand_repository.rs +++ b/src/shorthand_repository.rs @@ -5,7 +5,7 @@ use std::time::Duration; use color_eyre::eyre::{eyre, Result}; use owo_colors::{OwoColorize, Stream}; -use crate::config::settings::Settings; +use crate::config::Settings; use crate::file::changed_within; use crate::git::Git; use crate::{dirs, file}; diff --git a/src/test.rs b/src/test.rs index 53d17b564..231bc2862 100644 --- a/src/test.rs +++ b/src/test.rs @@ -31,6 +31,9 @@ fn init() { assert_cli!("plugin", "install", "shfmt"); assert_cli!("plugin", "install", "nodejs"); assert_cli!("plugin", "install", "jq"); + assert_cli!("plugin", "install", "golang"); + assert_cli!("plugin", "install", "python"); + assert_cli!("plugin", "install", "rust"); assert_cli!("install"); } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index a1237199b..8bf84783c 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,7 +1 @@ pub mod prompt; - -pub fn is_tty() -> bool { - atty::is(atty::Stream::Stdin) - && atty::is(atty::Stream::Stderr) - && atty::is(atty::Stream::Stdout) -} diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 6b0424931..b3f02523d 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,3 +1,4 @@ +use owo_colors::OwoColorize; use std::io::stdin; pub fn prompt() -> String { @@ -6,3 +7,22 @@ pub fn prompt() -> String { input.trim().to_string() } + +pub fn prompt_for_install(thing: &str) -> bool { + match is_tty() { + true => { + eprint!( + "rtx: Would you like to install plugin {}? [Y/n] ", + thing.cyan() + ); + matches!(prompt().to_lowercase().as_str(), "" | "y" | "yes") + } + false => false, + } +} + +pub fn is_tty() -> bool { + atty::is(atty::Stream::Stdin) + && atty::is(atty::Stream::Stderr) + && atty::is(atty::Stream::Stdout) +} From 2c1c8fe3c38d3366c1996b94ee39f72cf7c07045 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 13:56:40 -0600 Subject: [PATCH 0033/1891] added shell completions (#28) --- Cargo.lock | 10 + Cargo.toml | 1 + README.md | 21 + completions/_rtx | 1371 ++++++++++++++++++++++++++++++ completions/rtx.bash | 1935 ++++++++++++++++++++++++++++++++++++++++++ completions/rtx.fish | 210 +++++ justfile | 5 + src/cli/complete.rs | 48 ++ src/cli/mod.rs | 3 + 9 files changed, 3604 insertions(+) create mode 100644 completions/_rtx create mode 100644 completions/rtx.bash create mode 100644 completions/rtx.fish create mode 100644 src/cli/complete.rs diff --git a/Cargo.lock b/Cargo.lock index 5c936784e..e73fc8fe5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,6 +146,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "clap_complete" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.1.0" @@ -1006,6 +1015,7 @@ dependencies = [ "build-time", "chrono", "clap", + "clap_complete", "color-eyre", "ctor", "dirs-next", diff --git a/Cargo.toml b/Cargo.toml index 4d12a6367..2fb41e718 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ versions = "4.1.0" build-time = "0.1.2" serde_json = "1.0.91" once_cell = "1.17.0" +clap_complete = "4.1.1" [target.'cfg(unix)'.dependencies] exec = "0.3.1" diff --git a/README.md b/README.md index 3fdb50dfe..45493e53b 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,27 @@ Examples: $ rtx aliases nodejs lts/hydrogen 18.0.0 +``` +### `rtx complete` + +``` +generate shell completions + +Usage: complete --shell + +Options: + -s, --shell + shell type + + [possible values: bash, elvish, fish, powershell, zsh] + + -h, --help + Print help (see a summary with '-h') + + +Examples: + $ rtx complete + ``` ### `rtx deactivate` diff --git a/completions/_rtx b/completions/_rtx new file mode 100644 index 000000000..154188369 --- /dev/null +++ b/completions/_rtx @@ -0,0 +1,1371 @@ +#compdef rtx + +autoload -U is-at-least + +_rtx() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'-V[Print version]' \ +'--version[Print version]' \ +":: :_rtx_commands" \ +"*::: :->rtx" \ +&& ret=0 + case $state in + (rtx) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-command-$line[1]:" + case $line[1] in + (activate) +_arguments "${_arguments_options[@]}" \ +'-s+[Shell type to generate the script for]:SHELL:(bash fish zsh)' \ +'--shell=[Shell type to generate the script for]:SHELL:(bash fish zsh)' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(alias) +_arguments "${_arguments_options[@]}" \ +'-p+[filter aliases by plugin]:PLUGIN: ' \ +'--plugin=[filter aliases by plugin]:PLUGIN: ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help]' \ +'--help[Print help]' \ +":: :_rtx__alias_commands" \ +"*::: :->alias" \ +&& ret=0 + + case $state in + (alias) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-alias-command-$line[1]:" + case $line[1] in + (ls) +_arguments "${_arguments_options[@]}" \ +'-p+[Show aliases for ]:PLUGIN: ' \ +'--plugin=[Show aliases for ]:PLUGIN: ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__alias__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-alias-help-command-$line[1]:" + case $line[1] in + (ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; +(asdf) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help]' \ +'--help[Print help]' \ +'*::args -- all arguments:' \ +&& ret=0 +;; +(current) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::plugin -- plugin to filter by:' \ +&& ret=0 +;; +(deactivate) +_arguments "${_arguments_options[@]}" \ +'-s+[shell type to generate the script for]:SHELL:(bash fish zsh)' \ +'--shell=[shell type to generate the script for]:SHELL:(bash fish zsh)' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(direnv) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +":: :_rtx__direnv_commands" \ +"*::: :->direnv" \ +&& ret=0 + + case $state in + (direnv) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-direnv-command-$line[1]:" + case $line[1] in + (envrc) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(exec) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(activate) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__direnv__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-direnv-help-command-$line[1]:" + case $line[1] in + (envrc) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(exec) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(activate) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; +(doctor) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(complete) +_arguments "${_arguments_options[@]}" \ +'-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ +'--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(env) +_arguments "${_arguments_options[@]}" \ +'-s+[Shell type to generate environment variables for]:SHELL:(bash fish zsh)' \ +'--shell=[Shell type to generate environment variables for]:SHELL:(bash fish zsh)' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::runtime -- runtime version to use:' \ +&& ret=0 +;; +(exec) +_arguments "${_arguments_options[@]}" \ +'()-c+[the command string to execute]:C: ' \ +'()--command=[the command string to execute]:C: ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::runtime -- runtime(s) to start:' \ +'*::command -- the command string to execute (same as --command):' \ +&& ret=0 +;; +(global) +_arguments "${_arguments_options[@]}" \ +'*--remove=[remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--fuzzy[save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0`]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::runtime -- runtimes:' \ +&& ret=0 +;; +(hook-env) +_arguments "${_arguments_options[@]}" \ +'-s+[Shell type to generate script for]:SHELL:(bash fish zsh)' \ +'--shell=[Shell type to generate script for]:SHELL:(bash fish zsh)' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(install) +_arguments "${_arguments_options[@]}" \ +'()*-p+[only install runtime(s) for ]:PLUGIN: ' \ +'()*--plugin=[only install runtime(s) for ]:PLUGIN: ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-f[force reinstall even if already installed]' \ +'--force[force reinstall even if already installed]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::runtime -- runtime(s) to install:' \ +&& ret=0 +;; +(latest) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':runtime -- Runtime to get the latest version of:' \ +'::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ +&& ret=0 +;; +(local) +_arguments "${_arguments_options[@]}" \ +'*--remove=[remove the plugin(s) from .tool-versions]:PLUGIN: ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-p[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ +'--parent[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ +'--fuzzy[save fuzzy match to .tool-versions e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions by default it would save the exact version, e.g.: `nodejs 20.0.0`]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::runtime -- runtimes to add to .tool-versions:' \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +'-p+[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ +'--plugin=[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-c[Only show runtimes currently specified in .tool-versions]' \ +'--current[Only show runtimes currently specified in .tool-versions]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(ls-remote) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':plugin -- Plugin:' \ +&& ret=0 +;; +(plugins) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-a[list all available remote plugins]' \ +'--all[list all available remote plugins]' \ +'-u[show the git url for each plugin]' \ +'--urls[show the git url for each plugin]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +":: :_rtx__plugins_commands" \ +"*::: :->plugins" \ +&& ret=0 + + case $state in + (plugins) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-plugins-command-$line[1]:" + case $line[1] in + (install) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-f[Reinstalls even if plugin exists]' \ +'--force[Reinstalls even if plugin exists]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':name -- The name of the plugin to install:' \ +'::git_url -- The git url of the plugin:_urls' \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-a[list all available remote plugins]' \ +'--all[list all available remote plugins]' \ +'-u[show the git url for each plugin]' \ +'--urls[show the git url for each plugin]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(ls-remote) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-u[show the git url for each plugin]' \ +'--urls[show the git url for each plugin]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(uninstall) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':plugin -- plugin to remove:' \ +&& ret=0 +;; +(update) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::plugin -- plugin(s) to update:' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__plugins__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-plugins-help-command-$line[1]:" + case $line[1] in + (install) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls-remote) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(uninstall) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(update) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; +(settings) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help]' \ +'--help[Print help]' \ +":: :_rtx__settings_commands" \ +"*::: :->settings" \ +&& ret=0 + + case $state in + (settings) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-settings-command-$line[1]:" + case $line[1] in + (get) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':key -- The setting to show:' \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':key -- The setting to set:' \ +':value -- The value to set:' \ +&& ret=0 +;; +(unset) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':key -- The setting to remove:' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__settings__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-settings-help-command-$line[1]:" + case $line[1] in + (get) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(unset) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; +(uninstall) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::runtime -- runtime(s) to remove:' \ +&& ret=0 +;; +(version) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(where) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':runtime -- runtime(s) to remove:' \ +'::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ +&& ret=0 +;; +(render-help) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-help-command-$line[1]:" + case $line[1] in + (activate) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(alias) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__help__alias_commands" \ +"*::: :->alias" \ +&& ret=0 + + case $state in + (alias) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-help-alias-command-$line[1]:" + case $line[1] in + (ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; +(asdf) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(current) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(deactivate) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(direnv) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__help__direnv_commands" \ +"*::: :->direnv" \ +&& ret=0 + + case $state in + (direnv) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-help-direnv-command-$line[1]:" + case $line[1] in + (envrc) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(exec) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(activate) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; +(doctor) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(complete) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(env) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(exec) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(global) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(hook-env) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(install) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(latest) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(local) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls-remote) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(plugins) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__help__plugins_commands" \ +"*::: :->plugins" \ +&& ret=0 + + case $state in + (plugins) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-help-plugins-command-$line[1]:" + case $line[1] in + (install) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls-remote) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(uninstall) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(update) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; +(settings) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__help__settings_commands" \ +"*::: :->settings" \ +&& ret=0 + + case $state in + (settings) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-help-settings-command-$line[1]:" + case $line[1] in + (get) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(unset) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; +(uninstall) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(version) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(where) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(render-help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +} + +(( $+functions[_rtx_commands] )) || +_rtx_commands() { + local commands; commands=( +'activate:Enables rtx to automatically modify runtimes when changing directory' \ +'alias:Manage aliases' \ +'a:Manage aliases' \ +'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ +'current:Get the latest runtime version available for install' \ +'deactivate:disable rtx for current shell session' \ +'direnv:Output direnv function to use rtx inside direnv' \ +'doctor:Check rtx installation for possible problems.' \ +'complete:generate shell completions' \ +'env:exports environment variables to activate rtx in a single shell session' \ +'e:exports environment variables to activate rtx in a single shell session' \ +'exec:execute a command with runtime(s) set' \ +'x:execute a command with runtime(s) set' \ +'global:sets global .tool-versions to include a specified runtime' \ +'g:sets global .tool-versions to include a specified runtime' \ +'hook-env:\[internal\] called by activate hook to update env vars directory change' \ +'install:install a runtime' \ +'i:install a runtime' \ +'latest:get the latest runtime version of a plugin'\''s runtimes' \ +'local:Sets .tool-versions to include a specific runtime' \ +'l:Sets .tool-versions to include a specific runtime' \ +'ls:list installed runtime versions' \ +'list:list installed runtime versions' \ +'ls-remote:list runtime versions available for install +note that these versions are cached for commands like `rtx install nodejs@latest` +however _this_ command will always clear that cache and fetch the latest remote versions' \ +'list-remote:list runtime versions available for install +note that these versions are cached for commands like `rtx install nodejs@latest` +however _this_ command will always clear that cache and fetch the latest remote versions' \ +'plugins:Manage plugins' \ +'p:Manage plugins' \ +'settings:Manage settings' \ +'uninstall:removes runtime versions' \ +'version:Show rtx version' \ +'where:Display the installation path for a runtime' \ +'render-help:internal command to generate markdown from help' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx commands' commands "$@" +} +(( $+functions[_rtx__activate_commands] )) || +_rtx__activate_commands() { + local commands; commands=() + _describe -t commands 'rtx activate commands' commands "$@" +} +(( $+functions[_rtx__direnv__activate_commands] )) || +_rtx__direnv__activate_commands() { + local commands; commands=() + _describe -t commands 'rtx direnv activate commands' commands "$@" +} +(( $+functions[_rtx__direnv__help__activate_commands] )) || +_rtx__direnv__help__activate_commands() { + local commands; commands=() + _describe -t commands 'rtx direnv help activate commands' commands "$@" +} +(( $+functions[_rtx__help__activate_commands] )) || +_rtx__help__activate_commands() { + local commands; commands=() + _describe -t commands 'rtx help activate commands' commands "$@" +} +(( $+functions[_rtx__help__direnv__activate_commands] )) || +_rtx__help__direnv__activate_commands() { + local commands; commands=() + _describe -t commands 'rtx help direnv activate commands' commands "$@" +} +(( $+functions[_rtx__alias_commands] )) || +_rtx__alias_commands() { + local commands; commands=( +'ls:List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`.' \ +'list:List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`.' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx alias commands' commands "$@" +} +(( $+functions[_rtx__help__alias_commands] )) || +_rtx__help__alias_commands() { + local commands; commands=( +'ls:List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`.' \ + ) + _describe -t commands 'rtx help alias commands' commands "$@" +} +(( $+functions[_rtx__asdf_commands] )) || +_rtx__asdf_commands() { + local commands; commands=() + _describe -t commands 'rtx asdf commands' commands "$@" +} +(( $+functions[_rtx__help__asdf_commands] )) || +_rtx__help__asdf_commands() { + local commands; commands=() + _describe -t commands 'rtx help asdf commands' commands "$@" +} +(( $+functions[_rtx__complete_commands] )) || +_rtx__complete_commands() { + local commands; commands=() + _describe -t commands 'rtx complete commands' commands "$@" +} +(( $+functions[_rtx__help__complete_commands] )) || +_rtx__help__complete_commands() { + local commands; commands=() + _describe -t commands 'rtx help complete commands' commands "$@" +} +(( $+functions[_rtx__current_commands] )) || +_rtx__current_commands() { + local commands; commands=() + _describe -t commands 'rtx current commands' commands "$@" +} +(( $+functions[_rtx__help__current_commands] )) || +_rtx__help__current_commands() { + local commands; commands=() + _describe -t commands 'rtx help current commands' commands "$@" +} +(( $+functions[_rtx__deactivate_commands] )) || +_rtx__deactivate_commands() { + local commands; commands=() + _describe -t commands 'rtx deactivate commands' commands "$@" +} +(( $+functions[_rtx__help__deactivate_commands] )) || +_rtx__help__deactivate_commands() { + local commands; commands=() + _describe -t commands 'rtx help deactivate commands' commands "$@" +} +(( $+functions[_rtx__direnv_commands] )) || +_rtx__direnv_commands() { + local commands; commands=( +'envrc:\[internal\] This is an internal command that writes an envrc file +for direnv to consume.' \ +'exec:\[internal\] This is an internal command that writes an envrc file +for direnv to consume.' \ +'activate:Output direnv function to use rtx inside direnv' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx direnv commands' commands "$@" +} +(( $+functions[_rtx__help__direnv_commands] )) || +_rtx__help__direnv_commands() { + local commands; commands=( +'envrc:\[internal\] This is an internal command that writes an envrc file +for direnv to consume.' \ +'exec:\[internal\] This is an internal command that writes an envrc file +for direnv to consume.' \ +'activate:Output direnv function to use rtx inside direnv' \ + ) + _describe -t commands 'rtx help direnv commands' commands "$@" +} +(( $+functions[_rtx__doctor_commands] )) || +_rtx__doctor_commands() { + local commands; commands=() + _describe -t commands 'rtx doctor commands' commands "$@" +} +(( $+functions[_rtx__help__doctor_commands] )) || +_rtx__help__doctor_commands() { + local commands; commands=() + _describe -t commands 'rtx help doctor commands' commands "$@" +} +(( $+functions[_rtx__env_commands] )) || +_rtx__env_commands() { + local commands; commands=() + _describe -t commands 'rtx env commands' commands "$@" +} +(( $+functions[_rtx__help__env_commands] )) || +_rtx__help__env_commands() { + local commands; commands=() + _describe -t commands 'rtx help env commands' commands "$@" +} +(( $+functions[_rtx__direnv__envrc_commands] )) || +_rtx__direnv__envrc_commands() { + local commands; commands=() + _describe -t commands 'rtx direnv envrc commands' commands "$@" +} +(( $+functions[_rtx__direnv__help__envrc_commands] )) || +_rtx__direnv__help__envrc_commands() { + local commands; commands=() + _describe -t commands 'rtx direnv help envrc commands' commands "$@" +} +(( $+functions[_rtx__help__direnv__envrc_commands] )) || +_rtx__help__direnv__envrc_commands() { + local commands; commands=() + _describe -t commands 'rtx help direnv envrc commands' commands "$@" +} +(( $+functions[_rtx__direnv__exec_commands] )) || +_rtx__direnv__exec_commands() { + local commands; commands=() + _describe -t commands 'rtx direnv exec commands' commands "$@" +} +(( $+functions[_rtx__direnv__help__exec_commands] )) || +_rtx__direnv__help__exec_commands() { + local commands; commands=() + _describe -t commands 'rtx direnv help exec commands' commands "$@" +} +(( $+functions[_rtx__exec_commands] )) || +_rtx__exec_commands() { + local commands; commands=() + _describe -t commands 'rtx exec commands' commands "$@" +} +(( $+functions[_rtx__help__direnv__exec_commands] )) || +_rtx__help__direnv__exec_commands() { + local commands; commands=() + _describe -t commands 'rtx help direnv exec commands' commands "$@" +} +(( $+functions[_rtx__help__exec_commands] )) || +_rtx__help__exec_commands() { + local commands; commands=() + _describe -t commands 'rtx help exec commands' commands "$@" +} +(( $+functions[_rtx__help__settings__get_commands] )) || +_rtx__help__settings__get_commands() { + local commands; commands=() + _describe -t commands 'rtx help settings get commands' commands "$@" +} +(( $+functions[_rtx__settings__get_commands] )) || +_rtx__settings__get_commands() { + local commands; commands=() + _describe -t commands 'rtx settings get commands' commands "$@" +} +(( $+functions[_rtx__settings__help__get_commands] )) || +_rtx__settings__help__get_commands() { + local commands; commands=() + _describe -t commands 'rtx settings help get commands' commands "$@" +} +(( $+functions[_rtx__global_commands] )) || +_rtx__global_commands() { + local commands; commands=() + _describe -t commands 'rtx global commands' commands "$@" +} +(( $+functions[_rtx__help__global_commands] )) || +_rtx__help__global_commands() { + local commands; commands=() + _describe -t commands 'rtx help global commands' commands "$@" +} +(( $+functions[_rtx__alias__help_commands] )) || +_rtx__alias__help_commands() { + local commands; commands=( +'ls:List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`.' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx alias help commands' commands "$@" +} +(( $+functions[_rtx__alias__help__help_commands] )) || +_rtx__alias__help__help_commands() { + local commands; commands=() + _describe -t commands 'rtx alias help help commands' commands "$@" +} +(( $+functions[_rtx__direnv__help_commands] )) || +_rtx__direnv__help_commands() { + local commands; commands=( +'envrc:\[internal\] This is an internal command that writes an envrc file +for direnv to consume.' \ +'exec:\[internal\] This is an internal command that writes an envrc file +for direnv to consume.' \ +'activate:Output direnv function to use rtx inside direnv' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx direnv help commands' commands "$@" +} +(( $+functions[_rtx__direnv__help__help_commands] )) || +_rtx__direnv__help__help_commands() { + local commands; commands=() + _describe -t commands 'rtx direnv help help commands' commands "$@" +} +(( $+functions[_rtx__help_commands] )) || +_rtx__help_commands() { + local commands; commands=( +'activate:Enables rtx to automatically modify runtimes when changing directory' \ +'alias:Manage aliases' \ +'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ +'current:Get the latest runtime version available for install' \ +'deactivate:disable rtx for current shell session' \ +'direnv:Output direnv function to use rtx inside direnv' \ +'doctor:Check rtx installation for possible problems.' \ +'complete:generate shell completions' \ +'env:exports environment variables to activate rtx in a single shell session' \ +'exec:execute a command with runtime(s) set' \ +'global:sets global .tool-versions to include a specified runtime' \ +'hook-env:\[internal\] called by activate hook to update env vars directory change' \ +'install:install a runtime' \ +'latest:get the latest runtime version of a plugin'\''s runtimes' \ +'local:Sets .tool-versions to include a specific runtime' \ +'ls:list installed runtime versions' \ +'ls-remote:list runtime versions available for install +note that these versions are cached for commands like `rtx install nodejs@latest` +however _this_ command will always clear that cache and fetch the latest remote versions' \ +'plugins:Manage plugins' \ +'settings:Manage settings' \ +'uninstall:removes runtime versions' \ +'version:Show rtx version' \ +'where:Display the installation path for a runtime' \ +'render-help:internal command to generate markdown from help' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx help commands' commands "$@" +} +(( $+functions[_rtx__help__help_commands] )) || +_rtx__help__help_commands() { + local commands; commands=() + _describe -t commands 'rtx help help commands' commands "$@" +} +(( $+functions[_rtx__plugins__help_commands] )) || +_rtx__plugins__help_commands() { + local commands; commands=( +'install:install a plugin' \ +'ls:List installed plugins' \ +'ls-remote:List all available remote plugins' \ +'uninstall:removes a plugin' \ +'update:updates a plugin to the latest version' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx plugins help commands' commands "$@" +} +(( $+functions[_rtx__plugins__help__help_commands] )) || +_rtx__plugins__help__help_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins help help commands' commands "$@" +} +(( $+functions[_rtx__settings__help_commands] )) || +_rtx__settings__help_commands() { + local commands; commands=( +'get:Show a current setting' \ +'ls:Show current settings' \ +'set:Add/update a setting' \ +'unset:Clears a setting' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx settings help commands' commands "$@" +} +(( $+functions[_rtx__settings__help__help_commands] )) || +_rtx__settings__help__help_commands() { + local commands; commands=() + _describe -t commands 'rtx settings help help commands' commands "$@" +} +(( $+functions[_rtx__help__hook-env_commands] )) || +_rtx__help__hook-env_commands() { + local commands; commands=() + _describe -t commands 'rtx help hook-env commands' commands "$@" +} +(( $+functions[_rtx__hook-env_commands] )) || +_rtx__hook-env_commands() { + local commands; commands=() + _describe -t commands 'rtx hook-env commands' commands "$@" +} +(( $+functions[_rtx__help__install_commands] )) || +_rtx__help__install_commands() { + local commands; commands=() + _describe -t commands 'rtx help install commands' commands "$@" +} +(( $+functions[_rtx__help__plugins__install_commands] )) || +_rtx__help__plugins__install_commands() { + local commands; commands=() + _describe -t commands 'rtx help plugins install commands' commands "$@" +} +(( $+functions[_rtx__install_commands] )) || +_rtx__install_commands() { + local commands; commands=() + _describe -t commands 'rtx install commands' commands "$@" +} +(( $+functions[_rtx__plugins__help__install_commands] )) || +_rtx__plugins__help__install_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins help install commands' commands "$@" +} +(( $+functions[_rtx__plugins__install_commands] )) || +_rtx__plugins__install_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins install commands' commands "$@" +} +(( $+functions[_rtx__help__latest_commands] )) || +_rtx__help__latest_commands() { + local commands; commands=() + _describe -t commands 'rtx help latest commands' commands "$@" +} +(( $+functions[_rtx__latest_commands] )) || +_rtx__latest_commands() { + local commands; commands=() + _describe -t commands 'rtx latest commands' commands "$@" +} +(( $+functions[_rtx__help__local_commands] )) || +_rtx__help__local_commands() { + local commands; commands=() + _describe -t commands 'rtx help local commands' commands "$@" +} +(( $+functions[_rtx__local_commands] )) || +_rtx__local_commands() { + local commands; commands=() + _describe -t commands 'rtx local commands' commands "$@" +} +(( $+functions[_rtx__alias__help__ls_commands] )) || +_rtx__alias__help__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx alias help ls commands' commands "$@" +} +(( $+functions[_rtx__alias__ls_commands] )) || +_rtx__alias__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx alias ls commands' commands "$@" +} +(( $+functions[_rtx__help__alias__ls_commands] )) || +_rtx__help__alias__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx help alias ls commands' commands "$@" +} +(( $+functions[_rtx__help__ls_commands] )) || +_rtx__help__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx help ls commands' commands "$@" +} +(( $+functions[_rtx__help__plugins__ls_commands] )) || +_rtx__help__plugins__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx help plugins ls commands' commands "$@" +} +(( $+functions[_rtx__help__settings__ls_commands] )) || +_rtx__help__settings__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx help settings ls commands' commands "$@" +} +(( $+functions[_rtx__ls_commands] )) || +_rtx__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx ls commands' commands "$@" +} +(( $+functions[_rtx__plugins__help__ls_commands] )) || +_rtx__plugins__help__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins help ls commands' commands "$@" +} +(( $+functions[_rtx__plugins__ls_commands] )) || +_rtx__plugins__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins ls commands' commands "$@" +} +(( $+functions[_rtx__settings__help__ls_commands] )) || +_rtx__settings__help__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx settings help ls commands' commands "$@" +} +(( $+functions[_rtx__settings__ls_commands] )) || +_rtx__settings__ls_commands() { + local commands; commands=() + _describe -t commands 'rtx settings ls commands' commands "$@" +} +(( $+functions[_rtx__help__ls-remote_commands] )) || +_rtx__help__ls-remote_commands() { + local commands; commands=() + _describe -t commands 'rtx help ls-remote commands' commands "$@" +} +(( $+functions[_rtx__help__plugins__ls-remote_commands] )) || +_rtx__help__plugins__ls-remote_commands() { + local commands; commands=() + _describe -t commands 'rtx help plugins ls-remote commands' commands "$@" +} +(( $+functions[_rtx__ls-remote_commands] )) || +_rtx__ls-remote_commands() { + local commands; commands=() + _describe -t commands 'rtx ls-remote commands' commands "$@" +} +(( $+functions[_rtx__plugins__help__ls-remote_commands] )) || +_rtx__plugins__help__ls-remote_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins help ls-remote commands' commands "$@" +} +(( $+functions[_rtx__plugins__ls-remote_commands] )) || +_rtx__plugins__ls-remote_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins ls-remote commands' commands "$@" +} +(( $+functions[_rtx__help__plugins_commands] )) || +_rtx__help__plugins_commands() { + local commands; commands=( +'install:install a plugin' \ +'ls:List installed plugins' \ +'ls-remote:List all available remote plugins' \ +'uninstall:removes a plugin' \ +'update:updates a plugin to the latest version' \ + ) + _describe -t commands 'rtx help plugins commands' commands "$@" +} +(( $+functions[_rtx__plugins_commands] )) || +_rtx__plugins_commands() { + local commands; commands=( +'install:install a plugin' \ +'i:install a plugin' \ +'a:install a plugin' \ +'ls:List installed plugins' \ +'list:List installed plugins' \ +'ls-remote:List all available remote plugins' \ +'list-remote:List all available remote plugins' \ +'uninstall:removes a plugin' \ +'update:updates a plugin to the latest version' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx plugins commands' commands "$@" +} +(( $+functions[_rtx__help__render-help_commands] )) || +_rtx__help__render-help_commands() { + local commands; commands=() + _describe -t commands 'rtx help render-help commands' commands "$@" +} +(( $+functions[_rtx__render-help_commands] )) || +_rtx__render-help_commands() { + local commands; commands=() + _describe -t commands 'rtx render-help commands' commands "$@" +} +(( $+functions[_rtx__help__settings__set_commands] )) || +_rtx__help__settings__set_commands() { + local commands; commands=() + _describe -t commands 'rtx help settings set commands' commands "$@" +} +(( $+functions[_rtx__settings__help__set_commands] )) || +_rtx__settings__help__set_commands() { + local commands; commands=() + _describe -t commands 'rtx settings help set commands' commands "$@" +} +(( $+functions[_rtx__settings__set_commands] )) || +_rtx__settings__set_commands() { + local commands; commands=() + _describe -t commands 'rtx settings set commands' commands "$@" +} +(( $+functions[_rtx__help__settings_commands] )) || +_rtx__help__settings_commands() { + local commands; commands=( +'get:Show a current setting' \ +'ls:Show current settings' \ +'set:Add/update a setting' \ +'unset:Clears a setting' \ + ) + _describe -t commands 'rtx help settings commands' commands "$@" +} +(( $+functions[_rtx__settings_commands] )) || +_rtx__settings_commands() { + local commands; commands=( +'get:Show a current setting' \ +'ls:Show current settings' \ +'list:Show current settings' \ +'set:Add/update a setting' \ +'unset:Clears a setting' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx settings commands' commands "$@" +} +(( $+functions[_rtx__help__plugins__uninstall_commands] )) || +_rtx__help__plugins__uninstall_commands() { + local commands; commands=() + _describe -t commands 'rtx help plugins uninstall commands' commands "$@" +} +(( $+functions[_rtx__help__uninstall_commands] )) || +_rtx__help__uninstall_commands() { + local commands; commands=() + _describe -t commands 'rtx help uninstall commands' commands "$@" +} +(( $+functions[_rtx__plugins__help__uninstall_commands] )) || +_rtx__plugins__help__uninstall_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins help uninstall commands' commands "$@" +} +(( $+functions[_rtx__plugins__uninstall_commands] )) || +_rtx__plugins__uninstall_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins uninstall commands' commands "$@" +} +(( $+functions[_rtx__uninstall_commands] )) || +_rtx__uninstall_commands() { + local commands; commands=() + _describe -t commands 'rtx uninstall commands' commands "$@" +} +(( $+functions[_rtx__help__settings__unset_commands] )) || +_rtx__help__settings__unset_commands() { + local commands; commands=() + _describe -t commands 'rtx help settings unset commands' commands "$@" +} +(( $+functions[_rtx__settings__help__unset_commands] )) || +_rtx__settings__help__unset_commands() { + local commands; commands=() + _describe -t commands 'rtx settings help unset commands' commands "$@" +} +(( $+functions[_rtx__settings__unset_commands] )) || +_rtx__settings__unset_commands() { + local commands; commands=() + _describe -t commands 'rtx settings unset commands' commands "$@" +} +(( $+functions[_rtx__help__plugins__update_commands] )) || +_rtx__help__plugins__update_commands() { + local commands; commands=() + _describe -t commands 'rtx help plugins update commands' commands "$@" +} +(( $+functions[_rtx__plugins__help__update_commands] )) || +_rtx__plugins__help__update_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins help update commands' commands "$@" +} +(( $+functions[_rtx__plugins__update_commands] )) || +_rtx__plugins__update_commands() { + local commands; commands=() + _describe -t commands 'rtx plugins update commands' commands "$@" +} +(( $+functions[_rtx__help__version_commands] )) || +_rtx__help__version_commands() { + local commands; commands=() + _describe -t commands 'rtx help version commands' commands "$@" +} +(( $+functions[_rtx__version_commands] )) || +_rtx__version_commands() { + local commands; commands=() + _describe -t commands 'rtx version commands' commands "$@" +} +(( $+functions[_rtx__help__where_commands] )) || +_rtx__help__where_commands() { + local commands; commands=() + _describe -t commands 'rtx help where commands' commands "$@" +} +(( $+functions[_rtx__where_commands] )) || +_rtx__where_commands() { + local commands; commands=() + _describe -t commands 'rtx where commands' commands "$@" +} + +_rtx "$@" + diff --git a/completions/rtx.bash b/completions/rtx.bash new file mode 100644 index 000000000..ec0bfb136 --- /dev/null +++ b/completions/rtx.bash @@ -0,0 +1,1935 @@ +_rtx() { + local i cur prev opts cmd + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="" + opts="" + + for i in ${COMP_WORDS[@]} + do + case "${cmd},${i}" in + ",$1") + cmd="rtx" + ;; + rtx,a) + cmd="rtx__alias" + ;; + rtx,activate) + cmd="rtx__activate" + ;; + rtx,alias) + cmd="rtx__alias" + ;; + rtx,asdf) + cmd="rtx__asdf" + ;; + rtx,complete) + cmd="rtx__complete" + ;; + rtx,current) + cmd="rtx__current" + ;; + rtx,deactivate) + cmd="rtx__deactivate" + ;; + rtx,direnv) + cmd="rtx__direnv" + ;; + rtx,doctor) + cmd="rtx__doctor" + ;; + rtx,e) + cmd="rtx__env" + ;; + rtx,env) + cmd="rtx__env" + ;; + rtx,exec) + cmd="rtx__exec" + ;; + rtx,g) + cmd="rtx__global" + ;; + rtx,global) + cmd="rtx__global" + ;; + rtx,help) + cmd="rtx__help" + ;; + rtx,hook-env) + cmd="rtx__hook__env" + ;; + rtx,i) + cmd="rtx__install" + ;; + rtx,install) + cmd="rtx__install" + ;; + rtx,l) + cmd="rtx__local" + ;; + rtx,latest) + cmd="rtx__latest" + ;; + rtx,list) + cmd="rtx__ls" + ;; + rtx,list-remote) + cmd="rtx__ls__remote" + ;; + rtx,local) + cmd="rtx__local" + ;; + rtx,ls) + cmd="rtx__ls" + ;; + rtx,ls-remote) + cmd="rtx__ls__remote" + ;; + rtx,p) + cmd="rtx__plugins" + ;; + rtx,plugins) + cmd="rtx__plugins" + ;; + rtx,render-help) + cmd="rtx__render__help" + ;; + rtx,settings) + cmd="rtx__settings" + ;; + rtx,uninstall) + cmd="rtx__uninstall" + ;; + rtx,version) + cmd="rtx__version" + ;; + rtx,where) + cmd="rtx__where" + ;; + rtx,x) + cmd="rtx__exec" + ;; + rtx__alias,help) + cmd="rtx__alias__help" + ;; + rtx__alias,list) + cmd="rtx__alias__ls" + ;; + rtx__alias,ls) + cmd="rtx__alias__ls" + ;; + rtx__alias__help,help) + cmd="rtx__alias__help__help" + ;; + rtx__alias__help,ls) + cmd="rtx__alias__help__ls" + ;; + rtx__direnv,activate) + cmd="rtx__direnv__activate" + ;; + rtx__direnv,envrc) + cmd="rtx__direnv__envrc" + ;; + rtx__direnv,exec) + cmd="rtx__direnv__exec" + ;; + rtx__direnv,help) + cmd="rtx__direnv__help" + ;; + rtx__direnv__help,activate) + cmd="rtx__direnv__help__activate" + ;; + rtx__direnv__help,envrc) + cmd="rtx__direnv__help__envrc" + ;; + rtx__direnv__help,exec) + cmd="rtx__direnv__help__exec" + ;; + rtx__direnv__help,help) + cmd="rtx__direnv__help__help" + ;; + rtx__help,activate) + cmd="rtx__help__activate" + ;; + rtx__help,alias) + cmd="rtx__help__alias" + ;; + rtx__help,asdf) + cmd="rtx__help__asdf" + ;; + rtx__help,complete) + cmd="rtx__help__complete" + ;; + rtx__help,current) + cmd="rtx__help__current" + ;; + rtx__help,deactivate) + cmd="rtx__help__deactivate" + ;; + rtx__help,direnv) + cmd="rtx__help__direnv" + ;; + rtx__help,doctor) + cmd="rtx__help__doctor" + ;; + rtx__help,env) + cmd="rtx__help__env" + ;; + rtx__help,exec) + cmd="rtx__help__exec" + ;; + rtx__help,global) + cmd="rtx__help__global" + ;; + rtx__help,help) + cmd="rtx__help__help" + ;; + rtx__help,hook-env) + cmd="rtx__help__hook__env" + ;; + rtx__help,install) + cmd="rtx__help__install" + ;; + rtx__help,latest) + cmd="rtx__help__latest" + ;; + rtx__help,local) + cmd="rtx__help__local" + ;; + rtx__help,ls) + cmd="rtx__help__ls" + ;; + rtx__help,ls-remote) + cmd="rtx__help__ls__remote" + ;; + rtx__help,plugins) + cmd="rtx__help__plugins" + ;; + rtx__help,render-help) + cmd="rtx__help__render__help" + ;; + rtx__help,settings) + cmd="rtx__help__settings" + ;; + rtx__help,uninstall) + cmd="rtx__help__uninstall" + ;; + rtx__help,version) + cmd="rtx__help__version" + ;; + rtx__help,where) + cmd="rtx__help__where" + ;; + rtx__help__alias,ls) + cmd="rtx__help__alias__ls" + ;; + rtx__help__direnv,activate) + cmd="rtx__help__direnv__activate" + ;; + rtx__help__direnv,envrc) + cmd="rtx__help__direnv__envrc" + ;; + rtx__help__direnv,exec) + cmd="rtx__help__direnv__exec" + ;; + rtx__help__plugins,install) + cmd="rtx__help__plugins__install" + ;; + rtx__help__plugins,ls) + cmd="rtx__help__plugins__ls" + ;; + rtx__help__plugins,ls-remote) + cmd="rtx__help__plugins__ls__remote" + ;; + rtx__help__plugins,uninstall) + cmd="rtx__help__plugins__uninstall" + ;; + rtx__help__plugins,update) + cmd="rtx__help__plugins__update" + ;; + rtx__help__settings,get) + cmd="rtx__help__settings__get" + ;; + rtx__help__settings,ls) + cmd="rtx__help__settings__ls" + ;; + rtx__help__settings,set) + cmd="rtx__help__settings__set" + ;; + rtx__help__settings,unset) + cmd="rtx__help__settings__unset" + ;; + rtx__plugins,a) + cmd="rtx__plugins__install" + ;; + rtx__plugins,help) + cmd="rtx__plugins__help" + ;; + rtx__plugins,i) + cmd="rtx__plugins__install" + ;; + rtx__plugins,install) + cmd="rtx__plugins__install" + ;; + rtx__plugins,list) + cmd="rtx__plugins__ls" + ;; + rtx__plugins,list-remote) + cmd="rtx__plugins__ls__remote" + ;; + rtx__plugins,ls) + cmd="rtx__plugins__ls" + ;; + rtx__plugins,ls-remote) + cmd="rtx__plugins__ls__remote" + ;; + rtx__plugins,uninstall) + cmd="rtx__plugins__uninstall" + ;; + rtx__plugins,update) + cmd="rtx__plugins__update" + ;; + rtx__plugins__help,help) + cmd="rtx__plugins__help__help" + ;; + rtx__plugins__help,install) + cmd="rtx__plugins__help__install" + ;; + rtx__plugins__help,ls) + cmd="rtx__plugins__help__ls" + ;; + rtx__plugins__help,ls-remote) + cmd="rtx__plugins__help__ls__remote" + ;; + rtx__plugins__help,uninstall) + cmd="rtx__plugins__help__uninstall" + ;; + rtx__plugins__help,update) + cmd="rtx__plugins__help__update" + ;; + rtx__settings,get) + cmd="rtx__settings__get" + ;; + rtx__settings,help) + cmd="rtx__settings__help" + ;; + rtx__settings,list) + cmd="rtx__settings__ls" + ;; + rtx__settings,ls) + cmd="rtx__settings__ls" + ;; + rtx__settings,set) + cmd="rtx__settings__set" + ;; + rtx__settings,unset) + cmd="rtx__settings__unset" + ;; + rtx__settings__help,get) + cmd="rtx__settings__help__get" + ;; + rtx__settings__help,help) + cmd="rtx__settings__help__help" + ;; + rtx__settings__help,ls) + cmd="rtx__settings__help__ls" + ;; + rtx__settings__help,set) + cmd="rtx__settings__help__set" + ;; + rtx__settings__help,unset) + cmd="rtx__settings__help__unset" + ;; + *) + ;; + esac + done + + case "${cmd}" in + rtx) + opts="-h -V --log-level --help --version activate alias asdf current deactivate direnv doctor complete env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__activate) + opts="-s -h --shell --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias) + opts="-p -h --plugin --log-level --help ls help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --plugin) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help) + opts="ls help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__ls) + opts="-p -h --plugin --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --plugin) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__asdf) + opts="-h --log-level --help [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__complete) + opts="-s -h --shell --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__current) + opts="-h --log-level --help [PLUGIN]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__deactivate) + opts="-s -h --shell --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv) + opts="-h --log-level --help envrc exec activate help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__activate) + opts="-h --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__envrc) + opts="-h --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__exec) + opts="-h --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help) + opts="envrc exec activate help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__activate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__envrc) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__exec) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__doctor) + opts="-h --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__env) + opts="-s -h --shell --log-level --help [RUNTIME]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__exec) + opts="-c -h --command --log-level --help [RUNTIME]... [COMMAND]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --command) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -c) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__global) + opts="-h --fuzzy --remove --log-level --help [RUNTIME]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help) + opts="activate alias asdf current deactivate direnv doctor complete env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__activate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias) + opts="ls" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__asdf) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__complete) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__current) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__deactivate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv) + opts="envrc exec activate" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv__activate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv__envrc) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv__exec) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__doctor) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__env) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__exec) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__global) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__hook__env) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__install) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__latest) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__local) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__ls__remote) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins) + opts="install ls ls-remote uninstall update" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__install) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__ls__remote) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__uninstall) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__update) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__render__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings) + opts="get ls set unset" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__uninstall) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__version) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__where) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__hook__env) + opts="-s -h --shell --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__install) + opts="-p -f -h --plugin --force --log-level --help [RUNTIME]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --plugin) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__latest) + opts="-h --log-level --help [ASDF_VERSION]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__local) + opts="-p -h --parent --fuzzy --remove --log-level --help [RUNTIME]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__ls) + opts="-p -c -h --plugin --current --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --plugin) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__ls__remote) + opts="-h --log-level --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins) + opts="-a -u -h --all --urls --log-level --help install ls ls-remote uninstall update help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help) + opts="install ls ls-remote uninstall update help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__install) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__ls__remote) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__uninstall) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__update) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__install) + opts="-f -h --force --log-level --help [GIT_URL]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__ls) + opts="-a -u -h --all --urls --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__ls__remote) + opts="-u -h --urls --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__uninstall) + opts="-h --log-level --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__update) + opts="-h --log-level --help [PLUGIN]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__render__help) + opts="-h --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings) + opts="-h --log-level --help get ls set unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__get) + opts="-h --log-level --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help) + opts="get ls set unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__ls) + opts="-h --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__set) + opts="-h --log-level --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__unset) + opts="-h --log-level --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__uninstall) + opts="-h --log-level --help ..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__version) + opts="-h --log-level --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__where) + opts="-h --log-level --help [ASDF_VERSION]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +complete -F _rtx -o bashdefault -o default rtx + diff --git a/completions/rtx.fish b/completions/rtx.fish new file mode 100644 index 000000000..4f13e405e --- /dev/null +++ b/completions/rtx.fish @@ -0,0 +1,210 @@ +complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' +complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Get the latest runtime version available for install' +complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'exports environment variables to activate rtx in a single shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'execute a command with runtime(s) set' +complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'install a runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'list installed runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'list runtime versions available for install +note that these versions are cached for commands like `rtx install nodejs@latest` +however _this_ command will always clear that cache and fetch the latest remote versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`.' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`.' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file +for direnv to consume.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file +for direnv to consume.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file +for direnv to consume.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file +for direnv to consume.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'the command string to execute' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'remove the plugin(s) from ~/.tool-versions' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0`' +complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' +complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'remove the plugin(s) from .tool-versions' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'save fuzzy match to .tool-versions e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions by default it would save the exact version, e.g.: `nodejs 20.0.0`' +complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List all available remote plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstalls even if plugin exists' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List all available remote plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Get the latest runtime version available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports environment variables to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install +note that these versions are cached for commands like `rtx install nodejs@latest` +however _this_ command will always clear that cache and fetch the latest remote versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls" -f -a "ls" -d 'List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`.' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file +for direnv to consume.' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file +for direnv to consume.' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "install" -d 'install a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "ls" -d 'List installed plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "ls-remote" -d 'List all available remote plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "uninstall" -d 'removes a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "update" -d 'updates a plugin to the latest version' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show a current setting' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'Show current settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "set" -d 'Add/update a setting' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "unset" -d 'Clears a setting' + diff --git a/justfile b/justfile index 170a6fc43..02b89282d 100644 --- a/justfile +++ b/justfile @@ -50,3 +50,8 @@ lint-fix: render-help: ./.bin/rtx render-help > README.md + +render-completions: + ./.bin/rtx complete -s bash > completions/rtx.bash + ./.bin/rtx complete -s zsh > completions/_rtx + ./.bin/rtx complete -s fish > completions/rtx.fish diff --git a/src/cli/complete.rs b/src/cli/complete.rs new file mode 100644 index 000000000..f5b40979c --- /dev/null +++ b/src/cli/complete.rs @@ -0,0 +1,48 @@ +use color_eyre::eyre::Result; +use std::io::Cursor; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +use crate::cli::Cli; +use clap_complete::generate; + +/// generate shell completions +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct Complete { + /// shell type + #[clap(long, short)] + shell: clap_complete::Shell, +} + +impl Command for Complete { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let mut c = Cursor::new(Vec::new()); + generate(self.shell, &mut Cli::command(), "rtx", &mut c); + rtxprintln!(out, "{}", String::from_utf8(c.into_inner()).unwrap()); + + Ok(()) + } +} + +const AFTER_LONG_HELP: &str = r#" +Examples: + $ rtx complete +"#; + +// #[cfg(test)] +// mod test { +// use std::fs; +// +// use insta::assert_snapshot; +// +// use crate::{assert_cli, dirs}; +// +// #[test] +// fn test_complete() { +// let stdout = assert_cli!("complete", "-s", "zsh"); +// assert_snapshot!(stdout); +// } +// } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b61c2c98c..b0250f790 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -12,6 +12,7 @@ mod alias; pub mod args; mod asdf; pub mod command; +mod complete; mod current; mod deactivate; mod direnv; @@ -46,6 +47,7 @@ pub enum Commands { Activate(activate::Activate), Alias(alias::Alias), Asdf(asdf::Asdf), + Complete(complete::Complete), Current(current::Current), Deactivate(deactivate::Deactivate), Direnv(direnv::Direnv), @@ -75,6 +77,7 @@ impl Commands { Self::Activate(cmd) => cmd.run(config, out), Self::Alias(cmd) => cmd.run(config, out), Self::Asdf(cmd) => cmd.run(config, out), + Self::Complete(cmd) => cmd.run(config, out), Self::Current(cmd) => cmd.run(config, out), Self::Deactivate(cmd) => cmd.run(config, out), Self::Direnv(cmd) => cmd.run(config, out), From 0e831a58179e0a010dd391e5ca1b90edec6ac835 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 14:17:30 -0600 Subject: [PATCH 0034/1891] [feat] this makes it so running `rtx local nodejs 20` does what the user expects. There are probably other places I should add this too (#31) --- src/cli/args/runtime.rs | 23 +++++++++++++++++++ src/cli/global.rs | 5 +++- src/cli/install.rs | 11 ++++++--- src/cli/local.rs | 9 ++++++-- .../rtx__cli__global__test__global-4.snap | 7 ++++++ src/main.rs | 3 +++ src/regex.rs | 8 +++++++ 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__global__test__global-4.snap create mode 100644 src/regex.rs diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index 2b0a0d906..d48e6ea86 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -2,6 +2,7 @@ use std::ffi::{OsStr, OsString}; use std::fmt::Display; use clap::{Arg, Command, Error}; +use regex::Regex; use crate::plugins::PluginName; @@ -19,6 +20,28 @@ impl RuntimeArg { version: version.into(), } } + + /// this handles the case where the user typed in: + /// rtx local nodejs 20.0.0 + /// instead of + /// rtx local nodejs 20.0.0 + /// + /// We can detect this, and we know what they meant, so make it work the way + /// they expected. + pub fn double_runtime_condition(runtimes: &[RuntimeArg]) -> Vec { + let mut runtimes = runtimes.to_vec(); + if runtimes.len() == 2 { + let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); + let a = runtimes[0].clone(); + let b = runtimes[1].clone(); + if a.version == "latest" && b.version == "latest" && re.is_match(&b.plugin) { + runtimes[1].version = b.plugin; + runtimes[1].plugin = a.plugin; + runtimes.remove(0); + } + } + runtimes + } } impl Display for RuntimeArg { diff --git a/src/cli/global.rs b/src/cli/global.rs index 4b7a51287..51c8d1595 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -46,7 +46,8 @@ impl Command for Global { } } if let Some(runtimes) = &self.runtime { - cf.add_runtimes(&config, runtimes, self.fuzzy)?; + let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); + cf.add_runtimes(&config, &runtimes, self.fuzzy)?; } if self.runtime.is_some() || self.remove.is_some() { @@ -91,6 +92,8 @@ mod test { assert_snapshot!(stdout); let stdout = assert_cli!("global", "--remove", "nodejs"); assert_snapshot!(stdout); + let stdout = assert_cli!("global", "tiny", "2"); + assert_snapshot!(stdout); if let Some(orig) = orig { fs::write(cf_path, orig).unwrap(); diff --git a/src/cli/install.rs b/src/cli/install.rs index ce1e2ca72..764b26270 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -55,14 +55,14 @@ impl Install { &self, config: Config, out: &mut Output, - runtime: &[RuntimeArg], + runtimes: &[RuntimeArg], ) -> Result<()> { let settings = Settings { missing_runtime_behavior: AutoInstall, ..config.settings.clone() }; - for r in runtime { + for r in RuntimeArg::double_runtime_condition(runtimes) { if r.version == "system" { continue; } @@ -160,10 +160,15 @@ mod test { use crate::assert_cli; #[test] - fn test_install() { + fn test_install_force() { assert_cli!("install", "-f", "shfmt"); } + #[test] + fn test_install_asdf_style() { + assert_cli!("install", "shfmt", "2"); + } + #[test] fn test_install_with_alias() { assert_cli!("install", "-f", "shfmt@my/alias"); diff --git a/src/cli/local.rs b/src/cli/local.rs index 49f659fbb..dce2621c3 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -62,8 +62,10 @@ impl Command for Local { cf.remove_plugin(plugin); } } + if let Some(runtimes) = &self.runtime { - cf.add_runtimes(&config, runtimes, self.fuzzy)?; + let runtimes = RuntimeArg::double_runtime_condition(runtimes); + cf.add_runtimes(&config, &runtimes, self.fuzzy)?; } if self.runtime.is_some() || self.remove.is_some() { @@ -101,7 +103,6 @@ mod test { use pretty_assertions::assert_str_eq; use crate::cli::test::grep; - use crate::{assert_cli, dirs}; #[test] @@ -122,6 +123,10 @@ mod test { grep(stdout, "nodejs"), " nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)" ); + let stdout = assert_cli!("local", "tiny@1"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); + let stdout = assert_cli!("local", "tiny", "2"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); fs::write(cf_path, orig).unwrap(); } diff --git a/src/cli/snapshots/rtx__cli__global__test__global-4.snap b/src/cli/snapshots/rtx__cli__global__test__global-4.snap new file mode 100644 index 000000000..18f952f79 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__global__test__global-4.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/global.rs +expression: stdout +--- +shfmt 2 +tiny 2.1.0 + diff --git a/src/main.rs b/src/main.rs index 17beb9e7b..0c72312d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,9 @@ use crate::output::Output; #[macro_use] mod output; +#[macro_use] +mod regex; + pub mod build_time; mod cli; mod cmd; diff --git a/src/regex.rs b/src/regex.rs new file mode 100644 index 000000000..dcd53926b --- /dev/null +++ b/src/regex.rs @@ -0,0 +1,8 @@ +pub use regex; + +macro_rules! regex { + ($re:literal $(,)?) => {{ + static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); + RE.get_or_init(|| regex::Regex::new($re).unwrap()) + }}; +} From 2636f5461cbc21ccc5f94a70381368f7eb9ee5e6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 14:17:47 -0600 Subject: [PATCH 0035/1891] [feat] made current better and not just an alias for `ls` (#32) --- README.md | 33 ++++++++++++++++++++ src/cli/current.rs | 75 ++++++++++++++++++++++++++++------------------ 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 45493e53b..3f204e558 100644 --- a/README.md +++ b/README.md @@ -481,6 +481,39 @@ Options: Examples: $ rtx complete +``` +### `rtx current` + +``` +Shows currently active, and installed runtime versions + +This is similar to `rtx list --current`, but this +only shows the runtime and/or version so it's +designed to fit into scripts more easily. + +Usage: current [PLUGIN] + +Arguments: + [PLUGIN] + plugin to show versions of + + e.g.: ruby, nodejs + +Options: + -h, --help + Print help (see a summary with '-h') + + +Examples: + + $ rtx current + shfmt@3.6.0 + shellcheck@0.9.0 + nodejs@18.13.0 + + $ rtx current nodejs + 18.13.0 + ``` ### `rtx deactivate` diff --git a/src/cli/current.rs b/src/cli/current.rs index 6e1ac8a20..79fb3263d 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,74 +1,91 @@ use color_eyre::eyre::Result; use crate::cli::command::Command; -use crate::cli::Cli; use crate::config::Config; use crate::output::Output; -/// Get the latest runtime version available for install +/// Shows currently active, and installed runtime versions /// -/// this exists for compatibility with asdf -/// it just calls `rtx list --current` under the hood +/// This is similar to `rtx list --current`, but this +/// only shows the runtime and/or version so it's +/// designed to fit into scripts more easily. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, hide = true)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Current { - /// plugin to filter by + /// plugin to show versions of /// /// e.g.: ruby, nodejs #[clap()] - plugin: Option>, + plugin: Option, } impl Command for Current { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let mut args = vec![ - String::from("rtx"), - String::from("list"), - String::from("--current"), - ]; - if let Some(plugins) = self.plugin { - for p in plugins { - args.push("-p".to_string()); - args.push(p.to_string()); + let plugin = match self.plugin { + Some(plugin_name) => { + let plugin = config.ts.find_plugin(&plugin_name); + if plugin.is_none() { + warn!("Plugin {} is not installed", plugin_name); + return Ok(()); + } + Some(plugin.unwrap()) } - } + None => None, + }; - Cli::new().run(config, &args, out) + for rtv in config.ts.list_current_versions() { + if !rtv.is_installed() { + let source = config.ts.get_source_for_plugin(&rtv.plugin.name).unwrap(); + warn!( + "{}@{} is specified in {}, but not installed", + rtv.plugin.name, source, rtv.version + ); + } + if let Some(plugin) = &plugin { + if plugin != &rtv.plugin { + continue; + } + rtxprintln!(out, "{}", rtv.version); + } else { + rtxprintln!(out, "{}@{}", rtv.plugin.name, rtv.version); + } + } + Ok(()) } } const AFTER_LONG_HELP: &str = r#" Examples: + $ rtx current - -> shfmt 3.6.0 (set by /Users/jdx/src/rtx/.tool-versions) - shellcheck 0.9.0 (missing) (set by /Users/jdx/tool-versions) - -> nodejs 18.13.0 (set by /Users/jdx/.tool-versions) + shfmt@3.6.0 + shellcheck@0.9.0 + nodejs@18.13.0 $ rtx current nodejs - -> nodejs 18.13.0 (set by /Users/jdx/.tool-versions) + 18.13.0 "#; #[cfg(test)] mod test { - use regex::Regex; + use insta::assert_snapshot; use crate::assert_cli; + use crate::cli::test::grep; #[test] fn test_current() { - assert_cli!("plugin", "add", "shellcheck"); assert_cli!("install"); let stdout = assert_cli!("current"); - let re = Regex::new(r"-> shellcheck\s+0\.9\.0\s+").unwrap(); - assert!(re.is_match(&stdout)); + assert_snapshot!(grep(stdout, "shfmt"), @"shfmt@3.5.2"); } #[test] fn test_current_with_runtimes() { - assert_cli!("plugin", "add", "shfmt"); assert_cli!("install"); let stdout = assert_cli!("current", "shfmt"); - let re = Regex::new(r"-> shfmt\s+3\.5\.2\s+").unwrap(); - assert!(re.is_match(&stdout)); + assert_snapshot!(stdout, @r###" + 3.5.2 + "###); } } From 6e2377e431c6e2c6eb48d93fb7fdc2118ac5232a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 14:26:54 -0600 Subject: [PATCH 0036/1891] [bug] fixed `rtx settings set` with no config file (#34) --- src/config/config_file/rtxrc.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index eff67a502..67f57fec4 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -222,6 +222,11 @@ impl RTXFile { fn get_or_create_edit(&mut self) -> &mut toml_edit::Document { if self.edit.is_none() { + if !self.path.exists() { + let dir = self.path.parent().unwrap(); + fs::create_dir_all(dir).expect("could not create directory"); + fs::write(&self.path, "").expect("could not create new config.toml file"); + } let body = fs::read_to_string(&self.path) .suggestion("ensure file exists and can be read") .unwrap(); @@ -603,4 +608,13 @@ nodejs=[true] "3.10" = "3.10.0" "###); } + + #[test] + fn test_edit_when_file_does_not_exist() { + let mut cf = RTXFile::from_str("".to_string()).unwrap(); + let dir = tempfile::tempdir().unwrap(); + cf.path = dir.path().join("subdir").join("does-not-exist.toml"); + cf.set_alias("nodejs", "18", "18.0.1"); + cf.save().unwrap(); + } } From a23fa4d3d4fd8dd8545b2964df51c93cb1bb8635 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 14:29:58 -0600 Subject: [PATCH 0037/1891] chore: Release rtx-cli version 1.2.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e73fc8fe5..0477dd906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.1" +version = "1.2.2" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 2fb41e718..fbf72fc14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.1" +version = "1.2.2" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 3f204e558..d08195c06 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.2.1 +rtx 1.2.2 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 573c2ab18..9b1818e70 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.1 +Version: 1.2.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 7c3f422ee5262d4af11693ffa6bc2d1421c9d617 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 14:34:11 -0600 Subject: [PATCH 0038/1891] [bug] fixed 2 styling issues with `rtx current` Before: ``` [WARN] shfmt@~/.tool-versions is specified in 2, but not installed shfmt@2 [WARN] python@~/.tool-versions is specified in 3.10, but not installed python@3.10 [WARN] nodejs@~/.tool-versions is specified in 18.13.0, but not installed nodejs@18.13.0 [WARN] java@~/.tool-versions is specified in openjdk-19.0.2, but not installed java@openjdk-19.0.2 [WARN] golang@~/.tool-versions is specified in 1.19.5, but not installed golang@1.19.5 [WARN] ruby@~/.tool-versions is specified in 3, but not installed ruby@3 ``` After: ``` [WARN] shfmt@2 is specified in ~/.tool-versions, but not installed [WARN] python@3.10 is specified in ~/.tool-versions, but not installed nodejs@18.13.0 [WARN] java@openjdk-19.0.2 is specified in ~/.tool-versions, but not installed [WARN] golang@1.19.5 is specified in ~/.tool-versions, but not installed [WARN] ruby@3 is specified in ~/.tool-versions, but not installed. ``` --- src/cli/current.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/current.rs b/src/cli/current.rs index 79fb3263d..1037e2c9c 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -38,8 +38,9 @@ impl Command for Current { let source = config.ts.get_source_for_plugin(&rtv.plugin.name).unwrap(); warn!( "{}@{} is specified in {}, but not installed", - rtv.plugin.name, source, rtv.version + rtv.plugin.name, rtv.version, source ); + continue; } if let Some(plugin) = &plugin { if plugin != &rtv.plugin { From 982aa39c67319a27e7c921554f9b4f6592171d10 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 14:59:00 -0600 Subject: [PATCH 0039/1891] [test] do not hardcode version since it changes on release (#36) --- src/cli/version.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index 94baa62ae..5be93e0cd 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -28,15 +28,13 @@ impl Command for Version { #[cfg(test)] mod tests { - use insta::assert_snapshot; - + use super::*; use crate::assert_cli; + use pretty_assertions::assert_str_eq; #[test] fn test_version() { let stdout = assert_cli!("version"); - assert_snapshot!(stdout, @r###" - 1.2.1 (built on 2023-01-28) - "###); + assert_str_eq!(stdout, VERSION.to_string() + "\n"); } } From ae60a58d0c10bdd8fa579a74a54045dce6f020ef Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 15:12:16 -0600 Subject: [PATCH 0040/1891] [bug] add watch on ROOT directory (#37) This prevents issues around not having a .tool-version file with any active plugins, then running `rtx install`. There are cases where rtx won't update when it should. Writing to this directory should be accessible globally on the machine. --- src/cli/hook_env.rs | 3 +++ src/runtimes/mod.rs | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 235cb8ca3..3312b64df 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -49,6 +49,9 @@ impl Command for HookEnv { fn get_watches(config: &Config) -> Result { let mut watches = HookEnvWatches::new(); + if dirs::ROOT.exists() { + watches.insert(dirs::ROOT.clone(), dirs::ROOT.metadata()?.modified()?); + } for cf in &config.config_files { watches.insert(cf.clone(), cf.metadata()?.modified()?); } diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index 928ba6e60..a2b5419b7 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -104,8 +104,10 @@ impl RuntimeVersion { conf.write(&self.runtime_conf_path)?; // attempt to touch all the .tool-version files to trigger updates in hook-env - for path in &config.config_files { - let err = file::touch_dir(path); + let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; + touch_dirs.extend(config.config_files.iter().cloned()); + for path in touch_dirs { + let err = file::touch_dir(&path); if let Err(err) = err { debug!("error touching config file: {:?} {:?}", path, err); } From d6adc1ac34297c5f1fdeb9c796ae6f469de89606 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 15:12:51 -0600 Subject: [PATCH 0041/1891] chore: Release rtx-cli version 1.2.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0477dd906..259173a06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.2" +version = "1.2.3" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index fbf72fc14..d94bde5f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.2" +version = "1.2.3" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index d08195c06..6a00527ff 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.2.2 +rtx 1.2.3 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9b1818e70..555ad16ef 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.2 +Version: 1.2.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From b8aaf5be7e6eb86db84da9ce91c6d7a3ad84d461 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 15:36:34 -0600 Subject: [PATCH 0042/1891] [release] attempt to release raw binaries, also fixed new urls for rtx.jdxcode.com --- scripts/release.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index 55ace9ca5..525a39705 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -33,6 +33,9 @@ platforms=( for platform in "${platforms[@]}"; do cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" + tar -xvzf "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" + cp -v rtx/bin/rtx "$RELEASE_DIR/rtx-latest-$platform" + cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" done pushd "$RELEASE_DIR" @@ -45,13 +48,15 @@ sha256sum ./* >SHASUMS256.txt gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc popd -./rtx/scripts/render-install.sh >rtx.jdxcode.com/install.sh +./rtx/scripts/render-install.sh >rtx.jdxcode.com/static/install.sh -rm -rf rtx.jdxcode.com/rpm -mv artifacts/rpm rtx.jdxcode.com/rpm +rm -rf rtx.jdxcode.com/static/rpm +mv artifacts/rpm rtx.jdxcode.com/static/rpm -rm -rf rtx.jdxcode.com/deb -mv artifacts/deb rtx.jdxcode.com/deb +rm -rf rtx.jdxcode.com/static/deb +mv artifacts/deb rtx.jdxcode.com/static/deb + +cp -vrf "$RELEASE_DIR/*" rtx.jdxcode.com/static ./rtx/scripts/release-npm.sh From 7d7d85a568f507f96eaae403d1c142eb6ec2cb99 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 15:36:47 -0600 Subject: [PATCH 0043/1891] chore: Release rtx-cli version 1.2.4 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 259173a06..10b031d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.3" +version = "1.2.4" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index d94bde5f5..feb816591 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.3" +version = "1.2.4" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 6a00527ff..a89d2ae98 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.2.3 +rtx 1.2.4 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 555ad16ef..e0f6e7da4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.3 +Version: 1.2.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 5a107ab140b580c8793e9a201066d214771db14e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 15:45:55 -0600 Subject: [PATCH 0044/1891] [release] tiny bug in the release script --- scripts/release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.sh b/scripts/release.sh index 525a39705..ffbac95a7 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -56,7 +56,7 @@ mv artifacts/rpm rtx.jdxcode.com/static/rpm rm -rf rtx.jdxcode.com/static/deb mv artifacts/deb rtx.jdxcode.com/static/deb -cp -vrf "$RELEASE_DIR/*" rtx.jdxcode.com/static +cp -vrf "$RELEASE_DIR/"* rtx.jdxcode.com/static ./rtx/scripts/release-npm.sh From 7dc8b3d3db0f3d794cbb6827db47b34dffca0862 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 16:42:41 -0600 Subject: [PATCH 0045/1891] chore: Release rtx-cli version 1.2.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10b031d09..117acab56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.4" +version = "1.2.5" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index feb816591..aca7d9825 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.4" +version = "1.2.5" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a89d2ae98..79f88ea90 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.2.4 +rtx 1.2.5 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e0f6e7da4..ecfa997ba 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.4 +Version: 1.2.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From bd42f476cdea39f4bba455d42fbbfe2c3b22e369 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 17:04:41 -0600 Subject: [PATCH 0046/1891] doc correction --- README.md | 5 ++--- src/cli/render_help.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 79f88ea90..e0bc2282b 100644 --- a/README.md +++ b/README.md @@ -1204,9 +1204,8 @@ v18.13.0 I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). `rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add nodejs` or -`rtx plugin install nodejs`. asdf also just has too many commands. It's hard to remember what the -difference is between `asdf list` and `asdf current` is. `rtx` has a single command `rtx list` which -can be passed a flag `rtx list --current` to show the current versions. +`rtx plugin install nodejs`. If I can guess what you meant, then I'll try to get rtx to respond +in the right way. That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there and I've really been impressed with the plugin system. Most of the design decisions the authors made diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 58e61a46e..7b1c2cd65 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -526,9 +526,8 @@ v18.13.0 I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). `rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add nodejs` or -`rtx plugin install nodejs`. asdf also just has too many commands. It's hard to remember what the -difference is between `asdf list` and `asdf current` is. `rtx` has a single command `rtx list` which -can be passed a flag `rtx list --current` to show the current versions. +`rtx plugin install nodejs`. If I can guess what you meant, then I'll try to get rtx to respond +in the right way. That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there and I've really been impressed with the plugin system. Most of the design decisions the authors made From 6e87dd21736deda455edcc72a109c043bdada60f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 17:33:13 -0600 Subject: [PATCH 0047/1891] Check for git with `git --version` before attempting to clone Also disabled release opmitizations to fix stack traces --- Cargo.toml | 12 ++++++------ src/git.rs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aca7d9825..df7104704 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,12 +69,12 @@ tempfile = "3.3.0" env_logger = "0.10.0" [profile.release] -opt-level = "z" # optimize for size -lto = true -debug = false -debug-assertions = false -panic = "abort" -strip = "symbols" +#opt-level = "z" # optimize for size +#lto = true +#debug = false +#debug-assertions = false +#panic = "abort" +#strip = "symbols" [package.metadata.release] allow-branch = ["main"] diff --git a/src/git.rs b/src/git.rs index b8b8a65f0..d58ca536f 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,3 +1,4 @@ +use std::fs::create_dir_all; use std::path::PathBuf; use color_eyre::eyre::Result; @@ -68,6 +69,16 @@ impl Git { pub fn clone(&self, url: &str) -> Result<()> { debug!("cloning {} to {}", url, self.dir.display()); + if let Some(parent) = self.dir.parent() { + create_dir_all(parent)?; + } + match get_git_version() { + Ok(version) => trace!("git version: {}", version), + Err(err) => warn!( + "failed to get git version: {}\n Git is required to use rtx.", + err + ), + } cmd!("git", "clone", "-q", "--depth", "1", url, &self.dir).run()?; Ok(()) } @@ -105,6 +116,11 @@ impl Git { } } +fn get_git_version() -> Result { + let version = cmd!("git", "--version").read()?; + Ok(version.trim().into()) +} + #[cfg(test)] mod tests { use tempfile::tempdir; From 0e04fbd5e046d3f3d27068e14a0c1dc777e314db Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 19:57:20 -0600 Subject: [PATCH 0048/1891] chore: Release rtx-cli version 1.2.6 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 117acab56..15a0ff9c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.5" +version = "1.2.6" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index df7104704..4d00ab948 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.5" +version = "1.2.6" edition = "2021" description = "Polyglot runtime manager" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e0bc2282b..0ac74d869 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ brew install jdxcode/tap/rtx $ rtx --version -rtx 1.2.5 +rtx 1.2.6 ``` Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ecfa997ba..a23c30759 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.5 +Version: 1.2.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From c737eeca0eaf5b60821faad49bc0eb761d3fb8c3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 28 Jan 2023 21:41:25 -0600 Subject: [PATCH 0049/1891] docs --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4d00ab948..88ebacbc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rtx-cli" version = "1.2.6" edition = "2021" -description = "Polyglot runtime manager" +description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] homepage = "https://github.com/jdxcode/rtx" documentation = "https://github.com/jdxcode/rtx" diff --git a/README.md b/README.md index 0ac74d869..f8a16d149 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Codecov](https://codecov.io/gh/jdxcode/rtx/branch/main/graph/badge.svg?token=XYH3Q0BOO0)](https://codecov.io/gh/jdxcode/rtx) [![Discord](https://img.shields.io/discord/1066429325269794907)](https://discord.gg/mABnUDvP57) -_Polyglot runtime manager_ +_Polyglot runtime manager (asdf rust clone)_ ## Quickstart (macOS) From 2221309bb3f978013950f10ad3504462e1232ff6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 29 Jan 2023 18:10:41 -0600 Subject: [PATCH 0050/1891] use standalone install method as quick start (#43) --- Cargo.toml | 1 + README.md | 45 +++++++++++++++++++++++++++++++++--------- src/cli/render_help.rs | 45 +++++++++++++++++++++++++++++++++--------- 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 88ebacbc8..1753358a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,7 @@ allow-branch = ["main"] #sign-commit = true pre-release-replacements = [ { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, + { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, ] diff --git a/README.md b/README.md index f8a16d149..0c5f0e696 100644 --- a/README.md +++ b/README.md @@ -8,27 +8,27 @@ _Polyglot runtime manager (asdf rust clone)_ -## Quickstart (macOS) +## Quickstart Install rtx (other methods [here](#installation)): ```sh-session -$ brew install jdxcode/tap/rtx +$ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version rtx 1.2.6 ``` -Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): +Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. +(choose one, and open a new shell session for the changes to take effect): ```sh-session -$ echo 'eval "$(rtx activate -s bash)"' >> ~/.bashrc -$ echo 'eval "$(rtx activate -s zsh)"' >> ~/.zshrc -$ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish +$ echo 'eval "$(~/bin/rtx activate -s bash)"' >> ~/.bashrc +$ echo 'eval "$(~/bin/rtx activate -s zsh)"' >> ~/.zshrc +$ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` > **Warning** -> -> If you use direnv, [see below](#direnv) for direnv-compatible setup. +> > If you use direnv, [see below](#direnv) for direnv-compatible setup. Install a runtime and set it as the default: @@ -106,6 +106,33 @@ file, rtx will automatically add itself to `PATH`. $ curl https://rtx.jdxcode.com/install.sh | sh ``` +> **Note** +> +> There isn't currently an autoupdater in rtx. So if you use this method you'll need to remember +> to fetch a new version manually for bug/feature fixes. I'm not sure if I'll ever add an autoupdater +> because it might be disruptive to autoupdate to a major version that has breaking changes. + +or if you're allergic to `| sh`: + +```sh-session +$ curl https://rtx.jdxcode.com/rtx-latest-macos-arm64 > /usr/local/bin/rtx +``` + +It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` +or whatever. + +Supported architectures: + +- `x64` +- `arm64` + +Supported platforms: + +- `macos` +- `linux` + +If you need something else, compile it with [cargo](#cargo). + ### Homebrew ```sh-session @@ -147,7 +174,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/rtx-latest-macos-arm64.tar.xz | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.2.6/rtx-v1.2.6-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 7b1c2cd65..b92097887 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -26,27 +26,27 @@ impl Command for RenderHelp { _{about}_ -## Quickstart (macOS) +## Quickstart Install rtx (other methods [here](#installation)): ```sh-session -$ brew install jdxcode/tap/rtx +$ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version rtx {version} ``` -Hook rtx into to your shell (choose one, and open a new shell session for the changes to take effect): +Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. +(choose one, and open a new shell session for the changes to take effect): ```sh-session -$ echo 'eval "$(rtx activate -s bash)"' >> ~/.bashrc -$ echo 'eval "$(rtx activate -s zsh)"' >> ~/.zshrc -$ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish +$ echo 'eval "$(~/bin/rtx activate -s bash)"' >> ~/.bashrc +$ echo 'eval "$(~/bin/rtx activate -s zsh)"' >> ~/.zshrc +$ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` > **Warning** -> -> If you use direnv, [see below](#direnv) for direnv-compatible setup. +> > If you use direnv, [see below](#direnv) for direnv-compatible setup. Install a runtime and set it as the default: @@ -124,6 +124,33 @@ file, rtx will automatically add itself to `PATH`. $ curl https://rtx.jdxcode.com/install.sh | sh ``` +> **Note** +> +> There isn't currently an autoupdater in rtx. So if you use this method you'll need to remember +> to fetch a new version manually for bug/feature fixes. I'm not sure if I'll ever add an autoupdater +> because it might be disruptive to autoupdate to a major version that has breaking changes. + +or if you're allergic to `| sh`: + +```sh-session +$ curl https://rtx.jdxcode.com/rtx-latest-macos-arm64 > /usr/local/bin/rtx +``` + +It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` +or whatever. + +Supported architectures: + +- `x64` +- `arm64` + +Supported platforms: + +- `macos` +- `linux` + +If you need something else, compile it with [cargo](#cargo). + ### Homebrew ```sh-session @@ -165,7 +192,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/rtx-latest-macos-arm64.tar.xz | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.2.6/rtx-v1.2.6-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 63f93cedda4ac189e2beeaf65c1bac107b77c42c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 29 Jan 2023 22:01:30 -0600 Subject: [PATCH 0051/1891] Bump toml from 0.6.0 to 0.7.0 (#45) Bumps [toml](https://github.com/toml-rs/toml) from 0.6.0 to 0.7.0. - [Release notes](https://github.com/toml-rs/toml/releases) - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.6.0...toml-v0.7.0) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 29 +++++++++++++++++++++++------ Cargo.toml | 2 +- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15a0ff9c4..353f8a23b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1045,7 +1045,7 @@ dependencies = [ "tempfile", "thiserror", "toml", - "toml_edit", + "toml_edit 0.18.1", "url", "versions", ] @@ -1303,14 +1303,14 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "toml" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb9d890e4dc9298b70f740f615f2e05b9db37dce531f6b24fb77ac993f9f217" +checksum = "2f560bc7fb3eb31f5eee1340c68a2160cad39605b7b9c9ec32045ddbdee13b85" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.0", + "toml_edit 0.19.0", ] [[package]] @@ -1318,6 +1318,12 @@ name = "toml_datetime" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" + +[[package]] +name = "toml_datetime" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886f31a9b85b6182cabd4d8b07df3b451afcc216563748201490940d2a28ed36" dependencies = [ "serde", ] @@ -1327,12 +1333,23 @@ name = "toml_edit" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" +dependencies = [ + "indexmap", + "nom8", + "toml_datetime 0.5.1", +] + +[[package]] +name = "toml_edit" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d8716cdc5d20ec88a18a839edaf545edc71efa4a5ff700ef4a102c26cd8fa" dependencies = [ "indexmap", "nom8", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1753358a9..165c97028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ shell-escape = "0.1.5" simplelog = "0.12.0" thiserror = "1.0.38" ctor = "0.1.26" -toml = "0.6.0" +toml = "0.7.0" toml_edit = "0.18.0" url = "2.3.1" versions = "4.1.0" From 6c1b93386c494f244e8d2a814b8fddd7591aeb74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 29 Jan 2023 22:01:42 -0600 Subject: [PATCH 0052/1891] Bump indoc from 1.0.8 to 2.0.0 (#46) Bumps [indoc](https://github.com/dtolnay/indoc) from 1.0.8 to 2.0.0. - [Release notes](https://github.com/dtolnay/indoc/releases) - [Commits](https://github.com/dtolnay/indoc/compare/1.0.8...2.0.0) --- updated-dependencies: - dependency-name: indoc dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 353f8a23b..451dbccdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,9 +588,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.8" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780" +checksum = "6fe2b9d82064e8a0226fddb3547f37f28eaa46d0fc210e275d835f08cf3b76a7" [[package]] name = "insta" diff --git a/Cargo.toml b/Cargo.toml index 165c97028..9df9f886c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ duct = "0.13.6" filetime = "0.2.19" flate2 = "1.0.25" indexmap = "1.9.2" -indoc = "1.0.8" +indoc = "2.0.0" itertools = "0.10.5" lazy_static = "1.4.0" log = "0.4.17" From 454b0aaf3ce569e640309800bc3e6650a58e6773 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jan 2023 00:48:54 -0600 Subject: [PATCH 0053/1891] Bump toml_edit from 0.18.1 to 0.19.0 (#44) --- Cargo.lock | 25 ++++--------------------- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 451dbccdf..95ef2012a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1045,7 +1045,7 @@ dependencies = [ "tempfile", "thiserror", "toml", - "toml_edit 0.18.1", + "toml_edit", "url", "versions", ] @@ -1309,16 +1309,10 @@ checksum = "2f560bc7fb3eb31f5eee1340c68a2160cad39605b7b9c9ec32045ddbdee13b85" dependencies = [ "serde", "serde_spanned", - "toml_datetime 0.6.0", - "toml_edit 0.19.0", + "toml_datetime", + "toml_edit", ] -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - [[package]] name = "toml_datetime" version = "0.6.0" @@ -1328,17 +1322,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap", - "nom8", - "toml_datetime 0.5.1", -] - [[package]] name = "toml_edit" version = "0.19.0" @@ -1349,7 +1332,7 @@ dependencies = [ "nom8", "serde", "serde_spanned", - "toml_datetime 0.6.0", + "toml_datetime", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9df9f886c..3574f6d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ simplelog = "0.12.0" thiserror = "1.0.38" ctor = "0.1.26" toml = "0.7.0" -toml_edit = "0.18.0" +toml_edit = "0.19.0" url = "2.3.1" versions = "4.1.0" build-time = "0.1.2" From 68c847bda4cd3882ab0ac77e222304e3bbd75258 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 13:54:06 -0600 Subject: [PATCH 0054/1891] [chore] fix cargo-binsttall config (#54) unfortunately I don't have a way to verify this works without publishing a release. So we'll see if this actually works. --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3574f6d8c..c76984114 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,9 +86,8 @@ pre-release-replacements = [ { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, ] -[package.metadata.binstall.overrides] +[package.metadata.binstall] bin-dir = "rtx/bin/rtx" - [package.metadata.binstall.overrides.aarch64-apple-darwin] pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-macos-arm64{ archive-suffix }" [package.metadata.binstall.overrides.x86_64-apple-darwin] From 03606d8f232a4571e3c0a48672496ee5c42dc2e7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 17:37:05 -0600 Subject: [PATCH 0055/1891] [chore] fix up internal `.bin/rtx` script to work in any directory --- .bin/rtx | 7 +++++-- README.md | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index 97fa6c59e..aff628859 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -1,6 +1,9 @@ -#!/bin/sh +#!/bin/bash # add this directory to `$PATH` to automatically build/run chim # when chims are called in shebangs -cargo run -- "$@" +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +pushd "$SCRIPT_DIR/.." || exit 1 +cargo build +popd && "$SCRIPT_DIR/../target/debug/rtx" "$@" diff --git a/README.md b/README.md index 0c5f0e696..659f1ccc8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +~/src/rtx ~/src/rtx +~/src/rtx # [rtx](https://github.com/jdxcode/rtx) [![Crates.io](https://img.shields.io/crates/v/rtx-cli.svg)](https://crates.io/crates/rtx-cli) @@ -435,6 +437,7 @@ This is unlikely to ever happen since this leverages the vast ecosystem of asdf At some point it may be worth exploring an alternate plugin format that would be Windows compatible. ## Commands + ### `rtx activate` ``` @@ -613,7 +616,7 @@ Examples: ### `rtx env` ``` -exports environment variables to activate rtx in a single shell session +exports env vars to activate rtx in a single shell session It's not necessary to use this if you have `rtx activate` in your shell rc file. Use this if you don't want to permanently install rtx. @@ -863,6 +866,7 @@ Examples: ``` list runtime versions available for install + note that these versions are cached for commands like `rtx install nodejs@latest` however _this_ command will always clear that cache and fetch the latest remote versions From dcbfd46a0baab5770540bfc838a519838927746d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 17:52:55 -0600 Subject: [PATCH 0056/1891] [chore] fix up internal `.bin/rtx` script to work in any directory --- .bin/rtx | 4 ++-- README.md | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index aff628859..3cd66eda6 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -4,6 +4,6 @@ # when chims are called in shebangs SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -pushd "$SCRIPT_DIR/.." || exit 1 +pushd "$SCRIPT_DIR/.." >/dev/null || exit 1 cargo build -popd && "$SCRIPT_DIR/../target/debug/rtx" "$@" +popd >/dev/null && "$SCRIPT_DIR/../target/debug/rtx" "$@" diff --git a/README.md b/README.md index 659f1ccc8..01f621083 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -~/src/rtx ~/src/rtx -~/src/rtx # [rtx](https://github.com/jdxcode/rtx) [![Crates.io](https://img.shields.io/crates/v/rtx-cli.svg)](https://crates.io/crates/rtx-cli) From 51bc243a2fd6a70590db0f2a93e0246b97b252e6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 17:53:14 -0600 Subject: [PATCH 0057/1891] [docs] minor tweaks to help output --- src/cli/env.rs | 2 +- src/cli/ls_remote.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/env.rs b/src/cli/env.rs index 80eb57b27..fb07c09e6 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -6,7 +6,7 @@ use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -/// exports environment variables to activate rtx in a single shell session +/// exports env vars to activate rtx in a single shell session /// /// It's not necessary to use this if you have `rtx activate` in your shell rc file. /// Use this if you don't want to permanently install rtx. diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 29b503fb1..279d10a0c 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -6,6 +6,7 @@ use crate::errors::Error::PluginNotInstalled; use crate::output::Output; /// list runtime versions available for install +/// /// note that these versions are cached for commands like `rtx install nodejs@latest` /// however _this_ command will always clear that cache and fetch the latest remote versions #[derive(Debug, clap::Args)] From 916af0a185beb5e598750e95a065cb4541944ad1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 18:31:42 -0600 Subject: [PATCH 0058/1891] [chore] added debug output for early-exit to diagnose why GOROOT is not being set sometimes --- .bin/rtx | 1 + src/env.rs | 9 +++++++-- src/hook_env.rs | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index 3cd66eda6..93328eb50 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -1,4 +1,5 @@ #!/bin/bash +set -e # add this directory to `$PATH` to automatically build/run chim # when chims are called in shebangs diff --git a/src/env.rs b/src/env.rs index 29bf6f73b..7e8495dca 100644 --- a/src/env.rs +++ b/src/env.rs @@ -61,9 +61,11 @@ lazy_static! { "warn" => log::LevelFilter::Warn, "error" => log::LevelFilter::Error, _ => { - if var_is_true("RTX_DEBUG") { + if *RTX_TRACE { + log::LevelFilter::Trace + } else if *RTX_DEBUG { log::LevelFilter::Debug - } else if var_is_true("RTX_QUIET") { + } else if *RTX_QUIET { log::LevelFilter::Error } else { log::LevelFilter::Info @@ -78,6 +80,9 @@ lazy_static! { }; pub static ref __RTX_DIR: Option = var_os("__RTX_DIR").map(PathBuf::from); pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); + pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); + pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); + pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String = if cfg!(test) { diff --git a/src/hook_env.rs b/src/hook_env.rs index 0a771dbc8..ef778940c 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -24,6 +24,9 @@ pub fn should_exit_early(current_env: HashMap) -> bool { if has_watch_file_been_modified(¤t_env) { return false; } + if *env::RTX_TRACE { + eprintln!("rtx: early-exit"); + } true } From 1e19108b494b499acbead5f77dbdcfafac95b36b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 20:36:22 -0600 Subject: [PATCH 0059/1891] [bug] fixed bug with env vars from exec-env they were not being set if entering a directory that also had a .tool-versions file inside of it that exported the same environment variable. e.g.: if 2 .tool-versions files both had golang in it, entering the second directory would cause GOROOT to be _cleared entirely_. The bug was that I was using the _current_ environment here when I should have been using the _pristine_ environment. --- src/env_diff.rs | 26 +++++++++++++------ ...tx__env_diff__tests__from_bash_script.snap | 4 ++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/env_diff.rs b/src/env_diff.rs index 8ebfc1929..805a5d04d 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::ffi::{OsStr, OsString}; use std::fmt::Debug; use std::io::prelude::*; use std::path::Path; @@ -12,7 +11,7 @@ use flate2::Compression; use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; -use crate::{cmd, env}; +use crate::cmd; #[derive(Default, Serialize, Deserialize)] pub struct EnvDiff { @@ -59,10 +58,10 @@ impl EnvDiff { pub fn from_bash_script(script: &Path, env: T) -> Result where T: IntoIterator, - U: Into, - V: Into, + U: Into, + V: Into, { - let env: HashMap = + let env: HashMap = env.into_iter().map(|(k, v)| (k.into(), v.into())).collect(); let out = cmd!( "bash", @@ -79,17 +78,28 @@ impl EnvDiff { let mut additions = HashMap::new(); for line in out.lines() { let (k, v) = line.split_once('=').unwrap_or_default(); - if k == "_" || k == "SHLVL" || k == "PATH" { + if k == "_" + || k == "SHLVL" + || k == "PATH" + || k == "PWD" + || k == "OLDPWD" + || k == "HOME" + || k == "USER" + || k == "SHELL" + || k == "SHELLOPTS" + || k == "COMP_WORDBREAKS" + || k == "PS1" + { continue; } - if let Some(orig) = env.get(OsStr::new(k)) { + if let Some(orig) = env.get(k) { if v == orig { continue; } } additions.insert(k.into(), v.into()); } - Ok(Self::new(&env::vars().collect(), additions)) + Ok(Self::new(&env, additions)) } pub fn deserialize(raw: &str) -> Result { diff --git a/src/snapshots/rtx__env_diff__tests__from_bash_script.snap b/src/snapshots/rtx__env_diff__tests__from_bash_script.snap index 450f20c59..f30b59c0a 100644 --- a/src/snapshots/rtx__env_diff__tests__from_bash_script.snap +++ b/src/snapshots/rtx__env_diff__tests__from_bash_script.snap @@ -3,7 +3,9 @@ source: src/env_diff.rs expression: ed --- EnvDiff { - old: [], + old: [ + "MODIFIED_VAR=original", + ], new: [ "ADDED_VAR=added", "MODIFIED_VAR=modified", From 4bffcd8c09214e8edefff682328f63e488426db2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 20:39:30 -0600 Subject: [PATCH 0060/1891] chore: Release rtx-cli version 1.2.7 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95ef2012a..34f7b016c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.6" +version = "1.2.7" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index c76984114..48d2e71a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.6" +version = "1.2.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 01f621083..4498feae4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.2.6 +rtx 1.2.7 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a23c30759..b455f4243 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.6 +Version: 1.2.7 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From ea39f6be0257df3fbdad780857e01b0707fe59da Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 30 Jan 2023 22:35:52 -0600 Subject: [PATCH 0061/1891] [docs] typo (#57) --- src/cli/render_help.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index b92097887..5e301635e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -46,7 +46,7 @@ $ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` > **Warning** -> > If you use direnv, [see below](#direnv) for direnv-compatible setup. +> If you use direnv, [see below](#direnv) for direnv-compatible setup. Install a runtime and set it as the default: From 37ed75b648410f5f5c307627cea02d58cfea6e09 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 09:39:03 -0600 Subject: [PATCH 0062/1891] [chore] add VERSION and SHA512SUMS to releases (#60) --- scripts/release.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/release.sh b/scripts/release.sh index ffbac95a7..2ec785db9 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -39,13 +39,17 @@ for platform in "${platforms[@]}"; do done pushd "$RELEASE_DIR" -sha256sum ./*.tar.xz ./*.tar.gz >SHASUMS256.txt +sha256sum ./rtx-latest-* >SHASUMS256.txt +sha512sum ./rtx-latest-* >SHASUMS512.txt gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc +gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd pushd "$RELEASE_DIR/$RTX_VERSION" sha256sum ./* >SHASUMS256.txt +sha512sum ./* >SHASUMS512.txt gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc +gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd ./rtx/scripts/render-install.sh >rtx.jdxcode.com/static/install.sh @@ -57,6 +61,7 @@ rm -rf rtx.jdxcode.com/static/deb mv artifacts/deb rtx.jdxcode.com/static/deb cp -vrf "$RELEASE_DIR/"* rtx.jdxcode.com/static +echo "$RTX_VERSION" > rtx.jdxcode.com/static/VERSION ./rtx/scripts/release-npm.sh From 255451a4e22a37028f1a4ef3ff55d726ed2e9164 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 11:53:32 -0600 Subject: [PATCH 0063/1891] [chore] move most pre-commit logic into justfile --- .bin/rtx | 4 +-- .husky/pre-commit | 4 +-- README.md | 2 +- completions/_rtx | 62 ++++++++++++++++++++-------------------- completions/rtx.bash | 26 ++++++++++++++--- completions/rtx.fish | 67 +++++++++++++++++++++----------------------- justfile | 4 +++ 7 files changed, 93 insertions(+), 76 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index 93328eb50..509206f91 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -5,6 +5,4 @@ set -e # when chims are called in shebangs SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -pushd "$SCRIPT_DIR/.." >/dev/null || exit 1 -cargo build -popd >/dev/null && "$SCRIPT_DIR/../target/debug/rtx" "$@" +cargo run --manifest-path "$SCRIPT_DIR/../Cargo.toml" "$@" diff --git a/.husky/pre-commit b/.husky/pre-commit index 0ed656c38..8a057e790 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,6 +2,4 @@ set -e . "$(dirname -- "$0")/_/husky.sh" -just lint -just render-help -git add README.md +just pre-commit diff --git a/README.md b/README.md index 4498feae4..a1710e5de 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ $ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` > **Warning** -> > If you use direnv, [see below](#direnv) for direnv-compatible setup. +> If you use direnv, [see below](#direnv) for direnv-compatible setup. Install a runtime and set it as the default: diff --git a/completions/_rtx b/completions/_rtx index 154188369..d1e0aae5f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -100,12 +100,21 @@ _arguments "${_arguments_options[@]}" \ '*::args -- all arguments:' \ && ret=0 ;; +(complete) +_arguments "${_arguments_options[@]}" \ +'-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ +'--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; (current) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::plugin -- plugin to filter by:' \ +'::plugin -- plugin to show versions of:' \ && ret=0 ;; (deactivate) @@ -196,15 +205,6 @@ _arguments "${_arguments_options[@]}" \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 ;; -(complete) -_arguments "${_arguments_options[@]}" \ -'-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ -'--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; (env) _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish zsh)' \ @@ -358,6 +358,8 @@ _arguments "${_arguments_options[@]}" \ (update) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'()-a[update all plugins]' \ +'()--all[update all plugins]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::plugin -- plugin(s) to update:' \ @@ -565,6 +567,10 @@ esac _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(complete) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (current) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -605,10 +611,6 @@ esac _arguments "${_arguments_options[@]}" \ && ret=0 ;; -(complete) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; (env) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -749,13 +751,13 @@ _rtx_commands() { 'alias:Manage aliases' \ 'a:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ -'current:Get the latest runtime version available for install' \ +'complete:generate shell completions' \ +'current:Shows currently active, and installed runtime versions' \ 'deactivate:disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ -'complete:generate shell completions' \ -'env:exports environment variables to activate rtx in a single shell session' \ -'e:exports environment variables to activate rtx in a single shell session' \ +'env:exports env vars to activate rtx in a single shell session' \ +'e:exports env vars to activate rtx in a single shell session' \ 'exec:execute a command with runtime(s) set' \ 'x:execute a command with runtime(s) set' \ 'global:sets global .tool-versions to include a specified runtime' \ @@ -768,12 +770,8 @@ _rtx_commands() { 'l:Sets .tool-versions to include a specific runtime' \ 'ls:list installed runtime versions' \ 'list:list installed runtime versions' \ -'ls-remote:list runtime versions available for install -note that these versions are cached for commands like `rtx install nodejs@latest` -however _this_ command will always clear that cache and fetch the latest remote versions' \ -'list-remote:list runtime versions available for install -note that these versions are cached for commands like `rtx install nodejs@latest` -however _this_ command will always clear that cache and fetch the latest remote versions' \ +'ls-remote:list runtime versions available for install' \ +'list-remote:list runtime versions available for install' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ 'settings:Manage settings' \ @@ -1018,12 +1016,12 @@ _rtx__help_commands() { 'activate:Enables rtx to automatically modify runtimes when changing directory' \ 'alias:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ -'current:Get the latest runtime version available for install' \ +'complete:generate shell completions' \ +'current:Shows currently active, and installed runtime versions' \ 'deactivate:disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ -'complete:generate shell completions' \ -'env:exports environment variables to activate rtx in a single shell session' \ +'env:exports env vars to activate rtx in a single shell session' \ 'exec:execute a command with runtime(s) set' \ 'global:sets global .tool-versions to include a specified runtime' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ @@ -1031,9 +1029,7 @@ _rtx__help_commands() { 'latest:get the latest runtime version of a plugin'\''s runtimes' \ 'local:Sets .tool-versions to include a specific runtime' \ 'ls:list installed runtime versions' \ -'ls-remote:list runtime versions available for install -note that these versions are cached for commands like `rtx install nodejs@latest` -however _this_ command will always clear that cache and fetch the latest remote versions' \ +'ls-remote:list runtime versions available for install' \ 'plugins:Manage plugins' \ 'settings:Manage settings' \ 'uninstall:removes runtime versions' \ @@ -1286,7 +1282,13 @@ _rtx__settings_commands() { 'ls:Show current settings' \ 'list:Show current settings' \ 'set:Add/update a setting' \ +'add:Add/update a setting' \ +'create:Add/update a setting' \ 'unset:Clears a setting' \ +'rm:Clears a setting' \ +'remove:Clears a setting' \ +'delete:Clears a setting' \ +'del:Clears a setting' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx settings commands' commands "$@" diff --git a/completions/rtx.bash b/completions/rtx.bash index ec0bfb136..848c47cd6 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -309,6 +309,18 @@ _rtx() { rtx__plugins__help,update) cmd="rtx__plugins__help__update" ;; + rtx__settings,add) + cmd="rtx__settings__set" + ;; + rtx__settings,create) + cmd="rtx__settings__set" + ;; + rtx__settings,del) + cmd="rtx__settings__unset" + ;; + rtx__settings,delete) + cmd="rtx__settings__unset" + ;; rtx__settings,get) cmd="rtx__settings__get" ;; @@ -321,6 +333,12 @@ _rtx() { rtx__settings,ls) cmd="rtx__settings__ls" ;; + rtx__settings,remove) + cmd="rtx__settings__unset" + ;; + rtx__settings,rm) + cmd="rtx__settings__unset" + ;; rtx__settings,set) cmd="rtx__settings__set" ;; @@ -349,7 +367,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-h -V --log-level --help --version activate alias asdf current deactivate direnv doctor complete env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="-h -V --log-level --help --version activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -531,7 +549,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-h --log-level --help [PLUGIN]..." + opts="-h --log-level --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -809,7 +827,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf current deactivate direnv doctor complete env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1665,7 +1683,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-h --log-level --help [PLUGIN]..." + opts="-a -h --all --log-level --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 4f13e405e..2ecdc8fc3 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -4,12 +4,12 @@ complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Get the latest runtime version available for install' +complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows currently active, and installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'disable rtx for current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'exports environment variables to activate rtx in a single shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'execute a command with runtime(s) set' complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' @@ -17,9 +17,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'install a runtime complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'list runtime versions available for install -note that these versions are cached for commands like `rtx install nodejs@latest` -however _this_ command will always clear that cache and fetch the latest remote versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'list runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'removes runtime versions' @@ -46,6 +44,9 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" @@ -73,9 +74,6 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' @@ -129,6 +127,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' @@ -164,32 +163,30 @@ complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Get the latest runtime version available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports environment variables to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install -note that these versions are cached for commands like `rtx install nodejs@latest` -however _this_ command will always clear that cache and fetch the latest remote versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' diff --git a/justfile b/justfile index 02b89282d..a81e673fe 100644 --- a/justfile +++ b/justfile @@ -55,3 +55,7 @@ render-completions: ./.bin/rtx complete -s bash > completions/rtx.bash ./.bin/rtx complete -s zsh > completions/_rtx ./.bin/rtx complete -s fish > completions/rtx.fish + +pre-commit: lint render-help render-completions + git add README.md + git add completions From dc4dcfb1218db4e03932336303876b8a19823f09 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 11:56:47 -0600 Subject: [PATCH 0064/1891] [bug] exclude RUBYLIB from exec-env vars that can be set Fixes #64 (see TODO comment) --- src/env_diff.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/env_diff.rs b/src/env_diff.rs index 805a5d04d..862dc2990 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -89,6 +89,11 @@ impl EnvDiff { || k == "SHELLOPTS" || k == "COMP_WORDBREAKS" || k == "PS1" + // TODO: consider removing this + // this is to make the ruby plugin compatible, + // it causes ruby to attempt to call asdf to reshim the binaries + // which we don't need or want to happen + || k == "RUBYLIB" { continue; } From e25d14b0a15f293a6106ba0df6f5ba949864c165 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 11:58:35 -0600 Subject: [PATCH 0065/1891] chore: Release rtx-cli version 1.2.8 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34f7b016c..73ffb3e7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.7" +version = "1.2.8" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 48d2e71a1..7ab234a94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.7" +version = "1.2.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a1710e5de..608a557ed 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.2.7 +rtx 1.2.8 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b455f4243..b100c2c64 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.7 +Version: 1.2.8 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From eab5333d99ccce5314440507ea5018df033b54f4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 13:13:13 -0600 Subject: [PATCH 0066/1891] [bug] making `rtx activate` compatible with direnv --- .bin/rtx | 2 +- Cargo.lock | 7 + Cargo.toml | 12 +- README.md | 3 + completions/_rtx | 2 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/activate.rs | 8 + src/cli/doctor.rs | 2 +- src/cli/hook_env.rs | 105 ++++++++--- src/cli/plugins/uninstall.rs | 5 +- src/cli/version.rs | 14 +- src/cli/where.rs | 2 +- src/config/mod.rs | 24 ++- src/direnv.rs | 123 +++++++++++++ src/env.rs | 53 +++++- src/errors.rs | 2 +- src/fake_asdf.rs | 2 +- src/hook_env.rs | 165 +++++++++--------- src/logger.rs | 2 +- src/main.rs | 13 +- src/output.rs | 22 ++- src/shell/mod.rs | 6 +- ...renv__test__add_path_to_old_and_new-2.snap | 5 + ...direnv__test__add_path_to_old_and_new.snap | 5 + src/snapshots/rtx__direnv__test__dump-2.snap | 5 + src/snapshots/rtx__direnv__test__dump.snap | 5 + src/snapshots/rtx__direnv__test__parse.snap | 5 + 28 files changed, 442 insertions(+), 160 deletions(-) create mode 100644 src/direnv.rs create mode 100644 src/snapshots/rtx__direnv__test__add_path_to_old_and_new-2.snap create mode 100644 src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap create mode 100644 src/snapshots/rtx__direnv__test__dump-2.snap create mode 100644 src/snapshots/rtx__direnv__test__dump.snap create mode 100644 src/snapshots/rtx__direnv__test__parse.snap diff --git a/.bin/rtx b/.bin/rtx index 509206f91..2acb2e01f 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -5,4 +5,4 @@ set -e # when chims are called in shebangs SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -cargo run --manifest-path "$SCRIPT_DIR/../Cargo.toml" "$@" +cargo run --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" diff --git a/Cargo.lock b/Cargo.lock index 73ffb3e7a..dbf73867e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -844,6 +844,12 @@ dependencies = [ "supports-color", ] +[[package]] +name = "paris" +version = "1.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eaf2319cd71dd9ff38c72bebde61b9ea657134abcf26ae4205f54f772a32810" + [[package]] name = "paste" version = "1.0.11" @@ -1163,6 +1169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" dependencies = [ "log", + "paris", "termcolor", "time 0.3.17", ] diff --git a/Cargo.toml b/Cargo.toml index 7ab234a94..5d990ee1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,12 @@ path = "src/main.rs" [dependencies] atty = "0.2.14" base64 = "0.21.0" +build-time = "0.1.2" chrono = "0.4.23" clap = { version = "4.1.1", features = ["derive", "string"] } +clap_complete = "4.1.1" color-eyre = "0.6.2" +ctor = "0.1.26" dirs-next = "2.0.0" duct = "0.13.6" filetime = "0.2.19" @@ -40,24 +43,21 @@ itertools = "0.10.5" lazy_static = "1.4.0" log = "0.4.17" num_cpus = "1.15.0" +once_cell = "1.17.0" owo-colors = { version = "3.5.0", features = ["supports-colors"] } rayon = "1.6.1" regex = "1.7.1" rmp-serde = "1.1.1" serde = "1.0.152" serde_derive = "1.0.152" +serde_json = "1.0.91" shell-escape = "0.1.5" -simplelog = "0.12.0" +simplelog = { version = "0.12.0", features = ["paris"] } thiserror = "1.0.38" -ctor = "0.1.26" toml = "0.7.0" toml_edit = "0.19.0" url = "2.3.1" versions = "4.1.0" -build-time = "0.1.2" -serde_json = "1.0.91" -once_cell = "1.17.0" -clap_complete = "4.1.1" [target.'cfg(unix)'.dependencies] exec = "0.3.1" diff --git a/README.md b/README.md index 608a557ed..42105057c 100644 --- a/README.md +++ b/README.md @@ -453,6 +453,9 @@ Options: [possible values: bash, fish, zsh] + -q, --quiet + Hide the "rtx: @" message when changing directories + -h, --help Print help (see a summary with '-h') diff --git a/completions/_rtx b/completions/_rtx index d1e0aae5f..28401ca5a 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -34,6 +34,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-q[Hide the "rtx: @" message when changing directories]' \ +'--quiet[Hide the "rtx: @" message when changing directories]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 diff --git a/completions/rtx.bash b/completions/rtx.bash index 848c47cd6..780252f93 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -385,7 +385,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -h --shell --log-level --help" + opts="-s -q -h --shell --quiet --log-level --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 2ecdc8fc3..c283c08dc 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -27,6 +27,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal comm complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'Hide the "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 210f2f7e7..4c197bcb7 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -17,12 +17,20 @@ pub struct Activate { /// Shell type to generate the script for #[clap(long, short)] shell: Option, + + /// Hide the "rtx: @" message when changing directories + #[clap(long, short)] + quiet: bool, } impl Command for Activate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { let shell = get_shell(self.shell); + if self.quiet { + rtxprintln!(out, "{}", shell.set_env("RTX_QUIET", "1")); + } + let exe = if cfg!(test) { "rtx".into() } else { diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 72ff46b98..943c5059a 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -20,7 +20,7 @@ impl Command for Doctor { } } - if env::__RTX_DIR.is_none() { + if env::var("__RTX_DIFF").is_err() { checks.push( "rtx is not activated, run `rtx help activate` for setup instructions".to_string(), ); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 3312b64df..af43f6c66 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,10 +1,15 @@ +use std::env::join_paths; +use std::ops::Deref; +use std::path::PathBuf; + use color_eyre::eyre::Result; +use itertools::Itertools; use crate::cli::command::Command; use crate::config::Config; -use crate::config::MissingRuntimeBehavior::Ignore; +use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; +use crate::direnv::DirenvDiff; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; -use crate::hook_env::HookEnvWatches; use crate::output::Output; use crate::shell::{get_shell, ShellType}; use crate::{dirs, env, hook_env}; @@ -22,43 +27,28 @@ pub struct HookEnv { impl Command for HookEnv { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - config.settings.missing_runtime_behavior = Ignore; + if config.settings.missing_runtime_behavior == Prompt { + config.settings.missing_runtime_behavior = Warn; + } config.ensure_installed()?; self.clear_old_env(out); - let mut env = config.env()?; - env.insert("PATH".into(), config.path_env()?); - env.insert("__RTX_DIR".into(), dirs::CURRENT.to_string_lossy().into()); + let env = config.env()?; let diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); - patches.push(EnvDiffOperation::Add( - "__RTX_DIFF".into(), - diff.serialize()?, - )); - patches.push(EnvDiffOperation::Add( - "__RTX_WATCH".into(), - hook_env::serialize_watches(&get_watches(&config)?)?, - )); + patches.extend(self.build_path_operations(&config)?); + patches.push(self.build_diff_operation(&diff)?); + patches.push(self.build_watch_operation(&config)?); + let output = self.build_env_commands(&patches); out.stdout.write(output); + self.display_status(&config, out); Ok(()) } } -fn get_watches(config: &Config) -> Result { - let mut watches = HookEnvWatches::new(); - if dirs::ROOT.exists() { - watches.insert(dirs::ROOT.clone(), dirs::ROOT.metadata()?.modified()?); - } - for cf in &config.config_files { - watches.insert(cf.clone(), cf.metadata()?.modified()?); - } - - Ok(watches) -} - impl HookEnv { fn build_env_commands(&self, patches: &EnvDiffPatches) -> String { let shell = get_shell(self.shell); @@ -83,6 +73,69 @@ impl HookEnv { let output = self.build_env_commands(&patches); out.stdout.write(output); } + + fn display_status(&self, config: &Config, out: &mut Output) { + let installed_versions = config + .ts + .list_current_installed_versions() + .into_iter() + .map(|v| v.to_string()) + .collect_vec(); + if !installed_versions.is_empty() && !*env::RTX_QUIET { + rtxstatusln!(out, "{}", installed_versions.join(" ")); + } + } + + /// modifies the PATH and optionally DIRENV_DIFF env var if it exists + fn build_path_operations(&self, config: &Config) -> Result> { + let installs = config.list_paths()?; + let other = env::PATH + .clone() + .into_iter() + .filter(|p| !p.starts_with(dirs::INSTALLS.deref())) + .collect_vec(); + let new_path = join_paths([installs.clone(), other].concat())? + .to_string_lossy() + .to_string(); + let mut ops = vec![EnvDiffOperation::Add("PATH".into(), new_path)]; + + if let Some(input) = env::DIRENV_DIFF.deref() { + match self.update_direnv_diff(input, &installs) { + Ok(op) => { + ops.push(op); + } + Err(err) => warn!("failed to update DIRENV_DIFF: {}", err), + } + } + + Ok(ops) + } + + /// inserts install path to DIRENV_DIFF both for old and new + /// this makes direnv think that these paths were added before it ran + /// that way direnv will not remove the path when it runs the next time + fn update_direnv_diff(&self, input: &str, installs: &Vec) -> Result { + let mut diff = DirenvDiff::parse(input)?; + for install in installs { + diff.add_path_to_old_and_new(install)?; + } + + Ok(EnvDiffOperation::Change("DIRENV_DIFF".into(), diff.dump()?)) + } + + fn build_diff_operation(&self, diff: &EnvDiff) -> Result { + Ok(EnvDiffOperation::Add( + "__RTX_DIFF".into(), + diff.serialize()?, + )) + } + + fn build_watch_operation(&self, config: &Config) -> Result { + Ok(EnvDiffOperation::Add( + "__RTX_WATCH".into(), + hook_env::serialize_watches(&hook_env::build_watches(config)?)?, + )) + } } #[cfg(test)] diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 6920ba04d..52a96ca14 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -15,8 +15,7 @@ pub struct PluginsUninstall { } impl Command for PluginsUninstall { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let config = Config::load()?; + fn run(self, config: Config, out: &mut Output) -> Result<()> { let plugin = config.ts.find_plugin(&self.plugin); match plugin { Some(plugin) if plugin.is_installed() => { @@ -59,5 +58,7 @@ mod test { let stdout = assert_cli!("plugin", "rm", "nodejs"); assert_snapshot!(stdout); + + ensure_plugin_installed("nodejs"); } } diff --git a/src/cli/version.rs b/src/cli/version.rs index 5be93e0cd..688eaeaca 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -12,8 +12,12 @@ pub struct Version {} lazy_static! { pub static ref VERSION: String = format!( - "{} (built on {})", - env!("CARGO_PKG_VERSION"), + "{} (build {})", + if cfg!(debug_assertions) { + format!("{}-DEBUG", env!("CARGO_PKG_VERSION")) + } else { + env!("CARGO_PKG_VERSION").to_string() + }, BUILD_TIME.format("%Y-%m-%d") ); } @@ -28,10 +32,12 @@ impl Command for Version { #[cfg(test)] mod tests { - use super::*; - use crate::assert_cli; use pretty_assertions::assert_str_eq; + use crate::assert_cli; + + use super::*; + #[test] fn test_version() { let stdout = assert_cli!("version"); diff --git a/src/cli/where.rs b/src/cli/where.rs index a9acd606b..ded31303c 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -89,6 +89,6 @@ mod test { #[test] fn test_where_not_found() { let err = assert_cli_err!("where", "shfmt@1111"); - assert_display_snapshot!(err, @"[shfmt] version 1111 not installed: 1111"); + assert_display_snapshot!(err, @"[shfmt] version 1111 not installed"); } } diff --git a/src/config/mod.rs b/src/config/mod.rs index d5381f499..95f96b1c3 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::env::{join_paths, split_paths}; +use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -29,7 +29,7 @@ mod toolset; type AliasMap = IndexMap>; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Config { pub settings: Settings, pub rtxrc: RTXFile, @@ -93,17 +93,15 @@ impl Config { } pub fn path_env(&self) -> Result { - let mut paths = self.list_paths()?; - let default_path = String::new(); - let orig_path = env::PRISTINE_ENV.get("PATH").unwrap_or(&default_path); - for p in split_paths(orig_path) { - if p.starts_with(dirs::INSTALLS.deref()) { - // ignore existing install directories from previous runs - continue; - } - paths.push(p); - } - Ok(join_paths(paths)?.to_string_lossy().into()) + let installs = self.list_paths()?; + let other = env::PATH + .clone() + .into_iter() + .filter(|p| !p.starts_with(dirs::INSTALLS.deref())) + .collect_vec(); + Ok(join_paths([installs, other].concat())? + .to_string_lossy() + .into()) } pub fn with_runtime_args(mut self, args: &[RuntimeArg]) -> Result { diff --git a/src/direnv.rs b/src/direnv.rs new file mode 100644 index 000000000..612737271 --- /dev/null +++ b/src/direnv.rs @@ -0,0 +1,123 @@ +use base64::prelude::*; +use color_eyre::eyre::Result; +use flate2::write::{ZlibDecoder, ZlibEncoder}; +use flate2::Compression; +use itertools::Itertools; +use serde_derive::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::env::{join_paths, split_paths}; +use std::fmt::{Display, Formatter}; +use std::io::Write; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct DirenvDiff { + #[serde(default, rename = "p")] + pub old: HashMap, + #[serde(default, rename = "n")] + pub new: HashMap, +} + +impl DirenvDiff { + pub fn parse(input: &str) -> Result { + // let bytes = BASE64_URL_SAFE.decode(input)?; + // let uncompressed = inflate_bytes_zlib(&bytes).unwrap(); + // Ok(serde_json::from_slice(&uncompressed[..])?) + let mut writer = Vec::new(); + let mut decoder = ZlibDecoder::new(writer); + let bytes = BASE64_URL_SAFE.decode(input)?; + decoder.write_all(&bytes[..])?; + writer = decoder.finish()?; + Ok(serde_json::from_slice(&writer[..])?) + } + + pub fn new_path(&self) -> Vec { + split_paths(&self.new.get("PATH").cloned().unwrap_or_default()).collect() + } + + pub fn old_path(&self) -> Vec { + split_paths(&self.old.get("PATH").cloned().unwrap_or_default()).collect() + } + + /// this adds a directory to both the old and new path in DIRENV_DIFF + /// the purpose is to trick direnv into thinking that this path has always been there + /// that way it does not remove it when it modifies PATH + /// if the directory exists it is first removed, then added to the front of the list + /// it returns the old and new paths as vectors + pub fn add_path_to_old_and_new(&mut self, path: &Path) -> Result<(Vec, Vec)> { + let mut old = self.old_path(); + let mut new = self.new_path(); + + old.retain(|p| p != path); + new.retain(|p| p != path); + + old.insert(0, path.into()); + new.insert(0, path.into()); + + self.old + .insert("PATH".into(), join_paths(&old)?.into_string().unwrap()); + self.new + .insert("PATH".into(), join_paths(&new)?.into_string().unwrap()); + + Ok((old, new)) + } + + pub fn dump(&self) -> Result { + let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); + gz.write_all(&serde_json::to_vec(self)?)?; + Ok(BASE64_URL_SAFE.encode(gz.finish()?)) + } +} + +impl Display for DirenvDiff { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let print_sorted = |hashmap: &HashMap| { + hashmap + .iter() + .map(|(k, v)| format!("{k}={v}")) + .sorted() + .collect::>() + }; + f.debug_struct("DirenvDiff") + .field("old", &print_sorted(&self.old)) + .field("new", &print_sorted(&self.new)) + .finish() + } +} + +#[cfg(test)] +mod test { + use super::*; + use insta::assert_display_snapshot; + + #[test] + fn test_parse() { + let input = r#"eJys0c1yojAAwPF3ybmWaLB-zPSAGCqIQCGgeGGIELDlM2BEOr77zs7szr7AXv-H3-X_Axqw_gGabYM1qPk1A88XUP1OW93FVhBtdReswURq-FXEfSqJmEusLpKUdxLspALRJY1Yt2Bifk8aLhf5iiZIhhDCjEtE6svmteGuSJVHAV7-qppuYrAG_0WVXtNK8Ms__KgQdYc9sAapMXRj1-9XW8VX7A16UA4NPIs9xCK5WO51XnvfwWBT1R9N7zIcHvvJbZF5g8pk0V2c5CboIw8_NjOUWDK5qcxIcaFrp3anhwdr5FeKJmfd9stgqvuVZqcXsXHYJ-kSGWpoxyZLzf0a0LUcMgv17exenXXunfOTZZfybiVmb9OAhjDtHEcOk0lrRWG84OrRobW6IgGGZqwelglTq8UmJrbP9p0x9pTW5t3L21P1mZfL7_pMtIW599v-Cx_dmzEdCcZ1TAzkz7dvfO4QAefO6Y4VxYmijzgP_Oz9Hbz8uU5jDp7PXwEAAP__wB6qKg=="#; + let diff = DirenvDiff::parse(input).unwrap(); + assert_display_snapshot!(diff); + } + + #[test] + fn test_dump() { + let diff = DirenvDiff { + old: HashMap::from([("a".to_string(), "b".to_string())]), + new: HashMap::from([("c".to_string(), "d".to_string())]), + }; + let output = diff.dump().unwrap(); + assert_display_snapshot!(&output); + let diff = DirenvDiff::parse(&output).unwrap(); + assert_display_snapshot!(diff); + } + + #[test] + fn test_add_path_to_old_and_new() { + let mut diff = DirenvDiff { + old: HashMap::from([("PATH".to_string(), "/foo:/tmp:/bar:/old".to_string())]), + new: HashMap::from([("PATH".to_string(), "/foo:/bar:/new".to_string())]), + }; + let path = PathBuf::from("/tmp"); + diff.add_path_to_old_and_new(&path).unwrap(); + assert_display_snapshot!(diff.old.get("PATH").unwrap()); + assert_display_snapshot!(diff.new.get("PATH").unwrap()); + } +} diff --git a/src/env.rs b/src/env.rs index 7e8495dca..152c3b22f 100644 --- a/src/env.rs +++ b/src/env.rs @@ -5,8 +5,7 @@ use std::path::PathBuf; use lazy_static::lazy_static; -use crate::env_diff::EnvDiff; -use crate::hook_env::get_pristine_env; +use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; lazy_static! { pub static ref ARGS: Vec = args().collect(); @@ -49,7 +48,6 @@ lazy_static! { .unwrap_or_else(|| XDG_DATA_HOME.join("rtx")) }; pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); - pub static ref PATH: OsString = var_os("PATH").unwrap_or_default(); pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); pub static ref RTX_EXE: PathBuf = current_exe().unwrap_or_else(|_| "rtx".into()); pub static ref RTX_LOG_LEVEL: log::LevelFilter = { @@ -78,19 +76,21 @@ lazy_static! { } else { var("RTX_MISSING_RUNTIME_BEHAVIOR").ok() }; - pub static ref __RTX_DIR: Option = var_os("__RTX_DIR").map(PathBuf::from); pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); + pub static ref PATH: Vec = + split_paths(&var_os("PATH").unwrap_or(OsString::new())).collect(); pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String = if cfg!(test) { ".tool-versions".into() } else { var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) }; pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); + pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); } fn get_env_diff() -> EnvDiff { @@ -110,3 +110,48 @@ fn var_is_true(key: &str) -> bool { Err(_) => false, } } + +/// this returns the environment as if __RTX_DIFF was reversed. +/// putting the shell back into a state before hook-env was run +fn get_pristine_env( + rtx_diff: &EnvDiff, + orig_env: HashMap, +) -> HashMap { + let patches = rtx_diff.reverse().to_patches(); + apply_patches(&orig_env, &patches) +} + +fn apply_patches( + env: &HashMap, + patches: &EnvDiffPatches, +) -> HashMap { + let mut new_env = env.clone(); + for patch in patches { + match patch { + EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { + new_env.insert(k.into(), v.into()); + } + EnvDiffOperation::Remove(k) => { + new_env.remove(k); + } + } + } + + new_env +} + +#[test] +fn test_apply_patches() { + let mut env = HashMap::new(); + env.insert("foo".into(), "bar".into()); + env.insert("baz".into(), "qux".into()); + let patches = vec![ + EnvDiffOperation::Add("foo".into(), "bar".into()), + EnvDiffOperation::Change("baz".into(), "qux".into()), + EnvDiffOperation::Remove("quux".into()), + ]; + let new_env = apply_patches(&env, &patches); + assert_eq!(new_env.len(), 2); + assert_eq!(new_env.get("foo").unwrap(), "bar"); + assert_eq!(new_env.get("baz").unwrap(), "qux"); +} diff --git a/src/errors.rs b/src/errors.rs index 4aa00293b..4641dc5e6 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -8,7 +8,7 @@ use crate::plugins::PluginName; pub enum Error { #[error("[{0}] plugin not installed")] PluginNotInstalled(PluginName), - #[error("[{0}] version {1} not installed: {1}")] + #[error("[{0}] version {1} not installed")] VersionNotInstalled(PluginName, String), #[error("[{}] script exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(PluginName, Option), diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 707f2f932..ffbdf598a 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -42,7 +42,7 @@ pub fn get_path_with_fake_asdf() -> String { warn!("Failed to setup fake asdf: {}", e); } }; - path.push(env::PATH.to_string_lossy().to_string()); + path.push(env::var("PATH").unwrap()); path.join(":") } diff --git a/src/hook_env.rs b/src/hook_env.rs index ef778940c..5041b403c 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::io::prelude::*; use std::path::PathBuf; use std::time::SystemTime; @@ -9,62 +9,72 @@ use flate2::write::GzDecoder; use flate2::write::GzEncoder; use flate2::Compression; -use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; +use crate::config::Config; use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being /// called and it does not need to be -pub fn should_exit_early(current_env: HashMap) -> bool { +pub fn should_exit_early(config: &Config) -> bool { + // TODO: make this not depend on config + // if possible, this should avoid loading the entire config + // all I need is the list of config files to load. + // This will likely require splitting config loading into 2 phases: + // 1. load the config filenames + // 2. parse/load the config files, then runtime versions + if env::ARGS.len() < 2 || env::ARGS[1] != "hook-env" { return false; } - if has_rf_path_changed(¤t_env) { - return false; - } - if has_watch_file_been_modified(¤t_env) { + let watch_files = get_watch_files(config); + if have_config_files_been_modified(&env::vars().collect(), watch_files) { return false; } - if *env::RTX_TRACE { - eprintln!("rtx: early-exit"); - } - true -} - -/// this returns the environment as if __RTX_DIFF was reversed -/// putting the shell back into a state before hook-env was run -pub fn get_pristine_env( - rtx_diff: &EnvDiff, - orig_env: HashMap, -) -> HashMap { - let patches = rtx_diff.reverse().to_patches(); - apply_patches(&orig_env, &patches) -} - -fn has_rf_path_changed(env: &HashMap) -> bool { - if let Some(prev) = env.get("__RTX_DIR").map(PathBuf::from) { - if prev == dirs::CURRENT.as_path() { - return false; - } - } + trace!("rtx: early-exit"); true } -fn has_watch_file_been_modified(env: &HashMap) -> bool { - if let Some(prev) = env.get("__RTX_WATCH") { - let watches = deserialize_watches(prev.to_string()).unwrap(); - for (fp, prev_modtime) in watches { - if !fp.exists() { +fn have_config_files_been_modified( + env: &HashMap, + watch_files: HashSet, +) -> bool { + match env.get("__RTX_WATCH") { + Some(prev) => { + let watches = match deserialize_watches(prev.to_string()) { + Ok(watches) => watches, + Err(e) => { + debug!("error deserializing watches: {:?}", e); + return true; + } + }; + + // make sure they have exactly the same config filenames + let watch_keys = watches.keys().cloned().collect::>(); + if watch_keys != watch_files { + trace!( + "config files do not match {:?}", + watch_keys.symmetric_difference(&watch_files) + ); return true; } - if let Ok(modtime) = fp.metadata().unwrap().modified() { - if modtime != prev_modtime { - return true; + + // check the files to see if they've been altered + for (fp, prev_modtime) in watches { + if let Ok(modtime) = fp + .metadata() + .expect("accessing config file modtime") + .modified() + { + if modtime != prev_modtime { + trace!("config file modified: {:?}", fp); + return true; + } } } + trace!("config files unmodified"); + false } - return false; + _ => true, // no previous watch data, we say they have been modified, so we don't exit early } - true } pub type HookEnvWatches = HashMap; @@ -84,57 +94,35 @@ pub fn deserialize_watches(raw: String) -> Result { Ok(rmp_serde::from_slice(&writer[..])?) } -fn apply_patches( - env: &HashMap, - patches: &EnvDiffPatches, -) -> HashMap { - let mut new_env = env.clone(); - for patch in patches { - match patch { - EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { - new_env.insert(k.into(), v.into()); - } - EnvDiffOperation::Remove(k) => { - new_env.remove(k); - } - } - } - - new_env -} - #[cfg(test)] mod test { use std::time::UNIX_EPOCH; + use crate::dirs; + use super::*; #[test] - fn test_has_rf_path_changed() { + fn test_have_config_files_been_modified() { let mut env = HashMap::new(); - assert!(has_rf_path_changed(&env)); - env.insert("__RTX_DIR".into(), dirs::CURRENT.to_string_lossy().into()); - assert!(!has_rf_path_changed(&env)); - env.insert("__RTX_DIR".into(), dirs::HOME.to_string_lossy().into()); - assert!(has_rf_path_changed(&env)); - } + let files = HashSet::new(); + assert!(have_config_files_been_modified(&env, files)); - #[test] - fn test_has_watch_file_been_modified() { - let mut env = HashMap::new(); - assert!(has_watch_file_been_modified(&env)); let fp = dirs::CURRENT.join(".tool-versions"); env.insert( "__RTX_WATCH".into(), serialize_watches(&HookEnvWatches::from([(fp.clone(), UNIX_EPOCH)])).unwrap(), ); - assert!(has_watch_file_been_modified(&env)); + let files = HashSet::from([fp.clone()]); + assert!(have_config_files_been_modified(&env, files)); + let modtime = fp.metadata().unwrap().modified().unwrap(); env.insert( "__RTX_WATCH".into(), - serialize_watches(&HookEnvWatches::from([(fp, modtime)])).unwrap(), + serialize_watches(&HookEnvWatches::from([(fp.clone(), modtime)])).unwrap(), ); - assert!(!has_watch_file_been_modified(&env)); + let files = HashSet::from([fp]); + assert!(!have_config_files_been_modified(&env, files)); } #[test] @@ -155,20 +143,25 @@ mod test { &UNIX_EPOCH ); } +} - #[test] - fn test_apply_patches() { - let mut env = HashMap::new(); - env.insert("foo".into(), "bar".into()); - env.insert("baz".into(), "qux".into()); - let patches = vec![ - EnvDiffOperation::Add("foo".into(), "bar".into()), - EnvDiffOperation::Change("baz".into(), "qux".into()), - EnvDiffOperation::Remove("quux".into()), - ]; - let new_env = apply_patches(&env, &patches); - assert_eq!(new_env.len(), 2); - assert_eq!(new_env.get("foo").unwrap(), "bar"); - assert_eq!(new_env.get("baz").unwrap(), "qux"); +pub fn build_watches(config: &Config) -> Result { + let mut watches = HookEnvWatches::new(); + for cf in get_watch_files(config) { + watches.insert(cf.clone(), cf.metadata()?.modified()?); + } + + Ok(watches) +} + +pub fn get_watch_files(config: &Config) -> HashSet { + let mut watches = HashSet::new(); + if dirs::ROOT.exists() { + watches.insert(dirs::ROOT.clone()); } + for cf in &config.config_files { + watches.insert(cf.clone()); + } + + watches } diff --git a/src/logger.rs b/src/logger.rs index e9fd12b61..c2c930e80 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -36,7 +36,7 @@ fn init_term_logger(level: LevelFilter) -> Box { TermLogger::new( level, ConfigBuilder::new() - .set_thread_level(LevelFilter::Off) + .set_thread_level(LevelFilter::Trace) .set_time_level(LevelFilter::Off) .set_target_level(LevelFilter::Debug) .build(), diff --git a/src/main.rs b/src/main.rs index 0c72312d6..764635487 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,27 +33,28 @@ mod shell; pub mod shorthand_repository; mod ui; +mod direnv; mod hash; #[cfg(test)] mod test; fn main() -> Result<()> { - if hook_env::should_exit_early(env::vars().collect()) { - return Ok(()); - } color_eyre::install()?; let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level); let config = Config::load()?; + if hook_env::should_exit_early(&config) { + return Ok(()); + } let cli = Cli::new_with_external_commands(&config)?; match cli.run(config, &env::ARGS, &mut Output::new()) { Err(err) if log_level < log::LevelFilter::Debug => { - eprintln!("rtx: error {err}"); - eprintln!( + error!("error {err}"); + error!( // "rtx error: Run with `--log-level debug` or RTX_DEBUG=1 for more information." - "rtx: Run with RTX_DEBUG=1 for more information." + "Run with RTX_DEBUG=1 for more information." ); std::process::exit(1); } diff --git a/src/output.rs b/src/output.rs index 978a51274..1d105d6bd 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,3 +1,5 @@ +use atty::Stream; +use owo_colors::OwoColorize; use std::io; use std::io::Write; use std::process::ExitCode; @@ -65,19 +67,31 @@ impl OutputStream { } } +pub fn dim(stream: Stream, s: &str) -> String { + s.if_supports_color(stream, |s| s.dimmed()).to_string() +} + #[macro_export] macro_rules! rtxprintln { () => { rtxprint!("\n") }; - ($ctx:ident, $($arg:tt)*) => {{ - $ctx.stdout.writeln(format!($($arg)*)); + ($out:ident, $($arg:tt)*) => {{ + $out.stdout.writeln(format!($($arg)*)); }}; } #[macro_export] macro_rules! rtxprint { - ($ctx:ident, $($arg:tt)*) => {{ - $ctx.stdout.write(format!($($arg)*)); + ($out:ident, $($arg:tt)*) => {{ + $out.stdout.write(format!($($arg)*)); + }}; +} + +#[macro_export] +macro_rules! rtxstatusln { + ($out:ident, $($arg:tt)*) => {{ + let rtx = $crate::output::dim(atty::Stream::Stderr, "rtx: "); + $out.stderr.writeln(format!("{}{}", rtx, format!($($arg)*))); }}; } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 04c88f207..67ac9fcb0 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,5 +1,4 @@ use std::fmt::{Display, Formatter}; -use std::ops::Deref; use std::path::Path; use crate::env; @@ -58,5 +57,8 @@ pub fn get_shell(shell: Option) -> Box { pub fn is_dir_in_path(dir: &Path) -> bool { let dir = dir.canonicalize().unwrap_or(dir.to_path_buf()); - env::split_paths(env::PATH.deref()).any(|p| p.canonicalize().unwrap_or(p) == dir) + env::PATH + .clone() + .into_iter() + .any(|p| p.canonicalize().unwrap_or(p) == dir) } diff --git a/src/snapshots/rtx__direnv__test__add_path_to_old_and_new-2.snap b/src/snapshots/rtx__direnv__test__add_path_to_old_and_new-2.snap new file mode 100644 index 000000000..e5c2a471c --- /dev/null +++ b/src/snapshots/rtx__direnv__test__add_path_to_old_and_new-2.snap @@ -0,0 +1,5 @@ +--- +source: src/direnv.rs +expression: "diff.new.get(\"PATH\").unwrap()" +--- +/tmp:/foo:/bar:/new diff --git a/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap b/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap new file mode 100644 index 000000000..fa18f8d18 --- /dev/null +++ b/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap @@ -0,0 +1,5 @@ +--- +source: src/direnv.rs +expression: "diff.old.get(\"PATH\").unwrap()" +--- +/tmp:/foo:/bar:/old diff --git a/src/snapshots/rtx__direnv__test__dump-2.snap b/src/snapshots/rtx__direnv__test__dump-2.snap new file mode 100644 index 000000000..95677fef4 --- /dev/null +++ b/src/snapshots/rtx__direnv__test__dump-2.snap @@ -0,0 +1,5 @@ +--- +source: src/direnv.rs +expression: diff +--- +DirenvDiff { old: ["a=b"], new: ["c=d"] } diff --git a/src/snapshots/rtx__direnv__test__dump.snap b/src/snapshots/rtx__direnv__test__dump.snap new file mode 100644 index 000000000..6bff483eb --- /dev/null +++ b/src/snapshots/rtx__direnv__test__dump.snap @@ -0,0 +1,5 @@ +--- +source: src/direnv.rs +expression: "&output" +--- +eAGrVipQsqpWSlSyUkpSqtVRygPxkoG8FKXaWgB2AQf9 diff --git a/src/snapshots/rtx__direnv__test__parse.snap b/src/snapshots/rtx__direnv__test__parse.snap new file mode 100644 index 000000000..fc4fc403a --- /dev/null +++ b/src/snapshots/rtx__direnv__test__parse.snap @@ -0,0 +1,5 @@ +--- +source: src/direnv.rs +expression: diff +--- +DirenvDiff { old: ["FOO=orig"], new: ["DIRENV_DIR=-/private/var/folders/0s/l3b8b_fs7fv5wdpr4lh9bd340000gr/T/tmp.prRveAyl", "DIRENV_FILE=/private/var/folders/0s/l3b8b_fs7fv5wdpr4lh9bd340000gr/T/tmp.prRveAyl/.envrc", "DIRENV_WATCHES=eJxszstK9DAUAOB3ybr0JE2aS3f_4l8KIroSkVxObCUzLScxMyK-u7gSxCf4vscPduvbyhYGB23dN4TuCfJeElIFXqHIYMNzrib3-ZIOUmV1IUnFOecvBPfQTsd40F3Hf-8FRjx3imxgN3tq2wnZIrSZhXNOm4H9v261VbY0esPP4Yd-qN_Ya7rCWPboC9TVE0LaCM8dfCn7BaTOUfKsJztbboLwShqXnQhm8koZTF7LKUqtjEWRuJ1zTEEoaTJ3U5D6r5PTv05PXwEAAP__GahVUg==", "FOO=bar"] } From e42e495bda4eca06bf7e6e469788a58fa50601c3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 18:15:05 -0600 Subject: [PATCH 0067/1891] chore: Release rtx-cli version 1.2.9 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbf73867e..b5266570e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1014,7 +1014,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.8" +version = "1.2.9" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 5d990ee1e..74b93265c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.8" +version = "1.2.9" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 42105057c..b4ff7da4a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.2.8 +rtx 1.2.9 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b100c2c64..580127c23 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.8 +Version: 1.2.9 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 60cc91d038fedf6cb74d1fd59bcbdc986ede6f55 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 19:42:35 -0600 Subject: [PATCH 0068/1891] [feat] improvements to plugins-install * added --all flag (Fixes #50) * added spinner (Addresses #53) --- Cargo.lock | 45 ++++++++++++++++ Cargo.toml | 1 + README.md | 11 ++-- completions/_rtx | 7 +-- completions/rtx.bash | 2 +- completions/rtx.fish | 3 +- src/cli/install.rs | 15 +++--- src/cli/ls.rs | 19 +++---- src/cli/plugins/install.rs | 51 +++++++++++++++++-- ...__cli__plugins__install__test__nodejs.snap | 5 ++ src/cli/plugins/update.rs | 8 ++- src/plugins/mod.rs | 20 +++++--- src/ui/color.rs | 23 +++++++++ src/ui/mod.rs | 1 + 14 files changed, 165 insertions(+), 46 deletions(-) create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__test__nodejs.snap create mode 100644 src/ui/color.rs diff --git a/Cargo.lock b/Cargo.lock index b5266570e..2b1bb3b98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -708,6 +708,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "memchr" version = "2.5.0" @@ -1048,6 +1054,7 @@ dependencies = [ "serde_json", "shell-escape", "simplelog", + "spinners", "tempfile", "thiserror", "toml", @@ -1076,6 +1083,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + [[package]] name = "ryu" version = "1.0.12" @@ -1174,12 +1187,44 @@ dependencies = [ "time 0.3.17", ] +[[package]] +name = "spinners" +version = "4.1.0" +source = "git+https://github.com/FGRibreau/spinners?rev=8b4d130#8b4d130e80cc7c8d2111c95bdd6448bf8fc419f0" +dependencies = [ + "lazy_static", + "maplit", + "strum", +] + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "supports-color" version = "1.3.1" diff --git a/Cargo.toml b/Cargo.toml index 74b93265c..ea6e1ae87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ serde_derive = "1.0.152" serde_json = "1.0.91" shell-escape = "0.1.5" simplelog = { version = "0.12.0", features = ["paris"] } +spinners = { git = "https://github.com/FGRibreau/spinners", rev = "8b4d130" } thiserror = "1.0.38" toml = "0.7.0" toml_edit = "0.19.0" diff --git a/README.md b/README.md index b4ff7da4a..ffa827ba3 100644 --- a/README.md +++ b/README.md @@ -898,10 +898,10 @@ e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin This behavior can be modified in ~/.rtx/config.toml -Usage: install [OPTIONS] [GIT_URL] +Usage: install [OPTIONS] [NAME] [GIT_URL] Arguments: - + [NAME] The name of the plugin to install e.g.: nodejs, ruby @@ -913,7 +913,12 @@ Arguments: Options: -f, --force - Reinstalls even if plugin exists + Reinstall even if plugin exists + + --all + Install all missing plugins + + This will only install plugins that have matching shortnames. i.e.: they don't need the full git repo url -h, --help Print help (see a summary with '-h') diff --git a/completions/_rtx b/completions/_rtx index 28401ca5a..df27a0f2c 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -321,11 +321,12 @@ _arguments "${_arguments_options[@]}" \ (install) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-f[Reinstalls even if plugin exists]' \ -'--force[Reinstalls even if plugin exists]' \ +'-f[Reinstall even if plugin exists]' \ +'--force[Reinstall even if plugin exists]' \ +'(-f --force)--all[Install all missing plugins]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':name -- The name of the plugin to install:' \ +'::name -- The name of the plugin to install:' \ '::git_url -- The git url of the plugin:_urls' \ && ret=0 ;; diff --git a/completions/rtx.bash b/completions/rtx.bash index 780252f93..6da416e3c 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1611,7 +1611,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -h --force --log-level --help [GIT_URL]" + opts="-f -h --force --all --log-level --help [NAME] [GIT_URL]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index c283c08dc..a6dfeaeb9 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -116,7 +116,8 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstalls even if plugin exists' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l all -d 'Install all missing plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' diff --git a/src/cli/install.rs b/src/cli/install.rs index 764b26270..4fe3d8ce6 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,8 +1,9 @@ +use atty::Stream::Stderr; use std::ops::Deref; use std::sync::Arc; use color_eyre::eyre::Result; -use owo_colors::{OwoColorize, Stream}; +use owo_colors::Stream; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -14,6 +15,7 @@ use crate::output::Output; use crate::plugins::InstallType::Version; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; +use crate::ui::color::cyan; /// install a runtime /// @@ -78,8 +80,7 @@ impl Install { } else if rtv.is_installed() { warn!( "{} is already installed", - rtv.to_string() - .if_supports_color(Stream::Stderr, |t| t.cyan()) + cyan(Stream::Stderr, &rtv.to_string()) ); continue; } @@ -87,8 +88,7 @@ impl Install { rtxprintln!( out, "rtx: Installing runtime: {}", - rtv.to_string() - .if_supports_color(Stream::Stderr, |t| t.cyan()) + cyan(Stderr, &rtv.to_string()) ); rtv.install(Version, &config)?; } @@ -130,8 +130,7 @@ impl Install { rtxprintln!( out, "rtx: Installing runtime: {}", - rtv.to_string() - .if_supports_color(Stream::Stderr, |t| t.cyan()) + cyan(Stderr, &rtv.to_string()) ); rtv.install(Version, &config)?; } @@ -142,7 +141,7 @@ impl Install { fn warn_plugin_not_installed(plugin: &Plugin) { warn!( "plugin {} is not installed. Install it with `rtx plugin add {}`", - plugin.name.if_supports_color(Stream::Stderr, |t| t.cyan()), + cyan(Stderr, &plugin.name), plugin.name, ); } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 25536b19a..cbbfdf423 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -1,3 +1,4 @@ +use atty::Stream::Stdout; use std::cmp::max; use std::collections::HashMap; use std::sync::Arc; @@ -12,6 +13,7 @@ use crate::config::{Config, PluginSource}; use crate::output::Output; use crate::plugins::PluginName; use crate::runtimes::RuntimeVersion; +use crate::ui::color::{cyan, dimmed, green, red}; /// list installed runtime versions /// @@ -42,9 +44,7 @@ impl Command for Ls { true => "->", false => " ", }, - &rtv.plugin - .name - .if_supports_color(Stream::Stdout, |t| t.cyan()), + cyan(Stdout, &rtv.plugin.name), styled_version(&rtv.version, !rtv.is_installed(), source.is_some()), match source { Some(source) => format!("(set by {source})"), @@ -62,18 +62,11 @@ fn styled_version(version: &String, missing: bool, active: bool) -> String { version .if_supports_color(Stream::Stdout, |t| t.strikethrough().red().to_string()) .to_string() - + " (missing)" - .if_supports_color(Stream::Stdout, |t| t.red()) - .to_string() - .as_str() + + red(Stdout, " (missing)").as_str() } else if active { - version - .if_supports_color(Stream::Stdout, |t| t.green()) - .to_string() + green(Stdout, version) } else { - version - .if_supports_color(Stream::Stdout, |t| t.dimmed()) - .to_string() + dimmed(Stdout, version) }; let unstyled = if missing { format!("{version} (missing)") diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 6bebd2bcd..40d97fd25 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use color_eyre::eyre::{eyre, Result}; use url::Url; @@ -19,8 +21,8 @@ pub struct PluginsInstall { /// The name of the plugin to install /// /// e.g.: nodejs, ruby - #[clap()] - name: String, + #[clap(required_unless_present = "all")] + name: Option, /// The git url of the plugin /// @@ -28,14 +30,24 @@ pub struct PluginsInstall { #[clap(help = "The git url of the plugin", value_hint = clap::ValueHint::Url)] git_url: Option, - /// Reinstalls even if plugin exists + /// Reinstall even if plugin exists #[clap(short, long)] force: bool, + + /// Install all missing plugins + /// + /// This will only install plugins that have matching shortnames. + /// i.e.: they don't need the full git repo url + #[clap(long, conflicts_with_all = ["name", "force"])] + all: bool, } impl Command for PluginsInstall { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let (name, git_url) = get_name_and_url(&config, self.name, self.git_url)?; + if self.all { + return self.install_all_missing_plugins(&config); + } + let (name, git_url) = get_name_and_url(&config, self.name.unwrap(), self.git_url)?; let plugin = Plugin::load(&name)?; if self.force { plugin.uninstall()?; @@ -50,6 +62,29 @@ impl Command for PluginsInstall { } } +impl PluginsInstall { + fn install_all_missing_plugins(&self, config: &Config) -> Result<()> { + let missing_plugins = self.missing_plugins(config)?; + if missing_plugins.is_empty() { + warn!("all plugins already installed"); + } + for plugin in missing_plugins { + let (_, git_url) = get_name_and_url(config, plugin.name.clone(), None)?; + plugin.install(&git_url)?; + } + Ok(()) + } + + fn missing_plugins(&self, config: &Config) -> Result>> { + Ok(config + .ts + .list_plugins() + .into_iter() + .filter(|p| !p.is_installed()) + .collect::>()) + } +} + fn get_name_and_url( config: &Config, name: String, @@ -123,4 +158,12 @@ mod test { let err = cli_run(&args).unwrap_err(); assert_display_snapshot!(err); } + + #[test] + fn test_plugin_install_all() { + assert_cli!("plugin", "rm", "nodejs"); + assert_cli!("plugin", "install", "--all"); + let stdout = assert_cli!("plugin"); + assert_snapshot!(grep(stdout, "nodejs"), "nodejs"); + } } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__nodejs.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__nodejs.snap new file mode 100644 index 000000000..16fbb5bdf --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__nodejs.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/plugins/install.rs +expression: "\"nodejs\"" +--- +nodejs diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index cebc1e7dc..436fed71f 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,12 +1,13 @@ use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; -use owo_colors::{OwoColorize, Stream}; +use owo_colors::Stream; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; +use crate::ui::color::cyan; /// updates a plugin to the latest version /// @@ -30,10 +31,7 @@ impl Command for Update { .into_iter() .map(|p| { config.ts.find_plugin(&p).ok_or_else(|| { - eyre!( - "plugin {} not found", - p.if_supports_color(Stream::Stderr, |t| t.cyan()) - ) + eyre!("plugin {} not found", cyan(Stream::Stderr, p.as_str())) }) }) .collect::>>>()?, diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index b18b17dc8..5635729ae 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -4,12 +4,13 @@ use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; +use atty::Stream::Stderr; use color_eyre::eyre::WrapErr; use color_eyre::eyre::{eyre, Result}; use itertools::Itertools; use lazy_static::lazy_static; -use owo_colors::{OwoColorize, Stream}; use regex::Regex; +use spinners::{Spinner, Spinners, Stream}; use versions::Mess; use cache::PluginCache; @@ -23,6 +24,7 @@ use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::shorthand_repository::ShorthandRepo; +use crate::ui::color::{bright_green, cyan}; use crate::ui::prompt; use crate::{dirs, file}; @@ -92,9 +94,10 @@ impl Plugin { pub fn install(&self, repository: &String) -> Result<()> { debug!("install {} {:?}", self.name, repository); - eprint!( - "rtx: Installing plugin {}...", - self.name.if_supports_color(Stream::Stderr, |t| t.cyan()) + let mut sp = Spinner::with_stream( + Spinners::Dots10, + format!("rtx: Installing plugin {}...", cyan(Stderr, &self.name)), + Stream::Stderr, ); if self.is_installed() { @@ -103,7 +106,10 @@ impl Plugin { let git = Git::new(self.plugin_path.to_path_buf()); git.clone(repository)?; - eprintln!(" done"); + sp.stop_and_persist( + &bright_green(Stderr, "âś”"), + format!("Plugin {} installed", cyan(Stderr, &self.name)), + ); Ok(()) } @@ -173,9 +179,7 @@ impl Plugin { fs::remove_dir_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", - dir.to_str() - .unwrap() - .if_supports_color(Stream::Stderr, |t| t.cyan()) + cyan(Stderr, &dir.to_string_lossy()) ) }) }; diff --git a/src/ui/color.rs b/src/ui/color.rs new file mode 100644 index 000000000..ea596010a --- /dev/null +++ b/src/ui/color.rs @@ -0,0 +1,23 @@ +use atty::Stream; +use owo_colors::OwoColorize; + +pub fn dimmed(stream: Stream, s: &str) -> String { + s.if_supports_color(stream, |s| s.dimmed()).to_string() +} +pub fn _yellow(stream: Stream, s: &str) -> String { + s.if_supports_color(stream, |s| s.yellow()).to_string() +} +pub fn cyan(stream: Stream, s: &str) -> String { + s.if_supports_color(stream, |s| s.cyan()).to_string() +} +pub fn green(stream: Stream, s: &str) -> String { + s.if_supports_color(stream, |s| s.green()).to_string() +} +pub fn bright_green(stream: Stream, s: &str) -> String { + s.if_supports_color(stream, |s| s.bright_green()) + .to_string() +} + +pub fn red(stream: Stream, s: &str) -> String { + s.if_supports_color(stream, |s| s.red()).to_string() +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 8bf84783c..093bb1252 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1 +1,2 @@ +pub mod color; pub mod prompt; From e3221a58cbf3dc63ed0b1935730347f1d17b94ca Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 20:43:24 -0600 Subject: [PATCH 0069/1891] [feat] improvements to install * added --all flag (Fixes #50) * added spinner (Addresses #53) --- README.md | 9 +++- completions/_rtx | 5 +++ completions/rtx.bash | 4 +- completions/rtx.fish | 4 +- src/cli/install.rs | 85 ++++++++++++++++++++++++----------- src/cli/plugins/install.rs | 2 +- src/plugins/mod.rs | 2 +- src/plugins/script_manager.rs | 29 ++++++++++++ src/runtimes/mod.rs | 56 ++++++++++++++--------- src/test.rs | 9 +--- 10 files changed, 144 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index ffa827ba3..ab6940757 100644 --- a/README.md +++ b/README.md @@ -750,6 +750,12 @@ Options: -f, --force force reinstall even if already installed + -a, --all + install all missing runtimes as well as all plugins for the current directory + + -v, --verbose + show installation output + -h, --help Print help (see a summary with '-h') @@ -759,6 +765,7 @@ Examples: $ rtx install nodejs@18 # install fuzzy nodejs version $ rtx install nodejs # install latest nodejs version—or what is specified in .tool-versions $ rtx install # installs all runtimes specified in .tool-versions for installed plugins + $ rtx install --all # installs all runtimes and all plugins ``` ### `rtx latest` @@ -915,7 +922,7 @@ Options: -f, --force Reinstall even if plugin exists - --all + -a, --all Install all missing plugins This will only install plugins that have matching shortnames. i.e.: they don't need the full git repo url diff --git a/completions/_rtx b/completions/_rtx index df27a0f2c..1b150bf6c 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -254,6 +254,10 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[force reinstall even if already installed]' \ '--force[force reinstall even if already installed]' \ +'(-p --plugin -f --force)-a[install all missing runtimes as well as all plugins for the current directory]' \ +'(-p --plugin -f --force)--all[install all missing runtimes as well as all plugins for the current directory]' \ +'-v[show installation output]' \ +'--verbose[show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- runtime(s) to install:' \ @@ -323,6 +327,7 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ +'(-f --force)-a[Install all missing plugins]' \ '(-f --force)--all[Install all missing plugins]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 6da416e3c..d2e95e56d 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1385,7 +1385,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-p -f -h --plugin --force --log-level --help [RUNTIME]..." + opts="-p -f -a -v -h --plugin --force --all --verbose --log-level --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1611,7 +1611,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -h --force --all --log-level --help [NAME] [GIT_URL]" + opts="-f -a -h --force --all --log-level --help [NAME] [GIT_URL]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index a6dfeaeb9..107112e05 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -91,6 +91,8 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' +complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'install all missing runtimes as well as all plugins for the current directory' +complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' @@ -117,7 +119,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l all -d 'Install all missing plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' diff --git a/src/cli/install.rs b/src/cli/install.rs index 4fe3d8ce6..85f6c0b68 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,9 +1,9 @@ -use atty::Stream::Stderr; -use std::ops::Deref; use std::sync::Arc; +use atty::Stream::Stderr; use color_eyre::eyre::Result; use owo_colors::Stream; +use spinners::{Spinner, Spinners}; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -15,7 +15,7 @@ use crate::output::Output; use crate::plugins::InstallType::Version; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; -use crate::ui::color::cyan; +use crate::ui::color::{bright_green, cyan}; /// install a runtime /// @@ -39,13 +39,21 @@ pub struct Install { /// force reinstall even if already installed #[clap(long, short, requires = "runtime")] force: bool, + + /// install all missing runtimes as well as all plugins for the current directory + #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"])] + all: bool, + + /// show installation output + #[clap(long, short)] + verbose: bool, } impl Command for Install { fn run(self, config: Config, out: &mut Output) -> Result<()> { match &self.runtime { Some(runtime) => self.install_runtimes(config, out, runtime)?, - None => self.install_missing_runtimes(config, out, &self.plugin)?, + None => self.install_missing_runtimes(config, out)?, } Ok(()) @@ -85,29 +93,25 @@ impl Install { continue; } - rtxprintln!( - out, - "rtx: Installing runtime: {}", - cyan(Stderr, &rtv.to_string()) - ); - rtv.install(Version, &config)?; + self.do_install(&config, out, &rtv)?; } Ok(()) } - fn install_missing_runtimes( - &self, - config: Config, - out: &mut Output, - plugin_flag: &Option>, - ) -> Result<()> { + fn install_missing_runtimes(&self, mut config: Config, out: &mut Output) -> Result<()> { for rtv in config.ts.list_current_versions() { - if let Some(plugin_flag) = plugin_flag { - if !plugin_flag.contains(&rtv.plugin.name) { + let plugins = match self.all { + true => Some(get_all_plugin_names(&config)), + false => self.plugin.clone(), + }; + if let Some(plugins) = &plugins { + // they've specified --all or --plugin, so we already know they want to install + config.settings.missing_runtime_behavior = AutoInstall; + if !plugins.contains(&rtv.plugin.name) { continue; } - // ensure plugin is installed only if explicitly called with --plugin + // ensure plugin is installed only if explicitly called with --plugin or using --all if !rtv.plugin.ensure_installed(&config.settings)? { Err(PluginNotInstalled(rtv.plugin.name.to_string()))?; } @@ -120,19 +124,36 @@ impl Install { if rtv.version == "system" || rtv.is_installed() { continue; } - // need to re-resolve the version in case it was a fuzzy version - let mut rtv = rtv.deref().clone(); - rtv.version = rtv + let version = rtv .plugin .latest_version(&rtv.version)? .unwrap_or_else(|| rtv.version.clone()); + // need to re-create the rtv because the version may have changed + let rtv = RuntimeVersion::new(rtv.plugin.clone(), &version); + self.do_install(&config, out, &rtv)?; + } + Ok(()) + } - rtxprintln!( - out, - "rtx: Installing runtime: {}", - cyan(Stderr, &rtv.to_string()) + fn do_install(&self, config: &Config, out: &mut Output, rtv: &RuntimeVersion) -> Result<()> { + let rtv_label = cyan(Stderr, &rtv.to_string()); + let install_message = format!("Installing runtime: {rtv_label}..."); + let sp = if self.verbose { + out.stderr.writeln(install_message); + None + } else { + Some(Spinner::with_stream( + Spinners::Dots10, + install_message, + spinners::Stream::Stderr, + )) + }; + rtv.install(Version, config, self.verbose)?; + if let Some(mut sp) = sp { + sp.stop_and_persist( + &bright_green(Stderr, "âś”"), + format!("Runtime {rtv_label} installed"), ); - rtv.install(Version, &config)?; } Ok(()) } @@ -146,12 +167,22 @@ fn warn_plugin_not_installed(plugin: &Plugin) { ); } +fn get_all_plugin_names(config: &Config) -> Vec { + config + .ts + .list_plugins() + .into_iter() + .map(|p| p.name.clone()) + .collect() +} + const AFTER_LONG_HELP: &str = r#" Examples: $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version $ rtx install nodejs # install latest nodejs version—or what is specified in .tool-versions $ rtx install # installs all runtimes specified in .tool-versions for installed plugins + $ rtx install --all # installs all runtimes and all plugins "#; #[cfg(test)] diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 40d97fd25..e62314375 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -38,7 +38,7 @@ pub struct PluginsInstall { /// /// This will only install plugins that have matching shortnames. /// i.e.: they don't need the full git repo url - #[clap(long, conflicts_with_all = ["name", "force"])] + #[clap(short, long, conflicts_with_all = ["name", "force"])] all: bool, } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 5635729ae..e4b54fd81 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -96,7 +96,7 @@ impl Plugin { debug!("install {} {:?}", self.name, repository); let mut sp = Spinner::with_stream( Spinners::Dots10, - format!("rtx: Installing plugin {}...", cyan(Stderr, &self.name)), + format!("Installing plugin {}...", cyan(Stderr, &self.name)), Stream::Stderr, ); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 5efd36464..f5aa8844c 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -1,5 +1,6 @@ use std::fmt; use std::fmt::{Display, Formatter}; +use std::io::{stderr, Write}; use std::path::PathBuf; use std::process::Output; @@ -148,4 +149,32 @@ impl ScriptManager { .read() .with_context(|| ScriptFailed(self.plugin_name.clone(), None)) } + + pub fn run_with_hidden_output(&self, script: Script, on_error: F) -> Result<()> + where + F: FnOnce(), + { + let out = self + .cmd(script) + .stderr_to_stdout() + .stdout_capture() + .unchecked() + .run(); + + match out { + Err(err) => { + on_error(); + Err(err)? + } + Ok(out) => match out.status.success() { + true => Ok(()), + false => { + stderr().write_all(out.stdout.as_slice())?; + on_error(); + let err = ScriptFailed(self.plugin_name.clone(), Some(out.status)); + Err(err)? + } + }, + } + } } diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index a2b5419b7..f1dadf7d5 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::error::Error; + use std::fmt; use std::fmt::{Display, Formatter}; use std::fs::{create_dir_all, remove_dir_all}; @@ -64,7 +64,7 @@ impl RuntimeVersion { Ok(versions) } - pub fn install(&self, install_type: InstallType, config: &Config) -> Result<()> { + pub fn install(&self, install_type: InstallType, config: &Config, verbose: bool) -> Result<()> { let plugin = &self.plugin; let settings = &config.settings; debug!("install {} {} {}", plugin.name, self.version, install_type); @@ -78,25 +78,38 @@ impl RuntimeVersion { let install = Script::Install(install_type); if self.script_man.script_exists(&download) { + if verbose { + self.script_man + .cmd(download) + .stdout_to_stderr() + .run() + .map_err(|err| { + self.cleanup_install_dirs_on_error(settings); + err + })?; + } else { + self.script_man.run_with_hidden_output(download, || { + self.cleanup_install_dirs_on_error(settings); + })?; + } + } + + if verbose { self.script_man - .cmd(download) + .cmd(install) .stdout_to_stderr() .run() .map_err(|err| { - self.cleanup_install_dirs(Some(&err), settings); + self.cleanup_install_dirs_on_error(settings); err })?; - } - - self.script_man - .cmd(install) - .stdout_to_stderr() - .run() - .map_err(|err| { - self.cleanup_install_dirs(Some(&err), settings); - err + self.cleanup_install_dirs(settings); + } else { + self.script_man.run_with_hidden_output(install, || { + self.cleanup_install_dirs_on_error(settings); })?; - self.cleanup_install_dirs(None, settings); + } + self.cleanup_install_dirs(settings); let conf = RuntimeConf { bin_paths: self.get_bin_paths()?, @@ -137,12 +150,12 @@ impl RuntimeVersion { } match config.settings.missing_runtime_behavior { MissingRuntimeBehavior::AutoInstall => { - self.install(InstallType::Version, config)?; + self.install(InstallType::Version, config, false)?; Ok(true) } MissingRuntimeBehavior::Prompt => { if prompt_for_install(&format!("{self}")) { - self.install(InstallType::Version, config)?; + self.install(InstallType::Version, config, false)?; Ok(true) } else { Ok(false) @@ -228,15 +241,18 @@ impl RuntimeVersion { } fn create_install_dirs(&self) -> Result<()> { + let _ = remove_dir_all(&self.install_path); + let _ = remove_dir_all(&self.download_path); create_dir_all(&self.install_path)?; create_dir_all(&self.download_path)?; Ok(()) } - fn cleanup_install_dirs(&self, err: Option<&dyn Error>, settings: &Settings) { - if err.is_some() { - let _ = remove_dir_all(&self.install_path); - } + fn cleanup_install_dirs_on_error(&self, settings: &Settings) { + let _ = remove_dir_all(&self.install_path); + self.cleanup_install_dirs(settings); + } + fn cleanup_install_dirs(&self, settings: &Settings) { if !settings.always_keep_download { let _ = remove_dir_all(&self.download_path); } diff --git a/src/test.rs b/src/test.rs index 231bc2862..1f81c8d50 100644 --- a/src/test.rs +++ b/src/test.rs @@ -27,14 +27,7 @@ fn init() { "tiny", "https://github.com/jdxcode/asdf-tiny" ); - assert_cli!("plugin", "install", "shellcheck"); - assert_cli!("plugin", "install", "shfmt"); - assert_cli!("plugin", "install", "nodejs"); - assert_cli!("plugin", "install", "jq"); - assert_cli!("plugin", "install", "golang"); - assert_cli!("plugin", "install", "python"); - assert_cli!("plugin", "install", "rust"); - assert_cli!("install"); + assert_cli!("install", "--all"); } pub fn reset_config() { From 7580539a8951c343e6da75d386dacee89f099d82 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 20:48:43 -0600 Subject: [PATCH 0070/1891] chore: Release rtx-cli version 1.3.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- packaging/rpm/rtx.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b1bb3b98..b7edc6199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1020,7 +1020,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.2.9" +version = "1.3.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index ea6e1ae87..c0a2d3246 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.2.9" +version = "1.3.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index ab6940757..f120ccd3d 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.2.9 +rtx 1.3.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 580127c23..01cdafe45 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.2.9 +Version: 1.3.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From ada8ccac4ecc314402f278c49b478ae05982c7dd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 20:52:42 -0600 Subject: [PATCH 0071/1891] [chore] use custom fork of spinner --- Cargo.lock | 7 ++++--- Cargo.toml | 2 +- src/cli/install.rs | 4 ++-- src/plugins/mod.rs | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7edc6199..ddb80323c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1054,7 +1054,7 @@ dependencies = [ "serde_json", "shell-escape", "simplelog", - "spinners", + "spinners-jdxcode", "tempfile", "thiserror", "toml", @@ -1188,9 +1188,10 @@ dependencies = [ ] [[package]] -name = "spinners" +name = "spinners-jdxcode" version = "4.1.0" -source = "git+https://github.com/FGRibreau/spinners?rev=8b4d130#8b4d130e80cc7c8d2111c95bdd6448bf8fc419f0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bbd00662c4720cbae51a6743924e83c81ea3ef7e80fc991a537988ee0da3bf" dependencies = [ "lazy_static", "maplit", diff --git a/Cargo.toml b/Cargo.toml index c0a2d3246..6708796c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ serde_derive = "1.0.152" serde_json = "1.0.91" shell-escape = "0.1.5" simplelog = { version = "0.12.0", features = ["paris"] } -spinners = { git = "https://github.com/FGRibreau/spinners", rev = "8b4d130" } +spinners-jdxcode = "4.1.0" thiserror = "1.0.38" toml = "0.7.0" toml_edit = "0.19.0" diff --git a/src/cli/install.rs b/src/cli/install.rs index 85f6c0b68..76f9b11b7 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use atty::Stream::Stderr; use color_eyre::eyre::Result; use owo_colors::Stream; -use spinners::{Spinner, Spinners}; +use spinners_jdxcode::{Spinner, Spinners}; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -145,7 +145,7 @@ impl Install { Some(Spinner::with_stream( Spinners::Dots10, install_message, - spinners::Stream::Stderr, + spinners_jdxcode::Stream::Stderr, )) }; rtv.install(Version, config, self.verbose)?; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index e4b54fd81..50e2b2edb 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -10,7 +10,7 @@ use color_eyre::eyre::{eyre, Result}; use itertools::Itertools; use lazy_static::lazy_static; use regex::Regex; -use spinners::{Spinner, Spinners, Stream}; +use spinners_jdxcode::{Spinner, Spinners, Stream}; use versions::Mess; use cache::PluginCache; From c7db4615c762627a614f57cce4b7ef496c9cdec4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 20:59:16 -0600 Subject: [PATCH 0072/1891] [chore] set release version on publish --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 6708796c5..f15586b32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,6 +84,7 @@ allow-branch = ["main"] pre-release-replacements = [ { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, + { file = "src/cli/render_help.rs", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, ] From d4c9ef1d2803b9c872a4fdc6c26567771fa05566 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 20:59:27 -0600 Subject: [PATCH 0073/1891] chore: Release rtx-cli version 1.3.0 --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f120ccd3d..51d694c05 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.2.6/rtx-v1.2.6-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.0/rtx-v1.3.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 5e301635e..9e99adc0e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -192,7 +192,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.2.6/rtx-v1.2.6-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.0/rtx-v1.3.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From b0368ec32fc0ccad70300cb8f5efe99db3faf568 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 22:35:57 -0600 Subject: [PATCH 0074/1891] minor ui tweaks --- src/cli/install.rs | 2 +- src/cli/version.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/install.rs b/src/cli/install.rs index 76f9b11b7..5b13ab4ba 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -139,7 +139,7 @@ impl Install { let rtv_label = cyan(Stderr, &rtv.to_string()); let install_message = format!("Installing runtime: {rtv_label}..."); let sp = if self.verbose { - out.stderr.writeln(install_message); + rtxstatusln!(out, "{install_message}"); None } else { Some(Spinner::with_stream( diff --git a/src/cli/version.rs b/src/cli/version.rs index 688eaeaca..80e2bd6cf 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -12,7 +12,7 @@ pub struct Version {} lazy_static! { pub static ref VERSION: String = format!( - "{} (build {})", + "{} (built {})", if cfg!(debug_assertions) { format!("{}-DEBUG", env!("CARGO_PKG_VERSION")) } else { From 55c0ebc35c4d077b1186dd043aab0b2f8bb5fb69 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 23:03:53 -0600 Subject: [PATCH 0075/1891] retry direnv install --- .github/workflows/rtx.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 27b44815d..27c02f51d 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -45,7 +45,11 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 - name: Install direnv - run: curl -sfL https://direnv.net/install.sh | bash + uses: nick-fields/retry@v2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: curl -sfL https://direnv.net/install.sh | bash - name: Install just uses: taiki-e/install-action@just - name: Run tests with coverage From 2991afe621e190a98062b31d3b0c845be3dfcd8a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 31 Jan 2023 23:17:13 -0600 Subject: [PATCH 0076/1891] [docs] note about adding extra shells --- README.md | 8 ++++++++ src/cli/render_help.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 51d694c05..1a7e07711 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,14 @@ $ echo 'eval "$(rtx activate -s bash)"' >> ~/.bashrc $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` +### Something else? + +Adding a new shell is not hard at all since very little shell code is +in this project. +[See here](https://github.com/jdxcode/rtx/tree/main/src/shell) for how +the others are implemented. If your shell isn't currently supported +I'd be happy to help you get yours integrated. + ## Configuration ### `.tool-versions` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9e99adc0e..1106f1036 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -264,6 +264,14 @@ $ echo 'eval "$(rtx activate -s bash)"' >> ~/.bashrc $ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` +### Something else? + +Adding a new shell is not hard at all since very little shell code is +in this project. +[See here](https://github.com/jdxcode/rtx/tree/main/src/shell) for how +the others are implemented. If your shell isn't currently supported +I'd be happy to help you get yours integrated. + ## Configuration ### `.tool-versions` From 6643835ae6adc100af6af98b3710d7e1829c72a4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 08:01:50 -0600 Subject: [PATCH 0077/1891] docs: mention direnv is WIP --- README.md | 4 +++- src/cli/render_help.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a7e07711..3a2a6d36f 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ $ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` > **Warning** -> If you use direnv, [see below](#direnv) for direnv-compatible setup. +> [We're working to make `rtx activate` not conflict with direnv.](https://github.com/jdxcode/rtx/issues/8) +> Hopefully soon you'll be able to use `rtx activate` with direnv. +> If you use direnv, [see below](#direnv) for direnv-compatible setup that does not require `rtx activate`. Install a runtime and set it as the default: diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1106f1036..192b97f4b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -46,7 +46,9 @@ $ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` > **Warning** -> If you use direnv, [see below](#direnv) for direnv-compatible setup. +> [We're working to make `rtx activate` not conflict with direnv.](https://github.com/jdxcode/rtx/issues/8) +> Hopefully soon you'll be able to use `rtx activate` with direnv. +> If you use direnv, [see below](#direnv) for direnv-compatible setup that does not require `rtx activate`. Install a runtime and set it as the default: From 9d6089f7bb3945006dd1110f1a3ebb0c46b70dc4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 13:17:52 -0600 Subject: [PATCH 0078/1891] [feat] added RTX_LOG_FILE_LEVEL to log at a different level than is shown on screen (#70) --- README.md | 14 ++++++++++ src/cli/render_help.rs | 14 ++++++++++ src/config/config_file/tool_versions.rs | 22 ++++++++++------ src/config/mod.rs | 35 ++++++++++++++++++------- src/env.rs | 16 ++++++----- src/logger.rs | 8 +++--- src/main.rs | 2 +- 7 files changed, 82 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 3a2a6d36f..af694b3e2 100644 --- a/README.md +++ b/README.md @@ -379,6 +379,20 @@ of what is set in `.tool-versions`. Plugins can read the versions files used by other version managers (if enabled by the plugin) for example, .nvmrc in the case of nodejs's nvm. +#### `RTX_LOG_LEVEL=trace|debug|info|warn|error` + +Can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1`. These adjust the log +output to the screen. + +#### `RTX_LOG_FILE=~/.rtx/rtx.log` + +Output logs to a file. + +#### `RTX_LOG_FILE_LEVEL=trace|debug|info|warn|error` + +Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want +to store the logs but not have them litter your display. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 192b97f4b..eaa096bb5 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -397,6 +397,20 @@ of what is set in `.tool-versions`. Plugins can read the versions files used by other version managers (if enabled by the plugin) for example, .nvmrc in the case of nodejs's nvm. +#### `RTX_LOG_LEVEL=trace|debug|info|warn|error` + +Can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1`. These adjust the log +output to the screen. + +#### `RTX_LOG_FILE=~/.rtx/rtx.log` + +Output logs to a file. + +#### `RTX_LOG_FILE_LEVEL=trace|debug|info|warn|error` + +Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want +to store the logs but not have them litter your display. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 7ca832fef..4d3d5249c 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -6,9 +6,11 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; use indexmap::IndexMap; +use itertools::Itertools; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::PluginSource; +use crate::file::display_path; use crate::plugins::PluginName; // python 3.11.0 3.10.0 @@ -100,7 +102,17 @@ impl ToolVersions { impl Display for ToolVersions { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.dump()) + let plugins = &self + .plugins + .iter() + .map(|(p, v)| format!("{}@{}", p, v.versions.join("|"))) + .collect_vec(); + write!( + f, + "ToolVersions({}): {}", + display_path(&self.path), + plugins.join(", ") + ) } } @@ -177,13 +189,7 @@ pub(crate) mod tests { fn test_parse() { let tv = ToolVersions::from_file(dirs::CURRENT.join(".tool-versions").as_path()).unwrap(); assert_eq!(tv.path, dirs::CURRENT.join(".tool-versions")); - assert_display_snapshot!(tv, @r###" - #python 3.11.1 3.10.9 # foo - shellcheck 0.9.0 - shfmt 3.5.2 # test comment - #nodejs 18.13.0 - nodejs system - "###); + assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.tool-versions): shellcheck@0.9.0, shfmt@3.5.2, nodejs@system"); } #[test] diff --git a/src/config/mod.rs b/src/config/mod.rs index 95f96b1c3..5faa4e47b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -262,7 +262,7 @@ fn load_config_files( } fn load_config_file(ts: &mut Toolset, cf: Box) -> Result<()> { - trace!("config file: {:#?}", cf); + trace!("config file: {}", cf); for (plugin, versions) in cf.plugins() { ts.set_current_runtime_versions(&plugin, versions.clone(), cf.source())?; } @@ -317,15 +317,30 @@ fn err_load_settings(settings_path: &Path) -> Report { impl Display for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let plugins = self + .ts + .list_installed_plugins() + .into_iter() + .map(|p| p.name.clone()) + .collect::>(); + let versions = self + .ts + .list_current_installed_versions() + .into_iter() + .map(|rtv| rtv.to_string()) + .collect::>(); + let config_files = self + .config_files + .iter() + .map(|p| { + p.to_string_lossy() + .to_string() + .replace(&dirs::HOME.to_string_lossy().to_string(), "~") + }) + .collect::>(); writeln!(f, "Config:")?; - writeln!(f, " Installed Plugins:")?; - for plugin in self.ts.list_installed_plugins() { - writeln!(f, " {}", plugin.name)?; - } - writeln!(f, " Active Versions:")?; - for rtv in self.ts.list_current_versions() { - writeln!(f, " {rtv}")?; - } - Ok(()) + writeln!(f, " Files: {}", config_files.join(", "))?; + writeln!(f, " Installed Plugins: {}", plugins.join(", "))?; + write!(f, " Active Versions: {}", versions.join(", ")) } } diff --git a/src/env.rs b/src/env.rs index 152c3b22f..010d289c4 100644 --- a/src/env.rs +++ b/src/env.rs @@ -4,6 +4,7 @@ use std::ffi::OsString; use std::path::PathBuf; use lazy_static::lazy_static; +use log::LevelFilter; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; @@ -52,12 +53,8 @@ lazy_static! { pub static ref RTX_EXE: PathBuf = current_exe().unwrap_or_else(|_| "rtx".into()); pub static ref RTX_LOG_LEVEL: log::LevelFilter = { let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); - match log_level.as_str() { - "trace" => log::LevelFilter::Trace, - "debug" => log::LevelFilter::Debug, - "info" => log::LevelFilter::Info, - "warn" => log::LevelFilter::Warn, - "error" => log::LevelFilter::Error, + match log_level.parse::() { + Ok(level) => level, _ => { if *RTX_TRACE { log::LevelFilter::Trace @@ -71,6 +68,13 @@ lazy_static! { } } }; + pub static ref RTX_LOG_FILE_LEVEL: log::LevelFilter = { + let log_level = var("RTX_LOG_FILE_LEVEL").unwrap_or_default(); + match log_level.parse::() { + Ok(level) => level, + _ => *RTX_LOG_LEVEL, + } + }; pub static ref RTX_MISSING_RUNTIME_BEHAVIOR: Option = if cfg!(test) { Some("autoinstall".into()) } else { diff --git a/src/logger.rs b/src/logger.rs index c2c930e80..19738c1b5 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -7,13 +7,13 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use simplelog::*; -pub fn init(log_level: LevelFilter) { +pub fn init(log_level: LevelFilter, log_file_level: LevelFilter) { let mut loggers: Vec> = vec![]; loggers.push(init_term_logger(log_level)); if let Ok(log) = env::var("RTX_LOG_FILE") { let log_file = PathBuf::from(log); - if let Some(logger) = init_write_logger(log_level, log_file) { + if let Some(logger) = init_write_logger(log_file_level, log_file) { loggers.push(logger) } } @@ -50,7 +50,7 @@ fn init_write_logger(level: LevelFilter, log_path: PathBuf) -> Option Some(WriteLogger::new( level, ConfigBuilder::new() - .set_thread_level(LevelFilter::Off) + .set_thread_level(LevelFilter::Trace) .build(), log_file, )), @@ -68,6 +68,6 @@ mod tests { #[test] fn test_init() { - init(LevelFilter::Debug); + init(LevelFilter::Debug, LevelFilter::Debug); } } diff --git a/src/main.rs b/src/main.rs index 764635487..72e2c1129 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,7 @@ fn main() -> Result<()> { color_eyre::install()?; let log_level = *env::RTX_LOG_LEVEL; - logger::init(log_level); + logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); let config = Config::load()?; if hook_env::should_exit_early(&config) { return Ok(()); From 1e92a3028bdf61f15a3447b38131f8b33b9b8ecb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 13:51:19 -0600 Subject: [PATCH 0079/1891] [bug] direnv activate bug (#73) --- .../rtx-direnv-break-path-source/.envrc | 1 + .../rtx-direnv-break-path-target/.envrc | 1 + e2e/direnv/no_tool_versions/test_direnv | 25 +++++++++++++++++++ e2e/run_all_tests | 17 +++---------- e2e/run_test | 17 +++++++++++++ src/cli/hook_env.rs | 17 ++++++++++--- src/direnv.rs | 24 ++++++++++++++++-- .../rtx__direnv__test__null_path-2.snap | 5 ++++ .../rtx__direnv__test__null_path.snap | 5 ++++ 9 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc create mode 100644 e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc create mode 100755 e2e/direnv/no_tool_versions/test_direnv create mode 100755 e2e/run_test create mode 100644 src/snapshots/rtx__direnv__test__null_path-2.snap create mode 100644 src/snapshots/rtx__direnv__test__null_path.snap diff --git a/e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc b/e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc new file mode 100644 index 000000000..c78c44709 --- /dev/null +++ b/e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc @@ -0,0 +1 @@ +export FOO=foo diff --git a/e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc b/e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc new file mode 100644 index 000000000..29bcb5abe --- /dev/null +++ b/e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc @@ -0,0 +1 @@ +export FOO=bar diff --git a/e2e/direnv/no_tool_versions/test_direnv b/e2e/direnv/no_tool_versions/test_direnv new file mode 100755 index 000000000..a8cef4aca --- /dev/null +++ b/e2e/direnv/no_tool_versions/test_direnv @@ -0,0 +1,25 @@ +#!/usr/bin/env zsh + +set -e + +eval "$(direnv hook zsh)" +eval "$(rtx activate -s zsh)" +_rtx_hook && _direnv_hook + +assert_go_version() { + local expected="$1" + if [[ "$GOPATH" != "$expected" ]]; then + echo "Invalid GOPATH: $GOPATH, expected: $expected" + exit 1 + fi +} + +rtx i golang@1.18.10 golang@1.19.5 && _rtx_hook +#assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" +cd rtx-direnv-break-path-source && _rtx_hook +direnv allow && _direnv_hook +#assert_gopath "$RTX_DATA_DIR/installs/golang/1.18.10/packages" +cd ../rtx-direnv-break-path-target && _rtx_hook +direnv allow && _direnv_hook +#assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" +rtx -v # should not fail, the bug is that PATH gets set to a junk value and this does not work diff --git a/e2e/run_all_tests b/e2e/run_all_tests index 777066559..ca5673676 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -1,21 +1,10 @@ #!/usr/bin/env bash set -euo pipefail -export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" -export RTX_DATA_DIR="/tmp/rtx" -export PATH="$PWD/target/debug:$PATH" -unset GOPATH - -rtx plugin add nodejs -rtx plugin add shfmt - ROOT="$PWD" FILES=$(find e2e -name 'test_*' -type f) for f in $FILES; do - echo "Running $f" - cd "$(dirname "$f")" - "./$(basename "$f")" - cd "$ROOT" - rm -f "$ROOT/e2e/.tool-versions" - git checkout "$ROOT/.tool-versions" + "$ROOT/e2e/run_test" "$f" + rm -f "$ROOT/e2e/.tool-versions" + git checkout "$ROOT/.tool-versions" done diff --git a/e2e/run_test b/e2e/run_test new file mode 100755 index 000000000..efc1397f6 --- /dev/null +++ b/e2e/run_test @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" +export RTX_DATA_DIR="/tmp/rtx" +#export PATH="$PWD/target/debug:$PATH" +unset GOPATH + +ROOT="$PWD" + +TEST="$1" +echo "Running $TEST" +cd "$(dirname "$TEST")" +"./$(basename "$TEST")" + +rm -f "$ROOT/e2e/.tool-versions" +git checkout "$ROOT/.tool-versions" diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index af43f6c66..dc4b4f971 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -101,10 +101,11 @@ impl HookEnv { if let Some(input) = env::DIRENV_DIFF.deref() { match self.update_direnv_diff(input, &installs) { - Ok(op) => { + Ok(Some(op)) => { ops.push(op); } Err(err) => warn!("failed to update DIRENV_DIFF: {}", err), + _ => {} } } @@ -114,13 +115,23 @@ impl HookEnv { /// inserts install path to DIRENV_DIFF both for old and new /// this makes direnv think that these paths were added before it ran /// that way direnv will not remove the path when it runs the next time - fn update_direnv_diff(&self, input: &str, installs: &Vec) -> Result { + fn update_direnv_diff( + &self, + input: &str, + installs: &Vec, + ) -> Result> { let mut diff = DirenvDiff::parse(input)?; + if diff.new_path().is_empty() { + return Ok(None); + } for install in installs { diff.add_path_to_old_and_new(install)?; } - Ok(EnvDiffOperation::Change("DIRENV_DIFF".into(), diff.dump()?)) + Ok(Some(EnvDiffOperation::Change( + "DIRENV_DIFF".into(), + diff.dump()?, + ))) } fn build_diff_operation(&self, diff: &EnvDiff) -> Result { diff --git a/src/direnv.rs b/src/direnv.rs index 612737271..f27378eb6 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -32,11 +32,19 @@ impl DirenvDiff { } pub fn new_path(&self) -> Vec { - split_paths(&self.new.get("PATH").cloned().unwrap_or_default()).collect() + let path = self.new.get("PATH"); + match path { + Some(path) => split_paths(path).collect(), + None => vec![], + } } pub fn old_path(&self) -> Vec { - split_paths(&self.old.get("PATH").cloned().unwrap_or_default()).collect() + let path = self.old.get("PATH"); + match path { + Some(path) => split_paths(path).collect(), + None => vec![], + } } /// this adds a directory to both the old and new path in DIRENV_DIFF @@ -120,4 +128,16 @@ mod test { assert_display_snapshot!(diff.old.get("PATH").unwrap()); assert_display_snapshot!(diff.new.get("PATH").unwrap()); } + + #[test] + fn test_null_path() { + let mut diff = DirenvDiff { + old: HashMap::from([]), + new: HashMap::from([]), + }; + let path = PathBuf::from("/tmp"); + diff.add_path_to_old_and_new(&path).unwrap(); + assert_display_snapshot!(diff.old.get("PATH").unwrap()); + assert_display_snapshot!(diff.new.get("PATH").unwrap()); + } } diff --git a/src/snapshots/rtx__direnv__test__null_path-2.snap b/src/snapshots/rtx__direnv__test__null_path-2.snap new file mode 100644 index 000000000..f05c7b4e5 --- /dev/null +++ b/src/snapshots/rtx__direnv__test__null_path-2.snap @@ -0,0 +1,5 @@ +--- +source: src/direnv.rs +expression: "diff.new.get(\"PATH\").unwrap()" +--- +/tmp diff --git a/src/snapshots/rtx__direnv__test__null_path.snap b/src/snapshots/rtx__direnv__test__null_path.snap new file mode 100644 index 000000000..a8c057a3a --- /dev/null +++ b/src/snapshots/rtx__direnv__test__null_path.snap @@ -0,0 +1,5 @@ +--- +source: src/direnv.rs +expression: "diff.old.get(\"PATH\").unwrap()" +--- +/tmp From dadc61e58d01481f9d6ea3c2f0d1d8ce9c37edca Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 14:05:41 -0600 Subject: [PATCH 0080/1891] [docs] direnv --- README.md | 31 +++++++++++++++++++++---------- src/cli/render_help.rs | 31 +++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index af694b3e2..28b5b7f72 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,6 @@ $ echo 'eval "$(~/bin/rtx activate -s zsh)"' >> ~/.zshrc $ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` -> **Warning** -> [We're working to make `rtx activate` not conflict with direnv.](https://github.com/jdxcode/rtx/issues/8) -> Hopefully soon you'll be able to use `rtx activate` with direnv. -> If you use direnv, [see below](#direnv) for direnv-compatible setup that does not require `rtx activate`. - Install a runtime and set it as the default: ```sh-session @@ -1282,11 +1277,14 @@ were very good. I really just have 2 complaints: the shims and the fact it's wri ## direnv [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze -the current environment variables before and after their respective "hook" commands are run, they -can easily conflict and overwrite each other's environment variables (including, but not limited to, `PATH`). +the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. -To avoid this, **don't** use `rtx activate` alongside direnv. Instead, call rtx from _within_ direnv -so that it can track the environment variables separately. +There were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). +However, these _should_ be resolved now and you should be able to use direnv alongside +rtx. + +If you do encounter issues, or just want to use direnv in an alternate way: there +is a method of calling rtx from within direnv so you do not need to run `rtx activate`. This is a simpler setup that's less likely to cause issues. To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: @@ -1302,7 +1300,20 @@ use rtx ``` direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` -too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). +too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. + +Note that in this method direnv typically won't know to refresh `.tool-version` files +unless they're at the same level at a `.envrc` file. You'll likely always want to have +a `.envrc` file next to your `.tool-versions` for this reason. To make this a little +easier to manage, I encourage _not_ actually using `.tool-versions` and instead +setting environment variables entirely in `.envrc`: + +``` +export RTX_NODEJS_VERSION=18.0.0 +export RTX_PYTHON_VERSION=3.11 +``` + +Of course if you use `rtx activate` none of this is necesary. ## Cache Behavior diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index eaa096bb5..61b8ac843 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -45,11 +45,6 @@ $ echo 'eval "$(~/bin/rtx activate -s zsh)"' >> ~/.zshrc $ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish ``` -> **Warning** -> [We're working to make `rtx activate` not conflict with direnv.](https://github.com/jdxcode/rtx/issues/8) -> Hopefully soon you'll be able to use `rtx activate` with direnv. -> If you use direnv, [see below](#direnv) for direnv-compatible setup that does not require `rtx activate`. - Install a runtime and set it as the default: ```sh-session @@ -587,11 +582,14 @@ were very good. I really just have 2 complaints: the shims and the fact it's wri ## direnv [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze -the current environment variables before and after their respective "hook" commands are run, they -can easily conflict and overwrite each other's environment variables (including, but not limited to, `PATH`). +the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. -To avoid this, **don't** use `rtx activate` alongside direnv. Instead, call rtx from _within_ direnv -so that it can track the environment variables separately. +There were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). +However, these _should_ be resolved now and you should be able to use direnv alongside +rtx. + +If you do encounter issues, or just want to use direnv in an alternate way: there +is a method of calling rtx from within direnv so you do not need to run `rtx activate`. This is a simpler setup that's less likely to cause issues. To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: @@ -607,7 +605,20 @@ use rtx ``` direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` -too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). +too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. + +Note that in this method direnv typically won't know to refresh `.tool-version` files +unless they're at the same level at a `.envrc` file. You'll likely always want to have +a `.envrc` file next to your `.tool-versions` for this reason. To make this a little +easier to manage, I encourage _not_ actually using `.tool-versions` and instead +setting environment variables entirely in `.envrc`: + +``` +export RTX_NODEJS_VERSION=18.0.0 +export RTX_PYTHON_VERSION=3.11 +``` + +Of course if you use `rtx activate` none of this is necesary. ## Cache Behavior From 40adb49d9073018426237f333972aee61f51c01a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 14:27:31 -0600 Subject: [PATCH 0081/1891] [feat] added global --verbose flag (#75) --- Cargo.lock | 59 +++++--------- Cargo.toml | 10 +-- README.md | 15 +++- completions/_rtx | 76 ++++++++++++++++++- completions/rtx.bash | 72 +++++++++--------- completions/rtx.fish | 38 +++++++++- src/cli/args/log_level.rs | 25 ++---- src/cli/args/mod.rs | 1 + src/cli/args/verbose.rs | 15 ++++ src/cli/asdf.rs | 2 +- src/cli/install.rs | 32 +++----- src/cli/mod.rs | 12 ++- src/cli/plugins/install.rs | 8 +- src/cli/render_help.rs | 8 ++ src/cli/settings/set.rs | 4 +- ..._cli__settings__ls__test__settings_ls.snap | 1 + ...__settings__set__test__settings_set-2.snap | 11 --- ...li__settings__set__test__settings_set.snap | 9 ++- src/cli/settings/unset.rs | 11 +-- src/cli/version.rs | 2 +- src/config/config_file/rtxrc.rs | 1 + src/config/settings.rs | 16 ++-- src/env.rs | 15 +++- src/main.rs | 2 +- src/plugins/mod.rs | 23 ++---- src/runtimes/mod.rs | 10 +-- src/test.rs | 1 + src/ui/color.rs | 2 +- src/ui/mod.rs | 1 + src/ui/spinner.rs | 29 +++++++ test/config/config.toml | 1 + 31 files changed, 319 insertions(+), 193 deletions(-) create mode 100644 src/cli/args/verbose.rs delete mode 100644 src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap create mode 100644 src/ui/spinner.rs diff --git a/Cargo.lock b/Cargo.lock index ddb80323c..3760fb881 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,17 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + [[package]] name = "console" version = "0.15.5" @@ -708,12 +719,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "memchr" version = "2.5.0" @@ -1054,7 +1059,7 @@ dependencies = [ "serde_json", "shell-escape", "simplelog", - "spinners-jdxcode", + "spinoff", "tempfile", "thiserror", "toml", @@ -1083,12 +1088,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "rustversion" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" - [[package]] name = "ryu" version = "1.0.12" @@ -1188,14 +1187,14 @@ dependencies = [ ] [[package]] -name = "spinners-jdxcode" -version = "4.1.0" +name = "spinoff" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bbd00662c4720cbae51a6743924e83c81ea3ef7e80fc991a537988ee0da3bf" +checksum = "fee259f96b31e7a18657d11741fe30d63f98e07de70e7a19d2b705ab9b331cdc" dependencies = [ - "lazy_static", - "maplit", - "strum", + "colored", + "once_cell", + "paste", ] [[package]] @@ -1204,28 +1203,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - [[package]] name = "supports-color" version = "1.3.1" diff --git a/Cargo.toml b/Cargo.toml index f15586b32..cb530b46e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ atty = "0.2.14" base64 = "0.21.0" build-time = "0.1.2" chrono = "0.4.23" -clap = { version = "4.1.1", features = ["derive", "string"] } +clap = { version = "4.1.1", features = ["env", "derive", "string"] } clap_complete = "4.1.1" color-eyre = "0.6.2" ctor = "0.1.26" @@ -53,7 +53,7 @@ serde_derive = "1.0.152" serde_json = "1.0.91" shell-escape = "0.1.5" simplelog = { version = "0.12.0", features = ["paris"] } -spinners-jdxcode = "4.1.0" +spinoff = "0.7.0" thiserror = "1.0.38" toml = "0.7.0" toml_edit = "0.19.0" @@ -64,12 +64,12 @@ versions = "4.1.0" exec = "0.3.1" [dev-dependencies] -pretty_assertions = "1.3.0" +env_logger = "0.10.0" insta = "1.26.0" +pretty_assertions = "1.3.0" tempfile = "3.3.0" -env_logger = "0.10.0" -[profile.release] +#[profile.release] #opt-level = "z" # optimize for size #lto = true #debug = false diff --git a/README.md b/README.md index 28b5b7f72..e83722911 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,8 @@ plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable u # e.g.: nodejs -> https://github.com/asdf-vm/asdf-nodejs.git plugin_repository_last_check_duration = 10080 # (one week) set to 0 to disable updates +verbose = false # see explanation under `RTX_VERBOSE` + # disables the short name repository (described above) disable_plugin_short_name_repository = false @@ -388,6 +390,12 @@ Output logs to a file. Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want to store the logs but not have them litter your display. +#### `RTX_VERBOSE=1` + +This shows the installation output during `rtx install` and `rtx plugin install`. +This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have +2 configuration for the same thing, but for now it is it's own config. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS @@ -772,8 +780,8 @@ Options: -a, --all install all missing runtimes as well as all plugins for the current directory - -v, --verbose - show installation output + -v, --verbose... + Show installation output -h, --help Print help (see a summary with '-h') @@ -946,6 +954,9 @@ Options: This will only install plugins that have matching shortnames. i.e.: they don't need the full git repo url + -v, --verbose... + Show installation output + -h, --help Print help (see a summary with '-h') diff --git a/completions/_rtx b/completions/_rtx index 1b150bf6c..6c47e306c 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -16,6 +16,8 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '-V[Print version]' \ @@ -36,6 +38,8 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-q[Hide the "rtx: @" message when changing directories]' \ '--quiet[Hide the "rtx: @" message when changing directories]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -45,6 +49,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help]' \ '--help[Print help]' \ ":: :_rtx__alias_commands" \ @@ -62,6 +68,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -97,6 +105,8 @@ esac (asdf) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help]' \ '--help[Print help]' \ '*::args -- all arguments:' \ @@ -107,6 +117,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -114,6 +126,8 @@ _arguments "${_arguments_options[@]}" \ (current) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::plugin -- plugin to show versions of:' \ @@ -124,6 +138,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type to generate the script for]:SHELL:(bash fish zsh)' \ '--shell=[shell type to generate the script for]:SHELL:(bash fish zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -131,6 +147,8 @@ _arguments "${_arguments_options[@]}" \ (direnv) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ":: :_rtx__direnv_commands" \ @@ -146,6 +164,8 @@ _arguments "${_arguments_options[@]}" \ (envrc) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -153,6 +173,8 @@ _arguments "${_arguments_options[@]}" \ (exec) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -160,6 +182,8 @@ _arguments "${_arguments_options[@]}" \ (activate) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -203,6 +227,8 @@ esac (doctor) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -212,6 +238,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- runtime version to use:' \ @@ -222,6 +250,8 @@ _arguments "${_arguments_options[@]}" \ '()-c+[the command string to execute]:C: ' \ '()--command=[the command string to execute]:C: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- runtime(s) to start:' \ @@ -233,6 +263,8 @@ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--fuzzy[save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0`]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- runtimes:' \ @@ -243,6 +275,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -256,8 +290,8 @@ _arguments "${_arguments_options[@]}" \ '--force[force reinstall even if already installed]' \ '(-p --plugin -f --force)-a[install all missing runtimes as well as all plugins for the current directory]' \ '(-p --plugin -f --force)--all[install all missing runtimes as well as all plugins for the current directory]' \ -'-v[show installation output]' \ -'--verbose[show installation output]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- runtime(s) to install:' \ @@ -266,6 +300,8 @@ _arguments "${_arguments_options[@]}" \ (latest) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':runtime -- Runtime to get the latest version of:' \ @@ -279,6 +315,8 @@ _arguments "${_arguments_options[@]}" \ '-p[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--parent[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--fuzzy[save fuzzy match to .tool-versions e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions by default it would save the exact version, e.g.: `nodejs 20.0.0`]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- runtimes to add to .tool-versions:' \ @@ -291,6 +329,8 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -298,6 +338,8 @@ _arguments "${_arguments_options[@]}" \ (ls-remote) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':plugin -- Plugin:' \ @@ -310,6 +352,8 @@ _arguments "${_arguments_options[@]}" \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ":: :_rtx__plugins_commands" \ @@ -329,6 +373,8 @@ _arguments "${_arguments_options[@]}" \ '--force[Reinstall even if plugin exists]' \ '(-f --force)-a[Install all missing plugins]' \ '(-f --force)--all[Install all missing plugins]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::name -- The name of the plugin to install:' \ @@ -342,6 +388,8 @@ _arguments "${_arguments_options[@]}" \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -351,6 +399,8 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -358,6 +408,8 @@ _arguments "${_arguments_options[@]}" \ (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':plugin -- plugin to remove:' \ @@ -368,6 +420,8 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '()-a[update all plugins]' \ '()--all[update all plugins]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::plugin -- plugin(s) to update:' \ @@ -420,6 +474,8 @@ esac (settings) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help]' \ '--help[Print help]' \ ":: :_rtx__settings_commands" \ @@ -435,6 +491,8 @@ _arguments "${_arguments_options[@]}" \ (get) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':key -- The setting to show:' \ @@ -443,6 +501,8 @@ _arguments "${_arguments_options[@]}" \ (ls) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -450,6 +510,8 @@ _arguments "${_arguments_options[@]}" \ (set) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':key -- The setting to set:' \ @@ -459,6 +521,8 @@ _arguments "${_arguments_options[@]}" \ (unset) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':key -- The setting to remove:' \ @@ -507,6 +571,8 @@ esac (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- runtime(s) to remove:' \ @@ -515,6 +581,8 @@ _arguments "${_arguments_options[@]}" \ (version) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -522,6 +590,8 @@ _arguments "${_arguments_options[@]}" \ (where) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':runtime -- runtime(s) to remove:' \ @@ -531,6 +601,8 @@ _arguments "${_arguments_options[@]}" \ (render-help) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 diff --git a/completions/rtx.bash b/completions/rtx.bash index d2e95e56d..0ca3d2978 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -367,7 +367,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-h -V --log-level --help --version activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="-v -h -V --log-level --verbose --help --version activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -385,7 +385,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -h --shell --quiet --log-level --help" + opts="-s -q -v -h --shell --quiet --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -411,7 +411,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -h --plugin --log-level --help ls help" + opts="-p -v -h --plugin --log-level --verbose --help ls help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -479,7 +479,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -h --plugin --log-level --help" + opts="-p -v -h --plugin --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -505,7 +505,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-h --log-level --help [ARGS]..." + opts="-v -h --log-level --verbose --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -523,7 +523,7 @@ _rtx() { return 0 ;; rtx__complete) - opts="-s -h --shell --log-level --help" + opts="-s -v -h --shell --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -549,7 +549,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-h --log-level --help [PLUGIN]" + opts="-v -h --log-level --verbose --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -567,7 +567,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-s -h --shell --log-level --help" + opts="-s -v -h --shell --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -593,7 +593,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-h --log-level --help envrc exec activate help" + opts="-v -h --log-level --verbose --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -611,7 +611,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-h --log-level --help" + opts="-v -h --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -629,7 +629,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-h --log-level --help" + opts="-v -h --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -647,7 +647,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-h --log-level --help" + opts="-v -h --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -735,7 +735,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-h --log-level --help" + opts="-v -h --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -753,7 +753,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -h --shell --log-level --help [RUNTIME]..." + opts="-s -v -h --shell --log-level --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -779,7 +779,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -h --command --log-level --help [RUNTIME]... [COMMAND]..." + opts="-c -v -h --command --log-level --verbose --help [RUNTIME]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -805,7 +805,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-h --fuzzy --remove --log-level --help [RUNTIME]..." + opts="-v -h --fuzzy --remove --log-level --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1359,7 +1359,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -h --shell --log-level --help" + opts="-s -v -h --shell --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1411,7 +1411,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-h --log-level --help [ASDF_VERSION]" + opts="-v -h --log-level --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1429,7 +1429,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -h --parent --fuzzy --remove --log-level --help [RUNTIME]..." + opts="-p -v -h --parent --fuzzy --remove --log-level --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1451,7 +1451,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -h --plugin --current --log-level --help" + opts="-p -c -v -h --plugin --current --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1477,7 +1477,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-h --log-level --help " + opts="-v -h --log-level --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1495,7 +1495,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -u -h --all --urls --log-level --help install ls ls-remote uninstall update help" + opts="-a -u -v -h --all --urls --log-level --verbose --help install ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1611,7 +1611,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -h --force --all --log-level --help [NAME] [GIT_URL]" + opts="-f -a -v -h --force --all --verbose --log-level --help [NAME] [GIT_URL]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1629,7 +1629,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -u -h --all --urls --log-level --help" + opts="-a -u -v -h --all --urls --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1647,7 +1647,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -h --urls --log-level --help" + opts="-u -v -h --urls --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1665,7 +1665,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-h --log-level --help " + opts="-v -h --log-level --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1683,7 +1683,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -h --all --log-level --help [PLUGIN]..." + opts="-a -v -h --all --log-level --verbose --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1701,7 +1701,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-h --log-level --help" + opts="-v -h --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1719,7 +1719,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-h --log-level --help get ls set unset help" + opts="-v -h --log-level --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1737,7 +1737,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-h --log-level --help " + opts="-v -h --log-level --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1839,7 +1839,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-h --log-level --help" + opts="-v -h --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1857,7 +1857,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-h --log-level --help " + opts="-v -h --log-level --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1875,7 +1875,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-h --log-level --help " + opts="-v -h --log-level --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1893,7 +1893,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-h --log-level --help ..." + opts="-v -h --log-level --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1911,7 +1911,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-h --log-level --help" + opts="-v -h --log-level --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1929,7 +1929,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-h --log-level --help [ASDF_VERSION]" + opts="-v -h --log-level --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 107112e05..9066b1f96 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,4 +1,5 @@ complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' @@ -28,9 +29,11 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message o complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'Hide the "rtx: @" message when changing directories' +complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. @@ -38,22 +41,28 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file for direnv to consume.' @@ -62,10 +71,13 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file for direnv to consume.' @@ -74,42 +86,52 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'the command string to execute' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0`' +complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'install all missing runtimes as well as all plugins for the current directory' -complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'show installation output' +complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'save fuzzy match to .tool-versions e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions by default it would save the exact version, e.g.: `nodejs 20.0.0`' +complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' @@ -120,18 +142,23 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'update all plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' @@ -140,6 +167,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' @@ -147,12 +175,16 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' @@ -160,12 +192,16 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' diff --git a/src/cli/args/log_level.rs b/src/cli/args/log_level.rs index 35d4963c3..5e07857f2 100644 --- a/src/cli/args/log_level.rs +++ b/src/cli/args/log_level.rs @@ -1,27 +1,15 @@ use clap::builder::ValueParser; use clap::Arg; -use color_eyre::eyre::eyre; -use color_eyre::eyre::Result; -use lazy_static::lazy_static; -use log::LevelFilter; +use log::{LevelFilter, ParseLevelError}; +use once_cell::sync::Lazy; use crate::env; #[derive(Clone)] pub struct LogLevel(pub LevelFilter); -fn parse_log_level(input: &str) -> Result { - match input { - "trace" => Ok(LevelFilter::Trace), - "debug" => Ok(LevelFilter::Debug), - "info" => Ok(LevelFilter::Info), - "warn" => Ok(LevelFilter::Warn), - "error" => Ok(LevelFilter::Error), - _ => Err(eyre!( - "invalid log level: {}\nvalid input: trace, debug, info, warn, error", - input - )), - } +fn parse_log_level(input: &str) -> core::result::Result { + input.parse::() } impl LogLevel { @@ -37,6 +25,5 @@ impl LogLevel { } } -lazy_static! { - pub static ref DEFAULT_LOG_LEVEL: String = env::RTX_LOG_LEVEL.to_string().to_lowercase(); -} +pub static DEFAULT_LOG_LEVEL: Lazy = + Lazy::new(|| env::RTX_LOG_LEVEL.to_string().to_lowercase()); diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index 58d685bae..4c84098b1 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,2 +1,3 @@ pub mod log_level; pub mod runtime; +pub mod verbose; diff --git a/src/cli/args/verbose.rs b/src/cli/args/verbose.rs new file mode 100644 index 000000000..8ca0defc0 --- /dev/null +++ b/src/cli/args/verbose.rs @@ -0,0 +1,15 @@ +use clap::{Arg, ArgAction}; + +#[derive(Clone)] +pub struct Verbose(pub u8); + +impl Verbose { + pub fn arg() -> clap::Arg { + Arg::new("verbose") + .short('v') + .long("verbose") + .help("Show installation output") + .global(true) + .action(ArgAction::Count) + } +} diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 07d508679..f694ec387 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -68,7 +68,7 @@ mod test { #[test] fn test_fake_asdf() { - let stdout = assert_cli!("asdf", "-v"); + let stdout = assert_cli!("asdf", "version"); assert_str_eq!(stdout, VERSION.to_string() + "\n"); } diff --git a/src/cli/install.rs b/src/cli/install.rs index 5b13ab4ba..29b1b2afb 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use atty::Stream::Stderr; use color_eyre::eyre::Result; use owo_colors::Stream; -use spinners_jdxcode::{Spinner, Spinners}; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -15,7 +14,8 @@ use crate::output::Output; use crate::plugins::InstallType::Version; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; -use crate::ui::color::{bright_green, cyan}; +use crate::ui::color::cyan; +use crate::ui::spinner::Spinner; /// install a runtime /// @@ -44,9 +44,9 @@ pub struct Install { #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"])] all: bool, - /// show installation output - #[clap(long, short)] - verbose: bool, + /// Show installation output + #[clap(long, short, action = clap::ArgAction::Count)] + verbose: u8, } impl Command for Install { @@ -135,26 +135,12 @@ impl Install { Ok(()) } - fn do_install(&self, config: &Config, out: &mut Output, rtv: &RuntimeVersion) -> Result<()> { + fn do_install(&self, config: &Config, _out: &mut Output, rtv: &RuntimeVersion) -> Result<()> { let rtv_label = cyan(Stderr, &rtv.to_string()); let install_message = format!("Installing runtime: {rtv_label}..."); - let sp = if self.verbose { - rtxstatusln!(out, "{install_message}"); - None - } else { - Some(Spinner::with_stream( - Spinners::Dots10, - install_message, - spinners_jdxcode::Stream::Stderr, - )) - }; - rtv.install(Version, config, self.verbose)?; - if let Some(mut sp) = sp { - sp.stop_and_persist( - &bright_green(Stderr, "âś”"), - format!("Runtime {rtv_label} installed"), - ); - } + let mut sp = Spinner::start(install_message, config.settings.verbose); + rtv.install(Version, config)?; + sp.success(format!("Runtime {rtv_label} installed")); Ok(()) } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b0250f790..ed137b5c9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -129,7 +129,8 @@ impl Cli { .subcommand_required(true) .after_help(AFTER_HELP) .color(ColorChoice::Never) - .arg(args::log_level::LogLevel::arg()), + .arg(args::log_level::LogLevel::arg()) + .arg(args::verbose::Verbose::arg()), ) } @@ -139,9 +140,16 @@ impl Cli { *matches.get_one::("log-level").unwrap() } - pub fn run(self, config: Config, args: &Vec, out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config, args: &Vec, out: &mut Output) -> Result<()> { debug!("{}", &args.join(" ")); + if args[1..] == ["-v"] { + // normally this would be considered --verbose + return version::Version {}.run(config, out); + } let matches = self.command.get_matches_from(args); + if *matches.get_one::("verbose").unwrap() > 0 { + config.settings.verbose = true; + } if let Some((command, sub_m)) = matches.subcommand() { external::execute(&config, command, sub_m, self.external_commands)?; } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index e62314375..d42e949da 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -40,6 +40,10 @@ pub struct PluginsInstall { /// i.e.: they don't need the full git repo url #[clap(short, long, conflicts_with_all = ["name", "force"])] all: bool, + + /// Show installation output + #[clap(long, short, action = clap::ArgAction::Count)] + verbose: u8, } impl Command for PluginsInstall { @@ -55,7 +59,7 @@ impl Command for PluginsInstall { if !self.force && plugin.is_installed() { warn!("plugin {} already installed", name); } else { - plugin.install(&git_url)?; + plugin.install(&config.settings, &git_url)?; } Ok(()) @@ -70,7 +74,7 @@ impl PluginsInstall { } for plugin in missing_plugins { let (_, git_url) = get_name_and_url(config, plugin.name.clone(), None)?; - plugin.install(&git_url)?; + plugin.install(&config.settings, &git_url)?; } Ok(()) } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 61b8ac843..caa9b162e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -346,6 +346,8 @@ plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable u # e.g.: nodejs -> https://github.com/asdf-vm/asdf-nodejs.git plugin_repository_last_check_duration = 10080 # (one week) set to 0 to disable updates +verbose = false # see explanation under `RTX_VERBOSE` + # disables the short name repository (described above) disable_plugin_short_name_repository = false @@ -406,6 +408,12 @@ Output logs to a file. Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want to store the logs but not have them litter your display. +#### `RTX_VERBOSE=1` + +This shows the installation output during `rtx install` and `rtx plugin install`. +This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have +2 configuration for the same thing, but for now it is it's own config. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 9057941c4..df3ec9320 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -28,6 +28,7 @@ impl Command for SettingsSet { "disable_plugin_short_name_repository" => parse_bool(&self.value)?, "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, "plugin_repository_last_check_duration" => parse_i64(&self.value)?, + "verbose" => parse_bool(&self.value)?, _ => return Err(eyre!("Unknown setting: {}", self.key)), }; @@ -67,9 +68,6 @@ pub mod test { #[test] fn test_settings_set() { reset_config(); - let stdout = assert_cli!("settings"); - assert_snapshot!(stdout); - assert_cli!("settings", "set", "missing_runtime_behavior", "warn"); assert_cli!("settings", "set", "legacy_version_file", "false"); assert_cli!("settings", "set", "always_keep_download", "true"); diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap index d5212f3ba..1162ee017 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap @@ -8,4 +8,5 @@ legacy_version_file = true disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 plugin_repository_last_check_duration = 20 +verbose = true diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap deleted file mode 100644 index 5ff92839e..000000000 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set-2.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: src/cli/settings/set.rs -expression: stdout ---- -missing_runtime_behavior = autoinstall -always_keep_download = true -legacy_version_file = false -disable_plugin_short_name_repository = true -plugin_autoupdate_last_check_duration = 1 -plugin_repository_last_check_duration = 2 - diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap index 5637d9bd5..6d32a0db1 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap @@ -4,8 +4,9 @@ expression: stdout --- missing_runtime_behavior = autoinstall always_keep_download = true -legacy_version_file = true -disable_plugin_short_name_repository = false -plugin_autoupdate_last_check_duration = 20 -plugin_repository_last_check_duration = 20 +legacy_version_file = false +disable_plugin_short_name_repository = true +plugin_autoupdate_last_check_duration = 1 +plugin_repository_last_check_duration = 2 +verbose = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index ea6708d91..b72a661ba 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -41,16 +41,6 @@ mod test { fn test_settings_unset() { reset_config(); - let stdout = assert_cli!("settings"); - assert_snapshot!(stdout, @r###" - missing_runtime_behavior = autoinstall - always_keep_download = true - legacy_version_file = true - disable_plugin_short_name_repository = false - plugin_autoupdate_last_check_duration = 20 - plugin_repository_last_check_duration = 20 - "###); - assert_cli!("settings", "unset", "legacy_version_file"); let stdout = assert_cli!("settings"); @@ -61,6 +51,7 @@ mod test { disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 plugin_repository_last_check_duration = 20 + verbose = true "###); reset_config(); diff --git a/src/cli/version.rs b/src/cli/version.rs index 80e2bd6cf..79f0da97e 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -7,7 +7,7 @@ use crate::config::Config; use crate::output::Output; #[derive(Debug, clap::Args)] -#[clap(about = "Show rtx version", alias = "-v", alias = "v")] +#[clap(about = "Show rtx version", alias = "v")] pub struct Version {} lazy_static! { diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 67f57fec4..d8365c1f7 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -100,6 +100,7 @@ impl RTXFile { "disable_plugin_short_name_repository" => { self.settings.disable_plugin_short_name_repository = Some(self.parse_bool(k, v)?) } + "verbose" => self.settings.verbose = Some(self.parse_bool(k, v)?), "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} _ => self.parse_plugin(k, v)?, diff --git a/src/config/settings.rs b/src/config/settings.rs index c0cf9710b..e917348c9 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -6,6 +6,7 @@ use indexmap::IndexMap; use crate::config::AliasMap; use crate::env; use crate::plugins::PluginName; +use crate::ui::prompt::is_tty; #[derive(Debug, Clone)] pub struct Settings { @@ -16,6 +17,7 @@ pub struct Settings { pub plugin_autoupdate_last_check_duration: Duration, pub plugin_repository_last_check_duration: Duration, pub aliases: IndexMap>, + pub verbose: bool, } impl Default for Settings { @@ -28,6 +30,7 @@ impl Default for Settings { plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), plugin_repository_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), aliases: IndexMap::new(), + verbose: !is_tty(), } } } @@ -59,6 +62,7 @@ impl Settings { "plugin_repository_last_check_duration".to_string(), (self.plugin_repository_last_check_duration.as_secs() / 60).to_string(), ); + map.insert("verbose".into(), self.verbose.to_string()); map } } @@ -72,6 +76,7 @@ pub struct SettingsBuilder { pub plugin_autoupdate_last_check_duration: Option, pub plugin_repository_last_check_duration: Option, pub aliases: Option, + pub verbose: Option, } impl SettingsBuilder { @@ -102,6 +107,9 @@ impl SettingsBuilder { self.plugin_repository_last_check_duration = other.plugin_repository_last_check_duration; } + if other.verbose.is_some() { + self.verbose = other.verbose; + } if other.aliases.is_some() { self.aliases = other.aliases; } @@ -139,6 +147,7 @@ impl SettingsBuilder { settings.plugin_autoupdate_last_check_duration = self .plugin_autoupdate_last_check_duration .unwrap_or(settings.plugin_autoupdate_last_check_duration); + settings.verbose = self.verbose.unwrap_or(settings.verbose); settings.aliases = self.aliases.clone().unwrap_or(settings.aliases); settings @@ -173,15 +182,12 @@ mod tests { fn test_settings_merge() { let mut s1 = SettingsBuilder::default(); let s2 = SettingsBuilder { - missing_runtime_behavior: Some(MissingRuntimeBehavior::AutoInstall), + missing_runtime_behavior: Some(AutoInstall), ..SettingsBuilder::default() }; s1._merge(s2); - assert_eq!( - s1.missing_runtime_behavior, - Some(MissingRuntimeBehavior::AutoInstall) - ); + assert_eq!(s1.missing_runtime_behavior, Some(AutoInstall)); } #[test] diff --git a/src/env.rs b/src/env.rs index 010d289c4..5abacc4e1 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; pub use std::env::*; -use std::ffi::OsString; use std::path::PathBuf; use lazy_static::lazy_static; @@ -84,10 +83,11 @@ lazy_static! { pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); + /// essentially, this is whether we show spinners or build output on runtime install pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); pub static ref PATH: Vec = - split_paths(&var_os("PATH").unwrap_or(OsString::new())).collect(); + split_paths(&var_os("PATH").unwrap_or_default()).collect(); pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String = if cfg!(test) { ".tool-versions".into() } else { @@ -110,7 +110,16 @@ fn get_env_diff() -> EnvDiff { fn var_is_true(key: &str) -> bool { match var(key) { - Ok(v) => v == "true" || v == "1", + Ok(v) => { + let v = v.to_lowercase(); + !v.is_empty() + && v != "n" + && v != "no" + && v != "false" + && v != "0" + && v != "off" + && v != " " + } Err(_) => false, } } diff --git a/src/main.rs b/src/main.rs index 72e2c1129..91e80d43c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,7 @@ fn main() -> Result<()> { match cli.run(config, &env::ARGS, &mut Output::new()) { Err(err) if log_level < log::LevelFilter::Debug => { - error!("error {err}"); + error!("{err}"); error!( // "rtx error: Run with `--log-level debug` or RTX_DEBUG=1 for more information." "Run with RTX_DEBUG=1 for more information." diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 50e2b2edb..0d362fda1 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -10,7 +10,6 @@ use color_eyre::eyre::{eyre, Result}; use itertools::Itertools; use lazy_static::lazy_static; use regex::Regex; -use spinners_jdxcode::{Spinner, Spinners, Stream}; use versions::Mess; use cache::PluginCache; @@ -24,8 +23,9 @@ use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::shorthand_repository::ShorthandRepo; -use crate::ui::color::{bright_green, cyan}; +use crate::ui::color::cyan; use crate::ui::prompt; +use crate::ui::spinner::Spinner; use crate::{dirs, file}; mod cache; @@ -92,13 +92,10 @@ impl Plugin { git.get_remote_url() } - pub fn install(&self, repository: &String) -> Result<()> { + pub fn install(&self, settings: &Settings, repository: &String) -> Result<()> { debug!("install {} {:?}", self.name, repository); - let mut sp = Spinner::with_stream( - Spinners::Dots10, - format!("Installing plugin {}...", cyan(Stderr, &self.name)), - Stream::Stderr, - ); + let install_message = format!("Installing plugin {}...", cyan(Stderr, &self.name)); + let mut sp = Spinner::start(install_message, settings.verbose); if self.is_installed() { self.uninstall()?; @@ -106,11 +103,7 @@ impl Plugin { let git = Git::new(self.plugin_path.to_path_buf()); git.clone(repository)?; - sp.stop_and_persist( - &bright_green(Stderr, "âś”"), - format!("Plugin {} installed", cyan(Stderr, &self.name)), - ); - + sp.success(format!("Plugin {} installed", cyan(Stderr, &self.name))); Ok(()) } @@ -123,12 +116,12 @@ impl Plugin { match shr.lookup(&self.name) { Ok(repo) => match settings.missing_runtime_behavior { MissingRuntimeBehavior::AutoInstall => { - self.install(&repo)?; + self.install(settings, &repo)?; Ok(true) } MissingRuntimeBehavior::Prompt => match prompt::prompt_for_install(&self.name) { true => { - self.install(&repo)?; + self.install(settings, &repo)?; Ok(true) } false => Ok(false), diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index f1dadf7d5..875b076a0 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -64,7 +64,7 @@ impl RuntimeVersion { Ok(versions) } - pub fn install(&self, install_type: InstallType, config: &Config, verbose: bool) -> Result<()> { + pub fn install(&self, install_type: InstallType, config: &Config) -> Result<()> { let plugin = &self.plugin; let settings = &config.settings; debug!("install {} {} {}", plugin.name, self.version, install_type); @@ -78,7 +78,7 @@ impl RuntimeVersion { let install = Script::Install(install_type); if self.script_man.script_exists(&download) { - if verbose { + if settings.verbose { self.script_man .cmd(download) .stdout_to_stderr() @@ -94,7 +94,7 @@ impl RuntimeVersion { } } - if verbose { + if settings.verbose { self.script_man .cmd(install) .stdout_to_stderr() @@ -150,12 +150,12 @@ impl RuntimeVersion { } match config.settings.missing_runtime_behavior { MissingRuntimeBehavior::AutoInstall => { - self.install(InstallType::Version, config, false)?; + self.install(InstallType::Version, config)?; Ok(true) } MissingRuntimeBehavior::Prompt => { if prompt_for_install(&format!("{self}")) { - self.install(InstallType::Version, config, false)?; + self.install(InstallType::Version, config)?; Ok(true) } else { Ok(false) diff --git a/src/test.rs b/src/test.rs index 1f81c8d50..6b39f3f27 100644 --- a/src/test.rs +++ b/src/test.rs @@ -34,6 +34,7 @@ pub fn reset_config() { fs::write( env::HOME.join("config/config.toml"), indoc! {r#" + verbose = true missing_runtime_behavior= 'autoinstall' always_keep_download= true legacy_version_file= true diff --git a/src/ui/color.rs b/src/ui/color.rs index ea596010a..b2cb0b5f8 100644 --- a/src/ui/color.rs +++ b/src/ui/color.rs @@ -13,7 +13,7 @@ pub fn cyan(stream: Stream, s: &str) -> String { pub fn green(stream: Stream, s: &str) -> String { s.if_supports_color(stream, |s| s.green()).to_string() } -pub fn bright_green(stream: Stream, s: &str) -> String { +pub fn _bright_green(stream: Stream, s: &str) -> String { s.if_supports_color(stream, |s| s.bright_green()) .to_string() } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 093bb1252..b4804e850 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,2 +1,3 @@ pub mod color; pub mod prompt; +pub mod spinner; diff --git a/src/ui/spinner.rs b/src/ui/spinner.rs new file mode 100644 index 000000000..8f55ba990 --- /dev/null +++ b/src/ui/spinner.rs @@ -0,0 +1,29 @@ +use spinoff::{spinners, Color, Streams}; + +pub struct Spinner { + spinner: Option, +} + +impl Spinner { + pub fn start(message: String, verbose: bool) -> Spinner { + let sp = match verbose { + true => { + eprintln!("{message}"); + None + } + false => Some(spinoff::Spinner::new_with_stream( + spinners::Dots10, + message, + Color::Blue, + Streams::Stderr, + )), + }; + Spinner { spinner: sp } + } + + pub fn success(&mut self, message: String) { + if let Some(sp) = self.spinner.take() { + sp.success(&message); + } + } +} diff --git a/test/config/config.toml b/test/config/config.toml index af1749ff1..c143c6183 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -1,3 +1,4 @@ +verbose = true missing_runtime_behavior= 'autoinstall' always_keep_download= true legacy_version_file= true From b4ca1772451d33f6b0f85398673e174bca63cc72 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 14:27:46 -0600 Subject: [PATCH 0082/1891] chore: Release rtx-cli version 1.3.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3760fb881..70e86d84f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.3.0" +version = "1.3.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index cb530b46e..07aea03be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.3.0" +version = "1.3.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e83722911..9cc6666b9 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.3.0 +rtx 1.3.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -171,7 +171,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.0/rtx-v1.3.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.1/rtx-v1.3.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 01cdafe45..37ca5731f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.3.0 +Version: 1.3.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index caa9b162e..35cdb6b7c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -189,7 +189,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.0/rtx-v1.3.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.1/rtx-v1.3.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 30d37e325ca1770ccea80ea09f4ca189e0ebbf13 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 15:49:17 -0600 Subject: [PATCH 0083/1891] [bug] show spinner on ensure_install The spinner was not displaying for commands like `rtx env`. This made it look like nothing was happening --- src/cli/install.rs | 5 ----- src/runtimes/mod.rs | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cli/install.rs b/src/cli/install.rs index 29b1b2afb..31cd4b695 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -15,7 +15,6 @@ use crate::plugins::InstallType::Version; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; use crate::ui::color::cyan; -use crate::ui::spinner::Spinner; /// install a runtime /// @@ -136,11 +135,7 @@ impl Install { } fn do_install(&self, config: &Config, _out: &mut Output, rtv: &RuntimeVersion) -> Result<()> { - let rtv_label = cyan(Stderr, &rtv.to_string()); - let install_message = format!("Installing runtime: {rtv_label}..."); - let mut sp = Spinner::start(install_message, config.settings.verbose); rtv.install(Version, config)?; - sp.success(format!("Runtime {rtv_label} installed")); Ok(()) } } diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index 875b076a0..574a2a1c2 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use atty::Stream::Stderr; use std::fmt; use std::fmt::{Display, Formatter}; use std::fs::{create_dir_all, remove_dir_all}; @@ -16,7 +17,9 @@ use crate::config::{MissingRuntimeBehavior, Settings}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; +use crate::ui::color::cyan; use crate::ui::prompt; +use crate::ui::spinner::Spinner; use crate::{dirs, env, fake_asdf, file}; mod runtime_conf; @@ -68,6 +71,9 @@ impl RuntimeVersion { let plugin = &self.plugin; let settings = &config.settings; debug!("install {} {} {}", plugin.name, self.version, install_type); + let rtv_label = cyan(Stderr, &self.to_string()); + let install_message = format!("Installing runtime: {rtv_label}..."); + let mut sp = Spinner::start(install_message, config.settings.verbose); if !self.plugin.ensure_installed(settings)? { return Err(PluginNotInstalled(self.plugin.name.clone()).into()); @@ -125,6 +131,7 @@ impl RuntimeVersion { debug!("error touching config file: {:?} {:?}", path, err); } } + sp.success(format!("Runtime {rtv_label} installed")); Ok(()) } From f0dc795c84ef20b6ba042fa77cef6adc3a79a129 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 15:56:32 -0600 Subject: [PATCH 0084/1891] chore: Release rtx-cli version 1.3.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70e86d84f..1dc6614fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.3.1" +version = "1.3.2" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 07aea03be..59fc31c0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.3.1" +version = "1.3.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 9cc6666b9..f9e403891 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.3.1 +rtx 1.3.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -171,7 +171,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.1/rtx-v1.3.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.2/rtx-v1.3.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 37ca5731f..e8e97d25e 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.3.1 +Version: 1.3.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 35cdb6b7c..9cb4b440c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -189,7 +189,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.1/rtx-v1.3.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.2/rtx-v1.3.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 99a48e31564506dcf02fd8e7dadb77edb82e16a2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:36:36 -0600 Subject: [PATCH 0085/1891] [chore] added release-aur script --- scripts/release-aur.sh | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100755 scripts/release-aur.sh diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh new file mode 100755 index 000000000..4830ab012 --- /dev/null +++ b/scripts/release-aur.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euxo pipefail + +VERSION=$(curl https://rtx.jdxcode.com/VERSION | sed -e "s/^v//") +SHA512=$(curl https://rtx.jdxcode.com/SHASUMS512.txt | grep linux-x64.tar.gz | awk '{print $1}') + +cat >aur/PKGBUILD < + +pkgname=rtx +pkgver=$VERSION +pkgrel=1 +pkgdesc='Polyglot runtime manager' +arch=('x86_64') +url='https://github.com/jdxcode/rtx' +license=('MIT') +makedepends=('cargo' 'jq') +provides=('rtx') +conflicts=('rtx') +source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdxcode/\$pkgname/archive/v\$pkgver.tar.gz") +sha512sums=('$SHA512') + +prepare() { + cd "\$pkgname-\$pkgver" + + cargo fetch --locked --target "\$CARCH-unknown-linux-gnu" +} + +build() { + cd "\$pkgname-\$pkgver" + + export RUSTUP_TOOLCHAIN=stable + export CARGO_TARGET_DIR=target + cargo build --release --locked --message-format=json-render-diagnostics | + jq -r 'select(.out_dir) | select(.package_id | startswith("ripgrep ")) | .out_dir' > out_dir +} + +package() { + cd "\$pkgname-\$pkgver" + local OUT_DIR=\$(aur/.SRCINFO < Date: Wed, 1 Feb 2023 19:04:15 -0600 Subject: [PATCH 0086/1891] added release-fast profile --- Cargo.toml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 59fc31c0c..e69b56510 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,13 +69,14 @@ insta = "1.26.0" pretty_assertions = "1.3.0" tempfile = "3.3.0" -#[profile.release] -#opt-level = "z" # optimize for size -#lto = true -#debug = false -#debug-assertions = false -#panic = "abort" -#strip = "symbols" +[profile.release] + +[profile.release-fast] +inherits = "release" +opt-level = 3 +lto = true +panic = "abort" +strip = "symbols" [package.metadata.release] allow-branch = ["main"] From aebca24c7063cfafefe82a5e485b848cd80274c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 19:16:16 -0600 Subject: [PATCH 0087/1891] [docs] added notes on latest performance numbers Unfortunately rtx is not as fast as it was, I have documented why and explained that the focus currently is on stability. --- README.md | 16 ++++++++++++---- src/cli/render_help.rs | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f9e403891..99eb0d52e 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ directory containing a `.tool-versions` file, rtx will automatically activate th Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This should be very fast and it exits early if the the directory wasn't changed or the `.tool-version` -files haven't been updated. On my machine this takes 1-2ms even if it _doesn't_ exit early. +files haven't been updated. On my machine this takes <10ms in the fast case, 30ms in the slow case. This was much faster (2-3ms) but more checks and features have been +added which have slowed it down a bit. See [Performance](#performance) for more on this topic. Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies `PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids @@ -1214,7 +1215,7 @@ asdf made (what I consider) a poor design decision to use shims that go between and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, which then calls `asdf exec`, which then calls the correct version of node. -These shims have terrible performance, adding ~200ms to every call. rtx does not use shims and instead +These shims have terrible performance, adding ~200ms to every runtime call. rtx does not use shims and instead updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. I don't think it's possible for asdf to fix thse issues. The author of asdf did a great writeup @@ -1225,8 +1226,15 @@ shim design. I don't think it's possible to fix that without a complete rewrite. rtx does call an internal command `rtx hook-env` every time the directory has changed, but because it's written in Rust, this is very quick—taking ~2ms on my machine. -tl;dr: asdf adds overhead (~200ms) when calling a runtime, rtx adds a tiny amount of overhead (~2ms) -when changing directories. +At one point rtx was nearly complete and running <3ms. It's not that fast anymore. +Now when `rtx hook-env` runs it takes ~30ms on my machine and ~10ms if it can exit +early. This is with 10 plugins and about as many active runtimes. This is fast enough to not really be noticeable to me, but I think we can do better. +This slowed down because more checks and more features were added which meant +loading more things. I will optimize this at some point, but right now in development +my focus is on stability and compatibility. In this case, "performance" means +taking shortcuts and caching which are both likely to reduce stability. As long as we're staying <50ms I think it will feel fast enough for now. If we creep above that we'll need to fix something. + +tl;dr: asdf adds overhead (~200ms) when calling a runtime, rtx adds a small amount of overhead (~30ms) only when changing directories if they have a `.tool-versions` file. ### Environment variables diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9cb4b440c..47b29ca2f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -85,7 +85,8 @@ directory containing a `.tool-versions` file, rtx will automatically activate th Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This should be very fast and it exits early if the the directory wasn't changed or the `.tool-version` -files haven't been updated. On my machine this takes 1-2ms even if it _doesn't_ exit early. +files haven't been updated. On my machine this takes <10ms in the fast case, 30ms in the slow case. This was much faster (2-3ms) but more checks and features have been +added which have slowed it down a bit. See [Performance](#performance) for more on this topic. Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies `PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids @@ -516,7 +517,7 @@ asdf made (what I consider) a poor design decision to use shims that go between and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, which then calls `asdf exec`, which then calls the correct version of node. -These shims have terrible performance, adding ~200ms to every call. rtx does not use shims and instead +These shims have terrible performance, adding ~200ms to every runtime call. rtx does not use shims and instead updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. I don't think it's possible for asdf to fix thse issues. The author of asdf did a great writeup @@ -527,8 +528,15 @@ shim design. I don't think it's possible to fix that without a complete rewrite. rtx does call an internal command `rtx hook-env` every time the directory has changed, but because it's written in Rust, this is very quick—taking ~2ms on my machine. -tl;dr: asdf adds overhead (~200ms) when calling a runtime, rtx adds a tiny amount of overhead (~2ms) -when changing directories. +At one point rtx was nearly complete and running <3ms. It's not that fast anymore. +Now when `rtx hook-env` runs it takes ~30ms on my machine and ~10ms if it can exit +early. This is with 10 plugins and about as many active runtimes. This is fast enough to not really be noticeable to me, but I think we can do better. +This slowed down because more checks and more features were added which meant +loading more things. I will optimize this at some point, but right now in development +my focus is on stability and compatibility. In this case, "performance" means +taking shortcuts and caching which are both likely to reduce stability. As long as we're staying <50ms I think it will feel fast enough for now. If we creep above that we'll need to fix something. + +tl;dr: asdf adds overhead (~200ms) when calling a runtime, rtx adds a small amount of overhead (~30ms) only when changing directories if they have a `.tool-versions` file. ### Environment variables From c3cfec5b93a8e36fbedb139aa7ca19c8cb27bf8d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 21:46:53 -0600 Subject: [PATCH 0088/1891] [chore] update aur script --- scripts/release-aur.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 4830ab012..0894222e3 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -2,7 +2,11 @@ set -euxo pipefail VERSION=$(curl https://rtx.jdxcode.com/VERSION | sed -e "s/^v//") -SHA512=$(curl https://rtx.jdxcode.com/SHASUMS512.txt | grep linux-x64.tar.gz | awk '{print $1}') +SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/v$VERSION.tar.gz" | sha512sum | awk '{print $1}') + +if [ ! -d aur ]; then + git clone ssh://aur@aur.archlinux.org/rtx.git aur +fi cat >aur/PKGBUILD < From 05b92398eda621a852af14bc69648633936d0084 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Feb 2023 21:54:52 -0600 Subject: [PATCH 0089/1891] [docs] updated performance number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In aebca24c7063cfafefe82a5e485b848cd80274c4 I updated the docs to represent what I thought were more accurate numbers. I realized that it's actually my work laptop that often gives very poor performance for both asdf and rtx. This explains why I sometimes see asdf take as long as 900ms to launch a shim. I tested on my personal laptop and I get much more realistic numbers for both. These seem to be a lot closer to what other people get online and they are more consistent. My work laptop seems to vary from moment to moment. The good news is rtx looks a lot better now. So I'm not going to benchmark on my work laptop, it doesn't seem useful. These new numbers don't need a disclaimer about focusing on performance I don't think. If we're consistently under 15ms for "slow" runs I don't think it's much to worry about. I had said rtx was ~100x faster than rtx which was an exaggeration it turns out. That was based on favorable rtx numbers and unfavorable asdf ones. I think accurately it's best described as 32x as fast (take asdf avg (120) / rtx "fast" avg (13.5)). I think it's more accurate to look at just the "fast" number for rtx as the slow number is only paid if `.tool-versions` is modified or the user just entered a new project directory. I updated both the benchmarks based on the hyperfine results below for `hook-env` with an early exit and a full run. Here are the results (note this is with use_legacy_file on for both): ``` $ hyperfine "~/.asdf/shims/ruby -v" --warmup 10 Benchmark 1: ~/.asdf/shims/ruby -v Time (mean ± Ď): 120.4 ms ± 1.5 ms [User: 11.4 ms, System: 10.3 ms] Range (min … max): 116.6 ms … 122.5 ms 24 runs $ hyperfine "rtx x -- ruby -v" --warmup 10 Benchmark 1: rtx x -- ruby -v Time (mean ± Ď): 10.9 ms ± 4.3 ms [User: 6.0 ms, System: 2.9 ms] Range (min … max): 8.7 ms … 40.0 ms 78 runs $ hyperfine "rtx hook-env" --warmup 10 # slow run Benchmark 1: rtx hook-env Time (mean ± Ď): 13.5 ms ± 0.3 ms [User: 8.5 ms, System: 11.6 ms] Range (min … max): 12.8 ms … 15.3 ms 185 runs $ hyperfine "rtx hook-env" --warmup 10 # fast run Benchmark 1: rtx hook-env Time (mean ± Ď): 3.7 ms ± 0.2 ms [User: 2.9 ms, System: 4.2 ms] Range (min … max): 3.3 ms … 6.0 ms 460 runs ``` --- README.md | 19 ++++++------------- src/cli/render_help.rs | 19 ++++++------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 99eb0d52e..056d3ad05 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,7 @@ directory containing a `.tool-versions` file, rtx will automatically activate th Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This should be very fast and it exits early if the the directory wasn't changed or the `.tool-version` -files haven't been updated. On my machine this takes <10ms in the fast case, 30ms in the slow case. This was much faster (2-3ms) but more checks and features have been -added which have slowed it down a bit. See [Performance](#performance) for more on this topic. +files haven't been updated. On my machine this takes 4ms in the fast case, 14ms in the slow case. See [Performance](#performance) for more on this topic. Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies `PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids @@ -1215,7 +1214,7 @@ asdf made (what I consider) a poor design decision to use shims that go between and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, which then calls `asdf exec`, which then calls the correct version of node. -These shims have terrible performance, adding ~200ms to every runtime call. rtx does not use shims and instead +These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. I don't think it's possible for asdf to fix thse issues. The author of asdf did a great writeup @@ -1224,17 +1223,11 @@ in bash which certainly makes it challening to be performant, however I think th shim design. I don't think it's possible to fix that without a complete rewrite. rtx does call an internal command `rtx hook-env` every time the directory has changed, but because -it's written in Rust, this is very quick—taking ~2ms on my machine. +it's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's +a full reload. -At one point rtx was nearly complete and running <3ms. It's not that fast anymore. -Now when `rtx hook-env` runs it takes ~30ms on my machine and ~10ms if it can exit -early. This is with 10 plugins and about as many active runtimes. This is fast enough to not really be noticeable to me, but I think we can do better. -This slowed down because more checks and more features were added which meant -loading more things. I will optimize this at some point, but right now in development -my focus is on stability and compatibility. In this case, "performance" means -taking shortcuts and caching which are both likely to reduce stability. As long as we're staying <50ms I think it will feel fast enough for now. If we creep above that we'll need to fix something. - -tl;dr: asdf adds overhead (~200ms) when calling a runtime, rtx adds a small amount of overhead (~30ms) only when changing directories if they have a `.tool-versions` file. +tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~10ms) +when the prompt loads. ### Environment variables diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 47b29ca2f..bad59070e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -85,8 +85,7 @@ directory containing a `.tool-versions` file, rtx will automatically activate th Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This should be very fast and it exits early if the the directory wasn't changed or the `.tool-version` -files haven't been updated. On my machine this takes <10ms in the fast case, 30ms in the slow case. This was much faster (2-3ms) but more checks and features have been -added which have slowed it down a bit. See [Performance](#performance) for more on this topic. +files haven't been updated. On my machine this takes 4ms in the fast case, 14ms in the slow case. See [Performance](#performance) for more on this topic. Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies `PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids @@ -517,7 +516,7 @@ asdf made (what I consider) a poor design decision to use shims that go between and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, which then calls `asdf exec`, which then calls the correct version of node. -These shims have terrible performance, adding ~200ms to every runtime call. rtx does not use shims and instead +These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. I don't think it's possible for asdf to fix thse issues. The author of asdf did a great writeup @@ -526,17 +525,11 @@ in bash which certainly makes it challening to be performant, however I think th shim design. I don't think it's possible to fix that without a complete rewrite. rtx does call an internal command `rtx hook-env` every time the directory has changed, but because -it's written in Rust, this is very quick—taking ~2ms on my machine. +it's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's +a full reload. -At one point rtx was nearly complete and running <3ms. It's not that fast anymore. -Now when `rtx hook-env` runs it takes ~30ms on my machine and ~10ms if it can exit -early. This is with 10 plugins and about as many active runtimes. This is fast enough to not really be noticeable to me, but I think we can do better. -This slowed down because more checks and more features were added which meant -loading more things. I will optimize this at some point, but right now in development -my focus is on stability and compatibility. In this case, "performance" means -taking shortcuts and caching which are both likely to reduce stability. As long as we're staying <50ms I think it will feel fast enough for now. If we creep above that we'll need to fix something. - -tl;dr: asdf adds overhead (~200ms) when calling a runtime, rtx adds a small amount of overhead (~30ms) only when changing directories if they have a `.tool-versions` file. +tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~10ms) +when the prompt loads. ### Environment variables From 62d3afbe5cbcbed877930ece88cac6b37ff96c0e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Feb 2023 09:33:49 -0600 Subject: [PATCH 0090/1891] added RTX_HIDE_OUTDATED_BUILD --- README.md | 12 ++++++++++++ src/build_time.rs | 5 ++++- src/cli/render_help.rs | 12 ++++++++++++ src/env.rs | 1 + 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 056d3ad05..d9cc73230 100644 --- a/README.md +++ b/README.md @@ -396,6 +396,18 @@ This shows the installation output during `rtx install` and `rtx plugin install` This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have 2 configuration for the same thing, but for now it is it's own config. +#### `RTX_HIDE_OUTDATED_BUILD=1` + +If a release is 12 months old, it will show a warning message every time it launches: + +``` +rtx has not been updated in over a year. Please update to the latest version. +``` + +You likely do not want to be using rtx if it is that old. I'm doing this instead of +autoupdating. If, for some reason, you want to stay on some old version, you can hide +this message with `RTX_HIDE_OUTDATED_BUILD=1`. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/src/build_time.rs b/src/build_time.rs index 63924748e..4555a052c 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -1,3 +1,4 @@ +use crate::env::RTX_HIDE_OUTDATED_BUILD; use build_time::build_time_utc; use chrono::{DateTime, FixedOffset, Months, Utc}; use lazy_static::lazy_static; @@ -9,7 +10,9 @@ lazy_static! { #[ctor::ctor] fn init() { - if BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() { + if !*RTX_HIDE_OUTDATED_BUILD + && BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() + { eprintln!("rtx has not been updated in over a year. Please update to the latest version."); } } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index bad59070e..50575362a 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -414,6 +414,18 @@ This shows the installation output during `rtx install` and `rtx plugin install` This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have 2 configuration for the same thing, but for now it is it's own config. +#### `RTX_HIDE_OUTDATED_BUILD=1` + +If a release is 12 months old, it will show a warning message every time it launches: + +``` +rtx has not been updated in over a year. Please update to the latest version. +``` + +You likely do not want to be using rtx if it is that old. I'm doing this instead of +autoupdating. If, for some reason, you want to stay on some old version, you can hide +this message with `RTX_HIDE_OUTDATED_BUILD=1`. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/src/env.rs b/src/env.rs index 5abacc4e1..cd865810c 100644 --- a/src/env.rs +++ b/src/env.rs @@ -95,6 +95,7 @@ lazy_static! { }; pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); + pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); } fn get_env_diff() -> EnvDiff { From 3ce6720e002d1caa10939d55464def10a83c685e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bojan=20Deli=C4=87?= Date: Fri, 3 Feb 2023 02:06:29 +0100 Subject: [PATCH 0091/1891] Issue #71 - use positional arguments for activate (#85) --- README.md | 40 +++++++++---------- completions/_rtx | 2 + completions/rtx.bash | 4 +- e2e/cd/test_bash | 2 +- e2e/cd/test_bash_legacy_activate | 17 ++++++++ e2e/cd/test_fish | 2 +- e2e/cd/test_zsh | 2 +- e2e/direnv/no_tool_versions/test_direnv | 2 +- e2e/gopath/test_gopath | 2 +- src/cli/activate.rs | 20 +++++++--- src/cli/deactivate.rs | 23 +++++++---- src/cli/render_help.rs | 12 +++--- ...__activate__test__activate_zsh_legacy.snap | 20 ++++++++++ ...activate__test__deactivate_zsh_legacy.snap | 7 ++++ 14 files changed, 110 insertions(+), 45 deletions(-) create mode 100755 e2e/cd/test_bash_legacy_activate create mode 100644 src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap create mode 100644 src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap diff --git a/README.md b/README.md index d9cc73230..d076e387f 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it (choose one, and open a new shell session for the changes to take effect): ```sh-session -$ echo 'eval "$(~/bin/rtx activate -s bash)"' >> ~/.bashrc -$ echo 'eval "$(~/bin/rtx activate -s zsh)"' >> ~/.zshrc -$ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish +$ echo 'eval "$(~/bin/rtx activate bash)"' >> ~/.bashrc +$ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc +$ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` Install a runtime and set it as the default: @@ -61,7 +61,7 @@ Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). ### How it works -rtx installs as a shell extension (e.g. `rtx activate -s zsh`) that sets the `PATH` +rtx installs as a shell extension (e.g. `rtx activate zsh`) that sets the `PATH` environment variable to point your shell to the correct runtime binaries. When you `cd` into a directory containing a `.tool-versions` file, rtx will automatically activate the correct versions. @@ -234,13 +234,13 @@ makepkg -si ### Bash ```sh-session -$ echo 'eval "$(rtx activate -s bash)"' >> ~/.bashrc +$ echo 'eval "$(rtx activate bash)"' >> ~/.bashrc ``` ### Fish ```sh-session -$ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish +$ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` ### Something else? @@ -484,14 +484,15 @@ This should go into your shell's rc file. Otherwise, it will only take effect in the current session. (e.g. ~/.bashrc) -Usage: activate [OPTIONS] +Usage: activate [OPTIONS] [SHELL_TYPE] -Options: - -s, --shell +Arguments: + [SHELL_TYPE] Shell type to generate the script for [possible values: bash, fish, zsh] +Options: -q, --quiet Hide the "rtx: @" message when changing directories @@ -500,9 +501,9 @@ Options: Examples: - $ eval "$(rtx activate -s bash)" - $ eval "$(rtx activate -s zsh)" - $ rtx activate -s fish | source + $ eval "$(rtx activate bash)" + $ eval "$(rtx activate zsh)" + $ rtx activate fish | source ``` ### `rtx alias ls` @@ -592,24 +593,23 @@ disable rtx for current shell session This can be used to temporarily disable rtx in a shell session. -Usage: deactivate [OPTIONS] +Usage: deactivate [SHELL_TYPE] -Options: - -s, --shell +Arguments: + [SHELL_TYPE] shell type to generate the script for - e.g.: bash, zsh, fish - [possible values: bash, fish, zsh] +Options: -h, --help Print help (see a summary with '-h') Examples: - $ eval "$(rtx deactivate -s bash)" - $ eval "$(rtx deactivate -s zsh)" - $ rtx deactivate -s fish | source + $ eval "$(rtx deactivate bash)" + $ eval "$(rtx deactivate zsh)" + $ rtx deactivate fish | source ``` ### `rtx direnv activate` diff --git a/completions/_rtx b/completions/_rtx index 6c47e306c..b7e096f3d 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -42,6 +42,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ +'::shell_type -- Shell type to generate the script for:(bash fish zsh)' \ && ret=0 ;; (alias) @@ -142,6 +143,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ +'::shell_type -- shell type to generate the script for:(bash fish zsh)' \ && ret=0 ;; (direnv) diff --git a/completions/rtx.bash b/completions/rtx.bash index 0ca3d2978..dcaa8ea56 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -385,7 +385,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -v -h --shell --quiet --log-level --verbose --help" + opts="-s -q -v -h --shell --quiet --log-level --verbose --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -567,7 +567,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-s -v -h --shell --log-level --verbose --help" + opts="-s -v -h --shell --log-level --verbose --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index b9c0d6ff8..2aa08886a 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -3,7 +3,7 @@ set -euo pipefail rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 -eval "$(rtx activate -s bash)" +eval "$(rtx activate bash)" _rtx_hook #rtx install diff --git a/e2e/cd/test_bash_legacy_activate b/e2e/cd/test_bash_legacy_activate new file mode 100755 index 000000000..b9c0d6ff8 --- /dev/null +++ b/e2e/cd/test_bash_legacy_activate @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +rtx install nodejs@18.0.0 nodejs@16.0.0 +# shellcheck disable=SC1090 +eval "$(rtx activate -s bash)" +_rtx_hook + +#rtx install +test "$(node -v)" = "v18.0.0" + +cd 16 && _rtx_hook +#rtx install +test "$(node -v)" = "v16.0.0" + +cd .. && _rtx_hook +test "$(node -v)" = "v18.0.0" diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index f7d208bb3..f32240987 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -4,7 +4,7 @@ #set -l fish_trace 1 rtx install nodejs@18.0.0 nodejs@16.0.0; or exit -rtx activate -s fish | source && __rtx_env_eval +rtx activate fish | source && __rtx_env_eval #rtx i test (node -v) = "v18.0.0"; or exit diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index 4c350534e..083861b08 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -3,7 +3,7 @@ set -euo pipefail rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 -eval "$(rtx activate -s zsh)" +eval "$(rtx activate zsh)" _rtx_hook #rtx install diff --git a/e2e/direnv/no_tool_versions/test_direnv b/e2e/direnv/no_tool_versions/test_direnv index a8cef4aca..7c8bbacab 100755 --- a/e2e/direnv/no_tool_versions/test_direnv +++ b/e2e/direnv/no_tool_versions/test_direnv @@ -3,7 +3,7 @@ set -e eval "$(direnv hook zsh)" -eval "$(rtx activate -s zsh)" +eval "$(rtx activate zsh)" _rtx_hook && _direnv_hook assert_go_version() { diff --git a/e2e/gopath/test_gopath b/e2e/gopath/test_gopath index 5e20b3e98..70394bfb2 100755 --- a/e2e/gopath/test_gopath +++ b/e2e/gopath/test_gopath @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -eval "$(rtx activate -s bash)" +eval "$(rtx activate bash)" _rtx_hook assert_gopath() { diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 4c197bcb7..eb627f80d 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -15,9 +15,13 @@ use crate::shell::{get_shell, ShellType}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Activate { /// Shell type to generate the script for - #[clap(long, short)] + #[clap(long, short, hide = true)] shell: Option, + /// Shell type to generate the script for + #[clap()] + shell_type: Option, + /// Hide the "rtx: @" message when changing directories #[clap(long, short)] quiet: bool, @@ -25,7 +29,7 @@ pub struct Activate { impl Command for Activate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let shell = get_shell(self.shell); + let shell = get_shell(self.shell_type.or(self.shell)); if self.quiet { rtxprintln!(out, "{}", shell.set_env("RTX_QUIET", "1")); @@ -45,9 +49,9 @@ impl Command for Activate { const AFTER_LONG_HELP: &str = r#" Examples: - $ eval "$(rtx activate -s bash)" - $ eval "$(rtx activate -s zsh)" - $ rtx activate -s fish | source + $ eval "$(rtx activate bash)" + $ eval "$(rtx activate zsh)" + $ rtx activate fish | source "#; #[cfg(test)] @@ -58,6 +62,12 @@ mod test { #[test] fn test_activate_zsh() { + let stdout = assert_cli!("activate", "zsh"); + assert_display_snapshot!(stdout); + } + + #[test] + fn test_activate_zsh_legacy() { let stdout = assert_cli!("activate", "-s", "zsh"); assert_display_snapshot!(stdout); } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 6bede6091..69621b595 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -12,15 +12,17 @@ use crate::shell::{get_shell, ShellType}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Deactivate { /// shell type to generate the script for - /// - /// e.g.: bash, zsh, fish - #[clap(long, short)] + #[clap(long, short, hide = true)] shell: Option, + + /// shell type to generate the script for + #[clap()] + shell_type: Option, } impl Command for Deactivate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let shell = get_shell(self.shell); + let shell = get_shell(self.shell_type.or(self.shell)); let output = shell.deactivate(); out.stdout.write(output); @@ -31,9 +33,9 @@ impl Command for Deactivate { const AFTER_LONG_HELP: &str = r#" Examples: - $ eval "$(rtx deactivate -s bash)" - $ eval "$(rtx deactivate -s zsh)" - $ rtx deactivate -s fish | source + $ eval "$(rtx deactivate bash)" + $ eval "$(rtx deactivate zsh)" + $ rtx deactivate fish | source "#; #[cfg(test)] @@ -44,6 +46,13 @@ mod test { #[test] fn test_deactivate_zsh() { + std::env::set_var("NO_COLOR", "1"); + let stdout = assert_cli!("deactivate", "zsh"); + assert_display_snapshot!(stdout); + } + + #[test] + fn test_deactivate_zsh_legacy() { std::env::set_var("NO_COLOR", "1"); let stdout = assert_cli!("deactivate", "-s", "zsh"); assert_display_snapshot!(stdout); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 50575362a..27d11dd87 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -40,9 +40,9 @@ Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it (choose one, and open a new shell session for the changes to take effect): ```sh-session -$ echo 'eval "$(~/bin/rtx activate -s bash)"' >> ~/.bashrc -$ echo 'eval "$(~/bin/rtx activate -s zsh)"' >> ~/.zshrc -$ echo '~/bin/rtx activate -s fish | source' >> ~/.config/fish/config.fish +$ echo 'eval "$(~/bin/rtx activate bash)"' >> ~/.bashrc +$ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc +$ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` Install a runtime and set it as the default: @@ -79,7 +79,7 @@ Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). ### How it works -rtx installs as a shell extension (e.g. `rtx activate -s zsh`) that sets the `PATH` +rtx installs as a shell extension (e.g. `rtx activate zsh`) that sets the `PATH` environment variable to point your shell to the correct runtime binaries. When you `cd` into a directory containing a `.tool-versions` file, rtx will automatically activate the correct versions. @@ -252,13 +252,13 @@ makepkg -si ### Bash ```sh-session -$ echo 'eval "$(rtx activate -s bash)"' >> ~/.bashrc +$ echo 'eval "$(rtx activate bash)"' >> ~/.bashrc ``` ### Fish ```sh-session -$ echo 'rtx activate -s fish | source' >> ~/.config/fish/config.fish +$ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` ### Something else? diff --git a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap new file mode 100644 index 000000000..072685c45 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap @@ -0,0 +1,20 @@ +--- +source: src/cli/activate.rs +assertion_line: 72 +expression: stdout +--- +export PATH=":$PATH" +_rtx_hook() { + trap -- '' SIGINT; + eval "$("rtx" hook-env -s zsh)"; + trap - SIGINT; +} +typeset -ag precmd_functions; +if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then + precmd_functions=( _rtx_hook ${precmd_functions[@]} ) +fi +typeset -ag chpwd_functions; +if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then + chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) +fi + diff --git a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap new file mode 100644 index 000000000..1dae038b7 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/deactivate.rs +assertion_line: 58 +expression: stdout +--- +unset _rtx_hook; + From 62f709afd25cd13a062c3bfa64f54627f610e8f9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Feb 2023 19:33:01 -0600 Subject: [PATCH 0092/1891] Create CONTRIBUTING.md --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..5a2c00cff --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +## Dependencies + +* [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that) +* [just](https://github.com/casey/just) any version should do + +(you'd think we'd use rtx to fetch these but frankly it's kind of a pain to dogfood rtx while testing it) + +## Setup + +Shouldn't require anything special I'm aware of, but `just build` is a good sanity check to run and make sure it's all working. + +## Running Tests + +* Run only unit tests: `just test-unit` +* Run only E2E tests: `just test-e2e` +* Run all tests: `just test` + +## Linting + +* Lint codebase: `just lint` +* Lint and fix codebase: `just lint-fix` + +## Generating readme and shell completion files + +``` +just pre-commit +``` + +## [optional] Pre-commit hook + +This project uses husky which will automatically install a pre-commit hook: + +``` +npm i # installs and configured husky precommit hook automatically +git commit # will automatically run `just pre-commit` +``` From c4bd317c63392889a7f3387ad319507555a8563f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Feb 2023 19:37:46 -0600 Subject: [PATCH 0093/1891] Update CONTRIBUTING.md --- CONTRIBUTING.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a2c00cff..e90f13c9e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,20 @@ Shouldn't require anything special I'm aware of, but `just build` is a good sanity check to run and make sure it's all working. +## Running the CLI + +I put a shim for `cargo run` that makes it easy to run build + run rtx in dev mode. It's at `.bin/rtx`. What I do is add this to PATH +with direnv. Here is my `.envrc`: + +``` +source_up_if_exists +PATH_add .bin +``` + +Now I can just run `rtx` as if I was using an installed version and it will build it from source everytime there are changes. + +You don't have to do this, but it makes things like `rtx activate` a lot easier to setup. + ## Running Tests * Run only unit tests: `just test-unit` From 6798ab1afc4d4d8b530ff0ffc7532b3deb6b8175 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Feb 2023 19:38:49 -0600 Subject: [PATCH 0094/1891] Update CONTRIBUTING.md --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e90f13c9e..8c637253a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ ## Dependencies -* [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that) -* [just](https://github.com/casey/just) any version should do +* [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that). As of this writing: 1.67.0 but GH actions will use the latest stable whenever it runs. +* [just](https://github.com/casey/just) any version should do, but as of this writing I'm on 1.13.0 (you'd think we'd use rtx to fetch these but frankly it's kind of a pain to dogfood rtx while testing it) From 7fb1c631fd16456ce79554996593bc405db4e041 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Feb 2023 07:45:36 -0600 Subject: [PATCH 0095/1891] chore: Release rtx-cli version 1.4.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1dc6614fa..bad3da2c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.3.2" +version = "1.4.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index e69b56510..30171f77a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.3.2" +version = "1.4.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index d076e387f..357485baf 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.3.2 +rtx 1.4.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -171,7 +171,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.2/rtx-v1.3.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.4.0/rtx-v1.4.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e8e97d25e..b10c789a4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.3.2 +Version: 1.4.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 27d11dd87..2d4747b0b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -189,7 +189,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.3.2/rtx-v1.3.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.4.0/rtx-v1.4.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 1661b23aadb4e0fcc95f9175c7bb506fdd8e63ab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Feb 2023 08:29:53 -0600 Subject: [PATCH 0096/1891] [chore] document justfile (#93) Also made `just test-update-snapshots` delete snapshots that are no longer used. --- CONTRIBUTING.md | 26 +++++++++++++++++++ justfile | 15 +++++++++++ ...__activate__test__activate_zsh_legacy.snap | 1 - ...activate__test__deactivate_zsh_legacy.snap | 1 - 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8c637253a..e259f7937 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,32 @@ (you'd think we'd use rtx to fetch these but frankly it's kind of a pain to dogfood rtx while testing it) +## Just + +Just should be used for just about every task. Here is a full list of its +tasks: + +``` +~/src/rtx ❯ just --list +Available recipes: + build *args # just `cargo build` + clean # delete built files + default # defaults to `just test` + lint # clippy, cargo fmt --check, and just --fmt + lint-fix # runs linters but makes fixes when possible + pre-commit # called by husky precommit hook + render-completions # regenerate shell completion files + render-help # regenerate README.md + test # run all test types + b # alias for `test` + t # alias for `test` + test-coverage # run unit tests w/ coverage + test-e2e # runs the E2E tests in ./e2e + test-setup # prepare repo to execute tests + test-unit # run the rust "unit" tests + test-update-snapshots # update all test snapshot files +``` + ## Setup Shouldn't require anything special I'm aware of, but `just build` is a good sanity check to run and make sure it's all working. diff --git a/justfile b/justfile index a81e673fe..78e109d24 100644 --- a/justfile +++ b/justfile @@ -5,57 +5,72 @@ export PATH := env_var("PWD") + "/target/debug:" + env_var("PATH") export RTX_MISSING_RUNTIME_BEHAVIOR := "autoinstall" export RUST_TEST_THREADS := "1" +# defaults to `just test` default: test alias b := test +# just `cargo build` build *args: cargo build {{ args }} alias t := test +# run all test types test: test-unit test-e2e +# prepare repo to execute tests test-setup: build +# update all test snapshot files test-update-snapshots: test-setup + find . -name '*.snap' -delete cargo insta test --accept +# run the rust "unit" tests test-unit: test-setup cargo test +# runs the E2E tests in ./e2e test-e2e: test-setup build ./e2e/run_all_tests +# run unit tests w/ coverage test-coverage: clean test-setup cargo +nightly tarpaulin \ --all-features --workspace \ --timeout 120 --out Xml --ignore-tests +# delete built files clean: cargo clean rm -rf target rm -rf *.profraw rm -rf coverage +# clippy, cargo fmt --check, and just --fmt lint: cargo clippy cargo fmt --all -- --check just --unstable --fmt --check +# runs linters but makes fixes when possible lint-fix: cargo clippy --fix --allow-staged --allow-dirty cargo fmt --all just --unstable --fmt +# regenerate README.md render-help: ./.bin/rtx render-help > README.md +# regenerate shell completion files render-completions: ./.bin/rtx complete -s bash > completions/rtx.bash ./.bin/rtx complete -s zsh > completions/_rtx ./.bin/rtx complete -s fish > completions/rtx.fish +# called by husky precommit hook pre-commit: lint render-help render-completions git add README.md git add completions diff --git a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap index 072685c45..4aa4945ae 100644 --- a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap @@ -1,6 +1,5 @@ --- source: src/cli/activate.rs -assertion_line: 72 expression: stdout --- export PATH=":$PATH" diff --git a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap index 1dae038b7..037f20fee 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap @@ -1,6 +1,5 @@ --- source: src/cli/deactivate.rs -assertion_line: 58 expression: stdout --- unset _rtx_hook; From 067ba808a14e061e6fb53d7ec144ae88d79eff6d Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sat, 4 Feb 2023 03:27:53 +0700 Subject: [PATCH 0097/1891] [feat] add Xonsh shell support (#91) * [feat] add xonsh support * [test] add xonsh snapshots * [docs] add reference/example of xonsh * [docs] add reference/example of xonsh to completions --- README.md | 28 +++- completions/_rtx | 24 +-- completions/rtx.bash | 20 +-- completions/rtx.fish | 10 +- src/cli/activate.rs | 1 + src/cli/deactivate.rs | 1 + src/cli/env.rs | 1 + src/cli/hook_env.rs | 2 - src/cli/render_help.rs | 19 +++ src/shell/mod.rs | 8 +- .../rtx__shell__xonsh__tests__hook_init.snap | 16 ++ .../rtx__shell__xonsh__tests__set_env.snap | 11 ++ .../rtx__shell__xonsh__tests__unset_env.snap | 11 ++ src/shell/xonsh.rs | 142 ++++++++++++++++++ 14 files changed, 261 insertions(+), 33 deletions(-) create mode 100644 src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap create mode 100644 src/shell/snapshots/rtx__shell__xonsh__tests__set_env.snap create mode 100644 src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap create mode 100644 src/shell/xonsh.rs diff --git a/README.md b/README.md index 357485baf..081898086 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,25 @@ $ echo 'eval "$(rtx activate bash)"' >> ~/.bashrc $ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` +### Xonsh + +Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a bit off startup time by using a pure Python import: add the code below to, for example, `~/.config/xonsh/rtx.py` config file and `import rtx` it in `~/.config/xonsh/rc.xsh`: +```xsh +from pathlib import Path +from xonsh.built_ins import XSH + +ctx = XSH.ctx +rtx_init = subprocess.run([Path('~/bin/rtx').expanduser(),'activate','xonsh'],capture_output=True,encoding="UTF-8").stdout +XSH.builtins.execx(rtx_init,'exec',ctx,filename='rtx') +``` + +Or continue to use `rc.xsh`/`.xonshrc`: +```xsh +echo 'execx($(~/bin/rtx activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xonshrc +``` + +Given that `rtx` replaces both shell env `$PATH` and OS environ `PATH`, watch out that your configs don't have these two set differently (might throw `os.environ['PATH'] = xonsh.built_ins.XSH.env.get_detyped('PATH')` at the end of a config to make sure they match) + ### Something else? Adding a new shell is not hard at all since very little shell code is @@ -490,7 +509,7 @@ Arguments: [SHELL_TYPE] Shell type to generate the script for - [possible values: bash, fish, zsh] + [possible values: bash, fish, xonsh, zsh] Options: -q, --quiet @@ -504,6 +523,7 @@ Examples: $ eval "$(rtx activate bash)" $ eval "$(rtx activate zsh)" $ rtx activate fish | source + $ execx($(rtx activate xonsh)) ``` ### `rtx alias ls` @@ -599,7 +619,7 @@ Arguments: [SHELL_TYPE] shell type to generate the script for - [possible values: bash, fish, zsh] + [possible values: bash, fish, xonsh, zsh] Options: -h, --help @@ -610,6 +630,7 @@ Examples: $ eval "$(rtx deactivate bash)" $ eval "$(rtx deactivate zsh)" $ rtx deactivate fish | source + $ execx($(rtx deactivate xonsh)) ``` ### `rtx direnv activate` @@ -674,7 +695,7 @@ Options: -s, --shell Shell type to generate environment variables for - [possible values: bash, fish, zsh] + [possible values: bash, fish, xonsh, zsh] -h, --help Print help (see a summary with '-h') @@ -684,6 +705,7 @@ Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" $ rtx env -s fish | source + $ execx($(rtx env -s xonsh)) ``` ### `rtx exec` diff --git a/completions/_rtx b/completions/_rtx index b7e096f3d..90eecb61f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -33,8 +33,8 @@ _rtx() { case $line[1] in (activate) _arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate the script for]:SHELL:(bash fish zsh)' \ -'--shell=[Shell type to generate the script for]:SHELL:(bash fish zsh)' \ +'-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ +'--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-q[Hide the "rtx: @" message when changing directories]' \ '--quiet[Hide the "rtx: @" message when changing directories]' \ @@ -42,7 +42,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::shell_type -- Shell type to generate the script for:(bash fish zsh)' \ +'::shell_type -- Shell type to generate the script for:(bash fish xonsh zsh)' \ && ret=0 ;; (alias) @@ -136,14 +136,14 @@ _arguments "${_arguments_options[@]}" \ ;; (deactivate) _arguments "${_arguments_options[@]}" \ -'-s+[shell type to generate the script for]:SHELL:(bash fish zsh)' \ -'--shell=[shell type to generate the script for]:SHELL:(bash fish zsh)' \ +'-s+[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ +'--shell=[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::shell_type -- shell type to generate the script for:(bash fish zsh)' \ +'::shell_type -- shell type to generate the script for:(bash fish xonsh zsh)' \ && ret=0 ;; (direnv) @@ -237,8 +237,8 @@ _arguments "${_arguments_options[@]}" \ ;; (env) _arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate environment variables for]:SHELL:(bash fish zsh)' \ -'--shell=[Shell type to generate environment variables for]:SHELL:(bash fish zsh)' \ +'-s+[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ +'--shell=[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -274,13 +274,13 @@ _arguments "${_arguments_options[@]}" \ ;; (hook-env) _arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate script for]:SHELL:(bash fish zsh)' \ -'--shell=[Shell type to generate script for]:SHELL:(bash fish zsh)' \ +'-s+[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ +'--shell=[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ +'-h[Print help]' \ +'--help[Print help]' \ && ret=0 ;; (install) diff --git a/completions/rtx.bash b/completions/rtx.bash index dcaa8ea56..ca5beda52 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -385,18 +385,18 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -v -h --shell --quiet --log-level --verbose --help bash fish zsh" + opts="-s -q -v -h --shell --quiet --log-level --verbose --help bash fish xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --shell) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; -s) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; --log-level) @@ -567,18 +567,18 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-s -v -h --shell --log-level --verbose --help bash fish zsh" + opts="-s -v -h --shell --log-level --verbose --help bash fish xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --shell) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; -s) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; --log-level) @@ -760,11 +760,11 @@ _rtx() { fi case "${prev}" in --shell) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; -s) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; --log-level) @@ -1366,11 +1366,11 @@ _rtx() { fi case "${prev}" in --shell) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; -s) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; --log-level) diff --git a/completions/rtx.fish b/completions/rtx.fish index 9066b1f96..726473604 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -26,7 +26,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'Hide the "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' @@ -57,7 +57,7 @@ complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' @@ -88,7 +88,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' @@ -101,10 +101,10 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0`' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' diff --git a/src/cli/activate.rs b/src/cli/activate.rs index eb627f80d..1923fa22b 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -52,6 +52,7 @@ Examples: $ eval "$(rtx activate bash)" $ eval "$(rtx activate zsh)" $ rtx activate fish | source + $ execx($(rtx activate xonsh)) "#; #[cfg(test)] diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 69621b595..5c51f5f13 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -36,6 +36,7 @@ Examples: $ eval "$(rtx deactivate bash)" $ eval "$(rtx deactivate zsh)" $ rtx deactivate fish | source + $ execx($(rtx deactivate xonsh)) "#; #[cfg(test)] diff --git a/src/cli/env.rs b/src/cli/env.rs index fb07c09e6..09353b650 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -51,6 +51,7 @@ Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" $ rtx env -s fish | source + $ execx($(rtx env -s xonsh)) "#; #[cfg(test)] diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index dc4b4f971..0d43ff8af 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -19,8 +19,6 @@ use crate::{dirs, env, hook_env}; #[clap(hide = true)] pub struct HookEnv { /// Shell type to generate script for - /// - /// e.g.: bash, zsh, fish #[clap(long, short)] shell: Option, } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 2d4747b0b..02d02904d 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -261,6 +261,25 @@ $ echo 'eval "$(rtx activate bash)"' >> ~/.bashrc $ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` +### Xonsh + +Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a bit off startup time by using a pure Python import: add the code below to, for example, `~/.config/xonsh/rtx.py` config file and `import rtx` it in `~/.config/xonsh/rc.xsh`: +```xsh +from pathlib import Path +from xonsh.built_ins import XSH + +ctx = XSH.ctx +rtx_init = subprocess.run([Path('~/bin/rtx').expanduser(),'activate','xonsh'],capture_output=True,encoding="UTF-8").stdout +XSH.builtins.execx(rtx_init,'exec',ctx,filename='rtx') +``` + +Or continue to use `rc.xsh`/`.xonshrc`: +```xsh +echo 'execx($(~/bin/rtx activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xonshrc +``` + +Given that `rtx` replaces both shell env `$PATH` and OS environ `PATH`, watch out that your configs don't have these two set differently (might throw `os.environ['PATH'] = xonsh.built_ins.XSH.env.get_detyped('PATH')` at the end of a config to make sure they match) + ### Something else? Adding a new shell is not hard at all since very little shell code is diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 67ac9fcb0..20515e96d 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -5,12 +5,14 @@ use crate::env; mod bash; mod fish; +mod xonsh; mod zsh; #[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)] pub enum ShellType { Bash, Fish, + Xonsh, Zsh, } @@ -21,6 +23,8 @@ impl ShellType { Some(ShellType::Bash) } else if shell.ends_with("fish") { Some(ShellType::Fish) + } else if shell.ends_with("xonsh") { + Some(ShellType::Xonsh) } else if shell.ends_with("zsh") { Some(ShellType::Zsh) } else { @@ -34,6 +38,7 @@ impl Display for ShellType { match self { Self::Bash => write!(f, "bash"), Self::Fish => write!(f, "fish"), + Self::Xonsh => write!(f, "xonsh"), Self::Zsh => write!(f, "zsh"), } } @@ -49,8 +54,9 @@ pub trait Shell { pub fn get_shell(shell: Option) -> Box { match shell.or_else(ShellType::load) { Some(ShellType::Bash) => Box::::default(), - Some(ShellType::Zsh) => Box::::default(), Some(ShellType::Fish) => Box::::default(), + Some(ShellType::Xonsh) => Box::::default(), + Some(ShellType::Zsh) => Box::::default(), _ => panic!("no shell provided, use `--shell=zsh`"), } } diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap new file mode 100644 index 000000000..3b21233f5 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap @@ -0,0 +1,16 @@ +--- +source: src/shell/xonsh.rs +expression: "Xonsh::default().activate(Path::new(\"/some/dir/rtx\"))" +--- +from os import environ +from xonsh.built_ins import XSH + +envx = XSH.env +envx['PATH'].add('/some/dir') +environ['PATH'] = envx.get_detyped('PATH') + +def listen_prompt(): # Hook Events + execx($(/some/dir/rtx hook-env -s xonsh)) + +XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt + diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__set_env.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__set_env.snap new file mode 100644 index 000000000..99a4fa213 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__set_env.snap @@ -0,0 +1,11 @@ +--- +source: src/shell/xonsh.rs +expression: "Xonsh::default().set_env(\"FOO\", \"1\")" +--- +from os import environ +from xonsh.built_ins import XSH + +envx = XSH.env +envx[ 'FOO'] = '1' +environ['FOO'] = envx.get_detyped('FOO') + diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap new file mode 100644 index 000000000..dc61fc800 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap @@ -0,0 +1,11 @@ +--- +source: src/shell/xonsh.rs +expression: "Xonsh::default().unset_env(\"FOO\")" +--- +from os import environ +from xonsh.built_ins import XSH + +envx = XSH.env +envx.pop[ 'FOO',None] +environ.pop['FOO',None] + diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs new file mode 100644 index 000000000..9db78ae28 --- /dev/null +++ b/src/shell/xonsh.rs @@ -0,0 +1,142 @@ +use std::path::Path; + +use indoc::formatdoc; + +use crate::shell::{is_dir_in_path, Shell}; + +#[derive(Default)] +pub struct Xonsh {} + +use std::borrow::Cow; +fn xonsh_escape_sq(input: &str) -> Cow { + for (i, ch) in input.chars().enumerate() { + if xonsh_escape_char(ch).is_some() { + let mut escaped_string = String::with_capacity(input.len()); + + escaped_string.push_str(&input[..i]); + for ch in input[i..].chars() { + match xonsh_escape_char(ch) { + Some(escaped_char) => escaped_string.push_str(escaped_char), + None => escaped_string.push(ch), + }; + } + return Cow::Owned(escaped_string); + } + } + Cow::Borrowed(input) +} + +fn xonsh_escape_char(ch: char) -> Option<&'static str> { + match ch { + // escape ' \ ⤠(docs.python.org/3/reference/lexical_analysis.html#strings) + '\'' => Some("\\'"), + '\\' => Some("\\\\"), + '\n' => Some("\\n"), + _ => None, + } +} + +impl Shell for Xonsh { + fn activate(&self, exe: &Path) -> String { + let dir = exe.parent().unwrap(); + let exe = exe.display(); + let mut out = String::new(); + + // todo: xonsh doesn't update the environment that rtx relies on with $PATH.add even with $UPDATE_OS_ENVIRON (github.com/xonsh/xonsh/issues/3207) + // with envx.swap(UPDATE_OS_ENVIRON=True): # ↠use when ↑ fixed before PATH.add; remove environ + // meanwhile, save variables twice: in shell env + in os env + // use xonsh API instead of $.xsh to allow use inside of .py configs, which start faster due to being compiled to .pyc + out.push_str(&formatdoc! {r#" + from os import environ + from xonsh.built_ins import XSH + + "#}); + if !is_dir_in_path(dir) { + let dir_str = dir.to_string_lossy(); + let dir_esc = xonsh_escape_sq(&dir_str); + out.push_str(&formatdoc! {r#" + envx = XSH.env + envx['PATH'].add('{dir_esc}') + environ['PATH'] = envx.get_detyped('PATH') + + "#}); + } + // todo: subprocess instead of $() is a bit faster, but lose auto-color detection (use $FORCE_COLOR) + out.push_str(&formatdoc! {r#" + def listen_prompt(): # Hook Events + execx($({exe} hook-env -s xonsh)) + + XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt + "#}); + + out + } + + fn deactivate(&self) -> String { + formatdoc! {r#" + from xonsh.built_ins import XSH + + hooks = {{ + 'on_pre_prompt' : ['listen_prompt'], + }} + for hook_type in hooks: + hook_fns = hooks[hook_type] + for hook_fn in hook_fns: + hndl = getattr(XSH.builtins.events, hook_type) + for fn in hndl: + if fn.__name__ == hook_fn: + hndl.remove(fn) + break + "#} + } + + fn set_env(&self, k: &str, v: &str) -> String { + let k = shell_escape::unix::escape(k.into()); // todo: drop illegal chars, not escape? + formatdoc!( + r#" + from os import environ + from xonsh.built_ins import XSH + + envx = XSH.env + envx[ '{k}'] = '{v}' + environ['{k}'] = envx.get_detyped('{k}') + "#, + k = shell_escape::unix::escape(k), // todo: drop illegal chars, not escape? + v = xonsh_escape_sq(v) + ) + } + + fn unset_env(&self, k: &str) -> String { + formatdoc!( + r#" + from os import environ + from xonsh.built_ins import XSH + + envx = XSH.env + envx.pop[ '{k}',None] + environ.pop['{k}',None] + "#, + k = shell_escape::unix::escape(k.into()) // todo: drop illegal chars, not escape? + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hook_init() { + insta::assert_snapshot!(Xonsh::default().activate(Path::new("/some/dir/rtx"))); + } + + #[test] + fn test_set_env() { + insta::assert_snapshot!(Xonsh::default().set_env("FOO", "1")); + } + + #[test] + fn test_unset_env() { + insta::assert_snapshot!(Xonsh::default().unset_env("FOO")); + } +} From 3cf97e1047bcde7369ddd5c5094d2d4def9007ea Mon Sep 17 00:00:00 2001 From: Alexander Moosbrugger Date: Sat, 4 Feb 2023 16:40:41 +0100 Subject: [PATCH 0098/1891] add e2e test for direnv unload path reset issue (#79) * add e2e test for direnv unload path reset issue * [chore] use nodejs version from other tests --- e2e/direnv/system_version/.tool-versions | 1 + .../load-first/.envrc | 3 + .../load-first/.tool-versions | 1 + .../system_version/test_direnv_system_version | 60 +++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 e2e/direnv/system_version/.tool-versions create mode 100644 e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.envrc create mode 100644 e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.tool-versions create mode 100755 e2e/direnv/system_version/test_direnv_system_version diff --git a/e2e/direnv/system_version/.tool-versions b/e2e/direnv/system_version/.tool-versions new file mode 100644 index 000000000..10edede5b --- /dev/null +++ b/e2e/direnv/system_version/.tool-versions @@ -0,0 +1 @@ +nodejs system diff --git a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.envrc b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.envrc new file mode 100644 index 000000000..906a9cb86 --- /dev/null +++ b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.envrc @@ -0,0 +1,3 @@ +# modifying the path relevant for the test case +PATH_add node_modules/.bin +export FIRST='first' diff --git a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.tool-versions b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.tool-versions new file mode 100644 index 000000000..35830be2c --- /dev/null +++ b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.tool-versions @@ -0,0 +1 @@ +nodejs 16.0.0 diff --git a/e2e/direnv/system_version/test_direnv_system_version b/e2e/direnv/system_version/test_direnv_system_version new file mode 100755 index 000000000..deef0a7fa --- /dev/null +++ b/e2e/direnv/system_version/test_direnv_system_version @@ -0,0 +1,60 @@ +#!/usr/bin/env zsh + +set -e + +eval "$(direnv hook zsh)" +eval "$(rtx activate -s zsh)" +_rtx_hook && _direnv_hook + +# prepare + +# use old node version on purpose to not conflict with unknown system node version +custom_node_version="16.0.0" +rtx_nodejs_path_segment="${RTX_DATA_DIR}/installs/nodejs" + +# with nodejs@system rtx should not add a nodejs path segment +if [[ $PATH == *"${rtx_nodejs_path_segment}"* ]]; then + echo "Rtx nodejs path segment: ${rtx_nodejs_path_segment} must not be in PATH: ${PATH}" + exit 1 +fi + +system_node_version=$(node -v) +# the test is only working, if system node version is not equal to custom node version +if [[ $system_node_version == "v${custom_node_version}" ]]; then + echo "Equal system node version: ${system_node_version} and rtx custom version: v${custom_node_version}" + exit 1 +fi + +# allow direnv to execute .envrc file +direnv allow rtx-direnv-system-version-reset/load-first + +# test + +# install custom nodejs version +rtx i nodejs@$custom_node_version && _rtx_hook + +cd rtx-direnv-system-version-reset/load-first && _rtx_hook && _direnv_hook +node_version=$(node -v) +if [[ $node_version != "v${custom_node_version}" ]]; then + echo "Invalid node version: ${node_version} Expected: v${custom_node_version}" + exit 1 +fi + +if [[ ! $PATH == *"${rtx_nodejs_path_segment}/${custom_node_version}"* ]]; then + echo "Rtx nodejs path segment: ${rtx_nodejs_path_segment}/${custom_node_version} must be in PATH: ${PATH}" + exit 1 +fi + +cd .. && _rtx_hook && _direnv_hook + +# with nodejs@system rtx should not add a nodejs path segment +if [[ $PATH == *"${rtx_nodejs_path_segment}"* ]]; then + echo "Rtx nodejs path segment: ${rtx_nodejs_path_segment} must not be in PATH: ${PATH}" + exit 1 +fi + +test_node_version=$(node -v) +if [[ $test_node_version != "${system_node_version}" ]]; then + echo "Invalid node version: ${test_node_version} Expected: ${system_node_version}" + exit 1 +fi From e6cd99d301a7c83e2efb1cafe20499b6cc80a06e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Feb 2023 10:19:20 -0600 Subject: [PATCH 0099/1891] bug: track added install paths (#89) then only remove those which were added once also remove those paths from DIRENV_DIFF --- .gitignore | 3 ++ CONTRIBUTING.md | 2 +- e2e/.e2e-tool-versions | 5 +++ e2e/.gitignore | 2 + e2e/cd/{.tool-versions => .e2e-tool-versions} | 0 .../16/{.tool-versions => .e2e-tool-versions} | 0 e2e/cd/test_bash | 19 ++++++++- e2e/direnv/no_tool_versions/test_direnv | 2 +- .../{.tool-versions => .e2e-tool-versions} | 0 .../{.tool-versions => .e2e-tool-versions} | 0 .../system_version/test_direnv_system_version | 1 - .../{.tool-versions => .e2e-tool-versions} | 0 .../18/{.tool-versions => .e2e-tool-versions} | 0 e2e/run_all_tests | 6 ++- e2e/run_test | 11 ++--- e2e/test_env | 1 + e2e/test_local | 12 ++++-- src/cli/hook_env.rs | 41 +++++++++++-------- src/config/mod.rs | 19 +++------ src/direnv.rs | 24 +++++++++-- src/env.rs | 32 +++++++++++++-- src/env_diff.rs | 5 ++- ...direnv__test__add_path_to_old_and_new.snap | 2 +- 23 files changed, 133 insertions(+), 54 deletions(-) create mode 100644 e2e/.e2e-tool-versions create mode 100644 e2e/.gitignore rename e2e/cd/{.tool-versions => .e2e-tool-versions} (100%) rename e2e/cd/16/{.tool-versions => .e2e-tool-versions} (100%) rename e2e/direnv/system_version/{.tool-versions => .e2e-tool-versions} (100%) rename e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/{.tool-versions => .e2e-tool-versions} (100%) rename e2e/gopath/{.tool-versions => .e2e-tool-versions} (100%) rename e2e/gopath/18/{.tool-versions => .e2e-tool-versions} (100%) diff --git a/.gitignore b/.gitignore index 006bb124b..d009fd0ae 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ **/snapshots/*.snap.new package-lock.json + +# ignore macos system file +.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e259f7937..d328267ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,7 +42,7 @@ with direnv. Here is my `.envrc`: ``` source_up_if_exists -PATH_add .bin +PATH_add "$(expand_path .bin)" ``` Now I can just run `rtx` as if I was using an installed version and it will build it from source everytime there are changes. diff --git a/e2e/.e2e-tool-versions b/e2e/.e2e-tool-versions new file mode 100644 index 000000000..c638108e3 --- /dev/null +++ b/e2e/.e2e-tool-versions @@ -0,0 +1,5 @@ +#python 3.11.1 3.10.9 # foo +shellcheck 0.9.0 +shfmt 3.6.0 # test comment +#nodejs 18.13.0 +jq latest diff --git a/e2e/.gitignore b/e2e/.gitignore new file mode 100644 index 000000000..1ed92b5eb --- /dev/null +++ b/e2e/.gitignore @@ -0,0 +1,2 @@ +.local +.rtx diff --git a/e2e/cd/.tool-versions b/e2e/cd/.e2e-tool-versions similarity index 100% rename from e2e/cd/.tool-versions rename to e2e/cd/.e2e-tool-versions diff --git a/e2e/cd/16/.tool-versions b/e2e/cd/16/.e2e-tool-versions similarity index 100% rename from e2e/cd/16/.tool-versions rename to e2e/cd/16/.e2e-tool-versions diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 2aa08886a..556c394f8 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -1,17 +1,32 @@ #!/usr/bin/env bash +# shellcheck disable=SC2088 set -euo pipefail +orig_path="$PATH" + rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 eval "$(rtx activate bash)" _rtx_hook -#rtx install +assert_path() { + local expected="${1//$HOME/\~}:" + local actual="${PATH/%$orig_path/}" + actual="${actual//$HOME/\~}" + if [[ "$actual" != "$expected" ]]; then + echo "Invalid PATH: $actual" + echo "Expected PATH: $expected" + exit 1 + fi +} + test "$(node -v)" = "v18.0.0" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" cd 16 && _rtx_hook -#rtx install test "$(node -v)" = "v16.0.0" +assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" diff --git a/e2e/direnv/no_tool_versions/test_direnv b/e2e/direnv/no_tool_versions/test_direnv index 7c8bbacab..3bcaf1386 100755 --- a/e2e/direnv/no_tool_versions/test_direnv +++ b/e2e/direnv/no_tool_versions/test_direnv @@ -4,7 +4,7 @@ set -e eval "$(direnv hook zsh)" eval "$(rtx activate zsh)" -_rtx_hook && _direnv_hook +_rtx_hook && direnv allow && _direnv_hook assert_go_version() { local expected="$1" diff --git a/e2e/direnv/system_version/.tool-versions b/e2e/direnv/system_version/.e2e-tool-versions similarity index 100% rename from e2e/direnv/system_version/.tool-versions rename to e2e/direnv/system_version/.e2e-tool-versions diff --git a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.tool-versions b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions similarity index 100% rename from e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.tool-versions rename to e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions diff --git a/e2e/direnv/system_version/test_direnv_system_version b/e2e/direnv/system_version/test_direnv_system_version index deef0a7fa..16712d361 100755 --- a/e2e/direnv/system_version/test_direnv_system_version +++ b/e2e/direnv/system_version/test_direnv_system_version @@ -5,7 +5,6 @@ set -e eval "$(direnv hook zsh)" eval "$(rtx activate -s zsh)" _rtx_hook && _direnv_hook - # prepare # use old node version on purpose to not conflict with unknown system node version diff --git a/e2e/gopath/.tool-versions b/e2e/gopath/.e2e-tool-versions similarity index 100% rename from e2e/gopath/.tool-versions rename to e2e/gopath/.e2e-tool-versions diff --git a/e2e/gopath/18/.tool-versions b/e2e/gopath/18/.e2e-tool-versions similarity index 100% rename from e2e/gopath/18/.tool-versions rename to e2e/gopath/18/.e2e-tool-versions diff --git a/e2e/run_all_tests b/e2e/run_all_tests index ca5673676..33bdd3451 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -1,9 +1,13 @@ #!/usr/bin/env bash set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" -ROOT="$PWD" +ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" FILES=$(find e2e -name 'test_*' -type f) for f in $FILES; do + if [[ "$f" == "e2e/.rtx/"* ]]; then + continue + fi "$ROOT/e2e/run_test" "$f" rm -f "$ROOT/e2e/.tool-versions" git checkout "$ROOT/.tool-versions" diff --git a/e2e/run_test b/e2e/run_test index efc1397f6..9a75e664e 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -1,17 +1,18 @@ #!/usr/bin/env bash set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" +ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)" +export ROOT export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" -export RTX_DATA_DIR="/tmp/rtx" -#export PATH="$PWD/target/debug:$PATH" +export RTX_DATA_DIR="$ROOT/e2e/.rtx" +export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions unset GOPATH -ROOT="$PWD" - TEST="$1" echo "Running $TEST" +export HOME="$ROOT/e2e" cd "$(dirname "$TEST")" "./$(basename "$TEST")" rm -f "$ROOT/e2e/.tool-versions" -git checkout "$ROOT/.tool-versions" diff --git a/e2e/test_env b/e2e/test_env index 6cc06d0e0..a75aec84b 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -2,6 +2,7 @@ . ./assert.sh +rtx i nodejs@16.0.0 eval "$(rtx env -s bash nodejs@16.0.0)" assert "node -v" "v16.0.0" diff --git a/e2e/test_local b/e2e/test_local index 7db1c2893..66a8d79fb 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -4,17 +4,16 @@ export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall -git checkout ../.tool-versions assert_raises "rtx uninstall shfmt@3.6.0 shfmt@3.5.0" -assert "rtx local -p" "#python 3.11.1 3.10.9 # foo +assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 jq latest " -assert "rtx local -p shfmt@3.5.0" "#python 3.11.1 3.10.9 # foo +assert "rtx local shfmt@3.5.0" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.5.0 # test comment #nodejs 18.13.0 @@ -26,7 +25,12 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi -assert "rtx local shfmt@3.6.0" "shfmt 3.6.0" +assert "rtx local shfmt@3.6.0" "#python 3.11.1 3.10.9 # foo +shellcheck 0.9.0 +shfmt 3.6.0 # test comment +#nodejs 18.13.0 +jq latest +" rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 0d43ff8af..a2abbf990 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,18 +1,19 @@ +use color_eyre::eyre::Result; +use itertools::Itertools; + use std::env::join_paths; use std::ops::Deref; use std::path::PathBuf; -use color_eyre::eyre::Result; -use itertools::Itertools; - use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::direnv::DirenvDiff; +use crate::env::__RTX_DIFF; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -use crate::{dirs, env, hook_env}; +use crate::{env, hook_env}; /// [internal] called by activate hook to update env vars directory change #[derive(Debug, clap::Args)] @@ -32,10 +33,13 @@ impl Command for HookEnv { self.clear_old_env(out); let env = config.env()?; - let diff = EnvDiff::new(&env::PRISTINE_ENV, env); + let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); - patches.extend(self.build_path_operations(&config)?); + let installs = config.list_paths()?; // load the active runtime paths + diff.path = installs.clone(); // update __RTX_DIFF with the new paths for the next run + + patches.extend(self.build_path_operations(&installs, &__RTX_DIFF.path)?); patches.push(self.build_diff_operation(&diff)?); patches.push(self.build_watch_operation(&config)?); @@ -67,7 +71,10 @@ impl HookEnv { } fn clear_old_env(&self, out: &mut Output) { - let patches = env::__RTX_DIFF.reverse().to_patches(); + let mut patches = env::__RTX_DIFF.reverse().to_patches(); + if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { + patches.push(EnvDiffOperation::Change("PATH".into(), path.to_string())); + } let output = self.build_env_commands(&patches); out.stdout.write(output); } @@ -85,20 +92,18 @@ impl HookEnv { } /// modifies the PATH and optionally DIRENV_DIFF env var if it exists - fn build_path_operations(&self, config: &Config) -> Result> { - let installs = config.list_paths()?; - let other = env::PATH - .clone() - .into_iter() - .filter(|p| !p.starts_with(dirs::INSTALLS.deref())) - .collect_vec(); - let new_path = join_paths([installs.clone(), other].concat())? + fn build_path_operations( + &self, + installs: &Vec, + to_remove: &Vec, + ) -> Result> { + let new_path = join_paths([installs.clone(), env::PATH.clone()].concat())? .to_string_lossy() .to_string(); let mut ops = vec![EnvDiffOperation::Add("PATH".into(), new_path)]; if let Some(input) = env::DIRENV_DIFF.deref() { - match self.update_direnv_diff(input, &installs) { + match self.update_direnv_diff(input, installs, to_remove) { Ok(Some(op)) => { ops.push(op); } @@ -117,11 +122,15 @@ impl HookEnv { &self, input: &str, installs: &Vec, + to_remove: &Vec, ) -> Result> { let mut diff = DirenvDiff::parse(input)?; if diff.new_path().is_empty() { return Ok(None); } + for path in to_remove { + diff.remove_path_from_old_and_new(path)?; + } for install in installs { diff.add_path_to_old_and_new(install)?; } diff --git a/src/config/mod.rs b/src/config/mod.rs index 5faa4e47b..dfdd85584 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,10 +1,3 @@ -use std::collections::HashMap; -use std::env::join_paths; -use std::fmt::{Display, Formatter}; -use std::ops::Deref; -use std::path::{Path, PathBuf}; -use std::sync::Arc; - use color_eyre::eyre::{eyre, Result, WrapErr}; use color_eyre::Report; use indexmap::IndexMap; @@ -13,6 +6,11 @@ use rayon::prelude::*; pub use plugin_source::PluginSource; pub use settings::{MissingRuntimeBehavior, Settings}; +use std::collections::HashMap; +use std::env::join_paths; +use std::fmt::{Display, Formatter}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; use crate::cli::args::runtime::RuntimeArg; use crate::config::config_file::legacy_version::LegacyVersionFile; @@ -94,12 +92,7 @@ impl Config { pub fn path_env(&self) -> Result { let installs = self.list_paths()?; - let other = env::PATH - .clone() - .into_iter() - .filter(|p| !p.starts_with(dirs::INSTALLS.deref())) - .collect_vec(); - Ok(join_paths([installs, other].concat())? + Ok(join_paths([installs, env::PATH.clone()].concat())? .to_string_lossy() .into()) } diff --git a/src/direnv.rs b/src/direnv.rs index f27378eb6..3bc0fd7e1 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -8,6 +8,7 @@ use std::collections::HashMap; use std::env::{join_paths, split_paths}; use std::fmt::{Display, Formatter}; use std::io::Write; + use std::path::{Path, PathBuf}; #[derive(Debug, Serialize, Deserialize)] @@ -50,15 +51,11 @@ impl DirenvDiff { /// this adds a directory to both the old and new path in DIRENV_DIFF /// the purpose is to trick direnv into thinking that this path has always been there /// that way it does not remove it when it modifies PATH - /// if the directory exists it is first removed, then added to the front of the list /// it returns the old and new paths as vectors pub fn add_path_to_old_and_new(&mut self, path: &Path) -> Result<(Vec, Vec)> { let mut old = self.old_path(); let mut new = self.new_path(); - old.retain(|p| p != path); - new.retain(|p| p != path); - old.insert(0, path.into()); new.insert(0, path.into()); @@ -70,6 +67,25 @@ impl DirenvDiff { Ok((old, new)) } + pub fn remove_path_from_old_and_new( + &mut self, + path: &Path, + ) -> Result<(Vec, Vec)> { + let mut old = self.old_path(); + let mut new = self.new_path(); + + // remove the path from both old and new but only once + old.iter().position(|p| p == path).map(|i| old.remove(i)); + new.iter().position(|p| p == path).map(|i| new.remove(i)); + + self.old + .insert("PATH".into(), join_paths(&old)?.into_string().unwrap()); + self.new + .insert("PATH".into(), join_paths(&new)?.into_string().unwrap()); + + Ok((old, new)) + } + pub fn dump(&self) -> Result { let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); gz.write_all(&serde_json::to_vec(self)?)?; diff --git a/src/env.rs b/src/env.rs index cd865810c..7157cea2c 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,7 +1,8 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; pub use std::env::*; use std::path::PathBuf; +use itertools::Itertools; use lazy_static::lazy_static; use log::LevelFilter; @@ -86,8 +87,10 @@ lazy_static! { /// essentially, this is whether we show spinners or build output on runtime install pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); - pub static ref PATH: Vec = - split_paths(&var_os("PATH").unwrap_or_default()).collect(); + pub static ref PATH: Vec = match PRISTINE_ENV.get("PATH") { + Some(path) => split_paths(path).collect(), + None => vec![], + }; pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String = if cfg!(test) { ".tool-versions".into() } else { @@ -132,7 +135,28 @@ fn get_pristine_env( orig_env: HashMap, ) -> HashMap { let patches = rtx_diff.reverse().to_patches(); - apply_patches(&orig_env, &patches) + let mut env = apply_patches(&orig_env, &patches); + + // get the current path as a vector + let path = match env.get("PATH") { + Some(path) => split_paths(path).collect(), + None => vec![], + }; + // get the paths that were removed by rtx as a hashset + let mut to_remove = rtx_diff.path.iter().collect::>(); + + // remove those paths that were added by rtx, but only once (the first time) + let path = path + .into_iter() + .filter(|p| !to_remove.remove(p)) + .collect_vec(); + + // put the pristine PATH back into the environment + env.insert( + "PATH".into(), + join_paths(path).unwrap().to_string_lossy().to_string(), + ); + env } fn apply_patches( diff --git a/src/env_diff.rs b/src/env_diff.rs index 862dc2990..51fd8e663 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::fmt::Debug; use std::io::prelude::*; -use std::path::Path; +use std::path::{Path, PathBuf}; use base64::prelude::*; use color_eyre::eyre::Result; @@ -19,6 +19,8 @@ pub struct EnvDiff { pub old: HashMap, #[serde(default)] pub new: HashMap, + #[serde(default)] + pub path: Vec, } #[derive(Debug)] @@ -145,6 +147,7 @@ impl EnvDiff { EnvDiff { old: self.new.clone(), new: self.old.clone(), + path: self.path.clone(), } } } diff --git a/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap b/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap index fa18f8d18..4c11af15a 100644 --- a/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap +++ b/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap @@ -2,4 +2,4 @@ source: src/direnv.rs expression: "diff.old.get(\"PATH\").unwrap()" --- -/tmp:/foo:/bar:/old +/tmp:/foo:/tmp:/bar:/old From 485c063ecbdd50857b35320262e861ccbab42e38 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Feb 2023 10:19:42 -0600 Subject: [PATCH 0100/1891] chore: Release rtx-cli version 1.5.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bad3da2c3..a77750d16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.4.0" +version = "1.5.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 30171f77a..eee529931 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.4.0" +version = "1.5.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 081898086..adb4657f9 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.4.0 +rtx 1.5.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -171,7 +171,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.4.0/rtx-v1.4.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.0/rtx-v1.5.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b10c789a4..593220151 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.4.0 +Version: 1.5.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 02d02904d..906311e70 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -189,7 +189,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.4.0/rtx-v1.4.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.0/rtx-v1.5.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 69e17aa0e3fb49f5d6f0fe631a0062a807a6dcbc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Feb 2023 18:17:33 -0600 Subject: [PATCH 0101/1891] ignore exported functions Fixes #103 --- completions/_rtx | 2 +- src/env_diff.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/completions/_rtx b/completions/_rtx index 90eecb61f..40be14ca1 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -596,7 +596,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':runtime -- runtime(s) to remove:' \ +':runtime -- runtime(s) to look up:' \ '::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ && ret=0 ;; diff --git a/src/env_diff.rs b/src/env_diff.rs index 51fd8e663..2c5aa763a 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -91,6 +91,7 @@ impl EnvDiff { || k == "SHELLOPTS" || k == "COMP_WORDBREAKS" || k == "PS1" + || k.is_empty() // this happens when exporting a function (export -f) // TODO: consider removing this // this is to make the ruby plugin compatible, // it causes ruby to attempt to call asdf to reshim the binaries From b346df13eb22b1d3ae4d8b16b9b4ce49faadae87 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Feb 2023 10:34:49 -0600 Subject: [PATCH 0102/1891] chore: enable line numbers in backtrace this does not seem to meaningfully impact performance, if it does it appears to be <1ms. It does increase binary size from 6.3M to 8.4M, but I think the trade-off is worth it for now. With this in place it will be easier for users to diagnose issues with rtx. --- Cargo.toml | 1 + completions/_rtx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index eee529931..f9af7af44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ pretty_assertions = "1.3.0" tempfile = "3.3.0" [profile.release] +debug = 1 # show line numbers in backtrace [profile.release-fast] inherits = "release" diff --git a/completions/_rtx b/completions/_rtx index 40be14ca1..90eecb61f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -596,7 +596,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':runtime -- runtime(s) to look up:' \ +':runtime -- runtime(s) to remove:' \ '::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ && ret=0 ;; From 9b9018de3bca832a0620011a7133e89d4bdbf76e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Feb 2023 10:46:04 -0600 Subject: [PATCH 0103/1891] bug: handle any error with config file parsing in this case we will just skip that file rather than crashing Fixes #100 --- src/config/mod.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index dfdd85584..e57facd18 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -232,18 +232,25 @@ fn load_config_files( let parsed_config_files = config_files .into_par_iter() .rev() - .map(|path| { + .filter_map(|path| { let filename = path.file_name().unwrap().to_string_lossy().to_string(); - match legacy_filenames.get(&filename) { + let result = match legacy_filenames.get(&filename) { Some(plugin) => { let plugin = ts.find_plugin(plugin).unwrap(); - let cf = LegacyVersionFile::parse(path.into(), &plugin)?; - Ok(Box::new(cf) as Box) + LegacyVersionFile::parse(path.into(), &plugin) + .map(|cf| Box::new(cf) as Box) } None => config_file::parse(path), + }; + match result { + Ok(cf) => Some(cf), + Err(e) => { + warn!("error parsing config file: {}", e); + None + } } }) - .collect::>>()?; + .collect::>(); for cf in parsed_config_files { let path = cf.get_path().to_path_buf(); From 977ddfe35a2f7a6cf5011e0e0c4eeea859a142d1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Feb 2023 10:47:32 -0600 Subject: [PATCH 0104/1891] bug: if bin/parse_legacy_file does not exist then we skip it and just read the legacy file as the raw version Fixes #100 --- src/plugins/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 0d362fda1..f57c61e67 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -382,11 +382,13 @@ impl Plugin { return Ok(cached); } trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); - let legacy_version = self - .script_man - .read(ParseLegacyFile(legacy_file.to_string_lossy().into()))? - .trim() - .to_string(); + let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); + let legacy_version = match self.script_man.script_exists(&script) { + true => self.script_man.read(script)?, + false => fs::read_to_string(legacy_file)?, + } + .trim() + .to_string(); self.write_legacy_cache(legacy_file, &legacy_version)?; Ok(legacy_version) From bbad73e3b81f6e43fb8b833fce88ecb1a772a59b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Feb 2023 10:49:44 -0600 Subject: [PATCH 0105/1891] chore: Release rtx-cli version 1.5.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a77750d16..cae77c45e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.5.0" +version = "1.5.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index f9af7af44..c59e94f01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.5.0" +version = "1.5.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index adb4657f9..8b067d5a5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.5.0 +rtx 1.5.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -171,7 +171,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.0/rtx-v1.5.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.1/rtx-v1.5.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 593220151..6bcbe0108 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.5.0 +Version: 1.5.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 906311e70..028f9c348 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -189,7 +189,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.0/rtx-v1.5.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.1/rtx-v1.5.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From b522ad8aac0abdef998c476b7a0a29cd63442cea Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Feb 2023 09:26:15 -0600 Subject: [PATCH 0106/1891] adding newlines to option help --- README.md | 10 +++++++--- completions/_rtx | 10 +++++++--- completions/rtx.fish | 7 +++++-- src/cli/local.rs | 6 +++--- src/cli/plugins/install.rs | 2 +- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 8b067d5a5..4a4d90afe 100644 --- a/README.md +++ b/README.md @@ -871,10 +871,13 @@ Arguments: Options: -p, --parent - recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") + recurse up to find a .tool-versions file rather than using the current directory only + by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") --fuzzy - save fuzzy match to .tool-versions e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions by default it would save the exact version, e.g.: `nodejs 20.0.0` + save fuzzy match to .tool-versions + e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions + without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0` --remove remove the plugin(s) from .tool-versions @@ -986,7 +989,8 @@ Options: -a, --all Install all missing plugins - This will only install plugins that have matching shortnames. i.e.: they don't need the full git repo url + This will only install plugins that have matching shortnames. + i.e.: they don't need the full git repo url -v, --verbose... Show installation output diff --git a/completions/_rtx b/completions/_rtx index 90eecb61f..0be4e8518 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -314,9 +314,13 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from .tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-p[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ -'--parent[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ -'--fuzzy[save fuzzy match to .tool-versions e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions by default it would save the exact version, e.g.: `nodejs 20.0.0`]' \ +'-p[recurse up to find a .tool-versions file rather than using the current directory only +by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ +'--parent[recurse up to find a .tool-versions file rather than using the current directory only +by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ +'--fuzzy[save fuzzy match to .tool-versions +e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions +without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0`]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 726473604..878e19326 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -116,8 +116,11 @@ complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'save fuzzy match to .tool-versions e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions by default it would save the exact version, e.g.: `nodejs 20.0.0`' +complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only +by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'save fuzzy match to .tool-versions +e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions +without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0`' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r diff --git a/src/cli/local.rs b/src/cli/local.rs index dce2621c3..a159efb54 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -22,13 +22,13 @@ pub struct Local { /// recurse up to find a .tool-versions file rather than using the current directory only /// by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") - #[clap(short, long)] + #[clap(short, long, verbatim_doc_comment)] parent: bool, /// save fuzzy match to .tool-versions /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions - /// by default it would save the exact version, e.g.: `nodejs 20.0.0` - #[clap(long)] + /// without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0` + #[clap(long, verbatim_doc_comment)] fuzzy: bool, /// remove the plugin(s) from .tool-versions diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index d42e949da..788cbea92 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -38,7 +38,7 @@ pub struct PluginsInstall { /// /// This will only install plugins that have matching shortnames. /// i.e.: they don't need the full git repo url - #[clap(short, long, conflicts_with_all = ["name", "force"])] + #[clap(short, long, conflicts_with_all = ["name", "force"], verbatim_doc_comment)] all: bool, /// Show installation output From 2b2e64a752f09550b481912481ad80e2bbd11520 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Feb 2023 09:57:33 -0600 Subject: [PATCH 0107/1891] bug: fix issue with HOME/~ replacement If HOME was in the middle of the PATH like /local/home/jdx/something, then we should NOT replace that with /local/~/something, just return the original path Fixes #81 --- src/file.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/file.rs b/src/file.rs index 3efb55439..f3b27a9ff 100644 --- a/src/file.rs +++ b/src/file.rs @@ -11,9 +11,13 @@ pub fn basename(path: &Path) -> Option { path.file_name().map(|f| f.to_string_lossy().to_string()) } +/// replaces $HOME with "~" pub fn display_path(path: &Path) -> String { let home = dirs::HOME.to_string_lossy(); - path.to_string_lossy().replace(home.as_ref(), "~") + match path.starts_with(home.as_ref()) { + true => path.to_string_lossy().replacen(home.as_ref(), "~", 1), + false => path.to_string_lossy().to_string(), + } } pub fn changed_within(f: &Path, within: Duration) -> Result { @@ -117,6 +121,8 @@ impl Iterator for FindUp { #[cfg(test)] mod test { + use std::ops::Deref; + use crate::dirs; use super::*; @@ -154,4 +160,15 @@ mod test { let subdirs = dir_subdirs(dirs::HOME.as_path()).unwrap(); assert!(subdirs.contains(&"cwd".to_string())); } + + #[test] + fn test_display_path() { + let path = dirs::HOME.join("cwd"); + assert_eq!(display_path(&path), "~/cwd"); + + let path = Path::new("/tmp") + .join(dirs::HOME.deref().strip_prefix("/").unwrap()) + .join("cwd"); + assert_eq!(display_path(&path), path.display().to_string()); + } } From a80d3d8ba20b31d0ce7b82db1883802a0eff9b9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 10:29:46 -0600 Subject: [PATCH 0108/1891] Bump toml from 0.7.0 to 0.7.1 (#107) Bumps [toml](https://github.com/toml-rs/toml) from 0.7.0 to 0.7.1. - [Release notes](https://github.com/toml-rs/toml/releases) - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.7.0...toml-v0.7.1) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cae77c45e..2d086b960 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1136,9 +1136,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c68e921cef53841b8925c2abadd27c9b891d9613bdc43d6b823062866df38e8" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" dependencies = [ "serde", ] @@ -1333,9 +1333,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "toml" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f560bc7fb3eb31f5eee1340c68a2160cad39605b7b9c9ec32045ddbdee13b85" +checksum = "772c1426ab886e7362aedf4abc9c0d1348a979517efedfc25862944d10137af0" dependencies = [ "serde", "serde_spanned", @@ -1345,18 +1345,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886f31a9b85b6182cabd4d8b07df3b451afcc216563748201490940d2a28ed36" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d8716cdc5d20ec88a18a839edaf545edc71efa4a5ff700ef4a102c26cd8fa" +checksum = "90a238ee2e6ede22fb95350acc78e21dc40da00bb66c0334bde83de4ed89424e" dependencies = [ "indexmap", "nom8", diff --git a/Cargo.toml b/Cargo.toml index c59e94f01..087c5e028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ shell-escape = "0.1.5" simplelog = { version = "0.12.0", features = ["paris"] } spinoff = "0.7.0" thiserror = "1.0.38" -toml = "0.7.0" +toml = "0.7.1" toml_edit = "0.19.0" url = "2.3.1" versions = "4.1.0" From a1e169664f8e016a15522e9aeb9067ce7e4ec913 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 10:30:08 -0600 Subject: [PATCH 0109/1891] Bump serde_json from 1.0.91 to 1.0.92 (#105) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.91 to 1.0.92. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.91...v1.0.92) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d086b960..bd9e9b607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1125,9 +1125,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 087c5e028..e7531a298 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ regex = "1.7.1" rmp-serde = "1.1.1" serde = "1.0.152" serde_derive = "1.0.152" -serde_json = "1.0.91" +serde_json = "1.0.92" shell-escape = "0.1.5" simplelog = { version = "0.12.0", features = ["paris"] } spinoff = "0.7.0" From 07bdf56cc3e8d8b0774cdadb6daa4575204ae79a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Feb 2023 10:42:38 -0600 Subject: [PATCH 0110/1891] bug: use exact version match (#114) before it would use the latest matching prefix so python@3.9.1 would resolve to python@3.9.16 Fixes #111 --- src/plugins/mod.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index f57c61e67..b97fa19d0 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -194,18 +194,18 @@ impl Plugin { r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" ).unwrap(); } - let query = String::from(r"^\s*") + query; - let query_regex = Regex::new(&query)?; - let latest = self + let query_regex = Regex::new((String::from(r"^\s*") + query).as_str())?; + let matches = self .get_cache()? .versions - .iter() + .into_iter() .filter(|v| !VERSION_REGEX.is_match(v)) .filter(|v| query_regex.is_match(v)) - .last() - .map(|v| v.into()); - - Ok(latest) + .collect_vec(); + match matches.contains(&query.to_string()) { + true => Ok(Some(query.to_string())), + false => Ok(matches.last().map(|v| v.to_string())), + } } pub fn legacy_filenames(&self) -> Result> { @@ -444,4 +444,12 @@ mod test { let version = plugin.parse_legacy_file(&gemfile).unwrap(); assert_str_eq!(version, "3.0.5"); } + + #[test] + fn test_exact_match() { + assert_cli!("plugin", "add", "python"); + let plugin = Plugin::load(&PluginName::from("python")).unwrap(); + let version = plugin.latest_version("3.9.1").unwrap().unwrap(); + assert_str_eq!(version, "3.9.1"); + } } From 52f9c25de9946dd4b5f7eec10d8a726208ea8447 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:29:55 -0600 Subject: [PATCH 0111/1891] bug: RTX_QUIET should still show warnings Fixes #109 --- src/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env.rs b/src/env.rs index 7157cea2c..8bbb3f51e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -61,7 +61,7 @@ lazy_static! { } else if *RTX_DEBUG { log::LevelFilter::Debug } else if *RTX_QUIET { - log::LevelFilter::Error + log::LevelFilter::Warn } else { log::LevelFilter::Info } From a75f7d54a8623d7fd3d9ac441472f497bc12074b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:35:22 -0600 Subject: [PATCH 0112/1891] chore: Release rtx-cli version 1.5.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd9e9b607..b4e3315ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.5.1" +version = "1.5.2" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index e7531a298..1fbd13bfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.5.1" +version = "1.5.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 4a4d90afe..dad635700 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.5.1 +rtx 1.5.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -171,7 +171,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.1/rtx-v1.5.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.2/rtx-v1.5.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6bcbe0108..84309efbc 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.5.1 +Version: 1.5.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 028f9c348..2b81205aa 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -189,7 +189,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.1/rtx-v1.5.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.2/rtx-v1.5.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 15e33a05deb57a9f06b8944cf47b947096e14426 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Feb 2023 14:48:13 -0600 Subject: [PATCH 0113/1891] bug: fix ls output to be more aligned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit before: ``` ~/src/rtx main ≡ ❯ rtx ls golang 1.18.10 -> golang 1.19.5 (set by ~/.tool-versions) golang 1.20 gradle 7.6 -> hadolint 2.10.0 (set by ~/.tool-versions) -> java openjdk-19.0.2 (set by ~/.tool-versions) -> jq 1.6 (set by ~/src/rtx/.tool-versions) nodejs 16.0.0 nodejs 17.7.1 -> nodejs 18.13.0 (set by ~/src/rtx/.node-version) python 3.9.1 python 3.10.9 python 3.11.1 -> ruby 3.2.0 (set by ~/.tool-versions) -> rust 1.67.0 (set by ~/.tool-versions) shellcheck 0.7.2 -> shellcheck 0.9.0 (set by ~/src/rtx/.tool-versions) shfmt 3.6.0 (missing) (set by ~/src/rtx/.tool-versions) ``` After: ``` ~/src/rtx main î­„ ❯ rtx ls golang 1.18.10 -> golang 1.19.5 (set by ~/.tool-versions) golang 1.20 gradle 7.6 -> hadolint 2.10.0 (set by ~/.tool-versions) -> java openjdk-19.0.2 (set by ~/.tool-versions) -> jq 1.6 (set by ~/src/rtx/.tool-versions) nodejs 16.0.0 nodejs 17.7.1 -> nodejs 18.13.0 (set by ~/src/rtx/.node-version) python 3.9.1 python 3.10.9 python 3.11.1 -> ruby 3.2.0 (set by ~/.tool-versions) -> rust 1.67.0 (set by ~/.tool-versions) shellcheck 0.7.2 -> shellcheck 0.9.0 (set by ~/src/rtx/.tool-versions) shfmt 3.6.0 (missing) (set by ~/src/rtx/.tool-versions) ``` --- src/cli/ls.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index cbbfdf423..88a642eea 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -39,13 +39,12 @@ impl Command for Ls { } rtxprintln!( out, - "{} {:10} {:10} {}", + "{} {} {}", match rtv.is_installed() && source.is_some() { true => "->", false => " ", }, - cyan(Stdout, &rtv.plugin.name), - styled_version(&rtv.version, !rtv.is_installed(), source.is_some()), + styled_version(&rtv, !rtv.is_installed(), source.is_some()), match source { Some(source) => format!("(set by {source})"), None => "".into(), @@ -57,25 +56,30 @@ impl Command for Ls { } } -fn styled_version(version: &String, missing: bool, active: bool) -> String { +fn styled_version(rtv: &RuntimeVersion, missing: bool, active: bool) -> String { let styled = if missing { - version + rtv.version .if_supports_color(Stream::Stdout, |t| t.strikethrough().red().to_string()) .to_string() + red(Stdout, " (missing)").as_str() } else if active { - green(Stdout, version) + green(Stdout, &rtv.version) } else { - dimmed(Stdout, version) + dimmed(Stdout, &rtv.version) }; let unstyled = if missing { - format!("{version} (missing)") + format!("{} {} (missing)", &rtv.plugin.name, &rtv.version) } else { - version.to_string() + format!("{} {}", &rtv.plugin.name, &rtv.version) }; - let pad = max(0, 18isize - unstyled.len() as isize) as usize; - format!("{}{}", styled, " ".repeat(pad)) + let pad = max(0, 25 - unstyled.len() as isize) as usize; + format!( + "{} {}{}", + cyan(Stdout, &rtv.plugin.name), + styled, + " ".repeat(pad) + ) } fn get_runtime_list( From 32eb1b2879c63f7635264d26313b8894ee8c4043 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Feb 2023 15:50:25 -0600 Subject: [PATCH 0114/1891] test: fix the build --- src/cli/local.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/local.rs b/src/cli/local.rs index a159efb54..6c891a01f 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -121,7 +121,7 @@ mod test { let stdout = assert_cli!("ls", "--current"); assert_str_eq!( grep(stdout, "nodejs"), - " nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)" + " nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)" ); let stdout = assert_cli!("local", "tiny@1"); assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); From 828abd3a02b99d22bd8b389116eaaa6f53d1b879 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:49:07 -0600 Subject: [PATCH 0115/1891] bug: handle .ruby-version and Gemfile properly I had not considered what would happen when there were 2 legacy versionfiles, which is likely with ruby when you would have `.ruby-version` and `Gemfile` in the same directory. This fixes 2 bugs with that situation, first, if the Gemfile did not specify a ruby version the script returns nothing. In that case, the legacy file should fall through and it should go to .ruby-version or .tool-versions ignoring the Gemfile. The other is that I was using HashMap for the legacy version files which ignored the ordering specified by the plugin. `.ruby-version` is supposed to be parsed _before_ `Gemfile`. In the previous behavior that was nondeterministic --- src/config/config_file/legacy_version.rs | 6 +++++- src/config/mod.rs | 15 +++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 87a673b28..879ffa4ff 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -42,7 +42,11 @@ impl ConfigFile for LegacyVersionFile { } fn plugins(&self) -> IndexMap> { - IndexMap::from([(self.plugin.clone(), vec![self.version.clone()])]) + if self.version.is_empty() { + IndexMap::new() + } else { + IndexMap::from([(self.plugin.clone(), vec![self.version.clone()])]) + } } fn env(&self) -> HashMap { diff --git a/src/config/mod.rs b/src/config/mod.rs index e57facd18..67a8f7876 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -182,9 +182,12 @@ fn load_installed_runtimes(ts: &mut Toolset) -> Result<()> { Ok(()) } -fn load_legacy_filenames(settings: &Settings, ts: &Toolset) -> Result> { +fn load_legacy_filenames( + settings: &Settings, + ts: &Toolset, +) -> Result> { if !settings.legacy_version_file { - return Ok(HashMap::new()); + return Ok(IndexMap::new()); } let filenames = ts .list_plugins() @@ -199,11 +202,11 @@ fn load_legacy_filenames(settings: &Settings, ts: &Toolset) -> Result>>>()? .into_iter() .flatten() - .collect::>(); + .collect::>(); Ok(filenames) } -fn find_all_config_files(legacy_filenames: &HashMap) -> Vec { +fn find_all_config_files(legacy_filenames: &IndexMap) -> Vec { let mut filenames = vec![ // ".rtxrc.toml", // ".rtxrc", @@ -227,7 +230,7 @@ fn find_all_config_files(legacy_filenames: &HashMap) -> Vec< fn load_config_files( ts: &mut Toolset, config_files: &Vec, - legacy_filenames: &HashMap, + legacy_filenames: &IndexMap, ) -> Result<()> { let parsed_config_files = config_files .into_par_iter() @@ -270,7 +273,7 @@ fn load_config_file(ts: &mut Toolset, cf: Box) -> Result<()> { Ok(()) } -fn load_runtime_env(ts: &mut Toolset, env: HashMap) -> Result<()> { +fn load_runtime_env(ts: &mut Toolset, env: IndexMap) -> Result<()> { for (k, v) in env { if k.starts_with("RTX_") && k.ends_with("_VERSION") { let plugin_name = k[4..k.len() - 8].to_lowercase(); From b5706f468fd4415f2eb402821448cf4a3bce586f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:50:06 -0600 Subject: [PATCH 0116/1891] chore: Release rtx-cli version 1.5.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b4e3315ac..86c7ee133 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.5.2" +version = "1.5.3" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 1fbd13bfe..0eaca9c4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.5.2" +version = "1.5.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index dad635700..c24e8f5f4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.5.2 +rtx 1.5.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -171,7 +171,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.2/rtx-v1.5.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.3/rtx-v1.5.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 84309efbc..4e472ca18 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.5.2 +Version: 1.5.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 2b81205aa..810aa31e8 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -189,7 +189,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.2/rtx-v1.5.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.3/rtx-v1.5.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From e7db3aa39d6134a58ab3389cbda000483827ebe5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:51:32 -0600 Subject: [PATCH 0117/1891] chore: simplified aur packaging --- scripts/release-aur.sh | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 0894222e3..a078a6693 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -18,42 +18,32 @@ pkgdesc='Polyglot runtime manager' arch=('x86_64') url='https://github.com/jdxcode/rtx' license=('MIT') -makedepends=('cargo' 'jq') +makedepends=('cargo') provides=('rtx') conflicts=('rtx') source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdxcode/\$pkgname/archive/v\$pkgver.tar.gz") sha512sums=('$SHA512') prepare() { - cd "\$pkgname-\$pkgver" - + cd "\$srcdir/\$pkgname-\$pkgver" cargo fetch --locked --target "\$CARCH-unknown-linux-gnu" } build() { - cd "\$pkgname-\$pkgver" - + cd "\$srcdir/\$pkgname-\$pkgver" export RUSTUP_TOOLCHAIN=stable export CARGO_TARGET_DIR=target - cargo build --release --locked --message-format=json-render-diagnostics | - jq -r 'select(.out_dir) | select(.package_id | startswith("ripgrep ")) | .out_dir' > out_dir + cargo build --frozen --release } package() { - cd "\$pkgname-\$pkgver" - local OUT_DIR=\$( Date: Wed, 8 Feb 2023 12:43:41 -0600 Subject: [PATCH 0118/1891] docs: mention direnv must be activated after rtx --- README.md | 32 ++++++++++++++++++++++++++------ src/cli/render_help.rs | 32 ++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c24e8f5f4..f084f2a1c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,11 @@ $ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` +> **Note** +> +> If you use direnv, you will want to activate direnv _before_ rtx. There is also +> an alternative way to use rtx inside of direnv, see [here](#direnv). + Install a runtime and set it as the default: ```sh-session @@ -1328,13 +1333,27 @@ were very good. I really just have 2 complaints: the shims and the fact it's wri [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. +As a result, there were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). +However, we think we've mitigated these. If you find that rtx and direnv are not working well together, +please comment on that ticket ideally with a good description of your directory layout so we can +reproduce the problem. + +If there are remaining issues, they're likely to do with the ordering of PATH. This means it would +really only be a problem if you were trying to manage the same runtime with direnv and rtx. For example, +you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with python +in it as well. + +A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated +binaries to PATH. In these cases, rtx will not interfere with direnv. + +As mentioned in the Quick Start, it is important to make sure that `rtx activate` is called after `direnv hook` +in the shell rc file. rtx overrides some of the internal direnv state (`DIRENV_DIFF`) so calling +direnv first gives rtx the opportunity to make those changes to direnv's state. -There were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). -However, these _should_ be resolved now and you should be able to use direnv alongside -rtx. +### rtx inside of direnv (`use rtx` in `.envrc`) -If you do encounter issues, or just want to use direnv in an alternate way: there -is a method of calling rtx from within direnv so you do not need to run `rtx activate`. This is a simpler setup that's less likely to cause issues. +If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, +this is a simpler setup that's less likely to cause issues. To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: @@ -1363,7 +1382,8 @@ export RTX_NODEJS_VERSION=18.0.0 export RTX_PYTHON_VERSION=3.11 ``` -Of course if you use `rtx activate` none of this is necesary. +Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx +as if direnv was not used. ## Cache Behavior diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 810aa31e8..eea28b0a2 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -45,6 +45,11 @@ $ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` +> **Note** +> +> If you use direnv, you will want to activate direnv _before_ rtx. There is also +> an alternative way to use rtx inside of direnv, see [here](#direnv). + Install a runtime and set it as the default: ```sh-session @@ -623,13 +628,27 @@ were very good. I really just have 2 complaints: the shims and the fact it's wri [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. +As a result, there were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). +However, we think we've mitigated these. If you find that rtx and direnv are not working well together, +please comment on that ticket ideally with a good description of your directory layout so we can +reproduce the problem. + +If there are remaining issues, they're likely to do with the ordering of PATH. This means it would +really only be a problem if you were trying to manage the same runtime with direnv and rtx. For example, +you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with python +in it as well. + +A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated +binaries to PATH. In these cases, rtx will not interfere with direnv. + +As mentioned in the Quick Start, it is important to make sure that `rtx activate` is called after `direnv hook` +in the shell rc file. rtx overrides some of the internal direnv state (`DIRENV_DIFF`) so calling +direnv first gives rtx the opportunity to make those changes to direnv's state. -There were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). -However, these _should_ be resolved now and you should be able to use direnv alongside -rtx. +### rtx inside of direnv (`use rtx` in `.envrc`) -If you do encounter issues, or just want to use direnv in an alternate way: there -is a method of calling rtx from within direnv so you do not need to run `rtx activate`. This is a simpler setup that's less likely to cause issues. +If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, +this is a simpler setup that's less likely to cause issues. To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: @@ -658,7 +677,8 @@ export RTX_NODEJS_VERSION=18.0.0 export RTX_PYTHON_VERSION=3.11 ``` -Of course if you use `rtx activate` none of this is necesary. +Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx +as if direnv was not used. ## Cache Behavior From c8da59da5227bafdc77fb07ef154da9bb5638fde Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 8 Feb 2023 12:50:36 -0600 Subject: [PATCH 0119/1891] docs: should have been a warning --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f084f2a1c..b16f7979d 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ $ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` -> **Note** +> **Warning** > > If you use direnv, you will want to activate direnv _before_ rtx. There is also > an alternative way to use rtx inside of direnv, see [here](#direnv). diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index eea28b0a2..382aebc40 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -45,7 +45,7 @@ $ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` -> **Note** +> **Warning** > > If you use direnv, you will want to activate direnv _before_ rtx. There is also > an alternative way to use rtx inside of direnv, see [here](#direnv). From c9a09f5a44e88bbe4616a0f2153022bec6102207 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 8 Feb 2023 12:54:26 -0600 Subject: [PATCH 0120/1891] docs: typos --- README.md | 6 +++--- src/cli/render_help.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b16f7979d..e4cf6ca2c 100644 --- a/README.md +++ b/README.md @@ -1369,12 +1369,12 @@ use rtx ``` direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` -too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. +to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. Note that in this method direnv typically won't know to refresh `.tool-version` files -unless they're at the same level at a `.envrc` file. You'll likely always want to have +unless they're at the same level as a `.envrc` file. You'll likely always want to have a `.envrc` file next to your `.tool-versions` for this reason. To make this a little -easier to manage, I encourage _not_ actually using `.tool-versions` and instead +easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead setting environment variables entirely in `.envrc`: ``` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 382aebc40..9f7960bd7 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -664,12 +664,12 @@ use rtx ``` direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` -too all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. +to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. Note that in this method direnv typically won't know to refresh `.tool-version` files -unless they're at the same level at a `.envrc` file. You'll likely always want to have +unless they're at the same level as a `.envrc` file. You'll likely always want to have a `.envrc` file next to your `.tool-versions` for this reason. To make this a little -easier to manage, I encourage _not_ actually using `.tool-versions` and instead +easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead setting environment variables entirely in `.envrc`: ``` From 0ccb4d09730edea6d70e0e564c54d4875bb9470f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 8 Feb 2023 14:09:20 -0600 Subject: [PATCH 0121/1891] docs: typos --- README.md | 6 +++--- src/cli/render_help.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e4cf6ca2c..c812111f6 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ environment variable to point your shell to the correct runtime binaries. When y directory containing a `.tool-versions` file, rtx will automatically activate the correct versions. Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This -should be very fast and it exits early if the the directory wasn't changed or the `.tool-version` +should be very fast and it exits early if the the directory wasn't changed or the `.tool-versions` files haven't been updated. On my machine this takes 4ms in the fast case, 14ms in the slow case. See [Performance](#performance) for more on this topic. Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies @@ -279,7 +279,7 @@ I'd be happy to help you get yours integrated. ### `.tool-versions` -The `.tool-versions` file is used to specify the runtime versions for a project. An example of this +The `.tool-versions` file is used to specify the runtime versions for a project. An example of this is: ``` @@ -1371,7 +1371,7 @@ use rtx direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. -Note that in this method direnv typically won't know to refresh `.tool-version` files +Note that in this method direnv typically won't know to refresh `.tool-versions` files unless they're at the same level as a `.envrc` file. You'll likely always want to have a `.envrc` file next to your `.tool-versions` for this reason. To make this a little easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9f7960bd7..802f12340 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -89,7 +89,7 @@ environment variable to point your shell to the correct runtime binaries. When y directory containing a `.tool-versions` file, rtx will automatically activate the correct versions. Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This -should be very fast and it exits early if the the directory wasn't changed or the `.tool-version` +should be very fast and it exits early if the the directory wasn't changed or the `.tool-versions` files haven't been updated. On my machine this takes 4ms in the fast case, 14ms in the slow case. See [Performance](#performance) for more on this topic. Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies @@ -297,7 +297,7 @@ I'd be happy to help you get yours integrated. ### `.tool-versions` -The `.tool-versions` file is used to specify the runtime versions for a project. An example of this +The `.tool-versions` file is used to specify the runtime versions for a project. An example of this is: ``` @@ -666,7 +666,7 @@ use rtx direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. -Note that in this method direnv typically won't know to refresh `.tool-version` files +Note that in this method direnv typically won't know to refresh `.tool-versions` files unless they're at the same level as a `.envrc` file. You'll likely always want to have a `.envrc` file next to your `.tool-versions` for this reason. To make this a little easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead From c4df8498f0720c06523c95af79ddd4a653716361 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:01:30 -0600 Subject: [PATCH 0122/1891] runtimeargv2 (#121) --- README.md | 4 +-- completions/_rtx | 2 +- src/cli/activate.rs | 3 ++ src/cli/args/runtime.rs | 65 ++++++++++++++++++++++++++++++----- src/cli/env.rs | 2 +- src/cli/global.rs | 4 +-- src/cli/install.rs | 46 ++++++++++--------------- src/cli/latest.rs | 12 ++++--- src/cli/local.rs | 4 +-- src/cli/mod.rs | 2 +- src/cli/render_help.rs | 2 +- src/cli/uninstall.rs | 22 +++++++----- src/cli/where.rs | 35 ++++++++++--------- src/config/config_file/mod.rs | 37 +++++++++++--------- src/config/mod.rs | 58 ++++++++++++++++++++++--------- 15 files changed, 188 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index c812111f6..f2d7e3a8a 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin rtx local nodejs@20 Use node-20.x in current project rtx global nodejs@20 Use node-20.x as default - rtx install nodejs Install the latest available version + rtx install nodejs Install the version specified in .tool-versions rtx local nodejs@latest Use latest node in current directory rtx global nodejs@system Use system node as default @@ -829,7 +829,7 @@ Options: Examples: $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version - $ rtx install nodejs # install latest nodejs version—or what is specified in .tool-versions + $ rtx install nodejs # install version specified in .tool-versions $ rtx install # installs all runtimes specified in .tool-versions for installed plugins $ rtx install --all # installs all runtimes and all plugins diff --git a/completions/_rtx b/completions/_rtx index 0be4e8518..fd94c5f63 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -600,7 +600,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':runtime -- runtime(s) to remove:' \ +':runtime -- runtime(s) to look up if "@" is specified, it will show the latest installed version that matches the prefix otherwise, it will show the current, active installed version:' \ '::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ && ret=0 ;; diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 1923fa22b..6f715938d 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -32,6 +32,9 @@ impl Command for Activate { let shell = get_shell(self.shell_type.or(self.shell)); if self.quiet { + // TODO: it would probably be better to just set --quiet on `hook-env` + // this will cause _all_ rtx commands to be quiet, not just the hook + // however as of this writing I don't think RTX_QUIET impacts other commands rtxprintln!(out, "{}", shell.set_env("RTX_QUIET", "1")); } diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index d48e6ea86..fad25d679 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -1,3 +1,4 @@ +use color_eyre::eyre::Result; use std::ffi::{OsStr, OsString}; use std::fmt::Display; @@ -9,22 +10,51 @@ use crate::plugins::PluginName; #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct RuntimeArg { pub plugin: PluginName, - pub version: String, + pub version: RuntimeArgVersion, +} + +/// The type of runtime argument +/// Generally, these are in the form of `plugin@version` that's "Version" +/// but there are some alternatives like `plugin@ref:sha` or `plugin@path:/path/to/runtime` +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum RuntimeArgVersion { + /// Nothing was specified, e.g.: `nodejs` + None, + /// references a version, version prefix, or alias + /// e.g.: `nodejs@20`, `nodejs@latest`, `nodejs@lts` + Version(String), + /// use the system runtime already on PATH + /// e.g.: `nodejs@system` + System, + // /// build runtime from source at this VCS sha + // rtx currently does not support this, see https://github.com/jdxcode/rtx/issues/98 + // Ref, + // /// runtime is in a local directory, not managed by rtx + // Path, } impl RuntimeArg { pub fn parse(input: &str) -> Self { - let (plugin, version) = input.split_once('@').unwrap_or((input, "latest")); - Self { - plugin: plugin.into(), - version: version.into(), + match input.split_once('@') { + Some((plugin, "system")) => Self { + plugin: plugin.into(), + version: RuntimeArgVersion::System, + }, + Some((plugin, version)) => Self { + plugin: plugin.into(), + version: RuntimeArgVersion::Version(version.into()), + }, + None => Self { + plugin: input.into(), + version: RuntimeArgVersion::None, + }, } } /// this handles the case where the user typed in: /// rtx local nodejs 20.0.0 /// instead of - /// rtx local nodejs 20.0.0 + /// rtx local nodejs@20.0.0 /// /// We can detect this, and we know what they meant, so make it work the way /// they expected. @@ -34,8 +64,11 @@ impl RuntimeArg { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let a = runtimes[0].clone(); let b = runtimes[1].clone(); - if a.version == "latest" && b.version == "latest" && re.is_match(&b.plugin) { - runtimes[1].version = b.plugin; + if matches!(a.version, RuntimeArgVersion::None) + && matches!(b.version, RuntimeArgVersion::None) + && re.is_match(&b.plugin) + { + runtimes[1].version = RuntimeArgVersion::Version(b.plugin); runtimes[1].plugin = a.plugin; runtimes.remove(0); } @@ -46,7 +79,21 @@ impl RuntimeArg { impl Display for RuntimeArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}@{}", self.plugin, self.version) + match &self.version { + RuntimeArgVersion::System => write!(f, "{}@system", self.plugin), + RuntimeArgVersion::Version(version) => write!(f, "{}@{}", self.plugin, version), + RuntimeArgVersion::None => write!(f, "{}", self.plugin), + } + } +} + +impl Display for RuntimeArgVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + RuntimeArgVersion::System => write!(f, "system"), + RuntimeArgVersion::Version(version) => write!(f, "{version}"), + RuntimeArgVersion::None => write!(f, "current"), + } } } diff --git a/src/cli/env.rs b/src/cli/env.rs index 09353b650..ce0b6ea42 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -82,7 +82,7 @@ mod test { assert!(stdout.contains( dirs::ROOT - .join("installs/shfmt/3.5.2/bin") + .join("installs/shfmt/3.5.1/bin") .to_string_lossy() .as_ref() )); diff --git a/src/cli/global.rs b/src/cli/global.rs index 51c8d1595..eccc075a8 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -32,7 +32,7 @@ pub struct Global { } impl Command for Global { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let cf_path = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); let mut cf = match cf_path.exists() { @@ -47,7 +47,7 @@ impl Command for Global { } if let Some(runtimes) = &self.runtime { let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); - cf.add_runtimes(&config, &runtimes, self.fuzzy)?; + cf.add_runtimes(&mut config, &runtimes, self.fuzzy)?; } if self.runtime.is_some() || self.remove.is_some() { diff --git a/src/cli/install.rs b/src/cli/install.rs index 31cd4b695..46914b3b9 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use atty::Stream::Stderr; use color_eyre::eyre::Result; use owo_colors::Stream; @@ -8,7 +6,6 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; -use crate::config::Settings; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; use crate::plugins::InstallType::Version; @@ -62,37 +59,30 @@ impl Command for Install { impl Install { fn install_runtimes( &self, - config: Config, + mut config: Config, out: &mut Output, runtimes: &[RuntimeArg], ) -> Result<()> { - let settings = Settings { - missing_runtime_behavior: AutoInstall, - ..config.settings.clone() - }; + config.settings.missing_runtime_behavior = AutoInstall; for r in RuntimeArg::double_runtime_condition(runtimes) { - if r.version == "system" { - continue; - } - let plugin = Plugin::load_ensure_installed(&r.plugin, &settings)?; - - let version = config.resolve_alias(&r.plugin, r.version.clone()); - let version = plugin.latest_version(&version)?.unwrap_or(version); - - let rtv = RuntimeVersion::new(Arc::new(plugin), &version); + let resolved_version = config.resolve_runtime_arg(&r)?; + let plugin = config.ts.find_plugin(&r.plugin).unwrap(); + if let Some(resolved_version) = resolved_version { + let rtv = RuntimeVersion::new(plugin, &resolved_version); + + if rtv.is_installed() && self.force { + rtv.uninstall()?; + } else if rtv.is_installed() { + warn!( + "{} is already installed", + cyan(Stream::Stderr, &rtv.to_string()) + ); + continue; + } - if rtv.is_installed() && self.force { - rtv.uninstall()?; - } else if rtv.is_installed() { - warn!( - "{} is already installed", - cyan(Stream::Stderr, &rtv.to_string()) - ); - continue; + self.do_install(&config, out, &rtv)?; } - - self.do_install(&config, out, &rtv)?; } Ok(()) @@ -161,7 +151,7 @@ const AFTER_LONG_HELP: &str = r#" Examples: $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version - $ rtx install nodejs # install latest nodejs version—or what is specified in .tool-versions + $ rtx install nodejs # install version specified in .tool-versions $ rtx install # installs all runtimes specified in .tool-versions for installed plugins $ rtx install --all # installs all runtimes and all plugins "#; diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 0f409edab..ec73c6637 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,6 +1,6 @@ -use color_eyre::eyre::Result; +use color_eyre::eyre::{eyre, Result}; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -23,14 +23,16 @@ pub struct Latest { impl Command for Latest { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let prefix = match self.runtime.version.as_str() { - "latest" => match self.asdf_version { + let prefix = match self.runtime.version { + RuntimeArgVersion::None => match self.asdf_version { Some(version) => version, None => "latest".to_string(), }, - v => v.into(), + RuntimeArgVersion::Version(version) => version, + _ => Err(eyre!("invalid version {}", self.runtime))?, }; let plugin = Plugin::load_ensure_installed(&self.runtime.plugin, &config.settings)?; + let prefix = config.resolve_alias(&self.runtime.plugin, prefix); if let Some(version) = plugin.latest_version(&prefix)? { rtxprintln!(out, "{}", version); diff --git a/src/cli/local.rs b/src/cli/local.rs index 6c891a01f..307a34a0b 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -37,7 +37,7 @@ pub struct Local { } impl Command for Local { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let cf_path = match self.parent { true => file::find_up( &dirs::CURRENT, @@ -65,7 +65,7 @@ impl Command for Local { if let Some(runtimes) = &self.runtime { let runtimes = RuntimeArg::double_runtime_condition(runtimes); - cf.add_runtimes(&config, &runtimes, self.fuzzy)?; + cf.add_runtimes(&mut config, &runtimes, self.fuzzy)?; } if self.runtime.is_some() || self.remove.is_some() { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ed137b5c9..448fdf7d4 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -174,7 +174,7 @@ const AFTER_HELP: &str = indoc! {" rtx local nodejs@20 Use node-20.x in current project rtx global nodejs@20 Use node-20.x as default - rtx install nodejs Install the latest available version + rtx install nodejs Install the version specified in .tool-versions rtx local nodejs Use latest node in current directory rtx global system Use system node as default diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 802f12340..4cec99492 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -104,7 +104,7 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin rtx local nodejs@20 Use node-20.x in current project rtx global nodejs@20 Use node-20.x as default - rtx install nodejs Install the latest available version + rtx install nodejs Install the version specified in .tool-versions rtx local nodejs@latest Use latest node in current directory rtx global nodejs@system Use system node as default diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index af291f6a9..f98a52a9d 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -3,7 +3,7 @@ use itertools::Itertools; use owo_colors::OwoColorize; use owo_colors::Stream; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; @@ -19,16 +19,21 @@ pub struct Uninstall { } impl Command for Uninstall { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let runtime_versions = self .runtime .iter() .map(|a| { - let prefix = match a.version.as_str() { - "latest" => "", - v => v, + let mut versions = config.ts.list_current_versions(); + versions.extend(config.ts.list_installed_versions()); + + let prefix = match &a.version { + RuntimeArgVersion::None => config.resolve_runtime_arg(a)?.unwrap(), + RuntimeArgVersion::Version(version) => { + config.resolve_alias(&a.plugin, version.to_string()) + } + _ => Err(eyre!("invalid version {}", a.to_string()))?, }; - let prefix = config.resolve_alias(&a.plugin, prefix.to_string()); let mut versions = config.ts.list_current_versions(); versions.extend(config.ts.list_installed_versions()); let versions = versions @@ -39,9 +44,10 @@ impl Command for Uninstall { .collect::>(); if versions.is_empty() { - Err(VersionNotInstalled(a.plugin.clone(), a.version.clone()))? + Err(VersionNotInstalled(a.plugin.clone(), a.version.to_string()))? } else { - Ok(versions) + // TODO: add a flag to uninstall all matching versions + Ok(vec![versions[0].clone()]) } }) .collect::>>()? diff --git a/src/cli/where.rs b/src/cli/where.rs index ded31303c..85fbaf357 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -12,7 +12,9 @@ use crate::output::Output; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, hide = true)] pub struct Where { - /// runtime(s) to remove + /// runtime(s) to look up + /// if "@" is specified, it will show the latest installed version that matches the prefix + /// otherwise, it will show the current, active installed version #[clap(required = true, value_parser = RuntimeArgParser)] runtime: RuntimeArg, @@ -24,18 +26,11 @@ pub struct Where { } impl Command for Where { - fn run(self, config: Config, out: &mut Output) -> Result<()> { - let prefix = match self.runtime.version.as_str() { - "latest" => match self.asdf_version { - Some(version) => version, - None => "".to_string(), - }, - v => v.into(), - }; - - let rtv = config - .ts - .find_by_prefix(&config.aliases, &self.runtime.plugin, prefix.as_str()); + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + let version = config.resolve_runtime_arg(&self.runtime)?; + let rtv = config.ts.list_installed_versions().into_iter().find(|rtv| { + rtv.plugin.name == self.runtime.plugin && version.eq(&Some(rtv.version.clone())) + }); match rtv { Some(rtv) => { @@ -43,8 +38,8 @@ impl Command for Where { Ok(()) } None => Err(VersionNotInstalled( - self.runtime.plugin, - self.runtime.version, + self.runtime.plugin.to_string(), + self.runtime.version.to_string(), ))?, } } @@ -52,8 +47,16 @@ impl Command for Where { const AFTER_LONG_HELP: &str = r#" Examples: + + # Show the latest installed version of nodejs + # If it is is not installed, errors $ rtx where nodejs@20 - /Users/jdx/.local/share/rtx/installs/nodejs/20.13.0 + /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + + # Show the current, active install directory of nodejs + # Errors if nodejs is not referenced in any .tool-version file + $ rtx where nodejs + /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 "#; #[cfg(test)] diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index e03deb9b6..dd01f07de 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -9,7 +9,7 @@ use indexmap::IndexMap; use rtxrc::RTXFile; use tool_versions::ToolVersions; -use crate::cli::args::runtime::RuntimeArg; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::Config; use crate::config::PluginSource; use crate::env; @@ -44,28 +44,31 @@ pub trait ConfigFile: Debug + Display + Send { impl dyn ConfigFile { pub fn add_runtimes( &mut self, - config: &Config, + config: &mut Config, runtimes: &[RuntimeArg], fuzzy: bool, ) -> Result<()> { let mut runtime_map: HashMap> = HashMap::new(); for runtime in runtimes { let plugin = Plugin::load_ensure_installed(&runtime.plugin, &config.settings)?; - let latest = plugin - .latest_version(&runtime.version)? - .unwrap_or_else(|| runtime.version.clone()); - let rtv = RuntimeVersion::new(Arc::new(plugin), &latest); - if !rtv.ensure_installed(config)? { - return Err(VersionNotInstalled(rtv.plugin.name.clone(), rtv.version))?; - }; - runtime_map - .entry(rtv.plugin.name.clone()) - .or_default() - .push(if fuzzy { - runtime.version.to_string() - } else { - rtv.version.to_string() - }); + let latest = config.resolve_runtime_arg(runtime)?; + if let Some(latest) = latest { + let rtv = RuntimeVersion::new(Arc::new(plugin), &latest); + if !rtv.ensure_installed(config)? { + return Err(VersionNotInstalled(rtv.plugin.name.clone(), rtv.version))?; + }; + runtime_map + .entry(rtv.plugin.name.clone()) + .or_default() + .push(if fuzzy { + match runtime.version { + RuntimeArgVersion::Version(ref v) => v.to_string(), + _ => "latest".to_string(), + } + } else { + rtv.version.to_string() + }); + } } for (plugin, versions) in runtime_map { self.replace_versions(&plugin, &versions); diff --git a/src/config/mod.rs b/src/config/mod.rs index 67a8f7876..db59c6266 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,3 +1,9 @@ +use std::collections::HashMap; +use std::env::join_paths; +use std::fmt::{Display, Formatter}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + use color_eyre::eyre::{eyre, Result, WrapErr}; use color_eyre::Report; use indexmap::IndexMap; @@ -6,13 +12,8 @@ use rayon::prelude::*; pub use plugin_source::PluginSource; pub use settings::{MissingRuntimeBehavior, Settings}; -use std::collections::HashMap; -use std::env::join_paths; -use std::fmt::{Display, Formatter}; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use crate::cli::args::runtime::RuntimeArg; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtxrc::RTXFile; use crate::config::config_file::ConfigFile; @@ -100,19 +101,15 @@ impl Config { pub fn with_runtime_args(mut self, args: &[RuntimeArg]) -> Result { let args_by_plugin = &args.iter().group_by(|arg| arg.plugin.clone()); for (plugin_name, args) in args_by_plugin { - match self.ts.plugins.get(&plugin_name) { - Some(plugin) => plugin, - _ => { - let plugin = Plugin::load_ensure_installed(&plugin_name, &self.settings)?; - self.ts - .plugins - .entry(plugin_name.clone()) - .or_insert_with(|| Arc::new(plugin)) - } - }; let args = args.collect_vec(); let source = PluginSource::Argument(args[0].clone()); - let versions = args.iter().map(|arg| arg.version.clone()).collect(); + let versions = args + .iter() + .map(|arg| self.resolve_runtime_arg(arg)) + .collect::>>>()? + .into_iter() + .flatten() + .collect(); self.ts .set_current_runtime_versions(&plugin_name, versions, source)?; } @@ -139,6 +136,33 @@ impl Config { } version } + + pub fn resolve_runtime_arg(&mut self, arg: &RuntimeArg) -> Result> { + match &arg.version { + RuntimeArgVersion::System => Ok(None), + RuntimeArgVersion::Version(version) => { + let plugin = self.ts.get_or_add_plugin(arg.plugin.to_string())?; + plugin.ensure_installed(&self.settings)?; + let version = self.resolve_alias(&arg.plugin, version.into()); + let version = plugin.latest_version(&version)?.unwrap_or(version); + Ok(Some(version)) + } + RuntimeArgVersion::None => { + let plugin = self + .ts + .list_current_versions() + .into_iter() + .find(|rtv| rtv.plugin.name == arg.plugin); + match plugin { + Some(rtv) => Ok(Some(rtv.version.clone())), + None => Err(eyre!( + "No version of {} is specified in a .tool-versions file", + arg.plugin + ))?, + } + } + } + } } fn load_rtxrc() -> Result { From 21ac3f1bac1c9417eaab2286d32235b3f9eca6b9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:02:02 -0600 Subject: [PATCH 0123/1891] chore: Release rtx-cli version 1.6.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86c7ee133..f3669d042 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.5.3" +version = "1.6.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 0eaca9c4c..042afac13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.5.3" +version = "1.6.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index f2d7e3a8a..87c726f6e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.5.3 +rtx 1.6.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -176,7 +176,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.3/rtx-v1.5.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.0/rtx-v1.6.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 4e472ca18..33c1e811a 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.5.3 +Version: 1.6.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 4cec99492..1712e5e9b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -194,7 +194,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.5.3/rtx-v1.5.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.0/rtx-v1.6.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 1dfce06d940819ad309729cb2f6da059652d47b1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 06:50:11 -0600 Subject: [PATCH 0124/1891] test: use shfmt@3.5.1 (#122) shfmt@3.5.2 does not exist but because the plugin did not fail on invalid versions, it behaved as if it did. This uses a real version of shfmt --- src/cli/current.rs | 4 ++-- .../rtx__cli__direnv__envrc__test__direnv_envrc.snap | 2 +- src/cli/env.rs | 2 +- src/cli/ls.rs | 4 ++-- src/cli/where.rs | 2 +- src/config/config_file/tool_versions.rs | 2 +- test/cwd/.tool-versions | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cli/current.rs b/src/cli/current.rs index 1037e2c9c..05ed3caf3 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -78,7 +78,7 @@ mod test { fn test_current() { assert_cli!("install"); let stdout = assert_cli!("current"); - assert_snapshot!(grep(stdout, "shfmt"), @"shfmt@3.5.2"); + assert_snapshot!(grep(stdout, "shfmt"), @"shfmt@3.5.1"); } #[test] @@ -86,7 +86,7 @@ mod test { assert_cli!("install"); let stdout = assert_cli!("current", "shfmt"); assert_snapshot!(stdout, @r###" - 3.5.2 + 3.5.1 "###); } } diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap index 915c992ad..637abd0b3 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap @@ -7,7 +7,7 @@ watch_file ~/cwd/.tool-versions watch_file ~/cwd/.node-version watch_file ~/.tool-versions export JDXCODE_TINY=2.1.0 -PATH_add ~/data/installs/shfmt/3.5.2/bin +PATH_add ~/data/installs/shfmt/3.5.1/bin PATH_add ~/data/installs/jq/1.6/bin PATH_add ~/data/installs/tiny/2.1.0/bin PATH_add ~/data/installs/shellcheck/0.9.0/bin diff --git a/src/cli/env.rs b/src/cli/env.rs index ce0b6ea42..918aa4aa5 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -68,7 +68,7 @@ mod test { let stdout = assert_cli!("env", "-s", "bash"); assert!(stdout.contains( dirs::ROOT - .join("installs/shfmt/3.5.2/bin") + .join("installs/shfmt/3.5.1/bin") .to_string_lossy() .as_ref() )); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 88a642eea..dc2e98b25 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -160,9 +160,9 @@ mod test { let re = Regex::new(r" {3}shfmt\s+3\.5\.0\s+").unwrap(); assert!(re.is_match(&stdout)); - assert_cli!("uninstall", "shfmt@3.5.2"); + assert_cli!("uninstall", "shfmt@3.5.1"); let stdout = assert_cli!("list"); - let re = Regex::new(r" {3}shfmt\s+3\.5\.2 \(missing\)\s+").unwrap(); + let re = Regex::new(r" {3}shfmt\s+3\.5\.1 \(missing\)\s+").unwrap(); assert!(re.is_match(&stdout)); } } diff --git a/src/cli/where.rs b/src/cli/where.rs index 85fbaf357..2496bce8c 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -74,7 +74,7 @@ mod test { let stdout = assert_cli!("where", "shfmt"); assert_str_eq!( stdout.trim(), - dirs::ROOT.join("installs/shfmt/3.5.2").to_string_lossy() + dirs::ROOT.join("installs/shfmt/3.5.1").to_string_lossy() ); } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 4d3d5249c..ced72571b 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -189,7 +189,7 @@ pub(crate) mod tests { fn test_parse() { let tv = ToolVersions::from_file(dirs::CURRENT.join(".tool-versions").as_path()).unwrap(); assert_eq!(tv.path, dirs::CURRENT.join(".tool-versions")); - assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.tool-versions): shellcheck@0.9.0, shfmt@3.5.2, nodejs@system"); + assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.tool-versions): shellcheck@0.9.0, shfmt@3.5.1, nodejs@system"); } #[test] diff --git a/test/cwd/.tool-versions b/test/cwd/.tool-versions index c120066de..7808524f6 100644 --- a/test/cwd/.tool-versions +++ b/test/cwd/.tool-versions @@ -1,5 +1,5 @@ #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.5.2 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 nodejs system From ce5e2ecd3b286dda82cb38260ab73d068dadc5c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 07:18:51 -0600 Subject: [PATCH 0125/1891] bug: fix semver version sorting (#124) --- src/cli/ls.rs | 4 ++-- src/config/toolset.rs | 4 ++-- src/plugins/mod.rs | 4 ++-- src/runtimes/mod.rs | 3 ++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index dc2e98b25..7bbe2ae70 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; use itertools::Itertools; use owo_colors::{OwoColorize, Stream}; -use versions::Mess; +use versions::Versioning; use crate::cli::command::Command; use crate::config::{Config, PluginSource}; @@ -118,7 +118,7 @@ fn get_runtime_list( let rvs: Vec<(Arc, Option)> = versions .into_iter() .sorted_by_cached_key(|((plugin_name, version), _)| { - (plugin_name.clone(), Mess::new(version).unwrap_or_default()) + (plugin_name.clone(), Versioning::new(version)) }) .map(|(k, rtv)| { let source = match &active.get(&k) { diff --git a/src/config/toolset.rs b/src/config/toolset.rs index fcd1bbe1b..83b75d82e 100644 --- a/src/config/toolset.rs +++ b/src/config/toolset.rs @@ -5,7 +5,7 @@ use color_eyre::eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; -use versions::Mess; +use versions::Versioning; use crate::config::{AliasMap, PluginSource}; use crate::plugins::{Plugin, PluginName}; @@ -191,7 +191,7 @@ impl Toolset { } let sorted_versions = installed_versions .keys() - .sorted_by_cached_key(|v| v.parse::().unwrap()) + .sorted_by_cached_key(|v| Versioning::new(v)) .rev() .collect::>(); for v in sorted_versions { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index b97fa19d0..0f2eb2a9d 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -10,7 +10,7 @@ use color_eyre::eyre::{eyre, Result}; use itertools::Itertools; use lazy_static::lazy_static; use regex::Regex; -use versions::Mess; +use versions::Versioning; use cache::PluginCache; pub use script_manager::{InstallType, Script, ScriptManager}; @@ -216,7 +216,7 @@ impl Plugin { Ok(match self.installs_path.exists() { true => file::dir_subdirs(&self.installs_path)? .iter() - .map(|v| Mess::new(v).unwrap()) + .map(|v| Versioning::new(v).unwrap_or_default()) .sorted() .map(|v| v.to_string()) .collect(), diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index 574a2a1c2..150f48aee 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; use owo_colors::{OwoColorize, Stream}; +use versions::Versioning; use runtime_conf::RuntimeConf; @@ -63,7 +64,7 @@ impl RuntimeVersion { versions.push(Self::new(plugin.clone(), &version)); } } - versions.sort_by_cached_key(|rtv| versions::Mess::new(rtv.version.as_str())); + versions.sort_by_cached_key(|rtv| Versioning::new(rtv.version.as_str())); Ok(versions) } From e68965627e94314110fe1046280ffa14aff81ff4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 07:19:07 -0600 Subject: [PATCH 0126/1891] chore: Release rtx-cli version 1.6.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3669d042..818be8c7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.6.0" +version = "1.6.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 042afac13..7f8fed831 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.6.0" +version = "1.6.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 87c726f6e..5754ff346 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.6.0 +rtx 1.6.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -176,7 +176,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.0/rtx-v1.6.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.1/rtx-v1.6.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 33c1e811a..e3fdf9fdf 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.6.0 +Version: 1.6.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1712e5e9b..fbdcc9db9 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -194,7 +194,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.0/rtx-v1.6.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.1/rtx-v1.6.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 12a0c25bab0a7a93a2ae4a1c9d99c2b82056a920 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 07:26:48 -0600 Subject: [PATCH 0127/1891] chore: release depends on unit tests passing --- .github/workflows/rtx.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 27c02f51d..02fd865db 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -203,6 +203,7 @@ jobs: permissions: contents: write needs: + - unit - e2e-linux - build-linux - build-macos From ef0c55779ce99c64426be6367f178cee7754ed80 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 17:03:26 -0600 Subject: [PATCH 0128/1891] ui: status message now truncates to screen width It was annoying to have this spill out on multiple lines I feel --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + src/cli/hook_env.rs | 8 +++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 818be8c7e..547422e1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1061,6 +1061,7 @@ dependencies = [ "simplelog", "spinoff", "tempfile", + "term_size", "thiserror", "toml", "toml_edit", @@ -1238,6 +1239,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "term_size" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.3" diff --git a/Cargo.toml b/Cargo.toml index 7f8fed831..3337028d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ serde_json = "1.0.92" shell-escape = "0.1.5" simplelog = { version = "0.12.0", features = ["paris"] } spinoff = "0.7.0" +term_size = "0.3.2" thiserror = "1.0.38" toml = "0.7.1" toml_edit = "0.19.0" diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index a2abbf990..116eacc8f 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -87,7 +87,13 @@ impl HookEnv { .map(|v| v.to_string()) .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { - rtxstatusln!(out, "{}", installed_versions.join(" ")); + let (w, _) = term_size::dimensions_stderr().unwrap_or_default(); + let status = installed_versions.join(" "); + if status.len() > w - 5 { + rtxstatusln!(out, "{}...", &status[..w - 9]) + } else { + rtxstatusln!(out, "{}", status) + }; } } From 0929f1a7f069873c5910aa573cd5e05822ed836b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 17:19:42 -0600 Subject: [PATCH 0129/1891] feat: make `rtx current` output usable as a `.tool-versions` file --- README.md | 12 ++++-- src/cli/current.rs | 91 ++++++++++++++++++++++++++++++------------- src/config/toolset.rs | 15 +++++++ 3 files changed, 89 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 5754ff346..e4be25231 100644 --- a/README.md +++ b/README.md @@ -602,14 +602,20 @@ Options: Examples: + # outputs `.tool-versions` compatible format $ rtx current - shfmt@3.6.0 - shellcheck@0.9.0 - nodejs@18.13.0 + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + nodejs 18.13.0 $ rtx current nodejs 18.13.0 + # can output multiple versions + $ rtx current python + 3.11.0 3.10.0 + ``` ### `rtx deactivate` diff --git a/src/cli/current.rs b/src/cli/current.rs index 05ed3caf3..a8e1bbb1f 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,8 +1,10 @@ use color_eyre::eyre::Result; +use std::sync::Arc; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; /// Shows currently active, and installed runtime versions /// @@ -21,35 +23,66 @@ pub struct Current { impl Command for Current { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugin = match self.plugin { - Some(plugin_name) => { - let plugin = config.ts.find_plugin(&plugin_name); - if plugin.is_none() { + match &self.plugin { + Some(plugin_name) => match config.ts.find_plugin(plugin_name) { + Some(plugin) => self.one(&config, out, plugin), + None => { warn!("Plugin {} is not installed", plugin_name); - return Ok(()); + Ok(()) } - Some(plugin.unwrap()) - } - None => None, - }; + }, + None => self.all(&config, out), + } + } +} - for rtv in config.ts.list_current_versions() { - if !rtv.is_installed() { - let source = config.ts.get_source_for_plugin(&rtv.plugin.name).unwrap(); - warn!( - "{}@{} is specified in {}, but not installed", - rtv.plugin.name, rtv.version, source +impl Current { + fn one(&self, config: &Config, out: &mut Output, plugin: Arc) -> Result<()> { + if !plugin.is_installed() { + warn!("Plugin {} is not installed", plugin.name); + return Ok(()); + } + let versions = config.ts.list_current_versions_by_plugin(); + match versions.get(&plugin.name) { + Some(versions) => { + rtxprintln!( + out, + "{}", + versions + .iter() + .map(|v| v.version.to_string()) + .collect::>() + .join(" ") ); - continue; } - if let Some(plugin) = &plugin { - if plugin != &rtv.plugin { - continue; + None => { + warn!("Plugin {} does not have a version set", plugin.name); + } + }; + Ok(()) + } + + fn all(&self, config: &Config, out: &mut Output) -> Result<()> { + for (plugin, versions) in config.ts.list_current_versions_by_plugin() { + for rtv in &versions { + if !rtv.is_installed() { + let source = config.ts.get_source_for_plugin(&rtv.plugin.name).unwrap(); + warn!( + "{}@{} is specified in {}, but not installed", + &rtv.plugin.name, &rtv.version, &source + ); } - rtxprintln!(out, "{}", rtv.version); - } else { - rtxprintln!(out, "{}@{}", rtv.plugin.name, rtv.version); } + rtxprintln!( + out, + "{} {}", + &plugin, + versions + .iter() + .map(|v| v.version.to_string()) + .collect::>() + .join(" ") + ); } Ok(()) } @@ -58,13 +91,19 @@ impl Command for Current { const AFTER_LONG_HELP: &str = r#" Examples: + # outputs `.tool-versions` compatible format $ rtx current - shfmt@3.6.0 - shellcheck@0.9.0 - nodejs@18.13.0 + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + nodejs 18.13.0 $ rtx current nodejs 18.13.0 + + # can output multiple versions + $ rtx current python + 3.11.0 3.10.0 "#; #[cfg(test)] @@ -78,7 +117,7 @@ mod test { fn test_current() { assert_cli!("install"); let stdout = assert_cli!("current"); - assert_snapshot!(grep(stdout, "shfmt"), @"shfmt@3.5.1"); + assert_snapshot!(grep(stdout, "shfmt"), @"shfmt 3.5.1"); } #[test] diff --git a/src/config/toolset.rs b/src/config/toolset.rs index 83b75d82e..f01e7e33b 100644 --- a/src/config/toolset.rs +++ b/src/config/toolset.rs @@ -224,4 +224,19 @@ impl Toolset { .into_iter() .find(|rtv| rtv.plugin.name == plugin && rtv.version.starts_with(&prefix)) } + + pub fn list_current_versions_by_plugin( + &self, + ) -> IndexMap>> { + self.current_versions + .iter() + .map(|(plugin_name, versions)| { + let versions = versions + .iter() + .filter_map(|v| self.resolve_version(plugin_name, v)) + .collect(); + (plugin_name.clone(), versions) + }) + .collect() + } } From a94d1ff14bcc354d79038ca51cce5a8e073e7231 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 17:33:59 -0600 Subject: [PATCH 0130/1891] ui: reverse order of hook-env status this way you see the runtimes in the current directory first --- src/cli/hook_env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 116eacc8f..f913f22e4 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -88,7 +88,7 @@ impl HookEnv { .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { let (w, _) = term_size::dimensions_stderr().unwrap_or_default(); - let status = installed_versions.join(" "); + let status = installed_versions.into_iter().rev().join(" "); if status.len() > w - 5 { rtxstatusln!(out, "{}...", &status[..w - 9]) } else { From 35e0b1fcb647749acc2463178a3b0524dd615a59 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 20:30:26 -0600 Subject: [PATCH 0131/1891] test: fix CI --- src/cli/hook_env.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index f913f22e4..87b75d166 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,10 +1,11 @@ -use color_eyre::eyre::Result; -use itertools::Itertools; - +use std::cmp::min; use std::env::join_paths; use std::ops::Deref; use std::path::PathBuf; +use color_eyre::eyre::Result; +use itertools::Itertools; + use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; @@ -88,6 +89,7 @@ impl HookEnv { .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { let (w, _) = term_size::dimensions_stderr().unwrap_or_default(); + let w = min(w, 80); let status = installed_versions.into_iter().rev().join(" "); if status.len() > w - 5 { rtxstatusln!(out, "{}...", &status[..w - 9]) From a4f63e349aec7b696afbe204e8dae0d44980712f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 08:11:10 -0600 Subject: [PATCH 0132/1891] chore: github pages -> s3 (#125) --- .github/workflows/rtx.yml | 17 +++++++---------- scripts/release.sh | 19 ++++++++----------- src/cli/hook_env.rs | 4 ++-- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 02fd865db..731ab7b00 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -213,12 +213,6 @@ jobs: - uses: actions/checkout@v3 with: path: rtx - - uses: actions/checkout@v3 - with: - repository: jdxcode/rtx.jdxcode.com - path: rtx.jdxcode.com - token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - lfs: 'true' - uses: actions/checkout@v3 with: repository: jdxcode/homebrew-tap @@ -234,7 +228,6 @@ jobs: git_user_signingkey: true git_commit_gpgsign: true workdir: homebrew-tap - - uses: actions/download-artifact@v3 with: { path: artifacts } - run: rtx/scripts/release.sh @@ -243,9 +236,13 @@ jobs: - name: homebrew-tap push run: git push working-directory: homebrew-tap - - name: rtx.jdxcode.com push - run: git push - working-directory: rtx.jdxcode.com + - uses: jakejarvis/s3-sync-action@master + env: + AWS_S3_BUCKET: rtx-cli + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_REGION: 'us-west-2' # optional: defaults to us-east-1 + SOURCE_DIR: 'rtx.jdxcode.com' - name: GitHub Release Assets uses: softprops/action-gh-release@v1 diff --git a/scripts/release.sh b/scripts/release.sh index 2ec785db9..d84010c3d 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -52,23 +52,20 @@ gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd -./rtx/scripts/render-install.sh >rtx.jdxcode.com/static/install.sh +mkdir -p rtx.jdxcode.com +./rtx/scripts/render-install.sh >rtx.jdxcode.com/install.sh -rm -rf rtx.jdxcode.com/static/rpm -mv artifacts/rpm rtx.jdxcode.com/static/rpm +rm -rf rtx.jdxcode.com/rpm +mv artifacts/rpm rtx.jdxcode.com/rpm -rm -rf rtx.jdxcode.com/static/deb -mv artifacts/deb rtx.jdxcode.com/static/deb +rm -rf rtx.jdxcode.com/deb +mv artifacts/deb rtx.jdxcode.com/deb -cp -vrf "$RELEASE_DIR/"* rtx.jdxcode.com/static -echo "$RTX_VERSION" > rtx.jdxcode.com/static/VERSION +cp -vrf "$RELEASE_DIR/"* rtx.jdxcode.com +echo "$RTX_VERSION" | tr -d 'v' > rtx.jdxcode.com/VERSION ./rtx/scripts/release-npm.sh -pushd rtx.jdxcode.com -git add . && git commit -m "rtv $RTX_VERSION" -popd - ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb pushd homebrew-tap git add . && git commit -m "rtx $RTX_VERSION" diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 87b75d166..a7a8d9cd7 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,4 +1,4 @@ -use std::cmp::min; +use std::cmp::max; use std::env::join_paths; use std::ops::Deref; use std::path::PathBuf; @@ -89,7 +89,7 @@ impl HookEnv { .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { let (w, _) = term_size::dimensions_stderr().unwrap_or_default(); - let w = min(w, 80); + let w = max(w, 80); let status = installed_versions.into_iter().rev().join(" "); if status.len() > w - 5 { rtxstatusln!(out, "{}...", &status[..w - 9]) From b753930749497076f675db4f99067684b75f26af Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:39:34 -0600 Subject: [PATCH 0133/1891] chore: set cache-control headers in s3 (#126) --- .github/workflows/rtx.yml | 13 ++++++------- README.md | 16 ++++++++-------- packaging/rpm/rtx.repo | 4 ++-- scripts/publish-s3.sh | 31 +++++++++++++++++++++++++++++++ scripts/release-aur.sh | 2 +- scripts/release.sh | 13 +------------ src/cli/render_help.rs | 16 ++++++++-------- 7 files changed, 57 insertions(+), 38 deletions(-) create mode 100755 scripts/publish-s3.sh diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 731ab7b00..d724fa5ef 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -222,6 +222,12 @@ jobs: with: node-version: '18.x' registry-url: 'https://registry.npmjs.org' + - name: Set AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-2 - uses: crazy-max/ghaction-import-gpg@v5 with: gpg_private_key: ${{ secrets.GPG_KEY }} @@ -236,13 +242,6 @@ jobs: - name: homebrew-tap push run: git push working-directory: homebrew-tap - - uses: jakejarvis/s3-sync-action@master - env: - AWS_S3_BUCKET: rtx-cli - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_REGION: 'us-west-2' # optional: defaults to us-east-1 - SOURCE_DIR: 'rtx.jdxcode.com' - name: GitHub Release Assets uses: softprops/action-gh-release@v1 diff --git a/README.md b/README.md index e4be25231..e6459ca04 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ _Polyglot runtime manager (asdf rust clone)_ Install rtx (other methods [here](#installation)): ```sh-session -$ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx +$ https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version rtx 1.6.1 ``` @@ -105,7 +105,7 @@ Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate file, rtx will automatically add itself to `PATH`. ```sh-session -$ curl https://rtx.jdxcode.com/install.sh | sh +$ curl https://rtx.pub/install.sh | sh ``` > **Note** @@ -117,7 +117,7 @@ $ curl https://rtx.jdxcode.com/install.sh | sh or if you're allergic to `| sh`: ```sh-session -$ curl https://rtx.jdxcode.com/rtx-latest-macos-arm64 > /usr/local/bin/rtx +$ curl https://rtx.pub/rtx-latest-macos-arm64 > /usr/local/bin/rtx ``` It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` @@ -185,8 +185,8 @@ $ mv rtx/bin/rtx /usr/local/bin For installation on Ubuntu/Debian: ```sh-session -wget -qO - https://rtx.jdxcode.com/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list sudo apt update sudo apt install -y rtx ``` @@ -195,7 +195,7 @@ sudo apt install -y rtx > > If you're on arm64 you'll need to run the following: > ``` -> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` ### dnf @@ -204,7 +204,7 @@ For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: ```sh-session dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo +dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo dnf install -y rtx ``` @@ -212,7 +212,7 @@ dnf install -y rtx ```sh-session yum install -y yum-utils -yum-config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo +yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo yum install -y rtx ``` diff --git a/packaging/rpm/rtx.repo b/packaging/rpm/rtx.repo index fe0f99c37..94053a357 100644 --- a/packaging/rpm/rtx.repo +++ b/packaging/rpm/rtx.repo @@ -1,6 +1,6 @@ [rtx-repo] name=RTX Repo -baseurl=https://rtx.jdxcode.com/rpm +baseurl=https://rtx.pub/rpm enabled=1 gpgcheck=1 -gpgkey=http://rtx.jdxcode.com/gpg-key.pub +gpgkey=http://rtx.pub/gpg-key.pub diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh new file mode 100755 index 000000000..4df0652ca --- /dev/null +++ b/scripts/publish-s3.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euxo pipefail + +cache_hour="max-age=3600,s-maxage=3600,public,immutable" +cache_day="max-age=86400,s-maxage=86400,public,immutable" +cache_week="max-age=604800,s-maxage=604800,public,immutable" + +platforms=( + linux-x64 + linux-arm64 + macos-x64 + macos-arm64 +) + +./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh +echo "$RTX_VERSION" | tr -d 'v' > "$RELEASE_DIR"/VERSION + +aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive +aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" \ + --include "rtx-latest-*" \ + --include "SHASUMS*" \ + --include "VERSION" \ + --include "install.sh" + +aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress +aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive +aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "repomd.xml*" +aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" + +aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive +aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_hour" --no-progress --no-progress --recursive diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index a078a6693..97f25f80a 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euxo pipefail -VERSION=$(curl https://rtx.jdxcode.com/VERSION | sed -e "s/^v//") +VERSION=$(curl https://rtx.pub/VERSION | sed -e "s/^v//") SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/v$VERSION.tar.gz" | sha512sum | awk '{print $1}') if [ ! -d aur ]; then diff --git a/scripts/release.sh b/scripts/release.sh index d84010c3d..f7a64cde7 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -52,19 +52,8 @@ gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd -mkdir -p rtx.jdxcode.com -./rtx/scripts/render-install.sh >rtx.jdxcode.com/install.sh - -rm -rf rtx.jdxcode.com/rpm -mv artifacts/rpm rtx.jdxcode.com/rpm - -rm -rf rtx.jdxcode.com/deb -mv artifacts/deb rtx.jdxcode.com/deb - -cp -vrf "$RELEASE_DIR/"* rtx.jdxcode.com -echo "$RTX_VERSION" | tr -d 'v' > rtx.jdxcode.com/VERSION - ./rtx/scripts/release-npm.sh +./rtx/scripts/publish-s3.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb pushd homebrew-tap diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index fbdcc9db9..2741f17d8 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -31,7 +31,7 @@ _{about}_ Install rtx (other methods [here](#installation)): ```sh-session -$ https://rtx.jdxcode.com/rtx-latest-macos-arm64 > ~/bin/rtx +$ https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version rtx {version} ``` @@ -123,7 +123,7 @@ Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate file, rtx will automatically add itself to `PATH`. ```sh-session -$ curl https://rtx.jdxcode.com/install.sh | sh +$ curl https://rtx.pub/install.sh | sh ``` > **Note** @@ -135,7 +135,7 @@ $ curl https://rtx.jdxcode.com/install.sh | sh or if you're allergic to `| sh`: ```sh-session -$ curl https://rtx.jdxcode.com/rtx-latest-macos-arm64 > /usr/local/bin/rtx +$ curl https://rtx.pub/rtx-latest-macos-arm64 > /usr/local/bin/rtx ``` It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` @@ -203,8 +203,8 @@ $ mv rtx/bin/rtx /usr/local/bin For installation on Ubuntu/Debian: ```sh-session -wget -qO - https://rtx.jdxcode.com/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list sudo apt update sudo apt install -y rtx ``` @@ -213,7 +213,7 @@ sudo apt install -y rtx > > If you're on arm64 you'll need to run the following: > ``` -> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdxcode.com/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` ### dnf @@ -222,7 +222,7 @@ For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: ```sh-session dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo +dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo dnf install -y rtx ``` @@ -230,7 +230,7 @@ dnf install -y rtx ```sh-session yum install -y yum-utils -yum-config-manager --add-repo https://rtx.jdxcode.com/rpm/rtx.repo +yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo yum install -y rtx ``` From e1c1442dfb7fb01ca84cd9050221f6112ba8e279 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:39:59 -0600 Subject: [PATCH 0134/1891] chore: Release rtx-cli version 1.7.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 547422e1e..350dcfc07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.6.1" +version = "1.7.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 3337028d2..75a400591 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.6.1" +version = "1.7.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e6459ca04..8c3a8b9bf 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version -rtx 1.6.1 +rtx 1.7.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -176,7 +176,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.1/rtx-v1.6.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.7.0/rtx-v1.7.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e3fdf9fdf..a77392938 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.6.1 +Version: 1.7.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 2741f17d8..b3d353965 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -194,7 +194,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.6.1/rtx-v1.6.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.7.0/rtx-v1.7.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 561408f7b05f2244247c6c4035f411f19729dd09 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:47:12 -0600 Subject: [PATCH 0135/1891] docs: lol --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8c3a8b9bf..f5899b246 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ _Polyglot runtime manager (asdf rust clone)_ Install rtx (other methods [here](#installation)): ```sh-session -$ https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx +$ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version rtx 1.7.0 ``` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index b3d353965..80b4e0719 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -31,7 +31,7 @@ _{about}_ Install rtx (other methods [here](#installation)): ```sh-session -$ https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx +$ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ rtx --version rtx {version} ``` From e4749eafdef9276ce911bf70175094a01a10ff06 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:48:12 -0600 Subject: [PATCH 0136/1891] docs: forgot chmod --- README.md | 1 + src/cli/render_help.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index f5899b246..9719fb39d 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx +$ chmod +x ~/bin/rtx $ rtx --version rtx 1.7.0 ``` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 80b4e0719..f20f26643 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -32,6 +32,7 @@ Install rtx (other methods [here](#installation)): ```sh-session $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx +$ chmod +x ~/bin/rtx $ rtx --version rtx {version} ``` From 564b71541c179b912104bd85a9a3160d200d459f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 11:02:27 -0600 Subject: [PATCH 0137/1891] docs: added instructions for testing rpm/deb --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d328267ef..fb36fcf73 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,3 +74,39 @@ This project uses husky which will automatically install a pre-commit hook: npm i # installs and configured husky precommit hook automatically git commit # will automatically run `just pre-commit` ``` + +## Testing packaging + +I test these with finch, but docker should work the same. This is only necessary to test +if actually changing the packaging setup. + +### Ubuntu (apt) + +This is for arm64, but you can change the arch to amd64 if you want. + +``` +finch run -ti --rm ubuntuapt update -y && apt install gpg sudo wget curl \ +&& wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null \ +&& echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list \ +&& apt update && apt install -y rtx && rtx -V +``` + +### Amazon Linux 2 (yum) + +``` +finch run -ti --rm amazonlinux +yum install -y yum-utils +yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo +yum install -y rtx +rtx -v +``` + +### Fedora (dnf) + +``` +finch run -ti --rm fedora +dnf install -y dnf-plugins-core +dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo +dnf install -y rtx +rtx -v +``` From 11a31ab68543cf5bf5955626c69fa574b164b8c6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 12:34:29 -0600 Subject: [PATCH 0138/1891] feat: colored help (#53) --- README.md | 67 ++++++++++++------------------------ src/cli/activate.rs | 23 ++++++++----- src/cli/alias/ls.rs | 16 ++++++--- src/cli/complete.rs | 17 ++++++--- src/cli/current.rs | 38 +++++++++++--------- src/cli/deactivate.rs | 23 ++++++++----- src/cli/direnv/activate.rs | 22 +++++++----- src/cli/doctor.rs | 19 ++++++---- src/cli/env.rs | 23 ++++++++----- src/cli/exec.rs | 25 +++++++++----- src/cli/global.rs | 29 ++++++++++------ src/cli/install.rs | 25 ++++++++------ src/cli/latest.rs | 25 +++++++++----- src/cli/local.rs | 41 +++++++++++++--------- src/cli/ls.rs | 31 ++++++++++------- src/cli/ls_remote.rs | 21 +++++++---- src/cli/mod.rs | 53 ++++++++++++++++------------ src/cli/plugins/install.rs | 21 +++++++---- src/cli/plugins/ls.rs | 22 ++++++------ src/cli/plugins/uninstall.rs | 16 ++++++--- src/cli/plugins/update.rs | 19 ++++++---- src/cli/settings/get.rs | 16 ++++++--- src/cli/settings/ls.rs | 16 ++++++--- src/cli/settings/set.rs | 16 ++++++--- src/cli/settings/unset.rs | 16 ++++++--- src/cli/uninstall.rs | 18 ++++++---- src/cli/where.rs | 32 ++++++++++------- src/ui/color.rs | 23 +++++++++++++ 28 files changed, 438 insertions(+), 275 deletions(-) diff --git a/README.md b/README.md index 9719fb39d..b8fe8a80f 100644 --- a/README.md +++ b/README.md @@ -524,7 +524,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ eval "$(rtx activate bash)" $ eval "$(rtx activate zsh)" @@ -574,7 +573,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx complete @@ -600,9 +598,7 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: - # outputs `.tool-versions` compatible format $ rtx current python 3.11.0 3.10.0 @@ -637,12 +633,11 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: - $ eval "$(rtx deactivate bash)" - $ eval "$(rtx deactivate zsh)" - $ rtx deactivate fish | source - $ execx($(rtx deactivate xonsh)) + $ eval "$(rtx deactivate bash)" + $ eval "$(rtx deactivate zsh)" + $ rtx deactivate fish | source + $ execx($(rtx deactivate xonsh)) ``` ### `rtx direnv activate` @@ -662,11 +657,10 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: - $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh - $ echo 'use rtx' > .envrc - $ direnv allow + $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh + $ echo 'use rtx' > .envrc + $ direnv allow ``` ### `rtx doctor` @@ -680,7 +674,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx doctor [WARN] plugin nodejs is not installed @@ -712,7 +705,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" @@ -752,12 +744,11 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x rtx x nodejs@20 -- node ./app.js # shorter alias -Specify command as a string: + # Specify command as a string: rtx exec nodejs@20 python@3.11 --command "node -v && python -V" ``` @@ -787,11 +778,10 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: # set the current version of nodejs to 20.x # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global nodejs@20 + $ rtx global nodejs@20 # set the current version of nodejs to 20.x # will use a fuzzy version (e.g.: 20) in .tool-versions file @@ -832,7 +822,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version @@ -856,11 +845,10 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx latest nodejs@18 # get the latest version of nodejs 18 18.0.0 - + $ rtx latest nodejs # get the latest stable version of nodejs 20.0.0 @@ -897,7 +885,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: # set the current version of nodejs to 20.x for the current directory # will use a precise version (e.g.: 20.0.0) in .tool-versions file @@ -934,13 +921,12 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx list -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) python 3.10.0 - + $ rtx list --current -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) @@ -964,7 +950,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx list-remote nodejs 18.0.0 @@ -1010,17 +995,16 @@ Options: -h, --help Print help (see a summary with '-h') +Examples: + $ rtx install nodejs # install the nodejs plugin using the shorthand repo: + # https://github.com/asdf-vm/asdf-plugins -EXAMPLES: - $ rtx install nodejs # install the nodejs plugin using the shorthand repo: - # https://github.com/asdf-vm/asdf-plugins - - $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git - # install the nodejs plugin using the git url + $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git + # install the nodejs plugin using the git url - $ rtx install https://github.com/asdf-vm/asdf-nodejs.git - # install the nodejs plugin using the git url only - # (nodejs is inferred from the url) + $ rtx install https://github.com/asdf-vm/asdf-nodejs.git + # install the nodejs plugin using the git url only + # (nodejs is inferred from the url) ``` ### `rtx plugins ls` @@ -1046,15 +1030,11 @@ Options: -h, --help Print help (see a summary with '-h') -List installed plugins -Can also show remotely available plugins to install. - Examples: - $ rtx plugins ls nodejs ruby - + $ rtx plugins ls --urls nodejs https://github.com/asdf-vm/asdf-nodejs.git ruby https://github.com/asdf-vm/asdf-ruby.git @@ -1098,7 +1078,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx uninstall nodejs @@ -1123,10 +1102,9 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: - rtx plugins update --all # update all plugins - rtx plugins update nodejs # update only nodejs + $ rtx plugins update --all # update all plugins + $ rtx plugins update nodejs # update only nodejs ``` ### `rtx settings get` @@ -1235,7 +1213,6 @@ Options: -h, --help Print help (see a summary with '-h') - Examples: $ rtx uninstall nodejs@18 # will uninstall ALL nodejs-18.x versions $ rtx uninstall nodejs # will uninstall ALL nodejs versions diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 6f715938d..702cc2d01 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,10 +1,14 @@ +use atty::Stream; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::env; use crate::output::Output; use crate::shell::{get_shell, ShellType}; +use crate::ui::color::Color; /// Enables rtx to automatically modify runtimes when changing directory /// @@ -12,7 +16,7 @@ use crate::shell::{get_shell, ShellType}; /// Otherwise, it will only take effect in the current session. /// (e.g. ~/.bashrc) #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Activate { /// Shell type to generate the script for #[clap(long, short, hide = true)] @@ -50,13 +54,16 @@ impl Command for Activate { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ eval "$(rtx activate bash)" - $ eval "$(rtx activate zsh)" - $ rtx activate fish | source - $ execx($(rtx activate xonsh)) -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ eval "$(rtx activate bash)" + $ eval "$(rtx activate zsh)" + $ rtx activate fish | source + $ execx($(rtx activate xonsh)) + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 32792cc12..725f760c3 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,10 +1,13 @@ +use atty::Stream; use color_eyre::eyre::Result; -use indoc::indoc; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::PluginName; +use crate::ui::color::Color; /// List aliases /// Shows the aliases that can be specified. @@ -15,7 +18,7 @@ use crate::plugins::PluginName; /// [alias.nodejs] /// lts = "18.0.0" #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct AliasLs { /// Show aliases for #[clap(short, long)] @@ -39,11 +42,14 @@ impl Command for AliasLs { } } -const AFTER_LONG_HELP: &str = indoc! {r#" - Examples: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} $ rtx aliases nodejs lts/hydrogen 18.0.0 - "#}; + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/complete.rs b/src/cli/complete.rs index f5b40979c..30b9b30a3 100644 --- a/src/cli/complete.rs +++ b/src/cli/complete.rs @@ -1,3 +1,4 @@ +use atty::Stream; use color_eyre::eyre::Result; use std::io::Cursor; @@ -6,11 +7,14 @@ use crate::config::Config; use crate::output::Output; use crate::cli::Cli; +use crate::ui::color::Color; use clap_complete::generate; +use indoc::formatdoc; +use once_cell::sync::Lazy; /// generate shell completions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Complete { /// shell type #[clap(long, short)] @@ -27,10 +31,13 @@ impl Command for Complete { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx complete -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx complete + "#, COLOR.header("Examples:")} +}); // #[cfg(test)] // mod test { diff --git a/src/cli/current.rs b/src/cli/current.rs index a8e1bbb1f..cd185b314 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,10 +1,14 @@ +use atty::Stream; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use std::sync::Arc; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; +use crate::ui::color::Color; /// Shows currently active, and installed runtime versions /// @@ -12,7 +16,7 @@ use crate::plugins::Plugin; /// only shows the runtime and/or version so it's /// designed to fit into scripts more easily. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Current { /// plugin to show versions of /// @@ -88,23 +92,25 @@ impl Current { } } -const AFTER_LONG_HELP: &str = r#" -Examples: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + # outputs `.tool-versions` compatible format + $ rtx current + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + nodejs 18.13.0 - # outputs `.tool-versions` compatible format - $ rtx current - python 3.11.0 3.10.0 - shfmt 3.6.0 - shellcheck 0.9.0 - nodejs 18.13.0 + $ rtx current nodejs + 18.13.0 - $ rtx current nodejs - 18.13.0 - - # can output multiple versions - $ rtx current python - 3.11.0 3.10.0 -"#; + # can output multiple versions + $ rtx current python + 3.11.0 3.10.0 + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 5c51f5f13..30a174a3e 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -1,15 +1,19 @@ +use atty::Stream; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; +use crate::ui::color::Color; /// disable rtx for current shell session /// /// This can be used to temporarily disable rtx in a shell session. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Deactivate { /// shell type to generate the script for #[clap(long, short, hide = true)] @@ -31,13 +35,16 @@ impl Command for Deactivate { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ eval "$(rtx deactivate bash)" - $ eval "$(rtx deactivate zsh)" - $ rtx deactivate fish | source - $ execx($(rtx deactivate xonsh)) -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ eval "$(rtx deactivate bash)" + $ eval "$(rtx deactivate zsh)" + $ rtx deactivate fish | source + $ execx($(rtx deactivate xonsh)) + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index d3ea81ef3..fdfa6baef 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,9 +1,12 @@ +use atty::Stream; use color_eyre::eyre::Result; -use indoc::indoc; +use indoc::{formatdoc, indoc}; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; /// Output direnv function to use rtx inside direnv /// @@ -13,7 +16,7 @@ use crate::output::Output; /// you should run this command after installing new plugins. Otherwise /// direnv may not know to update environment variables when legacy file versions change. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct DirenvActivate {} impl Command for DirenvActivate { @@ -33,9 +36,12 @@ impl Command for DirenvActivate { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh - $ echo 'use rtx' > .envrc - $ direnv allow -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh + $ echo 'use rtx' > .envrc + $ direnv allow + "#, COLOR.header("Examples:")} +}); diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 943c5059a..9c952559b 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -1,13 +1,17 @@ +use atty::Stream; use color_eyre::eyre::{eyre, Result}; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::env; use crate::output::Output; +use crate::ui::color::Color; /// Check rtx installation for possible problems. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Doctor {} impl Command for Doctor { @@ -38,11 +42,14 @@ impl Command for Doctor { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx doctor - [WARN] plugin nodejs is not installed -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx doctor + [WARN] plugin nodejs is not installed + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/env.rs b/src/cli/env.rs index 918aa4aa5..04f4fe650 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,10 +1,14 @@ +use atty::Stream; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; +use crate::ui::color::Color; /// exports env vars to activate rtx in a single shell session /// @@ -14,7 +18,7 @@ use crate::shell::{get_shell, ShellType}; /// Unfortunately, it requires `eval` to work since it's not written in Bash though. /// It's also useful just to see what environment variables rtx sets. #[derive(Debug, clap::Args)] -#[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Env { /// Shell type to generate environment variables for #[clap(long, short)] @@ -46,13 +50,16 @@ impl Command for Env { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ eval "$(rtx env -s bash)" - $ eval "$(rtx env -s zsh)" - $ rtx env -s fish | source - $ execx($(rtx env -s xonsh)) -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ eval "$(rtx env -s bash)" + $ eval "$(rtx env -s zsh)" + $ rtx env -s fish | source + $ execx($(rtx env -s xonsh)) + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 00cf8c72e..09aa58355 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -1,8 +1,11 @@ +use atty::Stream; use std::ffi::{OsStr, OsString}; use color_eyre::eyre::{eyre, Result}; use duct::IntoExecutablePath; use indexmap::IndexMap; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -12,6 +15,7 @@ use crate::cmd; use crate::config::Config; use crate::env; use crate::output::Output; +use crate::ui::color::Color; /// execute a command with runtime(s) set /// @@ -24,7 +28,7 @@ use crate::output::Output; /// /// The "--" separates runtimes from the commands to pass along to the subprocess. #[derive(Debug, clap::Args)] -#[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Exec { /// runtime(s) to start /// @@ -105,14 +109,17 @@ fn parse_command( } } -const AFTER_LONG_HELP: &str = r#" -Examples: - rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x - rtx x nodejs@20 -- node ./app.js # shorter alias - -Specify command as a string: - rtx exec nodejs@20 python@3.11 --command "node -v && python -V" -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x + rtx x nodejs@20 -- node ./app.js # shorter alias + + # Specify command as a string: + rtx exec nodejs@20 python@3.11 --command "node -v && python -V" + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/global.rs b/src/cli/global.rs index eccc075a8..c3e418c7f 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,10 +1,14 @@ +use atty::Stream; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::{config_file, Config}; use crate::output::Output; use crate::plugins::PluginName; +use crate::ui::color::Color; use crate::{dirs, env}; /// sets global .tool-versions to include a specified runtime @@ -12,7 +16,7 @@ use crate::{dirs, env}; /// this file is `$HOME/.tool-versions` by default /// use `rtx local` to set a runtime version locally in the current directory #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Global { /// runtimes /// @@ -60,16 +64,19 @@ impl Command for Global { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - # set the current version of nodejs to 20.x - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global nodejs@20 - - # set the current version of nodejs to 20.x - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx global --fuzzy nodejs@20 -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + # set the current version of nodejs to 20.x + # will use a precise version (e.g.: 20.0.0) in .tool-versions file + $ rtx global nodejs@20 + + # set the current version of nodejs to 20.x + # will use a fuzzy version (e.g.: 20) in .tool-versions file + $ rtx global --fuzzy nodejs@20 + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/install.rs b/src/cli/install.rs index 46914b3b9..10856916b 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,5 +1,7 @@ use atty::Stream::Stderr; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use owo_colors::Stream; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; @@ -11,7 +13,7 @@ use crate::output::Output; use crate::plugins::InstallType::Version; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; -use crate::ui::color::cyan; +use crate::ui::color::{cyan, Color}; /// install a runtime /// @@ -20,7 +22,7 @@ use crate::ui::color::cyan; /// For that, you must set up a `.tool-version` file manually or with `rtx local/global`. /// Or you can call a runtime explicitly with `rtx exec @ -- `. #[derive(Debug, clap::Args)] -#[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Install { /// runtime(s) to install /// @@ -147,14 +149,17 @@ fn get_all_plugin_names(config: &Config) -> Vec { .collect() } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx install nodejs@18.0.0 # install specific nodejs version - $ rtx install nodejs@18 # install fuzzy nodejs version - $ rtx install nodejs # install version specified in .tool-versions - $ rtx install # installs all runtimes specified in .tool-versions for installed plugins - $ rtx install --all # installs all runtimes and all plugins -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx install nodejs@18.0.0 # install specific nodejs version + $ rtx install nodejs@18 # install fuzzy nodejs version + $ rtx install nodejs # install version specified in .tool-versions + $ rtx install # installs all runtimes specified in .tool-versions for installed plugins + $ rtx install --all # installs all runtimes and all plugins + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/latest.rs b/src/cli/latest.rs index ec73c6637..7c75bbea6 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,14 +1,18 @@ +use atty::Stream; use color_eyre::eyre::{eyre, Result}; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; +use crate::ui::color::Color; /// get the latest runtime version of a plugin's runtimes #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Latest { /// Runtime to get the latest version of #[clap(value_parser = RuntimeArgParser)] @@ -41,14 +45,17 @@ impl Command for Latest { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx latest nodejs@18 # get the latest version of nodejs 18 - 18.0.0 - - $ rtx latest nodejs # get the latest stable version of nodejs - 20.0.0 -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx latest nodejs@18 # get the latest version of nodejs 18 + 18.0.0 + + $ rtx latest nodejs # get the latest stable version of nodejs + 20.0.0 + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/local.rs b/src/cli/local.rs index 307a34a0b..1c24137da 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -1,10 +1,14 @@ +use atty::Stream; use color_eyre::eyre::{eyre, ContextCompat, Result}; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::{config_file, Config}; use crate::output::Output; use crate::plugins::PluginName; +use crate::ui::color::Color; use crate::{dirs, env, file}; /// Sets .tool-versions to include a specific runtime @@ -12,7 +16,7 @@ use crate::{dirs, env, file}; /// use this to set the runtime version when within a directory /// use `rtx global` to set a runtime version globally #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Local { /// runtimes to add to .tool-versions /// @@ -78,22 +82,25 @@ impl Command for Local { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - # set the current version of nodejs to 20.x for the current directory - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx local nodejs@20 - - # set nodejs to 20.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@20 - - # set the current version of nodejs to 20.x for the current directory - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx local --fuzzy nodejs@20 - - # removes nodejs from .tool-versions - $ rtx local --remove=nodejs -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + # set the current version of nodejs to 20.x for the current directory + # will use a precise version (e.g.: 20.0.0) in .tool-versions file + $ rtx local nodejs@20 + + # set nodejs to 20.x for the current project (recurses up to find .tool-versions) + $ rtx local -p nodejs@20 + + # set the current version of nodejs to 20.x for the current directory + # will use a fuzzy version (e.g.: 20) in .tool-versions file + $ rtx local --fuzzy nodejs@20 + + # removes nodejs from .tool-versions + $ rtx local --remove=nodejs + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 7bbe2ae70..68f133150 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -4,7 +4,9 @@ use std::collections::HashMap; use std::sync::Arc; use color_eyre::eyre::Result; +use indoc::formatdoc; use itertools::Itertools; +use once_cell::sync::Lazy; use owo_colors::{OwoColorize, Stream}; use versions::Versioning; @@ -13,14 +15,14 @@ use crate::config::{Config, PluginSource}; use crate::output::Output; use crate::plugins::PluginName; use crate::runtimes::RuntimeVersion; -use crate::ui::color::{cyan, dimmed, green, red}; +use crate::ui::color::{cyan, dimmed, green, red, Color}; /// list installed runtime versions /// /// The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. /// (Assuming `rtx activate` or `rtx env` is in use). #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Ls { /// Only show runtimes from [PLUGIN] #[clap(long, short)] @@ -132,17 +134,20 @@ fn get_runtime_list( Ok(rvs) } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx list - -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) - -> python 3.11.0 (set by ~/.tool-versions) - python 3.10.0 - - $ rtx list --current - -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) - -> python 3.11.0 (set by ~/.tool-versions) -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx list + -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + -> python 3.11.0 (set by ~/.tool-versions) + python 3.10.0 + + $ rtx list --current + -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + -> python 3.11.0 (set by ~/.tool-versions) + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 279d10a0c..2f80ce2a5 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,16 +1,20 @@ +use atty::Stream; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; +use crate::ui::color::Color; /// list runtime versions available for install /// /// note that these versions are cached for commands like `rtx install nodejs@latest` /// however _this_ command will always clear that cache and fetch the latest remote versions #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list-remote", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "list-remote", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct LsRemote { /// Plugin #[clap()] @@ -33,12 +37,15 @@ impl Command for LsRemote { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx list-remote nodejs - 18.0.0 - 20.0.0 -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx list-remote nodejs + 18.0.0 + 20.0.0 + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 448fdf7d4..da436d78e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,11 +1,14 @@ -use clap::{ColorChoice, FromArgMatches, Subcommand}; +use atty::Stream; +use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; -use indoc::indoc; +use indoc::{formatdoc, indoc}; use log::LevelFilter; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; mod activate; mod alias; @@ -127,8 +130,7 @@ impl Cli { .long_about(LONG_ABOUT) .arg_required_else_help(true) .subcommand_required(true) - .after_help(AFTER_HELP) - .color(ColorChoice::Never) + .after_help(AFTER_HELP.as_str()) .arg(args::log_level::LogLevel::arg()) .arg(args::verbose::Verbose::arg()), ) @@ -157,30 +159,37 @@ impl Cli { } } -const LONG_ABOUT: &str = indoc! {" -rtx is a tool for managing runtime versions. For example, use this to install a particular -version of node and ruby for a project. Using `rtx activate`, you can also have your shell -automatically switch to the correct node and ruby versions when you `cd` into the project's -directory. - -It is inspired by asdf and uses asdf's plugin ecosystem under the hood: https://asdf-vm.com/ -"}; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); -const AFTER_HELP: &str = indoc! {" - Examples: +const LONG_ABOUT: &str = indoc! {" +rtx is a tool for managing runtime versions. - rtx install nodejs@20.0.0 Install a specific version number - rtx install nodejs@20.0 Install a fuzzy version number - rtx local nodejs@20 Use node-20.x in current project - rtx global nodejs@20 Use node-20.x as default +Use this to install a particular version of node or ruby for a project. Using `rtx activate`, +you can also have your shell automatically switch to the correct node and ruby versions when you +`cd` into the project's directory. - rtx install nodejs Install the version specified in .tool-versions - rtx local nodejs Use latest node in current directory - rtx global system Use system node as default +It's a replacement for tools like `nvm`, `nodenv`, `rbenv`, `rvm`, `chruby`, `pyenv`, etc. that +works for any language. It's also great for managing linters/tools like `jq` and `shellcheck`. - rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to node-20.x +It is inspired by asdf and uses asdf's plugin ecosystem under the hood: https://asdf-vm.com/ "}; +static AFTER_HELP: Lazy = Lazy::new(|| { + formatdoc! { " + {} + rtx install nodejs@20.0.0 Install a specific node version + rtx install nodejs@20.0 Install a version matching a prefix + rtx local nodejs@20 Use node-20.x in current project + rtx global nodejs@20 Use node-20.x as default + + rtx install nodejs Install the version specified in .tool-versions + rtx local nodejs Use latest node in current directory + rtx global system Use system node everywhere unless overridden + + rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to node-20.x +", COLOR.header("Examples:") } +}); + #[cfg(test)] pub mod test { use crate::config::MissingRuntimeBehavior::AutoInstall; diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 788cbea92..133ece28c 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,6 +1,9 @@ +use atty::Stream; use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; +use indoc::formatdoc; +use once_cell::sync::Lazy; use url::Url; use crate::cli::command::Command; @@ -8,6 +11,7 @@ use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; use crate::shorthand_repository::ShorthandRepo; +use crate::ui::color::Color; /// install a plugin /// @@ -16,7 +20,7 @@ use crate::shorthand_repository::ShorthandRepo; /// /// This behavior can be modified in ~/.rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct PluginsInstall { /// The name of the plugin to install /// @@ -118,18 +122,21 @@ fn get_name_from_url(url: &str) -> Result { Err(eyre!("could not infer plugin name from url: {}", url)) } -const AFTER_LONG_HELP: &str = r#" -EXAMPLES: - $ rtx install nodejs # install the nodejs plugin using the shorthand repo: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx install nodejs # install the nodejs plugin using the shorthand repo: # https://github.com/asdf-vm/asdf-plugins - $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git + $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git # install the nodejs plugin using the git url - $ rtx install https://github.com/asdf-vm/asdf-nodejs.git + $ rtx install https://github.com/asdf-vm/asdf-nodejs.git # install the nodejs plugin using the git url only # (nodejs is inferred from the url) -"#; + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 2e532f41f..7f26d8e7a 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -1,16 +1,19 @@ +use atty::Stream; use color_eyre::eyre::Result; -use indoc::indoc; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::cli::plugins::ls_remote::PluginsLsRemote; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; /// List installed plugins /// /// Can also show remotely available plugins to install. #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct PluginsLs { /// list all available remote plugins /// @@ -44,20 +47,19 @@ impl Command for PluginsLs { } } -const AFTER_LONG_HELP: &str = indoc! {r#" - List installed plugins - Can also show remotely available plugins to install. - - Examples: - +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} $ rtx plugins ls nodejs ruby - + $ rtx plugins ls --urls nodejs https://github.com/asdf-vm/asdf-nodejs.git ruby https://github.com/asdf-vm/asdf-ruby.git - "#}; + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 52a96ca14..197b91e30 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,13 +1,16 @@ use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use owo_colors::{OwoColorize, Stream}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; /// removes a plugin #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP.as_str())] pub struct PluginsUninstall { /// plugin to remove #[clap()] @@ -37,10 +40,13 @@ impl Command for PluginsUninstall { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx uninstall nodejs -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx uninstall nodejs + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 436fed71f..00c6274a9 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,19 +1,21 @@ use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; +use indoc::formatdoc; +use once_cell::sync::Lazy; use owo_colors::Stream; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; -use crate::ui::color::cyan; +use crate::ui::color::{cyan, Color}; /// updates a plugin to the latest version /// /// note: this updates the plugin itself, not the runtime versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "upgrade", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, alias = "upgrade", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Update { /// plugin(s) to update #[clap()] @@ -47,11 +49,14 @@ impl Command for Update { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - rtx plugins update --all # update all plugins - rtx plugins update nodejs # update only nodejs -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx plugins update --all # update all plugins + $ rtx plugins update nodejs # update only nodejs + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 19d03ddbc..c31a252a8 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,9 +1,12 @@ +use atty::Stream; use color_eyre::eyre::{eyre, Result}; -use indoc::indoc; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; /// Show a current setting /// @@ -12,7 +15,7 @@ use crate::output::Output; /// Note that aliases are also stored in this file /// but managed separately with `rtx aliases get` #[derive(Debug, clap::Args)] -#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct SettingsGet { /// The setting to show pub key: String, @@ -27,11 +30,14 @@ impl Command for SettingsGet { } } -const AFTER_LONG_HELP: &str = indoc! {r#" - Examples: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} $ rtx settings get legacy_version_file true - "#}; + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index c13d93278..81ae9b02e 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,9 +1,12 @@ +use atty::Stream; use color_eyre::eyre::Result; -use indoc::indoc; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; /// Show current settings /// @@ -12,7 +15,7 @@ use crate::output::Output; /// Note that aliases are also stored in this file /// but managed separately with `rtx aliases` #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct SettingsLs {} impl Command for SettingsLs { @@ -24,11 +27,14 @@ impl Command for SettingsLs { } } -const AFTER_LONG_HELP: &str = indoc! {r#" - Examples: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} $ rtx settings legacy_version_file = false - "#}; + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index df3ec9320..38e48b4bf 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,16 +1,19 @@ +use atty::Stream; use color_eyre::eyre::{eyre, Result}; -use indoc::indoc; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; /// Add/update a setting /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct SettingsSet { /// The setting to set pub key: String, @@ -52,10 +55,13 @@ fn parse_i64(value: &str) -> Result { } } -const AFTER_LONG_HELP: &str = indoc! {r#" - Examples: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} $ rtx settings set legacy_version_file true - "#}; + "#, COLOR.header("Examples:")} +}); #[cfg(test)] pub mod test { diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index b72a661ba..a0c82b543 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,16 +1,19 @@ +use atty::Stream; use color_eyre::eyre::Result; -use indoc::indoc; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; +use crate::ui::color::Color; /// Clears a setting /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases=["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] +#[clap(visible_aliases=["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct SettingsUnset { /// The setting to remove pub key: String, @@ -24,10 +27,13 @@ impl Command for SettingsUnset { } } -const AFTER_LONG_HELP: &str = indoc! {r#" - Examples: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} $ rtx settings unset legacy_version_file - "#}; + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index f98a52a9d..192ddcc60 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,5 +1,7 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; +use indoc::formatdoc; use itertools::Itertools; +use once_cell::sync::Lazy; use owo_colors::OwoColorize; use owo_colors::Stream; @@ -8,10 +10,11 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; use crate::output::Output; +use crate::ui::color::Color; /// removes runtime versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Uninstall { /// runtime(s) to remove #[clap(required = true, value_parser = RuntimeArgParser)] @@ -73,8 +76,11 @@ impl Command for Uninstall { } } -const AFTER_LONG_HELP: &str = r#" -Examples: - $ rtx uninstall nodejs@18 # will uninstall ALL nodejs-18.x versions - $ rtx uninstall nodejs # will uninstall ALL nodejs versions -"#; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx uninstall nodejs@18 # will uninstall ALL nodejs-18.x versions + $ rtx uninstall nodejs # will uninstall ALL nodejs versions + "#, COLOR.header("Examples:")} +}); diff --git a/src/cli/where.rs b/src/cli/where.rs index 2496bce8c..5d86157ba 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,16 +1,20 @@ +use atty::Stream; use color_eyre::eyre::Result; +use indoc::formatdoc; +use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; use crate::output::Output; +use crate::ui::color::Color; /// Display the installation path for a runtime /// /// Must be installed. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, hide = true)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), hide = true)] pub struct Where { /// runtime(s) to look up /// if "@" is specified, it will show the latest installed version that matches the prefix @@ -45,19 +49,21 @@ impl Command for Where { } } -const AFTER_LONG_HELP: &str = r#" -Examples: +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + # Show the latest installed version of nodejs + # If it is is not installed, errors + $ rtx where nodejs@20 + /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 - # Show the latest installed version of nodejs - # If it is is not installed, errors - $ rtx where nodejs@20 - /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 - - # Show the current, active install directory of nodejs - # Errors if nodejs is not referenced in any .tool-version file - $ rtx where nodejs - /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 -"#; + # Show the current, active install directory of nodejs + # Errors if nodejs is not referenced in any .tool-version file + $ rtx where nodejs + /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + "#, COLOR.header("Examples:")} +}); #[cfg(test)] mod test { diff --git a/src/ui/color.rs b/src/ui/color.rs index b2cb0b5f8..b000ce3f1 100644 --- a/src/ui/color.rs +++ b/src/ui/color.rs @@ -21,3 +21,26 @@ pub fn _bright_green(stream: Stream, s: &str) -> String { pub fn red(stream: Stream, s: &str) -> String { s.if_supports_color(stream, |s| s.red()).to_string() } + +pub struct Color { + stream: Stream, +} + +impl Color { + pub fn new(stream: Stream) -> Self { + Self { stream } + } + + pub fn header(&self, title: &str) -> String { + self.underline(&self.bold(title)) + } + + pub fn bold(&self, s: &str) -> String { + s.if_supports_color(self.stream, |s| s.bold()).to_string() + } + + pub fn underline(&self, s: &str) -> String { + s.if_supports_color(self.stream, |s| s.underline()) + .to_string() + } +} From 9df10fdaf986fed2ea8d3f97962e24fee3c9217d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 12:34:48 -0600 Subject: [PATCH 0139/1891] feat: show os/arch on `rtx version` (#127) --- src/cli/version.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index 79f0da97e..32d42c3f6 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,5 +1,7 @@ +use std::string::ToString; + use color_eyre::eyre::Result; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use crate::build_time::BUILD_TIME; use crate::cli::command::Command; @@ -10,17 +12,29 @@ use crate::output::Output; #[clap(about = "Show rtx version", alias = "v")] pub struct Version {} -lazy_static! { - pub static ref VERSION: String = format!( - "{} (built {})", +pub static OS: Lazy = Lazy::new(|| std::env::consts::OS.into()); +pub static ARCH: Lazy = Lazy::new(|| { + match std::env::consts::ARCH { + "x86_64" => "x64", + "aarch64" => "arm64", + _ => std::env::consts::ARCH, + } + .to_string() +}); + +pub static VERSION: Lazy = Lazy::new(|| { + format!( + "{} {}-{} (built {})", if cfg!(debug_assertions) { format!("{}-DEBUG", env!("CARGO_PKG_VERSION")) } else { env!("CARGO_PKG_VERSION").to_string() }, - BUILD_TIME.format("%Y-%m-%d") - ); -} + *OS, + *ARCH, + BUILD_TIME.format("%Y-%m-%d"), + ) +}); impl Command for Version { fn run(self, _config: Config, out: &mut Output) -> Result<()> { From 3b4dceb7d3f74f94603ef13cb3e5b1e19aa76313 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 12:53:46 -0600 Subject: [PATCH 0140/1891] bug: fix RTX_VERBOSE=1 --- src/config/settings.rs | 3 ++- src/env.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/config/settings.rs b/src/config/settings.rs index e917348c9..09b564602 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -5,6 +5,7 @@ use indexmap::IndexMap; use crate::config::AliasMap; use crate::env; +use crate::env::RTX_VERBOSE; use crate::plugins::PluginName; use crate::ui::prompt::is_tty; @@ -30,7 +31,7 @@ impl Default for Settings { plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), plugin_repository_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), aliases: IndexMap::new(), - verbose: !is_tty(), + verbose: *RTX_VERBOSE || !is_tty(), } } } diff --git a/src/env.rs b/src/env.rs index 8bbb3f51e..d6ecfa3be 100644 --- a/src/env.rs +++ b/src/env.rs @@ -81,6 +81,7 @@ lazy_static! { var("RTX_MISSING_RUNTIME_BEHAVIOR").ok() }; pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); + pub static ref RTX_VERBOSE: bool = var_is_true("RTX_VERBOSE"); pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); From 33bdccafa19e9674e7c4c940f8d93cbbcdce8cb0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 12:58:55 -0600 Subject: [PATCH 0141/1891] ui: clean up prompt colors --- src/plugins/mod.rs | 19 ++++++++++++------- src/runtimes/mod.rs | 25 ++++++------------------- src/ui/color.rs | 8 ++++++++ src/ui/prompt.rs | 11 ++++++++--- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 0f2eb2a9d..d447a9468 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -9,6 +9,7 @@ use color_eyre::eyre::WrapErr; use color_eyre::eyre::{eyre, Result}; use itertools::Itertools; use lazy_static::lazy_static; +use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; @@ -23,7 +24,7 @@ use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::shorthand_repository::ShorthandRepo; -use crate::ui::color::cyan; +use crate::ui::color::{cyan, Color}; use crate::ui::prompt; use crate::ui::spinner::Spinner; use crate::{dirs, file}; @@ -108,6 +109,7 @@ impl Plugin { } pub fn ensure_installed(&self, settings: &Settings) -> Result { + static COLOR: Lazy = Lazy::new(|| Color::new(Stderr)); if self.is_installed() { return Ok(true); } @@ -119,13 +121,16 @@ impl Plugin { self.install(settings, &repo)?; Ok(true) } - MissingRuntimeBehavior::Prompt => match prompt::prompt_for_install(&self.name) { - true => { - self.install(settings, &repo)?; - Ok(true) + MissingRuntimeBehavior::Prompt => { + match prompt::prompt_for_install(&format!("plugin {}", COLOR.cyan(&self.name))) + { + true => { + self.install(settings, &repo)?; + Ok(true) + } + false => Ok(false), } - false => Ok(false), - }, + } MissingRuntimeBehavior::Warn => { warn!("{}", PluginNotInstalled(self.name.clone())); Ok(false) diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index 150f48aee..6334391fc 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; -use owo_colors::{OwoColorize, Stream}; +use once_cell::sync::Lazy; use versions::Versioning; use runtime_conf::RuntimeConf; @@ -18,13 +18,15 @@ use crate::config::{MissingRuntimeBehavior, Settings}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; -use crate::ui::color::cyan; +use crate::ui::color::{cyan, Color}; use crate::ui::prompt; use crate::ui::spinner::Spinner; use crate::{dirs, env, fake_asdf, file}; mod runtime_conf; +static COLOR: Lazy = Lazy::new(|| Color::new(Stderr)); + /// These represent individual plugin@version pairs of runtimes /// installed to ~/.local/share/rtx/runtimes #[derive(Debug, Clone)] @@ -162,7 +164,7 @@ impl RuntimeVersion { Ok(true) } MissingRuntimeBehavior::Prompt => { - if prompt_for_install(&format!("{self}")) { + if prompt::prompt_for_install(&COLOR.cyan(&self.to_string())) { self.install(InstallType::Version, config)?; Ok(true) } else { @@ -206,9 +208,7 @@ impl RuntimeVersion { remove_dir_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", - dir.to_str() - .unwrap() - .if_supports_color(Stream::Stderr, |t| t.cyan()) + COLOR.cyan(dir.to_str().unwrap()) ) }) }; @@ -279,19 +279,6 @@ impl PartialEq for RuntimeVersion { } } -fn prompt_for_install(thing: &str) -> bool { - match prompt::is_tty() { - true => { - eprint!( - "rtx: Would you like to install {}? [Y/n] ", - thing.if_supports_color(Stream::Stderr, |s| s.bold()) - ); - matches!(prompt::prompt().to_lowercase().as_str(), "" | "y" | "yes") - } - false => false, - } -} - fn build_script_man( version: &str, plugin_path: &Path, diff --git a/src/ui/color.rs b/src/ui/color.rs index b000ce3f1..c641690ae 100644 --- a/src/ui/color.rs +++ b/src/ui/color.rs @@ -35,6 +35,10 @@ impl Color { self.underline(&self.bold(title)) } + pub fn dimmed(&self, s: &str) -> String { + s.if_supports_color(self.stream, |s| s.dimmed()).to_string() + } + pub fn bold(&self, s: &str) -> String { s.if_supports_color(self.stream, |s| s.bold()).to_string() } @@ -43,4 +47,8 @@ impl Color { s.if_supports_color(self.stream, |s| s.underline()) .to_string() } + + pub fn cyan(&self, s: &str) -> String { + s.if_supports_color(self.stream, |s| s.cyan()).to_string() + } } diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index b3f02523d..8ae444d84 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,6 +1,10 @@ -use owo_colors::OwoColorize; +use crate::ui::color::Color; +use atty::Stream; +use once_cell::sync::Lazy; use std::io::stdin; +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); + pub fn prompt() -> String { let mut input = String::new(); stdin().read_line(&mut input).expect("error reading stdin"); @@ -12,8 +16,9 @@ pub fn prompt_for_install(thing: &str) -> bool { match is_tty() { true => { eprint!( - "rtx: Would you like to install plugin {}? [Y/n] ", - thing.cyan() + "{} Would you like to install {}? [Y/n] ", + COLOR.dimmed("rtx:"), + thing, ); matches!(prompt().to_lowercase().as_str(), "" | "y" | "yes") } From 20074907798fb632e6f79eec01178f30936fb7fa Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 13:56:40 -0600 Subject: [PATCH 0142/1891] feat: bake shortname repository into codebase (#129) The shortname repository can be persisted into a simple file. This is not a significant amount of data so the cost is minimal. I suppose the downside is this means any changes will need to wait for a new rtx release, but I do not see that as a major problem. As a bonus, I was able to add an alias for node so now you can use node or nodejs and rtx will work the same way --- README.md | 19 +- scripts/update-shorthand-repo.sh | 30 + src/cli/plugins/install.rs | 20 +- src/cli/plugins/ls_remote.rs | 12 +- src/cli/render_help.rs | 19 +- src/cli/settings/set.rs | 14 - ..._cli__settings__ls__test__settings_ls.snap | 2 - ...li__settings__set__test__settings_set.snap | 2 - src/cli/settings/unset.rs | 2 - src/config/config_file/rtxrc.rs | 7 - src/config/settings.rs | 27 - src/main.rs | 3 +- src/plugins/mod.rs | 17 +- src/shorthand.rs | 10 + src/shorthand_list.rs | 1190 +++++++++++++++++ src/shorthand_repository.rs | 141 -- ...orthand_repository__tests__lookup_err.snap | 5 - src/test.rs | 2 - test/config/config.toml | 2 - 19 files changed, 1256 insertions(+), 268 deletions(-) create mode 100755 scripts/update-shorthand-repo.sh create mode 100644 src/shorthand.rs create mode 100644 src/shorthand_list.rs delete mode 100644 src/shorthand_repository.rs delete mode 100644 src/snapshots/rtx__shorthand_repository__tests__lookup_err.snap diff --git a/README.md b/README.md index b8fe8a80f..691fdc72e 100644 --- a/README.md +++ b/README.md @@ -346,18 +346,11 @@ always_keep_download = false # deleted after install by default # configure how frequently (in minutes) to fetch updated plugin repository changes # this is updated whenever a new runtime is installed +# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates -# configure how frequently (in minutes) to fetch updated shortname repository changes -# note this is not plugins themselves, it's the shortname mappings -# e.g.: nodejs -> https://github.com/asdf-vm/asdf-nodejs.git -plugin_repository_last_check_duration = 10080 # (one week) set to 0 to disable updates - verbose = false # see explanation under `RTX_VERBOSE` -# disables the short name repository (described above) -disable_plugin_short_name_repository = false - [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x # this can also be specified in a plugin (see below in "Aliases") @@ -1378,16 +1371,6 @@ things are hardcoded but I'm happy to add more settings to cover whatever config Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear to be updating, this is a good place to start. -### Shorthand Repository Cache - -asdf maintains a [shorthand repository](https://github.com/asdf-vm/asdf-plugins) which maps plugin -short names (e.g.: `nodejs`) to full repository names (e.g.: `https://github.com/asdf-vm/asdf-nodejs`). - -This is stored in `~/.local/share/rtx/repository` and updated every week by default if short names -are requested. This is similar to what asdf does, but I'm considering just baking this straight into -the codebase so it doesn't have to be fetched/maintained separately. It's not like new plugins get -added that often. - ### Plugin Cache Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack.gz`. It stores diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh new file mode 100755 index 000000000..a4719b469 --- /dev/null +++ b/scripts/update-shorthand-repo.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euxo pipefail + +rm -rf asdf-plugins +git clone --depth 1 https://github.com/asdf-vm/asdf-plugins +rm -f src/shorthand_list.rs + +num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') +num_plugins=$((num_plugins + 1)) # +1 for node alias to nodejs + +cat > src/shorthand_list.rs <> src/shorthand_list.rs +done +cat >> src/shorthand_list.rs <, -) -> Result<(String, String)> { +fn get_name_and_url(name: String, git_url: Option) -> Result<(String, String)> { Ok(match git_url { Some(url) => (name, url), None => match name.contains(':') { true => (get_name_from_url(&name)?, name), false => { - let shr = ShorthandRepo::new(&config.settings); - let git_url = shr.lookup(&name)?; - (name, git_url) + let git_url = shorthand_to_repository(&name) + .ok_or_else(|| eyre!("could not find plugin {}", name))?; + (name, git_url.to_string()) } }, }) diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index ddbe7a712..2aab207a7 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -1,11 +1,12 @@ use std::collections::HashSet; use color_eyre::eyre::Result; +use itertools::Itertools; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::shorthand_repository::ShorthandRepo; +use crate::shorthand::SHORTHAND_MAP; /// List all available remote plugins /// @@ -30,15 +31,14 @@ impl Command for PluginsLsRemote { .map(|p| p.name.clone()) .collect::>(); - let shr = ShorthandRepo::new(&config.settings); - for plugin in shr.list_all()? { - let installed = if installed_plugins.contains(&plugin.name) { + for (plugin, repo) in SHORTHAND_MAP.iter().sorted().collect_vec() { + let installed = if installed_plugins.contains(*plugin) { "*" } else { " " }; - let url = if self.urls { plugin.url } else { "".into() }; - rtxprintln!(out, "{:28} {}{}", plugin.name, installed, url); + let url = if self.urls { *repo } else { "" }; + rtxprintln!(out, "{:28} {}{}", plugin, installed, url); } Ok(()) diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f20f26643..e97b681e3 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -364,18 +364,11 @@ always_keep_download = false # deleted after install by default # configure how frequently (in minutes) to fetch updated plugin repository changes # this is updated whenever a new runtime is installed +# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates -# configure how frequently (in minutes) to fetch updated shortname repository changes -# note this is not plugins themselves, it's the shortname mappings -# e.g.: nodejs -> https://github.com/asdf-vm/asdf-nodejs.git -plugin_repository_last_check_duration = 10080 # (one week) set to 0 to disable updates - verbose = false # see explanation under `RTX_VERBOSE` -# disables the short name repository (described above) -disable_plugin_short_name_repository = false - [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x # this can also be specified in a plugin (see below in "Aliases") @@ -690,16 +683,6 @@ things are hardcoded but I'm happy to add more settings to cover whatever config Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear to be updating, this is a good place to start. -### Shorthand Repository Cache - -asdf maintains a [shorthand repository](https://github.com/asdf-vm/asdf-plugins) which maps plugin -short names (e.g.: `nodejs`) to full repository names (e.g.: `https://github.com/asdf-vm/asdf-nodejs`). - -This is stored in `~/.local/share/rtx/repository` and updated every week by default if short names -are requested. This is similar to what asdf does, but I'm considering just baking this straight into -the codebase so it doesn't have to be fetched/maintained separately. It's not like new plugins get -added that often. - ### Plugin Cache Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack.gz`. It stores diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 38e48b4bf..1475c123d 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -28,9 +28,7 @@ impl Command for SettingsSet { "missing_runtime_behavior" => self.value.into(), "always_keep_download" => parse_bool(&self.value)?, "legacy_version_file" => parse_bool(&self.value)?, - "disable_plugin_short_name_repository" => parse_bool(&self.value)?, "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, - "plugin_repository_last_check_duration" => parse_i64(&self.value)?, "verbose" => parse_bool(&self.value)?, _ => return Err(eyre!("Unknown setting: {}", self.key)), }; @@ -77,24 +75,12 @@ pub mod test { assert_cli!("settings", "set", "missing_runtime_behavior", "warn"); assert_cli!("settings", "set", "legacy_version_file", "false"); assert_cli!("settings", "set", "always_keep_download", "true"); - assert_cli!( - "settings", - "set", - "disable_plugin_short_name_repository", - "true" - ); assert_cli!( "settings", "set", "plugin_autoupdate_last_check_duration", "1" ); - assert_cli!( - "settings", - "set", - "plugin_repository_last_check_duration", - "2" - ); let stdout = assert_cli!("settings"); assert_snapshot!(stdout); diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap index 1162ee017..050a4b72c 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap @@ -5,8 +5,6 @@ expression: stdout missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = true -disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 -plugin_repository_last_check_duration = 20 verbose = true diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap index 6d32a0db1..311355ee0 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap @@ -5,8 +5,6 @@ expression: stdout missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = false -disable_plugin_short_name_repository = true plugin_autoupdate_last_check_duration = 1 -plugin_repository_last_check_duration = 2 verbose = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index a0c82b543..09f38ff3f 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -54,9 +54,7 @@ mod test { missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = true - disable_plugin_short_name_repository = false plugin_autoupdate_last_check_duration = 20 - plugin_repository_last_check_duration = 20 verbose = true "###); diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index d8365c1f7..0c466fc13 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -93,13 +93,6 @@ impl RTXFile { self.settings.plugin_autoupdate_last_check_duration = Some(self.parse_duration_minutes(k, v)?) } - "plugin_repository_last_check_duration" => { - self.settings.plugin_repository_last_check_duration = - Some(self.parse_duration_minutes(k, v)?) - } - "disable_plugin_short_name_repository" => { - self.settings.disable_plugin_short_name_repository = Some(self.parse_bool(k, v)?) - } "verbose" => self.settings.verbose = Some(self.parse_bool(k, v)?), "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} diff --git a/src/config/settings.rs b/src/config/settings.rs index 09b564602..5a4933b7d 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -14,9 +14,7 @@ pub struct Settings { pub missing_runtime_behavior: MissingRuntimeBehavior, pub always_keep_download: bool, pub legacy_version_file: bool, - pub disable_plugin_short_name_repository: bool, pub plugin_autoupdate_last_check_duration: Duration, - pub plugin_repository_last_check_duration: Duration, pub aliases: IndexMap>, pub verbose: bool, } @@ -27,9 +25,7 @@ impl Default for Settings { missing_runtime_behavior: MissingRuntimeBehavior::Prompt, always_keep_download: false, legacy_version_file: true, - disable_plugin_short_name_repository: false, plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), - plugin_repository_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), aliases: IndexMap::new(), verbose: *RTX_VERBOSE || !is_tty(), } @@ -51,18 +47,10 @@ impl Settings { "legacy_version_file".to_string(), self.legacy_version_file.to_string(), ); - map.insert( - "disable_plugin_short_name_repository".to_string(), - self.disable_plugin_short_name_repository.to_string(), - ); map.insert( "plugin_autoupdate_last_check_duration".to_string(), (self.plugin_autoupdate_last_check_duration.as_secs() / 60).to_string(), ); - map.insert( - "plugin_repository_last_check_duration".to_string(), - (self.plugin_repository_last_check_duration.as_secs() / 60).to_string(), - ); map.insert("verbose".into(), self.verbose.to_string()); map } @@ -73,9 +61,7 @@ pub struct SettingsBuilder { pub missing_runtime_behavior: Option, pub always_keep_download: Option, pub legacy_version_file: Option, - pub disable_plugin_short_name_repository: Option, pub plugin_autoupdate_last_check_duration: Option, - pub plugin_repository_last_check_duration: Option, pub aliases: Option, pub verbose: Option, } @@ -97,17 +83,10 @@ impl SettingsBuilder { if other.legacy_version_file.is_some() { self.legacy_version_file = other.legacy_version_file; } - if other.disable_plugin_short_name_repository.is_some() { - self.disable_plugin_short_name_repository = other.disable_plugin_short_name_repository; - } if other.plugin_autoupdate_last_check_duration.is_some() { self.plugin_autoupdate_last_check_duration = other.plugin_autoupdate_last_check_duration; } - if other.plugin_repository_last_check_duration.is_some() { - self.plugin_repository_last_check_duration = - other.plugin_repository_last_check_duration; - } if other.verbose.is_some() { self.verbose = other.verbose; } @@ -139,12 +118,6 @@ impl SettingsBuilder { settings.legacy_version_file = self .legacy_version_file .unwrap_or(settings.legacy_version_file); - settings.disable_plugin_short_name_repository = self - .disable_plugin_short_name_repository - .unwrap_or(settings.disable_plugin_short_name_repository); - settings.plugin_repository_last_check_duration = self - .plugin_repository_last_check_duration - .unwrap_or(settings.plugin_repository_last_check_duration); settings.plugin_autoupdate_last_check_duration = self .plugin_autoupdate_last_check_duration .unwrap_or(settings.plugin_autoupdate_last_check_duration); diff --git a/src/main.rs b/src/main.rs index 91e80d43c..effb680fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,11 +30,12 @@ mod logger; mod plugins; pub mod runtimes; mod shell; -pub mod shorthand_repository; mod ui; mod direnv; mod hash; +mod shorthand; +mod shorthand_list; #[cfg(test)] mod test; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index d447a9468..f91c21a18 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -23,7 +23,7 @@ use crate::file::changed_within; use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; -use crate::shorthand_repository::ShorthandRepo; +use crate::shorthand::shorthand_to_repository; use crate::ui::color::{cyan, Color}; use crate::ui::prompt; use crate::ui::spinner::Spinner; @@ -93,7 +93,7 @@ impl Plugin { git.get_remote_url() } - pub fn install(&self, settings: &Settings, repository: &String) -> Result<()> { + pub fn install(&self, settings: &Settings, repository: &str) -> Result<()> { debug!("install {} {:?}", self.name, repository); let install_message = format!("Installing plugin {}...", cyan(Stderr, &self.name)); let mut sp = Spinner::start(install_message, settings.verbose); @@ -114,18 +114,17 @@ impl Plugin { return Ok(true); } - let shr = ShorthandRepo::new(settings); - match shr.lookup(&self.name) { - Ok(repo) => match settings.missing_runtime_behavior { + match shorthand_to_repository(&self.name) { + Some(repo) => match settings.missing_runtime_behavior { MissingRuntimeBehavior::AutoInstall => { - self.install(settings, &repo)?; + self.install(settings, repo)?; Ok(true) } MissingRuntimeBehavior::Prompt => { match prompt::prompt_for_install(&format!("plugin {}", COLOR.cyan(&self.name))) { true => { - self.install(settings, &repo)?; + self.install(settings, repo)?; Ok(true) } false => Ok(false), @@ -140,10 +139,10 @@ impl Plugin { Ok(false) } }, - Err(err) => match settings.missing_runtime_behavior { + None => match settings.missing_runtime_behavior { MissingRuntimeBehavior::Ignore => Ok(false), _ => { - warn!("{}", err); + warn!("Plugin not found: {}", COLOR.cyan(&self.name)); Ok(false) } }, diff --git a/src/shorthand.rs b/src/shorthand.rs new file mode 100644 index 000000000..c90b33f49 --- /dev/null +++ b/src/shorthand.rs @@ -0,0 +1,10 @@ +use crate::shorthand_list::SHORTHAND_LIST; +use once_cell::sync::Lazy; +use std::collections::HashMap; + +pub fn shorthand_to_repository(name: &str) -> Option<&'static str> { + SHORTHAND_MAP.get(name).copied() +} + +pub static SHORTHAND_MAP: Lazy> = + Lazy::new(|| HashMap::from(SHORTHAND_LIST)); diff --git a/src/shorthand_list.rs b/src/shorthand_list.rs new file mode 100644 index 000000000..4b1b71498 --- /dev/null +++ b/src/shorthand_list.rs @@ -0,0 +1,1190 @@ +// This file is generated by scripts/update-shorthand-repo.sh +// Do not edit this file manually + +pub const SHORTHAND_LIST: [(&str, &str); 592] = [ + // rtx custom aliases + ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), + // asdf original aliases from https://github.com/asdf-vm/asdf-plugins + ( + "1password-cli", + "https://github.com/NeoHsu/asdf-1password-cli.git", + ), + ("R", "https://github.com/asdf-community/asdf-r.git"), + ("act", "https://github.com/grimoh/asdf-act.git"), + ( + "action-validator", + "https://github.com/mpalmer/action-validator.git", + ), + ( + "actionlint", + "https://github.com/crazy-matt/asdf-actionlint.git", + ), + ("adr-tools", "https://gitlab.com/td7x/asdf/adr-tools.git"), + ("ag", "https://github.com/koketani/asdf-ag.git"), + ("age", "https://github.com/threkk/asdf-age"), + ("agebox", "https://github.com/slok/asdf-agebox.git"), + ( + "aks-engine", + "https://github.com/robsonpeixoto/asdf-aks-engine.git", + ), + ("alias", "https://github.com/andrewthauer/asdf-alias.git"), + ("allure", "https://github.com/comdotlinux/asdf-allure.git"), + ("alp", "https://github.com/asdf-community/asdf-alp.git"), + ("amass", "https://github.com/dhoeric/asdf-amass.git"), + ( + "amazon-ecr-credential-helper", + "https://github.com/dex4er/asdf-amazon-ecr-credential-helper.git", + ), + ("ansible-base", "https://github.com/amrox/asdf-pyapp.git"), + ("ant", "https://github.com/jackboespflug/asdf-ant.git"), + ( + "apollo-router", + "https://github.com/safx/asdf-apollo-router.git", + ), + ("arc", "https://github.com/ORCID/asdf-arc.git"), + ("argo", "https://github.com/sudermanjr/asdf-argo.git"), + ( + "argo-rollouts", + "https://github.com/abatilo/asdf-argo-rollouts.git", + ), + ("argocd", "https://github.com/beardix/asdf-argocd.git"), + ("aria2", "https://github.com/asdf-community/asdf-aria2.git"), + ( + "asciidoctorj", + "https://github.com/gliwka/asdf-asciidoctorj.git", + ), + ("assh", "https://github.com/zekker6/asdf-assh.git"), + ( + "aws-amplify-cli", + "https://github.com/LozanoMatheus/asdf-aws-amplify-cli.git", + ), + ("aws-copilot", "https://github.com/NeoHsu/asdf-copilot"), + ( + "aws-iam-authenticator", + "https://github.com/zekker6/asdf-aws-iam-authenticator", + ), + ( + "aws-nuke", + "https://github.com/bersalazar/asdf-aws-nuke.git", + ), + ("aws-sam-cli", "https://github.com/amrox/asdf-pyapp.git"), + ( + "aws-vault", + "https://github.com/karancode/asdf-aws-vault.git", + ), + ("awscli", "https://github.com/MetricMike/asdf-awscli.git"), + ("awsebcli", "https://github.com/amrox/asdf-pyapp.git"), + ("awsls", "https://github.com/chessmango/asdf-awsls.git"), + ("awsrm", "https://github.com/chessmango/asdf-awsrm.git"), + ( + "awsweeper", + "https://github.com/chessmango/asdf-awsweeper.git", + ), + ("azure-cli", "https://github.com/itspngu/asdf-azure-cli.git"), + ( + "azure-functions-core-tools", + "https://github.com/daveneeley/asdf-azure-functions-core-tools.git", + ), + ("babashka", "https://github.com/fredZen/asdf-babashka"), + ( + "balena-cli", + "https://github.com/boatkit-io/asdf-balena-cli", + ), + ( + "bashbot", + "https://github.com/mathew-fleisch/asdf-bashbot.git", + ), + ("bat", "https://gitlab.com/wt0f/asdf-bat.git"), + ("batect", "https://github.com/johnlayton/asdf-batect.git"), + ("bats", "https://github.com/timgluz/asdf-bats.git"), + ("bazel", "https://github.com/rajatvig/asdf-bazel.git"), + ("benthos", "https://github.com/benthosdev/benthos-asdf.git"), + ("binnacle", "https://github.com/Traackr/asdf-binnacle.git"), + ("bitwarden", "https://github.com/vixus0/asdf-bitwarden.git"), + ( + "bombardier", + "https://github.com/NeoHsu/asdf-bombardier.git", + ), + ("borg", "https://github.com/lwiechec/asdf-borg"), + ( + "bosh", + "https://github.com/laidbackware/asdf-github-release-downloader.git", + ), + ("bottom", "https://github.com/carbonteq/asdf-btm.git"), + ( + "boundary", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ("bpkg", "https://github.com/bpkg/asdf-bpkg.git"), + ("brig", "https://github.com/Ibotta/asdf-brig.git"), + ("btrace", "https://github.com/joschi/asdf-btrace.git"), + ("buf", "https://github.com/truepay/asdf-buf.git"), + ( + "buildpack", + "https://github.com/johnlayton/asdf-buildpack.git", + ), + ("bun", "https://github.com/cometkim/asdf-bun.git"), + ( + "bundler", + "https://github.com/jonathanmorley/asdf-bundler.git", + ), + ("caddy", "https://github.com/salasrod/asdf-caddy.git"), + ( + "camunda-modeler", + "https://github.com/barmac/asdf-camunda-modeler.git", + ), + ( + "cargo-make", + "https://github.com/kachick/asdf-cargo-make.git", + ), + ("carthage", "https://github.com/younke/asdf-carthage.git"), + ( + "ccache", + "https://github.com/asdf-community/asdf-ccache.git", + ), + ( + "certstrap", + "https://github.com/carnei-ro/asdf-certstrap.git", + ), + ("cf", "https://github.com/mattysweeps/asdf-cf.git"), + ("cfssl", "https://github.com/mathew-fleisch/asdf-cfssl.git"), + ("chamber", "https://github.com/mintel/asdf-chamber"), + ("cheat", "https://github.com/jmoratilla/asdf-cheat-plugin"), + ("checkov", "https://github.com/bosmak/asdf-checkov.git"), + ("chezmoi", "https://github.com/joke/asdf-chezmoi.git"), + ( + "chezscheme", + "https://github.com/asdf-community/asdf-chezscheme.git", + ), + ("chicken", "https://github.com/evhan/asdf-chicken.git"), + ("choose", "https://github.com/carbonteq/asdf-choose.git"), + ( + "chromedriver", + "https://github.com/schinckel/asdf-chromedriver.git", + ), + ( + "cidr-merger", + "https://github.com/ORCID/asdf-cidr-merger.git", + ), + ( + "cilium-cli", + "https://github.com/carnei-ro/asdf-cilium-cli.git", + ), + ( + "cilium-hubble", + "https://github.com/NitriKx/asdf-cilium-hubble.git", + ), + ( + "clojure", + "https://github.com/asdf-community/asdf-clojure.git", + ), + ("cloudflared", "https://github.com/threkk/asdf-cloudflared"), + ( + "cloudsql-proxy", + "https://github.com/itspngu/asdf-cloudsql-proxy.git", + ), + ( + "clusterawsadm", + "https://github.com/kahun/asdf-clusterawsadm.git", + ), + ( + "clusterctl", + "https://github.com/pfnet-research/asdf-clusterctl.git", + ), + ( + "cmake", + "https://github.com/srivathsanmurali/asdf-cmake.git", + ), + ("cmctl", "https://github.com/asdf-community/asdf-cmctl.git"), + ( + "cockroach", + "https://github.com/salasrod/asdf-cockroach.git", + ), + ( + "codefresh", + "https://github.com/gurukulkarni/asdf-codefresh.git", + ), + ( + "codeql", + "https://github.com/bored-engineer/asdf-codeql.git", + ), + ("conan", "https://github.com/amrox/asdf-pyapp.git"), + ( + "concourse", + "https://github.com/mattysweeps/asdf-concourse.git", + ), + ("conduit", "https://github.com/gmcabrita/asdf-conduit.git"), + ("conform", "https://github.com/skyzyx/asdf-conform.git"), + ("conftest", "https://github.com/looztra/asdf-conftest.git"), + ( + "consul", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ( + "container-diff", + "https://github.com/cgroschupp/asdf-container-diff.git", + ), + ( + "container-structure-test", + "https://github.com/jonathanmorley/asdf-container-structure-test.git", + ), + ( + "cookiecutter", + "https://github.com/shawon-crosen/asdf-cookiecutter.git", + ), + ("copper", "https://github.com/vladlosev/asdf-copper.git"), + ("coq", "https://github.com/gingerhot/asdf-coq.git"), + ("cosign", "https://gitlab.com/wt0f/asdf-cosign.git"), + ( + "coursier", + "https://github.com/jiahuili430/asdf-coursier.git", + ), + ("crane", "https://github.com/dmpe/asdf-crane"), + ("crc", "https://github.com/sqtran/asdf-crc.git"), + ( + "credhub", + "https://github.com/laidbackware/asdf-github-release-downloader.git", + ), + ( + "crossplane-cli", + "https://github.com/joke/asdf-crossplane-cli.git", + ), + ( + "crystal", + "https://github.com/asdf-community/asdf-crystal.git", + ), + ("ctlptl", "https://github.com/ezcater/asdf-ctlptl.git"), + ("ctop", "https://github.com/NeoHsu/asdf-ctop.git"), + ("cue", "https://github.com/asdf-community/asdf-cue.git"), + ( + "dagger", + "https://github.com/virtualstaticvoid/asdf-dagger.git", + ), + ("dart", "https://github.com/PatOConnor43/asdf-dart.git"), + ("dasel", "https://github.com/asdf-community/asdf-dasel.git"), + ("datree", "https://github.com/lukeab/asdf-datree.git"), + ("dbmate", "https://github.com/juusujanar/asdf-dbmate.git"), + ("deck", "https://github.com/nutellinoit/asdf-deck.git"), + ("delta", "https://github.com/andweeb/asdf-delta.git"), + ("deno", "https://github.com/asdf-community/asdf-deno.git"), + ("dep", "https://github.com/paxosglobal/asdf-dep.git"), + ("depot", "https://github.com/depot/asdf-depot.git"), + ("desk", "https://github.com/endorama/asdf-desk.git"), + ("devspace", "https://github.com/NeoHsu/asdf-devspace.git"), + ("dhall", "https://github.com/aaaaninja/asdf-dhall.git"), + ( + "difftastic", + "https://github.com/volf52/asdf-difftastic.git", + ), + ("digdag", "https://github.com/jtakakura/asdf-digdag.git"), + ( + "direnv", + "https://github.com/asdf-community/asdf-direnv.git", + ), + ("dive", "https://github.com/looztra/asdf-dive.git"), + ( + "djinni", + "https://github.com/cross-language-cpp/asdf-djinni.git", + ), + ("dmd", "https://github.com/sylph01/asdf-dmd.git"), + ( + "docker-compose-v1", + "https://github.com/kompiro/asdf-docker-compose-v1", + ), + ( + "docker-slim", + "https://github.com/everpeace/asdf-docker-slim.git", + ), + ( + "dockle", + "https://github.com/mathew-fleisch/asdf-dockle.git", + ), + ("doctl", "https://github.com/maristgeek/asdf-doctl.git"), + ( + "doctoolchain", + "https://github.com/joschi/asdf-doctoolchain", + ), + ("docuum", "https://github.com/bradym/asdf-docuum.git"), + ("dome", "https://github.com/jtakakura/asdf-dome.git"), + ( + "dotenv-linter", + "https://github.com/wesleimp/asdf-dotenv-linter.git", + ), + ("dotnet", "https://github.com/hensou/asdf-dotnet"), + ( + "dotnet-core", + "https://github.com/emersonsoares/asdf-dotnet-core.git", + ), + ("dotty", "https://github.com/vic/asdf-dotty.git"), + ("dprint", "https://github.com/asdf-community/asdf-dprint"), + ("draft", "https://github.com/kristoflemmens/asdf-draft.git"), + ( + "driftctl", + "https://github.com/nlamirault/asdf-driftctl.git", + ), + ( + "drone", + "https://github.com/virtualstaticvoid/asdf-drone.git", + ), + ("dtm", "https://github.com/zhenyuanlau/asdf-dtm.git"), + ("duf", "https://github.com/NeoHsu/asdf-duf.git"), + ("dust", "https://github.com/looztra/asdf-dust.git"), + ("dyff", "https://gitlab.com/wt0f/asdf-dyff.git"), + ( + "editorconfig-checker", + "https://github.com/gabitchov/asdf-editorconfig-checker.git", + ), + ("ejson", "https://github.com/cipherstash/asdf-ejson.git"), + ("eksctl", "https://github.com/elementalvoid/asdf-eksctl.git"), + ( + "elasticsearch", + "https://github.com/asdf-community/asdf-elasticsearch.git", + ), + ("elixir", "https://github.com/asdf-vm/asdf-elixir.git"), + ("elm", "https://github.com/asdf-community/asdf-elm.git"), + ("embulk", "https://github.com/yuokada/asdf-embulk.git"), + ("emsdk", "https://github.com/RobLoach/asdf-emsdk.git"), + ("envcli", "https://github.com/zekker6/asdf-envcli.git"), + ("erlang", "https://github.com/asdf-vm/asdf-erlang.git"), + ("esy", "https://github.com/asdf-community/asdf-esy.git"), + ("etcd", "https://github.com/particledecay/asdf-etcd.git"), + ("exa", "https://github.com/nyrst/asdf-exa.git"), + ("fd", "https://gitlab.com/wt0f/asdf-fd.git"), + ("ffmpeg", "https://github.com/acj/asdf-ffmpeg"), + ( + "figma-export", + "https://github.com/younke/asdf-figma-export.git", + ), + ("fillin", "https://github.com/ouest/asdf-fillin"), + ("firebase", "https://github.com/jthegedus/asdf-firebase.git"), + ( + "fission", + "https://github.com/virtualstaticvoid/asdf-fission.git", + ), + ("flarectl", "https://github.com/ORCID/asdf-flarectl.git"), + ("flutter", "https://github.com/oae/asdf-flutter.git"), + ("flux2", "https://github.com/tablexi/asdf-flux2.git"), + ( + "fluxctl", + "https://github.com/stefansedich/asdf-fluxctl.git", + ), + ( + "fly", + "https://github.com/laidbackware/asdf-github-release-downloader.git", + ), + ("flyctl", "https://github.com/chessmango/asdf-flyctl.git"), + ("func-e", "https://github.com/carnei-ro/asdf-func-e.git"), + ("furyctl", "https://github.com/sighupio/asdf-furyctl.git"), + ("fx", "https://gitlab.com/wt0f/asdf-fx.git"), + ("fzf", "https://github.com/kompiro/asdf-fzf.git"), + ("gam", "https://github.com/offbyone/asdf-gam.git"), + ("gator", "https://github.com/MxNxPx/asdf-gator.git"), + ("gauche", "https://github.com/sakuro/asdf-gauche.git"), + ( + "gcc-arm-none-eabi", + "https://github.com/dlech/asdf-gcc-arm-none-eabi.git", + ), + ("gcloud", "https://github.com/jthegedus/asdf-gcloud.git"), + ( + "getenvoy", + "https://github.com/asdf-community/asdf-getenvoy.git", + ), + ("ghidra", "https://github.com/Honeypot95/asdf-ghidra.git"), + ("ghorg", "https://github.com/gbloquel/asdf-ghorg.git"), + ("ghq", "https://github.com/kajisha/asdf-ghq.git"), + ("ginkgo", "https://github.com/jimmidyson/asdf-ginkgo.git"), + ("git", "https://gitlab.com/jcaigitlab/asdf-git.git"), + ( + "git-chglog", + "https://github.com/GoodwayGroup/asdf-git-chglog.git", + ), + ("gitconfig", "https://github.com/0ghny/asdf-gitconfig.git"), + ( + "github-cli", + "https://github.com/bartlomiejdanek/asdf-github-cli.git", + ), + ( + "github-markdown-toc", + "https://github.com/skyzyx/asdf-github-markdown-toc.git", + ), + ("gitleaks", "https://github.com/jmcvetta/asdf-gitleaks.git"), + ( + "gitsign", + "https://github.com/spencergilbert/asdf-gitsign.git", + ), + ("gitui", "https://github.com/looztra/asdf-gitui.git"), + ("glab", "https://github.com/particledecay/asdf-glab.git"), + ("gleam", "https://github.com/vic/asdf-gleam.git"), + ("glen", "https://github.com/bradym/asdf-glen"), + ("glooctl", "https://github.com/halilkaya/asdf-glooctl.git"), + ("glow", "https://github.com/chessmango/asdf-glow.git"), + ( + "go-containerregistry", + "https://github.com/dex4er/asdf-go-containerregistry.git", + ), + ("go-getter", "https://github.com/ryodocx/asdf-go-getter.git"), + ("go-jira", "https://github.com/dguihal/asdf-go-jira.git"), + ( + "go-jsonnet", + "https://gitlab.com/craigfurman/asdf-go-jsonnet.git", + ), + ( + "go-junit-report", + "https://github.com/jwillker/asdf-go-junit-report.git", + ), + ("go-sdk", "https://github.com/yacchi/asdf-go-sdk.git"), + ( + "go-swagger", + "https://github.com/jfreeland/asdf-go-swagger.git", + ), + ("gohugo", "https://github.com/nklmilojevic/asdf-hugo.git"), + ("gojq", "https://github.com/jimmidyson/asdf-gojq.git"), + ("golang", "https://github.com/kennyp/asdf-golang.git"), + ( + "golangci-lint", + "https://github.com/hypnoglow/asdf-golangci-lint.git", + ), + ("gomigrate", "https://github.com/joschi/asdf-gomigrate.git"), + ( + "gomplate", + "https://github.com/sneakybeaky/asdf-gomplate.git", + ), + ("gopass", "https://github.com/trallnag/asdf-gopass.git"), + ( + "goreleaser", + "https://github.com/kforsthoevel/asdf-goreleaser.git", + ), + ("goss", "https://github.com/raimon49/asdf-goss.git"), + ( + "graalvm", + "https://github.com/asdf-community/asdf-graalvm.git", + ), + ("gradle", "https://github.com/rfrancis/asdf-gradle.git"), + ( + "gradle-profiler", + "https://github.com/joschi/asdf-gradle-profiler.git", + ), + ("grails", "https://github.com/weibemoura/asdf-grails.git"), + ("grain", "https://github.com/cometkim/asdf-grain.git"), + ("granted", "https://github.com/dex4er/asdf-granted.git"), + ("grex", "https://github.com/ouest/asdf-grex"), + ("groovy", "https://github.com/weibemoura/asdf-groovy.git"), + ( + "grpc-health-probe", + "https://github.com/zufardhiyaulhaq/asdf-grpc-health-probe.git", + ), + ( + "grpcurl", + "https://github.com/asdf-community/asdf-grpcurl.git", + ), + ("grype", "https://github.com/poikilotherm/asdf-grype.git"), + ("guile", "https://github.com/indiebrain/asdf-guile.git"), + ("gum", "https://github.com/lwiechec/asdf-gum"), + ( + "gwvault", + "https://github.com/GoodwayGroup/asdf-gwvault.git", + ), + ( + "hadolint", + "https://github.com/devlincashman/asdf-hadolint.git", + ), + ("hamler", "https://github.com/scudelletti/asdf-hamler.git"), + ("has", "https://github.com/sylvainmetayer/asdf-has"), + ( + "haskell", + "https://github.com/asdf-community/asdf-haskell.git", + ), + ( + "hasura-cli", + "https://github.com/gurukulkarni/asdf-hasura.git", + ), + ("haxe", "https://github.com/asdf-community/asdf-haxe.git"), + ("hcl2json", "https://github.com/dex4er/asdf-hcl2json.git"), + ("hcloud", "https://github.com/chessmango/asdf-hcloud.git"), + ("helm", "https://github.com/Antiarchitect/asdf-helm.git"), + ( + "helm-cr", + "https://github.com/Antiarchitect/asdf-helm-cr.git", + ), + ("helm-ct", "https://github.com/tablexi/asdf-helm-ct.git"), + ("helm-diff", "https://github.com/dex4er/asdf-helm-diff.git"), + ( + "helm-docs", + "https://github.com/sudermanjr/asdf-helm-docs.git", + ), + ("helmfile", "https://github.com/feniix/asdf-helmfile.git"), + ("helmsman", "https://github.com/luisdavim/asdf-helmsman"), + ( + "heroku-cli", + "https://github.com/treilly94/asdf-heroku-cli.git", + ), + ("hey", "https://github.com/raimon49/asdf-hey.git"), + ("httpie-go", "https://github.com/abatilo/asdf-httpie-go.git"), + ("hub", "https://github.com/vixus0/asdf-hub.git"), + ("hugo", "https://github.com/NeoHsu/asdf-hugo.git"), + ("hurl", "https://github.com/raimon49/asdf-hurl.git"), + ("hwatch", "https://github.com/chessmango/asdf-hwatch.git"), + ("hygen", "https://github.com/brentjanderson/asdf-hygen.git"), + ("hyperfine", "https://github.com/volf52/asdf-hyperfine.git"), + ( + "iam-policy-json-to-terraform", + "https://github.com/carlduevel/asdf-iam-policy-json-to-terraform.git", + ), + ("iamlive", "https://github.com/chessmango/asdf-iamlive.git"), + ("idris", "https://github.com/asdf-community/asdf-idris.git"), + ( + "idris2", + "https://github.com/asdf-community/asdf-idris2.git", + ), + ( + "imagemagick", + "https://github.com/mangalakader/asdf-imagemagick.git", + ), + ("imgpkg", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ("infracost", "https://github.com/dex4er/asdf-infracost.git"), + ("inlets", "https://github.com/nlamirault/asdf-inlets.git"), + ("io", "https://github.com/mracos/asdf-io.git"), + ( + "istioctl", + "https://github.com/virtualstaticvoid/asdf-istioctl.git", + ), + ("janet", "https://github.com/Jakski/asdf-janet.git"), + ("java", "https://github.com/halcyon/asdf-java.git"), + ("jb", "https://github.com/beardix/asdf-jb.git"), + ("jbang", "https://github.com/joschi/asdf-jbang.git"), + ("jib", "https://github.com/joschi/asdf-jib.git"), + ("jiq", "https://github.com/chessmango/asdf-jiq.git"), + ("jless", "https://github.com/jc00ke/asdf-jless.git"), + ("jmespath", "https://github.com/skyzyx/asdf-jmespath.git"), + ("jmeter", "https://github.com/comdotlinux/asdf-jmeter"), + ("jq", "https://github.com/azmcode/asdf-jq.git"), + ("jqp", "https://gitlab.com/wt0f/asdf-jqp.git"), + ("jreleaser", "https://github.com/joschi/asdf-jreleaser.git"), + ("jsonnet", "https://github.com/Banno/asdf-jsonnet.git"), + ("julia", "https://github.com/rkyleg/asdf-julia.git"), + ("just", "https://github.com/olofvndrhr/asdf-just.git"), + ("jx", "https://github.com/vbehar/asdf-jx.git"), + ("k2tf", "https://github.com/carlduevel/asdf-k2tf.git"), + ("k3d", "https://github.com/spencergilbert/asdf-k3d.git"), + ("k3sup", "https://github.com/cgroschupp/asdf-k3sup.git"), + ("k6", "https://github.com/grimoh/asdf-k6.git"), + ("k9s", "https://github.com/looztra/asdf-k9s.git"), + ("kafka", "https://github.com/ueisele/asdf-kafka.git"), + ("kafkactl", "https://github.com/anweber/asdf-kafkactl.git"), + ("kapp", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ("kbld", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ("kcat", "https://github.com/douglasdgoulart/asdf-kcat.git"), + ("kcctl", "https://github.com/joschi/asdf-kcctl.git"), + ("kconf", "https://github.com/particledecay/asdf-kconf.git"), + ("ki", "https://github.com/comdotlinux/asdf-ki"), + ("kind", "https://github.com/johnlayton/asdf-kind.git"), + ("kn", "https://github.com/joke/asdf-kn.git"), + ("ko", "https://github.com/zasdaym/asdf-ko.git"), + ( + "kompose", + "https://github.com/technikhil314/asdf-kompose.git", + ), + ("kops", "https://github.com/Antiarchitect/asdf-kops.git"), + ( + "kotlin", + "https://github.com/asdf-community/asdf-kotlin.git", + ), + ("kpt", "https://github.com/nlamirault/asdf-kpt.git"), + ("krew", "https://github.com/jimmidyson/asdf-krew.git"), + ("kscript", "https://github.com/edgelevel/asdf-kscript.git"), + ("ksonnet", "https://github.com/Banno/asdf-ksonnet.git"), + ("ktlint", "https://github.com/esensar/asdf-ktlint.git"), + ( + "kube-capacity", + "https://github.com/looztra/asdf-kube-capacity.git", + ), + ( + "kube-code-generator", + "https://github.com/jimmidyson/asdf-kube-code-generator.git", + ), + ( + "kube-controller-tools", + "https://github.com/jimmidyson/asdf-kube-controller-tools.git", + ), + ( + "kube-credential-cache", + "https://github.com/ryodocx/kube-credential-cache.git", + ), + ( + "kube-linter", + "https://github.com/devlincashman/asdf-kube-linter.git", + ), + ( + "kube-score", + "https://github.com/bageljp/asdf-kube-score.git", + ), + ( + "kubebuilder", + "https://github.com/virtualstaticvoid/asdf-kubebuilder.git", + ), + ("kubecm", "https://github.com/samhvw8/asdf-kubecm"), + ( + "kubeconform", + "https://github.com/lirlia/asdf-kubeconform.git", + ), + ( + "kubectl", + "https://github.com/asdf-community/asdf-kubectl.git", + ), + ( + "kubectl-bindrole", + "https://github.com/looztra/asdf-kubectl-bindrole.git", + ), + ( + "kubectl-buildkit", + "https://github.com/ezcater/asdf-kubectl-buildkit.git", + ), + ( + "kubectl-kots", + "https://github.com/ganta/asdf-kubectl-kots.git", + ), + ("kubectx", "https://gitlab.com/wt0f/asdf-kubectx.git"), + ( + "kubefedctl", + "https://github.com/kvokka/asdf-kubefedctl.git", + ), + ( + "kubelogin", + "https://github.com/sechmann/asdf-kubelogin.git", + ), + ( + "kubemqctl", + "https://github.com/johnlayton/asdf-kubemqctl.git", + ), + ( + "kubent", + "https://github.com/virtualstaticvoid/asdf-kubent.git", + ), + ( + "kubergrunt", + "https://github.com/NeoHsu/asdf-kubergrunt.git", + ), + ( + "kubeseal", + "https://github.com/stefansedich/asdf-kubeseal.git", + ), + ("kubesec", "https://github.com/vitalis/asdf-kubesec.git"), + ("kubespy", "https://github.com/jfreeland/asdf-kubespy.git"), + ( + "kubeval", + "https://github.com/stefansedich/asdf-kubeval.git", + ), + ("kubie", "https://github.com/johnhamelink/asdf-kubie.git"), + ("kustomize", "https://github.com/Banno/asdf-kustomize.git"), + ("kuttl", "https://github.com/jimmidyson/asdf-kuttl.git"), + ("kwt", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ("lab", "https://github.com/particledecay/asdf-lab.git"), + ( + "lazygit", + "https://github.com/nklmilojevic/asdf-lazygit.git", + ), + ("lean", "https://github.com/asdf-community/asdf-lean.git"), + ("leiningen", "https://github.com/miorimmax/asdf-lein.git"), + ( + "levant", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ("lfe", "https://github.com/asdf-community/asdf-lfe.git"), + ("link", "https://github.com/asdf-community/asdf-link.git"), + ( + "linkerd", + "https://github.com/kforsthoevel/asdf-linkerd.git", + ), + ("liqoctl", "https://github.com/pdemagny/asdf-liqoctl"), + ("litestream", "https://github.com/threkk/asdf-litestream"), + ( + "logtalk", + "https://github.com/LogtalkDotOrg/asdf-logtalk.git", + ), + ( + "loki-logcli", + "https://github.com/comdotlinux/asdf-loki-logcli.git", + ), + ("lua", "https://github.com/Stratus3D/asdf-lua.git"), + ( + "luaJIT", + "https://github.com/smashedtoatoms/asdf-luaJIT.git", + ), + ("lucy", "https://github.com/cometkim/asdf-lucy.git"), + ("mage", "https://github.com/mathew-fleisch/asdf-mage.git"), + ("make", "https://github.com/yacchi/asdf-make.git"), + ("mani", "https://github.com/anweber/asdf-mani.git"), + ("mark", "https://github.com/jfreeland/asdf-mark.git"), + ("mask", "https://github.com/aaaaninja/asdf-mask.git"), + ("maven", "https://github.com/halcyon/asdf-maven.git"), + ("mc", "https://github.com/penpyt/asdf-mc.git"), + ("mdbook", "https://github.com/cipherstash/asdf-mdbook.git"), + ( + "mdbook-linkcheck", + "https://github.com/cipherstash/asdf-mdbook-linkcheck.git", + ), + ("melt", "https://github.com/chessmango/asdf-melt.git"), + ("memcached", "https://github.com/furkanural/asdf-memcached"), + ("meson", "https://github.com/asdf-community/asdf-meson.git"), + ( + "micronaut", + "https://github.com/weibemoura/asdf-micronaut.git", + ), + ("mill", "https://github.com/asdf-community/asdf-mill.git"), + ("minikube", "https://github.com/alvarobp/asdf-minikube.git"), + ("minio", "https://github.com/aeons/asdf-minio.git"), + ("minishift", "https://github.com/sqtran/asdf-minishift.git"), + ("mint", "https://github.com/mint-lang/asdf-mint"), + ("mitmproxy", "https://github.com/NeoHsu/asdf-mitmproxy.git"), + ("mkcert", "https://github.com/salasrod/asdf-mkcert.git"), + ("mlton", "https://github.com/asdf-community/asdf-mlton.git"), + ("mockery", "https://github.com/cabify/asdf-mockery.git"), + ( + "mongo-tools", + "https://github.com/itspngu/asdf-mongo-tools.git", + ), + ("mongodb", "https://github.com/sylph01/asdf-mongodb.git"), + ("mongosh", "https://github.com/itspngu/asdf-mongosh.git"), + ("mutanus", "https://github.com/soriur/asdf-mutanus.git"), + ("mvnd", "https://github.com/joschi/asdf-mvnd.git"), + ("mysql", "https://github.com/iroddis/asdf-mysql.git"), + ("nancy", "https://github.com/iilyak/asdf-nancy.git"), + ("nano", "https://github.com/mfakane/asdf-nano.git"), + ("neko", "https://github.com/asdf-community/asdf-neko.git"), + ("neovim", "https://github.com/richin13/asdf-neovim.git"), + ("nerdctl", "https://github.com/dmpe/asdf-nerdctl"), + ( + "newrelic-cli", + "https://github.com/NeoHsu/asdf-newrelic-cli.git", + ), + ("nfpm", "https://github.com/ORCID/asdf-nfpm"), + ("nim", "https://github.com/asdf-community/asdf-nim.git"), + ("ninja", "https://github.com/asdf-community/asdf-ninja.git"), + ("nodejs", "https://github.com/asdf-vm/asdf-nodejs.git"), + ( + "nomad", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ("nova", "https://github.com/elementalvoid/asdf-nova.git"), + ("nsc", "https://github.com/dex4er/asdf-nsc.git"), + ("oc", "https://github.com/sqtran/asdf-oc.git"), + ("ocaml", "https://github.com/asdf-community/asdf-ocaml.git"), + ("odin", "https://github.com/jtakakura/asdf-odin"), + ("odo", "https://github.com/rm3l/asdf-odo.git"), + ("okteto", "https://github.com/BradenM/asdf-okteto"), + ( + "om", + "https://github.com/laidbackware/asdf-github-release-downloader.git", + ), + ("opa", "https://github.com/tochukwuvictor/asdf-opa.git"), + ("opam", "https://github.com/asdf-community/asdf-opam.git"), + ( + "openfaas-faas-cli", + "https://github.com/zekker6/asdf-faas-cli.git", + ), + ( + "openresty", + "https://github.com/smashedtoatoms/asdf-openresty.git", + ), + ( + "opensearch", + "https://github.com/randikabanura/asdf-opensearch.git", + ), + ( + "openshift-install", + "https://github.com/hhemied/asdf-openshift-install.git", + ), + ( + "operator-sdk", + "https://github.com/Medium/asdf-operator-sdk.git", + ), + ( + "opsgenie-lamp", + "https://github.com/ORCID/asdf-opsgenie-lamp", + ), + ("osm", "https://github.com/nlamirault/asdf-osm.git"), + ( + "osqueryi", + "https://github.com/davidecavestro/asdf-osqueryi.git", + ), + ("pachctl", "https://github.com/abatilo/asdf-pachctl.git"), + ( + "packer", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ("patat", "https://github.com/airtonix/asdf-patat.git"), + ("pdm", "https://github.com/1oglop1/asdf-pdm"), + ("peco", "https://github.com/asdf-community/asdf-peco.git"), + ("perl", "https://github.com/ouest/asdf-perl.git"), + ("php", "https://github.com/asdf-community/asdf-php.git"), + ("pint", "https://github.com/sam-burrell/asdf-pint.git"), + ( + "pivnet", + "https://github.com/laidbackware/asdf-github-release-downloader.git", + ), + ( + "please", + "https://github.com/asdf-community/asdf-please.git", + ), + ("pluto", "https://github.com/FairwindsOps/asdf-pluto.git"), + ("pnpm", "https://github.com/jonathanmorley/asdf-pnpm.git"), + ( + "poetry", + "https://github.com/asdf-community/asdf-poetry.git", + ), + ( + "polaris", + "https://github.com/particledecay/asdf-polaris.git", + ), + ("popeye", "https://github.com/nlamirault/asdf-popeye.git"), + ( + "postgres", + "https://github.com/smashedtoatoms/asdf-postgres.git", + ), + ( + "powershell-core", + "https://github.com/daveneeley/asdf-powershell-core.git", + ), + ( + "pre-commit", + "https://github.com/jonathanmorley/asdf-pre-commit.git", + ), + ("protoc", "https://github.com/paxosglobal/asdf-protoc.git"), + ( + "protoc-gen-go", + "https://github.com/pbr0ck3r/asdf-protoc-gen-go.git", + ), + ( + "protoc-gen-go-grpc", + "https://github.com/pbr0ck3r/asdf-protoc-gen-go-grpc.git", + ), + ( + "protoc-gen-grpc-web", + "https://github.com/pbr0ck3r/asdf-protoc-gen-grpc-web.git", + ), + ( + "protoc-gen-js", + "https://github.com/pbr0ck3r/asdf-protoc-gen-js.git", + ), + ( + "protolint", + "https://github.com/spencergilbert/asdf-protolint.git", + ), + ("pulumi", "https://github.com/canha/asdf-pulumi.git"), + ("purerl", "https://github.com/GoNZooo/asdf-purerl.git"), + ( + "purescript", + "https://github.com/nsaunders/asdf-purescript.git", + ), + ("purty", "https://github.com/nsaunders/asdf-purty.git"), + ("python", "https://github.com/danhper/asdf-python.git"), + ( + "quarkus", + "https://github.com/asdf-community/asdf-quarkus.git", + ), + ("rabbitmq", "https://github.com/w-sanches/asdf-rabbitmq.git"), + ( + "racket", + "https://github.com/asdf-community/asdf-racket.git", + ), + ("raku", "https://github.com/m-dango/asdf-raku.git"), + ("rancher", "https://github.com/abinet/asdf-rancher.git"), + ( + "rbac-lookup", + "https://github.com/looztra/asdf-rbac-lookup.git", + ), + ("rclone", "https://github.com/johnlayton/asdf-rclone.git"), + ("rebar", "https://github.com/Stratus3D/asdf-rebar.git"), + ( + "reckoner", + "https://github.com/FairwindsOps/asdf-reckoner.git", + ), + ("redis", "https://github.com/smashedtoatoms/asdf-redis.git"), + ("redis-cli", "https://github.com/NeoHsu/asdf-redis-cli.git"), + ("redo", "https://github.com/chessmango/asdf-redo.git"), + ( + "redskyctl", + "https://github.com/sudermanjr/asdf-redskyctl.git", + ), + ("reg", "https://github.com/looztra/asdf-reg.git"), + ("regctl", "https://github.com/ORCID/asdf-regctl.git"), + ("riak", "https://github.com/smashedtoatoms/asdf-riak.git"), + ("richgo", "https://github.com/paxosglobal/asdf-richgo.git"), + ("riff", "https://github.com/abinet/asdf-riff.git"), + ("ripgrep", "https://gitlab.com/wt0f/asdf-ripgrep.git"), + ("rke", "https://github.com/particledecay/asdf-rke.git"), + ( + "rlwrap", + "https://github.com/asdf-community/asdf-rlwrap.git", + ), + ("rstash", "https://github.com/carlduevel/asdf-rstash.git"), + ("ruby", "https://github.com/asdf-vm/asdf-ruby.git"), + ("rust", "https://github.com/code-lever/asdf-rust.git"), + ( + "rust-analyzer", + "https://github.com/Xyven1/asdf-rust-analyzer", + ), + ( + "saml2aws", + "https://github.com/elementalvoid/asdf-saml2aws.git", + ), + ("sbcl", "https://github.com/smashedtoatoms/asdf-sbcl.git"), + ("sbt", "https://github.com/bram2000/asdf-sbt.git"), + ("scala", "https://github.com/asdf-community/asdf-scala.git"), + ( + "scaleway-cli", + "https://github.com/albarralnunez/asdf-plugin-scaleway-cli", + ), + ("sccache", "https://github.com/emersonmx/asdf-sccache.git"), + ("scenery", "https://github.com/skyzyx/asdf-scenery.git"), + ( + "schemacrawler", + "https://github.com/davidecavestro/asdf-schemacrawler.git", + ), + ( + "semgrep", + "https://github.com/brentjanderson/asdf-semgrep.git", + ), + ("semtag", "https://github.com/junminahn/asdf-semtag"), + ( + "semver", + "https://github.com/mathew-fleisch/asdf-semver.git", + ), + ( + "sentinel", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ( + "serf", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ( + "serverless", + "https://github.com/pdemagny/asdf-serverless.git", + ), + ("shellcheck", "https://github.com/luizm/asdf-shellcheck.git"), + ( + "shellspec", + "https://github.com/poikilotherm/asdf-shellspec.git", + ), + ("shfmt", "https://github.com/luizm/asdf-shfmt.git"), + ("sinker", "https://github.com/elementalvoid/asdf-sinker.git"), + ( + "skaffold", + "https://github.com/nklmilojevic/asdf-skaffold.git", + ), + ("skate", "https://github.com/chessmango/asdf-skate.git"), + ("sloth", "https://github.com/slok/asdf-sloth.git"), + ("smlnj", "https://github.com/samontea/asdf-smlnj.git"), + ("snyk", "https://github.com/nirfuchs/asdf-snyk.git"), + ( + "soft-serve", + "https://github.com/chessmango/asdf-soft-serve.git", + ), + ( + "solidity", + "https://github.com/diegodorado/asdf-solidity.git", + ), + ("sops", "https://github.com/feniix/asdf-sops.git"), + ( + "sopstool", + "https://github.com/elementalvoid/asdf-sopstool.git", + ), + ("sourcery", "https://github.com/younke/asdf-sourcery.git"), + ("spago", "https://github.com/nsaunders/asdf-spago.git"), + ("spark", "https://github.com/joshuaballoch/asdf-spark.git"), + ("spectral", "https://github.com/vbyrd/asdf-spectral.git"), + ("spin", "https://github.com/pavloos/asdf-spin.git"), + ( + "spring-boot", + "https://github.com/joschi/asdf-spring-boot.git", + ), + ("spruce", "https://github.com/woneill/asdf-spruce.git"), + ("sqldef", "https://github.com/cometkim/asdf-sqldef.git"), + ("sqlite", "https://github.com/cLupus/asdf-sqlite.git"), + ("stack", "https://github.com/sestrella/asdf-ghcup.git"), + ( + "starboard", + "https://github.com/zufardhiyaulhaq/asdf-starboard.git", + ), + ("starport", "https://github.com/nikever/asdf-starport.git"), + ("starship", "https://github.com/grimoh/asdf-starship.git"), + ( + "steampipe", + "https://github.com/carnei-ro/asdf-steampipe.git", + ), + ("step", "https://github.com/log2/asdf-step.git"), + ("stern", "https://github.com/looztra/asdf-stern.git"), + ("stripe-cli", "https://github.com/offbyone/asdf-stripe.git"), + ("stylua", "https://github.com/jc00ke/asdf-stylua.git"), + ("svu", "https://github.com/asdf-community/asdf-svu"), + ("swag", "https://github.com/behoof4mind/asdf-swag.git"), + ("swift", "https://github.com/fcrespo82/asdf-swift.git"), + ( + "swiftformat", + "https://github.com/younke/asdf-swiftformat.git", + ), + ("swiftgen", "https://github.com/younke/asdf-swiftgen.git"), + ( + "swiftlint", + "https://github.com/klundberg/asdf-swiftlint.git", + ), + ("swiprolog", "https://github.com/mracos/asdf-swiprolog.git"), + ("syft", "https://github.com/davidgp1701/asdf-syft.git"), + ("syncher", "https://github.com/nwillc/syncher.git"), + ("talos", "https://github.com/particledecay/asdf-talos.git"), + ("tanka", "https://github.com/trotttrotttrott/asdf-tanka.git"), + ("task", "https://github.com/particledecay/asdf-task.git"), + ( + "tekton-cli", + "https://github.com/johnhamelink/asdf-tekton-cli.git", + ), + ( + "teleport-community", + "https://github.com/MaloPolese/asdf-teleport-community", + ), + ("teleport-ent", "https://github.com/highb/asdf-teleport-ent"), + ( + "telepresence", + "https://github.com/pirackr/asdf-telepresence.git", + ), + ( + "terradozer", + "https://github.com/chessmango/asdf-terradozer.git", + ), + ( + "terraform", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ( + "terraform-docs", + "https://github.com/looztra/asdf-terraform-docs.git", + ), + ( + "terraform-ls", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ( + "terraform-lsp", + "https://github.com/bartlomiejdanek/terraform-lsp.git", + ), + ( + "terraform-validator", + "https://github.com/looztra/asdf-terraform-validator.git", + ), + ("terragrunt", "https://github.com/ohmer/asdf-terragrunt.git"), + ( + "terramate", + "https://github.com/martinlindner/asdf-terramate.git", + ), + ( + "tf-summarize", + "https://github.com/adamcrews/asdf-tf-summarize.git", + ), + ( + "tfc-agent", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ("tfctl", "https://github.com/deas/asdf-tfctl"), + ("tfenv", "https://github.com/carlduevel/asdf-tfenv.git"), + ("tflint", "https://github.com/skyzyx/asdf-tflint.git"), + ("tfmigrate", "https://github.com/dex4er/asdf-tfmigrate.git"), + ("tfsec", "https://github.com/woneill/asdf-tfsec.git"), + ( + "tfstate-lookup", + "https://github.com/carnei-ro/asdf-tfstate-lookup.git", + ), + ("tfupdate", "https://github.com/yuokada/asdf-tfupdate.git"), + ("thrift", "https://github.com/alisaifee/asdf-thrift.git"), + ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), + ("titan", "https://github.com/gabitchov/asdf-titan.git"), + ("tmux", "https://github.com/aphecetche/asdf-tmux.git"), + ("tokei", "https://github.com/gasuketsu/asdf-tokei.git"), + ("tomcat", "https://github.com/mbutov/asdf-tomcat"), + ( + "tonnage", + "https://github.com/elementalvoid/asdf-tonnage.git", + ), + ( + "tool-versions-to-env", + "https://github.com/smartcontractkit/tool-versions-to-env-action.git", + ), + ("trdsql", "https://github.com/johnlayton/asdf-trdsql.git"), + ( + "tridentctl", + "https://github.com/asdf-community/asdf-tridentctl.git", + ), + ("trivy", "https://github.com/zufardhiyaulhaq/asdf-trivy.git"), + ( + "tsuru", + "https://github.com/virtualstaticvoid/asdf-tsuru.git", + ), + ("upt", "https://github.com/ORCID/asdf-upt.git"), + ("upx", "https://github.com/jimmidyson/asdf-upx.git"), + ("usql", "https://github.com/itspngu/asdf-usql.git"), + ("v", "https://github.com/jthegedus/asdf-v.git"), + ("vals", "https://github.com/dex4er/asdf-vals.git"), + ( + "vault", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ("vcluster", "https://gitlab.com/wt0f/asdf-vcluster.git"), + ("vela", "https://github.com/pdemagny/asdf-vela"), + ("velad", "https://github.com/pdemagny/asdf-velad"), + ("velero", "https://github.com/looztra/asdf-velero.git"), + ("vendir", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ("vhs", "https://github.com/chessmango/asdf-vhs.git"), + ("viddy", "https://github.com/ryodocx/asdf-viddy.git"), + ("vim", "https://github.com/tsuyoshicho/asdf-vim.git"), + ( + "vultr-cli", + "https://github.com/ikuradon/asdf-vultr-cli.git", + ), + ( + "wasi-sdk", + "https://github.com/coolreader18/asdf-wasi-sdk.git", + ), + ("wasm3", "https://github.com/tachyonicbytes/asdf-wasm3"), + ("wasm4", "https://github.com/jtakakura/asdf-wasm4"), + ("wasmer", "https://github.com/tachyonicbytes/asdf-wasmer"), + ( + "wasmtime", + "https://github.com/tachyonicbytes/asdf-wasmtime", + ), + ("watchexec", "https://github.com/nyrst/asdf-watchexec.git"), + ( + "waypoint", + "https://github.com/asdf-community/asdf-hashicorp.git", + ), + ("weave-gitops", "https://github.com/deas/asdf-weave-gitops"), + ( + "websocat", + "https://github.com/bdellegrazie/asdf-websocat.git", + ), + ("wren-cli", "https://github.com/jtakakura/asdf-wren-cli.git"), + ("wtfutil", "https://github.com/NeoHsu/asdf-wtfutil.git"), + ( + "xchtmlreport", + "https://github.com/younke/asdf-xchtmlreport.git", + ), + ("xcodegen", "https://github.com/younke/asdf-xcodegen.git"), + ("xh", "https://github.com/NeoHsu/asdf-xh"), + ("yadm", "https://github.com/particledecay/asdf-yadm.git"), + ( + "yamllint", + "https://github.com/ericcornelissen/asdf-yamllint.git", + ), + ("yarn", "https://github.com/twuni/asdf-yarn.git"), + ("yay", "https://github.com/aaaaninja/asdf-yay.git"), + ("yj", "https://github.com/ryodocx/asdf-yj.git"), + ("yor", "https://github.com/ordinaryexperts/asdf-yor"), + ("yq", "https://github.com/sudermanjr/asdf-yq.git"), + ("ytt", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ("zellij", "https://github.com/chessmango/asdf-zellij.git"), + ("zephyr", "https://github.com/nsaunders/asdf-zephyr.git"), + ("zig", "https://github.com/cheetah/asdf-zig.git"), + ("zigmod", "https://github.com/kachick/asdf-zigmod.git"), + ("zola", "https://github.com/salasrod/asdf-zola.git"), + ("zoxide", "https://github.com/nyrst/asdf-zoxide"), + ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), +]; diff --git a/src/shorthand_repository.rs b/src/shorthand_repository.rs deleted file mode 100644 index 189b48686..000000000 --- a/src/shorthand_repository.rs +++ /dev/null @@ -1,141 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use std::time::Duration; - -use color_eyre::eyre::{eyre, Result}; -use owo_colors::{OwoColorize, Stream}; - -use crate::config::Settings; -use crate::file::changed_within; -use crate::git::Git; -use crate::{dirs, file}; - -const ASDF_PLUGINS_REPO: &str = "https://github.com/asdf-vm/asdf-plugins"; - -#[derive(Debug)] -pub struct ShorthandRepo { - repo_dir: PathBuf, - plugin_repository_last_check_duration: Duration, - disable_plugin_repository: bool, -} - -impl ShorthandRepo { - pub fn new(settings: &Settings) -> Self { - Self { - repo_dir: dirs::SHORTHAND_REPOSITORY.to_path_buf(), - plugin_repository_last_check_duration: settings.plugin_repository_last_check_duration, - disable_plugin_repository: settings.disable_plugin_short_name_repository, - } - } - - pub fn list_all(&self) -> Result> { - self.create_or_update()?; - let mut output = vec![]; - for dir in self.repo_dir.join("plugins").read_dir()? { - let file_name = dir?.file_name().to_string_lossy().to_string(); - output.push(ShorthandRepoEntry { - url: self.lookup(&file_name)?, - name: file_name, - }); - } - output.sort_by(|a, b| a.name.cmp(&b.name)); - - Ok(output) - } - - pub fn lookup(&self, name: &str) -> Result { - if !self.disable_plugin_repository { - self.create_or_update()?; - let plugin = self.repo_dir.join("plugins").join(name); - let file = fs::read_to_string(plugin).unwrap_or_default(); - for line in file.split('\n') { - if line.starts_with("repository") { - let value = line.split('=').nth(1).unwrap().trim(); - return Ok(value.to_string()); - } - } - } - - Err(eyre!( - "No plugin found for {}", - name.if_supports_color(Stream::Stderr, |t| t.cyan()) - )) - } - - pub fn create_or_update(&self) -> Result<()> { - self.ensure_created()?; - if !self.changed_recently()? { - eprintln!("rtx: Updating shorthand plugins repository..."); - let git = self.get_git(); - git.update(None)?; - file::touch_dir(&self.repo_dir)?; - } - - Ok(()) - } - - pub fn ensure_created(&self) -> Result<()> { - if !self.repo_dir.exists() { - eprint!("rtx: Cloning shorthand plugins repository..."); - self.get_git().clone(ASDF_PLUGINS_REPO)?; - eprintln!(" done"); - } - Ok(()) - } - - /// returns true if repo_dir was modified less than 24 hours ago - fn changed_recently(&self) -> Result { - changed_within(&self.repo_dir, self.plugin_repository_last_check_duration) - } - - fn get_git(&self) -> Git { - Git::new(self.repo_dir.clone()) - } -} - -pub struct ShorthandRepoEntry { - pub name: String, - pub url: String, -} - -#[cfg(test)] -mod tests { - use filetime::FileTime; - use insta::assert_display_snapshot; - use pretty_assertions::assert_str_eq; - - use super::*; - - #[test] - fn test_lookup() { - let shr = ShorthandRepo::new(&Settings::default()); - let url = shr.lookup("ruby").unwrap(); - assert_str_eq!(url, "https://github.com/asdf-vm/asdf-ruby.git"); - } - - #[test] - fn test_lookup_err() { - let shr = ShorthandRepo::new(&Settings::default()); - let err = shr.lookup("xxruby").unwrap_err(); - assert_display_snapshot!(err); - } - - #[test] - fn test_update() { - let shr = ShorthandRepo::new(&Settings::default()); - let url = shr.lookup("ruby").unwrap(); - assert_str_eq!(url, "https://github.com/asdf-vm/asdf-ruby.git"); - filetime::set_file_times(shr.repo_dir.clone(), FileTime::zero(), FileTime::zero()).unwrap(); - let url = shr.lookup("ruby").unwrap(); - assert_str_eq!(url, "https://github.com/asdf-vm/asdf-ruby.git"); - } - - #[test] - fn test_create() { - let dir = tempfile::tempdir().unwrap(); - let mut shr = ShorthandRepo::new(&Settings::default()); - shr.repo_dir = dir.path().join("shr"); - let url = shr.lookup("ruby").unwrap(); - assert_str_eq!(url, "https://github.com/asdf-vm/asdf-ruby.git"); - } -} diff --git a/src/snapshots/rtx__shorthand_repository__tests__lookup_err.snap b/src/snapshots/rtx__shorthand_repository__tests__lookup_err.snap deleted file mode 100644 index af51772d9..000000000 --- a/src/snapshots/rtx__shorthand_repository__tests__lookup_err.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/shorthand_repository.rs -expression: err ---- -No plugin found for xxruby diff --git a/src/test.rs b/src/test.rs index 6b39f3f27..d9e6c3b51 100644 --- a/src/test.rs +++ b/src/test.rs @@ -38,8 +38,6 @@ pub fn reset_config() { missing_runtime_behavior= 'autoinstall' always_keep_download= true legacy_version_file= true - disable_plugin_short_name_repository= false - plugin_repository_last_check_duration = 20 plugin_autoupdate_last_check_duration = 20 [alias.shfmt] diff --git a/test/config/config.toml b/test/config/config.toml index c143c6183..517c8c3a4 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -2,8 +2,6 @@ verbose = true missing_runtime_behavior= 'autoinstall' always_keep_download= true legacy_version_file= true -disable_plugin_short_name_repository= false -plugin_repository_last_check_duration = 20 plugin_autoupdate_last_check_duration = 20 [alias.shfmt] From 8d7997e4fe2f4e0959f7cf0d2309dced14d03538 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 13:57:03 -0600 Subject: [PATCH 0143/1891] chore: Release rtx-cli version 1.8.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 350dcfc07..996472afd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.7.0" +version = "1.8.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 75a400591..f60c6d49b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.7.0" +version = "1.8.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 691fdc72e..0be489e27 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.7.0 +rtx 1.8.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -177,7 +177,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.7.0/rtx-v1.7.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.8.0/rtx-v1.8.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a77392938..bbe5c281a 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.7.0 +Version: 1.8.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e97b681e3..84b4c6d09 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -195,7 +195,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.7.0/rtx-v1.7.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.8.0/rtx-v1.8.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From cd2cf202c35004499b46af64be9cb1cc03f86752 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 14:29:24 -0600 Subject: [PATCH 0144/1891] bug: ensure `rtx version` works even if config loading fails (#130) This also adds the version to error messages and makes it so config loading will show a friendlier error message unless RTX_DEBUG=1 is set. --- src/cli/mod.rs | 2 +- src/cli/version.rs | 19 ++++++++++++++++--- src/main.rs | 30 +++++++++++++++++++----------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index da436d78e..ff1a2d99a 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -33,7 +33,7 @@ mod ls_remote; mod plugins; mod settings; mod uninstall; -mod version; +pub mod version; mod r#where; // render help diff --git a/src/cli/version.rs b/src/cli/version.rs index 32d42c3f6..aef4d2d02 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -38,14 +38,27 @@ pub static VERSION: Lazy = Lazy::new(|| { impl Command for Version { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let v = VERSION.to_string(); - rtxprintln!(out, "{v}"); + show_version(out); Ok(()) } } +pub fn print_version_if_requested(args: &[String], out: &mut Output) { + if args.len() == 2 { + let cmd = &args[1].to_lowercase(); + if cmd == "version" || cmd == "-v" || cmd == "--version" { + show_version(out); + std::process::exit(0); + } + } +} + +fn show_version(out: &mut Output) { + rtxprintln!(out, "{}", *VERSION); +} + #[cfg(test)] -mod tests { +mod test { use pretty_assertions::assert_str_eq; use crate::assert_cli; diff --git a/src/main.rs b/src/main.rs index effb680fa..a133e12d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate log; use color_eyre::eyre::Result; +use crate::cli::version::VERSION; use crate::cli::Cli; use crate::config::Config; use crate::output::Output; @@ -41,24 +42,31 @@ mod test; fn main() -> Result<()> { color_eyre::install()?; - let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); - let config = Config::load()?; - if hook_env::should_exit_early(&config) { - return Ok(()); - } - let cli = Cli::new_with_external_commands(&config)?; - match cli.run(config, &env::ARGS, &mut Output::new()) { + match run(&env::ARGS) { Err(err) if log_level < log::LevelFilter::Debug => { error!("{err}"); - error!( - // "rtx error: Run with `--log-level debug` or RTX_DEBUG=1 for more information." - "Run with RTX_DEBUG=1 for more information." - ); + // TODO: tell user they can use --log-level when it's implemented + error!("Run with RTX_DEBUG=1 for more information."); + error!("rtx {}", *VERSION); std::process::exit(1); } result => result, } } + +fn run(args: &Vec) -> Result<()> { + let out = &mut Output::new(); + + // show version before loading config in case of error + cli::version::print_version_if_requested(&env::ARGS, out); + + let config = Config::load()?; + if hook_env::should_exit_early(&config) { + return Ok(()); + } + let cli = Cli::new_with_external_commands(&config)?; + cli.run(config, args, out) +} From 8b3d8bba622ee367415545c7e7cd9b981dba6652 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 14:38:20 -0600 Subject: [PATCH 0145/1891] test: rename mod test -> mod tests (#131) I just realized I was not at all consistent about this --- src/cli/activate.rs | 2 +- src/cli/alias/ls.rs | 4 ++-- src/cli/asdf.rs | 2 +- src/cli/complete.rs | 2 +- src/cli/current.rs | 4 ++-- src/cli/deactivate.rs | 2 +- src/cli/direnv/envrc.rs | 2 +- src/cli/direnv/exec.rs | 4 ++-- ...ap => rtx__cli__direnv__envrc__tests__direnv_envrc.snap} | 0 src/cli/doctor.rs | 4 ++-- src/cli/env.rs | 4 ++-- src/cli/exec.rs | 4 ++-- src/cli/global.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/install.rs | 2 +- src/cli/latest.rs | 2 +- src/cli/local.rs | 4 ++-- src/cli/ls.rs | 2 +- src/cli/ls_remote.rs | 4 ++-- src/cli/mod.rs | 6 +++--- src/cli/plugins/install.rs | 6 +++--- src/cli/plugins/ls.rs | 4 ++-- src/cli/plugins/ls_remote.rs | 4 ++-- ....snap => rtx__cli__plugins__install__tests__nodejs.snap} | 0 ...lugins__install__tests__plugin_install_invalid_url.snap} | 0 ...cli__plugins__uninstall__tests__plugin_uninstall-2.snap} | 0 ...__cli__plugins__uninstall__tests__plugin_uninstall.snap} | 0 src/cli/plugins/uninstall.rs | 4 ++-- src/cli/plugins/update.rs | 2 +- src/cli/settings/get.rs | 2 +- src/cli/settings/ls.rs | 2 +- src/cli/settings/set.rs | 2 +- ...snap => rtx__cli__settings__ls__tests__settings_ls.snap} | 0 ...ap => rtx__cli__settings__set__tests__settings_set.snap} | 0 src/cli/settings/unset.rs | 2 +- ...sh.snap => rtx__cli__activate__tests__activate_zsh.snap} | 0 ... => rtx__cli__activate__tests__activate_zsh_legacy.snap} | 0 ...nap => rtx__cli__deactivate__tests__deactivate_zsh.snap} | 0 ...rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap} | 0 ...global-2.snap => rtx__cli__global__tests__global-2.snap} | 0 ...global-3.snap => rtx__cli__global__tests__global-3.snap} | 0 ...global-4.snap => rtx__cli__global__tests__global-4.snap} | 0 ...st__global.snap => rtx__cli__global__tests__global.snap} | 0 ...st__latest.snap => rtx__cli__latest__tests__latest.snap} | 0 ...nap => rtx__cli__latest__tests__latest_asdf_format.snap} | 0 ...t__local-2.snap => rtx__cli__local__tests__local-2.snap} | 0 ...t__local-3.snap => rtx__cli__local__tests__local-3.snap} | 0 ..._test__local.snap => rtx__cli__local__tests__local.snap} | 0 src/cli/version.rs | 2 +- src/cli/where.rs | 2 +- src/direnv.rs | 2 +- src/file.rs | 2 +- src/hook_env.rs | 2 +- src/plugins/mod.rs | 2 +- ...p => rtx__direnv__tests__add_path_to_old_and_new-2.snap} | 0 ...nap => rtx__direnv__tests__add_path_to_old_and_new.snap} | 0 ...v__test__dump-2.snap => rtx__direnv__tests__dump-2.snap} | 0 ...irenv__test__dump.snap => rtx__direnv__tests__dump.snap} | 0 ...ull_path-2.snap => rtx__direnv__tests__null_path-2.snap} | 0 ...t__null_path.snap => rtx__direnv__tests__null_path.snap} | 0 ...env__test__parse.snap => rtx__direnv__tests__parse.snap} | 0 61 files changed, 49 insertions(+), 49 deletions(-) rename src/cli/direnv/snapshots/{rtx__cli__direnv__envrc__test__direnv_envrc.snap => rtx__cli__direnv__envrc__tests__direnv_envrc.snap} (100%) rename src/cli/plugins/snapshots/{rtx__cli__plugins__install__test__nodejs.snap => rtx__cli__plugins__install__tests__nodejs.snap} (100%) rename src/cli/plugins/snapshots/{rtx__cli__plugins__install__test__plugin_install_invalid_url.snap => rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap} (100%) rename src/cli/plugins/snapshots/{rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap => rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap} (100%) rename src/cli/plugins/snapshots/{rtx__cli__plugins__uninstall__test__plugin_uninstall.snap => rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap} (100%) rename src/cli/settings/snapshots/{rtx__cli__settings__ls__test__settings_ls.snap => rtx__cli__settings__ls__tests__settings_ls.snap} (100%) rename src/cli/settings/snapshots/{rtx__cli__settings__set__test__settings_set.snap => rtx__cli__settings__set__tests__settings_set.snap} (100%) rename src/cli/snapshots/{rtx__cli__activate__test__activate_zsh.snap => rtx__cli__activate__tests__activate_zsh.snap} (100%) rename src/cli/snapshots/{rtx__cli__activate__test__activate_zsh_legacy.snap => rtx__cli__activate__tests__activate_zsh_legacy.snap} (100%) rename src/cli/snapshots/{rtx__cli__deactivate__test__deactivate_zsh.snap => rtx__cli__deactivate__tests__deactivate_zsh.snap} (100%) rename src/cli/snapshots/{rtx__cli__deactivate__test__deactivate_zsh_legacy.snap => rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap} (100%) rename src/cli/snapshots/{rtx__cli__global__test__global-2.snap => rtx__cli__global__tests__global-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__global__test__global-3.snap => rtx__cli__global__tests__global-3.snap} (100%) rename src/cli/snapshots/{rtx__cli__global__test__global-4.snap => rtx__cli__global__tests__global-4.snap} (100%) rename src/cli/snapshots/{rtx__cli__global__test__global.snap => rtx__cli__global__tests__global.snap} (100%) rename src/cli/snapshots/{rtx__cli__latest__test__latest.snap => rtx__cli__latest__tests__latest.snap} (100%) rename src/cli/snapshots/{rtx__cli__latest__test__latest_asdf_format.snap => rtx__cli__latest__tests__latest_asdf_format.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__test__local-2.snap => rtx__cli__local__tests__local-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__test__local-3.snap => rtx__cli__local__tests__local-3.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__test__local.snap => rtx__cli__local__tests__local.snap} (100%) rename src/snapshots/{rtx__direnv__test__add_path_to_old_and_new-2.snap => rtx__direnv__tests__add_path_to_old_and_new-2.snap} (100%) rename src/snapshots/{rtx__direnv__test__add_path_to_old_and_new.snap => rtx__direnv__tests__add_path_to_old_and_new.snap} (100%) rename src/snapshots/{rtx__direnv__test__dump-2.snap => rtx__direnv__tests__dump-2.snap} (100%) rename src/snapshots/{rtx__direnv__test__dump.snap => rtx__direnv__tests__dump.snap} (100%) rename src/snapshots/{rtx__direnv__test__null_path-2.snap => rtx__direnv__tests__null_path-2.snap} (100%) rename src/snapshots/{rtx__direnv__test__null_path.snap => rtx__direnv__tests__null_path.snap} (100%) rename src/snapshots/{rtx__direnv__test__parse.snap => rtx__direnv__tests__parse.snap} (100%) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 702cc2d01..539d3a780 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -66,7 +66,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_display_snapshot; use crate::assert_cli; diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 725f760c3..8ecb63e2b 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -52,9 +52,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; - use crate::cli::test::ensure_plugin_installed; + use crate::cli::tests::ensure_plugin_installed; #[test] fn test_alias_ls() { diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index f694ec387..447f7d3b0 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -60,7 +60,7 @@ fn list_versions(out: &mut Output, args: &Vec) -> Result<()> { } #[cfg(test)] -mod test { +mod tests { use pretty_assertions::assert_str_eq; use crate::assert_cli; diff --git a/src/cli/complete.rs b/src/cli/complete.rs index 30b9b30a3..f58f401d3 100644 --- a/src/cli/complete.rs +++ b/src/cli/complete.rs @@ -40,7 +40,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); // #[cfg(test)] -// mod test { +// mod tests { // use std::fs; // // use insta::assert_snapshot; diff --git a/src/cli/current.rs b/src/cli/current.rs index cd185b314..a4b26f421 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -113,11 +113,11 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_snapshot; use crate::assert_cli; - use crate::cli::test::grep; + use crate::cli::tests::grep; #[test] fn test_current() { diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 30a174a3e..d0aa7337e 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -47,7 +47,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_display_snapshot; use crate::assert_cli; diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 2ac2697f9..5f93813ee 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -56,7 +56,7 @@ impl Command for Envrc { } #[cfg(test)] -mod test { +mod tests { use std::fs; use insta::assert_display_snapshot; diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 286ca79da..576535573 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -46,9 +46,9 @@ impl Command for DirenvExec { } #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; - use crate::cli::test::grep; + use crate::cli::tests::grep; use pretty_assertions::assert_str_eq; #[test] diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap similarity index 100% rename from src/cli/direnv/snapshots/rtx__cli__direnv__envrc__test__direnv_envrc.snap rename to src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 9c952559b..17b77f9aa 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -52,8 +52,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { - use crate::cli::test::cli_run; +mod tests { + use crate::cli::tests::cli_run; #[test] fn test_doctor() { diff --git a/src/cli/env.rs b/src/cli/env.rs index 04f4fe650..f55bf4f18 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -62,9 +62,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; - use crate::cli::test::grep; + use crate::cli::tests::grep; use crate::dirs; use pretty_assertions::assert_str_eq; diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 09aa58355..419f35dc3 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -122,9 +122,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; - use crate::cli::test::cli_run; + use crate::cli::tests::cli_run; #[test] fn test_exec_ok() { diff --git a/src/cli/global.rs b/src/cli/global.rs index c3e418c7f..f05118673 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -79,7 +79,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use std::fs; use insta::assert_snapshot; diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index a7a8d9cd7..e290a30ec 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -165,7 +165,7 @@ impl HookEnv { } #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; #[test] diff --git a/src/cli/install.rs b/src/cli/install.rs index 10856916b..2f206ebf6 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -162,7 +162,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; #[test] diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 7c75bbea6..c2313a6f6 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -58,7 +58,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_display_snapshot; use crate::assert_cli; diff --git a/src/cli/local.rs b/src/cli/local.rs index 1c24137da..7bdf97a41 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -103,13 +103,13 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use std::fs; use insta::assert_snapshot; use pretty_assertions::assert_str_eq; - use crate::cli::test::grep; + use crate::cli::tests::grep; use crate::{assert_cli, dirs}; #[test] diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 68f133150..7d44136fe 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -150,7 +150,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use regex::Regex; use crate::assert_cli; diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 2f80ce2a5..07a6696a0 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -48,9 +48,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; - use crate::cli::test::ensure_plugin_installed; + use crate::cli::tests::ensure_plugin_installed; #[test] fn test_list_remote() { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ff1a2d99a..481c2d9a5 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -191,7 +191,7 @@ static AFTER_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -pub mod test { +pub mod tests { use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::config::Settings; use crate::dirs; @@ -211,7 +211,7 @@ pub mod test { macro_rules! assert_cli { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::test::cli_run(args).unwrap().stdout.content + $crate::cli::tests::cli_run(args).unwrap().stdout.content }}; } @@ -219,7 +219,7 @@ pub mod test { macro_rules! assert_cli_err { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::test::cli_run(args).unwrap_err() + $crate::cli::tests::cli_run(args).unwrap_err() }}; } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 0764a94b5..6227483d0 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -135,12 +135,12 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::{assert_display_snapshot, assert_snapshot}; use crate::assert_cli; - use crate::cli::test::cli_run; - use crate::cli::test::grep; + use crate::cli::tests::cli_run; + use crate::cli::tests::grep; #[test] fn test_plugin_install() { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 7f26d8e7a..ef864ad6f 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -62,11 +62,11 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use pretty_assertions::assert_str_eq; use crate::assert_cli; - use crate::cli::test::grep; + use crate::cli::tests::grep; #[test] fn test_plugin_list() { diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 2aab207a7..0035999c1 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -55,9 +55,9 @@ Examples: "#; #[cfg(test)] -mod test { +mod tests { use crate::assert_cli; - use crate::cli::test::ensure_plugin_installed; + use crate::cli::tests::ensure_plugin_installed; #[test] fn test_plugin_list_remote() { diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__nodejs.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__nodejs.snap similarity index 100% rename from src/cli/plugins/snapshots/rtx__cli__plugins__install__test__nodejs.snap rename to src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__nodejs.snap diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_invalid_url.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap similarity index 100% rename from src/cli/plugins/snapshots/rtx__cli__plugins__install__test__plugin_install_invalid_url.snap rename to src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap similarity index 100% rename from src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall-2.snap rename to src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap similarity index 100% rename from src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__test__plugin_uninstall.snap rename to src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 197b91e30..c60a25b99 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -49,11 +49,11 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_snapshot; use crate::assert_cli; - use crate::cli::test::ensure_plugin_installed; + use crate::cli::tests::ensure_plugin_installed; #[test] fn test_plugin_uninstall() { diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 00c6274a9..18e894fd6 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -59,7 +59,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use pretty_assertions::assert_str_eq; use crate::{assert_cli, assert_cli_err}; diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index c31a252a8..4c19a2669 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -40,7 +40,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::{assert_display_snapshot, assert_snapshot}; use crate::test::reset_config; diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 81ae9b02e..329f33d28 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -37,7 +37,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_snapshot; use crate::assert_cli; diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 1475c123d..253a85a2a 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -62,7 +62,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -pub mod test { +pub mod tests { use insta::assert_snapshot; use crate::assert_cli; diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap similarity index 100% rename from src/cli/settings/snapshots/rtx__cli__settings__ls__test__settings_ls.snap rename to src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap similarity index 100% rename from src/cli/settings/snapshots/rtx__cli__settings__set__test__settings_set.snap rename to src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 09f38ff3f..f105dfd03 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -36,7 +36,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_snapshot; use crate::assert_cli; diff --git a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__activate__test__activate_zsh.snap rename to src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap diff --git a/src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__activate__test__activate_zsh_legacy.snap rename to src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap diff --git a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh.snap rename to src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap diff --git a/src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__deactivate__test__deactivate_zsh_legacy.snap rename to src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap diff --git a/src/cli/snapshots/rtx__cli__global__test__global-2.snap b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__global__test__global-2.snap rename to src/cli/snapshots/rtx__cli__global__tests__global-2.snap diff --git a/src/cli/snapshots/rtx__cli__global__test__global-3.snap b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__global__test__global-3.snap rename to src/cli/snapshots/rtx__cli__global__tests__global-3.snap diff --git a/src/cli/snapshots/rtx__cli__global__test__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__global__test__global-4.snap rename to src/cli/snapshots/rtx__cli__global__tests__global-4.snap diff --git a/src/cli/snapshots/rtx__cli__global__test__global.snap b/src/cli/snapshots/rtx__cli__global__tests__global.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__global__test__global.snap rename to src/cli/snapshots/rtx__cli__global__tests__global.snap diff --git a/src/cli/snapshots/rtx__cli__latest__test__latest.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__latest__test__latest.snap rename to src/cli/snapshots/rtx__cli__latest__tests__latest.snap diff --git a/src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__latest__test__latest_asdf_format.snap rename to src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap diff --git a/src/cli/snapshots/rtx__cli__local__test__local-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__test__local-2.snap rename to src/cli/snapshots/rtx__cli__local__tests__local-2.snap diff --git a/src/cli/snapshots/rtx__cli__local__test__local-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local-3.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__test__local-3.snap rename to src/cli/snapshots/rtx__cli__local__tests__local-3.snap diff --git a/src/cli/snapshots/rtx__cli__local__test__local.snap b/src/cli/snapshots/rtx__cli__local__tests__local.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__test__local.snap rename to src/cli/snapshots/rtx__cli__local__tests__local.snap diff --git a/src/cli/version.rs b/src/cli/version.rs index aef4d2d02..e55083a39 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -58,7 +58,7 @@ fn show_version(out: &mut Output) { } #[cfg(test)] -mod test { +mod tests { use pretty_assertions::assert_str_eq; use crate::assert_cli; diff --git a/src/cli/where.rs b/src/cli/where.rs index 5d86157ba..3f757b6d1 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -66,7 +66,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { }); #[cfg(test)] -mod test { +mod tests { use insta::assert_display_snapshot; use pretty_assertions::assert_str_eq; diff --git a/src/direnv.rs b/src/direnv.rs index 3bc0fd7e1..6a55f4af8 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -110,7 +110,7 @@ impl Display for DirenvDiff { } #[cfg(test)] -mod test { +mod tests { use super::*; use insta::assert_display_snapshot; diff --git a/src/file.rs b/src/file.rs index f3b27a9ff..961c1cb90 100644 --- a/src/file.rs +++ b/src/file.rs @@ -120,7 +120,7 @@ impl Iterator for FindUp { } #[cfg(test)] -mod test { +mod tests { use std::ops::Deref; use crate::dirs; diff --git a/src/hook_env.rs b/src/hook_env.rs index 5041b403c..c1ed497c3 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -95,7 +95,7 @@ pub fn deserialize_watches(raw: String) -> Result { } #[cfg(test)] -mod test { +mod tests { use std::time::UNIX_EPOCH; use crate::dirs; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index f91c21a18..54822d051 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -429,7 +429,7 @@ impl PartialEq for Plugin { } #[cfg(test)] -mod test { +mod tests { use pretty_assertions::assert_str_eq; use crate::{assert_cli, env}; diff --git a/src/snapshots/rtx__direnv__test__add_path_to_old_and_new-2.snap b/src/snapshots/rtx__direnv__tests__add_path_to_old_and_new-2.snap similarity index 100% rename from src/snapshots/rtx__direnv__test__add_path_to_old_and_new-2.snap rename to src/snapshots/rtx__direnv__tests__add_path_to_old_and_new-2.snap diff --git a/src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap b/src/snapshots/rtx__direnv__tests__add_path_to_old_and_new.snap similarity index 100% rename from src/snapshots/rtx__direnv__test__add_path_to_old_and_new.snap rename to src/snapshots/rtx__direnv__tests__add_path_to_old_and_new.snap diff --git a/src/snapshots/rtx__direnv__test__dump-2.snap b/src/snapshots/rtx__direnv__tests__dump-2.snap similarity index 100% rename from src/snapshots/rtx__direnv__test__dump-2.snap rename to src/snapshots/rtx__direnv__tests__dump-2.snap diff --git a/src/snapshots/rtx__direnv__test__dump.snap b/src/snapshots/rtx__direnv__tests__dump.snap similarity index 100% rename from src/snapshots/rtx__direnv__test__dump.snap rename to src/snapshots/rtx__direnv__tests__dump.snap diff --git a/src/snapshots/rtx__direnv__test__null_path-2.snap b/src/snapshots/rtx__direnv__tests__null_path-2.snap similarity index 100% rename from src/snapshots/rtx__direnv__test__null_path-2.snap rename to src/snapshots/rtx__direnv__tests__null_path-2.snap diff --git a/src/snapshots/rtx__direnv__test__null_path.snap b/src/snapshots/rtx__direnv__tests__null_path.snap similarity index 100% rename from src/snapshots/rtx__direnv__test__null_path.snap rename to src/snapshots/rtx__direnv__tests__null_path.snap diff --git a/src/snapshots/rtx__direnv__test__parse.snap b/src/snapshots/rtx__direnv__tests__parse.snap similarity index 100% rename from src/snapshots/rtx__direnv__test__parse.snap rename to src/snapshots/rtx__direnv__tests__parse.snap From aa9cb26819f407a3bf35ae2fe47d4f595538d749 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 15:23:08 -0600 Subject: [PATCH 0146/1891] feat: display current tool-versions value if no version set (#132) Fixes #67 Before this change the behavior of something like `rtx local ruby` was pretty inconsistent. Generally it would set the version to what was in the global tool-versions file or just error out. Either one seemed pretty useless to me. I was thinking this could be a "get" instead of "set" mode, so now it will display what the current value is in `.tool-versions`. This is slightly different than `rtx current ruby` because that shows what is the currently used which could be coming from any .tool-versions file (or env var or something). This _only_ shows the value from the current `.tool-versions` file. I'm not entirely sure this behavior is good/predictible, so I may regret this decision but I think it is at least better than what we have currently. --- README.md | 16 +++++++++++++++- completions/_rtx | 2 +- src/cli/global.rs | 36 ++++++++++++++++++++++++++++++++--- src/cli/local.rs | 27 ++++++++++++++++++++++++-- src/config/config_file/mod.rs | 33 +++++++++++++++++++++++++++++++- 5 files changed, 106 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0be489e27..e3dfc7c20 100644 --- a/README.md +++ b/README.md @@ -750,6 +750,7 @@ Examples: ``` sets global .tool-versions to include a specified runtime +then displays the contents of ~/.tool-versions this file is `$HOME/.tool-versions` by default use `rtx local` to set a runtime version locally in the current directory @@ -757,9 +758,11 @@ Usage: global [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - runtimes + runtime(s) to add to .tool-versions e.g.: nodejs@20 + if this is a single runtime with no version, the current value of the global + .tool-versions will be displayed Options: --fuzzy @@ -780,6 +783,10 @@ Examples: # will use a fuzzy version (e.g.: 20) in .tool-versions file $ rtx global --fuzzy nodejs@20 + # show the current version of nodejs in ~/.tool-versions + $ rtx global nodejs + 20.0.0 + ``` ### `rtx install` @@ -851,6 +858,7 @@ Examples: ``` Sets .tool-versions to include a specific runtime +then displays the contents of .tool-versions use this to set the runtime version when within a directory use `rtx global` to set a runtime version globally @@ -861,6 +869,8 @@ Arguments: runtimes to add to .tool-versions e.g.: nodejs@20 + if this is a single runtime with no version, + the current value of .tool-versions will be displayed Options: -p, --parent @@ -893,6 +903,10 @@ Examples: # removes nodejs from .tool-versions $ rtx local --remove=nodejs + # show the current version of nodejs in .tool-versions + $ rtx local nodejs + 20.0.0 + ``` ### `rtx ls` diff --git a/completions/_rtx b/completions/_rtx index fd94c5f63..1cf4f3187 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -269,7 +269,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- runtimes:' \ +'*::runtime -- runtime(s) to add to .tool-versions:' \ && ret=0 ;; (hook-env) diff --git a/src/cli/global.rs b/src/cli/global.rs index f05118673..c0844dbfc 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -13,15 +13,18 @@ use crate::{dirs, env}; /// sets global .tool-versions to include a specified runtime /// +/// then displays the contents of ~/.tool-versions /// this file is `$HOME/.tool-versions` by default /// use `rtx local` to set a runtime version locally in the current directory #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Global { - /// runtimes + /// runtime(s) to add to .tool-versions /// /// e.g.: nodejs@20 - #[clap(value_parser = RuntimeArgParser)] + /// if this is a single runtime with no version, the current value of the global + /// .tool-versions will be displayed + #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, /// save fuzzy match to .tool-versions @@ -51,6 +54,9 @@ impl Command for Global { } if let Some(runtimes) = &self.runtime { let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); + if cf.display_runtime(out, &runtimes)? { + return Ok(()); + } cf.add_runtimes(&mut config, &runtimes, self.fuzzy)?; } @@ -75,6 +81,10 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # set the current version of nodejs to 20.x # will use a fuzzy version (e.g.: 20) in .tool-versions file $ rtx global --fuzzy nodejs@20 + + # show the current version of nodejs in ~/.tool-versions + $ rtx global nodejs + 20.0.0 "#, COLOR.header("Examples:")} }); @@ -83,8 +93,9 @@ mod tests { use std::fs; use insta::assert_snapshot; + use pretty_assertions::assert_str_eq; - use crate::{assert_cli, dirs}; + use crate::{assert_cli, assert_cli_err, dirs}; #[test] fn test_global() { @@ -102,6 +113,25 @@ mod tests { let stdout = assert_cli!("global", "tiny", "2"); assert_snapshot!(stdout); + // will output the current version(s) + let stdout = assert_cli!("global", "tiny"); + assert_str_eq!(stdout, "2.1.0\n"); + + // this plugin isn't installed + let err = assert_cli_err!("global", "invalid-plugin"); + assert_str_eq!( + err.to_string(), + "no version set for invalid-plugin in ~/.tool-versions" + ); + + // can only request a version one plugin at a time + let err = assert_cli_err!("global", "tiny", "dummy"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + + // this is just invalid + let err = assert_cli_err!("global", "tiny", "dummy@latest"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + if let Some(orig) = orig { fs::write(cf_path, orig).unwrap(); } diff --git a/src/cli/local.rs b/src/cli/local.rs index 7bdf97a41..a9e7ee747 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -6,6 +6,7 @@ use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::{config_file, Config}; + use crate::output::Output; use crate::plugins::PluginName; use crate::ui::color::Color; @@ -13,6 +14,7 @@ use crate::{dirs, env, file}; /// Sets .tool-versions to include a specific runtime /// +/// then displays the contents of .tool-versions /// use this to set the runtime version when within a directory /// use `rtx global` to set a runtime version globally #[derive(Debug, clap::Args)] @@ -21,7 +23,9 @@ pub struct Local { /// runtimes to add to .tool-versions /// /// e.g.: nodejs@20 - #[clap(value_parser = RuntimeArgParser)] + /// if this is a single runtime with no version, + /// the current value of .tool-versions will be displayed + #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, /// recurse up to find a .tool-versions file rather than using the current directory only @@ -69,6 +73,9 @@ impl Command for Local { if let Some(runtimes) = &self.runtime { let runtimes = RuntimeArg::double_runtime_condition(runtimes); + if cf.display_runtime(out, &runtimes)? { + return Ok(()); + } cf.add_runtimes(&mut config, &runtimes, self.fuzzy)?; } @@ -99,6 +106,10 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # removes nodejs from .tool-versions $ rtx local --remove=nodejs + + # show the current version of nodejs in .tool-versions + $ rtx local nodejs + 20.0.0 "#, COLOR.header("Examples:")} }); @@ -110,7 +121,7 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; - use crate::{assert_cli, dirs}; + use crate::{assert_cli, assert_cli_err, dirs}; #[test] fn test_local() { @@ -135,6 +146,18 @@ mod tests { let stdout = assert_cli!("local", "tiny", "2"); assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); + // will output the current version(s) + let stdout = assert_cli!("local", "tiny"); + assert_str_eq!(stdout, "2.1.0\n"); + + // can only request a version one plugin at a time + let err = assert_cli_err!("local", "tiny", "dummy"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + + // this is just invalid + let err = assert_cli_err!("local", "tiny", "dummy@latest"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + fs::write(cf_path, orig).unwrap(); } } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index dd01f07de..2448b0d46 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Display}; use std::path::Path; use std::sync::Arc; -use color_eyre::eyre::Result; +use color_eyre::eyre::{eyre, Result}; use indexmap::IndexMap; use rtxrc::RTXFile; @@ -14,6 +14,8 @@ use crate::config::Config; use crate::config::PluginSource; use crate::env; use crate::errors::Error::VersionNotInstalled; +use crate::file::display_path; +use crate::output::Output; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; @@ -49,6 +51,7 @@ impl dyn ConfigFile { fuzzy: bool, ) -> Result<()> { let mut runtime_map: HashMap> = HashMap::new(); + for runtime in runtimes { let plugin = Plugin::load_ensure_installed(&runtime.plugin, &config.settings)?; let latest = config.resolve_runtime_arg(runtime)?; @@ -76,6 +79,34 @@ impl dyn ConfigFile { Ok(()) } + + /// this is for `rtx local|global RUNTIME` which will display the version instead of setting it + /// it's only valid to use a single runtime in this case + /// returns "true" if the runtime was displayed which means the CLI should exit + pub fn display_runtime(&self, out: &mut Output, runtimes: &[RuntimeArg]) -> Result { + // in this situation we just print the current version in the config file + if runtimes.len() == 1 && runtimes[0].version == RuntimeArgVersion::None { + let plugin = &runtimes[0].plugin; + let plugins = self.plugins(); + let version = plugins.get(plugin).ok_or_else(|| { + eyre!( + "no version set for {} in {}", + plugin.to_string(), + display_path(self.get_path()) + ) + })?; + rtxprintln!(out, "{}", version.join(" ")); + return Ok(true); + } + // check for something like `rtx local nodejs python@latest` which is invalid + if runtimes + .iter() + .any(|r| r.version == RuntimeArgVersion::None) + { + return Err(eyre!("invalid input, specify a version for each runtime. Or just specify one runtime to print the current version")); + } + Ok(false) + } } pub fn init(path: &Path) -> Box { From be7eb3aaaec5964086895440be7b262ba42d31eb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Feb 2023 15:25:02 -0600 Subject: [PATCH 0147/1891] chore: cargo update --- Cargo.lock | 132 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 996472afd..18a29d462 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,9 +106,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -234,7 +234,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -307,9 +307,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322296e2f2e5af4270b54df9e85a02ff037e271af20ba3e7fe1575515dc840b8" +checksum = "90d59d9acd2a682b4e40605a242f6670eaa58c5957471cbf85e8aa6a0b97a5e8" dependencies = [ "cc", "cxxbridge-flags", @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017a1385b05d631e7875b1f151c9f012d37b53491e2a87f65bff5c262b2111d8" +checksum = "ebfa40bda659dd5c864e65f4c9a2b0aff19bea56b017b9b77c73d3766a453a38" dependencies = [ "cc", "codespan-reporting", @@ -334,15 +334,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26bbb078acf09bc1ecda02d4223f03bdd28bd4874edcb0379138efc499ce971" +checksum = "457ce6757c5c70dc6ecdbda6925b958aae7f959bda7d8fb9bde889e34a09dc03" [[package]] name = "cxxbridge-macro" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357f40d1f06a24b60ae1fe122542c1fb05d28d32acb2aed064e84bc2ad1e252e" +checksum = "ebf883b7aacd7b2aeb2a7b338648ee19f57c140d4ee8e52c68979c6b2f7f2263" dependencies = [ "proc-macro2", "quote", @@ -465,14 +465,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -519,9 +519,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -541,6 +541,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "humantime" version = "2.1.0" @@ -627,24 +633,24 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -670,9 +676,9 @@ checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -823,12 +829,12 @@ checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "os_pipe" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a252f1f8c11e84b3ab59d7a488e48e4478a93937e027076638c49536204639" +checksum = "a53dbb20faf34b16087a931834cba2d7a73cc74af2b7ef345a4c8324e2409a12" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -917,9 +923,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -1077,16 +1083,16 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.7" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1126,9 +1132,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -1338,15 +1344,15 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772c1426ab886e7362aedf4abc9c0d1348a979517efedfc25862944d10137af0" +checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" dependencies = [ "serde", "serde_spanned", @@ -1365,9 +1371,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90a238ee2e6ede22fb95350acc78e21dc40da00bb66c0334bde83de4ed89424e" +checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5" dependencies = [ "indexmap", "nom8", @@ -1492,9 +1498,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1502,9 +1508,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -1517,9 +1523,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1527,9 +1533,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -1540,9 +1546,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "winapi" @@ -1590,6 +1596,30 @@ dependencies = [ "windows_x86_64_msvc", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" From b530ffa0723858bee693fffe96ea7115df924624 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Feb 2023 07:42:43 -0600 Subject: [PATCH 0148/1891] bug: ignore removed settings Fixes #135 --- src/config/config_file/rtxrc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 0c466fc13..15a9a04c8 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -96,6 +96,8 @@ impl RTXFile { "verbose" => self.settings.verbose = Some(self.parse_bool(k, v)?), "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} + "disable_plugin_short_name_repository" => {} + "plugin_repository_last_check_duration" => {} _ => self.parse_plugin(k, v)?, }; Ok(()) From 1098330fb261123eec758ad83d3a81863b72b227 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Feb 2023 07:44:24 -0600 Subject: [PATCH 0149/1891] chore: cargo update --- Cargo.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18a29d462..210054be8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1286,10 +1286,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] From 86a5f37de2c4c99ae651c1537ccb2d9d6fccce1e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Feb 2023 07:44:44 -0600 Subject: [PATCH 0150/1891] chore: Release rtx-cli version 1.9.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 210054be8..04598b3cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1031,7 +1031,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.8.0" +version = "1.9.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index f60c6d49b..392bc167a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.8.0" +version = "1.9.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e3dfc7c20..42f2a837f 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.8.0 +rtx 1.9.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -177,7 +177,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.8.0/rtx-v1.8.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.9.0/rtx-v1.9.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index bbe5c281a..47e5d62f0 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.8.0 +Version: 1.9.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 84b4c6d09..d9e4fb832 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -195,7 +195,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.8.0/rtx-v1.8.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.9.0/rtx-v1.9.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 8909b0bb45b65e17a25d5b48e2f0d01a9a5cac47 Mon Sep 17 00:00:00 2001 From: Chris Serino Date: Mon, 13 Feb 2023 13:22:04 -0600 Subject: [PATCH 0151/1891] chore: Fix typo in README.md (#136) * chore: Fix typo in README.md * chore: Update render_help.rs to match the README.md change --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 42f2a837f..9f1168aa5 100644 --- a/README.md +++ b/README.md @@ -327,7 +327,7 @@ Here are some of the supported legacy version files: > asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies > that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" > version files since they're version files not specific to asdf/rtx and can be used by other tools. -> (`.npmrc` being a notable exception, which is tied to a specific tool.) +> (`.nvmrc` being a notable exception, which is tied to a specific tool.) ### Global config: `~/.config/rtx/config.toml` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index d9e4fb832..2f130369a 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -345,7 +345,7 @@ Here are some of the supported legacy version files: > asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies > that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" > version files since they're version files not specific to asdf/rtx and can be used by other tools. -> (`.npmrc` being a notable exception, which is tied to a specific tool.) +> (`.nvmrc` being a notable exception, which is tied to a specific tool.) ### Global config: `~/.config/rtx/config.toml` From a4647015ed0b00826d310eb7b5458e4f5646bad4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Feb 2023 13:24:02 -0600 Subject: [PATCH 0152/1891] docs: note that README is autogenerated --- README.md | 1 + src/cli/render_help.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 9f1168aa5..55a089c68 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # [rtx](https://github.com/jdxcode/rtx) [![Crates.io](https://img.shields.io/crates/v/rtx-cli.svg)](https://crates.io/crates/rtx-cli) diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 2f130369a..3b666fab3 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -16,6 +16,7 @@ impl Command for RenderHelp { let mut cli = Cli::command().term_width(80).max_term_width(80); out.stdout.write(formatdoc!( r#" + # [rtx](https://github.com/jdxcode/rtx) [![Crates.io](https://img.shields.io/crates/v/rtx-cli.svg)](https://crates.io/crates/rtx-cli) From 67fa81e9685ec810711cd2c29b091f1497c01388 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Feb 2023 15:20:37 -0600 Subject: [PATCH 0153/1891] docs: added basic demo --- README.md | 16 ++++++++++++++++ docs/demo.gif | Bin 0 -> 582092 bytes src/cli/render_help.rs | 16 ++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 docs/demo.gif diff --git a/README.md b/README.md index 55a089c68..700b8dc15 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,22 @@ _Polyglot runtime manager (asdf rust clone)_ +## 30 Second Demo + +The following shows using rtx to install node, python, and jq into a project using a `.tool-versions` file. + +[![demo](./docs/demo.gif)](./docs/demo.gif) + +## Features + +- **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. +- **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. +- **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. +- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them. +- **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. +- **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. +- **One command install** - No need to manually install each plugin, just run `rtx install --all` and it will install all the plugins you need. + ## Quickstart Install rtx (other methods [here](#installation)): diff --git a/docs/demo.gif b/docs/demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..6d079ceddcba6de55b17f88856f5107779de8c65 GIT binary patch literal 582092 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¬_xWEhxl|}!Upn;>^x;!2 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 z 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

%o7k+lFyZ2O8YSOVZVTsbQo9S75&T8vL{!A zA`D9;?_Yn<^VT2xU@_3SzE62RVNU(a&mE-K17FU;h4Ij`Qxk`BoC6aY^@`kdziv^qHL#8J}$o zGHQ~`0p?#Nie_X<%qGDbK6=gb<%;UiL-N;#3a><2zaR+8-)b6rT`8a_DQ{}tzYqcC zvWCwX*WyGmpCr700$dQkC;$F&W$gCUJt>aza`^T`g+wQ6>s`#{{|R614t6aoISulO-9TmFh?>owdywWuJKVC4SJ`A=O@ zI~eer(G!28Jo}>WUHOj`NKpMsAy>>}DHs?^QzoEYW&r%D1U^t^ha$*Z*W?Y7&<_Ls zv8;0%W)hQ?-AIM=+v;dsd-o6ql739(%}^Jp#7sJ&b5j5+HlUBz+B1=eS;1m%BcyKQ zFzAnNEw+)4Y7gd2n-*6Ovrd^<(Kd8iiUi2-N8&aW}uxsY!*;MU+#w zvl6W&DL~EVov11i)Dtid+NkA7R;i2?Xk3QjG$)S*=FRaMm3UPhFE~BEt-WfO$&*bv z6-1!$Dt!w+@#h3w)JLCKUTU(OIoBeY6OWQwpu7yRh$=VL=xT{AGATL>gKU`|n=yG_ zr9$pxSeR#!IMQ%xdkm^Ba_1$M^)domBVcO@-Xa#58Ed&)C#V@5uWAlQgL=KS2kw;F z^UCOWlII`{w7NmR3L~!zlVS~86D=eW06r-I;Uc1(5YNVY(rI*ep1f?#fVojbF4_P8Z`gOKhO@$Tnxy)eQTN_c708_8fyuh`9%q>HgqVFEFtU7%}F#`h=N~I#qKz^x4rK$$))3C3o_(QQwU9qNcJMR}wf3HO0{)RCx$i_t7V8XFS zg^!w)Zyqv1-Pn{K%U5`jj7S(hyOmtx0n}ex#>DB%c*63nD6MJ_dm@_|Klvb_2-32F zky!>k){Xqt4!&QhqRtsppygM(|5n!wW@Vb^ZC3&Ml+PAN%c& z^6os5mes|`c2l6-3yQJ371swOkb(UPtKg0R-&j{F5gA=~hh^eyO%rc+$jQG2aVQA& z?&0K%c@!imNpfM>X5aU!wxFpo-=I@kOI=i3wjQa5A2mZ9eFjG~JDfUj&$5*|5*c(V ze_j)MPpVGoV!cDPCBDnIM&1C$n%9CHmpBUwLiD-h0cn-B` z32VV(L{5jd(y>Oxvzhz7h$G^)hIg|`0wjR=R*M|NG;D%iyGXyPocZ1WX24e?8EwyB z#3N}-7#k+LEM1OZ5cXeSq7tf4C5JL-8(>e8M&fZ;JEhaLqB1D{T#W@s3LcP+@4P%zR5f@!)|G&Z zlEiptYbb-R@!6{A$Uv4+_J;YH3%L+#OSGqqj`1rKcff$OAqm_1{8JqETz>74&Q^tW zMlU#|lTgz!_+AK{KRf^tY%rvOc|k;|Ezc#xOHgH*=a;6kYcEBY7lOBVI&Rv3F;)5y zjeE@|nE(xiadHp5I{e-h#jcWSznU+*XOEVEf7;;4qzk7Prf&P-Q@=P|ukT;>9!$?* z+m33~J<($IdEp%%MNQ9>6hj%i(Eu8Sv|w{7|)G>e$_z0CD+9E%McY@1*@v-5R@W zv(&=d?6|5`c9yG?r|Ju;EA^>N96@y?wzDB;01@DTZ{Ky!yux}G0vT2YQxI~kq ozbEz|_BQ;#5B(pfz<>Mj{^Qi~cklE6M1dXv06_g;@0HO%0j{xS^8f$< literal 0 HcmV?d00001 diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 3b666fab3..9e63a753e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -27,6 +27,22 @@ impl Command for RenderHelp { _{about}_ +## 30 Second Demo + +The following shows using rtx to install node, python, and jq into a project using a `.tool-versions` file. + +[![demo](./docs/demo.gif)](./docs/demo.gif) + +## Features + +- **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. +- **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. +- **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. +- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them. +- **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. +- **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. +- **One command install** - No need to manually install each plugin, just run `rtx install --all` and it will install all the plugins you need. + ## Quickstart Install rtx (other methods [here](#installation)): From 5181a00704706e732df220c8df4e0a87cf004655 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Feb 2023 16:16:05 -0600 Subject: [PATCH 0154/1891] bug: set min term size to 40 --- src/cli/hook_env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index e290a30ec..2f8f4f9b2 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -89,7 +89,7 @@ impl HookEnv { .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { let (w, _) = term_size::dimensions_stderr().unwrap_or_default(); - let w = max(w, 80); + let w = max(w, 40); let status = installed_versions.into_iter().rev().join(" "); if status.len() > w - 5 { rtxstatusln!(out, "{}...", &status[..w - 9]) From bc4994ae6feea596a14fd38d02a0fea14c996ece Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:44:22 -0600 Subject: [PATCH 0155/1891] added some aliases to make rtx more compatible with asdf --- src/cli/ls_remote.rs | 2 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 07a6696a0..9c4449a35 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -14,7 +14,7 @@ use crate::ui::color::Color; /// note that these versions are cached for commands like `rtx install nodejs@latest` /// however _this_ command will always clear that cache and fetch the latest remote versions #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list-remote", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(visible_alias = "list-remote", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), alias = "list-all")] pub struct LsRemote { /// Plugin #[clap()] diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 0035999c1..eaaa1905d 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -12,7 +12,7 @@ use crate::shorthand::SHORTHAND_MAP; /// /// These are fetched from https://github.com/asdf-vm/asdf-plugins #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list-remote", long_about = LONG_ABOUT, verbatim_doc_comment)] +#[clap(visible_alias = "list-remote", long_about = LONG_ABOUT, verbatim_doc_comment, alias = "list-all")] pub struct PluginsLsRemote { /// show the git url for each plugin /// diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index cd069c05b..6a86ede42 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -12,7 +12,7 @@ mod uninstall; mod update; #[derive(Debug, clap::Args)] -#[clap(about = "Manage plugins", visible_alias = "p", alias = "plugin")] +#[clap(about = "Manage plugins", visible_alias = "p", aliases = ["plugin", "plugin-list"])] pub struct Plugins { #[clap(subcommand)] command: Option, From ec90f503b16e9d32c8b00a56a2b3990655b5237a Mon Sep 17 00:00:00 2001 From: Kian-Meng Ang Date: Tue, 14 Feb 2023 12:16:49 +0800 Subject: [PATCH 0156/1891] docs: fix typos (#138) Found via `codespell -S target,plugins -L crate,esy` --- CONTRIBUTING.md | 2 +- README.md | 10 +++++----- src/cli/exec.rs | 2 +- src/cli/render_help.rs | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb36fcf73..f6e3e5d4a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,7 +45,7 @@ source_up_if_exists PATH_add "$(expand_path .bin)" ``` -Now I can just run `rtx` as if I was using an installed version and it will build it from source everytime there are changes. +Now I can just run `rtx` as if I was using an installed version and it will build it from source every time there are changes. You don't have to do this, but it makes things like `rtx activate` a lot easier to setup. diff --git a/README.md b/README.md index 700b8dc15..7fc349e34 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ $ node -v v18.10.9 ``` -> **Note** +> **Note** > > `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not > already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). @@ -731,7 +731,7 @@ use this to avoid modifying the shell session or running ad-hoc commands with th set. Runtimes will be loaded from .tool-versions, though they can be overridden with args -Note that only the plugin specified will be overriden, so if a `.tool-versions` file +Note that only the plugin specified will be overridden, so if a `.tool-versions` file includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. The "--" separates runtimes from the commands to pass along to the subprocess. @@ -1268,9 +1268,9 @@ which then calls `asdf exec`, which then calls the correct version of node. These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. -I don't think it's possible for asdf to fix thse issues. The author of asdf did a great writeup +I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written -in bash which certainly makes it challening to be performant, however I think the real problem is the +in bash which certainly makes it challenging to be performant, however I think the real problem is the shim design. I don't think it's possible to fix that without a complete rewrite. rtx does call an internal command `rtx hook-env` every time the directory has changed, but because @@ -1299,7 +1299,7 @@ variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https:// ### UX Some commands are the same in asdf but others have been changed. Everything that's possible -in asdf should be possible in rtx but may use slighly different syntax. rtx has more forgiving commands, +in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, such as using fuzzy-matching, e.g.: `rtx install nodejs@18`. While in asdf you _can_ run `asdf install nodejs latest:18`, you can't use `latest:18` in a `.tool-versions` file or many other places. In `rtx` you can use fuzzy-matching everywhere. diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 419f35dc3..a707ad38e 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -23,7 +23,7 @@ use crate::ui::color::Color; /// set. /// /// Runtimes will be loaded from .tool-versions, though they can be overridden with args -/// Note that only the plugin specified will be overriden, so if a `.tool-versions` file +/// Note that only the plugin specified will be overridden, so if a `.tool-versions` file /// includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. /// /// The "--" separates runtimes from the commands to pass along to the subprocess. diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9e63a753e..e66133f22 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -77,7 +77,7 @@ $ node -v v18.10.9 ``` -> **Note** +> **Note** > > `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not > already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). @@ -566,9 +566,9 @@ which then calls `asdf exec`, which then calls the correct version of node. These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. -I don't think it's possible for asdf to fix thse issues. The author of asdf did a great writeup +I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written -in bash which certainly makes it challening to be performant, however I think the real problem is the +in bash which certainly makes it challenging to be performant, however I think the real problem is the shim design. I don't think it's possible to fix that without a complete rewrite. rtx does call an internal command `rtx hook-env` every time the directory has changed, but because @@ -597,7 +597,7 @@ variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https:// ### UX Some commands are the same in asdf but others have been changed. Everything that's possible -in asdf should be possible in rtx but may use slighly different syntax. rtx has more forgiving commands, +in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, such as using fuzzy-matching, e.g.: `rtx install nodejs@18`. While in asdf you _can_ run `asdf install nodejs latest:18`, you can't use `latest:18` in a `.tool-versions` file or many other places. In `rtx` you can use fuzzy-matching everywhere. From 93b5fadb8593b73f7eb1d8fcf8878e481ced5ebc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 15 Feb 2023 06:31:40 -0600 Subject: [PATCH 0157/1891] chore: added homebrew formula bump to release action --- .github/workflows/rtx.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index d724fa5ef..a25dab127 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -251,3 +251,8 @@ jobs: draft: false files: releases/${{github.ref_name}}/* generate_release_notes: true + - name: Update Homebrew formula + uses: dawidd6/action-homebrew-bump-formula@v3 + with: + token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + formula: rtx From 5d092d66fa2332ed8d1eb07d793319d162e90398 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 15 Feb 2023 07:11:44 -0600 Subject: [PATCH 0158/1891] chore: removed unused code --- scripts/publish-s3.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 4df0652ca..7cf7cbdcb 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -5,13 +5,6 @@ cache_hour="max-age=3600,s-maxage=3600,public,immutable" cache_day="max-age=86400,s-maxage=86400,public,immutable" cache_week="max-age=604800,s-maxage=604800,public,immutable" -platforms=( - linux-x64 - linux-arm64 - macos-x64 - macos-arm64 -) - ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh echo "$RTX_VERSION" | tr -d 'v' > "$RELEASE_DIR"/VERSION From dfa2ab65b122736909ccad9ce7facead0fbbd205 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 15 Feb 2023 07:18:47 -0600 Subject: [PATCH 0159/1891] docs: document homebrew core tap usage Fixes #88 --- README.md | 10 ++++++++++ src/cli/render_help.rs | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/README.md b/README.md index 7fc349e34..d88644a5e 100644 --- a/README.md +++ b/README.md @@ -155,10 +155,20 @@ If you need something else, compile it with [cargo](#cargo). ### Homebrew +There are 2 ways to install rtx with Homebrew. The recommended method is to use +the custom tap which will always contain the latest release. + ```sh-session $ brew install jdxcode/tap/rtx ``` +Alternatively, you can use the built-in tap (homebrew-core), which will be updated +once Homebrew maintainers merge the PR for a new release: + +```sh-session +$ brew install rtx +``` + ### Cargo Build from source with Cargo. diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e66133f22..b6f03fdbb 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -173,10 +173,20 @@ If you need something else, compile it with [cargo](#cargo). ### Homebrew +There are 2 ways to install rtx with Homebrew. The recommended method is to use +the custom tap which will always contain the latest release. + ```sh-session $ brew install jdxcode/tap/rtx ``` +Alternatively, you can use the built-in tap (homebrew-core), which will be updated +once Homebrew maintainers merge the PR for a new release: + +```sh-session +$ brew install rtx +``` + ### Cargo Build from source with Cargo. From 0553ea4a157b0f43eb73bdb5cce05122a3c3bfd8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 15 Feb 2023 21:20:28 -0600 Subject: [PATCH 0160/1891] test: simplify E2E asserts --- e2e/assert.sh | 186 ------------------------------------- e2e/test_env | 12 ++- e2e/test_local | 18 +++- e2e/test_tool_versions_alt | 14 ++- 4 files changed, 34 insertions(+), 196 deletions(-) delete mode 100644 e2e/assert.sh diff --git a/e2e/assert.sh b/e2e/assert.sh deleted file mode 100644 index ffd2b9551..000000000 --- a/e2e/assert.sh +++ /dev/null @@ -1,186 +0,0 @@ -#!/bin/bash -# assert.sh 1.1 - bash unit testing framework -# Copyright (C) 2009-2015 Robert Lehmann -# -# http://github.com/lehmannro/assert.sh -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see . - -export DISCOVERONLY=${DISCOVERONLY:-} -export DEBUG=${DEBUG:-} -export STOP=${STOP:-} -export INVARIANT=${INVARIANT:-} -export CONTINUE=${CONTINUE:-} - -args="$(getopt -n "$0" -l \ - verbose,help,stop,discover,invariant,continue vhxdic $*)" \ -|| exit -1 -for arg in $args; do - case "$arg" in - -h) - echo "$0 [-vxidc]" \ - "[--verbose] [--stop] [--invariant] [--discover] [--continue]" - echo "`sed 's/./ /g' <<< "$0"` [-h] [--help]" - exit 0;; - --help) - cat < [stdin] - (( tests_ran++ )) || : - [[ -z "$DISCOVERONLY" ]] || return - expected=$(echo -ne "${2:-}") - result="$(eval 2>/dev/null $1 <<< ${3:-})" || true - if [[ "$result" == "$expected" ]]; then - [[ -z "$DEBUG" ]] || echo -n . - return - fi - result="$(sed -e :a -e '$!N;s/\n/\\n/;ta' <<< "$result")" - [[ -z "$result" ]] && result="nothing" || result="\"$result\"" - [[ -z "$2" ]] && expected="nothing" || expected="\"$2\"" - _assert_fail "expected $expected${_indent}got $result" "$1" "$3" -} - -assert_raises() { - # assert_raises [stdin] - (( tests_ran++ )) || : - [[ -z "$DISCOVERONLY" ]] || return - status=0 - (eval $1 <<< ${3:-}) > /dev/null 2>&1 || status=$? - expected=${2:-0} - if [[ "$status" -eq "$expected" ]]; then - [[ -z "$DEBUG" ]] || echo -n . - return - fi - _assert_fail "program terminated with code $status instead of $expected" "$1" "$3" -} - -_assert_fail() { - # _assert_fail - [[ -n "$DEBUG" ]] && echo -n X - report="test #$tests_ran \"$2${3:+ <<< $3}\" failed:${_indent}$1" - if [[ -n "$STOP" ]]; then - [[ -n "$DEBUG" ]] && echo - echo "$report" - exit 1 - fi - tests_errors[$tests_failed]="$report" - (( tests_failed++ )) || : -} - -skip_if() { - # skip_if - (eval $@) > /dev/null 2>&1 && status=0 || status=$? - [[ "$status" -eq 0 ]] || return - skip -} - -skip() { - # skip (no arguments) - shopt -q extdebug && tests_extdebug=0 || tests_extdebug=1 - shopt -q -o errexit && tests_errexit=0 || tests_errexit=1 - # enable extdebug so returning 1 in a DEBUG trap handler skips next command - shopt -s extdebug - # disable errexit (set -e) so we can safely return 1 without causing exit - set +o errexit - tests_trapped=0 - trap _skip DEBUG -} -_skip() { - if [[ $tests_trapped -eq 0 ]]; then - # DEBUG trap for command we want to skip. Do not remove the handler - # yet because *after* the command we need to reset extdebug/errexit (in - # another DEBUG trap.) - tests_trapped=1 - [[ -z "$DEBUG" ]] || echo -n s - return 1 - else - trap - DEBUG - [[ $tests_extdebug -eq 0 ]] || shopt -u extdebug - [[ $tests_errexit -eq 1 ]] || set -o errexit - return 0 - fi -} - - -_assert_reset -: ${tests_suite_status:=0} # remember if any of the tests failed so far -_assert_cleanup() { - local status=$? - # modify exit code if it's not already non-zero - [[ $status -eq 0 && -z $CONTINUE ]] && exit $tests_suite_status -} -trap _assert_cleanup EXIT diff --git a/e2e/test_env b/e2e/test_env index a75aec84b..a64f053db 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -1,9 +1,15 @@ #!/usr/bin/env bash -. ./assert.sh +assert() { + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi +} rtx i nodejs@16.0.0 eval "$(rtx env -s bash nodejs@16.0.0)" assert "node -v" "v16.0.0" - -assert_end diff --git a/e2e/test_local b/e2e/test_local index 66a8d79fb..8d667a9df 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -1,6 +1,20 @@ #!/usr/bin/env bash -. ./assert.sh +assert() { + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi +} +assert_raises() { + if ! $1; then + echo "assertion failed: $1" + exit 1 + fi +} export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall @@ -36,5 +50,3 @@ rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then exit 1 fi - -assert_end diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index f1dc9cee9..e77af0864 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -1,7 +1,5 @@ #!/usr/bin/env bash -. ./assert.sh - export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions @@ -13,6 +11,16 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi +assert() { + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi +} + assert "rtx local" "shfmt 3.5.0" assert "rtx local -p shfmt@3.6.0" "shfmt 3.6.0" @@ -23,5 +31,3 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then fi assert "rtx local shfmt@3.5.0" "shfmt 3.5.0" - -assert_end From 339915e0971423ec39b8c08a8c1e1b74945841d9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 15 Feb 2023 22:52:12 -0600 Subject: [PATCH 0161/1891] docs --- README.md | 7 ++++--- src/cli/render_help.rs | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d88644a5e..5e05b2d52 100644 --- a/README.md +++ b/README.md @@ -515,8 +515,10 @@ to that to help debug issues. ### Windows support? -This is unlikely to ever happen since this leverages the vast ecosystem of asdf plugins which are built on Bash scripts. -At some point it may be worth exploring an alternate plugin format that would be Windows compatible. +This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 + +It's not a near-term goal and it would require plugin modifications, but +it should be feasible. ## Commands @@ -1377,7 +1379,6 @@ To do this, first use `rtx` to build a `use_rtx` function that you can use in `. ```sh-session $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh -# replace ~/.config with XDG_CONFIG_HOME if you've changed it ``` Now in your `.envrc` file add the following: diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index b6f03fdbb..aff0fbc1b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -533,8 +533,10 @@ to that to help debug issues. ### Windows support? -This is unlikely to ever happen since this leverages the vast ecosystem of asdf plugins which are built on Bash scripts. -At some point it may be worth exploring an alternate plugin format that would be Windows compatible. +This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 + +It's not a near-term goal and it would require plugin modifications, but +it should be feasible. ## Commands @@ -675,7 +677,6 @@ To do this, first use `rtx` to build a `use_rtx` function that you can use in `. ```sh-session $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh -# replace ~/.config with XDG_CONFIG_HOME if you've changed it ``` Now in your `.envrc` file add the following: From 92c6a8ee86503f4f768d8863481a29505a2c4c83 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Feb 2023 07:55:51 -0600 Subject: [PATCH 0162/1891] chore: create amd64 copies of x64 binaries it seems people are trying to download these --- scripts/publish-s3.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 7cf7cbdcb..e2fbd82e9 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -8,6 +8,9 @@ cache_week="max-age=604800,s-maxage=604800,public,immutable" ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh echo "$RTX_VERSION" | tr -d 'v' > "$RELEASE_DIR"/VERSION +cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-$RTX_VERSION-linux-amd64" +cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-$RTX_VERSION-macos-amd64" + aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" \ --include "rtx-latest-*" \ From 61741d7f52b52ecfebbe6f9d7653a56bc356b876 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 18 Feb 2023 21:26:04 -0600 Subject: [PATCH 0163/1891] toolset refactor (#145) --- Cargo.lock | 69 ++-- Cargo.toml | 6 +- README.md | 23 +- completions/_rtx | 83 +++- completions/rtx.bash | 370 ++++++++++++++++-- completions/rtx.fish | 45 ++- e2e/cd/test_bash | 7 +- e2e/test_local | 2 +- src/cli/args/jobs.rs | 21 + src/cli/args/mod.rs | 1 + src/cli/current.rs | 38 +- src/cli/deactivate.rs | 1 + src/cli/direnv/envrc.rs | 7 +- src/cli/direnv/exec.rs | 7 +- ...i__direnv__envrc__tests__direnv_envrc.snap | 2 +- src/cli/doctor.rs | 2 +- src/cli/env.rs | 15 +- src/cli/exec.rs | 12 +- src/cli/external.rs | 18 +- src/cli/global.rs | 21 +- src/cli/hook_env.rs | 25 +- src/cli/install.rs | 128 +++--- src/cli/latest.rs | 35 +- src/cli/local.rs | 21 +- src/cli/ls.rs | 52 +-- src/cli/ls_remote.rs | 6 +- src/cli/mod.rs | 10 +- src/cli/plugins/install.rs | 28 +- src/cli/plugins/ls.rs | 2 +- src/cli/plugins/ls_remote.rs | 5 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/plugins/update.rs | 10 +- src/cli/render_help.rs | 5 +- ...cli__settings__ls__tests__settings_ls.snap | 2 + ...i__settings__set__tests__settings_set.snap | 2 + src/cli/settings/unset.rs | 2 + ..._latest__tests__latest_missing_plugin.snap | 5 + ...tx__cli__latest__tests__latest_system.snap | 5 + src/cli/uninstall.rs | 60 +-- src/cli/where.rs | 18 +- src/config/config_file/legacy_version.rs | 31 +- src/config/config_file/mod.rs | 33 +- src/config/config_file/rtxrc.rs | 25 +- src/config/config_file/tool_versions.rs | 48 ++- src/config/mod.rs | 280 +++---------- src/config/plugin_source.rs | 26 -- src/config/settings.rs | 18 +- src/config/toolset.rs | 242 ------------ src/env.rs | 6 +- src/errors.rs | 4 +- src/fake_asdf.rs | 14 - src/file.rs | 3 +- src/git.rs | 8 + src/hook_env.rs | 2 +- src/main.rs | 2 + src/output.rs | 2 +- src/plugins/mod.rs | 198 +++++++--- src/plugins/script_manager.rs | 46 ++- src/runtimes/mod.rs | 98 ++--- src/test.rs | 2 +- src/toolset/builder.rs | 122 ++++++ src/toolset/mod.rs | 332 ++++++++++++++++ src/toolset/tool_source.rs | 25 ++ src/toolset/tool_version.rs | 126 ++++++ src/toolset/tool_version_list.rs | 38 ++ src/ui/color.rs | 28 +- src/ui/mod.rs | 3 +- src/ui/multi_progress_report.rs | 35 ++ src/ui/progress_report.rs | 70 ++++ src/ui/prompt.rs | 14 +- src/ui/spinner.rs | 29 -- test/config/config.toml | 1 + 72 files changed, 1977 insertions(+), 1107 deletions(-) create mode 100644 src/cli/args/jobs.rs create mode 100644 src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap create mode 100644 src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap delete mode 100644 src/config/plugin_source.rs delete mode 100644 src/config/toolset.rs create mode 100644 src/toolset/builder.rs create mode 100644 src/toolset/mod.rs create mode 100644 src/toolset/tool_source.rs create mode 100644 src/toolset/tool_version.rs create mode 100644 src/toolset/tool_version_list.rs create mode 100644 src/ui/multi_progress_report.rs create mode 100644 src/ui/progress_report.rs delete mode 100644 src/ui/spinner.rs diff --git a/Cargo.lock b/Cargo.lock index 04598b3cf..20eb21882 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,17 +214,6 @@ dependencies = [ "tracing-error", ] -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi", -] - [[package]] name = "console" version = "0.15.5" @@ -234,6 +223,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", + "unicode-width", "windows-sys 0.42.0", ] @@ -603,6 +593,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", +] + [[package]] name = "indoc" version = "2.0.0" @@ -812,6 +814,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.30.3" @@ -861,12 +869,6 @@ dependencies = [ "supports-color", ] -[[package]] -name = "paris" -version = "1.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eaf2319cd71dd9ff38c72bebde61b9ea657134abcf26ae4205f54f772a32810" - [[package]] name = "paste" version = "1.0.11" @@ -885,6 +887,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "portable-atomic" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" + [[package]] name = "pretty_assertions" version = "1.3.0" @@ -1040,6 +1048,7 @@ dependencies = [ "clap", "clap_complete", "color-eyre", + "console", "ctor", "dirs-next", "duct", @@ -1048,6 +1057,7 @@ dependencies = [ "filetime", "flate2", "indexmap", + "indicatif", "indoc", "insta", "itertools", @@ -1065,9 +1075,9 @@ dependencies = [ "serde_json", "shell-escape", "simplelog", - "spinoff", "tempfile", "term_size", + "test-log", "thiserror", "toml", "toml_edit", @@ -1188,22 +1198,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" dependencies = [ "log", - "paris", "termcolor", "time 0.3.17", ] -[[package]] -name = "spinoff" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee259f96b31e7a18657d11741fe30d63f98e07de70e7a19d2b705ab9b331cdc" -dependencies = [ - "colored", - "once_cell", - "paste", -] - [[package]] name = "strsim" version = "0.10.0" @@ -1264,6 +1262,17 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "test-log" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f0c854faeb68a048f0f2dc410c5ddae3bf83854ef0e4977d58306a5edef50e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thiserror" version = "1.0.38" diff --git a/Cargo.toml b/Cargo.toml index 392bc167a..8e8108a23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,12 +32,14 @@ chrono = "0.4.23" clap = { version = "4.1.1", features = ["env", "derive", "string"] } clap_complete = "4.1.1" color-eyre = "0.6.2" +console = "0.15.5" ctor = "0.1.26" dirs-next = "2.0.0" duct = "0.13.6" filetime = "0.2.19" flate2 = "1.0.25" indexmap = "1.9.2" +indicatif = "0.17.3" indoc = "2.0.0" itertools = "0.10.5" lazy_static = "1.4.0" @@ -52,8 +54,7 @@ serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.92" shell-escape = "0.1.5" -simplelog = { version = "0.12.0", features = ["paris"] } -spinoff = "0.7.0" +simplelog = { version = "0.12.0" } term_size = "0.3.2" thiserror = "1.0.38" toml = "0.7.1" @@ -69,6 +70,7 @@ env_logger = "0.10.0" insta = "1.26.0" pretty_assertions = "1.3.0" tempfile = "3.3.0" +test-log = "*" [profile.release] debug = 1 # show line numbers in backtrace diff --git a/README.md b/README.md index 5e05b2d52..eb2fb8c85 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The following shows using rtx to install node, python, and jq into a project usi - **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them. - **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. - **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. -- **One command install** - No need to manually install each plugin, just run `rtx install --all` and it will install all the plugins you need. +- **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. ## Quickstart @@ -794,8 +794,10 @@ Arguments: .tool-versions will be displayed Options: - --fuzzy - save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0` + --pin + save exact version to `.tool-versions` + + e.g.: `rtx global --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, --remove remove the plugin(s) from ~/.tool-versions @@ -842,9 +844,6 @@ Options: -f, --force force reinstall even if already installed - -a, --all - install all missing runtimes as well as all plugins for the current directory - -v, --verbose... Show installation output @@ -906,10 +905,10 @@ Options: recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") - --fuzzy - save fuzzy match to .tool-versions - e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions - without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0` + --pin + save exact version to `.tool-versions` + + e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, --remove remove the plugin(s) from .tool-versions @@ -1250,8 +1249,8 @@ Options: Print help (see a summary with '-h') Examples: - $ rtx uninstall nodejs@18 # will uninstall ALL nodejs-18.x versions - $ rtx uninstall nodejs # will uninstall ALL nodejs versions + $ rtx uninstall nodejs@18.0.0 # will uninstall specific version + $ rtx uninstall nodejs # will uninstall current nodejs version ``` ### `rtx version` diff --git a/completions/_rtx b/completions/_rtx index 1cf4f3187..c4345ed38 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -16,6 +16,8 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -36,6 +38,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-q[Hide the "rtx: @" message when changing directories]' \ '--quiet[Hide the "rtx: @" message when changing directories]' \ '*-v[Show installation output]' \ @@ -50,6 +54,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -69,6 +75,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -106,6 +114,8 @@ esac (asdf) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -118,6 +128,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -127,6 +139,8 @@ _arguments "${_arguments_options[@]}" \ (current) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -139,6 +153,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -149,6 +165,8 @@ _arguments "${_arguments_options[@]}" \ (direnv) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -166,6 +184,8 @@ _arguments "${_arguments_options[@]}" \ (envrc) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -175,6 +195,8 @@ _arguments "${_arguments_options[@]}" \ (exec) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -184,6 +206,8 @@ _arguments "${_arguments_options[@]}" \ (activate) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -229,6 +253,8 @@ esac (doctor) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -240,6 +266,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -252,6 +280,8 @@ _arguments "${_arguments_options[@]}" \ '()-c+[the command string to execute]:C: ' \ '()--command=[the command string to execute]:C: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -264,7 +294,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--fuzzy[save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0`]' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ +'--pin[save exact version to `.tool-versions`]' \ +'--fuzzy[]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -277,6 +310,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -288,6 +323,8 @@ _arguments "${_arguments_options[@]}" \ '()*-p+[only install runtime(s) for ]:PLUGIN: ' \ '()*--plugin=[only install runtime(s) for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-f[force reinstall even if already installed]' \ '--force[force reinstall even if already installed]' \ '(-p --plugin -f --force)-a[install all missing runtimes as well as all plugins for the current directory]' \ @@ -302,6 +339,8 @@ _arguments "${_arguments_options[@]}" \ (latest) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -314,13 +353,14 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from .tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-p[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--parent[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ -'--fuzzy[save fuzzy match to .tool-versions -e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions -without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0`]' \ +'--pin[save exact version to `.tool-versions`]' \ +'--fuzzy[]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -333,17 +373,22 @@ _arguments "${_arguments_options[@]}" \ '-p+[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--plugin=[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ +'::plugin_arg:' \ && ret=0 ;; (ls-remote) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -354,6 +399,8 @@ _arguments "${_arguments_options[@]}" \ (plugins) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ @@ -375,6 +422,8 @@ _arguments "${_arguments_options[@]}" \ (install) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ '(-f --force)-a[Install all missing plugins]' \ @@ -390,6 +439,8 @@ _arguments "${_arguments_options[@]}" \ (ls) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ @@ -403,6 +454,8 @@ _arguments "${_arguments_options[@]}" \ (ls-remote) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ '*-v[Show installation output]' \ @@ -414,6 +467,8 @@ _arguments "${_arguments_options[@]}" \ (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -424,6 +479,8 @@ _arguments "${_arguments_options[@]}" \ (update) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '()-a[update all plugins]' \ '()--all[update all plugins]' \ '*-v[Show installation output]' \ @@ -480,6 +537,8 @@ esac (settings) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -497,6 +556,8 @@ _arguments "${_arguments_options[@]}" \ (get) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -507,6 +568,8 @@ _arguments "${_arguments_options[@]}" \ (ls) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -516,6 +579,8 @@ _arguments "${_arguments_options[@]}" \ (set) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -527,6 +592,8 @@ _arguments "${_arguments_options[@]}" \ (unset) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -577,6 +644,8 @@ esac (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -587,6 +656,8 @@ _arguments "${_arguments_options[@]}" \ (version) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -596,6 +667,8 @@ _arguments "${_arguments_options[@]}" \ (where) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -607,6 +680,8 @@ _arguments "${_arguments_options[@]}" \ (render-help) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of parallel jobs to run]: : ' \ +'--jobs=[Number of parallel jobs to run]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index ca5beda52..3018d7ecb 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -367,7 +367,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-v -h -V --log-level --verbose --help --version activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -377,6 +377,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -385,7 +393,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -v -h --shell --quiet --log-level --verbose --help bash fish xonsh zsh" + opts="-s -q -j -v -h --shell --quiet --log-level --jobs --verbose --help bash fish xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -403,6 +411,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -411,7 +427,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -v -h --plugin --log-level --verbose --help ls help" + opts="-p -j -v -h --plugin --log-level --jobs --verbose --help ls help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -429,6 +445,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -479,7 +503,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -v -h --plugin --log-level --verbose --help" + opts="-p -j -v -h --plugin --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -497,6 +521,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -505,7 +537,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-v -h --log-level --verbose --help [ARGS]..." + opts="-j -v -h --log-level --jobs --verbose --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -515,6 +547,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -523,7 +563,7 @@ _rtx() { return 0 ;; rtx__complete) - opts="-s -v -h --shell --log-level --verbose --help" + opts="-s -j -v -h --shell --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -541,6 +581,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -549,7 +597,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-v -h --log-level --verbose --help [PLUGIN]" + opts="-j -v -h --log-level --jobs --verbose --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -559,6 +607,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -567,7 +623,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-s -v -h --shell --log-level --verbose --help bash fish xonsh zsh" + opts="-s -j -v -h --shell --log-level --jobs --verbose --help bash fish xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -585,6 +641,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -593,7 +657,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-v -h --log-level --verbose --help envrc exec activate help" + opts="-j -v -h --log-level --jobs --verbose --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -603,6 +667,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -611,7 +683,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-v -h --log-level --verbose --help" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -621,6 +693,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -629,7 +709,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-v -h --log-level --verbose --help" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -639,6 +719,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -647,7 +735,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-v -h --log-level --verbose --help" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -657,6 +745,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -735,7 +831,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-v -h --log-level --verbose --help" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -745,6 +841,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -753,7 +857,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -v -h --shell --log-level --verbose --help [RUNTIME]..." + opts="-s -j -v -h --shell --log-level --jobs --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -771,6 +875,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -779,7 +891,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -v -h --command --log-level --verbose --help [RUNTIME]... [COMMAND]..." + opts="-c -j -v -h --command --log-level --jobs --verbose --help [RUNTIME]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -797,6 +909,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -805,7 +925,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-v -h --fuzzy --remove --log-level --verbose --help [RUNTIME]..." + opts="-j -v -h --pin --fuzzy --remove --log-level --jobs --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -819,6 +939,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1359,7 +1487,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -v -h --shell --log-level --verbose --help" + opts="-s -j -v -h --shell --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1377,6 +1505,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1385,7 +1521,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-p -f -a -v -h --plugin --force --all --verbose --log-level --help [RUNTIME]..." + opts="-p -f -a -v -j -h --plugin --force --all --verbose --log-level --jobs --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1403,6 +1539,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1411,7 +1555,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-v -h --log-level --verbose --help [ASDF_VERSION]" + opts="-j -v -h --log-level --jobs --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1421,6 +1565,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1429,7 +1581,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -v -h --parent --fuzzy --remove --log-level --verbose --help [RUNTIME]..." + opts="-p -j -v -h --parent --pin --fuzzy --remove --log-level --jobs --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1443,6 +1595,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1451,7 +1611,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -v -h --plugin --current --log-level --verbose --help" + opts="-p -c -j -v -h --plugin --current --log-level --jobs --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1469,6 +1629,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1477,7 +1645,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-v -h --log-level --verbose --help " + opts="-j -v -h --log-level --jobs --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1487,6 +1655,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1495,7 +1671,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -u -v -h --all --urls --log-level --verbose --help install ls ls-remote uninstall update help" + opts="-a -u -j -v -h --all --urls --log-level --jobs --verbose --help install ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1505,6 +1681,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1611,7 +1795,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -h --force --all --verbose --log-level --help [NAME] [GIT_URL]" + opts="-f -a -v -j -h --force --all --verbose --log-level --jobs --help [NAME] [GIT_URL]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1621,6 +1805,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1629,7 +1821,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -u -v -h --all --urls --log-level --verbose --help" + opts="-a -u -j -v -h --all --urls --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1639,6 +1831,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1647,7 +1847,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -v -h --urls --log-level --verbose --help" + opts="-u -j -v -h --urls --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1657,6 +1857,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1665,7 +1873,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-v -h --log-level --verbose --help " + opts="-j -v -h --log-level --jobs --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1675,6 +1883,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1683,7 +1899,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -v -h --all --log-level --verbose --help [PLUGIN]..." + opts="-a -j -v -h --all --log-level --jobs --verbose --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1693,6 +1909,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1701,7 +1925,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-v -h --log-level --verbose --help" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1711,6 +1935,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1719,7 +1951,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-v -h --log-level --verbose --help get ls set unset help" + opts="-j -v -h --log-level --jobs --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1729,6 +1961,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1737,7 +1977,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-v -h --log-level --verbose --help " + opts="-j -v -h --log-level --jobs --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1747,6 +1987,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1839,7 +2087,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-v -h --log-level --verbose --help" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1849,6 +2097,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1857,7 +2113,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-v -h --log-level --verbose --help " + opts="-j -v -h --log-level --jobs --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1867,6 +2123,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1875,7 +2139,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-v -h --log-level --verbose --help " + opts="-j -v -h --log-level --jobs --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1885,6 +2149,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1893,7 +2165,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-v -h --log-level --verbose --help ..." + opts="-j -v -h --log-level --jobs --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1903,6 +2175,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1911,7 +2191,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-v -h --log-level --verbose --help" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1921,6 +2201,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1929,7 +2217,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-v -h --log-level --verbose --help [ASDF_VERSION]" + opts="-j -v -h --log-level --jobs --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1939,6 +2227,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; diff --git a/completions/rtx.fish b/completions/rtx.fish index 878e19326..2b7631ee4 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,4 +1,5 @@ complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' @@ -28,11 +29,13 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal comm complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'Hide the "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -41,6 +44,7 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -48,20 +52,25 @@ Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -71,12 +80,15 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -86,52 +98,63 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'the command string to execute' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'save fuzzy match to .tool-versions e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, by default, it would save the exact version, e.g.: `nodejs 20.0.0`' +complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'save exact version to `.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'install all missing runtimes as well as all plugins for the current directory' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'save fuzzy match to .tool-versions -e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions -without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0`' +complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'save exact version to `.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -143,23 +166,28 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' @@ -170,6 +198,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -178,15 +207,19 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -195,15 +228,19 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of parallel jobs to run' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 556c394f8..eb2b5d19c 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -4,7 +4,6 @@ set -euo pipefail orig_path="$PATH" -rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 eval "$(rtx activate bash)" _rtx_hook @@ -21,12 +20,12 @@ assert_path() { } test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin" cd 16 && _rtx_hook test "$(node -v)" = "v16.0.0" -assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin" cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin" diff --git a/e2e/test_local b/e2e/test_local index 8d667a9df..2be6fc516 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -18,7 +18,7 @@ assert_raises() { export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall -assert_raises "rtx uninstall shfmt@3.6.0 shfmt@3.5.0" +assert_raises "rtx uninstall shfmt@3.6.0" assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 diff --git a/src/cli/args/jobs.rs b/src/cli/args/jobs.rs new file mode 100644 index 000000000..6fdb94317 --- /dev/null +++ b/src/cli/args/jobs.rs @@ -0,0 +1,21 @@ +use clap::builder::ValueParser; +use clap::Arg; +use std::num::ParseIntError; + +#[derive(Clone)] +pub struct Jobs(pub usize); + +fn parse_jobs(input: &str) -> Result { + input.parse::() +} + +impl Jobs { + pub fn arg() -> clap::Arg { + Arg::new("jobs") + .short('j') + .long("jobs") + .help("Number of parallel jobs to run") + .value_parser(ValueParser::new(parse_jobs)) + .global(true) + } +} diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index 4c84098b1..f1776aba3 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,3 +1,4 @@ +pub mod jobs; pub mod log_level; pub mod runtime; pub mod verbose; diff --git a/src/cli/current.rs b/src/cli/current.rs index a4b26f421..83c7d9b56 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -2,12 +2,13 @@ use atty::Stream; use color_eyre::eyre::Result; use indoc::formatdoc; use once_cell::sync::Lazy; -use std::sync::Arc; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; +use crate::toolset::{Toolset, ToolsetBuilder}; + use crate::ui::color::Color; /// Shows currently active, and installed runtime versions @@ -27,27 +28,27 @@ pub struct Current { impl Command for Current { fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config); match &self.plugin { - Some(plugin_name) => match config.ts.find_plugin(plugin_name) { - Some(plugin) => self.one(&config, out, plugin), + Some(plugin_name) => match config.plugins.get(plugin_name) { + Some(plugin) => self.one(ts, out, plugin), None => { warn!("Plugin {} is not installed", plugin_name); Ok(()) } }, - None => self.all(&config, out), + None => self.all(ts, out), } } } impl Current { - fn one(&self, config: &Config, out: &mut Output, plugin: Arc) -> Result<()> { + fn one(&self, ts: Toolset, out: &mut Output, plugin: &Plugin) -> Result<()> { if !plugin.is_installed() { warn!("Plugin {} is not installed", plugin.name); return Ok(()); } - let versions = config.ts.list_current_versions_by_plugin(); - match versions.get(&plugin.name) { + match ts.list_versions_by_plugin().get(&plugin.name) { Some(versions) => { rtxprintln!( out, @@ -66,11 +67,14 @@ impl Current { Ok(()) } - fn all(&self, config: &Config, out: &mut Output) -> Result<()> { - for (plugin, versions) in config.ts.list_current_versions_by_plugin() { + fn all(&self, ts: Toolset, out: &mut Output) -> Result<()> { + for (plugin, versions) in ts.list_versions_by_plugin() { + if versions.is_empty() { + continue; + } for rtv in &versions { if !rtv.is_installed() { - let source = config.ts.get_source_for_plugin(&rtv.plugin.name).unwrap(); + let source = ts.versions.get(&rtv.plugin.name).unwrap().source.clone(); warn!( "{}@{} is specified in {}, but not installed", &rtv.plugin.name, &rtv.version, &source @@ -115,6 +119,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { use insta::assert_snapshot; + use pretty_assertions::assert_str_eq; + use std::env; use crate::assert_cli; use crate::cli::tests::grep; @@ -134,4 +140,16 @@ mod tests { 3.5.1 "###); } + + #[test] + fn test_current_missing() { + assert_cli!("uninstall", "dummy@1.0.1"); + env::set_var("RTX_DUMMY_VERSION", "1.0.1"); + let stdout = assert_cli!("current"); + assert_str_eq!(grep(stdout, "dummy"), ""); + env::set_var("RTX_DUMMY_VERSION", "1.1.0"); + let stdout = assert_cli!("current"); + assert_str_eq!(grep(stdout, "dummy"), "dummy 1.1.0"); + env::remove_var("RTX_DUMMY_VERSION"); + } } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index d0aa7337e..be43171bb 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -28,6 +28,7 @@ impl Command for Deactivate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { let shell = get_shell(self.shell_type.or(self.shell)); + // TODO: clear env using __RTX_DIFF let output = shell.deactivate(); out.stdout.write(output); diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 5f93813ee..d0b99e0f2 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -9,6 +9,7 @@ use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::hash::hash_to_str; use crate::output::Output; +use crate::toolset::ToolsetBuilder; use crate::{dirs, env}; /// [internal] This is an internal command that writes an envrc file @@ -22,7 +23,7 @@ impl Command for Envrc { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } - config.ensure_installed()?; + let ts = ToolsetBuilder::new().with_install_missing().build(&config); let envrc_path = env::RTX_TMP_DIR .join("direnv") .join(hash_to_str(dirs::CURRENT.deref()) + ".envrc"); @@ -38,7 +39,7 @@ impl Command for Envrc { for cf in &config.config_files { writeln!(file, "watch_file {}", cf.to_string_lossy())?; } - for (k, v) in config.env()? { + for (k, v) in ts.env() { writeln!( file, "export {}={}", @@ -46,7 +47,7 @@ impl Command for Envrc { shell_escape::unix::escape(v.into()), )?; } - for path in &config.list_paths()? { + for path in ts.list_paths().into_iter().rev() { writeln!(file, "PATH_add {}", path.to_string_lossy())?; } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 576535573..e09224a07 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -6,6 +6,7 @@ use crate::cmd; use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::output::Output; +use crate::toolset::ToolsetBuilder; /// [internal] This is an internal command that writes an envrc file /// for direnv to consume. @@ -24,17 +25,17 @@ impl Command for DirenvExec { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } - config.ensure_installed()?; + let ts = ToolsetBuilder::new().with_install_missing().build(&config); let mut cmd = if cfg!(test) { cmd!("env") } else { cmd!("direnv", "dump") }; - for (k, v) in config.env()? { + for (k, v) in ts.env() { cmd = cmd.env(k, v); } - cmd = cmd.env("PATH", config.path_env()?); + cmd = cmd.env("PATH", ts.path_env()); let json = cmd!("direnv", "watch", "json", ".tool-versions").read()?; let w: DirenvWatches = serde_json::from_str(&json)?; diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index 637abd0b3..0396da070 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -7,8 +7,8 @@ watch_file ~/cwd/.tool-versions watch_file ~/cwd/.node-version watch_file ~/.tool-versions export JDXCODE_TINY=2.1.0 -PATH_add ~/data/installs/shfmt/3.5.1/bin PATH_add ~/data/installs/jq/1.6/bin PATH_add ~/data/installs/tiny/2.1.0/bin PATH_add ~/data/installs/shellcheck/0.9.0/bin +PATH_add ~/data/installs/shfmt/3.5.1/bin diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 17b77f9aa..709ba6f4e 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -17,7 +17,7 @@ pub struct Doctor {} impl Command for Doctor { fn run(self, config: Config, _out: &mut Output) -> Result<()> { let mut checks = Vec::new(); - for plugin in config.ts.list_plugins() { + for plugin in config.plugins.values() { if !plugin.is_installed() { checks.push(format!("plugin {} is not installed", plugin.name)); continue; diff --git a/src/cli/env.rs b/src/cli/env.rs index f55bf4f18..03544daca 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -8,6 +8,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; +use crate::toolset::ToolsetBuilder; use crate::ui::color::Color; /// exports env vars to activate rtx in a single shell session @@ -31,20 +32,18 @@ pub struct Env { impl Command for Env { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let config = config.with_runtime_args(&self.runtime)?; - config.ensure_installed()?; + let ts = ToolsetBuilder::new() + .with_install_missing() + .with_args(&self.runtime) + .build(&config); let shell = get_shell(self.shell); - for (k, v) in config.env()? { + for (k, v) in ts.env() { let k = k.to_string(); let v = v.to_string(); rtxprint!(out, "{}", shell.set_env(&k, &v)); } - rtxprintln!( - out, - "{}", - shell.set_env("PATH", config.path_env()?.as_ref()) - ); + rtxprintln!(out, "{}", shell.set_env("PATH", ts.path_env().as_ref())); Ok(()) } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index a707ad38e..6cdaf1b5c 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -15,6 +15,7 @@ use crate::cmd; use crate::config::Config; use crate::env; use crate::output::Output; +use crate::toolset::ToolsetBuilder; use crate::ui::color::Color; /// execute a command with runtime(s) set @@ -47,12 +48,14 @@ pub struct Exec { impl Command for Exec { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let config = config.with_runtime_args(&self.runtime)?; - config.ensure_installed()?; + let ts = ToolsetBuilder::new() + .with_args(&self.runtime) + .with_install_missing() + .build(&config); let (program, args) = parse_command(&env::SHELL, self.command, self.c); - let mut env = config.env()?; - env.insert("PATH".into(), config.path_env()?); + let mut env = ts.env(); + env.insert("PATH".into(), ts.path_env()); exec(program, args, env) } @@ -125,6 +128,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use crate::assert_cli; use crate::cli::tests::cli_run; + use test_log::test; #[test] fn test_exec_ok() { diff --git a/src/cli/external.rs b/src/cli/external.rs index 634abfe81..48013a76a 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -1,13 +1,15 @@ use clap::{ArgMatches, Command}; use color_eyre::eyre::Result; +use itertools::Itertools; use rayon::prelude::*; use crate::config::Config; -pub fn commands(config: &Config) -> Result> { +pub fn commands(config: &Config) -> Result> { let commands = config - .ts - .list_plugins() + .plugins + .values() + .collect_vec() .into_par_iter() .map(|p| p.external_commands()) .collect::>>>>()? @@ -17,8 +19,12 @@ pub fn commands(config: &Config) -> Result> { .map(|commands| { clap::Command::new(commands[0][0].to_string()).subcommands(commands.into_iter().map( |cmd| { - clap::Command::new(cmd[1..].join("-")) - .arg(clap::Arg::new("args").num_args(1..).trailing_var_arg(true)) + clap::Command::new(cmd[1..].join("-")).arg( + clap::Arg::new("args") + .num_args(1..) + .allow_hyphen_values(true) + .trailing_var_arg(true), + ) }, )) }) @@ -35,7 +41,7 @@ pub fn execute( ) -> Result<()> { if let Some(_cmd) = external_commands.iter().find(|c| c.get_name() == plugin) { if let Some((subcommand, matches)) = args.subcommand() { - let plugin = config.ts.find_plugin(&plugin.to_string()).unwrap(); + let plugin = config.plugins.get(&plugin.to_string()).unwrap(); let args: Vec = matches .get_raw("args") .unwrap_or_default() diff --git a/src/cli/global.rs b/src/cli/global.rs index c0844dbfc..17de92d8e 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -27,10 +27,13 @@ pub struct Global { #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, - /// save fuzzy match to .tool-versions - /// e.g.: `rtx global --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions, - /// by default, it would save the exact version, e.g.: `nodejs 20.0.0` - #[clap(long)] + /// save exact version to `.tool-versions` + /// + /// e.g.: `rtx global --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, + #[clap(long, verbatim_doc_comment)] + pin: bool, + + #[clap(long, hide = true)] fuzzy: bool, /// remove the plugin(s) from ~/.tool-versions @@ -39,7 +42,7 @@ pub struct Global { } impl Command for Global { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { let cf_path = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); let mut cf = match cf_path.exists() { @@ -57,7 +60,7 @@ impl Command for Global { if cf.display_runtime(out, &runtimes)? { return Ok(()); } - cf.add_runtimes(&mut config, &runtimes, self.fuzzy)?; + cf.add_runtimes(&config, &runtimes, self.pin)?; } if self.runtime.is_some() || self.remove.is_some() { @@ -104,13 +107,13 @@ mod tests { let _ = fs::remove_file(&cf_path); assert_cli!("install", "shfmt@2"); - let stdout = assert_cli!("global", "shfmt@2"); + let stdout = assert_cli!("global", "--pin", "shfmt@2"); assert_snapshot!(stdout); - let stdout = assert_cli!("global", "--fuzzy", "shfmt@2"); + let stdout = assert_cli!("global", "shfmt@2"); assert_snapshot!(stdout); let stdout = assert_cli!("global", "--remove", "nodejs"); assert_snapshot!(stdout); - let stdout = assert_cli!("global", "tiny", "2"); + let stdout = assert_cli!("global", "--pin", "tiny", "2"); assert_snapshot!(stdout); // will output the current version(s) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 2f8f4f9b2..63238757f 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -4,6 +4,7 @@ use std::ops::Deref; use std::path::PathBuf; use color_eyre::eyre::Result; +use console::truncate_str; use itertools::Itertools; use crate::cli::command::Command; @@ -14,6 +15,7 @@ use crate::env::__RTX_DIFF; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::output::Output; use crate::shell::{get_shell, ShellType}; +use crate::toolset::{Toolset, ToolsetBuilder}; use crate::{env, hook_env}; /// [internal] called by activate hook to update env vars directory change @@ -30,14 +32,14 @@ impl Command for HookEnv { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } - config.ensure_installed()?; + let ts = ToolsetBuilder::new().with_install_missing().build(&config); self.clear_old_env(out); - let env = config.env()?; + let env = ts.env(); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); - let installs = config.list_paths()?; // load the active runtime paths + let installs = ts.list_paths(); // load the active runtime paths diff.path = installs.clone(); // update __RTX_DIFF with the new paths for the next run patches.extend(self.build_path_operations(&installs, &__RTX_DIFF.path)?); @@ -46,7 +48,7 @@ impl Command for HookEnv { let output = self.build_env_commands(&patches); out.stdout.write(output); - self.display_status(&config, out); + self.display_status(&ts, out); Ok(()) } @@ -80,22 +82,17 @@ impl HookEnv { out.stdout.write(output); } - fn display_status(&self, config: &Config, out: &mut Output) { - let installed_versions = config - .ts + fn display_status(&self, ts: &Toolset, out: &mut Output) { + let installed_versions = ts .list_current_installed_versions() .into_iter() .map(|v| v.to_string()) .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { - let (w, _) = term_size::dimensions_stderr().unwrap_or_default(); - let w = max(w, 40); + let (mut w, _) = term_size::dimensions_stderr().unwrap_or((80, 80)); + w = max(w, 40); let status = installed_versions.into_iter().rev().join(" "); - if status.len() > w - 5 { - rtxstatusln!(out, "{}...", &status[..w - 9]) - } else { - rtxstatusln!(out, "{}", status) - }; + rtxstatusln!(out, "{}", truncate_str(&status, w - 4, "...")); } } diff --git a/src/cli/install.rs b/src/cli/install.rs index 2f206ebf6..e8cbf25ab 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,8 +1,8 @@ -use atty::Stream::Stderr; use color_eyre::eyre::Result; use indoc::formatdoc; use once_cell::sync::Lazy; use owo_colors::Stream; +use std::collections::HashSet; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -10,10 +10,11 @@ use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::InstallType::Version; -use crate::plugins::{Plugin, PluginName}; -use crate::runtimes::RuntimeVersion; -use crate::ui::color::{cyan, Color}; + +use crate::plugins::PluginName; + +use crate::toolset::ToolsetBuilder; +use crate::ui::color::Color; /// install a runtime /// @@ -39,7 +40,9 @@ pub struct Install { force: bool, /// install all missing runtimes as well as all plugins for the current directory - #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"])] + /// + /// this is hidden because it's now the default behavior + #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"], hide = true)] all: bool, /// Show installation output @@ -48,10 +51,12 @@ pub struct Install { } impl Command for Install { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + config.settings.missing_runtime_behavior = AutoInstall; + match &self.runtime { - Some(runtime) => self.install_runtimes(config, out, runtime)?, - None => self.install_missing_runtimes(config, out)?, + Some(runtime) => self.install_runtimes(&config, runtime)?, + None => self.install_missing_runtimes(&config)?, } Ok(()) @@ -59,96 +64,53 @@ impl Command for Install { } impl Install { - fn install_runtimes( - &self, - mut config: Config, - out: &mut Output, - runtimes: &[RuntimeArg], - ) -> Result<()> { - config.settings.missing_runtime_behavior = AutoInstall; - - for r in RuntimeArg::double_runtime_condition(runtimes) { - let resolved_version = config.resolve_runtime_arg(&r)?; - let plugin = config.ts.find_plugin(&r.plugin).unwrap(); - if let Some(resolved_version) = resolved_version { - let rtv = RuntimeVersion::new(plugin, &resolved_version); - - if rtv.is_installed() && self.force { - rtv.uninstall()?; - } else if rtv.is_installed() { - warn!( - "{} is already installed", - cyan(Stream::Stderr, &rtv.to_string()) - ); - continue; + fn install_runtimes(&self, config: &Config, runtimes: &[RuntimeArg]) -> Result<()> { + let runtimes = RuntimeArg::double_runtime_condition(runtimes); + let mut ts = ToolsetBuilder::new().with_args(&runtimes).build(config); + let plugins_to_install = runtimes.iter().map(|r| &r.plugin).collect::>(); + for plugin in ts.versions.clone().keys() { + if !plugins_to_install.contains(plugin) { + ts.versions.remove(plugin); + } + } + for (plugin, versions) in &ts.versions { + if plugins_to_install.contains(plugin) && self.force { + for v in &versions.versions { + if let Some(rtv) = &v.rtv { + if rtv.is_installed() { + info!("uninstalling {}", rtv); + rtv.uninstall()?; + } + } } - - self.do_install(&config, out, &rtv)?; } } + ts.install_missing(config)?; Ok(()) } - fn install_missing_runtimes(&self, mut config: Config, out: &mut Output) -> Result<()> { - for rtv in config.ts.list_current_versions() { - let plugins = match self.all { - true => Some(get_all_plugin_names(&config)), - false => self.plugin.clone(), - }; - if let Some(plugins) = &plugins { - // they've specified --all or --plugin, so we already know they want to install - config.settings.missing_runtime_behavior = AutoInstall; - if !plugins.contains(&rtv.plugin.name) { - continue; + fn install_missing_runtimes(&self, config: &Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().build(config); + if let Some(plugins) = &self.plugin { + let plugins = plugins.iter().collect::>(); + for plugin in ts.versions.keys().cloned().collect::>() { + if !plugins.contains(&plugin) { + ts.versions.remove(&plugin); } - // ensure plugin is installed only if explicitly called with --plugin or using --all - if !rtv.plugin.ensure_installed(&config.settings)? { - Err(PluginNotInstalled(rtv.plugin.name.to_string()))?; - } - } - - if !rtv.plugin.is_installed() { - warn_plugin_not_installed(&rtv.plugin); - continue; } - if rtv.version == "system" || rtv.is_installed() { - continue; + for plugin in plugins { + if !ts.versions.contains_key(plugin) { + Err(PluginNotInstalled(plugin.to_string()))?; + } } - let version = rtv - .plugin - .latest_version(&rtv.version)? - .unwrap_or_else(|| rtv.version.clone()); - // need to re-create the rtv because the version may have changed - let rtv = RuntimeVersion::new(rtv.plugin.clone(), &version); - self.do_install(&config, out, &rtv)?; } - Ok(()) - } + ts.install_missing(config)?; - fn do_install(&self, config: &Config, _out: &mut Output, rtv: &RuntimeVersion) -> Result<()> { - rtv.install(Version, config)?; Ok(()) } } -fn warn_plugin_not_installed(plugin: &Plugin) { - warn!( - "plugin {} is not installed. Install it with `rtx plugin add {}`", - cyan(Stderr, &plugin.name), - plugin.name, - ); -} - -fn get_all_plugin_names(config: &Config) -> Vec { - config - .ts - .list_plugins() - .into_iter() - .map(|p| p.name.clone()) - .collect() -} - static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" diff --git a/src/cli/latest.rs b/src/cli/latest.rs index c2313a6f6..48c8a2e81 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,5 +1,6 @@ use atty::Stream; use color_eyre::eyre::{eyre, Result}; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,7 +8,7 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion} use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; + use crate::ui::color::Color; /// get the latest runtime version of a plugin's runtimes @@ -33,12 +34,22 @@ impl Command for Latest { None => "latest".to_string(), }, RuntimeArgVersion::Version(version) => version, - _ => Err(eyre!("invalid version {}", self.runtime))?, + _ => Err(eyre!( + "invalid version: {}", + style(&self.runtime).cyan().for_stderr() + ))?, }; - let plugin = Plugin::load_ensure_installed(&self.runtime.plugin, &config.settings)?; - let prefix = config.resolve_alias(&self.runtime.plugin, prefix); + let plugin = config.plugins.get(&self.runtime.plugin).ok_or_else(|| { + eyre!( + "plugin {} not found. run {} to install it", + style(self.runtime.plugin.to_string()).cyan().for_stderr(), + style(format!("rtx plugin install {}", self.runtime.plugin)) + .yellow() + .for_stderr() + ) + })?; - if let Some(version) = plugin.latest_version(&prefix)? { + if let Some(version) = plugin.latest_version(&prefix) { rtxprintln!(out, "{}", version); } Ok(()) @@ -61,7 +72,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use insta::assert_display_snapshot; - use crate::assert_cli; + use crate::{assert_cli, assert_cli_err}; #[test] fn test_latest() { @@ -82,4 +93,16 @@ mod tests { let stdout = assert_cli!("latest", "nodejs", "12"); assert_display_snapshot!(stdout); } + + #[test] + fn test_latest_system() { + let stdout = assert_cli_err!("latest", "nodejs@system"); + assert_display_snapshot!(stdout); + } + + #[test] + fn test_latest_missing_plugin() { + let stdout = assert_cli_err!("latest", "invalid_plugin"); + assert_display_snapshot!(stdout); + } } diff --git a/src/cli/local.rs b/src/cli/local.rs index a9e7ee747..8790cf6fd 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -33,10 +33,13 @@ pub struct Local { #[clap(short, long, verbatim_doc_comment)] parent: bool, - /// save fuzzy match to .tool-versions - /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions - /// without --fuzzy, it would save the exact version, e.g.: `nodejs 20.0.0` + /// save exact version to `.tool-versions` + /// + /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, #[clap(long, verbatim_doc_comment)] + pin: bool, + + #[clap(long, hide = true)] fuzzy: bool, /// remove the plugin(s) from .tool-versions @@ -45,7 +48,7 @@ pub struct Local { } impl Command for Local { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { let cf_path = match self.parent { true => file::find_up( &dirs::CURRENT, @@ -76,7 +79,7 @@ impl Command for Local { if cf.display_runtime(out, &runtimes)? { return Ok(()); } - cf.add_runtimes(&mut config, &runtimes, self.fuzzy)?; + cf.add_runtimes(&config, &runtimes, self.pin)?; } if self.runtime.is_some() || self.remove.is_some() { @@ -130,9 +133,9 @@ mod tests { assert_cli!("plugin", "add", "nodejs"); assert_cli!("install", "shfmt@2"); - let stdout = assert_cli!("local", "shfmt@2"); + let stdout = assert_cli!("local", "--pin", "shfmt@2"); assert_snapshot!(stdout); - let stdout = assert_cli!("local", "--fuzzy", "shfmt@2"); + let stdout = assert_cli!("local", "shfmt@2"); assert_snapshot!(stdout); let stdout = assert_cli!("local", "--remove", "nodejs"); assert_snapshot!(stdout); @@ -141,9 +144,9 @@ mod tests { grep(stdout, "nodejs"), " nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)" ); - let stdout = assert_cli!("local", "tiny@1"); + let stdout = assert_cli!("local", "--pin", "tiny@1"); assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); - let stdout = assert_cli!("local", "tiny", "2"); + let stdout = assert_cli!("local", "--pin", "tiny", "2"); assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); // will output the current version(s) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 7d44136fe..3f2d2b75b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -1,21 +1,20 @@ -use atty::Stream::Stdout; use std::cmp::max; use std::collections::HashMap; -use std::sync::Arc; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use itertools::Itertools; use once_cell::sync::Lazy; -use owo_colors::{OwoColorize, Stream}; +use owo_colors::OwoColorize; use versions::Versioning; use crate::cli::command::Command; -use crate::config::{Config, PluginSource}; +use crate::config::Config; use crate::output::Output; use crate::plugins::PluginName; use crate::runtimes::RuntimeVersion; -use crate::ui::color::{cyan, dimmed, green, red, Color}; +use crate::toolset::{ToolSource, ToolsetBuilder}; /// list installed runtime versions /// @@ -28,6 +27,9 @@ pub struct Ls { #[clap(long, short)] plugin: Option, + #[clap(hide = true)] + plugin_arg: Option, + /// Only show runtimes currently specified in .tool-versions #[clap(long, short)] current: bool, @@ -35,7 +37,8 @@ pub struct Ls { impl Command for Ls { fn run(self, config: Config, out: &mut Output) -> Result<()> { - for (rtv, source) in get_runtime_list(&config, &self.plugin)? { + let plugin = self.plugin.or(self.plugin_arg); + for (rtv, source) in get_runtime_list(&config, &plugin)? { if self.current && source.is_none() { continue; } @@ -60,14 +63,12 @@ impl Command for Ls { fn styled_version(rtv: &RuntimeVersion, missing: bool, active: bool) -> String { let styled = if missing { - rtv.version - .if_supports_color(Stream::Stdout, |t| t.strikethrough().red().to_string()) - .to_string() - + red(Stdout, " (missing)").as_str() + style(&rtv.version).strikethrough().red().to_string() + + style(" (missing)").red().to_string().as_str() } else if active { - green(Stdout, &rtv.version) + style(&rtv.version).green().to_string() } else { - dimmed(Stdout, &rtv.version) + style(&rtv.version).dim().to_string() }; let unstyled = if missing { format!("{} {} (missing)", &rtv.plugin.name, &rtv.version) @@ -78,7 +79,7 @@ fn styled_version(rtv: &RuntimeVersion, missing: bool, active: bool) -> String { let pad = max(0, 25 - unstyled.len() as isize) as usize; format!( "{} {}{}", - cyan(Stdout, &rtv.plugin.name), + style(&rtv.plugin.name).cyan(), styled, " ".repeat(pad) ) @@ -87,10 +88,10 @@ fn styled_version(rtv: &RuntimeVersion, missing: bool, active: bool) -> String { fn get_runtime_list( config: &Config, plugin_flag: &Option, -) -> Result, Option)>> { - let mut versions: HashMap<(PluginName, String), Arc> = config - .ts - .list_installed_versions() +) -> Result)>> { + let ts = ToolsetBuilder::new().build(config); + let mut versions: HashMap<(PluginName, String), RuntimeVersion> = ts + .list_installed_versions()? .into_iter() .filter(|rtv| match plugin_flag { Some(plugin) => rtv.plugin.name == *plugin, @@ -99,12 +100,11 @@ fn get_runtime_list( .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv)) .collect(); - let active = config - .ts + let active = ts .list_current_versions() .into_iter() .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv.clone())) - .collect::>>(); + .collect::>(); versions.extend( active @@ -114,17 +114,20 @@ fn get_runtime_list( Some(plugin) => plugin_name == plugin, None => true, }) - .collect::)>>(), + .collect::>(), ); - let rvs: Vec<(Arc, Option)> = versions + let rvs: Vec<(RuntimeVersion, Option)> = versions .into_iter() .sorted_by_cached_key(|((plugin_name, version), _)| { (plugin_name.clone(), Versioning::new(version)) }) .map(|(k, rtv)| { let source = match &active.get(&k) { - Some(rtv) => config.ts.get_source_for_plugin(&rtv.plugin.name), + Some(rtv) => ts + .versions + .get(&rtv.plugin.name) + .map(|tv| tv.source.clone()), None => None, }; (rtv, source) @@ -134,7 +137,6 @@ fn get_runtime_list( Ok(rvs) } -static COLOR: Lazy = Lazy::new(|| Color::new(Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -146,7 +148,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx list --current -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 9c4449a35..ed17fbaa8 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -24,10 +24,10 @@ pub struct LsRemote { impl Command for LsRemote { fn run(self, config: Config, out: &mut Output) -> Result<()> { let plugin = config - .ts - .find_plugin(&self.plugin) + .plugins + .get(&self.plugin) .ok_or(PluginNotInstalled(self.plugin))?; - let versions = plugin.list_remote_versions()?; + let versions = plugin.list_remote_versions(&config.settings)?; for version in versions { rtxprintln!(out, "{}", version); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 481c2d9a5..cbdaf507c 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -132,6 +132,7 @@ impl Cli { .subcommand_required(true) .after_help(AFTER_HELP.as_str()) .arg(args::log_level::LogLevel::arg()) + .arg(args::jobs::Jobs::arg()) .arg(args::verbose::Verbose::arg()), ) } @@ -149,6 +150,12 @@ impl Cli { return version::Version {}.run(config, out); } let matches = self.command.get_matches_from(args); + if let Some(log_level) = matches.get_one::("log-level") { + config.settings.log_level = *log_level; + } + if let Some(jobs) = matches.get_one::("jobs") { + config.settings.jobs = *jobs; + } if *matches.get_one::("verbose").unwrap() > 0 { config.settings.verbose = true; } @@ -211,7 +218,8 @@ pub mod tests { macro_rules! assert_cli { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::tests::cli_run(args).unwrap().stdout.content + let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; + console::strip_ansi_codes(&output).to_string() }}; } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 6227483d0..14d2ee177 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use atty::Stream; use color_eyre::eyre::{eyre, Result}; use indoc::formatdoc; @@ -11,7 +9,9 @@ use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; use crate::shorthand::shorthand_to_repository; +use crate::toolset::ToolsetBuilder; use crate::ui::color::Color; +use crate::ui::progress_report::ProgressReport; /// install a plugin /// @@ -56,14 +56,15 @@ impl Command for PluginsInstall { return self.install_all_missing_plugins(&config); } let (name, git_url) = get_name_and_url(self.name.unwrap(), self.git_url)?; - let plugin = Plugin::load(&name)?; + let mut plugin = Plugin::load(&name, &config.settings)?; if self.force { plugin.uninstall()?; } if !self.force && plugin.is_installed() { warn!("plugin {} already installed", name); } else { - plugin.install(&config.settings, &git_url)?; + let pr = ProgressReport::new(config.settings.verbose); + plugin.install(&config.settings, Some(&git_url), pr)?; } Ok(()) @@ -72,25 +73,22 @@ impl Command for PluginsInstall { impl PluginsInstall { fn install_all_missing_plugins(&self, config: &Config) -> Result<()> { - let missing_plugins = self.missing_plugins(config)?; + let ts = ToolsetBuilder::new().build(config); + let missing_plugins = ts.list_missing_plugins(); if missing_plugins.is_empty() { warn!("all plugins already installed"); } for plugin in missing_plugins { + let mut plugin = Plugin::new(&plugin); let (_, git_url) = get_name_and_url(plugin.name.clone(), None)?; - plugin.install(&config.settings, &git_url)?; + plugin.install( + &config.settings, + Some(&git_url), + ProgressReport::new(config.settings.verbose), + )?; } Ok(()) } - - fn missing_plugins(&self, config: &Config) -> Result>> { - Ok(config - .ts - .list_plugins() - .into_iter() - .filter(|p| !p.is_installed()) - .collect::>()) - } } fn get_name_and_url(name: String, git_url: Option) -> Result<(String, String)> { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index ef864ad6f..199f6f9d1 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -34,7 +34,7 @@ impl Command for PluginsLs { return PluginsLsRemote { urls: self.urls }.run(config, out); } - for plugin in config.ts.list_installed_plugins() { + for plugin in config.plugins.values() { if self.urls { if let Some(url) = plugin.get_remote_url() { rtxprintln!(out, "{:29} {}", plugin.name, url); diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index eaaa1905d..f8030ab58 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -24,9 +24,8 @@ pub struct PluginsLsRemote { impl Command for PluginsLsRemote { fn run(self, config: Config, out: &mut Output) -> Result<()> { let installed_plugins = config - .ts - .list_plugins() - .into_iter() + .plugins + .values() .filter(|p| p.is_installed()) .map(|p| p.name.clone()) .collect::>(); diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index c60a25b99..ed846ae3c 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -19,7 +19,7 @@ pub struct PluginsUninstall { impl Command for PluginsUninstall { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugin = config.ts.find_plugin(&self.plugin); + let plugin = config.plugins.get(&self.plugin); match plugin { Some(plugin) if plugin.is_installed() => { rtxprintln!( diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 18e894fd6..add17bcd1 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use color_eyre::eyre::{eyre, Result}; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -28,16 +26,16 @@ pub struct Update { impl Command for Update { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugins: Vec> = match (self.plugin, self.all) { + let plugins: Vec<&Plugin> = match (self.plugin, self.all) { (Some(plugins), _) => plugins .into_iter() .map(|p| { - config.ts.find_plugin(&p).ok_or_else(|| { + config.plugins.get(&p).ok_or_else(|| { eyre!("plugin {} not found", cyan(Stream::Stderr, p.as_str())) }) }) - .collect::>>>()?, - (_, true) => config.ts.list_installed_plugins(), + .collect::>()?, + (_, true) => config.plugins.values().collect(), _ => Err(eyre!("no plugins specified"))?, }; diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index aff0fbc1b..2e617ce42 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Result; +use console::strip_ansi_codes; use indoc::formatdoc; use crate::cli::command::Command; @@ -41,7 +42,7 @@ The following shows using rtx to install node, python, and jq into a project usi - **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them. - **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. - **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. -- **One command install** - No need to manually install each plugin, just run `rtx install --all` and it will install all the plugins you need. +- **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. ## Quickstart @@ -792,7 +793,7 @@ fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option ``` ", name = name, - about = c.render_long_help(), + about = strip_ansi_codes(&c.render_long_help().to_string()), )) } diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 050a4b72c..bfeaf6805 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -7,4 +7,6 @@ always_keep_download = true legacy_version_file = true plugin_autoupdate_last_check_duration = 20 verbose = true +jobs = 2 +log_level = INFO diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 311355ee0..7c9d6d68b 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -7,4 +7,6 @@ always_keep_download = true legacy_version_file = false plugin_autoupdate_last_check_duration = 1 verbose = true +jobs = 2 +log_level = INFO diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index f105dfd03..0505649cc 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -56,6 +56,8 @@ mod tests { legacy_version_file = true plugin_autoupdate_last_check_duration = 20 verbose = true + jobs = 2 + log_level = INFO "###); reset_config(); diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap new file mode 100644 index 000000000..d9e64789c --- /dev/null +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/latest.rs +expression: stdout +--- +plugin invalid_plugin not found. run rtx plugin install invalid_plugin to install it diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap new file mode 100644 index 000000000..abc02be47 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/latest.rs +expression: stdout +--- +invalid version: nodejs@system diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 192ddcc60..afbb74a6d 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,16 +1,14 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; +use console::style; use indoc::formatdoc; -use itertools::Itertools; use once_cell::sync::Lazy; use owo_colors::OwoColorize; -use owo_colors::Stream; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; -use crate::errors::Error::VersionNotInstalled; use crate::output::Output; -use crate::ui::color::Color; +use crate::toolset::ToolsetBuilder; /// removes runtime versions #[derive(Debug, clap::Args)] @@ -22,49 +20,14 @@ pub struct Uninstall { } impl Command for Uninstall { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let runtime_versions = self - .runtime - .iter() - .map(|a| { - let mut versions = config.ts.list_current_versions(); - versions.extend(config.ts.list_installed_versions()); - - let prefix = match &a.version { - RuntimeArgVersion::None => config.resolve_runtime_arg(a)?.unwrap(), - RuntimeArgVersion::Version(version) => { - config.resolve_alias(&a.plugin, version.to_string()) - } - _ => Err(eyre!("invalid version {}", a.to_string()))?, - }; - let mut versions = config.ts.list_current_versions(); - versions.extend(config.ts.list_installed_versions()); - let versions = versions - .into_iter() - .filter(|rtv| rtv.plugin.name == a.plugin) - .filter(|rtv| rtv.version.starts_with(&prefix)) - .unique_by(|rtv| rtv.version.clone()) - .collect::>(); - - if versions.is_empty() { - Err(VersionNotInstalled(a.plugin.clone(), a.version.to_string()))? - } else { - // TODO: add a flag to uninstall all matching versions - Ok(vec![versions[0].clone()]) - } - }) - .collect::>>()? - .into_iter() - .flatten() - .collect_vec(); + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let runtimes = RuntimeArg::double_runtime_condition(&self.runtime); + let ts = ToolsetBuilder::new().with_args(&runtimes).build(&config); + let runtime_versions = runtimes.iter().filter_map(|a| ts.resolve_runtime_arg(a)); for rtv in runtime_versions { if !rtv.is_installed() { - warn!( - "{} is not installed", - rtv.to_string() - .if_supports_color(Stream::Stderr, |t| t.cyan()) - ); + warn!("{} is not installed", style(rtv).cyan().for_stderr()); continue; } @@ -76,11 +39,10 @@ impl Command for Uninstall { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx uninstall nodejs@18 # will uninstall ALL nodejs-18.x versions - $ rtx uninstall nodejs # will uninstall ALL nodejs versions - "#, COLOR.header("Examples:")} + $ rtx uninstall nodejs@18.0.0 # will uninstall specific version + $ rtx uninstall nodejs # will uninstall current nodejs version + "#, style("Examples:").underline().bold()} }); diff --git a/src/cli/where.rs b/src/cli/where.rs index 3f757b6d1..cbaf014c6 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -8,6 +8,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; use crate::output::Output; +use crate::toolset::ToolsetBuilder; use crate::ui::color::Color; /// Display the installation path for a runtime @@ -30,18 +31,17 @@ pub struct Where { } impl Command for Where { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let version = config.resolve_runtime_arg(&self.runtime)?; - let rtv = config.ts.list_installed_versions().into_iter().find(|rtv| { - rtv.plugin.name == self.runtime.plugin && version.eq(&Some(rtv.version.clone())) - }); + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new() + .with_args(&[self.runtime.clone()]) + .build(&config); - match rtv { - Some(rtv) => { + match ts.resolve_runtime_arg(&self.runtime) { + Some(rtv) if rtv.is_installed() => { rtxprintln!(out, "{}", rtv.install_path.to_string_lossy()); Ok(()) } - None => Err(VersionNotInstalled( + _ => Err(VersionNotInstalled( self.runtime.plugin.to_string(), self.runtime.version.to_string(), ))?, @@ -98,6 +98,6 @@ mod tests { #[test] fn test_where_not_found() { let err = assert_cli_err!("where", "shfmt@1111"); - assert_display_snapshot!(err, @"[shfmt] version 1111 not installed"); + assert_display_snapshot!(err, @"shfmt@1111 not installed"); } } diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 879ffa4ff..31b3fff13 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -6,8 +6,9 @@ use color_eyre::eyre::Result; use indexmap::IndexMap; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::PluginSource; +use crate::config::Settings; use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; #[derive(Debug)] pub struct LegacyVersionFile { @@ -17,8 +18,8 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(path: PathBuf, plugin: &Plugin) -> Result { - let version = plugin.parse_legacy_file(path.as_path())?; + pub fn parse(settings: &Settings, path: PathBuf, plugin: &Plugin) -> Result { + let version = plugin.parse_legacy_file(path.as_path(), settings)?; Ok(Self { path, @@ -37,10 +38,6 @@ impl ConfigFile for LegacyVersionFile { self.path.as_path() } - fn source(&self) -> PluginSource { - PluginSource::LegacyVersionFile(self.path.clone()) - } - fn plugins(&self) -> IndexMap> { if self.version.is_empty() { IndexMap::new() @@ -72,6 +69,10 @@ impl ConfigFile for LegacyVersionFile { fn dump(&self) -> String { unimplemented!() } + + fn to_toolset(&self) -> Toolset { + self.into() + } } impl Display for LegacyVersionFile { @@ -79,3 +80,19 @@ impl Display for LegacyVersionFile { write!(f, "LegacyVersionFile({})", self.path.display()) } } + +impl From<&LegacyVersionFile> for Toolset { + fn from(value: &LegacyVersionFile) -> Self { + let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(value.path.clone())); + if !value.version.is_empty() { + toolset.add_version( + value.plugin.clone(), + ToolVersion::new( + value.plugin.clone(), + ToolVersionType::Version(value.version.clone()), + ), + ); + } + toolset + } +} diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 2448b0d46..4c6885b5b 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::fmt::{Debug, Display}; use std::path::Path; -use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; use indexmap::IndexMap; @@ -11,13 +10,13 @@ use tool_versions::ToolVersions; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::Config; -use crate::config::PluginSource; use crate::env; -use crate::errors::Error::VersionNotInstalled; + use crate::file::display_path; use crate::output::Output; -use crate::plugins::{Plugin, PluginName}; -use crate::runtimes::RuntimeVersion; +use crate::plugins::PluginName; + +use crate::toolset::{Toolset, ToolsetBuilder}; pub mod legacy_version; pub mod rtxrc; @@ -33,7 +32,6 @@ pub enum ConfigFileType { pub trait ConfigFile: Debug + Display + Send { fn get_type(&self) -> ConfigFileType; fn get_path(&self) -> &Path; - fn source(&self) -> PluginSource; fn plugins(&self) -> IndexMap>; fn env(&self) -> HashMap; fn remove_plugin(&mut self, plugin_name: &PluginName); @@ -41,35 +39,34 @@ pub trait ConfigFile: Debug + Display + Send { fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]); fn save(&self) -> Result<()>; fn dump(&self) -> String; + fn to_toolset(&self) -> Toolset; } impl dyn ConfigFile { pub fn add_runtimes( &mut self, - config: &mut Config, + config: &Config, runtimes: &[RuntimeArg], - fuzzy: bool, + pin: bool, ) -> Result<()> { let mut runtime_map: HashMap> = HashMap::new(); + let ts = ToolsetBuilder::new() + .with_install_missing() + .with_args(runtimes) + .build(config); for runtime in runtimes { - let plugin = Plugin::load_ensure_installed(&runtime.plugin, &config.settings)?; - let latest = config.resolve_runtime_arg(runtime)?; - if let Some(latest) = latest { - let rtv = RuntimeVersion::new(Arc::new(plugin), &latest); - if !rtv.ensure_installed(config)? { - return Err(VersionNotInstalled(rtv.plugin.name.clone(), rtv.version))?; - }; + if let Some(rtv) = ts.resolve_runtime_arg(runtime) { runtime_map .entry(rtv.plugin.name.clone()) .or_default() - .push(if fuzzy { + .push(if pin { + rtv.version.to_string() + } else { match runtime.version { RuntimeArgVersion::Version(ref v) => v.to_string(), _ => "latest".to_string(), } - } else { - rtv.version.to_string() }); } } diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 15a9a04c8..60d61d3fd 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -7,13 +7,14 @@ use std::time::Duration; use color_eyre::eyre::{eyre, Context}; use color_eyre::{Result, Section, SectionExt}; use indexmap::IndexMap; +use log::LevelFilter; use toml::Value; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::{MissingRuntimeBehavior, Settings, SettingsBuilder}; use crate::config::AliasMap; -use crate::config::PluginSource; use crate::plugins::PluginName; +use crate::toolset::Toolset; const ENV_SUGGESTION: &str = r#" [env] @@ -94,6 +95,8 @@ impl RTXFile { Some(self.parse_duration_minutes(k, v)?) } "verbose" => self.settings.verbose = Some(self.parse_bool(k, v)?), + "jobs" => self.settings.jobs = Some(self.parse_usize(k, v)?), + "log_level" => self.settings.log_level = Some(self.parse_log_level(v)?), "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} "disable_plugin_short_name_repository" => {} @@ -170,6 +173,13 @@ impl RTXFile { } } + fn parse_usize(&self, k: &str, v: &Value) -> Result { + match v { + Value::Integer(v) => Ok(*v as usize), + _ => Err(eyre!("expected {k} to be an integer, got: {v}")), + } + } + fn parse_string(&self, k: &str, v: &Value) -> Result { match v { Value::String(v) => Ok(v.clone()), @@ -188,6 +198,11 @@ impl RTXFile { } } + fn parse_log_level(&mut self, v: &Value) -> Result { + let level = self.parse_string("log_level", v)?.parse()?; + Ok(level) + } + fn parse_aliases(&mut self, v: &Value) -> Result { match v { Value::Table(table) => { @@ -311,10 +326,6 @@ impl ConfigFile for RTXFile { self.path.as_path() } - fn source(&self) -> PluginSource { - PluginSource::RtxRc(self.path.clone()) - } - fn plugins(&self) -> IndexMap> { self.plugins .iter() @@ -368,6 +379,10 @@ impl ConfigFile for RTXFile { fn dump(&self) -> String { self.get_edit().expect("unable to parse toml").to_string() } + + fn to_toolset(&self) -> Toolset { + todo!() + } } #[cfg(test)] diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index ced72571b..7611063b1 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -9,9 +9,9 @@ use indexmap::IndexMap; use itertools::Itertools; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::PluginSource; use crate::file::display_path; use crate::plugins::PluginName; +use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; // python 3.11.0 3.10.0 // shellcheck 0.9.0 @@ -100,6 +100,25 @@ impl ToolVersions { } } +impl From<&ToolVersions> for Toolset { + fn from(value: &ToolVersions) -> Self { + let mut toolset = Toolset::new(ToolSource::ToolVersions(value.path.clone())); + for (plugin, tvp) in &value.plugins { + for version in &tvp.versions { + let v = match version.split_once(':') { + Some(("prefix", v)) => ToolVersionType::Prefix(v.to_string()), + Some(("ref", v)) => ToolVersionType::Ref(v.to_string()), + Some(("path", v)) => ToolVersionType::Path(v.to_string()), + None if version == "system" => ToolVersionType::System, + _ => ToolVersionType::Version(version.to_string()), + }; + toolset.add_version(plugin.clone(), ToolVersion::new(plugin.clone(), v)); + } + } + toolset + } +} + impl Display for ToolVersions { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { let plugins = &self @@ -124,11 +143,6 @@ impl ConfigFile for ToolVersions { fn get_path(&self) -> &Path { self.path.as_path() } - - fn source(&self) -> PluginSource { - PluginSource::ToolVersions(self.path.clone()) - } - fn plugins(&self) -> IndexMap> { self.plugins .iter() @@ -171,6 +185,10 @@ impl ConfigFile for ToolVersions { s.trim_end().to_string() + "\n" } + + fn to_toolset(&self) -> Toolset { + self.into() + } } #[cfg(test)] @@ -216,6 +234,16 @@ pub(crate) mod tests { "###); } + #[test] + fn test_from_toolset() { + let orig = indoc! {" + ruby: 3.0.5 3.1 + "}; + let tv = ToolVersions::parse_str(orig).unwrap(); + let toolset: Toolset = (&tv).into(); + assert_display_snapshot!(toolset, @"Toolset: ruby@3.0.5 ruby@3.1"); + } + #[derive(Debug)] pub struct MockToolVersions { pub path: PathBuf, @@ -258,10 +286,6 @@ pub(crate) mod tests { self.path.as_path() } - fn source(&self) -> PluginSource { - todo!() - } - fn plugins(&self) -> IndexMap> { self.plugins.clone() } @@ -289,5 +313,9 @@ pub(crate) mod tests { fn dump(&self) -> String { todo!() } + + fn to_toolset(&self) -> Toolset { + todo!() + } } } diff --git a/src/config/mod.rs b/src/config/mod.rs index db59c6266..c5b72381d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,8 +1,5 @@ -use std::collections::HashMap; -use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; -use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; use color_eyre::Report; @@ -10,21 +7,14 @@ use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; -pub use plugin_source::PluginSource; pub use settings::{MissingRuntimeBehavior, Settings}; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; -use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtxrc::RTXFile; -use crate::config::config_file::ConfigFile; -use crate::config::toolset::Toolset; use crate::plugins::{Plugin, PluginName}; use crate::{dirs, env, file}; pub mod config_file; -pub mod plugin_source; mod settings; -mod toolset; type AliasMap = IndexMap>; @@ -32,137 +22,34 @@ type AliasMap = IndexMap>; pub struct Config { pub settings: Settings, pub rtxrc: RTXFile, - pub ts: Toolset, + pub legacy_files: IndexMap, pub config_files: Vec, pub aliases: AliasMap, + pub plugins: IndexMap, } impl Config { pub fn load() -> Result { let rtxrc = load_rtxrc()?; let settings = rtxrc.settings(); - let mut ts = Toolset::default(); - load_installed_plugins(&mut ts)?; - load_installed_runtimes(&mut ts)?; - let legacy_filenames = load_legacy_filenames(&settings, &ts)?; - let config_files = find_all_config_files(&legacy_filenames); - load_config_files(&mut ts, &config_files, &legacy_filenames)?; - load_runtime_env(&mut ts, env::vars().collect())?; - let aliases = load_aliases(&settings, &ts)?; - ts.resolve_all_versions(&aliases)?; + let plugins = load_plugins(&settings)?; + let legacy_files = load_legacy_files(&settings, &plugins); + let config_files = find_all_config_files(&legacy_files); + let aliases = load_aliases(&settings, &plugins)?; let config = Self { settings, - ts, + legacy_files, config_files, aliases, rtxrc, + plugins, }; debug!("{}", &config); Ok(config) } - - pub fn env(&self) -> Result> { - let mut entries = self - .ts - .list_current_installed_versions() - .into_par_iter() - .map(|p| p.exec_env()) - .collect::>>>()? - .into_iter() - .flatten() - .collect_vec(); - entries.par_sort(); - Ok(entries.into_iter().collect()) - } - - pub fn list_paths(&self) -> Result> { - let paths = self - .ts - .list_current_installed_versions() - .into_par_iter() - .map(|rtv| rtv.list_bin_paths()) - .collect::>>>()? - .into_iter() - .flatten() - .collect::>(); - Ok(paths) - } - - pub fn path_env(&self) -> Result { - let installs = self.list_paths()?; - Ok(join_paths([installs, env::PATH.clone()].concat())? - .to_string_lossy() - .into()) - } - - pub fn with_runtime_args(mut self, args: &[RuntimeArg]) -> Result { - let args_by_plugin = &args.iter().group_by(|arg| arg.plugin.clone()); - for (plugin_name, args) in args_by_plugin { - let args = args.collect_vec(); - let source = PluginSource::Argument(args[0].clone()); - let versions = args - .iter() - .map(|arg| self.resolve_runtime_arg(arg)) - .collect::>>>()? - .into_iter() - .flatten() - .collect(); - self.ts - .set_current_runtime_versions(&plugin_name, versions, source)?; - } - if !args.is_empty() { - self.ts.resolve_all_versions(&self.aliases)?; - } - Ok(self) - } - - pub fn ensure_installed(&self) -> Result<()> { - for rtv in self.ts.list_current_versions() { - if rtv.plugin.is_installed() { - rtv.ensure_installed(self)?; - } - } - Ok(()) - } - - pub fn resolve_alias(&self, plugin: &str, version: String) -> String { - if let Some(plugin_aliases) = self.aliases.get(plugin) { - if let Some(alias) = plugin_aliases.get(&version) { - return alias.clone(); - } - } - version - } - - pub fn resolve_runtime_arg(&mut self, arg: &RuntimeArg) -> Result> { - match &arg.version { - RuntimeArgVersion::System => Ok(None), - RuntimeArgVersion::Version(version) => { - let plugin = self.ts.get_or_add_plugin(arg.plugin.to_string())?; - plugin.ensure_installed(&self.settings)?; - let version = self.resolve_alias(&arg.plugin, version.into()); - let version = plugin.latest_version(&version)?.unwrap_or(version); - Ok(Some(version)) - } - RuntimeArgVersion::None => { - let plugin = self - .ts - .list_current_versions() - .into_iter() - .find(|rtv| rtv.plugin.name == arg.plugin); - match plugin { - Some(rtv) => Ok(Some(rtv.version.clone())), - None => Err(eyre!( - "No version of {} is specified in a .tool-versions file", - arg.plugin - ))?, - } - } - } - } } fn load_rtxrc() -> Result { @@ -180,54 +67,50 @@ fn load_rtxrc() -> Result { Ok(rtxrc) } -fn load_installed_plugins(ts: &mut Toolset) -> Result<()> { - let plugins = file::dir_subdirs(&dirs::PLUGINS)? +fn load_plugins(settings: &Settings) -> Result> { + let plugins = Plugin::list()? .into_par_iter() - .map(|p| { - let plugin = Plugin::load(&p)?; - Ok((p, Arc::new(plugin))) + .filter_map(|mut p| match p.ensure_loaded(settings) { + Ok(_) => Some((p.name.clone(), p)), + Err(e) => { + error!("Failed to load plugin {}: {}", p.name, e); + None + } }) - .collect::>>()?; - for (name, plugin) in plugins { - ts.plugins.entry(name).or_insert(plugin); - } - Ok(()) -} - -fn load_installed_runtimes(ts: &mut Toolset) -> Result<()> { - let plugin_versions = ts - .list_plugins() - .into_par_iter() - .map(|p| Ok((p.clone(), p.list_installed_versions()?))) - .collect::, Vec)>>>()?; - for (plugin, versions) in plugin_versions { - ts.add_runtime_versions(&plugin.name, versions)?; - } - Ok(()) + .collect::>() + .into_iter() + .sorted_by_cached_key(|(p, _)| p.to_string()) + .collect(); + Ok(plugins) } -fn load_legacy_filenames( +fn load_legacy_files( settings: &Settings, - ts: &Toolset, -) -> Result> { + plugins: &IndexMap, +) -> IndexMap { if !settings.legacy_version_file { - return Ok(IndexMap::new()); + return IndexMap::new(); } - let filenames = ts - .list_plugins() + plugins + .values() + .collect_vec() .into_par_iter() - .map(|plugin| { - let mut legacy_filenames = vec![]; - for filename in plugin.legacy_filenames()? { - legacy_filenames.push((filename, plugin.name.clone())); + .filter_map(|plugin| match plugin.legacy_filenames(settings) { + Ok(filenames) => Some( + filenames + .into_iter() + .map(|f| (f, plugin.name.clone())) + .collect_vec(), + ), + Err(err) => { + eprintln!("Error: {err}"); + None } - Ok(legacy_filenames) }) - .collect::>>>()? + .collect::>>() .into_iter() .flatten() - .collect::>(); - Ok(filenames) + .collect() } fn find_all_config_files(legacy_filenames: &IndexMap) -> Vec { @@ -251,71 +134,10 @@ fn find_all_config_files(legacy_filenames: &IndexMap) -> Vec config_files.into_iter().unique().collect() } -fn load_config_files( - ts: &mut Toolset, - config_files: &Vec, - legacy_filenames: &IndexMap, -) -> Result<()> { - let parsed_config_files = config_files - .into_par_iter() - .rev() - .filter_map(|path| { - let filename = path.file_name().unwrap().to_string_lossy().to_string(); - let result = match legacy_filenames.get(&filename) { - Some(plugin) => { - let plugin = ts.find_plugin(plugin).unwrap(); - LegacyVersionFile::parse(path.into(), &plugin) - .map(|cf| Box::new(cf) as Box) - } - None => config_file::parse(path), - }; - match result { - Ok(cf) => Some(cf), - Err(e) => { - warn!("error parsing config file: {}", e); - None - } - } - }) - .collect::>(); - - for cf in parsed_config_files { - let path = cf.get_path().to_path_buf(); - load_config_file(ts, cf) - .with_context(|| eyre!("error loading file: {}", path.display()))?; - } - - Ok(()) -} - -fn load_config_file(ts: &mut Toolset, cf: Box) -> Result<()> { - trace!("config file: {}", cf); - for (plugin, versions) in cf.plugins() { - ts.set_current_runtime_versions(&plugin, versions.clone(), cf.source())?; - } - - Ok(()) -} - -fn load_runtime_env(ts: &mut Toolset, env: IndexMap) -> Result<()> { - for (k, v) in env { - if k.starts_with("RTX_") && k.ends_with("_VERSION") { - let plugin_name = k[4..k.len() - 8].to_lowercase(); - if let Some(plugin) = ts.find_plugin(&plugin_name) { - if plugin.is_installed() { - let source = PluginSource::Environment(k, v.clone()); - ts.set_current_runtime_versions(&plugin.name, vec![v], source)?; - } - } - } - } - Ok(()) -} - -fn load_aliases(settings: &Settings, ts: &Toolset) -> Result { +fn load_aliases(settings: &Settings, plugins: &IndexMap) -> Result { let mut aliases = IndexMap::new(); - for plugin in ts.list_installed_plugins() { - for (from, to) in plugin.list_aliases()? { + for plugin in plugins.values() { + for (from, to) in plugin.get_aliases() { aliases .entry(plugin.name.clone()) .or_insert_with(IndexMap::new) @@ -345,16 +167,9 @@ fn err_load_settings(settings_path: &Path) -> Report { impl Display for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let plugins = self - .ts - .list_installed_plugins() - .into_iter() - .map(|p| p.name.clone()) - .collect::>(); - let versions = self - .ts - .list_current_installed_versions() - .into_iter() - .map(|rtv| rtv.to_string()) + .plugins + .keys() + .map(|p| p.to_string()) .collect::>(); let config_files = self .config_files @@ -367,7 +182,6 @@ impl Display for Config { .collect::>(); writeln!(f, "Config:")?; writeln!(f, " Files: {}", config_files.join(", "))?; - writeln!(f, " Installed Plugins: {}", plugins.join(", "))?; - write!(f, " Active Versions: {}", versions.join(", ")) + writeln!(f, " Installed Plugins: {}", plugins.join(", ")) } } diff --git a/src/config/plugin_source.rs b/src/config/plugin_source.rs deleted file mode 100644 index b82366fd0..000000000 --- a/src/config/plugin_source.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::fmt::{Display, Formatter}; -use std::path::PathBuf; - -use crate::cli::args::runtime::RuntimeArg; -use crate::file::display_path; - -#[derive(Debug, Clone)] -pub enum PluginSource { - ToolVersions(PathBuf), - RtxRc(PathBuf), - LegacyVersionFile(PathBuf), - Argument(RuntimeArg), - Environment(String, String), -} - -impl Display for PluginSource { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - match self { - PluginSource::ToolVersions(path) => write!(f, "{}", display_path(path)), - PluginSource::RtxRc(path) => write!(f, "{}", display_path(path)), - PluginSource::LegacyVersionFile(path) => write!(f, "{}", display_path(path)), - PluginSource::Argument(arg) => write!(f, "--runtime {arg}"), - PluginSource::Environment(k, v) => write!(f, "{k}={v}"), - } - } -} diff --git a/src/config/settings.rs b/src/config/settings.rs index 5a4933b7d..8669b5506 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -2,10 +2,11 @@ use std::fmt::{Display, Formatter}; use std::time::Duration; use indexmap::IndexMap; +use log::LevelFilter; use crate::config::AliasMap; use crate::env; -use crate::env::RTX_VERBOSE; +use crate::env::{RTX_JOBS, RTX_LOG_LEVEL, RTX_VERBOSE}; use crate::plugins::PluginName; use crate::ui::prompt::is_tty; @@ -17,6 +18,8 @@ pub struct Settings { pub plugin_autoupdate_last_check_duration: Duration, pub aliases: IndexMap>, pub verbose: bool, + pub jobs: usize, + pub log_level: LevelFilter, } impl Default for Settings { @@ -28,6 +31,8 @@ impl Default for Settings { plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), aliases: IndexMap::new(), verbose: *RTX_VERBOSE || !is_tty(), + jobs: *RTX_JOBS, + log_level: *RTX_LOG_LEVEL, } } } @@ -52,6 +57,8 @@ impl Settings { (self.plugin_autoupdate_last_check_duration.as_secs() / 60).to_string(), ); map.insert("verbose".into(), self.verbose.to_string()); + map.insert("jobs".into(), self.jobs.to_string()); + map.insert("log_level".into(), self.log_level.to_string()); map } } @@ -64,6 +71,8 @@ pub struct SettingsBuilder { pub plugin_autoupdate_last_check_duration: Option, pub aliases: Option, pub verbose: Option, + pub jobs: Option, + pub log_level: Option, } impl SettingsBuilder { @@ -90,6 +99,12 @@ impl SettingsBuilder { if other.verbose.is_some() { self.verbose = other.verbose; } + if other.jobs.is_some() { + self.jobs = other.jobs; + } + if other.log_level.is_some() { + self.log_level = other.log_level; + } if other.aliases.is_some() { self.aliases = other.aliases; } @@ -122,6 +137,7 @@ impl SettingsBuilder { .plugin_autoupdate_last_check_duration .unwrap_or(settings.plugin_autoupdate_last_check_duration); settings.verbose = self.verbose.unwrap_or(settings.verbose); + settings.jobs = self.jobs.unwrap_or(settings.jobs); settings.aliases = self.aliases.clone().unwrap_or(settings.aliases); settings diff --git a/src/config/toolset.rs b/src/config/toolset.rs deleted file mode 100644 index f01e7e33b..000000000 --- a/src/config/toolset.rs +++ /dev/null @@ -1,242 +0,0 @@ -use std::collections::HashMap; -use std::sync::Arc; - -use color_eyre::eyre::Result; -use indexmap::IndexMap; -use itertools::Itertools; -use rayon::prelude::*; -use versions::Versioning; - -use crate::config::{AliasMap, PluginSource}; -use crate::plugins::{Plugin, PluginName}; -use crate::runtimes::RuntimeVersion; - -#[derive(Debug, Default)] -pub struct Toolset { - pub plugins: HashMap>, - installed_versions: HashMap>>, - current_versions: IndexMap>, - current_versions_sources: HashMap, -} - -impl Toolset { - pub fn find_plugin(&self, key: &PluginName) -> Option> { - self.plugins.get(key).map(Arc::clone) - } - - pub fn get_or_add_plugin(&mut self, name: String) -> Result> { - let plugin = match self.plugins.get(&name) { - Some(p) => p, - None => { - let plugin = Plugin::load(&name)?; - self.plugins.entry(name).or_insert_with(|| Arc::new(plugin)) - } - }; - - Ok(plugin.clone()) - } - - pub fn get_or_add_version( - &mut self, - plugin: &str, - version: String, - ) -> Result> { - let plugin = self.get_or_add_plugin(plugin.into())?; - let rtv = self - .installed_versions - .entry(plugin.name.clone()) - .or_default() - .entry(version.clone()) - .or_insert_with(|| Arc::new(RuntimeVersion::new(plugin, &version))) - .clone(); - - Ok(rtv) - } - - pub fn add_runtime_versions(&mut self, plugin: &str, versions: Vec) -> Result<()> { - for version in versions { - self.get_or_add_version(plugin, version)?; - } - Ok(()) - } - - pub fn set_current_runtime_versions( - &mut self, - plugin: &str, - versions: Vec, - source: PluginSource, - ) -> Result<()> { - self.get_or_add_plugin(plugin.into())?; - self.current_versions.insert(plugin.into(), versions); - self.current_versions_sources.insert(plugin.into(), source); - Ok(()) - } - - pub fn list_plugins(&self) -> Vec> { - self.plugins - .values() - .sorted_by_cached_key(|p| p.name.clone()) - .map(Arc::clone) - .collect() - } - - pub fn list_installed_plugins(&self) -> Vec> { - self.list_plugins() - .into_iter() - .filter(|p| p.is_installed()) - .collect() - } - - pub fn list_current_plugins(&self) -> Vec> { - self.current_versions - .keys() - .sorted() - .map(|p| self.find_plugin(p).unwrap()) - .collect() - } - - pub fn list_installed_versions(&self) -> Vec> { - self.installed_versions - .iter() - .sorted_by_cached_key(|(plugin_name, _)| plugin_name.to_string()) - .flat_map(|(_, versions)| versions.iter().map(|(_, rtv)| rtv.clone())) - .collect() - } - - pub fn list_current_versions(&self) -> Vec> { - self.current_versions - .iter() - .flat_map(|(plugin_name, versions)| { - versions - .iter() - .map(|v| { - self.resolve_version(plugin_name, v).unwrap_or_else(|| { - let plugin = self - .find_plugin(plugin_name) - .unwrap_or_else(|| Arc::new(Plugin::new(plugin_name))); - Arc::new(RuntimeVersion::new(plugin, v)) - }) - }) - .collect::>() - }) - .collect() - } - - pub fn list_current_installed_versions(&self) -> Vec> { - self.list_current_versions() - .into_iter() - .filter(|rtv| rtv.is_installed()) - .collect() - } - - pub fn resolve_all_versions(&mut self, aliases: &AliasMap) -> Result<()> { - let default_aliases = IndexMap::new(); - self.current_versions = self - .current_versions - .clone() - .into_iter() - .collect_vec() - .into_par_iter() - .map(|(plugin_name, versions)| { - let aliases = aliases.get(&plugin_name).unwrap_or(&default_aliases); - let plugin = self - .find_plugin(&plugin_name) - .unwrap_or_else(|| Arc::new(Plugin::new(&plugin_name))); - let versions = versions - .iter() - .map(|v| { - let v = match aliases.get(v) { - Some(version) => { - trace!("resolved alias: {}@{} -> {}", plugin.name, v, version); - version - } - _ => v, - }; - match self.resolve_version(&plugin_name, v) { - Some(rtv) => Ok(rtv.version.clone()), - None => { - let latest = if plugin.is_installed() { - plugin.latest_version(v)? - } else { - Some(v.clone()) - }; - Ok(latest.unwrap_or_else(|| v.clone())) - } - } - }) - .collect::>>()?; - Ok((plugin_name, versions)) - }) - .collect::)>>>()? - .into_iter() - .collect::>>(); - trace!("resolved versions: {:?}", self.current_versions); - Ok(()) - // if plugin.is_installed() { - // if let Some(latest) = plugin.latest_version(version)? { - // return Ok(Arc::new(RuntimeVersion::new(plugin, &latest))); - // } - // } - // Ok(Arc::new(RuntimeVersion::new(plugin, version))) - } - - pub fn resolve_version( - &self, - plugin: &PluginName, - version: &str, - ) -> Option> { - if let Some(installed_versions) = self.installed_versions.get(plugin) { - if let Some(rtv) = installed_versions.get(version) { - return Some(rtv.clone()); - } - let sorted_versions = installed_versions - .keys() - .sorted_by_cached_key(|v| Versioning::new(v)) - .rev() - .collect::>(); - for v in sorted_versions { - if v.starts_with(version) { - return Some(installed_versions[v].clone()); - } - } - } - - None - } - - pub fn get_source_for_plugin(&self, plugin: &PluginName) -> Option { - self.current_versions_sources.get(plugin).cloned() - } - - pub fn find_by_prefix( - &self, - aliases: &AliasMap, - plugin: &str, - prefix: &str, - ) -> Option> { - let default_aliases = IndexMap::new(); - let aliases = aliases.get(plugin).unwrap_or(&default_aliases); - let prefix = aliases.get(prefix).cloned().unwrap_or(prefix.to_string()); - - let mut versions = self.list_current_versions(); - versions.extend(self.list_installed_versions()); - versions - .into_iter() - .find(|rtv| rtv.plugin.name == plugin && rtv.version.starts_with(&prefix)) - } - - pub fn list_current_versions_by_plugin( - &self, - ) -> IndexMap>> { - self.current_versions - .iter() - .map(|(plugin_name, versions)| { - let versions = versions - .iter() - .filter_map(|v| self.resolve_version(plugin_name, v)) - .collect(); - (plugin_name.clone(), versions) - }) - .collect() - } -} diff --git a/src/env.rs b/src/env.rs index d6ecfa3be..9b0554ce8 100644 --- a/src/env.rs +++ b/src/env.rs @@ -81,10 +81,14 @@ lazy_static! { var("RTX_MISSING_RUNTIME_BEHAVIOR").ok() }; pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); - pub static ref RTX_VERBOSE: bool = var_is_true("RTX_VERBOSE"); pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); + pub static ref RTX_VERBOSE: bool = *RTX_DEBUG || *RTX_TRACE || var_is_true("RTX_VERBOSE"); + pub static ref RTX_JOBS: usize = var("RTX_JOBS") + .ok() + .and_then(|v| v.parse::().ok()) + .unwrap_or_else(num_cpus::get); /// essentially, this is whether we show spinners or build output on runtime install pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); diff --git a/src/errors.rs b/src/errors.rs index 4641dc5e6..70f9582ae 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -8,8 +8,10 @@ use crate::plugins::PluginName; pub enum Error { #[error("[{0}] plugin not installed")] PluginNotInstalled(PluginName), - #[error("[{0}] version {1} not installed")] + #[error("{0}@{1} not installed")] VersionNotInstalled(PluginName, String), + #[error("{0}@{1} not found")] + VersionNotFound(PluginName, String), #[error("[{}] script exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(PluginName, Option), } diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index ffbdf598a..b9f7957df 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -45,17 +45,3 @@ pub fn get_path_with_fake_asdf() -> String { path.push(env::var("PATH").unwrap()); path.join(":") } - -#[cfg(test)] -mod tests { - use std::fs; - - use super::*; - - #[test] - fn test_setup() { - let path = setup().unwrap(); - assert!(path.join("asdf").exists()); - fs::remove_dir_all(&path).unwrap(); - } -} diff --git a/src/file.rs b/src/file.rs index 961c1cb90..016bcf45d 100644 --- a/src/file.rs +++ b/src/file.rs @@ -56,7 +56,8 @@ pub fn dir_subdirs(dir: &Path) -> Result> { for entry in dir.read_dir()? { let entry = entry?; - if entry.file_type()?.is_dir() { + let ft = entry.file_type()?; + if ft.is_dir() || ft.is_symlink() { output.push(entry.file_name().into_string().unwrap()); } } diff --git a/src/git.rs b/src/git.rs index d58ca536f..d5c38f2d0 100644 --- a/src/git.rs +++ b/src/git.rs @@ -89,6 +89,12 @@ impl Git { Ok(sha) } + pub fn current_sha_short(&self) -> Result { + let sha = cmd!("git", "-C", &self.dir, "rev-parse", "--short", "HEAD").read()?; + debug!("current sha for {}: {}", self.dir.display(), &sha); + Ok(sha) + } + pub fn get_remote_url(&self) -> Option { let res = cmd!( "git", @@ -123,6 +129,7 @@ fn get_git_version() -> Result { #[cfg(test)] mod tests { + use pretty_assertions::assert_str_eq; use tempfile::tempdir; use super::*; @@ -137,6 +144,7 @@ mod tests { let latest = git.current_sha().unwrap(); let update_result = git.update(Some(prev_rev.clone())).unwrap(); assert_eq!(update_result, (latest.to_string(), prev_rev.to_string())); + assert_str_eq!(git.current_sha_short().unwrap(), "f4b510d"); let update_result = git.update(None).unwrap(); assert_eq!(update_result, (prev_rev, latest)); } diff --git a/src/hook_env.rs b/src/hook_env.rs index c1ed497c3..a6c373d6b 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -29,7 +29,7 @@ pub fn should_exit_early(config: &Config) -> bool { if have_config_files_been_modified(&env::vars().collect(), watch_files) { return false; } - trace!("rtx: early-exit"); + trace!("early-exit"); true } diff --git a/src/main.rs b/src/main.rs index a133e12d5..b623fead2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,8 @@ mod direnv; mod hash; mod shorthand; mod shorthand_list; +mod toolset; + #[cfg(test)] mod test; diff --git a/src/output.rs b/src/output.rs index 1d105d6bd..324b59ca5 100644 --- a/src/output.rs +++ b/src/output.rs @@ -91,7 +91,7 @@ macro_rules! rtxprint { #[macro_export] macro_rules! rtxstatusln { ($out:ident, $($arg:tt)*) => {{ - let rtx = $crate::output::dim(atty::Stream::Stderr, "rtx: "); + let rtx = $crate::output::dim(atty::Stream::Stderr, "rtx "); $out.stderr.writeln(format!("{}{}", rtx, format!($($arg)*))); }}; } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 54822d051..f2de4a1e8 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -4,9 +4,13 @@ use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; +use atty::Stream; use atty::Stream::Stderr; use color_eyre::eyre::WrapErr; use color_eyre::eyre::{eyre, Result}; +use console::style; +use indexmap::IndexMap; +use indicatif::ProgressStyle; use itertools::Itertools; use lazy_static::lazy_static; use once_cell::sync::Lazy; @@ -25,8 +29,8 @@ use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::shorthand::shorthand_to_repository; use crate::ui::color::{cyan, Color}; +use crate::ui::progress_report::ProgressReport; use crate::ui::prompt; -use crate::ui::spinner::Spinner; use crate::{dirs, file}; mod cache; @@ -60,10 +64,10 @@ impl Plugin { } } - pub fn load(name: &PluginName) -> Result { + pub fn load(name: &PluginName, settings: &Settings) -> Result { let mut plugin = Self::new(name); if plugin.is_installed() { - plugin.cache = Some(plugin.get_cache()?); + plugin.ensure_loaded(settings)?; } Ok(plugin) } @@ -73,7 +77,7 @@ impl Plugin { if !plugin.ensure_installed(settings)? { Err(PluginNotInstalled(plugin.name.to_string()))?; } - plugin.cache = Some(plugin.get_cache()?); + plugin.cache = Some(plugin.get_cache(settings)?); Ok(plugin) } @@ -88,27 +92,57 @@ impl Plugin { self.plugin_path.exists() } + pub fn ensure_loaded(&mut self, settings: &Settings) -> Result<()> { + self.cache = Some(self.get_cache(settings)?); + Ok(()) + } + pub fn get_remote_url(&self) -> Option { let git = Git::new(self.plugin_path.to_path_buf()); git.get_remote_url() } - pub fn install(&self, settings: &Settings, repository: &str) -> Result<()> { + pub fn install( + &mut self, + settings: &Settings, + repository: Option<&str>, + mut pr: ProgressReport, + ) -> Result<()> { + static PROG_TEMPLATE: Lazy = Lazy::new(|| { + ProgressStyle::with_template("{prefix}{wide_msg} {spinner:.blue} {elapsed:.dim.italic}") + .unwrap() + }); + pr.set_style(PROG_TEMPLATE.clone()); + pr.set_prefix(format!( + "{} {} ", + COLOR.dimmed("rtx"), + COLOR.cyan(&self.name) + )); + pr.enable_steady_tick(); + let repository = repository + .or_else(|| shorthand_to_repository(&self.name)) + .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; debug!("install {} {:?}", self.name, repository); - let install_message = format!("Installing plugin {}...", cyan(Stderr, &self.name)); - let mut sp = Spinner::start(install_message, settings.verbose); - if self.is_installed() { + pr.set_message("uninstalling existing plugin".into()); self.uninstall()?; } let git = Git::new(self.plugin_path.to_path_buf()); + pr.set_message(format!("cloning {repository}")); git.clone(repository)?; - sp.success(format!("Plugin {} installed", cyan(Stderr, &self.name))); + pr.set_message("loading plugin".into()); + self.ensure_loaded(settings)?; + let sha = git.current_sha_short()?; + pr.finish_with_message(format!( + "{} {repository}@{}", + COLOR.green("✓"), + COLOR.bright_yellow(&sha), + )); Ok(()) } - pub fn ensure_installed(&self, settings: &Settings) -> Result { + pub fn ensure_installed(&mut self, settings: &Settings) -> Result { static COLOR: Lazy = Lazy::new(|| Color::new(Stderr)); if self.is_installed() { return Ok(true); @@ -117,14 +151,18 @@ impl Plugin { match shorthand_to_repository(&self.name) { Some(repo) => match settings.missing_runtime_behavior { MissingRuntimeBehavior::AutoInstall => { - self.install(settings, repo)?; + self.install(settings, Some(repo), ProgressReport::new(settings.verbose))?; Ok(true) } MissingRuntimeBehavior::Prompt => { match prompt::prompt_for_install(&format!("plugin {}", COLOR.cyan(&self.name))) { true => { - self.install(settings, repo)?; + self.install( + settings, + Some(repo), + ProgressReport::new(settings.verbose), + )?; Ok(true) } false => Ok(false), @@ -152,12 +190,18 @@ impl Plugin { pub fn update(&self, gitref: Option) -> Result<()> { let plugin_path = self.plugin_path.to_path_buf(); if plugin_path.is_symlink() { - warn!("Plugin: {} is a symlink, not updating", self.name); + warn!( + "Plugin: {} is a symlink, not updating", + style(&self.name).cyan().for_stderr() + ); return Ok(()); } let git = Git::new(plugin_path); if !git.is_repo() { - warn!("Plugin {} is not a git repository not updating", self.name); + warn!( + "Plugin {} is not a git repository, not updating", + style(&self.name).cyan().for_stderr() + ); return Ok(()); } // TODO: asdf_run_hook "pre_plugin_update" @@ -188,7 +232,15 @@ impl Plugin { Ok(()) } - pub fn latest_version(&self, query: &str) -> Result> { + pub fn latest_version(&self, query: &str) -> Option { + let matches = self.list_versions_matching(query); + match matches.contains(&query.to_string()) { + true => Some(query.to_string()), + false => matches.last().map(|v| v.to_string()), + } + } + + pub fn list_versions_matching(&self, query: &str) -> Vec { let mut query = query; if query == "latest" { query = "[0-9]"; @@ -198,22 +250,21 @@ impl Plugin { r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" ).unwrap(); } - let query_regex = Regex::new((String::from(r"^\s*") + query).as_str())?; - let matches = self - .get_cache()? + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + self.cache + .as_ref() + .expect("plugin not loaded") .versions - .into_iter() + .iter() .filter(|v| !VERSION_REGEX.is_match(v)) .filter(|v| query_regex.is_match(v)) - .collect_vec(); - match matches.contains(&query.to_string()) { - true => Ok(Some(query.to_string())), - false => Ok(matches.last().map(|v| v.to_string())), - } + .cloned() + .collect_vec() } - pub fn legacy_filenames(&self) -> Result> { - Ok(self.get_cache()?.legacy_filenames) + pub fn legacy_filenames(&self, settings: &Settings) -> Result> { + Ok(self.get_cache(settings)?.legacy_filenames) } pub fn list_installed_versions(&self) -> Result> { @@ -228,16 +279,21 @@ impl Plugin { }) } - pub fn list_remote_versions(&self) -> Result> { + pub fn list_remote_versions(&self, settings: &Settings) -> Result> { self.clear_cache(); - let cache = self.get_cache()?; + let cache = self.get_cache(settings)?; Ok(cache.versions) } - pub fn list_aliases(&self) -> Result> { - let cache = self.get_cache()?; - Ok(cache.aliases) + pub fn get_aliases(&self) -> IndexMap { + self.cache + .as_ref() + .expect("plugin not loaded") + .aliases + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect() } pub fn external_commands(&self) -> Result>> { @@ -279,28 +335,40 @@ impl Plugin { exit(result.status.code().unwrap_or(1)); } - fn fetch_remote_versions(&self) -> Result> { - Ok(self + fn fetch_remote_versions(&self, settings: &Settings) -> Result> { + let result = self .script_man .cmd(Script::ListAll) - .read()? - .split_whitespace() - .map(|v| v.into()) - .collect()) + .stdout_capture() + .stderr_capture() + .unchecked() + .run()?; + let stdout = String::from_utf8(result.stdout).unwrap(); + let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); + + let display_stderr = || { + if !stderr.is_empty() { + eprintln!("{stderr}"); + } + }; + if !result.status.success() { + display_stderr(); + return Err(eyre!( + "error running {}: exited with code {}", + Script::ListAll, + result.status.code().unwrap_or_default() + ))?; + } else if settings.verbose { + display_stderr(); + } + + Ok(stdout.split_whitespace().map(|v| v.into()).collect()) } - fn get_cache(&self) -> Result { + fn get_cache(&self, settings: &Settings) -> Result { if let Some(cache) = self.cache.as_ref() { return Ok(cache.clone()); } - // lazy_static! { - // static ref CACHE: Mutex>>> = - // Mutex::new(HashMap::new()); - // } - // let mut cache = CACHE.lock().expect("failed to get mutex"); - // let pc = match cache.get(&self.name) { - // Some(cached) => cached, - // None => { if !self.is_installed() { return Err(PluginNotInstalled(self.name.clone()).into()); } @@ -309,7 +377,7 @@ impl Plugin { let pc = match cp.exists() && changed_within(cp, Duration::from_secs(60 * 60 * 24))? { true => PluginCache::parse(cp)?, false => { - let pc = self.build_cache()?; + let pc = self.build_cache(settings)?; pc.write(cp).unwrap_or_else(|e| { warn!( "Failed to write plugin cache to {}: {}", @@ -325,16 +393,16 @@ impl Plugin { Ok(pc) } - fn build_cache(&self) -> Result { + fn build_cache(&self, settings: &Settings) -> Result { Ok(PluginCache { versions: self - .fetch_remote_versions() + .fetch_remote_versions(settings) .wrap_err_with(|| eyre!("fetching remote versions for {}", self.name))?, legacy_filenames: self - .fetch_legacy_filenames() + .fetch_legacy_filenames(settings) .wrap_err_with(|| eyre!("fetching legacy filenames for {}", self.name))?, aliases: self - .fetch_aliases() + .fetch_aliases(settings) .wrap_err_with(|| eyre!("fetching aliases for {}", self.name))?, }) } @@ -347,23 +415,25 @@ impl Plugin { } } - fn fetch_legacy_filenames(&self) -> Result> { + fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { if !self.script_man.script_exists(&Script::ListLegacyFilenames) { return Ok(vec![]); } Ok(self .script_man - .read(Script::ListLegacyFilenames)? + .read(Script::ListLegacyFilenames, settings.verbose)? .split_whitespace() .map(|v| v.into()) .collect()) } - fn fetch_aliases(&self) -> Result> { + fn fetch_aliases(&self, settings: &Settings) -> Result> { if !self.script_man.script_exists(&Script::ListAliases) { return Ok(vec![]); } - let stdout = self.script_man.read(Script::ListAliases)?; + let stdout = self + .script_man + .read(Script::ListAliases, settings.verbose)?; let aliases = stdout .lines() .filter_map(|line| { @@ -381,14 +451,14 @@ impl Plugin { Ok(aliases) } - pub fn parse_legacy_file(&self, legacy_file: &Path) -> Result { + pub fn parse_legacy_file(&self, legacy_file: &Path, settings: &Settings) -> Result { if let Some(cached) = self.fetch_cached_legacy_file(legacy_file)? { return Ok(cached); } trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); let legacy_version = match self.script_man.script_exists(&script) { - true => self.script_man.read(script)?, + true => self.script_man.read(script, settings.verbose)?, false => fs::read_to_string(legacy_file)?, } .trim() @@ -428,6 +498,8 @@ impl PartialEq for Plugin { } } +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); + #[cfg(test)] mod tests { use pretty_assertions::assert_str_eq; @@ -439,21 +511,23 @@ mod tests { #[test] fn test_legacy_gemfile() { assert_cli!("plugin", "add", "ruby"); - let plugin = Plugin::load(&PluginName::from("ruby")).unwrap(); + let settings = Settings::default(); + let plugin = Plugin::load(&PluginName::from("ruby"), &settings).unwrap(); let gemfile = env::HOME.join("fixtures/Gemfile"); - let version = plugin.parse_legacy_file(&gemfile).unwrap(); + let version = plugin.parse_legacy_file(&gemfile, &settings).unwrap(); assert_str_eq!(version, "3.0.5"); // do it again to test the cache - let version = plugin.parse_legacy_file(&gemfile).unwrap(); + let version = plugin.parse_legacy_file(&gemfile, &settings).unwrap(); assert_str_eq!(version, "3.0.5"); } #[test] fn test_exact_match() { assert_cli!("plugin", "add", "python"); - let plugin = Plugin::load(&PluginName::from("python")).unwrap(); - let version = plugin.latest_version("3.9.1").unwrap().unwrap(); + let settings = Settings::default(); + let plugin = Plugin::load(&PluginName::from("python"), &settings).unwrap(); + let version = plugin.latest_version("3.9.1").unwrap(); assert_str_eq!(version, "3.9.1"); } } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index f5aa8844c..b154332e8 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -1,8 +1,9 @@ use std::fmt; use std::fmt::{Display, Formatter}; -use std::io::{stderr, Write}; +use std::io::{BufRead, BufReader}; use std::path::PathBuf; use std::process::Output; +use std::sync::Arc; use color_eyre::eyre::{Context, Result}; use duct::Expression; @@ -64,12 +65,14 @@ impl fmt::Display for Script { #[derive(Debug, Clone)] pub enum InstallType { Version, + Ref, } impl Display for InstallType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { InstallType::Version => write!(f, "version"), + InstallType::Ref => write!(f, "ref"), } } } @@ -144,34 +147,39 @@ impl ScriptManager { } } - pub fn read(&self, script: Script) -> Result { - self.cmd(script) - .read() + pub fn read(&self, script: Script, verbose: bool) -> Result { + let mut cmd = self.cmd(script); + if !verbose { + cmd = cmd.stderr_null(); + } + cmd.read() .with_context(|| ScriptFailed(self.plugin_name.clone(), None)) } - pub fn run_with_hidden_output(&self, script: Script, on_error: F) -> Result<()> + pub fn run_by_line(&self, script: Script, on_error: F1, on_output: F2) -> Result<()> where - F: FnOnce(), + F1: Fn(String), + F2: Fn(&str), { - let out = self - .cmd(script) - .stderr_to_stdout() - .stdout_capture() - .unchecked() - .run(); - - match out { + let reader = self.cmd(script).stderr_to_stdout().unchecked().reader()?; + let reader = Arc::new(reader); + let mut output = vec![]; + for line in BufReader::new(&*reader).lines() { + let line = line.unwrap(); + on_output(&line); + output.push(line); + } + + match reader.try_wait() { Err(err) => { - on_error(); + on_error(output.join("\n")); Err(err)? } - Ok(out) => match out.status.success() { + Ok(out) => match out.unwrap().status.success() { true => Ok(()), false => { - stderr().write_all(out.stdout.as_slice())?; - on_error(); - let err = ScriptFailed(self.plugin_name.clone(), Some(out.status)); + on_error(output.join("\n")); + let err = ScriptFailed(self.plugin_name.clone(), Some(out.unwrap().status)); Err(err)? } }, diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index 6334391fc..e5a4b669f 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -8,6 +8,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; +use indicatif::ProgressStyle; use once_cell::sync::Lazy; use versions::Versioning; @@ -16,11 +17,11 @@ use runtime_conf::RuntimeConf; use crate::config::Config; use crate::config::{MissingRuntimeBehavior, Settings}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; -use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; +use crate::errors::Error::VersionNotInstalled; use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; -use crate::ui::color::{cyan, Color}; +use crate::ui::color::Color; +use crate::ui::progress_report::ProgressReport; use crate::ui::prompt; -use crate::ui::spinner::Spinner; use crate::{dirs, env, fake_asdf, file}; mod runtime_conf; @@ -70,54 +71,53 @@ impl RuntimeVersion { Ok(versions) } - pub fn install(&self, install_type: InstallType, config: &Config) -> Result<()> { - let plugin = &self.plugin; - let settings = &config.settings; - debug!("install {} {} {}", plugin.name, self.version, install_type); - let rtv_label = cyan(Stderr, &self.to_string()); - let install_message = format!("Installing runtime: {rtv_label}..."); - let mut sp = Spinner::start(install_message, config.settings.verbose); + pub fn install( + &self, + install_type: InstallType, + config: &Config, + mut pr: ProgressReport, + ) -> Result<()> { + static PROG_TEMPLATE: Lazy = Lazy::new(|| { + ProgressStyle::with_template("{prefix}{wide_msg} {spinner:.blue} {elapsed:.dim.italic}") + .unwrap() + }); + pr.set_style(PROG_TEMPLATE.clone()); + pr.set_prefix(format!( + "{} {} ", + COLOR.dimmed("rtx"), + COLOR.cyan(&self.to_string()) + )); + pr.enable_steady_tick(); - if !self.plugin.ensure_installed(settings)? { - return Err(PluginNotInstalled(self.plugin.name.clone()).into()); - } + let settings = &config.settings; + debug!("install {} {}", self, install_type); self.create_install_dirs()?; let download = Script::Download(install_type.clone()); let install = Script::Install(install_type); - if self.script_man.script_exists(&download) { - if settings.verbose { - self.script_man - .cmd(download) - .stdout_to_stderr() - .run() - .map_err(|err| { - self.cleanup_install_dirs_on_error(settings); - err - })?; - } else { - self.script_man.run_with_hidden_output(download, || { + let run_script = |script| { + self.script_man.run_by_line( + script, + |output| { self.cleanup_install_dirs_on_error(settings); - })?; - } - } + pr.finish_with_message(format!("error {}", COLOR.red("✗"))); + if !settings.verbose && !output.trim().is_empty() { + pr.println(output); + } + }, + |line| { + pr.set_message(line.into()); + }, + ) + }; - if settings.verbose { - self.script_man - .cmd(install) - .stdout_to_stderr() - .run() - .map_err(|err| { - self.cleanup_install_dirs_on_error(settings); - err - })?; - self.cleanup_install_dirs(settings); - } else { - self.script_man.run_with_hidden_output(install, || { - self.cleanup_install_dirs_on_error(settings); - })?; + if self.script_man.script_exists(&download) { + pr.set_message("downloading".into()); + run_script(download)?; } + pr.set_message("installing".into()); + run_script(install)?; self.cleanup_install_dirs(settings); let conf = RuntimeConf { @@ -134,7 +134,7 @@ impl RuntimeVersion { debug!("error touching config file: {:?} {:?}", path, err); } } - sp.success(format!("Runtime {rtv_label} installed")); + pr.finish_with_message(COLOR.green("✓")); Ok(()) } @@ -160,12 +160,20 @@ impl RuntimeVersion { } match config.settings.missing_runtime_behavior { MissingRuntimeBehavior::AutoInstall => { - self.install(InstallType::Version, config)?; + self.install( + InstallType::Version, + config, + ProgressReport::new(config.settings.verbose), + )?; Ok(true) } MissingRuntimeBehavior::Prompt => { if prompt::prompt_for_install(&COLOR.cyan(&self.to_string())) { - self.install(InstallType::Version, config)?; + self.install( + InstallType::Version, + config, + ProgressReport::new(config.settings.verbose), + )?; Ok(true) } else { Ok(false) diff --git a/src/test.rs b/src/test.rs index d9e6c3b51..a1b73749b 100644 --- a/src/test.rs +++ b/src/test.rs @@ -27,7 +27,6 @@ fn init() { "tiny", "https://github.com/jdxcode/asdf-tiny" ); - assert_cli!("install", "--all"); } pub fn reset_config() { @@ -39,6 +38,7 @@ pub fn reset_config() { always_keep_download= true legacy_version_file= true plugin_autoupdate_last_check_duration = 20 + jobs = 2 [alias.shfmt] "my/alias" = '3.0' diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs new file mode 100644 index 000000000..10f280b8f --- /dev/null +++ b/src/toolset/builder.rs @@ -0,0 +1,122 @@ +use color_eyre::eyre::Result; +use indexmap::IndexMap; +use itertools::Itertools; +use rayon::prelude::*; + +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; +use crate::config::config_file::legacy_version::LegacyVersionFile; +use crate::config::config_file::ConfigFile; +use crate::config::{config_file, Config}; + +use crate::toolset::tool_version::ToolVersionType; +use crate::toolset::{ToolSource, ToolVersion, Toolset}; +use crate::{env, file}; + +#[derive(Debug)] +pub struct ToolsetBuilder { + args: Vec, + install_missing: bool, +} + +impl ToolsetBuilder { + pub fn new() -> Self { + Self { + args: Vec::new(), + install_missing: false, + } + } + + pub fn with_args(mut self, args: &[RuntimeArg]) -> Self { + self.args = args.to_vec(); + self + } + + pub fn with_install_missing(mut self) -> Self { + self.install_missing = true; + self + } + + pub fn build(self, config: &Config) -> Toolset { + let mut toolset = Toolset::default().with_plugins(config.plugins.clone()); + load_config_files(config, &mut toolset); + load_runtime_env(&mut toolset, env::vars().collect()); + load_runtime_args(&mut toolset, &self.args); + toolset.resolve(config); + + if self.install_missing { + if let Err(e) = toolset.install_missing(config) { + warn!("Error installing runtimes: {}", e); + }; + } + + debug!("{}", toolset); + toolset + } +} + +fn load_config_files(config: &Config, ts: &mut Toolset) { + let toolsets: Vec<_> = config + .config_files + .par_iter() + .rev() + .filter_map(|path| { + let filename = path.file_name().unwrap().to_string_lossy().to_string(); + let result: Result = match config.legacy_files.get(&filename) { + Some(plugin) => LegacyVersionFile::parse( + &config.settings, + path.into(), + config.plugins.get(plugin).unwrap(), + ) + .map(|cf| cf.to_toolset()), + None => config_file::parse(path).map(|cf| cf.to_toolset()), + }; + match result { + Ok(ts) => Some(ts), + Err(e) => { + warn!("error parsing config file: {}", e); + warn!("file: {}", file::display_path(path)); + None + } + } + }) + .collect(); + for toolset in toolsets { + ts.merge(toolset); + } +} + +fn load_runtime_env(ts: &mut Toolset, env: IndexMap) { + for (k, v) in env { + if k.starts_with("RTX_") && k.ends_with("_VERSION") { + let plugin_name = k[4..k.len() - 8].to_lowercase(); + let source = ToolSource::Environment(k, v.clone()); + let mut env_ts = Toolset::new(source); + let version = ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v)); + env_ts.add_version(plugin_name, version); + ts.merge(env_ts); + } + } +} + +fn load_runtime_args(ts: &mut Toolset, args: &[RuntimeArg]) { + for (plugin_name, args) in args.iter().into_group_map_by(|arg| arg.plugin.clone()) { + let mut arg_ts = Toolset::new(ToolSource::Argument); + for arg in args { + match arg.version { + RuntimeArgVersion::Version(ref v) => { + let version = + ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v.clone())); + arg_ts.add_version(plugin_name.clone(), version); + } + // I believe this will do nothing since it would just default to the `.tool-versions` version + // RuntimeArgVersion::None => { + // arg_ts.add_version(plugin_name.clone(), ToolVersion::None); + // }, + _ => { + trace!("ignoring: {:?}", arg); + } + } + } + ts.merge(arg_ts); + } +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs new file mode 100644 index 000000000..38d0fc276 --- /dev/null +++ b/src/toolset/mod.rs @@ -0,0 +1,332 @@ +use std::env::join_paths; +use std::fmt::{Display, Formatter}; +use std::path::PathBuf; +use std::sync::Arc; + +use atty::Stream; +use color_eyre::eyre::Result; +use indexmap::IndexMap; +use itertools::Itertools; +use once_cell::sync::Lazy; +use rayon::prelude::*; +use rayon::ThreadPoolBuilder; + +pub use builder::ToolsetBuilder; +pub use tool_source::ToolSource; +pub use tool_version::ToolVersion; +pub use tool_version::ToolVersionType; + +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; +use crate::config::{Config, MissingRuntimeBehavior}; +use crate::env; +use crate::plugins::{Plugin, PluginName}; +use crate::runtimes::RuntimeVersion; +use crate::toolset::tool_version_list::ToolVersionList; +use crate::ui::color::Color; +use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::prompt; + +mod builder; +mod tool_source; +mod tool_version; +mod tool_version_list; + +/// a toolset is a collection of tools for various plugins +/// +/// one example is a .tool-versions file +/// the idea is that we start with an empty toolset, then +/// merge in other toolsets from various sources +#[derive(Debug, Default)] +pub struct Toolset { + pub versions: IndexMap, + source: Option, + plugins: IndexMap, +} + +impl Toolset { + pub fn new(source: ToolSource) -> Self { + Self { + source: Some(source), + ..Default::default() + } + } + pub fn with_plugins(mut self, plugins: IndexMap) -> Self { + self.plugins = plugins; + self + } + pub fn add_version(&mut self, plugin: PluginName, version: ToolVersion) { + let versions = self + .versions + .entry(plugin) + .or_insert_with(|| ToolVersionList::new(self.source.clone().unwrap())); + versions.add_version(version); + } + pub fn merge(&mut self, other: Toolset) { + for plugin in other.versions.keys() { + self.versions.shift_remove(plugin); + } + for (plugin, versions) in other.versions { + self.versions.insert(plugin, versions); + } + self.source = other.source; + } + pub fn resolve(&mut self, config: &Config) { + self.versions + .iter_mut() + .collect::>() + .par_iter_mut() + .for_each(|(p, v)| { + let plugin = match self.plugins.get(&p.to_string()) { + Some(p) => p, + None => { + debug!("Plugin {} not found", p); + return; + } + }; + if let Err(e) = v.resolve(&config.settings, plugin) { + warn!("Error resolving plugin versions: {}", e); + } + }); + } + pub fn install_missing(&mut self, config: &Config) -> Result<()> { + let versions = self.list_missing_versions_mut(); + if versions.is_empty() { + return Ok(()); + } + let display_versions = display_versions(&versions); + let plural_versions = if versions.len() == 1 { "" } else { "s" }; + let warn = || { + warn!( + "Tool{} not installed: {}", + plural_versions, display_versions + ); + }; + match config.settings.missing_runtime_behavior { + MissingRuntimeBehavior::Ignore => {} + MissingRuntimeBehavior::Warn => { + warn(); + } + MissingRuntimeBehavior::Prompt => { + if prompt::prompt_for_install(&display_versions) { + self.install_missing_versions(config)?; + } else { + warn(); + } + } + MissingRuntimeBehavior::AutoInstall => { + self.install_missing_versions(config)?; + } + } + Ok(()) + } + + pub fn list_missing_plugins(&self) -> Vec { + self.versions + .keys() + .filter(|p| !self.plugins.contains_key(*p)) + .cloned() + .collect() + } + + fn install_missing_versions(&mut self, config: &Config) -> Result<()> { + ThreadPoolBuilder::new() + .num_threads(config.settings.jobs) + .build() + .unwrap() + .install(|| -> Result<()> { + let mpr = MultiProgressReport::new(config.settings.verbose); + self.install_missing_plugins(config, &mpr)?; + self.versions + .iter_mut() + .par_bridge() + .filter_map(|(p, v)| { + let versions = v + .versions + .iter_mut() + .filter(|v| v.is_missing()) + .collect_vec(); + let plugin = self.plugins.get(&p.to_string()).unwrap(); + match versions.is_empty() { + true => None, + false => Some((plugin, versions)), + } + }) + .map(|(plugin, versions)| { + for version in versions { + version.resolve(&config.settings, plugin)?; + version.install(config, mpr.add())?; + } + Ok(()) + }) + .collect::>>()?; + Ok(()) + }) + } + fn install_missing_plugins( + &mut self, + config: &Config, + mpr: &MultiProgressReport, + ) -> Result<()> { + let missing_plugins = self.list_missing_plugins(); + if missing_plugins.is_empty() { + return Ok(()); + } + let plugins = missing_plugins + .into_par_iter() + .map(|plugin_name| { + let mut plugin = Plugin::new(&plugin_name); + if !plugin.is_installed() { + plugin.install(&config.settings, None, mpr.add())?; + } + Ok(plugin) + }) + .collect::>>()?; + for plugin in plugins { + self.plugins.insert(plugin.name.clone(), plugin); + } + self.plugins.sort_keys(); + Ok(()) + } + + fn list_missing_versions_mut(&mut self) -> Vec<&mut ToolVersion> { + let versions = self + .versions + .values_mut() + .flat_map(|v| { + v.versions + .iter_mut() + .filter(|v| v.is_missing()) + .collect_vec() + }) + .collect_vec(); + versions + } + pub fn list_installed_versions(&self) -> Result> { + let versions = self + .plugins + .values() + .collect_vec() + .into_par_iter() + .map(|p| { + let versions = p.list_installed_versions()?; + Ok(versions + .into_iter() + .map(|v| RuntimeVersion::new(Arc::new(p.clone()), &v))) + }) + .collect::>>()? + .into_iter() + .flatten() + .collect(); + + Ok(versions) + } + pub fn list_versions_by_plugin(&self) -> IndexMap> { + self.versions + .iter() + .filter_map(|(p, v)| match self.plugins.get(&p.to_string()) { + Some(plugin) => { + let plugin = Arc::new(plugin.clone()); + let versions = v.resolved_versions(); + Some((plugin.name.clone(), versions)) + } + None => { + debug!("Plugin {} not found", p); + None + } + }) + .collect() + } + pub fn list_current_versions(&self) -> Vec<&RuntimeVersion> { + self.list_versions_by_plugin() + .into_iter() + .flat_map(|(_, v)| v) + .collect() + } + pub fn list_current_installed_versions(&self) -> Vec<&RuntimeVersion> { + self.list_current_versions() + .into_iter() + .filter(|v| v.is_installed()) + .collect() + } + pub fn env(&self) -> IndexMap { + let mut entries: Vec<(String, String)> = self + .list_current_installed_versions() + .into_par_iter() + .flat_map(|p| match p.exec_env() { + Ok(env) => env.into_iter().collect(), + Err(e) => { + warn!("Error running exec-env: {}", e); + Vec::new() + } + }) + .collect(); + entries.par_sort(); + entries.into_iter().collect() + } + pub fn path_env(&self) -> String { + let installs = self.list_paths(); + join_paths([installs, env::PATH.clone()].concat()) + .unwrap() + .to_string_lossy() + .into() + } + pub fn list_paths(&self) -> Vec { + self.list_current_installed_versions() + .into_par_iter() + .rev() + .flat_map(|rtv| match rtv.list_bin_paths() { + Ok(paths) => paths, + Err(e) => { + warn!("Error listing bin paths for {}: {}", rtv, e); + Vec::new() + } + }) + .collect() + } + pub fn resolve_runtime_arg(&self, arg: &RuntimeArg) -> Option<&RuntimeVersion> { + match &arg.version { + RuntimeArgVersion::System => None, + RuntimeArgVersion::Version(version) => { + if let Some(tvl) = self.versions.get(&arg.plugin) { + for tv in tvl.versions.iter() { + match &tv.r#type { + ToolVersionType::Version(v) if v == version => { + return tv.rtv.as_ref(); + } + _ => (), + } + } + } + None + } + RuntimeArgVersion::None => { + let plugin = self.versions.get(&arg.plugin); + match plugin { + Some(tvl) => tvl.versions.first().unwrap().rtv.as_ref(), + None => None, + } + } + } + } +} + +impl Display for Toolset { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let plugins = &self + .versions + .iter() + .map(|(_, v)| v.versions.iter().map(|v| v.to_string()).join(" ")) + .collect_vec(); + write!(f, "Toolset: {}", plugins.join(", ")) + } +} + +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); + +fn display_versions(versions: &[&mut ToolVersion]) -> String { + let display_versions = versions + .iter() + .map(|v| COLOR.cyan(&v.to_string())) + .join(", "); + display_versions +} diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs new file mode 100644 index 000000000..6daf97f45 --- /dev/null +++ b/src/toolset/tool_source.rs @@ -0,0 +1,25 @@ +use crate::file::display_path; +use std::fmt::{Display, Formatter}; +use std::path::PathBuf; + +/// where a tool version came from (e.g.: .tool-versions) +#[derive(Debug, Clone)] +pub enum ToolSource { + ToolVersions(PathBuf), + // RtxRc(PathBuf), + LegacyVersionFile(PathBuf), + Argument, + Environment(String, String), +} + +impl Display for ToolSource { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + match self { + ToolSource::ToolVersions(path) => write!(f, "{}", display_path(path)), + // ToolSource::RtxRc(path) => write!(f, "{}", display_path(path)), + ToolSource::LegacyVersionFile(path) => write!(f, "{}", display_path(path)), + ToolSource::Argument => write!(f, "--runtime"), + ToolSource::Environment(k, v) => write!(f, "{k}={v}"), + } + } +} diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs new file mode 100644 index 000000000..c101a61cd --- /dev/null +++ b/src/toolset/tool_version.rs @@ -0,0 +1,126 @@ +use std::fmt::{Display, Formatter}; +use std::sync::Arc; + +use color_eyre::eyre::Result; + +use crate::config::{Config, Settings}; +use crate::errors::Error::VersionNotFound; +use crate::plugins::{InstallType, Plugin}; +use crate::runtimes::RuntimeVersion; +use crate::ui::progress_report::ProgressReport; + +/// represents a single version of a tool for a particular plugin +#[derive(Debug, Clone)] +pub struct ToolVersion { + pub plugin_name: String, + pub r#type: ToolVersionType, + pub rtv: Option, +} + +#[derive(Debug, Clone)] +pub enum ToolVersionType { + Version(String), + Prefix(String), + Ref(String), + Path(String), + System, +} + +impl ToolVersion { + pub fn new(plugin_name: String, r#type: ToolVersionType) -> Self { + Self { + plugin_name, + r#type, + rtv: None, + } + } + + pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) -> Result<()> { + if self.rtv.is_some() { + return Ok(()); + } + match self.r#type.clone() { + ToolVersionType::Version(v) => self.resolve_version(settings, plugin, &v), + ToolVersionType::Prefix(v) => self.resolve_prefix(plugin, &v), + ToolVersionType::Ref(_) => unimplemented!(), + ToolVersionType::Path(_) => unimplemented!(), + ToolVersionType::System => Ok(()), + } + } + + fn resolve_version(&mut self, settings: &Settings, plugin: &Plugin, v: &str) -> Result<()> { + let v = resolve_alias(settings, plugin, v); + + let matches = plugin.list_versions_matching(&v); + if matches.contains(&v) { + self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), &v)); + Ok(()) + } else { + self.resolve_prefix(plugin, &v) + } + } + + fn resolve_prefix(&mut self, plugin: &Plugin, prefix: &str) -> Result<()> { + match plugin.list_versions_matching(prefix).last() { + Some(v) => { + self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), v)); + Ok(()) + } + None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, + } + } + + pub fn is_missing(&self) -> bool { + match self.rtv { + Some(ref rtv) => !rtv.is_installed(), + None => true, + } + } + + pub fn install(&mut self, config: &Config, pr: ProgressReport) -> Result<()> { + match self.r#type { + ToolVersionType::Version(_) | ToolVersionType::Prefix(_) => { + self.rtv + .as_ref() + .unwrap() + .install(InstallType::Version, config, pr)?; + } + ToolVersionType::Ref(_) => { + self.rtv + .as_ref() + .unwrap() + .install(InstallType::Ref, config, pr)?; + } + _ => (), + } + if matches!(self.r#type, ToolVersionType::System) { + return Ok(()); + } + Ok(()) + } +} + +impl Display for ToolVersion { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let plugin = &self.plugin_name; + match &self.r#type { + ToolVersionType::Version(v) => write!(f, "{plugin}@{v}"), + ToolVersionType::Prefix(p) => write!(f, "{plugin}@prefix:{p}"), + ToolVersionType::Ref(r) => write!(f, "{plugin}@ref:{r}"), + ToolVersionType::Path(p) => write!(f, "{plugin}@path:{p}"), + ToolVersionType::System => write!(f, "{plugin}@system"), + } + } +} + +pub fn resolve_alias(settings: &Settings, plugin: &Plugin, v: &str) -> String { + if let Some(plugin_aliases) = settings.aliases.get(&plugin.name) { + if let Some(alias) = plugin_aliases.get(v) { + return alias.clone(); + } + } + if let Some(alias) = plugin.get_aliases().get(v) { + return alias.clone(); + } + v.to_string() +} diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs new file mode 100644 index 000000000..61361e46e --- /dev/null +++ b/src/toolset/tool_version_list.rs @@ -0,0 +1,38 @@ +use color_eyre::eyre::Result; + +use crate::config::Settings; +use crate::plugins::Plugin; +use crate::runtimes::RuntimeVersion; + +use crate::toolset::{ToolSource, ToolVersion}; + +/// represents several versions of a tool for a particular plugin +#[derive(Debug, Clone)] +pub struct ToolVersionList { + pub versions: Vec, + pub source: ToolSource, +} + +impl ToolVersionList { + pub fn new(source: ToolSource) -> Self { + Self { + versions: Vec::new(), + source, + } + } + pub fn add_version(&mut self, version: ToolVersion) { + self.versions.push(version); + } + pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) -> Result<()> { + for tv in &mut self.versions { + tv.resolve(settings, plugin)?; + } + Ok(()) + } + pub fn resolved_versions(&self) -> Vec<&RuntimeVersion> { + self.versions + .iter() + .filter_map(|v| v.rtv.as_ref()) + .collect() + } +} diff --git a/src/ui/color.rs b/src/ui/color.rs index c641690ae..888bc4fd9 100644 --- a/src/ui/color.rs +++ b/src/ui/color.rs @@ -1,26 +1,9 @@ use atty::Stream; use owo_colors::OwoColorize; -pub fn dimmed(stream: Stream, s: &str) -> String { - s.if_supports_color(stream, |s| s.dimmed()).to_string() -} -pub fn _yellow(stream: Stream, s: &str) -> String { - s.if_supports_color(stream, |s| s.yellow()).to_string() -} pub fn cyan(stream: Stream, s: &str) -> String { s.if_supports_color(stream, |s| s.cyan()).to_string() } -pub fn green(stream: Stream, s: &str) -> String { - s.if_supports_color(stream, |s| s.green()).to_string() -} -pub fn _bright_green(stream: Stream, s: &str) -> String { - s.if_supports_color(stream, |s| s.bright_green()) - .to_string() -} - -pub fn red(stream: Stream, s: &str) -> String { - s.if_supports_color(stream, |s| s.red()).to_string() -} pub struct Color { stream: Stream, @@ -51,4 +34,15 @@ impl Color { pub fn cyan(&self, s: &str) -> String { s.if_supports_color(self.stream, |s| s.cyan()).to_string() } + + pub fn green(&self, s: &str) -> String { + s.if_supports_color(self.stream, |s| s.green()).to_string() + } + pub fn red(&self, s: &str) -> String { + s.if_supports_color(self.stream, |s| s.red()).to_string() + } + pub fn bright_yellow(&self, s: &str) -> String { + s.if_supports_color(self.stream, |s| s.bright_yellow()) + .to_string() + } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index b4804e850..09896916f 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,3 +1,4 @@ pub mod color; +pub mod multi_progress_report; +pub mod progress_report; pub mod prompt; -pub mod spinner; diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs new file mode 100644 index 000000000..111067b4f --- /dev/null +++ b/src/ui/multi_progress_report.rs @@ -0,0 +1,35 @@ +use crate::ui::progress_report::ProgressReport; +use indicatif::MultiProgress; + +pub struct MultiProgressReport { + mp: Option, +} + +impl MultiProgressReport { + pub fn new(verbose: bool) -> Self { + match verbose { + true => Self { mp: None }, + false => Self { + mp: Some(MultiProgress::new()), + }, + } + } + pub fn add(&self) -> ProgressReport { + match &self.mp { + Some(mp) => { + let mut pr = ProgressReport::new(false); + pr.pb = Some(mp.add(pr.pb.unwrap())); + pr + } + None => ProgressReport::new(true), + } + } + // pub fn clear(&self) { + // match &self.mp { + // Some(mp) => { + // let _ = mp.clear(); + // }, + // None => () + // } + // } +} diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs new file mode 100644 index 000000000..e8c6de58b --- /dev/null +++ b/src/ui/progress_report.rs @@ -0,0 +1,70 @@ +use crate::ui::color::Color; +use atty::Stream; +use indicatif::ProgressBar; +use once_cell::sync::Lazy; +use std::time::Duration; + +#[derive(Debug)] +pub struct ProgressReport { + pub pb: Option, + prefix: String, +} + +impl ProgressReport { + pub fn new(verbose: bool) -> ProgressReport { + let pb = match verbose { + true => None, + false => Some(ProgressBar::new(0)), + }; + ProgressReport { + pb, + prefix: String::new(), + } + } + + pub fn enable_steady_tick(&self) { + match &self.pb { + Some(pb) => pb.enable_steady_tick(Duration::from_millis(100)), + None => (), + } + } + + pub fn set_prefix(&mut self, prefix: String) { + match &self.pb { + Some(pb) => pb.set_prefix(prefix), + None => { + self.prefix = prefix; + } + } + } + + pub fn set_style(&self, style: indicatif::ProgressStyle) { + match &self.pb { + Some(pb) => { + pb.set_style(style); + pb.set_prefix(COLOR.dimmed("rtx")); + } + None => (), + } + } + pub fn set_message(&self, message: String) { + match &self.pb { + Some(pb) => pb.set_message(message), + None => eprintln!("{}{message}", self.prefix), + } + } + pub fn println(&self, message: String) { + match &self.pb { + Some(pb) => pb.println(message), + None => eprintln!("{message}"), + } + } + pub fn finish_with_message(&self, message: String) { + match &self.pb { + Some(pb) => pb.finish_with_message(message), + None => eprintln!("{}{message}", self.prefix), + } + } +} + +static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 8ae444d84..e501c3580 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -13,21 +13,23 @@ pub fn prompt() -> String { } pub fn prompt_for_install(thing: &str) -> bool { - match is_tty() { + match console::user_attended_stderr() { true => { + let stderr = console::Term::stderr(); eprint!( "{} Would you like to install {}? [Y/n] ", - COLOR.dimmed("rtx:"), + COLOR.dimmed("rtx"), thing, ); - matches!(prompt().to_lowercase().as_str(), "" | "y" | "yes") + let yn = matches!(prompt().to_lowercase().as_str(), "" | "y" | "yes"); + let _ = stderr.move_cursor_up(1); + let _ = stderr.clear_to_end_of_screen(); + yn } false => false, } } pub fn is_tty() -> bool { - atty::is(atty::Stream::Stdin) - && atty::is(atty::Stream::Stderr) - && atty::is(atty::Stream::Stdout) + atty::is(atty::Stream::Stdin) && atty::is(atty::Stream::Stderr) } diff --git a/src/ui/spinner.rs b/src/ui/spinner.rs deleted file mode 100644 index 8f55ba990..000000000 --- a/src/ui/spinner.rs +++ /dev/null @@ -1,29 +0,0 @@ -use spinoff::{spinners, Color, Streams}; - -pub struct Spinner { - spinner: Option, -} - -impl Spinner { - pub fn start(message: String, verbose: bool) -> Spinner { - let sp = match verbose { - true => { - eprintln!("{message}"); - None - } - false => Some(spinoff::Spinner::new_with_stream( - spinners::Dots10, - message, - Color::Blue, - Streams::Stderr, - )), - }; - Spinner { spinner: sp } - } - - pub fn success(&mut self, message: String) { - if let Some(sp) = self.spinner.take() { - sp.success(&message); - } - } -} diff --git a/test/config/config.toml b/test/config/config.toml index 517c8c3a4..e75e742c1 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -3,6 +3,7 @@ missing_runtime_behavior= 'autoinstall' always_keep_download= true legacy_version_file= true plugin_autoupdate_last_check_duration = 20 +jobs = 2 [alias.shfmt] "my/alias" = '3.0' From aac40aa258602a3e6716d6c838e2c62b9ae176e0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 18 Feb 2023 21:50:29 -0600 Subject: [PATCH 0164/1891] cargo update --- Cargo.lock | 50 +++++++++++++++++++++++++------------------------- Cargo.toml | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20eb21882..7cc63a157 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,9 +133,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.4" +version = "4.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" dependencies = [ "bitflags", "clap_derive", @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" +checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" dependencies = [ "clap", ] @@ -297,9 +297,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90d59d9acd2a682b4e40605a242f6670eaa58c5957471cbf85e8aa6a0b97a5e8" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" dependencies = [ "cc", "cxxbridge-flags", @@ -309,9 +309,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfa40bda659dd5c864e65f4c9a2b0aff19bea56b017b9b77c73d3766a453a38" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" dependencies = [ "cc", "codespan-reporting", @@ -324,15 +324,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "457ce6757c5c70dc6ecdbda6925b958aae7f959bda7d8fb9bde889e34a09dc03" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" [[package]] name = "cxxbridge-macro" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf883b7aacd7b2aeb2a7b338648ee19f57c140d4ee8e52c68979c6b2f7f2263" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", @@ -446,9 +446,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -497,9 +497,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "hashbrown" @@ -613,9 +613,9 @@ checksum = "6fe2b9d82064e8a0226fddb3547f37f28eaa46d0fc210e275d835f08cf3b76a7" [[package]] name = "insta" -version = "1.26.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f0f08b46e4379744de2ab67aa8f7de3ffd1da3e275adc41fcc82053ede46ff" +checksum = "fea5b3894afe466b4bcf0388630fc15e11938a6074af0cd637c825ba2ec8a099" dependencies = [ "console", "lazy_static", @@ -831,9 +831,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "os_pipe" @@ -1199,7 +1199,7 @@ checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" dependencies = [ "log", "termcolor", - "time 0.3.17", + "time 0.3.19", ] [[package]] @@ -1316,9 +1316,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2" dependencies = [ "itoa", "libc", @@ -1336,9 +1336,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c" dependencies = [ "time-core", ] diff --git a/Cargo.toml b/Cargo.toml index 8e8108a23..02481af25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ env_logger = "0.10.0" insta = "1.26.0" pretty_assertions = "1.3.0" tempfile = "3.3.0" -test-log = "*" +test-log = "0.2" [profile.release] debug = 1 # show line numbers in backtrace From a238ca343a19e0e27dd27c00058353aa07b27bc8 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sun, 19 Feb 2023 04:52:11 +0100 Subject: [PATCH 0165/1891] add version update check on rtx version #74 (#142) * feat: add version update check on rtx version (#74) * feat: use reqwest instead of minreq (#74) * feat: fix linting errors (#74) --------- Co-authored-by: Roland Schaer Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- Cargo.lock | 507 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/cli/doctor.rs | 9 + src/cli/version.rs | 42 +++- 4 files changed, 558 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7cc63a157..833ed8e88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,6 +104,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + [[package]] name = "cc" version = "1.0.79" @@ -227,6 +233,16 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -390,6 +406,15 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -475,6 +500,27 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -484,6 +530,54 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" + +[[package]] +name = "futures-io" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" + +[[package]] +name = "futures-sink" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" + +[[package]] +name = "futures-task" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" + +[[package]] +name = "futures-util" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "getrandom" version = "0.2.8" @@ -501,6 +595,25 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +[[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -537,12 +650,83 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "0.14.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -643,6 +827,12 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + [[package]] name = "is-terminal" version = "0.4.3" @@ -742,6 +932,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -757,6 +953,36 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.45.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nom" version = "7.1.3" @@ -835,6 +1061,61 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "openssl" +version = "0.10.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "111.25.0+1.1.1t" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3173cd3626c43e3854b1b727422a276e568d9ec5fe8cec197822cf52cfb743d6" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" +dependencies = [ + "autocfg", + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_pipe" version = "1.1.3" @@ -887,6 +1168,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "portable-atomic" version = "0.3.19" @@ -1015,6 +1308,43 @@ dependencies = [ "winapi", ] +[[package]] +name = "reqwest" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rmp" version = "0.8.11" @@ -1065,10 +1395,12 @@ dependencies = [ "log", "num_cpus", "once_cell", + "openssl", "owo-colors", "pretty_assertions", "rayon", "regex", + "reqwest", "rmp-serde", "serde", "serde_derive", @@ -1111,6 +1443,15 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1123,6 +1464,29 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.152" @@ -1160,6 +1524,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -1199,6 +1575,37 @@ checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" dependencies = [ "log", "termcolor", + "time 0.3.17", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spinoff" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee259f96b31e7a18657d11741fe30d63f98e07de70e7a19d2b705ab9b331cdc" +dependencies = [ + "colored", + "once_cell", + "paste", "time 0.3.19", ] @@ -1358,6 +1765,47 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys 0.42.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + [[package]] name = "toml" version = "0.7.2" @@ -1392,6 +1840,12 @@ dependencies = [ "toml_datetime", ] +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.37" @@ -1434,6 +1888,12 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + [[package]] name = "unicode-bidi" version = "0.3.10" @@ -1478,6 +1938,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1494,6 +1960,16 @@ dependencies = [ "nom", ] +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -1531,6 +2007,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.84" @@ -1560,6 +2048,16 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1672,6 +2170,15 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 02481af25..9b12613f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,9 +46,11 @@ lazy_static = "1.4.0" log = "0.4.17" num_cpus = "1.15.0" once_cell = "1.17.0" +openssl = { version = "0.10", features = ["vendored"] } owo-colors = { version = "3.5.0", features = ["supports-colors"] } rayon = "1.6.1" regex = "1.7.1" +reqwest = { version = "0.11.14", features = ["blocking"] } rmp-serde = "1.1.1" serde = "1.0.152" serde_derive = "1.0.152" diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 709ba6f4e..afdf9ca95 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -3,6 +3,7 @@ use color_eyre::eyre::{eyre, Result}; use indoc::formatdoc; use once_cell::sync::Lazy; +use crate::cli; use crate::cli::command::Command; use crate::config::Config; use crate::env; @@ -24,6 +25,14 @@ impl Command for Doctor { } } + if let Some(latest) = cli::version::check_for_new_version() { + warn!( + "new rtx version {} available, currently on {}", + latest, + env!("CARGO_PKG_VERSION") + ) + } + if env::var("__RTX_DIFF").is_err() { checks.push( "rtx is not activated, run `rtx help activate` for setup instructions".to_string(), diff --git a/src/cli/version.rs b/src/cli/version.rs index e55083a39..0dcd6ece8 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,7 +1,8 @@ -use std::string::ToString; - use color_eyre::eyre::Result; use once_cell::sync::Lazy; +use std::string::ToString; +use std::time::Duration; +use versions::Versioning; use crate::build_time::BUILD_TIME; use crate::cli::command::Command; @@ -55,6 +56,43 @@ pub fn print_version_if_requested(args: &[String], out: &mut Output) { fn show_version(out: &mut Output) { rtxprintln!(out, "{}", *VERSION); + show_latest(); +} + +fn show_latest() { + if let Some(latest) = check_for_new_version() { + warn!("rtx version {} available", latest) + } +} + +pub fn check_for_new_version() -> Option { + if let Some(latest) = get_latest_version() { + let current = Versioning::new(env!("CARGO_PKG_VERSION")).unwrap(); + if current < latest { + return Some(latest.to_string()); + } + } + None +} + +fn get_latest_version() -> Option { + reqwest::blocking::ClientBuilder::new() + .timeout(Duration::from_secs(1)) + .build() + .ok()? + .get("https://rtx.jdxcode.com/VERSION") + .send() + .ok() + .and_then(|res| { + if res.status().is_success() { + return res + .text() + .ok() + .and_then(|text| Versioning::new(text.as_str().trim())); + } + debug!("failed to check for version: {:#?}", res); + None + }) } #[cfg(test)] From a362764b4b68bd30d6520ae57bebd69f697f6c15 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 18 Feb 2023 21:53:59 -0600 Subject: [PATCH 0166/1891] cargo update --- Cargo.lock | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 833ed8e88..cb54546ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1575,7 +1575,7 @@ checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" dependencies = [ "log", "termcolor", - "time 0.3.17", + "time 0.3.19", ] [[package]] @@ -1597,18 +1597,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "spinoff" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee259f96b31e7a18657d11741fe30d63f98e07de70e7a19d2b705ab9b331cdc" -dependencies = [ - "colored", - "once_cell", - "paste", - "time 0.3.19", -] - [[package]] name = "strsim" version = "0.10.0" From 9a8b50a675e3481a80e689c92a7e1e94592ed838 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 18 Feb 2023 21:54:21 -0600 Subject: [PATCH 0167/1891] chore: Release rtx-cli version 1.10.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb54546ad..8fe179a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1369,7 +1369,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.9.0" +version = "1.10.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 9b12613f4..46f35fae5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.9.0" +version = "1.10.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index eb2fb8c85..5e60c06e7 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.9.0 +rtx 1.10.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -204,7 +204,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.9.0/rtx-v1.9.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.0/rtx-v1.10.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 47e5d62f0..7a6838be6 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.9.0 +Version: 1.10.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 2e617ce42..bffb400ee 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -223,7 +223,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.9.0/rtx-v1.9.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.0/rtx-v1.10.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From c623a251cd65e14474df13f036a0572aa914a5ea Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 18 Feb 2023 22:49:27 -0600 Subject: [PATCH 0168/1891] chore: release updates --- .github/workflows/rtx.yml | 9 ++++++++- scripts/release-aur.sh | 14 ++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index a25dab127..d11287792 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -251,7 +251,14 @@ jobs: draft: false files: releases/${{github.ref_name}}/* generate_release_notes: true - - name: Update Homebrew formula + bump-homebrew-formula: + runs-on: macos-latest + if: startsWith(github.event.ref, 'refs/tags/v') + needs: [ release ] + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Bump Homebrew formula uses: dawidd6/action-homebrew-bump-formula@v3 with: token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 97f25f80a..831b0cf50 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -1,8 +1,10 @@ #!/usr/bin/env bash set -euxo pipefail -VERSION=$(curl https://rtx.pub/VERSION | sed -e "s/^v//") -SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/v$VERSION.tar.gz" | sha512sum | awk '{print $1}') + +RTX_VERSION=$(./scripts/get-version.sh) + +SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') if [ ! -d aur ]; then git clone ssh://aur@aur.archlinux.org/rtx.git aur @@ -12,7 +14,7 @@ cat >aur/PKGBUILD < pkgname=rtx -pkgver=$VERSION +pkgver=${RTX_VERSION#v*} pkgrel=1 pkgdesc='Polyglot runtime manager' arch=('x86_64') @@ -50,7 +52,7 @@ EOF cat >aur/.SRCINFO < Date: Sat, 18 Feb 2023 23:12:03 -0600 Subject: [PATCH 0169/1891] docs: document jobs flag --- README.md | 8 +++ completions/_rtx | 148 ++++++++++++++++++++--------------------- completions/rtx.fish | 74 ++++++++++----------- src/cli/args/jobs.rs | 3 +- src/cli/install.rs | 2 + src/cli/render_help.rs | 6 ++ src/env.rs | 2 +- 7 files changed, 130 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index 5e60c06e7..0d0a226f2 100644 --- a/README.md +++ b/README.md @@ -376,6 +376,8 @@ always_keep_download = false # deleted after install by default # (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates +jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. + verbose = false # see explanation under `RTX_VERBOSE` [alias.nodejs] @@ -435,6 +437,10 @@ Output logs to a file. Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want to store the logs but not have them litter your display. +#### `RTX_JOBS=1` + +Set the number plugins or runtimes to install in parallel. The default is `4`. + #### `RTX_VERBOSE=1` This shows the installation output during `rtx install` and `rtx plugin install`. @@ -829,6 +835,8 @@ it won't be used simply by being installed, however. For that, you must set up a `.tool-version` file manually or with `rtx local/global`. Or you can call a runtime explicitly with `rtx exec @ -- `. +Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` + Usage: install [OPTIONS] [RUNTIME]... Arguments: diff --git a/completions/_rtx b/completions/_rtx index c4345ed38..c70d1d963 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -16,8 +16,8 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -38,8 +38,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-q[Hide the "rtx: @" message when changing directories]' \ '--quiet[Hide the "rtx: @" message when changing directories]' \ '*-v[Show installation output]' \ @@ -54,8 +54,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -75,8 +75,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -114,8 +114,8 @@ esac (asdf) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -128,8 +128,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -139,8 +139,8 @@ _arguments "${_arguments_options[@]}" \ (current) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -153,8 +153,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -165,8 +165,8 @@ _arguments "${_arguments_options[@]}" \ (direnv) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -184,8 +184,8 @@ _arguments "${_arguments_options[@]}" \ (envrc) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -195,8 +195,8 @@ _arguments "${_arguments_options[@]}" \ (exec) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -206,8 +206,8 @@ _arguments "${_arguments_options[@]}" \ (activate) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -253,8 +253,8 @@ esac (doctor) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -266,8 +266,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -280,8 +280,8 @@ _arguments "${_arguments_options[@]}" \ '()-c+[the command string to execute]:C: ' \ '()--command=[the command string to execute]:C: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -294,8 +294,8 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '--pin[save exact version to `.tool-versions`]' \ '--fuzzy[]' \ '*-v[Show installation output]' \ @@ -310,8 +310,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -323,8 +323,8 @@ _arguments "${_arguments_options[@]}" \ '()*-p+[only install runtime(s) for ]:PLUGIN: ' \ '()*--plugin=[only install runtime(s) for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-f[force reinstall even if already installed]' \ '--force[force reinstall even if already installed]' \ '(-p --plugin -f --force)-a[install all missing runtimes as well as all plugins for the current directory]' \ @@ -339,8 +339,8 @@ _arguments "${_arguments_options[@]}" \ (latest) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -353,8 +353,8 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from .tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-p[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--parent[recurse up to find a .tool-versions file rather than using the current directory only @@ -373,8 +373,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--plugin=[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ '*-v[Show installation output]' \ @@ -387,8 +387,8 @@ _arguments "${_arguments_options[@]}" \ (ls-remote) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -399,8 +399,8 @@ _arguments "${_arguments_options[@]}" \ (plugins) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ @@ -422,8 +422,8 @@ _arguments "${_arguments_options[@]}" \ (install) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ '(-f --force)-a[Install all missing plugins]' \ @@ -439,8 +439,8 @@ _arguments "${_arguments_options[@]}" \ (ls) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ @@ -454,8 +454,8 @@ _arguments "${_arguments_options[@]}" \ (ls-remote) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ '*-v[Show installation output]' \ @@ -467,8 +467,8 @@ _arguments "${_arguments_options[@]}" \ (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -479,8 +479,8 @@ _arguments "${_arguments_options[@]}" \ (update) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '()-a[update all plugins]' \ '()--all[update all plugins]' \ '*-v[Show installation output]' \ @@ -537,8 +537,8 @@ esac (settings) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -556,8 +556,8 @@ _arguments "${_arguments_options[@]}" \ (get) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -568,8 +568,8 @@ _arguments "${_arguments_options[@]}" \ (ls) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -579,8 +579,8 @@ _arguments "${_arguments_options[@]}" \ (set) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -592,8 +592,8 @@ _arguments "${_arguments_options[@]}" \ (unset) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -644,8 +644,8 @@ esac (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -656,8 +656,8 @@ _arguments "${_arguments_options[@]}" \ (version) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -667,8 +667,8 @@ _arguments "${_arguments_options[@]}" \ (where) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -680,8 +680,8 @@ _arguments "${_arguments_options[@]}" \ (render-help) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of parallel jobs to run]: : ' \ -'--jobs=[Number of parallel jobs to run]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 2b7631ee4..8949a8256 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,5 +1,5 @@ complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' @@ -29,13 +29,13 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal comm complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'Hide the "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -44,7 +44,7 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -52,25 +52,25 @@ Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -80,15 +80,15 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -98,45 +98,45 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'the command string to execute' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'save exact version to `.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'install all missing runtimes as well as all plugins for the current directory' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'save exact version to `.tool-versions`' @@ -145,16 +145,16 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -166,28 +166,28 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' @@ -198,7 +198,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -207,19 +207,19 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -228,19 +228,19 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of parallel jobs to run' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' diff --git a/src/cli/args/jobs.rs b/src/cli/args/jobs.rs index 6fdb94317..1ca6e29b4 100644 --- a/src/cli/args/jobs.rs +++ b/src/cli/args/jobs.rs @@ -14,8 +14,9 @@ impl Jobs { Arg::new("jobs") .short('j') .long("jobs") - .help("Number of parallel jobs to run") + .help("Number of plugins and runtimes to install in parallel") .value_parser(ValueParser::new(parse_jobs)) + .default_value("4") .global(true) } } diff --git a/src/cli/install.rs b/src/cli/install.rs index e8cbf25ab..060de0bdd 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -22,6 +22,8 @@ use crate::ui::color::Color; /// it won't be used simply by being installed, however. /// For that, you must set up a `.tool-version` file manually or with `rtx local/global`. /// Or you can call a runtime explicitly with `rtx exec @ -- `. +/// +/// Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` #[derive(Debug, clap::Args)] #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Install { diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index bffb400ee..7368dbae2 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -395,6 +395,8 @@ always_keep_download = false # deleted after install by default # (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates +jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. + verbose = false # see explanation under `RTX_VERBOSE` [alias.nodejs] @@ -454,6 +456,10 @@ Output logs to a file. Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want to store the logs but not have them litter your display. +#### `RTX_JOBS=1` + +Set the number plugins or runtimes to install in parallel. The default is `4`. + #### `RTX_VERBOSE=1` This shows the installation output during `rtx install` and `rtx plugin install`. diff --git a/src/env.rs b/src/env.rs index 9b0554ce8..6cdbcf9c1 100644 --- a/src/env.rs +++ b/src/env.rs @@ -88,7 +88,7 @@ lazy_static! { pub static ref RTX_JOBS: usize = var("RTX_JOBS") .ok() .and_then(|v| v.parse::().ok()) - .unwrap_or_else(num_cpus::get); + .unwrap_or(4); /// essentially, this is whether we show spinners or build output on runtime install pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); From d1544b0b8f0b847e0e4f6bfdb929b9b82b931b76 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 18 Feb 2023 23:41:08 -0600 Subject: [PATCH 0170/1891] test: fix default job count --- completions/_rtx | 148 +++++++++++++++++++++---------------------- completions/rtx.fish | 74 +++++++++++----------- src/cli/args/jobs.rs | 3 +- 3 files changed, 112 insertions(+), 113 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index c70d1d963..75cde431e 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -16,8 +16,8 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -38,8 +38,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-q[Hide the "rtx: @" message when changing directories]' \ '--quiet[Hide the "rtx: @" message when changing directories]' \ '*-v[Show installation output]' \ @@ -54,8 +54,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -75,8 +75,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -114,8 +114,8 @@ esac (asdf) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -128,8 +128,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -139,8 +139,8 @@ _arguments "${_arguments_options[@]}" \ (current) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -153,8 +153,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -165,8 +165,8 @@ _arguments "${_arguments_options[@]}" \ (direnv) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -184,8 +184,8 @@ _arguments "${_arguments_options[@]}" \ (envrc) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -195,8 +195,8 @@ _arguments "${_arguments_options[@]}" \ (exec) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -206,8 +206,8 @@ _arguments "${_arguments_options[@]}" \ (activate) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -253,8 +253,8 @@ esac (doctor) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -266,8 +266,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -280,8 +280,8 @@ _arguments "${_arguments_options[@]}" \ '()-c+[the command string to execute]:C: ' \ '()--command=[the command string to execute]:C: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -294,8 +294,8 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--pin[save exact version to `.tool-versions`]' \ '--fuzzy[]' \ '*-v[Show installation output]' \ @@ -310,8 +310,8 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -323,8 +323,8 @@ _arguments "${_arguments_options[@]}" \ '()*-p+[only install runtime(s) for ]:PLUGIN: ' \ '()*--plugin=[only install runtime(s) for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-f[force reinstall even if already installed]' \ '--force[force reinstall even if already installed]' \ '(-p --plugin -f --force)-a[install all missing runtimes as well as all plugins for the current directory]' \ @@ -339,8 +339,8 @@ _arguments "${_arguments_options[@]}" \ (latest) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -353,8 +353,8 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '*--remove=[remove the plugin(s) from .tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-p[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--parent[recurse up to find a .tool-versions file rather than using the current directory only @@ -373,8 +373,8 @@ _arguments "${_arguments_options[@]}" \ '-p+[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--plugin=[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ '*-v[Show installation output]' \ @@ -387,8 +387,8 @@ _arguments "${_arguments_options[@]}" \ (ls-remote) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -399,8 +399,8 @@ _arguments "${_arguments_options[@]}" \ (plugins) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ @@ -422,8 +422,8 @@ _arguments "${_arguments_options[@]}" \ (install) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ '(-f --force)-a[Install all missing plugins]' \ @@ -439,8 +439,8 @@ _arguments "${_arguments_options[@]}" \ (ls) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ @@ -454,8 +454,8 @@ _arguments "${_arguments_options[@]}" \ (ls-remote) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ '*-v[Show installation output]' \ @@ -467,8 +467,8 @@ _arguments "${_arguments_options[@]}" \ (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -479,8 +479,8 @@ _arguments "${_arguments_options[@]}" \ (update) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '()-a[update all plugins]' \ '()--all[update all plugins]' \ '*-v[Show installation output]' \ @@ -537,8 +537,8 @@ esac (settings) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -556,8 +556,8 @@ _arguments "${_arguments_options[@]}" \ (get) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -568,8 +568,8 @@ _arguments "${_arguments_options[@]}" \ (ls) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -579,8 +579,8 @@ _arguments "${_arguments_options[@]}" \ (set) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -592,8 +592,8 @@ _arguments "${_arguments_options[@]}" \ (unset) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -644,8 +644,8 @@ esac (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -656,8 +656,8 @@ _arguments "${_arguments_options[@]}" \ (version) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -667,8 +667,8 @@ _arguments "${_arguments_options[@]}" \ (where) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -680,8 +680,8 @@ _arguments "${_arguments_options[@]}" \ (render-help) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-j+[Number of plugins and runtimes to install in parallel]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 8949a8256..7cc60ae0a 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,5 +1,5 @@ complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' @@ -29,13 +29,13 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal comm complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'Hide the "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -44,7 +44,7 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -52,25 +52,25 @@ Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -80,15 +80,15 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -98,45 +98,45 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'the command string to execute' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'save exact version to `.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'install all missing runtimes as well as all plugins for the current directory' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'save exact version to `.tool-versions`' @@ -145,16 +145,16 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -166,28 +166,28 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' @@ -198,7 +198,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -207,19 +207,19 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -228,19 +228,19 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' diff --git a/src/cli/args/jobs.rs b/src/cli/args/jobs.rs index 1ca6e29b4..ae66912a3 100644 --- a/src/cli/args/jobs.rs +++ b/src/cli/args/jobs.rs @@ -14,9 +14,8 @@ impl Jobs { Arg::new("jobs") .short('j') .long("jobs") - .help("Number of plugins and runtimes to install in parallel") + .help("Number of plugins and runtimes to install in parallel, default: 4") .value_parser(ValueParser::new(parse_jobs)) - .default_value("4") .global(true) } } From 957ae7c76814ed750f2e7fe8158716903ddecf49 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 07:42:45 -0600 Subject: [PATCH 0171/1891] bug: do not force versions to be found in order to install This broke `rtx i python@miniconda3-4.7.12` --- src/cli/current.rs | 5 ++--- src/errors.rs | 1 + src/toolset/mod.rs | 6 ++---- src/toolset/tool_version.rs | 27 +++++++++++++-------------- src/toolset/tool_version_list.rs | 7 ++----- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/cli/current.rs b/src/cli/current.rs index 83c7d9b56..185ac657e 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -144,12 +144,11 @@ mod tests { #[test] fn test_current_missing() { assert_cli!("uninstall", "dummy@1.0.1"); - env::set_var("RTX_DUMMY_VERSION", "1.0.1"); - let stdout = assert_cli!("current"); - assert_str_eq!(grep(stdout, "dummy"), ""); + env::set_var("RTX_DUMMY_VERSION", "1.1.0"); let stdout = assert_cli!("current"); assert_str_eq!(grep(stdout, "dummy"), "dummy 1.1.0"); + env::remove_var("RTX_DUMMY_VERSION"); } } diff --git a/src/errors.rs b/src/errors.rs index 70f9582ae..b86e6e1b1 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -11,6 +11,7 @@ pub enum Error { #[error("{0}@{1} not installed")] VersionNotInstalled(PluginName, String), #[error("{0}@{1} not found")] + #[allow(dead_code)] VersionNotFound(PluginName, String), #[error("[{}] script exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(PluginName, Option), diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 38d0fc276..d77400535 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -83,9 +83,7 @@ impl Toolset { return; } }; - if let Err(e) = v.resolve(&config.settings, plugin) { - warn!("Error resolving plugin versions: {}", e); - } + v.resolve(&config.settings, plugin); }); } pub fn install_missing(&mut self, config: &Config) -> Result<()> { @@ -153,7 +151,7 @@ impl Toolset { }) .map(|(plugin, versions)| { for version in versions { - version.resolve(&config.settings, plugin)?; + version.resolve(&config.settings, plugin); version.install(config, mpr.add())?; } Ok(()) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index c101a61cd..13f81069a 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::{Config, Settings}; -use crate::errors::Error::VersionNotFound; + use crate::plugins::{InstallType, Plugin}; use crate::runtimes::RuntimeVersion; use crate::ui::progress_report::ProgressReport; @@ -35,39 +35,38 @@ impl ToolVersion { } } - pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) -> Result<()> { + pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) { if self.rtv.is_some() { - return Ok(()); + return; } match self.r#type.clone() { ToolVersionType::Version(v) => self.resolve_version(settings, plugin, &v), ToolVersionType::Prefix(v) => self.resolve_prefix(plugin, &v), ToolVersionType::Ref(_) => unimplemented!(), ToolVersionType::Path(_) => unimplemented!(), - ToolVersionType::System => Ok(()), + ToolVersionType::System => (), } } - fn resolve_version(&mut self, settings: &Settings, plugin: &Plugin, v: &str) -> Result<()> { + fn resolve_version(&mut self, settings: &Settings, plugin: &Plugin, v: &str) { let v = resolve_alias(settings, plugin, v); let matches = plugin.list_versions_matching(&v); if matches.contains(&v) { self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), &v)); - Ok(()) } else { self.resolve_prefix(plugin, &v) } } - fn resolve_prefix(&mut self, plugin: &Plugin, prefix: &str) -> Result<()> { - match plugin.list_versions_matching(prefix).last() { - Some(v) => { - self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), v)); - Ok(()) - } - None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, - } + fn resolve_prefix(&mut self, plugin: &Plugin, prefix: &str) { + let matches = plugin.list_versions_matching(prefix); + let v = match matches.last() { + Some(v) => v, + None => prefix, + // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, + }; + self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), v)); } pub fn is_missing(&self) -> bool { diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 61361e46e..56cf77b0d 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -1,5 +1,3 @@ -use color_eyre::eyre::Result; - use crate::config::Settings; use crate::plugins::Plugin; use crate::runtimes::RuntimeVersion; @@ -23,11 +21,10 @@ impl ToolVersionList { pub fn add_version(&mut self, version: ToolVersion) { self.versions.push(version); } - pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) -> Result<()> { + pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) { for tv in &mut self.versions { - tv.resolve(settings, plugin)?; + tv.resolve(settings, plugin); } - Ok(()) } pub fn resolved_versions(&self) -> Vec<&RuntimeVersion> { self.versions From 4ec8d1c35d1adfe12f31efe3c9544157606ff6d8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 07:43:03 -0600 Subject: [PATCH 0172/1891] chore: Release rtx-cli version 1.10.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8fe179a02..2f69c1a37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1369,7 +1369,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.10.0" +version = "1.10.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index 46f35fae5..e89304805 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.10.0" +version = "1.10.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0d0a226f2..413fee84c 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.10.0 +rtx 1.10.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -204,7 +204,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.0/rtx-v1.10.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.1/rtx-v1.10.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 7a6838be6..537c2d4e6 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.10.0 +Version: 1.10.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 7368dbae2..2e5c8a63a 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -223,7 +223,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.0/rtx-v1.10.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.1/rtx-v1.10.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From dc4af604605c4f7ff14d1d6c6ad933e318458170 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 08:17:19 -0600 Subject: [PATCH 0173/1891] chore: invalidate CDN on release (#146) --- scripts/publish-s3.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index e2fbd82e9..370246d65 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -25,3 +25,11 @@ aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$c aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_hour" --no-progress --no-progress --recursive + +aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ + "/VERSION" \ + "/SHASUMS*" \ + "/install.sh" \ + "/rtx-latest-*" \ + "/rpm/repodata/*" \ + "/deb/dists/*" From aa6cbd70a5d9240189df0f5d7cf8a1bfa9321048 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 09:57:48 -0600 Subject: [PATCH 0174/1891] updated demo for 1.10 --- README.md | 2 +- docs/demo.gif | Bin 582092 -> 489732 bytes src/cli/render_help.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 413fee84c..870dfd995 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ _Polyglot runtime manager (asdf rust clone)_ ## 30 Second Demo -The following shows using rtx to install node, python, and jq into a project using a `.tool-versions` file. +The following shows using rtx to install [nodejs](https://nodejs.org) and [jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. [![demo](./docs/demo.gif)](./docs/demo.gif) diff --git a/docs/demo.gif b/docs/demo.gif index 6d079ceddcba6de55b17f88856f5107779de8c65..1ad0e1df87a952b4d4291c1457dbc90fcab57d2c 100644 GIT binary patch literal 489732 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 z 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�yQEVP zvWqMkMxef@|2#ZWyGYHXOj?&R`ht?zP4%i$#d}%(#nIjHsQGec$F*pIO4&-wC_)Hr z*mx=P$={19rNGc0|2ee(B|9g7lHcF+kNw<>{tN%Ob;R}${9^^`U9De0w#HMC5>o6h z#O50jYo4FLn}*ddIt|M37aNDb8~+ykm8fAYvqL+lLAh36F03w^ zdxO{K$AT4j$)*ti|JYo^&hJ^G^Hc67kbl2&%#g&y4&)!}Gn9mPrODOhu zL|G|NoQN2(43_~yl)-YrK7jXU$ksANQvnQ7g5|nLnu!w-qAaOALTnysCjVB=WG@XQ zq>+XlNJU7i;&$h_zjVE%0DJP z&zggTX@ECp9u^UaC8u4qQvhV|RQymX^Uz3{zRgjtX(6nzH8(_71s>7Ns;pFBrr_-V zJO{s%(yMd@WykP5h%>c}wU-dGF;D2rtP@W{79kZit(`mM!E(Opwa%c5_8qpgI8|Yo zhL>S-S-B3D*kDzOXYm!-sL zKp-{;;v?DaTlq;$Z!GbUhgAH(HoyEsKhU5500&N!gGBr+;QhZ0PGi|&o9+D>#$UW` z?n5*!qPw|>)85thtK@YdE^`vlS{n|f`9``|nB zdAaxlBvT`(l`=jL*QC|9gFYCKJJ=zV&h-5_^Z@jbwttPPcRqOXqXP`%Tjw{v7Xvx^ z#3%#(vP~aG1ANdfLt5RC@9d|@+1!)oN9n+l_Off1C~@!|iKiV;gYp`H;ItOH z)GPj=ma{KB9;TcQYB?4}HvZ0iJj*#U=5SQF=aGl>%aMol$V2+S^^hL?-N(QBza9(t z6A$S>8^&KOOTTNFs_(m1VMbP=->))$H*2fXPTkRvFBU3Uzg6Xu$Y;FFJJI@VtJ?bs zpXo=;_#rsWNuP)f2TlvEnrEDA)o&7^rMQ`R%93kce@J%x?(M2d8`c|>AUMsG;}if+ zGkkDYr>1n)(Lt|bx-A_5r*Tx+S*jXM9_YH=L${xDIs0g4c3-!twW`WZRdQy5fv&E^ zncp#^;^k87R`bXOr|SSXt%J9*sq;ydcU{};s}5}Ie1i*Qe?RVW^XrP*-AJAuhj?|T z*HpDgN55sq_}%aqG>h%7!HX4hb;UmI;p(Ry>1E9Dckn2N)df7tX6AOLMQh3CdLk}L z&faZhBgHc#^cOs?s{mZ0PcT2^>O_zr>8z;CW+SQaLoI5y%}F(o6?}xxV(Nm!AL12b zd|nMr)V79GzU+O+sn!*{VbfGK;w66q_9>e3KxdGT91?4!w(zm|1^?Qzc=&ugT0!=$)8W?w5KDBWY0Ava{Zwiq;aycmWFZB2gEH&y@l|*n zqhlOgNb`PVdHoF}L8g+KSfD2tV@53uZ;Z0TUUUGm_YOHgEjY zkKeZRC;htTlSChL*tzQUG*GPTcp6Q7jUy0zeSg5k@x->&YxQ?QA7IcA8N#{lVWBT8 zD52{mqb~XyH@CWl^IH1qe!Q>9m?TejIm2AM@vf#K@PmzF%hb;OIDzvyD`yS_i9&|; z^qae>t3!!Sg?^h9XZNiWDS20C%{;X^JV~AaZSvboh=GQ%y})?g*B>>0bLL^k8dFW+ zc&_w!?uz!$+;f53@)x6-VMl2R+fXaGf{xR`6ZnwA-X1$yRip5GD3T>h^O5I~G|g zHX3w#8~E0mX3y(0*dT89>QyJ3^ly7)5t*uvhd8{jG2bM1)(son39)(MY_mfwrXRW^ z90Y{!Vkj9#+|ImYFEjmQwbMm-v1lWu0*xak{vsp*D>rY)7OMT{tMhuzJb z{^$nXkPD)|o-hlPO-lZOooB9AhPdEH2Bsu8%CXcdp*cDixjp{IGK>Y=^o)2W=ttJ&jdhC~K6KVdf2ThvM>~lvn_4wuH{Am7uDp5s2|^=iR$o*ah#J8UYY zZsqxg%;mSP4`p*P6!{}cZ#m>%ZN+xd7ylS5CB@6?r2ePCW`Dk9{gw0SU-}=o)eiya zeo+Jhe~UN#(Hct|C|JxUe}ks~{;h$!JN-9VJj-z^+W;npfQ{=GF;J%YjG>Pz(J z;-~)wbS=cuS0dgo^hbDFxWvOxzlW#sci*`3#>MkDc$(4g;c4BP3#R7}k2UP7E@htq zN$@<6#-Z+q`Oy9U*n8{PI391yv+Wq#n6@1=#B3*KCuU}hDKRrMGcz-Do0*xJ9dpdg z%#7*v_cw26-oni6te!?%?Wq4Osio?wuDbW0b3f-Sa3X$n>Yv=p_kK+}GoQ;a>G)sC z$M#i3H)ac!W{2RXb;q*Y^MBU3wPl>gSRJPF#1_WdTmRAC;XVC}r*n-DRp=mQyPA3T z?_R0*q$G z8M+tpdC@;&4fVD_V$O|ZAlX0b4XC|)K!-mi@&u*z6UvKC6tm8#v9s*IN^HI2?yy4{s&?rA3ulVj7wI+h#qoWypI z&NsH+RajF1H4Y>fT9+})KGb~3y>+W*d2(d+c`MT~wqNMQYpk~8c?VsWsr)Uut1*qF zRiiRj8hi&`tNx(<2XtM*$y%LFSZ*SOzc`WBSo49S!t4hZ1$Xm(13cOQjnNCDGz4e2 zp_&CqWAYLvN*+-g16ye@&Z!Yze&1|AM{AdCzPQ({MB+OYKnma~`8h`N+%Yj3d-7#GG?dS~5UjOJ7%}1q zc>jDs&co(FiQ^1(HfwB7qNq!O3}4hAjQx|aXmFgv;nh9!P-U_F);dD+5#sp|&7s60 z_-?0j(jRw`B(1E>y6_MI0Ke`=8zCGJ_nZO-^cx_yHj3 zxj{E6B4wHz6s*i5pcD+gQ4qGh4yA%KYkDf${8xTa6F%Q@Rj ze?wG?hd{-cQD$lN!2fC7Bs$xjxP16V;1M}33kilhh*#V(5)}YWR-TEbhm#eIMWL4B zq`hglopa4y){AH<#WOzXA3@dujBQn;PSP%wjGC8vb)5djYNX4EaTLtX*rA;iB|jy) zDv4S;!EY+9y{L9FRGvea27hHjhA0M4srEG;iZJ+)fksYJ$$DKx8R9C{9eiHegt5h~ z$Ugd<`sHHVVZ9M+F_G!Iklq4ZL>RDq&$JR;h+X9R=?rco)KlDvYm+?~w4h!VY6Wos zi?7YW+9AI&Hi%mfIxd1MZ}Rd!U{o`RGc*c>p0>R#(__&?I>ONs`3?MEfoz!3fuT9#(VLP8{BV8RN z=|S86ZgV6y-{%F}rA_leECkYE9V1G6za}5uIZ!mV?zSSx2M#Tg-*x)R6&B4Q*;sEj zNj+>3aS4_nl^Eo-2~1ef9l>_{2JH{6tNy`P_X8TCC^d+O8MH=h;jf3np^TUfeZC{n;4bj1`rN&|pjya|g7v znw$_QL7vGd)Xu@uPQea_K1vPV>J7n4b3Us3w*3$}!;oxq++@R?YSZpULx&W@r5IB} z6=c?A3(Q~_zoB4uV?Qc(P#hz|i4kc6F+v3n+U6B2>-BJc=; zj{*SZbU;mV#^F;a03S=3X_OcMz?T@*XA%Tv1G-cL+du^9`(fEWsIoY^E-`_B65X1B zfI!B;NgW^nfIv8ic*GhB(1~0W_csLsj#;C_M1v5otgZ@`c9PM&<#b|`&~6lct*e1Q z_pJ39fruR1rHsG;xp#V*#;Kwio3od$j@et2jZy>r7iFKkdBw0pRdSp-#U>lDIM4tN zNS18qE^d^fqR5cy9Nc8&V*}qb7+epbbO|B0{CH(wx#uA53_7evsa8b15(hDdfbbd< zCgp+M@PKbBQFHtb;LUI&AfSXFGZlk;+XPA>0E9U}yNQ7Soxlko zz%3B*a0&@#I`IQklHQkSL|=y+m!SJ*6WIslXeY07te8&%)=N72j7pAmv5v`&TDm&% zDg)Z_92S3J0rnv(pK+DAB(#Bt&gRM91h@u1#Gw?p2F@VgrS4dz0pEin-(Y7Wdu5%7 zWQ)*bi~K{?Kl`3lhL&_#2>_o6XaR)IM~(3ANSG}(fhHs`Ea2K@#v}q@EYv-JOH&#M zh+_n$>LfzTN6D&y9!)$?AV!`|AmBEfdSrJbUZa)8Q&bNJNTEb?WeL0~4@UB}s$wBq z3|5DRGM+>roC9QvtAILjy{?teLL__|iQ%!BfavhpI-*`-)7CFom?s0V8KMS#a0b$a zvAKhW7k8;HEO8My1_M4i?$vRWZrWW*zP`yQR*WgX23%ySZAli*Q&TO-Rl<0dtg2uW zbWK1hav6?Bfz#A(F5OWB;+B6X2mzZ&BP~|bn`(v}i65Bqd!CS|FOhll3dDjln-dYT zFWu8Xgmarnrzsheib-qY4vll*KaTmLVd`-<2>`i5Kv<#VQC{U9vNNKVY?v_sM3^B4 zGGA1-q;|x!g@=VG1;gP6bLqy1jbcQ#I371>s4K*sZ6^#own1jjw5F7IiOT#=+BlSMl0n?`#vrI!I?nT50 zF~v9MDCbvVnv1a_our~VCA<|sywxUL8hc)&5t8m@2zzQ?qhx9Oa-Q%)EgwQkcWI{Z za+30*>o>?_TIM0_Kp@uyPAXk9b=)e25h=s;YI2QL{O!ZSZi^G=HWQ%HdM?sH`qcI6 z>7ZaU#wfVPPrA9BOo}1Z7y?*`b!Y~TCM9Koc5QBo0XFby%fVJOA88apYm z*b28B?v|BWG&QY;+fpy+ga82L`!Gn&EUL&{Wa8H8dHV$&8M|10ii? zwsUpK9_(Rq{rMQN=2}_VV0CQf*;9iQM9|yF1&+WEx_4uIEOmh-qWA-_8(F=9M({>^ z*$2U9=p|~<0>IE1V2I7{{I3=@jf#%^1A?qgf@7V!m$0GyA^n%XYxWzZxfT2OJAT4; zdYyDMxy7=l8rfZ%S-=e<$R~X(E6iq$n7V2~gF>9tjdIlhMR#jX2~@0dJA}WZ64gBH zLQzkMTe%ja;%q7kl!528pbxa5j%L3Vyy!~930~@^ZMi=w{~#`CIe#7ZWo_sKlL zy_Ut^{QzJc8bW#Fw9NK2ASt*$0;K6=%YhuS-Bz9ZtVKMcl_}znqzn8BX)7Yp1@e}m zOFsbPr{HtAqa%qCy2L!cW&QzsfCPAEuS2ZvMi9#ZqYkH@1)HWO#v2q}CkRYr=$*ffsGVcjim`;py+?*&~sXg*muRf`>l*4k_nDW|X zr|In3_356OB^f>81wPB4>=6$A@5i+r`Y8wL&~OYYMK94^JMfC@PdWd16R5L6&~T3; zzEJ-j)AC>aZU4s)kiB0G!hgFO?>6yo`zSqr@F-DFL)AHbLC{dd-^FdW1-((2m}egu zas>lm_&Qz1<8+0?F=>o6T55LqV;C`$$X%H!M#E_#wznzO#>1%}&DVb|)fUSnqw7Dz z9Lp8|NF>M;{3OmaRi-yUs(SY;=IB?bHM%1{SCV3r9-O@-568Z0le**jcRTfnY~}b5 zXAy})OtVY%3XyKevu8_U62@)oJfX#x{UYAjc$!=`a(V$#^cy0aqNjDCk))q9S8Xuo zcmnyHB)RRby4m!xyr^We}zuX#2@3&U?cZnk4 z(p~Q0EQL8#F0rU21cGbupv&)1?qd+xxCq@kJo+ErZQ{wFjXK|+px*tV?|_{DP>;@k z*!cLr{a^bZx*z^OcY^OmC&c#zWB(6|{~DZsfVrglf6SElKMl^u)7kBhS4aLYsU!b| zDbY}>7{y=vpP3S2gi`-5b!4T<=6~m(y4)PE{r(qI;sFtcG@yE`H{>IY%$Q5f&S1=E zsVHgJ+P%>f2J?wA*Sdp=Y`$>RA8z$WGsUuHGUILyC-c?XzoUM*H=ZpwTc1pfuiWeO zsUpEId?jeU+8z$2`8@IZXm>CkFXl~8*m`%oSYn^_GieO;dAHP^W)J;)+FSw7vyaZd(#^l+C;|}h+e$u!;d__;@>6$+zLQf65k5M zG78xW!gCtl3ML8yZikR2iR?@?#|8T6R-Rl2Z3m z%^FAc(~SmO3Nx%`5Dqe2=2H(ctymHEv$Wt453~KSBoA|fD8mkO!&sM9!rVkh5AvOq zT8j$e^dyf8GK`jw3c*2$$Hi$$qa|5Ug`v#FO&cd9~D(+_bclqSm<4 zld3kjld|d#ETq%wVLYkRnyDPgle$Jxq_g@NC8@K9d82UZ{1N7pv)WB3{L0$xB&qY3 zjkI+7)}6|5aNY7?_*wh)ywpX<{eCz@S##;idDmaKvC8gqXzt4%SPToBUSK%lMd!09 z@>M^&vh>vemhqTnAENWv)ev%U`{giExCZkGabCnhAFlqX-EYP&TKlo@lhV3fU$V;W zC%DsB>qhx6PH(0JAlzSnvo4f7%t$kwIsB1ZXk(fd#QxDRt)gAgFsGq><~aYA?Co|@ zKKaM}l2K8lQy{zbTf>S@*P7$1L!afts`Kx0@S@oRq@!`e2SVqvX(k)_u;sQ8*}NTk zF#fm`CDuu^;jb*yyqBU~>AD};*wMTj=}qr;m@mZJdQ{+#O0<{WG|_TW-9_(y+JOsx zJ}NzkdO2@;hkH2Z z%oU=y$2lo$-lv5;Z?C5qW9?#00guT7G;wyQ&ew;7XugWE50ApwfbYE-{oQci321?n z0-HVw)d6s{x7k+MNfX{7$MXmQ$+z5+Cq4Q&O0#q5J}CsPOMqAwh!)0w{*nRJhP;{8-zCh-~#ag6<(WR1VBJ zO41SNpi(&o11M$(>2ZwY>=Z)MT1Je!UQ8ml={`oNVA451l;D^Y5{;aoub5wW5xxZm z$n-FgRG3I0?Z6;{Zwu6#O{IMC{?Lqlj~1WPS7?I&VjwDzA-E}s)l5wMjQ|bdu?8A{ zSdM_=6Np_BSf=#5nt*u~185{d4pkMJN7C%*r(#p49{x>$l7Iv#aY+6Z;ad;&Dod4| z#RLsmYZf_-BfDfau`MMK7KTVSxC^EiwFuB-L8Qd4Xt0G=yE(EwJXg)eBclx|UD&+6 zMU<}I0CA4UkM%0lWf%%_8gor7LvsH#o*@B18Sgc1KMATbyPv@h@vmuzt&m@!AE2pj zI4WW|WDCFtgN*JVudjn(U_j+twv_Bz`!tjK=9X^UW*{{&B~Yu_Pr&z5l9HA(uaHTQ zDpLxFcC$L?=tqR^T6ju4JqeTYl;0cTH|;(gU0{lZv|hOT`fX)XN6=9TmdO_wytD;I zSo$$vjPhAjhPgg-d}J)I^ab``Jvp`^f<6%@y)3t4;HWVwe8we$syIvzBMM{(*x^7| zyramdsb9t z+Q`p8fZ{VQiDdzm=laFwYi_kUjLWdl&SbZ1gDSqiA1k2sVm4uyL{(}6ZAm=vcLHc4 zX6KYcdhvocVcDsiCh}ye67nL?xcX>f{FW#Pey zDV>9IS2kq?hFPY$83XP@uxf)TJI$!fb;c}q;h2PPX6lCp#U*4)={k&?TW_hh+1M+$ znU1xy#yU?Uk5^d)*~cvLWZ#+jShlDmx&T74xuF+ZLG(}5gv4S)zsV0StUlsrkfgh@ z%NT*;xV#Jo)r+?G-Z}W6+zCeU_s9EfxraHlQ&{bdZvf7&W4hL=Czjuvg4J$k$UtrHQ3=7DOV zfz~u5b_fxHgENse)A2Fb6gLsE78(+Kod2v6V~h96?JI?$V*+N?u7rHG5S1u_Mz%uM zu5Z9Ef@={0g&>RP92+PjubwMOWzY}Vd{_ff+waYU7y*`YAXunDn}a5E?f~B&G(T_x zEV+r=Ct_K|O`U3DC zc}xZ;$v7@|awkKupA^lw#c+HSg-S4SCA(pul!U&D;)%%#=?3F$6v_ScfiWc)*rvjj z=~hKFG!lm-%OMoF2+9S6g|)Aoon{+Dm80f8-@F z7YT4~KUW+QNHW5V|01qC^!wWrMrRkEzZkAy64-SZ9_JUB0}LBfi5PZ?5c&k@S&XrTr`|%G<<3d&=l`+I2uA71N9VxeiZX5 zmF=-O2B#$kwK784^h#)l%uO;rQYXk~H9HVL+lSJHi(>T@= zQf$ab9OqIT*HZlF{aCgy@q()H-*6LzIT9WOVz^rpc$X5SOSl>t=iK-?UxF!+iCup`LX)h&NAbgYONK!IQvJXwNb4@p z@@Pr+3Z>IkP4){-c9KXA;7D=IOY&?<@m@-a7@@W`O^H)YNeE3zbWMTEOO8HD$!JLh z<5KvBrpBA5=6^{`=18Mbjmd0D%UVh+Um}ThO{-N+D^^XfGfm^jO|3dgYi~*KOvTGF zO|N%N?+r~KRLxi^PU~pN=z2FWxza$zME7%K_NitLNo1y!q)#4YthQuUE_pAQW)4F_ zGk3m#YZ0Q?Qo-vbU_y?t-6!xqZq^n@mS`yW#5LJj%LW$}%#|dQ#1P zHq9m$je>qph{VfAe$HMH%7*960ZQh$_Gf_*v+xkF%+l zbH1c~L+8vTea@v1F)LLMSNB0e{P+_!C zYq?NglGre;&>^kR5iwQZxX=x+$Q`lBtM#+J*?Tx@k^eG<`DjtdbCKtBVFUz^*jKVR zMy)tjl2o&`I4P|-GOQ%|D^c{<5-?{;)+noNYe{Npahh9cVHiOsVre;EX$2mBVpwSb zXIZ{lnMZ4BWm;KPX&KnIxJ0t7)~u{cGNrk-Y;d$}=$YCTuY8QNd>pZyMXh|8vtnel ztP`jIrqtS}%u*#dSi6_UE zXK7WEl9dO`RacT#fZtpXrByKDRm6x@ch6OS)2fkIB0iW`!{XPRj#MG4*PygjL#=Rq zq^Ti5su>Th#&xg3!mlN7W5hqHAxy6=lc*tGsiokm#R+GpDy#h-Uh4%xsAWQ`<21C)v`*)+cdXq~Vr!q~G2U62#u2ReN zCTINSfD=0Fm8OuBCcc((|CMH^mu5etV)wG(8ehImNfO|7%7}!^_Fb&7DCac zjJB3k_10n`~FoVM1=mDXmOya=hb!ryHrCvDJrZ7p2wP562~ zTx}ic?Oim@z3T1#FYPiyt;22Yvs@jP%k5L?9TO+{^GNOMW$ogS@Q#(Tj$M4FnU{{a z@Xj^!l5O?QbFR)S=(f$W&Rec7i{;MCm(J(1!Z!1+qm!w1T^EC^Vpa<`@JIJja`?cp2LGO544?%kmC34!Ec@ODWH%&$^ zxkoRfMlXq9H*I+@t480?r(R})K5p7ly4OB7x+`$L0vWPezPQ zuMRX=jIVQ#ZMJ_|Y9C)-ZT<5)J{B>tP)@$1F|j+=vqms+!aaHXN^|x)alYDgKs$Li z_THgWK4eTjws%}*OhBY3;XS_&&`u%qOl2bvBM?r*@l1cfm_qfO-cz3f{+NCno3?A6 z!XcbN$;5v-ou=%VrnV%*;+Y|}Y{Xle{z5m+bXH6Z8J}VGoTlLU!-?{TI}?*;ZH7&= znt|>QkLS$#>mLD>S-A8+A{~E(-)2!1{zzudc5u&%qRh#7&h_}t{#=_g{5`9(Hmi3w ztnp(`%d#SzVBV}^PL+<#&~x5styE`xUjN5}0o|M}%7UiloTcW1=lG;`=7L`)*#2$7 z$#e09V9||d(Q$Oa>uu58voCCXG5oC_6uB4^xrENMl=x#w`gk!mb18^tIOA+7v!fxI zXF0cHc}rut$a0w!aXF1=rF6W%5@n?-GCOd5xqf^_)P1ETa^>;MO2gVpj^&CA;p!;e zNZb1a{cRP3wA$OTx+<~S>A5y>Ry*@!?ax~JI0R*F5oLX;b!}~Yt;%$5iEw=&vvt>U zeXk>RqhtM;XQO_3{o-srGIV{rW8<2x;XZQX;VkLu$HwcAP3`9mDAY~!l8rab%_GYu zVC5#lM8b#n$+y=QbjB(M{nlm1JdV{Su~r-2#1?+#WC`K+XREE>_*)b*+cYDa)a#qf z=S8&V+jNyNnBZ+r-ko1+J8V`v+rXW#L_5N~8N8^weDu*A6FXd5yEm@85>dN3)Vn`; zca_$Qk+!Sqg9 zXGS|Ge|XPVD)XZMo*mLx4r!gA(w~tXoo#~8zmuJxO`P3>`woaMp1szWWX{k3UZ|#C zTz6j7pq$;EUp$;2e(1WaU%!BdTmrn)FDEWPU9jB}U4gPLnb@viw67F)E^$6z<7pp4 zZ(LDAlCb%%fnC>>>eocx*JCZ`q>#z$Zw#~qkZbm=?_XqZzGhwRgKzk|%9uB9ShR0N z?Qa-A-`3RL@NV3SLT)5J-*s}_a%ZsL>o<{znlLGD~WJ{XkVJ8V2`9NpViJ-EuAd1ya)RmD3qJcfOK z)Kh;9wtmDNxebrLPmm?F|M(Og-5byMmvcbL`@EJi320>uu(ut`FkL`vq8T6KvY_nDILKeAR)a+v7DYz2qu+izRR?pXcP{Q z)oZc5fmjTMSP;4Ej6p8|3JX2pNx?`u?VII%zw1w988DaUJ+7X<@L1LsP2AQFSm2-)?@U?`UEXOf01({gR*xEtJ?s)NZ)-j8Ha zPc=ug`7+I>pf@!qi%B{N%f>{;3-kF}E7JqqUv>72t%Gx%w&1@SoHs`k zB6i@+%toj4l@4ckh^B|j_0D**n73BPkNUa1pTX9ee_x)?&xVS!AYPuYFLw{{F?>)E z{Hd;uYITO5TdZHz0&t%l7zKe;3Dts#4CNz@&>zUFg+6e++6bZXz|{1k36Wn3WBfEg z6Ty}e1_|NP<=cwloA+Od658+DihXuBvmU@!B(D`AiKev^CyN)hlb}irs2!nB{Y5`W zRQ1XvMcXu6D@EUR%Pft+;-Mh!i<6} z1&gADGK=DzlBx)%(kLxT!@R6@1B?%g#|c$$!mG(23>{9()=g`s4Z6x}ckBA_f1S5nwH@zQZN>h& z?8QGMnr(!7^FD9pWNAHbiG2q@?KLfQx}UeLuDKmoRdsq?Pk!cmYp;c@yFaW1L*DK( z*tFlC2ZkVCZ_~*<7Ee3yn-CZr{@Va+@B5t%sGDSdIMOMTQ+yp51Zn|9nJKDU^G#^N zVgb~zQxJb#ax54+6#?|9sQ~ov#6ZR7o{zOQfrK78vBD~Xc;KlZ76L*z&1NB->*_!r znC*`@-}>;e(1PEyU)L25`*2ueLuHY3G4d91NQtJyB>J~8(F*&%ILU`7ypn$E!|DHO zG##PFt&dmIAk5%59jWJ`kH2-;&73h(-=)hPv|vapl}*0b!j*s1-=2+}ZO?`e@S^{UJ4Bsk#MQmrK7eDB`*+ zk@0Y21mD3Na>JVSIPAw~y?i$jd}-Vl;$=~%vIUKT0~8>Dz{@LRR_<}EJC*}cCjjzIEq+6 zv?$CM`(^HVJq<042-{RIksE6h8cvPL)K$jp=Ihf$EX~}$s?7(@H)J=MoBrfl`7?j7 zT_XD4G59%PJ|7S@ZL@Jlw&y|cMeQCPr=FL4I zxSC+0Rb8y2(_YFT+t8zttxruZ11y6~{aUm;I1f0f)Sb35irfbHVrE0UqRi1hArkr| z*h?cEl*}1X<-6p{9I^aScJVo{26W#{N0s2dCH@)SrAdE49rXuQElV?prG$LilYa746QSf zsJB{hgr+i5oWVAY4uuRnX7V@2f54)SMbn~33c<^BDMZ&LikW6=Y$((DUM!WmYbL4- z%L{e;M-I*v=6X$Ti#|sz)!rSabbil^Ev!y8IXp22-&U4Kjj+p#-Yl%7-0SBC?;8dp z6|IxGmJik&^M*RkZ9dDdtckL<|EW;4sash;!uG)u9tXT^tsi}P9dg)szH?@|&J;x5 zV$rW1DI2?~gvs3HIrAKM*SXEt@ZOj5dmd}?y)5A4IMp_3o=PlnF1J)VwMs>wSv$M0 z`|h5$PV$_2!|$%$@w&7Rk)L}eyKkfMvG-tuFa6otHYloGy0I&+qMbeV1MMD189HyW zCKvZu_}s?of-ka*UUzx;c&3xVw^e+(k7(&jxt!cMTI=>4LdwHredmbxqJkNjZy=%zwJagW7*}(377~u1|PTqJu5c7VX z>+-s9+IYJN_I};tgWTF@{k@8Qd%NrM{`;^2fxveIK6OKpcSC>g{_yJe;a4}TK{uR3 zH+(=haJ7purW>)o8>zn=dA1v6w;T1g`y))x%}XEv5Cr<(gCX4W=~oY?K@ZkgPwljfMlbka@oIhZMK5x9GMRvh)zG{ zY(@vCQlk3QpKkO9bU-K3rZDaHB~Yo)uQt`a=X&z(5D+GnnN}A{mGN4}tn>DlB@R+% zw%%LR*bDsw@Mx0k6(+NOH}%(S_ZY{1C{zwZFVI}+JcEvMwb%9S^;H*>iQ#nG_!kID zyZXCEi}@e?q>}aal}e2T-_`*{^g=-P`U)6{?^G3XRG^e(w);<30$4G5%}~}en9zSj zF$vfI^YqRf=Y((_s^LewX2L)+&&O=%4}{Kye($-Sq;l2>IK=L+Z^kPT&J>1NzGiby zS{BUc&D+uZa3k?XNN~=%!SQsgIk705PI?Bukt(US@}e9WHiG}avwto*fFfXgIpo!g zDFW674eb8^0%K(^6^!6!08#!9w;R2z9II`k=sK_-C<^(e*Alr3||G^jDk15{aoR;Q z`?bbJYvXjM)tA3Q4-L(0JQZthKd*i}Z_NBfVXt@n=yigjNp2M&?1yhfgJ~nY4!aX| z5GK59lOo`{*IeoQgocJW@l>v$LoXs68BKqJmQsZVBV1A@Q-UEU3>An0Z5s=Vjgjih zfnNPPsszLK5>1Ri*@stz;HUH~?EWu)^47~(JzEcS#eVrfj3qIq>Al!0H14}Z(Hu{J zB!RXEfrRugx7{MXPh3w?^ztHD(1d6rm_O?oVnN_=g2P=gKB*3Rvd!NbhloI$VF^@6 zWQRE{XkhR_B!gd>8}uz}uz=zdy`5~#@GWO^*;6c|G9~v`g+g(!T4Z%#qaF#eAw?hV z^_PE-gZm${@B9Zkf&K%(>R+ZJ48SJ<%=-rbL=460abhD2TAKSm*Nz>-|y#DChb{gl_8B4UlVR7X`J zNaB9Zo++6~AsfV7R+_Q%C3fD|`8&(Aq*Gxmqo|n{3(oH5ES=TiYDt}lVV;crF#Yvz zA?*Nz-N|eY#^8mJ2$;GA^T;8Z>PIvWrs$JMJY|9}(cNA%h3#^BDqC_n2JZFeK2&_w zO4oYh83r&jY%4|sz2uOu9O`vK@=lgai!Ii+J2UbbSBOuZ6}3UsS*kgv5egnwtdw*b zWx8;FsEn96xRVw_aC;abdG4qb$J>!%GOXG%0gR)hD$Gx_zVi4gFbhlvrPFU5%c#kWTS{gHc#09MGPm;$0UkEsI2F4sVz z5EnhLgm(aNJ&=G?1@tSB7CpoS7S~pcBn+8ZU(lJ_SU!>l_1AVRz@lczHw3^jFB0m-m!L|_1n>`np2Iu%>n6e#69?4xdyi=6rN07fv znqaamP8MjSFr(#7ey>8c+=4bo8bs727EgZWL@E;D<~O3hgtkj!knblsg_R&KDn|@P zt_3+eP(u0%6F&PYe=SMQ4AV5N#JUZvh&?iya>MR11Cgf@JPnY8ji6O+U>ws*DPyoc ziBd)j28B8SxE0a@5Z=_({9!F~5GdR|OA(r3G}9}Jbb<9nZ2Oq8;oR#4yW&*)bbi=? zKnJ}&QD+HKFbJxyt%@p>@wB=dL*gme#9kvU29(6ZHr*LRz%5P{SC21>6Y5esG^}gD zE=Cm(oF%15K{W`dOToGp(~K%`gd;t2y&V`1$>g>Rawbt&z)g9@ub>L_APK-PxmS{l zn^KtFR)O)H4%LHU*+y_zccEbcz<$oK5nzHQox(0xOTHVna@h_MbZ2>Un57 zGu%VIXb0vgYttnmDmN@N68>$pXq$ehGB_VkTXTk0Xn=o!2pW_gP}KqCNB$k{Th%lw zsk3j~0x5gON9b5U__`G+IqOGsg1 ze)#*&BZ9%^&>?xK3^g@!CZp!M8#@TzPFC@Q?ys?4ilzX5v=I5@+%aw@1oOAcFzor9JFAmdu9xi5zniM-D^P0rxD`4OP}G}QTb z0U^V2+nS(73I?+``-cn+NBmMRvBzwSFCaGrvnE%_Y7s;oCQlN{Y#c)@014%E$W0;t zk|U@_K0sVM<|0pbDjR_H zJp!4B%+Mv;`G)ey$V@{mv6DQ6_^pP+j70PSZ6bdeMF#L!!TA|oA>2o7Y*UoF-=_h3mYfrY4&OiUE-V z(?F43rS~m#Ny0wSy1-8Y^C6-ZGg;#_0ZlqeAWrUm!M8qP{eq?`Ar`+r?z8@5tlbj+ zQz-kKW3@1BKOAXdXi!KuR%Yj>L6u?dP!vvVtdtm0cq8RTSvwDzKI;j=o$;GE~1VcQM9_5(;e`N(+VP+V!#oF6z(YeqEMZn)NE!p9Gh=Ub{b)0vzP2oM zSlMFtFP?gd`(`|+ad303KT?LbUBq8_y}WFkEj6hFWG?;iHK?KC0qq|rE`zvU$^Ol( z{ok%&B;Shxw|^@Jpnx!>|7|vUq#!Znzb^*%g#14Kmtr6d`DrTa--?0nWYWRR;YpvM zcZ+BIe`NAzN;*=?=2J#yED3%B{wak^)q<63EL2J7E})k_W{Rbf)W;MxENwLS3D!QJ zEfG49!3os9zpuD)E?j6eBw5c)SJ9izP_}o)$e%Kn5KH^c!A*-*)5jmZD$Gq|6HO^w z!~(0J0^e}Lhbm#ei@Zc5IT4H>-57a8&FGr&vG$DG098529#@%Q*Hor|6}s!RrLHK3 zY7zcMMr_v9QRtB1=osSR5qGXT*^1;Rrp}n$u8J63mk@~-OUc=`lQjQ*Sl9d%dAexY zP4_A(&W8#u1+2h778h=CEgp}=_!03o8sC3acM8iNMlV2w5Vcn9Cmb$GE}GBx+F>Fj zOEe&9Br)``E%Y1OFmaqq?JzMnG<6KfoqAiG#F5bT+jH84YuuJ!A zPho@(F46TFs+&U3S=WIgksRx`Ku|l$6qH~qfU9GtZe+UW3g`A^GSg-MOAMd7+_r=+ z0A^dl`x6hek5L*wG#CWt-yY5>V!2jy$jnGWFiZ20my0TCNm>eu&j=dHiKI11bGAc} z-~F6fvanQUT8b@k`BgQPx-a?;7&!b%2b&IKE+EM z3=ZcuEe-0HDia9JISmOYY4Q=UJwk8)||{h$Wg^ ze{B#zm1+^2P8mXQ7eb{UD6pd&0`SS26g#U)Q#nF6i!n8`e$t+Lr>@Lb7!2WBCU4Cl zK2%N&LP|G=YDU~n-EPsWHmlvlIzZdX4U+a7?h9|}#4w?3acGj*GZG{vqpmmD$MY!f z&l9;gbsTVl+7#*2*DnE%RyIqnIGM#(Q?U{gU#|E`(_h!(?H;V`(!Pd=GGEAyuQFfT zQSf?<7_e6EUw00101JCgcVlV@}h)pYq7e`s42XiE4mi?7bLooWmtCd8H@9=f0VJ_^&vJ?a`~HHvTI(enyxT z>^xH{j?5XiNe!J{rk6G(+$0E|Y%MVX5|pw(lVR9)FsGKRg*M!fkFjh)r~|@-&~D1Kg(fzWstNmf^?znlV#VT5 zUCG5-{+wU&qv|oDtMs!MA`?ds?x8NJw#OUUeJCw1--eBhcf-(qd~}jn;x@8NB%2n8 zVF{tr$;I$V18Q0ngJyngJCxXmpmFB#`gdEAh|tF4n-zgp-^?V|a<(wn622kmNk?En z%_oeqcYqKX+<(MtVi~J2g<0IBuix$tOf^%lG*e;ke(;g)rwIMHCV;VtSk#_v1fh9a z3i4w6-b)_F(KvyPi|L#Vu(1*yktTu zSg;=@0W{hFtIlr zUoo_-IiEo-_bk@B0U=LV!Xy2FsE*6XDhGX1?X#BT_PcRwy-u3XZ_f{1063|uXZ%fQ z{KxLoBLqL}u}!!v@_*~}|6i`%{L|1<|0@gpUB?B!_tfwC9{i|SuSM0meF3OYj1l7U z*`P2C8qt75#=OB`96l@LFST1D{sa_BFh2(oC4B|(+{#meBBcVz`Q~@8nYV@MO*2$T zgy6z4{B&mWzw`x3r{(L=s!8 zF*E!rY7vuW2={e~Cg^0n!xYL!*PpTwvsX+JdQnYL2cI=`qt=ugq_wUH-ZnHh97dE1tynGNa8TG^ZozE-g^c$)wb=wAtaE50E-g3O7C5|qM`Q^YADis z6Oi7d1V}^fW;b(0{AD#Z6rj?BseKCUFDZ#g9J~+zQKp1XJe&Xm;-3lUv80Cd?p3FZHu~s?h^nCuz;!1y!RVL?`xG|yC*FMsJ z$#a5)gvMXT!7q1g#Zs_+b+}8d%knP(^FQ|s4i{63`e#aS|2?HJ5NsrY{G1EI>9VbI zmx@|Rzo&IuJq|&qJCJu&I*|g%+Kpoacw^Hc@`mb)hi}G7l;%nvv1AYv!Uxvoq(T4*S~u>taE_#*q`VmM<8bW+Zffa8 z6TT^(I3X&-#lUw}!|CMIY&uR$Zu*56jFs`sDi0=6_(L=qC=t#eswplFk(@|jYA^+q zj!azN-)}Ir1rNhxOEbCDGCigvp27|I`IF5S+acBK8M>=pozEGD>BTS(hGKcSO)A~y zNSeh_^+WZ9!~{PBTY&JY?J}4BjX4u3=f|wF?BWU=rLJ8&LMX-s#E>N^3wq827Bjy=Lf=pjEqJT_g}IOm|FO^fco|*jt0)1iuLE7NT8Mgw}xf#XxyV?r3nHjPBZcw z7ilvpjHl$}igzLv1xbV)Q56u!ba^7&0AxDA!o}h;MVAWl+2P2$!xx()VI;n>!x)<> zYVKf>-z(*43evtnO7}`tsEV1#SkxVx6LN)a`q~jP`DRdJ*cgho{iRuyApJarqO`iJ z2L1|Nve|)gr6wuuKTmYwzbnu9cjc-`VaS%z)@VHJifWJ`9eSLI6w)1lfo8IK5$BlH za%iPWI&ZI_4~$PQN7y>AXAb^^_bTj|uBW1Sfp1$dtluVk+Qbi3q;3(3BUt{pdfX zx!QkMS@Lh$41G~$tbf@^5)J$h1Iv-aC=n@Pf$PcG(M+S`q8J%<(aq+AvJ2OhPt2ku ztn)4=T0@UX0A%5%k}m~g6oh7l5u5_H0Wnh|7)$S}J1u1ABF#u&>4xIRdh^fs@Vbp~ zVZ<~SGkFC~Qmi^ad@Oti%N26DqWR^W9`req`LXwB7N>zCS{0=typ*$JIu}&pH}ijR z)H^O}rv2xd$O4gp$k45&D)HwanBo+G9*v`>=C@^OE4>+qqB5Mr1F@NWoGLVqdHw_@ z34u-*$6bjj5((3R=BjHgoxV?b<$1PF7I$o+s1&`7;#K$gGGR~E-_y@(jY=sc#QC1z z5ilgE=G(1=F{0_k%;UwWO`r$a5A`@gr~`4+sBF7-$l`PWk5(PW%Fjk^`HGjRf589o zQy=+vo$3EwC*-m%jI#_#qGX`KVU4*bhzJQeNT~}!>z*1DzwM5Oo{ogEI+*2HikKrR zECA-rm*$R5hU5;UT9Npl6kYS3`Rd8=VXl-y3=C7fiho+HEk&bIw^VDGX9VXzlAiEf zN(H5wEt0oR z;?MmNuM{vQl?9$O=vl?gNC1S!E%T9B+khiwBXSDL@aA_r_8_H zN9d{2w)$1LFe04^?MeH}kr$c%`C-E+^9${eqcb%MdUd-<7R+ve>5>Po;|;1`2SSf$B_E5P%*m|z zoXjiy9aPoSJ3xAJol@-oj|Kn#Iu@LY3`|cD#PQK!2!==}h63|b$Q|-hh zx3(0ex7;iNXA@Gdj8okj9a*1gtI4!ulDwmwkuL=wGf%dqi&yeowhDW!+-!U=M&I!Y zIYAXoe<5UDcY#yaP0{hUXK=gl@~WIo>BJak<{UWiU7embj5y9JMOF!F!LvD|=3!N! z#0yQ7=ToW4eYbE|c(Np}5k^L5k2c^xs05y2b+~O<)LFi_>w)vD@<{n=oGyX0wodbK zy;fBXQYlnSG>$L0RGq(8op7^goO!!;l3&FMqN@-uJPM=aWz1X%Hmqdc=J zj>Ga>YcS6}&od>B%K=zG0#65laCHh-!gnNqrsXz{XOrP~oEldZI8OG*sWC{A)hNvF zB&qQ3&@QM?b6*djEXR&e>E~55cf>+-JirE$t`j<+&8T^Lc#->f8Z{HTG{R*ZYQY$1 zumGg{t}}Ao5%khn>P@=_Hm{}Ns-F<%Hm?9yYWZ2mm11;ACRoPm8@|)#_jKu-0)sj2 zs420o@i04+%BFpPl)i`VYW$&0qv;PYpWO&zsC~3haKu~zXM~RSTdF&?lhp%@%1%wPCJ!wW zy#INTEGSa&qX^qRd}dU=OQ7zP@16d%mvXD!l61`)e_}0jw3&J-rVrerrE$`+Bit-Y z;~b+Pm{}{hk2fD8@?Da_^v2uDm8M%@08f;5iHRqhhB~_sWeqcQX-S% zJyq5=7n61<-_3o*C)J=LLzjN*ZRjHbjK2!YfkR=(N}gH%?dWJQgDy!9@-oT|g8$0^ESSS-I2E7wxCko1GCpPNrkWwp4mJL&dd_mHf)~(D z0eHfkn1{kNu-%75lPE5=AwYvwBOt|+CBppX(1g$*(NuIx08I;^DZwU{Y~%2itI0K} zbe~96)fzKQlKYDO`IBfwHTEegh`hb@CG=S#=l2`hL#HoqC(QM&l1WSr^WF0Arsv&eJm0<}EF(t5QVzpP zdnW1%Bae=PBci{kmb|1`X}4cIj4O&;m8T6?=M>x1ME+g^a|PAXDU%Fy z*_O**5g3++6N$?z>JU1xh=U?YjMs_2pcEp`oC(LDZnRAOWoG~3^IF{DZ`73UxQN^V zAmCAk&_5hSStupObCe-O45FAIPIkPFW>g8uU|o1QWZb?CVSPBdLs^cSi;Su2*A1zWa2)OU2?|bqmp=USH$cAoSQX@3S3ek3{`vDtf$c=^lGo zr^H~GPapNAozuLnV!Ea6R_IIm zF>{~u?;fSzkI0Wyg{RM3{>Z0ZUI<#9UVGj})6Wdsc0m4SrXFggd3_p59YFEyl-eWE zp9~$@q~#9YM!s-B{(MKZP-?%z=>lzwd3fqM>K+K@is^KZeyMBgPCEDwwZD4>v8*sagp6F zYV;JbZ_Glz80j?;`%FG*RUQ?2h`<{IRh*Gz=Kw|HQ_H$7OO0*^XLn=OLzwfLulp9o z7ipNEKZUz-5I+UNK!&nW(h1lOwH$`H$wBf$4ai3z)&Nus0O`br+w%i?%+P8VXkM~w z2Mk&r1Tigz_On1bI#M6kLZB)sRt~0GBxn+fZm)xiBAD{YXv|xuI4GIn;1-1{2^Jh^ z_{_p=h@=;3EbxUH6naP*xdj7Zft*h2J-kiu5*)G})s1#aG!}^61#-So50dmkN%yW% z+}q+sL>^KeVx6erhNW91S|PyR*lbi%KlISkjMAu)r1ye}hD;G4I$%r_{lu|^n@Lf^ z)A#SgJXyUbcSq}JW-F}5K0dv`f zpA|KhI;VLQMxR?6xO77704O;f#LgJ{&MM7{A{-J2&B}G%*8z04iYWt9%jAJPcQ>#j zL~SdT))BG|i62ZtQqV=RS(ZMT&KY*caPjfp)&}ly#$upltN+R=iEeqETn83 zDBC|w@^dI7SBZ^a1*r#Dk}tv}*vd8TYus(6VbLtTAcN*@l|t!h`?2jDc^=CaSHJ4}StS0L^QXMo3=;7*mFX2?=4TiS z2Jm9Y);E7yU7&UxQQ(o@a25(tF-Q~u)JmamgaIvwW^zn3Hl$=v!vOm}^n({Lf0k+u zg4TVw_$vxY+;WD-1yYc~ptZiTo>l@I-t>Y%uw>DPuuKTvF;udM58h}qm22P?56-Y^ z%Lg93GlT|Y2<%a)edI`i$1`n5y@~)9D1%h{B2z%sj5Do}#WrEDHt=~|Yoty#zk91x z7BEH8liR>^?PS`YxP6zG)#G}B%8wn^>qqgG?9b{JPHUYwh^D-9Zu8POZ{OPG;EX&<=^~gp_qsjC5Y1>T-p!_H_IVC z?vh zfV~_d4*HPl0lJ&Etu^yw!1mj~(8ED#rb;kf+l^~Le*d5xVbEV8_B~bAUA-Y%NB;r2 zLAhU|V3q2uh-!%ABN!K?)Yxy-0Xgk3EKl`lk@FFMq$A5|J$SJL;hyojm0Emrv?}7^ zNuF81zz7+7Bw096HyB`>8@Y@e^%olDMGo=r4ixXCL5`qezeisHV@OfJ@cARk)A6NQ zbAC~v^M2fd1JdSTNLVBpior0wLk^PQOEW-kXQZ`8+w&A)*BeFX!TXiMfDE3(d1M zFpr(4-X2Dlb(53LeAu;46#>BB9pnMM`yxJZg*IZ+Gm^7Fjc5-GJ7{Ubs^MGPU8;7S zuwefDChD>zk?UUCQSsZrEcW^=ScOuWN~r&!do*W8Q4dJ4nO&x$Q>pgSJv1{?R1cFXxrAa$U*!@J)>Zs4;nFdzb?Cl}L} zmB7hLJMgYZ%mg*r;P`1hx6R<)7lRwKm5yiKYu?#*93Xq)p`xEFn5dx%-AbVu>%reE z&wooz}NNOukx?WYZi@y2mSW}zHgMb(xS(b5F22wHAT;(4JDu!A$t;OCY`2l6Oiilp_P*A^>AX$k+=Y#W!dH7z1<7 zw9B=3`DFj}?P(Bw*r`8Hz8!xKO`olKoggv{tC+o9I6mN&H9eqvcOUSTZEW}1W@ey) zF3f4AY|AvPb`4ft69taXl7f@~l=+el7A7vx-XBWg(zp)u3-oB{GWgX&X1wjkF`t~~ zC$~S>e_CbpVuL1QQrr%Z{rtq|#UrLa+u+4F6m1Qr(6`~-;O z8_9fMlaXNHyo(z$bF!_B-=Uee9;_hG*3gYfuebU}TMP0uSK-&aKHmqtdq*!i17gmS zG+U_`pZZ4{+*>fFev&r3f0$26X5``y^fd1e7$*O`1&rBkw$qH4Oor~MhhUU$IqwTz zxG)-{pT`g^(u9Gk=B;-3F$JIJ{gR(xN1w*~s%91rcnS~L{*;6U+6YI{l~gAkxPPho zl<>pw6J+EISjzs-(1GelYcMTV)A*1g;E(~c?)vF7l`G^&F#_U#~WW~dgl4qlbqOYHhOmg~m`t)c% zwQ@#^GF}_9zC7rB{R|;687~pZ%u2n|O2z7g*{Q<}f`rAV(hR&Y;@!}x(8&i;r{0D4i@ol<9y7JfEg;ZeJdNy$J;sy?ChrMqIC7cB&A4|Hwc`}OuV z26RNs6mXs#Wu+oX#>9hL`ZxF{743I>xrA& zIP*$e+nSg=^&_)^GlPn&E|*1!o8NVpoBUscA0UlSXtW)-yOdKE+IR(1w{h8<$My9O zb#5?x77}cHFYgG|u|VP$twt=hUk)X*Tl(3e8%>mjE2lpjB<5qw3YK>_&>qfv-Urm*#ZhvQDA3)8dOEF4AeTityj?eoo? z8{j4Q{;GB9ToX)Zr_X=kPtm}eeH(?HZegYR$<3-lqB~o=?WwdQ=g!Njmi_xrBRYwZ z?YT$>52IKOyLT~G-6oFKI6eW5v9O`H6}#j6l-hL#=%j}Cbfi&E-M-tpQl7M_7toZ- zL(+`PgIim=w+Fx9xS(cyxv|{L{ipKR?du1s`n4I`*G=@xjsULK42o{6*(;d*|)Hqddp? zNJ`Tgy)Hn&Y<_TThfnV9z8CLBN#9EsCo_ixUFuYa3!hvw-!Q8+mih}PYhiVh??B4P z+Dsd!Z4!QP--JG27VG#jP?f+*l6HcvY?`QUbSw0O>)dkh%cd%yWqzYlYG&(tp($}7 zw|TRLVTVTDh~6n(SyEXj^=1!rnp0!*qt0aS5Nhqo)$i-0O@U8*Lutbd+Pmy4hd}E_ z;oE_4Xl)I2LvK}ftta$dkp0h^lCFpgIfb;W(~=UGE8S)S`}5*~5h3`#4m;Nl@6 z?yzr_U#|0NySLC+(DYdI0?+rvu-~^Lt#+)mDEyC8Zt%yTYqtkaLki`^{uIYs4^dL; zJiDFqkZ_2z<8RqjuVu7>$Kro);!vry}P=I@8N5sHWx}zOuE>tnR7` zNW-QUvr}Zia-wyTW2|ukIe{{~MHEy{&v5nEC$2g+j`?^{sYUJV^lKEWN1p5y26wex zBe~3bw|ULTiHGZD<#||4;)=z?;WyM7r7UJ-o^z70876O&6+6#=n_OLs8|>;lzRzFA z$M1X!)%}XN>Yhynhwch!w>o8Ov8&Qgc2OEFn|ei;7xIY8b!9_l#QxS7MVV<7kHt{8 z0;z-nwgxc;?o0%it_p2sro%VW2+E0?Gm7oYSjVp(mzC^59E{l!5l$sBKgs15zeA(B zp`~EdhlM0#3dyMlKnV{zqF`iVVyNQw^n0%PnGOy<0xOmhN;=WrIqrF3-WE2-7i~1ev(L|wYmw$@s zmc@mIb5jJjn4&qi&7|FK{V}lr#mllCrk3G*hcPb%9y_e@JzBx5rXC{9e99R6lqaNL z4ilGumPhilHcJfWZWy##Z)kKwD~ldTzd?5k(Hw zl0V>mUc3ISSF?2cq4;< z*^!px9^nt4GH7IC8dg{a#>l5*avNY0reWfDwr=wbAYbCnn0olynnOE(z33&*!acX* z8$S*s2oz{oW2vKR7YVQ95l^pT1~Vp)&C@vhD5Y#Z<#g%co}NhMbj!Lsj~&-qk6@W> zjba+DNIXuY=>6?RI%@y-4lDJ`9{D=A>Q&tgihgh1xjw?19xW1I@)_2zL`@bFfR-*5 z3MN#r5bvoZIU~D%Xq!Jmf||^sSF>f*y<|+LhtU(>?|qyb;5vMoufR{iC2#BeUeWaA zR-iCex=KIhzjxKV<#v%*7o)RFZX-uuIgimAW8MdK55Egc`r|W`58sgec(|A9%Q99! z1S%GhXaGVYX>J;h&}%pDT{6OK?#RxB$>QHrSW9??`n7g>Gk`1H>>(PGp_ep^?qsH) z9>3YT{H({@*RR7&gS!r0?xZ{dIESe+7K0|#jCLrZy_5Lz*{5aR94F5;y+PHQz}oUF z4ngBZrqSObq^s9`T1tCn zIIvvAw0=IA%C6(vno=lVtjjTGoz2tuq^kM=tQ}gb)4!tr9w%AJ><6fFm!C}f-5z6> z-%tzMj7q+FuuaxkMe6A{IOJ;TQSuFahb2e8JRo zQUnz(qgr~o@(WWrlJ?m7`!}N~wf>F`5e`$l85)}Bkf?bvt`oE+Q)XOHq!`Rr7Oyt# z0G$$sh9YvNO*?TgutX2ID=vP%kc!6xR=y$VA_%vQY|_g{9y8FU4m0UvlOOC?#r_h; zn88eBG`Rc`<%)^!kyK|242k{?y*l`wpEY&dEUClyHS+j>58oH-NsutZtHknlb8766 z!@ChemYWpi7(r4xixEMT#`c%n8~H#>!_BTKbZl*Dp13xreIo0M&Aoz%gnsWvFZ&fd$Ojk{AV zNvCk~OsBG^;73>w4kXAeL%>VJCkd?}(ZLLl>sTpRlMFn8)DGI3C3?_4m}6^C5M)%R zZ7a}opJBTzJ?l3+y9h~N(ueT~;$}Pv=j%E>GI$(*qOcSJYQRsWrgWeiKu-~lEP3Y} z$k^w|*cbZvE_FK2!1?4C`XlNY)O6_d_S(#+20dE_ltFV@Xu~;%?$SFC}|FBW^L|{z&pgFRM*VgjrEG{37}*O!bOt zb^8NxS^V<{(_=oEpUdo>6^!!6xF!`{<`JaDAw+j8S6ie^Y>BEwnh?@H1G|GXnriLc znt1}6CANawQ>kR5Q@%jp_D!wm{Dn6`v!WBqlgqO}07?6$N@!||6E$dMK$Gj5{u2m% z;%f)bOPw!)53q?TDV)lQz#2u|GVu_2P?^vVfsg;zzw0%7j-KD;MZ2yTZ(-YIqI;ZB zhKcR-{&`YGB*mk8f)|jK@ClDvnf2Aq!|hrIR1#xRt3p|Z=aY=9QPc(r%Ij&e8iAMA zS47v-4A$+ASChg7Qa=G!jPPR|>Lh!}IeL}h(vtsE^+b?R7Tzc;OvvzMp&|r+ZO&pM zzTc$u8udpinLAYE%5WZRW1xu;*3q~n$hhsT`F_!|fthd?`dRnpQyvuN$+TI_>@3YK z)4QV(tDux>lf}%Z8g*bP7T+lW+4!3t#BV_#usDn(fQux8G{*F-<|Z#9X_Hp@q?PP|O_)P=bB zS@rbTiZ9wqq9ppvZ>fkqR=vcOtDmRq+SZ^9Z_UJ=M>gVVHHcmBth(uR9m@D~UQP!h zur2y+US7iW zu$s;(=agDy)j>7+1vCI#o%Ni-M@V|v+z2-ww7_%Y@~jzV*{+7HRAau9jN8t1nt>G zw9R+aCbQV9HmjD{Tl0fzIS>OF=)Th2+}L?m>{a94+?&_|jpcYvef$Qg2A6joexHhf zw!3O&CKiz7iU1LYt3aTeZDO?RFQ;3nCk8fcul`7appt|-3Y0W#1Lv(PpCXp@;IZcT zma7^(>q#ENC~jrIy_O=Uvye^(UZ*2NE`rd`agjrA5~o~vF1=6~q3!iTu(hYhespOO zfj6tY-4(0^2}0A5Z~fPuV}*N}t8I0;=Yox0t#f*7R5Kz~5z^6aN(?Ud9D;a>HtRgc=FTT^1GXQMLl2m&z3(Li*49{&y~ zm+<#?QGBoy3kii#Nu)iCFJ+^$fIswiNW@!y9%uao@BaRhqRo%!zwX&Ni7!yJDVpB9 zeKuNH+!W7Oko=dWq@Qjj+k}4!R=b*g)zW z3AL$^uOmavk2emnrh9{?c}Gf5Po%l7ST{;d_xX(U`2wAu_!8+z+o8;&o3vr^LqYvA z-TCk=nPWOwk)&9bnF;c9H)p6XmPv}DLL@I_uXKMtICOUPCmCnRhvzX9GFW@9ITkaV zCbh57CEd&46iIaBQ$fgc(I~*_>LU-G#R3=2wXbmbt9mNhdtiBbU{byLQgPXz(G>Sp zkL5fwH8p{AZ{Z``Ui#dp^f7)rIfL24R(Blpv>9mcCkWlYG@wPfChr!6Qs=*2v5{ac zWuCr>>OHxy9P(-*E+;GY`pUZb_2Spwa3Cx&8SFhQX4tyI{<4stdma-lDJz<(WG+M+8?zZv!> zp!lt0`1_-?f)e7#-pjq~2_7uBE1wp>_Vlvr{&8aUwM_nJh1So?$J`{#pVgs1Ym$GG zKR?C6{zV!2SHnAb;e{)o=c4se);k?O(sulCS?Tnmoml^}A^m5c9lf||0)vXZFT_&ggy*r|)~m}G$Gf>MGhN5@mp zS;PP1p#Niss1Doe05c&)6Kc2_vztXj@D31Q^{WnNa1)|A>Ab5S;4IRUSA1BqAEcJWBu6aRq z&+gwSp@`NEcDtmXE$ukk@px-8L*rWUh*_=INE&?K<)!W(t-k$seIjbZ)X}JnK4B+1 zZ)wNuq2PX>dL-bZS##Hh{`=41FN@>hU$~QyJ;z!`+pDfLr!yj$879i66IWKyZd`#( zgPW_omzLvxJ?jxm(C6W5H6!w215&8piz?-Q3(>QK4?Fjw8?N872{m{}dy^;0k1hOg zpW;jG@mo)3_k_@IN#~-BhFH&O*s1^NG8Os*E?O)m;4S}q$I{c2_c#0POYbBfIfeoe z;&cim$COL1oO)CRtLy%{(Aw9g)UQ@cVri5tSOs5?xZm=qxc~h%`T=OzT6LMP#_=}5 zy;6=AQexx@;faSlPnBCaTTGKsO5{mG?qN6XA)F>>l0htFGh(9yCOIlLvD~Rr{raQ! zm-N4zz``r7x+X*#eJ}{nXsV8}ad8jjD%ufbOtkw}wRZ)$Gr+Ack+yt9VFy9>r9GAD8vz)tZGspc{`DF6AUO`PJXr66y^Eg-qn?&c< zqOW8;I@sf=&b53))p)2SifsJSB51hgF8KA%XHLgL_YFgrVlLzL@;QWh0fs?AOJT9m z>Q&q{?%Y`plwd}V&IP|bdVDz@_eS5zQScyTEz;PA+j-t%?RA046IP+SGtEVdwf*nh z_bPW(7=?CO4x+NxhH4g)gG>&``(3Zh>H;0oo5<8 zlzm9PygQSm@hh?EFY%+M-(s|HgH;07S^ewO}Kvz1xq;{3H3b0^(k3lt}7JLH;cM!WMQb>r!p$D57boE(y1`JC3N*j^tEh5 z+H)OkHHINTP=dW|PoanV1I#nhSX=Ke4|yD9v7ErnWz{&<5L-b zM>WlXOw-)8k;RRexR5+K=d)i+Ps2c-Unt4C?V^g|Jro+4uS z<|zzxqk0Czew``Py1OreKQIOPAWI~TN!4OOx1kWy;E$V795X{TY@Fzs#Zp?pF|rn7 z7g+Q~qOK0NQGHYPvd|O6nsq%xB>FlNg}u(;y@IMpZayywont+jYES0xR$I-ORHYzt!Ag z{#X`F{}o5kDaLJ%9p8T6h3zl&RXGvbjFao=Sx9qth>Eo3Kh7y;W~~HV&kWPQueQn@ z>j(@nlw_4dfk*~em%iR|Jm-DRydF`9kR=IFkZY}H&=Zx^($+fO&ryFiG!;Nnz!Hl& zXNc`)bdE0YmH(t(`@nGk>E{zg!>`JGX`B1R z!2X14$1>VzsW)Dv3Z}Hr8p*b-sXlSmBC<(Rt4NS;Y6Ek(zozW~KS|kaAC-5AYkcO- zW`TRd-tCZhH50Qj)7r$=udOi(0+!%FdPX`>Dl4RG*cGi|>p3 zp%7p2d53ypwqcWRTGa=Xbj`xkO=CC|KFoYPy!$A<(dK;FZbohTBMk0HGm6E!z2YJ1 zzz$aLu+Z?XjQE@)scr_d7aYHY zGsfTjgpno3P!D5m*w^BZ9JxAVmITuL zqt`+{-LOgdY}#jA_4zqrHl#E<_b}*OoZ*Mv;>)hGL;YWe z!8`-nF@fK6?+txbZihMyL8A2KOtn9z?^y)<{G9!9Aq z;k(g0A^-knvsXtQ@8i4I#8_X&oVgF38$)AtGj7ku1%kt3|8j>c###$6GR!bhFC6++ zqBxWiVwu9?SXdl)D8qJh<1U}Yak9j7E5!3+6K!+9 zC$o)WPaJqEagG~hrI08Sfbt$eW#75RB*kR3(u{& zoXcgDUAVRvk<6H{`)a5HOSE8;a2#uW2G&0m4?E{#v!O^5%VH~}b49(SYvp3^SajEC zv1!~fw8X}2zDfMBNO((mx4p{v(NVI%NOX51UaaiW=Jq8S=0H&ay0-y_>Z{TpM=pKB zq_A1iok&Fpb>SLolY^o7{=n3Jg_v~hDCE*L?iy`I6KppuWpM4vD~8CqFn}~A+P`9z zM#0i6Ktz!dh1}A&6k;lC?{1$eeN>2kf={zvXV;A9)g9$E3#CKa@`3p@~3fraE|X{3Fb=7HHQ6Q|BWmW;pwb#hOCQho){^c zrzY}%wAf0Z*v69N{;^m$m-t(Hn)j+CJ(Zi4ZQ`Gf#gE!=eRYyJE0_2!4YX_plUUdNFq(|(S5hgPLfi0&aJV?P3#V-hK1j(Al_e#lgH)833;XG=58_@!H~JVXrLX?rY`760*ov38ECAp0=92t9eCs@P2}9OPvqlx?2{4{h+_)rFjo7&ggU%y{?L&HZU(SF7yh$YT!eA?_JCzY?uam(vA zBZbTS)k9nt&{;!1suwhP%ijKmknPRM>yjC?!>y=T~b(>SIw?9U` zA>RER4)mVYt=5==KvtILN>*4z%Wk>V*Pr$D)<8QO3cXfE;b?t<-sJe0)AY@nk1c$d zn9j}EDPrB&*Qvg#+gWI#HYeLS`Hpy>!nT>N$@E&&16b#s0!(UMQ=~^@cwX0VU!_=K z+M%l5siPex&hE!UyQ7bGT?o)oRlSyqJtV;Xw69KQ$v*fff=tcHyIm|*TT|#vE7B+Hq{r)>I>sk*($ij* z(w>6hdMsZT(66q^BsY-ZqPOZ|#N>KY#g*LAbvxEov(%N^OU!pWYLP6PJJr?UCy*~ICH;3sS-zZcOjBZT8W zRAeM|malfs2R>5%`AGQrkPfS`71h1k)%@LSHG?90ElHB?n%-SZG(FYcD~I7j?=O$Y z`Sg4GOjY~LRi_vo`7Fx$u4n>lIleDeeYX#N`=emt1g z4_3D?y?b!lb!EY-?=<8=!qnaQtNuE3k*q0wD3R>NF>Qux>a^TKh6fL*wX&I0CT#RG zZ(SEnTo(@b)&>#qH?tkz`!PW~XD%slXWuwQ&eCs?bmwN<9cA|sHFhP{8dmiWJw|as z*K001@c~21V4m-6nx^s!7N_D?-NCn#(Q%*Fa zyl!X$q3KtDo0NL~w}#G_RWW4)c{Wt}jhp$|YmJ|3EBiQ_do(JGeoS^`gxj}yc zk*EVgtAud#=ylx6W3#;vB^$YQqXl6f=i==|;{VzVyaemsgg!aqz~LI?V#)?ub{QX37)ScLA>EaY5}ysyI^?rJBaZE4;qwx$i&7!s89 zBZ3^*MBs#(aW?bX^>RQ8Y@kaorrs!qF$n%;A-d2UM14b+wZrpOg1rp)9`%jqPk^<&4c~`w(&Gr7xl~qf*e36%`nxv;_)Ck*h@|wSNbH}Ga@!d>M zjO?=xg3Jf+nHzBhgUH_=+Eui7Zu5$KYqWbl+u6m@xBPakb^LXv=(W&?&kKF-if|{r zC<^mZm8DB*8L!QbQt1~5?D$^{Z}9p*HQLpkBkTFaY; zO8(ys&YWDjW*&4rDsgOz5jal(Hu|5XIg;1?TZ6m*w+3gx&gazgziV)T|D}liBiy-z zx$U92RLQe-4Fu$ z+m*pX3Vy7Nnq>w>idhkx8>V&7lJ!fPi^#PcOi!SEj#Vx<;(4c-X$CD4`aNYA3{=k7RNlSGlukrYr$6r_MX}}S! zj30uxSE+Z_V{X+v+4refQJE^UAhC~bg_cML`~M&8y?Hd0kN^KY#*Ep}HFhF1_BHz& znXzwaELjpEWl0Q?J!TAsv5X}ol{FNFWLIO277dXlgpjR5NUNXs_w%{G-|z37`*)xF z{Lb(G?>^T**E!d9uIpU?Tz@=X&*$SMVWkfkQg7jWJh(mezYU1xNbcgq?sFgOouJ4T8d`HL`XQ?~c7tCDs7N+oO?|ccV^4BO5DTw(h z@th;PTs8y|9od}RQ|M4L?GJSe2$?%A!)Qz*MS6_?u-;6dDIHt1&IktqNiuSUKj;_% zPNP(X@=dn*#0h6Hxa{hvk)?HVs5wwf=JJ=xrDs5jaHi^{UL#MQai-!rJI(jisVe{oM`<(pb_w#|H~U<{=-qzN^5@E9(rbF4*Dpo>v@FW2uW}o!mjn`XIE~M# z_k)-spsgd6HC@nL^4;I8>6V1+=fH)yD3SrmxW^`#6{o%3%yCB03V#o2Q)i4WBTZ23 z4eXsTO{BX)zp2C_hUoRuE!lWp0tWP(&5&>r(5hh#U_}^fufag8#%26(yNZ$v%s{g^;c2m(*VZ{xMC#iGg8%fh{)7GU@iWuTiJd^CRoHeRE#IN zs`&Rl*JHGi!na_k@lgCQ0B(eC9&R;0>3!r_kxjj;kOOAh|tp;UEy>#A=Wtu;^^P`lP z3vmMO0L{W$&m=m^oscAt;>(29%uOc|BT@ZVP$b>~k+lfgl?|q05A%ge=67lD1NVU_ za3rAVD~|H~S>41ONW&JCgNDN$+X2Yej)OlH^Ogx>(CH>OX1I(EdvFps2xR_i?Cqy}L zM}kV@@S+_48TvIczJ6OdLEizqT{`8ArKE<%JgvQ6-6Y&MO{?eB9Y{a0x&&4;CHzX) zz8sOMWDP$=YF_7SSb0bhCfeCpy4XNz3wWNs&3Inuxs$C?9xoPJ=5i?DA!AIa$9QTr z03&gs7-p3FPVP-tAFlG|Vb<}AYE<>lqSfaxVmTRaOuT}rGlxkj4A zrFyG_&b7P*wIkh~Rf@SZy^nK+8Mo$r;_IvC164a5nzCJw>k_Rez}P+0WuhIays@ZV zs(C;lwuq$zrmBuO)=fer7`J1$O{v8i;X$Cq_VD7l=GH$l6hnuL z^DTDa?0>4LL;dd;z%JR(dbaG7ATgMidFps?>VtHDPEgUoH(~r!W^djJqa|o$j`un+ zMJf;$S3kWZru=2HP!uv@2F=4Y)r*PmPh*OXn{U^J&A=*jMYy@lN6apzREc`8*~50P zCeG~`;%^^nQHE@r=rhjI+(po>N7u7r7-fuKjOc4kxU#pg9Uq!JVU3ug?7XH zG+&(Rm=SsMMnwt5iYr>aGU|Rxt}6rvnh|+LhiAqlxh3&3)pzNxvJ!x8Q^^;;stcQY z1sKX{_-GoI{Q_mP0W@Kup1~2{i}Ze8`RPXO?}BOx(jDTRxb4t$r(=f7+)uz=V%N`~ z9_al3=PRU(3tOf@r-;^L;4}SNObD(yG0<6AeO3?}X*zHRm0e1^ZZrV? z!Bzq@)DM{WFj~pEix<{spK=xx`38i|_5i!#ar3J26Xi0jU2%V5@s6--Ptn5S;=vriPk1b7_*Ak4I*L0$`87U>m^<;l^XBQg-f$(=suZTVtAbySY63^sJ8tw|QMt2lp2UXec8{&6?9Iz+$885Bg3-XD}2JI~_=FB7ZktE6r!NCGS zn82PYLk;Q`!5+S|^_LgHkk2eeZyl*0t^tM&i(>*jN>Y5Y%j^W%8-kvpwG>ao{NRD` z;BT5hAOSAsWMmk@HiU7Wtj`T`Ai|o1{%8Vj)z{SxfzK*Irkhgt9|!OAB_Yj%qF32J zCMNOcOS)!TO1zVIwabSE7Z_(3B;BNn^JZjd0|kt$w|Yz@uvBYv;K3j@{AT`kjvVHB zAvmkhfS>akDK^-J!?Ninm?h^?S2l=|0-g7LamJOq6jtbr{cxcOA#j{|)9Q`t?aT(5 z-OYHz6oL8q0M~RaH$+Il)l0*~rAxqrY6AkkH1 zp~^Z=V#KW}P25A5=pO?ab=<|7Kkmp1-9WZpF(3m?PEm62GMaC~S!O-BT~m&-FeJ!y&PV!F ziJC4@0bmaMbPvOQ9C)%{krZM~B{%%oAI-6EI~DzWUfDXDJy7O{DBvXUoKlI*iCN3e z$g|=)5X<@SO@U(RFKk%#VNk-~M{IFNuM-_95p`d zP^0^(MzPAD0543TW>X4A34C97KM>71q75LP3-+0MkuIv9<9e9G5VXrtIvsijyhZt? znbcqPpwTIzXbYJ;hv;TFxEKbi?bN(HtL6bu-0^?d8UOGD@DLu2a*PNF-r;Db*IJus z7d_@UT&b(J&9SyhXio*G1>(P^9$nwLU$6ThYP9T}YW&8hfcOAkzw+EM(7AuD63>qYRO3zQBtVKR(qXJq&$d z+waW?_Uwrx*Ry4q-9q+Oagk!E@89(+3Z&1v9=YpS{b}n)aMwwp2oc`V=r579Tzc|X zjb_a)_$ew6zzhFw&oT1uxLUShB_RNdid!2&*n2e}X+(uymc{{Wq&gU`?rP_VsDC-m zAw(n|<-nB+q!SJ7OD}yS!HaUe-|d+Rm!}mFIDRIuugL-#@onA3Qc_K&I&G@-msHL1 zHa(S07ds1Ail};dhW3jKx-YVN*V(OQfgE}=DbeB$x7npeTl^@Z@s{Y|0WlKN3yIIY7h(?&245s=h(3T+veq}FMhwFG zLnpkgM6$zP>|l<|YV|M}tIVR;yx57&_yc|{(?hZRQku;;_QVf8Zec7hdo%H9q^|Et z?|QVb=`lkhY~m&1Y8}j{xZAT1*2f0n+7*V~Fa6R7T&TC5&A+Djip!@Cmf}MQCpC*%o<-{^O{26xyoJs9=Unn2d$(lj9qqPZsxU$3w?D^#XU=QeYyyb#Pn4$rX<*J+W@wXPPu`I!b3 zE5FGTv`5y%hH(j~tlDqvwMlwhrp1VMrm=L}8$e{3OMjThZ8&GcqvG4 z!(zch7?IciT?_sXk6{C`AHomGe>n{gc?=r~&SD5qyOU68O9wkPYdXneq8M9c%%1;0 zvzAg2^zZ<|c@7gwhhETP92SQJo5L493`zg}75{=VtcN!uK_ocZ9DvjR`*Z%6IO%_R z;lCcp0s1e>1NmU627wP*&r@WJ8i)A%6cf5-yw@FTjax$g=t30s7lm=^i4s$GE%g_k;KZ8KWBBdM zs5wV0zqs1}1A?@y*ydcgO#TIeT8p!+^ZU-)tO@Q6s1+cw|K>lw@1#;(zvE}0lHRf> z_z_HS^WA=hDQ$)HRFY*q_~N-zy3rvBIv7zK=Boa-VgWrJk(4V*iF$SS{Q0_pAM2Ul z#sgm7RqRt*H+~Dq4X^a)<7@<0# zy_s>8hy9ye`xj!ix(=6qxEm&qvcASQc)Ps8dPG%!xT&@^Hf8Kd5y$)oC!(-({lkff zruK)NNR{dBe`mzU#8uDmE$VH^IvsK&v|R^Vif`64 z)7P$F&DDkefkgvWK^9Q{P-3_CmiB#@jj83$e_^AyIueSS3W(7qJ+!Cn1tYiXE`aPV z`(t|UV3Pb}tE^p8Xz3 z8zBuipSlH_a%cHM(jD-XV46zvTFt%tLv#@#AXih4;Ci(KeC;1>6#UNe=z${gjpHxG zlTn9nYxn*eH%dF?M$8J(`oFo6-@myLGW$Qckw<$yY$6)dyN5TWF1%dM6&~Fk_k3$f z5NVEggICmWE?Q_On)SYrKhLu>AWwsP>#lWH4YjS$YqPd*G`|0$G2wNzxBV;QsCvv6 z5W9txGl1zg;tRh2MT)^@Jj0bzs)Y1F=W`cOs_ngOt;4ZuQ_Ude6Zb>ERgHj$(HdW) z>F7LfG%HRvtx4ThpxoEYs&JGoJMD@@CWe#jJn7BC5#aFv(^CbLMT$wPa(JU8dfC*Q zi~$7|<0CzE&-!~NKwhf?R-vc=)j`rkcCbDPev0W5*RKJ9OnL-B0|2O48;Gf81u1yh z^1xJ;$a5=4>D=Z@4`t}SjQe3=1dOk_SQpi+>AaJUhrSVX z^0rl<-Bnk;mz4?c%EwRFajtVn0Q1FSEHk4tSp7g2pp(G+tgAGI#e?%(strv-lFlh~ z!M&TvhIwEs5s}zKhO%4?-E*!cZIJThy~Obj8ZU|EU=wg8MMlro;zE%n57HRkE(QnT znuc?$9F}yQBk9^**_eh#Z$)T`mDCgSeAfA;gcyW12%b}rrFTj7$b#_&kNYP5+Bc8Z zP{r+#5Om{)xO|h&!JCyidEsV{b9}*#868>vCPlqGLZS`HCo{hBuCGAx^gI)5$E;$= z4KdLDVHxpPUG`5#S@UW%B(a)aV{%0N+KsBHUFE~qZETjBQ=nUmX$%n2hW$vNNL$1pA08I7@?hA3u)FDWH`uCcA zkI=gW9o6p+${wyoJrY~xHKaf`P@m!~O;4XfbDf7DSu(6a;7 z(qj-*&tYwe5b8?dYGBLmElpa{@?i&D4uer_cWq%M_oSq- z*ia9+&=*UGIF~J?461HafVBXIvU1bwS@tMC_GP;n)Ti#o>LS<{yHDmOdm%?`{qR z8m-(vK|n}2-O8)2>sd_QF=~yUNWSZbv*VvH+FlcV*K2kJ z!c`Txpnj2(dKSzMN|dR@|HGhoAaoVYZc+9%`jNOYqodrrxMhOx#iq-)n7uw-92&kQ zl_2R_Wu~h;Dw(tGFu&vJqN`UCJvn-D?S|*yvfa7tE3(g@YD5Lu0<5nBy1Q zCjrN>^df$a*VS# z8HOh32C##2@AE8g1`Y5P>0PZ*eS!)3qUuvLaku4QFymk^6a+};0+-mb^wPnQ1ct>2 zfTNv>F!j)h9_BlrkNqJH@RkY*YMMY;45F7sW2NFDE1Dc#=6qqkwePNWlpa5VRY9WR zYs;8)uXEroKag?&#Fm6$(e1~u_k+y2AIGmVW(u5_c6K_rJ*&thF=WAr?z#KifDt>)_!B9H>Z{sDDir}wBX|VZ8$gpmK4A8da z3bVU*#mLO7GR@oPTCIHfZos6iplobmH~FDk^APr&w-P_S2DXnbSRcy>cGMJF=Hf&4l1Ve zbY+0EGQ?aizJX@SSIhmW%K9rnfM-S5OQcsH;M0*L>gzu7ZnGFfm(pdpSC%>;DW$qx z2@EFKZ8WDMrHv}!91YHZs8+CfN-)0%*?%}xG!ulXT&shEJiM)3#>0xb1mxghIEHwJao9!p zwN*2xUSIxFDZ%rf*gat&P9b#eJzLNmeDHa;!c?S%9XwIXBIGJtf;Mo=ulR{WWPWpa ztQH`2-#TK1WFqT3D+}OsfP&3i2$v{c5_O1hZAJz-dEd8yzdX`8#>A=IFsi)jW_i!| zL%39)0;}L6W&1c;h51C3EkuW0^{ZKke%%LXrj+xilGLLB%vz+){c>;r7}$R4STQMo z!F*;U)(2yB81j?+nqOtPdhDS&P2IE_+@&fIUafc)C;ipvV7^v0Put!$FPV^QJM)xuGc-V<>7RdHua54 zbZNQ8O09um-TQiumx)0-{jJ_ygv3%zP3t5ES}D9F^T_Qu2aq*y#<=$KBWQ-?uBs1`!Y>_PBk+#3@Tjf8e8B zJ@mj9X|#EqzzuiK(Xl z^94gwq8D3zW0x0Am?Zi&gmll6*S}QC?Yjf}3;EM(Y5oWi|IvhUb-~=Q{3ba-)ZvhY zsryqrs_Hr5jVM8KT>-xcLktqR%W=L=EovJY+t}iB!k=Z=RQ{K1vq4G_3y1AM^E{z|wLUz_DqwgRbuB^m;R(brR@dCi96a7dc*P8A@gD&hZtE<&ul*1z|dXA8{gZ%?;G|UT&Dhx z>KJVANcfH!`en(NBKy|0QzE6)FE!)+X!+AH)Ng9&@cXANG)H_5XA;u>Tc@|c5L3UE;Zq^P2MV4oo3_Eog%xu z>o^>O)k3IG29n8?>1Xms^THh+IPAyOSYDY`dg%1Krf82pd+O24{}^S?F8^;L2E?4# zC7gAL=2q>iPOOCw!*>=@ZF|`LQL!;%SW}}}cM4*RZZe?E03Xc5cO=-GCvQ5p)Uo3G z57}1em_^rMpFCL>umBduEK=i>j=G}ry&ki&3~se)XY2w}VLHgUiq5$BoFn@_& zUHv5RM)oE|1yRx{w_|$z*Qi+cTy1$LE8OSj+BU@B z2I;`!Fi-1tDSvM=bvbk-UcV@~hyIm|Hh@cLeh{-Dc>YS;b@dtZTs&DjY3L7ykqpgPd!|X~=s{Z@N86Zu%$kMwXu)WXqFA9cXe*}8#ckX?EEno5G`=L5i(Jp%Q*ZbS; zHvFED!aCIb(TC4(&rEgBOwY{B9{ib^6PaDmpIvmDU5=eyxjnnqIji0L*&D@ z{)Zio*+1Bs-P<32c7FK%C&YhY>W|1A_~abqI^TD1;IW9pv| z>eoMN-}%@I|EN3r@#No+KS~yGCl`&~7u~u(n%-Hoe7b1h`O*6CBH`GQDrwQqeaZ3q zk`Q*$`RUTR*(H9rdG}+>UdNYhPA*@%zHDo=4LO;2h>%N+IeYN1u zYT?t>qS@6ue^-68#(Y^Oi{01mo`e_yvxf2TYB#=!`T2Xt)_oQrRvu7Z669<#)Cz|- zkB7R{K`iKiMIGdv^0)=)AD^5h2vqu)r{~xP5)HAcgUG)=ROfB**@}!E=MKXmZqkKe zazNljRYVpp3R*Kz=@iqF4@Z`^tIn)jfWbuU;bj586x>U5I%;rLD($<0UHz zyUw|K9*3}3)2IQyNU|Vm4sc&jdO~@F&_+=p6G}M0%N2w^KL^)%jW$G}qvsI5k6Z zqt-y8*SxIKk`aN;!vn4Q2yqo)i;qXvDDPoa5H-Xv$A>qNo?rP6cm(SqXX#KVeyg1m zWJ6#79k>fsff$|!_D({9U`XrJb;2V65dDFkhx~N^VeyrF$pU>lUInT0;%d+*4+fh* z0Szc1Ya3xTKnFh>p1uhUk4F^F!P}DH>2vUVIfxA6Z$1&P43Ei+SAU<61@LqzVGcr2 zhFUYeZX7&@*fJn49_wr+5SQXV79QVHlmOfth&=$+ee~A_IM}`mJ$o9Mc=Okq_y?i_ zb*j?<%^O?sfIt}zf_4O29+`v1S#X6(&6DF)bXTV;!$FEp%3yf6$;;ey(Nkao8CdMj zkv5r$;(a{Yr`T*0>nZsvUk1znrfyrZ#z{_#)4nf_&t^it;E_TgTJqJzaZ6GC#H;?> z{_kiN1^qlG-_FPt>6!?(YJa*hWE$q~=P&5=3X=h?nnPG8-h#{T&W6?WeA=uW&{ zK403*DR0i1SO?x!AC@?k3&h^MwK`VnPSYou!2?bpK$(T{x-Wn<;Rl z*Z;OV@?*W3XdFb<9GfiBU@o2+;G5|L)K}%Ak0L)lt~b9R$=<3?+F%D!A|R?VZ-}hi zj%>jn)6{CLxf<>)dzj=ZdaYAaz9ta@5y=GtE7aXwt8VO4>BInXDeW@+w2Y>%*8x)T z=gt+lnaCLj1a0#bxK_M@NoJ-J`$uX?+lKap^5}AOusn9EDa_QD)B7 za>rknUV-yEDqr>Gaunz{pSym$qvtrOu{bzoPYBsflhYk)#FF+|L9_*HzR3~^%fIHf zpOJPphlO6k7&ViH!A--SKLUm+tcvb}ht2Nlw@o>N!UgMIBRzmnxNa_`OH zagkOl&15>GwixTLv;vyUY%asS$W$-e&Z_4RGKh*(PlS@ewlA=kTq3`fyLD%IKQx$n^Uk<-M=K@cTbLyC z=OzsFZD}oJK0beu=TM`k$s`@w7(T|v2C}UqTU2W&uI}&ZwE3DISaAfiiY$x+DYoq5 z{+@l-US{aEni>oPeP;s+&YFdGA&)~q#QVz7W83sZmAB-P8jqtp#-50^;hWJOYp2EOyDN>f=N~TgnDqQ2*{K>q&D0(R^$C+jyUB-873_7COTtx0+NjcRKF&#doFX3njg0g1e6&u za_(KbX1$vANvvSO3!jmkFRx3{9wu>WHuFE}j1R`GS&ax9G$a}b4BQRzK5A;%h!U!Q zL+7l1FZwMhtMjv(2Ico9T%UPA8RwOSG`W0stj*EfZYYGaYZ0NJnj%kf%EE( zJDilB6d5_493U>tB?o`ZHQ>1BINmm1%P+S&b-1O&uS_H2eJ7^zF-5)w=FJf-JHRZv`yQ|4{iSP^r7p zy6?yro9H(iP5CM=sB^e_)A$9uuaKLv#Iy^POrH!0WW6|D!DkGAPc@wct&NfEx-t~k3$C4z(aKWPwv`&qT;iJax6BC({=?C>#Z_n|;(@7z@f3^im)yvUoesBlNtybj@ zuv>BCWh(+g@RV<92}qfov&IBeG{81uyftd)^QskOEW0^c-T8{=jOI($kS+|v{gbHP z^L&ugXQ*JFQjDmAwUQpb>KjiseTA%DlAJ1pI3makG1=8ZHO>e4J-Ujv`cA~^^V~Oj z7>QOm=hIlR=Xp=^RKC7Ik3b|P%OPz`Vkv32`qh-Fl5;)kQ&OMUl z?ct=%qL^#+f-KMdq}oLE&A6#4fx-CU+VI<_v8?f})3J#OL=6Pla&qQtQg{an40kMF zKqoS|T-2$l7U~P=Y7eM6uc_ie>vRdZ{6_;L%BtlJlcnx6NB!m=L_}vMcVQz-JFY}6 z@mGPdPL$WNd&O!Wl9UAoICZ)M{fd6~EbDo|4y&XuXR!XSXj?w?UOq%B@d| zQ&YY2_#8EjccErGDSCS8AyXezq<)7{1z>`6M{*Zx;bCMh-E;I?tDnRz1<3PfP^Ugg zTz8O2u5lyBNA%r#?qCpN$h#{^(b<@P6cOAbYRs=g)QJ32X%@RC(vql_Hmh=;*du)= zh^wH1r_LQ z_xJmUg98`?#KT~bV1U&bqrZ|N)(lo}23sft7K(%JB*)dkL*f~zUIzOpZo{4don{RAkoG}p0!s<=bsZxNe6zSrVkvvCo>aP0?7VDGxwM?X1=eh~)spS{WOw0=A65Em*{A zw$g1KZ@>(O94PftG`#ct1)jAESv`loXLyRN_jkMT}o`fW5{_fV;d8WvKXywqf zi;SX!6Y%Dc;m0WcQJTpnr9+N=j!8CsD_~;VDl5}CKi>;`jFJRyE?rJhEVzqAz@ocp zB&75ynG=rcTn<8>$ndeN@_A_Z%8CK;9l-&qL z2hNHk7Tov^w|Iq0U&~4t&}+rt2OC<>iuQ3{H~hTiKHNpbl3TM$F!!J!hD@> zs-HK$ZnZ5FC~~6;*XHs+c6d-9fa5Ds>BO0Lf><>PtewhaCt{BJAf#=-iw38d?voWq zA!b!F#=a0UfplvkrCaau2_ghXq$&}Eehd6IgNOB)JiHD?ZuY~89VKz@V}a^S3-&^I*T^!r}wU3h9q%fO2F8+)(B z6WdV7&4E1NI2Sb0)fp)@nCD7N_!a}@sGyaBMjEErQ(A_FP3{g6;abJ!>m5w?J{s3d z;`JiwW4psxNj<_uVl{!exN!6nBvD(4P}f2&Ye_8MOuXmYe=umw-p6Q2ieL|X*)Uj@ z_R<$#tbY42TqEb1ei(XqyTUgX0ewg0(9NcO+SjSTgV#56CHV4eQ8MvPH^)WGHMYXt&=EAl%EOh{U6pslLw1A+JzK*%Kgae~fz?Y#}$N@ITES? z_)zl-=kAR{Z@+s&>$@`joY(YR%FK)^=3wfz^ZN>#+hmgakIJ`K;FngRS^(L&n66rm zx-^-n1AvVqW|Jb&VQ*)NfOgoVd)QlB&^}*`9GrC$syIx)G)ULqXC=;0`^mb^{CN$k zFnzi@6Jj-^VS&6^^dS@EuEi{ymV-}AVtzp5$qIR)YMlqXvt)t1=&~=y>`}D9tHH`R*0w^rSwY7SjV+Ql=x*d{zGZFO6F>NY5OQR=?uhRlM7* z#!+Bs-n}ZXT!!iPgYA3-_gfBFfJL59@CTa5hl_rBXRCRum-yo%tH^)=nFW-97pVQr zpg9X96AKRA1gST@(&lNPZ|Mh9#b~=M+3zbi??yUUzNSHFob69&%DAM1sw5|P&zFW< zX3nq%1?sb`o+RzWn%_>vpP$cU+jq^qm}M<`C?X8P>3%qyyb6xzuh;B;pi8Y@Boj|q zXP^wEhHz|Cr%WH)9FresUuqL5d+7PNZvHq}5ZkKKX?yRY=83!{XNtuD<;hl}_2!br zez762`~#ijIYe0(SDk#dL|!@NJtr4aTW?>CzSe%x{?uX{+*yJR^yz1D-Z_YIo=NaA zj9nlc$G1qv+)^;QW!+Hg=srf2x%D{sOxj@@0C(x4X^zssbdvIeu%SgF?xHy1Vp~Mk zd+){3{Z9?57n#+QWJcS;wi_&n?bCNqi{0LtQ_Bw%_I$XGi&tDgN9B2w`lki2zZ4IC z@N!TXM3o1v2y-Guj&nYzVQ%a3N_I@ijC(>?#%Rw|A20m4Z7KfxQ&x>ERiT7sx^)8l zgG%o0dB1G#e|S!isXP;qGTA0a41t?$zCO|iH)n{76OWJoLQPwmzhCgb{&Ou)9k>(g zdFQsGb)ZEDb4@tuGALp_^73W>lPNoBOkCS#Kd8GUK>A=Q-&4%#u#?0&W z7GRwycG>yTdS&Y81G0zbqtp%lo1a@|X-}@t&%awI&P@*RkqzT7Gxjt-ihV9f<41%% zMz$4K%2TZ;FlmgpNq`c-g{28x_y&IT6nEh}*ILKz>e-YFx7tv9$~B2HFY+c>9jIAK zsE3L-QaQFNOM1MWHp(ukuMlNYO(T4}BNkn)+aCy3U2$%JKkp+Ats6u@s6Q0p;RfGt zZMIgO4*nKYT)T;aEwQE$Iq%MMKT%Zs`PJ$gRmF0PCII12_8C{8CWgT~{8BDCO4uG# zeWppaX(@BHN_{Z8tdUNO*C@gJLevG@u1su7mR%CQ8!TfG{GROh*Il*RUR*OoTswry zZV-H-VDorT*@2ef=N9G`ZNIkC%L;w|xViFrdMTatG?8$lQY+b)wa~ZIJy|knyA1#< z@-}YIgPas0{ z5DujS7aCE;muk+EZ+h8LizC0j>PA@)w(dNo%}z^;6Qv`#*ofaMHIICI#CaS!)`#}Y z+v7>gb^p91R6H9aeV(7~yatf=ggQIT=9gS~;R?cC8aNNz6K>j5*9ETJ-D~r;_{g^x zm>NuT4i90yf=u+QIhithY|riw^?BYYBJEn3?AWV^=U?=H3K_o^_-2D$>wDeKp6`+H zU`v~;ULpqprz0LkM}S*DMRikWg|9rizxP!88ptCrV08b|_s@KJ(yZuxna^Pn;O1Mg z$8!WC0gcF*=I|LL?5_q_QmNN7l~*Z-IbUZ3$(K{M^Im6kzfn8Zn05B6X2$NlE``c~ z6q!wMNojhJeGA^(QVTaz{yxvch2{vzh&Iz| zPq$S@{mP_9Kiyx9v(p8gx3f5aKa<{Q>fK6m{w5k^)%D!Se~*HDDEFj&>&iWpWb%&_ zS_om$wt%6nM_;01v~JxKD(;XrV1ECdr~Ny6{08FLuTDaJgTXJZ@T=#_T~0ckcri}n zQqkv2{&tWV@ttxmdf+r4!)H&-#joY;Tb%;=!aKNIQeipF)y#vs)sYZ92Yuie&i4*3IE3#5|T?suwSTDOAZGan9Agg^Y5Knp@NW+?i6 zm;S~AzW`$6Qh?)}TMXDxvj}M-wwDSDOiXY9vU!Yz;K%Dp%6aP9#v@4-Zb~Fz!Jemwj_RZr9bVq^_J9uQ)d#mwQZCU*Kkqk)y^9G zE0Y=_lcI0PQ9e+dbBdfBF*Og%_Q==55YWjX;X8~43rt?}$eej-O{!W-?Zvv+De=Ua z{J_a9e)!_z^qK>2oyXFF{FFae8>R_MLh(~Q&iqPwlA&g5PH~P4H}-baHWP$_3-nWZIBA}V2PCi$&wQY8uU1Y_(KjL%aI&-6P8S2i_Qde- zDP?ec=frqHW(v^wlFk+;hBYr<`Wg{%Ah8vyM&bS`Sz%m5 zT92rPwrQ;Ml4zUvD>Zc$mo0uH`}oZEt{UTyq+cDj9~Lf%&)NC(QohuY`<#33xj(6D zKEWL0IXG!Q=CS^&+w4OUN7YKk=XbV|h9A;UxGBlUo#|8kfQ2X56=s1krJL@L0P(P8I^a1&I zwjEZsh7QKlM;;z;d_WE@71BNjQ~fPnT7@sCowsHaGk*)``~gsv#XcIoGB;M&lrn<` zfApMK;R;w;f`rEDU=fW#A94oAzh5kB=h+CMh-I zcv&{*rC4@~sjg9S;i3emJ|f;$YDCa`(Niq0O8NjqA^B+k?w4KgwUE76k9o53M$yy0 z(9qPIYnb7w9iswE=tzz2Bzmc2Mn1VH1j*ChfwIKr-M6Z>&5A3ys3u8HaT62w=N%EV z1Q7>}#X_>6k(4UpzT}=@dK`SmSo1q1#R0R)TTwM~;H{<@#pNJovu|TeR)$D}7)TKb zYE&@@5~b^z1lV>PlERYonWtr<2P&c8fdN=7i;su~wMyNV2|IL<#c9j>t!$21wa%Ay zWy@MSA>);p_$Y~rdo~u_Y#Hur>}nixeruaB`mzZ;tj^Ea|Ahm&(V_gLj-2s*UAyux zJAvmESGD@tvXmlt#g6h`Cd|~0dL+)xAMst1JNK<2QEf34W4KQ~%0x2adT-n@@&Jc< zbmNbJ8Hh8RU><>~@jlhOFy~Th&zPx+LA$1gyiSEnY7Zt~+q|;~Tu|^eYM+d=mX9x$ z9ANy_fcBAlODIqVAXSwpXWgY!*?9#&amg~lnIpXAk0LQaetMp(xdk;`8=UjtT*?M- zi*o_^%FQ|oK=y{)50Ihx3`n?(XKMk6k@_?u3+GMFoYhx~di!8@7tG%Q_EL&5I&q8C z-~4p1Q|bC4jQz9S{OqrW&D8_>ITr2~2HQzxGWR);5xbX|fA=i@!(-vW`u2ZUV9N#q zffW89`WDmwY1R0DZMJn`9smDEVEfN!vi*mrSLr_+D-e>5gbakrAaRl~?Bu%t>UNl= zBPBTl_5ob)|5QnFVIBMb%`g84%`Xs^QP2Yx-hcOPAfW%j+*=1U_4ob%V+`0RH@ewI zcSwV}jYd$qLApdhQWTZZ&FD_)kPa#7RHP9_Nokb^G5F2T=en=U`}e)B`+NWS{d+rS zJMVMO`_+%95*Ua53!&n%oQk$)!n2R>7oZWef3uVSnz#AE3z|$zz#~-jw<2`8HPg*| ziy9rdFux~WR=`D8Z-Pi4pGwFa@Tg>|!NPhZc+2&Y9YtyDUl8eWq{vjV(i*Eeyt={I zXP0@=SOwKcWKc1qj}r=PzNgGZgcMwCj=L_xrdf7YsH8thdQYgGN=L?;%|upDNoG6W zr_1$;3B6Wvt&bec#bzwSK&3B&Sst(0m{dAF+1q&t8l^TaLNzPMO;0XQ2`Sr?t{JB#|j9>TLo5;RTB!RHPb37#E1ktY% zAs_aDERgWAPETNj$Ip3yr*9%YaM6VE_GUY8s=QHdAmR^j zg8-5|DUJ)12_vU$lPLV_Srsjqrpb`jl<5hue3}bVWI*U;IFz>rugoL@0Q2LZX`S`s zX6{7dP=Vc!sd-bsy&ZDQWRV}A{UBgJ7Bz`%9FksnTl`M0^|06uGaC{Nb@aP0vr@BK zA!Tg2cm2h9Js}YuG@Q0k^g+s1`6>hQJSKB|#;>P9G#*P8$onmN-oZI-xN^qGxHfv>xopXtVmlxIo7Agb91>u_0@(vrv~$Y5!BnOj#&?MfcKQ8N3wc1x3$5^-^>tIX^OsNp%^-5ua z9sSfgO%(PaAv1|2+>2~Fv?w+2eM`2!s*5D)@fo`ecB*9wJWG_%T&@Kyx9G}F_LXtH z5~3&K22N0G4Zo87ZUaDGZ@atF@kLX{+4*=;Dw)tjz7)`kkirDM8Y^CkGk=3CyDr?Q zaF9dIbFAcZ;08jjbV=i?0NDrk^}s6?0)UR^dU9y?X%!)W^M$qy3YIJ{Ly1U&s49W# zZ(v<}?qJ|iysgE!6Vak;@eDDjnA%3H6%g>DH?JZ4QZIli5kxxC zF1#Tn0!HRr3&{b$DZZu?C!rR%b0ovAq~5{~9C0amzJE)~=_&J^9oS93s}_p!NP+h= zaWbA}`!XJTE#mA4*p_xZ!WIfArS&8iL-cANZ5#EASmtRxU z@FM#G13!Tx^ReI&hFH%*2I?v11-=m3_o87}^<83OC==3hS++$(8D0{K4>>T;I*k~P z>ZL#Fv0D;dkn(2WNt>gI5m)@gW*3DMzfOg4(pQ5!y_@tvu9s+txpbwr#M<$#JL`~< zz$qU}2i5_>2_{NBSnXTNXjR@Cf~^iUI|j`!VF<3z>-w&AFwtKj34YhOFoTRdd52V$ zgzB@zX+{**GE$89X!3<*rDTUprR=R2HYH(X>Z1IH@NDIBdl7kg{Th z@k7-x6N#O63%fB#MJJhJ;t-yAC0a%cQ`F$4k`^tzGAFn zQ>O48_k3G<-+gaEq-Rjsef3zP6Frp1&WQ z1_p`&W{g@dMrKw$2RS3Wq@OW_DiV*d0hUjqIP@gXTgPBlGX<@6cUwDZP8)lKlxVoCAzJ{UBYD=!_rQ3j4JnFMg&4HVkB@$G|PB3*=_=fC-CfJ0ew^>Ey^Q{MeCC_(E5U+C_ z`y!PY4^`t`ik!`Jo|Fk*l0WaY&-5Dpf}n18b7)PElvDjv&yEVL$YSOvLEl72 z5ki%CM4=u|?qy-yOn zNplB95=9I!t0mbsLi?bCkk%j;UYMf?Hsk<{7>3>f+$M(+qtaC#O$0F>5PkN&zF}`4 zazNBxOPS6gkwNc0#c5{vAk;WLbd%5oi%*`MQM^s0<|<>MueYI1z?!CqxwMA4%1~KD zDSo9Hro*0`hX*=Q|2gFiBA5o)00sX2$Tg@X0$4nu#uo+s z+XYk&rV@L?vM^Do_M4(7$l&?c$n_u%P$}Y77KEqzs901_##%=G;{tVK87fCX`ZrF` zS_{tm7$~V>z&%xA+~5W}Ocv0p;g7X)0R`UGsul|kO)AnBDvEcY4J*(uv(5Kdkth&4 zKY3=_4E#<>o>cxE{nt447VS>=pcQl52i|oUmj*ag(B_16h9y2ulz^LIL5*8OO7?oM zgt}*Ii!_9JuB}b7_jS&;-D8c0Grbf?D#EQCoI#^9sh)Dy>jP6K}jD7%wIIF^kd&HiBwjIkt#G0)H={g4vcFi*k6GWl3Dh!B8 zT@#4ArmrS>BkbrkdiY1kFk7Z;l99?CIo=I4<|D#EkBOp?+s0NnBq~nkT1HBa^@fSI zxIE@50}91VsigBRTs(vhB#h;vGD|3FGW#~7!*w(#{&pRg8OMh8Yt_Th|VZ#y7>F~ zZ`B%d2{o|-$+l6URf?_}=%R-es9>2^)ku(mbA>Ih%F*wcXe8-#KoQ<8p8WA(OrRzL z4B)>!6(H{h2tvB)YKrilZZBAGln$NSqaiYgPcAV&r*!NW>b07>kG@{<_Bjqvv`ZdM zlO|q+ItyAK5$@{H1&BpxH8Lyk0yfsPUI%N)hxWOr}=%IcciDJlYAVi6;M)0x7xc#*cH)r%HmG%Yr*)GXz zdx8GN;?ejSZe?^_M`8rZOP??Tube^ZCSy$5s9Z}a`HMu$X4TA4D+#YUvAoG&B)gs% zpNYIl@y4u%_l&|0#0!5Pp#AP{i^T+e@wu*q31hM6*a}G2Ga4CV)aP7Z{!+tVDc!bs zho%45gK+mvpS{IrE?7P}G(QmBEeGu6gQl;OFu(y{?$zCrcmUiYAHa@4WY_aEqxR&M z7<8IYDM5y(ASwoMfD;Y+ zw3Y&N-^sskg(5(FwaN%rW3&PWp@E1T>CRQv zNBI}$Ys`X-P$My_eAES3U#MiYDWPnibOp9jwd$EC<+onChtI0KAl76qiHK7cn-Brt zGB|;t8pB6NaxsEohB|pgDnd?ypnXx)=taSF$7bjC>zq+U1%;@0GCh>e3DJc2`{~Pd zg#{)*i$%bb+dSqNxP2hX@An57b^+W3UskSUznf*hmGM%(ib||d<`X~3A(0s58K2)4 zeGM=?-6&>~LOO)XXeNolKuFU>iz7#Cf+0?HIp$WE%px0{OF4JXh7yAU6|oRp$7;Lc zOZr)+#^@yCE~kVt^H1y-1|$I|HmGpIl3;~MHfnT;@wn3rot^!qI2O7~MvDu5L#QUN}WM2P^wuX||g96){4umEj;GhlVyC_fn`hQCEY4CIU~%G}g@Z zUvkgl5`o>pOX3l?$m&Z2fB>4Mw_#wvr1CwkUX!^#1HU%vY>$8f>2%|8L>{u7rlN^E zrETWHB0Z(FlIJx-$f{X^O~{P^Zja7y!Q8#@3ak^bwi<{sf7D}$h2F0Jo@f!Y6}}J? zlnCzt>UKmlfQNlIZ}@o_yv%G4m5=d>g@;B!vqQ`3FC!#G_tpgY86M(>xF_lX+OJTz z?n`A2^D!xye%3RUpTiEjlvh*r+O^w)L?x?fcA>`TS~aM4Svk|L+Mp_PP^Y*9zs37} z2IzU1LYzknJYI+v&;`vexkeY$v`G9ME~Y;AT(K2crxV8ZNtLXAvW>9kxi93<68k_} zd4*L(vkI?XJTb+{FfO{RyOoYEBYKgmzrhn~o9b;pEFk>wra6=>qzze~YC?qaxEPsW z{&wY7sp)<646q{!T^tw3a9ezmD3JWVi+PORG73Oo0)X=<`W+0ouhQCJp%s+RG2{X= zkBT(alMyIwG8w{WsY9XKBZTN%DzdL^+eSn$vBO?jIE7a6HfMjbVrFn^nac=!ILB~C zTY=ieta-AONcRH*J&B5Q9IaoR+hvcYmQDZbY_^ARpS=UCLO*&A=@*!vdlG0GtRhyF zQA5AWBTTHr8cia_63RAg_}(B&sWf6zL?;+E)lDox?!eqlxhq9JVsoX~hIz8}?zOAR z%OCfwS$Rs-V?-MaJ52eTKL+I8w*5iU5%HWpqgAk3>ys=1Mbcee5gf|@y%KqwrfQ}0LhTJP4tAeCz1U_x?tW(wd`^5>SQmZE!$f~jbJ+F9Njgd*=vJ(Fn0pkbCL;U& zQ`q{wjt^R2pp*w4z)RvDijRdRJ(1iym#J}Ozu>}H7HI^9?~3q`cM*4GLGl})sp>-} zl^9=~#YSsr?kN;~#x4?#80OfPQS5b)e{*8~7WZ)S8ffnxIO{FIN><#wOD?4UN3;Y< zQicVRSQxAXajpe6RBWUam5(rHZqzPHR~MFwGLGC)KWKeT#nG$}83dJc#S(~;bosY4 z)f8t{Fg04+i~sV<0|8>$!`Fi)iu3Mq=vV|EA4m9GGI((%K%eiu=sgpdw4FUzWCe!E z6++dO)K!cE8Xd3-AK^ag%Nr!d1w^@H$D&Fd=-MJKZpg|(#TBY3t zne$K?#}cjH1m5xGu&dcCITNqJm&Xv#N3y;a@DJm-FZB<8<$bH0;fo&M^98XG7hrOyT_t-wC+BQdCYWZqLH?3%UleV5scZ$Mz$B|u z8B@k8%Y33fff5AVN4i|J5Fw)Ra>va}l* zZhsIKvfrWxm*HpPfhs2k51!n2^$XS_Msf25p-@4-22klDkv)(XtEXZ*8ZZCGEUn5R zD-D$aBGMc3;-ygxM_+{42>ZM#tgtDT7N8CPL@Y zvj}J`G8z!b=t)fLy&*g}6x~Mx2yoypHFo9TlL}md7X2L)fGi{1lQI)CI_>xuP z!CH#)3FEJqG;E*i$#zlt2E0%`T?z{f4TO_5S`kH#lpktULlJPf)C)^tA@2bycSB4q zY(T?v5+bT@-Bgr=IFF1K!PI0vibIMjfY@yVsO&d3NUu|WBI@>i^EGVBbf#ma|3(t+Pdx($_yC-&PVE6u zk=PzP`vc(*sYoS4nS==E!F+rVBSkxo)CETAW^6ZEM|S@i_l2rl?(#hhj_*#s;OZci z?WK)Q+!g|?S`4$(qMF^p)zr`pJK8<2De{rEoJ-P0Vm6E=H)vZ`frGZIex zEBL`f7^Ng>vVK&N5fj7p3z12_BJC*pM;TPW)?glKar6i?Z#vV<1Mts749TSoq|_*y z_MD5Lo`Tp(_WXrXRsOZ7a8`wRvCN4(;JTd7d<-Z-I*jz*=R@$)A+=+m2nHY%t;e5{ z&%M4z9=t5uH7OFhg%C!NEtrZT7%{e1xL7$a|6!mRDv+E=hp~`t z*DH)5kp@2)D~!BbTpJwMCa53{EsP2z79&|#%y5G%brxQ4+|uIBygs@A{G~4Du-I*$ zU#TgDPYeiQ<*4FoeGUgAEx>?`{VMmeC`%LQN)&x(Z6%pvpgg*oXcDqa1Rtp_V$wm7 zRR&>>>xkNKbAjMT522hP6=gP$UocXOaI>g*kU(!jRYXZ1iQ0KyHj-?E0U^5OBs!{5 zxUBmL0YwKyV$86OW~k3TiBwkAHyIWQ`BLHoq83lqG;dBz0v)TOhL!FHur=sWx7aP6 zCd0!d-FkP}1G97M~5&S@2p2hd3-=H^Wu8B2BeYg21 z!kTYP(7Tff)lXl3GblxqW1Dz7Z809sh9mFHhsf@}80;$OBq3~lZPvB%sB0^$Yp1Sh|4<-5~RB;(%^&b~kB9H~C^W z<&SPCOAnPo4~=;bT|f^*b`MiW56fZ?+m9YNOD|HPm(#qLJD`_0yO+PCS8%ac_(!iO zOP{zxpM-gzR6w6hcAs2FpTc6_^&fqx4tg2~YqWX43SRtl;cn`0aJ6yKMRW1ge(87`~8cv_Md6`|8o`5gzzoCZpVvH5McgUxBHKz zIr_+dlK;7B#aXtr;enyBo4Sn=39(FZY=ppni8xpjzQaT4{+8|h|6}Na|B~JO2kNaq zLK~qNP86(01A)W;Jbnd#{BPM#K0KX{00`(tA&9WNf`8~?;>(G&uy!xWHx_SDal9)kn5|1ag2(;MFomRlJMye&hz`lXt=1f z!#Y@Lc`#kn!ZfD*H-V1AeM$kGGHPDG`vfxy{XzP%5e-Cd$+cDpcXbz5n7S<`F--^_+PA5USBcoB(OLAkw-Q< zl`5Y~QeM>ytc;}>n|6(QJzp+PWfm{_;nk@7ic>a8<@Lh@=g_cg@k)aIYSf&5MnffS z%&4z(-QO-gT`-+|o$3oV(y!|9A6U~ex{*enM4BKBlBJGS__2L+Do3&6^7KpABd5=5 zS~WlAV2^!Ia{F#bJiRWySPA}A^Tz##*puh6_jqV9>*_@djyQ@f_MjA^bT+*u*{0kl zQZLesJRR!NavUZR#&EywoKs`{iY6ZG0BBd5P3S&_glPy@V(|=~7++_7r+342k6|OjM!he%RNMMx-98 zR9n8)M1~Aoq=Kw*?lbo5wAnLOv@-b*I_$BF7q7ABcp zGKjL1S=k-!>bYa*pdYL$0<}3C$K`&7Pl~s*8u@+lBQgw`Y^w6KqWRJxbB#9I@segj zW<`lZ3^fbC=JWj-WD#_d6#dC z@g1moTd)A}>C&ba%#VU)em1Ca_1lvQ9P{C-{qP~B(`Uh0@3NAAendECz534DqF;Xl zP~Erc3BB8q(ul^z;j9JoujPt>n~kA9Dm-nx&JMS_4&r56yJz{#=e8B!?uzkMwUw2x(LDGL4^O9W`0}X+`@VED@4MB#Bh$}Y zMs3q6LxF{gvzLpimCaZc`+6IzoDzc@WCa4clWlViPntxlLn*M!RCFK5PbCrt-1XnN zuy2sJwop>NGKDTIGDV<5Ge>TD(?2T6)99_)e_Uh5f0Uzm>2}_i|7q}%3@7_`R62?y zF5VB`k&*Dk@8#;YaMU$&HmXRafxelW4pZ-QZG9go&fXJyXm*?feZ7?j=hu<=Bo^eu z&{RGY%H!#6RzUeori=1PZPb!1>%0P8Hz8i#kaLj^ZhbTaef=31r;j+~S5?qZ`RZ+G zHu26-`T1gbe0*Y~%_5Dl`ptX9fyq~kkmw{~V9;&PR8GAO;tcv16Lw^+-`HS|Qp)gO zS`qFVIj2skO45UnGTw-D*hR)yXh=NYc1&pqJKsR6_IE z_mxxOK}thA_j;F;qCI!R!wK&VTA|HbKBm;ZQp~rB-ke;DT1aYGR0_hyt-Xg}zmoEb z`}KdxIK2$1cPb$BHZS-wq8*r+=yBd)P$BWKo6sk^kUi8IaaH4{aZ~)Wiz0Sqy;hxQ z&swWr&+H$49GZ#)9)}c`mur6C$fY|?viM0|zGi7u#w&T-*3$)fwMXq1JKJnz7ifbv z_TrV8^HCPWj_oXe=!Q@I-W}nr4{2L7D!y*iSktDRj4w0So?oA>ApBft`k4C+o6!bVk< z!VX+nkKepkxS2XAJSqEB=b5F>*t@y5)23SGSbf`@W^2g3y5`o`)oy-cX5TWJTe`17 zyd9VqSDDUQhjXf|lcF>KgrWXza(}Z@{|(youPz@Gyiq2`n`HnP_8YqjREof1@x%rY z4yuOwmsRt|H@J`i@M1^c0Q|SA^uVw{As|uM+U=-Ytm;eCt3`^loVJ8an?yJ!24M7D8J~Y@Wc_mt|Jy4d#ebRW_bNg0a9X^& z5LmO1I2MIhaU*0N@|ampT41;{d?$$F}|cb-b5@4)Xi8XHw?zCKc~|k=hMJEeja> zaJmSd^FZ@aSh{;GvVSf7%fN@qs$lh4lqT@)D!x{hE~3gbdCWhdo+c~F|1h*dJ3R@Y zSxD{zrK*euoVLb5lKIdGVL}2cT5dkwN}?1u9}r!kF5J!1n*XN9Shmm&f>+kXk)OLU zRa65?FT!Uz+kw+T@9G<=E75@j-~v$o%rlijW9-E!T||O1EkRMCU5L09!g`zm!SKgZ zV~+1xBmC>#0^@HUBQMVCk5}s7-LL=oMw;V0)xdz?4=sSp-)LjEMRDF3bvPBRh8>@m-FPmFWR*PfzN0ok<<3;2zr@x=iMFlq zXb6Owt0H};NN}WXe6}L_7ei6-$xd!)SFgcUaZme!JRQVyPEwtSXPQY+QuY3wlrmYC zP=!Jz=atk7%!7)Mn-ef@^(c9KEpAK5BAkwcI{WR-YKIteYRb+Zcw~rj@`k386DM`? z8^*jrS|?NYjj+ky>gm_a`lC5zg$B3Mlk-bH44W_>_dhzT4DIc`cN94-zPC^qt*F4^ z>em|VmWa5#LQk18C^9*(Wn}E~;rTACl3HQyE^FXdmOM(+O@a1+7xD>G$)W()q;wU6 zUe)(c^NGqP*rpf>*acROF*!kE6a(qn5b=l!&fEuy?}c&$J?S(QKU3YZ{KeR)8j)*! zZjSZ~0c$vp@-+@{I5sv}qnoVHCR`Y4b+u%iAA8}%R=`QaY&ovfx40P?Bkg1~xb?%m z9dXT!2|$wtlT_vmLvUh0R(9PSxY`)X;RxD>s?{%)Y~Z~48CbdeD7{HiHT`K!^`7~+ z!n4AVGh=em0qgb_G9T*4IpnzHw0QvQ5m4ThSKwq{;#odUO*h;o1hBNMI>EZD)R&5i z47pq*SF*$@D)8uhHJUl$yQhuPi_a@78cBj5O2_U2EpVfC_jt|jPVovyMCKz3mTVA_0 zP&E$it#3ESz6R(Mc0V{R=b2$`THCxiByT+$6%3^K#N78z)^_RfAOoM!K*qSUFne#THslMi%mmoU@Kdv@0#M4&snr;o>n>xjSrt;JnN0{qF~|%`Xld!MeJVISuhK4e z^N5VH?_;Rv&3GNIaOW+Adk*m$yUwj`*4oD!z{RH#8AV$rit$P29tq<83LoF4X+>U5 zzELd7DL@{68JHibMrlW8tU-QD32{9=P9Q06>Xr8wE-0yU1)OwUn@88DNPj9>OkX0( zyYYym={%mc*SgSVlqaO@VyEgNd0a2zp{8LrrkJYdj#AsSCR{C&Z#;h^4@C@+s|waQ zsN)NMUOJ6EZY(YcqR=qNl*n_r%lau{yaZ1l&&>rHnuIwP+3is|b9qT<7# zhzwR_!Q11y9*5;z=^;4g>*`9%xGgRk>!^z0n3j(96Fe7clC$N3--}ND=M)6mrtg$U zpumODM3y=VbJ*((V>R(s+WJjqH6 zMlxk5{bZR2=L9y0g(NVe2?J3)iE41Bp5)Vz6`J0y9r}p3b(y^lw*-D%1pupUR9-%0 zj;DK@wWc6&$B!pJ7~YJE5$im)nxo$B4nc{dohW{8Gp7@Em!}G-uL*;jHT9eBo~hD2 ziT}d$$!sFWq*o!#2|t}tSfZ?}iEH{4rZDT|?ro4vujppoISUON%m7*YKbtRjLLTmk zlY({2^x+_vJP{#8K!j_x!`zTvS)uw=DM$IBLfO79pN=ausq#XnshrE)4MHlNy|R^4 zpwF(SvV3+rX-~)qN_=%}0bp1eWSp1bv}K9Ap>3y~BhWA8Hra4v(WZr~;EQxm@*%zS zh}33p>mb?bUFI;tJ}|Zj<%zd-D+!p)?)S0xPFZxad$t^FaZ~o+jshoXGc`lsJ$!wHJKh^Jm-~=*u2@2jkAW&k1d+!mZ+bjCJI{SVG}_(Gx%qM8(Y3I z>O9PoSTOK_<#how0BUt6WmTT)L|{ZSG9^GHp-gdNwi4(9O7L*&u{t(_qC$PCb+7Sc6AW@sF$x*EtMLvlMpnP$bi&*ur(AXR!`FhEp05f73n6Y`VR zX`JMHABc~^$g8v|at~>ePM!Hks022(i4%e{(6>Q7oR()C(#?KysU~`ffh#!D8<*A~ z)n5IK2{MBRpUEotY)03DJB@6Rwzjo|QoISuki~{*mJYmx@yoJ8p72d*_>WPYg?gsjNXC ztkv5ez&f22e;9cXqA_y#s=>6{=G8|EuzRBq9!1(iTb-caRpaIL-O{++w~3vM#Yq$< z*^;^WPYflYtLlYF*cS$efe7mL2=Ww1);b?-^(Q5o`(*9hT$9?ObMw9omoLnn|5hJ@ zbG6jlk#h^QZ}1_$k)|(02D|TXuF4=x)!rS%aj*@C zJ2?4}@(Sd5X$C08ax2nP-zQzBCib{bY^m;O8X0IPE%4rhY|oQ@u^yg{Var6MS^BdR z*^<9J_hzJ{90{j>%1F6fBy=VQ_2s)+coj;ctAsCcNjs>kW+dN~O$|v;ZCoL%=7iywHp|K7Gc~LdfwlkI)S;Hn$j2ouyByiy9|#Z9AIAZAiW?4B=36= zAAo0*z6G!rBfQ|`tqqh{#qUm^1+?p6NM&ip%GAxY!5jwQjFmbG##2*+HcIdFXPLG#8<;h6_rda6fb@y7%$6ANc zLmP!WGpjq0o?dej||=1uJT zj#@aCJFWui^RP5}vfRi4TzDG*)XCmY8ajf6bAJaeLYBa!bG>`y?7bOPVnlhGk zs{J!#V@>#b$m;LR&%cJO{uH(OJJbi`Pl&{alQck(8Wf8HlY+Fhhw*aN^!$8;4hRM* z7dkmuAJ-q5m%rot--j{$Ga~`|b6)Dtyve@{JO7b(dW+X>{+)e6{_`w<>o%`o;N%p| zj9}PskAxvHDON`Gk01Y?ha&weLGT!WPb~rMme~Lx7$v9>3@F9|$-=BtTyA0j3}T%Z zUa&PbLsBstn#8CSW;jwz&gN4YTqDMdmlW}KSdSHvYx$Xv7eo~(|J2f2Ll)AVn-bg{ zpksPGUT9R6uOWHiNX1oYsQlBMSIKTNSQrAt9`D3qf*>ZW{S1b7e}wVB(@1|`2=_nJ zNdHlQI_1Ajjs3gD`70*>AG3DpUlM>zHb~a7 zm+Qi)W~u_q$RSmgZeufYtC;TA-a+lcXsm3rP=rL|cEU6Dl4f&y>!s-%My35Xjjar; z|czi!+;XrBn5U);(1{^)~7PrPb;>-T`86|uS8TL4p@TxBAg;@qGuE+ba$ z_d+}?HlH4!WTIRE2>(d+P=Bw|Db= zomQl3$vR)+!Ztf0xzY}a3x=;8pDYouh`e}z!IjcCps`!z`(0dJJc{6rX+?D@-4C;2 znuaRRS4)}ZS5t%tF)7M>5QoZg^ zf01&;EjBpnnd4c3A>x79N6&T*_dm`x+OG&2Ha1ISP*^-onAbAaYlf;=<1HK-bHR zo8}Qm$sb1T)7@piScAus&E`l-LH4dnp;?7*N5jM}m9HqMha}H$5VwoQgJG&W*IYMvsIW->|#tel}%C|)=`uo=nD~i zhRBdqe|Ml38Qi#z^C%mE+1&M&vi*P$GvrfsAR1Q%-{s&O6*r-`?U;YCe%0Vsto{b$ zHZ{HSQ`2jxxV0kf?z$bFj%|r4`Q**}+QsxJ^X;n=DaE6f zdk>GYmdQ(Hh9DYdiAUL6nx%3)f0~uQ)A4vi@_*Bc`*&OHU-su;TkQWSB1Zraq`)Uy zqY0%6erH7q|4KyvPPP6Y<@Ud(4_3S4{@GlBFSnbI{4WIGMjOkgOSSQWZyNahwbHo3 z<-=%G<$R4*Uli*<1m7ww#+s|&w|K0L=G<%%o`3TFV&TJBOU=^Dz@#rnX9;V|@!^C5 zmakgt*6JUeh{t44ETKoie6~+sy=d5clkdgGt@-fS3LB|IP3e(&+&u-nY3A@bQ)+d# zz-#y8>vrjZVgF!4_FTVwhn0cI2I4OB2Z3vek8kGP>b$U>u6K{;PG|V8`tW;)<7M~< z*0b*Ex#`L~Z*m2XHV23(MZm1rJ9U$JKfgP@m-gd)f40TM>!`_b84Koi(syZwftdX& zQ(7o_TWZCjyzdrNEJHSkL@ljJ!+2LCIO`i1BFABz%h!)5g6HMNl^WtKCuEJ5{4ZAw zR^t>-w>Xr^GfNN;E9{MPajUEg%ki30+v`ck1Zq|uAf~j%6bWP+ho^uF$)_}{uor8t z3^0FOhD}NNMy6}?_C}V+Am3)T_ndQ18rh2TW^Tag_GVrnG5=P62%XDTK?HZjR$+|P z&ek)W3jcOdvZ2d%ak@jrc1gDH&UR^j82?ULQL4*Md09!tPDNGo&Q4|R;3fZVRpXq? zZguNM#qRTt)1BR#ZeoGG+J3sbdv(Lym3#HCq;~fjCR7AIH_jN|{oM4{q4IO{qVMkK zmgO*kFRkmTcfY*YDyjU^w%5G-rG0-;;A_Y6+}*F8=Npw@yMCPRetiib5!~+v(Yx;V zfO)F+d&#Bu_WPi!f(QLHMy>|~431R?gDie~2Sf01!NXzBG}prs-qNbWQNfnI!!gkz z!J}6a^R7p)Wj3ph#ud)?j^3b1gpMba=wG=U{nxjx(wbivdo5poecvAvx%_cF?|%97e6!~A z*N?NWmzMzYd;p1BH;`#R5UiOGq#y1kmfOcdWAZ^fYCWW;`#}t^@` zVVQv;(6DGyrL7>y%M%b%!aDS$++S*A3^rpBP(d$Ku2tV%^#X_tIg0GEd_wW=J#;uK z89@>4q(mb{5UOBjLp_fIAvF$6RZ!LxtoTw4n84DE7eV-v0U!cgiF!+gp`RQclxjPO z^@w@KvZ*#Cr%@ekNgm9aQmi7GTL52uyH@)O47x^oX#5z|%YMaKP=T}u7sF|Yq-PvK zSJdHBl8YGmGSsbPsS}o= zIBCtdS19b~nPG7+3n^eGNjurxY||#>)CIcN-459hUu-Pg`Q;I$O9XO~1;LK49 zc*Axx6sXvht)67B5hie#PQue6dOVNZor&BNTGpeK%R3;!e=wFK=d-m4N!lmVFZU^< zqp8rg%U5-KA~#i3zA<0Rc;zIyt)Nhaf@(gyxZ9b*3a=;6?cd~F z^WSFjc45#dZ7~y}QYtE^oX$+%exNU3W^FzI5*i=%QNc+#7eRh~zv=|#yd6zU!~}}S z&qDi=x+UDRTg{zoIOCKMcZ!FhV(B2aTe+ZxDiMI6tmlr+oNud1uxz|`@krHBL4nJT zwQ{LG`FIM`WN!D=jSkH;keRq>T5RaoDj$ggwrLQ8inS9aAFc8ram3rtDM$?sd`COzo#b4Yfq9fK z%Na;?ei-M{%$mmb=N{u5Q`)UNdD0g2T!fb&hBp?qR!2A^ zm#q2vAH7$BgxFk3j>wl!;JT~mX6&>y`q)zwH>A4u1;QQnz64>$-kzXt7F$*|K^ME# zVt8b&J!gn8*Ll34ZpQLX=UYT3O&3}=_Um=+UHX|{-;dwWylgw!ygmI>dHd_rn?DG< zfBaJIj{P%jLk*z8V|hUMH<%Q#2Eq48Satl_@$(Q8_XagYpQuixB)12<*o2U@&akh;RiUp*DZ&5hy7`aS@_QHK z{l_l$cb`a45Q>uSM`^8fUkD|EXpEXpJ~WD2KqX{L^x0rI!wolbzWNnqeAYh|q&G;a zfkiVttV$1yy&1xJV{ZLWd{s%s@~_7pH!sElW0vC z7Rw}Ml|pVu+AL@+3B<~v`y7V5Go3*$_IfI=xJ-Lu{sn=s-H)Bl1RmDG+$FTVss_Nf zrUq8bQjtsb&I(YQr7~A{{*ODp@Xa7e$twzwKq2!W@=#Y=d5?&cVW8hB$Rpk371qmy z5Ki%KV-I09wwNm5A*s9|LnPiA(IXk|IPp=}loy8>}SMA3WIebRV%ceJaa|y$df){#r z+WGMN*C|%TcxKbJD&v&+wYSm#AA8>&*3`P@8$uEi2$+Q41BB2KkZw!pfq?YhdsUEb z*-`?89(qRzy-JfNDj;1%KoF!TAS#Ll5EUyoy7!#f_s*O%=bV{8=04B)I}fb&t@3{F z`n9(j|7UGe5bYdv=zia|Xi(+v&o0Y<`Z;DIf*`|=|GWCR@?h6xEa#8;+lJ9H{I~jk zpTF&b3gP}af1BmS>(4RSUPd(08eBVK_TF5zwM4Ik?U-49qtaD<@LovGn0ASrL#k@7 zzj>U=Y9=^&H@QeX(7 zFgYJ{A5V~g%x)%jVDCU!ZAOT+3DUYEH)2?B?nyqX0q`A{o+AWmqIFjMTO*FkzMXPo zqT4a#bwPD17dQWZ_1!9X>r5FpjqyBu%#x>Zkv+^;*!5si)!K|itx(G`o9>llq?_v}Wb zpArUQQdhWlbw!e24?NN$y;PmyxPqA_3ts`LO$)>gc?$#V;M7W-&tsQqf#^%}qr%DX z!MV_j2i>$Wc(2RJB5(mvG0MVweVEXLB{r6*pSv~b76yEt3D?sChGM2+Fk|+tS5>x!kPSWI&--I^B%tg_ERFAK%*dh;LH_CW#Me&1g9`PWZS^+;e1M0&}-RE9`ti0S@} z&V9?)QS{Nd_xGbisCvEAqHTFirQMM;;kG)YvA&DDTZs+8^0+Y$jpAs+xr4AwC%j99 zLNGq9`(8F8HbgiPk2rGp2|VLBsD~-aY)Lgk7~|-2%n1?5I2;3Yve3Q7fvj?Yo?ndA zyUgPb5-la>tP4Vdx*hoop$^8EZ6AN?#GUn?{j68-$R3}6q(^>~KRV^|=-c46sm~hM zc|*RsR(XUcVBM|e=5KPy7nLBLjPKUt&qgT76)tstm3>k=?Sg1{)TF%k$=`Rd4i}Uq zV`;AGEf3ywx_3%=e{8q2z3istZ^n=PCXW0F+{^90XM~=3BnT)yrV?%5Ags~Cfe~XjXkCWa{l+pP;>+Jk|E_&6>MvU0ecJZWFm`|+Z zO0~}Qo3wq$fIP@{2vP(em6lX-GI6L?4_0f?(>{5}j7(R7f*2AvBy?&ug*n#A+WE9B z9hX&&4V^??MIb6Qf`rxS7S(UuP2Gy&4Z&4I)my5CL;DLfsS%VH-Z5!m`zwBZ3_33& zH;Ali^eqbbMEuISWNXnX{i6<9jhJ)R0M*#QMHS_QA)_#F#iwWn6e!jr8dj^g`0cz1 z_t$&FXxy|@5Zi2RHH;D3wFHbmF;hN_2tXwpYl)B__QzlXh0f|F%e}-*s=oC`P_{@j z;_|pe_;?Kbx#JQ~H|fL%ucut1)2JleZP6RiR1T^MxEAXozioLh2GgF; zD8wyV%XUbV97aM7jOR8;av+h}bEXg*DsJlOP#2$jusl&50YUO-!=%K*rypNfu^5ZH z<(0D3KF)3apf7PVBjjR=x2De0c=Xz6CTFC8ZVDn^XKboeMP>}sW2Kko*d`QYR-)mW za0ai9XCgQYBQnva$K;>I*-^9zoI{=6)22l&Y=fK+=cRN{Afs<0xyMH$iE$wxusV8o zwVOX98r3mP+w?WN`VkqdVOr1<=Zap(2+i2q`BI@Amy@g9_hoRd7w!1Pq}$8D!}3^0 zNGMl>u^FaK-t&km>m$w2-CT8BOzr8DFwdraEv>S5h5%fhMhp1nad+2xUim@H!_f!H zhsFCs#i48dKIR05G*k4c)R#i?nJ~SU>ZDU_V@+>8Nbf;uHj}MBYnyT7^QG13D7_LR zk?fLm8%mk2>LMyv4s7w;rXVi=$opy#KhZQp(K`jXVw$aE1FJ-e-@GSSRsnN(UYS(F zrPaD9+I8I=2{^|D(oq>M*J$x=;qlS3WkixS+^MY5MNqpc)kznPgj@AFa#(SH7r2>B zv7EWT)LK|wsW4!Zxtb7=E6Lh!Up!Y+d{Q6l?oSwBcggX2bAh zFHT-39|uPD_S}76%6>k*;Rz&=!J)njr5KhnT)e0MVN`|iR)eW-hd(3miZ%-T+12* z0*k(`Y{lzEEZjRAmM6BlllG~z+~I8G^4G`fus=0-KlgNjUwy^G&%Q#h1r0z$n12|I zA)+Yp^qd;fn1)$Laf=Hi`7+I#DGdn z%p^JAi$9WXzDupD<;3DaozjVv#9VPB0K9+-PVT=7j|1(R#-UL%X3f1PR6+g&7|o$x zwwO)vyREoJZjLt}r^k)1iwZi<%$lLIYxLKFYo^&SwtA~<`x4l$3k74* zfhfu32pr8aQWyKsh>}SEuS{w+{HJ^*w}hoEVd%5qxl7$rN&+@NhH>Shf#}76Fj?j@yC&Rr;tzdKI0S zL2%Vbv`Jra;{ifHSK6XOt|!v0Oc$+o(;KP3pL8ZpKOXKvyC|krx@LpfFZV=QRs%jdakq51pW^OA0F?Ft5_OvP0fM#XYIPorW=Be% z$R8RTNZ^7g%$SN|q7oqm5p}4cHSJitOx28T`3g<4b=%ftOx*K9N!vb9iAHc)rjTZ) zx6rFL?0|@4KF2=iP-SM-DP|3ir9I40j8&Cy<$>a>(QBYPo-*CnwUHQqfa&ZGsj z9_bY`Pj(`b0=l8B<@4UdrG}kO5No&lcip<$pLghwo;2`wh{%!?W~X zE!7x#U1#st>(WPOdbDj}Y)p9v2Ho}9hQX0ub<{XQ?u%w7b)mB-LiNOqla56zL~fvD zX6T9!hk+-Va!HHVgY%};jy1H`A4z#7V#Om@~;xa{Tg7O2R#z*pb7&EkjWzOqNXWgWe z0|gu4s)i7n?s4Es%0?BKO_zVSGL+v#Nd%zlj^EP6pQzic3q$U2Az}p**&_;)4kt*Z zY4;eTl5IouW-hTM&UpHtO=`vRx~d{c?9QHBS_LxIYX02%9!*SnZ|uT6$^ zv$X|~kEw44oRD~dPZcF1Tz7@#ef@0@UQ>`}n5K{j`bb9hRL0AriW>TCsgws>+>(3K zs9p7pYtGr#q;_!E%CV*}sT>cCa=alp5g* zwJB%+Fn8un2I_7`?ZVU%!ad{p`m6k>5-lQn9z9Kcw5+tvCPAlDVnYoIf8$=A8rI(F zmh}!kcsecu&g`yN2BiCdGAT$_yX9ucHkjEPUak}5SZl8@p3iBAPem8ILAPeT5SWl@ zm-L3Up?Y(qXp7HTa0>I=+3FjBk48d+$5-&4)s(z__+<#4?dT!g3L&(YLiQFSd$Ull zlk?9B;X=p{ABSVN@k4%GHa3%Ibv1jCLs04M#j9H*H|Rc|QTG6_J@)rPl#`*1j{T2t zYl}VGb!lm^9*s0y1ep0kC1bmZ#a5r0ERtnbGy24`kcSz9-H4=b@1x1BSfk8?-9GwY z_95<7wve(gNtyURIim^tJ7cK?7B`BP4#)w6BCJOAEmfg zrQ48W1S-Tb#CR}T`XU*#uMX~tgM#xrVgyklF~j5*81rWWeeS98xZ_pjMs|GU(H|kV zSE5aYRxuo0ijiL7S@@Sx-2p-{? zB+%ZYA>bYqYGTq~T0PA^Z{jF1^g{Ej8^_5i7XzCZFWc^@)2`fb8yDf&SWq{`?QvPinM(c7@W7IuCWv7MX1CCWr!tl<^anur?m6eQF6_-Eo%Eceq-F6p69zqP&tksz zhdFSvplU#H>7P zbI5D~?7XZh?2!40IYXzaIUZgbp?x*{Q(P8IH0x5Qu@XZViUt3{M0isD#hVed=w3ht zm-s5T*(w>Mf1L%BT^2K`JcZjJC_1hJ35vDO3hTIK=ko?i*Cx3DQk2)IRKIQWr{gKC zrPqxVDJ!Fu^4lT86UsM?XY(@jX0sBpGg`p{fskn7ah3U~Jx2U|NDM)ta)7;G#xGuk zG4j64hQU#aJJ9pI=*O2{#@oc0aqmT>uAt~mu526CTgDqqCo@BYjaB6!&i1xcq6UvB z6|}=B>J#)_RFZC=bwT~Rxh70%-aO04mhSao@Lk!C`1W*c)AD0HG&wFV!igr$QCOX>G53W`+bX2JGzVD!6yk-%5!WxgoR zlP6iogqp9#Oty;eJ!WB;l1mjlUD>#ecPd`b5>tA%9T#4zpFDq&>EwM;9)RRF3ur#OTt zNh1P489F>C%R`?%D+A>SCt7g6 z=}#(S2uh&!NCO4k#|uxT21A4i);QTiPYK&rAHJx1s+Jj}=(CUa^2PF@Pg8C=qqL4R zJKi8r#G`Jr=PlpjO0*mT&Uf!FR^~l6DHCF#z?;`$yg1cE{!SLjLyON`eXEhPSAz>4 z=lM8a+dr}2mZtCeQTgWR!|h0C&FACcRf>YRYsP1QuN@yp0>j;H+A|wpt|bVXZMJJa zPS?~E47ugIDKaFc^)C6pNuk5bp}Km5sKOnRII*13YHX0BcPCCRr5x_1cZX+bCth{3 zoF#nhj=-0l1RR`-I84wR66V<@>k+A_ys;sy`fj3e3YD!!Z&=cHH_3XE%F#78EPG)$ z*%@BJHL5qFP`I1oO|0Nq_`fOirQNiM$qIo_W22|O?50P-E71&uF%6zQ3Yl0b%sD=$ zqrR6xNvXt$5ytgx_cHS*E3qo$<3<-c3auOD75mq3_w<$0e!MyyuI8=v%4e_t@2Qmt4+_=`lT>z|;| z0nD{H2L0(6p8YbYVXX$|#B{v+emNqwR!dBOCdqc6%5|?+M`dCr?ZSQqnz>F-SARCM zaKBRAuuk7I?QTW7z(l7fpIOcle1pPTG&xcw)!+O)a ziMeX^4|T?=_2xDD^YykL>aFk9TXs#%H(&VB;LO}$J*xk(t?ZoL3>F7@KDLkz8(qIMl6n|jnp1PO-JbD0>NZkt z&WYRhSTB6kb@pRZN$9rMD$i19T4z(0$F|R-!lmoYVNFdI+kW#r%N>VP%1zg`w*zJh zm)qZdY`m$oeU8)Mmt&p2=Z*kSH33IHhFCX7Xah}>tRkogC~{Cl91ly82C|;5C2%Q3 zJ0yJ*>MbmTqU)KG@R%WFK1EA|Z6L{t?8?Fs3BqDq5hBJw);mgM1RwsYuw?Bm2NbQ@ei7$9-RXr@7F`g3-Su&?sbhB?Nqr}#*||RF~??E z$-FD5^&TPy&grNdk2FoXZoCN>Puo2rG>`nij~qjP{2 zgahER$Vj-gX%U!8CZ67e+cfW|F>Abl=#u6#So-S%xX3z})>-nWNg{(dgqGqU(sP0& zl6I54sSZSd9u2m3?NH=aHrN+$eUu_QP}KVdxo%ny@tqZth{inSox?&KzoMel%;}eU zPjzUe^t)>txHDbT8|JhYf;*92=Rxv=!=&9LdDcyqCvU;R5W44#d4rrIi`pWLsCX;y z<&9dP_roeXBY5JfMl@pC`u}nj&R}S;D`@lfgMA#5CI|e!d-b>A4C83&g$-MO$ zdkc^F;tL{%g&j>CEL&m*b1!IL&T9^_gl{sLCW{;31i&lM@}Z#-MI++m-F4@U$L9D;j;9#D#cOKO9cc81@;@b5xxLSdI;NG<5@sNXflsxCYbl$Fflmp62any&?qGgy*c-!sb(3Vz&4czz{y7*zgV zrq%(9J&k?Cd`)xx96l^|u2|SBP|8&xclsr9hypXt?@k5=HSi1Sma~-4-}Px zFAv4W;z~~WV&7Y#?WQkHeqtbYh60gZ*Kh%65n&5mU@9jdyx-jr8_BTiRo3Yljs}(O zFfRixv+iDIK!yccAvshv@iiA}`x!ARh{Rk(!>oUmu{-Ck5=0zi)gD=c4s%*_qp_0I z7KW}J<}52jwHPu+?7U4E)7U8DI2Vgw4Q!pFR1mI|H!ow_9Xk&QR2%b&7m;1fcCyU=T833P{?vFZJcX;DbT^JqkVFx|B8!e~6ug!upkP*x>@=wcccyl%EI zxa>fu6k-_HBSCZy_7RTui)ZD<5VRoALRCc6bRbaP=V}B((HikJJp9b3sO6nRIk6;q zlNeA2W4NBglm)U<6`|4Z?tn$yK(KsJK~8dM;u+2>=+H`7OjLD9of&c<-#*mJUwte# zcHy$tViGjCM*>H|APIBz>z72nqS(o$Nf8W`E$Z>xlbZcy3Sw8q}80W`o#7jhMB!UI1VkR!%v}gUoCR+JL20;Sh`4pFnB}rQ9sJ@&E*&~qh120?Ad}Mr7m!fIZxf7DQSh>H?`3BvfzQka zFLMMWQ>-2^aV&T}+EZs>1?cqC770&_sx|JcO?gF4O@bc%q+}kWQpJIl&`H60Hp))a zCQ%TNyz?>(U9VQvroO5jsc(Fo9|R9#ptgj(?UFoXh|=k*L=Lzoj5W`IU{V+#VYGb%L8<6BIJ)vSf?k)oHB=Ypb1cfSOcC9`amrtf{8MF?9EY zfA-OF0hAr>Vu&5d1qwyH@J2edFkBM_(L(4iex?zQ4A(qBS~n19Zp1)Maw8-_X9KT; zg(5s-k+j_UD{CcZMmw-b2-raPVxW-T1w<*#V~QHX?*{^mOe=%^$bM@o6 z4spqmlZ-B{ZN;FvB{-OEzaqkoBNC4jscZ0oC8m<7bOt)8m@UH2S!@Ks9AnL2wx%@I z!X&DU)F^}9Sc6X?>c-e_v>m_EVRxhR;*IX28@)Gf^ex}G_4P(SZ{OhYz9G9lT6Eu7 zQQyRkK9&6=!R)B>&-!MLTg~!XO*dGanFcR4^e~y+w9y6!K0(}aKqDU~Tj(Kf1v*1E z4b1UTNWZ9Cx(MV#gN13-EmH*YS+a$0)Gfd1TSqc(AAbfiMu3giK)?a8O+T2`1+tY4 zLeTZAJp%>xGXxv;Pw7E@xwk4(iKeBnzf!`1gk}C^mu%nlMxGsUB+P#cO zYTrF7>)vCD(QX!Z%(RSQnqIybA z%k9ipCqnhDUf7dqyUn~*-iw*Oi`%l3cdwr{90=#_yw0O6V>^<}nRkz;K*H$4*G2_H z@kr-q275Be$9XLQZUEwb(>#wM2xsZB@1gM1X3XS{GO~(m%e$)Gz#)!~#)%vNTO$S=h zRJ85Y_#AMKxP}X|?qk?4H&*bRu7^ zX=hUZV+B&hj+!KWxATpmn9oK`V$sOB1;7cSrm=~ASJD^-iIh?GGB%FU`6zwf+}mjI zcx>k+VNQHHk7NfBTKXy$FmRHVL&DSHRZck>#{pJPQJoePxxyo}L=#S-D!NnOo`9|q zv1bYteRwMCOdjG(Uvc?wO27wX29ylBTE64k7aomw%H4$r)M`2?ik%y5#R?7+=NZY^_rf}fBgc+dQQF}yi7@Nqc|;|E zos%!w zMfIennxEamg)Zjn3E72J$<^;S`Es6Xc_jX9$Um;tVKm(^+%X(*X@!Cyf9vGOB4Tbm zzVOvm78Y8J-l(>G#Mn`&AO zDuLYOy8hBE)ricoxu@jHt858<-Y7|_E>v`$*j!o4@FZq?NI^_CD#eV;8S5Ues!_Zm8ctx4E6TNaTC$r=%a_wK4z8cB5kZ2}d zn17`g^XCTSuU?gZ{D%I^il~gYnxvKde6>l&zK!MwC0hB@xe{E`O6d7%zsa>G-HH zJl0>%oaJ3$x}!H0)Ak*rCS1g{vznIb{@f7Z#j&ibaEz|SWSk<@TfjRszNtsSWZVEA z22!6fX4Pp5ODXrre;AOmt!5!@Tqt{2M&A@sU}XI9OSDCVkRTxCkN{cWZgj&uk8{@r6O-Tnc1bGyE&*N@T4s*w+`a_A}63@0#4v{Lb6 z)zGNarHq8DiQ)+zqu54`<@@45=3VD91MK(O=qTVH`P%0V076yf;fHppMD+w_RIZ`zd-*}e?j9C;WRt$HeJo%#U;AwToL$F`t?7I^5@~ka0OJddm&#u+Ae!yFBHq7BeW?Vv8M+Mw#2@4}Jh`^utW|`mQwCR0l{DJ8P_$qMVAz9Kar^3Zhb*TP zOXc*hb+%I3?p+nrFG;azfcRK-+m*1@Ft?*vrnJsp>=^G{3^Ggf{j zZc<)1Jb_t;Dku7a)Sl;5$471?mf9yO5S+h8!;aqZN7pLcGpX?IZafvj3uW}4Z179L~oAeQ(g8!sxa)}x3~)2a)jwS zDSNs|-lS||=i4E+J6dNHDScQ650}adk!A{$7B%5{ETU$HQ z#Kd#1f|uDtSM#$;W;|QA2-t&QabfmM^?sIAoR7iD&!%Ta=BkecJU$&p;}U5ZVL#S< zjKkIEu0(BSo-%x8Bu_9eSN|YLw5UH5{l&b3QK{bayM$@e(p)~XqMUt#6T^(LBX#I2Csn`85F!ewx74sZTD=jK?3YNc;o=QjE%A_kB?rGC3! zN5R==$=vPzQ+b*T?EHX`)$v-hGe(yV!&P*PRjjapOjKbtCWlLzd~nKDYN>4A*EG=IoUK3a)%K zAX46c;L3{|Kc;RU8gJeSP^JWpcz8K@?oYp;|CyyQ6;|TmRTec6G-BiV!=tv`XnmDo zCi25DhwyKm&#fGHNyjb7{92`k5o_MnF8Rf&ORcp})8wMPACtM*tcMM=c-x_<>P z{403jKL#)S1C@Ri2}B&mi)#t9AfXx*epH_L5LVVC(Lj;Pma{b^c}hM^JB7-T#dRDj zyUTJhP?)WqiyTN2Vb$IzBLrsnepe0@amLA!LrL^(Rx4wiBxG8s|5M>`sIJm2<1T5A z-6LdiVNNAevM=cl=la2j_5m4oi7Jq|>k0kF160sJ_B!MRSSpbuDTD80m;k=A=Bf&x6XHtqFt(jr@=s zm8uyMheI@{W!5XUF^Mu8q@NLqo%$`Ff1x!wYQ!)}k2s?GfNRWzMGKjZ8RIM-m`Q6B z7TU=spSUxVe3G<|Oq;7-+2>~Y4JZT%w@#3U#z13OHkqE}i-mLw@sqd|g|n=66&czX zj`85n#`96N#uJACY)af92`ySq)GYag87mm+g|_q^zI;l)`WU~SVS;+bRSkE}ZEr37 zrPefjV@R@rVFk7UkI*NE3R|2c^CE)gVotoTphw1tJUy6h?%YpWhUyAI26fx?hZ?~W zzN&-zl#>U$EcEzV?WeisXzA<4bmH2W<)`pdz3+v*XjXYrkdb%2G7?M|$9-qUD(3LS zG4*Q{Z`B`iT?W8l7ONGY#@DT6?Zr8vv(~lpU#$r-puO%^!$$s+==)us^6&@8QFUE&6+NHySa zr^G%YZ{zXx{9(yctE|1ar%R_chbt?9d|@l##I=YJy+wJx$u+mRCj6K#c`V653@l_I zBz#(66-nxgN8>OP@xeegDgZ17B{A8o4QfrI-7)r&K}KYH!3{)$6ecp3F(`jfs~7Dq ziK974?*NPb$iBFoHmDWT_f)CaCdgzb7?9oXsWd7CWA)ifyL##AuuM6l4Pp#QHI9?O z*$Qi@?xkhf`;6GAiI4=^GEHjS1T;T~*ddho{8tdtv2S6avTZNN`kspEf$sOTUw=b# zIPUs@Hmm;F$Jg0!y8bI$`Ty1r#{VDrgu8UMf5w{roXWuzeL@TRi#HQhuO$EUlJM}J zr|}8yn$f(5_4YP$m^&HLZWls&5Y@vnp;Ke_1hevcNiHXZmg-PdW9eS%GQz%XUV~Q= zu`C|?sIgqTnp-WX=LXp(Ng8j_wrqM{gGb|dgw(S_d-JJ%i9#NcWh z?$=pEh+uelI8#Yp<1j2>bS!1Wk;U}DtKLbn55}JFG|O07IW#$!1rGADabF&f+=Jrr z?0H3|Pz5~-65@&(5=q1DLF3BU74^g_nfLAd9)8fB7Tg9w`%mLVGYhbD%oxFFfL>gg zSoVooC?@s9pfGLN;^0PlEDo}YbMdBybkxPMrd|OEWV5B%_32IrGj?iIc(WyD$Apu; zxiKc$Au-Dy{PDGpi9lDKY0l%ls!n(Xln<{33``w&%ks|TN7Ty@5a@NT;AzehK2^6M zr-%(be5fiEP@X(nP!LVxu`O{DX3?T1LL(pY0usG5g#bG48w4(T?hJAveR;wwT(~=F z@UhWdhcE^_;fvbzm13aWsB1DD2=maP1CZTg0UG5MfRzCo^hGvmBK8{UdV+i5nlhyT z^d|awqO9wnH8$D1LCEd>NfjwTNJJ+WW*)^}h0Qp7+yt-V-bF#WHEkYd z43i*FwzwQsD}n912`G?49Zuj9{mp&RWOIaaM9Eb8bD+CMHvEu%T*>dQw9l+(&TDIT zOIe?O5FRdarnG~qeUmvP0wQ7RO#eMVLNb6Us(R1U@Pyqrf9l z#dcPY9nvlx-~Q0h-R73y!tgwklN0AU;lwYf<;Rxa)y6KCEFis;`Cx`!rETRrq}qTa z$6B8~rto|`b(Bf@3|EQsdD8y{xZBb$#qU%>#$V9w{{&a(pF)KoT=Dq5%Fqy~DF%=X zF>vLJz~(9X#F&?|K}|~yBil97_OVB;kbszoLM^Tl&w*mixG_F))^*b|b+1zajPAbX z@m`ye$1kw!A&dAJ^tTz&H7A_g`(XSq^nzi&)v-4C`yJusWN`_Fj^kPHZvS0%`sbZg z{-ebFg_;Kg397WQmI;U>jL}<1sl#L@LG`{dM?i%yj=Dnv;5-_%s&g~~H;>-eB&y0t27R!Vxa+!-1z$Mv11}d-m(aNj!F7zYfQHlD~EhY~}0t(}S59)>7KsaY* zduSW`Q&1H9fG6FgAuEQQ)8oY124)3C*(+Pm^vcLkn2PQY=20Q3$K+`MeBFIBF|I5a@#GBztuc6WUNGVTZ1YJdBg>|(_hPFT zg*JG#Yb^-C=4r`uY4v&@irz5HoY$AKSjh8rz=|)rc@?B{p%FI6nS3mUBg@Y>icW{e zw^n}0W;MXN!Xt)RN5=yk-O6cvdfsx$Jg&!Lgfeh4q%y?FpJ0s8mm?quX>m4)Gg>Dr zSv9$8QL%bn>c`Ob766l1ZF<4Q7 z#-qxh9pj22G#lP_KYy31DQ?38A!Le<>!3|Kq}5cllXLP29YpzBEdzEEV}o~)h8&dR zsBzS(Nh;W2pimRR$gMhb*9dU(3a~_c9|{mRls9rOG_OUa@F#4YpgvgB1DH`R6i9TU z7o{{;b5CqkH9bzl8kk->ZY`&kz~hAd!TEbN{wI5_W;z5-5=)x_@$b`p0_v#T_P?f4 zLMjYVIxT`j$&i;#b_~uU_|)|+dP~5l>b7ro%uz= z631E8RP?^FA+^JAxyxZ&JQ20XG^^~DeF>%rk>K`!1SlqGaHOFsjS6CpFTXg0mU@!! ze&x>G-Gc3mva?lHie^~JhuJ^$QSdePD(@#4{JB*t#a4_ljjYL&HWncOzMhD5_4rhA zH*|^`Fx0^lb#!5$e12XwKZIH;M(Nv2vH`3B$7QCIOttRQnk%Yt5c3CRm>HK+Wrnt(Oo&^m(qAAg+S3iEJ!uqx`JeB>zloxL zR$gG@AEGE0HtH{KFFL`uf@1 zovC-(WgTe4IvuY!g!?|eW&9cF`6aw%{SKM+SC*(-b-J9Pem8ku$~Z)pF(})oO+zGK zoE!g{jH+sKA;sBsy>aI9YH(|>kI-4{4P57FV_dkq!8za9%Cf{UWz~I-AuEnG-a8$; zQ7Ft&Z~3izQ2oiRk~-C!>gVgd(vlB>i006Nlk4?J>5eHbEtT$*bO*V|%ikEW-&qrI zD)p+jb7I>ZlSzUq>MC7CG|qBd7LhlXGSgra6bot!Fr-EWJyOm>D$@{3wBrGJLIj1OuS# zQv1Cu4jb=jnf1PnnM`$VyaNT0-8SXVaNQdrKBV1lq;S!>vH~BQoge~e)M_8o_I$Ok zuUZBN@#a8+2oyxsnvR3wDNEP}PA7kh8z6k@d`6kd_f{4K;40Ec5%x@NT1v5(4kt1f z={-{f3T;cvpihLtN;TgeYL(Q+3SJ3 zDzQLlQvz`Dlq78;)MSwFWl%KFazGaWC}q5*c1$;(aXrZc3zk^$#GhqT@T$2Bq!5lC ze2F<4n#sfV&im!Vi&=>^jhfVsR>n%gh4-?;Uid4Q+FxnZN^aKU3*%$!G#)(8){k8G z*EJ3p$xg8wA7q0@AzA{0?@HCDMqtmbbA`ss59ae3jgO!+Ddceu5aT`Nij+6!Ma9}4 z^c?@n^tP*^1WOzAv-jO&#G6}p1p0Ju9=U3~ zJ0b|WwAXX&Xy1Dd@b7YkKM-XE;4z&P@b8K86~SNm`YrM=lXHJ@hp}J3y!m?2R(-EX zHTc!axS88nfe`Emn_8f^aWpy+OO)L4y8lO%Z}nt@e39#$8l~z5fa5jEZ#+2v`F8II z^$vFP-lkoF1=y;tcUuEp=a`l}evk6yFJvxafBmpo;bjhO(%C}ixf>vX$LhgokAmo9 zevc-~%AidZngHf*J=jq`cV)Xf{8mV2Y$9%54pE>Kd)ibwm zegAs!e*4M&+qY>!su1zDC=iGD&nVy8wHUba)>cX6d~i$K_eO9?uuHwVr_f z73G`jy^$zhO+%EWJGVBH|K>wvW)wP$!%S5>{y?C z)RNSh2`~$>W4|6T-09I8U z;KD;UVI(G&@gM995>=J9z66 zMza0C`jq_J2`~T9C&542(f&in_#ZsozxuEK7q0^c5Clg3HCT~0%U&9~DKwb)Yqn>Q zvvvaK&)7tTr?iMA16t>aio#K3+$J_7GF|k^I)hvV<7OWB;to^h3Rq1t#PoUMR)QX6 zJ>^g*3jQ!ZI75T#ki0&#l|jkaN<*diT@rM|AlpveFiG5fiX&C0Ievbt`hhUnj1}@> zzqZb*C0Hy?=BqJ`ONzdy(nJ9P=K>tg8Yuv4XQ(G(pFliA-0d177ZFO5S{=^z1f3tM zrkjye3jSi}H=k_p`!+E;Z`n*0w^9a=#(G~>b6Y@f=~PsxyS(QD@I0r#ONsVp&#WL8 zC`S6a?_`L*DQv+WegnR|DE20i@rT2v&usWE>X2u6|K>UT-jnzA3S7_o#J*glgkHUv z?@V<-%hm~v;C!<)AOJj$^HF3HbRR5QIv3=`< zO$B7c^8l=)A)MZr35Xjj5YlhGlKRO-r@Cwz~-SU=*nZA#3VtK>q^9E*qE>b8l5FvL-#+(DJC$Fc>J>SyzJN7m@i6ss-eXa$ zt)4lr#vw{k+|v`GToNU*`&-kz@JN;noeByem)5-JzN~M&`hCJzZ1GfxZS4VSzy3n0 zo@ssCdkq6V?9aqs4;pGYlxnTIaE!rQ0*pu1hzRUOLf) z^|LYXZdyd?dc$JKfIHPDK_n|E~3<=4FU#7eL zP;U6$ZDJSQ#35uX^8SnR$|6%V((I;C>pU<5w%Ba zucD!-(UC+FvG*)$kJ?I&mRhwbElP``v}zUAR;SxFe%I@I@_XI)qyPVD^5n>Q9y!nB z_#EHw`@Q^hB44Ub3Xo_`$LR|-t$o^T@C2x))GADsb&tc_Y5hKnn$DJ6v|r^0Fw%rf2O%u)q|rsaq4MBMRlMk zZq4}p-Ii$kn|x*QwuQ z?)t}+!T#5jIi)|Jh7dxWB^E2ssHd+2P6%kN|MXSBT06gAGDu>+$hTfKRXUsw(aqAc zZyd&m*yQ_w)`H9R;)yMNYM%dv{|aK zXr6+MK_&;$Nbn)Z)C}PCQW61SNa(3G=t)7)4@&et_C4&>AJ%8iRrZ#N)7sLLcLs!= zs4vA+Czj87fcPl26)gO!9y`MFH-9wGk<8R?d5H`{^s7zy&j=n{Bq9OWnGECT`2$DQ z`pYuD~ zD}9N&WHztTj$hwnd}jcSB*wdKe!G5v16&$$cD%2_ z(<>3_h?#dftGpS@*CB$N_es+eLsYJa%=3DDkge}C7@!acrPIselM=kGu_OI$@Gm$p77#U@+ zb6kk5(f{u#`F~wn5l<)2zp_%h|Kzg(@@Zi|pcq31Bc#bjQ)dVbX;0G}UeDz+=(LwvzL?hD?@c91bE?KYA!i>&)c*tY zJLz;3|7tHN`_CvqU_K`rz9@yl%z;&&hZFi@8O7YjH}N8d@j`S~Pia9O@MJCuas>GN z)c9`NnEx9x5St}!+TwIj;tA_bRc%npQFQ^ew9vn9_^=4&nC#xKgwGqE0= zv-0Sxc4&wcv{RDltur;N$k*WLfj40$fDjV5%ca7iFzOZ`jig|O)GYBzi=x400R zb^6@%6~sd$8Q}w9YY~T>sXn&laAxIo;|Vux;f?jmY@Aaix?=!)w|ICK^|C~4g z2>+Z7SSnZ$n*hPA3`9fEy507f8c7r7=XE&f1C{DW8@FWm=LD?|XR^~tj+~ksQKd> zJSpYBdE(9gnM%F?plkl$Sok)mz>q4uC?G-jVit3WWf_O8X@#D#TcZd-%=)QQb;Ky0=&L%NS^pQ1=wHABJafHS4iDzEfWXMtZm3}hVY73{~p zeYA|bR%(|I@fe=#5Nq(^J^fK!9bRa8Xxw$b?h>1>`k!q>J#p)$XJI5(Vy{a_5 zhb{OybDE25)wwPCU6Fa+aJHNzDD&zx7Z;u=aeji6d)vnSyszMGR{c`vtuGECHEo|U z9e3%^bD654-}QyDiQKIL16H0BDS#h_r+~20l--{-PjiDm-urv*RhMaA^JYh(dd=Tk ze1X0%>)zchoKRPN`#L+I;qnB3i|>+mkR!w0tgz2h14FQ(e1V;V*@=R)-hu@+LGKD{ zZWfq1|C;^yw98#-L;mm9*M*JhG;=mC&9HB~mHqc3yTAP|-~N0i^qu{)m%sl)t*?dA zaf4lmS_j|xNtl1%cJRMSX4wGu=so^l0?wc{jYz@&r8(k5|BYHQmy@BfRi9(+Tqx(D zbpAxCQM$DAe_UmL!S~CY!JnEAGZivLi%+5HPsKj*|1049m#eJcrDNOK9;cLF+JXHc z*RQFi0ACYX8s!&PEOWG}HJ9*v+L8D8`In8qb5{fa|J+SDZH_o~mFdO{U3MsGG@b_L z?{O8q5p{hl-UZb6Wk1)KZUUaab^R2g_5@Rr*RtJK*-IBjS1D?oz5tl^yTlHD{JLzh zK|Gfwd*r<2dU=2R$r=d0e7P-6+c2L8qKUdopxbl)8#;AkZvz4qDZbl6F|nM9o!AO z3trX!D@k*`n&LE%_M&Sfjhs)19gTX5#m$e9UmzG@7D9POAOGztvs_OQtqMPBPL}9* z<#oJ&zCPU%P-5yfqcP|bCPE!hvCj^EODn&2mhsK(i0C#%H`eTkP~xo816`lT9049D zDNPezZ~e;ru#15xz7pMd=QFOtm+ z-vn1hAMvl4Yz|S5yQ?^!$8ADd!r|5kN&zer|gzU6u}ur-CT2aD-Np75etd*!mC4k7Pc# zQ~ETnPfY0(MOJd32%%fYY_^d}8J`nNj{3MXp(aEHo!iYbz+<>n3fgHksx!m$u<<iBw8-TxCZ*LbeQd+Ca!ZEYP#=C%#IrWFx!KqXfhC(>`@+i<2~AS?I74s=sCT4xwP446_P_eQxJP|_?hARKc$%hcvz5&lwN0#wzQro#K)!oq^F00<8CU;p)3t;ZaDiEXPqx_ zx@&*zqD>O*Wx`A{bd}W=j@1_-x@DY>ph@)jFNqH8U&CExFdH;hUL$&O3hJp7O=_dD9nxN?zyMm?&N}l`v`xB9z zmwT6$K=m|DvD4+5?wQLwsxm}K8EQQFBWRQfPT06~VE}4uv61!c*zujl{1d{5P{61Y zV$Y3#%0z28pBD%sg3zxcS#O18`UN<}=RJX`w^c=7zEKgNGlEw*tH=CfmMq{{bHaju zCQ{=1oK>L=E;uX}>qC|_I&S#txS`JyJSTN@jGB}Y=ltmh?>P*H@_g8a19-{ye_ynH zIniE;L4~=1*~a;?|FhhU z7?;&a!jasUgqr?wqLhP55 zis9fM`CAaQ>bs!O`B4751rdS?>Q6&8zIWEBf20}msaJjn#qXbA=yEDsmpDt+V-VP+ zkD<-X2H2RxvYAT#8;f1@M)C}Dp@cs|HD`j!pM&nctxm2`*RO|5kd@Op&d~G}V~u&! z|3+2ZYD?_89pz%9buj!opW~{Wtu9X)g~vRWothH%%ko5c>e=v7&4b^2CvrcR*`A#o z51Icxynph0)BM@b*DwBldvfw;Kl$13kLD*o-=6$Ee(~(@_ZKIBf1RA%5C(0io(D>T z0O15#AP5Kn(c7^z(Ks1=;0QGYb2|YB;o(*zauyRAdx?-^qAHHS-SHjtOBHwiM#d&f- zI+4AX44jVEkR)HRBPtye1aK5fBtXn3nmvbNqXu_DQZ5+5)zsh`NUB{p)#sQZ9!}w= z!LQS(*5U8~WQl zx>u1_s$%$3$q$e*i;}dp`9%Hjq)DUrbxF#m8gadf`U#nQM2p=wid{2G)NYR-^Pz6F z!yS+bl4>dC;c>mRIG*W5i~0EAs`#e%WavUlxny!6B%!t{0Xv-7Lxc1B5|9z8Eyy(X zk>tzBq&JcXsgAf*wd5frwT?y>^F_!uZR_wZz$;q<1> zq@V4vM!q!hkr>~3Dkmg{(=OquU8-S6I$cLf{boAbrxdJx5^MpkcAV;_mS9s2ccR5u z`=$uwraR_lUG9jPKZff|opz&=ELl#KI$C;77=_(O9T_f39^J$6d8NIQ2-6JW+zBxj^$&~rnB;)*Rx!KQ* z@6Y^5=7+=&*ky^d7g(w16d2`I<|H_sw8u^iQ!6^+rtISW8YMJAvm5LRSA7eLBGMy_ z3ch{HA6zK>8Xik8nSYCy@{Bh_u{vj&cAsKY+bF~5Q*7%G}3~$h<_fU$J;(iDX_$?OL&NtcUc^5(U1}bCK+_8l|d{rD}Pl zvba)>H>JCbceVM-uo`80aqJj}GNZgQlg=^|x{IeEVhat4r|&P|gDy=(voFWm4Ml4@ zbe50vl)Lb;_cJigUSW5!VEC!WzHw7qtXS*dIo#mLnDu$o5Kl!|CnD~Hwiw#TSA+e} zmoh%Z0MISXvu)0&RP^^tgvG1I=%oKvql|)-|4Z5?sYGFbq|oMo*@im;I@7lh}I1Y(^U$&t)rlC zJ!4Xt5tS8JmD^d%F>P28S~hB9-6s-}Q*M;rX5`mnihF*El)-?&ndX)SLcKgb&}(yh zyWe6keaabG2GZVMH=ZgBu*t@Ie8Z1-mMyMdURn2NX$r?HM8S2;JpsC>;r^9xW+re= zDRQHlxMpRvna}=1TDfJE>XnLHR~#(Dex~EJW-t9I^8!$eHf*%*@fS)mnpi2d`en7> z^U8Eotn@>zj8zb(Dq3bIT! zcPp-pmBC4!@MuFX>HE!gPg=DfUR|BNs;6RgqZ5ArO*Na2d94cQ;0jzj9=^HW$er32 zF6Q^1Qa?Qay3`0}RIJ8lhFV#fzOkv+FKfLkQ>LTpp&#ZUy->wo+|FG57^(Ji6oI)w^PzsHjw+x-<NjS1}+!Z$E~=t{fuQ za?Uyq)AEPoPM!`YEDk6A9!?P$Nz)w3a2m(mjFiX-j9?m z3RjGeY@i8rttz>2R*h8nR38^d6F3^qPwiD?AqOhJaBnO11#)qMzzIFW`ybi-L^Eqa(-LAg^99#_z-TJHJU3GpC? z9193!l_8k`&A~vu6*#tUv+ps#U_`$-@_(U(V8~H`aM3|l;jDQmj(1KhnhtQH1*{eT z`(2wBgJSAOF-0mMvM?}#rRg&K3uq8SnF|zB%*a16jdF(T_e`@av7eFwqZ%1Sn;?ZJ zct%l;0$xOsn(9sI5to?kXpx_>*BV);SJGr@uxW*9#$MQTBg8O>;R||_ZiV3s4l!>k zb!lmak!}{{j&LgAw&-H9>_S90vbNloWOPPuW2O`lbMAEr&pUG<9LzTW=`YAZ1B`K{ zzTTdK!n#=BV#XPWGbWeefhcB5>Rg`%Bchmb-hwTKWuX~`_yk|by8IFv1o;YJVZec! zT^7FLA&dtL`AeJzMbO%PSS5x%r3a?Eo9eX?Bj)Gw%pe=10HQd?KbA_tz!_HIr>xKz zOe2$3$ti$R$S@VQIwb-Pf{i&N9QPqo0q`LfDC6qeYFEU30r%*{qWB3866p-T1!q-T zg%+(q15q4HiR>#~WAuv48+VpJ$#F!(S%c*e1Ph4V65`qvC_ zYkMR_6rr`KS5RCwW}?JK;bu&2+FK;iU z`Zhs(tOX27Sz~(by7!H=k->^1-GQG}j zo6Bx@%5KBT2Ln7)HEOhPg{i#ghIb=Z-xO2z{yR_;xXpzbSP%c2Cg$aHrZ zaud%KBo8kq>|)+?fO~hBS@#0>cBbTEd`O0dBK}hXYTF8wp19;_0sD9r_A3BX)W|g0 z$n=#}udtD+dmlzA_;hP(FR+nuSN=W2Nzi9TS5V0clZZLgabjgk zzk~m|yO($h@>JOW&3@cK*azwCHn{BGVB4clWq#Xp1frYu=ms|fSmxntU`6Jy7#R4p zNI(l-cH`$1VZl@so;d-JRA8Q0_;n``PLSV((rwPKaJm9uUzXM&P2kw6a~T9k(HTJQ z{t?HSz1sbExrJ}$&HvD+es4HgVF1scB8NXP(_MYB9yu8f+Ho*B+OOHU> ztr>Qp1FiXxx6e2M4*Ry>uf+loC;%J{V$nvw)GNY7g9YW8_dT7J-B%w|9KFYf`}~kv z_5JMuuF5H5T6Z0h;!dqsw;vM|#6fF?*{lAYzv*#B;wh^ke;2vTX3S}Aa}hszt3I^h z8~T2bHpe|$9*ABnbPD$>Z_HFJ&8=O-@IA^ji8Dm36Y%e{@(A+J%yr|CIH9Hcc38Q)+?| z`G6N8>~X&oDTv(4_15u6kt&2Pg~aW{L0tKUy^+*uV;y35_;w1zHqIg|vdDgz-QFk` z&Tnaxq0dI^JKdgt4;)Z5q>*#vPM2J0X=WR{2(e6CDzm$U4Msh>$S@0pEmD}o({tD` z1iepCN^|l_7Nfx3SZ(w^9T-Tow3DC`Kx7F_F3S!A5pSWbK~QOUB`9q%!3}*rm*8V2 zNrJ4|a36?4s|8S4y>-~FRHPXKn4-Xd!lP!;H%G5XNhlIcL{!BGWp*WU zGFy(&UMeyR>U^Jk@f4#pr?tr8!{!*owZV2RB5_#QHLcdYX#nJ~&DH+_KdN284*lG6 zR(>t5N-k$KtT--Eu{I^CtbBIPpl`b2^|hOVS+fC7EJaC48umU(EvTRGF;a=(pyVXX zv?8EB()f_o6W!O!bDnHeCSv%M#XALn4-h33!GC;ugYV>mEl!Tr(Cb6vpON>Dn5+KlfIJm-fna(&=0$+b+<8E@ z>*Mj0kKe6+4rbr=r1-d;Pr#Iw8d`*PraV{Wpvl;H1iLpGbD!(8b>?}ZE8$eY(!)|Y zH8}m=*=mpWSz}!Pd!@sT32VEnZ5DYp2Z0NNa{gw@my<_4?R|106=IBZ;NVUt)Yvw< z{3cXoU~rHkerB*yms1aM1op1H(>H#eS?$(RHh-F=iJh-r#aRJYN*aJXyq>8ggr#J@ z;K?I%x!wDD2Z1tiEe{lYF@x;{WbF&Xa)FS(cMMcxqut?e^qYRX$KrrE0od^5PDXO-EHckRA z;zkC!n<4W>vW|}J(cePOK};n-%4Jl&@Ri>zxNKi$SQ!q(&2SX;lix>cOq-}hl4C>Id(N{sGkRcysVh`RIXd>c0 z=hH{&LCD=?#t2SR4Yk55lkb2;o%%4n6sMHL=WiIe(265$b)|gEy81IMmMk>Rz9c=x zL5A8bcU@krTJ2y_&Nm_ij9it?0HN)d+s-D$}rk<9NDEv~& zFr^HIv+2t%;m8dXnkO(&ox-U>umQa$CW4re4s4>sr?6}jr~2wZ-M&mW^a*`ck{uCN z628V|HO@~X6hUpqdr=spWmN1J7}wtc$b3|qh-gl!lC^88(NrI&s2Vw?Vhe(Hh8XAe zRA1OIN1;5g{j&JUVWHz^NJ=w%xK?(B%z%Mi#$zktSTGi`C09^VV)8KcVe^y)N+)%| zHxR*U1lNyi(PLthcwBIfu0@zFn#oo=tFTW_58*Te6&y9msJ7uE%NV=O?3B;mjxel- z=hh@`b(Ug5ZfJr6lii#Hf;hmgR|H`czk4{#PZt*J=&65VJHp-y$dA7PJQxUDKBV-9 z%<gqyO&lpyKfS?;5uuq3ptB>OsDeQI?Oje zr8bZ)Dt@>apZ?@*U42DM*!8&Y!L~8241kVoE=cGrFrvzfIU2ZNKuEBd^AEg&!m15i zl*mqU9TvuxIU1?1@)8t$UWMe#V99EtDTmmy`(L;qYTs)((5Cevz}S>sVCM?IKD%(P z%X8t#$fxTCy=V-cUa*s|>(jyqqjCbuuytiRWAesrBL&4OjZU~sZ3EgS=N;C+3_BK zYAnVB9{R&TIcysGY0IcC=XWf>jpYZxB3fkLUS2P3z8CMoOT#&0Ur_CeD$gs?X?ULwqu*%hfPt^E6(^ML6G2g@*c3^&BBA-yTU|2=>C z@}ShcD{~%OhSS=XWu-j8Pi;ndFSEMWZuC6${lwk(s>r4eUFWcMCEHdzgbr##Q7BTOs#HANS!j_ z?~NtXf~n}HK8}p}et+)KI3T+9%0;5yH?#K)!V#xJ_bo{-V+}C(ljC(6Zlm~Im*9fe zPhqBj$SFnrD}o#;Xp9Axd$Ejy;QzD9#&W=&wn!GeU?EY`_tU_dJ<;5{X-e}K+OgWt zTJx7`U4xxzxOAS#UP7K^fCQ{#;*Md2dM<;PHk1NN6Wke!gn=jM!4%Xh#1LPL2Uo~96D_hLe z;H(kzN7sp2Hhf63$JDUz6EM^JQd`=`1i)= zIx{L`9J;H7)5)aJ;w6+dnn?seu`MFoN|F~pRVDI~kWtl~>Ck*8!0!e17=q$AohI#$ z)ISSN5cU)_AR|Yk&>}*;+L2zk2q=-x3G!2w8tX1`Y1?}BL{3*V;0Jv@URvN2jrD>^ zT2(X(ar&Snt2xrtqnOyJz+ODv*%p^W~fiM=QaNauSM!olUC(%wz31MC^Yh_C?1#y%B3if_z8=ZGaYvUAeo1cIc}jFE=jV1!{*(8>Oag zV@jgH<)YwpbXduG+Ddm!f5C$(fj7B=@lT%p;;;Ii6Aki^qsH~Og@fWq@dn{w!+GFN z5ITonkukp-D^>jmCq;w+#UN5ymS?`@c5EOY35eh zSJ&$CH0k!?3!kyE@*PjKJ+K1kmfbDoyPyXAej*tSYdstSvVEe4$Mtu5 z%P2F@^OB&Em#~vMjp!TqS)bh;dSy~KOH#V0ISfFx4E=--{*c>pqzMnmFTx~)Z!$#X zUdTUy&cI@xyUP*hhdlY7P$WlQVMZtx#=^>d0K74FeYgtuNIRZy>*Yf^EdSQIkqx8n z4alf+jZsNEjUYQ3-Z3N-ZTQ)()GxeTRi?(KwoM6B*_I>Vq<85$8XUiUcG|Ta0FVGY z8nd5)auccDJD0${&z%O;7-cXvl3-$0<99pIN(7S+9mV!Xv?4TzLAEKU6R1a*DLDm{ zB=Dc%2j(gO#R(WDkcAWfkH%gn@wqN0t>F@Rp1IH<*e z(yU|5Nh^`5vZw2gaV@1N`8@||f0R48|FHs|>Nk9G&w(+L7~hJlYl~v-=cGQGMn7Y! zdl5}D<&@WUO7L2X+hG=Ng8_a@PF}2HI=4duD|ZQ#Xz>6!~=vK?*1AN?X zCD>=XNgtodE+t^a3YQ3+L50(N$)0)7j+?moLLM~LhP2>Sw)oIuDCA(F$(h2)H2_I0 zL0b(VnF&cLIRFJ<>F~w-`!y}Gd?K4P6eq+O$<{ul8rXlnc?UuI4Lx4(r$~ac!@(9k zDrWvF?LPgV${N=FbltnMU;#|NPxuu{ zBfVpCU8!*#roA)m+MEEcM~{4{mwIY}Du^#F;HeHI>%N`EU= z<;eAcJ+pI5st3zs5(R#H)Y($if=e&)siHc&fa}BSDLt71n_!!HN_^Fn#iIo1+pHV# z^MBmqu4|Q6AHoF1vb7Yb_|V)N?X922d0fgZ-^I)DX~;0UfzQT4ZK|nO7i{kL;Aj}x z`#FtrmU*@-aW~pu19Cw3_rc>b2``xluXJl?`rB?a&b6W1DvChnaE6oQ;$qK$Iq$ke z%1Y9WcFHY^R>5%X8gq_aC(V@G=sM13+f=!MK${2HI5AcBWA zAnjTfqD>yPe1zD#=9oFxsk$OtEeFo0+#x4BL+~1@r--!(g;yq)aGe!P2H&%H?#J9a zhxpd#$S%dfv3lMft`-vw`TivJ=lxgUUqH+(*$kOBHcO78C|Ko?4Z_J*F5sWcJ^UT? zI25}LWa?cmnL1BG=jti>4vx-1HK&1R?aoLPm5_!>Z=D~Uh$<)^B4}dmri%qY(e^fp z)0(&D^uQ3(@>l1x$P8}fb22rTmo$sEW;KL{8aE&#n5O1 z4Ft#DKxr*CLc@Q>R&)&jR-o2V@d^;o_jdUQ>ukwA^@m?+V!|)PWm^oYSg&nn*^ja& zR59q?Nf34(@sotQr@W!y$y;!$TE6Z{hRQE37VtNSE3%(A=-o%!wRKrneS$^WEaGd? z3frIs5x(lSzQPgs?!JX9UBD_2g9GQE%fuW|*FN}6C~mI@;)*w_+yXHTLOhCIw57zk zERq~u*s=*P#cxB;-7dve@jD7lFMF<#c|K+9OIq zOjmSi3EjDwa)MPO-<0SAd6Y;3)e9C0KS?6E^%?8J%S4a}I?d9EtXtth!vn?I&&Trt z!6YWJ`SlI_8K5J?{AzleOEtk^$mB71J3HwDW=$|RS_@-Ob`o-eG3rp5vU@!R)Or3` zd!pXZtG-RW05Nd5nxt?{KjOx!(YXA*isnpZIzLZOr+IoFvtjZk+U@TKA>xB}!G~86 z4tr|6-0+8hyUAxEcJb`q!THe_!|gw)wYDKsZg7`tipJes)l(f{7Jx?UT6ozUeQZN< zYQf3(2HSL}+;7@!5)h=bc>3t8n*o7dCjyAx{n*WT?GLx}UwKH6wOOz!JF<${#as1k zrY-x}vU{c5_$Hb8W`_ADD3LU(AlC|Cot>wI&O7}2MM|R8W`FzifWePp%;VSn%~yo0 z6-?EZbFsy&e!Wkntt+C9hh5(0fH2|7&Um{YRn%L7TlIx1)!(+#lD4W@x0}V|8e0>5 zR{R+H-C|hS{1_yop~*fuZjT;sKT*A2@%W-_4v^2CBVfSSD+wMDty_KZRb*{ZN)xGxyd+RoP8_NM*UV9&@ zdz)E%pH#O?Y<#vW_IBp>c0cUxecSuY@Ohv6^MUy1!-~L<)PNoBvtPOcz6S2bckZNf zQjQC+yct(~n-p+-*Y}sa@1HQ=zh0jKJouq7&IfnZmnX>$(KKU#s=xwC$7SaWX*Oiw zMqobviP?T%_a4);P3C*PJF^AqjeeP4NZM5&){6)9XZE@7NmWFrt4$X;Bp%e)h?=IX zq-6#DdJnVs4XvjQE%s(6X|wR%nm+y9Y7imPcwnJ_fVMp#po0Y#4*sZG6JXJ%Rof4S z54abDzAqOj^^j#BBpLRcwv3QZChyAKcM+9qIIMA(I%_+ZN%$h#CuAW>R%JtKrBp_o zOH8y({bsW1w4R}a0;?rS*aJe44`wBvrP|I4IwS^{JX)?5f!TW=yuv8T`OJdp_XX6O zDeb)*7;vXHiw%vzXD-#O5|0;$sQdY<(0>wWa*)vaYVKX~4tT&%*Wz@qXwg4dVD;-O z{MQrKFhL#N_RS-kHpo%+y0=K2<;rTP&-5a?Wy>ka!}jVDu_EC3BaY|G=WvTLLSo2Z zs;~m$4NkDNtRP|~e?*05{rk~Ku3(t$x5Uh-e+;gwAI8k25{7eK-08rHK zv%3KQTdG8y;Yqg*I&y@(ymw)_mhoHmqIEC3teBtJ&5?u|=wgbWk2G{1xGSz;l@*2M4?EQ!G>JNh@kqn-nWrzj=q7dk%<~XLb}% zm5$N4_FjXH9^%@?H_=fp1?U5mUtNm)YGTz#u0|R#eXLoPv4QrJ>Fs*t?t90(Z%4L}gpQ*V3T-rgj zOSlc_tmeC3mK^25nm7xdyUj&#Ev@%!3Z$F8G(Xi^6bN;H_-#_gy$kLO=0CV3bq&j3 zx6^4U^ZKOTpc}@;kK5q2=>}BtT% z1tt#y|44h3&NCul_I5T_qco0d)_OEW*XDq0VOZ8SnG%HkRHKdvMMa`IvLA2IV#VfQ zhH~60cb6&X6l)nsXhma1#^=I#nLbG|rP+qGGGw+DkUA^+6 zAairpW-t>qG=<9{98Kl*tI`8p^+EK+&@mIa*lkfquG|g^2*PEljw*KFr(KW%4n1W> zRKnT6r|RB8@}tXY+emj%Je?JXXxcWY<1%(y@`q^JyB@2{XSe-JJ(L-NO+%S<j`NP{a2ak#tcPe8IS^mnMxm=Z_)2Qu6S8hy;_=)J!ys)QRL+ zNlej~G7(V1H+@j^u)6M*feCc7Q*c05iYD7g^AyjQag{U9s3cjh>y6QNxz%Uy(;YsZ z>%PL1qmr-gcdRn+8n2~F(P0kyws6I#STEoT%1Rb1!)k}T`RBk8gfK*Lf^Oc)=A1m= z-4i*K`UH$0I&<&%-1W66C(4vi>{!)3*e$o}l3*bxJ^xOPrkZlA&i> zweL21K**4Et}R|;$;0Pt{<|iLO^obvJU>=6xK;$Jqe1(z3Ky3VcJ2^j{di)BF5TfN z5b+2HkZd~u3Q%_5b2IXj0P+PjcN+wh>t{mB6M&|$uv70+;crrkMH5Lv4%#Ey{;~6u zJ_J1s8It??u>+4}g_J~Fe*)q)#;w-59Wl20WL$;^>S4@Ptks{t?=$wq1|YyiUHv_a z`yMX(x6Zj)K!VH!-sAjNIcODSsbE8?{HQ z*!i4C>T@Dm5Jf&!7jdTCURkt1nc+I9*T7znoY;SCH@t!zQU&(1qoW5e?^iLRcN7Kh zsrDvoF9v{>rx<4-<(x3&VqU4o{-*S>*nUn`Vc&`QV zQgw#)hh|(8$onF8=ylGpzEMGqk|OVi!4|9St|kgiNuFRAT%yTvsW7E#yLAd&fb;jmj!AkRa1szz&8$47&AHK0r^oQYxcfCw=h#vACC}f zdO4rsstdpDUXygUvz1i9orUY4?sj&DTxZNHJ2nvZQwm;1S;_{$3e`~8>5~n>RV)quw*=qR^y$k z`?EuuX}1g@@V>-;!g)SDS^Kk%`R|rD7I{-G_USio$!y`$FW1neZ1@_i zKPE%6+bjNl;=Y}`D6+B(i7?o_6tP~#E^#w=!z#8`GHCm+_&Sqj=LkykYogCi35Nly zCgKT}vEuI=7IKMC!XBzj0KHc5B>m*0L*aX5Ewf3d)Q@Ntncq(cu&pNwr@*@)!PK9t zR@Z~q6t9EE_0sG(AxN+bU@yJ~Aod*Dr@&BH|0%;X#6!KudJ0t-d7T`>Um&%*m?&1C z7U%BC4>@U1EWaGk&-r@=IuzHOyX)^ogk>Ra@z^{*ukkCuo&R0c57jW&)0L9DU_G5s zwv@*fZ3itd5{?`2_7QJWh1CZfsyL4fr{CBy7kjr^V=@_?SjX?s@+S71YfN#BL4~_e zG;7aoRCQ6Ux%akzi|m_E?}hb6M0eb8l`VMA2wQC5!7|*84EQA<{@N?ArbjTc#klVH z`L*G(%BzkK%>y`PnA`T5U@}}M{uw_cM3)Z*Mv!I>30KIPk8)+E&x%^*s!Om(>4c!n z*lJQeaoPfCzTA!_X+G9RdQF>#L$Tg!c_|R@kT(YP$Hi*H-CBm+-1Yp`U3^}xJ8|4vrXbSBtgwslk&UxbzZ@Uq!djaL1V38zu{?FsVIb`uAZtk zABvG5f^9cgmIGpA&LZfztcIt09aXDAp@`g|%_Mm<1^y(qJ{^Tc)0LcYXp0VY6?y##`bLf=u>Y z+w6d#_~MSH?vH6%j~7rrZMrnufYY_3TdfJAF&Uv_a-X)QUW8aN-ElD7Hb z$R$C!%Zt6vSmen>SkH*-Lh7qV+!?8267n*9@;!TC;;kNMZ8MgO>_Se}#qXB*)Ku5i zyR%lE-B)6Z^&LEJ)J+g2ZMpP7JeoYV`o##3!e!+vdw(Vh=gFI)l)O74Th;m>KrqPF zIM%*64y{yD$o<=)#opugg>$$VfEt9QL@sdb9k*0(zn`Sq2~XB z4?A|gvCq^a#nni7uDw!>Jua$<-)wh8q}`|r?gNAMGfonSydXUxWIpu1b8Hx11}h>i;hP>g#QFNe%Wu@_c0WkP=} z<~bRsVb=)6Du)bG=2M^~N*MR*Vb|%>VF4ig_S~80A3W44Wqolr;6nL3E9M37E1Kq3>ipI| zNy^vRh0RF^su$jvW#C5XaW1C4foE6n8tvKh&FQ6E7V;k*SHv^RhADcZPUG6FRnv5Sy=?-Ci^A5*5c!WH|0b z_wv&B*6PKF>b3OgWpRSPh=J~a39XUFS*FI5&ezpudZXb!YE!0L6NGA&nh z?F8-uxE+08t^e=-{3ZW>-ObnMMSTG&+rd@()4NwkVf~{918e@*+knPDkehOiB&Eh{ zoYcWw2MLK!V8ABJ=7nv+ix0sf%3wFh+NMQuoaBrPb4WXmIlK{pe}SVGOf& z;QCzudK#67??WhS%_ryL%pZwcNxS7ZqnmFY?mkYdwkC4V^Mzn^XbL*)Rl~IpxdS{) z{YO^o7hLTWT;yQ0{hVGQVBmAB{>WWJWV=jJKG0rE?p%(ogqqjvK2;oUeavcv1oa64 zdUJd&+O(j}l2D(D0TIoHSZCpVyKJMj6o{+bXhwQ-%yf&v)1sNd=hV4_7ja|Fstv*@qSd#Fm3L?wVqQ{tp0vK!3lG z(Hzvq77&atY|-d-Lba?zG9W^2WbkC>uL(!X2XBOaAq3!{?SRzDrwIRpB2c4@m}#+A zB%9z#1g`~&VnqQf$QBerHxIX{1c~%S!&pI0efZ3G09r)YW8w`1 z$%srk)MlirF*Y0m&!n-=u(5dT*>@D=X>0);=gb_pDnx3EybZ5IRwQZ>FGFIX@!qZ^ zw~`ZRK`nKK+3=DT2ycMUs&lSgsA1nLtsaZq!Ou0*9PB|jsYMussap8RB48m8Ey7!F z4G?TmQ9UR1Nyrwi#To1Ywk?x(=KrW}mlh#4)eM z77e9^gfg_G!W7;_0O-LXP&0a2GeNJiRvv;fCj>!rj(>QkUmZf`sz*YXMm)b(MmzIC z*Iw;TGDuJI5HNukL;-~aFR;FnBQqW!>Xuv8l!9~PZEv#iQ$WNvgwGtWA} zbgd#XcD^*+V5d-rjSZD5Z!X@?;e zOaW>$!4ed;f(*eFWPwV@)NG;6LNqu7w7!C6gCQfAwr~%3NQ1&|(da|78>7b`4YExe>ZrCw|I{?d6&0&pEr7^w|cKP zd$+fHzc+lxw|vhxeb={r-#32ew|?(8fA_b4|2KdKxPT8hffu-eA2@<1xPmV@gEzQ? zKRAR(xP(tQg;%(RUpR(Oh-WKyhKrad+qY+TxQLHbOuKtUE@ z0f&H15Hxub@OXDF!4jBwb2j;tTi}d0u~zr>R|hnB*Z4u}xK*!MXSeus!Fg_lN7%q_ zov-c_jd?4@Dk|N0Xa|QYi}zJ)h!uE2T3-kfc*w54b5}Tl+IWbEOhJ_=grjSL7hG~g zR63+l*2`DZU!a9c=L1GkR8 z<=@G9!K7+-iyEH>yPvO;izossjGLhQx>}&M*bKpv)82%rO%||?6JUWBQ~{4$f$lPa zsCR|hOhFP1!4h1777#gxBtf@ZvV0CP)8)P8fmA+YQ7c#N-cwO1!*UZ~S3h zh&6L|Hb&<-5M*8#kS*+sauyQ&*H~wE(fP3QKGc6&sIB#Ag7(API>QT*o!frASAFtd zUY|4n@E825yRH?=Zo_|mrAF28~q_9@M76?*-hV-G8M!qnR; zN3KXM)ja5TWQTM}79>cbi#0%8@dCvQlK=+;D5>J*N);_$vIs$_eB$carp-7C3hS&5ki2QGT~EZNbR z#WprvI`B`sm0`!0J)3rI+qZGgJ}D#>D>s~T2N!-&h!dGiUJh}%M5Dm~M>HnU=r9UV zD-N9>WTFKM(EwAlNZ%M_Ncr;Mm5kk<#mMt4TAUk!4+Mz9k6BojrZ429X&_Lvm|}<^ zmXIkuyWld3zNhGuX|4CNpbt2x_G3`N{uV52zX|n&=?Ef-fKIRtN8_x*t1>JRE(rTBQAcUOo;!(kpfbTKzL=wy)CxjZ}KqDFj zVmmB`z;6n?9K;I?fff=FIKG%XYbmv?kSQl1vZz8lyjm1fqN;MO3scspSmTMrUK0~A z&rGyYHrJ#z*0XJcQuZ`rCtC~KCO>n^s?=DcHrmk$!?i^s*WET=cje8NUCMGJa$I;} z+t=E7wc_wx$I|~@H!^EQLziBI7pB%*Lm`e>;yveJB^4n|YQ&Q|CN|W#O*cX!z{;R| z^`Idq&?zHVtCrv0^$3svrQ=!l5dLc$Yr!VDnWf z@VMA7itr%&SHFY$v--`aq-f$LAiAQ0DDQ~0GD~}%)bLAd&BoC`$(&3Z=wdC)b!(uP zyxYpVza6n%w}Zs-?73yzJ5Qi*B~)&_dgPFB6ccy+v9gmTRBa03&YbQXEfly&HXqM> za=ieLu}sN3PF?lYiSy)@J&J;al{;AH^JB1vxbz?-0>~}^QbF$3cPn%k0trp0NIrR^ zKgDP)D+K>)D2gR=ItbOCV#+SRvSQUJh%9)5E{TOgWsR}5c14O&CW3HkYA!mbn=E8E zS9S|3ymI2h5W!_Q@xR}twZ}YcUZf*e!RntKAK87_mRR0uxP|1S?>d z!{FRbFer(Vx*UaSf+5H8>waFr-?K2MB)=gpUVDqp;+~|mYDo)T z5oG^UkDkON2?zaXaP=SQ6 zoMFRe7#nQ<(}3wx*2C)3NQ6q}fo2lm0Vi0mfhI745v*WES(wV(gwUVY;@}=1io!{% zkcJ|y-)aUn!h{A1VWewdE0r13m@eWKtf=WtfhbejFq0$UESW~i7lbrIs)mH2%1XG%#F1_j z3jRb?O3o?OV1lz;FHw2NzGWzGc9mRSA(u+N;%TsoEF|folqMKnt(J4OOyE`-$UPa( zudF<2nl3v)#TAy6fbHlmcS+f5neK0i1+D0Gnp&CuVG@*RZEHm_JJrU9nL==8WqJYy zp$J4IMqq;OMuHK^Ea3`0L8|i*5`>13>SRp~LaN>~1t?TuoF)Nl018wEMFn6dSGXBU z9#RrX8YKWsi`M(xlDlvwhJO8A%NCGu(h^G4rK4SEV+jgCk~Z|S82z7S57_^(l`@p0 z5S?d0Ejr-C(6^Eq<QoKcW2u)hE+7`_zTKVpqmzXr~*hwJN5n9i2OH#Er)gIHp< z@YIMJfggOVXteDHplDfu!t#7qpetkn3sXa`%(Q^Tjclh1QGh}emVyO@j0_0hOI{L; zY!l^yCqPeb33!T|h2LJ)F9p&grl$N6CqOw%`MS1-lGZ{ zv!5&$C-)m^Pj7a@poVmuN1fQlN&3+$c6Gpd4?!cLsy z9pYAG3P@1%bhHrHjX2>w72ytHsM{V39^oR@wg~mkVgw{tdkR=>Qb!76Es9v%+E`5s zdf9@q^_G{~@T@jEH`7UleUyPARLq9Ob#K+gCBQBP;agOLtA2}cTnbZ;igocwrjK?9|8iX4QU9UEI$MQmn0PKO*CBEfVoS+1+ za)_JEeT))P0-H(QJm*LOkZy$o6QTATGENu}2=Dq({TN+0?epc!HCZ>e5A^xXsHfos* zfr8C1J>tn?bD|8i`)o^o_(COK@eV)a)%%5at4qG|mACxmS=T;OBYo_%X*L(90Qls> zMmZm;f}1yr_C7)Vv|_h2=I`El*b7wkb{F&^1)pb7K6up=1N-cOAAAyvMlD1sylt>B zh0`-(2{X2h5yYB2B*I3`$CoLEg`a)x+y3KIhx|INKl$))pZw)F|M}6Me)X@P{mQIg z`{5sd`OlyJ^|$~1UHyCf@1Oq?J9hs8FaQN`012=F4RG`hFaZ^C0U59X9q<7mFajlT z0x7TpEs*~H?*cV&139n*J>(&6?ovq!G-V6oN8ctc;98LJ6mD%Oj|%Cq4(-sFj6f4? z>J*mH)rLTxW&=F3K<1o4$*O>9t^+>G$on2+JG_lb5KWfu3eIdJ5?v2B%H$3;aT7W5 zhTNbOSfPhlLH6v<_#UG`tmrBLBvKGX$*yY&J4KBsDy7OL0F0msc&DUXForr~a(2<< zVClhru@i~07*B8uULh3*0SH(D6)KNZvLG6zQS|>3A`4z63A6~Srog+fBxerd2#}^h zv|vIA?J0u5A%;M-BH6BFbqK9H<*zXDla`Q zA^?P@d;$Oo%J3-O!yqJrBz__#R>EYa!n*8fg;0t)B4Xb7ZKRr{E53pkxi0e9qT=!~ zG)PKM#*ZIavLzu<2(|zwSm6{Zk37s{2+#vKOlHR7V?OG`A+*3%mgFSZ3bHKGCa&NL zhJXu}ARRS_&md!el#SDZLx9XC=uR?`NYN#^vMUX6KUhH^tB@=}WkSmEAb`$#uBmsp zuvPK{CW^oy?Mb7Q#frZ0A)?^BA`D$@P6+>+1&|VMHadxfBCHZq(l9N|D;0Aw74RpT zaV3?>G|&U=q{BIK1}>sX2zgb80o{$v#0yn`kJn@e#W)d=iNp5lyIKKldkjOIU!ysRUKJo)gvgU-W zsG(8MOScWH*P={mkMwPi8$;2AZzt zSmJXcv*o%lNF$=a3&evaev5aevn2ohvsw13Kwl~=HI4YX^CY{kL20x`w+|~G6G5-f zMkX_wTuf4)3NtB12+)u-vtkk5!X~;3N8UrX%)}v}BTG;-Dd0-psYBO zdDBM0G)xb#M|M*-Q_DAnYb}W4Rf6rBfF(etYkPuXIm@e=3eqXOBX^V%A#{r~8!YkQ zOTrcmfMCj8B2V7h0!l#>K(u3;4kFqXsNMg(03oXF5!G!9Rs;IZQa~m_-ZH3H z(KTJ|?hA10rUKw~EN|zEFC~EBiO}-dYH#gq!YNZva_TY83ZqfiMqLTEVE1wFjH@!7 z^>_S^8s9KNXVhRNc48?uI6hCz92P0;^<;qZ^Z*g}GBNNVsbWdCWKH%dk}r9f&-vB@ zCsR= zC+YsHTMe&m=L@1v6eSf1cmJp5W_N!XSZCAs-q<#CweoLgNF6(?Kc8fD@#tnFt${uG zWG#sjVfRCsa}NJ2_nz8NjrF)I9tSV-s(6nL znP35S_$1F=zW9(G`H}ne2sw{ClGEtYXP0Fz)SHZZM#NeYM{7js#ZpP&njnPu+}b%?A1 zmEZ@LUB;pHsW%p=9y2VU=8fq zqA^(t^jQjUgA3BY39Nt&$RLh10u0h14a$HG$RG`b8VsN)4L;flgxa9h6bqPO3Z_Rb zpf3ujTArXF8nHtfS6T<9u?yWP3q&sovcQgvK&q+wqiKw*VN4niMXjS?q}5cSpAg=-MV~pUgnE(q=`Y|dxH=J4w$UqFhfEt59r^x^e*4YV= zT2h$W#U|SdAbY2u!U(t^v;o={!N9a>T3wGopVwfqk%A1^01Vgw4cOqev8bqTd$(^} z4KT&FL&cxdz&7lIA$)DC7J`ckf@vIr+{lo*En*7PY-%3SA%qzxF9Iak2O*l<-Oe&0 z7NQ{@Vx{{;y+Gn45E3?+vd0Pn3zopWp@S&8+Y6-oDa_m1LM2m9PbR`Eo@1k)b3+N# zfVbH|4a&y}Y@4@-8&lYz41mh0HA1#&d%z3)z;%1K#bCQ!!nWHW!54hBS<(rPOt1d~ zfD5vKt!Kjw^m(RZL$=ExJ%YfW9bBrEKncWPwrjk`sj0TDqqdaJ(_4zn4mrE;}L12v2WwX!Js{ynhnGt!u{L{g1`!FduE-W!J8by5yHh` zT*d)i3`j)@idv}`eYT0h35puULA(>4AP)E-4&vYnN+u3uaW=X@pZUo)Wc#DrfDJ^? zqaQ=h1EA1tgJ{x{yZElWG-bO)rqoNCWa!%*7sBQ&<<@PCX}I92p5oUJ<)!}*VqyDa z3cNtWhk&CWBMF!?M49ggxqup}t<=9`+LNo=G36p`u0RsjHe#B^WuvHVZVPnWdf1>1 zcKpw60?~m}(GOzPHKNs-D+p?PyM_SYf2X$Vebe_53qXB*;-CtgpbFw3-Eq*hZ$q}r z$KsK~pHJI*Y+JbZq{W&`7L!0EI0K zIQY6UrV1%?{wXFJWqhYL@Z2`^JOh=@Fh7 zqoCmv0@OV{4#Zq7Y?_;KTGiP=$cDfQUY!jz9g1!n4Pg5zmH?}#TH61uY3SF2+1KLR z)gpIHh9W@5dc^AP!Nb=@R4tC@^ulcLW#cB2GV&$fya#&;)DSlq<<`~0@9jIgEC2Fs z!r2oN%4Y+>al;A*Tn)-V47k9&tU&1xo#|u$!J)p=)t>E7#?LF`_1l09%E0$seCv&I z3929!k01&>wgokso2|VvWLpf?LgOoA;2V7IlM6hgXo?OWilqE81bQuc-cgc`#*qB_ zjfRReb=kE*)1zptrii@xM2mpZXwq9YcK+mNUjDfVX)uM#0V2Q$qj2y>+>Lwt{tZ01@ZrRZ z8$Z63N>n&qsH)6~)yhjSY|=PE^SoyiEs6~$F?{d{c#%`0DBRvX;&_Dvrzlx(5IsUG z@Z)oT*uJ4&VNCh4=&{{t+R9aC%T=f4MLMEwZ1cVw@hY}k@yfl(W zW$+fjgvgCZVu>c6h+>K=s<_1(%Ng-g5Vhe%9T+TKv_$}1SjZDzl*JdBSXbO<5ENRN zmk<(p(?I_%vBVTpz{iCa1VORu6@JC$ ztFBW37@M)d8oQ;DLpqU=ty$oz>siqjt1Gf!YH|NX7FcYjg_lV&!EF>-L@^{5JPl@+ zwrDAf?G!(f8|Jy`8fd3Lc<#htsuzg?Mj92-x}#TVbcF_tWNlR4M6P8xY(fPCoRS)T z?brqw0kffoxTJmza>yc&Omb6ZEcb-J5kF)F8Wqik6{nj`%BW6B@Z|+TX({L(&W3r6 z5Er{@p;=o*ADy#i2GO+CxJ7s`Ot&<~&7%Nd>W8(pPNB)0&GRjkJPXBmK2U zoqe{iPNQkvlM`53#74#nanY4UVnCZv%XE{$_d%*Y6olUvl@T!)*jYqI%_Tn$dE}B$ zPWh-#3=ud)m%}*X<(UVi1m*_;!Bh~Te_sDw5J!mKTfaj&p#cCfI)qV&gq*<_wS0&hkTFRbrlN!m*7rbkv**iD*6VxzB-m>Xh27sZDV*308n` zpN3>z6e6iyB{ZYT6iuvy6$xpk6a(M} z8piS);ZVpO))9@~DdMSD_30VxsZ^#mG5{83WLq=X$FLeT0Az)#Pj3p?z?vu!jrhVH zFrf)YgaILlXoMp`@rq11!m*1u$Q>L3h>vc;vAWAi7;f>3(1P|Ai;W`?>hKC<^kNZn zxJ4%pl8kS3RtRssg+b;}4L}&=8!#0p3?YKfJ^0fg9xd()xA2Noe1R3h@P#OP_eLQY z0Tj0o#w!YO%>djXwY~p9#2^AnTp)a*6uvOVE*jy_FuY>4>m{v1&cKRZsFoEfJ%}^D zAxebQ_O{jdg9z=3)c~Zj7YH#zIHDm?CprtW^RGJj z=oo$bVT6R3xB;ecb`9d;5h~cYf^D(?GVzK^p3Xk4CXClT8JmxGaRg#GKw!u!+EB2g>DGuB>=4g5W*Z-A&SoC#0Y=b!ynF#&^j>LqPN%r5DI}#Uv!zC7p#MzZ&BrkJUGFm`>l_+ zv5h@U!V|(}a*Fwh)NlC0)O(ocYl)l5Ubw*s5iPQP)0rc9(-Vn6$RsN;=mvD&F#uaQ zx4Hj-&LtycqOZu28>B36l80Km=u9W1O?yFmB0K=4aOfR`0E%yHBbNabs{93>Em@&14e}Ra{%624N?|j9Wmd$L4Y|2H#%b- zaTmfK!iZD?2Y{EL0ECpeOk&b;TI!x4>pY#|O%x9s*TjwdL7-TT(z2o&1~sMR^<7q4 z2ZhY!7dGVsTz>Qq)cew3u^UgE_V}w02*{oT3}Jj@gFNCD(N~BO^xkZaP-`1z5Rp^| zS0?{qD702F7X}iALDdiq7!-Jqmk>&4O)~WbBGn6f5C)GhPffQ{bA(jY5Op(TRRI7+ z!mvVfa9{^vf(WsI2LT8h7eft*VBzINepf~w2VFkqfIzSf5eNhZMuB7mU=NWB&UauY zlwh`IfhdMfm@q=S5Dpd>b-OlPQ`cLKl!ZKTc5Q`)E2ecNCTw|Rb^bJA)F*#yXg+KA z3R$K?Za@d(Hg`8M2Rv2^YM2v!7Y=`C5NBl!j#O2chI&AtN+^_XkQZj06l`*LO9-(C zG}MFe$4+RKYcq6d22oWi)@C;t0D(YzJvE310Z`ju49;+h#$bubXGp4uXb1sCH01vb zy^slU*MPm?V8)-7IA&?4bPMa?2(DH}y@n98 zHcC>*6SoFz?{|LFXnx+vaoD(xjmU=OXg>63V_C;i+|+*x;Rash3F25v17(1a7!Jwc zbpXYHp#}uspo_{!fz`N$;dOK)CS_lBaZFft4`G8vcR?w55Z~nsX7^T}2v90`MEV$! zC?yOX>5;Z2ePpDA3DH_L2TI=b1)`T>Czyx?sdF+VkqE(po``d$^n?K*Wy%(9XE0Ha zP?ORK5meWNL9umAHe6g+hTh0wBUW`qIe_K}mDK}d*#;4H2oclu3Y2hNK*9fq{RfDG zXn2Tch{Aw~0eKM1*lX9c3+vDb3BgOp2$TwOcnGFKn0OEuX-q=Ui4hr!2Qi8QMsMPH zO}N)YgTPDsD15wlmc3YXyA=-6#0u+Rg$6-O`Dc6kw2V?_Xp+>H$+wLVVU1NMk9x#@ z4#|y3_nC1inkvSH#1@sWX+6khnGdml?T8RV<_KG$clAY@BUFzE(SWgsLJ@|T54cQ1 zaAan=TLZayZh#0zfN)aARdF;=mdTXB*@8y|kp@wbWHf^(_(=gtoR(#2*NKA{XPXJJ z1)xNF!dDH|kU`paO4Js;BH-* zVa)k;N8xpzxsV|_d8}!5VTgsO37Z=#J}}0cFR=)$(3uKxhoInYe*kWL7gc_j5F&+L z8I(y@wFP1+WzO&l(a@4pw}@&MiOq;rd!S6wXL+n7j(b^`mWB}XR0twu1Zz1=)fWy5 zX;CL=1oMPwqyq`*l$x&SL|gElx>E=1@OZaq5RqvNuW(<;*J{hRLYRP7U-k$`XpcyW znLFBkEA))fn0$Z0Xk@8}d=-Az_>`;ZeieGBscD*q8b@OGeWt0Q915w@Bbzz#j>)D8 znowD9qIc>hLen;)JHb!Cc@RDK4Y$Aw&X7s9Ct*W~rq0j^rpo`F#$XJ>U{R_htBF96 zpg=?60G(wdW#6z1uMkP$@CW>ca5e}-DY!xrCQ-M5P@yzBeO9WciVWao5JI&LUlfer zppZ_dLL+$)nY0bPuwEjiR2ha0Z^8=EkPMChtL!AJvr0p=Y7B_*CJ40+!J0{Xl@Pir ziMm9qvO2G`st7ozLR9FJA?dH-&}}Pp2J~91@oKNo^rw4RlwrtX(pX^+8dC+SbsjsY zkt(v1GnG1V2cn>34;KJ-HwmV+1vR!#UKmyA1bheavbN+4i{N_IunnEXeub7~Nv2OE z_DQOgUDG8}isTIXDQZzA1asL_m?%?|V3NI1vt8C_lH~sjjo^9)(FxTsNy&f+=448{ z_n{=W3yh{o(`gXV@C~PQWSgl-2&rCh21*H=5Jh`}2LZHlO9|oVjBF{5d+=m_>O?0c zx8ZP~61o%ar)%R#jlOnbl-RWJ_i7`Hxd{{oH~A)epi(herr}TuA|@2##cEAN2Y*17 zdbAT?aDZFkxj2!!aaVOI>7YgD2C%Q-+ z6H>OT4z;>1Wv$v)a}YSO=p(jKB#Y3eLc;z0e8$`4E6$ zqw0wXEklUKY#Fee) zSL2t)W$efE7rjg|$6N?@)tj-U`^Ljj#e65mVN5zu7m}1{T!Y+J2Aq72?8un>$D3R| zaeN}w2vpwJ#{I;?E1bwnF}Y4lN@`e|o=pF!4oS*UY<8v0$+ZkQM)!3dD|SjL#vsd5 z7fX;7J3{<)%HK4~O?hx2#-PBgvDD|3%6ybr7-A9Hg!kTZR3 z{J4&)n!a1dm0Nzm7F{G}TBX~~L^^C0nr4uj#_=r9dVJ5Ow1|Pltf9)q5Nw^ zDyaAz#jkvsD*DnhVK z>{HR3%!oY2W!=eay$FnVLCW&?l{;;MmLR_tTeo*XZ27RXxv%y3W!k znggxZ*~n69`Oa5W*OwhKmb}Xs2*zrRp_@(CL*3HN>&!Jx)s&aj6WZ0ewskSJMXXVlBh*q}O^!Hv`c zZQ00J&ZNnR+NjdK&D}F~&5R4r8qJld9hV>7Z_9j2mOETuIFIiq+aD{2&HddW$l1mH z$jki8rTyAoT+Poslz7zL0j~cdgB-`AT+?*SsLXxTJ?+>_{m+f6#e}V>Or3tBcHKq| z)C&%{O#RnvY~eTEPZ2)Zb9~?eZsLuh*#xQ93SHvXeaTzQ&a9o&{%x@PJ;}X^;WRGe zYVDA@jm#o_$R!Zz{ktIq%Gt?uft4(qWl>$6VlwQlRTj_bLu>$}eD%JiSir z3G@VAfb0_aa3QtZ*5K*|vn%|R5bLM!P58CB3b!!GULzCTbQ6-J>1jx#;p z{t#P`1V;ew?QTFW5*6(3?(@#+Qm`CS@Dp;A25As5`;IyiK?Y)A1xk=C0TF;TmbP|5HU^w1rW~!Q1CfekOd*{Ef5g|OArN2!0-uS1X%zD zMzHZrfCcDI?=wF=N3a}gAoB@f5_Cg1!!iUfGcdCe99bYG2>~VIas+(AA2}l?2C*x6 zaWz*^GigCISCIcS9^*4}k`PXi_5YzZRj?~bGX=^{^JO0@8XpB7ZxCFN1qR;}CleLS zgA=Cn>%ZO=!;%tdAQo286(ABE-w_((5hqTc7fZ7%1|I~wG6fs5^6)_}SpXwPfEPRy zIzs^X4?!+Wa0EecGeoi(+`mJd7q#kpzrECpi;1X3_Mg zul*~61*?BEaZm+Z9|zgL6XFgBYf$@<5+bg#FhZ{rMxZR&vi0#VFA0Gc#lI`!k|2ZO z1db07TCD#BAQ)hZ79<6kXn_)>;6sQ?v`m2*V2Bnb4hc%6NYIIvDi1F*saVqFNt7v7 zu4LKLnW` zTet<~k}T*1Z{x=Wk+3CN+45z~nKf_b+}ZPI(4j@MTv8=V+bC70IE5)>O;k8Xs9MF! zrVLj$Vl-FLauo{0wN;o5C$5&@-jqtR@YVv7Z$*w37eD-%H$Zif7)NjC-rf6m@ZrUe zC%^w)qfI2R&DgAZwP4n*ioIrr;suLAEwT$H(N6IEL*!68&k82IU<@L}D&p_J>)wLQ zx&S6itUL-UwD3XGa!4YJH1bF!S=!>YsQ#MGy@J|cV<3XaND(vMe!K4>BdYKM$|Srn z4!;>I+MZ)JOx2 zGOW~1v)``J!Z3)Im@5k`qG&E5y|gH^qJ^%AB8w;_-O?hv4w|U0Itj8AqbLrlg3|x% zd?aW^Ky%e~S6+MdH9Rw5d!kS_XeG!9MA^u#tN1dL$Uu`y^FpxIAPUf=AWEIqiz`}< zYg@s>HSjzxycCQHC>w+j&tKbh_g#47mA5h{)KCK=ApBFpu&y5ME(j%tFxDl9f;d9p znv6(yUWOZX_+f}6e$UD@RAM%>|9;9?VvalZ_+yZNMN|!CZ5z0xenVDyWtLlZ`Q@7! zZBz^{oIJ^)A<8%vW}bWY`DdVmCNf`wh!*;2q?1;9X{MWY`e~@6mU?QctG4=T&4j>u zYp%QY`fISm7JF>6%QpLLw9{65ZMNHX`)z{m*aI{njE=Z&xbxO~Z=M1PC!GIGVgjOW zAnb-nh({=)BqhQPe`pa*+;Eq0zALxs{3=3z7Qsyb+$=q@WD;GBb;i! za2Iv0F_(RI%>O_n_LmAry`(~_3CEXkzELT4lSaqn-NJFFeR<~DR$eC94G-gQQ343Z z^qCw9$C-woZ~lAmu@2*wSIQ^?hcG1gIpPsy3+W@s_2w5n(EZO7>v#nWy>}Dbd2e?M#9RN-d>BK595IJR z#G&1k_(B{Kv57zYU=^(>FC+Y64}ajIGr~~^1ro#<;kd;X0#FD6`l2KdJc<4!xWOV8 z_U?}q2eEd7{euEFpdFOA`JUD%URyiaj|?P z>|7~HU$IlaEDHr!eh#&m)1ZZj~h79oGM0jE5kilXCn99k)@? zU4RmMD2e4H*5Sf}?BQ=VTZs}4H$_DvGM*Mqpz?b8#5LwJogR(jBS(r)l%_ODegr}> z!5GnSB;z54U?#rUXc9M`Zk8<6!~(q-h|Ew9flP#B1>I>*3$AgL=459Q>uFMzMpdd8 zs^mlb3DANF6rxfT=|e)vP$ceR9gX;(FV-=L%>Vmok9%MI21S5#fXEg~NjhIFVxX>EsvA%_Led@2s(%y4Qb94= z%{gNatvn!93Cvcu@-K?I}PXlby^m7J7GkG(-taqnndOT2`q? zeR7w*%rQ|oBO1x*MJFhF5qohD4G0aILH54&U2=7o$Y*QJm*=@d**YW{rqP@ z2U^gBCUl_Y^R}=w9L2C-R*MIw5^&Oy2~!JBeORHl1luhZ>w*7F<$u zJXukvTGd1GWusY=;Z?^P)bZsk2IK1zKBD?`HkNg-A8pa+0UOt^thB3reQZQ$8LEf0 zG_FYub{Yp5)qX4L7&VUFd4_mcyS;px{9K>~qI^ z&fwlGyx&-A4USvh`-XG6iJNVE>r%t~CU~B`{ZwP?w3;IQc6|%}@Hk@_milh1xHAk~ zSVLUnPG0snT{2FGCsLOi+<3{oEb%t4WQzYCw`&tk{_-X}T;ROcw5vG?bDWP@$tKBo z&V8P2_KLgKKPS4OQ@-S)Ctc}FXL{3}{&c8EUFuV(deyCdb*yJy>s#k~*S-FAutV$# zT_F3JJL3c{P$}$dciV@e5~9!yAvbKNJKNF|mGy+?Vs+4YZCdDT1bMJfM$p#gv zz$6HZLKYds0EPf$%m`da0~x@ecC1uh3|82CW57TLGNb|XEcrV`ppb<#Cm{>0F?{Rc zbp+U~q4XzlLW!(|24&rbI#nqd8z3)|l93Ei{tAE+aIXd_v7ur+(bN*GB@ov~e?v}y zLKL7tDK2Dz3o!{+R5;a=+N*&Ke=+|)8@68%NAU~yn6FA2f)E5NRHaz~uo4&?;)JS< z-X{D>j6@(LeE=*ECx`>4h=VJTjVXwO31NvY7?iJ27IIO(f(U{Vu^ANcm)dKChZsH* z(Y?61lAGv~Nht^{ppyVR!ScWYrAUG*I0~?cgE47|yMu!@ct8^Yj1++n>aYzQoWIVK zyZNg<52TS)sf*Kih%C^8Q@IutY(noa3Zzg90&I$>fQ_keiQ2otjYtu>Bfcz@kNN9D z97KagDZ>)^3bY^#h!_Gk@joYgL+>b!BRqoCsFv0UJpBMa9_&Fd>?0v08X&}tX6Xtv z06jwtJ)E!`-jEF~nLRjs#0~$M!Mwx5Gkgy&Bs`BeLxOqc|d0D?teg;xLtI+zI|aD+?%N|Z1HOrV5e6s-A4 zoWStq!qK0AV~K+sI@5f^T?mKFdDf1|j$y zM@S`?_<}9?92Nf>B_Y73Kv=7lD~K6Fo$ElVgU>02bzp@b!cKyCuyBZmbx4M} z`MBLF&yr%XZO|lEh=xV@C4r-?_ngm)8ls((&^H7E76Jv-;U~hH%_Leb*7;ECtgIsP z%@_)xaA3*+c+N+VEUBcY*g;O_6gmctP?@vQCKQ4{SO;XNo7IU1x8l%ONF_G_f=2Ki z{Ar0CGEt-Hgok>F=Y#|or7Ux*n;3mF5A(N^!cs^q9LEBJ+Rp&+8(%1(IrxTX za5kbbP<8)eAyGI3Np*u>2nR=aQ7COEA#l*-R5=A|Ha>Mi7D9yp5TK)6Ez%4C7Mg_U z86*CBHR55@f*4Z-+Z;)lQ~R%uON-7cOmHG_r2VSTNNFtA!B zovQx~fGxNM6e68yP%wzt0~D&)0Km@!J21XvqPls`Tm7GYZLlH|0-HVB1nUWQi`kVl zf;#wvh2_d+ttfJPs~0OwtSwu!JzKO*TeV$VwryLteOtJVTe+QEx~*Hgy<5D^TfN;| zzD1fVbt)~ZEShUCJjJZS?c0j%G${I{*0|b#g9*h&T$Zd-MG87km9(H7Tq^xr$tB5F z+ocb)H(NqA%?-+4?Oc6iIl!eSczROhj9NXqIcGy8)cr=3Gon9|tKm{px-wl~#a*YW zU2j}Y(#q{khxymT$p!4q_o5Vj?bLBR*mzPGTiq zVkT~4Cw^imj$$dE;G?SOV7D;%Q68 zRon?9*uz}35)A}MEgTIifEG61Hc9k}VpIwE!{U@E$L&~f7gahidh{FkA&Dq!J+WYu2nY3<6+loZ6nrAa`@L{Jao28C#@lGx%~*Seh|q{2dN3-j5gEj|Wm?SiRvIR}! zx5T|>W*1{IkIFHGD9@XxNu=n!3a$d9N;@S9Q1=b^AJ9HZ|MH1=z#92QXq(c5+f#1A zP`;~I7dLt$y*d<4XK*y`&m$;}Gq-1(>WH&AB9*p>$tLj;6BfjaknEZ7jk4UvgN?x2 z27BgDmJMx(ktfnLOLl`~r=w|D35;=Di@RGVJPKNoV*ZgO&7A-Vv{!>%g!#-e458 zemY4Ngb{kW5lXh!fMUowL33=9Av{LIIvcPchT~M`i#ofu9#Z# zvH#gL#BLeQfwb;u#6NMMHU$lG3jW+^Y@3u}nPLhF;3fMVp=$T98~-FOiG>9$?R0R! z=#%$~FcDQbPir_!F=K&(5>v=^Q8m1rq_N}#$mBAhXxo?OEP}R6)Q&H?1}dTA zh<6`};Bst*LyvrNsQl*xn?XB(Pr8NW8wgbWn&|W96t*5B6(?sl{zm^txeN&+`xDG6 z`%5(>Oxo$B>r>$OpvG8Na_7@mPKRJrzKMu%oqa2lpk#$UH(bIYM8r>UIt$I7gn0AK zP-Kkne2R`6fJru11VS%CmI5Y&tN!H=am(Ly`+#&aCVgXs=bm7TYbNe)uIB#H$o-R% zyXj|l%XoLIe0S?_?l#}uAD2-z_HuBi-R&Jn9Zm`9nL`~m5}Y`1CIxQdARc1RUGq*i zKLT#joXXjX6SN6Xy~QI1$$m17CHw9sE0fjYKs<{kv4c1xImm#lKIxw^;sxbrvIIOm z5^v|_f!g_yD2L2xt7X6~sxr;jAaJlUGY5<5)~O%g8ab69N2K^|cFE)%0F0(cbN2(8 z;FXmQNp*-6DhN^T2`P)2oLIceLwco++@*1$Dl#t}ljYhTV}Id{RQ&Vfq#(F(_wHLP zW&W<0a;taNqGur(O<961697zai7XR`m1_R%R{$0fg=+tWRVqhvoZTIAfS-kC<8~(; zExqYSfC<`=%|!2p4WB{*H09Pi`Znce-r5yb&8)fVc5T7)>TDC0xhlF`*R^*+h#c>p*3V;&F{0lnIRnCTaVKgA(Kt6}B5kz6|AGHY>j4t^<)uOgcwmpCJ*@pTGxrb$8} zY7(_?d?IG#N@w#SgD)@{k|BY57*jcstDnJjt2vI$5PtbEG%Sp_p^&Ck#S~-@A|xvE zH5XgGa^&9Bk5vOmL)5}xC-w4h#a_7gM2FgiZL0Vl0af zuiIAlQcFOdpJk`2b#OW}pULaK(MyhjIjM><4A?~QMI*SZTx(50zF0#dG{hX|zE*F* zaf6uxi-~@Yz=zN4g$9&CIrdjWfSl;6|WU!$?)|_b{kVr3l%*WVQBgiO=I^ zh|F#+FUx2i|N4X5ZEk)?pGMGxLEGqVa(z&r5Wc|n>MR!B+lRGn*I@g;&`Y9C{nkj2 z1WN7<=A4~mp8iP8gd0;mb^fWc7DJ!D>X{t4Maa8JPoh+QYC9~+#YJVTN$x`U=Lio3 zdDWGvGH2D1n>tw$*lgleENnJ`>02vGBxheIkDO&QO5Ij;S4oggRFPe(0o zS9ELos{o_gbBKYnTXI<1C?#n>(&;DvbQDLB&@j9Tn>*r;$1@hJ>522FL6m}MfNMrJ(*>#ZBTeJpFX~{7)YY3uA4?U z5x-y+m7b1htU?U*f&!?N zM&%c%b~>@4P^K`apbO!sWx~cmc^B#%QaDUp^6J}S5Og&`#D}Vm-`-JHfI%aRUe*jx zqIOBS2MA0{al{=x9E3|Y40DC;<9%KXru*oI!No1D)xx|*Q{a{$H^CqVtr#Lb*(0TI zvkw7PjK4Au0oM!sqDd+#d5J?HR}1B2F_GL>Ykia0e$|H~DGy}Da~?1ZNQ!HbqGtYB z3VA=rqU^9V$Bgk-lHd7{#;1K5rc;SDRTz*QNq%Hb6|=8&PZS%b+3s>0E~CMk39O&n5PU54}8*E~y54 zQXXh}hog0W(l#_$ZvM7Wgu!Q^XgXnX3VDai7K}tFi zTFt!0#!kV4IHo{ZR%g68g9wWJQH0;M3+<+`Jj>n;Ox@Rvvgkf?kTpppZrQv-p2Ny8 zL_?*1u^KlD$c+E79w()8)?QPwOkzq8VM7f}Z{PkX@OHE->xZnCB{o1XS58jYIgz^( zC5UmLIO|zW^>rTi$YFN@1^r`h@XsscG~FU^vzz6wT8AYpsCm;@j@4cXEEd~oGUr7A zjTsdWoq-_@OB5T0IceuoP*v7VXy?EV-l0S>{##3^a-+KWiol4C&FhR{P4{mgTD$ka zy>}ZV3}&<(r1qSRE82y0y5zzeN1nm>%2j6V7*|BY~SWATyK?=605hat#tScM7vaIuP`S8kbXOo67KJX(!WbmyAS7swGg?{SKPgveL(u zOX%&83AWUgGI-)x%+rshRP+e%e{NqrXK{_KcHxNhBade|M9gm4SK%im4+>BxMMIfJS9YugCfAUYt z{f2hhPf!n|2)BKEzN+F#WTB0I$c!|{mFy2c{OV^vHO0Khme{v*qa)VurV>ADak}rD zxuia8rRz%Qj-OPQ2&~W;@y#OSPYszcH$f2{VFD+SeJcf)kb&-Lc^oMbt9 z@VA#-C&`D@g{U(9mPE1Lp|Pz5P>@NJgR~iGF4wcxM2+o?AGLYufa?7_Jv0N2?}!u zyidyeOElFAxxvD&%Ws626yCoe{D5Rm>`FB9(G4}NyHf~r3yu?t~k0vjb7P4*(7+J}y zD&%UUCHpkn4E#mATtLP6j---;f}56tBm`(*M8bzprATWQDnYPO?8Rpx^{bYm+KX99G?L9&i+h=&Cr!81 zv=;N2+m#c(IZ0*P1oC(f6jC*F@mi1;p%IfLyU`u6Ka#9JTbE=vf+G-emh`s!)H_Qr zpw!05T@8Ji5IHLiY3V0YC)PB!L>})8GVnlAd#(;EMnxY;Msj?-sUBp%$9B2Oi-{`Mr z*@fog=hj+tfmsAnCIb+anN^o4j zohe6Kl=$(9BwHDW#};U4A3{lldNoJ+CTYhqY=S)E6Z~u-4CiGT(A0DLPrd;SFEmw$c%y@&y4jKwJOjlZ1@+t1QYOASFFXj z0He(q!nV&~+)Ab3qq5y5x~E|Xo?eLYs}Ki&;J~?b06Kt5rOf7H4Q{ad@m`XX%rYHeA{cy%tbrTTys$46VTUVVlb{Djyp zW=X>o^%$9coI$fe2%M!c6W%F9H!v^q!_q>pw5wC*bhTVOk6HFHaIVAv&LD~Wbhf6? z90V5_geMF>npA-5`XopOTmmezg`@(;NcjGZMz1HtfC^;nUpBGF$||npC4|PqCEKW^ z3-o}8b_4Gtm4aLe9A)~4)LCU~x37-Z-?Z;#Lw-4%9!N997tw7_{GnQEt7yO7s|l&h z2}6sDd)AUP&(#|LsUCgZN|24v766(97H62_@~xY&3-ef^ewB%VFSGwKr(}fI|G^Ed zDbji?{Uno@CCT>p`KG`t8gD=vyXv$w_GW86rK+lRs}>Ng@(;YHq8b#AUn@7yweLS& z9{bBO@@asyc6j*%f%j1#8!y$BphoX{pMJsi(e@x)Etb!=iRvE{3=$v`Iy=bcJMyX% zeH?(&laxu@wuXg@QU)i0YN~_kBzYQ5>|*o<*mVHq8dd<(P>x95h%~6VvNRdHD@xH= zJv)?So=@V4qZR`eRMkWGV)?PqFiD1&Olp=72kX45D&xRv`3QfGS-xPH%{Yijy1Jol zPg%N}n|D&4#ZGn0GJ%VoDeFZxa9=__hzT6bcRc5WyU`zos^%Nq7&y&ea@?p=B_mHg zOCjahX*==5c2Y-q`2>DWE=8GSIQu1NBqNb>C$z7bBc)J|H$`4);FxW~ZY_#KS5s;h z6Rm~>XqRXg$*b}~Q;M^;nt4sBN4DIXM0)bNkArt@`aObw6&1+UvQ>&UTOgKuq%iPw~-5eijW6<)9qAb%-QGOOH~2Pa*B@>!6Uz zaU*&1_u%7|HFKOIrZ>?cbpj`qAKJk+h!OYq#+T#J6XLnF$T`W4Q_#29BBlUQ+kxhS z@9QCqBN;NveG9I#cl)K&2a|j;I*dBCuX!s=$6`f!q{(PbPjVzT%u#)D=B;A6EIZ?h z!GTbQ_}`6Ib|dp7ZN2(BEKqgSg>4lcfn`Y%)ZgXkJ&3cLs=+v~vm1f_N8$lYoWVINNQDt)OblToizhMV3jNHj8)rA-x zxJVFmx{m5M_cpj6n9D|CQ3uN8n#&lxtX~ASY?r@UXOLHwHsf2*u zsz;ai;6QOgZ0peAC*6Tzu|1NbK;aE(vLhE-oN=TzWKha1L3RmmXHcQ@04zaKu!h0bOeBBe9_x<#V82j9N|?z)-KzxnVk zLj{}9bl1QPi!TttjizXEEobX)5r1u@6l9gpcc2nv z?SfC$cy0Zy>7yB+>1V#>kY<&hW}9($^CLba5b5rKb>p}IWR?zoEztj}oY?8Lhl}uy zihUgK_?{&E8UhLuh^~Srw!>8lMr{BYO z{Kj|2!*Aur?>E0yhKI+l$LEKe&uE?jShoQ-H>+fx0tB8xY_~zLJ%fdBgFj1qedZ5& z=NYPh8*1hm#(xv&(i-M-8y@`JM0OiNIq1*E7+LHY_4PKY;Wog<6D!{%di*wK#xr)M z)mBNsbK^Gd(lh?yHvZjkG^IcSp;sd1T_R~)nHhM3IWu0lD}p&Tf_Uq9 zd6!=K`fVv4x%pW41%yKJUj?;Ey^GlHi!1~RlDUedyi1gXf_J^lRqsp9yuU286c4w4 z@wqPx_I7>YU7qY+ku4NAewUJeU)kXORotx9qy6jnebtPRnWK00Z||BzA;p;cnuq&u z$op!vhg!mps($Y}dY}5__F6Wd2H}T>>;Z9!hsJjgB@a?fWuJBGZKADV;j+KY5cLKycz1<#xDzn1fXudso0t83G zu#CX(SiXI1BJLP)(<*rH3%E+v1G4X(@8Ea~5m6`6?7(+@-(eqL_ZRTqZ}9$n;PB_i z(PH190w_e%C`1BqxFejzu~#Jn-b;_7nBhBi`1nI9jBo(u#Q+>;03T3;!<2hfT;aX% zP!yF#riA~^Fo8&begv9um}VfMrXSHNu=n(VVpC)`*l%$~nn=eFzzjzqePIl}D#nl9 zHol|LeyihMGVE|-b2uCZC(`UCs_Ob7`q(WevO4u|ld#*|v8z|fcZ==m7c!*#@?q$; z|F)9Y)<03$#DnDa(C@3Q}%$ERp<7Efb~;F{V>Y=iqKn z5kM66#PM4cF_gb9mdFtK_$dd1Pb*UllcRVu>S`rl%7`I^&H}ZT{R*iT3mJWHsTOS* ze+`p&$Y011nhv8Y~g*D4f z^99M#bTAG`*Z>(cfklw3qu+yXzvISHrZ%qimhVshZvCOl+pZ9A{l*}J;b=O4PV8x4 z;K)9w)5uw@gRD`iFI-8AYVE4#coC6l^hPD)rBcg$@JSU!uyH8hzgv-XG#^wH0Lt@< z00AgK;D1}H|632x|6`y2Z%zK6LGr(O^8b|&L;J3NcMuRCm}NW%MEJFF(nS za<)ZBmdv=8-Ex!tN?-0nbB#fV)8)^uac$1^F8>Eq>c^H^1aM)X>~bVpX_Kk-RKF% zdZF6cdj5MPna$|Os>fzUrhf7ps%Nw4>HG$>4f_v19w!Umqmg)O>pos*J2S;b;)Z@c z*Sj0z7#v-1uI^{gUo%F0YeOOdAm+^gAc^H>AegayGYFfnb-^}rpP$P2WYEGSlsIIscW_ZSL!4z%1anwd%xo)eqHBi z1vF)tM#|;27A48Q%G^#?m0j9SQPzUIOx4zFD@tr?Bl{_K2;P2ajrY`|#t;8ev6E%n zyuXv}IHaJ#QWvX$F9fYAr4%(B6rfFeYYo{e2qMY)Q}{qm!CVx=Q)yWoExTM6W8Q3T z0XO+rv@7pA-A^fw62Q7!UXo^gP*MJ+lGQPRXj=i03q)>Kl)l@7WV;yM3l^8eUmxs! z>qN!cuk8leu-EmGL?4A2tcNG~N#`{kG|p<-95*d~imrS;vbMaEPr%A%U%yQ)T+_x} z)Hl~Q-aLNN@uxjnr{Ntunj%;IWhG^Kk@ex}cK`~7XPcdID}5yZ$*_a$Qt+}lk{EJJ}UYkK=u5BYD~ zrax3>%5Sz)wC(Tyu;<5Uni(?r-|psxci-+srQ-_i2l4siZ~KqM-W}Eszj`>byP&eu z&ne-s1`W)5lB1g29dk{*#LD=_1DGuInYdjepn2 zm3bN$j+`(4-R+fqd%8brIemIK8|FklUM)Bv|K09>Lp~j0^gc%*b^!oGz6X`!ETH5f ze>{W>3Zgp;gvJyAndEyh_0EFGCJI3KBcXw=j=?n8gbLxZwI2wVGs2X(mW%7f( z3g@(1-~cj^s|>0NEuV%umJ?D+3lO+hqm;o!a7>S&4oAqe)XtS0rnh{N-qRS1-|$Cz+4Djm z8e5$wcy!{^(@v~hD+x#O{)F|@MN|zt4QKV}q`miL_9k|jz_7v(=d8<|J>@c?h0!1G z?U%V{F=ZmV3RB+8mwC4nWnwp@$SME(%X|P%xdetHB8cLu0IX6jNjioI6S^vd#+FMn zDNaY}T@{f{mdo;wO~-j(71Q8U$jd4IOv<_{VOFV7)E@hp)_zsW6@hauqAY8$90!z+^tQHsw^!UCZ@Bl6GBC+ zt&6pm=GwLNE9|NQEHjqYkptIF3Ayz49&F#|DfXH>aqL}SO8DAu8~BEaYn<&mR(FJM z+7Pidu4PJV2YNT{i<33(E#qq^-ZveaI1U1lY=)<(EuBXUr}iKl@xOfL5F95?Z+w=G zyJe5m36WFB10SQtZpQ}epAMhzm^M);$>5i*Tcnhd^UKsaohu9spYe)TmY`d`WJ3m3Mfu zbp>8NUSxWF-Fee-hn#eby9BJT?+UHl{U|PZo%g=fg7oBWDgd{UY5s<^(UDc-sI(C|ShPv?^*vA@cZDdoc=Ar4=C`sC3k;fEzeTyvvYnQf@1 z&+_?plT*!_qU~#<@v|m(cqM;^=+Vhb7c!juLfOgr${!_$mlhBlrcW4iF`<$H`8cH<+f*mG7;x?v;p% zTgdloUBMz9v@QLQp&XPE#A0MJnf$t*(z=sQhVt7c$r!NAzoA5RDs?S9*ddP7Lm}sv zJ|GO3Eg60xI*pT#GZHnxN!C-XKY)WajH57|Ln>sX7ld;jh))(EX6goG7Jk=CFO=b? zj@;vvjG%GXiRgw~oTTcx4jZm$T776y(h7kI?0Hy{NyfHPhA=}dX|$t5DZ7cImTn?i z5`93ooGxSl&ppa$GJMWO*_u|JGM&$#LL<<66?DRazSG74cp@V$VedVCUETG^ETu~2 zBk=~pXFX#VGh&xpV^M$q#BJ-u?RduRWyBq{#vLujo!rKqk;PvK#9!&e zUwg*iX2jpO#y>8`Ki$Ry$P-Wn6P|BBg1i#InF*L}3D`>sxOWLq@#68lopt0hC!BHJ7?%GY;Ee7YZIkeci$zr-{c1=Nczrw{wd8`r90~*n-TV9ylJ`7}(s=6t_zF_gBWcG@%cTy>JCb4e? ziFL~5FzKYe-v(1?K@Fji0Mk^o$W+@4pEu+H2YD!toNRAz%7;v`kqr8Pj3jF>`W16| zZK7BY7MR)H3j@In>t6xlrdn8}slMSE33u9}knqGddd|i4#%Xge-Ap=J8b3zkpwY~t z(a&gGA;l0iZr7~Jwydh9teU&5TJr3A!R$ue>}Id**39how(QQO?C!hl9`c+%!JGlz zoFT8Ak<6U2ww#HjoF8{N2=d&Yg1NK0x$|DRiVhM^8Nud&Hy%JgP68WqW#r6{AwWp;{lzlti*@@K+vP9z_g@?- z%AAGDT=mM_y~{i+OQ@~0>F=GVToU>G{k+@;#73K=iFw5rRXTcy8fZ|()l6&QPl!}(o3fua!(B+(a{!0GlLad?? zp~_11w-p-SbtdR8sAv-s{V7U1oh+Fs`H= zRlVF^y}DezeqX&wQS(cvW?Qdj$Gc`PtLC{S`DnT3Y<*CvSET(0R`p%dqV%8z~#gL4!GR^Pq@^- zrfem)>8(NOi8@}6uhI=PZL5^&;Imz6wEf+lisezW*6z7+P}*^0ztQQ7_CSp7S-aI2 zfn;UuymkCN5JNAVhV51VXDs7|&6mzQ=iP}MDIXFX@5cR~<>KE(DbwC)&3{}NvX4!( z)&KTCfy>Ue%UwjVQvNG1)=!JI?~~{KvwRMYH#@?S$XDGWcbDrk@!Ae~qW6E#R)#-w zei!@qa8kE$E!6Sde;Gg`n;<$%{NLbmZ!;Jw%e)l=nop%PMgHAg54&`-%n!eHWBwIR zA141RlJN`pSJcb;h@xoLW&y)6W8D^`0NyCst^W#_AeQX}X%edv2UP37I&qw1i`&WE zl91misgf{8@M9m@cgny=r6I2 zyG8Z+E@w5h?f%Z`ywf2T!l_v0{jRDO{rszrw`=}s!Bp+OWZA;OIg=Hay=C;~<9~t6 zn{^s)q%w!e@Ak>-Wh*>;&#efoJb|q!Bs%}1OQfiWo9}M=o^>)JTeiDy zq8~01a-9FJ1hl_0d<=ZyAacI!G4=0eB>cN5qWZ;v?}e$b+Q0uHTt42MB9Ui=sQ)iq zf|UzUNiA7XhS|h2(lbM;fnkRT=tQ)pM`P(Pt~m=WX+BeDcTC?@(P^03nqAaJfO*0W@j61{#HaCI(d zFj7o|(bg;8ZW}jkLPtwFDv$oYFfk#fgki00B#ow?Ce;A(l4*2QRn{`jN<^JB7!9bF zb&)cMISvQ{2e!Zb{{b#5)x-Y_TyBW`2V81?VQi{U zkFC@!8>3`X|6BPJ%fh~dxe%Xk;HwVKSDj%+tzgThDtN$N;S{bX|H5i}95(%Z8So zR3lqb&6Q0GZJ`#w5z`kJ`l}4rtq5XOr{ezsTz>N$R$9Nvy6N1TGjX1wT>n#_UU2wN z1^hz6;-{ttmKWe9TmF-hEi@gnCn|2Qj$Q4A2UFdpL+lVRXDD66Kd=++? zg#Jq2rLH~<(}ye#kx36Ee%u-oe&cJ#PITRZV*jrY!7^OI^u z2W*u)`EH`~jwfqjVuz2E0U7$q{k7xo{{okuvNXAu6T4y$Ug_dbE_0||G?G~N&v5C= za8qSzKiM*!5Z72Tsiz^U)?V$@?F5+hwW<wHeirBS5kEt99Gly*W`fdj zLAX@@=|(Q!7Wx@0q;Ghsu7}p!gn})6qfLQUJJ#$y-M#D_*6EkTBvyx&F&+Tb)GfdQ zn@PW4cUv22SKX_zu9o!sMsN$;E12uY1^a=Hz^1BQ3nc0E4{zHpo37VnoxC}yNto{9 z%MF65e4Co~Q9#nD9S%|5Ek=Sh-@>d z-J!hdzF>-dxy60@mUZ`@A7vP4Qjl{7k(^f>?=Z5bHg!L5qq_Fh!%v#&l~2LXwxpzQ z|0MEX!3qxZ%F>blB!W2~e^DZD?X{Ynoa6r!F2Rgq|4VRrJN5nPW(xWA@O;Ea7Jw=c z;8gDgWLBB*2)L*B!#4>)bCCsxAZ5n)49XYF+UOSpa4z3aZ{!-}Ym)e8Vx--ea4i^TZVCPK_ z9pIMp+yG3!#PJ>6QKav^0#^tyF|e0UPnhlK6V3T-SNSp4gHA{fr=8wf9oI={zfN4X&^CzlRjbs zc^(Yf3ZjnCmURyQ7$Iy5W{?JZ7`Ae#-zp?qGQ~6-R+qZ6%sRqRjYA@cN9H3vEg~rz zBS&c?QBfj^Or&ZS3F!mz*9@v6RN3cwz?CB zi4tujN4qK;wlHit*cA1OA-b>}zE1Xk94_yYxX6=v1e1Anlli=o1(2D^LT$+^o-`_a zI?r_oNh=>IT?y;bSeeX}Ctht~d8U~16pnsS=OWCtoYLPCs=e=M2=`IHqnTi4*ep-+ z@_a+mN@YYVGoYP1J)0~qWoKjLhvV`=(V?MBm&hOF32_(Df zGH~BGJ6xw%{!E+2Pl>XEeIaGA7)&*|ql~-D$XL=Ce3Ow$PTMRWD@yPwa4A!)f~Hy4 zG+iO9(n|8RtNm9iwQ=;UZ~q72@=7=V`aj|FzAgW8RK8*H`W{+S^qoXGONtHz07yH%>TYDz`ImfFULPUn6NxQeKt0* zz1$EPC}rUhl+yY|C6ah5L(%LY8bqMte;4*Bm`YUVh1H%;gN%u^n-oVzJd*sUQ&7zC8fD#EF&_)T7U-%Q`a3!P@DQjMyx8j~)Gpdm}6 z>})TQXQ8TMEeW-zY1I4r_L(pL_rPU)vjWn%rYEiLPkSAO55t9WmUHT-8y}CL0Ojl3WKN@?4V2I21Sn{%4&8MVgiF_m zBGD*&NbI7Hq3H^8J42V#$FL{})X>Lp<*Eh-H!7~sC?7T+0f8noco%>MoO+DB0*Kuq zL`?}ATL8&%etvCBUI3(>8$K zv;ASSlMh#-O{?EZYh;J2WG%Yo*Ji8>^t=Q}pd*HlBgV{fgCUlnTWP z4Sn$Iw>R_*x=45rKeNIc} zW^YA$KA<-@mQxuH&fOvddRg4DbLYv7% z*J;)uZgxQJF7W+i3!exv&oQxy-R!Cg^mjIdKy0STXY|GZY(xXJFPJ*Tf#h<5QHemw zh_PG04I}8BO&6ubCL(DKa;gj^&zq-=+j4v8Y7`k}7n|YqAB{NcLv30g$QSTLW{1|fjZ#6<F((L9*U;yDQR1vGnM-Wuk*?#32OnPWZ$4G9?BpNqH z;dA4J3T%HB!Xk~4paK<&HXrmq$}oJ5<}|w{+?{^{TEq3e&ylqC+4w>G9D3`CqEJee zFxfM7j+`GyPe)snpmOT@uj>aAe*Jmfr z{kM-|3^a`GAep?Ks=7+x+>=ZgF*t=pz5tBsFBBOK#pfReiQPpRJ*3AgWjb7=Pv4=P z-$keFiOf#|6EA=ETyma5G>O(5kl$7h9>dbbTT{-!v76J$_J2_vr^KjYFA(f%3p??vO7Tj7!pJ0vzz9^BNbAQ^S(LQXR!g~r_j9do(2EZC|4jRfbDUy>(pm4HVtOq z?B~JbC4}xPc#_MMlQECs2dO9UDuo-~+3d!nrAC{!u(??xtEDl^C6GEy@L(74{##V( zz2Mb;UGjA0%iJ3dskSoYepnrw-i`fwmmd;DZP0qk+V6(7^z2_J1-~evdi3B@FOxta za&x{!M3i;Fgg?0VYibnBL=P?CBFf*9b@Cw_n{){F(^S{Uee`^X2wz_8j283PR11m- z7AL?%5DYQ!SA?jw3XfkHq)5hWM^+C0YLP;X_bRW~Vp*h0 zG1=tmMMmGVeS|--R?UlSy`PR)&z7dsdEw2jG?T*fD_XYw7<2t$NOG_4!1I!2wJat; znq86~jkI#kxA>aZ#&3+T%nqabTHg0qH}ZT z^KNk`=LzATW2LPWC3H2nhj2=_9AHJuMimDYW4b0_my}AiphWD=eJF!OVArP zb29uaWv~E*MaNy-T#lIj9IhEyNOsHsJ$5`)j5OD0Wq5->zb&G3n&4=T$?M2NR9 zZxaZ>X86(Ad9RL&|5+Vx@TxwPmoG??LGt%g2wK^gXb5hjzO+#WkAe)}HeOt-dfI_R z#w&mBXpWzVs8^QUtGpq&9%m)%RSh!I095>77EJ&EJ`4x^!YA^cyX~CK*8NnJ=7B6p z`E}g_J`fpTG`OPU!~4~&N<#-_8XYKS3@@wCBuK3s0J6CVMraS!+cjeEa-gLs9dJ+Q zBY~EKu)+3VUW}+(VKCi@Hc?n-J!yzZj1LSd8GpU}LF@exK(u*eaDxpa4MT&p{ zL5ipl2!dbThbk59~^ABXMeeFHjd%dsM zS}X2>ni5sK#y}Z`hUlL2dsw`Js{?iJw61*WWVBY|-K3dkZg)?)>K-gqU($~e-1CUx z9%!j{s*N@><&>M1yI~?5FX~d6mr*@8%@FW%?ZD|0%TlD}Qd2e$J#ch#X-e|8c8%H_ zhnORxL!J!n<9|M|4&ZJ?KFew)$!f4;xIn+~?`hay`kJjlSx^P6SF5K!-L^Si2v&rL0dY#hAY{gla|V7klk zN857G7vk-RDb@7~B(t=W18>MqmlGy;PxcQK9|=`+2D62}czYl5@$|ceYU)VeCCfB4 zGu#DXwKBjqjE_}pv!M&QC?kOdkhIlYPx)3v-~s{hH@aO}+gDyn#RepLsJU@2uMEeQ zNtuDc|Mf}Ye~qacgRH>xAnprnxBwIdV%KZf?0cv|D+)O>*&HCiFSCC8fa4pCVdb#Q zV3*;4naGA!D9Aia#9})k4g~_Yv#_^MjLg*dO&qb?n9;>9QI z5vAZr@8C~;5^v(cB{WuOySTsq>m}O$d%-*x3(or=3kK7P{t?pJ8i=8%=1a7`2)l@; zlL9w{rt)j2FmSMr$vKK2#Fe_eA2SFk}mm5__3&oml2k+RYko# z3rVg&xe8wW1w<-(U%qlT=JdF1^ZzqgHuhq#;=%vgtMmV$$AnYzt%sx$6KqH>#2$fJce1Wb7_VywgF~swd?KL z34Mj@$4-ExrGfwVy&**Q3tyUemuMaF*KL?I@vXqwG=Zo`;`{nx!*ivj$tc6Ry-=FS z(R5?W-UwWZ+eqo95bmV2;}28db7fTG4>v&CH}J!>9ho*?;n{1I+_IMwnF(tf4)nXp zmgAbAv*?U_yTh~(Ksl<4)DF+Fwx0(coeS|qxc%H8Z?E-|+SB>5FC>9>LJL)uo|kWHN^0zEV=6kB zjAAcKoH3C#hIfmYoXIE{J2WaamJw=`3cHQ1=)Xu5j$dTTawp3?!P-~MTIE}B>H=~0 zypY&z@0_X+xqgHwS9535mf&qEkyLF)ute%h0PI2m#p*cs4>6lcTawFl(ftr68*UWN zJdOT%pW%rtMHS|{J8B!F>wew{!P;OLVjdegy9{aRS~Nbpz^cP4Fm{k_Zixx;E56tY zNHeX(4nxJG<_T`T_pB9YuEblHXBiVcAvTOgEf$>06%8B*q#mz114vb+1tr z=y9QkQwqo&aov?HBf&43&&@#uS%+0-b^lm z@5105yG#mJGN5quNV4*l`WeF=3OB`>?bNRHMssj~a{b5rM^w*4DEBFzhkn$eDg0da z)jy7yB6bTUa-v}IE2dIae}x<_1_6{Dh@GEt9Q(nlRRJyV? zUTm9msYmE;*hIL!wBQ}m&Z(GkKiQB=_otF=%}!YJ#Aq7YqBkm(AE z;+Rd=-RYI9gg(>cv8~ru3&+X+v{vtTtd)}~N|FQn`LPQmy;N*W;z#N2-$rNp zLX9%%u|bUJ{S|Jbchmg$YV5Hv4xN)xK}A;-!>hb^T%ac|ME*&-2N+>kX2&BW60P~l zUI{3K4okV_aVmUq1Hha^k-mK?(&-#!QPNC;H%{%COOM)7UR#eql{chY0Vtt^t_ajY zU4S-%Q+i^tLq3m? zf2P92b2;Gf>QjxILG4MStS#7$cTa9V08=pPFUXO5B4V>z;G(zteaI0u?)v=#S;{K` zJp||MidX8-TG43^m)|#~7@qirj=tYDR66R7ILX=JmNn4U-^UKaYbD}|qV`*ZR+S&-)o9-VOb~>v z5|}k+kBBS@H80K^c+86cwSQkk=x;t{`?Ko05RNs!e@jB+lbzBkXA2+WKYFKd*Eh2g zXYHSFH7SehzW;F*O}jgKvOn41^C9bYyR5fmQx=21pj$G}M?Ppu$)tPwo8rHl;a;zJ>H>A?ZRtZtw< zOBzizJ#UIg*EVNtE3V@BR&}U*&J^nyWz(nPJNGP(B=yJLc<*E@n@K9=YgJ`(-N}8d zo$xi6Uw-*+bFdhg=Z?Fb9gM@VtoZPAh?~i?okE2#74DyAUDn^A_J8OrsRMrua-^^0 zGzl&`)=}($2lytXE7LnJv&%yZ)Nyz^p1K1Anu-_l0UsEjAj?G))k?wVNd#*$#*Is; zqId{anL_=`cNy`yQ9IVJSt!jt1s*K{ ze>}!>9me4wr1sOk#_%=YwJ+1=)4#t9-s3^*Q`u-e=(LKad7^dc!N&+VqYKiD8^sa= zA7&u<#0sr^sveGGEx|(tZk8g_{oXNMyYBW5|6}=yhoR4w&7DW_E331XVo6~|XDJ!& zuFf~VcCS@CQtN-%*!FYJM@j7;#K-HMbXk%cDA3?DZ5UL zEiMyz;lo1ed%w9E7j^Sc-z7R+rmDEiUd85t`iwbun$i?1`w5^;!Z~LfYfOAOZ^Nz6 zJ($l$J{j^ax4|;GGc_|X>t?NG3Rgqc&&uS7Dy$&m1zX8Sfb>rjV-zm0?3Uw^mfsbe zR;=%_mI>SJ9j>PgE{ZDMLI6DgoT0XFl5!SXSwSw@# z?;-Vo8@dd9D>4EkyR}UY?#FcdA<^e)(csi5)SbIj0a2edW4PcTna~?o;2?~(g~lm^ z(5S&B8Sls|_bFXu@4XE0h=kpI$0f;sp$#uPmce{xtiqOodsg_8C0QSkk9dVoB-?`* zjY1OT%S*z)XuKv|`Jl|?)! zF@B&UzCAjzo?U`hCgC$KfpQriO$s9EcEip;ok!5PZqqH)wW+gLk6D z(a0=uI5d6jqSAQDfptE{c_>49KkeOY#skX;L61xi=5%ci9(n!D{io?V-mI4znROy# z0|Y`)t|52%AosSgcV(G>w#H$%AesPs-fKJ3G~9- zD^7di9eqf7>woc%UI;p-|Fk{-?}Bc&mHS}PdBRk){$oizdmujc|qnkEHdIisp}UReV&)|UVa{2`7GdL`>~r|c)OrJ zqeExw;c~<3+~7jhThFNCed>yK|I4?-zYXm3c1Uh)gIasoFV5D&)U`d&+pT!x%`EFmdE<_5QR9e zZ#WHV^&X?Zgs2=}e%wU@iH3e81v)2BXshzaTZKhjQ;tx^N7*rS8Ld#6&w$oYJUX?luuN#tS(aL03j!pehv6AxQHy#f@j}l8^a0^5^r-Cv z>zh^Yvy@rjV-f>iV0|UvGh?3u)4*x549!iAOL--}^M)j!H4?4*v~!xi{2{t6N0{8; zN-IoOVv3Y;^8boJTM4$Lcn?hKUP9-5V~iB`*AX?6k9nY@UosHWOe0vN#g7ooQ2L4x zY=@9N<0*p9!DCmk8chjOIf=@+YtKJ5m1Fw?L_RhQvEG~Y$k}UimjCUsJCUF+*l8l7 z^<%|Q-uR|jDSC{y<+3pN#+A6oB}RnoD+(}N-IaAXB@(;-v56*U{WYIdAjdC)ps0Y^ zKs;vl{vbkNy@o$7A1t8fB)9Fas4uE>ozFuseTM(@3yM?OxKil%72!n2CbKEU0dCKa zW5Q3n-}@HAV=BGcF-`Qs@Rad2NwRRfk5KNn?v$w^Q?Ng15tGJO@|>m6Rgiqtz2i(t z{Z&NpG33a&E(58XB3Q{zi7qD=d6%F&Srg-gDbGYXV-(E@@zoi9qPtf;u6ng#%ja}) zLhUu@233=yRFbEgwen)*u5WRNx2jnbx=lK_ye4fMs8u@h(OyiSTtG;{o=)KmHP)K; zVtuyPe!ssp`-t?^Z2v%OYj8|otzuErU!*pC=bSFW`R7aOO~>I1^zG^~8LTDiw-uFH zC3E!F1>URf0Bz%rluqQ+)n5gl{d$~SB%U27sP?ORH}jAzN-oaUNNaJ`fpHp7j%qQ} zp)*KJV?TbkNEuZ;zvHm$923{-@=hlwbbV1JI^KR()QZp#NjUmZy>D~j9gUgrkiFA` zh=;qZGwO6ow_FvbfJ>=2aR&;@$OWWUyJ{IOm(uQ(ZmB_ZnLaXXw^0aKoIZ6P;?jG6 z?z++5NZPps(6(DBZ*x zM&+E#!mQk>qp_MsG+$QqMpV|0MJLx`obAztE%qbsA+!}pD*aIn&I|9TQ3W5{zr3R- z|HgZT^v4WrFTA6Z6@rQvcyIVgddY=%R9Ao8>;mttG@v(R-bBxW} zNmj??W62QjV%zIFa7qe6sYm*guAEGbpOAKt5FNl6ZEwgtKatM*Cv_P^KR+(l0GM239 zr?x~=ax`p02rv+>Hyp#Uf{B%LW}&5Q)ZpwuUKeuCET`|+U|q_Cin9;FDIy6ByyFmY zNPj*!0L+{t4Hd*t)CM@*VrfB=TX}CFv3+2t@`f1Djs+5?{!y`CWFaA3F6VQLC{{1r zh7g%v0X_5e)XlT$hG9y|xw%QDUT}$dfJB3OY!Y9Sm#8@qR18`l>mtm#uX`s%%J9{ z!+6j!PL(|idOFKp>HVJT?bKXI!9c|q?7Io4$&>chtbe`)I2mqcP+;3Ua0Itz+t?^! zC6H@QEu-L{&3W6>HZ16-Utx(YQP>5psW%XqpZ^MkR{}-*`C^;MTm0h8Jz$DsAg2T> zKAO`tG33drq~<75nS)GKCt<{X+q`16Y0(iB_EEPp3s_?tqwuJ`X?Slf?LqTcxkN*j z3F|uO^jnLcGo>>n&U{hy%D~fBKXs}}Kp?T>9C;lh{3yzMMi_FX6R-UdNXC00zsdC} z5y8x^c@U|UPUJ;LIA zBUY?1w;3Uu9!=+r(p7Dl*_Ct5?y>cM^lN>X^LuorGQ^X$V)CQIE|D@ame#5ZHR4~V za25x#rRjfeYc0u?)d2N7U!6Nh(r|i8ws*9%tjz6gx+ihpDK><&_op_zkL$j-@z1ll z6KMNzC)!Rx+>rB*pNu9FiekRefsAb2!HM3EP`S&F4xxc2PKy?s zvALa<@FrUWcN8R(4_*G!@;f^D<~j3;KfsW36$L8vUlIE!yz5nPgo$)-|Znk-7ZKjkudL7wOU|`D@_7uAiKLBKT1Xz-B%a84)Sv|{zaC*)F7Gy>l08IhHPt6fgXofJ0Q0bSEdwSVIBV@ zG`=z?{#i$S%}RXTX?z2FLX%QLi*-UI(b?-m8z`i~~F|h^$B;+&NvbGaX_IQ4C9yML|LusP17HFX*xm9J3|n!ABC#|1pzO zpBi1%zbde)`Vq4YaK!-FRs-EXUVuL?i-kc{)E#gZ$%0|CF7q=4hB3Q)X9>x`4>3tl zQv}L}`*1T=CLr5WnK67U8?u!>?7~gpU?PE%SdMcJoz*YOzwT=!Q}t&$>RDH5LQ|ces0e2E{u7> zyHLOsPPPF;0DAB?b;%~RKa%M~9OFUfMUiFE7mnhuB23YMGAjj~7?~k(3{9FTrkX8C zj|8T_B1}18Wf(ySCrBHYx8h7Kt$gV_IS**OSTRinsO(A=kOkz!Q1I{4moCJ71tuL@ zN+q&ZsI&zWjiauKl;M-1u9?Xg($6d=G3m@e?Dhbcl1$nFnnPR)b!mwr1Kpu?0o;`C zqM;kzUlGum!e*MSvsHn!Wqjlf%RbdeR7S(6!~8PhH9G}8jAcbeV_t&X|Mr!JXZSU6j61)nOcKW0~p{*N6?T+>I-;q zMF}9yz>`6UdNOr#UlpDM6tW55R08b!s&ZBVEE)Rny-DzUYw8Y&X&=Ow zw!NXYce7T>2hvVP4C>WB2330YA$pOtJ!Ayj0IID`2fGdo662NX$11+1NQ5VMC)OuRL*lW#F8SC2*A$w6u7Xy zk+lmxwYQ-N z=Mw}8fAJ_a^pN4_HZ4v#L~kT*7eEH`YpL^VW!LI@oN0Ud5VC6k$gnmEM^*3KKoQwM z-PHh&s$CneeWL=5HP9Iv0`9p_z>Ux*5Zy{c8B~V$I|czY&FhGJR-QmNvzgb#3923g z!lh{&5=sSa0b+P1wQ1$bCX)*Y@lRO!Kn^?|beS~MNkOK*ev7>xUk*R0BAE8fCX|Q$ zM!?tL^+!+W7@}6sA&+W8AaAsZf$Si?NZgsbg@p*P{T^y1ZS9DB(r7utV>A4hiP+?NHekM|{<(E(j4wdT@{2EaY%{)e4(7Ko>) zPGCyE^Gzo`rz#NT-2WC==q3hCH}w7eg{0~3V-yDhIYiAk>3<)<4jbyD0D3bf{t^JTz`uK3E#-enQjx^QRs-f_PJQ1I~epO%wcd1DX znAmtuftwWZne0^sTDd@zcEF>O((jw4U0k3nP}xKxow!OF(3LmS&7{%rtOiuD6;_@Y z-jjQfUjj_lx z;TmDV*;aRGv?oK?*yMGnFk7F7Qk(K23O>ZX(90RL*uKG zhFw%<@rkqyqCJsGA$<#w(v+S}*gN6J$)g1**ro<3s_Py5~!ilf#L0``n<%%CtM7@M`7C$KLr*S0^j&rY>qOU|Uj2 zAS0(uIAuAy9@ARchgjtXsURjGTT-r7X&-B6&X!WNgT0a;8*5C@30k^RMnOL%5Fsen zVSV5<=0!BoQb!shR67H~LT?>G7)&d2B>*oU!2cOwX$y>V>{2wq4;zx!MQ7~rRM(0| zbC4ro29=xl0hjS78n~?L_`(z8XJMa4c0YBZI-lj7H_$(+8C3f?NQuqb>g!H+o&eit z&3&Wty9($uq*U8VP;RN=S;kk`OM@@=`>&;_B#_cTUvdlW!}|djo(;i1jj(|;&lh~w zxHtt^N2D&oZHvXZ=}U`ND|+8$I08E41B!-&+P}M%q90P~vM8~KlrD#b6iMkNhuz75 zv*e7MB%s?vH;2AblArlU38*X?vK0l0k;8Bo+CvN#bar6!7UW^W_$7wTw@Bllybp%m zgVd(GUf0*Ms1Z@pYp)qWb~96Rko+;)>DS%q#60?xH&YPPvS@=Y5kyzD@+H+U80$6Q zxiX*;_k1TYy&93fKhxPnrst|-N(l#w&W{l6?_q_9`KOZGj_WOV-Vj9NUZwCbFz5k` zia@at&^#O{{c}gp@ixr!R*lemTl^dkUF9Vd)VR;|+z{IOt(>Z~AZc#Ucdg)*{b)7} z(0wh8Em$cjm|-^U!=?bG@7gJ6i+(?Y4;uqP4R5KA3!PFP3)T!Z8w2-vlAO=$qu&6; z7dAxTLfoe{7G{l@_kmMC8yX7aI0N{%0QuFAn#~_z)DKAN(uqTxm&wb@FSL59YyEp_ zID<0^=d%Mw`dlX<{}oVp4fu6>21os(#QuW0{DK`rt4v-7hMz`VPD*$&6!GOZxDhVa zy-czxqUEIjSesJs{GHyED&qXbu9y+9Q9t3$MDOu%(KTE!ym_B{`zSvczHgtmk4&E^ zcz*BK6qntlOZCUxwvY+?DNsNqZyN|oY5k09sswBHJyt?a7-FYx1}j}`hL~>aB=e|0 zupf#Z}vowFBR<1~*#U0ea`8KUYv)|N7XO01X` z4SlVw_A`qjo~K?M;Ms8&DXV8%HjL<}{Sp==xq!eJcq+de+XEXmKbI2xu-qHlpQGD# z_zZB7CaeARSjSBFv^kfto~OD z-%4P=#@1an?j1Y+N_@T2gVnZAcE9|(kn{*D)xLsdnn!HciXy`9jB%G5KAl#HrqwjM zsL?(6+yxr=?T0#-oHd$sbpZgN07k?vS%{3?NAXj%h$Watt z8rHCtHW5B&qX($ROY0#CO}+}yOOw{rnoC@ypEX`rm3Mugku(j&v6u+2Qci&6 zTwcBr^vsW@pL`at%)?t732>{g-&cGSHdv)tK|Ee;=X^js{@Li3&J&7>rn3z} z5esW)HweSfFFOSL>z$jht*@tU4{q=4IT7fdi8y=kbOj88lnj?kRGN4sxE)cy%GL<( zVqWK5XAm=CAx^1hdQ(9SQBMrLcn|gxr4}bSr&>4y&C8WNl(#RY%^kx0v0v^QRea^9 z(5|pDz)D6MIZ|(w=iGcZ3dcE??qq5lBrcQ`EAhn7gZM5Xsf|+uMI%eg@E@PmFkU9a zO^t}&qT{RV_&T_fC@DPJQ}8!o1thuSm2fQv+j0F7!`o4k*HYEC6f zAH3FI(@kuoR|$0odN+}JUd@2s$4cGrTcnS%=vI)go2`#tGkd}a;ZcW7TPG?>8 zh$I>NMUNI7G-?UXQQtO!P>bOx(v;=snV_hJbF~wa)gM~Eq);M%8xCPvGbEEk(+3E8 zkojv&1M?6B#tmz-fbaFBjKGN-_Kz8m%xHKHSpPDOE2O!FXxT3VpJW|i)Bkp0)&FZ) z!{1#!$+!Qm+ZL?=YL3U4^P=VYG#VR$9o!9)y_@opm5&Ate+KP?Ps@<_2TV&rpeNU= zeFY2=DB;bO16moMB+=Uf*FsnzEGGz1Se+i9xxb-SXAQbB>t@dm5$D2x?y`bzl&>W) zUjdDDugKD*jj@*n7RlRh!$5|w)$=s+ABTsdkNx^G4P!WP#tPcU@N1$Qt|)HvVphP>yS zhELI<{(gik)4rc`iDpMT?)@smu*ZbFl_3nqTLJnp<@F-Avl?xk_missH7~v^AhLlr}!LIGh5#_WVMOReu(z?cpYP<99;~ERd zUNIuXl}sj^ebR`mP}-Y?5pY3Hq_%0i?&1l{izz<6jdLU;&P#(Sp+l78XM$R(WN@u_ zfg7l!K~&IvOZ3Ldbx=veGjU9mXjb($OH(BDnd?Qqoj7T~7fck!u+Uta9#doS1}ukl zRi529m3y*XQ>k6f+2suVGH~2%>R--Qv+`1?>K1U)T{-H0Hmv9s#QWY~CA61d`mnZ@ z$}J;Y=`9FwbzsiJHjC9E%!U$x+IlZ$4(UZNlQJhc4+EjYIp~&Wt7CuH?W1r;sgswZ z2&2XozI4Z&B{^Mx3todz4ffFzr}E1@`*PsV!OVH*!6iJ zS7Ey*$q(wyHJ7%uqSzKdz zkLuLxJ6;L}1YUF6o~V;nxf}gMn&&{Sdtm_MTU>bT8NDeDvV(`n@>2M>3AnQ}?DcLX;0%MEvGVjw$Tp5!> zwM4Bc*85qe`9lC`x%Kfn2uENsiB8iqP-2z4PS2;0%Vf()vn07=X~I1<7z<7+8vfol z(+i!`vGCA~R_gx}`xDH}cr7^D>nMEB_g){fJy{odi>J0b7|Gq1?4#tWSMv9dB0+qN z4W-Xd>sg7FYoxcmi>8gr8RK&w&VBXs{3>_xC6^Bm-x^G_?&x&-4DG49-CaYzORu>6 zOy@^K(i9tnX>qSd2Hgwj3Oljeek=|Sv+D!(z2P6b+$+uM#kHUq@g3TD_<>jo|L`o^ zrDQb%RKLDX$a%rPm;K^$bjZT0JESWs(bDs9b=rOuw&cYrrQ;k)s)SNwl3LTENnN^2|IZ+X zxk0^BOE-uX_Xn;BXr~-$Vm^{2Fxof%kfb){BT`=`9}Qj$ZHL>W44n;{whU>b1@dK+ zE!Y#Jl_177OzK`b$pDQy0P#d8XzFR$E$EB@1Sve_t&L%Pclz8hp^@nCPsSc-}J6 zH8jz^Fj2}}ap&WN%AbiI=E;8a0 zHZ-v_IsI+&6=Z6Ld1@9tH77SUuQjz`F$G$gTnw68jxnB{oLs4xTI=TG7lt-&kR$-; z>lWj}@u~BPA>+4yrrya-zv3p;tLUOYgr$uMqdmnOyyOB$Od;BMFVSFl==$>l%G4TN zlwM4%+VpYI_%4L-HG&Uqohe{V>TA*bN;@gh7qizT@?ishD)&lX&E%Au<_&di(k2h- zS-Ppu2&W9esN|KZ4B>3U;Jju+dNih_g^5aH@Jb(q+Ary%IMk>FV$Pj#bwV-#jr+Yr zCkuws)-tF!K+K$HGxrP);VL$xI$~;+W=H+vai)cLOim*B)Hk9Hzcp$fL8NTqyK-~i z7P?gDO&CAT?rvy(-hx|z3{sqlUN|j(xmWx|lK7MfOMK!Jark)T2xp_xXp`BVsjjNX z)$^xnNq(UDnuror?|H?ZDqxmm*3kDhT1s_Gy^U!WMyV^JZF=Bc=Wdf^&z->Ml`hDq zlH^ksMuw{XDJ9}91PKe@ca8^wr0t;)lAruG#4b)1_>?9hx;}_ut;d$0jI1SU$owGu%A_Y zpT*@nl(GXc1x-vJ)VNbN&BmE%B#0y*<3T}uwMUE@ax7srs!J8M@|*bvnZ4-TL>~S~ zzp`rH(%|(dr;T}8jdfR|xhnOlO3OTPCPqijh=V{{)f6|iegyE)RL;W#K9v%rt3afQ z%bFym##KIzs(UZNEHvkI8T4w zAXKrKknr8&$n_=(Ya}L91g>V`@`^xSB!$`~OD9N1u754CcK(N;^%aVPUy!?Sx*dW+R$3A)uKb02npazBGA3pM93oi6ENmeh*|}3}P_icboxYr}ROcrX8=_)E?u(#LO65@rD82*+SUz8n z0Gs4i(oA%IG|Z4>C1{f`;p|e{lP?V-o^LG&8N}$%KnySt6Rra7Q?7hrW`lVRiNvQ; z7zagZGwEL@WHNuxwrkCvArb?wtJHh3&CLJLyRO%yb0MXKA9CB=-9Sj#Rks!T_X+)W z@qO&R9WGU|j$RF~D3`a(u4=xHP0Z|hb&t*RQ=6j=)drD-fxEwNst&43-r}!OfZ3UxB%?^SU@2&Nb`wc5I%(b1>7H zYTtV{!rxmLz4s7<-%!|j`;{oIN~!Xr-Z>^#HuLa<-nxIE1`{i`3otW1Lp#S*belbfUFnESw=KBO+laQ(RC`4 zrOV}BE){@1vG9#0KX+==t_RdT!=C5iaoCy7gEIX*tQC60whh%OSjhj^kBC)3Qm6f{TbDIk^*mJZwUAuLCb$?E~tnl1oJcVEld8Lshji0-4*6=|I*uI!x|1P#2QpWwuC=x9; zj%|X|GJ3^&6HbNgk6As~xyRSbb}Xmccc(Tkk@9Bn6=aB`W&R zm{piaj8P7x7l_rz{4j$1lG#f;qtjx=np{I@4F|B%k*gfsH%)pIVhc<8uqYfH(q+r2 zO&1^+P{krZRPKkdddxn~XUrRjExJPD!>P!}F$I~pWWU=AB5No`!RgM^q8dWjb%#X^ za;!S!6iXP8$c%I4$XET;SV@h*4R>hn-58#KNOcl$^}H3;ag(XsKwBbQ1d~9(xh-vx zWS6&Zdz&Dg(Yn8G&@>j}97(3GddWYlE#AXJ0{oIUdCoj6uhU0bZ~p)(Nn6#1ja%wQ zfH_^vD(vzbFkeXOOazUUtCq5y_gvdpTX2X&hY-e-=&~ z6&_7$g}FQq%6;1Sin`gvFLsC2DFxSQ5d^={YLkobRKkL6TZs6|J}X|b*B{V~dTe~e z2Wl#c)-wb}4OTXsG`h;Dxy9#Tk!L`4`A@{skW0$xpZOH87o7h{b(+S!DrORoOV80N zmfg;p(K<&7iRKFvB|{PY@Ggl->r}%kWWlb5aSdts;C51dwM*S=kQZ$ZXLsf(f)b?Y?AU-R5% zra@-d@{*md&G%Rq9t9f{km3F=k56bNZ%YS+Me#0e?&gOXI*F((uQ2wTQw7@db$-7U zK5sk^`KmB+kTG$kCiY%gizf{hnP=Te4T6x!A9zrW&zY9#s;!F34j)LyY%)t2py_92 z-z$?rmMzlzdk)Ws{x#9fJx5FadVv)9yDGvkD!FAucoPC)2{lwAcYM=UTGaZjK9sERjs(0$0{FQNTuAOeSy$Hbv1Ors4i@_BWQ~b zTf}Cr_0xgzqjAvZ_O~qTkrB55EYa)3UlxmmB!i)4{*QMpstg$nzCn8#wcB4_9$4Au z4!L=QDY;dfgJDV~7-EkH<$PP6Emim{=8UJSd(4dW-w`lH<}qqLi8;UGVzi#Ey@h_l z<)LCThozQ~n;m4h)hdI%N8Xs>SdWP&87i`6Trq%5aa&DN%((Mgs@Qz@@>B0>$;{C> zUj+sbPWNvvUVF%1BXelI3fP4^K(qbC4IyJH1ml?Ob)MtuV&`=vD@KW=KYXjMBl)I} zZkCN~s$0${&gD(U*9WZwwxvk&EV4C6HX>O%+=s+UOP6zmkKTIb0z=1WPZidrvv(eGk4 zke+<*Co3EUF70_?wBcAzM$ts($l8)=(=Y2*f5h4Ql!MEJtq~YVy9E|zfR6gZHUGyx zsIuD>?DYuYY&zVYP0I)olrA9sv}Fb9zc+Rx%Ni(I%ZO{pzjC`8GzOwkO8r)Q$%}ET z)CP?1iIXNhT&x_nuq1Vci`U(VrNLAQr+0*tHSQErNAgOxH`&Oe?>PGEaR%HFb+mbs z$QUrmq4{(~{e;1Kq%4WS+7yw}{qAnrzea|p8Oq&YW;@WpWouOY#;KUSEqk_BT?r8l zLcz0qO*Gf!)%QBwY4l2xdMZhc8T*I!H5VWB+9IjvRuCV)NNQau z(V}7^82>fj_{yHqQF%y@qbr=?kxI|(AYdkd}FXlAWWCeH*GQ*2IT6s=y5`!%lbe_tX^(dtRNsq zB0eC&DZ|K0!0cI&aH_n!->6zg4!c9o`LMhXEk^xdHkS|5C)3S&%f{{T(AAUH`UgZN zJYG27tXqt>-s{PMS2T}hqy|%-HN^Oq)uY=ke5svVWPuTW25~PejcMcn^8lqmEb&rv zs|c^pSAO{q$}<>DiIbgV)6CyU2*0NrPVQMFjisofXUiJ__a_TUBAT} zAgK$$pC1}8Rt~@1ms&`$Q>x-TpL1AK^zTP_YFQfq?( z4fw$o@|LYA(mg+ho!mAFWHdf>t;spsPFc7zB1aK3K-6G z|16%M^mTkXbm>a*x#+%r^kha+oin8VOVlz0cUw_&Wz7QzwiyecuVpx zZDHWzT_?{?QO9K(vi4T#TzhckF3NpW7F39L)xDSwCa?<7Ml~$)MZ(g(=T*7q|GKn% za=6ynC{dNv@gw>A)J0_}-Fke+ghG)qU}O>fX0$RulbZtXQj?4{xZ^bs5Bz*fp@IRL z61U9hDtmv~&WX*F6GIJ-OHtLl&y=fG1ZJ{m;23(->lIU|GK>Fj0Bk^$zk4SGX%g9Z zTs*FCVT61p-Ns&EXE}6592L1s){RCg-Vj<&TNs6C`W_MvPa7A)I#;*bN=Qy}s1l^v z7aCeLzG2^qXeO?pncPIcT9hpeBdu{whaDx-_PAo>5OiHlI@}HoxZ7AVer64>=x+B| z<(<-wf4rc+@QPJWzVbd30wn)ZQTb9#6!N0!-4%)wgdsRVJ;US8wheZhcdfm6yJ1i@ zpmT?rcSHzt*n=V4y@$0639@Dpi0^HKb9Vpr411W0S%h#0ssF`i?f%1FFGYv7*QWQ1 z-NUIv7lu9Ln2L3vzWs178an);`vI`NXxxDPxY%C&bKe8=L-z%-y#IDRx#sqTkKJJz zgroRD;~`|9ZWw_c9765|$00;tssx}*cv1iq!69%ClN8_qdY%PdAh8I+7r21}VqilI z0TXyZ6coj~0GkJPj=<~@USN?~912m`h7mlI|D7NWipB~eUky&$4d!5P7(pEf3GsDA z+3>~}EYlzr%NINhD|G)L4>q9_J|Pr#P8M_)6;46viN<=2Rutj}?C}vDOajDp#2icl zAkfAxG?z^^i1}^d1%6=|vLWcWAsoiVl_gh5z|6wX#x0;Bh6rG=+(DjHLp03O92TM> z9%2q+L1;|@6D$D^#>Eg!K^7pQXncV)Y+VkfLNqwTctr~(ej+G_Vr_uJCOX3|oD*&A zK{S9@ZLHWP8iVbCjuB|WE;xfT;FBokqAu)TAC%W zlw0j70wrjrON2)jC;<>S0cTY~Nm{|JF+p5*M0iX=5)8o-Xwnjd zQee7763nI+;H7&g!Ejz-ZdidP(WVx(k`_UfM-@nf6_iU*&SwA|L1&?)CM9187HDobfmbHzf(8q87(o-9 z5TF2jUr-W3gnC8C+nf8T(&5F?q!SSXiuIC zCcOWG%b})3Ou-dAqJerAK^#F9U{Z!+)_RN}P5I78+9ym>=@3N6aMq)D2+tG*flJEg zQz}7~LPuwPCwxNXbIeBQF+*9Civ{DW%g^qZstrrrt#D(oQ5aCy4J(aE4CtRt>x>) z0;I(rEU`&!yc%0mQtV%TCdV>Nm%2-zMy$ey+rM_Hfw-%|k`}r8>u3tWsJQ{K?xPV5 z51V#Y7BFi^yeU5N+7t{y5CG^Ecw~1nrFagfX+_5rW`TY3Dru!2cfM(UDy3W=0TB>E zt|4l=N(X$V)?TJ+pDLxN(rRhBUaz_*cf6{fiYD-g?A69CNRDUN=0~rV>ZLZSt4=6` z%58npEv|wsPO5FwS}Ld#YVO=^tHP>!Qmx>YZLHdAdaP}&MQ*2lZR0L%tv>(m)XJ)% z{wTPtt*Cx#+mb1t+H2y{pd+w?w%x2f8o{*&0BvHy5cF)awk$zFYe!(g6?j1vlnW*m zY{}kZhIYhyT*0;mKo(R1MMCV!rk=f^>xr)26+#CUtigR$Z@?BWz>;9Ys;u}*FTHvz z>_V^K5--FSuf51?j0WbtmhX?+>-fg(>d7zrl9KzrEB%u1{CclwYOKd5EdHWz0K+T* zZ)|z$qxlYG0|%s8h^(#}>~fj!|E_QPLa)GL@Bz zX%#$Z00e<~NM(Uo?esK65b&Ds_|EX6>I;LgYYk^fHfwlrfpkQ{CT0Jydb+9*)Mjo- zK@*f75U?v1cv2AiFb^Yfq((5P=4ts-t;#;--a;il9F+W2y{m@vIJN1dnmU&L>c+79A@j7vr(m zp0Ta^s?sX**S4|f)}Ro0!Yfz{bWq3ZG^Ffm>FF^mW{&AZ1VI*vpz;K#7YuLwrt9%a z#1i-#ntq27v*cg;D)jR1ZO8|GIDyu3t;<3%0P|~*a_=1DBfi2fjef7YDzj^?FUA6? z{c7+m`*JdO>@`m?`C9XD`einU>~i%o7Nc{(>g6_bFd?_IIS>D^81v}Eo)$FU=>os+ z1hcFoI-wrZ24{4@Wav=|LBp2oCZuCh9 zCETX$os#XX_Aw#*v_ao*dekjAAGK4T@#OmPp@Q&sMzbOJEme21FC#7^?=h!dE=q6e zRonCzQ*y0cv1K;yG@CVj-t?%xXAQRQAZ)=G(Dfv^j7uSKQ64oJZ#5WivBN^{CeQKcN{1dN=1wPa*@iV%FQrdDG8!AWP3QDl z|8yYBabFHDO`|Rzr!#&G_j!_PX)W@vx;2Mj)_}V;O^dZoV=^*(ZRdL6A4~!zxVVd} z+9>;D5X|lrP5~5DL0|tcaS{Z8RsjxL>yuh$d6fT)`(|hrukS9G>=1yZ1uN(k?C*M- zl4gQm#%8v0*EVP;ux%grJR`9{S932Hw`+g!ZF8@omE-Qyt5`5NJ zE@F6?houYga7IBEz$J%z2Y{}$TWWe|Euu-MbxB7mXLS~uZW~uFVybt#>3X#x$9Jht zDA_)0pyqcO8+Gcw^`@@)+mh_xesLZXb>;>*TsL@9GH_G>`m!e~uTM37K6{|w@qweN zwx9GQ%kYY)bV`4FS_f`a6ZLPZb;G2)wJZOzoqjvw-ukIRIBlfo<2fZHxDHF3V{^WX zjzj509D!mN{1P~z5k$f7e&rNk_qPne?=pd~8E3&SHg;R)l0$5HmI`Z0D3QG_u0qMns z6A-Ooa!1wt!xsN8W;yd8ubg*VPg<>sy zgKtmwwCQ#ZzRNvWlOR$*zN9as69oS+6d)%eruJ-Wy&7X{Ic8=ul72a^c}{Mt(ICWRCnJ?d`^ihZlbpbQUE+oM6#XMQs2pRkSeCqNT7@`AhQtUQWF>c!SOP;;*3Q z?!pMbwFn!JpaT8U&!Yqf8tgIM{@Mw`0sV_`F2>v&bcEI6i`7W9n!HQ<)BLOv;0j1kWf3GkVH9EUhflOpd0w!idwfh(e$vsu)6``LblPIv|38ZwLraoUl&G zfS`hiF81s5KM8M3%tJCmd<#*xL_8GG3LmY|L`bRYlhGeJbX3s=MGR~@=uSNJQ4K5Q z?L$ZX1QpN$CHoP}QY8g(!AVV}Fw`AsWouVdMFln0<^1Eb(@|L^DA*7QJQl-OiFIq) zGpViCqAR8#Xb2|)z*Zpi2Ewt*TbJ-6i|c&*?n>sKAfgG}vg0q_45cg1K`OsHY&%}# zg?Ha|l{Ic&Fh~DI*Wc#?9+*pd`%U;?6BSO^;4B+HxL%4MzB99YRjnA~?ADz(qI?x2 zc_oo8)>z&B;59Mii%FIZ;X)mrnB$u3of%_mdF~k^BjOWC3HV&}HcNtV{PH0noVenO zA-Gs#PwgfZ_`@TJAmRvMM{4!4PhIVh*}NFm3+zkr4OKhFFkV|Nb>Syw{eBZ4Gf6L}^Al zShoFCd-A*FzHIQu+rHK8$Whna=h=NW!V5P8kPnL?vM?I50E)QricR0jg0#_YUlZ02 zxgCm%HJ<-)7~qzDTln5hd&_x5?z+s>dugry9yqGV7c+c_(O+I;*AdbgeWaMuKC<$u zKEL|u)$f>n>eKIk=R#4o8t{oPB03`wqwqzPm5r%>0fZRL%r`%MeNTcNyBO^-=rbp@ zNg!3I!nb_%r#WdsYzr~M7233|B*5oIs)CLbn&1Spw2KP)+ncZmwlq7XZGRXNTZ!-| z!baf_b|vJMs}|S8zr?OFvU`?b7`H^d6v$ZhL*fuaS10h1%1(sCAr!ZmtA#}>Kf(%_ z5p5_$7Z#_9QoJD)H%2D4T`^jgOJWe`m_a@E%yzg7nn1jj9dS`430}z7K!z}%_GED& zTX_Fo46&v){RPp1H|#O_geyc`)qQi&VJe@xdr)aH4+JvGNv|ydAXTz9J zjl33%7Of{$#a1~g3NEYs*(euFCdIc|(Tlyst#0ueUCjjHc84Vm6!;2Q6Unq7Y8irP zu<2bdJZ&H`(k^8SvIQh0%9#MKBJn?s;hOzYI#Zq zXqYGSE0>9mwI7XVo#AX`l0MGKTRw4$5zQ06Di0w?5Y3~J_f3H$GK32&GiPPrqA(MF;p64Y3`|*6f|{yi@)!V@T3`>S62l*R*nb(gUr_&t^@6V!r2{L; z>aQ9oZ>z5GFimXiX2#idvrHeWP+F`kk2*jXDYTm)EEs1Iyn2fGFw7c!1Lh2n#efze# zyxBMAupM!$IH3w&fC9HtG_DEPH>L2Ec$73wJ8M5_T$=LUOdjocvNLnUZ#p;n(J69iCb-xN1TpMdLS7qZBc19B`t+z( zPVI4*yy{)|`nSFwcCnA0>}5Cm+0mYMwXdD+ZFl?I;U0In&z=A7b+`N7@t$|RduZ={ z_xs-gA9%qJp74b?{NWLwc*QTC@polr;~^h;$xj|LM;YTq^j5$nrxu4icjs+=&PK|Q zp7eHaRY#(pl!^B8(5TiD%1@0}p}Mp6&CYu1ai9CDr+#FfuS&vYRTiKRy>Si&=BjWm zK;Y}1`ORl}=8@F#rYMajQ&nK8zq-b}T=XmBWp z!47A*t`GSz#8Ze*^Wcc+Y7dUOj|7RZ2xmg0IERs}Zs^Q;jVwNVgbhNyb$6#?!0 z?#ULX=ltBpR~jsI=CJ-`ai@5QQ);EkzObW!!w|Re9`SL=?(m7wYuKQv38Rn-CCCbs zkx6omdcNcei;aRTXi=hZ3O#P;FhU&ju_8k;f|#omtE{A2FBRqQ&FJp{S7)tM@B&@2 z2I=lFo#Nl*t=`N{xc={=T&XE*vVflQE5Wk&C=#zwj<%#SEYUJ8Mr@-G21Fa>ik3A66(vM>=dG1u-e6|*rN z^D!YaG9}aS7;`c$^D?!OE58m2o*=R?^E1tEEFEq$lE4U_PV5RRD5QW0bP6oP6@OfH+e^LD_RW66p${Ksblf zARN>)BVvPmb0e1XK1CEI4)h^T^V$ClVh#F}Ls2gP1e8I$ODJ>j5+~A5Xlg>S4kd0B z?5^TO4We9H2qJ=~L*7qc=2IA79U<#suJ)s~AvH(7q zz)$^@Ai6?OZG*ujbKjoluZMmPyaMN1T{znB0cC7M;pRNPXh{;jtMT# zB3cAf3H4IF)F7MyRHr~xA=E>S092U(3p}+ULewIh01U){48#Bo6g2>X087aL3<%US z%#UJ01eonT}?wE#Y%`3Vz}UK!Z~;LO!w} zc8y1L9|AN`R%f*U$2zytT=#YZ;0SWpUU7s8*5q+5;#MibZ^2+qa+M9lU}~w?34*{1 z*cCmU;AulvY6qfjO(O{M)_TRjamN%*!#7=j!U@JyQpa`#K??=-!U^Jl58@yWu3&4X zAP%(al)9ile@Y_Il|eTLpLiZ#xmTQNAMHwOqqUL44Vk~~u z(atLXZg?PqAcuKY3y8BtaEBs}G)W<1Oo?*~0@qsEpbZFOaH}^{y%&+dS0D&0I(o`S11mufa2nyiP115_>(%=+1?Ab;;S4%kzarj$CR0Fc?>UF*UM6c`8?xEbA}UD4nt zs0tyLAWxSrV?~!pba%gESg1zWAinF6Wcfp_bqSbYo2MlpSJdE5ZtlRt?HP47gyC2G^MFHI2JB zn$Z}h!FZgt#hfRtjTd5Y+kgzp0I2I$nu!pO(Pas$;9QC~3Sw?TO;HF`lsa{|A<*?* zBPt{e+5V&gji2@>W~DKL05qy#pqH-Fnof5^OF`imZDjeB7i&^0*XhKXtU&{<13;}0 z!V3S^gRIHAWH&+yDs?{M{;I*ep zUD33a4tEQHfD6|3oeKi7Y~y7W!dy{^J)s*4th;@%+aNMl%k5OlEm%R%OUw}hg@g># zpgSXsz=PW3uP%Da8|`KbqRq=wXbg$F3BtRbm^F{H4a(r7e>s}B_ge&1ec^RL*B8+{ z8>bfnfzcDd@049FJ8X5F02eYN@u}!S;t2#eH*eai{YeP8I;e+r(g&0!9{8bXh0?rY z32F?m$Ra*u>(~SR;Z! zK^r!sJzUNanqiSgbaNhgEEHKo8s;SeyelGE=T+bhf(x?td_x;-$y8Ba8zHin>h1RF zsh$k9)!<2wDXUQ{Mhb91N+Z1OS5G4Vf)*#zUL(SdI5iXN;~pr2;0XW3?IlutBAh@8 z)ZU2o9a+yKBl`ZM4FWxspzXn)2uJcN%CbE$(k@-uDNQ;nCV%n4-Yqw0i+Zs!IrHx^ zKlJzF)pkymyt6VzKlN4LCQyI%UH|oAKlWvR_G!QNZU6RhU-4Q$_j$kfegF4?Klp_| z`0rp3>~0PMVfdAw@B$$m!XXnZA`nX96+EF3+UF4{ff6)g5ir3Glp+i=!TK%Y51d~U zECLXw9~1^*Ashh{Bw-;GffZgs6y^XU9sv_3LBuHm6WCG+0K!qGNdXEPJcux%!i5YQ zI(!H*qQr?5D_XpWF{8$f96Nga2r{I|kt9Vf@^q)j27+|od97(eT(L|V4-T^e1-d_Q70z51`9RL z_@_`sAlXi;HVRrVKo|@ZrRZ z8$XVG?j%-wkbClsFjY9EgrABEkUOKJ(ZY!ub*pI|D}-Y;6?F4d>9=qR@2rbfx}YNN z63;xoo}J<9mrK(JSf5;g0uD%Efd(FkU;u$M^2HsPXyX4!7zZKJh$Eo9l8GY~E@IFf zjsSAd78PzGQ5d(pg5rs@hRXeO^L@=7VM zu)@ks1zpI>rlN9c(3h`x8bBkjJTg%oGrii9UIqoSO-t*&Qj|g4ICIb)yKR$9L0hnh zU04=*vd$|Qh4J2M>#bu9lmVQ?Xt`78?}C8E#<0${=o>aR#vg>|wEAbFd;xz7QGl#~y#o+?iAdt#%8Eg#hM@uwB*> z?k&42^i87^eX-3pdraa9!V!h>m@g9U!B~w3>C}rGM)bz2oPp`g^Fca|7l0dp5hU!) zGXDXXtOcR=3W;vu+H(L~035&_fCcuhLVO-n%4l~80m?Vq*lbbJ3*o9PM}JQYdE}B$ zPI+>cB8&Y3z7d@zNdKm1z82@B+4GQd;>2+1XI-QoHXs? z@-Vlx4V0^YH|cf;2zvAq3ibsm5E=R4L4*L9$rNN4;pm!0jtIak zYH^EPl$@pFbRIhNu5%5U!=_5X5gz|`2wHvmPV0!b!l5N3ei50(I$XGir~I%X%+jHP z!eOt1c;_H}oE7!jSee`y!x@V-#(VU$4s^-yDWmB{CN_7${{-?s=R-*P4sr`WNeB_u z_{JbGLPt;l5|rz3;6*;!#aPO6mb4sD#SFL*yeRM>ZU~hpj)xHl9wd*Q41i@Uh_`QS zl6FKhT10SVp6rE#i751A3k|}h>P1h7mT}=Rv6&lTh;y9eN{AW{GNZlyL@!?$-kzW* zN833wo9K+;E1ij}i+St}sDT73omtC(3Ur_Z6^f-ywh%HdL`tuqgq1dO&b+bFAcG9R z8{es`4jR!|6WPT&$aIjZoHG9+t@C3bR;id366TQwVTm>?8UUhb^C8z`h!6%*6=a6* z8=VYCF&CykgRo*9R(#z$a48Ww;>uhz0crjU3e~7eb*dD((Zj7LMY?|DC_`@1%7px3T`nZrd{>L$1S@!dR&_`(Ev5-ga424*LmbFrTamCDByiuj z1uLAPlj_mO2=8@9BRsrUV;Dmit0{_#6M+y_>M`o=C^A(LTlhmmo^06b?KuMkBjzd_9%=C+5q>BX67bDcdQBVMeCMlu|MV#26+#rtJ3BI4DV zZQNKV(@BVo!|}tjjCsE+Rs=(+=+78aGQVe7v5M(zj59BI(1b3uqz(#^JBT7wtgu=D zK!-MAajLu&0nGmZCH)lYEnoqP?%$Z5Qj>iChB^jc??)MX+l2WX<%fpX3=KJ}GtCLOl~o z{P&{?*+Z=g901&4d$NWux4F+9)i7k%)O*+sJqyw;Gu?k$7A4k*nj84Z$0s7BCT}Xy7lPpooSuoUse)Tto<(*u~djy!5oIeeG;-yW8Im z_qfY_?sTua-S3X~yz71MeDAy8{|@-T3x4o~FTCLokNCtZe({WNyiJb|1R(s|@szK; z+l3%`Lu1}9k_Uq2KM(qlbUyO5oP6XbA5hGn-t!1iy+uy%5!Z))_Ou^+=TXlQ%;O$7 zop;FXOVayE>HhZ!A^t>y&k^L;e)-I2NaU3-lIIHu_6?CeNvIzw)sLR_2f_YCtiKWO zH-G$t-~B^w&wY{TULodp3-sd>{Px48{qL{-@i*U*`jdbEv)8`-pZI**2Y{=$dIlkV z_jdn)5)pu;mkBoT#Xb~OweJ8kqqt|*Y2!R;5f(hY&4_FW|$bUV^Mde8xwNsQ7+FIETfEg%t>f%14ah zmxLq8hGMvE^_Ps-c!bpm5vXWW-$;&b=#9|$j8iy=P*{#|xQp+29GHlW;b@Bz0e;Y@ zgrXRJU5v$CexUe~shE^ANRhbMiaCgps>qh&_<9Yw8DdG245^PEsDecKi6!}p9|)2IS(X;5 zk$7pAu85U~DJfm3hI;9gqbP;)hm7ZFlfL(mDH(}!xQz1%mz=nnJV}{L>5Lnxj<3g< z5MhUr$$e1iktT?Z?8ujh37fn)i!Zp8`Iv)4se&C@lz?fL|0aoqxtpeFf@didgV~$e zXqDDik#zYG#z}&yxt6?{jv>jAun3)28JpRe98GDD;s}nv2a^kdnsa50jTxNMxP{ZIDW3azhv%uC1zP_ceyN72IDmDrq{9h?>Iar@;fN&RoMUN_5y_lh>3n4h zrgbWOD)E}SNT+U*r*`V6e~NKp3aEohsD)~%hl;3)s;G;~sEz8Vj|!=gDyfr7sg-J} zmx`&Gs;QgGsh#Snp9-pussu_fRY?#8$=9c$s;Y|j1YO{&Qb+$0L%;@Xzy-D^rn8x% zak>^vpaoU1r;mu8(#V`?%AvtJiZ{8Z^|-3bS|Bh<1#keZU9b_d$_8Mtm|Pl@8iA#7 z!317V1xAp0r#hD>ilj$+rS?XoIm(!O+N8|tuE;^G0e}S13I}Gu5lUbM##*6$n1oxI ztEsvW;wlkakOW5%uk@Ipu1BGG$&ELdqk;;oak-}NO0mWfo@+p_M-UhFIhB@~5nigM z4(f#u7=Mbmjqdq>;JJ_>Yos+;u`e645_+LB`g~GAuTpTZ2;l^2z_Vb$vuWT2384gF zKn7x91xkP7r)akOfH)C0M`&QxN|JR@;3`kOfD;1zDQ~q^h$} zkhM$z1wnfdSday6n*~?^eL=7UQNRRMix5VT1yEoFX3GRvAg~K6m$uj)rP?@!M?kM@5Cq1m1hcBSvr4uGF$8KbtDp-8Y(NGG2!Jk&x*li| zS>OdrV1ZNM1w&vEM^FV?(5qgc1yRs_Q=kP|paoZ;1zvCkR&WqQfV;wbys~Q$wR^l% z;EPVcyusVM2jK+X%Dc@gEl?_i>X?%kD2=Xpf2P~AEeM^DYrZAn1W*tKX)AeLkOfMc zp#x|J^oj)k7X+hs#c)CV$lDzGRlz_kpx;W1p#;jy(+N03k3yn z1iY)X0T2YdI|Z_fw+eg^yqX2zdIY}91P7r6LofshyudWbt4weNL68Ks%e4XE1i#A! zQac2-y96Q{v3)qBZaIw(OPY3>fBJg9Mf?y>5C?n^2XSx(8aoAXFa=0Dj$J^nRG<<1 z%fCRt250~!qg%S7sgmMb5x^_8mudPzBH%2Zl_bLO8F`x&~Lgza-2CWnllo1z`oGE1Vg)v_>!mw~WhKptHD)%MpBU zzU#V?$GgfK07IY!Odzl`9K}1xtHk@pT7U%1tOZaYuGr^#N}#~VXUxcK5ZJuTGOWgP zwao+AlZ=hsy&HYV-fDnIFwt4MpXA7zExWDViG!C(#NG?fKRppkPz71w7e^2URWJql zytM3xvCz857=gvC?8*ia%LH7I+w1>?!x@*gOR8rK1tloaRlo#eP1dAr$67$l$w<#x zP`kEU1! z%JsStQQgf1JE`Hi00=$l*6)No(~smlM{1nOUR@Q z1g7nuTTlg6Ag)571hPH3evFxO?94_G1zzCGG7Qr@DAV5@p9@aYH*J(!SmXFTndM5E z`px6iS(ps^1XT>N4>8~YFuH1x24GMI{%h5!n}QX}qU3zCXH3R4$jDdlwozca(L7fg zu6(?D1yPU%Q2@N1T@XXS%eLFg2EoY390j}^%ITfg*Da!3$$)YxkLUd4Xer-sX?pYB zl`5*MJ$}A$d8C*(ztH*wIUN!DtG1>#y0dDulpUVhNV3(4dDz^>*eKM^o6i}J)}vVv zK|tomdj%^V0BkJ1#~c5=+*}Y`FvqRVzqIY*w!M?nX{2cg-0S$g*vi{n_}jNm=)*1- zPM`*AP<*4V1VLNXOq+iV&Ybr<1dmP;ry2xDFzxB-5JsQ`H~Emt3ZvQzvA?Q-%1!L& z-WE#WziIFgu`JN-`VoIi67pW0jGl^=jPChfXh*KOWkBr<(d;uj=vwra`U&p(j_|9c z^oPe1E-?~0u@gP<6GAuiO>cO7 z0k8_u8;)^W5+VN?PLK6i2{qw>AO1xV+p$(zFZOz8A}Eq3YSJQEA|o_1C_lnhRsRq~ z5)Lyz_H{pZuEJFBLo2r88P?Vi!?IBrfh;Fv_l0kFFtav)P%{XDGhmZs6tQk3l{8D! zG=^{aco$Kq<7o!*JgDUL5s^E^Miwo1`K7OR8YV#l@{N1y)?c7#VWru)mkbf`~E*z))j5%~`RO$gB$QO5k) zA9K7vQG(?65pi4(;ZYbSQrd6+Fo*h3lUN2JSohQrmIYVb@y^!L ze`s#y+STh@ngu5B~PYYSz?%P-zFN_b0)x`pe(=a5kgT2oj+kLuV&ra^=sI%WzVKf zaF4Kcw=N>GTif?<;K79tCtlq6MygO7s72QLzL>Oa~u{;lJ9O=Xp z;lr^sf_R+qM<9cgEkztj%27HWGfFW@A)9paNy&C>5lSknwDL-hSY#3-9G4_AA}_t% z>cxl1B&f?HA41d2f{0`hA~#c_EPe368bjPiVR5Qdg2W3)G zKc(!mOerODv{6R4-1AaQ7Yy^vJ2^tr(=ZKf^Tju5T2jqZd%V-lg0u`k%r=Yc@=*U) zBhs?g09=JNQ(k*5P|;ld)F{x9Y=qQDV`)luSxTp57SUIs6_r+7n;kXHWPR0k+x_g^ zb)z^%`m$9yd7PHZTc->*)H+)f6<0Q=O?6#$C1R6PY&)Iz)lRwf_g@fm1hyk$LCSX8 zY%yY#Pe%nk65&aq4K~Sl2L@AORVkKM;)DVA_~Y}&-LxZiLz1`AerF=JUvE*am*J7? z-11~(S;iP-oO7nmQja2C(OPnOeo0o2v9(uNTZ4Z2+=;18)LEo;mU`;=Tot$9cyErW zEn4VDpO#c>L+g$fYN6Bi`|tnb!o3mW zmc0@j(oiW*S>`y)PB-7g$(@pEz$>>rIJgZKw$isLpP0~ND~gy_&f`9K?#okG{k?n5 z4bk(lN+pf5B>br*j4{u+eDu>-e|`4bci+I;-{$$_ii7xU7Pttuq8n+@R zaKQ@nBVYl$0y>UR0S*i7!kqNxKj=YZ2y7680WEmJp~bHvNLU~o%)q}{ne2EFu>u>& zfI$?dkR(AE$r?I%1cp8Db_yGz1SzOO9Om#Mg=5^e2qJ|JN4XG*odTPpk+OvammbBq0k)&|w>gS30F- zE&xa9;2OvnEpkP~32Z9^3!$5J&Pe0DBZhNEWn!g@SZ)2ofbK+MR-i!kq_ZGTq0davs zblyApXw8()^pXAKql#pzRe??r4P_t$Sqpj6jX2>7Yh^1(6X}I>UNf6TrK{AIPz9dO zF$z_ff>UXSs(J~*g$sn?oUB?| zQG%A8{AJ-iu&Tim3zorr=G+-Cc)dk)n~Un=F}wd+&U2=7o$Y*QJm*=@d**YW{rqP@ z2U^gBCUl_7f!tmQs=rvgD{LQb|Mj*2m=v&(1c+$!I45#BPhS7 zNF6fcnT{lT*_zRHwKa5xorod;;lMRS_7IM0Jfslo7>GvPkQ7e@;2Ytn2yQyzkuW4h z+uXKxy%m&-TYLc`j<|&)2r`FiXhq%Beh6=N@sKTm`z`?|2(u+JiH49lA^-;jK{8`+ zj2mbd;YjyG*b)eW7=bz4?)F2@@QrHt$PxeRIJic>u!VxGdm>*j49GpQg^|-c<2w%! zZv;~iIw)Ks7mo-k8ln(Td?O(saX3V75f1W@gy=k{I)99y?2(sZ9j%s#&LdKoa71Gr z$w&-HWF8UFYy;*2U_~?*!Ss?>UGDgy3MdMqYK07);APSYxWjJqk2F2xY{_&0HvR~+ z?|trzpU)rGfeeBGCK?p+`a@p9ayJB^5z4OkN6!9`PORhS1lc$w;Ldo|(?{8v*GVZT zGWCK4;yM5R#^eL9_yABv6ldVQ8+s8AMZZVLx!D~MMs3ZxJSqwu#}QMGNjg;xLyj{7>OU=pHOilh)hM2JA(bHSv5!J;^d zz$l8Q&_E!B4)7C*`{Rr26E%X^f?L=IzK90Dh=@I4!qEe|>(h&4n~06ezP|{JBCNu` z2tqKN4lLphv7I;=xGyhA+9Lp|I>KI}t3{6jzt zL_r)xLM+5O{1mc)GDBR%#*m}0kTOR9j6}0I9I@yhNxVdrkhtN3M48}3O#H;Iuo`el zmt5(gr6EPc@x(IOp_E}WP?W@m*$6l?9RypLI8w!7*_;}B#ULCRS45Xz6df@Mp{H@B z-g+Fx$q^qKoXOcmUerKfi6Dz`#M7!6x%sZ%xfX5AM&Pl=XN1F+(I8q{MvI^s$@!XN z)EBd{9Xdgknwg<*%s?A~Ga8b{INQdj;zrTB7J974wQ(AIjK>TV8Dg}ZS7Jr7iIsPJ zn2&-SJ1L1|92-p($UXEKSp=GV%$QQ#N4tTEd2~jK^g~h92y-+>k1Csl9N~>&@qq!YLRLHCBO4iUxuMA7E980n+OS3#nv`kC2TuZiWOSgPWxQt7= zoJ+a{7$dNPEu#!Gt4l;vMEubouvE!W zli-4bE&$1D=@=uhDJL2sKl-P;VVcxJ3oGyfCYVe?YezvTEis{3fdo&@*_#|Oc2E;CeVT_Sh911q$*f4 zAar3ls44L!R8oRMLL}D;Q#IYCwBk`FkcuHtC;}sh9gTt`2m*`J z0?F*8C}1HZP$&rh-BBoDp(E%d3!T!U>ZWfBr*SH$ABB{vTBikSr;R8BK?+epIxb$a zB~&7adHOGv5~Mr2Cp3@>51Amuf+u;Rr#;nz{aFGpSX6uRf-30M2Q3IE;L(S0DC=|r zVSNbRv{cZdsHVE8jM^yv;U6I=t&!RY5sN7_;DVDXA^Ng0mx`>KdeNlHsvNNb`f@F_ zN~}GdD}pf6AHA+l&8~Va)`ED}dDYi`Vlrr@tD~v{AW$lB`ld>C&KdJg@Z1PT@}e?0 zt{`wE@aW9vk}#}7SJv9l_;Od(ir2TYP9$JbW5uR@_1Bmp*#H<>zS5~qlGlJGs=LYp z4>^Lp>MIBTnlZt8p@}RZD|pX)8iF)_ z2<6w9;!`Hr+O3t+m?bLY%t?3JOxLVRmEwXa0)lU)EMpC%K5^OvWm>SZClw*1(u`Y} zdRmipDU}^r2+b~ebx;WP+amqduPv~~5ytogg3HWI?u?p7Y6B|}f+<1+J0++tIod&z zTi1e9As{4y(#>?uTZ^b#mjc*h?bPeC&THz_CGc0NJzVap%<^)W@aiBVXt9?eD>gu- zG(b!(wOEuQ-Gb%Z0BEmZaiq(-+tCGCzJ*W}^Q%mPsE|Xk5;FoOP}u;m-hx zB`TNybg)!8kp&A?OO(ws5d%s}5iY1CC8)8hS}sVctU|ga%0eU|n5PQ!BmI)!i#1oh zjaq<(t|K+jmqjDa(gOa>DU^NPE64&Y$RsU5vha;41d_^_1cEMog0Nv4A#f!10s;yP z0v-`v38OF>H6$(qf@8YTKvDukVP4I}2-9_1>@GCt$8 zJW@7pV>f`ZMJkDc1-eW%QV?U;vEf58}bB#bA`Vv#*Rt`i%ZszNtlb**kqxYh&cef;qYYQ$b{Z#4O5;%uSjKy*n&YA zx$+=o#+ZZ76A4zvj$0;}M4;l3$YuQi3M~wPFTjLGc!)5_ghFr(pfEj&_=BXlLW&3j zN=W9gkY;KIiDlM^I-rD1zywYcIIh^{ZvN(s$YzZ&0!j!zv;YeG0}FPRh~G=Ow4j4= z=4LdEJa6V^Ot|Ne0Opqn156kMkN|{d9*K7rluLWQGD!qU69wt>2q6G9B&3Kf@aDh_ z07t-tU~ac?XlEnHgkr`BUz2Bp?&y~|15CJP-#E9p!wZLqJtCZC3@ixV2tbSf7z9oZ z3!MJsj{rXcvb+A3NNb04QHD@rvk$`H60E%t6XpCsP zx9bQ`Shc8oh@$3;qZSF4h6$eoiJE@5kg#f#gEe-$zhp4Na5%n>ur;~(>6~D>k2nKg z$cwnH2)7OZYzsG$MhISZHExS)li2CtI0dMC2=H_20B~kiP79+8>tka_f&WJB)gv`tB)^-W!xa`?bHgFCAmwpJ@E4Rhq?~!n9ozCfx zAaIWez2fc)2FD1o<7bQbf~H0bvCF%T*tm%ni3|UVjZ^53c#7sOhzBPL1$T+G28#|a zh;wT}2n>KbXzKk*gz(ddcngPl)9Zpjibu|f7EiYqkBAi~h{E2AA#Vu-_YLQm?a6)! z%Z7+EV1-^VhF)NW^bP}2IEq~e>4)%yS8xMJ@C9Lbg@*<~RuJ=ENQL^A2+)}AFn9$O zd<8gv1z0ACI#|J8K!p4*h(~w@0TgCAhh-xWg1t$6SITv??dxcUU zc$}vQnNPx7I0c~J5+eY0N0*2?NcdhTgwQr-ROfQbxCNV5zjb)^00{7hpulx#z@0$D zI;aMOFpS)Q2;8_l!$=BIjzYlB>;8TStN(NV7HYXDc7l+-q%e$BK=3dyjB9?nktb|r z`}(|4Luf@rhIXq*#a4K7+ysdsV&zXL$R$@HEV~ zL7p!NuLt{YNWU;>YNRlGV?d+C-}}Rd2&ABjbwdc1b^~SeyKvAAEX47MNPC2U3cyo* zyC=9asJZInYl+yn)F+71*NfQ}X4u~extRT~-+b2pPe0{fwY{r-Zo7RK^z;BY{fBUS zs6dFgF9^#w_Uzw%?q~7B*NfCf1SZsehL}Qta8oT@xPjqr1xOgc&AM<6AI?#j@D9Os z-x_|~BT?e6aH2MT*`n}UxQzk66cm|oQn+3wUn<-ZMq#*ZFvASg2yfwbMII4~iV*v~j{mMvVmjC{*x^<(4z=Odguh@UA&R5Dj!B(dn(& zvwO1=5+H0iNH0sD&a2SVVVH({xe<~mdGB7ogG)4a__tF{Cb^f@D>wV_&kGmR4ioNM zFWz?sb|Min2k}-%d%Zc6*=An_@K|I{P4dzg^O6AqS}WF4R}j|2X4e2WIMqJlV_~(rdUhY z@wHKlFJ>rXd2SeiTsV&`2U~8>ITlWI3qh!m5jv{Y+D0`dhF^)M@wDGdrFi8UDBo;D zhjtr%^9@Xk#kc26a_%%CoD%7`jWGWI4djVisj0|dLWxotV>phQWGH=m@Mhr0+NI1qw~$ViNe-KyR5^?7ETo+5lY)gm(U;U5Y}r-3Ssi3wi0!l zpRmNXyAido2GB{kFB$P}LX^mRQcdXwux`Equ!0J11BbJVN&X(W6DI47wvn#92H=DtP=OiO2q*@vJS}!sfTIDaPc~oM1^>35+xYFbZoK#EchOE%Yx$bJ_uO@XAp-D#nm@HAsD=P#_cRNuGlT)WbE3Ll8DilW32|eA@!3sg5 zvO*wN^KbyD6f3hrG*`QkG3)3FHOC&mbaY)L!PE&!136=Mt2MnOST%jI5>2_TBEFO1 zT7|=LBQqpjp!seroC&+ux*RVILmniQh1(ArY7N);jO)r80@SgMP z$Fc*OBzh85$Y!hqlP`$>?;r*w6-@p@I{j3GfoMx0PdbQ~{SlCSG4zi0>>@lCEl?p1 zJRaIisKf8!sC*SP-b=W*ro$``Ch8#}ObE3RA)sP$Mv>mD`eYIzI0a}4>4*m(=cf_k zFooH@bdttKoMsRg`9?H$(TODXPmp!_Ti_Cc2(&q}Z^Lp( zG#ELeHA*CvtwZA}7bZ*jJu;G!v|u1XshzNyBoLr09fouRONnej6TJ|IF@!N0LnZ{6 zFsTFNB8QelE)r4y>mZ}8py`QSG&7RyN>4b_r>;lvN;likB_y|L5;|0~LhG<(BQfbS ztHDG!1@UD7;F&v^C@oX&{GlNQgGfcXa*IDh5;&Qut2KH}h8vNlSvJ|pPF#O4DapT)aU<8tR{0K^&3DFgCz;#GX3P@+b}+pD%H$!gM&yq7c!Tu>_qXw{g-*{xPiDVMPJ`BCG-W z)>I;a&bZ8Zs5C0fLAIPNUf(v2#;=M{vdF^Ks@n|?y7 z*b&j@t#O6_>s%Ak*WcxDBUv18r6L z!%ohksL2YWvJ5M0Z|qtZ7w*JXhlPo0cLL87p4E4uS!+QYmk{7?#I;+2t?vS0B%Y8q zbf|4EUwIoWGNQGSk6mp-Hk(-5oP{d5)vZE|s9omnbtA>yi4%XgFdt&>ixOE3DBN&{ z|9XZ?uBxwmy&C}X9@T;YpeAz32*U#V6~S;UmU$11A;Hd!!ZpEdZpG^1x)?z$b$AIO z30hmE=n-c;sU%*u@Q126&yJv>V)~{wQB7Fsuwh;NlximlUzAx^R!Dxw0Iq{ zAf*&AN%KwuDkUyY875iIaR93Jk}pdn%n&uOLY54$7yB;6>!9(SJIcQbtBr_3mPjHr zd}bvAjwgFoC7opo6p6569RhaDI@~Z|qb}wlPgzGBwL{d6bXp-!jr2=IM>?vCSs}4b z@EZlqWQhz}Ax};t=!A*14>BZR;NyaF{LEF4+!P(_CBTw9$kmE`u zUJhK$Ey5s|Yxj>qXGo+*!CNeF!>d>nL55wHZ5KBbBBK(?ZvWh!uR5xm-OmjNK0jLj zBtqYm+tEg&gu@Hngd1|Ub@u2^PRZ;5s0ZCUdH6=iZSHW;bEFq%UxQhD%!Fk7jRWtZ zL>_)hX!Z-?)|ELjwLKzcH@sK?S7E-WNk)RvhMF+%HelLD+O2i1~?$xoX zrHGn{ByQ2T-avF(iquI&E{RY`M=GXyYjb{>aLGJ<2U1E%h>#=ec)psWZW2H( zwi>*NS2PgY=keRc&gR0iM+aZ{Zz~-A=NJBSbN%d;`dIH>P2`=1{3QhLaa18mMCtVk zP@N1xm=lbd$v`k#h_F{e*jP+NpW$(v^WDX(1;E8fopR1pNL1i&k-gJ0QNQ)!#8i68lC#T!+XLi}FvxgJUAgb{RJ>Lnh$FrMD! z-4~EVLXjXr?7}Nd()Dmf7T$tf$XTJ)#4CWpEs%t78B1O9gkfw$FR;S@F35#&oJ1Ak zg|}H2LEHi>BtvY`1_*^i(bNa|#7o4yLRCDWLJ$mNXraK|;X&vjA4){5Yy%mZA?(c! z9rA?N5QO__pivmZC%OzvD56u`-_>DZA?}CSP~Kr+f+u`pbq$^;f?`ZyV$Rfr7lI*Y znOu$##4AvOCkVrUER4h<$ry^lW_$yg?Zr1(VH%?0P8d`)d}77;As_}ojUZE>G~*tG zQ*5o%C#J%8?P8cP-Ya}zID{c<83i*1$}0LIFbX4S3`8}2qA>IwGC74bGLy>~Mm6+; zImV&6)S{Fm*TM{9FWkZ;F%nsQLmooXV|BuQyuvX;;7-^fU6teiIi};YXd_IVK{%<$ zt$ZRP^vYyxLmpPerI>^!hJ*WkWH=E7Ga19`!9+)lTGyb3`-Qvz*n!3`9c+!(b{zVLpX0Af{i|r87+CU)tVF?1568TmamGFOWn- z%#|Zl=3toG>Okf?NajX70%W#Co}GwlK85OV$FXgMW?Y2-L&W9$IhsT?LR|_25RO@0 zbi!;V15k?Lr8UT!*~M)>1^;*k*MtE{NM}S|nr^6?sad-+}2RMr>pNnB{1u4gEpWB!~q;_(EG^O+^TUBlym9J_Isc4ov7u zY{tY}5~o~(r*W;?h9*lGyaIk!0}e_A3a$}DZ0JK^!p5X$aMeC~>QYiH^5^ z>vXJxxQ^?&3W~O(t9DSUwF*kOQr)_8E4;2Ny~^vo0?!;w!ZYHltIPoitX5vZP}Xb*`jUQs_ojc zZQHu-+rn+!%I)0JZQa`K-QsQD>h0e0ZQp8#5CFlh%B-v%8 z0`BOZu3fCIc1Z5UJ}&I?Ztwc;?<&Oq;?C}?xL>;5uH#Ow<|6Cp4lnRJ@AE>h-#%{b zM(*j7?(j};_HIPx=I%>mFXT$Z;&Lze;_mn!ua3zs`G&9gx}W(*@B6}U{FbfoQm^e| zuk{*l=+ZA@?XUOlZ|&-D0Pjfv3-1&C@AeXK^P(>S%Wnfa@B`26_$Ea6?uq!S?_D%* z0OW4>O7Qd&X8Kz0`c5wQ1}_PVFYbDvY zH}VGyGb8^pEi-d7JM$8MG7mSd3e$1;k})WoL^Q{-8uv0PxAG`!vnO-2Fcb4LoAWu} zF#}Vs=<4q=7xJGH@({oCJi9X>8#6sWaXT-tBPTOD`}053FbKEG9A|Pkr*Zmr@fUY; z8Gmp&XY)9(ut2{tEL$`GLOV1-V{}Hp?hdcBE=Mvyzw`elGyNiSMf31TC$c^xGf9_j z6tlEO!*onzu`T~mH2bO!V{kX0vFTp4O#Adt1GR_IblwehP#g78BXv?M^-?pn(iU}7 zLv>V3bs@8_MZFwmS9|qWgLPPo^;na2S)27)qjg%V^;)xaTX${{)CF9- z^<2}n?#8mu+BDYYwbGXI&*Cz){&lj+b4IwmmrMm#7g)iE z6?R2C^j-&m6IcQN7XUY9Z-f}I0U8W8zwmZmDoOb|hcX#K-LL0CIpFw!TgdSiwcDwgWBzG3y z^?UDk^_nsF&bN5CFnI&`<;t)`tap2pa(`#DIEQwEBe#Q#)p8##6;E;fQUM%rco(#a z6BM^l>$FOvwiyQj7_dQ#r}%Ae1R1bF8`N}klQw9RIJO?}Ez@-1I>8iZffroCt7wBe zh<7l!11xWh7B(P=|>FV}cN1o@B`d8YMD|a7PbUQ0KlbZxBxWkx_ zIe|BMX%Ddflkah8qcR}}@RzT2ls~zQFSAKZc>rYjnUA&;uQmd!d7J;at5|l=rZWG= zG7@k&9GJm}vq2enn1R2sT`ac}uz?zY0dRAHa7#oGO!gmHxPP;`DQEJwQnaK~_~ThY z6=(qyXn__0xsc;|l~4HP!uj@|din0Ef!}$a3(AxO0k0qUcQ<#fON1V{13S z`?+G%xv7V`e%G)05_@@XHK>0&DF5lM%Q{sbwn0}fnzyiG2YSuIHHPytC$2%FAAz8N zI2wq!xYxNvZ~+^n!K)m1oh-YljoGIu- zpZjn*cXq~uJQ7FoEtj;7U%Yq!ywB#gYm+e$NI{}Yff;YHLV$P~H~|=tff#^+`hr0k zD1ilAK^m}l5TpSZ7y;Bv{c$ty(~|)iX#E9qK^pjW*<*ndkaN9*L3t|#7*u^4biMn1 zz1KrM8Gu2)2f^2if!SNZv|qcl5493xK@w>25@f*;Bm@>f!A4*K6HGxASocOS{t+Yr z6EHy*w0i)+HRKNg=O4l7GlAnLgcD=|7Oe3RWWf@cNftms5KKN3U;!w>cS0ON6$}CY zLL{)CdYLTQ; zg4)~(q~(s3!<++UUS(TV?asAoziOnbGbdcDc$dm;OZVhnzc|0THGCLxV#RU)?Y?bH zk>}eZa44?{@)$4V#!lFvA=8-+n=*F6umPi4NEtRt269FthK-ugWz;G`6T405G#5XY zz8#wNKr3Llz$U|mI2b1cRfiV6l_2LbpL4SzV}xK3C%4=DPJk~g63mly(y+x?+SvH&|(U{hPW>~FW%GQ3N5^t z0z0h2(@Q(ND1?kL)G%7cogyG|CnSQ-a7P;w*>Q)(i}WB1Mi^q7;t|Z=lPBnDRs`2Lf_O7=0}NNXHu45o@4@ zVB`_1fh-}#BZlCFQy`-FQVU3Sgmi~U6@@$mGA4s@D9=6nEND+1$4qa-##U_6ojtW_ z49psDj4H=9C2BLhLWhhjF(vg{vPrn0bZE)|s@%vfC9eXJ)eUhna@NdTowZgGW3_cW zETgh@)Ww7yR#+#Xhyn^HbmAflF4%H)t|WmlgEBaf0CldyT8m8#>}+Gh*@2W`qm9b~ z5Mo@~1~MWxGMqqHH87&;?J_4+v%;az%3v*sG(=<0xqw5%S6n5Ou;RJDI8#FmWxow~ zpx!L97hJ|H3e3)oLUrg0_=I3EivWVqBIJRlAX(WV)?31%lcxy(Fo-O)s6s$3tN?-u zEs_8t3Y`Z!fxZQqHt%iyfC?3COev zA~6^}ggAsOOB^CAm?8o|n^Pc2oCpXY)n3}7risFspoNw>Nskzxy*lfyS!Ft_U$3S} z>q8o28*H+~9*9Yx>h5uEK23ysOd4za98IThm0Kc_>>i25%~@n=Y>C`Hz4es>2;1qw zdh+^9$x-FgY`E_pi0vYP;C%OqW>1?~r-||#uE4dq=<0zQcPm)J#LFvhjgL%xJj8F6 z_WHu8wwP+nyvMdJZIfT0eTSTggO51kxZ;Qarifz-$6{swtcz-?XmwPu3IJ!=ke`8Y zfemR8Nq#;9F@MQxTWoljP7o%B==_T<2qVM1D#n)FEGGa~;DQzWMFtUy5QLgZSJVO! z8W08mfxFoj8XQu=BkgZ*-%Cst@&`01l#RlrLS9t59t(MMSnNdnPss6WTJ?L(r1Rshwg7Z|ZlReT~y5hCRkidaI9 z0|`T==M8 z=%G#l*rPf4g1I!2f+P%i)0^P`~y4-4{3LKWgr1t-umiG{4%sIr2DYOMh@o!F*hPa2yiJCR(wX#B zL^|=YPE;bwmd^ypqHMq@TM!6_zdUPVqS4*}9V*ccii-^vyr8=DS|!kabDjTVwXYxYQ%4RF)R7Hxdm<96|a{J0Fy|87qWyh zs4P_9AuD3UR^fJhN;GA{(7sTl%-5thINCQRY~#AH0zel{AyBs|dzQT%Wfy%4SiHK;0Gj8GLo zq*a;J?W11ybQ8nmb+@whKcOLXFvP7 zwQcp4U>wDwCBqg(PoDEzm>j7-|9Mzj?lPCbd^W*3udCdo-kH0Lq;QtGdO>!jOIavD zRI^i7(Umn~mQaN(P~-?v;GuSYxG=;V&G2%kG!2+?&5O zAKIUbVVQ7{1bP~m%lraN1#ZF!YP1Jpzae^8M8X4E{g_-_@8L z2pt9RRs@`-b;Vb{2X3$bIP+}I=q~rL5ftgA{G~( zV+ehb$I;&EtD<%%BCndvXihSgGY+CLFTK#JB@z&f_|49%+96;6t4p~%>Qw76B5h7= zlD2RN5{)UY6e$AF<46m1x)MnX>9iW{%8=3}fBlgmzhQtGT2C*-fK8qq)hVrfyASL7 zq^~T%?l6Q8`l`?5#ts1$@Bm*e_|&P?5^(M&kg&R{;>d#vs-+8>OZZ4?H2&_u2m&@9 zNH5q$4d9~k0w4tgYunxqDls2H9@77!5I;%OSJ?3a-EkST74~jUal4 z*MvjGfS}(X&VIE2KqLeX2%w6I7H%uXsKT^L3!o$6cyGDBDhr#7pJLE0W^3sR!qHM| zOhAnwAS-ZU%UljA?g+y$oagwYh5B-cJi>}pey0q*iH-oxc{C>bh(fX+Dtx-C4OuPa z_(ZeZ!Er=p{{YPp%}^500M35tw1|&WKrL@RYs_9N4Yw}`^)O>Hh7KLA-Ez>hxDXDj z=FIYtxx_;i8_&5eknEU{2Pse&zsdT5uaLF?*eHXF+Uf564y6tZFAxSel!Sn|fG0{L z4dkp1)PP?iPYtpy2=FUE>aLI^Pk7P`FIK47L<$m-jUa9#IE26o+92B&P}L4_oGu~= zP|T@-APbiNh#;g03L>Lth-x5OPn@7A0Hi1gXe?aj(F>A*B7y)PvxGjDKqF+P!s@Q~ z;NthPWSx%eB9zSI2;xsPqH>(=MZ}^AzRw{xOAoff5;!YFxa)fQ4tO?Ya<6C5uT2{)8aTLhGoH zBPY!x9T6lYLL?nAJxVfelG05$>m@s|klcbS&cY;avhy^g6?u>EOzrw2@D6>k@oEwR zHG&)Yau;=Ru)1g6qT&hshX z&hUsG5P~d_Df)KgC+;e-B7z-gp(fbjOty#Z46)sEVi8~D46;QG@di0*(+oN5O%QES zNaV{@;zfpHAkKobY>v&A%jd#S?0^71<@0Ll6PAP|CMaTV93mpj0Ym9Cbnu8zXu(Bz zOAarNJQK@2(X)=Q!a>_JLfPU%=Tk$uN*2M>w;a?R`V$rriP*5GGSCk)wXYI+{(qz6~bR2}z`A3dE>B3X&k^=|7l2_53ja zSWH(;CdPyS3#N$1mPhPQ~QGEm|2OA~fbtCW3aaYe1dHXW|r z7Q+ZUlcAigGeklO`im$GMp+1JV}*qj>B2C~O9?&}4~;8S2(Ubc;AESR<<#yloL~rW zc7PVnWk(I@7K2IM!e`r#F+QnZX9AQCLk|w2l~i_Oqbp;F1(c$eC_qU?X{u>4@f8!} zX|a}Nf9Yy}sr$q>XAj3NQ9=)v)**_ZYY!=G>5pci%VG;~YOmCt^mZ{U_HLz=V&#rl z1D9B0$SP`(?ogF*7k6+MH*kYMLQ>Xo-$`*NSI;aLbE#G>GxuO6w-r7Amvb$*awm6m zL)UcMXJt>(_qo7k~3tfA^Pv``3RbP!bBk4Maf*Bmoi502H>s5f&i; zC_#Wh!3ZD$5yC(e6j%`gU=j-932s#*rL0E)I*o0A7g#&O^TkvN8zxQS~RigTEQso09KSc`>tg$3A%UpR?nn2Bll ziElWHb(n`gIE1elh_^U}+qi{~7={`6e+$`=4;hgYnPPiE6apa{zTg&E;SQ<+l35`D zcHtEMpc;%|7gAvlq9F`k;S~aaksY~`C%KX@85QJNc8Pd6rF?o2_}3vH6pcd7OdymYZ3Zp*ftjnVf_F*_?}+m|`V4Mil!f6G z24Ne%;Gy?mq$%2>0bv`ApcgK>8anzG0$`yVnxr9GqEY&yGkT-9p`$-Kq)+-4OuD8k zniW)R_+M}sj zq^%mLi8`y1`W9lkt84nJaayc*da6PCtV=qrQ+lPf`lZ`iscHJ5<9d`6ny?Goun&83 z7a{uvDciC!TeDgFvl}6_8~d?Ko3>F~2vi%lU3;;4o3v;9v~8QTJ3F^` zJGOm0xl?iWgL}HG`?ZZ*w#6H@Gkdwc+quL0 zw_#hjyZf`x`?--DvGZHM_nW_m1rq+i4LV^97NHQr0D>DKw^th!0>BXl;S4(A3lbp_ z0ss;KA;67b5fI@E4m`mPTnHXvu^}805P`x0T)+w3z>NUGD_g-C+`%DS!YSOsI|0Kr zoWoh%!$JJPzhJ~mJirIMz;7JE4cx_dJjN^k{K7MQ!&SV)LE*zgoX1K0zkeLXg}lWZ z+{h;!$!T24tvtt}yvL{f#Dkp4aeTqC9LBYL#%p}ZSA58wT*pOR%1s=|Q+&ny8_)Ax z&-2?CQbDD+U>8_{mBXN{ec==Wp&9^P&?UO8dm$A9A){M*&QeG4RA)}MOSYu(j1 z{nB^6qG?^!Q{B-aJ=ag&)qB0z3mw>F-PMV`)f*kxb$!__z1cM#)|I`i6=M=G0TU=8 z6TqDkCV?Oxf!xPE+{b+nhyvULp?wPf0Tfsv6Wrh`20;{9K@-k^eFkCPHNoDkLf+{; z;FD+I>;2yUz2Ntp;TzuJAD(}!VI9I@;wyd|2qGFPp5ixt9YoC5Ln&QNx2lTo!c$B7fL~sgWcGp-sy#X>6;$w8(r(ap6acB>$6_!pT6tM9_-Iv z*2n(pp?&SuKAD+b?xCLT3El1MzUuG3(dqu{lR50+KJWkD?)Bd9;eN0aV;jN&6gKSDp^9tR2poa3!GD7T;1L|$6TV;(7&!a4U&Rw4#lfHagM5e0{|gjB z{k5O_8^QbGU;I5DARY}mBw3^}qY&;V%Ds#Uu!+}gKkd#$SoH-NBksn$uV%QwK8 zaNCTeeYDP3+A!;?eMvhhoUp!c!-P|umXhPNe*+IL40-L}YJ$-cHjGv>Wwe$bcV3;= z&8E+H)U9LJ&fPnB>*JMoUwUV(x1W3P z$(P)6&D}R$c>8VFT>#&O7od621wf#I?Y$S@aSPVxT!s(omz{+ESx6p+=&8qEavmy3 zUxOs(cioBoQTU(#cq02avLI1s%6AvX(>`= zT0&sC))u!I1KV1OgtLoUT~?D8l~Sg4rJ8FQaf>jNyv3%KUItL+nOx>s+@F93D(Iku z7Ha6Bh$fnrFsTf(%@@7Avd1@JL>hoEto-rK7MT9A%^AB$DGVx(LMkbxmSPIXH%4^& zX{dHJ`e>w+R{F}NnQrPTsG^cO>#4Tlx@xPLzACD$rq-HjuACOjt6jb(i|Vbavbrm* zjFw94w76>8tf$Y8sx7d~4twpf<0?xnv*$vaF1OVZ3of?EZW}CX)ws2qTy)tPWtY+1 zmPt6bvb9bBT9T~8%39le^Oh#-grl!olPJuv!)Og$a9Z0Oyp|{7ti$SBm=Mgc#|c@? z7RHLU?DESn$1L;AG}mnN%{b=_=#l$|qexw>gaex~;hbTcWeXcznaN6%DKVUCmAo-p z9WR|U$0)D)^jnQxO*P9>pA0A>(Ri)%*=VP&_S!V}0!kp!d~r)EcPRGC!nc(22WWZk z5ltAc+`7x#ao@tq9fdEvODTREvAEx7+#P`1aLY}%-FWNGH{*W?9>Cz08;-c#igWHb z=aDZ=dEu9TA$i_=%gH(5f)h^q=!So8`s2~0KDq64*X?@dvG?71?V%r@xbBVf?)&PN z3;(+R=Cb=u`{%$bPdf9_oDR9<&ZQCSPO*Pw`e+OLr)|E`r0R*jyZDHS14I%+l zjaJ1Azp_nq4TH-dFk!T{B&>h`%OBWGWu>dqMe<(X(0Q?6)mJ#O_ zeqx&lM@YgFny@yMK!h7kA%saJ;tZwOf+HLe08A8O4y7;xBo+a~EkL3X0Z5@6O3^|^ z^zactwBZnqAc;kU;S^gyVh~lxLKpUMhBdrl4tLnYA5L+IMLc2>3$er|J~4_w6k-)$ z7(*=D5QjSCVGO+}L?TYYh%uC+5_4!qC`wU{Eo7q%Y52x1%F%~uRG}U5h{i0I(TRTl zOymj!c|}5MF^*l749AuA#!z5zAXRIm`G2!k{=7zkD@CV;fzUjVxLRhC^ftI}Le*syA}2a1)f$lRt} z=StVQnot<8fYKK5`iG+RLQ2M91(d$v3rU5eQlb)UIQIIAz9QBxtdJ$A8hhBk+9j`x z<*Q!-t60Js_OZfHEMpyO+0aV1u%s0gW=Ff(00efhh22AC6RTIvf;O^?MeS@aTU*MW z!LqLnhi7Gb+uo)YvZtjiXjiM*-*OhVpDnFuZ7bd69v831ZEY!8(+i)$1%%P?g)n^a zjd0ZAmu7P&)38>Xur)1+#S~ju1Ek7*An6O-WS3WrtsGSOyUxo_{49y1t|Qsg;$8; z4$cSzEAR%2KRBbsrGT;PQenXw-}n_dj`8b!jN{S0g2yUmv5R3WV;bAI$j;btkDm-= zCJ&j)IgZk$zg^vnTcFwA)~p-T3&OP znGEJKr#Z@7_A`_LcjqeSnagcn@|VrlmjOeDm2dfipQuC{*7UU(YLPV50uc^Or$y2M zqYWU!QRx7HIxUyZbO<4n>QCos)TKT(if2vhTF+Gzh@e9%j6jM1N62^!m;hoX8sP?3 z2tgBza6>A-0EyXj0ugga#TF>xh%>Ol2*Iu)u@{DHWq&~uv%$5ldF^Xf09)AGK6bK~ z-RuB7JKEE(_O-Je>|zI?+sg*`y>q?mUjI7V!!EYEz1{A2OPku(#eeZRDJKX#x z_rK9CaC|e{+0Z_?ycMo(ds|%J;_i33&mDk(8{6Uq&v?8OPH%>P9OC2lx4E;uRPN4& zYn?_DU~2P)wyX~=tca?czVQvEZg7@s2}3ff!RRX$JuM*Qlc{~4mY}yuEp9NzHh8?2 zo`>V-@e?{)oNn}}+xqNiPrKRxafdH7LI{Cq`y$|}%D9LBVG&07Lq{8t_qwKSU@Cp-HfqQ^~73f<39JmD^7=j}h012*|Pgm7wFs=?zhbVGR7d0^FfL=979oor+n4e9m_`_c*gFv#9X#S`+;IlHDZ5-#ax6%9}P!;g2rrV#O!F`7MyU@X}FV?M-*~6s^`(b zNG#1oEWH5kTUhM=a175#9J#<_%F_5hOmY7-;)veHahAr3l;SvG2?&7%?!72wxkMF< z#DFbW42rB80nR>#x*o&raIhKzEE=DvHVumf*pyZt%(kD$=6RtQk+VYUtGXlVJUWUDf$*E zZ{8+ZJWus|n_@4Jtk0bKEG^k(CHd9!6!(!tz1CEtm6Vv$6q}Wl1X$|R6=+aeT4-yU zMp|kPb5ic}q_?oN!i%H;i?q_#^pLlynXn8`IX*SH%zlf^!3&0fO;QIGRLza-O%3F{ zp3D;fz0oJL1F~KpL&o++z#;k8u2Ec+Th6-0Q17JO@iIvMgstE^A0GU(zza!6zi` zN$|5x@@H6zYJ>&-uDQY}R>_w4lnYp|%l0a`3`O5k-C`Ma<`g=Bq_kqeTY$1wN2s zMZsbl%VL%EBAR7#{&nrvB`E(lH`s z`EhGEy=p(bYG<|T`=6@gG6p4}TJp=SJ?HA(i0bRjTW71)|Nc~~$W?<5#1AZMcI9iJ z88z@o@2-}bkofA~EVb84k(A_&^anLe8MTzi8WtfWsZ|X-Yh9FYEmyl8n^j$ZZndCa z^+y4)l2RR#wO*8@Uc8)@->Sa*r1rp)Rg@fjFOpSJTlwBvz06G!rFK2%LA?e!vzAMP z=v}04q=YVOV-un7hjU{Pw$TmU@K8I_*hRu!!yW}r*X)x7p7?W+2GHPQxXpOOA z74mDk8m)KpWA!YT?zC!jsc&%N>4xnsM1a zrqL-z+c|30UQX0{XvtdX(h;)O>O$0Rxz@TA+4{P?%gV3CMXa?*sMoEnK^&q`b%ZvcBe^ zp-QOtOL;5ldiM|V26~~Nsy z#*DYASU0{s9P}O=d`HpyN|?=ky=RVfP;s4gGoz_ZsK@7SYp6oIfB6W#e-8;;(gkD0$13OyW-7$2gXXg^~c%ek6j@0|9xo~2@Edzd+MqlZCtXYW+b z!ZwDpFoT-@!+e!D_sq;c>*@FYv!d*?43r~Eip^fs3TqY~xJ|g`m$2um) zgvWRl+O)?TejGL!Ps}ZJ%#V%_om#b6z8l&+9Hmqk>&Waif3ax%Vq8sRk->W5NBg98 z<$~4WBARV+OJU(UZ;bc7%||3f{i#mhE1M~K%0(8PC7G8?8Nv%T>9D}mO_<+*E3x-)gcvyB^Tu`gyjvKqzNhkG_=(F$v9(L>J_R$q?I_KHjw*{nYB zUzg8Xx5`+F^&7GMJ1!xzBqP*bG_kyTwXomWVKFg$ba!RMzdLlR=QZWW9g%S%g^9h4 z&#{W5T}KTAg!xe2)qjeMS1!HOS;$}SK7DstD=+Ufj~+!ROno{WA)+FbW^UX(n*ZBi zooQ!bem`|lQFlG{cX8rqNJ??t>*Zh;VWZ;R2KSM;LFVk=%&iwuGk;t*$|=9RLl1S& ztV=3>c~JQo!9J}(!6tiW?OxXGd~~zY`>xu~<)e&k6WcDAjag-muWrIKWj3vw(X5)$ z!{vA93jJ&ODOQsIe%3i9>?wZa=~yuSBt9g(vS+jN@x@Xr#WLg$LC58*?grtR&5}3O zu6Fdq&v!dXtb=4#J6AgGD20wAkpX{>-I&Tx(jBYbREWY-QcW{5=YfI;51LYdq-)&Z%`OdhlzRsEUPuq4>6MA|F z3h%$*Ck_l(2-n*`x!l9w`4m0zHEC@(Wn=s&>$0%I zo}267;o;bun9mg12fuX*F4?PBHvgR+5qkXz+*F^x-TSO_MA*&V>zY{{>S_kZE|dN@ zk(kYTt~*^^@ts8UKmEx?x}1+^8zax}%=>h8Y`V77luupC?+12mms748j1Q0K?PqVS zTIg*|XYGO%w+AXa&pv&Tsh$p)96&}NiA8@55uQ6a{1UkJqpq`SJ$jXY@<@?=!&BkM zlIy;CSHJf4YVXXH59?`z*v`APUgE=@!%xkhs3dBu+6=nKYF+AK*C&ukJJ(zPz5MrI zx5zK9>|=r3OBRx>zdy4{OuwJcjj5LXaq2Vm^Ofs)SdO&kf1S3sn*Ou-Wqtd1`2CA% z?F)Z{En)H|gX`Jkfb*>Di>J5#xXhgA+5IVcm>3W+g^8_Fb(1I!_)~NHvW)zahzP`a z0fvx*KpajsPI$ORZQej6lZ5m7aBcoj zEaE`~n`T|XNCHa`{)M??;aCdl@o1)IebGdQ?CbsYk^17P9Hk(*iL86cOuj~fpv`DQ z>0Fc`yV^Ug#&7dwTG5Hbg>I3^D)R(q2&?Ir<+>YT(`IZj7eG7+ZJKILeDkt#@wlr>g6vCgQ z7Hw?aq7JvwuG(isQ>yp<~LvfmoXDsU{+ZKNg znmHFHRGrC1!&4y{20STF0+&88b#ib}O{9ziYsMLZRhS4W63@|zosHVE2}nE>Gt&GC2~LAcrs-=N1?}5x;bDjm$$uPi4nq;X2&xe|~Ta zWhXRtUSbOMFP_*A?aLG;^w2f+15BvGx@DTDf+rOhUJ*hU>_`@(O(-<%@?*k)#RA7iI8?5m;MaT(%xWDJ@HW2K zApU_)uP_or=T-d3dO-YmE?&uRk~S_&U%KI04kXTS3Ps+VR{hYbBR;~r0#9Rri1xpB zC*w<(JzY`?liY$Ls~xw(2zQCyK5z$?G=&fzOVg<^=z~B5bPV2C$<*2^y($c*9VRzy zG{@ezG)dw!wY26aF;%(@nr#&Z@RPU@T5#uAFkPL?wH$t@UEMDuz{pTJj zw#(O0DFGKquBH(GU^ZV({kmmf32X@e@A*SIQtI0m;~(zr8B8(eF+F6mHHeVd=%Xds zTVT*4-18CZhvJt*#Jp$jW0`ts+m8o?#)Dh#&QDSLmE;UkoOTB>q3OEJIeD-BrMv%Z zOd-5lRR6*aDqJaVs&SRn}9AbD*%-p_7iIy%={L#7P0K(ac zM$M3$D%Ej9Dr~v;k0T(&cnnprJ-V*B^LyGW#K^K5J&ZWN1m<`HM`M&F1GQkSpZ3?1ZOrArdP_{5KCOVmj%RX-t3@R{ zQXs$TXrgRrV!(zHLIYU6cuPu&Y#ZmPge@qU?Cg{l1ZSn;+EV;?e1KjG9r5_ zDc#u`aJ<&zc^#%nyt9;`I#57^^K+G2R0T@bdsd$|%6jARk~OR7D$ z6PjZAyqXx@Zxk{HA0WoJY+US%OeQYyP7usB^IYmWmT`*EH-**a>Y`Q7MlJCE7K`X_c*~KVj(Dtf`R`T6`18Gs7UF!T^lsKWdFlvM=4lSBbaT=_Ute18puBUJ%N!G zMq&;*BeT5jlOH3W+2FBQDUP)p&P z-q8<=bgP+SG=p~gJ)H%__{wTG9ioq7pRhb!ZSadeN4pm|5opRBvB91Qn^9P%i6z4C z-vjO*XW+qaIko`lGb(grv^)u(O71dVX$KI*UZHCn7}V&0<0R^2`=vV1$JkkPajQ4Z z(D30jZqhu%qxn#o;;qMMNp>oI5)d4YOov5`k)E+*7mNffA1! z0LT|#k$Q%*#=A)$`>*ATgmATeKP%2-9N$!Yhwk0qCKrQG+>W{ra4#2mB+ANz=0h@e z{teh<^8hnLZp02?SAHP2hN^1bZDUY-?DxBU2*_qmBm@Uba1-o9!5C6upNfElkoz-S zz!e$jA3x@+DL}%cM&@Gy*RUP=9cWFDp_K*beK6j+7?x!WG}ljb(T|uYU=3iwO=Ite zS?Xiq5%iKEeQ5F%V6cYD6JdE^@1=H3w)7KF`%RfUBL!}8aZCbCfB1nwf=N5%2Ou~G z=Q=V?W2Jv<4`A_oWJj?R3fhw1!<)Kl0L1n7Abb8F_B!vOh-bJDB)Rq^gxgJEhcg2? zzj&(hYaa4Fkhfx-3>g7djpA@UzNvyizOG?ePgG0!2_H8L+(AEznHKvFepu1V{EG*; zL2vwWlvf8ulAJ{7;92nM;+aHG{*#1|5s6#Y_`32vVf*Rp777?ngY}e{xm0gPIYBuS z$~X_xg*SrrM4=U1R!zNH>-<1tFI@I1wV>2X7=b0iSfoN4h`>0 zus`-^i8<(P>=Tm&;##O7FVMZC(t`zfEr7-o_%R8!*KrKUK5KoL6(I^gfFFz}k-)PCx7lY}1A%@(<;=AAc;O>G?jDdR= z!KMqYooNWUH4?k?3{AWR|5asfSs_wKNy}^%L)R|dY*tMAxJ`I@a%HAG+Md01iALY zO(l1&zo+HtGUbfWa}%xRi$?&%HB@Hi*>ztjI&rY~OEv@?1$;H+O;YZ$kJRv6&(DDr zBqx+Q@*mvZ0#+!B-yWzRII1LWR6rQz(}-j+C)5`u4RTAd)B;>Jfq*{m5c6AZ&$Tgf z;Vh=W=>xHBC79nPQwCJ;Dc>{5%?xh-K5PqCeVr0v02o0`kc6&FBTm`emjx7WSg)+|31 z06g`zW|B(aGuBj=z@RVSS5p8TjZrQwKMjjj*^5da?IcGiLdX&5pb|! zEg^@3I|~SkU6xng^c7)GSY`4nr7Yj+dsYB(5=%b?{otTaEL59o96+AI6HyQ79MV!---3G5fJdbuTqK{kc*cm2>r8s#H{X&tUk2hQ zr85H6l71?iQF-cVZU@;wUN)FIbRezV=udgKs&2q0%fb>MN9*&`OyXsq(0xH5)vb=? zBunt1dHuZHPbuIlS)t@!-Tv=#nLhx73-Du4W$C%eeqHYM8!U-?3)u`#&$Bgz9At%R zi73p+HR1&|s~CFW2O#u*yjrm~maVMq8$DInLEHV1)-1L5`A6+Xq3yz!)H#uHd(Ud; z?zVy5pU=;#-8u<2*uDSsy5!yYOgRV@tQV1MAprQ_Elg^nw19)g{}fTpgh7ZJ0I{$) zNWg)lSWF0bE#Kh8$p3bfHn9bG?bdkfEfVhom?f4RY(u#nHK}tO8#N+{#Ug9XnVWX? zYf4xW)y3o500W|^{67jMxirP!5Q!My(YdFjM9m>AijB_l&1Fdhw`i@TXzNxJlv+}j zS{GF=?_PV&Jslw7r}?Be@Ljh51nEBpOW6C7OH6>;XqHn$2c8*13FbM@PYND|#5ViJ z3$(_AIs4^0%0YNu(u*g&{*ZZ^w8$lJ6rxLhm_2d_RdpNx7>e@lbhq&&zAzvu#*S?!Bzos^(`O-jF1eVHYJKXuBg==NXXL38)4ZYi3ke^S}!M#p+{T_&DIIB!j{=V!ocVB_J4xypYfZ}+KL)wST=%U zQ%wqVXA}Iddc=dAuc}H`vl_qzC;UWRu2y$QZc|Z#)La`iySC|>H!Dz^HKboZBfd^5 zeT5KeB04gqu38ek$#?eOOf>HBRT=8d!$wZwc_6~eqgv57-0ho+3D*l~Awes`Bk&#r zLH3h~oFidBo^TCQKR%*3RRm7jAx8h8hVRGR^XlEiZ>3LYdvig_2-0M896wOE=zsA) zx6pCbFb|mBf4bTYsu`oeG$@=vS}I{#N@9IgFb|v55)>@@7+Tr`A0%p|bSKM0>9vu* zt3bi{w)QHHJ7d}!T_YXIp9tsyEU)4qgh{X_J`HRzNw^0Ql=#Hq<*Q~&r{s1wi&|gb zK7;Sc6uXIGGqbX|FU#(Si0KdJgN%1#dla?e-~V8OikeW;tYiaKCKVeW3HF7ggl{*` zaSNl|Qzj_vQBv?@BObfguvff$#lbaJK(xJeSI=|BJZtT1L&}~`b2NQ>sy-zugd*r3 z5MyuM2kLm6nNwDN0-u2YLXJ&tY8g|bc-=dytZ*@_Cz5Pn=lXY*Rk*7~-z*trKs;mr z{s*iU5;Bd@@o`pFK1D5rB-$U((@PxtbZP(--S?9#Egn(sR%#q7*Pv<-B$58?H!e}f=>%I*?Ugbc z@9O8FL;T%8*6$h?k%mZ8$_Iz1AoVM4ZCLoMr7B?GD$1Yo5VG7@U0C)O>JBWMUP9he z9+-Z&2DuH)4rDZ!#K{l#9gSW-S!y$M={6=G(kitbjAp+ddMF*qFq&8_8=iTwnNsPq zrvoo=o8(dAdGqc8yKA}XL}m4Rsw2x^O3U@vFYVqHTE3B7eEBN(Ur`&&aO0aiSgh&p zFOQvxEXIEE!cjUt?eF)NE(g+3honZTuNicgg|;>(a@2D^NgO8e7v=3FpRO!teYgHNTg2mLBpB2=qvA*gTQ)ed=&!ao1SyfKF{f$@|ir^vM8ixC^ z8P;2s$VVn6TB4M6^A+L-cQ{q41w9sx*5pYNtSLRdQ0t&_ zx4Uvd2D%B6-io`LM&Vlx>2^Wz0y4(3UNjo zFUm(r+Ic$BUdZRaO`KMpPHYUCoYuiPpS~+xT5q4$lkkb0qf*Cx08796QAR-=~H-|=;cBx zp6jhNmwgi{^AEhCu@!%&7pZ{O^{$uvO3SX{#&#-?-QvpN6o!w()X^a?)G{?REWVJV zdE>nqUZUo0d-hvL&RGrZeM~66^`Pr=Clpf^?o!3f&h`z?Y2otZq?zkngk6j1sl@yA+C+{dFJe>@+)w)KTwT zoCy)+VG~y^Za$lP`>fnYj*RPo)l`9KfL11%xBy3hba~r3h5X5jJD^@weI1-B_m^r_ zl?ai3L`&2E-9aNRB=POu;2;fJL$jE}a9ezV^IQ$M+KUbNC$ZW9GNlbXiFBYmvl&V? ztM=uMeQTBn)2-<%A~5G(!!$}XnGnhGRuw^}+Y+D4xQ5H=?^K0I2pLK)=5_@mc5ZnH zeCDy`txpMw;Zg8UzU6S+{*krMU53^1u;-6b|NAG4 zL+?W+ER-C%vW|aEjB+}|0z%zLg&OBKTUW#}v zw>+xM0{AF{(hRx7O~3`;GT<{x+G)m=&lu+Rlpb<=qY-oAqf-%ppfA8}FNtSKLZIGZ zbRS^_HN7;Ri^2^Q(%}8H;o*2*ks$-it}QPwW(}_WV|azgckHXyB2kvw1y?vBgPlHP zQonT64H}$GqB$ttrPLcs6srDz5gC7SA4W_R{SnUw{34B3dzs7el4qFVxXeuZ*t6De zf%zJ^5tIkvHLt#ISvlMqQ>@;9jd@4Ep4Xv1tViQ+0{G`uby@QAf;R0z(^#bj6@bSY zji}9{pcPz^g?SvoRGf%8X^ZPWsD2b(!=;N=1*MiqnK|<(0>0P~xmghd(V?+l=0m6=B*f%`jZMU!FaN+@;Qt~4WP{>h4| zU`XmSntsXyH_|2L$59}4ZjnzSHAgH+{A0pU2ZY&4CfVSs3Ye6*VTvWy{+ML{lr099P)M>m{O+6`}0h3)O!=(l8g z;g8n+QjwrvsP7)v4jX$rrYO_r7)YF2>Bqo?{|AlZK5{W(N z4F+$t)GkLdSQ*~NDMsP>Jdc91l-242uq9Ysg{?Hy@*F*k< zcfVPoL#+c0RUKNqybokV7b$0>M|hu~K)-yyH_6VB6opk``!4puaN`YU0vb^ifwQstl>wOGmlX)aYr- zS0r)o@-ClUu1(q2{CzA1_*9c|UfpBg-@+R+1{4g6cGcfh&N~`pC=E)?CDdPT*L*19 zalFN8-^3230~b$O-X+p9HvdT5q%J{y=N-bVK?r-y73>qi=1X6Bd>>;T?1f9{777z- z3E~kpti`%QrP^eB` z*fLaxGhc)@OnEq16M5SqHCSmJyoFCQ>!p2cPA2a|n|2<06fWVX*{Q(>6+gWza}fdl zk4Nz3SN0N>+o{MSp04vgoL6)qg+ z#^|eB1jcu|tAbD!o=7Y|p%Z)F`7vG+o!V$O)@7MLsQ03JSdhiOUG0yy_{+mV(-AIK zYC1@>*)oYh{r*JpYyN_TK6jfSt%G;g*)tYhR*jyWom_9ia;@TnfjN8 zSkHh$ww(FiK2JAD-nyJFvyQngkWb1WI6)SAEgx1B6qer&QM|lW|&)*AgS!k`mAI8xdh*T+}e}rO{oubkLU7p zuhdR2N5K0kAsy7I&+j8=Xr9uBy^b2ZUS21@av9<-Y2x0@YAYQLLnl&{yW`A7-Gv6C{4)KPA0# zR=RUS^GQQ5f`yjbIWKfXi-lr_|9KvEIh5jwK^zbCv|!q>R-a;F8oR0YA9(7vgtkm> zo*gE3Q?u>mGHEn0Yoo6&gAVnAj$oL=+l?z{R)X9#LPH(Wbrj-tgPCP6RQzBA+!v(9 z67jE;RJkpLU!dlu90w&?Qm@U~NELm$-uCE>DaVT|8mTAD@iXgU?2Tj^gFOT1PU9PG zxTiDH8v6x|?MUWT*yk4xMSg6nVJ~<*wsk?rx}X|jkkXJ@ZYBYIN7t8lLm+*uG^JRf zmkwUJY>*x}-!zHhleZTl;FK0rpkl;^YmTt_i)>_;p^-o~KN~dB(~t-pC}wT)J1sHx z%7oENt6qhFKr(){S1Jh4lJqSSSBK zBG6bLqhim^8Ji12ViRpFu81b4DDdWy7F}r!>8cfnw5i8N;oO*&AD7c-rwpm8mgFqm zLNmG|Zrzw&T`WjX^@;HfT2Tr?EQsXFqMqhxQ;$3nqvh(^lUy)q?AW52yuV4s|7bpF zGs2S_$?Ob83s^C2X`UxOJS7TjuAi#J$16@h#H4CskEcvYrn&ak)TE#;ol+PLeUjG( zksi~9LDRey9d12qn7~_U%IlPhB-_eu%Hm;4vNJQe>%JZag8Q5ULeMnJ)OJN^7SBe1 zW0nZc>e^p&nsa{!dv2g!XR7UDt2uvTn$`XL#Z~{ouiX$?N=N z_OK?Rio9^ujUdi814cPr==URwyX**smn$bvXn*id>us+h{?IRk9qyZyx2%(m#(Gdfa;az+3cAIKep1vFigtofJ#Eo zt{#Dy?67$5pfH`RaMc}J;%XOg|%IXfZO&qJlfTi)jEP=4M3H4G?Qz&=HaI|G(RTf*A znGafdHSClroQN{Wu_RPxY^a=>om(^Vwx(z@j>BK;t}o2m_xVmx%R}hShP;0;KOu(G z0IlIh``r6!aR;i6p17YW*=SeH9|F1tpoyuqhwrALM>~4QS?f6E=0}TIQqVPGz>c2s zgNi;)GPLJC)dy=a;vTnfJ;UgWM>XFF@Y76Y4Owy6ubm(_C!%eeglN)GiFo9OC^s}l z5z$b8^3iZ+#NT%QtS^DbM#9%rA)3&}~xHOce?vzIY(*nW(E%r@M5R|A^hhfBVq_KK29! zEzseofEZ4Og*q>X7#K$1eAn0QLQI!KqR-_q=W%X$=8((K*1i@Eho-JBHt^(w7j{Ej z`ZgP>!%%t0+9;~KdkmMGtXwHYX)c9*j8b;y&3YyZ$Jmrk~ zlvnN)XZYHy`t>S&pXnNto+{Nmlcn+M7rh+XcR=b0uRwY_hb zJc!=9|M)$Pqcl_txm?H)ramq4t)a>p3f?ITt+Gx+L0$LdLv9$mjy_3x!_IwT)pC+- zy|5sqWfH{hm|z`C>4oSXe4FdUbB|{9(s8!X6}%&!9rT!4RSjHULYn!9UVt`K7(%R5 z61sEKcmriJVhnxs$d;QrpXbaP6Zo?s3a_Sg2Lpu8CTU({#q?$18cJ0q?xE5L1)8!{ z$NM32Zi&paLX)I{dTwc68l)=biLbwLd8Jf&2Rt*rC3;QKb;2=9NnsQW&{ySrZ|vQx z_sH%xOO;}JO`6yt|G)&h zJF!S$w=4_sWj$8?p$3|ts{~Tnq;JC662z-Z7hBWgJG&QjOdds`|7euP5YLc+|ELr@ z(Majnx)M|nj%X!&I|j31{6|8|{ow20#I=>ng^1qR9^K}LFAxBX%#JN|Is3!1yiIOU z#Pp@xre8=PvZ$T8oh)9_>B>?qJ8~k7=_f15zU(>(fF+?|c2DqY4&lauU-j;SLuoxj zI>OsiSTmKvGC(j(y@4FJu&>|L=kosgU6d8$-Y**8Z^FUL5HR%*XI1Ao|FZ#fr^TqD*W{S;$mSTld z?PiKI!Te?GE_EP);0*B>e(uf#B=D-%8SkC)j;D%0o2_^*QG^q=^!}c?)t^r3{+0zWX_uVx} z*><*5g>Bu|(Ku7N#H(nh)vx1ec|+AQ-GiOpEf?EW3-z!5`=@wye)?^$`qlOOfja2V zFFCFA=K-0J<=Yqtiw^<|6Kp{Q?Hep2f~mEjo5A#!KAfS<&MllD*uACkA2=gqxx#tV zeYhe7%38Q0McU4}qQpjJxud04ee(SgTP=@+Z+V!TYSRx4! zGEa5VW)dy5uHWsi6qGZ7om0ONn#d}CQ<^2v+fvZe(%3p-2GD67+x>Kw=lchAT2QTu zS~J=H!&*xvq6Au<^RfX|edq$OvK29?vR>KapeW{3pVXcA&B{(yn){1M0=^O1La*Gu z`|cN@zt*~#cKrEib)akUkJaUcus|Q2moo3tP``apGB{UNtDCZYH49x5`-Br{p3p zW~4&?yL5)n%ksZ|E$t{)M+LiJXI~xdXp2HiZe6!oHO^!$b;fueq<)*N4eu%yjIxKu z(viBLN$74ZErU`|)HJ|)JMn-{kiC}=Bw*$EGS9SowUD-pxLrnXhj|7}6G<}u-`A7Q zmz!O;U%odgw|fW`?aYyJtm-j&>iT5SCY|b6DYwJv=xwMWX$Y-;V)B~@YQoeIkcBzA zn#LkAS>+@2$#_4V0Z(rUt%b(@cMSKxMvBpmOJFY1M%E7f#cxP%^-!BoILzy1kkUgO z)y~-~o)9J9R{?w@qx6AmYbP<)zx+g%!54u*@YzVY^SQXaMu}4J9brlr*R9yNnjMKL zlZltfE4PR3W;ZAz$oOj0 zOqsp!_!$Wo3;Bk0uPz4c#2rPTBE0FR^wtfnA<5GC)dPQ6@m=wLX`g-{eM?YcHNqAY z$XMsrggtZSH#;V#n|}&`d&^IxG`D=I_ z%{;KIL8y2h9|!;B$P{#x5_25WB&V7NGY#%nA)4V7URrNPVsHxPk|g;4@#PGtDiEDX zJ5JnIo)WTIsl0Zl6i)tbSt#hjtfjw2lk{bVR^-XWu-*4~*@57%TBdKSPo1>ViYT%q zWJ(0rkySIG-gftK2bu)1pGwA)}{!EAj)rlvR>b^?N$ zq-Q8ki8&Vb6(Jhb7ZmXX$q6RXA{Al4N1WCP<9DF)D@m8B_H>}{JmeVbbpz68SsFKhf&O$Xb@Ybz%h>1}$2)7%yxgtM zq@lMfFnpwi-It*XS3?_@qK`vx0(! zeDj6i>(UQ8D&@C$k#luz-%B;HWrlOJCKLW%nXlZzLTrS7ukTFHp>!p4N`B1wn88jmzQ(+>E#bNg7bkF|=Van@6gu9^+ZlPmuiq(5Q#1Tg}l z2ZnPBo0(6gK5E;HJ!wu-^V;wpvg!xv%A{|_Rr(y!*!}o^==tf%j_;VC?r->y_U@3X zfY!aGws8#ojq6{7g%B=Jx9gg?v6*gofb%VCdPPMN_=LTw$R>Q-m4+jYK^Yz&z#^@2 zy+xu)kG$J+tDUZ8b#-|#w8yrd!?6(~$iNsw0}(lIYONQJRMT7r1SByyB_>|_?}aL9 z`;0|FCLX3~6!zt_QlTl@oSOgjnTafUl>jd`Owq_S`Z|wd^4F(CQZ4iK`^T7gL4^C0 zb4fnSg%2-6>ymWozm`Tr#{ax4&nBy2;Ply|_rvk=n7e-Qs$m#Fd!7ocC9 zNc!&kMA1F+Ktgh)m6eif+;itSi@G;m+wYoU^UFuh^b$I(RvD`v$Z5NL{vDbVeC_(a zyL96E6KVHW=zlr6ojUqka_ckyhMPk~`hV0lu1>Kvw*`sVxO>cvO`33O9*a0-ToLF~ z&DU=h>_jZL9CMj331SNs^Edoc2Pu^VVX>-wZkb;ydtZbR%sOI^3gEELHT|>XRkPnO z_$gP8(T=|eQZoI6^1WDEkMF_kzkMcOiD>*umo9yrV2Bz0iO)D1|Mq5%Dg0gbiGIc< zFI7y^hswmZ{mif(#d_lqXrj!mAlaq-PmP5{<;E-JEnY&OTRRpC>a0>eeb>0~cXpMM zXvw&DoC5L&tj_yB^PfbhN_5O9`!s}d-xH2t_i0O!cBmrdOx?600LMXfG<`4y=D z!Ir4@jQk2(Hz9E=?n{{6Hu8+-4(_^fHe%&v3% zbGr`13EZ@z`!D?2SrBHrdEW3Gkq!wQXLdQcNSH@pSrikJ20#Xj;V?9Pu=c;+*s-j{ zQE+4lXFoL$+RY+5S_D1hwLWy7Y#@sP!!2-fS-b+%x)WJBx+|%T!14_HYNyRor48KM zBF)Vr>2KzGVOFB5)%8ls!ZQBXjKyrDMV#l#tvhK{9vi?vCg`e3=euhQN=oW!YxpNI z8`#z+?LFo{N&UBVh?xQ>}(L|SSPY9%YdC3(`aozn)wiokK(pi-F|Kg zv=}`5866Rwtfxan$F@1X^6){wEC(p*UGflfdn=Ni$ zySPNX#S5JS2cusi5u)B1Viun-jxu~PTR9df?VOM4ZE_oU*ZY2|e}oNPt;{Jj4h{lb zpbm3}UAN)i;#`eoHN^**I#27U;(%ssA!r?&X=lB&l=d=qON9rlri_9j)Kl7&lU> zCE>t-3#NY-Y(Q2GLRbC=u0T=0NOmMmLSy7q4I~VnI$4q7iDAC94A8mLfarv;FaaZ7 z7~G@`vQ$n*e9Q=LQ1tA?wLrmt93X0#+Y!u>>a7exwd1i=L1Pus9qEd^$dT%$o;+Pi zL-tJHOrk;5V;7b!y0?OBa59g~|J-}wO?GEx5~G4-PN^~+^mn>Agc zY4#pz-WxQ1CiuxjYYJTJm855y8*5IcdD&)Xo+fAxpKbP1ZL*S7hDv!P%pP3jeAFGr zD9faLR%bng68zCcJQj3HCqih88JbWs2~c!C=YBW={q)%i@f%fv=XM@P-E|$Ltc|x> zVK6>jXV93?Y)%e-j(nzPdPYSKQWby3&`JoWSk($i=pDakUDOblPLkDd%E)ZiVpI%) zwZvgbIKgXiPvksf(5#}`NuG@qpNV*Af_RfKBB!{JXNJDcf~IJ}2&H&Ng--Cq{&;6e zz*EU7p*lA@<&Vop?u25FcEH@bxH zFwYdE$-D@uZZ0X8wu^}Npwl#|etv0}mZ_PZDVnCKnyx9EwyB%GDV)ZsoX#no)~TJ| zDW2x3p6)51_Nkx#DWC?bpbjdb7OJ5hDxxN;qAn_jKnZ)8D5FNIq)zIHtcgIrM4ZgY z^YDzL6sY3d$y&-}+j-ED0@HoE=WXC9rLHQg9*7X!!J(n5e3a2Ussyy8Ua}}pv9u9; zmWdKfmW%?UFO8>|rp7Qi>4`#Wt1c_E+6Q;A-zi{dd_W9LRLsR>3_f*?%PinnfXd7C zWl=7X*bQZ=j$M1os*yIUx~?mJxIrnf!ojhEs=ogRWvo<5#LdSEN8NzL-Tcby&4gur zSiXrLcX<}&yrQx`*R;*6wk53RI4rwHti(FR7Q8|#3<40a0xBTLPf(Ba&`eR_pYdQ= z@yL_+fKOzc82JQ{-nVwI(R%=ri*5Hd zfI>QD>~tImp!mwL6~z4^LAYScLm5OM`4J!q5+Q}eaP?d8wTT#k(`Me+^^8&}^&nZjnyZ>o&<|xKY%(kjUdHeu zFZ~)SREchn#>bVIu0ceJghj8at!_V2(iWjd>^7f4Fj60}L}E@-){!L9C0k8}>UcCL zapvZ0hUrTHXZ?2Yx&{f}GOv4V3PS0J|Nf2Qeap5CTRZ~6t9{A`zGv{LOlF9h&DvW8 z8yyl&6LJ=t4o4EiH+$ZLwdnL ziG;OO4lJ%M0L)(PWmEWRuG_8~nM&J*nsE`gF`%Ny^0IMpIB$sk$D|oV=uIy^IZF^E zAfs^Wvq)g2=)|E-!Q5ZQr;wPVh~)+l^b6&rB)68qN@_82mhX9 z3I{>t?biPEA|zsK(m5P( zBnBzvFQ>D_et{;mb0>(dCUpOTCNNlkT!~uphY@JYJUL!L$mMDZ0b_oV7a2=mCgv1y zi|>d`M>!}OTPAPfBC|a-^YIckC9yhR^r3!%`?Vhc7+Qi*XG0VeAz>VL<}ZzbCnx7` zfSxO70Om+d+%d}7bbgbkAjK(NXSe$B*9BK4esIVxR zcxt%vkZX>iRF5@Tm$g}+HCm^&TCX)*2TWVP zHC%_uOUE@`*R@^WHD2enhRn5I_qAXDHDCvJo?3Li2)1D#c8GLUn3~njiYH$qHe^ez z&)S3tQ(t8VCoiJth(7;zWOp{`T5x4>GVluV8*6`O)jq7ft8o4B)N(i(#7xaLKQg)b8auUo8EBda-^{KCMf0}?-eTt zr`H)1WvLK00yDRFzp=eFbWQ=)kc7~f(UsZ_sn-FwaqHQPZFiu(FL!@8eK$9mp;at0 zbae@HH~kkZis)>waZihN+Sa#$%47SWwV#OJm0!i}$#k zYEW2xj)rP>cYpsM!LlM4Z{~>`Z;2|mk3TsyLMm|t>3mu^k`5s(0&RV&W)U7CSc^84 zhq+Xi8P!PnnVlj{q$Ws&+kY3IFM{}*@7IU(vY6NTn%1(v>78)vlpHhoo-ZMCfAf#E z)Kl8Iq1&mT2jyj$PLuZcg+_E}E-bFO`Dz}zrO#pNs4LBGR+8Ei%xu))C72P9g=79@dAGsVd_NZ(um z6d=kH$Y{z-J0)5~HQEHd*GIW?yrizd$J;znjC|;sycWj1OXN> zL`?=+8Z^$BkY1@(jm_0;MsSC4QsUKZSw5!8M26g}U&%-;`-;yaIArxhUKg9AZ8B}U_sJ5#LmZr6M%sjkbxM0fsE!)8jt}Pl)MwH{jj|K zL2v==TS4o4eeZC=?_;Tc1c4E-zS@`k)%WQUeEb@mzCn-y8-M{Dr~w;Xe@LPI^>6?6 ztARl{0UEHu9*uk&sDu$vR2zjQ1in@tF@cY~QDfc@{KHm5>{wrZOt-JbwHS;08w5a9 z(c)!bK`&PTBm|(O%0Yo%vIJ2$kzz%Q6o(MhQc%l~ix;^p!4ky_6D%T^98vgi;1r7) zH*)lt(218SQ?y)ZY2;&108)q`@%d4S8a8a&991)uCYqy9(@b>2rp&}4Y{*O`!v_Bh z8>3#C0&r61=}|E}6*_U+#wnYqL*d4iJC|-;k?p{h_xXE9tmcb>?F4H}77N-Lg=GmBz|T9!;?q9uyrAvm#c z9x`M$mfgE2D%qVxi%W{cnFQBTWg=_a0+&c!xV!i7u(P2^Jc2Vx;MoxY9Lb_3dE6j4 zW2V>AJ)!U+#Enz@u6=xYu{oLWd>z{^m7sS&1A`|gx)MVxHpFlu2rHbjBCX9h!|FiG zFw?9mg|(M5`!h=Y$f;}yP zgM*5?wi+>^q*PN#Ga)Mq5P$~h3IYl!CQ8DKC=?39CbR%RqPU7kV(+6PywEYBAQ~zX z3ooElD2wbc1Aq(Kxb(tHscedpyuhaL0?QzVP)V*NLdv3~C6ZWziy{>QQ_O_&+_TTL z2r6<3IPH>RjmhdFtH>=xOUMYMCPK|XnjlQ*s;tHgav~zfEDg)6E)=V@P!W95)?0DS zRo7j4?bR6;g|xKqzD0d9Vv2qF%|bpcz-#laN&WxrNeOrpn(rbf zmV4LUx%|VFt^m!YNC^oajP>GJ7s5E9t*HIj+4ek6$coEI9+gy%eQnw0mtl@s=9wpo zg4l&YoAE3M+WmWW~sCiX3fUa5!b(kDg7v?|Q@8lK3A zC76JEUvH(ex*{ZO;&*K3=5peSx8X)sA()C|Vu>vVMzf-dv95^jr|+hd?S!<%7cQVA zp34fO)F?v?E-FS1)s-{0s^qPN24D!HO|A7K)Y>4U4ACp2+4R#yD$c9Xy+66yC!!)(fa1%j-5A9PE`rWWnm)eUF zl(3b_C6IDe?A+u4(7~5@?t-GK;1|IdMlp^tMO5ff7dU7@-mxKM73oSE)S||@$jeUg zIRd(zFohk)i(CdnShuFozMA#XWC)|9-~PB4a{<93M(F<<2?55wL{h|&gPWhj?t(wQ z1YuTI?AYW!g$7!^g^^mU$W%BsmTX-Ni)3`=D`6Q+SZ?8Vk-?JgP^MmtP=zX(O9?I{ zVKa$Xk#LTaGv-vH5hv*r#MvbXZ72iYNX9WHRfsDSAxp@%!b_25ZfQvg*&7vNtz4q! zfwFYyLm?VbUOk~lKT6{Pw@4KR3RIyX8)00w1+XP7VQe~j6M3M3lPh2}r2U$k+H%4# zYc4Y;)Eec7e+(4 zWs~HBUa_oqFT!E(UxIK1`razP`z4WA@8bUiCERyR7=@7%CAi08(|4g zn8G|HZ-OiAmw9HG!yWeUhc66b5o7QP1Rn8;QJi8GLlna+cJYg09Ag>JxV(&{@r`ku zV;%39$36D(kAWOyArG0zMK6L$$jDPG};LR>@$ zkDvr4_Ob{}xM3(^w#b(qt(P!lV$gT_!=5#97eD|S6odGPBQPO}k0^o_uMou?dXi>H z%UL0hz{Di-MF~tq8q&3ML?&SU5mo=!nb*Bu-6A}32VKWG(svoeI>G@8i=?^O3JF6p z!hvjL8-vjk`GPQ_y$!wGAsp5C!bRfj6JqlP5#bOz1)+(pW@lr29ouO3L`t!aT~H+5Jvjrs_uP|)`WM@n9JinY0Ky=OZ$!hA48O8R2+Ez0V+ua5w`?E)Pd9WNr~-m|GEh(8SC8Oc7PzStF>%5}s)QxM9!j{zf<|a))(9151ineB|{GfHTP4@Q4S%!Kbcl z)c1t*f(O9o8K3&N@1FN|2}C2la0g6i!VzJZ2qGHc2vEEt6OKs!A{255M*w2$TSz{G zhZ2Tcyn_4Ne}(ZClIA+R!Wg|+#2jwX356u%8`u}Z>Ti*dIaC7>3Hb)weSYVQkbDnl zPe{nOZr2iG3tk}=zJL{k!52i~mcYyiK;agI;S~yD;_iU_dI1pzq38Y&2)>{ce8CuY zp%Kt73|_(eO7QzC;tc;-p%==J70gZ{oZ%b3Z6e@L{;J^*(oE(WFCogU7rZ7MqQU15 zZvOrN%?%)iBU>lNQ0KxC@v<==6Xg#=_tX+yE0;VG!Kl49?&Z z0bmaVQV4`#4p>1Hux}`g;1BlT4?wc$>Yxy(?iRKH2nvDZd|?1#?#t>x7jMB4E#e4; zkddCj#nT0dL%35m%Bcvk?I9faFRJ8Ab8SWG*NHpcIzw4uk*{ zzF`~c4GaH)@+ZHHCbe!6U%?B5G5`&;3nxMfAFUtd0ss?})xK~G=`!T<5zinK9czu_ zH1o}F@*hF-uY@2C%~8!zffZ&@A?nT;D}oYOVG)3!6f&+Z(yizSG0cR3>`t=FPQezx zK;hC1+eBdxZs8k}u_9bAALX$SYcU3;Z5KAu3l;Mjk?kAPOcTOk;hr%Z6#^0z?he>09dhbE`Kg*Cqhhz^$OALPyt{O2T~!=0O}wiQz;fXb(T=?Vlw{=(f=s3 zL;aR*?Y1$w&Qd$}aKk7KCGsL#wOW>s5+u+rYBL;U^j34#H-WQPnT>20Q&=l@VgXbgj)<;|y9A!fDm4TE`Utj!kJ5Vp{>A+4Frk*J1%vVyhQm!|!tuw|rkI zAe+}BV3cGhf)5>G3uN;Jhb~9Mp)Z;BJl`w{fp!_5s4!3ctK5ic+N zUaol!_kM#A(vCJEn0D3Dv^=>Dfb}=}nz4Z&6##70C$^y5wi7?Ap&I|X?1C*q2hlEH zf0kCmfi=C5faf&)+!hmhp%;ANhI`@V9JSWmpb$<{a1SqUC$%puvw9EH|CUfzIrV$Z z_ld_S4dwSE7J(J0w<2B@6i)IFGIDz-mt?`Aa4sYcM+Z86{3N2hu3ovls@+? zUL|i23hqFgQxj9qTA#HUC*tJ_AR=s?Ge{Exd5z%}V$eU&aT<3J6Grb6A3+Bx0$KSuU=8lm_8$L$7=876G1Ort zmqfkyjadzsQFm?k@#oGle4%)lQ3rj8!ej+f6Ep$(JViD~GR^-O@`~ePW$PF7WbPJN z!5Oe^J(W;TIoTN+0h=Y*7>q#}rq0~RIT5gsV3XDV7V#T);T51Q9R8ptgOW|}%uD4g z37_s3iq6~6u@=7po1Fm}s1gADZW~N3U%w$}4KvQPHcrW|7fSH!3@-|i!Bbcv8j`^g z#2Mwtxt!zJoDsoOif$X?8QW~HN(Xk&!r{FhE~MkQoE0H1Q>ICy8RFsXT#n5i0d6c;Y;KosT>DFMJWCxO_uzzu{B7aTHbtN5yZ9{wgLOpu@|LR+H8&sxoujz&;kFy4%wUmhPAQbev{=^w_xe6 zYkT3W2e1~S%@-O$Y!jjrszKV40TD!w*y3}FxpEhXG20S2A)?_MCJz7r(H8^pXGsth zyDg_F;;ze6A>^90*8$PU70eFyisNh#5OJ0jf)3`owDDL&H&$cq5mbY@msvUBe3?S4 zdbv?74BXaJ_Q34WHj~4l6pZ)_%u(0q;13p8Fuq_%K`6R?V!KoG(dv}#icJXIK)flU z7Ez%Jh4}UE;1AN*+Oiujwyr0_z_07#sUOp*jk;*{!c(RCVVV2DBWw@g?P`a$cEy$) zX|cSw*RPDA4yH~!=R%T=E;_|4V|yjE5j@0kY!Uxmdg;2mBBE9y_P{NPl&CX|#9cZX zBs?zeKo?uQ#sXZ#b=)6C!5KKZ7dl~vDFP7Em?E|S6Fx8+gs#FsAsU>)8FpdtG*lCI z;mOr`$FV%iwS3FDyvx1(%fUR%#eB@kyv)t~%+Wl})qKs_yv^PG&EY)G<$TWRe9N`B z$8x;R^?c8BF1`yjGxHC`;o^wl?9Nrzzr`)TH;xLU8o&KKGWXWQ`FzqvGtc=#xyd@X zXM4bh`&K%AehnSq=25sI7P)D&xNX@kxR=sd9k2-9L?nIKFq1PM8qo*c(oy8qY16h{K+#l22i(1$px~Odo=Wx9yBYmoq`ZJIH+7YwBn-Ja=9czpD z-9NS6?|pvboeFI|Lo1Zr89ss%l(ibeF@O3q=txVm;CI(R)|jdMkdm zhx_3{-qfYDVkPe<@%Wd;UE>i{)Qx@PVZPyQ9(6eGCiymSXMNtuP~UyMQ!&=vlX`E7 zJ}wZG)QvaS>J%0>!&)y|h?|vQGhmG)2zh%Upm2*$< zhpj}@e&sb4M{gP9qaAg(-Fd5*L^WM}>-FN9`j;U;x$D)@eL0tnKJ}G*>T5n_O!Gb^*5JdXZC#a zsp-&RJG*{+7^_v-S?RWnjd65tk}WH8go(Q^OUu4>Q$CJ7x$@=An>&9VnJvt~a5u`8 zzEdj0v(pg4K$Q|2=+f{ll^ArS6|^n6W1y zdr?7$V1f!R$Y6sGK3M+~aeckE*Ka$S=80BkdSH2lVThxdSeS_;7N;Ru z>2*kRq zs1%YzZpmerUVaH?m^AeU9B(v=Nz`pQ$%tl~ZoUa;oN~@N6@JqpSznZNUiRLa_3a60 zpn?ucXrYm*I8%vi8aktzJhjMZq>@fbX{DB4ifN{rZpvw=o_-2ysG^QaYN@84ifXE= zuFC3yL9_~Mtg_BZYpu54ifgXA?#gSgzWxequ)+>YY_Y~3Ym^d7behDg$UX~gw4y%I zMYTr!Gz1%LaIya>6IxUuZMfo&J1G@#oZAJq+Je!o7gbzKZoKl&>n0NC!eItbN?5_^ z7D*gIZ@>Z%OqsJit#L2FycR)l!wx^poD}y;k&_c?Tnxs=X*f|507`&Ch8R{Tkp{Po zL6HT=5G9dC5)c`I1rt+5;j%!^E|J9%T*#covK2W2h0IJq;e^2eV39@ASzw`25KBbC zM9UQ!kp&b+1kD5%MnlYX*IuV|#Jy{5J(CjJo~^CV2MwWywrzvK1{p>fOm-ArEK$)E zUJP;25mjjMtruEEk+&9E0Ir1>SMa;G;EFrW_d$Of&4Wfga+=@cBid;bpDgyu%G$#<_f$Jbv z@B;S^;yL;Ozz9|FLIw3EIsgnoVHG(7=q$1Y_pQtegcAtoD0q-14DNnB>>;eMz`yjx zp$eCaLk)3auXC;8fVYE)*~$PBE5r>aMwo&Xub73OUGa)gFxugkAQI0-PK8?dpbe{c z5O4o6P9UC(oj|FhB10&n6X)2z4GN@=X7r&S|0t>`4AEo!(_b9ccN2-7i()-N zpcALaK}g!f0?NzR3VE1I6@SvFa<=~LQXrq~V;*mLytUa9nDneCtdfYYpG4DplJsOh z83P3`FwJw%6kZ=MBF>svfe9YGhzkXH5QA=xmbyF$FCl8rjB0dL=0cY~n|R9wLWKVd z|6EKRr(nFw-BG0}@m4xvVuW~BL<#F;UoZIx&r{-bqde_tznTe$6z1er`xHnU*sw<3 zJ@A@ZxFFMBRzkHUfriLSWlFYCg(?^qG+hm`+c3D%Os&%b}dO`t# zQd9uIO$})PLm6~u&Bt7Dg0d8d4zIAZC;-llY_w`i-4}%{L}7wYRpAx^$Hg21jtNol z91(L$$F#C_vz(37>(2EAxU!+IMu3~PL{`$p(6pf!5vJgVr_6*lZLyBKLRkTT1jl_Y zaed@M33-dViVEbSoh`0$Kjj29sG(^};FuKi+ML-9p|7$#!gOu66C*4ug2(^uu6H}7 z1l^@!CQ@ALch8I7^a^CIXDb7BE%IFT%6GoTwd-BQzy+adWC&$o7k&Q=-~bDFzyvO^ zfe(z}1S@#K3~sQ49}M9LOL)Q*uCRqKjNuGx*ui($19E~>DG+aX#KsLoIKq*MsT@cn zLU;rvC{ZRYL1Yn_aD$eK(rq7jZgWSKF8 zQBQd)-JSxim@uI>Phs?m{zi}2u?vYehC&;XQpw4*8y5+OJTg&s$rTQBVHqeH z-tNef@q7?PbQvOFaE8x+&We<<`%YegcQ|^nhcG;X%dfzRyYv52@B*oPD+ZShVfroO zDv7!+SI5h}V-9v&QG_532gx1QVGM{MqT&bn!Z+f*jkoV2CBQDzUM8^)T_0o*C)TgV zp$#LJf21|eo=t^N68LoE$m%J7dDtJHtLgxO=HK3XIFbR8LhM{Xqh2?qu_O>&Yoa9G z4#Z>Zf~2RnJnQZec-L7(AFfXw^0dblS{e?Kv#0$aYu9^?qEvT{Lu420XoOXKv5rAJ zCL^lhjm3fE8T43YHHarXwQG<4R#6@zZ>|PJD6x6?q*>CRzla+UVFV=MI_MMOvW*>M zX(%E2>+@kbVDMz03b8)>{BITRA+inOPzYnjcF`wd!Ds&wd>0PJAQO9FWU(d?9EWqK zcP1G!dl!dt#G!#5k%89Ne;+t2+XoS)@MX8a3eG@e=;n2?aR$a<48jm@x#oh2P!XVT zV&RZ}6@hEtunVt1bK&p@(SdLgVJGr87kP4Z0Ag?kB6}tWf={?Am^KF$u>~AgWWKNn z1qdRT;RYY~YDHFNxp!j1kRqTEfIa36dvJY6fpUUZffu(M&88z}B8ShmhERxyni2*> zXAwrQ2WJ2PgAjg2@dauKbpt^Me-H*wLK&SG7XU|pQxb`JNQtDf2g0xpw=fgEw-k)% z5vP|JcUXy|=qtE(gLmd@DxrBQC=^OaZR$pfv8exGqTmeCkPN-h34Ui0fZz;GHx!7H z5}Gl7vPg`@2q&LmjLE2s%gBt)=#0+@jnOEL(@2fgXpPs1joGM;+n6Ym$c^7PVUE}& z0a7R42#)9IFcsK}ZKz_yh>q{*HJ(_GIF=gj2#@!;S-&A--6)Fq=#Sx|dVldJHX$AM zc!cKoj|pikI^u@QhGe9X9s8(|6B#Y8m>2CKjs%I2?naRv88FmGhdd#XES7j4X_5em ze{K;L{4pi{7#6?HNi6EadZk`5|!#I7ZM~_d5m9nBJ{pSCY5Sebe0c8f6m1Bu29-@RwiE8#YAW=t_ zZK;(hQj%sdhb&?oHsY3d$tv{7d`;;mOyYWY37DnAj?WjEg-I{27-sutn2U)lz$ko- z37L^8nUhJGm1&umiJ6(HnVZR(o#~mM37VlPnxjdYDM2mPq8v`Z1#48At+^!~1qbPp z9N7Y0iospWBYo$s>vc2aI$RK~Ptv6*B%+5kbHO zX+Q>Gz?#xzog(v_n*%arkOtWq6eyEI=p!}AiJmGEHcE7x8sP*Bq&sM!El{*Mwu3g( zxjfn8Hf#Vl(4_?OsRl>2J4GQ_B2@oa;+dY6c{-^B0ITynHt|_-Kv*^Lo@zh_*Ycm+ z0ugxST=L19w!=F?;5+@KJ7DlCPGCC-+7se)N2ipamYF~M(?9WH#pYo=Tc6=GC1l)K6tfMWr+a#B>mc(^#@arIjg2;GzVDv_HyJ6Uxb)6bh#N zv{c3!QfLrK=0&J#iUxPZsDVnMn{-J=GX$bUQ!ZMklPOHZWK77!r(-glIKif2x>RY( zK5Ss7{gkFsga%~5s;&B?M1lWJ7NiA@b*Yxwo;Sgp72~L58m7?oo`$-lXj)CZsu+i( zJb#lwwThmwDVtxaq#h$lp(?1-WU3=2rq${cL2*(krL0uC1wf^XD)Fn2WL`(LMrpvG z2N48q<1y zpax)&G0OE)2>@VgDuIcNrngP;X5rwuew(?OnF_by zWDwy9x1b0D@n}J)x`Yb=Yqtwgu?0+Ky4COpRPkjEF_e>VXSnfn2k~ftKoyhbjjyOB zuvokAxC`Nsx)6bBrZ+;V__+XZ2H#K(LXZ%S0CG3+1zV61ww5AB7YJq4|R)kb11la4puN!*- zjE_dZWnqvIrLYdHU>xTw5M~$-(XbB5;9*Mn5cG?9g18M5#|qJ~2row)zqSo<2xL7B z!uJRSxCROgQFa%Bz!O1&OxD8WOOPGWyd+@+nD(^*@V$>fYVh%T*sGXm#)KbCghPCf zLhuLcfD8n&WYHjID*Or{=LSH~2wWCv%LEcM+!URVcf%JBkif&$$G<-;mIi2+AVS7O z3fF~MblYoc%lo$Lm^5Dtzocy6(T8~hFOI3`}F z!H0a0xQ71<0Dx&*s}bjmYm?v-;WmZ;d&lAM5^wy4JtheV@rhGs5-KbdV>igGOpSc! z40CX2D)Gn_oC$(Kb1@7NZcqp!r*czl5Dk$Dy#UU>0M1;d#qx*EMsOW>{CQnDe?+Ow z--v0aunyrn%d`ssn!sf8TM$`z!xixd9_M=-g2!BW5Z~*^AhKlPfDAc_aX|bigZa+i zm>VKy zY_r#m4sqG+Y$m!*kx|Kd1P2$4-Pj}vlmcSh6WM_x5*&`{Cl*&5aoxeueU0fXA6dte z7h>AovD(GK-3rMX!6<#myxrEZa)vD4=Z)T}?U!KblW{F$s5X_)E#J||-s-)0HL3q% zyXKH~+~5BQAXwIJvn|FX*=PgF;4OLJ2oBL+8GWZ=c#C~~A2Qh%KH=}!*^p=_s%PJ@ zXp#HJz2hN%NciFBsE*Ut6mfas4JmAbHz5Qb*)3j_pPd$oA=)|)55h2+WCb=06IDLt;CPx{K(-W*P_1S-1a z8OE$fVFcJZ6S`xh8S5M!bWm%)VYzA)<4O}Eisj-8=gT2ccy3^~N)w-26#se@e9jYw zz7uv15spsi4d$mf@iB~3oj&8RHe{;MDF!B55e};{`1vwiAO_&cI3iJ|P5}QhpN^Y0 zK{Z4J1yhhUWMc$R6Ez4*PPCo`?esG-Gc%n!=?u1>a4R^iA^sEQLp&ny9(pjNmK=2wmN$$f0*CIb! zV4&U-1?Q7KT7XEN69v8VH+=+0uhKjoFYohiNHYpOHJTGQ3I{oA6A4?Yb_J~_Q=t{) zqZctv(;1{;s-!#GqXRneS|B=0Kvg#5E=NC4?Q;bX5v67%TmUfWDZl?&Rw_h9gr!?b z6J3fEX|P-!%LRriMLxsm0Bh}mKCMxtHfMjP-hN8NwMV_gt#jW;RnJTA)UsBuQFls6 z{IjPzQRz1UH>_R;W)lQ(121p>tZ#1-Jx@o&ni6Nvs}rwNtc6>cZ&P|y^`3i85YQ)DDSzK&V!G*47N zPoMNY-{ej4PWlI?=Qm+CTyUKLfCkXNRJxy9kWZ|WzpG5@p1nV*W|Uifq(P(9N8xW# zNx%FL*5*0EpKZV|*NFxWALy0;GiqO|&x)c%I{(~n?cV|rK>+^@9HM2)KmbP!A_P#7 z2|^_c5iZg4kf20{88vR?*wN!hkRe5mBw5nrNt7v7u4LKL@ngu4pZtVF1*I4@ zZ3c2t!$!&1uw$h{BvZN!8#SfLfI-NG4I43Fh^qNK5bRTgQOk-vn>IJbAY8Om%rXUS zP=rv1XMr-sxLW`euVleOS4-Z=*|l%y-rf6m@ZrUehiU(Y@)ML?%UXFY(6-gwqX)8o zUBCYBAXd=SFH`%yScv4~4K1kpVkn6!wD6)LqcX}uL4%So5HJX*K!Q9BGt_WH4mm^CYyBfNhqU~a!M+zwDL+UMH+5PF1z&dOEAL(GfOhdH1kX}(^PX!HrsUbO*rF} zb51(zwDV3p^VD-sKKu0ZPe20|bWlPIHS|zK6GdnXQ9uEaQAd}A^hYB~iPXbNFHJ1d zEGPAm(Mi>eslR`3D6$o%?QdLEezy)GjNI3cqFu@l`H^SM5Ave}>hM_>hF$U&uqlW3*ct28g z4y`*vB%F0TVMx`e2RW57yIn8aa`|SSOn76yJt% zl2~y@5tk&V9HD8qF*_z!qFLl5PYe&|6^#l9{BW1D?)#>!_j8U`MFsqh{^!Jj%>jZXSfLkEm)E}2oMw$LmWc_2ntUS&?VoKU`+;rKa~KY5bPrf z2JKf3{DtEi8!-m160wI)Y$F_*C`tbzaQL(xcBBqkZ5*o7Pjwq4iNjky0 z#r&~^9*M>}L^hHyJT5zhyaP&h5ssg=gprAPB+XO;iY{hEkS^&X?4qTZNg^a`;gH)m zdY6$qJdSaR2!|OP7!FYYplu!Lp{7PM%2J+^kn3pV^eR@EP;&2XIlA8i2O>U(lrMLz z=!G$Q!HOnoOBBK|#x9z6J|KAF6>flpFNE=mIiycjXJCaldy$GQj_6x2G$sJT@QPc! zLZ0yy7D854hgS%r7l`;GLLUF|3b|QJp7jKm5k#>IW88ugY#hiIJh2O3ykdR>!KXg? z`AKU{vznvp2s=|!x)w6T2oH_uM3r{XghnzWjH2c)RGJZxg5-s+WC%H%`OIj#(}7=L zg)n>}ip`zW7u9^}K(u*=NqF-WbkN8bN-=(Iz*QsxyS#>=n_#)jUh+2!Jx= z3j^KAR5MZvdBQW685t`oc_BA%}pq)>^nxcDH3!t+pJvg;Mxb6lOy!JaMLxExe)> zZ~bW=&AO;toPxT`g)B)Wx{*3ewikuiUq-^9QP6Ja7I9mx*T5z=hTMT&>-YxXzHvwZ z)S(*36XH5ESDM$l$B7mR&du$A3A(WQ_=z z!0d|EKvYcO*P8!Uh;0VIfJK}UG-t%ffomrK5=rGRuj9&24zhg@`DWAYHp^PuvPLjz zV}vLg#2ma9B0|AmX2p=jTrqZ;nT&8=2UZax-$LsUzYNK< zwX$c*rdBL_lYk;gwop%5B2Qa5oHZhEt;;jRGItKV9^hyS0Isg?*#Mwk=bYVjW|6jqUyjgY79BAkf8VZ#ve@sN+4bKzjctg`$;hDaRPCK+r-p4JODG^^$e znN}}a{_iFOpvx`iYRec>^j`^a=mV)Yit-J^D(bKoD!&5`ZHEwKlv(9 z8vy(!BUdfSR;{Pmfp9-KLiUjHr-9<)7-xtiOb!5)tGuasM`gwvA@{Iw3%hAD$)(j1wO1YR_-mVajulU>zYORQcB*4qbPfSBH}aK;_%zcBC7D=HYSO;Oa7$eX%gusMeD?f&iLA}91hR{GT z8VD3r2}zr+YRI16dObheLGtlIhF}F$V4U8%vw?_0jlhI;utJ8AK&G%jYXKZ!Q$P_j z0#+ELM_3+)=phL+g8foF>am|090*D%!;RRT%L73?gQSiiAtAsaj^Zsq>O+z171!bogGO0*U%90*A8L_b@H zYG9oAk)1t6h(hQ?gfND6*uDr{2gOqwOw5QsG{cR+wTBtvyW2yR@qZyZAZl0qshLTZyn06;=1yCQ^O z!twZ)a|wq=SRWOUw}DV5m^&RK0Lb^sA1iVtAn2h%K$~f4Ga+~yR(KXT;xd2Ki1mrU zaNszESQ+!tN3p^o3Th#O)Qdu(vvoJ2jJzh&$s_<+8J7Rlyly*5 zrAbMT@JXY>$vO-Nn`6FL2&%BFo(F6~hR{j3qqDg)uz^^and~#EGfEx`hm_elsRRHI z>WD8O$ugrQt?UT4aX;D`h_ErAdQ(b<2+NRw%F_cs08l-yL-ub0!@V7Wn5El*az?d zV;iHk(LEZZ21p6Y2BRBkknZkQ8H|(`73r3iPT@~W3kXP;l$5A|VC~^~_q==FoHyru z&a3kO1kdh zcl1U6U`sq_dP_c>tWE1KP5iALu23=nAg6K2nLA1b7kPR&^UO4tDz%RNCb_Dg|IDUT z8l=yRbU4c0)W&&rOrAf}*IpUB{H~R$|1lZ;(c4NZq{PsNTg}FB>b~q8?IQ!Phg0lX zYygq>L~Kp>2~D|Pq0@hiroN(H8Agykxsd)#J0ADBT3ix?paU7O85|Nr4$|MKu$eIsoC^v z-yxm52^0Y!W`EN(eS_A!e7a5xdJ73*bX9(IasI<5^E9#}Y2hAI&o-8!vuEMJrX4Y!Vp>J!U{M;t$5ARBK@4GacV#(cnWbGr8XGFv3&_hW}%#Hc_-r&c5-+G}4g{Ww8&6Dcz+ifMC)ZH`p*8rpL<4L0W{ zQg$F1J3$$5-)*2?W;j6CUb&E9t&x;0*Q!{10}W6unIf8H^C9oM&k zCImfFIb8+2ul~xjpz7q<5LS8cSfQKkRkWqnjb>chVX-0-et}8wBfIy&OV6dqIKqN1 z^{6E zOes-v(HR2i1Sh?H(V$(Q)1qf=J>haIf88iq$!?%b;O~h@k9i6E6~r>gUQ=f$4Q3AQ zdS`KeXW$$Ncgi$EgF~8fbD31~_f;_@=Vfm2Iu5%Y?7WwMhnYT*;v3FqibuAwj8%3er76EW}VXAtrSr z5@Z7ieTQ<|^^OxZ14$=1Lpgx3Z(?Pho(X*VQsFX z0f%>0+HlB0vnzhK6;?CJ-Sk$2s7GM=VdvCo$Z>f;ZUf?@kVDkm=$F@aU3>rh^2>dd z`A>iM7c4EgQM?)A#5T^5hpJA-d}(4RUL>!(W+dt1+QjrSX()ngCgpBj80nZqd1$`o z+W7pBupF<@ibt>#K9cD6f2udb7DmRCsY0z14zZ2`raep(zGg$=&HP+>$8K^?afc#* ziaj{z7sq=&9~t*~ogZ7Gc)=bg9nKJKdj@7=C-Cj+d5N+X@~W>sqyTxbN%WgPVADPa zt~=}GPoJ(^({}7@)%71+&KyU0?%)K@OpAbeu(%dU4mRDMUIINS^cSegv)w1#s~?oe zUM}Gvz&W+=36l7_yb(hw73VKvu&zs*C}r3FaPJ*ee2=IuxTJ!3!25LHdvD~_ea6eK zp`2yX%RRHkjjbn0ZpaY| zyaCkr)^koJE5EWMSk~)>%WvAf7{9r3@~R1;nybG3a%OOsh;!1F-e*f#p#nFPk*sg% z2Uq#9i48M-@C6(071%T6Y{YOA+I?(&hhCd^c~%N-+9$F%ZKPIiZcM;9{9FXg;$*)q z{yX-Cc%EOgbWbH{9EvrLeKCwYU09CeodPO`#JzRgt0A0rp!EHI--{)m!0(xJgRBBM zQB8RWV$Sm>n$ONXRhXav63!z{<6`{Z=v>Fp(aJD9V(`V>%0(X>q^HLMKwb3tfn@7~ z%ugViADy{=km`~j;(YNY3~>j>?;qO48-0M79OPTeuG>%t8w;^HS_xuY8Zh=&5gTKw z=K*#JYbCobI+|CGmETeG3wMQF(`+yM>@<=(n^CCpJBof2Y!)WJ%fi{0^Y6-X$`|mm zC8#B|<(*!cfkRU1;ta@TjEJxL3|dtS#n_;}{A)o!G~FJUivJ-Bl+6>f^93%R;2qUK zo~#gV`789-5T#E%fnxI!?Oh?zD|gvGQ%V06!XfjQSQhQWgv*kRm4~Q_M8p= z3}SNK8#KB*Z&cTgu=zh;aM;||NbJ*sp1*B2GsQEt1i8?Jd=>blasiQ9B7r+6$t}gy z<>uZ){Z6^A>lFMwXWySJ%)mymd)pv5aQdA?M$-5*K}=wkqUm>9WsIV11VCM0etmgX zBvGsZl{WLck-t|Vm3xzq%&Q3C_45`n&CCWbcOusREA&82-M5May54thB!zN+aueACbECIQ{%FI-YFT zC2{yeY1iBE7MZ`_(#6V0V8_&C+?6rxD*-PEs3&=hIVV5iZ5f8tOlm*$C@u;e_?Zaj zOaIPf5-)8sZ%mVanLd}x1}bc(%M}5mAV6DWfAre{PAuc8R(~87hf=bDAJ=eVfB;!- zr62eERN4de@k2izjnqKCMB%E;t+6a2n}OsTKLql%GzYsjqj&N9moiU@^A9B}HL|d2 zTsqZ(U(ouqd2*|JiGnJeMsMw>s)K|+)mvBHi|rzx|J3CCp+u)9*vlB{9os=l{L^c# z)BkvdI}RQ&TuDu;5aaG1p2_)9T|>Dn;KgXsdr7%GwQ zyI!ljNE>um;8MIxk6SK53&6Q=Joe79Wak$b;K`SW;vwHrsR_h{|-`x;fQ zOx%Y4nah{#ZHvdre~*LX*G(-=wf^q?{J19<#}T%1)3*soZP#OG{1^C(dOcwH?Z)Xy zujOCUEOzX#*L17_f9|{3;DX20U@?#Z?3NxV)##HJEdu)~Dw4<`GZt~9f{23~2-qrf z*5BpQhw7TJ2Od|Eenu|^31lQ{ughj6lguq`8Hda=Zl(UbF{4la?G(b9j6p~_V(+J# z!qVm3cOA7&9%z)O99&+*vQ(g9r7t(w0ZG!pPht>FHG9OgxaJa7dz>m z{oSi_unzyXyqIr%rD2sDNmZSR2M{LRKISr=U9!e&R6zFeFA+JFYQI!+Y^`&0s$Qi$ z`&DIEnI(Nku$-M8N?VoQxwMt@XiAf-!svdueT^L=nn7@$TESIFLkPA^%HeHq~)t(Dggx(XE8aTaqsTQUibBZ7+qnGxIh1rM6Hh=2%~zF z3vyisCwG=l2F&>^8s8vv^Tcd^2IqZy&qJCbI`+d(?P1=2mi7t-Z?g$OUiPwH-yz@c(}L#T^7=<&I#;h$pK0wjy4XB+UU&#T zK4`MAjFhgnr_pZjdxX#uS#=ux8$9y(!_?0W9Eq;fx*c~x`+r(A8?rOjGWG4BUwqD& z{qzt~fBd#!x?3c}Tus+--9Jr4ZrO*W-t(xgwDZ@_tA{B|eaKRaH#Q_J*Nt&v6Ki)X z`&{aLB0esza{kvnLH2fl4e{a7TT_b=pb`?Ns``P~hC3s{j68t0>ysA6)$Gtvv6ya*BQNU$*&Z$U!&FA6rn9i2=2t z`$Ow$s$gN?uqyKb7Uql01DTsff}Z187WJjG&y$#6OC?&5u z7)-qUbGlin`b`GegD2vWh@VqCjP@b-)1BLxt=Cf-%fAk}$Ej*_QM{;B7WEPeFbP~= zu$Prf#LUDxNSYi}9?H&y8Tc9tmoSk6rC5)A1Kn%#o3mxvDKyiPt75o091gIpg2!o2 zS`H_@3D{M-D(kN|2@k5o}CwHX1`W3DbVKaC!xT7Jm8>HLx9Iq?08A_e69IG<(n=;E$LT19GOB0qAP4Sc`rIRH$25)kjUMSK$ z{A)FaA?^&QQE}oEm8sBaVE$3FY*cNr(5h4GFJZbOR-C?NiE9nd!`~YF6f&PwZR$EoU-wW4N)>XqND_JE0j)zWSNpD7@=SxeZyk62m zYuVi9la+Q4KeK8XW;fB4dKK5Q1+b{dDm9k*t#NzoF{)8aU-)dhpL&*CtZdSowoI7| z1Zr7M7t#g1RHoz$Prp-tVuE<9HC1N*;$|v_h}_l==wj8JGj)~vyzY~Od)Qu%S0~?Cn3UJFYLg?|1^~mfVr>aVo1Jc{SRbatO z1$Sb(Fc93evG>)R5OJawRZrU?L)GNz!|cQmky0$tbmH$HsW(j8W@%J02X-^ldiv{o zr@gtd|?nLv!w`U)B^H4K6i?LcJr;&<8j@qeql2jSau6 zR9Kj66!#dDN@R>9W~Celhj)uZOy<;%!@7Sw+yFY0o|PWOWWKek8g-vlt-Juo|%9=iH-b} zaQ?c(u&0;1hxb_EiKn4B_$+wtqd#fS8}#0!>@C>!CPzndXGX(PUu)2wHe`k{gI@3jyZ%u^w}c*f26*pYtz&&cRS zZOzd{VRISYN8Rml`x6d~lTH-Fu#3qwtyK>-Br(2j4Rb750RD zZYCTa{K(l&11Z}w4!#}TBZ6wG3yZ&XG#9nCK;lRSaJQl$OBT*f;D1pjMpq7o3u|Q{(bp*uopmgM z&Im`3!qL0ppiM>8N4BuVEy~+@sqi7XeNIDlJLN;1d;^I{x)K+3%afwS0>A}x-Zrl# zVqnLqsUw*gK@1HTW`$zr%mSJjPI^ETeHl`t*7i3Yr=Wlecg3(EG5SvGkRXUi_-GqO z4;1WBMxo+Z*hz&-Vuj}Hd2(WDeT!+$xEPs<7}If#QA7YB2V)ryaTiY)g#m*w%uyH# zQEo<95sd&hQyB(Ke@kHzU1bn4*U_cwXQjQShkFzN1>G6NPHIwDz9zVZRd|hH>SnoME`{HuJeX#%c##f&;~IVjOMd5m=@M++E^6 z-ta=^Y-eQwj9WE^#TCgAO=YJ;|M=9h#0at87sLxytmwv_!yrQ`DFHM zJ#lnv!?<~KnaJW8Sa|?L#p)(RG_WCuN?=%Z`)P-^ z>HZWTT>EKhhhU*Zp}M#8!~B8;TeRvfDnQ)5OnVLC74=3+B7~K>DcPHVj z--3g7(5yk@d8=@P_@I=YCs^4xj24>%QE~B z-lS|ex0MoIDPp0-CF-ir$0b<1hdu01cwD_Qx3*6`Enux z@xW>vqq>b(6H#HR9Sd-iQQ{3eos;RJ0MSt4P7LtbFQ94QQ+#5}r2bhddfVOGw$dMo z5x`Vg^uLkD7bRiJUh);1++k_qu3*1oVugFU??NwIO22i4&bFn$*nkZcYasAsxw8={BNb5?3Chmjp9y~EQR?Fm~`Qsk)5~!1jMKuhf)0NVGm2-+J|0=Jt z7Ij4(;$W-;&sesv6ZDIt@QL`)3OetkwPQ zc@`%yaZe1>$BU)4`BES{RV{klC3-@P{_)_gh`pHeijX!f?kfU#9_Kt045VlDLKtCK zjc~UIqjtiF=Dnr<%AACX3ogJq0t@EHvRFsDSdi zoY+aP>itu+t1pnGk1<*V3_gk+Kd1FP(3n1tJUc?8g#Z8)gMiRslCLsE^yBwC&3EeQ zL(9na*=ZF-0mA)TRKQk*A1Gc_z+JS>x=}6kSZ`7+Ug>SmKcSnInzJOo)Zj){Pn>k+ zHv)5-TP_t|D4bMir{?md-&J+7RVGlV;G1<0iM+O(^5M6iO(osLb=W*V?la-DCN8Fk zMy97?%x}e6WU#rx3pmiY2vlQFDk)=3uG5VI$gBghdkMfrndR=&Uf3rZ}Q_5lNW< zNo7d@>Koh^(-@9{p~OkW`my7_hs5acqy{=3qTO)Zu6Hv{1WtM9fcD3mr}wy{lAN1@ zJp}(@U(o}(R%;%}e1Gt?QBM01t>~|U$H^h@Cgza5tmgO-*JuLc(>FYMU@Ab6Pv;dB z<`9C~edFa|PXkgyFC<`h&yv2qCzd#-YEdWm{~L~1B>d2##%p;5qTgIVGg~m+fgId- zl|Lf;9^B>I96}iN*Rx}2jrwV$By4p`NGx_$6HcF$d`Fk@0YW(xO?(3^&Z|oL<@}{& z3+hCbfn-`k4@=LNQaQ;zf=mk?79>ayEikl>7?>*&f>DYzXDcMSnUx+-2Kr|GsaQ%z zoF3h{IS@d%8nDFPcKA<}V+cvuJY_I%~8lU|GAT=Z~G3}E`= zY|ho$6sT_6W^`{T&3&-CDA@g>+fBWv!_#jLpT2p?TsRJ1Iaz)e@)jWIuMYjw1rmpB zi+6oDFGVrS;+Q)mK6N#fO1uI6=ZoEyP)P{F0)A+4-3Gn`g+gMtMEhwI?CJ3B3YOlq zKn_HLq?{Ud*FtiyNpgQBKsewG%}8{gJD5IX=x|@sYt^3XbFea@{WllsdHo?TKdI<` zrKe9nC#_r5V7XcZkW%78xy+C9pLDDi-qQ!KMIIVOxNv>u7YmNX4T}4|RUvt>C7u&x zM2-LHBvMWsRa%X~00M#)u|ax6K`!bj`61pF**l-F7wv~Ptuf8c{rWV(7QR-x!^@_t z%O*{48b$GKK51%hQF}3II=ydCd^&Yl{S*GRM12~~mXw%o3MALkew>y}#Iy;sI zsfR$ls^-^QoeoH5+4YjV;^!s$f1Lf5|$pawo2>;Ri(aGx`*X^=U=>Pbn7!`02 zkhQlwJ^veZ?I*y@_?gd3CH;xKb1ER<{)zZjF}>2t zICr3O$hlwpx`oR!h+yd3%z*M*pymKH^V3wyG`71$ypaUh5=B~ye*T3Doe;A{lbH)-K#wzGHIVJ117*$1H`@3dX zURW)dVf8+xhf{gM|NioF|HSpMW+Rtb8nD>>(Vbl&BJjAqHzZR!AKrSJ(j6cZ@{ct< z@XJ(ZgGTeLhHd9<^3LX2z5`6Gp#M3~bWddX<*{;!3xWMfi?F^M{!AQ(mGxx4ei^5h+9*1a7I znuG`2D?2Yt&(zaim|mf4^d8_QAz7BzWWatDiizj_gKf_VLx4oA*T-v#(-sja9Icd$ zp^Ram4lm~M*N;Yf_^%XC|GhRgd0KL_BO(=a+tM|^FZcmsZqBJ;`e0#bG{xQd?*SbU zPNtU4obrfP^nuj+yfda>$nV=R_zUfSvO%608>(a?SM zo`Z@0IF0?HotmbRkttCqzToL$#w9%vO!l6EndnMV)KKTKm;E(Q+)|y1SghxQ2S?kd z(WK38#@(O^kDrCQP4ApcWZsDou0&*<|I#UN|Kc^VO+HGO%DaDMXHuH75Fx!19gOIj zf1gZ>ex&_TM9wsG+Ue_RMMyRCQA&Dm*Oy26dExhKb)2c4a)=;~i)tw7=a)WZ<_Edf`$+diqw~dF!)R-bxEKGKlkI-BY&r>eX4z)$!eVnc znn34bMzr_U-EgeZMn(STa3ij-_cO;l4lP@%?E?qVB$NM=EfurI?2((`zmaCmlSz~q z*jZy7OXaQM6|b=L-ew=A{u3Bxa13_CyG0zgJ_<5w>}i@ou|L^;p<*P~{xNFd!_q?D z@_&f=v^ORk?l;?O4?Mc2=?JC{9qNma5WodH;EQP!c8c_AWAmfFci$TxdZk%!2r>O- zm+kW_PI5Tfv8lc%-F7x~#|aoVr1*!Z3U^}1#&Z#0d)VKO8$IC=tX)u)z-7pnrJE3z zzA;QwM&?FyZRKqW(?dwI=O70u$&O;RxPsjmC=HJ`S7(J(y4V`V zR8flybG@7R?(ramSZI-1{CjK=c93!VT6H6t^PS@!WtsykgiDnFy>A1t#X+}&Y&AU9 zcTFk9isvJ9w`{s)tul>A;K)6y7x$%cS{Y}*KXLuwZ+#<`p5Y7S9hD#(SLGY=0BV%K zH+%hZ?6JR9@#Lt0m>fYn zPZG#@Q-$QeZwe|k8WbEW=r0wN7_G`c(@5v=Zeckqq_(~)wLh}J%`YDMHIxR?E%U`P|5xkoQ`46v^z%rs@Y{(Zh!@Cpr34YCiGx{V z^Z<-@3_Y?UfP3G}7vLG}LK=3no>$aQF&XTc_iY4S1V@&>98u>$l<%05)uY~tPylCv zYy0%6Ug>0rN^o6Al~i zM-Ty*iHqCz?h127)e3TX$0VEbjZT?~*QjUCxqpscCl&i*RF_FsM#DCG@0ql|E2(GB zG!l|a)CP%z?^09LFsPSiDEd9_XTs56JbCpi$v0}ia2f(;)L`vN_P=&|C4MsW$HKPn z!M#CUa@&WGt2Lae5%Z3{MQ^@BO^61JU%5W6f5dkGNc)wP$n#+L>HQT0UFEI;*j=gG zhYB39Y6{4h1Y^c??X)1q-?oGzCW?=p6`0BKM1U)hEaN?#V@?~Qc%{~2!?OBxvTb6I zKuhdZ+DH}f8MT6rDlrUdO)$-qHUnv0d9Jrl7RfQp5k&X^YmAi1wLdCJ1c5EdL64qN zJLcsX)67D?*LpDyGQng{B*Q4 zn!x;{&c^G%w7Ab(Bx3=&h3(RPG>%(dAoMm|SKUs5{kvgE%OC9?aVa`~Dm2=Mkot;w zUia0_E;Q@n_05L=2Zz=Yrg@LUuRA{*40~tUNLCj%-1`cnjib$+{#L8xFZC7{lr)$o zFJ(U{WOm?*4J~X_Y;p6lX?=yC)%E968t{x(_|38Q@4e_dO7GQP`&heA!Cjx(Gk2(J z+Ww&gCmZoTX^6*P0I2K#Qj)GOs2u-!JP}hx_z`fwxr}v__wo{>%i(Qs`W3dQ$>UKh`^J?iHUm(+6UGnHTI$hOFp8kwU60riRC=6*p*2% z>aOWMoQ-Y+9x>;0d^|0p29?@lpc1NgwehJsMM)1-05l2kYMrdmCX z`32wkfsxL4D z;zn3J)upDG6-*ptr()tc2?^)SgOu13>(QFH2Iy-o2a^6Sp#)IvcZ2L1oMT7pDZiEY zB>W?4bJT(icp=sOIGSL9bfOiA{W_ociye_Sk=iD-K7&||7w2`a*7_LRIO#4<7k;Ju zBlbo@1^tq@GX6LrDaP;sK>5lf1X@K^kA?7Tr?dJJ>+NaUL({Q@V#`bofGNtJZ&Xwt z_U}$Qk+FWS>RVDlXLbz5;f3E5TbK*ff51}|DRPd~NhjtsBs-<+R?>Fcw9p7Y3}#flW-JS7#!e8ev89?b97?cD(AC9 zFjcvpW$!yje`9>4!@ah(=Bv&_t!p$nnm%$mC+$V??c^T-KtoZ*;EkEBCNhN(r}u8t z-{Vj9Olsdfq{D90Pr@(pZ>d{B>bm{i19n}`by52gIPJ5yTnz{@ulY>>?+T4q`iUP| z4ewg%HK1I@KdF(2=w5rLA#Nd8l7}C!VUoP!x0g#KL0Ll4aM-`{=)x7LiAgdUWeEMe zQslFW8lcHc!3XzCxxlt_G80B7_;DF-5_VEwIRDy;pLw7CF-pwCzuCR&8?H#emuc(# z+wwm=9au^j*{EcZv`36jrAOjMXeQ|M+~;i($f(JCO6vHVp+b{g-?v z`*&*hkBE^eZcoo7zr>|+E5~$l)jsf==6RznP88pwemtjC+OqpkQd1tGQA4ZMY@~&u zMZ6Bw+C0!2G}3-=^mHIub1V=(NTKs7OJ{Xnhwg{YXCvL=`S1Jlx?gGaei-Tf%+mWk zuScNOCo$Fs2WdRX(x;{~IOReD0Gu~KQV;+D5WWkLC)Olk1ppuf01<>$y`iW-210Yk zYP6wvFdoLOnWx@ZGW?8DQabPMXo>)L8sc_iu{X;F$b^Q`a*@q4>07eqmz5#1;OYqj z>49aCzA`25STwO_lL2=jn_?WR`S-GsH~OWTu@EdIy~d=`nl!!j$oQ@0f5B|zw?Cn8 zo!%#{S6_K9H#=_E>vS)k%y)tE_)Bq*eNV;~yODD6M8TukYOlBLUp6+T=-Pd1x}KVz z_N<1S?T7|kjU6;p8%^sW6J-0azTZ7LC9D2R)ZhlZcZX|A*QWrBR z{IGUQ2ryP-UWfE_HH#!a0UZ5poT4Z4=H7G|$deeAwmEDE#}KOC7et&Jb8|dCbh?HG zc1pRd1`M$MWJwrK9A$}j4U=U}>T^5Xd4?Jh_#B+_$1jdgiAO@6F^3U1iUbHFMpKj^ zW1s0`X^GJ(GR(#5NQGYzNA9R|GoGv*WEIbI*(1iiG|4!!#ccCSK2tLns#kmgUN|Sd z*ET(*{3brFW6qDf(_p9NvLV!(6d=JDOrG zdT11POkS}oSE4Lby-Za&dX(XnuK8hcqUef1k!TZvF+X55!!<8yY^<6ku`PJi{;g~O z9bsfq!`v9_fc=4%YyvMi0HLSgr{6Mfc#Kt60q)9RTx3ss%n` zQW(wlUok&G4!iHfnFP`qdh&6+a&yVENt}d^*~5p#h1glj8qwyIT+m6EEWvahGIF3F zBh7LUY=m}7DzJbiBPg%|5XGV^d#pg26jv+z@p+)JO@2CR+q2YkagGT?3U}m~A7XZ- z!QIA>>IVXsG3s<7eSsuhl=Go#f2Yt3yM$AjJEWw(ht?< zLpN4K4b!(16nkVbQgU_bTS+aQudV+AkuyO^ORthS{WgQJK1?9!a~CoRGAUlV8Vdh&?X|2sbF ze*AOK5@aq|IQ;vs!@={yukV7M%e=`|T012ZD7c_b;?pAF#WW$^OSOCn$x8DWnoY?2VOqw1O2Y0J0ceG7RnLpX!MnZxUKRIZ=@=DjtHD@41e29Lf);f zrb)c34meMcdtwIcnk<1Otrt|mB8Y}gZ*fuJ-6xKToVi7x5*7We*~u{#tE^N_9h%+ zi-7k>napO%9p3SWk=UtV`F|xPLCa`)gDB+54QuaTmoRwyx``#I!?+U$7)buwtE;(x z$n=gw+6a*9N`}L@*OVBuvq#}Mw)Z8th9J`u1=#2+p zB|28rikwS(0H4<2h*tt~sXuKnj2yCP%)K|Mge%ZSi51*VA-UsSiFgl zsx7@`y}gkgL7&*6p6=At-ZEu7FPNdu!Q_<6og$wK3on-X=w4%xULDEF44A=VvrXRM z4u$hJTDUBOE z-a=EY#U>057zkpoXYTFU=k?Av7?qS5~y2e0Ug#mQbG z9gdY$3eZ47BS%joU+b*=Pk2u9T`xDST;q?;?3@gT6x~H>D8t4gv5VW3+iO+EX$s_Z zWDEg)F0P+_9KZp}mz(mCHhqfBC1U@qto_K@HI|n~b`2 zHru&geW4~MME>z9Tddl&4Rf!q5=+UOC=qW|Xc8q8cvMqf8ZuxZO6sbzni=apCG9fn zv_6tGOx+eCuRbkinM=3+*0*vneHQ@%OVCPy!8BN3>HQo@bfmruby@E;(!SN;-KOuK zc}if`5ZbVl(x&!1Dv4#3{WkZ)3AaOi4id+z3c`HjmDfo6PlS?AbcL#O*U#d9a_rXG zg~|-905hc0JA$*w;xv(?kkdQINP{m>$MsXH_uZd$VBsWvl!$yh#!6`I8EYqUp1?go z)AlD_#7N9S*k^QUMLGbWj`Jev3}c96UF0L&9Bg&wDx-eiiP_S9b{V9MRiL~bK(ff* z;A{N^Rr24bcYLiFbT9F>=p`>#`!3LJ&*AVQaC+ODrMyzPj;ZO<_ssUCy~n>--g|h; z`L(~^K5ea^`t6RaeAPo%JQyJ+Y7;&G$)8wU31`~58D#b@kjm&_D`rTWR59fnpbr>L zIWU}9mbseM-k2yZhQI$O0GY2h%EqU+8I%{uR&z0Quh$i5;+UU)4DiMn>ZLzIl)>5* zMmg>h-F>b`&1q?N)0O%n+ z^@}<&QDiQCcT?J!L?8e$*GKJ9vYQQZEYVSUSssFho+~XL*>P?|s;oh8LLR@@z=V1# zXM2tn!S*g}iHRVz^M2b%+x3xHD{kdWI8_u979F7SInKB5!t;e1Y(f(56sikhh^w`A zBAboFF~q|dsE9M58DMD1bC?+<)KfqKjEi*^2rJ^J<5z=WU_f0$pCc9)0EGh`2aR=S z6tG2()Z&i;==;jSk4Z8dy?Ef+MTl}+U}giv?zVR2N1GJ|@%Du(p~$!lpyJz**QSsF z-=y>gh>PvB^sS@@GiY-qE(8bd>XEDIvc6uU?qvwvu)_ z(8Wes2sHBnkiqB~nacF&K3veAtVa&58!b&r*=H}M8JQthw?WQefNiR*Y|y?6A4z}E zWDxXs2evto8vvuay9ZNFz(=}Bc)WqlRq|~H@w;K@TqT4KRFrrwLQbW^zBxHu4#xt{ z!D&%pe^h({Fi47iWPBUtv@M002HNC}maR-?Y9NQf^e%@&9| z2iu^?l(t?0wqB)?0iu~e_#1Hi>+EOC**0jh3^MyCWZ5s}vSS4^KV-8J9pWn->7dzM zV6aughy{8{PD%iX>x1%`xo2Lv#p*+;X`|Ifb2tWY|H;J+2)gHHv$> zmIt5nTY!b7tsXiI)Pv?2>4O$slJ-V9QyGxyRw|GjKeO#$QSDC_5Syd++FIGGx zK#@r~&<~EC^;H>YkO_!N(H_D*vP+wt)lB1~zpBi5QJ!kspF7(h1T+ZND}!CD2miU| z+khbHzj!c(g(#YN?92y0CM41*j4p+EP`a)qH&zz*^==J z7@)Ql3F?0Z^a~Jx0;CRLBATyI7O*w2lVwibJZIn+IF+se3~@t((qo>nf@`2)S*Ivg2*m8Hk3;$NZ`kV{WmGxKQ3t%5cX>&IG0x~ne1DMWVO}?(3Dg0=+t0nH z8%W>kLqpI^Z_}aw$e_*%>mb(6^4o*{qK-!W*HfR+j) ztBEVip^KaFBGzap=Jca|xNb3&UjD@tNpHwoyIk z$SUZPI*!T&8Mu=rlC2g++?9JSyJ0Z<=AYH-9@nRAfpUwn9D1+Ho!&Dw&nI04!7!Z=wUQM2~bShX)T=EUr4Y`C+wwvgwwknULI*3(#S z`bL?+u~jcvZG2@unbFlo*@o;)pq>U5w`V}@tGqs;Ogv*@672__F|HU##M&2EjE zw}T5jDVnY*O>V{jfMP&jJPk7y9TYHTf+psnfPX5iJsCg0J5~Zy*o?~AX34^i!gSFl zjw;e~$*MC)Erv6sMtm(=S}$cjIX(j1mr8QfI4;o=GIn_W%AQvh28RT}Kq*Kd$xqT0 zTObJ-5akQLNY4HB4r1y10p|<0Yk*w617BFp2v&XgmiGbN<1KhI{Y~M+E#EKe$@XZR zE`(dZKv=&Q*lC+}(@U8+2P<`1q#J7X65RqKR^k%i!Vf^!f?x`Y!#NN=O;0gg^gXEqs@5 z;6nd*$YUC*WoKBrzO5d~L&3#v>0jOC8D!vnTQ0Y1hMxr_M2n#T&6L}Vp`R%#$wb-X zY?cIJ!E92|hZbD)QqG4xdar9Vcws5$ivwFVVDTk$by&Xb;&D2KO8a=lkGB*!C&$uA zkEoLQW@$s;T5-)O$Ty(mFNMWPnBT{eMbkRV^C`CRZe?>@@96hGR_m(;NljyBjKK1$0;!6bK%(1-{)P3qc)J5dgBmsR!Yr(4Z}fr_<3^aCm*TV@%_td>!S)PZYL^%f*DBQIaIZXEPYGYvWSf9fGiaS zej7EHwxw&6PS&~s>F@^TpF>g_NnazqYf_JuX2??ejv+L?wP!~SqQ@;yj-vf$`MEpF zTlv(~m6ua9;70r}f@T-3&-S03J#GXCHISy*hufeaX1dsP1SrN97~%^)Ih(i+yuBsR zs{sD${q_49=tA`T#5#Pm(AZ+oyfO8!)!7l3Wb97t{*?W z)?)k_28aEh+9W3cO)N%)_nuD^WmRy46@y`NS)fanBnx2_+nRV?Yp%$l%C_4!)u-r5a%l}U6;k~QnMwMieW|2)K)Q$H7CJ=yV132BrZ z9L5z3i7HE#^!Qg}fLs{&$T0$)2RDED=r(LJWpR^eHvd1AeRWinZP)!c3^0@q-7s`Z zBQ4$CE!`kU3nsz3;ca=lc^DYq9Qq&e><5 zeVyyRtF1)D*pD0&yPswyCych<8!6MhHSVeWMX$-FBa!Wn9|>58we!~0Ziqwkmwn=1 z*E~NN&a+ReOqke`EFs=sPj;x~sYxJzo3|85^Va*;|8Cwo>X5ud0z`EW3DB#;!9-^5 za+7p7Q^8cO2SXlr0wAF2YBvmR1V4>W2XavgO&lG$7<-60gjRKn?0{VB)%KWVHo)G}HzuiHhLjU^w1r<8YRW~8af|@R z(`7_GLfdO;{1or*WMw9edQW?r>nYmFCFr%HWX}^o&*qA+w4wYe z{N?nF48$Fyh6+~>@Rdj(;=N-CQJrIyCDxe>UA1lXE48$iBmuuCQ_X5hQ#oZwU5XUM zBNLN+}5#9)Sxnapl~MZzz};24fK1MRDmb}6l5Ob z0Imd;zc{`Z5N_u~{p~Mkkb!*iZvvV0pMfOhUJ||zB=%o{Z2movF@FbA_s>Aq{t-yV zV2CG>s8c7-1{uiVnYEd8&fozTWTwwRRncfQ{m%*@P^piYR7 zbjr)~s6lJN5~UEyrTT{hgSpbPg+Oyo+tK3su1(gKdZz@_aM24keFc2lC=vhS3uGW8 z6~b44vTb0*w?*q${Tyv;mL3JPh{n@?f8{#%w$|xRboylmy1N*Llub4lNH}Qcy#wxHGv9kgMq%wC+>#KD83nAypXH;()C#4z=8E= z65f4Chm9ZK_pR8b}oJe1{l_pT(Q?W>EkE zJbP=>S&_#nxdgPPWb#+&T-oMcA0lJW58j$xtTP%9c{}7^0W*pfX@!a1VY0KeLfHw<5EprD@hyPlTF@J+*J^ z0VBvdKNu7g-5+CLV6YlPLpb{!6O@IL6Jg0LHZAocN zq9Ige40^T)HrbK44R=jaO)EbyT0*<(HZ%12ZD)Nnc@X+$rfFLgDSb6%Ogg4HvNBni zsJA-t)urT6ZDm4vt-@&zcbT)jpvGU@}JpWPI<`{8zvU#F7&XJriMC}YrtOa z?v_)KyB@3^;N1CIFXZWB#q@zz2l8~0@v;8KD)ND!pDya$JTMUv+4TbhNcww5norgS z`Ng8BRP}jH-j!-6iVbJH+MBJe%D9aV3Xhv>@*qcbArC)X=}hkU!dmEkv_7B-Q+wMc zB%cn*aP>x>F7|BB)H1>_vG}7q#E#}~-TJ*hNCFRmxc`gJ z`Tx?wS`jKi7Ga4B#a2q>`v21+)HMrtDHLO1?Dw>As9R=n0Zf274DjV60w zFqozOkZ}Ibv@ng#=|Zk`;|=7v^&MjVkrwjhx~+EE)jhw`;#faPDyR+9C-R|faCm-A zok~mH?qsPpuSpwvX9GvTH0F|tYW=}tlgIv(Od*v6c{yUNN)N1ehwB50Y!AdwqH4WL z#Cd<6!Q#Y#v3#(2kvgY4N>4s}UZKjXJsM0s*3tg$++B0I+z}*UTX1x;zcO}J0@2$S zJP8Th|6;cq3}zhABr%eui{^%igEL{sRgJX}lx*C$!bZ0`X~Iw}nLmWncll610sfwl z*NwL5UnS&#rg;-mQo=qe{9SnYbTmPeRaUcp7RW!jT zg|6!gyqMknfUH1$K2e?P3d9mfNpG&*?oa9tq*879wAECkU16Kq=(RarZRH`>e)z0b z>y^j;OQj2>l5B-zoh!DgajJADvOOey+Hu^bB1Il|6K7hjynRn|aJbq{jz4v` zBjEhg)})n>*lG3U`CA9{-vkN8U!@HOgaAmH{EK&|#o9WGB zskLoNy_TIfG)5?k`2+k5L{?R$+OpB2KWOYtp45w9G!~=Q{p5zmUKq&c+|XF6h09RD z4UIu2Lwl}w1{&Qne^Mf8Ot+m5=bFasR!d@#G-iUwtvQs&>-6NS@7C5>uC#FnDKcLN zvbS^0MlU}t&!!p==Nt%lHQj%!HL*OpxWA*n-|&S>&7|A~snZA_ylvar*%~kSREV)! zX16<6TN3cHz11hC;dK-dHD^4ss(0>$s*mM}Ip;?#4pToA`K1SL)+_#|NK8O5m;i`? zz6tszF8-1WJ^v2L8oD=b$O#8~x8@H4f71|fW^f;W}|ljoWruN#7= z`Dn?#%s(0eYQ*i{UzIN;MM-|s5ZWCn({CDrS8Tfw?@dEcGhx%Z-oE(!HjwPPAvj(T z$s!wqRRO#}{JJ41^+J(4h(QAkp-GXBqM}SZG|*e?!1#`hsN0_{tT%M1Ujz7W(f00zF~(iyP?O{)S%tAJAL;20hMS(ChvQ{p6p}#~`7v z)!@@}zg~PHUN?%b>T=mvZmPEE_ITdXjJjKm?8T!$8Az{NlNP>w??`j4U3OyB6C@Mx z$&d1>R+xuejUuNuF9`x^33O85;=04`58 z^dER$xBBIOiDyCof5DUEKT{e0JDzn`zv0R77oPEd;i)twtaYPp%qaamikGgnjn|;w z#`5(d(G!L9-RoArf1s>&-RfTx#on}f1yVSO78EWaGhtwX#M5(dkT2Mc=qsxU|75k* z@RL#@3OnStiI-q}t&I;?N)LWgsRcBwtjk8RJ$ND{sD>m3x|ba7Ene+!tDII|rU)Y! ziCSk^L6BryE8C#(}&X4)Rv>JqbC&h31Oau56 z-Rl{V&5LcRLAagk_k6y*B?80&To3!|fNl&5g}BugH*|bj6NBnCi4X{>urmqw2boAL zHnX16&#Q89Qt8LvnX3zA5*Xz%K@xGB((yEkDTp!+TR8xxVfpv8cZ{QHD5ft#4m|%D zU#^u1(u4V5w!!`>P!$1E6c!2e8-+;6<##30j6Xp70N8!YAp#E!$@yKNwi}chHJPn- zkh%z+?o9nHP^sPnz}py|_wuA-U1k3gs95f5_4g%T_kI~_{6nCA{5+fz{IHeh4}m&t zo1KYlk4R>Z>L3w1+(9al3bR1L3I}9S4Ckndl*A3xd+aYG9T%Ab*FY?4WKrxjHFlFC znZ4Pg!?afXT8VfSnKQ!osSt*I1wlFr_LvPs5FZ4htB`uJGFB? z1x8Y~dX^jB$lhTh>)CjhYuQU&IiJNJyz}B_sg8RkmH;RNzODtf6kmNu3uqLwK}H+6 zDPA{7v&FQ%>jtS`AFXpO=={AK(p&2HXBid4;Hs?+F5wkU$fdg0drK=t{#evG!i{Pl z1`;2pyl87a>Fs;2{QPaI5OS$*a+!T7!wV_s>W!dx)H_5ccaXG>F8l;Z>l_nET7T}O zxLUivzw&g#_aCa_Uk=(g^nFb?sK9?=ef=7xz}*oPijU|AZmh3AM=2c=SJTl<0guqk zzeg!Pi@^fgs6R(3-49viyuSwR_n7#*n!hFsZ?@^$8zI+lpjgF#9JG?E+2()jjX3`v zT*!X|H>v5a$u+nye+Sp{cW`Zf2bbVaa2wbG<@Te$=F}uJ<&Nt))wI>#Yk{30X8PKA z#d0M}-KcO|M7tJv+(T{J@0Va3P1hr^ih%EI@D$+A_ZQ{7ww6Arbrsd zwA*vLrhx<82G!+GIF^qBo`m~bq)H|}^xr<-9(P!YMbg0T7IJKREgFa%+k)N6Se{Xm zBYUH3E3!9=v!5Y*qp>dM>y96JpFZuc+&^hj-1v^lY_2r=JGg)I0}|Z--YBX6J-ATR zP;$jr^n-ENrtP1Zo8^Zz{W1j~?qSRSZ35WKB`V01UAx-XGcn$%qF2eUnRw`ngI3|q z2+~k#7^*w@OFcJ=z0N@V;#lJ1_kO%L8@C?G##%QVJGP{(dovSj(+6l>gGJ7zEv-1@0e!Qi-?jya2*_Rd&@DI6xRJ7!%gQu9GA&XJn0`6Po0OaI9=$HIsF z%#a-G_X#GVx!z!bomI<#BEnyN^F~4coyq@G-~3xC{tu%J`~M*r)c-9QWsgh+uY+OoTQHcF ze-DNdWm@gt+p=HtpwmpDLi-<%4Bm@!*A+8yiSR#))XI>4vFMURK^P^{{tG#x+x`{bK5a^ok!hOud;H%JGd#t?g^q z(mka2Y=aEO+N%dI7SGyRyygaGCw7Z=Th2e_*}yre)u}wx0Qz3355|60e??~c`siI` zrZ-$?`dG5~)fGUBkixA96&VaEn}13dN#O4P)xIbkkjgc%d1Q5SO!K>FC_9R(b_343 zoX|tUHUA+RlAGAFYNULGU9j}Q*CuT7->%lQFPa2D9iUU(Xq)YDw*IdbaxC1CR$YSd zc(-Z5pRU$DOU(0f`#G0ITBqe}Djw5d3bA51I&65DixdsWgmwx`XGUq##lZ!PRNaUM zA2X$b_dsSZk=jo;_QlUfk2a->7CzV_6B^m=up$``2nSrI=8^UVwffImk6}OuDd&xS zVSk0#*ZqoR`SmN(zIb*rJR{;=^Xj(6cS0nFU`r5!X)WMHiS@nc zU{H^4KoW|yFTRF+mL~!IlUhW8LjQ+!75Z=Ks_0?fEKMs75 z2I6Cl65Sk~KMh2s#9xzltv$DyY345jQ5?rf>z9Ez+LXfdwjD{#RP3p)iZ}L!=q&Qu z;N8tszl|LGN)YBPT5IIISUvW5Ymjy6UT|e_&$Y0adbhT8 znqQbve+~6yR<<_Mz8E*8%IV;{hMJA%D)V|*Myf)(`eC-v-u@?|e|wn!eU8KdFaw^T zAYTadf6~N*!BT2GDrNtX-hV5NKim#e);JsK5|x4vh!%oyO{i2Q<4AcuQv#EGAzsgd z?nl{Iwl}6NM^7bvA_>Na21~ti)CnpTDIYey1g&tWrhntho~}^ipV?*iYSy#VTNDI% z2o>hTO*qx3MB|X(HNtOhsUIN?N}yNP65-w<^^|(217}yvul_8>3d2cIYw<7Kfm?H| zd(9hfJba%X#@1khdp0sM8j@P?UlF!YV5^bx;IHRAC5$1 zUJa2-l}Q=X;B)F;c7(CL#`J&vxgE43se#PoV52Gd@jzXT&~aZBpmISgI998%RR?l*i@kxanlNjHMZ~qi=qQ`l#<*^sS5m%V?AcU+r)xp&bNo z>y1U9fl?ph?yQ4%LU<8KJJOM%+%n)n=`vRX^~E0x6M0%b9o zi-csA;-B21#q1=LEyvJG&?f6~DDrac)g&-;Ylh@K7P#th3@j1YbWqHC(u5#3EVb9b zg(wsjZJ8qcO0E-tUY8zWXFLZ>>W}Kg`n>xicdOCV@G{K1&T}q~t zlb3SDj2LC(wM31`i5&pusHD~aH%5SYVZ0ovb6mXKYjbRCSuzvrEt%KfUSe5647j*u z36$+^d+;;?5LrA8$#_{JUHdmZ{nYpf)Ime@cxGj)PgoLohEu7@xVY+BT#{69cAlXF zVa=01H{l^B)7=l7$d`}t-U=CBqpd>_86L5W57Jv%kVE8|+W9111j7074L}pg<9j?z zc2+5`FhWVJ!*8KYN{%a|ktkzs^mM*?Z^{~O(st#7y67P2o{nn*FuNz|gcaah6ii#< zV5U{Y{N)8c=F(kXgQ#MI$$_4n`xNV&jH%PT8rqlQry%{DAl{ z7*@TK$S*`V>4SS@B;}iCNKIKn0#?7HndLqIj;2P_psjgVQ)7S>*aazegL06BW1LGv zeze7PC}lqjKHew1h?Ezmz_kXW%ES?cjkLWdjmN}zSfnYRMOvBqZ{k$KtSvuX3W)@86_$d!j&Y-`S?CI?N?ev z`^Sj9P)WD0(*=zlx`oIv!9wU~=P4?x-A!Lkt(0|ddOEJycv%a2y25dAGP&B3tTzak z>n{xq0qt)H@>{5sDsdXB*IReCY?%2S(wPr^tg^`2L_L>G{dQEX5T7;?! zCfw5Tan+S=qE*;4SW*c?To8sPE$nfRA~p<5)Lk5z$KQ+y7Oc}y-(;&}{bW-h(BqW= zl&V0LNV*`Ra8w)CMCc%e6kZ)yNS}&F;EV4n&wLd};!r2~hOCQu!f<62r^oSxH+t~i96UfS(F)aU(qwJ@VtX_LfCzWgwc;<3f~+QqEg?)oD`C z?y3RimI*G@G!Fani=3DW*>x!DNT!u9lCpIXL)zrWW%*AqS&Pk1S_+k>J)XuVX=M&I z&FRJo5xEeUqz#GWgdRqxCnjmgBd?A)FjP8BE@{yzH3O1>@+`VwKSw(nJG;3PUS%wP65M=3IIVvw<`TSkQAa+TaW$ z$7wj|5rUwP8LWHMm0rDyI(DVUinUDvCa!}T!AAC=U92PggJII6<(kjUxVlVXTp&$` zM^MGDxnR3m&|R6cyDzeV2ym%MC6~Sq-aFW;)^Xi3npS+T7!eCw1nnZ=ql$4_kwkQ7 zsDNit3Z-m59(q?#0DnkLh~LL#7*s6OHYB1_hL+5JP;>ps=caals|$)(()>htoKxji z(X8KBKPY`|n_8=;=T#O3OApAeNG{T&?yeaK;g!8vU-Q!)F#{Kz$I^Dx(4HGuQl1y8 zH4I`B{mekH_T*uzaXorSx5Pl3Zil1xco`B5wV7gw5VJ>t;TAJ>+V(X9^Ie47yN;;}%QoNZI8 zKAhB*21W_F-1RWTqilY8z^F2J>aH`&n8u#^f}KRS&OxVqMUN3Tqp}RxVsPSn3yz|D>e4NmP?F59OK_S4y>Bo^JjK96)O5UAG7$W!Ywb4)Pi{tq=yA)l z7mi^B-BQEjflODi@%S%0k5f2F0qlj0_$k$>*68;78l7Awudwpc*s``vGRGgNeX|?7 zB)cnI=^l0PMVdcJ65C`|hvSFwUiq{1DJfqw<*Rp}*tj*ZS<7w62Q<)LJ=dzm7ZA=B zY3t*oWgK|_6DuULcb&6XZ1aQG)SIQaRm_x#c&qv4RP- zXRQ|0FV;LKH;%$gqzLJK5zIOkm@k!dq7VSq6G37vBcF#*FW-1nOvtnw%-_zN9%f{E%+Wgeq5mtC(b{0qMnINIz{ zYbo0Yae|n+cz8sE7@a52{AY_rc9Jb6&JIEn3xEwG9&!LG})Qe0r ziA*s13QXOdLTAD86)LM`wCZ-APtn)^g8!V3Pkctwc+Fbw5lLCUbwV$iHcV6wz?Fvv z3Y274Pjrw9lEgW8^A01%m-m|wft+m^($qc#RI_R3Qp=DRgaMk%qE z9~ejSo?tWu1Kb2C)10E@%&}~}zTJD!V9n+1CQ~i|>MSN?)J2<#*S;W(8{dNMhY9z~ z;ex|q`Kj?A?O?bUmYf66+KI>lJ~(_hbNSRyKg^>$Bd5QACX$x#V%Y1FQ$X>ImXnt> zA>+!{^3X>lU2CUkrG}u7&t0kY-fb`AH_=w~nwjkX&YM(q1OI_60 zsZfDb)0%q^d<@;Ba#LlAO?(VI%Y2CynIaBCXeGzdY>;&quNA7GRgg^2&j10`(yMRC zTo#7|KO5-f681CO4=Ti=k^0%AT8Upo@^w+???yz+Tg57x(8)z);zlOh`P6}Z-=CZC zZe?tcxYzAQR0>*n3|hWl&lDfXc$MxO;uAa;@AIr#XS&P(@hK?6#-$23x~UdXbrr^$ z*=$phLYU&^beq=}EeW;k7Jvs7tNlow#}n0HAZJR(eiGe-k%=*+A;m~Y`Yt}BMj{!s zB$UfeB2*5d?t#jJ&p=+7Qz9*ZMa!rehpIWA(#Q0;Tar(rGZvLwBBVGMVQVb0O6new zM^+x^+C}J-0wai!KHOGoJ`uHF6>vC`&cpy{3~F9!nFGd&QSNa8y5qi=JWOGRi0uiC z6`*}X18K~onU8a75!@x-)v>7$5-H)$KG*P3?Dc*PN$N|>C6ok-GJ}Z=HF@q^@%V9WrJ}C6VIs;^aY5}y_cf|Xy7CpOFC!pLVL=7*BZ#l_!$S%nux9ZVy!R&T@BAhy-OU=iB!x!O*-(apcnR|zzu=SA5}GwUuk zGGQ09v=!l}l|*Oy7`1lnkrKj@-!2DW;^CqVLT-zH?Cv{y4f>4QCDF53ovG)JzNUfm zU^Tv~2{#;ayGsLCzwLGogqq+3TGwj#VJq@C=&0^!9o4sym&ef8&;~Sm4l^<9(jXSq zJ^SN5iTarP)mQ}XXciwkAm6$qH9I_aY0`)r2=v-XuefVyrR0g`<-ad9TZ3DKMSZnC zqlZJffVenoZdjfGfCUtD1%jid37&@B?tt80sV03|)03tF!z;rL2^u2$j2?nqg5APi zJHoULK+A{Reybr}OmVwCcL?1A+n^HcpNmm~{hBKh0^@fjdpex1|Qq-Fpp}C@@@TGOBM^YCs-WVgT3B4j0E(I{Q%F(f1)ZXlQ^) zxAB(>5WC!=TY;lV;UmZk*CeB3fa-~0XCln2K=?h1j?j1x647jd#z@LHVZ4=XD0ou> zxM+<>mj76oA(eX5Tng6!LD^I0i~Q_6nd5#r<6)6yl+QgS@7=QavPOA}QB7 z=x?4NYUqKyEmH}_?to%q_i`XlCQW}}hUAj^0H)i6z;KCSMH9>p0HAdojEaj^m5a=| zDKvMq%5f~sQOtQ!$lD{F2SJo32h-C>=!TM`Aot#O0J$9G_5`$8>UjDobY^AMAqg;I zw1<}ILRuc+`cY4)=rg0rrttn?UVZJNK~X{!TQNA$wfUfAV@U`??kmRbU@UwuiJpyvZXXRua5av2+eB4RFG>y0TM39y z+~{H)Hn0X&g#$7h-C(eWv44d5h`a{n&D4ZBHa7>PPeWQNZq#{XqEUkgC1AC3bs6Q> z;-N8))6z8I?S99$+t1lo$lGsMeC$|cgG{etTU&rUxX>jax6y6`9#o_H&`gF=_9h{} zVzPwQj7cbmyhT{El1zX`(t(~#z8->my9Lwl=~RMnNwqgYO|0UJ?|TDr2xfAgO}|qG zYPoT&icNNM-#(VrNMa=a_=pN*O%6319Lm|74Gz@!o|F$z(17HQ(EX3leP0gSsz3$; zu=w@CS)y}*YEWDwo)eX{+ub8uS~()%3~`T^~LV+XN}W$2Ec zwKT|d*B|{QO%Y(k2MWqP!da}|ZX4ANZrCB1UT$&iR$KhA0?Ao$h?v52{@EY=-t3jf zm-uBp*BE2nr5B5@(MvY(9*UvD=bD2pgmq%b>*uIkKK(3KU542+ykC2%ZBb?9g6)xLxc(FnFrt`9G zSVk_@q|~>?bMP`Cw*#)&A=)a(D7P>WVi3{?IQ*WUac}@kF>5}W;Qib^&*MH~lfC^T zWS~I)ai>=l3sP}?xd8Bi%LV(GwVj?ebc-V}$;*9oU&xgS zPU}R+{pSn!?*J6i--;PUD9 zi!So?CHo=Q40s~omIN3A1z=Ojq#<9C6b#0|)I{!*$-t4zm-N2wAEZJFgrs`rxM+I9 zNM*?acHHQClL+K-d4*I3w->sbewkdxon^?mJj+`wpSm77L#dY zHPx#XTTZNLG`%Mnr5kxw-2)F$hJFqJ+tJfcz%6EE_c5Uwf+c9U@vEx=$S zB8j}JzARFKGdTqT&R_~Rdyk@|^RDIQDoZbzV)Hztpg}dM3 zDa823I+qK$lDJjsbVLM@7cq^}V{Y|wiFY@>bEoy|!;#s3(-y>zk)Z7MWQm9D?Qd0& zo()&|KQqi0ItyQ@pZ#t|&S;$ZVZI7o*zED#(bi^#kNwi6@8(t}z87c9el%^h1j-#5 z2-DAx-JEYw5;00{BhJ9+b#U-WZ!Q-PZ+I=dV_qpgtmC4uL?1BTLsJNRQz{7%h?Wx= z09kQ#!`}j+8CV587~OER3ndbouq79c!Xzd8SmXQ%_AJM^@3dK_(5^`63m8gn4Xh)kw0@<;iOa^3y~*iCdHo#j;kGr>{|P-zS!;JRH*QIW{5SZB~1Ze=?RQ$Z^uX zPh!L0Bri0|H>R)X#ieiRvzbhnq8C^;`#jd9ysV@e7{ppJj`vY%C+O=CQw5o%0{Fp< z1;^|2QdmVn^CLD;RYSwa;iA^q`Wms&I77SJn+TE(Bl3Gw?8@V9ud0n!@hok!S@>6W9|2Nbs73v07|EK8z(U3Tm@m-bX8iS=^_tnqTrErmhd%vq4f+dMqlfg z2<P5Y`xsd~@LMsH^d*<>jaUD}z1$O=0Ym0=0D76rmIq(;gm z!>3B&N ziME>-E-1?-XHHJp0*r7YP`uKP zksKf*X+({ivY@2N*O$*Y#~8-JkKop!`O{K+=)?m{-c_~`tafoVZCopPEi$8Agda&DQXTk+KZ^{OBy1N zndj^&A0w2rEWI(m@O+t`h?Q-Aw(siQ50~MfDbje)VXzkcwJ7Q#fD4F~Jpq;^+raMQ z3gwE%B~>J&!^OBIoA~yO>|3A}aa9lm@Dp00Yr!Z-lt->qnUZeoTtt>C6u!_=Lv9D{ zehB{Dqi;qN`7QtsE6-5T!oz#*f_y1RPsQbBbWSA^hhUGySj(Q^grPBAx6L_A~ z>2?b5Dts1VkylN6#u-x9g1Ofk*T+Yr@<<t)7 zBPJx~6KOfm9B{>~NAd$D7UBUB6ZWfy^A7iia~n1J>+SgB9C}Hf!*p=#s&oxy>o$$v zzl)dbwmNW?#hQ_D^8S?xQ*T{LG)wnr8B2Q}bp7!JVs(=d}0c2h~G) zq(06TRs}XPit}J4W)Z|Rh?DlTWIRgD|NP--dgHe9A`dMih0U>0+9>Ly+En5NKI{Uu zBIQ`-D(mmI;^*^&`EH?n{u2>dfG$!dOd7@ji)i~c&LMem2y^}#w%teCEZ?b~yUf{O z;cxSk&!3#QNivu-;Q93xqj{CuG#;tHBilRJ*{{Y2xX zZ8@KoX-ZeEs>S!8LVemcUsMPV*G;Ohxk+C+xP~kswC1x>OPA3`p7QuktU4lyP8i2h7zjJ!;fCR>zrYJ zBOyf==w1O^-e)nvI;~W<+|dV_c$1zG|73gjih@Zx)$d)hxLYClvm#7gzjTJZm5dzG zH@d{QBq-&YoACtQB>X#BTEI2QFZ5m1=MM)`JG>hTz74YkzIXAv>&POI-Be<8Oab@z z0sJ_tR}aX{0de9AkQta>MmH^B)bk3mbsRhk3usVnH%VW`&-Ht2KkvbVKP0hqk+_LtCW=paSb`YgE%B8_{gumiYF49{9S`pKQ0Koo=i2WiZk2T(i(c4g$~W`* za%X#fo!*sT#QwE;>w}e_=i6S2k+Yvr^uM1wtu;nsb*wMuk86oDT#CG3qwT3k>cNlm zj=B@MCpOC~^1AyqR!^q|n>d!IP?=Tx#fgN`8YOBQe(AbsK1xoBvRI$7*yngEQOi3C zD3WNWF*C!R@%}HF3l6UyZlH@@Piotv3TxDJ_Fuz`6r z{D!qoij%H@E-5DHTh+VnX4G}@cg8uw1-Gjz_!Bhm?~&4B$h^9G49`qwrF)wBrmVF~ zxK3IfE)AlK@IK+_D3=r*O1t+V|MIBP(IWo?Fr(GDBiW&V1FvN#oIA`3C)i$sq^(=I zM@AiAMs>IIg%cB(sIaVLX-Q(K7OeH|Mp~4VC})x+e^1LeuNbFF8^LL*(0->%Pp`=- z@7e`ZVS&g2-91{qmn2KA7JOZxQ?Z2v5iIK-(09pd5AmVNUWdXyb+#9bDtGUBbe~Kh znT(4@t2&4c!dlt)h_7FL^1fZG;A(fDhiAVJLY`#5G`{wYZ(YBCk9=A}6LaP3fYbh` zpn)KQfnfRp7~cR~W&oix5Mn(L>NyaG7zj@qh$tM0tQ)wB>KTZh8i?5#VAKXO#5K@^ zVX^ds2|5`}JFujs!h8~-fH}(Dfo83xYIhkC3kx7eDKK$rFl?$VqnnU52%h^926Rvq z0KhpDT1ROik=kU8M=;j8!uX}ZGI|BZ;p9eMFg;jFkP8Jx6Udg^4}-N9(aUGXDP_;W z=mml0*2Az$d7#iM{<)!g3Lzzs;CDbq4qTF@@I}L^a+K&Du%~dwa7*bhm}O3hrBf+V z0p16K_o=|+xxidd6mGyUU(n#!#n*%%F_;H{OpsXQ!_rHD={kXoX)tE!D8c~7E(p9U zG0Lt1{Ne^=mQZC30x~Ip*#}_DBS7}t@GGbRjM*GEp#r8G05Wp{7p;Npg2S&7YTwsY z3^m`_j7V(=!d{rbp=tM1Pt{UEiU<-QznkJQ2t@#jLbQ=6WYm>40OW*OfXM%THKGCl!>+PmmojQJvf-H{zuM6hXS&jkUobhWZ%z-&h_4zcj7=*bW+80!)6eUdt7 z_z+F*FhUT>37)FL(?BQyId|0Iof;fmx&Q;<&#Xza7vh<_BJ6XMyfJXrv~j`G>F101 zFR+LB1$D?awFH<^nE1hL66$~xLIXY+%j%5lC=B5Sb3K@$cZqpu3XBRLM`Ch!K5$tA?3b52^tZ z8=VwX(7w9r2KQhqvG~r&giJVzft>=U=%+}HU%=S73;|6rYkn{t*L;eqVOTZrsmnAA zBqFUH=$@?(rwqTM03LjOr)sGWR2^j)(AD$O4GA|?ub(av1!MEiRi5gHBrg=9=xrLq zSORA#Mg?jzaY#JU(WOsD|r1Xizx>mK#3LY7T3g zUbH3z=6G>23;@56jIr8}*TyV7lbtJ`)-g6Ufdl5sLY4}psfcyE=J?)p7o?Pz)eYw|uD8)a9L@24Z|mJ3R&IW~F0fmbhh1|yYja4tDHJ0|sGi6GRar#KpcGyZZ?0eg+ zddT~Xrop697&D2+s;7zj=$N}$xT(u5^H+5%U6U^y4+x0XA3F687Z5xUmAHy9pU4dW z7FR})ax4s%EoLxkf<*XZ!*# zV@F|4p|gFm<+8P98x`Y&I+(+k*F!!Q?UT)SV<6};F!>HBmy{ljSs^c-L)lP`42A;ne!FqG8ZbA22v;4dr`daXiXjb6*G?~T${NfyVNmfu8hbr z&2)UfMc|{!X#w1q0-=GZkPPR{tsC$TZPf~|Uyf*a8!ZNg%bRCbihmsI=x()*>@=(? zzeH~dhrQvj}W**(JANX05MJxQcXQX1Z-fj-xK(>*y;pO zV3dz~Ub=;`C4lu9m>Wiw+bRC(+e`6%G=M}#ktAzjwr`<=Qi)OvJ%Xg94)AdLf*y7cqxB2Vg&A?s}D?&4ZGc8e12Tl+D^DVyOmiA%m z5^hnt=&Ah;5h(-*@Oy6|$mhQL(6E?~D3zQl%0h|I;j{PjyogZq~-)0EX1kee{ys<6xd3X6*!Tmy8TW@R8I(yc7 z&Hq9(vpb!*GneVyT1JLBUp(nkJ>sF4+*pL2x-2j3i^LVxyAY4}uTIU;Wi$HqFnOho zUtfCmJW!~b%*4Hj$m}+Lo?UrA_vN>w!`;Uv=lt}*(m_3HD`E=fpzJahi(**aE#5aEgG;rTOxTYkmItZiC|^|*N`~&WqGfVXZ+*8|KW$dd`O42D z*%$!+evg$`IL?lG3x7mKK={Hn7zg*`qx3p`j z#`6EPD7X09YYCldE3Z-b{P8n3o4WlUH6=ghfMBQu00N@5hDri}A@ri*)vJ;)Y+}Yr zgK=}&;5#_tbvvKw2I6St6WAS&>4%b7^6lfM;1V&n4YBH;r0FtOs(+TKCvz6(}lP;5-WMAm^EA=c8vMc4`jIwU9Hn2-K zkxulP8lSToR0*CRAMBrVu6DxE@$ZTn&@EimIm7QxHR-Ot>!rihJ{+jwwvI|06>bZd zx7=r#kqQmXtA?@|8A(%a)-an)#hCU98Yv6Wuehms@mk5-<|_cv&((`UJ%;gS-S) z;S2gCO(h|QWZjgW!em3oW`~S?)tZOxa!w zeoQ%jd(BMG11~R_a)U92ne#%(9y8~|{Ypy0BZM!R3m=G2pccth>SZ{Q3B3s+q`6&2 z9uYb(m>yQCAcIQL?CqZSq7aiGL~dC~Tv27fx=^a{ zbCaGrupzV&Pp9J*AN0kvQPfr$5luWBg>8?FGXmw71uD6*9k~#gJ&|{7MJ|E(Z-B_{<0kHrJ11GhQq4ns_vjhZ@{_{*0=Y}w<+C$huA`K+W|J>$2%7+|sP_(=TX#SNni6Zs zcidXPL7mPFbU|xW5H!JEag4J7K@w^u1Eiitt$_e~DpbOd&=Oo3h#tvZKFO!>c%L4iQM zA(8wl&_ssD!QiPJj$59K`Vkj|Wfs)6`|^Ymi<05K()Y1|{5hfq3kHem3bi_;50sJ9 zhmpA7X-Sgds9217nC_)8{1K86i+N@6;?Oji++1T3APO5pQ>rv(jiG<=j$`+#!67#-1+7_Y= ztmyb5ymDhOg6QrkVSCQ2#7!m4M>5jVNA~hC5|w97Itq8_EUTLUSU5J&Zf>0OVKm`2 z%(nry1f4t}PB*tFUka>ovV9d>zJD?_(4p*og%LmRSL3N|LUjP5@2xF-m3`PVh*utm z8cIQfshcLn&J^)HXw%W0nZ{ZYbkT1*q~Z2qk4_F23VC!9gMHhp6qCFuO&i1AT*IDz z)Nv=%BjTe;X^rZ`J>J3(rIA5ZwWf#}Mb5cfaSXQum{hDB%b!p6$1EMsaCoH4o1qP- z0tSq^(53ED0CQ9MM@)3ayAzmuH_W2l(^g zF~>V<6CAe`t5UZ|5zF^MNA$)eH-(LSlz6z?Zw1Ml2Q8gBsJ)6es`tqd@p8&|IoA@{ zQPi@-f#?{xp@ISy-7c!o49YVZZ;)Y1k<>--JSIn>21D<9Me!8oD_^R?la!Zg$8O{ntx)uPd#6TacK%zrslD4;3BDLX`2LXGfJ1Cu zjG||7b7u#q?tTj$8Bt=d1;UBCQ9SQtLCtBVkBXi0IU8j)pMSzWdi1a9-``#FZPZ+9 zZLOs)=1QTzoC@`Kt#=2)%3?22C22_Bo+&M-PSotaFfH7+8nG#X{3e$IH>zPm@mMyN z`9{OCVRqaxlw8&v9YvjeI;S@h6Yg0@v6>TePA50*c|#Qcvj$yKvHWnJxQ(;s@0ZU8 z{>)Fh^b(>!$~)#>4HAsegt*Ka)$YCI+O)a%!nl$rLMhA%d3U-ha6-QLr#G7$_tY4C zB`~*ULqL7Edn$(E=Jf*B!p{-nuDU*-%Y>x2CAMR$XVL<5a7kvuH+tR{pIxreklr!L z=y_MIu2_4sVaNPw&-=!QiuEqiyVh@eW;^;78}Bsi+W+kN(D)F9#Uj(SnpZhWOQSgX z(;!ZXL*U#}GVH+-Sl^iXVYdHX8Wo-7U+=2$U5HC_*^u|c+p@1ZyQ zR>jp`^lJel{DT(+!@xR<5~gu?Q5Qsfbvs1?`%HIZ*B6Vd^iVSm0V%e9n@TbU623p^ z6IE6@6VRi4wLcgmFE0wkfk!S$w9-=w?6yEAD!N!Cvqx@+Af6F4E&A|h!ySInUa-z9 zN!Db4P$XI#tU>VfO;ZT3;JF(xq?Z0LUB(-Okz^d>+PD9m6uT0EqRsB#%4=?Fe*hsn8rS882D-e-t}HvuhBun zbzJzz=Ay3e?WN)U`}P3mOB2rN^mmW?|MYi`N>YIdWOBiQz)HB4ewr^?$K`w02Q|dV zgf}4kA5t2B_WddC_`muK+@Nj^m2xEOC((6|fcxhtN|Jy5Q_bHT+e2#b5=xVX^Ph+h z>StF{{SPIdvttI;0U$!Z^^$Vj=bs^(`|(t6sZ!oUf{F_D7vAyA5dDGvq6A=I4#TTU zxd;G#K17n`$S?TXE{>a%kK=iJ$_j+%F4A|PKRhT@cs=+o9t3c9z*>=?4;E{6;W2Zc zj`Yv~SAq<@Oa_jjT9@eT6WhdT0*IbcwwZ;wBB~mBiQ&^lyeHl0@v`8%Vy)9b<)P2I zT_w6xB{~s~D#0bX{>yBQW$jgTBhfEjn3KD?FYs6M@C$I|h-J2#CH1+h-ha&)ITFW!4l+FJvv zeE}OjB#>Kv$}b@H(0PzF^r4|tE7wU9OXdwPzf@h0{ayZr8_$1==Zn-tZ4n*ANpgS7 z&#mnWN)-y~LYK8GE*l9cT2v@H2r0Q&DESI0-xJC+D^iZBP)QL|&8|=_7E-IOP)jgh z@YcK1D0KB9B(g>Sl|M}n`%*|XH<6G?mSMlS?54tnX4OPTeVeLv+lT#t<@MPx zFJh@}?mLY2XJ9b>Xsu(7C9+RBJLz#<+i?5mCUWfNul>c5n9t&cwPIyxm&);R7qJdZ z59&5@@O~VWB5KsP5&Jc_BL0;bRK)baH7ei@4ejCL#1=9u>U68BDl4TF^5uaUHhsR* zlHb}#KkEUf7-_L$sIMYmf6}8Ty69OJN!v5w^`@VGO?1Cu`J4G@U$I5AYTrPyxR{!_ z6tVd1n)qU|gzB1vMzO?>n#6vwq~WbHanDE;iGyOD2*^)r6pJbzsx*65$Wi&m|3+;b z{_~cY9*72fyl;L-Wsr6KZAyxma{|a_aIi7>OA+^=z#D@Hr%X&whT=KmID&y}nor_q zx$%7_ou`#IA~kc=zhjKr8 z73+KIO6P{Kf}{sY(kIyFz?>yBBxQWy^|2NCK^5>xBv5xQ359y|H|Q2O zf~lsKjC39RjvHi`1#)iHAf@o^vUtw=9ey`_1D3?$Nh;q&aLNvzi{vveNqF#Z8y@5? z4Ip!zvIO!Z00t@T0vYoVW^Oa1WePBddt&7)VkK^OC5{9un)_@pA@GmwpDaEC$j!J! zGvNT_J#!~@c#=4SNfCHp-m4qW97u=|V86ViHy!Z%5%YfG)c$Ff@k4UlAduBASEmLK ze}d;GGQ+HI|17DudBri>v&$h%s)Cac99;N; z+w6RJL}nT%Zu^TS={frRp=2L{^qg<-i&WiU?FPtvik=^c@I){gTHcE=Zj7VcHP_^Z zGk>nnu`|5!xOR|A2ZSEa@_$3-v>Woa#2{w@V_Ewgre?!?>E7($CUyQ`(~ zNHT}#t?^4YO}=I7sQ~|(fmlK3^Z!c#_-r48MaxGoLZ5F->t3H=qfMjfKQWS|xv`Yu zhb_&WN*;>NRp#kTpaA{g+STOj7+-$9I0tL8NeKBl`N>w#uHuiG=ha?Eo5s7WpgpW+ z`R3jy!5K_e)Aw4ps~q0fmTs!gS6zS%7Ms>Q5-=t_j}+UV1n+JYa1nE+?$G-$ z`MD>E?6<9S(C$M&lVlmzr0-w#_g4~{%J=qp0``NQP5rlMT3HU_8#d&%w!w*Y zI8U>;-F7;e&)<&22;T0!RcocUxDR`A>HEW$@`)SYFAcIVT6|}f^H+CQwkCT9jI+{> z=29gNV8oBEcXOOAdDPDRjz4nWf<7P`tUmUoMdo#0NFFQ+}$jkC#(I{~7v{_F#3s zTo+rv29o*@cE0TUXxU|Qj@~-qtmAgXa}ozPJ%Pfv4{TZk+_b;4HD@aO-0B9HFON1a zeV4LQ}Sj8&8*8F^~KZX!)FDDT*Aakd6ir8oSL(mU%Puwx2pVr1n!G z$2>CKU3Usz(EcP|oWz3N*5{L03Affo4I+k~YKaYM{Cr9@^|Z8!C&09|Z(hFYzC{;s zS(i6H_P2GRcaUz$Ve(d;e$(aaoo&~jUp9DtS%31f;fFTE&zFt9v>AQBeB)1Bk}pXN z{y7=YZfprL5sF7<5=_Q*O=a2xF1P3L{Yt~NXBjI7THP%$psF3wrFbe@Mh)?)d`=5i zOn0R|Ux~B+Tpm#QOUHWBxf}T!c=8NnYddD&t1Zaac76SBfj6%--2fMnAY`VA zawTA-Mmyer);Y!ZymZzj14V@I1?nofbq+a~X!0A=2v{QZDN~V?_dSnC9eS?6^-w^O ztE+dsd07P+Z$Bbm=&>hF4SL?WC;za-U0;5RpJk91740#IoPh+d6-x`zmd}9SVV1yN=Yt#eW;+3T9+L z_M%-K2G6&|o-%~?ZVz1iWBHT}w^`BkjJ#Cr-~>>CLc4T{i%LT+y5vDMROuabS7ZiA zQbj|63L-xm>hOuu$Oi3g7wZSpiQOvJLIgv3x~|v!ab$P6KJ{n3d+59z+FiAv(}kB0 zcUG}0)gR#PJnq!WEM9yv#C=59lSS0+qp1LhcB2pOcmBBB9biX(OMb{UChl7NKH5=B zrNf3xcP(B;_Y@c!rHO$P1Ifn^n})J0h6I8m^RJ+D*tGMTRI@V3yd5EWLxoYwBZW^v zn{rA9>mjyRsIsd=#Z5!}HL7ANrSTVV`B9Og&D{nDszqy{Z&}^?00PEa1#lEX&@Aj% zbOJ*)1i#`%mlv4IL62=e>AVAu(ErubEWDsprsb&ynCsRH#|xD@mW+frl0&k;gQ+AX zd~;{medowiH3Q9%K=hUCs1yAG$8xTir#YItKYr_mc^QDSvg4Npf3i;3p7~Qrj zc(ke$;;N%qSStCr=t2bilWKMozvN-0+##K0^WXYJDrPV8z9m_-FOnA*DFc2Xd9{G%=!d0rIaT#&)svR#$>}#alBB4`s zh%=aa>4+*Be*EUk=|st0t#HyX?~6;pD!N_a*CT?v3;5q&x%N&caQfndnbg(y->LI# z>O2z+eMWQhOfADwa=P)DCfGFUtiKfN}RIJ6Kp zG!h%WQgHh1&FNfP_-j~~&?znaJ?z2wLYP)2_4P>Ku=NmEADzVVvrkb3zVT}>ZNp0+ z6JDnl$&B{JpIlpx(p-qu+?zZa+I_GT)t%*cw*BRqOijNI3MjTnH>Tjsy%{cOptdcl zE-%&Z6x;v$Io>WiY} zB0s$N)-y3(#;v!fTax^^K8at^S+b7hWPov(|4OO<1d47haF-n)1s0-{UG>UovW%9e ztGRRCs)-OyJx)MrXUe+t@(De_;LePGMAw;&L6 zx3*!SgK4`Vjyn4+J@hio4jmKLA$?8aSE@nLRqnrPN)J!`6y;1uqH9;wwZArI2+F$Qazrb>7r~avo5Vzdz z#%{^Nnj~$Yj8Bj3>mJWxs)@bF*F!2bASb~g?u6rJ<-&nP&`)K)J9YBbz5V%jcTJk0 zOi%4kd{($?KL9;9c;!R2XKq)xojUXWQLgMuOkujpdt!RBzwi<~e8D+Pg`f|6Z2&N~kqo zOge}aFwu2TU-pukS9dA8G+n>*OQ^w3!@>^#$>Gxk*R51I*TKer97|%p27q$2H%uPX zG;*0(MZm3c6|S9)3F*WFxeBEhA$Q88&yHMD_4E3K1hIZ50SN4$@XFD*#`cuH?#B% z<$3NA@;XW-tSq_SD2RN_-Pw3|zde5!lmls&3p5+plPU)Xg5+bZ< zu}56H)XtWvFHLjPO*a9G{WAM?$n;}Id)-Y8ULCG_H}!cK5P$5>+c|q0(@RO{y=NHRTrBQbCo*A}8$cr@zShUgvPQ&r zJ~{f_^}`3X*cZS&VwaqHo?sP;VpzVZ#!=4Yg`>Y_doac^L;evR9%w37&MD~Qlzax5 zzVrxawH{b6ZxL6kfXE3-ymI-?=)pBNf;<1T&gU4636G0s&g%}Myego7R2ma~c0TG5 zva7RvK7>CH7{y=?vh&7na%fn3O zFh3~!HODXz_&b^C<^~XGVg3ySCL~RYkp(>=2WhDf&xL!tW3RbEoDeP<&E>H{6;m*6M z_-QD?6W*lbaERuLXHS__BqTudUfhr`$Em9M@q2z01OrP)CI?vzmrfjx+^ca*(&YOt z`82CgPUmZ{3v zI>sk0E0%L}(^!|=2+)_FODSAc)DYAUxFqb*pFYOro_FcC^Bo1`1upj9?lD>rD}KfQ zv0=8gwDX(Fd}9S32{-4lBm;N}6q(>(-CY%TEfZ7C`?m0vYK8^RA;+nKs9KX!M;sV< zZi$%@o5Xe`fk}EOGw|)Ryy~_wkn&-lXyNN)_OO)3vV@=2a`=xO#inK$;LAl#nhax$ z9Me;udll<9Jyv5jgD>BK&leVUttL6RuHH$=NKi-uTHt=MOI|g#6B1SgSA`4l^lp)L z3c585jFH|@{Llu2iO$>k>N?1YxW+-xV^LFZ(_7e(i@UK|slIvz+O1XJs{%93uW%SmI+PSeU?; zrCq5~>i>e9(oj>z8(BWm(%nsCY^&#rdrggE;NW3Z;{v!oc0Y# zm7d{{zlXSJuY#0OdC9_TjY}{1(e!D%QUVT$6EDQr)-;=>o3Je&9b>bqt3Oc=P|WoV)+cAr!aH~lY`28N2X7?G$PjRM{5eWPYycHeuZMx@;KBo#LnNw^9O1-*_DjgW4XZWNG_-+Vea0E}sXW9ZYpFfQ`MyQp9os zCMNlJco~=MJ{?W4I$VS9HUXF;Gq=xB=Px5v?Ng>3TSEh12i5tkV;g5US3yNODk>Q^|r+IZQNkBgJG_d#T_fW!CSyy{hILn1d;9?EZa*FD8-uVeU7+*Iv4M<_}EUYju01~S(8x)pL@E9JMhhNkTSx2yZoyIl--SxDkyrjPxwFi*ZSbe$YnXfwxBc>!;0!{7Y%K~2r z%C$}qjWNRq9AblPWT1WH_&H9&O=!+h~8yA=LsJS z4a?H#dw;*~Xq4w@W%~R3K-zId@C8PwrB>I@nXq$k=_ji+t(>RP6cyBbkh`vANAUex z$rHMwU}=i~$V&f<1rXZGbAx%D9EOCd2E(+7exSnGLk*;H+VRbx)>pW zfQOgUiKk<9IabdN8z}D}jDL_c*-6KRT`Sp4TUX|3GIL0vTir7+I!m|V^Cf3;I-zDJp!HH zhsYduw+QOMHGuhvg|*Y8%P@iUDOE3M%rMiozY7 zt{1ontgStMCumBOBgxO=_s&G53gK-jig)?$VvB1ClyV*csiw9U>U>of(;98p`+5NX8L!4(+IT{`U+Z z5oeawU*6PZN3T^F?i@7Gf!$eV0doSTUOGKaF%DaYZAD0k3_H6~na(2Q{pghcHe-`; z#Q$dHPutzS$jmmsD~=Q$73h>hvwyh%CQfd;`^h@}Av$q6JBn|^czjpVv$3rAJY;5X z=cl-b+)F1fGoRtSOvtXb_0A^0-R>MT4UA=r=@}`IZvmWn<#6BAN+9vt> zQNcR^Wm@e!Uv3t^e@g!2O)Yd>wR>^?us{By&Hmh6qJYi-FHOH=B|~gpU@WNu=WojWtO3i zcftmh!(ZMHAL|T%^Cx^-`N8}959T``Ed6<~qWo~<{=@Cghu{7@{Gt5l*ZoJwosa(g zc?496pbw6KbVV>7MIcp39Kj^+F4DQ07NZg=5*#Vs6)AlbDW?*p7#yYA6?N?>3a>)e z3MT7yk!glqFC%c^2x9a#%V^Rv*-0hFEjUKTD%xl6&dsCfjeFj}h*+y!HF8q#F^py{B1;GhVx)K`Z0_{=pVZ!J4o@kBo#Kfb-r*nyZZEZ(l27x=BBrDQ^t={s;n@FM@eNnF+Y!z=|d=xY7wmRr`jn^k9w&Ls=f4jrnh!~zIikF; zOz*VHw>{47%_~+_&6l*!Es;pd>n;MSmD1bXQa;a0tG*girPy+px#X2_vlNVll!}Cw zi-#Hxs~8^S-AI`=0n!33MS`s237N?t+Va(7ft_Gdi7LG zeoR}NuTaj|C*3EsCO*HY)4GZ~wCcR|c$4w+PL^-e#tg=0Ew($gq~_58(O%2#Pl<5#5@Bs^eaT^q`+655&3& zg1ZKw5qVf`o{ExV@4^9S7rGsDMQ|vBX$se}paRK`fK3duO5wGb2U!nsn8^WFX3~8h z-p;$WhLOC0z_3og=FUe~gbxQge0aM#thz}j9m!!`gQ3+zbl@5Qb5}2{%LZFG&|YDK zo#{@?>CuSnRRUywoeqlRmjxCA5aNv*aAj@f8$Z>62MDNM~Tz>&eqxQnFAy`6K zadfC*W(3na0Nk_yW>J8NTy9yKgVy3;xj0xG`nf{*Akc0=ZgGISPluInl-F)lh`_Q) z;`b!6m-6+n9Z|jhj4Jn4J6%b~sMSRinQ*6IzI-f|mq}ngR&l;BP35(86l@O7G=UvY z=9Spj`CtGXY(LEKFsxIkkX_89^>*Yd$3K%m^b~TDAF#v^`iK2`iiJPG z=nnEnVj@K!1R?FG4gbEb%1vrl%OK&PI6El8{`Gt*ybu5%#lZ*Af&*x#Oh9@AnrV?2 z5Q%0Q7yw%>y>|+Wwk(2=4$LYBOB)Vy~G2 z>tayZBu9aM^^2avR+ua7a`D4~_(C&OD*~$Kcb|fB;Y^VOIeLrjE4)mzy>Jxa z*&u*29>J7}UbgRTf4{shWDS8kGJPaITPnmX+dgA@^z5P|rXDbCTLA9@3=a~Ac}t!l z{}a^b>sKgY8a+>V4nW|~nbaTsd@u{?LoWf*BanV*E)f$$g!V;@d@F#kUpbGZ{P})z z^bD{J95~8Dk31$q1N$a{I7k~2igE_`5s!W>!N?_(-@>41b-`PYFh{4}*@OJp-kEN7 z$|9ckQ_1-FW}eW4c`D##gj&v^DHlyNfjebj-o!9C=X zp=&U<+z7x^q7*)A=KQ8wfeYInJY3X4F>HSy9`}~NApzu8`!9r}e6}e_`qsMcw2*F^ zu;J`Km`d~VAQ{H1?v09L6Ei7Q0iwy*IWKXMz};dXFhap!O{g0_2jNw8P6C)j#xS{& z^yk_jbY#T>d3bUX_NSE|w-Qk-eT8XZ%vZACLlTG(e&Zd}JFoI+uTbT-h+j7N^klgf2YmW`U1uW< z#IZ9%gEYg~nO10}_iSoBE}4W;q11K(ZjILuEgqWZoG>ZH?2fU8)4an0SdE6#uU%0 z=#03ajV_@ic56Y4Wapw$;}oGEU6!&&>Xpv+!mTcX3H}}P<;m9^RE@L4wmly^s_z9= z2xt(jh2tEUUwKxfs6)M+jD`kv_yX(#K!}?|a`f)prkU1UMT7WgVtGqhx|>~dS`1F& z->}xbSMkclcTyp)MJRZ@Hm@trN=G~3GjNK5x6|f4ocbz_B-Pq!`p%|_ecoM4qpqWt zpV!kklXkmO&wSb|$~XvG_K?mE7_CniP^QJsF1Hfhz3mmS%kBUMMRREbnl=0C=|_zb z8o@2aIPGA(jE0`3*qkmefhYTl=WjQ2 zq6xCC9-evAz^E@;Ko>I9qAKv>E?7Lhei9%SI~>a!@A6s8>Eg&OS9C zV#_i6@sfKy>COoJffQw0NXX~Y80({kY%QUd*Y_5DpWCB2v#};xeC8@9oxPl17I|*E zNj))7K0-6+5#FHdD$R}69ZiE#-$VHUF+#rFO)rl}ru=ek#}_QKErmaJzzrviZ}$)` z(Y`qv84QN*8k@Ol?lz2zQX&CUZ=xe$e!fU@5pzv+(9aN(>VqR}pXNijyp-yT^WmN3 zA=#@;tJ0Y^dZ*0jLP!v0QCV7^XzQu*@K_cW#HGQq^tGX9PVR8~kEDKl+9`nIZKC&u z(Vh0oso+IQZS#iqho>cpoLTI&vB`%q(2{@qvCkxqZy0STIBF}EtKV;C@#Xtk%J?6O zzPD)DG&A8sq*Qv|D_3o3MLPBI)juj|P?=)f3nPT-&s;lFwMF?I^L2P^j64M&*Sn1Y zJiJplZM|Z>yJKfs?v^$QAqRB@zCkphx}T#~pypkXTur5&_IH0I5-Y*%ZT=uB+TjQc zui~->Ad*F7NsybRLO+*ZUXc_obNEAt>o=QedM`!_xgd!O>_eAsi3EmP#+g}Bl__7% zx6^J`oEQI;vJKR}$vDZzism^p*AZ{HGMz5RMz$oG{q+*1cZyYt#3!_CO{KfOb#w}L zPBFN&hM^2Oyz^k!gdO1c9XEMr@gvFJ;UU}cTQxIoO z;Ao}f326fDL>CvBS8}*9^-g9wDx&u4kGUnB8NtM5CdAMH!+Eh%NgK|uQ6I%14-P7w zqhsMs&&@QSh6>RMz^U=XX_s1OBVNbL_gle_q?+rJJpHambx`es>riWNr_S#%Tn_Oh9hoqTJ9PnhUz){*SMhX;E~!q94*HGzQx3tj|mP zX5WT#)lyl{**_1p1|R5l3H>m3mI>cZbUdRQKy!(!M!siAV-FGV_W7tAx6xK_xFIet zbex$%*s0O_Mbyi+evRah6nicmY2_1Q-Y6n_-9qG@aacmGi?*>noOb9VPdZUry=C0E zF5P6O=)&D!rumE=FTzJNx;j@b zM4kr1@$4dhOjL%eL!QIknX5aW7ZWguj^>F8R9O>T?+ff-JpX`tuI;1=9qGo)=%85z zrdIDLo|Fr`mukvN@woD2NkMCC3k#(u;}%V3f;WUJ8Okg?HE8%1PO=(S3bvna+3#@Q z>Fq(I;FDiMyw<(>24UwZ^R1u(1XczR9q_WdYP5{8VoBG+Yiz5o5eY5N5R}cq09;E% z=ul5$g@ujyf^IiO1w>WAIUx^mPg+Z~#3A`oePbjiNiok=EZ=q^}c|H;W^|eeFEhk3* z8wJTgT_KiJ)J-&diAZ?1y3jXS?WD&uBh6+Gu-hNH=xFQe3l?Q^3^R0u-PWF2lcu}e zN|Tu*+K-7>K`vKd%Qy2ra^0JXWaqb;DV@roL>3Na#z2Y2G1eljp!0C;Oeb!&|Nenn z*dvm7{KxqT=1xD1pxi5@mcDaJd#AmoYampbVCwhdTZg_Y^kgoc;ppk-(f#xrSLq(G z-@pI*+2?w{e+%R*>8nxMXY4zg75#Q?%-}4`u_F$5TRpxR6CJQ=J^&O4}=^-45*+wA) zSeivJ?cC;`Bb4L_JMsHgI+uJoJAyN)6;Hv#?C~`7$|-i|fKYX3G22b0^E>YN)PFqF zY~=e949Lq-_fgO|wvYbcR$&~P&F^As1lkixcSK@}LjtViC9DML#X#IO2uSdGw^*Dd z*tK!w{NGv$l*9hj9Hos8^fTj)y2E4OihNf_c2v^PCz6SqAPs-XP9?FMo-Q5HeDClM z7FL%-OFcPEKuSM3LjA#-Yf&U811jSjw7i%7$mk zm$;Penv~tqly6%p-@&Or#8Ok8K~3i~m0(z@F=KTbebYYl{=P;1J~T{LtkfUYga9{k zG33gEe{NA&AZhBs3}^c+9C~SIh;!Z_-WQivJYcAeORFae_!={D9J4enhyITMh)9#( zPM6`fbTUqx_J{Q%m=w109>!^<1BL|SG{F#5DvpJQV_^@0H7bKwmSM7EnTFe$-a;9) zDF{3O#<9)7zs|t1owndg1N|3*x{FI&X=Xg}PZ#e_zY(A9^(32&%(8_5NXBWYIHZ$5 z?DILBuo-4KhHxaphxfs~2eLIpa4M3^b3YjBOv4- z^i2^^#{npH8CHrY&?Zu-`_MRly*LtHLhS{7}&nCqA&4~M+JT+DgQa?)IIsF(J~ zEB&uH4Y9CavhP&_O-TRR&3ptYNx>l(mRU6NiaD&A+L7sS5@dV6^zILOfH=bSxQt^3 zLONz@(c^M#Wuig4HZ$iN zBPW`fL8`?!pjD%D*>rM@EBh=fvSq&^V1PfPMGv#FQ<}aSc<;ChZjyeu3?U%E7Wyon zGr4E75WrON?=i&ZeU=3PKqS6uVxQ%+@ncO01hCKOnqSo>4zfkVIaISK)A_!#ncOz0 z&Jd)8c%?U_qQ5jPOtw=06@rRj{vX6H0<0mC14lAxg$hRd*UpF|ieEu^RB!azM7nU(l4w`Ks5Xq>hT0Yu9__1T1!Hs=o8q&-GFRfYlX z@ieYM0UI{e8PGOBL}~C&ZfaVKb60pxr<|o zSx7s4k_DFobHukMQ;J{3BPVvUm3CRgV2!JPS){nzbN zUnKmw*mM>RoxZWda`QT>IjsHV_1;c>YNzCoUq}mk8kp4<4129q-^^SN02m}RaeKeC z0$E`<$y*W0uu5ySpf>==k%V(HOs zq=WeL-{Q?tm?xHD10IqszJO=!avgLgj8RgE%;teagCU=%j8nHq|0TZ6NgDJ2)yeP{ zwyoN(k=I)eD5-eTkSK|evg^@`Z>DR3adgw3X4|HaA&wP>;bx{fRa9%@X#4Hz6?C3e*j+e3>iE8Gb(CzW z;*-f=;V)1t8EUT)MT^vk6^4q1lGv~zx`1-cTb9#9qZbU2xwy(_{;*(MCZ6ql*-%*3 zaXD%MBKsFw?hkve$fsNZ3L4mcnW@a}Mc_M)m_L}f9bg0GecMTQYuxo)NDNFpBX=e>BX$MLK> zO$w2L=+WGPU9sg==gFlmgB^MsW4UujWlJbCRlB9LDu#2>Ov+KE5E5lNLXI)FbWZ9i zW4shHoF6m=;>3 z7oHj}wEHY{CNFe1EcCuvc=m1KIn&}`QFae1Wl?PLyz@rFFOI!gyvWO-2208)1;2Td zl8%N}`7dD%mI}l`ap;dJts2d-@uh&bV*a*`w+0_dz3ZAoep5moG}lceQovNht-Ki2EQ!fb2j4u;UL`;{-N0+ z3Htxe)(l6ZA^^~)DadJZqQ=fArN5szr$4b=K|vk3R_&2Z=(*4KmaxV!zRb+e`;6^d zAVYwo9!A2SvReDop@NRl-G8$e1v0~dZsS0A1XiO1KzDo-zx~_bL{9%(n2p>5@jPaL zN8g}nq29P0EWFE21Je{0`>%Z&+L za~xjEAZ+0?5H#jdT%vBXk=HD}SOBO9Lr+fIw4Ykpb!8Y3qu0dI>-vLk$bR8T+0``u z(zf+vHmQy`xg+XL=!+2sXLKN!6a5p?ji`rPeZY0RK%6=c69oXyFKuD?D<;!0JkP#! z7YI6g2CjLCGW8XZ`Ig-si`sQS9WZkX3{@II6WjYY0srm7%RHTZ8FG_ZZKt>|umBi6 zHv6|gno}Tl5@^5()$AY<($8FIgnaPnwePpkg=yXx2isf50`L33sjsS2MLtK#SJKsi zBl*Q6^dRKXt(6Gyy^Wc(Bk0&i2d#d_{?c6hXIL18Kko;9IT}9P3`<1#Z&&U3{60vb z=ds7p=x-1i+=(mJllx9@>D`+dY$i4Hks!y5zfCEt+GzU0OZ3(kzdkndzrm6l4fw8y z1o7{!gna%5N4BIo@OE4O%(vP#EoFtJBAH9R@_pi-WCe9FqAXH>**pRnmi{Vz``fqV zC=!^vvxMh(v z*Due9JvlVE@l@v@)E5ouk0_Km`_rR`s!7unbF}r`KmDkVdO||k0T?7i8H`H*St<(< z(G0F=1|oVr4)dIDF;AcX+Jt-c<+v#6$w}Y$6Lt)xv^V`Mc!mRC)IV@2&x`=zXe}St z>T(JqpPd)n=KRN{T{3x$Dy^o=wb1=kX*xl&bDRGzL9GHjG_T|`J$oEj-TIL;2DfEq z+u2|6y-JFU%Wm-Mf0%+f*Wh_ct_F_i#J$MqH4)u4UUT@fzUksu@?NtdE-cVE15< zjD2sS8;i1(_tM2g-`O;8lvrU){QZ6)C%5n9P@bY+W0=E@W ziK(nG>f1$`iVGvO{<;e)`|{}b*<$54d7XS&u~q&Z$MG1$T7^1Mv@@Nc&a|$Et4_k+ zkqe6s)ye3kKLZe#>(2uu=FB)dr*ouk0wC#a_r5}el&SFy5&TQeU~vU9`X*RnnUYk7 z&9q6XQykQU);-zu9);8u1L)$bX1k`P`QEI?w-MS34WNQGxYf8z`IJ@giddjgZXyEN z#KWlY{#|pW)on3D6~Ur_$M*{9^{f4Hy4-T%O%0*PDmy?%a^kD&5A=nL zthX@U;;lhqjN7~hpWg00UF|>1%uRwT@vMJ<0)~heh%q1r4O!6vq6XXxi0I^bE7c=3 zT+()p6)@9Jk6sMm{pgbV-(|WDmh>yGp87G10I&3zbiKeaYzbTxnZVv{R`>L(y#D26 zmHdEm)$F=aH=zik2mzo8(P4|B?jJnX>S*`$z-PIn+^Vbul*3eN=4`}c_J!*(!k%uU zahEEsvdvbKbR}%gy*y8Z@FAeL4ecMxPnywNHmPN_OL1c3<=19cX3PJ(d|d7{eCJzR zdFu_sd&w#=A;tMd;J|Cy%Fmu!n;uReQA1me0}IOsr~LfC{s%} zK-Br#dj`hR_$6L>x|#P1ip<>!^~IyATReg8MKAAvbV-RRJZmkhVQ~yRFHN4qR})wn zA9elSY`D>OG9{(~52s=4!GN<2{gq$ro8@J+#m@xDgQ_KJ9>r{p^KMO?9F-Iwvna?{ znmhWloDqOAXc9C|*VUQ;G{vwxi!jLztD#JxTfhOf-I`@h22#AjWsr^}`&-xWcZ7s@ zgSzx^##|$0%1e?UUmh{;&Zzmbds!e|Lgfn@{B97tO2nmjN86k0f*jc`B(FFoy;qh) zo4unC+^$QU@6dcrm}C=1u*4yAr|>&hV$eVvu4#*(34exTuB8aNrr*ey7*QKn(Yli^ z`Fcy85zu%%X0C6Y?dbpjNy6{t(ABK&$*!zu3sIR~bFxFZ*9G2zDMS<|#u09kOY9nm zIpKJH&b28<;()9_%sd4t6dphlpp224#L?ImN7rJ8#0|81;Wf3HfD~xuc5|4&oW4nT zV1Du4G(mhXN&_&OQ4tLU>+d?CZ_!raE&%q3)}i^yz3QupM*;C9gEjN~R))v$6jA%q zNNxcet!82RL{xO?)lM+LLQ|u1!AeK5e42HgBj$!DD1ygYEsg4xnyH}mW|N0d>o$*+ z%h8DZ_`7SYGl-d@$9JnxaD=@?aFatiemKY=bmrC@_H^A~YAANBN7HafSrcd9ani7Y3uq1nL&%L0bDN8#lsa;-7MZbZoWO=M2opa5C?)`o znM{T#0Sx>}5E}YdJk?@qB1fx`Mx1ow6jx)#2@Jrh zwShblBPfAiWbmI6xOtPVZfq!F_{KKaIqYIjgn|~a)DJHLTL6G?aU(qLOoi~mx5%)b z05IT=ZukWt=uop0Lq^>&(q7!&B!%W3FcW*jQH$8|Cs_=eMg^@!7={UFIU>|)eA5KV ztkEJzOU15DJ`qgEjl2IAjf_QtMJy-g2Z|F8HBmF4GfZk5)3Fx`!hj_9hbbTCFVbwtO@5{k1@iqZTj)BKtsI?TU!BMI`fMsnn&*ZeBP*L z7`o*2))X;2*aw;)sSYsT2+YV^{0&Yt3s2 z&hxxvBaGl1J_lj8i!i$baXW0I5BEs}UrMYUqaSO_k2WZSt~#t}n+U=S2hTfezkL&z?s$xwpo4~>CN6_F5SlF#qKGhXhH4PJP1zCdgDGP$ z24Mgo7CAy`>Ng=6t}iIA1BwYvh>=$SgE8T5vvGl0>Pykig06+ZRmwpxCICi zg^8%bZMecL42Kvqpcq3$@lZs#Z~`(2M}7g2a3mOT6vqS+N48^#V@i;cptd$h12Eth zG?2c*fV&?1v4)^WF#v-!K#*Ueh-3Uc!%(1a*o9YMlJ&BPn>a-8h!JOm#&D3v(DD){ zoQS`uMo}=xsPeLN!l6RctcK7b@gPM9;fbE92!9HZ5a|VmP&3QZC(OH>On?xPaE7)h zsGR@lqM~30*V=?`~56sM~3Zn5TZAV0K;%7&awYQ zj5_#(KNJni1Htq(463rrmjenR@f^hhTRxHsyI8oG~gFgt;75xJNh0w;K zgq!eBCS@=M@`b&OQY*buEX`6a6|uY|zAgPynz|qvfup|&K`=d2O-TeIMbqLzgf(ST zIL(z9jZ-=u&_a*|N|=O6AfP(!Q{tF}aOh0NahXQ)Q$syeL`_shT~tPGR7d}9oIuEg z&U<hz56iR7{nPI^5JQ?9}x7R4xQnP6gFWEmc!JRa8w?Rb5q9ZBRbUNPVI5XtEmmVaR%A_9WnETgZB}P}R%ne@E6uGstajo!l+m}EKhJv*#ou1MdZSY7}X&(*oOakS;Xi<2hrK| zx(HH54W6~n`!o!lJvj8D*SDy{OgUOS-_PR*xgrox-m8QrS|Y!im(D4lZ~zYytn^2t%d#Fv_0O7;NIdz z-{N6d!JS+?X zFW+KX12!`uwqYg?+Z#S&;$7n4)nB4rS|m>2_A*|B+T!#2VdRBcG``|4zT)+r8~mkV z^PSH+v#rU!t=1LSP}Qw6ZsX>CVnFub`7Gkq-M9xXSbG0e4<6ZGk5bzJKBhD{+?{M8 zGH3%bxQ}qWk2YW?CHPGQVS_d}va|5oLf*+H{t2m-Wad@d^@ZidW!L&uS4mFg!u`CQ zk>kPe*Go>?OWxbay=6snWiw9WTVCZ|mc1rE<}3DPVisn*{pDg_=2xcQw~gk(jb&@r z-&~&MR_^9s=H|ndvn+AjXEtY}W#t+z=fFj0{(a?c4p?&4=Cal0ZADGq3F<=HrvVfz2A=Yob5k$NgH~i5 z1{95*VuA*ep(g1=M!3`kYNmB!G;V04cIwmR;hjd?p?+#`ePb@7n>YsPqYhOqE@{vM zY8(dQp!Vk@+U898U9@iAkls`{mT8=gYq9n%m?mn2=Ho@KG-!TgH3;WsjtPY!vIG$W zSAwpc;g^n37>xcg`S=ebD2gCZf*U=pTq0~~-t0y5LaGVvNCsx{#ozwrdaRR_!g~>^Vm5fW78pj@-g_=G0C!g9}^JzGvd*Z9)d_-7fCnUT%8+ zZ33R{-`4HguI}NsE!vgkgN@mpsbvAhY0&@XZY+*%x7KCo7H#Q1ZtMPEMjme-xnQcU zQ6oSQF~IE070#d@?*G`4-JClB;1@6mg4TWE>&C672IQm;S>&B=ownncZRsICYrXcu z1lMC2Uee&LX$Al4n|@x;7U~Me<2o*I>t0_THgN2A?*i9wAv#{zb=NRf;_}|O>+b3) zn&}(Qxal2Uf<19MPGY)-T-T=J)4q`o*XJL9S*Zvb4hwc!^akhrrz-9~BueQdh~SsyOoQJMML(pK-qMeZ3#?;5w~RUQu5W^LLwT;GOq zzzyc<=2w0e?!qSK@y>3~{uzfw3*-M*?mr*xe9m)x25)R`XH`z;+!l1_uI?{y?Mk0< zZ}#m>f8xCLW=$=05;t2imhfu!^h}p@=2q`br|sA_W(mGefmVZ;)e-@>R{L3@4c>5z z_z#|-A0Xh(-u#auJ7Lobhez;mDF*UX9%Cq9axZ3MC-+}lH)+x)O?N_8CGL;_3Lfn$2p{BUFX{z%^9HYRdUt7Pm-n@O_kBMN zB`^2MxLw!|@oQi40iJhiNAY#%cb*LQDF^I37i^x0QM;{ZiV&CvadV2mM>dFT|EA|5 z5EzEB2+eNu5})Tp$8${A^gI7{X9$k-ivMmozw|{<^=-#=+zxe@Pxa*P<>}RKIPdxO zK6+P&^QLEY(dXUxo={9kkc6=2NeQ$5^85ekIKUoB)bji1IA}@Hd zRd+XrUMSYB(XHLPsp}v=eLV*F)W2&b&v(k_`F@{v;#YSpRam3Aa-6yBUMho+!rCJ{ z>{H)IHhAokC-b>80yO_X1B`CF4y1^d*GXnJ|Hn;xpwIc)v-(iCTAL^JSFif;9(wtw zZu5tAnQ!&|k9vRrAP|TUAOa5(G+Boi2Tul&VgcOnI8b3AHNOsAkWiO$&r*5CBfdz$L?mOed-e zn=ZXN>S>CwXQ%&M9UEzD)VEbH?d_GT$lhT|dqrp*dG4maQG15&QF=?^xkYOQO>;SN z?aIIE)@}6m_uod1PbZ)HG*Hj&4QB_BzI=H2;fY^-`aFJT`qsHq<(h2VZ4}yhTP;`K zcI+_+U`VV%Cth{(y>_2`>>0*jS{riM;Z*`Tk(Y>bL6(vdbCDrk5L~p8R~dy>xKLXH z1tAv@K`a)85O|dcKoFJXr3Pl1g)_-hE+Ls*Rp8;&ACm7qxs_NkMm42vPgZEU=s;MZVh35I^pp8IxAhop^!_0FZ1)=Z3g#*OYe!G6&yT(Y9)!nAB$I zDzngHyKI^qZmZ<3t+@&Yw{ExJIlJn5S9U9}TGlqZu5<62WpBCq{_85f z?Ov-czz36xu)_N)dr&m%gtHC+lPp|uhe}zT@w6CgtT31zPt`EUBd^Ob$sB%)*2gEa zys^O`uiUcC9`if1wv-~(h$NIuGRYY>ckD0F2R}PBxdYFPw9!k)iyzaeskfohPq#cZ z%U1tWo%P7FYTc*EU4tFA*khAjw%MniownL*v)v)rZNnY6+;h`ix7~N+owwe5^WC@K ze*+%4;DZxhxZ#H*p19(RGv2u4k3;_V+mTaVx#gE*p1J0mbKbeLr>|qZZnL{BI5s2$CB!LP1g9IVyybE&Z3=!MlI<~=zxxN1) z9LDgTtEQlZD>yC?=lh-9oWKMxXh91Qxq=p8XhSWuZ$mD;p%#{~xGm^{8bX9f5QS(& zY8avjX)(kRn>dQZeE}1%V8sU?5(Z67af+-c1Vc)ZMOI|d4Hz6_TEY;HZFE8to_NJK z!f}eY{b73~bd?d3Fu%o3A{@z(n-!{{1@NKpA@PG>7Gemav_wG*Q%HgmmOw+hAkGd# zEFwgNIEqVRGJs2@hAuF9$sj)QaC0aHD=5K=R6N88o?t~M?%;+&pyCzCJIEgZ5r|tV zVv3q1BQH0i!D=i-h1;0p+Fr4aPFQSwWK*Uf+Ybk#D|>IRZP^yLW&?n3lc62R0IS7Qc=Z)+~F0TSO^_XNs%p(@(#Tm zC`HT|4TeM`9MTlX7DOQoW9)(w4B5ghPVog+2*Vem=+7KpA&g!$Vh*>^1Vg@13SU69 z5w5C6ICi-Z`wf8!OgKVJnJ|QxW+A6pz(Ojs00k#NL8e$>rot{M2VLkQ3`f<49Jp45 zQ6Nf>!23-G07@&&OQMmMJ zUl7I50N_uCID!>{V8|*vyAUIQf)y;}P#_xdg*{**6OM4{78=3DgM7ge^c08@98riZ z6haf2m}N;3feGOjLaPL|+bHMZ8(MNo-Bw(M5+-f+r-8mWD7zR ztUv@zkwvUy7ZmYC#J&Mwt!+V8*Zk*w+1gewK!G7w@IqRG@ZR{&_k^+<0t{o=V!S@B z2o@ylLC#qOXR->%00<(3(IVhU5||oul*56kFUy-@5rP>7h&F5qilBDXn&PrEh0 z3~|B*y^b^m>Q$-9$;O45GGPXiMYP7cf%nJiXh^Az$_bDDFTHP zV&RZ!S%MZqypSsd5-phqz@`Dv>4ShT3vD?_S3IT!Dy!6~qKUBThMp%%VjTY7U?fLJR+jgUEBu0y)Dg{0x9Cu;LV% zxNaCoxm$ru;uVXac)uqtXXb7%5QP|oC#tcIS1g1TsJJjC!Xe>>pU;ArSciH!a>hAw zmAo(?wm=H84xMkP4wiN=i2(owFI;yCUg*(5l%Poc!f<%ZhHHS&4FJY^kFl_Rs$v1K zPKJO|!GYb#9@g<|iu^$n00-NKA(F@ztNJWS05Jfva0RJ8Ei{tNJm9s!9bY#A&tmlDxkX|EU&hn ztbpK`6%K$gJN%-oFv%WX@rZ@wdyYm3!`eR%H#7fIm%6)XSRBs|05kF&04g;89m3Jw zgD4^#jTQ(X!U6Q-51m7EaK3wGXml;;3JX1ah|@*A5K>oRAwv*n)fZd&tJ@kPZ$NN@ zEh+1!#L*aW%So{*@+(Jb0gO1!L4;El0DvEbSl*?D3Gp5H0f6}VkU?Y{Q9aG!l~Y7C zUaN>51P$Op1d;n?UHpL(uaOPCErb-6!XgBMDXG><2*DQs0u}Y%MhG129E8A4nLHgF zcCkVxB-ks6LV2-*!vO#$utFk`pznd)H&78Y1>r<#LN7d&FgSwkMAN)aH{9RpC z5tzI!1g;5LQ7nW4QN znF+*2J>kN=!dM-|9JE;~fC3~0!eJ?4+0YpPI70R%SQS=-FnA-L8Q(Pu#PS`)9_Udn zO5Z^Y!WnsEI|@V1ZAhiDAww|W_vs3=&0!smnp_>k`kCLVSsm8F-_{LSRMFo-m|H1A z1Ub@8|22gbupe45o3kB+0!o|r9b5nSjbGDcfgit;K7{v3f@np>9Iyg2rUedeM8Yiu!#Nzp?Vv!w9z%pdBc#?8mBI{GW7;&A zKuFp`bV7t(m!6e<^Ml?c%)r}&8h!xCFTyDrCideLrg&Q7STK*kGAi)cH z8`!jkNlp}IMg=Rf3SCCtN~Y3L9c0&R-U5XlWw`-7F`N&c-Yb~aOzP7@;AHHb=AXR+ zYo^i}2pkbMW!s3OCUDEZeDqd=@*WunC&oPzg|r}qFtd8UPDzTf1%+CX^SXvUk^!DPyX11hNv=@gr+ z92-RffLl==LmWX8Oip;7)>|%Mc537t9)uBm=UMDQDtJ$XUe_O_0xqr#xM3Bn>E&qt znH{_$*!?9c)+K08jysJc*vRBbtWg~>gf1e&LhL~)aR^V^M#SM0E8HGKy~0oyBX6EW zZT4o{WaSo^T#O0?E3AW8X~tD%B>-q4BCbLqY+a5wO&g2?QjB13Yd>@g(Cy zI3^s*p^VUBcjgs>wgvxUriCx8!|lPTBLILftbR6!JUWcW-Dv&B%$o{&$O z&=nNkMK<6)ZX~sxkjh2@4e?Z3;2Fb)gAZ1rPMS*?03wh{)j_yqCl%2ry5z4e1YWw$ z#DZq4aS~KrAk}O^8fk*S4WTA<0+%)@DzL)Z8R0270#f#9$O3?kQbZk4(IhOwDuIGY z2&E7bAqvv1B$(~JajV)qDOrYtl|6#Volh@VD9|E^PYSgm`;=eX^q2OeZeQo|cC1aNM{ z>tPXB_@_g5Cp;7)zB6A=UJE! z@@NM5K9{}(0qzzVhr%E2LIkZ+gu1l~d#WObenHe)QivLjJblp@DQmwW3q?4>mQm3o zEM8P#*=s_?9h?Ff^&l}xE5hC8RrQ+!Z&Ba^jvM^J0JBOXxEw^#!3C4cl)4;K&WsUE z842^2zOIW>VX#>=Lc?yu#TC>ZU?|gcAdP$)2{MHfgrt5A!SWtV5YUtln}rZe84+`Y z4OWd(*)ML%0qszrm_$Wn1<(`2&F;B@+pbp_%rIJn!5IuH1!s;C^um2+j3yYW>X=V2 z2o(Pq-wqYC@f&x}E_}lr3)>3o3nCb>-PEvAunHc-@gD4(A4Zs+PlfXvaDD$;+Gc-^0%K&pV(=xP#Mba!wmz2t`e6!~O$}k%QQM9wT zWQ{`zO{By#F$2t1gbJ)Ej4kWSH{V3nIEzZ$^EfYvJ{L^dSco?7vEs}#xg2w~Sabi) z1hhrlOg3Y5bvUy)o69pZ$U`&EH3N-Ci!?%8%1L+1EPJ$VoJ3O|g+do}KC3jV95l<= zvrO;FJ6DW6w=~#9G`Q%r%;a=UqjYin^l*FzGQY}ztVh)FhEH3EN8rpHCS&nJX5totTi>Ci$N&OM5l*@ zREU6Ni?#?eyhQa|Qwm?BwT7q(a2&`s+s9lBHKBNQI0yAAa|&8W3O!>5NL)5&Ys#1i zg`$LZ%z!qTbav4AL`V3>n5c@Cl(t<*h*e~^${fed&~%`rOsaT=I!}sGGfe-a#K=u2 zhm@?$Y@bR`fVR~1^H^;5rZ~!JpUa~-w`BA7bR!Ix#P)5ovVfqA%Ru&1(=>L7#%Pm< zUq?q-Pqsnhi-SZps)z?;L(O$;^}I04Qtt**pEqyh$9_kLQ_FRJ`1W_JNmE}(JQqzv zr+0Y&HGmUMv>;7t3wUb8w|(%+g5NiT`}KZ&w|#F*Y?$|ZLx_5BxQ8Ejf{1m64+n$q zvx8F$g!}d-+etZJiHzejJ%a@@yS8jIiJ_>rXs>gY#EF@_I7L^=jgv}Eq;+$2wQ27* zq$u~o=Fdi29%>HK|{9U}yTXAo@@% z^@Ce8s2{aONOxMK3_0_7QH!~pe7TuJN;xYag2^pYQSU<0x{jf?ZQt6zG5w@UwnqdTL|`gr@ddyF;0 z0Q**l^kNToq}TPt%Xy%;xWHrj#J5Mld$m>cyIc?UK8yIhzw}3I%BeGXYXdj8E405D zJ9QxYO3MtKym`D6v$Wg$gXnm$U(Ar3^Skf(kuQD6=z3CLbk2K<(PxU)Pr9c__HVOu zwnu%rPrb%eJ)GaWW2bX^{|U7~Jg!3oNpm_=r+mcMH>y<4Y-Bj9ue`c+2W2CL#q)iD z!};5by3(`#rdteRlgvO9`e;~sVY7H2`&@*fn@xu1N>?`y~^Y}-P3&7-@LC+ zdTwWVmt+0YgZ-~R`$Uw!#>8~$OTDcieseGRXm9)Ee}4bmllh^51#H86!srW_gABC` z%9IQL*6Xs73wyIqIn*on>N`Kt2YtJ*y|Rx!=+C*tE57CP3WoTH$Ty8coA|{)wx?T6 zXF&RTm;9$M#jChKR%`rM=k>=If8Xs{7jC>rk>Ny$8ZUArNV4F^lqE}MB#Bbw$&f1_u6#N3Z27wO-|l6XMp6S;@+*N>D5SvS*#f%!<}4 z+_ggi#06=#F4(yl=K>+xb!}U*TKRT82$*n9#BKi%r)4}5vEId215-xYcWhz0lgAQv ztCnrv(45Wgm23EM>C~%Pw|4y+c5Aw3{T|-AQ=!V(NL%jaJ##i=yKwzt^xaxF#n1_j zA9tQJxYgRsam%hQa&~f%(|<;fsNJP^uH2uOH-8>|`s0p4i=XITeSEC)snShlNuxMKmQ2S4?O!6ToA$tC7h7L3N5@aH?T6pki+wa>kz~cMO5m+ z5luW1#S~Rsk;N8Wd=bVNWt@@58g0B$#1e7bk;fi={1M34bPSTnB8@x}$t0CrlF25W zd=knirJRz=Dy_T{%Ph6rlFKf={1VJC#T@^W%reb96U{W$d{UELe7R*35a)0N6G}2U zgUK*5DP+w){rvODIl}R$Ab++A14CBAS!dC35@8aNaD)Mr(n>9zahreWxdjwo{Q1Y3 z3-<`;8&*K^#1lN1EF>IXE`1f&SV3%rAWfjU1%Q2W z8swjU91#qNEkF^*m|Z3b?hICXF{T$*b_EIuPr`ZSx}Ux%#g}SnHRxGS4Eo{~0KPrf z7i4x>_aJF|5oQ-jirV6pRK8$E7+*v&0wE(nxkZ>)_(bTASGYxFkX8?(SKZWDdF6|P z9(iREV?`eMRh%3uq}gYk0^$y5)-nIcRfFybhoEn2-UFyfJOO2wb%Z%p6i?g$%8hEm z3CHMgek~}BZNhmNfLp@pWxAq|PI~Er+=zzJqu22T;h(}-CmLf&UDTMc2|B}QMj6eT zphC7`^qX)L6_y~Ykvur<5UIG~J>tAk2;zfIFf=$kkW25WG5N$aeP=E@9R9_I? z!{|;7BE1(kj3~tDM+|aCY1dER9DvzPzrC$Q!ZF4mK_@>P{P52NVvtY!UJ3|SPEk9~ zUV?Htb^wg{V-BDenIx0HeaZg>|4F`;=nP0RNFlzqke;Pt3tTJ2Py$$u0Tz%TMnD?l z2oi{JBm*d4U=*TimAis`AspKn3MAICiw~}&8frU*qzcl&2U4#oP8%9QQZX*^-4KUg za>F|Q5e~IAr8xi~Tt<8`uCN6WG7J${ycz@%K(wkS!28}w!eBJ1k!w1Cuo%-=SCA*- zO)ZEB#P0-H5DVf>i(vGg8Ch5mMQjlOPo$m{iSh+!+!2q+GRP}>R}kpkA%}q!WR-vi zfOXK}F+eavC-!9wVN4M%T0ELFdXb4QASfbG>BKr{_o0ZeY8%FIhA53ewvH@fQPH@h zK_V5(QI67-6@(yC#s>dM3v!Pj!7@lK%{WT{=rV30Bqb~%DUvU2V;kQ<<~B@dkcx#0 z0CQLeGzVEtYbt3AnWD!SA7g}MAWazIL`Gxg@QTx24Uj)+$P!@^lZtI4obeP!-+&-V zX9$5V6|06k!*EJzv)QZecUaEkvNAROPx&v~ZCX!Wb%DXv*jivr0A(f9`d z9D&KDxN8?bv+i-_*4pgTSZD^F4;W8rex<%8%fwO|t zA*T>=Ll>DAjb{JGM4$vA=-SvykS`WwX4C`#CE)ng*o?{U05BWgR0~=Fh;}unQ`Aun+g#^%C=AUa)Hf=r5;uegQNO7WL)jjNq85!W_eAquH|Be+!zhaxOeM92}O6QpXd)WQ*5 z08HX&-6GvLj4P733bBm@;p^0H0X^6mL{Z_i~@uHG}2!s6X7FltF(*|J>9lH$~ zq6=-?EIUMV^%MZNJjf)@Ikoy3WDAN~lrI{QVEpcQ9X)2v%zQRtGoQIfXZS<>5@Lio z?16(v=?zlou;!!)VGeeN$Qky)=GA{S8q=B9^rku8X-|I|)X(*ZPFO-}QwwF(s4lgtB~b`Bh(ZXGK*Sk9u?0sg0tl3F zH7JY#2}FcJ6t<@CBnoi`SVN-N!EQt&fG~+cyxItlNQAMs@CaPD`qis|Ny z*TMgG#ITbs1Y}ct+0B0T!K6)XYXbq>u$DEgZH;SPyMfof2DY$;Kx|{1JK0-Uc1+@} zZF=8&uiw_UxMl0_V+VZT&W3iogKcf9x?0}bu6M%m4eou9`@iKrx3Xy^aduC;;vp;e zyty5+P``XheUW)&Xg+hB*Bl7F5JezVIpI6NZo)#?#VP)f!d;|d577w2E6AmDo`1pT zK&RatGK$)veCVOP7@i{9I^ zFTLq;k9yc+f_Aw}9RNeG`_Yq*cL4Z(?-LGu)s2pIt;Y-TUkAM4$zFJ-A71a0=R5z~ z8=v&YWB%!hr!mY)AEZ;K8uhDA{pnTTde*;Q)v#ZE>}fxH+q=H@xc5ludEfi{;QZ#n z2mbK0A`Dav0(QH2#T^c%d?EOP6@S>q7N9TvGu(n)!Z^hsw($k!@1gt7hdv;-VT5iK z{ra~6g7J~>{pC0R70-|U^sB#(>t}!a;eQ4A-7kOgn?L%hA^q0x_>%Aa!a)4ykNW2C z{?;%5+>ig1FDBT}0GST~HAeyK@BXUi0l!cG0AT#e@B9St7Jh{S-OmCgu>Ka%`mm1! zxeo$AFa!Y*{YtQU3J?Y1&-ZqaM{ZB{bPotwZxI6F3~Xfx!$1?Zpb!cH2pa$44~ozT z6d@3h&wh)@|3 z0TEJ67kSYafzb$r@d}C27?DvKnb8@cQ5van9IX))uu&VofE&GW7kmHl7pt)xf$dWfg%KDz3LXFPxCD|Q-BB1Fkr?ICAGz_kz7ZeAu_77L zcaG5?nK2^Su^`{kBCjzUGt$Qp5*+gpB|~i^%%mb*1c{Ub$DpHJ;^PN|J6EP)oF8luy1T7OUUC<^p2o;1tWnls8w!GJXr>_ChPm>>tfC=1CE^Q6$8EO3 zcXr7a+~#NkhbY3JLK`I}IGx4~T~)IvM7H3}gbMo%J8??Md3Lw2$- zTth~m<0ii2Cc~4|7$gXP5=eb8_j=(J0AVf#Gv`V{GvWV|c6y-{itaMkQb~_=EsK;& zmC{L`yH4eFUI9^^j3G*4Z^EEKAz~N8A<61M z6Y8eO3L;aDp%Cc66Nro`LKP9}pc70LR5i5_IMq{6b$bfo4p#MP3<6bEl~q%Nj|LPd zwt_ncBv@l(SYe}BStBv-vpwW-`&D9eCme;m5CL~s255{8g6*eI@WF(ei85TAP)?hz& zUNcr?IaXi!)nw1L5z@6{`D9?Pv0(QVUR#!4?UheFV_6HrX>`;fdSM+Fh%KOkbW&j* zB*9q~B7n-TARb|s#^%8Y0>DlzB7kRV_bS1fR&AhmrkECKx;AQ&CVu$JYMa6hZUGX& zWi)WZE|MeFYy;J>VkQft)HH$NKXh62o&K7NmmiF5EDQ* z5HX<&2eA-xQ*$}jb76N8Mz?gQFcVN$bicZIii zPqz$%cX-3#b)Q!enKuuemlb)}bbogetyc(I7kfcB6VKpyX?Kinw|VsheWRCj!j}aStL=;6{S9%6?xf zD9Q-SZowE{vmmqwvV=f`C)gk=IAIuu5)gufQ%i$Ecp)@cJ>qjPB%?oRt~~8R<}?E^ z^p-S4BR^|Shl2y>^pj_Oc!!CYJ@)?-T!z9~--21K;#Yy#KaaIN;8R-9Qy5YK276)u zz99^_SpNRt8(7f(c0v8vulu-o54;$R$L|}AKm*Nq{j@lZyZDRaulmL~j?eh`>UfRs z*#F*mkLP%c?YNDjPmdW;j?wrF)R>Le6e6;?kpGyAK@gG2_zcYW1}FKEEg295S&>bU zjvLvKF;I+IP+l~dksbMtJsFg(PnAcRl`DBTLc?f^7%zl&XPFoXCRl`{VQCX06S~T0 zeU++I3bta*AT*(C5MmOL*=Ln`nAa4U5JFtm;f)Uh6Ns50s+nq`xto<)J$BS4@YZe{ zmpgibP}{aP=4>Y0$@R>uo!|fVD&X1FCKoj^LZ98Xo|_|{5qO=2n4Fh5Hy9T(uEU_W zLo^mTC#vFrUlemA8Ym??NGbYqCmN$GI-}!uWg@ttf3G+anr_L%WDpub61PVA0-(9V zP}Ny(4{yE*l_xwWPR!;EN`$Xy%$v2AnvMB`uLdEuxu**vrw?MM3nEfrm}*NWnF~Uw zjoPQtXC@G#MVDAvXE>dUc7bUaFTTP)>q9&FGpn0*IzA*=9pfzexi+wxZli;(6`Dja z$ur`!t(P^J=~ga!R%cy3_~`+w#a|7Xmx&yiVv!A?bQc zvfqvsa?Y`#Zm?meu!aBNu-vtgHyd7%<+D>Lwl9yiAA9pq`?OViPIKF}qXxDs+wg*0?ryudqan2|`|yyPvo|Xw z`Wd!Rs2Zwa8@fB47Fw6{f-Ao14ALhYG{K{t+J7ez89H2| ztib|2=z1hL+;3m>t^@Zr9Qsm296V)opqXMPb>qbqTD#S0p8di=D0izaTBCb>_9y`n z+~5@YZQ4q~);j+R6AEDtN}<;l;S7u%5||Ch-JlfuO%a~F+L$fLsoV%8VG+XM6tY|h zrhLdJp~#OM2$Fosn;grdJlBG}$|vE{8`jo&Zm7zuj0jMP+`H18NiM`9Fjf4C8DU2z1oS|hNk`7S7s*aKy9r$lSYH9!J47- z+K83-tvCOqD5SVFaM|6%LaNd_yJ^@vy}GS?csvm#-qix7sv;`x8j9^&tMd~({JO7e z5fSd-3?9J<0%6UrWf1m22r~W)CIJWv0nQ#_3;rMwdRgKr-r~Q25;k7rGd>I`;p0Po z3jm?yBYxs5{^D7l9^`#~W9AT;VgxtKIz9u>#ZK+apvife(J?u=+}(s-QMiK zUg~LH?zg_}7rMp?!e}0Myo**5e1##l;2Wx;*Z}~+3!xMcg~3%S5LlsOl>K5QpYkER zAR7Pw@y9(Tp4##8B)&1f^0)mwUfjj2LxvgGa6fvb%UM42mMU0+Z%tg_*LolpxAkg& zJ5~)j1e&8`;zmVUrTren|5o@dTKPA6{a&HSwxD4M=L~v5{fvPXitGz~VgCT&i-SxU zt{(uP{}l+Q``3>Z_=Nh#pZlr5`JX@f<%RvNAN#c*XS!bqzTf@Tzx=-+{k0z;{s0Km z>lP4UuLc3wf>7X@fx z3`Z~|N0cgA)&#(@P)YzRLGnzPvSG`D0APlbxrZjwn?+YTwaLoo7K=Kc63uxuq!9lg zKuUfkxh-7Dl3;}Z=oL;80I(y0yb2f1moQ)7!qqv;cO<27tV(X%<~Q6c!G!zr#bg+9 z;lN}QD=s++u;6ba86S>3xwGfbXMv0z`BkmR(j-NPB`tcgYQ?V=qmDb8umFlgx{>w z33GpKHqwM6L9z~HBT2}dhaie1qDUE*#362)sVEtVm)YmqZ~k?bR%&n!r`!LHapl+- zk9+|cHu~7(aINt;-I6uF<)n=EU1_CiX=!OCfV3UCPn{2{)W}I}+X{VcYrgaM_dqlIvE27-tOc<=N0>qwwIP+&If`0KzDu;rS z=%Rv#@rt2{D*6he(Kwol5PSCdXP|=?8tJ5)Hu~tPnld`*rL0og>7$_X=_jC-nwlx4 z&UhMYs;`zfS*W*?N@!ra0_!ON$+~JOvXZuX$E>L^YwM`FLW`=a%Qjo-rPgjcZMWCr zT54cIo=KKj)rI9tIEfth1pw8Mga`n>Fvn6aBz+N1y&?q?4!TQJ21om1Ca2-A{mV3nycye9e~DZH=V~iqNyCn$%Sk($)4Tj@^Lk?93Wbz5hpU3 zF&DWXb~)qMoX<3`+%wNWJJ)e*FQW|Ree^Xg-_xpTf(RX{7(vM+gl>UJBSK`-h#Ra3 zp~)g{r1AwMkO0vMB6Fm&1tpH0!HN-E3$ZoWK#X1X7m}ncHPu#Q&5G7sdkwbOWSfn) z+HAWGx7>7deYc@{o85QbQ&)X;)^!^mcI9WMy>{Dg$36Gfp#816;DiI31VS9WNrQ62QJzBM zrZ9={I=%@D2=Bxt7M_qbcnVFNveZGHL1}45GTE2z)SsG-1!gZ)(gv5+_5g${hG7v#*kTpKxCbFzv5G>N;u!b9#X!^{3|tdqBghB@HChpi zT5RJTzDUL~ZqbZX33qN9M6iby}A( zhAE6;V$4WvQG~kW7Y_mTq9@B`sdKZLiL^@9ftpI4_8w=j;$B}6#w`RA z24CDl2*yZ={&E@!0JxzSy8uEmUI9~?Vk8VQ#i{>Jx4=`M0u=}@E$U1MVpF9m#0X9O zX;6nM)uSdgrwU=}D|)I`sJ;{cF`a5nZwl6(j@7AKB`R8tIuMzHCaO!3=^xgy)}-hZ zt8djR0JxghTkL_ab_MG?#40es;x(;%?Wj=j>0Fc@U(Trc+JJR*$ARShOLln)?L^WC~3~2&@5@ktkG8kBrri23-eF3g& z!!g{m=$5y>1;8IFB#gd1mz>7%t#XA++<$sEO+Y;8cSGpI@hY*rT{170#)QHdg;%{w zv{BLisTTGYl!;M0HF`&KkR3f_`?3;G>{ zX3&CR07MujbA~@`STSKJ<7C3%;SpW zbBj*=!5CX$g(&Edj4udT2(JLe9g<;$S9szM#t1_yP;n?916jy*=+%*vya#6>nNLw> z1*CfX;~)>Y$Xix2lbsA@DN~uuR~AK9a(-|my@-mn6Old=(`O=SGv!LDF>5RQ)K$L6uJ$y3` zFhek!f?N+asf14wsw3(`nRhk#Pj-3UmxAf3`J9U`TIlw$DS;0d4SIq&a(J~Lmq z_PX|7d#!!lTVPnLH?id)AFfs^f!i=#*iunqA-AJFcRE!+RP)m9&f3|fZ^^B%kIR^8 zZiZ;U+K8Xocd)lag-HW##E~qughKnF+^>vrlcG8+a%^|y1w>~JTA|m{7hpoK+F{AQ zft7WcaEr@LGd=Rhl__#|Rw{FEXQue7S3cON^fN z9mBqTTOX1C+B!??l)&t@Nd3NMBt-r&oBGEldTGWpcCnK7wqDQZ*8u8vE*Qi73V{v^ z3bHe7y7?>ugOSrK8+$=73}|7>1&xyxPhoTs3m;s1PpA6shH|E!-T7c{@olQ<=TZ4^ z^RA85w~2#vm%3q$kB(P8XFvF0w-x``4tsxlrc3^$b2eYc)Q&vkJb15wc6$O{ZLlnNRQlEY4 zRk#~~kGH$QZNOuzCao~M9G*$PMv8A7s$G1QaMyF4%ohNT*4`p}pS(U*KkC)#xg5A- zVNj-uZ!N!c`R76Gv4oEUyE7H>-QJv^B2W%Rv+XT+)(3bNlKBhVa4rl9u?z`L40%$IaDmZ2{t_A#8Zu%84d@McmKYkK8IZcE zhk*gmeT8CT0RX^}aLE&b0bl?C3<_X?6Z+?Wz&!s09e{$MF^IrFoBhN#^DspU9D2?yZN%2XGQTCPl8)5F<**Jw*{Is1wFW>&e&WQ6l!wdz)JbV)X6C6yhu zVvgnb3q2isYw&^#yNh}Z5ErIhea+(-Yp+o+efhP(>fHWQUB$avk*`Pz#yU8k4wa|f zZ@4A>+SmP9o1gDPsmrq|f1DFFM)QF}m1455f;Rl}c8 zM$I7vohAY#@W4KyY*8&!(b79SJ)@T@KXU@lN~*#|G@d#qi@J%kZ3scqDhVVqOH^n9 zVRbP@x}7in(QS|lA_A%GHyntv7@X?fE(m3G|F{zQ89ty)1F!C)WyTQ?nY#2riB%-g z<5m=*50>8XtktuAULem4-#2-_6Qd(ltFq?iSH{ z0^{XTeM004#W<%`IB&jl4?S)i&Ik|@ABK7rewTmsOYk`F=YCw%iUVMzG^#5e0uZx% zlC5LyzxtN$2)YshcY#6T+~&ryOZLK2IiugD1ZG}mc;AOQJRJETvfm}NDiH;Kr(Ss> zmSUWsvN4dO)D^Pdc|8In^TstU_f~E>f$sRIlF32GSEDrV@u0q&t`Y+;K zX(Mv1f2%j}=wSzP5KAduh)S8lCjgcY^~c!`3J6pdHl+79ZvE^jie zKP%47z@vLN>dWR32@%}9F%XlZ+y2panIx2pu>FaPFlQnzO)vXh$*5u7J?Eta^OO*`u5dEk<`npV{ZVm?0?at+@ z%DGFviiNBuihD(`#K3&u?J3OZ~~K-ilHaI)zMTxcDHJ8X6Zb5lK<-3;6ptd6~BpG^4EUs z?z_kNdgbjwql)7#?IPm=_Cc=(Mkj=B3XO$W%QQXIe$V08-@>1_CxEmXi;uEtP3*Hn z==7KK!$sk&`!T_FGX25S7#d<(+==aqs+o5`hccOs1ybtwXHo2E5A{j8}a zuT=|%^ofT>=iTt=Eq1{9~EVds`#V0r`HBWvO2E%$CDX1Yk57ccM=KA%)p{!#Pb~aB(;A3{j)vy zAu;d+%zu?s8sIj>_!7;3RZceD-tw%D5CnrvD*C)~QgB=A3Rp!^D@k6tCd6PpkRt&w zlAf}N6J>K})(VJ9TU}#eh(ZLhZlMW%rGwBoek9eVIg)MFG4@9)=E$Tqp1&a0 zEHm%IK^3c&7&Q1F$&j^9RT&J%&G(VcYC2_j%heubT7;;&zNSzVZHD94U5J3ulAcAk#fZ8 zayqM%a|RC6U4uTXlJI%W@)Io>EzRL zNBG%Qg_c)e4>rG@8e>|fMC+HJG8$ZPeYsQvcs_Z!Sm-4F07_1J_;g_PgI-Z^r+(y| zSH;p5d`P{%=cg`>L9e5{0wb}}t&Mrx5&RGudpat9oIa0^*M2< zF#!`zQ|otgy2e@3smX&4q*F;|{+Jr6T5a#lQ(T)_H_{jK%%U?E{VYexgg;wtN<{9# zo*x$W3p`?zfs-VV{;sUXtAgt3%3-@?`)c0Vep!0+lyNGJJ9ByU`U z<0nq8C+r|DA|-6}vEltwYCZd!3#K4&n6)SHtMM0-~d#*U`?$eIB*X$!rhujO& z0=SC9sC6dQU{y&Y4>r;q{av`(1)oVMz5$1rM+P8PyrC=-8Akc2m`5CneMa}4r$snb z#L1^--ZJq_PY^W93S0`RDxC7CB5@TN773(gANpdd^cJ?|ikNp~X1p&jw|N%CZ!4u( zfkhZdJc=ozfVe5J5>8DJO{~hI|Ap96Rznd%X5q8Rw^B0x_5Bi_>frnIgewGWn3!V? z+$2FO;ae-t$|K~S2`%_6M5FSjeCZ_XLc5j3>+>j7y}Y7;pf*7(UplU;M-<|whN826 z3d^gPgwhI#BL$UC8G%tnA{a~R4J%#;*kqC7$>m73tBmBOoWj-E3q%Cpagv;a^^eyS zG}l#8q7BI?Xg{3MK@~MkOmBe-0TA#d`qakCkd~suY!b{A%~r%zxC$U@40z69a#OSq zi06}J-UL6e#4U;t!ZS){xSY1g2pw{Vkfit0vGBB!%508Mt~|mdIJ;AU{mwLxWDZA) z!kVumEpm_|v`~y$py!ruBtB(OVE|JLAwfK4MVLBX$W0uF5Z2%v#E6G6$sp{GUuM`N z1r8{!u!zJvm^iWEs}=V4{m9#jBb?I%#Ne0MgoPxaR(9gC;Vhpc9}4fVCBZ^&6w==- z+=T#f^{@q|TebJ6@?)z6+o_U$1^tkIFgXhJYAz}Yi5P-k7Bpj1+p0I^bVTNL_A>C) zu%JWxi47E?GE9Up{zt~Rkt1+4O$DQQ3>0|wM6j)Q8-E-uge%nP46B85h3}bW$c?=TI^dA| zCO~Rwzg?8%x2{4lt%9bQ%1SD`FPdRZEJ`7H5-JAS&as*^RTI?~X`1Y^MXKq~#jA*f z)njyV5f!+(2vgiTfi7}Q zIy{5W_NNe|E|YAdjGn}D?=Iple;e=JfvCR&*5}GOU4J z&#RySQSu08S&3tnzi{SCts|6P(Fhp|MKwW~gBZ?6T>T+}qU5LN=xN7uqOAG*jI8MJnGVWZbWm||R$>*1FTI_(o`fcxc-U+#GT26smDVkFtu1ln z4JEk9v%Se;mplj6uL%F(?k)Ds3oNl-*jV_oKe>)H`X#@RM*B@ zyrD^?i@*B)B&K{}>ev@hGkFw)d@}MW2}>8h7QTY3I~mByUEIQr`PtIZSVz{RWLDhx z`J-J~Q}d?jRY9Y5f*mf&NNiT_kcg{eS}LUr57h} zH-F&G#=LeHYFCnWn&p1};Sb|a&6#xGL))eN>$5rmiiMN{?7+p+HEKzgtq5`}sA}*j zTS1qD9eoH?P32*E1K~RxqsTh|5ap|C3BgD)4D_q6wGZmx6k~!~UrI9~KO&T5qc{xG ze`S1m2^LUwi6rA83Cmq<(OU1laioQq&f9Os3KbRJyEk%9Zod;QIGms)a3!!o>^utc zX2;7mkTa$&*&IxNPTZ&QJ$T^JXYu!_A2j!&`%9tmL(Ny&qihS^%aaSML>T=(#R_?O zh@vG0WTLe~9ymr%ShJRLzjaVrn&Ia<`&r*B;v-vQXnJ`C6&#LxE953Wc7yR^3iolV z(YNSXj&4{8_eUhOu-zH?>D3czUzRYx2`B1UC}0dAgo{3{T#kiyU9I(b9|EJ>LTP#k zB;Sqt(qfEjv}7_-`qZV$_Qz!jnqJ!4MOapy=9Ls9HOL-?!kv7b$-VyF^o!h?hT{SSPk`^E2yc3Yc9t)uAu{JYRqI^f@(=fi~s3XA+*!I-T*}6a2sd0(|U_g!ktDidV*=4V#~D zT#s5Mhkgyhs|d!8QRtn3f9w3Vc*ZBA6!MfiusdwNBw~`RmPV&#edFwHI74!EW%hS^ z6q)0UzsI`Yyw)3$_izIv=wvy;2_vGtoS<*qUPfGn>xeYmSILl!V8z}S@P((SBN7gc z2$d8@0eV6fbMIr!Iy$JQqEo;mRZ5zpo|J-J}RJ*0D#w1HVg?tmk0&T zjXcWZ1n|XCt(btMp$?(~H?NiA$$oG}8)Y+q6K6zOR8CdaN?GSC8a5h|Yedy#7*ga% z88k!bND&gTLNSow`SvW@&PxS9rXGK?)oIh2bZ0_dq%N?aoFGy0;eoir*JGSHE*Nk1 zL-I%Vb&B{0nD+IK)Y54G;n9bva?pXdXH{~@rC^-Ewh8csTL3J$*g#Xg@Z|)aIz^!+ zMVBi*^h1T#%-0+ZEse{*JSl${u^GtAsX;T}>o~dTNRHvuXUL3&;eHPr0F^M&U}sHp zCeK*2<57u`O8zYv@Pb=fOG)8gk0R9132Xl@iNiC;>}L@LUT3C0ZKL;CFL64GVvA1S zdCZI`8u88a6=u~W_eDy^=aBwTF`;x1RO?WCVeV7TcTdjJqcBhg-5NEbY%RVF&9yLD zFVvDpq0k5qvolNTa92YK2263=&w8V{gbEGi>sh=58XPvNEpUsN;^H6XaL4OP(kvuc6?Aw}laXIC z^1kMZlc(j>^Dw{?t+bbp-Jz*GW{%%{9#<0`4ctiHFNm!hlqu^wl zjwWZ^@TGd18;?xSR|bE%F0d)Bu>x;0#FL%0XtxhSaiz1rOPCu;{cdGSZGLB5Gv?BY zhw_L`&XET-94cW*s!)!l3^?k5Um^TLs)G>BGYh({E@BLW=AT@@XC)If4prWRiq0Ye z%CU{2q=S63pOs_!`s#+-V_WROBoVO3dzi6ED06bEr*95Wo^3Re{TRr(C6mKuu7hqxvOdExPXpgiG z3ks=&m6_j1G6fSFWEyEz6yGbL8NrrIQ;K@5ShNp=9Wx_t2s}+alTr97h)~f%6tfX7 zh5N)dC5$9Qom_f}&+3dt7!7bmtEoh@)mrTxkYbtR!L`FroDe?MPnTXGc+5FCH#`)g zw4!saJJNgZCg`9?Y_?5EUrJ$K({Amwu@N63-8#*}#?VGM;A+3e)7b+zcwj%@$0^z~ z&upb&=D=}V#xrUSxc(iRDWaYGJ0^!$hhS5Yv7Heb#Wh+3g#;nD zH2mOmzD5Q*&5wN%QAS=wH~Tt``VwDZ#?)ihDPiyIIdxV@{habQa7g!s)bZ34>?Q?3 zz`;vP(mu_M>E8Z%bV&}eY7M(_`NsJonIaUwkFj#tIP?=Fn>ID*Wv4r`E9l9A_P_%V z)x9^YM;R!=;Dq9r_<=IR4+gU)5s4!(yH?8Na+qBdjsX(Bmje$)VHX)f@uQ0d3 zJuaC;U#EsXeaDOf?xp#{oT6}aQ1GYr>XIYFTd#%yg!n!_JCO@!lr2 zj$-4CfH3?RKOP44Br)vY$4oUz5N*ZL4`%L;c+-5=Hny@n#>Hu5-7BRh6#=;3FtE4yj-~q(}T{BzVK}YT^oew-3n2Yd&1SEB0Wx@%+R7p`z3qa z!gBs46n8yjg~My+nJIH6ErIqZ4MjQ*6#*yW`U=TiuQ1hU5(?`iwbcUq85RQQ+e-XX zhz8SqwZ{W;zeBQH>O~)ev^BWzeF(WJ+CoOz#xlb1EC7dNqWygGltnjE0IEJFGt#6H zuOS5NI#C)@ln;9!mYn}ozz3mm*GlV($I)l|x#dS1EC|D&f4`j%BWB0Zb*~~!41ZccACRT_TJ4-g;T_Z%T{6Bpr)hIPGA3XgT3&aDujozxzRk=o zy*yGdLPcQSOBU%bXbb~PVNm2N%$L{?rUnt+2Lu9X2J;%qdkmsEcp*kHLE<<^;i+81>4f39Md3;A;iTJR+h*VtUOI79ILTJT9*R2g z%s95WH*5FsxN85yRb>unjh(6tM_k$H0pr*7v#*(F^ywooXXL|V04`92nT&K#UxqpD z;avU+6F9<5YCVnIJCz)PKU=2IiGs`VpO)R5e#-TY)+r$O;c4Mx*W#jFovyu4QZh&wgh0?0{6H-q7&P1g($)~h; zBuOBQ>*#1e6oSx-Sx3jRYUGReea?%D=ho>~-MaPue&ThT({<^Cb*XHL$SV@bs$0tW za%p#isMNMqU#JN(d8)C@lN;6j47|Mt4oaJpVFk_6@2VlojWLh|Pil9jx$Fk4}7ED%E>^7o7g^y#dJ7_NLpKhTF~q&f^;&Jl#GlybjvE-lD^|H^*c_{OJev@!>S1 zN%E^AqHoe4=7Y@7?7W$yc0~K!uwVc1`f{}0e8%xO_SEYXfI$A1m;cGJy|8l6b!S(M zf1x|8QoIBm+bjI%j%{vVEQ`tu-6VTG0dP>SU$>_+e=tSBX?tFfD0lejAC9e3*v;4> z;r{BP@d8DOpNEt+FD8pM)7Tc0Yl^4K1fB_`;SiO~R#~!QH8i?x4EUo~^V4L>OXK{c z(qZE5al1YKqQ0;q+4^!dW~{HuMsN98=UamrWcm6}KDO4#ot|O}HB?z-gIjp$V1Y2g zZo38_{lQc7&CyHP8Fw3#oOb5wWm~Y2d2k{mU`}oOil=UWjogi&P*3~O=-ZVj*^Hm| z{4vb($vI5&v5hC6Fb%LH<88FLM_$vl6`%an=Gt2x3Uhq?wMXm4(U-`pg0ybsg!DT~Qn4`P@6N`GLt5(Z$5bWz3QCumzcA7;b-DLk+O^~KRQldYs)o#@(9#?NRWsIkyc zQaV0O)%ySkW^5Rb>qaM`jxeTPr0{X#sMo?*mh~ut59sx1G!@h|<~~!HK6;CnHSZY; z>zAkgSA+uoO@vYvO{4+ zfK)dmX+|P5wp>LdI8AoidbUyuKwvnMXU8&O&iT9(Ixt)42#x$qD;op@Ds5=7FgW%~ zTA2gZg73d+;2vs1Pbs?3Pt$GqyQfg>%Lo*`pDtH=VJph`aJH9VE}aaP>!4qn%-?fG zUU-d|Uinc%kigr|ts5n{Zk+PXLYI<9)cbU`LfW)k`Wc88+U z9$tjt!l0hPo@v5a+kHhX;+LbHfzR-}Gip1}eZpC#3*@H8n!q zm2XAMn|FgoEH8Sd({Z%MTr*mgX#-pYCMVgcLm(?Q9;n(ewYIR0awAj>(otHRWREWPX zI1L~I;lUvMfA~ja8I}_;R1R^(ugQz^drZqmr)-Z;1O#L^%ScyU+~YB5rIHD`pA=B8 zT_;yCnuCsIlVF90BK+jl=^eH=rgHN%tE?B2Cs`4Ir25_c{+jc9EWzh36Vy9gW3|?w zCaZyrYSIfuxI3MOL7BEB^4kcot1 zh5W>U!U@^3Rf-9`)_bJ@`Ddy6a!tpxuQF2Z($RO-ep-@|VAO4|wFgdO6hW*@Y~PL_qLDb0-KLGjp3)gC9s!FjwE90%_yl4^=^Tx*750RyQG<0L8`&JWm z0l3d7P95}S-J1yvhJ>>$85|>FO5bnm9_-9qBF-A4`nsDu+i}C284n1x92X%DCmFu$ zva^ML6mp!Ny7B$^%eSEf(dqBbhoQ|0OTMmf^eo}Y{t@l{jWns{0L!Ek4NHQLYP5kA zwb!7A=xVY~<69W5s`n}5S>hj)LJH%OzLgd#_VtACsO06KR zY%Pdj0vj1=I1(n$e0hbB4juCZ!C!~Wx^O@f(8c&1YD2cT(5`f-SA;o#}F|e3GO`PTG?|F3mm!qb z$9i?17s>G{EeKldy&o|O=b+!~qhgJVy@cG#bwB*H%uwZIcE7V2{Q(F)AsBA?u^Ba| zaH-d4&h+@`brCm^6wA6&;xJAT%CQ{cIp84%Y`P;iB7}GEkhvD0L>OIV>SZNJ0=pR zR<2m<;rzx&1UlJ?Em7PdKfay70D6>wnDbb!p>eabijDptRSvZUw9bfazOi;<#JdQA zv7AsV#)h4dY0fcLyT1mD3?j~FQGA!)n?wFC!W7?rK7`goKP|cV@KY^z&{;SWmvfOz zS!;2bbUmDK__22xIr`O?@83M`1j%+aeM-0QUS>9wRY1^5xId1>LRno>b2HRm801|J zbTg{!5o%W~q?6V`>@N~4;E@p`^bn(+gd!v?GxkTeo2%N*%|t`2H>NC=!W!MdP0WZN zYRh(0VK6$4#aYXBjrtE5t$aE(Tc%=?k65}0<&i6kRsLdsZCU?#0-^2pv!Y>_WO@1 zM+bzODg1OE8!o;u3JW773-pv1c3v)iC4!Tc*e=VCD8mMOy`$rUhz2BB?M6GkMdF zGp)7f+g`dtNBUEUQ5;c#Q!PpSW-*T#aB(@>>m^E~yQOd#!(oV!qKUpP!NCw+Vr*Pl z{CN<+tA}YwxUA;7{2gr0!;!>V^x-I)8GmY+kNv~pxFUJp)`W?q?a`#>>rUq>5$yjW zS1vkYB!H~Jq<_-=q;7u%9lH6Fa~&St+=E*g@2<04Y(JT86Ou}aN?=xw z)5%yQXa(mlfbDsI@s=MtbWp!QgKTNh2nWPXnEUk>`fmCY{zBj1?ME@^*4MJwxw8dW|#N=sCg~!g{?B_Nhct z`#5O~BOjjU%*4RGw=9fmb$z{A55<^@7?p^wZ>`7jkHX%?sm4s0KG!t28ub(N&VQF+ zc#F{p1^i8Q{*Rh22e|}X0yz*qa3;X+!aiRs)XatXU*WF%cj1mU{-1E?$p)`Xb)~Xa znb#+rcRT0d&LEY*`2qVCZZll<)ANl_lGbX0{xKpgqNn z5sV5Tv)myrMmIh>`0OQWicd%neE<0YLKsTS=KBt3G=;lFE=kn)joJBpYK!XFO9`53 zIs~I!D3XcDz0&Nts~9BAtFdM$%qy=XoqD}2HpDip^T%z^eVf>)DKf`Dn(FucGn?Y{ zWyNti8RXtVz7)?KIz$#p=`Xe1seIUpM%tahS5q3@KF(YXml$4j*_xCJf?z!n6a6YuUcQmC@iVJ>o&zv=ZO!bl+rE8&@sRZn> zlS(F9v4TAbUd%Mq)tMs0Z?kd0}1EmNO z)2}g9k(1ma_EAP;(fAN^vR)IVw%fWUzc?w`Nysl#t!ZpPw7z=Zsk|25nV&aJt1J{pn6JVMdI)^_GH7zw=gp>Z-U^ zL1wUwaz4!y>+K>k3_<0n!rE=N`wDL%B>zL65g>35e;Zr=FX|Ca5iPt0F~sfuV{92D z&xkZdx=Kl8G&8neulOJ2IbK&96CQJ2Je1}pxELCdc0oN<8HoTnUx4d05Z2=_na6hl zi(IubvOA)I{nJ(8*fOb>bLJ?6&6}5LvUM*P5>dYT&EW8rLB51<)HUPvvXzcd1tE|X zTCJW_4`FNj@Y&`VZkwS8oh5ODnPLol^g*E{{g5*O*=ryys`84UqilPVjkaY@JMuVj z{bV`Nt;4Zu5EijI{(KlHiR-?|o*dcBTZ}95pwai+6xw+gaefdB|JOkTAl)GV?DvE4 z6UY)3MIBv8n+~@K2CK+ zF^FAvw0|hom&k2%eWvc+#&9O?xEWPr^;Y#gzo@%|jV`JMo_CtkzWd*Ecb)$(BUCW7*@Jx(-d4pQ`o{(9#Gej|m3GP>bm96lBcQmS(%{^>C;%Yq zbT%9;;7|F3?O=uxbY1+%hJvEB)aR_zve}yUR{?N&+AQd#Sgql3K6gjHsvTW2WxI3! zAJ;o&G&b;Vm4mFa;^#HWhRSyXlEhM7Z$SOyd2G1P6}d(pi9sH@V*NoOo6V_mlgE;G zRBAuWMM*$LC9Ry{94iRxx7V%$)6VfX@ zy-1-NVYi}7vc^aXI!fe37llQ0!=lUV!AA2N(Ykyxb%xNczuK}SAZs;7dmlWo0QEfB zeH;g?o=V>^;k)<21Iy8QdBy$nx`}v;R!Z>v*W=2q@j|7~dLE?q;*1(gi`8!#Yd*}? z6H_&?y$dB~yzO__bm3iCTyd5YyMfPJw%N)DVGp!ea+mjc<(_hzfrE-hBRwM~|dZpR$gXG=I7A?b{cF&z$gEY|*jAlYB{9Ur8+uCCVe2W1UFMj^>Ri zX~FFsm#vs3$V=pcl_Yg0T*dW0lvq|nLov#`)l?)HRiu@Bor%N1K}AK7=O|Ih{%4bP z8}jDg!nNZc;7Zz2dI4Aazu~IzA8y29bMLb z0av4rbGTw&z;*BsxGMhv*R((2D)l>D>wdvC{ZF`tT)_3w;z&m%yMey?Ib16);5wEJ zWapp5b@&3V7F*|VrM-Zw@i|=Cf5G+3pK$#{J^ND^`TBokH1Z&Xu>apLQvSN%@4(MQ zVL3YgO6_t(jG<6~G*a*!u7~Cdtk3|26(qM1)HidqogtanDi47)OL&>(UwfX>#IV3JvZc(ZeSmZ2e!U^W-zYCr!q~-Pr6=luo{p%B zHHtx&!DjIl-!8EqYEfAbmyzfFcwvYP-Dk>Hoy6Rw{B*fFvsosQMVzGjoxMA6TLTjC z#=tsoJx2@IU`Y4Vc8g7NwViykM;B5mN|Bc0KMLJ#$l||*PfpK2z=!jHvt7XN@ToTW z4L;ZYf=~2c@R6AiQa$<}g5DDln*+4J5m>NVL@ zs`G4zrVN0BoE9ZMs%ZpfJLkSW9zT1sFKoKJ1DhS$a0&e*r15#=3fpr^E?#59(#EA$5zEe$Wxf6k6PVqW&e7bO4f_|7GYEy#I!{QY^;|L_EE>-pZ_z=WoI$|X%? z{8wxIOJv)gFGBQE8bCTQjQXnnEEeaY5gD!;?lk*6KT<5~7kxZ$jgL05Pyz}-3!D^U zT5^7TpvYGDu|sh3C-g@*h^mVrZ7}zB-_XH&LAyPDUMv`7)A1(R)U)HbZ5F{|@jf(s z_PkhBZ;d;bK9L**dBSwL6^<576Id+joo;j{tAoX&HNegM_HCNBdqXmCgP~UqPUR7$ zM6XEg=0MS?%BHNZUZ4%+)VAd3L)z})-D4@d*Ab&%PxjV&%3>8&P`^`&+mM}q4YlAE z(I+&lpL2d03%}$XywDyG4d72`js_PLCJuC(mU`a{l9iR8;!_4*|vRC(}dtNxM^ zgdjp&A5^v2oAJ&yoGYPxEz04F4jg~R%rP?vbix{yd>z;{OyEgv?D{| zs9e!mig}XN&K~cmE7ukx$f*iPw z4apMCwHQ6uUP{rJt@rcpm&uLOcRBciwL!EqO5G@k?Sr@tvq z<^VCPeeCvmaTNg@LqLBV$^}G%ZVc0Xbq2*&1*F2_o7rMrKdJ5hA8Q zCQ?W4bF9t< z+Jk?MpC|u-9}_ZN@~8QO$pX`Tzgo3({NVWJjz)?9k^{#Js2<7;!Y^c~D(fGQCN|Fn z+9$M4&M&ko&z}+wkeN|@ivCZP*U=#oRQl2O7)pVgc zc@RGj<3ao!be-d8=mJ0EiyZyQ=lH3)z>o0wIexH(&hf)}j-L!0>E$XAKac+dKmXJk z|0U{S{wq=MB6Gny!f2!&8GA2mzCXoPRSG-3!4y8H;FOET_d?X;G3v{q55Evs!7`|} zn)-tKm)yO8L%gN*@Pfzd}RXL0cbK-B`9~#h2Cr0 zk_fA|nr{ujO_q`R}WkNFzw;@FTJ}#vH z6qi@^*LBb1^76O1Oc?(jm&d=wMVsW$xYU-2ys-Qww(2D4%eGu}o=wov?dq_LXFplp z*C;_Y-4Uv>ot9jGUXUpX_%7NHKXQ$W_M;{?_M-hz9ppc6KN>AI?MqDt(ti;08oaG{ z+HpnK*KIDe27Ib*CV(O6+GE)bew+$Ky&K7KV!Ga0f4DP4{dx%Ga~r9^i+tu|`IhhV zA3&5d%X)z**E&bJfz`LuF9+Wa)8Za782vdOiy!uPKEBXwN z<`oYGd?~ANJ3*fy*z^xfr#nlVnMkpLo*$InY#9xp1Anz{;n(v3LI@NUl_-BDn3Ll9 zlc?hJ4Dk&#W3KBqnFmqSY_*ojHCCQu+8|hW7=ofYGD4?7&2WAWfS4|JsJlWp#<;rT zf6MQ|WH{(a^kj;K*VZT5sB{KnI2*l%N>9Jh!EC|Nu&oBGF|PIE189kU$aM{Vx=JdP z`Af*oynkF%!$FU3ILxb3QpT{O(+}ysx_)%2tVUdQE54Ce(Z?pNPV9+WX; z;Vlb!bf(O8EDalM+X2c5@>#Li*)Fw*&yNb0{n;^(NeQJQP81)4133~dc;=u`txH%l zXS_*BCqa%Dsb2|W5p^abM9-WkB52jfh)EUlEY~8j@GYZ>r5=bV{vL+&L{0VYAx!&E z5dQuTsb#|CcL*o^24O1FzacDk0byLCP#ro{6d~u4L?s`b&iX&B9+o)%EG1@jj=5VHbh(w(buhSFfKZtFM6JPuT|4 z?akg+?F^UxGO0k>=2q5SiC-qwT0iY}&Bu#IhV#*Sn89n{=ar-{;>*j;p;j+=lQiw< z6iaS3SlxHuC8oCtMPNi}Igy8o6q0c0HaPb;-g8Tq{3f9(;I~ujE(FUx-ky`Zq4JeF z5r=RL-w#dshyoy*@8!OJJ;`hLrF}Qf!d5k>E?odP8Dlk+wqeHl)(<#?WzY7B9bi6F znO$u57Msvpu()$6Gno*0d$shyjO*3+Gd8+Waq`))6I$^ee13$xTqyQ(z$H#MqCgco zq9IPmq`A1jq~hj^%xuN`Ifu)n$CM%|6(?Cj{ofB z*R@(F_>+$^j|0bLgHc{>bU;~W?Z+o{F;bm`#X_p@Tj*SGZZ$jHk>!#xP<87mDJcn{ zqiwcyEDxF8;wyMkZp|b?-tysgh0eCmE+Ha4@L-U=sJ?cP#_h@XWmj>e604=(k3ve) zu7(Hd3V@ed{t&fUfpo|n>MHC?lo-X!3mbOKG6?TT(&#&3_k^Z}-t#tXw+~0tN>|~> zGo}g6F4nF|rN?g{ti{==64!E`%sYp4x-1a(cpsb$|G~6PV2XYE z#~2qV+8WFT7i@X4q`XWG^s&OtAGoilTb4j^Fz8Ls>W8jXt({e!mjG z&U3arF}5;)n4Ozk^9kg4nH-^XJ2uegSu`DlDEJr@tF7 z{=|9Cma|+St#4_-#y(~aZ0rs8zWxNT9wqod$Se)D&S(pl{dJV;Cd}|8S&UTP|9+zQ z06XAy2@UGp|J>^bg75S%9%O?fsOYZ9zXxjm)H%Tn18zrHdy~Ruvr4i_*gN#Q4Nl

oZB`{W-sc!^dbZvh)kyX2cU>A0RRXyGRh)EoG4`=4vN znHV&kpXfPbZltBvHWJ&gT@2J$a3pjQ}i8fvm@^E}JVM$i;OiwIvUqBIN?ciZ~^vAI5Wp7|@DE zZC!4ZY7Jra!-}+h1EUprl%#GH^-KbzmFSUN7N&a{rh9_6C|}Z){u!awQk+V>shKa1 z(Uz%%{!q=e03+AqC_9KY+%(Z*kD@hK8%-*+Wo6>X! zNO>wsw>-LAN+ilMP;OyWz?hm3jv=WdThX?Pn!9;h%|KN~Fp5ykawSk+^ASeZ0}ONb zjMUFlJ?{)2`iqx&<2_H>%LjH|?1Xpl1)6ufHW$9(qQN$|FLfmOb)#!K{=w(IkjPL; zw+9Xh3?}xGU#GwS0BIdp-$Ri#G|`uCNHi}EEOaHWNtG&HoiOi42O$=e;d zq=5OE?|pu3vtlY{+0*i#7ye#CX*tuS-#)$~zs9X9h+CcJ&ej;NHlVS9*J^w%`2F{1 zE%f28s?c|yfe1yK<_{A%r%<=j0rNrjU`D^khJhLb=04rlOX)u)*1rjvRvx^xs2vyP z-}LzO{p8a z=4a#%Yo#Y@N64^BT;-1XCjP!HGOOIRaNJPc_~bR!+r40hXv#%KHA32LQ(uU)hS^!8 zMC+@;2;`hU^-m^rl_D*jDqQet35_XT>4L%&j)tpJ^;5Y&Tx>mtKd)ky*4B_e`4mpv zNl(#cE=kk4A8GH51`H&FKOFVq@JRhF`KbAW8cl#_noXUW9%gq+0EF=GK445i@ zJnznVbH6yB`*WZ3yUul8UtM#J+ie-hD{u;L0epB~RVgvkTZ~P#ARAF^b0dEzO*$!y*{nT7^ z_}W8rTI;gv#6kH<&5RI3B;6|d+lY<#EN@4jjW|_tbK zQ`KN;1uT<+TYXdKR?g+#?}m~A)0gsYaa3`nUU!XnG+gDYP~v?2C<0V(6y+?~NTfDc z9Y1n>WjWJsXO-@I>9O<2v6-%(f*!%mqC628T$7nS> zAn>D=a;edi_w_7Q_eWb+dZV|r)f~K*E8|OJqwjgWr)D@$4kjnCygLK4t}7OnF)}1E z0t1NSh#dFECbc97oeSx4)3_f)igN=uAHOyw+_N`$AFN}wFqnwuqdC6PV&{PRN&I}) zSUAE@YRe#y!~+{)X39pq?+@N+NG%N)hWa=wFZgKOlsJ;vRtSz&EQ!n-Tgh~fWGqsmGCc7m@b>KM(hBKyKpK=Gji0< zN;C0Y#IuZ7ULTS(4aV2H>Q;C>Y%;||Dq->Cl>+znM&eJ26v9pwQf8t_uyrB(HwFgF zJxdwuZzC7wg6Q4;37cFmsW`tV(|a%1n>3X>8r3_#q1^FJSB;%&r33|9p2L!)_c+oC zU<}d}W_;OPs8&6;TEHf3NVoS-mU0kEQJrUq>@2#SW^XH9gTbtvm_qS3D`3+6|HT)q5>t+>*&oAzN zK5u`gcTX0PF8K68#ltP%6wWt+-gzQ_fLPisv(|Oo<*%YM@vQL+D4{9%I>pL0>srt! zHY0yh979+(nRAUgfE>Ax!XM|~>x_C<=Jv|xKISm$=W2VDaC4fP*<})zIP)C;Ji~uJw(xjW@3cE*)Qq_!^az)Kldjp4fehxeT zwrQ9CpXAifxg_w&Dz|>KVvnU6$Lk!R)w5>7%;?+;uvg-jl@EVjzJe;9<-bwk%N&k_ z#s?QIi=5;WAT%g>kHEZt1DwtDQYF4uC0^DyViOEtJ(0G*f1RO2&RzO8KF@Rq6pn&L zK1GE;Dd4*{6xqcX+qX_UKDurB>YkRimB^I;S@>C%DnD%oFOKtk@IxSVnE=^mTxw;H zsfRC`8Q(sy;>QRWv2p)?-aFwM`5U9E^oP5OV5+m%b0Cm{_hArp3&QLn74x3nJl3pz@q zEaY7ZaZLTYieQ+fKxxnw-n*kFO!PL$(^j?>UbezX{@X@rR_5^GnN+%i8{H?`!}M-M zc+{_a!BVd4j+E=tc`Cd=EotPtwO;p5u1SB=R(-6MSiEK{KAhNfk`d+&j@)C6puq7J zaYZs(1hjJUKI8;uxObBXc;+JiA)fltdiWK;ji$Q`V-pCFIJb%2Jq-TQPj)jxO)Z6t6D5bN0-hNm2Eij zSR#dmRb?zE5!5x|T|1#!TiFx*#Q?$sY8ZS11zo8uRy!0v3@EYk20H;D)_ckq;~;vF zvo1%lX$~aX8*Z5exzY!=z(JgC%74+oj(y-OaLAJYzh+pv`$qY+xnucF6k0Jg*ZRQs)WCHZ3p&2kmQDbpv%qy6RoPsS*YV&YWB5fv zEgAqetB^ohS_gP>id)pxjKTZYs;M;2AY}c8T4<%L3;iyh9i*x*J^-D6 zuh{-5Itd7Ho~+KpK6F`!*c&zSr*K?O59EgAD|ah4!Dn?=34K#%si-cTcq?93j4* z3?63Ue&YOyQX7sYz^UNQrE#qh%$=mI}o#mWe$}zYWFuvWCD5!P) zo_1fDRL%6lqlKYCi%EqYf^+Xh=x<=L}tAqTxJVH((z z?X9)hbz2khF}jU%na0~G@1KURQ`&Nvz)?V4=BFo2|wi8 zE#-He8m72X0q2(nZQyH29S1W@CwlaAKY6Iyn4-Zz^G$JX{;SvtPT4ygBC($opIwzn zBz5L?oY8+@$elK;Tfq}@D!H8H4447*DhPyGW1>XVYPr!V4)X3X#2Ef)gLHf4`tz@L zX0OG?qvf%Gtl+6_)q0jjZ+~6ht$H?+`kza~e+CF}+;fBP{k8nRAL-*YEQ-Oy&+J9o z!1r|_=9A>~+jiV9nv^b@fU3ijs=(~C@ResK&8uMDNP#9zFr^A^i5&jLIpkO>C41c6 zkps7S;YBMN_WW~INcOT_U)^MV6}#~2 z?w?n2LL)@|5t8djV(f^|6G#;ueuG#!k`^nSF)nCo!<@;=m+LyJ9yS`uIr_YEG%5h0z3c>Ow>vojX%q5}J4s@T%Vb;IbUK-lYO zv2ncum_;dKXk1S--t_|v;1S1^ZUo0?F_CRdJ-@`blU!qO!tdeSrV8PBBc|yWoHYFj z-pV)UY#H;imc!GakH{p!-LC zdofW+nB?mpmqS1cRbadfu*F8izf$gpni2dtuxd%>g;(yGMofJTaF@vmpdvgYj_Hl7 z7p?EDX%^Ge0{n;^AV?3Jk_m$r;wBOqz{Rhk1iINL;J11T-A&Unm=SRo+~9811Qu0T z-5*ZtrZJxQ5AaH+2|hP9{4_0TnuWo0UZsx}0sTt2g{4j7zQG%pSz{XzzIWgwPuQf> zXE@Fy%9m3=Il!G2@4A*DlnXvcp@MkZKAcZP1iK}D@Nr|LK}RQ3-=0T!#JP?=f&Zfh zaD+j7ZQL|wrX^;okp-S=O|Gwk5ae_YTQ-6EtY9!A&RY@w+4c36<7`1H{B_hv*gm6f zI-IQHVVFH{XMpHnL)>0w8ep63WaI2NSZH_y4|7~#LqPqnalH;k%yzvIKz#1rfgSsE zyf;AHL@rd&0h6~C;r(pP=rl zTZ)NcxSR-DDqNr$QTvipHUuGk0a4b0pj*fAJ=S-d)b* zx+xx8%J!X`D(oDJ z`ZCMF9}GhB4HtMaJ*E=&F14`0#4vAbUx zZ5cI|Sjc_z5QZ(H^_EAx%jA#qtAZp{XaP(R8v zJD^25seNfa0{3ga;&g-^@HFnXQu!Jq?X1ln9mWZjzjgH38TAQxa@P+K zKK;4!FA!>Gs^U&zC@W~^wDs*Nr1FmPd9ShB_g-~3W@>*iBK|@9e*xM;T(pVt0HL%l zrBX~HtydUK@IC8-ZkhQ;EJXA*6RI?Tgc+4juav)5@!#m4EX+>332Q#B+nX1mF!3(t z6@^)A5a+p=Pho(o-Ph2lDCbvWTOtp@ydkGvM>D#Y1+2~t0wF%8=cfrA)0Bqor-a4< z2J&ov#Ye)^ZY^(Zv+CDmRpEE6V^dydjwob~B!6@9QbO*)v07k+6(5Dx#m~0N9lA1f zhn`sdqOF>$POJLG(J)zLTFz>AgGXV!ZENV3?X@ePk2HqLnCTuoZ?s3Y`>uYC^=Z6v zX}K>lL|xRZTu2ALf$7R(17Yj^HUK27$?ZvA+y6q`$){|#PwbE(rR3Z^+enRKmyno= z*;KtOoh8J*Sdok{s^YzWJNudSdgj+(x1gh$zgL*)dp(5r_u70{q3&vjDt{Z8^I=E9 z_s6o+qI-soz~W~Xdq5O3V@}1v{N-n9`V8_7-)@B&Q?R;et@oMa$6>YCq}D8QGjT(T zZHmx9MAbL#S*r-efIE#dJE!j;ArN|DMxR@ z4*)^W=Fh3JxCI}$uRjneVe#e}AV{KAoP|2)c?GCG$ZR~sh z`!!w558=H+B`2AY?dlkn0YKkcYnbqB|4r%7`sVbt9km=MJRs}$)#@6?1PVv}x!**8 zN?LC*_fSBLFDT!Zx zRCgz=JT$qFpP|qmGhGs{njY0UMVd29-!2QBg#z-k#W}{qMiSI~g|9m$$$YQCzGZE# z&_%tL_lq;*`;z$&9%SfHh0w+C8$S?wLQo4?yHzIkuc6}%qUU}i$MKJ8{rFcsR=-vSLCNi-M(V*BO4j|!hQ`;ss=V8BiXUoaSwE#w|dWJJ-%E4a{4Jn%b_F%0&>!u01B(Apd$N5|obw>m#c zn~jbod_ZSkz9I#PP=ApyZfBoHubDlPnH#qIqGH38vLg1`9v$vWWg{}shJ+wFX;&4* zcf=|G2S2A-TtQB#Krg)Id^2{*v^ahC92|fb(He<_YqUy7aBJu*+tE3)jOtIkkjQKWcE4Dcp zem^Z6@jb2&`d^cKU^y!FfW0B5pyIdH{2^)gqQMV@I@5Dj-b;v9Cj6f1WWRS-XoVHW>uu)PGtADF&-fq0MPEP^LbsL@%V*EfV-B%~SgsWRFODj5V%#UtmG(1fGAsU|@dhNrB1f7edOf+HsyA58d)?a{JH-LeQ(Pd4Xr=m0w9Yf~WMe z_m+*Ot!hfh*t!QE!1vPc10}Gxgx|<6k#wMGNlMSLzv*_8s$Zi-p1PUEa}PWCkftJJ zU{b_*`R2gPUrHK^eloE=bu+uKOhzseB*;<1C-!xEH2ZalHq+O? zmLXFZs?+@pIZAun$lW3=HR$dK1dN)hk ztG}gI#-9PcVZy|4Nj5D!XspKGp7f@!hWt3F73w21xf>jyScGt6^zkbHQCyV(bm@Zr z4*c`u+c*bmi~iegqcYDT%7novWUP_r~1TO&|Z^u?b`x_e*N zn9ua$3>Mw*F0JPO=EgV^k;c7y?5x{k{PB-CyTB#ZUx(QOp9JjFA}rL{S6cc1(Vq2= zFQdDVd^W54I*w34y863L+MP`vJRgkm>{nQfT3*8YTwOr@CWp7stL+U1Fi!bbw!4?M z-X`mN{+-n8EJ} z*+p?=RxR8Pr^}3H0{(R*p0Q>;Bz}+cI*#Arm0Tz(6ZSK;31SMb>)`|)zuOen30ZtG zYQzzf-c7HBxBYm*6O7V2;U$(AG`P;z~{Uh=2H(g7G z$8Uq2iNuf_2aF~cDgbjaX2gpu!Ic8I!5#Id`{@j_T%7Z*ZtL&p2vm@`fMOMsobG>X z+TFXOy7-5sMYiBqd#UTm(7uBdH#zc3cPYUfOj)Khs}eyU3c-ziququsf<|K}356$` zXVx?dLvJnNeMlH0{NBbSe3eMm9~(R5^3Jlq1wOKpY|edsABIyLR)ua;rY36-mL5S(T8aH z8pXw);&?*8-bGA0isgk0@EnQq3seqQ_|Nzh*dCWveFYBa%c?RzvvK`*t(zPVf0_U% zS`*T)0mv>$79&R)?$pXdVBFGdqC1Z47R}1Cjq-}^AQzm6d*PEm_@L zfH+IOHfgpz2O>s8F7AO-Na8;aSyLL#DI=M$!>Ji*R6-%u@Wyj< zb5q;s%uv4S%@gSTH16-Z?9s&|&6Q@R+dNeoV+M|o*sJAIE|Rqmdtouu!cq&?!?a?# zoGc0E(hsA#M=607=6EB+f6K|a4G&}HG6J_C{z9+_SMzGDf$+d9_ipl?N75Z9iSa|y z_U+WrXh;Pswz}fwY@9{FT4s>yn7X4}o{C}$7L3=)4CXVR)-KH?j1aVyM_uKJXJ!4} zM%Bv{ihNVjRqp(?@!Fn?wF%=|DbPP&kO_q$2iZ4=CyAYZ@_Gl==?yh+re9N1kH}2# z&HK2<*`EtsUw{UEFs%`yuD=6s;5A%|Nu{caY_xO1-jratP|_#~8lGr0tD#DJ^mV7^ z=Sk|7Ny$gy)$-hOSWUMkl`_yd~Kc|O?G8S221;tf}X?58}axJ-cqPr0CfVlS`2 z^BBmNADqJK;)b8?LE3F#yWu3DL2B}<8NiK^VVYtFm>kr`unbSiVjn@A5#M8(`|(|O z6DXzx8$9lrT;Ra?78rghahCNZQJi0am6_uulTyyPc_vW%p6zw8UHU-x1K2a)*Rnrb zS>oYBpJdr4tEWm@rzO>n12Ix<3_^f9I6QkhANh8M#(NUtl}y&VUdXQjtckxNSeA9tEqvCo~c-#4*yMD=zMAr=Rp5g0=l>E5Qy%){r6fp2T|`NA>|1( z%0MI7?OKw6OA1SVh3oWSV?G|ATbp%SQz7aa zF`Z}ogctf$)v>uWE6%r> zxR8qyEY4U+l0D;-&pK<_ED0FO348rsT6DfkQxT}=^E|#3WYIAHp9#BeA*r9udC+s^v^y0Vm#ogn@?~tWE?xlUnr31~SLzAT=`=w)_r5}+?Kgmlc z`AffQmwrE4Ivrm6Grjb8ed*uv5*@M(;8|vnS_Wz@gG`sf4$EgDduY@$W8yNbV410I znYnA3g}Tf-v&^=!%>HBf9FzvBVeKlw1aq+rUw9a<quk14%FybC4vCf1{PCp}m1L2dSt4RgfT6Kmu}aZhV=j zf%8^Ff)q}^B;f;8V9aMvr_DOy2{f)d_<_q-6vARPL=B2fJNUd1E}{3E91cj~Bg*ap>EyeI*fM3`Ap#LcXu z)e0|1MuOAFqey6E#1DdvpI_8uNbpRg?PjFap1;}skW4Aa-w9R&nd2)@zhvq~-t5}A zDt(-u7+lW`zISqi>55Q9OJ0&||A>e(sC_zgJOL4Lj{W!mb&@Tr!U| zyTYnxH?^{^e=Xd<&BJq73M36DivGOLYq6nL81}^dAb}DldF_Di1qDi0M9cT>*L?NS zgoBJ6h$6h-5@y3bW$b4v8`?YvqQ4(10OF97zufQk*k zl8->F_10L%*>w;=n|OhKqozK%+!t8Hc!QTg)AVv74wsaGgy1$a)7_!}5q^Si9^ocI zC~ZC{s3aAqqk3HIpet;U}`&lw3Xl3*R1zXPlZ;Tyjr z-@-b~P6IZM!#9tjq7Yp-Z?_u~EX{6PGAeY5u04HAX`!ETU(QgR{Qc(Vt;g)AoyxZ# zUxM&`}!g#Y&AE^N@RKm40U2{#W}>+l7s!S2S@ znHJ1#s%h(rBRArF1Mb&_$ze1o~s4`nfF$o8Q+NC}Mz4R|ec3a)89lE2h6X@wp(O zW&xt-I8^qG0#&rt=Yxu4oOcU^7gnqVF&Ps4?LkZx6dekq$-D4?!@2>n&Onhh$NdVe zBIwhtsa3?~^l8n%cS=jYW;*v%Y%L&QqCX0`6+WPp(jip;J1 zOCrzKQb#gBR~8KR2_is?_?m_p`-15JS3V(+3Rzk?cPYPyOW@--8=rz+>UzqwjkdBm zSM*+@?|0WR>N#KX8^t;QGHiG{?)%?@G;)COUOc_-_;}IFFhC37Z>F!ap6{}#Qr22Y zBMJEXF9`VI-FdbyA)iaA8HZ8p+NMkwVr)VbKz-}$bBd}E9>CSG=aY@M5acNUa=)|T zqi|W^J9pQaN4Ee&x|+2w1>?VlKIfVFn)`=YHpuy7NT|Y3L&!NvT$Z8!)YGVQk(8u` zC3`IGrt~PUv$uTBvN=6k@Vep0(_QVHsarMON91!Z>m`%x91VRCwJc@+Vm7!^0d)FB zfLEZ=NRj#do`k|?$p#nm4Ns8v8@$Tp33dE>Cx9#;o5bYQ0KCDvQYw-4B>?Ni^e&J3 zsE&W=*0e=l^FcyMz1t-Ux9)=Di=PGwGKjOFxlx?C+69?k4asb`$FBXppOreyd41tHqsG4Lyz#GgYjiEIa_Pk`rfrZ_V3r_d@C5D4{*|9|92BQO zc@#6MH-Rn%iP96e&Lxc`3_NnK9Vw5APxK6|ZFpK;X7a-T5MQ4PT9Ypme^Dh5T|j_*?PE7|avb>9^Ii|I zkcHB@D*4{kqQeu@@7Mp>nY#)=z8Z+n)8@Ah+q)v> zC1-zns_>4vxR(~cPS~?mRs>5{Y89~MW%P)UADd~ni0(Ds%E&Uj#5i`g-=VMfiG=E? z7(hRwD!I_BErk44Ulzl1PO{USe)_0;NZ@`uM-)21qR~h2R3e-7x|#EiVvyH$KHXo5 zEZm)(0*N;K^WHnv4nCud7A7M!j{82%EFYv117sVH9M+|HJ|$YmhkX;X!cKuj1qK_d zYO!-HV~1t(oK6rt&mjy}na;i~d(P=G=J#oqkG^fwA?L+7(TliSFJTH>c_T!oM);q=?moI! zTT8FG(5Jsjb_1-7RxX%Wij~$zpGtvZ#tl}NJ||PQz`hSL!JN{X+p`XqHoz=~Z4#=% zqA1--P4cl+ow)kssQnZuUD1x~{uT|6k~_GRa^OSeA`fqVR?F|v-{_}2lXTfr%ctb5 zM^qI_213=#4;%fcHPpP6_BZJ07n^9qZ3hQ&jVjKjEfe*gsf_X*iwCJfMut7_60_TD z)tk02-ROB=?q0$9XDCaN^80;V`8Zcv%oqEPp6TYhnvGsB1LR-#%yji?HsAQG;xpm& zvG<>5Yl7kqp7Z%E^@3J=ZqtsB`t!MoyIP&qir)e_otr=OYISuqeG9(ve17pCU8{Rg zaW^dY`NGD9^F8mIb|XFJVJ+Q|7oiL(x~*X1@r5@i&ZCrT3zbz${ZA`GfqUfE74F+O zR+*6f6r(;Z)t*5@|L9}NS>bmL+-JUgj6Iy=QsouMvag&E?5SC?x`-6x)H>gPOJ@Ym1i0v}| zBC4kCQ`|^i!lN?a>8E=sfsLzzFAI&0RmxM`0DVVr!x8zMe&(4DF?i#DkkKweYH*{M zU~k3XloO5BA&z)FZEk`A--EB8ij68h8#H`$4$!JT1bYgHN--ajuT`wDG{O^=jqrC~ zOStm27!6@|_n7fVVhAr~Jxs678GpcwH$B>}pNz)n56CMFtO_H6JSD?zpV9gQh9{uJ zoqk>Y3PV>R1FivdHv{!j1@*776mm%TB98iZ@B--pI&Z;{fP8bO0v!Zma=pGkf*C=_ky9nFaS3InpnOR+b=8xUg4+XG0~XqJA=RHhIku|HTaCR zV~w}@jdMm_wWzc_k`=;>sOF}! zHHJPR(x4#;gy~+^1pwg-@uJOx=u$Lwn1;NF6cZU5pBfy65Jlf5n98hxtbuTI9J9#K z`9FhNfc|lYD)m2u=cB7WqJe-v@#0W1>MtTZC|(8UI*)gQm*YPEt-uqOFw3O^Jf?iE zmC6wdA{BTc5t0hYSh+hMfdmRTFQTy^K~pTsT>KwDR;?X#y*pmR8bg-BX!C(EN0mw| zl{)2KkDG)Ic8ov%GS-Y10mxJt<_#>_(t%V}AwUIE;a#$fK8_;?LglB4xh~MxSLF-R z;76;5f2vu25aBP%RABw`5mi1r7-cRAKm^fHgv9c0a4EPS{H4^#`~mwrkUj^MqkTx! zp9tVE()Z&Qz2^tq)8Rji7J*LtGA^tV$w3byZmei)tLy)S_yUK>7uh@T%%7 z7i#O8$_#e~hij4S0wl2oanmL@MNcug<#{n&DFe_5Me(VK0m}5b>w7N9{&92sH|TiR zQyIX31@>bvcq$kBun@&Cz&MtWK{QN69=D*nyJFZ``H8I-ZBu35>}hj=*VZ0fGuRNz z`i%Y)?{f>QjUB|r#;eEDrTn!d0WUDxaRX>=W9>iUSDU4-D}4gaRE@`!IrmB$G#Urr z{cN~X3El9$4(mta7VNbKKm(%26%}h!7EZqh?X@HTMm2C&DR)b6jYd#p%Ci0MTD^b5 z0EGd0t{Q|RGDNEmUsIEN5#?uHr!9a*>2Fw-O9M1kY*$>pRu;7Q64YnwRc-KocL%kO zr0?ynq0`E|F&lARb@3wp<=gl~KtDgyT~K!b8sZ+AIB4%#6(9f>!?~g{TZRjZ7)KdX z9~oBxlIy#5Ls){FT@B&{&+Jg27`|rs2WOgok&0S0~+F_8CLpJ1DKMV@<2?h3p*&7JIK}df;44<^^g=PC*AFJPF^|gbR&8db_}#WHw-v*R zf!A+|)aJDg=u&`yahiplY^{SFNY;NO(oLCfNc5_R=~?%*XM_6;1HL^`aJEjadEKyZ zBZ%UUzUw*qVckuDr1}SC$`CKHRqH|Z_mCqkH~BMDCGdNmoExS<>tZ(~DLv4usQ|pQA6N!kU0T7Sx$FQ?yF%Yo_=ndbvM-S1lpD#^N zm2mV@XQFI)%C>vRqZ^odH0A3B5_$xc@Z58=47m9E;pTAiChpJneStwOBT;38J}}%gILY+QkgEnhyZvsiM3K3& z``=*Xr=f>E4Igd&GJ$cNb@;v~q%8LhFHelXj{(IBU(JYxBR86&%mZ!_A8A*bJY_&J zNFlG3cquWVwOxV66XHceGln2J-&x4+;UK>Uc!F}m5{1gdNYcw2pk1JSX~4)|y41(! zfEzus{|R8Fw3Q5Yw(WuOW$g>E)*r%|snJ4;+;ySyO5ZCuLZFk>BfuNXVRP*4jfYPx;OCBpx3XJJfbh8>~kn(TI+liNA9hh_f zA~Mo^H#UAGYDuKq;mdfx=t$G?g!12+mcNV2|2A6w?JCoMw9x-40~lKY=TsPYTNy-E zfM;r>vI^*YE67jan%O}^_u>=L&MTiJWPpsBB@z^jY$4%(hDtRP zgV;#uIv<0~$+xDLmFm$A%r{C@%>A{E8ry9NKwY4e4MqxwfuB>AYM^hRPly5q%3UzD zasx`HaqjVF^im>7qstktkLHbtk7>iggH$>EVID~IS$6`jet!!pp2rZ)E1D?qbpN5G zxQxVr7+l%O251V58#HJM8qMb>#EU6n;eXm{*r=i)HL)8E+3S4BxB>YHAjfk7fiJD> zhbn5#374HGbAy*i}4)v;l^CoR0x$dsa1K4XG z$vC2PG%&Cib3S1}dGmqzMY$o@v%fp@5+smXs{ltMgHRt`U8q#eSO_g^g~oRt=;x~H zmoPM2Fd%FgIE4B+7sB~A)e&oIk0r%lWvq5Q`gUZU7jm4KsYv1`y&HD5QGaYICf}Zs zkJm5)BKQaa%4(kkH3jP=g(y7`Z;x>zIIu0utat{e}%GDQ2!;tAi`2j9O6(9>Q5BV;83S03bgh=zItS;Y`S+b``lMX0cwqy zxpH2Xh-BOxC#N4~?_2Lnpn()g{Cm9e3lX=U#EXYDGOz^I9iSB_)lnJCYtzqJ7|%~= z!@s{_5fRVd*pF8}@K)*avSJVtjOT)Na`AN;iPE9l`>J>_1ONRte|aqopjOjw>}PFc z^;`#+>&Rt!tj%CNh6T!zrMt^vO@0E0-sMfiEkMPn&^A=b4U+=gW%ci(~Ls zrl$O8*ki)Wy&(2z;TW{AF%NFu636zxBx>|5Jx{Lt_Y32(sS1b#$}c<-T!@s&9aiK^ z2)s68sZ7$aZ0Ir#yklLjtUVav0J5K?Gkgsml(>hohQ)hIk@)l4_0Rvf5)CdYc9Oj)2S6m7&Rvr@Dk}%fBf8CEL4@L_Pst0(P8VZ^Q zNt4PBhYRi>6v%5`O3=B&OLe|%jb74GK4*$nK99MA=4|YbGQ7zNm{XcRP@E5skk7gT zI@E=!4~q;5{N^m~xyYz2>4Cx!Dh28)GXw_D!$1ND zPc#<2G5*AdhNG48L&AUhMI`8M@s_3?O(It>qrud^aUxu-Y!Kt}SX z9q6nBfx>I~A2l%gzXVA811qXAD#jQUbQc^ zFk6Rp^F!t0*axdaedl8PMX~aR`f#DMU8ji`I$y;ZU&Yyv3+h+o)DYx^DkkkufdEE+ zIz~79eWLXd+P6gSJjIaCV}#@}`up-&l3><`?TVi0t{%p*QeC2Q&p-onQZ*`=*es8o zU&YF}9a-cvB+P>Y0095kSHtF?hU5Crsyl{HOvzcknyrx-zN%+89<_^*W^TOvC^{sv z(=RI1rcIB3E{@eIr{m6xVAV*2FOrO3CK(rrfwi?_yw#{28#v6~*I{LB?Hq(RlX zCiGQb>{IYn<)Pfw8*=KAa#s4&Yd_E*w1gts5P4w*ue$b^4$(6A@M$qcOIY}VT6QEF zqfP=Z{(Mm8w5EEqR{5g~Oo+Ge?530n$?J}dVhkb)xwbi%#yW|^Ys#2uNS&kr&} zW^}ChWJ=pe6EkIuwMy3v&%?I*A4fj?3W?Z}F zg=#bW2JEdI{mYa|)EQv~$n1OFL1sq0?%_;u3xQ%Z!&GmFT1==P7zJ}Hy+;>hgl?>{ z#!dKV`YxL@OiKO?(e`B*iw7mG_A3s`-{N9t97RiyAe2HyjvX|=(guP%+=H{`#UY$x zsH*3y4+=V_>aYDL(zmC?5>~>%5;yk!>E%R_W9~irX+wA9s-lthj8Q|cW}Wf({BOOZ zA4RJAysOmTWqXF8b4%0 z@jB6M!zw>=3|Q0)4#w{xc^U9+)%5_tinzqo^#nE*ILGSf(-GV%vdw&r$kxH0!;$tY zZD#~#Q`N5|Zy$wTkj(HsL2RW;4+w|X+vhORBBLJ{qVO?-P+zR z$;w8;p=va;Sj=~MK#!H~R{nvXhNNGZ4~TYUS6q4pw6 z{`qC1V2HMQ>-rg`uR5T$*tIOa%_&n#;y9V2)HpMn&@1lA@)Q&6zm%LKo=?%F(ETwf z(tWY_4RYe_8{X$nR8L*>yEVFY>7(2muJ`;&u6~*M0v0Jwb*02Wtu78bBAeRc!I!bN zflnML`46};IVBF?E_R2gV8!adfiO^<>CBu7>aewXb|nK=Qd5m-AH4b{Qj2`CJ@QA> zjvATsfVDFddwA4#fx$@fiP71)_a&GVF#pZP_eO#j8E_PAM7V#$KJ;2WC-CXgQS+@P~cSBZ-*2pETtuu8vW!^zfg^fR1MT z?xICyd1rmQ{0RSM4}g=w-oe^>aw6wM?DNdo0^ueu*@%sBL7V=5ewc}!Gn(>^)Rlqv-6Z%Me^@8#mdt(l>*Um=k}H;-5jCPA&miYNf2xSpC6a!d zr>eU@M`2d-vu0&Yn6a(gcN#~O#k8>=&pF>C!0p}ADI~nK6BovDB_{)hhxhukV&ohL zGqcvb2F3Z!J3qes{^Vk;C(7y&oII zbspp+Q5?X-Xo+3LAtnb(J)#>&&TCSLRTdY$ugd{`6tTvBkFpq~A0|ZxT!JzGkEXMJ zYx4d3@E8NP!C<3PHb&>@5*gjy9nzhG!bf3rN_TfN8YxL>q$NZFK@?CyL{ZT_e1CZU zgZsGd`?!wldfo5Wd5X~3FVSSi3=51u?)Wl>@0mUglxpMwv>}280tZ zK*#%ixi2b3)XhW65aq0poNN~Gu)c~@FTQAau*TRrzch+N1KBmFA%5=zLW_QVMEd#dpC#Cwt) z&;R5lQmn*qVW;QI8?2)=DVy4Xk_0oANmTz*jJGff4^l;%`i2wqvOr9(A^AOUuW zH1hv4JI8fq{U8>Z${HD*J$qD4|rDSZ*j4A-d*9#be)`xlghZjdm>-2eWRl{niM4CNVZ!0p!_}2Qh=$M%t^8-HOhHV+|iBxSc}|^ zXs^=e`vGk)LlO^_)1D8~VswAx?Ujn?d;hg-K|SPnRZ~}ox)%)~El!-7Lzh$wt)iW8 zmXJBI5+@#6q2<2krO|k32yll~*U%9&tQd&#EXc5E9+BG*8@kaGVu?%mLyj~$#@!U+ ziI>#J^~7(A(z7Y7X!<1I0v`2i#Ws`5>8HUBSbHg+dt2|Eew-v`HC`5ATC`6S_$j_F``KnP+g9 zw{R8ZfLQ9h`-|u1oN`|u`OYPDJFikry2N??v)&_mEd(q(AHb#D$ld#*F$+;5d1_8K z|LZWVJz0amc#6BiFeCMNCg17Rwcw5Cq!MEez*V`63 za~xSuk@5+?GTR7@4#}#s!#n>!;LZ-@1jNIis&)tC6$`jWU_9lWY&|?6R}HJCKRqu9 zN`3peI{XlUU45uWxsvD^EXQasH~pBmlLE*#F}hzL{_34kyh6RS{4-IWV|(|7XC^_1 z`M18Y^Axx`xj%E@7Y&9VBkrrOo{(KKxv4kGTw+L2KQ~JM()%R~tspEI+cMuEFrDAyX`@oX&82V1z8-ad#)g1gybhgKvlZ^XU zh;Om}5yW%Q_WM7!l;aiFo=Q4iN1r{_59A?ow-E;9B??FEACmhMG2)3>&xv+%96bvy zNIcL7EYd>+DB!FqoCV6Kt5Tu<+)wv{E8gCvL3u7W1OtB(dOVyXii*pT>I_HX;jhZ2 zSi|lXxza-V2!H3l^E*)(aI8N#5g!6XQ6qI6$B;|{4d9Yr1RS;cKyL_h!7E>mI$EEn}qg_oKgX) zq8w?SC07I9h zy+2A?G?YMkA_uyhc8|M;j6MN$j{=wo4ed;SmY}sttF~t%x7p&@$8R1?&C=`H(uS{IG{kiDBmg+3fI)YvvyX5R5~zt&cM{J)^C-KvPi3 zr;FTW>_D*wlH~wkn{Ld}0W9=m;K75lzV?@N9W0{&@@y>m1oB432pu&78NrfI@2%^l zvifKhZyM5&P;r=vaLu(N2inn|9bBs-Tx{R|*XFjwfLF%uDx@-68lt*5V8IxJR9xnUsN!-MVGRqpZ-~yC5Yh|~9smNG0pLasks9aKK@M;XfO88=u5>~7 z>Vhj&RCDt}(Ah{cER$L8lIxB!lZz3Z<}&xOsDx>dgyn>wb)x|77|$vdV3Pg6Rz33I z81b?W0ZUSRw8`Gg5wfsXI3XUIM_7)KmpzN<>(hXhVZtoNQZ`>Qy#fmV|-% zm1RW;HDPpYO+C7fWcupG0<&Dt}n;%E9! zh8zwLxsQa9yJd=%hnO&7>@=? zukIdr%MXwbl}5L?_X|n;sUET3AKuH7KI;#Cwt9SafB5W6`W|hd`ycv#{^5He>31b5 zK^U#}{h15?`@_$L#?%n+_U9FKLaV=Za2Ssx0{>7R)a9=##`Ls@3=#^~-GGYyjFXgt z$@K!|LIdazzC7`jOaVajGK9E$Lwut=9~wB;XITRC{XK-2?Yz3laB;)4qh0 z_o2z9qo}2MPuBmv#73bkD3Cw@8|Mg=K^xH?Q2YS=hC5L}6%oLFva_IQscTAtM&G}0 zrt+9gH~ydD#MgJV*B=N<%e#hIPUMkh&>AqpM1ZYE*+P$b!*uD{2U8r$w#_+ev1F|y zH)$5U2|w>DKa{r^TUwJ!QU)r|T)34)LI$y9UFGOjELne8N_XTF=G5fL&E!0!N7<$z zoiTgT-g!z80$TW;mycCXV>y@{N!O+HCT_Eb=dk5b!JDC+IE zc;++9kKJn=O|ZA%NI^or|Fj5|F;RHrjXoq5ekBtv&f&{|ie?mP!jchsLKEqMPrpi$ z4O(DS*`Zwy&`j*@8mCC5iWP08zU$33pP)ElcqUhwre0C9TM%V@{j5Qe{>}4}PhsgE z3^@hYS*jb%$K^B@QB>7u?DA2xvilTo9BxxvfW%=x-|i0fZvDs{2E3&+ARh~!fiYjKpzzxS{8L42>B`a z-vrm(#KyTm*4hD`-aeUyB142CjkrIBog%~I3dC96U%(!j)+l|7BmKuIJK^7Kx4}Mp z_tW@DNd6w!s0b3b_XCe4bCx5+0|2Q=vhoo~IkvkUtMfV(z3@n!wzA|1OCO9PPqL;z zL^>up(4<(?lPjXgD@t4f$+j8iR1gwRq#0B9=wgVdK}OY+VrdNCe|r6q5kCsQN9jaf zKT4t2o`&vC%McxmrB7FP6jOIBWxJ?M-07P_J|}QW>yD2+PYtKRJ{zTHkx(?okDC1$ z1}wQ6&Z?{;EJkfr+RI%aj8ieR4BmKEF*wsc*$)7<=qSR(n~aI51bIQmQlYUqfq*)a zK^3Vnj(1)F5E!C4GNJ+F_5#YTO8%_KIh)ZJp@B0tT{A`bSJq|3{_`Qyzp04X<|e|v zU^(&ckr9gO@G2%75P*H0aq(5yFwvlNLq;T*2p&DuxSB)=u`Tnkm*(M4G zgZnp=r{qUe&4_Dkcb2JSq@IIS!srACRe5c|N#)=$`moQoOrJI>_QH0FBG*^9)*Bof zj*uG-6%*Q$4^wS-t5{bOvlunc1UdI1{lw41W1H%MCcUzz$Sh^a|a=-)NBPFDK683nt?e{2`kdn}Cq z5}7lYkgTag#U77Eb=n-zCLK@&JH7FDVvbPc`hgWO`gZ|9Mna=%_dry;i5NTP@j{Y3Fh%Nt<1^PzhKrU-T|CS~C(aQIrmH8Pntp`T4*VI!3XfD+# zTB9~ZwKv@C%{khf8i32G!vJEWok*aOV;CSUkSOp&&TSCTgO|;j0Y_qLEQl(>4l7Nn zOylBC5)cjz6xO8CnefZtNEs9AqD-(1GBVx>NvD$>?zJob+gVzu8|F*atW zC-$JhfB3|Vn7?|df6UZRw1rxzaJ&#&7ghn8Oh%xz2mQAm8z<)SrqRk?R8B%BIjt%U z4o@VwU6yPMHq7di3Ï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 OfL^J=q9+&tkp3UK$`}d& literal 582092 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¬_xWEhxl|}!Upn;>^x;!2 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 z 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

iG~W+*h}^ck=h?nbid_X$`Une%){T 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%0DdL@Sz@05tPJeU#k0I0fAaz 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%0AJ=4+r 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 JQKpp@ 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 B~J;ZAph z=akwtr-CP)W#VQpbl!tHK{b3~(+((RfAB+(3u%x91<@Y8@7aZ>KvIEO#tL7Q7MVa9Wds#1N7csD3 z(()RLu#Y?Ko-%+&K}EUo;$KKzQ8STMH3Ln9&7Cmu{uX!_u=D!{4A_K)=*Z0E;U=tN z^>HV^N>lYAw>x=mg7j?`o$v5M$F=S;r56N6$vQ=nuIL1fGJ=lXnC|}mLES0PJH!uhg`S zy14T8ce+M_oSXyD?zUyvNZRDmIonUEjN?z~NmMe;68-HB$oR zHAYlm`CYoPMP6MwE>=jB!B1LwCqY%NXXRBxbr%(CkvNjT*(t{!8Qb0#qPYh1 zu9>{y!GvFa#8#u#C9p467qrywUh|mm|B^oYUtI8=38xp&F4pJ&NjR-7=!&GKIlEZ@ zM|t2Fpf8b;QK56Nu6W=cAG@R*V7#!K%x(C$=fQ0_lZrbo>Th{qygYd0`5X}tor{gE z|9c%{6ZInHMq7y+x@ov#gFCGSShG|UF!t;z1@Fd2NrwnvXVqsC&3Gb$X{BLuuvo_g zApnV|OjBPwyI7^^{9)*A;Mpu#&}0`ifJzF`$(l4-s10b4>b;B;Ytu8ehD5txz7BFm z;rU}xq$M1jBd#E(lhds;MBwD$ofZL^z8=Hdr?dp1pVrFPI$LtZQdT$zMnOheTbZt) z_(=fRkeAiT#hPpdV7`MQN4Y?ZO;G}{ekv;$@MbR&Xe-s!sh@*xesJZ2OYD?OD7kdp z+U#ugjzoG>?9=IG-lL-CW$|6Es{IEO#pge&^13Y2y9p$Sa|t~Jh4X}BL#d-P*0BN% z`0Zkt2KyvH&BlCyH5`4q85L=P^>nPf?>(96MOT|Ck`u0`I8keuYKhDeyYwNmz9{)u zkr($;+oEnUvT>@(%wR6v+7qWktOZQtiLjczy7xw07;|btHB`H<1GPH<%4|9*(#sWv zAmgDh^y*hC@UIN5h?C^Q$d@O~iVbZ8TGFfB${e+2q4y(7P$599)>nC(K~Nr#+!-HB-r%vXQaVq} z?^S;SN7*r*ej`^UnNk2T26she$3(Yin-TE5zz@AtG)zjJ4u$jwo8CTo#l2S!QlEBv zpIVOs^&<0>vNNC}9BP7?go>PZg-3@5+u6;nMXQ zId)o!QWGHbBpibAl086{`~d9}2!6XN2dG#&FKt0*RxoXX zBXP~HV&Q{WJG%5nD)Im{Paq1;<;g_vBI(2jDWnlxqSOnyb=x@Gw18@jNOgQsDVlb6)xf9%ZrNrN`nm5mSv0uS8dJ`<>Jc5lRH+s-wnohqDDF4P{TXh9fW8oQ0v?uJx6C@lJ-7K1 zjciO;X1LM#nS07k6>Vhc{@T3y_5{7#l*ER?g@+sH((9cbWstTvQ%z5qD z-#Q7dSLE6E3V5id&3ZCz8SUl_*sByg5Y~}|%sTV#+fYN_BV`J?T*q?c1eKX_Zd9`G z44*t!Y_*RkigXtRrKz$g;$p7Jb$H&C$KsK`Uqv0&YiXtqU#A->l1JiG@q)&sX9M3%ig%PMyXbs$A6oTuXY)$SgGrSsKlX!-_c zVqb90cvt(p)yxQdN@wajBlBYU1>tB>kq?3vR7zywO&+;Zh}(tH?Q(t0@`aJJcz4o7 zPMpjr=5vD+jkoV)+SPhBu|CPLiDhzcTt`MjJGkyKmHdEPj6#~(`qZb(vU;;+9n&cN zH)a(1thU&U{)w+kKKI!DXEP3=9`r7F7}ZZS=gp`%S`No43gEnkPNHRz!)$~pw^gdB z5SG>#$jYkslD)F8JI1*)p1WM~8M$Td^2G82{+G}bqd#InAhG$Msy$#_nUB-ZTnO!W3 z+i_=^d#}S=gECtepd)&e`+cCw%r>kJ{zlgjI|FdbBf7u(%U(ex>h`S)M(QL7fy^urEW%YxPH4 z{|=)4pKo;i$DZN;F242O7^^QB1^yfU#++@M{ar)-uL_vG7yns9p|le$IXBFsSNz~X_cq^N<&D(tGxN6F$JWGre7K;(vdf-;{V?~>_U1`*h#%eYX66|Z61A;)wH61F zo{fj+rvYH7M{Fk*t3FSG+w8eiTWMY~Sq7)X4RRW5dTf@oefPH3ec@gYXLl-zom#hp zwgqE_e*DUPc&gHr#5@h83R0o9kRD1<0>&GgImDEP>6Sfa&S)qReqYC|Fot2spT#F+ zDM|V*S=`1*Jh6n>F4#4eT6v(v&WE>Ew1K?*BJ*?zqSNWNMVH*&Kf4>`kertA-$Xts zX??~91crehD0*#egi?vAf7W`%T(vhWxu92&%gz*P^Yo@m>vq)rO}Ymq5jvt@u*NG~ zaILstyWY26a*&-XB*p6%qX2Kesje$0eq}-aTSn&9#=jp1h_-qgneye$7gXsev{WC= zUwhj>EaH1_a2S(JkTb9hP+lX5R@0p-z!&o=pij%b)<1(6YhFp6CEIG{^0847-Ehfb z$s6Ut)t+mE{3)JA@D2#@jX@bi$EN01C7@udTc)GE&M(=Ypyj)03cJ+C6qgGM z;e6XDv%FmuebDrMtApl{rslA3k*JL!5w%USYSbFFdyf{MXV)`UP@!6bC$8ucOoViPPBZ*r{-Uw7$zsC^9 z0Y~{7fRsc*$j9$7r1PeBO(0hmdmx0}SKLgAVkM2(EES-vQG@DO5W0n$CsA-}aGSHB z0KV6ZV2rW~fL3n=7L0QekYYw_*b`z^F;j_k(yJWOm5HeOWC6xA9SYth*kiJZwz8oq zg_K2B;j{OI+`yxlllwR>=8bz#dbI@M=7Vab-x%Svg)*`FM#;5qvFGeSh%3FXxK-Au zfejP%37v2|0_e&W9)f7eFR;!P&=tc&l0uyqmWD?*dwnv>9H*mb^|4;Nma-;#XaPBQ z3`neq&u^0nJ_QG?nSlx$fe5<3eiZ{O^JLW!+HWP!=7=T9I2|b!I9V#dO438n7mM%F z(CV9BN4fI|`Me1Ob5iZ;q!BV+6hU6h5c`m(4O)CudkOD4;s}S`@LtaWbMajTHp4+1 zO&b45U5>$G2N38|r+gz@8>r&LCuaI>lyQ*kgo%P&B>F)}u*2O4ecvYJG~yq`vEpQt{IV?JXU1VbKf|KVyefyIq~}I>+^YtY|ol zoC@p2pFzlV_+zYp3AW(tH#aN3YznfH!$ITOzO_wlk*h=dRrATI(lC?2hh)Ry51rbH z4ZH6?grPoU|(?GSEL&GJ#)!+PtYb>thTj0>!gwZU6!{Ha-T`X zekk4hp`flzm7fe~mj1%4;6&qU`KUhXsTeTmVFapg(S8ymMI3N?>6%Oz=H_a1yXdsC ziv-Qep`!tupzp-M{ri7!!J+E~Hyc#8={3<3!hdRRel>0^8u?B0ZF&@Wy$>h^pMaTd zc42ZlGbSJTIF(vXXGF2VB<{vV+I3l?Fg*5feLu97q(x@UV6+Xd&ja1K07`kIzT_LK zep8>pveM~MX2hK3L%vD1*hVdju1FC;Az3pNN_p;4XB?{k7F(brAfhiiF4*MH+V+J} z5>-g!pL?05@Vy|Daz+jQxGS{A068{nd^5n+Pm`+siDMRfVt2THEAuFR?iCO1`{0k% zcj%xrjA91NZ!9NM-#9mYhG^5cJ+nxA{)9HztN&(*?-+_vHJf5Pt}6w+^8J)GP8g)C zJsSSuZR4QAy`*Dfbqz~YGHmvlv+OmRMW@Rfc5PWPula2X=BVgPqx;z&7LJW|>mPB& zJst2V&{fDL)UC8i8;%D6Oe8%4XT5y>lBO~APg06Vkf{xfrZvYala$WkTE{>dZin=~ zFC>1zMAiWJE1*P0+t);eez=Ok&s&a#P|Uy_-uD)*Bq%fLmW@^ucewzY^vl)vm)>EV zJ~Fy$OT(!6g#WCC@WEqo&x6QWs7RL=&p%w`#eyBDqaY`n!0d zRKj`e$!rBXtoPmOdrTCag}ZK&chzXxU{i4H^MO(RJp+U5!wVQ&!}!yhMbTqJHRGI)@*JLuYuBiy85${{PA#wh2I$<%owU*ZE>caD0FR0F{1m68 zi&i2o1JY!Y6j&N3?d$6a!x)9SetwO|*9^3*ZUo+r=@&WzDg}4@f_5FAXVS({(KHrB z9JL6a#Dc$OUI|7z70KzgwnUx}6?ngnq1%RwY^zgkz_UF>7)5x$;e>EymgWOS7yJ#s z?S<6I_=Gg@)tO41D}pL9(+229a&HB2G+H)%cQf}>+9gYR&tRTsv1+-4l?veA+W~1U z+#lBh3J=cpt_zx86?IQ%oe3mQx=OXUh;&*;BZ8uT#rV?&2#%iq5CEgCCbiW}zsnj0 zgCjoO^Mgl8<6mPbuy7(*?d4kUM(Qqaj?$Nw52aDVt?)WI2B(G zMYKBzmE2_WSV`OtPb^oko%E-9#sX)ES1%7m|IVV;!Q$R=+?CUUBj!?D*VQ;4+;s1` zp|~4YM8!A8p{GNH8+t}i75R#IO0;(SG*E7*DbWH?f8E@0PDu!2j&_SxJ@o5WNyoQw z3^pcO`1w1eX^Ic{Z|p{gY+-)48hkUiG?q0Roy4HD%|k(K0Pwl|PX0InZH(-uvsv23i^3R7s&i*Uf}7?DyTWXPI`gIP8lVH*ab2i$prBE6!nlIMGB{ir z08x+&=VxKDFUmMM6nLSl=TMZ{*qH%g%5Jhw?^b>2S9t6BRgO+2xO6IQm-6lTGXcI& z^!4_Qi8_c_uTu}~QV|GpTOQtdcI)OyH#^u)n&&qumU0zkS9^*2$DJFo z-iE$3GWZBdKOt~eu#ycV*%c2Y7(ZkszVl2mpS#zgW1C#!S7aWk6SI@C@aAGN$^3r2oY(QM{ONcZV(HBimx7d1_g>Xvg?Tp3)`)4@ zC?(SZ^7!zeas5J3 zm-}^*3rPcy-OzmO5N>hVcy_X6;c2LqNRSM=|NQzCh9?Ad@4*GepV6pdbPG(*KfL5c zgR~kfY1%Bl->SGgr&5oUgeghdsbB|s86?R??$AhHhD41h24?Nvx021g0Wo#g_5{Db z!`E&n#KHEA3UvYvCJCK8_{mi{YHc~oe+nWzNw*8LjPPj8=M;FH=WkxM&s765la{%- zTSggYzOnjKgr0!YyRQUG)jy=NaG!v^gqzn0-uwzPSNV2J$6^>g%l#8QY6hq-_>I83fMf9bV3dy_L zmxJaZ&L2cv1c`U3q9n)Nk4_tJ3DTMcd{eDJYn~vD7sk(<9_T-f0ss1*)f23?X$d)U zA!wKC+O`Y$Y&}rwc1}^1UB2IB0c4|5EVL@d5XR!h#-lq!X_PRxq-SLWne`ILT&7o@ z(@@%6pB%>1@g)|y9^chW)J>#E49DHQGUhBKeSsX3dmwd#naSsa_%E4*)>81Pk*4{1;GDah?t37Ue+^-~cv(31IS zuBOT64Zua?H|FC6{a(!P0vf?g~Xa@Fp_bI|-LjW4U1IK(D8R37$tlM&y-5u^vW zJGO}8XZN9F5*=jmy5_b!n8fry!iB4?vZ)G3ySm>53LLtgYY0C5lB>8v-N8m;87vi# z`@8VF|?Qp9BPvvhH+#g)lt`8>LVXpDs19y^K_--?4n&T|WtA;kmI-O~s{ib~up@sRL z*u_Iea2tu0h$D0H(&Q}Brf$(IWCgFeC)je`Pg=SsZCvhNR%sjE0ePi|)em>f96V2YSQiyGU`3Q6?rMr%wor z)57|Erl*^W?i=Q13Q0^)T?cxfjp8&W@eY%^cP0sWlLj4=MoW_>$CIYKQ|1~|mJU;w z?o8R_P1$u!*)L69Ii7Ojop#Zfc5|5axHIjUH|^aqeQjy_#__Z-?~K33OrXO|@ST~^ zyqWNhncGVqH_^&tOO z&dXm9mw!Dv{Z+vKyGZkQiR16Gh~MS;XXxth>gC@xr@w3Y|I};#X>|P49Py_$|4;kN zKhKx{yg2>S$$!+XdDQE8)E{v)n13|<^61s_(VNqwQU2p`&ErYO2A77sAET4QiJ^99ex~F-%?|6C;aeA14`upYS(emkk zj=`iKaE6rQ zzcE&g2r6E?eb0Yktad-Vr=K|dM+|Pc|6dsEol`14`@?@QR=r2|zy85kWBD9@2Y&pE zu|9J66Z~cAAB^=VbZ_(ZUySuQ{NVG_UySwS_U|8`m;b?7PmYgIsb$VER-sxfm=XUM zV|A<5qUQgLv5J(`;%LwP#aNX$YPA_P|6;6qLUnkSi+?dzYqvTb_P-b_=hc$BzZk2m z9&gA--CvAVj)0C8s{f0z%IRaW-2P&$QE~=ik4x$eB%b!l8A`SM_ZXb)fKY>x{29h- ztT^M=aE7r)$(yKdmz-g&Uwh>*YW&=2xTtvwQ83k_#x$C0GwLXun(45+H=613M=O}? zi0N3(mhI>++I zsJO(RJ&|xpJlC({nykFl>UvL;O4Th@Pq@wP{zY9?_Y7-~Huo&Y7*&t#t7UB-xi|Y& zujYkpwO!4Rpi=WJj1_M8EWW3!=2e>I(eCv)KSs^F;&EB~sdv@Wel?#bEnDqAPhaZh z0BX72P=!?eCKOO3ujJ)|<{5@sAZRiZdyTXc^GB14!PALU|Mo=vCSY55Wry^Q?MU+_ zBViHS_Tk2D>Fv%wdG>F9Z@>?a0s!Zf?e|ZVlsh!vT5O*Soc<|z{Nva( zi}&S}&&#(#i=Pwkg#7XRdFRDKWY)!ywe?TOhlfP#cO9#_H{XW7pEJB0e(<2>LdSN4 z-o@}QZ>vuJe6MBCfBt!d|Lv{)KH7*oyMrO8&%Uq!G`aKpna}CTmz5dEXTScuO*sa{ z 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

%o7k+lFyZ2O8YSOVZVTsbQo9S75&T8vL{!A zA`D9;?_Yn<^VT2xU@_3SzE62RVNU(a&mE-K17FU;h4Ij`Qxk`BoC6aY^@`kdziv^qHL#8J}$o zGHQ~`0p?#Nie_X<%qGDbK6=gb<%;UiL-N;#3a><2zaR+8-)b6rT`8a_DQ{}tzYqcC zvWCwX*WyGmpCr700$dQkC;$F&W$gCUJt>aza`^T`g+wQ6>s`#{{|R614t6aoISulO-9TmFh?>owdywWuJKVC4SJ`A=O@ zI~eer(G!28Jo}>WUHOj`NKpMsAy>>}DHs?^QzoEYW&r%D1U^t^ha$*Z*W?Y7&<_Ls zv8;0%W)hQ?-AIM=+v;dsd-o6ql739(%}^Jp#7sJ&b5j5+HlUBz+B1=eS;1m%BcyKQ zFzAnNEw+)4Y7gd2n-*6Ovrd^<(Kd8iiUi2-N8&aW}uxsY!*;MU+#w zvl6W&DL~EVov11i)Dtid+NkA7R;i2?Xk3QjG$)S*=FRaMm3UPhFE~BEt-WfO$&*bv z6-1!$Dt!w+@#h3w)JLCKUTU(OIoBeY6OWQwpu7yRh$=VL=xT{AGATL>gKU`|n=yG_ zr9$pxSeR#!IMQ%xdkm^Ba_1$M^)domBVcO@-Xa#58Ed&)C#V@5uWAlQgL=KS2kw;F z^UCOWlII`{w7NmR3L~!zlVS~86D=eW06r-I;Uc1(5YNVY(rI*ep1f?#fVojbF4_P8Z`gOKhO@$Tnxy)eQTN_c708_8fyuh`9%q>HgqVFEFtU7%}F#`h=N~I#qKz^x4rK$$))3C3o_(QQwU9qNcJMR}wf3HO0{)RCx$i_t7V8XFS zg^!w)Zyqv1-Pn{K%U5`jj7S(hyOmtx0n}ex#>DB%c*63nD6MJ_dm@_|Klvb_2-32F zky!>k){Xqt4!&QhqRtsppygM(|5n!wW@Vb^ZC3&Ml+PAN%c& z^6os5mes|`c2l6-3yQJ371swOkb(UPtKg0R-&j{F5gA=~hh^eyO%rc+$jQG2aVQA& z?&0K%c@!imNpfM>X5aU!wxFpo-=I@kOI=i3wjQa5A2mZ9eFjG~JDfUj&$5*|5*c(V ze_j)MPpVGoV!cDPCBDnIM&1C$n%9CHmpBUwLiD-h0cn-B` z32VV(L{5jd(y>Oxvzhz7h$G^)hIg|`0wjR=R*M|NG;D%iyGXyPocZ1WX24e?8EwyB z#3N}-7#k+LEM1OZ5cXeSq7tf4C5JL-8(>e8M&fZ;JEhaLqB1D{T#W@s3LcP+@4P%zR5f@!)|G&Z zlEiptYbb-R@!6{A$Uv4+_J;YH3%L+#OSGqqj`1rKcff$OAqm_1{8JqETz>74&Q^tW zMlU#|lTgz!_+AK{KRf^tY%rvOc|k;|Ezc#xOHgH*=a;6kYcEBY7lOBVI&Rv3F;)5y zjeE@|nE(xiadHp5I{e-h#jcWSznU+*XOEVEf7;;4qzk7Prf&P-Q@=P|ukT;>9!$?* z+m33~J<($IdEp%%MNQ9>6hj%i(Eu8Sv|w{7|)G>e$_z0CD+9E%McY@1*@v-5R@W zv(&=d?6|5`c9yG?r|Ju;EA^>N96@y?wzDB;01@DTZ{Ky!yux}G0vT2YQxI~kq ozbEz|_BQ;#5B(pfz<>Mj{^Qi~cklE6M1dXv06_g;@0HO%0j{xS^8f$< diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 2e5c8a63a..a58bccccb 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -30,7 +30,7 @@ _{about}_ ## 30 Second Demo -The following shows using rtx to install node, python, and jq into a project using a `.tool-versions` file. +The following shows using rtx to install [nodejs](https://nodejs.org) and [jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. [![demo](./docs/demo.gif)](./docs/demo.gif) From 8f82794af83d02a9e5339d0a726d3e4ba30c7308 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 10:08:48 -0600 Subject: [PATCH 0175/1891] docs: demo text --- README.md | 11 +++++++++-- src/cli/render_help.rs | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 870dfd995..c4a7d0818 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,15 @@ _Polyglot runtime manager (asdf rust clone)_ ## 30 Second Demo -The following shows using rtx to install [nodejs](https://nodejs.org) and [jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. +The following shows using rtx to install [nodejs](https://nodejs.org) and +[jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. +[hyperfine](https://github.com/sharkdp/hyperfine) is then used to show the performance using +rtx vs asdf. (See [Performance](#performance)). [![demo](./docs/demo.gif)](./docs/demo.gif) +Note that calling `which node` gives us a real path to the binary, not a shim. + ## Features - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. @@ -1285,7 +1290,9 @@ and the runtime itself. e.g.: when you call `node` it will call an asdf shim fil which then calls `asdf exec`, which then calls the correct version of node. These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead -updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. +updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo gif at the top of this README +that `rtx` isn't actually used when calling `node -v` for this reason. The performance is +identical to running node without using rtx. I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index a58bccccb..f3d1170e6 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -30,10 +30,15 @@ _{about}_ ## 30 Second Demo -The following shows using rtx to install [nodejs](https://nodejs.org) and [jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. +The following shows using rtx to install [nodejs](https://nodejs.org) and +[jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. +[hyperfine](https://github.com/sharkdp/hyperfine) is then used to show the performance using +rtx vs asdf. (See [Performance](#performance)). [![demo](./docs/demo.gif)](./docs/demo.gif) +Note that calling `which node` gives us a real path to the binary, not a shim. + ## Features - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. @@ -583,7 +588,9 @@ and the runtime itself. e.g.: when you call `node` it will call an asdf shim fil which then calls `asdf exec`, which then calls the correct version of node. These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead -updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. +updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo gif at the top of this README +that `rtx` isn't actually used when calling `node -v` for this reason. The performance is +identical to running node without using rtx. I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written From 367fc6445b83dad21d8b72d45412674113eb831b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 10:10:08 -0600 Subject: [PATCH 0176/1891] docs: demo text --- README.md | 5 ++--- src/cli/render_help.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c4a7d0818..78cd81ff6 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,12 @@ _Polyglot runtime manager (asdf rust clone)_ The following shows using rtx to install [nodejs](https://nodejs.org) and [jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. -[hyperfine](https://github.com/sharkdp/hyperfine) is then used to show the performance using +[hyperfine](https://github.com/sharkdp/hyperfine) is used to show the performance using rtx vs asdf. (See [Performance](#performance)). +Note that calling `which node` gives us a real path to the binary, not a shim. [![demo](./docs/demo.gif)](./docs/demo.gif) -Note that calling `which node` gives us a real path to the binary, not a shim. - ## Features - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f3d1170e6..26c75c93c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -32,13 +32,12 @@ _{about}_ The following shows using rtx to install [nodejs](https://nodejs.org) and [jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. -[hyperfine](https://github.com/sharkdp/hyperfine) is then used to show the performance using +[hyperfine](https://github.com/sharkdp/hyperfine) is used to show the performance using rtx vs asdf. (See [Performance](#performance)). +Note that calling `which node` gives us a real path to the binary, not a shim. [![demo](./docs/demo.gif)](./docs/demo.gif) -Note that calling `which node` gives us a real path to the binary, not a shim. - ## Features - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. From 2394fe52f9aa120dab3e177f8effa8adab8e5ba4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 10:39:56 -0600 Subject: [PATCH 0177/1891] refactor: remove duplication with rtv listing --- src/cli/asdf.rs | 9 +++++---- src/runtimes/mod.rs | 13 ------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 447f7d3b0..16610f350 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -5,7 +5,7 @@ use crate::cli::command::Command; use crate::cli::Cli; use crate::config::Config; use crate::output::Output; -use crate::runtimes::RuntimeVersion; +use crate::toolset::ToolsetBuilder; /// [internal] simulates asdf for plugins that call "asdf" internally #[derive(Debug, clap::Args)] @@ -23,7 +23,7 @@ impl Command for Asdf { match args.get(1).map(|s| s.as_str()) { Some("reshim") => Ok(()), - Some("list") => list_versions(out, &args), + Some("list") => list_versions(&config, out, &args), Some("install") => { if args.len() == 4 { let version = args.pop().unwrap(); @@ -36,8 +36,9 @@ impl Command for Asdf { } } -fn list_versions(out: &mut Output, args: &Vec) -> Result<()> { - let mut versions = RuntimeVersion::list()?; +fn list_versions(config: &Config, out: &mut Output, args: &Vec) -> Result<()> { + let ts = ToolsetBuilder::new().build(config); + let mut versions = ts.list_installed_versions()?; let plugin = match args.len() { 3 => Some(&args[2]), _ => None, diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index e5a4b669f..d2da005fc 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -10,7 +10,6 @@ use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; use indicatif::ProgressStyle; use once_cell::sync::Lazy; -use versions::Versioning; use runtime_conf::RuntimeConf; @@ -59,18 +58,6 @@ impl RuntimeVersion { } } - pub fn list() -> Result> { - let mut versions = vec![]; - for plugin in Plugin::list()? { - let plugin = Arc::new(plugin); - for version in file::dir_subdirs(&dirs::INSTALLS.join(&plugin.name))? { - versions.push(Self::new(plugin.clone(), &version)); - } - } - versions.sort_by_cached_key(|rtv| Versioning::new(rtv.version.as_str())); - Ok(versions) - } - pub fn install( &self, install_type: InstallType, From 0679c758ece43b1b131fb930519d8e5afb480560 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:28:45 -0600 Subject: [PATCH 0178/1891] chore: use zlib instead of gzip (#77) the purpose of this is to consolidate the compression to be consistent throughout the codebase --- README.md | 4 ++-- src/cli/render_help.rs | 4 ++-- src/env_diff.rs | 8 ++++---- src/hook_env.rs | 8 ++++---- src/plugins/cache.rs | 8 ++++---- src/plugins/mod.rs | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 78cd81ff6..fde540de3 100644 --- a/README.md +++ b/README.md @@ -1428,14 +1428,14 @@ to be updating, this is a good place to start. ### Plugin Cache -Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack.gz`. It stores +Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack`. It stores the list of versions available for that plugin (`rtx ls-remote `) and the legacy filenames (see below). It is updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is gzipped messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/.local/share/rtx/plugins/nodejs/.rtxcache.msgpack.gz | gunzip | msgpack-cli decode +cat ~/.local/share/rtx/plugins/nodejs/.rtxcache.msgpack.gz | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` ### Runtime Cache diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 26c75c93c..d5184390c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -726,14 +726,14 @@ to be updating, this is a good place to start. ### Plugin Cache -Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack.gz`. It stores +Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack`. It stores the list of versions available for that plugin (`rtx ls-remote `) and the legacy filenames (see below). It is updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is gzipped messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/.local/share/rtx/plugins/nodejs/.rtxcache.msgpack.gz | gunzip | msgpack-cli decode +cat ~/.local/share/rtx/plugins/nodejs/.rtxcache.msgpack.gz | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` ### Runtime Cache diff --git a/src/env_diff.rs b/src/env_diff.rs index 2c5aa763a..34daf4902 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -5,8 +5,8 @@ use std::path::{Path, PathBuf}; use base64::prelude::*; use color_eyre::eyre::Result; -use flate2::write::GzDecoder; -use flate2::write::GzEncoder; +use flate2::write::ZlibDecoder; +use flate2::write::ZlibEncoder; use flate2::Compression; use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; @@ -112,7 +112,7 @@ impl EnvDiff { pub fn deserialize(raw: &str) -> Result { let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); + let mut decoder = ZlibDecoder::new(writer); let bytes = BASE64_STANDARD_NO_PAD.decode(raw)?; decoder.write_all(&bytes[..])?; writer = decoder.finish()?; @@ -120,7 +120,7 @@ impl EnvDiff { } pub fn serialize(&self) -> Result { - let mut gz = GzEncoder::new(Vec::new(), Compression::fast()); + let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); gz.write_all(&rmp_serde::to_vec_named(self)?)?; Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish()?)) } diff --git a/src/hook_env.rs b/src/hook_env.rs index a6c373d6b..64fdc796e 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -5,8 +5,8 @@ use std::time::SystemTime; use base64::prelude::*; use color_eyre::eyre::Result; -use flate2::write::GzDecoder; -use flate2::write::GzEncoder; +use flate2::write::ZlibDecoder; +use flate2::write::ZlibEncoder; use flate2::Compression; use crate::config::Config; @@ -80,14 +80,14 @@ fn have_config_files_been_modified( pub type HookEnvWatches = HashMap; pub fn serialize_watches(watches: &HookEnvWatches) -> Result { - let mut gz = GzEncoder::new(Vec::new(), Compression::fast()); + let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); gz.write_all(&rmp_serde::to_vec_named(watches)?)?; Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish()?)) } pub fn deserialize_watches(raw: String) -> Result { let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); + let mut decoder = ZlibDecoder::new(writer); let bytes = BASE64_STANDARD_NO_PAD.decode(raw)?; decoder.write_all(&bytes[..])?; writer = decoder.finish()?; diff --git a/src/plugins/cache.rs b/src/plugins/cache.rs index d5de60bda..ad5b122a8 100644 --- a/src/plugins/cache.rs +++ b/src/plugins/cache.rs @@ -1,5 +1,5 @@ -use flate2::read::GzDecoder; -use flate2::write::GzEncoder; +use flate2::read::ZlibDecoder; +use flate2::write::ZlibEncoder; use flate2::Compression; use serde_derive::{Deserialize, Serialize}; use std::fs::File; @@ -16,7 +16,7 @@ pub struct PluginCache { impl PluginCache { pub fn parse(path: &Path) -> color_eyre::Result { trace!("reading plugin cache from {}", path.to_string_lossy()); - let mut gz = GzDecoder::new(File::open(path)?); + let mut gz = ZlibDecoder::new(File::open(path)?); let mut bytes = Vec::new(); gz.read_to_end(&mut bytes)?; Ok(rmp_serde::from_slice(&bytes)?) @@ -24,7 +24,7 @@ impl PluginCache { pub fn write(&self, path: &Path) -> color_eyre::Result<()> { trace!("writing plugin cache to {}", path.to_string_lossy()); - let mut gz = GzEncoder::new(File::create(path)?, Compression::fast()); + let mut gz = ZlibEncoder::new(File::create(path)?, Compression::fast()); gz.write_all(&rmp_serde::to_vec_named(self)?[..])?; Ok(()) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index f2de4a1e8..80898ff58 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -55,7 +55,7 @@ impl Plugin { let plugin_path = dirs::PLUGINS.join(name); Self { name: name.into(), - cache_path: plugin_path.join(".rtxcache.msgpack.gz"), + cache_path: plugin_path.join(".rtxcache.msgpack"), script_man: ScriptManager::new(plugin_path.clone()), plugin_path, downloads_path: dirs::DOWNLOADS.join(name), From c0399112b9282f70f6949b2109a4ac78dd75a667 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:18:38 -0600 Subject: [PATCH 0179/1891] chore: pull aur repo before modifying --- scripts/release-aur.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 831b0cf50..673a2dee5 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -9,6 +9,7 @@ SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz" | if [ ! -d aur ]; then git clone ssh://aur@aur.archlinux.org/rtx.git aur fi +git -C aur pull cat >aur/PKGBUILD < From ece42e5643f574852f5a068ea1d599174b49b7fb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:29:42 -0600 Subject: [PATCH 0180/1891] chore: use apt-get to install direnv the install script failed fairly often (possibly due to github api rate limit) --- .github/workflows/rtx.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index d11287792..0a0987209 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -45,11 +45,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 - name: Install direnv - uses: nick-fields/retry@v2 - with: - timeout_minutes: 10 - max_attempts: 3 - command: curl -sfL https://direnv.net/install.sh | bash + run: sudo apt-get update; sudo apt-get install direnv - name: Install just uses: taiki-e/install-action@just - name: Run tests with coverage From 4e032f36af2f4f05414986c1fbaf8e01f6e0f166 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:46:13 -0600 Subject: [PATCH 0181/1891] feat: added `rtx cache clear` Fixes #78 --- README.md | 12 ++++ completions/_rtx | 124 ++++++++++++++++++++++++++++++++++ completions/rtx.bash | 150 ++++++++++++++++++++++++++++++++++++++++- completions/rtx.fish | 63 ++++++++++------- src/cli/cache/clear.rs | 33 +++++++++ src/cli/cache/mod.rs | 58 ++++++++++++++++ src/cli/mod.rs | 3 + src/env.rs | 14 ++++ 8 files changed, 431 insertions(+), 26 deletions(-) create mode 100644 src/cli/cache/clear.rs create mode 100644 src/cli/cache/mod.rs diff --git a/README.md b/README.md index fde540de3..f0f4688f6 100644 --- a/README.md +++ b/README.md @@ -588,6 +588,18 @@ Examples: $ rtx aliases nodejs lts/hydrogen 18.0.0 +``` +### `rtx cache clear` + +``` +Deletes all cache files in rtx + +Usage: clear + +Options: + -h, --help + Print help + ``` ### `rtx complete` diff --git a/completions/_rtx b/completions/_rtx index 75cde431e..e0ac62781 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -123,6 +123,64 @@ _arguments "${_arguments_options[@]}" \ '*::args -- all arguments:' \ && ret=0 ;; +(cache) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +":: :_rtx__cache_commands" \ +"*::: :->cache" \ +&& ret=0 + + case $state in + (cache) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-cache-command-$line[1]:" + case $line[1] in + (clear) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__cache__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-cache-help-command-$line[1]:" + case $line[1] in + (clear) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; (complete) _arguments "${_arguments_options[@]}" \ '-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ @@ -728,6 +786,26 @@ esac _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(cache) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__help__cache_commands" \ +"*::: :->cache" \ +&& ret=0 + + case $state in + (cache) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-help-cache-command-$line[1]:" + case $line[1] in + (clear) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; (complete) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -912,6 +990,7 @@ _rtx_commands() { 'alias:Manage aliases' \ 'a:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ +'cache:Manage the rtx cache' \ 'complete:generate shell completions' \ 'current:Shows currently active, and installed runtime versions' \ 'deactivate:disable rtx for current shell session' \ @@ -1001,6 +1080,37 @@ _rtx__help__asdf_commands() { local commands; commands=() _describe -t commands 'rtx help asdf commands' commands "$@" } +(( $+functions[_rtx__cache_commands] )) || +_rtx__cache_commands() { + local commands; commands=( +'clear:Deletes all cache files in rtx' \ +'c:Deletes all cache files in rtx' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx cache commands' commands "$@" +} +(( $+functions[_rtx__help__cache_commands] )) || +_rtx__help__cache_commands() { + local commands; commands=( +'clear:Deletes all cache files in rtx' \ + ) + _describe -t commands 'rtx help cache commands' commands "$@" +} +(( $+functions[_rtx__cache__clear_commands] )) || +_rtx__cache__clear_commands() { + local commands; commands=() + _describe -t commands 'rtx cache clear commands' commands "$@" +} +(( $+functions[_rtx__cache__help__clear_commands] )) || +_rtx__cache__help__clear_commands() { + local commands; commands=() + _describe -t commands 'rtx cache help clear commands' commands "$@" +} +(( $+functions[_rtx__help__cache__clear_commands] )) || +_rtx__help__cache__clear_commands() { + local commands; commands=() + _describe -t commands 'rtx help cache clear commands' commands "$@" +} (( $+functions[_rtx__complete_commands] )) || _rtx__complete_commands() { local commands; commands=() @@ -1154,6 +1264,19 @@ _rtx__alias__help__help_commands() { local commands; commands=() _describe -t commands 'rtx alias help help commands' commands "$@" } +(( $+functions[_rtx__cache__help_commands] )) || +_rtx__cache__help_commands() { + local commands; commands=( +'clear:Deletes all cache files in rtx' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx cache help commands' commands "$@" +} +(( $+functions[_rtx__cache__help__help_commands] )) || +_rtx__cache__help__help_commands() { + local commands; commands=() + _describe -t commands 'rtx cache help help commands' commands "$@" +} (( $+functions[_rtx__direnv__help_commands] )) || _rtx__direnv__help_commands() { local commands; commands=( @@ -1177,6 +1300,7 @@ _rtx__help_commands() { 'activate:Enables rtx to automatically modify runtimes when changing directory' \ 'alias:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ +'cache:Manage the rtx cache' \ 'complete:generate shell completions' \ 'current:Shows currently active, and installed runtime versions' \ 'deactivate:disable rtx for current shell session' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 3018d7ecb..c3d66a908 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -24,6 +24,9 @@ _rtx() { rtx,asdf) cmd="rtx__asdf" ;; + rtx,cache) + cmd="rtx__cache" + ;; rtx,complete) cmd="rtx__complete" ;; @@ -126,6 +129,21 @@ _rtx() { rtx__alias__help,ls) cmd="rtx__alias__help__ls" ;; + rtx__cache,c) + cmd="rtx__cache__clear" + ;; + rtx__cache,clear) + cmd="rtx__cache__clear" + ;; + rtx__cache,help) + cmd="rtx__cache__help" + ;; + rtx__cache__help,clear) + cmd="rtx__cache__help__clear" + ;; + rtx__cache__help,help) + cmd="rtx__cache__help__help" + ;; rtx__direnv,activate) cmd="rtx__direnv__activate" ;; @@ -159,6 +177,9 @@ _rtx() { rtx__help,asdf) cmd="rtx__help__asdf" ;; + rtx__help,cache) + cmd="rtx__help__cache" + ;; rtx__help,complete) cmd="rtx__help__complete" ;; @@ -225,6 +246,9 @@ _rtx() { rtx__help__alias,ls) cmd="rtx__help__alias__ls" ;; + rtx__help__cache,clear) + cmd="rtx__help__cache__clear" + ;; rtx__help__direnv,activate) cmd="rtx__help__direnv__activate" ;; @@ -367,7 +391,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -562,6 +586,100 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__cache) + opts="-j -v -h --log-level --jobs --verbose --help clear help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__clear) + opts="-j -v -h --log-level --jobs --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__help) + opts="clear help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__help__clear) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__complete) opts="-s -j -v -h --shell --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -955,7 +1073,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1024,6 +1142,34 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__cache) + opts="clear" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__cache__clear) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__complete) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 7cc60ae0a..0203c9afa 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -6,6 +6,7 @@ complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_use_subcommand" -f -a "cache" -d 'Manage the rtx cache' complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'generate shell completions' complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows currently active, and installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'disable rtx for current shell session' @@ -55,6 +56,18 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the l complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r @@ -243,33 +256,35 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs new file mode 100644 index 000000000..5073c8e4d --- /dev/null +++ b/src/cli/cache/clear.rs @@ -0,0 +1,33 @@ +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::env; +use crate::output::Output; + +/// Deletes all cache files in rtx +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, visible_alias = "c", alias = "clean")] +pub struct CacheClear {} + +impl Command for CacheClear { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let cache_dir = env::RTX_CACHE_DIR.to_path_buf(); + if cache_dir.exists() { + debug!("clearing cache from {}", cache_dir.display()); + std::fs::remove_dir_all(cache_dir)?; + } + rtxstatusln!(out, "cache cleared"); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::assert_cli; + + #[test] + fn test_cache_clear() { + assert_cli!("cache", "clear"); + } +} diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs new file mode 100644 index 000000000..9fe9d547d --- /dev/null +++ b/src/cli/cache/mod.rs @@ -0,0 +1,58 @@ +use clap::Subcommand; +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::env; +use crate::output::Output; + +mod clear; + +/// Manage the rtx cache +/// +/// Run `rtx cache` with no args to view the current cache directory. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct Cache { + #[clap(subcommand)] + command: Option, +} + +#[derive(Debug, Subcommand)] +enum Commands { + Clear(clear::CacheClear), +} + +impl Commands { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + match self { + Self::Clear(cmd) => cmd.run(config, out), + } + } +} + +impl Command for Cache { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + match self.command { + Some(cmd) => cmd.run(config, out), + None => { + // just show the cache dir + rtxprintln!(out, "{}", env::RTX_CACHE_DIR.display()); + Ok(()) + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::assert_cli; + use crate::env; + use pretty_assertions::assert_str_eq; + + #[test] + fn test_cache() { + let stdout = assert_cli!("cache"); + assert_str_eq!(stdout.trim(), env::RTX_CACHE_DIR.display().to_string()); + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index cbdaf507c..2e51b3e20 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -14,6 +14,7 @@ mod activate; mod alias; pub mod args; mod asdf; +mod cache; pub mod command; mod complete; mod current; @@ -50,6 +51,7 @@ pub enum Commands { Activate(activate::Activate), Alias(alias::Alias), Asdf(asdf::Asdf), + Cache(cache::Cache), Complete(complete::Complete), Current(current::Current), Deactivate(deactivate::Deactivate), @@ -80,6 +82,7 @@ impl Commands { Self::Activate(cmd) => cmd.run(config, out), Self::Alias(cmd) => cmd.run(config, out), Self::Asdf(cmd) => cmd.run(config, out), + Self::Cache(cmd) => cmd.run(config, out), Self::Complete(cmd) => cmd.run(config, out), Self::Current(cmd) => cmd.run(config, out), Self::Deactivate(cmd) => cmd.run(config, out), diff --git a/src/env.rs b/src/env.rs index 6cdbcf9c1..ff23a1932 100644 --- a/src/env.rs +++ b/src/env.rs @@ -20,6 +20,13 @@ lazy_static! { } else { current_dir().unwrap_or_else(|_| PathBuf::new()) }; + pub static ref XDG_CACHE_HOME: PathBuf = if cfg!(test) { + HOME.join("cache") + } else { + var_os("XDG_CACHE_HOME") + .map(PathBuf::from) + .unwrap_or_else(|| HOME.join(".cache")) + }; pub static ref XDG_DATA_HOME: PathBuf = if cfg!(test) { HOME.join("data") } else { @@ -34,6 +41,13 @@ lazy_static! { .map(PathBuf::from) .unwrap_or_else(|| HOME.join(".config")) }; + pub static ref RTX_CACHE_DIR: PathBuf = if cfg!(test) { + XDG_CACHE_HOME.clone() + } else { + var_os("RTX_CACHE_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| XDG_CACHE_HOME.join("rtx")) + }; pub static ref RTX_CONFIG_DIR: PathBuf = if cfg!(test) { XDG_CONFIG_HOME.clone() } else { From 2b7336579d7295d3a180ff2c35ddb2284d5c8f35 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:47:24 -0600 Subject: [PATCH 0182/1891] chore: fix direnv install in coverage job --- .github/workflows/rtx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 0a0987209..4d7e47a8a 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -45,7 +45,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 - name: Install direnv - run: sudo apt-get update; sudo apt-get install direnv + run: apt-get update; apt-get install direnv - name: Install just uses: taiki-e/install-action@just - name: Run tests with coverage From 9e85c63b569be505f81e21a17153d95ae145e282 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:33:08 -0600 Subject: [PATCH 0183/1891] granular plugin cache (#149) --- e2e/.gitignore | 1 + src/cache.rs | 122 +++++++++++++++++++++ src/cli/latest.rs | 2 +- src/cli/mod.rs | 8 +- src/cli/plugins/install.rs | 2 +- src/cli/plugins/update.rs | 1 + src/config/mod.rs | 44 +++++--- src/dirs.rs | 3 +- src/file.rs | 17 --- src/main.rs | 1 + src/plugins/cache.rs | 32 ------ src/plugins/mod.rs | 181 ++++++++++++------------------- src/toolset/mod.rs | 2 +- src/toolset/tool_version.rs | 40 ++++--- src/toolset/tool_version_list.rs | 4 +- test/.gitignore | 1 + 16 files changed, 258 insertions(+), 203 deletions(-) create mode 100644 src/cache.rs delete mode 100644 src/plugins/cache.rs diff --git a/e2e/.gitignore b/e2e/.gitignore index 1ed92b5eb..bf6b6fd37 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,2 +1,3 @@ .local .rtx +.cache diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 000000000..2e55442c6 --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,122 @@ +use std::cmp::min; +use std::fs; +use std::fs::File; +use std::io::{Read, Write}; +use std::path::PathBuf; +use std::time::Duration; + +use color_eyre::eyre::Result; +use flate2::read::ZlibDecoder; +use flate2::write::ZlibEncoder; +use flate2::Compression; +use once_cell::sync::{Lazy, OnceCell}; +use serde::de::DeserializeOwned; +use serde::Serialize; + +#[derive(Debug, Clone)] +pub struct CacheManager +where + T: Clone + Serialize + DeserializeOwned, +{ + cache_file_path: PathBuf, + fresh_duration: Duration, + fresh_files: Vec, + cache: Box>, +} + +impl CacheManager +where + T: Clone + Serialize + DeserializeOwned, +{ + pub fn new(cache_file_path: PathBuf) -> Self { + Self { + cache_file_path, + cache: Box::new(OnceCell::new()), + fresh_files: Vec::new(), + fresh_duration: *FRESH_DURATION_YEAR, + } + } + + pub fn with_fresh_duration(mut self, duration: Duration) -> Self { + self.fresh_duration = duration; + self + } + + pub fn with_fresh_file(mut self, path: PathBuf) -> Self { + self.fresh_files.push(path); + self + } + + pub fn get(&self, fetch: F) -> Result<&T> + where + F: FnOnce() -> Result, + { + let val = self.cache.get_or_try_init(|| { + let path = &self.cache_file_path; + if self.is_fresh() { + match self.parse() { + Ok(val) => return Ok::<_, color_eyre::Report>(val), + Err(err) => { + warn!("failed to parse cache file: {} {}", path.display(), err); + } + } + } + let val = (fetch)()?; + if let Err(err) = self.write(val.clone()) { + warn!("failed to write cache file: {} {}", path.display(), err); + } + Ok(val) + })?; + Ok(val) + } + + fn parse(&self) -> Result { + let path = &self.cache_file_path; + trace!("reading cache {}", path.display()); + let mut zlib = ZlibDecoder::new(File::open(path)?); + let mut bytes = Vec::new(); + zlib.read_to_end(&mut bytes)?; + Ok(rmp_serde::from_slice(&bytes)?) + } + + pub fn write(&self, val: T) -> Result<()> { + let path = &self.cache_file_path; + trace!("writing cache {}", path.display()); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let mut zlib = ZlibEncoder::new(File::create(path)?, Compression::fast()); + zlib.write_all(&rmp_serde::to_vec_named(&val)?[..])?; + + Ok(()) + } + + fn is_fresh(&self) -> bool { + if !self.cache_file_path.exists() { + return false; + } + let fresh_duration = self.freshest_duration(); + if let Ok(metadata) = self.cache_file_path.metadata() { + if let Ok(modified) = metadata.modified() { + return modified.elapsed().unwrap_or_default() < fresh_duration; + } + } + true + } + + fn freshest_duration(&self) -> Duration { + let mut freshest = self.fresh_duration; + for path in &self.fresh_files { + if let Ok(metadata) = path.metadata() { + if let Ok(modified) = metadata.modified() { + let duration = modified.elapsed().unwrap_or_default(); + freshest = min(freshest, duration); + } + } + } + freshest + } +} + +static FRESH_DURATION_YEAR: Lazy = + Lazy::new(|| Duration::from_secs(60 * 60 * 24 * 7 * 52)); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 48c8a2e81..a4d693806 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -49,7 +49,7 @@ impl Command for Latest { ) })?; - if let Some(version) = plugin.latest_version(&prefix) { + if let Some(version) = plugin.latest_version(&config.settings, &prefix)? { rtxprintln!(out, "{}", version); } Ok(()) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2e51b3e20..a63183613 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -206,6 +206,7 @@ pub mod tests { use crate::config::Settings; use crate::dirs; use crate::plugins::{Plugin, PluginName}; + use crate::ui::progress_report::ProgressReport; use super::*; @@ -239,7 +240,12 @@ pub mod tests { missing_runtime_behavior: AutoInstall, ..Settings::default() }; - Plugin::load_ensure_installed(&PluginName::from(name), &settings).unwrap(); + let mut plugin = Plugin::new(&PluginName::from(name)); + if plugin.is_installed() { + plugin + .install(&settings, None, ProgressReport::new(true)) + .unwrap(); + } } pub fn grep(output: String, pattern: &str) -> String { diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 14d2ee177..11d715d4d 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -56,7 +56,7 @@ impl Command for PluginsInstall { return self.install_all_missing_plugins(&config); } let (name, git_url) = get_name_and_url(self.name.unwrap(), self.git_url)?; - let mut plugin = Plugin::load(&name, &config.settings)?; + let mut plugin = Plugin::new(&name); if self.force { plugin.uninstall()?; } diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index add17bcd1..4b0178bc9 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -64,6 +64,7 @@ mod tests { #[test] fn test_plugin_update() { + assert_cli!("plugin", "install", "nodejs"); let err = assert_cli_err!("p", "update"); assert_str_eq!(err.to_string(), "no plugins specified"); assert_cli!("plugin", "update", "--all"); diff --git a/src/config/mod.rs b/src/config/mod.rs index c5b72381d..49098a128 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -32,10 +32,10 @@ impl Config { pub fn load() -> Result { let rtxrc = load_rtxrc()?; let settings = rtxrc.settings(); - let plugins = load_plugins(&settings)?; + let plugins = load_plugins()?; let legacy_files = load_legacy_files(&settings, &plugins); let config_files = find_all_config_files(&legacy_files); - let aliases = load_aliases(&settings, &plugins)?; + let aliases = load_aliases(&settings, &plugins); let config = Self { settings, @@ -67,16 +67,10 @@ fn load_rtxrc() -> Result { Ok(rtxrc) } -fn load_plugins(settings: &Settings) -> Result> { +fn load_plugins() -> Result> { let plugins = Plugin::list()? .into_par_iter() - .filter_map(|mut p| match p.ensure_loaded(settings) { - Ok(_) => Some((p.name.clone(), p)), - Err(e) => { - error!("Failed to load plugin {}: {}", p.name, e); - None - } - }) + .map(|p| (p.name.clone(), p)) .collect::>() .into_iter() .sorted_by_cached_key(|(p, _)| p.to_string()) @@ -98,8 +92,8 @@ fn load_legacy_files( .filter_map(|plugin| match plugin.legacy_filenames(settings) { Ok(filenames) => Some( filenames - .into_iter() - .map(|f| (f, plugin.name.clone())) + .iter() + .map(|f| (f.to_string(), plugin.name.clone())) .collect_vec(), ), Err(err) => { @@ -134,12 +128,26 @@ fn find_all_config_files(legacy_filenames: &IndexMap) -> Vec config_files.into_iter().unique().collect() } -fn load_aliases(settings: &Settings, plugins: &IndexMap) -> Result { - let mut aliases = IndexMap::new(); - for plugin in plugins.values() { - for (from, to) in plugin.get_aliases() { +fn load_aliases(settings: &Settings, plugins: &IndexMap) -> AliasMap { + let mut aliases: AliasMap = IndexMap::new(); + let plugin_aliases: Vec<_> = plugins + .values() + .par_bridge() + .map(|plugin| { + let aliases = match plugin.get_aliases(settings) { + Ok(aliases) => aliases, + Err(err) => { + eprintln!("Error: {err}"); + IndexMap::new() + } + }; + (&plugin.name, aliases) + }) + .collect(); + for (plugin, plugin_aliases) in plugin_aliases { + for (from, to) in plugin_aliases { aliases - .entry(plugin.name.clone()) + .entry(plugin.clone()) .or_insert_with(IndexMap::new) .insert(from, to); } @@ -154,7 +162,7 @@ fn load_aliases(settings: &Settings, plugins: &IndexMap) -> } } - Ok(aliases) + aliases } fn err_load_settings(settings_path: &Path) -> Report { diff --git a/src/dirs.rs b/src/dirs.rs index 26bc5a522..1d6c15db0 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -8,10 +8,9 @@ lazy_static! { pub static ref CURRENT: PathBuf = env::PWD.clone(); pub static ref HOME: PathBuf = env::HOME.clone(); pub static ref ROOT: PathBuf = env::RTX_DATA_DIR.clone(); + pub static ref CACHE: PathBuf = env::RTX_CACHE_DIR.clone(); pub static ref CONFIG: PathBuf = env::RTX_CONFIG_DIR.clone(); - pub static ref SHORTHAND_REPOSITORY: PathBuf = env::RTX_DATA_DIR.join("repository"); pub static ref PLUGINS: PathBuf = env::RTX_DATA_DIR.join("plugins"); pub static ref DOWNLOADS: PathBuf = env::RTX_DATA_DIR.join("downloads"); pub static ref INSTALLS: PathBuf = env::RTX_DATA_DIR.join("installs"); - pub static ref LEGACY_CACHE: PathBuf = env::RTX_DATA_DIR.join("legacy_cache"); } diff --git a/src/file.rs b/src/file.rs index 016bcf45d..da767babd 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,6 +1,5 @@ use std::io; use std::path::{Path, PathBuf}; -use std::time::Duration; use color_eyre::eyre::Result; use filetime::{set_file_times, FileTime}; @@ -20,13 +19,6 @@ pub fn display_path(path: &Path) -> String { } } -pub fn changed_within(f: &Path, within: Duration) -> Result { - let now = std::time::SystemTime::now(); - let last_modified = f.metadata()?.modified()?; - let diff = now.duration_since(last_modified)?; - Ok(diff < within) -} - pub fn touch_dir(dir: &Path) -> io::Result<()> { let now = FileTime::now(); set_file_times(dir, now, now) @@ -147,15 +139,6 @@ mod tests { assert_eq!(result, Some(dirs::HOME.join(".tool-versions"))); } - #[test] - fn test_changed_within() { - let dir = dirs::CURRENT.to_path_buf(); - set_file_times(&dir, FileTime::zero(), FileTime::zero()).unwrap(); - assert!(!changed_within(&dir, Duration::from_secs(1000)).unwrap()); - touch_dir(&dir).unwrap(); - assert!(changed_within(&dir, Duration::from_secs(1000)).unwrap()); - } - #[test] fn test_dir_subdirs() { let subdirs = dir_subdirs(dirs::HOME.as_path()).unwrap(); diff --git a/src/main.rs b/src/main.rs index b623fead2..38ba34fb7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ mod output; mod regex; pub mod build_time; +mod cache; mod cli; mod cmd; mod config; diff --git a/src/plugins/cache.rs b/src/plugins/cache.rs deleted file mode 100644 index ad5b122a8..000000000 --- a/src/plugins/cache.rs +++ /dev/null @@ -1,32 +0,0 @@ -use flate2::read::ZlibDecoder; -use flate2::write::ZlibEncoder; -use flate2::Compression; -use serde_derive::{Deserialize, Serialize}; -use std::fs::File; -use std::io::{Read, Write}; -use std::path::Path; - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] -pub struct PluginCache { - pub versions: Vec, - pub legacy_filenames: Vec, - pub aliases: Vec<(String, String)>, -} - -impl PluginCache { - pub fn parse(path: &Path) -> color_eyre::Result { - trace!("reading plugin cache from {}", path.to_string_lossy()); - let mut gz = ZlibDecoder::new(File::open(path)?); - let mut bytes = Vec::new(); - gz.read_to_end(&mut bytes)?; - Ok(rmp_serde::from_slice(&bytes)?) - } - - pub fn write(&self, path: &Path) -> color_eyre::Result<()> { - trace!("writing plugin cache to {}", path.to_string_lossy()); - let mut gz = ZlibEncoder::new(File::create(path)?, Compression::fast()); - gz.write_all(&rmp_serde::to_vec_named(self)?[..])?; - - Ok(()) - } -} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 80898ff58..aaea4a22b 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,5 +1,4 @@ use std::fs; -use std::fs::remove_file; use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; @@ -17,13 +16,12 @@ use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; -use cache::PluginCache; pub use script_manager::{InstallType, Script, ScriptManager}; +use crate::cache::CacheManager; use crate::cmd::cmd; use crate::config::{MissingRuntimeBehavior, Settings}; use crate::errors::Error::PluginNotInstalled; -use crate::file::changed_within; use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; @@ -33,7 +31,6 @@ use crate::ui::progress_report::ProgressReport; use crate::ui::prompt; use crate::{dirs, file}; -mod cache; mod script_manager; pub type PluginName = String; @@ -46,39 +43,34 @@ pub struct Plugin { cache_path: PathBuf, downloads_path: PathBuf, installs_path: PathBuf, - cache: Option, script_man: ScriptManager, + remote_version_cache: CacheManager>, + alias_cache: CacheManager>, + legacy_filename_cache: CacheManager>, } impl Plugin { pub fn new(name: &PluginName) -> Self { let plugin_path = dirs::PLUGINS.join(name); + let cache_path = dirs::CACHE.join(name); Self { name: name.into(), - cache_path: plugin_path.join(".rtxcache.msgpack"), script_man: ScriptManager::new(plugin_path.clone()), - plugin_path, downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), - cache: None, - } - } - - pub fn load(name: &PluginName, settings: &Settings) -> Result { - let mut plugin = Self::new(name); - if plugin.is_installed() { - plugin.ensure_loaded(settings)?; - } - Ok(plugin) - } - - pub fn load_ensure_installed(name: &PluginName, settings: &Settings) -> Result { - let mut plugin = Self::new(name); - if !plugin.ensure_installed(settings)? { - Err(PluginNotInstalled(plugin.name.to_string()))?; + remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack")) + .with_fresh_duration(Duration::from_secs(60 * 60 * 24)) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-all")), + alias_cache: CacheManager::new(cache_path.join("aliases.msgpack")) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-aliases")), + legacy_filename_cache: CacheManager::new(cache_path.join("legacy_filenames.msgpack")) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), + plugin_path, + cache_path, } - plugin.cache = Some(plugin.get_cache(settings)?); - Ok(plugin) } pub fn list() -> Result> { @@ -92,11 +84,6 @@ impl Plugin { self.plugin_path.exists() } - pub fn ensure_loaded(&mut self, settings: &Settings) -> Result<()> { - self.cache = Some(self.get_cache(settings)?); - Ok(()) - } - pub fn get_remote_url(&self) -> Option { let git = Git::new(self.plugin_path.to_path_buf()); git.get_remote_url() @@ -131,8 +118,18 @@ impl Plugin { let git = Git::new(self.plugin_path.to_path_buf()); pr.set_message(format!("cloning {repository}")); git.clone(repository)?; - pr.set_message("loading plugin".into()); - self.ensure_loaded(settings)?; + + pr.set_message("loading plugin remote versions".into()); + self.list_remote_versions(settings)?; + if self.has_list_alias_script() { + pr.set_message("getting plugin aliases".into()); + self.get_aliases(settings)?; + } + if self.has_list_legacy_filenames_script() { + pr.set_message("getting plugin legacy filenames".into()); + self.legacy_filenames(settings)?; + } + let sha = git.current_sha_short()?; pr.finish_with_message(format!( "{} {repository}@{}", @@ -232,15 +229,16 @@ impl Plugin { Ok(()) } - pub fn latest_version(&self, query: &str) -> Option { - let matches = self.list_versions_matching(query); - match matches.contains(&query.to_string()) { + pub fn latest_version(&self, settings: &Settings, query: &str) -> Result> { + let matches = self.list_versions_matching(settings, query)?; + let v = match matches.contains(&query.to_string()) { true => Some(query.to_string()), false => matches.last().map(|v| v.to_string()), - } + }; + Ok(v) } - pub fn list_versions_matching(&self, query: &str) -> Vec { + pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { let mut query = query; if query == "latest" { query = "[0-9]"; @@ -252,19 +250,14 @@ impl Plugin { } let query_regex = Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - self.cache - .as_ref() - .expect("plugin not loaded") - .versions + let versions = self + .list_remote_versions(settings)? .iter() .filter(|v| !VERSION_REGEX.is_match(v)) .filter(|v| query_regex.is_match(v)) .cloned() - .collect_vec() - } - - pub fn legacy_filenames(&self, settings: &Settings) -> Result> { - Ok(self.get_cache(settings)?.legacy_filenames) + .collect_vec(); + Ok(versions) } pub fn list_installed_versions(&self) -> Result> { @@ -279,21 +272,25 @@ impl Plugin { }) } - pub fn list_remote_versions(&self, settings: &Settings) -> Result> { - self.clear_cache(); - let cache = self.get_cache(settings)?; - - Ok(cache.versions) + pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { + // TODO: self.remote_version_cache.clear(); + self.remote_version_cache + .get(|| self.fetch_remote_versions(settings)) } - pub fn get_aliases(&self) -> IndexMap { - self.cache - .as_ref() - .expect("plugin not loaded") - .aliases + pub fn get_aliases(&self, settings: &Settings) -> Result> { + let aliases = self + .alias_cache + .get(|| self.fetch_aliases(settings))? .iter() .map(|(k, v)| (k.to_string(), v.to_string())) - .collect() + .collect(); + Ok(aliases) + } + + pub fn legacy_filenames(&self, settings: &Settings) -> Result<&Vec> { + self.legacy_filename_cache + .get(|| self.fetch_legacy_filenames(settings)) } pub fn external_commands(&self) -> Result>> { @@ -365,58 +362,8 @@ impl Plugin { Ok(stdout.split_whitespace().map(|v| v.into()).collect()) } - fn get_cache(&self, settings: &Settings) -> Result { - if let Some(cache) = self.cache.as_ref() { - return Ok(cache.clone()); - } - if !self.is_installed() { - return Err(PluginNotInstalled(self.name.clone()).into()); - } - let cp = &self.cache_path; - // TODO: put this duration into settings - let pc = match cp.exists() && changed_within(cp, Duration::from_secs(60 * 60 * 24))? { - true => PluginCache::parse(cp)?, - false => { - let pc = self.build_cache(settings)?; - pc.write(cp).unwrap_or_else(|e| { - warn!( - "Failed to write plugin cache to {}: {}", - cp.to_string_lossy(), - e - ); - }); - - pc - } - }; - - Ok(pc) - } - - fn build_cache(&self, settings: &Settings) -> Result { - Ok(PluginCache { - versions: self - .fetch_remote_versions(settings) - .wrap_err_with(|| eyre!("fetching remote versions for {}", self.name))?, - legacy_filenames: self - .fetch_legacy_filenames(settings) - .wrap_err_with(|| eyre!("fetching legacy filenames for {}", self.name))?, - aliases: self - .fetch_aliases(settings) - .wrap_err_with(|| eyre!("fetching aliases for {}", self.name))?, - }) - } - - fn clear_cache(&self) { - if self.cache_path.exists() { - remove_file(&self.cache_path).unwrap_or_else(|e| { - debug!("failed to remove cache file: {}", e); - }); - } - } - fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { - if !self.script_man.script_exists(&Script::ListLegacyFilenames) { + if !self.has_list_legacy_filenames_script() { return Ok(vec![]); } Ok(self @@ -427,8 +374,14 @@ impl Plugin { .collect()) } + fn has_list_alias_script(&self) -> bool { + self.script_man.script_exists(&Script::ListAliases) + } + fn has_list_legacy_filenames_script(&self) -> bool { + self.script_man.script_exists(&Script::ListLegacyFilenames) + } fn fetch_aliases(&self, settings: &Settings) -> Result> { - if !self.script_man.script_exists(&Script::ListAliases) { + if !self.has_list_alias_script() { return Ok(vec![]); } let stdout = self @@ -478,8 +431,8 @@ impl Plugin { } fn legacy_cache_file_path(&self, legacy_file: &Path) -> PathBuf { - dirs::LEGACY_CACHE - .join(&self.name) + self.cache_path + .join("legacy") .join(hash_to_str(&legacy_file.to_string_lossy())) .with_extension("txt") } @@ -512,7 +465,7 @@ mod tests { fn test_legacy_gemfile() { assert_cli!("plugin", "add", "ruby"); let settings = Settings::default(); - let plugin = Plugin::load(&PluginName::from("ruby"), &settings).unwrap(); + let plugin = Plugin::new(&PluginName::from("ruby")); let gemfile = env::HOME.join("fixtures/Gemfile"); let version = plugin.parse_legacy_file(&gemfile, &settings).unwrap(); assert_str_eq!(version, "3.0.5"); @@ -526,8 +479,8 @@ mod tests { fn test_exact_match() { assert_cli!("plugin", "add", "python"); let settings = Settings::default(); - let plugin = Plugin::load(&PluginName::from("python"), &settings).unwrap(); - let version = plugin.latest_version("3.9.1").unwrap(); + let plugin = Plugin::new(&PluginName::from("python")); + let version = plugin.latest_version(&settings, "3.9.1").unwrap().unwrap(); assert_str_eq!(version, "3.9.1"); } } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index d77400535..f1ddd7d04 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -151,7 +151,7 @@ impl Toolset { }) .map(|(plugin, versions)| { for version in versions { - version.resolve(&config.settings, plugin); + version.resolve(&config.settings, plugin)?; version.install(config, mpr.add())?; } Ok(()) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 13f81069a..7a45af594 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::{Config, Settings}; +use crate::dirs; use crate::plugins::{InstallType, Plugin}; use crate::runtimes::RuntimeVersion; @@ -35,38 +36,47 @@ impl ToolVersion { } } - pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) { + pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) -> Result<()> { if self.rtv.is_some() { - return; + return Ok(()); } match self.r#type.clone() { ToolVersionType::Version(v) => self.resolve_version(settings, plugin, &v), - ToolVersionType::Prefix(v) => self.resolve_prefix(plugin, &v), + ToolVersionType::Prefix(v) => self.resolve_prefix(settings, plugin, &v), ToolVersionType::Ref(_) => unimplemented!(), ToolVersionType::Path(_) => unimplemented!(), - ToolVersionType::System => (), + ToolVersionType::System => Ok(()), } } - fn resolve_version(&mut self, settings: &Settings, plugin: &Plugin, v: &str) { - let v = resolve_alias(settings, plugin, v); + fn resolve_version(&mut self, settings: &Settings, plugin: &Plugin, v: &str) -> Result<()> { + let v = resolve_alias(settings, plugin, v)?; + + if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { + // if the version is already installed, no need to fetch all of the remote versions + self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), &v)); + return Ok(()); + } - let matches = plugin.list_versions_matching(&v); + let matches = plugin.list_versions_matching(settings, &v)?; if matches.contains(&v) { self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), &v)); } else { - self.resolve_prefix(plugin, &v) + self.resolve_prefix(settings, plugin, &v)?; } + + Ok(()) } - fn resolve_prefix(&mut self, plugin: &Plugin, prefix: &str) { - let matches = plugin.list_versions_matching(prefix); + fn resolve_prefix(&mut self, settings: &Settings, plugin: &Plugin, prefix: &str) -> Result<()> { + let matches = plugin.list_versions_matching(settings, prefix)?; let v = match matches.last() { Some(v) => v, None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), v)); + Ok(()) } pub fn is_missing(&self) -> bool { @@ -112,14 +122,14 @@ impl Display for ToolVersion { } } -pub fn resolve_alias(settings: &Settings, plugin: &Plugin, v: &str) -> String { +pub fn resolve_alias(settings: &Settings, plugin: &Plugin, v: &str) -> Result { if let Some(plugin_aliases) = settings.aliases.get(&plugin.name) { if let Some(alias) = plugin_aliases.get(v) { - return alias.clone(); + return Ok(alias.clone()); } } - if let Some(alias) = plugin.get_aliases().get(v) { - return alias.clone(); + if let Some(alias) = plugin.get_aliases(settings)?.get(v) { + return Ok(alias.clone()); } - v.to_string() + Ok(v.to_string()) } diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 56cf77b0d..6489481ec 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -23,7 +23,9 @@ impl ToolVersionList { } pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) { for tv in &mut self.versions { - tv.resolve(settings, plugin); + if let Err(err) = tv.resolve(settings, plugin) { + warn!("failed to resolve tool version: {}", err); + } } } pub fn resolved_versions(&self) -> Vec<&RuntimeVersion> { diff --git a/test/.gitignore b/test/.gitignore index 8fce60300..b981dcfea 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1 +1,2 @@ data/ +cache/ From 4dc859149b6c28120a2c44fdd7c7a68fafce9889 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 16:46:27 -0600 Subject: [PATCH 0184/1891] refactor: clean up colors and remove unused code --- src/cli/plugins/update.rs | 8 ++--- src/config/settings.rs | 3 +- src/plugins/mod.rs | 64 +++++---------------------------------- src/runtimes/mod.rs | 62 ++++++------------------------------- src/toolset/mod.rs | 10 +++--- src/ui/color.rs | 27 ++--------------- src/ui/progress_report.rs | 8 ++--- src/ui/prompt.rs | 12 ++------ 8 files changed, 31 insertions(+), 163 deletions(-) diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 4b0178bc9..2aecde7be 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,13 +1,12 @@ use color_eyre::eyre::{eyre, Result}; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; -use owo_colors::Stream; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; -use crate::ui::color::{cyan, Color}; /// updates a plugin to the latest version /// @@ -31,7 +30,7 @@ impl Command for Update { .into_iter() .map(|p| { config.plugins.get(&p).ok_or_else(|| { - eyre!("plugin {} not found", cyan(Stream::Stderr, p.as_str())) + eyre!("plugin {} not found", style(p.as_str()).cyan().for_stderr()) }) }) .collect::>()?, @@ -47,13 +46,12 @@ impl Command for Update { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx plugins update --all # update all plugins $ rtx plugins update nodejs # update only nodejs - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/config/settings.rs b/src/config/settings.rs index 8669b5506..57ad233f9 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -8,7 +8,6 @@ use crate::config::AliasMap; use crate::env; use crate::env::{RTX_JOBS, RTX_LOG_LEVEL, RTX_VERBOSE}; use crate::plugins::PluginName; -use crate::ui::prompt::is_tty; #[derive(Debug, Clone)] pub struct Settings { @@ -30,7 +29,7 @@ impl Default for Settings { legacy_version_file: true, plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), aliases: IndexMap::new(), - verbose: *RTX_VERBOSE || !is_tty(), + verbose: *RTX_VERBOSE || !console::user_attended_stderr(), jobs: *RTX_JOBS, log_level: *RTX_LOG_LEVEL, } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index aaea4a22b..d3db17e4c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -3,8 +3,6 @@ use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; -use atty::Stream; -use atty::Stream::Stderr; use color_eyre::eyre::WrapErr; use color_eyre::eyre::{eyre, Result}; use console::style; @@ -20,15 +18,14 @@ pub use script_manager::{InstallType, Script, ScriptManager}; use crate::cache::CacheManager; use crate::cmd::cmd; -use crate::config::{MissingRuntimeBehavior, Settings}; +use crate::config::Settings; use crate::errors::Error::PluginNotInstalled; use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::shorthand::shorthand_to_repository; -use crate::ui::color::{cyan, Color}; + use crate::ui::progress_report::ProgressReport; -use crate::ui::prompt; use crate::{dirs, file}; mod script_manager; @@ -102,8 +99,8 @@ impl Plugin { pr.set_style(PROG_TEMPLATE.clone()); pr.set_prefix(format!( "{} {} ", - COLOR.dimmed("rtx"), - COLOR.cyan(&self.name) + style("rtx").dim().for_stderr(), + style(&self.name).cyan().for_stderr() )); pr.enable_steady_tick(); let repository = repository @@ -133,57 +130,12 @@ impl Plugin { let sha = git.current_sha_short()?; pr.finish_with_message(format!( "{} {repository}@{}", - COLOR.green("âś“"), - COLOR.bright_yellow(&sha), + style("âś“").green().for_stderr(), + style(&sha).bright().yellow().for_stderr(), )); Ok(()) } - pub fn ensure_installed(&mut self, settings: &Settings) -> Result { - static COLOR: Lazy = Lazy::new(|| Color::new(Stderr)); - if self.is_installed() { - return Ok(true); - } - - match shorthand_to_repository(&self.name) { - Some(repo) => match settings.missing_runtime_behavior { - MissingRuntimeBehavior::AutoInstall => { - self.install(settings, Some(repo), ProgressReport::new(settings.verbose))?; - Ok(true) - } - MissingRuntimeBehavior::Prompt => { - match prompt::prompt_for_install(&format!("plugin {}", COLOR.cyan(&self.name))) - { - true => { - self.install( - settings, - Some(repo), - ProgressReport::new(settings.verbose), - )?; - Ok(true) - } - false => Ok(false), - } - } - MissingRuntimeBehavior::Warn => { - warn!("{}", PluginNotInstalled(self.name.clone())); - Ok(false) - } - MissingRuntimeBehavior::Ignore => { - debug!("{}", PluginNotInstalled(self.name.clone())); - Ok(false) - } - }, - None => match settings.missing_runtime_behavior { - MissingRuntimeBehavior::Ignore => Ok(false), - _ => { - warn!("Plugin not found: {}", COLOR.cyan(&self.name)); - Ok(false) - } - }, - } - } - pub fn update(&self, gitref: Option) -> Result<()> { let plugin_path = self.plugin_path.to_path_buf(); if plugin_path.is_symlink() { @@ -217,7 +169,7 @@ impl Plugin { fs::remove_dir_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", - cyan(Stderr, &dir.to_string_lossy()) + style(&dir.to_string_lossy()).cyan().for_stderr() ) }) }; @@ -451,8 +403,6 @@ impl PartialEq for Plugin { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); - #[cfg(test)] mod tests { use pretty_assertions::assert_str_eq; diff --git a/src/runtimes/mod.rs b/src/runtimes/mod.rs index d2da005fc..0d92a1083 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes/mod.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use atty::Stream::Stderr; use std::fmt; use std::fmt::{Display, Formatter}; use std::fs::{create_dir_all, remove_dir_all}; @@ -8,25 +7,24 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; +use console::style; use indicatif::ProgressStyle; use once_cell::sync::Lazy; use runtime_conf::RuntimeConf; use crate::config::Config; -use crate::config::{MissingRuntimeBehavior, Settings}; +use crate::config::Settings; use crate::env_diff::{EnvDiff, EnvDiffOperation}; -use crate::errors::Error::VersionNotInstalled; + use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; -use crate::ui::color::Color; + use crate::ui::progress_report::ProgressReport; -use crate::ui::prompt; + use crate::{dirs, env, fake_asdf, file}; mod runtime_conf; -static COLOR: Lazy = Lazy::new(|| Color::new(Stderr)); - /// These represent individual plugin@version pairs of runtimes /// installed to ~/.local/share/rtx/runtimes #[derive(Debug, Clone)] @@ -71,8 +69,8 @@ impl RuntimeVersion { pr.set_style(PROG_TEMPLATE.clone()); pr.set_prefix(format!( "{} {} ", - COLOR.dimmed("rtx"), - COLOR.cyan(&self.to_string()) + style("rtx").dim().for_stderr(), + style(&self.to_string()).cyan().for_stderr() )); pr.enable_steady_tick(); @@ -88,7 +86,7 @@ impl RuntimeVersion { script, |output| { self.cleanup_install_dirs_on_error(settings); - pr.finish_with_message(format!("error {}", COLOR.red("âś—"))); + pr.finish_with_message(format!("error {}", style("âś—").red().for_stderr())); if !settings.verbose && !output.trim().is_empty() { pr.println(output); } @@ -121,7 +119,7 @@ impl RuntimeVersion { debug!("error touching config file: {:?} {:?}", path, err); } } - pr.finish_with_message(COLOR.green("âś“")); + pr.finish_with_message(style("âś“").green().for_stderr().to_string()); Ok(()) } @@ -141,46 +139,6 @@ impl RuntimeVersion { Ok(bin_paths) } - pub fn ensure_installed(&self, config: &Config) -> Result { - if self.is_installed() || self.version == "system" { - return Ok(true); - } - match config.settings.missing_runtime_behavior { - MissingRuntimeBehavior::AutoInstall => { - self.install( - InstallType::Version, - config, - ProgressReport::new(config.settings.verbose), - )?; - Ok(true) - } - MissingRuntimeBehavior::Prompt => { - if prompt::prompt_for_install(&COLOR.cyan(&self.to_string())) { - self.install( - InstallType::Version, - config, - ProgressReport::new(config.settings.verbose), - )?; - Ok(true) - } else { - Ok(false) - } - } - MissingRuntimeBehavior::Warn => { - let plugin = self.plugin.name.clone(); - let version = self.version.clone(); - warn!("{}", VersionNotInstalled(plugin, version)); - Ok(false) - } - MissingRuntimeBehavior::Ignore => { - let plugin = self.plugin.name.clone(); - let version = self.version.clone(); - debug!("{}", VersionNotInstalled(plugin, version)); - Ok(false) - } - } - } - pub fn is_installed(&self) -> bool { if self.version == "system" { return true; @@ -203,7 +161,7 @@ impl RuntimeVersion { remove_dir_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", - COLOR.cyan(dir.to_str().unwrap()) + style(dir.to_str().unwrap()).cyan().for_stderr() ) }) }; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index f1ddd7d04..dd679ee33 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -3,11 +3,11 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::Arc; -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indexmap::IndexMap; use itertools::Itertools; -use once_cell::sync::Lazy; + use rayon::prelude::*; use rayon::ThreadPoolBuilder; @@ -22,7 +22,7 @@ use crate::env; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; use crate::toolset::tool_version_list::ToolVersionList; -use crate::ui::color::Color; + use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; @@ -319,12 +319,10 @@ impl Display for Toolset { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); - fn display_versions(versions: &[&mut ToolVersion]) -> String { let display_versions = versions .iter() - .map(|v| COLOR.cyan(&v.to_string())) + .map(|v| style(&v.to_string()).cyan().for_stderr().to_string()) .join(", "); display_versions } diff --git a/src/ui/color.rs b/src/ui/color.rs index 888bc4fd9..08121b0c0 100644 --- a/src/ui/color.rs +++ b/src/ui/color.rs @@ -1,10 +1,6 @@ use atty::Stream; use owo_colors::OwoColorize; -pub fn cyan(stream: Stream, s: &str) -> String { - s.if_supports_color(stream, |s| s.cyan()).to_string() -} - pub struct Color { stream: Stream, } @@ -18,31 +14,12 @@ impl Color { self.underline(&self.bold(title)) } - pub fn dimmed(&self, s: &str) -> String { - s.if_supports_color(self.stream, |s| s.dimmed()).to_string() - } - - pub fn bold(&self, s: &str) -> String { + fn bold(&self, s: &str) -> String { s.if_supports_color(self.stream, |s| s.bold()).to_string() } - pub fn underline(&self, s: &str) -> String { + fn underline(&self, s: &str) -> String { s.if_supports_color(self.stream, |s| s.underline()) .to_string() } - - pub fn cyan(&self, s: &str) -> String { - s.if_supports_color(self.stream, |s| s.cyan()).to_string() - } - - pub fn green(&self, s: &str) -> String { - s.if_supports_color(self.stream, |s| s.green()).to_string() - } - pub fn red(&self, s: &str) -> String { - s.if_supports_color(self.stream, |s| s.red()).to_string() - } - pub fn bright_yellow(&self, s: &str) -> String { - s.if_supports_color(self.stream, |s| s.bright_yellow()) - .to_string() - } } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index e8c6de58b..3e924eda9 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,7 +1,5 @@ -use crate::ui::color::Color; -use atty::Stream; use indicatif::ProgressBar; -use once_cell::sync::Lazy; + use std::time::Duration; #[derive(Debug)] @@ -42,7 +40,7 @@ impl ProgressReport { match &self.pb { Some(pb) => { pb.set_style(style); - pb.set_prefix(COLOR.dimmed("rtx")); + pb.set_prefix(console::style("rtx").dim().for_stderr().to_string()); } None => (), } @@ -66,5 +64,3 @@ impl ProgressReport { } } } - -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index e501c3580..9fce9282b 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,10 +1,6 @@ -use crate::ui::color::Color; -use atty::Stream; -use once_cell::sync::Lazy; +use console::style; use std::io::stdin; -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stderr)); - pub fn prompt() -> String { let mut input = String::new(); stdin().read_line(&mut input).expect("error reading stdin"); @@ -18,7 +14,7 @@ pub fn prompt_for_install(thing: &str) -> bool { let stderr = console::Term::stderr(); eprint!( "{} Would you like to install {}? [Y/n] ", - COLOR.dimmed("rtx"), + style("rtx").dim().for_stderr(), thing, ); let yn = matches!(prompt().to_lowercase().as_str(), "" | "y" | "yes"); @@ -29,7 +25,3 @@ pub fn prompt_for_install(thing: &str) -> bool { false => false, } } - -pub fn is_tty() -> bool { - atty::is(atty::Stream::Stdin) && atty::is(atty::Stream::Stderr) -} From a7bfcd750929cf5c6221411c1eb1f51d0e3e608b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 18:29:40 -0600 Subject: [PATCH 0185/1891] dynamically regenerate runtimeconf This actually removes the runtimeconf in favor of just caching the bin_paths as a discrete cache item (which was the only thing inside of runtimeconf before anyways) --- README.md | 28 +++++-------------- src/cache.rs | 29 ++++++++++---------- src/cli/render_help.rs | 28 +++++-------------- src/plugins/mod.rs | 26 ++++++++++-------- src/{runtimes/mod.rs => runtimes.rs} | 40 +++++++++------------------- src/runtimes/runtime_conf.rs | 27 ------------------- 6 files changed, 54 insertions(+), 124 deletions(-) rename src/{runtimes/mod.rs => runtimes.rs} (90%) delete mode 100644 src/runtimes/runtime_conf.rs diff --git a/README.md b/README.md index f0f4688f6..2f7d1fc87 100644 --- a/README.md +++ b/README.md @@ -1440,31 +1440,15 @@ to be updating, this is a good place to start. ### Plugin Cache -Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack`. It stores -the list of versions available for that plugin (`rtx ls-remote `) and the legacy filenames (see below). +Each plugin has a cache that's stored in `~/.cache/rtx/plugins/`. It stores +the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), +the list of aliases, and the bin directories within each runtime installation. -It is updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is -gzipped messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). +Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is +zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/.local/share/rtx/plugins/nodejs/.rtxcache.msgpack.gz | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode -``` - -### Runtime Cache - -Each runtime (language version, e.g.: `nodejs@20.0.0`), has a file called "runtimeconf" that's stored -inside the install directory, e.g.: `~/.asdf/installs/nodejs/20.0.0/.rtxconf.msgpack`. This stores the -information about the runtime that should not change after installation. Currently this is just the -bin paths the plugin defines in `bin/list-bin-paths`. By default this is just `/bin`. It's the list -of paths that rtx will add to `PATH` when the runtime is activated. - -I have not seen a plugins which has _dynamic_ bin paths but let me know if you find one. If that is -the case, we may need to make this cached instead of static. - -"Runtimeconf" is stored as uncompressed messagepack and can be viewed with the following: - -``` -cat ~/.local/share/rtx/installs/nodejs/18.13.0/.rtxconf.msgpack | msgpack-cli decode +cat ~/.cache/rtx/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` ### Legacy File Cache diff --git a/src/cache.rs b/src/cache.rs index 2e55442c6..00784c483 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -9,7 +9,7 @@ use color_eyre::eyre::Result; use flate2::read::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; -use once_cell::sync::{Lazy, OnceCell}; +use once_cell::sync::OnceCell; use serde::de::DeserializeOwned; use serde::Serialize; @@ -19,7 +19,7 @@ where T: Clone + Serialize + DeserializeOwned, { cache_file_path: PathBuf, - fresh_duration: Duration, + fresh_duration: Option, fresh_files: Vec, cache: Box>, } @@ -33,12 +33,12 @@ where cache_file_path, cache: Box::new(OnceCell::new()), fresh_files: Vec::new(), - fresh_duration: *FRESH_DURATION_YEAR, + fresh_duration: None, } } pub fn with_fresh_duration(mut self, duration: Duration) -> Self { - self.fresh_duration = duration; + self.fresh_duration = Some(duration); self } @@ -47,7 +47,7 @@ where self } - pub fn get(&self, fetch: F) -> Result<&T> + pub fn get_or_try_init(&self, fetch: F) -> Result<&T> where F: FnOnce() -> Result, { @@ -95,28 +95,29 @@ where if !self.cache_file_path.exists() { return false; } - let fresh_duration = self.freshest_duration(); - if let Ok(metadata) = self.cache_file_path.metadata() { - if let Ok(modified) = metadata.modified() { - return modified.elapsed().unwrap_or_default() < fresh_duration; + if let Some(fresh_duration) = self.freshest_duration() { + if let Ok(metadata) = self.cache_file_path.metadata() { + if let Ok(modified) = metadata.modified() { + return modified.elapsed().unwrap_or_default() < fresh_duration; + } } } true } - fn freshest_duration(&self) -> Duration { + fn freshest_duration(&self) -> Option { let mut freshest = self.fresh_duration; for path in &self.fresh_files { if let Ok(metadata) = path.metadata() { if let Ok(modified) = metadata.modified() { let duration = modified.elapsed().unwrap_or_default(); - freshest = min(freshest, duration); + freshest = Some(match freshest { + None => duration, + Some(freshest) => min(freshest, duration), + }) } } } freshest } } - -static FRESH_DURATION_YEAR: Lazy = - Lazy::new(|| Duration::from_secs(60 * 60 * 24 * 7 * 52)); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index d5184390c..d6fb6788e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -726,31 +726,15 @@ to be updating, this is a good place to start. ### Plugin Cache -Each plugin has a cache that's stored in `~/.local/share/rtx/plugins//.rtxcache.msgpack`. It stores -the list of versions available for that plugin (`rtx ls-remote `) and the legacy filenames (see below). +Each plugin has a cache that's stored in `~/.cache/rtx/plugins/`. It stores +the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), +the list of aliases, and the bin directories within each runtime installation. -It is updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is -gzipped messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). +Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is +zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/.local/share/rtx/plugins/nodejs/.rtxcache.msgpack.gz | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode -``` - -### Runtime Cache - -Each runtime (language version, e.g.: `nodejs@20.0.0`), has a file called "runtimeconf" that's stored -inside the install directory, e.g.: `~/.asdf/installs/nodejs/20.0.0/.rtxconf.msgpack`. This stores the -information about the runtime that should not change after installation. Currently this is just the -bin paths the plugin defines in `bin/list-bin-paths`. By default this is just `/bin`. It's the list -of paths that rtx will add to `PATH` when the runtime is activated. - -I have not seen a plugins which has _dynamic_ bin paths but let me know if you find one. If that is -the case, we may need to make this cached instead of static. - -"Runtimeconf" is stored as uncompressed messagepack and can be viewed with the following: - -``` -cat ~/.local/share/rtx/installs/nodejs/18.13.0/.rtxconf.msgpack | msgpack-cli decode +cat ~/.cache/rtx/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` ### Legacy File Cache diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index d3db17e4c..a9213728e 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -55,16 +55,20 @@ impl Plugin { script_man: ScriptManager::new(plugin_path.clone()), downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), - remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack")) - .with_fresh_duration(Duration::from_secs(60 * 60 * 24)) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-all")), - alias_cache: CacheManager::new(cache_path.join("aliases.msgpack")) + remote_version_cache: CacheManager::new( + cache_path.join("remote_versions.msgpack.zlib"), + ) + .with_fresh_duration(Duration::from_secs(60 * 60 * 24)) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-all")), + alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.zlib")) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-aliases")), - legacy_filename_cache: CacheManager::new(cache_path.join("legacy_filenames.msgpack")) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), + legacy_filename_cache: CacheManager::new( + cache_path.join("legacy_filenames.msgpack.zlib"), + ) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), plugin_path, cache_path, } @@ -227,13 +231,13 @@ impl Plugin { pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { // TODO: self.remote_version_cache.clear(); self.remote_version_cache - .get(|| self.fetch_remote_versions(settings)) + .get_or_try_init(|| self.fetch_remote_versions(settings)) } pub fn get_aliases(&self, settings: &Settings) -> Result> { let aliases = self .alias_cache - .get(|| self.fetch_aliases(settings))? + .get_or_try_init(|| self.fetch_aliases(settings))? .iter() .map(|(k, v)| (k.to_string(), v.to_string())) .collect(); @@ -242,7 +246,7 @@ impl Plugin { pub fn legacy_filenames(&self, settings: &Settings) -> Result<&Vec> { self.legacy_filename_cache - .get(|| self.fetch_legacy_filenames(settings)) + .get_or_try_init(|| self.fetch_legacy_filenames(settings)) } pub fn external_commands(&self) -> Result>> { diff --git a/src/runtimes/mod.rs b/src/runtimes.rs similarity index 90% rename from src/runtimes/mod.rs rename to src/runtimes.rs index 0d92a1083..b5f303851 100644 --- a/src/runtimes/mod.rs +++ b/src/runtimes.rs @@ -1,30 +1,23 @@ use std::collections::HashMap; - use std::fmt; use std::fmt::{Display, Formatter}; use std::fs::{create_dir_all, remove_dir_all}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use color_eyre::eyre::{eyre, Result, WrapErr}; +use color_eyre::eyre::{Result, WrapErr}; use console::style; use indicatif::ProgressStyle; use once_cell::sync::Lazy; -use runtime_conf::RuntimeConf; - +use crate::cache::CacheManager; use crate::config::Config; use crate::config::Settings; use crate::env_diff::{EnvDiff, EnvDiffOperation}; - use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; - use crate::ui::progress_report::ProgressReport; - use crate::{dirs, env, fake_asdf, file}; -mod runtime_conf; - /// These represent individual plugin@version pairs of runtimes /// installed to ~/.local/share/rtx/runtimes #[derive(Debug, Clone)] @@ -33,22 +26,24 @@ pub struct RuntimeVersion { pub plugin: Arc, pub install_path: PathBuf, download_path: PathBuf, - runtime_conf_path: PathBuf, script_man: ScriptManager, + bin_paths_cache: CacheManager>, } impl RuntimeVersion { pub fn new(plugin: Arc, version: &str) -> Self { let install_path = dirs::INSTALLS.join(&plugin.name).join(version); let download_path = dirs::DOWNLOADS.join(&plugin.name).join(version); + let cache_path = dirs::CACHE.join(&plugin.name).join(version); Self { - runtime_conf_path: install_path.join(".rtxconf.msgpack"), script_man: build_script_man( version, &plugin.plugin_path, &install_path, &download_path, ), + bin_paths_cache: CacheManager::new(cache_path.join("bin_paths.msgpack.zlib")) + .with_fresh_file(install_path.clone()), download_path: dirs::DOWNLOADS.join(&plugin.name).join(version), install_path, version: version.into(), @@ -105,11 +100,6 @@ impl RuntimeVersion { run_script(install)?; self.cleanup_install_dirs(settings); - let conf = RuntimeConf { - bin_paths: self.get_bin_paths()?, - }; - conf.write(&self.runtime_conf_path)?; - // attempt to touch all the .tool-version files to trigger updates in hook-env let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; touch_dirs.extend(config.config_files.iter().cloned()); @@ -125,25 +115,19 @@ impl RuntimeVersion { } pub fn list_bin_paths(&self) -> Result> { - if self.version == "system" { - return Ok(vec![]); - } - let conf = RuntimeConf::parse(&self.runtime_conf_path) - .wrap_err_with(|| eyre!("failed to fetch runtimeconf for {}", self))?; - let bin_paths = conf - .bin_paths + Ok(self + .bin_paths_cache + .get_or_try_init(|| self.fetch_bin_paths())? .iter() .map(|path| self.install_path.join(path)) - .collect(); - - Ok(bin_paths) + .collect()) } pub fn is_installed(&self) -> bool { if self.version == "system" { return true; } - self.runtime_conf_path.is_file() + self.install_path.exists() } pub fn uninstall(&self) -> Result<()> { @@ -191,7 +175,7 @@ impl RuntimeVersion { Ok(env) } - fn get_bin_paths(&self) -> Result> { + fn fetch_bin_paths(&self) -> Result> { let list_bin_paths = self.plugin.plugin_path.join("bin/list-bin-paths"); if list_bin_paths.exists() { let output = self.script_man.cmd(Script::ListBinPaths).read()?; diff --git a/src/runtimes/runtime_conf.rs b/src/runtimes/runtime_conf.rs deleted file mode 100644 index a427f24cf..000000000 --- a/src/runtimes/runtime_conf.rs +++ /dev/null @@ -1,27 +0,0 @@ -use serde_derive::{Deserialize, Serialize}; -use std::fs::File; -use std::io::Write; -use std::path::Path; - -#[derive(Debug, Serialize, Deserialize, Default)] -pub struct RuntimeConf { - pub bin_paths: Vec, -} - -impl RuntimeConf { - pub fn parse(path: &Path) -> color_eyre::Result { - Ok(rmp_serde::from_read(File::open(path)?)?) - // let contents = std::fs::read_to_string(path) - // .wrap_err_with(|| format!("failed to read {}", path.to_string_lossy()))?; - // let conf: Self = toml::from_str(&contents) - // .wrap_err_with(|| format!("failed to from_file {}", path.to_string_lossy()))?; - - // Ok(conf) - } - - pub fn write(&self, path: &Path) -> color_eyre::Result<()> { - let bytes = rmp_serde::to_vec_named(self)?; - File::create(path)?.write_all(&bytes)?; - Ok(()) - } -} From e2faded858cb5c7bc326e5156293ff0eb21ea9c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 18:46:44 -0600 Subject: [PATCH 0186/1891] refactor: static plugins this makes it so plugins are not mutable, which was not necessary --- src/cli/mod.rs | 2 +- src/cli/plugins/install.rs | 4 ++-- src/cli/plugins/update.rs | 3 ++- src/config/mod.rs | 11 ++++++----- src/plugins/mod.rs | 2 +- src/toolset/mod.rs | 10 +++++----- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index a63183613..1ebd6e40e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -240,7 +240,7 @@ pub mod tests { missing_runtime_behavior: AutoInstall, ..Settings::default() }; - let mut plugin = Plugin::new(&PluginName::from(name)); + let plugin = Plugin::new(&PluginName::from(name)); if plugin.is_installed() { plugin .install(&settings, None, ProgressReport::new(true)) diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 11d715d4d..91aefa34e 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -56,7 +56,7 @@ impl Command for PluginsInstall { return self.install_all_missing_plugins(&config); } let (name, git_url) = get_name_and_url(self.name.unwrap(), self.git_url)?; - let mut plugin = Plugin::new(&name); + let plugin = Plugin::new(&name); if self.force { plugin.uninstall()?; } @@ -79,7 +79,7 @@ impl PluginsInstall { warn!("all plugins already installed"); } for plugin in missing_plugins { - let mut plugin = Plugin::new(&plugin); + let plugin = Plugin::new(&plugin); let (_, git_url) = get_name_and_url(plugin.name.clone(), None)?; plugin.install( &config.settings, diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 2aecde7be..30b334fa0 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -2,6 +2,7 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; +use std::sync::Arc; use crate::cli::command::Command; use crate::config::Config; @@ -25,7 +26,7 @@ pub struct Update { impl Command for Update { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugins: Vec<&Plugin> = match (self.plugin, self.all) { + let plugins: Vec<&Arc> = match (self.plugin, self.all) { (Some(plugins), _) => plugins .into_iter() .map(|p| { diff --git a/src/config/mod.rs b/src/config/mod.rs index 49098a128..729dcbac2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,6 @@ use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; +use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; use color_eyre::Report; @@ -25,7 +26,7 @@ pub struct Config { pub legacy_files: IndexMap, pub config_files: Vec, pub aliases: AliasMap, - pub plugins: IndexMap, + pub plugins: IndexMap>, } impl Config { @@ -67,10 +68,10 @@ fn load_rtxrc() -> Result { Ok(rtxrc) } -fn load_plugins() -> Result> { +fn load_plugins() -> Result>> { let plugins = Plugin::list()? .into_par_iter() - .map(|p| (p.name.clone(), p)) + .map(|p| (p.name.clone(), Arc::new(p))) .collect::>() .into_iter() .sorted_by_cached_key(|(p, _)| p.to_string()) @@ -80,7 +81,7 @@ fn load_plugins() -> Result> { fn load_legacy_files( settings: &Settings, - plugins: &IndexMap, + plugins: &IndexMap>, ) -> IndexMap { if !settings.legacy_version_file { return IndexMap::new(); @@ -128,7 +129,7 @@ fn find_all_config_files(legacy_filenames: &IndexMap) -> Vec config_files.into_iter().unique().collect() } -fn load_aliases(settings: &Settings, plugins: &IndexMap) -> AliasMap { +fn load_aliases(settings: &Settings, plugins: &IndexMap>) -> AliasMap { let mut aliases: AliasMap = IndexMap::new(); let plugin_aliases: Vec<_> = plugins .values() diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index a9213728e..afeb0c703 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -91,7 +91,7 @@ impl Plugin { } pub fn install( - &mut self, + &self, settings: &Settings, repository: Option<&str>, mut pr: ProgressReport, diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index dd679ee33..4dbd4fc88 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -40,7 +40,7 @@ mod tool_version_list; pub struct Toolset { pub versions: IndexMap, source: Option, - plugins: IndexMap, + plugins: IndexMap>, } impl Toolset { @@ -50,7 +50,7 @@ impl Toolset { ..Default::default() } } - pub fn with_plugins(mut self, plugins: IndexMap) -> Self { + pub fn with_plugins(mut self, plugins: IndexMap>) -> Self { self.plugins = plugins; self } @@ -172,7 +172,7 @@ impl Toolset { let plugins = missing_plugins .into_par_iter() .map(|plugin_name| { - let mut plugin = Plugin::new(&plugin_name); + let plugin = Plugin::new(&plugin_name); if !plugin.is_installed() { plugin.install(&config.settings, None, mpr.add())?; } @@ -180,7 +180,7 @@ impl Toolset { }) .collect::>>()?; for plugin in plugins { - self.plugins.insert(plugin.name.clone(), plugin); + self.plugins.insert(plugin.name.clone(), Arc::new(plugin)); } self.plugins.sort_keys(); Ok(()) @@ -209,7 +209,7 @@ impl Toolset { let versions = p.list_installed_versions()?; Ok(versions .into_iter() - .map(|v| RuntimeVersion::new(Arc::new(p.clone()), &v))) + .map(|v| RuntimeVersion::new(p.clone(), &v))) }) .collect::>>()? .into_iter() From eecb758b5f516d21d9c81788cc4eb14a54bc97f9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 20:05:02 -0600 Subject: [PATCH 0187/1891] feat: ref/path support (#150) Fixes #98 Fixes #120 ref: lets you specify a git sha to download path: lets you use a custom runtime directory prefix: forces prefix matching (so you can do golang@prefix:1.19 to match any "go1.19*" version --- README.md | 9 ++-- src/cli/args/runtime.rs | 36 +++++++++++---- src/cli/install.rs | 14 +++++- src/cli/local.rs | 12 +++++ src/cli/render_help.rs | 9 ++-- src/config/config_file/mod.rs | 5 ++- src/plugins/script_manager.rs | 19 ++++---- src/runtimes.rs | 76 +++++++++++++++++++++----------- src/toolset/builder.rs | 15 +++++++ src/toolset/mod.rs | 47 ++++++++++++++++++-- src/toolset/tool_version.rs | 50 ++++++++++++--------- src/toolset/tool_version_list.rs | 5 ++- 12 files changed, 218 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 2f7d1fc87..5b8672590 100644 --- a/README.md +++ b/README.md @@ -315,10 +315,13 @@ The `.tool-versions` file is used to specify the runtime versions for a project. is: ``` -nodejs 20.0.0 # comments are allowed -ruby 3 # can be fuzzy version -shellcheck latest # also supports "latest" +nodejs 20.0.0 # comments are allowed +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 +shfmt path:./shfmt # use a custom runtime ``` Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local) to create them automatically. diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index fad25d679..eee006078 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -26,11 +26,11 @@ pub enum RuntimeArgVersion { /// use the system runtime already on PATH /// e.g.: `nodejs@system` System, - // /// build runtime from source at this VCS sha - // rtx currently does not support this, see https://github.com/jdxcode/rtx/issues/98 - // Ref, - // /// runtime is in a local directory, not managed by rtx - // Path, + /// build runtime from source at this VCS sha + Ref(String), + /// runtime is in a local directory, not managed by rtx + Path(String), + Prefix(String), } impl RuntimeArg { @@ -40,9 +40,23 @@ impl RuntimeArg { plugin: plugin.into(), version: RuntimeArgVersion::System, }, - Some((plugin, version)) => Self { - plugin: plugin.into(), - version: RuntimeArgVersion::Version(version.into()), + Some((plugin, version)) => match version.split_once(':') { + Some(("path", path)) => Self { + plugin: plugin.into(), + version: RuntimeArgVersion::Path(path.into()), + }, + Some(("ref", ref_)) => Self { + plugin: plugin.into(), + version: RuntimeArgVersion::Ref(ref_.into()), + }, + Some(("prefix", prefix)) => Self { + plugin: plugin.into(), + version: RuntimeArgVersion::Prefix(prefix.into()), + }, + _ => Self { + plugin: plugin.into(), + version: RuntimeArgVersion::Version(version.into()), + }, }, None => Self { plugin: input.into(), @@ -81,7 +95,10 @@ impl Display for RuntimeArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.version { RuntimeArgVersion::System => write!(f, "{}@system", self.plugin), + RuntimeArgVersion::Path(path) => write!(f, "{}@path:{}", self.plugin, path), RuntimeArgVersion::Version(version) => write!(f, "{}@{}", self.plugin, version), + RuntimeArgVersion::Ref(ref_) => write!(f, "{}@ref:{}", self.plugin, ref_), + RuntimeArgVersion::Prefix(prefix) => write!(f, "{}@prefix:{}", self.plugin, prefix), RuntimeArgVersion::None => write!(f, "{}", self.plugin), } } @@ -92,6 +109,9 @@ impl Display for RuntimeArgVersion { match self { RuntimeArgVersion::System => write!(f, "system"), RuntimeArgVersion::Version(version) => write!(f, "{version}"), + RuntimeArgVersion::Path(path) => write!(f, "path:{path}"), + RuntimeArgVersion::Ref(ref_) => write!(f, "ref:{ref_}"), + RuntimeArgVersion::Prefix(prefix) => write!(f, "prefix:{prefix}"), RuntimeArgVersion::None => write!(f, "current"), } } diff --git a/src/cli/install.rs b/src/cli/install.rs index 060de0bdd..0e2359f49 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -127,7 +127,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use crate::assert_cli; + use crate::{assert_cli, dirs}; + use pretty_assertions::assert_str_eq; #[test] fn test_install_force() { @@ -144,4 +145,15 @@ mod tests { assert_cli!("install", "-f", "shfmt@my/alias"); assert_cli!("where", "shfmt@my/alias"); } + + #[test] + fn test_install_ref() { + assert_cli!("install", "-f", "dummy@ref:master"); + assert_cli!("global", "dummy@ref:master"); + let output = assert_cli!("where", "dummy"); + assert_str_eq!( + output.trim(), + dirs::INSTALLS.join("dummy/ref-master").to_string_lossy() + ); + } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 8790cf6fd..62636fa4f 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -149,6 +149,18 @@ mod tests { let stdout = assert_cli!("local", "--pin", "tiny", "2"); assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); + // path + let stdout = assert_cli!("local", "dummy@path:."); + assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); + + // ref + let stdout = assert_cli!("local", "dummy@ref:master"); + assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); + + // prefix + let stdout = assert_cli!("local", "dummy@prefix:1"); + assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); + // will output the current version(s) let stdout = assert_cli!("local", "tiny"); assert_str_eq!(stdout, "2.1.0\n"); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index d6fb6788e..1ad252ac8 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -334,10 +334,13 @@ The `.tool-versions` file is used to specify the runtime versions for a project. is: ``` -nodejs 20.0.0 # comments are allowed -ruby 3 # can be fuzzy version -shellcheck latest # also supports "latest" +nodejs 20.0.0 # comments are allowed +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 +shfmt path:./shfmt # use a custom runtime ``` Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local) to create them automatically. diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 4c6885b5b..1b2b8fbdc 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -63,8 +63,11 @@ impl dyn ConfigFile { .push(if pin { rtv.version.to_string() } else { - match runtime.version { + match &runtime.version { RuntimeArgVersion::Version(ref v) => v.to_string(), + RuntimeArgVersion::Path(p) => format!("path:{p}"), + RuntimeArgVersion::Ref(r) => format!("ref:{r}"), + RuntimeArgVersion::Prefix(p) => format!("prefix:{p}"), _ => "latest".to_string(), } }); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index b154332e8..994e177e8 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -64,15 +64,19 @@ impl fmt::Display for Script { #[derive(Debug, Clone)] pub enum InstallType { - Version, - Ref, + Version(String), + Ref(String), + Path(PathBuf), + System, } impl Display for InstallType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - InstallType::Version => write!(f, "version"), - InstallType::Ref => write!(f, "ref"), + InstallType::Version(v) => write!(f, "{v}"), + InstallType::Ref(r) => write!(f, "ref:{r}"), + InstallType::Path(p) => write!(f, "path:{}", p.display()), + InstallType::System => write!(f, "system"), } } } @@ -117,13 +121,8 @@ impl ScriptManager { } pub fn cmd(&self, script: Script) -> Expression { - let mut env = self.env.clone(); let args = match &script { Script::ParseLegacyFile(filename) => vec![filename.clone()], - Script::Install(install_type) | Script::Download(install_type) => { - env.insert("ASDF_INSTALL_TYPE".to_string(), install_type.to_string()); - vec![] - } _ => vec![], }; let script_path = self.get_script_path(&script); @@ -131,7 +130,7 @@ impl ScriptManager { // return Err(PluginNotInstalled(self.plugin_name.clone()).into()); // } let mut cmd = cmd(&script_path, args); - for (k, v) in env.iter() { + for (k, v) in self.env.iter() { cmd = cmd.env(k, v); } cmd diff --git a/src/runtimes.rs b/src/runtimes.rs index b5f303851..7efce7f3a 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; -use std::fmt; use std::fmt::{Display, Formatter}; -use std::fs::{create_dir_all, remove_dir_all}; +use std::fs::{create_dir_all, remove_dir_all, File}; use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::{fmt, fs}; use color_eyre::eyre::{Result, WrapErr}; use console::style; @@ -14,6 +14,7 @@ use crate::cache::CacheManager; use crate::config::Config; use crate::config::Settings; use crate::env_diff::{EnvDiff, EnvDiffOperation}; +use crate::hash::hash_to_str; use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; use crate::ui::progress_report::ProgressReport; use crate::{dirs, env, fake_asdf, file}; @@ -25,38 +26,44 @@ pub struct RuntimeVersion { pub version: String, pub plugin: Arc, pub install_path: PathBuf, + pub install_type: InstallType, download_path: PathBuf, script_man: ScriptManager, bin_paths_cache: CacheManager>, } impl RuntimeVersion { - pub fn new(plugin: Arc, version: &str) -> Self { - let install_path = dirs::INSTALLS.join(&plugin.name).join(version); - let download_path = dirs::DOWNLOADS.join(&plugin.name).join(version); - let cache_path = dirs::CACHE.join(&plugin.name).join(version); + pub fn new(plugin: Arc, install_type: InstallType) -> Self { + let version = match &install_type { + InstallType::Version(v) => v.to_string(), + InstallType::Ref(r) => format!("ref-{r}"), + InstallType::Path(p) => hash_to_str(&p), + InstallType::System => "system".into(), + }; + let install_path = match &install_type { + InstallType::Path(p) => p.clone(), + _ => dirs::INSTALLS.join(&plugin.name).join(&version), + }; + let download_path = dirs::DOWNLOADS.join(&plugin.name).join(&version); + let cache_path = dirs::CACHE.join(&plugin.name).join(&version); Self { script_man: build_script_man( - version, + install_type.clone(), &plugin.plugin_path, &install_path, &download_path, ), bin_paths_cache: CacheManager::new(cache_path.join("bin_paths.msgpack.zlib")) .with_fresh_file(install_path.clone()), - download_path: dirs::DOWNLOADS.join(&plugin.name).join(version), + download_path, install_path, - version: version.into(), + version, plugin, + install_type, } } - pub fn install( - &self, - install_type: InstallType, - config: &Config, - mut pr: ProgressReport, - ) -> Result<()> { + pub fn install(&self, config: &Config, mut pr: ProgressReport) -> Result<()> { static PROG_TEMPLATE: Lazy = Lazy::new(|| { ProgressStyle::with_template("{prefix}{wide_msg} {spinner:.blue} {elapsed:.dim.italic}") .unwrap() @@ -70,11 +77,11 @@ impl RuntimeVersion { pr.enable_steady_tick(); let settings = &config.settings; - debug!("install {} {}", self, install_type); + debug!("install {} {}", self, self.install_type); self.create_install_dirs()?; - let download = Script::Download(install_type.clone()); - let install = Script::Install(install_type); + let download = Script::Download(self.install_type.clone()); + let install = Script::Install(self.install_type.clone()); let run_script = |script| { self.script_man.run_by_line( @@ -109,6 +116,9 @@ impl RuntimeVersion { debug!("error touching config file: {:?} {:?}", path, err); } } + if let Err(err) = fs::remove_file(self.incomplete_file_path()) { + debug!("error removing .rtx-incomplete: {:?}", err); + } pr.finish_with_message(style("âś“").green().for_stderr().to_string()); Ok(()) @@ -124,10 +134,13 @@ impl RuntimeVersion { } pub fn is_installed(&self) -> bool { - if self.version == "system" { - return true; + match &self.install_type { + InstallType::System => true, + InstallType::Path(p) => p.exists(), + InstallType::Version(_) | InstallType::Ref(_) => { + self.install_path.exists() && !self.incomplete_file_path().exists() + } } - self.install_path.exists() } pub fn uninstall(&self) -> Result<()> { @@ -190,6 +203,7 @@ impl RuntimeVersion { let _ = remove_dir_all(&self.download_path); create_dir_all(&self.install_path)?; create_dir_all(&self.download_path)?; + File::create(self.incomplete_file_path())?; Ok(()) } @@ -202,6 +216,10 @@ impl RuntimeVersion { let _ = remove_dir_all(&self.download_path); } } + + fn incomplete_file_path(&self) -> PathBuf { + self.install_path.join(".rtx-incomplete") + } } impl Display for RuntimeVersion { @@ -217,15 +235,14 @@ impl PartialEq for RuntimeVersion { } fn build_script_man( - version: &str, + install_type: InstallType, plugin_path: &Path, install_path: &Path, download_path: &Path, ) -> ScriptManager { - ScriptManager::new(plugin_path.to_path_buf()) + let sm = ScriptManager::new(plugin_path.to_path_buf()) .with_envs(env::PRISTINE_ENV.clone()) .with_env("PATH".into(), fake_asdf::get_path_with_fake_asdf()) - .with_env("ASDF_INSTALL_VERSION".into(), version.to_string()) .with_env( "ASDF_INSTALL_PATH".into(), install_path.to_string_lossy().to_string(), @@ -234,5 +251,14 @@ fn build_script_man( "ASDF_DOWNLOAD_PATH".into(), download_path.to_string_lossy().to_string(), ) - .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()) + .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()); + match install_type { + InstallType::Version(v) => sm + .with_env("ASDF_INSTALL_TYPE".into(), "version".into()) + .with_env("ASDF_INSTALL_VERSION".into(), v), + InstallType::Ref(r) => sm + .with_env("ASDF_INSTALL_TYPE".into(), "ref".into()) + .with_env("ASDF_INSTALL_VERSION".into(), r), + _ => sm, + } } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 10f280b8f..3dacaaf32 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -108,6 +108,21 @@ fn load_runtime_args(ts: &mut Toolset, args: &[RuntimeArg]) { ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v.clone())); arg_ts.add_version(plugin_name.clone(), version); } + RuntimeArgVersion::Ref(ref v) => { + let version = + ToolVersion::new(plugin_name.clone(), ToolVersionType::Ref(v.clone())); + arg_ts.add_version(plugin_name.clone(), version); + } + RuntimeArgVersion::Path(ref v) => { + let version = + ToolVersion::new(plugin_name.clone(), ToolVersionType::Path(v.clone())); + arg_ts.add_version(plugin_name.clone(), version); + } + RuntimeArgVersion::Prefix(ref v) => { + let version = + ToolVersion::new(plugin_name.clone(), ToolVersionType::Prefix(v.clone())); + arg_ts.add_version(plugin_name.clone(), version); + } // I believe this will do nothing since it would just default to the `.tool-versions` version // RuntimeArgVersion::None => { // arg_ts.add_version(plugin_name.clone(), ToolVersion::None); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 4dbd4fc88..69c603bde 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -19,7 +19,7 @@ pub use tool_version::ToolVersionType; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::{InstallType, Plugin, PluginName}; use crate::runtimes::RuntimeVersion; use crate::toolset::tool_version_list::ToolVersionList; @@ -83,7 +83,7 @@ impl Toolset { return; } }; - v.resolve(&config.settings, plugin); + v.resolve(&config.settings, plugin.clone()); }); } pub fn install_missing(&mut self, config: &Config) -> Result<()> { @@ -151,7 +151,7 @@ impl Toolset { }) .map(|(plugin, versions)| { for version in versions { - version.resolve(&config.settings, plugin)?; + version.resolve(&config.settings, plugin.clone())?; version.install(config, mpr.add())?; } Ok(()) @@ -209,7 +209,7 @@ impl Toolset { let versions = p.list_installed_versions()?; Ok(versions .into_iter() - .map(|v| RuntimeVersion::new(p.clone(), &v))) + .map(|v| RuntimeVersion::new(p.clone(), InstallType::Version(v)))) }) .collect::>>()? .into_iter() @@ -297,6 +297,45 @@ impl Toolset { } None } + RuntimeArgVersion::Prefix(version) => { + if let Some(tvl) = self.versions.get(&arg.plugin) { + for tv in tvl.versions.iter() { + match &tv.r#type { + ToolVersionType::Prefix(v) if v.starts_with(version) => { + return tv.rtv.as_ref(); + } + _ => (), + } + } + } + None + } + RuntimeArgVersion::Ref(ref_) => { + if let Some(tvl) = self.versions.get(&arg.plugin) { + for tv in tvl.versions.iter() { + match &tv.r#type { + ToolVersionType::Ref(v) if v == ref_ => { + return tv.rtv.as_ref(); + } + _ => (), + } + } + } + None + } + RuntimeArgVersion::Path(path) => { + if let Some(tvl) = self.versions.get(&arg.plugin) { + for tv in tvl.versions.iter() { + match &tv.r#type { + ToolVersionType::Path(v) if v == path => { + return tv.rtv.as_ref(); + } + _ => (), + } + } + } + None + } RuntimeArgVersion::None => { let plugin = self.versions.get(&arg.plugin); match plugin { diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 7a45af594..8b10d2bcd 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -1,11 +1,11 @@ use std::fmt::{Display, Formatter}; +use std::fs; use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::{Config, Settings}; use crate::dirs; - use crate::plugins::{InstallType, Plugin}; use crate::runtimes::RuntimeVersion; use crate::ui::progress_report::ProgressReport; @@ -36,31 +36,38 @@ impl ToolVersion { } } - pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) -> Result<()> { + pub fn resolve(&mut self, settings: &Settings, plugin: Arc) -> Result<()> { if self.rtv.is_some() { return Ok(()); } match self.r#type.clone() { ToolVersionType::Version(v) => self.resolve_version(settings, plugin, &v), ToolVersionType::Prefix(v) => self.resolve_prefix(settings, plugin, &v), - ToolVersionType::Ref(_) => unimplemented!(), - ToolVersionType::Path(_) => unimplemented!(), + ToolVersionType::Ref(r) => { + self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Ref(r))); + Ok(()) + } + ToolVersionType::Path(path) => { + let path = fs::canonicalize(path)?; + self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Path(path))); + Ok(()) + } ToolVersionType::System => Ok(()), } } - fn resolve_version(&mut self, settings: &Settings, plugin: &Plugin, v: &str) -> Result<()> { - let v = resolve_alias(settings, plugin, v)?; + fn resolve_version(&mut self, settings: &Settings, plugin: Arc, v: &str) -> Result<()> { + let v = resolve_alias(settings, plugin.clone(), v)?; if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { // if the version is already installed, no need to fetch all of the remote versions - self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), &v)); + self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Version(v))); return Ok(()); } let matches = plugin.list_versions_matching(settings, &v)?; if matches.contains(&v) { - self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), &v)); + self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Version(v))); } else { self.resolve_prefix(settings, plugin, &v)?; } @@ -68,14 +75,22 @@ impl ToolVersion { Ok(()) } - fn resolve_prefix(&mut self, settings: &Settings, plugin: &Plugin, prefix: &str) -> Result<()> { + fn resolve_prefix( + &mut self, + settings: &Settings, + plugin: Arc, + prefix: &str, + ) -> Result<()> { let matches = plugin.list_versions_matching(settings, prefix)?; let v = match matches.last() { Some(v) => v, None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; - self.rtv = Some(RuntimeVersion::new(Arc::new(plugin.clone()), v)); + self.rtv = Some(RuntimeVersion::new( + plugin, + InstallType::Version(v.to_string()), + )); Ok(()) } @@ -88,17 +103,8 @@ impl ToolVersion { pub fn install(&mut self, config: &Config, pr: ProgressReport) -> Result<()> { match self.r#type { - ToolVersionType::Version(_) | ToolVersionType::Prefix(_) => { - self.rtv - .as_ref() - .unwrap() - .install(InstallType::Version, config, pr)?; - } - ToolVersionType::Ref(_) => { - self.rtv - .as_ref() - .unwrap() - .install(InstallType::Ref, config, pr)?; + ToolVersionType::Version(_) | ToolVersionType::Prefix(_) | ToolVersionType::Ref(_) => { + self.rtv.as_ref().unwrap().install(config, pr)?; } _ => (), } @@ -122,7 +128,7 @@ impl Display for ToolVersion { } } -pub fn resolve_alias(settings: &Settings, plugin: &Plugin, v: &str) -> Result { +pub fn resolve_alias(settings: &Settings, plugin: Arc, v: &str) -> Result { if let Some(plugin_aliases) = settings.aliases.get(&plugin.name) { if let Some(alias) = plugin_aliases.get(v) { return Ok(alias.clone()); diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 6489481ec..379b386c9 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -1,6 +1,7 @@ use crate::config::Settings; use crate::plugins::Plugin; use crate::runtimes::RuntimeVersion; +use std::sync::Arc; use crate::toolset::{ToolSource, ToolVersion}; @@ -21,9 +22,9 @@ impl ToolVersionList { pub fn add_version(&mut self, version: ToolVersion) { self.versions.push(version); } - pub fn resolve(&mut self, settings: &Settings, plugin: &Plugin) { + pub fn resolve(&mut self, settings: &Settings, plugin: Arc) { for tv in &mut self.versions { - if let Err(err) = tv.resolve(settings, plugin) { + if let Err(err) = tv.resolve(settings, plugin.clone()) { warn!("failed to resolve tool version: {}", err); } } From c2689b750ea3c00ce43bbc25da400c22c41b2514 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Mon, 20 Feb 2023 03:19:12 +0100 Subject: [PATCH 0188/1891] feat: rtx env should default to bash (#86) (#148) Co-authored-by: Roland Schaer Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- src/cli/activate.rs | 3 ++- src/cli/deactivate.rs | 3 ++- src/cli/env.rs | 12 +++++++++++- src/cli/hook_env.rs | 2 +- src/shell/mod.rs | 12 ++++++------ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 539d3a780..1fdea433b 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -33,7 +33,8 @@ pub struct Activate { impl Command for Activate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let shell = get_shell(self.shell_type.or(self.shell)); + let shell = get_shell(self.shell_type.or(self.shell)) + .expect("no shell provided, use `--shell=zsh`"); if self.quiet { // TODO: it would probably be better to just set --quiet on `hook-env` diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index be43171bb..21dc142df 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -26,7 +26,8 @@ pub struct Deactivate { impl Command for Deactivate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let shell = get_shell(self.shell_type.or(self.shell)); + let shell = get_shell(self.shell_type.or(self.shell)) + .expect("no shell provided, use `--shell=zsh`"); // TODO: clear env using __RTX_DIFF let output = shell.deactivate(); diff --git a/src/cli/env.rs b/src/cli/env.rs index 03544daca..db510a1cf 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -37,7 +37,8 @@ impl Command for Env { .with_args(&self.runtime) .build(&config); - let shell = get_shell(self.shell); + let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); + let shell = get_shell(self.shell).unwrap_or(default_shell); for (k, v) in ts.env() { let k = k.to_string(); let v = v.to_string(); @@ -62,6 +63,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { + use std::env; + use crate::assert_cli; use crate::cli::tests::grep; use crate::dirs; @@ -112,4 +115,11 @@ mod tests { let stdout = assert_cli!("env", "tiny@1", "-s", "bash"); assert_str_eq!(grep(stdout, "JDXCODE"), "export JDXCODE_TINY=1.0.1"); } + + #[test] + fn test_env_default_shell() { + env::set_var("SHELL", ""); + let stdout = assert_cli!("env"); + assert!(stdout.contains("export PATH=")); + } } diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 63238757f..337224fbf 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -56,7 +56,7 @@ impl Command for HookEnv { impl HookEnv { fn build_env_commands(&self, patches: &EnvDiffPatches) -> String { - let shell = get_shell(self.shell); + let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); let mut output = String::new(); for patch in patches.iter() { diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 20515e96d..5afab5061 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -51,13 +51,13 @@ pub trait Shell { fn unset_env(&self, k: &str) -> String; } -pub fn get_shell(shell: Option) -> Box { +pub fn get_shell(shell: Option) -> Option> { match shell.or_else(ShellType::load) { - Some(ShellType::Bash) => Box::::default(), - Some(ShellType::Fish) => Box::::default(), - Some(ShellType::Xonsh) => Box::::default(), - Some(ShellType::Zsh) => Box::::default(), - _ => panic!("no shell provided, use `--shell=zsh`"), + Some(ShellType::Bash) => Some(Box::::default()), + Some(ShellType::Fish) => Some(Box::::default()), + Some(ShellType::Xonsh) => Some(Box::::default()), + Some(ShellType::Zsh) => Some(Box::::default()), + _ => None, } } From 570512a0022e40761a01d440bb346cf3e35f328c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 20:22:41 -0600 Subject: [PATCH 0189/1891] chore: Release rtx-cli version 1.11.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f69c1a37..985fc8477 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1369,7 +1369,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.10.1" +version = "1.11.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index e89304805..fe6ab817c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.10.1" +version = "1.11.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 5b8672590..eda01b414 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.10.1 +rtx 1.11.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -208,7 +208,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.1/rtx-v1.10.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.0/rtx-v1.11.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 537c2d4e6..07085cc22 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.10.1 +Version: 1.11.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1ad252ac8..df8f497e0 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -227,7 +227,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.10.1/rtx-v1.10.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.0/rtx-v1.11.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 2b97208c432aaa4dae96159c4fa32b7bdd9f967d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 21:55:31 -0600 Subject: [PATCH 0190/1891] perf: added RTX_PREFER_STALE config this will be set for "fast" commands like `exec-env`. If true, it will not refetch new runtime versions if they are stale. This will improve performance by not fetching new runtimes daily and also make rtx a bit more predictible: if you have "nodejs@18" set in your `.tool-versions`, it will not refetch new runtime versions --- src/cache.rs | 13 +++++++++++-- src/cli/latest.rs | 1 + src/cli/ls_remote.rs | 1 + src/config/mod.rs | 2 +- src/env.rs | 12 ++++++++++++ src/plugins/mod.rs | 12 ++++++++++-- 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index 00784c483..7eba767a1 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -37,8 +37,8 @@ where } } - pub fn with_fresh_duration(mut self, duration: Duration) -> Self { - self.fresh_duration = Some(duration); + pub fn with_fresh_duration(mut self, duration: Option) -> Self { + self.fresh_duration = duration; self } @@ -91,6 +91,15 @@ where Ok(()) } + pub fn clear(&self) -> Result<()> { + let path = &self.cache_file_path; + trace!("clearing cache {}", path.display()); + if path.exists() { + fs::remove_file(path)?; + } + Ok(()) + } + fn is_fresh(&self) -> bool { if !self.cache_file_path.exists() { return false; diff --git a/src/cli/latest.rs b/src/cli/latest.rs index a4d693806..a10a5f719 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -49,6 +49,7 @@ impl Command for Latest { ) })?; + plugin.clear_remote_version_cache()?; if let Some(version) = plugin.latest_version(&config.settings, &prefix)? { rtxprintln!(out, "{}", version); } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index ed17fbaa8..8fb5f9c06 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -27,6 +27,7 @@ impl Command for LsRemote { .plugins .get(&self.plugin) .ok_or(PluginNotInstalled(self.plugin))?; + plugin.clear_remote_version_cache()?; let versions = plugin.list_remote_versions(&config.settings)?; for version in versions { diff --git a/src/config/mod.rs b/src/config/mod.rs index 729dcbac2..4e9eb98d8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -191,6 +191,6 @@ impl Display for Config { .collect::>(); writeln!(f, "Config:")?; writeln!(f, " Files: {}", config_files.join(", "))?; - writeln!(f, " Installed Plugins: {}", plugins.join(", ")) + write!(f, " Installed Plugins: {}", plugins.join(", ")) } } diff --git a/src/env.rs b/src/env.rs index ff23a1932..c9cae1f20 100644 --- a/src/env.rs +++ b/src/env.rs @@ -118,6 +118,7 @@ lazy_static! { pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); + pub static ref RTX_PREFER_STALE: bool = prefer_stale(&ARGS); } fn get_env_diff() -> EnvDiff { @@ -197,6 +198,17 @@ fn apply_patches( new_env } +/// returns true if new runtime versions should not be fetched +fn prefer_stale(args: &[String]) -> bool { + if let Some(c) = args.get(1) { + return vec![ + "env", "hook-env", "x", "exec", "direnv", "activate", "current", "ls", "where", + ] + .contains(&c.as_str()); + } + false +} + #[test] fn test_apply_patches() { let mut env = HashMap::new(); diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index afeb0c703..6066d0562 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -25,6 +25,7 @@ use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::shorthand::shorthand_to_repository; +use crate::env::RTX_PREFER_STALE; use crate::ui::progress_report::ProgressReport; use crate::{dirs, file}; @@ -50,6 +51,11 @@ impl Plugin { pub fn new(name: &PluginName) -> Self { let plugin_path = dirs::PLUGINS.join(name); let cache_path = dirs::CACHE.join(name); + let fresh_duration = if *RTX_PREFER_STALE { + None + } else { + Some(Duration::from_secs(60 * 60 * 24)) + }; Self { name: name.into(), script_man: ScriptManager::new(plugin_path.clone()), @@ -58,7 +64,7 @@ impl Plugin { remote_version_cache: CacheManager::new( cache_path.join("remote_versions.msgpack.zlib"), ) - .with_fresh_duration(Duration::from_secs(60 * 60 * 24)) + .with_fresh_duration(fresh_duration) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-all")), alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.zlib")) @@ -228,8 +234,10 @@ impl Plugin { }) } + pub fn clear_remote_version_cache(&self) -> Result<()> { + self.remote_version_cache.clear() + } pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { - // TODO: self.remote_version_cache.clear(); self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) } From 28a09834f2cdea62cf9ca678fcccc087b831dd71 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 21:56:37 -0600 Subject: [PATCH 0191/1891] chore: Release rtx-cli version 1.11.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 985fc8477..ce12dad2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1369,7 +1369,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.11.0" +version = "1.11.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index fe6ab817c..58b94ce37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.11.0" +version = "1.11.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index eda01b414..ff008c654 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.11.0 +rtx 1.11.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -208,7 +208,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.0/rtx-v1.11.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.1/rtx-v1.11.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 07085cc22..7cc41b812 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.11.0 +Version: 1.11.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index df8f497e0..35cfe318a 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -227,7 +227,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.0/rtx-v1.11.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.1/rtx-v1.11.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From c931ab625af3cfe26dd48bac2fcc7c7bcaa93232 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 22:56:42 -0600 Subject: [PATCH 0192/1891] feat: added `rtx self-update` (#151) --- Cargo.lock | 33 +++++++++++++++++++++++++ Cargo.toml | 1 + README.md | 18 +++++++++----- completions/_rtx | 27 ++++++++++++++++++++ completions/rtx.bash | 50 +++++++++++++++++++++++++++++++++++-- completions/rtx.fish | 56 +++++++++++++++++++++++------------------- src/build_time.rs | 11 ++++++++- src/cli/mod.rs | 5 +++- src/cli/render_help.rs | 6 ----- src/cli/self_update.rs | 31 +++++++++++++++++++++++ 10 files changed, 197 insertions(+), 41 deletions(-) create mode 100644 src/cli/self_update.rs diff --git a/Cargo.lock b/Cargo.lock index ce12dad2d..9f407e217 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1231,6 +1231,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.23" @@ -1402,6 +1411,7 @@ dependencies = [ "regex", "reqwest", "rmp-serde", + "self_update", "serde", "serde_derive", "serde_json", @@ -1487,6 +1497,29 @@ dependencies = [ "libc", ] +[[package]] +name = "self_update" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e18819cd93c4799f93cd4cf0ac069ed0e615fea3af28ec78df71e0ea890628a" +dependencies = [ + "hyper", + "indicatif", + "log", + "quick-xml", + "regex", + "reqwest", + "semver", + "serde_json", + "tempfile", +] + +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + [[package]] name = "serde" version = "1.0.152" diff --git a/Cargo.toml b/Cargo.toml index 58b94ce37..1383cf9e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ rayon = "1.6.1" regex = "1.7.1" reqwest = { version = "0.11.14", features = ["blocking"] } rmp-serde = "1.1.1" +self_update = "0.35.0" serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.92" diff --git a/README.md b/README.md index ff008c654..0b09842f3 100644 --- a/README.md +++ b/README.md @@ -130,12 +130,6 @@ file, rtx will automatically add itself to `PATH`. $ curl https://rtx.pub/install.sh | sh ``` -> **Note** -> -> There isn't currently an autoupdater in rtx. So if you use this method you'll need to remember -> to fetch a new version manually for bug/feature fixes. I'm not sure if I'll ever add an autoupdater -> because it might be disruptive to autoupdate to a major version that has breaking changes. - or if you're allergic to `| sh`: ```sh-session @@ -1168,6 +1162,18 @@ Examples: $ rtx plugins update --all # update all plugins $ rtx plugins update nodejs # update only nodejs +``` +### `rtx self-update` + +``` +updates rtx itself + +Usage: self-update + +Options: + -h, --help + Print help + ``` ### `rtx settings get` diff --git a/completions/_rtx b/completions/_rtx index e0ac62781..37dd2674a 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -592,6 +592,17 @@ esac ;; esac ;; +(self-update) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; (settings) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ @@ -922,6 +933,10 @@ _arguments "${_arguments_options[@]}" \ ;; esac ;; +(self-update) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (settings) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help__settings_commands" \ @@ -1014,6 +1029,7 @@ _rtx_commands() { 'list-remote:list runtime versions available for install' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ +'self-update:updates rtx itself' \ 'settings:Manage settings' \ 'uninstall:removes runtime versions' \ 'version:Show rtx version' \ @@ -1316,6 +1332,7 @@ _rtx__help_commands() { 'ls:list installed runtime versions' \ 'ls-remote:list runtime versions available for install' \ 'plugins:Manage plugins' \ +'self-update:updates rtx itself' \ 'settings:Manage settings' \ 'uninstall:removes runtime versions' \ 'version:Show rtx version' \ @@ -1535,6 +1552,16 @@ _rtx__render-help_commands() { local commands; commands=() _describe -t commands 'rtx render-help commands' commands "$@" } +(( $+functions[_rtx__help__self-update_commands] )) || +_rtx__help__self-update_commands() { + local commands; commands=() + _describe -t commands 'rtx help self-update commands' commands "$@" +} +(( $+functions[_rtx__self-update_commands] )) || +_rtx__self-update_commands() { + local commands; commands=() + _describe -t commands 'rtx self-update commands' commands "$@" +} (( $+functions[_rtx__help__settings__set_commands] )) || _rtx__help__settings__set_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index c3d66a908..ca2799dc4 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -99,6 +99,9 @@ _rtx() { rtx,render-help) cmd="rtx__render__help" ;; + rtx,self-update) + cmd="rtx__self__update" + ;; rtx,settings) cmd="rtx__settings" ;; @@ -231,6 +234,9 @@ _rtx() { rtx__help,render-help) cmd="rtx__help__render__help" ;; + rtx__help,self-update) + cmd="rtx__help__self__update" + ;; rtx__help,settings) cmd="rtx__help__settings" ;; @@ -391,7 +397,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1073,7 +1079,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins settings uninstall version where render-help help" + opts="activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1520,6 +1526,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__self__update) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__settings) opts="get ls set unset" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2096,6 +2116,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__self__update) + opts="-j -v -h --log-level --jobs --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__settings) opts="-j -v -h --log-level --jobs --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 0203c9afa..be5cf8892 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -22,6 +22,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'list installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'list runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'removes runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' @@ -210,6 +211,10 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -256,31 +261,32 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' diff --git a/src/build_time.rs b/src/build_time.rs index 4555a052c..66c5d4af2 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -1,6 +1,8 @@ use crate::env::RTX_HIDE_OUTDATED_BUILD; use build_time::build_time_utc; use chrono::{DateTime, FixedOffset, Months, Utc}; +use console::style; +use indoc::eprintdoc; use lazy_static::lazy_static; lazy_static! { @@ -13,6 +15,13 @@ fn init() { if !*RTX_HIDE_OUTDATED_BUILD && BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() { - eprintln!("rtx has not been updated in over a year. Please update to the latest version."); + eprintdoc!( + " + {rtx} rtx has not been updated in over a year. + {rtx} Please update to the latest version, update with: `rtx self-update` + {rtx} To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1. + ", + rtx = style("rtx").dim().for_stderr() + ); } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1ebd6e40e..25c44b182 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -32,6 +32,7 @@ mod local; mod ls; mod ls_remote; mod plugins; +mod self_update; mod settings; mod uninstall; pub mod version; @@ -67,6 +68,7 @@ pub enum Commands { Ls(ls::Ls), LsRemote(ls_remote::LsRemote), Plugins(plugins::Plugins), + SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Uninstall(uninstall::Uninstall), Version(version::Version), @@ -94,10 +96,11 @@ impl Commands { Self::HookEnv(cmd) => cmd.run(config, out), Self::Install(cmd) => cmd.run(config, out), Self::Latest(cmd) => cmd.run(config, out), + Self::Local(cmd) => cmd.run(config, out), Self::Ls(cmd) => cmd.run(config, out), Self::LsRemote(cmd) => cmd.run(config, out), - Self::Local(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), + Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), Self::Version(cmd) => cmd.run(config, out), diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 35cfe318a..d91651df8 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -149,12 +149,6 @@ file, rtx will automatically add itself to `PATH`. $ curl https://rtx.pub/install.sh | sh ``` -> **Note** -> -> There isn't currently an autoupdater in rtx. So if you use this method you'll need to remember -> to fetch a new version manually for bug/feature fixes. I'm not sure if I'll ever add an autoupdater -> because it might be disruptive to autoupdate to a major version that has breaking changes. - or if you're allergic to `| sh`: ```sh-session diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs new file mode 100644 index 000000000..a09fe95bb --- /dev/null +++ b/src/cli/self_update.rs @@ -0,0 +1,31 @@ +use color_eyre::Result; +use console::style; +use self_update::cargo_crate_version; + +use crate::cli::command::Command; +use crate::cli::version::{ARCH, OS}; +use crate::config::Config; +use crate::output::Output; + +/// updates rtx itself +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct SelfUpdate {} + +impl Command for SelfUpdate { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let status = self_update::backends::github::Update::configure() + .repo_owner("jdxcode") + .repo_name("rtx") + .bin_name("rtx") + .show_download_progress(true) + .current_version(cargo_crate_version!()) + .target(&format!("{}-{}", *OS, *ARCH)) + .build()? + .update()?; + let version = style(status.version()).bright().yellow(); + rtxprintln!(out, "Updated rtx to {version}"); + + Ok(()) + } +} From c3c3b02ffb935f16211a58385975f9eba88aea82 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Feb 2023 23:08:33 -0600 Subject: [PATCH 0193/1891] chore: set debug=0 for release (#152) Fixes #110 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1383cf9e1..d411b3f29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ tempfile = "3.3.0" test-log = "0.2" [profile.release] -debug = 1 # show line numbers in backtrace +debug = 0 [profile.release-fast] inherits = "release" From 8d5e945ccbf538bd4ac247382dfaf718ee5d2511 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 06:58:47 -0600 Subject: [PATCH 0194/1891] chore: added self-update feature (#153) This will allow me to only enable self-update when building non-package manager CLIs --- .bin/rtx | 2 +- .github/workflows/rtx.yml | 4 ++-- Cargo.toml | 2 +- src/build_time.rs | 16 ++++++++-------- src/cli/mod.rs | 6 +++++- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index 2acb2e01f..36a087b2c 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -5,4 +5,4 @@ set -e # when chims are called in shebangs SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -cargo run --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" +cargo run --all-features --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 4d7e47a8a..078cf0f0a 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -84,7 +84,7 @@ jobs: with: use-cross: true command: build - args: --release --target ${{matrix.target}} + args: --release --all-features --target ${{matrix.target}} - run: scripts/build-tarball.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 with: @@ -113,7 +113,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: { key: "${{matrix.target}}" } - - run: cargo build --release --target ${{matrix.target}} + - run: cargo build --release --all-features --target ${{matrix.target}} - run: scripts/build-tarball.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 with: diff --git a/Cargo.toml b/Cargo.toml index d411b3f29..b47a3f03a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ rayon = "1.6.1" regex = "1.7.1" reqwest = { version = "0.11.14", features = ["blocking"] } rmp-serde = "1.1.1" -self_update = "0.35.0" +self_update = { version = "0.35.0", optional = true } serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.92" diff --git a/src/build_time.rs b/src/build_time.rs index 66c5d4af2..067bd7808 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -2,7 +2,7 @@ use crate::env::RTX_HIDE_OUTDATED_BUILD; use build_time::build_time_utc; use chrono::{DateTime, FixedOffset, Months, Utc}; use console::style; -use indoc::eprintdoc; + use lazy_static::lazy_static; lazy_static! { @@ -15,13 +15,13 @@ fn init() { if !*RTX_HIDE_OUTDATED_BUILD && BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() { - eprintdoc!( - " - {rtx} rtx has not been updated in over a year. - {rtx} Please update to the latest version, update with: `rtx self-update` - {rtx} To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1. - ", - rtx = style("rtx").dim().for_stderr() + let rtx = style("rtx").dim().for_stderr(); + eprintln!( + "{rtx} rtx has not been updated in over a year. Please update to the latest version" ); + if cfg!(feature = "self_update") { + eprintln!("{rtx} update with: `rtx self-update`"); + } + eprintln!("{rtx} To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1."); } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 25c44b182..b08212540 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -32,7 +32,6 @@ mod local; mod ls; mod ls_remote; mod plugins; -mod self_update; mod settings; mod uninstall; pub mod version; @@ -42,6 +41,9 @@ mod r#where; #[cfg(debug_assertions)] mod render_help; +#[cfg(feature = "self_update")] +mod self_update; + pub struct Cli { command: clap::Command, external_commands: Vec, @@ -68,6 +70,7 @@ pub enum Commands { Ls(ls::Ls), LsRemote(ls_remote::LsRemote), Plugins(plugins::Plugins), + #[cfg(feature = "self_update")] SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Uninstall(uninstall::Uninstall), @@ -100,6 +103,7 @@ impl Commands { Self::Ls(cmd) => cmd.run(config, out), Self::LsRemote(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), + #[cfg(feature = "self_update")] Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), From a94b8c35a520854442b9b9f6ae193bf60c6c91ce Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 07:04:42 -0600 Subject: [PATCH 0195/1891] feat: added `rtx activate --status` (#155) This changes the behavior of activate to default to not displaying the status line. Fixes #154 --- README.md | 4 ++-- completions/_rtx | 6 ++++-- completions/rtx.bash | 4 ++-- completions/rtx.fish | 4 +++- e2e/cd/test_bash | 2 +- e2e/cd/test_bash_legacy_activate | 2 +- e2e/cd/test_zsh | 2 +- e2e/direnv/no_tool_versions/test_direnv | 2 +- .../system_version/test_direnv_system_version | 2 +- src/cli/activate.rs | 17 +++++++---------- src/cli/hook_env.rs | 10 ++++++++-- src/hook_env.rs | 7 ------- src/shell/bash.rs | 9 ++++++--- src/shell/fish.rs | 13 ++++++++----- src/shell/mod.rs | 2 +- .../rtx__shell__bash__tests__hook_init.snap | 4 ++-- .../rtx__shell__fish__tests__hook_init.snap | 8 ++++---- .../rtx__shell__xonsh__tests__hook_init.snap | 4 ++-- .../rtx__shell__zsh__tests__hook_init.snap | 4 ++-- src/shell/xonsh.rs | 10 +++++++--- src/shell/zsh.rs | 9 ++++++--- 21 files changed, 69 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 0b09842f3..9d799cc0e 100644 --- a/README.md +++ b/README.md @@ -547,8 +547,8 @@ Arguments: [possible values: bash, fish, xonsh, zsh] Options: - -q, --quiet - Hide the "rtx: @" message when changing directories + --status + Show "rtx: @" message when changing directories -h, --help Print help (see a summary with '-h') diff --git a/completions/_rtx b/completions/_rtx index 37dd2674a..df39c136c 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -40,8 +40,9 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'-q[Hide the "rtx: @" message when changing directories]' \ -'--quiet[Hide the "rtx: @" message when changing directories]' \ +'--status[Show "rtx: @" message when changing directories]' \ +'-q[noop]' \ +'--quiet[noop]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -370,6 +371,7 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--status[Show "rtx: @" message when changing directories]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index ca2799dc4..c1f7341ee 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -423,7 +423,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -j -v -h --shell --quiet --log-level --jobs --verbose --help bash fish xonsh zsh" + opts="-s -q -j -v -h --shell --status --quiet --log-level --jobs --verbose --help bash fish xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1653,7 +1653,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -v -h --shell --log-level --jobs --verbose --help" + opts="-s -j -v -h --shell --status --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index be5cf8892..d1cb16556 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -32,7 +32,8 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message o complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'Hide the "rtx: @" message when changing directories' +complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' +complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r @@ -135,6 +136,7 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print h complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index eb2b5d19c..786f20ad3 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -5,7 +5,7 @@ set -euo pipefail orig_path="$PATH" # shellcheck disable=SC1090 -eval "$(rtx activate bash)" +eval "$(rtx activate bash --status)" _rtx_hook assert_path() { diff --git a/e2e/cd/test_bash_legacy_activate b/e2e/cd/test_bash_legacy_activate index b9c0d6ff8..9a03ecb37 100755 --- a/e2e/cd/test_bash_legacy_activate +++ b/e2e/cd/test_bash_legacy_activate @@ -3,7 +3,7 @@ set -euo pipefail rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 -eval "$(rtx activate -s bash)" +eval "$(rtx activate -s bash --status)" _rtx_hook #rtx install diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index 083861b08..c2775848f 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -3,7 +3,7 @@ set -euo pipefail rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 -eval "$(rtx activate zsh)" +eval "$(rtx activate zsh --status)" _rtx_hook #rtx install diff --git a/e2e/direnv/no_tool_versions/test_direnv b/e2e/direnv/no_tool_versions/test_direnv index 3bcaf1386..d76115c4b 100755 --- a/e2e/direnv/no_tool_versions/test_direnv +++ b/e2e/direnv/no_tool_versions/test_direnv @@ -3,7 +3,7 @@ set -e eval "$(direnv hook zsh)" -eval "$(rtx activate zsh)" +eval "$(rtx activate zsh --status)" _rtx_hook && direnv allow && _direnv_hook assert_go_version() { diff --git a/e2e/direnv/system_version/test_direnv_system_version b/e2e/direnv/system_version/test_direnv_system_version index 16712d361..be3ca8c90 100755 --- a/e2e/direnv/system_version/test_direnv_system_version +++ b/e2e/direnv/system_version/test_direnv_system_version @@ -3,7 +3,7 @@ set -e eval "$(direnv hook zsh)" -eval "$(rtx activate -s zsh)" +eval "$(rtx activate zsh --status)" _rtx_hook && _direnv_hook # prepare diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 1fdea433b..9762bd2c1 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -26,8 +26,12 @@ pub struct Activate { #[clap()] shell_type: Option, - /// Hide the "rtx: @" message when changing directories - #[clap(long, short)] + /// Show "rtx: @" message when changing directories + #[clap(long)] + status: bool, + + /// noop + #[clap(long, short, hide = true)] quiet: bool, } @@ -36,19 +40,12 @@ impl Command for Activate { let shell = get_shell(self.shell_type.or(self.shell)) .expect("no shell provided, use `--shell=zsh`"); - if self.quiet { - // TODO: it would probably be better to just set --quiet on `hook-env` - // this will cause _all_ rtx commands to be quiet, not just the hook - // however as of this writing I don't think RTX_QUIET impacts other commands - rtxprintln!(out, "{}", shell.set_env("RTX_QUIET", "1")); - } - let exe = if cfg!(test) { "rtx".into() } else { env::RTX_EXE.to_path_buf() }; - let output = shell.activate(&exe); + let output = shell.activate(&exe, self.status); out.stdout.write(output); Ok(()) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 337224fbf..b14992634 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -25,6 +25,10 @@ pub struct HookEnv { /// Shell type to generate script for #[clap(long, short)] shell: Option, + + /// Show "rtx: @" message when changing directories + #[clap(long)] + status: bool, } impl Command for HookEnv { @@ -48,7 +52,9 @@ impl Command for HookEnv { let output = self.build_env_commands(&patches); out.stdout.write(output); - self.display_status(&ts, out); + if self.status { + self.display_status(&ts, out); + } Ok(()) } @@ -167,6 +173,6 @@ mod tests { #[test] fn test_hook_env() { - assert_cli!("hook-env", "-s", "fish"); + assert_cli!("hook-env", "--status", "-s", "fish"); } } diff --git a/src/hook_env.rs b/src/hook_env.rs index 64fdc796e..27af6eac9 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -15,13 +15,6 @@ use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being /// called and it does not need to be pub fn should_exit_early(config: &Config) -> bool { - // TODO: make this not depend on config - // if possible, this should avoid loading the entire config - // all I need is the list of config files to load. - // This will likely require splitting config loading into 2 phases: - // 1. load the config filenames - // 2. parse/load the config files, then runtime versions - if env::ARGS.len() < 2 || env::ARGS[1] != "hook-env" { return false; } diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 23f8eea18..11aaf0900 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -8,9 +8,10 @@ use crate::shell::{is_dir_in_path, Shell}; pub struct Bash {} impl Shell for Bash { - fn activate(&self, exe: &Path) -> String { + fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); let exe = exe.display(); + let status = if status { " --status" } else { "" }; let mut out = String::new(); if !is_dir_in_path(dir) { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); @@ -19,7 +20,7 @@ impl Shell for Bash { _rtx_hook() {{ local previous_exit_status=$?; trap -- '' SIGINT; - eval "$("{exe}" hook-env -s bash)"; + eval "$("{exe}" hook-env{status} -s bash)"; trap - SIGINT; return $previous_exit_status; }}; @@ -56,7 +57,9 @@ mod tests { #[test] fn test_hook_init() { - insta::assert_snapshot!(Bash::default().activate(Path::new("/some/dir/rtx"))); + let bash = Bash::default(); + let exe = Path::new("/some/dir/rtx"); + insta::assert_snapshot!(bash.activate(exe, true)); } #[test] diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 53b0b552d..c163a94fb 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -8,9 +8,10 @@ use crate::shell::{is_dir_in_path, Shell}; pub struct Fish {} impl Shell for Fish { - fn activate(&self, exe: &Path) -> String { + fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); let exe = exe.display(); + let status = if status { " --status" } else { "" }; let description = "'Update rtx environment when changing directories'"; let mut out = String::new(); @@ -22,14 +23,14 @@ impl Shell for Fish { // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_fish.go#L14-L36 out.push_str(&formatdoc! {r#" function __rtx_env_eval --on-event fish_prompt --description {description}; - {exe} hook-env -s fish | source; + {exe} hook-env{status} -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description {description}; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - {exe} hook-env -s fish | source; + {exe} hook-env{status} -s fish | source; end; end; end; @@ -38,7 +39,7 @@ impl Shell for Fish { function __rtx_env_eval_2 --on-event fish_preexec --description {description}; if set -q __rtx_env_again; set -e __rtx_env_again; - {exe} hook-env -s fish | source; + {exe} hook-env{status} -s fish | source; echo; end; @@ -76,7 +77,9 @@ mod tests { #[test] fn test_hook_init() { - insta::assert_snapshot!(Fish::default().activate(Path::new("/some/dir/rtx"))); + let fish = Fish::default(); + let exe = Path::new("/some/dir/rtx"); + insta::assert_snapshot!(fish.activate(exe, true)); } #[test] diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 5afab5061..803c0aaf3 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -45,7 +45,7 @@ impl Display for ShellType { } pub trait Shell { - fn activate(&self, exe: &Path) -> String; + fn activate(&self, exe: &Path, status: bool) -> String; fn deactivate(&self) -> String; fn set_env(&self, k: &str, v: &str) -> String; fn unset_env(&self, k: &str) -> String; diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 948aded5c..574b1dcff 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -1,12 +1,12 @@ --- source: src/shell/bash.rs -expression: "Bash::default().activate(Path::new(\"/some/dir/rtx\"))" +expression: "bash.activate(exe, true)" --- export PATH="/some/dir:$PATH" _rtx_hook() { local previous_exit_status=$?; trap -- '' SIGINT; - eval "$("/some/dir/rtx" hook-env -s bash)"; + eval "$("/some/dir/rtx" hook-env --status -s bash)"; trap - SIGINT; return $previous_exit_status; }; diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 7d3f51593..1e36ca181 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -1,17 +1,17 @@ --- source: src/shell/fish.rs -expression: "Fish::default().activate(Path::new(\"/some/dir/rtx\"))" +expression: "fish.activate(exe, true)" --- fish_add_path -g /some/dir function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; - /some/dir/rtx hook-env -s fish | source; + /some/dir/rtx hook-env --status -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - /some/dir/rtx hook-env -s fish | source; + /some/dir/rtx hook-env --status -s fish | source; end; end; end; @@ -20,7 +20,7 @@ end; function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; if set -q __rtx_env_again; set -e __rtx_env_again; - /some/dir/rtx hook-env -s fish | source; + /some/dir/rtx hook-env --status -s fish | source; echo; end; diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap index 3b21233f5..d2d7c7a14 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap @@ -1,6 +1,6 @@ --- source: src/shell/xonsh.rs -expression: "Xonsh::default().activate(Path::new(\"/some/dir/rtx\"))" +expression: "xonsh.activate(exe, true)" --- from os import environ from xonsh.built_ins import XSH @@ -10,7 +10,7 @@ envx['PATH'].add('/some/dir') environ['PATH'] = envx.get_detyped('PATH') def listen_prompt(): # Hook Events - execx($(/some/dir/rtx hook-env -s xonsh)) + execx($(/some/dir/rtx hook-env --status -s xonsh)) XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 8e7ca596c..911bb10a5 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -1,11 +1,11 @@ --- source: src/shell/zsh.rs -expression: "Zsh::default().activate(Path::new(\"/some/dir/rtx\"))" +expression: "zsh.activate(exe, true)" --- export PATH="/some/dir:$PATH" _rtx_hook() { trap -- '' SIGINT; - eval "$("/some/dir/rtx" hook-env -s zsh)"; + eval "$("/some/dir/rtx" hook-env --status -s zsh)"; trap - SIGINT; } typeset -ag precmd_functions; diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 9db78ae28..717c3d3b9 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -8,6 +8,7 @@ use crate::shell::{is_dir_in_path, Shell}; pub struct Xonsh {} use std::borrow::Cow; + fn xonsh_escape_sq(input: &str) -> Cow { for (i, ch) in input.chars().enumerate() { if xonsh_escape_char(ch).is_some() { @@ -37,9 +38,10 @@ fn xonsh_escape_char(ch: char) -> Option<&'static str> { } impl Shell for Xonsh { - fn activate(&self, exe: &Path) -> String { + fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); let exe = exe.display(); + let status = if status { " --status" } else { "" }; let mut out = String::new(); // todo: xonsh doesn't update the environment that rtx relies on with $PATH.add even with $UPDATE_OS_ENVIRON (github.com/xonsh/xonsh/issues/3207) @@ -64,7 +66,7 @@ impl Shell for Xonsh { // todo: subprocess instead of $() is a bit faster, but lose auto-color detection (use $FORCE_COLOR) out.push_str(&formatdoc! {r#" def listen_prompt(): # Hook Events - execx($({exe} hook-env -s xonsh)) + execx($({exe} hook-env{status} -s xonsh)) XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt "#}); @@ -127,7 +129,9 @@ mod tests { #[test] fn test_hook_init() { - insta::assert_snapshot!(Xonsh::default().activate(Path::new("/some/dir/rtx"))); + let xonsh = Xonsh::default(); + let exe = Path::new("/some/dir/rtx"); + insta::assert_snapshot!(xonsh.activate(exe, true)); } #[test] diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 8af76655a..996f99ebd 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -9,9 +9,10 @@ use crate::shell::{is_dir_in_path, Shell}; pub struct Zsh {} impl Shell for Zsh { - fn activate(&self, exe: &Path) -> String { + fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); let exe = exe.display(); + let status = if status { " --status" } else { "" }; let mut out = String::new(); // much of this is from direnv @@ -22,7 +23,7 @@ impl Shell for Zsh { out.push_str(&formatdoc! {r#" _rtx_hook() {{ trap -- '' SIGINT; - eval "$("{exe}" hook-env -s zsh)"; + eval "$("{exe}" hook-env{status} -s zsh)"; trap - SIGINT; }} typeset -ag precmd_functions; @@ -59,7 +60,9 @@ mod tests { #[test] fn test_hook_init() { - insta::assert_snapshot!(Zsh::default().activate(Path::new("/some/dir/rtx"))); + let zsh = Zsh::default(); + let exe = Path::new("/some/dir/rtx"); + insta::assert_snapshot!(zsh.activate(exe, true)); } #[test] From acade304c9a557db443d197f18e0277bab518cfb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 07:08:13 -0600 Subject: [PATCH 0196/1891] chore: Release rtx-cli version 1.12.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f407e217..5ea356d02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1378,7 +1378,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.11.1" +version = "1.12.0" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index b47a3f03a..e4330382e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.11.1" +version = "1.12.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 9d799cc0e..21547d256 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.11.1 +rtx 1.12.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -202,7 +202,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.1/rtx-v1.11.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.0/rtx-v1.12.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 7cc41b812..261b69d63 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.11.1 +Version: 1.12.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index d91651df8..d2a2c9462 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -221,7 +221,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.11.1/rtx-v1.11.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.0/rtx-v1.12.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From e9fa8da38c5975abee612d528da0f92272ddc4e2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 07:22:09 -0600 Subject: [PATCH 0197/1891] explain how to update when showing out-of-date message on `rtx version` --- src/cli/version.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index 0dcd6ece8..06296ffbb 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Result; +use console::style; use once_cell::sync::Lazy; use std::string::ToString; use std::time::Duration; @@ -61,7 +62,11 @@ fn show_version(out: &mut Output) { fn show_latest() { if let Some(latest) = check_for_new_version() { - warn!("rtx version {} available", latest) + warn!("rtx version {} available", latest); + if cfg!(feature = "self_update") { + let cmd = style("rtx self-update").bright().yellow().for_stderr(); + warn!("To update, run {}", cmd); + } } } From 1846f8668490fef37a9caf922f93caac3d930ab2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 07:30:19 -0600 Subject: [PATCH 0198/1891] chore: fix amd64 URLs --- scripts/publish-s3.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 370246d65..382b0b025 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -8,8 +8,8 @@ cache_week="max-age=604800,s-maxage=604800,public,immutable" ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh echo "$RTX_VERSION" | tr -d 'v' > "$RELEASE_DIR"/VERSION -cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-$RTX_VERSION-linux-amd64" -cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-$RTX_VERSION-macos-amd64" +cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-latest-linux-amd64" +cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-latest-macos-amd64" aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" \ From 17fafecb32352a81b457ae410601e5a7573204f8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 07:30:30 -0600 Subject: [PATCH 0199/1891] chore: Release rtx-cli version 1.12.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ea356d02..5e4fa1dee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1378,7 +1378,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.12.0" +version = "1.12.1" dependencies = [ "atty", "base64", diff --git a/Cargo.toml b/Cargo.toml index e4330382e..d05d317c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.12.0" +version = "1.12.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 21547d256..80db006e2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.12.0 +rtx 1.12.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -202,7 +202,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.0/rtx-v1.12.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.1/rtx-v1.12.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 261b69d63..b64de3eee 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.12.0 +Version: 1.12.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index d2a2c9462..982e465e9 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -221,7 +221,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.0/rtx-v1.12.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.1/rtx-v1.12.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 4d6c36356a13523340c3d644c284e3f8c136de0e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 09:16:19 -0600 Subject: [PATCH 0200/1891] bug: use dirs_next::cache_dir() to find cache dir This changes the cache location to ~/Library/Caches/rtx on macOS --- src/env.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/env.rs b/src/env.rs index c9cae1f20..9043cf67e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -23,9 +23,7 @@ lazy_static! { pub static ref XDG_CACHE_HOME: PathBuf = if cfg!(test) { HOME.join("cache") } else { - var_os("XDG_CACHE_HOME") - .map(PathBuf::from) - .unwrap_or_else(|| HOME.join(".cache")) + dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache")) }; pub static ref XDG_DATA_HOME: PathBuf = if cfg!(test) { HOME.join("data") From e11fcda8a927182dbe3be200601b02b5683ee336 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 09:32:14 -0600 Subject: [PATCH 0201/1891] bug: do not hide `rtx where` I am not sure why this was hidden --- README.md | 29 +++++++++++++++++++++++++++++ src/cli/where.rs | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 80db006e2..afd1436da 100644 --- a/README.md +++ b/README.md @@ -1297,6 +1297,35 @@ Options: -h, --help Print help +``` +### `rtx where` + +``` +Display the installation path for a runtime + +Must be installed. + +Usage: where + +Arguments: + + runtime(s) to look up if "@" is specified, it will show the latest installed version that matches the prefix otherwise, it will show the current, active installed version + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + # Show the latest installed version of nodejs + # If it is is not installed, errors + $ rtx where nodejs@20 + /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + + # Show the current, active install directory of nodejs + # Errors if nodejs is not referenced in any .tool-version file + $ rtx where nodejs + /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + ``` ## Comparison to asdf diff --git a/src/cli/where.rs b/src/cli/where.rs index cbaf014c6..061405b18 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -15,7 +15,7 @@ use crate::ui::color::Color; /// /// Must be installed. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), hide = true)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Where { /// runtime(s) to look up /// if "@" is specified, it will show the latest installed version that matches the prefix From 58041d03d6ac6ec95f303897a3864e00106c07be Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 09:47:19 -0600 Subject: [PATCH 0202/1891] feat: added `rtx implode` (#156) Fixes #147 --- README.md | 20 ++++++++++++++ completions/_rtx | 29 ++++++++++++++++++++ completions/rtx.bash | 50 ++++++++++++++++++++++++++++++++-- completions/rtx.fish | 60 +++++++++++++++++++++++------------------ e2e/.gitignore | 1 + src/cli/implode.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/cli/mod.rs | 3 +++ 7 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 src/cli/implode.rs diff --git a/README.md b/README.md index afd1436da..50c7c2b01 100644 --- a/README.md +++ b/README.md @@ -837,6 +837,26 @@ Examples: $ rtx global nodejs 20.0.0 +``` +### `rtx implode` + +``` +removes rtx CLI and all generated data + +skips config directory by default + +Usage: implode [OPTIONS] + +Options: + --config + also remove config directory + + --dry-run + list directories that would be removed without actually removing them + + -h, --help + Print help (see a summary with '-h') + ``` ### `rtx install` diff --git a/completions/_rtx b/completions/_rtx index df39c136c..53335c043 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -378,6 +378,19 @@ _arguments "${_arguments_options[@]}" \ '--help[Print help]' \ && ret=0 ;; +(implode) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--config[also remove config directory]' \ +'--dry-run[list directories that would be removed without actually removing them]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; (install) _arguments "${_arguments_options[@]}" \ '()*-p+[only install runtime(s) for ]:PLUGIN: ' \ @@ -879,6 +892,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(implode) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (install) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1020,6 +1037,7 @@ _rtx_commands() { 'global:sets global .tool-versions to include a specified runtime' \ 'g:sets global .tool-versions to include a specified runtime' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ +'implode:removes rtx CLI and all generated data' \ 'install:install a runtime' \ 'i:install a runtime' \ 'latest:get the latest runtime version of a plugin'\''s runtimes' \ @@ -1328,6 +1346,7 @@ _rtx__help_commands() { 'exec:execute a command with runtime(s) set' \ 'global:sets global .tool-versions to include a specified runtime' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ +'implode:removes rtx CLI and all generated data' \ 'install:install a runtime' \ 'latest:get the latest runtime version of a plugin'\''s runtimes' \ 'local:Sets .tool-versions to include a specific runtime' \ @@ -1392,6 +1411,16 @@ _rtx__hook-env_commands() { local commands; commands=() _describe -t commands 'rtx hook-env commands' commands "$@" } +(( $+functions[_rtx__help__implode_commands] )) || +_rtx__help__implode_commands() { + local commands; commands=() + _describe -t commands 'rtx help implode commands' commands "$@" +} +(( $+functions[_rtx__implode_commands] )) || +_rtx__implode_commands() { + local commands; commands=() + _describe -t commands 'rtx implode commands' commands "$@" +} (( $+functions[_rtx__help__install_commands] )) || _rtx__help__install_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index c1f7341ee..4b6ae5ffb 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -66,6 +66,9 @@ _rtx() { rtx,i) cmd="rtx__install" ;; + rtx,implode) + cmd="rtx__implode" + ;; rtx,install) cmd="rtx__install" ;; @@ -213,6 +216,9 @@ _rtx() { rtx__help,hook-env) cmd="rtx__help__hook__env" ;; + rtx__help,implode) + cmd="rtx__help__implode" + ;; rtx__help,install) cmd="rtx__help__install" ;; @@ -397,7 +403,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1079,7 +1085,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" + opts="activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1358,6 +1364,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__implode) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__install) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -1686,6 +1706,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__implode) + opts="-j -v -h --config --dry-run --log-level --jobs --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__install) opts="-p -f -a -v -j -h --plugin --force --all --verbose --log-level --jobs --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index d1cb16556..9eb0dab9d 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -16,6 +16,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'exports env vars to a complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'execute a command with runtime(s) set' complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'removes rtx CLI and all generated data' complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'install a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' @@ -139,6 +140,12 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Numbe complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'also remove config directory' +complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'list directories that would be removed without actually removing them' +complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r @@ -263,32 +270,33 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' diff --git a/e2e/.gitignore b/e2e/.gitignore index bf6b6fd37..b92473d37 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,3 +1,4 @@ .local .rtx .cache +Library diff --git a/src/cli/implode.rs b/src/cli/implode.rs new file mode 100644 index 000000000..626ce5e63 --- /dev/null +++ b/src/cli/implode.rs @@ -0,0 +1,64 @@ +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; + +use crate::output::Output; + +use crate::{dirs, env}; + +/// removes rtx CLI and all generated data +/// +/// skips config directory by default +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct Implode { + /// also remove config directory + #[clap(long, verbatim_doc_comment)] + config: bool, + + /// list directories that would be removed without actually removing them + #[clap(long, verbatim_doc_comment)] + dry_run: bool, +} + +impl Command for Implode { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let mut files = vec![&*dirs::ROOT, &*dirs::CACHE, &*env::RTX_EXE]; + if self.config { + files.push(&*dirs::CONFIG); + } + for f in files.into_iter().filter(|d| d.exists()) { + if f.is_dir() { + rtxprintln!(out, "rm -rf {}", f.display()); + if !self.dry_run { + std::fs::remove_dir_all(f)?; + } + } else { + rtxprintln!(out, "rm -f {}", f.display()); + if !self.dry_run { + std::fs::remove_file(f)?; + } + } + } + + Ok(()) + } +} + +#[cfg(test)] +#[cfg(test)] +mod tests { + + use crate::assert_cli; + use crate::{dirs, env}; + + #[test] + fn test_implode() { + let stdout = assert_cli!("implode", "--config", "--dry-run"); + assert!(stdout.contains(format!("rm -rf {}", dirs::ROOT.display()).as_str())); + assert!(stdout.contains(format!("rm -rf {}", dirs::CACHE.display()).as_str())); + assert!(stdout.contains(format!("rm -rf {}", dirs::CONFIG.display()).as_str())); + assert!(stdout.contains(format!("rm -f {}", env::RTX_EXE.display()).as_str())); + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b08212540..1edd578be 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -26,6 +26,7 @@ mod exec; mod external; mod global; mod hook_env; +mod implode; mod install; mod latest; mod local; @@ -64,6 +65,7 @@ pub enum Commands { Exec(exec::Exec), Global(global::Global), HookEnv(hook_env::HookEnv), + Implode(implode::Implode), Install(install::Install), Latest(latest::Latest), Local(local::Local), @@ -97,6 +99,7 @@ impl Commands { Self::Exec(cmd) => cmd.run(config, out), Self::Global(cmd) => cmd.run(config, out), Self::HookEnv(cmd) => cmd.run(config, out), + Self::Implode(cmd) => cmd.run(config, out), Self::Install(cmd) => cmd.run(config, out), Self::Latest(cmd) => cmd.run(config, out), Self::Local(cmd) => cmd.run(config, out), From 948205ff7b01c288e95ef30fe5778e933af9015d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:32:38 -0600 Subject: [PATCH 0203/1891] docs: clarified cache directory --- README.md | 16 ++++++++++------ src/cli/render_help.rs | 16 ++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 50c7c2b01..412728ad8 100644 --- a/README.md +++ b/README.md @@ -396,15 +396,19 @@ rtx can also be configured via environment variables. The following options are This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. -#### `RTX_DATA_DIR` - -This is the directory where rtx stores its data. The default is `~/.local/share/rtx`. - ```sh-session $ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@20 $ RTX_NODEJS_VERSION=20 rtx exec -- node --version ``` +#### `RTX_DATA_DIR` + +This is the directory where rtx stores its data. The default is `~/.local/share/rtx`. + +#### `RTX_CACHE_DIR` + +This is the directory where rtx stores cache. The default is `~/.cache/rtx` on Linux and `~/Library/Caches/rtx` on macOS. + #### `RTX_CONFIG_FILE` This is the path to the config file. The default is `~/.config/rtx/config.toml`. @@ -1498,7 +1502,7 @@ to be updating, this is a good place to start. ### Plugin Cache -Each plugin has a cache that's stored in `~/.cache/rtx/plugins/`. It stores +Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/plugins/`. It stores the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), the list of aliases, and the bin directories within each runtime installation. @@ -1506,7 +1510,7 @@ Remote versions are updated daily by default or anytime that `rtx ls-remote` is zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/.cache/rtx/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode +cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` ### Legacy File Cache diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 982e465e9..e69123a80 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -415,15 +415,19 @@ rtx can also be configured via environment variables. The following options are This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. -#### `RTX_DATA_DIR` - -This is the directory where rtx stores its data. The default is `~/.local/share/rtx`. - ```sh-session $ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@20 $ RTX_NODEJS_VERSION=20 rtx exec -- node --version ``` +#### `RTX_DATA_DIR` + +This is the directory where rtx stores its data. The default is `~/.local/share/rtx`. + +#### `RTX_CACHE_DIR` + +This is the directory where rtx stores cache. The default is `~/.cache/rtx` on Linux and `~/Library/Caches/rtx` on macOS. + #### `RTX_CONFIG_FILE` This is the path to the config file. The default is `~/.config/rtx/config.toml`. @@ -723,7 +727,7 @@ to be updating, this is a good place to start. ### Plugin Cache -Each plugin has a cache that's stored in `~/.cache/rtx/plugins/`. It stores +Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/plugins/`. It stores the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), the list of aliases, and the bin directories within each runtime installation. @@ -731,7 +735,7 @@ Remote versions are updated daily by default or anytime that `rtx ls-remote` is zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/.cache/rtx/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode +cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` ### Legacy File Cache From aa793a89713b755979cd1858ffd9059aa8df8d00 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 18:04:41 -0600 Subject: [PATCH 0204/1891] feat: `rtx ls-remote` prefix support (#157) Fixes #113 --- README.md | 17 +++++- completions/_rtx | 3 +- completions/rtx.bash | 2 +- src/cli/ls_remote.rs | 60 ++++++++++++++----- src/cli/mod.rs | 10 ++++ src/cli/plugins/ls_remote.rs | 2 - ...x__cli__ls_remote__tests__list_remote.snap | 8 +++ ..._ls_remote__tests__ls_remote_prefix-2.snap | 6 ++ ...i__ls_remote__tests__ls_remote_prefix.snap | 7 +++ 9 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap create mode 100644 src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap create mode 100644 src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap diff --git a/README.md b/README.md index 412728ad8..18d71c27a 100644 --- a/README.md +++ b/README.md @@ -1020,21 +1020,32 @@ list runtime versions available for install note that these versions are cached for commands like `rtx install nodejs@latest` however _this_ command will always clear that cache and fetch the latest remote versions -Usage: ls-remote +Usage: ls-remote [PREFIX] Arguments: - Plugin + plugin to get versions for + + [PREFIX] + the version prefix to use when querying the latest version same as the first argument after the "@" Options: -h, --help Print help (see a summary with '-h') Examples: - $ rtx list-remote nodejs + $ rtx ls-remote nodejs 18.0.0 20.0.0 + $ rtx ls-remote nodejs@18 + 18.0.0 + 18.1.0 + + $ rtx ls-remote nodejs 18 + 18.0.0 + 18.1.0 + ``` ### `rtx plugins install` diff --git a/completions/_rtx b/completions/_rtx index 53335c043..575e06ef1 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -466,7 +466,8 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- Plugin:' \ +':plugin -- plugin to get versions for:' \ +'::prefix -- the version prefix to use when querying the latest version same as the first argument after the "@":' \ && ret=0 ;; (plugins) diff --git a/completions/rtx.bash b/completions/rtx.bash index 4b6ae5ffb..d1ef2dbbf 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1857,7 +1857,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -v -h --log-level --jobs --verbose --help [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 8fb5f9c06..7df47578c 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,5 +1,6 @@ -use atty::Stream; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,7 +8,6 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::ui::color::Color; /// list runtime versions available for install /// @@ -16,19 +16,37 @@ use crate::ui::color::Color; #[derive(Debug, clap::Args)] #[clap(visible_alias = "list-remote", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), alias = "list-all")] pub struct LsRemote { - /// Plugin + /// plugin to get versions for + #[clap(value_parser = RuntimeArgParser)] + plugin: RuntimeArg, + + /// the version prefix to use when querying the latest version + /// same as the first argument after the "@" #[clap()] - plugin: String, + prefix: Option, } impl Command for LsRemote { fn run(self, config: Config, out: &mut Output) -> Result<()> { let plugin = config .plugins - .get(&self.plugin) - .ok_or(PluginNotInstalled(self.plugin))?; + .get(&self.plugin.plugin) + .ok_or(PluginNotInstalled(self.plugin.plugin))?; plugin.clear_remote_version_cache()?; - let versions = plugin.list_remote_versions(&config.settings)?; + + let prefix = match self.plugin.version { + RuntimeArgVersion::Version(v) => Some(v), + _ => self.prefix, + }; + + let versions = plugin.list_remote_versions(&config.settings)?.clone(); + let versions = match prefix { + Some(prefix) => versions + .into_iter() + .filter(|v| v.starts_with(&prefix)) + .collect(), + None => versions, + }; for version in versions { rtxprintln!(out, "{}", version); @@ -38,25 +56,37 @@ impl Command for LsRemote { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx list-remote nodejs + $ rtx ls-remote nodejs 18.0.0 20.0.0 - "#, COLOR.header("Examples:")} + + $ rtx ls-remote nodejs@18 + 18.0.0 + 18.1.0 + + $ rtx ls-remote nodejs 18 + 18.0.0 + 18.1.0 + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] mod tests { - use crate::assert_cli; - use crate::cli::tests::ensure_plugin_installed; + use insta::assert_snapshot; + + use crate::assert_cli_snapshot; #[test] fn test_list_remote() { - ensure_plugin_installed("nodejs"); - let stdout = assert_cli!("list-remote", "nodejs"); - assert!(stdout.contains("18.0.0")); + assert_cli_snapshot!("list-remote", "dummy"); + } + + #[test] + fn test_ls_remote_prefix() { + assert_cli_snapshot!("list-remote", "dummy", "1"); + assert_cli_snapshot!("list-remote", "dummy@2"); } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1edd578be..607e92a98 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -237,6 +237,16 @@ pub mod tests { }}; } + #[macro_export] + macro_rules! assert_cli_snapshot { + ($($args:expr),+) => {{ + let args = &vec!["rtx".into(), $($args.into()),+]; + let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; + let output = console::strip_ansi_codes(&output).to_string(); + assert_snapshot!(output); + }}; + } + #[macro_export] macro_rules! assert_cli_err { ($($args:expr),+) => {{ diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index f8030ab58..ffed9abc2 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -56,11 +56,9 @@ Examples: #[cfg(test)] mod tests { use crate::assert_cli; - use crate::cli::tests::ensure_plugin_installed; #[test] fn test_plugin_list_remote() { - ensure_plugin_installed("nodejs"); let stdout = assert_cli!("plugin", "ls-remote"); assert!(stdout.contains("nodejs")); } diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap b/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap new file mode 100644 index 000000000..abe0b70dc --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap @@ -0,0 +1,8 @@ +--- +source: src/cli/ls_remote.rs +expression: stdout +--- +1.0.0 +1.1.0 +2.0.0 + diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap new file mode 100644 index 000000000..3dfc8868a --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/ls_remote.rs +expression: output +--- +2.0.0 + diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap new file mode 100644 index 000000000..1e1f6c111 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/ls_remote.rs +expression: output +--- +1.0.0 +1.1.0 + From fbdfbb3c0ffcadf59821978496fc56c0318b28b1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 18:35:07 -0600 Subject: [PATCH 0205/1891] chore: consolidate color utilities (#158) moves the rest of the code over to console::style --- Cargo.lock | 44 ++---------------------------------- Cargo.toml | 3 +-- src/cli/activate.rs | 6 ++--- src/cli/alias/ls.rs | 6 ++--- src/cli/cache/mod.rs | 3 ++- src/cli/command.rs | 2 +- src/cli/complete.rs | 18 +++++++-------- src/cli/current.rs | 10 ++++---- src/cli/deactivate.rs | 6 ++--- src/cli/direnv/activate.rs | 7 +++--- src/cli/doctor.rs | 6 ++--- src/cli/env.rs | 9 ++++---- src/cli/exec.rs | 9 ++++---- src/cli/global.rs | 6 ++--- src/cli/implode.rs | 3 --- src/cli/install.rs | 14 +++++------- src/cli/latest.rs | 6 +---- src/cli/local.rs | 7 ++---- src/cli/ls_remote.rs | 2 +- src/cli/mod.rs | 7 ++---- src/cli/plugins/install.rs | 6 ++--- src/cli/plugins/ls.rs | 6 ++--- src/cli/plugins/uninstall.rs | 14 ++++-------- src/cli/plugins/update.rs | 3 ++- src/cli/settings/get.rs | 6 ++--- src/cli/settings/ls.rs | 7 ++---- src/cli/settings/set.rs | 7 ++---- src/cli/settings/unset.rs | 9 +++----- src/cli/uninstall.rs | 5 ++-- src/cli/version.rs | 5 ++-- src/cli/where.rs | 6 ++--- src/output.rs | 8 +------ src/ui/color.rs | 25 -------------------- src/ui/mod.rs | 1 - 34 files changed, 78 insertions(+), 204 deletions(-) delete mode 100644 src/ui/color.rs diff --git a/Cargo.lock b/Cargo.lock index 5e4fa1dee..93b763817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,17 +35,6 @@ dependencies = [ "libc", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -626,15 +615,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -845,12 +825,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "is_ci" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" - [[package]] name = "itertools" version = "0.10.5" @@ -1146,9 +1120,6 @@ name = "owo-colors" version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" -dependencies = [ - "supports-color", -] [[package]] name = "paste" @@ -1380,7 +1351,6 @@ dependencies = [ name = "rtx-cli" version = "1.12.1" dependencies = [ - "atty", "base64", "build-time", "chrono", @@ -1613,9 +1583,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -1636,16 +1606,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "supports-color" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba6faf2ca7ee42fdd458f4347ae0a9bd6bcc445ad7cb57ad82b383f18870d6f" -dependencies = [ - "atty", - "is_ci", -] - [[package]] name = "syn" version = "1.0.107" diff --git a/Cargo.toml b/Cargo.toml index d05d317c8..efbf93ec7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ path = "src/main.rs" #harness = false [dependencies] -atty = "0.2.14" base64 = "0.21.0" build-time = "0.1.2" chrono = "0.4.23" @@ -47,7 +46,7 @@ log = "0.4.17" num_cpus = "1.15.0" once_cell = "1.17.0" openssl = { version = "0.10", features = ["vendored"] } -owo-colors = { version = "3.5.0", features = ["supports-colors"] } +owo-colors = { version = "3.5.0" } rayon = "1.6.1" regex = "1.7.1" reqwest = { version = "0.11.14", features = ["blocking"] } diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 9762bd2c1..c1447cc71 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -8,7 +8,6 @@ use crate::config::Config; use crate::env; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -use crate::ui::color::Color; /// Enables rtx to automatically modify runtimes when changing directory /// @@ -52,7 +51,6 @@ impl Command for Activate { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -60,7 +58,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ eval "$(rtx activate zsh)" $ rtx activate fish | source $ execx($(rtx activate xonsh)) - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 8ecb63e2b..96898ec6b 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,7 +7,6 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::PluginName; -use crate::ui::color::Color; /// List aliases /// Shows the aliases that can be specified. @@ -42,13 +41,12 @@ impl Command for AliasLs { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx aliases nodejs lts/hydrogen 18.0.0 - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 9fe9d547d..c10512e82 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -46,9 +46,10 @@ impl Command for Cache { #[cfg(test)] mod tests { + use pretty_assertions::assert_str_eq; + use crate::assert_cli; use crate::env; - use pretty_assertions::assert_str_eq; #[test] fn test_cache() { diff --git a/src/cli/command.rs b/src/cli/command.rs index 8d65e05e1..4790ecc5a 100644 --- a/src/cli/command.rs +++ b/src/cli/command.rs @@ -1,6 +1,6 @@ -use crate::config::Config; use color_eyre::eyre::Result; +use crate::config::Config; use crate::output::Output; /// described a CLI command diff --git a/src/cli/complete.rs b/src/cli/complete.rs index f58f401d3..8b611a0a4 100644 --- a/src/cli/complete.rs +++ b/src/cli/complete.rs @@ -1,17 +1,16 @@ -use atty::Stream; -use color_eyre::eyre::Result; use std::io::Cursor; -use crate::cli::command::Command; -use crate::config::Config; -use crate::output::Output; - -use crate::cli::Cli; -use crate::ui::color::Color; use clap_complete::generate; +use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; +use crate::cli::command::Command; +use crate::cli::Cli; +use crate::config::Config; +use crate::output::Output; + /// generate shell completions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] @@ -31,12 +30,11 @@ impl Command for Complete { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx complete - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); // #[cfg(test)] diff --git a/src/cli/current.rs b/src/cli/current.rs index 185ac657e..9649cd4b1 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -9,8 +9,6 @@ use crate::output::Output; use crate::plugins::Plugin; use crate::toolset::{Toolset, ToolsetBuilder}; -use crate::ui::color::Color; - /// Shows currently active, and installed runtime versions /// /// This is similar to `rtx list --current`, but this @@ -96,7 +94,6 @@ impl Current { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -113,14 +110,15 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # can output multiple versions $ rtx current python 3.11.0 3.10.0 - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] mod tests { + use std::env; + use insta::assert_snapshot; use pretty_assertions::assert_str_eq; - use std::env; use crate::assert_cli; use crate::cli::tests::grep; diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 21dc142df..f5bf7ba29 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,7 +7,6 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -use crate::ui::color::Color; /// disable rtx for current shell session /// @@ -37,7 +36,6 @@ impl Command for Deactivate { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -45,7 +43,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ eval "$(rtx deactivate zsh)" $ rtx deactivate fish | source $ execx($(rtx deactivate xonsh)) - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index fdfa6baef..4c958f62d 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,4 +1,5 @@ -use atty::Stream; +use console::style; + use color_eyre::eyre::Result; use indoc::{formatdoc, indoc}; use once_cell::sync::Lazy; @@ -6,7 +7,6 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; /// Output direnv function to use rtx inside direnv /// @@ -36,12 +36,11 @@ impl Command for DirenvActivate { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh $ echo 'use rtx' > .envrc $ direnv allow - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index afdf9ca95..ba45b547f 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::{eyre, Result}; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -8,7 +8,6 @@ use crate::cli::command::Command; use crate::config::Config; use crate::env; use crate::output::Output; -use crate::ui::color::Color; /// Check rtx installation for possible problems. #[derive(Debug, clap::Args)] @@ -51,13 +50,12 @@ impl Command for Doctor { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx doctor [WARN] plugin nodejs is not installed - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/env.rs b/src/cli/env.rs index db510a1cf..03c26e484 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -9,7 +9,6 @@ use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; use crate::toolset::ToolsetBuilder; -use crate::ui::color::Color; /// exports env vars to activate rtx in a single shell session /// @@ -50,7 +49,6 @@ impl Command for Env { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -58,17 +56,18 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ eval "$(rtx env -s zsh)" $ rtx env -s fish | source $ execx($(rtx env -s xonsh)) - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] mod tests { use std::env; + use pretty_assertions::assert_str_eq; + use crate::assert_cli; use crate::cli::tests::grep; use crate::dirs; - use pretty_assertions::assert_str_eq; #[test] fn test_env() { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 6cdaf1b5c..85d0163ea 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -1,7 +1,7 @@ -use atty::Stream; use std::ffi::{OsStr, OsString}; use color_eyre::eyre::{eyre, Result}; +use console::style; use duct::IntoExecutablePath; use indexmap::IndexMap; use indoc::formatdoc; @@ -16,7 +16,6 @@ use crate::config::Config; use crate::env; use crate::output::Output; use crate::toolset::ToolsetBuilder; -use crate::ui::color::Color; /// execute a command with runtime(s) set /// @@ -112,7 +111,6 @@ fn parse_command( } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -121,14 +119,15 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # Specify command as a string: rtx exec nodejs@20 python@3.11 --command "node -v && python -V" - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] mod tests { + use test_log::test; + use crate::assert_cli; use crate::cli::tests::cli_run; - use test_log::test; #[test] fn test_exec_ok() { diff --git a/src/cli/global.rs b/src/cli/global.rs index 17de92d8e..7dcd3a106 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -8,7 +8,6 @@ use crate::cli::command::Command; use crate::config::{config_file, Config}; use crate::output::Output; use crate::plugins::PluginName; -use crate::ui::color::Color; use crate::{dirs, env}; /// sets global .tool-versions to include a specified runtime @@ -73,7 +72,6 @@ impl Command for Global { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -88,7 +86,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # show the current version of nodejs in ~/.tool-versions $ rtx global nodejs 20.0.0 - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 626ce5e63..7dc7a68bb 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -2,9 +2,7 @@ use color_eyre::eyre::Result; use crate::cli::command::Command; use crate::config::Config; - use crate::output::Output; - use crate::{dirs, env}; /// removes rtx CLI and all generated data @@ -49,7 +47,6 @@ impl Command for Implode { #[cfg(test)] #[cfg(test)] mod tests { - use crate::assert_cli; use crate::{dirs, env}; diff --git a/src/cli/install.rs b/src/cli/install.rs index 0e2359f49..80c9ce661 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,8 +1,9 @@ +use std::collections::HashSet; + use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; -use owo_colors::Stream; -use std::collections::HashSet; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -10,11 +11,8 @@ use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; - use crate::plugins::PluginName; - use crate::toolset::ToolsetBuilder; -use crate::ui::color::Color; /// install a runtime /// @@ -113,7 +111,6 @@ impl Install { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -122,14 +119,15 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx install nodejs # install version specified in .tool-versions $ rtx install # installs all runtimes specified in .tool-versions for installed plugins $ rtx install --all # installs all runtimes and all plugins - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] mod tests { - use crate::{assert_cli, dirs}; use pretty_assertions::assert_str_eq; + use crate::{assert_cli, dirs}; + #[test] fn test_install_force() { assert_cli!("install", "-f", "shfmt"); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index a10a5f719..52fc40091 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,4 +1,3 @@ -use atty::Stream; use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; @@ -9,8 +8,6 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; - /// get the latest runtime version of a plugin's runtimes #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] @@ -57,7 +54,6 @@ impl Command for Latest { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -66,7 +62,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx latest nodejs # get the latest stable version of nodejs 20.0.0 - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/local.rs b/src/cli/local.rs index 62636fa4f..641ab3198 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -1,15 +1,13 @@ -use atty::Stream; use color_eyre::eyre::{eyre, ContextCompat, Result}; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::{config_file, Config}; - use crate::output::Output; use crate::plugins::PluginName; -use crate::ui::color::Color; use crate::{dirs, env, file}; /// Sets .tool-versions to include a specific runtime @@ -92,7 +90,6 @@ impl Command for Local { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -113,7 +110,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # show the current version of nodejs in .tool-versions $ rtx local nodejs 20.0.0 - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 7df47578c..e856977ce 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,9 +1,9 @@ -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use color_eyre::eyre::Result; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 607e92a98..f762cc507 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,6 +1,6 @@ -use atty::Stream; use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; +use console::style; use indoc::{formatdoc, indoc}; use log::LevelFilter; use once_cell::sync::Lazy; @@ -8,7 +8,6 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; mod activate; mod alias; @@ -179,8 +178,6 @@ impl Cli { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); - const LONG_ABOUT: &str = indoc! {" rtx is a tool for managing runtime versions. @@ -207,7 +204,7 @@ static AFTER_HELP: Lazy = Lazy::new(|| { rtx global system Use system node everywhere unless overridden rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to node-20.x -", COLOR.header("Examples:") } +", style("Examples:").bold().underlined() } }); #[cfg(test)] diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 91aefa34e..8ed8330f7 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::{eyre, Result}; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; use url::Url; @@ -10,7 +10,6 @@ use crate::output::Output; use crate::plugins::Plugin; use crate::shorthand::shorthand_to_repository; use crate::toolset::ToolsetBuilder; -use crate::ui::color::Color; use crate::ui::progress_report::ProgressReport; /// install a plugin @@ -116,7 +115,6 @@ fn get_name_from_url(url: &str) -> Result { Err(eyre!("could not infer plugin name from url: {}", url)) } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -129,7 +127,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx install https://github.com/asdf-vm/asdf-nodejs.git # install the nodejs plugin using the git url only # (nodejs is inferred from the url) - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 199f6f9d1..18b7cceb7 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,7 +7,6 @@ use crate::cli::command::Command; use crate::cli::plugins::ls_remote::PluginsLsRemote; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; /// List installed plugins /// @@ -47,7 +46,6 @@ impl Command for PluginsLs { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -58,7 +56,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx plugins ls --urls nodejs https://github.com/asdf-vm/asdf-nodejs.git ruby https://github.com/asdf-vm/asdf-ruby.git - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index ed846ae3c..a1a292adb 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,12 +1,11 @@ use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; -use owo_colors::{OwoColorize, Stream}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; /// removes a plugin #[derive(Debug, clap::Args)] @@ -22,17 +21,13 @@ impl Command for PluginsUninstall { let plugin = config.plugins.get(&self.plugin); match plugin { Some(plugin) if plugin.is_installed() => { - rtxprintln!( - out, - "uninstalling plugin: {}", - self.plugin.if_supports_color(Stream::Stderr, |t| t.cyan()) - ); + rtxprintln!(out, "uninstalling plugin: {}", style(&self.plugin).cyan()); plugin.uninstall()?; } _ => { warn!( "{} is not installed", - self.plugin.if_supports_color(Stream::Stderr, |t| t.cyan()) + style(&self.plugin).cyan().for_stderr() ); } } @@ -40,12 +35,11 @@ impl Command for PluginsUninstall { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx uninstall nodejs - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 30b334fa0..ad4b3e2aa 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,8 +1,9 @@ +use std::sync::Arc; + use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; -use std::sync::Arc; use crate::cli::command::Command; use crate::config::Config; diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 4c19a2669..e5e58ef4f 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,12 +1,11 @@ -use atty::Stream; use color_eyre::eyre::{eyre, Result}; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; /// Show a current setting /// @@ -30,13 +29,12 @@ impl Command for SettingsGet { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx settings get legacy_version_file true - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 329f33d28..2c69e7e21 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,12 +1,11 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; /// Show current settings /// @@ -27,13 +26,12 @@ impl Command for SettingsLs { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx settings legacy_version_file = false - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] @@ -41,7 +39,6 @@ mod tests { use insta::assert_snapshot; use crate::assert_cli; - use crate::test::reset_config; #[test] diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 253a85a2a..d67cf2566 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::{eyre, Result}; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,7 +7,6 @@ use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; /// Add/update a setting /// @@ -53,12 +52,11 @@ fn parse_i64(value: &str) -> Result { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx settings set legacy_version_file true - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] @@ -66,7 +64,6 @@ pub mod tests { use insta::assert_snapshot; use crate::assert_cli; - use crate::test::reset_config; #[test] diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 0505649cc..9b3a2c406 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,13 +7,12 @@ use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; -use crate::ui::color::Color; /// Clears a setting /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases=["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct SettingsUnset { /// The setting to remove pub key: String, @@ -27,12 +26,11 @@ impl Command for SettingsUnset { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx settings unset legacy_version_file - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] @@ -40,7 +38,6 @@ mod tests { use insta::assert_snapshot; use crate::assert_cli; - use crate::test::reset_config; #[test] diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index afbb74a6d..fe0f06380 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -2,7 +2,6 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; -use owo_colors::OwoColorize; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -31,7 +30,7 @@ impl Command for Uninstall { continue; } - rtxprintln!(out, "uninstalling {}", rtv.to_string().cyan()); + rtxprintln!(out, "uninstalling {}", style(rtv).cyan()); rtv.uninstall() .wrap_err_with(|| eyre!("error uninstalling {}", rtv))?; } @@ -44,5 +43,5 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { {} $ rtx uninstall nodejs@18.0.0 # will uninstall specific version $ rtx uninstall nodejs # will uninstall current nodejs version - "#, style("Examples:").underline().bold()} + "#, style("Examples:").underlined().bold()} }); diff --git a/src/cli/version.rs b/src/cli/version.rs index 06296ffbb..001032d93 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,8 +1,9 @@ +use std::string::ToString; +use std::time::Duration; + use color_eyre::eyre::Result; use console::style; use once_cell::sync::Lazy; -use std::string::ToString; -use std::time::Duration; use versions::Versioning; use crate::build_time::BUILD_TIME; diff --git a/src/cli/where.rs b/src/cli/where.rs index 061405b18..a568cc898 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,5 +1,5 @@ -use atty::Stream; use color_eyre::eyre::Result; +use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -9,7 +9,6 @@ use crate::config::Config; use crate::errors::Error::VersionNotInstalled; use crate::output::Output; use crate::toolset::ToolsetBuilder; -use crate::ui::color::Color; /// Display the installation path for a runtime /// @@ -49,7 +48,6 @@ impl Command for Where { } } -static COLOR: Lazy = Lazy::new(|| Color::new(Stream::Stdout)); static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -62,7 +60,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 - "#, COLOR.header("Examples:")} + "#, style("Examples:").bold().underlined()} }); #[cfg(test)] diff --git a/src/output.rs b/src/output.rs index 324b59ca5..73e53f766 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,5 +1,3 @@ -use atty::Stream; -use owo_colors::OwoColorize; use std::io; use std::io::Write; use std::process::ExitCode; @@ -67,10 +65,6 @@ impl OutputStream { } } -pub fn dim(stream: Stream, s: &str) -> String { - s.if_supports_color(stream, |s| s.dimmed()).to_string() -} - #[macro_export] macro_rules! rtxprintln { () => { @@ -91,7 +85,7 @@ macro_rules! rtxprint { #[macro_export] macro_rules! rtxstatusln { ($out:ident, $($arg:tt)*) => {{ - let rtx = $crate::output::dim(atty::Stream::Stderr, "rtx "); + let rtx = console::style("rtx ").dim().for_stderr(); $out.stderr.writeln(format!("{}{}", rtx, format!($($arg)*))); }}; } diff --git a/src/ui/color.rs b/src/ui/color.rs deleted file mode 100644 index 08121b0c0..000000000 --- a/src/ui/color.rs +++ /dev/null @@ -1,25 +0,0 @@ -use atty::Stream; -use owo_colors::OwoColorize; - -pub struct Color { - stream: Stream, -} - -impl Color { - pub fn new(stream: Stream) -> Self { - Self { stream } - } - - pub fn header(&self, title: &str) -> String { - self.underline(&self.bold(title)) - } - - fn bold(&self, s: &str) -> String { - s.if_supports_color(self.stream, |s| s.bold()).to_string() - } - - fn underline(&self, s: &str) -> String { - s.if_supports_color(self.stream, |s| s.underline()) - .to_string() - } -} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 09896916f..60fe8b916 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,4 +1,3 @@ -pub mod color; pub mod multi_progress_report; pub mod progress_report; pub mod prompt; From 0dc27c2e0ca906a1d57a256717bbdc5a43842665 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 18:38:48 -0600 Subject: [PATCH 0206/1891] chore: Release rtx-cli version 1.13.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93b763817..f18902f3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.12.1" +version = "1.13.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index efbf93ec7..9e5aede78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.12.1" +version = "1.13.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 18d71c27a..4c9724c12 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.12.1 +rtx 1.13.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -202,7 +202,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.1/rtx-v1.12.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.13.0/rtx-v1.13.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b64de3eee..840c9911d 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.12.1 +Version: 1.13.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e69123a80..79a30290a 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -221,7 +221,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.12.1/rtx-v1.12.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.13.0/rtx-v1.13.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From da88853ba170d8e181fb79fe17ad8a572aae7210 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 19:12:15 -0600 Subject: [PATCH 0207/1891] chore: added aur release script to gh action --- .github/workflows/rtx.yml | 6 +++++- scripts/release-aur.sh | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 078cf0f0a..75d2901c4 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -224,6 +224,10 @@ jobs: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 + - name: ssh key + uses: webfactory/ssh-agent@0.7.0 + with: + ssh-private-key: ${{ secrets.RTX_SSH_KEY }} - uses: crazy-max/ghaction-import-gpg@v5 with: gpg_private_key: ${{ secrets.GPG_KEY }} @@ -238,7 +242,6 @@ jobs: - name: homebrew-tap push run: git push working-directory: homebrew-tap - - name: GitHub Release Assets uses: softprops/action-gh-release@v1 if: startsWith(github.event.ref, 'refs/tags/v') @@ -247,6 +250,7 @@ jobs: draft: false files: releases/${{github.ref_name}}/* generate_release_notes: true + - run: rtx/scripts/release-aur.sh bump-homebrew-formula: runs-on: macos-latest if: startsWith(github.event.ref, 'refs/tags/v') diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 673a2dee5..b0e4047c1 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -euxo pipefail - RTX_VERSION=$(./scripts/get-version.sh) SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') From 934271e65cbfc79bcde0d46b3b2bf137abdc9158 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 20:47:05 -0600 Subject: [PATCH 0208/1891] chore: added aur release script to gh action --- src/cli/self_update.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index a09fe95bb..33f48b7e3 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -1,10 +1,12 @@ use color_eyre::Result; use console::style; +use self_update::backends::github::Update; use self_update::cargo_crate_version; use crate::cli::command::Command; use crate::cli::version::{ARCH, OS}; use crate::config::Config; +use crate::env; use crate::output::Output; /// updates rtx itself @@ -14,17 +16,23 @@ pub struct SelfUpdate {} impl Command for SelfUpdate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let status = self_update::backends::github::Update::configure() + let current_version = + env::var("RTX_SELF_UPDATE_VERSION").unwrap_or(cargo_crate_version!().to_string()); + let status = Update::configure() .repo_owner("jdxcode") .repo_name("rtx") .bin_name("rtx") .show_download_progress(true) - .current_version(cargo_crate_version!()) + .current_version(¤t_version) .target(&format!("{}-{}", *OS, *ARCH)) .build()? .update()?; - let version = style(status.version()).bright().yellow(); - rtxprintln!(out, "Updated rtx to {version}"); + if status.updated() { + let version = style(status.version()).bright().yellow(); + rtxprintln!(out, "Updated rtx to {version}"); + } else { + rtxprintln!(out, "rtx is already up to date"); + } Ok(()) } From fcb74d770c2dd7eae80533cdc3353763a47cd5a7 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Tue, 21 Feb 2023 04:06:53 +0100 Subject: [PATCH 0209/1891] feat: alias management commands (#25) (#159) * feat: alias management commands (#25) * feat: alias management commands (#25) - consolidate color utilities * feat: alias management commands (#25) - alphabetize commands * feat: alias management commands (#25) - regenerate help and completions * Update src/config/config_file/rtxrc.rs --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- README.md | 76 +++++++ completions/_rtx | 130 ++++++++++- completions/rtx.bash | 213 +++++++++++++++++- completions/rtx.fish | 41 +++- src/cli/alias/get.rs | 69 ++++++ src/cli/alias/mod.rs | 9 + src/cli/alias/set.rs | 59 +++++ ...tx__cli__alias__set__tests__alias_set.snap | 8 + src/cli/alias/unset.rs | 58 +++++ src/config/config_file/rtxrc.rs | 48 +++- 10 files changed, 691 insertions(+), 20 deletions(-) create mode 100644 src/cli/alias/get.rs create mode 100644 src/cli/alias/set.rs create mode 100644 src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap create mode 100644 src/cli/alias/unset.rs diff --git a/README.md b/README.md index 4c9724c12..9ad35d2cd 100644 --- a/README.md +++ b/README.md @@ -563,6 +563,31 @@ Examples: $ rtx activate fish | source $ execx($(rtx activate xonsh)) +``` +### `rtx alias get` + +``` +Show an alias for a plugin + +This is the contents of an alias. entry in ~/.config/rtx/config.toml + +Usage: get + +Arguments: + + The plugin to show the alias for + + + The alias to show + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + $ rtx alias get nodejs lts/hydrogen + 18.0.0 + ``` ### `rtx alias ls` @@ -589,6 +614,57 @@ Examples: $ rtx aliases nodejs lts/hydrogen 18.0.0 +``` +### `rtx alias set` + +``` +Add/update an alias for a plugin + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: set + +Arguments: + + The plugin to set the alias for + + + The alias to set + + + The value to set the alias to + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + $ rtx alias set nodejs lts/hydrogen 18.0.0 + +``` +### `rtx alias unset` + +``` +Clears an alias for a plugin + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: unset + +Arguments: + + The plugin to remove the alias from + + + The alias to remove + +Options: + -h, --help + Print help (see a summary with '-h') + +Examples: + $ rtx alias unset nodejs lts/hydrogen + ``` ### `rtx cache clear` diff --git a/completions/_rtx b/completions/_rtx index 575e06ef1..f4787caad 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -71,7 +71,20 @@ _arguments "${_arguments_options[@]}" \ (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:rtx-alias-command-$line[1]:" case $line[1] in - (ls) + (get) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':plugin -- The plugin to show the alias for:' \ +':alias -- The alias to show:' \ +&& ret=0 +;; +(ls) _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ @@ -84,6 +97,33 @@ _arguments "${_arguments_options[@]}" \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 ;; +(set) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':plugin -- The plugin to set the alias for:' \ +':alias -- The alias to set:' \ +':value -- The value to set the alias to:' \ +&& ret=0 +;; +(unset) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':plugin -- The plugin to remove the alias from:' \ +':alias -- The alias to remove:' \ +&& ret=0 +;; (help) _arguments "${_arguments_options[@]}" \ ":: :_rtx__alias__help_commands" \ @@ -96,7 +136,19 @@ _arguments "${_arguments_options[@]}" \ (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:rtx-alias-help-command-$line[1]:" case $line[1] in - (ls) + (get) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(unset) _arguments "${_arguments_options[@]}" \ && ret=0 ;; @@ -801,7 +853,19 @@ _arguments "${_arguments_options[@]}" \ (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:rtx-help-alias-command-$line[1]:" case $line[1] in - (ls) + (get) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(ls) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(unset) _arguments "${_arguments_options[@]}" \ && ret=0 ;; @@ -1088,12 +1152,21 @@ _rtx__help__direnv__activate_commands() { (( $+functions[_rtx__alias_commands] )) || _rtx__alias_commands() { local commands; commands=( +'get:Show an alias for a plugin' \ 'ls:List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' \ 'list:List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' \ +'set:Add/update an alias for a plugin' \ +'add:Add/update an alias for a plugin' \ +'create:Add/update an alias for a plugin' \ +'unset:Clears an alias for a plugin' \ +'rm:Clears an alias for a plugin' \ +'remove:Clears an alias for a plugin' \ +'delete:Clears an alias for a plugin' \ +'del:Clears an alias for a plugin' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx alias commands' commands "$@" @@ -1101,9 +1174,12 @@ These can come from user config or from plugins in `bin/list-aliases`.' \ (( $+functions[_rtx__help__alias_commands] )) || _rtx__help__alias_commands() { local commands; commands=( +'get:Show an alias for a plugin' \ 'ls:List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' \ +'set:Add/update an alias for a plugin' \ +'unset:Clears an alias for a plugin' \ ) _describe -t commands 'rtx help alias commands' commands "$@" } @@ -1261,6 +1337,21 @@ _rtx__help__exec_commands() { local commands; commands=() _describe -t commands 'rtx help exec commands' commands "$@" } +(( $+functions[_rtx__alias__get_commands] )) || +_rtx__alias__get_commands() { + local commands; commands=() + _describe -t commands 'rtx alias get commands' commands "$@" +} +(( $+functions[_rtx__alias__help__get_commands] )) || +_rtx__alias__help__get_commands() { + local commands; commands=() + _describe -t commands 'rtx alias help get commands' commands "$@" +} +(( $+functions[_rtx__help__alias__get_commands] )) || +_rtx__help__alias__get_commands() { + local commands; commands=() + _describe -t commands 'rtx help alias get commands' commands "$@" +} (( $+functions[_rtx__help__settings__get_commands] )) || _rtx__help__settings__get_commands() { local commands; commands=() @@ -1289,9 +1380,12 @@ _rtx__help__global_commands() { (( $+functions[_rtx__alias__help_commands] )) || _rtx__alias__help_commands() { local commands; commands=( +'get:Show an alias for a plugin' \ 'ls:List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' \ +'set:Add/update an alias for a plugin' \ +'unset:Clears an alias for a plugin' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx alias help commands' commands "$@" @@ -1594,6 +1688,21 @@ _rtx__self-update_commands() { local commands; commands=() _describe -t commands 'rtx self-update commands' commands "$@" } +(( $+functions[_rtx__alias__help__set_commands] )) || +_rtx__alias__help__set_commands() { + local commands; commands=() + _describe -t commands 'rtx alias help set commands' commands "$@" +} +(( $+functions[_rtx__alias__set_commands] )) || +_rtx__alias__set_commands() { + local commands; commands=() + _describe -t commands 'rtx alias set commands' commands "$@" +} +(( $+functions[_rtx__help__alias__set_commands] )) || +_rtx__help__alias__set_commands() { + local commands; commands=() + _describe -t commands 'rtx help alias set commands' commands "$@" +} (( $+functions[_rtx__help__settings__set_commands] )) || _rtx__help__settings__set_commands() { local commands; commands=() @@ -1662,6 +1771,21 @@ _rtx__uninstall_commands() { local commands; commands=() _describe -t commands 'rtx uninstall commands' commands "$@" } +(( $+functions[_rtx__alias__help__unset_commands] )) || +_rtx__alias__help__unset_commands() { + local commands; commands=() + _describe -t commands 'rtx alias help unset commands' commands "$@" +} +(( $+functions[_rtx__alias__unset_commands] )) || +_rtx__alias__unset_commands() { + local commands; commands=() + _describe -t commands 'rtx alias unset commands' commands "$@" +} +(( $+functions[_rtx__help__alias__unset_commands] )) || +_rtx__help__alias__unset_commands() { + local commands; commands=() + _describe -t commands 'rtx help alias unset commands' commands "$@" +} (( $+functions[_rtx__help__settings__unset_commands] )) || _rtx__help__settings__unset_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index d1ef2dbbf..37d2f37a7 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -120,6 +120,21 @@ _rtx() { rtx,x) cmd="rtx__exec" ;; + rtx__alias,add) + cmd="rtx__alias__set" + ;; + rtx__alias,create) + cmd="rtx__alias__set" + ;; + rtx__alias,del) + cmd="rtx__alias__unset" + ;; + rtx__alias,delete) + cmd="rtx__alias__unset" + ;; + rtx__alias,get) + cmd="rtx__alias__get" + ;; rtx__alias,help) cmd="rtx__alias__help" ;; @@ -129,12 +144,33 @@ _rtx() { rtx__alias,ls) cmd="rtx__alias__ls" ;; + rtx__alias,remove) + cmd="rtx__alias__unset" + ;; + rtx__alias,rm) + cmd="rtx__alias__unset" + ;; + rtx__alias,set) + cmd="rtx__alias__set" + ;; + rtx__alias,unset) + cmd="rtx__alias__unset" + ;; + rtx__alias__help,get) + cmd="rtx__alias__help__get" + ;; rtx__alias__help,help) cmd="rtx__alias__help__help" ;; rtx__alias__help,ls) cmd="rtx__alias__help__ls" ;; + rtx__alias__help,set) + cmd="rtx__alias__help__set" + ;; + rtx__alias__help,unset) + cmd="rtx__alias__help__unset" + ;; rtx__cache,c) cmd="rtx__cache__clear" ;; @@ -255,9 +291,18 @@ _rtx() { rtx__help,where) cmd="rtx__help__where" ;; + rtx__help__alias,get) + cmd="rtx__help__alias__get" + ;; rtx__help__alias,ls) cmd="rtx__help__alias__ls" ;; + rtx__help__alias,set) + cmd="rtx__help__alias__set" + ;; + rtx__help__alias,unset) + cmd="rtx__help__alias__unset" + ;; rtx__help__cache,clear) cmd="rtx__help__cache__clear" ;; @@ -463,7 +508,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -v -h --plugin --log-level --jobs --verbose --help ls help" + opts="-p -j -v -h --plugin --log-level --jobs --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -496,8 +541,34 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__alias__get) + opts="-j -v -h --log-level --jobs --verbose --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__alias__help) - opts="ls help" + opts="get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -510,6 +581,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__alias__help__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__alias__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -538,6 +623,34 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__alias__help__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__alias__ls) opts="-p -j -v -h --plugin --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -572,6 +685,58 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__alias__set) + opts="-j -v -h --log-level --jobs --verbose --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__unset) + opts="-j -v -h --log-level --jobs --verbose --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__asdf) opts="-j -v -h --log-level --jobs --verbose --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -1113,7 +1278,7 @@ _rtx() { return 0 ;; rtx__help__alias) - opts="ls" + opts="get ls set unset" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1126,6 +1291,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__alias__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__alias__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -1140,6 +1319,34 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__alias__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__asdf) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 9eb0dab9d..1c13336e0 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -37,24 +37,42 @@ complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rt complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' @@ -297,9 +315,12 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from ls" -f -a "ls" -d 'List aliases +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`.' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "set" -d 'Add/update an alias for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "unset" -d 'Clears an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file for direnv to consume.' diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs new file mode 100644 index 000000000..0939740e8 --- /dev/null +++ b/src/cli/alias/get.rs @@ -0,0 +1,69 @@ +use color_eyre::eyre::{eyre, Result}; +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +/// Show an alias for a plugin +/// +/// This is the contents of an alias. entry in ~/.config/rtx/config.toml +/// +#[derive(Debug, clap::Args)] +#[clap(after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +pub struct AliasGet { + /// The plugin to show the alias for + pub plugin: String, + /// The alias to show + pub alias: String, +} + +impl Command for AliasGet { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + match config.aliases.get(&self.plugin) { + Some(plugin) => match plugin.get(&self.alias) { + Some(alias) => Ok(rtxprintln!(out, "{}", alias)), + None => Err(eyre!("Unknown alias: {}", &self.alias)), + }, + None => Err(eyre!("Unknown plugin: {}", &self.plugin)), + } + } +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx alias get nodejs lts/hydrogen + 18.0.0 + "#, style("Examples:").bold().underlined()} +}); + +#[cfg(test)] +mod tests { + use insta::{assert_display_snapshot, assert_snapshot}; + + use crate::{assert_cli, assert_cli_err, test::reset_config}; + + #[test] + fn test_alias_get() { + reset_config(); + let stdout = assert_cli!("alias", "get", "shfmt", "my/alias"); + assert_snapshot!(stdout, @r###" + 3.0 + "###); + } + + #[test] + fn test_alias_get_plugin_unknown() { + let err = assert_cli_err!("alias", "get", "unknown", "unknown"); + assert_display_snapshot!(err, @"Unknown plugin: unknown"); + } + + #[test] + fn test_alias_get_alias_unknown() { + let err = assert_cli_err!("alias", "get", "shfmt", "unknown"); + assert_display_snapshot!(err, @"Unknown alias: unknown"); + } +} diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index 26c826893..d55148cd1 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -6,7 +6,10 @@ use crate::config::Config; use crate::output::Output; use crate::plugins::PluginName; +mod get; mod ls; +mod set; +mod unset; #[derive(Debug, clap::Args)] #[clap(about = "Manage aliases", visible_alias = "a", alias = "aliases")] @@ -21,13 +24,19 @@ pub struct Alias { #[derive(Debug, Subcommand)] enum Commands { + Get(get::AliasGet), Ls(ls::AliasLs), + Set(set::AliasSet), + Unset(unset::AliasUnset), } impl Commands { pub fn run(self, config: Config, out: &mut Output) -> Result<()> { match self { + Self::Get(cmd) => cmd.run(config, out), Self::Ls(cmd) => cmd.run(config, out), + Self::Set(cmd) => cmd.run(config, out), + Self::Unset(cmd) => cmd.run(config, out), } } } diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs new file mode 100644 index 000000000..f8b8811a9 --- /dev/null +++ b/src/cli/alias/set.rs @@ -0,0 +1,59 @@ +use color_eyre::eyre::Result; +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::config::config_file::ConfigFile; +use crate::config::Config; +use crate::output::Output; + +/// Add/update an alias for a plugin +/// +/// This modifies the contents of ~/.config/rtx/config.toml +#[derive(Debug, clap::Args)] +#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +pub struct AliasSet { + /// The plugin to set the alias for + pub plugin: String, + /// The alias to set + pub alias: String, + /// The value to set the alias to + pub value: String, +} + +impl Command for AliasSet { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let mut rtxrc = config.rtxrc; + + rtxrc.set_alias(&self.plugin, &self.alias, &self.value); + rtxrc.save() + } +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx alias set nodejs lts/hydrogen 18.0.0 + "#, style("Examples:").bold().underlined()} +}); + +#[cfg(test)] +pub mod tests { + use insta::assert_snapshot; + + use crate::assert_cli; + + use crate::test::reset_config; + + #[test] + fn test_alias_set() { + reset_config(); + assert_cli!("alias", "set", "shfmt", "my/alias", "3.0"); + + let stdout = assert_cli!("aliases"); + println!("stdout {}", stdout); + assert_snapshot!(stdout); + reset_config(); + } +} diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap new file mode 100644 index 000000000..f4c510b44 --- /dev/null +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -0,0 +1,8 @@ +--- +source: src/cli/alias/set.rs +assertion_line: 55 +expression: stdout +--- +shfmt my/alias 3.0 + + diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs new file mode 100644 index 000000000..8aff57698 --- /dev/null +++ b/src/cli/alias/unset.rs @@ -0,0 +1,58 @@ +use color_eyre::eyre::Result; +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::config::config_file::ConfigFile; +use crate::config::Config; +use crate::output::Output; + +/// Clears an alias for a plugin +/// +/// This modifies the contents of ~/.config/rtx/config.toml +#[derive(Debug, clap::Args)] +#[clap(visible_aliases=["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +pub struct AliasUnset { + /// The plugin to remove the alias from + pub plugin: String, + /// The alias to remove + pub alias: String, +} + +impl Command for AliasUnset { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let mut rtxrc = config.rtxrc; + rtxrc.remove_alias(&self.plugin, &self.alias); + rtxrc.save() + } +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx alias unset nodejs lts/hydrogen + "#, style("Examples:").bold().underlined()} +}); + +#[cfg(test)] +mod tests { + use insta::assert_snapshot; + + use crate::assert_cli; + + use crate::test::reset_config; + + #[test] + fn test_settings_unset() { + reset_config(); + + assert_cli!("alias", "unset", "shfmt", "my/alias"); + + let stdout = assert_cli!("aliases"); + assert_snapshot!(stdout, @r###" + "###); + + reset_config(); + } +} diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 60d61d3fd..c118c7eba 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -298,7 +298,7 @@ impl RTXFile { let doc = self.get_or_create_edit(); let aliases = doc .as_table_mut() - .entry("aliases") + .entry("alias") .or_insert(toml_edit::table()) .as_table_mut() .unwrap(); @@ -309,6 +309,21 @@ impl RTXFile { .unwrap(); plugin_aliases[from] = toml_edit::value(to); } + + pub fn remove_alias(&mut self, plugin: &str, from: &str) { + let doc = self.get_or_create_edit(); + if let Some(aliases) = doc.get_mut("alias").and_then(|v| v.as_table_mut()) { + if let Some(plugin_aliases) = aliases.get_mut(plugin).and_then(|v| v.as_table_mut()) { + plugin_aliases.remove(from); + if plugin_aliases.is_empty() { + aliases.remove(plugin); + } + } + if aliases.is_empty() { + doc.as_table_mut().remove("alias"); + } + } + } } impl Display for RTXFile { @@ -599,7 +614,7 @@ nodejs=[true] writedoc!( f, r#" - [aliases.nodejs] + [alias.nodejs] 16 = "16.0.0" 18 = "18.0.0" "# @@ -610,16 +625,41 @@ nodejs=[true] cf.set_alias("nodejs", "20", "20.0.0"); cf.set_alias("python", "3.10", "3.10.0"); assert_display_snapshot!(cf.dump(), @r###" - [aliases.nodejs] + [alias.nodejs] 16 = "16.0.0" 18 = "18.0.1" 20 = "20.0.0" - [aliases.python] + [alias.python] "3.10" = "3.10.0" "###); } + #[test] + fn test_remove_alias() { + let mut f = tempfile::NamedTempFile::new().unwrap(); + writedoc!( + f, + r#" + [alias.nodejs] + 16 = "16.0.0" + 18 = "18.0.0" + + [alias.python] + "3.10" = "3.10.0" + "# + ) + .unwrap(); + let mut cf = RTXFile::from_file(f.path()).unwrap(); + cf.remove_alias("nodejs", "16"); + cf.remove_alias("python", "3.10"); + + assert_display_snapshot!(cf.dump(), @r###" + [alias.nodejs] + 18 = "18.0.0" + "###); + } + #[test] fn test_edit_when_file_does_not_exist() { let mut cf = RTXFile::from_str("".to_string()).unwrap(); From dd47ef301e1c16ab06a278033f0e8ccc29f63cd4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 21:52:16 -0600 Subject: [PATCH 0210/1891] refactor: clean up rtxrc editing (#160) This uses a OnceCell to help with creating the editable document and memoizing it. It also uses a Mutex which reduces the need to making things mutable --- src/cli/alias/set.rs | 4 +- src/cli/alias/unset.rs | 4 +- src/cli/settings/set.rs | 4 +- src/cli/settings/unset.rs | 4 +- src/config/config_file/rtxrc.rs | 113 +++++++++++++++++--------------- 5 files changed, 67 insertions(+), 62 deletions(-) diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index f8b8811a9..ea9c23a48 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -24,9 +24,9 @@ pub struct AliasSet { impl Command for AliasSet { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let mut rtxrc = config.rtxrc; + let rtxrc = config.rtxrc; - rtxrc.set_alias(&self.plugin, &self.alias, &self.value); + rtxrc.set_alias(&self.plugin, &self.alias, &self.value)?; rtxrc.save() } } diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 8aff57698..17b55bc4f 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -22,8 +22,8 @@ pub struct AliasUnset { impl Command for AliasUnset { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let mut rtxrc = config.rtxrc; - rtxrc.remove_alias(&self.plugin, &self.alias); + let rtxrc = config.rtxrc; + rtxrc.remove_alias(&self.plugin, &self.alias)?; rtxrc.save() } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index d67cf2566..01c845f20 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -22,7 +22,7 @@ pub struct SettingsSet { impl Command for SettingsSet { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let mut rtxrc = config.rtxrc; + let rtxrc = config.rtxrc; let value: toml_edit::Value = match self.key.as_str() { "missing_runtime_behavior" => self.value.into(), "always_keep_download" => parse_bool(&self.value)?, @@ -32,7 +32,7 @@ impl Command for SettingsSet { _ => return Err(eyre!("Unknown setting: {}", self.key)), }; - rtxrc.update_setting(&self.key, value); + rtxrc.update_setting(&self.key, value)?; rtxrc.save() } } diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 9b3a2c406..f535bc007 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -20,8 +20,8 @@ pub struct SettingsUnset { impl Command for SettingsUnset { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let mut rtxrc = config.rtxrc; - rtxrc.remove_setting(&self.key); + let rtxrc = config.rtxrc; + rtxrc.remove_setting(&self.key)?; rtxrc.save() } } diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index c118c7eba..953b0dbab 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -2,12 +2,14 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::fs; use std::path::{Path, PathBuf}; +use std::sync::Mutex; use std::time::Duration; use color_eyre::eyre::{eyre, Context}; use color_eyre::{Result, Section, SectionExt}; use indexmap::IndexMap; use log::LevelFilter; +use once_cell::sync::OnceCell; use toml::Value; use crate::config::config_file::{ConfigFile, ConfigFileType}; @@ -26,7 +28,7 @@ pub struct RTXFile { pub path: PathBuf, pub plugins: IndexMap, pub env: HashMap, - edit: Option, + edit: OnceCell>, settings: SettingsBuilder, } @@ -187,7 +189,7 @@ impl RTXFile { } } - fn parse_missing_runtime_behavior(&mut self, v: &Value) -> Result { + fn parse_missing_runtime_behavior(&self, v: &Value) -> Result { let v = self.parse_string("missing_runtime_behavior", v)?; match v.to_lowercase().as_str() { "warn" => Ok(MissingRuntimeBehavior::Warn), @@ -198,12 +200,12 @@ impl RTXFile { } } - fn parse_log_level(&mut self, v: &Value) -> Result { + fn parse_log_level(&self, v: &Value) -> Result { let level = self.parse_string("log_level", v)?.parse()?; Ok(level) } - fn parse_aliases(&mut self, v: &Value) -> Result { + fn parse_aliases(&self, v: &Value) -> Result { match v { Value::Table(table) => { let mut aliases = AliasMap::new(); @@ -231,35 +233,22 @@ impl RTXFile { } } - fn get_or_create_edit(&mut self) -> &mut toml_edit::Document { - if self.edit.is_none() { + fn get_edit(&self) -> Result<&Mutex> { + self.edit.get_or_try_init(|| { if !self.path.exists() { let dir = self.path.parent().unwrap(); - fs::create_dir_all(dir).expect("could not create directory"); - fs::write(&self.path, "").expect("could not create new config.toml file"); + fs::create_dir_all(dir)?; + fs::write(&self.path, "")?; } - let body = fs::read_to_string(&self.path) - .suggestion("ensure file exists and can be read") - .unwrap(); - self.edit = Some(body.parse::().unwrap()); - } - self.edit.as_mut().unwrap() - } - - fn get_edit(&self) -> Result { - match &self.edit { - Some(doc) => Ok(doc.clone()), - None => { - let body = fs::read_to_string(&self.path) - .suggestion("ensure file exists and can be read") - .unwrap(); - Ok(body.parse::()?) - } - } + let body = + fs::read_to_string(&self.path).suggestion("ensure file exists and can be read")?; + let edit = body.parse::()?; + Ok(Mutex::new(edit)) + }) } - pub fn update_setting>(&mut self, key: &str, value: V) { - let doc = self.get_or_create_edit(); + pub fn update_setting>(&self, key: &str, value: V) -> Result<()> { + let mut doc = self.get_edit()?.lock().unwrap(); let key = key.split('.').collect::>(); let mut table = doc.as_table_mut(); for (i, k) in key.iter().enumerate() { @@ -274,10 +263,11 @@ impl RTXFile { .unwrap(); } } + Ok(()) } - pub fn remove_setting(&mut self, key: &str) { - let doc = self.get_or_create_edit(); + pub fn remove_setting(&self, key: &str) -> Result<()> { + let mut doc = self.get_edit()?.lock().unwrap(); let key = key.split('.').collect::>(); let mut table = doc.as_table_mut(); for (i, k) in key.iter().enumerate() { @@ -292,10 +282,11 @@ impl RTXFile { .unwrap(); } } + Ok(()) } - pub fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { - let doc = self.get_or_create_edit(); + pub fn set_alias(&self, plugin: &str, from: &str, to: &str) -> Result<()> { + let mut doc = self.get_edit()?.lock().unwrap(); let aliases = doc .as_table_mut() .entry("alias") @@ -308,10 +299,11 @@ impl RTXFile { .as_table_mut() .unwrap(); plugin_aliases[from] = toml_edit::value(to); + Ok(()) } - pub fn remove_alias(&mut self, plugin: &str, from: &str) { - let doc = self.get_or_create_edit(); + pub fn remove_alias(&self, plugin: &str, from: &str) -> Result<()> { + let mut doc = self.get_edit()?.lock().unwrap(); if let Some(aliases) = doc.get_mut("alias").and_then(|v| v.as_table_mut()) { if let Some(plugin_aliases) = aliases.get_mut(plugin).and_then(|v| v.as_table_mut()) { plugin_aliases.remove(from); @@ -323,6 +315,7 @@ impl RTXFile { doc.as_table_mut().remove("alias"); } } + Ok(()) } } @@ -354,7 +347,12 @@ impl ConfigFile for RTXFile { fn remove_plugin(&mut self, plugin: &PluginName) { self.plugins.remove(plugin); - self.get_or_create_edit().as_table_mut().remove(plugin); + self.get_edit() + .unwrap() + .lock() + .unwrap() + .as_table_mut() + .remove(plugin); } fn add_version(&mut self, plugin: &PluginName, version: &str) { @@ -364,7 +362,10 @@ impl ConfigFile for RTXFile { .versions .push(version.to_string()); - self.get_or_create_edit() + self.get_edit() + .unwrap() + .lock() + .unwrap() .entry(plugin) .or_insert_with(toml_edit::array) .as_array_mut() @@ -375,7 +376,10 @@ impl ConfigFile for RTXFile { fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { let plugin = self.plugins.entry(plugin_name.into()).or_default(); plugin.versions.clear(); - self.get_or_create_edit() + self.get_edit() + .unwrap() + .lock() + .unwrap() .entry(plugin_name) .or_insert_with(toml_edit::array) .as_array_mut() @@ -392,7 +396,7 @@ impl ConfigFile for RTXFile { } fn dump(&self) -> String { - self.get_edit().expect("unable to parse toml").to_string() + self.get_edit().unwrap().lock().unwrap().to_string() } fn to_toolset(&self) -> Toolset { @@ -555,12 +559,13 @@ nodejs=[true] "# ) .unwrap(); - let mut cf = RTXFile::from_file(f.path()).unwrap(); - cf.update_setting("legacy_version_file", false); - cf.update_setting("something_else", "foo"); - cf.update_setting("something.nested.very.deeply", 123); - cf.update_setting("aliases.nodejs.20", "20.0.0"); - cf.update_setting("aliases.python.3", "3.9.0"); + let cf = RTXFile::from_file(f.path()).unwrap(); + cf.update_setting("legacy_version_file", false).unwrap(); + cf.update_setting("something_else", "foo").unwrap(); + cf.update_setting("something.nested.very.deeply", 123) + .unwrap(); + cf.update_setting("aliases.nodejs.20", "20.0.0").unwrap(); + cf.update_setting("aliases.python.3", "3.9.0").unwrap(); assert_display_snapshot!(cf.dump(), @r###" legacy_version_file = false something_else = "foo" @@ -596,8 +601,8 @@ nodejs=[true] "# ) .unwrap(); - let mut cf = RTXFile::from_file(f.path()).unwrap(); - cf.remove_setting("something.nested.other"); + let cf = RTXFile::from_file(f.path()).unwrap(); + cf.remove_setting("something.nested.other").unwrap(); assert_display_snapshot!(cf.dump(), @r###" [something] @@ -620,10 +625,10 @@ nodejs=[true] "# ) .unwrap(); - let mut cf = RTXFile::from_file(f.path()).unwrap(); - cf.set_alias("nodejs", "18", "18.0.1"); - cf.set_alias("nodejs", "20", "20.0.0"); - cf.set_alias("python", "3.10", "3.10.0"); + let cf = RTXFile::from_file(f.path()).unwrap(); + cf.set_alias("nodejs", "18", "18.0.1").unwrap(); + cf.set_alias("nodejs", "20", "20.0.0").unwrap(); + cf.set_alias("python", "3.10", "3.10.0").unwrap(); assert_display_snapshot!(cf.dump(), @r###" [alias.nodejs] 16 = "16.0.0" @@ -650,9 +655,9 @@ nodejs=[true] "# ) .unwrap(); - let mut cf = RTXFile::from_file(f.path()).unwrap(); - cf.remove_alias("nodejs", "16"); - cf.remove_alias("python", "3.10"); + let cf = RTXFile::from_file(f.path()).unwrap(); + cf.remove_alias("nodejs", "16").unwrap(); + cf.remove_alias("python", "3.10").unwrap(); assert_display_snapshot!(cf.dump(), @r###" [alias.nodejs] @@ -665,7 +670,7 @@ nodejs=[true] let mut cf = RTXFile::from_str("".to_string()).unwrap(); let dir = tempfile::tempdir().unwrap(); cf.path = dir.path().join("subdir").join("does-not-exist.toml"); - cf.set_alias("nodejs", "18", "18.0.1"); + cf.set_alias("nodejs", "18", "18.0.1").unwrap(); cf.save().unwrap(); } } From 8c74b39d4589c7e6050d76f0782898050ec399f9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 21:53:00 -0600 Subject: [PATCH 0211/1891] docs: uninstall instructions --- README.md | 8 ++++++-- src/cli/render_help.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9ad35d2cd..356995e1e 100644 --- a/README.md +++ b/README.md @@ -118,8 +118,12 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin > **Warning** > -> Regardless of the installation method, when uninstalling rtx, -> remove `RTX_DATA_DIR` folder (usually `~/.local/share/rtx`) to fully clean up. +> Regardless of the installation method, use `rtx implode` to fully clean up. +> Alternatively, manually remove the following: +> * `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) +> * `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) +> * on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) +> * on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) ### Standalone diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 79a30290a..58b33d5fa 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -137,8 +137,12 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin > **Warning** > -> Regardless of the installation method, when uninstalling rtx, -> remove `RTX_DATA_DIR` folder (usually `~/.local/share/rtx`) to fully clean up. +> Regardless of the installation method, use `rtx implode` to fully clean up. +> Alternatively, manually remove the following: +> * `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) +> * `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) +> * on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) +> * on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) ### Standalone From 332da0e13966bd8bf1b4d6f33cf0d152259c4031 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 21:55:57 -0600 Subject: [PATCH 0212/1891] docs: uninstall instructions --- README.md | 21 ++++++++++++--------- src/cli/render_help.rs | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 356995e1e..a541bb16b 100644 --- a/README.md +++ b/README.md @@ -116,15 +116,6 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin ## Installation -> **Warning** -> -> Regardless of the installation method, use `rtx implode` to fully clean up. -> Alternatively, manually remove the following: -> * `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) -> * `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) -> * on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) -> * on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) - ### Standalone Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate script in your rc @@ -305,6 +296,18 @@ in this project. the others are implemented. If your shell isn't currently supported I'd be happy to help you get yours integrated. +## Uninstalling + +Use `rtx implode` to uninstall rtx. This will remove the rtx binary and all of its data. Use +`rtx implode --help` for more information. + +Alternatively, manually remove the following directories to fully clean up: + +* `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) +* `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) +* on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) +* on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) + ## Configuration ### `.tool-versions` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 58b33d5fa..fac68db75 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -135,15 +135,6 @@ means there isn't any need to run `asdf reshim` after installing new runtime bin ## Installation -> **Warning** -> -> Regardless of the installation method, use `rtx implode` to fully clean up. -> Alternatively, manually remove the following: -> * `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) -> * `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) -> * on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) -> * on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) - ### Standalone Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate script in your rc @@ -324,6 +315,18 @@ in this project. the others are implemented. If your shell isn't currently supported I'd be happy to help you get yours integrated. +## Uninstalling + +Use `rtx implode` to uninstall rtx. This will remove the rtx binary and all of its data. Use +`rtx implode --help` for more information. + +Alternatively, manually remove the following directories to fully clean up: + +* `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) +* `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) +* on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) +* on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) + ## Configuration ### `.tool-versions` From 663eca88d0539eae3013a3609db901501b8ac96a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:06:12 -0600 Subject: [PATCH 0213/1891] feat: added `rtx bin-paths` command (#161) This will be useful for me in the github action --- README.md | 12 +++++++++ completions/_rtx | 27 ++++++++++++++++++++ completions/rtx.bash | 50 ++++++++++++++++++++++++++++++++++-- completions/rtx.fish | 60 ++++++++++++++++++++++++-------------------- src/cli/bin_paths.rs | 35 ++++++++++++++++++++++++++ src/cli/mod.rs | 3 +++ 6 files changed, 158 insertions(+), 29 deletions(-) create mode 100644 src/cli/bin_paths.rs diff --git a/README.md b/README.md index a541bb16b..469abc243 100644 --- a/README.md +++ b/README.md @@ -672,6 +672,18 @@ Options: Examples: $ rtx alias unset nodejs lts/hydrogen +``` +### `rtx bin-paths` + +``` +List all the active runtime bin paths + +Usage: bin-paths + +Options: + -h, --help + Print help + ``` ### `rtx cache clear` diff --git a/completions/_rtx b/completions/_rtx index f4787caad..a1bb97227 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -176,6 +176,17 @@ _arguments "${_arguments_options[@]}" \ '*::args -- all arguments:' \ && ret=0 ;; +(bin-paths) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; (cache) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ @@ -877,6 +888,10 @@ esac _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(bin-paths) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (cache) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help__cache_commands" \ @@ -1089,6 +1104,7 @@ _rtx_commands() { 'alias:Manage aliases' \ 'a:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ +'bin-paths:List all the active runtime bin paths' \ 'cache:Manage the rtx cache' \ 'complete:generate shell completions' \ 'current:Shows currently active, and installed runtime versions' \ @@ -1193,6 +1209,16 @@ _rtx__help__asdf_commands() { local commands; commands=() _describe -t commands 'rtx help asdf commands' commands "$@" } +(( $+functions[_rtx__bin-paths_commands] )) || +_rtx__bin-paths_commands() { + local commands; commands=() + _describe -t commands 'rtx bin-paths commands' commands "$@" +} +(( $+functions[_rtx__help__bin-paths_commands] )) || +_rtx__help__bin-paths_commands() { + local commands; commands=() + _describe -t commands 'rtx help bin-paths commands' commands "$@" +} (( $+functions[_rtx__cache_commands] )) || _rtx__cache_commands() { local commands; commands=( @@ -1431,6 +1457,7 @@ _rtx__help_commands() { 'activate:Enables rtx to automatically modify runtimes when changing directory' \ 'alias:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ +'bin-paths:List all the active runtime bin paths' \ 'cache:Manage the rtx cache' \ 'complete:generate shell completions' \ 'current:Shows currently active, and installed runtime versions' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 37d2f37a7..dc8521fca 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -24,6 +24,9 @@ _rtx() { rtx,asdf) cmd="rtx__asdf" ;; + rtx,bin-paths) + cmd="rtx__bin__paths" + ;; rtx,cache) cmd="rtx__cache" ;; @@ -219,6 +222,9 @@ _rtx() { rtx__help,asdf) cmd="rtx__help__asdf" ;; + rtx__help,bin-paths) + cmd="rtx__help__bin__paths" + ;; rtx__help,cache) cmd="rtx__help__cache" ;; @@ -448,7 +454,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -763,6 +769,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__bin__paths) + opts="-j -v -h --log-level --jobs --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__cache) opts="-j -v -h --log-level --jobs --verbose --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -1250,7 +1282,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" + opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1361,6 +1393,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__bin__paths) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__cache) opts="clear" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 1c13336e0..215a8ab70 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -6,6 +6,7 @@ complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_use_subcommand" -f -a "bin-paths" -d 'List all the active runtime bin paths' complete -c rtx -n "__fish_use_subcommand" -f -a "cache" -d 'Manage the rtx cache' complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'generate shell completions' complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows currently active, and installed runtime versions' @@ -77,6 +78,10 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the l complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -288,33 +293,34 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'removes rtx CLI and all generated data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs new file mode 100644 index 000000000..1fdb3305f --- /dev/null +++ b/src/cli/bin_paths.rs @@ -0,0 +1,35 @@ +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; +use crate::toolset::ToolsetBuilder; + +/// List all the active runtime bin paths +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct BinPaths {} + +impl Command for BinPaths { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().with_install_missing().build(&config); + for p in ts.list_paths() { + rtxprintln!(out, "{}", p.display()); + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use pretty_assertions::assert_str_eq; + + use crate::assert_cli; + use crate::cli::tests::grep; + + #[test] + fn test_bin_paths() { + let stdout = assert_cli!("bin-paths"); + assert_str_eq!(grep(stdout, "tiny"), "~/data/installs/tiny/2.1.0/bin"); + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index f762cc507..2feb7c905 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -13,6 +13,7 @@ mod activate; mod alias; pub mod args; mod asdf; +mod bin_paths; mod cache; pub mod command; mod complete; @@ -54,6 +55,7 @@ pub enum Commands { Activate(activate::Activate), Alias(alias::Alias), Asdf(asdf::Asdf), + BinPaths(bin_paths::BinPaths), Cache(cache::Cache), Complete(complete::Complete), Current(current::Current), @@ -88,6 +90,7 @@ impl Commands { Self::Activate(cmd) => cmd.run(config, out), Self::Alias(cmd) => cmd.run(config, out), Self::Asdf(cmd) => cmd.run(config, out), + Self::BinPaths(cmd) => cmd.run(config, out), Self::Cache(cmd) => cmd.run(config, out), Self::Complete(cmd) => cmd.run(config, out), Self::Current(cmd) => cmd.run(config, out), From 8be4d4586f44db60663f9341c9710bc5943e6c68 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:31:50 -0600 Subject: [PATCH 0214/1891] ui: hide install output if blank --- src/runtimes.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index 7efce7f3a..a42c810fd 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -94,7 +94,9 @@ impl RuntimeVersion { } }, |line| { - pr.set_message(line.into()); + if !line.trim().is_empty() { + pr.set_message(line.into()); + } }, ) }; From 4cd4262f0d57be0cd3c2a5a7b06677ec15dfaf29 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:34:20 -0600 Subject: [PATCH 0215/1891] test: test plugin uninstall when not installed --- ...s__uninstall__tests__plugin_uninstall_not_installed.snap | 5 +++++ src/cli/plugins/uninstall.rs | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap new file mode 100644 index 000000000..e835030b3 --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/plugins/uninstall.rs +expression: stdout +--- + diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index a1a292adb..5e3de916a 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -61,4 +61,10 @@ mod tests { ensure_plugin_installed("nodejs"); } + + #[test] + fn test_plugin_uninstall_not_installed() { + let stdout = assert_cli!("plugin", "rm", "xxx"); + assert_snapshot!(stdout); + } } From 1d8f371c5db707e99b8271916cc5d8cb82aefbab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:40:16 -0600 Subject: [PATCH 0216/1891] test: use tiny for plugin uninstall test --- ...s__uninstall__tests__plugin_uninstall.snap | 4 +-- src/cli/plugins/uninstall.rs | 32 +++++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap index 083a54b0a..502bbe446 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap @@ -1,6 +1,6 @@ --- source: src/cli/plugins/uninstall.rs -expression: stdout +expression: output --- -uninstalling plugin: nodejs +uninstalling plugin: tiny diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 5e3de916a..ec3a16df6 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -46,25 +46,23 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use insta::assert_snapshot; - use crate::assert_cli; - use crate::cli::tests::ensure_plugin_installed; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_plugin_uninstall() { - ensure_plugin_installed("nodejs"); - - let stdout = assert_cli!("plugin", "rm", "nodejs"); - assert_snapshot!(stdout); - - let stdout = assert_cli!("plugin", "rm", "nodejs"); - assert_snapshot!(stdout); - - ensure_plugin_installed("nodejs"); - } - - #[test] - fn test_plugin_uninstall_not_installed() { - let stdout = assert_cli!("plugin", "rm", "xxx"); - assert_snapshot!(stdout); + assert_cli!( + "plugin", + "add", + "tiny", + "https://github.com/jdxcode/rtx-tiny" + ); + assert_cli_snapshot!("plugin", "rm", "tiny"); + assert_cli_snapshot!("plugin", "rm", "tiny"); + assert_cli!( + "plugin", + "add", + "tiny", + "https://github.com/jdxcode/rtx-tiny" + ); } } From ad88f62aaf0b82537f73b83cb60937a5c13ba336 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 00:03:38 -0600 Subject: [PATCH 0217/1891] chore: run update-shorthand-repo script on release --- Cargo.toml | 1 + scripts/pre-release-hook.sh | 6 ++++++ scripts/update-shorthand-repo.sh | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100755 scripts/pre-release-hook.sh diff --git a/Cargo.toml b/Cargo.toml index 9e5aede78..f7c9260fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ strip = "symbols" allow-branch = ["main"] #sign-tag = true #sign-commit = true +pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh new file mode 100755 index 000000000..74a19e92e --- /dev/null +++ b/scripts/pre-release-hook.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euxo pipefail + +./scripts/update-shorthand-repo.sh +just lint-fix +git add src/shorthand_list.rs diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index a4719b469..fcef33227 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -euxo pipefail +set -euo pipefail rm -rf asdf-plugins git clone --depth 1 https://github.com/asdf-vm/asdf-plugins From b2e2661ee59e66d486146416b0ab8a623536e2c7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 00:47:08 -0600 Subject: [PATCH 0218/1891] test: use tiny for plugin tests (#162) --- scripts/update-shorthand-repo.sh | 3 +- src/cli/alias/get.rs | 4 +- src/cli/alias/ls.rs | 2 +- src/cli/alias/set.rs | 2 +- ...tx__cli__alias__set__tests__alias_set.snap | 6 +- src/cli/alias/unset.rs | 4 +- src/cli/env.rs | 15 +++-- src/cli/global.rs | 2 +- src/cli/install.rs | 1 + src/cli/local.rs | 20 +++---- src/cli/mod.rs | 2 +- src/cli/plugins/install.rs | 19 ++---- src/cli/plugins/ls.rs | 6 +- ...li__plugins__install__tests__rtx-tiny.snap | 5 ++ ...x__cli__plugins__install__tests__tiny.snap | 5 ++ ..._uninstall__tests__plugin_uninstall-2.snap | 2 +- ...tests__plugin_uninstall_not_installed.snap | 5 -- src/cli/plugins/update.rs | 9 ++- .../rtx__cli__local__tests__local-2.snap | 5 +- .../rtx__cli__local__tests__local-3.snap | 5 +- .../rtx__cli__local__tests__local.snap | 5 +- ...x__cli__ls_remote__tests__list_remote.snap | 2 +- src/cli/where.rs | 16 +++-- src/shorthand_list.rs | 58 +++++++++++++++---- src/test.rs | 2 +- test/config/config.toml | 2 +- 26 files changed, 122 insertions(+), 85 deletions(-) create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index fcef33227..5ab8ea1cd 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -6,7 +6,7 @@ git clone --depth 1 https://github.com/asdf-vm/asdf-plugins rm -f src/shorthand_list.rs num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') -num_plugins=$((num_plugins + 1)) # +1 for node alias to nodejs +num_plugins=$((num_plugins + 2)) # +2 for custom aliases (node, tiny, etc) cat > src/shorthand_list.rs < src/shorthand_list.rs <>, } diff --git a/src/cli/install.rs b/src/cli/install.rs index 80c9ce661..699c7b18d 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -153,5 +153,6 @@ mod tests { output.trim(), dirs::INSTALLS.join("dummy/ref-master").to_string_lossy() ); + assert_cli!("global", "--unset", "dummy"); } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 641ab3198..652184ca0 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -41,7 +41,7 @@ pub struct Local { fuzzy: bool, /// remove the plugin(s) from .tool-versions - #[clap(long, value_name = "PLUGIN")] + #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] remove: Option>, } @@ -121,25 +121,21 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; - use crate::{assert_cli, assert_cli_err, dirs}; + use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; #[test] fn test_local() { let cf_path = dirs::CURRENT.join(".tool-versions"); let orig = fs::read_to_string(&cf_path).unwrap(); - assert_cli!("plugin", "add", "nodejs"); - assert_cli!("install", "shfmt@2"); - let stdout = assert_cli!("local", "--pin", "shfmt@2"); - assert_snapshot!(stdout); - let stdout = assert_cli!("local", "shfmt@2"); - assert_snapshot!(stdout); - let stdout = assert_cli!("local", "--remove", "nodejs"); - assert_snapshot!(stdout); + assert_cli!("install", "tiny@2"); + assert_cli_snapshot!("local", "--pin", "tiny@2"); + assert_cli_snapshot!("local", "tiny@2"); + assert_cli_snapshot!("local", "--remove", "tiny"); let stdout = assert_cli!("ls", "--current"); assert_str_eq!( - grep(stdout, "nodejs"), - " nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)" + grep(stdout, "tiny"), + "-> tiny 2.1.0 (set by ~/.tool-versions)" ); let stdout = assert_cli!("local", "--pin", "tiny@1"); assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2feb7c905..17851eaba 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -273,7 +273,7 @@ pub mod tests { .split('\n') .find(|line| line.contains(pattern)) .map(|line| line.to_string()) - .unwrap_or_default() + .unwrap() .replace(dirs::HOME.to_string_lossy().as_ref(), "~") } } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 8ed8330f7..305a21b92 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -109,6 +109,7 @@ fn get_name_from_url(url: &str) -> Result { if let Some(segments) = url.path_segments() { let last = segments.last().unwrap_or_default(); let name = last.strip_prefix("asdf-").unwrap_or(last); + let name = name.strip_prefix("rtx-").unwrap_or(name); return Ok(name.to_string()); } } @@ -138,21 +139,11 @@ mod tests { use crate::cli::tests::cli_run; use crate::cli::tests::grep; - #[test] - fn test_plugin_install() { - assert_cli!("plugin", "add", "nodejs"); - } - #[test] fn test_plugin_install_url() { - assert_cli!( - "plugin", - "add", - "-f", - "https://github.com/jdxcode/asdf-nodejs" - ); + assert_cli!("plugin", "add", "-f", "https://github.com/jdxcode/rtx-tiny"); let stdout = assert_cli!("plugin", "--urls"); - assert_snapshot!(grep(stdout, "nodejs"), @"nodejs https://github.com/jdxcode/asdf-nodejs"); + assert_snapshot!(grep(stdout, "tiny"), @"tiny https://github.com/jdxcode/rtx-tiny"); } #[test] @@ -164,9 +155,9 @@ mod tests { #[test] fn test_plugin_install_all() { - assert_cli!("plugin", "rm", "nodejs"); + assert_cli!("plugin", "rm", "tiny"); assert_cli!("plugin", "install", "--all"); let stdout = assert_cli!("plugin"); - assert_snapshot!(grep(stdout, "nodejs"), "nodejs"); + assert_snapshot!(grep(stdout, "tiny"), "tiny"); } } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 18b7cceb7..93a459c4e 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -69,15 +69,15 @@ mod tests { #[test] fn test_plugin_list() { let stdout = assert_cli!("plugin", "list"); - assert_str_eq!(grep(stdout, "nodejs"), "nodejs"); + assert_str_eq!(grep(stdout, "dummy"), "dummy"); } #[test] fn test_plugin_list_urls() { let stdout = assert_cli!("plugin", "list", "--urls"); assert_str_eq!( - grep(stdout, "shfmt"), - "shfmt https://github.com/luizm/asdf-shfmt.git" + grep(stdout, "tiny"), + "tiny https://github.com/jdxcode/rtx-tiny" ); } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap new file mode 100644 index 000000000..3bfd9d8ad --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/plugins/install.rs +expression: "\"tiny\"" +--- +tiny diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap new file mode 100644 index 000000000..3bfd9d8ad --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/plugins/install.rs +expression: "\"tiny\"" +--- +tiny diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap index e835030b3..faf1a84ac 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap @@ -1,5 +1,5 @@ --- source: src/cli/plugins/uninstall.rs -expression: stdout +expression: output --- diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap deleted file mode 100644 index e835030b3..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall_not_installed.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/plugins/uninstall.rs -expression: stdout ---- - diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index ad4b3e2aa..0f31b53ce 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -64,10 +64,15 @@ mod tests { #[test] fn test_plugin_update() { - assert_cli!("plugin", "install", "nodejs"); + assert_cli!( + "plugin", + "install", + "tiny", + "https://github.com/jdxcode/rtx-tiny" + ); let err = assert_cli_err!("p", "update"); assert_str_eq!(err.to_string(), "no plugins specified"); assert_cli!("plugin", "update", "--all"); - assert_cli!("plugins", "update", "nodejs"); + assert_cli!("plugins", "update", "tiny"); } } diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local-2.snap index f3c8c33c1..aea5835d1 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local-2.snap @@ -1,10 +1,11 @@ --- source: src/cli/local.rs -expression: stdout +expression: output --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 2 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 nodejs system +tiny 2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local-3.snap index b94ee7f22..49777dd15 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local-3.snap @@ -1,9 +1,10 @@ --- source: src/cli/local.rs -expression: stdout +expression: output --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 2 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 +nodejs system diff --git a/src/cli/snapshots/rtx__cli__local__tests__local.snap b/src/cli/snapshots/rtx__cli__local__tests__local.snap index 34c0c2f61..42c952e30 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local.snap @@ -1,10 +1,11 @@ --- source: src/cli/local.rs -expression: stdout +expression: output --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 2.6.4 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 nodejs system +tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap b/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap index abe0b70dc..bc50965d1 100644 --- a/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap +++ b/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap @@ -1,6 +1,6 @@ --- source: src/cli/ls_remote.rs -expression: stdout +expression: output --- 1.0.0 1.1.0 diff --git a/src/cli/where.rs b/src/cli/where.rs index a568cc898..29dc70d3d 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -73,29 +73,27 @@ mod tests { #[test] fn test_where() { - assert_cli!("plugin", "add", "shfmt"); assert_cli!("install"); - let stdout = assert_cli!("where", "shfmt"); + let stdout = assert_cli!("where", "tiny"); assert_str_eq!( stdout.trim(), - dirs::ROOT.join("installs/shfmt/3.5.1").to_string_lossy() + dirs::ROOT.join("installs/tiny/2.1.0").to_string_lossy() ); } #[test] fn test_where_alias() { - assert_cli!("plugin", "add", "shfmt"); - assert_cli!("install", "shfmt@my/alias"); - let stdout = assert_cli!("where", "shfmt@my/alias"); + assert_cli!("install", "tiny@my/alias"); + let stdout = assert_cli!("where", "tiny@my/alias"); assert_str_eq!( stdout.trim(), - dirs::ROOT.join("installs/shfmt/3.0.2").to_string_lossy() + dirs::ROOT.join("installs/tiny/3.0.1").to_string_lossy() ); } #[test] fn test_where_not_found() { - let err = assert_cli_err!("where", "shfmt@1111"); - assert_display_snapshot!(err, @"shfmt@1111 not installed"); + let err = assert_cli_err!("where", "tiny@1111"); + assert_display_snapshot!(err, @"tiny@1111 not installed"); } } diff --git a/src/shorthand_list.rs b/src/shorthand_list.rs index 4b1b71498..5f2d16074 100644 --- a/src/shorthand_list.rs +++ b/src/shorthand_list.rs @@ -1,9 +1,10 @@ // This file is generated by scripts/update-shorthand-repo.sh // Do not edit this file manually -pub const SHORTHAND_LIST: [(&str, &str); 592] = [ +pub const SHORTHAND_LIST: [(&str, &str); 607] = [ // rtx custom aliases ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), + ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), // asdf original aliases from https://github.com/asdf-vm/asdf-plugins ( "1password-cli", @@ -54,10 +55,6 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "https://github.com/gliwka/asdf-asciidoctorj.git", ), ("assh", "https://github.com/zekker6/asdf-assh.git"), - ( - "aws-amplify-cli", - "https://github.com/LozanoMatheus/asdf-aws-amplify-cli.git", - ), ("aws-copilot", "https://github.com/NeoHsu/asdf-copilot"), ( "aws-iam-authenticator", @@ -68,6 +65,10 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "https://github.com/bersalazar/asdf-aws-nuke.git", ), ("aws-sam-cli", "https://github.com/amrox/asdf-pyapp.git"), + ( + "aws-sso-cli", + "https://github.com/adamcrews/asdf-aws-sso-cli.git", + ), ( "aws-vault", "https://github.com/karancode/asdf-aws-vault.git", @@ -98,6 +99,14 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("batect", "https://github.com/johnlayton/asdf-batect.git"), ("bats", "https://github.com/timgluz/asdf-bats.git"), ("bazel", "https://github.com/rajatvig/asdf-bazel.git"), + ( + "bbr", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", + ), + ( + "bbr-s3-config-validator", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", + ), ("benthos", "https://github.com/benthosdev/benthos-asdf.git"), ("binnacle", "https://github.com/Traackr/asdf-binnacle.git"), ("bitwarden", "https://github.com/vixus0/asdf-bitwarden.git"), @@ -108,7 +117,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("borg", "https://github.com/lwiechec/asdf-borg"), ( "bosh", - "https://github.com/laidbackware/asdf-github-release-downloader.git", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", ), ("bottom", "https://github.com/carbonteq/asdf-btm.git"), ( @@ -208,6 +217,10 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "codeql", "https://github.com/bored-engineer/asdf-codeql.git", ), + ( + "colima", + "https://github.com/CrouchingMuppet/asdf-colima.git", + ), ("conan", "https://github.com/amrox/asdf-pyapp.git"), ( "concourse", @@ -243,7 +256,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("crc", "https://github.com/sqtran/asdf-crc.git"), ( "credhub", - "https://github.com/laidbackware/asdf-github-release-downloader.git", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", ), ( "crossplane-cli", @@ -370,7 +383,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ), ( "fly", - "https://github.com/laidbackware/asdf-github-release-downloader.git", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", ), ("flyctl", "https://github.com/chessmango/asdf-flyctl.git"), ("func-e", "https://github.com/carnei-ro/asdf-func-e.git"), @@ -589,7 +602,12 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "kotlin", "https://github.com/asdf-community/asdf-kotlin.git", ), + ( + "kpack-cli", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", + ), ("kpt", "https://github.com/nlamirault/asdf-kpt.git"), + ("krab", "https://github.com/ohkrab/asdf-krab.git"), ("krew", "https://github.com/jimmidyson/asdf-krew.git"), ("kscript", "https://github.com/edgelevel/asdf-kscript.git"), ("ksonnet", "https://github.com/Banno/asdf-ksonnet.git"), @@ -684,6 +702,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "https://github.com/nklmilojevic/asdf-lazygit.git", ), ("lean", "https://github.com/asdf-community/asdf-lean.git"), + ("lefthook", "https://github.com/jtzero/asdf-lefthook.git"), ("leiningen", "https://github.com/miorimmax/asdf-lein.git"), ( "levant", @@ -769,12 +788,13 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("nsc", "https://github.com/dex4er/asdf-nsc.git"), ("oc", "https://github.com/sqtran/asdf-oc.git"), ("ocaml", "https://github.com/asdf-community/asdf-ocaml.git"), + ("oci", "https://github.com/yasn77/asdf-oci.git"), ("odin", "https://github.com/jtakakura/asdf-odin"), ("odo", "https://github.com/rm3l/asdf-odo.git"), ("okteto", "https://github.com/BradenM/asdf-okteto"), ( "om", - "https://github.com/laidbackware/asdf-github-release-downloader.git", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", ), ("opa", "https://github.com/tochukwuvictor/asdf-opa.git"), ("opam", "https://github.com/asdf-community/asdf-opam.git"), @@ -818,9 +838,10 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("perl", "https://github.com/ouest/asdf-perl.git"), ("php", "https://github.com/asdf-community/asdf-php.git"), ("pint", "https://github.com/sam-burrell/asdf-pint.git"), + ("pipectl", "https://github.com/pipe-cd/asdf-pipectl.git"), ( "pivnet", - "https://github.com/laidbackware/asdf-github-release-downloader.git", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", ), ( "please", @@ -908,7 +929,6 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ), ("reg", "https://github.com/looztra/asdf-reg.git"), ("regctl", "https://github.com/ORCID/asdf-regctl.git"), - ("riak", "https://github.com/smashedtoatoms/asdf-riak.git"), ("richgo", "https://github.com/paxosglobal/asdf-richgo.git"), ("riff", "https://github.com/abinet/asdf-riff.git"), ("ripgrep", "https://gitlab.com/wt0f/asdf-ripgrep.git"), @@ -1035,6 +1055,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("talos", "https://github.com/particledecay/asdf-talos.git"), ("tanka", "https://github.com/trotttrotttrott/asdf-tanka.git"), ("task", "https://github.com/particledecay/asdf-task.git"), + ("tctl", "https://github.com/eko/asdf-tctl.git"), ( "tekton-cli", "https://github.com/johnhamelink/asdf-tekton-cli.git", @@ -1048,6 +1069,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "telepresence", "https://github.com/pirackr/asdf-telepresence.git", ), + ("temporalite", "https://github.com/eko/asdf-temporalite.git"), ( "terradozer", "https://github.com/chessmango/asdf-terradozer.git", @@ -1077,6 +1099,10 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "terramate", "https://github.com/martinlindner/asdf-terramate.git", ), + ( + "terrascan", + "https://github.com/hpdobrica/asdf-terrascan.git", + ), ( "tf-summarize", "https://github.com/adamcrews/asdf-tf-summarize.git", @@ -1119,6 +1145,10 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "tsuru", "https://github.com/virtualstaticvoid/asdf-tsuru.git", ), + ( + "uaa-cli", + "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git", + ), ("upt", "https://github.com/ORCID/asdf-upt.git"), ("upx", "https://github.com/jimmidyson/asdf-upx.git"), ("usql", "https://github.com/itspngu/asdf-usql.git"), @@ -1133,6 +1163,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("velad", "https://github.com/pdemagny/asdf-velad"), ("velero", "https://github.com/looztra/asdf-velero.git"), ("vendir", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ("venom", "https://github.com/aabouzaid/asdf-venom.git"), ("vhs", "https://github.com/chessmango/asdf-vhs.git"), ("viddy", "https://github.com/ryodocx/asdf-viddy.git"), ("vim", "https://github.com/tsuyoshicho/asdf-vim.git"), @@ -1168,6 +1199,7 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ "https://github.com/younke/asdf-xchtmlreport.git", ), ("xcodegen", "https://github.com/younke/asdf-xcodegen.git"), + ("xcodes", "https://github.com/younke/asdf-xcodes.git"), ("xh", "https://github.com/NeoHsu/asdf-xh"), ("yadm", "https://github.com/particledecay/asdf-yadm.git"), ( @@ -1180,6 +1212,10 @@ pub const SHORTHAND_LIST: [(&str, &str); 592] = [ ("yor", "https://github.com/ordinaryexperts/asdf-yor"), ("yq", "https://github.com/sudermanjr/asdf-yq.git"), ("ytt", "https://github.com/vmware-tanzu/asdf-carvel.git"), + ( + "zbctl", + "https://github.com/camunda-community-hub/asdf-zbctl.git", + ), ("zellij", "https://github.com/chessmango/asdf-zellij.git"), ("zephyr", "https://github.com/nsaunders/asdf-zephyr.git"), ("zig", "https://github.com/cheetah/asdf-zig.git"), diff --git a/src/test.rs b/src/test.rs index a1b73749b..7ccaba075 100644 --- a/src/test.rs +++ b/src/test.rs @@ -40,7 +40,7 @@ pub fn reset_config() { plugin_autoupdate_last_check_duration = 20 jobs = 2 - [alias.shfmt] + [alias.tiny] "my/alias" = '3.0' "#}, ) diff --git a/test/config/config.toml b/test/config/config.toml index e75e742c1..8d9a78bf8 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -5,5 +5,5 @@ legacy_version_file= true plugin_autoupdate_last_check_duration = 20 jobs = 2 -[alias.shfmt] +[alias.tiny] "my/alias" = '3.0' From c6476a36a5169292da97ec0dddf5e688a4ed331f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 10:58:40 -0600 Subject: [PATCH 0219/1891] chore: fix coverage action to reuse cache (#167) that definitely should not have had "clean" set on it --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index 78e109d24..e5b4d9d54 100644 --- a/justfile +++ b/justfile @@ -36,7 +36,7 @@ test-e2e: test-setup build ./e2e/run_all_tests # run unit tests w/ coverage -test-coverage: clean test-setup +test-coverage: cargo +nightly tarpaulin \ --all-features --workspace \ --timeout 120 --out Xml --ignore-tests From ed482f2ff10f26538a6925bc7d3c3a19781653ef Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 11:02:33 -0600 Subject: [PATCH 0220/1891] bug: allow specifying ref/path as an alias (#166) --- src/cli/args/runtime.rs | 9 +- src/cli/local.rs | 28 ++++++ .../rtx__cli__local__tests__local-4.snap | 6 ++ .../rtx__cli__local__tests__local-5.snap | 6 ++ .../rtx__cli__local__tests__local-6.snap | 6 ++ src/runtimes.rs | 12 ++- src/toolset/tool_source.rs | 24 ++++- src/toolset/tool_version.rs | 88 +++++++++++-------- 8 files changed, 131 insertions(+), 48 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__local__tests__local-4.snap create mode 100644 src/cli/snapshots/rtx__cli__local__tests__local-5.snap create mode 100644 src/cli/snapshots/rtx__cli__local__tests__local-6.snap diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index eee006078..80c3db873 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -93,14 +93,7 @@ impl RuntimeArg { impl Display for RuntimeArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.version { - RuntimeArgVersion::System => write!(f, "{}@system", self.plugin), - RuntimeArgVersion::Path(path) => write!(f, "{}@path:{}", self.plugin, path), - RuntimeArgVersion::Version(version) => write!(f, "{}@{}", self.plugin, version), - RuntimeArgVersion::Ref(ref_) => write!(f, "{}@ref:{}", self.plugin, ref_), - RuntimeArgVersion::Prefix(prefix) => write!(f, "{}@prefix:{}", self.plugin, prefix), - RuntimeArgVersion::None => write!(f, "{}", self.plugin), - } + write!(f, "{}@{}", self.plugin, self.version) } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 652184ca0..7d1a8621c 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -166,6 +166,34 @@ mod tests { let err = assert_cli_err!("local", "tiny", "dummy@latest"); assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + // alias ref + assert_cli!("alias", "set", "dummy", "m", "ref:master"); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_cli_snapshot!("current", "dummy"); + + // alias path + let local_dummy_path = dirs::INSTALLS.join("dummy").join("1.1.0"); + let path_arg = String::from("path:") + &local_dummy_path.to_string_lossy(); + assert_cli!("alias", "set", "dummy", "m", &path_arg); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + let stdout = assert_cli!("current", "dummy"); + assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); + + // alias prefix + assert_cli!("alias", "set", "dummy", "m", "prefix:1"); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_cli_snapshot!("current", "dummy"); + + // alias system + assert_cli!("alias", "set", "dummy", "m", "system"); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_cli_snapshot!("current", "dummy"); + + assert_cli!("alias", "unset", "dummy", "m"); fs::write(cf_path, orig).unwrap(); } } diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-4.snap b/src/cli/snapshots/rtx__cli__local__tests__local-4.snap new file mode 100644 index 000000000..73f17be11 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__local__tests__local-4.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/local.rs +expression: output +--- +ref-master + diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-5.snap b/src/cli/snapshots/rtx__cli__local__tests__local-5.snap new file mode 100644 index 000000000..b6210172a --- /dev/null +++ b/src/cli/snapshots/rtx__cli__local__tests__local-5.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/local.rs +expression: output +--- +1.1.0 + diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-6.snap b/src/cli/snapshots/rtx__cli__local__tests__local-6.snap new file mode 100644 index 000000000..fdc036a38 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__local__tests__local-6.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/local.rs +expression: output +--- +system + diff --git a/src/runtimes.rs b/src/runtimes.rs index a42c810fd..9868bf590 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -37,15 +37,21 @@ impl RuntimeVersion { let version = match &install_type { InstallType::Version(v) => v.to_string(), InstallType::Ref(r) => format!("ref-{r}"), - InstallType::Path(p) => hash_to_str(&p), + InstallType::Path(p) => p.display().to_string(), InstallType::System => "system".into(), }; let install_path = match &install_type { InstallType::Path(p) => p.clone(), _ => dirs::INSTALLS.join(&plugin.name).join(&version), }; - let download_path = dirs::DOWNLOADS.join(&plugin.name).join(&version); - let cache_path = dirs::CACHE.join(&plugin.name).join(&version); + let download_path = match &install_type { + InstallType::Path(p) => p.clone(), + _ => dirs::DOWNLOADS.join(&plugin.name).join(&version), + }; + let cache_path = match &install_type { + InstallType::Path(p) => dirs::CACHE.join(&plugin.name).join(hash_to_str(&p)), + _ => dirs::CACHE.join(&plugin.name).join(&version), + }; Self { script_man: build_script_man( install_type.clone(), diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index 6daf97f45..c49772c38 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -1,7 +1,8 @@ -use crate::file::display_path; use std::fmt::{Display, Formatter}; use std::path::PathBuf; +use crate::file::display_path; + /// where a tool version came from (e.g.: .tool-versions) #[derive(Debug, Clone)] pub enum ToolSource { @@ -23,3 +24,24 @@ impl Display for ToolSource { } } } + +#[cfg(test)] +mod tests { + use pretty_assertions::assert_str_eq; + + use super::*; + + #[test] + fn test_tool_source_display() { + let path = PathBuf::from("/home/user/.tool-versions"); + + let ts = ToolSource::ToolVersions(path); + assert_str_eq!(ts.to_string(), "/home/user/.tool-versions"); + + let ts = ToolSource::Argument; + assert_str_eq!(ts.to_string(), "--runtime"); + + let ts = ToolSource::Environment("RTX_NODEJS_VERSION".to_string(), "20".to_string()); + assert_str_eq!(ts.to_string(), "RTX_NODEJS_VERSION=20"); + } +} diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 8b10d2bcd..f5036b94a 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -37,61 +37,81 @@ impl ToolVersion { } pub fn resolve(&mut self, settings: &Settings, plugin: Arc) -> Result<()> { - if self.rtv.is_some() { - return Ok(()); - } - match self.r#type.clone() { - ToolVersionType::Version(v) => self.resolve_version(settings, plugin, &v), - ToolVersionType::Prefix(v) => self.resolve_prefix(settings, plugin, &v), - ToolVersionType::Ref(r) => { - self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Ref(r))); - Ok(()) - } - ToolVersionType::Path(path) => { - let path = fs::canonicalize(path)?; - self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Path(path))); - Ok(()) - } - ToolVersionType::System => Ok(()), + if self.rtv.is_none() { + self.rtv = match &self.r#type { + ToolVersionType::Version(v) => self.resolve_version(settings, plugin, v)?, + ToolVersionType::Prefix(v) => self.resolve_prefix(settings, plugin, v)?, + ToolVersionType::Ref(r) => self.resolve_ref(plugin, r)?, + ToolVersionType::Path(path) => self.resolve_path(plugin, path)?, + ToolVersionType::System => None, + }; } + Ok(()) } - fn resolve_version(&mut self, settings: &Settings, plugin: Arc, v: &str) -> Result<()> { + fn resolve_version( + &self, + settings: &Settings, + plugin: Arc, + v: &str, + ) -> Result> { let v = resolve_alias(settings, plugin.clone(), v)?; + match v.split_once(':') { + Some(("ref", r)) => { + return self.resolve_ref(plugin, r); + } + Some(("path", p)) => { + return self.resolve_path(plugin, p); + } + Some(("prefix", p)) => { + return self.resolve_prefix(settings, plugin, p); + } + Some(("system", _)) => { + return Ok(None); + } + _ => (), + } if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { // if the version is already installed, no need to fetch all of the remote versions - self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Version(v))); - return Ok(()); + let rtv = RuntimeVersion::new(plugin, InstallType::Version(v)); + return Ok(Some(rtv)); } let matches = plugin.list_versions_matching(settings, &v)?; if matches.contains(&v) { - self.rtv = Some(RuntimeVersion::new(plugin, InstallType::Version(v))); + let rtv = RuntimeVersion::new(plugin, InstallType::Version(v)); + Ok(Some(rtv)) } else { - self.resolve_prefix(settings, plugin, &v)?; + self.resolve_prefix(settings, plugin, &v) } - - Ok(()) } fn resolve_prefix( - &mut self, + &self, settings: &Settings, plugin: Arc, prefix: &str, - ) -> Result<()> { + ) -> Result> { let matches = plugin.list_versions_matching(settings, prefix)?; let v = match matches.last() { Some(v) => v, None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; - self.rtv = Some(RuntimeVersion::new( - plugin, - InstallType::Version(v.to_string()), - )); - Ok(()) + let rtv = RuntimeVersion::new(plugin, InstallType::Version(v.to_string())); + Ok(Some(rtv)) + } + + fn resolve_ref(&self, plugin: Arc, r: &str) -> Result> { + let rtv = RuntimeVersion::new(plugin, InstallType::Ref(r.to_string())); + Ok(Some(rtv)) + } + + fn resolve_path(&self, plugin: Arc, path: &str) -> Result> { + let path = fs::canonicalize(path)?; + let rtv = RuntimeVersion::new(plugin, InstallType::Path(path)); + Ok(Some(rtv)) } pub fn is_missing(&self) -> bool { @@ -104,14 +124,10 @@ impl ToolVersion { pub fn install(&mut self, config: &Config, pr: ProgressReport) -> Result<()> { match self.r#type { ToolVersionType::Version(_) | ToolVersionType::Prefix(_) | ToolVersionType::Ref(_) => { - self.rtv.as_ref().unwrap().install(config, pr)?; + self.rtv.as_ref().unwrap().install(config, pr) } - _ => (), + _ => Ok(()), } - if matches!(self.r#type, ToolVersionType::System) { - return Ok(()); - } - Ok(()) } } From 89eee758ab849ec654ee132271ea6e553dd2de28 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 11:23:49 -0600 Subject: [PATCH 0221/1891] chore: skip fmt on shortname list --- scripts/update-shorthand-repo.sh | 1 + src/shorthand_list.rs | 1022 ++++++------------------------ 2 files changed, 207 insertions(+), 816 deletions(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index 5ab8ea1cd..cb1a5b766 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -12,6 +12,7 @@ cat > src/shorthand_list.rs < Date: Tue, 21 Feb 2023 12:21:25 -0600 Subject: [PATCH 0222/1891] test: refactor local tests into individual test cases --- src/cli/local.rs | 182 +++++++++++------- ..._cli__plugins__install__tests__nodejs.snap | 5 - ...li__plugins__install__tests__rtx-tiny.snap | 5 - ...li__local__tests__local_alias_prefix.snap} | 0 ...__cli__local__tests__local_alias_ref.snap} | 0 ...li__local__tests__local_alias_system.snap} | 0 ...x__cli__local__tests__local_remove-2.snap} | 0 ...x__cli__local__tests__local_remove-3.snap} | 0 ...rtx__cli__local__tests__local_remove.snap} | 0 9 files changed, 114 insertions(+), 78 deletions(-) delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__nodejs.snap delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap rename src/cli/snapshots/{rtx__cli__local__tests__local-5.snap => rtx__cli__local__tests__local_alias_prefix.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local-4.snap => rtx__cli__local__tests__local_alias_ref.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local-6.snap => rtx__cli__local__tests__local_alias_system.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local-2.snap => rtx__cli__local__tests__local_remove-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local-3.snap => rtx__cli__local__tests__local_remove-3.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local.snap => rtx__cli__local__tests__local_remove.snap} (100%) diff --git a/src/cli/local.rs b/src/cli/local.rs index 7d1a8621c..bd256d0fe 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -115,7 +115,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use std::fs; + use std::{fs, panic}; use insta::assert_snapshot; use pretty_assertions::assert_str_eq; @@ -124,76 +124,122 @@ mod tests { use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; #[test] - fn test_local() { + fn test_local_remove() { + run_test(|| { + assert_cli!("install", "tiny@2"); + assert_cli_snapshot!("local", "--pin", "tiny@2"); + assert_cli_snapshot!("local", "tiny@2"); + assert_cli_snapshot!("local", "--remove", "tiny"); + let stdout = assert_cli!("ls", "--current"); + assert_str_eq!( + grep(stdout, "tiny"), + "-> tiny 2.1.0 (set by ~/.tool-versions)" + ); + }); + } + #[test] + fn test_local_pin() { + run_test(|| { + let stdout = assert_cli!("local", "--pin", "tiny@1"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); + let stdout = assert_cli!("local", "--pin", "tiny", "2"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); + }); + } + #[test] + fn test_local_path() { + run_test(|| { + let stdout = assert_cli!("local", "dummy@path:."); + assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); + }); + } + #[test] + fn test_local_ref() { + run_test(|| { + let stdout = assert_cli!("local", "dummy@ref:master"); + assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); + }); + } + #[test] + fn test_local_prefix() { + run_test(|| { + let stdout = assert_cli!("local", "dummy@prefix:1"); + assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); + }); + } + #[test] + fn test_local_output_current_version() { + run_test(|| { + assert_cli!("local", "tiny", "2"); + let stdout = assert_cli!("local", "tiny"); + assert_str_eq!(stdout, "2\n"); + }); + } + #[test] + fn test_local_invalid_multiple_plugins() { + run_test(|| { + let err = assert_cli_err!("local", "tiny", "dummy"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + }); + } + #[test] + fn test_local_invalid() { + run_test(|| { + let err = assert_cli_err!("local", "tiny", "dummy@latest"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + }); + } + #[test] + fn test_local_alias_ref() { + run_test(|| { + assert_cli!("alias", "set", "dummy", "m", "ref:master"); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_cli_snapshot!("current", "dummy"); + }); + } + #[test] + fn test_local_alias_path() { + run_test(|| { + let local_dummy_path = dirs::INSTALLS.join("dummy").join("1.1.0"); + let path_arg = String::from("path:") + &local_dummy_path.to_string_lossy(); + assert_cli!("alias", "set", "dummy", "m", &path_arg); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + let stdout = assert_cli!("current", "dummy"); + assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); + }); + } + #[test] + fn test_local_alias_prefix() { + run_test(|| { + assert_cli!("alias", "set", "dummy", "m", "prefix:1"); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_cli_snapshot!("current", "dummy"); + }); + } + #[test] + fn test_local_alias_system() { + run_test(|| { + assert_cli!("alias", "set", "dummy", "m", "system"); + let stdout = assert_cli!("local", "dummy@m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_cli_snapshot!("current", "dummy"); + }); + } + + fn run_test(test: T) + where + T: FnOnce() + panic::UnwindSafe, + { let cf_path = dirs::CURRENT.join(".tool-versions"); let orig = fs::read_to_string(&cf_path).unwrap(); - assert_cli!("install", "tiny@2"); - assert_cli_snapshot!("local", "--pin", "tiny@2"); - assert_cli_snapshot!("local", "tiny@2"); - assert_cli_snapshot!("local", "--remove", "tiny"); - let stdout = assert_cli!("ls", "--current"); - assert_str_eq!( - grep(stdout, "tiny"), - "-> tiny 2.1.0 (set by ~/.tool-versions)" - ); - let stdout = assert_cli!("local", "--pin", "tiny@1"); - assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); - let stdout = assert_cli!("local", "--pin", "tiny", "2"); - assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); - - // path - let stdout = assert_cli!("local", "dummy@path:."); - assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); - - // ref - let stdout = assert_cli!("local", "dummy@ref:master"); - assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); - - // prefix - let stdout = assert_cli!("local", "dummy@prefix:1"); - assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); - - // will output the current version(s) - let stdout = assert_cli!("local", "tiny"); - assert_str_eq!(stdout, "2.1.0\n"); - - // can only request a version one plugin at a time - let err = assert_cli_err!("local", "tiny", "dummy"); - assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); - - // this is just invalid - let err = assert_cli_err!("local", "tiny", "dummy@latest"); - assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); - - // alias ref - assert_cli!("alias", "set", "dummy", "m", "ref:master"); - let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); - assert_cli_snapshot!("current", "dummy"); - - // alias path - let local_dummy_path = dirs::INSTALLS.join("dummy").join("1.1.0"); - let path_arg = String::from("path:") + &local_dummy_path.to_string_lossy(); - assert_cli!("alias", "set", "dummy", "m", &path_arg); - let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); - let stdout = assert_cli!("current", "dummy"); - assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); - - // alias prefix - assert_cli!("alias", "set", "dummy", "m", "prefix:1"); - let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); - assert_cli_snapshot!("current", "dummy"); - - // alias system - assert_cli!("alias", "set", "dummy", "m", "system"); - let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); - assert_cli_snapshot!("current", "dummy"); - - assert_cli!("alias", "unset", "dummy", "m"); + let result = panic::catch_unwind(test); + fs::write(cf_path, orig).unwrap(); + + assert!(result.is_ok()) } } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__nodejs.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__nodejs.snap deleted file mode 100644 index 16fbb5bdf..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__nodejs.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/plugins/install.rs -expression: "\"nodejs\"" ---- -nodejs diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap deleted file mode 100644 index 3bfd9d8ad..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__rtx-tiny.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/plugins/install.rs -expression: "\"tiny\"" ---- -tiny diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-5.snap b/src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local-5.snap rename to src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-4.snap b/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local-4.snap rename to src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-6.snap b/src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local-6.snap rename to src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local-2.snap rename to src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local-3.snap rename to src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local.snap rename to src/cli/snapshots/rtx__cli__local__tests__local_remove.snap From 12d0257c472e67f17b6e1ecd0a164a7a272f8eb2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 16:20:12 -0600 Subject: [PATCH 0223/1891] chore: use alternate .tool-versions filename for tests (#172) this way it wont conflict --- .github/workflows/rtx.yml | 3 +++ e2e/run_all_tests | 2 -- e2e/run_test | 2 -- ...tx__cli__direnv__envrc__tests__direnv_envrc.snap | 4 ++-- src/cli/global.rs | 4 ++-- src/cli/local.rs | 5 +++-- src/config/config_file/mod.rs | 2 +- src/config/config_file/tool_versions.rs | 7 ++++--- src/env.rs | 2 +- src/file.rs | 13 ++++++++----- src/hook_env.rs | 2 +- src/test.rs | 6 +++--- src/toolset/tool_source.rs | 4 ++-- test/{.tool-versions => .test-tool-versions} | 0 test/cwd/{.tool-versions => .test-tool-versions} | 0 15 files changed, 30 insertions(+), 26 deletions(-) rename test/{.tool-versions => .test-tool-versions} (100%) rename test/cwd/{.tool-versions => .test-tool-versions} (100%) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 75d2901c4..c3662994f 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -28,6 +28,7 @@ jobs: uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + RUST_BACKTRACE: "1" with: timeout_minutes: 10 max_attempts: 3 @@ -52,6 +53,7 @@ jobs: uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + RUST_BACKTRACE: "1" with: timeout_minutes: 10 max_attempts: 3 @@ -141,6 +143,7 @@ jobs: uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + RUST_BACKTRACE: "1" with: timeout_minutes: 20 max_attempts: 3 diff --git a/e2e/run_all_tests b/e2e/run_all_tests index 33bdd3451..8e92aeb64 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -9,6 +9,4 @@ for f in $FILES; do continue fi "$ROOT/e2e/run_test" "$f" - rm -f "$ROOT/e2e/.tool-versions" - git checkout "$ROOT/.tool-versions" done diff --git a/e2e/run_test b/e2e/run_test index 9a75e664e..4d7a70a94 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -14,5 +14,3 @@ echo "Running $TEST" export HOME="$ROOT/e2e" cd "$(dirname "$TEST")" "./$(basename "$TEST")" - -rm -f "$ROOT/e2e/.tool-versions" diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index 0396da070..6a8570059 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -3,9 +3,9 @@ source: src/cli/direnv/envrc.rs expression: envrc --- ### Do not edit. This was autogenerated by 'asdf direnv envrc' ### -watch_file ~/cwd/.tool-versions +watch_file ~/cwd/.test-tool-versions watch_file ~/cwd/.node-version -watch_file ~/.tool-versions +watch_file ~/.test-tool-versions export JDXCODE_TINY=2.1.0 PATH_add ~/data/installs/jq/1.6/bin PATH_add ~/data/installs/tiny/2.1.0/bin diff --git a/src/cli/global.rs b/src/cli/global.rs index 9493eee85..be8499a8e 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -100,7 +100,7 @@ mod tests { #[test] fn test_global() { - let cf_path = dirs::HOME.join(".tool-versions"); + let cf_path = dirs::HOME.join(".test-tool-versions"); let orig = fs::read_to_string(&cf_path).ok(); let _ = fs::remove_file(&cf_path); @@ -122,7 +122,7 @@ mod tests { let err = assert_cli_err!("global", "invalid-plugin"); assert_str_eq!( err.to_string(), - "no version set for invalid-plugin in ~/.tool-versions" + "no version set for invalid-plugin in ~/.test-tool-versions" ); // can only request a version one plugin at a time diff --git a/src/cli/local.rs b/src/cli/local.rs index bd256d0fe..36e881808 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -133,7 +133,7 @@ mod tests { let stdout = assert_cli!("ls", "--current"); assert_str_eq!( grep(stdout, "tiny"), - "-> tiny 2.1.0 (set by ~/.tool-versions)" + "-> tiny 2.1.0 (set by ~/.test-tool-versions)" ); }); } @@ -201,6 +201,7 @@ mod tests { #[test] fn test_local_alias_path() { run_test(|| { + assert_cli!("install", "dummy@1.1.0"); let local_dummy_path = dirs::INSTALLS.join("dummy").join("1.1.0"); let path_arg = String::from("path:") + &local_dummy_path.to_string_lossy(); assert_cli!("alias", "set", "dummy", "m", &path_arg); @@ -233,7 +234,7 @@ mod tests { where T: FnOnce() + panic::UnwindSafe, { - let cf_path = dirs::CURRENT.join(".tool-versions"); + let cf_path = dirs::CURRENT.join(".test-tool-versions"); let orig = fs::read_to_string(&cf_path).unwrap(); let result = panic::catch_unwind(test); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 1b2b8fbdc..6c92ff4da 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -153,7 +153,7 @@ mod tests { Some(ConfigFileType::RtxRc) ); assert_eq!( - detect_config_file_type(Path::new("/foo/bar/.tool-versions")), + detect_config_file_type(Path::new("/foo/bar/.test-tool-versions")), Some(ConfigFileType::ToolVersions) ); assert_eq!( diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 7611063b1..07a818a6e 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -205,9 +205,10 @@ pub(crate) mod tests { #[test] fn test_parse() { - let tv = ToolVersions::from_file(dirs::CURRENT.join(".tool-versions").as_path()).unwrap(); - assert_eq!(tv.path, dirs::CURRENT.join(".tool-versions")); - assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.tool-versions): shellcheck@0.9.0, shfmt@3.5.1, nodejs@system"); + let tv = + ToolVersions::from_file(dirs::CURRENT.join(".test-tool-versions").as_path()).unwrap(); + assert_eq!(tv.path, dirs::CURRENT.join(".test-tool-versions")); + assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.test-tool-versions): shellcheck@0.9.0, shfmt@3.5.1, nodejs@system"); } #[test] diff --git a/src/env.rs b/src/env.rs index 9043cf67e..43f58f269 100644 --- a/src/env.rs +++ b/src/env.rs @@ -109,7 +109,7 @@ lazy_static! { None => vec![], }; pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String = if cfg!(test) { - ".tool-versions".into() + ".test-tool-versions".into() } else { var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) }; diff --git a/src/file.rs b/src/file.rs index da767babd..0c53b9764 100644 --- a/src/file.rs +++ b/src/file.rs @@ -123,20 +123,23 @@ mod tests { #[test] fn test_find_up() { let path = &dirs::CURRENT; - let filenames = vec![".rtxrc", ".rtxrc.toml", ".tool-versions"]; + let filenames = vec![".rtxrc", ".rtxrc.toml", ".test-tool-versions"]; #[allow(clippy::needless_collect)] let find_up = FindUp::new(path, &filenames).collect::>(); let mut find_up = find_up.into_iter(); - assert_eq!(find_up.next(), Some(dirs::HOME.join("cwd/.tool-versions"))); - assert_eq!(find_up.next(), Some(dirs::HOME.join(".tool-versions"))); + assert_eq!( + find_up.next(), + Some(dirs::HOME.join("cwd/.test-tool-versions")) + ); + assert_eq!(find_up.next(), Some(dirs::HOME.join(".test-tool-versions"))); } #[test] fn test_find_up_2() { let path = &dirs::HOME.join("fixtures"); - let filenames = vec![".tool-versions"]; + let filenames = vec![".test-tool-versions"]; let result = find_up(path, &filenames); - assert_eq!(result, Some(dirs::HOME.join(".tool-versions"))); + assert_eq!(result, Some(dirs::HOME.join(".test-tool-versions"))); } #[test] diff --git a/src/hook_env.rs b/src/hook_env.rs index 27af6eac9..7c146a492 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -101,7 +101,7 @@ mod tests { let files = HashSet::new(); assert!(have_config_files_been_modified(&env, files)); - let fp = dirs::CURRENT.join(".tool-versions"); + let fp = dirs::CURRENT.join(".test-tool-versions"); env.insert( "__RTX_WATCH".into(), serialize_watches(&HookEnvWatches::from([(fp.clone(), UNIX_EPOCH)])).unwrap(), diff --git a/src/test.rs b/src/test.rs index 7ccaba075..9afc632a8 100644 --- a/src/test.rs +++ b/src/test.rs @@ -8,12 +8,12 @@ use crate::{assert_cli, cmd, env}; fn init() { env::set_var("NO_COLOR", "1"); env_logger::init(); - let _ = fs::remove_dir_all("test/data/legacy_cache"); + let _ = fs::remove_dir_all("test/cache"); if let Err(err) = cmd!( "git", "checkout", - "test/.tool-versions", - "test/cwd/.tool-versions", + "test/.test-tool-versions", + "test/cwd/.test-tool-versions", "test/config/config.toml" ) .run() diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index c49772c38..85463a8e4 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -33,10 +33,10 @@ mod tests { #[test] fn test_tool_source_display() { - let path = PathBuf::from("/home/user/.tool-versions"); + let path = PathBuf::from("/home/user/.test-tool-versions"); let ts = ToolSource::ToolVersions(path); - assert_str_eq!(ts.to_string(), "/home/user/.tool-versions"); + assert_str_eq!(ts.to_string(), "/home/user/.test-tool-versions"); let ts = ToolSource::Argument; assert_str_eq!(ts.to_string(), "--runtime"); diff --git a/test/.tool-versions b/test/.test-tool-versions similarity index 100% rename from test/.tool-versions rename to test/.test-tool-versions diff --git a/test/cwd/.tool-versions b/test/cwd/.test-tool-versions similarity index 100% rename from test/cwd/.tool-versions rename to test/cwd/.test-tool-versions From a80156596d50b4a615a33ec0c7784a41e2f114d4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 16:31:40 -0600 Subject: [PATCH 0224/1891] bug: fix order of env and path when using multiple versions (#170) --- .tool-versions | 1 + e2e/cd/test_bash | 6 ++--- ...i__direnv__envrc__tests__direnv_envrc.snap | 4 +-- src/cli/env.rs | 4 +-- src/cli/local.rs | 7 +++++ src/cli/mod.rs | 1 + ...cal__tests__local_multiple_versions-2.snap | 11 ++++++++ ...local__tests__local_multiple_versions.snap | 11 ++++++++ src/toolset/mod.rs | 26 +++++++++---------- 9 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap create mode 100644 src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap diff --git a/.tool-versions b/.tool-versions index c638108e3..6caabc71c 100644 --- a/.tool-versions +++ b/.tool-versions @@ -3,3 +3,4 @@ shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 jq latest +tiny 2 1 3 diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 786f20ad3..5fe8e0401 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -20,12 +20,12 @@ assert_path() { } test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/jq/1.6/bin" cd 16 && _rtx_hook test "$(node -v)" = "v16.0.0" -assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin" +assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/jq/1.6/bin" cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/jq/1.6/bin" diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index 6a8570059..180fc2b7f 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -7,8 +7,8 @@ watch_file ~/cwd/.test-tool-versions watch_file ~/cwd/.node-version watch_file ~/.test-tool-versions export JDXCODE_TINY=2.1.0 -PATH_add ~/data/installs/jq/1.6/bin PATH_add ~/data/installs/tiny/2.1.0/bin -PATH_add ~/data/installs/shellcheck/0.9.0/bin +PATH_add ~/data/installs/jq/1.6/bin PATH_add ~/data/installs/shfmt/3.5.1/bin +PATH_add ~/data/installs/shellcheck/0.9.0/bin diff --git a/src/cli/env.rs b/src/cli/env.rs index c6bbb632a..8067c0287 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -110,8 +110,8 @@ mod tests { #[test] fn test_env_tiny() { - let stdout = assert_cli!("env", "tiny@1", "-s", "bash"); - assert_str_eq!(grep(stdout, "JDXCODE"), "export JDXCODE_TINY=1.0.1"); + let stdout = assert_cli!("env", "tiny@2", "tiny@1", "tiny@3", "-s", "bash"); + assert_str_eq!(grep(stdout, "JDXCODE"), "export JDXCODE_TINY=2.1.0"); } #[test] diff --git a/src/cli/local.rs b/src/cli/local.rs index 36e881808..b657f4cca 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -168,6 +168,13 @@ mod tests { }); } #[test] + fn test_local_multiple_versions() { + run_test(|| { + assert_cli_snapshot!("local", "tiny@2", "tiny@1", "tiny@3"); + assert_cli_snapshot!("bin-paths"); + }); + } + #[test] fn test_local_output_current_version() { run_test(|| { assert_cli!("local", "tiny", "2"); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 17851eaba..027dcf82f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -243,6 +243,7 @@ pub mod tests { let args = &vec!["rtx".into(), $($args.into()),+]; let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; let output = console::strip_ansi_codes(&output).to_string(); + let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); assert_snapshot!(output); }}; } diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap new file mode 100644 index 000000000..fd548215c --- /dev/null +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap @@ -0,0 +1,11 @@ +--- +source: src/cli/local.rs +expression: output +--- +~/data/installs/shellcheck/0.9.0/bin +~/data/installs/shfmt/3.5.1/bin +~/data/installs/tiny/2.1.0/bin +~/data/installs/tiny/1.0.1/bin +~/data/installs/tiny/3.1.0/bin +~/data/installs/jq/1.6/bin + diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap new file mode 100644 index 000000000..237d91cb2 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap @@ -0,0 +1,11 @@ +--- +source: src/cli/local.rs +expression: output +--- +#python 3.11.1 3.10.9 # foo +shellcheck 0.9.0 +shfmt 3.5.1 # test comment +#nodejs 18.13.0 +nodejs system +tiny 2 1 3 + diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 69c603bde..d8be385aa 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -7,7 +7,6 @@ use color_eyre::eyre::Result; use console::style; use indexmap::IndexMap; use itertools::Itertools; - use rayon::prelude::*; use rayon::ThreadPoolBuilder; @@ -22,7 +21,6 @@ use crate::env; use crate::plugins::{InstallType, Plugin, PluginName}; use crate::runtimes::RuntimeVersion; use crate::toolset::tool_version_list::ToolVersionList; - use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; @@ -61,13 +59,13 @@ impl Toolset { .or_insert_with(|| ToolVersionList::new(self.source.clone().unwrap())); versions.add_version(version); } - pub fn merge(&mut self, other: Toolset) { - for plugin in other.versions.keys() { - self.versions.shift_remove(plugin); - } - for (plugin, versions) in other.versions { - self.versions.insert(plugin, versions); + pub fn merge(&mut self, mut other: Toolset) { + for (plugin, versions) in self.versions.clone() { + if !other.versions.contains_key(&plugin) { + other.versions.insert(plugin, versions); + } } + self.versions = other.versions; // swap to use other's first self.source = other.source; } pub fn resolve(&mut self, config: &Config) { @@ -247,19 +245,22 @@ impl Toolset { .collect() } pub fn env(&self) -> IndexMap { - let mut entries: Vec<(String, String)> = self + let mut entries: IndexMap = self .list_current_installed_versions() .into_par_iter() - .flat_map(|p| match p.exec_env() { + .flat_map(|v| match v.exec_env() { Ok(env) => env.into_iter().collect(), Err(e) => { warn!("Error running exec-env: {}", e); Vec::new() } }) + .collect::>() + .into_iter() + .rev() .collect(); - entries.par_sort(); - entries.into_iter().collect() + entries.sort_keys(); + entries } pub fn path_env(&self) -> String { let installs = self.list_paths(); @@ -271,7 +272,6 @@ impl Toolset { pub fn list_paths(&self) -> Vec { self.list_current_installed_versions() .into_par_iter() - .rev() .flat_map(|rtv| match rtv.list_bin_paths() { Ok(paths) => paths, Err(e) => { From 626b03e2b6eb5dd9b4f3cd130766b46b78ed408c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 16:33:10 -0600 Subject: [PATCH 0225/1891] chore: Release rtx-cli version 1.14.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f18902f3c..8bc71ba04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.13.0" +version = "1.14.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index f7c9260fe..56982c50d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.13.0" +version = "1.14.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 469abc243..ac6fbf0c7 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.13.0 +rtx 1.14.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -197,7 +197,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.13.0/rtx-v1.13.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.0/rtx-v1.14.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 840c9911d..6e58daca1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.13.0 +Version: 1.14.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index fac68db75..70a6834b7 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -216,7 +216,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.13.0/rtx-v1.13.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.0/rtx-v1.14.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 858433474933ccf1981665e93fa610dbb072fba0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 17:43:41 -0600 Subject: [PATCH 0226/1891] chore: fix ssh-agent gh action --- .github/workflows/rtx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index c3662994f..baa4ab06c 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -228,7 +228,7 @@ jobs: aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - name: ssh key - uses: webfactory/ssh-agent@0.7.0 + uses: webfactory/ssh-agent@v0.7.0 with: ssh-private-key: ${{ secrets.RTX_SSH_KEY }} - uses: crazy-max/ghaction-import-gpg@v5 From a7fb6bc9cc25eefdcafb7256bf5466b2eeda54a6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 17:44:40 -0600 Subject: [PATCH 0227/1891] chore: Release rtx-cli version 1.14.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bc71ba04..9dcfeac1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.14.0" +version = "1.14.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 56982c50d..c93f4e364 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.14.0" +version = "1.14.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index ac6fbf0c7..4cd0a083a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.14.0 +rtx 1.14.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -197,7 +197,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.0/rtx-v1.14.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.1/rtx-v1.14.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6e58daca1..9cbac66e2 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.14.0 +Version: 1.14.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 70a6834b7..bf0d79d13 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -216,7 +216,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.0/rtx-v1.14.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.1/rtx-v1.14.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 2cba1bbf8d7bdc9eb2a406bee931f3ab2e266336 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 18:08:25 -0600 Subject: [PATCH 0228/1891] chore: fix release-aur directory --- .github/workflows/rtx.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index baa4ab06c..dd7900ea4 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -253,7 +253,9 @@ jobs: draft: false files: releases/${{github.ref_name}}/* generate_release_notes: true - - run: rtx/scripts/release-aur.sh + - name: Release to aur + run: rtx/scripts/release-aur.sh + working-directory: rtx bump-homebrew-formula: runs-on: macos-latest if: startsWith(github.event.ref, 'refs/tags/v') From 6ef8d022dff0434cbfae9fa8ee2743583abb7abe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 18:08:51 -0600 Subject: [PATCH 0229/1891] chore: Release rtx-cli version 1.14.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9dcfeac1d..fc98dbd15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.14.1" +version = "1.14.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index c93f4e364..3e0cfa28f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.14.1" +version = "1.14.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 4cd0a083a..a4fd32b69 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.14.1 +rtx 1.14.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -197,7 +197,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.1/rtx-v1.14.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.2/rtx-v1.14.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9cbac66e2..ec63c6dd7 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.14.1 +Version: 1.14.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index bf0d79d13..2cd48d154 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -216,7 +216,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.1/rtx-v1.14.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.2/rtx-v1.14.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From e73e8fc03952a345e3f592a5c8013c73aae3a7fe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 18:49:28 -0600 Subject: [PATCH 0230/1891] chore: add coverage to E2E tests (#173) Fixes #96 --- .github/workflows/rtx.yml | 22 +++++++++++++++------- justfile | 13 ++++++++++--- scripts/update-shorthand-repo.sh | 1 + src/shorthand_list.rs | 1 + 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index dd7900ea4..321a18673 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -20,6 +20,8 @@ jobs: uses: actions/checkout@v3 - name: Rust Cache uses: Swatinem/rust-cache@v2 + with: + save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' - name: Install direnv run: sudo apt-get update; sudo apt-get install direnv - name: Install just @@ -37,16 +39,17 @@ jobs: coverage: runs-on: ubuntu-latest - container: - image: xd009642/tarpaulin:develop-nightly - options: --security-opt seccomp=unconfined steps: - name: Checkout uses: actions/checkout@v3 + - run: rustup toolchain install nightly --component llvm-tools-preview - name: Rust Cache uses: Swatinem/rust-cache@v2 - - name: Install direnv - run: apt-get update; apt-get install direnv + with: + save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' + - uses: taiki-e/install-action@cargo-llvm-cov + - name: Install zsh/fish/direnv + run: sudo apt-get update; sudo apt-get install zsh fish direnv - name: Install just uses: taiki-e/install-action@just - name: Run tests with coverage @@ -62,6 +65,7 @@ jobs: uses: codecov/codecov-action@v3 with: fail_ci_if_error: false + files: lcov.info build-linux: name: build-${{matrix.target}} @@ -81,7 +85,9 @@ jobs: override: true - name: Rust Cache uses: Swatinem/rust-cache@v2 - with: { key: "${{matrix.target}}" } + with: + key: "${{matrix.target}}" + save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' - uses: actions-rs/cargo@v1 with: use-cross: true @@ -114,7 +120,9 @@ jobs: override: true - name: Rust Cache uses: Swatinem/rust-cache@v2 - with: { key: "${{matrix.target}}" } + with: + key: "${{matrix.target}}" + save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' - run: cargo build --release --all-features --target ${{matrix.target}} - run: scripts/build-tarball.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 diff --git a/justfile b/justfile index e5b4d9d54..ede31eb3e 100644 --- a/justfile +++ b/justfile @@ -37,9 +37,16 @@ test-e2e: test-setup build # run unit tests w/ coverage test-coverage: - cargo +nightly tarpaulin \ - --all-features --workspace \ - --timeout 120 --out Xml --ignore-tests + #!/usr/bin/env bash + set -euxo pipefail + source <(cargo llvm-cov show-env --export-prefix) + cargo llvm-cov clean --workspace + + cargo test + cargo build + PATH="$PWD/target/debug:$PATH" ./e2e/run_all_tests + cargo llvm-cov report --html + cargo llvm-cov report --lcov --output-path lcov.info # delete built files clean: diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index cb1a5b766..3ae09fec2 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -13,6 +13,7 @@ cat > src/shorthand_list.rs < Date: Tue, 21 Feb 2023 18:18:34 -0600 Subject: [PATCH 0231/1891] chore: fix release-aur script --- .bin/rtx | 3 --- .github/workflows/rtx.yml | 8 ++++---- scripts/release-aur.sh | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index 36a087b2c..5d8552b60 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -1,8 +1,5 @@ #!/bin/bash set -e -# add this directory to `$PATH` to automatically build/run chim -# when chims are called in shebangs - SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cargo run --all-features --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 321a18673..b70f594c9 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -235,10 +235,10 @@ jobs: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - - name: ssh key - uses: webfactory/ssh-agent@v0.7.0 + - uses: shimataro/ssh-key-action@v2 with: - ssh-private-key: ${{ secrets.RTX_SSH_KEY }} + key: ${{ secrets.RTX_SSH_KEY }} + known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} - uses: crazy-max/ghaction-import-gpg@v5 with: gpg_private_key: ${{ secrets.GPG_KEY }} @@ -262,7 +262,7 @@ jobs: files: releases/${{github.ref_name}}/* generate_release_notes: true - name: Release to aur - run: rtx/scripts/release-aur.sh + run: scripts/release-aur.sh working-directory: rtx bump-homebrew-formula: runs-on: macos-latest diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index b0e4047c1..fd56a49d5 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -11,7 +11,7 @@ fi git -C aur pull cat >aur/PKGBUILD < +# Maintainer: Jeff Dickey pkgname=rtx pkgver=${RTX_VERSION#v*} From 39fa796a1764ee31e59df9b0634885ba640d02e1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 18:53:08 -0600 Subject: [PATCH 0232/1891] chore: Release rtx-cli version 1.14.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc98dbd15..2a46f33d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.14.2" +version = "1.14.3" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 3e0cfa28f..a20d9a040 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.14.2" +version = "1.14.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a4fd32b69..1498665e7 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.14.2 +rtx 1.14.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -197,7 +197,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.2/rtx-v1.14.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.3/rtx-v1.14.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ec63c6dd7..0ea6701aa 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.14.2 +Version: 1.14.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 2cd48d154..6ab00c3ba 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -216,7 +216,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.2/rtx-v1.14.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.3/rtx-v1.14.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 1f1b2e2cb85b47cb2b3ae5cd3167bc639912c360 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 19:43:03 -0600 Subject: [PATCH 0233/1891] feat: add padding to .tool-versions output (#174) Fixes #165 --- .tool-versions | 8 +++----- e2e/.e2e-tool-versions | 6 +++--- e2e/test_local | 18 +++++++++--------- src/cli/local.rs | 18 +++++++++--------- .../rtx__cli__global__tests__global-4.snap | 2 +- ..._local__tests__local_multiple_versions.snap | 6 +++--- ...rtx__cli__local__tests__local_remove-2.snap | 6 +++--- ...rtx__cli__local__tests__local_remove-3.snap | 4 ++-- .../rtx__cli__local__tests__local_remove.snap | 6 +++--- src/config/config_file/tool_versions.rs | 10 +++++++++- test/.test-tool-versions | 4 ++-- 11 files changed, 47 insertions(+), 41 deletions(-) diff --git a/.tool-versions b/.tool-versions index 6caabc71c..a1226bb30 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,6 +1,4 @@ -#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.6.0 # test comment -#nodejs 18.13.0 -jq latest -tiny 2 1 3 +shfmt 3.6.0 +jq latest +tiny 2 1 3 diff --git a/e2e/.e2e-tool-versions b/e2e/.e2e-tool-versions index c638108e3..754fc4c54 100644 --- a/e2e/.e2e-tool-versions +++ b/e2e/.e2e-tool-versions @@ -1,5 +1,5 @@ #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.6.0 # test comment -#nodejs 18.13.0 -jq latest +shfmt 3.6.0 # test comment +#nodejs 18.13.0 +jq latest diff --git a/e2e/test_local b/e2e/test_local index 2be6fc516..006c923ef 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -22,16 +22,16 @@ assert_raises "rtx uninstall shfmt@3.6.0" assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.6.0 # test comment -#nodejs 18.13.0 -jq latest +shfmt 3.6.0 # test comment +#nodejs 18.13.0 +jq latest " assert "rtx local shfmt@3.5.0" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.5.0 # test comment -#nodejs 18.13.0 -jq latest +shfmt 3.5.0 # test comment +#nodejs 18.13.0 +jq latest " rtx exec -- shfmt --version >&2 @@ -41,9 +41,9 @@ fi assert "rtx local shfmt@3.6.0" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.6.0 # test comment -#nodejs 18.13.0 -jq latest +shfmt 3.6.0 # test comment +#nodejs 18.13.0 +jq latest " rtx exec -- shfmt --version >&2 diff --git a/src/cli/local.rs b/src/cli/local.rs index b657f4cca..5ea978b78 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -141,30 +141,30 @@ mod tests { fn test_local_pin() { run_test(|| { let stdout = assert_cli!("local", "--pin", "tiny@1"); - assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); let stdout = assert_cli!("local", "--pin", "tiny", "2"); - assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); }); } #[test] fn test_local_path() { run_test(|| { let stdout = assert_cli!("local", "dummy@path:."); - assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); + assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); }); } #[test] fn test_local_ref() { run_test(|| { let stdout = assert_cli!("local", "dummy@ref:master"); - assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); + assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); }); } #[test] fn test_local_prefix() { run_test(|| { let stdout = assert_cli!("local", "dummy@prefix:1"); - assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); + assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); }); } #[test] @@ -201,7 +201,7 @@ mod tests { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "ref:master"); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); } @@ -213,7 +213,7 @@ mod tests { let path_arg = String::from("path:") + &local_dummy_path.to_string_lossy(); assert_cli!("alias", "set", "dummy", "m", &path_arg); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); let stdout = assert_cli!("current", "dummy"); assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); }); @@ -223,7 +223,7 @@ mod tests { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "prefix:1"); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); } @@ -232,7 +232,7 @@ mod tests { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "system"); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); } diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap index 18f952f79..7a3cdb8cb 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap @@ -3,5 +3,5 @@ source: src/cli/global.rs expression: stdout --- shfmt 2 -tiny 2.1.0 +tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap index 237d91cb2..b28497c7b 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap @@ -4,8 +4,8 @@ expression: output --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.5.1 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 -nodejs system -tiny 2 1 3 +nodejs system +tiny 2 1 3 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap index aea5835d1..2353b11ac 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap @@ -4,8 +4,8 @@ expression: output --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.5.1 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 -nodejs system -tiny 2 +nodejs system +tiny 2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap index 49777dd15..cfb4547c2 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap @@ -4,7 +4,7 @@ expression: output --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.5.1 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 -nodejs system +nodejs system diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap index 42c952e30..5e220952e 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap @@ -4,8 +4,8 @@ expression: output --- #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 -shfmt 3.5.1 # test comment +shfmt 3.5.1 # test comment #nodejs 18.13.0 -nodejs system -tiny 2.1.0 +nodejs system +tiny 2.1.0 diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 07a818a6e..ff949cf28 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -5,6 +5,7 @@ use std::fs::read_to_string; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; +use console::{measure_text_width, pad_str, Alignment}; use indexmap::IndexMap; use itertools::Itertools; @@ -179,7 +180,14 @@ impl ConfigFile for ToolVersions { fn dump(&self) -> String { let mut s = self.pre.clone(); + let max_plugin_len = self + .plugins + .keys() + .map(|p| measure_text_width(p)) + .max() + .unwrap_or_default(); for (plugin, tv) in &self.plugins { + let plugin = pad_str(plugin, max_plugin_len, Alignment::Left, None); s.push_str(&format!("{} {}{}", plugin, tv.versions.join(" "), tv.post)); } @@ -217,7 +225,7 @@ pub(crate) mod tests { # intro comment python 3.11.0 3.10.0 # some comment # more comment #shellcheck 0.9.0 - shfmt 3.6.0 + shfmt 3.6.0 # tail comment "}; let tv = ToolVersions::parse_str(orig).unwrap(); diff --git a/test/.test-tool-versions b/test/.test-tool-versions index 5712a47c9..a4d4d0dc0 100644 --- a/test/.test-tool-versions +++ b/test/.test-tool-versions @@ -1,3 +1,3 @@ shfmt 2 -jq 1.6 -tiny 2 +jq 1.6 +tiny 2 From 443936016a78c9adeefae945953ac15bbfa5f410 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 19:51:03 -0600 Subject: [PATCH 0234/1891] docs: correct shortname -> shorthand --- README.md | 2 +- src/cli/plugins/install.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1498665e7..da5ddeb1b 100644 --- a/README.md +++ b/README.md @@ -1172,7 +1172,7 @@ Options: -a, --all Install all missing plugins - This will only install plugins that have matching shortnames. + This will only install plugins that have matching shorthands. i.e.: they don't need the full git repo url -v, --verbose... diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 305a21b92..137239284 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -39,7 +39,7 @@ pub struct PluginsInstall { /// Install all missing plugins /// - /// This will only install plugins that have matching shortnames. + /// This will only install plugins that have matching shorthands. /// i.e.: they don't need the full git repo url #[clap(short, long, conflicts_with_all = ["name", "force"], verbatim_doc_comment)] all: bool, From f30d35201e0a2cdafaa9dec900a64e4ad86ce7c5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 19:54:55 -0600 Subject: [PATCH 0235/1891] feat: add RTX_ASDF_COMPAT setting (#175) Fixes #168 --- README.md | 26 ++++++++++++++++--- completions/_rtx | 6 ++--- completions/rtx.fish | 6 ++--- src/cli/global.rs | 15 +++++++---- src/cli/local.rs | 13 +++++++--- src/cli/render_help.rs | 10 ++++++- ...cli__settings__ls__tests__settings_ls.snap | 1 + ...i__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + src/config/settings.rs | 10 ++++++- src/env.rs | 1 + 11 files changed, 69 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index da5ddeb1b..d63b99ce8 100644 --- a/README.md +++ b/README.md @@ -385,8 +385,8 @@ always_keep_download = false # deleted after install by default plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. - verbose = false # see explanation under `RTX_VERBOSE` +asdf_compat = false # see explanation under `RTX_ASDF_COMPAT` [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x @@ -459,6 +459,14 @@ This shows the installation output during `rtx install` and `rtx plugin install` This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have 2 configuration for the same thing, but for now it is it's own config. +#### `RTX_ASDF_COMPAT=1` + +Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. + +Currently this disables the following: + +* `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) + #### `RTX_HIDE_OUTDATED_BUILD=1` If a release is 12 months old, it will show a warning message every time it launches: @@ -913,9 +921,14 @@ Arguments: Options: --pin - save exact version to `.tool-versions` + save exact version to `~/.tool-versions` + + e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions + + --fuzzy + save fuzzy version to `~/.tool-versions` - e.g.: `rtx global --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, + e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove remove the plugin(s) from ~/.tool-versions @@ -1048,7 +1061,12 @@ Options: --pin save exact version to `.tool-versions` - e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, + e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions + + --fuzzy + save fuzzy version to `.tool-versions` + + e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove remove the plugin(s) from .tool-versions diff --git a/completions/_rtx b/completions/_rtx index a1bb97227..a28ba7190 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -418,8 +418,8 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--pin[save exact version to `.tool-versions`]' \ -'--fuzzy[]' \ +'--pin[save exact version to `~/.tool-versions`]' \ +'--fuzzy[save fuzzy version to `~/.tool-versions`]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -496,7 +496,7 @@ by default this command will only set the runtime in the current directory ("$PW '--parent[recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--pin[save exact version to `.tool-versions`]' \ -'--fuzzy[]' \ +'--fuzzy[save fuzzy version to `.tool-versions`]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 215a8ab70..95dca0663 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -153,8 +153,8 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print hel complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'save exact version to `.tool-versions`' -complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy +complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'save exact version to `~/.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'save fuzzy version to `~/.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" @@ -186,7 +186,7 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'save exact version to `.tool-versions`' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'save fuzzy version to `.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r diff --git a/src/cli/global.rs b/src/cli/global.rs index be8499a8e..df5fbc539 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -26,13 +26,17 @@ pub struct Global { #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, - /// save exact version to `.tool-versions` + /// save exact version to `~/.tool-versions` /// - /// e.g.: `rtx global --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, - #[clap(long, verbatim_doc_comment)] + /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions + #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, - #[clap(long, hide = true)] + /// save fuzzy version to `~/.tool-versions` + /// + /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions + /// this is the default behavior unless RTX_ASDF_COMPAT=1 + #[clap(long, overrides_with = "pin")] fuzzy: bool, /// remove the plugin(s) from ~/.tool-versions @@ -59,7 +63,8 @@ impl Command for Global { if cf.display_runtime(out, &runtimes)? { return Ok(()); } - cf.add_runtimes(&config, &runtimes, self.pin)?; + let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); + cf.add_runtimes(&config, &runtimes, pin)?; } if self.runtime.is_some() || self.remove.is_some() { diff --git a/src/cli/local.rs b/src/cli/local.rs index 5ea978b78..d81827212 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -33,11 +33,15 @@ pub struct Local { /// save exact version to `.tool-versions` /// - /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions, - #[clap(long, verbatim_doc_comment)] + /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions + #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, - #[clap(long, hide = true)] + /// save fuzzy version to `.tool-versions` + /// + /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions + /// this is the default behavior unless RTX_ASDF_COMPAT=1 + #[clap(long, overrides_with = "pin")] fuzzy: bool, /// remove the plugin(s) from .tool-versions @@ -77,7 +81,8 @@ impl Command for Local { if cf.display_runtime(out, &runtimes)? { return Ok(()); } - cf.add_runtimes(&config, &runtimes, self.pin)?; + let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); + cf.add_runtimes(&config, &runtimes, pin)?; } if self.runtime.is_some() || self.remove.is_some() { diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 6ab00c3ba..0ffc7bd37 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -404,8 +404,8 @@ always_keep_download = false # deleted after install by default plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. - verbose = false # see explanation under `RTX_VERBOSE` +asdf_compat = false # see explanation under `RTX_ASDF_COMPAT` [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x @@ -478,6 +478,14 @@ This shows the installation output during `rtx install` and `rtx plugin install` This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have 2 configuration for the same thing, but for now it is it's own config. +#### `RTX_ASDF_COMPAT=1` + +Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. + +Currently this disables the following: + +* `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) + #### `RTX_HIDE_OUTDATED_BUILD=1` If a release is 12 months old, it will show a warning message every time it launches: diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index bfeaf6805..0b93ad1bc 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -7,6 +7,7 @@ always_keep_download = true legacy_version_file = true plugin_autoupdate_last_check_duration = 20 verbose = true +asdf_compat = false jobs = 2 log_level = INFO diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 7c9d6d68b..fb6210f9d 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -7,6 +7,7 @@ always_keep_download = true legacy_version_file = false plugin_autoupdate_last_check_duration = 1 verbose = true +asdf_compat = false jobs = 2 log_level = INFO diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index f535bc007..b19af4c47 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -53,6 +53,7 @@ mod tests { legacy_version_file = true plugin_autoupdate_last_check_duration = 20 verbose = true + asdf_compat = false jobs = 2 log_level = INFO "###); diff --git a/src/config/settings.rs b/src/config/settings.rs index 57ad233f9..6adb2ac68 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -6,7 +6,7 @@ use log::LevelFilter; use crate::config::AliasMap; use crate::env; -use crate::env::{RTX_JOBS, RTX_LOG_LEVEL, RTX_VERBOSE}; +use crate::env::{RTX_ASDF_COMPAT, RTX_JOBS, RTX_LOG_LEVEL, RTX_VERBOSE}; use crate::plugins::PluginName; #[derive(Debug, Clone)] @@ -17,6 +17,7 @@ pub struct Settings { pub plugin_autoupdate_last_check_duration: Duration, pub aliases: IndexMap>, pub verbose: bool, + pub asdf_compat: bool, pub jobs: usize, pub log_level: LevelFilter, } @@ -30,6 +31,7 @@ impl Default for Settings { plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), aliases: IndexMap::new(), verbose: *RTX_VERBOSE || !console::user_attended_stderr(), + asdf_compat: *RTX_ASDF_COMPAT, jobs: *RTX_JOBS, log_level: *RTX_LOG_LEVEL, } @@ -56,6 +58,7 @@ impl Settings { (self.plugin_autoupdate_last_check_duration.as_secs() / 60).to_string(), ); map.insert("verbose".into(), self.verbose.to_string()); + map.insert("asdf_compat".into(), self.asdf_compat.to_string()); map.insert("jobs".into(), self.jobs.to_string()); map.insert("log_level".into(), self.log_level.to_string()); map @@ -70,6 +73,7 @@ pub struct SettingsBuilder { pub plugin_autoupdate_last_check_duration: Option, pub aliases: Option, pub verbose: Option, + pub asdf_compat: Option, pub jobs: Option, pub log_level: Option, } @@ -98,6 +102,9 @@ impl SettingsBuilder { if other.verbose.is_some() { self.verbose = other.verbose; } + if other.asdf_compat.is_some() { + self.asdf_compat = other.asdf_compat; + } if other.jobs.is_some() { self.jobs = other.jobs; } @@ -136,6 +143,7 @@ impl SettingsBuilder { .plugin_autoupdate_last_check_duration .unwrap_or(settings.plugin_autoupdate_last_check_duration); settings.verbose = self.verbose.unwrap_or(settings.verbose); + settings.asdf_compat = self.asdf_compat.unwrap_or(settings.asdf_compat); settings.jobs = self.jobs.unwrap_or(settings.jobs); settings.aliases = self.aliases.clone().unwrap_or(settings.aliases); diff --git a/src/env.rs b/src/env.rs index 43f58f269..0355e1b9d 100644 --- a/src/env.rs +++ b/src/env.rs @@ -117,6 +117,7 @@ lazy_static! { pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); pub static ref RTX_PREFER_STALE: bool = prefer_stale(&ARGS); + pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); } fn get_env_diff() -> EnvDiff { From 0a8b4cac1354f84a44a8b6cad2c2738d62d0014f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:25:31 -0600 Subject: [PATCH 0236/1891] feat: added `RTX_DISABLE_DEFAULT_SHORTHANDS` config (#176) See #163 --- README.md | 20 ++++++++++++------- src/cli/plugins/install.rs | 14 ++++++++----- src/cli/plugins/ls_remote.rs | 4 ++++ src/cli/render_help.rs | 20 ++++++++++++------- ...cli__settings__ls__tests__settings_ls.snap | 1 + ...i__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + src/config/settings.rs | 17 +++++++++++++++- src/env.rs | 1 + src/plugins/mod.rs | 2 +- src/shorthand.rs | 9 +++++++-- 11 files changed, 67 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index d63b99ce8..56150ff5d 100644 --- a/README.md +++ b/README.md @@ -384,9 +384,10 @@ always_keep_download = false # deleted after install by default # (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates -jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. -verbose = false # see explanation under `RTX_VERBOSE` -asdf_compat = false # see explanation under `RTX_ASDF_COMPAT` +verbose = false # set to true to see full installation output, see `RTX_VERBOSE` +asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` +jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. +disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x @@ -449,10 +450,6 @@ Output logs to a file. Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want to store the logs but not have them litter your display. -#### `RTX_JOBS=1` - -Set the number plugins or runtimes to install in parallel. The default is `4`. - #### `RTX_VERBOSE=1` This shows the installation output during `rtx install` and `rtx plugin install`. @@ -463,6 +460,15 @@ This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don' Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. +#### `RTX_JOBS=1` + +Set the number plugins or runtimes to install in parallel. The default is `4`. + +#### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` + +Disables the shorthand aliases for installing plugins. You will have to specify full urls when +installing plugins, e.g.: `rtx plugin install nodejs https://github.com/asdf-vm/asdf-nodejs.git` + Currently this disables the following: * `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 137239284..3e3a5c3c9 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -5,7 +5,7 @@ use once_cell::sync::Lazy; use url::Url; use crate::cli::command::Command; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::output::Output; use crate::plugins::Plugin; use crate::shorthand::shorthand_to_repository; @@ -54,7 +54,7 @@ impl Command for PluginsInstall { if self.all { return self.install_all_missing_plugins(&config); } - let (name, git_url) = get_name_and_url(self.name.unwrap(), self.git_url)?; + let (name, git_url) = get_name_and_url(&config.settings, self.name.unwrap(), self.git_url)?; let plugin = Plugin::new(&name); if self.force { plugin.uninstall()?; @@ -79,7 +79,7 @@ impl PluginsInstall { } for plugin in missing_plugins { let plugin = Plugin::new(&plugin); - let (_, git_url) = get_name_and_url(plugin.name.clone(), None)?; + let (_, git_url) = get_name_and_url(&config.settings, plugin.name.clone(), None)?; plugin.install( &config.settings, Some(&git_url), @@ -90,13 +90,17 @@ impl PluginsInstall { } } -fn get_name_and_url(name: String, git_url: Option) -> Result<(String, String)> { +fn get_name_and_url( + settings: &Settings, + name: String, + git_url: Option, +) -> Result<(String, String)> { Ok(match git_url { Some(url) => (name, url), None => match name.contains(':') { true => (get_name_from_url(&name)?, name), false => { - let git_url = shorthand_to_repository(&name) + let git_url = shorthand_to_repository(settings, &name) .ok_or_else(|| eyre!("could not find plugin {}", name))?; (name, git_url.to_string()) } diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index ffed9abc2..311bae5df 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -30,6 +30,10 @@ impl Command for PluginsLsRemote { .map(|p| p.name.clone()) .collect::>(); + if config.settings.disable_default_shorthands { + warn!("default shorthands are disabled"); + return Ok(()); + } for (plugin, repo) in SHORTHAND_MAP.iter().sorted().collect_vec() { let installed = if installed_plugins.contains(*plugin) { "*" diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 0ffc7bd37..4fdd89234 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -403,9 +403,10 @@ always_keep_download = false # deleted after install by default # (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates -jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. -verbose = false # see explanation under `RTX_VERBOSE` -asdf_compat = false # see explanation under `RTX_ASDF_COMPAT` +verbose = false # set to true to see full installation output, see `RTX_VERBOSE` +asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` +jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. +disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x @@ -468,10 +469,6 @@ Output logs to a file. Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want to store the logs but not have them litter your display. -#### `RTX_JOBS=1` - -Set the number plugins or runtimes to install in parallel. The default is `4`. - #### `RTX_VERBOSE=1` This shows the installation output during `rtx install` and `rtx plugin install`. @@ -482,6 +479,15 @@ This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don' Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. +#### `RTX_JOBS=1` + +Set the number plugins or runtimes to install in parallel. The default is `4`. + +#### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` + +Disables the shorthand aliases for installing plugins. You will have to specify full urls when +installing plugins, e.g.: `rtx plugin install nodejs https://github.com/asdf-vm/asdf-nodejs.git` + Currently this disables the following: * `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 0b93ad1bc..76318d293 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -9,5 +9,6 @@ plugin_autoupdate_last_check_duration = 20 verbose = true asdf_compat = false jobs = 2 +disable_default_shorthands = false log_level = INFO diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index fb6210f9d..cf1eb4db6 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -9,5 +9,6 @@ plugin_autoupdate_last_check_duration = 1 verbose = true asdf_compat = false jobs = 2 +disable_default_shorthands = false log_level = INFO diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index b19af4c47..eb5eaca24 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -55,6 +55,7 @@ mod tests { verbose = true asdf_compat = false jobs = 2 + disable_default_shorthands = false log_level = INFO "###); diff --git a/src/config/settings.rs b/src/config/settings.rs index 6adb2ac68..af34b2c1d 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -6,7 +6,9 @@ use log::LevelFilter; use crate::config::AliasMap; use crate::env; -use crate::env::{RTX_ASDF_COMPAT, RTX_JOBS, RTX_LOG_LEVEL, RTX_VERBOSE}; +use crate::env::{ + RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_VERBOSE, +}; use crate::plugins::PluginName; #[derive(Debug, Clone)] @@ -19,6 +21,7 @@ pub struct Settings { pub verbose: bool, pub asdf_compat: bool, pub jobs: usize, + pub disable_default_shorthands: bool, pub log_level: LevelFilter, } @@ -33,6 +36,7 @@ impl Default for Settings { verbose: *RTX_VERBOSE || !console::user_attended_stderr(), asdf_compat: *RTX_ASDF_COMPAT, jobs: *RTX_JOBS, + disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, log_level: *RTX_LOG_LEVEL, } } @@ -60,6 +64,10 @@ impl Settings { map.insert("verbose".into(), self.verbose.to_string()); map.insert("asdf_compat".into(), self.asdf_compat.to_string()); map.insert("jobs".into(), self.jobs.to_string()); + map.insert( + "disable_default_shorthands".into(), + self.disable_default_shorthands.to_string(), + ); map.insert("log_level".into(), self.log_level.to_string()); map } @@ -75,6 +83,7 @@ pub struct SettingsBuilder { pub verbose: Option, pub asdf_compat: Option, pub jobs: Option, + pub disable_default_shorthands: Option, pub log_level: Option, } @@ -108,6 +117,9 @@ impl SettingsBuilder { if other.jobs.is_some() { self.jobs = other.jobs; } + if other.disable_default_shorthands.is_some() { + self.disable_default_shorthands = other.disable_default_shorthands; + } if other.log_level.is_some() { self.log_level = other.log_level; } @@ -145,6 +157,9 @@ impl SettingsBuilder { settings.verbose = self.verbose.unwrap_or(settings.verbose); settings.asdf_compat = self.asdf_compat.unwrap_or(settings.asdf_compat); settings.jobs = self.jobs.unwrap_or(settings.jobs); + settings.disable_default_shorthands = self + .disable_default_shorthands + .unwrap_or(settings.disable_default_shorthands); settings.aliases = self.aliases.clone().unwrap_or(settings.aliases); settings diff --git a/src/env.rs b/src/env.rs index 0355e1b9d..00d723467 100644 --- a/src/env.rs +++ b/src/env.rs @@ -118,6 +118,7 @@ lazy_static! { pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); pub static ref RTX_PREFER_STALE: bool = prefer_stale(&ARGS); pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); + pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); } fn get_env_diff() -> EnvDiff { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 6066d0562..be1236e0b 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -114,7 +114,7 @@ impl Plugin { )); pr.enable_steady_tick(); let repository = repository - .or_else(|| shorthand_to_repository(&self.name)) + .or_else(|| shorthand_to_repository(settings, &self.name)) .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; debug!("install {} {:?}", self.name, repository); if self.is_installed() { diff --git a/src/shorthand.rs b/src/shorthand.rs index c90b33f49..43d192114 100644 --- a/src/shorthand.rs +++ b/src/shorthand.rs @@ -1,9 +1,14 @@ +use crate::config::Settings; use crate::shorthand_list::SHORTHAND_LIST; use once_cell::sync::Lazy; use std::collections::HashMap; -pub fn shorthand_to_repository(name: &str) -> Option<&'static str> { - SHORTHAND_MAP.get(name).copied() +pub fn shorthand_to_repository(settings: &Settings, name: &str) -> Option<&'static str> { + if !settings.disable_default_shorthands { + SHORTHAND_MAP.get(name).copied() + } else { + None + } } pub static SHORTHAND_MAP: Lazy> = From ef7f63aa18fe1cf0f114b59780564d622cf9e3a0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:33:44 -0600 Subject: [PATCH 0237/1891] bug: skip list-all if not exists --- src/plugins/mod.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index be1236e0b..d11f3fa8d 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -127,7 +127,9 @@ impl Plugin { git.clone(repository)?; pr.set_message("loading plugin remote versions".into()); - self.list_remote_versions(settings)?; + if self.has_list_all_script() { + self.list_remote_versions(settings)?; + } if self.has_list_alias_script() { pr.set_message("getting plugin aliases".into()); self.get_aliases(settings)?; @@ -303,7 +305,11 @@ impl Plugin { .stdout_capture() .stderr_capture() .unchecked() - .run()?; + .run() + .with_context(|| { + let script = self.script_man.get_script_path(&Script::ListAll); + format!("failed to run {}", script.display()) + })?; let stdout = String::from_utf8(result.stdout).unwrap(); let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); @@ -338,6 +344,9 @@ impl Plugin { .collect()) } + fn has_list_all_script(&self) -> bool { + self.script_man.script_exists(&Script::ListAll) + } fn has_list_alias_script(&self) -> bool { self.script_man.script_exists(&Script::ListAliases) } From 791357d4cf8f3360e568d65e36bd4dd3b2489123 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:52:44 -0600 Subject: [PATCH 0238/1891] refactor: regexes --- src/cli/ls.rs | 7 +++---- src/plugins/mod.rs | 12 +++++------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 3f2d2b75b..fd79e85d2 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -153,7 +153,6 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use regex::Regex; use crate::assert_cli; @@ -162,14 +161,14 @@ mod tests { assert_cli!("install"); assert_cli!("install", "shfmt@3.5.0"); let stdout = assert_cli!("list"); - let re = Regex::new(r"-> shellcheck\s+0\.9\.0\s+").unwrap(); + let re = regex!(r"-> shellcheck\s+0\.9\.0\s+"); assert!(re.is_match(&stdout)); - let re = Regex::new(r" {3}shfmt\s+3\.5\.0\s+").unwrap(); + let re = regex!(r" {3}shfmt\s+3\.5\.0\s+"); assert!(re.is_match(&stdout)); assert_cli!("uninstall", "shfmt@3.5.1"); let stdout = assert_cli!("list"); - let re = Regex::new(r" {3}shfmt\s+3\.5\.1 \(missing\)\s+").unwrap(); + let re = regex!(r" {3}shfmt\s+3\.5\.1 \(missing\)\s+"); assert!(re.is_match(&stdout)); } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index d11f3fa8d..36ff63268 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -9,7 +9,7 @@ use console::style; use indexmap::IndexMap; use indicatif::ProgressStyle; use itertools::Itertools; -use lazy_static::lazy_static; + use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; @@ -207,17 +207,15 @@ impl Plugin { if query == "latest" { query = "[0-9]"; } - lazy_static! { - static ref VERSION_REGEX: Regex = Regex::new( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" - ).unwrap(); - } + let version_regex = regex!( + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" + ); let query_regex = Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); let versions = self .list_remote_versions(settings)? .iter() - .filter(|v| !VERSION_REGEX.is_match(v)) + .filter(|v| !version_regex.is_match(v)) .filter(|v| query_regex.is_match(v)) .cloned() .collect_vec(); From b4e9d214ac51c1da8527f3b8f68ac7ed6695c36f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Feb 2023 23:10:27 -0600 Subject: [PATCH 0239/1891] docs --- README.md | 23 ++++++++++------------- src/cli/render_help.rs | 23 ++++++++++------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 56150ff5d..62ed4a5cd 100644 --- a/README.md +++ b/README.md @@ -330,20 +330,12 @@ See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) ### Legacy version files -RTX supports "legacy version files" just like asdf. +rtx supports "legacy version files" just like asdf. They're language-specific files like `.node-version` +and `.python-version`. These are ideal for setting the runtime version of a project without forcing +other developers to use a specific tool like rtx/asdf. -It's behind a config setting "legacy_version_file", but it's enabled by default (asdf defaults to disabled). -You can disable these with `rtx settings set legacy_version_file false`. There is a performance cost -to having these when they're parsed as it's performed by the plugin in `bin/parse-version-file`. However -these are [cached](#cache-behavior) so it's not a huge deal. You may not even notice. - -These are ideal for setting the runtime version of a project without forcing other developers to -use a specific tool like rtx/asdf. - -They support aliases, which means you can (finally) have an `.nvmrc` file with `lts/hydrogen` -and it will work in rtx _and_ nvm. This wasn't possible with asdf. - -Here are some of the supported legacy version files: +They support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work +in rtx and nvm. Here are some of the supported legacy version files: | Plugin | "Legacy" (Idiomatic) Files | | --------- | -------------------------------------------------- | @@ -357,6 +349,11 @@ Here are some of the supported legacy version files: | terraform | `.terraform-version`, `.packer-version`, `main.tf` | | yarn | `.yvmrc` | +In rtx these are enabled by default. You can disable them with `rtx settings set legacy_version_file false`. +There is a performance cost to having these when they're parsed as it's performed by the plugin in +`bin/parse-version-file`. However these are [cached](#cache-behavior) so it's not a huge deal. +You may not even notice. + > **Note** > > asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 4fdd89234..94ae714e7 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -349,20 +349,12 @@ See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) ### Legacy version files -RTX supports "legacy version files" just like asdf. +rtx supports "legacy version files" just like asdf. They're language-specific files like `.node-version` +and `.python-version`. These are ideal for setting the runtime version of a project without forcing +other developers to use a specific tool like rtx/asdf. -It's behind a config setting "legacy_version_file", but it's enabled by default (asdf defaults to disabled). -You can disable these with `rtx settings set legacy_version_file false`. There is a performance cost -to having these when they're parsed as it's performed by the plugin in `bin/parse-version-file`. However -these are [cached](#cache-behavior) so it's not a huge deal. You may not even notice. - -These are ideal for setting the runtime version of a project without forcing other developers to -use a specific tool like rtx/asdf. - -They support aliases, which means you can (finally) have an `.nvmrc` file with `lts/hydrogen` -and it will work in rtx _and_ nvm. This wasn't possible with asdf. - -Here are some of the supported legacy version files: +They support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work +in rtx and nvm. Here are some of the supported legacy version files: | Plugin | "Legacy" (Idiomatic) Files | | --------- | -------------------------------------------------- | @@ -376,6 +368,11 @@ Here are some of the supported legacy version files: | terraform | `.terraform-version`, `.packer-version`, `main.tf` | | yarn | `.yvmrc` | +In rtx these are enabled by default. You can disable them with `rtx settings set legacy_version_file false`. +There is a performance cost to having these when they're parsed as it's performed by the plugin in +`bin/parse-version-file`. However these are [cached](#cache-behavior) so it's not a huge deal. +You may not even notice. + > **Note** > > asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies From 86f4db3b29e8fe87d2f610bc6e502ccc6102b4b4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:14:23 -0600 Subject: [PATCH 0240/1891] chore: make codecov informational (#178) --- .github/workflows/rtx.yml | 8 ++++---- codecov.yml | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 codecov.yml diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index b70f594c9..e88ef5afe 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -21,7 +21,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' + save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - name: Install direnv run: sudo apt-get update; sudo apt-get install direnv - name: Install just @@ -46,7 +46,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' + save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - uses: taiki-e/install-action@cargo-llvm-cov - name: Install zsh/fish/direnv run: sudo apt-get update; sudo apt-get install zsh fish direnv @@ -87,7 +87,7 @@ jobs: uses: Swatinem/rust-cache@v2 with: key: "${{matrix.target}}" - save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' + save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - uses: actions-rs/cargo@v1 with: use-cross: true @@ -122,7 +122,7 @@ jobs: uses: Swatinem/rust-cache@v2 with: key: "${{matrix.target}}" - save-if: github.event_name == 'push' && github.ref == 'refs/heads/main' + save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - run: cargo build --release --all-features --target ${{matrix.target}} - run: scripts/build-tarball.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..d08101fc8 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,5 @@ +coverage: + status: + project: + default: + informational: true From 7597c035ba91de2c1bdb00b618dbe7a1bdfd0338 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:15:16 -0600 Subject: [PATCH 0241/1891] docs: github action --- README.md | 13 +++++++++++++ src/cli/render_help.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/README.md b/README.md index 62ed4a5cd..d70d60d21 100644 --- a/README.md +++ b/README.md @@ -1563,6 +1563,19 @@ That said, there are a lot of great things about asdf. It's the best multi-runti and I've really been impressed with the plugin system. Most of the design decisions the authors made were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. +### CI/CD + +Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. + +### GitHub Actions + +Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): + +```yaml +- uses: jdxcode/rtx-action@v1 +- run: node -v # will be the node version from `.tool-versions` +``` + ## direnv [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 94ae714e7..62dc00381 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -679,6 +679,19 @@ That said, there are a lot of great things about asdf. It's the best multi-runti and I've really been impressed with the plugin system. Most of the design decisions the authors made were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. +### CI/CD + +Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. + +### GitHub Actions + +Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): + +```yaml +- uses: jdxcode/rtx-action@v1 +- run: node -v # will be the node version from `.tool-versions` +``` + ## direnv [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze From 428cd87d278e162fb5a89c4aff09bccba15b9499 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:52:25 -0600 Subject: [PATCH 0242/1891] docs: added table-of-contents --- README.md | 97 ++++++++++ justfile | 1 + scripts/gh-md-toc | 411 +++++++++++++++++++++++++++++++++++++++++ src/cli/render_help.rs | 4 + 4 files changed, 513 insertions(+) create mode 100755 scripts/gh-md-toc diff --git a/README.md b/README.md index d70d60d21..05cecd6a6 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,103 @@ v18.10.9 > `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not > already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). +## Table of Contents + + + * [About](#about) + * [How it works](#how-it-works) + * [Common example commands](#common-example-commands) + * [Installation](#installation) + * [Standalone](#standalone) + * [Homebrew](#homebrew) + * [Cargo](#cargo) + * [npm](#npm) + * [GitHub Releases](#github-releases) + * [apt](#apt) + * [dnf](#dnf) + * [yum](#yum) + * [aur](#aur) + * [Other Shells](#other-shells) + * [Bash](#bash) + * [Fish](#fish) + * [Xonsh](#xonsh) + * [Something else?](#something-else) + * [Uninstalling](#uninstalling) + * [Configuration](#configuration) + * [.tool-versions](#tool-versions) + * [Legacy version files](#legacy-version-files) + * [Global config: ~/.config/rtx/config.toml](#global-config-configrtxconfigtoml) + * [Environment variables](#environment-variables) + * [RTX_MISSING_RUNTIME_BEHAVIOR](#rtx_missing_runtime_behavior) + * [RTX_DATA_DIR](#rtx_data_dir) + * [RTX_CACHE_DIR](#rtx_cache_dir) + * [RTX_CONFIG_FILE](#rtx_config_file) + * [RTX_DEFAULT_TOOL_VERSIONS_FILENAME](#rtx_default_tool_versions_filename) + * [RTX_${PLUGIN}_VERSION](#rtx_plugin_version) + * [RTX_LEGACY_VERSION_FILE](#rtx_legacy_version_file) + * [RTX_LOG_LEVEL=trace|debug|info|warn|error](#rtx_log_leveltracedebuginfowarnerror) + * [RTX_LOG_FILE=~/.rtx/rtx.log](#rtx_log_filertxrtxlog) + * [RTX_LOG_FILE_LEVEL=trace|debug|info|warn|error](#rtx_log_file_leveltracedebuginfowarnerror) + * [RTX_VERBOSE=1](#rtx_verbose1) + * [RTX_ASDF_COMPAT=1](#rtx_asdf_compat1) + * [RTX_JOBS=1](#rtx_jobs1) + * [RTX_DISABLE_DEFAULT_SHORTHANDS=1](#rtx_disable_default_shorthands1) + * [RTX_HIDE_OUTDATED_BUILD=1](#rtx_hide_outdated_build1) + * [Aliases](#aliases) + * [Plugins](#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) + * [How do I create my own plugin?](#how-do-i-create-my-own-plugin) + * [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) + * [Windows support?](#windows-support) + * [Commands](#commands) + * [rtx activate](#rtx-activate) + * [rtx alias get](#rtx-alias-get) + * [rtx alias ls](#rtx-alias-ls) + * [rtx alias set](#rtx-alias-set) + * [rtx alias unset](#rtx-alias-unset) + * [rtx bin-paths](#rtx-bin-paths) + * [rtx cache clear](#rtx-cache-clear) + * [rtx complete](#rtx-complete) + * [rtx current](#rtx-current) + * [rtx deactivate](#rtx-deactivate) + * [rtx direnv activate](#rtx-direnv-activate) + * [rtx doctor](#rtx-doctor) + * [rtx env](#rtx-env) + * [rtx exec](#rtx-exec) + * [rtx global](#rtx-global) + * [rtx implode](#rtx-implode) + * [rtx install](#rtx-install) + * [rtx latest](#rtx-latest) + * [rtx local](#rtx-local) + * [rtx ls](#rtx-ls) + * [rtx ls-remote](#rtx-ls-remote) + * [rtx plugins install](#rtx-plugins-install) + * [rtx plugins ls](#rtx-plugins-ls) + * [rtx plugins ls-remote](#rtx-plugins-ls-remote) + * [rtx plugins uninstall](#rtx-plugins-uninstall) + * [rtx plugins update](#rtx-plugins-update) + * [rtx self-update](#rtx-self-update) + * [rtx settings get](#rtx-settings-get) + * [rtx settings ls](#rtx-settings-ls) + * [rtx settings set](#rtx-settings-set) + * [rtx settings unset](#rtx-settings-unset) + * [rtx uninstall](#rtx-uninstall) + * [rtx version](#rtx-version) + * [rtx where](#rtx-where) + * [Comparison to asdf](#comparison-to-asdf) + * [Performance](#performance) + * [Environment variables](#environment-variables-1) + * [UX](#ux) + * [CI/CD](#cicd) + * [GitHub Actions](#github-actions) + * [direnv](#direnv) + * [rtx inside of direnv (use rtx in .envrc)](#rtx-inside-of-direnv-use-rtx-in-envrc) + * [Cache Behavior](#cache-behavior) + * [Plugin Cache](#plugin-cache) + * [Legacy File Cache](#legacy-file-cache) + * [Development](#development) + ## About diff --git a/justfile b/justfile index ede31eb3e..69ef1513a 100644 --- a/justfile +++ b/justfile @@ -70,6 +70,7 @@ lint-fix: # regenerate README.md render-help: ./.bin/rtx render-help > README.md + ./scripts/gh-md-toc --insert --no-backup --hide-footer --skip-header README.md # regenerate shell completion files render-completions: diff --git a/scripts/gh-md-toc b/scripts/gh-md-toc new file mode 100755 index 000000000..a23d2f78b --- /dev/null +++ b/scripts/gh-md-toc @@ -0,0 +1,411 @@ +#!/usr/bin/env bash + +# +# Steps: +# +# 1. Download corresponding html file for some README.md: +# curl -s $1 +# +# 2. Discard rows where no substring 'user-content-' (github's markup): +# awk '/user-content-/ { ... +# +# 3.1 Get last number in each row like ' ... sitemap.js.*<\/h/)+2, RLENGTH-5) +# +# 5. Find anchor and insert it inside "(...)": +# substr($0, match($0, "href=\"[^\"]+?\" ")+6, RLENGTH-8) +# + +gh_toc_version="0.8.0" + +gh_user_agent="gh-md-toc v$gh_toc_version" + +# +# Download rendered into html README.md by its url. +# +# +gh_toc_load() { + local gh_url=$1 + + if type curl &>/dev/null; then + curl --user-agent "$gh_user_agent" -s "$gh_url" + elif type wget &>/dev/null; then + wget --user-agent="$gh_user_agent" -qO- "$gh_url" + else + echo "Please, install 'curl' or 'wget' and try again." + exit 1 + fi +} + +# +# Converts local md file into html by GitHub +# +# -> curl -X POST --data '{"text": "Hello world github/linguist#1 **cool**, and #1!"}' https://api.github.com/markdown +#

Hello world github/linguist#1 cool, and #1!

'" +gh_toc_md2html() { + local gh_file_md=$1 + local skip_header=$2 + + URL=https://api.github.com/markdown/raw + + if [ ! -z "$GH_TOC_TOKEN" ]; then + TOKEN=$GH_TOC_TOKEN + else + TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" + if [ -f "$TOKEN_FILE" ]; then + TOKEN="$(cat $TOKEN_FILE)" + fi + fi + if [ ! -z "${TOKEN}" ]; then + AUTHORIZATION="Authorization: token ${TOKEN}" + fi + + local gh_tmp_file_md=$gh_file_md + if [ "$skip_header" = "yes" ]; then + if grep -Fxq "" "$gh_src"; then + # cut everything before the toc + gh_tmp_file_md=$gh_file_md~~ + sed '1,//d' $gh_file_md > $gh_tmp_file_md + fi + fi + + # echo $URL 1>&2 + OUTPUT=$(curl -s \ + --user-agent "$gh_user_agent" \ + --data-binary @"$gh_tmp_file_md" \ + -H "Content-Type:text/plain" \ + -H "$AUTHORIZATION" \ + "$URL") + + rm -f $gh_file_md~~ + + if [ "$?" != "0" ]; then + echo "XXNetworkErrorXX" + fi + if [ "$(echo "${OUTPUT}" | awk '/API rate limit exceeded/')" != "" ]; then + echo "XXRateLimitXX" + else + echo "${OUTPUT}" + fi +} + + +# +# Is passed string url +# +gh_is_url() { + case $1 in + https* | http*) + echo "yes";; + *) + echo "no";; + esac +} + +# +# TOC generator +# +gh_toc(){ + local gh_src=$1 + local gh_src_copy=$1 + local gh_ttl_docs=$2 + local need_replace=$3 + local no_backup=$4 + local no_footer=$5 + local indent=$6 + local skip_header=$7 + + if [ "$gh_src" = "" ]; then + echo "Please, enter URL or local path for a README.md" + exit 1 + fi + + + # Show "TOC" string only if working with one document + if [ "$gh_ttl_docs" = "1" ]; then + + echo "Table of Contents" + echo "=================" + echo "" + gh_src_copy="" + + fi + + if [ "$(gh_is_url "$gh_src")" == "yes" ]; then + gh_toc_load "$gh_src" | gh_toc_grab "$gh_src_copy" "$indent" + if [ "${PIPESTATUS[0]}" != "0" ]; then + echo "Could not load remote document." + echo "Please check your url or network connectivity" + exit 1 + fi + if [ "$need_replace" = "yes" ]; then + echo + echo "!! '$gh_src' is not a local file" + echo "!! Can't insert the TOC into it." + echo + fi + else + local rawhtml=$(gh_toc_md2html "$gh_src" "$skip_header") + if [ "$rawhtml" == "XXNetworkErrorXX" ]; then + echo "Parsing local markdown file requires access to github API" + echo "Please make sure curl is installed and check your network connectivity" + exit 1 + fi + if [ "$rawhtml" == "XXRateLimitXX" ]; then + echo "Parsing local markdown file requires access to github API" + echo "Error: You exceeded the hourly limit. See: https://developer.github.com/v3/#rate-limiting" + TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" + echo "or place GitHub auth token here: ${TOKEN_FILE}" + exit 1 + fi + local toc=`echo "$rawhtml" | gh_toc_grab "$gh_src_copy" "$indent"` + echo "$toc" + if [ "$need_replace" = "yes" ]; then + if grep -Fxq "" "$gh_src" && grep -Fxq "" "$gh_src"; then + echo "Found markers" + else + echo "You don't have or in your file...exiting" + exit 1 + fi + local ts="<\!--ts-->" + local te="<\!--te-->" + local dt=`date +'%F_%H%M%S'` + local ext=".orig.${dt}" + local toc_path="${gh_src}.toc.${dt}" + local toc_createdby="" + local toc_footer="" + # http://fahdshariff.blogspot.ru/2012/12/sed-mutli-line-replacement-between-two.html + # clear old TOC + sed -i${ext} "/${ts}/,/${te}/{//!d;}" "$gh_src" + # create toc file + echo "${toc}" > "${toc_path}" + if [ "${no_footer}" != "yes" ]; then + echo -e "\n${toc_createdby}\n${toc_footer}\n" >> "$toc_path" + fi + + # insert toc file + if ! sed --version > /dev/null 2>&1; then + sed -i "" "/${ts}/r ${toc_path}" "$gh_src" + else + sed -i "/${ts}/r ${toc_path}" "$gh_src" + fi + echo + if [ "${no_backup}" = "yes" ]; then + rm "$toc_path" "$gh_src$ext" + fi + echo "!! TOC was added into: '$gh_src'" + if [ -z "${no_backup}" ]; then + echo "!! Origin version of the file: '${gh_src}${ext}'" + echo "!! TOC added into a separate file: '${toc_path}'" + fi + echo + fi + fi +} + +# +# Grabber of the TOC from rendered html +# +# $1 - a source url of document. +# It's need if TOC is generated for multiple documents. +# $2 - number of spaces used to indent. +# +gh_toc_grab() { + common_awk_script=' + modified_href = "" + split(href, chars, "") + for (i=1;i <= length(href); i++) { + c = chars[i] + res = "" + if (c == "+") { + res = " " + } else { + if (c == "%") { + res = "\\x" + } else { + res = c "" + } + } + modified_href = modified_href res + } + print sprintf("%*s", (level-1)*'"$2"', "") "* [" text "](" gh_url modified_href ")" + ' + if [ `uname -s` == "OS/390" ]; then + grepcmd="pcregrep -o" + echoargs="" + awkscript='{ + level = substr($0, length($0), 1) + text = substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5) + href = substr($0, match($0, "href=\"([^\"]+)?\"")+6, RLENGTH-7) + '"$common_awk_script"' + }' + else + grepcmd="grep -Eo" + echoargs="-e" + awkscript='{ + level = substr($0, length($0), 1) + text = substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5) + href = substr($0, match($0, "href=\"[^\"]+?\"")+6, RLENGTH-7) + '"$common_awk_script"' + }' + fi + href_regex='href=\"[^\"]+?\"' + + # if closed is on the new line, then move it on the prev line + # for example: + # was: The command foo1 + # + # became: The command foo1 + sed -e ':a' -e 'N' -e '$!ba' -e 's/\n<\/h/<\/h/g' | + + # find strings that corresponds to template + $grepcmd '//g' | sed 's/<\/code>//g' | + + # remove g-emoji + sed 's/]*[^<]*<\/g-emoji> //g' | + + # now all rows are like: + # ... /dev/null`; then + echo `$tool --version | head -n 1` + else + echo "not installed" + fi + done +} + +show_help() { + local app_name=$(basename "$0") + echo "GitHub TOC generator ($app_name): $gh_toc_version" + echo "" + echo "Usage:" + echo " $app_name [options] src [src] Create TOC for a README file (url or local path)" + echo " $app_name - Create TOC for markdown from STDIN" + echo " $app_name --help Show help" + echo " $app_name --version Show version" + echo "" + echo "Options:" + echo " --indent Set indent size. Default: 3." + echo " --insert Insert new TOC into original file. For local files only. Default: false." + echo " See https://github.com/ekalinin/github-markdown-toc/issues/41 for details." + echo " --no-backup Remove backup file. Set --insert as well. Default: false." + echo " --hide-footer Do not write date & author of the last TOC update. Set --insert as well. Default: false." + echo " --skip-header Hide entry of the topmost headlines. Default: false." + echo " See https://github.com/ekalinin/github-markdown-toc/issues/125 for details." + echo "" +} + +# +# Options handlers +# +gh_toc_app() { + local need_replace="no" + local indent=3 + + if [ "$1" = '--help' ] || [ $# -eq 0 ] ; then + show_help + return + fi + + if [ "$1" = '--version' ]; then + show_version + return + fi + + if [ "$1" = '--indent' ]; then + indent="$2" + shift 2 + fi + + if [ "$1" = "-" ]; then + if [ -z "$TMPDIR" ]; then + TMPDIR="/tmp" + elif [ -n "$TMPDIR" -a ! -d "$TMPDIR" ]; then + mkdir -p "$TMPDIR" + fi + local gh_tmp_md + if [ `uname -s` == "OS/390" ]; then + local timestamp=$(date +%m%d%Y%H%M%S) + gh_tmp_md="$TMPDIR/tmp.$timestamp" + else + gh_tmp_md=$(mktemp $TMPDIR/tmp.XXXXXX) + fi + while read input; do + echo "$input" >> "$gh_tmp_md" + done + gh_toc_md2html "$gh_tmp_md" | gh_toc_grab "" "$indent" + return + fi + + if [ "$1" = '--insert' ]; then + need_replace="yes" + shift + fi + + if [ "$1" = '--no-backup' ]; then + need_replace="yes" + no_backup="yes" + shift + fi + + if [ "$1" = '--hide-footer' ]; then + need_replace="yes" + no_footer="yes" + shift + fi + + if [ "$1" = '--skip-header' ]; then + skip_header="yes" + shift + fi + + + for md in "$@" + do + echo "" + gh_toc "$md" "$#" "$need_replace" "$no_backup" "$no_footer" "$indent" "$skip_header" + done + + echo "" + echo "" +} + +# +# Entry point +# +gh_toc_app "$@" diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 62dc00381..cffdcd17d 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -87,6 +87,10 @@ v18.10.9 > `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not > already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). +## Table of Contents + + + ## About From 62db971ba1d2a5fc6f7372ac80b5c89c6987bb2e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 01:04:01 -0600 Subject: [PATCH 0243/1891] docs --- README.md | 153 +++++++++++++------------------- completions/_rtx | 164 +++++++++++++++++------------------ completions/rtx.fish | 102 +++++++++++----------- justfile | 2 +- src/cli/command.rs | 2 +- src/cli/complete.rs | 6 +- src/cli/current.rs | 9 +- src/cli/deactivate.rs | 6 +- src/cli/env.rs | 10 +-- src/cli/exec.rs | 8 +- src/cli/global.rs | 18 ++-- src/cli/implode.rs | 8 +- src/cli/install.rs | 16 ++-- src/cli/latest.rs | 4 +- src/cli/local.rs | 10 +-- src/cli/ls.rs | 2 +- src/cli/ls_remote.rs | 6 +- src/cli/plugins/install.rs | 2 +- src/cli/plugins/ls.rs | 4 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/uninstall.rs | 4 +- src/cli/plugins/update.rs | 6 +- src/cli/render_help.rs | 2 +- src/cli/self_update.rs | 2 +- src/cli/uninstall.rs | 4 +- 25 files changed, 260 insertions(+), 292 deletions(-) diff --git a/README.md b/README.md index 05cecd6a6..6dbfa2201 100644 --- a/README.md +++ b/README.md @@ -677,7 +677,6 @@ Examples: $ eval "$(rtx activate zsh)" $ rtx activate fish | source $ execx($(rtx activate xonsh)) - ``` ### `rtx alias get` @@ -702,7 +701,6 @@ Options: Examples: $ rtx alias get nodejs lts/hydrogen 18.0.0 - ``` ### `rtx alias ls` @@ -728,7 +726,6 @@ Options: Examples: $ rtx aliases nodejs lts/hydrogen 18.0.0 - ``` ### `rtx alias set` @@ -755,7 +752,6 @@ Options: Examples: $ rtx alias set nodejs lts/hydrogen 18.0.0 - ``` ### `rtx alias unset` @@ -779,7 +775,6 @@ Options: Examples: $ rtx alias unset nodejs lts/hydrogen - ``` ### `rtx bin-paths` @@ -791,7 +786,6 @@ Usage: bin-paths Options: -h, --help Print help - ``` ### `rtx cache clear` @@ -803,12 +797,11 @@ Usage: clear Options: -h, --help Print help - ``` ### `rtx complete` ``` -generate shell completions +Generate shell completions Usage: complete --shell @@ -822,23 +815,23 @@ Options: Print help (see a summary with '-h') Examples: - $ rtx complete - + $ rtx complete -s bash > /etc/bash_completion.d/rtx + $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx + $ rtx complete -s fish > ~/.config/fish/completions/rtx.fish ``` ### `rtx current` ``` -Shows currently active, and installed runtime versions +Shows current active and installed runtime versions -This is similar to `rtx list --current`, but this -only shows the runtime and/or version so it's -designed to fit into scripts more easily. +This is similar to `rtx ls --current`, but this only shows the runtime +and/or version. It's designed to fit into scripts more easily. Usage: current [PLUGIN] Arguments: [PLUGIN] - plugin to show versions of + Plugin to show versions of e.g.: ruby, nodejs @@ -860,12 +853,11 @@ Examples: # can output multiple versions $ rtx current python 3.11.0 3.10.0 - ``` ### `rtx deactivate` ``` -disable rtx for current shell session +Disable rtx for current shell session This can be used to temporarily disable rtx in a shell session. @@ -873,7 +865,7 @@ Usage: deactivate [SHELL_TYPE] Arguments: [SHELL_TYPE] - shell type to generate the script for + Shell type to generate the script for [possible values: bash, fish, xonsh, zsh] @@ -886,7 +878,6 @@ Examples: $ eval "$(rtx deactivate zsh)" $ rtx deactivate fish | source $ execx($(rtx deactivate xonsh)) - ``` ### `rtx direnv activate` @@ -909,7 +900,6 @@ Examples: $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh $ echo 'use rtx' > .envrc $ direnv allow - ``` ### `rtx doctor` @@ -925,24 +915,23 @@ Options: Examples: $ rtx doctor [WARN] plugin nodejs is not installed - ``` ### `rtx env` ``` exports env vars to activate rtx in a single shell session -It's not necessary to use this if you have `rtx activate` in your shell rc file. -Use this if you don't want to permanently install rtx. -This can be used similarly to `asdf shell`. -Unfortunately, it requires `eval` to work since it's not written in Bash though. +Use this if you don't want to permanently install rtx. It's not necessary to +use this if you have `rtx activate` in your shell rc file. +This can be used similarly to `asdf shell`. It requires `eval` to work since +it's not written in Bash. It's also useful just to see what environment variables rtx sets. Usage: env [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - runtime version to use + Runtime version to use Options: -s, --shell @@ -958,12 +947,11 @@ Examples: $ eval "$(rtx env -s zsh)" $ rtx env -s fish | source $ execx($(rtx env -s xonsh)) - ``` ### `rtx exec` ``` -execute a command with runtime(s) set +Execute a command with runtime(s) set use this to avoid modifying the shell session or running ad-hoc commands with the rtx runtimes set. @@ -978,16 +966,16 @@ Usage: exec [OPTIONS] [RUNTIME]... [-- ...] Arguments: [RUNTIME]... - runtime(s) to start + Runtime(s) to start e.g.: nodejs@20 python@3.10 [COMMAND]... - the command string to execute (same as --command) + Command string to execute (same as --command) Options: -c, --command - the command string to execute + Command string to execute -h, --help Print help (see a summary with '-h') @@ -998,40 +986,39 @@ Examples: # Specify command as a string: rtx exec nodejs@20 python@3.11 --command "node -v && python -V" - ``` ### `rtx global` ``` -sets global .tool-versions to include a specified runtime +Sets global .tool-versions to include a specified runtime -then displays the contents of ~/.tool-versions -this file is `$HOME/.tool-versions` by default -use `rtx local` to set a runtime version locally in the current directory +Displays the contents of ~/.tool-versions after writing. +The file is `$HOME/.tool-versions` by default. +Use `rtx local` to set a runtime version locally in the current directory. Usage: global [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - runtime(s) to add to .tool-versions + Runtime(s) to add to .tool-versions e.g.: nodejs@20 - if this is a single runtime with no version, the current value of the global + If this is a single runtime with no version, the current value of the global .tool-versions will be displayed Options: --pin - save exact version to `~/.tool-versions` + Save exact version to `~/.tool-versions` e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions --fuzzy - save fuzzy version to `~/.tool-versions` + Save fuzzy version to `~/.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove - remove the plugin(s) from ~/.tool-versions + Remove the plugin(s) from ~/.tool-versions -h, --help Print help (see a summary with '-h') @@ -1048,35 +1035,33 @@ Examples: # show the current version of nodejs in ~/.tool-versions $ rtx global nodejs 20.0.0 - ``` ### `rtx implode` ``` -removes rtx CLI and all generated data +Removes rtx CLI and all generated data -skips config directory by default +Skips config directory by default. Usage: implode [OPTIONS] Options: --config - also remove config directory + Also remove config directory --dry-run - list directories that would be removed without actually removing them + List directories that would be removed without actually removing them -h, --help Print help (see a summary with '-h') - ``` ### `rtx install` ``` -install a runtime +Install a runtime -this will install a runtime to `~/.local/share/rtx/installs//` -it won't be used simply by being installed, however. +This will install a runtime to `~/.local/share/rtx/installs//` +It won't be used simply by being installed, however. For that, you must set up a `.tool-version` file manually or with `rtx local/global`. Or you can call a runtime explicitly with `rtx exec @ -- `. @@ -1086,16 +1071,16 @@ Usage: install [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - runtime(s) to install + Runtime(s) to install e.g.: nodejs@20 Options: -p, --plugin - only install runtime(s) for + Only install runtime(s) for -f, --force - force reinstall even if already installed + Force reinstall even if already installed -v, --verbose... Show installation output @@ -1109,12 +1094,11 @@ Examples: $ rtx install nodejs # install version specified in .tool-versions $ rtx install # installs all runtimes specified in .tool-versions for installed plugins $ rtx install --all # installs all runtimes and all plugins - ``` ### `rtx latest` ``` -get the latest runtime version of a plugin's runtimes +Get the latest runtime version of a plugin's runtimes Usage: latest @@ -1132,7 +1116,6 @@ Examples: $ rtx latest nodejs # get the latest stable version of nodejs 20.0.0 - ``` ### `rtx local` @@ -1147,7 +1130,7 @@ Usage: local [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - runtimes to add to .tool-versions + Runtimes to add to .tool-versions e.g.: nodejs@20 if this is a single runtime with no version, @@ -1155,21 +1138,21 @@ Arguments: Options: -p, --parent - recurse up to find a .tool-versions file rather than using the current directory only + Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") --pin - save exact version to `.tool-versions` + Save exact version to `.tool-versions` e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions --fuzzy - save fuzzy version to `.tool-versions` + Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove - remove the plugin(s) from .tool-versions + Remove the plugin(s) from .tool-versions -h, --help Print help (see a summary with '-h') @@ -1192,12 +1175,11 @@ Examples: # show the current version of nodejs in .tool-versions $ rtx local nodejs 20.0.0 - ``` ### `rtx ls` ``` -list installed runtime versions +List installed runtime versions The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. (Assuming `rtx activate` or `rtx env` is in use). @@ -1223,12 +1205,11 @@ Examples: $ rtx list --current -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) - ``` ### `rtx ls-remote` ``` -list runtime versions available for install +List runtime versions available for install note that these versions are cached for commands like `rtx install nodejs@latest` however _this_ command will always clear that cache and fetch the latest remote versions @@ -1237,10 +1218,10 @@ Usage: ls-remote [PREFIX] Arguments: - plugin to get versions for + Plugin to get versions for [PREFIX] - the version prefix to use when querying the latest version same as the first argument after the "@" + The version prefix to use when querying the latest version same as the first argument after the "@" Options: -h, --help @@ -1258,12 +1239,11 @@ Examples: $ rtx ls-remote nodejs 18 18.0.0 18.1.0 - ``` ### `rtx plugins install` ``` -install a plugin +Install a plugin note that rtx automatically can install plugins when you install a runtime e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin @@ -1309,7 +1289,6 @@ Examples: $ rtx install https://github.com/asdf-vm/asdf-nodejs.git # install the nodejs plugin using the git url only # (nodejs is inferred from the url) - ``` ### `rtx plugins ls` @@ -1322,12 +1301,12 @@ Usage: ls [OPTIONS] Options: -a, --all - list all available remote plugins + List all available remote plugins same as `rtx plugins ls-remote` -u, --urls - show the git url for each plugin + Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git @@ -1342,7 +1321,6 @@ Examples: $ rtx plugins ls --urls nodejs https://github.com/asdf-vm/asdf-nodejs.git ruby https://github.com/asdf-vm/asdf-ruby.git - ``` ### `rtx plugins ls-remote` @@ -1359,24 +1337,23 @@ Usage: ls-remote [OPTIONS] Options: -u, --urls - show the git url for each plugin + Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git -h, --help Print help (see a summary with '-h') - ``` ### `rtx plugins uninstall` ``` -removes a plugin +Removes a plugin Usage: uninstall Arguments: - plugin to remove + Plugin to remove Options: -h, --help @@ -1384,12 +1361,11 @@ Options: Examples: $ rtx uninstall nodejs - ``` ### `rtx plugins update` ``` -updates a plugin to the latest version +Updates a plugin to the latest version note: this updates the plugin itself, not the runtime versions @@ -1397,11 +1373,11 @@ Usage: update [OPTIONS] [PLUGIN]... Arguments: [PLUGIN]... - plugin(s) to update + Plugin(s) to update Options: -a, --all - update all plugins + Update all plugins -h, --help Print help (see a summary with '-h') @@ -1409,19 +1385,17 @@ Options: Examples: $ rtx plugins update --all # update all plugins $ rtx plugins update nodejs # update only nodejs - ``` ### `rtx self-update` ``` -updates rtx itself +Updates rtx itself Usage: self-update Options: -h, --help Print help - ``` ### `rtx settings get` @@ -1446,7 +1420,6 @@ Options: Examples: $ rtx settings get legacy_version_file true - ``` ### `rtx settings ls` @@ -1467,7 +1440,6 @@ Options: Examples: $ rtx settings legacy_version_file = false - ``` ### `rtx settings set` @@ -1491,7 +1463,6 @@ Options: Examples: $ rtx settings set legacy_version_file true - ``` ### `rtx settings unset` @@ -1512,18 +1483,17 @@ Options: Examples: $ rtx settings unset legacy_version_file - ``` ### `rtx uninstall` ``` -removes runtime versions +Removes runtime versions Usage: uninstall ... Arguments: ... - runtime(s) to remove + Runtime(s) to remove Options: -h, --help @@ -1532,7 +1502,6 @@ Options: Examples: $ rtx uninstall nodejs@18.0.0 # will uninstall specific version $ rtx uninstall nodejs # will uninstall current nodejs version - ``` ### `rtx version` @@ -1544,7 +1513,6 @@ Usage: version Options: -h, --help Print help - ``` ### `rtx where` @@ -1573,7 +1541,6 @@ Examples: # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 - ``` ## Comparison to asdf diff --git a/completions/_rtx b/completions/_rtx index a28ba7190..9c8322f2b 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -267,13 +267,13 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::plugin -- plugin to show versions of:' \ +'::plugin -- Plugin to show versions of:' \ && ret=0 ;; (deactivate) _arguments "${_arguments_options[@]}" \ -'-s+[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ -'--shell=[shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ +'-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ +'--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ @@ -281,7 +281,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::shell_type -- shell type to generate the script for:(bash fish xonsh zsh)' \ +'::shell_type -- Shell type to generate the script for:(bash fish xonsh zsh)' \ && ret=0 ;; (direnv) @@ -394,13 +394,13 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- runtime version to use:' \ +'*::runtime -- Runtime version to use:' \ && ret=0 ;; (exec) _arguments "${_arguments_options[@]}" \ -'()-c+[the command string to execute]:C: ' \ -'()--command=[the command string to execute]:C: ' \ +'()-c+[Command string to execute]:C: ' \ +'()--command=[Command string to execute]:C: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ @@ -408,23 +408,23 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- runtime(s) to start:' \ -'*::command -- the command string to execute (same as --command):' \ +'*::runtime -- Runtime(s) to start:' \ +'*::command -- Command string to execute (same as --command):' \ && ret=0 ;; (global) _arguments "${_arguments_options[@]}" \ -'*--remove=[remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ +'*--remove=[Remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--pin[save exact version to `~/.tool-versions`]' \ -'--fuzzy[save fuzzy version to `~/.tool-versions`]' \ +'--pin[Save exact version to `~/.tool-versions`]' \ +'--fuzzy[Save fuzzy version to `~/.tool-versions`]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- runtime(s) to add to .tool-versions:' \ +'*::runtime -- Runtime(s) to add to .tool-versions:' \ && ret=0 ;; (hook-env) @@ -446,8 +446,8 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--config[also remove config directory]' \ -'--dry-run[list directories that would be removed without actually removing them]' \ +'--config[Also remove config directory]' \ +'--dry-run[List directories that would be removed without actually removing them]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -456,20 +456,20 @@ _arguments "${_arguments_options[@]}" \ ;; (install) _arguments "${_arguments_options[@]}" \ -'()*-p+[only install runtime(s) for ]:PLUGIN: ' \ -'()*--plugin=[only install runtime(s) for ]:PLUGIN: ' \ +'()*-p+[Only install runtime(s) for ]:PLUGIN: ' \ +'()*--plugin=[Only install runtime(s) for ]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'-f[force reinstall even if already installed]' \ -'--force[force reinstall even if already installed]' \ -'(-p --plugin -f --force)-a[install all missing runtimes as well as all plugins for the current directory]' \ -'(-p --plugin -f --force)--all[install all missing runtimes as well as all plugins for the current directory]' \ +'-f[Force reinstall even if already installed]' \ +'--force[Force reinstall even if already installed]' \ +'(-p --plugin -f --force)-a[Install all missing runtimes as well as all plugins for the current directory]' \ +'(-p --plugin -f --force)--all[Install all missing runtimes as well as all plugins for the current directory]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- runtime(s) to install:' \ +'*::runtime -- Runtime(s) to install:' \ && ret=0 ;; (latest) @@ -482,26 +482,26 @@ _arguments "${_arguments_options[@]}" \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':runtime -- Runtime to get the latest version of:' \ -'::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ +'::asdf_version -- The version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ && ret=0 ;; (local) _arguments "${_arguments_options[@]}" \ -'*--remove=[remove the plugin(s) from .tool-versions]:PLUGIN: ' \ +'*--remove=[Remove the plugin(s) from .tool-versions]:PLUGIN: ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'-p[recurse up to find a .tool-versions file rather than using the current directory only +'-p[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ -'--parent[recurse up to find a .tool-versions file rather than using the current directory only +'--parent[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ -'--pin[save exact version to `.tool-versions`]' \ -'--fuzzy[save fuzzy version to `.tool-versions`]' \ +'--pin[Save exact version to `.tool-versions`]' \ +'--fuzzy[Save fuzzy version to `.tool-versions`]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- runtimes to add to .tool-versions:' \ +'*::runtime -- Runtimes to add to .tool-versions:' \ && ret=0 ;; (ls) @@ -529,8 +529,8 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- plugin to get versions for:' \ -'::prefix -- the version prefix to use when querying the latest version same as the first argument after the "@":' \ +':plugin -- Plugin to get versions for:' \ +'::prefix -- The version prefix to use when querying the latest version same as the first argument after the "@":' \ && ret=0 ;; (plugins) @@ -578,10 +578,10 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'-a[list all available remote plugins]' \ -'--all[list all available remote plugins]' \ -'-u[show the git url for each plugin]' \ -'--urls[show the git url for each plugin]' \ +'-a[List all available remote plugins]' \ +'--all[List all available remote plugins]' \ +'-u[Show the git url for each plugin]' \ +'--urls[Show the git url for each plugin]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -593,8 +593,8 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'-u[show the git url for each plugin]' \ -'--urls[show the git url for each plugin]' \ +'-u[Show the git url for each plugin]' \ +'--urls[Show the git url for each plugin]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -610,7 +610,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- plugin to remove:' \ +':plugin -- Plugin to remove:' \ && ret=0 ;; (update) @@ -618,13 +618,13 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'()-a[update all plugins]' \ -'()--all[update all plugins]' \ +'()-a[Update all plugins]' \ +'()--all[Update all plugins]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::plugin -- plugin(s) to update:' \ +'*::plugin -- Plugin(s) to update:' \ && ret=0 ;; (help) @@ -798,7 +798,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- runtime(s) to remove:' \ +'*::runtime -- Runtime(s) to remove:' \ && ret=0 ;; (version) @@ -1106,33 +1106,33 @@ _rtx_commands() { 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ 'bin-paths:List all the active runtime bin paths' \ 'cache:Manage the rtx cache' \ -'complete:generate shell completions' \ -'current:Shows currently active, and installed runtime versions' \ -'deactivate:disable rtx for current shell session' \ +'complete:Generate shell completions' \ +'current:Shows current active and installed runtime versions' \ +'deactivate:Disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ 'env:exports env vars to activate rtx in a single shell session' \ 'e:exports env vars to activate rtx in a single shell session' \ -'exec:execute a command with runtime(s) set' \ -'x:execute a command with runtime(s) set' \ -'global:sets global .tool-versions to include a specified runtime' \ -'g:sets global .tool-versions to include a specified runtime' \ +'exec:Execute a command with runtime(s) set' \ +'x:Execute a command with runtime(s) set' \ +'global:Sets global .tool-versions to include a specified runtime' \ +'g:Sets global .tool-versions to include a specified runtime' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ -'implode:removes rtx CLI and all generated data' \ -'install:install a runtime' \ -'i:install a runtime' \ -'latest:get the latest runtime version of a plugin'\''s runtimes' \ +'implode:Removes rtx CLI and all generated data' \ +'install:Install a runtime' \ +'i:Install a runtime' \ +'latest:Get the latest runtime version of a plugin'\''s runtimes' \ 'local:Sets .tool-versions to include a specific runtime' \ 'l:Sets .tool-versions to include a specific runtime' \ -'ls:list installed runtime versions' \ -'list:list installed runtime versions' \ -'ls-remote:list runtime versions available for install' \ -'list-remote:list runtime versions available for install' \ +'ls:List installed runtime versions' \ +'list:List installed runtime versions' \ +'ls-remote:List runtime versions available for install' \ +'list-remote:List runtime versions available for install' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ -'self-update:updates rtx itself' \ +'self-update:Updates rtx itself' \ 'settings:Manage settings' \ -'uninstall:removes runtime versions' \ +'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ 'render-help:internal command to generate markdown from help' \ @@ -1459,25 +1459,25 @@ _rtx__help_commands() { 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ 'bin-paths:List all the active runtime bin paths' \ 'cache:Manage the rtx cache' \ -'complete:generate shell completions' \ -'current:Shows currently active, and installed runtime versions' \ -'deactivate:disable rtx for current shell session' \ +'complete:Generate shell completions' \ +'current:Shows current active and installed runtime versions' \ +'deactivate:Disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ 'env:exports env vars to activate rtx in a single shell session' \ -'exec:execute a command with runtime(s) set' \ -'global:sets global .tool-versions to include a specified runtime' \ +'exec:Execute a command with runtime(s) set' \ +'global:Sets global .tool-versions to include a specified runtime' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ -'implode:removes rtx CLI and all generated data' \ -'install:install a runtime' \ -'latest:get the latest runtime version of a plugin'\''s runtimes' \ +'implode:Removes rtx CLI and all generated data' \ +'install:Install a runtime' \ +'latest:Get the latest runtime version of a plugin'\''s runtimes' \ 'local:Sets .tool-versions to include a specific runtime' \ -'ls:list installed runtime versions' \ -'ls-remote:list runtime versions available for install' \ +'ls:List installed runtime versions' \ +'ls-remote:List runtime versions available for install' \ 'plugins:Manage plugins' \ -'self-update:updates rtx itself' \ +'self-update:Updates rtx itself' \ 'settings:Manage settings' \ -'uninstall:removes runtime versions' \ +'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ 'render-help:internal command to generate markdown from help' \ @@ -1493,11 +1493,11 @@ _rtx__help__help_commands() { (( $+functions[_rtx__plugins__help_commands] )) || _rtx__plugins__help_commands() { local commands; commands=( -'install:install a plugin' \ +'install:Install a plugin' \ 'ls:List installed plugins' \ 'ls-remote:List all available remote plugins' \ -'uninstall:removes a plugin' \ -'update:updates a plugin to the latest version' \ +'uninstall:Removes a plugin' \ +'update:Updates a plugin to the latest version' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx plugins help commands' commands "$@" @@ -1671,26 +1671,26 @@ _rtx__plugins__ls-remote_commands() { (( $+functions[_rtx__help__plugins_commands] )) || _rtx__help__plugins_commands() { local commands; commands=( -'install:install a plugin' \ +'install:Install a plugin' \ 'ls:List installed plugins' \ 'ls-remote:List all available remote plugins' \ -'uninstall:removes a plugin' \ -'update:updates a plugin to the latest version' \ +'uninstall:Removes a plugin' \ +'update:Updates a plugin to the latest version' \ ) _describe -t commands 'rtx help plugins commands' commands "$@" } (( $+functions[_rtx__plugins_commands] )) || _rtx__plugins_commands() { local commands; commands=( -'install:install a plugin' \ -'i:install a plugin' \ -'a:install a plugin' \ +'install:Install a plugin' \ +'i:Install a plugin' \ +'a:Install a plugin' \ 'ls:List installed plugins' \ 'list:List installed plugins' \ 'ls-remote:List all available remote plugins' \ 'list-remote:List all available remote plugins' \ -'uninstall:removes a plugin' \ -'update:updates a plugin to the latest version' \ +'uninstall:Removes a plugin' \ +'update:Updates a plugin to the latest version' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx plugins commands' commands "$@" diff --git a/completions/rtx.fish b/completions/rtx.fish index 95dca0663..f7daabab0 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -8,25 +8,25 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' complete -c rtx -n "__fish_use_subcommand" -f -a "bin-paths" -d 'List all the active runtime bin paths' complete -c rtx -n "__fish_use_subcommand" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows currently active, and installed runtime versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'Disable rtx for current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'execute a command with runtime(s) set' -complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'removes rtx CLI and all generated data' -complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'install a runtime' -complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'list runtime versions available for install' +complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'updates rtx itself' +complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' @@ -103,7 +103,7 @@ complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set th complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' @@ -145,16 +145,16 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the lo complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'the command string to execute' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'remove the plugin(s) from ~/.tool-versions' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'save exact version to `~/.tool-versions`' -complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'save fuzzy version to `~/.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" @@ -165,28 +165,28 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Sh complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'also remove config directory' -complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'list directories that would be removed without actually removing them' +complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' +complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'only install runtime(s) for ' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only install runtime(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'force reinstall even if already installed' -complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'install all missing runtimes as well as all plugins for the current directory' +complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' +complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing runtimes as well as all plugins for the current directory' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'remove the plugin(s) from .tool-versions' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'recurse up to find a .tool-versions file rather than using the current directory only +complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' -complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'save exact version to `.tool-versions`' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'save fuzzy version to `.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r @@ -205,11 +205,11 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes a plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r @@ -219,13 +219,13 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'list all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r @@ -234,14 +234,14 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'update all plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes a plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'updates a plugin to the latest version' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r @@ -298,25 +298,25 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows currently active, and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'removes rtx CLI and all generated data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'list installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'list runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' @@ -333,11 +333,11 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "install" -d 'install a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "install" -d 'Install a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "ls" -d 'List installed plugins' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "ls-remote" -d 'List all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "uninstall" -d 'removes a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "update" -d 'updates a plugin to the latest version' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "uninstall" -d 'Removes a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show a current setting' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'Show current settings' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "set" -d 'Add/update a setting' diff --git a/justfile b/justfile index 69ef1513a..327799452 100644 --- a/justfile +++ b/justfile @@ -70,7 +70,7 @@ lint-fix: # regenerate README.md render-help: ./.bin/rtx render-help > README.md - ./scripts/gh-md-toc --insert --no-backup --hide-footer --skip-header README.md + ./scripts/gh-md-toc --insert --no-backup --hide-footer --skip-header README.md > /dev/null # regenerate shell completion files render-completions: diff --git a/src/cli/command.rs b/src/cli/command.rs index 4790ecc5a..b4e7741dc 100644 --- a/src/cli/command.rs +++ b/src/cli/command.rs @@ -3,7 +3,7 @@ use color_eyre::eyre::Result; use crate::config::Config; use crate::output::Output; -/// described a CLI command +/// Describes a CLI command /// /// e.g.: `rtx plugins ls` pub trait Command: Sized { diff --git a/src/cli/complete.rs b/src/cli/complete.rs index 8b611a0a4..502c29026 100644 --- a/src/cli/complete.rs +++ b/src/cli/complete.rs @@ -11,7 +11,7 @@ use crate::cli::Cli; use crate::config::Config; use crate::output::Output; -/// generate shell completions +/// Generate shell completions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Complete { @@ -33,7 +33,9 @@ impl Command for Complete { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx complete + $ rtx complete -s bash > /etc/bash_completion.d/rtx + $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx + $ rtx complete -s fish > ~/.config/fish/completions/rtx.fish "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/current.rs b/src/cli/current.rs index 9649cd4b1..3451d36bf 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -9,15 +9,14 @@ use crate::output::Output; use crate::plugins::Plugin; use crate::toolset::{Toolset, ToolsetBuilder}; -/// Shows currently active, and installed runtime versions +/// Shows current active and installed runtime versions /// -/// This is similar to `rtx list --current`, but this -/// only shows the runtime and/or version so it's -/// designed to fit into scripts more easily. +/// This is similar to `rtx ls --current`, but this only shows the runtime +/// and/or version. It's designed to fit into scripts more easily. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Current { - /// plugin to show versions of + /// Plugin to show versions of /// /// e.g.: ruby, nodejs #[clap()] diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index f5bf7ba29..7d33d65f6 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -8,17 +8,17 @@ use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -/// disable rtx for current shell session +/// Disable rtx for current shell session /// /// This can be used to temporarily disable rtx in a shell session. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Deactivate { - /// shell type to generate the script for + /// Shell type to generate the script for #[clap(long, short, hide = true)] shell: Option, - /// shell type to generate the script for + /// Shell type to generate the script for #[clap()] shell_type: Option, } diff --git a/src/cli/env.rs b/src/cli/env.rs index 8067c0287..31ec60328 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -12,10 +12,10 @@ use crate::toolset::ToolsetBuilder; /// exports env vars to activate rtx in a single shell session /// -/// It's not necessary to use this if you have `rtx activate` in your shell rc file. -/// Use this if you don't want to permanently install rtx. -/// This can be used similarly to `asdf shell`. -/// Unfortunately, it requires `eval` to work since it's not written in Bash though. +/// Use this if you don't want to permanently install rtx. It's not necessary to +/// use this if you have `rtx activate` in your shell rc file. +/// This can be used similarly to `asdf shell`. It requires `eval` to work since +/// it's not written in Bash. /// It's also useful just to see what environment variables rtx sets. #[derive(Debug, clap::Args)] #[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] @@ -24,7 +24,7 @@ pub struct Env { #[clap(long, short)] shell: Option, - /// runtime version to use + /// Runtime version to use #[clap(value_parser = RuntimeArgParser)] runtime: Vec, } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 85d0163ea..042ae46a2 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -17,7 +17,7 @@ use crate::env; use crate::output::Output; use crate::toolset::ToolsetBuilder; -/// execute a command with runtime(s) set +/// Execute a command with runtime(s) set /// /// use this to avoid modifying the shell session or running ad-hoc commands with the rtx runtimes /// set. @@ -30,17 +30,17 @@ use crate::toolset::ToolsetBuilder; #[derive(Debug, clap::Args)] #[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Exec { - /// runtime(s) to start + /// Runtime(s) to start /// /// e.g.: nodejs@20 python@3.10 #[clap(value_parser = RuntimeArgParser)] runtime: Vec, - /// the command string to execute (same as --command) + /// Command string to execute (same as --command) #[clap(conflicts_with = "c", required_unless_present = "c", last = true)] command: Option>, - /// the command string to execute + /// Command string to execute #[clap(short, long = "command", conflicts_with = "command")] c: Option, } diff --git a/src/cli/global.rs b/src/cli/global.rs index df5fbc539..e7a1a1149 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -10,36 +10,36 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; -/// sets global .tool-versions to include a specified runtime +/// Sets global .tool-versions to include a specified runtime /// -/// then displays the contents of ~/.tool-versions -/// this file is `$HOME/.tool-versions` by default -/// use `rtx local` to set a runtime version locally in the current directory +/// Displays the contents of ~/.tool-versions after writing. +/// The file is `$HOME/.tool-versions` by default. +/// Use `rtx local` to set a runtime version locally in the current directory. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Global { - /// runtime(s) to add to .tool-versions + /// Runtime(s) to add to .tool-versions /// /// e.g.: nodejs@20 - /// if this is a single runtime with no version, the current value of the global + /// If this is a single runtime with no version, the current value of the global /// .tool-versions will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, - /// save exact version to `~/.tool-versions` + /// Save exact version to `~/.tool-versions` /// /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, - /// save fuzzy version to `~/.tool-versions` + /// Save fuzzy version to `~/.tool-versions` /// /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, - /// remove the plugin(s) from ~/.tool-versions + /// Remove the plugin(s) from ~/.tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] remove: Option>, } diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 7dc7a68bb..22c6fc89b 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -5,17 +5,17 @@ use crate::config::Config; use crate::output::Output; use crate::{dirs, env}; -/// removes rtx CLI and all generated data +/// Removes rtx CLI and all generated data /// -/// skips config directory by default +/// Skips config directory by default. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment)] pub struct Implode { - /// also remove config directory + /// Also remove config directory #[clap(long, verbatim_doc_comment)] config: bool, - /// list directories that would be removed without actually removing them + /// List directories that would be removed without actually removing them #[clap(long, verbatim_doc_comment)] dry_run: bool, } diff --git a/src/cli/install.rs b/src/cli/install.rs index 699c7b18d..447626fd0 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -14,10 +14,10 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::toolset::ToolsetBuilder; -/// install a runtime +/// Install a runtime /// -/// this will install a runtime to `~/.local/share/rtx/installs//` -/// it won't be used simply by being installed, however. +/// This will install a runtime to `~/.local/share/rtx/installs//` +/// It won't be used simply by being installed, however. /// For that, you must set up a `.tool-version` file manually or with `rtx local/global`. /// Or you can call a runtime explicitly with `rtx exec @ -- `. /// @@ -25,23 +25,23 @@ use crate::toolset::ToolsetBuilder; #[derive(Debug, clap::Args)] #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Install { - /// runtime(s) to install + /// Runtime(s) to install /// /// e.g.: nodejs@20 #[clap(value_parser = RuntimeArgParser)] runtime: Option>, - /// only install runtime(s) for + /// Only install runtime(s) for #[clap(long, short, conflicts_with = "runtime")] plugin: Option>, - /// force reinstall even if already installed + /// Force reinstall even if already installed #[clap(long, short, requires = "runtime")] force: bool, - /// install all missing runtimes as well as all plugins for the current directory + /// Install all missing runtimes as well as all plugins for the current directory /// - /// this is hidden because it's now the default behavior + /// This is hidden because it's now the default behavior #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"], hide = true)] all: bool, diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 52fc40091..a299598fb 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -8,7 +8,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -/// get the latest runtime version of a plugin's runtimes +/// Get the latest runtime version of a plugin's runtimes #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Latest { @@ -16,7 +16,7 @@ pub struct Latest { #[clap(value_parser = RuntimeArgParser)] runtime: RuntimeArg, - /// the version prefix to use when querying the latest version + /// The version prefix to use when querying the latest version /// same as the first argument after the "@" /// used for asdf compatibility #[clap(hide = true)] diff --git a/src/cli/local.rs b/src/cli/local.rs index d81827212..a088e8686 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -18,7 +18,7 @@ use crate::{dirs, env, file}; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Local { - /// runtimes to add to .tool-versions + /// Runtimes to add to .tool-versions /// /// e.g.: nodejs@20 /// if this is a single runtime with no version, @@ -26,25 +26,25 @@ pub struct Local { #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, - /// recurse up to find a .tool-versions file rather than using the current directory only + /// Recurse up to find a .tool-versions file rather than using the current directory only /// by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") #[clap(short, long, verbatim_doc_comment)] parent: bool, - /// save exact version to `.tool-versions` + /// Save exact version to `.tool-versions` /// /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, - /// save fuzzy version to `.tool-versions` + /// Save fuzzy version to `.tool-versions` /// /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, - /// remove the plugin(s) from .tool-versions + /// Remove the plugin(s) from .tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] remove: Option>, } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index fd79e85d2..a6106b1eb 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -16,7 +16,7 @@ use crate::plugins::PluginName; use crate::runtimes::RuntimeVersion; use crate::toolset::{ToolSource, ToolsetBuilder}; -/// list installed runtime versions +/// List installed runtime versions /// /// The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. /// (Assuming `rtx activate` or `rtx env` is in use). diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index e856977ce..1094665ca 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -9,18 +9,18 @@ use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -/// list runtime versions available for install +/// List runtime versions available for install /// /// note that these versions are cached for commands like `rtx install nodejs@latest` /// however _this_ command will always clear that cache and fetch the latest remote versions #[derive(Debug, clap::Args)] #[clap(visible_alias = "list-remote", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), alias = "list-all")] pub struct LsRemote { - /// plugin to get versions for + /// Plugin to get versions for #[clap(value_parser = RuntimeArgParser)] plugin: RuntimeArg, - /// the version prefix to use when querying the latest version + /// The version prefix to use when querying the latest version /// same as the first argument after the "@" #[clap()] prefix: Option, diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 3e3a5c3c9..90e23dfb7 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -12,7 +12,7 @@ use crate::shorthand::shorthand_to_repository; use crate::toolset::ToolsetBuilder; use crate::ui::progress_report::ProgressReport; -/// install a plugin +/// Install a plugin /// /// note that rtx automatically can install plugins when you install a runtime /// e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 93a459c4e..7166916ee 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -14,13 +14,13 @@ use crate::output::Output; #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct PluginsLs { - /// list all available remote plugins + /// List all available remote plugins /// /// same as `rtx plugins ls-remote` #[clap(short, long)] pub all: bool, - /// show the git url for each plugin + /// Show the git url for each plugin /// /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long)] diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 311bae5df..615f02d64 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -14,7 +14,7 @@ use crate::shorthand::SHORTHAND_MAP; #[derive(Debug, clap::Args)] #[clap(visible_alias = "list-remote", long_about = LONG_ABOUT, verbatim_doc_comment, alias = "list-all")] pub struct PluginsLsRemote { - /// show the git url for each plugin + /// Show the git url for each plugin /// /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long)] diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index ec3a16df6..aff6c7bfe 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -7,11 +7,11 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -/// removes a plugin +/// Removes a plugin #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP.as_str())] pub struct PluginsUninstall { - /// plugin to remove + /// Plugin to remove #[clap()] plugin: String, } diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 0f31b53ce..96c9ebc35 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -10,17 +10,17 @@ use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; -/// updates a plugin to the latest version +/// Updates a plugin to the latest version /// /// note: this updates the plugin itself, not the runtime versions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, alias = "upgrade", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Update { - /// plugin(s) to update + /// Plugin(s) to update #[clap()] plugin: Option>, - /// update all plugins + /// Update all plugins #[clap(long, short = 'a', conflicts_with = "plugin")] all: bool, } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index cffdcd17d..a5406a810 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -825,7 +825,7 @@ fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option ``` ", name = name, - about = strip_ansi_codes(&c.render_long_help().to_string()), + about = strip_ansi_codes(&c.render_long_help().to_string()).trim(), )) } diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 33f48b7e3..2d5ac518d 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -9,7 +9,7 @@ use crate::config::Config; use crate::env; use crate::output::Output; -/// updates rtx itself +/// Updates rtx itself #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment)] pub struct SelfUpdate {} diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index fe0f06380..2e0d9a5d9 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -9,11 +9,11 @@ use crate::config::Config; use crate::output::Output; use crate::toolset::ToolsetBuilder; -/// removes runtime versions +/// Removes runtime versions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Uninstall { - /// runtime(s) to remove + /// Runtime(s) to remove #[clap(required = true, value_parser = RuntimeArgParser)] runtime: Vec, } From 0d395467ff9f815537a9eaea847f3b4d9de115b3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 01:12:29 -0600 Subject: [PATCH 0244/1891] docs --- README.md | 122 ----------------------------------------- src/cli/render_help.rs | 7 ++- 2 files changed, 6 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index 6dbfa2201..58f3abf08 100644 --- a/README.md +++ b/README.md @@ -669,9 +669,6 @@ Options: --status Show "rtx: @" message when changing directories - -h, --help - Print help (see a summary with '-h') - Examples: $ eval "$(rtx activate bash)" $ eval "$(rtx activate zsh)" @@ -694,10 +691,6 @@ Arguments: The alias to show -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx alias get nodejs lts/hydrogen 18.0.0 @@ -720,9 +713,6 @@ Options: -p, --plugin Show aliases for - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx aliases nodejs lts/hydrogen 18.0.0 @@ -746,10 +736,6 @@ Arguments: The value to set the alias to -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx alias set nodejs lts/hydrogen 18.0.0 ``` @@ -769,10 +755,6 @@ Arguments: The alias to remove -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx alias unset nodejs lts/hydrogen ``` @@ -782,10 +764,6 @@ Examples: List all the active runtime bin paths Usage: bin-paths - -Options: - -h, --help - Print help ``` ### `rtx cache clear` @@ -793,10 +771,6 @@ Options: Deletes all cache files in rtx Usage: clear - -Options: - -h, --help - Print help ``` ### `rtx complete` @@ -811,9 +785,6 @@ Options: [possible values: bash, elvish, fish, powershell, zsh] - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx complete -s bash > /etc/bash_completion.d/rtx $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx @@ -835,10 +806,6 @@ Arguments: e.g.: ruby, nodejs -Options: - -h, --help - Print help (see a summary with '-h') - Examples: # outputs `.tool-versions` compatible format $ rtx current @@ -869,10 +836,6 @@ Arguments: [possible values: bash, fish, xonsh, zsh] -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ eval "$(rtx deactivate bash)" $ eval "$(rtx deactivate zsh)" @@ -892,10 +855,6 @@ direnv may not know to update environment variables when legacy file versions ch Usage: activate -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh $ echo 'use rtx' > .envrc @@ -908,10 +867,6 @@ Check rtx installation for possible problems. Usage: doctor -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx doctor [WARN] plugin nodejs is not installed @@ -939,9 +894,6 @@ Options: [possible values: bash, fish, xonsh, zsh] - -h, --help - Print help (see a summary with '-h') - Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" @@ -977,9 +929,6 @@ Options: -c, --command Command string to execute - -h, --help - Print help (see a summary with '-h') - Examples: rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x rtx x nodejs@20 -- node ./app.js # shorter alias @@ -1020,9 +969,6 @@ Options: --remove Remove the plugin(s) from ~/.tool-versions - -h, --help - Print help (see a summary with '-h') - Examples: # set the current version of nodejs to 20.x # will use a precise version (e.g.: 20.0.0) in .tool-versions file @@ -1051,9 +997,6 @@ Options: --dry-run List directories that would be removed without actually removing them - - -h, --help - Print help (see a summary with '-h') ``` ### `rtx install` @@ -1085,9 +1028,6 @@ Options: -v, --verbose... Show installation output - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version @@ -1106,10 +1046,6 @@ Arguments: Runtime to get the latest version of -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx latest nodejs@18 # get the latest version of nodejs 18 18.0.0 @@ -1154,9 +1090,6 @@ Options: --remove Remove the plugin(s) from .tool-versions - -h, --help - Print help (see a summary with '-h') - Examples: # set the current version of nodejs to 20.x for the current directory # will use a precise version (e.g.: 20.0.0) in .tool-versions file @@ -1193,9 +1126,6 @@ Options: -c, --current Only show runtimes currently specified in .tool-versions - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx list -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) @@ -1223,10 +1153,6 @@ Arguments: [PREFIX] The version prefix to use when querying the latest version same as the first argument after the "@" -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx ls-remote nodejs 18.0.0 @@ -1276,9 +1202,6 @@ Options: -v, --verbose... Show installation output - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx install nodejs # install the nodejs plugin using the shorthand repo: # https://github.com/asdf-vm/asdf-plugins @@ -1310,9 +1233,6 @@ Options: e.g.: https://github.com/asdf-vm/asdf-nodejs.git - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx plugins ls nodejs @@ -1340,9 +1260,6 @@ Options: Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git - - -h, --help - Print help (see a summary with '-h') ``` ### `rtx plugins uninstall` @@ -1355,10 +1272,6 @@ Arguments: Plugin to remove -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx uninstall nodejs ``` @@ -1379,9 +1292,6 @@ Options: -a, --all Update all plugins - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx plugins update --all # update all plugins $ rtx plugins update nodejs # update only nodejs @@ -1392,10 +1302,6 @@ Examples: Updates rtx itself Usage: self-update - -Options: - -h, --help - Print help ``` ### `rtx settings get` @@ -1413,10 +1319,6 @@ Arguments: The setting to show -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx settings get legacy_version_file true @@ -1433,10 +1335,6 @@ but managed separately with `rtx aliases` Usage: ls -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx settings legacy_version_file = false @@ -1457,10 +1355,6 @@ Arguments: The value to set -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx settings set legacy_version_file true ``` @@ -1477,10 +1371,6 @@ Arguments: The setting to remove -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx settings unset legacy_version_file ``` @@ -1495,10 +1385,6 @@ Arguments: ... Runtime(s) to remove -Options: - -h, --help - Print help (see a summary with '-h') - Examples: $ rtx uninstall nodejs@18.0.0 # will uninstall specific version $ rtx uninstall nodejs # will uninstall current nodejs version @@ -1509,10 +1395,6 @@ Examples: Show rtx version Usage: version - -Options: - -h, --help - Print help ``` ### `rtx where` @@ -1527,10 +1409,6 @@ Arguments: runtime(s) to look up if "@" is specified, it will show the latest installed version that matches the prefix otherwise, it will show the current, active installed version -Options: - -h, --help - Print help (see a summary with '-h') - Examples: # Show the latest installed version of nodejs # If it is is not installed, errors diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index a5406a810..e1d730dfc 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -14,7 +14,11 @@ pub struct RenderHelp {} impl Command for RenderHelp { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let mut cli = Cli::command().term_width(80).max_term_width(80); + let mut cli = Cli::command() + .term_width(80) + .max_term_width(80) + .disable_help_subcommand(true) + .disable_help_flag(true); out.stdout.write(formatdoc!( r#" @@ -809,6 +813,7 @@ $ just lint-fix } fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option { + let mut c = c.clone().disable_help_flag(true); if c.is_hide_set() { return None; } From 4808e6373a04718732187cff9f728a4f5541d820 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 01:14:21 -0600 Subject: [PATCH 0245/1891] docs --- README.md | 11 ++++++----- src/cli/plugins/install.rs | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 58f3abf08..1b594787a 100644 --- a/README.md +++ b/README.md @@ -1203,15 +1203,16 @@ Options: Show installation output Examples: - $ rtx install nodejs # install the nodejs plugin using the shorthand repo: - # https://github.com/asdf-vm/asdf-plugins + # install the nodejs plugin using the shorthand repo: + # https://github.com/asdf-vm/asdf-plugins + $ rtx install nodejs + # install the nodejs plugin using the git url $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git - # install the nodejs plugin using the git url + # install the nodejs plugin using the git url only + # (nodejs is inferred from the url) $ rtx install https://github.com/asdf-vm/asdf-nodejs.git - # install the nodejs plugin using the git url only - # (nodejs is inferred from the url) ``` ### `rtx plugins ls` diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 90e23dfb7..0f16a25b4 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -123,15 +123,16 @@ fn get_name_from_url(url: &str) -> Result { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx install nodejs # install the nodejs plugin using the shorthand repo: - # https://github.com/asdf-vm/asdf-plugins + # install the nodejs plugin using the shorthand repo: + # https://github.com/asdf-vm/asdf-plugins + $ rtx install nodejs + # install the nodejs plugin using the git url $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git - # install the nodejs plugin using the git url + # install the nodejs plugin using the git url only + # (nodejs is inferred from the url) $ rtx install https://github.com/asdf-vm/asdf-nodejs.git - # install the nodejs plugin using the git url only - # (nodejs is inferred from the url) "#, style("Examples:").bold().underlined()} }); From 6b57b5938d9b2f81b1913db69bbb68b5de703b95 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 01:30:02 -0600 Subject: [PATCH 0246/1891] docs --- src/cli/mod.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 027dcf82f..96d72d01f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -142,6 +142,7 @@ impl Cli { clap::Command::new("rtx") .version(version::VERSION.to_string()) .about(env!("CARGO_PKG_DESCRIPTION")) + .author("Jeff Dickey <@jdxcode>") .long_about(LONG_ABOUT) .arg_required_else_help(true) .subcommand_required(true) @@ -182,17 +183,14 @@ impl Cli { } const LONG_ABOUT: &str = indoc! {" -rtx is a tool for managing runtime versions. +rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx -Use this to install a particular version of node or ruby for a project. Using `rtx activate`, -you can also have your shell automatically switch to the correct node and ruby versions when you -`cd` into the project's directory. +It's a replacement for tools like nvm, nodenv, rbenv, rvm, chruby, pyenv, etc. +that works for any language. It's also great for managing linters/tools like +jq and shellcheck. -It's a replacement for tools like `nvm`, `nodenv`, `rbenv`, `rvm`, `chruby`, `pyenv`, etc. that -works for any language. It's also great for managing linters/tools like `jq` and `shellcheck`. - -It is inspired by asdf and uses asdf's plugin ecosystem under the hood: https://asdf-vm.com/ -"}; +It is inspired by asdf and uses asdf's plugin ecosystem under the hood: +https://asdf-vm.com/"}; static AFTER_HELP: Lazy = Lazy::new(|| { formatdoc! { " @@ -202,11 +200,12 @@ static AFTER_HELP: Lazy = Lazy::new(|| { rtx local nodejs@20 Use node-20.x in current project rtx global nodejs@20 Use node-20.x as default - rtx install nodejs Install the version specified in .tool-versions + rtx install nodejs Install the .tool-versions node version rtx local nodejs Use latest node in current directory rtx global system Use system node everywhere unless overridden - rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to node-20.x + rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to + node-20.x ", style("Examples:").bold().underlined() } }); From df1c32239d00fbf4c6c2695794c56947cd7960dd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 08:28:41 -0600 Subject: [PATCH 0247/1891] feat: add RTX_SHORTHANDS_FILE (#177) Fixes #163 --- README.md | 14 ++++ scripts/update-shorthand-repo.sh | 15 ++-- src/cli/mod.rs | 10 +-- src/cli/plugins/install.rs | 17 ++-- src/cli/plugins/ls_remote.rs | 22 +++-- src/cli/render_help.rs | 14 ++++ src/cli/settings/set.rs | 3 + src/config/config_file/rtxrc.rs | 11 +++ src/config/mod.rs | 10 +++ src/config/settings.rs | 17 +++- ...horthand_list.rs => default_shorthands.rs} | 7 +- src/env.rs | 52 ++++++++---- src/main.rs | 4 +- src/plugins/mod.rs | 18 ++-- src/shorthand.rs | 15 ---- src/shorthands.rs | 82 +++++++++++++++++++ src/toolset/mod.rs | 2 +- test/fixtures/shorthands.toml | 2 + 18 files changed, 245 insertions(+), 70 deletions(-) rename src/{shorthand_list.rs => default_shorthands.rs} (99%) delete mode 100644 src/shorthand.rs create mode 100644 src/shorthands.rs create mode 100644 test/fixtures/shorthands.toml diff --git a/README.md b/README.md index 1b594787a..4081a3999 100644 --- a/README.md +++ b/README.md @@ -481,6 +481,8 @@ plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable u verbose = false # set to true to see full installation output, see `RTX_VERBOSE` asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. + +shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` [alias.nodejs] @@ -558,6 +560,18 @@ Only output `.tool-versions` files in `rtx local|global` which will be usable by Set the number plugins or runtimes to install in parallel. The default is `4`. +#### `RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml` + +Use a custom file for the shorthand aliases. This is useful if you want to share plugins within +an organization. + +The file should be in toml format: + +```toml +elixir = "https://github.com/my-org/rtx-elixir.git" +nodejs = "https://github.com/my-org/rtx-nodejs.git" +``` + #### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` Disables the shorthand aliases for installing plugins. You will have to specify full urls when diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index 3ae09fec2..fbf0730b2 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -3,18 +3,23 @@ set -euo pipefail rm -rf asdf-plugins git clone --depth 1 https://github.com/asdf-vm/asdf-plugins -rm -f src/shorthand_list.rs +rm -f src/default_shorthands.rs num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') num_plugins=$((num_plugins + 2)) # +2 for custom aliases (node, tiny, etc) -cat > src/shorthand_list.rs < src/default_shorthands.rs <> = + Lazy::new(|| HashMap::from(DEFAULT_SHORTHAND_LIST)); #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -pub const SHORTHAND_LIST: [(&str, &str); $num_plugins] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); $num_plugins] = [ // rtx custom aliases ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), @@ -25,9 +30,9 @@ for file in asdf-plugins/plugins/*; do plugin=$(basename "$file") repository=$(cat "$file") repository="${repository/#repository = }" - echo " (\"$plugin\", \"$repository\")," >> src/shorthand_list.rs + echo " (\"$plugin\", \"$repository\")," >> src/default_shorthands.rs done -cat >> src/shorthand_list.rs <> src/default_shorthands.rs < = Lazy::new(|| { #[cfg(test)] pub mod tests { use crate::config::MissingRuntimeBehavior::AutoInstall; - use crate::config::Settings; + use crate::dirs; use crate::plugins::{Plugin, PluginName}; use crate::ui::progress_report::ProgressReport; @@ -256,14 +256,12 @@ pub mod tests { } pub fn ensure_plugin_installed(name: &str) { - let settings = Settings { - missing_runtime_behavior: AutoInstall, - ..Settings::default() - }; + let mut config = Config::load().unwrap(); + config.settings.missing_runtime_behavior = AutoInstall; let plugin = Plugin::new(&PluginName::from(name)); if plugin.is_installed() { plugin - .install(&settings, None, ProgressReport::new(true)) + .install(&config, None, ProgressReport::new(true)) .unwrap(); } } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 0f16a25b4..7827f9cd6 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -5,10 +5,9 @@ use once_cell::sync::Lazy; use url::Url; use crate::cli::command::Command; -use crate::config::{Config, Settings}; +use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; -use crate::shorthand::shorthand_to_repository; use crate::toolset::ToolsetBuilder; use crate::ui::progress_report::ProgressReport; @@ -54,7 +53,7 @@ impl Command for PluginsInstall { if self.all { return self.install_all_missing_plugins(&config); } - let (name, git_url) = get_name_and_url(&config.settings, self.name.unwrap(), self.git_url)?; + let (name, git_url) = get_name_and_url(&config, self.name.unwrap(), self.git_url)?; let plugin = Plugin::new(&name); if self.force { plugin.uninstall()?; @@ -63,7 +62,7 @@ impl Command for PluginsInstall { warn!("plugin {} already installed", name); } else { let pr = ProgressReport::new(config.settings.verbose); - plugin.install(&config.settings, Some(&git_url), pr)?; + plugin.install(&config, Some(&git_url), pr)?; } Ok(()) @@ -79,9 +78,9 @@ impl PluginsInstall { } for plugin in missing_plugins { let plugin = Plugin::new(&plugin); - let (_, git_url) = get_name_and_url(&config.settings, plugin.name.clone(), None)?; + let (_, git_url) = get_name_and_url(config, plugin.name.clone(), None)?; plugin.install( - &config.settings, + config, Some(&git_url), ProgressReport::new(config.settings.verbose), )?; @@ -91,7 +90,7 @@ impl PluginsInstall { } fn get_name_and_url( - settings: &Settings, + config: &Config, name: String, git_url: Option, ) -> Result<(String, String)> { @@ -100,7 +99,9 @@ fn get_name_and_url( None => match name.contains(':') { true => (get_name_from_url(&name)?, name), false => { - let git_url = shorthand_to_repository(settings, &name) + let git_url = config + .get_shorthands() + .get(&name) .ok_or_else(|| eyre!("could not find plugin {}", name))?; (name, git_url.to_string()) } diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 615f02d64..3ecd9be6a 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -1,12 +1,12 @@ use std::collections::HashSet; use color_eyre::eyre::Result; +use console::{measure_text_width, pad_str, Alignment}; use itertools::Itertools; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::shorthand::SHORTHAND_MAP; /// List all available remote plugins /// @@ -30,18 +30,26 @@ impl Command for PluginsLsRemote { .map(|p| p.name.clone()) .collect::>(); - if config.settings.disable_default_shorthands { + let shorthands = config.get_shorthands().iter().sorted().collect_vec(); + let max_plugin_len = shorthands + .iter() + .map(|(plugin, _)| measure_text_width(plugin)) + .max() + .unwrap_or(0); + + if shorthands.is_empty() { warn!("default shorthands are disabled"); - return Ok(()); } - for (plugin, repo) in SHORTHAND_MAP.iter().sorted().collect_vec() { - let installed = if installed_plugins.contains(*plugin) { + + for (plugin, repo) in shorthands { + let installed = if installed_plugins.contains(plugin) { "*" } else { " " }; - let url = if self.urls { *repo } else { "" }; - rtxprintln!(out, "{:28} {}{}", plugin, installed, url); + let url = if self.urls { repo } else { "" }; + let plugin = pad_str(plugin, max_plugin_len, Alignment::Left, None); + rtxprintln!(out, "{} {}{}", plugin, installed, url); } Ok(()) diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e1d730dfc..02b3dc0bb 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -411,6 +411,8 @@ plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable u verbose = false # set to true to see full installation output, see `RTX_VERBOSE` asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. + +shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` [alias.nodejs] @@ -488,6 +490,18 @@ Only output `.tool-versions` files in `rtx local|global` which will be usable by Set the number plugins or runtimes to install in parallel. The default is `4`. +#### `RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml` + +Use a custom file for the shorthand aliases. This is useful if you want to share plugins within +an organization. + +The file should be in toml format: + +```toml +elixir = "https://github.com/my-org/rtx-elixir.git" +nodejs = "https://github.com/my-org/rtx-nodejs.git" +``` + #### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` Disables the shorthand aliases for installing plugins. You will have to specify full urls when diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 01c845f20..b08be844d 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -29,6 +29,9 @@ impl Command for SettingsSet { "legacy_version_file" => parse_bool(&self.value)?, "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, "verbose" => parse_bool(&self.value)?, + "jobs" => parse_i64(&self.value)?, + "shorthands_file" => self.value.into(), + "disable_default_shorthands" => parse_bool(&self.value)?, _ => return Err(eyre!("Unknown setting: {}", self.key)), }; diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 953b0dbab..910a55a46 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -98,6 +98,10 @@ impl RTXFile { } "verbose" => self.settings.verbose = Some(self.parse_bool(k, v)?), "jobs" => self.settings.jobs = Some(self.parse_usize(k, v)?), + "shorthands_file" => self.settings.shorthands_file = Some(self.parse_path(k, v)?), + "disable_default_shorthands" => { + self.settings.disable_default_shorthands = Some(self.parse_bool(k, v)?) + } "log_level" => self.settings.log_level = Some(self.parse_log_level(v)?), "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} @@ -182,6 +186,13 @@ impl RTXFile { } } + fn parse_path(&self, k: &str, v: &Value) -> Result { + match v { + Value::String(v) => Ok(v.into()), + _ => Err(eyre!("expected {k} to be a path, got: {v}")), + } + } + fn parse_string(&self, k: &str, v: &Value) -> Result { match v { Value::String(v) => Ok(v.clone()), diff --git a/src/config/mod.rs b/src/config/mod.rs index 4e9eb98d8..4e7287252 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -6,12 +7,14 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; use color_eyre::Report; use indexmap::IndexMap; use itertools::Itertools; +use once_cell::sync::OnceCell; use rayon::prelude::*; pub use settings::{MissingRuntimeBehavior, Settings}; use crate::config::config_file::rtxrc::RTXFile; use crate::plugins::{Plugin, PluginName}; +use crate::shorthands::{get_shorthands, Shorthands}; use crate::{dirs, env, file}; pub mod config_file; @@ -27,6 +30,7 @@ pub struct Config { pub config_files: Vec, pub aliases: AliasMap, pub plugins: IndexMap>, + shorthands: OnceCell>, } impl Config { @@ -45,12 +49,18 @@ impl Config { aliases, rtxrc, plugins, + shorthands: OnceCell::new(), }; debug!("{}", &config); Ok(config) } + + pub fn get_shorthands(&self) -> &Shorthands { + self.shorthands + .get_or_init(|| get_shorthands(&self.settings)) + } } fn load_rtxrc() -> Result { diff --git a/src/config/settings.rs b/src/config/settings.rs index af34b2c1d..239f41ed0 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,4 +1,5 @@ use std::fmt::{Display, Formatter}; +use std::path::PathBuf; use std::time::Duration; use indexmap::IndexMap; @@ -7,7 +8,8 @@ use log::LevelFilter; use crate::config::AliasMap; use crate::env; use crate::env::{ - RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_VERBOSE, + RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_SHORTHANDS_FILE, + RTX_VERBOSE, }; use crate::plugins::PluginName; @@ -21,6 +23,7 @@ pub struct Settings { pub verbose: bool, pub asdf_compat: bool, pub jobs: usize, + pub shorthands_file: Option, pub disable_default_shorthands: bool, pub log_level: LevelFilter, } @@ -36,6 +39,7 @@ impl Default for Settings { verbose: *RTX_VERBOSE || !console::user_attended_stderr(), asdf_compat: *RTX_ASDF_COMPAT, jobs: *RTX_JOBS, + shorthands_file: RTX_SHORTHANDS_FILE.clone(), disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, log_level: *RTX_LOG_LEVEL, } @@ -64,6 +68,12 @@ impl Settings { map.insert("verbose".into(), self.verbose.to_string()); map.insert("asdf_compat".into(), self.asdf_compat.to_string()); map.insert("jobs".into(), self.jobs.to_string()); + if let Some(shorthands_file) = &self.shorthands_file { + map.insert( + "shorthands_file".into(), + shorthands_file.to_string_lossy().to_string(), + ); + } map.insert( "disable_default_shorthands".into(), self.disable_default_shorthands.to_string(), @@ -83,6 +93,7 @@ pub struct SettingsBuilder { pub verbose: Option, pub asdf_compat: Option, pub jobs: Option, + pub shorthands_file: Option, pub disable_default_shorthands: Option, pub log_level: Option, } @@ -117,6 +128,9 @@ impl SettingsBuilder { if other.jobs.is_some() { self.jobs = other.jobs; } + if other.shorthands_file.is_some() { + self.shorthands_file = other.shorthands_file; + } if other.disable_default_shorthands.is_some() { self.disable_default_shorthands = other.disable_default_shorthands; } @@ -157,6 +171,7 @@ impl SettingsBuilder { settings.verbose = self.verbose.unwrap_or(settings.verbose); settings.asdf_compat = self.asdf_compat.unwrap_or(settings.asdf_compat); settings.jobs = self.jobs.unwrap_or(settings.jobs); + settings.shorthands_file = self.shorthands_file.clone().or(settings.shorthands_file); settings.disable_default_shorthands = self .disable_default_shorthands .unwrap_or(settings.disable_default_shorthands); diff --git a/src/shorthand_list.rs b/src/default_shorthands.rs similarity index 99% rename from src/shorthand_list.rs rename to src/default_shorthands.rs index c1c371eb9..986a59617 100644 --- a/src/shorthand_list.rs +++ b/src/default_shorthands.rs @@ -1,9 +1,14 @@ // This file is generated by scripts/update-shorthand-repo.sh // Do not edit this file manually +use once_cell::sync::Lazy; +use std::collections::HashMap; + +pub static DEFAULT_SHORTHANDS: Lazy> = + Lazy::new(|| HashMap::from(DEFAULT_SHORTHAND_LIST)); #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -pub const SHORTHAND_LIST: [(&str, &str); 607] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 607] = [ // rtx custom aliases ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), diff --git a/src/env.rs b/src/env.rs index 00d723467..551a8d915 100644 --- a/src/env.rs +++ b/src/env.rs @@ -118,6 +118,7 @@ lazy_static! { pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); pub static ref RTX_PREFER_STALE: bool = prefer_stale(&ARGS); pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); + pub static ref RTX_SHORTHANDS_FILE: Option = var_path("RTX_SHORTHANDS_FILE"); pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); } @@ -148,6 +149,10 @@ fn var_is_true(key: &str) -> bool { } } +fn var_path(key: &str) -> Option { + var_os(key).map(PathBuf::from) +} + /// this returns the environment as if __RTX_DIFF was reversed. /// putting the shell back into a state before hook-env was run fn get_pristine_env( @@ -209,18 +214,37 @@ fn prefer_stale(args: &[String]) -> bool { false } -#[test] -fn test_apply_patches() { - let mut env = HashMap::new(); - env.insert("foo".into(), "bar".into()); - env.insert("baz".into(), "qux".into()); - let patches = vec![ - EnvDiffOperation::Add("foo".into(), "bar".into()), - EnvDiffOperation::Change("baz".into(), "qux".into()), - EnvDiffOperation::Remove("quux".into()), - ]; - let new_env = apply_patches(&env, &patches); - assert_eq!(new_env.len(), 2); - assert_eq!(new_env.get("foo").unwrap(), "bar"); - assert_eq!(new_env.get("baz").unwrap(), "qux"); +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + + use crate::env::apply_patches; + use crate::env_diff::EnvDiffOperation; + + #[test] + fn test_apply_patches() { + let mut env = HashMap::new(); + env.insert("foo".into(), "bar".into()); + env.insert("baz".into(), "qux".into()); + let patches = vec![ + EnvDiffOperation::Add("foo".into(), "bar".into()), + EnvDiffOperation::Change("baz".into(), "qux".into()), + EnvDiffOperation::Remove("quux".into()), + ]; + let new_env = apply_patches(&env, &patches); + assert_eq!(new_env.len(), 2); + assert_eq!(new_env.get("foo").unwrap(), "bar"); + assert_eq!(new_env.get("baz").unwrap(), "qux"); + } + + #[test] + fn test_var_path() { + set_var("RTX_TEST_PATH", "/foo/bar"); + assert_eq!( + var_path("RTX_TEST_PATH").unwrap(), + PathBuf::from("/foo/bar") + ); + remove_var("RTX_TEST_PATH"); + } } diff --git a/src/main.rs b/src/main.rs index 38ba34fb7..278287717 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ mod cache; mod cli; mod cmd; mod config; +mod default_shorthands; mod dirs; mod env; mod env_diff; @@ -32,12 +33,11 @@ mod logger; mod plugins; pub mod runtimes; mod shell; +mod shorthands; mod ui; mod direnv; mod hash; -mod shorthand; -mod shorthand_list; mod toolset; #[cfg(test)] diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 36ff63268..cf4aa6695 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -18,14 +18,12 @@ pub use script_manager::{InstallType, Script, ScriptManager}; use crate::cache::CacheManager; use crate::cmd::cmd; -use crate::config::Settings; +use crate::config::{Config, Settings}; +use crate::env::RTX_PREFER_STALE; use crate::errors::Error::PluginNotInstalled; use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; -use crate::shorthand::shorthand_to_repository; - -use crate::env::RTX_PREFER_STALE; use crate::ui::progress_report::ProgressReport; use crate::{dirs, file}; @@ -98,8 +96,8 @@ impl Plugin { pub fn install( &self, - settings: &Settings, - repository: Option<&str>, + config: &Config, + repository: Option<&String>, mut pr: ProgressReport, ) -> Result<()> { static PROG_TEMPLATE: Lazy = Lazy::new(|| { @@ -114,7 +112,7 @@ impl Plugin { )); pr.enable_steady_tick(); let repository = repository - .or_else(|| shorthand_to_repository(settings, &self.name)) + .or_else(|| config.get_shorthands().get(&self.name)) .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; debug!("install {} {:?}", self.name, repository); if self.is_installed() { @@ -128,15 +126,15 @@ impl Plugin { pr.set_message("loading plugin remote versions".into()); if self.has_list_all_script() { - self.list_remote_versions(settings)?; + self.list_remote_versions(&config.settings)?; } if self.has_list_alias_script() { pr.set_message("getting plugin aliases".into()); - self.get_aliases(settings)?; + self.get_aliases(&config.settings)?; } if self.has_list_legacy_filenames_script() { pr.set_message("getting plugin legacy filenames".into()); - self.legacy_filenames(settings)?; + self.legacy_filenames(&config.settings)?; } let sha = git.current_sha_short()?; diff --git a/src/shorthand.rs b/src/shorthand.rs deleted file mode 100644 index 43d192114..000000000 --- a/src/shorthand.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::config::Settings; -use crate::shorthand_list::SHORTHAND_LIST; -use once_cell::sync::Lazy; -use std::collections::HashMap; - -pub fn shorthand_to_repository(settings: &Settings, name: &str) -> Option<&'static str> { - if !settings.disable_default_shorthands { - SHORTHAND_MAP.get(name).copied() - } else { - None - } -} - -pub static SHORTHAND_MAP: Lazy> = - Lazy::new(|| HashMap::from(SHORTHAND_LIST)); diff --git a/src/shorthands.rs b/src/shorthands.rs new file mode 100644 index 000000000..826b8f780 --- /dev/null +++ b/src/shorthands.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; + +use color_eyre::eyre::Result; +use toml::Table; + +use crate::config::Settings; +use crate::default_shorthands::DEFAULT_SHORTHANDS; +use crate::dirs; + +pub type Shorthands = HashMap; + +pub fn get_shorthands(settings: &Settings) -> Shorthands { + let mut shorthands = HashMap::new(); + if !settings.disable_default_shorthands { + shorthands.extend( + DEFAULT_SHORTHANDS + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())), + ); + }; + if let Some(f) = &settings.shorthands_file { + match parse_shorthands_file(f.clone()) { + Ok(custom) => { + shorthands.extend(custom); + } + Err(err) => { + warn!("Failed to read shorthands file: {} {}", &f.display(), err); + } + } + } + shorthands +} + +fn parse_shorthands_file(mut f: PathBuf) -> Result { + if f.starts_with("~") { + f = dirs::HOME.join(f.strip_prefix("~")?); + } + let raw = fs::read_to_string(&f)?; + let toml = raw.parse::()?; + + let mut shorthands = HashMap::new(); + for (k, v) in toml { + if let Some(v) = v.as_str() { + shorthands.insert(k, v.to_string()); + } + } + Ok(shorthands) +} + +#[cfg(test)] +mod tests { + use pretty_assertions::assert_str_eq; + + use super::*; + + #[test] + fn test_get_shorthands() { + let settings = Settings { + shorthands_file: Some("test/fixtures/shorthands.toml".into()), + ..Settings::default() + }; + let shorthands = get_shorthands(&settings); + assert_str_eq!( + shorthands["elixir"], + "https://github.com/asdf-vm/asdf-elixir.git" + ); + assert_str_eq!(shorthands["nodejs"], "https://nodejs"); + assert_str_eq!(shorthands["xxxxxx"], "https://xxxxxx"); + } + + #[test] + fn test_get_shorthands_missing_file() { + let settings = Settings { + shorthands_file: Some("test/fixtures/missing.toml".into()), + ..Settings::default() + }; + let shorthands = get_shorthands(&settings); + assert!(!shorthands.is_empty()); + } +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index d8be385aa..78420f2bf 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -172,7 +172,7 @@ impl Toolset { .map(|plugin_name| { let plugin = Plugin::new(&plugin_name); if !plugin.is_installed() { - plugin.install(&config.settings, None, mpr.add())?; + plugin.install(config, None, mpr.add())?; } Ok(plugin) }) diff --git a/test/fixtures/shorthands.toml b/test/fixtures/shorthands.toml new file mode 100644 index 000000000..c8fc91275 --- /dev/null +++ b/test/fixtures/shorthands.toml @@ -0,0 +1,2 @@ +nodejs = "https://nodejs" +xxxxxx = "https://xxxxxx" From 21bdfd2ebf62a8dfc3915bc3f9f1561771a58b3d Mon Sep 17 00:00:00 2001 From: chhe Date: Wed, 22 Feb 2023 21:28:38 +0100 Subject: [PATCH 0248/1891] fix: ignore env varibales from exported bash functions (#180) --- src/env_diff.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/env_diff.rs b/src/env_diff.rs index 34daf4902..4550900e7 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -97,6 +97,14 @@ impl EnvDiff { // it causes ruby to attempt to call asdf to reshim the binaries // which we don't need or want to happen || k == "RUBYLIB" + // following two ignores are for exported bash functions and exported bash + // functions which are multline, they appear in the environment as e.g.: + // BASH_FUNC_exported-bash-function%%=() { echo "this is an" + // echo "exported bash function" + // echo "with multiple lines" + // } + || k.starts_with("BASH_FUNC_") + || k.starts_with(' ') { continue; } From f210437b6cd7824859c6719184e9ece84c7dd949 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:04:41 -0600 Subject: [PATCH 0249/1891] chore: fix pre-release-hook --- README.md | 1 + scripts/pre-release-hook.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4081a3999..8cd298bf3 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ v18.10.9 * [RTX_VERBOSE=1](#rtx_verbose1) * [RTX_ASDF_COMPAT=1](#rtx_asdf_compat1) * [RTX_JOBS=1](#rtx_jobs1) + * [RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml](#rtx_shorthands_fileconfigrtxshorthandstoml) * [RTX_DISABLE_DEFAULT_SHORTHANDS=1](#rtx_disable_default_shorthands1) * [RTX_HIDE_OUTDATED_BUILD=1](#rtx_hide_outdated_build1) * [Aliases](#aliases) diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 74a19e92e..5468b2ac0 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -3,4 +3,4 @@ set -euxo pipefail ./scripts/update-shorthand-repo.sh just lint-fix -git add src/shorthand_list.rs +git add src/default_shorthands.rs From 628e5a89a0c64fc1646be9a42e705d0417ab73c0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:06:55 -0600 Subject: [PATCH 0250/1891] chore: Release rtx-cli version 1.15.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- src/default_shorthands.rs | 3 ++- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a46f33d2..53db8fd95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.14.3" +version = "1.15.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index a20d9a040..629c791ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.14.3" +version = "1.15.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 8cd298bf3..7673eebbc 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.14.3 +rtx 1.15.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -295,7 +295,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.3/rtx-v1.14.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.0/rtx-v1.15.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 0ea6701aa..e04fdc952 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.14.3 +Version: 1.15.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 02b3dc0bb..6bf10c4e5 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -224,7 +224,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.14.3/rtx-v1.14.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.0/rtx-v1.15.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 986a59617..cd2023b88 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 607] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 608] = [ // rtx custom aliases ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), @@ -273,6 +273,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 607] = [ ("hyperfine", "https://github.com/volf52/asdf-hyperfine.git"), ("iam-policy-json-to-terraform", "https://github.com/carlduevel/asdf-iam-policy-json-to-terraform.git"), ("iamlive", "https://github.com/chessmango/asdf-iamlive.git"), + ("ibmcloud", "https://github.com/triangletodd/asdf-ibmcloud.git"), ("idris", "https://github.com/asdf-community/asdf-idris.git"), ("idris2", "https://github.com/asdf-community/asdf-idris2.git"), ("imagemagick", "https://github.com/mangalakader/asdf-imagemagick.git"), From 61076b93a9541aaff560775b71b4a636c05039c1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 19:55:22 -0600 Subject: [PATCH 0251/1891] chore: added shellcheck/shfmt (#184) --- .github/workflows/rtx.yml | 22 +++++++++---------- justfile | 4 ++++ scripts/publish-s3.sh | 26 +++++++++++------------ scripts/release-aur.sh | 2 +- scripts/release-npm.sh | 36 ++++++++++++++++---------------- scripts/release.sh | 4 ++-- scripts/update-shorthand-repo.sh | 12 +++++------ 7 files changed, 55 insertions(+), 51 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index e88ef5afe..d4980aa02 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -2,10 +2,10 @@ name: rtx on: push: - branches: [ "main" ] - tags: [ "v*" ] + branches: ["main"] + tags: ["v*"] pull_request: - branches: [ "main" ] + branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: @@ -22,8 +22,8 @@ jobs: uses: Swatinem/rust-cache@v2 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - name: Install direnv - run: sudo apt-get update; sudo apt-get install direnv + - name: Install direnv/shfmt + run: sudo apt-get update; sudo apt-get install direnv shfmt - name: Install just uses: taiki-e/install-action@just - name: Run just test-unit @@ -135,7 +135,7 @@ jobs: e2e-linux: runs-on: ubuntu-22.04 - needs: [ build-linux ] + needs: [build-linux] steps: - uses: actions/checkout@v3 - name: Install zsh/fish/direnv @@ -158,7 +158,7 @@ jobs: command: ./e2e/run_all_tests rpm: runs-on: ubuntu-22.04 - needs: [ build-linux ] + needs: [build-linux] container: jdxcode/chim:rpm if: github.event_name != 'pull_request' steps: @@ -184,7 +184,7 @@ jobs: runs-on: ubuntu-22.04 container: jdxcode/chim:deb if: github.event_name != 'pull_request' - needs: [ build-linux ] + needs: [build-linux] steps: - uses: actions/checkout@v3 - uses: crazy-max/ghaction-import-gpg@v5 @@ -227,8 +227,8 @@ jobs: token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - uses: actions/setup-node@v3 with: - node-version: '18.x' - registry-url: 'https://registry.npmjs.org' + node-version: "18.x" + registry-url: "https://registry.npmjs.org" - name: Set AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: @@ -267,7 +267,7 @@ jobs: bump-homebrew-formula: runs-on: macos-latest if: startsWith(github.event.ref, 'refs/tags/v') - needs: [ release ] + needs: [release] steps: - name: Checkout repository uses: actions/checkout@v3 diff --git a/justfile b/justfile index 327799452..0c86c29ff 100644 --- a/justfile +++ b/justfile @@ -59,12 +59,16 @@ clean: lint: cargo clippy cargo fmt --all -- --check + shellcheck scripts/*.sh + shfmt -d scripts/*.sh just --unstable --fmt --check # runs linters but makes fixes when possible lint-fix: cargo clippy --fix --allow-staged --allow-dirty cargo fmt --all + shellcheck scripts/*.sh + shfmt -w scripts/*.sh just --unstable --fmt # regenerate README.md diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 382b0b025..b64c46dee 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -6,30 +6,30 @@ cache_day="max-age=86400,s-maxage=86400,public,immutable" cache_week="max-age=604800,s-maxage=604800,public,immutable" ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh -echo "$RTX_VERSION" | tr -d 'v' > "$RELEASE_DIR"/VERSION +echo "$RTX_VERSION" | tr -d 'v' >"$RELEASE_DIR"/VERSION cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-latest-linux-amd64" cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-latest-macos-amd64" aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" \ - --include "rtx-latest-*" \ - --include "SHASUMS*" \ - --include "VERSION" \ - --include "install.sh" + --include "rtx-latest-*" \ + --include "SHASUMS*" \ + --include "VERSION" \ + --include "install.sh" -aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress +aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "repomd.xml*" aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" -aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive +aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_hour" --no-progress --no-progress --recursive aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ - "/VERSION" \ - "/SHASUMS*" \ - "/install.sh" \ - "/rtx-latest-*" \ - "/rpm/repodata/*" \ - "/deb/dists/*" + "/VERSION" \ + "/SHASUMS*" \ + "/install.sh" \ + "/rtx-latest-*" \ + "/rpm/repodata/*" \ + "/deb/dists/*" diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index fd56a49d5..a275fd9fb 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -6,7 +6,7 @@ RTX_VERSION=$(./scripts/get-version.sh) SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') if [ ! -d aur ]; then - git clone ssh://aur@aur.archlinux.org/rtx.git aur + git clone ssh://aur@aur.archlinux.org/rtx.git aur fi git -C aur pull diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index 1f74e3d8b..2908ef512 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -9,9 +9,9 @@ error() { mkdir -p "$RELEASE_DIR/npm" dist_tag_from_version() { - IFS="-" read -r -a version_split <<< "$1" - IFS="." read -r -a version_split <<< "${version_split[1]:-latest}" - echo "${version_split[0]}" + IFS="-" read -r -a version_split <<<"$1" + IFS="." read -r -a version_split <<<"${version_split[1]:-latest}" + echo "${version_split[0]}" } dist_tag="$(dist_tag_from_version "$RTX_VERSION")" @@ -22,21 +22,21 @@ platforms=( macos-arm64 ) for platform in "${platforms[@]}"; do - # shellcheck disable=SC2206 - platform_split=(${platform//-/ }) - os="${platform_split[0]}" - arch="${platform_split[1]}" + # shellcheck disable=SC2206 + platform_split=(${platform//-/ }) + os="${platform_split[0]}" + arch="${platform_split[1]}" - if [[ "$os" == "macos" ]]; then - os="darwin" - fi + if [[ "$os" == "macos" ]]; then + os="darwin" + fi cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" - tar -xzvf "$RELEASE_DIR/rtx-latest-$platform.tar.gz" -C "$RELEASE_DIR" - rm -rf "$RELEASE_DIR/npm" - mv "$RELEASE_DIR/rtx" "$RELEASE_DIR/npm" - cat <"$RELEASE_DIR/npm/package.json" + tar -xzvf "$RELEASE_DIR/rtx-latest-$platform.tar.gz" -C "$RELEASE_DIR" + rm -rf "$RELEASE_DIR/npm" + mv "$RELEASE_DIR/rtx" "$RELEASE_DIR/npm" + cat <"$RELEASE_DIR/npm/package.json" { "name": "@jdxcode/rtx-$os-$arch", "version": "$RTX_VERSION", @@ -57,10 +57,10 @@ for platform in "${platforms[@]}"; do "cpu": "$arch" } EOF - pushd "$RELEASE_DIR/npm" - tree || true - npm publish --access public --tag "$dist_tag" - popd + pushd "$RELEASE_DIR/npm" + tree || true + npm publish --access public --tag "$dist_tag" + popd done cat <"$RELEASE_DIR/npm/installArchSpecificPackage.js" diff --git a/scripts/release.sh b/scripts/release.sh index f7a64cde7..f4c61d0a4 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -34,8 +34,8 @@ for platform in "${platforms[@]}"; do cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" tar -xvzf "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" - cp -v rtx/bin/rtx "$RELEASE_DIR/rtx-latest-$platform" - cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" + cp -v rtx/bin/rtx "$RELEASE_DIR/rtx-latest-$platform" + cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" done pushd "$RELEASE_DIR" diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index fbf0730b2..3bf2f8f8d 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -8,7 +8,7 @@ rm -f src/default_shorthands.rs num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') num_plugins=$((num_plugins + 2)) # +2 for custom aliases (node, tiny, etc) -cat > src/default_shorthands.rs <src/default_shorthands.rs <> src/default_shorthands.rs + plugin=$(basename "$file") + repository=$(cat "$file") + repository="${repository/#repository = /}" + echo " (\"$plugin\", \"$repository\")," >>src/default_shorthands.rs done -cat >> src/default_shorthands.rs <>src/default_shorthands.rs < Date: Wed, 22 Feb 2023 20:18:42 -0600 Subject: [PATCH 0252/1891] feat: added self-update support for brew/deb/rpm (#183) --- .github/workflows/rtx.yml | 11 ++---- Cargo.toml | 5 +++ scripts/build-deb.sh | 4 +-- scripts/build-linux.sh | 10 ++++++ scripts/build-macos.sh | 7 ++++ scripts/build-rpm.sh | 4 +-- scripts/build-tarball.sh | 35 ++++++++++++++----- scripts/release.sh | 5 +++ src/cli/mod.rs | 7 +--- .../{self_update.rs => self_update/github.rs} | 0 src/cli/self_update/mod.rs | 11 ++++++ src/cli/self_update/other.rs | 31 ++++++++++++++++ 12 files changed, 102 insertions(+), 28 deletions(-) create mode 100755 scripts/build-linux.sh create mode 100755 scripts/build-macos.sh rename src/cli/{self_update.rs => self_update/github.rs} (100%) create mode 100644 src/cli/self_update/mod.rs create mode 100644 src/cli/self_update/other.rs diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index d4980aa02..489d18282 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -88,12 +88,7 @@ jobs: with: key: "${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --release --all-features --target ${{matrix.target}} - - run: scripts/build-tarball.sh ${{matrix.target}} + - run: scripts/build-linux.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 with: name: tarball-${{matrix.target}} @@ -123,8 +118,7 @@ jobs: with: key: "${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - - run: cargo build --release --all-features --target ${{matrix.target}} - - run: scripts/build-tarball.sh ${{matrix.target}} + - run: scripts/build-macos.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 with: name: tarball-${{matrix.target}} @@ -132,7 +126,6 @@ jobs: dist/rtx-*.tar.xz dist/rtx-*.tar.gz if-no-files-found: error - e2e-linux: runs-on: ubuntu-22.04 needs: [build-linux] diff --git a/Cargo.toml b/Cargo.toml index 629c791ec..b9f679187 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,11 @@ pretty_assertions = "1.3.0" tempfile = "3.3.0" test-log = "0.2" +[features] +brew = [] +deb = [] +rpm = [] + [profile.release] debug = 0 diff --git a/scripts/build-deb.sh b/scripts/build-deb.sh index 52a156941..55faf9d97 100755 --- a/scripts/build-deb.sh +++ b/scripts/build-deb.sh @@ -3,7 +3,7 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -tar -xvJf "dist/rtx-$RTX_VERSION-linux-x64.tar.xz" +tar -xvJf "dist/rtx-deb-$RTX_VERSION-linux-x64.tar.xz" fpm -s dir -t deb \ --name rtx \ --license MIT \ @@ -14,7 +14,7 @@ fpm -s dir -t deb \ --maintainer "Jeff Dickey @jdxcode" \ rtx/bin/rtx=/usr/bin/rtx -tar -xvJf "dist/rtx-$RTX_VERSION-linux-arm64.tar.xz" +tar -xvJf "dist/rtx-deb-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t deb \ --name rtx \ --license MIT \ diff --git a/scripts/build-linux.sh b/scripts/build-linux.sh new file mode 100755 index 000000000..58230e390 --- /dev/null +++ b/scripts/build-linux.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euxo pipefail + +TARGET="$1" +export CROSS=1 + +scripts/build-tarball.sh rtx --release --features self_update --target "$TARGET" +scripts/build-tarball.sh rtx-brew --release --features brew --target "$TARGET" +scripts/build-tarball.sh rtx-deb --release --features deb --target "$TARGET" +scripts/build-tarball.sh rtx-rpm --release --features rpm --target "$TARGET" diff --git a/scripts/build-macos.sh b/scripts/build-macos.sh new file mode 100755 index 000000000..0cf50a2cc --- /dev/null +++ b/scripts/build-macos.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euxo pipefail + +TARGET="$1" + +scripts/build-tarball.sh rtx --release --features self_update --target "$TARGET" +scripts/build-tarball.sh rtx-brew --release --features brew --target "$TARGET" diff --git a/scripts/build-rpm.sh b/scripts/build-rpm.sh index 791dd3fd1..f07141597 100755 --- a/scripts/build-rpm.sh +++ b/scripts/build-rpm.sh @@ -3,7 +3,7 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -tar -xvJf "dist/rtx-$RTX_VERSION-linux-x64.tar.xz" +tar -xvJf "dist/rtx-rpm-$RTX_VERSION-linux-x64.tar.xz" fpm -s dir -t rpm \ --name rtx \ --license MIT \ @@ -14,7 +14,7 @@ fpm -s dir -t rpm \ --maintainer "Jeff Dickey @jdxcode" \ rtx/bin/rtx=/usr/bin/rtx -tar -xvJf "dist/rtx-$RTX_VERSION-linux-arm64.tar.xz" +tar -xvJf "dist/rtx-rpm-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t rpm \ --name rtx \ --license MIT \ diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index 241c6d29e..353b2f17d 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -1,13 +1,30 @@ #!/usr/bin/env bash -set -euxo pipefail +set -euo pipefail error() { echo "$@" >&2 exit 1 } -RUST_TRIPLE=${1:-$(rustc -vV | grep ^host: | cut -d ' ' -f2)} +NAME="$1" +shift +for arg in "$@"; do + if [ "${next_target:-}" = 1 ]; then + next_target= + TARGET="$arg" + continue + fi + case "$arg" in + --target) + next_target=1 + ;; + *) ;; + + esac +done + +RUST_TRIPLE=${TARGET:-$(rustc -vV | grep ^host: | cut -d ' ' -f2)} #region os/arch get_os() { case "$RUST_TRIPLE" in @@ -38,15 +55,15 @@ get_arch() { } #endregion +set -x VERSION=$(./scripts/get-version.sh) -BASENAME=rtx-$VERSION-$(get_os)-$(get_arch) - -#if [ "${CROSS:-}" = "1" ]; then -# cross build --release --target "$RUST_TRIPLE" -#else -# cargo build --release --target "$RUST_TRIPLE" -#fi +BASENAME=$NAME-$VERSION-$(get_os)-$(get_arch) +if [ "${CROSS:-}" = "1" ]; then + cross build "$@" +else + cargo build "$@" +fi mkdir -p "dist/rtx/bin" cp "target/$RUST_TRIPLE/release/rtx" "dist/rtx/bin/rtx" cp README.md "dist/rtx/README.md" diff --git a/scripts/release.sh b/scripts/release.sh index f4c61d0a4..d3b77ccc4 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -24,6 +24,11 @@ for target in "${targets[@]}"; do cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$RTX_VERSION" done +# these are already packaged into the deb/rpm +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-brew-*.gz" +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-deb-*" +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-rpm-*" + platforms=( linux-x64 linux-arm64 diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 990411625..b9488a3d9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -33,6 +33,7 @@ mod local; mod ls; mod ls_remote; mod plugins; +mod self_update; mod settings; mod uninstall; pub mod version; @@ -42,9 +43,6 @@ mod r#where; #[cfg(debug_assertions)] mod render_help; -#[cfg(feature = "self_update")] -mod self_update; - pub struct Cli { command: clap::Command, external_commands: Vec, @@ -73,7 +71,6 @@ pub enum Commands { Ls(ls::Ls), LsRemote(ls_remote::LsRemote), Plugins(plugins::Plugins), - #[cfg(feature = "self_update")] SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Uninstall(uninstall::Uninstall), @@ -108,7 +105,6 @@ impl Commands { Self::Ls(cmd) => cmd.run(config, out), Self::LsRemote(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), - #[cfg(feature = "self_update")] Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), @@ -212,7 +208,6 @@ static AFTER_HELP: Lazy = Lazy::new(|| { #[cfg(test)] pub mod tests { use crate::config::MissingRuntimeBehavior::AutoInstall; - use crate::dirs; use crate::plugins::{Plugin, PluginName}; use crate::ui::progress_report::ProgressReport; diff --git a/src/cli/self_update.rs b/src/cli/self_update/github.rs similarity index 100% rename from src/cli/self_update.rs rename to src/cli/self_update/github.rs diff --git a/src/cli/self_update/mod.rs b/src/cli/self_update/mod.rs new file mode 100644 index 000000000..104214507 --- /dev/null +++ b/src/cli/self_update/mod.rs @@ -0,0 +1,11 @@ +#[cfg(feature = "self_update")] +pub mod github; + +#[cfg(feature = "self_update")] +pub use github::SelfUpdate; + +#[cfg(not(feature = "self_update"))] +pub mod other; + +#[cfg(not(feature = "self_update"))] +pub use other::SelfUpdate; diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs new file mode 100644 index 000000000..88a0f4154 --- /dev/null +++ b/src/cli/self_update/other.rs @@ -0,0 +1,31 @@ +use color_eyre::eyre::eyre; +use color_eyre::Result; +use console::style; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; +use crate::{cmd, env}; + +/// Updates rtx itself +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct SelfUpdate {} + +impl Command for SelfUpdate { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let cmd = if cfg!(feature = "brew") { + "brew upgrade rtx" + } else if cfg!(feature = "deb") { + "sudo apt update && sudo apt install rtx" + } else if cfg!(feature = "rpm") { + "sudo dnf upgrade rtx" + } else { + return Err(eyre!("Self-update is not supported")); + }; + rtxprintln!(out, "running `{}`", style(&cmd).yellow()); + cmd!(&*env::SHELL, "-c", cmd).run()?; + + Ok(()) + } +} From 8ef3c1c2e8a4c990f7e14f6bd9df288324f6d6f8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 20:38:05 -0600 Subject: [PATCH 0253/1891] chore: remove deprecated actions-rs/toolchain (#185) --- .github/workflows/rtx.yml | 14 +++----------- packaging/homebrew/homebrew.rb | 8 ++++---- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 489d18282..074fc029f 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -78,16 +78,12 @@ jobs: - x86_64-unknown-linux-gnu steps: - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: ${{matrix.target}} - override: true - name: Rust Cache uses: Swatinem/rust-cache@v2 with: key: "${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + - uses: taiki-e/install-action@cross - run: scripts/build-linux.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 with: @@ -107,12 +103,8 @@ jobs: - x86_64-apple-darwin - aarch64-apple-darwin steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: ${{matrix.target}} - override: true + - uses: actions/checkout@v3 + - run: rustup target add ${{matrix.target}} - name: Rust Cache uses: Swatinem/rust-cache@v2 with: diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index ea4fd8a76..ca0b04c7e 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -6,7 +6,7 @@ class Rtx < Formula on_macos do if Hardware::CPU.intel? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-v$RTX_VERSION-macos-x64.tar.xz" + url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-x64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_X86_64" def install @@ -14,7 +14,7 @@ def install end end if Hardware::CPU.arm? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-v$RTX_VERSION-macos-arm64.tar.xz" + url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-arm64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_ARM64" def install @@ -25,7 +25,7 @@ def install on_linux do if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-v$RTX_VERSION-linux-arm64.tar.xz" + url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-arm64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_ARM64" def install @@ -33,7 +33,7 @@ def install end end if Hardware::CPU.intel? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-v$RTX_VERSION-linux-x64.tar.xz" + url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-x64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_X86_64" def install From 182b4edbceea2bc724535cf2cec8cf41c8af9da0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 20:38:39 -0600 Subject: [PATCH 0254/1891] chore: Release rtx-cli version 1.15.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53db8fd95..ed474dc49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.15.0" +version = "1.15.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index b9f679187..3b663d569 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.15.0" +version = "1.15.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 7673eebbc..a5e5faadd 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.15.0 +rtx 1.15.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -295,7 +295,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.0/rtx-v1.15.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.1/rtx-v1.15.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e04fdc952..bc5ad916c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.15.0 +Version: 1.15.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 6bf10c4e5..1bff6d637 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -224,7 +224,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.0/rtx-v1.15.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.1/rtx-v1.15.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From dfbdc71ea941a3f450bec23fdd826eacbe6ab528 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 20:53:45 -0600 Subject: [PATCH 0255/1891] chore: fix homebrew formula shas --- scripts/release.sh | 6 +++--- scripts/render-homebrew.sh | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index d3b77ccc4..a9b39975a 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -25,9 +25,9 @@ for target in "${targets[@]}"; do done # these are already packaged into the deb/rpm -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-brew-*.gz" -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-deb-*" -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-rpm-*" +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-brew-"*.gz +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-deb-"* +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-rpm-"* platforms=( linux-x64 diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index cf2f6a770..abee0b5df 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -3,9 +3,9 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=${RTX_VERSION#v*} \ - RTX_CHECKSUM_LINUX_X86_64=$(grep linux-x64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64=$(grep linux-arm64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_X86_64=$(grep macos-x64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_ARM64=$(grep macos-arm64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_X86_64=$(grep linux-brew-x64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARM64=$(grep linux-brew-arm64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_X86_64=$(grep macos-brew-x64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_ARM64=$(grep macos-brew-arm64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ Date: Wed, 22 Feb 2023 20:54:12 -0600 Subject: [PATCH 0256/1891] chore: Release rtx-cli version 1.15.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed474dc49..f7cc471d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.15.1" +version = "1.15.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 3b663d569..130ea7557 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.15.1" +version = "1.15.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a5e5faadd..73609c254 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.15.1 +rtx 1.15.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -295,7 +295,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.1/rtx-v1.15.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.2/rtx-v1.15.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index bc5ad916c..d31cb9083 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.15.1 +Version: 1.15.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1bff6d637..e80a27af1 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -224,7 +224,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.1/rtx-v1.15.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.2/rtx-v1.15.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 4f113e478246702d5b87df998223e8ed8796b2d1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 21:00:06 -0600 Subject: [PATCH 0257/1891] docs: contributing updates --- CONTRIBUTING.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6e3e5d4a..0144fffc8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,10 +85,14 @@ if actually changing the packaging setup. This is for arm64, but you can change the arch to amd64 if you want. ``` -finch run -ti --rm ubuntuapt update -y && apt install gpg sudo wget curl \ -&& wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null \ -&& echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list \ -&& apt update && apt install -y rtx && rtx -V +finch run -ti --rm ubuntu +apt update -y +apt install gpg sudo wget curl +wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +apt update +apt install -y rtx +rtx -V ``` ### Amazon Linux 2 (yum) From beebb0f41a96bc29acba63466618ca647111a77f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 21:03:16 -0600 Subject: [PATCH 0258/1891] chore: do not rebuild cache on tags --- .github/workflows/rtx.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 074fc029f..2cb1cd509 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -21,7 +21,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Install direnv/shfmt run: sudo apt-get update; sudo apt-get install direnv shfmt - name: Install just @@ -46,7 +46,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cargo-llvm-cov - name: Install zsh/fish/direnv run: sudo apt-get update; sudo apt-get install zsh fish direnv @@ -82,7 +82,7 @@ jobs: uses: Swatinem/rust-cache@v2 with: key: "${{matrix.target}}" - save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cross - run: scripts/build-linux.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 @@ -109,7 +109,7 @@ jobs: uses: Swatinem/rust-cache@v2 with: key: "${{matrix.target}}" - save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - run: scripts/build-macos.sh ${{matrix.target}} - uses: actions/upload-artifact@v3 with: From 7960594af45ff407baa4da3eedad672368dc8222 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 21:11:51 -0600 Subject: [PATCH 0259/1891] chore: fix homebrew formula shas --- scripts/render-homebrew.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index abee0b5df..4c1245854 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -3,9 +3,9 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=${RTX_VERSION#v*} \ - RTX_CHECKSUM_LINUX_X86_64=$(grep linux-brew-x64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64=$(grep linux-brew-arm64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_X86_64=$(grep macos-brew-x64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_ARM64=$(grep macos-brew-arm64.tar.xz "$RELEASE_DIR/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-brew-$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-brew-$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-brew-$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-brew-$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ Date: Wed, 22 Feb 2023 21:12:19 -0600 Subject: [PATCH 0260/1891] chore: Release rtx-cli version 1.15.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7cc471d8..b5d3871db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.15.2" +version = "1.15.3" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 130ea7557..49baeb7fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.15.2" +version = "1.15.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 73609c254..60505dfa6 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.15.2 +rtx 1.15.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -295,7 +295,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.2/rtx-v1.15.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.3/rtx-v1.15.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index d31cb9083..fdef31031 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.15.2 +Version: 1.15.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e80a27af1..bcd57db1c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -224,7 +224,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.2/rtx-v1.15.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.3/rtx-v1.15.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 406ac6725215110b8a9aa1c3b0f0310a58d88c8d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 21:30:32 -0600 Subject: [PATCH 0261/1891] chore: fix homebrew formula shas --- scripts/render-homebrew.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index 4c1245854..c3215cf4f 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -3,9 +3,9 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=${RTX_VERSION#v*} \ - RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-brew-$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-brew-$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-brew-$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-brew-$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-brew-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-brew-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-brew-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-brew-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ Date: Wed, 22 Feb 2023 21:31:01 -0600 Subject: [PATCH 0262/1891] chore: Release rtx-cli version 1.15.4 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5d3871db..0a12e06a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.15.3" +version = "1.15.4" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 49baeb7fa..b83c8e3aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.15.3" +version = "1.15.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 60505dfa6..fb1d13b26 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.15.3 +rtx 1.15.4 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -295,7 +295,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.3/rtx-v1.15.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.4/rtx-v1.15.4-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index fdef31031..4a84576f7 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.15.3 +Version: 1.15.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index bcd57db1c..fb98a32d8 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -224,7 +224,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.3/rtx-v1.15.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.4/rtx-v1.15.4-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From bd1f7a74c9a8660ed585a459be20845f9677a00d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 21:42:05 -0600 Subject: [PATCH 0263/1891] use fancier arrow on `rtx ls` unless TERM=dumb --- src/cli/ls.rs | 9 +++++++-- src/env.rs | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index a6106b1eb..e92b4fcf0 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -11,6 +11,7 @@ use versions::Versioning; use crate::cli::command::Command; use crate::config::Config; +use crate::env::DUMB_TERMINAL; use crate::output::Output; use crate::plugins::PluginName; use crate::runtimes::RuntimeVersion; @@ -46,7 +47,12 @@ impl Command for Ls { out, "{} {} {}", match rtv.is_installed() && source.is_some() { - true => "->", + true => + if *DUMB_TERMINAL { + "->" + } else { + "⏵ " + }, false => " ", }, styled_version(&rtv, !rtv.is_installed(), source.is_some()), @@ -153,7 +159,6 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use crate::assert_cli; #[test] diff --git a/src/env.rs b/src/env.rs index 551a8d915..c83fc4a9a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -97,6 +97,7 @@ lazy_static! { pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); pub static ref RTX_VERBOSE: bool = *RTX_DEBUG || *RTX_TRACE || var_is_true("RTX_VERBOSE"); + pub static ref DUMB_TERMINAL: bool = cfg!(test) || var("TERM").map_or(false, |term| term == "dumb"); pub static ref RTX_JOBS: usize = var("RTX_JOBS") .ok() .and_then(|v| v.parse::().ok()) From 9c09acd8074562469e5d0abe3aa210f91d090f2f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Feb 2023 22:51:28 -0600 Subject: [PATCH 0264/1891] feat: added multiselect to runtime prompt (#186) --- Cargo.lock | 25 +++++++++++++++ Cargo.toml | 1 + src/toolset/mod.rs | 64 ++++++++++++++++++++++++++----------- src/toolset/tool_version.rs | 21 +++++++----- src/ui/mod.rs | 1 - src/ui/prompt.rs | 27 ---------------- 6 files changed, 84 insertions(+), 55 deletions(-) delete mode 100644 src/ui/prompt.rs diff --git a/Cargo.lock b/Cargo.lock index 0a12e06a2..7ddbbfe29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -344,6 +344,18 @@ dependencies = [ "syn", ] +[[package]] +name = "dialoguer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3c796f3b0b408d9fd581611b47fa850821fcb84aa640b83a3c1a5be2d691f2" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + [[package]] name = "diff" version = "0.1.13" @@ -1359,6 +1371,7 @@ dependencies = [ "color-eyre", "console", "ctor", + "dialoguer", "dirs-next", "duct", "env_logger", @@ -1564,6 +1577,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "similar" version = "2.2.1" @@ -2174,3 +2193,9 @@ name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/Cargo.toml b/Cargo.toml index b83c8e3aa..d78304a0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ clap_complete = "4.1.1" color-eyre = "0.6.2" console = "0.15.5" ctor = "0.1.26" +dialoguer = { version = "0.10.3", features = [] } dirs-next = "2.0.0" duct = "0.13.6" filetime = "0.2.19" diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 78420f2bf..8ea2b03fd 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::path::PathBuf; @@ -5,6 +6,8 @@ use std::sync::Arc; use color_eyre::eyre::Result; use console::style; +use dialoguer::theme::ColorfulTheme; +use dialoguer::MultiSelect; use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; @@ -22,7 +25,6 @@ use crate::plugins::{InstallType, Plugin, PluginName}; use crate::runtimes::RuntimeVersion; use crate::toolset::tool_version_list::ToolVersionList; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::prompt; mod builder; mod tool_source; @@ -85,7 +87,7 @@ impl Toolset { }); } pub fn install_missing(&mut self, config: &Config) -> Result<()> { - let versions = self.list_missing_versions_mut(); + let versions = self.list_missing_versions(); if versions.is_empty() { return Ok(()); } @@ -103,14 +105,15 @@ impl Toolset { warn(); } MissingRuntimeBehavior::Prompt => { - if prompt::prompt_for_install(&display_versions) { - self.install_missing_versions(config)?; - } else { + let versions = prompt_for_versions(&versions)?; + if versions.is_empty() { warn(); + } else { + self.install_missing_versions(config, versions)?; } } MissingRuntimeBehavior::AutoInstall => { - self.install_missing_versions(config)?; + self.install_missing_versions(config, versions)?; } } Ok(()) @@ -124,14 +127,27 @@ impl Toolset { .collect() } - fn install_missing_versions(&mut self, config: &Config) -> Result<()> { + fn install_missing_versions( + &mut self, + config: &Config, + selected_versions: Vec, + ) -> Result<()> { ThreadPoolBuilder::new() .num_threads(config.settings.jobs) .build() .unwrap() .install(|| -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); - self.install_missing_plugins(config, &mpr)?; + let plugins = selected_versions + .iter() + .map(|v| v.plugin_name.clone()) + .unique() + .collect_vec(); + let selected_versions = selected_versions + .into_iter() + .map(|v| v.r#type) + .collect::>(); + self.install_missing_plugins(config, &mpr, plugins)?; self.versions .iter_mut() .par_bridge() @@ -139,7 +155,7 @@ impl Toolset { let versions = v .versions .iter_mut() - .filter(|v| v.is_missing()) + .filter(|v| v.is_missing() && selected_versions.contains(&v.r#type)) .collect_vec(); let plugin = self.plugins.get(&p.to_string()).unwrap(); match versions.is_empty() { @@ -162,8 +178,8 @@ impl Toolset { &mut self, config: &Config, mpr: &MultiProgressReport, + missing_plugins: Vec, ) -> Result<()> { - let missing_plugins = self.list_missing_plugins(); if missing_plugins.is_empty() { return Ok(()); } @@ -184,16 +200,12 @@ impl Toolset { Ok(()) } - fn list_missing_versions_mut(&mut self) -> Vec<&mut ToolVersion> { + fn list_missing_versions(&self) -> Vec { let versions = self .versions - .values_mut() - .flat_map(|v| { - v.versions - .iter_mut() - .filter(|v| v.is_missing()) - .collect_vec() - }) + .values() + .flat_map(|v| v.versions.iter().filter(|v| v.is_missing()).collect_vec()) + .cloned() .collect_vec(); versions } @@ -358,10 +370,24 @@ impl Display for Toolset { } } -fn display_versions(versions: &[&mut ToolVersion]) -> String { +fn display_versions(versions: &[ToolVersion]) -> String { let display_versions = versions .iter() .map(|v| style(&v.to_string()).cyan().for_stderr().to_string()) .join(", "); display_versions } + +fn prompt_for_versions(versions: &[ToolVersion]) -> Result> { + if !console::user_attended_stderr() { + return Ok(vec![]); + } + Ok(MultiSelect::with_theme(&ColorfulTheme::default()) + .with_prompt("Select versions to install") + .items(versions) + .defaults(&versions.iter().map(|_| true).collect_vec()) + .interact()? + .into_iter() + .map(|i| versions[i].clone()) + .collect()) +} diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index f5036b94a..3228411d3 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -18,7 +18,7 @@ pub struct ToolVersion { pub rtv: Option, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ToolVersionType { Version(String), Prefix(String), @@ -133,13 +133,18 @@ impl ToolVersion { impl Display for ToolVersion { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - let plugin = &self.plugin_name; - match &self.r#type { - ToolVersionType::Version(v) => write!(f, "{plugin}@{v}"), - ToolVersionType::Prefix(p) => write!(f, "{plugin}@prefix:{p}"), - ToolVersionType::Ref(r) => write!(f, "{plugin}@ref:{r}"), - ToolVersionType::Path(p) => write!(f, "{plugin}@path:{p}"), - ToolVersionType::System => write!(f, "{plugin}@system"), + write!(f, "{}@{}", &self.plugin_name, &self.r#type) + } +} + +impl Display for ToolVersionType { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + match self { + ToolVersionType::Version(v) => write!(f, "{v}"), + ToolVersionType::Prefix(p) => write!(f, "prefix:{p}"), + ToolVersionType::Ref(r) => write!(f, "ref:{r}"), + ToolVersionType::Path(p) => write!(f, "path:{p}"), + ToolVersionType::System => write!(f, "system"), } } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 60fe8b916..66bd7c324 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,3 +1,2 @@ pub mod multi_progress_report; pub mod progress_report; -pub mod prompt; diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs deleted file mode 100644 index 9fce9282b..000000000 --- a/src/ui/prompt.rs +++ /dev/null @@ -1,27 +0,0 @@ -use console::style; -use std::io::stdin; - -pub fn prompt() -> String { - let mut input = String::new(); - stdin().read_line(&mut input).expect("error reading stdin"); - - input.trim().to_string() -} - -pub fn prompt_for_install(thing: &str) -> bool { - match console::user_attended_stderr() { - true => { - let stderr = console::Term::stderr(); - eprint!( - "{} Would you like to install {}? [Y/n] ", - style("rtx").dim().for_stderr(), - thing, - ); - let yn = matches!(prompt().to_lowercase().as_str(), "" | "y" | "yes"); - let _ = stderr.move_cursor_up(1); - let _ = stderr.clear_to_end_of_screen(); - yn - } - false => false, - } -} From ad242083eb2e2e5f05eaf7ec6865b7bd7f7aacc5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 23 Feb 2023 00:27:37 -0600 Subject: [PATCH 0265/1891] test: use tiny/dummy for tests (#187) --- e2e/ruby/.e2e-tool-versions | 1 + {test/fixtures => e2e/ruby}/Gemfile | 0 e2e/ruby/test_ruby | 17 +++++++++++ src/cli/activate.rs | 9 ++---- src/cli/alias/set.rs | 7 ++--- ...tx__cli__alias__set__tests__alias_set.snap | 2 +- ...__alias__unset__tests__settings_unset.snap | 7 +++++ src/cli/alias/unset.rs | 10 ++----- src/cli/asdf.rs | 8 ++--- src/cli/bin_paths.rs | 7 ++--- src/cli/current.rs | 19 +++--------- src/cli/direnv/exec.rs | 2 +- ...i__direnv__envrc__tests__direnv_envrc.snap | 8 ++--- src/cli/env.rs | 4 +-- src/cli/global.rs | 8 ++--- src/cli/install.rs | 10 +++---- src/cli/latest.rs | 20 ++++--------- src/cli/local.rs | 19 ++++++------ src/cli/ls.rs | 30 +++++++++++-------- src/cli/ls_remote.rs | 1 - src/cli/mod.rs | 2 +- src/cli/plugins/install.rs | 12 ++++++-- src/cli/plugins/ls.rs | 8 ++--- src/cli/plugins/ls_remote.rs | 2 +- ...ll__tests__plugin_install_invalid_url.snap | 2 +- ..._plugins__ls__tests__plugin_list_urls.snap | 7 +++++ src/cli/plugins/uninstall.rs | 10 ++----- src/cli/plugins/update.rs | 2 +- ...x__cli__activate__tests__activate_zsh.snap | 2 +- ..._activate__tests__activate_zsh_legacy.snap | 2 +- ...rtx__cli__asdf__tests__fake_asdf_list.snap | 6 ++++ ...rtx__cli__bin_paths__tests__bin_paths.snap | 6 ++++ .../rtx__cli__current__tests__current.snap | 6 ++++ ..._cli__current__tests__current_missing.snap | 7 +++++ ...current__tests__current_with_runtimes.snap | 6 ++++ .../rtx__cli__global__tests__global-2.snap | 2 +- .../rtx__cli__global__tests__global-3.snap | 2 +- .../rtx__cli__global__tests__global-4.snap | 3 +- .../rtx__cli__global__tests__global.snap | 2 +- ...i__install__tests__install_with_alias.snap | 6 ++++ .../rtx__cli__latest__tests__latest.snap | 4 +-- ...li__latest__tests__latest_asdf_format.snap | 4 +-- ...tx__cli__latest__tests__latest_system.snap | 4 +-- ...cal__tests__local_multiple_versions-2.snap | 3 -- ...local__tests__local_multiple_versions.snap | 7 +---- ...tx__cli__local__tests__local_remove-2.snap | 7 +---- ...tx__cli__local__tests__local_remove-3.snap | 6 +--- .../rtx__cli__local__tests__local_remove.snap | 7 +---- .../snapshots/rtx__cli__ls__tests__ls-2.snap | 7 +++++ .../snapshots/rtx__cli__ls__tests__ls-3.snap | 7 +++++ .../snapshots/rtx__cli__ls__tests__ls-4.snap | 6 ++++ .../snapshots/rtx__cli__ls__tests__ls-5.snap | 6 ++++ .../snapshots/rtx__cli__ls__tests__ls.snap | 6 ++++ src/cli/where.rs | 2 +- src/config/config_file/tool_versions.rs | 2 +- src/plugins/mod.rs | 24 ++++----------- src/test.rs | 13 ++++---- src/toolset/tool_version.rs | 22 ++++++++++++++ test/.test-tool-versions | 4 +-- test/cwd/.node-version | 1 - test/cwd/.test-tool-versions | 6 +--- 61 files changed, 232 insertions(+), 200 deletions(-) create mode 100644 e2e/ruby/.e2e-tool-versions rename {test/fixtures => e2e/ruby}/Gemfile (100%) create mode 100755 e2e/ruby/test_ruby create mode 100644 src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap create mode 100644 src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap create mode 100644 src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap create mode 100644 src/cli/snapshots/rtx__cli__current__tests__current.snap create mode 100644 src/cli/snapshots/rtx__cli__current__tests__current_missing.snap create mode 100644 src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap create mode 100644 src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls.snap delete mode 100644 test/cwd/.node-version diff --git a/e2e/ruby/.e2e-tool-versions b/e2e/ruby/.e2e-tool-versions new file mode 100644 index 000000000..58b446162 --- /dev/null +++ b/e2e/ruby/.e2e-tool-versions @@ -0,0 +1 @@ +golang 1.19.5 diff --git a/test/fixtures/Gemfile b/e2e/ruby/Gemfile similarity index 100% rename from test/fixtures/Gemfile rename to e2e/ruby/Gemfile diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby new file mode 100755 index 000000000..70c12462f --- /dev/null +++ b/e2e/ruby/test_ruby @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e + +assert() { + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi +} + +export RTX_MISSING_RUNTIME_BEHAVIOR=ignore +assert "rtx plugin install ruby" +assert "rtx current ruby" "3.0.5" diff --git a/src/cli/activate.rs b/src/cli/activate.rs index c1447cc71..921dcd000 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -63,19 +63,16 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use insta::assert_display_snapshot; - use crate::assert_cli; + use crate::assert_cli_snapshot; #[test] fn test_activate_zsh() { - let stdout = assert_cli!("activate", "zsh"); - assert_display_snapshot!(stdout); + assert_cli_snapshot!("activate", "zsh"); } #[test] fn test_activate_zsh_legacy() { - let stdout = assert_cli!("activate", "-s", "zsh"); - assert_display_snapshot!(stdout); + assert_cli_snapshot!("activate", "-s", "zsh"); } } diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 8dee0ad93..442ae7c80 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -40,9 +40,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] pub mod tests { - use insta::assert_snapshot; - use crate::assert_cli; + use crate::{assert_cli, assert_cli_snapshot}; use crate::test::reset_config; @@ -51,9 +50,7 @@ pub mod tests { reset_config(); assert_cli!("alias", "set", "tiny", "my/alias", "3.0"); - let stdout = assert_cli!("aliases"); - println!("stdout {}", stdout); - assert_snapshot!(stdout); + assert_cli_snapshot!("aliases"); reset_config(); } } diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index c8ef2dca4..7d92b9591 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -1,6 +1,6 @@ --- source: src/cli/alias/set.rs -expression: stdout +expression: output --- tiny lts 3.1.0 tiny lts-prev 2.0.0 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap new file mode 100644 index 000000000..a1012e5fe --- /dev/null +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/alias/unset.rs +expression: output +--- +tiny lts 3.1.0 +tiny lts-prev 2.0.0 + diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index b93e979b0..ded47dac6 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -37,9 +37,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use insta::assert_snapshot; - use crate::assert_cli; + use crate::{assert_cli, assert_cli_snapshot}; use crate::test::reset_config; @@ -48,12 +47,7 @@ mod tests { reset_config(); assert_cli!("alias", "unset", "tiny", "my/alias"); - - let stdout = assert_cli!("aliases"); - assert_snapshot!(stdout, @r###" - tiny lts 3.1.0 - tiny lts-prev 2.0.0 - "###); + assert_cli_snapshot!("aliases"); reset_config(); } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 16610f350..9ec9f11a2 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -64,8 +64,8 @@ fn list_versions(config: &Config, out: &mut Output, args: &Vec) -> Resul mod tests { use pretty_assertions::assert_str_eq; - use crate::assert_cli; use crate::cli::version::VERSION; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_fake_asdf() { @@ -75,9 +75,7 @@ mod tests { #[test] fn test_fake_asdf_list() { - assert_cli!("plugin", "install", "shfmt"); - assert_cli!("install", "shfmt@2"); - let stdout = assert_cli!("asdf", "list", "shfmt"); - assert!(stdout.contains('2')); + assert_cli!("asdf", "install", "tiny"); + assert_cli_snapshot!("asdf", "list", "tiny"); } } diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 1fdb3305f..3c3c95eea 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -22,14 +22,11 @@ impl Command for BinPaths { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::assert_cli; - use crate::cli::tests::grep; + use crate::assert_cli_snapshot; #[test] fn test_bin_paths() { - let stdout = assert_cli!("bin-paths"); - assert_str_eq!(grep(stdout, "tiny"), "~/data/installs/tiny/2.1.0/bin"); + assert_cli_snapshot!("bin-paths"); } } diff --git a/src/cli/current.rs b/src/cli/current.rs index 3451d36bf..dcf25df44 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -116,26 +116,16 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use std::env; - use insta::assert_snapshot; - use pretty_assertions::assert_str_eq; - - use crate::assert_cli; - use crate::cli::tests::grep; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_current() { - assert_cli!("install"); - let stdout = assert_cli!("current"); - assert_snapshot!(grep(stdout, "shfmt"), @"shfmt 3.5.1"); + assert_cli_snapshot!("current"); } #[test] fn test_current_with_runtimes() { - assert_cli!("install"); - let stdout = assert_cli!("current", "shfmt"); - assert_snapshot!(stdout, @r###" - 3.5.1 - "###); + assert_cli_snapshot!("current", "tiny"); } #[test] @@ -143,8 +133,7 @@ mod tests { assert_cli!("uninstall", "dummy@1.0.1"); env::set_var("RTX_DUMMY_VERSION", "1.1.0"); - let stdout = assert_cli!("current"); - assert_str_eq!(grep(stdout, "dummy"), "dummy 1.1.0"); + assert_cli_snapshot!("current"); env::remove_var("RTX_DUMMY_VERSION"); } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index e09224a07..6992d9d73 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -55,6 +55,6 @@ mod tests { #[test] fn test_direnv_exec() { let stdout = assert_cli!("direnv", "exec"); - assert_str_eq!(grep(stdout, "JDXCODE_TINY="), "JDXCODE_TINY=2.1.0"); + assert_str_eq!(grep(stdout, "JDXCODE_TINY="), "JDXCODE_TINY=3.1.0"); } } diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index 180fc2b7f..18dc2d096 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -4,11 +4,7 @@ expression: envrc --- ### Do not edit. This was autogenerated by 'asdf direnv envrc' ### watch_file ~/cwd/.test-tool-versions -watch_file ~/cwd/.node-version watch_file ~/.test-tool-versions -export JDXCODE_TINY=2.1.0 -PATH_add ~/data/installs/tiny/2.1.0/bin -PATH_add ~/data/installs/jq/1.6/bin -PATH_add ~/data/installs/shfmt/3.5.1/bin -PATH_add ~/data/installs/shellcheck/0.9.0/bin +export JDXCODE_TINY=3.1.0 +PATH_add ~/data/installs/tiny/3.1.0/bin diff --git a/src/cli/env.rs b/src/cli/env.rs index 31ec60328..afe7cd3a3 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -71,12 +71,10 @@ mod tests { #[test] fn test_env() { - assert_cli!("plugin", "add", "shfmt"); - assert_cli!("install"); let stdout = assert_cli!("env", "-s", "bash"); assert!(stdout.contains( dirs::ROOT - .join("installs/shfmt/3.5.1/bin") + .join("installs/tiny/3.1.0/bin") .to_string_lossy() .as_ref() )); diff --git a/src/cli/global.rs b/src/cli/global.rs index e7a1a1149..057403c54 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -109,12 +109,12 @@ mod tests { let orig = fs::read_to_string(&cf_path).ok(); let _ = fs::remove_file(&cf_path); - assert_cli!("install", "shfmt@2"); - let stdout = assert_cli!("global", "--pin", "shfmt@2"); + assert_cli!("install", "tiny@2"); + let stdout = assert_cli!("global", "--pin", "tiny@2"); assert_snapshot!(stdout); - let stdout = assert_cli!("global", "shfmt@2"); + let stdout = assert_cli!("global", "tiny@2"); assert_snapshot!(stdout); - let stdout = assert_cli!("global", "--remove", "nodejs"); + let stdout = assert_cli!("global", "--remove", "tiny"); assert_snapshot!(stdout); let stdout = assert_cli!("global", "--pin", "tiny", "2"); assert_snapshot!(stdout); diff --git a/src/cli/install.rs b/src/cli/install.rs index 447626fd0..9d5d6e9dc 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -126,22 +126,22 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use pretty_assertions::assert_str_eq; - use crate::{assert_cli, dirs}; + use crate::{assert_cli, assert_cli_snapshot, dirs}; #[test] fn test_install_force() { - assert_cli!("install", "-f", "shfmt"); + assert_cli!("install", "-f", "tiny"); } #[test] fn test_install_asdf_style() { - assert_cli!("install", "shfmt", "2"); + assert_cli!("install", "tiny", "2"); } #[test] fn test_install_with_alias() { - assert_cli!("install", "-f", "shfmt@my/alias"); - assert_cli!("where", "shfmt@my/alias"); + assert_cli!("install", "-f", "tiny@my/alias"); + assert_cli_snapshot!("where", "tiny@my/alias"); } #[test] diff --git a/src/cli/latest.rs b/src/cli/latest.rs index a299598fb..671b9b735 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -69,32 +69,22 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use insta::assert_display_snapshot; - use crate::{assert_cli, assert_cli_err}; + use crate::{assert_cli_err, assert_cli_snapshot}; #[test] fn test_latest() { - assert_cli!("plugins", "install", "nodejs"); - let stdout = assert_cli!("latest", "nodejs@12"); - assert_display_snapshot!(stdout); - } - - #[test] - fn test_latest_ruby() { - assert_cli!("plugins", "install", "ruby"); - let stdout = assert_cli!("latest", "ruby"); - assert!(stdout.starts_with("3.")); + assert_cli_snapshot!("latest", "dummy@1"); } #[test] fn test_latest_asdf_format() { - let stdout = assert_cli!("latest", "nodejs", "12"); - assert_display_snapshot!(stdout); + assert_cli_snapshot!("latest", "dummy", "1"); } #[test] fn test_latest_system() { - let stdout = assert_cli_err!("latest", "nodejs@system"); - assert_display_snapshot!(stdout); + let err = assert_cli_err!("latest", "dummy@system"); + assert_display_snapshot!(err); } #[test] diff --git a/src/cli/local.rs b/src/cli/local.rs index a088e8686..5a0b93068 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -122,7 +122,6 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use std::{fs, panic}; - use insta::assert_snapshot; use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; @@ -146,30 +145,30 @@ mod tests { fn test_local_pin() { run_test(|| { let stdout = assert_cli!("local", "--pin", "tiny@1"); - assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); let stdout = assert_cli!("local", "--pin", "tiny", "2"); - assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); + assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); }); } #[test] fn test_local_path() { run_test(|| { let stdout = assert_cli!("local", "dummy@path:."); - assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); + assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); }); } #[test] fn test_local_ref() { run_test(|| { let stdout = assert_cli!("local", "dummy@ref:master"); - assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); + assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); }); } #[test] fn test_local_prefix() { run_test(|| { let stdout = assert_cli!("local", "dummy@prefix:1"); - assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); + assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); }); } #[test] @@ -206,7 +205,7 @@ mod tests { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "ref:master"); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); } @@ -218,7 +217,7 @@ mod tests { let path_arg = String::from("path:") + &local_dummy_path.to_string_lossy(); assert_cli!("alias", "set", "dummy", "m", &path_arg); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); let stdout = assert_cli!("current", "dummy"); assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); }); @@ -228,7 +227,7 @@ mod tests { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "prefix:1"); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); } @@ -237,7 +236,7 @@ mod tests { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "system"); let stdout = assert_cli!("local", "dummy@m"); - assert_str_eq!(grep(stdout, "dummy"), "dummy m"); + assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index e92b4fcf0..e059ac8ee 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -159,21 +159,25 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use crate::assert_cli; + use crate::{assert_cli, assert_cli_snapshot, dirs}; + use std::fs; #[test] - fn test_list() { + fn test_ls() { + let _ = fs::remove_dir_all(dirs::INSTALLS.as_path()); assert_cli!("install"); - assert_cli!("install", "shfmt@3.5.0"); - let stdout = assert_cli!("list"); - let re = regex!(r"-> shellcheck\s+0\.9\.0\s+"); - assert!(re.is_match(&stdout)); - let re = regex!(r" {3}shfmt\s+3\.5\.0\s+"); - assert!(re.is_match(&stdout)); - - assert_cli!("uninstall", "shfmt@3.5.1"); - let stdout = assert_cli!("list"); - let re = regex!(r" {3}shfmt\s+3\.5\.1 \(missing\)\s+"); - assert!(re.is_match(&stdout)); + assert_cli_snapshot!("list"); + + assert_cli!("install", "tiny@2.0.0"); + assert_cli_snapshot!("list"); + + assert_cli!("uninstall", "tiny@3.1.0"); + assert_cli_snapshot!("list"); + + assert_cli!("uninstall", "tiny@2.0.0"); + assert_cli_snapshot!("list"); + + assert_cli!("install"); + assert_cli_snapshot!("list"); } } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 1094665ca..851c78d01 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -75,7 +75,6 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use insta::assert_snapshot; use crate::assert_cli_snapshot; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b9488a3d9..c5a6fe575 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -238,7 +238,7 @@ pub mod tests { let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; let output = console::strip_ansi_codes(&output).to_string(); let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); - assert_snapshot!(output); + insta::assert_snapshot!(output); }}; } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 7827f9cd6..353d7e2be 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -115,6 +115,7 @@ fn get_name_from_url(url: &str) -> Result { let last = segments.last().unwrap_or_default(); 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()); } } @@ -147,14 +148,19 @@ mod tests { #[test] fn test_plugin_install_url() { - assert_cli!("plugin", "add", "-f", "https://github.com/jdxcode/rtx-tiny"); + assert_cli!( + "plugin", + "add", + "-f", + "https://github.com/jdxcode/rtx-tiny.git" + ); let stdout = assert_cli!("plugin", "--urls"); - assert_snapshot!(grep(stdout, "tiny"), @"tiny https://github.com/jdxcode/rtx-tiny"); + assert_snapshot!(grep(stdout, "tiny"), @"tiny https://github.com/jdxcode/rtx-tiny.git"); } #[test] fn test_plugin_install_invalid_url() { - let args = ["rtx", "plugin", "add", "ruby:"].map(String::from).into(); + let args = ["rtx", "plugin", "add", "tiny:"].map(String::from).into(); let err = cli_run(&args).unwrap_err(); assert_display_snapshot!(err); } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 7166916ee..ad04839b0 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -63,8 +63,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use pretty_assertions::assert_str_eq; - use crate::assert_cli; use crate::cli::tests::grep; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_plugin_list() { @@ -74,11 +74,7 @@ mod tests { #[test] fn test_plugin_list_urls() { - let stdout = assert_cli!("plugin", "list", "--urls"); - assert_str_eq!( - grep(stdout, "tiny"), - "tiny https://github.com/jdxcode/rtx-tiny" - ); + assert_cli_snapshot!("plugin", "list", "--urls"); } #[test] diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 3ecd9be6a..a5abda5e7 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -72,6 +72,6 @@ mod tests { #[test] fn test_plugin_list_remote() { let stdout = assert_cli!("plugin", "ls-remote"); - assert!(stdout.contains("nodejs")); + assert!(stdout.contains("tiny")); } } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap index 55ae85453..29a867ab5 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap @@ -2,4 +2,4 @@ source: src/cli/plugins/install.rs expression: err --- -could not infer plugin name from url: ruby: +could not infer plugin name from url: tiny: diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap new file mode 100644 index 000000000..b19b1ea77 --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/plugins/ls.rs +expression: output +--- +dummy https://github.com/jdxcode/rtx +tiny https://github.com/jdxcode/rtx-tiny.git + diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index aff6c7bfe..258206313 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -44,25 +44,19 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use insta::assert_snapshot; use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_plugin_uninstall() { - assert_cli!( - "plugin", - "add", - "tiny", - "https://github.com/jdxcode/rtx-tiny" - ); + assert_cli!("plugin", "add", "tiny"); assert_cli_snapshot!("plugin", "rm", "tiny"); assert_cli_snapshot!("plugin", "rm", "tiny"); assert_cli!( "plugin", "add", "tiny", - "https://github.com/jdxcode/rtx-tiny" + "https://github.com/jdxcode/rtx-tiny.git" ); } } diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 96c9ebc35..8244875da 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -68,7 +68,7 @@ mod tests { "plugin", "install", "tiny", - "https://github.com/jdxcode/rtx-tiny" + "https://github.com/jdxcode/rtx-tiny.git" ); let err = assert_cli_err!("p", "update"); assert_str_eq!(err.to_string(), "no plugins specified"); diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap index 4aa4945ae..efc8cd1d2 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap @@ -1,6 +1,6 @@ --- source: src/cli/activate.rs -expression: stdout +expression: output --- export PATH=":$PATH" _rtx_hook() { diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap index 4aa4945ae..efc8cd1d2 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap @@ -1,6 +1,6 @@ --- source: src/cli/activate.rs -expression: stdout +expression: output --- export PATH=":$PATH" _rtx_hook() { diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap new file mode 100644 index 000000000..3985be099 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/asdf.rs +expression: output +--- +3.1.0 + diff --git a/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap b/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap new file mode 100644 index 000000000..f30ed5926 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/bin_paths.rs +expression: output +--- +~/data/installs/tiny/3.1.0/bin + diff --git a/src/cli/snapshots/rtx__cli__current__tests__current.snap b/src/cli/snapshots/rtx__cli__current__tests__current.snap new file mode 100644 index 000000000..b70b22a4c --- /dev/null +++ b/src/cli/snapshots/rtx__cli__current__tests__current.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/current.rs +expression: output +--- +tiny 3.1.0 + diff --git a/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap b/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap new file mode 100644 index 000000000..80d44c39f --- /dev/null +++ b/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/current.rs +expression: output +--- +dummy 1.1.0 +tiny 3.1.0 + diff --git a/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap b/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap new file mode 100644 index 000000000..af8af8fe4 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/current.rs +expression: output +--- +3.1.0 + diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap index 6652aca02..be36578d5 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap @@ -2,5 +2,5 @@ source: src/cli/global.rs expression: stdout --- -shfmt 2 +tiny 2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap index 6652aca02..94891b1fd 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap @@ -2,5 +2,5 @@ source: src/cli/global.rs expression: stdout --- -shfmt 2 + diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap index 7a3cdb8cb..41595052f 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap @@ -2,6 +2,5 @@ source: src/cli/global.rs expression: stdout --- -shfmt 2 -tiny 2.1.0 +tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global.snap b/src/cli/snapshots/rtx__cli__global__tests__global.snap index cb4c9fc65..41595052f 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global.snap @@ -2,5 +2,5 @@ source: src/cli/global.rs expression: stdout --- -shfmt 2.6.4 +tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap b/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap new file mode 100644 index 000000000..86a2ad859 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/install.rs +expression: output +--- +~/data/installs/tiny/3.0.1 + diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest.snap index 0144922f6..b1916b4dd 100644 --- a/src/cli/snapshots/rtx__cli__latest__tests__latest.snap +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest.snap @@ -1,6 +1,6 @@ --- source: src/cli/latest.rs -expression: stdout +expression: output --- -12.22.12 +1.1.0 diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap index 0144922f6..b1916b4dd 100644 --- a/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap @@ -1,6 +1,6 @@ --- source: src/cli/latest.rs -expression: stdout +expression: output --- -12.22.12 +1.1.0 diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap index abc02be47..8edb27ad0 100644 --- a/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap @@ -1,5 +1,5 @@ --- source: src/cli/latest.rs -expression: stdout +expression: err --- -invalid version: nodejs@system +invalid version: dummy@system diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap index fd548215c..bb1b9fe63 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap @@ -2,10 +2,7 @@ source: src/cli/local.rs expression: output --- -~/data/installs/shellcheck/0.9.0/bin -~/data/installs/shfmt/3.5.1/bin ~/data/installs/tiny/2.1.0/bin ~/data/installs/tiny/1.0.1/bin ~/data/installs/tiny/3.1.0/bin -~/data/installs/jq/1.6/bin diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap index b28497c7b..6465eb1b6 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap @@ -2,10 +2,5 @@ source: src/cli/local.rs expression: output --- -#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 -shfmt 3.5.1 # test comment -#nodejs 18.13.0 -nodejs system -tiny 2 1 3 +tiny 2 1 3 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap index 2353b11ac..c52103aa5 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap @@ -2,10 +2,5 @@ source: src/cli/local.rs expression: output --- -#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 -shfmt 3.5.1 # test comment -#nodejs 18.13.0 -nodejs system -tiny 2 +tiny 2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap index cfb4547c2..4057a4d40 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap @@ -2,9 +2,5 @@ source: src/cli/local.rs expression: output --- -#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 -shfmt 3.5.1 # test comment -#nodejs 18.13.0 -nodejs system + diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap index 5e220952e..501a2b02a 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap @@ -2,10 +2,5 @@ source: src/cli/local.rs expression: output --- -#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 -shfmt 3.5.1 # test comment -#nodejs 18.13.0 -nodejs system -tiny 2.1.0 +tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap new file mode 100644 index 000000000..ec55ccb5a --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/ls.rs +expression: output +--- + tiny 2.0.0 +-> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap new file mode 100644 index 000000000..d8b37b9de --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/ls.rs +expression: output +--- + tiny 2.0.0 + tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap new file mode 100644 index 000000000..fc0661b53 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/ls.rs +expression: output +--- + tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap new file mode 100644 index 000000000..4889a9c4c --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/ls.rs +expression: output +--- +-> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap new file mode 100644 index 000000000..4889a9c4c --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/ls.rs +expression: output +--- +-> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) + diff --git a/src/cli/where.rs b/src/cli/where.rs index 29dc70d3d..7ed1613e8 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -77,7 +77,7 @@ mod tests { let stdout = assert_cli!("where", "tiny"); assert_str_eq!( stdout.trim(), - dirs::ROOT.join("installs/tiny/2.1.0").to_string_lossy() + dirs::ROOT.join("installs/tiny/3.1.0").to_string_lossy() ); } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index ff949cf28..334441d32 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -216,7 +216,7 @@ pub(crate) mod tests { let tv = ToolVersions::from_file(dirs::CURRENT.join(".test-tool-versions").as_path()).unwrap(); assert_eq!(tv.path, dirs::CURRENT.join(".test-tool-versions")); - assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.test-tool-versions): shellcheck@0.9.0, shfmt@3.5.1, nodejs@system"); + assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.test-tool-versions): tiny@3"); } #[test] diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index cf4aa6695..4dd62747c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -424,30 +424,16 @@ impl PartialEq for Plugin { mod tests { use pretty_assertions::assert_str_eq; - use crate::{assert_cli, env}; + use crate::assert_cli; use super::*; - #[test] - fn test_legacy_gemfile() { - assert_cli!("plugin", "add", "ruby"); - let settings = Settings::default(); - let plugin = Plugin::new(&PluginName::from("ruby")); - let gemfile = env::HOME.join("fixtures/Gemfile"); - let version = plugin.parse_legacy_file(&gemfile, &settings).unwrap(); - assert_str_eq!(version, "3.0.5"); - - // do it again to test the cache - let version = plugin.parse_legacy_file(&gemfile, &settings).unwrap(); - assert_str_eq!(version, "3.0.5"); - } - #[test] fn test_exact_match() { - assert_cli!("plugin", "add", "python"); + assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); - let plugin = Plugin::new(&PluginName::from("python")); - let version = plugin.latest_version(&settings, "3.9.1").unwrap().unwrap(); - assert_str_eq!(version, "3.9.1"); + let plugin = Plugin::new(&PluginName::from("tiny")); + let version = plugin.latest_version(&settings, "1.0.0").unwrap().unwrap(); + assert_str_eq!(version, "1.0.0"); } } diff --git a/src/test.rs b/src/test.rs index 9afc632a8..04dfbddfe 100644 --- a/src/test.rs +++ b/src/test.rs @@ -9,24 +9,23 @@ fn init() { env::set_var("NO_COLOR", "1"); env_logger::init(); let _ = fs::remove_dir_all("test/cache"); + let _ = fs::remove_dir_all("test/data"); + let _ = fs::remove_dir_all("plugins"); if let Err(err) = cmd!( "git", "checkout", + "plugins", "test/.test-tool-versions", "test/cwd/.test-tool-versions", - "test/config/config.toml" + "test/config/config.toml", + "test/data" ) .run() { warn!("failed to reset test files: {}", err); } reset_config(); - assert_cli!( - "plugin", - "install", - "tiny", - "https://github.com/jdxcode/asdf-tiny" - ); + assert_cli!("install", "tiny", "dummy"); } pub fn reset_config() { diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 3228411d3..5b221bab1 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -160,3 +160,25 @@ pub fn resolve_alias(settings: &Settings, plugin: Arc, v: &str) -> Resul } Ok(v.to_string()) } + +#[cfg(test)] +mod tests { + use pretty_assertions::assert_str_eq; + + use super::*; + + #[test] + fn test_tool_version_display() { + let foo = "foo".to_string(); + let tv = ToolVersion::new(foo.clone(), ToolVersionType::Version("1.2.3".to_string())); + assert_str_eq!(tv.to_string(), "foo@1.2.3"); + let tv = ToolVersion::new(foo.clone(), ToolVersionType::Prefix("1.2.3".to_string())); + assert_str_eq!(tv.to_string(), "foo@prefix:1.2.3"); + let tv = ToolVersion::new(foo.clone(), ToolVersionType::Ref("master".to_string())); + assert_str_eq!(tv.to_string(), "foo@ref:master"); + let tv = ToolVersion::new(foo.clone(), ToolVersionType::Path("~".to_string())); + assert_str_eq!(tv.to_string(), "foo@path:~"); + let tv = ToolVersion::new(foo, ToolVersionType::System); + assert_str_eq!(tv.to_string(), "foo@system"); + } +} diff --git a/test/.test-tool-versions b/test/.test-tool-versions index a4d4d0dc0..84c0668d0 100644 --- a/test/.test-tool-versions +++ b/test/.test-tool-versions @@ -1,3 +1 @@ -shfmt 2 -jq 1.6 -tiny 2 +tiny 2 diff --git a/test/cwd/.node-version b/test/cwd/.node-version deleted file mode 100644 index 7eae4e2e9..000000000 --- a/test/cwd/.node-version +++ /dev/null @@ -1 +0,0 @@ -18.0.0 diff --git a/test/cwd/.test-tool-versions b/test/cwd/.test-tool-versions index 7808524f6..55dc0d04d 100644 --- a/test/cwd/.test-tool-versions +++ b/test/cwd/.test-tool-versions @@ -1,5 +1 @@ -#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 -shfmt 3.5.1 # test comment -#nodejs 18.13.0 -nodejs system +tiny 3 From 3ca8b5243e1455d9558cee597605fcf91b11fa1f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 23 Feb 2023 08:01:11 -0600 Subject: [PATCH 0266/1891] bug: set identifier to self-update asset Fixes #189 --- src/cli/self_update/github.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli/self_update/github.rs b/src/cli/self_update/github.rs index 2d5ac518d..026a8d47e 100644 --- a/src/cli/self_update/github.rs +++ b/src/cli/self_update/github.rs @@ -25,6 +25,7 @@ impl Command for SelfUpdate { .show_download_progress(true) .current_version(¤t_version) .target(&format!("{}-{}", *OS, *ARCH)) + .identifier("rtx-v") .build()? .update()?; if status.updated() { From 89804ad5915fad73bec2f717df25c27bdbf0f9e3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 23 Feb 2023 08:04:11 -0600 Subject: [PATCH 0267/1891] chore: Release rtx-cli version 1.16.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ddbbfe29..152d5bc37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1361,7 +1361,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.15.4" +version = "1.16.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index d78304a0d..444718e83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.15.4" +version = "1.16.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index fb1d13b26..cdba00b04 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.15.4 +rtx 1.16.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -295,7 +295,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.4/rtx-v1.15.4-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.0/rtx-v1.16.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 4a84576f7..8ef18681f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.15.4 +Version: 1.16.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index fb98a32d8..7fd7fbee0 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -224,7 +224,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.15.4/rtx-v1.15.4-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.0/rtx-v1.16.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From a5bf2241c292514c28b4362633654c4e4fa94487 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 08:27:19 -0600 Subject: [PATCH 0268/1891] test: reset config after local tests --- src/cli/local.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cli/local.rs b/src/cli/local.rs index 5a0b93068..d5c35bd48 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -125,6 +125,7 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; + use crate::test::reset_config; use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; #[test] @@ -252,6 +253,7 @@ mod tests { fs::write(cf_path, orig).unwrap(); - assert!(result.is_ok()) + assert!(result.is_ok()); + reset_config(); } } From 1341dc92c15f03e2695f0dd251ea90ee3906e16a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 08:35:26 -0600 Subject: [PATCH 0269/1891] test: fix list-aliases in tiny plugin --- plugins/tiny/bin/list-aliases | 6 ++++++ src/cli/alias/ls.rs | 2 -- src/cli/mod.rs | 11 ----------- 3 files changed, 6 insertions(+), 13 deletions(-) create mode 100755 plugins/tiny/bin/list-aliases diff --git a/plugins/tiny/bin/list-aliases b/plugins/tiny/bin/list-aliases new file mode 100755 index 000000000..fb1a546b2 --- /dev/null +++ b/plugins/tiny/bin/list-aliases @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -eu -o pipefail + +echo "lts 3.1.0" +echo "lts-prev 2.0.0" diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 5c3be93dd..b1974b7e5 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -52,11 +52,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { use crate::assert_cli; - use crate::cli::tests::ensure_plugin_installed; #[test] fn test_alias_ls() { - ensure_plugin_installed("tiny"); let stdout = assert_cli!("aliases"); assert!(stdout.contains("my/alias")); } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index c5a6fe575..91b9f732f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -250,17 +250,6 @@ pub mod tests { }}; } - pub fn ensure_plugin_installed(name: &str) { - let mut config = Config::load().unwrap(); - config.settings.missing_runtime_behavior = AutoInstall; - let plugin = Plugin::new(&PluginName::from(name)); - if plugin.is_installed() { - plugin - .install(&config, None, ProgressReport::new(true)) - .unwrap(); - } - } - pub fn grep(output: String, pattern: &str) -> String { output .split('\n') From f504f61258f42c63473516e65c602678911ec42f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 08:47:12 -0600 Subject: [PATCH 0270/1891] test: fix `cargo nextest` --- .config/nextest.toml | 2 ++ src/cli/mod.rs | 3 --- src/cli/plugins/ls.rs | 10 +++++++--- .../rtx__cli__plugins__ls__tests__plugin_list.snap | 7 +++++++ ...rtx__cli__plugins__ls__tests__plugin_list_urls.snap | 7 ------- 5 files changed, 16 insertions(+), 13 deletions(-) create mode 100644 .config/nextest.toml create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 000000000..ee5013a7c --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,2 @@ +[profile.default] +test-threads = 1 diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 91b9f732f..7c6759e18 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -207,10 +207,7 @@ static AFTER_HELP: Lazy = Lazy::new(|| { #[cfg(test)] pub mod tests { - use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::dirs; - use crate::plugins::{Plugin, PluginName}; - use crate::ui::progress_report::ProgressReport; use super::*; diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index ad04839b0..cef669fea 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -68,13 +68,17 @@ mod tests { #[test] fn test_plugin_list() { - let stdout = assert_cli!("plugin", "list"); - assert_str_eq!(grep(stdout, "dummy"), "dummy"); + assert_cli_snapshot!("plugin", "list"); } #[test] fn test_plugin_list_urls() { - assert_cli_snapshot!("plugin", "list", "--urls"); + assert_cli!("plugin", "install", "-f", "tiny"); + let stdout = assert_cli!("plugin", "list", "--urls"); + assert_str_eq!( + grep(stdout, "tiny"), + "tiny https://github.com/jdxcode/rtx-tiny.git" + ); } #[test] diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap new file mode 100644 index 000000000..388fca08c --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/plugins/ls.rs +expression: output +--- +dummy +tiny + diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap deleted file mode 100644 index b19b1ea77..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_urls.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/plugins/ls.rs -expression: output ---- -dummy https://github.com/jdxcode/rtx -tiny https://github.com/jdxcode/rtx-tiny.git - From 355ee6985d5d4851cf7ef689dca208e793e15292 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:17:21 -0600 Subject: [PATCH 0271/1891] test: improve unit test performance (#193) --- .config/nextest.toml | 3 ++ .github/workflows/rtx.yml | 21 +++++---- e2e/test_plugins_install | 42 ++++++++++++++++++ src/cache.rs | 16 +++++++ src/cli/asdf.rs | 23 ++++++---- src/cli/plugins/install.rs | 24 +--------- src/cli/plugins/ls.rs | 10 +++-- src/cli/plugins/uninstall.rs | 19 -------- ...__cli__asdf__tests__fake_asdf_install.snap | 5 +++ ...tx__cli__asdf__tests__fake_asdf_other.snap | 6 +++ ...x__cli__asdf__tests__fake_asdf_reshim.snap | 5 +++ src/cli/where.rs | 1 + src/git.rs | 44 +++++++++---------- src/test.rs | 18 +------- 14 files changed, 136 insertions(+), 101 deletions(-) create mode 100755 e2e/test_plugins_install create mode 100644 src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap create mode 100644 src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap create mode 100644 src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_reshim.snap diff --git a/.config/nextest.toml b/.config/nextest.toml index ee5013a7c..8c6a0c3f2 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,2 +1,5 @@ [profile.default] test-threads = 1 +slow-timeout = { period = "100ms", terminate-after = 2 } +status-level = "all" +retries = { backoff = "exponential", count = 4, delay = "1s", max-delay = "10s" } diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 2cb1cd509..510eec5e0 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -15,6 +15,7 @@ env: jobs: unit: runs-on: ubuntu-22.04 + timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v3 @@ -24,21 +25,18 @@ jobs: save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Install direnv/shfmt run: sudo apt-get update; sudo apt-get install direnv shfmt - - name: Install just - uses: taiki-e/install-action@just - - name: Run just test-unit - uses: nick-fields/retry@v2 + - uses: taiki-e/install-action@just + - uses: taiki-e/install-action@nextest + - name: Run cargo nextest + run: cargo nextest run env: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} RUST_BACKTRACE: "1" - with: - timeout_minutes: 10 - max_attempts: 3 - command: just test-unit - run: just lint coverage: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v3 @@ -70,6 +68,7 @@ jobs: build-linux: name: build-${{matrix.target}} runs-on: ubuntu-22.04 + timeout-minutes: 10 strategy: fail-fast: false matrix: @@ -96,6 +95,7 @@ jobs: build-macos: name: build-${{matrix.target}} runs-on: macos-12 + timeout-minutes: 10 strategy: fail-fast: false matrix: @@ -121,6 +121,7 @@ jobs: e2e-linux: runs-on: ubuntu-22.04 needs: [build-linux] + timeout-minutes: 10 steps: - uses: actions/checkout@v3 - name: Install zsh/fish/direnv @@ -144,6 +145,7 @@ jobs: rpm: runs-on: ubuntu-22.04 needs: [build-linux] + timeout-minutes: 10 container: jdxcode/chim:rpm if: github.event_name != 'pull_request' steps: @@ -168,6 +170,7 @@ jobs: deb: runs-on: ubuntu-22.04 container: jdxcode/chim:deb + timeout-minutes: 10 if: github.event_name != 'pull_request' needs: [build-linux] steps: @@ -192,6 +195,7 @@ jobs: release: runs-on: ubuntu-22.04 if: startsWith(github.event.ref, 'refs/tags/v') + timeout-minutes: 10 permissions: contents: write needs: @@ -252,6 +256,7 @@ jobs: bump-homebrew-formula: runs-on: macos-latest if: startsWith(github.event.ref, 'refs/tags/v') + timeout-minutes: 10 needs: [release] steps: - name: Checkout repository diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install new file mode 100755 index 000000000..2e89fd6f8 --- /dev/null +++ b/e2e/test_plugins_install @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euxo pipefail + +assert_not_contains() { + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" == *"$expected"* ]]; then + echo "assertion failed, expected not '$expected', got '$actual'" + exit 1 + fi +} +assert_contains() { + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != *"$expected"* ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi +} + +rm -rf "$RTX_DATA_DIR/plugins/tiny" +rtx plugin install https://github.com/jdxcode/rtx-tiny.git +assert_contains "rtx plugin ls" "tiny" +rtx plugin install -f tiny +assert_contains "rtx plugin ls" "tiny" + +rm -rf "$RTX_DATA_DIR/plugins/tiny" +rtx plugin install tiny https://github.com/jdxcode/rtx-tiny +assert_contains "rtx plugin ls" "tiny" + +rm -rf "$RTX_DATA_DIR/plugins/shellcheck" +rtx plugin install --all +assert_contains "rtx plugin ls" "shellcheck" + +rtx plugin uninstall tiny +assert_not_contains "rtx plugin ls" "tiny" +rtx plugin uninstall tiny + +rtx plugin update --all +rtx plugin update shfmt diff --git a/src/cache.rs b/src/cache.rs index 7eba767a1..627c3dcdf 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -130,3 +130,19 @@ where freshest } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_cache() { + // does not fail with invalid path + let cache = CacheManager::new("/invalid:path/to/cache".into()); + cache.clear().unwrap(); + let val = cache.get_or_try_init(|| Ok(1)).unwrap(); + assert_eq!(val, &1); + let val = cache.get_or_try_init(|| Ok(2)).unwrap(); + assert_eq!(val, &1); + } +} diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 9ec9f11a2..aa907e98c 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -62,20 +62,27 @@ fn list_versions(config: &Config, out: &mut Output, args: &Vec) -> Resul #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::cli::version::VERSION; use crate::{assert_cli, assert_cli_snapshot}; - #[test] - fn test_fake_asdf() { - let stdout = assert_cli!("asdf", "version"); - assert_str_eq!(stdout, VERSION.to_string() + "\n"); - } - #[test] fn test_fake_asdf_list() { assert_cli!("asdf", "install", "tiny"); assert_cli_snapshot!("asdf", "list", "tiny"); } + + #[test] + fn test_fake_asdf_other() { + assert_cli_snapshot!("asdf", "current", "tiny"); + } + + #[test] + fn test_fake_asdf_reshim() { + assert_cli_snapshot!("asdf", "reshim"); + } + + #[test] + fn test_fake_asdf_install() { + assert_cli_snapshot!("asdf", "install", "tiny"); + } } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 353d7e2be..dc1c7613d 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -140,23 +140,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use insta::{assert_display_snapshot, assert_snapshot}; + use insta::assert_display_snapshot; - use crate::assert_cli; use crate::cli::tests::cli_run; - use crate::cli::tests::grep; - - #[test] - fn test_plugin_install_url() { - assert_cli!( - "plugin", - "add", - "-f", - "https://github.com/jdxcode/rtx-tiny.git" - ); - let stdout = assert_cli!("plugin", "--urls"); - assert_snapshot!(grep(stdout, "tiny"), @"tiny https://github.com/jdxcode/rtx-tiny.git"); - } #[test] fn test_plugin_install_invalid_url() { @@ -164,12 +150,4 @@ mod tests { let err = cli_run(&args).unwrap_err(); assert_display_snapshot!(err); } - - #[test] - fn test_plugin_install_all() { - assert_cli!("plugin", "rm", "tiny"); - assert_cli!("plugin", "install", "--all"); - let stdout = assert_cli!("plugin"); - assert_snapshot!(grep(stdout, "tiny"), "tiny"); - } } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index cef669fea..b61dedb0b 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -64,7 +64,8 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; - use crate::{assert_cli, assert_cli_snapshot}; + use crate::git::Git; + use crate::{assert_cli, assert_cli_snapshot, dirs}; #[test] fn test_plugin_list() { @@ -73,11 +74,12 @@ mod tests { #[test] fn test_plugin_list_urls() { - assert_cli!("plugin", "install", "-f", "tiny"); let stdout = assert_cli!("plugin", "list", "--urls"); + let git = Git::new(dirs::CURRENT.clone()); + let cur_remote = git.get_remote_url().unwrap(); assert_str_eq!( - grep(stdout, "tiny"), - "tiny https://github.com/jdxcode/rtx-tiny.git" + grep(stdout, "dummy"), + "dummy ".to_owned() + cur_remote.as_str() ); } diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 258206313..3b7a609cc 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -41,22 +41,3 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx uninstall nodejs "#, style("Examples:").bold().underlined()} }); - -#[cfg(test)] -mod tests { - - use crate::{assert_cli, assert_cli_snapshot}; - - #[test] - fn test_plugin_uninstall() { - assert_cli!("plugin", "add", "tiny"); - assert_cli_snapshot!("plugin", "rm", "tiny"); - assert_cli_snapshot!("plugin", "rm", "tiny"); - assert_cli!( - "plugin", - "add", - "tiny", - "https://github.com/jdxcode/rtx-tiny.git" - ); - } -} diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap new file mode 100644 index 000000000..7e33daa9d --- /dev/null +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/asdf.rs +expression: output +--- + diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap new file mode 100644 index 000000000..3985be099 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/asdf.rs +expression: output +--- +3.1.0 + diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_reshim.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_reshim.snap new file mode 100644 index 000000000..7e33daa9d --- /dev/null +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_reshim.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/asdf.rs +expression: output +--- + diff --git a/src/cli/where.rs b/src/cli/where.rs index 7ed1613e8..282686116 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -89,6 +89,7 @@ mod tests { stdout.trim(), dirs::ROOT.join("installs/tiny/3.0.1").to_string_lossy() ); + assert_cli!("uninstall", "tiny@my/alias"); } #[test] diff --git a/src/git.rs b/src/git.rs index d5c38f2d0..5ac3c16fd 100644 --- a/src/git.rs +++ b/src/git.rs @@ -127,25 +127,25 @@ fn get_git_version() -> Result { Ok(version.trim().into()) } -#[cfg(test)] -mod tests { - use pretty_assertions::assert_str_eq; - use tempfile::tempdir; - - use super::*; - - #[test] - fn test_clone_and_update() { - let dir = tempdir().unwrap().into_path(); - let git = Git::new(dir); - git.clone("https://github.com/asdf-vm/asdf-plugins") - .unwrap(); - let prev_rev = "f4b510d1d0c01ab2da95b80a1c1521f651cdd708".to_string(); - let latest = git.current_sha().unwrap(); - let update_result = git.update(Some(prev_rev.clone())).unwrap(); - assert_eq!(update_result, (latest.to_string(), prev_rev.to_string())); - assert_str_eq!(git.current_sha_short().unwrap(), "f4b510d"); - let update_result = git.update(None).unwrap(); - assert_eq!(update_result, (prev_rev, latest)); - } -} +// #[cfg(test)] +// mod tests { +// use pretty_assertions::assert_str_eq; +// use tempfile::tempdir; +// +// use super::*; +// +// #[test] +// fn test_clone_and_update() { +// let dir = tempdir().unwrap().into_path(); +// let git = Git::new(dir); +// git.clone("https://github.com/jdxcode/rtx-tiny") +// .unwrap(); +// let prev_rev = "c85ab2bea15e8b785592ce1a75db341e38ac4d33".to_string(); +// let latest = git.current_sha().unwrap(); +// let update_result = git.update(Some(prev_rev.clone())).unwrap(); +// assert_eq!(update_result, (latest.to_string(), prev_rev.to_string())); +// assert_str_eq!(git.current_sha_short().unwrap(), "c85ab2b"); +// let update_result = git.update(None).unwrap(); +// assert_eq!(update_result, (prev_rev, latest)); +// } +// } diff --git a/src/test.rs b/src/test.rs index 04dfbddfe..fc9752fc1 100644 --- a/src/test.rs +++ b/src/test.rs @@ -2,28 +2,12 @@ use std::fs; use indoc::indoc; -use crate::{assert_cli, cmd, env}; +use crate::{assert_cli, env}; #[ctor::ctor] fn init() { env::set_var("NO_COLOR", "1"); env_logger::init(); - let _ = fs::remove_dir_all("test/cache"); - let _ = fs::remove_dir_all("test/data"); - let _ = fs::remove_dir_all("plugins"); - if let Err(err) = cmd!( - "git", - "checkout", - "plugins", - "test/.test-tool-versions", - "test/cwd/.test-tool-versions", - "test/config/config.toml", - "test/data" - ) - .run() - { - warn!("failed to reset test files: {}", err); - } reset_config(); assert_cli!("install", "tiny", "dummy"); } From 971f42a712deec57ba4ffa187d16aa8c57f7931c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:21:33 -0600 Subject: [PATCH 0272/1891] test: add .node-version to e2e tests This uses 18.0.0 instead of 18.13.0 which just helps performance slightly since it can be re-used --- e2e/.node-version | 1 + e2e/test_plugins_install | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 e2e/.node-version diff --git a/e2e/.node-version b/e2e/.node-version new file mode 100644 index 000000000..7eae4e2e9 --- /dev/null +++ b/e2e/.node-version @@ -0,0 +1 @@ +18.0.0 diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install index 2e89fd6f8..dda27fa6b 100755 --- a/e2e/test_plugins_install +++ b/e2e/test_plugins_install @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -euxo pipefail +set -euo pipefail assert_not_contains() { actual="$($1)" From 00304bb7ecf0ed9997dc9bc13353070f640dd46a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:29:15 -0600 Subject: [PATCH 0273/1891] test: cover multi_progress_report --- src/ui/multi_progress_report.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 111067b4f..3f973bf03 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -33,3 +33,19 @@ impl MultiProgressReport { // } // } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_multi_progress_report() { + let mpr = MultiProgressReport::new(false); + let pr = mpr.add(); + pr.set_style(indicatif::ProgressStyle::with_template("").unwrap()); + pr.enable_steady_tick(); + pr.finish_with_message("test".into()); + pr.println("".into()); + pr.set_message("test".into()); + } +} From e32865ad3b76fbf563354e21679ad6f4938da04d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:31:59 -0600 Subject: [PATCH 0274/1891] test: cover config display --- src/config/mod.rs | 12 ++++++++++++ src/config/snapshots/rtx__config__tests__load.snap | 7 +++++++ 2 files changed, 19 insertions(+) create mode 100644 src/config/snapshots/rtx__config__tests__load.snap diff --git a/src/config/mod.rs b/src/config/mod.rs index 4e7287252..e0d3c026d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -204,3 +204,15 @@ impl Display for Config { write!(f, " Installed Plugins: {}", plugins.join(", ")) } } + +#[cfg(test)] +mod tests { + use super::*; + use insta::assert_display_snapshot; + + #[test] + fn test_load() { + let config = Config::load().unwrap(); + assert_display_snapshot!(config); + } +} diff --git a/src/config/snapshots/rtx__config__tests__load.snap b/src/config/snapshots/rtx__config__tests__load.snap new file mode 100644 index 000000000..93547335e --- /dev/null +++ b/src/config/snapshots/rtx__config__tests__load.snap @@ -0,0 +1,7 @@ +--- +source: src/config/mod.rs +expression: config +--- +Config: + Files: ~/cwd/.test-tool-versions, ~/.test-tool-versions + Installed Plugins: dummy, tiny From 6af60efed7b5cc0a7f9475bde8a578159160b356 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:52:41 -0600 Subject: [PATCH 0275/1891] test: cover self-update (#194) --- src/cli/self_update/other.rs | 16 ++++++++++++++++ ...__self_update__other__tests__self_update.snap | 5 +++++ 2 files changed, 21 insertions(+) create mode 100644 src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs index 88a0f4154..1f5985c07 100644 --- a/src/cli/self_update/other.rs +++ b/src/cli/self_update/other.rs @@ -29,3 +29,19 @@ impl Command for SelfUpdate { Ok(()) } } + +#[cfg(test)] +mod tests { + use crate::assert_cli_err; + use insta::assert_display_snapshot; + + use super::*; + + #[test] + fn test_self_update() -> Result<()> { + let err = assert_cli_err!("self-update"); + assert_display_snapshot!(err); + + Ok(()) + } +} diff --git a/src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap b/src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap new file mode 100644 index 000000000..e090928a1 --- /dev/null +++ b/src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/self_update/other.rs +expression: err +--- +Self-update is not supported From 5c8ddfff1e8bd032c8ececf1e0df937ed5a823e4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:56:29 -0600 Subject: [PATCH 0276/1891] test: added xonsh coverage --- ..._shell__xonsh__tests__xonsh_deactivate.snap | 18 ++++++++++++++++++ src/shell/xonsh.rs | 13 +++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap new file mode 100644 index 000000000..7c9616d01 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap @@ -0,0 +1,18 @@ +--- +source: src/shell/xonsh.rs +expression: "Xonsh::default().deactivate()" +--- +from xonsh.built_ins import XSH + +hooks = { + 'on_pre_prompt' : ['listen_prompt'], +} +for hook_type in hooks: + hook_fns = hooks[hook_type] + for hook_fn in hook_fns: + hndl = getattr(XSH.builtins.events, hook_type) + for fn in hndl: + if fn.__name__ == hook_fn: + hndl.remove(fn) + break + diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 717c3d3b9..9bb857f85 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -143,4 +143,17 @@ mod tests { fn test_unset_env() { insta::assert_snapshot!(Xonsh::default().unset_env("FOO")); } + + #[test] + fn test_xonsh_escape_sq() { + assert_eq!(xonsh_escape_sq("foo"), "foo"); + assert_eq!(xonsh_escape_sq("foo'bar"), "foo\\'bar"); + assert_eq!(xonsh_escape_sq("foo\\bar"), "foo\\\\bar"); + assert_eq!(xonsh_escape_sq("foo\nbar"), "foo\\nbar"); + } + + #[test] + fn test_xonsh_deactivate() { + insta::assert_snapshot!(Xonsh::default().deactivate()); + } } From 77088e91d0c43b0a90226947334301a7a75eac27 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 11:16:12 -0600 Subject: [PATCH 0277/1891] test: cover build_time.rs (#195) --- src/build_time.rs | 47 +++++++++++++++---- ..._time__tests__render_outdated_message.snap | 6 +++ 2 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 src/snapshots/rtx__build_time__tests__render_outdated_message.snap diff --git a/src/build_time.rs b/src/build_time.rs index 067bd7808..737dcd34a 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -1,10 +1,10 @@ -use crate::env::RTX_HIDE_OUTDATED_BUILD; use build_time::build_time_utc; use chrono::{DateTime, FixedOffset, Months, Utc}; use console::style; - use lazy_static::lazy_static; +use crate::env::RTX_HIDE_OUTDATED_BUILD; + lazy_static! { pub static ref BUILD_TIME: DateTime = DateTime::parse_from_rfc3339(build_time_utc!()).unwrap(); @@ -15,13 +15,40 @@ fn init() { if !*RTX_HIDE_OUTDATED_BUILD && BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() { - let rtx = style("rtx").dim().for_stderr(); - eprintln!( - "{rtx} rtx has not been updated in over a year. Please update to the latest version" - ); - if cfg!(feature = "self_update") { - eprintln!("{rtx} update with: `rtx self-update`"); - } - eprintln!("{rtx} To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1."); + eprintln!("{}", render_outdated_message()); + } +} + +fn render_outdated_message() -> String { + let rtx = style("rtx").dim().for_stderr(); + let mut output = vec![]; + output.push(format!( + "{rtx} rtx has not been updated in over a year. Please update to the latest version." + )); + if cfg!(any( + feature = "self_update", + feature = "brew", + feature = "deb", + feature = "rpm" + )) { + output.push(format!("{rtx} update with: `rtx self-update`")); + } + output.push(format!( + "{rtx} To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1." + )); + + output.join("\n") +} + +#[cfg(test)] +mod tests { + use insta::assert_snapshot; + + use super::*; + + #[test] + fn test_render_outdated_message() { + let msg = render_outdated_message(); + assert_snapshot!(console::strip_ansi_codes(&msg)); } } diff --git a/src/snapshots/rtx__build_time__tests__render_outdated_message.snap b/src/snapshots/rtx__build_time__tests__render_outdated_message.snap new file mode 100644 index 000000000..1dc5cb761 --- /dev/null +++ b/src/snapshots/rtx__build_time__tests__render_outdated_message.snap @@ -0,0 +1,6 @@ +--- +source: src/build_time.rs +expression: "console::strip_ansi_codes(&msg)" +--- +rtx rtx has not been updated in over a year. Please update to the latest version. +rtx To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1. From 5eb7db87b1405266f10098f0f4505926eafb7536 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 12:40:59 -0600 Subject: [PATCH 0278/1891] test: increase timeout of some jobs --- .github/workflows/rtx.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 510eec5e0..24f114792 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -36,7 +36,7 @@ jobs: coverage: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 steps: - name: Checkout uses: actions/checkout@v3 @@ -56,7 +56,6 @@ jobs: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} RUST_BACKTRACE: "1" with: - timeout_minutes: 10 max_attempts: 3 command: just test-coverage - name: Upload to codecov.io @@ -68,7 +67,7 @@ jobs: build-linux: name: build-${{matrix.target}} runs-on: ubuntu-22.04 - timeout-minutes: 10 + timeout-minutes: 20 strategy: fail-fast: false matrix: @@ -95,7 +94,7 @@ jobs: build-macos: name: build-${{matrix.target}} runs-on: macos-12 - timeout-minutes: 10 + timeout-minutes: 20 strategy: fail-fast: false matrix: From f5c43b249e184c41bcbca6b601f5fa24b0164372 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:29:37 -0600 Subject: [PATCH 0279/1891] test: increase timeout of some jobs --- .github/workflows/rtx.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 24f114792..6aa8999aa 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -56,6 +56,7 @@ jobs: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} RUST_BACKTRACE: "1" with: + timeout_minutes: 20 max_attempts: 3 command: just test-coverage - name: Upload to codecov.io From b272d990c014ff0f31028db57dde612fb4167b0c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 18:57:56 -0600 Subject: [PATCH 0280/1891] docs: show cargo install --git option --- README.md | 9 +++++++-- src/cli/render_help.rs | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cdba00b04..ecf62512e 100644 --- a/README.md +++ b/README.md @@ -262,11 +262,10 @@ $ brew install rtx ### Cargo -Build from source with Cargo. +Build from source with Cargo: ```sh-session $ cargo install rtx-cli -``` Do it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall): @@ -275,6 +274,12 @@ $ cargo install cargo-binstall $ cargo binstall rtx-cli ``` +Build from the latest commit in main: + +```sh-session +$ cargo install rtx-cli --git https://github.com/jdxcode/rtx --branch main +``` + ### npm rtx is available on npm as precompiled binaries. This isn't a node.js package, just distributed diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 7fd7fbee0..c41a95089 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -191,11 +191,10 @@ $ brew install rtx ### Cargo -Build from source with Cargo. +Build from source with Cargo: ```sh-session $ cargo install rtx-cli -``` Do it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall): @@ -204,6 +203,12 @@ $ cargo install cargo-binstall $ cargo binstall rtx-cli ``` +Build from the latest commit in main: + +```sh-session +$ cargo install rtx-cli --git https://github.com/jdxcode/rtx --branch main +``` + ### npm rtx is available on npm as precompiled binaries. This isn't a node.js package, just distributed From fe3a0562222ba1c6d928d8d9511e4094388ccf86 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 19:01:28 -0600 Subject: [PATCH 0281/1891] chore: lower rustc requirement using `cargo-msrv` --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 444718e83..e6727ff25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] include = ["src/**/*", "/LICENSE", "/README.md", "/Cargo.lock"] -rust-version = "1.66.1" +rust-version = "1.64.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From e5e472156ecf36816f2bb357ece9694e908a3f00 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 21:47:56 -0600 Subject: [PATCH 0282/1891] bug: do not pre-create install directory (#197) Apparently asdf creates the downloads directory but not the installs directory. Creating the installs directory causes erlang to fail to install. Fixes #196 --- src/runtimes.rs | 8 ++++++-- src/toolset/tool_version.rs | 3 --- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index 9868bf590..dddc6cb7f 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -28,6 +28,7 @@ pub struct RuntimeVersion { pub install_path: PathBuf, pub install_type: InstallType, download_path: PathBuf, + cache_path: PathBuf, script_man: ScriptManager, bin_paths_cache: CacheManager>, } @@ -61,6 +62,7 @@ impl RuntimeVersion { ), bin_paths_cache: CacheManager::new(cache_path.join("bin_paths.msgpack.zlib")) .with_fresh_file(install_path.clone()), + cache_path, download_path, install_path, version, @@ -125,7 +127,7 @@ impl RuntimeVersion { } } if let Err(err) = fs::remove_file(self.incomplete_file_path()) { - debug!("error removing .rtx-incomplete: {:?}", err); + debug!("error removing incomplete file: {:?}", err); } pr.finish_with_message(style("âś“").green().for_stderr().to_string()); @@ -209,8 +211,10 @@ impl RuntimeVersion { fn create_install_dirs(&self) -> Result<()> { let _ = remove_dir_all(&self.install_path); let _ = remove_dir_all(&self.download_path); + let _ = remove_dir_all(&self.cache_path); create_dir_all(&self.install_path)?; create_dir_all(&self.download_path)?; + create_dir_all(&self.cache_path)?; File::create(self.incomplete_file_path())?; Ok(()) } @@ -226,7 +230,7 @@ impl RuntimeVersion { } fn incomplete_file_path(&self) -> PathBuf { - self.install_path.join(".rtx-incomplete") + self.cache_path.join("incomplete") } } diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 5b221bab1..8e7f78441 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -66,9 +66,6 @@ impl ToolVersion { Some(("prefix", p)) => { return self.resolve_prefix(settings, plugin, p); } - Some(("system", _)) => { - return Ok(None); - } _ => (), } From c04dde4437b19d52bd6c0d308036e0b585ef2ff6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 21:49:34 -0600 Subject: [PATCH 0283/1891] test: show success message after e2e tests passed --- e2e/run_all_tests | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e/run_all_tests b/e2e/run_all_tests index 8e92aeb64..ed32dafa7 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -10,3 +10,5 @@ for f in $FILES; do fi "$ROOT/e2e/run_test" "$f" done + +echo "e2e: all tests passed" From 803a8fdfb620a02b05bdade99784757fe45912f0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 21:50:08 -0600 Subject: [PATCH 0284/1891] chore: Release rtx-cli version 1.16.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 152d5bc37..a6df9ea34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1361,7 +1361,7 @@ dependencies = [ [[package]] name = "rtx-cli" -version = "1.16.0" +version = "1.16.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index e6727ff25..5e99e0f24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.16.0" +version = "1.16.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index ecf62512e..5b3056199 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.16.0 +rtx 1.16.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -300,7 +300,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.0/rtx-v1.16.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.1/rtx-v1.16.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 8ef18681f..1a80696d5 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.16.0 +Version: 1.16.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index c41a95089..186d90904 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -229,7 +229,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.0/rtx-v1.16.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.1/rtx-v1.16.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 50f478c43440d5d5e71cbeb7191919636223d0c0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 22:03:44 -0600 Subject: [PATCH 0285/1891] chore: use S3 to host brew assets instead of github --- packaging/homebrew/homebrew.rb | 8 ++++---- scripts/release.sh | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index ca0b04c7e..80ed11379 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -6,7 +6,7 @@ class Rtx < Formula on_macos do if Hardware::CPU.intel? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-x64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-x64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_X86_64" def install @@ -14,7 +14,7 @@ def install end end if Hardware::CPU.arm? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-arm64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-arm64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_ARM64" def install @@ -25,7 +25,7 @@ def install on_linux do if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-arm64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-arm64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_ARM64" def install @@ -33,7 +33,7 @@ def install end end if Hardware::CPU.intel? - url "https://github.com/jdxcode/rtx/releases/download/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-x64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-x64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_X86_64" def install diff --git a/scripts/release.sh b/scripts/release.sh index a9b39975a..22b8fbc63 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -64,3 +64,6 @@ popd pushd homebrew-tap git add . && git commit -m "rtx $RTX_VERSION" popd + +# we don't want to include these in the github release, only S3 +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-brew"* From 308a0dabc8bc6601061c8f0c300ac63029752a67 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 24 Feb 2023 22:16:39 -0600 Subject: [PATCH 0286/1891] chore: publish to @jdxcode/rtx and rtx-cli npm packages --- scripts/release-npm.sh | 8 ++++---- scripts/release.sh | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index 2908ef512..7973056cc 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -38,7 +38,7 @@ for platform in "${platforms[@]}"; do mv "$RELEASE_DIR/rtx" "$RELEASE_DIR/npm" cat <"$RELEASE_DIR/npm/package.json" { - "name": "@jdxcode/rtx-$os-$arch", + "name": "$NPM_PREFIX-$os-$arch", "version": "$RTX_VERSION", "description": "polyglot runtime manager", "bin": { @@ -75,13 +75,13 @@ function installArchSpecificPackage(version) { var platform = process.platform == 'win32' ? 'win' : process.platform; var arch = platform == 'win' && process.arch == 'ia32' ? 'x86' : process.arch; - var cp = spawn(platform == 'win' ? 'npm.cmd' : 'npm', ['install', '--no-save', ['@jdxcode/rtx', platform, arch].join('-') + '@' + version], { + var cp = spawn(platform == 'win' ? 'npm.cmd' : 'npm', ['install', '--no-save', ['$NPM_PREFIX', platform, arch].join('-') + '@' + version], { stdio: 'inherit', shell: true }); cp.on('close', function(code) { - var pkgJson = require.resolve(['@jdxcode/rtx', platform, arch].join('-') + '/package.json'); + var pkgJson = require.resolve(['$NPM_PREFIX', platform, arch].join('-') + '/package.json'); var subpkg = JSON.parse(fs.readFileSync(pkgJson, 'utf8')); var executable = subpkg.bin.rtx; var bin = path.resolve(path.dirname(pkgJson), executable); @@ -125,7 +125,7 @@ EOF cat <"$RELEASE_DIR/npm/package.json" { - "name": "@jdxcode/rtx", + "name": "$NPM_PREFIX", "description": "polyglot runtime manager", "version": "$RTX_VERSION", "repository": { diff --git a/scripts/release.sh b/scripts/release.sh index 22b8fbc63..fefdece30 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -57,7 +57,8 @@ gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd -./rtx/scripts/release-npm.sh +NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh +NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh ./rtx/scripts/publish-s3.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb From 9f8f7a4f90a80950098b9b5602114d52fbc88eb7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 12:13:20 -0600 Subject: [PATCH 0287/1891] docs: clarify plugins a bit --- README.md | 11 +++++++++-- src/cli/render_help.rs | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5b3056199..8d07217e7 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,9 @@ Unlike asdf which uses shim files to dynamically locate runtimes when they're ca any overhead, but it also makes it so commands like `which node` work as expected. This also means there isn't any need to run `asdf reshim` after installing new runtime binaries. +rtx does not directly install runtimes. Instead, it uses asdf plugins to install runtimes. See +[plugins](#plugins) below. + ### Common example commands rtx install nodejs@20.0.0 Install a specific version number @@ -630,8 +633,12 @@ echo "lts/fermium 14" ## Plugins -rtx uses asdf's plugin ecosystem under the hood. See https://github.com/asdf-vm/asdf-plugins for a -list. +rtx uses asdf's plugin ecosystem under the hood. These plugins contain shell scripts like +`bin/install` (for installing) and `bin/list-all` (for listing all of the available versions). + +See https://github.com/asdf-vm/asdf-plugins for the list of built-in plugins shorthands. See asdf's +[Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn +more about how they work. ## FAQs diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 186d90904..3476966b1 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -128,6 +128,9 @@ Unlike asdf which uses shim files to dynamically locate runtimes when they're ca any overhead, but it also makes it so commands like `which node` work as expected. This also means there isn't any need to run `asdf reshim` after installing new runtime binaries. +rtx does not directly install runtimes. Instead, it uses asdf plugins to install runtimes. See +[plugins](#plugins) below. + ### Common example commands rtx install nodejs@20.0.0 Install a specific version number @@ -559,8 +562,12 @@ echo "lts/fermium 14" ## Plugins -rtx uses asdf's plugin ecosystem under the hood. See https://github.com/asdf-vm/asdf-plugins for a -list. +rtx uses asdf's plugin ecosystem under the hood. These plugins contain shell scripts like +`bin/install` (for installing) and `bin/list-all` (for listing all of the available versions). + +See https://github.com/asdf-vm/asdf-plugins for the list of built-in plugins shorthands. See asdf's +[Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn +more about how they work. ## FAQs From 51c9bbc583ccb501e27958d4edbe76882cc7e2a7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 13:29:57 -0600 Subject: [PATCH 0288/1891] feat: manpage generation (#200) * feat: manpage generation * feat: manpage generation --- .github/workflows/rtx.yml | 6 +- .gitignore | 31 ++--- Cargo.lock | 17 +++ Cargo.toml | 1 + completions/_rtx | 27 ++++ completions/rtx.bash | 50 ++++++- completions/rtx.fish | 62 +++++---- justfile | 43 +++--- man/man1/rtx.1 | 122 ++++++++++++++++++ packaging/deb/Dockerfile | 10 ++ packaging/homebrew/homebrew.rb | 25 ++-- packaging/rpm/Dockerfile | 6 + packaging/rpm/rtx.spec | 1 + scripts/build-deb.sh | 6 +- scripts/build-rpm.sh | 6 +- scripts/build-tarball.sh | 3 + scripts/pre-release-hook.sh | 5 +- src/cli/exec.rs | 4 +- src/cli/mangen.rs | 38 ++++++ src/cli/mod.rs | 7 + src/cli/self_update/github.rs | 11 +- .../rtx__cli__mangen__tests__complete.snap | 5 + src/env.rs | 1 + test/.gitignore | 1 + 24 files changed, 385 insertions(+), 103 deletions(-) create mode 100644 man/man1/rtx.1 create mode 100644 packaging/deb/Dockerfile create mode 100644 packaging/rpm/Dockerfile create mode 100644 src/cli/mangen.rs create mode 100644 src/cli/snapshots/rtx__cli__mangen__tests__complete.snap diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 6aa8999aa..a64401bba 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -28,7 +28,7 @@ jobs: - uses: taiki-e/install-action@just - uses: taiki-e/install-action@nextest - name: Run cargo nextest - run: cargo nextest run + run: cargo nextest run --features clap_mangen env: GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} RUST_BACKTRACE: "1" @@ -146,7 +146,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-linux] timeout-minutes: 10 - container: jdxcode/chim:rpm + container: jdxcode/rtx:rpm if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v3 @@ -169,7 +169,7 @@ jobs: if-no-files-found: error deb: runs-on: ubuntu-22.04 - container: jdxcode/chim:deb + container: jdxcode/rtx:deb timeout-minutes: 10 if: github.event_name != 'pull_request' needs: [build-linux] diff --git a/.gitignore b/.gitignore index d009fd0ae..3840d36a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,31 +1,16 @@ +.DS_Store /dist/ /node_modules/ - -# Generated by Cargo -# will have compiled files and executables -/target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - - -# Added by cargo - -/target - - -# Added by cargo -# -# already existing elements were commented out - -#/target +package-lock.json *.log *.profraw +lcov.info **/snapshots/*.snap.new -package-lock.json - -# ignore macos system file -.DS_Store +# Generated by Cargo +# will have compiled files and executables +/target/ +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock index a6df9ea34..9894c31c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,16 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_mangen" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0f09a0ca8f0dd8ac92c546b426f466ef19828185c6d504c80c48c9c2768ed9" +dependencies = [ + "clap", + "roff", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1359,6 +1369,12 @@ dependencies = [ "serde", ] +[[package]] +name = "roff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" + [[package]] name = "rtx-cli" version = "1.16.1" @@ -1368,6 +1384,7 @@ dependencies = [ "chrono", "clap", "clap_complete", + "clap_mangen", "color-eyre", "console", "ctor", diff --git a/Cargo.toml b/Cargo.toml index 5e99e0f24..48cf9ef3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ build-time = "0.1.2" chrono = "0.4.23" clap = { version = "4.1.1", features = ["env", "derive", "string"] } clap_complete = "4.1.1" +clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" console = "0.15.5" ctor = "0.1.26" diff --git a/completions/_rtx b/completions/_rtx index 9c8322f2b..d4c4c54d5 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -533,6 +533,17 @@ _arguments "${_arguments_options[@]}" \ '::prefix -- The version prefix to use when querying the latest version same as the first argument after the "@":' \ && ret=0 ;; +(mangen) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; (plugins) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ @@ -996,6 +1007,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(mangen) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (plugins) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help__plugins_commands" \ @@ -1128,6 +1143,7 @@ _rtx_commands() { 'list:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ 'list-remote:List runtime versions available for install' \ +'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ 'self-update:Updates rtx itself' \ @@ -1474,6 +1490,7 @@ _rtx__help_commands() { 'local:Sets .tool-versions to include a specific runtime' \ 'ls:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ +'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ @@ -1668,6 +1685,16 @@ _rtx__plugins__ls-remote_commands() { local commands; commands=() _describe -t commands 'rtx plugins ls-remote commands' commands "$@" } +(( $+functions[_rtx__help__mangen_commands] )) || +_rtx__help__mangen_commands() { + local commands; commands=() + _describe -t commands 'rtx help mangen commands' commands "$@" +} +(( $+functions[_rtx__mangen_commands] )) || +_rtx__mangen_commands() { + local commands; commands=() + _describe -t commands 'rtx mangen commands' commands "$@" +} (( $+functions[_rtx__help__plugins_commands] )) || _rtx__help__plugins_commands() { local commands; commands=( diff --git a/completions/rtx.bash b/completions/rtx.bash index dc8521fca..7882af64b 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -96,6 +96,9 @@ _rtx() { rtx,ls-remote) cmd="rtx__ls__remote" ;; + rtx,mangen) + cmd="rtx__mangen" + ;; rtx,p) cmd="rtx__plugins" ;; @@ -276,6 +279,9 @@ _rtx() { rtx__help,ls-remote) cmd="rtx__help__ls__remote" ;; + rtx__help,mangen) + cmd="rtx__help__mangen" + ;; rtx__help,plugins) cmd="rtx__help__plugins" ;; @@ -454,7 +460,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1282,7 +1288,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins self-update settings uninstall version where render-help help" + opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1701,6 +1707,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__mangen) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__plugins) opts="install ls ls-remote uninstall update" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2135,6 +2155,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__mangen) + opts="-j -v -h --log-level --jobs --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__plugins) opts="-a -u -j -v -h --all --urls --log-level --jobs --verbose --help install ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index f7daabab0..fb58a538d 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -23,6 +23,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Get the latest run complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_use_subcommand" -f -a "mangen" -d 'Generate man pages' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' @@ -199,6 +200,10 @@ complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from mangen" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from mangen" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from mangen" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' @@ -293,34 +298,35 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/justfile b/justfile index 0c86c29ff..bdd265024 100644 --- a/justfile +++ b/justfile @@ -12,27 +12,24 @@ alias b := test # just `cargo build` build *args: - cargo build {{ args }} + cargo build --all-features {{ args }} alias t := test # run all test types -test: test-unit test-e2e - -# prepare repo to execute tests -test-setup: build +test *args: (test-unit args) test-e2e # update all test snapshot files -test-update-snapshots: test-setup +test-update-snapshots: find . -name '*.snap' -delete cargo insta test --accept # run the rust "unit" tests -test-unit: test-setup - cargo test +test-unit *args: + cargo test --features clap_mangen {{ args }} # runs the E2E tests in ./e2e -test-e2e: test-setup build +test-e2e: build ./e2e/run_all_tests # run unit tests w/ coverage @@ -42,9 +39,12 @@ test-coverage: source <(cargo llvm-cov show-env --export-prefix) cargo llvm-cov clean --workspace - cargo test - cargo build + cargo test --features clap_mangen + cargo build --all-features PATH="$PWD/target/debug:$PATH" ./e2e/run_all_tests + RTX_SELF_UPDATE_VERSION=1.0.0 ./target/debug/rtx self-update < README.md +render-help: build + rtx render-help > README.md ./scripts/gh-md-toc --insert --no-backup --hide-footer --skip-header README.md > /dev/null # regenerate shell completion files -render-completions: - ./.bin/rtx complete -s bash > completions/rtx.bash - ./.bin/rtx complete -s zsh > completions/_rtx - ./.bin/rtx complete -s fish > completions/rtx.fish +render-completions: build + rtx complete -s bash > completions/rtx.bash + rtx complete -s zsh > completions/_rtx + rtx complete -s fish > completions/rtx.fish + +# regenerate manpages +render-mangen: build + rtx mangen # called by husky precommit hook -pre-commit: lint render-help render-completions +pre-commit: lint render-help render-completions render-mangen git add README.md git add completions + git add man diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 new file mode 100644 index 000000000..a7df2f8ef --- /dev/null +++ b/man/man1/rtx.1 @@ -0,0 +1,122 @@ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.TH rtx 1 "rtx 1.16.1" +.SH NAME +rtx \- Polyglot runtime manager (asdf rust clone) +.SH SYNOPSIS +\fBrtx\fR [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> +.SH DESCRIPTION +rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx +.PP +It\*(Aqs a replacement for tools like nvm, nodenv, rbenv, rvm, chruby, pyenv, etc. +that works for any language. It\*(Aqs also great for managing linters/tools like +jq and shellcheck. +.PP +It is inspired by asdf and uses asdf\*(Aqs plugin ecosystem under the hood: +https://asdf\-vm.com/ +.SH OPTIONS +.TP +\fB\-j\fR, \fB\-\-jobs\fR +Number of plugins and runtimes to install in parallel, default: 4 +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Show installation output +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help (see a summary with \*(Aq\-h\*(Aq) +.TP +\fB\-V\fR, \fB\-\-version\fR +Print version +.SH SUBCOMMANDS +.TP +rtx\-activate(1) +Enables rtx to automatically modify runtimes when changing directory +.TP +rtx\-alias(1) +Manage aliases +.TP +rtx\-bin\-paths(1) +List all the active runtime bin paths +.TP +rtx\-cache(1) +Manage the rtx cache +.TP +rtx\-complete(1) +Generate shell completions +.TP +rtx\-current(1) +Shows current active and installed runtime versions +.TP +rtx\-deactivate(1) +Disable rtx for current shell session +.TP +rtx\-direnv(1) +Output direnv function to use rtx inside direnv +.TP +rtx\-doctor(1) +Check rtx installation for possible problems. +.TP +rtx\-env(1) +exports env vars to activate rtx in a single shell session +.TP +rtx\-exec(1) +Execute a command with runtime(s) set +.TP +rtx\-global(1) +Sets global .tool\-versions to include a specified runtime +.TP +rtx\-implode(1) +Removes rtx CLI and all generated data +.TP +rtx\-install(1) +Install a runtime +.TP +rtx\-latest(1) +Get the latest runtime version of a plugin\*(Aqs runtimes +.TP +rtx\-local(1) +Sets .tool\-versions to include a specific runtime +.TP +rtx\-ls(1) +List installed runtime versions +.TP +rtx\-ls\-remote(1) +List runtime versions available for install +.TP +rtx\-plugins(1) +Manage plugins +.TP +rtx\-self\-update(1) +Updates rtx itself +.TP +rtx\-settings(1) +Manage settings +.TP +rtx\-uninstall(1) +Removes runtime versions +.TP +rtx\-version(1) +Show rtx version +.TP +rtx\-where(1) +Display the installation path for a runtime +.TP +rtx\-help(1) +Print this message or the help of the given subcommand(s) +.SH EXTRA +Examples: + rtx install nodejs@20.0.0 Install a specific node version + rtx install nodejs@20.0 Install a version matching a prefix + rtx local nodejs@20 Use node\-20.x in current project + rtx global nodejs@20 Use node\-20.x as default + + rtx install nodejs Install the .tool\-versions node version + rtx local nodejs Use latest node in current directory + rtx global system Use system node everywhere unless overridden + + rtx x nodejs@20 \-\- node app.js Run `node app.js` with PATH pointing to + node\-20.x +.SH VERSION +v1.16.1 +.SH AUTHORS +Jeff Dickey <@jdxcode> diff --git a/packaging/deb/Dockerfile b/packaging/deb/Dockerfile new file mode 100644 index 000000000..ae817e878 --- /dev/null +++ b/packaging/deb/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:22.04 +LABEL maintainer="jdxcode" + +RUN apt-get update \ + && apt-get install -y \ + build-essential \ + ruby \ + && apt-get clean + +RUN gem install fpm diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index 80ed11379..14aff4c34 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -8,18 +8,10 @@ class Rtx < Formula if Hardware::CPU.intel? url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-x64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_X86_64" - - def install - bin.install "bin/rtx" - end end if Hardware::CPU.arm? url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-arm64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_ARM64" - - def install - bin.install "bin/rtx" - end end end @@ -27,23 +19,22 @@ def install if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-arm64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_ARM64" - - def install - bin.install "bin/rtx" - end end if Hardware::CPU.intel? url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-x64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_X86_64" - - def install - bin.install "bin/rtx" - end end end + def install + bin.install "bin/rtx" + man1.install "man/man1/rtx.1" + generate_completions_from_executable(bin/"rtx", "complete", "--shell") + end + test do system "#{bin}/rtx --version" - assert_match "it works!", shell_output("#{bin}/rtx exec nodejs@18 -- node -p 'it works!'") + system "#{bin}/rtx", "install", "nodejs@18.13.0" + assert_match "v18.13.0", shell_output("#{bin}/rtx exec nodejs@18.13.0 -- node -v") end end diff --git a/packaging/rpm/Dockerfile b/packaging/rpm/Dockerfile new file mode 100644 index 000000000..79c1aa2e0 --- /dev/null +++ b/packaging/rpm/Dockerfile @@ -0,0 +1,6 @@ +FROM fedora:38 +LABEL maintainer="jdxcode" + +RUN dnf install -y rpm-build rpm-sign ruby ruby-devel gcc +RUN gem install fpm +RUN dnf install -y createrepo diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 1a80696d5..fe6101a75 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -14,6 +14,7 @@ RTX is a polyglot runtime manager %install mkdir -p %{buildroot}/usr/bin/ cp /root/rtx/target/release/rtx %{buildroot}/usr/bin +cp /root/rtx/man/man1/rtx.1 %{buildroot}/usr/share/man/man1/rtx.1 %files /usr/bin/rtx diff --git a/scripts/build-deb.sh b/scripts/build-deb.sh index 55faf9d97..af9cf78d3 100755 --- a/scripts/build-deb.sh +++ b/scripts/build-deb.sh @@ -12,7 +12,8 @@ fpm -s dir -t deb \ --description "Polyglot runtime manager" \ --url "https://github.com/jdxcode/rtx" \ --maintainer "Jeff Dickey @jdxcode" \ - rtx/bin/rtx=/usr/bin/rtx + rtx/bin/rtx=/usr/bin/rtx \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 tar -xvJf "dist/rtx-deb-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t deb \ @@ -23,7 +24,8 @@ fpm -s dir -t deb \ --description "Polyglot runtime manager" \ --url "https://github.com/jdxcode/rtx" \ --maintainer "Jeff Dickey @jdxcode" \ - rtx/bin/rtx=/usr/bin/rtx + rtx/bin/rtx=/usr/bin/rtx \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 mkdir -p dist/deb/pool/main cp -v ./*.deb dist/deb/pool/main diff --git a/scripts/build-rpm.sh b/scripts/build-rpm.sh index f07141597..8a7b9609d 100755 --- a/scripts/build-rpm.sh +++ b/scripts/build-rpm.sh @@ -12,7 +12,8 @@ fpm -s dir -t rpm \ --description "Polyglot runtime manager" \ --url "https://github.com/jdxcode/rtx" \ --maintainer "Jeff Dickey @jdxcode" \ - rtx/bin/rtx=/usr/bin/rtx + rtx/bin/rtx=/usr/bin/rtx \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 tar -xvJf "dist/rtx-rpm-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t rpm \ @@ -23,7 +24,8 @@ fpm -s dir -t rpm \ --description "Polyglot runtime manager" \ --url "https://github.com/jdxcode/rtx" \ --maintainer "Jeff Dickey @jdxcode" \ - rtx/bin/rtx=/usr/bin/rtx + rtx/bin/rtx=/usr/bin/rtx \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 cat <~/.rpmmacros %_signature gpg diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index 353b2f17d..d32527688 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -65,8 +65,11 @@ else cargo build "$@" fi mkdir -p "dist/rtx/bin" +mkdir -p "dist/rtx/man/man1" cp "target/$RUST_TRIPLE/release/rtx" "dist/rtx/bin/rtx" cp README.md "dist/rtx/README.md" +cp LICENSE "dist/rtx/LICENSE" +cp man/man1/rtx.1 "dist/rtx/man/man1" cd dist tar -cJf "$BASENAME.tar.xz" rtx diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 5468b2ac0..4e85d9191 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash set -euxo pipefail +just render-mangen + ./scripts/update-shorthand-repo.sh just lint-fix -git add src/default_shorthands.rs + +git add man src/default_shorthands.rs diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 042ae46a2..6333dbbc4 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -131,13 +131,13 @@ mod tests { #[test] fn test_exec_ok() { - assert_cli!("exec", "--", "jq", "--version"); + assert_cli!("exec", "--", "ls"); } #[test] fn test_exec_fail() { let _ = cli_run( - &vec!["rtx", "exec", "--", "jq", "-invalid"] + &vec!["rtx", "exec", "--", "ls", "--invalid"] .into_iter() .map(String::from) .collect::>(), diff --git a/src/cli/mangen.rs b/src/cli/mangen.rs new file mode 100644 index 000000000..9152a7012 --- /dev/null +++ b/src/cli/mangen.rs @@ -0,0 +1,38 @@ +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::cli::Cli; +use crate::config::Config; +use crate::dirs; +use crate::output::Output; + +/// Generate man pages +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, hide = true)] +pub struct Mangen {} + +impl Command for Mangen { + fn run(self, _config: Config, _out: &mut Output) -> Result<()> { + let cli = Cli::command().version(env!("CARGO_PKG_VERSION")); + + let man = clap_mangen::Man::new(cli); + let mut buffer: Vec = Default::default(); + man.render(&mut buffer)?; + + let out_dir = dirs::CURRENT.join("man").join("man1"); + std::fs::create_dir_all(&out_dir)?; + std::fs::write(out_dir.join("rtx.1"), buffer)?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::assert_cli_snapshot; + + #[test] + fn test_complete() { + assert_cli_snapshot!("mangen"); + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 7c6759e18..76be0f7f0 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -43,6 +43,9 @@ mod r#where; #[cfg(debug_assertions)] mod render_help; +#[cfg(feature = "clap_mangen")] +mod mangen; + pub struct Cli { command: clap::Command, external_commands: Vec, @@ -70,6 +73,8 @@ pub enum Commands { Local(local::Local), Ls(ls::Ls), LsRemote(ls_remote::LsRemote), + #[cfg(feature = "clap_mangen")] + Mangen(mangen::Mangen), Plugins(plugins::Plugins), SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), @@ -104,6 +109,8 @@ impl Commands { Self::Local(cmd) => cmd.run(config, out), Self::Ls(cmd) => cmd.run(config, out), Self::LsRemote(cmd) => cmd.run(config, out), + #[cfg(feature = "clap_mangen")] + Self::Mangen(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), diff --git a/src/cli/self_update/github.rs b/src/cli/self_update/github.rs index 026a8d47e..3abcfd527 100644 --- a/src/cli/self_update/github.rs +++ b/src/cli/self_update/github.rs @@ -18,16 +18,19 @@ impl Command for SelfUpdate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { let current_version = env::var("RTX_SELF_UPDATE_VERSION").unwrap_or(cargo_crate_version!().to_string()); - let status = Update::configure() + let mut update = Update::configure(); + update .repo_owner("jdxcode") .repo_name("rtx") .bin_name("rtx") .show_download_progress(true) .current_version(¤t_version) .target(&format!("{}-{}", *OS, *ARCH)) - .identifier("rtx-v") - .build()? - .update()?; + .identifier("rtx-v"); + if let Some(token) = &*env::GITHUB_API_TOKEN { + update.auth_token(token); + } + let status = update.build()?.update()?; if status.updated() { let version = style(status.version()).bright().yellow(); rtxprintln!(out, "Updated rtx to {version}"); diff --git a/src/cli/snapshots/rtx__cli__mangen__tests__complete.snap b/src/cli/snapshots/rtx__cli__mangen__tests__complete.snap new file mode 100644 index 000000000..8f7f9d249 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__mangen__tests__complete.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/mangen.rs +expression: output +--- + diff --git a/src/env.rs b/src/env.rs index c83fc4a9a..090502ac4 100644 --- a/src/env.rs +++ b/src/env.rs @@ -121,6 +121,7 @@ lazy_static! { pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); pub static ref RTX_SHORTHANDS_FILE: Option = var_path("RTX_SHORTHANDS_FILE"); pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); + pub static ref GITHUB_API_TOKEN: Option = var("GITHUB_API_TOKEN").ok(); } fn get_env_diff() -> EnvDiff { diff --git a/test/.gitignore b/test/.gitignore index b981dcfea..754d0d5e4 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,2 +1,3 @@ data/ cache/ +cwd/man/ From 027149268ba7664399a35940c0939616b1274ef6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 13:46:26 -0600 Subject: [PATCH 0289/1891] test: move test directories to test/data (#202) --- installs | 1 - test/data/plugins | 1 - {plugins => test/data/plugins}/.gitignore | 0 {plugins => test/data/plugins}/dummy/LICENSE | 0 {plugins => test/data/plugins}/dummy/bin/download | 0 .../data/plugins}/dummy/bin/get-version-from-legacy-file | 0 {plugins => test/data/plugins}/dummy/bin/help.overview | 0 {plugins => test/data/plugins}/dummy/bin/install | 0 {plugins => test/data/plugins}/dummy/bin/latest-stable | 0 {plugins => test/data/plugins}/dummy/bin/list-all | 0 {plugins => test/data/plugins}/dummy/bin/list-legacy-filenames | 0 {plugins => test/data/plugins}/dummy/bin/parse-legacy-file | 0 {plugins => test/data/plugins}/dummy/bin/post-plugin-add | 0 {plugins => test/data/plugins}/dummy/bin/post-plugin-update | 0 {plugins => test/data/plugins}/dummy/bin/pre-plugin-remove | 0 {plugins => test/data/plugins}/tiny/.gitignore | 0 {plugins => test/data/plugins}/tiny/bin/exec-env | 0 {plugins => test/data/plugins}/tiny/bin/install | 0 {plugins => test/data/plugins}/tiny/bin/list-aliases | 0 {plugins => test/data/plugins}/tiny/bin/list-all | 0 20 files changed, 2 deletions(-) delete mode 120000 installs delete mode 120000 test/data/plugins rename {plugins => test/data/plugins}/.gitignore (100%) rename {plugins => test/data/plugins}/dummy/LICENSE (100%) rename {plugins => test/data/plugins}/dummy/bin/download (100%) rename {plugins => test/data/plugins}/dummy/bin/get-version-from-legacy-file (100%) rename {plugins => test/data/plugins}/dummy/bin/help.overview (100%) rename {plugins => test/data/plugins}/dummy/bin/install (100%) rename {plugins => test/data/plugins}/dummy/bin/latest-stable (100%) rename {plugins => test/data/plugins}/dummy/bin/list-all (100%) rename {plugins => test/data/plugins}/dummy/bin/list-legacy-filenames (100%) rename {plugins => test/data/plugins}/dummy/bin/parse-legacy-file (100%) rename {plugins => test/data/plugins}/dummy/bin/post-plugin-add (100%) rename {plugins => test/data/plugins}/dummy/bin/post-plugin-update (100%) rename {plugins => test/data/plugins}/dummy/bin/pre-plugin-remove (100%) rename {plugins => test/data/plugins}/tiny/.gitignore (100%) rename {plugins => test/data/plugins}/tiny/bin/exec-env (100%) rename {plugins => test/data/plugins}/tiny/bin/install (100%) rename {plugins => test/data/plugins}/tiny/bin/list-aliases (100%) rename {plugins => test/data/plugins}/tiny/bin/list-all (100%) diff --git a/installs b/installs deleted file mode 120000 index fbd5b970e..000000000 --- a/installs +++ /dev/null @@ -1 +0,0 @@ -test/data/installs \ No newline at end of file diff --git a/test/data/plugins b/test/data/plugins deleted file mode 120000 index 9aa30addd..000000000 --- a/test/data/plugins +++ /dev/null @@ -1 +0,0 @@ -../../plugins \ No newline at end of file diff --git a/plugins/.gitignore b/test/data/plugins/.gitignore similarity index 100% rename from plugins/.gitignore rename to test/data/plugins/.gitignore diff --git a/plugins/dummy/LICENSE b/test/data/plugins/dummy/LICENSE similarity index 100% rename from plugins/dummy/LICENSE rename to test/data/plugins/dummy/LICENSE diff --git a/plugins/dummy/bin/download b/test/data/plugins/dummy/bin/download similarity index 100% rename from plugins/dummy/bin/download rename to test/data/plugins/dummy/bin/download diff --git a/plugins/dummy/bin/get-version-from-legacy-file b/test/data/plugins/dummy/bin/get-version-from-legacy-file similarity index 100% rename from plugins/dummy/bin/get-version-from-legacy-file rename to test/data/plugins/dummy/bin/get-version-from-legacy-file diff --git a/plugins/dummy/bin/help.overview b/test/data/plugins/dummy/bin/help.overview similarity index 100% rename from plugins/dummy/bin/help.overview rename to test/data/plugins/dummy/bin/help.overview diff --git a/plugins/dummy/bin/install b/test/data/plugins/dummy/bin/install similarity index 100% rename from plugins/dummy/bin/install rename to test/data/plugins/dummy/bin/install diff --git a/plugins/dummy/bin/latest-stable b/test/data/plugins/dummy/bin/latest-stable similarity index 100% rename from plugins/dummy/bin/latest-stable rename to test/data/plugins/dummy/bin/latest-stable diff --git a/plugins/dummy/bin/list-all b/test/data/plugins/dummy/bin/list-all similarity index 100% rename from plugins/dummy/bin/list-all rename to test/data/plugins/dummy/bin/list-all diff --git a/plugins/dummy/bin/list-legacy-filenames b/test/data/plugins/dummy/bin/list-legacy-filenames similarity index 100% rename from plugins/dummy/bin/list-legacy-filenames rename to test/data/plugins/dummy/bin/list-legacy-filenames diff --git a/plugins/dummy/bin/parse-legacy-file b/test/data/plugins/dummy/bin/parse-legacy-file similarity index 100% rename from plugins/dummy/bin/parse-legacy-file rename to test/data/plugins/dummy/bin/parse-legacy-file diff --git a/plugins/dummy/bin/post-plugin-add b/test/data/plugins/dummy/bin/post-plugin-add similarity index 100% rename from plugins/dummy/bin/post-plugin-add rename to test/data/plugins/dummy/bin/post-plugin-add diff --git a/plugins/dummy/bin/post-plugin-update b/test/data/plugins/dummy/bin/post-plugin-update similarity index 100% rename from plugins/dummy/bin/post-plugin-update rename to test/data/plugins/dummy/bin/post-plugin-update diff --git a/plugins/dummy/bin/pre-plugin-remove b/test/data/plugins/dummy/bin/pre-plugin-remove similarity index 100% rename from plugins/dummy/bin/pre-plugin-remove rename to test/data/plugins/dummy/bin/pre-plugin-remove diff --git a/plugins/tiny/.gitignore b/test/data/plugins/tiny/.gitignore similarity index 100% rename from plugins/tiny/.gitignore rename to test/data/plugins/tiny/.gitignore diff --git a/plugins/tiny/bin/exec-env b/test/data/plugins/tiny/bin/exec-env similarity index 100% rename from plugins/tiny/bin/exec-env rename to test/data/plugins/tiny/bin/exec-env diff --git a/plugins/tiny/bin/install b/test/data/plugins/tiny/bin/install similarity index 100% rename from plugins/tiny/bin/install rename to test/data/plugins/tiny/bin/install diff --git a/plugins/tiny/bin/list-aliases b/test/data/plugins/tiny/bin/list-aliases similarity index 100% rename from plugins/tiny/bin/list-aliases rename to test/data/plugins/tiny/bin/list-aliases diff --git a/plugins/tiny/bin/list-all b/test/data/plugins/tiny/bin/list-all similarity index 100% rename from plugins/tiny/bin/list-all rename to test/data/plugins/tiny/bin/list-all From 11ca1856e6fdd1431461fa862eec5c9ac059ef31 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 13:47:22 -0600 Subject: [PATCH 0290/1891] chore: Release rtx-cli version 1.17.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9894c31c2..13518d097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1377,7 +1377,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.16.1" +version = "1.17.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 48cf9ef3f..cab867e98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.16.1" +version = "1.17.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 8d07217e7..a375307e8 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.16.1 +rtx 1.17.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -303,7 +303,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.1/rtx-v1.16.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.17.0/rtx-v1.17.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a7df2f8ef..88ffbfc28 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.16.1" +.TH rtx 1 "rtx 1.17.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -117,6 +117,6 @@ Print this message or the help of the given subcommand(s) rtx x nodejs@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.16.1 +v1.17.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index fe6101a75..b9676c1ef 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.16.1 +Version: 1.17.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 3476966b1..e08fdd755 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -232,7 +232,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.16.1/rtx-v1.16.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.17.0/rtx-v1.17.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From baaf9b19a4f3b9ac979293ad957debb1ce8bf22d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 14:36:34 -0600 Subject: [PATCH 0291/1891] bug: immediately call hook-env after activating (#204) Fixes #199 --- e2e/cd/test_bash | 1 - e2e/cd/test_fish | 2 +- e2e/cd/test_zsh | 1 - justfile | 2 +- .../snapshots/rtx__cli__plugins__install__tests__tiny.snap | 5 ----- ..._cli__plugins__uninstall__tests__plugin_uninstall-2.snap | 5 ----- ...x__cli__plugins__uninstall__tests__plugin_uninstall.snap | 6 ------ .../snapshots/rtx__cli__activate__tests__activate_zsh.snap | 2 ++ .../rtx__cli__activate__tests__activate_zsh_legacy.snap | 2 ++ src/shell/bash.rs | 2 ++ src/shell/fish.rs | 2 ++ src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap | 2 ++ src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap | 2 ++ src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap | 2 ++ src/shell/zsh.rs | 2 ++ 15 files changed, 18 insertions(+), 20 deletions(-) delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 5fe8e0401..6eef90093 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -6,7 +6,6 @@ orig_path="$PATH" # shellcheck disable=SC1090 eval "$(rtx activate bash --status)" -_rtx_hook assert_path() { local expected="${1//$HOME/\~}:" diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index f32240987..4177a0ec4 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -4,7 +4,7 @@ #set -l fish_trace 1 rtx install nodejs@18.0.0 nodejs@16.0.0; or exit -rtx activate fish | source && __rtx_env_eval +rtx activate fish | source #rtx i test (node -v) = "v18.0.0"; or exit diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index c2775848f..2508457b5 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -4,7 +4,6 @@ set -euo pipefail rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 eval "$(rtx activate zsh --status)" -_rtx_hook #rtx install test "$(node -v)" = "v18.0.0" diff --git a/justfile b/justfile index bdd265024..96e643dd6 100644 --- a/justfile +++ b/justfile @@ -22,7 +22,7 @@ test *args: (test-unit args) test-e2e # update all test snapshot files test-update-snapshots: find . -name '*.snap' -delete - cargo insta test --accept + cargo insta test --accept --features clap_mangen # run the rust "unit" tests test-unit *args: diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap deleted file mode 100644 index 3bfd9d8ad..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__tiny.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/plugins/install.rs -expression: "\"tiny\"" ---- -tiny diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap deleted file mode 100644 index faf1a84ac..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall-2.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/plugins/uninstall.rs -expression: output ---- - diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap deleted file mode 100644 index 502bbe446..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__uninstall__tests__plugin_uninstall.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/plugins/uninstall.rs -expression: output ---- -uninstalling plugin: tiny - diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap index efc8cd1d2..4e178bc4f 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap @@ -17,3 +17,5 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi +_rtx_hook + diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap index efc8cd1d2..4e178bc4f 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap @@ -17,3 +17,5 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi +_rtx_hook + diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 11aaf0900..7ba32ca2e 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -27,6 +27,8 @@ impl Shell for Bash { if ! [[ "${{PROMPT_COMMAND:-}}" =~ _rtx_hook ]]; then PROMPT_COMMAND="_rtx_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" fi + + _rtx_hook "#}); out diff --git a/src/shell/fish.rs b/src/shell/fish.rs index c163a94fb..bd1907586 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -45,6 +45,8 @@ impl Shell for Fish { functions --erase __rtx_cd_hook; end; + + __rtx_env_eval "#}); out diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 574b1dcff..7d4ed4894 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -14,3 +14,5 @@ if ! [[ "${PROMPT_COMMAND:-}" =~ _rtx_hook ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi +_rtx_hook + diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 1e36ca181..ac33a087f 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -27,3 +27,5 @@ function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx envi functions --erase __rtx_cd_hook; end; +__rtx_env_eval + diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 911bb10a5..5043d22aa 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -17,3 +17,5 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi +_rtx_hook + diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 996f99ebd..fe18cb0c4 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -34,6 +34,8 @@ impl Shell for Zsh { if [[ -z "${{chpwd_functions[(r)_rtx_hook]+1}}" ]]; then chpwd_functions=( _rtx_hook ${{chpwd_functions[@]}} ) fi + + _rtx_hook "#}); out From b0fec941c2c11c0cec131aa8f355a3de155083d4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 14:56:12 -0600 Subject: [PATCH 0292/1891] chore: updated deps --- Cargo.lock | 79 ++++++++++++++++++++++++++---------------------------- Cargo.toml | 2 +- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13518d097..20375e356 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" +checksum = "0012995dc3a54314f4710f5631d74767e73c534b8757221708303e48eef7a19b" dependencies = [ "clap", ] @@ -165,9 +165,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" dependencies = [ "os_str_bytes", ] @@ -837,9 +837,9 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", @@ -989,15 +989,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - [[package]] name = "num-integer" version = "0.1.45" @@ -1301,15 +1292,6 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "reqwest" version = "0.11.14" @@ -1499,9 +1481,9 @@ dependencies = [ [[package]] name = "self_update" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e18819cd93c4799f93cd4cf0ac069ed0e615fea3af28ec78df71e0ea890628a" +checksum = "ca4e4e6f29fddb78b3e7a6e5a395e8274d4aca2d36b2278a297fa49673a5b7c7" dependencies = [ "hyper", "indicatif", @@ -1512,6 +1494,7 @@ dependencies = [ "semver", "serde_json", "tempfile", + "urlencoding", ] [[package]] @@ -1614,7 +1597,7 @@ checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" dependencies = [ "log", "termcolor", - "time 0.3.19", + "time 0.3.20", ] [[package]] @@ -1644,9 +1627,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1655,16 +1638,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys 0.42.0", ] [[package]] @@ -1740,9 +1722,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa", "libc", @@ -1760,9 +1742,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" dependencies = [ "time-core", ] @@ -1846,15 +1828,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.3" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5" +checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" dependencies = [ "indexmap", - "nom8", "serde", "serde_spanned", "toml_datetime", + "winnow", ] [[package]] @@ -1949,6 +1931,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" + [[package]] name = "valuable" version = "0.1.0" @@ -2187,6 +2175,15 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "winnow" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" diff --git a/Cargo.toml b/Cargo.toml index cab867e98..9385dada6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ rayon = "1.6.1" regex = "1.7.1" reqwest = { version = "0.11.14", features = ["blocking"] } rmp-serde = "1.1.1" -self_update = { version = "0.35.0", optional = true } +self_update = { version = "0.36.0", optional = true } serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.92" From 70055064694a4b449a4ece5eb9f1553fb7135bb6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 14:57:27 -0600 Subject: [PATCH 0293/1891] test: added test for tool_version resolve failure --- completions/_rtx | 1 - src/toolset/tool_version_list.rs | 24 ++++++++++++++++++++++++ test/data/plugins/dummy/bin/list-all | 5 +++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/completions/_rtx b/completions/_rtx index d4c4c54d5..89ea493e0 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -409,7 +409,6 @@ _arguments "${_arguments_options[@]}" \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtime(s) to start:' \ -'*::command -- Command string to execute (same as --command):' \ && ret=0 ;; (global) diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 379b386c9..bb565a8b2 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -36,3 +36,27 @@ impl ToolVersionList { .collect() } } + +#[cfg(test)] +mod tests { + use crate::config::Settings; + use crate::plugins::{Plugin, PluginName}; + use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType}; + use std::env; + use std::sync::Arc; + + #[test] + fn test_tool_version_list_failure() { + env::set_var("RTX_FAILURE", "1"); + let mut tvl = ToolVersionList::new(ToolSource::Argument); + let plugin = Arc::new(Plugin::new(&PluginName::from("dummy"))); + plugin.clear_remote_version_cache().unwrap(); + tvl.add_version(ToolVersion::new( + plugin.name.to_string(), + ToolVersionType::Version("1.0.0".to_string()), + )); + tvl.resolve(&Settings::default(), plugin); + assert_eq!(tvl.resolved_versions().len(), 0); + env::remove_var("RTX_FAILURE"); + } +} diff --git a/test/data/plugins/dummy/bin/list-all b/test/data/plugins/dummy/bin/list-all index efec9526d..da61b95f9 100755 --- a/test/data/plugins/dummy/bin/list-all +++ b/test/data/plugins/dummy/bin/list-all @@ -4,3 +4,8 @@ versions_list=(1.0.0 1.1.0 2.0.0) echo "${versions_list[@]}" # Sending message to STD error to ensure that it is ignored echo "ignore this error" >&2 + +if [ "$RTX_FAILURE" = "1" ]; then + echo "error: RTX_FAILURE set" >&2 + exit 1 +fi From 0ba50e65c57b7f8bd270aff98432b1c9632a8b5d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 16:50:32 -0600 Subject: [PATCH 0294/1891] bug: reset PATH on `rtx deactivate` (#208) --- src/cli/deactivate.rs | 17 +++++++---------- src/cli/mod.rs | 1 + ..._cli__deactivate__tests__deactivate_zsh.snap | 3 ++- ...eactivate__tests__deactivate_zsh_legacy.snap | 3 ++- src/shell/bash.rs | 11 ++++++++++- src/shell/fish.rs | 11 ++++++++++- src/shell/mod.rs | 2 +- .../rtx__shell__bash__tests__deactivate.snap | 7 +++++++ .../rtx__shell__fish__tests__deactivate.snap | 9 +++++++++ ...__shell__xonsh__tests__xonsh_deactivate.snap | 3 ++- .../rtx__shell__zsh__tests__deactivate.snap | 7 +++++++ src/shell/xonsh.rs | 10 +++++++--- src/shell/zsh.rs | 11 ++++++++++- src/test.rs | 12 ++++++++++++ 14 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap create mode 100644 src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap create mode 100644 src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 7d33d65f6..392bd57b9 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -2,9 +2,11 @@ use color_eyre::eyre::Result; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; +use std::env::join_paths; use crate::cli::command::Command; use crate::config::Config; +use crate::env; use crate::output::Output; use crate::shell::{get_shell, ShellType}; @@ -28,8 +30,8 @@ impl Command for Deactivate { let shell = get_shell(self.shell_type.or(self.shell)) .expect("no shell provided, use `--shell=zsh`"); - // TODO: clear env using __RTX_DIFF - let output = shell.deactivate(); + let path = join_paths(&*env::PATH)?.to_string_lossy().to_string(); + let output = shell.deactivate(path); out.stdout.write(output); Ok(()) @@ -48,21 +50,16 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use insta::assert_display_snapshot; - use crate::assert_cli; + use crate::assert_cli_snapshot; #[test] fn test_deactivate_zsh() { - std::env::set_var("NO_COLOR", "1"); - let stdout = assert_cli!("deactivate", "zsh"); - assert_display_snapshot!(stdout); + assert_cli_snapshot!("deactivate", "zsh"); } #[test] fn test_deactivate_zsh_legacy() { - std::env::set_var("NO_COLOR", "1"); - let stdout = assert_cli!("deactivate", "-s", "zsh"); - assert_display_snapshot!(stdout); + assert_cli_snapshot!("deactivate", "-s", "zsh"); } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 76be0f7f0..797822828 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -242,6 +242,7 @@ pub mod tests { let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; let output = console::strip_ansi_codes(&output).to_string(); let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); + let output = $crate::test::replace_path(&output); insta::assert_snapshot!(output); }}; } diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap index 037f20fee..121c7d7e0 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap @@ -1,6 +1,7 @@ --- source: src/cli/deactivate.rs -expression: stdout +expression: output --- +export PATH="$PATH"; unset _rtx_hook; diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap index 037f20fee..121c7d7e0 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap @@ -1,6 +1,7 @@ --- source: src/cli/deactivate.rs -expression: stdout +expression: output --- +export PATH="$PATH"; unset _rtx_hook; diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 7ba32ca2e..b55f7c205 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -34,8 +34,9 @@ impl Shell for Bash { out } - fn deactivate(&self) -> String { + fn deactivate(&self, path: String) -> String { formatdoc! {r#" + export PATH="{path}"; unset _rtx_hook; "#} } @@ -56,6 +57,8 @@ impl Shell for Bash { #[cfg(test)] mod tests { use super::*; + use crate::test::replace_path; + use insta::assert_snapshot; #[test] fn test_hook_init() { @@ -73,4 +76,10 @@ mod tests { fn test_unset_env() { insta::assert_snapshot!(Bash::default().unset_env("FOO")); } + + #[test] + fn test_deactivate() { + let deactivate = Bash::default().deactivate("/some/path".into()); + assert_snapshot!(replace_path(&deactivate)); + } } diff --git a/src/shell/fish.rs b/src/shell/fish.rs index bd1907586..3d19001c2 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -52,8 +52,9 @@ impl Shell for Fish { out } - fn deactivate(&self) -> String { + fn deactivate(&self, path: String) -> String { formatdoc! {r#" + set -gx PATH "{path}"; functions --erase __rtx_env_eval; functions --erase __rtx_env_eval_2; functions --erase __rtx_cd_hook; @@ -76,6 +77,8 @@ impl Shell for Fish { #[cfg(test)] mod tests { use super::*; + use crate::test::replace_path; + use insta::assert_snapshot; #[test] fn test_hook_init() { @@ -93,4 +96,10 @@ mod tests { fn test_unset_env() { insta::assert_snapshot!(Fish::default().unset_env("FOO")); } + + #[test] + fn test_deactivate() { + let deactivate = Fish::default().deactivate("/some/path".into()); + assert_snapshot!(replace_path(&deactivate)); + } } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 803c0aaf3..a6bc44126 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -46,7 +46,7 @@ impl Display for ShellType { pub trait Shell { fn activate(&self, exe: &Path, status: bool) -> String; - fn deactivate(&self) -> String; + fn deactivate(&self, path: String) -> String; fn set_env(&self, k: &str, v: &str) -> String; fn unset_env(&self, k: &str) -> String; } diff --git a/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap new file mode 100644 index 000000000..ddb052d25 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap @@ -0,0 +1,7 @@ +--- +source: src/shell/bash.rs +expression: replace_path(&deactivate) +--- +export PATH="/some/path"; +unset _rtx_hook; + diff --git a/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap new file mode 100644 index 000000000..2cd7d51f0 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap @@ -0,0 +1,9 @@ +--- +source: src/shell/fish.rs +expression: replace_path(&deactivate) +--- +set -gx PATH "/some/path"; +functions --erase __rtx_env_eval; +functions --erase __rtx_env_eval_2; +functions --erase __rtx_cd_hook; + diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap index 7c9616d01..a8b8efc24 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap @@ -1,9 +1,10 @@ --- source: src/shell/xonsh.rs -expression: "Xonsh::default().deactivate()" +expression: replace_path(&deactivate) --- from xonsh.built_ins import XSH +environ['PATH'] = 'oldpath' hooks = { 'on_pre_prompt' : ['listen_prompt'], } diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap new file mode 100644 index 000000000..5253faf18 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap @@ -0,0 +1,7 @@ +--- +source: src/shell/zsh.rs +expression: replace_path(&deactivate) +--- +export PATH="foo"; +unset _rtx_hook; + diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 9bb857f85..da1e80418 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -74,10 +74,11 @@ impl Shell for Xonsh { out } - fn deactivate(&self) -> String { + fn deactivate(&self, path: String) -> String { formatdoc! {r#" from xonsh.built_ins import XSH + environ['PATH'] = '{path}' hooks = {{ 'on_pre_prompt' : ['listen_prompt'], }} @@ -89,7 +90,7 @@ impl Shell for Xonsh { if fn.__name__ == hook_fn: hndl.remove(fn) break - "#} + "#} } fn set_env(&self, k: &str, v: &str) -> String { @@ -126,6 +127,8 @@ impl Shell for Xonsh { #[cfg(test)] mod tests { use super::*; + use crate::test::replace_path; + use insta::assert_snapshot; #[test] fn test_hook_init() { @@ -154,6 +157,7 @@ mod tests { #[test] fn test_xonsh_deactivate() { - insta::assert_snapshot!(Xonsh::default().deactivate()); + let deactivate = Xonsh::default().deactivate("oldpath".into()); + assert_snapshot!(replace_path(&deactivate)); } } diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index fe18cb0c4..ce05914bb 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -41,8 +41,9 @@ impl Shell for Zsh { out } - fn deactivate(&self) -> String { + fn deactivate(&self, path: String) -> String { formatdoc! {r#" + export PATH="{path}"; unset _rtx_hook; "#} } @@ -59,6 +60,8 @@ impl Shell for Zsh { #[cfg(test)] mod tests { use super::*; + use crate::test::replace_path; + use insta::assert_snapshot; #[test] fn test_hook_init() { @@ -76,4 +79,10 @@ mod tests { fn test_unset_env() { insta::assert_snapshot!(Zsh::default().unset_env("FOO")); } + + #[test] + fn test_deactivate() { + let deactivate = Zsh::default().deactivate("foo".into()); + assert_snapshot!(replace_path(&deactivate)); + } } diff --git a/src/test.rs b/src/test.rs index fc9752fc1..6676bac67 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,3 +1,4 @@ +use std::env::join_paths; use std::fs; use indoc::indoc; @@ -29,3 +30,14 @@ pub fn reset_config() { ) .unwrap(); } + +pub fn replace_path(input: &str) -> String { + let path = join_paths(&*env::PATH) + .unwrap() + .to_string_lossy() + .to_string(); + let home = env::HOME.to_string_lossy().to_string(); + input + .replace(path.as_str(), "$PATH") + .replace(home.as_str(), "~") +} From a46bfb1063959785ea662942d142e7a3e4cb4fbe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Feb 2023 23:21:43 -0600 Subject: [PATCH 0295/1891] feat: added `rtx shell` (#209) Fixes #198 --- .config/nextest.toml | 2 +- README.md | 33 ++++--- completions/_rtx | 31 ++++++- completions/rtx.bash | 60 ++++++++++--- completions/rtx.fish | 65 +++++++------- e2e/cd/test_bash | 9 +- e2e/cd/test_fish | 11 ++- e2e/cd/test_zsh | 19 ++++ justfile | 2 + man/man1/rtx.1 | 3 + src/cli/activate.rs | 10 +-- src/cli/deactivate.rs | 58 ++++++------ src/cli/doctor.rs | 9 +- src/cli/hook_env.rs | 1 + src/cli/implode.rs | 3 +- src/cli/mod.rs | 3 + src/cli/plugins/update.rs | 1 - src/cli/shell.rs | 90 +++++++++++++++++++ ...x__cli__activate__tests__activate_zsh.snap | 19 ++++ ..._activate__tests__activate_zsh_legacy.snap | 19 ++++ ...rtx__cli__asdf__tests__fake_asdf_list.snap | 2 + ..._cli__deactivate__tests__deactivate-2.snap | 7 ++ ...x__cli__deactivate__tests__deactivate.snap | 7 ++ .../rtx__cli__shell__tests__shell-2.snap | 7 ++ .../rtx__cli__shell__tests__shell.snap | 7 ++ src/config/mod.rs | 4 + src/env.rs | 6 +- src/shell/bash.rs | 19 ++++ src/shell/fish.rs | 14 +++ src/shell/mod.rs | 2 +- .../rtx__shell__bash__tests__hook_init.snap | 19 ++++ .../rtx__shell__fish__tests__hook_init.snap | 14 +++ .../rtx__shell__zsh__tests__hook_init.snap | 19 ++++ src/shell/zsh.rs | 19 ++++ src/test.rs | 2 +- 35 files changed, 495 insertions(+), 101 deletions(-) create mode 100644 src/cli/shell.rs create mode 100644 src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap create mode 100644 src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap create mode 100644 src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap create mode 100644 src/cli/snapshots/rtx__cli__shell__tests__shell.snap diff --git a/.config/nextest.toml b/.config/nextest.toml index 8c6a0c3f2..75fb6962d 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,5 +1,5 @@ [profile.default] test-threads = 1 -slow-timeout = { period = "100ms", terminate-after = 2 } +slow-timeout = { period = "200ms", terminate-after = 2 } status-level = "all" retries = { backoff = "exponential", count = 4, delay = "1s", max-delay = "10s" } diff --git a/README.md b/README.md index a375307e8..9d6c386e8 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,7 @@ v18.10.9 * [rtx settings ls](#rtx-settings-ls) * [rtx settings set](#rtx-settings-set) * [rtx settings unset](#rtx-settings-unset) + * [rtx shell](#rtx-shell) * [rtx uninstall](#rtx-uninstall) * [rtx version](#rtx-version) * [rtx where](#rtx-where) @@ -855,18 +856,12 @@ Disable rtx for current shell session This can be used to temporarily disable rtx in a shell session. -Usage: deactivate [SHELL_TYPE] - -Arguments: - [SHELL_TYPE] - Shell type to generate the script for - - [possible values: bash, fish, xonsh, zsh] +Usage: deactivate Examples: - $ eval "$(rtx deactivate bash)" - $ eval "$(rtx deactivate zsh)" - $ rtx deactivate fish | source + $ rtx deactivate bash + $ rtx deactivate zsh + $ rtx deactivate fish $ execx($(rtx deactivate xonsh)) ``` ### `rtx direnv activate` @@ -1402,6 +1397,24 @@ Arguments: Examples: $ rtx settings unset legacy_version_file ``` +### `rtx shell` + +``` +sets a runtime for the current shell session + +Only works in a session where rtx is already activated. + +Usage: shell [RUNTIME]... + +Arguments: + [RUNTIME]... + Runtime version(s) to use + +Examples: + $ rtx shell nodejs@20 + $ node -v + v20.0.0 +``` ### `rtx uninstall` ``` diff --git a/completions/_rtx b/completions/_rtx index 89ea493e0..4e73a0da3 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -272,8 +272,6 @@ _arguments "${_arguments_options[@]}" \ ;; (deactivate) _arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ -'--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ @@ -281,7 +279,6 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::shell_type -- Shell type to generate the script for:(bash fish xonsh zsh)' \ && ret=0 ;; (direnv) @@ -799,6 +796,18 @@ esac ;; esac ;; +(shell) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::runtime -- Runtime version(s) to use:' \ +&& ret=0 +;; (uninstall) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ @@ -1082,6 +1091,10 @@ _arguments "${_arguments_options[@]}" \ ;; esac ;; +(shell) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (uninstall) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1147,6 +1160,7 @@ _rtx_commands() { 'p:Manage plugins' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ +'shell:sets a runtime for the current shell session' \ 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ @@ -1493,6 +1507,7 @@ _rtx__help_commands() { 'plugins:Manage plugins' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ +'shell:sets a runtime for the current shell session' \ 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ @@ -1799,6 +1814,16 @@ _rtx__settings_commands() { ) _describe -t commands 'rtx settings commands' commands "$@" } +(( $+functions[_rtx__help__shell_commands] )) || +_rtx__help__shell_commands() { + local commands; commands=() + _describe -t commands 'rtx help shell commands' commands "$@" +} +(( $+functions[_rtx__shell_commands] )) || +_rtx__shell_commands() { + local commands; commands=() + _describe -t commands 'rtx shell commands' commands "$@" +} (( $+functions[_rtx__help__plugins__uninstall_commands] )) || _rtx__help__plugins__uninstall_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 7882af64b..7a72cf24a 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -114,6 +114,9 @@ _rtx() { rtx,settings) cmd="rtx__settings" ;; + rtx,shell) + cmd="rtx__shell" + ;; rtx,uninstall) cmd="rtx__uninstall" ;; @@ -294,6 +297,9 @@ _rtx() { rtx__help,settings) cmd="rtx__help__settings" ;; + rtx__help,shell) + cmd="rtx__help__shell" + ;; rtx__help,uninstall) cmd="rtx__help__uninstall" ;; @@ -460,7 +466,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings shell uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -956,20 +962,12 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-s -j -v -h --shell --log-level --jobs --verbose --help bash fish xonsh zsh" + opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --shell) - COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1288,7 +1286,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings uninstall version where render-help help" + opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings shell uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1903,6 +1901,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__shell) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__uninstall) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2701,6 +2713,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__shell) + opts="-j -v -h --log-level --jobs --verbose --help [RUNTIME]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__uninstall) opts="-j -v -h --log-level --jobs --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index fb58a538d..ba2411082 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -27,6 +27,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "mangen" -d 'Generate man pages complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'sets a runtime for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' @@ -104,7 +105,6 @@ complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set th complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' @@ -282,6 +282,10 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' @@ -298,35 +302,36 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'sets a runtime for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 6eef90093..9cea166dc 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -8,8 +8,9 @@ orig_path="$PATH" eval "$(rtx activate bash --status)" assert_path() { - local expected="${1//$HOME/\~}:" + local expected="${1//$HOME/\~}" local actual="${PATH/%$orig_path/}" + actual="${actual/%:/}" actual="${actual//$HOME/\~}" if [[ "$actual" != "$expected" ]]; then echo "Invalid PATH: $actual" @@ -28,3 +29,9 @@ assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/ cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/jq/1.6/bin" + +rtx shell nodejs@16.0.0 && _rtx_hook +test "$(node -v)" = "v16.0.0" + +rtx deactivate +assert_path "" diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index 4177a0ec4..9023918cf 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -1,17 +1,22 @@ #!/usr/bin/env fish # shellcheck disable=SC1072,SC1065,SC1064,SC1073,SC2103 +set -l orig_node (node -v) #set -l fish_trace 1 rtx install nodejs@18.0.0 nodejs@16.0.0; or exit -rtx activate fish | source -#rtx i +rtx activate --status fish | source test (node -v) = "v18.0.0"; or exit cd 16 && __rtx_env_eval -#rtx i test (node -v) = "v16.0.0"; or exit cd .. && __rtx_env_eval test (node -v) = "v18.0.0"; or exit + +rtx shell nodejs@16.0.0 && __rtx_env_eval +test (node -v) = "v16.0.0"; or exit + +rtx deactivate +test (node -v) = $orig_node; or exit diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index 2508457b5..9ddb126c2 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -1,5 +1,18 @@ #!/usr/bin/env zsh set -euo pipefail +orig_path="$PATH" + +assert_path() { + local expected="${1//$HOME/\~}" + local actual="${PATH/%$orig_path/}" + actual="${actual//$HOME/\~}" + actual="${actual/%:/}" + if [[ "$actual" != "$expected" ]]; then + echo "Invalid PATH: $actual" + echo "Expected PATH: $expected" + exit 1 + fi +} rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 @@ -14,3 +27,9 @@ test "$(node -v)" = "v16.0.0" cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" + +rtx shell nodejs@16.0.0 && _rtx_hook +test "$(node -v)" = "v16.0.0" + +rtx deactivate +assert_path "" diff --git a/justfile b/justfile index 96e643dd6..fbba30464 100644 --- a/justfile +++ b/justfile @@ -45,6 +45,8 @@ test-coverage: RTX_SELF_UPDATE_VERSION=1.0.0 ./target/debug/rtx self-update <, - - /// Shell type to generate the script for - #[clap()] - shell_type: Option, -} +pub struct Deactivate {} impl Command for Deactivate { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let shell = get_shell(self.shell_type.or(self.shell)) - .expect("no shell provided, use `--shell=zsh`"); + fn run(self, config: Config, out: &mut Output) -> Result<()> { + if !config.is_activated() { + err_inactive()?; + } + + let shell = get_shell(None).expect("no shell detected"); let path = join_paths(&*env::PATH)?.to_string_lossy().to_string(); let output = shell.deactivate(path); @@ -38,28 +33,39 @@ impl Command for Deactivate { } } +fn err_inactive() -> Result<()> { + return Err(eyre!(formatdoc!( + r#" + rtx is not activated in this shell session. + Please run `{}` first in your shell rc file. + "#, + style("rtx activate").yellow() + ))); +} + static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ eval "$(rtx deactivate bash)" - $ eval "$(rtx deactivate zsh)" - $ rtx deactivate fish | source + $ rtx deactivate bash + $ rtx deactivate zsh + $ rtx deactivate fish $ execx($(rtx deactivate xonsh)) "#, style("Examples:").bold().underlined()} }); #[cfg(test)] mod tests { - - use crate::assert_cli_snapshot; - - #[test] - fn test_deactivate_zsh() { - assert_cli_snapshot!("deactivate", "zsh"); - } + use crate::{assert_cli_err, assert_cli_snapshot, env}; + use insta::assert_display_snapshot; #[test] - fn test_deactivate_zsh_legacy() { - assert_cli_snapshot!("deactivate", "-s", "zsh"); + fn test_deactivate() { + let err = assert_cli_err!("deactivate"); + assert_display_snapshot!(err); + env::set_var("__RTX_DIFF", ""); + env::set_var("RTX_SHELL", "zsh"); + assert_cli_snapshot!("deactivate"); + env::remove_var("__RTX_DIFF"); + env::remove_var("RTX_SHELL"); } } diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index ba45b547f..9987348a2 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -6,7 +6,7 @@ use once_cell::sync::Lazy; use crate::cli; use crate::cli::command::Command; use crate::config::Config; -use crate::env; + use crate::output::Output; /// Check rtx installation for possible problems. @@ -15,7 +15,7 @@ use crate::output::Output; pub struct Doctor {} impl Command for Doctor { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { let mut checks = Vec::new(); for plugin in config.plugins.values() { if !plugin.is_installed() { @@ -32,17 +32,20 @@ impl Command for Doctor { ) } - if env::var("__RTX_DIFF").is_err() { + if !config.is_activated() { checks.push( "rtx is not activated, run `rtx help activate` for setup instructions".to_string(), ); } + rtxprintln!(out, "{}", &config); + for check in &checks { error!("{}", check); } if checks.is_empty() { + rtxprintln!(out, "No problems found"); Ok(()) } else { Err(eyre!("{} problems found", checks.len())) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index b14992634..3d19d0e04 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -92,6 +92,7 @@ impl HookEnv { let installed_versions = ts .list_current_installed_versions() .into_iter() + .rev() .map(|v| v.to_string()) .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 22c6fc89b..98680bd75 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -48,7 +48,7 @@ impl Command for Implode { #[cfg(test)] mod tests { use crate::assert_cli; - use crate::{dirs, env}; + use crate::dirs; #[test] fn test_implode() { @@ -56,6 +56,5 @@ mod tests { assert!(stdout.contains(format!("rm -rf {}", dirs::ROOT.display()).as_str())); assert!(stdout.contains(format!("rm -rf {}", dirs::CACHE.display()).as_str())); assert!(stdout.contains(format!("rm -rf {}", dirs::CONFIG.display()).as_str())); - assert!(stdout.contains(format!("rm -f {}", env::RTX_EXE.display()).as_str())); } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 797822828..44c1c0525 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -35,6 +35,7 @@ mod ls_remote; mod plugins; mod self_update; mod settings; +mod shell; mod uninstall; pub mod version; mod r#where; @@ -78,6 +79,7 @@ pub enum Commands { Plugins(plugins::Plugins), SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), + Shell(shell::Shell), Uninstall(uninstall::Uninstall), Version(version::Version), Where(r#where::Where), @@ -114,6 +116,7 @@ impl Commands { Self::Plugins(cmd) => cmd.run(config, out), Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), + Self::Shell(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), Self::Version(cmd) => cmd.run(config, out), Self::Where(cmd) => cmd.run(config, out), diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 8244875da..25673c032 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -72,7 +72,6 @@ mod tests { ); let err = assert_cli_err!("p", "update"); assert_str_eq!(err.to_string(), "no plugins specified"); - assert_cli!("plugin", "update", "--all"); assert_cli!("plugins", "update", "tiny"); } } diff --git a/src/cli/shell.rs b/src/cli/shell.rs new file mode 100644 index 000000000..a6e431abb --- /dev/null +++ b/src/cli/shell.rs @@ -0,0 +1,90 @@ +use color_eyre::eyre::{eyre, Result}; + +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::command::Command; +use crate::config::Config; +use crate::dirs; + +use crate::file::touch_dir; + +use crate::output::Output; +use crate::shell::get_shell; +use crate::toolset::{ToolSource, ToolsetBuilder}; + +/// sets a runtime for the current shell session +/// +/// Only works in a session where rtx is already activated. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +pub struct Shell { + /// Runtime version(s) to use + #[clap(value_parser = RuntimeArgParser)] + runtime: Vec, +} + +impl Command for Shell { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new() + .with_install_missing() + .with_args(&self.runtime) + .build(&config); + + if !config.is_activated() { + err_inactive()?; + } + let shell = get_shell(None).expect("no shell detected"); + + for rtv in ts.list_current_installed_versions() { + let source = &ts.versions.get(&rtv.plugin.name).unwrap().source; + if matches!(source, ToolSource::Argument) { + let k = format!("RTX_{}_VERSION", rtv.plugin.name.to_uppercase()); + rtxprintln!(out, "{}", shell.set_env(&k, &rtv.version)); + } + } + touch_dir(&dirs::ROOT)?; + + Ok(()) + } +} + +fn err_inactive() -> Result<()> { + return Err(eyre!(formatdoc!( + r#" + rtx is not activated in this shell session. + Please run `{}` first in your shell rc file. + "#, + style("rtx activate").yellow() + ))); +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx shell nodejs@20 + $ node -v + v20.0.0 + "#, style("Examples:").bold().underlined()} +}); + +#[cfg(test)] +mod tests { + use insta::assert_display_snapshot; + use std::env; + + use crate::{assert_cli_err, assert_cli_snapshot}; + + #[test] + fn test_shell() { + let err = assert_cli_err!("shell", "tiny@1.0.1"); + assert_display_snapshot!(err); + env::set_var("__RTX_DIFF", ""); + env::set_var("RTX_SHELL", "zsh"); + assert_cli_snapshot!("shell", "tiny@1.0.1"); + env::remove_var("__RTX_DIFF"); + env::remove_var("RTX_SHELL"); + } +} diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap index 4e178bc4f..2d971a4a3 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap @@ -3,6 +3,25 @@ source: src/cli/activate.rs expression: output --- export PATH=":$PATH" +export RTX_SHELL=bash + +rtx() { + local command + command="${1:-}" + if [ "$#" -gt 0 ]; then + shift + fi + + case "$command" in + deactivate|shell) + eval "$(rtx "$command" "$@")" + ;; + *) + command rtx "$command" "$@" + ;; + esac +} + _rtx_hook() { trap -- '' SIGINT; eval "$("rtx" hook-env -s zsh)"; diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap index 4e178bc4f..2d971a4a3 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap @@ -3,6 +3,25 @@ source: src/cli/activate.rs expression: output --- export PATH=":$PATH" +export RTX_SHELL=bash + +rtx() { + local command + command="${1:-}" + if [ "$#" -gt 0 ]; then + shift + fi + + case "$command" in + deactivate|shell) + eval "$(rtx "$command" "$@")" + ;; + *) + command rtx "$command" "$@" + ;; + esac +} + _rtx_hook() { trap -- '' SIGINT; eval "$("rtx" hook-env -s zsh)"; diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap index 3985be099..75e9cc723 100644 --- a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap @@ -2,5 +2,7 @@ source: src/cli/asdf.rs expression: output --- +1.0.1 +2.1.0 3.1.0 diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap new file mode 100644 index 000000000..121c7d7e0 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/deactivate.rs +expression: output +--- +export PATH="$PATH"; +unset _rtx_hook; + diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap new file mode 100644 index 000000000..c249b2f10 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/deactivate.rs +expression: err +--- +rtx is not activated in this shell session. +Please run `rtx activate` first in your shell rc file. + diff --git a/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap b/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap new file mode 100644 index 000000000..07cec3054 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/shell.rs +expression: output +--- +export RTX_TINY_VERSION=1.0.1 + + diff --git a/src/cli/snapshots/rtx__cli__shell__tests__shell.snap b/src/cli/snapshots/rtx__cli__shell__tests__shell.snap new file mode 100644 index 000000000..4a623ea2a --- /dev/null +++ b/src/cli/snapshots/rtx__cli__shell__tests__shell.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/shell.rs +expression: err +--- +rtx is not activated in this shell session. +Please run `rtx activate` first in your shell rc file. + diff --git a/src/config/mod.rs b/src/config/mod.rs index e0d3c026d..16d33a3b9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -61,6 +61,10 @@ impl Config { self.shorthands .get_or_init(|| get_shorthands(&self.settings)) } + + pub fn is_activated(&self) -> bool { + env::var("__RTX_DIFF").is_ok() + } } fn load_rtxrc() -> Result { diff --git a/src/env.rs b/src/env.rs index 090502ac4..2e92a7190 100644 --- a/src/env.rs +++ b/src/env.rs @@ -62,7 +62,11 @@ lazy_static! { }; pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); - pub static ref RTX_EXE: PathBuf = current_exe().unwrap_or_else(|_| "rtx".into()); + pub static ref RTX_EXE: PathBuf = if cfg!(test) { + "rtx".into() + } else { + current_exe().unwrap_or_else(|_| "rtx".into()) + }; pub static ref RTX_LOG_LEVEL: log::LevelFilter = { let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); match log_level.parse::() { diff --git a/src/shell/bash.rs b/src/shell/bash.rs index b55f7c205..421460e0f 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -17,6 +17,25 @@ impl Shell for Bash { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" + export RTX_SHELL=bash + + rtx() {{ + local command + command="${{1:-}}" + if [ "$#" -gt 0 ]; then + shift + fi + + case "$command" in + deactivate|shell) + eval "$({exe} "$command" "$@")" + ;; + *) + command {exe} "$command" "$@" + ;; + esac + }} + _rtx_hook() {{ local previous_exit_status=$?; trap -- '' SIGINT; diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 3d19001c2..ddac808da 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -22,6 +22,20 @@ impl Shell for Fish { // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_fish.go#L14-L36 out.push_str(&formatdoc! {r#" + set -gx RTX_SHELL fish + + function rtx + set command $argv[1] + set -e argv[1] + + switch "$command" + case deactivate shell + source ({exe} "$command" $argv|psub) + case '*' + command {exe} "$command" $argv + end + end + function __rtx_env_eval --on-event fish_prompt --description {description}; {exe} hook-env{status} -s fish | source; diff --git a/src/shell/mod.rs b/src/shell/mod.rs index a6bc44126..921fd2a66 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -18,7 +18,7 @@ pub enum ShellType { impl ShellType { pub fn load() -> Option { - let shell = env::var("SHELL").ok()?; + let shell = env::var("RTX_SHELL").or(env::var("SHELL")).ok()?; if shell.ends_with("bash") { Some(ShellType::Bash) } else if shell.ends_with("fish") { diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 7d4ed4894..6ac5c2deb 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -3,6 +3,25 @@ source: src/shell/bash.rs expression: "bash.activate(exe, true)" --- export PATH="/some/dir:$PATH" +export RTX_SHELL=bash + +rtx() { + local command + command="${1:-}" + if [ "$#" -gt 0 ]; then + shift + fi + + case "$command" in + deactivate|shell) + eval "$(/some/dir/rtx "$command" "$@")" + ;; + *) + command /some/dir/rtx "$command" "$@" + ;; + esac +} + _rtx_hook() { local previous_exit_status=$?; trap -- '' SIGINT; diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index ac33a087f..ddf252446 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -3,6 +3,20 @@ source: src/shell/fish.rs expression: "fish.activate(exe, true)" --- fish_add_path -g /some/dir +set -gx RTX_SHELL fish + +function rtx + set command $argv[1] + set -e argv[1] + + switch "$command" + case deactivate shell + source (/some/dir/rtx "$command" $argv|psub) + case '*' + command /some/dir/rtx "$command" $argv + end +end + function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; /some/dir/rtx hook-env --status -s fish | source; diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 5043d22aa..aad47b9de 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -3,6 +3,25 @@ source: src/shell/zsh.rs expression: "zsh.activate(exe, true)" --- export PATH="/some/dir:$PATH" +export RTX_SHELL=bash + +rtx() { + local command + command="${1:-}" + if [ "$#" -gt 0 ]; then + shift + fi + + case "$command" in + deactivate|shell) + eval "$(/some/dir/rtx "$command" "$@")" + ;; + *) + command /some/dir/rtx "$command" "$@" + ;; + esac +} + _rtx_hook() { trap -- '' SIGINT; eval "$("/some/dir/rtx" hook-env --status -s zsh)"; diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index ce05914bb..4fc136fdf 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -21,6 +21,25 @@ impl Shell for Zsh { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" + export RTX_SHELL=bash + + rtx() {{ + local command + command="${{1:-}}" + if [ "$#" -gt 0 ]; then + shift + fi + + case "$command" in + deactivate|shell) + eval "$({exe} "$command" "$@")" + ;; + *) + command {exe} "$command" "$@" + ;; + esac + }} + _rtx_hook() {{ trap -- '' SIGINT; eval "$("{exe}" hook-env{status} -s zsh)"; diff --git a/src/test.rs b/src/test.rs index 6676bac67..7460cc053 100644 --- a/src/test.rs +++ b/src/test.rs @@ -10,7 +10,7 @@ fn init() { env::set_var("NO_COLOR", "1"); env_logger::init(); reset_config(); - assert_cli!("install", "tiny", "dummy"); + assert_cli!("install", "tiny@1", "tiny@2", "tiny@3", "tiny", "dummy"); } pub fn reset_config() { From 070d54d4498cf612ef4bf52f1f0b95d3766ac583 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 10:09:54 -0600 Subject: [PATCH 0296/1891] show warning message on `rtx install` if nothing to install --- src/cli/install.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cli/install.rs b/src/cli/install.rs index 9d5d6e9dc..a5f494d54 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -73,6 +73,11 @@ impl Install { ts.versions.remove(plugin); } } + if ts.versions.is_empty() { + warn!("no runtimes to install"); + warn!("specify a version with `rtx install @`"); + return Ok(()); + } for (plugin, versions) in &ts.versions { if plugins_to_install.contains(plugin) && self.force { for v in &versions.versions { From e110d1cb4df14bf46346987c7c8ddbd3572c10cf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:47:21 -0600 Subject: [PATCH 0297/1891] bug: fix multiline env vars (#212) Fixes #210 --- e2e/test_lua | 18 ++++ src/cli/install.rs | 6 ++ ..._cli__install__tests__install_nothing.snap | 5 ++ src/env_diff.rs | 90 ++++++++++++------- src/shell/bash.rs | 9 +- src/shell/fish.rs | 9 +- ...tx__env_diff__tests__from_bash_script.snap | 1 + test/fixtures/exec-env | 3 + 8 files changed, 100 insertions(+), 41 deletions(-) create mode 100755 e2e/test_lua create mode 100644 src/cli/snapshots/rtx__cli__install__tests__install_nothing.snap diff --git a/e2e/test_lua b/e2e/test_lua new file mode 100755 index 000000000..0e6d176fe --- /dev/null +++ b/e2e/test_lua @@ -0,0 +1,18 @@ +#!/usr/bin/env fish + +set -gx RTX_MISSING_RUNTIME_BEHAVIOR autoinstall + +rtx activate --status fish | source +rtx shell lua@5.4.3 + +set -l actual (__rtx_env_eval 2>&1 && lua -v 2>&1) +set -l expected "rtx lua@5.4.3 shellcheck@0.9.0 shfmt@3.6.0 jq@1.6 nodejs@18.0.0 Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio" + +if test "$actual" = "$expected" + echo "OK" +else + echo "FAIL" + echo "Expected: $expected" + echo "Actual: $actual" + exit 1 +end diff --git a/src/cli/install.rs b/src/cli/install.rs index a5f494d54..7204d0480 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -160,4 +160,10 @@ mod tests { ); assert_cli!("global", "--unset", "dummy"); } + + #[test] + fn test_install_nothing() { + // this doesn't do anything since dummy isn't specified + assert_cli_snapshot!("install", "dummy"); + } } diff --git a/src/cli/snapshots/rtx__cli__install__tests__install_nothing.snap b/src/cli/snapshots/rtx__cli__install__tests__install_nothing.snap new file mode 100644 index 000000000..3da804a28 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__install__tests__install_nothing.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/install.rs +expression: output +--- + diff --git a/src/env_diff.rs b/src/env_diff.rs index 4550900e7..399012f3c 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -71,49 +71,49 @@ impl EnvDiff { indoc::formatdoc! {" set -e . {script} - env + export -p ", script = script.display()} ) .full_env(&env) .read()?; let mut additions = HashMap::new(); + let mut cur_key = None; for line in out.lines() { - let (k, v) = line.split_once('=').unwrap_or_default(); - if k == "_" - || k == "SHLVL" - || k == "PATH" - || k == "PWD" - || k == "OLDPWD" - || k == "HOME" - || k == "USER" - || k == "SHELL" - || k == "SHELLOPTS" - || k == "COMP_WORDBREAKS" - || k == "PS1" - || k.is_empty() // this happens when exporting a function (export -f) - // TODO: consider removing this - // this is to make the ruby plugin compatible, - // it causes ruby to attempt to call asdf to reshim the binaries - // which we don't need or want to happen - || k == "RUBYLIB" - // following two ignores are for exported bash functions and exported bash - // functions which are multline, they appear in the environment as e.g.: - // BASH_FUNC_exported-bash-function%%=() { echo "this is an" - // echo "exported bash function" - // echo "with multiple lines" - // } - || k.starts_with("BASH_FUNC_") - || k.starts_with(' ') - { - continue; + match line.strip_prefix("declare -x ") { + Some(line) => { + let (k, v) = line.split_once('=').unwrap_or_default(); + if valid_key(k) { + continue; + } + cur_key = Some(k.to_string()); + additions.insert(k.to_string(), v.to_string()); + } + None => { + if let Some(k) = &cur_key { + let v = format!("\n{}", line); + additions.get_mut(k).unwrap().push_str(&v); + } + } } + } + for (k, v) in additions.clone().iter() { + let v = if v.starts_with('"') && v.ends_with('"') { + v[1..v.len() - 1].to_string() + } else if v.starts_with("$'") && v.ends_with('\'') { + v[2..v.len() - 1].to_string() + } else { + v.to_string() + }; + let v = v.replace("\\'", "'"); + let v = v.replace("\\n", "\n"); if let Some(orig) = env.get(k) { - if v == orig { + if &v == orig { + additions.remove(k); continue; } } - additions.insert(k.into(), v.into()); + additions.insert(k.into(), v); } Ok(Self::new(&env, additions)) } @@ -161,6 +161,34 @@ impl EnvDiff { } } +fn valid_key(k: &str) -> bool { + k.is_empty() + || k == "_" + || k == "SHLVL" + || k == "PATH" + || k == "PWD" + || k == "OLDPWD" + || k == "HOME" + || k == "USER" + || k == "SHELL" + || k == "SHELLOPTS" + || k == "COMP_WORDBREAKS" + || k == "PS1" + // TODO: consider removing this + // this is to make the ruby plugin compatible, + // it causes ruby to attempt to call asdf to reshim the binaries + // which we don't need or want to happen + || k == "RUBYLIB" + // following two ignores are for exported bash functions and exported bash + // functions which are multiline, they appear in the environment as e.g.: + // BASH_FUNC_exported-bash-function%%=() { echo "this is an" + // echo "exported bash function" + // echo "with multiple lines" + // } + || k.starts_with("BASH_FUNC_") + || k.starts_with(' ') +} + impl Debug for EnvDiff { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let print_sorted = |hashmap: &HashMap| { diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 421460e0f..5c851c96d 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -61,11 +61,10 @@ impl Shell for Bash { } fn set_env(&self, k: &str, v: &str) -> String { - format!( - "export {k}={v}\n", - k = shell_escape::unix::escape(k.into()), - v = shell_escape::unix::escape(v.into()) - ) + let k = shell_escape::unix::escape(k.into()); + let v = shell_escape::unix::escape(v.into()); + let v = v.replace("\\n", "\n"); + format!("export {k}={v}\n") } fn unset_env(&self, k: &str) -> String { diff --git a/src/shell/fish.rs b/src/shell/fish.rs index ddac808da..55a5e6f50 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -76,11 +76,10 @@ impl Shell for Fish { } fn set_env(&self, k: &str, v: &str) -> String { - format!( - "set -gx {k} {v}\n", - k = shell_escape::unix::escape(k.into()), - v = shell_escape::unix::escape(v.into()) - ) + let k = shell_escape::unix::escape(k.into()); + let v = shell_escape::unix::escape(v.into()); + let v = v.replace("\\n", "\n"); + format!("set -gx {k} {v}\n") } fn unset_env(&self, k: &str) -> String { diff --git a/src/snapshots/rtx__env_diff__tests__from_bash_script.snap b/src/snapshots/rtx__env_diff__tests__from_bash_script.snap index f30b59c0a..d528248e0 100644 --- a/src/snapshots/rtx__env_diff__tests__from_bash_script.snap +++ b/src/snapshots/rtx__env_diff__tests__from_bash_script.snap @@ -9,5 +9,6 @@ EnvDiff { new: [ "ADDED_VAR=added", "MODIFIED_VAR=modified", + "MULTILINE_VAR=line1\nline2\nline3", ], } diff --git a/test/fixtures/exec-env b/test/fixtures/exec-env index 4d81e926a..4645dc18c 100644 --- a/test/fixtures/exec-env +++ b/test/fixtures/exec-env @@ -3,3 +3,6 @@ export UNMODIFIED_VAR="unmodified" export MODIFIED_VAR="modified" export ADDED_VAR="added" +export MULTILINE_VAR="line1 +line2 +line3" From b39942e167a20a5192f1d834d658a2fe9a6cd48c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:57:47 -0600 Subject: [PATCH 0298/1891] ui: tiny tweak --- src/cli/self_update/other.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs index 1f5985c07..75dff6f9e 100644 --- a/src/cli/self_update/other.rs +++ b/src/cli/self_update/other.rs @@ -23,7 +23,7 @@ impl Command for SelfUpdate { } else { return Err(eyre!("Self-update is not supported")); }; - rtxprintln!(out, "running `{}`", style(&cmd).yellow()); + rtxprintln!(out, "Running `{}`", style(&cmd).yellow()); cmd!(&*env::SHELL, "-c", cmd).run()?; Ok(()) From 786f12244fd267bbf8e58b26fdfb6ea6027d576a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 14:38:28 -0600 Subject: [PATCH 0299/1891] ui: improve default error message --- src/main.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 278287717..08e0aeea6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,8 @@ extern crate core; #[macro_use] extern crate log; -use color_eyre::eyre::Result; +use color_eyre::eyre::{Result}; +use color_eyre::{SectionExt, Help}; use crate::cli::version::VERSION; use crate::cli::Cli; @@ -48,16 +49,12 @@ fn main() -> Result<()> { let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); - match run(&env::ARGS) { - Err(err) if log_level < log::LevelFilter::Debug => { - error!("{err}"); - // TODO: tell user they can use --log-level when it's implemented - error!("Run with RTX_DEBUG=1 for more information."); - error!("rtx {}", *VERSION); - std::process::exit(1); - } - result => result, + let mut result = run(&env::ARGS) + .with_section(|| VERSION.to_string().header("Version:")); + if log_level < log::LevelFilter::Debug { + result = result.with_suggestion(|| "Run with RTX_DEBUG=1 for more information.".to_string()) } + result } fn run(args: &Vec) -> Result<()> { From c307b8061a6c4226e46dad54f32b7e312a406dfc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 15:51:55 -0600 Subject: [PATCH 0300/1891] feat: experimental shims support (#213) --- README.md | 17 +++ completions/_rtx | 28 +++++ completions/rtx.bash | 50 +++++++- completions/rtx.fish | 66 +++++----- e2e/.gitignore | 1 + e2e/test_shims | 16 +++ man/man1/rtx.1 | 3 + src/cli/exec.rs | 6 +- src/cli/mod.rs | 5 +- src/cli/reshim.rs | 117 ++++++++++++++++++ src/cli/settings/set.rs | 2 + ...cli__settings__ls__tests__settings_ls.snap | 2 + ...i__settings__set__tests__settings_set.snap | 2 + src/cli/settings/unset.rs | 2 + ...li__deactivate__tests__deactivate_zsh.snap | 7 -- ...ctivate__tests__deactivate_zsh_legacy.snap | 7 -- src/cli/version.rs | 2 +- src/config/config_file/rtxrc.rs | 2 + src/config/settings.rs | 23 +++- src/env.rs | 1 + src/main.rs | 9 +- src/shims.rs | 25 ++++ src/test.rs | 2 + test/config/config.toml | 2 + 24 files changed, 340 insertions(+), 57 deletions(-) create mode 100755 e2e/test_shims create mode 100644 src/cli/reshim.rs delete mode 100644 src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap delete mode 100644 src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap create mode 100644 src/shims.rs diff --git a/README.md b/README.md index 9d6c386e8..0c11fe855 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ v18.10.9 * [rtx plugins ls-remote](#rtx-plugins-ls-remote) * [rtx plugins uninstall](#rtx-plugins-uninstall) * [rtx plugins update](#rtx-plugins-update) + * [rtx reshim](#rtx-reshim) * [rtx self-update](#rtx-self-update) * [rtx settings get](#rtx-settings-get) * [rtx settings ls](#rtx-settings-ls) @@ -1319,6 +1320,22 @@ Examples: $ rtx plugins update --all # update all plugins $ rtx plugins update nodejs # update only nodejs ``` +### `rtx reshim` + +``` +[experimental] rebuilds the shim farm + +this requires that the shim_dir is set + +Usage: reshim + +Examples: + $ rtx settings set experimental true + $ rtx settings set shim_dir ~/.rtx/shims + $ rtx reshim + $ ~/.rtx/shims/node -v + v20.0.0 +``` ### `rtx self-update` ``` diff --git a/completions/_rtx b/completions/_rtx index 4e73a0da3..089a067fe 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -678,6 +678,18 @@ esac ;; esac ;; +(reshim) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'::plugin:' \ +&& ret=0 +;; (self-update) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ @@ -1055,6 +1067,10 @@ _arguments "${_arguments_options[@]}" \ ;; esac ;; +(reshim) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (self-update) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1158,6 +1174,7 @@ _rtx_commands() { 'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ +'reshim:\[experimental\] rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:sets a runtime for the current shell session' \ @@ -1505,6 +1522,7 @@ _rtx__help_commands() { 'ls-remote:List runtime versions available for install' \ 'mangen:Generate man pages' \ 'plugins:Manage plugins' \ +'reshim:\[experimental\] rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:sets a runtime for the current shell session' \ @@ -1746,6 +1764,16 @@ _rtx__render-help_commands() { local commands; commands=() _describe -t commands 'rtx render-help commands' commands "$@" } +(( $+functions[_rtx__help__reshim_commands] )) || +_rtx__help__reshim_commands() { + local commands; commands=() + _describe -t commands 'rtx help reshim commands' commands "$@" +} +(( $+functions[_rtx__reshim_commands] )) || +_rtx__reshim_commands() { + local commands; commands=() + _describe -t commands 'rtx reshim commands' commands "$@" +} (( $+functions[_rtx__help__self-update_commands] )) || _rtx__help__self-update_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 7a72cf24a..adf479aaa 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -108,6 +108,9 @@ _rtx() { rtx,render-help) cmd="rtx__render__help" ;; + rtx,reshim) + cmd="rtx__reshim" + ;; rtx,self-update) cmd="rtx__self__update" ;; @@ -291,6 +294,9 @@ _rtx() { rtx__help,render-help) cmd="rtx__help__render__help" ;; + rtx__help,reshim) + cmd="rtx__help__reshim" + ;; rtx__help,self-update) cmd="rtx__help__self__update" ;; @@ -466,7 +472,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings shell uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1286,7 +1292,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins self-update settings shell uninstall version where render-help help" + opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1817,6 +1823,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__reshim) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__self__update) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2473,6 +2493,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__reshim) + opts="-j -v -h --log-level --jobs --verbose --help [PLUGIN]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__self__update) opts="-j -v -h --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index ba2411082..9144cd957 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -25,6 +25,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "mangen" -d 'Generate man pages' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] rebuilds the shim farm' complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'sets a runtime for the current shell session' @@ -248,6 +249,10 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' @@ -302,36 +307,37 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'sets a runtime for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'sets a runtime for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/e2e/.gitignore b/e2e/.gitignore index b92473d37..e23396803 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,4 +1,5 @@ .local .rtx .cache +.config Library diff --git a/e2e/test_shims b/e2e/test_shims new file mode 100755 index 000000000..973b1f45b --- /dev/null +++ b/e2e/test_shims @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +assert() { + local actual + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +rtx settings set experimental true +rtx settings set shims_dir "$RTX_DATA_DIR/shims" +rtx reshim +assert "$RTX_DATA_DIR/shims/node -v" "v18.0.0" diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 7f74fcfb6..4049a1f87 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -86,6 +86,9 @@ List runtime versions available for install rtx\-plugins(1) Manage plugins .TP +rtx\-reshim(1) +[experimental] rebuilds the shim farm +.TP rtx\-self\-update(1) Updates rtx itself .TP diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 6333dbbc4..64d116494 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -34,15 +34,15 @@ pub struct Exec { /// /// e.g.: nodejs@20 python@3.10 #[clap(value_parser = RuntimeArgParser)] - runtime: Vec, + pub runtime: Vec, /// Command string to execute (same as --command) #[clap(conflicts_with = "c", required_unless_present = "c", last = true)] - command: Option>, + pub command: Option>, /// Command string to execute #[clap(short, long = "command", conflicts_with = "command")] - c: Option, + pub c: Option, } impl Command for Exec { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 44c1c0525..d8f7dfdd1 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -22,7 +22,7 @@ mod deactivate; mod direnv; mod doctor; mod env; -mod exec; +pub mod exec; mod external; mod global; mod hook_env; @@ -33,6 +33,7 @@ mod local; mod ls; mod ls_remote; mod plugins; +mod reshim; mod self_update; mod settings; mod shell; @@ -77,6 +78,7 @@ pub enum Commands { #[cfg(feature = "clap_mangen")] Mangen(mangen::Mangen), Plugins(plugins::Plugins), + Reshim(reshim::Reshim), SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Shell(shell::Shell), @@ -114,6 +116,7 @@ impl Commands { #[cfg(feature = "clap_mangen")] Self::Mangen(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), + Self::Reshim(cmd) => cmd.run(config, out), Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Shell(cmd) => cmd.run(config, out), diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs new file mode 100644 index 000000000..cad5c77b8 --- /dev/null +++ b/src/cli/reshim.rs @@ -0,0 +1,117 @@ +use std::fs::create_dir_all; +use std::os::unix::fs; +use std::path::PathBuf; + +use color_eyre::eyre::{eyre, Result}; +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::dirs; +use crate::env::RTX_EXE; +use crate::output::Output; +use crate::toolset::ToolsetBuilder; + +/// [experimental] rebuilds the shim farm +/// +/// this requires that the shim_dir is set +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +pub struct Reshim { + #[clap(hide = true)] + pub plugin: Option, +} + +impl Command for Reshim { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().with_install_missing().build(&config); + + if !config.settings.experimental { + err_experimental()?; + } + let shims_dir = get_shims_dir(&config)?; + + for path in ts.list_paths() { + if !path.exists() { + continue; + } + for bin in path.read_dir()? { + let bin = bin?; + if !bin.file_type()?.is_file() && !bin.file_type()?.is_symlink() { + continue; + } + let bin_name = bin.file_name().into_string().unwrap(); + let symlink_path = shims_dir.join(bin_name); + if !symlink_path.exists() { + fs::symlink(&*RTX_EXE, &symlink_path)?; + debug!( + "symlinked {} to {}", + bin.path().display(), + symlink_path.display() + ); + } + } + } + + Ok(()) + } +} + +fn get_shims_dir(config: &Config) -> Result { + match config.settings.shims_dir.clone() { + Some(mut shims_dir) => { + if shims_dir.starts_with("~") { + shims_dir = dirs::HOME.join(shims_dir.strip_prefix("~")?); + } + create_dir_all(&shims_dir)?; + Ok(shims_dir) + } + None => err_no_shim_dir(), + } +} + +fn err_experimental() -> Result<()> { + return Err(eyre!(formatdoc!( + r#" + rtx is not configured to use experimental features. + Please set the `{}` setting to `true`. + "#, + style("experimental").yellow() + ))); +} + +fn err_no_shim_dir() -> Result { + return Err(eyre!(formatdoc!( + r#" + rtx is not configured to use shims. + Please set the `{}` setting to a directory. + "#, + style("shim_dir").yellow() + ))); +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx settings set experimental true + $ rtx settings set shim_dir ~/.rtx/shims + $ rtx reshim + $ ~/.rtx/shims/node -v + v20.0.0 + "#, style("Examples:").bold().underlined()} +}); + +#[cfg(test)] +mod tests { + + // #[test] + // fn test_reshim() { + // assert_cli!("local", "dummy@1.0.0"); + // assert_cli_snapshot!("reshim"); + // assert_cli_snapshot!("x", "--", "ls", "../data/shims"); + // assert_cli!("uninstall", "dummy@1.0.0"); + // assert_cli!("local", "--rm", "dummy@1.0.0"); + // } +} diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index b08be844d..26c503cb3 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -24,6 +24,7 @@ impl Command for SettingsSet { fn run(self, config: Config, _out: &mut Output) -> Result<()> { let rtxrc = config.rtxrc; let value: toml_edit::Value = match self.key.as_str() { + "experimental" => parse_bool(&self.value)?, "missing_runtime_behavior" => self.value.into(), "always_keep_download" => parse_bool(&self.value)?, "legacy_version_file" => parse_bool(&self.value)?, @@ -32,6 +33,7 @@ impl Command for SettingsSet { "jobs" => parse_i64(&self.value)?, "shorthands_file" => self.value.into(), "disable_default_shorthands" => parse_bool(&self.value)?, + "shims_dir" => self.value.into(), _ => return Err(eyre!("Unknown setting: {}", self.key)), }; diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 76318d293..86bb9b3b0 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -2,6 +2,7 @@ source: src/cli/settings/ls.rs expression: stdout --- +experimental = true missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = true @@ -11,4 +12,5 @@ asdf_compat = false jobs = 2 disable_default_shorthands = false log_level = INFO +shims_dir = ~/data/shims diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index cf1eb4db6..493846431 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -2,6 +2,7 @@ source: src/cli/settings/set.rs expression: stdout --- +experimental = true missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = false @@ -11,4 +12,5 @@ asdf_compat = false jobs = 2 disable_default_shorthands = false log_level = INFO +shims_dir = ~/data/shims diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index eb5eaca24..0b86bcf8a 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -48,6 +48,7 @@ mod tests { let stdout = assert_cli!("settings"); assert_snapshot!(stdout, @r###" + experimental = true missing_runtime_behavior = autoinstall always_keep_download = true legacy_version_file = true @@ -57,6 +58,7 @@ mod tests { jobs = 2 disable_default_shorthands = false log_level = INFO + shims_dir = ~/data/shims "###); reset_config(); diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap deleted file mode 100644 index 121c7d7e0..000000000 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/deactivate.rs -expression: output ---- -export PATH="$PATH"; -unset _rtx_hook; - diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap deleted file mode 100644 index 121c7d7e0..000000000 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate_zsh_legacy.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/deactivate.rs -expression: output ---- -export PATH="$PATH"; -unset _rtx_hook; - diff --git a/src/cli/version.rs b/src/cli/version.rs index 001032d93..64d339b5c 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -47,7 +47,7 @@ impl Command for Version { } pub fn print_version_if_requested(args: &[String], out: &mut Output) { - if args.len() == 2 { + if args.len() == 2 && args[0] == "rtx" || args[0].ends_with("/rtx") { let cmd = &args[1].to_lowercase(); if cmd == "version" || cmd == "-v" || cmd == "--version" { show_version(out); diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 910a55a46..5e40ab819 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -82,6 +82,7 @@ impl RTXFile { fn parse_toplevel_key(&mut self, k: &String, v: &Value) -> Result<()> { match k.to_lowercase().as_str() { "env" => self.parse_env(v).with_suggestion(|| ENV_SUGGESTION)?, + "experimental" => self.settings.experimental = Some(self.parse_bool(k, v)?), "missing_runtime_behavior" => { self.settings.missing_runtime_behavior = Some(self.parse_missing_runtime_behavior(v)?) @@ -103,6 +104,7 @@ impl RTXFile { self.settings.disable_default_shorthands = Some(self.parse_bool(k, v)?) } "log_level" => self.settings.log_level = Some(self.parse_log_level(v)?), + "shims_dir" => self.settings.shims_dir = Some(self.parse_path(k, v)?), "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} "disable_plugin_short_name_repository" => {} diff --git a/src/config/settings.rs b/src/config/settings.rs index 239f41ed0..56638c3c9 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -8,13 +8,14 @@ use log::LevelFilter; use crate::config::AliasMap; use crate::env; use crate::env::{ - RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_SHORTHANDS_FILE, - RTX_VERBOSE, + RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_SHIMS_DIR, + RTX_SHORTHANDS_FILE, RTX_VERBOSE, }; use crate::plugins::PluginName; #[derive(Debug, Clone)] pub struct Settings { + pub experimental: bool, pub missing_runtime_behavior: MissingRuntimeBehavior, pub always_keep_download: bool, pub legacy_version_file: bool, @@ -26,11 +27,13 @@ pub struct Settings { pub shorthands_file: Option, pub disable_default_shorthands: bool, pub log_level: LevelFilter, + pub shims_dir: Option, } impl Default for Settings { fn default() -> Self { Self { + experimental: false, missing_runtime_behavior: MissingRuntimeBehavior::Prompt, always_keep_download: false, legacy_version_file: true, @@ -42,6 +45,7 @@ impl Default for Settings { shorthands_file: RTX_SHORTHANDS_FILE.clone(), disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, log_level: *RTX_LOG_LEVEL, + shims_dir: RTX_SHIMS_DIR.clone(), } } } @@ -49,6 +53,7 @@ impl Default for Settings { impl Settings { pub fn to_index_map(&self) -> IndexMap { let mut map = IndexMap::new(); + map.insert("experimental".to_string(), self.experimental.to_string()); map.insert( "missing_runtime_behavior".to_string(), self.missing_runtime_behavior.to_string(), @@ -79,12 +84,16 @@ impl Settings { self.disable_default_shorthands.to_string(), ); map.insert("log_level".into(), self.log_level.to_string()); + if let Some(shims) = &self.shims_dir { + map.insert("shims_dir".into(), shims.to_string_lossy().to_string()); + } map } } #[derive(Debug, Default, Clone)] pub struct SettingsBuilder { + pub experimental: Option, pub missing_runtime_behavior: Option, pub always_keep_download: Option, pub legacy_version_file: Option, @@ -96,6 +105,7 @@ pub struct SettingsBuilder { pub shorthands_file: Option, pub disable_default_shorthands: Option, pub log_level: Option, + pub shims_dir: Option, } impl SettingsBuilder { @@ -106,6 +116,9 @@ impl SettingsBuilder { // } pub fn _merge(&mut self, other: Self) -> &mut Self { + if other.experimental.is_some() { + self.experimental = other.experimental; + } if other.missing_runtime_behavior.is_some() { self.missing_runtime_behavior = other.missing_runtime_behavior; } @@ -137,6 +150,9 @@ impl SettingsBuilder { if other.log_level.is_some() { self.log_level = other.log_level; } + if other.shims_dir.is_some() { + self.shims_dir = other.shims_dir; + } if other.aliases.is_some() { self.aliases = other.aliases; } @@ -145,6 +161,7 @@ impl SettingsBuilder { pub fn build(&self) -> Settings { let mut settings = Settings::default(); + settings.experimental = self.experimental.unwrap_or(settings.experimental); settings.missing_runtime_behavior = match env::RTX_MISSING_RUNTIME_BEHAVIOR .to_owned() .unwrap_or_default() @@ -175,6 +192,8 @@ impl SettingsBuilder { settings.disable_default_shorthands = self .disable_default_shorthands .unwrap_or(settings.disable_default_shorthands); + settings.log_level = self.log_level.unwrap_or(settings.log_level); + settings.shims_dir = self.shims_dir.clone().or(settings.shims_dir); settings.aliases = self.aliases.clone().unwrap_or(settings.aliases); settings diff --git a/src/env.rs b/src/env.rs index 2e92a7190..859e96162 100644 --- a/src/env.rs +++ b/src/env.rs @@ -125,6 +125,7 @@ lazy_static! { pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); pub static ref RTX_SHORTHANDS_FILE: Option = var_path("RTX_SHORTHANDS_FILE"); pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); + pub static ref RTX_SHIMS_DIR: Option = var_path("RTX_SHIMS_DIR"); pub static ref GITHUB_API_TOKEN: Option = var("GITHUB_API_TOKEN").ok(); } diff --git a/src/main.rs b/src/main.rs index 08e0aeea6..705d44906 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,8 +2,8 @@ extern crate core; #[macro_use] extern crate log; -use color_eyre::eyre::{Result}; -use color_eyre::{SectionExt, Help}; +use color_eyre::eyre::Result; +use color_eyre::{Help, SectionExt}; use crate::cli::version::VERSION; use crate::cli::Cli; @@ -34,6 +34,7 @@ mod logger; mod plugins; pub mod runtimes; mod shell; +mod shims; mod shorthands; mod ui; @@ -49,8 +50,7 @@ fn main() -> Result<()> { let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); - let mut result = run(&env::ARGS) - .with_section(|| VERSION.to_string().header("Version:")); + let mut result = run(&env::ARGS).with_section(|| VERSION.to_string().header("Version:")); if log_level < log::LevelFilter::Debug { result = result.with_suggestion(|| "Run with RTX_DEBUG=1 for more information.".to_string()) } @@ -64,6 +64,7 @@ fn run(args: &Vec) -> Result<()> { cli::version::print_version_if_requested(&env::ARGS, out); let config = Config::load()?; + let config = shims::handle_shim(config, args, out)?; if hook_env::should_exit_early(&config) { return Ok(()); } diff --git a/src/shims.rs b/src/shims.rs new file mode 100644 index 000000000..4ca577e52 --- /dev/null +++ b/src/shims.rs @@ -0,0 +1,25 @@ +use crate::cli::command::Command; +use crate::cli::exec::Exec; +use color_eyre::eyre::Result; +use std::ffi::OsString; +use std::process::exit; + +use crate::config::Config; +use crate::output::Output; + +// executes as if it was a shim if the command is not "rtx", e.g.: "node" +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" || !config.settings.experimental { + return Ok(config); + } + let mut args: Vec = args.iter().map(OsString::from).collect(); + args[0] = OsString::from(bin_name); + let exec = Exec { + runtime: vec![], + c: None, + command: Some(args), + }; + exec.run(config, out)?; + exit(0); +} diff --git a/src/test.rs b/src/test.rs index 7460cc053..b8e514aa8 100644 --- a/src/test.rs +++ b/src/test.rs @@ -17,12 +17,14 @@ pub fn reset_config() { fs::write( env::HOME.join("config/config.toml"), indoc! {r#" + experimental = true verbose = true missing_runtime_behavior= 'autoinstall' always_keep_download= true legacy_version_file= true plugin_autoupdate_last_check_duration = 20 jobs = 2 + shims_dir = '~/data/shims' [alias.tiny] "my/alias" = '3.0' diff --git a/test/config/config.toml b/test/config/config.toml index 8d9a78bf8..92038cd17 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -1,9 +1,11 @@ +experimental = true verbose = true missing_runtime_behavior= 'autoinstall' always_keep_download= true legacy_version_file= true plugin_autoupdate_last_check_duration = 20 jobs = 2 +shims_dir = '~/data/shims' [alias.tiny] "my/alias" = '3.0' From e1c3f34c13e7410325342def3144d1307bf439de Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 15:53:03 -0600 Subject: [PATCH 0301/1891] chore: added release task --- justfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/justfile b/justfile index fbba30464..a3988d1ef 100644 --- a/justfile +++ b/justfile @@ -93,3 +93,6 @@ pre-commit: lint render-help render-completions render-mangen git add README.md git add completions git add man + +release *args: + cargo release {{ args }} From 3c979d9564147bb0ef3d7748daa32f2899542ca6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 15:53:42 -0600 Subject: [PATCH 0302/1891] chore: Release rtx-cli version 1.18.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- src/default_shorthands.rs | 6 +++++- 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20375e356..070bcc085 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1359,7 +1359,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.17.0" +version = "1.18.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 9385dada6..e76fa07e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.17.0" +version = "1.18.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0c11fe855..6f13f875c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.17.0 +rtx 1.18.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -305,7 +305,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.17.0/rtx-v1.17.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.0/rtx-v1.18.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 4049a1f87..980b0a5b3 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.17.0" +.TH rtx 1 "rtx 1.18.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -123,6 +123,6 @@ Print this message or the help of the given subcommand(s) rtx x nodejs@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.17.0 +v1.18.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b9676c1ef..b7b3a477d 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.17.0 +Version: 1.18.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e08fdd755..56f9e962d 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -232,7 +232,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.17.0/rtx-v1.17.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.0/rtx-v1.18.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index cd2023b88..5a02b8bd0 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 608] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 612] = [ // rtx custom aliases ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), @@ -29,6 +29,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 608] = [ ("alp", "https://github.com/asdf-community/asdf-alp.git"), ("amass", "https://github.com/dhoeric/asdf-amass.git"), ("amazon-ecr-credential-helper", "https://github.com/dex4er/asdf-amazon-ecr-credential-helper.git"), + ("ambient", "https://github.com/jtakakura/asdf-ambient.git"), ("ansible-base", "https://github.com/amrox/asdf-pyapp.git"), ("ant", "https://github.com/jackboespflug/asdf-ant.git"), ("apollo-router", "https://github.com/safx/asdf-apollo-router.git"), @@ -39,6 +40,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 608] = [ ("aria2", "https://github.com/asdf-community/asdf-aria2.git"), ("asciidoctorj", "https://github.com/gliwka/asdf-asciidoctorj.git"), ("assh", "https://github.com/zekker6/asdf-assh.git"), + ("aws-amplify-cli", "https://github.com/LozanoMatheus/asdf-aws-amplify-cli.git"), ("aws-copilot", "https://github.com/NeoHsu/asdf-copilot"), ("aws-iam-authenticator", "https://github.com/zekker6/asdf-aws-iam-authenticator"), ("aws-nuke", "https://github.com/bersalazar/asdf-aws-nuke.git"), @@ -450,6 +452,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 608] = [ ("protoc-gen-grpc-web", "https://github.com/pbr0ck3r/asdf-protoc-gen-grpc-web.git"), ("protoc-gen-js", "https://github.com/pbr0ck3r/asdf-protoc-gen-js.git"), ("protolint", "https://github.com/spencergilbert/asdf-protolint.git"), + ("protonge", "https://github.com/augustobmoura/asdf-protonge.git"), ("pulumi", "https://github.com/canha/asdf-pulumi.git"), ("purerl", "https://github.com/GoNZooo/asdf-purerl.git"), ("purescript", "https://github.com/nsaunders/asdf-purescript.git"), @@ -600,6 +603,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 608] = [ ("websocat", "https://github.com/bdellegrazie/asdf-websocat.git"), ("wren-cli", "https://github.com/jtakakura/asdf-wren-cli.git"), ("wtfutil", "https://github.com/NeoHsu/asdf-wtfutil.git"), + ("xc", "https://github.com/airtonix/asdf-xc"), ("xchtmlreport", "https://github.com/younke/asdf-xchtmlreport.git"), ("xcodegen", "https://github.com/younke/asdf-xcodegen.git"), ("xcodes", "https://github.com/younke/asdf-xcodes.git"), From d451c850be953ad6848e6b22f5ff69b6be5bbe79 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 16:23:52 -0600 Subject: [PATCH 0303/1891] bug: do not use RTX_EXE in fake-asdf (#215) --- src/fake_asdf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index b9f7957df..8068a9546 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -16,10 +16,10 @@ fn setup() -> color_eyre::Result { fs::create_dir_all(&path)?; fs::write( &asdf_bin, + // rtx="${{RTX_EXE:-rtx}}" formatdoc! {r#" #!/bin/sh - rtx="${{RTX_EXE:-rtx}}" - "$rtx" asdf "$@" + rtx asdf "$@" "#}, )?; let mut perms = asdf_bin.metadata()?.permissions(); From 2cd554d15669abb6a01548cd0d5e03e1356b48ff Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 18:30:49 -0600 Subject: [PATCH 0304/1891] bug: show cursor on ctrl-c (#217) --- Cargo.lock | 29 +++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 11 +++++++++++ 3 files changed, 41 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 070bcc085..805022a3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,6 +310,16 @@ dependencies = [ "syn", ] +[[package]] +name = "ctrlc" +version = "3.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639" +dependencies = [ + "nix", + "windows-sys 0.45.0", +] + [[package]] name = "cxx" version = "1.0.91" @@ -979,6 +989,18 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "static_assertions", +] + [[package]] name = "nom" version = "7.1.3" @@ -1370,6 +1392,7 @@ dependencies = [ "color-eyre", "console", "ctor", + "ctrlc", "dialoguer", "dirs-next", "duct", @@ -1619,6 +1642,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" diff --git a/Cargo.toml b/Cargo.toml index e76fa07e9..fc877f61d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" console = "0.15.5" ctor = "0.1.26" +ctrlc = "3.2.5" dialoguer = { version = "0.10.3", features = [] } dirs-next = "2.0.0" duct = "0.13.6" diff --git a/src/main.rs b/src/main.rs index 705d44906..ce9aba0d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate log; use color_eyre::eyre::Result; use color_eyre::{Help, SectionExt}; +use console::Term; use crate::cli::version::VERSION; use crate::cli::Cli; @@ -49,6 +50,7 @@ fn main() -> Result<()> { color_eyre::install()?; let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); + handle_ctrlc(); let mut result = run(&env::ARGS).with_section(|| VERSION.to_string().header("Version:")); if log_level < log::LevelFilter::Debug { @@ -71,3 +73,12 @@ fn run(args: &Vec) -> Result<()> { let cli = Cli::new_with_external_commands(&config)?; cli.run(config, args, out) } + +fn handle_ctrlc() { + ctrlc::set_handler(move || { + let _ = Term::stderr().show_cursor(); + debug!("Ctrl-C pressed, exiting..."); + std::process::exit(1); + }) + .expect("Error setting Ctrl-C handler"); +} From 0895c3a0dec8e8b27d6c0d5ab1239d6d56d4401d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 18:41:11 -0600 Subject: [PATCH 0305/1891] docs: reference node-18 not node-20 (#219) node-20 will not be out for a few months. Fixes #218 --- README.md | 86 +++++++++++++++++++------------------- man/man1/rtx.1 | 12 +++--- src/cli/args/runtime.rs | 6 +-- src/cli/exec.rs | 10 ++--- src/cli/global.rs | 20 ++++----- src/cli/install.rs | 2 +- src/cli/local.rs | 24 +++++------ src/cli/ls.rs | 4 +- src/cli/mod.rs | 12 +++--- src/cli/render_help.rs | 18 ++++---- src/cli/shell.rs | 2 +- src/cli/where.rs | 6 +-- src/toolset/tool_source.rs | 4 +- test/fixtures/.rtxrc.toml | 2 +- 14 files changed, 104 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index 6f13f875c..a585e083d 100644 --- a/README.md +++ b/README.md @@ -206,16 +206,16 @@ rtx does not directly install runtimes. Instead, it uses asdf plugins to install ### Common example commands - rtx install nodejs@20.0.0 Install a specific version number - rtx install nodejs@20.0 Install a fuzzy version number - rtx local nodejs@20 Use node-20.x in current project - rtx global nodejs@20 Use node-20.x as default + rtx install nodejs@18.0.0 Install a specific version number + rtx install nodejs@18.0 Install a fuzzy version number + rtx local nodejs@18 Use node-18.x in current project + rtx global nodejs@18 Use node-18.x as default rtx install nodejs Install the version specified in .tool-versions rtx local nodejs@latest Use latest node in current directory rtx global nodejs@system Use system node as default - rtx x nodejs@20 -- node app.js Run `node app.js` with the PATH pointing to node-20.x + rtx x nodejs@18 -- node app.js Run `node app.js` with the PATH pointing to node-18.x ## Installation @@ -424,7 +424,7 @@ The `.tool-versions` file is used to specify the runtime versions for a project. is: ``` -nodejs 20.0.0 # comments are allowed +nodejs 18.0.0 # comments are allowed ruby 3 # can be fuzzy version shellcheck latest # also supports "latest" jq 1.6 @@ -512,8 +512,8 @@ rtx can also be configured via environment variables. The following options are This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. ```sh-session -$ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@20 -$ RTX_NODEJS_VERSION=20 rtx exec -- node --version +$ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@18 +$ RTX_NODEJS_VERSION=18 rtx exec -- node --version ``` #### `RTX_DATA_DIR` @@ -535,7 +535,7 @@ Set to something other than ".tool-versions" to have rtx look for configuration #### `RTX_${PLUGIN}_VERSION` -Set the version for a runtime. For example, `RTX_NODEJS_VERSION=20` will use nodejs@20.x regardless +Set the version for a runtime. For example, `RTX_NODEJS_VERSION=18` will use nodejs@18.x regardless of what is set in `.tool-versions`. #### `RTX_LEGACY_VERSION_FILE` @@ -933,7 +933,7 @@ set. Runtimes will be loaded from .tool-versions, though they can be overridden with args Note that only the plugin specified will be overridden, so if a `.tool-versions` file -includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. +includes "nodejs 18" but you run `rtx exec python@3.11`; it will still load nodejs@18. The "--" separates runtimes from the commands to pass along to the subprocess. @@ -943,7 +943,7 @@ Arguments: [RUNTIME]... Runtime(s) to start - e.g.: nodejs@20 python@3.10 + e.g.: nodejs@18 python@3.10 [COMMAND]... Command string to execute (same as --command) @@ -953,11 +953,11 @@ Options: Command string to execute Examples: - rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x - rtx x nodejs@20 -- node ./app.js # shorter alias + rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x + rtx x nodejs@18 -- node ./app.js # shorter alias # Specify command as a string: - rtx exec nodejs@20 python@3.11 --command "node -v && python -V" + rtx exec nodejs@18 python@3.11 --command "node -v && python -V" ``` ### `rtx global` @@ -974,7 +974,7 @@ Arguments: [RUNTIME]... Runtime(s) to add to .tool-versions - e.g.: nodejs@20 + e.g.: nodejs@18 If this is a single runtime with no version, the current value of the global .tool-versions will be displayed @@ -982,28 +982,28 @@ Options: --pin Save exact version to `~/.tool-versions` - e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions + e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions --fuzzy Save fuzzy version to `~/.tool-versions` - e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 + e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove Remove the plugin(s) from ~/.tool-versions Examples: - # set the current version of nodejs to 20.x - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global nodejs@20 + # set the current version of nodejs to 18.x + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx global --fuzzy nodejs@18 - # set the current version of nodejs to 20.x - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx global --fuzzy nodejs@20 + # set the current version of nodejs to 18.x + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx global --pin nodejs@18 # show the current version of nodejs in ~/.tool-versions $ rtx global nodejs - 20.0.0 + 18.0.0 ``` ### `rtx implode` @@ -1039,7 +1039,7 @@ Arguments: [RUNTIME]... Runtime(s) to install - e.g.: nodejs@20 + e.g.: nodejs@18 Options: -p, --plugin @@ -1091,7 +1091,7 @@ Arguments: [RUNTIME]... Runtimes to add to .tool-versions - e.g.: nodejs@20 + e.g.: nodejs@18 if this is a single runtime with no version, the current value of .tool-versions will be displayed @@ -1103,34 +1103,34 @@ Options: --pin Save exact version to `.tool-versions` - e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions + e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions --fuzzy Save fuzzy version to `.tool-versions` - e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 + e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove Remove the plugin(s) from .tool-versions Examples: - # set the current version of nodejs to 20.x for the current directory - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx local nodejs@20 + # set the current version of nodejs to 18.x for the current directory + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx local nodejs@18 - # set nodejs to 20.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@20 + # set nodejs to 18.x for the current project (recurses up to find .tool-versions) + $ rtx local -p nodejs@18 - # set the current version of nodejs to 20.x for the current directory - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx local --fuzzy nodejs@20 + # set the current version of nodejs to 18.x for the current directory + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx local --fuzzy nodejs@18 # removes nodejs from .tool-versions $ rtx local --remove=nodejs # show the current version of nodejs in .tool-versions $ rtx local nodejs - 20.0.0 + 18.0.0 ``` ### `rtx ls` @@ -1151,12 +1151,12 @@ Options: Examples: $ rtx list - -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) python 3.10.0 $ rtx list --current - -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) ``` ### `rtx ls-remote` @@ -1428,7 +1428,7 @@ Arguments: Runtime version(s) to use Examples: - $ rtx shell nodejs@20 + $ rtx shell nodejs@18 $ node -v v20.0.0 ``` @@ -1470,13 +1470,13 @@ Arguments: Examples: # Show the latest installed version of nodejs # If it is is not installed, errors - $ rtx where nodejs@20 - /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + $ rtx where nodejs@18 + /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 # Show the current, active install directory of nodejs # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs - /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 ``` ## Comparison to asdf diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 980b0a5b3..5003c7379 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -111,17 +111,17 @@ rtx\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA Examples: - rtx install nodejs@20.0.0 Install a specific node version - rtx install nodejs@20.0 Install a version matching a prefix - rtx local nodejs@20 Use node\-20.x in current project - rtx global nodejs@20 Use node\-20.x as default + rtx install nodejs@18.0.0 Install a specific node version + rtx install nodejs@18.0 Install a version matching a prefix + rtx local nodejs@18 Use node\-18.x in current project + rtx global nodejs@18 Use node\-18.x as default rtx install nodejs Install the .tool\-versions node version rtx local nodejs Use latest node in current directory rtx global system Use system node everywhere unless overridden - rtx x nodejs@20 \-\- node app.js Run `node app.js` with PATH pointing to - node\-20.x + rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to + node\-18.x .SH VERSION v1.18.0 .SH AUTHORS diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index 80c3db873..a2eb8f25e 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -21,7 +21,7 @@ pub enum RuntimeArgVersion { /// Nothing was specified, e.g.: `nodejs` None, /// references a version, version prefix, or alias - /// e.g.: `nodejs@20`, `nodejs@latest`, `nodejs@lts` + /// e.g.: `nodejs@18`, `nodejs@latest`, `nodejs@lts` Version(String), /// use the system runtime already on PATH /// e.g.: `nodejs@system` @@ -66,9 +66,9 @@ impl RuntimeArg { } /// this handles the case where the user typed in: - /// rtx local nodejs 20.0.0 + /// rtx local nodejs 18.0.0 /// instead of - /// rtx local nodejs@20.0.0 + /// rtx local nodejs@18.0.0 /// /// We can detect this, and we know what they meant, so make it work the way /// they expected. diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 64d116494..ff59f63b8 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -24,7 +24,7 @@ use crate::toolset::ToolsetBuilder; /// /// Runtimes will be loaded from .tool-versions, though they can be overridden with args /// Note that only the plugin specified will be overridden, so if a `.tool-versions` file -/// includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. +/// includes "nodejs 18" but you run `rtx exec python@3.11`; it will still load nodejs@18. /// /// The "--" separates runtimes from the commands to pass along to the subprocess. #[derive(Debug, clap::Args)] @@ -32,7 +32,7 @@ use crate::toolset::ToolsetBuilder; pub struct Exec { /// Runtime(s) to start /// - /// e.g.: nodejs@20 python@3.10 + /// e.g.: nodejs@18 python@3.10 #[clap(value_parser = RuntimeArgParser)] pub runtime: Vec, @@ -114,11 +114,11 @@ fn parse_command( static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x - rtx x nodejs@20 -- node ./app.js # shorter alias + rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x + rtx x nodejs@18 -- node ./app.js # shorter alias # Specify command as a string: - rtx exec nodejs@20 python@3.11 --command "node -v && python -V" + rtx exec nodejs@18 python@3.11 --command "node -v && python -V" "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/global.rs b/src/cli/global.rs index 057403c54..c07fc6cb1 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -20,7 +20,7 @@ use crate::{dirs, env}; pub struct Global { /// Runtime(s) to add to .tool-versions /// - /// e.g.: nodejs@20 + /// e.g.: nodejs@18 /// If this is a single runtime with no version, the current value of the global /// .tool-versions will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] @@ -28,13 +28,13 @@ pub struct Global { /// Save exact version to `~/.tool-versions` /// - /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions + /// e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `~/.tool-versions` /// - /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions + /// e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, @@ -80,17 +80,17 @@ impl Command for Global { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - # set the current version of nodejs to 20.x - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global nodejs@20 + # set the current version of nodejs to 18.x + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx global --fuzzy nodejs@18 - # set the current version of nodejs to 20.x - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx global --fuzzy nodejs@20 + # set the current version of nodejs to 18.x + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx global --pin nodejs@18 # show the current version of nodejs in ~/.tool-versions $ rtx global nodejs - 20.0.0 + 18.0.0 "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/install.rs b/src/cli/install.rs index 7204d0480..6064b6c4d 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -27,7 +27,7 @@ use crate::toolset::ToolsetBuilder; pub struct Install { /// Runtime(s) to install /// - /// e.g.: nodejs@20 + /// e.g.: nodejs@18 #[clap(value_parser = RuntimeArgParser)] runtime: Option>, diff --git a/src/cli/local.rs b/src/cli/local.rs index d5c35bd48..27dfa1f71 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -20,7 +20,7 @@ use crate::{dirs, env, file}; pub struct Local { /// Runtimes to add to .tool-versions /// - /// e.g.: nodejs@20 + /// e.g.: nodejs@18 /// if this is a single runtime with no version, /// the current value of .tool-versions will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] @@ -33,13 +33,13 @@ pub struct Local { /// Save exact version to `.tool-versions` /// - /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions + /// e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `.tool-versions` /// - /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions + /// e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, @@ -98,23 +98,23 @@ impl Command for Local { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - # set the current version of nodejs to 20.x for the current directory - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx local nodejs@20 + # set the current version of nodejs to 18.x for the current directory + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx local nodejs@18 - # set nodejs to 20.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@20 + # set nodejs to 18.x for the current project (recurses up to find .tool-versions) + $ rtx local -p nodejs@18 - # set the current version of nodejs to 20.x for the current directory - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx local --fuzzy nodejs@20 + # set the current version of nodejs to 18.x for the current directory + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx local --fuzzy nodejs@18 # removes nodejs from .tool-versions $ rtx local --remove=nodejs # show the current version of nodejs in .tool-versions $ rtx local nodejs - 20.0.0 + 18.0.0 "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index e059ac8ee..77a222013 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -147,12 +147,12 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx list - -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) python 3.10.0 $ rtx list --current - -> nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) -> python 3.11.0 (set by ~/.tool-versions) "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index d8f7dfdd1..c8aac4dfd 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -204,17 +204,17 @@ https://asdf-vm.com/"}; static AFTER_HELP: Lazy = Lazy::new(|| { formatdoc! { " {} - rtx install nodejs@20.0.0 Install a specific node version - rtx install nodejs@20.0 Install a version matching a prefix - rtx local nodejs@20 Use node-20.x in current project - rtx global nodejs@20 Use node-20.x as default + rtx install nodejs@18.0.0 Install a specific node version + rtx install nodejs@18.0 Install a version matching a prefix + rtx local nodejs@18 Use node-18.x in current project + rtx global nodejs@18 Use node-18.x as default rtx install nodejs Install the .tool-versions node version rtx local nodejs Use latest node in current directory rtx global system Use system node everywhere unless overridden - rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to - node-20.x + rtx x nodejs@18 -- node app.js Run `node app.js` with PATH pointing to + node-18.x ", style("Examples:").bold().underlined() } }); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 56f9e962d..e8c6e8188 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -133,16 +133,16 @@ rtx does not directly install runtimes. Instead, it uses asdf plugins to install ### Common example commands - rtx install nodejs@20.0.0 Install a specific version number - rtx install nodejs@20.0 Install a fuzzy version number - rtx local nodejs@20 Use node-20.x in current project - rtx global nodejs@20 Use node-20.x as default + rtx install nodejs@18.0.0 Install a specific version number + rtx install nodejs@18.0 Install a fuzzy version number + rtx local nodejs@18 Use node-18.x in current project + rtx global nodejs@18 Use node-18.x as default rtx install nodejs Install the version specified in .tool-versions rtx local nodejs@latest Use latest node in current directory rtx global nodejs@system Use system node as default - rtx x nodejs@20 -- node app.js Run `node app.js` with the PATH pointing to node-20.x + rtx x nodejs@18 -- node app.js Run `node app.js` with the PATH pointing to node-18.x ## Installation @@ -351,7 +351,7 @@ The `.tool-versions` file is used to specify the runtime versions for a project. is: ``` -nodejs 20.0.0 # comments are allowed +nodejs 18.0.0 # comments are allowed ruby 3 # can be fuzzy version shellcheck latest # also supports "latest" jq 1.6 @@ -439,8 +439,8 @@ rtx can also be configured via environment variables. The following options are This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. ```sh-session -$ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@20 -$ RTX_NODEJS_VERSION=20 rtx exec -- node --version +$ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@18 +$ RTX_NODEJS_VERSION=18 rtx exec -- node --version ``` #### `RTX_DATA_DIR` @@ -462,7 +462,7 @@ Set to something other than ".tool-versions" to have rtx look for configuration #### `RTX_${{PLUGIN}}_VERSION` -Set the version for a runtime. For example, `RTX_NODEJS_VERSION=20` will use nodejs@20.x regardless +Set the version for a runtime. For example, `RTX_NODEJS_VERSION=18` will use nodejs@18.x regardless of what is set in `.tool-versions`. #### `RTX_LEGACY_VERSION_FILE` diff --git a/src/cli/shell.rs b/src/cli/shell.rs index a6e431abb..1779f05d4 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -64,7 +64,7 @@ fn err_inactive() -> Result<()> { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx shell nodejs@20 + $ rtx shell nodejs@18 $ node -v v20.0.0 "#, style("Examples:").bold().underlined()} diff --git a/src/cli/where.rs b/src/cli/where.rs index 282686116..a7f95c647 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -53,13 +53,13 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { {} # Show the latest installed version of nodejs # If it is is not installed, errors - $ rtx where nodejs@20 - /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + $ rtx where nodejs@18 + /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 # Show the current, active install directory of nodejs # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs - /Users/jdx/.local/share/rtx/installs/nodejs/20.0.0 + /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 "#, style("Examples:").bold().underlined()} }); diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index 85463a8e4..6efbb7980 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -41,7 +41,7 @@ mod tests { let ts = ToolSource::Argument; assert_str_eq!(ts.to_string(), "--runtime"); - let ts = ToolSource::Environment("RTX_NODEJS_VERSION".to_string(), "20".to_string()); - assert_str_eq!(ts.to_string(), "RTX_NODEJS_VERSION=20"); + let ts = ToolSource::Environment("RTX_NODEJS_VERSION".to_string(), "18".to_string()); + assert_str_eq!(ts.to_string(), "RTX_NODEJS_VERSION=18"); } } diff --git a/test/fixtures/.rtxrc.toml b/test/fixtures/.rtxrc.toml index 09651559c..d1a289228 100644 --- a/test/fixtures/.rtxrc.toml +++ b/test/fixtures/.rtxrc.toml @@ -1,2 +1,2 @@ python = ['3.10'] -nodejs = ['18', '20'] +nodejs = ['16', '18'] From c1d40e9b06af68aa775976a9cef3bf31be950571 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:00:05 -0600 Subject: [PATCH 0306/1891] bug: enable reshims in fake-asdf (#216) --- README.md | 4 +- completions/_rtx | 1 + completions/rtx.bash | 2 +- e2e/test_shims | 2 + src/cli/asdf.rs | 10 ++++- src/cli/exec.rs | 5 +++ src/cli/reshim.rs | 98 ++++++++++++++++++++++++++++++-------------- src/fake_asdf.rs | 2 +- 8 files changed, 89 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index a585e083d..65ca2e768 100644 --- a/README.md +++ b/README.md @@ -1325,13 +1325,13 @@ Examples: ``` [experimental] rebuilds the shim farm -this requires that the shim_dir is set +this requires that the shims_dir is set Usage: reshim Examples: $ rtx settings set experimental true - $ rtx settings set shim_dir ~/.rtx/shims + $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim $ ~/.rtx/shims/node -v v20.0.0 diff --git a/completions/_rtx b/completions/_rtx index 089a067fe..724b546a0 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -688,6 +688,7 @@ _arguments "${_arguments_options[@]}" \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::plugin:' \ +'::version:' \ && ret=0 ;; (self-update) diff --git a/completions/rtx.bash b/completions/rtx.bash index adf479aaa..02ff497d8 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2494,7 +2494,7 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -v -h --log-level --jobs --verbose --help [PLUGIN]" + opts="-j -v -h --log-level --jobs --verbose --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/e2e/test_shims b/e2e/test_shims index 973b1f45b..ba7a09535 100755 --- a/e2e/test_shims +++ b/e2e/test_shims @@ -14,3 +14,5 @@ rtx settings set experimental true rtx settings set shims_dir "$RTX_DATA_DIR/shims" rtx reshim assert "$RTX_DATA_DIR/shims/node -v" "v18.0.0" +rtx settings unset experimental +rtx settings unset shims_dir diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index aa907e98c..bc33ee494 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -22,7 +22,15 @@ impl Command for Asdf { args.append(&mut self.args); match args.get(1).map(|s| s.as_str()) { - Some("reshim") => Ok(()), + Some("reshim") => { + if config.settings.experimental && config.settings.shims_dir.is_some() { + // only reshim if experimental is enabled and shims_dir is set + // otherwise it would error + Cli::new().run(config, &args, out) + } else { + Ok(()) + } + } Some("list") => list_versions(&config, out, &args), Some("install") => { if args.len() == 4 { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index ff59f63b8..11257abe9 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -13,6 +13,7 @@ use crate::cli::command::Command; #[cfg(test)] use crate::cmd; use crate::config::Config; +use crate::config::MissingRuntimeBehavior::Ignore; use crate::env; use crate::output::Output; use crate::toolset::ToolsetBuilder; @@ -55,6 +56,10 @@ impl Command for Exec { let (program, args) = parse_command(&env::SHELL, self.command, self.c); let mut env = ts.env(); env.insert("PATH".into(), ts.path_env()); + if config.settings.missing_runtime_behavior != Ignore { + // prevent rtx from auto-installing inside a shim + env.insert("RTX_MISSING_RUNTIME_BEHAVIOR".into(), "warn".into()); + } exec(program, args, env) } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index cad5c77b8..e64844617 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,6 +1,8 @@ -use std::fs::create_dir_all; -use std::os::unix::fs; -use std::path::PathBuf; +use std::fs; +use std::fs::{create_dir_all, remove_dir_all}; +use std::os::unix::fs::symlink; +use std::os::unix::prelude::*; +use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; use console::style; @@ -9,19 +11,21 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; -use crate::dirs; use crate::env::RTX_EXE; use crate::output::Output; use crate::toolset::ToolsetBuilder; +use crate::{dirs, fake_asdf}; /// [experimental] rebuilds the shim farm /// -/// this requires that the shim_dir is set +/// this requires that the shims_dir is set #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Reshim { #[clap(hide = true)] pub plugin: Option, + #[clap(hide = true)] + pub version: Option, } impl Command for Reshim { @@ -33,6 +37,10 @@ impl Command for Reshim { } let shims_dir = get_shims_dir(&config)?; + // remove old shims + let _ = remove_dir_all(&shims_dir); + create_dir_all(&shims_dir)?; + for path in ts.list_paths() { if !path.exists() { continue; @@ -44,13 +52,21 @@ impl Command for Reshim { } let bin_name = bin.file_name().into_string().unwrap(); let symlink_path = shims_dir.join(bin_name); - if !symlink_path.exists() { - fs::symlink(&*RTX_EXE, &symlink_path)?; - debug!( - "symlinked {} to {}", - bin.path().display(), - symlink_path.display() - ); + make_symlink(&RTX_EXE, &symlink_path)?; + } + } + for plugin in config.plugins.values() { + match plugin.plugin_path.join("shims").read_dir() { + Ok(files) => { + for bin in files { + let bin = bin?; + let bin_name = bin.file_name().into_string().unwrap(); + let symlink_path = shims_dir.join(bin_name); + make_shim(&bin.path(), &symlink_path)?; + } + } + Err(_) => { + continue; } } } @@ -59,16 +75,51 @@ impl Command for Reshim { } } +fn make_symlink(target: &Path, link: &Path) -> Result<()> { + if link.exists() { + fs::remove_file(link)?; + } + symlink(target, link)?; + debug!("symlinked {} to {}", target.display(), link.display()); + Ok(()) +} + +fn make_shim(target: &Path, shim: &Path) -> Result<()> { + if shim.exists() { + fs::remove_file(shim)?; + } + fs::write( + shim, + formatdoc! {r#" + #!/bin/sh + export ASDF_DATA_DIR={data_dir} + export PATH="{fake_asdf_dir}:$PATH" + rtx x -- {target} "$@" + "#, + data_dir = dirs::ROOT.display(), + fake_asdf_dir = fake_asdf::setup()?.display(), + target = target.display()}, + )?; + let mut perms = shim.metadata()?.permissions(); + perms.set_mode(0o755); + fs::set_permissions(shim, perms)?; + debug!( + "shim created from {} to {}", + target.display(), + shim.display() + ); + Ok(()) +} + fn get_shims_dir(config: &Config) -> Result { match config.settings.shims_dir.clone() { Some(mut shims_dir) => { if shims_dir.starts_with("~") { shims_dir = dirs::HOME.join(shims_dir.strip_prefix("~")?); } - create_dir_all(&shims_dir)?; Ok(shims_dir) } - None => err_no_shim_dir(), + None => err_no_shims_dir(), } } @@ -82,13 +133,13 @@ fn err_experimental() -> Result<()> { ))); } -fn err_no_shim_dir() -> Result { +fn err_no_shims_dir() -> Result { return Err(eyre!(formatdoc!( r#" rtx is not configured to use shims. Please set the `{}` setting to a directory. "#, - style("shim_dir").yellow() + style("shims_dir").yellow() ))); } @@ -96,22 +147,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} $ rtx settings set experimental true - $ rtx settings set shim_dir ~/.rtx/shims + $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim $ ~/.rtx/shims/node -v v20.0.0 "#, style("Examples:").bold().underlined()} }); - -#[cfg(test)] -mod tests { - - // #[test] - // fn test_reshim() { - // assert_cli!("local", "dummy@1.0.0"); - // assert_cli_snapshot!("reshim"); - // assert_cli_snapshot!("x", "--", "ls", "../data/shims"); - // assert_cli!("uninstall", "dummy@1.0.0"); - // assert_cli!("local", "--rm", "dummy@1.0.0"); - // } -} diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 8068a9546..ed85dbf23 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -7,7 +7,7 @@ use once_cell::sync::OnceCell; use crate::env; -fn setup() -> color_eyre::Result { +pub fn setup() -> color_eyre::Result { static SETUP: OnceCell = OnceCell::new(); let path = SETUP.get_or_try_init(|| { let path = env::RTX_DATA_DIR.join(".fake-asdf"); From 0400e04fa7e466ad7b1cb96e9008a8c6968ae9c6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:29:28 -0600 Subject: [PATCH 0307/1891] bug: check if shim is valid (#220) --- README.md | 35 +++++++++++++++++++++- completions/_rtx | 28 +++++++++++++++++ completions/rtx.bash | 50 +++++++++++++++++++++++++++++-- completions/rtx.fish | 68 +++++++++++++++++++++++------------------- man/man1/rtx.1 | 3 ++ src/cli/mod.rs | 3 ++ src/cli/render_help.rs | 18 ++++++++++- src/cli/which.rs | 54 +++++++++++++++++++++++++++++++++ src/runtimes.rs | 11 +++++++ src/shims.rs | 17 +++++++++-- src/toolset/mod.rs | 12 ++++++++ 11 files changed, 261 insertions(+), 38 deletions(-) create mode 100644 src/cli/which.rs diff --git a/README.md b/README.md index 65ca2e768..734966f78 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Note that calling `which node` gives us a real path to the binary, not a shim. - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. - **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. - **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. -- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them. +- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them by default. - **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. - **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. - **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. @@ -155,12 +155,14 @@ v18.10.9 * [rtx uninstall](#rtx-uninstall) * [rtx version](#rtx-version) * [rtx where](#rtx-where) + * [rtx which](#rtx-which) * [Comparison to asdf](#comparison-to-asdf) * [Performance](#performance) * [Environment variables](#environment-variables-1) * [UX](#ux) * [CI/CD](#cicd) * [GitHub Actions](#github-actions) + * [Shims](#shims) * [direnv](#direnv) * [rtx inside of direnv (use rtx in .envrc)](#rtx-inside-of-direnv-use-rtx-in-envrc) * [Cache Behavior](#cache-behavior) @@ -1478,6 +1480,21 @@ Examples: $ rtx where nodejs /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 ``` +### `rtx which` + +``` +shows the plugin that a bin points to + +Usage: which + +Arguments: + + + +Examples: + $ rtx which node + /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node +``` ## Comparison to asdf @@ -1576,6 +1593,22 @@ Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): - run: node -v # will be the node version from `.tool-versions` ``` +## Shims + +While the PATH design of rtx works great in most cases, there are some situations where shims are +preferable. One example is when calling rtx binaries from an IDE. + +To support this, there is experimental support for using rtx in a "shim" mode. To use: + +``` +$ rtx settings set experimental true +$ rtx settings set shim_dir ~/.rtx/shims +$ rtx i nodejs@18.0.0 +$ rtx reshim +$ ~/.rtx/shims/node -v +v18.0.0 +``` + ## direnv [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze diff --git a/completions/_rtx b/completions/_rtx index 724b546a0..52ef93bd0 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -857,6 +857,18 @@ _arguments "${_arguments_options[@]}" \ '::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ && ret=0 ;; +(which) +_arguments "${_arguments_options[@]}" \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':bin_name:' \ +&& ret=0 +;; (render-help) _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ @@ -1124,6 +1136,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(which) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (render-help) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1182,6 +1198,7 @@ _rtx_commands() { 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ +'which:shows the plugin that a bin points to' \ 'render-help:internal command to generate markdown from help' \ 'help:Print this message or the help of the given subcommand(s)' \ ) @@ -1530,6 +1547,7 @@ _rtx__help_commands() { 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ +'which:shows the plugin that a bin points to' \ 'render-help:internal command to generate markdown from help' \ 'help:Print this message or the help of the given subcommand(s)' \ ) @@ -1943,6 +1961,16 @@ _rtx__where_commands() { local commands; commands=() _describe -t commands 'rtx where commands' commands "$@" } +(( $+functions[_rtx__help__which_commands] )) || +_rtx__help__which_commands() { + local commands; commands=() + _describe -t commands 'rtx help which commands' commands "$@" +} +(( $+functions[_rtx__which_commands] )) || +_rtx__which_commands() { + local commands; commands=() + _describe -t commands 'rtx which commands' commands "$@" +} _rtx "$@" diff --git a/completions/rtx.bash b/completions/rtx.bash index 02ff497d8..7d2cd52fd 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -129,6 +129,9 @@ _rtx() { rtx,where) cmd="rtx__where" ;; + rtx,which) + cmd="rtx__which" + ;; rtx,x) cmd="rtx__exec" ;; @@ -315,6 +318,9 @@ _rtx() { rtx__help,where) cmd="rtx__help__where" ;; + rtx__help,which) + cmd="rtx__help__which" + ;; rtx__help__alias,get) cmd="rtx__help__alias__get" ;; @@ -472,7 +478,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where render-help help" + opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1292,7 +1298,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where render-help help" + opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1977,6 +1983,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__which) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__hook__env) opts="-s -j -v -h --shell --status --log-level --jobs --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -2863,6 +2883,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__which) + opts="-j -v -h --log-level --jobs --verbose --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; esac } diff --git a/completions/rtx.fish b/completions/rtx.fish index 9144cd957..1d005219c 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -32,6 +32,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'sets a runtime for complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'shows the plugin that a bin points to' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" @@ -303,41 +304,46 @@ complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'sets a runtime for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'sets a runtime for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'shows the plugin that a bin points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 5003c7379..0907bde3f 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -107,6 +107,9 @@ Show rtx version rtx\-where(1) Display the installation path for a runtime .TP +rtx\-which(1) +shows the plugin that a bin points to +.TP rtx\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA diff --git a/src/cli/mod.rs b/src/cli/mod.rs index c8aac4dfd..7573c2bb3 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -40,6 +40,7 @@ mod shell; mod uninstall; pub mod version; mod r#where; +mod which; // render help #[cfg(debug_assertions)] @@ -85,6 +86,7 @@ pub enum Commands { Uninstall(uninstall::Uninstall), Version(version::Version), Where(r#where::Where), + Which(which::Which), #[cfg(debug_assertions)] RenderHelp(render_help::RenderHelp), @@ -123,6 +125,7 @@ impl Commands { Self::Uninstall(cmd) => cmd.run(config, out), Self::Version(cmd) => cmd.run(config, out), Self::Where(cmd) => cmd.run(config, out), + Self::Which(cmd) => cmd.run(config, out), #[cfg(debug_assertions)] Self::RenderHelp(cmd) => cmd.run(config, out), diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e8c6e8188..89af9b69b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -47,7 +47,7 @@ Note that calling `which node` gives us a real path to the binary, not a shim. - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. - **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. - **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. -- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them. +- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them by default. - **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. - **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. - **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. @@ -726,6 +726,22 @@ Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): - run: node -v # will be the node version from `.tool-versions` ``` +## Shims + +While the PATH design of rtx works great in most cases, there are some situations where shims are +preferable. One example is when calling rtx binaries from an IDE. + +To support this, there is experimental support for using rtx in a "shim" mode. To use: + +``` +$ rtx settings set experimental true +$ rtx settings set shim_dir ~/.rtx/shims +$ rtx i nodejs@18.0.0 +$ rtx reshim +$ ~/.rtx/shims/node -v +v18.0.0 +``` + ## direnv [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze diff --git a/src/cli/which.rs b/src/cli/which.rs new file mode 100644 index 000000000..92a9a387e --- /dev/null +++ b/src/cli/which.rs @@ -0,0 +1,54 @@ +use color_eyre::eyre::{eyre, Result}; +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::config::Config; + +use crate::output::Output; +use crate::toolset::ToolsetBuilder; + +/// shows the plugin that a bin points to +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +pub struct Which { + #[clap()] + pub bin_name: String, +} + +impl Command for Which { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config); + + if !config.settings.experimental { + err_experimental()?; + } + + match ts.which(&self.bin_name) { + Some(rtv) => { + println!("{}", rtv.which(&self.bin_name)?.unwrap().display()); + Ok(()) + } + None => Err(eyre!("{} not found", self.bin_name)), + } + } +} + +fn err_experimental() -> Result<()> { + return Err(eyre!(formatdoc!( + r#" + rtx is not configured to use experimental features. + Please set the `{}` setting to `true`. + "#, + style("experimental").yellow() + ))); +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx which node + /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node + "#, style("Examples:").bold().underlined()} +}); diff --git a/src/runtimes.rs b/src/runtimes.rs index dddc6cb7f..3defafb4b 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -143,6 +143,17 @@ impl RuntimeVersion { .collect()) } + pub fn which(&self, bin_name: &str) -> Result> { + let bin_paths = self.list_bin_paths()?; + for bin_path in bin_paths { + let bin_path = bin_path.join(bin_name); + if bin_path.exists() { + return Ok(Some(bin_path)); + } + } + Ok(None) + } + pub fn is_installed(&self) -> bool { match &self.install_type { InstallType::System => true, diff --git a/src/shims.rs b/src/shims.rs index 4ca577e52..80a9bd69b 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -1,11 +1,13 @@ -use crate::cli::command::Command; -use crate::cli::exec::Exec; -use color_eyre::eyre::Result; use std::ffi::OsString; use std::process::exit; +use color_eyre::eyre::{eyre, Result}; + +use crate::cli::command::Command; +use crate::cli::exec::Exec; use crate::config::Config; use crate::output::Output; +use crate::toolset::ToolsetBuilder; // executes as if it was a shim if the command is not "rtx", e.g.: "node" pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result { @@ -13,6 +15,7 @@ pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result< if bin_name == "rtx" || !config.settings.experimental { return Ok(config); } + is_valid_shim(&config, bin_name)?; let mut args: Vec = args.iter().map(OsString::from).collect(); args[0] = OsString::from(bin_name); let exec = Exec { @@ -23,3 +26,11 @@ pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result< exec.run(config, out)?; exit(0); } + +fn is_valid_shim(config: &Config, bin_name: &str) -> Result<()> { + let ts = ToolsetBuilder::new().build(config); + match ts.which(bin_name) { + Some(_) => Ok(()), + None => Err(eyre!("{} is not a valid shim", bin_name)), + } +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 8ea2b03fd..c14e37a12 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -357,6 +357,18 @@ impl Toolset { } } } + + pub fn which(&self, bin_name: &str) -> Option<&RuntimeVersion> { + self.list_current_installed_versions() + .into_par_iter() + .find_first(|v| { + if let Ok(x) = v.which(bin_name) { + x.is_some() + } else { + false + } + }) + } } impl Display for Toolset { From ffaecdf178f78531abb00df5f4e261f3c9fdf377 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:30:05 -0600 Subject: [PATCH 0308/1891] chore: Release rtx-cli version 1.18.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 805022a3e..18d7f9dd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.18.0" +version = "1.18.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index fc877f61d..889842f14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.18.0" +version = "1.18.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 734966f78..e3d9725bb 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.18.0 +rtx 1.18.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -307,7 +307,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.0/rtx-v1.18.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.1/rtx-v1.18.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 0907bde3f..1e14ac239 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.18.0" +.TH rtx 1 "rtx 1.18.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -126,6 +126,6 @@ Print this message or the help of the given subcommand(s) rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.18.0 +v1.18.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b7b3a477d..acdff80ca 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.18.0 +Version: 1.18.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 89af9b69b..ada0246f9 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -232,7 +232,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.0/rtx-v1.18.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.1/rtx-v1.18.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 4b4ae47abedba3e1ccab94a29cf60d481dc7765b Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Sun, 26 Feb 2023 19:33:25 -0600 Subject: [PATCH 0309/1891] chore: Add CI Tests installing all plugins (#182) --- .github/workflows/test-plugins.yml | 170 +++++++++++++++++++++++++++++ scripts/query-top-plugins.fish | 36 ++++++ 2 files changed, 206 insertions(+) create mode 100644 .github/workflows/test-plugins.yml create mode 100755 scripts/query-top-plugins.fish diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml new file mode 100644 index 000000000..6cc3a71ab --- /dev/null +++ b/.github/workflows/test-plugins.yml @@ -0,0 +1,170 @@ +name: test-plugins + +# Test Top 50 asdf plugins install correctly and the most common can print their +# current version + +on: + push: + tags: ["v*"] + schedule: + # run at midnight on sunday (utc?) + - cron: 0 0 * * 0 +# pull_request: +# branches: ["main"] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + +jobs: + build-linux: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - run: scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu + - uses: actions/upload-artifact@v3 + with: + name: tarball-x86_64-unknown-linux-gnu + path: | + dist/*.tar.xz + dist/*.tar.gz + if-no-files-found: error + test-install-and-run: + runs-on: ubuntu-22.04 + needs: [build-linux] + continue-on-error: true + env: + RTX_MISSING_RUNTIME_BEHAVIOR: autoinstall + strategy: + matrix: + include: + - plugin: nodejs + command: rtx exec nodejs@latest -- node -v + - plugin: ruby + command: rtx exec ruby@latest -- ruby --version + - plugin: python + command: rtx exec python@latest -- python -V + - plugin: direnv + command: rtx exec direnv@latest -- direnv --version + - plugin: erlang + command: rtx exec erlang@latest -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell + - plugin: elixir + command: | + rtx global erlang@latest + eval "$(rtx env bash)" + rtx global elixir@latest + eval "$(rtx env bash)" + rtx exec -- elixir --version + - plugin: golang + command: rtx exec golang@latest -- go version + - plugin: java@openjdk + command: rtx exec java@openjdk -- java -version + - plugin: terraform + command: rtx exec terraform@latest -- terraform -v + - plugin: yarn + command: rtx exec yarn@latest -- yarn --version + - plugin: deno + command: rtx exec deno@latest -- deno --version + - plugin: bun + command: rtx exec bun@latest -- bun --version + - plugin: kubectl + command: rtx exec kubectl@latest -- kubectl version --client + - plugin: dotnet + command: rtx exec dotnet@latest-core -- dotnet --list-sdks + - plugin: flutter + command: rtx exec flutter@latest -- flutter --version + - plugin: crystal + command: rtx exec crystal@latest -- crystal -v + - plugin: neovim + command: rtx exec neovim@latest -- nvim --version + - plugin: php + command: rtx exec php@latest -- php -v php + - plugin: rust + command: rtx exec rust@latest -- rustc -V + - plugin: postgres + command: rtx exec postgres@latest -- psql -V + steps: + - uses: actions/checkout@v3 + - name: Install zsh/fish/direnv + run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c + - uses: actions/download-artifact@v3 + with: + name: tarball-x86_64-unknown-linux-gnu + path: dist + # dist/rtx-v1.16.0-linux-x64.tar.xz + # x86_64-unknown-linux-gnu-v1.16.0-linux-x64.tar.xz + - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz + - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH + - run: rtx -v + - run: ${{matrix.command}} + test-install: + # Tests installing the top 50 plugins not already tested in `test-install-and-run`. + # installing is a better-than-nothing smoke test that the plugin is correctly implemented + # and behaves as expected with rtx. + runs-on: ubuntu-22.04 + needs: [build-linux] + continue-on-error: true + strategy: + matrix: + plugins: + - waypoint + - vault + - tfc-agent + - terraform-ls + - serf + - sentinel + - packer + - nomad + - levant + - consul + - boundary + - postgres + - rust + - action-validator + - dotnet-core + - neovim + - poetry + # TODO: - haskell not working due to already existing on image + - link + - lua + - redis + - gcloud + - helm + - gleam + - awscli + - dart + - conan + - awsebcli + - aws-sam-cli + - ansible-base + - kotlin + - pnpm + - ocaml + # TODO: - rebar install erlang first + - julia + - elm + # TODO: - R install libcurl + - nim + - alias + - mysql + - minikube + - gradle + - zig + - shellcheck + - scala + - maven + - kustomize + - graalvm + - sbcl + steps: + - uses: actions/checkout@v3 + - name: Install zsh/fish/direnv + run: sudo apt-get update; sudo apt-get install zsh fish direnv + - uses: actions/download-artifact@v3 + with: + name: tarball-x86_64-unknown-linux-gnu + path: dist + - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz + - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH + - run: rtx install ${{matrix.plugins}}@latest diff --git a/scripts/query-top-plugins.fish b/scripts/query-top-plugins.fish new file mode 100755 index 000000000..5451f3776 --- /dev/null +++ b/scripts/query-top-plugins.fish @@ -0,0 +1,36 @@ +#!/usr/bin/fish + +# Print out list of asdf plugins sorted by number of stars. Full list is +# persisted to stargazer_count.txt + +if test -n (type -t gh) +else + echo "Github CLI Missing! Aborting!" + exit 1 +end + + +if test -d /tmp/asdf-plugins + set current_dir (pwd) + cd /tmp/asdf-plugins + git pull /tmp/asdf-plugins + cd $current_dir +else + git clone --depth=1 git@github.com:asdf-vm/asdf-plugins.git /tmp/asdf-plugins +end + +if test -e stargazer_count.txt + rm -rf stargazer_count.txt +end + + +for i in /tmp/asdf-plugins/plugins/* + cat $i | \ + string split -f2 '=' | \ + string trim | \ + xargs -I '{}' gh repo view '{}' --json stargazerCount,name,owner | \ + jq -r "[.stargazerCount,\"$(basename $i)\",\"$(string split '=' -f2 (cat $i))\"]|@tsv" >> stargazer_count.txt & +end + +echo "$(cat stargazer_count.txt)" | sort -nr | uniq >stargazer_count.txt +head -n 50 stargazer_count.txt From a5139fe8d3ad7ef004eeb4ae9455c02c765c63f5 Mon Sep 17 00:00:00 2001 From: Grant McLendon Date: Sun, 26 Feb 2023 19:33:25 -0600 Subject: [PATCH 0310/1891] chore: Add CI Tests installing all plugins (#182) --- e2e/test_lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e/test_lua b/e2e/test_lua index 0e6d176fe..b2d53997f 100755 --- a/e2e/test_lua +++ b/e2e/test_lua @@ -1,5 +1,7 @@ #!/usr/bin/env fish +exit 0 # TODO: fix this test, it's flaky + set -gx RTX_MISSING_RUNTIME_BEHAVIOR autoinstall rtx activate --status fish | source From 65e822a5d311e9fcf81355d383d9d90feb02cc79 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 07:11:39 -0600 Subject: [PATCH 0311/1891] bug: touch ROOT when running activate This triggers a reload in hook-env. Fixes #143 --- src/cli/activate.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 510fd18e4..55c9b0988 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -5,8 +5,10 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; +use crate::dirs; use crate::env::RTX_EXE; +use crate::file::touch_dir; use crate::output::Output; use crate::shell::{get_shell, ShellType}; @@ -40,6 +42,9 @@ impl Command for Activate { let shell = get_shell(self.shell_type.or(self.shell)) .expect("no shell provided, use `--shell=zsh`"); + // touch ROOT to allow hook-env to run + let _ = touch_dir(&dirs::ROOT); + let output = shell.activate(&RTX_EXE, self.status); out.stdout.write(output); @@ -59,7 +64,6 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use crate::assert_cli_snapshot; #[test] From 9b6a1450d2eabaab1c4ee01c35c2942996714d2b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 07:12:04 -0600 Subject: [PATCH 0312/1891] test: do not run tests if rtx is activated This should be fixed but it is somewhat hard to do --- src/test.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test.rs b/src/test.rs index b8e514aa8..ef04d7569 100644 --- a/src/test.rs +++ b/src/test.rs @@ -7,6 +7,10 @@ use crate::{assert_cli, env}; #[ctor::ctor] fn init() { + if env::var("__RTX_DIFF").is_ok() { + // TODO: fix this + panic!("cannot run tests when rtx is activated"); + } env::set_var("NO_COLOR", "1"); env_logger::init(); reset_config(); From 9c01d72b39c9543ed98ad6f4d4d282b078a6b4a3 Mon Sep 17 00:00:00 2001 From: Alex Rod Date: Mon, 27 Feb 2023 07:33:13 -0600 Subject: [PATCH 0313/1891] fixed typo on `rtx shell ` example (#222) setting the shell version to 18 should output that node is version 18 --- README.md | 4 ++-- src/cli/reshim.rs | 2 +- src/cli/shell.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e3d9725bb..0a3cc0224 100644 --- a/README.md +++ b/README.md @@ -1336,7 +1336,7 @@ Examples: $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim $ ~/.rtx/shims/node -v - v20.0.0 + v18.0.0 ``` ### `rtx self-update` @@ -1432,7 +1432,7 @@ Arguments: Examples: $ rtx shell nodejs@18 $ node -v - v20.0.0 + v18.0.0 ``` ### `rtx uninstall` diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index e64844617..7f1f7403f 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -150,6 +150,6 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim $ ~/.rtx/shims/node -v - v20.0.0 + v18.0.0 "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 1779f05d4..35c5e002e 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -66,7 +66,7 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { {} $ rtx shell nodejs@18 $ node -v - v20.0.0 + v18.0.0 "#, style("Examples:").bold().underlined()} }); From 104495f430d9d74391b83730339fd5fc4c6da229 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 11:12:59 -0600 Subject: [PATCH 0314/1891] bug: clear exec-env vars in deactivate (#223) before this would only reset PATH --- src/cli/deactivate.rs | 10 +++--- src/cli/hook_env.rs | 34 +++---------------- ...x__cli__activate__tests__activate_zsh.snap | 8 +++-- ..._activate__tests__activate_zsh_legacy.snap | 8 +++-- ..._cli__deactivate__tests__deactivate-2.snap | 8 +++-- src/cli/version.rs | 2 +- src/hook_env.rs | 28 +++++++++++++++ src/shell/bash.rs | 22 +++++++----- src/shell/fish.rs | 18 ++++++---- src/shell/mod.rs | 2 +- .../rtx__shell__bash__tests__deactivate.snap | 6 ++-- .../rtx__shell__bash__tests__hook_init.snap | 6 ++-- .../rtx__shell__fish__tests__deactivate.snap | 9 ++--- .../rtx__shell__fish__tests__hook_init.snap | 5 +++ ...shell__xonsh__tests__xonsh_deactivate.snap | 1 - .../rtx__shell__zsh__tests__deactivate.snap | 7 ++-- .../rtx__shell__zsh__tests__hook_init.snap | 8 +++-- src/shell/xonsh.rs | 5 ++- src/shell/zsh.rs | 25 ++++++++------ 19 files changed, 125 insertions(+), 87 deletions(-) diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 1d06a5d9c..cc5b4821e 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -2,11 +2,10 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; -use std::env::join_paths; use crate::cli::command::Command; use crate::config::Config; -use crate::env; +use crate::hook_env; use crate::output::Output; use crate::shell::get_shell; @@ -25,8 +24,8 @@ impl Command for Deactivate { let shell = get_shell(None).expect("no shell detected"); - let path = join_paths(&*env::PATH)?.to_string_lossy().to_string(); - let output = shell.deactivate(path); + out.stdout.write(hook_env::clear_old_env(&*shell)); + let output = shell.deactivate(); out.stdout.write(output); Ok(()) @@ -55,9 +54,10 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use crate::{assert_cli_err, assert_cli_snapshot, env}; use insta::assert_display_snapshot; + use crate::{assert_cli_err, assert_cli_snapshot, env}; + #[test] fn test_deactivate() { let err = assert_cli_err!("deactivate"); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 3d19d0e04..4bddbce97 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -12,7 +12,7 @@ use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::direnv::DirenvDiff; use crate::env::__RTX_DIFF; -use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; +use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::output::Output; use crate::shell::{get_shell, ShellType}; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -38,7 +38,8 @@ impl Command for HookEnv { } let ts = ToolsetBuilder::new().with_install_missing().build(&config); - self.clear_old_env(out); + let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); + out.stdout.write(hook_env::clear_old_env(&*shell)); let env = ts.env(); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); @@ -50,7 +51,7 @@ impl Command for HookEnv { patches.push(self.build_diff_operation(&diff)?); patches.push(self.build_watch_operation(&config)?); - let output = self.build_env_commands(&patches); + let output = hook_env::build_env_commands(&*shell, &patches); out.stdout.write(output); if self.status { self.display_status(&ts, out); @@ -61,33 +62,6 @@ impl Command for HookEnv { } impl HookEnv { - fn build_env_commands(&self, patches: &EnvDiffPatches) -> String { - let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); - let mut output = String::new(); - - for patch in patches.iter() { - match patch { - EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { - output.push_str(&shell.set_env(k, v)); - } - EnvDiffOperation::Remove(k) => { - output.push_str(&shell.unset_env(k)); - } - } - } - - output - } - - fn clear_old_env(&self, out: &mut Output) { - let mut patches = env::__RTX_DIFF.reverse().to_patches(); - if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { - patches.push(EnvDiffOperation::Change("PATH".into(), path.to_string())); - } - let output = self.build_env_commands(&patches); - out.stdout.write(output); - } - fn display_status(&self, ts: &Toolset, out: &mut Output) { let installed_versions = ts .list_current_installed_versions() diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap index 2d971a4a3..53489d20a 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap @@ -3,14 +3,16 @@ source: src/cli/activate.rs expression: output --- export PATH=":$PATH" -export RTX_SHELL=bash +export RTX_SHELL=zsh rtx() { local command command="${1:-}" - if [ "$#" -gt 0 ]; then - shift + if [ "$#" = 0 ]; then + command rtx + return fi + shift case "$command" in deactivate|shell) diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap index 2d971a4a3..53489d20a 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap @@ -3,14 +3,16 @@ source: src/cli/activate.rs expression: output --- export PATH=":$PATH" -export RTX_SHELL=bash +export RTX_SHELL=zsh rtx() { local command command="${1:-}" - if [ "$#" -gt 0 ]; then - shift + if [ "$#" = 0 ]; then + command rtx + return fi + shift case "$command" in deactivate|shell) diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap index 121c7d7e0..361793baf 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap @@ -2,6 +2,10 @@ source: src/cli/deactivate.rs expression: output --- -export PATH="$PATH"; -unset _rtx_hook; +export PATH='$PATH' +precmd_functions=( ${precmd_functions[(r)_rtx_hook]} ) +chpwd_functions=( ${chpwd_functions[(r)_rtx_hook]} ) +unset -f _rtx_hook +unset -f rtx +unset RTX_SHELL diff --git a/src/cli/version.rs b/src/cli/version.rs index 64d339b5c..b1e7756b6 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -47,7 +47,7 @@ impl Command for Version { } pub fn print_version_if_requested(args: &[String], out: &mut Output) { - if args.len() == 2 && args[0] == "rtx" || args[0].ends_with("/rtx") { + if args.len() == 2 && (args[0] == "rtx" || args[0].ends_with("/rtx")) { let cmd = &args[1].to_lowercase(); if cmd == "version" || cmd == "-v" || cmd == "--version" { show_version(out); diff --git a/src/hook_env.rs b/src/hook_env.rs index 7c146a492..22628fdda 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; use std::io::prelude::*; +use std::ops::Deref; use std::path::PathBuf; use std::time::SystemTime; @@ -10,6 +11,8 @@ use flate2::write::ZlibEncoder; use flate2::Compression; use crate::config::Config; +use crate::env_diff::{EnvDiffOperation, EnvDiffPatches}; +use crate::shell::Shell; use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being @@ -158,3 +161,28 @@ pub fn get_watch_files(config: &Config) -> HashSet { watches } + +pub fn clear_old_env(shell: &dyn Shell) -> String { + let mut patches = env::__RTX_DIFF.reverse().to_patches(); + if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { + patches.push(EnvDiffOperation::Change("PATH".into(), path.to_string())); + } + build_env_commands(shell, &patches) +} + +pub fn build_env_commands(shell: &dyn Shell, patches: &EnvDiffPatches) -> String { + let mut output = String::new(); + + for patch in patches.iter() { + match patch { + EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { + output.push_str(&shell.set_env(k, v)); + } + EnvDiffOperation::Remove(k) => { + output.push_str(&shell.unset_env(k)); + } + } + } + + output +} diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 5c851c96d..c7b86221d 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -22,9 +22,11 @@ impl Shell for Bash { rtx() {{ local command command="${{1:-}}" - if [ "$#" -gt 0 ]; then - shift + if [ "$#" = 0 ]; then + command {exe} + return fi + shift case "$command" in deactivate|shell) @@ -53,10 +55,12 @@ impl Shell for Bash { out } - fn deactivate(&self, path: String) -> String { + fn deactivate(&self) -> String { formatdoc! {r#" - export PATH="{path}"; - unset _rtx_hook; + PROMPT_COMMAND="${{PROMPT_COMMAND//_rtx_hook/}}" + unset _rtx_hook + unset rtx + unset RTX_SHELL "#} } @@ -82,22 +86,22 @@ mod tests { fn test_hook_init() { let bash = Bash::default(); let exe = Path::new("/some/dir/rtx"); - insta::assert_snapshot!(bash.activate(exe, true)); + assert_snapshot!(bash.activate(exe, true)); } #[test] fn test_set_env() { - insta::assert_snapshot!(Bash::default().set_env("FOO", "1")); + assert_snapshot!(Bash::default().set_env("FOO", "1")); } #[test] fn test_unset_env() { - insta::assert_snapshot!(Bash::default().unset_env("FOO")); + assert_snapshot!(Bash::default().unset_env("FOO")); } #[test] fn test_deactivate() { - let deactivate = Bash::default().deactivate("/some/path".into()); + let deactivate = Bash::default().deactivate(); assert_snapshot!(replace_path(&deactivate)); } } diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 55a5e6f50..86bc3c968 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -25,6 +25,11 @@ impl Shell for Fish { set -gx RTX_SHELL fish function rtx + if test (count $argv) -eq 0 + command {exe} + return + end + set command $argv[1] set -e argv[1] @@ -66,12 +71,13 @@ impl Shell for Fish { out } - fn deactivate(&self, path: String) -> String { + fn deactivate(&self) -> String { formatdoc! {r#" - set -gx PATH "{path}"; - functions --erase __rtx_env_eval; - functions --erase __rtx_env_eval_2; - functions --erase __rtx_cd_hook; + functions --erase __rtx_env_eval + functions --erase __rtx_env_eval_2 + functions --erase __rtx_cd_hook + functions --erase rtx + set -e RTX_SHELL "#} } @@ -112,7 +118,7 @@ mod tests { #[test] fn test_deactivate() { - let deactivate = Fish::default().deactivate("/some/path".into()); + let deactivate = Fish::default().deactivate(); assert_snapshot!(replace_path(&deactivate)); } } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 921fd2a66..1e87c5156 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -46,7 +46,7 @@ impl Display for ShellType { pub trait Shell { fn activate(&self, exe: &Path, status: bool) -> String; - fn deactivate(&self, path: String) -> String; + fn deactivate(&self) -> String; fn set_env(&self, k: &str, v: &str) -> String; fn unset_env(&self, k: &str) -> String; } diff --git a/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap index ddb052d25..c90483684 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap @@ -2,6 +2,8 @@ source: src/shell/bash.rs expression: replace_path(&deactivate) --- -export PATH="/some/path"; -unset _rtx_hook; +PROMPT_COMMAND="${PROMPT_COMMAND//_rtx_hook/}" +unset _rtx_hook +unset rtx +unset RTX_SHELL diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 6ac5c2deb..282660c64 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -8,9 +8,11 @@ export RTX_SHELL=bash rtx() { local command command="${1:-}" - if [ "$#" -gt 0 ]; then - shift + if [ "$#" = 0 ]; then + command /some/dir/rtx + return fi + shift case "$command" in deactivate|shell) diff --git a/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap index 2cd7d51f0..76bb1967a 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap @@ -2,8 +2,9 @@ source: src/shell/fish.rs expression: replace_path(&deactivate) --- -set -gx PATH "/some/path"; -functions --erase __rtx_env_eval; -functions --erase __rtx_env_eval_2; -functions --erase __rtx_cd_hook; +functions --erase __rtx_env_eval +functions --erase __rtx_env_eval_2 +functions --erase __rtx_cd_hook +functions --erase rtx +set -e RTX_SHELL diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index ddf252446..26bdc1805 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -6,6 +6,11 @@ fish_add_path -g /some/dir set -gx RTX_SHELL fish function rtx + if test (count $argv) -eq 0 + command /some/dir/rtx + return + end + set command $argv[1] set -e argv[1] diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap index a8b8efc24..3ff50467a 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap @@ -4,7 +4,6 @@ expression: replace_path(&deactivate) --- from xonsh.built_ins import XSH -environ['PATH'] = 'oldpath' hooks = { 'on_pre_prompt' : ['listen_prompt'], } diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap index 5253faf18..2f9c1c3b7 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap @@ -2,6 +2,9 @@ source: src/shell/zsh.rs expression: replace_path(&deactivate) --- -export PATH="foo"; -unset _rtx_hook; +precmd_functions=( ${precmd_functions[(r)_rtx_hook]} ) +chpwd_functions=( ${chpwd_functions[(r)_rtx_hook]} ) +unset -f _rtx_hook +unset -f rtx +unset RTX_SHELL diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index aad47b9de..0ed9d2507 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -3,14 +3,16 @@ source: src/shell/zsh.rs expression: "zsh.activate(exe, true)" --- export PATH="/some/dir:$PATH" -export RTX_SHELL=bash +export RTX_SHELL=zsh rtx() { local command command="${1:-}" - if [ "$#" -gt 0 ]; then - shift + if [ "$#" = 0 ]; then + command /some/dir/rtx + return fi + shift case "$command" in deactivate|shell) diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index da1e80418..cc0ce7a4c 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -74,11 +74,10 @@ impl Shell for Xonsh { out } - fn deactivate(&self, path: String) -> String { + fn deactivate(&self) -> String { formatdoc! {r#" from xonsh.built_ins import XSH - environ['PATH'] = '{path}' hooks = {{ 'on_pre_prompt' : ['listen_prompt'], }} @@ -157,7 +156,7 @@ mod tests { #[test] fn test_xonsh_deactivate() { - let deactivate = Xonsh::default().deactivate("oldpath".into()); + let deactivate = Xonsh::default().deactivate(); assert_snapshot!(replace_path(&deactivate)); } } diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 4fc136fdf..957d11085 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -21,14 +21,16 @@ impl Shell for Zsh { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" - export RTX_SHELL=bash + export RTX_SHELL=zsh rtx() {{ local command command="${{1:-}}" - if [ "$#" -gt 0 ]; then - shift + if [ "$#" = 0 ]; then + command {exe} + return fi + shift case "$command" in deactivate|shell) @@ -60,10 +62,13 @@ impl Shell for Zsh { out } - fn deactivate(&self, path: String) -> String { + fn deactivate(&self) -> String { formatdoc! {r#" - export PATH="{path}"; - unset _rtx_hook; + precmd_functions=( ${{precmd_functions[(r)_rtx_hook]}} ) + chpwd_functions=( ${{chpwd_functions[(r)_rtx_hook]}} ) + unset -f _rtx_hook + unset -f rtx + unset RTX_SHELL "#} } @@ -86,22 +91,22 @@ mod tests { fn test_hook_init() { let zsh = Zsh::default(); let exe = Path::new("/some/dir/rtx"); - insta::assert_snapshot!(zsh.activate(exe, true)); + assert_snapshot!(zsh.activate(exe, true)); } #[test] fn test_set_env() { - insta::assert_snapshot!(Zsh::default().set_env("FOO", "1")); + assert_snapshot!(Zsh::default().set_env("FOO", "1")); } #[test] fn test_unset_env() { - insta::assert_snapshot!(Zsh::default().unset_env("FOO")); + assert_snapshot!(Zsh::default().unset_env("FOO")); } #[test] fn test_deactivate() { - let deactivate = Zsh::default().deactivate("foo".into()); + let deactivate = Zsh::default().deactivate(); assert_snapshot!(replace_path(&deactivate)); } } From 711d097b2eb42296b2cc7ffc6ed5eb013169bdd2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 11:13:47 -0600 Subject: [PATCH 0315/1891] chore: Release rtx-cli version 1.18.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- src/default_shorthands.rs | 3 ++- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18d7f9dd4..14dd9f6f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.18.1" +version = "1.18.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 889842f14..961ec195c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.18.1" +version = "1.18.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0a3cc0224..5aa587a4b 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.18.1 +rtx 1.18.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -307,7 +307,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.1/rtx-v1.18.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.2/rtx-v1.18.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 1e14ac239..61fadbd40 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.18.1" +.TH rtx 1 "rtx 1.18.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -126,6 +126,6 @@ Print this message or the help of the given subcommand(s) rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.18.1 +v1.18.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index acdff80ca..be1daf61c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.18.1 +Version: 1.18.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index ada0246f9..1045d251a 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -232,7 +232,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.1/rtx-v1.18.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.2/rtx-v1.18.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 5a02b8bd0..25a043f5b 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 612] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 613] = [ // rtx custom aliases ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), @@ -560,6 +560,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 612] = [ ("tfenv", "https://github.com/carlduevel/asdf-tfenv.git"), ("tflint", "https://github.com/skyzyx/asdf-tflint.git"), ("tfmigrate", "https://github.com/dex4er/asdf-tfmigrate.git"), + ("tfnotify", "https://github.com/jnavarrof/asdf-tfnotify.git"), ("tfsec", "https://github.com/woneill/asdf-tfsec.git"), ("tfstate-lookup", "https://github.com/carnei-ro/asdf-tfstate-lookup.git"), ("tfupdate", "https://github.com/yuokada/asdf-tfupdate.git"), From 0c4a4396d77eeb75d8f27d9fc04e66f37e6cdcdd Mon Sep 17 00:00:00 2001 From: Jay Bosamiya Date: Mon, 27 Feb 2023 14:48:32 -0500 Subject: [PATCH 0316/1891] bug: Fix config file for asdf_compat (#224) --- src/cli/settings/set.rs | 1 + src/config/config_file/rtxrc.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 26c503cb3..6bf79166f 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -30,6 +30,7 @@ impl Command for SettingsSet { "legacy_version_file" => parse_bool(&self.value)?, "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, "verbose" => parse_bool(&self.value)?, + "asdf_compat" => parse_bool(&self.value)?, "jobs" => parse_i64(&self.value)?, "shorthands_file" => self.value.into(), "disable_default_shorthands" => parse_bool(&self.value)?, diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 5e40ab819..cd43820d8 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -98,6 +98,7 @@ impl RTXFile { Some(self.parse_duration_minutes(k, v)?) } "verbose" => self.settings.verbose = Some(self.parse_bool(k, v)?), + "asdf_compat" => self.settings.asdf_compat = Some(self.parse_bool(k, v)?), "jobs" => self.settings.jobs = Some(self.parse_usize(k, v)?), "shorthands_file" => self.settings.shorthands_file = Some(self.parse_path(k, v)?), "disable_default_shorthands" => { From 1e5c17b3b6f83254e79759c583b3d03ce4b29654 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:00:52 -0600 Subject: [PATCH 0317/1891] Create PULL_REQUEST_TEMPLATE.md --- PULL_REQUEST_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..cb6b02e61 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1 @@ + From 944083a0d62fb62726aa068547031fa6077da5de Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:07:07 -0600 Subject: [PATCH 0318/1891] Update issue templates --- .github/ISSUE_TEMPLATE/blank.md | 10 +++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 26 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 10 +++++++++ 3 files changed, 46 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/blank.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/blank.md b/.github/ISSUE_TEMPLATE/blank.md new file mode 100644 index 000000000..50fac4f02 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/blank.md @@ -0,0 +1,10 @@ +--- +name: Blank +about: Blank issue template +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..18f56b985 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,26 @@ +--- +name: Bug report +about: Something not working right? +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**`rtx doctor` output** + +``` +REPLACE WITH OUTPUT OF `rtx doctor` +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..809b7b057 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,10 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + + From fa0520f78492cb06ecbc796d380d62f27458b8a7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:10:46 -0600 Subject: [PATCH 0319/1891] chore: move pull request template to .github --- PULL_REQUEST_TEMPLATE.md => .github/pull_request_template.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename PULL_REQUEST_TEMPLATE.md => .github/pull_request_template.md (100%) diff --git a/PULL_REQUEST_TEMPLATE.md b/.github/pull_request_template.md similarity index 100% rename from PULL_REQUEST_TEMPLATE.md rename to .github/pull_request_template.md From 8bcc82ae5c9d5e3f80194217c41cc0f9952ea8e9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:35:50 -0600 Subject: [PATCH 0320/1891] chore: cache latest version check (#225) --- src/cache.rs | 15 ++++++--------- src/cli/version.rs | 33 +++++++++++++++++++++++++-------- src/file.rs | 8 ++++++++ 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index 627c3dcdf..87547c8e1 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -5,6 +5,7 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::time::Duration; +use crate::file::modified_duration; use color_eyre::eyre::Result; use flate2::read::ZlibDecoder; use flate2::write::ZlibEncoder; @@ -117,15 +118,11 @@ where fn freshest_duration(&self) -> Option { let mut freshest = self.fresh_duration; for path in &self.fresh_files { - if let Ok(metadata) = path.metadata() { - if let Ok(modified) = metadata.modified() { - let duration = modified.elapsed().unwrap_or_default(); - freshest = Some(match freshest { - None => duration, - Some(freshest) => min(freshest, duration), - }) - } - } + let duration = modified_duration(path).unwrap_or_default(); + freshest = Some(match freshest { + None => duration, + Some(freshest) => min(freshest, duration), + }) } freshest } diff --git a/src/cli/version.rs b/src/cli/version.rs index b1e7756b6..7754cf311 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,3 +1,4 @@ +use std::fs; use std::string::ToString; use std::time::Duration; @@ -9,6 +10,8 @@ use versions::Versioning; use crate::build_time::BUILD_TIME; use crate::cli::command::Command; use crate::config::Config; +use crate::dirs; +use crate::file::modified_duration; use crate::output::Output; #[derive(Debug, clap::Args)] @@ -72,7 +75,7 @@ fn show_latest() { } pub fn check_for_new_version() -> Option { - if let Some(latest) = get_latest_version() { + if let Some(latest) = get_latest_version().and_then(|v| Versioning::new(&v)) { let current = Versioning::new(env!("CARGO_PKG_VERSION")).unwrap(); if current < latest { return Some(latest.to_string()); @@ -81,20 +84,34 @@ pub fn check_for_new_version() -> Option { None } -fn get_latest_version() -> Option { +fn get_latest_version() -> Option { + let version_file_path = dirs::CACHE.join("latest-version"); + if let Ok(metadata) = modified_duration(&version_file_path) { + if metadata < Duration::from_secs(60 * 60 * 24) { + if let Ok(version) = fs::read_to_string(&version_file_path) { + return Some(version); + } + } + } + let version = get_latest_version_call()?; + let _ = fs::create_dir_all(&*dirs::CACHE); + let _ = fs::write(version_file_path, &version); + Some(version) +} + +fn get_latest_version_call() -> Option { + const URL: &str = "https://rtx.jdxcode.com/VERSION"; + debug!("checking for version from {}", URL); reqwest::blocking::ClientBuilder::new() - .timeout(Duration::from_secs(1)) + .timeout(Duration::from_secs(2)) .build() .ok()? - .get("https://rtx.jdxcode.com/VERSION") + .get(URL) .send() .ok() .and_then(|res| { if res.status().is_success() { - return res - .text() - .ok() - .and_then(|text| Versioning::new(text.as_str().trim())); + return res.text().ok().map(|text| text.trim().to_string()); } debug!("failed to check for version: {:#?}", res); None diff --git a/src/file.rs b/src/file.rs index 0c53b9764..65a702007 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,5 +1,6 @@ use std::io; use std::path::{Path, PathBuf}; +use std::time::Duration; use color_eyre::eyre::Result; use filetime::{set_file_times, FileTime}; @@ -24,6 +25,13 @@ pub fn touch_dir(dir: &Path) -> io::Result<()> { set_file_times(dir, now, now) } +pub fn modified_duration(path: &Path) -> Result { + let metadata = path.metadata()?; + let modified = metadata.modified()?; + let duration = modified.elapsed()?; + Ok(duration) +} + pub fn find_up(from: &Path, filenames: &[&str]) -> Option { let mut current = from.to_path_buf(); loop { From 2e97a77e04501d914143edd54827761ed772f596 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:56:43 -0600 Subject: [PATCH 0321/1891] chore: doctor improvements --- src/cli/doctor.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 9987348a2..4f54e8a51 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -6,6 +6,7 @@ use once_cell::sync::Lazy; use crate::cli; use crate::cli::command::Command; use crate::config::Config; +use crate::env; use crate::output::Output; @@ -32,14 +33,15 @@ impl Command for Doctor { ) } + rtxprintln!(out, "{}\n", &config); + rtxprintln!(out, "{}\n", rtx_env_vars()); + if !config.is_activated() { checks.push( "rtx is not activated, run `rtx help activate` for setup instructions".to_string(), ); } - rtxprintln!(out, "{}", &config); - for check in &checks { error!("{}", check); } @@ -53,6 +55,17 @@ impl Command for Doctor { } } +fn rtx_env_vars() -> String { + let vars = env::vars() + .filter(|(k, _)| k.starts_with("RTX_")) + .collect::>(); + let mut s = style("rtx environment variables:\n").bold().to_string(); + for (k, v) in vars { + s.push_str(&format!("{}={}\n", k, v)); + } + s +} + static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} From e263f5e37c30d1d332000e242c0d2fc9894483ec Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:27:47 -0600 Subject: [PATCH 0322/1891] chore: husky -> lefthook (#227) --- .husky/pre-commit | 45 +++++++++++++++++++++++++++++++++++---- .husky/prepare-commit-msg | 42 ++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 18 +++++++++------- e2e/run_all_tests | 1 + justfile | 2 +- lefthook.yml | 7 ++++++ package.json | 10 --------- 7 files changed, 102 insertions(+), 23 deletions(-) create mode 100755 .husky/prepare-commit-msg create mode 100644 lefthook.yml delete mode 100644 package.json diff --git a/.husky/pre-commit b/.husky/pre-commit index 8a057e790..dc93a034b 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,42 @@ -#!/usr/bin/env sh -set -e -. "$(dirname -- "$0")/_/husky.sh" +#!/bin/sh -just pre-commit +if [ "$LEFTHOOK" = "0" ]; then + exit 0 +fi + +call_lefthook() +{ + dir="$(git rev-parse --show-toplevel)" + osArch=$(echo "$(uname)" | tr '[:upper:]' '[:lower:]') + cpuArch=$(echo "$(uname -m)" | sed 's/aarch64/arm64/') + + if lefthook -h >/dev/null 2>&1 + then + eval lefthook $@ + elif test -f "$dir/node_modules/lefthook/bin/index.js" + then + eval "\"$dir/node_modules/lefthook/bin/index.js\" $@" + elif test -f "$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook" + then + eval "\"$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" + elif test -f "$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook" + then + eval "\"$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" + elif bundle exec lefthook -h >/dev/null 2>&1 + then + bundle exec lefthook $@ + elif yarn lefthook -h >/dev/null 2>&1 + then + yarn lefthook $@ + elif pnpm lefthook -h >/dev/null 2>&1 + then + pnpm lefthook $@ + elif npx @evilmartians/lefthook -h >/dev/null 2>&1 + then + npx @evilmartians/lefthook $@ + else + echo "Can't find lefthook in PATH" + fi +} + +call_lefthook "run pre-commit $@" diff --git a/.husky/prepare-commit-msg b/.husky/prepare-commit-msg new file mode 100755 index 000000000..ea81fa901 --- /dev/null +++ b/.husky/prepare-commit-msg @@ -0,0 +1,42 @@ +#!/bin/sh + +if [ "$LEFTHOOK" = "0" ]; then + exit 0 +fi + +call_lefthook() +{ + dir="$(git rev-parse --show-toplevel)" + osArch=$(echo "$(uname)" | tr '[:upper:]' '[:lower:]') + cpuArch=$(echo "$(uname -m)" | sed 's/aarch64/arm64/') + + if lefthook -h >/dev/null 2>&1 + then + eval lefthook $@ + elif test -f "$dir/node_modules/lefthook/bin/index.js" + then + eval "\"$dir/node_modules/lefthook/bin/index.js\" $@" + elif test -f "$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook" + then + eval "\"$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" + elif test -f "$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook" + then + eval "\"$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" + elif bundle exec lefthook -h >/dev/null 2>&1 + then + bundle exec lefthook $@ + elif yarn lefthook -h >/dev/null 2>&1 + then + yarn lefthook $@ + elif pnpm lefthook -h >/dev/null 2>&1 + then + pnpm lefthook $@ + elif npx @evilmartians/lefthook -h >/dev/null 2>&1 + then + npx @evilmartians/lefthook $@ + else + echo "Can't find lefthook in PATH" + fi +} + +call_lefthook "run prepare-commit-msg $@" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0144fffc8..1d2e3c194 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,15 +19,16 @@ Available recipes: lint # clippy, cargo fmt --check, and just --fmt lint-fix # runs linters but makes fixes when possible pre-commit # called by husky precommit hook + release *args render-completions # regenerate shell completion files render-help # regenerate README.md - test # run all test types - b # alias for `test` - t # alias for `test` + render-mangen # regenerate manpages + test *args # run all test types + b *args # alias for `test` + t *args # alias for `test` test-coverage # run unit tests w/ coverage test-e2e # runs the E2E tests in ./e2e - test-setup # prepare repo to execute tests - test-unit # run the rust "unit" tests + test-unit *args # run the rust "unit" tests test-update-snapshots # update all test snapshot files ``` @@ -68,11 +69,12 @@ just pre-commit ## [optional] Pre-commit hook -This project uses husky which will automatically install a pre-commit hook: +This project uses lefthook which will automatically install a pre-commit hook: ``` -npm i # installs and configured husky precommit hook automatically -git commit # will automatically run `just pre-commit` +brew install lefthook # or install via some other means +lefthook install +git commit ``` ## Testing packaging diff --git a/e2e/run_all_tests b/e2e/run_all_tests index ed32dafa7..70d3f000b 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -9,6 +9,7 @@ for f in $FILES; do continue fi "$ROOT/e2e/run_test" "$f" + echo done echo "e2e: all tests passed" diff --git a/justfile b/justfile index a3988d1ef..7b477eff3 100644 --- a/justfile +++ b/justfile @@ -89,7 +89,7 @@ render-mangen: build rtx mangen # called by husky precommit hook -pre-commit: lint render-help render-completions render-mangen +pre-commit: render-help render-completions render-mangen git add README.md git add completions git add man diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 000000000..f731b99a2 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,7 @@ +pre-commit: + parallel: true + commands: + pre-commit: + run: just pre-commit + lint: + run: just lint diff --git a/package.json b/package.json deleted file mode 100644 index bca08c61a..000000000 --- a/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@jdxcode/rtx", - "private": true, - "devDependencies": { - "husky": "^8.0.0" - }, - "scripts": { - "prepare": "husky install" - } -} From bc51041f89f5af9ab41b67d40e574e12237c3268 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 21:32:34 -0600 Subject: [PATCH 0323/1891] chore: `rtx doctor` improvements (#230) --- Cargo.lock | 1 + Cargo.toml | 1 + e2e/test_doctor | 14 +++ src/cli/doctor.rs | 114 +++++++++++++----- src/config/config_file/tool_versions.rs | 2 +- src/config/mod.rs | 5 +- src/config/settings.rs | 8 +- .../snapshots/rtx__config__tests__load.snap | 5 +- src/toolset/mod.rs | 2 +- 9 files changed, 111 insertions(+), 41 deletions(-) create mode 100755 e2e/test_doctor diff --git a/Cargo.lock b/Cargo.lock index 14dd9f6f4..d6c8dc74a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1400,6 +1400,7 @@ dependencies = [ "exec", "filetime", "flate2", + "indenter", "indexmap", "indicatif", "indoc", diff --git a/Cargo.toml b/Cargo.toml index 961ec195c..fdaf70a5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ dirs-next = "2.0.0" duct = "0.13.6" filetime = "0.2.19" flate2 = "1.0.25" +indenter = "0.3.3" indexmap = "1.9.2" indicatif = "0.17.3" indoc = "2.0.0" diff --git a/e2e/test_doctor b/e2e/test_doctor new file mode 100755 index 000000000..2e96b1462 --- /dev/null +++ b/e2e/test_doctor @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +assert() { + local actual + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +eval "$(rtx activate bash)" +rtx doctor diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 4f54e8a51..23c90b97a 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -1,14 +1,20 @@ -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::Result; use console::style; +use indenter::indented; use indoc::formatdoc; use once_cell::sync::Lazy; +use std::fmt::Write; +use std::process::exit; -use crate::cli; use crate::cli::command::Command; +use crate::cli::version::VERSION; use crate::config::Config; use crate::env; +use crate::{cli, cmd}; use crate::output::Output; +use crate::shell::ShellType; +use crate::toolset::ToolsetBuilder; /// Check rtx installation for possible problems. #[derive(Debug, clap::Args)] @@ -17,6 +23,29 @@ pub struct Doctor {} impl Command for Doctor { fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config); + rtxprintln!(out, "{}", rtx_version()); + rtxprintln!(out, "{}", shell()); + rtxprintln!(out, "{}", rtx_env_vars()); + rtxprintln!( + out, + "{}\n{}\n", + style("config:").bold(), + indent(config.to_string()) + ); + rtxprintln!( + out, + "{}\n{}\n", + style("settings:").bold(), + indent(config.settings.to_string()) + ); + rtxprintln!( + out, + "{}\n{}\n", + style("toolset:").bold(), + indent(ts.to_string()) + ); + let mut checks = Vec::new(); for plugin in config.plugins.values() { if !plugin.is_installed() { @@ -26,32 +55,33 @@ impl Command for Doctor { } if let Some(latest) = cli::version::check_for_new_version() { - warn!( + checks.push(format!( "new rtx version {} available, currently on {}", latest, env!("CARGO_PKG_VERSION") - ) + )); } - rtxprintln!(out, "{}\n", &config); - rtxprintln!(out, "{}\n", rtx_env_vars()); - if !config.is_activated() { - checks.push( - "rtx is not activated, run `rtx help activate` for setup instructions".to_string(), - ); - } - - for check in &checks { - error!("{}", check); + let cmd = style("rtx activate").yellow().for_stderr(); + checks.push(format!( + "rtx is not activated, run `{cmd}` for setup instructions" + )); } if checks.is_empty() { rtxprintln!(out, "No problems found"); - Ok(()) } else { - Err(eyre!("{} problems found", checks.len())) + let checks_plural = if checks.len() == 1 { "" } else { "s" }; + let summary = format!("{} problem{checks_plural} found:", checks.len()); + rtxprintln!(out, "{}", style(summary).red().bold()); + for check in &checks { + rtxprintln!(out, "{}\n", check); + } + exit(1); } + + Ok(()) } } @@ -60,12 +90,47 @@ fn rtx_env_vars() -> String { .filter(|(k, _)| k.starts_with("RTX_")) .collect::>(); let mut s = style("rtx environment variables:\n").bold().to_string(); + if vars.is_empty() { + s.push_str(" (none)\n"); + } for (k, v) in vars { - s.push_str(&format!("{}={}\n", k, v)); + s.push_str(&format!(" {}={}\n", k, v)); } s } +fn rtx_version() -> String { + let mut s = style("rtx version:\n").bold().to_string(); + s.push_str(&format!(" {}\n", *VERSION)); + s +} + +fn shell() -> String { + let mut s = style("shell:\n").bold().to_string(); + match ShellType::load().map(|s| s.to_string()) { + Some(shell) => { + let shell_cmd = if env::SHELL.ends_with(shell.as_str()) { + &*env::SHELL + } else { + &shell + }; + let version = cmd!(shell_cmd, "--version") + .read() + .unwrap_or_else(|e| format!("failed to get shell version: {}", e)); + let out = format!("{}\n{}\n", shell_cmd, version); + s.push_str(&indent(out)); + } + None => s.push_str(" (unknown)\n"), + } + s +} + +fn indent(s: String) -> String { + let mut out = String::new(); + write!(indented(&mut out).with_str(" "), "{}", s).unwrap(); + out +} + static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -73,18 +138,3 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { [WARN] plugin nodejs is not installed "#, style("Examples:").bold().underlined()} }); - -#[cfg(test)] -mod tests { - use crate::cli::tests::cli_run; - - #[test] - fn test_doctor() { - let _ = cli_run( - &vec!["rtx", "doctor"] - .into_iter() - .map(String::from) - .collect::>(), - ); - } -} diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 334441d32..b79249f84 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -250,7 +250,7 @@ pub(crate) mod tests { "}; let tv = ToolVersions::parse_str(orig).unwrap(); let toolset: Toolset = (&tv).into(); - assert_display_snapshot!(toolset, @"Toolset: ruby@3.0.5 ruby@3.1"); + assert_display_snapshot!(toolset, @"ruby@3.0.5 ruby@3.1"); } #[derive(Debug)] diff --git a/src/config/mod.rs b/src/config/mod.rs index 16d33a3b9..bed806bd6 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -203,9 +203,8 @@ impl Display for Config { .replace(&dirs::HOME.to_string_lossy().to_string(), "~") }) .collect::>(); - writeln!(f, "Config:")?; - writeln!(f, " Files: {}", config_files.join(", "))?; - write!(f, " Installed Plugins: {}", plugins.join(", ")) + writeln!(f, "Files: {}", config_files.join(", "))?; + write!(f, "Installed Plugins: {}", plugins.join(", ")) } } diff --git a/src/config/settings.rs b/src/config/settings.rs index 56638c3c9..68b4b3311 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,4 +1,4 @@ -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; use std::time::Duration; @@ -200,6 +200,12 @@ impl SettingsBuilder { } } +impl Display for Settings { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.to_index_map().fmt(f) + } +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum MissingRuntimeBehavior { AutoInstall, diff --git a/src/config/snapshots/rtx__config__tests__load.snap b/src/config/snapshots/rtx__config__tests__load.snap index 93547335e..ec9aed78c 100644 --- a/src/config/snapshots/rtx__config__tests__load.snap +++ b/src/config/snapshots/rtx__config__tests__load.snap @@ -2,6 +2,5 @@ source: src/config/mod.rs expression: config --- -Config: - Files: ~/cwd/.test-tool-versions, ~/.test-tool-versions - Installed Plugins: dummy, tiny +Files: ~/cwd/.test-tool-versions, ~/.test-tool-versions +Installed Plugins: dummy, tiny diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index c14e37a12..9fa174f54 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -378,7 +378,7 @@ impl Display for Toolset { .iter() .map(|(_, v)| v.versions.iter().map(|v| v.to_string()).join(" ")) .collect_vec(); - write!(f, "Toolset: {}", plugins.join(", ")) + write!(f, "{}", plugins.join(", ")) } } From 34b1e2721e675cfaf6a0c594ffedabbdd70a677d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 21:47:08 -0600 Subject: [PATCH 0324/1891] bug: disable stdin by default unless RTX_RAW=1 (#229) --- README.md | 23 + completions/_rtx | 196 ++++++--- completions/rtx.bash | 392 +++++++++--------- completions/rtx.fish | 147 ++++--- e2e/test_raw | 14 + man/man1/rtx.1 | 5 +- src/cli/args/mod.rs | 1 + src/cli/args/raw.rs | 14 + src/cli/bin_paths.rs | 2 +- src/cli/direnv/envrc.rs | 2 +- src/cli/direnv/exec.rs | 2 +- ...i__direnv__envrc__tests__direnv_envrc.snap | 1 + src/cli/env.rs | 3 +- src/cli/exec.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/install.rs | 2 +- src/cli/mod.rs | 10 +- src/cli/render_help.rs | 20 + src/cli/reshim.rs | 2 +- src/cli/settings/set.rs | 1 + ...cli__settings__ls__tests__settings_ls.snap | 1 + ...i__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + ...rtx__cli__bin_paths__tests__bin_paths.snap | 1 + .../rtx__cli__current__tests__current.snap | 1 + .../rtx__cli__which__tests__which.snap | 6 + src/cli/uninstall.rs | 2 +- src/cli/which.rs | 34 +- src/config/config_file/rtxrc.rs | 1 + src/config/settings.rs | 17 +- src/env.rs | 9 +- src/plugins/mod.rs | 8 +- src/plugins/script_manager.rs | 71 ++-- src/runtimes.rs | 17 +- src/shims.rs | 2 +- src/toolset/mod.rs | 14 +- test/.test-tool-versions | 3 +- 37 files changed, 656 insertions(+), 374 deletions(-) create mode 100755 e2e/test_raw create mode 100644 src/cli/args/raw.rs create mode 100644 src/cli/snapshots/rtx__cli__which__tests__which.snap diff --git a/README.md b/README.md index 5aa587a4b..fe4613bc5 100644 --- a/README.md +++ b/README.md @@ -108,9 +108,12 @@ v18.10.9 * [RTX_VERBOSE=1](#rtx_verbose1) * [RTX_ASDF_COMPAT=1](#rtx_asdf_compat1) * [RTX_JOBS=1](#rtx_jobs1) + * [RTX_RAW=1](#rtx_raw1) * [RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml](#rtx_shorthands_fileconfigrtxshorthandstoml) * [RTX_DISABLE_DEFAULT_SHORTHANDS=1](#rtx_disable_default_shorthands1) * [RTX_HIDE_OUTDATED_BUILD=1](#rtx_hide_outdated_build1) + * [RTX_EXPERIMENTAL=1](#rtx_experimental1) + * [[experimental] RTX_SHIMS_DIR=~/.local/share/rtx/shims](#experimental-rtx_shims_dirlocalsharertxshims) * [Aliases](#aliases) * [Plugins](#plugins) * [FAQs](#faqs) @@ -494,10 +497,14 @@ plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable u verbose = false # set to true to see full installation output, see `RTX_VERBOSE` asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. +raw = false # set to true to directly pipe plugins to stdin/stdout/stderr shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` +experimental = false # enable experimental features such as shims +shims_dir = '~/.local/share/rtx/shims' # [experimental] directory where shims are stored + [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x # this can also be specified in a plugin (see below in "Aliases") @@ -573,6 +580,14 @@ Only output `.tool-versions` files in `rtx local|global` which will be usable by Set the number plugins or runtimes to install in parallel. The default is `4`. +#### `RTX_RAW=1` + +Set to "1" to directly pipe plugin scripts to stdin/stdout/stderr. By default stdin is disabled +because when installing a bunch of plugins in parallel you won't see the prompt. Use this if a +plugin accepts input or otherwise does not seem to be installing correctly. + +Sets `RTX_JOBS=1` because only 1 plugin script can be executed at a time. + #### `RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml` Use a custom file for the shorthand aliases. This is useful if you want to share plugins within @@ -606,6 +621,14 @@ You likely do not want to be using rtx if it is that old. I'm doing this instead autoupdating. If, for some reason, you want to stay on some old version, you can hide this message with `RTX_HIDE_OUTDATED_BUILD=1`. +#### `RTX_EXPERIMENTAL=1` + +Enables experimental features such as shims. + +#### [experimental] `RTX_SHIMS_DIR=~/.local/share/rtx/shims` + +Set a directory to output shims when running `rtx reshim`. Requires `experimental = true`. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/completions/_rtx b/completions/_rtx index 52ef93bd0..b2822f53a 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -15,9 +15,11 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -37,12 +39,14 @@ _rtx() { _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx: @" message when changing directories]' \ '-q[noop]' \ '--quiet[noop]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -54,9 +58,11 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -73,9 +79,11 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (get) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -88,9 +96,11 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -99,9 +109,11 @@ _arguments "${_arguments_options[@]}" \ ;; (set) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -113,9 +125,11 @@ _arguments "${_arguments_options[@]}" \ ;; (unset) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -166,9 +180,11 @@ esac ;; (asdf) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -178,9 +194,11 @@ _arguments "${_arguments_options[@]}" \ ;; (bin-paths) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -189,9 +207,11 @@ _arguments "${_arguments_options[@]}" \ ;; (cache) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -208,9 +228,11 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (clear) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -249,9 +271,11 @@ esac _arguments "${_arguments_options[@]}" \ '-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -260,9 +284,11 @@ _arguments "${_arguments_options[@]}" \ ;; (current) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -272,9 +298,11 @@ _arguments "${_arguments_options[@]}" \ ;; (deactivate) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -283,9 +311,11 @@ _arguments "${_arguments_options[@]}" \ ;; (direnv) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -302,9 +332,11 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (envrc) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -313,9 +345,11 @@ _arguments "${_arguments_options[@]}" \ ;; (exec) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -324,9 +358,11 @@ _arguments "${_arguments_options[@]}" \ ;; (activate) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -371,9 +407,11 @@ esac ;; (doctor) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -384,9 +422,11 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -398,9 +438,11 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '()-c+[Command string to execute]:C: ' \ '()--command=[Command string to execute]:C: ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -411,11 +453,13 @@ _arguments "${_arguments_options[@]}" \ (global) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to `~/.tool-versions`]' \ '--fuzzy[Save fuzzy version to `~/.tool-versions`]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -427,10 +471,12 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx: @" message when changing directories]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -439,11 +485,13 @@ _arguments "${_arguments_options[@]}" \ ;; (implode) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '--config[Also remove config directory]' \ '--dry-run[List directories that would be removed without actually removing them]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -454,15 +502,17 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '()*-p+[Only install runtime(s) for ]:PLUGIN: ' \ '()*--plugin=[Only install runtime(s) for ]:PLUGIN: ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Force reinstall even if already installed]' \ '--force[Force reinstall even if already installed]' \ '(-p --plugin -f --force)-a[Install all missing runtimes as well as all plugins for the current directory]' \ '(-p --plugin -f --force)--all[Install all missing runtimes as well as all plugins for the current directory]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtime(s) to install:' \ @@ -470,9 +520,11 @@ _arguments "${_arguments_options[@]}" \ ;; (latest) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -484,15 +536,17 @@ _arguments "${_arguments_options[@]}" \ (local) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from .tool-versions]:PLUGIN: ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-p[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--parent[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--pin[Save exact version to `.tool-versions`]' \ '--fuzzy[Save fuzzy version to `.tool-versions`]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -504,11 +558,13 @@ by default this command will only set the runtime in the current directory ("$PW _arguments "${_arguments_options[@]}" \ '-p+[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--plugin=[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -518,9 +574,11 @@ _arguments "${_arguments_options[@]}" \ ;; (ls-remote) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -531,9 +589,11 @@ _arguments "${_arguments_options[@]}" \ ;; (mangen) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -542,13 +602,15 @@ _arguments "${_arguments_options[@]}" \ ;; (plugins) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -565,15 +627,17 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (install) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ '(-f --force)-a[Install all missing plugins]' \ '(-f --force)--all[Install all missing plugins]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::name -- The name of the plugin to install:' \ @@ -582,13 +646,15 @@ _arguments "${_arguments_options[@]}" \ ;; (ls) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[List all available remote plugins]' \ '--all[List all available remote plugins]' \ '-u[Show the git url for each plugin]' \ '--urls[Show the git url for each plugin]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -597,11 +663,13 @@ _arguments "${_arguments_options[@]}" \ ;; (ls-remote) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[Show the git url for each plugin]' \ '--urls[Show the git url for each plugin]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -610,9 +678,11 @@ _arguments "${_arguments_options[@]}" \ ;; (uninstall) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -622,11 +692,13 @@ _arguments "${_arguments_options[@]}" \ ;; (update) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ '()-a[Update all plugins]' \ '()--all[Update all plugins]' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -680,9 +752,11 @@ esac ;; (reshim) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -693,9 +767,11 @@ _arguments "${_arguments_options[@]}" \ ;; (self-update) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -704,9 +780,11 @@ _arguments "${_arguments_options[@]}" \ ;; (settings) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -723,9 +801,11 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (get) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -735,9 +815,11 @@ _arguments "${_arguments_options[@]}" \ ;; (ls) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -746,9 +828,11 @@ _arguments "${_arguments_options[@]}" \ ;; (set) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -759,9 +843,11 @@ _arguments "${_arguments_options[@]}" \ ;; (unset) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -811,9 +897,11 @@ esac ;; (shell) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -823,9 +911,11 @@ _arguments "${_arguments_options[@]}" \ ;; (uninstall) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -835,9 +925,11 @@ _arguments "${_arguments_options[@]}" \ ;; (version) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -846,9 +938,11 @@ _arguments "${_arguments_options[@]}" \ ;; (where) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -859,9 +953,11 @@ _arguments "${_arguments_options[@]}" \ ;; (which) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -871,9 +967,11 @@ _arguments "${_arguments_options[@]}" \ ;; (render-help) _arguments "${_arguments_options[@]}" \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 7d2cd52fd..4b1755ba0 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -478,21 +478,21 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -v -h -V --log-level --jobs --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where which render-help help" + opts="-j -r -v -h -V --jobs --log-level --raw --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -504,7 +504,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -j -v -h --shell --status --quiet --log-level --jobs --verbose --help bash fish xonsh zsh" + opts="-s -q -j -r -v -h --shell --status --quiet --jobs --log-level --raw --verbose --help bash fish xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -518,15 +518,15 @@ _rtx() { COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -538,7 +538,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -v -h --plugin --log-level --jobs --verbose --help get ls set unset help" + opts="-p -j -r -v -h --plugin --jobs --log-level --raw --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -552,15 +552,15 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -572,21 +572,21 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -682,7 +682,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -j -v -h --plugin --log-level --jobs --verbose --help" + opts="-p -j -r -v -h --plugin --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -696,15 +696,15 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -716,21 +716,21 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -742,21 +742,21 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -768,21 +768,21 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-j -v -h --log-level --jobs --verbose --help [ARGS]..." + opts="-j -r -v -h --jobs --log-level --raw --verbose --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -794,21 +794,21 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -820,21 +820,21 @@ _rtx() { return 0 ;; rtx__cache) - opts="-j -v -h --log-level --jobs --verbose --help clear help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -846,21 +846,21 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -914,7 +914,7 @@ _rtx() { return 0 ;; rtx__complete) - opts="-s -j -v -h --shell --log-level --jobs --verbose --help" + opts="-s -j -r -v -h --shell --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -928,15 +928,15 @@ _rtx() { COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -948,21 +948,21 @@ _rtx() { return 0 ;; rtx__current) - opts="-j -v -h --log-level --jobs --verbose --help [PLUGIN]" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -974,21 +974,21 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1000,21 +1000,21 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-j -v -h --log-level --jobs --verbose --help envrc exec activate help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1026,21 +1026,21 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1052,21 +1052,21 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1078,21 +1078,21 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1174,21 +1174,21 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1200,7 +1200,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -v -h --shell --log-level --jobs --verbose --help [RUNTIME]..." + opts="-s -j -r -v -h --shell --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1214,15 +1214,15 @@ _rtx() { COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1234,7 +1234,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -v -h --command --log-level --jobs --verbose --help [RUNTIME]... [COMMAND]..." + opts="-c -j -r -v -h --command --jobs --log-level --raw --verbose --help [RUNTIME]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1248,15 +1248,15 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1268,7 +1268,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -v -h --pin --fuzzy --remove --log-level --jobs --verbose --help [RUNTIME]..." + opts="-j -r -v -h --pin --fuzzy --remove --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1278,15 +1278,15 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -1998,7 +1998,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -v -h --shell --status --log-level --jobs --verbose --help" + opts="-s -j -r -v -h --shell --status --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2012,15 +2012,15 @@ _rtx() { COMPREPLY=($(compgen -W "bash fish xonsh zsh" -- "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2032,21 +2032,21 @@ _rtx() { return 0 ;; rtx__implode) - opts="-j -v -h --config --dry-run --log-level --jobs --verbose --help" + opts="-j -r -v -h --config --dry-run --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2058,7 +2058,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-p -f -a -v -j -h --plugin --force --all --verbose --log-level --jobs --help [RUNTIME]..." + opts="-p -f -a -v -j -r -h --plugin --force --all --verbose --jobs --log-level --raw --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2072,15 +2072,15 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2092,21 +2092,21 @@ _rtx() { return 0 ;; rtx__latest) - opts="-j -v -h --log-level --jobs --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2118,7 +2118,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -v -h --parent --pin --fuzzy --remove --log-level --jobs --verbose --help [RUNTIME]..." + opts="-p -j -r -v -h --parent --pin --fuzzy --remove --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2128,15 +2128,15 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2148,7 +2148,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -j -v -h --plugin --current --log-level --jobs --verbose --help [PLUGIN_ARG]" + opts="-p -c -j -r -v -h --plugin --current --jobs --log-level --raw --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2162,15 +2162,15 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2182,21 +2182,21 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -v -h --log-level --jobs --verbose --help [PREFIX]" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2208,21 +2208,21 @@ _rtx() { return 0 ;; rtx__mangen) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2234,21 +2234,21 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -u -j -v -h --all --urls --log-level --jobs --verbose --help install ls ls-remote uninstall update help" + opts="-a -u -j -r -v -h --all --urls --jobs --log-level --raw --verbose --help install ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2358,21 +2358,21 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -h --force --all --verbose --log-level --jobs --help [NAME] [GIT_URL]" + opts="-f -a -v -j -r -h --force --all --verbose --jobs --log-level --raw --help [NAME] [GIT_URL]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2384,21 +2384,21 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -u -j -v -h --all --urls --log-level --jobs --verbose --help" + opts="-a -u -j -r -v -h --all --urls --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2410,21 +2410,21 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -v -h --urls --log-level --jobs --verbose --help" + opts="-u -j -r -v -h --urls --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2436,21 +2436,21 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2462,21 +2462,21 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -j -v -h --all --log-level --jobs --verbose --help [PLUGIN]..." + opts="-a -j -r -v -h --all --jobs --log-level --raw --verbose --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2488,21 +2488,21 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2514,21 +2514,21 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -v -h --log-level --jobs --verbose --help [PLUGIN] [VERSION]" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2540,21 +2540,21 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2566,21 +2566,21 @@ _rtx() { return 0 ;; rtx__settings) - opts="-j -v -h --log-level --jobs --verbose --help get ls set unset help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2592,21 +2592,21 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2702,21 +2702,21 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2728,21 +2728,21 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2754,21 +2754,21 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2780,21 +2780,21 @@ _rtx() { return 0 ;; rtx__shell) - opts="-j -v -h --log-level --jobs --verbose --help [RUNTIME]..." + opts="-j -r -v -h --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2806,21 +2806,21 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-j -v -h --log-level --jobs --verbose --help ..." + opts="-j -r -v -h --jobs --log-level --raw --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2832,21 +2832,21 @@ _rtx() { return 0 ;; rtx__version) - opts="-j -v -h --log-level --jobs --verbose --help" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2858,21 +2858,21 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -v -h --log-level --jobs --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --jobs --log-level --raw --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -2884,21 +2884,21 @@ _rtx() { return 0 ;; rtx__which) - opts="-j -v -h --log-level --jobs --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + --log-level) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; diff --git a/completions/rtx.fish b/completions/rtx.fish index 1d005219c..f770a2e1e 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,5 +1,6 @@ -complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' @@ -36,15 +37,17 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'shows the plugin th complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' +complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' @@ -54,21 +57,25 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' @@ -78,41 +85,49 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -121,16 +136,19 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subc for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -139,77 +157,90 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,xonsh ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r -complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' +complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only install runtime(s) for ' -r -complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing runtimes as well as all plugins for the current directory' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions`' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from mangen" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' @@ -218,30 +249,35 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' @@ -250,16 +286,19 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -267,20 +306,24 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -288,28 +331,34 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' diff --git a/e2e/test_raw b/e2e/test_raw new file mode 100755 index 000000000..9e478fdca --- /dev/null +++ b/e2e/test_raw @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +assert() { + local actual + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +rtx i --raw -f tiny@1 tiny@2 tiny@3 +RTX_RAW=1 rtx i -f tiny@1 tiny@2 tiny@3 diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 61fadbd40..dec20e2d2 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -4,7 +4,7 @@ .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS -\fBrtx\fR [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> +\fBrtx\fR [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> .SH DESCRIPTION rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx .PP @@ -19,6 +19,9 @@ https://asdf\-vm.com/ \fB\-j\fR, \fB\-\-jobs\fR Number of plugins and runtimes to install in parallel, default: 4 .TP +\fB\-r\fR, \fB\-\-raw\fR +Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets \-\-jobs=1. +.TP \fB\-v\fR, \fB\-\-verbose\fR Show installation output .TP diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index f1776aba3..47c479626 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,4 +1,5 @@ pub mod jobs; pub mod log_level; +pub mod raw; pub mod runtime; pub mod verbose; diff --git a/src/cli/args/raw.rs b/src/cli/args/raw.rs new file mode 100644 index 000000000..1343771f5 --- /dev/null +++ b/src/cli/args/raw.rs @@ -0,0 +1,14 @@ +use clap::{Arg, ArgAction}; + +pub struct Raw(pub bool); + +impl Raw { + pub fn arg() -> Arg { + Arg::new("raw") + .short('r') + .long("raw") + .help("Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.") + .action(ArgAction::SetTrue) + .global(true) + } +} diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 3c3c95eea..34badb684 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -13,7 +13,7 @@ pub struct BinPaths {} impl Command for BinPaths { fn run(self, config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().with_install_missing().build(&config); - for p in ts.list_paths() { + for p in ts.list_paths(&config.settings) { rtxprintln!(out, "{}", p.display()); } Ok(()) diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index d0b99e0f2..4ad76f70b 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -47,7 +47,7 @@ impl Command for Envrc { shell_escape::unix::escape(v.into()), )?; } - for path in ts.list_paths().into_iter().rev() { + for path in ts.list_paths(&config.settings).into_iter().rev() { writeln!(file, "PATH_add {}", path.to_string_lossy())?; } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 6992d9d73..b500e0914 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -35,7 +35,7 @@ impl Command for DirenvExec { for (k, v) in ts.env() { cmd = cmd.env(k, v); } - cmd = cmd.env("PATH", ts.path_env()); + cmd = cmd.env("PATH", ts.path_env(&config.settings)); let json = cmd!("direnv", "watch", "json", ".tool-versions").read()?; let w: DirenvWatches = serde_json::from_str(&json)?; diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index 18dc2d096..745c60e55 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -6,5 +6,6 @@ expression: envrc watch_file ~/cwd/.test-tool-versions watch_file ~/.test-tool-versions export JDXCODE_TINY=3.1.0 +PATH_add ~/data/installs/dummy/ref-master/bin PATH_add ~/data/installs/tiny/3.1.0/bin diff --git a/src/cli/env.rs b/src/cli/env.rs index afe7cd3a3..b8d3b12ec 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -43,7 +43,8 @@ impl Command for Env { let v = v.to_string(); rtxprint!(out, "{}", shell.set_env(&k, &v)); } - rtxprintln!(out, "{}", shell.set_env("PATH", ts.path_env().as_ref())); + let path = ts.path_env(&config.settings); + rtxprintln!(out, "{}", shell.set_env("PATH", &path)); Ok(()) } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 11257abe9..519488f45 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -55,7 +55,7 @@ impl Command for Exec { let (program, args) = parse_command(&env::SHELL, self.command, self.c); let mut env = ts.env(); - env.insert("PATH".into(), ts.path_env()); + env.insert("PATH".into(), ts.path_env(&config.settings)); if config.settings.missing_runtime_behavior != Ignore { // prevent rtx from auto-installing inside a shim env.insert("RTX_MISSING_RUNTIME_BEHAVIOR".into(), "warn".into()); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 4bddbce97..2a1e80424 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -44,7 +44,7 @@ impl Command for HookEnv { let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); - let installs = ts.list_paths(); // load the active runtime paths + let installs = ts.list_paths(&config.settings); // load the active runtime paths diff.path = installs.clone(); // update __RTX_DIFF with the new paths for the next run patches.extend(self.build_path_operations(&installs, &__RTX_DIFF.path)?); diff --git a/src/cli/install.rs b/src/cli/install.rs index 6064b6c4d..e29047768 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -84,7 +84,7 @@ impl Install { if let Some(rtv) = &v.rtv { if rtv.is_installed() { info!("uninstalling {}", rtv); - rtv.uninstall()?; + rtv.uninstall(&config.settings)?; } } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 7573c2bb3..8c4165efb 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -159,8 +159,9 @@ impl Cli { .arg_required_else_help(true) .subcommand_required(true) .after_help(AFTER_HELP.as_str()) - .arg(args::log_level::LogLevel::arg()) .arg(args::jobs::Jobs::arg()) + .arg(args::log_level::LogLevel::arg()) + .arg(args::raw::Raw::arg()) .arg(args::verbose::Verbose::arg()), ) } @@ -184,9 +185,16 @@ impl Cli { if let Some(jobs) = matches.get_one::("jobs") { config.settings.jobs = *jobs; } + if let Some(raw) = matches.get_one::("raw") { + config.settings.raw = *raw; + } if *matches.get_one::("verbose").unwrap() > 0 { config.settings.verbose = true; } + if config.settings.raw { + config.settings.jobs = 1; + config.settings.verbose = true; + } if let Some((command, sub_m)) = matches.subcommand() { external::execute(&config, command, sub_m, self.external_commands)?; } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1045d251a..56e3d2c9f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -419,10 +419,14 @@ plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable u verbose = false # set to true to see full installation output, see `RTX_VERBOSE` asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. +raw = false # set to true to directly pipe plugins to stdin/stdout/stderr shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` +experimental = false # enable experimental features such as shims +shims_dir = '~/.local/share/rtx/shims' # [experimental] directory where shims are stored + [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x # this can also be specified in a plugin (see below in "Aliases") @@ -498,6 +502,14 @@ Only output `.tool-versions` files in `rtx local|global` which will be usable by Set the number plugins or runtimes to install in parallel. The default is `4`. +#### `RTX_RAW=1` + +Set to "1" to directly pipe plugin scripts to stdin/stdout/stderr. By default stdin is disabled +because when installing a bunch of plugins in parallel you won't see the prompt. Use this if a +plugin accepts input or otherwise does not seem to be installing correctly. + +Sets `RTX_JOBS=1` because only 1 plugin script can be executed at a time. + #### `RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml` Use a custom file for the shorthand aliases. This is useful if you want to share plugins within @@ -531,6 +543,14 @@ You likely do not want to be using rtx if it is that old. I'm doing this instead autoupdating. If, for some reason, you want to stay on some old version, you can hide this message with `RTX_HIDE_OUTDATED_BUILD=1`. +#### `RTX_EXPERIMENTAL=1` + +Enables experimental features such as shims. + +#### [experimental] `RTX_SHIMS_DIR=~/.local/share/rtx/shims` + +Set a directory to output shims when running `rtx reshim`. Requires `experimental = true`. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 7f1f7403f..82b2a9207 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -41,7 +41,7 @@ impl Command for Reshim { let _ = remove_dir_all(&shims_dir); create_dir_all(&shims_dir)?; - for path in ts.list_paths() { + for path in ts.list_paths(&config.settings) { if !path.exists() { continue; } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 6bf79166f..e0a3450c2 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -35,6 +35,7 @@ impl Command for SettingsSet { "shorthands_file" => self.value.into(), "disable_default_shorthands" => parse_bool(&self.value)?, "shims_dir" => self.value.into(), + "raw" => parse_bool(&self.value)?, _ => return Err(eyre!("Unknown setting: {}", self.key)), }; diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 86bb9b3b0..2f0be12b2 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -13,4 +13,5 @@ jobs = 2 disable_default_shorthands = false log_level = INFO shims_dir = ~/data/shims +raw = false diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 493846431..502cb7cf5 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -13,4 +13,5 @@ jobs = 2 disable_default_shorthands = false log_level = INFO shims_dir = ~/data/shims +raw = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 0b86bcf8a..a08a02c96 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -59,6 +59,7 @@ mod tests { disable_default_shorthands = false log_level = INFO shims_dir = ~/data/shims + raw = false "###); reset_config(); diff --git a/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap b/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap index f30ed5926..13b480c7c 100644 --- a/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap +++ b/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap @@ -3,4 +3,5 @@ source: src/cli/bin_paths.rs expression: output --- ~/data/installs/tiny/3.1.0/bin +~/data/installs/dummy/ref-master/bin diff --git a/src/cli/snapshots/rtx__cli__current__tests__current.snap b/src/cli/snapshots/rtx__cli__current__tests__current.snap index b70b22a4c..f8468a445 100644 --- a/src/cli/snapshots/rtx__cli__current__tests__current.snap +++ b/src/cli/snapshots/rtx__cli__current__tests__current.snap @@ -3,4 +3,5 @@ source: src/cli/current.rs expression: output --- tiny 3.1.0 +dummy ref-master diff --git a/src/cli/snapshots/rtx__cli__which__tests__which.snap b/src/cli/snapshots/rtx__cli__which__tests__which.snap new file mode 100644 index 000000000..a92a17033 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__which__tests__which.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/which.rs +expression: output +--- +~/data/installs/dummy/1.0.0/bin/dummy + diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 2e0d9a5d9..f28bc842b 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -31,7 +31,7 @@ impl Command for Uninstall { } rtxprintln!(out, "uninstalling {}", style(rtv).cyan()); - rtv.uninstall() + rtv.uninstall(&config.settings) .wrap_err_with(|| eyre!("error uninstalling {}", rtv))?; } Ok(()) diff --git a/src/cli/which.rs b/src/cli/which.rs index 92a9a387e..21cf68918 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -18,16 +18,13 @@ pub struct Which { } impl Command for Which { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&config); - if !config.settings.experimental { - err_experimental()?; - } - - match ts.which(&self.bin_name) { + match ts.which(&config.settings, &self.bin_name) { Some(rtv) => { - println!("{}", rtv.which(&self.bin_name)?.unwrap().display()); + let path = rtv.which(&config.settings, &self.bin_name)?; + rtxprintln!(out, "{}", path.unwrap().display()); Ok(()) } None => Err(eyre!("{} not found", self.bin_name)), @@ -35,16 +32,6 @@ impl Command for Which { } } -fn err_experimental() -> Result<()> { - return Err(eyre!(formatdoc!( - r#" - rtx is not configured to use experimental features. - Please set the `{}` setting to `true`. - "#, - style("experimental").yellow() - ))); -} - static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} @@ -52,3 +39,16 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node "#, style("Examples:").bold().underlined()} }); + +#[cfg(test)] +mod tests { + use crate::{assert_cli, assert_cli_snapshot}; + + #[test] + fn test_which() { + assert_cli!("global", "dummy@1.0.0"); + assert_cli_snapshot!("which", "dummy"); + assert_cli!("global", "dummy@ref:master"); + assert_cli!("uninstall", "dummy@1.0.0"); + } +} diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index cd43820d8..2345128bc 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -106,6 +106,7 @@ impl RTXFile { } "log_level" => self.settings.log_level = Some(self.parse_log_level(v)?), "shims_dir" => self.settings.shims_dir = Some(self.parse_path(k, v)?), + "raw" => self.settings.raw = Some(self.parse_bool(k, v)?), "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), "get_path" => {} "disable_plugin_short_name_repository" => {} diff --git a/src/config/settings.rs b/src/config/settings.rs index 68b4b3311..28db1dca4 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -8,8 +8,8 @@ use log::LevelFilter; use crate::config::AliasMap; use crate::env; use crate::env::{ - RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_SHIMS_DIR, - RTX_SHORTHANDS_FILE, RTX_VERBOSE, + RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_RAW, + RTX_SHIMS_DIR, RTX_SHORTHANDS_FILE, RTX_VERBOSE, }; use crate::plugins::PluginName; @@ -28,6 +28,7 @@ pub struct Settings { pub disable_default_shorthands: bool, pub log_level: LevelFilter, pub shims_dir: Option, + pub raw: bool, } impl Default for Settings { @@ -46,6 +47,7 @@ impl Default for Settings { disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, log_level: *RTX_LOG_LEVEL, shims_dir: RTX_SHIMS_DIR.clone(), + raw: *RTX_RAW, } } } @@ -87,6 +89,7 @@ impl Settings { if let Some(shims) = &self.shims_dir { map.insert("shims_dir".into(), shims.to_string_lossy().to_string()); } + map.insert("raw".into(), self.raw.to_string()); map } } @@ -106,6 +109,7 @@ pub struct SettingsBuilder { pub disable_default_shorthands: Option, pub log_level: Option, pub shims_dir: Option, + pub raw: Option, } impl SettingsBuilder { @@ -156,6 +160,9 @@ impl SettingsBuilder { if other.aliases.is_some() { self.aliases = other.aliases; } + if other.raw.is_some() { + self.raw = other.raw; + } self } @@ -194,8 +201,14 @@ impl SettingsBuilder { .unwrap_or(settings.disable_default_shorthands); settings.log_level = self.log_level.unwrap_or(settings.log_level); settings.shims_dir = self.shims_dir.clone().or(settings.shims_dir); + settings.raw = self.raw.unwrap_or(settings.raw); settings.aliases = self.aliases.clone().unwrap_or(settings.aliases); + if settings.raw { + settings.verbose = true; + settings.jobs = 1; + } + settings } } diff --git a/src/env.rs b/src/env.rs index 859e96162..03164dbf8 100644 --- a/src/env.rs +++ b/src/env.rs @@ -102,10 +102,7 @@ lazy_static! { pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); pub static ref RTX_VERBOSE: bool = *RTX_DEBUG || *RTX_TRACE || var_is_true("RTX_VERBOSE"); pub static ref DUMB_TERMINAL: bool = cfg!(test) || var("TERM").map_or(false, |term| term == "dumb"); - pub static ref RTX_JOBS: usize = var("RTX_JOBS") - .ok() - .and_then(|v| v.parse::().ok()) - .unwrap_or(4); + pub static ref RTX_JOBS: usize = var("RTX_JOBS").ok().and_then(|v| v.parse::().ok()).unwrap_or(4); /// essentially, this is whether we show spinners or build output on runtime install pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); @@ -126,6 +123,7 @@ lazy_static! { pub static ref RTX_SHORTHANDS_FILE: Option = var_path("RTX_SHORTHANDS_FILE"); pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); pub static ref RTX_SHIMS_DIR: Option = var_path("RTX_SHIMS_DIR"); + pub static ref RTX_RAW: bool = var_is_true("RTX_RAW"); pub static ref GITHUB_API_TOKEN: Option = var("GITHUB_API_TOKEN").ok(); } @@ -223,12 +221,13 @@ fn prefer_stale(args: &[String]) -> bool { #[cfg(test)] mod tests { - use super::*; use std::collections::HashMap; use crate::env::apply_patches; use crate::env_diff::EnvDiffOperation; + use super::*; + #[test] fn test_apply_patches() { let mut env = HashMap::new(); diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 4dd62747c..e15f2929c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -297,7 +297,7 @@ impl Plugin { fn fetch_remote_versions(&self, settings: &Settings) -> Result> { let result = self .script_man - .cmd(Script::ListAll) + .cmd(settings, Script::ListAll) .stdout_capture() .stderr_capture() .unchecked() @@ -334,7 +334,7 @@ impl Plugin { } Ok(self .script_man - .read(Script::ListLegacyFilenames, settings.verbose)? + .read(settings, Script::ListLegacyFilenames, settings.verbose)? .split_whitespace() .map(|v| v.into()) .collect()) @@ -355,7 +355,7 @@ impl Plugin { } let stdout = self .script_man - .read(Script::ListAliases, settings.verbose)?; + .read(settings, Script::ListAliases, settings.verbose)?; let aliases = stdout .lines() .filter_map(|line| { @@ -380,7 +380,7 @@ impl Plugin { trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); let legacy_version = match self.script_man.script_exists(&script) { - true => self.script_man.read(script, settings.verbose)?, + true => self.script_man.read(settings, script, settings.verbose)?, false => fs::read_to_string(legacy_file)?, } .trim() diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 994e177e8..006a28a10 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -11,6 +11,7 @@ use indexmap::{indexmap, IndexMap}; use once_cell::sync::Lazy; use crate::cmd::cmd; +use crate::config::Settings; use crate::env; use crate::errors::Error::ScriptFailed; use crate::file::basename; @@ -43,7 +44,7 @@ pub enum Script { // ExecEnv, } -impl fmt::Display for Script { +impl Display for Script { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { // Plugin @@ -120,7 +121,7 @@ impl ScriptManager { self.get_script_path(script).is_file() } - pub fn cmd(&self, script: Script) -> Expression { + pub fn cmd(&self, settings: &Settings, script: Script) -> Expression { let args = match &script { Script::ParseLegacyFile(filename) => vec![filename.clone()], _ => vec![], @@ -130,14 +131,18 @@ impl ScriptManager { // return Err(PluginNotInstalled(self.plugin_name.clone()).into()); // } let mut cmd = cmd(&script_path, args); + if !settings.raw { + // ignore stdin, otherwise a prompt may show up where the user won't see it + cmd = cmd.stdin_null(); + } for (k, v) in self.env.iter() { cmd = cmd.env(k, v); } cmd } - pub fn run(&self, script: Script) -> Result<()> { - let cmd = self.cmd(script); + pub fn run(&self, settings: &Settings, script: Script) -> Result<()> { + let cmd = self.cmd(settings, script); let Output { status, .. } = cmd.unchecked().run()?; match status.success() { @@ -146,42 +151,60 @@ impl ScriptManager { } } - pub fn read(&self, script: Script, verbose: bool) -> Result { - let mut cmd = self.cmd(script); - if !verbose { + pub fn read(&self, settings: &Settings, script: Script, verbose: bool) -> Result { + let mut cmd = self.cmd(settings, script); + if !verbose && !settings.raw { cmd = cmd.stderr_null(); } cmd.read() .with_context(|| ScriptFailed(self.plugin_name.clone(), None)) } - pub fn run_by_line(&self, script: Script, on_error: F1, on_output: F2) -> Result<()> + pub fn run_by_line( + &self, + settings: &Settings, + script: Script, + on_error: F1, + on_output: F2, + ) -> Result<()> where F1: Fn(String), F2: Fn(&str), { - let reader = self.cmd(script).stderr_to_stdout().unchecked().reader()?; - let reader = Arc::new(reader); + let cmd = self.cmd(settings, script); let mut output = vec![]; - for line in BufReader::new(&*reader).lines() { - let line = line.unwrap(); - on_output(&line); - output.push(line); - } - - match reader.try_wait() { - Err(err) => { - on_error(output.join("\n")); - Err(err)? - } - Ok(out) => match out.unwrap().status.success() { + if settings.raw { + let Output { status, .. } = cmd.unchecked().run()?; + match status.success() { true => Ok(()), false => { on_error(output.join("\n")); - let err = ScriptFailed(self.plugin_name.clone(), Some(out.unwrap().status)); + Err(ScriptFailed(self.plugin_name.clone(), Some(status)).into()) + } + } + } else { + let reader = cmd.stdin_null().stderr_to_stdout().unchecked().reader()?; + let reader = Arc::new(reader); + for line in BufReader::new(&*reader).lines() { + let line = line.unwrap(); + on_output(&line); + output.push(line); + } + + match reader.try_wait() { + Err(err) => { + on_error(output.join("\n")); Err(err)? } - }, + Ok(out) => match out.unwrap().status.success() { + true => Ok(()), + false => { + on_error(output.join("\n")); + let err = ScriptFailed(self.plugin_name.clone(), Some(out.unwrap().status)); + Err(err)? + } + }, + } } } } diff --git a/src/runtimes.rs b/src/runtimes.rs index 3defafb4b..8bf6cbcce 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -93,6 +93,7 @@ impl RuntimeVersion { let run_script = |script| { self.script_man.run_by_line( + settings, script, |output| { self.cleanup_install_dirs_on_error(settings); @@ -134,17 +135,17 @@ impl RuntimeVersion { Ok(()) } - pub fn list_bin_paths(&self) -> Result> { + pub fn list_bin_paths(&self, settings: &Settings) -> Result> { Ok(self .bin_paths_cache - .get_or_try_init(|| self.fetch_bin_paths())? + .get_or_try_init(|| self.fetch_bin_paths(settings))? .iter() .map(|path| self.install_path.join(path)) .collect()) } - pub fn which(&self, bin_name: &str) -> Result> { - let bin_paths = self.list_bin_paths()?; + pub fn which(&self, settings: &Settings, bin_name: &str) -> Result> { + let bin_paths = self.list_bin_paths(settings)?; for bin_path in bin_paths { let bin_path = bin_path.join(bin_name); if bin_path.exists() { @@ -164,10 +165,10 @@ impl RuntimeVersion { } } - pub fn uninstall(&self) -> Result<()> { + pub fn uninstall(&self, settings: &Settings) -> Result<()> { debug!("uninstall {} {}", self.plugin.name, self.version); if self.plugin.plugin_path.join("bin/uninstall").exists() { - let err = self.script_man.run(Script::Uninstall); + let err = self.script_man.run(settings, Script::Uninstall); if err.is_err() { warn!("Failed to run uninstall script: {}", err.unwrap_err()); } @@ -209,10 +210,10 @@ impl RuntimeVersion { Ok(env) } - fn fetch_bin_paths(&self) -> Result> { + fn fetch_bin_paths(&self, settings: &Settings) -> Result> { let list_bin_paths = self.plugin.plugin_path.join("bin/list-bin-paths"); if list_bin_paths.exists() { - let output = self.script_man.cmd(Script::ListBinPaths).read()?; + let output = self.script_man.cmd(settings, Script::ListBinPaths).read()?; Ok(output.split_whitespace().map(|e| e.into()).collect()) } else { Ok(vec!["bin".into()]) diff --git a/src/shims.rs b/src/shims.rs index 80a9bd69b..0c0034a18 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -29,7 +29,7 @@ pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result< fn is_valid_shim(config: &Config, bin_name: &str) -> Result<()> { let ts = ToolsetBuilder::new().build(config); - match ts.which(bin_name) { + match ts.which(&config.settings, bin_name) { Some(_) => Ok(()), None => Err(eyre!("{} is not a valid shim", bin_name)), } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 9fa174f54..44c7608c1 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -19,7 +19,7 @@ pub use tool_version::ToolVersion; pub use tool_version::ToolVersionType; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; -use crate::config::{Config, MissingRuntimeBehavior}; +use crate::config::{Config, MissingRuntimeBehavior, Settings}; use crate::env; use crate::plugins::{InstallType, Plugin, PluginName}; use crate::runtimes::RuntimeVersion; @@ -274,17 +274,17 @@ impl Toolset { entries.sort_keys(); entries } - pub fn path_env(&self) -> String { - let installs = self.list_paths(); + pub fn path_env(&self, settings: &Settings) -> String { + let installs = self.list_paths(settings); join_paths([installs, env::PATH.clone()].concat()) .unwrap() .to_string_lossy() .into() } - pub fn list_paths(&self) -> Vec { + pub fn list_paths(&self, settings: &Settings) -> Vec { self.list_current_installed_versions() .into_par_iter() - .flat_map(|rtv| match rtv.list_bin_paths() { + .flat_map(|rtv| match rtv.list_bin_paths(settings) { Ok(paths) => paths, Err(e) => { warn!("Error listing bin paths for {}: {}", rtv, e); @@ -358,11 +358,11 @@ impl Toolset { } } - pub fn which(&self, bin_name: &str) -> Option<&RuntimeVersion> { + pub fn which(&self, settings: &Settings, bin_name: &str) -> Option<&RuntimeVersion> { self.list_current_installed_versions() .into_par_iter() .find_first(|v| { - if let Ok(x) = v.which(bin_name) { + if let Ok(x) = v.which(settings, bin_name) { x.is_some() } else { false diff --git a/test/.test-tool-versions b/test/.test-tool-versions index 84c0668d0..1d1e5cb84 100644 --- a/test/.test-tool-versions +++ b/test/.test-tool-versions @@ -1 +1,2 @@ -tiny 2 +tiny 2 +dummy ref:master From 85f797f807c45dcabbec9ffdc41cf76302c00950 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 21:53:43 -0600 Subject: [PATCH 0325/1891] chore: disable colors in manpages (#231) --- justfile | 10 +++++----- man/man1/rtx.1 | 2 +- src/cli/mangen.rs | 4 +++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/justfile b/justfile index 7b477eff3..c32c0996e 100644 --- a/justfile +++ b/justfile @@ -75,18 +75,18 @@ lint-fix: # regenerate README.md render-help: build - rtx render-help > README.md + NO_COLOR=1 rtx render-help > README.md ./scripts/gh-md-toc --insert --no-backup --hide-footer --skip-header README.md > /dev/null # regenerate shell completion files render-completions: build - rtx complete -s bash > completions/rtx.bash - rtx complete -s zsh > completions/_rtx - rtx complete -s fish > completions/rtx.fish + NO_COLOR=1 rtx complete -s bash > completions/rtx.bash + NO_COLOR=1 rtx complete -s zsh > completions/_rtx + NO_COLOR=1 rtx complete -s fish > completions/rtx.fish # regenerate manpages render-mangen: build - rtx mangen + NO_COLOR=1 rtx mangen # called by husky precommit hook pre-commit: render-help render-completions render-mangen diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index dec20e2d2..48acb7ad5 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -116,7 +116,7 @@ shows the plugin that a bin points to rtx\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA -Examples: +Examples: rtx install nodejs@18.0.0 Install a specific node version rtx install nodejs@18.0 Install a version matching a prefix rtx local nodejs@18 Use node\-18.x in current project diff --git a/src/cli/mangen.rs b/src/cli/mangen.rs index 9152a7012..f7bda1d6c 100644 --- a/src/cli/mangen.rs +++ b/src/cli/mangen.rs @@ -13,7 +13,9 @@ pub struct Mangen {} impl Command for Mangen { fn run(self, _config: Config, _out: &mut Output) -> Result<()> { - let cli = Cli::command().version(env!("CARGO_PKG_VERSION")); + let cli = Cli::command() + .version(env!("CARGO_PKG_VERSION")) + .disable_colored_help(true); let man = clap_mangen::Man::new(cli); let mut buffer: Vec = Default::default(); From b91f86bd667fcab5f763043f3f592f9f519316a5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 22:22:23 -0600 Subject: [PATCH 0326/1891] chore: remove lefthook scripts these should not have been added --- .husky/pre-commit | 42 --------------------------------------- .husky/prepare-commit-msg | 42 --------------------------------------- 2 files changed, 84 deletions(-) delete mode 100755 .husky/pre-commit delete mode 100755 .husky/prepare-commit-msg diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index dc93a034b..000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -if [ "$LEFTHOOK" = "0" ]; then - exit 0 -fi - -call_lefthook() -{ - dir="$(git rev-parse --show-toplevel)" - osArch=$(echo "$(uname)" | tr '[:upper:]' '[:lower:]') - cpuArch=$(echo "$(uname -m)" | sed 's/aarch64/arm64/') - - if lefthook -h >/dev/null 2>&1 - then - eval lefthook $@ - elif test -f "$dir/node_modules/lefthook/bin/index.js" - then - eval "\"$dir/node_modules/lefthook/bin/index.js\" $@" - elif test -f "$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook" - then - eval "\"$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" - elif test -f "$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook" - then - eval "\"$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" - elif bundle exec lefthook -h >/dev/null 2>&1 - then - bundle exec lefthook $@ - elif yarn lefthook -h >/dev/null 2>&1 - then - yarn lefthook $@ - elif pnpm lefthook -h >/dev/null 2>&1 - then - pnpm lefthook $@ - elif npx @evilmartians/lefthook -h >/dev/null 2>&1 - then - npx @evilmartians/lefthook $@ - else - echo "Can't find lefthook in PATH" - fi -} - -call_lefthook "run pre-commit $@" diff --git a/.husky/prepare-commit-msg b/.husky/prepare-commit-msg deleted file mode 100755 index ea81fa901..000000000 --- a/.husky/prepare-commit-msg +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -if [ "$LEFTHOOK" = "0" ]; then - exit 0 -fi - -call_lefthook() -{ - dir="$(git rev-parse --show-toplevel)" - osArch=$(echo "$(uname)" | tr '[:upper:]' '[:lower:]') - cpuArch=$(echo "$(uname -m)" | sed 's/aarch64/arm64/') - - if lefthook -h >/dev/null 2>&1 - then - eval lefthook $@ - elif test -f "$dir/node_modules/lefthook/bin/index.js" - then - eval "\"$dir/node_modules/lefthook/bin/index.js\" $@" - elif test -f "$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook" - then - eval "\"$dir/node_modules/@evilmartians/lefthook/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" - elif test -f "$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook" - then - eval "\"$dir/node_modules/@evilmartians/lefthook-installer/bin/lefthook_${osArch}_${cpuArch}/lefthook\" $@" - elif bundle exec lefthook -h >/dev/null 2>&1 - then - bundle exec lefthook $@ - elif yarn lefthook -h >/dev/null 2>&1 - then - yarn lefthook $@ - elif pnpm lefthook -h >/dev/null 2>&1 - then - pnpm lefthook $@ - elif npx @evilmartians/lefthook -h >/dev/null 2>&1 - then - npx @evilmartians/lefthook $@ - else - echo "Can't find lefthook in PATH" - fi -} - -call_lefthook "run prepare-commit-msg $@" From ceadd3ed16e0585268b260640982caa79e76ba91 Mon Sep 17 00:00:00 2001 From: Neeraj Jaiswal Date: Tue, 28 Feb 2023 10:51:41 +0530 Subject: [PATCH 0327/1891] docs: Fix readme shims_dir config name (#232) * Fix readme shims_dir config name * docs: correct shims_dir setting name --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fe4613bc5..7c7e64e5b 100644 --- a/README.md +++ b/README.md @@ -1625,7 +1625,7 @@ To support this, there is experimental support for using rtx in a "shim" mode. T ``` $ rtx settings set experimental true -$ rtx settings set shim_dir ~/.rtx/shims +$ rtx settings set shims_dir ~/.rtx/shims $ rtx i nodejs@18.0.0 $ rtx reshim $ ~/.rtx/shims/node -v diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 56e3d2c9f..9ae350d6c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -755,7 +755,7 @@ To support this, there is experimental support for using rtx in a "shim" mode. T ``` $ rtx settings set experimental true -$ rtx settings set shim_dir ~/.rtx/shims +$ rtx settings set shims_dir ~/.rtx/shims $ rtx i nodejs@18.0.0 $ rtx reshim $ ~/.rtx/shims/node -v From f928abe658c2cbd16f2e13e088d3692d5d0c4bb4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 23:28:37 -0600 Subject: [PATCH 0328/1891] chore: added RTX_EXPERIMENTAL env var (#233) --- src/config/settings.rs | 7 ++----- src/env.rs | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/config/settings.rs b/src/config/settings.rs index 28db1dca4..728ca821a 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -7,10 +7,7 @@ use log::LevelFilter; use crate::config::AliasMap; use crate::env; -use crate::env::{ - RTX_ASDF_COMPAT, RTX_DISABLE_DEFAULT_SHORTHANDS, RTX_JOBS, RTX_LOG_LEVEL, RTX_RAW, - RTX_SHIMS_DIR, RTX_SHORTHANDS_FILE, RTX_VERBOSE, -}; +use crate::env::*; use crate::plugins::PluginName; #[derive(Debug, Clone)] @@ -34,7 +31,7 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { Self { - experimental: false, + experimental: *RTX_EXPERIMENTAL, missing_runtime_behavior: MissingRuntimeBehavior::Prompt, always_keep_download: false, legacy_version_file: true, diff --git a/src/env.rs b/src/env.rs index 03164dbf8..f6d65afe8 100644 --- a/src/env.rs +++ b/src/env.rs @@ -117,6 +117,7 @@ lazy_static! { }; pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); + pub static ref RTX_EXPERIMENTAL: bool = var_is_true("RTX_EXPERIMENTAL"); pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); pub static ref RTX_PREFER_STALE: bool = prefer_stale(&ARGS); pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); From f953a5e1f74725399a8d766ce055c898dee503aa Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Feb 2023 23:48:40 -0600 Subject: [PATCH 0329/1891] feat: added `rtx which --version` and `--plugin` (#234) --- README.md | 26 +++++++----- completions/_rtx | 24 ++++++----- completions/rtx.bash | 2 +- completions/rtx.fish | 22 +++++----- man/man1/rtx.1 | 10 ++--- src/cli/env.rs | 5 +-- src/cli/implode.rs | 2 +- src/cli/latest.rs | 2 +- src/cli/mod.rs | 13 +++--- src/cli/shell.rs | 2 +- .../rtx__cli__which__tests__which_plugin.snap | 6 +++ ...rtx__cli__which__tests__which_version.snap | 6 +++ src/cli/which.rs | 40 +++++++++++++++++-- 13 files changed, 106 insertions(+), 54 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap create mode 100644 src/cli/snapshots/rtx__cli__which__tests__which_version.snap diff --git a/README.md b/README.md index 7c7e64e5b..1bf5998f4 100644 --- a/README.md +++ b/README.md @@ -922,13 +922,10 @@ Examples: ### `rtx env` ``` -exports env vars to activate rtx in a single shell session +Exports env vars to activate rtx a single time Use this if you don't want to permanently install rtx. It's not necessary to use this if you have `rtx activate` in your shell rc file. -This can be used similarly to `asdf shell`. It requires `eval` to work since -it's not written in Bash. -It's also useful just to see what environment variables rtx sets. Usage: env [OPTIONS] [RUNTIME]... @@ -1033,7 +1030,7 @@ Examples: ### `rtx implode` ``` -Removes rtx CLI and all generated data +Removes rtx CLI and all related data Skips config directory by default. @@ -1086,7 +1083,7 @@ Examples: ### `rtx latest` ``` -Get the latest runtime version of a plugin's runtimes +Gets the latest available version for a plugin Usage: latest @@ -1442,7 +1439,7 @@ Examples: ### `rtx shell` ``` -sets a runtime for the current shell session +Sets a tool version for the current shell session Only works in a session where rtx is already activated. @@ -1506,17 +1503,28 @@ Examples: ### `rtx which` ``` -shows the plugin that a bin points to +Shows the path that a bin name points to -Usage: which +Usage: which [OPTIONS] Arguments: +Options: + --plugin + Show the plugin name instead of the path + + --version + Show the version instead of the path + Examples: $ rtx which node /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node + $ rtx which node --plugin + nodejs + $ rtx which node --version + 18.0.0 ``` ## Comparison to asdf diff --git a/completions/_rtx b/completions/_rtx index b2822f53a..40b799fc9 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -956,6 +956,8 @@ _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'(--version)--plugin[Show the plugin name instead of the path]' \ +'(--plugin)--version[Show the version instead of the path]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ @@ -1269,17 +1271,17 @@ _rtx_commands() { 'deactivate:Disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ -'env:exports env vars to activate rtx in a single shell session' \ -'e:exports env vars to activate rtx in a single shell session' \ +'env:Exports env vars to activate rtx a single time' \ +'e:Exports env vars to activate rtx a single time' \ 'exec:Execute a command with runtime(s) set' \ 'x:Execute a command with runtime(s) set' \ 'global:Sets global .tool-versions to include a specified runtime' \ 'g:Sets global .tool-versions to include a specified runtime' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ -'implode:Removes rtx CLI and all generated data' \ +'implode:Removes rtx CLI and all related data' \ 'install:Install a runtime' \ 'i:Install a runtime' \ -'latest:Get the latest runtime version of a plugin'\''s runtimes' \ +'latest:Gets the latest available version for a plugin' \ 'local:Sets .tool-versions to include a specific runtime' \ 'l:Sets .tool-versions to include a specific runtime' \ 'ls:List installed runtime versions' \ @@ -1292,11 +1294,11 @@ _rtx_commands() { 'reshim:\[experimental\] rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ -'shell:sets a runtime for the current shell session' \ +'shell:Sets a tool version for the current shell session' \ 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ -'which:shows the plugin that a bin points to' \ +'which:Shows the path that a bin name points to' \ 'render-help:internal command to generate markdown from help' \ 'help:Print this message or the help of the given subcommand(s)' \ ) @@ -1626,13 +1628,13 @@ _rtx__help_commands() { 'deactivate:Disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ -'env:exports env vars to activate rtx in a single shell session' \ +'env:Exports env vars to activate rtx a single time' \ 'exec:Execute a command with runtime(s) set' \ 'global:Sets global .tool-versions to include a specified runtime' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ -'implode:Removes rtx CLI and all generated data' \ +'implode:Removes rtx CLI and all related data' \ 'install:Install a runtime' \ -'latest:Get the latest runtime version of a plugin'\''s runtimes' \ +'latest:Gets the latest available version for a plugin' \ 'local:Sets .tool-versions to include a specific runtime' \ 'ls:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ @@ -1641,11 +1643,11 @@ _rtx__help_commands() { 'reshim:\[experimental\] rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ -'shell:sets a runtime for the current shell session' \ +'shell:Sets a tool version for the current shell session' \ 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ -'which:shows the plugin that a bin points to' \ +'which:Shows the path that a bin name points to' \ 'render-help:internal command to generate markdown from help' \ 'help:Print this message or the help of the given subcommand(s)' \ ) diff --git a/completions/rtx.bash b/completions/rtx.bash index 4b1755ba0..3ec021a52 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2884,7 +2884,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --plugin --version --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index f770a2e1e..7eb044004 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -14,13 +14,13 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows current act complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'Disable rtx for current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'Exports env vars to activate rtx a single time' complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with runtime(s) set' complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest available version for a plugin' complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' @@ -29,11 +29,11 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] rebuilds the shim farm' complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'sets a runtime for the current shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'shows the plugin that a bin points to' +complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" @@ -353,6 +353,8 @@ complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' +complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' @@ -371,13 +373,13 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'exports env vars to activate rtx in a single shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all generated data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Get the latest runtime version of a plugin\'s runtimes' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' @@ -386,11 +388,11 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'sets a runtime for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'shows the plugin that a bin points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 48acb7ad5..70743c7f8 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -60,7 +60,7 @@ rtx\-doctor(1) Check rtx installation for possible problems. .TP rtx\-env(1) -exports env vars to activate rtx in a single shell session +Exports env vars to activate rtx a single time .TP rtx\-exec(1) Execute a command with runtime(s) set @@ -69,13 +69,13 @@ rtx\-global(1) Sets global .tool\-versions to include a specified runtime .TP rtx\-implode(1) -Removes rtx CLI and all generated data +Removes rtx CLI and all related data .TP rtx\-install(1) Install a runtime .TP rtx\-latest(1) -Get the latest runtime version of a plugin\*(Aqs runtimes +Gets the latest available version for a plugin .TP rtx\-local(1) Sets .tool\-versions to include a specific runtime @@ -99,7 +99,7 @@ rtx\-settings(1) Manage settings .TP rtx\-shell(1) -sets a runtime for the current shell session +Sets a tool version for the current shell session .TP rtx\-uninstall(1) Removes runtime versions @@ -111,7 +111,7 @@ rtx\-where(1) Display the installation path for a runtime .TP rtx\-which(1) -shows the plugin that a bin points to +Shows the path that a bin name points to .TP rtx\-help(1) Print this message or the help of the given subcommand(s) diff --git a/src/cli/env.rs b/src/cli/env.rs index b8d3b12ec..bd3972e11 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -10,13 +10,10 @@ use crate::output::Output; use crate::shell::{get_shell, ShellType}; use crate::toolset::ToolsetBuilder; -/// exports env vars to activate rtx in a single shell session +/// Exports env vars to activate rtx a single time /// /// Use this if you don't want to permanently install rtx. It's not necessary to /// use this if you have `rtx activate` in your shell rc file. -/// This can be used similarly to `asdf shell`. It requires `eval` to work since -/// it's not written in Bash. -/// It's also useful just to see what environment variables rtx sets. #[derive(Debug, clap::Args)] #[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Env { diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 98680bd75..a57e8e2f1 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -5,7 +5,7 @@ use crate::config::Config; use crate::output::Output; use crate::{dirs, env}; -/// Removes rtx CLI and all generated data +/// Removes rtx CLI and all related data /// /// Skips config directory by default. #[derive(Debug, clap::Args)] diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 671b9b735..8b890baf3 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -8,7 +8,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -/// Get the latest runtime version of a plugin's runtimes +/// Gets the latest available version for a plugin #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Latest { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 8c4165efb..03f2110e9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -32,7 +32,11 @@ mod latest; mod local; mod ls; mod ls_remote; +#[cfg(feature = "clap_mangen")] +mod mangen; mod plugins; +#[cfg(debug_assertions)] +mod render_help; mod reshim; mod self_update; mod settings; @@ -40,14 +44,7 @@ mod shell; mod uninstall; pub mod version; mod r#where; -mod which; - -// render help -#[cfg(debug_assertions)] -mod render_help; - -#[cfg(feature = "clap_mangen")] -mod mangen; +mod r#which; pub struct Cli { command: clap::Command, diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 35c5e002e..92877d5bd 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -15,7 +15,7 @@ use crate::output::Output; use crate::shell::get_shell; use crate::toolset::{ToolSource, ToolsetBuilder}; -/// sets a runtime for the current shell session +/// Sets a tool version for the current shell session /// /// Only works in a session where rtx is already activated. #[derive(Debug, clap::Args)] diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap b/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap new file mode 100644 index 000000000..6c335017f --- /dev/null +++ b/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/which.rs +expression: output +--- +dummy + diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_version.snap b/src/cli/snapshots/rtx__cli__which__tests__which_version.snap new file mode 100644 index 000000000..7915230b0 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__which__tests__which_version.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/which.rs +expression: output +--- +1.0.0 + diff --git a/src/cli/which.rs b/src/cli/which.rs index 21cf68918..998a3192c 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -9,12 +9,20 @@ use crate::config::Config; use crate::output::Output; use crate::toolset::ToolsetBuilder; -/// shows the plugin that a bin points to +/// Shows the path that a bin name points to #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Which { #[clap()] pub bin_name: String, + + /// Show the plugin name instead of the path + #[clap(long, conflicts_with = "version")] + pub plugin: bool, + + /// Show the version instead of the path + #[clap(long, conflicts_with = "plugin")] + pub version: bool, } impl Command for Which { @@ -23,8 +31,14 @@ impl Command for Which { match ts.which(&config.settings, &self.bin_name) { Some(rtv) => { - let path = rtv.which(&config.settings, &self.bin_name)?; - rtxprintln!(out, "{}", path.unwrap().display()); + if self.version { + rtxprintln!(out, "{}", rtv.version); + } else if self.plugin { + rtxprintln!(out, "{}", rtv.plugin.name); + } else { + let path = rtv.which(&config.settings, &self.bin_name)?; + rtxprintln!(out, "{}", path.unwrap().display()); + } Ok(()) } None => Err(eyre!("{} not found", self.bin_name)), @@ -37,6 +51,10 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { {} $ rtx which node /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node + $ rtx which node --plugin + nodejs + $ rtx which node --version + 18.0.0 "#, style("Examples:").bold().underlined()} }); @@ -51,4 +69,20 @@ mod tests { assert_cli!("global", "dummy@ref:master"); assert_cli!("uninstall", "dummy@1.0.0"); } + + #[test] + fn test_which_plugin() { + assert_cli!("global", "dummy@1.0.0"); + assert_cli_snapshot!("which", "--plugin", "dummy"); + assert_cli!("global", "dummy@ref:master"); + assert_cli!("uninstall", "dummy@1.0.0"); + } + + #[test] + fn test_which_version() { + assert_cli!("global", "dummy@1.0.0"); + assert_cli_snapshot!("which", "--version", "dummy"); + assert_cli!("global", "dummy@ref:master"); + assert_cli!("uninstall", "dummy@1.0.0"); + } } From ada812bb9b97b74be5a7434b70df960e5c01d3bc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 08:25:39 -0600 Subject: [PATCH 0330/1891] chore: Release rtx-cli version 1.19.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6c8dc74a..c8a1bfa78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.18.2" +version = "1.19.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index fdaf70a5e..22b887dbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.18.2" +version = "1.19.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 1bf5998f4..358b29067 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.18.2 +rtx 1.19.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -310,7 +310,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.2/rtx-v1.18.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.0/rtx-v1.19.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 70743c7f8..58aa52039 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.18.2" +.TH rtx 1 "rtx 1.19.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -129,6 +129,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.18.2 +v1.19.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index be1daf61c..e04a5c6e0 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.18.2 +Version: 1.19.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9ae350d6c..cb107aa78 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -232,7 +232,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.18.2/rtx-v1.18.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.0/rtx-v1.19.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From 11a487fc3a0429776d0f57dede25aa8ffe01bd28 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 10:55:06 -0600 Subject: [PATCH 0331/1891] docs: direnv --- README.md | 14 ++++++++------ src/cli/render_help.rs | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 358b29067..b21cc5c04 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv, you will want to activate direnv _before_ rtx. There is also -> an alternative way to use rtx inside of direnv, see [here](#direnv). +> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your .envrc. +> There is also an alternative way to use rtx inside of direnv, see [here](#direnv). Install a runtime and set it as the default: @@ -1657,14 +1657,14 @@ in it as well. A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated binaries to PATH. In these cases, rtx will not interfere with direnv. -As mentioned in the Quick Start, it is important to make sure that `rtx activate` is called after `direnv hook` -in the shell rc file. rtx overrides some of the internal direnv state (`DIRENV_DIFF`) so calling -direnv first gives rtx the opportunity to make those changes to direnv's state. +As mentioned in the Quick Start, calling `eval "$(rtx env -s bash)"` will add rtx runtimes +into an .envrc file. This is useful for `layout python` which should be using the +rtx python version. This isn't necessary unless the envrc needs access to a runtime. ### rtx inside of direnv (`use rtx` in `.envrc`) If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, -this is a simpler setup that's less likely to cause issues. +this is a simpler setup that's less likely to cause issues—at the cost of functionality. To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: @@ -1695,6 +1695,8 @@ export RTX_PYTHON_VERSION=3.11 Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx as if direnv was not used. +If you continue to struggle, you can also try using the [experimental shims feature](#shims). + ## Cache Behavior rtx makes use of caching in many places in order to be efficient. The details about how long to keep diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index cb107aa78..9a6556157 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -74,8 +74,8 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv, you will want to activate direnv _before_ rtx. There is also -> an alternative way to use rtx inside of direnv, see [here](#direnv). +> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your .envrc. +> There is also an alternative way to use rtx inside of direnv, see [here](#direnv). Install a runtime and set it as the default: @@ -779,14 +779,14 @@ in it as well. A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated binaries to PATH. In these cases, rtx will not interfere with direnv. -As mentioned in the Quick Start, it is important to make sure that `rtx activate` is called after `direnv hook` -in the shell rc file. rtx overrides some of the internal direnv state (`DIRENV_DIFF`) so calling -direnv first gives rtx the opportunity to make those changes to direnv's state. +As mentioned in the Quick Start, calling `eval "$(rtx env -s bash)"` will add rtx runtimes +into an .envrc file. This is useful for `layout python` which should be using the +rtx python version. This isn't necessary unless the envrc needs access to a runtime. ### rtx inside of direnv (`use rtx` in `.envrc`) If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, -this is a simpler setup that's less likely to cause issues. +this is a simpler setup that's less likely to cause issues—at the cost of functionality. To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: @@ -817,6 +817,8 @@ export RTX_PYTHON_VERSION=3.11 Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx as if direnv was not used. +If you continue to struggle, you can also try using the [experimental shims feature](#shims). + ## Cache Behavior rtx makes use of caching in many places in order to be efficient. The details about how long to keep From 3900f0bad1a1f9fbad100c95e63686539f1a1e50 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 10:55:06 -0600 Subject: [PATCH 0332/1891] docs: direnv --- README.md | 4 +++- src/cli/render_help.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b21cc5c04..bb786b324 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,9 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your .envrc. +> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your +> .envrc for `layout python` to work or for other logic that needs to reference rtx +> runtimes. > There is also an alternative way to use rtx inside of direnv, see [here](#direnv). Install a runtime and set it as the default: diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9a6556157..c4be5767f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -74,7 +74,9 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your .envrc. +> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your +> .envrc for `layout python` to work or for other logic that needs to reference rtx +> runtimes. > There is also an alternative way to use rtx inside of direnv, see [here](#direnv). Install a runtime and set it as the default: From c314d0f7c49477e70b2d0c21b7be1123651705ea Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:04:07 -0600 Subject: [PATCH 0333/1891] chore: sign on release --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22b887dbe..1c635e0d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,8 +95,8 @@ strip = "symbols" [package.metadata.release] allow-branch = ["main"] -#sign-tag = true -#sign-commit = true +sign-tag = true +sign-commit = true pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, From 26cef6025fdf57131ee9b7c4b350a4cb4cbf8f48 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 15:12:43 -0600 Subject: [PATCH 0334/1891] docs: styling of command help --- README.md | 48 ++++++++------------------- completions/_rtx | 63 +++++++++++++++++++++++------------- completions/rtx.fish | 24 ++++++++------ src/cli/current.rs | 1 - src/cli/exec.rs | 1 - src/cli/global.rs | 5 +-- src/cli/install.rs | 2 -- src/cli/local.rs | 5 +-- src/cli/plugins/install.rs | 3 -- src/cli/plugins/ls.rs | 4 +-- src/cli/plugins/ls_remote.rs | 1 - src/cli/where.rs | 7 ++-- 12 files changed, 77 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index bb786b324..637f39253 100644 --- a/README.md +++ b/README.md @@ -858,9 +858,7 @@ Usage: current [PLUGIN] Arguments: [PLUGIN] - Plugin to show versions of - - e.g.: ruby, nodejs + Plugin to show versions of e.g.: ruby, nodejs Examples: # outputs `.tool-versions` compatible format @@ -965,9 +963,7 @@ Usage: exec [OPTIONS] [RUNTIME]... [-- ...] Arguments: [RUNTIME]... - Runtime(s) to start - - e.g.: nodejs@18 python@3.10 + Runtime(s) to start e.g.: nodejs@18 python@3.10 [COMMAND]... Command string to execute (same as --command) @@ -997,7 +993,6 @@ Usage: global [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... Runtime(s) to add to .tool-versions - e.g.: nodejs@18 If this is a single runtime with no version, the current value of the global .tool-versions will be displayed @@ -1005,13 +1000,12 @@ Arguments: Options: --pin Save exact version to `~/.tool-versions` - e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions --fuzzy Save fuzzy version to `~/.tool-versions` - - e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 + e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions + this is the default behavior unless RTX_ASDF_COMPAT=1 --remove Remove the plugin(s) from ~/.tool-versions @@ -1061,9 +1055,7 @@ Usage: install [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - Runtime(s) to install - - e.g.: nodejs@18 + Runtime(s) to install e.g.: nodejs@18 Options: -p, --plugin @@ -1114,7 +1106,6 @@ Usage: local [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... Runtimes to add to .tool-versions - e.g.: nodejs@18 if this is a single runtime with no version, the current value of .tool-versions will be displayed @@ -1126,13 +1117,10 @@ Options: --pin Save exact version to `.tool-versions` - e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions --fuzzy - Save fuzzy version to `.tool-versions` - - e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 + Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 --remove Remove the plugin(s) from .tool-versions @@ -1227,14 +1215,10 @@ Usage: install [OPTIONS] [NAME] [GIT_URL] Arguments: [NAME] - The name of the plugin to install - - e.g.: nodejs, ruby + The name of the plugin to install e.g.: nodejs, ruby [GIT_URL] The git url of the plugin - - e.g.: https://github.com/asdf-vm/asdf-nodejs.git Options: -f, --force @@ -1242,7 +1226,6 @@ Options: -a, --all Install all missing plugins - This will only install plugins that have matching shorthands. i.e.: they don't need the full git repo url @@ -1272,14 +1255,10 @@ Usage: ls [OPTIONS] Options: -a, --all - List all available remote plugins - - same as `rtx plugins ls-remote` + List all available remote plugins Same as `rtx plugins ls-remote` -u, --urls - Show the git url for each plugin - - e.g.: https://github.com/asdf-vm/asdf-nodejs.git + Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git Examples: $ rtx plugins ls @@ -1305,9 +1284,7 @@ Usage: ls-remote [OPTIONS] Options: -u, --urls - Show the git url for each plugin - - e.g.: https://github.com/asdf-vm/asdf-nodejs.git + Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git ``` ### `rtx plugins uninstall` @@ -1489,7 +1466,10 @@ Usage: where Arguments: - runtime(s) to look up if "@" is specified, it will show the latest installed version that matches the prefix otherwise, it will show the current, active installed version + Runtime(s) to look up + e.g.: ruby@3 + if "@" is specified, it will show the latest installed version that matches the prefix + otherwise, it will show the current, active installed version Examples: # Show the latest installed version of nodejs diff --git a/completions/_rtx b/completions/_rtx index 40b799fc9..a7ec0a45d 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -293,7 +293,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::plugin -- Plugin to show versions of:' \ +'::plugin -- Plugin to show versions of e.g.\: ruby, nodejs:' \ && ret=0 ;; (deactivate) @@ -447,7 +447,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to start:' \ +'*::runtime -- Runtime(s) to start e.g.\: nodejs@18 python@3.10:' \ && ret=0 ;; (global) @@ -456,15 +456,21 @@ _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--pin[Save exact version to `~/.tool-versions`]' \ -'--fuzzy[Save fuzzy version to `~/.tool-versions`]' \ +'--pin[Save exact version to `~/.tool-versions` +e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions]' \ +'--fuzzy[Save fuzzy version to `~/.tool-versions` +e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions +this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to add to .tool-versions:' \ +'*::runtime -- Runtime(s) to add to .tool-versions +e.g.\: nodejs@18 +If this is a single runtime with no version, the current value of the global +.tool-versions will be displayed:' \ && ret=0 ;; (hook-env) @@ -507,15 +513,15 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Force reinstall even if already installed]' \ '--force[Force reinstall even if already installed]' \ -'(-p --plugin -f --force)-a[Install all missing runtimes as well as all plugins for the current directory]' \ -'(-p --plugin -f --force)--all[Install all missing runtimes as well as all plugins for the current directory]' \ +'(-p --plugin -f --force)-a[Install all missing runtimes as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ +'(-p --plugin -f --force)--all[Install all missing runtimes as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to install:' \ +'*::runtime -- Runtime(s) to install e.g.\: nodejs@18:' \ && ret=0 ;; (latest) @@ -543,15 +549,19 @@ _arguments "${_arguments_options[@]}" \ by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--parent[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ -'--pin[Save exact version to `.tool-versions`]' \ -'--fuzzy[Save fuzzy version to `.tool-versions`]' \ +'--pin[Save exact version to `.tool-versions` +e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions]' \ +'--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtimes to add to .tool-versions:' \ +'*::runtime -- Runtimes to add to .tool-versions +e.g.\: nodejs@18 +if this is a single runtime with no version, +the current value of .tool-versions will be displayed:' \ && ret=0 ;; (ls) @@ -632,15 +642,19 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ -'(-f --force)-a[Install all missing plugins]' \ -'(-f --force)--all[Install all missing plugins]' \ +'(-f --force)-a[Install all missing plugins +This will only install plugins that have matching shorthands. +i.e.: they don'\''t need the full git repo url]' \ +'(-f --force)--all[Install all missing plugins +This will only install plugins that have matching shorthands. +i.e.: they don'\''t need the full git repo url]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::name -- The name of the plugin to install:' \ +'::name -- The name of the plugin to install e.g.\: nodejs, ruby:' \ '::git_url -- The git url of the plugin:_urls' \ && ret=0 ;; @@ -649,10 +663,10 @@ _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-a[List all available remote plugins]' \ -'--all[List all available remote plugins]' \ -'-u[Show the git url for each plugin]' \ -'--urls[Show the git url for each plugin]' \ +'-a[List all available remote plugins Same as `rtx plugins ls-remote`]' \ +'--all[List all available remote plugins Same as `rtx plugins ls-remote`]' \ +'-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +'--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ @@ -666,8 +680,8 @@ _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-u[Show the git url for each plugin]' \ -'--urls[Show the git url for each plugin]' \ +'-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +'--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ @@ -947,8 +961,13 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':runtime -- runtime(s) to look up if "@" is specified, it will show the latest installed version that matches the prefix otherwise, it will show the current, active installed version:' \ -'::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ +':runtime -- Runtime(s) to look up +e.g.\: ruby@3 +if "@" is specified, it will show the latest installed version that matches the prefix +otherwise, it will show the current, active installed version:' \ +'::asdf_version -- the version prefix to use when querying the latest version +same as the first argument after the "@" +used for asdf compatibility:' \ && ret=0 ;; (which) diff --git a/completions/rtx.fish b/completions/rtx.fish index 7eb044004..7a31a18ba 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -177,8 +177,11 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print hel complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions`' -complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` +e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` +e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions +this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' @@ -200,7 +203,7 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' -complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing runtimes as well as all plugins for the current directory' +complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing runtimes as well as all plugins for the current directory This is hidden because it\'s now the default behavior' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' @@ -214,8 +217,9 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' -complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions`' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions`' +complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` +e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' @@ -252,20 +256,22 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins +This will only install plugins that have matching shorthands. +i.e.: they don\'t need the full git repo url' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins Same as `rtx plugins ls-remote`' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/cli/current.rs b/src/cli/current.rs index dcf25df44..c79bd682c 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -17,7 +17,6 @@ use crate::toolset::{Toolset, ToolsetBuilder}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Current { /// Plugin to show versions of - /// /// e.g.: ruby, nodejs #[clap()] plugin: Option, diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 519488f45..bb4b81389 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -32,7 +32,6 @@ use crate::toolset::ToolsetBuilder; #[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Exec { /// Runtime(s) to start - /// /// e.g.: nodejs@18 python@3.10 #[clap(value_parser = RuntimeArgParser)] pub runtime: Vec, diff --git a/src/cli/global.rs b/src/cli/global.rs index c07fc6cb1..e5e4c19f9 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -19,7 +19,6 @@ use crate::{dirs, env}; #[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Global { /// Runtime(s) to add to .tool-versions - /// /// e.g.: nodejs@18 /// If this is a single runtime with no version, the current value of the global /// .tool-versions will be displayed @@ -27,16 +26,14 @@ pub struct Global { runtime: Option>, /// Save exact version to `~/.tool-versions` - /// /// e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `~/.tool-versions` - /// /// e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 - #[clap(long, overrides_with = "pin")] + #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, /// Remove the plugin(s) from ~/.tool-versions diff --git a/src/cli/install.rs b/src/cli/install.rs index e29047768..7ce45b8c1 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -26,7 +26,6 @@ use crate::toolset::ToolsetBuilder; #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Install { /// Runtime(s) to install - /// /// e.g.: nodejs@18 #[clap(value_parser = RuntimeArgParser)] runtime: Option>, @@ -40,7 +39,6 @@ pub struct Install { force: bool, /// Install all missing runtimes as well as all plugins for the current directory - /// /// This is hidden because it's now the default behavior #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"], hide = true)] all: bool, diff --git a/src/cli/local.rs b/src/cli/local.rs index 27dfa1f71..38a1fe163 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -19,7 +19,6 @@ use crate::{dirs, env, file}; #[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Local { /// Runtimes to add to .tool-versions - /// /// e.g.: nodejs@18 /// if this is a single runtime with no version, /// the current value of .tool-versions will be displayed @@ -32,15 +31,13 @@ pub struct Local { parent: bool, /// Save exact version to `.tool-versions` - /// /// e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `.tool-versions` - /// /// e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions - /// this is the default behavior unless RTX_ASDF_COMPAT=1 + /// This is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index dc1c7613d..1487b8b70 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -21,13 +21,11 @@ use crate::ui::progress_report::ProgressReport; #[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct PluginsInstall { /// The name of the plugin to install - /// /// e.g.: nodejs, ruby #[clap(required_unless_present = "all")] name: Option, /// The git url of the plugin - /// /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(help = "The git url of the plugin", value_hint = clap::ValueHint::Url)] git_url: Option, @@ -37,7 +35,6 @@ pub struct PluginsInstall { force: bool, /// Install all missing plugins - /// /// This will only install plugins that have matching shorthands. /// i.e.: they don't need the full git repo url #[clap(short, long, conflicts_with_all = ["name", "force"], verbatim_doc_comment)] diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index b61dedb0b..2baee94bb 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -15,13 +15,11 @@ use crate::output::Output; #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] pub struct PluginsLs { /// List all available remote plugins - /// - /// same as `rtx plugins ls-remote` + /// Same as `rtx plugins ls-remote` #[clap(short, long)] pub all: bool, /// Show the git url for each plugin - /// /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long)] pub urls: bool, diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index a5abda5e7..b42c043da 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -15,7 +15,6 @@ use crate::output::Output; #[clap(visible_alias = "list-remote", long_about = LONG_ABOUT, verbatim_doc_comment, alias = "list-all")] pub struct PluginsLsRemote { /// Show the git url for each plugin - /// /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long)] pub urls: bool, diff --git a/src/cli/where.rs b/src/cli/where.rs index a7f95c647..4489ba648 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -16,16 +16,17 @@ use crate::toolset::ToolsetBuilder; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct Where { - /// runtime(s) to look up + /// Runtime(s) to look up + /// e.g.: ruby@3 /// if "@" is specified, it will show the latest installed version that matches the prefix /// otherwise, it will show the current, active installed version - #[clap(required = true, value_parser = RuntimeArgParser)] + #[clap(required = true, value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: RuntimeArg, /// the version prefix to use when querying the latest version /// same as the first argument after the "@" /// used for asdf compatibility - #[clap(hide = true)] + #[clap(hide = true, verbatim_doc_comment)] asdf_version: Option, } From 699a5f27a5f1f2f16891f588847e56d4b0ff6f4d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 16:58:13 -0600 Subject: [PATCH 0335/1891] bug: prevent install loop with reshimming --- e2e/.gitignore | 2 ++ src/cli/reshim.rs | 2 +- src/fake_asdf.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/e2e/.gitignore b/e2e/.gitignore index e23396803..8de18a6f1 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -2,4 +2,6 @@ .rtx .cache .config +.asdf Library + diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 82b2a9207..5e25b7d72 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -30,7 +30,7 @@ pub struct Reshim { impl Command for Reshim { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().with_install_missing().build(&config); + let ts = ToolsetBuilder::new().build(&config); if !config.settings.experimental { err_experimental()?; diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index ed85dbf23..c1617ca61 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -19,6 +19,7 @@ pub fn setup() -> color_eyre::Result { // rtx="${{RTX_EXE:-rtx}}" formatdoc! {r#" #!/bin/sh + export RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx asdf "$@" "#}, )?; From 139f7d97e1939811f7b7a05f6da667569c369c03 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 17:07:55 -0600 Subject: [PATCH 0336/1891] bug: revert #204 autoactivating This appears to have broken direnv since rtx would always be called first --- README.md | 13 +++++-------- e2e/cd/test_bash | 2 +- e2e/cd/test_fish | 1 + e2e/cd/test_zsh | 2 +- e2e/test_doctor | 2 +- src/cli/render_help.rs | 13 +++++-------- .../rtx__cli__activate__tests__activate_zsh.snap | 2 -- ...__cli__activate__tests__activate_zsh_legacy.snap | 2 -- src/shell/bash.rs | 2 -- src/shell/fish.rs | 2 -- .../rtx__shell__bash__tests__hook_init.snap | 2 -- .../rtx__shell__fish__tests__hook_init.snap | 2 -- .../rtx__shell__zsh__tests__hook_init.snap | 2 -- src/shell/zsh.rs | 2 -- 14 files changed, 14 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 637f39253..535bcbe2e 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,8 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your -> .envrc for `layout python` to work or for other logic that needs to reference rtx -> runtimes. -> There is also an alternative way to use rtx inside of direnv, see [here](#direnv). +> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes, +> see the [direnv section](#direnv) below. Install a runtime and set it as the default: @@ -1639,15 +1637,14 @@ in it as well. A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated binaries to PATH. In these cases, rtx will not interfere with direnv. -As mentioned in the Quick Start, calling `eval "$(rtx env -s bash)"` will add rtx runtimes -into an .envrc file. This is useful for `layout python` which should be using the -rtx python version. This isn't necessary unless the envrc needs access to a runtime. - ### rtx inside of direnv (`use rtx` in `.envrc`) If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, this is a simpler setup that's less likely to cause issues—at the cost of functionality. +This may be required if you want to use direnv's `layout python` with rtx. Otherwise there are +situations where rtx will override direnv's PATH. `use rtx` ensures that direnv always has control. + To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: ```sh-session diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 9cea166dc..99b88be05 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -5,7 +5,7 @@ set -euo pipefail orig_path="$PATH" # shellcheck disable=SC1090 -eval "$(rtx activate bash --status)" +eval "$(rtx activate bash --status)" && _rtx_hook assert_path() { local expected="${1//$HOME/\~}" diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index 9023918cf..74283f260 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -6,6 +6,7 @@ set -l orig_node (node -v) rtx install nodejs@18.0.0 nodejs@16.0.0; or exit rtx activate --status fish | source +__rtx_env_eval test (node -v) = "v18.0.0"; or exit diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index 9ddb126c2..6b88fddfa 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -16,7 +16,7 @@ assert_path() { rtx install nodejs@18.0.0 nodejs@16.0.0 # shellcheck disable=SC1090 -eval "$(rtx activate zsh --status)" +eval "$(rtx activate zsh --status)" && _rtx_hook #rtx install test "$(node -v)" = "v18.0.0" diff --git a/e2e/test_doctor b/e2e/test_doctor index 2e96b1462..4f4b313ab 100755 --- a/e2e/test_doctor +++ b/e2e/test_doctor @@ -10,5 +10,5 @@ assert() { fi } -eval "$(rtx activate bash)" +eval "$(rtx activate bash)" && _rtx_hook rtx doctor diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index c4be5767f..46636030c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -74,10 +74,8 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv, you may need to also add `eval "$(rtx env -s bash)"` to your -> .envrc for `layout python` to work or for other logic that needs to reference rtx -> runtimes. -> There is also an alternative way to use rtx inside of direnv, see [here](#direnv). +> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes, +> see the [direnv section](#direnv) below. Install a runtime and set it as the default: @@ -781,15 +779,14 @@ in it as well. A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated binaries to PATH. In these cases, rtx will not interfere with direnv. -As mentioned in the Quick Start, calling `eval "$(rtx env -s bash)"` will add rtx runtimes -into an .envrc file. This is useful for `layout python` which should be using the -rtx python version. This isn't necessary unless the envrc needs access to a runtime. - ### rtx inside of direnv (`use rtx` in `.envrc`) If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, this is a simpler setup that's less likely to cause issues—at the cost of functionality. +This may be required if you want to use direnv's `layout python` with rtx. Otherwise there are +situations where rtx will override direnv's PATH. `use rtx` ensures that direnv always has control. + To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: ```sh-session diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap index 53489d20a..85f888cc3 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap @@ -38,5 +38,3 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi -_rtx_hook - diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap index 53489d20a..85f888cc3 100644 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap +++ b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap @@ -38,5 +38,3 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi -_rtx_hook - diff --git a/src/shell/bash.rs b/src/shell/bash.rs index c7b86221d..5f6fd7c3b 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -48,8 +48,6 @@ impl Shell for Bash { if ! [[ "${{PROMPT_COMMAND:-}}" =~ _rtx_hook ]]; then PROMPT_COMMAND="_rtx_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" fi - - _rtx_hook "#}); out diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 86bc3c968..b16a9a6ec 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -64,8 +64,6 @@ impl Shell for Fish { functions --erase __rtx_cd_hook; end; - - __rtx_env_eval "#}); out diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 282660c64..8216f3d4c 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -35,5 +35,3 @@ if ! [[ "${PROMPT_COMMAND:-}" =~ _rtx_hook ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi -_rtx_hook - diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 26bdc1805..197f42371 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -46,5 +46,3 @@ function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx envi functions --erase __rtx_cd_hook; end; -__rtx_env_eval - diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 0ed9d2507..9f3c4abed 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -38,5 +38,3 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi -_rtx_hook - diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 957d11085..62078cccf 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -55,8 +55,6 @@ impl Shell for Zsh { if [[ -z "${{chpwd_functions[(r)_rtx_hook]+1}}" ]]; then chpwd_functions=( _rtx_hook ${{chpwd_functions[@]}} ) fi - - _rtx_hook "#}); out From 21b54280c99ea095f51dff41e34b0ece435a56cc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 17:30:55 -0600 Subject: [PATCH 0337/1891] chore: Release rtx-cli version 1.19.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8a1bfa78..8c3895984 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.19.0" +version = "1.19.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 1c635e0d8..fce1e6e78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.19.0" +version = "1.19.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 535bcbe2e..db15469aa 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.19.0 +rtx 1.19.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -310,7 +310,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.0/rtx-v1.19.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.1/rtx-v1.19.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 58aa52039..8bbb32e36 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.19.0" +.TH rtx 1 "rtx 1.19.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -129,6 +129,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.19.0 +v1.19.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e04a5c6e0..adade6db4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.19.0 +Version: 1.19.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 46636030c..917a42e10 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -232,7 +232,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.0/rtx-v1.19.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.1/rtx-v1.19.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From d9bf9ea495eabfbc95fa67ed304ef76dd2e9a044 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 17:30:55 -0600 Subject: [PATCH 0338/1891] chore: remove awsebcli from plugin tests --- .github/workflows/test-plugins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 6cc3a71ab..82b9f268e 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -135,7 +135,7 @@ jobs: - awscli - dart - conan - - awsebcli + # TODO: - awsebcli fails in asdf and rtx the same way - aws-sam-cli - ansible-base - kotlin From 7beb20b4533a1a60d419314e3b2c5254332d2371 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 18:03:52 -0600 Subject: [PATCH 0339/1891] perf: do not read alias/legacy_filename cache if no script exists --- src/plugins/mod.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index e15f2929c..80b1555e0 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -241,6 +241,9 @@ impl Plugin { } pub fn get_aliases(&self, settings: &Settings) -> Result> { + if !self.has_list_alias_script() { + return Ok(IndexMap::new()); + } let aliases = self .alias_cache .get_or_try_init(|| self.fetch_aliases(settings))? @@ -250,9 +253,13 @@ impl Plugin { Ok(aliases) } - pub fn legacy_filenames(&self, settings: &Settings) -> Result<&Vec> { + pub fn legacy_filenames(&self, settings: &Settings) -> Result> { + if !self.has_list_legacy_filenames_script() { + return Ok(vec![]); + } self.legacy_filename_cache .get_or_try_init(|| self.fetch_legacy_filenames(settings)) + .cloned() } pub fn external_commands(&self) -> Result>> { @@ -329,9 +336,6 @@ impl Plugin { } fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { - if !self.has_list_legacy_filenames_script() { - return Ok(vec![]); - } Ok(self .script_man .read(settings, Script::ListLegacyFilenames, settings.verbose)? @@ -350,9 +354,6 @@ impl Plugin { self.script_man.script_exists(&Script::ListLegacyFilenames) } fn fetch_aliases(&self, settings: &Settings) -> Result> { - if !self.has_list_alias_script() { - return Ok(vec![]); - } let stdout = self .script_man .read(settings, Script::ListAliases, settings.verbose)?; From 074605a063dac13d173d336d94f15b0a278cfe76 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Feb 2023 20:16:33 -0600 Subject: [PATCH 0340/1891] added go -> golang plugin alias Fixes #240 --- scripts/update-shorthand-repo.sh | 3 ++- src/default_shorthands.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index 3bf2f8f8d..e850d5d30 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -6,7 +6,7 @@ git clone --depth 1 https://github.com/asdf-vm/asdf-plugins rm -f src/default_shorthands.rs num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') -num_plugins=$((num_plugins + 2)) # +2 for custom aliases (node, tiny, etc) +num_plugins=$((num_plugins + 3)) # + for custom aliases (node, tiny, etc) cat >src/default_shorthands.rs <> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 613] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 614] = [ // rtx custom aliases ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), + ("go", "https://github.com/kennyp/asdf-golang.git"), // asdf original aliases from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), From 965c5359e87eaef5f153c0dcfb02917f43eb3f09 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 10:27:09 -0600 Subject: [PATCH 0341/1891] chore: use GITHUB_TOKEN for E2E tests (#242) This secret should be available on forks so external contributors should now have passing E2E tests --- .github/pull_request_template.md | 1 - .github/workflows/rtx.yml | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index cb6b02e61..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index a64401bba..2c85bd65f 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -30,7 +30,6 @@ jobs: - name: Run cargo nextest run: cargo nextest run --features clap_mangen env: - GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} RUST_BACKTRACE: "1" - run: just lint @@ -53,7 +52,7 @@ jobs: - name: Run tests with coverage uses: nick-fields/retry@v2 env: - GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" with: timeout_minutes: 20 @@ -136,7 +135,7 @@ jobs: - name: Run e2e tests uses: nick-fields/retry@v2 env: - GITHUB_API_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" with: timeout_minutes: 20 From f73b4ee540d43bef4ce350bd041c820bbbf93e21 Mon Sep 17 00:00:00 2001 From: Chad Crawford Date: Wed, 1 Mar 2023 11:46:57 -0500 Subject: [PATCH 0342/1891] feat: add Nix flake (#239) * Add Nix flake. * Fixes for unit tests to pass. * Fix paths, add explicit build inputs. * Update flake, add devShell * Remove cargoHash, add cargoLock instead. * Add Cargo.toml release command to update version in default.nix; add editorconfig. Add .editorconfig since `shfmt` will use one in a parent directory if set. Update `flake.nix` with some more env stuff to make the dev shell work out of the box. * Update overlay to be a simpler overlay at the root of the flake. * Update README.md --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- .editorconfig | 2 ++ Cargo.toml | 1 + README.md | 40 +++++++++++++++++++++++++++++++++++++++ default.nix | 42 +++++++++++++++++++++++++++++++++++++++++ flake.lock | 43 ++++++++++++++++++++++++++++++++++++++++++ flake.nix | 40 +++++++++++++++++++++++++++++++++++++++ src/cli/render_help.rs | 39 ++++++++++++++++++++++++++++++++++++++ src/env_diff.rs | 4 ++++ test/fixtures/exec-env | 3 +++ 9 files changed, 214 insertions(+) create mode 100644 .editorconfig create mode 100644 default.nix create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..706a53ecd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[*.sh] +indent_style = tabs diff --git a/Cargo.toml b/Cargo.toml index fce1e6e78..36acee366 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ pre-release-replacements = [ { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, { file = "src/cli/render_help.rs", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, + { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, ] [package.metadata.binstall] diff --git a/README.md b/README.md index db15469aa..412f5cdae 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ v18.10.9 * [dnf](#dnf) * [yum](#yum) * [aur](#aur) + * [nix](#nix) * [Other Shells](#other-shells) * [Bash](#bash) * [Fish](#fish) @@ -368,6 +369,45 @@ cd rtx makepkg -si ``` +### nix + +For NixOS or those using the Nix package manager: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + rtx-flake = { + url = "github:chadac/rtx/add-nix-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }; + }; + + outputs = { self, nixpkgs, flake-utils, rtx-flake }: + flake-utils.lib.eachDefaultSystem(system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ rtx-flake.overlay ]; + }; + in { + devShells.default = pkgs.mkShell { + name = "my-dev-env"; + nativeBuildInputs = with pkgs; [ + rtx + ]; + }; + } + ); +} +``` + +You can also import the package directly using +`rtx-flake.packages.${system}.rtx`. It supports all default Nix +systems. + ## Other Shells ### Bash diff --git a/default.nix b/default.nix new file mode 100644 index 000000000..e43c251f2 --- /dev/null +++ b/default.nix @@ -0,0 +1,42 @@ +{ pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: +rustPlatform.buildRustPackage { + pname = "rtx"; + version = "1.18.2"; + + src = lib.cleanSource ./.; + + cargoLock = { + lockFile = ./Cargo.lock; + }; + + buildInputs = with pkgs; [ coreutils bash direnv gnused git gawk ]; + + prePatch = '' + substituteInPlace ./test/data/plugins/**/bin/* \ + --replace '#!/usr/bin/env bash' '#!${bash}/bin/bash' + substituteInPlace ./src/fake_asdf.rs ./src/cli/reshim.rs \ + --replace '#!/bin/sh' '#!${bash}/bin/sh' + substituteInPlace ./src/env_diff.rs \ + --replace '"bash"' '"${bash}/bin/bash"' + substituteInPlace ./src/cli/direnv/exec.rs \ + --replace '"env"' '"${coreutils}/bin/env"' \ + --replace 'cmd!("direnv"' 'cmd!("${direnv}/bin/direnv"' + ''; + + # Skip the test_plugin_list_urls as it uses the .git folder, which + # is excluded by default from Nix. + checkPhase = '' + RUST_BACKTRACE=full cargo test --features clap_mangen -- \ + --skip cli::plugins::ls::tests::test_plugin_list_urls + ''; + + # Need this to ensure openssl-src's build uses an available version of `perl` + # https://github.com/alexcrichton/openssl-src-rs/issues/45 + OPENSSL_SRC_PERL = "${perl}/bin/perl"; + + meta = with lib; { + description = "Polyglot runtime manager (asdf rust clone)"; + homepage = "https://github.com/jdxcode/rtx"; + license = licenses.mit; + }; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..fa72d5745 --- /dev/null +++ b/flake.lock @@ -0,0 +1,43 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1676283394, + "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1677413016, + "narHash": "sha256-dwvL0VK5iyxXPQzJOPzYmuVinh/R9hwRu7eYq6Bf6ag=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "84e33aea0f7a8375c92458c5b6cad75fa1dd561b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..0774cfb2d --- /dev/null +++ b/flake.nix @@ -0,0 +1,40 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + { + overlay = final: prev: { + rtx = prev.callPackage ./default.nix { }; + }; + } // flake-utils.lib.eachDefaultSystem(system: + let + pkgs = import nixpkgs { inherit system; }; + rtx = pkgs.callPackage ./default.nix { }; + in + { + packages = { + inherit rtx; + default = rtx; + }; + + devShells.default = pkgs.mkShell { + name = "rtx-develop"; + + inputsFrom = [ rtx ]; + + nativeBuildInputs = with pkgs; [ + just + clippy + rustfmt + shellcheck + shfmt + nodejs + cargo-release + ]; + }; + } + ); +} diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 917a42e10..02bc4ace5 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -290,6 +290,45 @@ cd rtx makepkg -si ``` +### nix + +For NixOS or those using the Nix package manager: + +```nix +{{ + inputs = {{ + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + rtx-flake = {{ + url = "github:chadac/rtx/add-nix-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }}; + }}; + + outputs = {{ self, nixpkgs, flake-utils, rtx-flake }}: + flake-utils.lib.eachDefaultSystem(system: + let + pkgs = import nixpkgs {{ + inherit system; + overlays = [ rtx-flake.overlay ]; + }}; + in {{ + devShells.default = pkgs.mkShell {{ + name = "my-dev-env"; + nativeBuildInputs = with pkgs; [ + rtx + ]; + }}; + }} + ); +}} +``` + +You can also import the package directly using +`rtx-flake.packages.${{system}}.rtx`. It supports all default Nix +systems. + ## Other Shells ### Bash diff --git a/src/env_diff.rs b/src/env_diff.rs index 399012f3c..251e98058 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -107,6 +107,7 @@ impl EnvDiff { }; let v = v.replace("\\'", "'"); let v = v.replace("\\n", "\n"); + let v = v.replace("\\\\", "\\"); if let Some(orig) = env.get(k) { if &v == orig { additions.remove(k); @@ -282,6 +283,9 @@ mod tests { let path = dirs::HOME.join("fixtures/exec-env"); let orig = indexmap! { "UNMODIFIED_VAR" => "unmodified", + "UNMODIFIED_NEWLINE_VAR" => "hello\\\nworld", + "UNMODIFIED_SQUOTE_VAR" => "hello\\'world", + "UNMODIFIED_ESCAPE_VAR" => "hello\\world", "MODIFIED_VAR" => "original", } .into_iter() diff --git a/test/fixtures/exec-env b/test/fixtures/exec-env index 4645dc18c..b9106418c 100644 --- a/test/fixtures/exec-env +++ b/test/fixtures/exec-env @@ -1,6 +1,9 @@ #!/usr/bin/env bash export UNMODIFIED_VAR="unmodified" +export UNMODIFIED_NEWLINE_VAR="hello\nworld" +export UNMODIFIED_SQUOTE_VAR="hello\'world" +export UNMODIFIED_ESCAPE_VAR="hello\\world" export MODIFIED_VAR="modified" export ADDED_VAR="added" export MULTILINE_VAR="line1 From e3107e209aa93ad740756c30b229771c974603be Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 17:20:55 -0600 Subject: [PATCH 0343/1891] feat: added .rtx.toml (#241) --- .rtx.toml | 7 + Cargo.lock | 1 + Cargo.toml | 1 + README.md | 45 ++ e2e/.e2e-tool-versions | 1 - e2e/.e2e.rtx.toml | 7 + e2e/cd/test_bash | 6 +- e2e/run_test | 1 + e2e/test_local | 3 - src/cli/args/runtime.rs | 5 +- src/cli/direnv/envrc.rs | 4 +- src/cli/direnv/exec.rs | 2 +- src/cli/env.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/render_help.rs | 44 ++ src/config/config_file/legacy_version.rs | 12 +- src/config/config_file/mod.rs | 13 +- src/config/config_file/rtx_toml.rs | 598 ++++++++++++++++++ src/config/config_file/rtxrc.rs | 16 +- ...__config_file__rtx_toml__tests__env-2.snap | 7 + ...nfig_file__rtx_toml__tests__fixture-2.snap | 20 + ...nfig_file__rtx_toml__tests__fixture-3.snap | 25 + ...nfig_file__rtx_toml__tests__fixture-4.snap | 134 ++++ ...nfig_file__rtx_toml__tests__fixture-5.snap | 9 + ...nfig_file__rtx_toml__tests__fixture-6.snap | 25 + ...config_file__rtx_toml__tests__fixture.snap | 7 + ...file__rtx_toml__tests__remove_alias-2.snap | 7 + ...g_file__rtx_toml__tests__remove_alias.snap | 9 + ...ile__rtx_toml__tests__remove_plugin-2.snap | 7 + ..._file__rtx_toml__tests__remove_plugin.snap | 13 + ...__rtx_toml__tests__replace_versions-2.snap | 7 + ...le__rtx_toml__tests__replace_versions.snap | 39 ++ ...ig_file__rtx_toml__tests__set_alias-2.snap | 12 + ...nfig_file__rtx_toml__tests__set_alias.snap | 14 + src/config/config_file/tool_versions.rs | 20 +- src/config/mod.rs | 91 ++- src/config/settings.rs | 4 +- src/env.rs | 5 + src/hook_env.rs | 2 +- src/output.rs | 6 + src/plugins/mod.rs | 2 +- src/plugins/script_manager.rs | 27 +- src/runtimes.rs | 69 +- src/toolset/builder.rs | 33 +- src/toolset/mod.rs | 16 +- src/toolset/tool_source.rs | 7 +- src/toolset/tool_version.rs | 28 +- test/fixtures/.rtx.toml | 20 + test/fixtures/.rtxrc.toml | 2 - 50 files changed, 1290 insertions(+), 149 deletions(-) create mode 100644 .rtx.toml create mode 100644 e2e/.e2e.rtx.toml create mode 100644 src/config/config_file/rtx_toml.rs create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-2.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap create mode 100644 test/fixtures/.rtx.toml delete mode 100644 test/fixtures/.rtxrc.toml diff --git a/.rtx.toml b/.rtx.toml new file mode 100644 index 000000000..fac7233b6 --- /dev/null +++ b/.rtx.toml @@ -0,0 +1,7 @@ +[env] +FOO = "bar" + +[tools] +nodejs = '17' +tiny = {version="1", foo="bar"} +golang = {version="latest", foo="bar"} diff --git a/Cargo.lock b/Cargo.lock index 8c3895984..3cd8dda3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1400,6 +1400,7 @@ dependencies = [ "exec", "filetime", "flate2", + "humantime", "indenter", "indexmap", "indicatif", diff --git a/Cargo.toml b/Cargo.toml index 36acee366..0e168879b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ dirs-next = "2.0.0" duct = "0.13.6" filetime = "0.2.19" flate2 = "1.0.25" +humantime = "2.1.0" indenter = "0.3.3" indexmap = "1.9.2" indicatif = "0.17.3" diff --git a/README.md b/README.md index 412f5cdae..0fb9b0264 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ v18.10.9 * [.tool-versions](#tool-versions) * [Legacy version files](#legacy-version-files) * [Global config: ~/.config/rtx/config.toml](#global-config-configrtxconfigtoml) + * [[experimental] .rtx.toml](#experimental-rtxtoml) * [Environment variables](#environment-variables) * [RTX_MISSING_RUNTIME_BEHAVIOR](#rtx_missing_runtime_behavior) * [RTX_DATA_DIR](#rtx_data_dir) @@ -552,6 +553,50 @@ my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node- These settings can also be managed with `rtx settings ls|get|set|unset`. +### [experimental] `.rtx.toml` + +`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` file. + +It allows for functionality that is not possible with `.tool-versions`, such as: + +* setting arbitrary env vars while inside the directory +* passing options to plugins like `virtualenv='.venv'` for rtx-python. +* specifying plugin repo url for custom plugins so it does not need to be added manually + +Here is what the config looks like: + +```toml +[env] +NODE_ENV = 'production' # supports arbitrary env vars so rtx can be used like dotenv + +[tools] +# specify single or multiple versions +terraform = '1.0.0' +erlang = ['23.3', '24.0'] + +# supports everything you can do with .tool-versions currently +nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] + +# repo can be used to git clone a custom repo url (see #226) +jq = { version = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' } + +# send arbitrary options to the plugin, passed as: +# RTX_TOOL_OPTS__VENV=.venv +# RTX_TOOL_OPTS__DEFAULT_PACKAGES__0=ansible +# RTX_TOOL_OPTS__DEFAULT_PACKAGES__1=pipenv +python = { version = '3.10', venv = '.venv', default_packages = ['ansible', 'pipenv'] } + +[settings] # project-local settings +verbose = true +missing_runtime_behavior = 'warn' +shims_dir = '~/.rtx/shims' + +[alias.nodejs] # project-local aliases +my_custom_node = '18' +``` + +`.rtx.toml` is currently experimental and may change in minor versions of rtx. + ### Environment variables rtx can also be configured via environment variables. The following options are available: diff --git a/e2e/.e2e-tool-versions b/e2e/.e2e-tool-versions index 754fc4c54..ae660fffb 100644 --- a/e2e/.e2e-tool-versions +++ b/e2e/.e2e-tool-versions @@ -2,4 +2,3 @@ shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 -jq latest diff --git a/e2e/.e2e.rtx.toml b/e2e/.e2e.rtx.toml new file mode 100644 index 000000000..1df8bf5ba --- /dev/null +++ b/e2e/.e2e.rtx.toml @@ -0,0 +1,7 @@ +[env] +FOO = "bar" + +[tools] +jq = "latest" +#tiny = {version="1", foo="bar"} +#golang = {version="1.19.5", foo="bar"} diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 99b88be05..901017cf1 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -20,15 +20,15 @@ assert_path() { } test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/jq/1.6/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" cd 16 && _rtx_hook test "$(node -v)" = "v16.0.0" -assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/jq/1.6/bin" +assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin:~/.rtx/installs/jq/1.6/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" rtx shell nodejs@16.0.0 && _rtx_hook test "$(node -v)" = "v16.0.0" diff --git a/e2e/run_test b/e2e/run_test index 4d7a70a94..efa6740a6 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -7,6 +7,7 @@ export ROOT export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="$ROOT/e2e/.rtx" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions +export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml unset GOPATH TEST="$1" diff --git a/e2e/test_local b/e2e/test_local index 006c923ef..5a1f7ef2f 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -24,14 +24,12 @@ assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 -jq latest " assert "rtx local shfmt@3.5.0" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.5.0 # test comment #nodejs 18.13.0 -jq latest " rtx exec -- shfmt --version >&2 @@ -43,7 +41,6 @@ assert "rtx local shfmt@3.6.0" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 -jq latest " rtx exec -- shfmt --version >&2 diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index a2eb8f25e..effb720a1 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -1,6 +1,7 @@ use color_eyre::eyre::Result; use std::ffi::{OsStr, OsString}; use std::fmt::Display; +use std::path::PathBuf; use clap::{Arg, Command, Error}; use regex::Regex; @@ -29,7 +30,7 @@ pub enum RuntimeArgVersion { /// build runtime from source at this VCS sha Ref(String), /// runtime is in a local directory, not managed by rtx - Path(String), + Path(PathBuf), Prefix(String), } @@ -102,7 +103,7 @@ impl Display for RuntimeArgVersion { match self { RuntimeArgVersion::System => write!(f, "system"), RuntimeArgVersion::Version(version) => write!(f, "{version}"), - RuntimeArgVersion::Path(path) => write!(f, "path:{path}"), + RuntimeArgVersion::Path(path) => write!(f, "path:{}", path.display()), RuntimeArgVersion::Ref(ref_) => write!(f, "ref:{ref_}"), RuntimeArgVersion::Prefix(prefix) => write!(f, "prefix:{prefix}"), RuntimeArgVersion::None => write!(f, "current"), diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 4ad76f70b..f5312af1f 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -36,10 +36,10 @@ impl Command for Envrc { file, "### Do not edit. This was autogenerated by 'asdf direnv envrc' ###" )?; - for cf in &config.config_files { + for cf in config.config_files.keys() { writeln!(file, "watch_file {}", cf.to_string_lossy())?; } - for (k, v) in ts.env() { + for (k, v) in ts.env(&config) { writeln!( file, "export {}={}", diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index b500e0914..e7a7d2dea 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -32,7 +32,7 @@ impl Command for DirenvExec { cmd!("direnv", "dump") }; - for (k, v) in ts.env() { + for (k, v) in ts.env(&config) { cmd = cmd.env(k, v); } cmd = cmd.env("PATH", ts.path_env(&config.settings)); diff --git a/src/cli/env.rs b/src/cli/env.rs index bd3972e11..8c701b2ae 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -35,7 +35,7 @@ impl Command for Env { let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); - for (k, v) in ts.env() { + for (k, v) in ts.env(&config) { let k = k.to_string(); let v = v.to_string(); rtxprint!(out, "{}", shell.set_env(&k, &v)); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index bb4b81389..7550561c6 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -53,7 +53,7 @@ impl Command for Exec { .build(&config); let (program, args) = parse_command(&env::SHELL, self.command, self.c); - let mut env = ts.env(); + let mut env = ts.env(&config); env.insert("PATH".into(), ts.path_env(&config.settings)); if config.settings.missing_runtime_behavior != Ignore { // prevent rtx from auto-installing inside a shim diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 2a1e80424..ecfe17084 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -40,7 +40,7 @@ impl Command for HookEnv { let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); out.stdout.write(hook_env::clear_old_env(&*shell)); - let env = ts.env(); + let env = ts.env(&config); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 02bc4ace5..e1ae1d1db 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -473,6 +473,50 @@ my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node- These settings can also be managed with `rtx settings ls|get|set|unset`. +### [experimental] `.rtx.toml` + +`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` file. + +It allows for functionality that is not possible with `.tool-versions`, such as: + +* setting arbitrary env vars while inside the directory +* passing options to plugins like `virtualenv='.venv'` for rtx-python. +* specifying plugin repo url for custom plugins so it does not need to be added manually + +Here is what the config looks like: + +```toml +[env] +NODE_ENV = 'production' # supports arbitrary env vars so rtx can be used like dotenv + +[tools] +# specify single or multiple versions +terraform = '1.0.0' +erlang = ['23.3', '24.0'] + +# supports everything you can do with .tool-versions currently +nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] + +# repo can be used to git clone a custom repo url (see #226) +jq = {{ version = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' }} + +# send arbitrary options to the plugin, passed as: +# RTX_TOOL_OPTS__VENV=.venv +# RTX_TOOL_OPTS__DEFAULT_PACKAGES__0=ansible +# RTX_TOOL_OPTS__DEFAULT_PACKAGES__1=pipenv +python = {{ version = '3.10', venv = '.venv', default_packages = ['ansible', 'pipenv'] }} + +[settings] # project-local settings +verbose = true +missing_runtime_behavior = 'warn' +shims_dir = '~/.rtx/shims' + +[alias.nodejs] # project-local aliases +my_custom_node = '18' +``` + +`.rtx.toml` is currently experimental and may change in minor versions of rtx. + ### Environment variables rtx can also be configured via environment variables. The following options are available: diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 31b3fff13..4c2ce8ad2 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::default::Default; use std::fmt::Display; use std::path::{Path, PathBuf}; @@ -6,7 +7,8 @@ use color_eyre::eyre::Result; use indexmap::IndexMap; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::Settings; +use crate::config::settings::SettingsBuilder; +use crate::config::{AliasMap, Settings}; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; @@ -73,6 +75,14 @@ impl ConfigFile for LegacyVersionFile { fn to_toolset(&self) -> Toolset { self.into() } + + fn settings(&self) -> SettingsBuilder { + SettingsBuilder::default() + } + + fn aliases(&self) -> AliasMap { + AliasMap::default() + } } impl Display for LegacyVersionFile { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 6c92ff4da..2622e96ed 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -9,7 +9,8 @@ use rtxrc::RTXFile; use tool_versions::ToolVersions; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; -use crate::config::Config; +use crate::config::settings::SettingsBuilder; +use crate::config::{AliasMap, Config}; use crate::env; use crate::file::display_path; @@ -19,17 +20,19 @@ use crate::plugins::PluginName; use crate::toolset::{Toolset, ToolsetBuilder}; pub mod legacy_version; +pub mod rtx_toml; pub mod rtxrc; pub mod tool_versions; #[derive(Debug, PartialEq)] pub enum ConfigFileType { RtxRc, + RtxToml, ToolVersions, LegacyVersion, } -pub trait ConfigFile: Debug + Display + Send { +pub trait ConfigFile: Debug + Display + Send + Sync { fn get_type(&self) -> ConfigFileType; fn get_path(&self) -> &Path; fn plugins(&self) -> IndexMap>; @@ -40,6 +43,8 @@ pub trait ConfigFile: Debug + Display + Send { fn save(&self) -> Result<()>; fn dump(&self) -> String; fn to_toolset(&self) -> Toolset; + fn settings(&self) -> SettingsBuilder; + fn aliases(&self) -> AliasMap; } impl dyn ConfigFile { @@ -65,7 +70,7 @@ impl dyn ConfigFile { } else { match &runtime.version { RuntimeArgVersion::Version(ref v) => v.to_string(), - RuntimeArgVersion::Path(p) => format!("path:{p}"), + RuntimeArgVersion::Path(p) => format!("path:{}", p.display()), RuntimeArgVersion::Ref(r) => format!("ref:{r}"), RuntimeArgVersion::Prefix(p) => format!("prefix:{p}"), _ => "latest".to_string(), @@ -121,6 +126,7 @@ pub fn init(path: &Path) -> Box { pub fn parse(path: &Path) -> Result> { match detect_config_file_type(path) { + Some(ConfigFileType::RtxToml) => Ok(Box::new(rtx_toml::RtxToml::from_file(path)?)), Some(ConfigFileType::RtxRc) => Ok(Box::new(RTXFile::from_file(path)?)), Some(ConfigFileType::ToolVersions) => Ok(Box::new(ToolVersions::from_file(path)?)), #[allow(clippy::box_default)] @@ -131,6 +137,7 @@ pub fn parse(path: &Path) -> Result> { fn detect_config_file_type(path: &Path) -> Option { match path.file_name().unwrap().to_str().unwrap() { ".rtxrc" | ".rtxrc.toml" | "config.toml" => Some(ConfigFileType::RtxRc), + f if env::RTX_DEFAULT_CONFIG_FILENAME.as_str() == f => Some(ConfigFileType::RtxToml), f if env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() == f => { Some(ConfigFileType::ToolVersions) } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs new file mode 100644 index 000000000..b781f6efe --- /dev/null +++ b/src/config/config_file/rtx_toml.rs @@ -0,0 +1,598 @@ +use std::collections::HashMap; +use std::fmt::{Display, Formatter}; +use std::fs; +use std::path::{Path, PathBuf}; +use std::time::Duration; + +use color_eyre::eyre::eyre; +use color_eyre::{Result, Section}; +use indexmap::IndexMap; +use log::LevelFilter; +use toml_edit::{table, value, Array, Item, Value}; + +use crate::config::config_file::{ConfigFile, ConfigFileType}; +use crate::config::settings::SettingsBuilder; +use crate::config::{AliasMap, MissingRuntimeBehavior}; +use crate::plugins::PluginName; +use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; + +#[derive(Debug, Default)] +pub struct RtxToml { + path: PathBuf, + toolset: Toolset, + env: HashMap, + settings: SettingsBuilder, + alias: AliasMap, + doc: toml_edit::Document, +} + +#[macro_export] +macro_rules! parse_error { + ($key:expr, $val:expr, $t:expr) => {{ + Err(eyre!( + r#"expected value of "{}" to be a {}, got: {}"#, + $key, + $t, + $val + )) + }}; +} + +#[allow(dead_code)] // TODO: remove +impl RtxToml { + pub fn init(filename: &Path) -> Self { + Self { + path: filename.to_path_buf(), + ..Default::default() + } + } + + pub fn from_file(filename: &Path) -> Result { + trace!("parsing: {}", filename.display()); + let body = fs::read_to_string(filename).suggestion("ensure file exists and can be read")?; + let mut rf = Self::from_str(body)?; + rf.path = filename.to_path_buf(); + Ok(rf) + } + + pub fn from_str(s: String) -> Result { + Self { + doc: s.parse().suggestion("ensure file is valid TOML")?, + ..Default::default() + } + .parse() + } + + fn parse(mut self) -> Result { + for (k, v) in self.doc.iter() { + match k { + "env" => self.env = self.parse_hashmap(k, v)?, + "alias" => self.alias = self.parse_alias(k, v)?, + "tools" => self.toolset = self.parse_toolset(k, v)?, + "settings" => self.settings = self.parse_settings(k, v)?, + _ => warn!("unknown key: {}", k), + } + } + Ok(self) + } + + pub fn settings(&self) -> SettingsBuilder { + SettingsBuilder::default() + } + + fn parse_alias(&self, k: &str, v: &Item) -> Result { + match v.as_table_like() { + Some(table) => { + let mut aliases = AliasMap::new(); + for (plugin, table) in table.iter() { + let k = format!("{}.{}", k, plugin); + let plugin_aliases = aliases.entry(plugin.into()).or_default(); + match table.as_table_like() { + Some(table) => { + for (from, to) in table.iter() { + match to.as_str() { + Some(s) => { + plugin_aliases.insert(from.into(), s.into()); + } + _ => parse_error!(format!("{}.{}", k, from), v, "string")?, + } + } + } + _ => parse_error!(k, v, "table")?, + } + } + Ok(aliases) + } + _ => parse_error!(k, v, "table")?, + } + } + + fn parse_hashmap(&self, key: &str, v: &Item) -> Result> { + match v.as_table_like() { + Some(table) => { + let mut env = HashMap::new(); + for (k, v) in table.iter() { + match v.as_str() { + Some(s) => { + env.insert(k.into(), s.into()); + } + _ => parse_error!(key, v, "string")?, + } + } + Ok(env) + } + _ => parse_error!(key, v, "table"), + } + } + + fn parse_toolset(&self, key: &str, v: &Item) -> Result { + let source = ToolSource::RtxToml(self.path.clone()); + let mut toolset = Toolset::new(source); + + match v.as_table_like() { + Some(table) => { + for (plugin, v) in table.iter() { + let k = format!("{}.{}", key, plugin); + let tvl = self.parse_tool_version_list(&k, v, &plugin.into())?; + toolset.versions.insert(plugin.into(), tvl); + } + Ok(toolset) + } + _ => parse_error!(key, v, "table")?, + } + } + + fn parse_tool_version_list( + &self, + key: &str, + v: &Item, + plugin_name: &PluginName, + ) -> Result { + let source = ToolSource::RtxToml(self.path.clone()); + let mut tool_version_list = ToolVersionList::new(source); + + match v { + Item::ArrayOfTables(v) => { + for table in v.iter() { + for (tool, v) in table.iter() { + let k = format!("{}.{}", key, tool); + let tv = self.parse_tool_version(&k, v, plugin_name)?; + tool_version_list.versions.push(tv); + } + } + } + v => match v.as_array() { + Some(v) => { + for v in v.iter() { + let item = Item::Value(v.clone()); + let tv = self.parse_tool_version(key, &item, plugin_name)?; + tool_version_list.versions.push(tv); + } + } + _ => { + tool_version_list + .versions + .push(self.parse_tool_version(key, v, plugin_name)?) + } + }, + } + + Ok(tool_version_list) + } + + fn parse_tool_version( + &self, + key: &str, + v: &Item, + plugin_name: &PluginName, + ) -> Result { + let mut tv = ToolVersion::new(plugin_name.clone(), ToolVersionType::System); + + match v.as_table_like() { + Some(table) => { + if let Some(v) = table.get("version") { + match v { + Item::Value(v) => { + tv.r#type = self.parse_tool_version_value(key, v)?; + } + _ => parse_error!(format!("{}.version", key), v, "string")?, + } + } else if let Some(path) = table.get("path") { + match path.as_str() { + Some(s) => { + tv.r#type = ToolVersionType::Path(s.into()); + } + _ => parse_error!(format!("{}.path", key), v, "string")?, + } + } else if let Some(prefix) = table.get("prefix") { + match prefix.as_str() { + Some(s) => { + tv.r#type = ToolVersionType::Prefix(s.into()); + } + _ => parse_error!(format!("{}.prefix", key), v, "string")?, + } + } else if let Some(r) = table.get("ref") { + match r.as_str() { + Some(s) => { + tv.r#type = ToolVersionType::Ref(s.into()); + } + _ => parse_error!(format!("{}.ref", key), v, "string")?, + } + } else { + parse_error!(key, v, "version, path, or prefix")? + } + if let Some(repo) = table.get("repo") { + match repo.as_str() { + Some(s) => { + tv.repo = Some(s.into()); + } + _ => parse_error!(format!("{}.repo", key), v, "string")?, + } + } + for (k, v) in table.iter() { + if k == "version" || k == "path" || k == "prefix" || k == "ref" || k == "repo" { + continue; + } + match v.as_str() { + Some(s) => { + tv.options.insert(k.into(), s.into()); + } + _ => parse_error!(format!("{}.{}", key, k), v, "string")?, + } + } + } + _ => match v { + Item::Value(v) => { + tv.r#type = self.parse_tool_version_value(key, v)?; + } + _ => parse_error!(key, v, "value")?, + }, + } + + Ok(tv) + } + + fn parse_tool_version_value(&self, key: &str, v: &Value) -> Result { + match v.as_str() { + Some(s) => match s.split_once(':') { + Some(("prefix", v)) => Ok(ToolVersionType::Prefix(v.into())), + Some(("path", v)) => Ok(ToolVersionType::Path(v.into())), + Some(("ref", v)) => Ok(ToolVersionType::Ref(v.into())), + Some((unknown, v)) => { + parse_error!(format!("{}.{}", key, unknown), v, "prefix, path, or ref")? + } + None => Ok(ToolVersionType::Version(s.into())), + }, + _ => parse_error!(key, v, "string")?, + } + } + + fn parse_settings(&self, key: &str, v: &Item) -> Result { + let mut settings = SettingsBuilder::default(); + + match v.as_table_like() { + Some(table) => { + for (config_key, v) in table.iter() { + let k = format!("{}.{}", key, config_key); + match config_key.to_lowercase().as_str() { + "experimental" => settings.experimental = Some(self.parse_bool(&k, v)?), + "missing_runtime_behavior" => { + settings.missing_runtime_behavior = + Some(self.parse_missing_runtime_behavior(&k, v)?) + } + "legacy_version_file" => { + settings.legacy_version_file = Some(self.parse_bool(&k, v)?) + } + "always_keep_download" => { + settings.always_keep_download = Some(self.parse_bool(&k, v)?) + } + "plugin_autoupdate_last_check_duration" => { + settings.plugin_autoupdate_last_check_duration = + Some(self.parse_duration_minutes(&k, v)?) + } + "verbose" => settings.verbose = Some(self.parse_bool(&k, v)?), + "asdf_compat" => settings.asdf_compat = Some(self.parse_bool(&k, v)?), + "jobs" => settings.jobs = Some(self.parse_usize(&k, v)?), + "shorthands_file" => { + settings.shorthands_file = Some(self.parse_path(&k, v)?) + } + "disable_default_shorthands" => { + settings.disable_default_shorthands = Some(self.parse_bool(&k, v)?) + } + "log_level" => settings.log_level = Some(self.parse_log_level(&k, v)?), + "shims_dir" => settings.shims_dir = Some(self.parse_path(&k, v)?), + "raw" => settings.raw = Some(self.parse_bool(&k, v)?), + _ => parse_error!(k, v, "setting")?, + }; + } + } + None => parse_error!("settings", v, "table")?, + } + + Ok(settings) + } + + fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { + self.alias + .entry(plugin.into()) + .or_default() + .insert(from.into(), to.into()); + self.doc + .entry("alias") + .or_insert_with(table) + .as_table_like_mut() + .unwrap() + .entry(plugin) + .or_insert_with(table) + .as_table_like_mut() + .unwrap() + .insert(from, value(to)); + } + + pub fn remove_alias(&mut self, plugin: &str, from: &str) -> Result<()> { + if let Some(aliases) = self.doc.get_mut("alias").and_then(|v| v.as_table_mut()) { + if let Some(plugin_aliases) = aliases.get_mut(plugin).and_then(|v| v.as_table_mut()) { + self.alias.get_mut(plugin).unwrap().remove(from); + plugin_aliases.remove(from); + if plugin_aliases.is_empty() { + aliases.remove(plugin); + self.alias.remove(plugin); + } + } + if aliases.is_empty() { + self.doc.as_table_mut().remove("alias"); + } + } + Ok(()) + } + + fn parse_duration_minutes(&self, k: &str, v: &Item) -> Result { + match v.as_value() { + Some(Value::String(s)) => Ok(humantime::parse_duration(s.value())?), + Some(Value::Integer(i)) => Ok(Duration::from_secs(*i.value() as u64 * 60)), + _ => Err(eyre!("expected {k} to be an integer, got: {v}")), + } + } + + fn parse_bool(&self, k: &str, v: &Item) -> Result { + match v.as_value().map(|v| v.as_bool()) { + Some(Some(v)) => Ok(v), + _ => parse_error!(k, v, "boolean")?, + } + } + + fn parse_usize(&self, k: &str, v: &Item) -> Result { + match v.as_value().map(|v| v.as_integer()) { + Some(Some(v)) => Ok(v as usize), + _ => Err(eyre!("expected {k} to be an integer, got: {v}")), + } + } + + fn parse_path(&self, k: &str, v: &Item) -> Result { + match v.as_value().map(|v| v.as_str()) { + Some(Some(v)) => Ok(v.into()), + _ => Err(eyre!("expected {k} to be a path, got: {v}")), + } + } + + fn parse_string(&self, k: &str, v: &Item) -> Result { + match v.as_value().map(|v| v.as_str()) { + Some(Some(v)) => Ok(v.into()), + _ => Err(eyre!("expected {k} to be a string, got: {v}")), + } + } + + fn parse_missing_runtime_behavior(&self, k: &str, v: &Item) -> Result { + let v = self.parse_string("missing_runtime_behavior", v)?; + match v.to_lowercase().as_str() { + "warn" => Ok(MissingRuntimeBehavior::Warn), + "ignore" => Ok(MissingRuntimeBehavior::Ignore), + "prompt" => Ok(MissingRuntimeBehavior::Prompt), + "autoinstall" => Ok(MissingRuntimeBehavior::AutoInstall), + _ => Err(eyre!( + "expected {k} to be one of: 'warn', 'ignore', 'prompt', 'autoinstall'. Got: {v}" + )), + } + } + + fn parse_log_level(&self, k: &str, v: &Item) -> Result { + let level = self.parse_string(k, v)?.parse()?; + Ok(level) + } +} + +impl Display for RtxToml { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.dump()) + } +} + +impl ConfigFile for RtxToml { + fn get_type(&self) -> ConfigFileType { + ConfigFileType::RtxToml + } + + fn get_path(&self) -> &Path { + self.path.as_path() + } + + fn plugins(&self) -> IndexMap> { + self.toolset + .versions + .iter() + .map(|(p, v)| { + ( + p.to_string(), + v.versions.iter().map(|v| v.to_string()).collect(), + ) + }) + .collect() + } + + fn env(&self) -> HashMap { + self.env.clone() + } + + fn remove_plugin(&mut self, plugin: &PluginName) { + self.toolset.versions.remove(plugin); + self.doc.as_table_mut().remove(plugin.to_string().as_str()); + } + + fn add_version(&mut self, _plugin: &PluginName, _version: &str) { + unimplemented!(); + } + + fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { + let plugin = self.toolset.versions.get_mut(plugin_name).unwrap(); + plugin.versions = versions + .iter() + .map(|v| ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v.clone()))) + .collect(); + let tools = self + .doc + .entry("tools") + .or_insert_with(table) + .as_table_mut() + .unwrap(); + + if versions.len() == 1 { + tools.insert(plugin_name, value(versions[0].clone())); + } else { + let mut arr = Array::new(); + for v in versions { + arr.push(v); + } + tools.insert(plugin_name, Item::Value(Value::Array(arr))); + } + } + + fn save(&self) -> Result<()> { + let contents = self.dump(); + Ok(fs::write(&self.path, contents)?) + } + + fn dump(&self) -> String { + self.doc.to_string() + } + + fn to_toolset(&self) -> Toolset { + self.toolset.clone() + } + + fn settings(&self) -> SettingsBuilder { + self.settings.clone() + } + + fn aliases(&self) -> AliasMap { + self.alias.clone() + } +} + +#[allow(dead_code)] // TODO: remove +const ENV_SUGGESTION: &str = r#" +[env] +FOO = "bar" +"#; + +#[cfg(test)] +mod tests { + use indoc::formatdoc; + use insta::{assert_debug_snapshot, assert_display_snapshot}; + + use crate::dirs; + + use super::*; + + #[test] + fn test_fixture() { + let cf = RtxToml::from_file(&dirs::HOME.join("fixtures/.rtx.toml")).unwrap(); + + assert_debug_snapshot!(cf.env()); + assert_debug_snapshot!(cf.settings()); + assert_debug_snapshot!(cf.plugins()); + assert_debug_snapshot!(cf.toolset); + assert_debug_snapshot!(cf.alias); + + assert_display_snapshot!(cf); + } + + #[test] + fn test_env() { + let cf = RtxToml::from_str(formatdoc! {r#" + [env] + foo="bar" + "#}) + .unwrap(); + + assert_debug_snapshot!(cf.env(), @r###" + { + "foo": "bar", + } + "###); + assert_display_snapshot!(cf); + } + + #[test] + fn test_set_alias() { + let mut cf = RtxToml::from_str(formatdoc! {r#" + [alias.nodejs] + 16 = "16.0.0" + 18 = "18.0.0" + "#}) + .unwrap(); + + cf.set_alias("nodejs", "18", "18.0.1"); + cf.set_alias("nodejs", "20", "20.0.0"); + cf.set_alias("python", "3.10", "3.10.0"); + + assert_debug_snapshot!(cf.alias); + assert_display_snapshot!(cf); + } + + #[test] + fn test_remove_alias() { + let mut cf = RtxToml::from_str(formatdoc! {r#" + [alias.nodejs] + 16 = "16.0.0" + 18 = "18.0.0" + + [alias.python] + "3.10" = "3.10.0" + "#}) + .unwrap(); + cf.remove_alias("nodejs", "16").unwrap(); + cf.remove_alias("python", "3.10").unwrap(); + + assert_debug_snapshot!(cf.alias); + assert_display_snapshot!(cf); + } + + #[test] + fn test_replace_versions() { + let mut cf = RtxToml::from_str(formatdoc! {r#" + [tools] + nodejs = ["16.0.0", "18.0.0"] + "#}) + .unwrap(); + cf.replace_versions( + &PluginName::from("nodejs"), + &["16.0.1".into(), "18.0.1".into()], + ); + + assert_debug_snapshot!(cf.toolset); + assert_display_snapshot!(cf); + } + + #[test] + fn test_remove_plugin() { + let mut cf = RtxToml::from_str(formatdoc! {r#" + [tools] + nodejs = ["16.0.0", "18.0.0"] + "#}) + .unwrap(); + cf.remove_plugin(&PluginName::from("nodejs")); + + assert_debug_snapshot!(cf.toolset); + assert_display_snapshot!(cf); + } +} diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 2345128bc..0e681ec8a 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -13,7 +13,7 @@ use once_cell::sync::OnceCell; use toml::Value; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::settings::{MissingRuntimeBehavior, Settings, SettingsBuilder}; +use crate::config::settings::{MissingRuntimeBehavior, SettingsBuilder}; use crate::config::AliasMap; use crate::plugins::PluginName; use crate::toolset::Toolset; @@ -28,8 +28,8 @@ pub struct RTXFile { pub path: PathBuf, pub plugins: IndexMap, pub env: HashMap, + pub settings: SettingsBuilder, edit: OnceCell>, - settings: SettingsBuilder, } #[derive(Debug, PartialEq, Eq, Hash, Default)] @@ -75,8 +75,8 @@ impl RTXFile { Ok(rf) } - pub fn settings(&self) -> Settings { - self.settings.build() + pub fn settings(&self) -> SettingsBuilder { + self.settings.clone() } fn parse_toplevel_key(&mut self, k: &String, v: &Value) -> Result<()> { @@ -417,6 +417,14 @@ impl ConfigFile for RTXFile { fn to_toolset(&self) -> Toolset { todo!() } + + fn settings(&self) -> SettingsBuilder { + SettingsBuilder::default() + } + + fn aliases(&self) -> AliasMap { + AliasMap::default() + } } #[cfg(test)] diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-2.snap new file mode 100644 index 000000000..8913bebf1 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-2.snap @@ -0,0 +1,7 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[env] +foo="bar" + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap new file mode 100644 index 000000000..7c55720bd --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -0,0 +1,20 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.settings() +--- +SettingsBuilder { + experimental: None, + missing_runtime_behavior: None, + always_keep_download: None, + legacy_version_file: None, + plugin_autoupdate_last_check_duration: None, + aliases: None, + verbose: None, + asdf_compat: None, + jobs: None, + shorthands_file: None, + disable_default_shorthands: None, + log_level: None, + shims_dir: None, + raw: None, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap new file mode 100644 index 000000000..07e485886 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap @@ -0,0 +1,25 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.plugins() +--- +{ + "terraform": [ + "terraform@1.0.0", + ], + "nodejs": [ + "nodejs@16", + "nodejs@prefix:18", + "nodejs@ref:master", + "nodejs@path:~/.nodes/14", + ], + "jq": [ + "jq@prefix:1.6", + ], + "shellcheck": [ + "shellcheck@0.9.0", + ], + "python": [ + "python@3.10.0", + "python@3.9.0", + ], +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap new file mode 100644 index 000000000..8d3825ca9 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -0,0 +1,134 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.toolset +--- +Toolset { + versions: { + "terraform": ToolVersionList { + versions: [ + ToolVersion { + plugin_name: "terraform", + type: Version( + "1.0.0", + ), + rtv: None, + repo: None, + options: {}, + }, + ], + source: RtxToml( + "", + ), + }, + "nodejs": ToolVersionList { + versions: [ + ToolVersion { + plugin_name: "nodejs", + type: Version( + "16", + ), + rtv: None, + repo: None, + options: {}, + }, + ToolVersion { + plugin_name: "nodejs", + type: Prefix( + "18", + ), + rtv: None, + repo: None, + options: {}, + }, + ToolVersion { + plugin_name: "nodejs", + type: Ref( + "master", + ), + rtv: None, + repo: None, + options: {}, + }, + ToolVersion { + plugin_name: "nodejs", + type: Path( + "~/.nodes/14", + ), + rtv: None, + repo: None, + options: {}, + }, + ], + source: RtxToml( + "", + ), + }, + "jq": ToolVersionList { + versions: [ + ToolVersion { + plugin_name: "jq", + type: Prefix( + "1.6", + ), + rtv: None, + repo: Some( + "https://github.com/AZMCode/asdf-jq", + ), + options: {}, + }, + ], + source: RtxToml( + "", + ), + }, + "shellcheck": ToolVersionList { + versions: [ + ToolVersion { + plugin_name: "shellcheck", + type: Version( + "0.9.0", + ), + rtv: None, + repo: None, + options: {}, + }, + ], + source: RtxToml( + "", + ), + }, + "python": ToolVersionList { + versions: [ + ToolVersion { + plugin_name: "python", + type: Version( + "3.10.0", + ), + rtv: None, + repo: None, + options: { + "venv": ".venv", + }, + }, + ToolVersion { + plugin_name: "python", + type: Version( + "3.9.0", + ), + rtv: None, + repo: None, + options: {}, + }, + ], + source: RtxToml( + "", + ), + }, + }, + source: Some( + RtxToml( + "", + ), + ), + plugins: {}, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap new file mode 100644 index 000000000..376c3376e --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap @@ -0,0 +1,9 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.alias +--- +{ + "nodejs": { + "my_custom_node": "18", + }, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap new file mode 100644 index 000000000..e6f4c6278 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -0,0 +1,25 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[env] +NODE_ENV = 'production' + +[tools] +terraform = '1.0.0' +nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] +jq = { prefix = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' } +shellcheck = { version = '0.9.0' } +python = [ + { version = '3.10.0', venv = '.venv' }, + { version = '3.9.0' }, +] + +[settings] +verbose = true +missing_runtime_behavior = 'warn' +shims_dir = '~/.rtx/shims' + +[alias.nodejs] +my_custom_node = '18' + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture.snap new file mode 100644 index 000000000..7caa22cf7 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture.snap @@ -0,0 +1,7 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.env() +--- +{ + "NODE_ENV": "production", +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap new file mode 100644 index 000000000..78c5edcad --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap @@ -0,0 +1,7 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[alias.nodejs] +18 = "18.0.0" + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap new file mode 100644 index 000000000..0309db019 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap @@ -0,0 +1,9 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.alias +--- +{ + "nodejs": { + "18": "18.0.0", + }, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap new file mode 100644 index 000000000..4ea76e5f3 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap @@ -0,0 +1,7 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[tools] +nodejs = ["16.0.0", "18.0.0"] + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap new file mode 100644 index 000000000..6b71c05c3 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap @@ -0,0 +1,13 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.toolset +--- +Toolset { + versions: {}, + source: Some( + RtxToml( + "", + ), + ), + plugins: {}, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap new file mode 100644 index 000000000..2423c3fa4 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap @@ -0,0 +1,7 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[tools] +nodejs = ["16.0.1", "18.0.1"] + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap new file mode 100644 index 000000000..77f83b581 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -0,0 +1,39 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.toolset +--- +Toolset { + versions: { + "nodejs": ToolVersionList { + versions: [ + ToolVersion { + plugin_name: "nodejs", + type: Version( + "16.0.1", + ), + rtv: None, + repo: None, + options: {}, + }, + ToolVersion { + plugin_name: "nodejs", + type: Version( + "18.0.1", + ), + rtv: None, + repo: None, + options: {}, + }, + ], + source: RtxToml( + "", + ), + }, + }, + source: Some( + RtxToml( + "", + ), + ), + plugins: {}, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap new file mode 100644 index 000000000..466b9f027 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap @@ -0,0 +1,12 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[alias.nodejs] +16 = "16.0.0" +18 = "18.0.1" +20 = "20.0.0" + +[alias.python] +"3.10" = "3.10.0" + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap new file mode 100644 index 000000000..e4fb6ac7e --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap @@ -0,0 +1,14 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf.alias +--- +{ + "nodejs": { + "16": "16.0.0", + "18": "18.0.1", + "20": "20.0.0", + }, + "python": { + "3.10": "3.10.0", + }, +} diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index b79249f84..5177344b8 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -4,12 +4,14 @@ use std::fs; use std::fs::read_to_string; use std::path::{Path, PathBuf}; +use crate::config::AliasMap; use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; use indexmap::IndexMap; use itertools::Itertools; use crate::config::config_file::{ConfigFile, ConfigFileType}; +use crate::config::settings::SettingsBuilder; use crate::file::display_path; use crate::plugins::PluginName; use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; @@ -109,7 +111,7 @@ impl From<&ToolVersions> for Toolset { let v = match version.split_once(':') { Some(("prefix", v)) => ToolVersionType::Prefix(v.to_string()), Some(("ref", v)) => ToolVersionType::Ref(v.to_string()), - Some(("path", v)) => ToolVersionType::Path(v.to_string()), + Some(("path", v)) => ToolVersionType::Path(PathBuf::from(v)), None if version == "system" => ToolVersionType::System, _ => ToolVersionType::Version(version.to_string()), }; @@ -197,6 +199,14 @@ impl ConfigFile for ToolVersions { fn to_toolset(&self) -> Toolset { self.into() } + + fn settings(&self) -> SettingsBuilder { + SettingsBuilder::default() + } + + fn aliases(&self) -> AliasMap { + AliasMap::default() + } } #[cfg(test)] @@ -326,5 +336,13 @@ pub(crate) mod tests { fn to_toolset(&self) -> Toolset { todo!() } + + fn settings(&self) -> SettingsBuilder { + todo!() + } + + fn aliases(&self) -> AliasMap { + todo!() + } } } diff --git a/src/config/mod.rs b/src/config/mod.rs index bed806bd6..e1217fba3 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -12,7 +12,9 @@ use rayon::prelude::*; pub use settings::{MissingRuntimeBehavior, Settings}; +use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtxrc::RTXFile; +use crate::config::config_file::ConfigFile; use crate::plugins::{Plugin, PluginName}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::{dirs, env, file}; @@ -27,20 +29,27 @@ pub struct Config { pub settings: Settings, pub rtxrc: RTXFile, pub legacy_files: IndexMap, - pub config_files: Vec, + pub config_files: IndexMap>, pub aliases: AliasMap, pub plugins: IndexMap>, + pub env: IndexMap, shorthands: OnceCell>, } impl Config { pub fn load() -> Result { - let rtxrc = load_rtxrc()?; - let settings = rtxrc.settings(); let plugins = load_plugins()?; + let rtxrc = load_rtxrc()?; + let mut settings = rtxrc.settings(); + let config_files = load_all_config_files(&settings.build(), &plugins, &IndexMap::new()); + for cf in config_files.values() { + settings.merge(cf.settings()); + } + let settings = settings.build(); let legacy_files = load_legacy_files(&settings, &plugins); - let config_files = find_all_config_files(&legacy_files); - let aliases = load_aliases(&settings, &plugins); + let config_files = load_all_config_files(&settings, &plugins, &legacy_files); + let env = load_env(&config_files); + let aliases = load_aliases(&settings, &plugins, &config_files); let config = Self { settings, @@ -49,6 +58,7 @@ impl Config { aliases, rtxrc, plugins, + env, shorthands: OnceCell::new(), }; @@ -122,10 +132,13 @@ fn load_legacy_files( .collect() } -fn find_all_config_files(legacy_filenames: &IndexMap) -> Vec { +fn load_all_config_files( + settings: &Settings, + plugins: &IndexMap>, + legacy_filenames: &IndexMap, +) -> IndexMap> { let mut filenames = vec![ - // ".rtxrc.toml", - // ".rtxrc", + env::RTX_DEFAULT_CONFIG_FILENAME.as_str(), env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str(), ]; for filename in legacy_filenames.keys() { @@ -140,10 +153,52 @@ fn find_all_config_files(legacy_filenames: &IndexMap) -> Vec config_files.push(home_config); } - config_files.into_iter().unique().collect() + config_files + .into_iter() + .unique() + .collect_vec() + .into_par_iter() + .map( + |f| match parse_config_file(&f, settings, legacy_filenames, plugins) { + Ok(cf) => Some((f, cf)), + Err(err) => { + warn!("error parsing: {} {err}", f.display()); + None + } + }, + ) + .collect::>() + .into_iter() + .flatten() + .collect() } -fn load_aliases(settings: &Settings, plugins: &IndexMap>) -> AliasMap { +fn parse_config_file( + f: &PathBuf, + settings: &Settings, + legacy_filenames: &IndexMap, + plugins: &IndexMap>, +) -> Result> { + match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { + Some(plugin) => LegacyVersionFile::parse(settings, f.into(), plugins.get(plugin).unwrap()) + .map(|f| Box::new(f) as Box), + None => config_file::parse(f), + } +} + +fn load_env(config_files: &IndexMap>) -> IndexMap { + let mut env = IndexMap::new(); + for cf in config_files.values() { + env.extend(cf.env()); + } + env +} + +fn load_aliases( + settings: &Settings, + plugins: &IndexMap>, + config_files: &IndexMap>, +) -> AliasMap { let mut aliases: AliasMap = IndexMap::new(); let plugin_aliases: Vec<_> = plugins .values() @@ -168,6 +223,17 @@ fn load_aliases(settings: &Settings, plugins: &IndexMap> } } + for config_file in config_files.values() { + for (plugin, plugin_aliases) in config_file.aliases() { + for (from, to) in plugin_aliases { + aliases + .entry(plugin.clone()) + .or_insert_with(IndexMap::new) + .insert(from, to); + } + } + } + for (plugin, plugin_aliases) in &settings.aliases { for (from, to) in plugin_aliases { aliases @@ -197,7 +263,7 @@ impl Display for Config { let config_files = self .config_files .iter() - .map(|p| { + .map(|(p, _)| { p.to_string_lossy() .to_string() .replace(&dirs::HOME.to_string_lossy().to_string(), "~") @@ -210,9 +276,10 @@ impl Display for Config { #[cfg(test)] mod tests { - use super::*; use insta::assert_display_snapshot; + use super::*; + #[test] fn test_load() { let config = Config::load().unwrap(); diff --git a/src/config/settings.rs b/src/config/settings.rs index 728ca821a..4500213db 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -116,7 +116,7 @@ impl SettingsBuilder { // } // } - pub fn _merge(&mut self, other: Self) -> &mut Self { + pub fn merge(&mut self, other: Self) -> &mut Self { if other.experimental.is_some() { self.experimental = other.experimental; } @@ -247,7 +247,7 @@ mod tests { missing_runtime_behavior: Some(AutoInstall), ..SettingsBuilder::default() }; - s1._merge(s2); + s1.merge(s2); assert_eq!(s1.missing_runtime_behavior, Some(AutoInstall)); } diff --git a/src/env.rs b/src/env.rs index f6d65afe8..0798de656 100644 --- a/src/env.rs +++ b/src/env.rs @@ -115,6 +115,11 @@ lazy_static! { } else { var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) }; + pub static ref RTX_DEFAULT_CONFIG_FILENAME: String = if cfg!(test) { + ".test.rtx.toml".into() + } else { + var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into()) + }; pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); pub static ref RTX_EXPERIMENTAL: bool = var_is_true("RTX_EXPERIMENTAL"); diff --git a/src/hook_env.rs b/src/hook_env.rs index 22628fdda..083e977e6 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -155,7 +155,7 @@ pub fn get_watch_files(config: &Config) -> HashSet { if dirs::ROOT.exists() { watches.insert(dirs::ROOT.clone()); } - for cf in &config.config_files { + for cf in config.config_files.keys() { watches.insert(cf.clone()); } diff --git a/src/output.rs b/src/output.rs index 73e53f766..87f1a1c11 100644 --- a/src/output.rs +++ b/src/output.rs @@ -34,6 +34,12 @@ impl Output { } } +impl Default for Output { + fn default() -> Self { + Self::new() + } +} + #[derive(Debug)] pub struct OutputStream { pub content: String, diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 80b1555e0..56b612f35 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -14,7 +14,7 @@ use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; -pub use script_manager::{InstallType, Script, ScriptManager}; +pub use script_manager::{Script, ScriptManager}; use crate::cache::CacheManager; use crate::cmd::cmd; diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 006a28a10..29bd370d9 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -37,8 +37,8 @@ pub enum Script { ParseLegacyFile(String), // RuntimeVersion - Download(InstallType), - Install(InstallType), + Download, + Install, Uninstall, ListBinPaths, // ExecEnv, @@ -54,30 +54,11 @@ impl Display for Script { Script::ParseLegacyFile(_) => write!(f, "parse-legacy-file"), // RuntimeVersion - Script::Install(_) => write!(f, "install"), + Script::Install => write!(f, "install"), Script::Uninstall => write!(f, "uninstall"), Script::ListBinPaths => write!(f, "list-bin-paths"), // Script::ExecEnv => write!(f, "exec-env"), - Script::Download(_) => write!(f, "download"), - } - } -} - -#[derive(Debug, Clone)] -pub enum InstallType { - Version(String), - Ref(String), - Path(PathBuf), - System, -} - -impl Display for InstallType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - InstallType::Version(v) => write!(f, "{v}"), - InstallType::Ref(r) => write!(f, "ref:{r}"), - InstallType::Path(p) => write!(f, "path:{}", p.display()), - InstallType::System => write!(f, "system"), + Script::Download => write!(f, "download"), } } } diff --git a/src/runtimes.rs b/src/runtimes.rs index 8bf6cbcce..f0dbcd04e 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -15,7 +15,9 @@ use crate::config::Config; use crate::config::Settings; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::hash::hash_to_str; -use crate::plugins::{InstallType, Plugin, Script, ScriptManager}; +use crate::plugins::Script::{Download, Install}; +use crate::plugins::{Plugin, Script, ScriptManager}; +use crate::toolset::{ToolVersion, ToolVersionType}; use crate::ui::progress_report::ProgressReport; use crate::{dirs, env, fake_asdf, file}; @@ -26,7 +28,6 @@ pub struct RuntimeVersion { pub version: String, pub plugin: Arc, pub install_path: PathBuf, - pub install_type: InstallType, download_path: PathBuf, cache_path: PathBuf, script_man: ScriptManager, @@ -34,28 +35,23 @@ pub struct RuntimeVersion { } impl RuntimeVersion { - pub fn new(plugin: Arc, install_type: InstallType) -> Self { - let version = match &install_type { - InstallType::Version(v) => v.to_string(), - InstallType::Ref(r) => format!("ref-{r}"), - InstallType::Path(p) => p.display().to_string(), - InstallType::System => "system".into(), - }; - let install_path = match &install_type { - InstallType::Path(p) => p.clone(), + pub fn new(plugin: Arc, version: String, tv: ToolVersion) -> Self { + let install_path = match &tv.r#type { + ToolVersionType::Path(p) => p.clone(), _ => dirs::INSTALLS.join(&plugin.name).join(&version), }; - let download_path = match &install_type { - InstallType::Path(p) => p.clone(), + let download_path = match &tv.r#type { + ToolVersionType::Path(p) => p.clone(), _ => dirs::DOWNLOADS.join(&plugin.name).join(&version), }; - let cache_path = match &install_type { - InstallType::Path(p) => dirs::CACHE.join(&plugin.name).join(hash_to_str(&p)), + let cache_path = match &tv.r#type { + ToolVersionType::Path(p) => dirs::CACHE.join(&plugin.name).join(hash_to_str(&p)), _ => dirs::CACHE.join(&plugin.name).join(&version), }; Self { script_man: build_script_man( - install_type.clone(), + &tv, + &version, &plugin.plugin_path, &install_path, &download_path, @@ -67,7 +63,6 @@ impl RuntimeVersion { install_path, version, plugin, - install_type, } } @@ -85,11 +80,9 @@ impl RuntimeVersion { pr.enable_steady_tick(); let settings = &config.settings; - debug!("install {} {}", self, self.install_type); + debug!("install {}", self); self.create_install_dirs()?; - let download = Script::Download(self.install_type.clone()); - let install = Script::Install(self.install_type.clone()); let run_script = |script| { self.script_man.run_by_line( @@ -110,17 +103,17 @@ impl RuntimeVersion { ) }; - if self.script_man.script_exists(&download) { + if self.script_man.script_exists(&Download) { pr.set_message("downloading".into()); - run_script(download)?; + run_script(Download)?; } pr.set_message("installing".into()); - run_script(install)?; + run_script(Install)?; self.cleanup_install_dirs(settings); // attempt to touch all the .tool-version files to trigger updates in hook-env let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; - touch_dirs.extend(config.config_files.iter().cloned()); + touch_dirs.extend(config.config_files.keys().cloned()); for path in touch_dirs { let err = file::touch_dir(&path); if let Err(err) = err { @@ -156,12 +149,9 @@ impl RuntimeVersion { } pub fn is_installed(&self) -> bool { - match &self.install_type { - InstallType::System => true, - InstallType::Path(p) => p.exists(), - InstallType::Version(_) | InstallType::Ref(_) => { - self.install_path.exists() && !self.incomplete_file_path().exists() - } + match self.version.as_str() { + "system" => true, + _ => self.install_path.exists() && !self.incomplete_file_path().exists(), } } @@ -259,12 +249,13 @@ impl PartialEq for RuntimeVersion { } fn build_script_man( - install_type: InstallType, + tv: &ToolVersion, + version: &str, plugin_path: &Path, install_path: &Path, download_path: &Path, ) -> ScriptManager { - let sm = ScriptManager::new(plugin_path.to_path_buf()) + let mut sm = ScriptManager::new(plugin_path.to_path_buf()) .with_envs(env::PRISTINE_ENV.clone()) .with_env("PATH".into(), fake_asdf::get_path_with_fake_asdf()) .with_env( @@ -276,13 +267,17 @@ fn build_script_man( download_path.to_string_lossy().to_string(), ) .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()); - match install_type { - InstallType::Version(v) => sm + for (key, value) in tv.options.iter() { + let k = format!("RTX_TOOL_OPT__{}", key.to_uppercase()); + sm = sm.with_env(k, value.clone()); + } + match &tv.r#type { + ToolVersionType::Version(_) | ToolVersionType::Prefix(_) => sm .with_env("ASDF_INSTALL_TYPE".into(), "version".into()) - .with_env("ASDF_INSTALL_VERSION".into(), v), - InstallType::Ref(r) => sm + .with_env("ASDF_INSTALL_VERSION".into(), version.to_string()), + ToolVersionType::Ref(r) => sm .with_env("ASDF_INSTALL_TYPE".into(), "ref".into()) - .with_env("ASDF_INSTALL_VERSION".into(), r), + .with_env("ASDF_INSTALL_VERSION".into(), r.to_string()), _ => sm, } } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 3dacaaf32..b542e5462 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,16 +1,12 @@ -use color_eyre::eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; -use crate::config::config_file::legacy_version::LegacyVersionFile; -use crate::config::config_file::ConfigFile; -use crate::config::{config_file, Config}; - +use crate::config::Config; +use crate::env; use crate::toolset::tool_version::ToolVersionType; use crate::toolset::{ToolSource, ToolVersion, Toolset}; -use crate::{env, file}; #[derive(Debug)] pub struct ToolsetBuilder { @@ -57,28 +53,11 @@ impl ToolsetBuilder { fn load_config_files(config: &Config, ts: &mut Toolset) { let toolsets: Vec<_> = config .config_files - .par_iter() + .values() + .collect_vec() + .into_par_iter() .rev() - .filter_map(|path| { - let filename = path.file_name().unwrap().to_string_lossy().to_string(); - let result: Result = match config.legacy_files.get(&filename) { - Some(plugin) => LegacyVersionFile::parse( - &config.settings, - path.into(), - config.plugins.get(plugin).unwrap(), - ) - .map(|cf| cf.to_toolset()), - None => config_file::parse(path).map(|cf| cf.to_toolset()), - }; - match result { - Ok(ts) => Some(ts), - Err(e) => { - warn!("error parsing config file: {}", e); - warn!("file: {}", file::display_path(path)); - None - } - } - }) + .map(|cf| cf.to_toolset()) .collect(); for toolset in toolsets { ts.merge(toolset); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 44c7608c1..77549e07b 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -17,13 +17,13 @@ pub use builder::ToolsetBuilder; pub use tool_source::ToolSource; pub use tool_version::ToolVersion; pub use tool_version::ToolVersionType; +pub use tool_version_list::ToolVersionList; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::{Config, MissingRuntimeBehavior, Settings}; use crate::env; -use crate::plugins::{InstallType, Plugin, PluginName}; +use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; -use crate::toolset::tool_version_list::ToolVersionList; use crate::ui::multi_progress_report::MultiProgressReport; mod builder; @@ -36,7 +36,7 @@ mod tool_version_list; /// one example is a .tool-versions file /// the idea is that we start with an empty toolset, then /// merge in other toolsets from various sources -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct Toolset { pub versions: IndexMap, source: Option, @@ -217,9 +217,10 @@ impl Toolset { .into_par_iter() .map(|p| { let versions = p.list_installed_versions()?; - Ok(versions - .into_iter() - .map(|v| RuntimeVersion::new(p.clone(), InstallType::Version(v)))) + Ok(versions.into_iter().map(|v| { + let tv = ToolVersion::new(p.name.clone(), ToolVersionType::Version(v.clone())); + RuntimeVersion::new(p.clone(), v, tv) + })) }) .collect::>>()? .into_iter() @@ -256,7 +257,7 @@ impl Toolset { .filter(|v| v.is_installed()) .collect() } - pub fn env(&self) -> IndexMap { + pub fn env(&self, config: &Config) -> IndexMap { let mut entries: IndexMap = self .list_current_installed_versions() .into_par_iter() @@ -272,6 +273,7 @@ impl Toolset { .rev() .collect(); entries.sort_keys(); + entries.extend(config.env.clone()); entries } pub fn path_env(&self, settings: &Settings) -> String { diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index 6efbb7980..666bb04d6 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -7,7 +7,7 @@ use crate::file::display_path; #[derive(Debug, Clone)] pub enum ToolSource { ToolVersions(PathBuf), - // RtxRc(PathBuf), + RtxToml(PathBuf), LegacyVersionFile(PathBuf), Argument, Environment(String, String), @@ -17,7 +17,7 @@ impl Display for ToolSource { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { ToolSource::ToolVersions(path) => write!(f, "{}", display_path(path)), - // ToolSource::RtxRc(path) => write!(f, "{}", display_path(path)), + ToolSource::RtxToml(path) => write!(f, "{}", display_path(path)), ToolSource::LegacyVersionFile(path) => write!(f, "{}", display_path(path)), ToolSource::Argument => write!(f, "--runtime"), ToolSource::Environment(k, v) => write!(f, "{k}={v}"), @@ -38,6 +38,9 @@ mod tests { let ts = ToolSource::ToolVersions(path); assert_str_eq!(ts.to_string(), "/home/user/.test-tool-versions"); + let ts = ToolSource::RtxToml(PathBuf::from("/home/user/.rtx.toml")); + assert_str_eq!(ts.to_string(), "/home/user/.rtx.toml"); + let ts = ToolSource::Argument; assert_str_eq!(ts.to_string(), "--runtime"); diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 8e7f78441..4cc8b06ff 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -1,12 +1,14 @@ use std::fmt::{Display, Formatter}; use std::fs; +use std::path::PathBuf; use std::sync::Arc; use color_eyre::eyre::Result; +use indexmap::IndexMap; use crate::config::{Config, Settings}; use crate::dirs; -use crate::plugins::{InstallType, Plugin}; +use crate::plugins::Plugin; use crate::runtimes::RuntimeVersion; use crate::ui::progress_report::ProgressReport; @@ -16,6 +18,8 @@ pub struct ToolVersion { pub plugin_name: String, pub r#type: ToolVersionType, pub rtv: Option, + pub repo: Option, + pub options: IndexMap, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -23,7 +27,7 @@ pub enum ToolVersionType { Version(String), Prefix(String), Ref(String), - Path(String), + Path(PathBuf), System, } @@ -33,6 +37,8 @@ impl ToolVersion { plugin_name, r#type, rtv: None, + repo: None, + options: Default::default(), } } @@ -61,7 +67,7 @@ impl ToolVersion { return self.resolve_ref(plugin, r); } Some(("path", p)) => { - return self.resolve_path(plugin, p); + return self.resolve_path(plugin, &PathBuf::from(p)); } Some(("prefix", p)) => { return self.resolve_prefix(settings, plugin, p); @@ -71,13 +77,13 @@ impl ToolVersion { if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { // if the version is already installed, no need to fetch all of the remote versions - let rtv = RuntimeVersion::new(plugin, InstallType::Version(v)); + let rtv = RuntimeVersion::new(plugin, v, self.clone()); return Ok(Some(rtv)); } let matches = plugin.list_versions_matching(settings, &v)?; if matches.contains(&v) { - let rtv = RuntimeVersion::new(plugin, InstallType::Version(v)); + let rtv = RuntimeVersion::new(plugin, v, self.clone()); Ok(Some(rtv)) } else { self.resolve_prefix(settings, plugin, &v) @@ -96,18 +102,18 @@ impl ToolVersion { None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; - let rtv = RuntimeVersion::new(plugin, InstallType::Version(v.to_string())); + let rtv = RuntimeVersion::new(plugin, v.to_string(), self.clone()); Ok(Some(rtv)) } fn resolve_ref(&self, plugin: Arc, r: &str) -> Result> { - let rtv = RuntimeVersion::new(plugin, InstallType::Ref(r.to_string())); + let rtv = RuntimeVersion::new(plugin, format!("ref-{}", r), self.clone()); Ok(Some(rtv)) } - fn resolve_path(&self, plugin: Arc, path: &str) -> Result> { + fn resolve_path(&self, plugin: Arc, path: &PathBuf) -> Result> { let path = fs::canonicalize(path)?; - let rtv = RuntimeVersion::new(plugin, InstallType::Path(path)); + let rtv = RuntimeVersion::new(plugin, path.display().to_string(), self.clone()); Ok(Some(rtv)) } @@ -140,7 +146,7 @@ impl Display for ToolVersionType { ToolVersionType::Version(v) => write!(f, "{v}"), ToolVersionType::Prefix(p) => write!(f, "prefix:{p}"), ToolVersionType::Ref(r) => write!(f, "ref:{r}"), - ToolVersionType::Path(p) => write!(f, "path:{p}"), + ToolVersionType::Path(p) => write!(f, "path:{}", p.display()), ToolVersionType::System => write!(f, "system"), } } @@ -173,7 +179,7 @@ mod tests { assert_str_eq!(tv.to_string(), "foo@prefix:1.2.3"); let tv = ToolVersion::new(foo.clone(), ToolVersionType::Ref("master".to_string())); assert_str_eq!(tv.to_string(), "foo@ref:master"); - let tv = ToolVersion::new(foo.clone(), ToolVersionType::Path("~".to_string())); + let tv = ToolVersion::new(foo.clone(), ToolVersionType::Path(PathBuf::from("~"))); assert_str_eq!(tv.to_string(), "foo@path:~"); let tv = ToolVersion::new(foo, ToolVersionType::System); assert_str_eq!(tv.to_string(), "foo@system"); diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml new file mode 100644 index 000000000..7bf2418c2 --- /dev/null +++ b/test/fixtures/.rtx.toml @@ -0,0 +1,20 @@ +[env] +NODE_ENV = 'production' + +[tools] +terraform = '1.0.0' +nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] +jq = { prefix = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' } +shellcheck = { version = '0.9.0' } +python = [ + { version = '3.10.0', venv = '.venv' }, + { version = '3.9.0' }, +] + +[settings] +verbose = true +missing_runtime_behavior = 'warn' +shims_dir = '~/.rtx/shims' + +[alias.nodejs] +my_custom_node = '18' diff --git a/test/fixtures/.rtxrc.toml b/test/fixtures/.rtxrc.toml deleted file mode 100644 index d1a289228..000000000 --- a/test/fixtures/.rtxrc.toml +++ /dev/null @@ -1,2 +0,0 @@ -python = ['3.10'] -nodejs = ['16', '18'] From 298ef06e212b68e100b6bed7a8a5d0fe3009171a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 17:21:48 -0600 Subject: [PATCH 0344/1891] chore: Release rtx-cli version 1.20.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3cd8dda3c..6ac4006e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.19.1" +version = "1.20.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 0e168879b..6fa4ff7ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.19.1" +version = "1.20.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0fb9b0264..bdb21106f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.19.1 +rtx 1.20.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -312,7 +312,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.1/rtx-v1.19.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.0/rtx-v1.20.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index e43c251f2..6c06b353d 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.18.2"; + version = "1.20.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 8bbb32e36..179bb5449 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.19.1" +.TH rtx 1 "rtx 1.20.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -129,6 +129,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.19.1 +v1.20.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index adade6db4..cc59b8c24 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.19.1 +Version: 1.20.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e1ae1d1db..f8420f742 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -232,7 +232,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.19.1/rtx-v1.19.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.0/rtx-v1.20.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From d87c1d63dc0a86de112552aea9428f9e94009fe1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 17:24:07 -0600 Subject: [PATCH 0345/1891] docs --- README.md | 1 + src/cli/render_help.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index bdb21106f..2dbc709a0 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Note that calling `which node` gives us a real path to the binary, not a shim. - **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. - **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. - **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. +- **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. ## Quickstart diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f8420f742..1d18f52b3 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -51,6 +51,7 @@ Note that calling `which node` gives us a real path to the binary, not a shim. - **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. - **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. - **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. +- **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. ## Quickstart From 86fc4f847d22e0212be33b84a8df30c21e7e7539 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:06:48 -0600 Subject: [PATCH 0346/1891] use rtx-python plugin instead of asdf-python --- scripts/update-shorthand-repo.sh | 14 +++++++------- src/default_shorthands.rs | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index e850d5d30..e7320a420 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -6,7 +6,7 @@ git clone --depth 1 https://github.com/asdf-vm/asdf-plugins rm -f src/default_shorthands.rs num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') -num_plugins=$((num_plugins + 3)) # + for custom aliases (node, tiny, etc) +num_plugins=$((num_plugins + 4)) # + for custom aliases (node, tiny, etc) cat >src/default_shorthands.rs <> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] const DEFAULT_SHORTHAND_LIST: [(&str, &str); $num_plugins] = [ - // rtx custom aliases - ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), - ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), - ("go", "https://github.com/kennyp/asdf-golang.git"), - - // asdf original aliases from https://github.com/asdf-vm/asdf-plugins + // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins EOF for file in asdf-plugins/plugins/*; do plugin=$(basename "$file") @@ -34,6 +29,11 @@ for file in asdf-plugins/plugins/*; do echo " (\"$plugin\", \"$repository\")," >>src/default_shorthands.rs done cat >>src/default_shorthands.rs <> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 614] = [ - // rtx custom aliases - ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), - ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), - ("go", "https://github.com/kennyp/asdf-golang.git"), - - // asdf original aliases from https://github.com/asdf-vm/asdf-plugins +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 615] = [ + // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), ("act", "https://github.com/grimoh/asdf-act.git"), @@ -626,4 +621,9 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 614] = [ ("zola", "https://github.com/salasrod/asdf-zola.git"), ("zoxide", "https://github.com/nyrst/asdf-zoxide"), ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), + // rtx custom shorthands + ("go", "https://github.com/kennyp/asdf-golang.git"), + ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), + ("python", "https://github.com/jdxcode/rtx-python.git"), + ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), ]; From fd186d87f653aea713deef7c6c391ac20d7f69c9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:07:25 -0600 Subject: [PATCH 0347/1891] support RTX_ADD_PATH to export paths from exec-env --- src/runtimes.rs | 57 +++++++++++++++++++++++++++++++--------------- src/toolset/mod.rs | 2 +- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index f0dbcd04e..e45989c2a 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::env::split_paths; use std::fmt::{Display, Formatter}; use std::fs::{create_dir_all, remove_dir_all, File}; use std::path::{Path, PathBuf}; @@ -9,6 +10,7 @@ use color_eyre::eyre::{Result, WrapErr}; use console::style; use indicatif::ProgressStyle; use once_cell::sync::Lazy; +use once_cell::sync::OnceCell; use crate::cache::CacheManager; use crate::config::Config; @@ -32,6 +34,7 @@ pub struct RuntimeVersion { cache_path: PathBuf, script_man: ScriptManager, bin_paths_cache: CacheManager>, + exec_env_cache: Box>>, } impl RuntimeVersion { @@ -63,6 +66,7 @@ impl RuntimeVersion { install_path, version, plugin, + exec_env_cache: Box::new(OnceCell::new()), } } @@ -129,12 +133,27 @@ impl RuntimeVersion { } pub fn list_bin_paths(&self, settings: &Settings) -> Result> { - Ok(self + let mut bin_paths: Vec<_> = self .bin_paths_cache .get_or_try_init(|| self.fetch_bin_paths(settings))? .iter() .map(|path| self.install_path.join(path)) - .collect()) + .collect(); + + for bin_path in self.list_exec_env_bin_paths()? { + bin_paths.push(bin_path); + } + + Ok(bin_paths) + } + + fn list_exec_env_bin_paths(&self) -> Result> { + let env = self.exec_env()?; + let bin_paths = match env.get("RTX_ADD_PATH") { + Some(paths) => split_paths(paths).collect(), + None => vec![], + }; + Ok(bin_paths) } pub fn which(&self, settings: &Settings, bin_name: &str) -> Result> { @@ -182,22 +201,24 @@ impl RuntimeVersion { Ok(()) } - pub fn exec_env(&self) -> Result> { - let script = self.plugin.plugin_path.join("bin/exec-env"); - if !self.is_installed() || !script.exists() { - return Ok(HashMap::new()); - } - let ed = EnvDiff::from_bash_script(&script, &self.script_man.env)?; - let env = ed - .to_patches() - .into_iter() - .filter_map(|p| match p { - EnvDiffOperation::Add(key, value) => Some((key, value)), - EnvDiffOperation::Change(key, value) => Some((key, value)), - _ => None, - }) - .collect(); - Ok(env) + pub fn exec_env(&self) -> Result<&HashMap> { + self.exec_env_cache.get_or_try_init(|| { + let script = self.plugin.plugin_path.join("bin/exec-env"); + if !self.is_installed() || !script.exists() { + return Ok(HashMap::new()); + } + let ed = EnvDiff::from_bash_script(&script, &self.script_man.env)?; + let env = ed + .to_patches() + .into_iter() + .filter_map(|p| match p { + EnvDiffOperation::Add(key, value) => Some((key, value)), + EnvDiffOperation::Change(key, value) => Some((key, value)), + _ => None, + }) + .collect(); + Ok(env) + }) } fn fetch_bin_paths(&self, settings: &Settings) -> Result> { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 77549e07b..97c24c97b 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -262,7 +262,7 @@ impl Toolset { .list_current_installed_versions() .into_par_iter() .flat_map(|v| match v.exec_env() { - Ok(env) => env.into_iter().collect(), + Ok(env) => env.clone().into_iter().collect(), Err(e) => { warn!("Error running exec-env: {}", e); Vec::new() From 1f76bd1921d09d83723c0d51b3cfefbdc977a276 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:10:13 -0600 Subject: [PATCH 0348/1891] bug: use exec-env bin paths first --- src/runtimes.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index e45989c2a..13355dc5d 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -9,6 +9,7 @@ use std::{fmt, fs}; use color_eyre::eyre::{Result, WrapErr}; use console::style; use indicatif::ProgressStyle; +use itertools::Itertools; use once_cell::sync::Lazy; use once_cell::sync::OnceCell; @@ -133,16 +134,15 @@ impl RuntimeVersion { } pub fn list_bin_paths(&self, settings: &Settings) -> Result> { - let mut bin_paths: Vec<_> = self - .bin_paths_cache - .get_or_try_init(|| self.fetch_bin_paths(settings))? - .iter() - .map(|path| self.install_path.join(path)) - .collect(); + let mut bin_paths = self.list_exec_env_bin_paths()?; - for bin_path in self.list_exec_env_bin_paths()? { - bin_paths.push(bin_path); - } + bin_paths.extend( + self.bin_paths_cache + .get_or_try_init(|| self.fetch_bin_paths(settings))? + .iter() + .map(|path| self.install_path.join(path)) + .collect_vec(), + ); Ok(bin_paths) } From 1b9c3bcaaf5cc0ea7398e6486413920fc74c87b8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:17:35 -0600 Subject: [PATCH 0349/1891] chore: Release rtx-cli version 1.20.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/render_help.rs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ac4006e9..9e96ac677 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.20.0" +version = "1.20.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 6fa4ff7ae..edc4d5fb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.20.0" +version = "1.20.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 2dbc709a0..361ed6e77 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.20.0 +rtx 1.20.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -313,7 +313,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.0/rtx-v1.20.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.1/rtx-v1.20.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 6c06b353d..3a1e1a2d6 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.20.0"; + version = "1.20.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 179bb5449..168d402df 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.20.0" +.TH rtx 1 "rtx 1.20.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -129,6 +129,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.20.0 +v1.20.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index cc59b8c24..aa933f5e9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.20.0 +Version: 1.20.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 1d18f52b3..16da18b0b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -233,7 +233,7 @@ $ npx @jdxcode/rtx exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.0/rtx-v1.20.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.1/rtx-v1.20.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` From f5b8c219541dbb4cb4baf97407f128cfb40fc5c3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:23:47 -0600 Subject: [PATCH 0350/1891] docs --- README.md | 2 +- src/cli/render_help.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 361ed6e77..e53c71b34 100644 --- a/README.md +++ b/README.md @@ -561,7 +561,7 @@ These settings can also be managed with `rtx settings ls|get|set|unset`. It allows for functionality that is not possible with `.tool-versions`, such as: * setting arbitrary env vars while inside the directory -* passing options to plugins like `virtualenv='.venv'` for rtx-python. +* passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). * specifying plugin repo url for custom plugins so it does not need to be added manually Here is what the config looks like: diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 16da18b0b..6b69b5c1c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -481,7 +481,7 @@ These settings can also be managed with `rtx settings ls|get|set|unset`. It allows for functionality that is not possible with `.tool-versions`, such as: * setting arbitrary env vars while inside the directory -* passing options to plugins like `virtualenv='.venv'` for rtx-python. +* passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). * specifying plugin repo url for custom plugins so it does not need to be added manually Here is what the config looks like: From 8fcd13c481270404ce1c67c223ba7db564a1384a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 21:50:01 -0600 Subject: [PATCH 0351/1891] docs --- README.md | 91 +++++++++++++++++++++++++++++++++++------- src/cli/render_help.rs | 86 ++++++++++++++++++++++++++++++++------- 2 files changed, 148 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index e53c71b34..83db974b2 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,8 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes, -> see the [direnv section](#direnv) below. +> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes inside +> of an `.envrc`, see the [direnv section](#direnv) below. Install a runtime and set it as the default: @@ -119,11 +119,13 @@ v18.10.9 * [[experimental] RTX_SHIMS_DIR=~/.local/share/rtx/shims](#experimental-rtx_shims_dirlocalsharertxshims) * [Aliases](#aliases) * [Plugins](#plugins) + * [Plugin Options](#plugin-options) * [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) - * [How do I create my own plugin?](#how-do-i-create-my-own-plugin) * [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) * [Windows support?](#windows-support) + * [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) + * [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) * [Commands](#commands) * [rtx activate](#rtx-activate) * [rtx alias get](#rtx-alias-get) @@ -171,6 +173,7 @@ v18.10.9 * [Shims](#shims) * [direnv](#direnv) * [rtx inside of direnv (use rtx in .envrc)](#rtx-inside-of-direnv-use-rtx-in-envrc) + * [Do you need direnv?](#do-you-need-direnv) * [Cache Behavior](#cache-behavior) * [Plugin Cache](#plugin-cache) * [Legacy File Cache](#legacy-file-cache) @@ -753,6 +756,22 @@ See https://github.com/asdf-vm/asdf-plugins for the list of built-in plugins sho [Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn more about how they work. +### Plugin Options + +rtx has support for "plugin options" which is configuration specified in `.rtx.toml` to change behavior +of plugins. One example of this is virtualenv on python runtimes: + +```toml +[tools] +python = {version='3.11', virtualenv='.venv'} +``` + +This will be passed to all plugin scripts as `RTX_TOOL_OPTS__VIRTUALENV=.venv`. The user can specify +any option and it will be passed to the plugin in that format. + +Currently this only supports simple strings, but we can make it compatible with more complex types +(arrays, tables) fairly easily if there is a need for it. + ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. @@ -763,28 +782,60 @@ 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`. -### How do I create my own plugin? - -Just follow the [asdf docs](https://asdf-vm.com/plugins/create.html). Everything should work the same. -If it isn't, please open an issue. - ### rtx is failing or not working right -First try setting `RTX_LOG_LEVEL=debug` or `RTX_LOG_LEVEL=trace` and see if that gives you more information. -You can also set `RTX_LOG_FILE=/path/to/logfile` to write the logs to a file. +First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. +You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. -It can also be helpful to use `rtx env` to see what environment variables it wants to use. +It can also be helpful to use `rtx env` which will just output environment variables that would be set. +Also consider using [shims](#shims) which can be more compatible. + +If runtime installation isn't working right, try using the `--raw` flag which will install things in +series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact +with you for some reason this will make it work. + +Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` +to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used +to remove everything except config. -Lastly, there is an `rtx doctor` command. It doesn't have much in it but I hope to add more functionality -to that to help debug issues. +Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule +out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` +doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. + +Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues +detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. ### Windows support? This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 -It's not a near-term goal and it would require plugin modifications, but -it should be feasible. +It's not a near-term goal and it would require plugin modifications, but it should be feasible. + +### How do I use rtx with http proxies? + +Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. + +rtx doesn't really do anything with http itself. The only exception to that is checking for new versions +and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download +files with `curl` or `wget`. + +However this is really up to the plugin. If you're having a proxy-related issue installing something +you should post an issue on the plugin's repo. + +### How do the shorthand plugin names map to repositories? + +e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? + +asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. +This is regularly updated every time that rtx has a release. This repository is stored directly into +the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that +rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` +to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) +with some rtx features like virtualenv support. + +Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific +enhancements. ## Commands @@ -1762,6 +1813,16 @@ as if direnv was not used. If you continue to struggle, you can also try using the [experimental shims feature](#shims). +### Do you need direnv? + +While making rtx compatible with direnv is, and will always be a major goal of this project, I also +want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing +env vars and virtualenv for python using `.rtx.toml`. + +If you find you continue to need direnv, please open an issue and let me know what it is to see if +it's something rtx could support. rtx will never be as capable as direnv with a DSL like `.envrc`, +but I think we can handle enough common use cases to make that unnecessary for most people. + ## Cache Behavior rtx makes use of caching in many places in order to be efficient. The details about how long to keep diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 6b69b5c1c..42c798b18 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -75,8 +75,8 @@ $ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > **Warning** > -> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes, -> see the [direnv section](#direnv) below. +> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes inside +> of an `.envrc`, see the [direnv section](#direnv) below. Install a runtime and set it as the default: @@ -673,6 +673,22 @@ See https://github.com/asdf-vm/asdf-plugins for the list of built-in plugins sho [Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn more about how they work. +### Plugin Options + +rtx has support for "plugin options" which is configuration specified in `.rtx.toml` to change behavior +of plugins. One example of this is virtualenv on python runtimes: + +```toml +[tools] +python = {{version='3.11', virtualenv='.venv'}} +``` + +This will be passed to all plugin scripts as `RTX_TOOL_OPTS__VIRTUALENV=.venv`. The user can specify +any option and it will be passed to the plugin in that format. + +Currently this only supports simple strings, but we can make it compatible with more complex types +(arrays, tables) fairly easily if there is a need for it. + ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. @@ -683,28 +699,60 @@ 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`. -### How do I create my own plugin? - -Just follow the [asdf docs](https://asdf-vm.com/plugins/create.html). Everything should work the same. -If it isn't, please open an issue. - ### rtx is failing or not working right -First try setting `RTX_LOG_LEVEL=debug` or `RTX_LOG_LEVEL=trace` and see if that gives you more information. -You can also set `RTX_LOG_FILE=/path/to/logfile` to write the logs to a file. +First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. +You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. -It can also be helpful to use `rtx env` to see what environment variables it wants to use. +It can also be helpful to use `rtx env` which will just output environment variables that would be set. +Also consider using [shims](#shims) which can be more compatible. + +If runtime installation isn't working right, try using the `--raw` flag which will install things in +series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact +with you for some reason this will make it work. + +Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` +to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used +to remove everything except config. -Lastly, there is an `rtx doctor` command. It doesn't have much in it but I hope to add more functionality -to that to help debug issues. +Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule +out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` +doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. + +Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues +detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. ### Windows support? This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 -It's not a near-term goal and it would require plugin modifications, but -it should be feasible. +It's not a near-term goal and it would require plugin modifications, but it should be feasible. + +### How do I use rtx with http proxies? + +Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. + +rtx doesn't really do anything with http itself. The only exception to that is checking for new versions +and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download +files with `curl` or `wget`. + +However this is really up to the plugin. If you're having a proxy-related issue installing something +you should post an issue on the plugin's repo. + +### How do the shorthand plugin names map to repositories? + +e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? + +asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. +This is regularly updated every time that rtx has a release. This repository is stored directly into +the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that +rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` +to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) +with some rtx features like virtualenv support. + +Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific +enhancements. ## Commands @@ -902,6 +950,16 @@ as if direnv was not used. If you continue to struggle, you can also try using the [experimental shims feature](#shims). +### Do you need direnv? + +While making rtx compatible with direnv is, and will always be a major goal of this project, I also +want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing +env vars and virtualenv for python using `.rtx.toml`. + +If you find you continue to need direnv, please open an issue and let me know what it is to see if +it's something rtx could support. rtx will never be as capable as direnv with a DSL like `.envrc`, +but I think we can handle enough common use cases to make that unnecessary for most people. + ## Cache Behavior rtx makes use of caching in many places in order to be efficient. The details about how long to keep From bad7d64651c1294663a77fa6ce6054904075f3ed Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 22:00:08 -0600 Subject: [PATCH 0352/1891] docs --- README.md | 29 +++++++++++++++++++++++++++++ src/cli/render_help.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/README.md b/README.md index 83db974b2..147c3d3eb 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,8 @@ v18.10.9 * [Windows support?](#windows-support) * [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) * [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) + * [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) + * [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) * [Commands](#commands) * [rtx activate](#rtx-activate) * [rtx alias get](#rtx-alias-get) @@ -837,6 +839,33 @@ with some rtx features like virtualenv support. Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific enhancements. +### How do I migrate from asdf? + +First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your +shell rc file. + +Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will +install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over +to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, +however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` +and see what happens. + +If you need to switch to/from asdf or work in a project with asdf users, you can set [`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). + +### rtx isn't working with tmux + +It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` +right after activating: + +```bash +eval "$(rtx activate bash)" +eval "$(rtx hook-env)" +``` + +This can also be useful if you need to use a runtime right away in an rc file. The default behavior +of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not +immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. + ## Commands ### `rtx activate` diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 42c798b18..f1b87c932 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -754,6 +754,33 @@ with some rtx features like virtualenv support. Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific enhancements. +### How do I migrate from asdf? + +First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your +shell rc file. + +Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will +install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over +to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, +however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` +and see what happens. + +If you need to switch to/from asdf or work in a project with asdf users, you can set [`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). + +### rtx isn't working with tmux + +It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` +right after activating: + +```bash +eval "$(rtx activate bash)" +eval "$(rtx hook-env)" +``` + +This can also be useful if you need to use a runtime right away in an rc file. The default behavior +of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not +immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. + ## Commands "#, From f4dc0a589c25743fe0373e44d5e598a695273f35 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 22:12:04 -0600 Subject: [PATCH 0353/1891] docs --- README.md | 16 +++++++++++++++- completions/_rtx | 3 ++- src/cli/ls_remote.rs | 2 +- src/cli/render_help.rs | 12 ++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 147c3d3eb..267480568 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ v18.10.9 * [About](#about) + * [What do I use this for?](#what-do-i-use-this-for) * [How it works](#how-it-works) * [Common example commands](#common-example-commands) * [Installation](#installation) @@ -199,6 +200,18 @@ files like `.node-version` and `.ruby-version`. See [Legacy Version Files](#lega Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). +### What do I use this for? + +Typically, developers would use rtx to manage versions of their dev tools for _local_ development. +The main purpose of using rtx is being able to have different versions of languages for different projects +on the same machine. (For example, one project might require python-3.10 and another python-3.11). + +Using rtx in production is less common but still a supported use-case. Usually a production setup +won't have different directories for different projects with different dev tool requirements. +However using `.tool-versions`/`.rtx.toml` config in production provides parity with local development +so rtx is still definitely useful in production setups. See the [GitHub Action](#github-actions) for +an example of using rtx in production. + ### How it works rtx installs as a shell extension (e.g. `rtx activate zsh`) that sets the `PATH` @@ -1350,7 +1363,8 @@ Arguments: Plugin to get versions for [PREFIX] - The version prefix to use when querying the latest version same as the first argument after the "@" + The version prefix to use when querying the latest version + same as the first argument after the "@" Examples: $ rtx ls-remote nodejs diff --git a/completions/_rtx b/completions/_rtx index a7ec0a45d..972a8f048 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -594,7 +594,8 @@ _arguments "${_arguments_options[@]}" \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':plugin -- Plugin to get versions for:' \ -'::prefix -- The version prefix to use when querying the latest version same as the first argument after the "@":' \ +'::prefix -- The version prefix to use when querying the latest version +same as the first argument after the "@":' \ && ret=0 ;; (mangen) diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 851c78d01..fc6360060 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -22,7 +22,7 @@ pub struct LsRemote { /// The version prefix to use when querying the latest version /// same as the first argument after the "@" - #[clap()] + #[clap(verbatim_doc_comment)] prefix: Option, } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f1b87c932..57753cf26 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -114,6 +114,18 @@ files like `.node-version` and `.ruby-version`. See [Legacy Version Files](#lega Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). +### What do I use this for? + +Typically, developers would use rtx to manage versions of their dev tools for _local_ development. +The main purpose of using rtx is being able to have different versions of languages for different projects +on the same machine. (For example, one project might require python-3.10 and another python-3.11). + +Using rtx in production is less common but still a supported use-case. Usually a production setup +won't have different directories for different projects with different dev tool requirements. +However using `.tool-versions`/`.rtx.toml` config in production provides parity with local development +so rtx is still definitely useful in production setups. See the [GitHub Action](#github-actions) for +an example of using rtx in production. + ### How it works rtx installs as a shell extension (e.g. `rtx activate zsh`) that sets the `PATH` From b3dd6c3fe6b435da46cd8bd6ee4e2e1dee3a4493 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 22:15:40 -0600 Subject: [PATCH 0354/1891] docs --- README.md | 6 ++++-- completions/_rtx | 12 ++++++++---- completions/rtx.fish | 6 ++++-- src/cli/plugins/ls.rs | 4 ++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 267480568..a46cb93ba 100644 --- a/README.md +++ b/README.md @@ -1433,10 +1433,12 @@ Usage: ls [OPTIONS] Options: -a, --all - List all available remote plugins Same as `rtx plugins ls-remote` + List all available remote plugins + Same as `rtx plugins ls-remote` -u, --urls - Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git + Show the git url for each plugin + e.g.: https://github.com/asdf-vm/asdf-nodejs.git Examples: $ rtx plugins ls diff --git a/completions/_rtx b/completions/_rtx index 972a8f048..4ba2a9c36 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -664,10 +664,14 @@ _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-a[List all available remote plugins Same as `rtx plugins ls-remote`]' \ -'--all[List all available remote plugins Same as `rtx plugins ls-remote`]' \ -'-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ -'--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +'-a[List all available remote plugins +Same as `rtx plugins ls-remote`]' \ +'--all[List all available remote plugins +Same as `rtx plugins ls-remote`]' \ +'-u[Show the git url for each plugin +e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +'--urls[Show the git url for each plugin +e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 7a31a18ba..975ab63bd 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -264,8 +264,10 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins Same as `rtx plugins ls-remote`' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins +Same as `rtx plugins ls-remote`' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin +e.g.: https://github.com/asdf-vm/asdf-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 2baee94bb..d3077f91e 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -16,12 +16,12 @@ use crate::output::Output; pub struct PluginsLs { /// List all available remote plugins /// Same as `rtx plugins ls-remote` - #[clap(short, long)] + #[clap(short, long, verbatim_doc_comment)] pub all: bool, /// Show the git url for each plugin /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git - #[clap(short, long)] + #[clap(short, long, verbatim_doc_comment)] pub urls: bool, } From 9410e9f043a2dc3f1b26e4ddf183f9a539256bee Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 1 Mar 2023 22:30:39 -0600 Subject: [PATCH 0355/1891] docs --- README.md | 27 +-------------------------- src/cli/render_help.rs | 26 +------------------------- 2 files changed, 2 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index a46cb93ba..b6ce52089 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,6 @@ v18.10.9 * [Cache Behavior](#cache-behavior) * [Plugin Cache](#plugin-cache) * [Legacy File Cache](#legacy-file-cache) - * [Development](#development) ## About @@ -1751,17 +1750,7 @@ $ asdf local nodejs latest:18 In `rtx` this can all be done in a single step to set the local runtime version. If the plugin and/or runtime needs to be installed it will prompt: -```sh-session -$ asdf local nodejs@18 -rtx: Would you like to install nodejs@18.13.0? [Y/n] Y -Trying to update node-build... ok -Downloading node-v18.13.0-darwin-arm64.tar.gz... --> https://nodejs.org/dist/v18.13.0/node-v18.13.0-darwin-arm64.tar.gz -Installing node-v18.13.0-darwin-arm64... -Installed node-v18.13.0-darwin-arm64 to /Users/jdx/.local/share/rtx/installs/nodejs/18.13.0 -$ node -v -v18.13.0 -``` +[![asciicast](https://asciinema.org/a/564031.svg)](https://asciinema.org/a/564031) I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). @@ -1905,17 +1894,3 @@ plugin is called: It will remain cached until the file is modified. This is a simple text file that has the path to the legacy file stored as a hash for the filename. -## Development - -Run tests with `just`: - -```sh-session -$ just test -``` - -Lint the codebase with: - -```sh-session -$ just lint-fix -``` - diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 57753cf26..7decd08aa 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -882,17 +882,7 @@ $ asdf local nodejs latest:18 In `rtx` this can all be done in a single step to set the local runtime version. If the plugin and/or runtime needs to be installed it will prompt: -```sh-session -$ asdf local nodejs@18 -rtx: Would you like to install nodejs@18.13.0? [Y/n] Y -Trying to update node-build... ok -Downloading node-v18.13.0-darwin-arm64.tar.gz... --> https://nodejs.org/dist/v18.13.0/node-v18.13.0-darwin-arm64.tar.gz -Installing node-v18.13.0-darwin-arm64... -Installed node-v18.13.0-darwin-arm64 to /Users/jdx/.local/share/rtx/installs/nodejs/18.13.0 -$ node -v -v18.13.0 -``` +[![asciicast](https://asciinema.org/a/564031.svg)](https://asciinema.org/a/564031) I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). @@ -1035,20 +1025,6 @@ plugin is called: expensive so every file that gets parsed as a legacy file is cached into `~/.local/share/rtx/legacy_cache`. It will remain cached until the file is modified. This is a simple text file that has the path to the legacy file stored as a hash for the filename. - -## Development - -Run tests with `just`: - -```sh-session -$ just test -``` - -Lint the codebase with: - -```sh-session -$ just lint-fix -``` "# ); From ba58b614ca3de1168467c981b64be8a88c2daeef Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 09:38:48 -0600 Subject: [PATCH 0356/1891] bug: fix issue with not-installed plugins --- src/toolset/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 97c24c97b..2c7293dda 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -157,10 +157,10 @@ impl Toolset { .iter_mut() .filter(|v| v.is_missing() && selected_versions.contains(&v.r#type)) .collect_vec(); - let plugin = self.plugins.get(&p.to_string()).unwrap(); - match versions.is_empty() { - true => None, - false => Some((plugin, versions)), + let plugin = self.plugins.get(&p.to_string()); + match (plugin, versions.is_empty()) { + (Some(plugin), false) => Some((plugin, versions)), + _ => None, } }) .map(|(plugin, versions)| { From 2d9c384add38aec2cb9c256f177f2eb082c9af80 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 09:56:07 -0600 Subject: [PATCH 0357/1891] bug: fix asdf-style where This was not working with the version as an argument like `rtx where nodejs 18`. This seems to have made `rtx i nodejs@lts` not work in some cases Fixes #218 --- src/cli/args/runtime.rs | 6 +++- ...i__r#where__tests__where_asdf_style-2.snap | 6 ++++ ...cli__r#where__tests__where_asdf_style.snap | 6 ++++ src/cli/where.rs | 29 +++++++++++++++---- 4 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap create mode 100644 src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index effb720a1..8f032b4bb 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -1,9 +1,9 @@ -use color_eyre::eyre::Result; use std::ffi::{OsStr, OsString}; use std::fmt::Display; use std::path::PathBuf; use clap::{Arg, Command, Error}; +use color_eyre::eyre::Result; use regex::Regex; use crate::plugins::PluginName; @@ -90,6 +90,10 @@ impl RuntimeArg { } runtimes } + + pub fn with_version(self, version: RuntimeArgVersion) -> Self { + Self { version, ..self } + } } impl Display for RuntimeArg { diff --git a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap new file mode 100644 index 000000000..2e61ed71a --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/where.rs +expression: output +--- +~/data/installs/tiny/3.1.0 + diff --git a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap new file mode 100644 index 000000000..6ed345ef8 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/where.rs +expression: output +--- +~/data/installs/tiny/2.1.0 + diff --git a/src/cli/where.rs b/src/cli/where.rs index 4489ba648..a7d2c30bd 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -3,7 +3,7 @@ use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; @@ -32,18 +32,28 @@ pub struct Where { impl Command for Where { fn run(self, config: Config, out: &mut Output) -> Result<()> { + let runtime = match self.runtime.version { + RuntimeArgVersion::None => match self.asdf_version { + Some(version) => self + .runtime + .with_version(RuntimeArgVersion::Version(version)), + None => self.runtime, + }, + _ => self.runtime, + }; + let ts = ToolsetBuilder::new() - .with_args(&[self.runtime.clone()]) + .with_args(&[runtime.clone()]) .build(&config); - match ts.resolve_runtime_arg(&self.runtime) { + match ts.resolve_runtime_arg(&runtime) { Some(rtv) if rtv.is_installed() => { rtxprintln!(out, "{}", rtv.install_path.to_string_lossy()); Ok(()) } _ => Err(VersionNotInstalled( - self.runtime.plugin.to_string(), - self.runtime.version.to_string(), + runtime.plugin.to_string(), + runtime.version.to_string(), ))?, } } @@ -69,8 +79,8 @@ mod tests { use insta::assert_display_snapshot; use pretty_assertions::assert_str_eq; - use crate::dirs; use crate::{assert_cli, assert_cli_err}; + use crate::{assert_cli_snapshot, dirs}; #[test] fn test_where() { @@ -82,6 +92,13 @@ mod tests { ); } + #[test] + fn test_where_asdf_style() { + assert_cli!("install", "tiny@2", "tiny@3"); + assert_cli_snapshot!("where", "tiny", "2"); + assert_cli_snapshot!("where", "tiny", "3"); + } + #[test] fn test_where_alias() { assert_cli!("install", "tiny@my/alias"); From ee17ffe015def071ab74d85e79be175b764daeb7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 10:51:17 -0600 Subject: [PATCH 0358/1891] chore: render readme as a template --- README.md | 8 +- justfile | 2 +- src/cli/render_help.rs | 1053 ++-------------------------------------- 3 files changed, 48 insertions(+), 1015 deletions(-) diff --git a/README.md b/README.md index b6ce52089..ac2e12cd0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # [rtx](https://github.com/jdxcode/rtx) [![Crates.io](https://img.shields.io/crates/v/rtx-cli.svg)](https://crates.io/crates/rtx-cli) @@ -316,13 +315,13 @@ rtx is available on npm as precompiled binaries. This isn't a node.js package, j via npm. It can be useful for JS projects that want to setup rtx via `package.json` or `npx`. ```sh-session -$ npm install -g @jdxcode/rtx +$ npm install -g rtx-cli ``` Or use npx if you just want to test it out for a single command without fully installing: ```sh-session -$ npx @jdxcode/rtx exec python@3.11 -- python some_script.py +$ npx rtx-cli exec python@3.11 -- python some_script.py ``` ### GitHub Releases @@ -878,6 +877,7 @@ This can also be useful if you need to use a runtime right away in an rc file. T of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. + ## Commands ### `rtx activate` @@ -1687,6 +1687,8 @@ Examples: $ rtx which node --version 18.0.0 ``` + + ## Comparison to asdf diff --git a/justfile b/justfile index c32c0996e..a6eeb0bda 100644 --- a/justfile +++ b/justfile @@ -75,7 +75,7 @@ lint-fix: # regenerate README.md render-help: build - NO_COLOR=1 rtx render-help > README.md + NO_COLOR=1 rtx render-help ./scripts/gh-md-toc --insert --no-backup --hide-footer --skip-header README.md > /dev/null # regenerate shell completion files diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 7decd08aa..803c6fe4b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -1,6 +1,7 @@ use color_eyre::eyre::Result; use console::strip_ansi_codes; use indoc::formatdoc; +use std::fs; use crate::cli::command::Command; use crate::cli::Cli; @@ -13,1023 +14,52 @@ use crate::output::Output; pub struct RenderHelp {} impl Command for RenderHelp { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let mut cli = Cli::command() - .term_width(80) - .max_term_width(80) - .disable_help_subcommand(true) - .disable_help_flag(true); - out.stdout.write(formatdoc!( - r#" - -# [rtx](https://github.com/jdxcode/rtx) - -[![Crates.io](https://img.shields.io/crates/v/rtx-cli.svg)](https://crates.io/crates/rtx-cli) -[![License: MIT](https://img.shields.io/github/license/jdxcode/rtx)](https://github.com/jdxcode/rtx/blob/main/LICENSE) -[![CI](https://github.com/jdxcode/rtx/actions/workflows/rtx.yml/badge.svg?branch=main)](https://github.com/jdxcode/rtx/actions/workflows/rtx.yml) -[![Codecov](https://codecov.io/gh/jdxcode/rtx/branch/main/graph/badge.svg?token=XYH3Q0BOO0)](https://codecov.io/gh/jdxcode/rtx) -[![Discord](https://img.shields.io/discord/1066429325269794907)](https://discord.gg/mABnUDvP57) - -_{about}_ - -## 30 Second Demo - -The following shows using rtx to install [nodejs](https://nodejs.org) and -[jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. -[hyperfine](https://github.com/sharkdp/hyperfine) is used to show the performance using -rtx vs asdf. (See [Performance](#performance)). -Note that calling `which node` gives us a real path to the binary, not a shim. - -[![demo](./docs/demo.gif)](./docs/demo.gif) - -## Features - -- **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. -- **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. -- **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. -- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them by default. -- **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. -- **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. -- **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. -- **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. - -## Quickstart - -Install rtx (other methods [here](#installation)): - -```sh-session -$ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx -$ chmod +x ~/bin/rtx -$ rtx --version -rtx {version} -``` - -Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. -(choose one, and open a new shell session for the changes to take effect): - -```sh-session -$ echo 'eval "$(~/bin/rtx activate bash)"' >> ~/.bashrc -$ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc -$ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish -``` - -> **Warning** -> -> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes inside -> of an `.envrc`, see the [direnv section](#direnv) below. - -Install a runtime and set it as the default: - -```sh-session -$ rtx install nodejs@18 -$ rtx global nodejs@18 -$ node -v -v18.10.9 -``` - -> **Note** -> -> `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not -> already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). - -## Table of Contents - - - - -## About - -rtx is a tool for managing programming language and tool versions. For example, use this to install -a particular version of node.js and ruby for a project. Using `rtx activate`, you can have your -shell automatically switch to the correct node and ruby versions when you `cd` into the project's -directory. Other projects on your machine can use a different set of versions. - -rtx is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecosystem](https://github.com/asdf-vm/asdf-plugins) -under the hood. However, it is _much_ faster than asdf and has a more friendly user experience. -For more on how rtx compares to asdf, [see below](#comparison-to-asdf). The goal of this project -was to create a better front-end to asdf. - -It uses the same `.tool-versions` file that asdf uses. It's also compatible with idiomatic version -files like `.node-version` and `.ruby-version`. See [Legacy Version Files](#legacy-version-files) below. - -Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). - -### What do I use this for? - -Typically, developers would use rtx to manage versions of their dev tools for _local_ development. -The main purpose of using rtx is being able to have different versions of languages for different projects -on the same machine. (For example, one project might require python-3.10 and another python-3.11). - -Using rtx in production is less common but still a supported use-case. Usually a production setup -won't have different directories for different projects with different dev tool requirements. -However using `.tool-versions`/`.rtx.toml` config in production provides parity with local development -so rtx is still definitely useful in production setups. See the [GitHub Action](#github-actions) for -an example of using rtx in production. - -### How it works - -rtx installs as a shell extension (e.g. `rtx activate zsh`) that sets the `PATH` -environment variable to point your shell to the correct runtime binaries. When you `cd` into a -directory containing a `.tool-versions` file, rtx will automatically activate the correct versions. - -Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This -should be very fast and it exits early if the the directory wasn't changed or the `.tool-versions` -files haven't been updated. On my machine this takes 4ms in the fast case, 14ms in the slow case. See [Performance](#performance) for more on this topic. - -Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies -`PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids -any overhead, but it also makes it so commands like `which node` work as expected. This also -means there isn't any need to run `asdf reshim` after installing new runtime binaries. - -rtx does not directly install runtimes. Instead, it uses asdf plugins to install runtimes. See -[plugins](#plugins) below. - -### Common example commands - - rtx install nodejs@18.0.0 Install a specific version number - rtx install nodejs@18.0 Install a fuzzy version number - rtx local nodejs@18 Use node-18.x in current project - rtx global nodejs@18 Use node-18.x as default - - rtx install nodejs Install the version specified in .tool-versions - rtx local nodejs@latest Use latest node in current directory - rtx global nodejs@system Use system node as default - - rtx x nodejs@18 -- node app.js Run `node app.js` with the PATH pointing to node-18.x - -## Installation - -### Standalone - -Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate script in your rc -file, rtx will automatically add itself to `PATH`. - -```sh-session -$ curl https://rtx.pub/install.sh | sh -``` - -or if you're allergic to `| sh`: - -```sh-session -$ curl https://rtx.pub/rtx-latest-macos-arm64 > /usr/local/bin/rtx -``` - -It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` -or whatever. - -Supported architectures: - -- `x64` -- `arm64` - -Supported platforms: - -- `macos` -- `linux` - -If you need something else, compile it with [cargo](#cargo). - -### Homebrew - -There are 2 ways to install rtx with Homebrew. The recommended method is to use -the custom tap which will always contain the latest release. - -```sh-session -$ brew install jdxcode/tap/rtx -``` - -Alternatively, you can use the built-in tap (homebrew-core), which will be updated -once Homebrew maintainers merge the PR for a new release: - -```sh-session -$ brew install rtx -``` - -### Cargo - -Build from source with Cargo: - -```sh-session -$ cargo install rtx-cli - -Do it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall): - -```sh-session -$ cargo install cargo-binstall -$ cargo binstall rtx-cli -``` - -Build from the latest commit in main: - -```sh-session -$ cargo install rtx-cli --git https://github.com/jdxcode/rtx --branch main -``` - -### npm - -rtx is available on npm as precompiled binaries. This isn't a node.js package, just distributed -via npm. It can be useful for JS projects that want to setup rtx via `package.json` or `npx`. - -```sh-session -$ npm install -g @jdxcode/rtx -``` - -Or use npx if you just want to test it out for a single command without fully installing: - -```sh-session -$ npx @jdxcode/rtx exec python@3.11 -- python some_script.py -``` - -### GitHub Releases - -Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). - -```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.1/rtx-v1.20.1-linux-x64 | tar -xJv -$ mv rtx/bin/rtx /usr/local/bin -``` - -### apt - -For installation on Ubuntu/Debian: - -```sh-session -wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list -sudo apt update -sudo apt install -y rtx -``` - -> **Warning** -> -> If you're on arm64 you'll need to run the following: -> ``` -> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list -> ``` - -### dnf - -For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: - -```sh-session -dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo -dnf install -y rtx -``` - -### yum - -```sh-session -yum install -y yum-utils -yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo -yum install -y rtx -``` - -### ~~apk~~ (coming soon) - -For Alpine Linux: - -```sh-session -apk add rtx --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ -``` - -### aur - -For Arch Linux: - -```sh-session -git clone https://aur.archlinux.org/rtx.git -cd rtx -makepkg -si -``` - -### nix - -For NixOS or those using the Nix package manager: - -```nix -{{ - inputs = {{ - nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - rtx-flake = {{ - url = "github:chadac/rtx/add-nix-flake"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.flake-utils.follows = "flake-utils"; - }}; - }}; + fn run(self, _config: Config, _out: &mut Output) -> Result<()> { + let readme = fs::read_to_string("README.md")?; + let mut current_readme = readme.split(""); + + let mut doc = String::new(); + doc.push_str(current_readme.next().unwrap()); + current_readme.next(); // discard existing commands + doc.push_str(render_commands().as_str()); + doc.push_str(current_readme.next().unwrap()); + fs::write("README.md", &doc)?; + Ok(()) + } +} - outputs = {{ self, nixpkgs, flake-utils, rtx-flake }}: - flake-utils.lib.eachDefaultSystem(system: - let - pkgs = import nixpkgs {{ - inherit system; - overlays = [ rtx-flake.overlay ]; - }}; - in {{ - devShells.default = pkgs.mkShell {{ - name = "my-dev-env"; - nativeBuildInputs = with pkgs; [ - rtx - ]; - }}; - }} +fn render_commands() -> String { + let mut cli = Cli::command() + .term_width(80) + .max_term_width(80) + .disable_help_subcommand(true) + .disable_help_flag(true); + let mut doc = formatdoc!( + r#" + + ## Commands + + "# ); -}} -``` - -You can also import the package directly using -`rtx-flake.packages.${{system}}.rtx`. It supports all default Nix -systems. - -## Other Shells - -### Bash - -```sh-session -$ echo 'eval "$(rtx activate bash)"' >> ~/.bashrc -``` - -### Fish - -```sh-session -$ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish -``` - -### Xonsh - -Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a bit off startup time by using a pure Python import: add the code below to, for example, `~/.config/xonsh/rtx.py` config file and `import rtx` it in `~/.config/xonsh/rc.xsh`: -```xsh -from pathlib import Path -from xonsh.built_ins import XSH - -ctx = XSH.ctx -rtx_init = subprocess.run([Path('~/bin/rtx').expanduser(),'activate','xonsh'],capture_output=True,encoding="UTF-8").stdout -XSH.builtins.execx(rtx_init,'exec',ctx,filename='rtx') -``` - -Or continue to use `rc.xsh`/`.xonshrc`: -```xsh -echo 'execx($(~/bin/rtx activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xonshrc -``` - -Given that `rtx` replaces both shell env `$PATH` and OS environ `PATH`, watch out that your configs don't have these two set differently (might throw `os.environ['PATH'] = xonsh.built_ins.XSH.env.get_detyped('PATH')` at the end of a config to make sure they match) - -### Something else? - -Adding a new shell is not hard at all since very little shell code is -in this project. -[See here](https://github.com/jdxcode/rtx/tree/main/src/shell) for how -the others are implemented. If your shell isn't currently supported -I'd be happy to help you get yours integrated. - -## Uninstalling - -Use `rtx implode` to uninstall rtx. This will remove the rtx binary and all of its data. Use -`rtx implode --help` for more information. - -Alternatively, manually remove the following directories to fully clean up: - -* `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) -* `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) -* on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) -* on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) - -## Configuration - -### `.tool-versions` - -The `.tool-versions` file is used to specify the runtime versions for a project. An example of this -is: - -``` -nodejs 18.0.0 # comments are allowed -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 -shfmt path:./shfmt # use a custom runtime -``` - -Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local) to create them automatically. -See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. - -### Legacy version files - -rtx supports "legacy version files" just like asdf. They're language-specific files like `.node-version` -and `.python-version`. These are ideal for setting the runtime version of a project without forcing -other developers to use a specific tool like rtx/asdf. - -They support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work -in rtx and nvm. Here are some of the supported legacy version files: - -| Plugin | "Legacy" (Idiomatic) Files | -| --------- | -------------------------------------------------- | -| crystal | `.crystal-version` | -| elixir | `.exenv-version` | -| golang | `.go-version`, `go.mod` | -| java | `.java-version` | -| nodejs | `.nvmrc`, `.node-version` | -| python | `.python-version` | -| ruby | `.ruby-version`, `Gemfile` | -| terraform | `.terraform-version`, `.packer-version`, `main.tf` | -| yarn | `.yvmrc` | - -In rtx these are enabled by default. You can disable them with `rtx settings set legacy_version_file false`. -There is a performance cost to having these when they're parsed as it's performed by the plugin in -`bin/parse-version-file`. However these are [cached](#cache-behavior) so it's not a huge deal. -You may not even notice. - -> **Note** -> -> asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies -> that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" -> version files since they're version files not specific to asdf/rtx and can be used by other tools. -> (`.nvmrc` being a notable exception, which is tied to a specific tool.) - -### Global config: `~/.config/rtx/config.toml` - -rtx can be configured in `~/.config/rtx/config.toml`. The following options are available (defaults shown): - -```toml -# whether to prompt to install plugins and runtimes if they're not already installed -missing_runtime_behavior = 'prompt' # other options: 'ignore', 'warn', 'prompt', 'autoinstall' - -# plugins can read the versions files used by other version managers (if enabled by the plugin) -# for example, .nvmrc in the case of nodejs's nvm -legacy_version_file = true # enabled by default (different than asdf) - -# configure `rtx install` to always keep the downloaded archive -always_keep_download = false # deleted after install by default - -# configure how frequently (in minutes) to fetch updated plugin repository changes -# this is updated whenever a new runtime is installed -# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) -plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates - -verbose = false # set to true to see full installation output, see `RTX_VERBOSE` -asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` -jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. -raw = false # set to true to directly pipe plugins to stdin/stdout/stderr - -shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` -disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` - -experimental = false # enable experimental features such as shims -shims_dir = '~/.local/share/rtx/shims' # [experimental] directory where shims are stored - -[alias.nodejs] -my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x - # this can also be specified in a plugin (see below in "Aliases") -``` - -These settings can also be managed with `rtx settings ls|get|set|unset`. - -### [experimental] `.rtx.toml` - -`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` file. - -It allows for functionality that is not possible with `.tool-versions`, such as: - -* setting arbitrary env vars while inside the directory -* passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). -* specifying plugin repo url for custom plugins so it does not need to be added manually - -Here is what the config looks like: - -```toml -[env] -NODE_ENV = 'production' # supports arbitrary env vars so rtx can be used like dotenv - -[tools] -# specify single or multiple versions -terraform = '1.0.0' -erlang = ['23.3', '24.0'] - -# supports everything you can do with .tool-versions currently -nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] - -# repo can be used to git clone a custom repo url (see #226) -jq = {{ version = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' }} - -# send arbitrary options to the plugin, passed as: -# RTX_TOOL_OPTS__VENV=.venv -# RTX_TOOL_OPTS__DEFAULT_PACKAGES__0=ansible -# RTX_TOOL_OPTS__DEFAULT_PACKAGES__1=pipenv -python = {{ version = '3.10', venv = '.venv', default_packages = ['ansible', 'pipenv'] }} - -[settings] # project-local settings -verbose = true -missing_runtime_behavior = 'warn' -shims_dir = '~/.rtx/shims' - -[alias.nodejs] # project-local aliases -my_custom_node = '18' -``` - -`.rtx.toml` is currently experimental and may change in minor versions of rtx. - -### Environment variables - -rtx can also be configured via environment variables. The following options are available: - -#### `RTX_MISSING_RUNTIME_BEHAVIOR` - -This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. - -```sh-session -$ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@18 -$ RTX_NODEJS_VERSION=18 rtx exec -- node --version -``` - -#### `RTX_DATA_DIR` - -This is the directory where rtx stores its data. The default is `~/.local/share/rtx`. - -#### `RTX_CACHE_DIR` - -This is the directory where rtx stores cache. The default is `~/.cache/rtx` on Linux and `~/Library/Caches/rtx` on macOS. - -#### `RTX_CONFIG_FILE` - -This is the path to the config file. The default is `~/.config/rtx/config.toml`. -(Or `$XDG_CONFIG_HOME/config.toml` if that is set) - -#### `RTX_DEFAULT_TOOL_VERSIONS_FILENAME` - -Set to something other than ".tool-versions" to have rtx look for configuration with alternate names. - -#### `RTX_${{PLUGIN}}_VERSION` - -Set the version for a runtime. For example, `RTX_NODEJS_VERSION=18` will use nodejs@18.x regardless -of what is set in `.tool-versions`. - -#### `RTX_LEGACY_VERSION_FILE` - -Plugins can read the versions files used by other version managers (if enabled by the plugin) -for example, .nvmrc in the case of nodejs's nvm. - -#### `RTX_LOG_LEVEL=trace|debug|info|warn|error` - -Can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1`. These adjust the log -output to the screen. - -#### `RTX_LOG_FILE=~/.rtx/rtx.log` - -Output logs to a file. - -#### `RTX_LOG_FILE_LEVEL=trace|debug|info|warn|error` - -Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want -to store the logs but not have them litter your display. - -#### `RTX_VERBOSE=1` - -This shows the installation output during `rtx install` and `rtx plugin install`. -This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have -2 configuration for the same thing, but for now it is it's own config. - -#### `RTX_ASDF_COMPAT=1` - -Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. - -#### `RTX_JOBS=1` - -Set the number plugins or runtimes to install in parallel. The default is `4`. - -#### `RTX_RAW=1` - -Set to "1" to directly pipe plugin scripts to stdin/stdout/stderr. By default stdin is disabled -because when installing a bunch of plugins in parallel you won't see the prompt. Use this if a -plugin accepts input or otherwise does not seem to be installing correctly. - -Sets `RTX_JOBS=1` because only 1 plugin script can be executed at a time. - -#### `RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml` - -Use a custom file for the shorthand aliases. This is useful if you want to share plugins within -an organization. - -The file should be in toml format: - -```toml -elixir = "https://github.com/my-org/rtx-elixir.git" -nodejs = "https://github.com/my-org/rtx-nodejs.git" -``` - -#### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` - -Disables the shorthand aliases for installing plugins. You will have to specify full urls when -installing plugins, e.g.: `rtx plugin install nodejs https://github.com/asdf-vm/asdf-nodejs.git` - -Currently this disables the following: - -* `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) - -#### `RTX_HIDE_OUTDATED_BUILD=1` - -If a release is 12 months old, it will show a warning message every time it launches: - -``` -rtx has not been updated in over a year. Please update to the latest version. -``` - -You likely do not want to be using rtx if it is that old. I'm doing this instead of -autoupdating. If, for some reason, you want to stay on some old version, you can hide -this message with `RTX_HIDE_OUTDATED_BUILD=1`. - -#### `RTX_EXPERIMENTAL=1` - -Enables experimental features such as shims. - -#### [experimental] `RTX_SHIMS_DIR=~/.local/share/rtx/shims` - -Set a directory to output shims when running `rtx reshim`. Requires `experimental = true`. - -## Aliases - -rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS -versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for nodejs@18.x. -So you can use the runtime with `nodejs lts/hydrogen` in `.tool-versions`. - -User aliases can be created by adding an `alias.` section to `~/.config/rtx/config.toml`: - -```toml -[alias.nodejs] -my_custom_18 = '18' -``` - -Plugins can also provide aliases via a `bin/list-aliases` script. Here is an example showing node.js -versions: - -```bash -#!/usr/bin/env bash - -echo "lts/hydrogen 18" -echo "lts/gallium 16" -echo "lts/fermium 14" -``` - -> **Note:** -> -> Because this is rtx-specific functionality not currently used by asdf it isn't likely to be in any -> plugin currently, but plugin authors can add this script without impacting asdf users. - -## Plugins - -rtx uses asdf's plugin ecosystem under the hood. These plugins contain shell scripts like -`bin/install` (for installing) and `bin/list-all` (for listing all of the available versions). - -See https://github.com/asdf-vm/asdf-plugins for the list of built-in plugins shorthands. See asdf's -[Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn -more about how they work. - -### Plugin Options - -rtx has support for "plugin options" which is configuration specified in `.rtx.toml` to change behavior -of plugins. One example of this is virtualenv on python runtimes: - -```toml -[tools] -python = {{version='3.11', virtualenv='.venv'}} -``` - -This will be passed to all plugin scripts as `RTX_TOOL_OPTS__VIRTUALENV=.venv`. The user can specify -any option and it will be passed to the plugin in that format. - -Currently this only supports simple strings, but we can make it compatible with more complex types -(arrays, tables) fairly easily if there is a need for it. - -## FAQs - -### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. - -You can make git ignore these files in 3 different ways: - -- Adding `.tool-versions` to project's `.gitignore` file. This has the downside that you need to commit the change to the ignore file. -- 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`. - -### rtx is failing or not working right - -First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. -You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. - -If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. -It can also be helpful to use `rtx env` which will just output environment variables that would be set. -Also consider using [shims](#shims) which can be more compatible. - -If runtime installation isn't working right, try using the `--raw` flag which will install things in -series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact -with you for some reason this will make it work. - -Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` -to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used -to remove everything except config. - -Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule -out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` -doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. - -Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues -detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. - -### Windows support? - -This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 - -It's not a near-term goal and it would require plugin modifications, but it should be feasible. - -### How do I use rtx with http proxies? - -Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. - -rtx doesn't really do anything with http itself. The only exception to that is checking for new versions -and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download -files with `curl` or `wget`. - -However this is really up to the plugin. If you're having a proxy-related issue installing something -you should post an issue on the plugin's repo. - -### How do the shorthand plugin names map to repositories? - -e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? - -asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. -This is regularly updated every time that rtx has a release. This repository is stored directly into -the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that -rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` -to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) -with some rtx features like virtualenv support. - -Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific -enhancements. - -### How do I migrate from asdf? - -First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your -shell rc file. - -Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will -install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over -to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, -however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` -and see what happens. - -If you need to switch to/from asdf or work in a project with asdf users, you can set [`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). - -### rtx isn't working with tmux - -It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` -right after activating: - -```bash -eval "$(rtx activate bash)" -eval "$(rtx hook-env)" -``` - -This can also be useful if you need to use a runtime right away in an rc file. The default behavior -of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not -immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. - -## Commands - -"#, - version = env!("CARGO_PKG_VERSION"), - about = cli.get_about().unwrap(), - )); - for command in cli.get_subcommands_mut() { - match command.has_subcommands() { - true => { - let name = command.get_name().to_string(); - for subcommand in command.get_subcommands_mut() { - if let Some(output) = render_command(Some(&name), subcommand) { - out.stdout.write(output); - } + for command in cli.get_subcommands_mut() { + match command.has_subcommands() { + true => { + let name = command.get_name().to_string(); + for subcommand in command.get_subcommands_mut() { + if let Some(output) = render_command(Some(&name), subcommand) { + doc.push_str(&output); } } - false => { - if let Some(output) = render_command(None, command) { - out.stdout.write(output); - } + } + false => { + if let Some(output) = render_command(None, command) { + doc.push_str(&output); } } } - - rtxprintln!( - out, - r#" -## Comparison to asdf - -rtx is mostly a clone of asdf, but there are notable areas where improvements have been made. - -### Performance - -asdf made (what I consider) a poor design decision to use shims that go between a call to a runtime -and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, -which then calls `asdf exec`, which then calls the correct version of node. - -These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead -updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo gif at the top of this README -that `rtx` isn't actually used when calling `node -v` for this reason. The performance is -identical to running node without using rtx. - -I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup -of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written -in bash which certainly makes it challenging to be performant, however I think the real problem is the -shim design. I don't think it's possible to fix that without a complete rewrite. - -rtx does call an internal command `rtx hook-env` every time the directory has changed, but because -it's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's -a full reload. - -tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~10ms) -when the prompt loads. - -### Environment variables - -asdf only helps manage runtime executables. However, some tools are managed via environment variables -(notably Java which switches via `JAVA_HOME`). This isn't supported very well in asdf and requires -a separate shell extension just to manage. - -However asdf _plugins_ have a `bin/exec-env` script that is used for exporting environment variables -like [`JAVA_HOME`](https://github.com/halcyon/asdf-java/blob/master/bin/exec-env). rtx simply exports -the environment variables from the `bin/exec-env` script in the plugin but places them in the shell -for _all_ commands. In asdf it only exports those commands when the shim is called. This means if you -call `java` it will set `JAVA_HOME`, but not if you call some Java tool like `mvn`. - -This means we're just using the existing plugin script but because rtx doesn't use shims it can be -used for more things. It would be trivial to make a plugin that exports arbitrary environment -variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https://github.com/direnv/direnv). - -### UX - -Some commands are the same in asdf but others have been changed. Everything that's possible -in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, -such as using fuzzy-matching, e.g.: `rtx install nodejs@18`. While in asdf you _can_ run -`asdf install nodejs latest:18`, you can't use `latest:18` in a `.tool-versions` file or many other places. -In `rtx` you can use fuzzy-matching everywhere. - -asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: - -```sh-session -$ asdf plugin add nodejs -$ asdf install nodejs latest:18 -$ asdf local nodejs latest:18 -``` - -In `rtx` this can all be done in a single step to set the local runtime version. If the plugin -and/or runtime needs to be installed it will prompt: - -[![asciicast](https://asciinema.org/a/564031.svg)](https://asciinema.org/a/564031) - -I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like -having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). -`rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add nodejs` or -`rtx plugin install nodejs`. If I can guess what you meant, then I'll try to get rtx to respond -in the right way. - -That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there -and I've really been impressed with the plugin system. Most of the design decisions the authors made -were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. - -### CI/CD - -Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. - -### GitHub Actions - -Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): - -```yaml -- uses: jdxcode/rtx-action@v1 -- run: node -v # will be the node version from `.tool-versions` -``` - -## Shims - -While the PATH design of rtx works great in most cases, there are some situations where shims are -preferable. One example is when calling rtx binaries from an IDE. - -To support this, there is experimental support for using rtx in a "shim" mode. To use: - -``` -$ rtx settings set experimental true -$ rtx settings set shims_dir ~/.rtx/shims -$ rtx i nodejs@18.0.0 -$ rtx reshim -$ ~/.rtx/shims/node -v -v18.0.0 -``` - -## direnv - -[direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze -the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. -As a result, there were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). -However, we think we've mitigated these. If you find that rtx and direnv are not working well together, -please comment on that ticket ideally with a good description of your directory layout so we can -reproduce the problem. - -If there are remaining issues, they're likely to do with the ordering of PATH. This means it would -really only be a problem if you were trying to manage the same runtime with direnv and rtx. For example, -you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with python -in it as well. - -A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated -binaries to PATH. In these cases, rtx will not interfere with direnv. - -### rtx inside of direnv (`use rtx` in `.envrc`) - -If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, -this is a simpler setup that's less likely to cause issues—at the cost of functionality. - -This may be required if you want to use direnv's `layout python` with rtx. Otherwise there are -situations where rtx will override direnv's PATH. `use rtx` ensures that direnv always has control. - -To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: - -```sh-session -$ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh -``` - -Now in your `.envrc` file add the following: - -```sh-session -use rtx -``` - -direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` -to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. - -Note that in this method direnv typically won't know to refresh `.tool-versions` files -unless they're at the same level as a `.envrc` file. You'll likely always want to have -a `.envrc` file next to your `.tool-versions` for this reason. To make this a little -easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead -setting environment variables entirely in `.envrc`: - -``` -export RTX_NODEJS_VERSION=18.0.0 -export RTX_PYTHON_VERSION=3.11 -``` - -Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx -as if direnv was not used. - -If you continue to struggle, you can also try using the [experimental shims feature](#shims). - -### Do you need direnv? - -While making rtx compatible with direnv is, and will always be a major goal of this project, I also -want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing -env vars and virtualenv for python using `.rtx.toml`. - -If you find you continue to need direnv, please open an issue and let me know what it is to see if -it's something rtx could support. rtx will never be as capable as direnv with a DSL like `.envrc`, -but I think we can handle enough common use cases to make that unnecessary for most people. - -## Cache Behavior - -rtx makes use of caching in many places in order to be efficient. The details about how long to keep -cache for should eventually all be configurable. There may be gaps in the current behavior where -things are hardcoded but I'm happy to add more settings to cover whatever config is needed. - -Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear -to be updating, this is a good place to start. - -### Plugin Cache - -Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/plugins/`. It stores -the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), -the list of aliases, and the bin directories within each runtime installation. - -Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is -zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). - -```sh-session -cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode -``` - -### Legacy File Cache - -If enabled, rtx will read the legacy filenames such as `.node-version` for -[asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs). This leverages cache in 2 places where the -plugin is called: - -- [`list-legacy-filenames`](https://github.com/asdf-vm/asdf-nodejs/blob/master/bin/list-legacy-filenames) - In every plugin I've seen this simply returns a static list of filenamed like ".nvmrc .node-version". - It's cached alongside the standard "runtime" cache which is refreshed daily by default. -- [`parse-legacy-file`](https://github.com/asdf-vm/asdf-nodejs/blob/master/bin/parse-legacy-file) - This plugin binary is called to parse a legacy file to get the version out of it. It's relatively - expensive so every file that gets parsed as a legacy file is cached into `~/.local/share/rtx/legacy_cache`. - It will remain cached until the file is modified. This is a simple text file that has the path to the - legacy file stored as a hash for the filename. -"# - ); - - Ok(()) } + doc.push_str(""); + doc } fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option { @@ -1060,7 +90,8 @@ mod tests { #[test] fn test_render_help() { - let stdout = assert_cli!("render-help"); - assert!(stdout.contains("Quickstart")); + assert_cli!("render-help"); + let readme = std::fs::read_to_string("README.md").unwrap(); + assert!(readme.contains("")); } } From d3630b71f91f1ec08f5f13bca3cd62001ac984fc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 10:56:04 -0600 Subject: [PATCH 0359/1891] docs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ac2e12cd0..9e41b40b7 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,7 @@ Build from source with Cargo: ```sh-session $ cargo install rtx-cli +``` Do it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall): From faeb054f7cc16f5660b781e433ab73f5a7715674 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 11:12:15 -0600 Subject: [PATCH 0360/1891] perf: only parse each config file once --- src/config/mod.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index e1217fba3..6ccd2a955 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -41,13 +41,18 @@ impl Config { let plugins = load_plugins()?; let rtxrc = load_rtxrc()?; let mut settings = rtxrc.settings(); - let config_files = load_all_config_files(&settings.build(), &plugins, &IndexMap::new()); + let config_files = load_all_config_files( + &settings.build(), + &plugins, + &IndexMap::new(), + IndexMap::new(), + ); for cf in config_files.values() { settings.merge(cf.settings()); } let settings = settings.build(); let legacy_files = load_legacy_files(&settings, &plugins); - let config_files = load_all_config_files(&settings, &plugins, &legacy_files); + let config_files = load_all_config_files(&settings, &plugins, &legacy_files, config_files); let env = load_env(&config_files); let aliases = load_aliases(&settings, &plugins, &config_files); @@ -136,6 +141,7 @@ fn load_all_config_files( settings: &Settings, plugins: &IndexMap>, legacy_filenames: &IndexMap, + mut existing: IndexMap>, ) -> IndexMap> { let mut filenames = vec![ env::RTX_DEFAULT_CONFIG_FILENAME.as_str(), @@ -156,17 +162,21 @@ fn load_all_config_files( config_files .into_iter() .unique() + .map(|f| (f.clone(), existing.shift_remove(&f))) .collect_vec() .into_par_iter() - .map( - |f| match parse_config_file(&f, settings, legacy_filenames, plugins) { + .map(|(f, existing)| match existing { + // already parsed so just return it + Some(cf) => Some((f, cf)), + // need to parse this config file + None => match parse_config_file(&f, settings, legacy_filenames, plugins) { Ok(cf) => Some((f, cf)), Err(err) => { warn!("error parsing: {} {err}", f.display()); None } }, - ) + }) .collect::>() .into_iter() .flatten() From bcf0ffcc0a69e4d3a0d2341618556ca8fb7710e8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 12:39:12 -0600 Subject: [PATCH 0361/1891] chore: release fix --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index edc4d5fb7..b51d6b186 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,7 +102,6 @@ pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, - { file = "src/cli/render_help.rs", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, ] From 85d3de4c10e84cd57038104e9cee5eb66554fdab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 12:39:48 -0600 Subject: [PATCH 0362/1891] chore: Release rtx-cli version 1.20.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e96ac677..54b99f070 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.20.1" +version = "1.20.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index b51d6b186..90823ad1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.20.1" +version = "1.20.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 9e41b40b7..373eca28f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.20.1 +rtx 1.20.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.1/rtx-v1.20.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.2/rtx-v1.20.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 3a1e1a2d6..97dcff3dd 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.20.1"; + version = "1.20.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 168d402df..e7ffbf9fb 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.20.1" +.TH rtx 1 "rtx 1.20.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -129,6 +129,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.20.1 +v1.20.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index aa933f5e9..f529c40ae 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.20.1 +Version: 1.20.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 5da9afc6b7c6f98bf6a5cbcccfb0130dde47c56d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 20:08:54 -0600 Subject: [PATCH 0363/1891] perf: improvements to install/uninstall (#247) --- README.md | 21 +-- completions/_rtx | 8 +- completions/rtx.bash | 6 +- completions/rtx.fish | 1 + e2e/run_test | 1 + e2e/test_plugins_install | 7 + justfile | 2 +- src/cache.rs | 15 +- src/cli/alias/get.rs | 2 +- src/cli/alias/ls.rs | 2 +- ...tx__cli__alias__set__tests__alias_set.snap | 2 +- src/cli/args/runtime.rs | 23 +++ src/cli/cache/clear.rs | 3 +- src/cli/direnv/exec.rs | 23 ++- src/cli/env.rs | 5 +- src/cli/exec.rs | 3 +- src/cli/external.rs | 21 ++- src/cli/hook_env.rs | 3 +- src/cli/implode.rs | 3 +- src/cli/install.rs | 127 +++++++++++++--- src/cli/ls.rs | 4 +- src/cli/mod.rs | 10 +- src/cli/plugins/install.rs | 108 +++++++++----- src/cli/plugins/ls.rs | 6 +- src/cli/plugins/ls_remote.rs | 7 +- src/cli/plugins/uninstall.rs | 41 ++++-- src/cli/reshim.rs | 2 +- src/cli/uninstall.rs | 16 +- src/config/config_file/legacy_version.rs | 30 ++-- src/config/config_file/mod.rs | 2 +- src/config/config_file/rtx_toml.rs | 4 +- src/config/config_file/rtxrc.rs | 2 +- ...nfig_file__rtx_toml__tests__fixture-4.snap | 1 + ..._file__rtx_toml__tests__remove_plugin.snap | 1 + ...le__rtx_toml__tests__replace_versions.snap | 1 + src/config/config_file/tool_versions.rs | 139 ++++-------------- src/config/mod.rs | 136 +++++++++++------ src/env.rs | 9 ++ src/errors.rs | 4 +- src/file.rs | 19 ++- src/hook_env.rs | 97 ++++++------ src/main.rs | 34 +++-- src/plugins/mod.rs | 100 +++++++------ src/plugins/script_manager.rs | 34 +++-- src/runtimes.rs | 126 ++++++++-------- src/toolset/builder.rs | 51 +------ src/toolset/mod.rs | 52 ++++--- src/toolset/tool_version.rs | 30 ++-- src/toolset/tool_version_list.rs | 36 +++-- src/ui/multi_progress_report.rs | 7 + src/ui/progress_report.rs | 54 ++++++- 51 files changed, 869 insertions(+), 572 deletions(-) diff --git a/README.md b/README.md index 373eca28f..671f120b5 100644 --- a/README.md +++ b/README.md @@ -1393,7 +1393,9 @@ Usage: install [OPTIONS] [NAME] [GIT_URL] Arguments: [NAME] - The name of the plugin to install e.g.: nodejs, ruby + The name of the plugin to install + e.g.: nodejs, ruby + Can specify multiple plugins: `rtx plugins install nodejs ruby python` [GIT_URL] The git url of the plugin @@ -1411,11 +1413,10 @@ Options: Show installation output Examples: - # install the nodejs plugin using the shorthand repo: - # https://github.com/asdf-vm/asdf-plugins + # install the nodejs via shorthand $ rtx install nodejs - # install the nodejs plugin using the git url + # install the nodejs plugin using a specific git url $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git # install the nodejs plugin using the git url only @@ -1465,17 +1466,20 @@ Usage: ls-remote [OPTIONS] Options: -u, --urls Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git + + --only-names + Only show the name of each plugin by default it will show a "*" next to installed plugins ``` ### `rtx plugins uninstall` ``` Removes a plugin -Usage: uninstall +Usage: uninstall ... Arguments: - - Plugin to remove + ... + Plugin(s) to remove Examples: $ rtx uninstall nodejs @@ -1879,7 +1883,7 @@ Remote versions are updated daily by default or anytime that `rtx ls-remote` is zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.zlib | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode +cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` ### Legacy File Cache @@ -1896,4 +1900,3 @@ plugin is called: expensive so every file that gets parsed as a legacy file is cached into `~/.local/share/rtx/legacy_cache`. It will remain cached until the file is modified. This is a simple text file that has the path to the legacy file stored as a hash for the filename. - diff --git a/completions/_rtx b/completions/_rtx index 4ba2a9c36..5f8179eff 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -655,8 +655,11 @@ i.e.: they don'\''t need the full git repo url]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::name -- The name of the plugin to install e.g.\: nodejs, ruby:' \ +'::name -- The name of the plugin to install +e.g.\: nodejs, ruby +Can specify multiple plugins\: `rtx plugins install nodejs ruby python`:' \ '::git_url -- The git url of the plugin:_urls' \ +'*::rest:' \ && ret=0 ;; (ls) @@ -687,6 +690,7 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +'--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ '*-v[Show installation output]' \ @@ -706,7 +710,7 @@ _arguments "${_arguments_options[@]}" \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- Plugin to remove:' \ +'*::plugin -- Plugin(s) to remove:' \ && ret=0 ;; (update) diff --git a/completions/rtx.bash b/completions/rtx.bash index 3ec021a52..fca6f3197 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2358,7 +2358,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -r -h --force --all --verbose --jobs --log-level --raw --help [NAME] [GIT_URL]" + opts="-f -a -v -j -r -h --force --all --verbose --jobs --log-level --raw --help [NAME] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2410,7 +2410,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -r -v -h --urls --jobs --log-level --raw --verbose --help" + opts="-u -j -r -v -h --urls --only-names --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2436,7 +2436,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --jobs --log-level --raw --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 975ab63bd..c8ef0ea42 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -274,6 +274,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/e2e/run_test b/e2e/run_test index efa6740a6..8a230e62c 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -6,6 +6,7 @@ ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)" export ROOT export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="$ROOT/e2e/.rtx" +export RTX_CACHE_DIR="$ROOT/e2e/.cache" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml unset GOPATH diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install index dda27fa6b..33bec4d89 100755 --- a/e2e/test_plugins_install +++ b/e2e/test_plugins_install @@ -20,6 +20,13 @@ assert_contains() { fi } +# install/uninstall multiple +rtx plugin uninstall tiny shfmt shellcheck +rtx plugin install tiny shfmt shellcheck +assert_contains "rtx plugin ls" "tiny" +assert_contains "rtx plugin ls" "shfmt" +assert_contains "rtx plugin ls" "shellcheck" + rm -rf "$RTX_DATA_DIR/plugins/tiny" rtx plugin install https://github.com/jdxcode/rtx-tiny.git assert_contains "rtx plugin ls" "tiny" diff --git a/justfile b/justfile index a6eeb0bda..f383f85f2 100644 --- a/justfile +++ b/justfile @@ -17,7 +17,7 @@ build *args: alias t := test # run all test types -test *args: (test-unit args) test-e2e +test *args: (test-unit args) test-e2e lint # update all test snapshot files test-update-snapshots: diff --git a/src/cache.rs b/src/cache.rs index 87547c8e1..2226917c8 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -5,7 +5,7 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::time::Duration; -use crate::file::modified_duration; +use crate::file::{display_path, modified_duration}; use color_eyre::eyre::Result; use flate2::read::ZlibDecoder; use flate2::write::ZlibEncoder; @@ -23,6 +23,7 @@ where fresh_duration: Option, fresh_files: Vec, cache: Box>, + no_cache: bool, } impl CacheManager @@ -35,6 +36,7 @@ where cache: Box::new(OnceCell::new()), fresh_files: Vec::new(), fresh_duration: None, + no_cache: false, } } @@ -48,13 +50,18 @@ where self } + pub fn with_no_cache(mut self) -> Self { + self.no_cache = true; + self + } + pub fn get_or_try_init(&self, fetch: F) -> Result<&T> where F: FnOnce() -> Result, { let val = self.cache.get_or_try_init(|| { let path = &self.cache_file_path; - if self.is_fresh() { + if !self.no_cache && self.is_fresh() { match self.parse() { Ok(val) => return Ok::<_, color_eyre::Report>(val), Err(err) => { @@ -73,7 +80,7 @@ where fn parse(&self) -> Result { let path = &self.cache_file_path; - trace!("reading cache {}", path.display()); + trace!("reading {}", display_path(path)); let mut zlib = ZlibDecoder::new(File::open(path)?); let mut bytes = Vec::new(); zlib.read_to_end(&mut bytes)?; @@ -82,7 +89,7 @@ where pub fn write(&self, val: T) -> Result<()> { let path = &self.cache_file_path; - trace!("writing cache {}", path.display()); + trace!("writing {}", display_path(path)); if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index be67f4889..8340970b5 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -22,7 +22,7 @@ pub struct AliasGet { impl Command for AliasGet { fn run(self, config: Config, out: &mut Output) -> Result<()> { - match config.aliases.get(&self.plugin) { + match config.get_all_aliases().get(&self.plugin) { Some(plugin) => match plugin.get(&self.alias) { Some(alias) => Ok(rtxprintln!(out, "{}", alias)), None => Err(eyre!("Unknown alias: {}", &self.alias)), diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index b1974b7e5..761f24170 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -26,7 +26,7 @@ pub struct AliasLs { impl Command for AliasLs { fn run(self, config: Config, out: &mut Output) -> Result<()> { - for (plugin_name, aliases) in &config.aliases { + for (plugin_name, aliases) in config.get_all_aliases() { if let Some(plugin) = &self.plugin { if plugin_name != plugin { continue; diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 7d92b9591..0963f8bce 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -2,7 +2,7 @@ source: src/cli/alias/set.rs expression: output --- +tiny my/alias 3.0 tiny lts 3.1.0 tiny lts-prev 2.0.0 -tiny my/alias 3.0 diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index 8f032b4bb..9c0d1f9f9 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -7,6 +7,7 @@ use color_eyre::eyre::Result; use regex::Regex; use crate::plugins::PluginName; +use crate::toolset::{ToolVersion, ToolVersionType}; #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct RuntimeArg { @@ -94,6 +95,28 @@ impl RuntimeArg { pub fn with_version(self, version: RuntimeArgVersion) -> Self { Self { version, ..self } } + + pub fn to_tool_version(&self) -> Option { + match self.version { + RuntimeArgVersion::Version(ref v) => Some(ToolVersion::new( + self.plugin.clone(), + ToolVersionType::Version(v.clone()), + )), + RuntimeArgVersion::Ref(ref v) => Some(ToolVersion::new( + self.plugin.clone(), + ToolVersionType::Ref(v.clone()), + )), + RuntimeArgVersion::Path(ref v) => Some(ToolVersion::new( + self.plugin.clone(), + ToolVersionType::Path(v.clone()), + )), + RuntimeArgVersion::Prefix(ref v) => Some(ToolVersion::new( + self.plugin.clone(), + ToolVersionType::Prefix(v.clone()), + )), + _ => None, + } + } } impl Display for RuntimeArg { diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index 5073c8e4d..a75a47c53 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -3,6 +3,7 @@ use color_eyre::eyre::Result; use crate::cli::command::Command; use crate::config::Config; use crate::env; +use crate::file::remove_dir_all; use crate::output::Output; /// Deletes all cache files in rtx @@ -15,7 +16,7 @@ impl Command for CacheClear { let cache_dir = env::RTX_CACHE_DIR.to_path_buf(); if cache_dir.exists() { debug!("clearing cache from {}", cache_dir.display()); - std::fs::remove_dir_all(cache_dir)?; + remove_dir_all(cache_dir)?; } rtxstatusln!(out, "cache cleared"); Ok(()) diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index e7a7d2dea..352a64011 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Result; +use duct::Expression; use serde_derive::Deserialize; use crate::cli::command::Command; @@ -26,16 +27,11 @@ impl Command for DirenvExec { config.settings.missing_runtime_behavior = Warn; } let ts = ToolsetBuilder::new().with_install_missing().build(&config); - let mut cmd = if cfg!(test) { - cmd!("env") - } else { - cmd!("direnv", "dump") - }; + let mut cmd = env_cmd(); - for (k, v) in ts.env(&config) { + for (k, v) in ts.env_with_path(&config) { cmd = cmd.env(k, v); } - cmd = cmd.env("PATH", ts.path_env(&config.settings)); let json = cmd!("direnv", "watch", "json", ".tool-versions").read()?; let w: DirenvWatches = serde_json::from_str(&json)?; @@ -46,11 +42,22 @@ impl Command for DirenvExec { } } +#[cfg(test)] +fn env_cmd() -> Expression { + cmd!("env") +} + +#[cfg(not(test))] +fn env_cmd() -> Expression { + cmd!("direnv", "dump") +} + #[cfg(test)] mod tests { + use pretty_assertions::assert_str_eq; + use crate::assert_cli; use crate::cli::tests::grep; - use pretty_assertions::assert_str_eq; #[test] fn test_direnv_exec() { diff --git a/src/cli/env.rs b/src/cli/env.rs index 8c701b2ae..ede43ef1d 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -35,13 +35,12 @@ impl Command for Env { let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); - for (k, v) in ts.env(&config) { + + for (k, v) in ts.env_with_path(&config) { let k = k.to_string(); let v = v.to_string(); rtxprint!(out, "{}", shell.set_env(&k, &v)); } - let path = ts.path_env(&config.settings); - rtxprintln!(out, "{}", shell.set_env("PATH", &path)); Ok(()) } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 7550561c6..a6c745529 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -53,8 +53,7 @@ impl Command for Exec { .build(&config); let (program, args) = parse_command(&env::SHELL, self.command, self.c); - let mut env = ts.env(&config); - env.insert("PATH".into(), ts.path_env(&config.settings)); + let mut env = ts.env_with_path(&config); if config.settings.missing_runtime_behavior != Ignore { // prevent rtx from auto-installing inside a shim env.insert("RTX_MISSING_RUNTIME_BEHAVIOR".into(), "warn".into()); diff --git a/src/cli/external.rs b/src/cli/external.rs index 48013a76a..ca8313686 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -5,14 +5,23 @@ use rayon::prelude::*; use crate::config::Config; -pub fn commands(config: &Config) -> Result> { - let commands = config +pub fn commands(config: &Config) -> Vec { + config .plugins .values() .collect_vec() .into_par_iter() - .map(|p| p.external_commands()) - .collect::>>>>()? + .map(|p| match p.external_commands() { + Ok(commands) => commands, + Err(e) => { + warn!( + "failed to load external commands for plugin {}: {}", + p.name, e + ); + vec![] + } + }) + .collect::>>>() .into_iter() .filter(|commands| !commands.is_empty()) .filter(|commands| commands[0][0] != "direnv") @@ -28,9 +37,7 @@ pub fn commands(config: &Config) -> Result> { }, )) }) - .collect::>(); - - Ok(commands) + .collect() } pub fn execute( diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index ecfe17084..b33627015 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -135,9 +135,10 @@ impl HookEnv { } fn build_watch_operation(&self, config: &Config) -> Result { + let config_filenames: Vec<_> = config.config_files.keys().cloned().collect(); Ok(EnvDiffOperation::Add( "__RTX_WATCH".into(), - hook_env::serialize_watches(&hook_env::build_watches(config)?)?, + hook_env::serialize_watches(&hook_env::build_watches(&config_filenames)?)?, )) } } diff --git a/src/cli/implode.rs b/src/cli/implode.rs index a57e8e2f1..3fce5b698 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -2,6 +2,7 @@ use color_eyre::eyre::Result; use crate::cli::command::Command; use crate::config::Config; +use crate::file::remove_dir_all; use crate::output::Output; use crate::{dirs, env}; @@ -30,7 +31,7 @@ impl Command for Implode { if f.is_dir() { rtxprintln!(out, "rm -rf {}", f.display()); if !self.dry_run { - std::fs::remove_dir_all(f)?; + remove_dir_all(f)?; } } else { rtxprintln!(out, "rm -f {}", f.display()); diff --git a/src/cli/install.rs b/src/cli/install.rs index 7ce45b8c1..15f2a2d52 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,18 +1,22 @@ use std::collections::HashSet; +use std::sync::Arc; use color_eyre::eyre::Result; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; +use rayon::prelude::*; +use rayon::ThreadPoolBuilder; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::PluginName; -use crate::toolset::ToolsetBuilder; +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionType, ToolsetBuilder}; +use crate::ui::multi_progress_report::MultiProgressReport; /// Install a runtime /// @@ -63,34 +67,109 @@ impl Command for Install { impl Install { fn install_runtimes(&self, config: &Config, runtimes: &[RuntimeArg]) -> Result<()> { - let runtimes = RuntimeArg::double_runtime_condition(runtimes); - let mut ts = ToolsetBuilder::new().with_args(&runtimes).build(config); - let plugins_to_install = runtimes.iter().map(|r| &r.plugin).collect::>(); - for plugin in ts.versions.clone().keys() { - if !plugins_to_install.contains(plugin) { - ts.versions.remove(plugin); + let mpr = MultiProgressReport::new(config.settings.verbose); + let mut tool_versions = vec![]; + let ts = ToolsetBuilder::new().build(config); + for runtime in RuntimeArg::double_runtime_condition(runtimes) { + match runtime.to_tool_version() { + Some(tv) => tool_versions.push(tv), + None => { + if runtime.version == RuntimeArgVersion::None { + match ts.versions.get(&runtime.plugin) { + Some(tvl) => { + for tv in &tvl.versions { + tool_versions.push(tv.clone()); + } + } + None => { + let tv = ToolVersion::new( + runtime.plugin.clone(), + ToolVersionType::Version("latest".into()), + ); + tool_versions.push(tv); + } + } + } + } } } - if ts.versions.is_empty() { + let mut versions = vec![]; + for mut tv in tool_versions { + let plugin = match config.plugins.get(&tv.plugin_name).cloned() { + Some(plugin) => plugin, + None => { + let plugin = Plugin::new(&tv.plugin_name); + let mut pr = mpr.add(); + match plugin.install(config, None, &mut pr) { + Ok(_) => Arc::new(plugin), + Err(err) => { + pr.error(); + return Err(err)?; + } + } + } + }; + tv.resolve(config, plugin)?; + versions.push(tv.rtv.unwrap()); + } + if versions.is_empty() { warn!("no runtimes to install"); warn!("specify a version with `rtx install @`"); return Ok(()); } - for (plugin, versions) in &ts.versions { - if plugins_to_install.contains(plugin) && self.force { - for v in &versions.versions { - if let Some(rtv) = &v.rtv { - if rtv.is_installed() { - info!("uninstalling {}", rtv); - rtv.uninstall(&config.settings)?; - } - } + let mut to_uninstall = vec![]; + for rtv in &versions { + if rtv.is_installed() { + if self.force { + to_uninstall.push(rtv.clone()); + } else { + warn!("{} already installed", style(rtv).cyan().for_stderr()); } } } - ts.install_missing(config)?; + ThreadPoolBuilder::new() + .num_threads(config.settings.jobs) + .build()? + .install(|| -> Result<()> { + if !to_uninstall.is_empty() { + to_uninstall + .into_par_iter() + .map(|rtv| { + let mut pr = mpr.add(); + rtv.decorate_progress_bar(&mut pr); + match rtv.uninstall(&config.settings, &pr) { + Ok(_) => { + pr.finish(); + Ok(()) + } + Err(err) => { + pr.error(); + Err(err.wrap_err(format!("failed to uninstall {}", rtv))) + } + } + }) + .collect::>>()?; + } + versions + .into_par_iter() + .map(|rtv| { + if rtv.is_installed() { + return Ok(()); + } + let mut pr = mpr.add(); + rtv.decorate_progress_bar(&mut pr); + match rtv.install(config, &mut pr) { + Ok(_) => Ok(()), + Err(err) => { + pr.error(); + Err(err.wrap_err(format!("failed to install {}", rtv))) + } + } + }) + .collect::>>()?; - Ok(()) + Ok(()) + }) } fn install_missing_runtimes(&self, config: &Config) -> Result<()> { @@ -108,7 +187,11 @@ impl Install { } } } - ts.install_missing(config)?; + if ts.list_missing_versions().is_empty() { + warn!("no runtimes to install"); + } + let mpr = MultiProgressReport::new(config.settings.verbose); + ts.install_missing(config, Some(mpr))?; Ok(()) } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 77a222013..b48979784 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -159,12 +159,12 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { + use crate::file::remove_dir_all; use crate::{assert_cli, assert_cli_snapshot, dirs}; - use std::fs; #[test] fn test_ls() { - let _ = fs::remove_dir_all(dirs::INSTALLS.as_path()); + let _ = remove_dir_all(dirs::INSTALLS.as_path()); assert_cli!("install"); assert_cli_snapshot!("list"); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 03f2110e9..3eade47a5 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -138,12 +138,12 @@ impl Cli { } } - pub fn new_with_external_commands(config: &Config) -> Result { - let external_commands = external::commands(config)?; - Ok(Self { + pub fn new_with_external_commands(config: &Config) -> Self { + let external_commands = external::commands(config); + Self { command: Self::command().subcommands(external_commands.clone()), external_commands, - }) + } } pub fn command() -> clap::Command { @@ -235,7 +235,7 @@ pub mod tests { pub fn cli_run(args: &Vec) -> Result { let config = Config::load()?; let mut out = Output::tracked(); - Cli::new_with_external_commands(&config)?.run(config, args, &mut out)?; + Cli::new_with_external_commands(&config).run(config, args, &mut out)?; Ok(out) } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 1487b8b70..255c0d311 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -2,14 +2,16 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; +use rayon::prelude::*; +use rayon::ThreadPoolBuilder; use url::Url; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; +use crate::plugins::{Plugin, PluginName}; use crate::toolset::ToolsetBuilder; -use crate::ui::progress_report::ProgressReport; +use crate::ui::multi_progress_report::MultiProgressReport; /// Install a plugin /// @@ -22,16 +24,17 @@ use crate::ui::progress_report::ProgressReport; pub struct PluginsInstall { /// The name of the plugin to install /// e.g.: nodejs, ruby - #[clap(required_unless_present = "all")] + /// Can specify multiple plugins: `rtx plugins install nodejs ruby python` + #[clap(required_unless_present = "all", verbatim_doc_comment)] name: Option, /// The git url of the plugin /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git - #[clap(help = "The git url of the plugin", value_hint = clap::ValueHint::Url)] + #[clap(help = "The git url of the plugin", value_hint = clap::ValueHint::Url, verbatim_doc_comment)] git_url: Option, /// Reinstall even if plugin exists - #[clap(short, long)] + #[clap(short, long, verbatim_doc_comment)] force: bool, /// Install all missing plugins @@ -41,25 +44,27 @@ pub struct PluginsInstall { all: bool, /// Show installation output - #[clap(long, short, action = clap::ArgAction::Count)] + #[clap(long, short, action = clap::ArgAction::Count, verbatim_doc_comment)] verbose: u8, + + #[clap(hide = true)] + rest: Vec, } impl Command for PluginsInstall { fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let mpr = MultiProgressReport::new(config.settings.verbose); if self.all { - return self.install_all_missing_plugins(&config); - } - let (name, git_url) = get_name_and_url(&config, self.name.unwrap(), self.git_url)?; - let plugin = Plugin::new(&name); - if self.force { - plugin.uninstall()?; + return self.install_all_missing_plugins(&config, mpr); } - if !self.force && plugin.is_installed() { - warn!("plugin {} already installed", name); + let (name, git_url) = + get_name_and_url(&config, &self.name.clone().unwrap(), &self.git_url)?; + if git_url.contains("://") { + self.install_one(&config, &name, &git_url, &mpr)?; } else { - let pr = ProgressReport::new(config.settings.verbose); - plugin.install(&config, Some(&git_url), pr)?; + let mut plugins: Vec = vec![name, git_url]; + plugins.extend(self.rest.clone()); + self.install_many(&config, &plugins, mpr)?; } Ok(()) @@ -67,20 +72,56 @@ impl Command for PluginsInstall { } impl PluginsInstall { - fn install_all_missing_plugins(&self, config: &Config) -> Result<()> { + fn install_all_missing_plugins(&self, config: &Config, mpr: MultiProgressReport) -> Result<()> { let ts = ToolsetBuilder::new().build(config); let missing_plugins = ts.list_missing_plugins(); if missing_plugins.is_empty() { warn!("all plugins already installed"); } - for plugin in missing_plugins { - let plugin = Plugin::new(&plugin); - let (_, git_url) = get_name_and_url(config, plugin.name.clone(), None)?; - plugin.install( - config, - Some(&git_url), - ProgressReport::new(config.settings.verbose), - )?; + self.install_many(config, &missing_plugins, mpr)?; + Ok(()) + } + + fn install_many( + &self, + config: &Config, + plugins: &[PluginName], + mpr: MultiProgressReport, + ) -> Result<()> { + ThreadPoolBuilder::new() + .num_threads(config.settings.jobs) + .build()? + .install(|| -> Result<()> { + plugins + .into_par_iter() + .map(|plugin| { + let (_, git_url) = get_name_and_url(config, plugin, &None)?; + self.install_one(config, plugin, &git_url, &mpr) + }) + .collect::>>()?; + Ok(()) + }) + } + + fn install_one( + &self, + config: &Config, + name: &String, + git_url: &String, + mpr: &MultiProgressReport, + ) -> Result<()> { + let plugin = Plugin::new(name); + if !self.force && plugin.is_installed() { + mpr.suspend(|| { + warn!("plugin {} already installed", name); + }); + } else { + let mut pr = mpr.add(); + plugin.decorate_progress_bar(&mut pr); + if self.force { + plugin.uninstall(&pr)?; + } + plugin.install(config, Some(git_url), &mut pr)?; } Ok(()) } @@ -88,19 +129,19 @@ impl PluginsInstall { fn get_name_and_url( config: &Config, - name: String, - git_url: Option, + name: &String, + git_url: &Option, ) -> Result<(String, String)> { Ok(match git_url { - Some(url) => (name, url), + Some(url) => (name.clone(), url.clone()), None => match name.contains(':') { - true => (get_name_from_url(&name)?, name), + true => (get_name_from_url(name)?, name.clone()), false => { let git_url = config .get_shorthands() - .get(&name) + .get(name) .ok_or_else(|| eyre!("could not find plugin {}", name))?; - (name, git_url.to_string()) + (name.clone(), git_url.to_string()) } }, }) @@ -122,11 +163,10 @@ fn get_name_from_url(url: &str) -> Result { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - # install the nodejs plugin using the shorthand repo: - # https://github.com/asdf-vm/asdf-plugins + # install the nodejs via shorthand $ rtx install nodejs - # install the nodejs plugin using the git url + # install the nodejs plugin using a specific git url $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git # install the nodejs plugin using the git url only diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index d3077f91e..760617f33 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -28,7 +28,11 @@ pub struct PluginsLs { impl Command for PluginsLs { fn run(self, config: Config, out: &mut Output) -> Result<()> { if self.all { - return PluginsLsRemote { urls: self.urls }.run(config, out); + return PluginsLsRemote { + urls: self.urls, + only_names: false, + } + .run(config, out); } for plugin in config.plugins.values() { diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index b42c043da..7a5490f75 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -18,6 +18,11 @@ pub struct PluginsLsRemote { /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long)] pub urls: bool, + + /// Only show the name of each plugin + /// by default it will show a "*" next to installed plugins + #[clap(long)] + pub only_names: bool, } impl Command for PluginsLsRemote { @@ -41,7 +46,7 @@ impl Command for PluginsLsRemote { } for (plugin, repo) in shorthands { - let installed = if installed_plugins.contains(plugin) { + let installed = if !self.only_names && installed_plugins.contains(plugin) { "*" } else { " " diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 3b7a609cc..1ca1cb3c1 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,5 +1,6 @@ use color_eyre::eyre::Result; use console::style; + use indoc::formatdoc; use once_cell::sync::Lazy; @@ -7,29 +8,49 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::ui::multi_progress_report::MultiProgressReport; + /// Removes a plugin #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP.as_str())] pub struct PluginsUninstall { - /// Plugin to remove - #[clap()] - plugin: String, + /// Plugin(s) to remove + #[clap(required = true, verbatim_doc_comment)] + pub plugin: Vec, } impl Command for PluginsUninstall { - fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugin = config.plugins.get(&self.plugin); + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let mpr = MultiProgressReport::new(config.settings.verbose); + + for plugin_name in &self.plugin { + self.uninstall_one(&config, plugin_name, &mpr)?; + } + Ok(()) + } +} + +impl PluginsUninstall { + fn uninstall_one( + &self, + config: &Config, + plugin_name: &String, + mpr: &MultiProgressReport, + ) -> Result<()> { + let plugin = config.plugins.get(plugin_name); match plugin { Some(plugin) if plugin.is_installed() => { - rtxprintln!(out, "uninstalling plugin: {}", style(&self.plugin).cyan()); - plugin.uninstall()?; + let mut pr = mpr.add(); + plugin.decorate_progress_bar(&mut pr); + plugin.uninstall(&pr)?; + pr.finish_with_message("uninstalled".into()); } - _ => { + _ => mpr.suspend(|| { warn!( "{} is not installed", - style(&self.plugin).cyan().for_stderr() + style(plugin_name).cyan().for_stderr() ); - } + }), } Ok(()) } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 5e25b7d72..176162b79 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,5 +1,4 @@ use std::fs; -use std::fs::{create_dir_all, remove_dir_all}; use std::os::unix::fs::symlink; use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; @@ -12,6 +11,7 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::env::RTX_EXE; +use crate::file::{create_dir_all, remove_dir_all}; use crate::output::Output; use crate::toolset::ToolsetBuilder; use crate::{dirs, fake_asdf}; diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index f28bc842b..b717d2327 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::{eyre, Result, WrapErr}; +use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -8,6 +8,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::toolset::ToolsetBuilder; +use crate::ui::multi_progress_report::MultiProgressReport; /// Removes runtime versions #[derive(Debug, clap::Args)] @@ -19,20 +20,25 @@ pub struct Uninstall { } impl Command for Uninstall { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { let runtimes = RuntimeArg::double_runtime_condition(&self.runtime); let ts = ToolsetBuilder::new().with_args(&runtimes).build(&config); let runtime_versions = runtimes.iter().filter_map(|a| ts.resolve_runtime_arg(a)); + let mpr = MultiProgressReport::new(config.settings.verbose); for rtv in runtime_versions { if !rtv.is_installed() { warn!("{} is not installed", style(rtv).cyan().for_stderr()); continue; } - rtxprintln!(out, "uninstalling {}", style(rtv).cyan()); - rtv.uninstall(&config.settings) - .wrap_err_with(|| eyre!("error uninstalling {}", rtv))?; + let mut pr = mpr.add(); + rtv.decorate_progress_bar(&mut pr); + if let Err(err) = rtv.uninstall(&config.settings, &pr) { + pr.error(); + return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", rtv))); + } + pr.finish_with_message("uninstalled".into()); } Ok(()) } diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 4c2ce8ad2..1ade98437 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -17,6 +17,7 @@ pub struct LegacyVersionFile { path: PathBuf, version: String, plugin: String, + toolset: Toolset, } impl LegacyVersionFile { @@ -24,6 +25,7 @@ impl LegacyVersionFile { let version = plugin.parse_legacy_file(path.as_path(), settings)?; Ok(Self { + toolset: build_toolset(&path, plugin.name.as_str(), version.as_str()), path, version, plugin: plugin.name.clone(), @@ -72,8 +74,8 @@ impl ConfigFile for LegacyVersionFile { unimplemented!() } - fn to_toolset(&self) -> Toolset { - self.into() + fn to_toolset(&self) -> &Toolset { + &self.toolset } fn settings(&self) -> SettingsBuilder { @@ -91,18 +93,16 @@ impl Display for LegacyVersionFile { } } -impl From<&LegacyVersionFile> for Toolset { - fn from(value: &LegacyVersionFile) -> Self { - let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(value.path.clone())); - if !value.version.is_empty() { - toolset.add_version( - value.plugin.clone(), - ToolVersion::new( - value.plugin.clone(), - ToolVersionType::Version(value.version.clone()), - ), - ); - } - toolset +fn build_toolset(path: &Path, plugin: &str, version: &str) -> Toolset { + let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.to_path_buf())); + if !version.is_empty() { + toolset.add_version( + plugin.to_string(), + ToolVersion::new( + plugin.to_string(), + ToolVersionType::Version(version.to_string()), + ), + ); } + toolset } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 2622e96ed..25dc71b49 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -42,7 +42,7 @@ pub trait ConfigFile: Debug + Display + Send + Sync { fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]); fn save(&self) -> Result<()>; fn dump(&self) -> String; - fn to_toolset(&self) -> Toolset; + fn to_toolset(&self) -> &Toolset; fn settings(&self) -> SettingsBuilder; fn aliases(&self) -> AliasMap; } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index b781f6efe..8f16c7c85 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -475,8 +475,8 @@ impl ConfigFile for RtxToml { self.doc.to_string() } - fn to_toolset(&self) -> Toolset { - self.toolset.clone() + fn to_toolset(&self) -> &Toolset { + &self.toolset } fn settings(&self) -> SettingsBuilder { diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 0e681ec8a..91a6460b8 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -414,7 +414,7 @@ impl ConfigFile for RTXFile { self.get_edit().unwrap().lock().unwrap().to_string() } - fn to_toolset(&self) -> Toolset { + fn to_toolset(&self) -> &Toolset { todo!() } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index 8d3825ca9..f5c7eea21 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -131,4 +131,5 @@ Toolset { ), ), plugins: {}, + mpr: None, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap index 6b71c05c3..c66afee41 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap @@ -10,4 +10,5 @@ Toolset { ), ), plugins: {}, + mpr: None, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index 77f83b581..1830d6694 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -36,4 +36,5 @@ Toolset { ), ), plugins: {}, + mpr: None, } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 5177344b8..b9b585bde 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -26,6 +26,7 @@ pub struct ToolVersions { path: PathBuf, pre: String, plugins: IndexMap, + toolset: Toolset, } #[derive(Debug, Default)] @@ -44,13 +45,10 @@ impl ToolVersions { pub fn from_file(path: &Path) -> Result { trace!("parsing tool-versions: {}", path.display()); - Ok(Self { - path: path.to_path_buf(), - ..Self::parse_str(&read_to_string(path)?)? - }) + Self::parse_str(&read_to_string(path)?, path.to_path_buf()) } - pub fn parse_str(s: &str) -> Result { + pub fn parse_str(s: &str, path: PathBuf) -> Result { let mut pre = String::new(); for line in s.lines() { if !line.trim_start().starts_with('#') { @@ -60,9 +58,11 @@ impl ToolVersions { pre.push('\n'); } + let plugins = Self::parse_plugins(s)?; Ok(Self { - path: PathBuf::new(), - plugins: Self::parse_plugins(s)?, + toolset: build_toolset(&path, &plugins), + path, + plugins, pre, }) } @@ -103,23 +103,21 @@ impl ToolVersions { } } -impl From<&ToolVersions> for Toolset { - fn from(value: &ToolVersions) -> Self { - let mut toolset = Toolset::new(ToolSource::ToolVersions(value.path.clone())); - for (plugin, tvp) in &value.plugins { - for version in &tvp.versions { - let v = match version.split_once(':') { - Some(("prefix", v)) => ToolVersionType::Prefix(v.to_string()), - Some(("ref", v)) => ToolVersionType::Ref(v.to_string()), - Some(("path", v)) => ToolVersionType::Path(PathBuf::from(v)), - None if version == "system" => ToolVersionType::System, - _ => ToolVersionType::Version(version.to_string()), - }; - toolset.add_version(plugin.clone(), ToolVersion::new(plugin.clone(), v)); - } +fn build_toolset(path: &Path, plugins: &IndexMap) -> Toolset { + let mut toolset = Toolset::new(ToolSource::ToolVersions(path.to_path_buf())); + for (plugin, tvp) in plugins { + for version in &tvp.versions { + let v = match version.split_once(':') { + Some(("prefix", v)) => ToolVersionType::Prefix(v.to_string()), + Some(("ref", v)) => ToolVersionType::Ref(v.to_string()), + Some(("path", v)) => ToolVersionType::Path(PathBuf::from(v)), + None if version == "system" => ToolVersionType::System, + _ => ToolVersionType::Version(version.to_string()), + }; + toolset.add_version(plugin.clone(), ToolVersion::new(plugin.clone(), v)); } - toolset } + toolset } impl Display for ToolVersions { @@ -196,8 +194,8 @@ impl ConfigFile for ToolVersions { s.trim_end().to_string() + "\n" } - fn to_toolset(&self) -> Toolset { - self.into() + fn to_toolset(&self) -> &Toolset { + &self.toolset } fn settings(&self) -> SettingsBuilder { @@ -211,7 +209,6 @@ impl ConfigFile for ToolVersions { #[cfg(test)] pub(crate) mod tests { - use std::fmt::Debug; use indoc::indoc; use insta::{assert_display_snapshot, assert_snapshot}; @@ -238,7 +235,7 @@ pub(crate) mod tests { shfmt 3.6.0 # tail comment "}; - let tv = ToolVersions::parse_str(orig).unwrap(); + let tv = ToolVersions::parse_str(orig, PathBuf::new()).unwrap(); assert_eq!(tv.dump(), orig); } @@ -247,7 +244,7 @@ pub(crate) mod tests { let orig = indoc! {" ruby: 3.0.5 "}; - let tv = ToolVersions::parse_str(orig).unwrap(); + let tv = ToolVersions::parse_str(orig, PathBuf::new()).unwrap(); assert_snapshot!(tv.dump(), @r###" ruby 3.0.5 "###); @@ -258,91 +255,7 @@ pub(crate) mod tests { let orig = indoc! {" ruby: 3.0.5 3.1 "}; - let tv = ToolVersions::parse_str(orig).unwrap(); - let toolset: Toolset = (&tv).into(); - assert_display_snapshot!(toolset, @"ruby@3.0.5 ruby@3.1"); - } - - #[derive(Debug)] - pub struct MockToolVersions { - pub path: PathBuf, - pub plugins: IndexMap>, - pub env: HashMap, - } - - // impl MockToolVersions { - // pub fn new() -> Self { - // Self { - // path: PathBuf::from(".tool-versions"), - // plugins: IndexMap::from([ - // ( - // "python".to_string(), - // vec!["3.11.0".to_string(), "3.10.0".to_string()], - // ), - // ("shellcheck".to_string(), vec!["0.9.0".to_string()]), - // ("shfmt".to_string(), vec!["3.6.0".to_string()]), - // ]), - // env: HashMap::from([ - // ("FOO".to_string(), "bar".to_string()), - // ("BAZ".to_string(), "qux".to_string()), - // ]), - // } - // } - // } - // - impl Display for MockToolVersions { - fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { - todo!() - } - } - - impl ConfigFile for MockToolVersions { - fn get_type(&self) -> ConfigFileType { - ConfigFileType::ToolVersions - } - - fn get_path(&self) -> &Path { - self.path.as_path() - } - - fn plugins(&self) -> IndexMap> { - self.plugins.clone() - } - - fn env(&self) -> HashMap { - self.env.clone() - } - - fn remove_plugin(&mut self, _plugin_name: &PluginName) { - todo!() - } - - fn add_version(&mut self, _plugin_name: &PluginName, _version: &str) { - todo!() - } - - fn replace_versions(&mut self, _plugin_name: &PluginName, _versions: &[String]) { - todo!() - } - - fn save(&self) -> Result<()> { - todo!() - } - - fn dump(&self) -> String { - todo!() - } - - fn to_toolset(&self) -> Toolset { - todo!() - } - - fn settings(&self) -> SettingsBuilder { - todo!() - } - - fn aliases(&self) -> AliasMap { - todo!() - } + let tv = ToolVersions::parse_str(orig, PathBuf::new()).unwrap(); + assert_display_snapshot!(tv.to_toolset(), @"ruby@3.0.5 ruby@3.1"); } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 6ccd2a955..3d169633c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,7 +17,7 @@ use crate::config::config_file::rtxrc::RTXFile; use crate::config::config_file::ConfigFile; use crate::plugins::{Plugin, PluginName}; use crate::shorthands::{get_shorthands, Shorthands}; -use crate::{dirs, env, file}; +use crate::{dirs, env, file, hook_env}; pub mod config_file; mod settings; @@ -30,9 +30,11 @@ pub struct Config { pub rtxrc: RTXFile, pub legacy_files: IndexMap, pub config_files: IndexMap>, - pub aliases: AliasMap, pub plugins: IndexMap>, pub env: IndexMap, + pub aliases: AliasMap, + pub all_aliases: OnceCell, + pub should_exit_early: bool, shorthands: OnceCell>, } @@ -41,8 +43,10 @@ impl Config { let plugins = load_plugins()?; let rtxrc = load_rtxrc()?; let mut settings = rtxrc.settings(); + let config_filenames = load_config_filenames(&IndexMap::new()); let config_files = load_all_config_files( &settings.build(), + &config_filenames, &plugins, &IndexMap::new(), IndexMap::new(), @@ -51,20 +55,35 @@ impl Config { settings.merge(cf.settings()); } let settings = settings.build(); + trace!("Settings: {:#?}", rtxrc.settings()); + let legacy_files = load_legacy_files(&settings, &plugins); - let config_files = load_all_config_files(&settings, &plugins, &legacy_files, config_files); - let env = load_env(&config_files); - let aliases = load_aliases(&settings, &plugins, &config_files); + let config_filenames = load_config_filenames(&legacy_files); + + let (config_files, should_exit_early) = rayon::join( + || { + load_all_config_files( + &settings, + &config_filenames, + &plugins, + &legacy_files, + config_files, + ) + }, + || hook_env::should_exit_early(&config_filenames), + ); let config = Self { + env: load_env(&config_files), + aliases: load_aliases(&settings, &config_files), + all_aliases: OnceCell::new(), + shorthands: OnceCell::new(), + config_files, settings, legacy_files, - config_files, - aliases, rtxrc, plugins, - env, - shorthands: OnceCell::new(), + should_exit_early, }; debug!("{}", &config); @@ -77,9 +96,51 @@ impl Config { .get_or_init(|| get_shorthands(&self.settings)) } + pub fn get_all_aliases(&self) -> &AliasMap { + self.all_aliases.get_or_init(|| self.load_all_aliases()) + } + pub fn is_activated(&self) -> bool { env::var("__RTX_DIFF").is_ok() } + + fn load_all_aliases(&self) -> AliasMap { + let mut aliases: AliasMap = self.aliases.clone(); + let plugin_aliases: Vec<_> = self + .plugins + .values() + .par_bridge() + .map(|plugin| { + let aliases = match plugin.get_aliases(&self.settings) { + Ok(aliases) => aliases, + Err(err) => { + eprintln!("Error: {err}"); + IndexMap::new() + } + }; + (&plugin.name, aliases) + }) + .collect(); + for (plugin, plugin_aliases) in plugin_aliases { + for (from, to) in plugin_aliases { + aliases + .entry(plugin.clone()) + .or_insert_with(IndexMap::new) + .insert(from, to); + } + } + + for (plugin, plugin_aliases) in &self.aliases { + for (from, to) in plugin_aliases { + aliases + .entry(plugin.clone()) + .or_insert_with(IndexMap::new) + .insert(from.clone(), to.clone()); + } + } + + aliases + } } fn load_rtxrc() -> Result { @@ -88,10 +149,7 @@ fn load_rtxrc() -> Result { trace!("settings does not exist {:?}", settings_path); RTXFile::init(&settings_path) } else { - let rtxrc = RTXFile::from_file(&settings_path) - .wrap_err_with(|| err_load_settings(&settings_path))?; - trace!("Settings: {:#?}", rtxrc.settings()); - rtxrc + RTXFile::from_file(&settings_path).wrap_err_with(|| err_load_settings(&settings_path))? }; Ok(rtxrc) @@ -137,12 +195,7 @@ fn load_legacy_files( .collect() } -fn load_all_config_files( - settings: &Settings, - plugins: &IndexMap>, - legacy_filenames: &IndexMap, - mut existing: IndexMap>, -) -> IndexMap> { +fn load_config_filenames(legacy_filenames: &IndexMap) -> Vec { let mut filenames = vec![ env::RTX_DEFAULT_CONFIG_FILENAME.as_str(), env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str(), @@ -159,10 +212,20 @@ fn load_all_config_files( config_files.push(home_config); } - config_files - .into_iter() + config_files.into_iter().unique().collect() +} + +fn load_all_config_files( + settings: &Settings, + config_filenames: &[PathBuf], + plugins: &IndexMap>, + legacy_filenames: &IndexMap, + mut existing: IndexMap>, +) -> IndexMap> { + config_filenames + .iter() .unique() - .map(|f| (f.clone(), existing.shift_remove(&f))) + .map(|f| (f.clone(), existing.shift_remove(f))) .collect_vec() .into_par_iter() .map(|(f, existing)| match existing { @@ -206,30 +269,16 @@ fn load_env(config_files: &IndexMap>) -> IndexMap>, config_files: &IndexMap>, ) -> AliasMap { let mut aliases: AliasMap = IndexMap::new(); - let plugin_aliases: Vec<_> = plugins - .values() - .par_bridge() - .map(|plugin| { - let aliases = match plugin.get_aliases(settings) { - Ok(aliases) => aliases, - Err(err) => { - eprintln!("Error: {err}"); - IndexMap::new() - } - }; - (&plugin.name, aliases) - }) - .collect(); - for (plugin, plugin_aliases) in plugin_aliases { + + for (plugin, plugin_aliases) in &settings.aliases { for (from, to) in plugin_aliases { aliases .entry(plugin.clone()) .or_insert_with(IndexMap::new) - .insert(from, to); + .insert(from.clone(), to.clone()); } } @@ -244,15 +293,6 @@ fn load_aliases( } } - for (plugin, plugin_aliases) in &settings.aliases { - for (from, to) in plugin_aliases { - aliases - .entry(plugin.clone()) - .or_insert_with(IndexMap::new) - .insert(from.clone(), to.clone()); - } - } - aliases } diff --git a/src/env.rs b/src/env.rs index 0798de656..5f77e9b87 100644 --- a/src/env.rs +++ b/src/env.rs @@ -131,6 +131,7 @@ lazy_static! { pub static ref RTX_SHIMS_DIR: Option = var_path("RTX_SHIMS_DIR"); pub static ref RTX_RAW: bool = var_is_true("RTX_RAW"); pub static ref GITHUB_API_TOKEN: Option = var("GITHUB_API_TOKEN").ok(); + pub static ref PRELOAD_ENV: bool = is_cmd("hook-env") || is_cmd("env") || is_cmd("exec"); } fn get_env_diff() -> EnvDiff { @@ -225,6 +226,14 @@ fn prefer_stale(args: &[String]) -> bool { false } +// returns true if the subcommand to rtx is this value +fn is_cmd(cmd: &str) -> bool { + if let Some(c) = ARGS.get(1) { + return c == cmd; + } + false +} + #[cfg(test)] mod tests { use std::collections::HashMap; diff --git a/src/errors.rs b/src/errors.rs index b86e6e1b1..eeeca7ed5 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -13,8 +13,8 @@ pub enum Error { #[error("{0}@{1} not found")] #[allow(dead_code)] VersionNotFound(PluginName, String), - #[error("[{}] script exited with non-zero status: {}", .0, render_exit_status(.1))] - ScriptFailed(PluginName, Option), + #[error("{} exited with non-zero status: {}", .0, render_exit_status(.1))] + ScriptFailed(String, Option), } fn render_exit_status(exit_status: &Option) -> String { diff --git a/src/file.rs b/src/file.rs index 65a702007..1932e4262 100644 --- a/src/file.rs +++ b/src/file.rs @@ -7,6 +7,22 @@ use filetime::{set_file_times, FileTime}; use crate::dirs; +pub fn remove_dir_all>(path: P) -> io::Result<()> { + let path = path.as_ref(); + if path.exists() { + trace!("rm -rf {}", path.display()); + std::fs::remove_dir_all(path)?; + } + Ok(()) +} + +pub fn create_dir_all>(path: P) -> io::Result<()> { + let path = path.as_ref(); + trace!("mkdir -p {}", path.display()); + std::fs::create_dir_all(path)?; + Ok(()) +} + pub fn basename(path: &Path) -> Option { path.file_name().map(|f| f.to_string_lossy().to_string()) } @@ -21,6 +37,7 @@ pub fn display_path(path: &Path) -> String { } pub fn touch_dir(dir: &Path) -> io::Result<()> { + trace!("touch {}", dir.display()); let now = FileTime::now(); set_file_times(dir, now, now) } @@ -68,7 +85,7 @@ pub fn dir_subdirs(dir: &Path) -> Result> { pub fn dir_files(dir: &Path) -> Result> { let mut output = vec![]; - if !dir.exists() { + if !dir.is_dir() { return Ok(output); } diff --git a/src/hook_env.rs b/src/hook_env.rs index 083e977e6..cd214ecef 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -10,18 +10,17 @@ use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; -use crate::config::Config; use crate::env_diff::{EnvDiffOperation, EnvDiffPatches}; use crate::shell::Shell; use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being /// called and it does not need to be -pub fn should_exit_early(config: &Config) -> bool { +pub fn should_exit_early(config_filenames: &[PathBuf]) -> bool { if env::ARGS.len() < 2 || env::ARGS[1] != "hook-env" { return false; } - let watch_files = get_watch_files(config); + let watch_files = get_watch_files(config_filenames); if have_config_files_been_modified(&env::vars().collect(), watch_files) { return false; } @@ -90,6 +89,52 @@ pub fn deserialize_watches(raw: String) -> Result { Ok(rmp_serde::from_slice(&writer[..])?) } +pub fn build_watches(config_filenames: &[PathBuf]) -> Result { + let mut watches = HookEnvWatches::new(); + for cf in get_watch_files(config_filenames) { + watches.insert(cf.clone(), cf.metadata()?.modified()?); + } + + Ok(watches) +} + +pub fn get_watch_files(config_filenames: &[PathBuf]) -> HashSet { + let mut watches = HashSet::new(); + if dirs::ROOT.exists() { + watches.insert(dirs::ROOT.clone()); + } + for cf in config_filenames { + watches.insert(cf.clone()); + } + + watches +} + +pub fn clear_old_env(shell: &dyn Shell) -> String { + let mut patches = env::__RTX_DIFF.reverse().to_patches(); + if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { + patches.push(EnvDiffOperation::Change("PATH".into(), path.to_string())); + } + build_env_commands(shell, &patches) +} + +pub fn build_env_commands(shell: &dyn Shell, patches: &EnvDiffPatches) -> String { + let mut output = String::new(); + + for patch in patches.iter() { + match patch { + EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { + output.push_str(&shell.set_env(k, v)); + } + EnvDiffOperation::Remove(k) => { + output.push_str(&shell.unset_env(k)); + } + } + } + + output +} + #[cfg(test)] mod tests { use std::time::UNIX_EPOCH; @@ -140,49 +185,3 @@ mod tests { ); } } - -pub fn build_watches(config: &Config) -> Result { - let mut watches = HookEnvWatches::new(); - for cf in get_watch_files(config) { - watches.insert(cf.clone(), cf.metadata()?.modified()?); - } - - Ok(watches) -} - -pub fn get_watch_files(config: &Config) -> HashSet { - let mut watches = HashSet::new(); - if dirs::ROOT.exists() { - watches.insert(dirs::ROOT.clone()); - } - for cf in config.config_files.keys() { - watches.insert(cf.clone()); - } - - watches -} - -pub fn clear_old_env(shell: &dyn Shell) -> String { - let mut patches = env::__RTX_DIFF.reverse().to_patches(); - if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { - patches.push(EnvDiffOperation::Change("PATH".into(), path.to_string())); - } - build_env_commands(shell, &patches) -} - -pub fn build_env_commands(shell: &dyn Shell, patches: &EnvDiffPatches) -> String { - let mut output = String::new(); - - for patch in patches.iter() { - match patch { - EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { - output.push_str(&shell.set_env(k, v)); - } - EnvDiffOperation::Remove(k) => { - output.push_str(&shell.unset_env(k)); - } - } - } - - output -} diff --git a/src/main.rs b/src/main.rs index ce9aba0d3..852710146 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,11 @@ extern crate core; #[macro_use] extern crate log; +use std::process::exit; + use color_eyre::eyre::Result; -use color_eyre::{Help, SectionExt}; -use console::Term; +use color_eyre::{Help, Report, SectionExt}; +use console::{style, Term}; use crate::cli::version::VERSION; use crate::cli::Cli; @@ -52,11 +54,14 @@ fn main() -> Result<()> { logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); handle_ctrlc(); - let mut result = run(&env::ARGS).with_section(|| VERSION.to_string().header("Version:")); - if log_level < log::LevelFilter::Debug { - result = result.with_suggestion(|| "Run with RTX_DEBUG=1 for more information.".to_string()) + match run(&env::ARGS).with_section(|| VERSION.to_string().header("Version:")) { + Ok(()) => Ok(()), + Err(err) if log_level < log::LevelFilter::Debug => { + display_friendly_err(err); + exit(1); + } + Err(err) => Err(err).suggestion("Run with RTX_DEBUG=1 for more information."), } - result } fn run(args: &Vec) -> Result<()> { @@ -67,10 +72,10 @@ fn run(args: &Vec) -> Result<()> { let config = Config::load()?; let config = shims::handle_shim(config, args, out)?; - if hook_env::should_exit_early(&config) { + if config.should_exit_early { return Ok(()); } - let cli = Cli::new_with_external_commands(&config)?; + let cli = Cli::new_with_external_commands(&config); cli.run(config, args, out) } @@ -78,7 +83,18 @@ fn handle_ctrlc() { ctrlc::set_handler(move || { let _ = Term::stderr().show_cursor(); debug!("Ctrl-C pressed, exiting..."); - std::process::exit(1); + exit(1); }) .expect("Error setting Ctrl-C handler"); } + +fn display_friendly_err(err: Report) { + let dim = |s| style(s).dim().for_stderr(); + let dim_red = |s| style(s).dim().red().for_stderr(); + eprintln!("{} {}", dim_red("rtx"), err); + eprintln!( + "{} {}", + dim_red("rtx"), + dim("Run with RTX_DEBUG=1 for more information") + ); +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 56b612f35..95c086bbe 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -7,10 +7,9 @@ use color_eyre::eyre::WrapErr; use color_eyre::eyre::{eyre, Result}; use console::style; use indexmap::IndexMap; -use indicatif::ProgressStyle; + use itertools::Itertools; -use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; @@ -21,10 +20,11 @@ use crate::cmd::cmd; use crate::config::{Config, Settings}; use crate::env::RTX_PREFER_STALE; use crate::errors::Error::PluginNotInstalled; +use crate::file::remove_dir_all; use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::script_manager::Script::ParseLegacyFile; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; use crate::{dirs, file}; mod script_manager; @@ -59,20 +59,16 @@ impl Plugin { script_man: ScriptManager::new(plugin_path.clone()), downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), - remote_version_cache: CacheManager::new( - cache_path.join("remote_versions.msgpack.zlib"), - ) - .with_fresh_duration(fresh_duration) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-all")), - alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.zlib")) + remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) + .with_fresh_duration(fresh_duration) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-all")), + alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.z")) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-aliases")), - legacy_filename_cache: CacheManager::new( - cache_path.join("legacy_filenames.msgpack.zlib"), - ) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), + legacy_filename_cache: CacheManager::new(cache_path.join("legacy_filenames.msgpack.z")) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), plugin_path, cache_path, } @@ -98,26 +94,15 @@ impl Plugin { &self, config: &Config, repository: Option<&String>, - mut pr: ProgressReport, + pr: &mut ProgressReport, ) -> Result<()> { - static PROG_TEMPLATE: Lazy = Lazy::new(|| { - ProgressStyle::with_template("{prefix}{wide_msg} {spinner:.blue} {elapsed:.dim.italic}") - .unwrap() - }); - pr.set_style(PROG_TEMPLATE.clone()); - pr.set_prefix(format!( - "{} {} ", - style("rtx").dim().for_stderr(), - style(&self.name).cyan().for_stderr() - )); - pr.enable_steady_tick(); + self.decorate_progress_bar(pr); let repository = repository .or_else(|| config.get_shorthands().get(&self.name)) .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; debug!("install {} {:?}", self.name, repository); if self.is_installed() { - pr.set_message("uninstalling existing plugin".into()); - self.uninstall()?; + self.uninstall(pr)?; } let git = Git::new(self.plugin_path.to_path_buf()); @@ -139,8 +124,7 @@ impl Plugin { let sha = git.current_sha_short()?; pr.finish_with_message(format!( - "{} {repository}@{}", - style("✓").green().for_stderr(), + "{repository}@{}", style(&sha).bright().yellow().for_stderr(), )); Ok(()) @@ -169,14 +153,18 @@ impl Plugin { Ok(()) } - pub fn uninstall(&self) -> Result<()> { - debug!("uninstall {}", self.name); + pub fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + if !self.is_installed() { + return Ok(()); + } + pr.set_message("uninstalling".into()); let rmdir = |dir: &Path| { if !dir.exists() { return Ok(()); } - fs::remove_dir_all(dir).wrap_err_with(|| { + pr.set_message(format!("removing {}", &dir.to_string_lossy())); + remove_dir_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", style(&dir.to_string_lossy()).cyan().for_stderr() @@ -238,6 +226,12 @@ impl Plugin { pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) + .with_context(|| { + format!( + "Failed listing remote versions for plugin {}", + style(&self.name).cyan().for_stderr() + ) + }) } pub fn get_aliases(&self, settings: &Settings) -> Result> { @@ -246,7 +240,13 @@ impl Plugin { } let aliases = self .alias_cache - .get_or_try_init(|| self.fetch_aliases(settings))? + .get_or_try_init(|| self.fetch_aliases(settings)) + .with_context(|| { + format!( + "Failed fetching aliases for plugin {}", + style(&self.name).cyan().for_stderr() + ) + })? .iter() .map(|(k, v)| (k.to_string(), v.to_string())) .collect(); @@ -259,6 +259,12 @@ impl Plugin { } self.legacy_filename_cache .get_or_try_init(|| self.fetch_legacy_filenames(settings)) + .with_context(|| { + format!( + "Failed fetching legacy filenames for plugin {}", + style(&self.name).cyan().for_stderr() + ) + }) .cloned() } @@ -301,10 +307,20 @@ impl Plugin { exit(result.status.code().unwrap_or(1)); } + pub fn decorate_progress_bar(&self, pr: &mut ProgressReport) { + pr.set_style(PROG_TEMPLATE.clone()); + pr.set_prefix(format!( + "{} {} ", + style("rtx").dim().for_stderr(), + style(&self.name).cyan().for_stderr() + )); + pr.enable_steady_tick(); + } + fn fetch_remote_versions(&self, settings: &Settings) -> Result> { let result = self .script_man - .cmd(settings, Script::ListAll) + .cmd(settings, &Script::ListAll) .stdout_capture() .stderr_capture() .unchecked() @@ -322,11 +338,11 @@ impl Plugin { } }; if !result.status.success() { - display_stderr(); return Err(eyre!( - "error running {}: exited with code {}", + "error running {}: exited with code {}\n{}", Script::ListAll, - result.status.code().unwrap_or_default() + result.status.code().unwrap_or_default(), + stderr ))?; } else if settings.verbose { display_stderr(); @@ -338,7 +354,7 @@ impl Plugin { fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { Ok(self .script_man - .read(settings, Script::ListLegacyFilenames, settings.verbose)? + .read(settings, &Script::ListLegacyFilenames, settings.verbose)? .split_whitespace() .map(|v| v.into()) .collect()) @@ -356,7 +372,7 @@ impl Plugin { fn fetch_aliases(&self, settings: &Settings) -> Result> { let stdout = self .script_man - .read(settings, Script::ListAliases, settings.verbose)?; + .read(settings, &Script::ListAliases, settings.verbose)?; let aliases = stdout .lines() .filter_map(|line| { @@ -381,7 +397,7 @@ impl Plugin { trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); let legacy_version = match self.script_man.script_exists(&script) { - true => self.script_man.read(settings, script, settings.verbose)?, + true => self.script_man.read(settings, &script, settings.verbose)?, false => fs::read_to_string(legacy_file)?, } .trim() diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 29bd370d9..46ff8788a 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -14,7 +14,7 @@ use crate::cmd::cmd; use crate::config::Settings; use crate::env; use crate::errors::Error::ScriptFailed; -use crate::file::basename; +use crate::file::{basename, display_path}; #[derive(Debug, Clone)] pub struct ScriptManager { @@ -41,7 +41,7 @@ pub enum Script { Install, Uninstall, ListBinPaths, - // ExecEnv, + ExecEnv, } impl Display for Script { @@ -57,7 +57,7 @@ impl Display for Script { Script::Install => write!(f, "install"), Script::Uninstall => write!(f, "uninstall"), Script::ListBinPaths => write!(f, "list-bin-paths"), - // Script::ExecEnv => write!(f, "exec-env"), + Script::ExecEnv => write!(f, "exec-env"), Script::Download => write!(f, "download"), } } @@ -102,12 +102,12 @@ impl ScriptManager { self.get_script_path(script).is_file() } - pub fn cmd(&self, settings: &Settings, script: Script) -> Expression { - let args = match &script { + pub fn cmd(&self, settings: &Settings, script: &Script) -> Expression { + let args = match script { Script::ParseLegacyFile(filename) => vec![filename.clone()], _ => vec![], }; - let script_path = self.get_script_path(&script); + let script_path = self.get_script_path(script); // if !script_path.exists() { // return Err(PluginNotInstalled(self.plugin_name.clone()).into()); // } @@ -122,29 +122,31 @@ impl ScriptManager { cmd } - pub fn run(&self, settings: &Settings, script: Script) -> Result<()> { + pub fn run(&self, settings: &Settings, script: &Script) -> Result<()> { let cmd = self.cmd(settings, script); let Output { status, .. } = cmd.unchecked().run()?; match status.success() { true => Ok(()), - false => Err(ScriptFailed(self.plugin_name.clone(), Some(status)).into()), + false => { + Err(ScriptFailed(display_path(&self.get_script_path(script)), Some(status)).into()) + } } } - pub fn read(&self, settings: &Settings, script: Script, verbose: bool) -> Result { + pub fn read(&self, settings: &Settings, script: &Script, verbose: bool) -> Result { let mut cmd = self.cmd(settings, script); if !verbose && !settings.raw { cmd = cmd.stderr_null(); } cmd.read() - .with_context(|| ScriptFailed(self.plugin_name.clone(), None)) + .with_context(|| ScriptFailed(display_path(&self.get_script_path(script)), None)) } pub fn run_by_line( &self, settings: &Settings, - script: Script, + script: &Script, on_error: F1, on_output: F2, ) -> Result<()> @@ -160,7 +162,10 @@ impl ScriptManager { true => Ok(()), false => { on_error(output.join("\n")); - Err(ScriptFailed(self.plugin_name.clone(), Some(status)).into()) + Err( + ScriptFailed(display_path(&self.get_script_path(script)), Some(status)) + .into(), + ) } } } else { @@ -181,7 +186,10 @@ impl ScriptManager { true => Ok(()), false => { on_error(output.join("\n")); - let err = ScriptFailed(self.plugin_name.clone(), Some(out.unwrap().status)); + let err = ScriptFailed( + display_path(&self.get_script_path(script)), + Some(out.unwrap().status), + ); Err(err)? } }, diff --git a/src/runtimes.rs b/src/runtimes.rs index 13355dc5d..1b89c956a 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -1,27 +1,25 @@ use std::collections::HashMap; use std::env::split_paths; use std::fmt::{Display, Formatter}; -use std::fs::{create_dir_all, remove_dir_all, File}; +use std::fs::File; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{fmt, fs}; use color_eyre::eyre::{Result, WrapErr}; use console::style; -use indicatif::ProgressStyle; -use itertools::Itertools; use once_cell::sync::Lazy; -use once_cell::sync::OnceCell; use crate::cache::CacheManager; use crate::config::Config; use crate::config::Settings; use crate::env_diff::{EnvDiff, EnvDiffOperation}; +use crate::file::{create_dir_all, display_path, remove_dir_all}; use crate::hash::hash_to_str; -use crate::plugins::Script::{Download, Install}; +use crate::plugins::Script::{Download, ExecEnv, Install}; use crate::plugins::{Plugin, Script, ScriptManager}; use crate::toolset::{ToolVersion, ToolVersionType}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; use crate::{dirs, env, fake_asdf, file}; /// These represent individual plugin@version pairs of runtimes @@ -34,8 +32,8 @@ pub struct RuntimeVersion { download_path: PathBuf, cache_path: PathBuf, script_man: ScriptManager, - bin_paths_cache: CacheManager>, - exec_env_cache: Box>>, + bin_paths_cache: CacheManager>, + exec_env_cache: CacheManager>, } impl RuntimeVersion { @@ -52,6 +50,16 @@ impl RuntimeVersion { ToolVersionType::Path(p) => dirs::CACHE.join(&plugin.name).join(hash_to_str(&p)), _ => dirs::CACHE.join(&plugin.name).join(&version), }; + let mut bin_paths_cache = CacheManager::new(cache_path.join("bin_paths.msgpack.z")) + .with_fresh_file(install_path.clone()); + let mut exec_env_cache = CacheManager::new(cache_path.join("exec_env.msgpack.z")) + .with_fresh_file(install_path.clone()); + if plugin.name == "python" && tv.options.contains_key("virtualenv") { + // TODO: remove this for a better solution + // this is required for the virtualenv feature to work + bin_paths_cache = bin_paths_cache.with_no_cache(); + exec_env_cache = exec_env_cache.with_no_cache(); + } Self { script_man: build_script_man( &tv, @@ -60,33 +68,20 @@ impl RuntimeVersion { &install_path, &download_path, ), - bin_paths_cache: CacheManager::new(cache_path.join("bin_paths.msgpack.zlib")) - .with_fresh_file(install_path.clone()), + bin_paths_cache, + exec_env_cache, cache_path, download_path, install_path, version, plugin, - exec_env_cache: Box::new(OnceCell::new()), } } - pub fn install(&self, config: &Config, mut pr: ProgressReport) -> Result<()> { - static PROG_TEMPLATE: Lazy = Lazy::new(|| { - ProgressStyle::with_template("{prefix}{wide_msg} {spinner:.blue} {elapsed:.dim.italic}") - .unwrap() - }); - pr.set_style(PROG_TEMPLATE.clone()); - pr.set_prefix(format!( - "{} {} ", - style("rtx").dim().for_stderr(), - style(&self.to_string()).cyan().for_stderr() - )); - pr.enable_steady_tick(); + pub fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { + self.decorate_progress_bar(pr); let settings = &config.settings; - debug!("install {}", self); - self.create_install_dirs()?; let run_script = |script| { @@ -95,7 +90,7 @@ impl RuntimeVersion { script, |output| { self.cleanup_install_dirs_on_error(settings); - pr.finish_with_message(format!("error {}", style("✗").red().for_stderr())); + pr.error(); if !settings.verbose && !output.trim().is_empty() { pr.println(output); } @@ -110,10 +105,10 @@ impl RuntimeVersion { if self.script_man.script_exists(&Download) { pr.set_message("downloading".into()); - run_script(Download)?; + run_script(&Download)?; } pr.set_message("installing".into()); - run_script(Install)?; + run_script(&Install)?; self.cleanup_install_dirs(settings); // attempt to touch all the .tool-version files to trigger updates in hook-env @@ -128,22 +123,21 @@ impl RuntimeVersion { if let Err(err) = fs::remove_file(self.incomplete_file_path()) { debug!("error removing incomplete file: {:?}", err); } - pr.finish_with_message(style("✓").green().for_stderr().to_string()); + pr.finish(); Ok(()) } pub fn list_bin_paths(&self, settings: &Settings) -> Result> { - let mut bin_paths = self.list_exec_env_bin_paths()?; - - bin_paths.extend( - self.bin_paths_cache - .get_or_try_init(|| self.fetch_bin_paths(settings))? - .iter() - .map(|path| self.install_path.join(path)) - .collect_vec(), + let (a, b) = rayon::join( + || self.list_exec_env_bin_paths(), + || { + self.bin_paths_cache + .get_or_try_init(|| self.fetch_bin_paths(settings)) + }, ); - + let mut bin_paths = a?; + bin_paths.extend(b?.clone()); Ok(bin_paths) } @@ -174,18 +168,17 @@ impl RuntimeVersion { } } - pub fn uninstall(&self, settings: &Settings) -> Result<()> { - debug!("uninstall {} {}", self.plugin.name, self.version); + pub fn uninstall(&self, settings: &Settings, pr: &ProgressReport) -> Result<()> { + pr.set_message(format!("uninstall {}", self)); + if self.plugin.plugin_path.join("bin/uninstall").exists() { - let err = self.script_man.run(settings, Script::Uninstall); - if err.is_err() { - warn!("Failed to run uninstall script: {}", err.unwrap_err()); - } + self.script_man.run(settings, &Script::Uninstall)?; } let rmdir = |dir: &Path| { if !dir.exists() { return Ok(()); } + pr.set_message(format!("removing {}", display_path(dir))); remove_dir_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", @@ -194,19 +187,16 @@ impl RuntimeVersion { }) }; rmdir(&self.install_path)?; - let err = rmdir(&self.download_path); - if err.is_err() { - warn!("Failed to remove download directory: {}", err.unwrap_err()); - } + rmdir(&self.download_path)?; Ok(()) } pub fn exec_env(&self) -> Result<&HashMap> { + if !self.script_man.script_exists(&ExecEnv) { + return Ok(&*EMPTY_HASH_MAP); + } self.exec_env_cache.get_or_try_init(|| { - let script = self.plugin.plugin_path.join("bin/exec-env"); - if !self.is_installed() || !script.exists() { - return Ok(HashMap::new()); - } + let script = self.script_man.get_script_path(&ExecEnv); let ed = EnvDiff::from_bash_script(&script, &self.script_man.env)?; let env = ed .to_patches() @@ -221,14 +211,22 @@ impl RuntimeVersion { }) } - fn fetch_bin_paths(&self, settings: &Settings) -> Result> { + fn fetch_bin_paths(&self, settings: &Settings) -> Result> { let list_bin_paths = self.plugin.plugin_path.join("bin/list-bin-paths"); - if list_bin_paths.exists() { - let output = self.script_man.cmd(settings, Script::ListBinPaths).read()?; - Ok(output.split_whitespace().map(|e| e.into()).collect()) + let bin_paths = if list_bin_paths.exists() { + let output = self + .script_man + .cmd(settings, &Script::ListBinPaths) + .read()?; + output.split_whitespace().map(|f| f.to_string()).collect() } else { - Ok(vec!["bin".into()]) - } + vec!["bin".into()] + }; + let bin_paths = bin_paths + .into_iter() + .map(|path| self.install_path.join(path)) + .collect(); + Ok(bin_paths) } fn create_install_dirs(&self) -> Result<()> { @@ -255,6 +253,16 @@ impl RuntimeVersion { fn incomplete_file_path(&self) -> PathBuf { self.cache_path.join("incomplete") } + + pub fn decorate_progress_bar(&self, pr: &mut ProgressReport) { + pr.set_style(PROG_TEMPLATE.clone()); + pr.set_prefix(format!( + "{} {} ", + style("rtx").dim().for_stderr(), + style(&self.to_string()).cyan().for_stderr() + )); + pr.enable_steady_tick(); + } } impl Display for RuntimeVersion { @@ -302,3 +310,5 @@ fn build_script_man( _ => sm, } } + +static EMPTY_HASH_MAP: Lazy> = Lazy::new(HashMap::new); diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index b542e5462..65ab1d671 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,8 +1,7 @@ use indexmap::IndexMap; use itertools::Itertools; -use rayon::prelude::*; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; +use crate::cli::args::runtime::RuntimeArg; use crate::config::Config; use crate::env; use crate::toolset::tool_version::ToolVersionType; @@ -40,7 +39,7 @@ impl ToolsetBuilder { toolset.resolve(config); if self.install_missing { - if let Err(e) = toolset.install_missing(config) { + if let Err(e) = toolset.install_missing(config, None) { warn!("Error installing runtimes: {}", e); }; } @@ -51,16 +50,8 @@ impl ToolsetBuilder { } fn load_config_files(config: &Config, ts: &mut Toolset) { - let toolsets: Vec<_> = config - .config_files - .values() - .collect_vec() - .into_par_iter() - .rev() - .map(|cf| cf.to_toolset()) - .collect(); - for toolset in toolsets { - ts.merge(toolset); + for cf in config.config_files.values().rev() { + ts.merge(cf.to_toolset()); } } @@ -72,7 +63,7 @@ fn load_runtime_env(ts: &mut Toolset, env: IndexMap) { let mut env_ts = Toolset::new(source); let version = ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v)); env_ts.add_version(plugin_name, version); - ts.merge(env_ts); + ts.merge(&env_ts); } } } @@ -81,36 +72,10 @@ fn load_runtime_args(ts: &mut Toolset, args: &[RuntimeArg]) { for (plugin_name, args) in args.iter().into_group_map_by(|arg| arg.plugin.clone()) { let mut arg_ts = Toolset::new(ToolSource::Argument); for arg in args { - match arg.version { - RuntimeArgVersion::Version(ref v) => { - let version = - ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v.clone())); - arg_ts.add_version(plugin_name.clone(), version); - } - RuntimeArgVersion::Ref(ref v) => { - let version = - ToolVersion::new(plugin_name.clone(), ToolVersionType::Ref(v.clone())); - arg_ts.add_version(plugin_name.clone(), version); - } - RuntimeArgVersion::Path(ref v) => { - let version = - ToolVersion::new(plugin_name.clone(), ToolVersionType::Path(v.clone())); - arg_ts.add_version(plugin_name.clone(), version); - } - RuntimeArgVersion::Prefix(ref v) => { - let version = - ToolVersion::new(plugin_name.clone(), ToolVersionType::Prefix(v.clone())); - arg_ts.add_version(plugin_name.clone(), version); - } - // I believe this will do nothing since it would just default to the `.tool-versions` version - // RuntimeArgVersion::None => { - // arg_ts.add_version(plugin_name.clone(), ToolVersion::None); - // }, - _ => { - trace!("ignoring: {:?}", arg); - } + if let Some(version) = arg.to_tool_version() { + arg_ts.add_version(plugin_name.clone(), version); } } - ts.merge(arg_ts); + ts.merge(&arg_ts); } } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 2c7293dda..fcfb267cd 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -36,11 +36,12 @@ mod tool_version_list; /// one example is a .tool-versions file /// the idea is that we start with an empty toolset, then /// merge in other toolsets from various sources -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default)] pub struct Toolset { pub versions: IndexMap, source: Option, plugins: IndexMap>, + mpr: Option, } impl Toolset { @@ -61,14 +62,15 @@ impl Toolset { .or_insert_with(|| ToolVersionList::new(self.source.clone().unwrap())); versions.add_version(version); } - pub fn merge(&mut self, mut other: Toolset) { - for (plugin, versions) in self.versions.clone() { + pub fn merge(&mut self, other: &Toolset) { + let mut versions = other.versions.clone(); + for (plugin, tvl) in self.versions.clone() { if !other.versions.contains_key(&plugin) { - other.versions.insert(plugin, versions); + versions.insert(plugin, tvl); } } - self.versions = other.versions; // swap to use other's first - self.source = other.source; + self.versions = versions; + self.source = other.source.clone(); } pub fn resolve(&mut self, config: &Config) { self.versions @@ -83,10 +85,14 @@ impl Toolset { return; } }; - v.resolve(&config.settings, plugin.clone()); + v.resolve(config, plugin.clone()); }); } - pub fn install_missing(&mut self, config: &Config) -> Result<()> { + pub fn install_missing( + &mut self, + config: &Config, + mpr: Option, + ) -> Result<()> { let versions = self.list_missing_versions(); if versions.is_empty() { return Ok(()); @@ -109,11 +115,11 @@ impl Toolset { if versions.is_empty() { warn(); } else { - self.install_missing_versions(config, versions)?; + self.install_missing_versions(config, versions, mpr)?; } } MissingRuntimeBehavior::AutoInstall => { - self.install_missing_versions(config, versions)?; + self.install_missing_versions(config, versions, mpr)?; } } Ok(()) @@ -131,13 +137,14 @@ impl Toolset { &mut self, config: &Config, selected_versions: Vec, + mpr: Option, ) -> Result<()> { ThreadPoolBuilder::new() .num_threads(config.settings.jobs) - .build() - .unwrap() + .build()? .install(|| -> Result<()> { - let mpr = MultiProgressReport::new(config.settings.verbose); + self.mpr = + Some(mpr.unwrap_or_else(|| MultiProgressReport::new(config.settings.verbose))); let plugins = selected_versions .iter() .map(|v| v.plugin_name.clone()) @@ -147,7 +154,7 @@ impl Toolset { .into_iter() .map(|v| v.r#type) .collect::>(); - self.install_missing_plugins(config, &mpr, plugins)?; + self.install_missing_plugins(config, plugins)?; self.versions .iter_mut() .par_bridge() @@ -165,19 +172,20 @@ impl Toolset { }) .map(|(plugin, versions)| { for version in versions { - version.resolve(&config.settings, plugin.clone())?; - version.install(config, mpr.add())?; + let mut pr = self.mpr.as_ref().unwrap().add(); + version.resolve(config, plugin.clone())?; + version.install(config, &mut pr)?; } Ok(()) }) .collect::>>()?; + self.mpr = None; Ok(()) }) } fn install_missing_plugins( &mut self, config: &Config, - mpr: &MultiProgressReport, missing_plugins: Vec, ) -> Result<()> { if missing_plugins.is_empty() { @@ -188,7 +196,7 @@ impl Toolset { .map(|plugin_name| { let plugin = Plugin::new(&plugin_name); if !plugin.is_installed() { - plugin.install(config, None, mpr.add())?; + plugin.install(config, None, &mut self.mpr.as_ref().unwrap().add())?; } Ok(plugin) }) @@ -200,7 +208,7 @@ impl Toolset { Ok(()) } - fn list_missing_versions(&self) -> Vec { + pub fn list_missing_versions(&self) -> Vec { let versions = self .versions .values() @@ -257,6 +265,12 @@ impl Toolset { .filter(|v| v.is_installed()) .collect() } + pub fn env_with_path(&self, config: &Config) -> IndexMap { + let (mut env, path_env) = + rayon::join(|| self.env(config), || self.path_env(&config.settings)); + env.insert("PATH".to_string(), path_env); + env + } pub fn env(&self, config: &Config) -> IndexMap { let mut entries: IndexMap = self .list_current_installed_versions() diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 4cc8b06ff..6b9a077c8 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; use indexmap::IndexMap; -use crate::config::{Config, Settings}; +use crate::config::Config; use crate::dirs; use crate::plugins::Plugin; use crate::runtimes::RuntimeVersion; @@ -42,11 +42,11 @@ impl ToolVersion { } } - pub fn resolve(&mut self, settings: &Settings, plugin: Arc) -> Result<()> { + pub fn resolve(&mut self, config: &Config, plugin: Arc) -> Result<()> { if self.rtv.is_none() { self.rtv = match &self.r#type { - ToolVersionType::Version(v) => self.resolve_version(settings, plugin, v)?, - ToolVersionType::Prefix(v) => self.resolve_prefix(settings, plugin, v)?, + ToolVersionType::Version(v) => self.resolve_version(config, plugin, v)?, + ToolVersionType::Prefix(v) => self.resolve_prefix(config, plugin, v)?, ToolVersionType::Ref(r) => self.resolve_ref(plugin, r)?, ToolVersionType::Path(path) => self.resolve_path(plugin, path)?, ToolVersionType::System => None, @@ -57,11 +57,11 @@ impl ToolVersion { fn resolve_version( &self, - settings: &Settings, + config: &Config, plugin: Arc, v: &str, ) -> Result> { - let v = resolve_alias(settings, plugin.clone(), v)?; + let v = resolve_alias(config, plugin.clone(), v)?; match v.split_once(':') { Some(("ref", r)) => { return self.resolve_ref(plugin, r); @@ -70,7 +70,7 @@ impl ToolVersion { return self.resolve_path(plugin, &PathBuf::from(p)); } Some(("prefix", p)) => { - return self.resolve_prefix(settings, plugin, p); + return self.resolve_prefix(config, plugin, p); } _ => (), } @@ -81,22 +81,22 @@ impl ToolVersion { return Ok(Some(rtv)); } - let matches = plugin.list_versions_matching(settings, &v)?; + let matches = plugin.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { let rtv = RuntimeVersion::new(plugin, v, self.clone()); Ok(Some(rtv)) } else { - self.resolve_prefix(settings, plugin, &v) + self.resolve_prefix(config, plugin, &v) } } fn resolve_prefix( &self, - settings: &Settings, + config: &Config, plugin: Arc, prefix: &str, ) -> Result> { - let matches = plugin.list_versions_matching(settings, prefix)?; + let matches = plugin.list_versions_matching(&config.settings, prefix)?; let v = match matches.last() { Some(v) => v, None => prefix, @@ -124,7 +124,7 @@ impl ToolVersion { } } - pub fn install(&mut self, config: &Config, pr: ProgressReport) -> Result<()> { + pub fn install(&mut self, config: &Config, pr: &mut ProgressReport) -> Result<()> { match self.r#type { ToolVersionType::Version(_) | ToolVersionType::Prefix(_) | ToolVersionType::Ref(_) => { self.rtv.as_ref().unwrap().install(config, pr) @@ -152,13 +152,13 @@ impl Display for ToolVersionType { } } -pub fn resolve_alias(settings: &Settings, plugin: Arc, v: &str) -> Result { - if let Some(plugin_aliases) = settings.aliases.get(&plugin.name) { +pub fn resolve_alias(config: &Config, plugin: Arc, v: &str) -> Result { + if let Some(plugin_aliases) = config.aliases.get(&plugin.name) { if let Some(alias) = plugin_aliases.get(v) { return Ok(alias.clone()); } } - if let Some(alias) = plugin.get_aliases(settings)?.get(v) { + if let Some(alias) = plugin.get_aliases(&config.settings)?.get(v) { return Ok(alias.clone()); } Ok(v.to_string()) diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index bb565a8b2..0e3981813 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -1,8 +1,9 @@ -use crate::config::Settings; -use crate::plugins::Plugin; -use crate::runtimes::RuntimeVersion; use std::sync::Arc; +use crate::config::Config; +use crate::env; +use crate::plugins::Plugin; +use crate::runtimes::RuntimeVersion; use crate::toolset::{ToolSource, ToolVersion}; /// represents several versions of a tool for a particular plugin @@ -22,10 +23,24 @@ impl ToolVersionList { pub fn add_version(&mut self, version: ToolVersion) { self.versions.push(version); } - pub fn resolve(&mut self, settings: &Settings, plugin: Arc) { + pub fn resolve(&mut self, config: &Config, plugin: Arc) { for tv in &mut self.versions { - if let Err(err) = tv.resolve(settings, plugin.clone()) { - warn!("failed to resolve tool version: {}", err); + match tv.resolve(config, plugin.clone()) { + Ok(_) => { + if *env::PRELOAD_ENV { + if let Some(rtv) = tv.rtv.as_ref() { + // optimize loading by preloading the rtv + let _ = rayon::join( + || rtv.exec_env(), + || rtv.list_bin_paths(&config.settings), + ); + } + } + } + Err(err) => { + warn!("failed to resolve tool version: {}", err); + return; + } } } } @@ -39,12 +54,13 @@ impl ToolVersionList { #[cfg(test)] mod tests { - use crate::config::Settings; - use crate::plugins::{Plugin, PluginName}; - use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType}; use std::env; use std::sync::Arc; + use crate::config::Config; + use crate::plugins::{Plugin, PluginName}; + use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType}; + #[test] fn test_tool_version_list_failure() { env::set_var("RTX_FAILURE", "1"); @@ -55,7 +71,7 @@ mod tests { plugin.name.to_string(), ToolVersionType::Version("1.0.0".to_string()), )); - tvl.resolve(&Settings::default(), plugin); + tvl.resolve(&Config::default(), plugin); assert_eq!(tvl.resolved_versions().len(), 0); env::remove_var("RTX_FAILURE"); } diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 3f973bf03..c4821adad 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,6 +1,7 @@ use crate::ui::progress_report::ProgressReport; use indicatif::MultiProgress; +#[derive(Debug)] pub struct MultiProgressReport { mp: Option, } @@ -24,6 +25,12 @@ impl MultiProgressReport { None => ProgressReport::new(true), } } + pub fn suspend R, R>(&self, f: F) -> R { + match &self.mp { + Some(mp) => mp.suspend(f), + None => f(), + } + } // pub fn clear(&self) { // match &self.mp { // Some(mp) => { diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 3e924eda9..c99d917be 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,13 +1,36 @@ -use indicatif::ProgressBar; - use std::time::Duration; +use console::style; +use indicatif::{ProgressBar, ProgressStyle}; +use once_cell::sync::Lazy; + #[derive(Debug)] pub struct ProgressReport { pub pb: Option, prefix: String, } +pub static PROG_TEMPLATE: Lazy = Lazy::new(|| { + ProgressStyle::with_template("{prefix}{wide_msg} {spinner:.blue} {elapsed:3.dim.italic}") + .unwrap() +}); + +pub static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { + let tmpl = format!( + "{{prefix}}{{wide_msg}} {} {{elapsed:3.dim.italic}}", + style("✓").bright().green().for_stderr() + ); + ProgressStyle::with_template(tmpl.as_str()).unwrap() +}); + +pub static ERROR_TEMPLATE: Lazy = Lazy::new(|| { + let tmpl = format!( + "{{prefix:.red}}{{wide_msg}} {} {{elapsed:3.dim.italic}}", + style("✗").red().for_stderr() + ); + ProgressStyle::with_template(tmpl.as_str()).unwrap() +}); + impl ProgressReport { pub fn new(verbose: bool) -> ProgressReport { let pb = match verbose { @@ -36,7 +59,7 @@ impl ProgressReport { } } - pub fn set_style(&self, style: indicatif::ProgressStyle) { + pub fn set_style(&self, style: ProgressStyle) { match &self.pb { Some(pb) => { pb.set_style(style); @@ -47,7 +70,7 @@ impl ProgressReport { } pub fn set_message(&self, message: String) { match &self.pb { - Some(pb) => pb.set_message(message), + Some(pb) => pb.set_message(message.replace('\r', "")), None => eprintln!("{}{message}", self.prefix), } } @@ -57,9 +80,30 @@ impl ProgressReport { None => eprintln!("{message}"), } } + pub fn error(&self) { + match &self.pb { + Some(pb) => { + pb.set_style(ERROR_TEMPLATE.clone()); + pb.finish() + } + None => (), + } + } + pub fn finish(&self) { + match &self.pb { + Some(pb) => { + pb.set_style(SUCCESS_TEMPLATE.clone()); + pb.finish() + } + None => (), + } + } pub fn finish_with_message(&self, message: String) { match &self.pb { - Some(pb) => pb.finish_with_message(message), + Some(pb) => { + pb.set_style(SUCCESS_TEMPLATE.clone()); + pb.finish_with_message(message) + } None => eprintln!("{}{message}", self.prefix), } } From 3945c8dffaf95b127c1c9535df8f7425fb882656 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 20:09:45 -0600 Subject: [PATCH 0364/1891] chore: Release rtx-cli version 1.20.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54b99f070..434e08db5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.20.2" +version = "1.20.3" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 90823ad1d..3978d6b5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.20.2" +version = "1.20.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 671f120b5..0a59c7757 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.20.2 +rtx 1.20.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.2/rtx-v1.20.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.3/rtx-v1.20.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 97dcff3dd..ecae90fdb 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.20.2"; + version = "1.20.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index e7ffbf9fb..79d2491b2 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.20.2" +.TH rtx 1 "rtx 1.20.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -129,6 +129,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.20.2 +v1.20.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f529c40ae..a351f870f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.20.2 +Version: 1.20.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 552c27d85cbea71f99a65e5ad30bf6356a8623cc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 2 Mar 2023 20:14:14 -0600 Subject: [PATCH 0365/1891] chore: use node@18 for dev --- .node-version | 2 +- .rtx.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.node-version b/.node-version index d939939b2..aac58983e 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -18.13.0 +17.0.0 diff --git a/.rtx.toml b/.rtx.toml index fac7233b6..29ee34bad 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -2,6 +2,6 @@ FOO = "bar" [tools] -nodejs = '17' +nodejs = '18' tiny = {version="1", foo="bar"} golang = {version="latest", foo="bar"} From cacd366da4ba624e015866e130cc1fbb491af9ad Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 00:01:47 -0600 Subject: [PATCH 0366/1891] editing support for .rtx.toml (#248) --- README.md | 8 +- e2e/test_local | 53 +++++++++++ e2e/test_tool_versions_alt | 1 + src/cli/asdf.rs | 8 +- src/cli/bin_paths.rs | 8 +- src/cli/current.rs | 16 ++-- src/cli/direnv/envrc.rs | 6 +- src/cli/direnv/exec.rs | 4 +- src/cli/doctor.rs | 4 +- src/cli/env.rs | 4 +- src/cli/exec.rs | 5 +- src/cli/global.rs | 4 +- src/cli/hook_env.rs | 12 ++- src/cli/install.rs | 84 ++++++++--------- src/cli/local.rs | 25 +++-- src/cli/ls.rs | 10 +- src/cli/plugins/install.rs | 16 ++-- src/cli/reshim.rs | 6 +- src/cli/shell.rs | 6 +- src/cli/uninstall.rs | 6 +- src/cli/where.rs | 4 +- src/cli/which.rs | 6 +- src/config/config_file/legacy_version.rs | 26 +----- src/config/config_file/mod.rs | 91 +++++++++++-------- src/config/config_file/rtx_toml.rs | 50 ++++------ src/config/config_file/rtxrc.rs | 43 ++++----- ...nfig_file__rtx_toml__tests__fixture-3.snap | 20 +--- ...nfig_file__rtx_toml__tests__fixture-4.snap | 13 --- ...nfig_file__rtx_toml__tests__fixture-6.snap | 5 +- ...ile__rtx_toml__tests__remove_plugin-2.snap | 2 - ..._file__rtx_toml__tests__remove_plugin.snap | 2 - ...le__rtx_toml__tests__replace_versions.snap | 4 - src/config/config_file/tool_versions.rs | 64 ++++++------- src/shims.rs | 8 +- src/toolset/builder.rs | 14 +-- src/toolset/mod.rs | 90 ++++++++---------- src/toolset/tool_version.rs | 2 - test/fixtures/.rtx.toml | 5 +- 38 files changed, 374 insertions(+), 361 deletions(-) diff --git a/README.md b/README.md index 0a59c7757..e8cb28576 100644 --- a/README.md +++ b/README.md @@ -595,15 +595,17 @@ erlang = ['23.3', '24.0'] # supports everything you can do with .tool-versions currently nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] -# repo can be used to git clone a custom repo url (see #226) -jq = { version = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' } - # send arbitrary options to the plugin, passed as: # RTX_TOOL_OPTS__VENV=.venv # RTX_TOOL_OPTS__DEFAULT_PACKAGES__0=ansible # RTX_TOOL_OPTS__DEFAULT_PACKAGES__1=pipenv python = { version = '3.10', venv = '.venv', default_packages = ['ansible', 'pipenv'] } +[plugins] +# specify a custom repo url +# note this will only be used if the plugin does not already exist +python = 'https://github.com/jdxcode/rtx-python' + [settings] # project-local settings verbose = true missing_runtime_behavior = 'warn' diff --git a/e2e/test_local b/e2e/test_local index 5a1f7ef2f..52fd4c893 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -20,6 +20,59 @@ export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall assert_raises "rtx uninstall shfmt@3.6.0" +assert "rtx local" "[env] +FOO = \"bar\" + +[tools] +jq = \"latest\" +#tiny = {version=\"1\", foo=\"bar\"} +#golang = {version=\"1.19.5\", foo=\"bar\"} +" + +assert "rtx local shfmt@3.5.0" "[env] +FOO = \"bar\" + +[tools] +jq = \"latest\" +shfmt = \"3.5.0\" +#tiny = {version=\"1\", foo=\"bar\"} +#golang = {version=\"1.19.5\", foo=\"bar\"} +" + +rtx exec -- shfmt --version >&2 +if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then + exit 1 +fi + +assert "rtx local shfmt@3.6.0" "[env] +FOO = \"bar\" + +[tools] +jq = \"latest\" +shfmt = \"3.6.0\" +#tiny = {version=\"1\", foo=\"bar\"} +#golang = {version=\"1.19.5\", foo=\"bar\"} +" + +rtx exec -- shfmt --version >&2 +if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then + exit 1 +fi + +assert "rtx local --rm shfmt" "[env] +FOO = \"bar\" + +[tools] +jq = \"latest\" +#tiny = {version=\"1\", foo=\"bar\"} +#golang = {version=\"1.19.5\", foo=\"bar\"} +" + + +export RTX_DEFAULT_CONFIG_FILENAME=.MISSING + +assert_raises "rtx uninstall shfmt@3.6.0" + assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index e77af0864..955537b9d 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -2,6 +2,7 @@ export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions +export RTX_DEFAULT_CONFIG_FILENAME=.MISSING git checkout .alternate-tool-versions diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index bc33ee494..f13f86af6 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -17,7 +17,7 @@ pub struct Asdf { } impl Command for Asdf { - fn run(mut self, config: Config, out: &mut Output) -> Result<()> { + fn run(mut self, mut config: Config, out: &mut Output) -> Result<()> { let mut args = vec![String::from("rtx")]; args.append(&mut self.args); @@ -31,7 +31,7 @@ impl Command for Asdf { Ok(()) } } - Some("list") => list_versions(&config, out, &args), + Some("list") => list_versions(&mut config, out, &args), Some("install") => { if args.len() == 4 { let version = args.pop().unwrap(); @@ -44,9 +44,9 @@ impl Command for Asdf { } } -fn list_versions(config: &Config, out: &mut Output, args: &Vec) -> Result<()> { +fn list_versions(config: &mut Config, out: &mut Output, args: &Vec) -> Result<()> { let ts = ToolsetBuilder::new().build(config); - let mut versions = ts.list_installed_versions()?; + let mut versions = ts.list_installed_versions(config)?; let plugin = match args.len() { 3 => Some(&args[2]), _ => None, diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 34badb684..63d768cbe 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -11,9 +11,11 @@ use crate::toolset::ToolsetBuilder; pub struct BinPaths {} impl Command for BinPaths { - fn run(self, config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().with_install_missing().build(&config); - for p in ts.list_paths(&config.settings) { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new() + .with_install_missing() + .build(&mut config); + for p in ts.list_paths(&config) { rtxprintln!(out, "{}", p.display()); } Ok(()) diff --git a/src/cli/current.rs b/src/cli/current.rs index c79bd682c..487c15307 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -23,28 +23,28 @@ pub struct Current { } impl Command for Current { - fn run(self, config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config); + 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.plugins.get(plugin_name) { - Some(plugin) => self.one(ts, out, plugin), + Some(plugin) => self.one(&config, ts, out, plugin), None => { warn!("Plugin {} is not installed", plugin_name); Ok(()) } }, - None => self.all(ts, out), + None => self.all(&config, ts, out), } } } impl Current { - fn one(&self, ts: Toolset, out: &mut Output, plugin: &Plugin) -> Result<()> { + fn one(&self, config: &Config, ts: Toolset, out: &mut Output, plugin: &Plugin) -> Result<()> { if !plugin.is_installed() { warn!("Plugin {} is not installed", plugin.name); return Ok(()); } - match ts.list_versions_by_plugin().get(&plugin.name) { + match ts.list_versions_by_plugin(config).get(&plugin.name) { Some(versions) => { rtxprintln!( out, @@ -63,8 +63,8 @@ impl Current { Ok(()) } - fn all(&self, ts: Toolset, out: &mut Output) -> Result<()> { - for (plugin, versions) in ts.list_versions_by_plugin() { + fn all(&self, config: &Config, ts: Toolset, out: &mut Output) -> Result<()> { + for (plugin, versions) in ts.list_versions_by_plugin(config) { if versions.is_empty() { continue; } diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index f5312af1f..5d1ebd4e2 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -23,7 +23,9 @@ impl Command for Envrc { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } - let ts = ToolsetBuilder::new().with_install_missing().build(&config); + let ts = ToolsetBuilder::new() + .with_install_missing() + .build(&mut config); let envrc_path = env::RTX_TMP_DIR .join("direnv") .join(hash_to_str(dirs::CURRENT.deref()) + ".envrc"); @@ -47,7 +49,7 @@ impl Command for Envrc { shell_escape::unix::escape(v.into()), )?; } - for path in ts.list_paths(&config.settings).into_iter().rev() { + for path in ts.list_paths(&config).into_iter().rev() { writeln!(file, "PATH_add {}", path.to_string_lossy())?; } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 352a64011..0cf765406 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -26,7 +26,9 @@ impl Command for DirenvExec { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } - let ts = ToolsetBuilder::new().with_install_missing().build(&config); + let ts = ToolsetBuilder::new() + .with_install_missing() + .build(&mut config); let mut cmd = env_cmd(); for (k, v) in ts.env_with_path(&config) { diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 23c90b97a..abe27e375 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -22,8 +22,8 @@ use crate::toolset::ToolsetBuilder; pub struct Doctor {} impl Command for Doctor { - fn run(self, config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config); + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&mut config); rtxprintln!(out, "{}", rtx_version()); rtxprintln!(out, "{}", shell()); rtxprintln!(out, "{}", rtx_env_vars()); diff --git a/src/cli/env.rs b/src/cli/env.rs index ede43ef1d..fcbbf127c 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -27,11 +27,11 @@ pub struct Env { } impl Command for Env { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.runtime) - .build(&config); + .build(&mut config); let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index a6c745529..c41c11f7b 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -9,7 +9,6 @@ use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; -// #[cfg(test)] use crate::cmd; use crate::config::Config; @@ -46,11 +45,11 @@ pub struct Exec { } impl Command for Exec { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_args(&self.runtime) .with_install_missing() - .build(&config); + .build(&mut config); let (program, args) = parse_command(&env::SHELL, self.command, self.c); let mut env = ts.env_with_path(&config); diff --git a/src/cli/global.rs b/src/cli/global.rs index e5e4c19f9..44c6baec9 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -42,7 +42,7 @@ pub struct Global { } impl Command for Global { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let cf_path = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); let mut cf = match cf_path.exists() { @@ -61,7 +61,7 @@ impl Command for Global { return Ok(()); } let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); - cf.add_runtimes(&config, &runtimes, pin)?; + cf.add_runtimes(&mut config, &runtimes, pin)?; } if self.runtime.is_some() || self.remove.is_some() { diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index b33627015..219dc3ced 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -36,7 +36,9 @@ impl Command for HookEnv { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } - let ts = ToolsetBuilder::new().with_install_missing().build(&config); + let ts = ToolsetBuilder::new() + .with_install_missing() + .build(&mut config); let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); out.stdout.write(hook_env::clear_old_env(&*shell)); @@ -44,7 +46,7 @@ impl Command for HookEnv { let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); - let installs = ts.list_paths(&config.settings); // load the active runtime paths + let installs = ts.list_paths(&config); // load the active runtime paths diff.path = installs.clone(); // update __RTX_DIFF with the new paths for the next run patches.extend(self.build_path_operations(&installs, &__RTX_DIFF.path)?); @@ -54,7 +56,7 @@ impl Command for HookEnv { let output = hook_env::build_env_commands(&*shell, &patches); out.stdout.write(output); if self.status { - self.display_status(&ts, out); + self.display_status(&config, &ts, out); } Ok(()) @@ -62,9 +64,9 @@ impl Command for HookEnv { } impl HookEnv { - fn display_status(&self, ts: &Toolset, out: &mut Output) { + fn display_status(&self, config: &Config, ts: &Toolset, out: &mut Output) { let installed_versions = ts - .list_current_installed_versions() + .list_current_installed_versions(config) .into_iter() .rev() .map(|v| v.to_string()) diff --git a/src/cli/install.rs b/src/cli/install.rs index 15f2a2d52..2b2cf91c2 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -57,8 +57,8 @@ impl Command for Install { config.settings.missing_runtime_behavior = AutoInstall; match &self.runtime { - Some(runtime) => self.install_runtimes(&config, runtime)?, - None => self.install_missing_runtimes(&config)?, + Some(runtime) => self.install_runtimes(config, runtime)?, + None => self.install_missing_runtimes(config)?, } Ok(()) @@ -66,10 +66,10 @@ impl Command for Install { } impl Install { - fn install_runtimes(&self, config: &Config, runtimes: &[RuntimeArg]) -> Result<()> { + fn install_runtimes(&self, mut config: Config, runtimes: &[RuntimeArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); let mut tool_versions = vec![]; - let ts = ToolsetBuilder::new().build(config); + let ts = ToolsetBuilder::new().build(&mut config); for runtime in RuntimeArg::double_runtime_condition(runtimes) { match runtime.to_tool_version() { Some(tv) => tool_versions.push(tv), @@ -93,44 +93,44 @@ impl Install { } } } - let mut versions = vec![]; - for mut tv in tool_versions { - let plugin = match config.plugins.get(&tv.plugin_name).cloned() { - Some(plugin) => plugin, - None => { - let plugin = Plugin::new(&tv.plugin_name); - let mut pr = mpr.add(); - match plugin.install(config, None, &mut pr) { - Ok(_) => Arc::new(plugin), - Err(err) => { - pr.error(); - return Err(err)?; - } - } - } - }; - tv.resolve(config, plugin)?; - versions.push(tv.rtv.unwrap()); - } - if versions.is_empty() { - warn!("no runtimes to install"); - warn!("specify a version with `rtx install @`"); - return Ok(()); - } - let mut to_uninstall = vec![]; - for rtv in &versions { - if rtv.is_installed() { - if self.force { - to_uninstall.push(rtv.clone()); - } else { - warn!("{} already installed", style(rtv).cyan().for_stderr()); - } - } - } ThreadPoolBuilder::new() .num_threads(config.settings.jobs) .build()? .install(|| -> Result<()> { + let mut versions = vec![]; + for mut tv in tool_versions { + let plugin = match config.plugins.get(&tv.plugin_name).cloned() { + Some(plugin) => plugin, + None => { + let plugin = Plugin::new(&tv.plugin_name); + let mut pr = mpr.add(); + match plugin.install(&config, None, &mut pr) { + Ok(_) => Arc::new(plugin), + Err(err) => { + pr.error(); + return Err(err)?; + } + } + } + }; + tv.resolve(&config, plugin)?; + versions.push(tv.rtv.unwrap()); + } + if versions.is_empty() { + warn!("no runtimes to install"); + warn!("specify a version with `rtx install @`"); + return Ok(()); + } + let mut to_uninstall = vec![]; + for rtv in &versions { + if rtv.is_installed() { + if self.force { + to_uninstall.push(rtv.clone()); + } else { + warn!("{} already installed", style(rtv).cyan().for_stderr()); + } + } + } if !to_uninstall.is_empty() { to_uninstall .into_par_iter() @@ -158,7 +158,7 @@ impl Install { } let mut pr = mpr.add(); rtv.decorate_progress_bar(&mut pr); - match rtv.install(config, &mut pr) { + match rtv.install(&config, &mut pr) { Ok(_) => Ok(()), Err(err) => { pr.error(); @@ -172,8 +172,8 @@ impl Install { }) } - fn install_missing_runtimes(&self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().build(config); + fn install_missing_runtimes(&self, mut config: Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().build(&mut config); if let Some(plugins) = &self.plugin { let plugins = plugins.iter().collect::>(); for plugin in ts.versions.keys().cloned().collect::>() { @@ -191,7 +191,7 @@ impl Install { warn!("no runtimes to install"); } let mpr = MultiProgressReport::new(config.settings.verbose); - ts.install_missing(config, Some(mpr))?; + ts.install_missing(&mut config, mpr)?; Ok(()) } diff --git a/src/cli/local.rs b/src/cli/local.rs index 38a1fe163..4b25b632d 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -6,9 +6,10 @@ use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::{config_file, Config}; +use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::output::Output; use crate::plugins::PluginName; -use crate::{dirs, env, file}; +use crate::{dirs, file}; /// Sets .tool-versions to include a specific runtime /// @@ -47,19 +48,29 @@ pub struct Local { } impl Command for Local { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let cf_path = match self.parent { true => file::find_up( &dirs::CURRENT, - &[env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()], + &[ + RTX_DEFAULT_CONFIG_FILENAME.as_str(), + RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str(), + ], ) .with_context(|| { eyre!( "no {} file found", - env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() + RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() ) })?, - false => dirs::CURRENT.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()), + false => { + let rtx_toml = dirs::CURRENT.join(RTX_DEFAULT_CONFIG_FILENAME.as_str()); + if rtx_toml.exists() { + rtx_toml + } else { + dirs::CURRENT.join(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) + } + } }; let mut cf = match cf_path.exists() { @@ -74,12 +85,12 @@ impl Command for Local { } if let Some(runtimes) = &self.runtime { - let runtimes = RuntimeArg::double_runtime_condition(runtimes); + let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); if cf.display_runtime(out, &runtimes)? { return Ok(()); } let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); - cf.add_runtimes(&config, &runtimes, pin)?; + cf.add_runtimes(&mut config, &runtimes, pin)?; } if self.runtime.is_some() || self.remove.is_some() { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index b48979784..54c346dcb 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -37,9 +37,9 @@ pub struct Ls { } impl Command for Ls { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let plugin = self.plugin.or(self.plugin_arg); - for (rtv, source) in get_runtime_list(&config, &plugin)? { + for (rtv, source) in get_runtime_list(&mut config, &plugin)? { if self.current && source.is_none() { continue; } @@ -92,12 +92,12 @@ fn styled_version(rtv: &RuntimeVersion, missing: bool, active: bool) -> String { } fn get_runtime_list( - config: &Config, + config: &mut Config, plugin_flag: &Option, ) -> Result)>> { let ts = ToolsetBuilder::new().build(config); let mut versions: HashMap<(PluginName, String), RuntimeVersion> = ts - .list_installed_versions()? + .list_installed_versions(config)? .into_iter() .filter(|rtv| match plugin_flag { Some(plugin) => rtv.plugin.name == *plugin, @@ -107,7 +107,7 @@ fn get_runtime_list( .collect(); let active = ts - .list_current_versions() + .list_current_versions(config) .into_iter() .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv.clone())) .collect::>(); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 255c0d311..37ec80063 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -52,10 +52,10 @@ pub struct PluginsInstall { } impl Command for PluginsInstall { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); if self.all { - return self.install_all_missing_plugins(&config, mpr); + return self.install_all_missing_plugins(&mut config, mpr); } let (name, git_url) = get_name_and_url(&config, &self.name.clone().unwrap(), &self.git_url)?; @@ -64,7 +64,7 @@ impl Command for PluginsInstall { } else { let mut plugins: Vec = vec![name, git_url]; plugins.extend(self.rest.clone()); - self.install_many(&config, &plugins, mpr)?; + self.install_many(&mut config, &plugins, mpr)?; } Ok(()) @@ -72,9 +72,13 @@ impl Command for PluginsInstall { } impl PluginsInstall { - fn install_all_missing_plugins(&self, config: &Config, mpr: MultiProgressReport) -> Result<()> { + fn install_all_missing_plugins( + &self, + config: &mut Config, + mpr: MultiProgressReport, + ) -> Result<()> { let ts = ToolsetBuilder::new().build(config); - let missing_plugins = ts.list_missing_plugins(); + let missing_plugins = ts.list_missing_plugins(config); if missing_plugins.is_empty() { warn!("all plugins already installed"); } @@ -84,7 +88,7 @@ impl PluginsInstall { fn install_many( &self, - config: &Config, + config: &mut Config, plugins: &[PluginName], mpr: MultiProgressReport, ) -> Result<()> { diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 176162b79..38266ebee 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -29,8 +29,8 @@ pub struct Reshim { } impl Command for Reshim { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config); + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&mut config); if !config.settings.experimental { err_experimental()?; @@ -41,7 +41,7 @@ impl Command for Reshim { let _ = remove_dir_all(&shims_dir); create_dir_all(&shims_dir)?; - for path in ts.list_paths(&config.settings) { + for path in ts.list_paths(&config) { if !path.exists() { continue; } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 92877d5bd..9784bcd63 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -27,18 +27,18 @@ pub struct Shell { } impl Command for Shell { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.runtime) - .build(&config); + .build(&mut config); if !config.is_activated() { err_inactive()?; } let shell = get_shell(None).expect("no shell detected"); - for rtv in ts.list_current_installed_versions() { + for rtv in ts.list_current_installed_versions(&config) { let source = &ts.versions.get(&rtv.plugin.name).unwrap().source; if matches!(source, ToolSource::Argument) { let k = format!("RTX_{}_VERSION", rtv.plugin.name.to_uppercase()); diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index b717d2327..d3b5fa65b 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -20,9 +20,11 @@ pub struct Uninstall { } impl Command for Uninstall { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let runtimes = RuntimeArg::double_runtime_condition(&self.runtime); - let ts = ToolsetBuilder::new().with_args(&runtimes).build(&config); + let ts = ToolsetBuilder::new() + .with_args(&runtimes) + .build(&mut config); let runtime_versions = runtimes.iter().filter_map(|a| ts.resolve_runtime_arg(a)); let mpr = MultiProgressReport::new(config.settings.verbose); diff --git a/src/cli/where.rs b/src/cli/where.rs index a7d2c30bd..34611f304 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -31,7 +31,7 @@ pub struct Where { } impl Command for Where { - fn run(self, config: Config, out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let runtime = match self.runtime.version { RuntimeArgVersion::None => match self.asdf_version { Some(version) => self @@ -44,7 +44,7 @@ impl Command for Where { let ts = ToolsetBuilder::new() .with_args(&[runtime.clone()]) - .build(&config); + .build(&mut config); match ts.resolve_runtime_arg(&runtime) { Some(rtv) if rtv.is_installed() => { diff --git a/src/cli/which.rs b/src/cli/which.rs index 998a3192c..bfc857ae0 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -26,10 +26,10 @@ pub struct Which { } impl Command for Which { - fn run(self, config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config); + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&mut config); - match ts.which(&config.settings, &self.bin_name) { + match ts.which(&config, &self.bin_name) { Some(rtv) => { if self.version { rtxprintln!(out, "{}", rtv.version); diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 1ade98437..789a40987 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -4,7 +4,6 @@ use std::fmt::Display; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; -use indexmap::IndexMap; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; @@ -15,8 +14,6 @@ use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; #[derive(Debug)] pub struct LegacyVersionFile { path: PathBuf, - version: String, - plugin: String, toolset: Toolset, } @@ -27,8 +24,6 @@ impl LegacyVersionFile { Ok(Self { toolset: build_toolset(&path, plugin.name.as_str(), version.as_str()), path, - version, - plugin: plugin.name.clone(), }) } } @@ -42,12 +37,8 @@ impl ConfigFile for LegacyVersionFile { self.path.as_path() } - fn plugins(&self) -> IndexMap> { - if self.version.is_empty() { - IndexMap::new() - } else { - IndexMap::from([(self.plugin.clone(), vec![self.version.clone()])]) - } + fn plugins(&self) -> HashMap { + Default::default() } fn env(&self) -> HashMap { @@ -58,10 +49,6 @@ impl ConfigFile for LegacyVersionFile { unimplemented!() } - fn add_version(&mut self, _plugin_name: &PluginName, _version: &str) { - unimplemented!() - } - fn replace_versions(&mut self, _plugin_name: &PluginName, _versions: &[String]) { unimplemented!() } @@ -96,13 +83,10 @@ impl Display for LegacyVersionFile { fn build_toolset(path: &Path, plugin: &str, version: &str) -> Toolset { let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.to_path_buf())); if !version.is_empty() { - toolset.add_version( + toolset.add_version(ToolVersion::new( plugin.to_string(), - ToolVersion::new( - plugin.to_string(), - ToolVersionType::Version(version.to_string()), - ), - ); + ToolVersionType::Version(version.to_string()), + )); } toolset } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 25dc71b49..569066a77 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -3,21 +3,20 @@ use std::fmt::{Debug, Display}; use std::path::Path; use color_eyre::eyre::{eyre, Result}; -use indexmap::IndexMap; use rtxrc::RTXFile; use tool_versions::ToolVersions; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; +use crate::config::config_file::rtx_toml::RtxToml; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, Config}; use crate::env; - use crate::file::display_path; use crate::output::Output; use crate::plugins::PluginName; - -use crate::toolset::{Toolset, ToolsetBuilder}; +use crate::toolset::{ToolVersionList, Toolset}; +use crate::ui::multi_progress_report::MultiProgressReport; pub mod legacy_version; pub mod rtx_toml; @@ -35,10 +34,9 @@ pub enum ConfigFileType { pub trait ConfigFile: Debug + Display + Send + Sync { fn get_type(&self) -> ConfigFileType; fn get_path(&self) -> &Path; - fn plugins(&self) -> IndexMap>; + fn plugins(&self) -> HashMap; fn env(&self) -> HashMap; fn remove_plugin(&mut self, plugin_name: &PluginName); - fn add_version(&mut self, plugin_name: &PluginName, version: &str); fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]); fn save(&self) -> Result<()>; fn dump(&self) -> String; @@ -50,35 +48,41 @@ pub trait ConfigFile: Debug + Display + Send + Sync { impl dyn ConfigFile { pub fn add_runtimes( &mut self, - config: &Config, + config: &mut Config, runtimes: &[RuntimeArg], pin: bool, ) -> Result<()> { - let mut runtime_map: HashMap> = HashMap::new(); - let ts = ToolsetBuilder::new() - .with_install_missing() - .with_args(runtimes) - .build(config); - + let mpr = MultiProgressReport::new(config.settings.verbose); + let mut ts = self.to_toolset().to_owned(); + let mut plugins_to_update = HashMap::new(); for runtime in runtimes { - if let Some(rtv) = ts.resolve_runtime_arg(runtime) { - runtime_map - .entry(rtv.plugin.name.clone()) - .or_default() - .push(if pin { - rtv.version.to_string() - } else { - match &runtime.version { - RuntimeArgVersion::Version(ref v) => v.to_string(), - RuntimeArgVersion::Path(p) => format!("path:{}", p.display()), - RuntimeArgVersion::Ref(r) => format!("ref:{r}"), - RuntimeArgVersion::Prefix(p) => format!("prefix:{p}"), - _ => "latest".to_string(), - } - }); + if let Some(tv) = runtime.to_tool_version() { + plugins_to_update + .entry(runtime.plugin.clone()) + .or_insert_with(Vec::new) + .push(tv); } } - for (plugin, versions) in runtime_map { + for (plugin, versions) in &plugins_to_update { + let mut tvl = ToolVersionList::new(ts.source.as_ref().unwrap().clone()); + tvl.versions = versions.clone(); + ts.versions.insert(plugin.clone(), tvl); + } + ts.resolve(config); + ts.install_missing(config, mpr)?; + for (plugin, versions) in plugins_to_update { + let versions = versions + .into_iter() + .map(|mut tv| { + if pin { + let plugin = config.plugins.get(&plugin).unwrap(); + tv.resolve(config, plugin.clone())?; + Ok(tv.rtv.unwrap().version) + } else { + Ok(tv.r#type.to_string()) + } + }) + .collect::>>()?; self.replace_versions(&plugin, &versions); } @@ -92,15 +96,22 @@ impl dyn ConfigFile { // in this situation we just print the current version in the config file if runtimes.len() == 1 && runtimes[0].version == RuntimeArgVersion::None { let plugin = &runtimes[0].plugin; - let plugins = self.plugins(); - let version = plugins.get(plugin).ok_or_else(|| { - eyre!( - "no version set for {} in {}", - plugin.to_string(), - display_path(self.get_path()) - ) - })?; - rtxprintln!(out, "{}", version.join(" ")); + let tvl = self + .to_toolset() + .versions + .get(plugin) + .ok_or_else(|| { + eyre!( + "no version set for {} in {}", + plugin.to_string(), + display_path(self.get_path()) + ) + })? + .versions + .iter() + .map(|tv| tv.r#type.to_string()) + .collect::>(); + rtxprintln!(out, "{}", tvl.join(" ")); return Ok(true); } // check for something like `rtx local nodejs python@latest` which is invalid @@ -117,6 +128,8 @@ impl dyn ConfigFile { pub fn init(path: &Path) -> Box { if path.ends_with(".rtxrc") || path.ends_with(".rtxrc.toml") { return Box::new(RTXFile::init(path)); + } else if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) { + return Box::new(RtxToml::init(path)); } else if path.ends_with(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) { return Box::new(ToolVersions::init(path)); } @@ -126,7 +139,7 @@ pub fn init(path: &Path) -> Box { pub fn parse(path: &Path) -> Result> { match detect_config_file_type(path) { - Some(ConfigFileType::RtxToml) => Ok(Box::new(rtx_toml::RtxToml::from_file(path)?)), + Some(ConfigFileType::RtxToml) => Ok(Box::new(RtxToml::from_file(path)?)), Some(ConfigFileType::RtxRc) => Ok(Box::new(RTXFile::from_file(path)?)), Some(ConfigFileType::ToolVersions) => Ok(Box::new(ToolVersions::from_file(path)?)), #[allow(clippy::box_default)] diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 8f16c7c85..aa27e08cb 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -6,7 +6,6 @@ use std::time::Duration; use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; -use indexmap::IndexMap; use log::LevelFilter; use toml_edit::{table, value, Array, Item, Value}; @@ -24,6 +23,7 @@ pub struct RtxToml { settings: SettingsBuilder, alias: AliasMap, doc: toml_edit::Document, + plugins: HashMap, } #[macro_export] @@ -70,6 +70,7 @@ impl RtxToml { "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, "settings" => self.settings = self.parse_settings(k, v)?, + "plugins" => self.plugins = self.parse_hashmap(k, v)?, _ => warn!("unknown key: {}", k), } } @@ -221,16 +222,8 @@ impl RtxToml { } else { parse_error!(key, v, "version, path, or prefix")? } - if let Some(repo) = table.get("repo") { - match repo.as_str() { - Some(s) => { - tv.repo = Some(s.into()); - } - _ => parse_error!(format!("{}.repo", key), v, "string")?, - } - } for (k, v) in table.iter() { - if k == "version" || k == "path" || k == "prefix" || k == "ref" || k == "repo" { + if k == "version" || k == "path" || k == "prefix" || k == "ref" { continue; } match v.as_str() { @@ -416,17 +409,8 @@ impl ConfigFile for RtxToml { self.path.as_path() } - fn plugins(&self) -> IndexMap> { - self.toolset - .versions - .iter() - .map(|(p, v)| { - ( - p.to_string(), - v.versions.iter().map(|v| v.to_string()).collect(), - ) - }) - .collect() + fn plugins(&self) -> HashMap { + self.plugins.clone() } fn env(&self) -> HashMap { @@ -435,19 +419,23 @@ impl ConfigFile for RtxToml { fn remove_plugin(&mut self, plugin: &PluginName) { self.toolset.versions.remove(plugin); - self.doc.as_table_mut().remove(plugin.to_string().as_str()); - } - - fn add_version(&mut self, _plugin: &PluginName, _version: &str) { - unimplemented!(); + if let Some(tools) = self.doc.get_mut("tools") { + if let Some(tools) = tools.as_table_like_mut() { + tools.remove(plugin); + if tools.is_empty() { + self.doc.as_table_mut().remove("tools"); + } + } + } } fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { - let plugin = self.toolset.versions.get_mut(plugin_name).unwrap(); - plugin.versions = versions - .iter() - .map(|v| ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v.clone()))) - .collect(); + if let Some(plugin) = self.toolset.versions.get_mut(plugin_name) { + plugin.versions = versions + .iter() + .map(|v| ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v.clone()))) + .collect(); + } let tools = self .doc .entry("tools") diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs index 91a6460b8..821b45469 100644 --- a/src/config/config_file/rtxrc.rs +++ b/src/config/config_file/rtxrc.rs @@ -332,6 +332,24 @@ impl RTXFile { } Ok(()) } + + fn add_version(&mut self, plugin: &PluginName, version: &str) { + self.plugins + .entry(plugin.into()) + .or_default() + .versions + .push(version.to_string()); + + self.get_edit() + .unwrap() + .lock() + .unwrap() + .entry(plugin) + .or_insert_with(toml_edit::array) + .as_array_mut() + .unwrap() + .push(version); + } } impl Display for RTXFile { @@ -349,11 +367,8 @@ impl ConfigFile for RTXFile { self.path.as_path() } - fn plugins(&self) -> IndexMap> { - self.plugins - .iter() - .map(|(k, v)| (k.clone(), v.versions.clone())) - .collect() + fn plugins(&self) -> HashMap { + Default::default() } fn env(&self) -> HashMap { @@ -370,24 +385,6 @@ impl ConfigFile for RTXFile { .remove(plugin); } - fn add_version(&mut self, plugin: &PluginName, version: &str) { - self.plugins - .entry(plugin.into()) - .or_default() - .versions - .push(version.to_string()); - - self.get_edit() - .unwrap() - .lock() - .unwrap() - .entry(plugin) - .or_insert_with(toml_edit::array) - .as_array_mut() - .unwrap() - .push(version); - } - fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { let plugin = self.plugins.entry(plugin_name.into()).or_default(); plugin.versions.clear(); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap index 07e485886..740232f39 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap @@ -3,23 +3,5 @@ source: src/config/config_file/rtx_toml.rs expression: cf.plugins() --- { - "terraform": [ - "terraform@1.0.0", - ], - "nodejs": [ - "nodejs@16", - "nodejs@prefix:18", - "nodejs@ref:master", - "nodejs@path:~/.nodes/14", - ], - "jq": [ - "jq@prefix:1.6", - ], - "shellcheck": [ - "shellcheck@0.9.0", - ], - "python": [ - "python@3.10.0", - "python@3.9.0", - ], + "nodejs": "https://github.com/jdxcode/rtx-nodejs", } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index f5c7eea21..bbdcefd86 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -12,7 +12,6 @@ Toolset { "1.0.0", ), rtv: None, - repo: None, options: {}, }, ], @@ -28,7 +27,6 @@ Toolset { "16", ), rtv: None, - repo: None, options: {}, }, ToolVersion { @@ -37,7 +35,6 @@ Toolset { "18", ), rtv: None, - repo: None, options: {}, }, ToolVersion { @@ -46,7 +43,6 @@ Toolset { "master", ), rtv: None, - repo: None, options: {}, }, ToolVersion { @@ -55,7 +51,6 @@ Toolset { "~/.nodes/14", ), rtv: None, - repo: None, options: {}, }, ], @@ -71,9 +66,6 @@ Toolset { "1.6", ), rtv: None, - repo: Some( - "https://github.com/AZMCode/asdf-jq", - ), options: {}, }, ], @@ -89,7 +81,6 @@ Toolset { "0.9.0", ), rtv: None, - repo: None, options: {}, }, ], @@ -105,7 +96,6 @@ Toolset { "3.10.0", ), rtv: None, - repo: None, options: { "venv": ".venv", }, @@ -116,7 +106,6 @@ Toolset { "3.9.0", ), rtv: None, - repo: None, options: {}, }, ], @@ -130,6 +119,4 @@ Toolset { "", ), ), - plugins: {}, - mpr: None, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index e6f4c6278..bc8a50e9e 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -8,13 +8,16 @@ NODE_ENV = 'production' [tools] terraform = '1.0.0' nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] -jq = { prefix = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' } +jq = { prefix = '1.6' } shellcheck = { version = '0.9.0' } python = [ { version = '3.10.0', venv = '.venv' }, { version = '3.9.0' }, ] +[plugins] +nodejs = 'https://github.com/jdxcode/rtx-nodejs' + [settings] verbose = true missing_runtime_behavior = 'warn' diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap index 4ea76e5f3..def19a35d 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap @@ -2,6 +2,4 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- -[tools] -nodejs = ["16.0.0", "18.0.0"] diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap index c66afee41..1c5a23ad1 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap @@ -9,6 +9,4 @@ Toolset { "", ), ), - plugins: {}, - mpr: None, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index 1830d6694..e5e74b9a1 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -12,7 +12,6 @@ Toolset { "16.0.1", ), rtv: None, - repo: None, options: {}, }, ToolVersion { @@ -21,7 +20,6 @@ Toolset { "18.0.1", ), rtv: None, - repo: None, options: {}, }, ], @@ -35,6 +33,4 @@ Toolset { "", ), ), - plugins: {}, - mpr: None, } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index b9b585bde..523d12ac2 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -38,6 +38,7 @@ struct ToolVersionPlugin { impl ToolVersions { pub fn init(filename: &Path) -> ToolVersions { ToolVersions { + toolset: Toolset::new(ToolSource::ToolVersions(filename.to_path_buf())), path: filename.to_path_buf(), ..Default::default() } @@ -49,22 +50,18 @@ impl ToolVersions { } pub fn parse_str(s: &str, path: PathBuf) -> Result { - let mut pre = String::new(); + let mut cf = Self::init(&path); for line in s.lines() { if !line.trim_start().starts_with('#') { break; } - pre.push_str(line); - pre.push('\n'); + cf.pre.push_str(line); + cf.pre.push('\n'); } - let plugins = Self::parse_plugins(s)?; - Ok(Self { - toolset: build_toolset(&path, &plugins), - path, - plugins, - pre, - }) + cf.plugins = Self::parse_plugins(s)?; + cf.populate_toolset(); + Ok(cf) } fn get_or_create_plugin(&mut self, plugin: &str) -> &mut ToolVersionPlugin { @@ -101,23 +98,28 @@ impl ToolVersions { } Ok(plugins) } -} -fn build_toolset(path: &Path, plugins: &IndexMap) -> Toolset { - let mut toolset = Toolset::new(ToolSource::ToolVersions(path.to_path_buf())); - for (plugin, tvp) in plugins { - for version in &tvp.versions { - let v = match version.split_once(':') { - Some(("prefix", v)) => ToolVersionType::Prefix(v.to_string()), - Some(("ref", v)) => ToolVersionType::Ref(v.to_string()), - Some(("path", v)) => ToolVersionType::Path(PathBuf::from(v)), - None if version == "system" => ToolVersionType::System, - _ => ToolVersionType::Version(version.to_string()), - }; - toolset.add_version(plugin.clone(), ToolVersion::new(plugin.clone(), v)); + fn add_version(&mut self, plugin: &PluginName, version: &str) { + self.get_or_create_plugin(plugin) + .versions + .push(version.to_string()); + } + + fn populate_toolset(&mut self) { + for (plugin, tvp) in &self.plugins { + for version in &tvp.versions { + let v = match version.split_once(':') { + Some(("prefix", v)) => ToolVersionType::Prefix(v.to_string()), + Some(("ref", v)) => ToolVersionType::Ref(v.to_string()), + Some(("path", v)) => ToolVersionType::Path(PathBuf::from(v)), + None if version == "system" => ToolVersionType::System, + _ => ToolVersionType::Version(version.to_string()), + }; + self.toolset + .add_version(ToolVersion::new(plugin.clone(), v)); + } } } - toolset } impl Display for ToolVersions { @@ -144,11 +146,9 @@ impl ConfigFile for ToolVersions { fn get_path(&self) -> &Path { self.path.as_path() } - fn plugins(&self) -> IndexMap> { - self.plugins - .iter() - .map(|(plugin, tvp)| (plugin.clone(), tvp.versions.clone())) - .collect() + + fn plugins(&self) -> HashMap { + Default::default() } fn env(&self) -> HashMap { @@ -159,12 +159,6 @@ impl ConfigFile for ToolVersions { self.plugins.remove(plugin); } - fn add_version(&mut self, plugin: &PluginName, version: &str) { - self.get_or_create_plugin(plugin) - .versions - .push(version.to_string()); - } - fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { self.get_or_create_plugin(plugin_name).versions.clear(); for version in versions { diff --git a/src/shims.rs b/src/shims.rs index 0c0034a18..57f9661b0 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -10,12 +10,12 @@ use crate::output::Output; use crate::toolset::ToolsetBuilder; // executes as if it was a shim if the command is not "rtx", e.g.: "node" -pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result { +pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Result { let (_, bin_name) = args[0].rsplit_once('/').unwrap_or(("", &args[0])); if bin_name == "rtx" || !config.settings.experimental { return Ok(config); } - is_valid_shim(&config, bin_name)?; + is_valid_shim(&mut config, bin_name)?; let mut args: Vec = args.iter().map(OsString::from).collect(); args[0] = OsString::from(bin_name); let exec = Exec { @@ -27,9 +27,9 @@ pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result< exit(0); } -fn is_valid_shim(config: &Config, bin_name: &str) -> Result<()> { +fn is_valid_shim(config: &mut Config, bin_name: &str) -> Result<()> { let ts = ToolsetBuilder::new().build(config); - match ts.which(&config.settings, bin_name) { + match ts.which(config, bin_name) { Some(_) => Ok(()), None => Err(eyre!("{} is not a valid shim", bin_name)), } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 65ab1d671..e5bc9b536 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -6,6 +6,7 @@ use crate::config::Config; use crate::env; use crate::toolset::tool_version::ToolVersionType; use crate::toolset::{ToolSource, ToolVersion, Toolset}; +use crate::ui::multi_progress_report::MultiProgressReport; #[derive(Debug)] pub struct ToolsetBuilder { @@ -31,15 +32,16 @@ impl ToolsetBuilder { self } - pub fn build(self, config: &Config) -> Toolset { - let mut toolset = Toolset::default().with_plugins(config.plugins.clone()); + pub fn build(self, config: &mut Config) -> Toolset { + let mut toolset = Toolset::default(); load_config_files(config, &mut toolset); load_runtime_env(&mut toolset, env::vars().collect()); load_runtime_args(&mut toolset, &self.args); toolset.resolve(config); if self.install_missing { - if let Err(e) = toolset.install_missing(config, None) { + let mpr = MultiProgressReport::new(config.settings.verbose); + if let Err(e) = toolset.install_missing(config, mpr) { warn!("Error installing runtimes: {}", e); }; } @@ -62,18 +64,18 @@ fn load_runtime_env(ts: &mut Toolset, env: IndexMap) { let source = ToolSource::Environment(k, v.clone()); let mut env_ts = Toolset::new(source); let version = ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v)); - env_ts.add_version(plugin_name, version); + env_ts.add_version(version); ts.merge(&env_ts); } } } fn load_runtime_args(ts: &mut Toolset, args: &[RuntimeArg]) { - for (plugin_name, args) in args.iter().into_group_map_by(|arg| arg.plugin.clone()) { + for (_, args) in args.iter().into_group_map_by(|arg| arg.plugin.clone()) { let mut arg_ts = Toolset::new(ToolSource::Argument); for arg in args { if let Some(version) = arg.to_tool_version() { - arg_ts.add_version(plugin_name.clone(), version); + arg_ts.add_version(version); } } ts.merge(&arg_ts); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index fcfb267cd..cddd01429 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -20,7 +20,7 @@ pub use tool_version::ToolVersionType; pub use tool_version_list::ToolVersionList; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; -use crate::config::{Config, MissingRuntimeBehavior, Settings}; +use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; @@ -36,12 +36,10 @@ mod tool_version_list; /// one example is a .tool-versions file /// the idea is that we start with an empty toolset, then /// merge in other toolsets from various sources -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct Toolset { pub versions: IndexMap, - source: Option, - plugins: IndexMap>, - mpr: Option, + pub source: Option, } impl Toolset { @@ -51,14 +49,10 @@ impl Toolset { ..Default::default() } } - pub fn with_plugins(mut self, plugins: IndexMap>) -> Self { - self.plugins = plugins; - self - } - pub fn add_version(&mut self, plugin: PluginName, version: ToolVersion) { + pub fn add_version(&mut self, version: ToolVersion) { let versions = self .versions - .entry(plugin) + .entry(version.plugin_name.clone()) .or_insert_with(|| ToolVersionList::new(self.source.clone().unwrap())); versions.add_version(version); } @@ -78,7 +72,7 @@ impl Toolset { .collect::>() .par_iter_mut() .for_each(|(p, v)| { - let plugin = match self.plugins.get(&p.to_string()) { + let plugin = match config.plugins.get(&p.to_string()) { Some(p) => p, None => { debug!("Plugin {} not found", p); @@ -88,11 +82,7 @@ impl Toolset { v.resolve(config, plugin.clone()); }); } - pub fn install_missing( - &mut self, - config: &Config, - mpr: Option, - ) -> Result<()> { + pub fn install_missing(&mut self, config: &mut Config, mpr: MultiProgressReport) -> Result<()> { let versions = self.list_missing_versions(); if versions.is_empty() { return Ok(()); @@ -125,26 +115,24 @@ impl Toolset { Ok(()) } - pub fn list_missing_plugins(&self) -> Vec { + pub fn list_missing_plugins(&self, config: &Config) -> Vec { self.versions .keys() - .filter(|p| !self.plugins.contains_key(*p)) + .filter(|p| !config.plugins.contains_key(*p)) .cloned() .collect() } fn install_missing_versions( &mut self, - config: &Config, + config: &mut Config, selected_versions: Vec, - mpr: Option, + mpr: MultiProgressReport, ) -> Result<()> { ThreadPoolBuilder::new() .num_threads(config.settings.jobs) .build()? .install(|| -> Result<()> { - self.mpr = - Some(mpr.unwrap_or_else(|| MultiProgressReport::new(config.settings.verbose))); let plugins = selected_versions .iter() .map(|v| v.plugin_name.clone()) @@ -154,7 +142,7 @@ impl Toolset { .into_iter() .map(|v| v.r#type) .collect::>(); - self.install_missing_plugins(config, plugins)?; + self.install_missing_plugins(config, plugins, &mpr)?; self.versions .iter_mut() .par_bridge() @@ -164,7 +152,7 @@ impl Toolset { .iter_mut() .filter(|v| v.is_missing() && selected_versions.contains(&v.r#type)) .collect_vec(); - let plugin = self.plugins.get(&p.to_string()); + let plugin = config.plugins.get(&p.to_string()); match (plugin, versions.is_empty()) { (Some(plugin), false) => Some((plugin, versions)), _ => None, @@ -172,21 +160,21 @@ impl Toolset { }) .map(|(plugin, versions)| { for version in versions { - let mut pr = self.mpr.as_ref().unwrap().add(); + let mut pr = mpr.add(); version.resolve(config, plugin.clone())?; version.install(config, &mut pr)?; } Ok(()) }) .collect::>>()?; - self.mpr = None; Ok(()) }) } fn install_missing_plugins( &mut self, - config: &Config, + config: &mut Config, missing_plugins: Vec, + mpr: &MultiProgressReport, ) -> Result<()> { if missing_plugins.is_empty() { return Ok(()); @@ -196,15 +184,15 @@ impl Toolset { .map(|plugin_name| { let plugin = Plugin::new(&plugin_name); if !plugin.is_installed() { - plugin.install(config, None, &mut self.mpr.as_ref().unwrap().add())?; + plugin.install(config, None, &mut mpr.add())?; } Ok(plugin) }) .collect::>>()?; for plugin in plugins { - self.plugins.insert(plugin.name.clone(), Arc::new(plugin)); + config.plugins.insert(plugin.name.clone(), Arc::new(plugin)); } - self.plugins.sort_keys(); + config.plugins.sort_keys(); Ok(()) } @@ -217,8 +205,8 @@ impl Toolset { .collect_vec(); versions } - pub fn list_installed_versions(&self) -> Result> { - let versions = self + pub fn list_installed_versions(&self, config: &Config) -> Result> { + let versions = config .plugins .values() .collect_vec() @@ -237,10 +225,13 @@ impl Toolset { Ok(versions) } - pub fn list_versions_by_plugin(&self) -> IndexMap> { + pub fn list_versions_by_plugin( + &self, + config: &Config, + ) -> IndexMap> { self.versions .iter() - .filter_map(|(p, v)| match self.plugins.get(&p.to_string()) { + .filter_map(|(p, v)| match config.plugins.get(&p.to_string()) { Some(plugin) => { let plugin = Arc::new(plugin.clone()); let versions = v.resolved_versions(); @@ -253,27 +244,26 @@ impl Toolset { }) .collect() } - pub fn list_current_versions(&self) -> Vec<&RuntimeVersion> { - self.list_versions_by_plugin() + pub fn list_current_versions(&self, config: &Config) -> Vec<&RuntimeVersion> { + self.list_versions_by_plugin(config) .into_iter() .flat_map(|(_, v)| v) .collect() } - pub fn list_current_installed_versions(&self) -> Vec<&RuntimeVersion> { - self.list_current_versions() + pub fn list_current_installed_versions(&self, config: &Config) -> Vec<&RuntimeVersion> { + self.list_current_versions(config) .into_iter() .filter(|v| v.is_installed()) .collect() } pub fn env_with_path(&self, config: &Config) -> IndexMap { - let (mut env, path_env) = - rayon::join(|| self.env(config), || self.path_env(&config.settings)); + let (mut env, path_env) = rayon::join(|| self.env(config), || self.path_env(config)); env.insert("PATH".to_string(), path_env); env } pub fn env(&self, config: &Config) -> IndexMap { let mut entries: IndexMap = self - .list_current_installed_versions() + .list_current_installed_versions(config) .into_par_iter() .flat_map(|v| match v.exec_env() { Ok(env) => env.clone().into_iter().collect(), @@ -290,17 +280,17 @@ impl Toolset { entries.extend(config.env.clone()); entries } - pub fn path_env(&self, settings: &Settings) -> String { - let installs = self.list_paths(settings); + pub fn path_env(&self, config: &Config) -> String { + let installs = self.list_paths(config); join_paths([installs, env::PATH.clone()].concat()) .unwrap() .to_string_lossy() .into() } - pub fn list_paths(&self, settings: &Settings) -> Vec { - self.list_current_installed_versions() + pub fn list_paths(&self, config: &Config) -> Vec { + self.list_current_installed_versions(config) .into_par_iter() - .flat_map(|rtv| match rtv.list_bin_paths(settings) { + .flat_map(|rtv| match rtv.list_bin_paths(&config.settings) { Ok(paths) => paths, Err(e) => { warn!("Error listing bin paths for {}: {}", rtv, e); @@ -374,11 +364,11 @@ impl Toolset { } } - pub fn which(&self, settings: &Settings, bin_name: &str) -> Option<&RuntimeVersion> { - self.list_current_installed_versions() + pub fn which(&self, config: &Config, bin_name: &str) -> Option<&RuntimeVersion> { + self.list_current_installed_versions(config) .into_par_iter() .find_first(|v| { - if let Ok(x) = v.which(settings, bin_name) { + if let Ok(x) = v.which(&config.settings, bin_name) { x.is_some() } else { false diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 6b9a077c8..398180f9b 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -18,7 +18,6 @@ pub struct ToolVersion { pub plugin_name: String, pub r#type: ToolVersionType, pub rtv: Option, - pub repo: Option, pub options: IndexMap, } @@ -37,7 +36,6 @@ impl ToolVersion { plugin_name, r#type, rtv: None, - repo: None, options: Default::default(), } } diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml index 7bf2418c2..a008eafce 100644 --- a/test/fixtures/.rtx.toml +++ b/test/fixtures/.rtx.toml @@ -4,13 +4,16 @@ NODE_ENV = 'production' [tools] terraform = '1.0.0' nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] -jq = { prefix = '1.6', repo = 'https://github.com/AZMCode/asdf-jq' } +jq = { prefix = '1.6' } shellcheck = { version = '0.9.0' } python = [ { version = '3.10.0', venv = '.venv' }, { version = '3.9.0' }, ] +[plugins] +nodejs = 'https://github.com/jdxcode/rtx-nodejs' + [settings] verbose = true missing_runtime_behavior = 'warn' From 0e88686f4fd5bc3b0bd9c6f5425e1b1209f05410 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 01:05:12 -0600 Subject: [PATCH 0367/1891] added plugin repository support in .rtx.toml (#249) --- .rtx.toml | 3 +++ src/cache.rs | 4 ++-- src/cli/external.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/install.rs | 2 +- src/cli/plugins/install.rs | 7 ++++--- src/cli/reshim.rs | 4 ++-- src/config/mod.rs | 14 +++++++++++-- src/env.rs | 2 +- src/fake_asdf.rs | 2 +- src/git.rs | 4 ++-- src/plugins/mod.rs | 23 +++++++++------------ src/shorthands.rs | 2 +- src/toolset/builder.rs | 2 +- src/toolset/mod.rs | 35 ++++++++++++++++---------------- src/toolset/tool_version_list.rs | 2 +- 16 files changed, 60 insertions(+), 50 deletions(-) diff --git a/.rtx.toml b/.rtx.toml index 29ee34bad..342b72ebd 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -5,3 +5,6 @@ FOO = "bar" nodejs = '18' tiny = {version="1", foo="bar"} golang = {version="latest", foo="bar"} + +[plugins] +nodejs = 'https://github.com/jdxcode/rtx-nodejs' diff --git a/src/cache.rs b/src/cache.rs index 2226917c8..fa18265aa 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -65,13 +65,13 @@ where match self.parse() { Ok(val) => return Ok::<_, color_eyre::Report>(val), Err(err) => { - warn!("failed to parse cache file: {} {}", path.display(), err); + warn!("failed to parse cache file: {} {:#}", path.display(), err); } } } let val = (fetch)()?; if let Err(err) = self.write(val.clone()) { - warn!("failed to write cache file: {} {}", path.display(), err); + warn!("failed to write cache file: {} {:#}", path.display(), err); } Ok(val) })?; diff --git a/src/cli/external.rs b/src/cli/external.rs index ca8313686..906abbc1a 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -15,7 +15,7 @@ pub fn commands(config: &Config) -> Vec { Ok(commands) => commands, Err(e) => { warn!( - "failed to load external commands for plugin {}: {}", + "failed to load external commands for plugin {}: {:#}", p.name, e ); vec![] diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 219dc3ced..4487f4a62 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -95,7 +95,7 @@ impl HookEnv { Ok(Some(op)) => { ops.push(op); } - Err(err) => warn!("failed to update DIRENV_DIFF: {}", err), + Err(err) => warn!("failed to update DIRENV_DIFF: {:#}", err), _ => {} } } diff --git a/src/cli/install.rs b/src/cli/install.rs index 2b2cf91c2..69e92b78d 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -104,7 +104,7 @@ impl Install { None => { let plugin = Plugin::new(&tv.plugin_name); let mut pr = mpr.add(); - match plugin.install(&config, None, &mut pr) { + match plugin.install(&config, &mut pr) { Ok(_) => Arc::new(plugin), Err(err) => { pr.error(); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 37ec80063..b92906d62 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -111,10 +111,11 @@ impl PluginsInstall { &self, config: &Config, name: &String, - git_url: &String, + git_url: &str, mpr: &MultiProgressReport, ) -> Result<()> { - let plugin = Plugin::new(name); + let mut plugin = Plugin::new(name); + plugin.repo_url = Some(git_url.to_string()); if !self.force && plugin.is_installed() { mpr.suspend(|| { warn!("plugin {} already installed", name); @@ -125,7 +126,7 @@ impl PluginsInstall { if self.force { plugin.uninstall(&pr)?; } - plugin.install(config, Some(git_url), &mut pr)?; + plugin.install(config, &mut pr)?; } Ok(()) } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 38266ebee..e74eddf37 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -80,7 +80,7 @@ fn make_symlink(target: &Path, link: &Path) -> Result<()> { fs::remove_file(link)?; } symlink(target, link)?; - debug!("symlinked {} to {}", target.display(), link.display()); + trace!("symlinked {} to {}", target.display(), link.display()); Ok(()) } @@ -103,7 +103,7 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { let mut perms = shim.metadata()?.permissions(); perms.set_mode(0o755); fs::set_permissions(shim, perms)?; - debug!( + trace!( "shim created from {} to {}", target.display(), shim.display() diff --git a/src/config/mod.rs b/src/config/mod.rs index 3d169633c..6690e89b9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -40,7 +40,7 @@ pub struct Config { impl Config { pub fn load() -> Result { - let plugins = load_plugins()?; + let mut plugins = load_plugins()?; let rtxrc = load_rtxrc()?; let mut settings = rtxrc.settings(); let config_filenames = load_config_filenames(&IndexMap::new()); @@ -73,6 +73,16 @@ impl Config { || hook_env::should_exit_early(&config_filenames), ); + for cf in config_files.values() { + for (plugin_name, repo_url) in cf.plugins() { + plugins.entry(plugin_name.clone()).or_insert_with(|| { + let mut plugin = Plugin::new(&plugin_name); + plugin.repo_url = Some(repo_url); + Arc::new(plugin) + }); + } + } + let config = Self { env: load_env(&config_files), aliases: load_aliases(&settings, &config_files), @@ -235,7 +245,7 @@ fn load_all_config_files( None => match parse_config_file(&f, settings, legacy_filenames, plugins) { Ok(cf) => Some((f, cf)), Err(err) => { - warn!("error parsing: {} {err}", f.display()); + warn!("error parsing: {} {:#}", f.display(), err); None } }, diff --git a/src/env.rs b/src/env.rs index 5f77e9b87..da99c98b8 100644 --- a/src/env.rs +++ b/src/env.rs @@ -138,7 +138,7 @@ fn get_env_diff() -> EnvDiff { let env = vars().collect::>(); match env.get("__RTX_DIFF") { Some(raw) => EnvDiff::deserialize(raw).unwrap_or_else(|err| { - warn!("Failed to deserialize __RTX_DIFF: {}", err); + warn!("Failed to deserialize __RTX_DIFF: {:#}", err); EnvDiff::default() }), None => EnvDiff::default(), diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index c1617ca61..5ce7a6ded 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -40,7 +40,7 @@ pub fn get_path_with_fake_asdf() -> String { path.push(fake_asdf_path.to_string_lossy().to_string()); } Err(e) => { - warn!("Failed to setup fake asdf: {}", e); + warn!("Failed to setup fake asdf: {:#}", e); } }; path.push(env::var("PATH").unwrap()); diff --git a/src/git.rs b/src/git.rs index 5ac3c16fd..736dff6b3 100644 --- a/src/git.rs +++ b/src/git.rs @@ -75,7 +75,7 @@ impl Git { match get_git_version() { Ok(version) => trace!("git version: {}", version), Err(err) => warn!( - "failed to get git version: {}\n Git is required to use rtx.", + "failed to get git version: {:#}\n Git is required to use rtx.", err ), } @@ -112,7 +112,7 @@ impl Git { } Err(err) => { warn!( - "failed to get remote url for {}: {}", + "failed to get remote url for {}: {:#}", self.dir.display(), err ); diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 95c086bbe..0f7d0a58f 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -36,6 +36,7 @@ pub type PluginName = String; pub struct Plugin { pub name: PluginName, pub plugin_path: PathBuf, + pub repo_url: Option, cache_path: PathBuf, downloads_path: PathBuf, installs_path: PathBuf, @@ -71,6 +72,7 @@ impl Plugin { .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), plugin_path, cache_path, + repo_url: None, } } @@ -90,14 +92,11 @@ impl Plugin { git.get_remote_url() } - pub fn install( - &self, - config: &Config, - repository: Option<&String>, - pr: &mut ProgressReport, - ) -> Result<()> { + pub fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { self.decorate_progress_bar(pr); - let repository = repository + let repository = self + .repo_url + .as_ref() .or_else(|| config.get_shorthands().get(&self.name)) .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; debug!("install {} {:?}", self.name, repository); @@ -226,12 +225,10 @@ impl Plugin { pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) - .with_context(|| { - format!( - "Failed listing remote versions for plugin {}", - style(&self.name).cyan().for_stderr() - ) - }) + .wrap_err(format!( + "Failed listing remote versions for plugin {}", + style(&self.name).cyan().for_stderr() + )) } pub fn get_aliases(&self, settings: &Settings) -> Result> { diff --git a/src/shorthands.rs b/src/shorthands.rs index 826b8f780..a6bfb90da 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -26,7 +26,7 @@ pub fn get_shorthands(settings: &Settings) -> Shorthands { shorthands.extend(custom); } Err(err) => { - warn!("Failed to read shorthands file: {} {}", &f.display(), err); + warn!("Failed to read shorthands file: {} {:#}", &f.display(), err); } } } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index e5bc9b536..e748a87cd 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -42,7 +42,7 @@ impl ToolsetBuilder { if self.install_missing { let mpr = MultiProgressReport::new(config.settings.verbose); if let Err(e) = toolset.install_missing(config, mpr) { - warn!("Error installing runtimes: {}", e); + warn!("Error installing runtimes: {:#}", e); }; } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index cddd01429..006802f32 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -73,9 +73,9 @@ impl Toolset { .par_iter_mut() .for_each(|(p, v)| { let plugin = match config.plugins.get(&p.to_string()) { - Some(p) => p, - None => { - debug!("Plugin {} not found", p); + Some(p) if p.is_installed() => p, + _ => { + debug!("Plugin {} is not installed", p); return; } }; @@ -176,23 +176,22 @@ impl Toolset { missing_plugins: Vec, mpr: &MultiProgressReport, ) -> Result<()> { - if missing_plugins.is_empty() { - return Ok(()); + for plugin in &missing_plugins { + config + .plugins + .entry(plugin.clone()) + .or_insert_with(|| Arc::new(Plugin::new(plugin))); } - let plugins = missing_plugins + config.plugins.sort_keys(); + missing_plugins .into_par_iter() - .map(|plugin_name| { - let plugin = Plugin::new(&plugin_name); - if !plugin.is_installed() { - plugin.install(config, None, &mut mpr.add())?; - } - Ok(plugin) + .map(|p| config.plugins.get(&p).unwrap()) + .filter(|p| !p.is_installed()) + .map(|p| { + let mut pr = mpr.add(); + p.install(config, &mut pr) }) .collect::>>()?; - for plugin in plugins { - config.plugins.insert(plugin.name.clone(), Arc::new(plugin)); - } - config.plugins.sort_keys(); Ok(()) } @@ -268,7 +267,7 @@ impl Toolset { .flat_map(|v| match v.exec_env() { Ok(env) => env.clone().into_iter().collect(), Err(e) => { - warn!("Error running exec-env: {}", e); + warn!("Error running exec-env: {:#}", e); Vec::new() } }) @@ -293,7 +292,7 @@ impl Toolset { .flat_map(|rtv| match rtv.list_bin_paths(&config.settings) { Ok(paths) => paths, Err(e) => { - warn!("Error listing bin paths for {}: {}", rtv, e); + warn!("Error listing bin paths for {}: {:#}", rtv, e); Vec::new() } }) diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 0e3981813..a45d69d66 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -38,7 +38,7 @@ impl ToolVersionList { } } Err(err) => { - warn!("failed to resolve tool version: {}", err); + warn!("failed to resolve tool version: {:#}", err); return; } } From f211decbc9d125f0ace05fae8c02909154905b67 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 02:25:29 -0600 Subject: [PATCH 0368/1891] make config.toml the same as .rtx.toml (#250) --- .rtx.toml | 3 + README.md | 3 +- src/cli/alias/set.rs | 14 +- src/cli/alias/unset.rs | 11 +- ...i__direnv__envrc__tests__direnv_envrc.snap | 1 + src/cli/plugins/install.rs | 2 +- src/cli/settings/set.rs | 7 +- src/cli/settings/unset.rs | 7 +- src/config/config_file/mod.rs | 20 +- src/config/config_file/rtx_toml.rs | 104 ++- src/config/config_file/rtxrc.rs | 696 ------------------ ...nfig_file__rtx_toml__tests__fixture-2.snap | 1 - src/config/mod.rs | 61 +- src/config/settings.rs | 9 - .../snapshots/rtx__config__tests__load.snap | 2 +- src/plugins/script_manager.rs | 106 ++- src/runtimes.rs | 5 + test/config/config.toml | 1 + 18 files changed, 235 insertions(+), 818 deletions(-) delete mode 100644 src/config/config_file/rtxrc.rs diff --git a/.rtx.toml b/.rtx.toml index 342b72ebd..374fd641b 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -8,3 +8,6 @@ golang = {version="latest", foo="bar"} [plugins] nodejs = 'https://github.com/jdxcode/rtx-nodejs' + +[alias.tiny] +abc = '1' diff --git a/README.md b/README.md index e8cb28576..6f343feb1 100644 --- a/README.md +++ b/README.md @@ -538,6 +538,7 @@ You may not even notice. rtx can be configured in `~/.config/rtx/config.toml`. The following options are available (defaults shown): ```toml +[settings] # whether to prompt to install plugins and runtimes if they're not already installed missing_runtime_behavior = 'prompt' # other options: 'ignore', 'warn', 'prompt', 'autoinstall' @@ -1389,7 +1390,7 @@ Install a plugin note that rtx automatically can install plugins when you install a runtime e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin -This behavior can be modified in ~/.rtx/config.toml +This behavior can be modified in ~/.config/rtx/config.toml Usage: install [OPTIONS] [NAME] [GIT_URL] diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 442ae7c80..82904c383 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -23,11 +23,11 @@ pub struct AliasSet { } impl Command for AliasSet { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let rtxrc = config.rtxrc; - - rtxrc.set_alias(&self.plugin, &self.alias, &self.value)?; - rtxrc.save() + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + config + .global_config + .set_alias(&self.plugin, &self.alias, &self.value); + config.global_config.save() } } @@ -40,10 +40,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] pub mod tests { - - use crate::{assert_cli, assert_cli_snapshot}; - use crate::test::reset_config; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_alias_set() { diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index ded47dac6..01afbbdde 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -21,10 +21,9 @@ pub struct AliasUnset { } impl Command for AliasUnset { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let rtxrc = config.rtxrc; - rtxrc.remove_alias(&self.plugin, &self.alias)?; - rtxrc.save() + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + config.global_config.remove_alias(&self.plugin, &self.alias); + config.global_config.save() } } @@ -37,10 +36,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - - use crate::{assert_cli, assert_cli_snapshot}; - use crate::test::reset_config; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_settings_unset() { diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index 745c60e55..d5cee519e 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -5,6 +5,7 @@ expression: envrc ### Do not edit. This was autogenerated by 'asdf direnv envrc' ### watch_file ~/cwd/.test-tool-versions watch_file ~/.test-tool-versions +watch_file ~/config/config.toml export JDXCODE_TINY=3.1.0 PATH_add ~/data/installs/dummy/ref-master/bin PATH_add ~/data/installs/tiny/3.1.0/bin diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index b92906d62..34d60d7b0 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -18,7 +18,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// note that rtx automatically can install plugins when you install a runtime /// e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin /// -/// This behavior can be modified in ~/.rtx/config.toml +/// This behavior can be modified in ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] #[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct PluginsInstall { diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index e0a3450c2..1272bcc1f 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -21,8 +21,7 @@ pub struct SettingsSet { } impl Command for SettingsSet { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let rtxrc = config.rtxrc; + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let value: toml_edit::Value = match self.key.as_str() { "experimental" => parse_bool(&self.value)?, "missing_runtime_behavior" => self.value.into(), @@ -39,8 +38,8 @@ impl Command for SettingsSet { _ => return Err(eyre!("Unknown setting: {}", self.key)), }; - rtxrc.update_setting(&self.key, value)?; - rtxrc.save() + config.global_config.update_setting(&self.key, value); + config.global_config.save() } } diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index a08a02c96..0283c843f 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -19,10 +19,9 @@ pub struct SettingsUnset { } impl Command for SettingsUnset { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let rtxrc = config.rtxrc; - rtxrc.remove_setting(&self.key)?; - rtxrc.save() + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + config.global_config.remove_setting(&self.key); + config.global_config.save() } } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 569066a77..486934ce1 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -4,7 +4,6 @@ use std::path::Path; use color_eyre::eyre::{eyre, Result}; -use rtxrc::RTXFile; use tool_versions::ToolVersions; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; @@ -20,12 +19,10 @@ use crate::ui::multi_progress_report::MultiProgressReport; pub mod legacy_version; pub mod rtx_toml; -pub mod rtxrc; pub mod tool_versions; #[derive(Debug, PartialEq)] pub enum ConfigFileType { - RtxRc, RtxToml, ToolVersions, LegacyVersion, @@ -126,9 +123,7 @@ impl dyn ConfigFile { } pub fn init(path: &Path) -> Box { - if path.ends_with(".rtxrc") || path.ends_with(".rtxrc.toml") { - return Box::new(RTXFile::init(path)); - } else if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) { + if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) { return Box::new(RtxToml::init(path)); } else if path.ends_with(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) { return Box::new(ToolVersions::init(path)); @@ -140,16 +135,15 @@ pub fn init(path: &Path) -> Box { pub fn parse(path: &Path) -> Result> { match detect_config_file_type(path) { Some(ConfigFileType::RtxToml) => Ok(Box::new(RtxToml::from_file(path)?)), - Some(ConfigFileType::RtxRc) => Ok(Box::new(RTXFile::from_file(path)?)), Some(ConfigFileType::ToolVersions) => Ok(Box::new(ToolVersions::from_file(path)?)), #[allow(clippy::box_default)] - _ => Ok(Box::new(RTXFile::default())), + _ => Ok(Box::new(RtxToml::default())), } } fn detect_config_file_type(path: &Path) -> Option { match path.file_name().unwrap().to_str().unwrap() { - ".rtxrc" | ".rtxrc.toml" | "config.toml" => Some(ConfigFileType::RtxRc), + "config.toml" => Some(ConfigFileType::RtxToml), f if env::RTX_DEFAULT_CONFIG_FILENAME.as_str() == f => Some(ConfigFileType::RtxToml), f if env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() == f => { Some(ConfigFileType::ToolVersions) @@ -164,14 +158,6 @@ mod tests { #[test] fn test_detect_config_file_type() { - assert_eq!( - detect_config_file_type(Path::new("/foo/bar/.rtxrc")), - Some(ConfigFileType::RtxRc) - ); - assert_eq!( - detect_config_file_type(Path::new("/foo/bar/.rtxrc.toml")), - Some(ConfigFileType::RtxRc) - ); assert_eq!( detect_config_file_type(Path::new("/foo/bar/.test-tool-versions")), Some(ConfigFileType::ToolVersions) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index aa27e08cb..f3e83ad3e 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -12,6 +12,7 @@ use toml_edit::{table, value, Array, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, MissingRuntimeBehavior}; +use crate::file::create_dir_all; use crate::plugins::PluginName; use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; @@ -63,6 +64,16 @@ impl RtxToml { .parse() } + pub fn migrate(path: &Path) -> Result { + // attempt to read as new .rtx.toml syntax + let mut raw = String::from("[settings]\n"); + raw.push_str(&fs::read_to_string(path)?); + let mut toml = RtxToml::from_str(raw)?; + toml.path = path.to_path_buf(); + toml.save()?; + Ok(toml) + } + fn parse(mut self) -> Result { for (k, v) in self.doc.iter() { match k { @@ -71,7 +82,7 @@ impl RtxToml { "tools" => self.toolset = self.parse_toolset(k, v)?, "settings" => self.settings = self.parse_settings(k, v)?, "plugins" => self.plugins = self.parse_hashmap(k, v)?, - _ => warn!("unknown key: {}", k), + _ => Err(eyre!("unknown key: {}", k))?, } } Ok(self) @@ -295,7 +306,7 @@ impl RtxToml { "log_level" => settings.log_level = Some(self.parse_log_level(&k, v)?), "shims_dir" => settings.shims_dir = Some(self.parse_path(&k, v)?), "raw" => settings.raw = Some(self.parse_bool(&k, v)?), - _ => parse_error!(k, v, "setting")?, + _ => Err(eyre!("Unknown config setting: {}", k))?, }; } } @@ -305,7 +316,7 @@ impl RtxToml { Ok(settings) } - fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { + pub(crate) fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { self.alias .entry(plugin.into()) .or_default() @@ -322,7 +333,7 @@ impl RtxToml { .insert(from, value(to)); } - pub fn remove_alias(&mut self, plugin: &str, from: &str) -> Result<()> { + pub fn remove_alias(&mut self, plugin: &str, from: &str) { if let Some(aliases) = self.doc.get_mut("alias").and_then(|v| v.as_table_mut()) { if let Some(plugin_aliases) = aliases.get_mut(plugin).and_then(|v| v.as_table_mut()) { self.alias.get_mut(plugin).unwrap().remove(from); @@ -336,7 +347,6 @@ impl RtxToml { self.doc.as_table_mut().remove("alias"); } } - Ok(()) } fn parse_duration_minutes(&self, k: &str, v: &Item) -> Result { @@ -392,6 +402,53 @@ impl RtxToml { let level = self.parse_string(k, v)?.parse()?; Ok(level) } + + pub fn update_setting>(&mut self, key: &str, value: V) { + let key = key.split('.').collect::>(); + let mut settings = self + .doc + .entry("settings") + .or_insert_with(table) + .as_table_like_mut() + .unwrap(); + for (i, k) in key.iter().enumerate() { + if i == key.len() - 1 { + settings.insert(k, toml_edit::value(value)); + break; + } else { + settings = settings + .entry(k) + .or_insert(toml_edit::table()) + .as_table_mut() + .unwrap(); + } + } + } + + pub fn remove_setting(&mut self, key: &str) { + let mut settings = self + .doc + .entry("settings") + .or_insert_with(table) + .as_table_like_mut() + .unwrap(); + let key = key.split('.').collect::>(); + for (i, k) in key.iter().enumerate() { + if i == key.len() - 1 { + settings.remove(k); + break; + } else { + settings = settings + .entry(k) + .or_insert(toml_edit::table()) + .as_table_mut() + .unwrap(); + } + } + if settings.is_empty() { + self.doc.as_table_mut().remove("settings"); + } + } } impl Display for RtxToml { @@ -456,6 +513,9 @@ impl ConfigFile for RtxToml { fn save(&self) -> Result<()> { let contents = self.dump(); + if let Some(parent) = self.path.parent() { + create_dir_all(parent)?; + } Ok(fs::write(&self.path, contents)?) } @@ -548,8 +608,8 @@ mod tests { "3.10" = "3.10.0" "#}) .unwrap(); - cf.remove_alias("nodejs", "16").unwrap(); - cf.remove_alias("python", "3.10").unwrap(); + cf.remove_alias("nodejs", "16"); + cf.remove_alias("python", "3.10"); assert_debug_snapshot!(cf.alias); assert_display_snapshot!(cf); @@ -583,4 +643,34 @@ mod tests { assert_debug_snapshot!(cf.toolset); assert_display_snapshot!(cf); } + + #[test] + fn test_update_setting() { + let mut cf = RtxToml::from_str(formatdoc! {r#" + [settings] + legacy_version_file = true + [alias.nodejs] + 18 = "18.0.0" + "#}) + .unwrap(); + cf.update_setting("legacy_version_file", false); + assert_display_snapshot!(cf.dump(), @r###" + [settings] + legacy_version_file = false + [alias.nodejs] + 18 = "18.0.0" + "###); + } + + #[test] + fn test_remove_setting() { + let mut cf = RtxToml::from_str(formatdoc! {r#" + [settings] + legacy_version_file = true + "#}) + .unwrap(); + cf.remove_setting("legacy_version_file"); + assert_display_snapshot!(cf.dump(), @r###" + "###); + } } diff --git a/src/config/config_file/rtxrc.rs b/src/config/config_file/rtxrc.rs deleted file mode 100644 index 821b45469..000000000 --- a/src/config/config_file/rtxrc.rs +++ /dev/null @@ -1,696 +0,0 @@ -use std::collections::HashMap; -use std::fmt::{Display, Formatter}; -use std::fs; -use std::path::{Path, PathBuf}; -use std::sync::Mutex; -use std::time::Duration; - -use color_eyre::eyre::{eyre, Context}; -use color_eyre::{Result, Section, SectionExt}; -use indexmap::IndexMap; -use log::LevelFilter; -use once_cell::sync::OnceCell; -use toml::Value; - -use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::settings::{MissingRuntimeBehavior, SettingsBuilder}; -use crate::config::AliasMap; -use crate::plugins::PluginName; -use crate::toolset::Toolset; - -const ENV_SUGGESTION: &str = r#" -[env] -FOO = "bar" -"#; - -#[derive(Debug, Default)] -pub struct RTXFile { - pub path: PathBuf, - pub plugins: IndexMap, - pub env: HashMap, - pub settings: SettingsBuilder, - edit: OnceCell>, -} - -#[derive(Debug, PartialEq, Eq, Hash, Default)] -pub struct Plugin { - pub name: String, - pub versions: Vec, -} - -impl RTXFile { - pub fn init(filename: &Path) -> RTXFile { - RTXFile { - path: filename.to_path_buf(), - ..Default::default() - } - } - - pub fn from_file(filename: &Path) -> Result { - trace!("parsing rtxrc: {}", filename.display()); - let body = fs::read_to_string(filename).suggestion("ensure file exists and can be read")?; - let mut rf = RTXFile::from_str(body).wrap_err("error parsing toml")?; - rf.path = filename.into(); - - Ok(rf) - } - - pub fn from_str(s: String) -> Result { - let mut rf = RTXFile::default(); - - match s - .parse::() - .suggestion("Ensure .rtxrc is valid TOML.")? - { - Value::Table(table) => { - for (k, v) in table.iter() { - rf.parse_toplevel_key(k, v) - .with_section(|| format!("[{k}]\n{v}").header("TOML:"))?; - } - Ok(()) - } - _ => Err(eyre!("Invalid TOML: {}", s)), - }?; - - Ok(rf) - } - - pub fn settings(&self) -> SettingsBuilder { - self.settings.clone() - } - - fn parse_toplevel_key(&mut self, k: &String, v: &Value) -> Result<()> { - match k.to_lowercase().as_str() { - "env" => self.parse_env(v).with_suggestion(|| ENV_SUGGESTION)?, - "experimental" => self.settings.experimental = Some(self.parse_bool(k, v)?), - "missing_runtime_behavior" => { - self.settings.missing_runtime_behavior = - Some(self.parse_missing_runtime_behavior(v)?) - } - "legacy_version_file" => { - self.settings.legacy_version_file = Some(self.parse_bool(k, v)?) - } - "always_keep_download" => { - self.settings.always_keep_download = Some(self.parse_bool(k, v)?) - } - "plugin_autoupdate_last_check_duration" => { - self.settings.plugin_autoupdate_last_check_duration = - Some(self.parse_duration_minutes(k, v)?) - } - "verbose" => self.settings.verbose = Some(self.parse_bool(k, v)?), - "asdf_compat" => self.settings.asdf_compat = Some(self.parse_bool(k, v)?), - "jobs" => self.settings.jobs = Some(self.parse_usize(k, v)?), - "shorthands_file" => self.settings.shorthands_file = Some(self.parse_path(k, v)?), - "disable_default_shorthands" => { - self.settings.disable_default_shorthands = Some(self.parse_bool(k, v)?) - } - "log_level" => self.settings.log_level = Some(self.parse_log_level(v)?), - "shims_dir" => self.settings.shims_dir = Some(self.parse_path(k, v)?), - "raw" => self.settings.raw = Some(self.parse_bool(k, v)?), - "alias" => self.settings.aliases = Some(self.parse_aliases(v)?), - "get_path" => {} - "disable_plugin_short_name_repository" => {} - "plugin_repository_last_check_duration" => {} - _ => self.parse_plugin(k, v)?, - }; - Ok(()) - } - - fn parse_env(&mut self, v: &Value) -> Result<()> { - match v { - Value::Table(table) => { - for (k, v) in table.iter() { - match v { - Value::String(s) => { - self.env.insert(k.into(), s.into()); - } - _ => Err(eyre!("expected [env] value to be a string, got: {v}"))?, - } - } - Ok(()) - } - _ => Err(eyre!("expected [env] to be a table, got: {v}")), - } - } - - fn parse_plugin(&mut self, k: &String, v: &Value) -> Result<()> { - let versions = self.parse_plugin_versions(v)?; - self.plugins.insert( - k.into(), - Plugin { - name: k.into(), - versions, - }, - ); - Ok(()) - } - - fn parse_plugin_versions(&self, v: &Value) -> Result> { - match v { - Value::String(s) => Ok(vec![s.to_string()]), - Value::Array(a) => a - .iter() - .map(|v| match v { - Value::String(s) => Ok(s.to_string()), - _ => Err(eyre!("Invalid TOML: {}", v)), - }) - .collect(), - Value::Table(t) => t - .iter() - // TODO: from_file value - .map(|(k, _v)| Ok(k.into())) - .collect(), - _ => Err(eyre!( - "expected plugin to be a string, array, or table, got: {v}" - )), - } - } - - fn parse_duration_minutes(&self, k: &str, v: &Value) -> Result { - match v { - Value::Integer(i) => { - let duration = Duration::from_secs(*i as u64 * 60); - Ok(duration) - } - _ => Err(eyre!("expected {k} to be an integer, got: {v}")), - } - } - - fn parse_bool(&self, k: &str, v: &Value) -> Result { - match v { - Value::Boolean(v) => Ok(*v), - _ => Err(eyre!("expected {k} to be a boolean, got: {v}")), - } - } - - fn parse_usize(&self, k: &str, v: &Value) -> Result { - match v { - Value::Integer(v) => Ok(*v as usize), - _ => Err(eyre!("expected {k} to be an integer, got: {v}")), - } - } - - fn parse_path(&self, k: &str, v: &Value) -> Result { - match v { - Value::String(v) => Ok(v.into()), - _ => Err(eyre!("expected {k} to be a path, got: {v}")), - } - } - - fn parse_string(&self, k: &str, v: &Value) -> Result { - match v { - Value::String(v) => Ok(v.clone()), - _ => Err(eyre!("expected {k} to be a string, got: {v}")), - } - } - - fn parse_missing_runtime_behavior(&self, v: &Value) -> Result { - let v = self.parse_string("missing_runtime_behavior", v)?; - match v.to_lowercase().as_str() { - "warn" => Ok(MissingRuntimeBehavior::Warn), - "ignore" => Ok(MissingRuntimeBehavior::Ignore), - "prompt" => Ok(MissingRuntimeBehavior::Prompt), - "autoinstall" => Ok(MissingRuntimeBehavior::AutoInstall), - _ => Err(eyre!("expected missing_runtime_behavior to be one of: 'warn', 'ignore', 'prompt', 'autoinstall'. Got: {v}")), - } - } - - fn parse_log_level(&self, v: &Value) -> Result { - let level = self.parse_string("log_level", v)?.parse()?; - Ok(level) - } - - fn parse_aliases(&self, v: &Value) -> Result { - match v { - Value::Table(table) => { - let mut aliases = AliasMap::new(); - for (plugin, table) in table.iter() { - let plugin_aliases = aliases.entry(plugin.into()).or_default(); - match table { - Value::Table(table) => { - for (from, to) in table.iter() { - match to { - Value::String(s) => { - plugin_aliases.insert(from.into(), s.into()); - } - _ => Err(eyre!( - "expected [aliases] value to be a string, got: {v}" - ))?, - } - } - } - _ => Err(eyre!("expected [aliases] value to be a table, got: {v}"))?, - } - } - Ok(aliases) - } - _ => Err(eyre!("expected [aliases] to be a table, got: {v}")), - } - } - - fn get_edit(&self) -> Result<&Mutex> { - self.edit.get_or_try_init(|| { - if !self.path.exists() { - let dir = self.path.parent().unwrap(); - fs::create_dir_all(dir)?; - fs::write(&self.path, "")?; - } - let body = - fs::read_to_string(&self.path).suggestion("ensure file exists and can be read")?; - let edit = body.parse::()?; - Ok(Mutex::new(edit)) - }) - } - - pub fn update_setting>(&self, key: &str, value: V) -> Result<()> { - let mut doc = self.get_edit()?.lock().unwrap(); - let key = key.split('.').collect::>(); - let mut table = doc.as_table_mut(); - for (i, k) in key.iter().enumerate() { - if i == key.len() - 1 { - table[k] = toml_edit::value(value); - break; - } else { - table = table - .entry(k) - .or_insert(toml_edit::table()) - .as_table_mut() - .unwrap(); - } - } - Ok(()) - } - - pub fn remove_setting(&self, key: &str) -> Result<()> { - let mut doc = self.get_edit()?.lock().unwrap(); - let key = key.split('.').collect::>(); - let mut table = doc.as_table_mut(); - for (i, k) in key.iter().enumerate() { - if i == key.len() - 1 { - table.remove(k); - break; - } else { - table = table - .entry(k) - .or_insert(toml_edit::table()) - .as_table_mut() - .unwrap(); - } - } - Ok(()) - } - - pub fn set_alias(&self, plugin: &str, from: &str, to: &str) -> Result<()> { - let mut doc = self.get_edit()?.lock().unwrap(); - let aliases = doc - .as_table_mut() - .entry("alias") - .or_insert(toml_edit::table()) - .as_table_mut() - .unwrap(); - let plugin_aliases = aliases - .entry(plugin) - .or_insert(toml_edit::table()) - .as_table_mut() - .unwrap(); - plugin_aliases[from] = toml_edit::value(to); - Ok(()) - } - - pub fn remove_alias(&self, plugin: &str, from: &str) -> Result<()> { - let mut doc = self.get_edit()?.lock().unwrap(); - if let Some(aliases) = doc.get_mut("alias").and_then(|v| v.as_table_mut()) { - if let Some(plugin_aliases) = aliases.get_mut(plugin).and_then(|v| v.as_table_mut()) { - plugin_aliases.remove(from); - if plugin_aliases.is_empty() { - aliases.remove(plugin); - } - } - if aliases.is_empty() { - doc.as_table_mut().remove("alias"); - } - } - Ok(()) - } - - fn add_version(&mut self, plugin: &PluginName, version: &str) { - self.plugins - .entry(plugin.into()) - .or_default() - .versions - .push(version.to_string()); - - self.get_edit() - .unwrap() - .lock() - .unwrap() - .entry(plugin) - .or_insert_with(toml_edit::array) - .as_array_mut() - .unwrap() - .push(version); - } -} - -impl Display for RTXFile { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.dump()) - } -} - -impl ConfigFile for RTXFile { - fn get_type(&self) -> ConfigFileType { - ConfigFileType::RtxRc - } - - fn get_path(&self) -> &Path { - self.path.as_path() - } - - fn plugins(&self) -> HashMap { - Default::default() - } - - fn env(&self) -> HashMap { - self.env.clone() - } - - fn remove_plugin(&mut self, plugin: &PluginName) { - self.plugins.remove(plugin); - self.get_edit() - .unwrap() - .lock() - .unwrap() - .as_table_mut() - .remove(plugin); - } - - fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { - let plugin = self.plugins.entry(plugin_name.into()).or_default(); - plugin.versions.clear(); - self.get_edit() - .unwrap() - .lock() - .unwrap() - .entry(plugin_name) - .or_insert_with(toml_edit::array) - .as_array_mut() - .unwrap() - .clear(); - for version in versions { - self.add_version(plugin_name, version); - } - } - - fn save(&self) -> Result<()> { - let contents = self.dump(); - Ok(fs::write(&self.path, contents)?) - } - - fn dump(&self) -> String { - self.get_edit().unwrap().lock().unwrap().to_string() - } - - fn to_toolset(&self) -> &Toolset { - todo!() - } - - fn settings(&self) -> SettingsBuilder { - SettingsBuilder::default() - } - - fn aliases(&self) -> AliasMap { - AliasMap::default() - } -} - -#[cfg(test)] -mod tests { - use std::io::*; - - use indoc::writedoc; - use insta::assert_display_snapshot; - use pretty_assertions::assert_eq; - - use super::*; - - #[test] - fn test_from_str() { - let cf = RTXFile::from_str( - r#" -nodejs = ["18.0.0", "20.0.0"] -"# - .to_string(), - ) - .unwrap(); - - assert_eq!(cf.plugins.len(), 1); - assert!(cf.plugins.contains_key("nodejs")); - assert_eq!(cf.plugins["nodejs"].versions, vec!["18.0.0", "20.0.0"]); - } - - #[test] - fn test_parse() { - let mut f = tempfile::NamedTempFile::new().unwrap(); - writedoc!( - f, - r#" - nodejs = ["18.0.0", "20.0.0"] # comments - "# - ) - .unwrap(); - let cf = RTXFile::from_file(f.path()).unwrap(); - - assert_eq!(cf.plugins.len(), 1); - assert!(cf.plugins.contains_key("nodejs")); - assert_eq!(cf.plugins["nodejs"].versions, vec!["18.0.0", "20.0.0"]); - assert_display_snapshot!(cf, @r###" - nodejs = ["18.0.0", "20.0.0"] # comments - "###); - } - - #[test] - fn test_single_version() { - let cf = RTXFile::from_str( - r#" -nodejs = "18.0.0" -"# - .to_string(), - ) - .unwrap(); - - assert_eq!(cf.plugins.len(), 1); - assert!(cf.plugins.contains_key("nodejs")); - assert_eq!(cf.plugins["nodejs"].versions, vec!["18.0.0"]); - } - - #[test] - fn test_plugin_hash() { - let cf = RTXFile::from_str( - r#" -[nodejs.20] -packages = ["urchin"] -"# - .to_string(), - ) - .unwrap(); - - assert_eq!(cf.plugins.len(), 1); - assert!(cf.plugins.contains_key("nodejs")); - assert_eq!(cf.plugins["nodejs"].versions, vec!["20"]); - } - - #[test] - fn test_env() { - let cf = RTXFile::from_str( - r#" -[env] -foo="bar" -"# - .to_string(), - ) - .unwrap(); - - assert_eq!(cf.env["foo"], "bar"); - } - - #[test] - fn test_invalid_env() { - let err = RTXFile::from_str( - r#" -env=[1,2,3] -"# - .to_string(), - ) - .unwrap_err(); - - assert_display_snapshot!(err, @"expected [env] to be a table, got: [1, 2, 3]"); - } - - #[test] - fn test_invalid_env_value() { - let err = RTXFile::from_str( - r#" -[env] -foo=[1,2,3] -"# - .to_string(), - ) - .unwrap_err(); - - assert_display_snapshot!(err, @"expected [env] value to be a string, got: [1, 2, 3]"); - } - - #[test] - fn test_invalid_plugin() { - let err = RTXFile::from_str( - r#" -nodejs=1 -"# - .to_string(), - ) - .unwrap_err(); - - assert_display_snapshot!(err, @"expected plugin to be a string, array, or table, got: 1"); - } - - #[test] - fn test_invalid_plugin_2() { - let err = RTXFile::from_str( - r#" -nodejs=[true] -"# - .to_string(), - ) - .unwrap_err(); - - assert_display_snapshot!(err, @"Invalid TOML: true"); - } - - #[test] - fn test_update_setting() { - let mut f = tempfile::NamedTempFile::new().unwrap(); - writedoc!( - f, - r#" - legacy_version_file = true - [aliases.nodejs] - 18 = "18.0.0" - "# - ) - .unwrap(); - let cf = RTXFile::from_file(f.path()).unwrap(); - cf.update_setting("legacy_version_file", false).unwrap(); - cf.update_setting("something_else", "foo").unwrap(); - cf.update_setting("something.nested.very.deeply", 123) - .unwrap(); - cf.update_setting("aliases.nodejs.20", "20.0.0").unwrap(); - cf.update_setting("aliases.python.3", "3.9.0").unwrap(); - assert_display_snapshot!(cf.dump(), @r###" - legacy_version_file = false - something_else = "foo" - [aliases.nodejs] - 18 = "18.0.0" - 20 = "20.0.0" - - [aliases.python] - 3 = "3.9.0" - - [something] - - [something.nested] - - [something.nested.very] - deeply = 123 - "###); - } - - #[test] - fn test_remove_setting() { - let mut f = tempfile::NamedTempFile::new().unwrap(); - writedoc!( - f, - r#" - [something] - - [something.nested] - other = "foo" - - [something.nested.very] - deeply = 123 - "# - ) - .unwrap(); - let cf = RTXFile::from_file(f.path()).unwrap(); - cf.remove_setting("something.nested.other").unwrap(); - assert_display_snapshot!(cf.dump(), @r###" - [something] - - [something.nested] - - [something.nested.very] - deeply = 123 - "###); - } - - #[test] - fn test_set_alias() { - let mut f = tempfile::NamedTempFile::new().unwrap(); - writedoc!( - f, - r#" - [alias.nodejs] - 16 = "16.0.0" - 18 = "18.0.0" - "# - ) - .unwrap(); - let cf = RTXFile::from_file(f.path()).unwrap(); - cf.set_alias("nodejs", "18", "18.0.1").unwrap(); - cf.set_alias("nodejs", "20", "20.0.0").unwrap(); - cf.set_alias("python", "3.10", "3.10.0").unwrap(); - assert_display_snapshot!(cf.dump(), @r###" - [alias.nodejs] - 16 = "16.0.0" - 18 = "18.0.1" - 20 = "20.0.0" - - [alias.python] - "3.10" = "3.10.0" - "###); - } - - #[test] - fn test_remove_alias() { - let mut f = tempfile::NamedTempFile::new().unwrap(); - writedoc!( - f, - r#" - [alias.nodejs] - 16 = "16.0.0" - 18 = "18.0.0" - - [alias.python] - "3.10" = "3.10.0" - "# - ) - .unwrap(); - let cf = RTXFile::from_file(f.path()).unwrap(); - cf.remove_alias("nodejs", "16").unwrap(); - cf.remove_alias("python", "3.10").unwrap(); - - assert_display_snapshot!(cf.dump(), @r###" - [alias.nodejs] - 18 = "18.0.0" - "###); - } - - #[test] - fn test_edit_when_file_does_not_exist() { - let mut cf = RTXFile::from_str("".to_string()).unwrap(); - let dir = tempfile::tempdir().unwrap(); - cf.path = dir.path().join("subdir").join("does-not-exist.toml"); - cf.set_alias("nodejs", "18", "18.0.1").unwrap(); - cf.save().unwrap(); - } -} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 7c55720bd..0d7bb7109 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -8,7 +8,6 @@ SettingsBuilder { always_keep_download: None, legacy_version_file: None, plugin_autoupdate_last_check_duration: None, - aliases: None, verbose: None, asdf_compat: None, jobs: None, diff --git a/src/config/mod.rs b/src/config/mod.rs index 6690e89b9..c1057ae75 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -13,8 +13,9 @@ use rayon::prelude::*; pub use settings::{MissingRuntimeBehavior, Settings}; use crate::config::config_file::legacy_version::LegacyVersionFile; -use crate::config::config_file::rtxrc::RTXFile; +use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::ConfigFile; +use crate::config::settings::SettingsBuilder; use crate::plugins::{Plugin, PluginName}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::{dirs, env, file, hook_env}; @@ -27,7 +28,7 @@ type AliasMap = IndexMap>; #[derive(Debug, Default)] pub struct Config { pub settings: Settings, - pub rtxrc: RTXFile, + pub global_config: RtxToml, pub legacy_files: IndexMap, pub config_files: IndexMap>, pub plugins: IndexMap>, @@ -41,8 +42,8 @@ pub struct Config { impl Config { pub fn load() -> Result { let mut plugins = load_plugins()?; - let rtxrc = load_rtxrc()?; - let mut settings = rtxrc.settings(); + let global_config = load_rtxrc()?; + let mut settings = SettingsBuilder::default(); let config_filenames = load_config_filenames(&IndexMap::new()); let config_files = load_all_config_files( &settings.build(), @@ -55,7 +56,7 @@ impl Config { settings.merge(cf.settings()); } let settings = settings.build(); - trace!("Settings: {:#?}", rtxrc.settings()); + trace!("Settings: {:#?}", settings); let legacy_files = load_legacy_files(&settings, &plugins); let config_filenames = load_config_filenames(&legacy_files); @@ -85,13 +86,13 @@ impl Config { let config = Self { env: load_env(&config_files), - aliases: load_aliases(&settings, &config_files), + aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), shorthands: OnceCell::new(), config_files, settings, legacy_files, - rtxrc, + global_config, plugins, should_exit_early, }; @@ -153,16 +154,26 @@ impl Config { } } -fn load_rtxrc() -> Result { +fn load_rtxrc() -> Result { let settings_path = dirs::CONFIG.join("config.toml"); - let rtxrc = if !settings_path.exists() { - trace!("settings does not exist {:?}", settings_path); - RTXFile::init(&settings_path) - } else { - RTXFile::from_file(&settings_path).wrap_err_with(|| err_load_settings(&settings_path))? - }; - - Ok(rtxrc) + match settings_path.exists() { + false => { + trace!("settings does not exist {:?}", settings_path); + Ok(RtxToml::init(&settings_path)) + } + true => match RtxToml::from_file(&settings_path) + .wrap_err_with(|| err_load_settings(&settings_path)) + { + Ok(cf) => Ok(cf), + Err(err) => match RtxToml::migrate(&settings_path) { + Ok(cf) => Ok(cf), + Err(e) => { + error!("Error migrating config.toml: {:#}", e); + Err(err) + } + }, + }, + } } fn load_plugins() -> Result>> { @@ -221,6 +232,10 @@ fn load_config_filenames(legacy_filenames: &IndexMap) -> Vec if home_config.is_file() { config_files.push(home_config); } + let global_config = dirs::CONFIG.join("config.toml"); + if global_config.is_file() { + config_files.push(global_config); + } config_files.into_iter().unique().collect() } @@ -277,21 +292,9 @@ fn load_env(config_files: &IndexMap>) -> IndexMap>, -) -> AliasMap { +fn load_aliases(config_files: &IndexMap>) -> AliasMap { let mut aliases: AliasMap = IndexMap::new(); - for (plugin, plugin_aliases) in &settings.aliases { - for (from, to) in plugin_aliases { - aliases - .entry(plugin.clone()) - .or_insert_with(IndexMap::new) - .insert(from.clone(), to.clone()); - } - } - for config_file in config_files.values() { for (plugin, plugin_aliases) in config_file.aliases() { for (from, to) in plugin_aliases { diff --git a/src/config/settings.rs b/src/config/settings.rs index 4500213db..7a86f09fb 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -5,10 +5,8 @@ use std::time::Duration; use indexmap::IndexMap; use log::LevelFilter; -use crate::config::AliasMap; use crate::env; use crate::env::*; -use crate::plugins::PluginName; #[derive(Debug, Clone)] pub struct Settings { @@ -17,7 +15,6 @@ pub struct Settings { pub always_keep_download: bool, pub legacy_version_file: bool, pub plugin_autoupdate_last_check_duration: Duration, - pub aliases: IndexMap>, pub verbose: bool, pub asdf_compat: bool, pub jobs: usize, @@ -36,7 +33,6 @@ impl Default for Settings { always_keep_download: false, legacy_version_file: true, plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), - aliases: IndexMap::new(), verbose: *RTX_VERBOSE || !console::user_attended_stderr(), asdf_compat: *RTX_ASDF_COMPAT, jobs: *RTX_JOBS, @@ -98,7 +94,6 @@ pub struct SettingsBuilder { pub always_keep_download: Option, pub legacy_version_file: Option, pub plugin_autoupdate_last_check_duration: Option, - pub aliases: Option, pub verbose: Option, pub asdf_compat: Option, pub jobs: Option, @@ -154,9 +149,6 @@ impl SettingsBuilder { if other.shims_dir.is_some() { self.shims_dir = other.shims_dir; } - if other.aliases.is_some() { - self.aliases = other.aliases; - } if other.raw.is_some() { self.raw = other.raw; } @@ -199,7 +191,6 @@ impl SettingsBuilder { settings.log_level = self.log_level.unwrap_or(settings.log_level); settings.shims_dir = self.shims_dir.clone().or(settings.shims_dir); settings.raw = self.raw.unwrap_or(settings.raw); - settings.aliases = self.aliases.clone().unwrap_or(settings.aliases); if settings.raw { settings.verbose = true; diff --git a/src/config/snapshots/rtx__config__tests__load.snap b/src/config/snapshots/rtx__config__tests__load.snap index ec9aed78c..deb69ec87 100644 --- a/src/config/snapshots/rtx__config__tests__load.snap +++ b/src/config/snapshots/rtx__config__tests__load.snap @@ -2,5 +2,5 @@ source: src/config/mod.rs expression: config --- -Files: ~/cwd/.test-tool-versions, ~/.test-tool-versions +Files: ~/cwd/.test-tool-versions, ~/.test-tool-versions, ~/config/config.toml Installed Plugins: dummy, tiny diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 46ff8788a..901627237 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -1,9 +1,9 @@ -use std::fmt; use std::fmt::{Display, Formatter}; use std::io::{BufRead, BufReader}; use std::path::PathBuf; -use std::process::Output; -use std::sync::Arc; +use std::process::{Command, ExitStatus, Output, Stdio}; +use std::sync::mpsc::channel; +use std::{fmt, thread}; use color_eyre::eyre::{Context, Result}; use duct::Expression; @@ -143,25 +143,29 @@ impl ScriptManager { .with_context(|| ScriptFailed(display_path(&self.get_script_path(script)), None)) } - pub fn run_by_line( - &self, + pub fn run_by_line<'a, F1, F2, F3>( + &'a self, settings: &Settings, script: &Script, on_error: F1, - on_output: F2, + on_stdout: F2, + on_stderr: F3, ) -> Result<()> where F1: Fn(String), - F2: Fn(&str), + F2: Fn(&str) + Send + Sync + 'a, + F3: Fn(&str) + Send + Sync, { - let cmd = self.cmd(settings, script); - let mut output = vec![]; + let mut cmd = Command::new(self.get_script_path(script)); + for (k, v) in self.env.iter() { + cmd.env(k, v); + } if settings.raw { - let Output { status, .. } = cmd.unchecked().run()?; + let status = cmd.spawn()?.wait()?; match status.success() { true => Ok(()), false => { - on_error(output.join("\n")); + on_error(String::new()); Err( ScriptFailed(display_path(&self.get_script_path(script)), Some(status)) .into(), @@ -169,31 +173,67 @@ impl ScriptManager { } } } else { - let reader = cmd.stdin_null().stderr_to_stdout().unchecked().reader()?; - let reader = Arc::new(reader); - for line in BufReader::new(&*reader).lines() { - let line = line.unwrap(); - on_output(&line); - output.push(line); - } - - match reader.try_wait() { - Err(err) => { - on_error(output.join("\n")); - Err(err)? + let mut cp = cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + let stdout = BufReader::new(cp.stdout.take().unwrap()); + let stderr = BufReader::new(cp.stderr.take().unwrap()); + let (tx, rx) = channel(); + thread::spawn({ + let tx = tx.clone(); + move || { + for line in stdout.lines() { + let line = line.unwrap(); + tx.send(ChildProcessOutput::Stdout(line)).unwrap(); + } } - Ok(out) => match out.unwrap().status.success() { - true => Ok(()), - false => { - on_error(output.join("\n")); - let err = ScriptFailed( - display_path(&self.get_script_path(script)), - Some(out.unwrap().status), - ); - Err(err)? + }); + thread::spawn({ + let tx = tx.clone(); + move || { + for line in stderr.lines() { + let line = line.unwrap(); + tx.send(ChildProcessOutput::Stderr(line)).unwrap(); } - }, + } + }); + thread::spawn(move || { + let status = cp.wait().unwrap(); + tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); + }); + let mut combined_output = vec![]; + for line in rx { + match line { + ChildProcessOutput::Stdout(line) => { + on_stdout(&line); + combined_output.push(line); + } + ChildProcessOutput::Stderr(line) => { + on_stderr(&line); + combined_output.push(line); + } + ChildProcessOutput::ExitStatus(status) => match status.success() { + true => return Ok(()), + false => { + on_error(combined_output.join("\n")); + Err(ScriptFailed( + display_path(&self.get_script_path(script)), + Some(status), + ))?; + } + }, + } } + + Ok(()) } } } + +enum ChildProcessOutput { + Stdout(String), + Stderr(String), + ExitStatus(ExitStatus), +} diff --git a/src/runtimes.rs b/src/runtimes.rs index 1b89c956a..1a6f5f7a7 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -100,6 +100,11 @@ impl RuntimeVersion { pr.set_message(line.into()); } }, + |line| { + if !line.trim().is_empty() { + pr.println(line.into()); + } + }, ) }; diff --git a/test/config/config.toml b/test/config/config.toml index 92038cd17..efef629b7 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -1,3 +1,4 @@ +[settings] experimental = true verbose = true missing_runtime_behavior= 'autoinstall' From 628fd31611b8b903c0f62e6be3aa6054f0c212dc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 02:26:10 -0600 Subject: [PATCH 0369/1891] chore: Release rtx-cli version 1.20.4 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 434e08db5..f803afb67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1381,7 +1381,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.20.3" +version = "1.20.4" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 3978d6b5f..b7c8a85cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.20.3" +version = "1.20.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 6f343feb1..f3b0090c7 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.20.3 +rtx 1.20.4 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.3/rtx-v1.20.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.4/rtx-v1.20.4-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index ecae90fdb..a5a0586bf 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.20.3"; + version = "1.20.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 79d2491b2..c0b498d54 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.20.3" +.TH rtx 1 "rtx 1.20.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -129,6 +129,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.20.3 +v1.20.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a351f870f..2547bfb26 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.20.3 +Version: 1.20.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 14e2245146451d2a4e30388b261ed9d1c0a00c64 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 02:48:12 -0600 Subject: [PATCH 0370/1891] chore: set content-type on s3 --- scripts/publish-s3.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index b64c46dee..1bb1a4c81 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -12,11 +12,11 @@ cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-latest-linux-amd64" cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-latest-macos-amd64" aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive -aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" \ - --include "rtx-latest-*" \ - --include "SHASUMS*" \ - --include "VERSION" \ - --include "install.sh" + +aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "rtx-latest-*" +aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" +aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive From c21fd194500294d810646c91adee60c324d110e7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 03:06:57 -0600 Subject: [PATCH 0371/1891] bug: fix source on `rtx ls` when using .rtx.toml --- src/config/config_file/rtx_toml.rs | 66 +++++++++---------- ...nfig_file__rtx_toml__tests__fixture-4.snap | 12 ++-- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index f3e83ad3e..845fac281 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -41,40 +41,33 @@ macro_rules! parse_error { #[allow(dead_code)] // TODO: remove impl RtxToml { - pub fn init(filename: &Path) -> Self { + pub fn init(path: &Path) -> Self { Self { - path: filename.to_path_buf(), + path: path.to_path_buf(), ..Default::default() } } - pub fn from_file(filename: &Path) -> Result { - trace!("parsing: {}", filename.display()); - let body = fs::read_to_string(filename).suggestion("ensure file exists and can be read")?; - let mut rf = Self::from_str(body)?; - rf.path = filename.to_path_buf(); + pub fn from_file(path: &Path) -> Result { + trace!("parsing: {}", path.display()); + let mut rf = Self::init(path); + let body = fs::read_to_string(path).suggestion("ensure file exists and can be read")?; + rf.parse(&body)?; Ok(rf) } - pub fn from_str(s: String) -> Result { - Self { - doc: s.parse().suggestion("ensure file is valid TOML")?, - ..Default::default() - } - .parse() - } - pub fn migrate(path: &Path) -> Result { // attempt to read as new .rtx.toml syntax let mut raw = String::from("[settings]\n"); raw.push_str(&fs::read_to_string(path)?); - let mut toml = RtxToml::from_str(raw)?; - toml.path = path.to_path_buf(); + let mut toml = RtxToml::init(path); + toml.parse(&raw)?; toml.save()?; Ok(toml) } - fn parse(mut self) -> Result { + fn parse(&mut self, s: &str) -> Result<()> { + self.doc = s.parse().suggestion("ensure file is valid TOML")?; for (k, v) in self.doc.iter() { match k { "env" => self.env = self.parse_hashmap(k, v)?, @@ -85,7 +78,7 @@ impl RtxToml { _ => Err(eyre!("unknown key: {}", k))?, } } - Ok(self) + Ok(()) } pub fn settings(&self) -> SettingsBuilder { @@ -566,11 +559,12 @@ mod tests { #[test] fn test_env() { - let cf = RtxToml::from_str(formatdoc! {r#" + let mut cf = RtxToml::init(&PathBuf::default()); + cf.parse(&formatdoc! {r#" [env] foo="bar" "#}) - .unwrap(); + .unwrap(); assert_debug_snapshot!(cf.env(), @r###" { @@ -582,12 +576,13 @@ mod tests { #[test] fn test_set_alias() { - let mut cf = RtxToml::from_str(formatdoc! {r#" + let mut cf = RtxToml::init(&PathBuf::default()); + cf.parse(&formatdoc! {r#" [alias.nodejs] 16 = "16.0.0" 18 = "18.0.0" "#}) - .unwrap(); + .unwrap(); cf.set_alias("nodejs", "18", "18.0.1"); cf.set_alias("nodejs", "20", "20.0.0"); @@ -599,7 +594,8 @@ mod tests { #[test] fn test_remove_alias() { - let mut cf = RtxToml::from_str(formatdoc! {r#" + let mut cf = RtxToml::init(&PathBuf::default()); + cf.parse(&formatdoc! {r#" [alias.nodejs] 16 = "16.0.0" 18 = "18.0.0" @@ -607,7 +603,7 @@ mod tests { [alias.python] "3.10" = "3.10.0" "#}) - .unwrap(); + .unwrap(); cf.remove_alias("nodejs", "16"); cf.remove_alias("python", "3.10"); @@ -617,11 +613,12 @@ mod tests { #[test] fn test_replace_versions() { - let mut cf = RtxToml::from_str(formatdoc! {r#" + let mut cf = RtxToml::init(&PathBuf::default()); + cf.parse(&formatdoc! {r#" [tools] nodejs = ["16.0.0", "18.0.0"] "#}) - .unwrap(); + .unwrap(); cf.replace_versions( &PluginName::from("nodejs"), &["16.0.1".into(), "18.0.1".into()], @@ -633,11 +630,12 @@ mod tests { #[test] fn test_remove_plugin() { - let mut cf = RtxToml::from_str(formatdoc! {r#" + let mut cf = RtxToml::init(&PathBuf::default()); + cf.parse(&formatdoc! {r#" [tools] nodejs = ["16.0.0", "18.0.0"] "#}) - .unwrap(); + .unwrap(); cf.remove_plugin(&PluginName::from("nodejs")); assert_debug_snapshot!(cf.toolset); @@ -646,13 +644,14 @@ mod tests { #[test] fn test_update_setting() { - let mut cf = RtxToml::from_str(formatdoc! {r#" + let mut cf = RtxToml::init(&PathBuf::default()); + cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true [alias.nodejs] 18 = "18.0.0" "#}) - .unwrap(); + .unwrap(); cf.update_setting("legacy_version_file", false); assert_display_snapshot!(cf.dump(), @r###" [settings] @@ -664,11 +663,12 @@ mod tests { #[test] fn test_remove_setting() { - let mut cf = RtxToml::from_str(formatdoc! {r#" + let mut cf = RtxToml::init(&PathBuf::default()); + cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true "#}) - .unwrap(); + .unwrap(); cf.remove_setting("legacy_version_file"); assert_display_snapshot!(cf.dump(), @r###" "###); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index bbdcefd86..b83f7e565 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -16,7 +16,7 @@ Toolset { }, ], source: RtxToml( - "", + "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", ), }, "nodejs": ToolVersionList { @@ -55,7 +55,7 @@ Toolset { }, ], source: RtxToml( - "", + "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", ), }, "jq": ToolVersionList { @@ -70,7 +70,7 @@ Toolset { }, ], source: RtxToml( - "", + "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", ), }, "shellcheck": ToolVersionList { @@ -85,7 +85,7 @@ Toolset { }, ], source: RtxToml( - "", + "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", ), }, "python": ToolVersionList { @@ -110,13 +110,13 @@ Toolset { }, ], source: RtxToml( - "", + "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", ), }, }, source: Some( RtxToml( - "", + "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", ), ), } From e656eb028805b51e1e41465bd7d7c3188c0c2617 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 04:25:35 -0600 Subject: [PATCH 0372/1891] CI fix --- .config/nextest.toml | 2 +- README.md | 4 ++-- src/cli/where.rs | 4 ++-- src/config/config_file/rtx_toml.rs | 7 ++++--- ...g__config_file__rtx_toml__tests__fixture-4.snap | 14 +++++++------- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.config/nextest.toml b/.config/nextest.toml index 75fb6962d..884eacf64 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,5 +1,5 @@ [profile.default] test-threads = 1 -slow-timeout = { period = "200ms", terminate-after = 2 } +slow-timeout = { period = "250ms", terminate-after = 4 } status-level = "all" retries = { backoff = "exponential", count = 4, delay = "1s", max-delay = "10s" } diff --git a/README.md b/README.md index f3b0090c7..bf455cbbd 100644 --- a/README.md +++ b/README.md @@ -1662,12 +1662,12 @@ Examples: # Show the latest installed version of nodejs # If it is is not installed, errors $ rtx where nodejs@18 - /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 # Show the current, active install directory of nodejs # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs - /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 ``` ### `rtx which` diff --git a/src/cli/where.rs b/src/cli/where.rs index 34611f304..1ccda349c 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -65,12 +65,12 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # Show the latest installed version of nodejs # If it is is not installed, errors $ rtx where nodejs@18 - /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 # Show the current, active install directory of nodejs # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs - /Users/jdx/.local/share/rtx/installs/nodejs/18.0.0 + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 "#, style("Examples:").bold().underlined()} }); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 845fac281..489cb5eef 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -538,9 +538,10 @@ FOO = "bar" #[cfg(test)] mod tests { use indoc::formatdoc; - use insta::{assert_debug_snapshot, assert_display_snapshot}; + use insta::{assert_debug_snapshot, assert_display_snapshot, assert_snapshot}; use crate::dirs; + use crate::test::replace_path; use super::*; @@ -551,10 +552,10 @@ mod tests { assert_debug_snapshot!(cf.env()); assert_debug_snapshot!(cf.settings()); assert_debug_snapshot!(cf.plugins()); - assert_debug_snapshot!(cf.toolset); + assert_snapshot!(replace_path(&format!("{:#?}", cf.toolset))); assert_debug_snapshot!(cf.alias); - assert_display_snapshot!(cf); + assert_snapshot!(replace_path(&cf.to_string())); } #[test] diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index b83f7e565..38504bd2c 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf.toolset +expression: "replace_path(&format!(\"{:#?}\", cf.toolset))" --- Toolset { versions: { @@ -16,7 +16,7 @@ Toolset { }, ], source: RtxToml( - "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", + "~/fixtures/.rtx.toml", ), }, "nodejs": ToolVersionList { @@ -55,7 +55,7 @@ Toolset { }, ], source: RtxToml( - "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", + "~/fixtures/.rtx.toml", ), }, "jq": ToolVersionList { @@ -70,7 +70,7 @@ Toolset { }, ], source: RtxToml( - "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", + "~/fixtures/.rtx.toml", ), }, "shellcheck": ToolVersionList { @@ -85,7 +85,7 @@ Toolset { }, ], source: RtxToml( - "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", + "~/fixtures/.rtx.toml", ), }, "python": ToolVersionList { @@ -110,13 +110,13 @@ Toolset { }, ], source: RtxToml( - "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", + "~/fixtures/.rtx.toml", ), }, }, source: Some( RtxToml( - "/Users/jdx/src/rtx/test/fixtures/.rtx.toml", + "~/fixtures/.rtx.toml", ), ), } From 09e208e063f81cb905fb8ec007d47578a0af8ba3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 04:37:05 -0600 Subject: [PATCH 0373/1891] docs: make CLI help fit on 80 character width --- README.md | 4 +- completions/_rtx | 599 ++++++++++++++++++++++++++++--------------- completions/rtx.bash | 3 - completions/rtx.fish | 302 ++++++++++++++-------- man/man1/rtx.1 | 10 +- src/cli/activate.rs | 2 +- src/cli/args/jobs.rs | 2 +- src/cli/args/raw.rs | 2 +- src/cli/global.rs | 2 +- src/cli/ls_remote.rs | 2 +- 10 files changed, 610 insertions(+), 318 deletions(-) diff --git a/README.md b/README.md index bf455cbbd..4d785bc58 100644 --- a/README.md +++ b/README.md @@ -887,7 +887,7 @@ immediately after activating. Not calling `hook-env` immediately appears to work ### `rtx activate` ``` -Enables rtx to automatically modify runtimes when changing directory +Initializes rtx in the current shell This should go into your shell's rc file. Otherwise, it will only take effect in the current session. @@ -1162,7 +1162,7 @@ Examples: ### `rtx global` ``` -Sets global .tool-versions to include a specified runtime +Shows/sets the global runtime version(s) Displays the contents of ~/.tool-versions after writing. The file is `$HOME/.tool-versions` by default. diff --git a/completions/_rtx b/completions/_rtx index 5f8179eff..f743d092e 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -15,11 +15,15 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -39,14 +43,18 @@ _rtx() { _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish xonsh zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx: @" message when changing directories]' \ '-q[noop]' \ '--quiet[noop]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -58,11 +66,15 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -79,11 +91,15 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (get) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -96,11 +112,15 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -109,11 +129,15 @@ _arguments "${_arguments_options[@]}" \ ;; (set) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -125,11 +149,15 @@ _arguments "${_arguments_options[@]}" \ ;; (unset) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -180,11 +208,15 @@ esac ;; (asdf) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -194,11 +226,15 @@ _arguments "${_arguments_options[@]}" \ ;; (bin-paths) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -207,11 +243,15 @@ _arguments "${_arguments_options[@]}" \ ;; (cache) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -228,11 +268,15 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (clear) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -271,11 +315,15 @@ esac _arguments "${_arguments_options[@]}" \ '-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ '--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -284,11 +332,15 @@ _arguments "${_arguments_options[@]}" \ ;; (current) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -298,11 +350,15 @@ _arguments "${_arguments_options[@]}" \ ;; (deactivate) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -311,11 +367,15 @@ _arguments "${_arguments_options[@]}" \ ;; (direnv) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -332,11 +392,15 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (envrc) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -345,11 +409,15 @@ _arguments "${_arguments_options[@]}" \ ;; (exec) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -358,11 +426,15 @@ _arguments "${_arguments_options[@]}" \ ;; (activate) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -407,11 +479,15 @@ esac ;; (doctor) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -422,11 +498,15 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish xonsh zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -438,11 +518,15 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '()-c+[Command string to execute]:C: ' \ '()--command=[Command string to execute]:C: ' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -453,16 +537,20 @@ _arguments "${_arguments_options[@]}" \ (global) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to `~/.tool-versions` e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions]' \ '--fuzzy[Save fuzzy version to `~/.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -477,12 +565,16 @@ If this is a single runtime with no version, the current value of the global _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish xonsh zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx: @" message when changing directories]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -491,13 +583,17 @@ _arguments "${_arguments_options[@]}" \ ;; (implode) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--config[Also remove config directory]' \ '--dry-run[List directories that would be removed without actually removing them]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -508,8 +604,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ '()*-p+[Only install runtime(s) for ]:PLUGIN: ' \ '()*--plugin=[Only install runtime(s) for ]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Force reinstall even if already installed]' \ '--force[Force reinstall even if already installed]' \ @@ -517,8 +615,10 @@ _arguments "${_arguments_options[@]}" \ '(-p --plugin -f --force)--all[Install all missing runtimes as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtime(s) to install e.g.\: nodejs@18:' \ @@ -526,11 +626,15 @@ _arguments "${_arguments_options[@]}" \ ;; (latest) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -542,8 +646,10 @@ _arguments "${_arguments_options[@]}" \ (local) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from .tool-versions]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-p[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ @@ -552,8 +658,10 @@ by default this command will only set the runtime in the current directory ("$PW '--pin[Save exact version to `.tool-versions` e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions]' \ '--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -568,13 +676,17 @@ the current value of .tool-versions will be displayed:' \ _arguments "${_arguments_options[@]}" \ '-p+[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ '--plugin=[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -584,11 +696,15 @@ _arguments "${_arguments_options[@]}" \ ;; (ls-remote) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -600,11 +716,15 @@ same as the first argument after the "@":' \ ;; (mangen) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -613,15 +733,19 @@ _arguments "${_arguments_options[@]}" \ ;; (plugins) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -638,8 +762,10 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (install) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ @@ -651,8 +777,10 @@ This will only install plugins that have matching shorthands. i.e.: they don'\''t need the full git repo url]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::name -- The name of the plugin to install @@ -664,8 +792,10 @@ Can specify multiple plugins\: `rtx plugins install nodejs ruby python`:' \ ;; (ls) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[List all available remote plugins Same as `rtx plugins ls-remote`]' \ @@ -675,8 +805,10 @@ Same as `rtx plugins ls-remote`]' \ e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -685,14 +817,18 @@ e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ ;; (ls-remote) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -701,11 +837,15 @@ _arguments "${_arguments_options[@]}" \ ;; (uninstall) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -715,13 +855,17 @@ _arguments "${_arguments_options[@]}" \ ;; (update) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '()-a[Update all plugins]' \ '()--all[Update all plugins]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -775,11 +919,15 @@ esac ;; (reshim) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -790,11 +938,15 @@ _arguments "${_arguments_options[@]}" \ ;; (self-update) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -803,11 +955,15 @@ _arguments "${_arguments_options[@]}" \ ;; (settings) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -824,11 +980,15 @@ _arguments "${_arguments_options[@]}" \ case $line[1] in (get) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -838,11 +998,15 @@ _arguments "${_arguments_options[@]}" \ ;; (ls) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -851,11 +1015,15 @@ _arguments "${_arguments_options[@]}" \ ;; (set) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -866,11 +1034,15 @@ _arguments "${_arguments_options[@]}" \ ;; (unset) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -920,11 +1092,15 @@ esac ;; (shell) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -934,11 +1110,15 @@ _arguments "${_arguments_options[@]}" \ ;; (uninstall) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -948,11 +1128,15 @@ _arguments "${_arguments_options[@]}" \ ;; (version) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -961,11 +1145,15 @@ _arguments "${_arguments_options[@]}" \ ;; (where) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -981,13 +1169,17 @@ used for asdf compatibility:' \ ;; (which) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '(--version)--plugin[Show the plugin name instead of the path]' \ '(--plugin)--version[Show the version instead of the path]' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -997,11 +1189,15 @@ _arguments "${_arguments_options[@]}" \ ;; (render-help) _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel, default: 4]: : ' \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-r[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ -'--raw[Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -1288,7 +1484,7 @@ esac (( $+functions[_rtx_commands] )) || _rtx_commands() { local commands; commands=( -'activate:Enables rtx to automatically modify runtimes when changing directory' \ +'activate:Initializes rtx in the current shell' \ 'alias:Manage aliases' \ 'a:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ @@ -1303,8 +1499,8 @@ _rtx_commands() { 'e:Exports env vars to activate rtx a single time' \ 'exec:Execute a command with runtime(s) set' \ 'x:Execute a command with runtime(s) set' \ -'global:Sets global .tool-versions to include a specified runtime' \ -'g:Sets global .tool-versions to include a specified runtime' \ +'global:Shows/sets the global runtime version(s)' \ +'g:Shows/sets the global runtime version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ 'install:Install a runtime' \ @@ -1315,7 +1511,6 @@ _rtx_commands() { 'ls:List installed runtime versions' \ 'list:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ -'list-remote:List runtime versions available for install' \ 'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ @@ -1646,7 +1841,7 @@ _rtx__direnv__help__help_commands() { (( $+functions[_rtx__help_commands] )) || _rtx__help_commands() { local commands; commands=( -'activate:Enables rtx to automatically modify runtimes when changing directory' \ +'activate:Initializes rtx in the current shell' \ 'alias:Manage aliases' \ 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ 'bin-paths:List all the active runtime bin paths' \ @@ -1658,7 +1853,7 @@ _rtx__help_commands() { 'doctor:Check rtx installation for possible problems.' \ 'env:Exports env vars to activate rtx a single time' \ 'exec:Execute a command with runtime(s) set' \ -'global:Sets global .tool-versions to include a specified runtime' \ +'global:Shows/sets the global runtime version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ 'install:Install a runtime' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index fca6f3197..44bda2848 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -84,9 +84,6 @@ _rtx() { rtx,list) cmd="rtx__ls" ;; - rtx,list-remote) - cmd="rtx__ls__remote" - ;; rtx,local) cmd="rtx__local" ;; diff --git a/completions/rtx.fish b/completions/rtx.fish index c8ef0ea42..0e2f58337 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,10 +1,12 @@ -complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' -complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Initializes rtx in the current shell' complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' complete -c rtx -n "__fish_use_subcommand" -f -a "bin-paths" -d 'List all the active runtime bin paths' @@ -16,7 +18,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv func complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'Exports env vars to activate rtx a single time' complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Shows/sets the global runtime version(s)' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a runtime' @@ -37,17 +39,21 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' @@ -57,25 +63,33 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' @@ -85,49 +99,65 @@ These can come from user config or from plugins in `bin/list-aliases`.' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from complete" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from complete" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -136,19 +166,25 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subc for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -157,94 +193,120 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,xonsh ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r -complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' -complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only install runtime(s) for ' -r -complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing runtimes as well as all plugins for the current directory This is hidden because it\'s now the default behavior' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' -complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from mangen" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' @@ -253,40 +315,50 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins This will only install plugins that have matching shorthands. i.e.: they don\'t need the full git repo url' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins Same as `rtx plugins ls-remote`' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' @@ -295,19 +367,25 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -315,24 +393,32 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -340,39 +426,51 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' -complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel, default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.' +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Enables rtx to automatically modify runtimes when changing directory' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' @@ -384,7 +482,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets global .tool-versions to include a specified runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Shows/sets the global runtime version(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c0b498d54..049e09f34 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -17,10 +17,12 @@ https://asdf\-vm.com/ .SH OPTIONS .TP \fB\-j\fR, \fB\-\-jobs\fR -Number of plugins and runtimes to install in parallel, default: 4 +Number of plugins and runtimes to install in parallel +default: 4 .TP \fB\-r\fR, \fB\-\-raw\fR -Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets \-\-jobs=1. +Directly pipe stdin/stdout/stderr to user. +sets \-\-jobs=1 .TP \fB\-v\fR, \fB\-\-verbose\fR Show installation output @@ -33,7 +35,7 @@ Print version .SH SUBCOMMANDS .TP rtx\-activate(1) -Enables rtx to automatically modify runtimes when changing directory +Initializes rtx in the current shell .TP rtx\-alias(1) Manage aliases @@ -66,7 +68,7 @@ rtx\-exec(1) Execute a command with runtime(s) set .TP rtx\-global(1) -Sets global .tool\-versions to include a specified runtime +Shows/sets the global runtime version(s) .TP rtx\-implode(1) Removes rtx CLI and all related data diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 55c9b0988..b88ba722a 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -12,7 +12,7 @@ use crate::file::touch_dir; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -/// Enables rtx to automatically modify runtimes when changing directory +/// Initializes rtx in the current shell /// /// This should go into your shell's rc file. /// Otherwise, it will only take effect in the current session. diff --git a/src/cli/args/jobs.rs b/src/cli/args/jobs.rs index ae66912a3..0c2ff0c56 100644 --- a/src/cli/args/jobs.rs +++ b/src/cli/args/jobs.rs @@ -14,7 +14,7 @@ impl Jobs { Arg::new("jobs") .short('j') .long("jobs") - .help("Number of plugins and runtimes to install in parallel, default: 4") + .help("Number of plugins and runtimes to install in parallel\ndefault: 4") .value_parser(ValueParser::new(parse_jobs)) .global(true) } diff --git a/src/cli/args/raw.rs b/src/cli/args/raw.rs index 1343771f5..fcc840987 100644 --- a/src/cli/args/raw.rs +++ b/src/cli/args/raw.rs @@ -7,7 +7,7 @@ impl Raw { Arg::new("raw") .short('r') .long("raw") - .help("Directly pipe stdin/stdout/stderr from plugin scripts to user. Sets --jobs=1.") + .help("Directly pipe stdin/stdout/stderr to user.\nsets --jobs=1") .action(ArgAction::SetTrue) .global(true) } diff --git a/src/cli/global.rs b/src/cli/global.rs index 44c6baec9..a0d63f4f1 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -10,7 +10,7 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; -/// Sets global .tool-versions to include a specified runtime +/// Shows/sets the global runtime version(s) /// /// Displays the contents of ~/.tool-versions after writing. /// The file is `$HOME/.tool-versions` by default. diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index fc6360060..72153542b 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -14,7 +14,7 @@ use crate::output::Output; /// note that these versions are cached for commands like `rtx install nodejs@latest` /// however _this_ command will always clear that cache and fetch the latest remote versions #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list-remote", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), alias = "list-all")] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), aliases = ["list-all", "list-remote"])] pub struct LsRemote { /// Plugin to get versions for #[clap(value_parser = RuntimeArgParser)] From 08973e54f4ecdfaf20f01c8e9556376e4a2e570b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 04:45:20 -0600 Subject: [PATCH 0374/1891] bug: prevent install from succeeding when script fails --- src/cli/asdf.rs | 2 +- src/cli/bin_paths.rs | 3 +-- src/cli/current.rs | 2 +- src/cli/direnv/envrc.rs | 2 +- src/cli/direnv/exec.rs | 2 +- src/cli/doctor.rs | 2 +- src/cli/env.rs | 3 +-- src/cli/exec.rs | 3 +-- src/cli/hook_env.rs | 3 +-- src/cli/install.rs | 4 ++-- src/cli/ls.rs | 2 +- src/cli/plugins/install.rs | 2 +- src/cli/reshim.rs | 2 +- src/cli/shell.rs | 3 +-- src/cli/uninstall.rs | 2 +- src/cli/where.rs | 3 +-- src/cli/which.rs | 2 +- src/shims.rs | 2 +- src/toolset/builder.rs | 9 ++++----- 19 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index f13f86af6..44b1079b5 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -45,7 +45,7 @@ impl Command for Asdf { } fn list_versions(config: &mut Config, out: &mut Output, args: &Vec) -> Result<()> { - let ts = ToolsetBuilder::new().build(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 63d768cbe..12a4850b4 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -14,7 +14,7 @@ impl Command for BinPaths { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() - .build(&mut config); + .build(&mut config)?; for p in ts.list_paths(&config) { rtxprintln!(out, "{}", p.display()); } @@ -24,7 +24,6 @@ impl Command for BinPaths { #[cfg(test)] mod tests { - use crate::assert_cli_snapshot; #[test] diff --git a/src/cli/current.rs b/src/cli/current.rs index 487c15307..a22b48045 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -24,7 +24,7 @@ pub struct Current { impl Command for Current { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config); + let ts = ToolsetBuilder::new().build(&mut config)?; match &self.plugin { Some(plugin_name) => match config.plugins.get(plugin_name) { Some(plugin) => self.one(&config, ts, out, plugin), diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 5d1ebd4e2..6661a50ad 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -25,7 +25,7 @@ impl Command for Envrc { } let ts = ToolsetBuilder::new() .with_install_missing() - .build(&mut config); + .build(&mut config)?; let envrc_path = env::RTX_TMP_DIR .join("direnv") .join(hash_to_str(dirs::CURRENT.deref()) + ".envrc"); diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 0cf765406..e935eea39 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -28,7 +28,7 @@ impl Command for DirenvExec { } let ts = ToolsetBuilder::new() .with_install_missing() - .build(&mut config); + .build(&mut config)?; let mut cmd = env_cmd(); for (k, v) in ts.env_with_path(&config) { diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index abe27e375..5afafb543 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -23,7 +23,7 @@ pub struct Doctor {} impl Command for Doctor { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config); + let ts = ToolsetBuilder::new().build(&mut config)?; rtxprintln!(out, "{}", rtx_version()); rtxprintln!(out, "{}", shell()); rtxprintln!(out, "{}", rtx_env_vars()); diff --git a/src/cli/env.rs b/src/cli/env.rs index fcbbf127c..37b6319a4 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -31,8 +31,7 @@ impl Command for Env { let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.runtime) - .build(&mut config); - + .build(&mut config)?; let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index c41c11f7b..1f58148c9 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -49,8 +49,7 @@ impl Command for Exec { let ts = ToolsetBuilder::new() .with_args(&self.runtime) .with_install_missing() - .build(&mut config); - + .build(&mut config)?; let (program, args) = parse_command(&env::SHELL, self.command, self.c); let mut env = ts.env_with_path(&config); if config.settings.missing_runtime_behavior != Ignore { diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 4487f4a62..0524d95ca 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -38,8 +38,7 @@ impl Command for HookEnv { } let ts = ToolsetBuilder::new() .with_install_missing() - .build(&mut config); - + .build(&mut config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); out.stdout.write(hook_env::clear_old_env(&*shell)); let env = ts.env(&config); diff --git a/src/cli/install.rs b/src/cli/install.rs index 69e92b78d..724146f8d 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -69,7 +69,7 @@ impl Install { fn install_runtimes(&self, mut config: Config, runtimes: &[RuntimeArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); let mut tool_versions = vec![]; - let ts = ToolsetBuilder::new().build(&mut config); + let ts = ToolsetBuilder::new().build(&mut config)?; for runtime in RuntimeArg::double_runtime_condition(runtimes) { match runtime.to_tool_version() { Some(tv) => tool_versions.push(tv), @@ -173,7 +173,7 @@ impl Install { } fn install_missing_runtimes(&self, mut config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().build(&mut config); + let mut ts = ToolsetBuilder::new().build(&mut config)?; if let Some(plugins) = &self.plugin { let plugins = plugins.iter().collect::>(); for plugin in ts.versions.keys().cloned().collect::>() { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 54c346dcb..84ca105ce 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -95,7 +95,7 @@ fn get_runtime_list( config: &mut Config, plugin_flag: &Option, ) -> Result)>> { - let ts = ToolsetBuilder::new().build(config); + let ts = ToolsetBuilder::new().build(config)?; let mut versions: HashMap<(PluginName, String), RuntimeVersion> = ts .list_installed_versions(config)? .into_iter() diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 34d60d7b0..579f4647b 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -77,7 +77,7 @@ impl PluginsInstall { config: &mut Config, mpr: MultiProgressReport, ) -> Result<()> { - let ts = ToolsetBuilder::new().build(config); + let ts = ToolsetBuilder::new().build(config)?; let missing_plugins = ts.list_missing_plugins(config); if missing_plugins.is_empty() { warn!("all plugins already installed"); diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index e74eddf37..2e5d40ca3 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -30,7 +30,7 @@ pub struct Reshim { impl Command for Reshim { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config); + let ts = ToolsetBuilder::new().build(&mut config)?; if !config.settings.experimental { err_experimental()?; diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 9784bcd63..df926dd1c 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -31,8 +31,7 @@ impl Command for Shell { let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.runtime) - .build(&mut config); - + .build(&mut config)?; if !config.is_activated() { err_inactive()?; } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index d3b5fa65b..5826e153b 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -24,7 +24,7 @@ impl Command for Uninstall { let runtimes = RuntimeArg::double_runtime_condition(&self.runtime); let ts = ToolsetBuilder::new() .with_args(&runtimes) - .build(&mut config); + .build(&mut config)?; let runtime_versions = runtimes.iter().filter_map(|a| ts.resolve_runtime_arg(a)); let mpr = MultiProgressReport::new(config.settings.verbose); diff --git a/src/cli/where.rs b/src/cli/where.rs index 1ccda349c..a46f5475b 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -44,8 +44,7 @@ impl Command for Where { let ts = ToolsetBuilder::new() .with_args(&[runtime.clone()]) - .build(&mut config); - + .build(&mut config)?; match ts.resolve_runtime_arg(&runtime) { Some(rtv) if rtv.is_installed() => { rtxprintln!(out, "{}", rtv.install_path.to_string_lossy()); diff --git a/src/cli/which.rs b/src/cli/which.rs index bfc857ae0..7c3fac308 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -27,7 +27,7 @@ pub struct Which { impl Command for Which { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config); + let ts = ToolsetBuilder::new().build(&mut config)?; match ts.which(&config, &self.bin_name) { Some(rtv) => { diff --git a/src/shims.rs b/src/shims.rs index 57f9661b0..7d5831850 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -28,7 +28,7 @@ pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Res } fn is_valid_shim(config: &mut Config, bin_name: &str) -> Result<()> { - let ts = ToolsetBuilder::new().build(config); + let ts = ToolsetBuilder::new().build(config)?; match ts.which(config, bin_name) { Some(_) => Ok(()), None => Err(eyre!("{} is not a valid shim", bin_name)), diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index e748a87cd..a8c47c74a 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,3 +1,4 @@ +use color_eyre::eyre::Result; use indexmap::IndexMap; use itertools::Itertools; @@ -32,7 +33,7 @@ impl ToolsetBuilder { self } - pub fn build(self, config: &mut Config) -> Toolset { + pub fn build(self, config: &mut Config) -> Result { let mut toolset = Toolset::default(); load_config_files(config, &mut toolset); load_runtime_env(&mut toolset, env::vars().collect()); @@ -41,13 +42,11 @@ impl ToolsetBuilder { if self.install_missing { let mpr = MultiProgressReport::new(config.settings.verbose); - if let Err(e) = toolset.install_missing(config, mpr) { - warn!("Error installing runtimes: {:#}", e); - }; + toolset.install_missing(config, mpr)?; } debug!("{}", toolset); - toolset + Ok(toolset) } } From 58e5c2f949f0362f3903cb243630bf34655fdea3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 10:13:45 -0600 Subject: [PATCH 0375/1891] refactor --- src/cli/current.rs | 12 ++++++------ src/cli/exec.rs | 4 ++-- src/cli/hook_env.rs | 6 +++--- src/cli/ls.rs | 2 +- src/cli/shell.rs | 2 +- src/toolset/mod.rs | 32 +++++++++++--------------------- 6 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/cli/current.rs b/src/cli/current.rs index a22b48045..5fa1791de 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -27,24 +27,24 @@ impl Command for Current { let ts = ToolsetBuilder::new().build(&mut config)?; match &self.plugin { Some(plugin_name) => match config.plugins.get(plugin_name) { - Some(plugin) => self.one(&config, ts, out, plugin), + Some(plugin) => self.one(ts, out, plugin), None => { warn!("Plugin {} is not installed", plugin_name); Ok(()) } }, - None => self.all(&config, ts, out), + None => self.all(ts, out), } } } impl Current { - fn one(&self, config: &Config, ts: Toolset, out: &mut Output, plugin: &Plugin) -> Result<()> { + fn one(&self, ts: Toolset, out: &mut Output, plugin: &Plugin) -> Result<()> { if !plugin.is_installed() { warn!("Plugin {} is not installed", plugin.name); return Ok(()); } - match ts.list_versions_by_plugin(config).get(&plugin.name) { + match ts.list_versions_by_plugin().get(&plugin.name) { Some(versions) => { rtxprintln!( out, @@ -63,8 +63,8 @@ impl Current { Ok(()) } - fn all(&self, config: &Config, ts: Toolset, out: &mut Output) -> Result<()> { - for (plugin, versions) in ts.list_versions_by_plugin(config) { + fn all(&self, ts: Toolset, out: &mut Output) -> Result<()> { + for (plugin, versions) in ts.list_versions_by_plugin() { if versions.is_empty() { continue; } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 1f58148c9..deb70dcf8 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -132,13 +132,13 @@ mod tests { #[test] fn test_exec_ok() { - assert_cli!("exec", "--", "ls"); + assert_cli!("exec", "--", "echo"); } #[test] fn test_exec_fail() { let _ = cli_run( - &vec!["rtx", "exec", "--", "ls", "--invalid"] + &vec!["rtx", "exec", "--", "exit", "1"] .into_iter() .map(String::from) .collect::>(), diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 0524d95ca..917dbca32 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -55,7 +55,7 @@ impl Command for HookEnv { let output = hook_env::build_env_commands(&*shell, &patches); out.stdout.write(output); if self.status { - self.display_status(&config, &ts, out); + self.display_status(&ts, out); } Ok(()) @@ -63,9 +63,9 @@ impl Command for HookEnv { } impl HookEnv { - fn display_status(&self, config: &Config, ts: &Toolset, out: &mut Output) { + fn display_status(&self, ts: &Toolset, out: &mut Output) { let installed_versions = ts - .list_current_installed_versions(config) + .list_current_installed_versions() .into_iter() .rev() .map(|v| v.to_string()) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 84ca105ce..98d9d6acf 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -107,7 +107,7 @@ fn get_runtime_list( .collect(); let active = ts - .list_current_versions(config) + .list_current_versions() .into_iter() .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv.clone())) .collect::>(); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index df926dd1c..b02176272 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -37,7 +37,7 @@ impl Command for Shell { } let shell = get_shell(None).expect("no shell detected"); - for rtv in ts.list_current_installed_versions(&config) { + for rtv in ts.list_current_installed_versions() { let source = &ts.versions.get(&rtv.plugin.name).unwrap().source; if matches!(source, ToolSource::Argument) { let k = format!("RTX_{}_VERSION", rtv.plugin.name.to_uppercase()); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 006802f32..f917c7a20 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -224,33 +224,23 @@ impl Toolset { Ok(versions) } - pub fn list_versions_by_plugin( - &self, - config: &Config, - ) -> IndexMap> { + pub fn list_versions_by_plugin(&self) -> IndexMap> { self.versions .iter() - .filter_map(|(p, v)| match config.plugins.get(&p.to_string()) { - Some(plugin) => { - let plugin = Arc::new(plugin.clone()); - let versions = v.resolved_versions(); - Some((plugin.name.clone(), versions)) - } - None => { - debug!("Plugin {} not found", p); - None - } + .map(|(p, v)| { + let versions = v.resolved_versions(); + (p.clone(), versions) }) .collect() } - pub fn list_current_versions(&self, config: &Config) -> Vec<&RuntimeVersion> { - self.list_versions_by_plugin(config) + pub fn list_current_versions(&self) -> Vec<&RuntimeVersion> { + self.list_versions_by_plugin() .into_iter() .flat_map(|(_, v)| v) .collect() } - pub fn list_current_installed_versions(&self, config: &Config) -> Vec<&RuntimeVersion> { - self.list_current_versions(config) + pub fn list_current_installed_versions(&self) -> Vec<&RuntimeVersion> { + self.list_current_versions() .into_iter() .filter(|v| v.is_installed()) .collect() @@ -262,7 +252,7 @@ impl Toolset { } pub fn env(&self, config: &Config) -> IndexMap { let mut entries: IndexMap = self - .list_current_installed_versions(config) + .list_current_installed_versions() .into_par_iter() .flat_map(|v| match v.exec_env() { Ok(env) => env.clone().into_iter().collect(), @@ -287,7 +277,7 @@ impl Toolset { .into() } pub fn list_paths(&self, config: &Config) -> Vec { - self.list_current_installed_versions(config) + self.list_current_installed_versions() .into_par_iter() .flat_map(|rtv| match rtv.list_bin_paths(&config.settings) { Ok(paths) => paths, @@ -364,7 +354,7 @@ impl Toolset { } pub fn which(&self, config: &Config, bin_name: &str) -> Option<&RuntimeVersion> { - self.list_current_installed_versions(config) + self.list_current_installed_versions() .into_par_iter() .find_first(|v| { if let Ok(x) = v.which(&config.settings, bin_name) { From fea79fa71f379dae0e74ee3d08ad5e29c2d6586a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 10:20:07 -0600 Subject: [PATCH 0376/1891] intellij --- .idea/.gitignore | 8 +++++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++++ .idea/inspectionProfiles/Project_Default.xml | 10 ++++++++ .idea/modules.xml | 8 +++++++ .idea/modules/fixtures.iml | 11 +++++++++ .idea/prettier.xml | 7 ++++++ .idea/rtx.iml | 24 ++++++++++++++++++++ .idea/vcs.xml | 22 ++++++++++++++++++ 8 files changed, 95 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/modules/fixtures.iml create mode 100644 .idea/prettier.xml create mode 100644 .idea/rtx.iml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 000000000..a55e7a179 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..64d6d1127 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..9c1941576 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/fixtures.iml b/.idea/modules/fixtures.iml new file mode 100644 index 000000000..0d39050a2 --- /dev/null +++ b/.idea/modules/fixtures.iml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 000000000..f6ac06c75 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/rtx.iml b/.idea/rtx.iml new file mode 100644 index 000000000..5af835124 --- /dev/null +++ b/.idea/rtx.iml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..7fde3db4a --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + \ No newline at end of file From 0a9c7658e9bbabbbec1be9e2bc83f3be2d62edb1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 12:30:11 -0600 Subject: [PATCH 0377/1891] better support for .rtx.toml in local/global commands (#253) --- Cargo.lock | 7 + Cargo.toml | 2 +- README.md | 25 +++- completions/_rtx | 12 +- completions/rtx.bash | 4 +- completions/rtx.fish | 6 +- man/man1/rtx.1 | 2 +- src/cli/global.rs | 83 ++++++----- src/cli/local.rs | 136 +++++++++++------- src/cli/plugins/install.rs | 4 +- src/cli/render_help.rs | 15 +- .../rtx__cli__global__tests__global-5.snap | 6 + .../rtx__cli__global__tests__global-6.snap | 6 + ...cal__tests__local_multiple_versions-2.snap | 4 +- ...cal__tests__local_multiple_versions-3.snap | 9 ++ ...local__tests__local_multiple_versions.snap | 2 +- .../snapshots/rtx__cli__ls__tests__ls-2.snap | 1 + .../snapshots/rtx__cli__ls__tests__ls-3.snap | 1 + .../snapshots/rtx__cli__ls__tests__ls-4.snap | 1 + .../snapshots/rtx__cli__ls__tests__ls-5.snap | 1 + .../snapshots/rtx__cli__ls__tests__ls.snap | 1 + src/config/config_file/mod.rs | 6 +- src/config/mod.rs | 25 ++-- src/env.rs | 88 +++--------- src/shorthands.rs | 2 +- src/test.rs | 51 +++++-- src/ui/multi_progress_report.rs | 16 ++- src/ui/progress_report.rs | 2 +- 28 files changed, 303 insertions(+), 215 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__global__tests__global-5.snap create mode 100644 src/cli/snapshots/rtx__cli__global__tests__global-6.snap create mode 100644 src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap diff --git a/Cargo.lock b/Cargo.lock index f803afb67..c7e163d1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -798,6 +798,7 @@ dependencies = [ "console", "number_prefix", "portable-atomic", + "unicode-segmentation", "unicode-width", ] @@ -1945,6 +1946,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" diff --git a/Cargo.toml b/Cargo.toml index b7c8a85cb..cfe4ef8a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ flate2 = "1.0.25" humantime = "2.1.0" indenter = "0.3.3" indexmap = "1.9.2" -indicatif = "0.17.3" +indicatif = { version = "0.17.3", features = ["default", "improved_unicode"] } indoc = "2.0.0" itertools = "0.10.5" lazy_static = "1.4.0" diff --git a/README.md b/README.md index 4d785bc58..10e2c02eb 100644 --- a/README.md +++ b/README.md @@ -1165,7 +1165,11 @@ Examples: Shows/sets the global runtime version(s) Displays the contents of ~/.tool-versions after writing. -The file is `$HOME/.tool-versions` by default. +The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_GLOBAL_FILE`. +If `$RTX_GLOBAL_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. +Otherwise, it will be parsed as a `.tool-versions` file. +A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. + Use `rtx local` to set a runtime version locally in the current directory. Usage: global [OPTIONS] [RUNTIME]... @@ -1190,6 +1194,9 @@ Options: --remove Remove the plugin(s) from ~/.tool-versions + --path + Get the path of the global config file + Examples: # set the current version of nodejs to 18.x # will use a fuzzy version (e.g.: 18) in .tool-versions file @@ -1275,20 +1282,21 @@ Examples: ### `rtx local` ``` -Sets .tool-versions to include a specific runtime +Sets or gets tool versions in the local .tool-versions or .rtx.toml file -then displays the contents of .tool-versions -use this to set the runtime version when within a directory -use `rtx global` to set a runtime version globally +Use this to set a tool's version when within a directory +Use `rtx global` to set a runtime version globally +This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` +is set. A future v2 release of rtx will default to using `.rtx.toml`. Usage: local [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - Runtimes to add to .tool-versions + Runtimes to add to .tool-versions/.rtx.toml e.g.: nodejs@18 if this is a single runtime with no version, - the current value of .tool-versions will be displayed + the current value of .tool-versions/.rtx.toml will be displayed Options: -p, --parent @@ -1305,6 +1313,9 @@ Options: --remove Remove the plugin(s) from .tool-versions + --path + Get the path of the config file + Examples: # set the current version of nodejs to 18.x for the current directory # will use a precise version (e.g.: 18.0.0) in .tool-versions file diff --git a/completions/_rtx b/completions/_rtx index f743d092e..ae9aca8e7 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -547,6 +547,7 @@ e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions] '--fuzzy[Save fuzzy version to `~/.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ +'--path[Get the path of the global config file]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -658,6 +659,7 @@ by default this command will only set the runtime in the current directory ("$PW '--pin[Save exact version to `.tool-versions` e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions]' \ '--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ +'--path[Get the path of the config file]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -666,10 +668,10 @@ sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtimes to add to .tool-versions +'*::runtime -- Runtimes to add to .tool-versions/.rtx.toml e.g.\: nodejs@18 if this is a single runtime with no version, -the current value of .tool-versions will be displayed:' \ +the current value of .tool-versions/.rtx.toml will be displayed:' \ && ret=0 ;; (ls) @@ -1506,8 +1508,8 @@ _rtx_commands() { 'install:Install a runtime' \ 'i:Install a runtime' \ 'latest:Gets the latest available version for a plugin' \ -'local:Sets .tool-versions to include a specific runtime' \ -'l:Sets .tool-versions to include a specific runtime' \ +'local:Sets or gets tool versions in the local .tool-versions or .rtx.toml file' \ +'l:Sets or gets tool versions in the local .tool-versions or .rtx.toml file' \ 'ls:List installed runtime versions' \ 'list:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ @@ -1858,7 +1860,7 @@ _rtx__help_commands() { 'implode:Removes rtx CLI and all related data' \ 'install:Install a runtime' \ 'latest:Gets the latest available version for a plugin' \ -'local:Sets .tool-versions to include a specific runtime' \ +'local:Sets or gets tool versions in the local .tool-versions or .rtx.toml file' \ 'ls:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ 'mangen:Generate man pages' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 44bda2848..f4bf7375b 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1265,7 +1265,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -v -h --pin --fuzzy --remove --jobs --log-level --raw --verbose --help [RUNTIME]..." + opts="-j -r -v -h --pin --fuzzy --remove --path --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2115,7 +2115,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -v -h --parent --pin --fuzzy --remove --jobs --log-level --raw --verbose --help [RUNTIME]..." + opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 0e2f58337..509c70553 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -23,7 +23,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] calle complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets or gets tool versions in the local .tool-versions or .rtx.toml file' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "mangen" -d 'Generate man pages' @@ -225,6 +225,7 @@ e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' +complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' @@ -273,6 +274,7 @@ by default this command will only set the runtime in the current directory ("$PW complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' +complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' @@ -487,7 +489,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets .tool-versions to include a specific runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets or gets tool versions in the local .tool-versions or .rtx.toml file' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 049e09f34..250cba909 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -80,7 +80,7 @@ rtx\-latest(1) Gets the latest available version for a plugin .TP rtx\-local(1) -Sets .tool\-versions to include a specific runtime +Sets or gets tool versions in the local .tool\-versions or .rtx.toml file .TP rtx\-ls(1) List installed runtime versions diff --git a/src/cli/global.rs b/src/cli/global.rs index a0d63f4f1..4f645329d 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use color_eyre::eyre::Result; use console::style; use indoc::formatdoc; @@ -5,7 +7,8 @@ use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; -use crate::config::{config_file, Config}; +use crate::cli::local::local; +use crate::config::Config; use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; @@ -13,7 +16,11 @@ use crate::{dirs, env}; /// Shows/sets the global runtime version(s) /// /// Displays the contents of ~/.tool-versions after writing. -/// The file is `$HOME/.tool-versions` by default. +/// The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_GLOBAL_FILE`. +/// If `$RTX_GLOBAL_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. +/// Otherwise, it will be parsed as a `.tool-versions` file. +/// A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. +/// /// Use `rtx local` to set a runtime version locally in the current directory. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP.as_str())] @@ -39,39 +46,35 @@ pub struct Global { /// Remove the plugin(s) from ~/.tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] remove: Option>, + + /// Get the path of the global config file + #[clap(long)] + path: bool, } impl Command for Global { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let cf_path = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); - - let mut cf = match cf_path.exists() { - true => config_file::parse(&cf_path)?, - false => config_file::init(&cf_path), - }; - - if let Some(plugins) = &self.remove { - for plugin in plugins { - cf.remove_plugin(plugin); - } - } - if let Some(runtimes) = &self.runtime { - let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); - if cf.display_runtime(out, &runtimes)? { - return Ok(()); - } - let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); - cf.add_runtimes(&mut config, &runtimes, pin)?; - } + fn run(self, config: Config, out: &mut Output) -> Result<()> { + local( + config, + out, + &global_file(), + self.runtime, + self.remove, + self.pin, + self.fuzzy, + self.path, + ) + } +} - if self.runtime.is_some() || self.remove.is_some() { - cf.save()?; +fn global_file() -> PathBuf { + env::RTX_GLOBAL_FILE.clone().unwrap_or_else(|| { + if *env::RTX_USE_TOML { + dirs::CONFIG.join("config.toml") + } else { + dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) } - - rtxprint!(out, "{}", cf.dump()); - - Ok(()) - } + }) } static AFTER_LONG_HELP: Lazy = Lazy::new(|| { @@ -95,10 +98,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { mod tests { use std::fs; - use insta::assert_snapshot; use pretty_assertions::assert_str_eq; - use crate::{assert_cli, assert_cli_err, dirs}; + use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; #[test] fn test_global() { @@ -107,18 +109,13 @@ mod tests { let _ = fs::remove_file(&cf_path); assert_cli!("install", "tiny@2"); - let stdout = assert_cli!("global", "--pin", "tiny@2"); - assert_snapshot!(stdout); - let stdout = assert_cli!("global", "tiny@2"); - assert_snapshot!(stdout); - let stdout = assert_cli!("global", "--remove", "tiny"); - assert_snapshot!(stdout); - let stdout = assert_cli!("global", "--pin", "tiny", "2"); - assert_snapshot!(stdout); + assert_cli_snapshot!("global", "--pin", "tiny@2"); + assert_cli_snapshot!("global", "tiny@2"); + assert_cli_snapshot!("global", "--remove", "tiny"); + assert_cli_snapshot!("global", "--pin", "tiny", "2"); // will output the current version(s) - let stdout = assert_cli!("global", "tiny"); - assert_str_eq!(stdout, "2.1.0\n"); + assert_cli_snapshot!("global", "tiny"); // this plugin isn't installed let err = assert_cli_err!("global", "invalid-plugin"); @@ -135,6 +132,8 @@ mod tests { let err = assert_cli_err!("global", "tiny", "dummy@latest"); assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + assert_cli_snapshot!("global", "--path"); + if let Some(orig) = orig { fs::write(cf_path, orig).unwrap(); } diff --git a/src/cli/local.rs b/src/cli/local.rs index 4b25b632d..9f5014525 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -1,3 +1,5 @@ +use std::path::{Path, PathBuf}; + use color_eyre::eyre::{eyre, ContextCompat, Result}; use console::style; use indoc::formatdoc; @@ -9,20 +11,21 @@ use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::output::Output; use crate::plugins::PluginName; -use crate::{dirs, file}; +use crate::{dirs, env, file}; -/// Sets .tool-versions to include a specific runtime +/// Sets or gets tool versions in the local .tool-versions or .rtx.toml file /// -/// then displays the contents of .tool-versions -/// use this to set the runtime version when within a directory -/// use `rtx global` to set a runtime version globally +/// Use this to set a tool's version when within a directory +/// Use `rtx global` to set a runtime version globally +/// This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` +/// is set. A future v2 release of rtx will default to using `.rtx.toml`. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP.as_str())] pub struct Local { - /// Runtimes to add to .tool-versions + /// Runtimes to add to .tool-versions/.rtx.toml /// e.g.: nodejs@18 /// if this is a single runtime with no version, - /// the current value of .tool-versions will be displayed + /// the current value of .tool-versions/.rtx.toml will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, @@ -45,62 +48,92 @@ pub struct Local { /// Remove the plugin(s) from .tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] remove: Option>, + + /// Get the path of the config file + #[clap(long)] + path: bool, } impl Command for Local { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let cf_path = match self.parent { - true => file::find_up( - &dirs::CURRENT, - &[ - RTX_DEFAULT_CONFIG_FILENAME.as_str(), - RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str(), - ], - ) - .with_context(|| { - eyre!( - "no {} file found", - RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() - ) - })?, - false => { - let rtx_toml = dirs::CURRENT.join(RTX_DEFAULT_CONFIG_FILENAME.as_str()); - if rtx_toml.exists() { - rtx_toml - } else { - dirs::CURRENT.join(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) - } - } + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let path = if self.parent { + get_parent_path()? + } else { + get_path() }; + local( + config, + out, + &path, + self.runtime, + self.remove, + self.pin, + self.fuzzy, + self.path, + ) + } +} - let mut cf = match cf_path.exists() { - true => config_file::parse(&cf_path)?, - false => config_file::init(&cf_path), - }; +fn get_path() -> PathBuf { + let rtx_toml = dirs::CURRENT.join(RTX_DEFAULT_CONFIG_FILENAME.as_str()); + if *env::RTX_USE_TOML || rtx_toml.exists() { + rtx_toml + } else { + dirs::CURRENT.join(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) + } +} - if let Some(plugins) = &self.remove { - for plugin in plugins { - cf.remove_plugin(plugin); - } - } +fn get_parent_path() -> Result { + let mut filenames = vec![RTX_DEFAULT_CONFIG_FILENAME.as_str()]; + if !*env::RTX_USE_TOML { + filenames.push(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); + } + file::find_up(&dirs::CURRENT, &filenames) + .with_context(|| eyre!("no {} file found", filenames.join(" or "),)) +} - if let Some(runtimes) = &self.runtime { - let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); - if cf.display_runtime(out, &runtimes)? { - return Ok(()); - } - let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); - cf.add_runtimes(&mut config, &runtimes, pin)?; - } +#[allow(clippy::too_many_arguments)] +pub fn local( + mut config: Config, + out: &mut Output, + path: &Path, + runtime: Option>, + remove: Option>, + pin: bool, + fuzzy: bool, + show_path: bool, +) -> Result<()> { + let mut cf = match path.exists() { + true => config_file::parse(path)?, + false => config_file::init(path), + }; + if show_path { + rtxprintln!(out, "{}", path.display()); + return Ok(()); + } - if self.runtime.is_some() || self.remove.is_some() { - cf.save()?; + if let Some(plugins) = &remove { + for plugin in plugins { + cf.remove_plugin(plugin); } + } - rtxprint!(out, "{}", cf.dump()); + if let Some(runtimes) = &runtime { + let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); + if cf.display_runtime(out, &runtimes)? { + return Ok(()); + } + let pin = pin || (config.settings.asdf_compat && !fuzzy); + cf.add_runtimes(&mut config, &runtimes, pin)?; + } - Ok(()) + if runtime.is_some() || remove.is_some() { + cf.save()?; } + + rtxprint!(out, "{}", cf.dump()); + + Ok(()) } static AFTER_LONG_HELP: Lazy = Lazy::new(|| { @@ -183,6 +216,7 @@ mod tests { #[test] fn test_local_multiple_versions() { run_test(|| { + assert_cli_snapshot!("local", "--path"); assert_cli_snapshot!("local", "tiny@2", "tiny@1", "tiny@3"); assert_cli_snapshot!("bin-paths"); }); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 579f4647b..36a569ef9 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -117,9 +117,7 @@ impl PluginsInstall { let mut plugin = Plugin::new(name); plugin.repo_url = Some(git_url.to_string()); if !self.force && plugin.is_installed() { - mpr.suspend(|| { - warn!("plugin {} already installed", name); - }); + mpr.warn(format!("plugin {} already installed", name)); } else { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 803c6fe4b..5d10ee570 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -87,11 +87,22 @@ fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option #[cfg(test)] mod tests { use crate::assert_cli; + use indoc::indoc; + use std::fs; #[test] fn test_render_help() { + fs::write( + "README.md", + indoc! {r#" + + + "#}, + ) + .unwrap(); assert_cli!("render-help"); - let readme = std::fs::read_to_string("README.md").unwrap(); - assert!(readme.contains("")); + let readme = fs::read_to_string("README.md").unwrap(); + assert!(readme.contains("## Commands")); + fs::remove_file("README.md").unwrap(); } } diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-5.snap b/src/cli/snapshots/rtx__cli__global__tests__global-5.snap new file mode 100644 index 000000000..f498cb9e4 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__global__tests__global-5.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/global.rs +expression: output +--- +2.1.0 + diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-6.snap b/src/cli/snapshots/rtx__cli__global__tests__global-6.snap new file mode 100644 index 000000000..f91f9f636 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__global__tests__global-6.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/global.rs +expression: output +--- +~/.test-tool-versions + diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap index bb1b9fe63..6465eb1b6 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap @@ -2,7 +2,5 @@ source: src/cli/local.rs expression: output --- -~/data/installs/tiny/2.1.0/bin -~/data/installs/tiny/1.0.1/bin -~/data/installs/tiny/3.1.0/bin +tiny 2 1 3 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap new file mode 100644 index 000000000..e2d22c7ee --- /dev/null +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap @@ -0,0 +1,9 @@ +--- +source: src/cli/local.rs +expression: output +--- +~/data/installs/tiny/2.1.0/bin +~/data/installs/tiny/1.0.1/bin +~/data/installs/tiny/3.1.0/bin +~/data/installs/dummy/ref-master/bin + diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap index 6465eb1b6..3107c39d8 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap @@ -2,5 +2,5 @@ source: src/cli/local.rs expression: output --- -tiny 2 1 3 +~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap index ec55ccb5a..7b7b4737b 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap @@ -2,6 +2,7 @@ source: src/cli/ls.rs expression: output --- +-> dummy ref-master (set by ~/.test-tool-versions) tiny 2.0.0 -> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap index d8b37b9de..94b78cf02 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap @@ -2,6 +2,7 @@ source: src/cli/ls.rs expression: output --- +-> dummy ref-master (set by ~/.test-tool-versions) tiny 2.0.0 tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap index fc0661b53..26eedac31 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap @@ -2,5 +2,6 @@ source: src/cli/ls.rs expression: output --- +-> dummy ref-master (set by ~/.test-tool-versions) tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap index 4889a9c4c..4a88870a3 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap @@ -2,5 +2,6 @@ source: src/cli/ls.rs expression: output --- +-> dummy ref-master (set by ~/.test-tool-versions) -> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap index 4889a9c4c..4a88870a3 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap @@ -2,5 +2,6 @@ source: src/cli/ls.rs expression: output --- +-> dummy ref-master (set by ~/.test-tool-versions) -> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 486934ce1..7d23ff8d0 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -123,7 +123,7 @@ impl dyn ConfigFile { } pub fn init(path: &Path) -> Box { - if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) { + if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) || path.ends_with(".toml") { return Box::new(RtxToml::init(path)); } else if path.ends_with(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) { return Box::new(ToolVersions::init(path)); @@ -143,7 +143,7 @@ pub fn parse(path: &Path) -> Result> { fn detect_config_file_type(path: &Path) -> Option { match path.file_name().unwrap().to_str().unwrap() { - "config.toml" => Some(ConfigFileType::RtxToml), + f if f.ends_with(".toml") => Some(ConfigFileType::RtxToml), f if env::RTX_DEFAULT_CONFIG_FILENAME.as_str() == f => Some(ConfigFileType::RtxToml), f if env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() == f => { Some(ConfigFileType::ToolVersions) @@ -164,7 +164,7 @@ mod tests { ); assert_eq!( detect_config_file_type(Path::new("/foo/bar/.tool-versions.toml")), - None + Some(ConfigFileType::RtxToml) ); } } diff --git a/src/config/mod.rs b/src/config/mod.rs index c1057ae75..d536516ab 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -228,14 +228,23 @@ fn load_config_filenames(legacy_filenames: &IndexMap) -> Vec let mut config_files = file::FindUp::new(&dirs::CURRENT, &filenames).collect::>(); - let home_config = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); - if home_config.is_file() { - config_files.push(home_config); - } - let global_config = dirs::CONFIG.join("config.toml"); - if global_config.is_file() { - config_files.push(global_config); - } + match env::RTX_GLOBAL_FILE.clone() { + Some(global) => { + if global.is_file() { + config_files.push(global); + } + } + None => { + let home_config = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); + if home_config.is_file() { + config_files.push(home_config); + } + let global_config = dirs::CONFIG.join("config.toml"); + if global_config.is_file() { + config_files.push(global_config); + } + } + }; config_files.into_iter().unique().collect() } diff --git a/src/env.rs b/src/env.rs index da99c98b8..ca44c0387 100644 --- a/src/env.rs +++ b/src/env.rs @@ -10,63 +10,25 @@ use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; lazy_static! { pub static ref ARGS: Vec = args().collect(); - pub static ref HOME: PathBuf = if cfg!(test) { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test") - } else { - dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/")) - }; - pub static ref PWD: PathBuf = if cfg!(test) { - HOME.join("cwd") - } else { - current_dir().unwrap_or_else(|_| PathBuf::new()) - }; - pub static ref XDG_CACHE_HOME: PathBuf = if cfg!(test) { - HOME.join("cache") - } else { - dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache")) - }; - pub static ref XDG_DATA_HOME: PathBuf = if cfg!(test) { - HOME.join("data") - } else { - var_os("XDG_DATA_HOME") - .map(PathBuf::from) - .unwrap_or_else(|| HOME.join(".local/share")) - }; - pub static ref XDG_CONFIG_HOME: PathBuf = if cfg!(test) { - HOME.join("config") - } else { - var_os("XDG_CONFIG_HOME") - .map(PathBuf::from) - .unwrap_or_else(|| HOME.join(".config")) - }; - pub static ref RTX_CACHE_DIR: PathBuf = if cfg!(test) { - XDG_CACHE_HOME.clone() - } else { - var_os("RTX_CACHE_DIR") - .map(PathBuf::from) - .unwrap_or_else(|| XDG_CACHE_HOME.join("rtx")) - }; - pub static ref RTX_CONFIG_DIR: PathBuf = if cfg!(test) { - XDG_CONFIG_HOME.clone() - } else { - var_os("RTX_CONFIG_DIR") - .map(PathBuf::from) - .unwrap_or_else(|| XDG_CONFIG_HOME.join("rtx")) - }; - pub static ref RTX_DATA_DIR: PathBuf = if cfg!(test) { - XDG_DATA_HOME.clone() - } else { - var_os("RTX_DATA_DIR") - .map(PathBuf::from) - .unwrap_or_else(|| XDG_DATA_HOME.join("rtx")) - }; + + // paths and directories + pub static ref HOME: PathBuf = dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/")); + pub static ref PWD: PathBuf =current_dir().unwrap_or_else(|_| PathBuf::new()); + pub static ref XDG_CACHE_HOME: PathBuf = dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache")); + pub static ref XDG_DATA_HOME: PathBuf =var_path("XDG_DATA_HOME").unwrap_or_else(|| HOME.join(".local/share")); + pub static ref XDG_CONFIG_HOME: PathBuf =var_path("XDG_CONFIG_HOME").unwrap_or_else(|| HOME.join(".config")); + pub static ref RTX_CACHE_DIR: PathBuf =var_path("RTX_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("rtx")); + pub static ref RTX_CONFIG_DIR: PathBuf =var_path("RTX_CONFIG_DIR").unwrap_or_else(|| XDG_CONFIG_HOME.join("rtx")); + pub static ref RTX_DATA_DIR: PathBuf = var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx")); + pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String =var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()); + pub static ref RTX_DEFAULT_CONFIG_FILENAME: String =var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into()); + pub static ref RTX_GLOBAL_FILE: Option = var_path("RTX_GLOBAL_FILE"); + pub static ref RTX_USE_TOML: bool = var_is_true("RTX_USE_TOML"); pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); - pub static ref RTX_EXE: PathBuf = if cfg!(test) { - "rtx".into() - } else { - current_exe().unwrap_or_else(|_| "rtx".into()) - }; + pub static ref RTX_EXE: PathBuf = if cfg!(test) {"rtx".into()} else {current_exe().unwrap_or_else(|_| "rtx".into())}; + + // logging pub static ref RTX_LOG_LEVEL: log::LevelFilter = { let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); match log_level.parse::() { @@ -91,11 +53,7 @@ lazy_static! { _ => *RTX_LOG_LEVEL, } }; - pub static ref RTX_MISSING_RUNTIME_BEHAVIOR: Option = if cfg!(test) { - Some("autoinstall".into()) - } else { - var("RTX_MISSING_RUNTIME_BEHAVIOR").ok() - }; + pub static ref RTX_MISSING_RUNTIME_BEHAVIOR: Option =var("RTX_MISSING_RUNTIME_BEHAVIOR").ok(); pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); @@ -110,16 +68,6 @@ lazy_static! { Some(path) => split_paths(path).collect(), None => vec![], }; - pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String = if cfg!(test) { - ".test-tool-versions".into() - } else { - var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) - }; - pub static ref RTX_DEFAULT_CONFIG_FILENAME: String = if cfg!(test) { - ".test.rtx.toml".into() - } else { - var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into()) - }; pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); pub static ref RTX_EXPERIMENTAL: bool = var_is_true("RTX_EXPERIMENTAL"); diff --git a/src/shorthands.rs b/src/shorthands.rs index a6bfb90da..615371dc7 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -58,7 +58,7 @@ mod tests { #[test] fn test_get_shorthands() { let settings = Settings { - shorthands_file: Some("test/fixtures/shorthands.toml".into()), + shorthands_file: Some("../fixtures/shorthands.toml".into()), ..Settings::default() }; let shorthands = get_shorthands(&settings); diff --git a/src/test.rs b/src/test.rs index ef04d7569..3684dd048 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,5 +1,6 @@ -use std::env::join_paths; +use std::env::{join_paths, set_current_dir}; use std::fs; +use std::path::PathBuf; use indoc::indoc; @@ -11,27 +12,55 @@ fn init() { // TODO: fix this panic!("cannot run tests when rtx is activated"); } + env::set_var( + "HOME", + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test"), + ); + set_current_dir(env::HOME.join("cwd")).unwrap(); env::set_var("NO_COLOR", "1"); + env::set_var("RTX_DATA_DIR", env::HOME.join("data")); + env::set_var("RTX_CONFIG_DIR", env::HOME.join("config")); + env::set_var("RTX_CACHE_DIR", env::HOME.join("data/cache")); + env::set_var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME", ".test-tool-versions"); + env::set_var("RTX_DEFAULT_CONFIG_FILENAME", ".test.rtx.toml"); + env::set_var("RTX_MISSING_RUNTIME_BEHAVIOR", "autoinstall"); + //env::set_var("TERM", "dumb"); env_logger::init(); reset_config(); assert_cli!("install", "tiny@1", "tiny@2", "tiny@3", "tiny", "dummy"); } pub fn reset_config() { + fs::write( + env::HOME.join(".test-tool-versions"), + indoc! {r#" + tiny 2 + dummy ref:master + "#}, + ) + .unwrap(); + fs::write( + env::PWD.join(".test-tool-versions"), + indoc! {r#" + tiny 3 + "#}, + ) + .unwrap(); fs::write( env::HOME.join("config/config.toml"), indoc! {r#" - experimental = true - verbose = true - missing_runtime_behavior= 'autoinstall' - always_keep_download= true - legacy_version_file= true - plugin_autoupdate_last_check_duration = 20 - jobs = 2 - shims_dir = '~/data/shims' + [settings] + experimental = true + verbose = true + missing_runtime_behavior= 'autoinstall' + always_keep_download= true + legacy_version_file= true + plugin_autoupdate_last_check_duration = 20 + jobs = 2 + shims_dir = '~/data/shims' - [alias.tiny] - "my/alias" = '3.0' + [alias.tiny] + "my/alias" = '3.0' "#}, ) .unwrap(); diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index c4821adad..0bead47c9 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,6 +1,8 @@ -use crate::ui::progress_report::ProgressReport; +use console::style; use indicatif::MultiProgress; +use crate::ui::progress_report::ProgressReport; + #[derive(Debug)] pub struct MultiProgressReport { mp: Option, @@ -31,6 +33,18 @@ impl MultiProgressReport { None => f(), } } + pub fn warn(&self, message: String) { + match &self.mp { + Some(pb) => { + let _ = pb.println(format!( + "{} {}", + style("[WARN]").yellow().for_stderr(), + message + )); + } + None => warn!("{}", message), + } + } // pub fn clear(&self) { // match &self.mp { // Some(mp) => { diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index c99d917be..3dc9948db 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -45,7 +45,7 @@ impl ProgressReport { pub fn enable_steady_tick(&self) { match &self.pb { - Some(pb) => pb.enable_steady_tick(Duration::from_millis(100)), + Some(pb) => pb.enable_steady_tick(Duration::from_millis(250)), None => (), } } From c2e698dfdcf19386c43cadc9e47120193bf76bd4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 17:15:44 -0600 Subject: [PATCH 0378/1891] feat: added `rtx shell --unset` (#255) Fixes #252 --- .bin/rtx | 2 +- README.md | 6 +++++- completions/_rtx | 2 ++ completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/shell.rs | 11 ++++++++++- 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index 5d8552b60..30bd6a146 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -2,4 +2,4 @@ set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -cargo run --all-features --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" +cargo run -q --all-features --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" diff --git a/README.md b/README.md index 10e2c02eb..9b14c8389 100644 --- a/README.md +++ b/README.md @@ -1620,12 +1620,16 @@ Sets a tool version for the current shell session Only works in a session where rtx is already activated. -Usage: shell [RUNTIME]... +Usage: shell [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... Runtime version(s) to use +Options: + -u, --unset + Removes a previously set version + Examples: $ rtx shell nodejs@18 $ node -v diff --git a/completions/_rtx b/completions/_rtx index ae9aca8e7..7deed47b6 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1099,6 +1099,8 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-u[Removes a previously set version]' \ +'--unset[Removes a previously set version]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index f4bf7375b..21ea06c17 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2777,7 +2777,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help [RUNTIME]..." + opts="-u -j -r -v -h --unset --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 509c70553..ec64681bb 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -431,6 +431,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' diff --git a/src/cli/shell.rs b/src/cli/shell.rs index b02176272..f35d89027 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -24,6 +24,10 @@ pub struct Shell { /// Runtime version(s) to use #[clap(value_parser = RuntimeArgParser)] runtime: Vec, + + /// Removes a previously set version + #[clap(long, short)] + unset: bool, } impl Command for Shell { @@ -41,7 +45,12 @@ impl Command for Shell { let source = &ts.versions.get(&rtv.plugin.name).unwrap().source; if matches!(source, ToolSource::Argument) { let k = format!("RTX_{}_VERSION", rtv.plugin.name.to_uppercase()); - rtxprintln!(out, "{}", shell.set_env(&k, &rtv.version)); + let op = if self.unset { + shell.unset_env(&k) + } else { + shell.set_env(&k, &rtv.version) + }; + out.stdout.writeln(op); } } touch_dir(&dirs::ROOT)?; From e4dec4495b42d7c347c1901d9bbf9c4d3727c1ad Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 17:22:23 -0600 Subject: [PATCH 0379/1891] lock plugin/install/shim directories when modifying them (#256) * bug: fix shims pointing to system versions * lock plugin/install/shim directories when modifying --- Cargo.lock | 11 ++++ Cargo.toml | 1 + src/cli/install.rs | 8 +-- src/cli/plugins/install.rs | 5 +- src/cli/reshim.rs | 105 +---------------------------- src/config/mod.rs | 23 +++++++ src/lock_file.rs | 40 ++++++++++++ src/main.rs | 11 ++-- src/plugins/mod.rs | 24 +++++-- src/runtimes.rs | 21 +++++- src/shims.rs | 127 +++++++++++++++++++++++++++++++++--- src/toolset/mod.rs | 7 +- src/toolset/tool_version.rs | 4 +- 13 files changed, 253 insertions(+), 134 deletions(-) create mode 100644 src/lock_file.rs diff --git a/Cargo.lock b/Cargo.lock index c7e163d1e..e51b8f1b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,6 +551,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "futures-channel" version = "0.3.26" @@ -1401,6 +1411,7 @@ dependencies = [ "exec", "filetime", "flate2", + "fslock", "humantime", "indenter", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index cfe4ef8a1..1c4387e20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ dirs-next = "2.0.0" duct = "0.13.6" filetime = "0.2.19" flate2 = "1.0.25" +fslock = "0.2.1" humantime = "2.1.0" indenter = "0.3.3" indexmap = "1.9.2" diff --git a/src/cli/install.rs b/src/cli/install.rs index 724146f8d..8a42d68af 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -15,6 +15,7 @@ use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; use crate::plugins::{Plugin, PluginName}; +use crate::shims::reshim; use crate::toolset::{ToolVersion, ToolVersionType, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -104,7 +105,7 @@ impl Install { None => { let plugin = Plugin::new(&tv.plugin_name); let mut pr = mpr.add(); - match plugin.install(&config, &mut pr) { + match plugin.install(&config, &mut pr, false) { Ok(_) => Arc::new(plugin), Err(err) => { pr.error(); @@ -158,7 +159,7 @@ impl Install { } let mut pr = mpr.add(); rtv.decorate_progress_bar(&mut pr); - match rtv.install(&config, &mut pr) { + match rtv.install(&config, &mut pr, self.force) { Ok(_) => Ok(()), Err(err) => { pr.error(); @@ -167,8 +168,7 @@ impl Install { } }) .collect::>>()?; - - Ok(()) + reshim(&mut config, &ts) }) } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 36a569ef9..0584e82c5 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -121,10 +121,7 @@ impl PluginsInstall { } else { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr); - if self.force { - plugin.uninstall(&pr)?; - } - plugin.install(config, &mut pr)?; + plugin.install(config, &mut pr, self.force)?; } Ok(()) } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 2e5d40ca3..8498af182 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,8 +1,3 @@ -use std::fs; -use std::os::unix::fs::symlink; -use std::os::unix::prelude::*; -use std::path::{Path, PathBuf}; - use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; @@ -10,11 +5,10 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; -use crate::env::RTX_EXE; -use crate::file::{create_dir_all, remove_dir_all}; + use crate::output::Output; +use crate::shims; use crate::toolset::ToolsetBuilder; -use crate::{dirs, fake_asdf}; /// [experimental] rebuilds the shim farm /// @@ -35,91 +29,8 @@ impl Command for Reshim { if !config.settings.experimental { err_experimental()?; } - let shims_dir = get_shims_dir(&config)?; - - // remove old shims - let _ = remove_dir_all(&shims_dir); - create_dir_all(&shims_dir)?; - - for path in ts.list_paths(&config) { - if !path.exists() { - continue; - } - for bin in path.read_dir()? { - let bin = bin?; - if !bin.file_type()?.is_file() && !bin.file_type()?.is_symlink() { - continue; - } - let bin_name = bin.file_name().into_string().unwrap(); - let symlink_path = shims_dir.join(bin_name); - make_symlink(&RTX_EXE, &symlink_path)?; - } - } - for plugin in config.plugins.values() { - match plugin.plugin_path.join("shims").read_dir() { - Ok(files) => { - for bin in files { - let bin = bin?; - let bin_name = bin.file_name().into_string().unwrap(); - let symlink_path = shims_dir.join(bin_name); - make_shim(&bin.path(), &symlink_path)?; - } - } - Err(_) => { - continue; - } - } - } - - Ok(()) - } -} - -fn make_symlink(target: &Path, link: &Path) -> Result<()> { - if link.exists() { - fs::remove_file(link)?; - } - symlink(target, link)?; - trace!("symlinked {} to {}", target.display(), link.display()); - Ok(()) -} - -fn make_shim(target: &Path, shim: &Path) -> Result<()> { - if shim.exists() { - fs::remove_file(shim)?; - } - fs::write( - shim, - formatdoc! {r#" - #!/bin/sh - export ASDF_DATA_DIR={data_dir} - export PATH="{fake_asdf_dir}:$PATH" - rtx x -- {target} "$@" - "#, - data_dir = dirs::ROOT.display(), - fake_asdf_dir = fake_asdf::setup()?.display(), - target = target.display()}, - )?; - let mut perms = shim.metadata()?.permissions(); - perms.set_mode(0o755); - fs::set_permissions(shim, perms)?; - trace!( - "shim created from {} to {}", - target.display(), - shim.display() - ); - Ok(()) -} -fn get_shims_dir(config: &Config) -> Result { - match config.settings.shims_dir.clone() { - Some(mut shims_dir) => { - if shims_dir.starts_with("~") { - shims_dir = dirs::HOME.join(shims_dir.strip_prefix("~")?); - } - Ok(shims_dir) - } - None => err_no_shims_dir(), + shims::reshim(&mut config, &ts) } } @@ -133,16 +44,6 @@ fn err_experimental() -> Result<()> { ))); } -fn err_no_shims_dir() -> Result { - return Err(eyre!(formatdoc!( - r#" - rtx is not configured to use shims. - Please set the `{}` setting to a directory. - "#, - style("shims_dir").yellow() - ))); -} - static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} diff --git a/src/config/mod.rs b/src/config/mod.rs index d536516ab..3ed9f4782 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use color_eyre::eyre::{eyre, Result, WrapErr}; use color_eyre::Report; +use console::style; use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::OnceCell; @@ -152,6 +153,18 @@ impl Config { aliases } + + pub fn get_shims_dir(&self) -> Result { + match self.settings.shims_dir.clone() { + Some(mut shims_dir) => { + if shims_dir.starts_with("~") { + shims_dir = dirs::HOME.join(shims_dir.strip_prefix("~")?); + } + Ok(shims_dir) + } + None => err_no_shims_dir(), + } + } } fn load_rtxrc() -> Result { @@ -325,6 +338,16 @@ fn err_load_settings(settings_path: &Path) -> Report { ) } +fn err_no_shims_dir() -> Result { + return Err(eyre!(indoc::formatdoc!( + r#" + rtx is not configured to use shims. + Please set the `{}` setting to a directory. + "#, + style("shims_dir").yellow() + ))); +} + impl Display for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let plugins = self diff --git a/src/lock_file.rs b/src/lock_file.rs new file mode 100644 index 000000000..2b62124cd --- /dev/null +++ b/src/lock_file.rs @@ -0,0 +1,40 @@ +use crate::file::create_dir_all; +use std::path::{Path, PathBuf}; + +pub type OnLockedFn = Box; + +pub struct LockFile { + path: PathBuf, + on_locked: Option, +} + +impl LockFile { + pub fn new(path: &Path) -> Self { + Self { + path: path.with_extension(".lock\0"), + on_locked: None, + } + } + + pub fn with_callback(mut self, cb: F) -> Self + where + F: Fn(&Path) + 'static, + { + self.on_locked = Some(Box::new(cb)); + self + } + + pub fn lock(self) -> Result { + if let Some(parent) = self.path.parent() { + create_dir_all(parent)?; + } + let mut lock = fslock::LockFile::open(&self.path)?; + if !lock.try_lock()? { + if let Some(f) = self.on_locked { + f(&self.path) + } + lock.lock()?; + } + Ok(lock) + } +} diff --git a/src/main.rs b/src/main.rs index 852710146..71d6f4212 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ mod cli; mod cmd; mod config; mod default_shorthands; +mod direnv; mod dirs; mod env; mod env_diff; @@ -32,21 +33,19 @@ mod errors; mod fake_asdf; mod file; mod git; +mod hash; mod hook_env; +mod lock_file; mod logger; mod plugins; pub mod runtimes; mod shell; mod shims; mod shorthands; -mod ui; - -mod direnv; -mod hash; -mod toolset; - #[cfg(test)] mod test; +mod toolset; +mod ui; fn main() -> Result<()> { color_eyre::install()?; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 0f7d0a58f..91a649d88 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -7,9 +7,7 @@ use color_eyre::eyre::WrapErr; use color_eyre::eyre::{eyre, Result}; use console::style; use indexmap::IndexMap; - use itertools::Itertools; - use regex::Regex; use versions::Versioning; @@ -20,9 +18,10 @@ use crate::cmd::cmd; use crate::config::{Config, Settings}; use crate::env::RTX_PREFER_STALE; use crate::errors::Error::PluginNotInstalled; -use crate::file::remove_dir_all; +use crate::file::{display_path, remove_dir_all}; use crate::git::Git; use crate::hash::hash_to_str; +use crate::lock_file::LockFile; use crate::plugins::script_manager::Script::ParseLegacyFile; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; use crate::{dirs, file}; @@ -92,7 +91,7 @@ impl Plugin { git.get_remote_url() } - pub fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { + pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { self.decorate_progress_bar(pr); let repository = self .repo_url @@ -100,6 +99,9 @@ impl Plugin { .or_else(|| config.get_shorthands().get(&self.name)) .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; debug!("install {} {:?}", self.name, repository); + + let _lock = self.get_lock(force)?; + if self.is_installed() { self.uninstall(pr)?; } @@ -426,6 +428,20 @@ impl Plugin { fs::write(fp, legacy_version)?; Ok(()) } + + fn get_lock(&self, force: bool) -> Result> { + let lock = if force { + None + } else { + let lock = LockFile::new(&self.plugin_path) + .with_callback(|l| { + debug!("waiting for lock on {}", display_path(l)); + }) + .lock()?; + Some(lock) + }; + Ok(lock) + } } impl PartialEq for Plugin { diff --git a/src/runtimes.rs b/src/runtimes.rs index 1a6f5f7a7..992100378 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -16,6 +16,7 @@ use crate::config::Settings; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::file::{create_dir_all, display_path, remove_dir_all}; use crate::hash::hash_to_str; +use crate::lock_file::LockFile; use crate::plugins::Script::{Download, ExecEnv, Install}; use crate::plugins::{Plugin, Script, ScriptManager}; use crate::toolset::{ToolVersion, ToolVersionType}; @@ -78,10 +79,11 @@ impl RuntimeVersion { } } - pub fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { + pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { self.decorate_progress_bar(pr); let settings = &config.settings; + let _lock = self.get_lock(force, pr)?; self.create_install_dirs()?; let run_script = |script| { @@ -224,6 +226,8 @@ impl RuntimeVersion { .cmd(settings, &Script::ListBinPaths) .read()?; output.split_whitespace().map(|f| f.to_string()).collect() + } else if self.version == "system" { + vec![] } else { vec!["bin".into()] }; @@ -268,6 +272,21 @@ impl RuntimeVersion { )); pr.enable_steady_tick(); } + + fn get_lock(&self, force: bool, _pr: &ProgressReport) -> Result> { + let lock = if force { + None + } else { + let lock = LockFile::new(&self.install_path) + .with_callback(|l| { + // pr.set_message(format!("waiting for lock on {}", display_path(l))); + debug!("waiting for lock on {}", display_path(l)); + }) + .lock()?; + Some(lock) + }; + Ok(lock) + } } impl Display for RuntimeVersion { diff --git a/src/shims.rs b/src/shims.rs index 7d5831850..e63770051 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -1,13 +1,23 @@ use std::ffi::OsString; +use std::fs; +use std::os::unix::fs::{symlink, PermissionsExt}; +use std::path::{Path, PathBuf}; use std::process::exit; use color_eyre::eyre::{eyre, Result}; +use indoc::formatdoc; use crate::cli::command::Command; use crate::cli::exec::Exec; use crate::config::Config; +use crate::dirs; +use crate::env; +use crate::env::RTX_EXE; +use crate::fake_asdf; +use crate::file::{create_dir_all, remove_dir_all}; +use crate::lock_file::LockFile; use crate::output::Output; -use crate::toolset::ToolsetBuilder; +use crate::toolset::{Toolset, ToolsetBuilder}; // executes as if it was a shim if the command is not "rtx", e.g.: "node" pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Result { @@ -15,9 +25,8 @@ pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Res if bin_name == "rtx" || !config.settings.experimental { return Ok(config); } - is_valid_shim(&mut config, bin_name)?; let mut args: Vec = args.iter().map(OsString::from).collect(); - args[0] = OsString::from(bin_name); + args[0] = which_shim(&mut config, bin_name)?.into(); let exec = Exec { runtime: vec![], c: None, @@ -27,10 +36,112 @@ pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Res exit(0); } -fn is_valid_shim(config: &mut Config, bin_name: &str) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; - match ts.which(config, bin_name) { - Some(_) => Ok(()), - None => Err(eyre!("{} is not a valid shim", bin_name)), +fn which_shim(config: &mut Config, bin_name: &str) -> Result { + if let Ok(shims_dir) = config.get_shims_dir() { + let shim = shims_dir.join(bin_name); + if shim.exists() { + let ts = ToolsetBuilder::new().build(config)?; + if let Some(rtv) = ts.which(config, bin_name) { + if let Some(bin) = rtv.which(&config.settings, bin_name)? { + return Ok(bin); + } + } + // fallback for "system" + for path in &*env::PATH { + if fs::canonicalize(path).unwrap_or_default() + == fs::canonicalize(&shims_dir).unwrap_or_default() + { + continue; + } + let bin = path.join(bin_name); + if bin.exists() { + return Ok(bin); + } + } + } } + Err(eyre!("{} is not a valid shim", bin_name)) +} + +pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { + if !config.settings.experimental { + return Ok(()); + } + let shims_dir = config.get_shims_dir()?; + let _lock = LockFile::new(&shims_dir) + .with_callback(|l| { + trace!("reshim callback {}", l.display()); + }) + .lock(); + + // remove old shims + let _ = remove_dir_all(&shims_dir); + create_dir_all(&shims_dir)?; + + for path in ts.list_paths(config) { + if !path.exists() { + continue; + } + for bin in path.read_dir()? { + let bin = bin?; + if !bin.file_type()?.is_file() && !bin.file_type()?.is_symlink() { + continue; + } + let bin_name = bin.file_name().into_string().unwrap(); + let symlink_path = shims_dir.join(bin_name); + make_symlink(&RTX_EXE, &symlink_path)?; + } + } + for plugin in config.plugins.values() { + match plugin.plugin_path.join("shims").read_dir() { + Ok(files) => { + for bin in files { + let bin = bin?; + let bin_name = bin.file_name().into_string().unwrap(); + let symlink_path = shims_dir.join(bin_name); + make_shim(&bin.path(), &symlink_path)?; + } + } + Err(_) => { + continue; + } + } + } + + Ok(()) +} + +fn make_symlink(target: &Path, link: &Path) -> Result<()> { + if link.exists() { + fs::remove_file(link)?; + } + symlink(target, link)?; + Ok(()) +} + +fn make_shim(target: &Path, shim: &Path) -> Result<()> { + if shim.exists() { + fs::remove_file(shim)?; + } + fs::write( + shim, + formatdoc! {r#" + #!/bin/sh + export ASDF_DATA_DIR={data_dir} + export PATH="{fake_asdf_dir}:$PATH" + rtx x -- {target} "$@" + "#, + data_dir = dirs::ROOT.display(), + fake_asdf_dir = fake_asdf::setup()?.display(), + target = target.display()}, + )?; + let mut perms = shim.metadata()?.permissions(); + perms.set_mode(0o755); + fs::set_permissions(shim, perms)?; + trace!( + "shim created from {} to {}", + target.display(), + shim.display() + ); + Ok(()) } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index f917c7a20..3d7c08444 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -24,6 +24,7 @@ use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; +use crate::shims::reshim; use crate::ui::multi_progress_report::MultiProgressReport; mod builder; @@ -162,12 +163,12 @@ impl Toolset { for version in versions { let mut pr = mpr.add(); version.resolve(config, plugin.clone())?; - version.install(config, &mut pr)?; + version.install(config, &mut pr, false)?; } Ok(()) }) .collect::>>()?; - Ok(()) + reshim(config, self) }) } fn install_missing_plugins( @@ -189,7 +190,7 @@ impl Toolset { .filter(|p| !p.is_installed()) .map(|p| { let mut pr = mpr.add(); - p.install(config, &mut pr) + p.install(config, &mut pr, false) }) .collect::>>()?; Ok(()) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 398180f9b..02f46e40f 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -122,10 +122,10 @@ impl ToolVersion { } } - pub fn install(&mut self, config: &Config, pr: &mut ProgressReport) -> Result<()> { + pub fn install(&mut self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { match self.r#type { ToolVersionType::Version(_) | ToolVersionType::Prefix(_) | ToolVersionType::Ref(_) => { - self.rtv.as_ref().unwrap().install(config, pr) + self.rtv.as_ref().unwrap().install(config, pr, force) } _ => Ok(()), } From 93d5a5fe08c41d2f6b5737c52e464c4a1f7cbabc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 19:06:03 -0600 Subject: [PATCH 0380/1891] added `rtx prune` (#257) --- README.md | 25 +++++ completions/_rtx | 43 +++++++++ completions/rtx.bash | 50 +++++++++- completions/rtx.fish | 82 +++++++++------- man/man1/rtx.1 | 7 ++ src/cli/install.rs | 2 +- src/cli/mod.rs | 3 + src/cli/prune.rs | 93 +++++++++++++++++++ .../rtx__cli__global__tests__global-2.snap | 2 +- .../rtx__cli__global__tests__global-3.snap | 2 +- .../rtx__cli__global__tests__global-4.snap | 2 +- .../rtx__cli__global__tests__global.snap | 2 +- src/cli/uninstall.rs | 2 +- ...nfig_file__rtx_toml__tests__fixture-6.snap | 2 +- src/config/mod.rs | 40 ++++++++ src/config/tracking.rs | 60 ++++++++++++ src/file.rs | 11 ++- src/runtimes.rs | 5 +- src/shims.rs | 14 +-- src/ui/progress_report.rs | 7 ++ 20 files changed, 400 insertions(+), 54 deletions(-) create mode 100644 src/cli/prune.rs create mode 100644 src/config/tracking.rs diff --git a/README.md b/README.md index 9b14c8389..d1d2dc120 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ v18.10.9 * [rtx plugins ls-remote](#rtx-plugins-ls-remote) * [rtx plugins uninstall](#rtx-plugins-uninstall) * [rtx plugins update](#rtx-plugins-update) + * [rtx prune](#rtx-prune) * [rtx reshim](#rtx-reshim) * [rtx self-update](#rtx-self-update) * [rtx settings get](#rtx-settings-get) @@ -1519,6 +1520,30 @@ Examples: $ rtx plugins update --all # update all plugins $ rtx plugins update nodejs # update only nodejs ``` +### `rtx prune` + +``` +Delete unused versions of tools +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`). + +Usage: prune [OPTIONS] [PLUGINS]... + +Arguments: + [PLUGINS]... + Prune only versions from these plugins + +Options: + --dry-run + Do not actually delete anything + +Examples: + $ rtx prune --dry-run + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 +``` ### `rtx reshim` ``` diff --git a/completions/_rtx b/completions/_rtx index 7deed47b6..01a9e2dcc 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -919,6 +919,25 @@ esac ;; esac ;; +(prune) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--dry-run[Do not actually delete anything]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +sets --jobs=1]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::plugins -- Prune only versions from these plugins:' \ +&& ret=0 +;; (reshim) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel @@ -1408,6 +1427,10 @@ _arguments "${_arguments_options[@]}" \ ;; esac ;; +(prune) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (reshim) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1518,6 +1541,11 @@ _rtx_commands() { 'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ +'prune:Delete unused versions of tools +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`).' \ 'reshim:\[experimental\] rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ @@ -1867,6 +1895,11 @@ _rtx__help_commands() { 'ls-remote:List runtime versions available for install' \ 'mangen:Generate man pages' \ 'plugins:Manage plugins' \ +'prune:Delete unused versions of tools +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`).' \ 'reshim:\[experimental\] rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ @@ -2100,6 +2133,16 @@ _rtx__plugins_commands() { ) _describe -t commands 'rtx plugins commands' commands "$@" } +(( $+functions[_rtx__help__prune_commands] )) || +_rtx__help__prune_commands() { + local commands; commands=() + _describe -t commands 'rtx help prune commands' commands "$@" +} +(( $+functions[_rtx__prune_commands] )) || +_rtx__prune_commands() { + local commands; commands=() + _describe -t commands 'rtx prune commands' commands "$@" +} (( $+functions[_rtx__help__render-help_commands] )) || _rtx__help__render-help_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 21ea06c17..64c247f3d 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -102,6 +102,9 @@ _rtx() { rtx,plugins) cmd="rtx__plugins" ;; + rtx,prune) + cmd="rtx__prune" + ;; rtx,render-help) cmd="rtx__render__help" ;; @@ -291,6 +294,9 @@ _rtx() { rtx__help,plugins) cmd="rtx__help__plugins" ;; + rtx__help,prune) + cmd="rtx__help__prune" + ;; rtx__help,render-help) cmd="rtx__help__render__help" ;; @@ -475,7 +481,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --jobs --log-level --raw --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where which render-help help" + opts="-j -r -v -h -V --jobs --log-level --raw --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1295,7 +1301,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins reshim self-update settings shell uninstall version where which render-help help" + opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1812,6 +1818,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__prune) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__render__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2484,6 +2504,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__prune) + opts="-j -r -v -h --dry-run --jobs --log-level --raw --verbose --help [PLUGINS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__render__help) opts="-j -r -v -h --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index ec64681bb..a6c5f4105 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -28,6 +28,11 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "mangen" -d 'Generate man pages' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`).' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] rebuilds the shim farm' complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' @@ -369,6 +374,14 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' +complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from prune" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r @@ -473,38 +486,43 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Dir sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Shows/sets the global runtime version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets or gets tool versions in the local .tool-versions or .rtx.toml file' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Shows/sets the global runtime version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets or gets tool versions in the local .tool-versions or .rtx.toml file' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`).' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 250cba909..4372db3c6 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -91,6 +91,13 @@ List runtime versions available for install rtx\-plugins(1) Manage plugins .TP +rtx\-prune(1) +Delete unused versions of tools +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`). +.TP rtx\-reshim(1) [experimental] rebuilds the shim farm .TP diff --git a/src/cli/install.rs b/src/cli/install.rs index 8a42d68af..988d29a9b 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -138,7 +138,7 @@ impl Install { .map(|rtv| { let mut pr = mpr.add(); rtv.decorate_progress_bar(&mut pr); - match rtv.uninstall(&config.settings, &pr) { + match rtv.uninstall(&config.settings, &pr, false) { Ok(_) => { pr.finish(); Ok(()) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 3eade47a5..dafd68312 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -35,6 +35,7 @@ mod ls_remote; #[cfg(feature = "clap_mangen")] mod mangen; mod plugins; +mod prune; #[cfg(debug_assertions)] mod render_help; mod reshim; @@ -76,6 +77,7 @@ pub enum Commands { #[cfg(feature = "clap_mangen")] Mangen(mangen::Mangen), Plugins(plugins::Plugins), + Prune(prune::Prune), Reshim(reshim::Reshim), SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), @@ -115,6 +117,7 @@ impl Commands { #[cfg(feature = "clap_mangen")] Self::Mangen(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), + Self::Prune(cmd) => cmd.run(config, out), Self::Reshim(cmd) => cmd.run(config, out), Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), diff --git a/src/cli/prune.rs b/src/cli/prune.rs new file mode 100644 index 000000000..3578a5e9b --- /dev/null +++ b/src/cli/prune.rs @@ -0,0 +1,93 @@ +use color_eyre::eyre::Result; +use console::style; +use indexmap::IndexMap; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; +use crate::plugins::PluginName; +use crate::runtimes::RuntimeVersion; +use crate::toolset::ToolsetBuilder; +use crate::ui::multi_progress_report::MultiProgressReport; + +/// Delete unused versions of tools +/// rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +/// Versions which are no longer the latest specified in any of those configs are deleted. +/// Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +/// as will versions only referenced on the command line (`rtx exec @`). +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +pub struct Prune { + /// Prune only versions from these plugins + #[clap()] + pub plugins: Option>, + + /// Do not actually delete anything + #[clap(long)] + pub dry_run: bool, +} + +impl Command for Prune { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&mut config)?; + let mut to_delete = ts + .list_installed_versions(&config)? + .into_iter() + .map(|rtv| (rtv.to_string(), rtv)) + .collect::>(); + + if let Some(plugins) = &self.plugins { + to_delete.retain(|_, rtv| plugins.contains(&rtv.plugin.name)); + } + + for cf in config.get_tracked_config_files()?.values() { + let mut ts = cf.to_toolset().clone(); + ts.resolve(&config); + for rtv in ts.list_current_versions() { + to_delete.remove(&rtv.to_string()); + } + } + + self.delete(&config, to_delete.into_values().collect()) + } +} + +impl Prune { + fn delete(&self, config: &Config, to_delete: Vec) -> Result<()> { + let mpr = MultiProgressReport::new(config.settings.verbose); + for rtv in to_delete { + let mut pr = mpr.add(); + rtv.decorate_progress_bar(&mut pr); + if self.dry_run { + pr.set_prefix(format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); + } + rtv.uninstall(&config.settings, &pr, self.dry_run)?; + pr.finish(); + } + Ok(()) + } +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx prune --dry-run + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 + "#, style("Examples:").bold().underlined()} +}); + +#[cfg(test)] +mod tests { + use crate::{assert_cli, cmd}; + + #[test] + fn test_prune() { + assert_cli!("prune", "--dry-run"); + assert_cli!("prune", "tiny"); + assert_cli!("prune"); + cmd!("git", "checkout", "../data").run().unwrap(); + } +} diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap index be36578d5..1f9e2e3f4 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap @@ -1,6 +1,6 @@ --- source: src/cli/global.rs -expression: stdout +expression: output --- tiny 2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap index 94891b1fd..2c986ca59 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap @@ -1,6 +1,6 @@ --- source: src/cli/global.rs -expression: stdout +expression: output --- diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap index 41595052f..3be683205 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap @@ -1,6 +1,6 @@ --- source: src/cli/global.rs -expression: stdout +expression: output --- tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global.snap b/src/cli/snapshots/rtx__cli__global__tests__global.snap index 41595052f..3be683205 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global.snap @@ -1,6 +1,6 @@ --- source: src/cli/global.rs -expression: stdout +expression: output --- tiny 2.1.0 diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 5826e153b..e4261c47e 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -36,7 +36,7 @@ impl Command for Uninstall { let mut pr = mpr.add(); rtv.decorate_progress_bar(&mut pr); - if let Err(err) = rtv.uninstall(&config.settings, &pr) { + if let Err(err) = rtv.uninstall(&config.settings, &pr, false) { pr.error(); return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", rtv))); } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index bc8a50e9e..16c08f5dc 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf +expression: replace_path(&cf.to_string()) --- [env] NODE_ENV = 'production' diff --git a/src/config/mod.rs b/src/config/mod.rs index 3ed9f4782..1d0c3bba8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::thread; use color_eyre::eyre::{eyre, Result, WrapErr}; use color_eyre::Report; @@ -17,12 +18,14 @@ use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::ConfigFile; use crate::config::settings::SettingsBuilder; +use crate::config::tracking::Tracker; use crate::plugins::{Plugin, PluginName}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::{dirs, env, file, hook_env}; pub mod config_file; mod settings; +mod tracking; type AliasMap = IndexMap>; @@ -61,6 +64,7 @@ impl Config { let legacy_files = load_legacy_files(&settings, &plugins); let config_filenames = load_config_filenames(&legacy_files); + let config_track = track_config_files(&config_filenames); let (config_files, should_exit_early) = rayon::join( || { @@ -84,6 +88,7 @@ impl Config { }); } } + config_track.join().unwrap(); let config = Self { env: load_env(&config_files), @@ -165,6 +170,25 @@ impl Config { None => err_no_shims_dir(), } } + + pub fn get_tracked_config_files(&self) -> Result>> { + let tracker = Tracker::new(); + let config_files = tracker + .list_all()? + .into_par_iter() + .map(|path| match config_file::parse(&path) { + Ok(cf) => Some((path, cf)), + Err(err) => { + error!("Error loading config file: {:#}", err); + None + } + }) + .collect::>() + .into_iter() + .flatten() + .collect(); + Ok(config_files) + } } fn load_rtxrc() -> Result { @@ -348,6 +372,22 @@ fn err_no_shims_dir() -> Result { ))); } +fn track_config_files(config_filenames: &[PathBuf]) -> thread::JoinHandle<()> { + let config_filenames = config_filenames.to_vec(); + let track = move || -> Result<()> { + let mut tracker = Tracker::new(); + for config_file in &config_filenames { + tracker.track(config_file)?; + } + Ok(()) + }; + thread::spawn(move || { + if let Err(err) = track() { + warn!("tracking config files: {:#}", err); + } + }) +} + impl Display for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let plugins = self diff --git a/src/config/tracking.rs b/src/config/tracking.rs new file mode 100644 index 000000000..51ecd2ef4 --- /dev/null +++ b/src/config/tracking.rs @@ -0,0 +1,60 @@ +use std::collections::HashSet; +use std::fs; +use std::fs::{read_dir, remove_file}; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::Result; + +use crate::dirs; +use crate::file::{create_dir_all, make_symlink}; +use crate::hash::hash_to_str; + +#[derive(Debug, Default)] +pub struct Tracker { + tracking_dir: PathBuf, + config_files: HashSet, +} + +impl Tracker { + pub fn new() -> Self { + Self { + tracking_dir: dirs::ROOT.join("tracked_config_files"), + ..Default::default() + } + } + + pub fn track(&mut self, path: &Path) -> Result<()> { + if !self.config_files.contains(path) { + let tracking_path = self.tracking_dir.join(hash_to_str(&path)); + if !tracking_path.exists() { + create_dir_all(&self.tracking_dir)?; + make_symlink(path, &tracking_path)?; + } + self.config_files.insert(path.to_path_buf()); + } + Ok(()) + } + + pub fn list_all(&self) -> Result> { + self.clean()?; + let mut output = vec![]; + for path in read_dir(&self.tracking_dir)? { + let path = path?.path(); + let path = fs::read_link(path)?; + if path.exists() { + output.push(path); + } + } + Ok(output) + } + + pub fn clean(&self) -> Result<()> { + for path in read_dir(&self.tracking_dir)? { + let path = path?.path(); + if !path.exists() { + remove_file(&path)?; + } + } + Ok(()) + } +} diff --git a/src/file.rs b/src/file.rs index 1932e4262..9e0c48f1a 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,9 +1,10 @@ -use std::io; use std::path::{Path, PathBuf}; use std::time::Duration; +use std::{fs, io}; use color_eyre::eyre::Result; use filetime::{set_file_times, FileTime}; +use std::os::unix::fs::symlink; use crate::dirs; @@ -184,3 +185,11 @@ mod tests { assert_eq!(display_path(&path), path.display().to_string()); } } + +pub fn make_symlink(target: &Path, link: &Path) -> Result<()> { + if link.exists() { + fs::remove_file(link)?; + } + symlink(target, link)?; + Ok(()) +} diff --git a/src/runtimes.rs b/src/runtimes.rs index 992100378..3f9490391 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -175,7 +175,7 @@ impl RuntimeVersion { } } - pub fn uninstall(&self, settings: &Settings, pr: &ProgressReport) -> Result<()> { + pub fn uninstall(&self, settings: &Settings, pr: &ProgressReport, dryrun: bool) -> Result<()> { pr.set_message(format!("uninstall {}", self)); if self.plugin.plugin_path.join("bin/uninstall").exists() { @@ -186,6 +186,9 @@ impl RuntimeVersion { return Ok(()); } pr.set_message(format!("removing {}", display_path(dir))); + if dryrun { + return Ok(()); + } remove_dir_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", diff --git a/src/shims.rs b/src/shims.rs index e63770051..596a066ab 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -1,6 +1,6 @@ use std::ffi::OsString; use std::fs; -use std::os::unix::fs::{symlink, PermissionsExt}; +use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; use std::process::exit; @@ -10,7 +10,6 @@ use indoc::formatdoc; use crate::cli::command::Command; use crate::cli::exec::Exec; use crate::config::Config; -use crate::dirs; use crate::env; use crate::env::RTX_EXE; use crate::fake_asdf; @@ -18,6 +17,7 @@ use crate::file::{create_dir_all, remove_dir_all}; use crate::lock_file::LockFile; use crate::output::Output; use crate::toolset::{Toolset, ToolsetBuilder}; +use crate::{dirs, file}; // executes as if it was a shim if the command is not "rtx", e.g.: "node" pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Result { @@ -89,7 +89,7 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { } let bin_name = bin.file_name().into_string().unwrap(); let symlink_path = shims_dir.join(bin_name); - make_symlink(&RTX_EXE, &symlink_path)?; + file::make_symlink(&RTX_EXE, &symlink_path)?; } } for plugin in config.plugins.values() { @@ -111,14 +111,6 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { Ok(()) } -fn make_symlink(target: &Path, link: &Path) -> Result<()> { - if link.exists() { - fs::remove_file(link)?; - } - symlink(target, link)?; - Ok(()) -} - fn make_shim(target: &Path, shim: &Path) -> Result<()> { if shim.exists() { fs::remove_file(shim)?; diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 3dc9948db..53f34da82 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -59,6 +59,13 @@ impl ProgressReport { } } + pub fn prefix(&self) -> String { + match &self.pb { + Some(pb) => pb.prefix(), + None => self.prefix.clone(), + } + } + pub fn set_style(&self, style: ProgressStyle) { match &self.pb { Some(pb) => { From e3404ec439f15c6d6cd691acc5014381e6e3dbd2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 19:06:43 -0600 Subject: [PATCH 0381/1891] chore: Release rtx-cli version 1.21.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 3 ++- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e51b8f1b3..243c173e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.20.4" +version = "1.21.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 1c4387e20..95008d2d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.20.4" +version = "1.21.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index d1d2dc120..aa98c3045 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.20.4 +rtx 1.21.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -331,7 +331,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.20.4/rtx-v1.20.4-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.0/rtx-v1.21.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index a5a0586bf..6d84c26b2 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.20.4"; + version = "1.21.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 4372db3c6..9cff21a29 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.20.4" +.TH rtx 1 "rtx 1.21.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -138,6 +138,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.20.4 +v1.21.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 2547bfb26..1432c4bf6 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.20.4 +Version: 1.21.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 322d824f8..5cce9bf4f 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 615] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 616] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -547,6 +547,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 615] = [ ("terraform-ls", "https://github.com/asdf-community/asdf-hashicorp.git"), ("terraform-lsp", "https://github.com/bartlomiejdanek/terraform-lsp.git"), ("terraform-validator", "https://github.com/looztra/asdf-terraform-validator.git"), + ("terraformer", "https://github.com/grimoh/asdf-terraformer.git"), ("terragrunt", "https://github.com/ohmer/asdf-terragrunt.git"), ("terramate", "https://github.com/martinlindner/asdf-terramate.git"), ("terrascan", "https://github.com/hpdobrica/asdf-terrascan.git"), From 3e4272502ec3c2ecd877aa225059f7719fa7d176 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 21:55:46 -0600 Subject: [PATCH 0382/1891] docs: readme TOC improvements --- README.md | 212 ++++++++++++------------ justfile | 2 +- scripts/gh-md-toc | 411 ---------------------------------------------- 3 files changed, 102 insertions(+), 523 deletions(-) delete mode 100755 scripts/gh-md-toc diff --git a/README.md b/README.md index aa98c3045..7ef16d561 100644 --- a/README.md +++ b/README.md @@ -70,117 +70,107 @@ v18.10.9 ## Table of Contents - - * [About](#about) - * [What do I use this for?](#what-do-i-use-this-for) - * [How it works](#how-it-works) - * [Common example commands](#common-example-commands) - * [Installation](#installation) - * [Standalone](#standalone) - * [Homebrew](#homebrew) - * [Cargo](#cargo) - * [npm](#npm) - * [GitHub Releases](#github-releases) - * [apt](#apt) - * [dnf](#dnf) - * [yum](#yum) - * [aur](#aur) - * [nix](#nix) - * [Other Shells](#other-shells) - * [Bash](#bash) - * [Fish](#fish) - * [Xonsh](#xonsh) - * [Something else?](#something-else) - * [Uninstalling](#uninstalling) - * [Configuration](#configuration) - * [.tool-versions](#tool-versions) - * [Legacy version files](#legacy-version-files) - * [Global config: ~/.config/rtx/config.toml](#global-config-configrtxconfigtoml) - * [[experimental] .rtx.toml](#experimental-rtxtoml) - * [Environment variables](#environment-variables) - * [RTX_MISSING_RUNTIME_BEHAVIOR](#rtx_missing_runtime_behavior) - * [RTX_DATA_DIR](#rtx_data_dir) - * [RTX_CACHE_DIR](#rtx_cache_dir) - * [RTX_CONFIG_FILE](#rtx_config_file) - * [RTX_DEFAULT_TOOL_VERSIONS_FILENAME](#rtx_default_tool_versions_filename) - * [RTX_${PLUGIN}_VERSION](#rtx_plugin_version) - * [RTX_LEGACY_VERSION_FILE](#rtx_legacy_version_file) - * [RTX_LOG_LEVEL=trace|debug|info|warn|error](#rtx_log_leveltracedebuginfowarnerror) - * [RTX_LOG_FILE=~/.rtx/rtx.log](#rtx_log_filertxrtxlog) - * [RTX_LOG_FILE_LEVEL=trace|debug|info|warn|error](#rtx_log_file_leveltracedebuginfowarnerror) - * [RTX_VERBOSE=1](#rtx_verbose1) - * [RTX_ASDF_COMPAT=1](#rtx_asdf_compat1) - * [RTX_JOBS=1](#rtx_jobs1) - * [RTX_RAW=1](#rtx_raw1) - * [RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml](#rtx_shorthands_fileconfigrtxshorthandstoml) - * [RTX_DISABLE_DEFAULT_SHORTHANDS=1](#rtx_disable_default_shorthands1) - * [RTX_HIDE_OUTDATED_BUILD=1](#rtx_hide_outdated_build1) - * [RTX_EXPERIMENTAL=1](#rtx_experimental1) - * [[experimental] RTX_SHIMS_DIR=~/.local/share/rtx/shims](#experimental-rtx_shims_dirlocalsharertxshims) - * [Aliases](#aliases) - * [Plugins](#plugins) - * [Plugin Options](#plugin-options) - * [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) - * [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) - * [Windows support?](#windows-support) - * [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) - * [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) - * [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - * [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) - * [Commands](#commands) - * [rtx activate](#rtx-activate) - * [rtx alias get](#rtx-alias-get) - * [rtx alias ls](#rtx-alias-ls) - * [rtx alias set](#rtx-alias-set) - * [rtx alias unset](#rtx-alias-unset) - * [rtx bin-paths](#rtx-bin-paths) - * [rtx cache clear](#rtx-cache-clear) - * [rtx complete](#rtx-complete) - * [rtx current](#rtx-current) - * [rtx deactivate](#rtx-deactivate) - * [rtx direnv activate](#rtx-direnv-activate) - * [rtx doctor](#rtx-doctor) - * [rtx env](#rtx-env) - * [rtx exec](#rtx-exec) - * [rtx global](#rtx-global) - * [rtx implode](#rtx-implode) - * [rtx install](#rtx-install) - * [rtx latest](#rtx-latest) - * [rtx local](#rtx-local) - * [rtx ls](#rtx-ls) - * [rtx ls-remote](#rtx-ls-remote) - * [rtx plugins install](#rtx-plugins-install) - * [rtx plugins ls](#rtx-plugins-ls) - * [rtx plugins ls-remote](#rtx-plugins-ls-remote) - * [rtx plugins uninstall](#rtx-plugins-uninstall) - * [rtx plugins update](#rtx-plugins-update) - * [rtx prune](#rtx-prune) - * [rtx reshim](#rtx-reshim) - * [rtx self-update](#rtx-self-update) - * [rtx settings get](#rtx-settings-get) - * [rtx settings ls](#rtx-settings-ls) - * [rtx settings set](#rtx-settings-set) - * [rtx settings unset](#rtx-settings-unset) - * [rtx shell](#rtx-shell) - * [rtx uninstall](#rtx-uninstall) - * [rtx version](#rtx-version) - * [rtx where](#rtx-where) - * [rtx which](#rtx-which) - * [Comparison to asdf](#comparison-to-asdf) - * [Performance](#performance) - * [Environment variables](#environment-variables-1) - * [UX](#ux) - * [CI/CD](#cicd) - * [GitHub Actions](#github-actions) - * [Shims](#shims) - * [direnv](#direnv) - * [rtx inside of direnv (use rtx in .envrc)](#rtx-inside-of-direnv-use-rtx-in-envrc) - * [Do you need direnv?](#do-you-need-direnv) - * [Cache Behavior](#cache-behavior) - * [Plugin Cache](#plugin-cache) - * [Legacy File Cache](#legacy-file-cache) - + +
+Click to expand + +- [30 Second Demo](#30-second-demo) +- [Features](#features) +- [Quickstart](#quickstart) +- [About](#about) + - [What do I use this for?](#what-do-i-use-this-for) + - [How it works](#how-it-works) + - [Common example commands](#common-example-commands) +- [Installation](#installation) + - [Standalone](#standalone) + - [Homebrew](#homebrew) + - [Cargo](#cargo) + - [npm](#npm) + - [GitHub Releases](#github-releases) + - [apt](#apt) + - [dnf](#dnf) + - [yum](#yum) + - [~~apk~~ (coming soon)](#apk-coming-soon) + - [aur](#aur) + - [nix](#nix) +- [Other Shells](#other-shells) + - [Bash](#bash) + - [Fish](#fish) + - [Xonsh](#xonsh) + - [Something else?](#something-else) +- [Uninstalling](#uninstalling) +- [Configuration](#configuration) + - [`.tool-versions`](#tool-versions) + - [Legacy version files](#legacy-version-files) + - [Global config: `~/.config/rtx/config.toml`](#global-config-configrtxconfigtoml) + - [[experimental] `.rtx.toml`](#experimental-rtxtoml) + - [Environment variables](#environment-variables) +- [Aliases](#aliases) +- [Plugins](#plugins) + - [Plugin Options](#plugin-options) +- [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) + - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) + - [Windows support?](#windows-support) + - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) + - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) + - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) + - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) +- [Commands](#commands) + - [`rtx activate`](#rtx-activate) + - [`rtx alias get`](#rtx-alias-get) + - [`rtx alias ls`](#rtx-alias-ls) + - [`rtx alias set`](#rtx-alias-set) + - [`rtx alias unset`](#rtx-alias-unset) + - [`rtx bin-paths`](#rtx-bin-paths) + - [`rtx cache clear`](#rtx-cache-clear) + - [`rtx complete`](#rtx-complete) + - [`rtx current`](#rtx-current) + - [`rtx deactivate`](#rtx-deactivate) + - [`rtx direnv activate`](#rtx-direnv-activate) + - [`rtx doctor`](#rtx-doctor) + - [`rtx env`](#rtx-env) + - [`rtx exec`](#rtx-exec) + - [`rtx global`](#rtx-global) + - [`rtx implode`](#rtx-implode) + - [`rtx install`](#rtx-install) + - [`rtx latest`](#rtx-latest) + - [`rtx local`](#rtx-local) + - [`rtx ls`](#rtx-ls) + - [`rtx ls-remote`](#rtx-ls-remote) + - [`rtx plugins install`](#rtx-plugins-install) + - [`rtx plugins ls`](#rtx-plugins-ls) + - [`rtx plugins ls-remote`](#rtx-plugins-ls-remote) + - [`rtx plugins uninstall`](#rtx-plugins-uninstall) + - [`rtx plugins update`](#rtx-plugins-update) + - [`rtx prune`](#rtx-prune) + - [`rtx reshim`](#rtx-reshim) + - [`rtx self-update`](#rtx-self-update) + - [`rtx settings get`](#rtx-settings-get) + - [`rtx settings ls`](#rtx-settings-ls) + - [`rtx settings set`](#rtx-settings-set) + - [`rtx settings unset`](#rtx-settings-unset) + - [`rtx shell`](#rtx-shell) + - [`rtx uninstall`](#rtx-uninstall) + - [`rtx version`](#rtx-version) + - [`rtx where`](#rtx-where) + - [`rtx which`](#rtx-which) +- [Comparison to asdf](#comparison-to-asdf) + - [Performance](#performance) + - [Environment variables](#environment-variables-1) + - [UX](#ux) + - [CI/CD](#cicd) + - [GitHub Actions](#github-actions) +- [Shims](#shims) +- [direnv](#direnv) + - [rtx inside of direnv (`use rtx` in `.envrc`)](#rtx-inside-of-direnv-use-rtx-in-envrc) + - [Do you need direnv?](#do-you-need-direnv) +- [Cache Behavior](#cache-behavior) + - [Plugin Cache](#plugin-cache) + - [Legacy File Cache](#legacy-file-cache) + +
+ ## About diff --git a/justfile b/justfile index f383f85f2..a48605905 100644 --- a/justfile +++ b/justfile @@ -76,7 +76,7 @@ lint-fix: # regenerate README.md render-help: build NO_COLOR=1 rtx render-help - ./scripts/gh-md-toc --insert --no-backup --hide-footer --skip-header README.md > /dev/null + npx markdown-magic # regenerate shell completion files render-completions: build diff --git a/scripts/gh-md-toc b/scripts/gh-md-toc deleted file mode 100755 index a23d2f78b..000000000 --- a/scripts/gh-md-toc +++ /dev/null @@ -1,411 +0,0 @@ -#!/usr/bin/env bash - -# -# Steps: -# -# 1. Download corresponding html file for some README.md: -# curl -s $1 -# -# 2. Discard rows where no substring 'user-content-' (github's markup): -# awk '/user-content-/ { ... -# -# 3.1 Get last number in each row like ' ... sitemap.js.*<\/h/)+2, RLENGTH-5) -# -# 5. Find anchor and insert it inside "(...)": -# substr($0, match($0, "href=\"[^\"]+?\" ")+6, RLENGTH-8) -# - -gh_toc_version="0.8.0" - -gh_user_agent="gh-md-toc v$gh_toc_version" - -# -# Download rendered into html README.md by its url. -# -# -gh_toc_load() { - local gh_url=$1 - - if type curl &>/dev/null; then - curl --user-agent "$gh_user_agent" -s "$gh_url" - elif type wget &>/dev/null; then - wget --user-agent="$gh_user_agent" -qO- "$gh_url" - else - echo "Please, install 'curl' or 'wget' and try again." - exit 1 - fi -} - -# -# Converts local md file into html by GitHub -# -# -> curl -X POST --data '{"text": "Hello world github/linguist#1 **cool**, and #1!"}' https://api.github.com/markdown -#

Hello world github/linguist#1 cool, and #1!

'" -gh_toc_md2html() { - local gh_file_md=$1 - local skip_header=$2 - - URL=https://api.github.com/markdown/raw - - if [ ! -z "$GH_TOC_TOKEN" ]; then - TOKEN=$GH_TOC_TOKEN - else - TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" - if [ -f "$TOKEN_FILE" ]; then - TOKEN="$(cat $TOKEN_FILE)" - fi - fi - if [ ! -z "${TOKEN}" ]; then - AUTHORIZATION="Authorization: token ${TOKEN}" - fi - - local gh_tmp_file_md=$gh_file_md - if [ "$skip_header" = "yes" ]; then - if grep -Fxq "" "$gh_src"; then - # cut everything before the toc - gh_tmp_file_md=$gh_file_md~~ - sed '1,//d' $gh_file_md > $gh_tmp_file_md - fi - fi - - # echo $URL 1>&2 - OUTPUT=$(curl -s \ - --user-agent "$gh_user_agent" \ - --data-binary @"$gh_tmp_file_md" \ - -H "Content-Type:text/plain" \ - -H "$AUTHORIZATION" \ - "$URL") - - rm -f $gh_file_md~~ - - if [ "$?" != "0" ]; then - echo "XXNetworkErrorXX" - fi - if [ "$(echo "${OUTPUT}" | awk '/API rate limit exceeded/')" != "" ]; then - echo "XXRateLimitXX" - else - echo "${OUTPUT}" - fi -} - - -# -# Is passed string url -# -gh_is_url() { - case $1 in - https* | http*) - echo "yes";; - *) - echo "no";; - esac -} - -# -# TOC generator -# -gh_toc(){ - local gh_src=$1 - local gh_src_copy=$1 - local gh_ttl_docs=$2 - local need_replace=$3 - local no_backup=$4 - local no_footer=$5 - local indent=$6 - local skip_header=$7 - - if [ "$gh_src" = "" ]; then - echo "Please, enter URL or local path for a README.md" - exit 1 - fi - - - # Show "TOC" string only if working with one document - if [ "$gh_ttl_docs" = "1" ]; then - - echo "Table of Contents" - echo "=================" - echo "" - gh_src_copy="" - - fi - - if [ "$(gh_is_url "$gh_src")" == "yes" ]; then - gh_toc_load "$gh_src" | gh_toc_grab "$gh_src_copy" "$indent" - if [ "${PIPESTATUS[0]}" != "0" ]; then - echo "Could not load remote document." - echo "Please check your url or network connectivity" - exit 1 - fi - if [ "$need_replace" = "yes" ]; then - echo - echo "!! '$gh_src' is not a local file" - echo "!! Can't insert the TOC into it." - echo - fi - else - local rawhtml=$(gh_toc_md2html "$gh_src" "$skip_header") - if [ "$rawhtml" == "XXNetworkErrorXX" ]; then - echo "Parsing local markdown file requires access to github API" - echo "Please make sure curl is installed and check your network connectivity" - exit 1 - fi - if [ "$rawhtml" == "XXRateLimitXX" ]; then - echo "Parsing local markdown file requires access to github API" - echo "Error: You exceeded the hourly limit. See: https://developer.github.com/v3/#rate-limiting" - TOKEN_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/token.txt" - echo "or place GitHub auth token here: ${TOKEN_FILE}" - exit 1 - fi - local toc=`echo "$rawhtml" | gh_toc_grab "$gh_src_copy" "$indent"` - echo "$toc" - if [ "$need_replace" = "yes" ]; then - if grep -Fxq "" "$gh_src" && grep -Fxq "" "$gh_src"; then - echo "Found markers" - else - echo "You don't have or in your file...exiting" - exit 1 - fi - local ts="<\!--ts-->" - local te="<\!--te-->" - local dt=`date +'%F_%H%M%S'` - local ext=".orig.${dt}" - local toc_path="${gh_src}.toc.${dt}" - local toc_createdby="" - local toc_footer="" - # http://fahdshariff.blogspot.ru/2012/12/sed-mutli-line-replacement-between-two.html - # clear old TOC - sed -i${ext} "/${ts}/,/${te}/{//!d;}" "$gh_src" - # create toc file - echo "${toc}" > "${toc_path}" - if [ "${no_footer}" != "yes" ]; then - echo -e "\n${toc_createdby}\n${toc_footer}\n" >> "$toc_path" - fi - - # insert toc file - if ! sed --version > /dev/null 2>&1; then - sed -i "" "/${ts}/r ${toc_path}" "$gh_src" - else - sed -i "/${ts}/r ${toc_path}" "$gh_src" - fi - echo - if [ "${no_backup}" = "yes" ]; then - rm "$toc_path" "$gh_src$ext" - fi - echo "!! TOC was added into: '$gh_src'" - if [ -z "${no_backup}" ]; then - echo "!! Origin version of the file: '${gh_src}${ext}'" - echo "!! TOC added into a separate file: '${toc_path}'" - fi - echo - fi - fi -} - -# -# Grabber of the TOC from rendered html -# -# $1 - a source url of document. -# It's need if TOC is generated for multiple documents. -# $2 - number of spaces used to indent. -# -gh_toc_grab() { - common_awk_script=' - modified_href = "" - split(href, chars, "") - for (i=1;i <= length(href); i++) { - c = chars[i] - res = "" - if (c == "+") { - res = " " - } else { - if (c == "%") { - res = "\\x" - } else { - res = c "" - } - } - modified_href = modified_href res - } - print sprintf("%*s", (level-1)*'"$2"', "") "* [" text "](" gh_url modified_href ")" - ' - if [ `uname -s` == "OS/390" ]; then - grepcmd="pcregrep -o" - echoargs="" - awkscript='{ - level = substr($0, length($0), 1) - text = substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5) - href = substr($0, match($0, "href=\"([^\"]+)?\"")+6, RLENGTH-7) - '"$common_awk_script"' - }' - else - grepcmd="grep -Eo" - echoargs="-e" - awkscript='{ - level = substr($0, length($0), 1) - text = substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5) - href = substr($0, match($0, "href=\"[^\"]+?\"")+6, RLENGTH-7) - '"$common_awk_script"' - }' - fi - href_regex='href=\"[^\"]+?\"' - - # if closed is on the new line, then move it on the prev line - # for example: - # was: The command foo1 - # - # became: The command foo1 - sed -e ':a' -e 'N' -e '$!ba' -e 's/\n<\/h/<\/h/g' | - - # find strings that corresponds to template - $grepcmd '//g' | sed 's/<\/code>//g' | - - # remove g-emoji - sed 's/]*[^<]*<\/g-emoji> //g' | - - # now all rows are like: - # ... /dev/null`; then - echo `$tool --version | head -n 1` - else - echo "not installed" - fi - done -} - -show_help() { - local app_name=$(basename "$0") - echo "GitHub TOC generator ($app_name): $gh_toc_version" - echo "" - echo "Usage:" - echo " $app_name [options] src [src] Create TOC for a README file (url or local path)" - echo " $app_name - Create TOC for markdown from STDIN" - echo " $app_name --help Show help" - echo " $app_name --version Show version" - echo "" - echo "Options:" - echo " --indent Set indent size. Default: 3." - echo " --insert Insert new TOC into original file. For local files only. Default: false." - echo " See https://github.com/ekalinin/github-markdown-toc/issues/41 for details." - echo " --no-backup Remove backup file. Set --insert as well. Default: false." - echo " --hide-footer Do not write date & author of the last TOC update. Set --insert as well. Default: false." - echo " --skip-header Hide entry of the topmost headlines. Default: false." - echo " See https://github.com/ekalinin/github-markdown-toc/issues/125 for details." - echo "" -} - -# -# Options handlers -# -gh_toc_app() { - local need_replace="no" - local indent=3 - - if [ "$1" = '--help' ] || [ $# -eq 0 ] ; then - show_help - return - fi - - if [ "$1" = '--version' ]; then - show_version - return - fi - - if [ "$1" = '--indent' ]; then - indent="$2" - shift 2 - fi - - if [ "$1" = "-" ]; then - if [ -z "$TMPDIR" ]; then - TMPDIR="/tmp" - elif [ -n "$TMPDIR" -a ! -d "$TMPDIR" ]; then - mkdir -p "$TMPDIR" - fi - local gh_tmp_md - if [ `uname -s` == "OS/390" ]; then - local timestamp=$(date +%m%d%Y%H%M%S) - gh_tmp_md="$TMPDIR/tmp.$timestamp" - else - gh_tmp_md=$(mktemp $TMPDIR/tmp.XXXXXX) - fi - while read input; do - echo "$input" >> "$gh_tmp_md" - done - gh_toc_md2html "$gh_tmp_md" | gh_toc_grab "" "$indent" - return - fi - - if [ "$1" = '--insert' ]; then - need_replace="yes" - shift - fi - - if [ "$1" = '--no-backup' ]; then - need_replace="yes" - no_backup="yes" - shift - fi - - if [ "$1" = '--hide-footer' ]; then - need_replace="yes" - no_footer="yes" - shift - fi - - if [ "$1" = '--skip-header' ]; then - skip_header="yes" - shift - fi - - - for md in "$@" - do - echo "" - gh_toc "$md" "$#" "$need_replace" "$no_backup" "$no_footer" "$indent" "$skip_header" - done - - echo "" - echo "" -} - -# -# Entry point -# -gh_toc_app "$@" From f11acf59b8d47d41c98919d56a0519d6af7d8e85 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 23:31:18 -0600 Subject: [PATCH 0383/1891] docs --- README.md | 320 ++++++++++++++++++++++------------ completions/_rtx | 14 +- completions/rtx.fish | 12 +- man/man1/rtx.1 | 3 + scripts/pre-release-hook.sh | 2 +- src/cli/direnv/exec.rs | 6 +- src/cli/global.rs | 6 +- src/cli/self_update/github.rs | 32 +++- src/cli/self_update/other.rs | 33 +++- src/config/mod.rs | 2 +- src/env.rs | 4 +- src/plugins/mod.rs | 4 +- 12 files changed, 301 insertions(+), 137 deletions(-) diff --git a/README.md b/README.md index 7ef16d561..cd7ef93e7 100644 --- a/README.md +++ b/README.md @@ -108,14 +108,8 @@ v18.10.9 - [Aliases](#aliases) - [Plugins](#plugins) - [Plugin Options](#plugin-options) -- [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) - - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) - - [Windows support?](#windows-support) - - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) - - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) - - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) +- [Versioning](#versioning) + - [Calver Breaking Changes](#calver-breaking-changes) - [Commands](#commands) - [`rtx activate`](#rtx-activate) - [`rtx alias get`](#rtx-alias-get) @@ -155,9 +149,18 @@ v18.10.9 - [`rtx version`](#rtx-version) - [`rtx where`](#rtx-where) - [`rtx which`](#rtx-which) +- [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) + - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) + - [Windows support?](#windows-support) + - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) + - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) + - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) + - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) + - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) - [Comparison to asdf](#comparison-to-asdf) - [Performance](#performance) - - [Environment variables](#environment-variables-1) + - [Environment variables in rtx](#environment-variables-in-rtx) - [UX](#ux) - [CI/CD](#cicd) - [GitHub Actions](#github-actions) @@ -166,8 +169,7 @@ v18.10.9 - [rtx inside of direnv (`use rtx` in `.envrc`)](#rtx-inside-of-direnv-use-rtx-in-envrc) - [Do you need direnv?](#do-you-need-direnv) - [Cache Behavior](#cache-behavior) - - [Plugin Cache](#plugin-cache) - - [Legacy File Cache](#legacy-file-cache) + - [Plugin/Runtime Cache](#pluginruntime-cache) @@ -565,7 +567,9 @@ These settings can also be managed with `rtx settings ls|get|set|unset`. ### [experimental] `.rtx.toml` -`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` file. +`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` +file. Think of `~/.config/rtx/config.toml` as just a +special `.rtx.toml` which is used from any directory on the machine. It allows for functionality that is not possible with `.tool-versions`, such as: @@ -607,7 +611,9 @@ shims_dir = '~/.rtx/shims' my_custom_node = '18' ``` -`.rtx.toml` is currently experimental and may change in minor versions of rtx. +`.rtx.toml` is currently experimental and may change in minor versions of rtx. It does not +require setting `experimental = true` in the global config in part because this config can +itself contain the setting for `experimental`. ### Environment variables @@ -639,6 +645,12 @@ This is the path to the config file. The default is `~/.config/rtx/config.toml`. Set to something other than ".tool-versions" to have rtx look for configuration with alternate names. +#### `RTX_DEFAULT_CONFIG_FILENAME` + +Set to something other than ".rtx.toml" to have rtx look for configuration with alternate names. + +This is the same as `RTX_DEFAULT_TOOL_VERSIONS_FILENAME` but for `.rtx.toml` format. + #### `RTX_${PLUGIN}_VERSION` Set the version for a runtime. For example, `RTX_NODEJS_VERSION=18` will use nodejs@18.x regardless @@ -649,6 +661,11 @@ of what is set in `.tool-versions`. Plugins can read the versions files used by other version managers (if enabled by the plugin) for example, .nvmrc in the case of nodejs's nvm. +#### `RTX_USE_TOML` + +Set to `1` to use default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for +configuration. + #### `RTX_LOG_LEVEL=trace|debug|info|warn|error` Can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1`. These adjust the log @@ -780,97 +797,43 @@ any option and it will be passed to the plugin in that format. Currently this only supports simple strings, but we can make it compatible with more complex types (arrays, tables) fairly easily if there is a need for it. -## FAQs - -### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. - -You can make git ignore these files in 3 different ways: - -- Adding `.tool-versions` to project's `.gitignore` file. This has the downside that you need to commit the change to the ignore file. -- 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`. - -### rtx is failing or not working right - -First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. -You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. - -If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. -It can also be helpful to use `rtx env` which will just output environment variables that would be set. -Also consider using [shims](#shims) which can be more compatible. - -If runtime installation isn't working right, try using the `--raw` flag which will install things in -series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact -with you for some reason this will make it work. - -Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` -to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used -to remove everything except config. - -Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule -out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` -doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. - -Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues -detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. - -### Windows support? - -This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 - -It's not a near-term goal and it would require plugin modifications, but it should be feasible. - -### How do I use rtx with http proxies? - -Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. - -rtx doesn't really do anything with http itself. The only exception to that is checking for new versions -and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download -files with `curl` or `wget`. - -However this is really up to the plugin. If you're having a proxy-related issue installing something -you should post an issue on the plugin's repo. - -### How do the shorthand plugin names map to repositories? - -e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? - -asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. -This is regularly updated every time that rtx has a release. This repository is stored directly into -the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that -rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` -to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) -with some rtx features like virtualenv support. +## Versioning -Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific -enhancements. +rtx is currently a new project and is under very rapid development. Slight behavior changes may +occur between releases. +Features marked as "experimental" may change significantly or be removed entirely. -### How do I migrate from asdf? +Starting June 1, 2023*, rtx will move to [Calver](https://calver.org/) versioning (`2023.6.1`). After the move to Calver, rtx's design will become mostly permanent and you will be able to rely on +its behavior for the long term. +Breaking changes will be few but when they do happen, +they will be communicated in the CLI with plenty of notice whenever possible. -First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your -shell rc file. +Rather than have semver major releases to communicate change in large releases, +new functionality and changes can be opted-into with settings like `experimental = true`. +This way plugin authors and users can +test out new functionality immediately without waiting for a major release. -Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will -install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over -to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, -however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` -and see what happens. +The numbers in Calver (YYYY.MM.RELEASE) simply represent the date of the release—not compatibility +or how many new features were added. +Each release will be small and incremental. -If you need to switch to/from asdf or work in a project with asdf users, you can set [`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). +_*This plan is tentative and the details may change, but the rough idea of making many changes now so we can have stability later is the goal._ -### rtx isn't working with tmux +### Calver Breaking Changes -It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` -right after activating: +When we switch to Calver, we'll immediately make some notable design changes to rtx. This will +be the first and last time that such a change is made and I actually want to make sure we make +as many as we can—because we'll be stuck with these decisions. -```bash -eval "$(rtx activate bash)" -eval "$(rtx hook-env)" -``` +Here are a list of the changes that will be made: -This can also be useful if you need to use a runtime right away in an rc file. The default behavior -of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not -immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. +* `rtx local` will default to creating `.rtx.toml` instead of `.tool-versions`. (If the config + already exists the format will be preserved.) +* `rtx global` will modify `~/.config/rtx/config.toml` instead of `~/.tool-versions`. This path + can be changed with `RTX_CONFIG_FILE`. +* `~/.tool-versions` will become simply another `.tool-versions` instead of being a special file + that is read anywhere such as from `/tmp`. +* (more to be added) ## Commands @@ -1156,8 +1119,8 @@ Examples: Shows/sets the global runtime version(s) Displays the contents of ~/.tool-versions after writing. -The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_GLOBAL_FILE`. -If `$RTX_GLOBAL_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. +The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. +If `$RTX_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. Otherwise, it will be parsed as a `.tool-versions` file. A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. @@ -1554,8 +1517,30 @@ Examples: ``` Updates rtx itself +Uses whatever package manager was used to install rtx or just downloads +a binary from GitHub Releases if rtx was installed manually. +Supports: standalone, brew, deb, rpm Usage: self-update + +Examples: + $ rtx self-update + Checking target-arch... macos-arm64 + Checking current version... v1.0.0 + Checking latest released version... v1.21.0-DEBUG macos-arm64 (built 2023-03-04) + New release found! v1.0.0 --> v1.21.0-DEBUG macos-arm64 (built 2023-03-04) + New release is compatible + + rtx release status: + * Current exe: "/Users/jdx/bin/rtx" + * New exe release: "rtx-v1.21.0-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" + + The new release will be downloaded/extracted and the existing binary will be replaced. + Do you want to continue? [Y/n] y + Downloading... + Extracting archive... Done + Replacing binary file... Done + Updated rtx to 1.21.0-DEBUG macos-arm64 (built 2023-03-04) ``` ### `rtx settings get` @@ -1727,6 +1712,116 @@ Examples: ``` +## FAQs + +### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. + +You can make git ignore these files in 3 different ways: + +- Adding `.tool-versions` to project's `.gitignore` file. This has the downside that you need to commit the change to the ignore file. +- 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`. + +### rtx is failing or not working right + +First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. +You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. + +If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. +It can also be helpful to use `rtx env` which will just output environment variables that would be set. +Also consider using [shims](#shims) which can be more compatible. + +If runtime installation isn't working right, try using the `--raw` flag which will install things in +series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact +with you for some reason this will make it work. + +Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` +to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used +to remove everything except config. + +Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule +out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` +doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. + +Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues +detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. + +### Windows support? + +This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 + +It's not a near-term goal and it would require plugin modifications, but it should be feasible. + +### How do I use rtx with http proxies? + +Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. + +rtx doesn't really do anything with http itself. The only exception to that is checking for new versions +and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download +files with `curl` or `wget`. + +However this is really up to the plugin. If you're having a proxy-related issue installing something +you should post an issue on the plugin's repo. + +### How do the shorthand plugin names map to repositories? + +e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? + +asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. +This is regularly updated every time that rtx has a release. This repository is stored directly into +the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that +rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` +to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) +with some rtx features like virtualenv support. + +Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific +enhancements. + +### How do I migrate from asdf? + +First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your +shell rc file. + +Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will +install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over +to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, +however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` +and see what happens. + +### How compatible is rtx with asdf? + +rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin +should be usable in rtx. The commands in rtx are slightly +different, such as `rtx install nodejs@18.0.0` vs `asdf install nodejs 18.0.0`—this is done so +multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx +install nodejs 18.0.0`). This is the case for most commands, though the help for the command may +say that asdf-style syntax is supported. + +When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may +not be possible to support every command identically, but +we should attempt to make things as consistent as possible. + +This isn't important for usability reasons so much as making it so plugins continue to work that +call asdf commands. + +If you need to switch to/from asdf or work in a project with asdf users, you can set +[`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). That prevents +rtx from writing `.tool-versions` files that will not be +compatible with asdf. Also consider using `.rtx.toml` instead which won't conflict with asdf setups. + +### rtx isn't working with tmux + +It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` +right after activating: + +```bash +eval "$(rtx activate bash)" +eval "$(rtx hook-env)" +``` + +This can also be useful if you need to use a runtime right away in an rc file. The default behavior +of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not +immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. ## Comparison to asdf @@ -1755,7 +1850,7 @@ a full reload. tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~10ms) when the prompt loads. -### Environment variables +### Environment variables in rtx asdf only helps manage runtime executables. However, some tools are managed via environment variables (notably Java which switches via `JAVA_HOME`). This isn't supported very well in asdf and requires @@ -1901,16 +1996,17 @@ but I think we can handle enough common use cases to make that unnecessary for m rtx makes use of caching in many places in order to be efficient. The details about how long to keep cache for should eventually all be configurable. There may be gaps in the current behavior where -things are hardcoded but I'm happy to add more settings to cover whatever config is needed. +things are hardcoded, but I'm happy to add more settings to cover whatever config is needed. Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear to be updating, this is a good place to start. -### Plugin Cache +### Plugin/Runtime Cache -Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/plugins/`. It stores +Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/`. It stores the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), -the list of aliases, and the bin directories within each runtime installation. +the list of aliases, the bin directories within each runtime installation, and the result of +running `exec-env` after the runtime was installed. Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). @@ -1919,17 +2015,11 @@ zlib messagepack, if you want to view it you can run the following (requires [ms cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` -### Legacy File Cache - -If enabled, rtx will read the legacy filenames such as `.node-version` for -[asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs). This leverages cache in 2 places where the -plugin is called: +Note that the caching of `exec-env` may be problematic if the script isn't simply exporting +static values. The vast majority of `exec-env` scripts only export static values, but if you're +working with a plugin that has a dynamic `exec-env` submit +a ticket and we can try to figure out what to do. -- [`list-legacy-filenames`](https://github.com/asdf-vm/asdf-nodejs/blob/master/bin/list-legacy-filenames) - In every plugin I've seen this simply returns a static list of filenamed like ".nvmrc .node-version". - It's cached alongside the standard "runtime" cache which is refreshed daily by default. -- [`parse-legacy-file`](https://github.com/asdf-vm/asdf-nodejs/blob/master/bin/parse-legacy-file) - This plugin binary is called to parse a legacy file to get the version out of it. It's relatively - expensive so every file that gets parsed as a legacy file is cached into `~/.local/share/rtx/legacy_cache`. - It will remain cached until the file is modified. This is a simple text file that has the path to the - legacy file stored as a hash for the filename. +Caching `exec-env` massively improved the performance of rtx since it requires calling bash +every time rtx is initialized. Ideally, we can keep this +behavior. diff --git a/completions/_rtx b/completions/_rtx index 01a9e2dcc..1e19cf964 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -970,8 +970,8 @@ sets --jobs=1]' \ sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ -'-h[Print help]' \ -'--help[Print help]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ && ret=0 ;; (settings) @@ -1547,7 +1547,10 @@ Versions which are no longer the latest specified in any of those configs are de Versions installed only with environment variables (`RTX__VERSION`) will be deleted, as will versions only referenced on the command line (`rtx exec @`).' \ 'reshim:\[experimental\] rebuilds the shim farm' \ -'self-update:Updates rtx itself' \ +'self-update:Updates rtx itself +Uses whatever package manager was used to install rtx or just downloads +a binary from GitHub Releases if rtx was installed manually. +Supports: standalone, brew, deb, rpm' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ 'uninstall:Removes runtime versions' \ @@ -1901,7 +1904,10 @@ Versions which are no longer the latest specified in any of those configs are de Versions installed only with environment variables (`RTX__VERSION`) will be deleted, as will versions only referenced on the command line (`rtx exec @`).' \ 'reshim:\[experimental\] rebuilds the shim farm' \ -'self-update:Updates rtx itself' \ +'self-update:Updates rtx itself +Uses whatever package manager was used to install rtx or just downloads +a binary from GitHub Releases if rtx was installed manually. +Supports: standalone, brew, deb, rpm' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ 'uninstall:Removes runtime versions' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index a6c5f4105..5463e3ee0 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -34,7 +34,10 @@ Versions which are no longer the latest specified in any of those configs are de Versions installed only with environment variables (`RTX__VERSION`) will be deleted, as will versions only referenced on the command line (`rtx exec @`).' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself +Uses whatever package manager was used to install rtx or just downloads +a binary from GitHub Releases if rtx was installed manually. +Supports: standalone, brew, deb, rpm' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' @@ -395,7 +398,7 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Se complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r @@ -514,7 +517,10 @@ Versions which are no longer the latest specified in any of those configs are de Versions installed only with environment variables (`RTX__VERSION`) will be deleted, as will versions only referenced on the command line (`rtx exec @`).' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself +Uses whatever package manager was used to install rtx or just downloads +a binary from GitHub Releases if rtx was installed manually. +Supports: standalone, brew, deb, rpm' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 9cff21a29..eae32eed8 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -103,6 +103,9 @@ rtx\-reshim(1) .TP rtx\-self\-update(1) Updates rtx itself +Uses whatever package manager was used to install rtx or just downloads +a binary from GitHub Releases if rtx was installed manually. +Supports: standalone, brew, deb, rpm .TP rtx\-settings(1) Manage settings diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 4e85d9191..2c4a8ca66 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euxo pipefail -just render-mangen +just render-mangen render-help ./scripts/update-shorthand-repo.sh just lint-fix diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index e935eea39..d56a5cc2c 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use color_eyre::eyre::{Context, Result}; use duct::Expression; use serde_derive::Deserialize; @@ -35,7 +35,9 @@ impl Command for DirenvExec { cmd = cmd.env(k, v); } - let json = cmd!("direnv", "watch", "json", ".tool-versions").read()?; + let json = cmd!("direnv", "watch", "json", ".tool-versions") + .read() + .with_context(|| "error running direnv watch")?; let w: DirenvWatches = serde_json::from_str(&json)?; cmd = cmd.env("DIRENV_WATCHES", w.watches); diff --git a/src/cli/global.rs b/src/cli/global.rs index 4f645329d..b7aa4ebad 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -16,8 +16,8 @@ use crate::{dirs, env}; /// Shows/sets the global runtime version(s) /// /// Displays the contents of ~/.tool-versions after writing. -/// The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_GLOBAL_FILE`. -/// If `$RTX_GLOBAL_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. +/// The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. +/// If `$RTX_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. /// Otherwise, it will be parsed as a `.tool-versions` file. /// A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. /// @@ -68,7 +68,7 @@ impl Command for Global { } fn global_file() -> PathBuf { - env::RTX_GLOBAL_FILE.clone().unwrap_or_else(|| { + env::RTX_CONFIG_FILE.clone().unwrap_or_else(|| { if *env::RTX_USE_TOML { dirs::CONFIG.join("config.toml") } else { diff --git a/src/cli/self_update/github.rs b/src/cli/self_update/github.rs index 3abcfd527..1f3c845de 100644 --- a/src/cli/self_update/github.rs +++ b/src/cli/self_update/github.rs @@ -1,17 +1,22 @@ use color_eyre::Result; use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; use self_update::backends::github::Update; use self_update::cargo_crate_version; use crate::cli::command::Command; -use crate::cli::version::{ARCH, OS}; +use crate::cli::version::{ARCH, OS, VERSION}; use crate::config::Config; use crate::env; use crate::output::Output; /// Updates rtx itself +/// Uses whatever package manager was used to install rtx or just downloads +/// a binary from GitHub Releases if rtx was installed manually. +/// Supports: standalone, brew, deb, rpm #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct SelfUpdate {} impl Command for SelfUpdate { @@ -41,3 +46,26 @@ impl Command for SelfUpdate { Ok(()) } } + +pub static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx self-update + Checking target-arch... macos-arm64 + Checking current version... v1.0.0 + Checking latest released version... v{version} + New release found! v1.0.0 --> v{version} + New release is compatible + + rtx release status: + * Current exe: "/Users/jdx/bin/rtx" + * New exe release: "rtx-v{version}-macos-arm64" + + The new release will be downloaded/extracted and the existing binary will be replaced. + Do you want to continue? [Y/n] y + Downloading... + Extracting archive... Done + Replacing binary file... Done + Updated rtx to {version} + "#, style("Examples:").bold().underlined(), version=*VERSION} +}); diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs index 75dff6f9e..610a27109 100644 --- a/src/cli/self_update/other.rs +++ b/src/cli/self_update/other.rs @@ -1,6 +1,8 @@ +use crate::cli::version::VERSION; use color_eyre::eyre::eyre; use color_eyre::Result; use console::style; +use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -8,8 +10,11 @@ use crate::output::Output; use crate::{cmd, env}; /// Updates rtx itself +/// Uses whatever package manager was used to install rtx or just downloads +/// a binary from GitHub Releases if rtx was installed manually. +/// Supports: standalone, brew, deb, rpm #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] pub struct SelfUpdate {} impl Command for SelfUpdate { @@ -30,11 +35,35 @@ impl Command for SelfUpdate { } } +pub static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + indoc::formatdoc! {r#" + {} + $ rtx self-update + Checking target-arch... macos-arm64 + Checking current version... v1.0.0 + Checking latest released version... v{version} + New release found! v1.0.0 --> v{version} + New release is compatible + + rtx release status: + * Current exe: "/Users/jdx/bin/rtx" + * New exe release: "rtx-v{version}-macos-arm64" + + The new release will be downloaded/extracted and the existing binary will be replaced. + Do you want to continue? [Y/n] y + Downloading... + Extracting archive... Done + Replacing binary file... Done + Updated rtx to {version} + "#, style("Examples:").bold().underlined(), version=*VERSION} +}); + #[cfg(test)] mod tests { - use crate::assert_cli_err; use insta::assert_display_snapshot; + use crate::assert_cli_err; + use super::*; #[test] diff --git a/src/config/mod.rs b/src/config/mod.rs index 1d0c3bba8..cf80aef1d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -265,7 +265,7 @@ fn load_config_filenames(legacy_filenames: &IndexMap) -> Vec let mut config_files = file::FindUp::new(&dirs::CURRENT, &filenames).collect::>(); - match env::RTX_GLOBAL_FILE.clone() { + match env::RTX_CONFIG_FILE.clone() { Some(global) => { if global.is_file() { config_files.push(global); diff --git a/src/env.rs b/src/env.rs index ca44c0387..ee9c9dfdf 100644 --- a/src/env.rs +++ b/src/env.rs @@ -22,7 +22,7 @@ lazy_static! { pub static ref RTX_DATA_DIR: PathBuf = var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx")); pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String =var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()); pub static ref RTX_DEFAULT_CONFIG_FILENAME: String =var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into()); - pub static ref RTX_GLOBAL_FILE: Option = var_path("RTX_GLOBAL_FILE"); + pub static ref RTX_CONFIG_FILE: Option = var_path("RTX_CONFIG_FILE"); pub static ref RTX_USE_TOML: bool = var_is_true("RTX_USE_TOML"); pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); @@ -61,6 +61,7 @@ lazy_static! { pub static ref RTX_VERBOSE: bool = *RTX_DEBUG || *RTX_TRACE || var_is_true("RTX_VERBOSE"); pub static ref DUMB_TERMINAL: bool = cfg!(test) || var("TERM").map_or(false, |term| term == "dumb"); pub static ref RTX_JOBS: usize = var("RTX_JOBS").ok().and_then(|v| v.parse::().ok()).unwrap_or(4); + pub static ref PREFER_STALE: bool = prefer_stale(&ARGS); /// essentially, this is whether we show spinners or build output on runtime install pub static ref PRISTINE_ENV: HashMap = get_pristine_env(&__RTX_DIFF, vars().collect()); @@ -72,7 +73,6 @@ lazy_static! { pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); pub static ref RTX_EXPERIMENTAL: bool = var_is_true("RTX_EXPERIMENTAL"); pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); - pub static ref RTX_PREFER_STALE: bool = prefer_stale(&ARGS); pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); pub static ref RTX_SHORTHANDS_FILE: Option = var_path("RTX_SHORTHANDS_FILE"); pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 91a649d88..532de4dfd 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -16,7 +16,7 @@ pub use script_manager::{Script, ScriptManager}; use crate::cache::CacheManager; use crate::cmd::cmd; use crate::config::{Config, Settings}; -use crate::env::RTX_PREFER_STALE; +use crate::env::PREFER_STALE; use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_dir_all}; use crate::git::Git; @@ -49,7 +49,7 @@ impl Plugin { pub fn new(name: &PluginName) -> Self { let plugin_path = dirs::PLUGINS.join(name); let cache_path = dirs::CACHE.join(name); - let fresh_duration = if *RTX_PREFER_STALE { + let fresh_duration = if *PREFER_STALE { None } else { Some(Duration::from_secs(60 * 60 * 24)) From e3a79dad0c22527816b81ab25ec94e09198bb88f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 3 Mar 2023 23:33:44 -0600 Subject: [PATCH 0384/1891] chore: Release rtx-cli version 1.21.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 243c173e0..fcf498b25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.21.0" +version = "1.21.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 95008d2d7..098d679ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.21.0" +version = "1.21.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index cd7ef93e7..f6287d5f2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.21.0 +rtx 1.21.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -323,7 +323,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.0/rtx-v1.21.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.1/rtx-v1.21.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1527,20 +1527,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.0-DEBUG macos-arm64 (built 2023-03-04) - New release found! v1.0.0 --> v1.21.0-DEBUG macos-arm64 (built 2023-03-04) + Checking latest released version... v1.21.1-DEBUG macos-arm64 (built 2023-03-04) + New release found! v1.0.0 --> v1.21.1-DEBUG macos-arm64 (built 2023-03-04) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.0-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" + * New exe release: "rtx-v1.21.1-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.0-DEBUG macos-arm64 (built 2023-03-04) + Updated rtx to 1.21.1-DEBUG macos-arm64 (built 2023-03-04) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 6d84c26b2..b058e1c8a 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.21.0"; + version = "1.21.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index eae32eed8..6d81f1683 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.21.0" +.TH rtx 1 "rtx 1.21.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -141,6 +141,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.21.0 +v1.21.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 1432c4bf6..a35d88627 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.21.0 +Version: 1.21.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 204048d13313d9e3740a7d5db6b1aece6a371734 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 00:26:14 -0600 Subject: [PATCH 0385/1891] feat: `rtx plugin update` git ref support Fixes #164 --- .github/workflows/test-plugins.yml | 2 +- README.md | 12 ++++++++---- codecov.yml | 1 + src/cli/plugins/install.rs | 11 +++++++++-- src/cli/plugins/update.rs | 31 ++++++++++++++++++------------ src/plugins/mod.rs | 6 ++++++ 6 files changed, 44 insertions(+), 19 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 82b9f268e..3039eedc2 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -87,7 +87,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Install zsh/fish/direnv - run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c + run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl-dev - uses: actions/download-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu diff --git a/README.md b/README.md index f6287d5f2..0eb436d17 100644 --- a/README.md +++ b/README.md @@ -1385,11 +1385,14 @@ Examples: $ rtx install nodejs # install the nodejs plugin using a specific git url - $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git + $ rtx install nodejs https://github.com/jdxcode/rtx-nodejs.git # install the nodejs plugin using the git url only # (nodejs is inferred from the url) - $ rtx install https://github.com/asdf-vm/asdf-nodejs.git + $ rtx install https://github.com/jdxcode/rtx-nodejs.git + + # install the nodejs plugin using a specific ref + $ rtx install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 ``` ### `rtx plugins ls` @@ -1470,8 +1473,9 @@ Options: Update all plugins Examples: - $ rtx plugins update --all # update all plugins - $ rtx plugins update nodejs # update only nodejs + $ rtx plugins update --all # update all plugins + $ rtx plugins update nodejs # update only nodejs + $ rtx plugins update nodejs@beta # specify a ref ``` ### `rtx prune` diff --git a/codecov.yml b/codecov.yml index d08101fc8..7da675ceb 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,4 +2,5 @@ coverage: status: project: default: + target: 80% informational: true diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 0584e82c5..7dd39f906 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -115,7 +115,11 @@ impl PluginsInstall { mpr: &MultiProgressReport, ) -> Result<()> { let mut plugin = Plugin::new(name); + let (git_url, ref_) = git_url + .split_once('#') + .map_or((git_url, None), |(a, b)| (a, Some(b))); plugin.repo_url = Some(git_url.to_string()); + plugin.repo_ref = ref_.map(|s| s.to_string()); if !self.force && plugin.is_installed() { mpr.warn(format!("plugin {} already installed", name)); } else { @@ -167,11 +171,14 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ rtx install nodejs # install the nodejs plugin using a specific git url - $ rtx install nodejs https://github.com/asdf-vm/asdf-nodejs.git + $ rtx install nodejs https://github.com/jdxcode/rtx-nodejs.git # install the nodejs plugin using the git url only # (nodejs is inferred from the url) - $ rtx install https://github.com/asdf-vm/asdf-nodejs.git + $ rtx install https://github.com/jdxcode/rtx-nodejs.git + + # install the nodejs plugin using a specific ref + $ rtx install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 25673c032..65d2f892e 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; @@ -8,7 +6,6 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; /// Updates a plugin to the latest version /// @@ -27,22 +24,31 @@ pub struct Update { impl Command for Update { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugins: Vec<&Arc> = match (self.plugin, self.all) { + let plugins: Vec<_> = match (self.plugin, self.all) { (Some(plugins), _) => plugins .into_iter() .map(|p| { - config.plugins.get(&p).ok_or_else(|| { - eyre!("plugin {} not found", style(p.as_str()).cyan().for_stderr()) - }) + let (p, ref_) = match p.split_once('@') { + Some((p, ref_)) => (p, Some(ref_.to_string())), + None => (p.as_str(), None), + }; + let plugin = config.plugins.get(p).ok_or_else(|| { + eyre!("plugin {} not found", style(p).cyan().for_stderr()) + })?; + Ok((plugin, ref_)) }) .collect::>()?, - (_, true) => config.plugins.values().collect(), + (_, true) => config + .plugins + .values() + .map(|p| (p, None)) + .collect::>(), _ => Err(eyre!("no plugins specified"))?, }; - for plugin in plugins { + for (plugin, ref_) in plugins { rtxprintln!(out, "updating plugin {}", plugin.name); - plugin.update(None)?; + plugin.update(ref_)?; } Ok(()) } @@ -51,8 +57,9 @@ impl Command for Update { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx plugins update --all # update all plugins - $ rtx plugins update nodejs # update only nodejs + $ rtx plugins update --all # update all plugins + $ rtx plugins update nodejs # update only nodejs + $ rtx plugins update nodejs@beta # specify a ref "#, style("Examples:").bold().underlined()} }); diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 532de4dfd..347f1c1c0 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -36,6 +36,7 @@ pub struct Plugin { pub name: PluginName, pub plugin_path: PathBuf, pub repo_url: Option, + pub repo_ref: Option, cache_path: PathBuf, downloads_path: PathBuf, installs_path: PathBuf, @@ -72,6 +73,7 @@ impl Plugin { plugin_path, cache_path, repo_url: None, + repo_ref: None, } } @@ -109,6 +111,10 @@ impl Plugin { let git = Git::new(self.plugin_path.to_path_buf()); pr.set_message(format!("cloning {repository}")); git.clone(repository)?; + if let Some(ref_) = &self.repo_ref { + pr.set_message(format!("checking out {ref_}")); + git.update(Some(ref_.to_string()))?; + } pr.set_message("loading plugin remote versions".into()); if self.has_list_all_script() { From a167c39f3fd364f54ea320d83d70bb5c08257fd3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 00:43:35 -0600 Subject: [PATCH 0386/1891] chore: Release rtx-cli version 1.21.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcf498b25..053f64565 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.21.1" +version = "1.21.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 098d679ce..30f989131 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.21.1" +version = "1.21.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0eb436d17..c1726b083 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.21.1 +rtx 1.21.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -323,7 +323,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.1/rtx-v1.21.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.2/rtx-v1.21.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1531,20 +1531,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.1-DEBUG macos-arm64 (built 2023-03-04) - New release found! v1.0.0 --> v1.21.1-DEBUG macos-arm64 (built 2023-03-04) + Checking latest released version... v1.21.2-DEBUG macos-arm64 (built 2023-03-04) + New release found! v1.0.0 --> v1.21.2-DEBUG macos-arm64 (built 2023-03-04) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.1-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" + * New exe release: "rtx-v1.21.2-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.1-DEBUG macos-arm64 (built 2023-03-04) + Updated rtx to 1.21.2-DEBUG macos-arm64 (built 2023-03-04) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index b058e1c8a..94f6d6c3f 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.21.1"; + version = "1.21.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 6d81f1683..d36e1bf59 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.21.1" +.TH rtx 1 "rtx 1.21.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -141,6 +141,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.21.1 +v1.21.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a35d88627..8c889aa36 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.21.1 +Version: 1.21.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 63deb4f830aaacdec0180ad232795026c64d2c81 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 01:19:51 -0600 Subject: [PATCH 0387/1891] chore: remove unused test dependency --- Cargo.lock | 1 - Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 053f64565..5ff9e5615 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1436,7 +1436,6 @@ dependencies = [ "serde_json", "shell-escape", "simplelog", - "tempfile", "term_size", "test-log", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 30f989131..6eec03421 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,6 @@ exec = "0.3.1" env_logger = "0.10.0" insta = "1.26.0" pretty_assertions = "1.3.0" -tempfile = "3.3.0" test-log = "0.2" [features] From 451a04f0904f821324c50ba1f68ab1c94d89bef8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 01:04:41 -0600 Subject: [PATCH 0388/1891] chore: fix php --- .github/workflows/test-plugins.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 3039eedc2..4fd2f689c 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -33,9 +33,9 @@ jobs: test-install-and-run: runs-on: ubuntu-22.04 needs: [build-linux] - continue-on-error: true env: RTX_MISSING_RUNTIME_BEHAVIOR: autoinstall + GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} strategy: matrix: include: @@ -71,7 +71,7 @@ jobs: - plugin: kubectl command: rtx exec kubectl@latest -- kubectl version --client - plugin: dotnet - command: rtx exec dotnet@latest-core -- dotnet --list-sdks + command: rtx exec dotnet@latest -- dotnet --list-sdks - plugin: flutter command: rtx exec flutter@latest -- flutter --version - plugin: crystal @@ -85,16 +85,15 @@ jobs: - plugin: postgres command: rtx exec postgres@latest -- psql -V steps: - - uses: actions/checkout@v3 - - name: Install zsh/fish/direnv - run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl-dev + - name: apt-get + run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl4-openssl-dev libgd-dev libonig-dev autoconf bison build-essential curl gettext git libgd-dev libcurl4-openssl-dev libedit-dev libicu-dev libjpeg-dev libmysqlclient-dev libonig-dev libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libxml2-dev libzip-dev openssl pkg-config re2c zlib1g-dev - uses: actions/download-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu path: dist # dist/rtx-v1.16.0-linux-x64.tar.xz # x86_64-unknown-linux-gnu-v1.16.0-linux-x64.tar.xz - - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz + - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH - run: rtx -v - run: ${{matrix.command}} @@ -104,7 +103,8 @@ jobs: # and behaves as expected with rtx. runs-on: ubuntu-22.04 needs: [build-linux] - continue-on-error: true + env: + GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} strategy: matrix: plugins: @@ -158,13 +158,12 @@ jobs: - graalvm - sbcl steps: - - uses: actions/checkout@v3 - name: Install zsh/fish/direnv run: sudo apt-get update; sudo apt-get install zsh fish direnv - uses: actions/download-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu path: dist - - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz + - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH - run: rtx install ${{matrix.plugins}}@latest From 235be325761d806002eb40db0363157c9f9f1cdd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 08:24:17 -0600 Subject: [PATCH 0389/1891] chore: use cache directory for lockfiles --- src/lock_file.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lock_file.rs b/src/lock_file.rs index 2b62124cd..34cad9ed0 100644 --- a/src/lock_file.rs +++ b/src/lock_file.rs @@ -1,4 +1,6 @@ +use crate::dirs; use crate::file::create_dir_all; +use crate::hash::hash_to_str; use std::path::{Path, PathBuf}; pub type OnLockedFn = Box; @@ -10,8 +12,9 @@ pub struct LockFile { impl LockFile { pub fn new(path: &Path) -> Self { + let path = dirs::CACHE.join("lockfiles").join(hash_to_str(&path)); Self { - path: path.with_extension(".lock\0"), + path, on_locked: None, } } From 1a22bbbe2a41c68f2e46e6d27049044f710ffa0c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 08:29:56 -0600 Subject: [PATCH 0390/1891] chore: prevent stderr from causing an error if process exited --- src/plugins/script_manager.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 901627237..9dba4f435 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -186,7 +186,7 @@ impl ScriptManager { move || { for line in stdout.lines() { let line = line.unwrap(); - tx.send(ChildProcessOutput::Stdout(line)).unwrap(); + let _ = tx.send(ChildProcessOutput::Stdout(line)); } } }); @@ -195,13 +195,13 @@ impl ScriptManager { move || { for line in stderr.lines() { let line = line.unwrap(); - tx.send(ChildProcessOutput::Stderr(line)).unwrap(); + let _ = tx.send(ChildProcessOutput::Stderr(line)); } } }); thread::spawn(move || { let status = cp.wait().unwrap(); - tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); + let _ = tx.send(ChildProcessOutput::ExitStatus(status)); }); let mut combined_output = vec![]; for line in rx { From a5e11feb9b05d71df1d195ecde4f69a2254b5699 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 08:34:39 -0600 Subject: [PATCH 0391/1891] chore: Release rtx-cli version 1.21.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ff9e5615..3b29a1553 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.21.2" +version = "1.21.3" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 6eec03421..9d158e398 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.21.2" +version = "1.21.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index c1726b083..8c41b9c49 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.21.2 +rtx 1.21.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -323,7 +323,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.2/rtx-v1.21.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.3/rtx-v1.21.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1531,20 +1531,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.2-DEBUG macos-arm64 (built 2023-03-04) - New release found! v1.0.0 --> v1.21.2-DEBUG macos-arm64 (built 2023-03-04) + Checking latest released version... v1.21.3-DEBUG macos-arm64 (built 2023-03-04) + New release found! v1.0.0 --> v1.21.3-DEBUG macos-arm64 (built 2023-03-04) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.2-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" + * New exe release: "rtx-v1.21.3-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.2-DEBUG macos-arm64 (built 2023-03-04) + Updated rtx to 1.21.3-DEBUG macos-arm64 (built 2023-03-04) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 94f6d6c3f..a13236fb4 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.21.2"; + version = "1.21.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index d36e1bf59..d8c22bce9 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.21.2" +.TH rtx 1 "rtx 1.21.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -141,6 +141,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.21.2 +v1.21.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 8c889aa36..5a2388bb4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.21.2 +Version: 1.21.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 7191e1d26c090ae8f6de50db5f7ed301584662e6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 08:47:54 -0600 Subject: [PATCH 0392/1891] bug: ensure all output is sent back from script --- src/plugins/script_manager.rs | 42 +++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 9dba4f435..2c14a2cbf 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -181,29 +181,31 @@ impl ScriptManager { let stdout = BufReader::new(cp.stdout.take().unwrap()); let stderr = BufReader::new(cp.stderr.take().unwrap()); let (tx, rx) = channel(); - thread::spawn({ + let mut threads = vec![]; + threads.push(thread::spawn({ let tx = tx.clone(); move || { for line in stdout.lines() { let line = line.unwrap(); - let _ = tx.send(ChildProcessOutput::Stdout(line)); + tx.send(ChildProcessOutput::Stdout(line)).unwrap(); } } - }); - thread::spawn({ + })); + threads.push(thread::spawn({ let tx = tx.clone(); move || { for line in stderr.lines() { let line = line.unwrap(); - let _ = tx.send(ChildProcessOutput::Stderr(line)); + tx.send(ChildProcessOutput::Stderr(line)).unwrap(); } } - }); + })); thread::spawn(move || { let status = cp.wait().unwrap(); - let _ = tx.send(ChildProcessOutput::ExitStatus(status)); + tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); }); let mut combined_output = vec![]; + let mut status = None; for line in rx { match line { ChildProcessOutput::Stdout(line) => { @@ -214,16 +216,22 @@ impl ScriptManager { on_stderr(&line); combined_output.push(line); } - ChildProcessOutput::ExitStatus(status) => match status.success() { - true => return Ok(()), - false => { - on_error(combined_output.join("\n")); - Err(ScriptFailed( - display_path(&self.get_script_path(script)), - Some(status), - ))?; - } - }, + ChildProcessOutput::ExitStatus(s) => { + status = Some(s); + } + } + if threads.iter().all(|t| t.is_finished()) { + break; + } + } + match status.unwrap().success() { + true => return Ok(()), + false => { + on_error(combined_output.join("\n")); + Err(ScriptFailed( + display_path(&self.get_script_path(script)), + status, + ))?; } } From 97a563700a47439ea3e647f807f05bc1e6332be3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 08:48:57 -0600 Subject: [PATCH 0393/1891] chore: Release rtx-cli version 1.21.4 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b29a1553..fae4198a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.21.3" +version = "1.21.4" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 9d158e398..cf8704e9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.21.3" +version = "1.21.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 8c41b9c49..ade158d38 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.21.3 +rtx 1.21.4 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -323,7 +323,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.3/rtx-v1.21.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.4/rtx-v1.21.4-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1531,20 +1531,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.3-DEBUG macos-arm64 (built 2023-03-04) - New release found! v1.0.0 --> v1.21.3-DEBUG macos-arm64 (built 2023-03-04) + Checking latest released version... v1.21.4-DEBUG macos-arm64 (built 2023-03-04) + New release found! v1.0.0 --> v1.21.4-DEBUG macos-arm64 (built 2023-03-04) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.3-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" + * New exe release: "rtx-v1.21.4-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.3-DEBUG macos-arm64 (built 2023-03-04) + Updated rtx to 1.21.4-DEBUG macos-arm64 (built 2023-03-04) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index a13236fb4..4ddec4bf6 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.21.3"; + version = "1.21.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index d8c22bce9..c5ee6b643 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.21.3" +.TH rtx 1 "rtx 1.21.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -141,6 +141,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.21.3 +v1.21.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 5a2388bb4..ce169fefa 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.21.3 +Version: 1.21.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 13359019dee3119f4e739e7e9218c360972fbb69 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 09:01:54 -0600 Subject: [PATCH 0394/1891] bug: fix issue with script threads --- src/plugins/script_manager.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 2c14a2cbf..33a5fcd07 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -200,10 +200,10 @@ impl ScriptManager { } } })); - thread::spawn(move || { + threads.push(thread::spawn(move || { let status = cp.wait().unwrap(); tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); - }); + })); let mut combined_output = vec![]; let mut status = None; for line in rx { From 4b1d3977761367eb207de9da10fa26d6a69c7310 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 09:02:27 -0600 Subject: [PATCH 0395/1891] chore: Release rtx-cli version 1.21.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fae4198a2..6fece8517 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.21.4" +version = "1.21.5" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index cf8704e9c..4136ed68b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.21.4" +version = "1.21.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index ade158d38..d4a339e3e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.21.4 +rtx 1.21.5 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -323,7 +323,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.4/rtx-v1.21.4-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.5/rtx-v1.21.5-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1531,20 +1531,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.4-DEBUG macos-arm64 (built 2023-03-04) - New release found! v1.0.0 --> v1.21.4-DEBUG macos-arm64 (built 2023-03-04) + Checking latest released version... v1.21.5-DEBUG macos-arm64 (built 2023-03-04) + New release found! v1.0.0 --> v1.21.5-DEBUG macos-arm64 (built 2023-03-04) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.4-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" + * New exe release: "rtx-v1.21.5-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.4-DEBUG macos-arm64 (built 2023-03-04) + Updated rtx to 1.21.5-DEBUG macos-arm64 (built 2023-03-04) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 4ddec4bf6..8dc0a9998 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.21.4"; + version = "1.21.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c5ee6b643..4a9452e7c 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.21.4" +.TH rtx 1 "rtx 1.21.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -141,6 +141,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.21.4 +v1.21.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ce169fefa..5be22f9f0 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.21.4 +Version: 1.21.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 39fb8919088c5ffd878a070275333cc6a1b564e9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 10:39:06 -0600 Subject: [PATCH 0396/1891] chore: sort e2e tests by name --- e2e/run_all_tests | 2 +- e2e/run_test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/run_all_tests b/e2e/run_all_tests index 70d3f000b..d3550df55 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -3,7 +3,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -FILES=$(find e2e -name 'test_*' -type f) +FILES=$(find e2e -name 'test_*' -type f | sort) for f in $FILES; do if [[ "$f" == "e2e/.rtx/"* ]]; then continue diff --git a/e2e/run_test b/e2e/run_test index 8a230e62c..caba72217 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -6,7 +6,7 @@ ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)" export ROOT export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="$ROOT/e2e/.rtx" -export RTX_CACHE_DIR="$ROOT/e2e/.cache" +export RTX_CACHE_DIR="$ROOT/e2e/.rtx/cache" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml unset GOPATH From c7bddba7e87082528e3b3818c96e82a8b46ff575 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 10:41:47 -0600 Subject: [PATCH 0397/1891] bug: fix symbolic link issue with shims I started getting "Too many levels of symbolic links (os error 62)" because it was using the shim as the binary path to rtx in some cases. I am surprised this was working before actually --- src/cli/reshim.rs | 1 - src/config/mod.rs | 10 ++++++++++ src/file.rs | 24 ++++++++++++++++-------- src/shims.rs | 4 ++-- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 8498af182..c024e5e10 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -5,7 +5,6 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; - use crate::output::Output; use crate::shims; use crate::toolset::ToolsetBuilder; diff --git a/src/config/mod.rs b/src/config/mod.rs index cf80aef1d..220f4aff3 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -189,6 +189,16 @@ impl Config { .collect(); Ok(config_files) } + + pub fn rtx_bin(&self) -> Option { + for path in &*env::PATH { + let rtx_bin = path.join("rtx"); + if file::is_executable(&rtx_bin) { + return Some(rtx_bin); + } + } + None + } } fn load_rtxrc() -> Result { diff --git a/src/file.rs b/src/file.rs index 9e0c48f1a..c6a325092 100644 --- a/src/file.rs +++ b/src/file.rs @@ -5,6 +5,7 @@ use std::{fs, io}; use color_eyre::eyre::Result; use filetime::{set_file_times, FileTime}; use std::os::unix::fs::symlink; +use std::os::unix::prelude::*; use crate::dirs; @@ -100,6 +101,21 @@ pub fn dir_files(dir: &Path) -> Result> { Ok(output) } +pub fn make_symlink(target: &Path, link: &Path) -> Result<()> { + if link.exists() { + fs::remove_file(link)?; + } + symlink(target, link)?; + Ok(()) +} + +pub fn is_executable(path: &Path) -> bool { + if let Ok(metadata) = path.metadata() { + return metadata.permissions().mode() & 0o111 != 0; + } + false +} + pub struct FindUp { current_dir: PathBuf, current_dir_filenames: Vec, @@ -185,11 +201,3 @@ mod tests { assert_eq!(display_path(&path), path.display().to_string()); } } - -pub fn make_symlink(target: &Path, link: &Path) -> Result<()> { - if link.exists() { - fs::remove_file(link)?; - } - symlink(target, link)?; - Ok(()) -} diff --git a/src/shims.rs b/src/shims.rs index 596a066ab..ed46c758b 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -11,7 +11,6 @@ use crate::cli::command::Command; use crate::cli::exec::Exec; use crate::config::Config; use crate::env; -use crate::env::RTX_EXE; use crate::fake_asdf; use crate::file::{create_dir_all, remove_dir_all}; use crate::lock_file::LockFile; @@ -77,6 +76,7 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { // remove old shims let _ = remove_dir_all(&shims_dir); create_dir_all(&shims_dir)?; + let rtx_bin = config.rtx_bin().unwrap(); for path in ts.list_paths(config) { if !path.exists() { @@ -89,7 +89,7 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { } let bin_name = bin.file_name().into_string().unwrap(); let symlink_path = shims_dir.join(bin_name); - file::make_symlink(&RTX_EXE, &symlink_path)?; + file::make_symlink(&rtx_bin, &symlink_path)?; } } for plugin in config.plugins.values() { From a321a1c18e6f6605887d17d78e6d5fbfba218b33 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 11:03:07 -0600 Subject: [PATCH 0398/1891] test: fix tests that do not have "rtx" in PATH --- src/shims.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims.rs b/src/shims.rs index ed46c758b..b1ab3d15a 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -76,7 +76,7 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { // remove old shims let _ = remove_dir_all(&shims_dir); create_dir_all(&shims_dir)?; - let rtx_bin = config.rtx_bin().unwrap(); + let rtx_bin = config.rtx_bin().unwrap_or(env::RTX_EXE.clone()); for path in ts.list_paths(config) { if !path.exists() { From 4165acd072422353291c82fe4f5c255c639cccef Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 13:39:12 -0600 Subject: [PATCH 0399/1891] docs: reference the "beginners guide" --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d4a339e3e..b3c7807b9 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,8 @@ v18.10.9 ## About +_New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction._ + rtx is a tool for managing programming language and tool versions. For example, use this to install a particular version of node.js and ruby for a project. Using `rtx activate`, you can have your shell automatically switch to the correct node and ruby versions when you `cd` into the project's From 53e4e518caacb48b858fe945e9f87c826e3db262 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 4 Mar 2023 21:35:23 -0600 Subject: [PATCH 0400/1891] docs --- README.md | 11 ++++++----- completions/_rtx | 3 ++- src/cli/where.rs | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b3c7807b9..92c39fcb1 100644 --- a/README.md +++ b/README.md @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.5-DEBUG macos-arm64 (built 2023-03-04) - New release found! v1.0.0 --> v1.21.5-DEBUG macos-arm64 (built 2023-03-04) + Checking latest released version... v1.21.5-DEBUG macos-arm64 (built 2023-03-05) + New release found! v1.0.0 --> v1.21.5-DEBUG macos-arm64 (built 2023-03-05) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.5-DEBUG macos-arm64 (built 2023-03-04)-macos-arm64" + * New exe release: "rtx-v1.21.5-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.5-DEBUG macos-arm64 (built 2023-03-04) + Updated rtx to 1.21.5-DEBUG macos-arm64 (built 2023-03-05) ``` ### `rtx settings get` @@ -1676,7 +1676,8 @@ Arguments: Runtime(s) to look up e.g.: ruby@3 - if "@" is specified, it will show the latest installed version that matches the prefix + if "@" is specified, it will show the latest installed version + that matches the prefix otherwise, it will show the current, active installed version Examples: diff --git a/completions/_rtx b/completions/_rtx index 1e19cf964..0903526ce 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1183,7 +1183,8 @@ sets --jobs=1]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':runtime -- Runtime(s) to look up e.g.\: ruby@3 -if "@" is specified, it will show the latest installed version that matches the prefix +if "@" is specified, it will show the latest installed version +that matches the prefix otherwise, it will show the current, active installed version:' \ '::asdf_version -- the version prefix to use when querying the latest version same as the first argument after the "@" diff --git a/src/cli/where.rs b/src/cli/where.rs index a46f5475b..892986258 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -18,7 +18,8 @@ use crate::toolset::ToolsetBuilder; pub struct Where { /// Runtime(s) to look up /// e.g.: ruby@3 - /// if "@" is specified, it will show the latest installed version that matches the prefix + /// if "@" is specified, it will show the latest installed version + /// that matches the prefix /// otherwise, it will show the current, active installed version #[clap(required = true, value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: RuntimeArg, From 42c498685bcae42c1efaae2d5ea4944f680321cb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 14:37:23 -0600 Subject: [PATCH 0401/1891] use "#" as separator for git ref this is the expected input for plugin-update --- src/plugins/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 347f1c1c0..d2b63d3b7 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -131,7 +131,7 @@ impl Plugin { let sha = git.current_sha_short()?; pr.finish_with_message(format!( - "{repository}@{}", + "{repository}#{}", style(&sha).bright().yellow().for_stderr(), )); Ok(()) From 3f3c3b2003350cdf8bba51f5e40a52e66a0f177a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 14:42:10 -0600 Subject: [PATCH 0402/1891] added RTX_* env vars for plugin interface (#262) --- .bin/rtx | 2 +- .rtx.toml | 1 + src/runtimes.rs | 19 ++++++++++++++++--- src/toolset/mod.rs | 2 ++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.bin/rtx b/.bin/rtx index 30bd6a146..e87624ee8 100755 --- a/.bin/rtx +++ b/.bin/rtx @@ -1,5 +1,5 @@ #!/bin/bash set -e -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +SCRIPT_DIR="$( cd "$( dirname "$(readlink -f "${BASH_SOURCE[0]}")")" >/dev/null 2>&1 && pwd )" cargo run -q --all-features --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" diff --git a/.rtx.toml b/.rtx.toml index 374fd641b..2666eca06 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -5,6 +5,7 @@ FOO = "bar" nodejs = '18' tiny = {version="1", foo="bar"} golang = {version="latest", foo="bar"} +python = {version="latest", virtualenv="$HOME/.cache/venv"} [plugins] nodejs = 'https://github.com/jdxcode/rtx-nodejs' diff --git a/src/runtimes.rs b/src/runtimes.rs index 3f9490391..f55a26464 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -318,22 +318,35 @@ fn build_script_man( "ASDF_INSTALL_PATH".into(), install_path.to_string_lossy().to_string(), ) + .with_env( + "RTX_INSTALL_PATH".into(), + install_path.to_string_lossy().to_string(), + ) .with_env( "ASDF_DOWNLOAD_PATH".into(), download_path.to_string_lossy().to_string(), ) + .with_env( + "RTX_DOWNLOAD_PATH".into(), + download_path.to_string_lossy().to_string(), + ) + .with_env("RTX_CONCURRENCY".into(), num_cpus::get().to_string()) .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()); for (key, value) in tv.options.iter() { - let k = format!("RTX_TOOL_OPT__{}", key.to_uppercase()); + let k = format!("RTX_TOOL_OPTS__{}", key.to_uppercase()); sm = sm.with_env(k, value.clone()); } match &tv.r#type { ToolVersionType::Version(_) | ToolVersionType::Prefix(_) => sm .with_env("ASDF_INSTALL_TYPE".into(), "version".into()) - .with_env("ASDF_INSTALL_VERSION".into(), version.to_string()), + .with_env("RTX_INSTALL_TYPE".into(), "version".into()) + .with_env("ASDF_INSTALL_VERSION".into(), version.to_string()) + .with_env("RTX_INSTALL_VERSION".into(), version.to_string()), ToolVersionType::Ref(r) => sm .with_env("ASDF_INSTALL_TYPE".into(), "ref".into()) - .with_env("ASDF_INSTALL_VERSION".into(), r.to_string()), + .with_env("RTX_INSTALL_TYPE".into(), "ref".into()) + .with_env("ASDF_INSTALL_VERSION".into(), r.to_string()) + .with_env("RTX_INSTALL_VERSION".into(), r.to_string()), _ => sm, } } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 3d7c08444..3420143e1 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -264,6 +264,8 @@ impl Toolset { }) .collect::>() .into_iter() + .filter(|(k, _)| k != "RTX_ADD_PATH") + .filter(|(k, _)| !k.starts_with("RTX_TOOL_OPTS__")) .rev() .collect(); entries.sort_keys(); From 7fffaf8dc08f0a3ab96d56f7bed4613ba6a74af6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 14:43:06 -0600 Subject: [PATCH 0403/1891] chore: Release rtx-cli version 1.21.6 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fece8517..38d360fa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.21.5" +version = "1.21.6" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 4136ed68b..293e436bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.21.5" +version = "1.21.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 92c39fcb1..3d66f8673 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.21.5 +rtx 1.21.6 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.5/rtx-v1.21.5-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.6/rtx-v1.21.6-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.5-DEBUG macos-arm64 (built 2023-03-05) - New release found! v1.0.0 --> v1.21.5-DEBUG macos-arm64 (built 2023-03-05) + Checking latest released version... v1.21.6-DEBUG macos-arm64 (built 2023-03-05) + New release found! v1.0.0 --> v1.21.6-DEBUG macos-arm64 (built 2023-03-05) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.5-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" + * New exe release: "rtx-v1.21.6-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.5-DEBUG macos-arm64 (built 2023-03-05) + Updated rtx to 1.21.6-DEBUG macos-arm64 (built 2023-03-05) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 8dc0a9998..66e1a149c 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.21.5"; + version = "1.21.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 4a9452e7c..dfa43b5c0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.21.5" +.TH rtx 1 "rtx 1.21.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -141,6 +141,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.21.5 +v1.21.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 5be22f9f0..0d0582a35 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.21.5 +Version: 1.21.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 5c1ca919910392092415f7da279c14e066e2bda0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 15:36:29 -0600 Subject: [PATCH 0404/1891] added --install-missing flag (#263) * added --install-missing flag Fixes #188 * bug: handle no status being returned from script --- completions/_rtx | 50 ++++++++++++++++ completions/rtx.bash | 100 ++++++++++++++++---------------- completions/rtx.fish | 50 ++++++++++++++++ e2e/.e2e.rtx.toml | 3 +- e2e/cd/test_bash | 6 +- e2e/test_local | 14 ++--- e2e/test_lua | 2 +- man/man1/rtx.1 | 5 +- src/cli/args/install_missing.rs | 13 +++++ src/cli/args/mod.rs | 1 + src/cli/mod.rs | 5 ++ src/plugins/script_manager.rs | 23 +++++--- 12 files changed, 197 insertions(+), 75 deletions(-) create mode 100644 src/cli/args/install_missing.rs diff --git a/completions/_rtx b/completions/_rtx index 0903526ce..000d77f73 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -20,6 +20,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -51,6 +52,7 @@ default: 4]: : ' \ '--status[Show "rtx: @" message when changing directories]' \ '-q[noop]' \ '--quiet[noop]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -71,6 +73,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -96,6 +99,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -117,6 +121,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -134,6 +139,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -154,6 +160,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -213,6 +220,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -231,6 +239,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -248,6 +257,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -273,6 +283,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -320,6 +331,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -337,6 +349,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -355,6 +368,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -372,6 +386,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -397,6 +412,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -414,6 +430,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -431,6 +448,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -484,6 +502,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -503,6 +522,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -523,6 +543,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -548,6 +569,7 @@ e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions] e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -572,6 +594,7 @@ default: 4]: : ' \ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx: @" message when changing directories]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -591,6 +614,7 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--config[Also remove config directory]' \ '--dry-run[List directories that would be removed without actually removing them]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -616,6 +640,7 @@ default: 4]: : ' \ '(-p --plugin -f --force)--all[Install all missing runtimes as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -632,6 +657,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -660,6 +686,7 @@ by default this command will only set the runtime in the current directory ("$PW e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions]' \ '--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the config file]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -685,6 +712,7 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -703,6 +731,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -723,6 +752,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -744,6 +774,7 @@ default: 4]: : ' \ '--all[list all available remote plugins]' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -779,6 +810,7 @@ This will only install plugins that have matching shorthands. i.e.: they don'\''t need the full git repo url]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -807,6 +839,7 @@ Same as `rtx plugins ls-remote`]' \ e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -827,6 +860,7 @@ default: 4]: : ' \ '-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -844,6 +878,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -864,6 +899,7 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '()-a[Update all plugins]' \ '()--all[Update all plugins]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -927,6 +963,7 @@ default: 4]: : ' \ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--dry-run[Do not actually delete anything]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -945,6 +982,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -964,6 +1002,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -981,6 +1020,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1006,6 +1046,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1024,6 +1065,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1041,6 +1083,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1060,6 +1103,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1120,6 +1164,7 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[Removes a previously set version]' \ '--unset[Removes a previously set version]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1138,6 +1183,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1156,6 +1202,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1173,6 +1220,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1200,6 +1248,7 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '(--version)--plugin[Show the plugin name instead of the path]' \ '(--plugin)--version[Show the version instead of the path]' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1218,6 +1267,7 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index 64c247f3d..823c08f88 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -481,7 +481,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --jobs --log-level --raw --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell uninstall version where which render-help help" + opts="-j -r -v -h -V --install-missing --jobs --log-level --raw --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -507,7 +507,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -j -r -v -h --shell --status --quiet --jobs --log-level --raw --verbose --help bash fish xonsh zsh" + opts="-s -q -j -r -v -h --shell --status --quiet --install-missing --jobs --log-level --raw --verbose --help bash fish xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -541,7 +541,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -r -v -h --plugin --jobs --log-level --raw --verbose --help get ls set unset help" + opts="-p -j -r -v -h --plugin --install-missing --jobs --log-level --raw --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -575,7 +575,7 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -685,7 +685,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -j -r -v -h --plugin --jobs --log-level --raw --verbose --help" + opts="-p -j -r -v -h --plugin --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -719,7 +719,7 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -745,7 +745,7 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -771,7 +771,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help [ARGS]..." + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -797,7 +797,7 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -823,7 +823,7 @@ _rtx() { return 0 ;; rtx__cache) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help clear help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -849,7 +849,7 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -917,7 +917,7 @@ _rtx() { return 0 ;; rtx__complete) - opts="-s -j -r -v -h --shell --jobs --log-level --raw --verbose --help" + opts="-s -j -r -v -h --shell --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -951,7 +951,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help [PLUGIN]" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -977,7 +977,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1003,7 +1003,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help envrc exec activate help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1029,7 +1029,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1055,7 +1055,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1081,7 +1081,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1177,7 +1177,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1203,7 +1203,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -r -v -h --shell --jobs --log-level --raw --verbose --help [RUNTIME]..." + opts="-s -j -r -v -h --shell --install-missing --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1237,7 +1237,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -v -h --command --jobs --log-level --raw --verbose --help [RUNTIME]... [COMMAND]..." + opts="-c -j -r -v -h --command --install-missing --jobs --log-level --raw --verbose --help [RUNTIME]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1271,7 +1271,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -v -h --pin --fuzzy --remove --path --jobs --log-level --raw --verbose --help [RUNTIME]..." + opts="-j -r -v -h --pin --fuzzy --remove --path --install-missing --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2015,7 +2015,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -r -v -h --shell --status --jobs --log-level --raw --verbose --help" + opts="-s -j -r -v -h --shell --status --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2049,7 +2049,7 @@ _rtx() { return 0 ;; rtx__implode) - opts="-j -r -v -h --config --dry-run --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --config --dry-run --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2075,7 +2075,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-p -f -a -v -j -r -h --plugin --force --all --verbose --jobs --log-level --raw --help [RUNTIME]..." + opts="-p -f -a -v -j -r -h --plugin --force --all --verbose --install-missing --jobs --log-level --raw --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2109,7 +2109,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2135,7 +2135,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --jobs --log-level --raw --verbose --help [RUNTIME]..." + opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --install-missing --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2165,7 +2165,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -j -r -v -h --plugin --current --jobs --log-level --raw --verbose --help [PLUGIN_ARG]" + opts="-p -c -j -r -v -h --plugin --current --install-missing --jobs --log-level --raw --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2199,7 +2199,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help [PREFIX]" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2225,7 +2225,7 @@ _rtx() { return 0 ;; rtx__mangen) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2251,7 +2251,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -u -j -r -v -h --all --urls --jobs --log-level --raw --verbose --help install ls ls-remote uninstall update help" + opts="-a -u -j -r -v -h --all --urls --install-missing --jobs --log-level --raw --verbose --help install ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2375,7 +2375,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -r -h --force --all --verbose --jobs --log-level --raw --help [NAME] [GIT_URL] [REST]..." + opts="-f -a -v -j -r -h --force --all --verbose --install-missing --jobs --log-level --raw --help [NAME] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2401,7 +2401,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -u -j -r -v -h --all --urls --jobs --log-level --raw --verbose --help" + opts="-a -u -j -r -v -h --all --urls --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2427,7 +2427,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -r -v -h --urls --only-names --jobs --log-level --raw --verbose --help" + opts="-u -j -r -v -h --urls --only-names --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2453,7 +2453,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help ..." + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2479,7 +2479,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -j -r -v -h --all --jobs --log-level --raw --verbose --help [PLUGIN]..." + opts="-a -j -r -v -h --all --install-missing --jobs --log-level --raw --verbose --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2505,7 +2505,7 @@ _rtx() { return 0 ;; rtx__prune) - opts="-j -r -v -h --dry-run --jobs --log-level --raw --verbose --help [PLUGINS]..." + opts="-j -r -v -h --dry-run --install-missing --jobs --log-level --raw --verbose --help [PLUGINS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2531,7 +2531,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2557,7 +2557,7 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help [PLUGIN] [VERSION]" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2583,7 +2583,7 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2609,7 +2609,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help get ls set unset help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2635,7 +2635,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2745,7 +2745,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2771,7 +2771,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2797,7 +2797,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2823,7 +2823,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -r -v -h --unset --jobs --log-level --raw --verbose --help [RUNTIME]..." + opts="-u -j -r -v -h --unset --install-missing --jobs --log-level --raw --verbose --help [RUNTIME]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2849,7 +2849,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help ..." + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2875,7 +2875,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2901,7 +2901,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -r -v -h --jobs --log-level --raw --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2927,7 +2927,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-j -r -v -h --plugin --version --jobs --log-level --raw --verbose --help " + opts="-j -r -v -h --plugin --version --install-missing --jobs --log-level --raw --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 5463e3ee0..344893b33 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,6 +1,7 @@ complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_use_subcommand" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' @@ -52,6 +53,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' +complete -c rtx -n "__fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' @@ -60,6 +62,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -74,6 +77,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' @@ -82,6 +86,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' @@ -89,6 +94,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' @@ -96,6 +102,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' @@ -110,6 +117,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' @@ -117,6 +125,7 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print hel complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' @@ -124,6 +133,7 @@ complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Prin complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -133,6 +143,7 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' @@ -143,6 +154,7 @@ complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shel complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from complete" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from complete" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' @@ -150,6 +162,7 @@ complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' @@ -157,6 +170,7 @@ complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' @@ -164,6 +178,7 @@ complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Pri complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -177,6 +192,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subc complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' @@ -184,6 +200,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' @@ -191,6 +208,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' @@ -204,6 +222,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' @@ -212,6 +231,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell typ complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' @@ -220,6 +240,7 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Comman complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' @@ -234,6 +255,7 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' +complete -c rtx -n "__fish_seen_subcommand_from global" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' @@ -243,6 +265,7 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Numbe default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' @@ -252,6 +275,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' +complete -c rtx -n "__fish_seen_subcommand_from implode" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' @@ -263,12 +287,14 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set th complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing runtimes as well as all plugins for the current directory This is hidden because it\'s now the default behavior' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' @@ -283,6 +309,7 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact ver e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' +complete -c rtx -n "__fish_seen_subcommand_from local" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' @@ -292,6 +319,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of p default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' @@ -299,6 +327,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' @@ -306,6 +335,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Prin complete -c rtx -n "__fish_seen_subcommand_from mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from mangen" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from mangen" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s v -l verbose -d 'Show installation output' @@ -315,6 +345,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -333,6 +364,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm This will only install plugins that have matching shorthands. i.e.: they don\'t need the full git repo url' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' @@ -343,6 +375,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm Same as `rtx plugins ls-remote`' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' @@ -352,6 +385,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' @@ -359,6 +393,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' @@ -367,6 +402,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' @@ -381,6 +417,7 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number o default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' +complete -c rtx -n "__fish_seen_subcommand_from prune" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from prune" -s v -l verbose -d 'Show installation output' @@ -388,6 +425,7 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print he complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from reshim" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' @@ -395,6 +433,7 @@ complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print h complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' @@ -402,6 +441,7 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Pr complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' @@ -414,6 +454,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' @@ -421,6 +462,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' @@ -428,6 +470,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' @@ -435,6 +478,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' @@ -448,6 +492,7 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number o default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' +complete -c rtx -n "__fish_seen_subcommand_from shell" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' @@ -455,6 +500,7 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print he complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' @@ -462,6 +508,7 @@ complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Prin complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' @@ -469,6 +516,7 @@ complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' @@ -478,6 +526,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' +complete -c rtx -n "__fish_seen_subcommand_from which" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' @@ -485,6 +534,7 @@ complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print he complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' diff --git a/e2e/.e2e.rtx.toml b/e2e/.e2e.rtx.toml index 1df8bf5ba..a63412114 100644 --- a/e2e/.e2e.rtx.toml +++ b/e2e/.e2e.rtx.toml @@ -2,6 +2,5 @@ FOO = "bar" [tools] -jq = "latest" -#tiny = {version="1", foo="bar"} +tiny = "latest" #golang = {version="1.19.5", foo="bar"} diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 901017cf1..88676ad91 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -20,15 +20,15 @@ assert_path() { } test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/tiny/3.1.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" cd 16 && _rtx_hook test "$(node -v)" = "v16.0.0" -assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/tiny/3.1.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/jq/1.6/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/tiny/3.1.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" rtx shell nodejs@16.0.0 && _rtx_hook test "$(node -v)" = "v16.0.0" diff --git a/e2e/test_local b/e2e/test_local index 52fd4c893..907342d49 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -24,8 +24,7 @@ assert "rtx local" "[env] FOO = \"bar\" [tools] -jq = \"latest\" -#tiny = {version=\"1\", foo=\"bar\"} +tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} " @@ -33,9 +32,8 @@ assert "rtx local shfmt@3.5.0" "[env] FOO = \"bar\" [tools] -jq = \"latest\" +tiny = \"latest\" shfmt = \"3.5.0\" -#tiny = {version=\"1\", foo=\"bar\"} #golang = {version=\"1.19.5\", foo=\"bar\"} " @@ -48,9 +46,8 @@ assert "rtx local shfmt@3.6.0" "[env] FOO = \"bar\" [tools] -jq = \"latest\" +tiny = \"latest\" shfmt = \"3.6.0\" -#tiny = {version=\"1\", foo=\"bar\"} #golang = {version=\"1.19.5\", foo=\"bar\"} " @@ -63,8 +60,7 @@ assert "rtx local --rm shfmt" "[env] FOO = \"bar\" [tools] -jq = \"latest\" -#tiny = {version=\"1\", foo=\"bar\"} +tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} " @@ -73,7 +69,7 @@ export RTX_DEFAULT_CONFIG_FILENAME=.MISSING assert_raises "rtx uninstall shfmt@3.6.0" -assert "rtx local" "#python 3.11.1 3.10.9 # foo +assert "rtx local --install-missing" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 diff --git a/e2e/test_lua b/e2e/test_lua index b2d53997f..a06c3584f 100755 --- a/e2e/test_lua +++ b/e2e/test_lua @@ -8,7 +8,7 @@ rtx activate --status fish | source rtx shell lua@5.4.3 set -l actual (__rtx_env_eval 2>&1 && lua -v 2>&1) -set -l expected "rtx lua@5.4.3 shellcheck@0.9.0 shfmt@3.6.0 jq@1.6 nodejs@18.0.0 Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio" +set -l expected "rtx lua@5.4.3 shellcheck@0.9.0 shfmt@3.6.0 nodejs@18.0.0 Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio" if test "$actual" = "$expected" echo "OK" diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index dfa43b5c0..6d8ba5690 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -4,7 +4,7 @@ .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS -\fBrtx\fR [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> +\fBrtx\fR [\fB\-\-install\-missing\fR] [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> .SH DESCRIPTION rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx .PP @@ -16,6 +16,9 @@ It is inspired by asdf and uses asdf\*(Aqs plugin ecosystem under the hood: https://asdf\-vm.com/ .SH OPTIONS .TP +\fB\-\-install\-missing\fR +Automatically install missing tools +.TP \fB\-j\fR, \fB\-\-jobs\fR Number of plugins and runtimes to install in parallel default: 4 diff --git a/src/cli/args/install_missing.rs b/src/cli/args/install_missing.rs new file mode 100644 index 000000000..9373fa67f --- /dev/null +++ b/src/cli/args/install_missing.rs @@ -0,0 +1,13 @@ +use clap::{Arg, ArgAction}; + +pub struct InstallMissing(pub bool); + +impl InstallMissing { + pub fn arg() -> Arg { + Arg::new("install-missing") + .long("install-missing") + .help("Automatically install missing tools") + .action(ArgAction::SetTrue) + .global(true) + } +} diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index 47c479626..ab62d9403 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,3 +1,4 @@ +pub mod install_missing; pub mod jobs; pub mod log_level; pub mod raw; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index dafd68312..b23cd842b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -7,6 +7,7 @@ use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; +use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::output::Output; mod activate; @@ -159,6 +160,7 @@ impl Cli { .arg_required_else_help(true) .subcommand_required(true) .after_help(AFTER_HELP.as_str()) + .arg(args::install_missing::InstallMissing::arg()) .arg(args::jobs::Jobs::arg()) .arg(args::log_level::LogLevel::arg()) .arg(args::raw::Raw::arg()) @@ -188,6 +190,9 @@ impl Cli { if let Some(raw) = matches.get_one::("raw") { config.settings.raw = *raw; } + if let Some(true) = matches.get_one::("install-missing") { + config.settings.missing_runtime_behavior = AutoInstall; + } if *matches.get_one::("verbose").unwrap() > 0 { config.settings.verbose = true; } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 33a5fcd07..209cd9a55 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -224,18 +224,23 @@ impl ScriptManager { break; } } - match status.unwrap().success() { - true => return Ok(()), - false => { + let on_failure = |status| -> Result<()> { + on_error(combined_output.join("\n")); + Err(ScriptFailed( + display_path(&self.get_script_path(script)), + status, + ))? + }; + match status { + Some(status) => match status.success() { + true => Ok(()), + false => on_failure(Some(status)), + }, + None => { on_error(combined_output.join("\n")); - Err(ScriptFailed( - display_path(&self.get_script_path(script)), - status, - ))?; + on_failure(None) } } - - Ok(()) } } } From ac16c24afd23094bb2aa469ae1dcf342ab8a0ea9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 16:08:22 -0600 Subject: [PATCH 0405/1891] feat: added RTX_PROJECT_ROOT (#264) Used in https://github.com/jdxcode/rtx-python/pull/3 --- src/config/mod.rs | 51 ++++++++++++++++++++++++------------- src/runtimes.rs | 8 +++++- src/toolset/mod.rs | 2 +- src/toolset/tool_version.rs | 32 +++++++++++++++-------- 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 220f4aff3..43ca9a7e5 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -16,7 +16,7 @@ pub use settings::{MissingRuntimeBehavior, Settings}; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; -use crate::config::config_file::ConfigFile; +use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::tracking::Tracker; use crate::plugins::{Plugin, PluginName}; @@ -28,18 +28,20 @@ mod settings; mod tracking; type AliasMap = IndexMap>; +type ConfigMap = IndexMap>; #[derive(Debug, Default)] pub struct Config { pub settings: Settings, pub global_config: RtxToml, pub legacy_files: IndexMap, - pub config_files: IndexMap>, + pub config_files: ConfigMap, pub plugins: IndexMap>, pub env: IndexMap, pub aliases: AliasMap, pub all_aliases: OnceCell, pub should_exit_early: bool, + pub project_root: Option, shorthands: OnceCell>, } @@ -95,6 +97,7 @@ impl Config { aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), shorthands: OnceCell::new(), + project_root: get_project_root(&config_files), config_files, settings, legacy_files, @@ -201,6 +204,18 @@ impl Config { } } +fn get_project_root(config_files: &ConfigMap) -> Option { + for (p, cf) in config_files.into_iter().rev() { + match cf.get_type() { + ConfigFileType::RtxToml | ConfigFileType::ToolVersions => { + return Some(p.parent()?.to_path_buf()); + } + _ => {} + } + } + None +} + fn load_rtxrc() -> Result { let settings_path = dirs::CONFIG.join("config.toml"); match settings_path.exists() { @@ -275,27 +290,29 @@ fn load_config_filenames(legacy_filenames: &IndexMap) -> Vec let mut config_files = file::FindUp::new(&dirs::CURRENT, &filenames).collect::>(); - match env::RTX_CONFIG_FILE.clone() { - Some(global) => { - if global.is_file() { - config_files.push(global); - } - } - None => { - let home_config = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); - if home_config.is_file() { - config_files.push(home_config); - } - let global_config = dirs::CONFIG.join("config.toml"); - if global_config.is_file() { - config_files.push(global_config); - } + if env::RTX_CONFIG_FILE.is_none() { + // only add ~/.tool-versions if RTX_CONFIG_FILE is not set + // because that's how the user overrides the default + let home_config = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); + if home_config.is_file() { + config_files.push(home_config); } }; + let global_config = get_global_rtx_toml(); + if global_config.is_file() { + config_files.push(global_config); + } config_files.into_iter().unique().collect() } +fn get_global_rtx_toml() -> PathBuf { + match env::RTX_CONFIG_FILE.clone() { + Some(global) => global, + None => dirs::CONFIG.join("config.toml"), + } +} + fn load_all_config_files( settings: &Settings, config_filenames: &[PathBuf], diff --git a/src/runtimes.rs b/src/runtimes.rs index f55a26464..8f4839ac3 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -38,7 +38,7 @@ pub struct RuntimeVersion { } impl RuntimeVersion { - pub fn new(plugin: Arc, version: String, tv: ToolVersion) -> Self { + pub fn new(config: &Config, plugin: Arc, version: String, tv: ToolVersion) -> Self { let install_path = match &tv.r#type { ToolVersionType::Path(p) => p.clone(), _ => dirs::INSTALLS.join(&plugin.name).join(&version), @@ -63,6 +63,7 @@ impl RuntimeVersion { } Self { script_man: build_script_man( + config, &tv, &version, &plugin.plugin_path, @@ -305,6 +306,7 @@ impl PartialEq for RuntimeVersion { } fn build_script_man( + config: &Config, tv: &ToolVersion, version: &str, plugin_path: &Path, @@ -332,6 +334,10 @@ fn build_script_man( ) .with_env("RTX_CONCURRENCY".into(), num_cpus::get().to_string()) .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()); + if let Some(project_root) = &config.project_root { + let project_root = project_root.to_string_lossy().to_string(); + sm = sm.with_env("RTX_PROJECT_ROOT".into(), project_root); + } for (key, value) in tv.options.iter() { let k = format!("RTX_TOOL_OPTS__{}", key.to_uppercase()); sm = sm.with_env(k, value.clone()); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 3420143e1..a723a2aca 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -215,7 +215,7 @@ impl Toolset { let versions = p.list_installed_versions()?; Ok(versions.into_iter().map(|v| { let tv = ToolVersion::new(p.name.clone(), ToolVersionType::Version(v.clone())); - RuntimeVersion::new(p.clone(), v, tv) + RuntimeVersion::new(config, p.clone(), v, tv) })) }) .collect::>>()? diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 02f46e40f..ce32b08a9 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -45,8 +45,8 @@ impl ToolVersion { self.rtv = match &self.r#type { ToolVersionType::Version(v) => self.resolve_version(config, plugin, v)?, ToolVersionType::Prefix(v) => self.resolve_prefix(config, plugin, v)?, - ToolVersionType::Ref(r) => self.resolve_ref(plugin, r)?, - ToolVersionType::Path(path) => self.resolve_path(plugin, path)?, + ToolVersionType::Ref(r) => self.resolve_ref(config, plugin, r)?, + ToolVersionType::Path(path) => self.resolve_path(config, plugin, path)?, ToolVersionType::System => None, }; } @@ -62,10 +62,10 @@ impl ToolVersion { let v = resolve_alias(config, plugin.clone(), v)?; match v.split_once(':') { Some(("ref", r)) => { - return self.resolve_ref(plugin, r); + return self.resolve_ref(config, plugin, r); } Some(("path", p)) => { - return self.resolve_path(plugin, &PathBuf::from(p)); + return self.resolve_path(config, plugin, &PathBuf::from(p)); } Some(("prefix", p)) => { return self.resolve_prefix(config, plugin, p); @@ -75,13 +75,13 @@ impl ToolVersion { if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { // if the version is already installed, no need to fetch all of the remote versions - let rtv = RuntimeVersion::new(plugin, v, self.clone()); + let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); return Ok(Some(rtv)); } let matches = plugin.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { - let rtv = RuntimeVersion::new(plugin, v, self.clone()); + let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); Ok(Some(rtv)) } else { self.resolve_prefix(config, plugin, &v) @@ -100,18 +100,28 @@ impl ToolVersion { None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; - let rtv = RuntimeVersion::new(plugin, v.to_string(), self.clone()); + let rtv = RuntimeVersion::new(config, plugin, v.to_string(), self.clone()); Ok(Some(rtv)) } - fn resolve_ref(&self, plugin: Arc, r: &str) -> Result> { - let rtv = RuntimeVersion::new(plugin, format!("ref-{}", r), self.clone()); + fn resolve_ref( + &self, + config: &Config, + plugin: Arc, + r: &str, + ) -> Result> { + let rtv = RuntimeVersion::new(config, plugin, format!("ref-{}", r), self.clone()); Ok(Some(rtv)) } - fn resolve_path(&self, plugin: Arc, path: &PathBuf) -> Result> { + fn resolve_path( + &self, + config: &Config, + plugin: Arc, + path: &PathBuf, + ) -> Result> { let path = fs::canonicalize(path)?; - let rtv = RuntimeVersion::new(plugin, path.display().to_string(), self.clone()); + let rtv = RuntimeVersion::new(config, plugin, path.display().to_string(), self.clone()); Ok(Some(rtv)) } From a5fb0f358573a491edf80880440e8a84218fafa5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 16:14:54 -0600 Subject: [PATCH 0406/1891] chore: Release rtx-cli version 1.22.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38d360fa9..7db026cd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.21.6" +version = "1.22.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 293e436bf..e639ad830 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.21.6" +version = "1.22.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 3d66f8673..a56cb80de 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.21.6 +rtx 1.22.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.21.6/rtx-v1.21.6-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.0/rtx-v1.22.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.21.6-DEBUG macos-arm64 (built 2023-03-05) - New release found! v1.0.0 --> v1.21.6-DEBUG macos-arm64 (built 2023-03-05) + Checking latest released version... v1.22.0-DEBUG macos-arm64 (built 2023-03-05) + New release found! v1.0.0 --> v1.22.0-DEBUG macos-arm64 (built 2023-03-05) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.21.6-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" + * New exe release: "rtx-v1.22.0-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.21.6-DEBUG macos-arm64 (built 2023-03-05) + Updated rtx to 1.22.0-DEBUG macos-arm64 (built 2023-03-05) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 66e1a149c..df0a33d50 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.21.6"; + version = "1.22.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 6d8ba5690..c3001b9b1 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.21.6" +.TH rtx 1 "rtx 1.22.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -144,6 +144,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.21.6 +v1.22.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 0d0582a35..a7e61513b 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.21.6 +Version: 1.22.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From d900d765f6e1030bd25799c597fb7f4d0a89a791 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 16:43:45 -0600 Subject: [PATCH 0407/1891] bug: wait for threads to finish (#266) --- .github/workflows/test-plugins.yml | 2 ++ src/plugins/script_manager.rs | 49 +++++++++++------------------- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 4fd2f689c..b23efc076 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -37,6 +37,7 @@ jobs: RTX_MISSING_RUNTIME_BEHAVIOR: autoinstall GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} strategy: + fail-fast: false matrix: include: - plugin: nodejs @@ -106,6 +107,7 @@ jobs: env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} strategy: + fail-fast: false matrix: plugins: - waypoint diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 209cd9a55..901627237 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -181,8 +181,7 @@ impl ScriptManager { let stdout = BufReader::new(cp.stdout.take().unwrap()); let stderr = BufReader::new(cp.stderr.take().unwrap()); let (tx, rx) = channel(); - let mut threads = vec![]; - threads.push(thread::spawn({ + thread::spawn({ let tx = tx.clone(); move || { for line in stdout.lines() { @@ -190,8 +189,8 @@ impl ScriptManager { tx.send(ChildProcessOutput::Stdout(line)).unwrap(); } } - })); - threads.push(thread::spawn({ + }); + thread::spawn({ let tx = tx.clone(); move || { for line in stderr.lines() { @@ -199,13 +198,12 @@ impl ScriptManager { tx.send(ChildProcessOutput::Stderr(line)).unwrap(); } } - })); - threads.push(thread::spawn(move || { + }); + thread::spawn(move || { let status = cp.wait().unwrap(); tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); - })); + }); let mut combined_output = vec![]; - let mut status = None; for line in rx { match line { ChildProcessOutput::Stdout(line) => { @@ -216,31 +214,20 @@ impl ScriptManager { on_stderr(&line); combined_output.push(line); } - ChildProcessOutput::ExitStatus(s) => { - status = Some(s); - } - } - if threads.iter().all(|t| t.is_finished()) { - break; - } - } - let on_failure = |status| -> Result<()> { - on_error(combined_output.join("\n")); - Err(ScriptFailed( - display_path(&self.get_script_path(script)), - status, - ))? - }; - match status { - Some(status) => match status.success() { - true => Ok(()), - false => on_failure(Some(status)), - }, - None => { - on_error(combined_output.join("\n")); - on_failure(None) + ChildProcessOutput::ExitStatus(status) => match status.success() { + true => return Ok(()), + false => { + on_error(combined_output.join("\n")); + Err(ScriptFailed( + display_path(&self.get_script_path(script)), + Some(status), + ))?; + } + }, } } + + Ok(()) } } } From fd5a0349c182c89fb43287ac875b2cd44d8fa1a7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 16:44:56 -0600 Subject: [PATCH 0408/1891] chore: Release rtx-cli version 1.22.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7db026cd0..441825cb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.0" +version = "1.22.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index e639ad830..7fc251cb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.0" +version = "1.22.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a56cb80de..20e236220 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.0 +rtx 1.22.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.0/rtx-v1.22.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.1/rtx-v1.22.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.22.0-DEBUG macos-arm64 (built 2023-03-05) - New release found! v1.0.0 --> v1.22.0-DEBUG macos-arm64 (built 2023-03-05) + Checking latest released version... v1.22.1-DEBUG macos-arm64 (built 2023-03-05) + New release found! v1.0.0 --> v1.22.1-DEBUG macos-arm64 (built 2023-03-05) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.22.0-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" + * New exe release: "rtx-v1.22.1-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.22.0-DEBUG macos-arm64 (built 2023-03-05) + Updated rtx to 1.22.1-DEBUG macos-arm64 (built 2023-03-05) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index df0a33d50..27c199466 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.0"; + version = "1.22.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c3001b9b1..4026b2904 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.0" +.TH rtx 1 "rtx 1.22.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -144,6 +144,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.0 +v1.22.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a7e61513b..e58922350 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.0 +Version: 1.22.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 5d5cd1d7c5745c2e62512c605cf0a20cc936d937 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 17:15:47 -0600 Subject: [PATCH 0409/1891] bug: fix potential race condition in script execution (#267) I believe with how the code was before a race condition might cause some output to be truncated --- .github/workflows/rtx.yml | 5 +++-- .github/workflows/test-plugins.yml | 6 ++++++ src/plugins/script_manager.rs | 32 +++++++++++++++++++++--------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 2c85bd65f..5bd9061cd 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -22,7 +22,8 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + shared-key: "build-linux-x86_64-unknown-linux-gnu" + save-if: false - name: Install direnv/shfmt run: sudo apt-get update; sudo apt-get install direnv shfmt - uses: taiki-e/install-action@just @@ -79,7 +80,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - key: "${{matrix.target}}" + shared-key: "build-linux-${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cross - run: scripts/build-linux.sh ${{matrix.target}} diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index b23efc076..e7af75433 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -6,6 +6,7 @@ name: test-plugins on: push: tags: ["v*"] + branches: ["main", "test-plugins"] schedule: # run at midnight on sunday (utc?) - cron: 0 0 * * 0 @@ -22,6 +23,11 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 + - name: Rust Cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "build-linux-x86_64-unknown-linux-gnu" + save-if: false - run: scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu - uses: actions/upload-artifact@v3 with: diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 901627237..053d76946 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -188,6 +188,7 @@ impl ScriptManager { let line = line.unwrap(); tx.send(ChildProcessOutput::Stdout(line)).unwrap(); } + tx.send(ChildProcessOutput::Done).unwrap(); } }); thread::spawn({ @@ -197,13 +198,17 @@ impl ScriptManager { let line = line.unwrap(); tx.send(ChildProcessOutput::Stderr(line)).unwrap(); } + tx.send(ChildProcessOutput::Done).unwrap(); } }); thread::spawn(move || { let status = cp.wait().unwrap(); tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); + tx.send(ChildProcessOutput::Done).unwrap(); }); let mut combined_output = vec![]; + let mut wait_for_count = 3; + let mut status = None; for line in rx { match line { ChildProcessOutput::Stdout(line) => { @@ -214,18 +219,26 @@ impl ScriptManager { on_stderr(&line); combined_output.push(line); } - ChildProcessOutput::ExitStatus(status) => match status.success() { - true => return Ok(()), - false => { - on_error(combined_output.join("\n")); - Err(ScriptFailed( - display_path(&self.get_script_path(script)), - Some(status), - ))?; + ChildProcessOutput::ExitStatus(s) => { + status = Some(s); + } + ChildProcessOutput::Done => { + wait_for_count -= 1; + if wait_for_count == 0 { + break; } - }, + } } } + let status = status.unwrap(); + + if !status.success() { + on_error(combined_output.join("\n")); + Err(ScriptFailed( + display_path(&self.get_script_path(script)), + Some(status), + ))?; + } Ok(()) } @@ -236,4 +249,5 @@ enum ChildProcessOutput { Stdout(String), Stderr(String), ExitStatus(ExitStatus), + Done, } From 133c459dc09ddb311ca4bf2237816c1fb97a76e7 Mon Sep 17 00:00:00 2001 From: Jay Bosamiya Date: Sun, 5 Mar 2023 18:32:23 -0500 Subject: [PATCH 0410/1891] Fix zsh deactivation (#268) * Fix zsh deactivation, removing rtx hook * updated snapshots --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- .../snapshots/rtx__cli__deactivate__tests__deactivate-2.snap | 4 ++-- src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap | 4 ++-- src/shell/zsh.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap index 361793baf..7739ccdb1 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap @@ -3,8 +3,8 @@ source: src/cli/deactivate.rs expression: output --- export PATH='$PATH' -precmd_functions=( ${precmd_functions[(r)_rtx_hook]} ) -chpwd_functions=( ${chpwd_functions[(r)_rtx_hook]} ) +precmd_functions=( ${precmd_functions:#_rtx_hook} ) +chpwd_functions=( ${chpwd_functions:#_rtx_hook} ) unset -f _rtx_hook unset -f rtx unset RTX_SHELL diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap index 2f9c1c3b7..600e477af 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap @@ -2,8 +2,8 @@ source: src/shell/zsh.rs expression: replace_path(&deactivate) --- -precmd_functions=( ${precmd_functions[(r)_rtx_hook]} ) -chpwd_functions=( ${chpwd_functions[(r)_rtx_hook]} ) +precmd_functions=( ${precmd_functions:#_rtx_hook} ) +chpwd_functions=( ${chpwd_functions:#_rtx_hook} ) unset -f _rtx_hook unset -f rtx unset RTX_SHELL diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 62078cccf..197d7f098 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -62,8 +62,8 @@ impl Shell for Zsh { fn deactivate(&self) -> String { formatdoc! {r#" - precmd_functions=( ${{precmd_functions[(r)_rtx_hook]}} ) - chpwd_functions=( ${{chpwd_functions[(r)_rtx_hook]}} ) + precmd_functions=( ${{precmd_functions:#_rtx_hook}} ) + chpwd_functions=( ${{chpwd_functions:#_rtx_hook}} ) unset -f _rtx_hook unset -f rtx unset RTX_SHELL From 848d81c5c854c13c605965808cefb57beebb77d6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 17:32:59 -0600 Subject: [PATCH 0411/1891] chore: retry test-plugins tests on failure (#269) --- .github/workflows/test-plugins.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index e7af75433..54dc4b181 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -6,7 +6,7 @@ name: test-plugins on: push: tags: ["v*"] - branches: ["main", "test-plugins"] + branches: ["test-plugins"] schedule: # run at midnight on sunday (utc?) - cron: 0 0 * * 0 @@ -88,7 +88,7 @@ jobs: - plugin: php command: rtx exec php@latest -- php -v php - plugin: rust - command: rtx exec rust@latest -- rustc -V + command: rtx exec rust@nightly -- rustc -V - plugin: postgres command: rtx exec postgres@latest -- psql -V steps: @@ -174,4 +174,9 @@ jobs: path: dist - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH - - run: rtx install ${{matrix.plugins}}@latest + - uses: nick-fields/retry@v2 + with: + timeout_minutes: 20 + max_attempts: 3 + retry_wait_seconds: 30 + command: rtx install ${{matrix.plugins}}@latest From c9c4833e74067a38d47c0418e9f3b61645511b65 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 17:33:37 -0600 Subject: [PATCH 0412/1891] chore: Release rtx-cli version 1.22.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 441825cb0..065816bc3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.1" +version = "1.22.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 7fc251cb8..77c2477e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.1" +version = "1.22.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 20e236220..b820604c1 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.1 +rtx 1.22.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.1/rtx-v1.22.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.2/rtx-v1.22.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.22.1-DEBUG macos-arm64 (built 2023-03-05) - New release found! v1.0.0 --> v1.22.1-DEBUG macos-arm64 (built 2023-03-05) + Checking latest released version... v1.22.2-DEBUG macos-arm64 (built 2023-03-05) + New release found! v1.0.0 --> v1.22.2-DEBUG macos-arm64 (built 2023-03-05) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.22.1-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" + * New exe release: "rtx-v1.22.2-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.22.1-DEBUG macos-arm64 (built 2023-03-05) + Updated rtx to 1.22.2-DEBUG macos-arm64 (built 2023-03-05) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 27c199466..5aaa2d244 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.1"; + version = "1.22.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 4026b2904..210fffe67 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.1" +.TH rtx 1 "rtx 1.22.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -144,6 +144,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.1 +v1.22.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e58922350..585ffb1a7 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.1 +Version: 1.22.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From b07b97cdc0347fa3931e87c9adb20d9b993f31a3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 17:53:57 -0600 Subject: [PATCH 0413/1891] use bot token for releases this avoids the issue that happened releasing 1.22.2 where it failed at the very end --- .github/workflows/rtx.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 5bd9061cd..aa4096c7f 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -250,6 +250,7 @@ jobs: draft: false files: releases/${{github.ref_name}}/* generate_release_notes: true + token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - name: Release to aur run: scripts/release-aur.sh working-directory: rtx From 51f432e542a2a5d6520ced5a51ef39ea7cf99faf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 17:54:42 -0600 Subject: [PATCH 0414/1891] chore: Release rtx-cli version 1.22.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 065816bc3..d9320bde0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.2" +version = "1.22.3" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 77c2477e6..3e750d13d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.2" +version = "1.22.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index b820604c1..2cca3fed5 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.2 +rtx 1.22.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.2/rtx-v1.22.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.3/rtx-v1.22.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.22.2-DEBUG macos-arm64 (built 2023-03-05) - New release found! v1.0.0 --> v1.22.2-DEBUG macos-arm64 (built 2023-03-05) + Checking latest released version... v1.22.3-DEBUG macos-arm64 (built 2023-03-05) + New release found! v1.0.0 --> v1.22.3-DEBUG macos-arm64 (built 2023-03-05) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.22.2-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" + * New exe release: "rtx-v1.22.3-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.22.2-DEBUG macos-arm64 (built 2023-03-05) + Updated rtx to 1.22.3-DEBUG macos-arm64 (built 2023-03-05) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 5aaa2d244..1d369a48f 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.2"; + version = "1.22.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 210fffe67..0c4878e3c 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.2" +.TH rtx 1 "rtx 1.22.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -144,6 +144,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.2 +v1.22.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 585ffb1a7..8242823a7 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.2 +Version: 1.22.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 8460ff2cb7534020d2b1bbbcc375b7244f48f4a6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:16:46 -0600 Subject: [PATCH 0415/1891] chore: use RTX_GITHUB_BOT_TOKEN if available for coverage tests (#270) This is needed for the self_update check. GITHUB_TOKEN can be rate limited, but RTX_GITHUB_BOT_TOKEN will not be available on forks --- .github/workflows/rtx.yml | 2 +- justfile | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index aa4096c7f..0332f8085 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -54,6 +54,7 @@ jobs: uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RTX_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} RUST_BACKTRACE: "1" with: timeout_minutes: 20 @@ -136,7 +137,6 @@ jobs: - name: Run e2e tests uses: nick-fields/retry@v2 env: - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" with: timeout_minutes: 20 diff --git a/justfile b/justfile index a48605905..575efba2d 100644 --- a/justfile +++ b/justfile @@ -37,7 +37,11 @@ test-coverage: #!/usr/bin/env bash set -euxo pipefail source <(cargo llvm-cov show-env --export-prefix) - cargo llvm-cov clean --workspace + cargo llvm-cov clean --workspace + + if [[ -n "${RTX_GITHUB_BOT_TOKEN:-}" ]]; then + export GITHUB_API_TOKEN="$RTX_GITHUB_BOT_TOKEN" + fi cargo test --features clap_mangen cargo build --all-features From c8d850f8698d07ee926b123e8cbfe7c19b706175 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:24:02 -0600 Subject: [PATCH 0416/1891] wip --- .github/workflows/test-plugins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 54dc4b181..2c92273dd 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -28,7 +28,7 @@ jobs: with: shared-key: "build-linux-x86_64-unknown-linux-gnu" save-if: false - - run: scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu + - run: echo 1 && scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu - uses: actions/upload-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu From 3e7cd3d8bea3fabdcfab1275a4be4640e5ae49cc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:24:24 -0600 Subject: [PATCH 0417/1891] test all branches --- .github/workflows/rtx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 0332f8085..1479e26c8 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -2,7 +2,7 @@ name: rtx on: push: - branches: ["main"] + branches: ["*"] tags: ["v*"] pull_request: branches: ["main"] From 241f72a154a2b77f614dbfd5c676d0dc1ab97048 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:26:09 -0600 Subject: [PATCH 0418/1891] do not use shared cache for unit tests (didnt work) --- .github/workflows/rtx.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 1479e26c8..13b925518 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -22,8 +22,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - shared-key: "build-linux-x86_64-unknown-linux-gnu" - save-if: false + save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Install direnv/shfmt run: sudo apt-get update; sudo apt-get install direnv shfmt - uses: taiki-e/install-action@just From 88e879a1438e986f79351bd07727736a01ecefbd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:27:09 -0600 Subject: [PATCH 0419/1891] removed unnecessary echo --- .github/workflows/test-plugins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 2c92273dd..54dc4b181 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -28,7 +28,7 @@ jobs: with: shared-key: "build-linux-x86_64-unknown-linux-gnu" save-if: false - - run: echo 1 && scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu + - run: scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu - uses: actions/upload-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu From 884a4cb3e0a32f50d1e51436816769077e2aab8d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:43:21 -0600 Subject: [PATCH 0420/1891] bug: fix issue with RTX_PROJECT_ROOT This was reversed from what it should be causing ~/.config/rtx/config.toml to be returned, not ~/src/myproj like it should have been --- README.md | 8 ++++---- src/config/mod.rs | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2cca3fed5..1d6ca3f03 100644 --- a/README.md +++ b/README.md @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.22.3-DEBUG macos-arm64 (built 2023-03-05) - New release found! v1.0.0 --> v1.22.3-DEBUG macos-arm64 (built 2023-03-05) + Checking latest released version... v1.22.3-DEBUG macos-arm64 (built 2023-03-06) + New release found! v1.0.0 --> v1.22.3-DEBUG macos-arm64 (built 2023-03-06) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.22.3-DEBUG macos-arm64 (built 2023-03-05)-macos-arm64" + * New exe release: "rtx-v1.22.3-DEBUG macos-arm64 (built 2023-03-06)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.22.3-DEBUG macos-arm64 (built 2023-03-05) + Updated rtx to 1.22.3-DEBUG macos-arm64 (built 2023-03-06) ``` ### `rtx settings get` diff --git a/src/config/mod.rs b/src/config/mod.rs index 43ca9a7e5..632aa1ebf 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -205,7 +205,11 @@ impl Config { } fn get_project_root(config_files: &ConfigMap) -> Option { - for (p, cf) in config_files.into_iter().rev() { + for (p, cf) in config_files.into_iter() { + if p == &get_global_rtx_toml() { + // ~/.config/rtx/config.toml is not a project config file + continue; + } match cf.get_type() { ConfigFileType::RtxToml | ConfigFileType::ToolVersions => { return Some(p.parent()?.to_path_buf()); From 49904e4c2097e91b9557603c78908d10c1151fcd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:43:55 -0600 Subject: [PATCH 0421/1891] chore: Release rtx-cli version 1.22.4 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 12 ++++++------ default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9320bde0..9469f9bae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.3" +version = "1.22.4" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 3e750d13d..f03401afc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.3" +version = "1.22.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 1d6ca3f03..b080babc6 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.3 +rtx 1.22.4 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.3/rtx-v1.22.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.4/rtx-v1.22.4-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` @@ -1533,20 +1533,20 @@ Examples: $ rtx self-update Checking target-arch... macos-arm64 Checking current version... v1.0.0 - Checking latest released version... v1.22.3-DEBUG macos-arm64 (built 2023-03-06) - New release found! v1.0.0 --> v1.22.3-DEBUG macos-arm64 (built 2023-03-06) + Checking latest released version... v1.22.4-DEBUG macos-arm64 (built 2023-03-06) + New release found! v1.0.0 --> v1.22.4-DEBUG macos-arm64 (built 2023-03-06) New release is compatible rtx release status: * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.22.3-DEBUG macos-arm64 (built 2023-03-06)-macos-arm64" + * New exe release: "rtx-v1.22.4-DEBUG macos-arm64 (built 2023-03-06)-macos-arm64" The new release will be downloaded/extracted and the existing binary will be replaced. Do you want to continue? [Y/n] y Downloading... Extracting archive... Done Replacing binary file... Done - Updated rtx to 1.22.3-DEBUG macos-arm64 (built 2023-03-06) + Updated rtx to 1.22.4-DEBUG macos-arm64 (built 2023-03-06) ``` ### `rtx settings get` diff --git a/default.nix b/default.nix index 1d369a48f..93625aae1 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.3"; + version = "1.22.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 0c4878e3c..875ef313a 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.3" +.TH rtx 1 "rtx 1.22.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -144,6 +144,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.3 +v1.22.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 8242823a7..7e9826b39 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.3 +Version: 1.22.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From bc4d2506d57e0af05c4babfa0d37559f847ed4d8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 5 Mar 2023 18:50:11 -0600 Subject: [PATCH 0422/1891] docs: removed examples of self_update These were not that helpful and they made commits noisy --- README.md | 19 ------------------- completions/_rtx | 4 ++-- completions/rtx.fish | 2 +- src/cli/self_update/github.rs | 30 +++--------------------------- src/cli/self_update/other.rs | 27 +-------------------------- 5 files changed, 7 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index b080babc6..d8ee9b31a 100644 --- a/README.md +++ b/README.md @@ -1528,25 +1528,6 @@ a binary from GitHub Releases if rtx was installed manually. Supports: standalone, brew, deb, rpm Usage: self-update - -Examples: - $ rtx self-update - Checking target-arch... macos-arm64 - Checking current version... v1.0.0 - Checking latest released version... v1.22.4-DEBUG macos-arm64 (built 2023-03-06) - New release found! v1.0.0 --> v1.22.4-DEBUG macos-arm64 (built 2023-03-06) - New release is compatible - - rtx release status: - * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v1.22.4-DEBUG macos-arm64 (built 2023-03-06)-macos-arm64" - - The new release will be downloaded/extracted and the existing binary will be replaced. - Do you want to continue? [Y/n] y - Downloading... - Extracting archive... Done - Replacing binary file... Done - Updated rtx to 1.22.4-DEBUG macos-arm64 (built 2023-03-06) ``` ### `rtx settings get` diff --git a/completions/_rtx b/completions/_rtx index 000d77f73..20b83d38d 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1009,8 +1009,8 @@ sets --jobs=1]' \ sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ +'-h[Print help]' \ +'--help[Print help]' \ && ret=0 ;; (settings) diff --git a/completions/rtx.fish b/completions/rtx.fish index 344893b33..763d880d5 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -437,7 +437,7 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r diff --git a/src/cli/self_update/github.rs b/src/cli/self_update/github.rs index 1f3c845de..879349eba 100644 --- a/src/cli/self_update/github.rs +++ b/src/cli/self_update/github.rs @@ -1,12 +1,11 @@ use color_eyre::Result; use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; + use self_update::backends::github::Update; use self_update::cargo_crate_version; use crate::cli::command::Command; -use crate::cli::version::{ARCH, OS, VERSION}; +use crate::cli::version::{ARCH, OS}; use crate::config::Config; use crate::env; use crate::output::Output; @@ -16,7 +15,7 @@ use crate::output::Output; /// a binary from GitHub Releases if rtx was installed manually. /// Supports: standalone, brew, deb, rpm #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment)] pub struct SelfUpdate {} impl Command for SelfUpdate { @@ -46,26 +45,3 @@ impl Command for SelfUpdate { Ok(()) } } - -pub static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx self-update - Checking target-arch... macos-arm64 - Checking current version... v1.0.0 - Checking latest released version... v{version} - New release found! v1.0.0 --> v{version} - New release is compatible - - rtx release status: - * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v{version}-macos-arm64" - - The new release will be downloaded/extracted and the existing binary will be replaced. - Do you want to continue? [Y/n] y - Downloading... - Extracting archive... Done - Replacing binary file... Done - Updated rtx to {version} - "#, style("Examples:").bold().underlined(), version=*VERSION} -}); diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs index 610a27109..11c1e9384 100644 --- a/src/cli/self_update/other.rs +++ b/src/cli/self_update/other.rs @@ -1,8 +1,6 @@ -use crate::cli::version::VERSION; use color_eyre::eyre::eyre; use color_eyre::Result; use console::style; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -14,7 +12,7 @@ use crate::{cmd, env}; /// a binary from GitHub Releases if rtx was installed manually. /// Supports: standalone, brew, deb, rpm #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment)] pub struct SelfUpdate {} impl Command for SelfUpdate { @@ -35,29 +33,6 @@ impl Command for SelfUpdate { } } -pub static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - indoc::formatdoc! {r#" - {} - $ rtx self-update - Checking target-arch... macos-arm64 - Checking current version... v1.0.0 - Checking latest released version... v{version} - New release found! v1.0.0 --> v{version} - New release is compatible - - rtx release status: - * Current exe: "/Users/jdx/bin/rtx" - * New exe release: "rtx-v{version}-macos-arm64" - - The new release will be downloaded/extracted and the existing binary will be replaced. - Do you want to continue? [Y/n] y - Downloading... - Extracting archive... Done - Replacing binary file... Done - Updated rtx to {version} - "#, style("Examples:").bold().underlined(), version=*VERSION} -}); - #[cfg(test)] mod tests { use insta::assert_display_snapshot; From 9b0e6dedb8632bdc0e97fd5a5edc98f9bc2fd844 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Mar 2023 20:26:25 -0600 Subject: [PATCH 0423/1891] chore(deps): bump indoc from 2.0.0 to 2.0.1 (#271) Bumps [indoc](https://github.com/dtolnay/indoc) from 2.0.0 to 2.0.1. - [Release notes](https://github.com/dtolnay/indoc/releases) - [Commits](https://github.com/dtolnay/indoc/compare/2.0.0...2.0.1) --- updated-dependencies: - dependency-name: indoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9469f9bae..67c2306c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -814,9 +814,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2b9d82064e8a0226fddb3547f37f28eaa46d0fc210e275d835f08cf3b76a7" +checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" [[package]] name = "insta" diff --git a/Cargo.toml b/Cargo.toml index f03401afc..978484c97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ humantime = "2.1.0" indenter = "0.3.3" indexmap = "1.9.2" indicatif = { version = "0.17.3", features = ["default", "improved_unicode"] } -indoc = "2.0.0" +indoc = "2.0.1" itertools = "0.10.5" lazy_static = "1.4.0" log = "0.4.17" From 6dd2547abb1a5525e377d57a5a39fdb5041e9c32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 02:35:00 +0000 Subject: [PATCH 0424/1891] chore(deps): bump clap_complete from 4.1.3 to 4.1.4 (#273) Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.1.3 to 4.1.4. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.1.3...clap_complete-v4.1.4) --- updated-dependencies: - dependency-name: clap_complete dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67c2306c5..14e5cef7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.3" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0012995dc3a54314f4710f5631d74767e73c534b8757221708303e48eef7a19b" +checksum = "501ff0a401473ea1d4c3b125ff95506b62c5bc5768d818634195fbb7c4ad5ff4" dependencies = [ "clap", ] diff --git a/Cargo.toml b/Cargo.toml index 978484c97..08e85294d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ base64 = "0.21.0" build-time = "0.1.2" chrono = "0.4.23" clap = { version = "4.1.1", features = ["env", "derive", "string"] } -clap_complete = "4.1.1" +clap_complete = "4.1.4" clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" console = "0.15.5" From 29fb459c39f6ce8aaccf85ef505575cdcdb0d20d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 02:41:50 +0000 Subject: [PATCH 0425/1891] chore(deps): bump thiserror from 1.0.38 to 1.0.39 (#274) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.38 to 1.0.39. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.38...1.0.39) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14e5cef7c..e57394e8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1723,18 +1723,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 08e85294d..e82fb94b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,7 @@ serde_json = "1.0.92" shell-escape = "0.1.5" simplelog = { version = "0.12.0" } term_size = "0.3.2" -thiserror = "1.0.38" +thiserror = "1.0.39" toml = "0.7.1" toml_edit = "0.19.0" url = "2.3.1" From f1df7108b0dcff94b8c098e9d8e72012df500ce5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 02:48:59 +0000 Subject: [PATCH 0426/1891] chore(deps): bump rayon from 1.6.1 to 1.7.0 (#272) Bumps [rayon](https://github.com/rayon-rs/rayon) from 1.6.1 to 1.7.0. - [Release notes](https://github.com/rayon-rs/rayon/releases) - [Changelog](https://github.com/rayon-rs/rayon/blob/master/RELEASES.md) - [Commits](https://github.com/rayon-rs/rayon/compare/rayon-core-v1.6.1...rayon-core-v1.7.0) --- updated-dependencies: - dependency-name: rayon dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e57394e8a..9a8fdceac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1268,9 +1268,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -1278,9 +1278,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", diff --git a/Cargo.toml b/Cargo.toml index e82fb94b7..c9732789e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ num_cpus = "1.15.0" once_cell = "1.17.0" openssl = { version = "0.10", features = ["vendored"] } owo-colors = { version = "3.5.0" } -rayon = "1.6.1" +rayon = "1.7.0" regex = "1.7.1" reqwest = { version = "0.11.14", features = ["blocking"] } rmp-serde = "1.1.1" From 10b4d0057982647259e62ac9a26886d7671f7b52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 02:56:30 +0000 Subject: [PATCH 0427/1891] chore(deps): bump clap from 4.1.6 to 4.1.8 (#275) Bumps [clap](https://github.com/clap-rs/clap) from 4.1.6 to 4.1.8. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.1.6...v4.1.8) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a8fdceac..6c9de52d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.6" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ "bitflags", "clap_derive", @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.1.0" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" dependencies = [ "heck", "proc-macro-error", diff --git a/Cargo.toml b/Cargo.toml index c9732789e..089ec5266 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ path = "src/main.rs" base64 = "0.21.0" build-time = "0.1.2" chrono = "0.4.23" -clap = { version = "4.1.1", features = ["env", "derive", "string"] } +clap = { version = "4.1.8", features = ["env", "derive", "string"] } clap_complete = "4.1.4" clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" From 70c55482be4321a6a56c8a4163e7a411e287ba02 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 07:24:45 -0600 Subject: [PATCH 0428/1891] bug: fail hard if parsing a config file fails --- src/config/mod.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 632aa1ebf..23fadd887 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -57,7 +57,7 @@ impl Config { &plugins, &IndexMap::new(), IndexMap::new(), - ); + )?; for cf in config_files.values() { settings.merge(cf.settings()); } @@ -80,6 +80,7 @@ impl Config { }, || hook_env::should_exit_early(&config_filenames), ); + let config_files = config_files?; for cf in config_files.values() { for (plugin_name, repo_url) in cf.plugins() { @@ -323,8 +324,8 @@ fn load_all_config_files( plugins: &IndexMap>, legacy_filenames: &IndexMap, mut existing: IndexMap>, -) -> IndexMap> { - config_filenames +) -> Result { + Ok(config_filenames .iter() .unique() .map(|f| (f.clone(), existing.shift_remove(f))) @@ -332,20 +333,18 @@ fn load_all_config_files( .into_par_iter() .map(|(f, existing)| match existing { // already parsed so just return it - Some(cf) => Some((f, cf)), + Some(cf) => Ok((f, cf)), // need to parse this config file None => match parse_config_file(&f, settings, legacy_filenames, plugins) { - Ok(cf) => Some((f, cf)), - Err(err) => { - warn!("error parsing: {} {:#}", f.display(), err); - None - } + Ok(cf) => Ok((f, cf)), + Err(err) => Err(eyre!("error parsing: {} {:#}", f.display(), err)), }, }) - .collect::>() + .collect::>>() .into_iter() - .flatten() - .collect() + .collect::>>()? + .into_iter() + .collect()) } fn parse_config_file( From cf94ff997e4762e4c2a10a042db117a6d79897e8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 07:26:18 -0600 Subject: [PATCH 0429/1891] bug: install shims for all installed versions before this was only installing _current_ versions but we actually need shims for everything Fixes #276 --- completions/_rtx | 6 +++++- src/shims.rs | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index 20b83d38d..ef65547d0 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -2399,5 +2399,9 @@ _rtx__which_commands() { _describe -t commands 'rtx which commands' commands "$@" } -_rtx "$@" +if [ "$funcstack[1]" = "_rtx" ]; then + _rtx "$@" +else + compdef _rtx rtx +fi diff --git a/src/shims.rs b/src/shims.rs index b1ab3d15a..8ba3a30f5 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -6,6 +6,7 @@ use std::process::exit; use color_eyre::eyre::{eyre, Result}; use indoc::formatdoc; +use rayon::prelude::*; use crate::cli::command::Command; use crate::cli::exec::Exec; @@ -78,7 +79,19 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { create_dir_all(&shims_dir)?; let rtx_bin = config.rtx_bin().unwrap_or(env::RTX_EXE.clone()); - for path in ts.list_paths(config) { + let paths: Vec = ts + .list_installed_versions(config)? + .into_par_iter() + .flat_map(|rtv| match rtv.list_bin_paths(&config.settings) { + Ok(paths) => paths, + Err(e) => { + warn!("Error listing bin paths for {}: {:#}", rtv, e); + Vec::new() + } + }) + .collect(); + + for path in paths { if !path.exists() { continue; } From 78795714962b093b1aa36987872b77df7d3f4c66 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 08:20:43 -0600 Subject: [PATCH 0430/1891] bug: reshim all installed versions (#277) --- .github/workflows/rtx.yml | 1 - src/cli/activate.rs | 15 ------- src/cli/install.rs | 4 +- src/cli/mod.rs | 5 ++- ...x__cli__activate__tests__activate_zsh.snap | 40 ------------------- ..._activate__tests__activate_zsh_legacy.snap | 40 ------------------- src/env.rs | 2 +- src/shims.rs | 10 ++++- src/test.rs | 1 + 9 files changed, 16 insertions(+), 102 deletions(-) delete mode 100644 src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap delete mode 100644 src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 13b925518..3dd355d8c 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -2,7 +2,6 @@ name: rtx on: push: - branches: ["*"] tags: ["v*"] pull_request: branches: ["main"] diff --git a/src/cli/activate.rs b/src/cli/activate.rs index b88ba722a..e0c7c7108 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -61,18 +61,3 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { $ execx($(rtx activate xonsh)) "#, style("Examples:").bold().underlined()} }); - -#[cfg(test)] -mod tests { - use crate::assert_cli_snapshot; - - #[test] - fn test_activate_zsh() { - assert_cli_snapshot!("activate", "zsh"); - } - - #[test] - fn test_activate_zsh_legacy() { - assert_cli_snapshot!("activate", "-s", "zsh"); - } -} diff --git a/src/cli/install.rs b/src/cli/install.rs index 988d29a9b..5ad335716 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::sync::Arc; -use color_eyre::eyre::Result; +use color_eyre::eyre::{Context, Result}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -168,7 +168,7 @@ impl Install { } }) .collect::>>()?; - reshim(&mut config, &ts) + reshim(&mut config, &ts).with_context(|| "failed to reshim") }) } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b23cd842b..ef2d6cbe4 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -237,13 +237,16 @@ static AFTER_HELP: Lazy = Lazy::new(|| { #[cfg(test)] pub mod tests { use crate::dirs; + use color_eyre::{Section, SectionExt}; use super::*; pub fn cli_run(args: &Vec) -> Result { let config = Config::load()?; let mut out = Output::tracked(); - Cli::new_with_external_commands(&config).run(config, args, &mut out)?; + Cli::new_with_external_commands(&config) + .run(config, args, &mut out) + .with_section(|| format!("{}", args.join(" ").header("Command:")))?; Ok(out) } diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap deleted file mode 100644 index 85f888cc3..000000000 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh.snap +++ /dev/null @@ -1,40 +0,0 @@ ---- -source: src/cli/activate.rs -expression: output ---- -export PATH=":$PATH" -export RTX_SHELL=zsh - -rtx() { - local command - command="${1:-}" - if [ "$#" = 0 ]; then - command rtx - return - fi - shift - - case "$command" in - deactivate|shell) - eval "$(rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" - ;; - esac -} - -_rtx_hook() { - trap -- '' SIGINT; - eval "$("rtx" hook-env -s zsh)"; - trap - SIGINT; -} -typeset -ag precmd_functions; -if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then - precmd_functions=( _rtx_hook ${precmd_functions[@]} ) -fi -typeset -ag chpwd_functions; -if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then - chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) -fi - diff --git a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap b/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap deleted file mode 100644 index 85f888cc3..000000000 --- a/src/cli/snapshots/rtx__cli__activate__tests__activate_zsh_legacy.snap +++ /dev/null @@ -1,40 +0,0 @@ ---- -source: src/cli/activate.rs -expression: output ---- -export PATH=":$PATH" -export RTX_SHELL=zsh - -rtx() { - local command - command="${1:-}" - if [ "$#" = 0 ]; then - command rtx - return - fi - shift - - case "$command" in - deactivate|shell) - eval "$(rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" - ;; - esac -} - -_rtx_hook() { - trap -- '' SIGINT; - eval "$("rtx" hook-env -s zsh)"; - trap - SIGINT; -} -typeset -ag precmd_functions; -if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then - precmd_functions=( _rtx_hook ${precmd_functions[@]} ) -fi -typeset -ag chpwd_functions; -if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then - chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) -fi - diff --git a/src/env.rs b/src/env.rs index ee9c9dfdf..d083c6577 100644 --- a/src/env.rs +++ b/src/env.rs @@ -26,7 +26,7 @@ lazy_static! { pub static ref RTX_USE_TOML: bool = var_is_true("RTX_USE_TOML"); pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); - pub static ref RTX_EXE: PathBuf = if cfg!(test) {"rtx".into()} else {current_exe().unwrap_or_else(|_| "rtx".into())}; + pub static ref RTX_EXE: PathBuf = current_exe().unwrap_or_else(|_| "rtx".into()); // logging pub static ref RTX_LOG_LEVEL: log::LevelFilter = { diff --git a/src/shims.rs b/src/shims.rs index 8ba3a30f5..26efdeb73 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -4,7 +4,7 @@ use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; use std::process::exit; -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::{eyre, Result, WrapErr}; use indoc::formatdoc; use rayon::prelude::*; @@ -102,7 +102,13 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { } let bin_name = bin.file_name().into_string().unwrap(); let symlink_path = shims_dir.join(bin_name); - file::make_symlink(&rtx_bin, &symlink_path)?; + file::make_symlink(&rtx_bin, &symlink_path).with_context(|| { + format!( + "Failed to create symlink from {} to {}", + rtx_bin.display(), + symlink_path.display() + ) + })?; } } for plugin in config.plugins.values() { diff --git a/src/test.rs b/src/test.rs index 3684dd048..a8601c6d9 100644 --- a/src/test.rs +++ b/src/test.rs @@ -75,4 +75,5 @@ pub fn replace_path(input: &str) -> String { input .replace(path.as_str(), "$PATH") .replace(home.as_str(), "~") + .replace(env::RTX_EXE.to_string_lossy().as_ref(), "rtx") } From 0aa2fc87638662f510067ce1c5bef485980d88e2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 10:10:15 -0600 Subject: [PATCH 0431/1891] bug: fix `exec *@system` (#279) Fixes #278 --- e2e/test_system | 19 +++++++++++++++++++ src/cli/args/runtime.rs | 6 +++++- src/toolset/tool_version.rs | 34 +++++++++++++++++----------------- 3 files changed, 41 insertions(+), 18 deletions(-) create mode 100755 e2e/test_system diff --git a/e2e/test_system b/e2e/test_system new file mode 100755 index 000000000..6f6ac78d6 --- /dev/null +++ b/e2e/test_system @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +assert() { + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi +} + +system_node="$(which node)" +rtx_node="$(rtx which node)" + +assert "rtx x nodejs@system -- which node" "$system_node" +assert "rtx x nodejs -- which node" "$rtx_node" diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index 9c0d1f9f9..76eeda9df 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -114,7 +114,11 @@ impl RuntimeArg { self.plugin.clone(), ToolVersionType::Prefix(v.clone()), )), - _ => None, + RuntimeArgVersion::System => Some(ToolVersion::new( + self.plugin.clone(), + ToolVersionType::System, + )), + RuntimeArgVersion::None => None, } } } diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index ce32b08a9..6729fdb3e 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -42,13 +42,13 @@ impl ToolVersion { pub fn resolve(&mut self, config: &Config, plugin: Arc) -> Result<()> { if self.rtv.is_none() { - self.rtv = match &self.r#type { + self.rtv = Some(match &self.r#type { ToolVersionType::Version(v) => self.resolve_version(config, plugin, v)?, ToolVersionType::Prefix(v) => self.resolve_prefix(config, plugin, v)?, ToolVersionType::Ref(r) => self.resolve_ref(config, plugin, r)?, ToolVersionType::Path(path) => self.resolve_path(config, plugin, path)?, - ToolVersionType::System => None, - }; + ToolVersionType::System => self.resolve_system(config, plugin), + }); } Ok(()) } @@ -58,7 +58,7 @@ impl ToolVersion { config: &Config, plugin: Arc, v: &str, - ) -> Result> { + ) -> Result { let v = resolve_alias(config, plugin.clone(), v)?; match v.split_once(':') { Some(("ref", r)) => { @@ -76,13 +76,13 @@ impl ToolVersion { if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { // if the version is already installed, no need to fetch all of the remote versions let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - return Ok(Some(rtv)); + return Ok(rtv); } let matches = plugin.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - Ok(Some(rtv)) + Ok(rtv) } else { self.resolve_prefix(config, plugin, &v) } @@ -93,7 +93,7 @@ impl ToolVersion { config: &Config, plugin: Arc, prefix: &str, - ) -> Result> { + ) -> Result { let matches = plugin.list_versions_matching(&config.settings, prefix)?; let v = match matches.last() { Some(v) => v, @@ -101,17 +101,12 @@ impl ToolVersion { // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; let rtv = RuntimeVersion::new(config, plugin, v.to_string(), self.clone()); - Ok(Some(rtv)) + Ok(rtv) } - fn resolve_ref( - &self, - config: &Config, - plugin: Arc, - r: &str, - ) -> Result> { + fn resolve_ref(&self, config: &Config, plugin: Arc, r: &str) -> Result { let rtv = RuntimeVersion::new(config, plugin, format!("ref-{}", r), self.clone()); - Ok(Some(rtv)) + Ok(rtv) } fn resolve_path( @@ -119,14 +114,19 @@ impl ToolVersion { config: &Config, plugin: Arc, path: &PathBuf, - ) -> Result> { + ) -> Result { let path = fs::canonicalize(path)?; let rtv = RuntimeVersion::new(config, plugin, path.display().to_string(), self.clone()); - Ok(Some(rtv)) + Ok(rtv) + } + + pub fn resolve_system(&self, config: &Config, plugin: Arc) -> RuntimeVersion { + RuntimeVersion::new(config, plugin, "system".to_string(), self.clone()) } pub fn is_missing(&self) -> bool { match self.rtv { + Some(ref rtv) if rtv.version == "system" => false, Some(ref rtv) => !rtv.is_installed(), None => true, } From ff2a3d1c22aef3f0c0ef2fb7bd8abdce19e86471 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 10:12:19 -0600 Subject: [PATCH 0432/1891] chore: Release rtx-cli version 1.22.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c9de52d0..926e953c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.4" +version = "1.22.5" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 089ec5266..63382129b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.4" +version = "1.22.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index d8ee9b31a..62223519e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.4 +rtx 1.22.5 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.4/rtx-v1.22.4-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.5/rtx-v1.22.5-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 93625aae1..ff2c0df84 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.4"; + version = "1.22.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 875ef313a..b3a3baf80 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.4" +.TH rtx 1 "rtx 1.22.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -144,6 +144,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.4 +v1.22.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 7e9826b39..7caef3720 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.4 +Version: 1.22.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From f92435247100318a10779bfdf3911bc550891a41 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 10:15:41 -0600 Subject: [PATCH 0433/1891] chore: ensure snapshots are not published in crate --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 63382129b..bb6650e0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] -include = ["src/**/*", "/LICENSE", "/README.md", "/Cargo.lock"] +include = ["src/**/*.rs", "/LICENSE", "/README.md", "/Cargo.lock"] rust-version = "1.64.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 763d4ecdce86910e4e4a8652cccba90f8b57bdf6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 10:17:16 -0600 Subject: [PATCH 0434/1891] chore: run tests against main branch --- .github/workflows/rtx.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 3dd355d8c..ffdae5ceb 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -3,6 +3,7 @@ name: rtx on: push: tags: ["v*"] + branches: ["main"] pull_request: branches: ["main"] # Allows you to run this workflow manually from the Actions tab From 2b3881b95e731b813a479a920f18a9a4ba0d970c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 6 Mar 2023 13:50:11 -0600 Subject: [PATCH 0435/1891] chore: removed non-subtree tiny --- test/data/plugins/.gitignore | 1 - test/data/plugins/tiny/.gitignore | 1 - test/data/plugins/tiny/bin/exec-env | 6 ------ test/data/plugins/tiny/bin/install | 5 ----- test/data/plugins/tiny/bin/list-aliases | 6 ------ test/data/plugins/tiny/bin/list-all | 14 -------------- 6 files changed, 33 deletions(-) delete mode 100644 test/data/plugins/.gitignore delete mode 100644 test/data/plugins/tiny/.gitignore delete mode 100755 test/data/plugins/tiny/bin/exec-env delete mode 100755 test/data/plugins/tiny/bin/install delete mode 100755 test/data/plugins/tiny/bin/list-aliases delete mode 100755 test/data/plugins/tiny/bin/list-all diff --git a/test/data/plugins/.gitignore b/test/data/plugins/.gitignore deleted file mode 100644 index 72e8ffc0d..000000000 --- a/test/data/plugins/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/test/data/plugins/tiny/.gitignore b/test/data/plugins/tiny/.gitignore deleted file mode 100644 index 7ec8c9bd2..000000000 --- a/test/data/plugins/tiny/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.rtxcache* diff --git a/test/data/plugins/tiny/bin/exec-env b/test/data/plugins/tiny/bin/exec-env deleted file mode 100755 index 97d840ef5..000000000 --- a/test/data/plugins/tiny/bin/exec-env +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -eu -o pipefail - -JDXCODE_TINY="$(cat "$ASDF_INSTALL_PATH/VERSION")" -export JDXCODE_TINY diff --git a/test/data/plugins/tiny/bin/install b/test/data/plugins/tiny/bin/install deleted file mode 100755 index 4be77da71..000000000 --- a/test/data/plugins/tiny/bin/install +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -eu -o pipefail - -echo "$ASDF_INSTALL_VERSION" > "$ASDF_INSTALL_PATH/VERSION" diff --git a/test/data/plugins/tiny/bin/list-aliases b/test/data/plugins/tiny/bin/list-aliases deleted file mode 100755 index fb1a546b2..000000000 --- a/test/data/plugins/tiny/bin/list-aliases +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -eu -o pipefail - -echo "lts 3.1.0" -echo "lts-prev 2.0.0" diff --git a/test/data/plugins/tiny/bin/list-all b/test/data/plugins/tiny/bin/list-all deleted file mode 100755 index 62647c735..000000000 --- a/test/data/plugins/tiny/bin/list-all +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -eu -o pipefail - -echo 1.0.0 -echo 1.1.0 -echo 1.0.1 -echo 2.0.0 -echo 2.0.1 -echo 2.1.0 -echo 3.0.0 -echo 3.0.1 -echo 3.1.0 - From 4a88f1d4357740bffa83a19fd06b11561fac3420 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 7 Mar 2023 07:50:35 -0600 Subject: [PATCH 0436/1891] chore: show warning if failed to remove install dirs --- src/file.rs | 7 +++++++ src/runtimes.rs | 21 ++++++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/file.rs b/src/file.rs index c6a325092..1822ba75e 100644 --- a/src/file.rs +++ b/src/file.rs @@ -18,6 +18,13 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { Ok(()) } +pub fn remove_dir_all_with_warning>(path: P) -> io::Result<()> { + remove_dir_all(&path).map_err(|e| { + warn!("failed to remove {}: {}", path.as_ref().display(), e); + e + }) +} + pub fn create_dir_all>(path: P) -> io::Result<()> { let path = path.as_ref(); trace!("mkdir -p {}", path.display()); diff --git a/src/runtimes.rs b/src/runtimes.rs index 8f4839ac3..fa2f447e7 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -6,7 +6,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{fmt, fs}; -use color_eyre::eyre::{Result, WrapErr}; +use color_eyre::eyre::Result; use console::style; use once_cell::sync::Lazy; @@ -14,7 +14,7 @@ use crate::cache::CacheManager; use crate::config::Config; use crate::config::Settings; use crate::env_diff::{EnvDiff, EnvDiffOperation}; -use crate::file::{create_dir_all, display_path, remove_dir_all}; +use crate::file::{create_dir_all, display_path, remove_dir_all_with_warning}; use crate::hash::hash_to_str; use crate::lock_file::LockFile; use crate::plugins::Script::{Download, ExecEnv, Install}; @@ -190,12 +190,7 @@ impl RuntimeVersion { if dryrun { return Ok(()); } - remove_dir_all(dir).wrap_err_with(|| { - format!( - "Failed to remove directory {}", - style(dir.to_str().unwrap()).cyan().for_stderr() - ) - }) + remove_dir_all_with_warning(dir) }; rmdir(&self.install_path)?; rmdir(&self.download_path)?; @@ -243,9 +238,9 @@ impl RuntimeVersion { } fn create_install_dirs(&self) -> Result<()> { - let _ = remove_dir_all(&self.install_path); - let _ = remove_dir_all(&self.download_path); - let _ = remove_dir_all(&self.cache_path); + let _ = remove_dir_all_with_warning(&self.install_path); + let _ = remove_dir_all_with_warning(&self.download_path); + let _ = remove_dir_all_with_warning(&self.cache_path); create_dir_all(&self.install_path)?; create_dir_all(&self.download_path)?; create_dir_all(&self.cache_path)?; @@ -254,12 +249,12 @@ impl RuntimeVersion { } fn cleanup_install_dirs_on_error(&self, settings: &Settings) { - let _ = remove_dir_all(&self.install_path); + let _ = remove_dir_all_with_warning(&self.install_path); self.cleanup_install_dirs(settings); } fn cleanup_install_dirs(&self, settings: &Settings) { if !settings.always_keep_download { - let _ = remove_dir_all(&self.download_path); + let _ = remove_dir_all_with_warning(&self.download_path); } } From d36053eadd66c2723c25e39ed526cc5395c476f2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 7 Mar 2023 07:59:25 -0600 Subject: [PATCH 0437/1891] docs: clean up in-cli help (#281) these displayed way too long in the CLI help --- README.md | 6 ++++-- completions/_rtx | 38 +++++++++++------------------------ completions/rtx.fish | 32 +++++++++-------------------- man/man1/rtx.1 | 11 ++-------- src/cli/global.rs | 2 +- src/cli/local.rs | 2 +- src/cli/prune.rs | 1 + src/cli/self_update/github.rs | 1 + src/cli/self_update/other.rs | 1 + 9 files changed, 32 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 62223519e..a51659a55 100644 --- a/README.md +++ b/README.md @@ -1118,7 +1118,7 @@ Examples: ### `rtx global` ``` -Shows/sets the global runtime version(s) +Sets/gets the global runtime version(s) Displays the contents of ~/.tool-versions after writing. The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. @@ -1238,7 +1238,7 @@ Examples: ### `rtx local` ``` -Sets or gets tool versions in the local .tool-versions or .rtx.toml file +Sets/gets tool version in local .tool-versions or .rtx.toml Use this to set a tool's version when within a directory Use `rtx global` to set a runtime version globally @@ -1483,6 +1483,7 @@ Examples: ``` Delete unused versions of tools + rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files Versions which are no longer the latest specified in any of those configs are deleted. Versions installed only with environment variables (`RTX__VERSION`) will be deleted, @@ -1523,6 +1524,7 @@ Examples: ``` Updates rtx itself + Uses whatever package manager was used to install rtx or just downloads a binary from GitHub Releases if rtx was installed manually. Supports: standalone, brew, deb, rpm diff --git a/completions/_rtx b/completions/_rtx index ef65547d0..d13854419 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1009,8 +1009,8 @@ sets --jobs=1]' \ sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ -'-h[Print help]' \ -'--help[Print help]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ && ret=0 ;; (settings) @@ -1577,31 +1577,24 @@ _rtx_commands() { 'e:Exports env vars to activate rtx a single time' \ 'exec:Execute a command with runtime(s) set' \ 'x:Execute a command with runtime(s) set' \ -'global:Shows/sets the global runtime version(s)' \ -'g:Shows/sets the global runtime version(s)' \ +'global:Sets/gets the global runtime version(s)' \ +'g:Sets/gets the global runtime version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ 'install:Install a runtime' \ 'i:Install a runtime' \ 'latest:Gets the latest available version for a plugin' \ -'local:Sets or gets tool versions in the local .tool-versions or .rtx.toml file' \ -'l:Sets or gets tool versions in the local .tool-versions or .rtx.toml file' \ +'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ +'l:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed runtime versions' \ 'list:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ 'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ -'prune:Delete unused versions of tools -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`).' \ +'prune:Delete unused versions of tools' \ 'reshim:\[experimental\] rebuilds the shim farm' \ -'self-update:Updates rtx itself -Uses whatever package manager was used to install rtx or just downloads -a binary from GitHub Releases if rtx was installed manually. -Supports: standalone, brew, deb, rpm' \ +'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ 'uninstall:Removes runtime versions' \ @@ -1939,26 +1932,19 @@ _rtx__help_commands() { 'doctor:Check rtx installation for possible problems.' \ 'env:Exports env vars to activate rtx a single time' \ 'exec:Execute a command with runtime(s) set' \ -'global:Shows/sets the global runtime version(s)' \ +'global:Sets/gets the global runtime version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ 'install:Install a runtime' \ 'latest:Gets the latest available version for a plugin' \ -'local:Sets or gets tool versions in the local .tool-versions or .rtx.toml file' \ +'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ 'mangen:Generate man pages' \ 'plugins:Manage plugins' \ -'prune:Delete unused versions of tools -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`).' \ +'prune:Delete unused versions of tools' \ 'reshim:\[experimental\] rebuilds the shim farm' \ -'self-update:Updates rtx itself -Uses whatever package manager was used to install rtx or just downloads -a binary from GitHub Releases if rtx was installed manually. -Supports: standalone, brew, deb, rpm' \ +'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ 'uninstall:Removes runtime versions' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 763d880d5..36c7ac88a 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -19,26 +19,19 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv func complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'Exports env vars to activate rtx a single time' complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Shows/sets the global runtime version(s)' +complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets/gets the global runtime version(s)' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets or gets tool versions in the local .tool-versions or .rtx.toml file' +complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "mangen" -d 'Generate man pages' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`).' +complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself -Uses whatever package manager was used to install rtx or just downloads -a binary from GitHub Releases if rtx was installed manually. -Supports: standalone, brew, deb, rpm' +complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' @@ -437,7 +430,7 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r @@ -551,26 +544,19 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Shows/sets the global runtime version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets or gets tool versions in the local .tool-versions or .rtx.toml file' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`).' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself -Uses whatever package manager was used to install rtx or just downloads -a binary from GitHub Releases if rtx was installed manually. -Supports: standalone, brew, deb, rpm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index b3a3baf80..31df83f7c 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -71,7 +71,7 @@ rtx\-exec(1) Execute a command with runtime(s) set .TP rtx\-global(1) -Shows/sets the global runtime version(s) +Sets/gets the global runtime version(s) .TP rtx\-implode(1) Removes rtx CLI and all related data @@ -83,7 +83,7 @@ rtx\-latest(1) Gets the latest available version for a plugin .TP rtx\-local(1) -Sets or gets tool versions in the local .tool\-versions or .rtx.toml file +Sets/gets tool version in local .tool\-versions or .rtx.toml .TP rtx\-ls(1) List installed runtime versions @@ -96,19 +96,12 @@ Manage plugins .TP rtx\-prune(1) Delete unused versions of tools -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`). .TP rtx\-reshim(1) [experimental] rebuilds the shim farm .TP rtx\-self\-update(1) Updates rtx itself -Uses whatever package manager was used to install rtx or just downloads -a binary from GitHub Releases if rtx was installed manually. -Supports: standalone, brew, deb, rpm .TP rtx\-settings(1) Manage settings diff --git a/src/cli/global.rs b/src/cli/global.rs index b7aa4ebad..76d8c2a00 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -13,7 +13,7 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; -/// Shows/sets the global runtime version(s) +/// Sets/gets the global runtime version(s) /// /// Displays the contents of ~/.tool-versions after writing. /// The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. diff --git a/src/cli/local.rs b/src/cli/local.rs index 9f5014525..72aa42b1f 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -13,7 +13,7 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env, file}; -/// Sets or gets tool versions in the local .tool-versions or .rtx.toml file +/// Sets/gets tool version in local .tool-versions or .rtx.toml /// /// Use this to set a tool's version when within a directory /// Use `rtx global` to set a runtime version globally diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 3578a5e9b..d151da0ce 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -13,6 +13,7 @@ use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; /// Delete unused versions of tools +/// /// rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files /// Versions which are no longer the latest specified in any of those configs are deleted. /// Versions installed only with environment variables (`RTX__VERSION`) will be deleted, diff --git a/src/cli/self_update/github.rs b/src/cli/self_update/github.rs index 879349eba..d76f82cf8 100644 --- a/src/cli/self_update/github.rs +++ b/src/cli/self_update/github.rs @@ -11,6 +11,7 @@ use crate::env; use crate::output::Output; /// Updates rtx itself +/// /// Uses whatever package manager was used to install rtx or just downloads /// a binary from GitHub Releases if rtx was installed manually. /// Supports: standalone, brew, deb, rpm diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs index 11c1e9384..d55fa3e32 100644 --- a/src/cli/self_update/other.rs +++ b/src/cli/self_update/other.rs @@ -8,6 +8,7 @@ use crate::output::Output; use crate::{cmd, env}; /// Updates rtx itself +/// /// Uses whatever package manager was used to install rtx or just downloads /// a binary from GitHub Releases if rtx was installed manually. /// Supports: standalone, brew, deb, rpm From 5c405e90461b872c54a4c29f9da697d7b2ba4a7c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 7 Mar 2023 08:00:51 -0600 Subject: [PATCH 0438/1891] bug: fix issue with partial install when install directory is a symlink this can happen in the case of `rtx i nodejs@lts-hydrogen` --- src/runtimes.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index fa2f447e7..e04209579 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::env::split_paths; use std::fmt::{Display, Formatter}; -use std::fs::File; +use std::fs::{remove_file, File}; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{fmt, fs}; @@ -241,6 +241,7 @@ impl RuntimeVersion { let _ = remove_dir_all_with_warning(&self.install_path); let _ = remove_dir_all_with_warning(&self.download_path); let _ = remove_dir_all_with_warning(&self.cache_path); + let _ = remove_file(&self.install_path); // removes if it is a symlink create_dir_all(&self.install_path)?; create_dir_all(&self.download_path)?; create_dir_all(&self.cache_path)?; From 785ea147a4bd7ab56ef1a355f69a27ad8d3f18b8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 7 Mar 2023 23:11:52 -0600 Subject: [PATCH 0439/1891] chore: Release rtx-cli version 1.22.6 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 926e953c3..941fba1a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.5" +version = "1.22.6" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index bb6650e0b..81e0c3df5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.5" +version = "1.22.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a51659a55..1ee892d06 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.5 +rtx 1.22.6 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.5/rtx-v1.22.5-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.6/rtx-v1.22.6-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index ff2c0df84..eb7f91143 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.5"; + version = "1.22.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 31df83f7c..263195bf5 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.5" +.TH rtx 1 "rtx 1.22.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -137,6 +137,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.5 +v1.22.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 7caef3720..a7b20e162 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.5 +Version: 1.22.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 18cce74d21203fd914d5040a89ff4cbc6b48b3b7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 8 Mar 2023 06:47:01 -0600 Subject: [PATCH 0440/1891] docs: correct `rtx plugins install` syntax See #285 --- README.md | 8 ++++---- src/cli/plugins/install.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1ee892d06..0e78bb6f0 100644 --- a/README.md +++ b/README.md @@ -1384,17 +1384,17 @@ Options: Examples: # install the nodejs via shorthand - $ rtx install nodejs + $ rtx plugins install nodejs # install the nodejs plugin using a specific git url - $ rtx install nodejs https://github.com/jdxcode/rtx-nodejs.git + $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git # install the nodejs plugin using the git url only # (nodejs is inferred from the url) - $ rtx install https://github.com/jdxcode/rtx-nodejs.git + $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git # install the nodejs plugin using a specific ref - $ rtx install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 + $ rtx plugins install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 ``` ### `rtx plugins ls` diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 7dd39f906..d4106599a 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -168,17 +168,17 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} # install the nodejs via shorthand - $ rtx install nodejs + $ rtx plugins install nodejs # install the nodejs plugin using a specific git url - $ rtx install nodejs https://github.com/jdxcode/rtx-nodejs.git + $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git # install the nodejs plugin using the git url only # (nodejs is inferred from the url) - $ rtx install https://github.com/jdxcode/rtx-nodejs.git + $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git # install the nodejs plugin using a specific ref - $ rtx install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 + $ rtx plugins install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 "#, style("Examples:").bold().underlined()} }); From c675341f591b674305e545d4b9c778ebd755f8b9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 8 Mar 2023 06:46:30 -0600 Subject: [PATCH 0441/1891] chore: remove set -x from e2e test --- e2e/test_ls_remote | 2 +- e2e/test_system | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/test_ls_remote b/e2e/test_ls_remote index 1b7cf3da0..0fd3c34db 100755 --- a/e2e/test_ls_remote +++ b/e2e/test_ls_remote @@ -1,4 +1,4 @@ #!/usr/bin/env bash -set -euxo pipefail +set -euo pipefail rtx p list-remote | grep nodejs diff --git a/e2e/test_system b/e2e/test_system index 6f6ac78d6..23de89558 100755 --- a/e2e/test_system +++ b/e2e/test_system @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -euxo pipefail +set -euo pipefail assert() { actual="$($1)" From 8b5b09facef5c09f1b77111d348e90c242aa5c2f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 9 Mar 2023 09:47:25 -0600 Subject: [PATCH 0442/1891] bug: fix env var precedence Fixes #290 --- e2e/cd/.e2e.rtx.toml | 2 ++ e2e/cd/16/.e2e.rtx.toml | 2 ++ e2e/cd/test_bash | 12 ++++++++++++ src/config/mod.rs | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 e2e/cd/.e2e.rtx.toml create mode 100644 e2e/cd/16/.e2e.rtx.toml diff --git a/e2e/cd/.e2e.rtx.toml b/e2e/cd/.e2e.rtx.toml new file mode 100644 index 000000000..99f0244b5 --- /dev/null +++ b/e2e/cd/.e2e.rtx.toml @@ -0,0 +1,2 @@ +[env] +FOO = "cd" diff --git a/e2e/cd/16/.e2e.rtx.toml b/e2e/cd/16/.e2e.rtx.toml new file mode 100644 index 000000000..1907f4e2f --- /dev/null +++ b/e2e/cd/16/.e2e.rtx.toml @@ -0,0 +1,2 @@ +[env] +FOO = "16" diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 88676ad91..29a52ea34 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -7,6 +7,16 @@ orig_path="$PATH" # shellcheck disable=SC1090 eval "$(rtx activate bash --status)" && _rtx_hook +assert() { + local actual="$1" + local expected="$2" + if [[ "$actual" != "$expected" ]]; then + echo "actual: $actual" + echo "expected: $expected" + exit 1 + fi +} + assert_path() { local expected="${1//$HOME/\~}" local actual="${PATH/%$orig_path/}" @@ -21,10 +31,12 @@ assert_path() { test "$(node -v)" = "v18.0.0" assert_path "~/.rtx/installs/nodejs/18.0.0/bin:~/.rtx/installs/tiny/3.1.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert "$FOO" "cd" cd 16 && _rtx_hook test "$(node -v)" = "v16.0.0" assert_path "~/.rtx/installs/nodejs/16.0.0/bin:~/.rtx/installs/tiny/3.1.0/bin:~/.rtx/installs/shellcheck/0.9.0/bin:~/.rtx/installs/shfmt/3.6.0/bin" +assert "$FOO" "16" cd .. && _rtx_hook test "$(node -v)" = "v18.0.0" diff --git a/src/config/mod.rs b/src/config/mod.rs index 23fadd887..032222869 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -362,7 +362,7 @@ fn parse_config_file( fn load_env(config_files: &IndexMap>) -> IndexMap { let mut env = IndexMap::new(); - for cf in config_files.values() { + for cf in config_files.values().rev() { env.extend(cf.env()); } env From e9cde9da0999f8a13a41e0ad434130229fc6fd1b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Mar 2023 15:27:50 -0600 Subject: [PATCH 0443/1891] chore: lint against 1.68.0 --- src/cli/deactivate.rs | 4 ++-- src/cli/external.rs | 19 ++++++++----------- src/cli/reshim.rs | 4 ++-- src/cli/shell.rs | 4 ++-- src/config/mod.rs | 4 ++-- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index cc5b4821e..08d27fc6f 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -33,13 +33,13 @@ impl Command for Deactivate { } fn err_inactive() -> Result<()> { - return Err(eyre!(formatdoc!( + Err(eyre!(formatdoc!( r#" rtx is not activated in this shell session. Please run `{}` first in your shell rc file. "#, style("rtx activate").yellow() - ))); + ))) } static AFTER_LONG_HELP: Lazy = Lazy::new(|| { diff --git a/src/cli/external.rs b/src/cli/external.rs index 906abbc1a..06590cdfd 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -26,16 +26,14 @@ pub fn commands(config: &Config) -> Vec { .filter(|commands| !commands.is_empty()) .filter(|commands| commands[0][0] != "direnv") .map(|commands| { - clap::Command::new(commands[0][0].to_string()).subcommands(commands.into_iter().map( - |cmd| { - clap::Command::new(cmd[1..].join("-")).arg( - clap::Arg::new("args") - .num_args(1..) - .allow_hyphen_values(true) - .trailing_var_arg(true), - ) - }, - )) + Command::new(commands[0][0].to_string()).subcommands(commands.into_iter().map(|cmd| { + Command::new(cmd[1..].join("-")).arg( + clap::Arg::new("args") + .num_args(1..) + .allow_hyphen_values(true) + .trailing_var_arg(true), + ) + })) }) .collect() } @@ -52,7 +50,6 @@ pub fn execute( let args: Vec = matches .get_raw("args") .unwrap_or_default() - .into_iter() .map(|s| s.to_string_lossy().to_string()) .collect(); plugin.execute_external_command(subcommand, args)?; diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index c024e5e10..02c3d1313 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -34,13 +34,13 @@ impl Command for Reshim { } fn err_experimental() -> Result<()> { - return Err(eyre!(formatdoc!( + Err(eyre!(formatdoc!( r#" rtx is not configured to use experimental features. Please set the `{}` setting to `true`. "#, style("experimental").yellow() - ))); + ))) } static AFTER_LONG_HELP: Lazy = Lazy::new(|| { diff --git a/src/cli/shell.rs b/src/cli/shell.rs index f35d89027..202735dfa 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -60,13 +60,13 @@ impl Command for Shell { } fn err_inactive() -> Result<()> { - return Err(eyre!(formatdoc!( + Err(eyre!(formatdoc!( r#" rtx is not activated in this shell session. Please run `{}` first in your shell rc file. "#, style("rtx activate").yellow() - ))); + ))) } static AFTER_LONG_HELP: Lazy = Lazy::new(|| { diff --git a/src/config/mod.rs b/src/config/mod.rs index 032222869..3f261a115 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -393,13 +393,13 @@ fn err_load_settings(settings_path: &Path) -> Report { } fn err_no_shims_dir() -> Result { - return Err(eyre!(indoc::formatdoc!( + Err(eyre!(indoc::formatdoc!( r#" rtx is not configured to use shims. Please set the `{}` setting to a directory. "#, style("shims_dir").yellow() - ))); + ))) } fn track_config_files(config_filenames: &[PathBuf]) -> thread::JoinHandle<()> { From 29645d743b53d990db5cf00624da0dfc57ee908d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 10 Mar 2023 15:56:42 -0600 Subject: [PATCH 0444/1891] chore: Release rtx-cli version 1.22.7 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 4 +++- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 941fba1a9..ab4458bdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1392,7 +1392,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.6" +version = "1.22.7" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 81e0c3df5..80b8c8bc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.6" +version = "1.22.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0e78bb6f0..b535e05e2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.6 +rtx 1.22.7 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.6/rtx-v1.22.6-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.7/rtx-v1.22.7-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index eb7f91143..77dd0f142 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.6"; + version = "1.22.7"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 263195bf5..c70158ee1 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.6" +.TH rtx 1 "rtx 1.22.7" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -137,6 +137,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.6 +v1.22.7 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a7b20e162..11a3210cb 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.6 +Version: 1.22.7 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 5cce9bf4f..e274f15f4 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 616] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 618] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -19,6 +19,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 616] = [ ("ag", "https://github.com/koketani/asdf-ag.git"), ("age", "https://github.com/threkk/asdf-age"), ("agebox", "https://github.com/slok/asdf-agebox.git"), + ("air", "https://github.com/pdemagny/asdf-air"), ("aks-engine", "https://github.com/robsonpeixoto/asdf-aks-engine.git"), ("alias", "https://github.com/andrewthauer/asdf-alias.git"), ("allure", "https://github.com/comdotlinux/asdf-allure.git"), @@ -540,6 +541,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 616] = [ ("teleport-community", "https://github.com/MaloPolese/asdf-teleport-community"), ("teleport-ent", "https://github.com/highb/asdf-teleport-ent"), ("telepresence", "https://github.com/pirackr/asdf-telepresence.git"), + ("teller", "https://github.com/pdemagny/asdf-teller"), ("temporalite", "https://github.com/eko/asdf-temporalite.git"), ("terradozer", "https://github.com/chessmango/asdf-terradozer.git"), ("terraform", "https://github.com/asdf-community/asdf-hashicorp.git"), From 2b9879d2ce2e190651878b4e9954f8cb76b4def6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 13:06:10 -0600 Subject: [PATCH 0445/1891] test: fix part of disabled lua e2e test This does not make it not flaky, just makes it function at all --- e2e/test_lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e/test_lua b/e2e/test_lua index a06c3584f..0255708ca 100755 --- a/e2e/test_lua +++ b/e2e/test_lua @@ -5,10 +5,12 @@ exit 0 # TODO: fix this test, it's flaky set -gx RTX_MISSING_RUNTIME_BEHAVIOR autoinstall rtx activate --status fish | source +rtx hook-env | source rtx shell lua@5.4.3 -set -l actual (__rtx_env_eval 2>&1 && lua -v 2>&1) -set -l expected "rtx lua@5.4.3 shellcheck@0.9.0 shfmt@3.6.0 nodejs@18.0.0 Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio" +rtx hook-env | source +set -l actual (lua -v 2>&1) +set -l expected "Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio" if test "$actual" = "$expected" echo "OK" From fe9db362c940729029daa9a960bec2b2630f870c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 15:10:00 -0600 Subject: [PATCH 0446/1891] chore: removed codecov.yml did not seem to do actually anything --- codecov.yml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index 7da675ceb..000000000 --- a/codecov.yml +++ /dev/null @@ -1,6 +0,0 @@ -coverage: - status: - project: - default: - target: 80% - informational: true From f42b44ce7b280d7e7b96fc79464ee791ab132b23 Mon Sep 17 00:00:00 2001 From: issmo Date: Sat, 11 Mar 2023 23:22:27 +0100 Subject: [PATCH 0447/1891] bug: fix environment variables escaping (#288) (#295) * bug: fix environment variables escaping (#288) Fixes #288 * refactor * more test cases * chore: removed codecov.yml did not seem to do actually anything --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- src/env_diff.rs | 76 ++++++++++++++++++++++++++++++++++++------ test/fixtures/exec-env | 18 ++++++++++ 2 files changed, 83 insertions(+), 11 deletions(-) diff --git a/src/env_diff.rs b/src/env_diff.rs index 251e98058..be7ab76b6 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -98,16 +98,7 @@ impl EnvDiff { } } for (k, v) in additions.clone().iter() { - let v = if v.starts_with('"') && v.ends_with('"') { - v[1..v.len() - 1].to_string() - } else if v.starts_with("$'") && v.ends_with('\'') { - v[2..v.len() - 1].to_string() - } else { - v.to_string() - }; - let v = v.replace("\\'", "'"); - let v = v.replace("\\n", "\n"); - let v = v.replace("\\\\", "\\"); + let v = normalize_escape_sequences(v); if let Some(orig) = env.get(k) { if &v == orig { additions.remove(k); @@ -206,6 +197,53 @@ impl Debug for EnvDiff { } } +fn normalize_escape_sequences(input: &str) -> String { + let input = if input.starts_with('"') && input.ends_with('"') { + input[1..input.len() - 1].to_string() + } else if input.starts_with("$'") && input.ends_with('\'') { + input[2..input.len() - 1].to_string() + } else { + input.to_string() + }; + + let mut result = String::with_capacity(input.len()); + let mut chars = input.chars(); + + while let Some(c) = chars.next() { + if c == '\\' { + match chars.next() { + Some(val) => match val { + 'a' => result.push('\u{07}'), + 'b' => result.push('\u{08}'), + 'e' | 'E' => result.push('\u{1b}'), + 'f' => result.push('\u{0c}'), + 'n' => result.push('\n'), + 'r' => result.push('\r'), + 't' => result.push('\t'), + 'v' => result.push('\u{0b}'), + '\\' => result.push('\\'), + '\'' => result.push('\''), + '"' => result.push('"'), + '?' => result.push('?'), + '`' => result.push('`'), + '$' => result.push('$'), + _ => { + result.push('\\'); + result.push(val); + } + }, + None => { + error!("Invalid escape sequence"); + } + } + } else { + result.push(c) + } + } + + result +} + #[cfg(test)] mod tests { use indexmap::indexmap; @@ -283,10 +321,26 @@ mod tests { let path = dirs::HOME.join("fixtures/exec-env"); let orig = indexmap! { "UNMODIFIED_VAR" => "unmodified", - "UNMODIFIED_NEWLINE_VAR" => "hello\\\nworld", + "UNMODIFIED_NEWLINE_VAR" => "hello\\nworld", "UNMODIFIED_SQUOTE_VAR" => "hello\\'world", "UNMODIFIED_ESCAPE_VAR" => "hello\\world", "MODIFIED_VAR" => "original", + "ESCAPES" => "\\n\\t\\r\\v\\f\\a\\b\\e\\0\\x1b\\u1234\\U00012345\\a\\b\\e\\E\\f\\n\\r\\t\\v\"?`$\\g'\\0", + "BACKSPACE" => "\u{08}", + "BACKTICK" => "`", + "BELL" => "\u{07}", + "CARRIAGE_RETURN" => "\r", + "DOLLAR" => "$", + "DOUBLE_QUOTE" => "\"", + "ESCAPE" => "\u{1b}", + "ESCAPE2" => "\u{1b}", + "FORM_FEED" => "\u{0c}", + "G" => "g", + "NEWLINE" => "\n", + "QUESTION_MARK" => "?", + "SINGLE_QUOTE" => "'", + "TAB" => "\t", + "VERTICAL_TAB" => "\u{0b}", } .into_iter() .map(|(k, v)| (k.into(), v.into())) diff --git a/test/fixtures/exec-env b/test/fixtures/exec-env index b9106418c..e8e9a085f 100644 --- a/test/fixtures/exec-env +++ b/test/fixtures/exec-env @@ -9,3 +9,21 @@ export ADDED_VAR="added" export MULTILINE_VAR="line1 line2 line3" +export ESCAPES="\\n\\t\\r\\v\\f\\a\\b\\e\\0\\x1b\\u1234\\U00012345\a\b\e\E\f\n\r\t\v\"?\`\$\g'\0" +export BELL=$'\a' +export BACKSPACE=$'\b' +export ESCAPE=$'\e' +export ESCAPE2=$'\E' +export FORM_FEED=$'\f' +export NEWLINE=$'\n' +export CARRIAGE_RETURN=$'\r' +export TAB=$'\t' +export VERTICAL_TAB=$'\v' +export DOUBLE_QUOTE=$'"' +export SINGLE_QUOTE=$"'" +export QUESTION_MARK=$'?' +export BACKTICK=$'`' +export DOLLAR=$'$' +export G=$'g' + +unexported="unexported val" From 4c829434b4f739e919b349232055239452fb6e29 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 17:38:50 -0600 Subject: [PATCH 0448/1891] feat: added --parseable and --json to `rtx ls` (#297) --- Cargo.lock | 1 + Cargo.toml | 2 +- README.md | 39 +++- completions/_rtx | 2 + completions/rtx.bash | 2 +- completions/rtx.fish | 2 + src/cli/ls.rs | 169 ++++++++++++++++-- .../rtx__cli__ls__tests__ls_current.snap | 7 + .../rtx__cli__ls__tests__ls_json-2.snap | 15 ++ .../rtx__cli__ls__tests__ls_json.snap | 27 +++ .../rtx__cli__ls__tests__ls_parseable-2.snap | 6 + .../rtx__cli__ls__tests__ls_parseable.snap | 7 + src/toolset/tool_source.rs | 83 ++++++++- 13 files changed, 340 insertions(+), 22 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap diff --git a/Cargo.lock b/Cargo.lock index ab4458bdc..f7b7b0bdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,6 +797,7 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 80b8c8bc8..f1c8a193a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ flate2 = "1.0.25" fslock = "0.2.1" humantime = "2.1.0" indenter = "0.3.3" -indexmap = "1.9.2" +indexmap = { version = "1.9.2", features = ["serde"] } indicatif = { version = "0.17.3", features = ["default", "improved_unicode"] } indoc = "2.0.1" itertools = "0.10.5" diff --git a/README.md b/README.md index b535e05e2..22ce5aaa2 100644 --- a/README.md +++ b/README.md @@ -1308,15 +1308,42 @@ Options: -c, --current Only show runtimes currently specified in .tool-versions + --parseable + Output in an easily parseable format + + [short aliases: x] + + --json + Output in json format + Examples: - $ rtx list - -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - -> python 3.11.0 (set by ~/.tool-versions) + $ rtx ls + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) python 3.10.0 - $ rtx list --current - -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - -> python 3.11.0 (set by ~/.tool-versions) + $ rtx ls --current + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) + + $ rtx ls --parseable + nodejs 18.0.0 + python 3.11.0 + + $ rtx ls --json + { + "nodejs": [ + { + "version": "18.0.0", + "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", + "source": { + "type": ".rtx.toml", + "path": "/Users/jdx/.rtx.toml" + } + } + ], + "python": [...] + } ``` ### `rtx ls-remote` diff --git a/completions/_rtx b/completions/_rtx index d13854419..955cb0181 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -712,6 +712,8 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ +'--parseable[Output in an easily parseable format]' \ +'--json[Output in json format]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. sets --jobs=1]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 823c08f88..28bf942e2 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2165,7 +2165,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -j -r -v -h --plugin --current --install-missing --jobs --log-level --raw --verbose --help [PLUGIN_ARG]" + opts="-p -c -j -r -v -h --plugin --current --parseable --json --install-missing --jobs --log-level --raw --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 36c7ac88a..23dbcd279 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -312,6 +312,8 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of p default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in an easily parseable format' +complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' complete -c rtx -n "__fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. sets --jobs=1' diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 98d9d6acf..ad024ae2b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -1,17 +1,21 @@ use std::cmp::max; use std::collections::HashMap; +use std::path::PathBuf; use color_eyre::eyre::Result; use console::style; +use indexmap::IndexMap; use indoc::formatdoc; use itertools::Itertools; use once_cell::sync::Lazy; use owo_colors::OwoColorize; +use serde_derive::Serialize; use versions::Versioning; use crate::cli::command::Command; use crate::config::Config; use crate::env::DUMB_TERMINAL; +use crate::errors::Error::PluginNotInstalled; use crate::output::Output; use crate::plugins::PluginName; use crate::runtimes::RuntimeVersion; @@ -34,15 +38,108 @@ pub struct Ls { /// Only show runtimes currently specified in .tool-versions #[clap(long, short)] current: bool, + + /// Output in an easily parseable format + #[clap(long, visible_short_alias = 'x')] + parseable: bool, + + /// Output in json format + #[clap(long)] + json: bool, } impl Command for Ls { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let plugin = self.plugin.or(self.plugin_arg); - for (rtv, source) in get_runtime_list(&mut config, &plugin)? { - if self.current && source.is_none() { - continue; + fn run(mut self, mut config: Config, out: &mut Output) -> Result<()> { + self.plugin = self.plugin.clone().or(self.plugin_arg.clone()); + self.verify_plugin(&config)?; + + let mut runtimes = get_runtime_list(&mut config, &self.plugin)?; + if self.current { + runtimes.retain(|(_, source)| source.is_some()); + } + if self.json { + self.display_json(runtimes, out) + } else if self.parseable { + self.display_parseable(runtimes, out) + } else { + self.display_user(runtimes, out) + } + } +} + +type JSONOutput = IndexMap>; + +#[derive(Serialize)] +struct JSONRuntime { + version: String, + install_path: PathBuf, + source: Option>, +} + +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() { + return Err(PluginNotInstalled(plugin_name.clone()))?; + } } + None => {} + } + Ok(()) + } + + fn display_json( + &self, + runtimes: Vec<(RuntimeVersion, Option)>, + out: &mut Output, + ) -> Result<()> { + let mut plugins = JSONOutput::new(); + for (plugin_name, runtimes) in &runtimes + .into_iter() + .group_by(|(rtv, _)| rtv.plugin.name.clone()) + { + let runtimes = runtimes + .map(|(rtv, source)| JSONRuntime { + version: rtv.version, + install_path: rtv.install_path, + source: source.map(|source| source.as_json()), + }) + .collect(); + if self.plugin.is_some() { + // only display 1 plugin + out.stdout.writeln(serde_json::to_string_pretty(&runtimes)?); + return Ok(()); + } + plugins.insert(plugin_name, runtimes); + } + out.stdout.writeln(serde_json::to_string_pretty(&plugins)?); + Ok(()) + } + + fn display_parseable( + &self, + runtimes: Vec<(RuntimeVersion, Option)>, + out: &mut Output, + ) -> Result<()> { + for (rtv, _) in runtimes { + if self.plugin.is_some() { + // only displaying 1 plugin so only show the version + rtxprintln!(out, "{}", rtv.version); + } else { + rtxprintln!(out, "{} {}", rtv.plugin.name, rtv.version); + } + } + Ok(()) + } + + fn display_user( + &self, + runtimes: Vec<(RuntimeVersion, Option)>, + out: &mut Output, + ) -> Result<()> { + for (rtv, source) in runtimes { rtxprintln!( out, "{} {} {}", @@ -62,7 +159,6 @@ impl Command for Ls { }, ); } - Ok(()) } } @@ -146,21 +242,41 @@ fn get_runtime_list( static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx list - -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - -> python 3.11.0 (set by ~/.tool-versions) + $ rtx ls + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) python 3.10.0 - $ rtx list --current - -> nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - -> python 3.11.0 (set by ~/.tool-versions) + $ rtx ls --current + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) + + $ rtx ls --parseable + nodejs 18.0.0 + python 3.11.0 + + $ rtx ls --json + {{ + "nodejs": [ + {{ + "version": "18.0.0", + "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", + "source": {{ + "type": ".rtx.toml", + "path": "/Users/jdx/.rtx.toml" + }} + }} + ], + "python": [...] + }} "#, style("Examples:").bold().underlined()} }); #[cfg(test)] mod tests { use crate::file::remove_dir_all; - use crate::{assert_cli, assert_cli_snapshot, dirs}; + use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; + use pretty_assertions::assert_str_eq; #[test] fn test_ls() { @@ -180,4 +296,31 @@ mod tests { assert_cli!("install"); assert_cli_snapshot!("list"); } + + #[test] + fn test_ls_current() { + assert_cli_snapshot!("ls", "-c"); + } + + #[test] + fn test_ls_json() { + let _ = remove_dir_all(dirs::INSTALLS.as_path()); + assert_cli!("install"); + assert_cli_snapshot!("ls", "--json"); + assert_cli_snapshot!("ls", "--json", "tiny"); + } + + #[test] + fn test_ls_parseable() { + let _ = remove_dir_all(dirs::INSTALLS.as_path()); + assert_cli!("install"); + assert_cli_snapshot!("ls", "-x"); + assert_cli_snapshot!("ls", "--parseable", "tiny"); + } + + #[test] + fn test_ls_missing_plugin() { + let err = assert_cli_err!("ls", "missing-plugin"); + assert_str_eq!(err.to_string(), r#"[missing-plugin] plugin not installed"#); + } } diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap new file mode 100644 index 000000000..4a88870a3 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/ls.rs +expression: output +--- +-> dummy ref-master (set by ~/.test-tool-versions) +-> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap new file mode 100644 index 000000000..b34587b11 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap @@ -0,0 +1,15 @@ +--- +source: src/cli/ls.rs +expression: output +--- +[ + { + "version": "3.1.0", + "install_path": "~/data/installs/tiny/3.1.0", + "source": { + "type": ".tool-versions", + "path": "~/cwd/.test-tool-versions" + } + } +] + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap new file mode 100644 index 000000000..8da1162e2 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap @@ -0,0 +1,27 @@ +--- +source: src/cli/ls.rs +expression: output +--- +{ + "dummy": [ + { + "version": "ref-master", + "install_path": "~/data/installs/dummy/ref-master", + "source": { + "type": ".tool-versions", + "path": "~/.test-tool-versions" + } + } + ], + "tiny": [ + { + "version": "3.1.0", + "install_path": "~/data/installs/tiny/3.1.0", + "source": { + "type": ".tool-versions", + "path": "~/cwd/.test-tool-versions" + } + } + ] +} + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap new file mode 100644 index 000000000..014ad6e9e --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/ls.rs +expression: output +--- +3.1.0 + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap new file mode 100644 index 000000000..a88b0d8c2 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/ls.rs +expression: output +--- +dummy ref-master +tiny 3.1.0 + diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index 666bb04d6..8c5728e41 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -1,10 +1,13 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; +use indexmap::{indexmap, IndexMap}; +use serde_derive::Serialize; + use crate::file::display_path; /// where a tool version came from (e.g.: .tool-versions) -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize)] pub enum ToolSource { ToolVersions(PathBuf), RtxToml(PathBuf), @@ -25,6 +28,33 @@ impl Display for ToolSource { } } +impl ToolSource { + pub fn as_json(&self) -> IndexMap { + match self { + ToolSource::ToolVersions(path) => indexmap! { + "type".to_string() => ".tool-versions".to_string(), + "path".to_string() => path.to_string_lossy().to_string(), + }, + ToolSource::RtxToml(path) => indexmap! { + "type".to_string() => ".rtx.toml".to_string(), + "path".to_string() => path.to_string_lossy().to_string(), + }, + ToolSource::LegacyVersionFile(path) => indexmap! { + "type".to_string() => "legacy-version-file".to_string(), + "path".to_string() => path.to_string_lossy().to_string(), + }, + ToolSource::Argument => indexmap! { + "type".to_string() => "argument".to_string(), + }, + ToolSource::Environment(key, value) => indexmap! { + "type".to_string() => "environment".to_string(), + "key".to_string() => key.to_string(), + "value".to_string() => value.to_string(), + }, + } + } +} + #[cfg(test)] mod tests { use pretty_assertions::assert_str_eq; @@ -41,10 +71,61 @@ mod tests { let ts = ToolSource::RtxToml(PathBuf::from("/home/user/.rtx.toml")); assert_str_eq!(ts.to_string(), "/home/user/.rtx.toml"); + let ts = ToolSource::LegacyVersionFile(PathBuf::from("/home/user/.node-version")); + assert_str_eq!(ts.to_string(), "/home/user/.node-version"); + let ts = ToolSource::Argument; assert_str_eq!(ts.to_string(), "--runtime"); let ts = ToolSource::Environment("RTX_NODEJS_VERSION".to_string(), "18".to_string()); assert_str_eq!(ts.to_string(), "RTX_NODEJS_VERSION=18"); } + + #[test] + fn test_tool_source_as_json() { + let ts = ToolSource::ToolVersions(PathBuf::from("/home/user/.test-tool-versions")); + assert_eq!( + ts.as_json(), + indexmap! { + "type".to_string() => ".tool-versions".to_string(), + "path".to_string() => "/home/user/.test-tool-versions".to_string(), + } + ); + + let ts = ToolSource::RtxToml(PathBuf::from("/home/user/.rtx.toml")); + assert_eq!( + ts.as_json(), + indexmap! { + "type".to_string() => ".rtx.toml".to_string(), + "path".to_string() => "/home/user/.rtx.toml".to_string(), + } + ); + + let ts = ToolSource::LegacyVersionFile(PathBuf::from("/home/user/.node-version")); + assert_eq!( + ts.as_json(), + indexmap! { + "type".to_string() => "legacy-version-file".to_string(), + "path".to_string() => "/home/user/.node-version".to_string(), + } + ); + + let ts = ToolSource::Argument; + assert_eq!( + ts.as_json(), + indexmap! { + "type".to_string() => "argument".to_string(), + } + ); + + let ts = ToolSource::Environment("RTX_NODEJS_VERSION".to_string(), "18".to_string()); + assert_eq!( + ts.as_json(), + indexmap! { + "type".to_string() => "environment".to_string(), + "key".to_string() => "RTX_NODEJS_VERSION".to_string(), + "value".to_string() => "18".to_string(), + } + ); + } } From 5b07ee49a022dd893e6e9ea7527f722b26616da9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 18:00:22 -0600 Subject: [PATCH 0449/1891] bug: do not exit early in hook-env if any RTX_* env vars are modified (#298) --- e2e/test_shell | 18 +++++ src/cli/hook_env.rs | 3 +- src/cli/shell.rs | 4 - src/hook_env.rs | 180 ++++++++++++++++++++++++++++---------------- 4 files changed, 135 insertions(+), 70 deletions(-) create mode 100755 e2e/test_shell diff --git a/e2e/test_shell b/e2e/test_shell new file mode 100755 index 000000000..7975240d6 --- /dev/null +++ b/e2e/test_shell @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +assert() { + local actual + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +eval "$(rtx activate bash)" && eval "$(rtx hook-env)" +assert "node -v" "v18.0.0" +rtx shell nodejs@16.0.0 && eval "$(rtx hook-env)" +assert "node -v" "v16.0.0" +export RTX_NODEJS_VERSION=18.0.0 && eval "$(rtx hook-env)" +assert "node -v" "v18.0.0" diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 917dbca32..704843b0f 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -137,9 +137,10 @@ impl HookEnv { fn build_watch_operation(&self, config: &Config) -> Result { let config_filenames: Vec<_> = config.config_files.keys().cloned().collect(); + let watches = hook_env::build_watches(&config_filenames)?; Ok(EnvDiffOperation::Add( "__RTX_WATCH".into(), - hook_env::serialize_watches(&hook_env::build_watches(&config_filenames)?)?, + hook_env::serialize_watches(&watches)?, )) } } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 202735dfa..2f8f34c38 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -7,9 +7,6 @@ use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; -use crate::dirs; - -use crate::file::touch_dir; use crate::output::Output; use crate::shell::get_shell; @@ -53,7 +50,6 @@ impl Command for Shell { out.stdout.writeln(op); } } - touch_dir(&dirs::ROOT)?; Ok(()) } diff --git a/src/hook_env.rs b/src/hook_env.rs index cd214ecef..7bd85af31 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -1,4 +1,3 @@ -use std::collections::{HashMap, HashSet}; use std::io::prelude::*; use std::ops::Deref; use std::path::PathBuf; @@ -9,8 +8,12 @@ use color_eyre::eyre::Result; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; +use indexmap::{IndexMap, IndexSet}; +use itertools::Itertools; +use serde_derive::{Deserialize, Serialize}; use crate::env_diff::{EnvDiffOperation, EnvDiffPatches}; +use crate::hash::hash_to_str; use crate::shell::Shell; use crate::{dirs, env}; @@ -21,58 +24,75 @@ pub fn should_exit_early(config_filenames: &[PathBuf]) -> bool { return false; } let watch_files = get_watch_files(config_filenames); - if have_config_files_been_modified(&env::vars().collect(), watch_files) { - return false; - } + match env::var("__RTX_WATCH") { + Ok(raw) => { + match deserialize_watches(raw) { + Ok(watches) => { + if have_config_files_been_modified(&watches, watch_files) { + return false; + } + if have_rtx_env_vars_been_modified(&watches) { + return false; + } + } + Err(e) => { + debug!("error deserializing watches: {:?}", e); + return false; + } + }; + } + Err(_) => { + // __RTX_WATCH is not set + return false; + } + }; trace!("early-exit"); true } fn have_config_files_been_modified( - env: &HashMap, - watch_files: HashSet, + watches: &HookEnvWatches, + watch_files: IndexSet, ) -> bool { - match env.get("__RTX_WATCH") { - Some(prev) => { - let watches = match deserialize_watches(prev.to_string()) { - Ok(watches) => watches, - Err(e) => { - debug!("error deserializing watches: {:?}", e); - return true; - } - }; + // make sure they have exactly the same config filenames + let watch_keys = watches.files.keys().cloned().collect::>(); + if watch_keys != watch_files { + trace!( + "config files do not match {:?}", + watch_keys.symmetric_difference(&watch_files) + ); + return true; + } - // make sure they have exactly the same config filenames - let watch_keys = watches.keys().cloned().collect::>(); - if watch_keys != watch_files { - trace!( - "config files do not match {:?}", - watch_keys.symmetric_difference(&watch_files) - ); + // check the files to see if they've been altered + for (fp, prev_modtime) in &watches.files { + if let Ok(modtime) = fp + .metadata() + .expect("accessing config file modtime") + .modified() + { + if &modtime != prev_modtime { + trace!("config file modified: {:?}", fp); return true; } - - // check the files to see if they've been altered - for (fp, prev_modtime) in watches { - if let Ok(modtime) = fp - .metadata() - .expect("accessing config file modtime") - .modified() - { - if modtime != prev_modtime { - trace!("config file modified: {:?}", fp); - return true; - } - } - } - trace!("config files unmodified"); - false } - _ => true, // no previous watch data, we say they have been modified, so we don't exit early } + trace!("config files unmodified"); + false } -pub type HookEnvWatches = HashMap; +fn have_rtx_env_vars_been_modified(watches: &HookEnvWatches) -> bool { + if get_rtx_env_vars_hashed() != watches.env_var_hash { + return true; + } + false +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct HookEnvWatches { + files: IndexMap, + env_var_hash: String, +} pub fn serialize_watches(watches: &HookEnvWatches) -> Result { let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); @@ -90,16 +110,19 @@ pub fn deserialize_watches(raw: String) -> Result { } pub fn build_watches(config_filenames: &[PathBuf]) -> Result { - let mut watches = HookEnvWatches::new(); + let mut watches = IndexMap::new(); for cf in get_watch_files(config_filenames) { watches.insert(cf.clone(), cf.metadata()?.modified()?); } - Ok(watches) + Ok(HookEnvWatches { + files: watches, + env_var_hash: get_rtx_env_vars_hashed(), + }) } -pub fn get_watch_files(config_filenames: &[PathBuf]) -> HashSet { - let mut watches = HashSet::new(); +pub fn get_watch_files(config_filenames: &[PathBuf]) -> IndexSet { + let mut watches = IndexSet::new(); if dirs::ROOT.exists() { watches.insert(dirs::ROOT.clone()); } @@ -110,6 +133,17 @@ pub fn get_watch_files(config_filenames: &[PathBuf]) -> HashSet { watches } +/// gets a hash of all RTX_ environment variables +fn get_rtx_env_vars_hashed() -> String { + let env_vars: Vec<(&String, &String)> = env::PRISTINE_ENV + .deref() + .iter() + .filter(|(k, _)| k.starts_with("RTX_")) + .sorted() + .collect(); + hash_to_str(&env_vars) +} + pub fn clear_old_env(shell: &dyn Shell) -> String { let mut patches = env::__RTX_DIFF.reverse().to_patches(); if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { @@ -139,48 +173,64 @@ pub fn build_env_commands(shell: &dyn Shell, patches: &EnvDiffPatches) -> String mod tests { use std::time::UNIX_EPOCH; + use pretty_assertions::assert_str_eq; + use crate::dirs; use super::*; #[test] fn test_have_config_files_been_modified() { - let mut env = HashMap::new(); - let files = HashSet::new(); - assert!(have_config_files_been_modified(&env, files)); + let files = IndexSet::new(); + let watches = HookEnvWatches { + files: IndexMap::new(), + env_var_hash: "".into(), + }; + assert!(!have_config_files_been_modified(&watches, files)); let fp = dirs::CURRENT.join(".test-tool-versions"); - env.insert( - "__RTX_WATCH".into(), - serialize_watches(&HookEnvWatches::from([(fp.clone(), UNIX_EPOCH)])).unwrap(), - ); - let files = HashSet::from([fp.clone()]); - assert!(have_config_files_been_modified(&env, files)); + let watches = HookEnvWatches { + files: IndexMap::from([(fp.clone(), UNIX_EPOCH)]), + env_var_hash: "".into(), + }; + let files = IndexSet::from([fp.clone()]); + assert!(have_config_files_been_modified(&watches, files)); let modtime = fp.metadata().unwrap().modified().unwrap(); - env.insert( - "__RTX_WATCH".into(), - serialize_watches(&HookEnvWatches::from([(fp.clone(), modtime)])).unwrap(), - ); - let files = HashSet::from([fp]); - assert!(!have_config_files_been_modified(&env, files)); + let watches = HookEnvWatches { + files: IndexMap::from([(fp.clone(), modtime)]), + env_var_hash: "".into(), + }; + let files = IndexSet::from([fp]); + assert!(!have_config_files_been_modified(&watches, files)); } #[test] fn test_serialize_watches_empty() { - let serialized = serialize_watches(&HookEnvWatches::new()).unwrap(); + let watches = HookEnvWatches { + files: IndexMap::new(), + env_var_hash: "".into(), + }; + let serialized = serialize_watches(&watches).unwrap(); let deserialized = deserialize_watches(serialized).unwrap(); - assert_eq!(deserialized.len(), 0); + assert_eq!(deserialized.files.len(), 0); } #[test] fn test_serialize_watches() { - let serialized = - serialize_watches(&HookEnvWatches::from([("foo".into(), UNIX_EPOCH)])).unwrap(); + let serialized = serialize_watches(&HookEnvWatches { + files: IndexMap::from([("foo".into(), UNIX_EPOCH)]), + env_var_hash: "testing-123".into(), + }) + .unwrap(); let deserialized = deserialize_watches(serialized).unwrap(); - assert_eq!(deserialized.len(), 1); + assert_eq!(deserialized.files.len(), 1); + assert_str_eq!(deserialized.env_var_hash, "testing-123"); assert_eq!( - deserialized.get(PathBuf::from("foo").as_path()).unwrap(), + deserialized + .files + .get(PathBuf::from("foo").as_path()) + .unwrap(), &UNIX_EPOCH ); } From 54eef432bdc7580559d5c56b309815bd3db8986c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 18:04:26 -0600 Subject: [PATCH 0450/1891] bug: fix automatic plugin install on `rtx i nodejs@latest` (#299) --- src/cli/install.rs | 19 ++++++++----------- src/plugins/mod.rs | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/cli/install.rs b/src/cli/install.rs index 5ad335716..2f504cf69 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -102,18 +102,15 @@ impl Install { for mut tv in tool_versions { let plugin = match config.plugins.get(&tv.plugin_name).cloned() { Some(plugin) => plugin, - None => { - let plugin = Plugin::new(&tv.plugin_name); - let mut pr = mpr.add(); - match plugin.install(&config, &mut pr, false) { - Ok(_) => Arc::new(plugin), - Err(err) => { - pr.error(); - return Err(err)?; - } - } - } + None => Arc::new(Plugin::new(&tv.plugin_name)), }; + if !plugin.is_installed() { + let mut pr = mpr.add(); + if let Err(err) = plugin.install(&config, &mut pr, false) { + pr.error(); + return Err(err)?; + } + } tv.resolve(&config, plugin)?; versions.push(tv.rtv.unwrap()); } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index d2b63d3b7..09cb813dd 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -332,7 +332,7 @@ impl Plugin { .run() .with_context(|| { let script = self.script_man.get_script_path(&Script::ListAll); - format!("failed to run {}", script.display()) + format!("Failed to run {}", script.display()) })?; let stdout = String::from_utf8(result.stdout).unwrap(); let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); From 9cefc2ba9f38e4d7820969f21100c3350e5dc069 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 18:04:36 -0600 Subject: [PATCH 0451/1891] chore: use rtx-nodejs instead of asdf-nodejs (#300) Fixes #287 --- scripts/update-shorthand-repo.sh | 5 +++-- src/default_shorthands.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index e7320a420..6121793ca 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -6,7 +6,7 @@ git clone --depth 1 https://github.com/asdf-vm/asdf-plugins rm -f src/default_shorthands.rs num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') -num_plugins=$((num_plugins + 4)) # + for custom aliases (node, tiny, etc) +num_plugins=$((num_plugins + 5)) # + for custom aliases (node, tiny, etc) cat >src/default_shorthands.rs <>src/default_shorthands.rs <> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 618] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 619] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -626,7 +626,8 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 618] = [ ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), // rtx custom shorthands ("go", "https://github.com/kennyp/asdf-golang.git"), - ("node", "https://github.com/asdf-vm/asdf-nodejs.git"), + ("node", "https://github.com/jdxcode/rtx-nodejs.git"), + ("nodejs", "https://github.com/jdxcode/rtx-nodejs.git"), ("python", "https://github.com/jdxcode/rtx-python.git"), ("tiny", "https://github.com/jdxcode/rtx-tiny.git"), ]; From 77ffdf2e352b2c86c7e719782fb54cd781d2bd94 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 19:05:12 -0600 Subject: [PATCH 0452/1891] feat: support bin/latest-stable (#301) Fixes #21 --- README.md | 5 +-- e2e/test_zigmod | 15 +++++++ src/cli/install.rs | 5 +-- src/cli/latest.rs | 9 ++-- src/plugins/mod.rs | 83 +++++++++++++++++++++++++++++++---- src/plugins/script_manager.rs | 8 ++-- src/toolset/tool_version.rs | 7 +++ 7 files changed, 108 insertions(+), 24 deletions(-) create mode 100755 e2e/test_zigmod diff --git a/README.md b/README.md index 22ce5aaa2..bb0c4114c 100644 --- a/README.md +++ b/README.md @@ -1213,9 +1213,8 @@ Options: Examples: $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version - $ rtx install nodejs # install version specified in .tool-versions - $ rtx install # installs all runtimes specified in .tool-versions for installed plugins - $ rtx install --all # installs all runtimes and all plugins + $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml + $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml ``` ### `rtx latest` diff --git a/e2e/test_zigmod b/e2e/test_zigmod new file mode 100755 index 000000000..ee35694be --- /dev/null +++ b/e2e/test_zigmod @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail + +assert() { + local actual + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +eval "$(rtx activate bash)" && eval "$(rtx hook-env)" +rtx plugin install https://github.com/kachick/asdf-zigmod +rtx x --install-missing zigmod@latest -- zigmod version diff --git a/src/cli/install.rs b/src/cli/install.rs index 2f504cf69..93d38b331 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -199,9 +199,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { {} $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version - $ rtx install nodejs # install version specified in .tool-versions - $ rtx install # installs all runtimes specified in .tool-versions for installed plugins - $ rtx install --all # installs all runtimes and all plugins + $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml + $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml "#, style("Examples:").bold().underlined()} }); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 8b890baf3..3de5688e7 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -26,11 +26,8 @@ pub struct Latest { impl Command for Latest { fn run(self, config: Config, out: &mut Output) -> Result<()> { let prefix = match self.runtime.version { - RuntimeArgVersion::None => match self.asdf_version { - Some(version) => version, - None => "latest".to_string(), - }, - RuntimeArgVersion::Version(version) => version, + RuntimeArgVersion::None => self.asdf_version, + RuntimeArgVersion::Version(version) => Some(version), _ => Err(eyre!( "invalid version: {}", style(&self.runtime).cyan().for_stderr() @@ -47,7 +44,7 @@ impl Command for Latest { })?; plugin.clear_remote_version_cache()?; - if let Some(version) = plugin.latest_version(&config.settings, &prefix)? { + if let Some(version) = plugin.latest_version(&config.settings, prefix)? { rtxprintln!(out, "{}", version); } Ok(()) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 09cb813dd..052eee476 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -42,6 +42,7 @@ pub struct Plugin { installs_path: PathBuf, script_man: ScriptManager, remote_version_cache: CacheManager>, + latest_stable_cache: CacheManager>, alias_cache: CacheManager>, legacy_filename_cache: CacheManager>, } @@ -64,6 +65,10 @@ impl Plugin { .with_fresh_duration(fresh_duration) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-all")), + latest_stable_cache: CacheManager::new(cache_path.join("latest_stable.msgpack.z")) + .with_fresh_duration(fresh_duration) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/latest-stable")), alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.z")) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-aliases")), @@ -186,13 +191,30 @@ impl Plugin { Ok(()) } - pub fn latest_version(&self, settings: &Settings, query: &str) -> Result> { - let matches = self.list_versions_matching(settings, query)?; - let v = match matches.contains(&query.to_string()) { - true => Some(query.to_string()), - false => matches.last().map(|v| v.to_string()), - }; - Ok(v) + pub fn latest_version( + &self, + settings: &Settings, + query: Option, + ) -> Result> { + match query { + Some(query) => { + let matches = self.list_versions_matching(settings, &query)?; + let v = match matches.contains(&query) { + true => Some(query), + false => matches.last().map(|v| v.to_string()), + }; + Ok(v) + } + None => self.latest_stable_version(settings), + } + } + + fn latest_stable_version(&self, settings: &Settings) -> Result> { + if let Some(latest) = self.get_latest_stable(settings)? { + Ok(Some(latest)) + } else { + self.latest_version(settings, Some("latest".into())) + } } pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { @@ -228,7 +250,8 @@ impl Plugin { } pub fn clear_remote_version_cache(&self) -> Result<()> { - self.remote_version_cache.clear() + self.remote_version_cache.clear()?; + self.latest_stable_cache.clear() } pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { self.remote_version_cache @@ -272,6 +295,20 @@ impl Plugin { }) .cloned() } + fn get_latest_stable(&self, settings: &Settings) -> Result> { + if !self.has_latest_stable_script() { + return Ok(None); + } + self.latest_stable_cache + .get_or_try_init(|| self.fetch_latest_stable(settings)) + .with_context(|| { + format!( + "Failed fetching latest stable version for plugin {}", + style(&self.name).cyan().for_stderr() + ) + }) + .cloned() + } pub fn external_commands(&self) -> Result>> { let command_path = self.plugin_path.join("lib/commands"); @@ -364,6 +401,18 @@ impl Plugin { .map(|v| v.into()) .collect()) } + fn fetch_latest_stable(&self, settings: &Settings) -> Result> { + let latest_stable = self + .script_man + .read(settings, &Script::LatestStable, settings.verbose)? + .trim() + .to_string(); + Ok(if latest_stable.is_empty() { + None + } else { + Some(latest_stable) + }) + } fn has_list_all_script(&self) -> bool { self.script_man.script_exists(&Script::ListAll) @@ -374,6 +423,9 @@ impl Plugin { fn has_list_legacy_filenames_script(&self) -> bool { self.script_man.script_exists(&Script::ListLegacyFilenames) } + fn has_latest_stable_script(&self) -> bool { + self.script_man.script_exists(&Script::LatestStable) + } fn fetch_aliases(&self, settings: &Settings) -> Result> { let stdout = self .script_man @@ -469,7 +521,20 @@ mod tests { assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); let plugin = Plugin::new(&PluginName::from("tiny")); - let version = plugin.latest_version(&settings, "1.0.0").unwrap().unwrap(); + let version = plugin + .latest_version(&settings, Some("1.0.0".into())) + .unwrap() + .unwrap(); assert_str_eq!(version, "1.0.0"); + let version = plugin.latest_version(&settings, None).unwrap().unwrap(); + assert_str_eq!(version, "3.1.0"); + } + + #[test] + fn test_latest_stable() { + let settings = Settings::default(); + let plugin = Plugin::new(&PluginName::from("dummy")); + let version = plugin.latest_version(&settings, None).unwrap().unwrap(); + assert_str_eq!(version, "2.0.0"); } } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 053d76946..46c4ed327 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -31,23 +31,25 @@ pub enum Script { // PostUninstall, // Plugin + LatestStable, + ListAliases, ListAll, ListLegacyFilenames, - ListAliases, ParseLegacyFile(String), // RuntimeVersion Download, + ExecEnv, Install, - Uninstall, ListBinPaths, - ExecEnv, + Uninstall, } impl Display for Script { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { // Plugin + Script::LatestStable => write!(f, "latest-stable"), Script::ListAll => write!(f, "list-all"), Script::ListLegacyFilenames => write!(f, "list-legacy-filenames"), Script::ListAliases => write!(f, "list-aliases"), diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 6729fdb3e..61b8354ab 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -79,6 +79,13 @@ impl ToolVersion { return Ok(rtv); } + if v == "latest" { + let v = plugin.latest_version(&config.settings, None)?; + if let Some(v) = v { + let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); + return Ok(rtv); + } + } let matches = plugin.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); From 386ac6f83e47a63997e1b558ebc558b4a08ddb5a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 19:12:32 -0600 Subject: [PATCH 0453/1891] display better error message when shim has no active version (#302) Fixes #282 --- src/shims.rs | 15 +++++++++++++++ src/toolset/mod.rs | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/shims.rs b/src/shims.rs index 26efdeb73..1c3a896f8 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -16,6 +16,7 @@ use crate::fake_asdf; use crate::file::{create_dir_all, remove_dir_all}; use crate::lock_file::LockFile; use crate::output::Output; +use crate::runtimes::RuntimeVersion; use crate::toolset::{Toolset, ToolsetBuilder}; use crate::{dirs, file}; @@ -58,6 +59,8 @@ fn which_shim(config: &mut Config, bin_name: &str) -> Result { return Ok(bin); } } + let rtvs = ts.list_rtvs_with_bin(config, bin_name)?; + err_no_version_set(bin_name, rtvs)?; } } Err(eyre!("{} is not a valid shim", bin_name)) @@ -156,3 +159,15 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { ); Ok(()) } + +fn err_no_version_set(bin_name: &str, rtvs: Vec) -> Result<()> { + if rtvs.is_empty() { + return Ok(()); + } + let mut msg = format!("No version is set for shim: {}\n", bin_name); + msg.push_str("Set a global default version with one of the following:\n"); + for rtv in rtvs { + msg.push_str(&format!("rtx global {}@{}\n", rtv.plugin.name, rtv.version)); + } + Err(eyre!(msg.trim().to_string())) +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index a723a2aca..64f53b736 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -367,6 +367,24 @@ impl Toolset { } }) } + + pub fn list_rtvs_with_bin( + &self, + config: &Config, + bin_name: &str, + ) -> Result> { + Ok(self + .list_installed_versions(config)? + .into_par_iter() + .filter(|v| match v.which(&config.settings, bin_name) { + Ok(x) => x.is_some(), + Err(e) => { + warn!("Error running which: {:#}", e); + false + } + }) + .collect()) + } } impl Display for Toolset { From 65bcdfe5784d0be7f86fe8f9d4750ed57384adec Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 19:54:04 -0600 Subject: [PATCH 0454/1891] feat: added new syntax for subtracting versions, e.g.: `nodejs@18!-2` to install node-16.x (#303) --- .rtx.toml | 2 +- e2e/test_bang | 13 +++++++++++++ src/toolset/tool_version.rs | 37 ++++++++++++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100755 e2e/test_bang diff --git a/.rtx.toml b/.rtx.toml index 2666eca06..67241ef0e 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -2,7 +2,7 @@ FOO = "bar" [tools] -nodejs = '18' +nodejs = 'lts' tiny = {version="1", foo="bar"} golang = {version="latest", foo="bar"} python = {version="latest", virtualenv="$HOME/.cache/venv"} diff --git a/e2e/test_bang b/e2e/test_bang new file mode 100755 index 000000000..385c13193 --- /dev/null +++ b/e2e/test_bang @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +assert() { + local actual + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +assert "rtx x nodejs@18.0.0!-2 -- node -v" "v16.0.0" diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 61b8354ab..21206e10c 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; use indexmap::IndexMap; +use versions::{Chunk, Version}; use crate::config::Config; use crate::dirs; @@ -89,9 +90,39 @@ impl ToolVersion { let matches = plugin.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - Ok(rtv) - } else { - self.resolve_prefix(config, plugin, &v) + return Ok(rtv); + } + if v.contains("!-") { + if let Some(rtv) = self.resolve_bang(config, plugin.clone(), &v)? { + return Ok(rtv); + } + } + self.resolve_prefix(config, plugin, &v) + } + + /// resolve a version like `12.0.0!-1` which becomes `11.0.0`, `12.1.0!-0.1` becomes `12.0.0` + fn resolve_bang( + &self, + config: &Config, + plugin: Arc, + v: &str, + ) -> Result> { + let (wanted, minus) = v.split_once("!-").unwrap(); + let wanted = resolve_alias(config, plugin.clone(), wanted)?; + let mut wanted = Version::new(&wanted).unwrap(); + for (i, m) in Version::new(minus).unwrap().chunks.0.iter().enumerate() { + let orig = match wanted.nth(i) { + Some(c) => c, + None => { + warn!("cannot subtract {minus} from {wanted}"); + return Ok(None); + } + }; + wanted.chunks.0[i] = Chunk::Numeric(orig - m.single_digit().unwrap()); + } + match plugin.latest_version(&config.settings, Some(wanted.to_string()))? { + Some(v) => Ok(RuntimeVersion::new(config, plugin, v, self.clone()).into()), + None => Ok(None), } } From acea52daa4501d44a284fbd9f95778544a0df19e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 20:15:42 -0600 Subject: [PATCH 0455/1891] added plugin url + sha to `rtx doctor` output (#304) Fixes #237 --- src/cli/doctor.rs | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 5afafb543..544bac11a 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -1,5 +1,5 @@ use color_eyre::eyre::Result; -use console::style; +use console::{pad_str, style, Alignment}; use indenter::indented; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -10,6 +10,7 @@ use crate::cli::command::Command; use crate::cli::version::VERSION; use crate::config::Config; use crate::env; +use crate::git::Git; use crate::{cli, cmd}; use crate::output::Output; @@ -27,18 +28,14 @@ impl Command for Doctor { rtxprintln!(out, "{}", rtx_version()); rtxprintln!(out, "{}", shell()); rtxprintln!(out, "{}", rtx_env_vars()); - rtxprintln!( - out, - "{}\n{}\n", - style("config:").bold(), - indent(config.to_string()) - ); rtxprintln!( out, "{}\n{}\n", style("settings:").bold(), indent(config.settings.to_string()) ); + rtxprintln!(out, "{}", render_config_files(&config)); + rtxprintln!(out, "{}", render_plugins(&config)); rtxprintln!( out, "{}\n{}\n", @@ -99,6 +96,39 @@ fn rtx_env_vars() -> String { s } +fn render_config_files(config: &Config) -> String { + let mut s = style("config files:\n").bold().to_string(); + for f in config.config_files.keys().rev() { + s.push_str(&format!(" {}\n", f.display())); + } + s +} + +fn render_plugins(config: &Config) -> String { + let mut s = style("plugins:\n").bold().to_string(); + let max_plugin_name_len = config + .plugins + .values() + .map(|p| p.name.len()) + .max() + .unwrap_or(0); + for p in config.plugins.values() { + let padded_name = pad_str(&p.name, max_plugin_name_len, Alignment::Left, None); + let git = Git::new(p.plugin_path.clone()); + let si = match git.get_remote_url() { + Some(url) => { + let sha = git + .current_sha_short() + .unwrap_or_else(|_| "(unknown)".to_string()); + format!(" {padded_name} {url}#{sha}\n") + } + None => format!(" {padded_name}\n"), + }; + s.push_str(&si); + } + s +} + fn rtx_version() -> String { let mut s = style("rtx version:\n").bold().to_string(); s.push_str(&format!(" {}\n", *VERSION)); From 68b4df2f9c708a6776f2895fef4fb870b2d228d5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 20:17:09 -0600 Subject: [PATCH 0456/1891] chore: Release rtx-cli version 1.23.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7b7b0bdc..b9654ba7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1393,7 +1393,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.22.7" +version = "1.23.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index f1c8a193a..bbf14e011 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.22.7" +version = "1.23.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index bb0c4114c..4b88ec0af 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.22.7 +rtx 1.23.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.22.7/rtx-v1.22.7-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.0/rtx-v1.23.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 77dd0f142..81a8ceefb 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.22.7"; + version = "1.23.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c70158ee1..d612587d0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.22.7" +.TH rtx 1 "rtx 1.23.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -137,6 +137,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.22.7 +v1.23.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 11a3210cb..988616c11 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.22.7 +Version: 1.23.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 4229d573c1188aecd850c9e6d987200282451a68 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 20:45:07 -0600 Subject: [PATCH 0457/1891] docs: document bang syntax --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4b88ec0af..5939b13dc 100644 --- a/README.md +++ b/README.md @@ -490,6 +490,9 @@ 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 shfmt path:./shfmt # use a custom runtime +nodejs lts # use lts version of nodejs (not supported by all plugins) +nodejs lts!-2 # install 2 versions behind the latest lts (e.g.: 16 if lts is 18) +python 3.11!-0.1 # another way to specify 3.10 (generally more useful with aliases) ``` Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local) to create them automatically. From 32071274bede767e5f8342006b01e4a130a054c1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 20:46:13 -0600 Subject: [PATCH 0458/1891] docs: document bang syntax --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5939b13dc..1b9f9eb35 100644 --- a/README.md +++ b/README.md @@ -492,7 +492,7 @@ golang prefix:1.19 # uses the latest 1.19.x version—needed in case "1.19 shfmt path:./shfmt # use a custom runtime nodejs lts # use lts version of nodejs (not supported by all plugins) nodejs lts!-2 # install 2 versions behind the latest lts (e.g.: 16 if lts is 18) -python 3.11!-0.1 # another way to specify 3.10 (generally more useful with aliases) +python latest!-0.1 # install python-3.10 if the latest is 3.11 ``` Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local) to create them automatically. From c7367a62b079d78254f38a32a628a23b52498855 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 20:47:24 -0600 Subject: [PATCH 0459/1891] bug: prevent using --json with --parseable --- completions/_rtx | 2 +- src/cli/ls.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index 955cb0181..596582575 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -712,7 +712,7 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show runtimes currently specified in .tool-versions]' \ '--current[Only show runtimes currently specified in .tool-versions]' \ -'--parseable[Output in an easily parseable format]' \ +'(--json)--parseable[Output in an easily parseable format]' \ '--json[Output in json format]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. diff --git a/src/cli/ls.rs b/src/cli/ls.rs index ad024ae2b..82bb1b8e4 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -40,7 +40,7 @@ pub struct Ls { current: bool, /// Output in an easily parseable format - #[clap(long, visible_short_alias = 'x')] + #[clap(long, visible_short_alias = 'x', conflicts_with = "json")] parseable: bool, /// Output in json format From aaac54db625cee248f5423c2e79007407de4c91b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 21:56:55 -0600 Subject: [PATCH 0460/1891] feat: initial autoupdating support (#305) --- src/cli/exec.rs | 1 + src/cli/global.rs | 1 + src/cli/install.rs | 1 + src/cli/local.rs | 1 + src/cli/shell.rs | 1 + src/config/mod.rs | 63 ++++++++++++++++++++++++++++++++++++++- src/plugins/mod.rs | 18 ++++++++++- src/ui/progress_report.rs | 6 ++++ 8 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index deb70dcf8..afc76f5bd 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -46,6 +46,7 @@ pub struct Exec { impl Command for Exec { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + config.autoupdate(); let ts = ToolsetBuilder::new() .with_args(&self.runtime) .with_install_missing() diff --git a/src/cli/global.rs b/src/cli/global.rs index 76d8c2a00..afc407950 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -54,6 +54,7 @@ pub struct Global { impl Command for Global { fn run(self, config: Config, out: &mut Output) -> Result<()> { + config.autoupdate(); local( config, out, diff --git a/src/cli/install.rs b/src/cli/install.rs index 93d38b331..5ac83023e 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -56,6 +56,7 @@ pub struct Install { impl Command for Install { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { config.settings.missing_runtime_behavior = AutoInstall; + config.autoupdate(); match &self.runtime { Some(runtime) => self.install_runtimes(config, runtime)?, diff --git a/src/cli/local.rs b/src/cli/local.rs index 72aa42b1f..213bfdf3f 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -56,6 +56,7 @@ pub struct Local { impl Command for Local { fn run(self, config: Config, out: &mut Output) -> Result<()> { + config.autoupdate(); let path = if self.parent { get_parent_path()? } else { diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 2f8f34c38..288d4c857 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -29,6 +29,7 @@ pub struct Shell { impl Command for Shell { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + config.autoupdate(); let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.runtime) diff --git a/src/config/mod.rs b/src/config/mod.rs index 3f261a115..7b07885d5 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -11,6 +11,7 @@ use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::OnceCell; use rayon::prelude::*; +use rayon::ThreadPoolBuilder; pub use settings::{MissingRuntimeBehavior, Settings}; @@ -21,7 +22,8 @@ use crate::config::settings::SettingsBuilder; use crate::config::tracking::Tracker; use crate::plugins::{Plugin, PluginName}; use crate::shorthands::{get_shorthands, Shorthands}; -use crate::{dirs, env, file, hook_env}; +use crate::ui::multi_progress_report::MultiProgressReport; +use crate::{cli, dirs, env, file, hook_env}; pub mod config_file; mod settings; @@ -203,6 +205,65 @@ impl Config { } None } + + pub fn autoupdate(&self) { + self.check_for_new_version(); + let thread_pool = match ThreadPoolBuilder::new() + .num_threads(self.settings.jobs) + .build() + { + Ok(thread_pool) => thread_pool, + Err(err) => { + warn!("Error building thread pool: {:#}", err); + return; + } + }; + if let Err(err) = thread_pool.install(|| -> Result<()> { + let plugins: Vec> = self + .plugins + .values() + .collect_vec() + .into_par_iter() + .filter(|p| match p.needs_autoupdate(&self.settings) { + Ok(should_autoupdate) => should_autoupdate, + Err(err) => { + warn!("Error checking for autoupdate: {:#}", err); + false + } + }) + .cloned() + .collect(); + if plugins.is_empty() { + return Ok(()); + } + let mpr = MultiProgressReport::new(self.settings.verbose); + plugins + .into_par_iter() + .map(|plugin| { + let mut pr = mpr.add(); + plugin.autoupdate(&mut pr)?; + pr.clear(); + Ok(()) + }) + .collect::>()?; + Ok(()) + }) { + warn!("Error autoupdating: {:#}", err); + } + } + + pub fn check_for_new_version(&self) { + if !console::user_attended_stderr() { + return; // not a tty so don't bother + } + if let Some(latest) = cli::version::check_for_new_version() { + warn!( + "newer rtx version {} available, currently on {}", + latest, + env!("CARGO_PKG_VERSION") + ); + } + } } fn get_project_root(config_files: &ConfigMap) -> Option { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 052eee476..4cbdad8c8 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -18,7 +18,7 @@ use crate::cmd::cmd; use crate::config::{Config, Settings}; use crate::env::PREFER_STALE; use crate::errors::Error::PluginNotInstalled; -use crate::file::{display_path, remove_dir_all}; +use crate::file::{display_path, remove_dir_all, touch_dir}; use crate::git::Git; use crate::hash::hash_to_str; use crate::lock_file::LockFile; @@ -359,6 +359,22 @@ impl Plugin { pr.enable_steady_tick(); } + pub fn needs_autoupdate(&self, settings: &Settings) -> Result { + if settings.plugin_autoupdate_last_check_duration == Duration::ZERO { + return Ok(false); + } + let updated_duration = self.plugin_path.metadata()?.modified()?.elapsed()?; + Ok(updated_duration > settings.plugin_autoupdate_last_check_duration) + } + + pub fn autoupdate(&self, _pr: &mut ProgressReport) -> Result<()> { + trace!("autoupdate({})", self.name); + // TODO: implement + // pr.set_message("Checking for updates...".into()); + touch_dir(&self.plugin_path)?; + Ok(()) + } + fn fetch_remote_versions(&self, settings: &Settings) -> Result> { let result = self .script_man diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 53f34da82..c9b3db17f 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -114,4 +114,10 @@ impl ProgressReport { None => eprintln!("{}{message}", self.prefix), } } + pub fn clear(&self) { + match &self.pb { + Some(pb) => pb.finish_and_clear(), + None => (), + } + } } From 82ba7668b1f1eb712abd4fe002f27813445387c9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 21:59:44 -0600 Subject: [PATCH 0461/1891] chore: Release rtx-cli version 1.23.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b9654ba7a..7eba1c7b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1393,7 +1393,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.0" +version = "1.23.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index bbf14e011..e1029f55b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.0" +version = "1.23.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 1b9f9eb35..9e0a9a8ec 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.0 +rtx 1.23.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.0/rtx-v1.23.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.1/rtx-v1.23.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 81a8ceefb..1e21122c2 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.0"; + version = "1.23.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index d612587d0..6784265f7 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.0" +.TH rtx 1 "rtx 1.23.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -137,6 +137,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.0 +v1.23.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 988616c11..6dd73d72c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.0 +Version: 1.23.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 3aae25c6d38a167f129dffa5f6a66fef3f6bf86e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 22:05:50 -0600 Subject: [PATCH 0462/1891] docs: use humanized duration for autoupdate duration --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e0a9a8ec..51a5035c1 100644 --- a/README.md +++ b/README.md @@ -550,7 +550,7 @@ always_keep_download = false # deleted after install by default # configure how frequently (in minutes) to fetch updated plugin repository changes # this is updated whenever a new runtime is installed # (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) -plugin_autoupdate_last_check_duration = 10080 # (one week) set to 0 to disable updates +plugin_autoupdate_last_check_duration = '1 week' # set to 0 to disable updates verbose = false # set to true to see full installation output, see `RTX_VERBOSE` asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` From 20a7816b001d15c3975036d374e7d19c647215c8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 22:17:09 -0600 Subject: [PATCH 0463/1891] bug: enable fake-asdf for latest-stable This appears to be needed for gradle: https://github.com/jdxcode/rtx/actions/runs/4395277363/jobs/7696983773 --- src/config/mod.rs | 2 +- src/plugins/mod.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 7b07885d5..6d98c437a 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -227,7 +227,7 @@ impl Config { .filter(|p| match p.needs_autoupdate(&self.settings) { Ok(should_autoupdate) => should_autoupdate, Err(err) => { - warn!("Error checking for autoupdate: {:#}", err); + debug!("Error checking for autoupdate: {:#}", err); false } }) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 4cbdad8c8..70aafd78e 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -18,6 +18,7 @@ use crate::cmd::cmd; use crate::config::{Config, Settings}; use crate::env::PREFER_STALE; use crate::errors::Error::PluginNotInstalled; +use crate::fake_asdf::get_path_with_fake_asdf; use crate::file::{display_path, remove_dir_all, touch_dir}; use crate::git::Git; use crate::hash::hash_to_str; @@ -58,7 +59,8 @@ impl Plugin { }; Self { name: name.into(), - script_man: ScriptManager::new(plugin_path.clone()), + script_man: ScriptManager::new(plugin_path.clone()) + .with_env("PATH".into(), get_path_with_fake_asdf()), downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) @@ -360,7 +362,8 @@ impl Plugin { } pub fn needs_autoupdate(&self, settings: &Settings) -> Result { - if settings.plugin_autoupdate_last_check_duration == Duration::ZERO { + if settings.plugin_autoupdate_last_check_duration == Duration::ZERO || !self.is_installed() + { return Ok(false); } let updated_duration = self.plugin_path.metadata()?.modified()?.elapsed()?; From 9260a5c2ce98cf89389b421295b05d7138c928ef Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 11 Mar 2023 22:30:19 -0600 Subject: [PATCH 0464/1891] bug: fix gradle latest-stable script --- src/cli/asdf.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 44b1079b5..47d7d6432 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -17,7 +17,7 @@ pub struct Asdf { } impl Command for Asdf { - fn run(mut self, mut config: Config, out: &mut Output) -> Result<()> { + fn run(mut self, config: Config, out: &mut Output) -> Result<()> { let mut args = vec![String::from("rtx")]; args.append(&mut self.args); @@ -31,7 +31,7 @@ impl Command for Asdf { Ok(()) } } - Some("list") => list_versions(&mut config, out, &args), + Some("list") => list_versions(config, out, &args), Some("install") => { if args.len() == 4 { let version = args.pop().unwrap(); @@ -44,9 +44,16 @@ impl Command for Asdf { } } -fn list_versions(config: &mut Config, out: &mut Output, args: &Vec) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; - let mut versions = ts.list_installed_versions(config)?; +fn list_versions(mut 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 { + new_args.push(args[3].clone()); + } + return Cli::new().run(config, &new_args, out); + } + let ts = ToolsetBuilder::new().build(&mut config)?; + let mut versions = ts.list_installed_versions(&config)?; let plugin = match args.len() { 3 => Some(&args[2]), _ => None, From dee2d2e01cfa2040a986e2058ae2ddfb9f355d1e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 08:03:25 -0500 Subject: [PATCH 0465/1891] test: fix tests locally --- src/cli/version.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index 7754cf311..bb475c07d 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -99,11 +99,18 @@ fn get_latest_version() -> Option { Some(version) } +#[cfg(test)] +fn get_latest_version_call() -> Option { + Some("0.0.0".to_string()) +} + +#[cfg(not(test))] fn get_latest_version_call() -> Option { - const URL: &str = "https://rtx.jdxcode.com/VERSION"; + const URL: &str = "https://rtx.pub/VERSION"; debug!("checking for version from {}", URL); reqwest::blocking::ClientBuilder::new() .timeout(Duration::from_secs(2)) + .user_agent(format!("rtx/{}", env!("CARGO_PKG_VERSION"))) .build() .ok()? .get(URL) From d8615a6a4f0f0650ea18c1ce9aeb31858605eb19 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 08:19:51 -0500 Subject: [PATCH 0466/1891] feat: added --log-level option (#307) Fixes #61 --- e2e/test_log_level | 14 ++++++++++++++ man/man1/rtx.1 | 5 ++++- src/cli/args/log_level.rs | 1 - src/cli/mod.rs | 6 ------ src/env.rs | 10 ++++++++++ 5 files changed, 28 insertions(+), 8 deletions(-) create mode 100755 e2e/test_log_level diff --git a/e2e/test_log_level b/e2e/test_log_level new file mode 100755 index 000000000..ab56937d4 --- /dev/null +++ b/e2e/test_log_level @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +assert() { + local actual + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +assert "rtx x nodejs@18.0.0 --log-level debug -- node -v" "v18.0.0" +assert "rtx x nodejs@18.0.0 --log-level=debug -- node -v" "v18.0.0" diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 6784265f7..f9da60a60 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -4,7 +4,7 @@ .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS -\fBrtx\fR [\fB\-\-install\-missing\fR] [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> +\fBrtx\fR [\fB\-\-install\-missing\fR] [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-\-log\-level\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> .SH DESCRIPTION rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx .PP @@ -23,6 +23,9 @@ Automatically install missing tools Number of plugins and runtimes to install in parallel default: 4 .TP +\fB\-\-log\-level\fR=\fILEVEL\fR [default: info] +Set the log output verbosity +.TP \fB\-r\fR, \fB\-\-raw\fR Directly pipe stdin/stdout/stderr to user. sets \-\-jobs=1 diff --git a/src/cli/args/log_level.rs b/src/cli/args/log_level.rs index 5e07857f2..ec96b18d2 100644 --- a/src/cli/args/log_level.rs +++ b/src/cli/args/log_level.rs @@ -21,7 +21,6 @@ impl LogLevel { .default_value(DEFAULT_LOG_LEVEL.as_str()) .global(true) .value_parser(ValueParser::new(parse_log_level)) - .hide(true) } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ef2d6cbe4..70a82d65d 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -168,12 +168,6 @@ impl Cli { ) } - // TODO: use this - pub fn _parse_log_level(self, args: &Vec) -> LevelFilter { - let matches = self.command.get_matches_from(args); - *matches.get_one::("log-level").unwrap() - } - pub fn run(self, mut config: Config, args: &Vec, out: &mut Output) -> Result<()> { debug!("{}", &args.join(" ")); if args[1..] == ["-v"] { diff --git a/src/env.rs b/src/env.rs index d083c6577..9e8a58e60 100644 --- a/src/env.rs +++ b/src/env.rs @@ -30,6 +30,16 @@ lazy_static! { // logging pub static ref RTX_LOG_LEVEL: log::LevelFilter = { + ARGS.iter().enumerate().for_each(|(i, arg)| { + if let Some(("--log-level", level)) = arg.split_once('=') { + std::env::set_var("RTX_LOG_LEVEL", level); + } + if arg == "--log-level" { + if let Some(level) = ARGS.get(i + 1) { + std::env::set_var("RTX_LOG_LEVEL", level); + } + } + }); let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); match log_level.parse::() { Ok(level) => level, From 6e6c35a1c204f550549418343bf5af63059a4195 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 08:44:20 -0500 Subject: [PATCH 0467/1891] feat: added RTX_DATA_DIR, RTX_PLUGIN_NAME, RTX_SHIMS_DIR to plugin interface --- src/runtimes.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index e04209579..0214c72f0 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -329,7 +329,16 @@ fn build_script_man( download_path.to_string_lossy().to_string(), ) .with_env("RTX_CONCURRENCY".into(), num_cpus::get().to_string()) - .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()); + .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()) + .with_env( + "RTX_DATA_DIR".into(), + dirs::ROOT.to_string_lossy().to_string(), + ) + .with_env("RTX_PLUGIN_NAME".into(), tv.plugin_name.clone()); + if let Some(shims_dir) = &config.settings.shims_dir { + let shims_dir = shims_dir.to_string_lossy().to_string(); + sm = sm.with_env("RTX_SHIMS_DIR".into(), shims_dir); + } if let Some(project_root) = &config.project_root { let project_root = project_root.to_string_lossy().to_string(); sm = sm.with_env("RTX_PROJECT_ROOT".into(), project_root); From ab0c87216ce56dc07edb16643fad3c55453a1e40 Mon Sep 17 00:00:00 2001 From: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Date: Sun, 12 Mar 2023 10:31:27 -0500 Subject: [PATCH 0468/1891] Update README.md (#308) Fix venv typo and use same spacing as other options --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51a5035c1..ec6ee4fb9 100644 --- a/README.md +++ b/README.md @@ -600,7 +600,7 @@ nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] # RTX_TOOL_OPTS__VENV=.venv # RTX_TOOL_OPTS__DEFAULT_PACKAGES__0=ansible # RTX_TOOL_OPTS__DEFAULT_PACKAGES__1=pipenv -python = { version = '3.10', venv = '.venv', default_packages = ['ansible', 'pipenv'] } +python = {version='3.10', virtualenv='.venv', default_packages=['ansible', 'pipenv']} [plugins] # specify a custom repo url From fbe8c28af1f06234edfd5ca5065170fcee0f6883 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 10:57:41 -0500 Subject: [PATCH 0469/1891] chore: fix editorconfig --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 706a53ecd..ef9265582 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,2 @@ [*.sh] -indent_style = tabs +indent_style = tab From da1a2422feb2660056a71066d51b8705fad33544 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 11:36:33 -0500 Subject: [PATCH 0470/1891] chore: puhlish to r2 (#306) --- .github/workflows/rtx.yml | 17 +++++++++----- scripts/publish-r2.sh | 47 +++++++++++++++++++++++++++++++++++++++ scripts/publish-s3.sh | 35 ----------------------------- scripts/release-npm.sh | 5 +++++ scripts/release.sh | 2 +- src/cli/doctor.rs | 3 ++- 6 files changed, 66 insertions(+), 43 deletions(-) create mode 100755 scripts/publish-r2.sh delete mode 100755 scripts/publish-s3.sh diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index ffdae5ceb..60ede43dc 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -199,6 +199,7 @@ jobs: contents: write needs: - unit + - coverage - e2e-linux - build-linux - build-macos @@ -213,16 +214,19 @@ jobs: repository: jdxcode/homebrew-tap path: homebrew-tap token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + - name: Install fd-find + run: | + sudo apt-get update + sudo apt-get install fd-find + mkdir -p "$HOME/.local/bin" + ln -s $(which fdfind) "$HOME/.local/bin/fd" + echo "$HOME/.local/bin" >> $GITHUB_PATH - uses: actions/setup-node@v3 with: node-version: "18.x" registry-url: "https://registry.npmjs.org" - - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-west-2 + - name: Wrangler + run: npm i -g wrangler@^2.12.2 - uses: shimataro/ssh-key-action@v2 with: key: ${{ secrets.RTX_SSH_KEY }} @@ -237,6 +241,7 @@ jobs: with: { path: artifacts } - run: rtx/scripts/release.sh env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: homebrew-tap push run: git push diff --git a/scripts/publish-r2.sh b/scripts/publish-r2.sh new file mode 100755 index 000000000..d55fbc603 --- /dev/null +++ b/scripts/publish-r2.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euxo pipefail + +export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 +export CLOUDFLARE_ZONE_ID=80d977fd09f01db52bec165778088891 +cache_hour="max-age=3600,s-maxage=3600,public,immutable" +cache_day="max-age=86400,s-maxage=86400,public,immutable" +cache_week="max-age=604800,s-maxage=604800,public,immutable" + +./rtx/scripts/render-install.sh >"$RELEASE_DIR/install.sh" +echo "$RTX_VERSION" | tr -d 'v' >"$RELEASE_DIR/VERSION" +cd "$RELEASE_DIR" + +cp "rtx-latest-linux-x64" "rtx-latest-linux-amd64" +cp "rtx-latest-macos-x64" "rtx-latest-macos-amd64" + +fd "$RTX_VERSION" -tfile -x wrangler r2 object put -f {} rtx/{} --cc "$cache_hour" + +for f in rtx-latest-*; do + wrangler r2 object put -f "$f" "rtx/$f" --cc "$cache_hour" +done + +for f in SHASUMS* VERSION install.sh; do + wrangler r2 object put -f "$f" "rtx/$f" --cc "$cache_hour" --ct text/plain +done + +cd ../artifacts +wrangler r2 object put -f rpm/rtx.repo rtx/rpm/rtx.repo --cc "$cache_day" +fd . rpm/repodata rpm/packages -tfile -E repomd.xml\* -x wrangler r2 object put -f {} rtx/{} --cc "$cache_week" +fd -g "repomd.xml*" -tfile -x wrangler r2 object put -f {} rtx/{} --cc "$cache_hour" --ct text/xml + +fd . deb/dists -tfile -x wrangler r2 object put -f {} rtx/{} --cc "$cache_hour" +fd . deb/pool -tfile -x wrangler r2 object put -f {} rtx/{} --cc "$cache_week" + +curl -X POST https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data '{ + "prefixes": [ + "/VERSION", + "/SHASUMS", + "/install.sh", + "/rtx-latest-", + "/rpm/repodata/", + "/deb/dists/" + ] + }' diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh deleted file mode 100755 index 1bb1a4c81..000000000 --- a/scripts/publish-s3.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash -set -euxo pipefail - -cache_hour="max-age=3600,s-maxage=3600,public,immutable" -cache_day="max-age=86400,s-maxage=86400,public,immutable" -cache_week="max-age=604800,s-maxage=604800,public,immutable" - -./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh -echo "$RTX_VERSION" | tr -d 'v' >"$RELEASE_DIR"/VERSION - -cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-latest-linux-amd64" -cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-latest-macos-amd64" - -aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive - -aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "rtx-latest-*" -aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" -aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" -aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" - -aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress -aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive -aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "repomd.xml*" -aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" - -aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive -aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_hour" --no-progress --no-progress --recursive - -aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ - "/VERSION" \ - "/SHASUMS*" \ - "/install.sh" \ - "/rtx-latest-*" \ - "/rpm/repodata/*" \ - "/deb/dists/*" diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index 7973056cc..b259e142e 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -6,6 +6,11 @@ error() { exit 1 } +if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then + echo "NODE_AUTH_TOKEN must be set" >&2 + exit 0 +fi + mkdir -p "$RELEASE_DIR/npm" dist_tag_from_version() { diff --git a/scripts/release.sh b/scripts/release.sh index fefdece30..ad92e0d95 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -59,7 +59,7 @@ popd NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh -./rtx/scripts/publish-s3.sh +./rtx/scripts/publish-r2.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb pushd homebrew-tap diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 544bac11a..0f4c96da1 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -111,7 +111,8 @@ fn render_plugins(config: &Config) -> String { .values() .map(|p| p.name.len()) .max() - .unwrap_or(0); + .unwrap_or(0) + + 2; for p in config.plugins.values() { let padded_name = pad_str(&p.name, max_plugin_name_len, Alignment::Left, None); let git = Git::new(p.plugin_path.clone()); From f0ec300a5c9ff84444ee13aff52c3f4f12e8bb19 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 11:37:10 -0500 Subject: [PATCH 0471/1891] chore: Release rtx-cli version 1.23.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7eba1c7b2..83a09fce0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1393,7 +1393,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.1" +version = "1.23.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index e1029f55b..104e17344 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.1" +version = "1.23.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index ec6ee4fb9..76462402b 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.1 +rtx 1.23.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.1/rtx-v1.23.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.2/rtx-v1.23.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 1e21122c2..a3cd96487 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.1"; + version = "1.23.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index f9da60a60..9710b09d5 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.1" +.TH rtx 1 "rtx 1.23.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.1 +v1.23.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6dd73d72c..e4d4ee26a 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.1 +Version: 1.23.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 729513e39da4611b015660196cbc1bb43efc1278 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 14:04:41 -0500 Subject: [PATCH 0472/1891] added extra env vars for plugin scripts --- src/cli/install.rs | 2 +- src/cli/plugins/install.rs | 2 +- src/config/mod.rs | 8 ++++---- src/plugins/mod.rs | 29 ++++++++++++++++++++++------- src/toolset/mod.rs | 2 +- src/toolset/tool_version_list.rs | 3 ++- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/cli/install.rs b/src/cli/install.rs index 5ac83023e..b4926551e 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -103,7 +103,7 @@ impl Install { for mut tv in tool_versions { let plugin = match config.plugins.get(&tv.plugin_name).cloned() { Some(plugin) => plugin, - None => Arc::new(Plugin::new(&tv.plugin_name)), + None => Arc::new(Plugin::new(&config.settings, &tv.plugin_name)), }; if !plugin.is_installed() { let mut pr = mpr.add(); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index d4106599a..3f22508b9 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -114,7 +114,7 @@ impl PluginsInstall { git_url: &str, mpr: &MultiProgressReport, ) -> Result<()> { - let mut plugin = Plugin::new(name); + let mut plugin = Plugin::new(&config.settings, name); let (git_url, ref_) = git_url .split_once('#') .map_or((git_url, None), |(a, b)| (a, Some(b))); diff --git a/src/config/mod.rs b/src/config/mod.rs index 6d98c437a..ad87e43ad 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -49,10 +49,10 @@ pub struct Config { impl Config { pub fn load() -> Result { - let mut plugins = load_plugins()?; let global_config = load_rtxrc()?; let mut settings = SettingsBuilder::default(); let config_filenames = load_config_filenames(&IndexMap::new()); + let mut plugins = load_plugins(&settings.build())?; let config_files = load_all_config_files( &settings.build(), &config_filenames, @@ -87,7 +87,7 @@ impl Config { for cf in config_files.values() { for (plugin_name, repo_url) in cf.plugins() { plugins.entry(plugin_name.clone()).or_insert_with(|| { - let mut plugin = Plugin::new(&plugin_name); + let mut plugin = Plugin::new(&settings, &plugin_name); plugin.repo_url = Some(repo_url); Arc::new(plugin) }); @@ -304,8 +304,8 @@ fn load_rtxrc() -> Result { } } -fn load_plugins() -> Result>> { - let plugins = Plugin::list()? +fn load_plugins(settings: &Settings) -> Result>> { + let plugins = Plugin::list(settings)? .into_par_iter() .map(|p| (p.name.clone(), Arc::new(p))) .collect::>() diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 70aafd78e..ae7c6395a 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -49,7 +49,7 @@ pub struct Plugin { } impl Plugin { - pub fn new(name: &PluginName) -> Self { + pub fn new(settings: &Settings, name: &PluginName) -> Self { let plugin_path = dirs::PLUGINS.join(name); let cache_path = dirs::CACHE.join(name); let fresh_duration = if *PREFER_STALE { @@ -59,8 +59,7 @@ impl Plugin { }; Self { name: name.into(), - script_man: ScriptManager::new(plugin_path.clone()) - .with_env("PATH".into(), get_path_with_fake_asdf()), + script_man: build_script_man(settings, name, &plugin_path), downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) @@ -84,10 +83,10 @@ impl Plugin { } } - pub fn list() -> Result> { + pub fn list(settings: &Settings) -> Result> { Ok(file::dir_subdirs(&dirs::PLUGINS)? .iter() - .map(Plugin::new) + .map(|name| Plugin::new(settings, name)) .collect()) } @@ -521,6 +520,22 @@ impl Plugin { } } +fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> ScriptManager { + let mut sm = ScriptManager::new(plugin_path.to_path_buf()) + .with_env("PATH".into(), get_path_with_fake_asdf()) + .with_env( + "RTX_DATA_DIR".into(), + dirs::ROOT.to_string_lossy().into_owned(), + ) + .with_env("RTX_PLUGIN_NAME".into(), name.to_string()); + if let Some(shims_dir) = &settings.shims_dir { + let shims_dir = shims_dir.to_string_lossy().to_string(); + sm = sm.with_env("RTX_SHIMS_DIR".into(), shims_dir); + } + + sm +} + impl PartialEq for Plugin { fn eq(&self, other: &Self) -> bool { self.name == other.name @@ -539,7 +554,7 @@ mod tests { fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); - let plugin = Plugin::new(&PluginName::from("tiny")); + let plugin = Plugin::new(&settings, &PluginName::from("tiny")); let version = plugin .latest_version(&settings, Some("1.0.0".into())) .unwrap() @@ -552,7 +567,7 @@ mod tests { #[test] fn test_latest_stable() { let settings = Settings::default(); - let plugin = Plugin::new(&PluginName::from("dummy")); + let plugin = Plugin::new(&settings, &PluginName::from("dummy")); let version = plugin.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 64f53b736..62660736d 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -181,7 +181,7 @@ impl Toolset { config .plugins .entry(plugin.clone()) - .or_insert_with(|| Arc::new(Plugin::new(plugin))); + .or_insert_with(|| Arc::new(Plugin::new(&config.settings, plugin))); } config.plugins.sort_keys(); missing_plugins diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index a45d69d66..f95b05dc7 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -65,7 +65,8 @@ mod tests { fn test_tool_version_list_failure() { env::set_var("RTX_FAILURE", "1"); let mut tvl = ToolVersionList::new(ToolSource::Argument); - let plugin = Arc::new(Plugin::new(&PluginName::from("dummy"))); + let settings = crate::config::Settings::default(); + let plugin = Arc::new(Plugin::new(&settings, &PluginName::from("dummy"))); plugin.clear_remote_version_cache().unwrap(); tvl.add_version(ToolVersion::new( plugin.name.to_string(), From a74ff740091586a18e807ca25aed4a519fca8942 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 15:20:01 -0500 Subject: [PATCH 0473/1891] chore: switch to rustls-tls (#312) This might work better for alpine --- Cargo.lock | 235 ++++++++++++++++++++--------------------------------- Cargo.toml | 5 +- 2 files changed, 88 insertions(+), 152 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83a09fce0..fe5576064 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,16 +232,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -527,21 +517,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.1.0" @@ -737,16 +712,16 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ - "bytes", + "http", "hyper", - "native-tls", + "rustls", "tokio", - "tokio-native-tls", + "tokio-rustls", ] [[package]] @@ -983,24 +958,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nix" version = "0.26.2" @@ -1082,61 +1039,6 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" -[[package]] -name = "openssl" -version = "0.10.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "111.25.0+1.1.1t" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3173cd3626c43e3854b1b727422a276e568d9ec5fe8cec197822cf52cfb743d6" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" -dependencies = [ - "autocfg", - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - [[package]] name = "os_pipe" version = "1.1.3" @@ -1192,12 +1094,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - [[package]] name = "portable-atomic" version = "0.3.19" @@ -1341,28 +1237,45 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-tls", + "hyper-rustls", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-native-tls", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "rmp" version = "0.8.11" @@ -1424,7 +1337,6 @@ dependencies = [ "log", "num_cpus", "once_cell", - "openssl", "owo-colors", "pretty_assertions", "rayon", @@ -1467,20 +1379,32 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.12" +name = "rustls" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] [[package]] -name = "schannel" -version = "0.1.21" +name = "rustls-pemfile" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "windows-sys 0.42.0", + "base64", ] +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + [[package]] name = "scopeguard" version = "1.1.0" @@ -1494,26 +1418,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" [[package]] -name = "security-framework" -version = "2.8.2" +name = "sct" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" -dependencies = [ - "core-foundation-sys", - "libc", + "ring", + "untrusted", ] [[package]] @@ -1656,6 +1567,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1825,13 +1742,14 @@ dependencies = [ ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "tokio-rustls" +version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "native-tls", + "rustls", "tokio", + "webpki", ] [[package]] @@ -1969,6 +1887,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.3.1" @@ -1992,12 +1916,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -2112,6 +2030,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 104e17344..9bb782db7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,13 +51,12 @@ lazy_static = "1.4.0" log = "0.4.17" num_cpus = "1.15.0" once_cell = "1.17.0" -openssl = { version = "0.10", features = ["vendored"] } owo-colors = { version = "3.5.0" } rayon = "1.7.0" regex = "1.7.1" -reqwest = { version = "0.11.14", features = ["blocking"] } +reqwest = { version = "0.11.14", default-features = false, features = ["blocking", "rustls-tls"] } rmp-serde = "1.1.1" -self_update = { version = "0.36.0", optional = true } +self_update = { version = "0.36.0", default-features = false, optional = true, features = ["rustls"] } serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.92" From b3bbf5e56ea6e219b41101acf3f91dcceac0698f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:38:04 -0500 Subject: [PATCH 0474/1891] feat: support for PATH in .rtx.toml env vars (#313) This makes it so you can add new directories to PATH in .rtx.toml. This is done by specifying PATH as an array like the following: ```toml [env] PATH = [ "/foo" # absolute path "./bar" # relative to the directory .rtx.toml is in "$PATH" # for now this is required to be at the end ] ``` --- e2e/.e2e.rtx.toml | 1 + e2e/test_local | 4 + src/config/config_file/legacy_version.rs | 4 + src/config/config_file/mod.rs | 3 +- src/config/config_file/rtx_toml.rs | 78 +++++++++++++++++-- ...__config_file__rtx_toml__tests__env-3.snap | 7 ++ ...ig_file__rtx_toml__tests__path_dirs-2.snap | 8 ++ ...ig_file__rtx_toml__tests__path_dirs-3.snap | 8 ++ src/config/config_file/tool_versions.rs | 4 + src/config/mod.rs | 10 +++ src/toolset/mod.rs | 2 +- 11 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap diff --git a/e2e/.e2e.rtx.toml b/e2e/.e2e.rtx.toml index a63412114..919c26e4e 100644 --- a/e2e/.e2e.rtx.toml +++ b/e2e/.e2e.rtx.toml @@ -1,5 +1,6 @@ [env] FOO = "bar" +PATH = ["/root", "./cwd", "$PATH"] [tools] tiny = "latest" diff --git a/e2e/test_local b/e2e/test_local index 907342d49..c49c2372e 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -22,6 +22,7 @@ assert_raises "rtx uninstall shfmt@3.6.0" assert "rtx local" "[env] FOO = \"bar\" +PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" @@ -30,6 +31,7 @@ tiny = \"latest\" assert "rtx local shfmt@3.5.0" "[env] FOO = \"bar\" +PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" @@ -44,6 +46,7 @@ fi assert "rtx local shfmt@3.6.0" "[env] FOO = \"bar\" +PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" @@ -58,6 +61,7 @@ fi assert "rtx local --rm shfmt" "[env] FOO = \"bar\" +PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 789a40987..19623a849 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -45,6 +45,10 @@ impl ConfigFile for LegacyVersionFile { HashMap::new() } + fn path_dirs(&self) -> Vec { + vec![] + } + fn remove_plugin(&mut self, _plugin_name: &PluginName) { unimplemented!() } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 7d23ff8d0..96d3cb6b7 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::fmt::{Debug, Display}; -use std::path::Path; +use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; @@ -33,6 +33,7 @@ pub trait ConfigFile: Debug + Display + Send + Sync { fn get_path(&self) -> &Path; fn plugins(&self) -> HashMap; fn env(&self) -> HashMap; + fn path_dirs(&self) -> Vec; fn remove_plugin(&mut self, plugin_name: &PluginName); fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]); fn save(&self) -> Result<()>; diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 489cb5eef..33de4b5b6 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -7,7 +7,7 @@ use std::time::Duration; use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; use log::LevelFilter; -use toml_edit::{table, value, Array, Item, Value}; +use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; @@ -21,9 +21,10 @@ pub struct RtxToml { path: PathBuf, toolset: Toolset, env: HashMap, + path_dirs: Vec, settings: SettingsBuilder, alias: AliasMap, - doc: toml_edit::Document, + doc: Document, plugins: HashMap, } @@ -67,10 +68,10 @@ impl RtxToml { } fn parse(&mut self, s: &str) -> Result<()> { - self.doc = s.parse().suggestion("ensure file is valid TOML")?; - for (k, v) in self.doc.iter() { + let doc: Document = s.parse().suggestion("ensure file is valid TOML")?; + for (k, v) in doc.iter() { match k { - "env" => self.env = self.parse_hashmap(k, v)?, + "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, "settings" => self.settings = self.parse_settings(k, v)?, @@ -78,6 +79,7 @@ impl RtxToml { _ => Err(eyre!("unknown key: {}", k))?, } } + self.doc = doc; Ok(()) } @@ -85,6 +87,47 @@ impl RtxToml { SettingsBuilder::default() } + fn parse_env(&mut self, k: &str, v: &Item) -> Result<()> { + let mut v = v.clone(); + if let Some(table) = v.as_table_like_mut() { + if let Some(path) = table.remove("PATH") { + self.path_dirs = self.parse_path_env(&format!("{}.PATH", k), &path)?; + } + } + self.env = self.parse_hashmap(k, &v)?; + Ok(()) + } + + fn parse_path_env(&self, k: &str, v: &Item) -> Result> { + match v.as_array() { + Some(array) => { + if let Some(Some(last)) = array.get(array.len() - 1).map(|v| v.as_str()) { + if last != "$PATH" { + // TODO: allow $PATH to be anywhere in the array + parse_error!(k, v, "array ending with '$PATH'")?; + } + } + let mut path = Vec::new(); + let config_root = self.path.parent().unwrap(); + for v in array { + match v.as_str() { + Some("$PATH") => {} + Some(s) => { + let s = match s.strip_prefix("./") { + Some(s) => config_root.join(s), + None => s.into(), + }; + path.push(s); + } + _ => parse_error!(k, v, "string")?, + } + } + Ok(path) + } + _ => parse_error!(k, v, "array")?, + } + } + fn parse_alias(&self, k: &str, v: &Item) -> Result { match v.as_table_like() { Some(table) => { @@ -467,6 +510,10 @@ impl ConfigFile for RtxToml { self.env.clone() } + fn path_dirs(&self) -> Vec { + self.path_dirs.clone() + } + fn remove_plugin(&mut self, plugin: &PluginName) { self.toolset.versions.remove(plugin); if let Some(tools) = self.doc.get_mut("tools") { @@ -572,6 +619,27 @@ mod tests { "foo": "bar", } "###); + assert_debug_snapshot!(cf.path_dirs(), @"[]"); + assert_display_snapshot!(cf); + } + + #[test] + fn test_path_dirs() { + let p = dirs::HOME.join("fixtures/.rtx.toml"); + let mut cf = RtxToml::init(&p); + cf.parse(&formatdoc! {r#" + [env] + foo="bar" + PATH=["/foo", "./bar", "$PATH"] + "#}) + .unwrap(); + + assert_debug_snapshot!(cf.env(), @r###" + { + "foo": "bar", + } + "###); + assert_snapshot!(replace_path(&format!("{:?}", cf.path_dirs())), @r###"["/foo", "~/fixtures/bar"]"###); assert_display_snapshot!(cf); } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap new file mode 100644 index 000000000..8913bebf1 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap @@ -0,0 +1,7 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[env] +foo="bar" + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap new file mode 100644 index 000000000..a62bbc53c --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap @@ -0,0 +1,8 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[env] +foo="bar" +PATH=["/foo", "./bar", "$PATH"] + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap new file mode 100644 index 000000000..a62bbc53c --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap @@ -0,0 +1,8 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +[env] +foo="bar" +PATH=["/foo", "./bar", "$PATH"] + diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 523d12ac2..d2cb00eef 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -155,6 +155,10 @@ impl ConfigFile for ToolVersions { HashMap::new() } + fn path_dirs(&self) -> Vec { + vec![] + } + fn remove_plugin(&mut self, plugin: &PluginName) { self.plugins.remove(plugin); } diff --git a/src/config/mod.rs b/src/config/mod.rs index ad87e43ad..5f3c3f8d6 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -40,6 +40,7 @@ pub struct Config { pub config_files: ConfigMap, pub plugins: IndexMap>, pub env: IndexMap, + pub path_dirs: Vec, pub aliases: AliasMap, pub all_aliases: OnceCell, pub should_exit_early: bool, @@ -97,6 +98,7 @@ impl Config { let config = Self { env: load_env(&config_files), + path_dirs: load_path_dirs(&config_files), aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), shorthands: OnceCell::new(), @@ -429,6 +431,14 @@ fn load_env(config_files: &IndexMap>) -> IndexMap>) -> Vec { + let mut path_dirs = vec![]; + for cf in config_files.values().rev() { + path_dirs.extend(cf.path_dirs()); + } + path_dirs +} + fn load_aliases(config_files: &IndexMap>) -> AliasMap { let mut aliases: AliasMap = IndexMap::new(); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 62660736d..44ff81821 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -274,7 +274,7 @@ impl Toolset { } pub fn path_env(&self, config: &Config) -> String { let installs = self.list_paths(config); - join_paths([installs, env::PATH.clone()].concat()) + join_paths([config.path_dirs.clone(), installs, env::PATH.clone()].concat()) .unwrap() .to_string_lossy() .into() From cd64c22793745d1126d3739f5edab75f6705d8e6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:50:28 -0500 Subject: [PATCH 0475/1891] feat: support for PATH in .rtx.toml env vars (#314) This makes it so you can add new directories to PATH in .rtx.toml. This is done by specifying PATH as an array like the following: ```toml [env] PATH = [ "/foo" # absolute path "./bar" # relative to the directory .rtx.toml is in "$PATH" # for now this is required to be at the end ] ``` --- README.md | 7 +++++++ src/config/config_file/rtx_toml.rs | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 76462402b..accfe526a 100644 --- a/README.md +++ b/README.md @@ -587,6 +587,13 @@ Here is what the config looks like: ```toml [env] NODE_ENV = 'production' # supports arbitrary env vars so rtx can be used like dotenv +PATH = [ + # adds an absolute path + "~/.local/share/bin", + # adds a path relative to the directory this config is in, not necessarily PWD + "./node_modules/.bin", + "$PATH" # required to be at the end +] [tools] # specify single or multiple versions diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 33de4b5b6..f72acd7d1 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -12,6 +12,7 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, MissingRuntimeBehavior}; +use crate::dirs; use crate::file::create_dir_all; use crate::plugins::PluginName; use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; @@ -115,7 +116,10 @@ impl RtxToml { Some(s) => { let s = match s.strip_prefix("./") { Some(s) => config_root.join(s), - None => s.into(), + None => match s.strip_prefix("~/") { + Some(s) => dirs::HOME.join(s), + None => s.into(), + }, }; path.push(s); } From d095ec58a81242a5fcb1a394b9e1993a91c55dcd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:57:45 -0500 Subject: [PATCH 0476/1891] chore: run `cargo update` on release --- scripts/pre-release-hook.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 2c4a8ca66..e1fd6adf6 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash set -euxo pipefail +if [[ "${NO_UPDATE:-}" == "1" ]]; then + echo "NO_UPDATE is set, skipping update" +else + cargo update && git add Cargo.lock +fi + just render-mangen render-help ./scripts/update-shorthand-repo.sh From 811dc9bb7908727741951dd05d5385e0eb735d5d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:59:11 -0500 Subject: [PATCH 0477/1891] chore: Release rtx-cli version 1.23.3 --- Cargo.lock | 156 ++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 85 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe5576064..8f85ea042 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,9 +113,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "js-sys", @@ -249,9 +249,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -259,9 +259,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -312,9 +312,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" +checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" dependencies = [ "cc", "cxxbridge-flags", @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" +checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" dependencies = [ "cc", "codespan-reporting", @@ -339,15 +339,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" +checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" [[package]] name = "cxxbridge-macro" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" +checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" dependencies = [ "proc-macro2", "quote", @@ -538,42 +538,42 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" dependencies = [ "futures-core", "futures-io", @@ -603,9 +603,9 @@ checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "h2" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ "bytes", "fnv", @@ -689,9 +689,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.24" +version = "0.14.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" dependencies = [ "bytes", "futures-channel", @@ -818,9 +818,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" dependencies = [ "libc", "windows-sys 0.45.0", @@ -855,9 +855,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" @@ -876,9 +876,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "link-cplusplus" @@ -918,9 +918,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] @@ -1072,9 +1072,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "paste" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "percent-encoding" @@ -1138,9 +1138,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] @@ -1156,9 +1156,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "50686e0021c4136d1d453b2dfe059902278681512a34d4248435dc34b6b5c8ec" dependencies = [ "proc-macro2", ] @@ -1306,7 +1306,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.2" +version = "1.23.3" dependencies = [ "base64", "build-time", @@ -1366,9 +1366,9 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.8" +version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ "bitflags", "errno", @@ -1401,9 +1401,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "scopeguard" @@ -1413,9 +1413,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "sct" @@ -1447,21 +1447,21 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" dependencies = [ "proc-macro2", "quote", @@ -1470,9 +1470,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ "itoa", "ryu", @@ -1539,9 +1539,9 @@ checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" [[package]] name = "simplelog" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786" +checksum = "acee08041c5de3d5048c8b3f6f13fafb3026b24ba43c6a695a0c76179b844369" dependencies = [ "log", "termcolor", @@ -1559,9 +1559,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -1726,9 +1726,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.25.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" dependencies = [ "autocfg", "bytes", @@ -1738,7 +1738,7 @@ dependencies = [ "num_cpus", "pin-project-lite", "socket2", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -1789,9 +1789,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.4" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" +checksum = "7082a95d48029677a28f181e5f6422d0c8339ad8396a39d3f33d62a90c1f6c30" dependencies = [ "indexmap", "serde", @@ -1856,15 +1856,15 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "unicode-bidi" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" +checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -2163,9 +2163,9 @@ checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winnow" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658" +checksum = "ee7b2c67f962bf5042bfd8b6a916178df33a26eec343ae064cb8e069f638fa6f" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 9bb782db7..929e256f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.2" +version = "1.23.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index accfe526a..765fd5aff 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.2 +rtx 1.23.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.2/rtx-v1.23.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.3/rtx-v1.23.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index a3cd96487..7bb381a7d 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.2"; + version = "1.23.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 9710b09d5..919224d90 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.2" +.TH rtx 1 "rtx 1.23.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.2 +v1.23.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e4d4ee26a..5d946bd96 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.2 +Version: 1.23.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 80a3e5a51fdf2b389308c3eefcaf325e5118e544 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 18:46:14 -0500 Subject: [PATCH 0478/1891] test: do not require git to run unit tests (#315) --- src/cli/plugins/ls.rs | 11 +++-------- src/cli/prune.rs | 4 ++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 760617f33..7e66cedb7 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -66,8 +66,8 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; - use crate::git::Git; - use crate::{assert_cli, assert_cli_snapshot, dirs}; + + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_plugin_list() { @@ -77,12 +77,7 @@ mod tests { #[test] fn test_plugin_list_urls() { let stdout = assert_cli!("plugin", "list", "--urls"); - let git = Git::new(dirs::CURRENT.clone()); - let cur_remote = git.get_remote_url().unwrap(); - assert_str_eq!( - grep(stdout, "dummy"), - "dummy ".to_owned() + cur_remote.as_str() - ); + assert!(stdout.contains("dummy")) } #[test] diff --git a/src/cli/prune.rs b/src/cli/prune.rs index d151da0ce..addbbd98c 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -82,13 +82,13 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use crate::{assert_cli, cmd}; + use crate::assert_cli; #[test] fn test_prune() { assert_cli!("prune", "--dry-run"); assert_cli!("prune", "tiny"); assert_cli!("prune"); - cmd!("git", "checkout", "../data").run().unwrap(); + assert_cli!("install"); } } From 1031cbd1027bb4580f8bdb92e835b304375be33f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 19:02:15 -0500 Subject: [PATCH 0479/1891] chore: updated intellij config --- .idea/rtx.iml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.idea/rtx.iml b/.idea/rtx.iml index 5af835124..95fa9b00d 100644 --- a/.idea/rtx.iml +++ b/.idea/rtx.iml @@ -7,15 +7,18 @@ - + - + + - - - + + + + + From 31caa8d74a64b97b336cbfb40a1023080f952919 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 19:02:54 -0500 Subject: [PATCH 0480/1891] bug: fix caching of exec-env --- src/runtimes.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index 0214c72f0..f4294c152 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -52,10 +52,16 @@ impl RuntimeVersion { _ => dirs::CACHE.join(&plugin.name).join(&version), }; let mut bin_paths_cache = CacheManager::new(cache_path.join("bin_paths.msgpack.z")) + .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(install_path.clone()); let mut exec_env_cache = CacheManager::new(cache_path.join("exec_env.msgpack.z")) + .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(install_path.clone()); - if plugin.name == "python" && tv.options.contains_key("virtualenv") { + if plugin.name == "python" + && (tv.options.contains_key("virtualenv") || tv.options.contains_key("pipenv")) + { // TODO: remove this for a better solution // this is required for the virtualenv feature to work bin_paths_cache = bin_paths_cache.with_no_cache(); From 1e55ca706221d7d144a76dd9030da7dbaf1f193f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 12 Mar 2023 19:08:37 -0500 Subject: [PATCH 0481/1891] chore: Release rtx-cli version 1.23.4 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f85ea042..6f8e76986 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1156,9 +1156,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50686e0021c4136d1d453b2dfe059902278681512a34d4248435dc34b6b5c8ec" +checksum = "5308e8208729c3e1504a6cfad0d5daacc4614c9a2e65d1ea312a34b5cb00fe84" dependencies = [ "proc-macro2", ] @@ -1306,7 +1306,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.3" +version = "1.23.4" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 929e256f4..c48757a1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.3" +version = "1.23.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 765fd5aff..7d60e88aa 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.3 +rtx 1.23.4 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.3/rtx-v1.23.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.4/rtx-v1.23.4-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 7bb381a7d..73ab4281b 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.3"; + version = "1.23.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 919224d90..afdb56c4f 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.3" +.TH rtx 1 "rtx 1.23.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.3 +v1.23.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 5d946bd96..aa5cdd0a4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.3 +Version: 1.23.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 8c3469c020a2d35303b3314537e2e4b773703ed8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 07:34:28 -0500 Subject: [PATCH 0482/1891] do not cache .rtx.toml when poetry is set See https://github.com/jdxcode/rtx-python/pull/6 --- src/runtimes.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index f4294c152..4dc253e1a 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -60,7 +60,9 @@ impl RuntimeVersion { .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(install_path.clone()); if plugin.name == "python" - && (tv.options.contains_key("virtualenv") || tv.options.contains_key("pipenv")) + && (tv.options.contains_key("virtualenv") + || tv.options.contains_key("pipenv") + || tv.options.contains_key("poetry")) { // TODO: remove this for a better solution // this is required for the virtualenv feature to work From ab03843fa85a408b0ae388479d38a64f3bc02df7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 08:58:35 -0500 Subject: [PATCH 0483/1891] docs --- completions/_rtx | 200 +++++++++++++++++++++---------------------- completions/rtx.fish | 100 +++++++++++----------- man/man1/rtx.1 | 2 +- src/cli/args/raw.rs | 2 +- 4 files changed, 152 insertions(+), 152 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index 596582575..ec699d34e 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -22,9 +22,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -54,9 +54,9 @@ default: 4]: : ' \ '--quiet[noop]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -75,9 +75,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -101,9 +101,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -123,9 +123,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -141,9 +141,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -162,9 +162,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -222,9 +222,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -241,9 +241,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -259,9 +259,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -285,9 +285,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -333,9 +333,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -351,9 +351,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -370,9 +370,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -388,9 +388,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -414,9 +414,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -432,9 +432,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -450,9 +450,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -504,9 +504,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -524,9 +524,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -545,9 +545,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -571,9 +571,9 @@ this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -596,9 +596,9 @@ default: 4]: : ' \ '--status[Show "rtx: @" message when changing directories]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -616,9 +616,9 @@ default: 4]: : ' \ '--dry-run[List directories that would be removed without actually removing them]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -642,9 +642,9 @@ default: 4]: : ' \ '*--verbose[Show installation output]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtime(s) to install e.g.\: nodejs@18:' \ @@ -659,9 +659,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -688,9 +688,9 @@ e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions]' '--path[Get the path of the config file]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -716,9 +716,9 @@ default: 4]: : ' \ '--json[Output in json format]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -735,9 +735,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -756,9 +756,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -778,9 +778,9 @@ default: 4]: : ' \ '--urls[show the git url for each plugin]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -814,9 +814,9 @@ i.e.: they don'\''t need the full git repo url]' \ '*--verbose[Show installation output]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::name -- The name of the plugin to install @@ -843,9 +843,9 @@ e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -864,9 +864,9 @@ default: 4]: : ' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -882,9 +882,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -903,9 +903,9 @@ default: 4]: : ' \ '()--all[Update all plugins]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -967,9 +967,9 @@ default: 4]: : ' \ '--dry-run[Do not actually delete anything]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -986,9 +986,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1006,9 +1006,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1024,9 +1024,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -1050,9 +1050,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1069,9 +1069,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1087,9 +1087,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1107,9 +1107,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1168,9 +1168,9 @@ default: 4]: : ' \ '--unset[Removes a previously set version]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1187,9 +1187,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1206,9 +1206,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ @@ -1224,9 +1224,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1252,9 +1252,9 @@ default: 4]: : ' \ '(--plugin)--version[Show the version instead of the path]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ @@ -1271,9 +1271,9 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. -sets --jobs=1]' \ +Sets --jobs=1]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 23dbcd279..d4650f4e9 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -3,7 +3,7 @@ default: 4' -r complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_use_subcommand" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' @@ -48,7 +48,7 @@ complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rt complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' complete -c rtx -n "__fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r @@ -57,7 +57,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' @@ -72,7 +72,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r @@ -81,7 +81,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -89,7 +89,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -97,7 +97,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' @@ -112,7 +112,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -120,7 +120,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -128,7 +128,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' @@ -138,7 +138,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' @@ -149,7 +149,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from complete" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from complete" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -157,7 +157,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -165,7 +165,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -173,7 +173,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -187,7 +187,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -195,7 +195,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -203,7 +203,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file @@ -217,7 +217,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,xonsh ,zsh }" @@ -226,7 +226,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r @@ -235,7 +235,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r @@ -250,7 +250,7 @@ this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' complete -c rtx -n "__fish_seen_subcommand_from global" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,xonsh ,zsh }" @@ -260,7 +260,7 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set t complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -270,7 +270,7 @@ complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remo complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' complete -c rtx -n "__fish_seen_subcommand_from implode" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only install runtime(s) for ' -r @@ -282,14 +282,14 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r @@ -304,7 +304,7 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy v complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' complete -c rtx -n "__fish_seen_subcommand_from local" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r @@ -316,7 +316,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in a complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' complete -c rtx -n "__fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -324,7 +324,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -332,7 +332,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from mangen" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from mangen" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from mangen" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -342,7 +342,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' @@ -361,7 +361,7 @@ i.e.: they don\'t need the full git repo url' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r @@ -372,7 +372,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm e.g.: https://github.com/asdf-vm/asdf-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -382,7 +382,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -390,7 +390,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -399,7 +399,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' @@ -414,7 +414,7 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from prune" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from prune" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -422,7 +422,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -430,7 +430,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -438,7 +438,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -451,7 +451,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -459,7 +459,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -467,7 +467,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -475,7 +475,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' @@ -489,7 +489,7 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' complete -c rtx -n "__fish_seen_subcommand_from shell" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -497,7 +497,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -505,7 +505,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -513,7 +513,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -523,7 +523,7 @@ complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the pl complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -531,7 +531,7 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -sets --jobs=1' +Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index afdb56c4f..a973018bf 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -28,7 +28,7 @@ Set the log output verbosity .TP \fB\-r\fR, \fB\-\-raw\fR Directly pipe stdin/stdout/stderr to user. -sets \-\-jobs=1 +Sets \-\-jobs=1 .TP \fB\-v\fR, \fB\-\-verbose\fR Show installation output diff --git a/src/cli/args/raw.rs b/src/cli/args/raw.rs index fcc840987..60670c50a 100644 --- a/src/cli/args/raw.rs +++ b/src/cli/args/raw.rs @@ -7,7 +7,7 @@ impl Raw { Arg::new("raw") .short('r') .long("raw") - .help("Directly pipe stdin/stdout/stderr to user.\nsets --jobs=1") + .help("Directly pipe stdin/stdout/stderr to user.\nSets --jobs=1") .action(ArgAction::SetTrue) .global(true) } From 44f809390460447a100e5df4ae9fb161469b0b58 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 10:02:58 -0500 Subject: [PATCH 0484/1891] added editorconfig setting for Cargo.toml (#318) --- .editorconfig | 4 ++++ Cargo.toml | 17 +++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.editorconfig b/.editorconfig index ef9265582..7ff8aed42 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,6 @@ [*.sh] indent_style = tab + +[Cargo.toml] +indent_style = space +indent_size = 2 diff --git a/Cargo.toml b/Cargo.toml index c48757a1f..389f74fb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,9 +54,14 @@ once_cell = "1.17.0" owo-colors = { version = "3.5.0" } rayon = "1.7.0" regex = "1.7.1" -reqwest = { version = "0.11.14", default-features = false, features = ["blocking", "rustls-tls"] } +reqwest = { version = "0.11.14", default-features = false, features = [ + "blocking", + "rustls-tls", +] } rmp-serde = "1.1.1" -self_update = { version = "0.36.0", default-features = false, optional = true, features = ["rustls"] } +self_update = { version = "0.36.0", default-features = false, optional = true, features = [ + "rustls", +] } serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.92" @@ -99,10 +104,10 @@ sign-tag = true sign-commit = true pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ - { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, - { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, - { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, - { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, + { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, + { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, + { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, + { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, ] [package.metadata.binstall] From 5a6fbd53dd43a0fd84cfbebbb9bd7c7ffc90fad6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 11:01:12 -0500 Subject: [PATCH 0485/1891] bug: fix `rtx global` with `RTX_USE_TOML=1` (#320) Fixes #319 --- src/config/config_file/mod.rs | 4 +++- src/config/config_file/rtx_toml.rs | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 96d3cb6b7..b502effe7 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -124,7 +124,9 @@ impl dyn ConfigFile { } pub fn init(path: &Path) -> Box { - if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) || path.ends_with(".toml") { + if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) + || path.extension() == Some("toml".as_ref()) + { return Box::new(RtxToml::init(path)); } else if path.ends_with(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) { return Box::new(ToolVersions::init(path)); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index f72acd7d1..4ac393506 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -46,6 +46,10 @@ impl RtxToml { pub fn init(path: &Path) -> Self { Self { path: path.to_path_buf(), + toolset: Toolset { + source: Some(ToolSource::RtxToml(path.to_path_buf())), + ..Default::default() + }, ..Default::default() } } @@ -178,8 +182,7 @@ impl RtxToml { } fn parse_toolset(&self, key: &str, v: &Item) -> Result { - let source = ToolSource::RtxToml(self.path.clone()); - let mut toolset = Toolset::new(source); + let mut toolset = Toolset::new(self.toolset.source.clone().unwrap()); match v.as_table_like() { Some(table) => { From 49ca9c1e83cc05e578baf4ad09754dae4508da18 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 11:08:42 -0500 Subject: [PATCH 0486/1891] chore: Release rtx-cli version 1.23.5 --- Cargo.lock | 38 +++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 3 ++- 7 files changed, 28 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f8e76986..2284c76cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1156,9 +1156,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.25" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5308e8208729c3e1504a6cfad0d5daacc4614c9a2e65d1ea312a34b5cb00fe84" +checksum = "50686e0021c4136d1d453b2dfe059902278681512a34d4248435dc34b6b5c8ec" dependencies = [ "proc-macro2", ] @@ -1306,7 +1306,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.4" +version = "1.23.5" dependencies = [ "base64", "build-time", @@ -2106,9 +2106,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2121,45 +2121,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index 389f74fb4..8d438852a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.4" +version = "1.23.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 7d60e88aa..6f5ea5a03 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.4 +rtx 1.23.5 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.4/rtx-v1.23.4-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.5/rtx-v1.23.5-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 73ab4281b..a2dd36feb 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.4"; + version = "1.23.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a973018bf..c1971e38e 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.4" +.TH rtx 1 "rtx 1.23.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.4 +v1.23.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index aa5cdd0a4..f24cc0678 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.4 +Version: 1.23.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 37fa9895a..cc7e2f0c4 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 619] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 620] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -364,6 +364,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 619] = [ ("logtalk", "https://github.com/LogtalkDotOrg/asdf-logtalk.git"), ("loki-logcli", "https://github.com/comdotlinux/asdf-loki-logcli.git"), ("lua", "https://github.com/Stratus3D/asdf-lua.git"), + ("lua-language-server", "https://github.com/bellini666/asdf-lua-language-server"), ("luaJIT", "https://github.com/smashedtoatoms/asdf-luaJIT.git"), ("lucy", "https://github.com/cometkim/asdf-lucy.git"), ("mage", "https://github.com/mathew-fleisch/asdf-mage.git"), From 616e8ef1212292afb018124a3a83a25a1e60d9e5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 14:07:10 -0500 Subject: [PATCH 0487/1891] updated badge styles --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6f5ea5a03..6430b3b2f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # [rtx](https://github.com/jdxcode/rtx) -[![Crates.io](https://img.shields.io/crates/v/rtx-cli.svg)](https://crates.io/crates/rtx-cli) -[![License: MIT](https://img.shields.io/github/license/jdxcode/rtx)](https://github.com/jdxcode/rtx/blob/main/LICENSE) -[![CI](https://github.com/jdxcode/rtx/actions/workflows/rtx.yml/badge.svg?branch=main)](https://github.com/jdxcode/rtx/actions/workflows/rtx.yml) -[![Codecov](https://codecov.io/gh/jdxcode/rtx/branch/main/graph/badge.svg?token=XYH3Q0BOO0)](https://codecov.io/gh/jdxcode/rtx) -[![Discord](https://img.shields.io/discord/1066429325269794907)](https://discord.gg/mABnUDvP57) +

+Crates.io +GitHub +GitHub Workflow Status +CodecovDiscord _Polyglot runtime manager (asdf rust clone)_ From f99e7bf42d54b65037e5f39b9c535c7bd3e92f07 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 14:10:10 -0500 Subject: [PATCH 0488/1891] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6430b3b2f..455a250f3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -# [rtx](https://github.com/jdxcode/rtx) - -

+

+

rtx

Crates.io GitHub GitHub Workflow Status -CodecovDiscord - -_Polyglot runtime manager (asdf rust clone)_ +Codecov +Discord +

Polyglot runtime manager (asdf rust clone)

+
## 30 Second Demo From 56dca6404cac7656a3e9f5c05b316927a5b1c9b4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:19:41 -0500 Subject: [PATCH 0489/1891] readme formatting --- README.md | 67 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 455a250f3..1783351ca 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,7 @@ sudo apt install -y rtx > **Warning** > > If you're on arm64 you'll need to run the following: +> > ``` > echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` @@ -439,6 +440,7 @@ $ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ### Xonsh Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a bit off startup time by using a pure Python import: add the code below to, for example, `~/.config/xonsh/rtx.py` config file and `import rtx` it in `~/.config/xonsh/rc.xsh`: + ```xsh from pathlib import Path from xonsh.built_ins import XSH @@ -449,6 +451,7 @@ XSH.builtins.execx(rtx_init,'exec',ctx,filename='rtx') ``` Or continue to use `rc.xsh`/`.xonshrc`: + ```xsh echo 'execx($(~/bin/rtx activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xonshrc ``` @@ -470,10 +473,10 @@ Use `rtx implode` to uninstall rtx. This will remove the rtx binary and all of i Alternatively, manually remove the following directories to fully clean up: -* `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) -* `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) -* on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) -* on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) +- `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) +- `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) +- on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) +- on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) ## Configuration @@ -572,15 +575,15 @@ These settings can also be managed with `rtx settings ls|get|set|unset`. ### [experimental] `.rtx.toml` -`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` +`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` file. Think of `~/.config/rtx/config.toml` as just a special `.rtx.toml` which is used from any directory on the machine. It allows for functionality that is not possible with `.tool-versions`, such as: -* setting arbitrary env vars while inside the directory -* passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). -* specifying plugin repo url for custom plugins so it does not need to be added manually +- setting arbitrary env vars while inside the directory +- passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). +- specifying plugin repo url for custom plugins so it does not need to be added manually Here is what the config looks like: @@ -623,8 +626,8 @@ shims_dir = '~/.rtx/shims' my_custom_node = '18' ``` -`.rtx.toml` is currently experimental and may change in minor versions of rtx. It does not -require setting `experimental = true` in the global config in part because this config can +`.rtx.toml` is currently experimental and may change in minor versions of rtx. It does not +require setting `experimental = true` in the global config in part because this config can itself contain the setting for `experimental`. ### Environment variables @@ -675,7 +678,7 @@ for example, .nvmrc in the case of nodejs's nvm. #### `RTX_USE_TOML` -Set to `1` to use default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for +Set to `1` to use default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for configuration. #### `RTX_LOG_LEVEL=trace|debug|info|warn|error` @@ -733,7 +736,7 @@ installing plugins, e.g.: `rtx plugin install nodejs https://github.com/asdf-vm/ Currently this disables the following: -* `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) +- `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) #### `RTX_HIDE_OUTDATED_BUILD=1` @@ -811,11 +814,11 @@ Currently this only supports simple strings, but we can make it compatible with ## Versioning -rtx is currently a new project and is under very rapid development. Slight behavior changes may -occur between releases. +rtx is currently a new project and is under very rapid development. Slight behavior changes may +occur between releases. Features marked as "experimental" may change significantly or be removed entirely. -Starting June 1, 2023*, rtx will move to [Calver](https://calver.org/) versioning (`2023.6.1`). After the move to Calver, rtx's design will become mostly permanent and you will be able to rely on +Starting June 1, 2023\*, rtx will move to [Calver](https://calver.org/) versioning (`2023.6.1`). After the move to Calver, rtx's design will become mostly permanent and you will be able to rely on its behavior for the long term. Breaking changes will be few but when they do happen, they will be communicated in the CLI with plenty of notice whenever possible. @@ -829,23 +832,23 @@ The numbers in Calver (YYYY.MM.RELEASE) simply represent the date of the release or how many new features were added. Each release will be small and incremental. -_*This plan is tentative and the details may change, but the rough idea of making many changes now so we can have stability later is the goal._ +_\*This plan is tentative and the details may change, but the rough idea of making many changes now so we can have stability later is the goal._ ### Calver Breaking Changes -When we switch to Calver, we'll immediately make some notable design changes to rtx. This will -be the first and last time that such a change is made and I actually want to make sure we make +When we switch to Calver, we'll immediately make some notable design changes to rtx. This will +be the first and last time that such a change is made and I actually want to make sure we make as many as we can—because we'll be stuck with these decisions. Here are a list of the changes that will be made: -* `rtx local` will default to creating `.rtx.toml` instead of `.tool-versions`. (If the config +- `rtx local` will default to creating `.rtx.toml` instead of `.tool-versions`. (If the config already exists the format will be preserved.) -* `rtx global` will modify `~/.config/rtx/config.toml` instead of `~/.tool-versions`. This path +- `rtx global` will modify `~/.config/rtx/config.toml` instead of `~/.tool-versions`. This path can be changed with `RTX_CONFIG_FILE`. -* `~/.tool-versions` will become simply another `.tool-versions` instead of being a special file +- `~/.tool-versions` will become simply another `.tool-versions` instead of being a special file that is read anywhere such as from `/tmp`. -* (more to be added) +- (more to be added) ## Commands @@ -1816,21 +1819,21 @@ and see what happens. ### How compatible is rtx with asdf? -rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin +rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin should be usable in rtx. The commands in rtx are slightly -different, such as `rtx install nodejs@18.0.0` vs `asdf install nodejs 18.0.0`—this is done so +different, such as `rtx install nodejs@18.0.0` vs `asdf install nodejs 18.0.0`—this is done so multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx -install nodejs 18.0.0`). This is the case for most commands, though the help for the command may +install nodejs 18.0.0`). This is the case for most commands, though the help for the command may say that asdf-style syntax is supported. -When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may +When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may not be possible to support every command identically, but we should attempt to make things as consistent as possible. -This isn't important for usability reasons so much as making it so plugins continue to work that +This isn't important for usability reasons so much as making it so plugins continue to work that call asdf commands. -If you need to switch to/from asdf or work in a project with asdf users, you can set +If you need to switch to/from asdf or work in a project with asdf users, you can set [`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). That prevents rtx from writing `.tool-versions` files that will not be compatible with asdf. Also consider using `.rtx.toml` instead which won't conflict with asdf setups. @@ -2031,7 +2034,7 @@ to be updating, this is a good place to start. Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/`. It stores the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), -the list of aliases, the bin directories within each runtime installation, and the result of +the list of aliases, the bin directories within each runtime installation, and the result of running `exec-env` after the runtime was installed. Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is @@ -2041,11 +2044,11 @@ zlib messagepack, if you want to view it you can run the following (requires [ms cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` -Note that the caching of `exec-env` may be problematic if the script isn't simply exporting -static values. The vast majority of `exec-env` scripts only export static values, but if you're +Note that the caching of `exec-env` may be problematic if the script isn't simply exporting +static values. The vast majority of `exec-env` scripts only export static values, but if you're working with a plugin that has a dynamic `exec-env` submit a ticket and we can try to figure out what to do. -Caching `exec-env` massively improved the performance of rtx since it requires calling bash +Caching `exec-env` massively improved the performance of rtx since it requires calling bash every time rtx is initialized. Ideally, we can keep this behavior. From 15f0b88f6cea788fe1f4999efe7a386d6a1d188b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:21:01 -0500 Subject: [PATCH 0490/1891] put commands at end of readme --- README.md | 1698 ++++++++++++++++++++++++++--------------------------- 1 file changed, 849 insertions(+), 849 deletions(-) diff --git a/README.md b/README.md index 1783351ca..ee57b4e5a 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,27 @@ v18.10.9 - [Plugin Options](#plugin-options) - [Versioning](#versioning) - [Calver Breaking Changes](#calver-breaking-changes) +- [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) + - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) + - [Windows support?](#windows-support) + - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) + - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) + - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) + - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) + - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) +- [Comparison to asdf](#comparison-to-asdf) + - [Performance](#performance) + - [Environment variables in rtx](#environment-variables-in-rtx) + - [UX](#ux) + - [CI/CD](#cicd) + - [GitHub Actions](#github-actions) +- [Shims](#shims) +- [direnv](#direnv) + - [rtx inside of direnv (`use rtx` in `.envrc`)](#rtx-inside-of-direnv-use-rtx-in-envrc) + - [Do you need direnv?](#do-you-need-direnv) +- [Cache Behavior](#cache-behavior) + - [Plugin/Runtime Cache](#pluginruntime-cache) - [Commands](#commands) - [`rtx activate`](#rtx-activate) - [`rtx alias get`](#rtx-alias-get) @@ -149,27 +170,6 @@ v18.10.9 - [`rtx version`](#rtx-version) - [`rtx where`](#rtx-where) - [`rtx which`](#rtx-which) -- [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) - - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) - - [Windows support?](#windows-support) - - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) - - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) - - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) - - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) -- [Comparison to asdf](#comparison-to-asdf) - - [Performance](#performance) - - [Environment variables in rtx](#environment-variables-in-rtx) - - [UX](#ux) - - [CI/CD](#cicd) - - [GitHub Actions](#github-actions) -- [Shims](#shims) -- [direnv](#direnv) - - [rtx inside of direnv (`use rtx` in `.envrc`)](#rtx-inside-of-direnv-use-rtx-in-envrc) - - [Do you need direnv?](#do-you-need-direnv) -- [Cache Behavior](#cache-behavior) - - [Plugin/Runtime Cache](#pluginruntime-cache) @@ -850,1205 +850,1205 @@ Here are a list of the changes that will be made: that is read anywhere such as from `/tmp`. - (more to be added) - -## Commands - -### `rtx activate` +## FAQs -``` -Initializes rtx in the current shell +### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. -This should go into your shell's rc file. -Otherwise, it will only take effect in the current session. -(e.g. ~/.bashrc) +You can make git ignore these files in 3 different ways: -Usage: activate [OPTIONS] [SHELL_TYPE] +- Adding `.tool-versions` to project's `.gitignore` file. This has the downside that you need to commit the change to the ignore file. +- 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`. -Arguments: - [SHELL_TYPE] - Shell type to generate the script for - - [possible values: bash, fish, xonsh, zsh] +### rtx is failing or not working right -Options: - --status - Show "rtx: @" message when changing directories +First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. +You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. -Examples: - $ eval "$(rtx activate bash)" - $ eval "$(rtx activate zsh)" - $ rtx activate fish | source - $ execx($(rtx activate xonsh)) -``` -### `rtx alias get` +If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. +It can also be helpful to use `rtx env` which will just output environment variables that would be set. +Also consider using [shims](#shims) which can be more compatible. -``` -Show an alias for a plugin +If runtime installation isn't working right, try using the `--raw` flag which will install things in +series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact +with you for some reason this will make it work. -This is the contents of an alias. entry in ~/.config/rtx/config.toml +Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` +to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used +to remove everything except config. -Usage: get +Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule +out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` +doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. -Arguments: - - The plugin to show the alias for +Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues +detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. - - The alias to show +### Windows support? -Examples: - $ rtx alias get nodejs lts/hydrogen - 18.0.0 -``` -### `rtx alias ls` +This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 -``` -List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`. +It's not a near-term goal and it would require plugin modifications, but it should be feasible. -For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: +### How do I use rtx with http proxies? - [alias.nodejs] - lts = "18.0.0" +Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. -Usage: ls [OPTIONS] +rtx doesn't really do anything with http itself. The only exception to that is checking for new versions +and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download +files with `curl` or `wget`. -Options: - -p, --plugin - Show aliases for +However this is really up to the plugin. If you're having a proxy-related issue installing something +you should post an issue on the plugin's repo. -Examples: - $ rtx aliases - nodejs lts/hydrogen 18.0.0 -``` -### `rtx alias set` +### How do the shorthand plugin names map to repositories? -``` -Add/update an alias for a plugin +e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? -This modifies the contents of ~/.config/rtx/config.toml +asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. +This is regularly updated every time that rtx has a release. This repository is stored directly into +the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that +rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` +to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) +with some rtx features like virtualenv support. -Usage: set +Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific +enhancements. -Arguments: - - The plugin to set the alias for +### How do I migrate from asdf? - - The alias to set +First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your +shell rc file. - - The value to set the alias to +Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will +install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over +to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, +however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` +and see what happens. -Examples: - $ rtx alias set nodejs lts/hydrogen 18.0.0 -``` -### `rtx alias unset` +### How compatible is rtx with asdf? -``` -Clears an alias for a plugin +rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin +should be usable in rtx. The commands in rtx are slightly +different, such as `rtx install nodejs@18.0.0` vs `asdf install nodejs 18.0.0`—this is done so +multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx +install nodejs 18.0.0`). This is the case for most commands, though the help for the command may +say that asdf-style syntax is supported. -This modifies the contents of ~/.config/rtx/config.toml +When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may +not be possible to support every command identically, but +we should attempt to make things as consistent as possible. -Usage: unset +This isn't important for usability reasons so much as making it so plugins continue to work that +call asdf commands. -Arguments: - - The plugin to remove the alias from +If you need to switch to/from asdf or work in a project with asdf users, you can set +[`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). That prevents +rtx from writing `.tool-versions` files that will not be +compatible with asdf. Also consider using `.rtx.toml` instead which won't conflict with asdf setups. - - The alias to remove +### rtx isn't working with tmux -Examples: - $ rtx alias unset nodejs lts/hydrogen -``` -### `rtx bin-paths` +It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` +right after activating: +```bash +eval "$(rtx activate bash)" +eval "$(rtx hook-env)" ``` -List all the active runtime bin paths -Usage: bin-paths -``` -### `rtx cache clear` +This can also be useful if you need to use a runtime right away in an rc file. The default behavior +of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not +immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. -``` -Deletes all cache files in rtx +## Comparison to asdf -Usage: clear -``` -### `rtx complete` +rtx is mostly a clone of asdf, but there are notable areas where improvements have been made. -``` -Generate shell completions +### Performance -Usage: complete --shell +asdf made (what I consider) a poor design decision to use shims that go between a call to a runtime +and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, +which then calls `asdf exec`, which then calls the correct version of node. -Options: - -s, --shell - shell type - - [possible values: bash, elvish, fish, powershell, zsh] +These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead +updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo gif at the top of this README +that `rtx` isn't actually used when calling `node -v` for this reason. The performance is +identical to running node without using rtx. -Examples: - $ rtx complete -s bash > /etc/bash_completion.d/rtx - $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx - $ rtx complete -s fish > ~/.config/fish/completions/rtx.fish -``` -### `rtx current` +I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup +of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written +in bash which certainly makes it challenging to be performant, however I think the real problem is the +shim design. I don't think it's possible to fix that without a complete rewrite. -``` -Shows current active and installed runtime versions +rtx does call an internal command `rtx hook-env` every time the directory has changed, but because +it's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's +a full reload. -This is similar to `rtx ls --current`, but this only shows the runtime -and/or version. It's designed to fit into scripts more easily. +tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~10ms) +when the prompt loads. -Usage: current [PLUGIN] +### Environment variables in rtx -Arguments: - [PLUGIN] - Plugin to show versions of e.g.: ruby, nodejs +asdf only helps manage runtime executables. However, some tools are managed via environment variables +(notably Java which switches via `JAVA_HOME`). This isn't supported very well in asdf and requires +a separate shell extension just to manage. -Examples: - # outputs `.tool-versions` compatible format - $ rtx current - python 3.11.0 3.10.0 - shfmt 3.6.0 - shellcheck 0.9.0 - nodejs 18.13.0 - - $ rtx current nodejs - 18.13.0 +However asdf _plugins_ have a `bin/exec-env` script that is used for exporting environment variables +like [`JAVA_HOME`](https://github.com/halcyon/asdf-java/blob/master/bin/exec-env). rtx simply exports +the environment variables from the `bin/exec-env` script in the plugin but places them in the shell +for _all_ commands. In asdf it only exports those commands when the shim is called. This means if you +call `java` it will set `JAVA_HOME`, but not if you call some Java tool like `mvn`. - # can output multiple versions - $ rtx current python - 3.11.0 3.10.0 -``` -### `rtx deactivate` +This means we're just using the existing plugin script but because rtx doesn't use shims it can be +used for more things. It would be trivial to make a plugin that exports arbitrary environment +variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https://github.com/direnv/direnv). -``` -Disable rtx for current shell session +### UX -This can be used to temporarily disable rtx in a shell session. +Some commands are the same in asdf but others have been changed. Everything that's possible +in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, +such as using fuzzy-matching, e.g.: `rtx install nodejs@18`. While in asdf you _can_ run +`asdf install nodejs latest:18`, you can't use `latest:18` in a `.tool-versions` file or many other places. +In `rtx` you can use fuzzy-matching everywhere. -Usage: deactivate +asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: -Examples: - $ rtx deactivate bash - $ rtx deactivate zsh - $ rtx deactivate fish - $ execx($(rtx deactivate xonsh)) +```sh-session +$ asdf plugin add nodejs +$ asdf install nodejs latest:18 +$ asdf local nodejs latest:18 ``` -### `rtx direnv activate` -``` -Output direnv function to use rtx inside direnv +In `rtx` this can all be done in a single step to set the local runtime version. If the plugin +and/or runtime needs to be installed it will prompt: -See https://github.com/jdxcode/rtx#direnv for more information +[![asciicast](https://asciinema.org/a/564031.svg)](https://asciinema.org/a/564031) -Because this generates the legacy files based on currently installed plugins, -you should run this command after installing new plugins. Otherwise -direnv may not know to update environment variables when legacy file versions change. +I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like +having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). +`rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add nodejs` or +`rtx plugin install nodejs`. If I can guess what you meant, then I'll try to get rtx to respond +in the right way. -Usage: activate +That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there +and I've really been impressed with the plugin system. Most of the design decisions the authors made +were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. -Examples: - $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh - $ echo 'use rtx' > .envrc - $ direnv allow -``` -### `rtx doctor` +### CI/CD -``` -Check rtx installation for possible problems. +Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. -Usage: doctor +### GitHub Actions -Examples: - $ rtx doctor - [WARN] plugin nodejs is not installed -``` -### `rtx env` +Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): +```yaml +- uses: jdxcode/rtx-action@v1 +- run: node -v # will be the node version from `.tool-versions` ``` -Exports env vars to activate rtx a single time - -Use this if you don't want to permanently install rtx. It's not necessary to -use this if you have `rtx activate` in your shell rc file. -Usage: env [OPTIONS] [RUNTIME]... +## Shims -Arguments: - [RUNTIME]... - Runtime version to use +While the PATH design of rtx works great in most cases, there are some situations where shims are +preferable. One example is when calling rtx binaries from an IDE. -Options: - -s, --shell - Shell type to generate environment variables for - - [possible values: bash, fish, xonsh, zsh] +To support this, there is experimental support for using rtx in a "shim" mode. To use: -Examples: - $ eval "$(rtx env -s bash)" - $ eval "$(rtx env -s zsh)" - $ rtx env -s fish | source - $ execx($(rtx env -s xonsh)) ``` -### `rtx exec` - +$ rtx settings set experimental true +$ rtx settings set shims_dir ~/.rtx/shims +$ rtx i nodejs@18.0.0 +$ rtx reshim +$ ~/.rtx/shims/node -v +v18.0.0 ``` -Execute a command with runtime(s) set - -use this to avoid modifying the shell session or running ad-hoc commands with the rtx runtimes -set. -Runtimes will be loaded from .tool-versions, though they can be overridden with args -Note that only the plugin specified will be overridden, so if a `.tool-versions` file -includes "nodejs 18" but you run `rtx exec python@3.11`; it will still load nodejs@18. +## direnv -The "--" separates runtimes from the commands to pass along to the subprocess. +[direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze +the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. +As a result, there were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). +However, we think we've mitigated these. If you find that rtx and direnv are not working well together, +please comment on that ticket ideally with a good description of your directory layout so we can +reproduce the problem. -Usage: exec [OPTIONS] [RUNTIME]... [-- ...] +If there are remaining issues, they're likely to do with the ordering of PATH. This means it would +really only be a problem if you were trying to manage the same runtime with direnv and rtx. For example, +you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with python +in it as well. -Arguments: - [RUNTIME]... - Runtime(s) to start e.g.: nodejs@18 python@3.10 +A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated +binaries to PATH. In these cases, rtx will not interfere with direnv. - [COMMAND]... - Command string to execute (same as --command) +### rtx inside of direnv (`use rtx` in `.envrc`) -Options: - -c, --command - Command string to execute +If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, +this is a simpler setup that's less likely to cause issues—at the cost of functionality. -Examples: - rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x - rtx x nodejs@18 -- node ./app.js # shorter alias +This may be required if you want to use direnv's `layout python` with rtx. Otherwise there are +situations where rtx will override direnv's PATH. `use rtx` ensures that direnv always has control. - # Specify command as a string: - rtx exec nodejs@18 python@3.11 --command "node -v && python -V" -``` -### `rtx global` +To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: +```sh-session +$ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh ``` -Sets/gets the global runtime version(s) -Displays the contents of ~/.tool-versions after writing. -The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. -If `$RTX_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. -Otherwise, it will be parsed as a `.tool-versions` file. -A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. +Now in your `.envrc` file add the following: -Use `rtx local` to set a runtime version locally in the current directory. +```sh-session +use rtx +``` -Usage: global [OPTIONS] [RUNTIME]... +direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` +to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. -Arguments: - [RUNTIME]... - Runtime(s) to add to .tool-versions - e.g.: nodejs@18 - If this is a single runtime with no version, the current value of the global - .tool-versions will be displayed +Note that in this method direnv typically won't know to refresh `.tool-versions` files +unless they're at the same level as a `.envrc` file. You'll likely always want to have +a `.envrc` file next to your `.tool-versions` for this reason. To make this a little +easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead +setting environment variables entirely in `.envrc`: -Options: - --pin - Save exact version to `~/.tool-versions` - e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions +``` +export RTX_NODEJS_VERSION=18.0.0 +export RTX_PYTHON_VERSION=3.11 +``` - --fuzzy - Save fuzzy version to `~/.tool-versions` - e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions - this is the default behavior unless RTX_ASDF_COMPAT=1 +Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx +as if direnv was not used. - --remove - Remove the plugin(s) from ~/.tool-versions +If you continue to struggle, you can also try using the [experimental shims feature](#shims). - --path - Get the path of the global config file +### Do you need direnv? -Examples: - # set the current version of nodejs to 18.x - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx global --fuzzy nodejs@18 +While making rtx compatible with direnv is, and will always be a major goal of this project, I also +want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing +env vars and virtualenv for python using `.rtx.toml`. - # set the current version of nodejs to 18.x - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx global --pin nodejs@18 +If you find you continue to need direnv, please open an issue and let me know what it is to see if +it's something rtx could support. rtx will never be as capable as direnv with a DSL like `.envrc`, +but I think we can handle enough common use cases to make that unnecessary for most people. - # show the current version of nodejs in ~/.tool-versions - $ rtx global nodejs - 18.0.0 -``` -### `rtx implode` +## Cache Behavior -``` -Removes rtx CLI and all related data +rtx makes use of caching in many places in order to be efficient. The details about how long to keep +cache for should eventually all be configurable. There may be gaps in the current behavior where +things are hardcoded, but I'm happy to add more settings to cover whatever config is needed. -Skips config directory by default. +Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear +to be updating, this is a good place to start. -Usage: implode [OPTIONS] +### Plugin/Runtime Cache -Options: - --config - Also remove config directory +Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/`. It stores +the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), +the list of aliases, the bin directories within each runtime installation, and the result of +running `exec-env` after the runtime was installed. - --dry-run - List directories that would be removed without actually removing them -``` -### `rtx install` +Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is +zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). +```sh-session +cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` -Install a runtime - -This will install a runtime to `~/.local/share/rtx/installs//` -It won't be used simply by being installed, however. -For that, you must set up a `.tool-version` file manually or with `rtx local/global`. -Or you can call a runtime explicitly with `rtx exec @ -- `. - -Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` - -Usage: install [OPTIONS] [RUNTIME]... -Arguments: - [RUNTIME]... - Runtime(s) to install e.g.: nodejs@18 +Note that the caching of `exec-env` may be problematic if the script isn't simply exporting +static values. The vast majority of `exec-env` scripts only export static values, but if you're +working with a plugin that has a dynamic `exec-env` submit +a ticket and we can try to figure out what to do. -Options: - -p, --plugin - Only install runtime(s) for +Caching `exec-env` massively improved the performance of rtx since it requires calling bash +every time rtx is initialized. Ideally, we can keep this +behavior. - -f, --force - Force reinstall even if already installed + +## Commands - -v, --verbose... - Show installation output +### `rtx activate` -Examples: - $ rtx install nodejs@18.0.0 # install specific nodejs version - $ rtx install nodejs@18 # install fuzzy nodejs version - $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml - $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml ``` -### `rtx latest` +Initializes rtx in the current shell -``` -Gets the latest available version for a plugin +This should go into your shell's rc file. +Otherwise, it will only take effect in the current session. +(e.g. ~/.bashrc) -Usage: latest +Usage: activate [OPTIONS] [SHELL_TYPE] Arguments: - - Runtime to get the latest version of + [SHELL_TYPE] + Shell type to generate the script for + + [possible values: bash, fish, xonsh, zsh] -Examples: - $ rtx latest nodejs@18 # get the latest version of nodejs 18 - 18.0.0 +Options: + --status + Show "rtx: @" message when changing directories - $ rtx latest nodejs # get the latest stable version of nodejs - 20.0.0 +Examples: + $ eval "$(rtx activate bash)" + $ eval "$(rtx activate zsh)" + $ rtx activate fish | source + $ execx($(rtx activate xonsh)) ``` -### `rtx local` +### `rtx alias get` ``` -Sets/gets tool version in local .tool-versions or .rtx.toml +Show an alias for a plugin -Use this to set a tool's version when within a directory -Use `rtx global` to set a runtime version globally -This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` -is set. A future v2 release of rtx will default to using `.rtx.toml`. +This is the contents of an alias. entry in ~/.config/rtx/config.toml -Usage: local [OPTIONS] [RUNTIME]... +Usage: get Arguments: - [RUNTIME]... - Runtimes to add to .tool-versions/.rtx.toml - e.g.: nodejs@18 - if this is a single runtime with no version, - the current value of .tool-versions/.rtx.toml will be displayed - -Options: - -p, --parent - Recurse up to find a .tool-versions file rather than using the current directory only - by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") - - --pin - Save exact version to `.tool-versions` - e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions - - --fuzzy - Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 - - --remove - Remove the plugin(s) from .tool-versions + + The plugin to show the alias for - --path - Get the path of the config file + + The alias to show Examples: - # set the current version of nodejs to 18.x for the current directory - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx local nodejs@18 - - # set nodejs to 18.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@18 - - # set the current version of nodejs to 18.x for the current directory - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx local --fuzzy nodejs@18 - - # removes nodejs from .tool-versions - $ rtx local --remove=nodejs - - # show the current version of nodejs in .tool-versions - $ rtx local nodejs + $ rtx alias get nodejs lts/hydrogen 18.0.0 ``` -### `rtx ls` +### `rtx alias ls` ``` -List installed runtime versions - -The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. -(Assuming `rtx activate` or `rtx env` is in use). - -Usage: ls [OPTIONS] - -Options: - -p, --plugin - Only show runtimes from [PLUGIN] - - -c, --current - Only show runtimes currently specified in .tool-versions - - --parseable - Output in an easily parseable format - - [short aliases: x] - - --json - Output in json format - -Examples: - $ rtx ls - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) - python 3.10.0 +List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`. - $ rtx ls --current - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) +For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: - $ rtx ls --parseable - nodejs 18.0.0 - python 3.11.0 + [alias.nodejs] + lts = "18.0.0" - $ rtx ls --json - { - "nodejs": [ - { - "version": "18.0.0", - "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", - "source": { - "type": ".rtx.toml", - "path": "/Users/jdx/.rtx.toml" - } - } - ], - "python": [...] - } +Usage: ls [OPTIONS] + +Options: + -p, --plugin + Show aliases for + +Examples: + $ rtx aliases + nodejs lts/hydrogen 18.0.0 ``` -### `rtx ls-remote` +### `rtx alias set` ``` -List runtime versions available for install +Add/update an alias for a plugin -note that these versions are cached for commands like `rtx install nodejs@latest` -however _this_ command will always clear that cache and fetch the latest remote versions +This modifies the contents of ~/.config/rtx/config.toml -Usage: ls-remote [PREFIX] +Usage: set Arguments: - Plugin to get versions for - - [PREFIX] - The version prefix to use when querying the latest version - same as the first argument after the "@" + The plugin to set the alias for -Examples: - $ rtx ls-remote nodejs - 18.0.0 - 20.0.0 + + The alias to set - $ rtx ls-remote nodejs@18 - 18.0.0 - 18.1.0 + + The value to set the alias to - $ rtx ls-remote nodejs 18 - 18.0.0 - 18.1.0 +Examples: + $ rtx alias set nodejs lts/hydrogen 18.0.0 ``` -### `rtx plugins install` +### `rtx alias unset` ``` -Install a plugin - -note that rtx automatically can install plugins when you install a runtime -e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin +Clears an alias for a plugin -This behavior can be modified in ~/.config/rtx/config.toml +This modifies the contents of ~/.config/rtx/config.toml -Usage: install [OPTIONS] [NAME] [GIT_URL] +Usage: unset Arguments: - [NAME] - The name of the plugin to install - e.g.: nodejs, ruby - Can specify multiple plugins: `rtx plugins install nodejs ruby python` - - [GIT_URL] - The git url of the plugin - -Options: - -f, --force - Reinstall even if plugin exists - - -a, --all - Install all missing plugins - This will only install plugins that have matching shorthands. - i.e.: they don't need the full git repo url + + The plugin to remove the alias from - -v, --verbose... - Show installation output + + The alias to remove Examples: - # install the nodejs via shorthand - $ rtx plugins install nodejs + $ rtx alias unset nodejs lts/hydrogen +``` +### `rtx bin-paths` - # install the nodejs plugin using a specific git url - $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git +``` +List all the active runtime bin paths - # install the nodejs plugin using the git url only - # (nodejs is inferred from the url) - $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git +Usage: bin-paths +``` +### `rtx cache clear` - # install the nodejs plugin using a specific ref - $ rtx plugins install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 ``` -### `rtx plugins ls` +Deletes all cache files in rtx +Usage: clear ``` -List installed plugins +### `rtx complete` -Can also show remotely available plugins to install. +``` +Generate shell completions -Usage: ls [OPTIONS] +Usage: complete --shell Options: - -a, --all - List all available remote plugins - Same as `rtx plugins ls-remote` - - -u, --urls - Show the git url for each plugin - e.g.: https://github.com/asdf-vm/asdf-nodejs.git + -s, --shell + shell type + + [possible values: bash, elvish, fish, powershell, zsh] Examples: - $ rtx plugins ls - nodejs - ruby - - $ rtx plugins ls --urls - nodejs https://github.com/asdf-vm/asdf-nodejs.git - ruby https://github.com/asdf-vm/asdf-ruby.git + $ rtx complete -s bash > /etc/bash_completion.d/rtx + $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx + $ rtx complete -s fish > ~/.config/fish/completions/rtx.fish ``` -### `rtx plugins ls-remote` +### `rtx current` ``` -List all available remote plugins +Shows current active and installed runtime versions -These are fetched from https://github.com/asdf-vm/asdf-plugins +This is similar to `rtx ls --current`, but this only shows the runtime +and/or version. It's designed to fit into scripts more easily. -Examples: - $ rtx plugins ls-remote +Usage: current [PLUGIN] +Arguments: + [PLUGIN] + Plugin to show versions of e.g.: ruby, nodejs -Usage: ls-remote [OPTIONS] +Examples: + # outputs `.tool-versions` compatible format + $ rtx current + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + nodejs 18.13.0 -Options: - -u, --urls - Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git + $ rtx current nodejs + 18.13.0 - --only-names - Only show the name of each plugin by default it will show a "*" next to installed plugins + # can output multiple versions + $ rtx current python + 3.11.0 3.10.0 ``` -### `rtx plugins uninstall` +### `rtx deactivate` ``` -Removes a plugin +Disable rtx for current shell session -Usage: uninstall ... +This can be used to temporarily disable rtx in a shell session. -Arguments: - ... - Plugin(s) to remove +Usage: deactivate Examples: - $ rtx uninstall nodejs + $ rtx deactivate bash + $ rtx deactivate zsh + $ rtx deactivate fish + $ execx($(rtx deactivate xonsh)) ``` -### `rtx plugins update` +### `rtx direnv activate` ``` -Updates a plugin to the latest version +Output direnv function to use rtx inside direnv -note: this updates the plugin itself, not the runtime versions +See https://github.com/jdxcode/rtx#direnv for more information -Usage: update [OPTIONS] [PLUGIN]... +Because this generates the legacy files based on currently installed plugins, +you should run this command after installing new plugins. Otherwise +direnv may not know to update environment variables when legacy file versions change. -Arguments: - [PLUGIN]... - Plugin(s) to update +Usage: activate -Options: - -a, --all - Update all plugins +Examples: + $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh + $ echo 'use rtx' > .envrc + $ direnv allow +``` +### `rtx doctor` + +``` +Check rtx installation for possible problems. + +Usage: doctor Examples: - $ rtx plugins update --all # update all plugins - $ rtx plugins update nodejs # update only nodejs - $ rtx plugins update nodejs@beta # specify a ref + $ rtx doctor + [WARN] plugin nodejs is not installed ``` -### `rtx prune` +### `rtx env` ``` -Delete unused versions of tools +Exports env vars to activate rtx a single time -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`). +Use this if you don't want to permanently install rtx. It's not necessary to +use this if you have `rtx activate` in your shell rc file. -Usage: prune [OPTIONS] [PLUGINS]... +Usage: env [OPTIONS] [RUNTIME]... Arguments: - [PLUGINS]... - Prune only versions from these plugins + [RUNTIME]... + Runtime version to use Options: - --dry-run - Do not actually delete anything + -s, --shell + Shell type to generate environment variables for + + [possible values: bash, fish, xonsh, zsh] Examples: - $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 + $ eval "$(rtx env -s bash)" + $ eval "$(rtx env -s zsh)" + $ rtx env -s fish | source + $ execx($(rtx env -s xonsh)) ``` -### `rtx reshim` +### `rtx exec` ``` -[experimental] rebuilds the shim farm +Execute a command with runtime(s) set -this requires that the shims_dir is set +use this to avoid modifying the shell session or running ad-hoc commands with the rtx runtimes +set. -Usage: reshim +Runtimes will be loaded from .tool-versions, though they can be overridden with args +Note that only the plugin specified will be overridden, so if a `.tool-versions` file +includes "nodejs 18" but you run `rtx exec python@3.11`; it will still load nodejs@18. -Examples: - $ rtx settings set experimental true - $ rtx settings set shims_dir ~/.rtx/shims - $ rtx reshim - $ ~/.rtx/shims/node -v - v18.0.0 -``` -### `rtx self-update` +The "--" separates runtimes from the commands to pass along to the subprocess. + +Usage: exec [OPTIONS] [RUNTIME]... [-- ...] + +Arguments: + [RUNTIME]... + Runtime(s) to start e.g.: nodejs@18 python@3.10 + + [COMMAND]... + Command string to execute (same as --command) -``` -Updates rtx itself +Options: + -c, --command + Command string to execute -Uses whatever package manager was used to install rtx or just downloads -a binary from GitHub Releases if rtx was installed manually. -Supports: standalone, brew, deb, rpm +Examples: + rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x + rtx x nodejs@18 -- node ./app.js # shorter alias -Usage: self-update + # Specify command as a string: + rtx exec nodejs@18 python@3.11 --command "node -v && python -V" ``` -### `rtx settings get` +### `rtx global` ``` -Show a current setting +Sets/gets the global runtime version(s) -This is the contents of a single entry in ~/.config/rtx/config.toml +Displays the contents of ~/.tool-versions after writing. +The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. +If `$RTX_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. +Otherwise, it will be parsed as a `.tool-versions` file. +A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. -Note that aliases are also stored in this file -but managed separately with `rtx aliases get` +Use `rtx local` to set a runtime version locally in the current directory. -Usage: get +Usage: global [OPTIONS] [RUNTIME]... Arguments: - - The setting to show + [RUNTIME]... + Runtime(s) to add to .tool-versions + e.g.: nodejs@18 + If this is a single runtime with no version, the current value of the global + .tool-versions will be displayed + +Options: + --pin + Save exact version to `~/.tool-versions` + e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions + + --fuzzy + Save fuzzy version to `~/.tool-versions` + e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions + this is the default behavior unless RTX_ASDF_COMPAT=1 + + --remove + Remove the plugin(s) from ~/.tool-versions + + --path + Get the path of the global config file Examples: - $ rtx settings get legacy_version_file - true + # set the current version of nodejs to 18.x + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx global --fuzzy nodejs@18 + + # set the current version of nodejs to 18.x + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx global --pin nodejs@18 + + # show the current version of nodejs in ~/.tool-versions + $ rtx global nodejs + 18.0.0 ``` -### `rtx settings ls` +### `rtx implode` ``` -Show current settings +Removes rtx CLI and all related data -This is the contents of ~/.config/rtx/config.toml +Skips config directory by default. -Note that aliases are also stored in this file -but managed separately with `rtx aliases` +Usage: implode [OPTIONS] -Usage: ls +Options: + --config + Also remove config directory -Examples: - $ rtx settings - legacy_version_file = false + --dry-run + List directories that would be removed without actually removing them ``` -### `rtx settings set` +### `rtx install` ``` -Add/update a setting +Install a runtime -This modifies the contents of ~/.config/rtx/config.toml +This will install a runtime to `~/.local/share/rtx/installs//` +It won't be used simply by being installed, however. +For that, you must set up a `.tool-version` file manually or with `rtx local/global`. +Or you can call a runtime explicitly with `rtx exec @ -- `. -Usage: set +Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` + +Usage: install [OPTIONS] [RUNTIME]... Arguments: - - The setting to set + [RUNTIME]... + Runtime(s) to install e.g.: nodejs@18 - - The value to set +Options: + -p, --plugin + Only install runtime(s) for + + -f, --force + Force reinstall even if already installed + + -v, --verbose... + Show installation output Examples: - $ rtx settings set legacy_version_file true + $ rtx install nodejs@18.0.0 # install specific nodejs version + $ rtx install nodejs@18 # install fuzzy nodejs version + $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml + $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml ``` -### `rtx settings unset` +### `rtx latest` ``` -Clears a setting - -This modifies the contents of ~/.config/rtx/config.toml +Gets the latest available version for a plugin -Usage: unset +Usage: latest Arguments: - - The setting to remove + + Runtime to get the latest version of Examples: - $ rtx settings unset legacy_version_file + $ rtx latest nodejs@18 # get the latest version of nodejs 18 + 18.0.0 + + $ rtx latest nodejs # get the latest stable version of nodejs + 20.0.0 ``` -### `rtx shell` +### `rtx local` ``` -Sets a tool version for the current shell session +Sets/gets tool version in local .tool-versions or .rtx.toml -Only works in a session where rtx is already activated. +Use this to set a tool's version when within a directory +Use `rtx global` to set a runtime version globally +This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` +is set. A future v2 release of rtx will default to using `.rtx.toml`. -Usage: shell [OPTIONS] [RUNTIME]... +Usage: local [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - Runtime version(s) to use + Runtimes to add to .tool-versions/.rtx.toml + e.g.: nodejs@18 + if this is a single runtime with no version, + the current value of .tool-versions/.rtx.toml will be displayed Options: - -u, --unset - Removes a previously set version + -p, --parent + Recurse up to find a .tool-versions file rather than using the current directory only + by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") -Examples: - $ rtx shell nodejs@18 - $ node -v - v18.0.0 -``` -### `rtx uninstall` + --pin + Save exact version to `.tool-versions` + e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions -``` -Removes runtime versions + --fuzzy + Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 -Usage: uninstall ... + --remove + Remove the plugin(s) from .tool-versions -Arguments: - ... - Runtime(s) to remove + --path + Get the path of the config file Examples: - $ rtx uninstall nodejs@18.0.0 # will uninstall specific version - $ rtx uninstall nodejs # will uninstall current nodejs version -``` -### `rtx version` + # set the current version of nodejs to 18.x for the current directory + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx local nodejs@18 -``` -Show rtx version + # set nodejs to 18.x for the current project (recurses up to find .tool-versions) + $ rtx local -p nodejs@18 -Usage: version + # set the current version of nodejs to 18.x for the current directory + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx local --fuzzy nodejs@18 + + # removes nodejs from .tool-versions + $ rtx local --remove=nodejs + + # show the current version of nodejs in .tool-versions + $ rtx local nodejs + 18.0.0 ``` -### `rtx where` +### `rtx ls` ``` -Display the installation path for a runtime +List installed runtime versions -Must be installed. +The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. +(Assuming `rtx activate` or `rtx env` is in use). -Usage: where +Usage: ls [OPTIONS] -Arguments: - - Runtime(s) to look up - e.g.: ruby@3 - if "@" is specified, it will show the latest installed version - that matches the prefix - otherwise, it will show the current, active installed version +Options: + -p, --plugin + Only show runtimes from [PLUGIN] + + -c, --current + Only show runtimes currently specified in .tool-versions + + --parseable + Output in an easily parseable format + + [short aliases: x] + + --json + Output in json format Examples: - # Show the latest installed version of nodejs - # If it is is not installed, errors - $ rtx where nodejs@18 - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 + $ rtx ls + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) + python 3.10.0 - # Show the current, active install directory of nodejs - # Errors if nodejs is not referenced in any .tool-version file - $ rtx where nodejs - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 + $ rtx ls --current + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) + + $ rtx ls --parseable + nodejs 18.0.0 + python 3.11.0 + + $ rtx ls --json + { + "nodejs": [ + { + "version": "18.0.0", + "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", + "source": { + "type": ".rtx.toml", + "path": "/Users/jdx/.rtx.toml" + } + } + ], + "python": [...] + } ``` -### `rtx which` +### `rtx ls-remote` ``` -Shows the path that a bin name points to +List runtime versions available for install -Usage: which [OPTIONS] +note that these versions are cached for commands like `rtx install nodejs@latest` +however _this_ command will always clear that cache and fetch the latest remote versions -Arguments: - - +Usage: ls-remote [PREFIX] -Options: - --plugin - Show the plugin name instead of the path +Arguments: + + Plugin to get versions for - --version - Show the version instead of the path + [PREFIX] + The version prefix to use when querying the latest version + same as the first argument after the "@" Examples: - $ rtx which node - /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node - $ rtx which node --plugin - nodejs - $ rtx which node --version + $ rtx ls-remote nodejs 18.0.0 -``` - + 20.0.0 -## FAQs + $ rtx ls-remote nodejs@18 + 18.0.0 + 18.1.0 -### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. + $ rtx ls-remote nodejs 18 + 18.0.0 + 18.1.0 +``` +### `rtx plugins install` -You can make git ignore these files in 3 different ways: +``` +Install a plugin -- Adding `.tool-versions` to project's `.gitignore` file. This has the downside that you need to commit the change to the ignore file. -- 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`. +note that rtx automatically can install plugins when you install a runtime +e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin -### rtx is failing or not working right +This behavior can be modified in ~/.config/rtx/config.toml -First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. -You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. +Usage: install [OPTIONS] [NAME] [GIT_URL] -If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. -It can also be helpful to use `rtx env` which will just output environment variables that would be set. -Also consider using [shims](#shims) which can be more compatible. +Arguments: + [NAME] + The name of the plugin to install + e.g.: nodejs, ruby + Can specify multiple plugins: `rtx plugins install nodejs ruby python` -If runtime installation isn't working right, try using the `--raw` flag which will install things in -series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact -with you for some reason this will make it work. + [GIT_URL] + The git url of the plugin -Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` -to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used -to remove everything except config. +Options: + -f, --force + Reinstall even if plugin exists -Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule -out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` -doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. + -a, --all + Install all missing plugins + This will only install plugins that have matching shorthands. + i.e.: they don't need the full git repo url -Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues -detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. + -v, --verbose... + Show installation output -### Windows support? +Examples: + # install the nodejs via shorthand + $ rtx plugins install nodejs -This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 + # install the nodejs plugin using a specific git url + $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git -It's not a near-term goal and it would require plugin modifications, but it should be feasible. + # install the nodejs plugin using the git url only + # (nodejs is inferred from the url) + $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git -### How do I use rtx with http proxies? + # install the nodejs plugin using a specific ref + $ rtx plugins install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 +``` +### `rtx plugins ls` -Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. +``` +List installed plugins -rtx doesn't really do anything with http itself. The only exception to that is checking for new versions -and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download -files with `curl` or `wget`. +Can also show remotely available plugins to install. -However this is really up to the plugin. If you're having a proxy-related issue installing something -you should post an issue on the plugin's repo. +Usage: ls [OPTIONS] -### How do the shorthand plugin names map to repositories? +Options: + -a, --all + List all available remote plugins + Same as `rtx plugins ls-remote` -e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? + -u, --urls + Show the git url for each plugin + e.g.: https://github.com/asdf-vm/asdf-nodejs.git -asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. -This is regularly updated every time that rtx has a release. This repository is stored directly into -the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that -rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` -to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) -with some rtx features like virtualenv support. +Examples: + $ rtx plugins ls + nodejs + ruby -Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific -enhancements. + $ rtx plugins ls --urls + nodejs https://github.com/asdf-vm/asdf-nodejs.git + ruby https://github.com/asdf-vm/asdf-ruby.git +``` +### `rtx plugins ls-remote` -### How do I migrate from asdf? +``` +List all available remote plugins -First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your -shell rc file. +These are fetched from https://github.com/asdf-vm/asdf-plugins -Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will -install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over -to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, -however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` -and see what happens. +Examples: + $ rtx plugins ls-remote -### How compatible is rtx with asdf? -rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin -should be usable in rtx. The commands in rtx are slightly -different, such as `rtx install nodejs@18.0.0` vs `asdf install nodejs 18.0.0`—this is done so -multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx -install nodejs 18.0.0`). This is the case for most commands, though the help for the command may -say that asdf-style syntax is supported. +Usage: ls-remote [OPTIONS] -When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may -not be possible to support every command identically, but -we should attempt to make things as consistent as possible. +Options: + -u, --urls + Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git -This isn't important for usability reasons so much as making it so plugins continue to work that -call asdf commands. + --only-names + Only show the name of each plugin by default it will show a "*" next to installed plugins +``` +### `rtx plugins uninstall` -If you need to switch to/from asdf or work in a project with asdf users, you can set -[`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). That prevents -rtx from writing `.tool-versions` files that will not be -compatible with asdf. Also consider using `.rtx.toml` instead which won't conflict with asdf setups. +``` +Removes a plugin -### rtx isn't working with tmux +Usage: uninstall ... -It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` -right after activating: +Arguments: + ... + Plugin(s) to remove -```bash -eval "$(rtx activate bash)" -eval "$(rtx hook-env)" +Examples: + $ rtx uninstall nodejs ``` +### `rtx plugins update` -This can also be useful if you need to use a runtime right away in an rc file. The default behavior -of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not -immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. +``` +Updates a plugin to the latest version -## Comparison to asdf +note: this updates the plugin itself, not the runtime versions -rtx is mostly a clone of asdf, but there are notable areas where improvements have been made. +Usage: update [OPTIONS] [PLUGIN]... -### Performance +Arguments: + [PLUGIN]... + Plugin(s) to update -asdf made (what I consider) a poor design decision to use shims that go between a call to a runtime -and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, -which then calls `asdf exec`, which then calls the correct version of node. +Options: + -a, --all + Update all plugins -These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead -updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo gif at the top of this README -that `rtx` isn't actually used when calling `node -v` for this reason. The performance is -identical to running node without using rtx. +Examples: + $ rtx plugins update --all # update all plugins + $ rtx plugins update nodejs # update only nodejs + $ rtx plugins update nodejs@beta # specify a ref +``` +### `rtx prune` -I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup -of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written -in bash which certainly makes it challenging to be performant, however I think the real problem is the -shim design. I don't think it's possible to fix that without a complete rewrite. +``` +Delete unused versions of tools -rtx does call an internal command `rtx hook-env` every time the directory has changed, but because -it's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's -a full reload. +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`). -tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~10ms) -when the prompt loads. +Usage: prune [OPTIONS] [PLUGINS]... -### Environment variables in rtx +Arguments: + [PLUGINS]... + Prune only versions from these plugins -asdf only helps manage runtime executables. However, some tools are managed via environment variables -(notably Java which switches via `JAVA_HOME`). This isn't supported very well in asdf and requires -a separate shell extension just to manage. +Options: + --dry-run + Do not actually delete anything -However asdf _plugins_ have a `bin/exec-env` script that is used for exporting environment variables -like [`JAVA_HOME`](https://github.com/halcyon/asdf-java/blob/master/bin/exec-env). rtx simply exports -the environment variables from the `bin/exec-env` script in the plugin but places them in the shell -for _all_ commands. In asdf it only exports those commands when the shim is called. This means if you -call `java` it will set `JAVA_HOME`, but not if you call some Java tool like `mvn`. +Examples: + $ rtx prune --dry-run + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 +``` +### `rtx reshim` -This means we're just using the existing plugin script but because rtx doesn't use shims it can be -used for more things. It would be trivial to make a plugin that exports arbitrary environment -variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https://github.com/direnv/direnv). +``` +[experimental] rebuilds the shim farm -### UX +this requires that the shims_dir is set -Some commands are the same in asdf but others have been changed. Everything that's possible -in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, -such as using fuzzy-matching, e.g.: `rtx install nodejs@18`. While in asdf you _can_ run -`asdf install nodejs latest:18`, you can't use `latest:18` in a `.tool-versions` file or many other places. -In `rtx` you can use fuzzy-matching everywhere. +Usage: reshim -asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: +Examples: + $ rtx settings set experimental true + $ rtx settings set shims_dir ~/.rtx/shims + $ rtx reshim + $ ~/.rtx/shims/node -v + v18.0.0 +``` +### `rtx self-update` -```sh-session -$ asdf plugin add nodejs -$ asdf install nodejs latest:18 -$ asdf local nodejs latest:18 ``` +Updates rtx itself -In `rtx` this can all be done in a single step to set the local runtime version. If the plugin -and/or runtime needs to be installed it will prompt: +Uses whatever package manager was used to install rtx or just downloads +a binary from GitHub Releases if rtx was installed manually. +Supports: standalone, brew, deb, rpm -[![asciicast](https://asciinema.org/a/564031.svg)](https://asciinema.org/a/564031) +Usage: self-update +``` +### `rtx settings get` -I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like -having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). -`rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add nodejs` or -`rtx plugin install nodejs`. If I can guess what you meant, then I'll try to get rtx to respond -in the right way. +``` +Show a current setting -That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there -and I've really been impressed with the plugin system. Most of the design decisions the authors made -were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. +This is the contents of a single entry in ~/.config/rtx/config.toml -### CI/CD +Note that aliases are also stored in this file +but managed separately with `rtx aliases get` -Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. +Usage: get -### GitHub Actions +Arguments: + + The setting to show -Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): +Examples: + $ rtx settings get legacy_version_file + true +``` +### `rtx settings ls` -```yaml -- uses: jdxcode/rtx-action@v1 -- run: node -v # will be the node version from `.tool-versions` ``` +Show current settings -## Shims +This is the contents of ~/.config/rtx/config.toml -While the PATH design of rtx works great in most cases, there are some situations where shims are -preferable. One example is when calling rtx binaries from an IDE. +Note that aliases are also stored in this file +but managed separately with `rtx aliases` -To support this, there is experimental support for using rtx in a "shim" mode. To use: +Usage: ls +Examples: + $ rtx settings + legacy_version_file = false ``` -$ rtx settings set experimental true -$ rtx settings set shims_dir ~/.rtx/shims -$ rtx i nodejs@18.0.0 -$ rtx reshim -$ ~/.rtx/shims/node -v -v18.0.0 +### `rtx settings set` + ``` +Add/update a setting -## direnv +This modifies the contents of ~/.config/rtx/config.toml -[direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze -the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. -As a result, there were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). -However, we think we've mitigated these. If you find that rtx and direnv are not working well together, -please comment on that ticket ideally with a good description of your directory layout so we can -reproduce the problem. +Usage: set -If there are remaining issues, they're likely to do with the ordering of PATH. This means it would -really only be a problem if you were trying to manage the same runtime with direnv and rtx. For example, -you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with python -in it as well. +Arguments: + + The setting to set -A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated -binaries to PATH. In these cases, rtx will not interfere with direnv. + + The value to set -### rtx inside of direnv (`use rtx` in `.envrc`) +Examples: + $ rtx settings set legacy_version_file true +``` +### `rtx settings unset` -If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, -this is a simpler setup that's less likely to cause issues—at the cost of functionality. +``` +Clears a setting -This may be required if you want to use direnv's `layout python` with rtx. Otherwise there are -situations where rtx will override direnv's PATH. `use rtx` ensures that direnv always has control. +This modifies the contents of ~/.config/rtx/config.toml -To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: +Usage: unset -```sh-session -$ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh -``` +Arguments: + + The setting to remove -Now in your `.envrc` file add the following: +Examples: + $ rtx settings unset legacy_version_file +``` +### `rtx shell` -```sh-session -use rtx ``` +Sets a tool version for the current shell session -direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` -to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. +Only works in a session where rtx is already activated. -Note that in this method direnv typically won't know to refresh `.tool-versions` files -unless they're at the same level as a `.envrc` file. You'll likely always want to have -a `.envrc` file next to your `.tool-versions` for this reason. To make this a little -easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead -setting environment variables entirely in `.envrc`: +Usage: shell [OPTIONS] [RUNTIME]... + +Arguments: + [RUNTIME]... + Runtime version(s) to use + +Options: + -u, --unset + Removes a previously set version +Examples: + $ rtx shell nodejs@18 + $ node -v + v18.0.0 ``` -export RTX_NODEJS_VERSION=18.0.0 -export RTX_PYTHON_VERSION=3.11 +### `rtx uninstall` + ``` +Removes runtime versions -Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx -as if direnv was not used. +Usage: uninstall ... -If you continue to struggle, you can also try using the [experimental shims feature](#shims). +Arguments: + ... + Runtime(s) to remove -### Do you need direnv? +Examples: + $ rtx uninstall nodejs@18.0.0 # will uninstall specific version + $ rtx uninstall nodejs # will uninstall current nodejs version +``` +### `rtx version` -While making rtx compatible with direnv is, and will always be a major goal of this project, I also -want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing -env vars and virtualenv for python using `.rtx.toml`. +``` +Show rtx version -If you find you continue to need direnv, please open an issue and let me know what it is to see if -it's something rtx could support. rtx will never be as capable as direnv with a DSL like `.envrc`, -but I think we can handle enough common use cases to make that unnecessary for most people. +Usage: version +``` +### `rtx where` -## Cache Behavior +``` +Display the installation path for a runtime -rtx makes use of caching in many places in order to be efficient. The details about how long to keep -cache for should eventually all be configurable. There may be gaps in the current behavior where -things are hardcoded, but I'm happy to add more settings to cover whatever config is needed. +Must be installed. -Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear -to be updating, this is a good place to start. +Usage: where -### Plugin/Runtime Cache +Arguments: + + Runtime(s) to look up + e.g.: ruby@3 + if "@" is specified, it will show the latest installed version + that matches the prefix + otherwise, it will show the current, active installed version -Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/`. It stores -the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), -the list of aliases, the bin directories within each runtime installation, and the result of -running `exec-env` after the runtime was installed. +Examples: + # Show the latest installed version of nodejs + # If it is is not installed, errors + $ rtx where nodejs@18 + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 -Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is -zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). + # Show the current, active install directory of nodejs + # Errors if nodejs is not referenced in any .tool-version file + $ rtx where nodejs + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 +``` +### `rtx which` -```sh-session -cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` +Shows the path that a bin name points to -Note that the caching of `exec-env` may be problematic if the script isn't simply exporting -static values. The vast majority of `exec-env` scripts only export static values, but if you're -working with a plugin that has a dynamic `exec-env` submit -a ticket and we can try to figure out what to do. +Usage: which [OPTIONS] -Caching `exec-env` massively improved the performance of rtx since it requires calling bash -every time rtx is initialized. Ideally, we can keep this -behavior. +Arguments: + + + +Options: + --plugin + Show the plugin name instead of the path + + --version + Show the version instead of the path + +Examples: + $ rtx which node + /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node + $ rtx which node --plugin + nodejs + $ rtx which node --version + 18.0.0 +``` + From 9b3dff4d917d66dd50a37dedb7feafcdd64280b2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 08:26:48 -0500 Subject: [PATCH 0491/1891] bug: fix "fatal alert BadCertificate" This makes the version check use http instead of https to avoid certificate issues. This just has the version number so there isn't a security risk of a MITM attack here. It also makes the version update only check once per day in the case of failure or success, before it was just success. --- src/cli/version.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index bb475c07d..bf7181932 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -93,10 +93,10 @@ fn get_latest_version() -> Option { } } } - let version = get_latest_version_call()?; let _ = fs::create_dir_all(&*dirs::CACHE); - let _ = fs::write(version_file_path, &version); - Some(version) + let version = get_latest_version_call(); + let _ = fs::write(version_file_path, version.clone().unwrap_or_default()); + version } #[cfg(test)] @@ -106,10 +106,10 @@ fn get_latest_version_call() -> Option { #[cfg(not(test))] fn get_latest_version_call() -> Option { - const URL: &str = "https://rtx.pub/VERSION"; + const URL: &str = "http://rtx.pub/VERSION"; debug!("checking for version from {}", URL); reqwest::blocking::ClientBuilder::new() - .timeout(Duration::from_secs(2)) + .timeout(Duration::from_secs(5)) .user_agent(format!("rtx/{}", env!("CARGO_PKG_VERSION"))) .build() .ok()? From fa007987cd3a123149c17bf285be6390e572be6b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 08:39:30 -0500 Subject: [PATCH 0492/1891] chore: Release rtx-cli version 1.23.6 --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2284c76cd..98d5913aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1156,9 +1156,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50686e0021c4136d1d453b2dfe059902278681512a34d4248435dc34b6b5c8ec" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -1306,7 +1306,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.5" +version = "1.23.6" dependencies = [ "base64", "build-time", @@ -1453,15 +1453,15 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.155" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" +checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" [[package]] name = "serde_derive" -version = "1.0.155" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" +checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" dependencies = [ "proc-macro2", "quote", @@ -1768,9 +1768,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" dependencies = [ "serde", "serde_spanned", @@ -1789,9 +1789,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.5" +version = "0.19.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7082a95d48029677a28f181e5f6422d0c8339ad8396a39d3f33d62a90c1f6c30" +checksum = "08de71aa0d6e348f070457f85af8bd566e2bc452156a423ddf22861b3a953fae" dependencies = [ "indexmap", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8d438852a..e1e753099 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.5" +version = "1.23.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index ee57b4e5a..e96ac9739 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.5 +rtx 1.23.6 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.5/rtx-v1.23.5-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.6/rtx-v1.23.6-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index a2dd36feb..7750f20c3 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.5"; + version = "1.23.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c1971e38e..5b962bfa0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.5" +.TH rtx 1 "rtx 1.23.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.5 +v1.23.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f24cc0678..f844be04a 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.5 +Version: 1.23.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 586c23db10666f0d313f5dfe9dd653ec0cd08130 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:14:35 -0500 Subject: [PATCH 0493/1891] chore: show extra logger info based on LOG_LEVEL This way we can see the line location on error/warn/debug if trace is set --- src/logger.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/logger.rs b/src/logger.rs index 19738c1b5..e52a12f1a 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -33,12 +33,18 @@ fn init_log_file(log_file: PathBuf) -> Result { } fn init_term_logger(level: LevelFilter) -> Box { + let trace_level = if level >= LevelFilter::Trace { + LevelFilter::Trace + } else { + LevelFilter::Off + }; TermLogger::new( level, ConfigBuilder::new() - .set_thread_level(LevelFilter::Trace) .set_time_level(LevelFilter::Off) - .set_target_level(LevelFilter::Debug) + .set_thread_level(trace_level) + .set_target_level(trace_level) + .set_location_level(trace_level) .build(), TerminalMode::Stderr, ColorChoice::Auto, From 8d1ae90ab6c9fd1f2c97eeab76046c5b75607f8e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:15:08 -0500 Subject: [PATCH 0494/1891] bug: ignore RTX_INSTALL_VERSION this was getting parsed as RTX__VERSION --- src/toolset/builder.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index a8c47c74a..7fd9942bd 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -60,6 +60,10 @@ fn load_runtime_env(ts: &mut Toolset, env: IndexMap) { for (k, v) in env { if k.starts_with("RTX_") && k.ends_with("_VERSION") { let plugin_name = k[4..k.len() - 8].to_lowercase(); + if plugin_name == "install" { + // ignore RTX_INSTALL_VERSION + continue; + } let source = ToolSource::Environment(k, v.clone()); let mut env_ts = Toolset::new(source); let version = ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v)); From 9072efda1acaa91549b7cb43e3540a578165c7c1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:24:09 -0500 Subject: [PATCH 0495/1891] bug: fix infinite loop on exec-env this adds an env var __RTX_SCRIPT=1 to stop looping exec-env calls --- src/env.rs | 3 +++ src/env_diff.rs | 1 - src/plugins/mod.rs | 1 + src/runtimes.rs | 5 ++++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/env.rs b/src/env.rs index 9e8a58e60..fd772b9c5 100644 --- a/src/env.rs +++ b/src/env.rs @@ -65,6 +65,9 @@ lazy_static! { }; pub static ref RTX_MISSING_RUNTIME_BEHAVIOR: Option =var("RTX_MISSING_RUNTIME_BEHAVIOR").ok(); pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); + /// true if inside of a script like bin/exec-env or bin/install + /// used to prevent infinite loops + pub static ref __RTX_SCRIPT: bool = var_is_true("__RTX_SCRIPT"); pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); diff --git a/src/env_diff.rs b/src/env_diff.rs index be7ab76b6..b2825a495 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -69,7 +69,6 @@ impl EnvDiff { "bash", "-c", indoc::formatdoc! {" - set -e . {script} export -p ", script = script.display()} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index ae7c6395a..469019fb9 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -527,6 +527,7 @@ fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> Scri "RTX_DATA_DIR".into(), dirs::ROOT.to_string_lossy().into_owned(), ) + .with_env("__RTX_SCRIPT".into(), "1".into()) .with_env("RTX_PLUGIN_NAME".into(), name.to_string()); if let Some(shims_dir) = &settings.shims_dir { let shims_dir = shims_dir.to_string_lossy().to_string(); diff --git a/src/runtimes.rs b/src/runtimes.rs index 4dc253e1a..a81623375 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -206,7 +206,9 @@ impl RuntimeVersion { } pub fn exec_env(&self) -> Result<&HashMap> { - if !self.script_man.script_exists(&ExecEnv) { + if !self.script_man.script_exists(&ExecEnv) || *env::__RTX_SCRIPT { + // if the script does not exist or we're running from within a script already + // the second is to prevent infinite loops return Ok(&*EMPTY_HASH_MAP); } self.exec_env_cache.get_or_try_init(|| { @@ -342,6 +344,7 @@ fn build_script_man( "RTX_DATA_DIR".into(), dirs::ROOT.to_string_lossy().to_string(), ) + .with_env("__RTX_SCRIPT".into(), "1".into()) .with_env("RTX_PLUGIN_NAME".into(), tv.plugin_name.clone()); if let Some(shims_dir) = &config.settings.shims_dir { let shims_dir = shims_dir.to_string_lossy().to_string(); From 210252b62796465fe53a75049fa1c929b18d64f6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:56:48 -0500 Subject: [PATCH 0496/1891] bug: always re-run exec-env for python This needs a longer-term solution since it doubles the time to run rtx if python is used at all. Fixes #321 --- src/runtimes.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index a81623375..f044530f8 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -59,11 +59,7 @@ impl RuntimeVersion { .with_fresh_file(dirs::ROOT.clone()) .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(install_path.clone()); - if plugin.name == "python" - && (tv.options.contains_key("virtualenv") - || tv.options.contains_key("pipenv") - || tv.options.contains_key("poetry")) - { + if plugin.name == "python" { // TODO: remove this for a better solution // this is required for the virtualenv feature to work bin_paths_cache = bin_paths_cache.with_no_cache(); From c026ceb6f9eac1a00b164f9c66a966b0cb9a499d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:57:58 -0500 Subject: [PATCH 0497/1891] chore: Release rtx-cli version 1.23.7 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98d5913aa..857ed60dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1306,7 +1306,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.6" +version = "1.23.7" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index e1e753099..03d060bf3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.6" +version = "1.23.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e96ac9739..4e75451ca 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.6 +rtx 1.23.7 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.6/rtx-v1.23.6-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.7/rtx-v1.23.7-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 7750f20c3..3e2cb6ca6 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.6"; + version = "1.23.7"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 5b962bfa0..6e2a38879 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.6" +.TH rtx 1 "rtx 1.23.7" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.6 +v1.23.7 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f844be04a..9bdd3e5f1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.6 +Version: 1.23.7 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From e79b0ebd38ff01cd2c9ca200ec533592268d8f49 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 11:34:41 -0500 Subject: [PATCH 0498/1891] chore: check for new version in different durations if using `rtx -v`, check daily, if using `rtx doctor`: daily, otherwise only weekly --- src/cli/doctor.rs | 4 ++-- src/cli/version.rs | 12 ++++++------ src/config/mod.rs | 4 ++-- src/duration.rs | 5 +++++ src/main.rs | 1 + 5 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 src/duration.rs diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 0f4c96da1..dad1266b8 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -9,9 +9,9 @@ use std::process::exit; use crate::cli::command::Command; use crate::cli::version::VERSION; use crate::config::Config; -use crate::env; use crate::git::Git; use crate::{cli, cmd}; +use crate::{duration, env}; use crate::output::Output; use crate::shell::ShellType; @@ -51,7 +51,7 @@ impl Command for Doctor { } } - if let Some(latest) = cli::version::check_for_new_version() { + if let Some(latest) = cli::version::check_for_new_version(duration::WEEKLY) { checks.push(format!( "new rtx version {} available, currently on {}", latest, diff --git a/src/cli/version.rs b/src/cli/version.rs index bf7181932..c4edf7a67 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -10,9 +10,9 @@ use versions::Versioning; use crate::build_time::BUILD_TIME; use crate::cli::command::Command; use crate::config::Config; -use crate::dirs; use crate::file::modified_duration; use crate::output::Output; +use crate::{dirs, duration}; #[derive(Debug, clap::Args)] #[clap(about = "Show rtx version", alias = "v")] @@ -65,7 +65,7 @@ fn show_version(out: &mut Output) { } fn show_latest() { - if let Some(latest) = check_for_new_version() { + if let Some(latest) = check_for_new_version(duration::DAILY) { warn!("rtx version {} available", latest); if cfg!(feature = "self_update") { let cmd = style("rtx self-update").bright().yellow().for_stderr(); @@ -74,8 +74,8 @@ fn show_latest() { } } -pub fn check_for_new_version() -> Option { - if let Some(latest) = get_latest_version().and_then(|v| Versioning::new(&v)) { +pub fn check_for_new_version(cache_duration: Duration) -> Option { + if let Some(latest) = get_latest_version(cache_duration).and_then(|v| Versioning::new(&v)) { let current = Versioning::new(env!("CARGO_PKG_VERSION")).unwrap(); if current < latest { return Some(latest.to_string()); @@ -84,10 +84,10 @@ pub fn check_for_new_version() -> Option { None } -fn get_latest_version() -> Option { +fn get_latest_version(duration: Duration) -> Option { let version_file_path = dirs::CACHE.join("latest-version"); if let Ok(metadata) = modified_duration(&version_file_path) { - if metadata < Duration::from_secs(60 * 60 * 24) { + if metadata < duration { if let Ok(version) = fs::read_to_string(&version_file_path) { return Some(version); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 5f3c3f8d6..ceb103119 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -23,7 +23,7 @@ use crate::config::tracking::Tracker; use crate::plugins::{Plugin, PluginName}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::{cli, dirs, env, file, hook_env}; +use crate::{cli, dirs, duration, env, file, hook_env}; pub mod config_file; mod settings; @@ -258,7 +258,7 @@ impl Config { if !console::user_attended_stderr() { return; // not a tty so don't bother } - if let Some(latest) = cli::version::check_for_new_version() { + if let Some(latest) = cli::version::check_for_new_version(duration::HOURLY) { warn!( "newer rtx version {} available, currently on {}", latest, diff --git a/src/duration.rs b/src/duration.rs new file mode 100644 index 000000000..6dcbef530 --- /dev/null +++ b/src/duration.rs @@ -0,0 +1,5 @@ +pub use std::time::Duration; + +pub(crate) const HOURLY: Duration = Duration::from_secs(60 * 60); +pub(crate) const DAILY: Duration = Duration::from_secs(60 * 60 * 24); +pub(crate) const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); diff --git a/src/main.rs b/src/main.rs index 71d6f4212..34731c2b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,7 @@ mod config; mod default_shorthands; mod direnv; mod dirs; +pub mod duration; mod env; mod env_diff; mod errors; From d560ff38dbb948007c2cd0a570aaf7c44db359c3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 11:43:46 -0500 Subject: [PATCH 0499/1891] chore: check for new version in different durations if using `rtx -v`, check daily, if using `rtx doctor`: daily, otherwise only weekly --- src/cli/doctor.rs | 2 +- src/config/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index dad1266b8..4ac083125 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -51,7 +51,7 @@ impl Command for Doctor { } } - if let Some(latest) = cli::version::check_for_new_version(duration::WEEKLY) { + if let Some(latest) = cli::version::check_for_new_version(duration::HOURLY) { checks.push(format!( "new rtx version {} available, currently on {}", latest, diff --git a/src/config/mod.rs b/src/config/mod.rs index ceb103119..3d934241d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -258,7 +258,7 @@ impl Config { if !console::user_attended_stderr() { return; // not a tty so don't bother } - if let Some(latest) = cli::version::check_for_new_version(duration::HOURLY) { + if let Some(latest) = cli::version::check_for_new_version(duration::WEEKLY) { warn!( "newer rtx version {} available, currently on {}", latest, From 11ed0de8cc7f59ec104ce6bc664d04333a4ce330 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 14 Mar 2023 19:38:01 -0500 Subject: [PATCH 0500/1891] updated badge links --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4e75451ca..7bfb721cc 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@

rtx

-Crates.io -GitHub -GitHub Workflow Status -Codecov -Discord +Crates.io +GitHub +GitHub Workflow Status +Codecov +Discord

Polyglot runtime manager (asdf rust clone)

From f54f83d494b268d172389844902e3363cca76f2e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 16 Mar 2023 17:09:31 -0500 Subject: [PATCH 0501/1891] chore: s3 publish --- scripts/publish-s3.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 scripts/publish-s3.sh diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh new file mode 100755 index 000000000..e04fecf33 --- /dev/null +++ b/scripts/publish-s3.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euxo pipefail + +cache_hour="max-age=3600,s-maxage=3600,public,immutable" +cache_day="max-age=86400,s-maxage=86400,public,immutable" +cache_week="max-age=604800,s-maxage=604800,public,immutable" + +./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh +echo "$RTX_VERSION" | tr -d 'v' >"$RELEASE_DIR"/VERSION + +cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-latest-linux-amd64" +cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-latest-macos-amd64" + +aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive + +aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "rtx-latest-*" +aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" +aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" + +aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress +aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive +aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "repomd.xml*" +aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" + +aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive +aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_hour" --no-progress --no-progress --recursive + +#aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ +# "/VERSION" \ +# "/SHASUMS*" \ +# "/install.sh" \ +# "/rtx-latest-*" \ +# "/rpm/repodata/*" \ +# "/deb/dists/*" From f380da397b34a6c25918481a65d9232a0f289925 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 16 Mar 2023 17:10:43 -0500 Subject: [PATCH 0502/1891] chore: Release rtx-cli version 1.23.8 --- Cargo.lock | 35 ++++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 4 +++- 7 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 857ed60dd..09dad5235 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.8" +version = "4.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +checksum = "9a9d6ada83c1edcce028902ea27dd929069c70df4c7600b131b4d9a1ad2879cc" dependencies = [ "bitflags", "clap_derive", @@ -143,18 +143,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.4" +version = "4.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501ff0a401473ea1d4c3b125ff95506b62c5bc5768d818634195fbb7c4ad5ff4" +checksum = "37686beaba5ac9f3ab01ee3172f792fc6ffdd685bfb9e63cfef02c0571a4e8e1" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.1.8" +version = "4.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644" dependencies = [ "heck", "proc-macro-error", @@ -165,18 +165,18 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" dependencies = [ "os_str_bytes", ] [[package]] name = "clap_mangen" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0f09a0ca8f0dd8ac92c546b426f466ef19828185c6d504c80c48c9c2768ed9" +checksum = "4237e29de9c6949982ba87d51709204504fb8ed2fd38232fcb1e5bf7d4ba48c8" dependencies = [ "clap", "roff", @@ -818,10 +818,11 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +checksum = "76e86b86ae312accbf05ade23ce76b625e0e47a255712b7414037385a1c05380" dependencies = [ + "hermit-abi 0.3.1", "libc", "windows-sys 0.45.0", ] @@ -1306,7 +1307,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.7" +version = "1.23.8" dependencies = [ "base64", "build-time", @@ -1789,9 +1790,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.6" +version = "0.19.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08de71aa0d6e348f070457f85af8bd566e2bc452156a423ddf22861b3a953fae" +checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274" dependencies = [ "indexmap", "serde", @@ -2163,9 +2164,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "winnow" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee7b2c67f962bf5042bfd8b6a916178df33a26eec343ae064cb8e069f638fa6f" +checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 03d060bf3..6754c0f2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.7" +version = "1.23.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 7bfb721cc..9ac8cf094 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.7 +rtx 1.23.8 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.7/rtx-v1.23.7-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.8/rtx-v1.23.8-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 3e2cb6ca6..ce4d530b9 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.7"; + version = "1.23.8"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 6e2a38879..7ab1fb1d9 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.7" +.TH rtx 1 "rtx 1.23.8" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.7 +v1.23.8 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9bdd3e5f1..3378a039d 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.7 +Version: 1.23.8 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index cc7e2f0c4..0bfde2e8d 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 620] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 622] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -397,6 +397,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 620] = [ ("mysql", "https://github.com/iroddis/asdf-mysql.git"), ("nancy", "https://github.com/iilyak/asdf-nancy.git"), ("nano", "https://github.com/mfakane/asdf-nano.git"), + ("nasm", "https://github.com/Dpbm/asdf-nasm.git"), ("neko", "https://github.com/asdf-community/asdf-neko.git"), ("neovim", "https://github.com/richin13/asdf-neovim.git"), ("nerdctl", "https://github.com/dmpe/asdf-nerdctl"), @@ -507,6 +508,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 620] = [ ("solidity", "https://github.com/diegodorado/asdf-solidity.git"), ("sops", "https://github.com/feniix/asdf-sops.git"), ("sopstool", "https://github.com/elementalvoid/asdf-sopstool.git"), + ("soracom", "https://github.com/grimoh/asdf-soracom.git"), ("sourcery", "https://github.com/younke/asdf-sourcery.git"), ("spago", "https://github.com/nsaunders/asdf-spago.git"), ("spark", "https://github.com/joshuaballoch/asdf-spark.git"), From 64c92aabcd7047bf010c8cd3c08a6948bc5d4001 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 08:31:00 -0500 Subject: [PATCH 0503/1891] chore: fix s3 publishing Fixes #338 --- scripts/release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/release.sh b/scripts/release.sh index ad92e0d95..5c1744fea 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -60,6 +60,7 @@ popd NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh ./rtx/scripts/publish-r2.sh +./rtx/scripts/publish-s3.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb pushd homebrew-tap From 013f7a88cc69c5b867c5bad1727214b2bdee05b3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 08:32:06 -0500 Subject: [PATCH 0504/1891] chore: Release rtx-cli version 1.23.9 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 3 ++- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09dad5235..7c505953f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,7 +1307,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.8" +version = "1.23.9" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 6754c0f2c..4fe493351 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.8" +version = "1.23.9" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 9ac8cf094..6881e6aa0 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.8 +rtx 1.23.9 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.8/rtx-v1.23.8-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.9/rtx-v1.23.9-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index ce4d530b9..284608c76 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.8"; + version = "1.23.9"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 7ab1fb1d9..24fb1e6d6 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.8" +.TH rtx 1 "rtx 1.23.9" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.8 +v1.23.9 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 3378a039d..00a71a82b 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.8 +Version: 1.23.9 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 0bfde2e8d..6dd20ab13 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 622] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 623] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -189,6 +189,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 622] = [ ("fluxctl", "https://github.com/stefansedich/asdf-fluxctl.git"), ("fly", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("flyctl", "https://github.com/chessmango/asdf-flyctl.git"), + ("flyway", "https://github.com/junminahn/asdf-flyway.git"), ("func-e", "https://github.com/carnei-ro/asdf-func-e.git"), ("furyctl", "https://github.com/sighupio/asdf-furyctl.git"), ("fx", "https://gitlab.com/wt0f/asdf-fx.git"), From b31edd013cfc25ff1f3fa88b52f041c4fed2cd41 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 08:51:03 -0500 Subject: [PATCH 0505/1891] chore: set aws credentials --- .github/workflows/rtx.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 60ede43dc..5df189939 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -225,6 +225,12 @@ jobs: with: node-version: "18.x" registry-url: "https://registry.npmjs.org" + - name: Set AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-2 - name: Wrangler run: npm i -g wrangler@^2.12.2 - uses: shimataro/ssh-key-action@v2 From a34ccced2bdc88e2382258dd14a3d5a562180dd5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 08:51:34 -0500 Subject: [PATCH 0506/1891] chore: Release rtx-cli version 1.23.10 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c505953f..9380ac130 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,7 +1307,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.9" +version = "1.23.10" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 4fe493351..0b0ce0e4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.9" +version = "1.23.10" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 6881e6aa0..3ec4b1791 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.9 +rtx 1.23.10 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -325,7 +325,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.9/rtx-v1.23.9-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.10/rtx-v1.23.10-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 284608c76..6246592cf 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.9"; + version = "1.23.10"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 24fb1e6d6..530d5021a 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.9" +.TH rtx 1 "rtx 1.23.10" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.9 +v1.23.10 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 00a71a82b..f8b5157fb 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.9 +Version: 1.23.10 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 2581334d173c424447f51ae9bffd9ddef01bb95c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 09:04:31 -0500 Subject: [PATCH 0507/1891] chore: skip R2 --- scripts/release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.sh b/scripts/release.sh index 5c1744fea..f2afa2944 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -59,7 +59,7 @@ popd NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh -./rtx/scripts/publish-r2.sh +#./rtx/scripts/publish-r2.sh ./rtx/scripts/publish-s3.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb From 6a615101bc9d50733c50925411f729b2578dec4a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 10:05:31 -0500 Subject: [PATCH 0508/1891] bug: do not use ~/.tool-versions as global config if RTX_USE_TOML=1 This will be the default behavior on the calver release. #337 --- .rtx.toml | 6 +++--- src/config/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.rtx.toml b/.rtx.toml index 67241ef0e..1ec12d7fa 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -3,9 +3,9 @@ FOO = "bar" [tools] nodejs = 'lts' -tiny = {version="1", foo="bar"} -golang = {version="latest", foo="bar"} -python = {version="latest", virtualenv="$HOME/.cache/venv"} +tiny = { version = "1", foo = "bar" } +golang = { version = "latest", foo = "bar" } +python = { version = "latest", virtualenv = "$HOME/.cache/venv" } [plugins] nodejs = 'https://github.com/jdxcode/rtx-nodejs' diff --git a/src/config/mod.rs b/src/config/mod.rs index 3d934241d..11f7912cc 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -358,7 +358,7 @@ fn load_config_filenames(legacy_filenames: &IndexMap) -> Vec let mut config_files = file::FindUp::new(&dirs::CURRENT, &filenames).collect::>(); - if env::RTX_CONFIG_FILE.is_none() { + if env::RTX_CONFIG_FILE.is_none() && !*env::RTX_USE_TOML { // only add ~/.tool-versions if RTX_CONFIG_FILE is not set // because that's how the user overrides the default let home_config = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); From 3010ce625098157e9d4d39f85e4bef452d4dffb7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 10:26:37 -0500 Subject: [PATCH 0509/1891] mark "!-" as experimental --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3ec4b1791..d5b639169 100644 --- a/README.md +++ b/README.md @@ -494,6 +494,8 @@ 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 shfmt path:./shfmt # use a custom runtime nodejs lts # use lts version of nodejs (not supported by all plugins) + +# The following syntax is experimental and subject to change nodejs lts!-2 # install 2 versions behind the latest lts (e.g.: 16 if lts is 18) python latest!-0.1 # install python-3.10 if the latest is 3.11 ``` From 45abdd5606315a54c97dee41f1dc315df0b052ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:24:15 +0000 Subject: [PATCH 0510/1891] chore(deps): bump aws-actions/configure-aws-credentials from 1 to 2 (#339) Bumps [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials) from 1 to 2. - [Release notes](https://github.com/aws-actions/configure-aws-credentials/releases) - [Changelog](https://github.com/aws-actions/configure-aws-credentials/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws-actions/configure-aws-credentials/compare/v1...v2) --- updated-dependencies: - dependency-name: aws-actions/configure-aws-credentials dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rtx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 5df189939..eaa6d93c4 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -226,7 +226,7 @@ jobs: node-version: "18.x" registry-url: "https://registry.npmjs.org" - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v1 + uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} From 85c2ca14068d802d4ca98392e1cff80f75e81894 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:07:46 -0500 Subject: [PATCH 0511/1891] bug: fix latest!-1 (#341) Fixes #330 --- e2e/test_bang | 20 +++++++++++------- src/toolset/tool_version.rs | 41 +++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/e2e/test_bang b/e2e/test_bang index 385c13193..4a463ef35 100755 --- a/e2e/test_bang +++ b/e2e/test_bang @@ -2,12 +2,18 @@ set -euo pipefail assert() { - local actual - actual="$($*)" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi + local actual + actual="$($1)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi } -assert "rtx x nodejs@18.0.0!-2 -- node -v" "v16.0.0" +rtx local tiny@latest!-1 +assert "rtx current tiny" "2.1.0" +rtx local tiny@lts!-1 +assert "rtx current tiny" "2.1.0" +rtx local tiny@3.1!-0.1 +assert "rtx current tiny" "3.0.1" +rtx local tiny@latest diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 21206e10c..36fa24239 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -108,19 +108,12 @@ impl ToolVersion { v: &str, ) -> Result> { let (wanted, minus) = v.split_once("!-").unwrap(); - let wanted = resolve_alias(config, plugin.clone(), wanted)?; - let mut wanted = Version::new(&wanted).unwrap(); - for (i, m) in Version::new(minus).unwrap().chunks.0.iter().enumerate() { - let orig = match wanted.nth(i) { - Some(c) => c, - None => { - warn!("cannot subtract {minus} from {wanted}"); - return Ok(None); - } - }; - wanted.chunks.0[i] = Chunk::Numeric(orig - m.single_digit().unwrap()); - } - match plugin.latest_version(&config.settings, Some(wanted.to_string()))? { + let wanted = match wanted { + "latest" => plugin.latest_version(&config.settings, None)?.unwrap(), + _ => resolve_alias(config, plugin.clone(), wanted)?, + }; + let wanted = version_sub(&wanted, minus); + match plugin.latest_version(&config.settings, Some(wanted))? { Some(v) => Ok(RuntimeVersion::new(config, plugin, v, self.clone()).into()), None => Ok(None), } @@ -210,6 +203,22 @@ pub fn resolve_alias(config: &Config, plugin: Arc, v: &str) -> Result "16" +/// e.g. version_sub("18.2.3", "0.1") -> "18.1" +fn version_sub(orig: &str, sub: &str) -> String { + let mut orig = Version::new(orig).unwrap(); + let sub = Version::new(sub).unwrap(); + while orig.chunks.0.len() > sub.chunks.0.len() { + orig.chunks.0.pop(); + } + for (i, orig_chunk) in orig.clone().chunks.0.iter().enumerate() { + let m = sub.nth(i).unwrap(); + orig.chunks.0[i] = Chunk::Numeric(orig_chunk.single_digit().unwrap() - m); + } + orig.to_string() +} + #[cfg(test)] mod tests { use pretty_assertions::assert_str_eq; @@ -230,4 +239,10 @@ mod tests { let tv = ToolVersion::new(foo, ToolVersionType::System); assert_str_eq!(tv.to_string(), "foo@system"); } + + #[test] + fn test_version_sub() { + assert_str_eq!(version_sub("18.2.3", "2"), "16"); + assert_str_eq!(version_sub("18.2.3", "0.1"), "18.1"); + } } From ed1251fd92dbb5a9f8943450fd4e2ddb9ffbacaa Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:16:46 -0500 Subject: [PATCH 0512/1891] feat: added `rtx x --cd` option (#342) Fixes #329 --- README.md | 8 ++++ completions/_rtx | 1 + completions/rtx.bash | 6 ++- completions/rtx.fish | 1 + e2e/test_exec | 13 +++++++ src/cli/exec.rs | 92 +++++++++++++++++++++++++++----------------- src/shims.rs | 1 + 7 files changed, 85 insertions(+), 37 deletions(-) create mode 100755 e2e/test_exec diff --git a/README.md b/README.md index d5b639169..92298e09b 100644 --- a/README.md +++ b/README.md @@ -1435,12 +1435,20 @@ Options: -c, --command Command string to execute + --cd + Change to this directory before executing the command + + [short aliases: C] + Examples: rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x rtx x nodejs@18 -- node ./app.js # shorter alias # Specify command as a string: rtx exec nodejs@18 python@3.11 --command "node -v && python -V" + + # Run a command in a different directory: + rtx x -C /path/to/project nodejs@18 -- node ./app.js ``` ### `rtx global` diff --git a/completions/_rtx b/completions/_rtx index ec699d34e..be8001ed3 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -538,6 +538,7 @@ Sets --jobs=1]' \ _arguments "${_arguments_options[@]}" \ '()-c+[Command string to execute]:C: ' \ '()--command=[Command string to execute]:C: ' \ +'--cd=[Change to this directory before executing the command]:CD: ' \ '-j+[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel diff --git a/completions/rtx.bash b/completions/rtx.bash index 28bf942e2..5093f5444 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1237,7 +1237,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -v -h --command --install-missing --jobs --log-level --raw --verbose --help [RUNTIME]... [COMMAND]..." + opts="-c -j -r -v -h --command --cd --install-missing --jobs --log-level --raw --verbose --help [RUNTIME]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1251,6 +1251,10 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index d4650f4e9..e7d5e5160 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -230,6 +230,7 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -l cd -d 'Change to this directory before executing the command' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r diff --git a/e2e/test_exec b/e2e/test_exec new file mode 100755 index 000000000..61b562e2f --- /dev/null +++ b/e2e/test_exec @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euxo pipefail + +assert() { + local actual + actual="$($1)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi +} + +assert "rtx x -C direnv -- pwd" "$(pwd)/direnv" diff --git a/src/cli/exec.rs b/src/cli/exec.rs index afc76f5bd..a208e2572 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -42,6 +42,10 @@ pub struct Exec { /// Command string to execute #[clap(short, long = "command", conflicts_with = "command")] pub c: Option, + + /// Change to this directory before executing the command + #[clap(visible_short_alias = 'C', long)] + pub cd: Option, } impl Command for Exec { @@ -51,57 +55,65 @@ impl Command for Exec { .with_args(&self.runtime) .with_install_missing() .build(&mut config)?; - let (program, args) = parse_command(&env::SHELL, self.command, self.c); + let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); let mut env = ts.env_with_path(&config); if config.settings.missing_runtime_behavior != Ignore { // prevent rtx from auto-installing inside a shim env.insert("RTX_MISSING_RUNTIME_BEHAVIOR".into(), "warn".into()); } - exec(program, args, env) + self.exec(program, args, env) } } -#[cfg(not(test))] -fn exec(program: T, args: U, env: IndexMap) -> Result<()> -where - T: IntoExecutablePath, - U: IntoIterator, - U::Item: Into, - E: AsRef, -{ - for (k, v) in env.iter() { - env::set_var(k, v); +impl Exec { + #[cfg(not(test))] + fn exec(&self, program: T, args: U, env: IndexMap) -> Result<()> + where + T: IntoExecutablePath, + U: IntoIterator, + U::Item: Into, + E: AsRef, + { + for (k, v) in env.iter() { + env::set_var(k, v); + } + let args = args.into_iter().map(Into::into).collect::>(); + let program = program.to_executable(); + if let Some(cd) = &self.cd { + env::set_current_dir(cd)?; + } + let err = exec::Command::new(program.clone()).args(&args).exec(); + Err(eyre!("{:?} {}", program.to_string_lossy(), err.to_string())) } - let args = args.into_iter().map(Into::into).collect::>(); - let program = program.to_executable(); - let err = exec::Command::new(program.clone()).args(&args).exec(); - Err(eyre!("{:?} {}", program.to_string_lossy(), err.to_string())) -} -#[cfg(test)] -fn exec(program: T, args: U, env: IndexMap) -> Result<()> -where - T: IntoExecutablePath, - U: IntoIterator, - U::Item: Into, - E: AsRef, -{ - let mut cmd = cmd::cmd(program, args); - for (k, v) in env.iter() { - cmd = cmd.env(k, v); - } - let res = cmd.unchecked().run()?; - match res.status.code().unwrap_or(1) { - 0 => Ok(()), - code => Err(eyre!("command failed with exit code {}", code)), + #[cfg(test)] + fn exec(&self, program: T, args: U, env: IndexMap) -> Result<()> + where + T: IntoExecutablePath, + U: IntoIterator, + U::Item: Into, + E: AsRef, + { + let mut cmd = cmd::cmd(program, args); + if let Some(cd) = &self.cd { + cmd = cmd.dir(cd); + } + for (k, v) in env.iter() { + cmd = cmd.env(k, v); + } + let res = cmd.unchecked().run()?; + match res.status.code().unwrap_or(1) { + 0 => Ok(()), + code => Err(eyre!("command failed with exit code {}", code)), + } } } fn parse_command( shell: &str, - command: Option>, - c: Option, + command: &Option>, + c: &Option, ) -> (OsString, Vec) { match (&command, &c) { (Some(command), _) => { @@ -109,7 +121,7 @@ fn parse_command( (program.clone(), args.into()) } - _ => (shell.into(), vec!["-c".into(), c.unwrap()]), + _ => (shell.into(), vec!["-c".into(), c.clone().unwrap()]), } } @@ -121,6 +133,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { # Specify command as a string: rtx exec nodejs@18 python@3.11 --command "node -v && python -V" + + # Run a command in a different directory: + rtx x -C /path/to/project nodejs@18 -- node ./app.js "#, style("Examples:").bold().underlined()} }); @@ -146,4 +161,9 @@ mod tests { ) .unwrap_err(); } + + #[test] + fn test_exec_cd() { + assert_cli!("exec", "-C", "/tmp", "--", "pwd"); + } } diff --git a/src/shims.rs b/src/shims.rs index 1c3a896f8..aefb90f76 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -32,6 +32,7 @@ pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Res runtime: vec![], c: None, command: Some(args), + cd: None, }; exec.run(config, out)?; exit(0); From d1c7aa4fe504c71f31727d59cecfdfde88b64990 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 14:54:07 -0500 Subject: [PATCH 0513/1891] removed unnecessary mut --- src/toolset/tool_version.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 36fa24239..cc4706c95 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -163,7 +163,7 @@ impl ToolVersion { } } - pub fn install(&mut self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { + pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { match self.r#type { ToolVersionType::Version(_) | ToolVersionType::Prefix(_) | ToolVersionType::Ref(_) => { self.rtv.as_ref().unwrap().install(config, pr, force) From 2aadd1b23f6d72c6c734970e8b8513546652ee5f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:18:09 -0500 Subject: [PATCH 0514/1891] feat: version symlinks (#343) Fixes #336 --- README.md | 72 +++++++++++ src/cli/install.rs | 5 +- src/main.rs | 1 + src/plugins/mod.rs | 2 + src/runtime_symlinks.rs | 120 ++++++++++++++++++ src/shims.rs | 2 +- ...untime_symlinks__tests__list_symlinks.snap | 14 ++ src/toolset/mod.rs | 5 +- src/toolset/tool_version.rs | 13 +- 9 files changed, 225 insertions(+), 9 deletions(-) create mode 100644 src/runtime_symlinks.rs create mode 100644 src/snapshots/rtx__runtime_symlinks__tests__list_symlinks.snap diff --git a/README.md b/README.md index 92298e09b..a6f263cf7 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,10 @@ v18.10.9 - [Plugin Options](#plugin-options) - [Versioning](#versioning) - [Calver Breaking Changes](#calver-breaking-changes) +- [Directories](#directories) + - [`~/.config/rtx`](#configrtx) + - [`~/.cache/rtx`](#cachertx) + - [`~/.local/share/rtx`](#localsharertx) - [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) - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) @@ -852,6 +856,74 @@ Here are a list of the changes that will be made: that is read anywhere such as from `/tmp`. - (more to be added) +## Directories + +The following are the directories that rtx uses. +These are the default directories, see +[Configuration](#configuration) for information on changing the locations. + +> **Tip** +> +> If you often find yourself using these directories (as I do), I suggest setting all of them to `~/.rtx` for easy access. + +### `~/.config/rtx` + +This directory stores the global configuration file `~/.config/rtx/config.toml`. + +### `~/.cache/rtx` + +_On macOS this is `~/Library/Caches/rtx`._ + +Stores internal cache that rtx uses for things like the list of all available versions of a +plugin. +See [Cache Behavior](#cache-behavior) for more information. + +### `~/.local/share/rtx` + +This is the main directory that rtx uses and is where plugins and tools are installed into. +It is nearly identical to `~/.asdf` in asdf, so much so that you may be able to get by +symlinking these together and using asdf and rtx simultaneously. (Supporting this isn't a +project goal, however). + +#### `~/.local/share/rtx/downloads` + +This is where plugins may optionally cache downloaded assets such as tarballs. Use the +`always_keep_downloads` setting to prevent rtx from removing files from here. + +#### `~/.local/share/rtx/plugins` + +rtx installs plugins to this directory when running `rtx plugins install`. If you are working on a +plugin, I suggest +symlinking it manually by running: + +``` +ln -s ~/src/rtx-my-tool ~/.local/share/rtx/plugins/my-tool +``` + +#### `~/.local/share/rtx/installs` + +This is where tools are installed to when running `rtx install`. For example, `rtx install +nodejs@18.0.0` will install to `~/.local/share/rtx/installs/nodejs/18.0.0` For example, `rtx +install 0.0` will install to `~/.local/share/rtx/installs/nodejs/18.0.0`. + +This will also create other symlinks to this directory for version prefixes ("18" and "18.15") +and matching aliases ("lts", "latest"). +For example: + +``` +18 -> ./18.15.0 +18.15 -> ./18.15.0 +latest -> ./18.15.0 +lts -> ./18.15.0 +``` + +These are currently experimental and only created when the "experimental" setting is true. + +#### `~/.local/share/rtx/shims` + +This will be the default location for storing shims. Currently this functionality is marked as +experimental, however, and this needs to be manually set with `shims_dir`. + ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. diff --git a/src/cli/install.rs b/src/cli/install.rs index b4926551e..dbbc369d5 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -15,6 +15,7 @@ use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; use crate::plugins::{Plugin, PluginName}; +use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; use crate::toolset::{ToolVersion, ToolVersionType, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -166,7 +167,9 @@ impl Install { } }) .collect::>>()?; - reshim(&mut config, &ts).with_context(|| "failed to reshim") + reshim(&mut config, &ts).with_context(|| "failed to reshim")?; + rebuild_symlinks(&config)?; + Ok(()) }) } diff --git a/src/main.rs b/src/main.rs index 34731c2b6..02684d625 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,7 @@ mod hook_env; mod lock_file; mod logger; mod plugins; +mod runtime_symlinks; pub mod runtimes; mod shell; mod shims; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 469019fb9..d773104ce 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -24,6 +24,7 @@ use crate::git::Git; use crate::hash::hash_to_str; use crate::lock_file::LockFile; use crate::plugins::script_manager::Script::ParseLegacyFile; +use crate::runtime_symlinks::is_runtime_symlink; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; use crate::{dirs, file}; @@ -242,6 +243,7 @@ impl Plugin { Ok(match self.installs_path.exists() { true => file::dir_subdirs(&self.installs_path)? .iter() + .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) .map(|v| Versioning::new(v).unwrap_or_default()) .sorted() .map(|v| v.to_string()) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs new file mode 100644 index 000000000..8008d1904 --- /dev/null +++ b/src/runtime_symlinks.rs @@ -0,0 +1,120 @@ +use std::path::{Path, PathBuf}; + +use crate::config::Config; +use crate::dirs; +use crate::file::make_symlink; +use color_eyre::eyre::Result; +use indexmap::IndexMap; +use itertools::Itertools; +use regex::Regex; +use versions::Version; + +use crate::plugins::Plugin; + +pub fn rebuild_symlinks(config: &Config) -> Result<()> { + if !config.settings.experimental { + return Ok(()); + } + for plugin in config.plugins.values() { + remove_existing_symlinks(plugin)?; + let symlinks = list_symlinks(config, plugin)?; + let installs_dir = dirs::INSTALLS.join(&plugin.name); + for (from, to) in symlinks { + let from = installs_dir.join(from); + if from.exists() { + continue; + } + make_symlink(&to, &from)?; + } + } + Ok(()) +} + +fn list_symlinks(config: &Config, plugin: &Plugin) -> Result> { + let mut symlinks = IndexMap::new(); + let rel_path = |x: &String| PathBuf::from(".").join(x.clone()); + for v in installed_versions(plugin)? { + let version = Version::new(&v).unwrap(); + if version.chunks.0.len() > 1 { + let chunks = &version.chunks.0[0..=version.chunks.0.len() - 2]; + for (i, _) in chunks.iter().enumerate() { + let partial = version.chunks.0[0..=i] + .iter() + .map(|c| c.to_string()) + .collect::>() + .join("."); + symlinks.insert(partial, rel_path(&v)); + } + } + symlinks.insert("latest".into(), rel_path(&v)); + for (from, to) in config + .get_all_aliases() + .get(&plugin.name) + .unwrap_or(&IndexMap::new()) + { + if from.contains('/') { + continue; + } + if !v.starts_with(to) { + continue; + } + symlinks.insert(from.clone(), rel_path(&v)); + } + } + symlinks = symlinks + .into_iter() + .sorted_by_key(|(k, _)| Version::new(k).unwrap()) + .collect(); + Ok(symlinks) +} + +fn installed_versions(plugin: &Plugin) -> Result> { + let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); + let versions = plugin + .list_installed_versions()? + .into_iter() + .filter(|v| re.is_match(v)) + .collect(); + Ok(versions) +} + +fn remove_existing_symlinks(plugin: &Plugin) -> Result<()> { + let installs_dir = dirs::INSTALLS.join(&plugin.name); + if !installs_dir.exists() { + return Ok(()); + } + for entry in std::fs::read_dir(installs_dir)? { + let entry = entry?; + let path = entry.path(); + if is_runtime_symlink(&path) { + trace!("Removing existing symlink: {}", path.display()); + std::fs::remove_file(path)?; + } + } + Ok(()) +} + +pub fn is_runtime_symlink(path: &Path) -> bool { + if let Ok(link) = path.read_link() { + return link.starts_with("./"); + } + false +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + + use crate::config::Config; + use crate::plugins::PluginName; + + use super::*; + + #[test] + fn test_list_symlinks() { + let config = Config::load().unwrap(); + let plugin = Plugin::new(&config.settings, &PluginName::from("tiny")); + let symlinks = list_symlinks(&config, &plugin).unwrap(); + assert_debug_snapshot!(symlinks); + } +} diff --git a/src/shims.rs b/src/shims.rs index aefb90f76..c6fe2e65b 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -68,7 +68,7 @@ fn which_shim(config: &mut Config, bin_name: &str) -> Result { } pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { - if !config.settings.experimental { + if !config.settings.experimental || config.settings.shims_dir.is_none() { return Ok(()); } let shims_dir = config.get_shims_dir()?; diff --git a/src/snapshots/rtx__runtime_symlinks__tests__list_symlinks.snap b/src/snapshots/rtx__runtime_symlinks__tests__list_symlinks.snap new file mode 100644 index 000000000..e126dd02a --- /dev/null +++ b/src/snapshots/rtx__runtime_symlinks__tests__list_symlinks.snap @@ -0,0 +1,14 @@ +--- +source: src/runtime_symlinks.rs +expression: symlinks +--- +{ + "latest": "./3.1.0", + "lts": "./3.1.0", + "1": "./1.0.1", + "1.0": "./1.0.1", + "2": "./2.1.0", + "2.1": "./2.1.0", + "3": "./3.1.0", + "3.1": "./3.1.0", +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 44ff81821..179494aa5 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -23,6 +23,7 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; use crate::plugins::{Plugin, PluginName}; +use crate::runtime_symlinks::rebuild_symlinks; use crate::runtimes::RuntimeVersion; use crate::shims::reshim; use crate::ui::multi_progress_report::MultiProgressReport; @@ -168,7 +169,9 @@ impl Toolset { Ok(()) }) .collect::>>()?; - reshim(config, self) + reshim(config, self)?; + rebuild_symlinks(config)?; + Ok(()) }) } fn install_missing_plugins( diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index cc4706c95..acf4edb3f 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -8,7 +8,7 @@ use indexmap::IndexMap; use versions::{Chunk, Version}; use crate::config::Config; -use crate::dirs; + use crate::plugins::Plugin; use crate::runtimes::RuntimeVersion; use crate::ui::progress_report::ProgressReport; @@ -74,11 +74,12 @@ impl ToolVersion { _ => (), } - if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { - // if the version is already installed, no need to fetch all of the remote versions - let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - return Ok(rtv); - } + // TODO: put this back in when it's compatible with #343 + // if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { + // // if the version is already installed, no need to fetch all of the remote versions + // let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); + // return Ok(rtv); + // } if v == "latest" { let v = plugin.latest_version(&config.settings, None)?; From f643833d5754b2b91456f3628f620573f4a05696 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:22:04 -0500 Subject: [PATCH 0515/1891] bug: install missing runtimes on `rtx global/local (#344) Fixes #327 --- e2e/test_local | 3 +++ src/cli/local.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/e2e/test_local b/e2e/test_local index c49c2372e..822343bfc 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -44,6 +44,9 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi +assert_raises "rtx uninstall shfmt@3.6.0" +assert_raises "rtx g shfmt --install-missing" + assert "rtx local shfmt@3.6.0" "[env] FOO = \"bar\" PATH = [\"/root\", \"./cwd\", \"\$PATH\"] diff --git a/src/cli/local.rs b/src/cli/local.rs index 213bfdf3f..cb0e73237 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -7,10 +7,12 @@ use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; +use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::output::Output; use crate::plugins::PluginName; +use crate::ui::multi_progress_report::MultiProgressReport; use crate::{dirs, env, file}; /// Sets/gets tool version in local .tool-versions or .rtx.toml @@ -122,11 +124,13 @@ pub fn local( if let Some(runtimes) = &runtime { let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); if cf.display_runtime(out, &runtimes)? { + install_missing_runtimes(&mut config, cf.as_ref())?; return Ok(()); } let pin = pin || (config.settings.asdf_compat && !fuzzy); cf.add_runtimes(&mut config, &runtimes, pin)?; } + install_missing_runtimes(&mut config, cf.as_ref())?; if runtime.is_some() || remove.is_some() { cf.save()?; @@ -137,6 +141,16 @@ pub fn local( Ok(()) } +fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result<()> { + let mut ts = cf.to_toolset().clone(); + if !ts.list_missing_versions().is_empty() { + let mpr = MultiProgressReport::new(config.settings.verbose); + ts.install_missing(config, mpr)?; + } + + Ok(()) +} + static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} From cb8255621db74ede87170105120be61c8881b744 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:23:04 -0500 Subject: [PATCH 0516/1891] chore: Release rtx-cli version 1.24.0 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9380ac130..5f1ba229f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,7 +1307,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.23.10" +version = "1.24.0" dependencies = [ "base64", "build-time", @@ -1857,9 +1857,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "unicode-bidi" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" +checksum = "7d502c968c6a838ead8e69b2ee18ec708802f99db92a0d156705ec9ef801993b" [[package]] name = "unicode-ident" diff --git a/Cargo.toml b/Cargo.toml index 0b0ce0e4b..027d588ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.23.10" +version = "1.24.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a6f263cf7..98de6ffeb 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.23.10 +rtx 1.24.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -329,7 +329,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.23.10/rtx-v1.23.10-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.24.0/rtx-v1.24.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 6246592cf..5d2ead36b 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.23.10"; + version = "1.24.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 530d5021a..0fa39c8c2 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.23.10" +.TH rtx 1 "rtx 1.24.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.23.10 +v1.24.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f8b5157fb..e8711bb8b 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.23.10 +Version: 1.24.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 364a6a0e05e3bb316a0e0c7edc1b0825919bc894 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:39:26 -0500 Subject: [PATCH 0517/1891] feat: dotenv support (#345) Fixes #331 --- .env | 3 +++ .rtx.toml | 1 + Cargo.lock | 7 +++++ Cargo.toml | 1 + README.md | 43 ++++++++++++++++++++++++------ e2e/.e2e.rtx.toml | 1 + e2e/.test-env | 1 + e2e/test_env | 15 ++++++----- e2e/test_local | 12 ++++++--- src/config/config_file/rtx_toml.rs | 19 ++++++++++++- 10 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 .env create mode 100644 e2e/.test-env diff --git a/.env b/.env new file mode 100644 index 000000000..36973ef1f --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +export FOO_FROM_FILE="foo_from_file" diff --git a/.rtx.toml b/.rtx.toml index 1ec12d7fa..c2b081ab9 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -1,3 +1,4 @@ +dotenv = '.env' [env] FOO = "bar" diff --git a/Cargo.lock b/Cargo.lock index 5f1ba229f..c3fbc4bb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,6 +393,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dotenvy" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0" + [[package]] name = "duct" version = "0.13.6" @@ -1321,6 +1327,7 @@ dependencies = [ "ctrlc", "dialoguer", "dirs-next", + "dotenvy", "duct", "env_logger", "exec", diff --git a/Cargo.toml b/Cargo.toml index 027d588ff..f15288fab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ ctor = "0.1.26" ctrlc = "3.2.5" dialoguer = { version = "0.10.3", features = [] } dirs-next = "2.0.0" +dotenvy = "0.15.6" duct = "0.13.6" filetime = "0.2.19" flate2 = "1.0.25" diff --git a/README.md b/README.md index 98de6ffeb..180c81f13 100644 --- a/README.md +++ b/README.md @@ -595,14 +595,8 @@ Here is what the config looks like: ```toml [env] -NODE_ENV = 'production' # supports arbitrary env vars so rtx can be used like dotenv -PATH = [ - # adds an absolute path - "~/.local/share/bin", - # adds a path relative to the directory this config is in, not necessarily PWD - "./node_modules/.bin", - "$PATH" # required to be at the end -] +# supports arbitrary env vars so rtx can be used like direnv/dotenv +NODE_ENV = 'production' [tools] # specify single or multiple versions @@ -636,6 +630,39 @@ my_custom_node = '18' require setting `experimental = true` in the global config in part because this config can itself contain the setting for `experimental`. +#### `[env]` - Arbitrary Environment Variables + +The `[env]` section of .rtx.toml allows setting arbitrary environment variables. +These can be simple key/value entries like this: + +```toml +[env] +NODE_ENV = 'production' +``` + +`PATH` is treated specially, it needs to be defined as an array with `$PATH` at the end: + +```toml +[env] +PATH = [ + # adds an absolute path + "~/.local/share/bin", + # adds a path relative to the .rtx.toml, not PWD + "./node_modules/.bin", + "$PATH" +] +``` + +_Note: other PATH-like variables like `LD_LIBRARY_PATH` cannot be set this way._ + +`dotenv` can be used to specify a [dotenv](https://dotenv.org) file to load: + +```toml +dotenv = '.env' +``` + +_Note: `dotenv` goes at the top of the file, above `[env]`._ + ### Environment variables rtx can also be configured via environment variables. The following options are available: diff --git a/e2e/.e2e.rtx.toml b/e2e/.e2e.rtx.toml index 919c26e4e..c201acdf4 100644 --- a/e2e/.e2e.rtx.toml +++ b/e2e/.e2e.rtx.toml @@ -1,3 +1,4 @@ +dotenv = '.test-env' [env] FOO = "bar" PATH = ["/root", "./cwd", "$PATH"] diff --git a/e2e/.test-env b/e2e/.test-env new file mode 100644 index 000000000..3c0ec58e8 --- /dev/null +++ b/e2e/.test-env @@ -0,0 +1 @@ +FOO_FROM_FILE="foo_from_file" diff --git a/e2e/test_env b/e2e/test_env index a64f053db..e33ba8615 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -1,15 +1,16 @@ #!/usr/bin/env bash assert() { - actual="$($1)" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" != "$expected" ]]; then - echo "assertion failed, expected '$expected', got '$actual'" - exit 1 - fi + actual="$(bash -c "$1")" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi } rtx i nodejs@16.0.0 eval "$(rtx env -s bash nodejs@16.0.0)" assert "node -v" "v16.0.0" +assert "rtx x -- env | grep FOO_FROM_FILE" "FOO_FROM_FILE=foo_from_file" diff --git a/e2e/test_local b/e2e/test_local index 822343bfc..c7f64952a 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -20,7 +20,8 @@ export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall assert_raises "rtx uninstall shfmt@3.6.0" -assert "rtx local" "[env] +assert "rtx local" "dotenv = '.test-env' +[env] FOO = \"bar\" PATH = [\"/root\", \"./cwd\", \"\$PATH\"] @@ -29,7 +30,8 @@ tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} " -assert "rtx local shfmt@3.5.0" "[env] +assert "rtx local shfmt@3.5.0" "dotenv = '.test-env' +[env] FOO = \"bar\" PATH = [\"/root\", \"./cwd\", \"\$PATH\"] @@ -47,7 +49,8 @@ fi assert_raises "rtx uninstall shfmt@3.6.0" assert_raises "rtx g shfmt --install-missing" -assert "rtx local shfmt@3.6.0" "[env] +assert "rtx local shfmt@3.6.0" "dotenv = '.test-env' +[env] FOO = \"bar\" PATH = [\"/root\", \"./cwd\", \"\$PATH\"] @@ -62,7 +65,8 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then exit 1 fi -assert "rtx local --rm shfmt" "[env] +assert "rtx local --rm shfmt" "dotenv = '.test-env' +[env] FOO = \"bar\" PATH = [\"/root\", \"./cwd\", \"\$PATH\"] diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 4ac393506..e925a7b92 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -76,6 +76,7 @@ impl RtxToml { let doc: Document = s.parse().suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { + "dotenv" => self.parse_dotenv(k, v)?, "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, @@ -92,6 +93,20 @@ impl RtxToml { SettingsBuilder::default() } + fn parse_dotenv(&mut self, k: &str, v: &Item) -> Result<()> { + match v.as_str() { + Some(filename) => { + let path = self.path.parent().unwrap().join(filename); + for item in dotenvy::from_path_iter(path)? { + let (k, v) = item?; + self.env.insert(k, v); + } + } + _ => parse_error!(k, v, "string")?, + } + Ok(()) + } + fn parse_env(&mut self, k: &str, v: &Item) -> Result<()> { let mut v = v.clone(); if let Some(table) = v.as_table_like_mut() { @@ -99,7 +114,9 @@ impl RtxToml { self.path_dirs = self.parse_path_env(&format!("{}.PATH", k), &path)?; } } - self.env = self.parse_hashmap(k, &v)?; + for (k, v) in self.parse_hashmap(k, &v)? { + self.env.insert(k, v); + } Ok(()) } From 4a98cd79437ebf426954a70c12d98fb1866d60f4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:55:44 -0500 Subject: [PATCH 0518/1891] feat: env var templating (#346) Fixes #332 --- .rtx.toml | 1 + Cargo.lock | 258 +++++++++++++++++- Cargo.toml | 1 + README.md | 18 ++ src/config/config_file/rtx_toml.rs | 31 ++- ..._file__rtx_toml__tests__remove_plugin.snap | 2 +- ...le__rtx_toml__tests__replace_versions.snap | 4 +- 7 files changed, 300 insertions(+), 15 deletions(-) diff --git a/.rtx.toml b/.rtx.toml index c2b081ab9..a3e86fdb0 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -1,6 +1,7 @@ dotenv = '.env' [env] FOO = "bar" +THIS_PROJECT = "{{config_root}}-{{env.PWD}}" [tools] nodejs = 'lts' diff --git a/Cargo.lock b/Cargo.lock index c3fbc4bb0..5e4d3906c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,6 +68,25 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "build-time" version = "0.1.2" @@ -238,6 +257,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -290,6 +318,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "ctor" version = "0.1.26" @@ -372,6 +410,16 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -590,6 +638,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.8" @@ -607,6 +665,30 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +[[package]] +name = "globset" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] + [[package]] name = "h2" version = "0.3.16" @@ -764,6 +846,23 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + [[package]] name = "indenter" version = "0.3.3" @@ -1089,6 +1188,50 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pest" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1357,6 +1500,7 @@ dependencies = [ "serde_json", "shell-escape", "simplelog", + "tera", "term_size", "test-log", "thiserror", @@ -1413,6 +1557,15 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1508,6 +1661,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -1617,6 +1781,23 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "tera" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a665751302f22a03c56721e23094e4dc22b04a80f381e6737a07bf7a7c70c0" +dependencies = [ + "globwalk", + "lazy_static", + "pest", + "pest_derive", + "regex", + "serde", + "serde_json", + "thread_local", + "unic-segment", +] + [[package]] name = "term_size" version = "0.3.2" @@ -1669,11 +1850,10 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "cfg-if", "once_cell", ] @@ -1862,6 +2042,68 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicode-bidi" version = "0.3.12" @@ -1940,6 +2182,16 @@ dependencies = [ "nom", ] +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index f15288fab..de16923e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ serde_derive = "1.0.152" serde_json = "1.0.92" shell-escape = "0.1.5" simplelog = { version = "0.12.0" } +tera = { version = "1.18.1", default-features = false } term_size = "0.3.2" thiserror = "1.0.39" toml = "0.7.1" diff --git a/README.md b/README.md index 180c81f13..7a83f36ed 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ v18.10.9 - [`~/.config/rtx`](#configrtx) - [`~/.cache/rtx`](#cachertx) - [`~/.local/share/rtx`](#localsharertx) +- [Templates](#templates) - [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) - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) @@ -655,6 +656,13 @@ PATH = [ _Note: other PATH-like variables like `LD_LIBRARY_PATH` cannot be set this way._ +Environment variable values can be templated, see [Templates](#templates) for details. + +```toml +[env] +LD_LIBRARY_PATH = "/some/path:{{env.LD_LIBRARY_PATH}}" +``` + `dotenv` can be used to specify a [dotenv](https://dotenv.org) file to load: ```toml @@ -951,6 +959,16 @@ These are currently experimental and only created when the "experimental" settin This will be the default location for storing shims. Currently this functionality is marked as experimental, however, and this needs to be manually set with `shims_dir`. +## Templates + +The following context objects are available inside templates: + +- `env: HashMap` – current environment variables +- `config_root: PathBuf` – directory containing the `.rtx.toml` file + +Templates are parsed with [tera](https://tera.netlify.app/docs). Currently templates are only +used for env var values, but in the future they may be used for other things. + ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index e925a7b92..96d5158d8 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -4,21 +4,23 @@ use std::fs; use std::path::{Path, PathBuf}; use std::time::Duration; -use color_eyre::eyre::eyre; +use color_eyre::eyre::{eyre, WrapErr}; use color_eyre::{Result, Section}; use log::LevelFilter; +use tera::{Context, Tera}; use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, MissingRuntimeBehavior}; -use crate::dirs; use crate::file::create_dir_all; use crate::plugins::PluginName; use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; +use crate::{dirs, env}; #[derive(Debug, Default)] pub struct RtxToml { + context: Context, path: PathBuf, toolset: Toolset, env: HashMap, @@ -44,8 +46,12 @@ macro_rules! parse_error { #[allow(dead_code)] // TODO: remove impl RtxToml { pub fn init(path: &Path) -> Self { + let mut context = Context::new(); + context.insert("env", &*env::PRISTINE_ENV); + context.insert("config_root", path.parent().unwrap().to_str().unwrap()); Self { path: path.to_path_buf(), + context, toolset: Toolset { source: Some(ToolSource::RtxToml(path.to_path_buf())), ..Default::default() @@ -115,6 +121,7 @@ impl RtxToml { } } for (k, v) in self.parse_hashmap(k, &v)? { + let v = self.parse_template(&k, &v)?; self.env.insert(k, v); } Ok(()) @@ -509,6 +516,12 @@ impl RtxToml { self.doc.as_table_mut().remove("settings"); } } + + fn parse_template(&self, k: &str, input: &str) -> Result { + let output = Tera::one_off(input, &self.context, false) + .with_context(|| format!("failed to parse template: {k}='{}'", input))?; + Ok(output) + } } impl Display for RtxToml { @@ -631,7 +644,7 @@ mod tests { #[test] fn test_env() { - let mut cf = RtxToml::init(&PathBuf::default()); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [env] foo="bar" @@ -669,7 +682,7 @@ mod tests { #[test] fn test_set_alias() { - let mut cf = RtxToml::init(&PathBuf::default()); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [alias.nodejs] 16 = "16.0.0" @@ -687,7 +700,7 @@ mod tests { #[test] fn test_remove_alias() { - let mut cf = RtxToml::init(&PathBuf::default()); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [alias.nodejs] 16 = "16.0.0" @@ -706,7 +719,7 @@ mod tests { #[test] fn test_replace_versions() { - let mut cf = RtxToml::init(&PathBuf::default()); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [tools] nodejs = ["16.0.0", "18.0.0"] @@ -723,7 +736,7 @@ mod tests { #[test] fn test_remove_plugin() { - let mut cf = RtxToml::init(&PathBuf::default()); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [tools] nodejs = ["16.0.0", "18.0.0"] @@ -737,7 +750,7 @@ mod tests { #[test] fn test_update_setting() { - let mut cf = RtxToml::init(&PathBuf::default()); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true @@ -756,7 +769,7 @@ mod tests { #[test] fn test_remove_setting() { - let mut cf = RtxToml::init(&PathBuf::default()); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap index 1c5a23ad1..ccf4993ab 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap @@ -6,7 +6,7 @@ Toolset { versions: {}, source: Some( RtxToml( - "", + "/tmp/.rtx.toml", ), ), } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index e5e74b9a1..9b4be7bc9 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -24,13 +24,13 @@ Toolset { }, ], source: RtxToml( - "", + "/tmp/.rtx.toml", ), }, }, source: Some( RtxToml( - "", + "/tmp/.rtx.toml", ), ), } From 0901c2d4ecc68ae5be22334eb4d04a72b0530d5c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:56:31 -0500 Subject: [PATCH 0519/1891] chore: Release rtx-cli version 1.25.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e4d3906c..49d3c6978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1456,7 +1456,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.24.0" +version = "1.25.0" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index de16923e5..0126d5db6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.24.0" +version = "1.25.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 7a83f36ed..492c7ec37 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.24.0 +rtx 1.25.0 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.24.0/rtx-v1.24.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.0/rtx-v1.25.0-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 5d2ead36b..be1e97814 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.24.0"; + version = "1.25.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 0fa39c8c2..04df5a928 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.24.0" +.TH rtx 1 "rtx 1.25.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.24.0 +v1.25.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e8711bb8b..9fe3121f4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.24.0 +Version: 1.25.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 0611ac05bc80954fe17e59438e90d2d619176ee2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:50:34 -0500 Subject: [PATCH 0520/1891] bug: re-enable a performance check (#347) This re-enables a check that prevents reloading all of the versions of a plugin if we are directly running a specified version --- src/toolset/tool_version.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index acf4edb3f..37c8c7689 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -8,8 +8,10 @@ use indexmap::IndexMap; use versions::{Chunk, Version}; use crate::config::Config; +use crate::dirs; use crate::plugins::Plugin; +use crate::runtime_symlinks::is_runtime_symlink; use crate::runtimes::RuntimeVersion; use crate::ui::progress_report::ProgressReport; @@ -74,12 +76,12 @@ impl ToolVersion { _ => (), } - // TODO: put this back in when it's compatible with #343 - // if dirs::INSTALLS.join(&plugin.name).join(&v).exists() { - // // if the version is already installed, no need to fetch all of the remote versions - // let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - // return Ok(rtv); - // } + let existing_path = dirs::INSTALLS.join(&plugin.name).join(&v); + if existing_path.exists() && !is_runtime_symlink(&existing_path) { + // if the version is already installed, no need to fetch all the remote versions + let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); + return Ok(rtv); + } if v == "latest" { let v = plugin.latest_version(&config.settings, None)?; From f9c33b16043662b4a554c6a9d6452d25c4e8fb49 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:31:20 -0500 Subject: [PATCH 0521/1891] added json schema for .rtx.toml --- README.md | 1 + schema/rtx.json | 158 ++++++++++++++++++++++++++++++++++++++++++ scripts/publish-s3.sh | 1 + 3 files changed, 160 insertions(+) create mode 100644 schema/rtx.json diff --git a/README.md b/README.md index 492c7ec37..e53607e1c 100644 --- a/README.md +++ b/README.md @@ -572,6 +572,7 @@ disable_default_shorthands = false # disable the default shorthands, see `RTX_DI experimental = false # enable experimental features such as shims shims_dir = '~/.local/share/rtx/shims' # [experimental] directory where shims are stored +log_level = 'debug' # log verbosity, see `RTX_LOG_LEVEL` [alias.nodejs] my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x diff --git a/schema/rtx.json b/schema/rtx.json new file mode 100644 index 000000000..7371788e8 --- /dev/null +++ b/schema/rtx.json @@ -0,0 +1,158 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://rtx.pub/schema/rtx.json", + "title": "rtx", + "description": "config file for rtx version manager (.rtx.toml)", + "type": "object", + "additionalProperties": false, + "properties": { + "dotenv": { + "description": "path to .env file", + "type": "string" + }, + "env": { + "description": "environment variables", + "type": "object", + "items": { + "description": "environment variable value", + "type": "string" + } + }, + "tools": { + "description": "dev tools to use", + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/tool" + } + }, + { + "$ref": "#/$defs/tool" + } + ] + } + }, + "plugins": { + "description": "plugins to use", + "type": "object", + "items": { + "description": "url to plugin repository", + "type": "string" + } + }, + "alias": { + "description": "custom shorthands for versions", + "type": "object", + "items": { + "description": "version to use", + "type": "string" + } + }, + "settings": { + "description": "settings for rtx", + "type": "object", + "additionalProperties": false, + "properties": { + "missing_runtime_behavior": { + "description": "what to do when a runtime is missing", + "type": "string", + "enum": [ + "ignore", + "prompt", + "autoinstall", + "warn", + "error" + ] + }, + "legacy_version_file": { + "description": "should rtx parse legacy version files (e.g. .node-version)", + "type": "boolean" + }, + "always_keep_download": { + "description": "should rtx keep downloaded files after installation", + "type": "boolean" + }, + "plugin_autoupdate_last_check_duration": { + "oneOf": [ + { + "description": "how often to check for plugin updates", + "type": "string" + }, + { + "description": "how often to check for plugin updates", + "type": "integer" + } + ] + }, + "asdf_compat": { + "description": "set to true to ensure .tool-versions will be compatible with asdf", + "type": "boolean" + }, + "jobs": { + "description": "number of tools to install in parallel, default is 4", + "type": "integer" + }, + "raw": { + "description": "directly connect plugin scripts to stdin/stdout, implies --jobs=1", + "type": "boolean" + }, + "shorthands_file": { + "description": "path to file containing shorthand mappings", + "type": "string" + }, + "disable_default_shorthands": { + "description": "disables built-in shorthands", + "type": "boolean" + }, + "experimental": { + "description": "enable experimental features", + "type": "boolean" + }, + "shims_dir": { + "description": "path to directory to output shims", + "type": "string" + }, + "log_level": { + "description": "log level", + "type": "string", + "enum": [ + "error", + "warn", + "info", + "debug", + "trace" + ] + }, + "verbose": { + "description": "display installation output", + "type": "boolean" + } + } + } + }, + "$defs": { + "tool": { + "oneOf": [ + { + "type": "string", + "description": "version of the tool to install" + }, + { + "type": "object", + "properties": { + "version": { + "description": "version of the tool to install", + "type": "string" + } + }, + "required": [ + "version" + ] + } + ] + } + } +} diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index e04fecf33..c92aee1eb 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -17,6 +17,7 @@ aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-prog aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR/schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive From 3541abf7a64831e7e0988d1350ba69ca73ebb620 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:32:11 -0500 Subject: [PATCH 0522/1891] chore: Release rtx-cli version 1.25.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49d3c6978..ccb041d37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1456,7 +1456,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.25.0" +version = "1.25.1" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 0126d5db6..1201f60df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.25.0" +version = "1.25.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e53607e1c..7cde075c0 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.25.0 +rtx 1.25.1 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.0/rtx-v1.25.0-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.1/rtx-v1.25.1-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index be1e97814..3d07b5ddf 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.25.0"; + version = "1.25.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 04df5a928..b8b8f5fd1 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.25.0" +.TH rtx 1 "rtx 1.25.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.25.0 +v1.25.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9fe3121f4..bf687b176 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.25.0 +Version: 1.25.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From a1b4ccdba407dee3d3f769ea12276df8d858d424 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:44:47 -0500 Subject: [PATCH 0523/1891] bug: patch json schema --- .rtx.toml | 1 + schema/rtx.json | 57 +++++++++++++++++++++++-------------------- scripts/publish-s3.sh | 2 +- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/.rtx.toml b/.rtx.toml index a3e86fdb0..e31c6c8b2 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -1,3 +1,4 @@ +#:schema ./schema/rtx.json dotenv = '.env' [env] FOO = "bar" diff --git a/schema/rtx.json b/schema/rtx.json index 7371788e8..c8fbb9360 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -38,7 +38,7 @@ "plugins": { "description": "plugins to use", "type": "object", - "items": { + "additionalProperties": { "description": "url to plugin repository", "type": "string" } @@ -46,11 +46,38 @@ "alias": { "description": "custom shorthands for versions", "type": "object", - "items": { - "description": "version to use", - "type": "string" + "additionalProperties": { + "description": "plugin to set aliases for", + "type": "object", + "additionalProperties": { + "description": "version alias points to", + "type": "string" + } } }, + "settings": {"$ref": "#/$defs/settings"} + }, + "$defs": { + "tool": { + "oneOf": [ + { + "type": "string", + "description": "version of the tool to install" + }, + { + "type": "object", + "properties": { + "version": { + "description": "version of the tool to install", + "type": "string" + } + }, + "required": [ + "version" + ] + } + ] + }, "settings": { "description": "settings for rtx", "type": "object", @@ -132,27 +159,5 @@ } } } - }, - "$defs": { - "tool": { - "oneOf": [ - { - "type": "string", - "description": "version of the tool to install" - }, - { - "type": "object", - "properties": { - "version": { - "description": "version of the tool to install", - "type": "string" - } - }, - "required": [ - "version" - ] - } - ] - } } } diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index c92aee1eb..ca09ac05e 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -17,7 +17,7 @@ aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-prog aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" -aws s3 cp "$RELEASE_DIR/schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" +aws s3 cp "./schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive From 8a91435831b260a8879af5d9388dd079bd55c2be Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:45:22 -0500 Subject: [PATCH 0524/1891] chore: Release rtx-cli version 1.25.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccb041d37..2a80ac85d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1456,7 +1456,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.25.1" +version = "1.25.2" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 1201f60df..691f33ed8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.25.1" +version = "1.25.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 7cde075c0..2531bc40e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.25.1 +rtx 1.25.2 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.1/rtx-v1.25.1-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.2/rtx-v1.25.2-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 3d07b5ddf..62293188d 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.25.1"; + version = "1.25.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index b8b8f5fd1..edecc8cf4 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.25.1" +.TH rtx 1 "rtx 1.25.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.25.1 +v1.25.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index bf687b176..3e4dc9d9c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.25.1 +Version: 1.25.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 8f074c18901c000d1db8c8a4fd3239b7eedddc50 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:55:10 -0500 Subject: [PATCH 0525/1891] bug: fix json schema path --- scripts/publish-s3.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index ca09ac05e..e131fa5ee 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -17,7 +17,7 @@ aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-prog aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" -aws s3 cp "./schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" +aws s3 cp "./rtx/schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive From 61e651686331a69e01a08059c64f5108172a8fd6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:55:59 -0500 Subject: [PATCH 0526/1891] chore: Release rtx-cli version 1.25.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a80ac85d..1082c0077 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1456,7 +1456,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.25.2" +version = "1.25.3" dependencies = [ "base64", "build-time", diff --git a/Cargo.toml b/Cargo.toml index 691f33ed8..3312981e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.25.2" +version = "1.25.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 2531bc40e..c19abef44 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.25.2 +rtx 1.25.3 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.2/rtx-v1.25.2-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.3/rtx-v1.25.3-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 62293188d..f23fc446c 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.25.2"; + version = "1.25.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index edecc8cf4..c1e3f5ec7 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.25.2" +.TH rtx 1 "rtx 1.25.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.25.2 +v1.25.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 3e4dc9d9c..8af04d85d 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.25.2 +Version: 1.25.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 8e2a9c07b7f4969e79cb2c821b64e2fdc94cb194 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:45:07 -0500 Subject: [PATCH 0527/1891] chore: make toml parsing errors more visible (#349) --- src/config/mod.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 11f7912cc..ff5929eda 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::Arc; use std::thread; -use color_eyre::eyre::{eyre, Result, WrapErr}; -use color_eyre::Report; +use color_eyre::eyre::{eyre, Result}; + use console::style; use indexmap::IndexMap; use itertools::Itertools; @@ -291,15 +291,17 @@ fn load_rtxrc() -> Result { trace!("settings does not exist {:?}", settings_path); Ok(RtxToml::init(&settings_path)) } - true => match RtxToml::from_file(&settings_path) - .wrap_err_with(|| err_load_settings(&settings_path)) - { + true => match RtxToml::from_file(&settings_path) { Ok(cf) => Ok(cf), Err(err) => match RtxToml::migrate(&settings_path) { Ok(cf) => Ok(cf), Err(e) => { - error!("Error migrating config.toml: {:#}", e); - Err(err) + trace!("Error migrating config.toml: {:#}", e); + Err(eyre!( + "Error parsing {}: {:#}", + &settings_path.display(), + err + )) } }, }, @@ -456,13 +458,6 @@ fn load_aliases(config_files: &IndexMap>) -> AliasM aliases } -fn err_load_settings(settings_path: &Path) -> Report { - eyre!( - "error loading settings from {}", - settings_path.to_string_lossy() - ) -} - fn err_no_shims_dir() -> Result { Err(eyre!(indoc::formatdoc!( r#" From f1c14e4eac105dfb4dc88c4a7214ef105864e8e0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:53:28 -0500 Subject: [PATCH 0528/1891] minor tweak to alias parse error (#350) --- src/config/config_file/rtx_toml.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 96d5158d8..cf2fcd62e 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -174,7 +174,7 @@ impl RtxToml { Some(s) => { plugin_aliases.insert(from.into(), s.into()); } - _ => parse_error!(format!("{}.{}", k, from), v, "string")?, + _ => parse_error!(format!("{}.{}", k, from), to, "string")?, } } } @@ -420,7 +420,7 @@ impl RtxToml { match v.as_value() { Some(Value::String(s)) => Ok(humantime::parse_duration(s.value())?), Some(Value::Integer(i)) => Ok(Duration::from_secs(*i.value() as u64 * 60)), - _ => Err(eyre!("expected {k} to be an integer, got: {v}")), + _ => parse_error!(k, v, "duration")?, } } @@ -434,21 +434,21 @@ impl RtxToml { fn parse_usize(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_integer()) { Some(Some(v)) => Ok(v as usize), - _ => Err(eyre!("expected {k} to be an integer, got: {v}")), + _ => parse_error!(k, v, "usize")?, } } fn parse_path(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => Ok(v.into()), - _ => Err(eyre!("expected {k} to be a path, got: {v}")), + _ => parse_error!(k, v, "path")?, } } fn parse_string(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => Ok(v.into()), - _ => Err(eyre!("expected {k} to be a string, got: {v}")), + _ => parse_error!(k, v, "string")?, } } @@ -613,12 +613,6 @@ impl ConfigFile for RtxToml { } } -#[allow(dead_code)] // TODO: remove -const ENV_SUGGESTION: &str = r#" -[env] -FOO = "bar" -"#; - #[cfg(test)] mod tests { use indoc::formatdoc; From d2cb0a9f5d16ce457c299f8fd626e17d0dd356f7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 20:13:51 -0500 Subject: [PATCH 0529/1891] Update README.md kudos to @delicb for this snippet --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c19abef44..9bf6342fc 100644 --- a/README.md +++ b/README.md @@ -968,7 +968,15 @@ The following context objects are available inside templates: - `config_root: PathBuf` – directory containing the `.rtx.toml` file Templates are parsed with [tera](https://tera.netlify.app/docs). Currently templates are only -used for env var values, but in the future they may be used for other things. +used for env var values, but in the future they may be used for other things. Submit a ticket if +you think some configuration would benefit from templating with Tera. + +Tera is quite powerful. For example, this snippet will get the directory name of the project: + +```toml +[env] +PROJECT_NAME = "{{config_root | split(pat='/') | last}}" +``` ## FAQs From 319744e1eedee7fd6844467ccb595c71f936165a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 20:40:37 -0500 Subject: [PATCH 0530/1891] feat: added tera templating to .tool-versions (#351) --- README.md | 13 ++++++----- src/config/config_file/rtx_toml.rs | 6 ++--- src/config/config_file/tool_versions.rs | 30 +++++++++++++++++++++---- src/main.rs | 1 + src/tera.rs | 10 +++++++++ 5 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 src/tera.rs diff --git a/README.md b/README.md index 9bf6342fc..9f0698b99 100644 --- a/README.md +++ b/README.md @@ -962,16 +962,19 @@ experimental, however, and this needs to be manually set with `shims_dir`. ## Templates +Templates are used in the following locations: + +- `.tool-versions` files +- env var values in `.rtx.toml` +- _(Submit a ticket if you want to see it used elsewhere!)_ + The following context objects are available inside templates: - `env: HashMap` – current environment variables - `config_root: PathBuf` – directory containing the `.rtx.toml` file -Templates are parsed with [tera](https://tera.netlify.app/docs). Currently templates are only -used for env var values, but in the future they may be used for other things. Submit a ticket if -you think some configuration would benefit from templating with Tera. - -Tera is quite powerful. For example, this snippet will get the directory name of the project: +Templates are parsed with [tera](https://tera.netlify.app/docs)—which is quite powerful. For +example, this snippet will get the directory name of the project: ```toml [env] diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index cf2fcd62e..f97420884 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -13,10 +13,11 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, MissingRuntimeBehavior}; +use crate::dirs; use crate::file::create_dir_all; use crate::plugins::PluginName; +use crate::tera::BASE_CONTEXT; use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; -use crate::{dirs, env}; #[derive(Debug, Default)] pub struct RtxToml { @@ -46,8 +47,7 @@ macro_rules! parse_error { #[allow(dead_code)] // TODO: remove impl RtxToml { pub fn init(path: &Path) -> Self { - let mut context = Context::new(); - context.insert("env", &*env::PRISTINE_ENV); + let mut context = BASE_CONTEXT.clone(); context.insert("config_root", path.parent().unwrap().to_str().unwrap()); Self { path: path.to_path_buf(), diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index d2cb00eef..b772090b1 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -9,11 +9,13 @@ use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; use indexmap::IndexMap; use itertools::Itertools; +use tera::{Context, Tera}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::file::display_path; use crate::plugins::PluginName; +use crate::tera::BASE_CONTEXT; use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; // python 3.11.0 3.10.0 @@ -23,6 +25,7 @@ use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; /// represents asdf's .tool-versions file #[derive(Debug, Default)] pub struct ToolVersions { + context: Context, path: PathBuf, pre: String, plugins: IndexMap, @@ -37,7 +40,10 @@ struct ToolVersionPlugin { impl ToolVersions { pub fn init(filename: &Path) -> ToolVersions { + let mut context = BASE_CONTEXT.clone(); + context.insert("config_root", filename.parent().unwrap().to_str().unwrap()); ToolVersions { + context, toolset: Toolset::new(ToolSource::ToolVersions(filename.to_path_buf())), path: filename.to_path_buf(), ..Default::default() @@ -51,6 +57,7 @@ impl ToolVersions { pub fn parse_str(s: &str, path: PathBuf) -> Result { let mut cf = Self::init(&path); + let s = Tera::one_off(s, &cf.context, false)?; for line in s.lines() { if !line.trim_start().starts_with('#') { break; @@ -59,7 +66,7 @@ impl ToolVersions { cf.pre.push('\n'); } - cf.plugins = Self::parse_plugins(s)?; + cf.plugins = Self::parse_plugins(&s)?; cf.populate_toolset(); Ok(cf) } @@ -233,7 +240,8 @@ pub(crate) mod tests { shfmt 3.6.0 # tail comment "}; - let tv = ToolVersions::parse_str(orig, PathBuf::new()).unwrap(); + let path = dirs::CURRENT.join(".test-tool-versions"); + let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_eq!(tv.dump(), orig); } @@ -242,7 +250,20 @@ pub(crate) mod tests { let orig = indoc! {" ruby: 3.0.5 "}; - let tv = ToolVersions::parse_str(orig, PathBuf::new()).unwrap(); + let path = dirs::CURRENT.join(".test-tool-versions"); + let tv = ToolVersions::parse_str(orig, path).unwrap(); + assert_snapshot!(tv.dump(), @r###" + ruby 3.0.5 + "###); + } + + #[test] + fn test_parse_tera() { + let orig = indoc! {" + ruby: {{'3.0.5'}} + "}; + let path = dirs::CURRENT.join(".test-tool-versions"); + let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_snapshot!(tv.dump(), @r###" ruby 3.0.5 "###); @@ -253,7 +274,8 @@ pub(crate) mod tests { let orig = indoc! {" ruby: 3.0.5 3.1 "}; - let tv = ToolVersions::parse_str(orig, PathBuf::new()).unwrap(); + let path = dirs::CURRENT.join(".test-tool-versions"); + let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_display_snapshot!(tv.to_toolset(), @"ruby@3.0.5 ruby@3.1"); } } diff --git a/src/main.rs b/src/main.rs index 02684d625..089ccaeae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,7 @@ pub mod runtimes; mod shell; mod shims; mod shorthands; +pub mod tera; #[cfg(test)] mod test; mod toolset; diff --git a/src/tera.rs b/src/tera.rs new file mode 100644 index 000000000..a0854e3cf --- /dev/null +++ b/src/tera.rs @@ -0,0 +1,10 @@ +use once_cell::sync::Lazy; +use tera::Context; + +use crate::env; + +pub static BASE_CONTEXT: Lazy = Lazy::new(|| { + let mut context = Context::new(); + context.insert("env", &*env::PRISTINE_ENV); + context +}); From fb5f29b08df310ae45d853bd5962f6dc6ea3bf23 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 20:51:33 -0500 Subject: [PATCH 0531/1891] feat: added tera templating to .rtx.toml config (#352) --- README.md | 2 +- src/config/config_file/rtx_toml.rs | 38 ++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 9f0698b99..cc1ace456 100644 --- a/README.md +++ b/README.md @@ -965,7 +965,7 @@ experimental, however, and this needs to be manually set with `shims_dir`. Templates are used in the following locations: - `.tool-versions` files -- env var values in `.rtx.toml` +- `.rtx.toml` files for most configuration - _(Submit a ticket if you want to see it used elsewhere!)_ The following context objects are available inside templates: diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index f97420884..d1ea134c7 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -142,6 +142,7 @@ impl RtxToml { match v.as_str() { Some("$PATH") => {} Some(s) => { + let s = self.parse_template(k, s)?; let s = match s.strip_prefix("./") { Some(s) => config_root.join(s), None => match s.strip_prefix("~/") { @@ -172,7 +173,9 @@ impl RtxToml { for (from, to) in table.iter() { match to.as_str() { Some(s) => { - plugin_aliases.insert(from.into(), s.into()); + let from = self.parse_template(&k, from)?; + let s = self.parse_template(&k, s)?; + plugin_aliases.insert(from, s); } _ => parse_error!(format!("{}.{}", k, from), to, "string")?, } @@ -194,7 +197,9 @@ impl RtxToml { for (k, v) in table.iter() { match v.as_str() { Some(s) => { - env.insert(k.into(), s.into()); + let k = self.parse_template(key, k)?; + let s = self.parse_template(key, s)?; + env.insert(k, s); } _ => parse_error!(key, v, "string")?, } @@ -325,15 +330,18 @@ impl RtxToml { fn parse_tool_version_value(&self, key: &str, v: &Value) -> Result { match v.as_str() { - Some(s) => match s.split_once(':') { - Some(("prefix", v)) => Ok(ToolVersionType::Prefix(v.into())), - Some(("path", v)) => Ok(ToolVersionType::Path(v.into())), - Some(("ref", v)) => Ok(ToolVersionType::Ref(v.into())), - Some((unknown, v)) => { - parse_error!(format!("{}.{}", key, unknown), v, "prefix, path, or ref")? + Some(s) => { + let s = self.parse_template(key, s)?; + match s.split_once(':') { + Some(("prefix", v)) => Ok(ToolVersionType::Prefix(v.into())), + Some(("path", v)) => Ok(ToolVersionType::Path(v.into())), + Some(("ref", v)) => Ok(ToolVersionType::Ref(v.into())), + Some((unknown, v)) => { + parse_error!(format!("{}.{}", key, unknown), v, "prefix, path, or ref")? + } + None => Ok(ToolVersionType::Version(s)), } - None => Ok(ToolVersionType::Version(s.into())), - }, + } _ => parse_error!(key, v, "string")?, } } @@ -440,14 +448,20 @@ impl RtxToml { fn parse_path(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { - Some(Some(v)) => Ok(v.into()), + Some(Some(v)) => { + let v = self.parse_template(k, v)?; + Ok(v.into()) + } _ => parse_error!(k, v, "path")?, } } fn parse_string(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { - Some(Some(v)) => Ok(v.into()), + Some(Some(v)) => { + let v = self.parse_template(k, v)?; + Ok(v) + } _ => parse_error!(k, v, "string")?, } } From 5c06d19750b3159c03bdf3d55b0caa31e2264a35 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 21:23:03 -0500 Subject: [PATCH 0532/1891] feat: added tera exec() function (#353) --- README.md | 15 ++++++++++++++ src/config/config_file/rtx_toml.rs | 8 +++++--- src/config/config_file/tool_versions.rs | 13 +++++++----- src/tera.rs | 27 ++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cc1ace456..9dd18d968 100644 --- a/README.md +++ b/README.md @@ -962,6 +962,10 @@ experimental, however, and this needs to be manually set with `shims_dir`. ## Templates +> **Warning** +> +> This functionality is experimental and may change in the future. + Templates are used in the following locations: - `.tool-versions` files @@ -973,6 +977,10 @@ The following context objects are available inside templates: - `env: HashMap` – current environment variables - `config_root: PathBuf` – directory containing the `.rtx.toml` file +As well as these functions: + +- `exec(command: &str) -> String` – execute a command and return the output + Templates are parsed with [tera](https://tera.netlify.app/docs)—which is quite powerful. For example, this snippet will get the directory name of the project: @@ -981,6 +989,13 @@ example, this snippet will get the directory name of the project: PROJECT_NAME = "{{config_root | split(pat='/') | last}}" ``` +Here's another using `exec()`: + +```toml +[aliases] +current = "{{exec(command='node --version')}}" +``` + ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index d1ea134c7..9d4533016 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -7,7 +7,7 @@ use std::time::Duration; use color_eyre::eyre::{eyre, WrapErr}; use color_eyre::{Result, Section}; use log::LevelFilter; -use tera::{Context, Tera}; +use tera::Context; use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; @@ -16,7 +16,7 @@ use crate::config::{AliasMap, MissingRuntimeBehavior}; use crate::dirs; use crate::file::create_dir_all; use crate::plugins::PluginName; -use crate::tera::BASE_CONTEXT; +use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; #[derive(Debug, Default)] @@ -532,7 +532,9 @@ impl RtxToml { } fn parse_template(&self, k: &str, input: &str) -> Result { - let output = Tera::one_off(input, &self.context, false) + let dir = self.path.parent().unwrap(); + let output = get_tera(dir) + .render_str(input, &self.context) .with_context(|| format!("failed to parse template: {k}='{}'", input))?; Ok(output) } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index b772090b1..98c84795b 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -9,13 +9,13 @@ use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; use indexmap::IndexMap; use itertools::Itertools; -use tera::{Context, Tera}; +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::tera::BASE_CONTEXT; +use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; // python 3.11.0 3.10.0 @@ -57,7 +57,8 @@ impl ToolVersions { pub fn parse_str(s: &str, path: PathBuf) -> Result { let mut cf = Self::init(&path); - let s = Tera::one_off(s, &cf.context, false)?; + let dir = path.parent().unwrap(); + let s = get_tera(dir).render_str(s, &cf.context)?; for line in s.lines() { if !line.trim_start().starts_with('#') { break; @@ -260,12 +261,14 @@ pub(crate) mod tests { #[test] fn test_parse_tera() { let orig = indoc! {" - ruby: {{'3.0.5'}} + ruby {{'3.0.5'}} + python {{exec(command='echo 3.11.0')}} "}; let path = dirs::CURRENT.join(".test-tool-versions"); let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_snapshot!(tv.dump(), @r###" - ruby 3.0.5 + ruby 3.0.5 + python 3.11.0 "###); } diff --git a/src/tera.rs b/src/tera.rs index a0854e3cf..99db0a01d 100644 --- a/src/tera.rs +++ b/src/tera.rs @@ -1,6 +1,10 @@ +use std::collections::HashMap; +use std::path::Path; + use once_cell::sync::Lazy; -use tera::Context; +use tera::{Context, Tera, Value}; +use crate::cmd::cmd; use crate::env; pub static BASE_CONTEXT: Lazy = Lazy::new(|| { @@ -8,3 +12,24 @@ pub static BASE_CONTEXT: Lazy = Lazy::new(|| { context.insert("env", &*env::PRISTINE_ENV); context }); + +pub fn get_tera(dir: &Path) -> Tera { + let mut tera = Tera::default(); + let dir = dir.to_path_buf(); + tera.register_function( + "exec", + move |args: &HashMap| -> tera::Result { + match args.get("command") { + Some(Value::String(command)) => { + let result = cmd("bash", ["-c", command]) + .dir(&dir) + .full_env(&*env::PRISTINE_ENV) + .read()?; + Ok(Value::String(result)) + } + _ => Err("exec command must be a string".into()), + } + }, + ); + tera +} From bf78c81077ead943dae3e01216912af86e855d65 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 21:24:01 -0500 Subject: [PATCH 0533/1891] chore: Release rtx-cli version 1.25.4 --- Cargo.lock | 73 ++++++++++++++++++++++++------------------ Cargo.toml | 2 +- README.md | 4 +-- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 49 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1082c0077..20255212b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,7 +97,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.9" +version = "4.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9d6ada83c1edcce028902ea27dd929069c70df4c7600b131b4d9a1ad2879cc" +checksum = "ce38afc168d8665cfc75c7b1dd9672e50716a137f433f070991619744a67342a" dependencies = [ "bitflags", "clap_derive", @@ -179,7 +179,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -335,7 +335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -350,9 +350,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" +checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038" dependencies = [ "cc", "cxxbridge-flags", @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" +checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca" dependencies = [ "cc", "codespan-reporting", @@ -372,24 +372,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 2.0.0", ] [[package]] name = "cxxbridge-flags" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" +checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31" [[package]] name = "cxxbridge-macro" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" +checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.0", ] [[package]] @@ -1218,7 +1218,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1271,7 +1271,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -1456,7 +1456,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.25.3" +version = "1.25.4" dependencies = [ "base64", "build-time", @@ -1614,19 +1614,19 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.156" +version = "1.0.157" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.157" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.0", ] [[package]] @@ -1768,6 +1768,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cff13bb1732bccfe3b246f3fdb09edfd51c01d6f5299b7ccd9457c2e4e37774" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.4.0" @@ -1825,27 +1836,27 @@ checksum = "38f0c854faeb68a048f0f2dc410c5ddae3bf83854ef0e4977d58306a5edef50e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.0", ] [[package]] @@ -2235,7 +2246,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -2269,7 +2280,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 3312981e7..f3f7a0ce4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.25.3" +version = "1.25.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 9dd18d968..de21d6b7e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.25.3 +rtx 1.25.4 ``` Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. @@ -330,7 +330,7 @@ $ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.3/rtx-v1.25.3-linux-x64 | tar -xJv +$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.4/rtx-v1.25.4-linux-x64 | tar -xJv $ mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index f23fc446c..f6046830f 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.25.3"; + version = "1.25.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c1e3f5ec7..54a79181e 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.25.3" +.TH rtx 1 "rtx 1.25.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.25.3 +v1.25.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 8af04d85d..84e91c13b 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.25.3 +Version: 1.25.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 237529603b4dc7114d8dae459b50a8ee433d85ea Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 23:06:11 -0500 Subject: [PATCH 0534/1891] docs --- README.md | 228 ++++++++++++++++++++------------------------ src/build_time.rs | 4 +- src/cli/activate.rs | 8 +- src/config/mod.rs | 2 +- src/env.rs | 2 +- 5 files changed, 114 insertions(+), 130 deletions(-) diff --git a/README.md b/README.md index de21d6b7e..d938c9cb8 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,10 @@ Note that calling `which node` gives us a real path to the binary, not a shim. - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. - **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. - **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. -- **No shims** - shims (used by asdf) cause problems, they break `which node`, and add overhead. We don't use them by default. -- **Better UX** - asdf is full of strange UX decisions (like `asdf plugin add` but also `asdf install`). We've taken care to make rtx easy to use. -- **Fuzzy matching and aliases** - no need to specify exact version numbers like with asdf. -- **One command install** - No need to manually install each plugin, just run `rtx install` and it will install all the plugins you need. +- **No shims** - shims cause problems, they break `which`, and add overhead. By default, rtx + does not use them—however you can if you want to. +- **Fuzzy matching and aliases** - It's enough to just say you want "v18" of node, or the "lts" + version. rtx will figure out the right version without you needing to specify an exact version. - **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. ## Quickstart @@ -40,13 +40,12 @@ $ rtx --version rtx 1.25.4 ``` -Hook rtx into to your shell. This will automatically add `~/bin` to `PATH` if it isn't already. -(choose one, and open a new shell session for the changes to take effect): +Hook rtx into to your shell (pick the right one for your shell): ```sh-session -$ echo 'eval "$(~/bin/rtx activate bash)"' >> ~/.bashrc -$ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc -$ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish +echo 'eval "$(~/bin/rtx activate bash)"' >> ~/.bashrc +echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc +echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` > **Warning** @@ -60,14 +59,9 @@ Install a runtime and set it as the default: $ rtx install nodejs@18 $ rtx global nodejs@18 $ node -v -v18.10.9 +v18.15.0 ``` -> **Note** -> -> `rtx install` is optional, `rtx global` will prompt to install the runtime if it's not -> already installed. This is configurable in [`~/.config/rtx/config.toml`](#configuration). - ## Table of Contents @@ -80,7 +74,7 @@ v18.10.9 - [About](#about) - [What do I use this for?](#what-do-i-use-this-for) - [How it works](#how-it-works) - - [Common example commands](#common-example-commands) + - [Common commands](#common-commands) - [Installation](#installation) - [Standalone](#standalone) - [Homebrew](#homebrew) @@ -190,14 +184,11 @@ directory. Other projects on your machine can use a different set of versions. rtx is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecosystem](https://github.com/asdf-vm/asdf-plugins) under the hood. However, it is _much_ faster than asdf and has a more friendly user experience. -For more on how rtx compares to asdf, [see below](#comparison-to-asdf). The goal of this project -was to create a better front-end to asdf. +For more on how rtx compares to asdf, [see below](#comparison-to-asdf). It uses the same `.tool-versions` file that asdf uses. It's also compatible with idiomatic version files like `.node-version` and `.ruby-version`. See [Legacy Version Files](#legacy-version-files) below. -Come chat about rtx on [discord](https://discord.gg/mABnUDvP57). - ### What do I use this for? Typically, developers would use rtx to manage versions of their dev tools for _local_ development. @@ -206,38 +197,41 @@ on the same machine. (For example, one project might require python-3.10 and ano Using rtx in production is less common but still a supported use-case. Usually a production setup won't have different directories for different projects with different dev tool requirements. -However using `.tool-versions`/`.rtx.toml` config in production provides parity with local development +That said, using `.tool-versions`/`.rtx.toml` config in production provides parity with local +development so rtx is still definitely useful in production setups. See the [GitHub Action](#github-actions) for an example of using rtx in production. ### How it works -rtx installs as a shell extension (e.g. `rtx activate zsh`) that sets the `PATH` +rtx hooks into your shell (with `rtx activate zsh`) and sets the `PATH` environment variable to point your shell to the correct runtime binaries. When you `cd` into a -directory containing a `.tool-versions` file, rtx will automatically activate the correct versions. +directory containing a `.tool-versions`/`.rtx.toml` file, rtx will automatically set the +appropriate tool versions in `PATH`. -Every time your prompt starts it will call `rtx hook-env` to fetch new environment variables. This -should be very fast and it exits early if the the directory wasn't changed or the `.tool-versions` -files haven't been updated. On my machine this takes 4ms in the fast case, 14ms in the slow case. See [Performance](#performance) for more on this topic. +After activating, every time your prompt starts it will call `rtx hook-env` to fetch new +environment variables. +This should be very fast. It exits early if the directory wasn't changed or `.tool-versions`/`.rtx.toml` files haven't been modified. Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies `PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids any overhead, but it also makes it so commands like `which node` work as expected. This also means there isn't any need to run `asdf reshim` after installing new runtime binaries. -rtx does not directly install runtimes. Instead, it uses asdf plugins to install runtimes. See -[plugins](#plugins) below. +You should note that rtx does not directly install these tools. +Instead, it leverages plugins to install runtimes. +See [plugins](#plugins) below. -### Common example commands +### Common commands - rtx install nodejs@18.0.0 Install a specific version number - rtx install nodejs@18.0 Install a fuzzy version number - rtx local nodejs@18 Use node-18.x in current project - rtx global nodejs@18 Use node-18.x as default + rtx install nodejs@18.0.0 Install a specific version number + rtx install nodejs@18 Install a fuzzy version number + rtx local nodejs@18 Use node-18.x in current project + rtx global nodejs@18 Use node-18.x as default - rtx install nodejs Install the version specified in .tool-versions - rtx local nodejs@latest Use latest node in current directory - rtx global nodejs@system Use system node as default + rtx install nodejs Install the version specified in .tool-versions + rtx local nodejs@latest Use latest node in current directory + rtx global nodejs@system Use system node as default rtx x nodejs@18 -- node app.js Run `node app.js` with the PATH pointing to node-18.x @@ -248,14 +242,14 @@ rtx does not directly install runtimes. Instead, it uses asdf plugins to install Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate script in your rc file, rtx will automatically add itself to `PATH`. -```sh-session -$ curl https://rtx.pub/install.sh | sh +``` +curl https://rtx.pub/install.sh | sh ``` or if you're allergic to `| sh`: -```sh-session -$ curl https://rtx.pub/rtx-latest-macos-arm64 > /usr/local/bin/rtx +``` +curl https://rtx.pub/rtx-latest-macos-arm64 > /usr/local/bin/rtx ``` It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` @@ -272,73 +266,70 @@ Supported platforms: - `linux` If you need something else, compile it with [cargo](#cargo). +[Windows isn't currently supported.](https://github.com/jdxcode/rtx/discussions/66) ### Homebrew -There are 2 ways to install rtx with Homebrew. The recommended method is to use -the custom tap which will always contain the latest release. - -```sh-session -$ brew install jdxcode/tap/rtx +``` +brew install rtx ``` -Alternatively, you can use the built-in tap (homebrew-core), which will be updated -once Homebrew maintainers merge the PR for a new release: +Alternatively, use the custom tap (which is updated immediately after a release)): -```sh-session -$ brew install rtx +``` +brew install jdxcode/tap/rtx ``` ### Cargo Build from source with Cargo: -```sh-session -$ cargo install rtx-cli +``` +cargo install rtx-cli ``` Do it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall): -```sh-session -$ cargo install cargo-binstall -$ cargo binstall rtx-cli +``` +cargo install cargo-binstall +cargo binstall rtx-cli ``` Build from the latest commit in main: -```sh-session -$ cargo install rtx-cli --git https://github.com/jdxcode/rtx --branch main +``` +cargo install rtx-cli --git https://github.com/jdxcode/rtx --branch main ``` ### npm -rtx is available on npm as precompiled binaries. This isn't a node.js package, just distributed -via npm. It can be useful for JS projects that want to setup rtx via `package.json` or `npx`. +rtx is available on npm as a precompiled binary. This isn't a node.js package—just distributed +via npm. This is useful for JS projects that want to setup rtx via `package.json` or `npx`. -```sh-session -$ npm install -g rtx-cli +``` +npm install -g rtx-cli ``` -Or use npx if you just want to test it out for a single command without fully installing: +Use npx if you just want to test it out for a single command without fully installing: -```sh-session -$ npx rtx-cli exec python@3.11 -- python some_script.py +``` +npx rtx-cli exec python@3.11 -- python some_script.py ``` ### GitHub Releases Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). -```sh-session -$ curl https://github.com/jdxcode/rtx/releases/download/v1.25.4/rtx-v1.25.4-linux-x64 | tar -xJv -$ mv rtx/bin/rtx /usr/local/bin +``` +curl https://github.com/jdxcode/rtx/releases/download/v1.25.4/rtx-v1.25.4-linux-x64 | tar -xJv +mv rtx/bin/rtx /usr/local/bin ``` ### apt For installation on Ubuntu/Debian: -```sh-session +``` wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list sudo apt update @@ -357,7 +348,7 @@ sudo apt install -y rtx For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: -```sh-session +``` dnf install -y dnf-plugins-core dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo dnf install -y rtx @@ -365,7 +356,7 @@ dnf install -y rtx ### yum -```sh-session +``` yum install -y yum-utils yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo yum install -y rtx @@ -375,7 +366,7 @@ yum install -y rtx For Alpine Linux: -```sh-session +``` apk add rtx --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ ``` @@ -383,7 +374,7 @@ apk add rtx --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ For Arch Linux: -```sh-session +``` git clone https://aur.archlinux.org/rtx.git cd rtx makepkg -si @@ -432,14 +423,14 @@ systems. ### Bash -```sh-session -$ echo 'eval "$(rtx activate bash)"' >> ~/.bashrc +``` +echo 'eval "$(rtx activate bash)"' >> ~/.bashrc ``` ### Fish -```sh-session -$ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish +``` +echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` ### Xonsh @@ -584,16 +575,13 @@ These settings can also be managed with `rtx settings ls|get|set|unset`. ### [experimental] `.rtx.toml` `.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` -file. Think of `~/.config/rtx/config.toml` as just a -special `.rtx.toml` which is used from any directory on the machine. - -It allows for functionality that is not possible with `.tool-versions`, such as: +file. It allows for functionality that is not possible with `.tool-versions`, such as: - setting arbitrary env vars while inside the directory - passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). -- specifying plugin repo url for custom plugins so it does not need to be added manually +- specifying custom plugin urls -Here is what the config looks like: +Here is what the `.rtx.toml` looks like: ```toml [env] @@ -629,8 +617,7 @@ my_custom_node = '18' ``` `.rtx.toml` is currently experimental and may change in minor versions of rtx. It does not -require setting `experimental = true` in the global config in part because this config can -itself contain the setting for `experimental`. +require setting `experimental = true` to use, however. #### `[env]` - Arbitrary Environment Variables @@ -657,7 +644,7 @@ PATH = [ _Note: other PATH-like variables like `LD_LIBRARY_PATH` cannot be set this way._ -Environment variable values can be templated, see [Templates](#templates) for details. +Environment variable values can be templates, see [Templates](#templates) for details. ```toml [env] @@ -680,18 +667,20 @@ rtx can also be configured via environment variables. The following options are This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. -```sh-session -$ RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@18 -$ RTX_NODEJS_VERSION=18 rtx exec -- node --version +``` +RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@18 +RTX_NODEJS_VERSION=18 rtx exec -- node --version ``` #### `RTX_DATA_DIR` -This is the directory where rtx stores its data. The default is `~/.local/share/rtx`. +This is the directory where rtx stores plugins and tool installs. The default location is `~/.local/share/rtx`. #### `RTX_CACHE_DIR` -This is the directory where rtx stores cache. The default is `~/.cache/rtx` on Linux and `~/Library/Caches/rtx` on macOS. +This is the directory where rtx stores internal cache. The default location is `~/.cache/rtx` on +Linux and +`~/Library/Caches/rtx` on macOS. #### `RTX_CONFIG_FILE` @@ -700,33 +689,35 @@ This is the path to the config file. The default is `~/.config/rtx/config.toml`. #### `RTX_DEFAULT_TOOL_VERSIONS_FILENAME` -Set to something other than ".tool-versions" to have rtx look for configuration with alternate names. +Set to something other than ".tool-versions" to have rtx look for `.tool-versions` files but with +a different name. #### `RTX_DEFAULT_CONFIG_FILENAME` -Set to something other than ".rtx.toml" to have rtx look for configuration with alternate names. - -This is the same as `RTX_DEFAULT_TOOL_VERSIONS_FILENAME` but for `.rtx.toml` format. +Set to something other than `.rtx.toml` to have rtx look for `.rtx.toml` config files with a different name. #### `RTX_${PLUGIN}_VERSION` Set the version for a runtime. For example, `RTX_NODEJS_VERSION=18` will use nodejs@18.x regardless -of what is set in `.tool-versions`. +of what is set in `.tool-versions`/`.rtx.toml`. #### `RTX_LEGACY_VERSION_FILE` Plugins can read the versions files used by other version managers (if enabled by the plugin) -for example, .nvmrc in the case of nodejs's nvm. +for example, `.nvmrc` in the case of nodejs's nvm. See [legacy version files](#legacy-version-files) for more +information. #### `RTX_USE_TOML` -Set to `1` to use default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for -configuration. +Set to `1` to default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for +configuration. This will be default behavior once we hit the [Calver](#calver) release. #### `RTX_LOG_LEVEL=trace|debug|info|warn|error` -Can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1`. These adjust the log -output to the screen. +These change the verbository of rtx. + +You can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1` as well as +`--log-level=trace|debug|info|warn|error`. #### `RTX_LOG_FILE=~/.rtx/rtx.log` @@ -734,18 +725,19 @@ Output logs to a file. #### `RTX_LOG_FILE_LEVEL=trace|debug|info|warn|error` -Same as `RTX_LOG_LEVEL` but for the log file output level. This is useful if you want +Same as `RTX_LOG_LEVEL` but for the log _file_ output level. This is useful if you want to store the logs but not have them litter your display. #### `RTX_VERBOSE=1` This shows the installation output during `rtx install` and `rtx plugin install`. This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have -2 configuration for the same thing, but for now it is it's own config. +2 configuration for the same thing, but for now it is its own config. #### `RTX_ASDF_COMPAT=1` Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. +This disables rtx functionality that would otherwise make these files incompatible with asdf. #### `RTX_JOBS=1` @@ -764,7 +756,7 @@ Sets `RTX_JOBS=1` because only 1 plugin script can be executed at a time. Use a custom file for the shorthand aliases. This is useful if you want to share plugins within an organization. -The file should be in toml format: +The file should be in this toml format: ```toml elixir = "https://github.com/my-org/rtx-elixir.git" @@ -780,17 +772,9 @@ Currently this disables the following: - `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) -#### `RTX_HIDE_OUTDATED_BUILD=1` +#### `RTX_HIDE_UPDATE_WARNING=1` -If a release is 12 months old, it will show a warning message every time it launches: - -``` -rtx has not been updated in over a year. Please update to the latest version. -``` - -You likely do not want to be using rtx if it is that old. I'm doing this instead of -autoupdating. If, for some reason, you want to stay on some old version, you can hide -this message with `RTX_HIDE_OUTDATED_BUILD=1`. +This hides the warning that is displayed when a new version of rtx is available. #### `RTX_EXPERIMENTAL=1` @@ -1161,9 +1145,9 @@ In `rtx` you can use fuzzy-matching everywhere. asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: ```sh-session -$ asdf plugin add nodejs -$ asdf install nodejs latest:18 -$ asdf local nodejs latest:18 +asdf plugin add nodejs +asdf install nodejs latest:18 +asdf local nodejs latest:18 ``` In `rtx` this can all be done in a single step to set the local runtime version. If the plugin @@ -1201,7 +1185,7 @@ preferable. One example is when calling rtx binaries from an IDE. To support this, there is experimental support for using rtx in a "shim" mode. To use: -``` +```sh-session $ rtx settings set experimental true $ rtx settings set shims_dir ~/.rtx/shims $ rtx i nodejs@18.0.0 @@ -1237,8 +1221,8 @@ situations where rtx will override direnv's PATH. `use rtx` ensures that direnv To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: -```sh-session -$ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh +``` +rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh ``` Now in your `.envrc` file add the following: @@ -1333,10 +1317,10 @@ Options: Show "rtx: @" message when changing directories Examples: - $ eval "$(rtx activate bash)" - $ eval "$(rtx activate zsh)" - $ rtx activate fish | source - $ execx($(rtx activate xonsh)) + eval "$(rtx activate bash)" + eval "$(rtx activate zsh)" + rtx activate fish | source + execx($(rtx activate xonsh)) ``` ### `rtx alias get` diff --git a/src/build_time.rs b/src/build_time.rs index 737dcd34a..06dfc3213 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, FixedOffset, Months, Utc}; use console::style; use lazy_static::lazy_static; -use crate::env::RTX_HIDE_OUTDATED_BUILD; +use crate::env::RTX_HIDE_UPDATE_WARNING; lazy_static! { pub static ref BUILD_TIME: DateTime = @@ -12,7 +12,7 @@ lazy_static! { #[ctor::ctor] fn init() { - if !*RTX_HIDE_OUTDATED_BUILD + if !*RTX_HIDE_UPDATE_WARNING && BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() { eprintln!("{}", render_outdated_message()); diff --git a/src/cli/activate.rs b/src/cli/activate.rs index e0c7c7108..7b46ba5c4 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -55,9 +55,9 @@ impl Command for Activate { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ eval "$(rtx activate bash)" - $ eval "$(rtx activate zsh)" - $ rtx activate fish | source - $ execx($(rtx activate xonsh)) + eval "$(rtx activate bash)" + eval "$(rtx activate zsh)" + rtx activate fish | source + execx($(rtx activate xonsh)) "#, style("Examples:").bold().underlined()} }); diff --git a/src/config/mod.rs b/src/config/mod.rs index ff5929eda..208e1006e 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -255,7 +255,7 @@ impl Config { } pub fn check_for_new_version(&self) { - if !console::user_attended_stderr() { + if !console::user_attended_stderr() || *env::RTX_HIDE_UPDATE_WARNING { return; // not a tty so don't bother } if let Some(latest) = cli::version::check_for_new_version(duration::WEEKLY) { diff --git a/src/env.rs b/src/env.rs index fd772b9c5..71f3531ca 100644 --- a/src/env.rs +++ b/src/env.rs @@ -85,7 +85,7 @@ lazy_static! { pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); pub static ref RTX_EXPERIMENTAL: bool = var_is_true("RTX_EXPERIMENTAL"); - pub static ref RTX_HIDE_OUTDATED_BUILD: bool = var_is_true("RTX_HIDE_OUTDATED_BUILD"); + pub static ref RTX_HIDE_UPDATE_WARNING: bool = var_is_true("RTX_HIDE_UPDATE_WARNING"); pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); pub static ref RTX_SHORTHANDS_FILE: Option = var_path("RTX_SHORTHANDS_FILE"); pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); From 15a4a7a46d9099cc660514960ec6ebfbe624e439 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 17 Mar 2023 23:06:53 -0500 Subject: [PATCH 0535/1891] docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d938c9cb8..b7273d369 100644 --- a/README.md +++ b/README.md @@ -509,7 +509,7 @@ They support aliases, which means you can have an `.nvmrc` file with `lts/hydrog in rtx and nvm. Here are some of the supported legacy version files: | Plugin | "Legacy" (Idiomatic) Files | -| --------- | -------------------------------------------------- | +|-----------|----------------------------------------------------| | crystal | `.crystal-version` | | elixir | `.exenv-version` | | golang | `.go-version`, `go.mod` | @@ -518,7 +518,7 @@ in rtx and nvm. Here are some of the supported legacy version files: | python | `.python-version` | | ruby | `.ruby-version`, `Gemfile` | | terraform | `.terraform-version`, `.packer-version`, `main.tf` | -| yarn | `.yvmrc` | +| yarn | `.yarnrc` | In rtx these are enabled by default. You can disable them with `rtx settings set legacy_version_file false`. There is a performance cost to having these when they're parsed as it's performed by the plugin in From 5307345df918e649b3d80b6460a653ce03fe6dd6 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sat, 18 Mar 2023 19:17:28 +0100 Subject: [PATCH 0536/1891] feat: dockerize dev setup #169 (#258) --- .devcontainer/Dockerfile | 26 ++++++++++++++++++++++++ .devcontainer/devcontainer.json | 36 +++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 16 +++++++++++++++ e2e/run_all_tests | 5 +---- justfile | 12 +++++++---- src/cli/direnv/envrc.rs | 5 +++++ 6 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..ea0066c8f --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,26 @@ +FROM mcr.microsoft.com/devcontainers/rust:0-1-bullseye + +WORKDIR /workspaces/cached + +# Use another target directory to avoid conflicts with the host target directory +RUN mkdir /workspaces/target +ENV CARGO_TARGET_DIR=/workspaces/target + +# Install rust tools +RUN rustup component add clippy llvm-tools rustfmt +RUN cargo install cargo-insta cargo-llvm-cov + +# Install dependencies +RUN export DEBIAN_FRONTEND=noninteractive \ + && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \ + && apt-get update \ + && apt-get -y install --no-install-recommends \ + # shells, direnv, shellcheck + bash fish zsh direnv nodejs shellcheck \ + && apt-get clean \ + # shfmt + && curl -sS https://webi.sh/shfmt | sh \ + # just + && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/bin + +ENTRYPOINT [ "/bin/bash" ] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..83b2b7c61 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/rust +{ + "name": "Rust", + + // "image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye", + + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "build": { + "dockerfile": "Dockerfile" + }, + + // Use 'mounts' to make the cargo cache persistent in a Docker Volume. + // "mounts": [ + // { + // "source": "devcontainer-cargo-cache-${devcontainerId}", + // "target": "/usr/local/cargo", + // "type": "volume" + // } + // ] + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "rustc --version", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + "remoteUser": "root" +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d2e3c194..72e9c34d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,19 @@ +# Contributing + +## Development Container + +The directory `.devcontainer` contains a Dockerfile that can be used to build a container for local development. This is useful if you want to use either VSCode's remote container feature or a standalone container to develop rtx. To use it, you'll need to have Docker Desktop installed and running. + +Build and run the container with the following commands: + +```shell +cd .devcontainer +docker build -t local/rtxdevcontainer . +docker run --rm -it -v "$(pwd)"/../:/workspaces/cached local/rtxdevcontainer +``` + +To use the container with VSCode, you'll need to install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. Once installed, you can open the project in a container by opening the Command Palette (F1) and selecting "Remote-Containers: Open Folder in Container...". Select the root of the rtx project and the container will be built and started. + ## Dependencies * [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that). As of this writing: 1.67.0 but GH actions will use the latest stable whenever it runs. diff --git a/e2e/run_all_tests b/e2e/run_all_tests index d3550df55..ee140da59 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -3,11 +3,8 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -FILES=$(find e2e -name 'test_*' -type f | sort) +FILES=$(find e2e -name 'test_*' -type f -not -path "*/.rtx/*" | sort) for f in $FILES; do - if [[ "$f" == "e2e/.rtx/"* ]]; then - continue - fi "$ROOT/e2e/run_test" "$f" echo done diff --git a/justfile b/justfile index 575efba2d..7036f4777 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,7 @@ set shell := ["bash", "-uc"] export RTX_DATA_DIR := "/tmp/rtx" -export PATH := env_var("PWD") + "/target/debug:" + env_var("PATH") +export PATH := env_var_or_default("CARGO_TARGET_DIR", "$PWD/target") + "/debug:" + env_var("PATH") export RTX_MISSING_RUNTIME_BEHAVIOR := "autoinstall" export RUST_TEST_THREADS := "1" @@ -43,10 +43,12 @@ test-coverage: export GITHUB_API_TOKEN="$RTX_GITHUB_BOT_TOKEN" fi + export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$PWD/target}" + export PATH="${CARGO_TARGET_DIR}/debug:$PATH" cargo test --features clap_mangen cargo build --all-features - PATH="$PWD/target/debug:$PATH" ./e2e/run_all_tests - RTX_SELF_UPDATE_VERSION=1.0.0 ./target/debug/rtx self-update <>() + .join("\n"); assert_display_snapshot!(envrc); } } From 7ee8f2f153f9edccb41c2224613857de7b3308e6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 18 Mar 2023 15:39:20 -0500 Subject: [PATCH 0537/1891] docs: shebang --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index b7273d369..046477948 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ v18.15.0 - [Xonsh](#xonsh) - [Something else?](#something-else) - [Uninstalling](#uninstalling) +- [Shebangs](#shebangs) - [Configuration](#configuration) - [`.tool-versions`](#tool-versions) - [Legacy version files](#legacy-version-files) @@ -474,6 +475,16 @@ Alternatively, manually remove the following directories to fully clean up: - on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) - on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) +## Shebangs + +You can specify a tool and its version in a shebang without needing to first setup `.tool-versions`/`.rtx.toml` config: + +```typescript +#!/usr/bin/env -S rtx x nodejs@18 -- node +// "env -S" allows multiple arguments in a shebang +console.log(`Running node: ${process.version}`); +``` + ## Configuration ### `.tool-versions` From 8235706be26c8feb2ab9a4ef164e488f412aba71 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Mar 2023 14:28:09 -0500 Subject: [PATCH 0538/1891] test: do not use custom HOME for e2e tests This stopped working entirely for me locally, not sure why --- e2e/cd/test_bash | 4 ++-- e2e/run_test | 4 +++- e2e/test_exec | 2 +- e2e/test_local | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 29a52ea34..e9f5e3fc7 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -18,10 +18,10 @@ assert() { } assert_path() { - local expected="${1//$HOME/\~}" + local expected="${1//$RTX_DATA_DIR/\~\/.rtx}" local actual="${PATH/%$orig_path/}" actual="${actual/%:/}" - actual="${actual//$HOME/\~}" + actual="${actual//$RTX_DATA_DIR/\~\/.rtx}" if [[ "$actual" != "$expected" ]]; then echo "Invalid PATH: $actual" echo "Expected PATH: $expected" diff --git a/e2e/run_test b/e2e/run_test index caba72217..473e313d4 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -4,15 +4,17 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)" export ROOT +export PATH="$ROOT/target/debug:$PATH" export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="$ROOT/e2e/.rtx" export RTX_CACHE_DIR="$ROOT/e2e/.rtx/cache" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml +export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" unset GOPATH TEST="$1" echo "Running $TEST" -export HOME="$ROOT/e2e" +rm -f "$RTX_CONFIG_FILE" cd "$(dirname "$TEST")" "./$(basename "$TEST")" diff --git a/e2e/test_exec b/e2e/test_exec index 61b562e2f..d52be0479 100755 --- a/e2e/test_exec +++ b/e2e/test_exec @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -euxo pipefail +set -euo pipefail assert() { local actual diff --git a/e2e/test_local b/e2e/test_local index c7f64952a..3ae5fb09c 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -47,7 +47,7 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then fi assert_raises "rtx uninstall shfmt@3.6.0" -assert_raises "rtx g shfmt --install-missing" +assert_raises "rtx local shfmt --install-missing" assert "rtx local shfmt@3.6.0" "dotenv = '.test-env' [env] From 6cb93f51e73155a5112c1d4a533c0ba24f0bfbd9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Mar 2023 14:29:15 -0500 Subject: [PATCH 0539/1891] bug: use RTX_CONFIG_FILE for settings This was incorrectly defaulting to ~/.config/rtx/config.toml no matter what --- src/config/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 208e1006e..87f3c4510 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -285,7 +285,9 @@ fn get_project_root(config_files: &ConfigMap) -> Option { } fn load_rtxrc() -> Result { - let settings_path = dirs::CONFIG.join("config.toml"); + let settings_path = env::RTX_CONFIG_FILE + .clone() + .unwrap_or(dirs::CONFIG.join("config.toml")); match settings_path.exists() { false => { trace!("settings does not exist {:?}", settings_path); From 9efb94a72730cf3e8932a8a44f274ad07c689e3a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Mar 2023 14:30:51 -0500 Subject: [PATCH 0540/1891] bug: fix `rtx latest @` Before this it would not resolve the alias. Now you can use `rtx latest nodejs@lts` and get the exact version that will use --- src/cli/latest.rs | 14 ++++++++++++-- src/config/mod.rs | 14 ++++++++++++++ src/toolset/tool_version.rs | 16 ++-------------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 3de5688e7..46cdeb53e 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -25,7 +25,7 @@ pub struct Latest { impl Command for Latest { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let prefix = match self.runtime.version { + let mut prefix = match self.runtime.version { RuntimeArgVersion::None => self.asdf_version, RuntimeArgVersion::Version(version) => Some(version), _ => Err(eyre!( @@ -42,6 +42,9 @@ impl Command for Latest { .for_stderr() ) })?; + if let Some(v) = prefix { + prefix = Some(config.resolve_alias(&plugin.name, &v)?); + } plugin.clear_remote_version_cache()?; if let Some(version) = plugin.latest_version(&config.settings, prefix)? { @@ -65,8 +68,9 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { use insta::assert_display_snapshot; + use pretty_assertions::assert_str_eq; - use crate::{assert_cli_err, assert_cli_snapshot}; + use crate::{assert_cli, assert_cli_err, assert_cli_snapshot}; #[test] fn test_latest() { @@ -89,4 +93,10 @@ mod tests { let stdout = assert_cli_err!("latest", "invalid_plugin"); assert_display_snapshot!(stdout); } + + #[test] + fn test_latest_alias() { + let stdout = assert_cli!("latest", "tiny@lts"); + assert_str_eq!(stdout, "3.1.0\n"); + } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 87f3c4510..77904a670 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -129,6 +129,20 @@ impl Config { env::var("__RTX_DIFF").is_ok() } + pub fn resolve_alias(&self, plugin_name: &PluginName, v: &str) -> Result { + if let Some(plugin_aliases) = self.aliases.get(plugin_name) { + if let Some(alias) = plugin_aliases.get(v) { + return Ok(alias.clone()); + } + } + if let Some(plugin) = self.plugins.get(plugin_name) { + if let Some(alias) = plugin.get_aliases(&self.settings)?.get(v) { + return Ok(alias.clone()); + } + } + Ok(v.to_string()) + } + fn load_all_aliases(&self) -> AliasMap { let mut aliases: AliasMap = self.aliases.clone(); let plugin_aliases: Vec<_> = self diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 37c8c7689..3ff1243c0 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -62,7 +62,7 @@ impl ToolVersion { plugin: Arc, v: &str, ) -> Result { - let v = resolve_alias(config, plugin.clone(), v)?; + let v = config.resolve_alias(&plugin.name, v)?; match v.split_once(':') { Some(("ref", r)) => { return self.resolve_ref(config, plugin, r); @@ -113,7 +113,7 @@ impl ToolVersion { let (wanted, minus) = v.split_once("!-").unwrap(); let wanted = match wanted { "latest" => plugin.latest_version(&config.settings, None)?.unwrap(), - _ => resolve_alias(config, plugin.clone(), wanted)?, + _ => config.resolve_alias(&plugin.name, wanted)?, }; let wanted = version_sub(&wanted, minus); match plugin.latest_version(&config.settings, Some(wanted))? { @@ -194,18 +194,6 @@ impl Display for ToolVersionType { } } -pub fn resolve_alias(config: &Config, plugin: Arc, v: &str) -> Result { - if let Some(plugin_aliases) = config.aliases.get(&plugin.name) { - if let Some(alias) = plugin_aliases.get(v) { - return Ok(alias.clone()); - } - } - if let Some(alias) = plugin.get_aliases(&config.settings)?.get(v) { - return Ok(alias.clone()); - } - Ok(v.to_string()) -} - /// subtracts sub from orig and removes suffix /// e.g. version_sub("18.2.3", "2") -> "16" /// e.g. version_sub("18.2.3", "0.1") -> "18.1" From cb2334c28d9521d22e73266b39632a555d2a2671 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 19 Mar 2023 14:31:52 -0500 Subject: [PATCH 0541/1891] chore: Release rtx-cli version 1.25.5 --- Cargo.lock | 54 +++++++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20255212b..fed6f4064 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,6 +68,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" + [[package]] name = "block-buffer" version = "0.10.4" @@ -79,9 +85,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" dependencies = [ "memchr", "serde", @@ -147,11 +153,11 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.10" +version = "4.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce38afc168d8665cfc75c7b1dd9672e50716a137f433f070991619744a67342a" +checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" dependencies = [ - "bitflags", + "bitflags 2.0.2", "clap_derive", "clap_lex", "is-terminal", @@ -372,7 +378,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.0", + "syn 2.0.2", ] [[package]] @@ -389,7 +395,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.0", + "syn 2.0.2", ] [[package]] @@ -684,7 +690,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -923,9 +929,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e86b86ae312accbf05ade23ce76b625e0e47a255712b7414037385a1c05380" +checksum = "0dd6da19f25979c7270e70fa95ab371ec3b701cd0eefc47667a09785b3c59155" dependencies = [ "hermit-abi 0.3.1", "libc", @@ -940,9 +946,9 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", @@ -1070,7 +1076,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "static_assertions", @@ -1157,9 +1163,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.4.1" +version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" [[package]] name = "output_vt100" @@ -1341,7 +1347,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1456,7 +1462,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.25.4" +version = "1.25.5" dependencies = [ "base64", "build-time", @@ -1518,11 +1524,11 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.9" +version = "0.36.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "2fe885c3a125aa45213b68cc1472a49880cb5923dc23f522ad2791b882228778" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -1626,7 +1632,7 @@ checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.0", + "syn 2.0.2", ] [[package]] @@ -1770,9 +1776,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cff13bb1732bccfe3b246f3fdb09edfd51c01d6f5299b7ccd9457c2e4e37774" +checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" dependencies = [ "proc-macro2", "quote", @@ -1856,7 +1862,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.0", + "syn 2.0.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f3f7a0ce4..07eff8aa4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.25.4" +version = "1.25.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 046477948..0ac1debfb 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.25.4 +rtx 1.25.5 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -322,7 +322,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.25.4/rtx-v1.25.4-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.25.5/rtx-v1.25.5-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index f6046830f..fce0a2585 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.25.4"; + version = "1.25.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 54a79181e..f5fb69386 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.25.4" +.TH rtx 1 "rtx 1.25.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -140,6 +140,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.25.4 +v1.25.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 84e91c13b..3e2793232 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.25.4 +Version: 1.25.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From f13a3d9bbcccb409c60b53c1017020f3ffff5422 Mon Sep 17 00:00:00 2001 From: tomotomo Date: Mon, 20 Mar 2023 23:04:40 +0900 Subject: [PATCH 0542/1891] Specify tool name to system version (#356) * Specify tool name to system version * docs --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- man/man1/rtx.1 | 9 ++++----- src/cli/mod.rs | 13 ++++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index f5fb69386..8dc720f5e 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -130,13 +130,12 @@ Print this message or the help of the given subcommand(s) Examples: rtx install nodejs@18.0.0 Install a specific node version rtx install nodejs@18.0 Install a version matching a prefix + rtx install nodejs Install the node version defined in + .tool\-versions or .rtx.toml rtx local nodejs@18 Use node\-18.x in current project rtx global nodejs@18 Use node\-18.x as default - - rtx install nodejs Install the .tool\-versions node version - rtx local nodejs Use latest node in current directory - rtx global system Use system node everywhere unless overridden - + rtx local nodejs@latest Use latest node in current directory + rtx global nodejs@system Use system node everywhere unless overridden rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 70a82d65d..a1a6c05d3 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -159,7 +159,7 @@ impl Cli { .long_about(LONG_ABOUT) .arg_required_else_help(true) .subcommand_required(true) - .after_help(AFTER_HELP.as_str()) + .after_long_help(AFTER_LONG_HELP.as_str()) .arg(args::install_missing::InstallMissing::arg()) .arg(args::jobs::Jobs::arg()) .arg(args::log_level::LogLevel::arg()) @@ -211,18 +211,17 @@ jq and shellcheck. It is inspired by asdf and uses asdf's plugin ecosystem under the hood: https://asdf-vm.com/"}; -static AFTER_HELP: Lazy = Lazy::new(|| { +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! { " {} rtx install nodejs@18.0.0 Install a specific node version rtx install nodejs@18.0 Install a version matching a prefix + rtx install nodejs Install the node version defined in + .tool-versions or .rtx.toml rtx local nodejs@18 Use node-18.x in current project rtx global nodejs@18 Use node-18.x as default - - rtx install nodejs Install the .tool-versions node version - rtx local nodejs Use latest node in current directory - rtx global system Use system node everywhere unless overridden - + rtx local nodejs@latest Use latest node in current directory + rtx global nodejs@system Use system node everywhere unless overridden rtx x nodejs@18 -- node app.js Run `node app.js` with PATH pointing to node-18.x ", style("Examples:").bold().underlined() } From dc15bf3a8006cd02aea5d5a685b3a71efaa8cebe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:41:48 -0500 Subject: [PATCH 0543/1891] chore: retry test-plugins tests on failure (#359) --- .github/workflows/test-plugins.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 54dc4b181..17f6bfe01 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -103,7 +103,13 @@ jobs: - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH - run: rtx -v - - run: ${{matrix.command}} + - name: ${{matrix.command}} + uses: nick-fields/retry@v2 + with: + timeout_minutes: 20 + max_attempts: 3 + retry_wait_seconds: 30 + command: ${{matrix.command}} test-install: # Tests installing the top 50 plugins not already tested in `test-install-and-run`. # installing is a better-than-nothing smoke test that the plugin is correctly implemented @@ -174,7 +180,8 @@ jobs: path: dist - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH - - uses: nick-fields/retry@v2 + - name: rtx install ${{matrix.plugins}}@latest + uses: nick-fields/retry@v2 with: timeout_minutes: 20 max_attempts: 3 From 34cdb3a5eb8efe4d28a943f8d9e5d9ec7362f042 Mon Sep 17 00:00:00 2001 From: KokaKiwi Date: Mon, 20 Mar 2023 17:22:51 +0100 Subject: [PATCH 0544/1891] fix: Use tool "as-is" when using "system" version (#361) Co-authored-by: KokaKiwi Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- src/runtimes.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runtimes.rs b/src/runtimes.rs index f044530f8..e61d6fad7 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -202,6 +202,9 @@ impl RuntimeVersion { } pub fn exec_env(&self) -> Result<&HashMap> { + if self.version.as_str() == "system" { + return Ok(&*EMPTY_HASH_MAP); + } if !self.script_man.script_exists(&ExecEnv) || *env::__RTX_SCRIPT { // if the script does not exist or we're running from within a script already // the second is to prevent infinite loops From 5bb0124df3e53eb8c792323505d3ee8ce1d138e1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 09:28:27 -0500 Subject: [PATCH 0545/1891] bug: fix local/global install prompts (#364) Fixes #363 The bug was that it did not "resolve" the versions so it thought everything was always not-installed --- src/cli/local.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli/local.rs b/src/cli/local.rs index cb0e73237..2c07192e5 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -143,6 +143,7 @@ pub fn local( fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result<()> { let mut ts = cf.to_toolset().clone(); + ts.resolve(config); if !ts.list_missing_versions().is_empty() { let mpr = MultiProgressReport::new(config.settings.verbose); ts.install_missing(config, mpr)?; From 0798ca3f3966942358ca1f4cd136e7a1009a2fd1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 09:31:46 -0500 Subject: [PATCH 0546/1891] chore: Release rtx-cli version 1.25.6 --- Cargo.lock | 65 ++++++++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 4 +-- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 7 ++++- 7 files changed, 50 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fed6f4064..5260b8173 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,7 +378,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.2", + "syn 2.0.4", ] [[package]] @@ -395,7 +395,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.4", ] [[package]] @@ -820,16 +820,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows", ] [[package]] @@ -929,9 +929,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd6da19f25979c7270e70fa95ab371ec3b701cd0eefc47667a09785b3c59155" +checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ "hermit-abi 0.3.1", "libc", @@ -1039,9 +1039,9 @@ dependencies = [ [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" @@ -1363,9 +1363,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c" dependencies = [ "aho-corasick", "memchr", @@ -1374,15 +1374,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "reqwest" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +checksum = "0ba30cc2c0cd02af1222ed216ba659cdb2f879dfe3181852fe7c50b1d0005949" dependencies = [ "base64", "bytes", @@ -1462,7 +1462,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.25.5" +version = "1.25.6" dependencies = [ "base64", "build-time", @@ -1524,9 +1524,9 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustix" -version = "0.36.10" +version = "0.36.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe885c3a125aa45213b68cc1472a49880cb5923dc23f522ad2791b882228778" +checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" dependencies = [ "bitflags 1.3.2", "errno", @@ -1620,19 +1620,19 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.157" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" [[package]] name = "serde_derive" -version = "1.0.157" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.4", ] [[package]] @@ -1776,9 +1776,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.2" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" +checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae" dependencies = [ "proc-macro2", "quote", @@ -1862,7 +1862,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.2", + "syn 2.0.4", ] [[package]] @@ -2123,9 +2123,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d502c968c6a838ead8e69b2ee18ec708802f99db92a0d156705ec9ef801993b" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" @@ -2357,6 +2357,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.42.0" diff --git a/Cargo.toml b/Cargo.toml index 07eff8aa4..668fb1c47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.25.5" +version = "1.25.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0ac1debfb..a951a2fe7 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.25.5 +rtx 1.25.6 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -322,7 +322,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.25.5/rtx-v1.25.5-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.25.6/rtx-v1.25.6-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index fce0a2585..58fc3c5db 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.25.5"; + version = "1.25.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 8dc720f5e..8492cdcf2 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.25.5" +.TH rtx 1 "rtx 1.25.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.25.5 +v1.25.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 3e2793232..2cb84e543 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.25.5 +Version: 1.25.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 6dd20ab13..46a812357 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 623] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 628] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -194,6 +194,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 623] = [ ("furyctl", "https://github.com/sighupio/asdf-furyctl.git"), ("fx", "https://gitlab.com/wt0f/asdf-fx.git"), ("fzf", "https://github.com/kompiro/asdf-fzf.git"), + ("gallery-dl", "https://github.com/iul1an/asdf-gallery-dl"), ("gam", "https://github.com/offbyone/asdf-gam.git"), ("gator", "https://github.com/MxNxPx/asdf-gator.git"), ("gauche", "https://github.com/sakuro/asdf-gauche.git"), @@ -336,6 +337,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 623] = [ ("kubectl", "https://github.com/asdf-community/asdf-kubectl.git"), ("kubectl-bindrole", "https://github.com/looztra/asdf-kubectl-bindrole.git"), ("kubectl-buildkit", "https://github.com/ezcater/asdf-kubectl-buildkit.git"), + ("kubectl-convert", "https://github.com/iul1an/asdf-kubectl-convert.git"), ("kubectl-kots", "https://github.com/ganta/asdf-kubectl-kots.git"), ("kubectx", "https://gitlab.com/wt0f/asdf-kubectx.git"), ("kubefedctl", "https://github.com/kvokka/asdf-kubefedctl.git"), @@ -422,6 +424,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 623] = [ ("openfaas-faas-cli", "https://github.com/zekker6/asdf-faas-cli.git"), ("openresty", "https://github.com/smashedtoatoms/asdf-openresty.git"), ("opensearch", "https://github.com/randikabanura/asdf-opensearch.git"), + ("opensearch-cli", "https://github.com/iul1an/asdf-opensearch-cli.git"), ("openshift-install", "https://github.com/hhemied/asdf-openshift-install.git"), ("operator-sdk", "https://github.com/Medium/asdf-operator-sdk.git"), ("opsgenie-lamp", "https://github.com/ORCID/asdf-opsgenie-lamp"), @@ -566,6 +569,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 623] = [ ("tfnotify", "https://github.com/jnavarrof/asdf-tfnotify.git"), ("tfsec", "https://github.com/woneill/asdf-tfsec.git"), ("tfstate-lookup", "https://github.com/carnei-ro/asdf-tfstate-lookup.git"), + ("tfswitch", "https://github.com/iul1an/asdf-tfswitch.git"), ("tfupdate", "https://github.com/yuokada/asdf-tfupdate.git"), ("thrift", "https://github.com/alisaifee/asdf-thrift.git"), ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), @@ -618,6 +622,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 623] = [ ("yay", "https://github.com/aaaaninja/asdf-yay.git"), ("yj", "https://github.com/ryodocx/asdf-yj.git"), ("yor", "https://github.com/ordinaryexperts/asdf-yor"), + ("youtube-dl", "https://github.com/iul1an/asdf-youtube-dl"), ("yq", "https://github.com/sudermanjr/asdf-yq.git"), ("ytt", "https://github.com/vmware-tanzu/asdf-carvel.git"), ("zbctl", "https://github.com/camunda-community-hub/asdf-zbctl.git"), From a0464b91788fb1adaa2cbc8303386c755df69101 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 10:56:29 -0500 Subject: [PATCH 0547/1891] added git commit to `rtx -v` (#365) also added build info to `rtx doctor` --- .github/workflows/rtx.yml | 2 +- Cargo.lock | 104 ++++++++++++++++-- Cargo.toml | 5 +- build.rs | 3 + justfile | 7 +- src/build_time.rs | 7 +- src/cli/doctor.rs | 12 ++ src/cli/version.rs | 5 +- ..._time__tests__render_outdated_message.snap | 1 + 9 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 build.rs diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index eaa6d93c4..72a6abde1 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -28,7 +28,7 @@ jobs: - uses: taiki-e/install-action@just - uses: taiki-e/install-action@nextest - name: Run cargo nextest - run: cargo nextest run --features clap_mangen + run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" - run: just lint diff --git a/Cargo.lock b/Cargo.lock index 5260b8173..2c0efb133 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,16 +94,14 @@ dependencies = [ ] [[package]] -name = "build-time" -version = "0.1.2" +name = "built" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b516fccffbcd4c007256d0d620522ea9fcc6f008c9ebb7173eeb349dfcf99786" +checksum = "96f9cdd34d6eb553f9ea20e5bf84abb7b13c729f113fc1d8e49dc00ad9fa8738" dependencies = [ + "cargo-lock", "chrono", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.109", + "git2", ] [[package]] @@ -124,11 +122,26 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "cargo-lock" +version = "8.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996" +dependencies = [ + "semver", + "serde", + "toml 0.5.11", + "url", +] + [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -671,6 +684,19 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +[[package]] +name = "git2" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" +dependencies = [ + "bitflags 1.3.2", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "globset" version = "0.4.10" @@ -971,6 +997,15 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.61" @@ -992,6 +1027,30 @@ version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +[[package]] +name = "libgit2-sys" +version = "0.14.2+1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "link-cplusplus" version = "1.0.8" @@ -1250,6 +1309,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "portable-atomic" version = "0.3.19" @@ -1465,7 +1530,7 @@ name = "rtx-cli" version = "1.25.6" dependencies = [ "base64", - "build-time", + "built", "chrono", "clap", "clap_complete", @@ -1510,7 +1575,7 @@ dependencies = [ "term_size", "test-log", "thiserror", - "toml", + "toml 0.7.3", "toml_edit", "url", "versions", @@ -1617,12 +1682,18 @@ name = "semver" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] [[package]] name = "serde" version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_derive" @@ -1971,6 +2042,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.7.3" @@ -2183,6 +2263,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 668fb1c47..57a72a257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ keywords = ["rtx"] categories = ["command-line-utilities"] include = ["src/**/*.rs", "/LICENSE", "/README.md", "/Cargo.lock"] rust-version = "1.64.0" +build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -26,7 +27,6 @@ path = "src/main.rs" [dependencies] base64 = "0.21.0" -build-time = "0.1.2" chrono = "0.4.23" clap = { version = "4.1.8", features = ["env", "derive", "string"] } clap_complete = "4.1.4" @@ -79,6 +79,9 @@ versions = "4.1.0" [target.'cfg(unix)'.dependencies] exec = "0.3.1" +[build-dependencies] +built = {version = "0.6.0", features = ["chrono", "git2"]} + [dev-dependencies] env_logger = "0.10.0" insta = "1.26.0" diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..d8f91cb91 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + built::write_built_file().expect("Failed to acquire build-time information"); +} diff --git a/justfile b/justfile index 7036f4777..80dc150df 100644 --- a/justfile +++ b/justfile @@ -22,11 +22,11 @@ test *args: (test-unit args) test-e2e lint # update all test snapshot files test-update-snapshots: find . -name '*.snap' -delete - cargo insta test --accept --features clap_mangen + cargo insta test --accept --all-features # run the rust "unit" tests test-unit *args: - cargo test --features clap_mangen {{ args }} + cargo test --all-features {{ args }} # runs the E2E tests in ./e2e test-e2e: build @@ -45,7 +45,7 @@ test-coverage: export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$PWD/target}" export PATH="${CARGO_TARGET_DIR}/debug:$PATH" - cargo test --features clap_mangen + cargo test --all-features cargo build --all-features ./e2e/run_all_tests RTX_SELF_UPDATE_VERSION=1.0.0 rtx self-update < = - DateTime::parse_from_rfc3339(build_time_utc!()).unwrap(); + DateTime::parse_from_rfc2822(built_info::BUILT_TIME_UTC).unwrap(); } #[ctor::ctor] diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 4ac083125..f2a87763a 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -6,6 +6,7 @@ use once_cell::sync::Lazy; use std::fmt::Write; use std::process::exit; +use crate::build_time::built_info; use crate::cli::command::Command; use crate::cli::version::VERSION; use crate::config::Config; @@ -26,6 +27,7 @@ impl Command for Doctor { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; rtxprintln!(out, "{}", rtx_version()); + rtxprintln!(out, "{}", build_info()); rtxprintln!(out, "{}", shell()); rtxprintln!(out, "{}", rtx_env_vars()); rtxprintln!( @@ -136,6 +138,16 @@ fn rtx_version() -> String { s } +fn build_info() -> String { + let mut s = style("build:\n").bold().to_string(); + s.push_str(&format!(" Target: {}\n", built_info::TARGET)); + s.push_str(&format!(" Features: {}\n", built_info::FEATURES_STR)); + s.push_str(&format!(" Built: {}\n", built_info::BUILT_TIME_UTC)); + s.push_str(&format!(" Rust Version: {}\n", built_info::RUSTC_VERSION)); + s.push_str(&format!(" Profile: {}\n", built_info::PROFILE)); + s +} + fn shell() -> String { let mut s = style("shell:\n").bold().to_string(); match ShellType::load().map(|s| s.to_string()) { diff --git a/src/cli/version.rs b/src/cli/version.rs index c4edf7a67..f88264575 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -7,7 +7,7 @@ use console::style; use once_cell::sync::Lazy; use versions::Versioning; -use crate::build_time::BUILD_TIME; +use crate::build_time::{built_info, BUILD_TIME}; use crate::cli::command::Command; use crate::config::Config; use crate::file::modified_duration; @@ -30,7 +30,7 @@ pub static ARCH: Lazy = Lazy::new(|| { pub static VERSION: Lazy = Lazy::new(|| { format!( - "{} {}-{} (built {})", + "{} {}-{} ({} {})", if cfg!(debug_assertions) { format!("{}-DEBUG", env!("CARGO_PKG_VERSION")) } else { @@ -38,6 +38,7 @@ pub static VERSION: Lazy = Lazy::new(|| { }, *OS, *ARCH, + built_info::GIT_COMMIT_HASH_SHORT.unwrap_or("unknown"), BUILD_TIME.format("%Y-%m-%d"), ) }); diff --git a/src/snapshots/rtx__build_time__tests__render_outdated_message.snap b/src/snapshots/rtx__build_time__tests__render_outdated_message.snap index 1dc5cb761..d03ed834f 100644 --- a/src/snapshots/rtx__build_time__tests__render_outdated_message.snap +++ b/src/snapshots/rtx__build_time__tests__render_outdated_message.snap @@ -3,4 +3,5 @@ source: src/build_time.rs expression: "console::strip_ansi_codes(&msg)" --- rtx rtx has not been updated in over a year. Please update to the latest version. +rtx update with: `rtx self-update` rtx To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1. From 47dfd41518f8d0a9759e3eea8b07f09c485b933b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 19:20:42 -0500 Subject: [PATCH 0548/1891] use env_path instead of env.PATH (#366) I think this style is cleaner and does not imply that it can be used for LD_LIBRARY_PATH or similar env vars This is a breaking change for .rtx.toml PATH functionality, but it is marked as experimental so we can change it with a minor release --- README.md | 8 +++----- e2e/.e2e.rtx.toml | 2 +- e2e/cd/test_fish | 2 ++ e2e/test_local | 8 ++++---- schema/rtx.json | 8 ++++++++ src/config/config_file/rtx_toml.rs | 14 ++++---------- ..._config_file__rtx_toml__tests__path_dirs-3.snap | 2 +- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index a951a2fe7..119c46aca 100644 --- a/README.md +++ b/README.md @@ -640,20 +640,18 @@ These can be simple key/value entries like this: NODE_ENV = 'production' ``` -`PATH` is treated specially, it needs to be defined as an array with `$PATH` at the end: +`PATH` is treated specially, it needs to be defined as an array in `env_path`: ```toml -[env] -PATH = [ +env_path = [ # adds an absolute path "~/.local/share/bin", # adds a path relative to the .rtx.toml, not PWD "./node_modules/.bin", - "$PATH" ] ``` -_Note: other PATH-like variables like `LD_LIBRARY_PATH` cannot be set this way._ +_Note: `env_path` is a top-level key, it does not go inside of `[env]`._ Environment variable values can be templates, see [Templates](#templates) for details. diff --git a/e2e/.e2e.rtx.toml b/e2e/.e2e.rtx.toml index c201acdf4..2c50026bd 100644 --- a/e2e/.e2e.rtx.toml +++ b/e2e/.e2e.rtx.toml @@ -1,7 +1,7 @@ dotenv = '.test-env' +env_path = ["/root", "./cwd"] [env] FOO = "bar" -PATH = ["/root", "./cwd", "$PATH"] [tools] tiny = "latest" diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index 74283f260..42cb29341 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -1,5 +1,7 @@ #!/usr/bin/env fish # shellcheck disable=SC1072,SC1065,SC1064,SC1073,SC2103 + +set -gx PATH $ROOT/target/debug:$PATH set -l orig_node (node -v) #set -l fish_trace 1 diff --git a/e2e/test_local b/e2e/test_local index 3ae5fb09c..8f5c50334 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -21,9 +21,9 @@ export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall assert_raises "rtx uninstall shfmt@3.6.0" assert "rtx local" "dotenv = '.test-env' +env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" -PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" @@ -31,9 +31,9 @@ tiny = \"latest\" " assert "rtx local shfmt@3.5.0" "dotenv = '.test-env' +env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" -PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" @@ -50,9 +50,9 @@ assert_raises "rtx uninstall shfmt@3.6.0" assert_raises "rtx local shfmt --install-missing" assert "rtx local shfmt@3.6.0" "dotenv = '.test-env' +env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" -PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" @@ -66,9 +66,9 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then fi assert "rtx local --rm shfmt" "dotenv = '.test-env' +env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" -PATH = [\"/root\", \"./cwd\", \"\$PATH\"] [tools] tiny = \"latest\" diff --git a/schema/rtx.json b/schema/rtx.json index c8fbb9360..50d05918f 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -10,6 +10,14 @@ "description": "path to .env file", "type": "string" }, + "env_path": { + "description": "PATH entries to add", + "type": "array", + "items": { + "description": "a path to add to PATH", + "type": "string" + } + }, "env": { "description": "environment variables", "type": "object", diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 9d4533016..db5cde465 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -83,6 +83,7 @@ impl RtxToml { for (k, v) in doc.iter() { match k { "dotenv" => self.parse_dotenv(k, v)?, + "env_path" => self.path_dirs = self.parse_path_env(k, v)?, "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, @@ -116,8 +117,8 @@ impl RtxToml { fn parse_env(&mut self, k: &str, v: &Item) -> Result<()> { let mut v = v.clone(); if let Some(table) = v.as_table_like_mut() { - if let Some(path) = table.remove("PATH") { - self.path_dirs = self.parse_path_env(&format!("{}.PATH", k), &path)?; + if table.contains_key("PATH") { + return Err(eyre!("use 'env_path' instead of 'env.PATH'")); } } for (k, v) in self.parse_hashmap(k, &v)? { @@ -130,17 +131,10 @@ impl RtxToml { fn parse_path_env(&self, k: &str, v: &Item) -> Result> { match v.as_array() { Some(array) => { - if let Some(Some(last)) = array.get(array.len() - 1).map(|v| v.as_str()) { - if last != "$PATH" { - // TODO: allow $PATH to be anywhere in the array - parse_error!(k, v, "array ending with '$PATH'")?; - } - } let mut path = Vec::new(); let config_root = self.path.parent().unwrap(); for v in array { match v.as_str() { - Some("$PATH") => {} Some(s) => { let s = self.parse_template(k, s)?; let s = match s.strip_prefix("./") { @@ -675,9 +669,9 @@ mod tests { let p = dirs::HOME.join("fixtures/.rtx.toml"); let mut cf = RtxToml::init(&p); cf.parse(&formatdoc! {r#" + env_path=["/foo", "./bar"] [env] foo="bar" - PATH=["/foo", "./bar", "$PATH"] "#}) .unwrap(); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap index a62bbc53c..c890b0931 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap @@ -2,7 +2,7 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- +env_path=["/foo", "./bar"] [env] foo="bar" -PATH=["/foo", "./bar", "$PATH"] From 3c40ca7df62969318b508254f41a668d79301804 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 19:35:37 -0500 Subject: [PATCH 0549/1891] bug: filter not installed runtimes from ls --parseable (#367) Fixes #357 --- justfile | 2 +- src/cli/ls.rs | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/justfile b/justfile index 80dc150df..26ea30afb 100644 --- a/justfile +++ b/justfile @@ -68,7 +68,7 @@ clean: # clippy, cargo fmt --check, and just --fmt lint: - cargo clippy + cargo clippy --all-features cargo fmt --all -- --check shellcheck scripts/*.sh shfmt -d scripts/*.sh diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 82bb1b8e4..bb158e305 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -123,14 +123,18 @@ impl Ls { runtimes: Vec<(RuntimeVersion, Option)>, out: &mut Output, ) -> Result<()> { - for (rtv, _) in runtimes { - if self.plugin.is_some() { - // only displaying 1 plugin so only show the version - rtxprintln!(out, "{}", rtv.version); - } else { - rtxprintln!(out, "{} {}", rtv.plugin.name, rtv.version); - } - } + runtimes + .into_iter() + .map(|(rtv, _)| rtv) + .filter(|rtv| rtv.is_installed()) + .for_each(|rtv| { + if self.plugin.is_some() { + // only displaying 1 plugin so only show the version + rtxprintln!(out, "{}", rtv.version); + } else { + rtxprintln!(out, "{} {}", rtv.plugin.name, rtv.version); + } + }); Ok(()) } From 0cfd4964192b40044f07a03828f50f42312b3f92 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 21:21:28 -0500 Subject: [PATCH 0550/1891] added "trust" support to make rtx a bit more secure (#368) config files that do "dangerous" things will now need to be marked as "trusted" --- README.md | 31 +++++++ completions/_rtx | 36 ++++++++ completions/rtx.bash | 50 ++++++++++- completions/rtx.fish | 77 +++++++++-------- e2e/cd/test_bash | 4 + justfile | 1 + man/man1/rtx.1 | 3 + src/cli/local.rs | 2 +- src/cli/mod.rs | 3 + .../rtx__cli__trust__tests__trust-2.snap | 6 ++ .../rtx__cli__trust__tests__trust-3.snap | 6 ++ .../rtx__cli__trust__tests__trust.snap | 6 ++ src/cli/trust.rs | 71 ++++++++++++++++ src/config/config_file/mod.rs | 33 +++++++- src/config/config_file/rtx_toml.rs | 84 ++++++++++++++----- src/config/config_file/tool_versions.rs | 8 +- src/errors.rs | 2 + src/test.rs | 1 + 18 files changed, 365 insertions(+), 59 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap create mode 100644 src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap create mode 100644 src/cli/snapshots/rtx__cli__trust__tests__trust.snap create mode 100644 src/cli/trust.rs diff --git a/README.md b/README.md index 119c46aca..6053fff77 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,7 @@ v18.15.0 - [`rtx settings set`](#rtx-settings-set) - [`rtx settings unset`](#rtx-settings-unset) - [`rtx shell`](#rtx-shell) + - [`rtx trust`](#rtx-trust) - [`rtx uninstall`](#rtx-uninstall) - [`rtx version`](#rtx-version) - [`rtx where`](#rtx-where) @@ -2122,6 +2123,36 @@ Examples: $ node -v v18.0.0 ``` +### `rtx trust` + +``` +Marks a config file as trusted + +This means rtx will parse the file with potentially dangerous +features enabled. + +This includes: +- environment variables +- templates +- `path:` plugin versions + +Usage: trust [OPTIONS] [CONFIG_FILE] + +Arguments: + [CONFIG_FILE] + The config file to trust + +Options: + --untrust + No longer trust this config + +Examples: + # trusts ~/some_dir/.rtx.toml + rtx trust ~/some_dir/.rtx.toml + + # trusts .rtx.toml in the current or parent directory + rtx trust +``` ### `rtx uninstall` ``` diff --git a/completions/_rtx b/completions/_rtx index be8001ed3..39bc9054a 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1179,6 +1179,26 @@ Sets --jobs=1]' \ '*::runtime -- Runtime version(s) to use:' \ && ret=0 ;; +(trust) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--untrust[No longer trust this config]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'::config_file -- The config file to trust:' \ +&& ret=0 +;; (uninstall) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel @@ -1529,6 +1549,10 @@ esac _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(trust) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (uninstall) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1600,6 +1624,7 @@ _rtx_commands() { 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ +'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ @@ -1950,6 +1975,7 @@ _rtx__help_commands() { 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ +'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ @@ -2287,6 +2313,16 @@ _rtx__shell_commands() { local commands; commands=() _describe -t commands 'rtx shell commands' commands "$@" } +(( $+functions[_rtx__help__trust_commands] )) || +_rtx__help__trust_commands() { + local commands; commands=() + _describe -t commands 'rtx help trust commands' commands "$@" +} +(( $+functions[_rtx__trust_commands] )) || +_rtx__trust_commands() { + local commands; commands=() + _describe -t commands 'rtx trust commands' commands "$@" +} (( $+functions[_rtx__help__plugins__uninstall_commands] )) || _rtx__help__plugins__uninstall_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 5093f5444..9d9052cd6 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -120,6 +120,9 @@ _rtx() { rtx,shell) cmd="rtx__shell" ;; + rtx,trust) + cmd="rtx__trust" + ;; rtx,uninstall) cmd="rtx__uninstall" ;; @@ -312,6 +315,9 @@ _rtx() { rtx__help,shell) cmd="rtx__help__shell" ;; + rtx__help,trust) + cmd="rtx__help__trust" + ;; rtx__help,uninstall) cmd="rtx__help__uninstall" ;; @@ -481,7 +487,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --install-missing --jobs --log-level --raw --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell uninstall version where which render-help help" + opts="-j -r -v -h -V --install-missing --jobs --log-level --raw --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1305,7 +1311,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell uninstall version where which render-help help" + opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1962,6 +1968,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__trust) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__uninstall) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2852,6 +2872,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__trust) + opts="-j -r -v -h --untrust --install-missing --jobs --log-level --raw --verbose --help [CONFIG_FILE]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__uninstall) opts="-j -r -v -h --install-missing --jobs --log-level --raw --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index e7d5e5160..14789b588 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -34,6 +34,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] reb complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' @@ -493,6 +494,15 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from trust" -l untrust -d 'No longer trust this config' +complete -c rtx -n "__fish_seen_subcommand_from trust" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from trust" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from trust" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from trust" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r @@ -535,39 +545,40 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Dir Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index e9f5e3fc7..5b6899fe9 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -4,6 +4,10 @@ set -euo pipefail orig_path="$PATH" +rtx trust +rtx trust ../.e2e.rtx.toml +rtx trust 16/.e2e.rtx.toml + # shellcheck disable=SC1090 eval "$(rtx activate bash --status)" && _rtx_hook diff --git a/justfile b/justfile index 26ea30afb..18066f497 100644 --- a/justfile +++ b/justfile @@ -48,6 +48,7 @@ test-coverage: cargo test --all-features cargo build --all-features ./e2e/run_all_tests + rtx trust RTX_SELF_UPDATE_VERSION=1.0.0 rtx self-update < PathBuf { } } -fn get_parent_path() -> Result { +pub fn get_parent_path() -> Result { let mut filenames = vec![RTX_DEFAULT_CONFIG_FILENAME.as_str()]; if !*env::RTX_USE_TOML { filenames.push(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index a1a6c05d3..1532cdd3d 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -43,6 +43,7 @@ mod reshim; mod self_update; mod settings; mod shell; +mod trust; mod uninstall; pub mod version; mod r#where; @@ -83,6 +84,7 @@ pub enum Commands { SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Shell(shell::Shell), + Trust(trust::Trust), Uninstall(uninstall::Uninstall), Version(version::Version), Where(r#where::Where), @@ -123,6 +125,7 @@ impl Commands { Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Shell(cmd) => cmd.run(config, out), + Self::Trust(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), Self::Version(cmd) => cmd.run(config, out), Self::Where(cmd) => cmd.run(config, out), diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap new file mode 100644 index 000000000..25005a3a1 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/trust.rs +expression: output +--- +untrusted ~/cwd/.test-tool-versions + diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap new file mode 100644 index 000000000..d9c3be1c9 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/trust.rs +expression: output +--- +trusted ~/cwd/.test-tool-versions + diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust.snap new file mode 100644 index 000000000..d9c3be1c9 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/trust.rs +expression: output +--- +trusted ~/cwd/.test-tool-versions + diff --git a/src/cli/trust.rs b/src/cli/trust.rs new file mode 100644 index 000000000..44a7376c8 --- /dev/null +++ b/src/cli/trust.rs @@ -0,0 +1,71 @@ +use std::path::PathBuf; + +use color_eyre::eyre::Result; +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::cli::local; +use crate::config::{config_file, Config}; +use crate::output::Output; + +/// Marks a config file as trusted +/// +/// This means rtx will parse the file with potentially dangerous +/// features enabled. +/// +/// This includes: +/// - environment variables +/// - templates +/// - `path:` plugin versions +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +pub struct Trust { + /// The config file to trust + pub config_file: Option, + + /// No longer trust this config + #[clap(long)] + pub untrust: bool, +} + +impl Command for Trust { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let path = match &self.config_file { + Some(filename) => PathBuf::from(filename), + None => local::get_parent_path()?, + }; + if self.untrust { + config_file::untrust(&path)?; + rtxprintln!(out, "untrusted {}", &path.canonicalize()?.display()); + } else { + config_file::trust(&path)?; + rtxprintln!(out, "trusted {}", &path.canonicalize()?.display()); + } + Ok(()) + } +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + # trusts ~/some_dir/.rtx.toml + rtx trust ~/some_dir/.rtx.toml + + # trusts .rtx.toml in the current or parent directory + rtx trust + "#, style("Examples:").bold().underlined()} +}); + +#[cfg(test)] +mod tests { + use crate::assert_cli_snapshot; + + #[test] + fn test_trust() { + assert_cli_snapshot!("trust"); + assert_cli_snapshot!("trust", "--untrust"); + assert_cli_snapshot!("trust", ".test-tool-versions"); + } +} diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index b502effe7..f431474be 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::fmt::{Debug, Display}; +use std::fs; use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; @@ -10,12 +11,13 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, Config}; -use crate::env; use crate::file::display_path; +use crate::hash::hash_to_str; use crate::output::Output; use crate::plugins::PluginName; use crate::toolset::{ToolVersionList, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::{dirs, env}; pub mod legacy_version; pub mod rtx_toml; @@ -144,6 +146,35 @@ pub fn parse(path: &Path) -> Result> { } } +pub fn is_trusted(path: &Path) -> bool { + trust_path(path.to_path_buf()).unwrap().exists() +} + +pub fn trust(path: &Path) -> Result<()> { + let hashed_path = trust_path(path.to_path_buf())?; + if !hashed_path.exists() { + fs::create_dir_all(hashed_path.parent().unwrap())?; + fs::write(hashed_path, "")?; + } + Ok(()) +} + +pub fn untrust(path: &Path) -> Result<()> { + let hashed_path = trust_path(path.to_path_buf())?; + if hashed_path.exists() { + fs::remove_file(hashed_path)?; + } + Ok(()) +} + +fn trust_path(mut path: PathBuf) -> Result { + if path.exists() { + path = path.canonicalize()?; + } + let trust_path = dirs::CACHE.join("trusted-configs").join(hash_to_str(&path)); + Ok(trust_path) +} + fn detect_config_file_type(path: &Path) -> Option { match path.file_name().unwrap().to_str().unwrap() { f if f.ends_with(".toml") => Some(ConfigFileType::RtxToml), diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index db5cde465..b171cefb8 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -12,12 +12,13 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; -use crate::config::{AliasMap, MissingRuntimeBehavior}; -use crate::dirs; +use crate::config::{config_file, AliasMap, MissingRuntimeBehavior}; +use crate::errors::Error::UntrustedConfig; use crate::file::create_dir_all; use crate::plugins::PluginName; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; +use crate::{dirs, env}; #[derive(Debug, Default)] pub struct RtxToml { @@ -30,6 +31,7 @@ pub struct RtxToml { alias: AliasMap, doc: Document, plugins: HashMap, + is_trusted: bool, } #[macro_export] @@ -44,7 +46,6 @@ macro_rules! parse_error { }}; } -#[allow(dead_code)] // TODO: remove impl RtxToml { pub fn init(path: &Path) -> Self { let mut context = BASE_CONTEXT.clone(); @@ -52,6 +53,7 @@ impl RtxToml { Self { path: path.to_path_buf(), context, + is_trusted: config_file::is_trusted(path), toolset: Toolset { source: Some(ToolSource::RtxToml(path.to_path_buf())), ..Default::default() @@ -101,6 +103,7 @@ impl RtxToml { } fn parse_dotenv(&mut self, k: &str, v: &Item) -> Result<()> { + self.trust_check()?; match v.as_str() { Some(filename) => { let path = self.path.parent().unwrap().join(filename); @@ -115,6 +118,7 @@ impl RtxToml { } fn parse_env(&mut self, k: &str, v: &Item) -> Result<()> { + self.trust_check()?; let mut v = v.clone(); if let Some(table) = v.as_table_like_mut() { if table.contains_key("PATH") { @@ -128,11 +132,12 @@ impl RtxToml { Ok(()) } - fn parse_path_env(&self, k: &str, v: &Item) -> Result> { + fn parse_path_env(&mut self, k: &str, v: &Item) -> Result> { + self.trust_check()?; match v.as_array() { Some(array) => { let mut path = Vec::new(); - let config_root = self.path.parent().unwrap(); + let config_root = self.path.parent().unwrap().to_path_buf(); for v in array { match v.as_str() { Some(s) => { @@ -155,7 +160,7 @@ impl RtxToml { } } - fn parse_alias(&self, k: &str, v: &Item) -> Result { + fn parse_alias(&mut self, k: &str, v: &Item) -> Result { match v.as_table_like() { Some(table) => { let mut aliases = AliasMap::new(); @@ -184,7 +189,7 @@ impl RtxToml { } } - fn parse_hashmap(&self, key: &str, v: &Item) -> Result> { + fn parse_hashmap(&mut self, key: &str, v: &Item) -> Result> { match v.as_table_like() { Some(table) => { let mut env = HashMap::new(); @@ -204,7 +209,7 @@ impl RtxToml { } } - fn parse_toolset(&self, key: &str, v: &Item) -> Result { + fn parse_toolset(&mut self, key: &str, v: &Item) -> Result { let mut toolset = Toolset::new(self.toolset.source.clone().unwrap()); match v.as_table_like() { @@ -221,7 +226,7 @@ impl RtxToml { } fn parse_tool_version_list( - &self, + &mut self, key: &str, v: &Item, plugin_name: &PluginName, @@ -255,11 +260,18 @@ impl RtxToml { }, } + for v in tool_version_list.versions.iter() { + if let ToolVersionType::Path(_) = v.r#type { + // "path:" can be dangerous to run automatically + self.trust_check()?; + } + } + Ok(tool_version_list) } fn parse_tool_version( - &self, + &mut self, key: &str, v: &Item, plugin_name: &PluginName, @@ -322,7 +334,7 @@ impl RtxToml { Ok(tv) } - fn parse_tool_version_value(&self, key: &str, v: &Value) -> Result { + fn parse_tool_version_value(&mut self, key: &str, v: &Value) -> Result { match v.as_str() { Some(s) => { let s = self.parse_template(key, s)?; @@ -340,7 +352,7 @@ impl RtxToml { } } - fn parse_settings(&self, key: &str, v: &Item) -> Result { + fn parse_settings(&mut self, key: &str, v: &Item) -> Result { let mut settings = SettingsBuilder::default(); match v.as_table_like() { @@ -418,7 +430,7 @@ impl RtxToml { } } - fn parse_duration_minutes(&self, k: &str, v: &Item) -> Result { + fn parse_duration_minutes(&mut self, k: &str, v: &Item) -> Result { match v.as_value() { Some(Value::String(s)) => Ok(humantime::parse_duration(s.value())?), Some(Value::Integer(i)) => Ok(Duration::from_secs(*i.value() as u64 * 60)), @@ -426,21 +438,21 @@ impl RtxToml { } } - fn parse_bool(&self, k: &str, v: &Item) -> Result { + fn parse_bool(&mut self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_bool()) { Some(Some(v)) => Ok(v), _ => parse_error!(k, v, "boolean")?, } } - fn parse_usize(&self, k: &str, v: &Item) -> Result { + fn parse_usize(&mut self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_integer()) { Some(Some(v)) => Ok(v as usize), _ => parse_error!(k, v, "usize")?, } } - fn parse_path(&self, k: &str, v: &Item) -> Result { + fn parse_path(&mut self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => { let v = self.parse_template(k, v)?; @@ -450,7 +462,7 @@ impl RtxToml { } } - fn parse_string(&self, k: &str, v: &Item) -> Result { + fn parse_string(&mut self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => { let v = self.parse_template(k, v)?; @@ -460,7 +472,11 @@ impl RtxToml { } } - fn parse_missing_runtime_behavior(&self, k: &str, v: &Item) -> Result { + fn parse_missing_runtime_behavior( + &mut self, + k: &str, + v: &Item, + ) -> Result { let v = self.parse_string("missing_runtime_behavior", v)?; match v.to_lowercase().as_str() { "warn" => Ok(MissingRuntimeBehavior::Warn), @@ -473,7 +489,7 @@ impl RtxToml { } } - fn parse_log_level(&self, k: &str, v: &Item) -> Result { + fn parse_log_level(&mut self, k: &str, v: &Item) -> Result { let level = self.parse_string(k, v)?.parse()?; Ok(level) } @@ -525,13 +541,41 @@ impl RtxToml { } } - fn parse_template(&self, k: &str, input: &str) -> Result { + fn parse_template(&mut self, k: &str, input: &str) -> Result { + if !input.contains("{{") && !input.contains("{%") && !input.contains("{#") { + return Ok(input.to_string()); + } + self.trust_check()?; let dir = self.path.parent().unwrap(); let output = get_tera(dir) .render_str(input, &self.context) .with_context(|| format!("failed to parse template: {k}='{}'", input))?; Ok(output) } + + fn trust_check(&mut self) -> Result<()> { + let default_cmd = String::new(); + let cmd = env::ARGS.get(1).unwrap_or(&default_cmd).as_str(); + if self.is_trusted || cmd == "trust" || cfg!(test) { + return Ok(()); + } + if console::user_attended_stderr() && cmd != "hook-env" { + let ans = dialoguer::Confirm::new() + .with_prompt(&format!( + "Config file {} is not trusted. Would you like to trust it?", + self.path.display() + )) + .default(false) + .interact() + .unwrap(); + if ans { + config_file::trust(self.path.as_path())?; + self.is_trusted = true; + return Ok(()); + } + } + Err(UntrustedConfig())? + } } impl Display for RtxToml { diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 98c84795b..11986c24c 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -4,7 +4,7 @@ use std::fs; use std::fs::read_to_string; use std::path::{Path, PathBuf}; -use crate::config::AliasMap; +use crate::config::{config_file, AliasMap}; use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; use indexmap::IndexMap; @@ -58,7 +58,11 @@ impl ToolVersions { pub fn parse_str(s: &str, path: PathBuf) -> Result { let mut cf = Self::init(&path); let dir = path.parent().unwrap(); - let s = get_tera(dir).render_str(s, &cf.context)?; + let s = if config_file::is_trusted(&path) { + get_tera(dir).render_str(s, &cf.context)? + } else { + s.to_string() + }; for line in s.lines() { if !line.trim_start().starts_with('#') { break; diff --git a/src/errors.rs b/src/errors.rs index eeeca7ed5..a37ff2495 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -15,6 +15,8 @@ pub enum Error { VersionNotFound(PluginName, String), #[error("{} exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(String, Option), + #[error("Config file is not trusted.\nTrust it with `rtx trust`.")] + UntrustedConfig(), } fn render_exit_status(exit_status: &Option) -> String { diff --git a/src/test.rs b/src/test.rs index a8601c6d9..265dc0609 100644 --- a/src/test.rs +++ b/src/test.rs @@ -27,6 +27,7 @@ fn init() { //env::set_var("TERM", "dumb"); env_logger::init(); reset_config(); + assert_cli!("trust"); assert_cli!("install", "tiny@1", "tiny@2", "tiny@3", "tiny", "dummy"); } From 412cce991848e1206f8f3902e3aedc0b68880be6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 21:37:22 -0500 Subject: [PATCH 0551/1891] chore: cache s3 assets longer --- scripts/publish-s3.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index e131fa5ee..c5f0c3fc1 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euxo pipefail -cache_hour="max-age=3600,s-maxage=3600,public,immutable" +#cache_hour="max-age=3600,s-maxage=3600,public,immutable" cache_day="max-age=86400,s-maxage=86400,public,immutable" cache_week="max-age=604800,s-maxage=604800,public,immutable" @@ -13,19 +13,19 @@ cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-latest-macos-amd64" aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive -aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "rtx-latest-*" -aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" -aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" -aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_hour" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "rtx-latest-*" +aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" +aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" aws s3 cp "./rtx/schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive -aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_hour" --no-progress --recursive --exclude "*" --include "repomd.xml*" +aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "repomd.xml*" aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive -aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_hour" --no-progress --no-progress --recursive +aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_day" --no-progress --no-progress --recursive #aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ # "/VERSION" \ From b1aa08a44314c2db178bb877b2d8170bfb839700 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 21 Mar 2023 22:43:09 -0500 Subject: [PATCH 0552/1891] docs: show usage for each command (#369) --- README.md | 120 ++++++++++++++++++++--------------------- src/cli/render_help.rs | 20 ++++--- 2 files changed, 74 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 6053fff77..238fbd516 100644 --- a/README.md +++ b/README.md @@ -132,45 +132,45 @@ v18.15.0 - [Cache Behavior](#cache-behavior) - [Plugin/Runtime Cache](#pluginruntime-cache) - [Commands](#commands) - - [`rtx activate`](#rtx-activate) - - [`rtx alias get`](#rtx-alias-get) - - [`rtx alias ls`](#rtx-alias-ls) - - [`rtx alias set`](#rtx-alias-set) - - [`rtx alias unset`](#rtx-alias-unset) + - [`rtx activate [OPTIONS] [SHELL_TYPE]`](#rtx-activate-options-shell_type) + - [`rtx alias get `](#rtx-alias-get-plugin-alias) + - [`rtx alias ls [OPTIONS]`](#rtx-alias-ls-options) + - [`rtx alias set `](#rtx-alias-set-plugin-alias-value) + - [`rtx alias unset `](#rtx-alias-unset-plugin-alias) - [`rtx bin-paths`](#rtx-bin-paths) - [`rtx cache clear`](#rtx-cache-clear) - - [`rtx complete`](#rtx-complete) - - [`rtx current`](#rtx-current) + - [`rtx complete --shell `](#rtx-complete---shell-shell) + - [`rtx current [PLUGIN]`](#rtx-current-plugin) - [`rtx deactivate`](#rtx-deactivate) - [`rtx direnv activate`](#rtx-direnv-activate) - [`rtx doctor`](#rtx-doctor) - - [`rtx env`](#rtx-env) - - [`rtx exec`](#rtx-exec) - - [`rtx global`](#rtx-global) - - [`rtx implode`](#rtx-implode) - - [`rtx install`](#rtx-install) - - [`rtx latest`](#rtx-latest) - - [`rtx local`](#rtx-local) - - [`rtx ls`](#rtx-ls) - - [`rtx ls-remote`](#rtx-ls-remote) - - [`rtx plugins install`](#rtx-plugins-install) - - [`rtx plugins ls`](#rtx-plugins-ls) - - [`rtx plugins ls-remote`](#rtx-plugins-ls-remote) - - [`rtx plugins uninstall`](#rtx-plugins-uninstall) - - [`rtx plugins update`](#rtx-plugins-update) - - [`rtx prune`](#rtx-prune) + - [`rtx env [OPTIONS] [RUNTIME]...`](#rtx-env-options-runtime) + - [`rtx exec [OPTIONS] [RUNTIME]... [-- ...]`](#rtx-exec-options-runtime----command) + - [`rtx global [OPTIONS] [RUNTIME]...`](#rtx-global-options-runtime) + - [`rtx implode [OPTIONS]`](#rtx-implode-options) + - [`rtx install [OPTIONS] [RUNTIME]...`](#rtx-install-options-runtime) + - [`rtx latest `](#rtx-latest-runtime) + - [`rtx local [OPTIONS] [RUNTIME]...`](#rtx-local-options-runtime) + - [`rtx ls [OPTIONS]`](#rtx-ls-options) + - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-plugin-prefix) + - [`rtx plugins install [OPTIONS] [NAME] [GIT_URL]`](#rtx-plugins-install-options-name-git_url) + - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) + - [`rtx plugins ls-remote [OPTIONS]`](#rtx-plugins-ls-remote-options) + - [`rtx plugins uninstall ...`](#rtx-plugins-uninstall-plugin) + - [`rtx plugins update [OPTIONS] [PLUGIN]...`](#rtx-plugins-update-options-plugin) + - [`rtx prune [OPTIONS] [PLUGINS]...`](#rtx-prune-options-plugins) - [`rtx reshim`](#rtx-reshim) - [`rtx self-update`](#rtx-self-update) - - [`rtx settings get`](#rtx-settings-get) + - [`rtx settings get `](#rtx-settings-get-key) - [`rtx settings ls`](#rtx-settings-ls) - - [`rtx settings set`](#rtx-settings-set) - - [`rtx settings unset`](#rtx-settings-unset) - - [`rtx shell`](#rtx-shell) - - [`rtx trust`](#rtx-trust) - - [`rtx uninstall`](#rtx-uninstall) + - [`rtx settings set `](#rtx-settings-set-key-value) + - [`rtx settings unset `](#rtx-settings-unset-key) + - [`rtx shell [OPTIONS] [RUNTIME]...`](#rtx-shell-options-runtime) + - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) + - [`rtx uninstall ...`](#rtx-uninstall-runtime) - [`rtx version`](#rtx-version) - - [`rtx where`](#rtx-where) - - [`rtx which`](#rtx-which) + - [`rtx where `](#rtx-where-runtime) + - [`rtx which [OPTIONS] `](#rtx-which-options-bin_name) @@ -1305,7 +1305,7 @@ behavior. ## Commands -### `rtx activate` +### `rtx activate [OPTIONS] [SHELL_TYPE]` ``` Initializes rtx in the current shell @@ -1332,7 +1332,7 @@ Examples: rtx activate fish | source execx($(rtx activate xonsh)) ``` -### `rtx alias get` +### `rtx alias get ` ``` Show an alias for a plugin @@ -1352,7 +1352,7 @@ Examples: $ rtx alias get nodejs lts/hydrogen 18.0.0 ``` -### `rtx alias ls` +### `rtx alias ls [OPTIONS]` ``` List aliases @@ -1374,7 +1374,7 @@ Examples: $ rtx aliases nodejs lts/hydrogen 18.0.0 ``` -### `rtx alias set` +### `rtx alias set ` ``` Add/update an alias for a plugin @@ -1396,7 +1396,7 @@ Arguments: Examples: $ rtx alias set nodejs lts/hydrogen 18.0.0 ``` -### `rtx alias unset` +### `rtx alias unset ` ``` Clears an alias for a plugin @@ -1429,7 +1429,7 @@ Deletes all cache files in rtx Usage: clear ``` -### `rtx complete` +### `rtx complete --shell ` ``` Generate shell completions @@ -1447,7 +1447,7 @@ Examples: $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx $ rtx complete -s fish > ~/.config/fish/completions/rtx.fish ``` -### `rtx current` +### `rtx current [PLUGIN]` ``` Shows current active and installed runtime versions @@ -1520,7 +1520,7 @@ Examples: $ rtx doctor [WARN] plugin nodejs is not installed ``` -### `rtx env` +### `rtx env [OPTIONS] [RUNTIME]...` ``` Exports env vars to activate rtx a single time @@ -1546,7 +1546,7 @@ Examples: $ rtx env -s fish | source $ execx($(rtx env -s xonsh)) ``` -### `rtx exec` +### `rtx exec [OPTIONS] [RUNTIME]... [-- ...]` ``` Execute a command with runtime(s) set @@ -1588,7 +1588,7 @@ Examples: # Run a command in a different directory: rtx x -C /path/to/project nodejs@18 -- node ./app.js ``` -### `rtx global` +### `rtx global [OPTIONS] [RUNTIME]...` ``` Sets/gets the global runtime version(s) @@ -1639,7 +1639,7 @@ Examples: $ rtx global nodejs 18.0.0 ``` -### `rtx implode` +### `rtx implode [OPTIONS]` ``` Removes rtx CLI and all related data @@ -1655,7 +1655,7 @@ Options: --dry-run List directories that would be removed without actually removing them ``` -### `rtx install` +### `rtx install [OPTIONS] [RUNTIME]...` ``` Install a runtime @@ -1689,7 +1689,7 @@ Examples: $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml ``` -### `rtx latest` +### `rtx latest ` ``` Gets the latest available version for a plugin @@ -1707,7 +1707,7 @@ Examples: $ rtx latest nodejs # get the latest stable version of nodejs 20.0.0 ``` -### `rtx local` +### `rtx local [OPTIONS] [RUNTIME]...` ``` Sets/gets tool version in local .tool-versions or .rtx.toml @@ -1763,7 +1763,7 @@ Examples: $ rtx local nodejs 18.0.0 ``` -### `rtx ls` +### `rtx ls [OPTIONS]` ``` List installed runtime versions @@ -1817,7 +1817,7 @@ Examples: "python": [...] } ``` -### `rtx ls-remote` +### `rtx ls-remote [PREFIX]` ``` List runtime versions available for install @@ -1848,7 +1848,7 @@ Examples: 18.0.0 18.1.0 ``` -### `rtx plugins install` +### `rtx plugins install [OPTIONS] [NAME] [GIT_URL]` ``` Install a plugin @@ -1895,7 +1895,7 @@ Examples: # install the nodejs plugin using a specific ref $ rtx plugins install nodejs http://github.com/jdxcode/rtx-nodejs.git#v1.0.0 ``` -### `rtx plugins ls` +### `rtx plugins ls [OPTIONS]` ``` List installed plugins @@ -1922,7 +1922,7 @@ Examples: nodejs https://github.com/asdf-vm/asdf-nodejs.git ruby https://github.com/asdf-vm/asdf-ruby.git ``` -### `rtx plugins ls-remote` +### `rtx plugins ls-remote [OPTIONS]` ``` List all available remote plugins @@ -1942,7 +1942,7 @@ Options: --only-names Only show the name of each plugin by default it will show a "*" next to installed plugins ``` -### `rtx plugins uninstall` +### `rtx plugins uninstall ...` ``` Removes a plugin @@ -1956,7 +1956,7 @@ Arguments: Examples: $ rtx uninstall nodejs ``` -### `rtx plugins update` +### `rtx plugins update [OPTIONS] [PLUGIN]...` ``` Updates a plugin to the latest version @@ -1978,7 +1978,7 @@ Examples: $ rtx plugins update nodejs # update only nodejs $ rtx plugins update nodejs@beta # specify a ref ``` -### `rtx prune` +### `rtx prune [OPTIONS] [PLUGINS]...` ``` Delete unused versions of tools @@ -2030,7 +2030,7 @@ Supports: standalone, brew, deb, rpm Usage: self-update ``` -### `rtx settings get` +### `rtx settings get ` ``` Show a current setting @@ -2066,7 +2066,7 @@ Examples: $ rtx settings legacy_version_file = false ``` -### `rtx settings set` +### `rtx settings set ` ``` Add/update a setting @@ -2085,7 +2085,7 @@ Arguments: Examples: $ rtx settings set legacy_version_file true ``` -### `rtx settings unset` +### `rtx settings unset ` ``` Clears a setting @@ -2101,7 +2101,7 @@ Arguments: Examples: $ rtx settings unset legacy_version_file ``` -### `rtx shell` +### `rtx shell [OPTIONS] [RUNTIME]...` ``` Sets a tool version for the current shell session @@ -2123,7 +2123,7 @@ Examples: $ node -v v18.0.0 ``` -### `rtx trust` +### `rtx trust [OPTIONS] [CONFIG_FILE]` ``` Marks a config file as trusted @@ -2153,7 +2153,7 @@ Examples: # trusts .rtx.toml in the current or parent directory rtx trust ``` -### `rtx uninstall` +### `rtx uninstall ...` ``` Removes runtime versions @@ -2175,7 +2175,7 @@ Show rtx version Usage: version ``` -### `rtx where` +### `rtx where ` ``` Display the installation path for a runtime @@ -2203,7 +2203,7 @@ Examples: $ rtx where nodejs /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 ``` -### `rtx which` +### `rtx which [OPTIONS] ` ``` Shows the path that a bin name points to diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 5d10ee570..f911706cb 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -1,3 +1,4 @@ +use clap::builder::StyledStr; use color_eyre::eyre::Result; use console::strip_ansi_codes; use indoc::formatdoc; @@ -67,20 +68,27 @@ fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option if c.is_hide_set() { return None; } - let name = match parent { - Some(p) => format!("{} {}", p, c.get_name()), - None => c.get_name().to_string(), + let strip_usage = |s: StyledStr| { + s.to_string() + .strip_prefix("Usage: ") + .unwrap_or_default() + .to_string() }; + let usage = match parent { + Some(p) => format!("{} {}", p, strip_usage(c.render_usage())), + None => strip_usage(c.render_usage()), + }; + let about = strip_ansi_codes(&c.render_long_help().to_string()) + .trim() + .to_string(); Some(formatdoc!( " - ### `rtx {name}` + ### `rtx {usage}` ``` {about} ``` ", - name = name, - about = strip_ansi_codes(&c.render_long_help().to_string()).trim(), )) } From 39407fe42b93b591ec381bd4dc1f2e1c06d863cb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 07:49:48 -0500 Subject: [PATCH 0553/1891] chore: fixing build.rs --- build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build.rs b/build.rs index d8f91cb91..aede1c1ca 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,4 @@ fn main() { built::write_built_file().expect("Failed to acquire build-time information"); + println!("cargo:rerun-if-changed=\"whateverYouLikeEvenAnAbsentDirectoryOrFile\""); } From 41160c29c0fb0b194f388c2b0ada6d70804e4743 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 08:00:56 -0500 Subject: [PATCH 0554/1891] chore: fixing build.rs --- Cargo.toml | 4 ++-- build.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 57a72a257..9cf120780 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] -include = ["src/**/*.rs", "/LICENSE", "/README.md", "/Cargo.lock"] +include = ["src/**/*.rs", "/build.rs", "/LICENSE", "/README.md", "/Cargo.lock"] rust-version = "1.64.0" build = "build.rs" @@ -80,7 +80,7 @@ versions = "4.1.0" exec = "0.3.1" [build-dependencies] -built = {version = "0.6.0", features = ["chrono", "git2"]} +built = { version = "0.6.0", features = ["chrono", "git2"] } [dev-dependencies] env_logger = "0.10.0" diff --git a/build.rs b/build.rs index aede1c1ca..d8f91cb91 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,3 @@ fn main() { built::write_built_file().expect("Failed to acquire build-time information"); - println!("cargo:rerun-if-changed=\"whateverYouLikeEvenAnAbsentDirectoryOrFile\""); } From 00ee0b02c689b60a160ffb1b35532980a6b311b3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 08:01:54 -0500 Subject: [PATCH 0555/1891] chore: Release rtx-cli version 1.26.0 --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 3 ++- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c0efb133..16e45ce1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -391,7 +391,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.4", + "syn 2.0.5", ] [[package]] @@ -408,7 +408,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.5", ] [[package]] @@ -1359,9 +1359,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" dependencies = [ "unicode-ident", ] @@ -1527,7 +1527,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.25.6" +version = "1.26.0" dependencies = [ "base64", "built", @@ -1703,7 +1703,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.5", ] [[package]] @@ -1847,9 +1847,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae" +checksum = "89c2d1c76a26822187a1fbb5964e3fff108bc208f02e820ab9dac1234f6b388a" dependencies = [ "proc-macro2", "quote", @@ -1933,7 +1933,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.5", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9cf120780..a9dd8382c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.25.6" +version = "1.26.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 238fbd516..a54f4918f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.25.6 +rtx 1.26.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -323,7 +323,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.25.6/rtx-v1.25.6-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.26.0/rtx-v1.26.0-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 58fc3c5db..b04d9649f 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.25.6"; + version = "1.26.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index ace451889..520bdb4df 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.25.6" +.TH rtx 1 "rtx 1.26.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.25.6 +v1.26.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 2cb84e543..0025849ad 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.25.6 +Version: 1.26.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 46a812357..3c8cec807 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 628] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 629] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -225,6 +225,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 628] = [ ("go-junit-report", "https://github.com/jwillker/asdf-go-junit-report.git"), ("go-sdk", "https://github.com/yacchi/asdf-go-sdk.git"), ("go-swagger", "https://github.com/jfreeland/asdf-go-swagger.git"), + ("goconvey", "https://github.com/therounds-contrib/asdf-goconvey.git"), ("gohugo", "https://github.com/nklmilojevic/asdf-hugo.git"), ("gojq", "https://github.com/jimmidyson/asdf-gojq.git"), ("golang", "https://github.com/kennyp/asdf-golang.git"), From 75449319624a68c127ac24a6eb27b012a0637514 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 09:58:56 -0500 Subject: [PATCH 0556/1891] Update README.md --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a54f4918f..8ef57ff6d 100644 --- a/README.md +++ b/README.md @@ -1207,14 +1207,10 @@ v18.0.0 ## direnv [direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze -the current environment variables before and after their respective "hook" commands are run, they can conflict with each other. -As a result, there were a [number of issues with direnv](https://github.com/jdxcode/rtx/issues/8). -However, we think we've mitigated these. If you find that rtx and direnv are not working well together, -please comment on that ticket ideally with a good description of your directory layout so we can -reproduce the problem. - -If there are remaining issues, they're likely to do with the ordering of PATH. This means it would -really only be a problem if you were trying to manage the same runtime with direnv and rtx. For example, +the current environment variables before and after their respective "hook" commands are run, they can sometimes conflict with each other. + +If you have an issue, it's likely to do with the ordering of PATH. This means it would +really only be a problem if you were trying to manage the same tool with direnv and rtx. For example, you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with python in it as well. @@ -1264,7 +1260,8 @@ If you continue to struggle, you can also try using the [experimental shims feat While making rtx compatible with direnv is, and will always be a major goal of this project, I also want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing -env vars and virtualenv for python using `.rtx.toml`. +env vars and [virtualenv](https://github.com/jdxcode/rtx-python#experimental-virtualenv-support) +for python using `.rtx.toml`. If you find you continue to need direnv, please open an issue and let me know what it is to see if it's something rtx could support. rtx will never be as capable as direnv with a DSL like `.envrc`, From 631237b53ff7d118806049aa7b054dc273eb4354 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:45:53 -0500 Subject: [PATCH 0557/1891] bug: do not worry about trust when generating completions --- src/config/config_file/rtx_toml.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index b171cefb8..442af1b29 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -556,7 +556,7 @@ impl RtxToml { fn trust_check(&mut self) -> Result<()> { let default_cmd = String::new(); let cmd = env::ARGS.get(1).unwrap_or(&default_cmd).as_str(); - if self.is_trusted || cmd == "trust" || cfg!(test) { + if self.is_trusted || cmd == "trust" || cmd == "complete" || cfg!(test) { return Ok(()); } if console::user_attended_stderr() && cmd != "hook-env" { From 59d1f3d206a47cb3fbc3fba24f205311f5a73338 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 11:20:20 -0500 Subject: [PATCH 0558/1891] default plugin update to use --all if no plugins specified (#372) --- README.md | 12 ++++-------- e2e/test_plugins_install | 2 +- src/cli/plugins/update.rs | 17 +++++++---------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8ef57ff6d..af039b746 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ v18.15.0 - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) - [`rtx plugins ls-remote [OPTIONS]`](#rtx-plugins-ls-remote-options) - [`rtx plugins uninstall ...`](#rtx-plugins-uninstall-plugin) - - [`rtx plugins update [OPTIONS] [PLUGIN]...`](#rtx-plugins-update-options-plugin) + - [`rtx plugins update [PLUGIN]...`](#rtx-plugins-update-plugin) - [`rtx prune [OPTIONS] [PLUGINS]...`](#rtx-prune-options-plugins) - [`rtx reshim`](#rtx-reshim) - [`rtx self-update`](#rtx-self-update) @@ -1953,25 +1953,21 @@ Arguments: Examples: $ rtx uninstall nodejs ``` -### `rtx plugins update [OPTIONS] [PLUGIN]...` +### `rtx plugins update [PLUGIN]...` ``` Updates a plugin to the latest version note: this updates the plugin itself, not the runtime versions -Usage: update [OPTIONS] [PLUGIN]... +Usage: update [PLUGIN]... Arguments: [PLUGIN]... Plugin(s) to update -Options: - -a, --all - Update all plugins - Examples: - $ rtx plugins update --all # update all plugins + $ rtx plugins update # update all plugins $ rtx plugins update nodejs # update only nodejs $ rtx plugins update nodejs@beta # specify a ref ``` diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install index 33bec4d89..c708e7eab 100755 --- a/e2e/test_plugins_install +++ b/e2e/test_plugins_install @@ -45,5 +45,5 @@ rtx plugin uninstall tiny assert_not_contains "rtx plugin ls" "tiny" rtx plugin uninstall tiny -rtx plugin update --all +rtx plugin update rtx plugin update shfmt diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 65d2f892e..8ed2e6fe0 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -18,14 +18,14 @@ pub struct Update { plugin: Option>, /// Update all plugins - #[clap(long, short = 'a', conflicts_with = "plugin")] + #[clap(long, short = 'a', conflicts_with = "plugin", hide = true)] all: bool, } impl Command for Update { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugins: Vec<_> = match (self.plugin, self.all) { - (Some(plugins), _) => plugins + let plugins: Vec<_> = match self.plugin { + Some(plugins) => plugins .into_iter() .map(|p| { let (p, ref_) = match p.split_once('@') { @@ -38,12 +38,11 @@ impl Command for Update { Ok((plugin, ref_)) }) .collect::>()?, - (_, true) => config + None => config .plugins .values() .map(|p| (p, None)) .collect::>(), - _ => Err(eyre!("no plugins specified"))?, }; for (plugin, ref_) in plugins { @@ -57,7 +56,7 @@ impl Command for Update { static AFTER_LONG_HELP: Lazy = Lazy::new(|| { formatdoc! {r#" {} - $ rtx plugins update --all # update all plugins + $ rtx plugins update # update all plugins $ rtx plugins update nodejs # update only nodejs $ rtx plugins update nodejs@beta # specify a ref "#, style("Examples:").bold().underlined()} @@ -65,9 +64,8 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::{assert_cli, assert_cli_err}; + use crate::assert_cli; #[test] fn test_plugin_update() { @@ -77,8 +75,7 @@ mod tests { "tiny", "https://github.com/jdxcode/rtx-tiny.git" ); - let err = assert_cli_err!("p", "update"); - assert_str_eq!(err.to_string(), "no plugins specified"); + // assert_cli!("p", "update"); tested in e2e assert_cli!("plugins", "update", "tiny"); } } From 4cf66b0a7d69465faf0b89a347d3afa6cf82a773 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:39:10 -0500 Subject: [PATCH 0559/1891] test: remove outdated message test This required having particular features installed which made it so you can't just run `cargo test`. The test is't that useful so I'm just removing it --- src/build_time.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/build_time.rs b/src/build_time.rs index 8253f26c6..a9a3634ab 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -42,16 +42,3 @@ fn render_outdated_message() -> String { output.join("\n") } - -#[cfg(test)] -mod tests { - use insta::assert_snapshot; - - use super::*; - - #[test] - fn test_render_outdated_message() { - let msg = render_outdated_message(); - assert_snapshot!(console::strip_ansi_codes(&msg)); - } -} From e18841d6e8553051e1cb1afe0acc531a1aef8de4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:40:08 -0500 Subject: [PATCH 0560/1891] chore: Release rtx-cli version 1.26.1 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16e45ce1c..8658ee9e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "dotenvy" -version = "0.15.6" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "duct" @@ -1527,7 +1527,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.26.0" +version = "1.26.1" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index a9dd8382c..8efe245e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.26.0" +version = "1.26.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index af039b746..93761084b 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.26.0 +rtx 1.26.1 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -323,7 +323,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.26.0/rtx-v1.26.0-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.26.1/rtx-v1.26.1-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index b04d9649f..f0bc3ffa8 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.26.0"; + version = "1.26.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 520bdb4df..a5ba005db 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.26.0" +.TH rtx 1 "rtx 1.26.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.26.0 +v1.26.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 0025849ad..efa94ec13 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.26.0 +Version: 1.26.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 00a6425279d9bd54625bcf4cfa6fefbba2eba55c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:42:59 -0500 Subject: [PATCH 0561/1891] chore: alpine apk (#311) --- .github/workflows/rtx.yml | 14 ++++++++++++++ .gitignore | 6 ++++++ Cargo.toml | 1 + README.md | 4 ++-- packaging/alpine/Dockerfile | 9 +++++++++ scripts/release-alpine.sh | 37 ++++++++++++++++++++++++++++++++++++ src/build_time.rs | 3 ++- src/cli/self_update/other.rs | 4 +++- 8 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 packaging/alpine/Dockerfile create mode 100755 scripts/release-alpine.sh diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 72a6abde1..53b1c6379 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -277,3 +277,17 @@ jobs: with: token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} formula: rtx + bump-alpine: + runs-on: ubuntu-22.04 + container: jdxcode/rtx:alpine + timeout-minutes: 30 + needs: [release] + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Bump APKBUILD + run: sudo -Eu packager ./scripts/release-alpine.sh + env: + ALPINE_PUB_KEY: ${{ secrets.ALPINE_PUB_KEY }} + ALPINE_PRIV_KEY: ${{ secrets.ALPINE_PRIV_KEY }} + GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} diff --git a/.gitignore b/.gitignore index 3840d36a8..deeb5cc06 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,9 @@ lcov.info /target/ # These are backup files generated by rustfmt **/*.rs.bk + +# alpine +.ash_history +.abuild +/aports +/aur diff --git a/Cargo.toml b/Cargo.toml index 8efe245e0..f0f07f740 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,6 +89,7 @@ pretty_assertions = "1.3.0" test-log = "0.2" [features] +alpine = [] brew = [] deb = [] rpm = [] diff --git a/README.md b/README.md index 93761084b..6590b9d7d 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ v18.15.0 - [apt](#apt) - [dnf](#dnf) - [yum](#yum) - - [~~apk~~ (coming soon)](#apk-coming-soon) + - [apk](#apk) - [aur](#aur) - [nix](#nix) - [Other Shells](#other-shells) @@ -364,7 +364,7 @@ yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo yum install -y rtx ``` -### ~~apk~~ (coming soon) +### apk For Alpine Linux: diff --git a/packaging/alpine/Dockerfile b/packaging/alpine/Dockerfile new file mode 100644 index 000000000..0cec8888b --- /dev/null +++ b/packaging/alpine/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:3 +RUN apk add --no-cache sudo build-base alpine-sdk bash direnv glab atools +RUN apk fix +RUN adduser -D packager +RUN addgroup packager abuild +RUN echo "packager ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers +RUN mkdir -p /__w && chown packager:packager /__w && chmod 777 /__w +#USER packager +#WORKDIR /home/packager diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh new file mode 100755 index 000000000..776bfc302 --- /dev/null +++ b/scripts/release-alpine.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euxo pipefail + +RTX_VERSION=$(./scripts/get-version.sh) + +export GITLAB_HOST=gitlab.alpinelinux.org + +sudo chown -R packager:packager /github/home +mkdir -p /github/home/.abuild +echo "$ALPINE_PUB_KEY" >/github/home/.abuild/-640e56d3.rsa.pub +echo "$ALPINE_PRIV_KEY" >/github/home/.abuild/-640e56d3.rsa +echo "PACKAGER_PRIVKEY=\"/github/home/.abuild/-640e56d3.rsa\"" >>/github/home/.abuild/abuild.conf + +git config --global user.name "Jeff Dickey" +git config --global user.email 6271-jdxcode@users.gitlab.alpinelinux.org + +git clone https://gitlab.alpinelinux.org/alpine/aports /home/packager/aports +cd /home/packager/aports +git config --local core.hooksPath .githooks +cd testing/rtx + +sed -i "s/pkgver=.*/pkgver=${RTX_VERSION#v}/" APKBUILD +sed -i "s/cargo test --frozen/cargo test --all-features --frozen/" APKBUILD + +abuild checksum +cat /github/home/.abuild/abuild.conf +abuild -r +apkbuild-lint APKBUILD + +git add APKBUILD +git checkout -B "rtx/${RTX_VERSION#v}" +git commit -m "testing/rtx: ${RTX_VERSION#v}" + +git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git" +git push -f jdxcode +glab mr create --fill --yes -H jdxcode/aports -R alpine/aports +#git show diff --git a/src/build_time.rs b/src/build_time.rs index a9a3634ab..2e52220f6 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -30,9 +30,10 @@ fn render_outdated_message() -> String { )); if cfg!(any( feature = "self_update", + feature = "alpine", feature = "brew", feature = "deb", - feature = "rpm" + feature = "rpm", )) { output.push(format!("{rtx} update with: `rtx self-update`")); } diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs index d55fa3e32..db0b090db 100644 --- a/src/cli/self_update/other.rs +++ b/src/cli/self_update/other.rs @@ -18,7 +18,9 @@ pub struct SelfUpdate {} impl Command for SelfUpdate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let cmd = if cfg!(feature = "brew") { + let cmd = if cfg!(feature = "alpine") { + "apk upgrade rtx" + } else if cfg!(feature = "brew") { "brew upgrade rtx" } else if cfg!(feature = "deb") { "sudo apt update && sudo apt install rtx" From 5e104642db64d6ddaacd6f3e9430f14c1b149212 Mon Sep 17 00:00:00 2001 From: Chad Crawford Date: Wed, 22 Mar 2023 15:30:49 -0400 Subject: [PATCH 0562/1891] Update Nix build to use proper `--all-features` flag when running tests. (#373) --- default.nix | 2 +- flake.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/default.nix b/default.nix index f0bc3ffa8..bce8f7575 100644 --- a/default.nix +++ b/default.nix @@ -26,7 +26,7 @@ rustPlatform.buildRustPackage { # Skip the test_plugin_list_urls as it uses the .git folder, which # is excluded by default from Nix. checkPhase = '' - RUST_BACKTRACE=full cargo test --features clap_mangen -- \ + RUST_BACKTRACE=full cargo test --all-features -- \ --skip cli::plugins::ls::tests::test_plugin_list_urls ''; diff --git a/flake.lock b/flake.lock index fa72d5745..b134471de 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "flake-utils": { "locked": { - "lastModified": 1676283394, - "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", + "lastModified": 1678901627, + "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", "owner": "numtide", "repo": "flake-utils", - "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073", + "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", "type": "github" }, "original": { @@ -17,11 +17,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1677413016, - "narHash": "sha256-dwvL0VK5iyxXPQzJOPzYmuVinh/R9hwRu7eYq6Bf6ag=", + "lastModified": 1679410443, + "narHash": "sha256-xDHO/jixWD+y5pmW5+2q4Z4O/I/nA4MAa30svnZKK+M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "84e33aea0f7a8375c92458c5b6cad75fa1dd561b", + "rev": "c9ece0059f42e0ab53ac870104ca4049df41b133", "type": "github" }, "original": { From 2fe26190df2a3ea566a90fbd639ca9e9e667c321 Mon Sep 17 00:00:00 2001 From: Jonathan Morley Date: Wed, 22 Mar 2023 15:31:23 -0400 Subject: [PATCH 0563/1891] Nix macos (#284) * Allow nix to build on macos * Update default.nix * Update default.nix * Update default.nix * Update default.nix --- default.nix | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/default.nix b/default.nix index bce8f7575..75e594757 100644 --- a/default.nix +++ b/default.nix @@ -1,4 +1,4 @@ -{ pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: +{ pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; version = "1.26.1"; @@ -9,7 +9,14 @@ rustPlatform.buildRustPackage { lockFile = ./Cargo.lock; }; - buildInputs = with pkgs; [ coreutils bash direnv gnused git gawk ]; + buildInputs = with pkgs; [ + coreutils + bash + direnv + gnused + git + gawk + ] ++ lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.Security; prePatch = '' substituteInPlace ./test/data/plugins/**/bin/* \ From ad0f755220e8b431558b9020ea3f06b44db840f8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 16:12:42 -0500 Subject: [PATCH 0564/1891] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72e9c34d0..335a65eca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Development Container -The directory `.devcontainer` contains a Dockerfile that can be used to build a container for local development. This is useful if you want to use either VSCode's remote container feature or a standalone container to develop rtx. To use it, you'll need to have Docker Desktop installed and running. +The directory `.devcontainer` contains a Dockerfile that can be used to build a container for local development. This is useful if you want to use a [GitHub Codespace](https://docs.github.com/codespaces), VSCode's remote container feature or a standalone container to develop rtx. To use it, you'll need to have Docker Desktop installed and running. Build and run the container with the following commands: From d3ed91d273adc14ce39506e698657cadfa67eefb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 20:57:30 -0500 Subject: [PATCH 0565/1891] hide local/global output by default (#375) --- e2e/run_test | 1 + e2e/test_local | 18 +++++++---- e2e/test_tool_versions_alt | 6 ++-- src/cli/local.rs | 31 ++++++++++++------- .../rtx__cli__global__tests__global-2.snap | 1 - .../rtx__cli__global__tests__global-4.snap | 1 - .../rtx__cli__global__tests__global.snap | 1 - ...cal__tests__local_multiple_versions-2.snap | 1 - ...tx__cli__local__tests__local_remove-2.snap | 1 - .../rtx__cli__local__tests__local_remove.snap | 1 - src/test.rs | 1 + 11 files changed, 38 insertions(+), 25 deletions(-) diff --git a/e2e/run_test b/e2e/run_test index 473e313d4..3386248f7 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -5,6 +5,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)" export ROOT export PATH="$ROOT/target/debug:$PATH" +export RTX_USE_TOML="0" export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="$ROOT/e2e/.rtx" export RTX_CACHE_DIR="$ROOT/e2e/.rtx/cache" diff --git a/e2e/test_local b/e2e/test_local index 8f5c50334..291c75d2e 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -30,7 +30,8 @@ tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} " -assert "rtx local shfmt@3.5.0" "dotenv = '.test-env' +rtx local shfmt@3.5.0 +assert "rtx local" "dotenv = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -49,7 +50,8 @@ fi assert_raises "rtx uninstall shfmt@3.6.0" assert_raises "rtx local shfmt --install-missing" -assert "rtx local shfmt@3.6.0" "dotenv = '.test-env' +rtx local shfmt@3.6.0 +assert "rtx local" "dotenv = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -65,7 +67,8 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then exit 1 fi -assert "rtx local --rm shfmt" "dotenv = '.test-env' +rtx local --rm shfmt +assert "rtx local" "dotenv = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -80,13 +83,15 @@ export RTX_DEFAULT_CONFIG_FILENAME=.MISSING assert_raises "rtx uninstall shfmt@3.6.0" -assert "rtx local --install-missing" "#python 3.11.1 3.10.9 # foo +rtx local --install-missing +assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 " -assert "rtx local shfmt@3.5.0" "#python 3.11.1 3.10.9 # foo +rtx local shfmt@3.5.0 +assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.5.0 # test comment #nodejs 18.13.0 @@ -97,7 +102,8 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi -assert "rtx local shfmt@3.6.0" "#python 3.11.1 3.10.9 # foo +rtx local shfmt@3.6.0 +assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment #nodejs 18.13.0 diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index 955537b9d..8412924eb 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -24,11 +24,13 @@ assert() { assert "rtx local" "shfmt 3.5.0" -assert "rtx local -p shfmt@3.6.0" "shfmt 3.6.0" +rtx local -p shfmt@3.6.0 +assert "rtx local -p" "shfmt 3.6.0" rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then exit 1 fi -assert "rtx local shfmt@3.5.0" "shfmt 3.5.0" +rtx local -p shfmt@3.5.0 +assert "rtx local shfmt" "3.5.0" diff --git a/src/cli/local.rs b/src/cli/local.rs index be460e6e3..589ef006f 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -134,10 +134,10 @@ pub fn local( if runtime.is_some() || remove.is_some() { cf.save()?; + } else { + rtxprint!(out, "{}", cf.dump()); } - rtxprint!(out, "{}", cf.dump()); - Ok(()) } @@ -202,30 +202,35 @@ mod tests { #[test] fn test_local_pin() { run_test(|| { - let stdout = assert_cli!("local", "--pin", "tiny@1"); + assert_cli!("local", "--pin", "tiny@1"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1"); - let stdout = assert_cli!("local", "--pin", "tiny", "2"); + assert_cli!("local", "--pin", "tiny", "2"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); }); } #[test] fn test_local_path() { run_test(|| { - let stdout = assert_cli!("local", "dummy@path:."); + assert_cli!("local", "dummy@path:."); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); }); } #[test] fn test_local_ref() { run_test(|| { - let stdout = assert_cli!("local", "dummy@ref:master"); + assert_cli!("local", "dummy@ref:master"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); }); } #[test] fn test_local_prefix() { run_test(|| { - let stdout = assert_cli!("local", "dummy@prefix:1"); + assert_cli!("local", "dummy@prefix:1"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); }); } @@ -263,7 +268,8 @@ mod tests { fn test_local_alias_ref() { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "ref:master"); - let stdout = assert_cli!("local", "dummy@m"); + assert_cli!("local", "dummy@m"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); @@ -275,7 +281,8 @@ mod tests { let local_dummy_path = dirs::INSTALLS.join("dummy").join("1.1.0"); let path_arg = String::from("path:") + &local_dummy_path.to_string_lossy(); assert_cli!("alias", "set", "dummy", "m", &path_arg); - let stdout = assert_cli!("local", "dummy@m"); + assert_cli!("local", "dummy@m"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy m"); let stdout = assert_cli!("current", "dummy"); assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); @@ -285,7 +292,8 @@ mod tests { fn test_local_alias_prefix() { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "prefix:1"); - let stdout = assert_cli!("local", "dummy@m"); + assert_cli!("local", "dummy@m"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); @@ -294,7 +302,8 @@ mod tests { fn test_local_alias_system() { run_test(|| { assert_cli!("alias", "set", "dummy", "m", "system"); - let stdout = assert_cli!("local", "dummy@m"); + assert_cli!("local", "dummy@m"); + let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy m"); assert_cli_snapshot!("current", "dummy"); }); diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap index 1f9e2e3f4..490bfa332 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap @@ -2,5 +2,4 @@ source: src/cli/global.rs expression: output --- -tiny 2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap index 3be683205..490bfa332 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap @@ -2,5 +2,4 @@ source: src/cli/global.rs expression: output --- -tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global.snap b/src/cli/snapshots/rtx__cli__global__tests__global.snap index 3be683205..490bfa332 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global.snap @@ -2,5 +2,4 @@ source: src/cli/global.rs expression: output --- -tiny 2.1.0 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap index 6465eb1b6..931ef3891 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap @@ -2,5 +2,4 @@ source: src/cli/local.rs expression: output --- -tiny 2 1 3 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap index c52103aa5..931ef3891 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap @@ -2,5 +2,4 @@ source: src/cli/local.rs expression: output --- -tiny 2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap index 501a2b02a..931ef3891 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap @@ -2,5 +2,4 @@ source: src/cli/local.rs expression: output --- -tiny 2.1.0 diff --git a/src/test.rs b/src/test.rs index 265dc0609..e66f59ed6 100644 --- a/src/test.rs +++ b/src/test.rs @@ -18,6 +18,7 @@ fn init() { ); set_current_dir(env::HOME.join("cwd")).unwrap(); env::set_var("NO_COLOR", "1"); + env::set_var("RTX_USE_TOML", "0"); env::set_var("RTX_DATA_DIR", env::HOME.join("data")); env::set_var("RTX_CONFIG_DIR", env::HOME.join("config")); env::set_var("RTX_CACHE_DIR", env::HOME.join("data/cache")); From d65714929fa93c54927583410335ac2a970d6eb4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 22 Mar 2023 21:13:09 -0500 Subject: [PATCH 0566/1891] new demo video (#376) --- README.md | 20 ++++++------- docs/demo.gif | Bin 489732 -> 1577362 bytes docs/demo.sh | 6 ++++ docs/demo.tape | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 11 deletions(-) create mode 100755 docs/demo.sh create mode 100644 docs/demo.tape diff --git a/README.md b/README.md index 6590b9d7d..3b0e5c3d1 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,6 @@

Polyglot runtime manager (asdf rust clone)

-## 30 Second Demo - -The following shows using rtx to install [nodejs](https://nodejs.org) and -[jq](https://stedolan.github.io/jq/) into a project using a `.tool-versions` file. -[hyperfine](https://github.com/sharkdp/hyperfine) is used to show the performance using -rtx vs asdf. (See [Performance](#performance)). -Note that calling `which node` gives us a real path to the binary, not a shim. - -[![demo](./docs/demo.gif)](./docs/demo.gif) - ## Features - **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. @@ -29,6 +19,14 @@ Note that calling `which node` gives us a real path to the binary, not a shim. version. rtx will figure out the right version without you needing to specify an exact version. - **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. +## 30 Second Demo + +The following shows using rtx to install different versions +of [nodejs](https://nodejs.org). +Note that calling `which node` gives us a real path to node, not a shim. + +[![demo](./docs/demo.gif)](./docs/demo.gif) + ## Quickstart Install rtx (other methods [here](#installation)): @@ -68,8 +66,8 @@ v18.15.0
Click to expand -- [30 Second Demo](#30-second-demo) - [Features](#features) +- [30 Second Demo](#30-second-demo) - [Quickstart](#quickstart) - [About](#about) - [What do I use this for?](#what-do-i-use-this-for) diff --git a/docs/demo.gif b/docs/demo.gif index 1ad0e1df87a952b4d4291c1457dbc90fcab57d2c..db4cc768506813585b8155bbb8c79c2c86a9e14b 100644 GIT binary patch literal 1577362 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�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

s?Kqo^|-kGs)C=gs0{v1 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

+nn8UT8g4 zoJm3U60dOmYA!}x#b|%rj4&(^{`2Qnu5@;cXcKtO=!q#tXBci4@eI#Jo$>G@Vp054 zv5MiBewty1Kau{7b2DsJ5tA^iFldofvpv9lMuNW%8LyI{jgHdA&-4$q8kD9`6uP6+$c*b~&x7MjDC?(qUuVU(Zbh z=ihvO|4oB)zvATZq=V6^dq@vi5x&Q70HWI1;WKD{hPQLK|2wog+h{O2DyV z1#&;M&dq>N5>X##yR)TL-|gOYMuDS+}ui6Rmbi-a?V z_`->2I1Z#Y!K$N|glaC#cFG>sD%R27{7BI-8hN)C6%cnMA`iA$f>>iBzL621h>+Ch z!bu%DA2JaOSlBf^nZaX-X(IR)7ID-ap%|O(@KwV+BZ*nZ+X5uFXbL&>1}99k$va9DX7PLcJ!RS?T}#2XqFD2ntlP|;}43n z>G!7ukyjG*VJ+&zOM!TMh+VFe#(M>cAmlt5@^$mV;vgTZ5{@@2nhhQKZ_lwEAVIC| zwkhda#kM-sA{U5)XDz0OUHT6O;emCziSM6{yCS&ne?y4*dAvZi>Re%F_{e+skv_qn zXhe?dW+4EvDs+d31Cy|}uJ}0jtpqWL6-FKQcm+X_LbomFXOH~T

*^A)2#ggu8v> z<^(e5qA8#uGV)s$L%XCnFT5vAgn_ z$O$2g=vBU@O{8L_sX+xIwX3<-wa)U+IZ>ru4wwJG(1NRn?ct+I9iWq~|5K$=1esKF zi++I0->B?RCgNZi*0lZiAASz+>X)P6{l~*;yS@_Sj_7l5!MfhwXTyC^paF(kJuIMu z?T|JmKY#n~??B`#6DyFs^NkHgWx9mq?f^287hhdDnYDlW{ovPEaX%LqK0kaX->L}V ze8|uHUd)W+`Bw1g$A9zo=+x;2Cvl&7$4nfyYCdgTFu~fCO*-5WJ!FiP;B=rq zUitbecJFQVxn!k@mye9!RqG6F%{Iq<2me5M^1@8GsTYCdymv)%7^N_eLi!acevFNM zMOnZR)P;@*<*Sq>#KcjNnKiIP0q*+v==)Kv%dyW4bc%Y&Bok8~_iPDZWCpq9Q2l=>-Ak~^_!})qEN(tJCtq;SzD(fiM)e`tv-Xrqx!74_XXQiQ&~9{O=-we&Qd>1k3yr4qpsyzdW#va~ zCqwFQ`RBZEjoBoq(xmJhy`@4Mfj!Sp+FPlW$BZX~C47gU(~F}g|Mv8TZF(I6D=a+a z10Ui>G|>V!lerKoc;V?u3%kbuf zSBa4O*Vo3=+BHkG9+u@!cd6bD?yWwAw&CcDB|~gv+X9LLLOg9h#)j}GL(IFp4;83J zmp(@0h30^Hp^d_HbaW?w%Uz;|)#m-X(*)aWm%8L7^i_dZAC+@ZetjzWzTWCIueEBr ztViL!ZqsXO68toOToLcoty2KVKs4{-f=rC8HV)jmTJSWR*uSfHPdd9*QBG@s0L}}V zu6~Ga9PA`;`%MY-d{>6UL(Q}Ha~&d~Eq#lXSMyG!jzks*iR4|wC??J;ju8*ZU&(Wd z7Ys6?0F%TOxgaI)b2YpBk@4J(PmjQ02=b+=77sEQ?5U8vLP~&lVB3|Kq(dt+`GinY zTMW9HON@Wwtz`fRf}iYw$YgQ6^1&x<%53aq(`TOhi+guFw8( zD607SoOZ{nbqFGp>+@9Djw*6(u4s6&pgYg^ZG+uYMhaA^Ps@w{K|#bnW!nb>S$Pj- zE`n#|b zTJG^Uz9W7r6M}*D>+0Zvu3HUNT?vH1?@_!0mjIwclXJ%n7{Um&u-LUtj99@BFd~bs zvH8VU*1$WrW=t)M;ZB6l!3DzUL!9jsb@Hw`QTV=Fq4SydmDEJ(H`ho>u@X z=q1X)H)qk)#|v5)g(b{G7`#P+9tk8&GM(27q*(>zw+~Cd3Wz6~C3UFC2PK>JXQoAa z^q7S_jTZ|f64szr^Z(qkvMUmdByK0iZqPC!s}wQ}>^t;FGU4a_1z7dJfoMcJyL9W|D=T2*+@veXqJ9$p=Y~=Tbdrk9nULt=0gnsn)=;{+6hE>f7tPa~5sYNJHCa}(YFGZL~QR0JnN@YA8 z-#DkRI`H}-QS&;e9%5#XSiYCs4i@4h7%e-5eFXjREl;Jw{#{AJ4|!Y(@6|R62!$CH zA@D=ohhi@)&bHvD}Hmg5F%RFE>? zB>!i&CCm^A>X;cPXf4%Si<|9vIt`Oza_ZWdY zP9<4xH^t2Y(QAG1$>NWP&Yn{Y`nZ^WE5wI;Z2!YiZ5s{Iz4z$1YIYU^0iLJ%deb=V zLb=j!g1bDzLQv}LdriZo86hP76Q_GaO_P8bakU07&#cfQ)GtZ5nr)r^Bz?zqlSh9t zgsO%kTAQsYAZ#}QcV8ZRqVPJ$wWHTon2Kje+uOn8npm*5`Gu~VyII6WU%sKLF}-Dy zB|1kU;=5;}OwS21(()amriZPU#sD>DQAy@KfuM`C;b-=jsaKO7h3kljIIVU2%iqAk z3XdqE;|l_R-VluT`3+mrY(zDc9-}nRC4|i@$vt07v;NsFa$WJTqlGkBpioMYk&>gF zMeH#d4okmQ&q9AuqQx4{AJ5nJ;q$Ar!+0|gH{z(?*m^!M{$1SldVO#Oo|CQzO(sT9 z%~dDpqS7%fJXe;Lv5(t0tXXol3d`ulyc4NGcV*n3aDVL z#rQu{#iMz(P_9Ps_r@P5-q9kO9++RgbgP#iUqv;4A$)<~za@SbbKEA2ofhZOAUnF8 zAhT*%E^S?i?nQMe%^yIo@0ZIA+1eLm{X939;(Ix$+67mrlZ<7SK$~A`>DK2ApO*Wh z?Ck6F>z{C%*q9->im`Dyz@1m~iw}Cc3KI1ppBEjcB))9yRN_6-wvFN`8;q} z8v5Dp_xR%Ni7H6syp_z3_OV+E{OmzY`NYXib)%%?ysvUi(Q{EW70wuu)M1Z9i%B>O zlZdxNbFAdPxk5(FVBX2QBl^rPj|*DwvG-zqP^k2d8xAg^Uv@M6{@UB6S;zax{bcLD zl{%*21-$Cv{9a>a#=R4SUhOylEhMajG7d7qwTG}t33K?9PXJ&sG>k_MzXNPc*NtYNy9qk`WDNj zfwrcTKW6|&^}A|_8~IjOF0Mx#kZ+!{4c{AW(8;%8Qof71d&*T+I<$Oq>OJ*Il`nDa zGp>;b6yR=$jA3>7-uE*ikYb479umh4xGgswJbow9zMOBoZU); z9yk8s{XF*Slkt3s-vX>$Lc=grd^CyjvI^on126r1Bnx#X*1lrAD!zg$5axvz?2rn; zQYD|7)cWvq>990n($Rjo6{X}xC8+^SL(>b1vqXB@Fx^fOa*Er~bM;PkFF5PDX*jA` zHkRK12`;kR)AR)qC+fl<*QawG^LqW9frT;8&9Ka(YR1wLY4d&A3 zva5rb#-{f1cQ?Vd!jgMs;H(0~4GjI89w;`3nX+Q>pHeZE)U)gX{Q1ph1qz0TXPja| zf|$>wlU~<)0E3p1HeHm!;ky2K%D(~O+nD;eB!)$!;<*IE@0izu`hD5feL3!Zp!izF zUhQx-LBu`G(1^g>tjxE|3H}&JL=}XBhnT39Nfgq#<)bov$H-Q&g^7J6Rz*of^bixM z?U5LSgB*Fzh{r)A<{tU6TV!AyNo8d?rk+{?mAg%~O#7V4A69;q9Z$U`zNd$;UGDth zZG3|SCY(5;oA7*}B@!D5wy|Vr;O<@{qy9;QIVly!_jD>oArF+2H86<*YLJ>PdKmtx zrEa41l-Y?UdIX7UJSMvD&|*=h_laG?FHr60B+mBI!l44Yp_iw7-??LcvbusoBS zgYYS>M?_<7UnWyhlORrNebTN}@OJg)HY0SNA-%~5g7LNMryU!l`{RKIP(E8mO3Qn& zErk+@&&}bM%3g4Kx_a$0rYu~3+EukBUzSOxjM0D2$=(@+*}kIk2W;|DrD>G78K**C*ZlUgnLPtY3+AEAP_Iz{V_Jr(&8k_W5;t z0>KAKi z`J+z%W>Z4BQfVtMK`*_)fhILBgmZSD_ZTz{8B`V=mAVQ-?`hleTPMcr?=tvAa0>9= zq>)rk{)J0jc~RB`7Vu0wu*;Pk;=z^@z*?s@pw}K*!}K|ESk@!>KLNGN*-M3(j@i zj)CHz;KT#EZ|4c=4qzxFg9wGVukdQGi5_R@;1jhDu_-Q0S}>F5Rg!f$O~A;*{cn?% zsbbyVE~>vL{UkoG#Wz{nW7G`WQ#L+0%i5xO#9&4e)qA zmY|d!XP?W!oX*ZZIe;5_`XXUWwyWA2OvMebryd*l+=q$m%0; zRzR`abntDU(%Cy%ygb@CnMeWVp7dFzFsccbN-A=>bpjN?0N3`4p#U7}T`0ZSUTFCQ z*1u;$Sd5`O|7OjTB)_~p~1N;3X<^f%wg zMG^UK4%59b6mg-V#a6mslwigi+4k7{`OMK>Fe;xn ziU|paf{r{8ku5PTng1;1C3lkvxv2(`)2Z`laC-kC<&`=_)_z0`Aem+Qh%rjudjSa| zidCcPq6{8N50iIOA?A!SX_DyYW-GIH=&@n?jp6_7|J_>xwEYrJ`;TXVnFPGR$Z#1h z5rZaP%>AIqOcR49WMdLfrR0TeVDgC%rZD+pOxjHb-EL=IJYU^~zjVA;S4I>5qZzvO z>x(juj<{Xs(G7A8gOqep&_&_~WIwU`#OT0>jku)j2#D>DugEZOMKrj5-i+w0WR_3A zIo^_B1Jnkj7e|RMF~HK|?~+s4mociRcoq&qIL0jraNgLYhaCyJVjj2V5{Wxl*WZeL zPhBlc%#s4>|I`IKlOV@>mrnHnjd3> z9(FvpN;r&xycS6FtD3V;1|AT38Tnh%`;g4bZ$@sLmCD7 z>q+xZqPf@4*uQ{~06Z7~_0+4jVlsuNmcD0ZdTN+9xR7_}IV~g~Y-H~efpCuO2HGUi z9foMzmEy5%KHK+-3|6rp2^_!#J%tKsxj_OvXu&%l>H#h8Q?$W#8X5^18Uj1vVY1jn z&DXRm40;RzqJ0Ic7bkt4O!Kn`U)ss-R6sSXJrAk>FZ1otE32el=WMptJ z>uXQ*$I^@U8&cXhHjd)K!n8Er>IN<=97v{FPlW%8x+tj|T5>K~+CH(ulkUIC=RHm< zP^W)p{TE#SZiS7C?xp#={yM5Ra{XUX@G{Lo8Zz{T=Fn@MDc-AcQ;=N;nR&am+CfL8 z&F1+nRAM0kxNwbgcNpUp4rLHZFgPT<914`a#uT|a9!gU<*1EAywcANJbVfr#Pj5hF z*P@1kPI``4kHgUqIw=x~(43T{I9Et(1P{9TVbnAsb{vs#8|b}EkAm`UAv%>k7`K?| zw{Qd!n@1-)DChF1JMDx=DK)#Bp2VidwkF3`z0(n(KfutIycce^LQeGx9Kz{t_U)U? zkXyZw+VLN;%aF}xR>UUcN}wUSo|e3{ldeV|5M!OM5xl_#bOFiEZqz2|-i>9*19cdY zrPJ2)S8xW>{)g@_ROGw0f0Lat{O<3MDt*J5}FnoLQ(7}MW&31YiSL)YWH*y}$bq)%KJx2L1_hnB;k(3l~S&7_$LIf6t zMl5yL9&mGu#Vp|otv$Z~Iw{_u} z1|iz{>9gy;udi?I`He;!Xj(kk-Cn4%gZYiL$Nbq^|Muqyn;8!g)ehOg&UU3p>V>ZD z==d^SNUkY#r1aQJ1N1S$NW_=tSB9oG)$)~-ABQfERa+gZJ5wU<^3S-yEU>UO{PF7v z6Z5-7;H}D%4cv-fy8Ls(q|DMGH&g)*}>kr*j^@%Z~LGo+i9A4B=h^S*w zoC>fDyHNEMVKUE46+;w-WDhy;&0w7kCtQ!8ffw~&LmrEr0Sp*^8jqSY7agz#f- z7Z05}IFYC~Iey$r__Wa6ka1h7sEht}_bOpzgfI22$?CniAq?n%#ln0F%y+@HJIAN# z;}1l=({PhXLxzO9WXHRqozE2sX3Gl4xS7%sE=Ka`iYf7>`D^JOF-5IIy3#X3{f1o% zzaB^rkmr`N-?0_u3-gG2{ilMxK>lVe8-!-1> zEjXkk(6;M;h+7g)J91){Ibb-1YV!BHX z4?DNyr77CfmHklq&^uLVR4=9z=4E;3o0GYL&!=PANVBP5Z>)}amkczwzWFWpw6b`1l6tHqy zcWD*9(0RiKcEY07QXoRU$4WrGB;lm_A0ZGcWV*=c?4o+tW|6G}lMz23t0K%254iio zkB}ey$_-W!>uDA7effQx?Mb$)$&Z33*dURDXRq2GKbj*NPCC>AzS-j0fM?RgP4;1= z4v7*WoO#;C@5h_dYH_<=Cy>_1#;Ft#%>J4EJM&&taFoEG)0F6A(hG3jsX>hSs(~PQ z7-R{*#CV;ykBsHurY{fyh%*zb1f3+{_MmHGa{&#)?(H$j<3nx#dJ@yanqE6aeB3AX zU&zi2c|zwyQ7j1vEwnoG%Te-m`}`2>dOcNcO2{IOdt9bSkOPK=1++V0C#0>;l?VTvfd7)n~0{k4pqdf}nj8&QNykFwFT}QFE(*ck3H`n)?eS z^v|ju^R0%An+a!x$A;5ylBtl0!P~AWB>h)v$1~~r$CTvNQIRVu;EwSg^W$zEksT%A zldZN^$91~L3>uG=eYS_Uzt4ym2STex2h=4`B%rw=?-ntTqit>=2aUs->DvQZw+eFX z9f$5TYuUrv-e*KMjp)3ZSJ62vHk8(`4aN;yn{K()ywu;y7rNVHQK{44h04B@;ZR`= z(i=bn326p^9*smO>Z0yp235<~}HjnMXk=;*J7oJcTu(&DC&gS%^c}Qp;feKn`wZiu#v_L$B3vK7ZM2dFG_q`8!T?YDT)YsLNdYYIe=k zg6^~DZ*ORamur4mIsU9I+dTcc@QKzcZ=)A76WXCK2G0Ee=d@3oABh=_MQvI>w%bjW zj@=cx$m$xwuC>p_1^HaanjRvQYYO>py=Xc>*fPHv)L-#&V86t)V&Un7@gFp2_~|Vq z@YazzY%0oVTmkm|#+e&lyX@D1aqQ_5s$7ayv(PuAPTut=+`>w}i0S37t!ABM&wF0r zZ~3pD>|e=3w68g!CgoWkbbMA78{8NXDVdr&15Lgv&5Fl~O`CU;I&T ze8{BlGU8XN)6nYaf#+}2r?1_SIUIbP)B3UOcXLh9;W-}AUiasr=Hjp$!G=d(jJ&=1 zTdrU;AxLTO)8&EYM8l$t;JCs8B&}J!p-56z%^UrjL03Jaxgq<`Xu=WntS%9LCE|PG z#IIA^-kWA2HZRT&?}5W>0=``Nc28vDCnEAG@*XKruYJa$rc*Qyzpkd~(UFt0hzFNl z4i)tra{xvV6Rt8Ss3pseMCCG@IxqGtfCII`KIy-o>{Yr6fPBtY7V0DlUK}sO{X6{o zR>oj3jC$_%hksG8DTw)ljk|16&$EV(+h5Q}<=9REP0dp0w>>YOUj_8UjIHngB1hg} z=ZBhfuu`{e4xL$}O4Lu}hF+$RzTC)M0m_{5NvDBUhz&Q zUrRyhZ{j!?mh?uv+8TNDXD|MX%k`$SH{TzYz)@5#2M%0(xwh!{ z?^BV*4T}>O|Cau|$$nhC)PMWd{siaZi>P<^uUkgm+6an_{5kOT=8MtS|8A~ypveul ziE9e8w_Y1=9Xk(q<-xVGOoh5kQ?1m-oeb+)rsOV@@lF$G^p4xqz7#^IiDeLIWyWM3 zCC2NU5lwxaF-2Th^IaI;9#?N=*eU|kcf?`1q#*aL5M+9eD&0Qa<7;KAMO92)1WC_Z>ywQS*v3=A3_5=zPf+Dfcj znT=c7PFR^X&6?L!xibZ-1auVBKVVFN2gaMPS?LN{3vgw{K`V1J-h*)~izutZ;y}qL zYr`DS`FX3O43O^+Jf?}|G)6TGe``KW)zWf-pNqHR8j`InxAybD8@{{`J1_NbN}_B= zGD6{(!~OQlMO(o0@|8;R@%JPf%O{%^CKc{UOGu6LSIF1-n5CCVt1AEH!&t1&?f&w? zxF};ZC?Zh=SuT7h3&QSLDiS*s>*l_60Sw3ZOn6yJft^S5`3&+QOJgikoYf(srGA%{ zZK9&pi0#Hnf;dMEh``VlGtWEPgDl3Z3`=-yzfg_UV48Ulm_C=7v}zs$bG6-%6-)!M z1ye1Sk_V6el$bfu8WsjLo?@9ql^Hp+oILqpL@T#Ekj66M5D9c}kGlCrNKVU2Pnn8q zEu)u~?>JQaZ7%;MtZZ#ju?JV(`*p@U{-T$LvNU>83gPRcIB#*vfBZ|iEaE)=Qe|q8 zf|ba5iC0QNj{f-L%9lpIhz{R_uK^D&cPdC*D!Rys<0?dXvrO{+&F_K5)+`u<=VkUghmdRfff9QLzO0I8)I1e|XywS?Upw4pG4T z(fN)jvo~P?pauq{4(k$#v$EK?)}93@1->z0lya&%c&AyXhN%Z7j<1{#X*hC4GOAQ9 zS$!O29%w1R+ZhG3+83j!ma*KLdX@J&SGocsTCEUhdrT|Hf&_BJDj9R?y>&~NQ)B69 z-xG%HHv&66nzZVCtW6#qr(_`q5o&FJd6l(N+)$-cx9wKTB$(?^R(ozHenFeL(g561z8&8jc2Ci@Lr z&v=LuY5}-qkV%rwWjxeW>tVy@gu&x7J*K58Y)Q9*EOjpc8{&D~cgZ53bxA7I%%f9a znPNH*x^Du6!9bc|hm$R=?~Jzw%T~~Z*~?{CY!AMQS*liB)~y+)64S~;h&5~0uOafN zDsi>yty+M$T-{{gwVPibFWz}XtEy=U8RRM6|4^HJN$$z3N0}Vpy#L7E!0vL!b+wtQ zFC)hOzdY%8q#k=Kej77TERvG?>mk!so_Bca?eu~Tc12kW8PQh7fzF!+G%lI$>S zff1m1Oz_Ss-xn7)K4TeGXXO?_H5>++N3Gu70vVqJ!ccBzuAQ&_N0|~pIbTu33OuUH zitYNabd_qNHLzeGf-}?bT(!dOfHxd0XT_Y>J$THT+s|Xa8bIeWzN@ zM=uxjdR=_!y$@=m$BNYAAJx#zW#W9yFG4K^pECGq4D3Ib6{&lLa5s-10f1;DnoH#{+wgTQ2mT|u0^9vo5m72GK z1PmF33+IQaS;j`#+<8Q~Jd>`!d{}b(vibh{Yw#LV6^IN6LBj}Y;RvmJ2$qTV{9=#s z8f!jXh5KoU5}^gHElLX_&UI=asLNPG!|v%SQETKJ3%RYFXgM z^qO~ZU4Ki_D7waVqn;q(=i6ELM}2)ub?%{vf68CmbHq*GUi% zRLjgd41+qECs;<*Tgeea<{DYNk`yV9nl{cg6fElX;A6UCs-2$eQb;Y2PF~WTB5ZYM z?T@|s)sZ#$vq0FKS3;UD;^9{Rzq-q|4N20${^+oeQekTn$|B`kewAC=b5)l&wnR*S ztnYa?+x!qa^fO$Y@|(v>d$98esS`cUWb1fu{{xptfM9Vex+GSn8H49H-6Q^({*&?h*h0QFQO|O#fdTz|GiPc5|Q0X71NCx#Zqvxs^1RT%y|CNu^v`s5Y0m zGnYc4&HYxPlBC)YQ@JD+rEha7LUJuh?YG~*`*Zs|9(#Y@=XIX1A|r{bCDH`d^*fWf z?MA^?cW=)uJ0AFP*FM7F?kcpmUC*EF@Nu840rK^`_CLAzv&BE|iJ4x7#Skh@o%!!? zY(T&2s;((t*gP~Fi!d;8m+?W^^z0oMRv6$&$~JDn^lY?UEPX}x>LSEr?QJ%D_ahEM zH0KY*0+CE1iB!CWknYDZ?7q)S)&uucfkqg3)S1;`Lg`KI?=jw2;^de@Gsy&k4HhI5 zD>d_<1y68B=vid4HRiNUE)6bZEgtkY9s97X@6VEqF%7XhW9Js?2=||=XkWP!Z}l+x zjs3Um{&r>IbBE_^tiS4qR-0|ge{@s*)Rgxl?_I~JyxCc61v#E7*7+V30qBE%3vxq2 zFa-DEUW?e2{oOMMASnlZXXoDmt&-xbc)+HLxNv^Mbc-2;Y45KPjZt-y;zJMHwh*ec z!QS#;Y|DZBV}Y>~Db{mz;c)p_oFha3g( znQnZ4eN|5jFBc7T``c@`OYqGEDwK*Db9)_23EmIWu%A~NIBe7H-km#a{mm5H?PfGP zuMeut6-I!_Erqivh-~oY`^bBnL|#r`R<9+ws_Z z{bu7{O8fOqJ?TehN;=a|$FCnV&+jk~xv3xY-|vjFSUnA2x`N^+A9_)ydgb(03eoA5 zhV&yx_;weov+kL^fbBd3y2#9(e$DJLq4plgAegTTBiS$TB>TpEpoL+I(uBQ$&ul5y z9|eKn#GZXMJ!x}*eTWoXDPXT=iaI1!{H1+;{gQBqYE-H|!~itX+EaSmtZpUYiS+oT7i95I^4I`-JXA%dNQYp7BV6L?ak!Cl2K+ z(#9PBi!w=dgLBq!0*-vv-VkfPY(>TMQ%8<^lc5ca1N?%ams)^b*YPuj?6+PGXCm(Z z98w&Q+jfyWG09KCoTS|Wn%1W&td|DukF}eJ;^k?gL z5ByOrR*|Qn8VJ`fABSiHt%89HNu_}n?G~;3an2^sMY#u3z*5>?oeVM|9j@kBY*7&C zkgZ@GTD*`NG?1r+r^{Lv2D=pLxYv0-DhxSXvX|UnY*`d~YHZdv1XsP(6?RJPW#+F#i2iMG*L%j92B(mlFdV<>H??x z9~|;Nd*boMwXbgWP~Kmuct7X$2x~C2;T0qfGQ)X{+vAYD-7K9taCpT<)Hf zs+PU;8mxMuN$8E53K0*kyfmTdSs9;<|1KEUH#qVu;=0PtxSt$8pH76lA9RGelq`?G zIf{o~v%@S>=F$Fv7H4aP1`Stn#oo?z)i~W(4H;JU;-W>Tm(SOGr)IG=d|W#o%@1j| z-#_Gbxl2*1TCT3GzA}2JMOWNtys@wn{OI;P`qbw`foV>!I09#Mc-oZi)%{!teeu7x zdGuwrn#XwJ+K|uZ%WbnXu-xCRl0BHf293%Dk_+b)hO2MSOQrH?Z!%T-InX1f01?0T za!Nk=t*q%PCJ$!^zn?3k&QiQGif?)#ciuUF+EAtipF&RfE2oATenV1B$~zKYmGOQC zVC$fkHyNDxIa|>bJxYEznR3X^a!>VlHieI%>)U-WSFy?*Kv4`xTLw9kKVm6!XS*xrWr^ecb6T9RJ)9Sa(+(?;xu8xDrT){?uof}~X5f?I z4sex;L&6{{Z9j+WMA`F-tgFDbV7VikLMbuJ)qX3P0FjRNI zNijjcR3NcC6pIDVoWWnU-aWMmg4 zD$e0(jN%&z(hGbkRwlq;DiwTBus`brNVZr}%T^LnL#%QKtP7=5q8EDUAiZS830D5; z8Xo3-j+0%K`;aEAm?>(eds!qR3*jiKy1ngW=ewQ1@+rj?80cyD!u@t)B|%k?z=dTA z36`;e=<8wu#qvGCvpJcrzbwG|(3w=V;W#cWy_*McuG$S!IW0l<{-Fj}v^rfCcgD$Pr2u{*nqzK2eB;o_8BwNB ztNi9;J&Ci&2w2(aoBcfmsBjxJh6zM{5GpVXY<+q$H3)&F0xTEw8r2(EsNbD*9G?bs z>;^JBZ5Phblmn*a>n_%mrrS)N&p(goRd^Z=^vq&{{aWpDn+^28Q7rM&ex}SiJKciX znjAVciyqPqa^`@WdQcwS*-Mi{q4GZWL z)}EM##|d>xRJ1wLK0lPlarlp-zuy;VUZ*aBpz!=}N>D~(r-097`b7AaHE%Q7 zZ9ej?tV*dSGv{sB9;8n+Ra`a@}yQ`EVP zktAQB=-;Hi13;?)Jp9IJ8tCx(FVnZ9xZ@8t;)KK8nF6uf9;iM3A3hKVjhVEE|CpGT z`)}X1{Dv%&IZ$8>8-Ff+_deh~h8E?_mW;TqerzUA0c}b|AWLTyITjT%+l1tZWgyDO zmnQB&2X6l(NaJ(fp6&2>7tRA@!kp4$uJO*l14se1;`rJ%LHqqMl28%Pnt@vp6- zX(UFnY|Wu3W}Tq6*ELQ0LNv+9)>J)@wyY?ZkIko!tTns(y*qO^<)o)Sr*Q;djGRbz zjW!d5bQZwlC#FA7aKW9+F5q~Tn1iI#MSD!C$#OM9qVBT~b6-(c_sn}s2l_kha|Ndi zRTHaPu->RwjN8Y8D?f_eRH}1vd#IT@i{7Bn(XW^wzW3%uG^^8gsNh!8m%Y!_%%7#3 zXi7e=_|=U*;Pg!q?x?*lFY4R3+=w@~+|Z5l8t4?NG|ce)C8W&1Dexjb2!>U`H0L8hs>5#C0A~?F2mh2Yb6C0_v{cm8}JF2T-y! zu!oTHCK(kAimU+RjI zs1F>J$Z4UYEkYZ6)z;lU$})c3=KuhEg^Or|eG%@hL)SBVRYG`YNy;fzrXHBj-L8hVa{ zZ(l&S3v_^1#fmk>eC}5P1ud+zShrV_2Fo#2g8>*wUo3=n7Sg+SaWT7Q3^6e_g8ndy zp)g^-G^KtuH2Ot0)gHd~!@^rgd6kU5gNHBUk}X~!z7KyW43UzFRzK;g+76IbBVN%) zAoN$m{-a4zNHXtPGLx@29BcR>$7q$#X$}0CGM%O5=e{YMOd4m(R033{rUTw_U;@PW zJ0^XdreJy$8a=3xhW#ZS_-Pz>ewBpSF+lH=Qp#P|E!cM|>MXj(^~t!TWb;u;%WAPs zwo3QykJ#0knvp-<61y*=-wv;;yeFat^K{j<^$K}X!<=(M^(!m+@Fh1vQMhvHyu>?~ zz%jh4h;;Evp3y5Yfd8_Z^tu#$1~9@p+5r=CAx8$X*FLZ)=2+Da0F9$YBBybzMKwA7 zp;QkX(3B+VRxf&_UB@6)G+GGW#X3Ugq{gn^dy$4}5+M3f=qAJs%9!J>mS_V9y-HRp zHP)kd38`D+q%QzOEIEwaDFcE-*F8 zT2d|bNOY{$a0It?0>FPA-bUhN5K98}4%AA!bDb=wB@F4|9qs{~=o^RZ1n)leg!Y;o z^T6?yb~xw^jwzL-RGOo-WF*?4iFW0rYdRV|nO;Mxfg;(k9{kA#H`Bh&!-X8zWoEhk zyqUb2cqJfwoLL_3q7EujgM01?e~JE}CL5?NeuIo&QB(1)29a1thVfFv)v$hYsYFH- zPEKZ6L%f5g`jcjhKkA_MLUvP4wVfq#h$}y%tw^HIL}U88rhD`l{h(d0mC+nlVi z?D&gJ=Y1}Z9{4}G*7@@sE@#7nIS$>|h#qIDI3D&o0)sI0(N^S&aa_7hq`zvFSPvOB zjz`U4(Ld!pb~L?TN!h$Tnv~pto&%t`G?n&m=+f2|5*67mf))s{qtnW4A-*n&sr0S} z^@^j?^ukNV40NA{`uPBbaXIx?4W%yy?#74QdvQwji%M+&b9n@wkH;Sq0Y{IY8|J8t zsg=}m=K}NZOtAt_zhrdNS`)4Z4yuKt;yn|#M1O@LW<*aY{8WKCp4kSLe;~(O9NzNA z_@y6oBE39roGbl-Hs}g)eYSOG+WhR2J;Rw?+F<;|N*H{d=l*uUJk`Eg1a`a- zRo(4S{eX|8;o#%bXs?GuuV^Z}02L7l&L&}GOcVWLPLre19@#_fSu(o1 z%9b;>_S34JYRYwF?949^sV%#P~w_YbJ zMqKDIcLfDf9|=t6h;0I1_DjvtjGRfexk9260=^iQ9M|w@}E2_P_ef^oG zRp5QpCP(ge=FRL!x0=-2eoj~XVyUjM^pukiEI;7QR2Oeuy7k-AxKmp5pQX{?F|F$` zEEOYq2Pf5uhgEaVoLH8yCnIlg6m>r+-k|Z?{?&7HQ z(FcvDD^EbKvn-1(t?EJ&>NeD`p@22E30jUjdjm*!lc3n;%x~ngIz6ZLCo8&+M~y@qz^5h zc5Y8w-T9Jm=UdmE?>l$atnPk}|Fr!+wLwmUcnEvKPp#!rdED_v2dLI^nP$}S>&pK7 z4&Bz@wgP=Pes@n|%T18!a8>&Wb#bWqY-gvQ zhmKrROQg-PZKJkD1v#Z4Udh&t2B3B?mbFQ`48PgD<2bT`Bw_oXRbA}L!K zsvwZPa=U8r2_5&k)xFt#wvC796=04E>?a#**k&zf=;bE9h z>+2G{D%x`_L|9CScIqRo8KePHdi&98`kBCSj(n-IZ%f^qr&yzqdenAWE(I^Rmxc~JIdd`e&VpqbBDLzqC)46-JUW2erjEDXz62kMo;ZIv)azd)}XArTKXUl%;coK zdwkzX+*J65v&oPBkl9pZ(jw^t3#M5MVsZjn0dN5TB0R19K}7N0-H+ch6c!|u*Qpmk z)5PqNqTwfIQzX_+7omY}bwfLlGw;*v<*V0Ejs?;6ibJ2oG=pSCmu#ih(~LtY0(gfV zKuFRHKwod{s>NT?lUK)2gnr3Z$L|iM9_N1fqoI~M?msat{nZ*&MRtY!P^UNoD`~1Q z8BoVl{*970py)<2&)uR!57$p>V>YkjN zgw^kKhSN2-?(2JIYG`>)Lqwq6to2Mql_iq3`#51SV5J>fA7t#BBo@ej%65* z%Q0k&`j8@$ekQ>!ptsB$tB2}qInHa_9d`qyo19&4+;@0!1lr;)dFr-$=4t6>=a3mb z{>AKvCxf3fA2t(yp305hepi+W5D|me{8)ECOtyG{NA|A1^(CMy}`+${YF^vwU=6DB}RVxHcm+U_>N^NhhpEmVy~~RqAm=q2|4OKjS`V^ z_tj!K>Xc}b9d+i@q#dOlI;FDI&#v0L>ZsJEWhri{c>(n|c)fX=&($9KTmLRCx|U-1 z&r<|l;o5V=Zjn)y>3WuZO$3(GT2(VA!oI|HQ+Y$*@DZw=80%^KA$FaA`8EvZ4_y z66RQ{;$&Y@zTKa>n4{KDd2Ar&$3hIWA*(y(=zil>Y=-skfTCn|{%8=?>c-cUqc%f~ zkYiGj4H^i%_ut+W^)KT^BX&36rNFdgw8jUmeua0nSQvSy688O=DjGTPr@IJhYxwBC zuf?x%&k>uSNxKe#)`bn|QwP^`a3= zPes{YtU-YXL5jq@mv7B&S#`B5384cmcZy^D@z;b;LnDn9Km_dkJ`VyOn;HnWZ4N$z zebtLTK4Lo`?vY~E`^h;>$|qU_Za27Cl()aa<5!{Ss%EpH-Kyrs`r%kXP5s{CKF@sH zU0)y&xwv5BCXFj){j@B+NnWxzHcr*;+I(dK*QPBw4p?sm6E^C$U&S2Bj}ZoBSaS7m z=G%UQ*kg0N@0tu+ZcfC&ZSz+V1ndse6Lw&GLMC^AQ_33+L>%J3Jgq2Ig%p!t6G6(A z#!<5$<~K$)?$~yS3=4Wv^&cO-GfHuCmm-(n8`;;#F50&H)NNLOmp}dLj$tfg7X76` z*n`B&j$uijU_Kr&tvuEsb|^YowuLFWH-iI-j80Lh;j*M3G&ouUK(9N&HipJhDz4S> z8@P1K2{JtKRke&UFWK_Ccbc4t27Qs(D`D>rPvRzvpT|m@g2CMUU;WhnK4fGGnfXxaZ zFaArPxE|ZlZtk^NTn+H*Zv@zZ#K=iv9!7m($ahTvGNv+zPRKUWEUy$9#5Dw=w?>^z z&w2ryZ>JV4IZxRp86$O8F)CR#=~koeH$Hz8)idTjxBbU=hsSlVs$K*Rj^7amhPT|2 zA;riJC5VaKs?bnLpaLZ7*7B<_5hK3nX1#gE$h&;-dxZY)2pUdxCB)C^|XQ8SG}Z(Enm)+8(7f ztm0$A-1`-f-0^-);%nn?3nTX+9+@u-Mt#{U&m|3H37?Y-m1D zj~vxFX68&Y-&AXqo!C%a6B3aiwOP3`c~W!DPA02t(fz&}^p_LO_$1L5T4yt;CS%$X zEv4j;qjA1h*G+1Hmv^PO7lO^;XpD27H)_(rQ`_mbovd_&QjWs5^7{i4geigQ<)VD8+B8@D*ThUx$#Ng{!3v9>sWH1C zMNxCYz8SJPa2+ST8woZTC#K8zq(si)Imh z;_A1>Tp+@V26*K|OC+nr00NvuB$&Jig>wIi>CG>It%dMz))}+tAH>xIIg$D8{RE}m zvMl$KhY+K1AcZHEvS+0;M@|S2UttHCu%%$pu_+29?yKgKHd{Y76BN|(24lz(V>S_F z3Yn=|GcudP11etvNq^l*g86a}!cQd2AV4gKc!s@6g0C^TAer@h z*hi{@)L@NhnoKoFnueU~>{UIBAEpyEi=E5&1V-y#ngS|mHo)Q3=)5E*!E}&hhNiAQ z^C+AtEAU9Uc-0A}La7H)I+x5Qe)i2tywo)d2iYyW&XmQ7fKn#>%~AtItVzAf6*xR3 zkV%tk5AyI7IcFtds4g8md%c;ehzLHJ60^|z)bcm@%86b{X(2UnU0=sL<!q#Tm81|n-FP%j|;v%Oi9d_xMprOR_*XDTJ+rOOQ}E@ zO(T5VCxK?-@Ol;6!HXq^N$#av+c-cBjNu*B1hZ8`$7}F|4#L-o<{dcUP@ev1t1vd2 z#w6_d6Aj1!l0+EkRN27Q|ZF*TjBFUNB4mhY(~ZZV?h5em=Y5@_*IwJ zQY=FVFgq`x880eY8u%v+-is3kYwG`6J@*cvKRXWPys<^p(@%5hXBOz^bp52~{oIH^ zZ3?_&^h7Vi2%CoZ?CBoAdSQbq;l_ro;GjDgs3ro&NIBnq4L-h{pa{7~2=2hlTF2Vfh1=N=}f(Eu+zR zdz)6_Oig&os$n+XBmr-jwHox23D6}bC{Y!@;Bs9aLO)USfAbfhT%zm`QD8ULV2@g6 zkKh&A8TrmPvFvrs{CZdxQ|u`dmYD)cFbxsFuYe$Xj5d6d31aOJQCNq+u9vaFK|V9` ze|JLTg`~}*#dWymW<;oCH3>%*j>L#}P$Aq_$af~ZzJQqcPLC>t-^&91xew9Ao){&; zc{t&5gkDjVjIq%1EmDMdTEy?@*lV&EZoZef#D?l*=KqI<5cJ#=R^^5`&~Jsb%bm1e zY^d=l#!=LtA_UB58nw0xN4CN$y{??~fv+N9@1vnJREvw9K3FQ`HU0lO?cdQ{iu5r8 zWlz7mh%O0~PYvNRApUQm-@WxNg5gEH+&I36SugkCUc7^~hp&PM@aIMNQ0tXw-JADZ zZa#>(`A{!i-3ureW;Z8tW{nA!_y*bL!2(0UR`!rs4Dl%y{vS?wbHlfv0)MNO5P-Az z5N%u15OZVUXm&X4kw)eW6Fx^u5ooaUOd}It>n(Pc=VsP>90D77a^*SlQ78PdbJlwd zD&GfTjFD`P5y$u*+=@QmEQK0!MxK<nuG&x2EN?wEaVj?d{m(63#d}%-~^PtH>-LKIy4_%cnt)3Tql;&&19sz;F zCUmQ{eC`p*(#*m$ScMp9(~#N8v+kiQfz;MF>8R z6-%An*B=h&ATr;T!6*2Ba$GqFD;jWy0eAJ3|FUzJL=WmU}OIq(iuu2^Z@kjW#ImH-$kXb5$foJjyHp z$6Z<&MyFq?}j>A0{?i;Glnb(D(>go?vduh64*4X;#!y zI-C;Pu*0V|^oGI?-+cHD3r*C*%o44CV4UZf2d_2JC?zfZtj6*kv2`N6QK;z;rpbYQ z=oO(F;re6U0eK>9_zLcGkg0 zd;K6ju9<-T8Ev_oAzphPMvi_mq5o{-@UyMc&vvtPE41v5MtYW7rVE4tLd7(-lcGp~lU>IyW)f&1gThyX^0RA#& zBO?1@c-t?R0&rW~WQGj-&#esv^9#*Lw8?BRx;??E)+W-0G28yWG#8O2@$8K_!V4(R z&tkm^tNYP<&+7F(H3`_uQHakJgwKO?V0-2KMNdKcN!?EJEb*B@NgUJsPwz#w>FSR3 zJvg>#08x~Lff-EiYm`!Axg(wNCSNh?dQBxeZ0OidNTH0<3BfCYMxn1%KRLjql=tv6 zvh%GJaE1zpCW)rWakCyPCyHAP&~RqGl9siAuhNhtZOQ82k>!aI4Z>YwG+?>}Eq9sQ z8dY+|T#O%0eTpHR{vFvjs&|Qz_N=?nsO0hEkB_Tvh|IXao-dm0m%Y8j%KDClbWn?) z*FmYTG4yg**oEdthw45t47iv9K3jBi_Q?v!6h5almGopl0-hy=H>N5q@m~TdINP(+ z8Z-r^b5%0Cu3Ro)^k335(KDmq+|k&o+itDGU*}*n#61qi%P7X#p&b@a6!8}Tga}xc zJdjU-s=d?fHoLoZh_e*T>6yWoQ(gzF9f+*yfqd9VA0gBKFtKhiqF*pwR~JQmS|{SDftOFntMM~y752T4IpLz60q

iXZ^SDqK)>l zm;otxk^}eZHsNzk*Xm+=sY-)nxP!D0`D3U)A1nh)=unc7jxgatZnZ;1@W-Hgfbs;A zfitLjf(ljl30;SwE6C=ZTwEgn=HIte$+e)6;AATTn`_46N{x3f>2s%=XFP^$(GQ1m zg^@1(O<+)E37?wQu@FGdD#nwMjYKIn&BB@_Wi@ju42U{NVA3?;N}FZYvyN_HK|x-jatklRZAh^DKzrQg&b{VG?R!Q2V0P7K25>(GOP7vL+lK& zNg=7hFxteAr1$(y4hMkcSUJD-v>#b&{Hg>z>t5~U;J~ZAwYASWwdlq%Yh-JdzV05| zbU33(zWG1ya3d|0PgEZqGm8al@VjGl_L+VPzQW-wkI1p8C^iUw$4Dw;q* z{R&!xp{5Cybh{ZH@{weWIRY*lRJOha9(wMyya+XBv5s zrZ1SGnR2pfGKbDWzu2q;RPmbgN3n;}k?0zl1#@@6iZdF{VwVE2WGg&@q)*@$h&0Dv zV3{MpZ+})9*gJ_);YKwi0tBSYn$RQ^vokFjKJ}K5F`>*?a0E?CqsN0ktdBT2A6-7O zA|wI;X=sCe{bk;exO6fyYed6c$#b09OcjcWNu9RN6!l*+Zs%tI`W)* z<*1rQVz04RCQoS<^@D<5jv#E3Bt_y6x6&FZH(+f5&6F8J?E9vsUQNLlYX()*p)oY& zA2;?nx5Y)Zzhm`Jy5p*PPIV*4a0Q%Vn=cUx7Qcou%LeN-XWr`wVILRT>vdd;CGPI{ za^Z^3;Z?2)wq4@!(7)**HU4YOaW7<*mDUhw)WDN4e$l3|z0;m3_6<>_<+50UuAc5>|dV1et2[ov=t?L($lIlJ+y9?-A$xmB3jDw>qMLsJ9 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≥w4HM8C&HWMms(4h#yT`F9N;Qh z%{^Qce%7t5DEMuyZod)$(=QIps9mVS$%E_&lq95dqlPxf9(IVzMI_a{llHHWvRog` z|2HvO?u&L4Rl^$`$bYphE8l60uNm;{)@Kp6h#cjh3HgTmoyr*LUWqKDxu+frDifQ< zyBr>1jq^?`BW~AKYwi26H@ZjMytmt?mnM$n+MQstvven}JL{O`D!1##SpGeaGOMQU z;9l3SQNTomY9;;2;o>SkzDnBV4HAfMS;k*9PPn1`b;9VkZ zsN}I#%Ye(R7*zBR{pQaChf<(X_*pAumCw9`POE&M_&a$6$Ca~+=S}kx1OqB3=52`! zz$gDOe&NQS_UIC7paTtR812nmTdMxM2!BX=$V(^9H*G_ACyM0wzz*V^R6zuT33=B` zPif6FbgQN$sBcpik)N8F7s`eW$9WKeB0HC|s3RNT%{9k`g*lIamm>1H-a@UefHe(B& z?hF{^pQ>rZzoKxg=b6>2t+o}P0@(V=B$VnAwSibJ)%xWu;%GwE?T_?;2i%GWr+ho* z`^`DqH=kGB!aAs3nTN9tVx&-KR@Ia_OgJLB0)3{KrO>n#XYFF8tMj@Mw?Re^C!%hx z$}<6I8x!RGs?~-7IpKMHnygM1Aciv}61XW$Dl|X=_j@={#1%j0C!dEwZwcM&DxmKi z(6eMjCjhlh7a_{UV!R+J0%S=eD9;w9>Wr}xbzd>ii$rk>0NNx(L2u~T|44t&gJ-Y% z{vxB`yV91vlB$ZRbzEc=EQdkj7K;2;90Z}o?;ZbSP(`*$VCI4T zfbJegwRhF11q}Kt5&eaM>LTmj8FOw2;_i<{H=fMU0$0D@j8IwOM&k8~z%>$M;diPN+|NgKNF?nk`jfIYXU!MYs68!oDs0lFn1opvorA$zQ0IG4R4(@y9SQzV0N z=p&5_6;B_Qk6Q$QQ@97qD4^;9*kvh_s{(qKhkUVm_}-dfp}4}Qj&lCabr)ZAN zbaFiHzY`@Z%oSmg=*a-c5)VDo2m+VIY%*bMd^3D^;VMhi+(X``q6k^wS3J~fj6#@^ zxN@Pd<)Wl@wYW~BEHK!*YqiMjA*C0dV zXz@>;sAWhD2yVpKd=gwpGZ9ZNLH|uczZE8n-39e=4H*0geqeofO8ub`=gzGF?g%Eu z7o12%J@G~wO<29ELbWr*OQ;e@A>QBAqJD5mwysErp{M|Gb))&kMiB85dTFKU3SA(cOZ zye5qb+__&Cj!s&IuY+pR5270}c5I8AKN$Xv=OOn6h+Zy2GQc5`11H;TaiQ3P+T9Hz+w-M3Ri1@%g^_r|JvR8ZqJo*AauT!eUNUC*$dtWFI+Pz>e zxQJc=QaS-GmVn`xp;tZk^;$d`IrJpHs{Y!pTy9wTT{wI(7(KDgkJP)5z^h6s39)2P zu_bOqqC#M!R>MH4^USStL#sEH?=}3GZ+MY@HD(YwuDT1{O!}#d(P1DR7w#PY<;>)U z_fpR1@H}65?%wc5s+*I)@lg}p0v-z$`c>!J5G|s}_+1P7H+RPt)nDtEvyL*-ZLzzJAZ47iyE}Mo43id5+Frf@#5W5Zqewcm$|RW!8nCy zMrG(1m}ASO_l_l>`{9Z54TLmOO-jwxANo6&Lp5PJ&<8v}Gx~$|r z>*x=j$LsT;A^wA#E+yfNn?H!C`W9Mh8BDtd{gwi{vMnIh5lu`Pu=fCuni74hMvxvC zlq0TtX%lTK5Est3UmHSCW74jlLFrK>tQ19H{LoL-9EcaVBoCCpLk$_Viu4eJz~?^% z=q|peElu*UBsxD8V=L8PvdVf(4gV@z|AkyX`fEUdd+~<(r0hUBY8Ikq*Ds7Nf!O*l zu?Z<%;5If2{yRnD?v;6qe+8R2n=}3`7B+ka+=*6~#1ElH8WDXIgt;02PZm;<#h+^7 z{}k}GCEML^P+yTz4@v?%m1*^iwqDHOMPI|T6Ga|5;QdzUtI8wSEYW?!>H~=D zR;s8?J}QxW)s+F-3Tra;gaq-b9?2-~KYMQV5%ZlOFqWZmk-@0opXv;IkQft^Y=ub~ z=!s#&8spIKR+$SK9_s+O2&8?Vvb)VQ@-+}#z(rl_KpvpyT)XIz&)Ow@WxSuEUV4za zB>Do}DACw>YD)MT#{!M>6aUtpRJt;Lr$3{w6|n=3&VPe3rT#~f@I2LHqUrL`ZxOxx z&3@Y#lWrj;Z6Lp52(i%2p!3Ca{TUB$$ZRUI&;O-r+?$T+`hP7NUL@z~`Tsjl|5yLd z%P%=sb%b$i86f>yAh!FJ*!FLIc$+WqSHmj?*?#PvcqRa81HA3V=Z&VOP{-Q&{ zH*FI~M&Kd_I=K(DC!z_zoc04Vbm=5R9j~aluX9%rL~nZF+R0N_E?AR=2w)^?wvqB+ z6!i{+YCuYv^Wf@{>DCKzp9SKGGT3d2IxzE|%kjWvO!KQ^)g3eJh(6R$I`TgF zdPw{eV9z8q3pr?#5+eSZq`Gm%O^>W=DnMF?(SRr#@gl;-<+|iDBfcbp&`AQ)_X+z^mt#9tA1*RT_3& zvgirncXn6YUC_4}^azbq$3RpIcDeaY)csnL?-1Kz^StyY{3}4HEjgrmT&Q8tDbX;r z7++dAlyu~U@D;T-M27KQfd0u_$eMe%h4Ha8Lu`@JMVKY}VCVrJ&yw@(cqRE4AkC8o z-H>ORHi$Us72Q2P<3hy*UWJpw>brkh49e$Amv2}fGpc0mjGw?zFcKmEpl2w1X4yY7L$$nVd`SB1c_lTH<1?rRKhsbLiQAeeU@71q-MKAKvGGCpndg1H* zA#us{lMkd#`I0WzfkuG-aK6tRMLCHD+ve^7JvjZce@g1)N9F4uw+>A|G>QM>3DXui zCioJwov+N>NaGB!eh$dc8Exoq5bzaM$lY2oaQw=LCrN-FpoFam}A zpO?bXf2D;g7Q)599qcHe+OeG6OV1c1eu8CxIsY24_$`e;H9g=&AE3+ON&?-W1B#0Hn|=ElQ3Z z=Kbt_v!*B3mYMyUxjlPwkaPqw_5)E1Z=YQ zJ|M@`V&d^wo)PF8F_{4@p!PJ`kPev2HszVDjTm4n}-MsFYfmyJKP5i@yj`}o`LeWQJ` zGe$1cbG_i>FTUxjy$>$gFXI6Gc zm=jm%Jy)S;nPkG5$##|owglL4B`jIosr>oNt&b|$w)UI0M`G?iQ+z5A2a|_#D2rE< zZ`^&RKwl=ExFoAPXDfB;^K4ja2_rIxFk5Kud@W}Dxu%K;84pB@Pag}H^9|i%6H@uv zOjUw6wP>Go>jVrZ?alvUg1ylWyXs7*-^#KWxAjm~x-P=EC&uCQw%I4Y8F4gn3Wdze zSbXs_`C!2NAZHbOj4ToZe2oU{XnTb4y;Rjr)X8t_dIgza|QoNq5r?h3py9W&E6a>>N4j;T~O z@PR$?F&#LkdTMG-Q}JllRyXO4|D_9+Sn91F!V&qG24NQtgg*?sc$B?6{8Ge?hv65K zJ9k5UH~V^Ii}iFrm!JJS;XJ#bZ!3B2Y)SZ|Yp0eO8`n;(SCnnLq^`FwUUAi&yWO9+ zx`lnZ8ML=uIc@yms}{>YyKm;m`ESAeL9-uVm*kQg9f-AGXGMKcKW#a$nz*DLDrak+ z!mdTIzuv;7uI~Q5YIXJooKw^=s&(=#UsH2lKo3|Y)L#6j2cK59+k2nm+=qzai=~x| z1fM7uJA7K}`8?&c5gpZoF@#sn_JeELH)ZZ-6^*LIReHQwAAd-5b3U)b!bR8b+X$ME z8!!2LP08-k;&STehl_Okuhe7n&oMi$EhqRZNpjql2DOS;w(nm2ek}I;j4ZQu5oSGk zw;)NxwW%=jcgpH+x&FPAP$n!2{2Ng)e)u?^G&ic&TV(?MT(zyTnmj7ea2I`+>#4$d z++zVfX*I;>DbD9gop$(0Y~F)hGx*&=o9yuhr2oX)yQbi0aFvPOxhR7+27!+VB^MG-j*G=|j>9HDA%$ zhhfSK9oH1gZOYqHJUpVe?l?#B|CK z>MG;}j*2#IOb<6`=hY;tD!(sXws^UQJd{wY;n-*| z`oFhh^=0xnjxoV$4uxyGNeu+cLle_0pRDs>Rw4?K zx%T|&q$1q`CGV!tcA%?wvu3xo)B$l-f8P-<%<{Jy)I6a5)$=Bhao&B@t;+d_za1vY zgmq}_t8JjdtZOQuWBZtLfgk;OUjEJ(<#2Q_s3W13){;zS#qW`M z^XolFcAZgSym|2gcEum<`EDd4iVIpv*#QkNH9T>LJ5e$s$iaz^5Z?pbbz?(qnQ#+uJfDBb^MV3{0vxY0tDBC{o-{D#yI=L}c)(`xSjIeu_ z;|WGQ>S1X=0-}@1_TS3372dr(k|5?+112m}4^BR5g-`QgTT`^bo}`KXqtN)$XI2ZN z4!iE{$dyMYi!R>gfA^S&w(D!$q5_!qLg8=Sm9YVLsW+E89=LwJa!B4SalA@p)aCHC z-vbfDvbL`h*nL%s`;-k`GsCzRTBy}PCFcV%L*)zYyT{y1BK;7r?(3Ld?&*+;Tj?Y$ zz%?(0Sw|lnn;d=6o!F3g_~YNCV8v?wazm!|iq-^3@e08HZ1$6waI-fPuh>Z~*Z(xB zns2@u?oJB1bBG&r>dl+C&{M6?tYhOYzL{EdI`!!Flh~vOZ>GPnPqn?bK9Mr^X68rt zsi)tcocQO*o44E0WWJaUeLG!YN(eg<)8LS|n$sFMB@tnM3`aPbb6{$&!{6QTz_8A5 zx)u4@UlYN&cV@yzhh2r%%>!05O&83jW}hiOzr}Qt3mUW%2Dc@@OnmzF@^vfI;BQ+2 zN|%(#8SP6>|Jp^j0@&4-MIThe9L#PQxe6%#^5aC9+Aiyrih}DBPB42x8tU85-0Am+ z@AS%ba1+YYpr0N|of&kUDZD%T95F1y$L{eFGo)8Yc(~ZT1rH}x$XxwQxn>@PNK0zE zb7Rdqtu0FJRs8bmaE^S9v@VgF23RArj z%m$>jpx(_M(kjL)5mvVUHU^UB7tV)@CsbGAJoU~jo{0+{Y&*Q3pAe7WiZEXpB=I%Z z-=~A3Hx_^4V3PsPrsteDzO{x#eiT>-Mo}aZ%GG3bgwJ-r9L%OxrLL8oGXLAWN9ni9 z)9suwt6oXUCm)-BV?H?Jfz~ER%ahUtru@-s10fJNUPj6|toAPFY~$rW;QTo%>>qO& z5erEc@pjF5^))PCF8g#OER+jz3B0FTs&t0SNu*{_-?cb1E*r+*@Z~~?^ruRc%;#K~ zHBo&O%UAFLABxm{aM|k5ncK28(3^qcuz9P2k2aiKVEhs+9=oSJB#%zXK0}2eQpB-B zv8%IU$X52YOq19G)k@E#`ct!=_B=)F_a4jnr|m4hetoC91D_)6kmy5!LL9Q2?STnT z!*{YmvqWfhb{>%}*Vqy)Y- zuIo&fv#8}uqmfCVgP^JDju52LvTP)&?c*Wm&mT=}LJXwIti*ASYke2L29zk^Y}3gS z?y{VB*}x;jYspm3=`2{rpmbSnmQoEnl>u{e0ba^QXQ^F|U4oq~HDPBwKAa%#)9K3p zXfmcGX)KfsWdKpBx)E4*3+ddzq29xJOiuyl6c=Jc)11jFnd#dT76c4WaB_}re&A-B zkqHm2|2ntTz53y$yC|2_j8_3IUfA+#Re;u{b$h1xdsgNDYalO+56D@KRPA6;Zd3HqCC65nR>$9>caLA`ph3&`O zv@DmsEzT8>Z4v}9x(m<{Q`Vtd9k~WQYo6zs#Yu!`>}rGkI%eMO$=OcjDzvm+y3*Jj z#O%Auur`;1`3$#~#aGtqqqaY`se-`PScrvCo>*)}ELAXrL#&1Ap7F-clB}dnj_Xvm z&4(+du1q=Vje%70m%r=MJy{e$22SzCB^J|TGsl^qw+LxV7pAK{27Rf1X;Yn*Lrcj>}3RuS0_k!Fag zRP1@u^6$UD-5grHp3d)if^*j|=66Ddh_~+%N;86b#XPdW%8fvVFJ+kP?goG*@2v~p zl;nfKu@ug+rRURR$*n4p);m3vr*UfadKkmJ{2?Z*xOaPGFVZxcVxUFU zs<;G2mS#*rz*gFv1eZNy>4m4T@R5Y(kC)jAM5qrqT7Ga%TF_QRaDn3|FVk@?G2x=j47wLvA8`;gOKFh{er?ax@+A!vt za-23NejNH>p6S6KIfCS9rdB?-hec8=l*pO!WSE;^BuQy_j|D8WS7XbF6UUc5P2t3C za^hXsKA&WdWNBur!u&Bey44Ca==Xc*Xg6%DWxzsa`qj}&Gt~MbNgHzGu%(7-qy%1FwV(5qI|ja@c1|^m4bPz)NytR&G&R(#AKyq z_4gcmVURDL(91~^2BvOuP6d#(YM6e#oU@yp4Q-XPOC0;b^HN3?`oEsNV-}xW;v{X} zbOwUxbS1TKwhyf#8!Ibb9G-?xQYGF$%)p18LxylIYijbR8Hr!nY2c+!vn5XR8A^m7 z1z1hvSkR{c>W>?8+lr6d5H57zjc*1T27+XJOA>`JCw*OBIXk6Is z{fk2{E%xJQga&Y0w-nwU%zRG498P4t*kot6GtDwNq1+7D0Jeq~j8J*7PQ!gWS2isR zdLIr;qd3clb*Bi~v@BR6nfHC_sT}cqGF-B}*~if3Z2}h-IM0qHLhaVYBlzs-rHhHJ z?6g*PGyt;gY*Z%Gts zk>bESB$f`3t6@j;*XEesC4~npf379=l0qg&ZA46)BR-!lwY)KZ3LE0pWP(G`k+xB?Y&IWZKm00HzgQQD1jSrp0Wv~1^`USfOjAR>!M$`U8mTw3sAK8?XSM#=PBf*Ol+%tK7iVmb5k@=jP+ z>j0)JAC?4Yds01j|MA`yHENNmaN9Ef(eR?N%#vOV74E;3Ia5hkVk(d`e6j+!57RTP z1?k+}qff~kJqA;W$n@aCQX|K-akjW?!556Md#^KYjyxYLJ^+O5p zr;o`wqGe1I0NOChxl~D{3$(`YU@jf(4uLt_dI>S-uF_fYTuwBR2^j>0r@}V9j$j1< ze{RUzbfz#~>S&f*B$27K8X48fxnSk@w0s788Y)Z8l?{N3s=1*9@aZ9v7*acXa*%VP zW+9ebT-j=f<3r;kp*B*BX^k8z5vTwJ_0Z-d4*^B%)Af3_$W9Y2DrFHeEqbBHh%e6` zq3-teOg33!*ens=Q)sDQAYnf2(Jz0J6rmZ#1T4g3TukkFra|k(;8Mw|D>RUK9E(vp z;Uc3Iz>MO)3j?LodtsVM#kvBpHSwXg4{PS1>GJx6S6-gzX5~ewHyPloEcno;jB}xP zA)9CCZYII3u8!lCj7YT~xg!#Im_=G=C@&ZIGmseh6a(RbmbK-%wVI_eZiyYp_u zrbNK>Q>DhtJ7mA|kV!QdM3!+}8k;ene00;M`Ga3y54Oq*AaR19r%nb_8o@Y9qp~q) z^cw;zfX)T7Ex36f_kQ}ybFv?ttsjAXD=s)8fF%GHwlY3_bW6v&#QbDCiODbF{G9Pm zyncU<0R8p)tGN;U3aL5mthkx(Q<`~r6V!u4lBzi=$xv5*M)ZRWU2zWlM;7-8TYCs> zcN@AlRkala%M61hQA(xK3Z;+w)W7%AYL&E(gf6v~C6l%K;-k*Ct_36-)IQ}T)!3;l z0*MOizu%QuEGgt9!*cgh@tMqR*Ku~7dEG$?6}<;OretoE3$XlHtdT_g8EpJN3;D)r z9Fs3__bhy{%W+2r$1YQxAk6f*qMLY!b4n0D!$<5vKiw2EqkCbe0>s?-NrA~*R4OVl z^c!f>n^+@#l8+Ghu_CdsTR*FkTVeFoJSCURLXtfl3w5gb&IWtMV{XW1LHE9Xc`*QZ zfRpH?Oi>b>;JtG@^59pi^J_44!x5Jh^5fUPX-GzBI-wD`Lzod*Dn@f*f$yjXHU^yG ziw>Q*UM&v%-=|R~F!4M6r%N*|URToy)51Ya3WIa`KK#_b2l>@r;y>h*vK&-)&laXF z7oE~Od~Yrl0}B$TZu9jviLd0+W1|AKr(4Lrj%fxsq8O7{(OOMR*K2|M6~Of>%DjALi^J?DjP;{2lMjDz}NV!u>rY zWpLEeLj6Dk;3oR8+&MkG#jRt_YOa?pPR$JT4fna1?TMDa?`^3XyrNemZ)y=A=~?Z` zTF;C6t~*+P@Il5g*iD_YqjaiTJS?zgmy6m1q6NaT*xQj~h~l zPPRl3T{EHrW>4x|wJ^Lg^Zv}j_(D$D*4&5PpPJzcalh`b@#|YcqzSVd*=}>c6JKBl zS6(;w+};`-ci3I>*sMUg-mf~ny?;@XT_j@F&*m;z?7~=oSs~?0S(@8?5dt0dZ}S`7 z89B1Fb2f7Tk_@WgKjnh`jM3~}8*TP5jJK$I)cT7{2g}S&g0IDO za=y(u5~0-*Hs6aw`gLnc3q5QQ=ZhT>Nxg+gi*2DyDEVJMO=(xnifV69 zaz;_X?rpT!_hIk3Ofxxua?Y5nr-$S9@EEsen+MA*o@@mLonC&Zb?xlWEiE2X;y*e} zwxc6v*Eq&muX#SsUGGc)2}0dJ@z5JtE$}HYpfJ{S6i~BSvY5oyqW#7x{CM=v)z`lE zT5u_QJA_drCh%DI?&8U)+k+1;Tr$-FI_(^EZ|XSyvDLOCVJ0tBCUn8tZf>6`>E_g_ zvF{0&5`JaGD_%89klt^-I?}0w2yC1NX$v+FEYm~|ZV9gP~D?>tA?PL*(y z+rD@b@~+(UMb=P0N>sL5JeN=mGSi+oZ+DwqUWK+-`}NokVJ=(IYg~6D#7T<4%(!lU z@P@3fR5-7wIwgV?_Z87JiKuyMA^b@I`Pd}vzgN$pP0S% z_iA@kZTP+JW_Yt}%?@qtTiY{NE%)FR+JAd>S{ixsGik~HZyn0wAWrAHy+6SUlg5- zH`D(g$2Vhh+10IKo6TKRb1Qe7xrdO1qzws4BZ*RNhLFoplBBsLN*YNjUv1`E5<)7~ zToRJzl5T3h{r-W^`JB)BocHDRdcGbH8^RC7iqKHk7%p5g%Rl)NSZQIuoL&XD|2j`g z9f%WaAF}xsBDkky#P&njf9pPy`DAJo`M_1&?5VBr&jMK3YqMMk-T$}C8lcEtcTvS& zVTY@me_?k~;}NG5rKs+Kl9U(U1ko?0DJpd;SW4ui_RXM7xNr$YSk{g~J}@!WKQLV> z+q+o}mMpIJZNr7?$upV@S=ma-q^IYVzovHeflcZ%K#GoA;}Z;*eu{wzAU4 zQ}4Id^Kw1oV{+b&)~Z+@%sG}UHC`5`-1@Np?(w)(ZOn{8uhmFX{*eVfE}>9?>hw(3 zmoqw@;AdZS={EL<4+QJOmQuvegf##3O7inXq_luE-%rT;#vtX>MUEgtH@@y$-|Z9E z5fDqs0Vlu=3KMd`vojuViDqyy0?bl=svv#FN2dR09pUUm+nxuFDt23P2ILGy7?BTG zii6b!kG1vMl~e)`@V;p{PfV5-A;G84QVI=xKvqjAho4kEOi_~zRJHy>lBgOp+FYVG zUkp>Mp5ninngyTrMTJLnC|(l56gn7-jRfZq-xRQ%l|TeS*{L$b6i!{e+C~ zA6IBBligDTkQu3DV}Bp1RrZ;|PXf}kn2fx1q`*O9XX+m%NfkI!2+kpV%imM^wruLv zyU%;Q-4kz~3eMYID(`H!%=GSgWEgnlO#WV)c57W{!s!4n?Y-Smy>}BH+zI`=HBcb0 zYP&eCoJlI5uHcND@Wo36TSm0qC^_#4HQd28^+;+b2fjQSuJS_rs_x)e{!u4wjb#b? zUUGTExpitx3VU{KoPZyr3pDN|e?q@1@lA&&;?|OT9nAZ(j>tWio9&ZSVtuTuy7aC7 z(92utQsuGI{g_wm9*fN32iY$`nxEPnkF_(cvoe~ty0>+P&P?S+`DkO6Fh{(o!i)HR zfyS#+7wg4BL^NPP&v`;G`Y|vsnmVI+tDa26+{rruUDueL&$NhXz2jeT6j#Zqq)@xD zNg)*VHxn-@R$5Ct;Q{s_Lx-+=Os_hU}(HyA11}QIx@TUo2<0-#cQp%p=x*b z9W0)R+aFOI>w72ctm&m{<4=ZrgZ7Z=0^B7ZkXGG;cyl!!FLO{w>Lx|A^1%hO$9I&9 z*TXfxw5@pM8|9}8!!`fRU$7fwvZv9qs{cf;4!_BtZGH$e-;$XAti#tMx!Sn(Qi$C= z3X#~*X*m?^(p^$0h2Ffc-Dh>dq5M;4m5`$(v9j1dTS6p;RLb5Qxo&Gbg~l}8*IYpt zW}Ha_c`8L{ZcbdVo}4P6wJk=z=VV>~QCN^#2clU|@y(T|*=K(W)J*7Z@*OLmcg|>Q zGB?B*?39^rR6?pXH{BpxTn?KN%UcIeHTGH!?1jh%D?mT>_1bMzBFIP6QZ0lT|H)S& z&PH)RItF-r*)%~UZ3e#~$AEcmNpi`F?*^^+U2y0sl)4ZSk9{7HL|!#1aP@$WeooeR z{|hXzrpn6{@Ca6EsiHfkhxfq$9NEV)_{o6F+OKp- zQee-n0cQS*M2f0#s~!@J%8RMdN~eO-G|Ex=C(1z>KA_8t<7@W9pQ0Xj-sZwRviv~g zr=y9VPgycl~ad~uo%#yJ{Xp4raAERbBS z+K01W2?463S>V-TO<1(00JiuKf>b8t#SGXP*w%s4`~T%Vb(ny*K8NBOJfnb@@iTLMul> zU7lLE?`E>v-aI*EpfWlgh!*kW{$ncv`1^F5|G*#qql zJXTYzEVuhEoe5WWTS$i$hcMOB$#rN~l~Iz?xe;zWG&!5$`6$WMB-_7Z}NR4 z?K1`+AIcmV=rY_#hG%-{dx@D`wMD4*&dBP3E-L<}v!XK4 zGED10_lu(R@DCAK>nzGNO$IsPXgwgX^GBLmU)@6&r(5OAzy`Z^1(XIbv>k#oxaBV$ zI=k)j-1ymoRXcfzdXGw?y(_A%Y|@L5Y2XOwZET^q~1PBnOaQg-`$*EwzUO1A5> z0QVSekJ=iKMxEUO)oP{u0AjY9LE5%a{@R0x1IkKvVc{ygG`%7IUtvvU%Vi(co4z<* zKfRmp8R7etnOk$J{mL@jVycb$L;N@T{X=gC#Odx&y1Dp&Qb3Gh|Tr;P}mhA9O?KZiX)F9@@Bh=-*9`ojN3WJ!&(arm7dFR~xon zFF;XuTtfB=y!lw!`3(o<7MZcvQ7^)ywk~Qe^0C$pq=K2^l;XB`WJJ!T4&&ACFiNPFo^yj!~rp6oc z9O;w$+ku2dzICQdOsyWmRuer7JkgBwFXPntbnUIvak|K%o|tJpclwk~ zy97e4Coiw&G)-FToAd1AnYB}F+9-_MtknOiEC6+k4v;mSoUHiF3jnn05?G8@$+~nG z4BXo3qq9HO2`8O);q*Knkfz4oQ!i7O-3c-rt&&+hl3a1bJ5sky_DDdZe%^RpUYIt{ zSny{`JJloCY$(Wj;)v;oTQBB&Ok0L>!D442^1&Oi3%PKK`*mXgrZ-Yz*qY zDOH72HumXb023 zwhohD0O~>0)OmouB%$6oQzt~y&1XLU-8Ffej2^wK9$&81#?;!R7`UaaU4Omx(r!Fk zLQQh9)&*LxtH2I}wMCgtBmI-1K-1Aad^&SHpi!7c#`<(lS$FAguO6*(m+SdDaBv#{ z!Uf#R(ADX|8w;#ASvKvI9I!8*D{GS+U}NlJlL%_tJYdrT;wN|MN^9)WsS#Uyn|Ts# z8Ynglfmh@un{tq`1ZF?LvhAW+&XaqSo%A^%+jfyH(%*u2m6yrdHc*H_7^s zW$7dJYm=iML9v;QwQU2L#(MQ7Nh2nt;Jp;+L(0xNGVJ1%DO+Tn3?>3IIa|ZMA z`y=YkF|y(Xz~|=e-&XfFBs{WYCBfdJY@|)*Dc#BA;JIs70N;8Yt_`3wDS&LXDX{fF z6cBW1myh8lN8r^+G8M6G+gbKYM8{dm*(7Nsz)`m_vn=~T85v3D#%Y^}F_ z%{1uB$*~T3L&k&?2ZY`wXqEzM>wru=K{dw&L_Ec`p;MwzlavtcEfpeky3BvN7SmvQ zcmYu)Wi4b?4|d7pDeM83MPjG6NXjNEORL7pqf z6pE0NzN~(mNx|2Vae)oy#DzF15KH&IszhtHE#|w z5q{SuAtN?Hc2ogA`R=xMiCO_f(^t#>9P(=Mo9eX(Irl72S3R)R8QWFLG!62<)}k*5 z?Ywv|4cxW+6xkIPMPb)SVf_`YOT|E@a_e_&!*27PyGgC5l6N2`pGn_M3vU2a_kgfb zq=;I^Haf*@!W+h8fPDn^ysp|u`u`f!tZM{1L-K015-vY0XTd4%K+{`Hi|To2`a6)V zt(2Sy0HrgnJ<;+ej@~CI4i9drK~G=0Bss9cO-WXAvdZo@nUO-){}qMliSb)5v$ zu$vv-Z^Mg-Xe1Ho0@Ednz+%oe)*F74<%9iy@~XbuPJoytQ^&!>I_+(Kl(Fx3LG~O< z{WFR|yKK<`$;O8$J|dPgZ7J3BG}pBpdEm8mF`c5H90oO3N*!>5g;1^@`s_jH-|{Ep zebRJ8r0zURxjOnNI?`2Df1SQnXG;UiJ{_d@;APPv7nkc7w{e|b8YpNyhF>ayBZbT- z>9O^?m$yan#2Ed&JO4q#8c<$+XB^kI++A4=-JpVN|qzWzJYmD-%J_{TxNl!*8 zjSd>DZ=cB)5*do1d9aJg8QhiFX}DoycG5<+3a{2w7C(^K8JZD-CZ_A_T zafVK+fbdzQ@KMYX{E_bZ=zhF(dr?8zu4B*=f;0YFL}9`^0J>{J>A)w4|BLbzs`DBx?Zure){B>*G)%W zcU(Vn>f1;Dg)I&hsVQrphi~nFT5d7$`wqBNHW^*R)q5tJHT@a89lNS4* zm)y?1h#=jP*2=0&SB;skJg-$&r`1Dub1bAiCf~y4KSt#nU-CaK!lN7cw<_X{X-+8T z*%3+llcD&mYbH{>JI1i6`J%^-SY-RwJ9i&TZN&}r1XyfA;uI{}P zU23kow>^)p-Tq15#@J-$v{V(?E~3A-JlWFmNF91-crV;+wBJ=#(N7lC^2+bP-3PB# zTQ0Vqj6GVfKZ+*wTpO``rgwjeeZZUVc6m4PsoItqREL+<*U?vd$gq8*zV6$`M)&%9 zSv;XET)U;@W?>QY^xwbxqY~Z~@-r^^?G&_NAS}aTqD0-ePB#OcAgh&akao98J&Z@l zRN>*Bv1f!SH8+d>g6r#4+M^YqXgZJVp*Hi!P!a`PG<3aLgl@I2uWOb!y4#jRC~ddC zI@EY{H5!7%`-yojHH%(A z)!E6}K<`8GmJrR8B~vmQr{{uXEZPE3ym%umbN84rS3&%0ub`bEyA-z3pT_ zND=#l0-u z>q2~Tdc~O}alsZ@3r9Jb0?3)gWY2UuFQS|-#Rq;-FkvE=htn}gR zRmMXK$9j8?X`l$Uw#L0bt|)W7Lh8`WKDKENcWZZb?Y6Ies7w1_6D8-z zI5rErE`*S?Zr{ten?~YEOnyL?3J(BwD1NE^As+GkZ?%S*oXcD2WlTkP+;MnV&c}Z! z%fr5s)~q|<{5K78fWyczit4eO9VVsM@YH@~LG(&xK^M#CHN?Bg6>YSFa@kBPV%@Nh zy3&(T9_J)AYs-7?O!evSv!PB~(=;aI3r@Oe$t-Aquk{c*(1HE9nL5E1z6f?^LO|17 z5|3GfhkMb1+UM%CCaEn~(n?ChG_&dzpgz=`JY(&%@tq*}JRO#BsT%Wv-XobFZ!q{2 ztHL#uLWaq(XtUusrEnTF><1!ty&8ANjVVt91dax;my}NiOa4%b((Al;NU15@8cJ7S!=_oz(yuH$K<*dt}QXxh! z<6({5Z9z)6*@`skmQYJLZd#PNtA}5Eexg!0(%;vna|IS3A;=?lx!5mCvT6(p_8Vq~ z97BbjD+$N0vmp*IOyD-T8IU)DhEdbB{De|%%u;hchUM?tsKbOz_Vo^nJ68}11C-om z%f9vb=z{Z-wC)0+-mZN`7ZWv8hyLE^qrw*~UT(PBM7o{D}w+LY7 zSRZ@6SMDdv1)5Vs5y%%)1#gyT@SR_K?J-)KC;P5w{x)c&i{r%wj=qqs%OclZXkNlA}#8Q`M^=?6Nn8rTyBALO@csd%_x?=V686=-oyu1@ zP)c|)6k@h@JvNg3E^SNg1X@xN%(d%nl#LO}>{#U$Y0+saL-RdukD8#KmKl)bWU!@a z4lLAIMvEbd`tpYJB7{>Y{(RR<1~P|)2p)+M&EyAJWE3;0-KJKxP+6ywTX?OWcykWtZqH>{!TgldORC#uQX8nYvsb69um07v|B@nT8LgK*m+^(e%x5 zwM)nw@0*tfZoPrcgl+unB}=*+1?~RMRN9To;&gQpK$avV!-)Gqsv8prlYFah^mjU5 z|7M#&vP^OJgtH*J1TgXVqweh=l+7MsWRqaEyQddc(QTHajYVXjKmLAWeydM#J+giSBDsP;I z{65ZxJ?d2qkymNI2;o+eItZ2JY0$gXaFcx12jRy>G>rc(8y^#E^IqtrM4g!VX^?x` zdJ1)$w`g$DGQ=A;$s1pUL&cLEb;&`(eVffd4P1w>Xh1`HI@$){)kAx3kq$e2sMNy& z|2o!zb(qRNG{v7HMsuF>Iz#D>c0@W|@mG_kRR+X>hMnX~91qw*ASRUzYyV>FeG#(G zAk8sxp#y53zBW1c3}SeSm%+#*h&vqHw+ao^@VP^)D=+%(zo zy~vKvQ4*JWm&kW~8SP0j?gJV1p_z3~ zD^5r_Z|Q|_yoG72vI$_QZ}KtC@jE`9uoqPC7?#(t2C8zWf|vQ&%s%Z;bUm|MA*XX8 z)9~%m%363IxMqe`C>+egW6@@Ai}@(mTG^B;S>wdzx_h2WTM5Qw)1%P?UA-{e6iPe^ z5Cv5@3orbaID^HFp z`!VIC%>!acs;UbZDnb4hP(Rb(COC1~jgin?Ec}KzswsNtQ6PKJc9VuUOoR~sXcdvi_ahZl$ZEL=Dw(fQ>ZL>cTt+|q@1 zpBi=}A1FmZcqGLD36UKLBM=YHGZX_PJY+HqO?G-{AUDZ#29ps0f^$l3*jG8E8-Giz z1fdRaF#W8#D%_XKKYg2olA4ltGYypR$3u>@ruAhccK2HX)5+4@q|1%;+5qyW_Ir8PTg8upGJzFU>M zqErkrA$}y(MEa!;e_ESR!~Z$1dFs?)i!M({6gQJWEpCTvw+F<=Z`%q&`T>Id@ERf@ zP8qnZl0tz@DMm;>%Cg!9&F6Ik*gN0=jj6auCENiZ(R?VKgusy%_4pz8sL0VVyi_5o z@pFtO5K$U-@{lxgorIWP!^duc@<<6RzVfW!o4i z9kL>td9auS8y$ms(o}d#(AB+)<4QN(m|k!BiXj#*D;%t-665A-v+RZvaWq=eP}_Y` zXt?QDd?<^oYCLtROzNmg(U{MbqzA*$KVvijAPj~+-YJw2>(U<5gA9NEE<0&ePqMg; z-}#z3ss~g5K#0Y5Tk2^!Nh>?(DoP7cylDWPktR~)f;GI0yfMpG@Vu@|rj zr6#rdS>5xROH7SEg68DIsbm2A3y?5Bh1t#zU5Os)tHkw@X$@g)UXQX%`0*bETn$jR zf3msk?Ffec`&{;Umw0mc3iR zOQSfvYm)f3P+dsQbu+@m$euv-slC132L5FpW{x0ftMmopB;@_9B{S8lpOV{forL94 zJeIpP!VQRPMdLbNEn-Hn(?IpaPnjQqY77-?1__a#(ERhsUhL7!tbzuJ4iFycMqEmlnGcTYDn= z9Ra<)et3wFOQxY6o67G^)nJFA?c^-?-I&fwTnAHkpiVEgs^T+Et*SY#{`cDUQmch5 z^}#enTot&CR{e&I)dCqC5Wt;6%sLZu8vst8qKxpNRE|<;?iM#8O3w<1?%XQgVu&ls zBqj$Qx>EhPYpQORuQx1jxpu|z+%4QB89O?~y{WFXz0%X93_I~dvtm8x4vEj3OW^@i z+&bmtdvf%uu#PL;ddp6!Gz&3buv$l&1R~SfWidPqZ~D6D6Vhs>T11ogmi}F%v|o!r z)kUdY^AAb3(0f;J?-2u4^&UNV&CGjEtF<+=qH@$5<`uiLA?I$Hd7M1{qOt+>;KBY! zkuy`8ZRFruU3DF$gxD11WTl2gYus0P#pH89C*$lb0#rnT(Mj`tT`^cgO)m3Ol?=q3 z=~YIqyDkOxOVRp3!zTQ4H+cv)r)ka6u%k?@y^}W)GVEiCi%WJC-}2D>pbmCq*1x57 zyia<#&qb97j$IAI?w(fCR=hVwzPC1Q+ynx*ku@V!z*e*ndaA(9OoBBT^gAo04k5e5IIEdrQ~NnMs`mZ@S?hC=4EYO}xHnnOVrvAJ! zCe#EoHKrpqV(>EOY#;dn3>Sg8b%0DDjcE;(DR3rySI8(^VT{Qz@hV4cAkq{vgL11pJxbQJKj7zw zcjk<$t~22Om=)u_$8QVyb9}W$yc_`dN=?Jv{KSEQDQ^lNzC_*jjrQPn?=xliByry66<8Tl}2Y9cVACyc*27@$`q_$cU zpguEM{=Yg7qG~#sDsEF6>spvLt+@LSm7tyaqoY^ypaqLeY?Td`2UKh1kPW{mok&r0 z10Woec=wt7i&ew9bCVE06gQjoL;v;pU?04l>2;e{YH>?`2xxhBIeU^Bd9y;W z$L{j$N_ZGAWnk3P(;ESp#&#Sf{!>ewuE|nA`KRnIeHAhNRQCk~lSk`NGv)SlBGSV%{)LtajFiKs zXYTl*gRuqw_vH09aDk3xW8MAF-iU(hws{_tL4wKul1tr`r+}c4j;lLYTApu->-NH# z%(m{`EA2u&vr%U9_lhIR_PYB&!*-ke-U)Qf_}?#?+EvAQM%HJ%eL+(Wd9$naCl+*i zn$N78AKsazE!V01YW2aL6KmAMtuLnE-`W4|hXs)|pzg4}?9S5Y%=*>m$JmgYDZkc( zUSIhZYGwPVP@}-UFWgk|&HAG|#ZK4l<78kxZc|q0X0or(zkgSf=30o3oOpBKb5AJ$ zk^qJ_>LR77EziF4l(zw*#BMhH45c2X$)qx9$M?RqKKa*^fmIT9>lLqu)I}FmX7oueAmU@i&{Agu6CTfWCoQpsY!?0f1_UrFxwb4E7(EgAt|tB zi{h6>>NN>3?dqb~5Zj+RW{0!avK}EEes5-aq3i-m_E?D-eEA(oZSDaTr-kop@YTrfCE=wsCzFY=mkxI>JqS|#yhKsv zW!?M(=gaZ|yY1Hk(zSYYck|lHQF^BqTWzOVvDJ&C$mO zRqB_`6OTP4f0jmu*v@EN`Y}+Pryid28T)d;>Y*W$ksSWQv|pz>Fa1}Dl2Jk#Fl3+Y zPyAkr)%HcE7}WW`Wxo?~yybnXS!A0U$napT;!#E0M6>-2a6Q@uSJS8UoT#w#CpG;? zOEu&nVsRzkj^98Xw0$M4&I7+GtwjY9Mbp#T#D4--?qX(y59;M5gsrE#KkLV6^6Mz-SAY|YC8YA<(&(#*tWQI4^ z(X1OO&Z!#KJ;K=& zsf@}$H2|{QbKAAM2#}eyIisFl-se!!B9FW3tgUVICWu{C@KhN{Fk#Es&&6lk*h^Wq zW-)yw7|J#FaD3#-RjYL}9D~k?IuCS&`H&H35~W-$xZRmV zh1mDW$I)Z@hU^}Dz$FblJ{-H!CoG=JXm@vZ%m1^8@?0n6X>nQDL7fZW&ZdInv5T4? z6>e-w#rvB6-EQ|wnknRAwUq~_l|7$#xD9dD!HE=dm-ab7u$8}Hp?64hfrhytUd zq&%(%GO-bDP-SJlMnjYH-pSdTR3yt4ycTYCo54cPg{S{#O5 zWZzcJ8T3c^6BrP!Z?$JXE?-TET90j&e6rPH$3$ z+;Abb_|IZN{+DxLED@PF00qv{LNT!;{CXGihBjS z#&h*{Zhm!I4JA7{582sa3Ae6OLul`P8_oZr)qH8s|8<(;Gv?F2t9D^8OyYWr&Y#K{ zse6t6de+r${la*pkd?CAx&FXQi8d5Z$DRD|sQv2cjD%UxIB7^0zO-66&_&99D|HRG z+$pbU{4*fmxl$f>IY&53c}e*%DpLQ!n`k!u!V9;{knzAJQ>C?T9Do5TW-Z}Gr zDemEukAIye?Tv!#gYsHq7|$Q1K5@6&D~(`xBI3+hnlBmrN3lReil=kr$o)o5VE-=i zzdP(Hy0=!bPsX<*mck#V46V~d)}pRb-n~8$)rtS;9V~Y#Ut71o6pHd!KX$oZj&2-} zmkWNIaJcX1g~8NKZ1X0x^L`NIUzt92ML6N{dw>mho8rj6>+QAnL*@AVoZdP#-=$M=_U92X z9HO6Y9Q0f9^5HfzERqMJG#;cBG(&G6aay^e?^P^DEHfb4{vdUWxY?QWt(CHEyAEG) zH3C~2p=FP2^f9sXOwFIn)!GBzT&WLiT?0kX4O2uyrr%qh;v@>hrz7S8@C}~4j|*ai zr2VOzK9+$@U8ny^+xhPMjw9srBUkKcj8Gv5^>N0um@PHuj5D56EUj^$WSeXX!k zQymr@rQQ9P`m~Ol zAuSC!vda<#Emv*8G5RG3m+LArldMLXSyN8Hd-c!%T5WOqrlYVzOB%n}nMMzt^8;y7J z(@fYB2cApc>B6Tr|HN$ghtAF%wI#vtv>tbf_oR%$XNj5DDzBd?tjH?V`Ocs{^aIHz zBF5NKAs{7Flo+3yPW*s3G@#O;j+9$h5R-NK1uJ>qMY09}`voc@tHp8dvJ`tKv%t;% zza!D#`u0BZ12u>=uJg2eq~Uta4obt4G@|~o?*USe2+}D>4Md0wT{4e+K|?IWpby9y z0KUHkvC64YbT9mlgwN~+aq%~lP0ud#VaGqAtA{I}u5Zt4k}4CT06#C@>@7-lge{H1 zhpApC!mrH?D;qFK8`R*CLgnvVsE%lVgR^R?G(0LsK{|>!!#y(cK%XQ8&+$UPa09&h z>+%-s3ZB*N36f3%C?K*CFR8i(G{jf7{7xYF6;<;iRo5}X@H+<{$(F)|2MzMH<9@MT z%ZTIm;}aq|5GVoGY@M)4kx!?=SpaEUHe{NF?(#u;2THh(AQBZk2Ec4FQzs3tg>5R1eFH*?or>Yur) z0=%M_0qux~8|q-qI^i`#mt#b*bd#)VzRZR?qE%$`ii`M1zwqs?r3)WafJA7d1$pXS zKS#N)v_e>8K;4nqb&{GE{i-bUgjrQ6G2CY^2=jEW^cy6cOO*BYkzvtc8?>E=3kj`; zzBAG&BRuSB6VwtQ{Zv(H30eI>O8TTw^BYgW9Ux7m!g#bJ&Wz9no)}A_%PsmK&TVks zxiL}`;d?r54H+bUA&g;}62p^;tdgVg&WBK{onADrf%%-rN~{ zR#pdLy-2d)Dz5Vs4yGu*q9T6s6uvScOzI;h2U1D8+{b_<;z_aUm<6KEnIfqPHbOKc z_ushPvakA*@D52Nd)Nkv2sVuHFtQNAe&KzN8bucX5Z7W9Hn+&nQ-f-|L4DMq55kiY z>cWdBg%PwG6BH)DR^L%st7PBqGg1M|B=mRgHnx1nlu^fw(Seu=l> ze+o|7fG;rMUx#!PO;Cp)5>zo-YW^nPKA>8X`w|1bNZqQY?2%6c&lCOSQ)6J0@Yh7u zFoVXOz1vLP(987gU|)p8>xfykd#DnRU%?>vRh_jj4>srsKGMh;4_8GY*51JtBM^{_ ze!8oOPYIF-YA%atWGK-gPy0pfmNZU92<9|m4v1> z;?t_D+x{3-pCDKN*uow^)i!bJXl`?ck7EBcw@W0FCF`ga0YSYb5+I;|MbS2M)5oX7 zE~)|%^K|%^Az1PSzmKbeMI+?+2InNF=Zulk#Mp(Ha9@1@%4mvo32$eyt__b=;MJx!_ z_jWgm+1_8cF!2z)4rTcqARe7J_j*G@|G0^q1CQ<*G5Ilc+9DVBm*Ziit?KIcqb9Hx1&$gCf#6dszgJGyrk_yuY@tX~uXGQ;|?t9z`dc~QXABDd`7Mi?u z*d(5qorM1N5w{sVmO42E?|&ebM}u7oz)q}~_X&e0{zK%R3>HwY{bc0q3#KR;kNoA9 z#`&q35Z=E*!9P)>TAslF5*ZJVrb%VMDl$f%YP{bN!X5`WWqj9=RE?!w9bL-cs ze{f19Lb*a;o5|l3Ca?B&*lT%qPvfvV6FU18+A_{tP9) z%N5aOGH-!PsgiY$s3RoSa^6gmD4j)Aq7M&p|ms}(#>2u?-MW_-r6QCHcnU*4 zurVY|K$6=}SE`l`#F%{j$M)Wf1mI8y;tu?RGgd};?slUe;#UfY)#N{T~&I%^Zb)Ty3Zp$^9d+R zy6c(WN)yq_SAp2IrmZh`C~o*mlbZfG$2gr$(9xRGyD*?+-}Gn8ezyRrzyFExy~kBw z9h%EbgHAJS1B#^Dt6SdtmKDuiET8_{{xnvO{CD5#IueMq_$P+x1WMZA>2fOSPNg+2 zFuW{G(Nnet4A)mG7MA|pA=jO*p*iiQg{pDHiIa7VqnccD(OWKZrGsXtoQq|4^)QCb z^w{}ii)qHMS6aO#J7`6-z+q0GmZSJhqBYmBzh>8i(9QW3+Gv{PZI7>Q_YDvi0u|mm zy&aD9xM%S=N9K!f>~JYP!x853AoD{&W+SzaO1wI{dQs;Jb}ulaEe*n|uH6$G3bnCPF{d zc3z(T_k*DaFkD9O)X!%r=AnNdIxaPvg}sb>|L2rws=HuEsJJWl$+?-vhCpBKtN*1A zN*CQa^zq->&0pWYeg63Iyco^q_f{lz0`<#JE%rmoRQ}yBc#_e=BI-koT11Y}31=4+nj*cn3ZzOqMP zjp)=u>2C8cEonGZL#mE7IkrWTd9=Y$z2!1k`tW8_~5f+MnT8NPVNsq^L^Ve zI^cSp=ZaQDmR@g;k3jX%60!u3U*cwLv8a&AhoEH@Egf=A~oKm7}7VSzU*&ZIJF2jZUAKGMbm)Ou9SHesta;-c#w4bn6Gm%F<@Piq~mAP?dyz;U2{I-DP*39I2`t_Ix z`|C2jZJ`<7y-)h}HIJ*eTwBOa=1s}JetTB`Mr@4my~PDla(ZEhnzZabuJn#9a_)by zD%sVv8wcKgmvyESe2P=L#OQdki>(x*MnN8#!@1z!=csx|Hhre18AYFEVV%w#dY|+e zjTVJzt|X_oh6I-X+ec(z~8aVKZ~7miLT9gwCb`m4tUwjfp3%v0vk=t=nV-C;8E` z=u~pPH&s%0#DlH$d`(Rc8lS;t1GldBb?5VVsvBI0F+Lje>1%b$%O|BeYw?Jr31Gx$&nIrm#rm!n|YtmDxst|KsRB!;)~n zK7fNDprPUhRK&dv_d)}4;HccWDp1Rj8P0H2APDBfky)v^Dl029Ei3B>;?_({%ghQ# zW@V*jWz&cM^PV?wT{ri+&VA13+wZ*8AoX`>DWNwGik~kl@R0z@z0K!3_f)&nX{73b z_7^*707ybN2=hr?=hG0<^lnn^#~Q93W4yPsWlrr&wWsq3i_)WPkX*3SlfSK7M1wU{ z;W;~NGW;8`6s;0droSM-okhv{+>SXr)qT);UQlepPt~>;^;q}5FCkXnQv9fU8PC`1 zeQr3Sw$WkW(#M3l^(+K(DXJ4D>u3b{=4bQ+a^I9HQ&TE^{yD+TfYIacH|h@VB7F0}vw`ZJAd0+rTfHDlHO zVFzr7=H1g4o7BZzXJV9yljNt6B(DK`(f+>{Crjf)95m#MVA~c$;dUpE?&i=QH^IAY zhSY2HOfJkWrF92hoM9Xmul<*1@uBK&#m!a<*(YZ|WSquzxVs>{tMh*8LlVe`PiEZq zJVgQBUavlU_!$x;m^*$U65{+AN-%(;b!$Hukd7A<)6b;;JhKWzrA3 zn-JnpyT0iNmdxskHSk+i;M=po5Vos2Sg#69alM^P8(X&n%5^rCjkUnc5qoCy$KWYTo@jmApYANF>Dt6hj3ezW;y+ zqWiqV5^yZ_`;v+d!g_!6B0ti;6!~CDBQ2i{*DD19;c-S+f{UeEGAGOAQrz@UB_Fqx zc3cZpS_A0s@nfOk$I1;xP=40_osf2cTry%s>v}lMNW_67$;}}tbFxja9#B9_G+~X$ zbq1L+++8#6S)QdwuvVW5|wC2<9U6893++?_r2b?6dz#*D>DiXoLez*1F{EqEz9_~OMh8(hsFNa01AW8L-| z{kszEt^fJm3#A%E`}*O8dCXZsJ^ety-vQ}5aXMY|d|&tIuJ?gIVOuj%VMB5KxXRZv zI9{%juzmo4R$e-=*;Qe$S1yVyUl0>&jcUgA86zi7X^(3uHvmWm)7K7sDP zoA7uy9h6v$@n*Al$UzBBYU0*_i*iA2(OfiU+WCZQ6jr8eZjZJ*z1LX33>>6OLOENhg${*(W;Am^3kD^wR5O~>3lCFUm^%>dKNl(R@yyOQVuQ|0Mq6e=4vm4BjPym z3`i7K(mX$3IgqWff=DAs2G)~oLW@6Puc1YpoNBb4Z!R%3Zx^qg*OI#{H1E}KF1k%} z>mD~1$vL={ecQ_llrhdt90y>#&Y}&W#{js%07La^PBzm02py7bXt!MlhV0_xgmQ~R zYepJRud2C+V1eo)paM*CE1aXm&0xw$ecJj zhYHIxhFN09!6qGfc!p&D0*u`PbTTByk|7cG;0|6#wMi~v1^mt*M(X&lln)H6=KAOK zCTKeh0mNDPAP^&~K59GU{yHuhCNP`&R+9A~=cMlOSy5Z7nCS=fI0>Pgx;|4PY- zMPT5qfrDh`bPLn7P4d~-Jn1aQTrtp!Z5mfYa+{|-_laR`fs{DNIDPAtO(`=n|JmKQ|p z^kYb3BZr5udAmZZl+swbaTOGp`HgMh3_g_3lYD4Ws4HdxXZP@&>dhaoaE6z`9prLfrdMu`bzqY z<1bUturOe(2%6KvO`+tuF)fsx9x(YFrU)v=9>wGCxh=qe&1;!02HBRFx8ZK{)?-=Y z(4;~1?p!FXntNiJTc5(EVvAxnxjEC&<1M=qoSHwawj;MFdGlAe>4*#855dd{+!NxW z^{btg2!4Lj9tqian+OEx|Hf-;~c)I=hOKd6F^~{5jSg-`}z+wbrsh=gNTj0 z%beyu*pQUb-MtUykS*a%#oKyR+kRPueq?hGkWWH#5!bb$k^=c-fD1tsQ-ge9R9v4A z8QN8L;ZlIxJ~}j~Oa6Ep6nqnEv{-@$h+)x&dz+T=_P0JSa*v8tvD{YOE{T*?p6px5 zUhQkze2&Un=<8N!3PSJ6JTN)`(M%IG+gLta+7L4i(wu_Gq~)S%kYgfb;crWieCV+@ z4stp_VVO&BgP7NYvp1n$f6m|x>kea?=eLYh+wSiX8?33A;GxF+RsZPE9ul?R%AdXPBHIvZj+}nN)cg#{#fu=C-w>&7 zlI9HNnXaAa-_Wd0=!YO~iXSwW$7T*bqa!ZO`(8TA<0c^*{VJhTdUomM&_u=)vQjFR* zqdM~@55LOBLaC$qrOSv7C1^6TY}(uK6|>qH37yX3reL8NGf=tL^x4AS1^e9f0H2nlUh$=LOLX)79 zcR3W0gd>?dSq#nMy-NQ8?&8ZvSzaV~U+~H2hRnQH+U(AR=^kn1q;;{!--ErqgPx>F zY)j(mEJ#IELyz&~ybqfh;PyE)fJ%V5T{b6`SH=7>)HDZdHQ4>F*VO6}S3H|wv*iFC z*Kw-^uzw3U;Edb|J^3s$G?fPJ@`9GU1-c{dD49d&Y%p5kz!?6MbmU&|M(&qi?F59~ zM$lZsJua1|F(w3hi=qy#&L8CI4N9QW$Jyg|*~{L~pGk91#6f)sK>I4_v3$W){Bdy#NZ5}6B3|-Voac+yo3=njiFZX3AJ51 zWL}1wjCesMlu5qk(l$Hhl%EE@7|$d~BC8)O+&w^+v^jMFlt$-j)-F(8J@X!Yj}^G3SrlmA*yhp$|eO!yrrsaQ~oo z)Hvf@i({=}uGL$gtCiB2F35{K?o{xl%z8*O0+W`%Gp%hYgZAb&tp=~dO=VomtcRxY z>Ys-K5!a#Ov4dkKWk+G=eo4@Ri>;cRb1AE)Q$_9{`$~G%z=tRi)2`6{0M?GTkv#;+ z76?@A2l5CV%9e%@{J;A#ptS9Bo(=kv?PU8`VTrAA?uVYY@p~QC_ zC}kO%AqsVAVuR$l3DdV2J-~1AP|G~Tz)uW@dh$2i;gST)q>G)=#ZBWysIOk56Ck)a z#KvE-i3>UfJCIH12Ekb3L5|b^5WOmO$vFL(t*%@ofOWu+caSW49SC-Zv1!;r@OLk} z>JgeB=sTYoBMJ+o&3(oyskgD0U7=oa(oS(R*>p&xEaHvsodfl3FFM;~5T@S3neK(y zj7L6fzoe4nYCyP?L%w(IAC$)Do~Va7R>LD0=4Nj4PDr-++m6Aa^1{WouumW#_#MDb zCzn!wbB)JY-%3nUDd2A*V4HP2^UV*bp$k8w-=)#sd4oW@24AggiBb*}~QerDOs z$RS?d`=G_}YfWF(*v5R=t?%Zk75T+5ZZ>`Xs2`Np1y)(a)Aa_GaI6Dlhz*|^R{Z%< z-mL?EJ7NN0Q3a1OV3Jm}-1seH%L@^}xco(})i z*&N;o#3o-OaMd61JD&y4H3^2UT<sCJ8 zDCfZwFt+8F?!y^_A~4tX1a~r+OXH>1kGxRkr#jyNemisZ=&tjoJsd}vYRz>c(FN#< z6?J4AJ5Pfv7n`~q01c}Kdjr57S>VDYNhLlDEPy5um?oRnN!8~tnqcSEZ-p5ispDs8 z0I+#it{=iKmGh9N|+{1CH8;g>eml`W`*KOrE#ta}X4q|f*n)(%H4q#`1*o2lFnf5dHmzvz>(05CN z*?bkexJ3QkoCbrCtBjkwpsY3!TgX)6v$J?yKQi#AyiJEIFp#pL9GYW)4wH?9l#(To zVrFL>^s^qv^aHp7BB4GG3K(ZYZ=4j0ItvCt_46F><8#41;v=x{vkdp6H_*}-7-IUL zZ!75ZexSTA^HBZBd6^xxVGsrSr8VQvJI@x)Ye8vlg*PzJPg-iZ?>WZ^l&X9c%|{T0 zEk7x2oJ%0Z_1UN_`jK`hfmz-H%zMO5;=esX;7CN|DPd#h7(rsE9w*Az#R3`C88nqemo|5(bqlDw*kz}OeGJbiw+kIXh{dz-xn z+UJES_1)>MEe|VEe)GK;6u^R(mPwU9TMqiNuN~#7+>hnl*he<7$341#2ktSFzpH%a z)_^g`wYgyO)&0}kP3>{`678H{9S2-7jI2rvhDc_znX3QN$WkZck2oM7W9s_hP3hRxl}x z-g?3ACHt=N9dqmpvKS)~LzqFBzFFcj#sl~`e;ftL$`-)~3dy=_2$05?#iwu|vnk4$ zvpC?n$HOG8LN3D^&Zwk&n- z<^dp1KjTQQ(hJLhva)!vf}Hbue%E6cZl{p!zikdt>m*hL3au}9v@~4XE1m)|-Ru?) zO6yOAficfwtcFU7QJ2P)OU%J+&u?u_u!{4q!_8V&MNN;S*G{F4ojs;e3HH}7Ya0!C zoWJMVy^rlLuiyXDqjsZv?ZZKc-5i5;a-Ok zd>s31HWJ5fDs}V-zf&Y8W~mB#)8=2_?!dvL<;cg^EtU25Z(&q-4N}xEah-npHVLFn z`1M5FU-f~K(VlCfM=p!J1L5-2`mbg7Z2$>3X`^03Y)@(*O-7800()b3RenXNt~tnq zEWiIreI%Wdcdo=mq!cbRHc+jk%CwjUBYNFi*1p*oVGoRWY8`-`b^O`twg)~0?A?^3>S%0|`h1xi*Gk=0SL+ZHFvd*zhp`6t+bTKx9DqP*F{nDa)* z!g^QwEjK_Z>S^<)%DjEtEEH-c%@Qu9^CEC!XhZ5orB=F&cTs!9TVxfaUjR z0aH*mBJHPBO58l)^1TIWBHrWTGMZpV1p=Md%+iDKEj>iDw}-Sx0B92DsUv{v5Rqj0X6E)|c{=JZaijtUgS&K?Wol9lxpApA|N!c|L{GMCNF2R{N}Ev<1f$2v$dF9krO-m>kqSqt@A zLvMwias1&*KbNc3*b;qL2`k@R)seV<%W-CDs{JGXxy{$cW9*Bx6&-b5dcVtcfoujt zOZnS$Xc;*dYI$ZTRm0J3EvCb-_;GUwoW}){ zRxZW?U$O4+u2sjO&MSdC1EigoEK1@D(P~>OEuOc>fgfKKI0by>14lEevqX=hbQY9GeAt{n|8 zn@IRy4W)(qIy66GUk4V{-}e*8pMM=^_ibFl(JfjrvR9*etvzp+KN(fYUJG*#Xp?Ek zBeH@;5bApJg(Iul@V8Cd-sWF9XHpYwy=Qfgr*QRN^5{}5(FuC1?rBlAu9?w4)8-ss zi_)yYMklQTu5S3<;$!)~kri}L=gBfpTB{KA!7n0u=KJj~FEI3WKGfyc*OFws4&wcj z*KY<>yR(j8geAK|Voqmj+%FH8X@97&n4R{S&$ZS+&1-HQ zi=VsK^D!z`oC3kZZB|1ayUL^uHa?5Aj)s{KnU= z>YH@O{xB5x=nzFd6G9c}t$DBKRW1)!FC2vl#PA`wSvhFIW54D5Xl-j*87xWj54P;! z(nck+H{Nl`$s6=TA|DntulbFUCpm@H8`9|Go^JPm-Eu8*r6yi9upqsfS$me6Un%eI z%H4s>nm9H|auPo-uRWWCVAz6`Is0+>_tBbvLfz5v7M{i%{KE9jN!1IwE6O&N?vPK_ z-Aly+#9xv-eGPkAQ=5~sb+Q4NfWW!j`q;+(HdlI}jji>lqDIPyIM~;0b^X{Q?(R=O zFLR8P=0{Njhr*~$6R+R>XzO!WB0?h)mu{J@X&IXtotG_ZI(4LIA)_PFU+%|(M&vm% zvWtkbtT=<xs9>80_TKe4>Co_K42P;9OY#D0}y9gQoxK)DBb1$6s5m|TzUl17XP zV(i9@Zlqm5S$q3ejboSB!DGH{b#o~yF0*AFob?J!MeZsNHnVHpuZQ)H7wvZS@TWu3 z+57GRg?6LiF zfX%@|_0MfwmtPfIvgO0Su?rH{{N<`o9jGrMShSTp=K`HCe^^jY3l{{J^@Fa>3zash z(|Zn6FHuZe9CU6Ph2Onc=Qh`*X?gmt%Rhnaz2Uy=G!sOU#hOgUsE#Hp)6*(+W$zhh zvt1u3HAyw6dxOQS8o$pqD& z@adlpS_D6m)wo4X?(=B%w(`L*xz8iI@RE>0M&g+7*Hb}%gqW*X<`CbzYH8n>yAKzD zIxv+Ig+<2_niM>d}H>*hAO zO46lf0w#@Q2kw!sL~c$@d}qGAQwuW52ft4Yn+fX~Qc{rfm9W@5drpLde$9cS)0ws&RP)Cbg~DZ+aCYyX;8nDQsu=d!N=xd#e*-kEu(Z? zCjFI&y55bt!;*+r1{x0He1kgSK^R^H)y!9jFZwxt?!n&C9nFzm7T8@{ZXT@w1VF-+ zOu8`#nlw`)EfcX|S4@kH{{gn`BI{<@tHAtiu??`dfSvt^BL@zg(jR0U5pkDtfTiN?^ztCh4YVgn+j&e~) zNUWmR%=bbYC0)d#;6jklkMhhJOCrukq>esv=*_pEe~V-6cO}oe`DynuAdY{8cGWv$ znddn2Vub}#Gsk|UB2_WmLs!~ z^-^Iyr^8P5GKv zV|y8dL7_ERh(nNGRg1a3TvVG@@chM`mWu1BAe?WX4Fj0d4Dc1rIX`%`+FIC!khIi0 z=bRW@YY5Z2t%!(Z+6N69!|HW%&IyCrHyOiM5B&K}xwv;#{1Bs84MS|yK7OL(vBn}`|-Sl!r zy_d$+5CJu-RAmPxZpUd*r&%9mLBp06W&EKZu4j%HMCH8}QyRtM? z^@uT*q@dzm?-xO~%Ym8ADto(RXXQ_!MND-5Huxk!gC{(ToN%pdW}#1IZ9cV3yFBLr zgd^r0@wt`0q}lQ2MGdy-6$`)eD*k7WbJ|SF1her2@Wk=D<-F59>fCo}J@0S!1_l8! z6qDzCN!d8k&6^Q-gN;_&AiDaef>MI|@402Z z0z*sbzq-irV{fDj@pPfIFWi1oCM#wzd8R(a(xCHh;kcuml)bkMIk!1@8E5obk@Joo z(4brwYt?eeAVbS`ndHd7WK$Uy4)5I)?|c0p>8^1ChFG+z9s=t788U0338eBhz16ZNn2#e8RD()}{HNtbYkQoo}v3*Bufx~cjg zv`@DNZc2LQ*l-M0*K+zb*&zMO^hi&$cbFhPkZ-Sx&fhm-@`hyO#uAl-8CuA%kk z{l(t$w9pZ(`$p!YXo3`s7?h5q;*mw8Iqxk?jNXev9RQy4tALtSZ;eSQlX|ptB6sNl z%egsNfkynZ4jyU&-sDRZ8H3L^F06Ne@K}(Po3>mtgEC0jQ!Q{9C*cQKimtvgtFEDb z1+D_Zw10?{mj=NYhnP*cv3levLr4He4UG$(@yKQW-n1($)JE~^UffF*tgV@iKJH!6 zORybeIf$MSu%D1tSk$T+%>VI3c|Bpy{1lX*WGT^ zy!O=3b=-j!A6DAjcOiOX&zIU~p|aI<05JA0OM}n&QqIRUyBh;MF>t6u4EV1E^KA2Y zD(%?@d;N42WSC&r0spNMl# z%)7sKdSv~LYqbEgm2{m<3RQn`znAf0nq-W%g5xD{M3&3VLckYj?5L&m;ERc8C*Sn@ z%k=7h#RnYrz6PQC+bO+tHa(&tCYA907g+lDIqmXZDAM4()NMkFun>=K@~ZP78>WKs(+>mQBg2NvPAb;CQF@{Gt$ZeEvHaa^aVW z<*rk|vu26D0nQXs>l2`LOkV77Kc_z+yeSL)hoxO41fPVjxEkf|I1l5o_=MIpmm?ZXfbug8z>g&6}xe-}29#kV% zEP?tIkTY$UHRf^JW?uIiVD}Wr9`1V7Nw^2Nwj)x2#pPwCb{`a1?(pMf0ku18- zyL6u%Kj`ml-Gw%Ez3THh%&hYs`_|SE*S*&g-4e1%2Fpa_BD!#9)C zFjtq{qZ{gq!F>z8l`~SY{Hcd;*$T2?6C-x7e0u1UI{_q*WrzuLCw0qc@;9)|#$&b7 zr!hs%^lqm?l2RvW3N`#hy_axH=)}KnHf(Cl2Z=pq#~c;W-acf(kKQWZV{j7jUy(gI zIXHRNg_q?&Ue^8sgzpk=6|63}m+YPr5)nns&BDf0qXndr$J-_67$IX8xX3O!?hFgx z)!}4#?&uYj_w{)U$*5bsQWN(<_-9e5;ye2&#&6T?OJu-!utw#+qlpWc8MVBSJa_!$ z1BT5-a^+qp+S!);$%Kwj@>`Mh*7=CIT>Pu3lhx6Fcn+ZD9R+AR<|A&O3HNKqxZ zPNoi3yL;_7C!JbYj)30#SwF^-z2Wpscx7?sB!cP=!=}peuUBPFqS{#l375% zS0taf|6$hZ>%RL(yTV4U7H+A6qzpD|9n&SgG=Kux$xA2f&HEPO*7r_kx$kh*_%v4A zox^$j?eFQu{r1O2<@|j`q^ILYRhel*?&Fuzr|k`g3XkS&bT4eQ{JTm`dSn0GsO8h4 zOPp&Xrce=WZv_8~kI99Tu?_5#W>STkzCe|7!`bfZ% zHjUm%zqDkXG|Zk%)^YmJ_sqMtOi`I}odQToo|E{{Np>i!*WdrXer=Azu%Va@9yV5u zkRG|w1JmJXx48{pFg;biW!Z?P%jY*`EqS?HM+_cw^(t$(y?4`Ca2WJi=;Au8~0kF2(M4RhA6&$a?&M%=Ybhz?!VVvgF3BX@M{R zLl29sYgjqM)rcvuUp}whGp@hubl2L&x)iv#bbfGz-pRUjKL=@}3-r~4nkgR=3ZR5x zsg$dG-o!(M;g9U!Y0^by?l&(o{8(z0_S%Itp04m)9O|56xn>E%-8 zr%U&FFJ0Wl>%3}Y5Ts$fGri{II}Jx-V^b}?``9~;BXeiC=c+=}mddP| z8x#JE)H;*(@2+9f#yl|Vmd|LzGfdWNK|j2T849^({iy607BSe=lK0okqEvdUZ6?HbRq5IpuU`)f{avOZvlXn-g z&IkmSh}hDjp;3F?t37HIJZ0ktK^neU8n!F)vT6zXkak`uer%0@wU?s&j&U}*SF1R? zJDR-xCa2W&;LXeycy37fg8KVVPbXKSH1Kcl2=l&MnU{-w4?F>F7Z0vR_({O|sS>hc z4AOPjRpGz(rwK~_&z_z*Aq*s-$~N&~$zYG?VV> z(q^$`b5WNlL-%6^ms244aj|)Om5DMHY>NUnDJIbLsuLvHcz!NY*yg6tQ$KQF#D|~8 zE#X{=-Urv$Tpnc&2GePI#K9=!0Nh>kyL$~^7sJQOxajHwVjaDHXbmk3YHW*h|GZtZwyah>^f-6(X?sHs^5fS0!Q;dmDC zkmUwxox*(dd_45`<()>8lgrAJ{VeTqpkf=v-Cz~KK_aJ&FvagYbcR8=t@=jPW4eb` zD3z10)eKu29B{afz0t~{UM(zFcBQMtLr$gvz z8n9Vg<1#7{6twTx6B$7f2I)xk4b3+_{r%Rk@&^j^gZV{itxi+?i{EnlpQv0e3ccd^ zQ55!Rv7KLdx5x9&l{5XuJ!QSTKAnH(*l{=Kt50`H9C+1M4RX4?)xFki<{XP+XmAkA-typK!Dpja`Cd$#SuOl!nUpu`a?uM*;`w$a9_QIsvg@S0+Q z-z5j9JPTZlgyY6stJ-=!B&DC|q^hXpaRdrG$w{fux@I-uz*YKy_0(7qf@Ba2!B^wF zWPJTgb99@G<;{=>%i&r)Jo=PFL1$ei>YbkF-Hz^FW_d$Rlh>yOjXqGz?w6)PfsN%| zIZMo{Bge!S*(#P1^wLOYSX+Iv9#S~=ZTXQh<2yQD>AWab^^l)-9KkKDKq&z<5 z*C^>X6R6iH>KF{6EY}C^Wgcy&kPg>p1_aGA=qZE%V{r zgPV^k4*N*W&grw^>X`gl;` z^xL%&|Iz4uuQDTkP87X&a89i|bKuR{C%>vXOy2xC9NuLA?Cy1e)nr3);sOI|vgzTn z>y!rbzd!GHsQjKD+Lv+b`~#!F*HSaJ(ZxrLNdIwP_dD?$8nL&ImCX7JjUQSdXp?GR zf^&ylRs|L+77`k9M%I9+mdf@M6O3tv7$){80S;+Vj|Qu-Wmi=QaPnzY`!6vvww} zo)u>tU-Iky{u7fzhU(vHuGE@KTK{U;W7m=2G=QS-HQiC7%2}U330UQ40?cYd)-qMy z@104{^?!dJ|D)Y_Z@IcYSPI&K0Fw~k@S~{Nxx=E1y4STl+<1}^t0g6uP`O&0N!vF@ zZ@@lK(B)!S(M*oyEUPli7gL^Ruk%JD%*PBa6#BfgkaekIQW#5Fmd9v<$Ir0wE_aujntYS|+bHA+IT~pyt2fJ2I#}v7#^k7dN5s7dCG@ zp}0d{i8S%gy3BjjZ)jJth`glaf76Rj7y^`*a6TEwO#CKKNXC~9{=4z#0}NKxD)X~N zA$wGbDw;1xs1A&&xR-q@w^*(AN1b1jlb3mU(PEhAZEa&+?MK?}_NBbaN=H>bCF79~lugEBJj$uefUWiHFVG~GGK z+5Ti#@>s#zAkQ`K3KfOsiay8>W|TdiWT-W1$)!Oy^e3dQy2&0fg!G#o&XtGto5{Uf zMq0=zN+R?e%JnWU>dZ}`wp-|hjjO~y@yeA)|HMh@Qi$sOx^m9O)AT>337$1xgk)eOn3*h>nE4OuQsD(%z&suKiJwX-OBC6 zh8H`{^i?V`Ed^=N*kIyqSkQc}Ul*xAW}IgURqf(0Yx5B)}}r5 zNrFaxl*TYqJ;rmVx_%ZNi%N_#l%8y%6VyI8nC5C5inLI@?Yoa&giTU38hbRJ2@-uj zp>xJdpFK5`jncO5AZaA|CYLJ$jkR4})yEsu**gusR{F3u9DY=~>pU@gZPwUo5@h-D}I{MV)pN z=~@-Zd+$s|)NTc>Y=~QdM2&T(`Z_^=g>SoZP*S`x`CVr=#q8rfx7Q){keFUG3IjZe zC5I3}|Cm(fC0#8r9Qys-zEevqv-s73bS`4PDp=$OtoE~K)J`(+h*$9Z@tL8VVEd$_PB86u_&1t6Wb!+{fzO!@y zG=KoIt|UD-(EU~f4G^^!tQdt*h^_&;W!k#X{#cD4v6|nN*B;$?s7<>ycD3h|C__=p zJAg{sYOh@Rbl@>*A%t&hsq%(Kk!&4tL7YBQUJq%R!;K1LdG2Ki1hrKv#^r0oyEV^K z8{u2UuR_-YM4j&3BasU>nWWS~@28g-Yneo!EQ?!;M*|~2PDlwmM+k~u&Xew^IuZ`2 zXKz28`RSB5gYp7qrXIk*sxAxX@Z=#t^zAvdb|#W9zJLh|XXnt}b81~$XkV(&Pu67> z4yKEVaMNk#XE$;EZ?irQZ}4Jcg$%4sp20LmGsV~jA}AW zJkwlk6)UB#vUt0EPxgqN`(1~CuHfu5&pm7H=tD1p52a?_|CW1bYc=WB-I~1Mx|6DY zeLq6p;_9v)B|H1oKRQ~%ARG%*hRqVf2j(<48#EfeDHeho+7 z+sDgGYvuzbSM<*>%@-cR>2`&xV~C)KM9op8(Q9pub)uRzVECYW>Ag-EpMOBQ=fYi(<5*A(wQ5WtGgdH{a|O~yJevNJCfOE| znz`?En%6+E?(?nM@+S*ND*U!p|6&edP- zt^cN_9{Nplw%)bwo?7pm=ej^8T)S-{3Nt*1Zf#KOVPQ6JKysNHlT<%rPmO0xjjje! z4FG~61zi!Khl$3$4NT_<)}7Rg&PcZZ?S#Uudh|0bLSm1@q`qVw@R1nQ?rBh)q+%%$ zTYXoY2zabVU^(4)qZRm@hoV2yQmd4-)a-CD-j zssG%kWJiIh&pSVUnECwqp7i2(HL^g3ERg+`m~&IN;RRJM0dOoC0ClOZQi`ZATyz>_ zs>$XXB3`sLHEOgspoiZEJ8HQ(?$KSDQ+pzT!N;KLN71%=av`F&)EM{s%?4hRgnEW|c01$eDP*(sSLzteonFf@z zS{*=G09MkEuM*xztr1C=w<{Jba`4Vnkt zr_B)(aN54MZHE&~RfwN}8te6s`2_JX!RS+W@BvreXeocMf>P!@Uu%t4NMudiu$_7M z>AypM4}W4SL&85c8C7qy>d3Kcz5<~<&hMh4rv;dQR5Y?UBK9G*mNNe7UdSYcun08h zs8Tm4#$zx~K2fUbi6GOh2DLgMoKM;RAMxq_sZWPGrzN*E$iR#WhH3$%?7u|Kf?O~e zD@mr}8>z;MJ+hn4!EHdqa=olVyd-B1vqVKi{?q?VRVGsuXpQ@8>ZL~sGRB$KlZmlP zjjkNx;z*rmT3n3J312VHwlSurDQLNnqGoMV{6}IkJWnGAxaqT^w-L%B^HH}Y)F|~! zUj!(K3RYKe%V6x>z4VV`dqM1lH#-b=MTH9OZUn-y_yR)OI!(v36iX`jW1q4>;>x-= z`bxDod6gTGuA9D3zVPUr;r`n(UKKiH=gqT!!NV&q`8DdKYAc67iJPeLjUBF>Q8a#f z)$`geN$HL&fm^3sZlzo}8@w`oEAHu)y(71;MchU(>z}HcL)(8M`v))!F`WRaKfF(&pz=OY86jCuXBb@nAE+!8e8aAu4@wWs!8=ja^2CN?bpVu!5&@N zUobYhg}<-;{Azgq>YnpfklQ(5HUKB5P50xy7q%obx}s1y&TTgAa z_JX@B1~oX`?6LdR9O%wcU*iuFHb$*>J8yOz^p^24%R^>7=8f;%@g2AR*deV9Hj!oh ziw)A-5LxZql12m9N-u6bcK)&W^onD; z(i#Gh*+mMKIq16}qmQ@ltn{UHHb2=ja4b(LsK5NqRCw26W#wCY;yV>X{`;&H7!YdX z)Y|bdXvXH#}XQ98gWlq{i-)R_pUCaally zfRXQJ19xvZJ`(GbGA4ie6y+)s^+z7`l~ekSM<};;+P7`OAFEJH5YsUFBGyd|G9NtfQ~hwOzJAM}LyR z*V&3uX|Es)qyr%+Bk;tQ^9Od)LeQ%cN2x0n!!>RdT=hJasLkC9RB&{Gb^*M7*v_F! zvHBLaw)(M^5gYVQ$B2(CDYEx%8hf(yQmQPrZHgv!%7~;yvi=E^icp3}%#T>VNPH@j zvD?Ez&E;c@#d*)Bo2=ah8r#2?+UrJElsZOIT7DYShT{Wjr$6Nf$Sn0PBji~1pv6Sp7Ig{n}4+iLgA%3uo3A5Yt&9@8++Dn=Z|iRzPP7t zpeP&;4`x{_z3-J?9hW_UU_}MW7j`AAn^MAj!rp|3L{xoi?eP0($S^68IGIwBNE|=h zf2CeRuZ!Of`)EYV#NOd_UXyC~$dl>~ubmb^L{d%lyv}nFHjjnJdD4#)_xodIj5rAEz$=o{j%(QS^QeoVd1? zsf3usRnrL|Iq{yV(@N^CHa?G~cx60~CXS$)#QJ-O1MT@u`THL5_MJr4Ksp4aS%wmj z0v&%N;hY>75TN;+|9FQf)F9Lko>=!(4%tnVJGQz|Q0HAsYOX9zA|xm6m>IAY$CzaB z<~2U#6YVx9WNf}|qbHwL^vt(&TKfxv4n@?ElGvp?&}*7MSGo4H4xQ;iYXzJ2T)cW- z`Ikpcj&>&}T_zhiqrKvcDav`rjWri+T9ZxnH~}6-kk~oM3VKQ!Z4n1KVMNr5VqfW- z`|c7_lt)Zw!>QZ$=DVJjl{8a@tNL_KT|cDkbJ6&)8k7{*ljb#kQ7>}O*4@!>f%OTi zEgxpy?~LvmxDx*Div8V&2Wc&;Ih6@IHk%F9rOVv-%INJLtx(%GDG!5Pt$Gz3vCd<_ zk|df?9rH43*S)xN+g){w&ODWJ8=bbC)%Dc;Oj&sR8aY556k^h>PnxdUTen1gGfTVA z*?U(ImXy|nI-LT8S52VZnvu!e0N6B8MbB8 z+yA5JUi_KTB;U>4 zsiq_qa!(?cR4TRKet*HX4<36v@7H<0E;?e?^^xw4-|8t3Kry#%`0QOlGN+(avz=|Y z=(E>Sv#YH!7mUYT#J`pNb3DM=@k7R@sy>~?DHJuB$|dVAc3Ndn41WW2j!jTQKamI3 z$J%mRC~DwU@mc#R?q^tR@5%VzHF)EW(bHGZ{uXu^yx9sprz@h?AM{;OKSey9(;HI* zf8%87raYe9ttYs^n-O=SWYGjKr4OrT;MJ7eIG+^$_1bJb0^s9L79&+B`DoXE=CshO zjwXfufK#{AY?@R&v@ms(ka~%e<>1ppCtRATEJ4A?#O*!Kargh97#S5}q|CQ9EOZ&?d|eX1Q0lcgr3 zJDPL7A_(o-=H{>aA}R(Mu!{k+t95z6XO&tX0Nm(e1Z$P6|1wuAgDtsd^h{UzEn@h< zx+}Hy1|)~8Hu|o}XiK*En)yh1N*$QNfLMA0Kf0BPLVC=zJJjvFbP(F5i@Y#TV4 zr&hvciQeECAunRk>t3(bQ6I7nu6c=>$c~Bs=SVSJuU*a4e_#3JUADA`@#ivm*u4lrmn)Ru|#2x|KD=zA@ZlRXonrjGS$F`Fi7X{b?z zZ?2|py+Mc7p}a4vM=#rZaZ>`;ilZFyZO@TY3$>TrRTE#yyt6ZhJL z@=p%(3p&M6CAl|Na1tVa8Iyd&RY3Iwe+(wMfJyZ|5NMbdv7Sses;0y63}fDah2|B&_vR3B3_iHuQSQPPa+L^vYHXaq zkb1qHG!l^%o6jE)0-Z7lQcFi}kReT8phlefnx^3aAZQbaOyFQFaD1X($V${zOA06x zfc%L=G#Ce6WFmgdnUcd1zi^236p$JQhE{RjomBhjsas4j7C0}c#u4PsAtF7(aKxir zoDiuuzhMFmy-D8gAlH3LUbfHhz#)F%C~}YeY$GU2k`VA6|}=#(;? z=dIjOU1|)=J|_Q$(e;H zyTEA2;3#M5o0xtH(+ln%P#V!V`mD5vH7$Vn^Cs8tr{jiO%oWFI>bsM@B_*Lh6Nfmk zQF7iI1NNLL^i(p|vWN~m=@!RPUndI3)k0sQk$X6Jy0lbz2yzuAl!X?IKP6*SEtqlu zaf1o1Bx1jlGXx(AHR6OG;f_pk1e@}N)*F@Ls>|z8uta@$4OyrWrGq>nz|0V;AtUzk z${HC$S*|h>4k4`;C&>)8z|T(fXX~4(YjEG*TM6hiP(vg(q{^{ z{emU{pe=KVC#&GIk41|0BfoFKxi`06@Nh{)2@_hjg(RIXEOEP~ zcuG-58f0mD-a15k2jvchTb)BEioX+Ux*Ch+SjE>e z%g&#UcEOzKyMSC~CZCCuwCTTbLeutqI?Z0PY0)6dIq+tRjD*vpn`IZ>PeDos!<)`G zp0v9_Gf2CcPb>NStNB#g;ms`v(oXSyHNrRY`W6Fu>l13|HFC){)^QGgF9P`u#k-W& zHV&-Qb-*my`GDJlj<`X%?g5x#A*Cz>HGQVgU#9j?fW}Xh%3oLb7YW$Ri1v>;)WUn1 z+P6e51IeA^yzq+E&X~Cm+FXWvUuG+b)?d3n$W~UE;|Hi3HcFAusk$+UK z@lPNvE{b8uuxsuJ84+;O?K^)@hW>SB@G1_rkNQ6Hf^0L8FY`#BILO7hf+J$5l-(M+ z0Hoymqu&JYbNw?ZLjWqz%_&3&i@dS=%TOJwz4Uq;@inh?O;d@W?Dm(0OP2**w^jH0 zWo7{cwb|YGlTkhd1byEwUYTobm1queJbX8^sd%IdBhhpyT6FCfS|#eHdfClK!p%oC zo6k8k2TpalHqsi`B<}yw5mCEJ7-Wov9=59nuaHr%o+8#!h~g&jCk|qiNSx&$-WWSy z=D^nh$Q@Ga*J=bcNE}NP?q7YzkL;gbI#n>WP$$tK`j44yko#N zh=}MpRgnSs2I;?T24Xl5{*`$z%pS2p6t*_;xP0WrrhdCUKHTs_T-zEm}h>Z9$mu18$U&cXhe`#S5eT8eGkn!9=G-4wU z_LmK+;l12`&xR|4Usm+xm%(Q|gXqXl31ce;5u-du5d`YkK1U-+eV z_sdN;0pt0XCO{4s7Hd%rzJU^|;|Nk+1uBw6u>f!xqr8L+;rr`yiV3Yj2~qPjJY2^S z^DmW^IjHgRyI;od32}^0jK|yo6X*B?aS)F@zR=%@EP$Nw=*v@Y(NZZ%9&6*+3VvSU zbln!RvKk6Io20dkRCxX(|3Io93xs6~P;r6N_U%&T5|g7QC!VuqA`|Yr!P!qas*|ckH^4Y z&8|r)@kks~qiLXl1?k zFzIeKdrx+Le>uPFp7TxO_Mw3TFCJ8WcyQ@`=&$$ep$VU$mp#v4_9^I5dKGm<`i8S7 z5c88SCynk{nxw=XRg?@${3&giGBKDvtR*YhAN zsc--2K6O>5)?N}FQwYN4DgASNKYj4zu0qJod|A$n#1K4jv*UzZ|C83gVpoBghPDzf z;FrQ_V!Lqhk;)m9@af2tNhxk(iwZN?@EMKm`7onYuEN*E2(i9hgBdTk_n%p>4cioF zD`qsRJl5J?B>npE6ZUaYSHe7J(c(o^^9K?5u_cD{hk=!}P}5Xw&Qc3};n3wJ$7geS zYfE`%%~eGnYg$cynjicBE)#P+OceBVi10rc-oAqOKY0>x}~_eW3{>KyZPhl=3dq2@1D*5+0B3d zHUUaoeAZk1=eEGtwx+8-dd+-xJv(zrGpJzflhC;>l=bAK)i(6pnq}2ACGKNr$w&A` zlnheu^1*q}9tV`tcC+Qq_JaMp`jP4?ehvUJjC*`UG+mf0ma})Ly$wExt0ww_nzrB{ zszXhHZ?un3YhAg6(3^?r`nI!k^*sP#5_wvEb2}t|M{@I!5mWdh3I29$=jGK^_3zN= zH-4G%Bl8$Ik^FsmR`STFbrWD%D=oA2Syzco0oP$snrZAL75>xP`DgXeL`jeOd>%Z! z_5IUi#g~cjk6ZA9ylG0?MT!lq$C;#wt@qgdHsqJ0a`+HI3 z=h%$&x)R7VSMsg%&+oUs`YVDOm`H%%eX*Qt0&vA6C9dZ-Xw*A~Y9W->{Ms z{w&$RBz0BeZDN5+SzWTQ6k^)g_aa%kTlyro!B#pxUHw6{`Y^BQ_l7d)H*(eBn4a*+ zk+mf>!fuEW{vqc14FyGL;rTGAzn67!}R1rdcrscJNrxwrj z#8R47obt0j_JkK0^0Dw&KDG~4@wWPJzLfXn$b_f*x!3<>$yTn+)Mldyl`+AW-Y8b- zgV7e^V&A0It~~5X{99L#OZRtswlQ<_Zn|&k=#!*RJ`OJ%i(B4)p{~uhNUiCtNiUGSh*@(T!n)St6lcfwvNWjB7Y2@3RgJ*0y&Hq2&W8kXuQw#&})w z;vph0u)NHQ^sBvA!ZGPlGo6D#v7<*F93++&@|yW~l!B)BAvA+8$Mb`ry&7b1xoJ8uC%QH!G|U=ui>66A$jD zCM+LN4__G8klCf_AkIXO8fkKDypx2V{@HnL)TTy)YTSzMlNSWz`fNmRxu)Lr!~Vl8$Re_vF-OsG*u8RYkz&~cVtavMfJG7 zy!H1E<${a$tDhUPV^SQHDBUK4G9N2s4=IwQS1Q#$X9PJ4ym1{Ii0FEEpdw}sh;guP z6S|ujlGAdhD!Nx%gdX}e{*ydQ;J8NV-<4Un?C1h_x_rb`lg2HQOZn5#;TVHG1zRy~ z+fY|-%?D#625_+4^Ie4PS{B##czWH7Q$dz%@S3ZF@=0H{9N>O_y*8p(gC5E6z7#&= zCv$C5%SiQY{C6WI5_#(L8?*8n30lB<#-{?>^*LYF?&_S;=&ch9162v0r*EqIx}Tw$ zq{UI4PX}u49=H|bWo0A~w$JkP?k6+wkzF>1sU2Tr=k^9vuTFNoHA+of41L=TUg?1J z+y@(xSrVMK+=Pc;Q*w`+!vVaO%YgNeN|h-Q2$s~V z8IJUpCvrytq7$7C#4cfP?Z?6@vm%_=t} z`7m;FQF75@lF%%_;|kyB&W|$YCuJEo%CJ*@_7!%#LN5?Z3Wmpi6+xDbjQ3U5EULGQ z75Zd!3Nw7lrs)n-0axdx2C#~42{U~56~ zF@KX?R4Fo`ju`B-Cu*FoRmV_M&i>U2F(>%JGg#j>ErOq83C-&DQ&GzLCES7L^{rxw zx?aVfu4~w~SCaBm%Cd7Ld2E=?>~o+Ee3Y@1&jP|t_60DGoxKK~4OJ^Qs#z~vmk$qfmy^o`*gC=fW?jnT6Pra3nhu4-CBxw^7Hxe` z$HEceQFuuXK3%2VCL0sXC&yg{n*f0Pikc~M!ovE|nz{TD=J>IZ2J|ai{2u#x>2BId$dz zymBTYJ1^_XME%So^zbuYLw(qsA8K;%p^5F~yo=GQ@?Qq@4Y=(OQ3LBcGF$^Fl3=rO z@ru7h*KGo(+b4(Qq`L6a%QG;n4IWmqazBANV4N~DJ7&SfW;$|?K9Yg@4J61Mz2L!kSyJHMAMcld4kwwqJ-MXCE|D!Fr2x)r`T z;YsZ8&@Uc`5!P_HaveC=t1SXc-@FdC(A3^D1Vs;V>EXB%Sx&ooB+Y%OT)jZptmI}e z4k%zsPliesA4>_JL&P%DE)3D3Y+W9U7l~DEO9zTpKuh-2VOF7lM@%#XaxFh zm0X*nzhOdRw@Ul;A?EKOO5OCRMu?)=!^mTlE35Pv0zKI)+oF^Xcqhv9G&`{A(bc(1 z4^m^X=~vSsfqd$FuX__Q(5twPE1Zm@_zKw}+SL;J^AOR1DSA>Iq5uk+tmcQK#4Vme z6#@Kld-Py5P@;5qX7kSDMMVZE7OfmGa0I zqW@VQUC?=2>p(pZ9CXEX?AdUexsdR#>~JPTsm?Ze2olj*aP&)Y^eR0NKu_AE8*S4% zROnatMC7YMF;kG(Mvx+bc~z6HlTLAA(6zhiNw`}j>F8t}J$8>}Q6w#K(bnU4o9mRi zc7qPK536Ocr0C-csP!MU-%5ZMkxGR z0$%Xex!lQnYNBL!E)T_|cd&uJxa&lgFnSfA#7LvD9!3&uux?MTp&-}hXd#@^s|1Lw z8U1SKP=c%2)x0!$mN03Ro`{x`C-xW!p5 zmUajIf@X6iF?ST7B~GGUMXAn>@!lBy^ph5qA#h%lLo$;d%dkRZ*l908&WLLibb`NB z3@2jgZ@se|v0}bsFY!iq!G2TX7#nXIyhPrN@5@s(Ga5mNLVoKGT_*=QmBF&ct4na4Gj(@(yw8h3XTriYvnAGz^!b` zBR7aX>w2gcO@#@(I|Q-W7mMJ~W65dSObQOw1~@ioTzupTIZYa)?ljR?3rLwpL(cO! zVkW;)iDcNto6#kQ9Nq{9?TcO^Vf!eQ%T0C{M!{`0knr5-lHqfix|pL5mxAfbEo?hHtnCZtma%wbW^ zw~Cu^s1^*6LXqHl$<5OE>ZT`|`B$dJPLBY6V>|xa=tNJwwjYbq=%rvVI;^mWq~sxV{z$p-AYI_mL9d5 z+N_y^ajlIb=lPMqF*wm}sF8 z9_~u-Wy{JFn&PD)0n*?AERRd&!sV9I(@pUL@wDKr25GM};0&^051gD%Cw8XD4uMpj zK|BejwLs8iD0uP=Fu0L(Lx%nX2M)r~Tu7krna3WBL+swG$zwo2Fp?5){BSnfi9BKX9SVv+u0hJWb`yb=^yJi*&k4ND#n z3(mbieM8ZC6R$T?$z`ebOSI6(Ud8`{o}C zJn=Vt=uu76qFE0Yy6_MZ%Sbh7NR4f@vl_SY-J{171mFaqC?NI05KV&l2I6fSgaK(V zRqI$U6FT`ti2_pnbRwF9PH`ysT@{vE9wOji*g5%WPJ{m`ghXDvn7nM-<3HS(B5p<3 z#!#+tPk#b04j_|2J1tipeO5VdIEfP2T zgnyvv%V&V%98h!|y~{}IK{UiM?v4a;FsX$0H`wWY3q2+;O`E*dP0oJM2o{}k6-B4T zkhl=OgVN^++D~T$(HN@M{`-2)NW$KvY&r!aP3Pjgr-;*L@S1_Yl4;~7@io`wUv$#c zQoz(CrPIv>UY?>y#QD07oxXQrqifmc zo{;nuO-+y%yKr8hdq9L$abeE8b)FKz$v*e~vzheZg}H-vB~qaTCEI%5S_yZKI!D2| zzDmH+FR#9fD*=nCo+%pG4&sMh%Ki6YUfde$ z{rRN*YO4yMq5H&j-*Ec1EpXQDfQzfkE(CX1&rD?rPm|M>0IyOLoN;X|-Y9OW{Hp4q}@M55|zM4EU7a+)N5RY5cy%2snA8rDKD zhgEHVoTL(XM;*C)W95N_BXrsR$%X*Jv!!+-J&r_=35LX>RuijLl&*-MctH>404@#T z0RpUu&P6p0$V~H_{wb;s=Yh?X`o+E43FQ#x__7KIw3-bfF_QHY#zPZ`;6UTCXf(uyxAiT4jHq0;mXT^1gozZqr7E!193 z^#Jf6?cy6BlWTq!^f-;-z|_1A3}(isN&xr=(O_`^h)1}GF;u-6`IkHDkB_=IGK@qm zua^pfE@L65hYTGacd&ARdH>ED+Gf>X$em&2NR+H3dZi(6AR-2Biz^h1vYX2%#RL-S zKR`i;2=c(AuBJ2~N{!BcdQIIaO}tw936sic0KwY*F;J=w5q+cOq|#BowgaK9OTb7{ zi*|b4WB9REtafk)_)jxr)IDc)1ag`2;pxm5?j9F>_4+T?Js|rKT_>aGDIebl3f+U4 z8(m^w2BoRl-1-UB9-Cax2Xy>sOu5NyArWl4(HoH*>a1vdWl&9T%0{FE4EH|9GCk`G zJ*_*RpRsspLAz(cc{dg?KvPXMkyZ+(NPps$={5rzVauK?uez)1Wj0dzeey^==P83zaQ>R{vsvsf#G>zEs6kqYbUDn zti-8s`4UEqE5D&D$OuY321t+l8O8!|7glDhL$oUPLx8wK z=Nv1b>Cl$1-+@99cAGl~Tf*Dyo8!NSy-9BqI%k<73bpy)0^T`b7Qj93Rna9N#ncsY`Z~k-tWOPfErGVFf#i^Ta9Cpjy=TwHh(0m$Od; zakl3z5`U=7UDIlh4-@Ju9KR=twVt(DrUya%H)qpSV7Dukt z4RpkLobtX{9x-cqUPpTXcVn|sMbV{sqS|8P12$r*>vFlJNORZFMe_c^ltbr?;S1~P zg|V0II+DIz4Qw56s(R+GZy>2(Yx;p}n~CYmZ&>F~SB%+wf0y?5F3np*Ye$zY=@MtQ zJK>*k4E~0A%<`v`;fK@uQz^&I6Z!y9iy!YvZ7uI>Mir)sD`j! zjI))<-Rc3ee}@fyuiiK5m#|@A4=4DxK`=sFWCzehgx0q97L!~fVOethmcWw0vhj8BA#;O`i3Q+>(cY!AX zdHm(#l7FuGG=HswgwCF{G@_u7`qEJ6@H>?I=XEh>A@Vlqh1G)QI~0-vErP+M)LCqk zpM9#XCZPtW?7_z~0VCtn0OF8~PUKbWf3y7h-jkBBTS6~2(T zdMHHA^5@V_2;Pyzb5~~qv_-MMD^B)T+C>?zn9rcZh9oi%34S#Hfu>#}YOaodytc&e zm8(YN^HenZWAW`^A&%4b!fKfCyH;_7+?Zp;*oA^F92>yE(rZ?`Yz@_ySyW2p)XCg9 z*Sm!;jj@c+E0!-Nw$6kJb5DM_^h5$k^I9qiFOu~^*RG+_5HOp*vCr=Xf0-q796M~m zM=N{fCS-5+D{pbL&X_VKILY0@q?^t)iM=S_c3M=s8*+u;+3M?5TQI)NsohJOqPv)5 zxiJBZeNS$#eQ6@=!;L&{#R%r)n-K|jjTf`c|6!N1tcRal?sP|*uIw%?9Q{bLn{q8%i z{C_QiiO$PDkuR+R%g)wP40mjhN2|&58#M$Nuh{UD=@liPNZX^Ue#+AB{NSEF$mOV$ zRpGok^S@JctKIzS1q{F8;vd@Of4$VpJT%mWw>FPq<;3_X%l+M>C2I4sQ|WYzm3J^| z1q$?|C{V?_lx zi7?6sR9d3ybvIIv`SP6fmiiIPYOsR;k?P%!T^rAkkqP+B30a{nz@^-evipwtlH zp88VW0ny3JH6g|XS2~e#TS#Vvj&&QNx>(dceijW@ETK{zc8gNh1TTWqreGDVi?SRN z&G7v;QdIFy*Ld*gxkEo%;;Z~EcX0xyKY(3dlQb-Rl17mCMf#K<1*tef@dp3=J_cgh zl4HLd;$MX$6H@WAFTLzd_>Z8oPmxX$UTLoL^ zT$jerIq`K~F@_6+3f~E}w#sU(Im4phqMM#Nd0?vr{fy?LqDlvw0&ez*_gv#L_~cd_ zT}5AuK=YPAH?~zCw0seM=kaPrK(v5|bP5a38z7K=LI;a91!|L0*>#252O9p>D_@xH zDE%3?;>1eW8-)Sors|B#7+!7});z@V z$AEbDqw~F$X+CbpK2jhx@fr>KB_Yo2EQs>y#S8nDb1s0e2aOY;N7vIXS6=Uk{inzY@APFIIgRru2S@`l>jG4!&FcHRc>etem$eb^!!2 z{yCshT%NnR(I<;KlY_Y4lk<370qiwt@N@R&KY@8$b9SGmwuLsvPLd^3h zxlEA;nc9Xgr(;(Alzw07J2K|CqTZjdka!T4Jqt#IMT8+%ng zHWX{)`>>R?m&I-Yf_Q*Mti%S5rurcrib7b+18#Is+f{SPm* zlK}&mDIU1y469DDg!T1K4`b)pn`%Jm3MZ31viCOG8%PO}N9TC4bEbMNwuT`Pn?MRVy4q-{#PZ9lnnbd^j?W9Tf5v&zhlHce0Nu694p(b6VMakB-+bQNa<4Ft4hI zW0~1rPTEsc%e!ksoyOeagc6QIm&f%nu!FEoHa<6-372zv{Bh+$-dWey}0F^xdHM6HE(Wxn;Pp zyyOS@*$kN>K0SW;RvnYYS+V)+XTeJ2-{w27tz_r%#*X4$nC|WHcND#qqKihN<^Y0I zXTtW2h5;^TlU1H&WN8j8c*%bli?V&V#rGL*d&+*~SODH@WuPf*z_dHd^5UIXeSfyT z2i}JjafXk;#}aaZHt$S_~U zi`ty~ysH*#cSeMmqP2AthV@lQ{bIgkb9yyzXu80$Zq`1^3EzGKp2wt5P_;A#Lxp%F z@K9JCS%HE7{TYm4IOJn}h0u6Ql)zToGVgXC0dV(EMrQeVnuES?{K-xL*LfHv=b!nNYt`MO2s1F`C zEocx2GD$sX5{K`uz?)$45?lG6nSBPUZ038vrz!L9y;L>kL8NQWFM)v1LmTf8j((a4 z8J%7f;z^&=Z1Y`cH3M&*PF?(~BbWptQc@WiEwWG@L8lb64v+!Sxhg8?Y}!%Fb@t&r zz^p{yUbRLerneSX@LpaS(lEl)m;__egIwwDTg)EdAqA*izDOP_IW$mK16|DiGIBs{vnDN3Fgl-Oucey#zm+E*t@m4 z0fobOp|5GGRvrM>2M~m%jQ?|oP1V=v3l`FD$MIY#65f%>H$4e3F4BJM)oMm;9f%0K zf0vv(fY)f%q2=MtN$jNdxy#?Fd`DF6HnTh?wSLlr?OI0_jZg{pPS&xs7)(oSnHBIOBM@@9(gR6p*PdVBzh@S$2(u#L7-4qC7q z=keI?Gj?-0jr6mYPX0pA1d88N&8B+O(d=>tzGEiBek(JT2G!ZJJ@^Js-Z=TyhpoL& zH99VH*Z0o-5wO*AzMDUUfBj7TyRwI069eBL zo8n8~|Lz`Io_u4ZiO`tlrK(?2Z1zhKRaX@FDl=rJO#6!eBem5Xm!m@NAeShRj&6je zt0VickK*p|-3gHH{=`*Qj><;k3}N>$bjaA}u)(U@ud+>hX}Jd_z`-(SqCft}?%Br@ z*Ui=Nx*zz^t~7K?wBv^qQ_NC!ua^SxumM*WWIj#B!axRUpaVq$NxC2dG~Te2efD;& zfvfH5FbPLUyKV`=GESord(3QqscIIiSylGzmm4O_$y}H19tnzLHbl)cEo(uEpT7<5 zo`G-irMH3%T6?wQ@DLF>wrNE}3H8V&_8DtXKo&?x=3ELX{C!yQzs3hnq&@xny||Ac zGlpnZsg0TVbYyXhbOF!z9pFyy7pE6#9Q(k))Udye-4!1 zT*J7Ab-!oHCDWc65RXStt>usJSA(rn^Q`g$MVs&%vSBGpAdALZ-qViQDA6ORA0^i8 zJLzieF#@HF)ZmLW3wNIB(;EaZJJNx-jvGDGn{MqyJ*-Nk6&x^Yb>!V{t6t{U-@{uw zjR&oRtatI&d8gvL@zz8~ve!!a>y3U_KbaIs-m4FqDNR3M?2jI@wy3JbCb)ZN7IozHZ`dVZ7*b zP<+~c&;1<3y3+@^1{uN8c7*Xz(P8$9o;1B90R%xym)4a3lCtws#mft+#Ch_83c_J; zF_dP1X}JfX=G&dzTr6s_{@@S&nX&)qMUuiVizNg%9=`X*T*t2Ctzgvuq7L22EAJ21 zobLdI)MjJ%sNS!S!o8|a&$BIe*`0iu*drK4sf?r2SI~PynOj|V$_o!xKkfQRwdzQ; zhJj$g*B?gWNlkD+q)PKRoQc(EatCBzX0;X4xnYSnf)isYlpGdbRoZ$c9 z*7XO3C1g4idV=3mt=9h;r+>_7>wfU=)xmr=MdeFv9igy}X}E{C=$>e5`zte>Ro#(P z4f*BmmD0`~yvm0Asz8J9^@z!GLf!6#}R@+G4S`i3zPU#6e&5@V7`4VQnWteVF1 zu9(e9KUF)IirchP;|(5v^z02IKipFb@lq{*LW;Ax_?)^i{WfN;=WK8In|bYU*O_{} z{rbTY6~wmy{HIuj$2iZnK#!-Aswmw2h=-1f$?6-~hLN<_-^P`5a5D$~OZ<7W;{JG0 zrTB^0-0W#=coD|`h@5Jv>185;d+dDByUwUDlQnXmvR)kTun(^&UqDD5@)74f`+?plag@78~im z-ccZ+@NU`z*>q6RZJ#!RMf;;!yi4$KQW~& z^5FBOVRK3*MJlq##@yQ|PXwZ{`bs9K%mVe%3`v@VLr|0QDVpWcOQw2N(f7i2o8Fwh zGV}ed{!taM{F-z?o&^~zVxbX7W@X{T!)w8P-=ahy(sKwTP5M2EkEXNhs)jNo61Q&4 zUTjQ8VFDd`45d5MucC~I0Ndlwr^T9~(%l+s+Mh}x&9RtW=_3h749HLIckk#m{jcst zbZ4Y#fQ>M`hI1775&5f~T{`ejNo>zu764hqNL5#}u_D#zB^zZ>WW(;zzH`FA#gSnuNJM1p(>zyt8z@ zw&gDrG%02CuWcnwIzee~%>-(h3Z$hf-wqkkurZJk(R679O0S!wn?YUTT^i4!kCZ&o z4ANR{r4@u^LzM~%7%5#8m)JB(`^ZXzTz*dA>tq77^z$qavB-=5mf9J4I zS#Rd#ei7-5nS80~6KkHg`IJ<*nIL%!RFp|T^|xjzMZ+Lg|wz-DW^M>Jj_q-sAaj!aH)WAw2sWXVaMmg{dFsqL(H>-`5=~p9H$|pNuR1 zqMN2xFxct^?e3EaCOoYUge;H(1zS;_0#9uJaZ^ex!avbS%Njap-~ zTU=|k-#pGSYE0s}q{aRdJzWUM{HlZbH0~`+>&CrIuATM?n9jReHCDT5KTCCGJon<^ zNLtGgmiAIUGPp=olkzac?QmCaVqHo{LVcb4#)ug@uU6?x=Z#AyA5Paor8JY?v|cjR z@ycQzQ`#fiT{?Snx_>0P%O?M8sD2k8CXXFfy$-wV4*^H-vgO0%o1^rEeZH4|?{t_C z^gh?(`|HKcp16p$b6?8O{r!6LzrWu%uL0$Wz{fvi=F#>&V2g8TSg+g+&-BqN;5W4B zmHZets6YkI)GUxC<~r@A-=Sp5?P%t`%Qr7xoYZ6{apXm2KV15a%mpuPa@`Mb=Q6ICte(q-e5&90e-zz&Jk#GF2k_7C z8@suWxy&_}XykrtbIBz%*NAE^6+&|ts?BW_nrqT+E=jqBN-EXdau=nd%KO5l44jo*Yitx?7zgHc+ctatWii4SKKR`ihbQwK*oAF_f@p1Mr@U~~V0behM?S)66< zuPl?Np9S^0LEr};!2h<+Nd5boDN#}fdFxURC=iUJvnrW1+czf8zI)7xR$JJw~S9geBi&BC-ARljW2jzg6HD zOgcrQRw{8+ZAK?}i_*x3Ew5nO(d;t(Cw1OMLo{!4ZYQJn+w7*V-49d+*Uk z$`3q`eZR_x?|f)N&k#qdhyt8skCD^qL@)X#l9VR-%dHuJ(g6sb@(qS(ibga|nb1H0 zz)cohH|d@xPB4L}J_x$_yeXqF){IQhcgMW4|?H@mNN@^cB%FsTYL?VuN z$SzkeaVn98bMhmB;>&8NHVTn6DnA5LsHJw<+$65TfXoy-yg1q29i-iZh9&o z;l!B2pWIE^g;N2EEzluuI4zGAxOAXoR3L}}Y~?dfz^RhC9THwtsoX$JUWHiOkU;qn zNhFFSX-AcWQ(;*vO7}=2bHbUW6&Q%SBw@y)^MdFNCbE+&X4fG-!G)LUp>mm0%QQ*C z8kR^!Jsd!Fr;Ay2NF-Aw)n?%3C)+q6VxzK@x4u+!hioTB?_7O6O^vuWNM58GO~fI) zY{krHP={#i3;XomR4BD|L~+lF(m*&ho&9Nend5jZx{&P)R8*W9RynDAZ&v;nOP&uW zuvHFCvq+ACL61V(9cL9cmF0c7px!!ScpV}zWUhTpZp~S*TPU@$)(`6;bZ`rF+LHvb z%+1yHf4fA|!xfF(WiCg<1p^eMhx8G=?m4aqU0JrYL$WLlru0&<;X5K-Ss~#=Lp*Dk zYK#&ct5gGxJe_V3?WUlOnV7wF=mH5C$lJb0nr=*m0rU7}PdXgXJa)@R0_9NGTn~s20{-Y`^W)#JGOl^%?ez#M( z%9E~P$)(Lm9VJVD6ScZKFH#yPM`?M#Ew=8st}&y#;|^FoGg#f z6Zz8Ce9%rF*o6eaD~m5t1hC{~%_Kl>pu%J*P|+>cqOXE@MwD`P?X(L^t~N0IY2MvM zXT3rZ#hf6Ryr}%%qC$gRzY}Ql=+~NiC5-MW*&8UH;+ga)7dpRI`sr>`9w>LM16z9=?n8&s_{6piv)FT5 z=Sb!^cmGp6sd@n6eK*$PaglfPT}!KtRo<(0#Sx+`$E4Zy;H%p{cfOcEeyx0(CIlu) zz0QZOYg^Cn7FmqP!Q#9&V&!T&q#OBX4f5CL?zint_d-cm4BezyoujMf(%BrZ_YkX- zB;llDAa_52WCC!C;McF=Y34})2|(b$HgiPd)`cx3=?9q(4W(-!8h?|GgYT2osV5=F zP6pMTd~=SzWi1`dTKO*v054PUWV(9yPLX2(NF`8A1i*|kfnOAde!8#&7+otq4X5C_ ze2``EXE>36HW)yf)jEshF^**iHc`F>K--07Z{r4HRw|$sULjZmoxKp!K z%K*@;Ol+L%Ew^sWDpRz3sdn>?wf=0aBagV%Q5u?N*jNRRgW$&LnL&=mubmyIj|)z0 zE!2i{MOJwh-7cDqOl%w7gBsXNSu5r>kty%;71LihGj3Q8*fFo11_X%yBE>v&(be?HT`Btpi3l9|Mojd7{IpPf@i4#4J&?WU)9 zPN@J80v9$!K{{?8zGSoKCRO@2@5qiiWE&4X#M4j0oVyD{hX_LyZw1m>fkI^!Z>>V7 zvt*JwWGj_rBUmzNEUDrf$W5N`g}9!t-J2w-SrzH#S@KOKDUtPuh5rpgn{3Dm{8C3X>dIYOq{_klOXa;a33@B!yD9s&?98wH7Ky!7u&}C*pEdxK_Fy~q#;EIye>fCe2_Iy zqOHaF{tY+*)a3(wOgb(#piJbEWcxbgN0bHfDmwJG3VH1y#yN_d5Ye1aHPJjM?@}&b z&SEup4h&FH&I*Mu6~dVg@}1Ot zBip@d!3q<~=J%BGUgZIT4(T`t9j|U#MTkmFxAYa|nn`7acB=TqEs=8{mEKSl`YI%T zsd?V*K_#)|yALY-1IgZ-*EZcNPf1r?n5pam-FSAx$VFLRj2~1OsE`;{ zR;rH8zF2l(ZOA^L8reuEc=*@64wR=WKbY&xyq}3EWyyPGIjoyKed50svwZlkB&CAz zH={|wAG>|kv^G8Yr0B%c5>ws{n#f0^4hI8~7N#tA2B$(nj(j_OiX^$|Ev?x3h*Ln= z86#WBBItp77aq@1zRA|ih?P=lx2P|Z>~J*|a<$5G+`v5tQf1p*I!i0$%2}>SY{}XR zIh&4i=W>JZ(ouW)prME46&}=v40}(xxUCB+mtD za#7`eXj+^k6a@0(A^(+ze{==3K@qk9AavM}zzJ8%ca1+!2l60)0I{7sq%jFJ=L34T z70Kp-mYH}gZ~IHD`kI;ab<2S;CWfqlsRmHafC%^idcjp~Po3hDGC}@_^$9@k4@f~# zTWOP}v;ayhaj$|AQ(YRY3OO%bBJrxCITjxX2ybEA}pM zSRSl2J)@X*jD55gImK1@6{z$jQ1MHJ@)k&mVs{6@Dt)ta#>z=7C_CUMOU?(-r2|v_ zGXm8{Eyd-E>FXjoVGiN^(KNTU6s^P~&6}AqlMU52UoL?A)lLCcj&01fsOJ zQ>jzgo!BV@ww}2>sOaL7r5*|^uTXM3t~Oz%^vFu*wt_s|W?HmTF)c9Fzf)ngL%Dpg zcAtNsIZDacdS;Ru+Irt%s6$aN;zQNH$kI;K1dCAg0p-Cb{!vyazL6hsM(N)S$;PO0 zi~Z1quy?LgPNY-#42oZ@9`{aXKe#MgK|tQ?n3wpcgjNw8EVGbRS6d1c{*=U+2YC?V z({_0FdDCZ7X4kFutYscvEScEAr*@xM-B=-7|J~%RU0rb%s0>9y?07IYK3;_{K;7fM zIZr^Y^SUFIW6bU=x0T6lmi)Y_EJb%e+yNOc2gwP!`70eV5gpR&T-PP06dfdeg)00| zicXcbVdcD1m)m+>zr>TRQ6^+-S?5>|-)#lU0bm2bVV>6ys@w-UrWESy+XUET;RdjF zpIa)#WDR7o=48;(?rbxe?(7cAD9J|Du#_OmwcmG95Bl7I#z4HL$B5=Ai1ldf@ zy`)LWe`?UQetmJQ+G((7t@hdzIytJmaR#kqk+A(H6LL}4rSPmi=R+ME#SSGr{gin- zdUroLa-!*emyF)tImy?nV|6n5WxA1TOAWg{Gk!cv6^y{XW<*?lk}Lq{Wc}GbB4+ZY zEiCxcq4&m7lbgUpKZwcC@$?b$RdlSI)z3JHo%m{xcX{Yf$5-!M^>gpOFs1x~*eR^k z)?f{)cUHMsZ6`@|?Xk2pz@<#D28o)yovd;_*Pc^!!E!Y2rPJ<}sk`}d0@DtN&W8{Q zH>-_|qG96?XwPm}``YFas}06oXYIE}UzzS1>0cJBTr=J3M~AIH1vC@!$pJ;fMow>Dp|JR;pX|i#nRoY_YS{@V(X46y z%-f|u(wCQ4<9<-C?1(jCvU>EK4@66dxrS-hF?L_DS^-*SqGmP^c8heEwT+OBQnhqL zzPbHwJTYW!ak71ER-~c*=ar(G(QNV=p4Se}oR#34O8Ap0mDJm<1I#jkx1 z`RN^nG@FX{p<_?m9XEgdu-8~f>PtpIlvc|!7)!kT6s|1>9kJiS?xSL}y$;H#jcdBK zh9Pt_nUDLu32#`q_@*Yf4z0^566n9U_LKxhcYMrDYom7eq;O8&_2pP5|I-a}r8nkC=G=0&B?3{vk zHq{Y!xG!{whzngvZ?c2+s9;8YY!yJXFR5b>Zz=BkV5`_%TrJV5KjhYa-0Q|U(c4}< z+FD}d3tw-&ZqT@)bNJ^MA984x)sj9&|2YX3tybMak~U6%eg2feA3ro#pXA>cQ<~k* z)>Tn&JY2z(-sB9cjy&w{3%EVD+CsBu zgp2~gPAr+m9@!_t{o091;xQ%U(?B*!of7w$b({eIGc!u6*2hrl zNn!fJp_)k@cXK;kLd{?q4d~Jg9ZG`)GlNq+#6gGSZ6)l!cAp*Ze|DBL9HHb3fIP&R zpb$Fr*?AineheyrO3uLDG{MMn1_CL>1E91Xgd!d&4h;lEMv)FNvw$5Z5PXwp1MVY> zJd2x&F{zCJ%d?O#SW&5#nl5T`c(`GG9zehYUn?2K)h={NSsDN*HvyV_w?q^ERiC!m zlKyEZ63(RTU1qRxWpqIEb7!BN&t$RP$>cMjT;KBmOT&`>2*>R}Mkyo7B$kMHCf--O zIRk;@qYEe*nqK4wKVPq$*&6&WTzhlpMCzElcWt=&DZH@X8)9imfLgAL<;7doAU|#Q z!jDa=r=cx8A4!H9UUfgU)qHQ;jIDKVZV-g4%96e7EJ{iIy&}dCkyW7 zNILJxdai7boBt^H>=6pxNVRe1(_!!X*cMYXBY8~~R_GrGDR>2v3{Wv~$gYPA1+#7A zB*`T+x74IH9G}CysM7?wSSWTY>)c)!h=}@q^X6;b-CQJH)4|$DN_|H+An{jzFFFaI zo%F|6?wPnNx{2CpBXnlQ`goneH#QLS^loYxJnfHbMRP-H5h{>zWh=i0?a08iCqR77%{aZq$BP>ise zP4Hc3Ta=MdJ6YWdJINU(p@EPH0tmB!2ejfAu&y*F6bpQZaX@0C1Tg)|YUy(lGZsZj zb7hEUqS|L8T$xNTwuv=FN2fIIqo{>GecP}vb6QQ|SLE5ZnZ*$#s5;Pyl5axFQ3Ayf z6mUSsMua%;_!%(2GpoPt&Fo;!9YgZZmit-fM@-PPsR^8t_3LBWvaU z4A!K{(DPca6`dt7`m<7Tz3It0jJBMJuAoQc2j2P$br$abX!wDbj41c#7UR?lww|eGLfqZ2tu5BxF z!B`)1-|daG_a`pZbab~u3-%`$vrAR)2M_Btj=hRMRX|JI^SJ2~ zgcfPR{bJ&d*x}Zjiac8#AOzW0boJY7uK#)Aey^fGA0UTp=}INBzH?Ysw{YXMU>{FJ zWD@3?A@YL_I#Gaxw2r1_dO(jcvES)C&i9vn=OOEn(5M96`(Z*;O~W=wOU_P?!aw?R zwQS#ni-~*qn3{}x+0i%m!imQ+n_4lyxY$7a@%R$#FCdFE!EQjDKDy}Mkd6I4in;s~ zcl#1<8m|X$Rs0W%Rijgqe6zR2bIycjuV{F#QE3}a?(N&xQj)H(_MbTCsGnPVVmzT_ zZZG$p@h)psm^}&HPZF`=0qjwIn^6ys)tpTfw1$j%!9*D06)kBnzaC{uI-(o!8pkvG zm?-a2ThaSoW*f*}B>8DyG;dqoi3U5Y8gqf>-B$}cS|nC}(?Smsd;V==8VP)4492R8 z6$qHnciXX>wTbqLaZW#Q4paz^f^==VkwHP;VFEa188hVz8ESUpMkpfb=Vh+s0BNyY3LJ^WGi0DbUrr}F_GHJQPahGbVqky^EvJIEob2Oov-{*j|@~RAld@7 zkRFRzR$Z2r#6J0abQ^y~Kn{;C0K0`=i5AQBT&x}X9Nx5WX3Xp=g?9Dr=j%xAoX>OF z8?#sW4=>%y!HULQ`8G?{=Aar9=$#^l2e?RK7Izr% zdPNdFbKZTU@cb)$)uT7(i4V>X=0M8Hm@z)uzRK=D8M3Ac_=JGt?-yuc?+i6~fV})m z3d%?Aqk)}-(@R9+wDjY=&c!(=N($FsI0I<+7nX|wC}3$qt+`SKY}Ve)iUldJK1R_% z{uLrl+Ba{{Bdhp;&W6u^fo9z`W;^WS{3^Jx zL)JMNLZ@4la3587JS_;WC{zYg>9P^DQy`k3fk|S5Xlu1t-J{YX|2cPkrbv2-NFT*U zqua6lQ;LtRLf6510i*td9Qy7r^vI9;u^kQmesUG`)2*v4eLQ+fM&x{TYn47G5FR09 zuH`CAQ5k3OL88wOK)(GrBVH^|AI%EQfE1A(B?L9Lay(I=m^+!b!eiVa!@SU90Dg?y z69@=N&U{(#rs5pdiDU4@eoT0%LpmQT;gQB7w3HQ>D+GJIT?4?w>EPL(C+Vm9dp@5 z=76i(mA5?4R$T!fnI}6n3EzTSMOc;5Sx;oN8v_xMWf(>%-LxC|jimXM!Com~Q*^G& z+h6bA*%~qtxm?O4e!qWcaA>ss3L3_hWVfpSxyC_eM=QgefCutLC$EGCBwlv&jWtjz z)oGz%SdWR=&3%|4crge45|2q2(2R)R+Y0K23=cm11%@UyJ?vOTg4xm7*{Y+vrES7J z5)%(P=79RHIA5CIpkXo5(Q5IM=#Cz^6)nhtm~Agv!! zw+9d5V0CqgMR#VYX!D1BL{FIJVVMPN$G!C@rH##%!-*|3weopaxd%M((NX@+`(pa?-Ro7^(K)cf8Q# zCPyO@YL$r#^@1b|djblTec-KOZ=88Q^m5ODzftMqe(#dCWejGBWD zpc#?54%_4sO8}YNN`XTm?-{r{HS-zZs=NnO>?S;(3okOiZj-bx-bhW0E_z$P+_sZ7 zbL(EWp3aH^j&dL=LolM6?#xI=O|lqsgL>kR#tKT}8>xKU6(%%6G9VL*4Q zzu?cj;wugOA@ktahqvL(xS8ICx>qK8d9ETOa9lNh2;}V^sxx%K_rBlbtFOePUJCx~ z&hQmr zf8C3qU5N)p8HhJJ2P^Lb`)5po@TN2hq>Kwbs|qwcHcb!wTz2hqC0BSy0m?F|*&Eru zNia9!NDncfDMkzP1NKxX6e4@?8g$c(qnmnWt3%Ml z`mu^FX9|N$&=&4-pGiH@jh#9GHue-ub96xL&ABfmB9juRiAR1Rv0wUet68`?4pft2 zKfY>z_nUIK3QCPUaE?Ftg}0mBg#IrMLo5WFt~wbOst85qbVIZp2dv3Oe&wItnm>F< zfQynmE}-lF7{!?K2PP@FWiB#tn*3hZ9C=ygY$eABB7YMc(-^czY8W zT!VQNC`!HnCT1(}d}!b<2y8FzDPtp$JGn+jbqZ!O7XkQ%53aW>_->3)BZ}+6y%eRr zl)_ES%iExaJ@WmluByrQuZ27EKlOcYu)jIDpWJ$}myIi2+)oB>%9)(~=XZ(a@Q66% z>>-@y_IC;svqj&(eQ$7vXWvD3TqdIiz;nU>Qgf|oU6xT>x9;aU{)0W5JN9+we(af~ zC~vTc#z@5c=hESKxnwgjkQNNTgJ73bdE;EsS(KDs+{@7l8`8xZdrz-)#09yia@X_{ z4npe3HtEErwO16Dg+szz@muKvHk{l zX+tt7^V^lXVQ*UxH36M$+%-5eeo|co>`)*sIi}KMfJJ1NT57iQs9EY95w0wFW<&`T zI-0>J(eIrvo`xLyg04UQ2DuQLdnhhqqih#`E*M zY$bK&=Cy>%@~o@GdD#raMFwqdG@;h-`K9BVnn4=7$Ms+JhqPW2@~53#=OOk#zrahW z(_`s3&W7_s9DTRyqq~w?K*jPY%kI7C+fDtSt~(2IvfPvTr=V+)3FmB z-lSD9D0#r{xvL@|U>z4u;rzScoYEGEL>j%hg*f8BWrs&vE>|B{^fKr!WmD(scU*I0 zBq5c(f;*`ar@maeNu+cIHYr$6T`{-H9kXS!)iWfsFMIxyR4_-SanfIb&dw!4oX~n|)_Jun{J_GnMpVr?t!HOY?FQDqojOfXgcCW|P|67aHfI}B>~8p* z4nmKn4QJq%1#Rg+Efgte@;#*Ezx0Jm$LrF29)&J7_el~e4F)-708hQ__?aA>CZ3wB z>EgNboU-u*006vW5EE|abVL=bdAkuO!?8IDr+~T*SEQ?&rp0&i_bkM9m}NKfYisv-i4eoc1C2H;P?I$+bNys+A@?H*?|4X0WdSS+!@RqfnCGrL;mz zzx+=O;=2h^GW*5$Oe(>h+5D)qvG~RU+)>zIA1Wn`99nNy;LetPRPvl9n6DOGIK3FG zB>2fgn6CqM^=8WO*4kdx9|gU!^;Jsqj>s$1)C&^dZ3{01^eXvxLMr}33V$#5n$M11 zh~m);ypafXRjuAQyoZ?fdnc*q6&F(E3rp*2skY%H(ImByLewSp&T?7fy1%Nh;niMC z08}Rz7o_x?({oK&rHY6PyYibeZ&8+mS6rkj6uUU?`BIU8dOX2R7>DQ4`#xdWh9@QBX^s`!x zFqRFwYu8pY`)UlaXE`6QIAyb%epTe3QP90SF{C!xGT+)3))*F~>wmCd&ZsS_A;QhB zZh0x(=VoU~WNL7qFT`*3!K8PhL(B!d3Ld09^qk3ZCGL-?kQ6pR$Mqp?mkR;W8(!&g zZ-F{#-mV(Nl6)TuU#hJwBKQV* zb!CH!Wl&k6#fx&miW}#$1105oLBz4zdI!aVyb~GsMaV#!ZevGY6dfYn6?yK08Ck={Mc9fBj%MwoAN2^!RaLloI7>&tH?^Hg{I5xPA*b(>_+;^X38`g8<{myQ9;R2#-o1-v#h|J2$!mR zC@mYQ=Xsx9_IJHtejqfk#Y7m@s;?$_8GX(_FGQ8uDlGIpCxvw6h47b^94FzIbPuZ> z6`YU@dYWWhN-Z&opL@N?hpU!0WBdsX%E~cWyvAsWNHdt6o)VNQEaaI)$P-`prH6e^ zes|>$T6&6>RMTA0lBrhls@wFF3vV?yf)O13XW3ul7af=}cA;jaglAJHLSxAxdh8ql@)C9g|ecL;>jnaY}A`kan~hchaNz30+2e*H@f zny8c@+FMKz3Ze3RQi4~UlXwyXMh>w?L18v?r?D^kzP@QFl_i1TOzP}3&j@G>{DRpeX^!ToYo-<3*xApNy zmSm_(ZF4@MDJzx1KKZg#AO%nfxzxN{V0lND6yAyiP;UcZ=O&nwBdAb_z?EgChO!TY zS?;nem#YOE(IC6I)GW<3sYR6?#WrGB3@L*gG7UoJ?*2-?krE2W&~1!r)1;an+Mi>| zA=A&2AqqJqnE;qj3*JpjKg$FuCUs0v#Ywd+^En$55A~>%CB?az{Yc~aY@If#gZPJs zcQH4b>O9+)Cgo_7?F-WQ!`99Q?Ul4@JlLf%2euqC|L31ga0D4u6ZA4b7d!D}zKvTw z$SVLTo=f$Qt5QqqkQ~+UA6JJ4+M3LP2!PFPr?fyQ)zHQKkPFLo?NI=W z_C2^Or@iR-+qeGgb{}&IQ}~CQLF%6t>aEpj^PWz{OW@LaeJKC{2``NZnb7PsJ>P6} za{m@L4X>I0E3MI9lVxAal&95WCHw!SI2GFA2l46C+5HbrIcKgqHgN{@DCc2+*!k%G zh76~9e`H|@_^OxF?R$>*>&?^ZRmf#G8RWJEm(Kg`T~T~?JdiFP0McVr$MKDC`wa?) zA!#aoecIaKZo{ERmM-1n(&UINqKnIUsM(F5mpTImRY*gFx#c}eL;Z&5`cocHoU-VS za7n2iZ0c7SfEL^)^tNse**kZh3n8}J4L?fFc^Tk3u{qRya36DO_`}k0!lna1!}Y-> z*J;b%{2@Dir4JMs?yoHd-{U@haCcx$ z&8e}Q4DEN;&*p)?2|WzAm0T8$q;{>7cEb;(Qja*vf%$S^mpj-eSM70!#snj&Lni{= z33=|a-&|&{xD!ubK3D8Oupc4ny5W}GNtl=KQeBlXZuL$hO1d8EhdeYQJ?=xnND8!j z^nzKa)r;=sKYqYNieZCno?nUX+YH^wypRJd z%)3RygCD&{{tNJ{{N`OPb+9(?;H|4;)iY`4ZSU&tr)SC^6#Fe>L546DEZpxy>Kh>D zrpQOtlhyYp_1)9&3{T>lAr|D4<&b(4C%^W{=NWBabJF|z5AOt34P&<&T+c}ba3c@? zw@HaTda%3awY@?>pTbnH?#r8}UlKH55v3#|f)OM00g2qI_+bq~XjUQ#;dyEB)-Bet zQ1(cqu;NqtpmMmXV(gAZq1<*>;wap=;t+uZPYh*8^*w(61Zl#9e6*T=XjDGw#~wK< zl$1+&;(M9jdNmpXdhbtTB@ZatzkELbE_Lc~*WcGS@&eZLroKtN?8nrrF(5%4=+KRW z@9&E_8x*CIGW{bhGaXqcCJfb(lS&BxL{n>tfP>n=`1`*)GX)q}aw${r>JsA#lboyx|d&j;2wlC{gEnRQB z{r(&)dV(!J&A~iGq%siZzSZQ#$8^$%R7&6t)Xk(Mw!_Sbjl!(M)xhQ98N2%-7H{U1 zb$fe`x+yJ`lk|>ey3Rhla!9rzZO1B0^>E!q*wI%*uDjALEwg3)n4o?y?NqTEvS1OFa%M`%3#|k3L481td(whz8w9fRg#F z3_Jgee2|mS3ZDoFU za8OzffdY?~{@5~`M&?B9CS>fRpWsE6tH-4~G(qkA8sbhMQ{n06Nl+^!M4ZIF#^S3l zEjg6E4_CZA^cXzcj_*W6teT*&j3FoTYu(D&r<$Ocro99v%Xw$fj#33HPN<|$w|NUp zc*=07P5UryF3+`n(F(N!(o^$}(y;SxhYudMf4S6iWCL#a=}O?`{IC`8mF+j5i;o4I zx%c^1bx5h(f4fS0m88SDdaH+StnAmbS8VN5oPf|LGS5z=`$UCvmLFx6T|FcU4WS`M zBH1+BrKA|ccuG_Pjcrp@CeXSC@~5-o`7K#ImJh^z=yUHYjO&C!o<9FS+g!7!BK4~VQnE|GW)valYjCs}kIyr`P zQYbtb(6kK7MCX8lfVmV(R0>i{Xo{ctM@%5RvdmrxzRgZl2{td=vD>UT)l_nab&Sf* z6OR*+*1HfDEr_|N2%9rm=xFfY_*yq%fOG`Gz#l&6~WlW}Tyj;u`r+W}CM=fO`emYfe1-&y%FTLrc=eEV=eB6{&Ssu6D1 ziAb41L^-ks_NASqXdICFCB#}|Q8$g2C3aJU&NyNR3X#fhxqEFnXRo;8BHZj{QZgw- zkh+KnZ_~(kdUckIIK^S#x(F|^-THGlAtrTe^htT!dDO6bYQpCCBZ&z^4;X`QPu6sV zM7~)0cyDW;w8h=!gjW}5dXE25m`*+K1y)~8Gd0chGlkPvGwpcbgk7hva%xXyvkkr3 zLjF4psY5D*9{0^UQHDrfgd0X@Nk0tsTU3kUfe3`G!w<6v_^-EfSRq15or3TkP2b0d zQ%B0^I_u|7A_++NZa>7~QHWDEJV}#I;i3K-6(us@&Wq46Ujnl>@m7|EeA)5`i66)d zl@S}OuIV!&Dm{e0rH7uL87jT`iaVs8j=xZR9CFnrtd4z$$WhZ9{80DSwMbFm_3_L6 z$LAlFIMmfIJ&&c&c^D*qU&?%cY3{$avMEDYVSH4`4tdE_^zfSaL)MX6rt84wh~gvf zQ>$_24_2m0ibm#v@^&`wo~Hg@eqJZD^ZB#05~mi!ZeF-(cTP}PAJdAy@+5J*^lxkp zD!b^ce#B(mkKvbo{>#5^>Ad`*`uU~8?@G6ZcXz_N>irKK*8P3|#JiHf{r3(XGzptl zbohA9iufaPw)^yTX}$NRk>k%?ar>7o+t$Clxf8tSaH`4H^7ONG+^#d0Ki3ytRPDcG zo%(gTiS_KqzYr}PF~#)rKuKMRvX0d?ODZhx)@#Z+%kNVX`9#h7CYx{ykJ3p(G*$|P z{mw#dQ`|Hz9cNWt+kv(IQcJxQ?IuYbvHFHiOY_&ykSNmCkLylXTjAS^x>~Q% zW>v77JJUzCQ*SUZ*566CHW(ugCD-bQp)Czl-*h)$U08et>LYV;H-tW0^jiKkXF zRIOhwZOfo___Pu0!_gUCY8!K1=ix@HoHX?hj3Na7WKT(&>2_24u;G+^n+!uZ;E_;n z%Hy(j{k)fsxJX{|niR1gNN2+>SD7~C|6DwKJa%|oJe1Nmxo|D+X5eqZbadZ5{J++B zS(o+NCS#6ArO3M?c0Cw$`V{r}Yr{>2huiD#?>rNL<(qhrDwE~-wE~@!iTj(5rDJxv z6gcgCCjarg6#Bh|KWk&+uA2h1(?s{S>}$#Pq*D6sHn`^T&t%egT(>uDxBOYWFt$EfNBu7t*j ze95J;z4LN19%J@9zwZ~BTCBnn>?JiXSoKLR*ojQw>kxPy%Z(~UOBZN{T!7I4M0MYe zst&Y%H^s*67cUFL#?dEkxrURNUF6sx#R?1%n(OS54pI?L~(ssFbsEh^M+(>Wdw_FWp!=ZlIGU z%e$B7GMS_Bvnk8Fuo{=Z$P@NY_?uFE(y0tpg{35fn1ZH;!J+Pm&%YcTH=}otS5t`5 zqPAjsMN}8x5tP2;b1QxzO1>J9`^9ijaGA@HbJ5c}9znNiWC=ukdC^jfeZ8iX=VC)) z%Q}|75T@&567g|e(&-fMBW?&Jx%#7G(;`V`C>nR<%F-@Yv%>PdHVbL75u=3J0jpUS z_C$3jMj!9`3!Y)MVz|p_+@BlcV`jA$ee?8|^NpX!oCX*B2U9-%I=s%i*|hN2<8*!f z4V@FQ&wM%!Oun7x>tFsnblhfl`9fg+gSbiJ8Ze5m#&;@G^w0YN5SECSQn<0t1$#LO zBZ+!;zt^c=x$auUZ<_9Hj4cOF_=MCFR_!SSEzn?rP52Pu`<|1?o-zlan1QS)gGEgaSX({+H`s;)P zHQo`?NDr>SoDLmOamEv9!A^W+rn)9Irzu)ekg90q-&XGEajs1AhEIL3Y6~Hq-tEC^q^RAltZEK?Mx1O@5ntK|K zb#EK|jC-4hBx54wh{LkKVP`HKGAO#d6tZx-wdefnwI_|cl~gj6#hwDs^+X#WxTOn$0M za7A}=s5pQi^yoQTg??tw z?)Ac%rmfpuxBoC!0^Z+r?&6{AvK1`V3hJN98DDLSi#8Z54}PKD+V}p;PC=CXd`D*r z#nQUK;^btM-}*x87mb$RWnm$^f28oYpSnITJ+->S)^b*yy)$3t8sq5tin+6&=>Wn3bf}WP60#xGgMYOZ? zGTC-t!ZqW9Yl$k?YgDj$Vz0wE%wtXzmdQG+ORb(OtN6t(Fq~8h6~mJEU51N6%0+LZIq;JH0nS9dUPeV>wgs8i6hhh9|!OqY>r*- zb2CTIj=66(x6YxYhz&`i=FC-X=1%S;g$)&wMk-2uH&c`jS3;`IP0C!MYrp;eh0i|k z&pw~m@px{1?%n+MbiVSBrgq8ekDD|9UFiskt3CHZufXBt*quKM-_J}g208vV_dj{~ z--bExzq|2ig6yE-uD<9*8do`Nb>yOS13(IXMz&XQg%bk*M z$kK>VZt;G)iU>YpqJ~CVgMPE3Z;#G>;@h;(F8<@mXL`eGo#{b74iL;EyV;Qbu?5h50aGp%Adc<*FIU zWBvnGEmS0mfo-zsX64TMk%7%0@E_*syE+l5rSu4Pnp77^vhdxFbyq1nXU9?SPF$}@ zVKwQ@gF&jFuzJj`)&I&=3oaCFT=)JZS+*Yi_2)BT&93J`KXdkN)%hFF6l?*p+rX)n z?=KC5gMMp7m6O{f|Fe7VyQs<6(+0GxZr05XR;Lf0}wDUza!9BP>6)lIjGbhf0@ zcc2c+$`kB%dHc12@9{V{IWPUyUG3|gt;*?k6VA~C9*3^dt+Ji1)qAZ0I@WO@zH<8K zVX(Cb*(_Ifcq92%=as`3uC-a62dSH9#gPi7OWk&Mu5#WVDgSPmYF0?MN~hZZUU=q% ztww1od^h>mpXI#=9C?7RW|@{0uvItRej03oO2@zGwqZ%_SI_t30;nm(7-xpt8B0}+bOfO z#9)-Zv`}Xm2}WnT!30kGJGqwO&K6YqTss|8Uv7*DGExkAIWTGZBzWV4S{%MM*hwSU zbj;ACM~Np8pA6us#*DDspe0XNhV9ZhiARqhuJ2)?h_Jo3rSpZr?}(wv~Q98Z*?!lRl*aG zpNjeAY+i?tFgtEN&2`MyPce9*;6ch95idb?8@%-2xmV>^$L%N^-91jXuPpe7B`=Vx zg34!W!Wy+seW}@Htr6aJIyiaZ`lQzDTeFpur%fUj!t)oZe4z@5Y1GhK;b;T<-oB40 zuyH#ry!4Rhmc&uP)_LHEFwjW=aHq&Y#14Mp&ucHJnMfwNnx7G3SMs~eWygOSO#rZfU{NGv{@4< z7XU?wjN|=htn9!T2Iy|F?4fen)2=gChn@A>)1Mx$I#VB_Z^yOF=8A4_^HGp;oib{k z25zSNhH+m8(!Vm?4#nMlJZ@;y2tl>eOgnE`#c@r-(}N_g>^cm#%H!5KId|k6Rwm!> zYPj8b%iv5{!xpWf>|#*(V9oW5v#T3RH=i4vh}V7pWnZ|{E+d=T&6&Z1nS~F*QNQoa za_WL`i^9nGEhJSwVh5)uPU6#lCO)#m0E2-mDj)E4_B5l3ePjPucL1SH)>%eyoRz0) z-#rs#=E0Nt0cw;*iKJJUoF~5E|l#bKQ zdL2W5NbRpN9Juo3+3Rm;H&|Y?O;_`(dep984UbBry2OteHlM!Ys(9I4yHoP!pVNDe zx2Unn%b=+0#D4$HvP1nK?cIwC+aCsB8HcPf)jwQ}8d+Ta=UaBOrf;JP2{@!aZhY>y zZ`j%&VZL4_NcV|^Rop;hhe6&-@2K^z886&v#%Jz2zi1O zkE*g0+z`r5dJO^Ihe(Tq%_+`sOC3wzVq&_0^9};Ld+yr5`@xENxaNKN3x_VB4Ei&@ z=S-7-a_V>4se(T?W5%oJ6#QF$d9EnT^$mKTGaLx%*-!UPr@P(aK1qlYqf>^wXSa%c zpf~y~Mm~TPXc#lF=vn18+I2Ophhet+*re*3lZpb;_`2IoVZ@52c8r$Ms+MVtb~O}r zlj$I#kkSPdv8+ckfLfz{X$m&R7tU^6O!At^)TQkmCGrj-7=zNR?H`cCi&2A`G`>yt< z;rqXb9~4inog_rd7wj^5zUCkoM^IZQXq%1fjde1O6NQsHJIA@~Ti4pN?&81h8WQJr zX5CHA3~9#v4{y5LTEvpScf4=RPB(MEyT129+`gxAW+yn>#5A?KHM6Ky+=B9Vxao$rBW>ymTeep+ruRkd=;|SWAh&KOA4a3bFM~C81eA+l+RI90HUS;R(GuP%j zbnfu`hwQeEt(65M#G3!qMzCo@h;70jkKh6OoMTT$f_Usu4T!|I@smLbbA0EZyP58X zENp5YhPoD>tMcy`;F~WluPHqGm@mM&9=jR*HFxFH@6Vrn9Dkl&OE~vCL4ilZPzVZk zAj4iKz0|yg8V@*+wu99bjdW57Sasn6lwfJPO=&wufl7k-tN}R2F3o_ErUN_J+?8N+ z^-%2s4b%S$-9W=ka|S$g1NxQ&E-(E4sTDM^`PW;6WIS@A`r$e0Evj6imy!@`%chH- zd|sh$wkY~!jfXOk>xkRh`{-lTFk5F@oBp4(X`6_xj6W%|xewF5@?7jY=@zWdNww#n z4OiNBgTJJ|wtNG&N#{(DJ*sXt4~9ooJM6l6Zg$VV^9A1$XlmO<+8wUomo&DsLoeMn z@txxvx=!d3g8nVLht7v4={<*+_&n#ZcDikzSP%7)?};SaHab}R<1s1UT1>t}p>v!l zv3;IvaoGCC;Me@8=K_9P4gK;TI!jU2j@r;oVygXOYP3zFGc4mkiLu;LGjLG4I2l4$ zO{eJ=g44|C^v;hO94E{?(72Q9MNRO_?ywc4sn*jBbOvqP_wMNsegeHnYL7*ppiBa?~R$*o4eTl-ok$LJGmK>8@{0|gwkK3u8;mc(kp zcr+3feCLw0-f55|uL81@>p@L`F+fgM^haQ{(bDyE_xu{=_nav~eYB?s)oTwhxKBVS z_rVsI4OcrHPcHe|tLM^jBj!Y;+|EpEX&@z1k4XHyTcG7LrS zck{cdKWXsAzWmf#dBR8kRQG1E(vmvT4}I+; ze!PS`o?;PxZQ5a#zO1X~u+B9zyV`Ya9}LE|Wh4n6i>z$LGx9v9CQm_t>g9cSKf67k zXFqsUF!*%iqU~Rn^WQ?_u({Yvn<#Kxe6P|FL8&EXa2-}~m#AxPgp=UXPb^VCcO z*F9RM+>5jw&#w0tO?j4T5+VXldxyR*-*dWor(|s1o15mIKi9YA!ih}h97XeF`P1IF z_FcD#|0N%BxWT8v_hGWa8Q**U9SIw%SF@@TH_L97`-xRPKWF@pQ=YK=8H<6I$je+? z4k*_#?p?5j)@c>umw(vPSMEbhQU#Er>=oq<2;98U>U2Z#Nm=X->vOv$OkOr7Z|puW z^!Om0)Mw%|a?`5hmel!P4OxlKnrL){;Tl6a3BkF;9k&6#zpNFl2d-7F-NjjC6 zmW-D))b(?q9{5aAD9^>kqP}hkOC45?at+75DoLaeKqU6m-FrNlU9qd%#ynll3i-XX zunR$6z48(-jxOzYg4@dvxF{TX?e;xpI{#i;H>aoS{5ykFl>#0)J?m1U@=m*iH^x~k zjfOwaY|3g&4?4E@*d0u2@Ae%mKFZZYR+zZhGI!Ikm{M{`3RpShG?AvDc*t>WVrVop zNi|_0{8nYzc*MPDil1D$jak(vF>k!kmxiCt55+8T+%+!z6M>=r6u)~Ae~CW#>I**> zAXOKtlKOq{Z*Co}PW^E#OGf>V8D%s#QU6r+r81hP6>P^#ioT6)h4Pq;C+r8w_S(Y* z9n^_M(@(_*98_jXj|5(yxh(pWE434A+bOxv!>dlBfC8v331htqQ$4mC?&GY!&U>NC z@a&k>@Loq12H>1d&sIb>wzyt7XnXe2p(g;%9r9^$u@)i48HQyc#Vf;!A;>A0#Hie_ z|4P1>eSfaD+_~}P#&TmZ#oN3xq<_3tsFm5ouTcj5cO^?1ai4F>b};#~qDtM`>JBxC zu*(dRocI;nZ@kA?KR-n~fBlK;j|G?Efij=zVgG_>%i~f1p*JVuzg8NCC*6+-9m+ZK zcXRTJBW8R0>Y>1{nQE=)!K0PcRlgSR{f9|WF@NvyYpg?v`6GCtQT=C{vFB?%e;}y( z@6XSdf>I0l=P&&G_5D8$;h&BF?AQPP6>3m{@}futKRg(NqDda+fmBBEqRL=epjVKX zfgeFS5Jm4dNIT_GEcVX+HpDts>XgaQ^>^7g1H6?wf>=&adXCC8)*;DKh*<yyQC_Pw76=XzH zi$0zOwwjPBNP44<`QGcM{6ybvU!ZKs^)|(Uh||Q`toy(^8~E z;mcM^xDaH0s#8j9Rn`T%R!N1>#OYcURcr{nos};tH&wR$z8Tgk)00A}y|ek|B>XuO z8CwT{dLCGu$pg_tdA0x73%osfm;dx?Ikc!C+&adO+>f~m{T=C!nN2G^_y(+j9Llr& zB~x(vPl&>n-vUColAmftw>zlcm9$!PC84W9f-DN#8mHySm%G((t7kd9YyqjmisBpw zV3w-`2wU7k$Cch5lh%qy_bw{5F%_beL$H^Bp}@h=V;l$mO1375qc+EKfq9dpQ{PP8 z$S|d+^$WeSwBCmeR#brzww`mFkG-k&hH9les`!`}=hTU5 z%@1RN)Yp2mtlyvpq)+f=FmX;&O~4b5U2E#`QBb?_=={ieW(CWxz@eQ0vcz%~1L~cu zR|$y3+|xCJt1Ee@mmKxFNvhkVHvti>T!BkEKA^Mr(zzR-K8g15zq8!cxm-BT194U< z78I%%!0$c|k%$j>XRi*-r1EOfb>Su1W6?fvGj3pIKef?h$=cw-8V`1VoozBhkkH)O5^jWG{U!E@@YQ(^?lRA)>ullmDr1Vb7-k%0)TfjsOp+#-uL^p?NX7;-m#q#@pz91Lc zpY3tf_%(3upew2lkz%K#z6vp$<*3j}OO0yhpy2oF6$sp$$O_@s!=7-edM6$KOGDi8 zsZE89lw~Q?W^aqhpgh#)o$dkP-4XHmf6726Pms+X$>}+plgMaH&_NHAgC@My+{)n8f=AfFq0fv)T?)i zOmxBwM!+naCaCZJW|0e6m?vPS$r~?qwSB3o0-*VyY^W1Q9Ypy%t%*)#K6e2@b@*sZ z1Dg6?XhV1TgqUHJH`EMmPWMs9ytSmrCA&7}6X6Y5PVITrhqDF_phTD*p%g8Fl z1Vso_YSw8-BLE5DD7?tDD#pV>nmK7;Xfpt{pC$sKPQPKqx=q%uvlSj()=6Z;6UnNL zOw~G|Vr!Tzf4^+4m+GxO+Ei*@dKW!YUylla1_Q<;0IgwNs!3RNOWjk$XJQiBo|);F zcNX~e7O6|-cKT8=C*Mm=g{rQ3X>1m0{2tH{%3#6XSZFa;dJv10)s*wrR4Ud~8`RX0 z)zbFX(ks?78r0e&t8MD7ZCR}SSWB|%JI1p{f)QmP+S$Dr?MfB#lC9eQgFCKel~gRp z=Ca`)USa7V2?$fAf~Fi(A0?!KB;+|N*&Nuk4Cq;!=z^&fGM54e4XVA*clKCF)VVKd zYNXM&sgt%{{per%7f2vTB26TV$(AqZF{2IB?rJ2!3_lI-+Hkwr9i^3A=fG->`$ton zoJXtfjN|F-Tq9#%uj)OTGxVh@uWRmBUD>5nVthJXDvc^p&XcSH=#N5($?2FS&TiM$U09)+m{T%x5b6WJ8MaCe_q4 zFflkCs1oq)X{5-hBWJVOiiPAy7){eCAgYX}%HpdKnG!C&ChJ&HY@SF`RPtj^|B}V| z(jwaVs%13UUxL-_Lo#Mel_tJw1zGy~4@)XlCX=Ap3{b2gsI@XxF#N0kGG&Tss*g0) zcEVvx5)#eWp=PG*U$BMb9S8=fQUz4IO;+(>I&b*w?}>BVWGG%_D&q;VaV3(A-9GC8 z%rAl{@?1Dg)?jNkU^Fqm_^L#z(*jd%oT(ww;1VU(a6ew&B%fHNpV*3t8OEv~q-Y4Y zn8Ycv%1AbtPgeWcrUBB$6f%8G^u`!WjR~gO5>sP~+4qH@=og`~6rtgLL?clg)duP4 zCU`?XpkFe*Cm-xB1Y!i5zDKTN9s#F%<&Tvp7?uKHFs4F`rqV^eyevm57a*y-W+@fi z^7E{Crl#Ep4dF|bUkp+3pgPTw&E9a--T+T{a!C-F$~YN4Lc2Q3@v_%~H1jnU37B_G zwbz=a{&#({Bj+Y*>YbYCNXctXIwGl9^NUDc1p58}qW3oMeHZcf9ZgO7l_3{c^^YuG zN4qx5SAR|(S^^GCt_d%uW6Uhn{T48pnnqWzhMjq&Uy7FuVt<}5obO-X{I-`Cx>a$HajGV0O@7s zSyO3^R!#9TghVh&ou}onZK<(!-v__kG0K;9R-(z3;@9mHVr$wfepob z!I@-Zk3F;=t2m`C$y7Epk|ceQtVrcZr&3L>&1g|ckvSp-nyLQfyP7w4R}~@m!)a5; z*SFjF83c<=js?V<&^)CZo;$^tOp!IJSn;Icq^5%1 z0OQURi)y^wE{;MjU#ZR<5$7wJOe)V&G4^9(Mri7y80%o3+9D_BEqMW7vAh0yp{MGN zL*w#gkqYGnKUT4*^{yLzt#*M=ibHI4yn}BKTrYV6gAWnr%ibl?whA7;%ay6^(tnJ7 zLu(-d(u46PZ>}{urdV9%!Grlq>f_R?eiFK-O)peMqBUj~h!Krkc;i2-zgELSnimc> zCskN?+|6k(ji-R zw2LH;I(symc_7BWZq6oBg(+vlk?o|NXswsiA!iKmG4nJvj3}3#-1&pRudrp2ZJz83 zc_OTTLU^RYSX39apg?35R_OYok>tNeqPHno0AGep{;U7dwzM15%a>ipBN=?mFQ%H* zvF9Z>wYS&g4yrXB`GkI|q8*IaT<6>$*B^+vYk1$Ju7irkyvrr?b~~Lm>zcxh(hvY` zNF)a{GNUoAX*wgIa$`ifuvb98#ZnN?-dNQw&5|qS^1d(RQSL<}1lab5`@0t^;|*=> z!XROY_`Xq-KG?IeN#MSExZE4>SC(jPwJq^b(tj;iO+&a16XXufu$Nzf=v7jp0uw#K zQFQtx<#AF~xl(O{hK@P$ag50w?6gbNM1xu|q)+OPaM2__dX(eQ2S$woM})afB;JuB zK2;_p_7i8caayK}gWivN^pUJ$cg2^ARUY9#T+qa@nJN>SXurw;j0o0!hUq_njs)Jc zLVqG_uYo}a;}6=OzO_C{it1V?(YOYx)*%?F*(j&7r2&Zbh|VDdn5Vd zId$F}jgo-tBXGsA{(7Igfp4EY{PvL*(pPoh>CYwQ&L3lRg{dH+j7?{1N6wPk5YF#t zxXrP5f3(-;{Hpf|ujxp3q%N{qJF=&4KEE&&k(fu$t$ud!PD@Q{);Tqp-s2C`WBE3a zmXwYCIhNVAa`vekxZ=Rb)4*WJ1>6hv>+`>+MJeWY*TYb-=SvR`(KqLZUR`Ve(%fyg zy=<}S`?O(o$2+55WXmpIca2Bdlk z1z7TyiReWexYCPze)#kZj^4W^gQUZp-D-dJtk!1^Bw2IC5u(R zO>>dPk+(B%ob4QQLn~=tpP6H%D@M#SvvnKiYw}dPxmKgXzwLMI?^67@F5ml^p>Bhm zIj=iaS|1i1t@dk)^4s%zt3~td*993X0!K+Ci@As>Z)J zbx@j{igx(7bM3pkxfuBU3%JF;e6^TI9WaMAzv82?Nzp{8e5$B z4xmsps%gGuTwCXP87Cii3pXobae>{3Ff*Iub^-twyOi{sD0A;V>D8;bW_a>^%F*b9 z4s#TmX*}ah+ml7p4(a=y&?7yzh_Y|o%Q23Cd<5|1-9Z!VlJ5P zquK@5UsIjm+4`T+YH~BDM2ocA$V>UT-N~`^&N3 zX}zI?MFlZLy%clPEa%2r8yqP_eX_k9=$K_MY&;ef8f8$mc)0$FqYC`AY61iNITlPIXn7Q@o;&}Uu1uGi#gxH(d z2)xwU9aHwqG(;T6$rUTFnQP?1IbB~5j9CJ!sm@O-ev)-P`j?)2Bi#eWDk?ay`~q9B zq^0i3YS3|s4)*T^AxNwSRgdC4S3d%Lw0IvJ)`eMNxai&;wbKFdrH(Laz9h1<&0g)+ zvSN$7?dC|WyA`VL6n?|>c^p?eQ|PLWi^h90v@A||_GJNLF5^9DkS_{* zChL6i>h@|~h*9yh`UTVSIIJZXLVDIjb=LSsr0=s^ho_8&V7@5_Z9f^yNuJPFH4aB- zJUZ`DCt%A0e^5!iR3|szUxtl zc~Qf)ZdPzHaNU1XE&?SLnMhZkmVjC&(%R>EZ1`KAn^pI~ zl`{dlMR=l%c?Bn9-+r)~aI77I(JB$cjykFFuuwuPSxO;6%5r-Oem|FVIb#3R!;x}- zo~W1*s&AqGndgc*^{~$nHKqF2V<3ic^vapI8tp-2PlsNp*h^YOQOZ-0Ni#VIrvp|S z6>XaD2Bnh^YpX7?pf)ut_zHiY9SX2U*!N*E=_pHu|j6!%qQwUa&zaPZTVTFmM^B4y@rm(PgN5knI9tXefqpB|&otBp5z-FoEfO}TYi{QstZ&RuL%Vv!Pm`c*ned>`_T>0EV*SZB& zp-!OH`pSPKGqA>+XJ=fOTcj+2Oa%X~`T^eYJ1Hz}`LF#@&re=OH=VL4pNitIZKzZ#p z`I`C4jH_DC>b5xh7iOt04vnW|T6T*gqF7x;QGA-gpC>b?rrr%3ny6kY| z-S(aXKVojE?Y#3a!+ET4=!vXxWX@gMuGy9c7yr;T5R;j5#VqyR4cg9suo4c_#(5q8 zYR_>;-ED=TMYk(wYJ2N)U%uEHD7YxriRrW2;#3bE^Jvh9{W-f&c5na*TcIm#!ok+N zA0cx;O{oicQL>3tc10qj!C@wexPN7R?c>|E#xsz8sCXOzDyR5&p}; z@SiaMl7EK;3DDEMs|uMCO3%PaxV>8FEQn2&hTbjA`f*-(CDeFO1)SA>j!m+PwsQi% z_xs@@^aAf625WGzgm`bNWRfVtylkj9d65aX4JW<3d^;jO7_JHcs~jOJdx?dStfq+K z@0>lXXQYSQFk6N2MkmwFe#8%4(l!+-@=kvjq0VP%{>H&PP369^kn_Cwq&edytbbnJ z*`MsQ*QOvxLJ&Vl(Ys@IR=XLNk&Kxi(|%In>fIOL3NA7&lNV7AW0~M$k}=mZS;SPe zqR!4GWcZb59M5*HOaq(OBElF)tEbPN-!Kq*pCxI3V<6`HQOAI`KLv;}7ObxjetHx!cQv4xX#NfbPIE?&Q4zCL z#2ryZvN(DJh2)dSKPbp`wtu`FWPy5$E>L_=L5loVBY?&r+30q==38={`y525i}?8w zA=U<)B+E_r;{`y=e42JFIR{a)yYQW+0f#=kseM z)`+_W0K_m4E(k#;Y@FhYBPZC|A5jh~g-|dJ+{?&Wq~tCz^5zAwe5lwwE@R&#*pxuy z3)@M8mQ=Bc8ZbL>>Xc|I2>A^M&r?Qhu=ePSfj7N`NG2=!b(Z5iRTN`_SXR1XDg%B? z)mUc0`>1gKj<~-du^FnycQ$+wg;>WG`Ocn?n@5cG!^Ro-4SdRZS1I^m#CIxkhG!_k z-pmbWOTQvX=d#5O%VhA^kV68cW5(w>r{LOP@Gf&?rMv024{{m+A7dd9 z8_{umO@9BCPccXiB~1v(m-9r76vCHKNrR}ff!S!XA1VOq=&y|!V#B|qk~rA-qr{S* zq^!3*_zKG&o0$FIG2|Qt{(&k)+zvRPyv>&WCRCSw`mV0kvFIVEw4&Z2@vi0LKX= zmb?%dJJ2;Nww&6dZS|Mi{OG*I+yMsUZ_eR?c=72w$ZacyV(<)(SS?k&wRuKvuHBA}8)qp-+aVVF(S`M+Gff!vy_^J1(dIfLH@y zew1^Bahl_G92=)#bDA3ECEE+P3>L zr>`Hy6ld}n5XwM+h%gSo1(X69uc#nbqL?lRA*8?~m0)rUh&+L-gcke=06gg>?wKOK z>xp`Lndppw`*+xw<7>9@%;!wV4*~M0f{Fp@;e*!b6B+P!E$LVZWEnngkbhu8_F(RG zO&(aRGu&%Pl-^fc*zGNzUj~1AIDIy@Y;-^p>y215+&eD5%(7KVJhXwvEWOp z^{W8s85jQu5(K4b4Klh6U8%oiCNXLJGWL{)gmA%MsCVoobi|n=6I?~VUlJJ_ zzlOSGVrC&;bdO!DWrvp(V3FUq5fj0=Zjy2$CGtpYET4_s07#e@B7TvApq!)DAG{)u zntm%Ji4}pk5lFs{$jOutwMC<3Dz*gCVE$fc1|mR2lBHWu zpAQe9ExY=a#XoeZKVlsF9u>M34Y8%99)iNcq#_M>dQw5TxDz}S zf{*fgc~?ijEa~;PJEnP3a@NRc7OV{SRP4yJx^=|Q@@G62a*>#BR0#V;l(8e)h{(=f zYPJ7fWK-d-NBAsSpU-CoazjjviV~)NB&FoT#Kx)UFFhJ<5qDiv@APKFA7O*O?AJK8 z8de06K?IadFeP=5Ar~l!EiU2_@g9cBId83U7bh8qhel8($Jo1Ou+3p3FrN+h*G^BHOR&O?s|Dh;*#h6>&Or67uAOm zzi?JWwDQ-P^pGWgAoaISMONL07Z9SOW zKI~)`fVg*1OvYMXQ8FqGF{ep91Hz5n1ZN{h? z4zQm3hiY$N;CFWU6RkeOUg96#=vs+B+D2NxBr;hw*^Yszvrd_r3GEI{i^{~pLny`etYhy~-N^lw~4>K{e@HAZgq+aHh6 zrud;=`y6_90=Y~YzXeDBWFaEZirU{jj|2a^`5jRO_d(J=w#KNa$_#yjR%0g-98rt~ zRcaAnx&x-@a8KvN3-F+ou>k-P9edlqYq$>&`ouyCNCm_94Cx*4-ii-3v$9fFqoiFU z;6C=#M{7raaZpjV06u-Ev$i!%*Jtr(D30K}3&U2P$b>8+hiCdw0)!QpSM78xQmc`x(!4TbtMY0pZ&sGo%< z`rWvBAU%@sl|K=-^Lge+JbZwJ_{sa)+jpm5?EPCVxSRr?Wlv((5FBewZlNRP6I+;y zfb|LI6wmg5@7YQDr19UFeY@slx!0s8NM82S;s&c^jG!S(y8jUh=@r12NW4uHVmv!F zGlbANHMN^ryp2OPvG;b=Nf0*SsCu6ckR_=dW8BUiaSHiwZzV5^o9Z5VY8Q_ysB4TsEad^poRNxko zl5*?pDjt@LldRt(S&WlR5GaHzeWS7#XwL2ih2Dw%lB3w_{Ds&)AUH(>S<)|L)a9YN z&pO2K-h7oWW&BZ6&C;Eya(zQ^J+>WTw^yQyhu+--o@dMlayaDUv-_ zMN9qf$;OhNhVVU=Q&aZ0CMJK(!Iz)Qxap&0%Zcy>A0(iq@ug#$FrvIw>AqZknmD<) z>(sfiTzMlim%fkh_7`Oe6LHDc_8iH}hewmr&L0|L=i8C$Jb-SMd~X1HKgH_q!vWPLvm|smtpEHrW8<5TqkH;%9!ps!0_WIdkJw&dh%bpMC;&bvX|_ zO&OIxkY?mLScl&sIXVC6{={gdxi5oFa4&uk|8sT6lp6SmeM&cJ^n1Gybll;50#&|= zzpMI*k*9D6P9ig!3UvEz6`gLD`KPxRkYLeDm(i`jrrg%u_#-^pH#cIKUgJBOI_q&AR8@gGx3@uUb@WnXO8UOfqWj znBTf*F5|A#;v#p*#n@HhXlRS8Qc$|Fo64!W7B{tXe|jX*A*8*Sy_9}q4|*uGrz&(S zHtObEHqZ0Q5#Q4&33VbVwEb+;VqMjxP)(qPmeV>m@u%3w60|#2d3!NxM}Pv)m^;dQ^T(X}#93D-C{aFa_ZwZp?b)Us~*Y zUOIzGA+|JT8@}E)sMi{<$Em?7_zolGZgYeC&s6tzzKfdCorlGrhnZ)AzSU=g+!xD?|tg zy`h{kt0E~9tI09qZ%31k^ZxAaUaU&?&;-ux@hO43e+6McE>`V_F zlFS7vUif$HR-Y=7O((Tt?*YpmN9Aa46=!O+5lx3XgzmPWBGB+*zWTM4()f+`dW&L?HRWP)jCPoim0&D!yhk66z8xP-$aIwN=Idl=&s@?e0p=mGerQASK zE;`Br!!(rfSjsIMMO1Ao9oU>!m z3+Wrq$hb=g!U>EEJPWaqS0P#UW;JryxaBZS$qc0s3d7>vX;}lN%e7!ei2{kPvCMLo ziXejF?BKk0r?2J}CfQ1ExAomu-gsB6mg-P|=qxCVmM@*H(5|t&F;x3vYjPQf3>fhXB(st0nM6$taVn)Zqu*X&(GdiHnneXD zTb{?ea6)@(YkC0z9?P)#7ooBFE8NDHRVQ&4CdP?m0)Iq{*)NjcOQDpiC2#ed_f46& zh%>d$eDhW}dooZ;nS+i_g+fMfXyZI(usm!YQ#Uke-`?`dTHG1Ez;e-!ee6^9bNG&< zcmy#cq85Ft1~W|~2yPP7aq_n@Q_7hJ#mxLsi-GWok+r|H;&deWM2{fFPUuW3#UwIAkO zCNiAVMMOaD{*%5L-2mtWyT>tmz(5Z`3*8oEA~zlr!UNu6CQ-~9D&6o%OQW{2epcqq z0ZH$sG?}Uf&Z8gEh~2|%#FGA37N$$tU%d&7XLRGz$kJy=oiT4&uDDQ{OdXx*oa)n) za?v=+mn?1Nz#SQu`MI#fsPmWSsjm7SwA{uHh}H%QYT(3?jvuYXoDs{{%H&H2nt?Gt z+uh>mOlZESnf&{qxY;DR;Izv}r37BDR9z8rtETJj*9Se~K~}Bt^Yo*R`;~Q6EIe;< zuxeZNJ=TMlrJf7Fgs6LnraKq?kralO{Bw^G`~EaWcX5b9B~IL0&{FU%?M@lo`h%@W zC+vR0q-yZ9mwsiF_Ybx|(s6dyy@WRrbYI^P8uwYNv~it=~pQN=f%;-=x*ZjwQof;7UCft zZ_Bgn+xR5AKlv1t{X~lXYl~W~tG;J@3*3IMX=G0KH%t`n*)y3}V5_OWZ-WXobCQud z9WKru^acawqOTC+x|Fy%JwBOFBEu{{jlIuIXxmq(t)BW09+CSIm!JIh%p~||E>Si7 zUr~X6#cpBlR$`BKDdeLKpFZ)E?Jj?LN~K+PN<$#g9U!dJEBrjA@e{r2*w2KdNt{Dz zwm_=h9UVpm14@yx+f!}J&w1F4r4@PkH52_J4WDi(&#nf-i%T?67I^z z0$shqzFBQ_02%IgegC_DXs7vXLBB4+c5$@F4o8r^KT6k_X6T2za9=abb;L&nP{*I5 zCHZe58h=?mFDML&lqImr+s3Xp@VTa1*Ma9=0Yt}TxyVNM>54kGA$EcvrLw54EmpJp zSeeYmg?Z~GKgLCu>hP-n=H0*E#Ux%5Od4xkfBN`wIWl!VL=9?~Y)|sqpPs?h zkP+rioBWbN!jeN#eX*9~&mI-tg-u1peT6n}wB!$#KX>|=dcmQ8#Z3EK#-0!NARVus zMWuFY-x=#jGuyDJk>6jdA<$PPBm%PkcwGE+`%|Z?D4l6y#KB$brke*d1w=dW`<=bX>y z{dv8g&v0G%928cT+l218;g8vPymQ#Tcjior?a-O>82frsbFY*t49Q<<|2 zste1_tN=MA98Y#M4PYg-<}^q&xSFxz5!q6B{Sz*%s9#$9n!tXM5CM!WAr5RlqrRdG0xjjC&D<$SqNMmPi2KtGw#jXjxze3P2OET=)GxexU-#<6-B;to(g?p?VG+|SnVbs0X2qWf$G+|tYI&B?%(QNR{5a@GeHjZ#PskAZ0 z&tA5qOhR*5?V`lOUG2v%LK#=QWEgM$URK8qG4V#sHGi@$s!laqd|$YUd%x#co_O04 z@NWCT`8=Reny@P%TLYkumh{3tIj?~7n)&dmb($;^E#}<|o!a)+IB>|~EYKiL!p{A2 z0|{nB_SgqtdOmqY)f}Ulj|C-HHY~Feta@c!CFXwB9Lp9*=e_zBpB zmIs~`8M-op)0A1Y@=bn2i|z;SKhIs9a(0)TRL}k=A~Z^3u8tKk4-G@sTmPRwnAC5&`A69rfr7lXZF= z4D%^r{&@FZS13w%T=wB>=Zgi1>D<#pMzX_Wr+TFuu5%LnT$H|yXN!zP6pYOY9SPR_ zaNYbvZO;9Y8F2j4%i3sO{B-UK*%A$%HxvL%fN=CZg~Eh`6I}McAA!ZfA%|M6>vB+N zKX5`GxVqxio*||O8+^k{Dz3m!04R*JGHtIq9EO2}`Mv+>d8A?Q(I=V{-R2WKTi+p$ zLi+*#Yx|y`*0s#!UaIr_Pwb;y~jU!-rC85rd7R4K6QLI=NP~@5Ey6yT9^{{rF{D|^?~{k6hrx2 zB`vJ=3DQ?3+T|f$ZXuNXdbLhkvhM)YLs}?BTH0V*)MDnJ$c)Tjm3-i|V(v^>+2Pao zDC{dU5s6gUnQ1v!@oSH#m3`mIrC5;l#nh@PQsq@DS|!Gwv$DHHnjDZ;r>QS<|GZAF z^d1-$TR5|KfmVHGcC&|u?#hZWVo?zjAKuTXouGwVQm{YZx5E*XQg+t!^J%Gvrh~KpMuh={)}0eb}BC+cLlo^ z9`+uiI%*9$4u))Y1_gx%1^Uh?DTE$P38t=vL`=>{-Vc@k5`1j1#Cz-bajg=!8^sdV zA(VyCeXvlUn1Wk3_53EaBEj>?ISa>~7DM}jLc3_GyIo-k4U6fy!A7TpkNsPez8w~# z5T3CWOh^xnMTcUI7ZILICvunaa-n*nLK>o3+MFeAwousQ;4!VKD!!S4XxLl=?R52# zReUe|SecoD(2x2#v#p0&RppVK+{k|Bc+cW#r|C4`cZsJXD19{h^3P?pTG#3 z0o%Ze5oyvqA>*WY87aA8QQ;Q zm8)l8HUW*|Kw01Oe3eACn~-8EUtFt~8=Xol?lkUk@zNbGo9#Sjy&+c}U-S3CWurLe z9*mf`*;(s^5zwkAr~HIzcd#MX#Q+h$e@I-i%oq1JiBdVIvsweJVs=V zVf#zu7$C2`Rl6-$9PKZ|Fn9O!`8^^{w#S}I~OLKvK z2uScRR+0-VwiOg;1xZG*JlMXb)46f*JPfcpBHYxv1$Y$Bidf1PG%_X=Sn<;$)nvKq za4^&o1Xg7Uz6&@nP#ET0a@@D54mpcvPz->j2w_G4a@^OpoB&??j9z`Cwf5U-31z?b zZESVcAXsfO9z8XMv`knioK@RBykR#V&%eK3+PAti7L7a{`9Ld%8JeJDx$%B&RRa=p zs(Q`%!EwDMhUJjRF*um&B7!HMxWAC_7bt`yu+H?iobkK%x2yd1G*ASahcD{BL@Uyt z+8E0NE@nVZVmKKDNZK?cbw9*_Kae@fC+!TLE(T}0Fj6i;(kO(4$E*lI>B_W_U?q2g zpIdIjrT=I-`W$kKp8O&a(#FZ(59n+@agOa0Ipbt~G;sC!naGg75QoOqcODC>MH@!P ztu%hF8d%0G8YE4wMQa=nAG`g{r#e>UaLRV|vcZ3}H(FaxF)6Xy-xJPI^~ge+zp@Tm zt!jJ~)wd#VBnTAuJgVRyxwO-|EJOl~~s0yjPdBzG|e)F~Os)`u$I^UfPg9S6HD< zLi31zH62JOE&G7LfQMma&{_DjnnR9CGJd%L+_s8+#%FMX=DYO=2e%`_5`vCz>}AD# zeRlFz?Dm>r3a$F|y$3;~4gU_7FR!TnX?d^_^KE-eb?*bkt=3C_{;-aJ`v=i-$wCA2 z&_|~$-(1|UsI$kl+A3n4ujhHuL18icD%g08K1LEF4mm}PyMFYF2My1}?m;MX5s9~l5 zocBO~?y20njVHV9yjpCb^EZCTO<9op2&5-hP%|q2IZ`K#t)z(i(R32?a3{+#!dmPyQynObC^V33G zrMoNdAH;`sb-v$Re%YPge)~y=mHWph$qxp1u0C9NH^f-9uzPHg{Gt5fC8xE&Hoy3@ z&&mvA|KYbcm*2I=e*0&;^K0?iPR54gSs5jhPIq0Ml>>0-k1d4M$)34UahY{G2oApm zD75=xRpLl;&E^i;zvC1ii-$+c7uim@m%XuRC0`tS4uG~Jr`jBunI!rkpwVX0>H9Dm!peiG`Z?UQ|-uY-k{2PDmgxB$` z>JzdekV$s$jP9}ObESRMnwQknPqA%EeG}}BvpBux`YR{(ZZzL`q<3>}IP98~T@+m+R)ES5vV7_hwfI+a6$IF?qb{++9{jFqMr zT{&0cQ_NzK!}YNV6A@uqXq-0tmbk6i@IK{JW^Y{2Zwt$|y^%g=)H`o-9&0$h*q-&| zAMQ%)pUOm$99i_$*KQWd`e$*=_$;3I&7HE>w!72cVQ9(I@Ag_B&bC=Auy!-2O3%(G zddO4^Fb^6Tyd>or%5HQ=L1nuB~_ChFbU7+Wr_l zdd7Bl>%D~YakzIK@SFj-m)5UH)T#M;+dw{T+C&WJ4T6R-gln>?-|k+@y}b(pBYe!{ zn3|lD`w5)uqBC6Oj>=w3m8zFwMxwbCEo@yXz#-7ZOQuY#MJ5c2J1R^;kBCGDA;Sq<*!RJ{T_ z*OnLv%dy;dT#$lj2VH=((o9sg$d_$2X5&Rg8UtQ{4-)3j%)BQTrz(zcI zU(!~&fY-*oy?g`Rid9_0=V0#-fi&Si?!C3)G)Nz3(?&D#!pBhAmBKXL;%r}ysRn|rt6U$`0x z@#ieM)-$(y7LQT^1(_o})LVj+$q=>Zj2Vw~L4X5)v@R8##zX(0H(?vk`OG-V$Y0P< z1nq9w`|H=ER{@c(|HZ#ak76SF0nWBP^?BX>BMHsHV$jO?Hz{~f+hQxku3K7mNb<*h z{S%Q#ipIx2<(E~4o!XOBrZ;%USGK};^;77xlkU^eiOt8O5BZsEzPjA2@7?oNE4b-u zzyr4jPu{fe$(-9W^&5Q)5}OwWKgr2{s$gzPAoHvz?@OKPTvc7BxbDi(<0LOR^k}VA zINKYQ9=MeY0gv#Xz5CEtbkc9uiO+|aOju&82jGVa+U2g8)25YkE!F8;qt!q0cS6(H;IM2G>Z{)~ z>)SP~?j5EpZ>gQ}7<)D%lcbPs5PQ{-$@Iw%QaY0EXnEf_+&o}T*?tBJCCB^wvwvND zH^jpEVF@XM;%6s7XhF+6CxkvX+CAKE+B38Ge_0e0bC-N#H-Zpg@%mA~vD;S!340yW zjQ2&`8?raQe!gZaaGu6!)!kKg{~YS`UOD5&cb5mpOqEB+UwE5(*Q$pkymf22Lr9pgiM+(=I*RXzwgc_lP*mZ#M7grk$)R|1V3Ng{$U@sZp;w-is7&6fh zu~~+@^kX7W1;QPiAiDKn551D)c@%9c8Gr(&K_RFP-c0hxUqM zx7x~VtG+j+$`;wyeA7UvsfWp>J~92_aFc5INe8hX7X#kK@KIwAR6MeN#{@|A0>CL& z&U+zJ3sagZc8}_A-?(43xe=GTFxS*E$r0t zp`4xhLr=HI6#smm!T%IKBZ!mhoF#kF3rlJcbBx&>jK`t5qNYSxBA9-6kCej5iV5LjV`DMa$8!HH;t# zD)o<@`Q_Tj8G>XB#$665g{W!fa|(b|(T!`ePBn5KSb5(X`9Q2fXpKS)RxxE}T&zYh zw+2y&RVuGhdZdiF;XEBeMk*Z0@{v;s>{IrYgB!VS$uXvCoCS?rN?SFm|F9S^E#ofs zWE?{P<5EhR9-?!x7T1y9#9$+u`hDT83I>u+Jn5pQ$j2s-y{CRu?E?nNa4;xeIc;$@ zy@u<0x36E7CqkoCu;mb#Fvz9_WYvoO_XR6e@jP9?rEFzh`~BW}3GF@&Faylte)(HR z(G2d0!?Q^??z}%f-OIRnI4gX*OBZi z$I~&cPk#lG0SvVyCa#ralN9WHhk0-U1D^&MW`eBnJmL`ti%O8QP>>argeVxB)fc)d!e)R1*YA!02G#UbYmRXud=^~jtnN*PB7mQFfek~ zKF)zCpwfHy+5<4HU8;f>)i>{>$UYfCdu9GvefM6S@;;q6Bf;g*Xm$=J8cbcN<{(*g zpK(pF+zTBcpzIO3t8BWdfC;)%wZ0D=@!>!!fGgfY7if*W-9pHGPE@1-3rh0s`jqA! znzc?qzmY@BXhTn4-xpthIO}ux7&RegU+DELmD5@Y-NI7t4&B)#6F4(fhG*o?#0xO{ znT|3&04;u*?GV$pg87N=Y5^a!66Wdkcbj#Bh_G%+q}G|O#xr0wpI=fiZ=j-_j>a8F zc{w7w2Xt8g?!_8WiE0YQ<%0)gX1U)GC1S$WdoH1C19_ zA0h6_PXprqkz!UsxK2#=f)<=k#NfLzo3;7!Zcq#_`a@0l4)fr)mSP=bd>Vk5=c-S0 z&x`Mq?3}~k9nf@OI2sEJU?8DFC~qJ%>GNTQTK9RPKyPM=tjQH3N_wbI9b=&ISr-$4 z@ma2V{pDZ|z52$8eI3a*e1FYelG_B&nhmn+(B3ZxMDP#Iu?dnr05Q>K+g2gNe~tBl zdJQpHDSWqeB@_Lt+qzEDCKCytXINK~a04J)z>%g<-iI0b-X;?6!daG4mUR=!;_gB! zA7Ii%s=2Ob8BBKU0q8gJtdfMxx_CA_B#R+#A8^2`m1(1M!lsF5LVvY;i~}&)0qq|H z;n}2`2Bt0?Ddi$07;&cyWOIRc(9x$D_J#HDpeZII|IR0Q(IFFI9?t!y4V$Uoxo8gn z>K2o1bZ!c~+?L+t>segWCKA{8rv6Y*#mRn-+gBU!ucmY$XN+T1$NTRF$wXuNOgyg( zxq=H|wj*`-jFW6e3iilo!}uI40j)T@7VYO~o5WPgCfQ+@k5&L}mOvJ4!2bMF&UiN} zGYJm~>yfJ`)cJvD*acx4J-~AbY@j`~?Jgi)Y<}f(tv?tdRP+N2IfvcH>Na zdVT6NUGRF^3fH$H`^5EmcKxLH2EC*&AS;R(e4M+Bg9b-E^tLl&stejrDtHIRdHBv( z?{4=WTM>rXde4CU(G|iGohQ5#w4T5E8vCa9V?5*GU6SoQFQ8)tpOkfc1hD6V-_gm> zf-AU@1MYmfMN9P2!BsqmXX_p%Stqn|q3gBak8%Kp6Cp>N&R%bIlCE$t zvm%)`f$S@$Z0+T@n zzC`h*2#m3Weo~!QF@PY?z%4N?Crb9a$J^b{mOl}a8)>Xb6%rfah#Q%%7pO@=v%WdG zvToC-bNSBvJXYJP0kWOs~7zJv@DI9tj-L`>7scR_X+NEZ4c`a1icYdAycq(Ci}g{;EYH+M99 z6pozuy6Y9ii|PgJw9scMPLe|}BWGui`Q@RSfKnX{w6FtasK@?kF5!e5@!ieT;PvT3 zlB`|cJHP+*D~$~0+{KeXtH?UP;+#IBu+%)`VZJUbp!?W%7I=hWY%gZ1L8-Y6bbq<2 zcDx%u4zdo6%mUBUI9uf*uypX+y$oaUNW@C58?n+~Si@vSh?h{Z^YC1g@s+I_n?o}PW49sK34 zwG7j?pQla^ki_#22pl1K$4lWsHD?8uB)a|x$X3Tnx7a}^TL^NB8T-vK?!N?gI?~T+HaxiUpY>IVS0{O? z=|O!N&r*}abFBP)ZAO5-ugr-b?}^Ttn?S|rHeBEQ57aq=c8l?!Q6>(wzwK~f2l89;VaXk$MD=uE2sv~wuf}Zbic{Kf%Mx1i!{~3@AN|D zX2TKES;-2!mF>-3(%*kkrHfjaY|>%=BRJ{)3tIifccAib+1Ku5eLR`|=by!{Wu370 zSJJyl(uKR$4^kgLc=qh%Yo?ZaEos2oU&;jCLW=5T>hjgD?e9Cin|=m@!$VKjw69Vn zWDrT+ro|u|eFeJ!lG)pYx-(#?JJ0njPcKP`XMeWAM!0dRurVmUDGbyswci(zf~Qc1 z4S2Slyz{(AEw5E>S!%aC^6>&Bc?V)))vuMVTKc0R(a?p14kb8U5YNPZq|AXEB*Z!=YBo%e? zY*l(Qa2MBlY=lEipM1s@V>nHKd;(%oUpctpyt2pZ@ z0gtyF#G9NyR!a(=r7KsQZwT5A{-o9N98A!V7OhpXOF4XQ=TJv6m6Yq+(ek!2y0=?? zdb8?gX&tyZ{iopgs3Le@N9OYF;=ARBleGx(AfqhSe@6?>SnZ;RA76sz5HJ*ktyftO zRoZlE>%e|)F+?-w{U-m{B@GdF+OO(cdE8~RjX-t3`k3`Cuq)$--}@*;P^DcWLB$|@ zSU2#njn~}5=;KSV$Df`7LKN^7aa0~lTHCj?B0lI@5!SgJe>oxK7!YHs}WBsn=Qn|D}B0oskHmvPc=gX2^h4`W_JV&O%D zR{Epu+Iw=#MFkRHn=_6y*F}o{ii`7XR1Z<9+A7c@nPdo8y zCSp#fd6L@+9Ip7^=`)sXw4SLW}d-oCP&$v-q`{iWsYppE4B zf!ZObJ+I70meU%m)4Cplm1DF@^aP0y>zCz-II<%zd5N>9JF*+Ncr|4?eo;BDJ3jP= ze5wEKhl|(SpDAonFbgdy_nRA#G2v0pQXMWwsh8Wwo-bU9uAa$ilE3qQRfY7jt+9G% zi^sj}{*)Lt6leGMSwVJM1^7eKG6PZ>`@mSe=IO3RW%$!G1~0;EHO|prqf_p3`>v)f zbF~pyjgp-GlUljCmF+7GV=;8+^JnPfJ8cbD(^k?UQu`H!Oq%Nzx*4VE;Jp{FM2$B$ zq7Oxmzo<^(1G?wW+!z;~z1JTvVZe%OnyW;WSS!B18b9d2Se3r^e(@Rub|kzPPs-6B z-nnqAozZ5z|Jtdo^{|RdG{4Ymr@Oce9YpDHqiURmc#CMt&X-2jQ~c-8qRxx~nROvM z&5Pcz4c@b^`3NkG(D;q#VXCL9Ev%I8k>4__GWm=Ts;MJ%iASm1xmT{Gyjj;)Id|Bq zapm+s*N-cwe|gS#AV=P3s=ofS4!KsUKHrTxv-`+8RV04LGwcQe;;J3p^wYRPnJV9n ztw>XQimOW90WP|u6Q)qhnajk5fm{uR(&mU4SvY>?BWaynA8@@RQ|kFaQ3n>y=$UF# z;6LM{#GWfoUu(YnH}&t&`s?Gne}8{_+J-N0%g4zznMq&|NOu(H$5--HX8QZor-g)% zTGcAi)07;Ghx0@7_87VHbHE@(cZeBNQLi@Jw7do^q`-x}3h%?vzDo%<6^IWAmh}s1 z*ojslQMjHY3{g@b@N}z8`Q?7h3KMg`NK$!Aan!Enig)rUS;)JyqM#-RrH!mCzs^~c z?zpZljT-TuxLjTRUXUN2sR-o)QN_Dl$%G1$$~$_meP2Bs9qw>+0rAXigK|EMef<=^ ziKMcar|Bg}%$K%#(Svkw@()l~`OFWp$O3{p_yie#lc#wDQ8LndPU+p7^TJis^LT@7 zNWaUowi~T(yRS;i@7?{pH~#YeW3zWeKVdNuDtFAT#xW$Ik;f$i-gY%}C?ZDT8pm<6 z%r*D2D`5#jQUPVzZ#EM|jJ;i?GY{qL3E-N(wK))xMrZDc17f8Tf+Q>Ba?bQ%s&x6o z_QkFTPE{L%Zx1h;U3;&HsH5+fAU0U9i-OQC?c&%BEm&Z8j$RKy^lxXF1A{|W2^c8| z^@C`rD}k=&w~JfFEjS>4+}(YBSyJ`-`~CLPkKnX~8qqrwpAW=eIaIZFq0#n-t{J2G z(w3+OJKyz+=UKgC%60_Stw6%_uNS97V{g+%SH0uxbE7Q^AtF`)lIc>3)K}XdH|($T zOzx~V$1-Y_jm+Hr&ma#!9K3it`QF!KsV7Hzmo8#6Z$W+P&plOJ670eKSkIQ*#0&q` zUlMlHQ(s5=KldoVbMf9vNTR}c4>`H{NCdsa#L06NLL(TgCtFrG zJSdkezROTmbjG|Ku@YEc$G(+=O@sLrDD8U=(aac4vKLWpBbN|EU{R(k;!<7qj zR~WDqLBxp$00~hSx{ZZ;aMSBB+t)!#7JCMmRHw7}vf1nSCMW#ta6!f7*uyhp(P>qk z2t-mXdWI5Rormv31^}VEy-}M7A}Nr4_*v<5WTpf5@6z--K&sZ@9_rj%_|R!&eV_;v zuLJ@G50OwQnD$UQTonIwPUifp<4`{4tSj_7hmw}95w|jjL>zrJdjGybIzKP5B?z@_ z#R47R=474T>c#`IbIIOPr>uCd6$bAT_r@#uVlF^FE*-VXd^?YO>^FL7EtTfhEtNO{ zGd6@l;gRtC#7dIN5i=dlZbn#oKM1|NgyoM@f}$j(v(Y+q@qv{sPHE9&Oc^@!XP zY!GUQy+uj7CzU!+iBQZUV0a6u*!DcjI=u#oR+U>!&=v?lwLStSoP&@4^ex8 zq5Am8AbNqln>{QM!*BMkk!^9w**jiS6nZzqh#uo2sbACLGi0Ouv*VfN#;c$spwO{9 zPQR&ccZw1MJ`Dd^kbsV`3r_CLp}(<7*zZHIp3yl}wfj+APkp?-JW+Dl=)CRxdP&9- zQ-xZVS(}kAmNd;nZ_{mplIo?7iX1Z?NOZPcVu-asB*9G;uABMMa)L$ROb&xFI>O~P zNL~B&I|IjiM3o4RdV&7s2YJfj)-Qm0w{Z60j)eBix)n zrqN>dZ~LXIEu?alC)MiOiAF9Nv_{L>Gs4|+bpS^Od_Zi%(5cwnFpXZ~u`qu(rboQz z@7S&sx2|YAE5h@QYp&o>TF8wn`wt^ZMhef5#FMgFBG*9=2Qv)ym z%oL3uRu_CG7AT9!xSnm&RX*GKDpH(L9 z;(Q#;di}+@Z?fOd6PLQt#Y7NA5L&0GT=@?vt|vw#NXlX5ynwQs)8Zqu;w!rVsfoV+ z2@Y(4aJ7;n$)8r-Wx$p>VmByo99CY73(X9^s`q+FXixVtLB@qEvft_Q?Jv&^u=4Ii z>1DRe>t-;AAf;a;3!V{26ITZ{#JV}KWrE}Y2g;#$PI?L&P9!ye@(w^ac;W2;M!|DN z`g9v?g8p&^);Ypaj0Z^RW94x()L>n3HwIqbCMyIK%>RGO6u1LdphL3S9Bjs`LkEoI z(1Ieg239p1duI6HZT73~C9TpL1OALkCpDNn#O?yBMrn$?5fec((i&!VB8S8%6vWz$ zsun}Ip+MM|=ufG^MZ${)04n4jbO#o-K@^iMPx3Np~h|8K;lHt2{i6ohQn#zekODaT-xf}Ies5h&|zmO99Z#HgOH2?3$X`1y3ozJzgJxs1HCv+; z2@u^Npr*M<0kU$FAh@EVNc;V7mm9P|L{YfbgUzNo2T^rx^w1^b1Tbisik@UBr<96< zuqx9ti?|Wg4aW4QFlrVUv;ahv&n%9`=#>(bCu>k~o2WYsJ!MJs3x?wO%;L&-<;=ap zr>J)FS?EC`Qiql7b)Yi~qB32hTt0)!-b6KF2j~EWAtE~43_Zk<@6d?l5J*o(>>3%d zFJ@8%g6TO1`X3cNja8AGaRo{+T+CDuXU!r33KKIZ(F3u?Spv=|v=Xc8(RwP5y_f%m zj*nDr!HN{h=w2*EJ2sj|5@hkAdcT*Os&5B=04kMYP@CL6jb)Hh25RyyNupP~(a0%^ zh+29ZG)qL0cW0_~UaL$46@rPVEvVq$KnJkH_lqR@sUA{rXrBN~*GC)UqT=M7b*U42 zo2V;T<cSN)Aud9FggfiMebFFI^Q!60Ks+~%-Hrig8Nq4JO9+UBW(!H0ipp>r8>h1vn_ zR1;@4u?p`1E--+bt3%@)tThk0Wp41YJ!E~qoRXI9ySHM#(@4Gma7@&T1mMZ@s0kwa z%C}>qcXs-Ky3sX(Ls;m-b@T=m;W90a2Pgc)2JF^Q8{o*jNh{)c$HbldH}laeyI9qJ zU|Nij`U;i$2^jT_iWm{n9x4z#{4@e+_kN)Y`&kg5m`;C=Yb6RMEjsuRd89zu0j^NT zLr?tB<7}Y=-C-nBQh3G z6JT5U8(7rcCOs-fdB<0#a?aYF_G7cbjSPgiP>^tQ$Jpy3FNmTA*LT#Cy-ol!SFjou zdLpgdB-#2ymzTdRag_nw%lfaqML^(8s$nu8Ry1!8ZALqh$IY^J z@;~jNYB3(dwUT>%DAagVVTFN~d#N)vBWRI=j}TBFzN|bPTxd@92~i`H}<;c3DTZJ+;UVJ1GdCIY@3T~xr5pwqBOA30ggiC+`07# z&6OGzFQSyj4AMQxsh~wRjjIqvJA2HBw=GdkObntoB-3Iad4=mc2#X}p=9W}BWY}x#WnL!+do>}As2FeF0 zm)E~0zkrQZprYoKif76hbniiR0kv1|!af@^1zz_sQ~E;E~e zo5N)tzU+QI8l9~J2BJ3@NV!LP#@TP&9~dlfk=>l@H)V<@&g$Thq5qmMV}!Mr9aP*9 zq7)2ttRpj?u6SEm$_oQ_p-afcwiwN~u3@c?fkr*Xg7j-1KK&5rLYD^%V(rFYGrHV` z`etb>^5i~A3J5$g9oNNmE@eOa(ab)Ffj%OluFnjj{$_mU&QoUX>p)04#nwabmjCXo zv>8TjSu=MOkiaJHq0HnT|CVm_8o7~|KRBZSmX&p3z=W0EDRkl6RKb$#*sQ)l$U=KX zly+fXizA>m8OnnqF6AL8GHzlMx(;~$({L5le<$(&`l+tS zjL_j2f8YB5Y(ppKuPbi|K=~N3nGYJrs7*Fgy+X9wtWjw&)aKVH1zU^VCaB$^K9>Kj zYH*j0YPo;#qONoPaEc1zqD`h zDu+G((<4`i!KfnUJ|=;dFR8>_+QV-5_Td`{x zOVw`T-a_Q&s-4`0vp*gJq>O504X{X@_vqpm`xVA3ZIkm))E?D(D0mShVcN(muGU7O zsD6eD>}61lyjC#PKTSv~ayJlK3kC>%>`Dwhw_}sXpSrlK7r?&f38Gjt`B#=$Cl#`cbwS<_IB<9Vd* zIkVx@1QlK|%j|C|+>WwiFSXRd;KIp5a;jZFD( zus54$0=lA%-+<)V8-6b*Kt-sX1Ocw}n~@ht@iV{OUFT;U z&jtUvBfdg^_;1KTqi*>WKiYZoEx%x%r=Ex1XFrLukk9lICB)}>*(m(Ciu*@SAbL{@ z&Th=)!eeh&eLoo2DIKO_^L+2SiNxUpUV`(G_50mM+fj|nM0~F0WYuDQqdDBT#RQcU z(I()X-W&mtQoaF7x9kDp2sixZ{O;R>vu79E58_}rpuobQvN~vU@!4EK@?%W~&vG!U z&B63nPpznwrE?X{W{*}6$Z)w|HpQ0DNgI@ZvG;wDE?Z@rtl4gI5;y-}2X3@`Yxd%##ZFSKGhV=$DqNo7 zf6u>n*5KT~+Hccy1C1A#6PuZQ3VixbC2)=_sjCSToxohNod??So~!$`srA`TuIF)X zokO&HF>i^FlpOnULv)7o49E7#RvY0+uJl7JhGal~?kt1`9f%SXH7M+9nge%?ATA_> zcBeV+lTdwVmm{6DL{i>GLdBtZB}GfkdLp03ouBA{o@TbH!`Iy^6rYOr8J&yI57w_$ zI)A72W^jo0^Hzv$!duI8Gcz=Ec$JOY1EDCsy7J3uh#9RFmfAmy`rco1d~)vmB_*)& z%a4+;FhOc=In2QIH-`rMxjAYBs}`S^gfW}bxlz+hb639)_E#)aJ`(mudQ>3evO(3e zOQaJIf(jGaOpt4KbktD>&}1-0>zj%pc6ONc@qSjd|LsO_bA^XC(g)-}|4PoBGdU$> z*>Og{1-%GhSw2;QMNABe`EZ!%!LuH=Ls+pgf7s*_@l_%KF1jKtcCMjD4V~aB$t3q+ zHUWi(B0OB*$K8?>eI-RnbZ$}rSD@f5DOi)+OggmvtnB&)ZSy+QssOsHq*1)`SFCWx zs?{MVhar{j9t5ZNgVe{`iq@@fWIiXTI*f~8{O8qGkO-PVC zzxFD);efU{>0vn?O!xJN?6GrYSqw6>zPC|qHrTHvQ-*w7C1!$7UKEZmerB!<=jVX{>% z{KJRKY1y=}4bj9CkF!3}FNRmQ2e=Ge!)ZLOS z@9VP`Hz^@|PJMqd_q?<`;PK}dT{6(;Q6i9cLmo!2GR$fB4>5Rsi!y#)_dM0^ zj5jK|7Cf(x4%n+Hut~9p@IvUHgj{eWor)+XfM))};H?t06}uSAd}AJN)3e~Hr?b_T z`=@0;f8murT0o5o z*zU-$C26TL>E9S9g*K0WNN`3$MBs9hgQTELujcO9w(D~JH(I$=>pSH&M9DQ-mC>js z{801K=SrPb26XWBJn!VBSiA1(igsDbhmqU&@BLR0&91Q6Bf$5fKg3HVcM3!55bsP} z0J8EhNfcNKBYYy8B~Rd?7dfoPyU$H7Nr#r0sNX9|9fituXkC2mqN|DbV&aqfkqR}d zSu-Nm=;ELYp9GV8=pKhz%tmtc49^}b>z<+qiGZ#RoP4k#eDtKG!+MAFg{8Ahyq-54di|y}g=#Fh2SFFw1FkjyMPYz9%jOMbeO=ebokv1GOzrF zY`g7X?Y2>GI7~9%wtCjoJe!(CuYG9zu&dO|r8L+Mzq=dGh5f18J2p%tnEwW*q^b^CqA`@i#7l4FVlg!jm$`V0b ztRh-5kD(-B)GrxE1XGRS;41{!R3b6jkd5NMt%63_~F6NXtCWoM-(+#4|;qDCx|75a-+(#Voj zQldtAGUc%Q947C%oTX6-OtDAY7yufOR{S#L38Kj_W5jl8@gnc}n$lZR6gterLHy<$ z%k3elellKm)Z=@I*aqL$#epn$PnpI#ZbgR>G%f!7g?cz*yI!pBRVF+WN33Ea3OmFF z49fALeOHqNAWI*rkEddN6yBK0{t0X4SX$8qmA#M;W@fKta?*^l;!4w#?xeRbA}hCS zi;9J~Khe|0N)RqQfCFlcQ?80j^`XH3d*FRXQO;mPeh8yrg^}P>R3E2?pH+~3x=7?M zhCfR1)nzLjK`0nc=kbd5(KVu1=wiwdVmFHqza@w>keRrqGr-kZ7^~PZh0PrqbbcU~axCe9-PML>; zeE?tqXp%alk)WvYdkDIfC{5vOXoR1`0)-_Q7+@e^YZ8~<*{NiAMe8E2(T|k z27`ChZuNj9gQdO^U~_S>w^XTSx=g(=%z0LFg@}18t@>*VZ6|7)Uw5E%`gHVR%<6RN za;sp2W_q9>HfID|Ho~t`jBl2TKLAS2V_-;Wi@FO5t#JJxbXbxrl~SR6FBBa0E=Bk^ z?6R0-xF>7%vpJ*$3RzEI1jNwOw3@7xa{7<|Oj2S0kD_~zXX^js0KOU9%xrUQ?sH9U z&HXl-JCWv+R!MV7a_NiET&m5mk;_Cvu2HT@CDC=W^$~)zuwPRm*&l{_$4f234_!i`h**seCJO0nWf@TX+6y^@2E8Xpe!?IYm`CT0b2n>{WqTw|QR0Uf2onCv8UeXY zO8*)twn{;KXhldgB0dl(a zOL8$0IN%8dJA==~vhOwvz7i;ZzAAsexp$dw^ND%!BNOon58pjmySEIiK2#N1lz~X} zL2~)ma&M+YBwdL<+gO*?*syxc*Q+M`0a8j5IoFz;XN1t`K;C^!dWElF$+rj-QTU5N zjxOxkW+7AW{kP5+n4%JI=aH!oklU^M9<3tZQG|x3L_eYK{9z&oi(%yZax4Zim4n;> zXl(H0KR5{*Zjpaj$gh~2+br0=YVZ~h`DYW!TW#FIBUmNkJAA~$3HSC*(atdG~uO_-mLALZG@zcoSzIE0EQ5l#p^BfhhVI45uFM1ZK!kh@b=!TkIyY!}t9_$tv6bnb`7NAenc zfMYl(Z97^~+KRl(LhPUv9leU?TeCm)BP;umpP7)bIkgSceUB4}6+SY{#kRNqCiS$~ zA0G0jA83(>+|<$9$Aj-gH~o&*2zY`_bKCoshaBM_2)9N&cqE0xi)(eZ{J|jKV+}@) zReE{Ipijv=(e_xZ=#4JeK zqiJNDw0u@{k$W;?nU8$WOhi{Bb_n8G$v!hIK#}H=$6kdrg2Y zRe0AfMik+#5RVZX9ju?Al5{HCXv6yiNr9Dg2X9SW{z2@>tFP{Ls-8|3o=KGWKjA`SCr zIb_>GnplF*+2073tj35Hpf2Ghbm~#!!n1H11>zl9H!ThArHH?c7H=nk1)Y7_(S~=c z2he3wZSL_;;W|YCv4$$J1yGn0{nA~ri~3W(0U-9DnWjXf=(9no7CYE*>#gBv(Lg4w ziPXO*A7Ys@=z3zXoRTLy2#c>eE71(qo0l(V!l!useO00jH}?8h4Ul;QP9#VhT&$eZ zr^*J!x5D4@#b>eN&C$o&T;Z3p#h+J!i)LT=#EMAZpc~n3dC@Nwvj_Gug$e;;929)F z0h{huYp}}`U3kiEWkEZdMNOlIRJ}wT4h=}>;3RGOoAA7^5#vX5#*ZmU7F64hP(c<1 z&_zQs`p38hW@6yBg4Up>ApunHlCSqgDWyhd#y&s(P=0lcRqVoesFI)W{P^8a)H3@Z z>EHOs+^fK-H;=cj*26*CTS`uw44;=`vnaShpSgCc_;JUF*(pB5zc4u$tuCFMK!+ZV z^_eilyq>)(W%fa-R2T$*I9;hfd1(F)C$8I#^v3*$MCs!AbXs7?AUZzhDfip7i|RCK z2!!WN{^$Z-+#0XX0li#*ma>q&$1cB7^6eeEZ)W-AOzI4_>hK#^>7J-b>4xy#q@00$ zBa^kx`7`!!ee5S{Y-S&hq`%Rd9qo8i`|NFK~zG~pae}|Ie%cmpWzB`^XC)YApUz+v3a}FR?@Ne^ocB_y!9>2|(l&Ki+aF8zh zH@6?L;4+BV<1MVs6ucB{5JEM4wP3TcZ~(DL0D^{4daKMA)A$-qsIJPZX@`+TJH*oF zfZ)-MT%w3y@?dtFKKFXHbaG?q)XtoaD&jkbv*s`P2p zSk$=>7ji!&R!~d9Vxv59K2Lmd z&X!M4UVVDD@#zI(ja@N!N&M5kt(h**nOhZ6I&o4b5fkaTYa<5huXCfgucX{lu~oUJ z4p1ekNwC@L5rTq>TIR42=k%dCwfmPO&>0(1$I#^zSR!F=qT>0QV2oDrJOK}r@?Sf6 zPhE~EQYv6x^{^-3etx#`M#mEy1X~~5*c@*++x2Gu3D`JsaRnr`wS8+tm93)?Xl^M$ z+)2pK_ZJQWg|k~>MbYci0TFQ|SUp}8_E~y+D_>H-!ZwRw+3F4Le_4pBkbRq`7V zTWMS2k8LJ+W?y#=JWMM0CVOAJKCThCiC)Bp?_L#}C0tY}-&TI5_-IS-ze;JBQ(x`)I`k=JZ?pupCQG_%}@%!)-gZGPwG8ZYpF0FEO-nG?W4%^M-S~KvX;oQwF;Z z0N2|}Th~Evv;LM>fi;moaRQBj#I=zC&4?hM?D?f|xqEl95@kq%osJRB)BL4`2EV-g zw<;Bsgn|v;6%7RZvzG{_wf=1apcoCDEt934WeEodhAhdss-X+545cIgPs<6|pcwQdep zfzxCAd~QKwaE%xC6J4?n75E!2iAy2(N*7Q9m)0fnY7cX?eE-~Y)=v6q;g=0;s;~(l z));xPqfS|2@iOg)pd7#F$!lwXDQn{TG%c^P-FE=Qdy+C4PHZ08r()xM!%1kXX#e|1 zGR%{*?1jPO*E9;`TJQ%2Z$h{OR0`@tcwjuI)EJEEV0ABPC0ffSt6y&>o~A>Sgj_cNKsW$I#TP_%ybgXvYD5%S-=63j|PF@*5koknrVD~UB zx{7Odh>6pAPRpvF8%Uj<*HXFgWhJIsgACZKk}y_`efj){9mM%tnYT9BZ$1;EWd5|^ zu4^ygq0g-zQW#hz@m-Bk^{b7Nz0$K~u0p$v$i>VL@@UzUXGJ3a?t`>{TYl12mhx(@ z>u^yxfK%GI%7zsELl`l9XC{w*s7&6tcSeS9dr(bO@>X(PIoacCkEFhnKQ%u#?pa;= zhF+>F`Xe#(n!dq3@oP7~qlUa^Zl~z2$R%bE(9zFQ#avWAMqcdENJ;%TUSsm0&xIJY zp8u*alf6%KT~tdXZ8=_B1izXnEut7reyu94)d^8P z=&k*GNG;3LctZZ2H>fod6}|bzHIEj(=IoAqr6q&OV><-TDYRw zi>Dcr%g>)+l%qF&?x=O(_o|$~bR-AT>$Af3Vn*2B2b&53x!JrusY+k4zc_ZZ$Za`D zLPKZE-%3x{0O$St*{O{UqjJHG8E&se;wu1mqF{8-#d{DXkF|P-yfd!g4})q_^MXin z-%u%!%f>@QI^~5AtG@W-4fCGU z*Dzd)xlmA%c>iVRo$d=n>qYOA|M zZQpwAqbCZ7B=jqr*xkqN+4}>BE=Iv$z17k%Rpe4~6SJv`iB%cn<2CZP1!v3tj6C@$ z35^2-pr5XGCNZkWz88xbJ=F5HG%+L%8 z-P^_blAOo5qTj+3Jt3?vljPb<)YyU&dBMuPBw!_GQ@nzOA|{Y(o@6 z;i}T~m=f8Z{?vejN$B2B8fPcfy+%TOTPYzVq}B~AWzEe`9N zDtVQ}RsY7c{Fx4vY68^l4?^!NUE)RJ`BV)*yX@$2AvpF>s=VG7Lyf|gEah=Ed;LJ> zar0H}RsUaS%q;2smQ-Eej}5ANie3R;XJbT^^z5Dtxx$b|^`UO-JnMWuUZQ%_$%w&* zxk(4wH{au8CgKnWJyInL`ELQ`lAvUp7)v*FlUieytka6rnI=k)&1Q9OsPsUx2Nh^o zOM?j-D0f{Au^21Qz4bJrmhvxR2AIsEq0{VeQysEZ+cfcl*&2me*KB|$jpinOPp$;! ze%R%>u+3~Cy1vT6yptk&Su$9rfElqr0s!@Y>?>a3Ru~@*&Ty|)yNMSr5BHxz-L*>~oSxrJIhIJ`*hW8l#?&+e9Eg3xRUCZ~zt0l0Y*Q|X7XU{R>ue%IHn?NpFHmS5D z%Q}j0TIr-jNm^}J5V{_nCNF;j+fZyL)ehLJQyTtIgB*{tAaFEIMl#)esixOm4KM2( zX0pB&zBGIVI;Iln$L7VO1Pa~(AS}bn;69j&d5OKszT&x}THyIGO+Fe6^(eDIUfK=f zYUJJ^HE9-7&d$UP zTwGCC`L5lAp`eOx^D~vdZTDE2)LP!=E-T&=0v)WB^o?JnDYl4-!C5hainki&+auR3 zCZ|vs6fN@?ugC7)NcO4tJ~+R)$Lz^~y+owB!gZ><{UHrX#< z{1AQQzQk+9DdL6DYxg+j{io$q#%L*WarWXFfyj7lgz|+*Z>d zhJZGcPboi+M>F9UCP6B<1A9!OE zUhCfpaV@cD9ym-t_Nr*M6a+}gjvr>hjPC)oYKwa31FIwA<{tK^3gWw9MKO7o`F2U3 z6t>xye8gw6l|>SI-H5=ug>6<>X;w#j|(R1 zQH(8BowhWZJ0WF-Q3A1OIcfgWYQp3btDE-xwB^CxinpJc-A(s)FIF@kGgB^){LmkmifPwWIIn_t6rCi?7}kte}q3jM#i>iA+)-z$(L0=>D$ z#9q(w3f}f1K*$M2R|`i9;v*Q6_TlrePgU*YZGkMxB|YJ8Pvh_Yu}Y3MCDvrL)R-F1 zW_+=DHjG8Y6CkIaKrT$)y9`LRTd7PULgMiB-~oCx|3(;1ZgBCKx)2^Deg({B z=8~CC4y!83{2trF+@#I)e`HvG%r3o;({q^t^k(E^U4_x*=*Ec0Nl61D?UBGX_dMtLQ1@j8K0ds+s=2RWTxr zeuNL4nzBy$W=(ocV}qJO2cP~ELiQO$j9sbnuD~Foc~j%lzx#v+#prkjP?`lEesIUp zmln^Xe=n&c^+FOEV(<}0G9E+I7P2BjbWXBG3s_vTkkTlApFr1BRiTzs%gNvVzdLAnAIb zG&4Ps2RVaR+g8}U7E2a>5|{C}z~Nde{EB0)ZJcy62Cob-POyN)k*}wOf%$x3>S_6m$tWM`%4m!OdOIUJ60(t&o6-RmZKR%=q@M@SzmDy>&|$+Q zUs(x*#BCn>auNe5&UPn2fecLP308h1|-xA(^`w zxDFv}G`wpy%^eS}J_dGQN%JJ6h4h1LPG$gAGu#1Vc2Fe_)bavT1j`pXh=Cln?Dm(k zKLe%RJeGec3^J*$pvV$FZ$Ur5l5tMGnz7n@#2c{m%QX#+^b z@>NuQhf4cY(c9K~|Fp?p!3+EhI{?k9zPd(CcP~2a=BRMrjlQnpU2xc9x{igudl=+0 zhMpUps#Ba6XD>MRn*xRcVuEKAAac^{FLJf;|EuXBH@9HJh|x{enX$ z6OP;_QqM)Z-j6J)2pbT1e<7Ikb7=hy@^RilA%l)Ios}|a*1&KG7qi4zOvCo{~VkpU7xWGs%#ly{Uy5T7J=nET*G4i!6Dv9izL zfd-o|lJPn6*x}gL{L6&2o2$ZGc+qsy@snP3LKVmqDx&2LG4;+Gt9CD1Ps=wjVKXFQ#Y=2mpz-SfeM3+owH#&j(>2knfgryU5- z*v+Sttr)sY;X^E8jZ0})J0NGFMn)Isz5C73(OxU(=8RAiSS{s7_(ogpF z*57D!gIwejW!m;!z=EXt)cTKUflv`z^o@t#GA>$Fpj|6&a!cG9eW9qnd|#py`;J;{ zM(857;uE~Z#Acuo;s@PrZ91+rtaD(|U5ZHDe{tmcIo9FVPR}1tm9`EI3?^o|QD>jS zu9I53A~4iSJn&c(Gh-NiLW4G-Kp zPsii0d~yTo>_Buj%KeQIpSR=(Ss4){df(<}*Z)9>7K}jtiaZ9A(tCGdK~fQ#UfAsM z>C+Kdb>{R%&!)s7odmDCd{}1!#76LAJ^?^IeU(cRKL>^QV5ss8pg8Kq-)T|h?d1zA zf*Dkm5{&k1AVXRp^+wal7W4{l`o&_f#y%yUsQH&e(A(mc#NOsc*%udZ1!(>%I{-LT zlpfuiA@Co)q&tLmvofS--#0=bSR%E*eHPeF4`ZEuuR)i=068bIiFjpf9L^3<7M1$ROGjTQy5MkGX+XDT^H~S-TEdO&$|;NmxzE= zWbQwvO&obz;TbIxgmP0B>WirVmcJ;{I$EgfhhD+9 z%f04g{1qeKNW78Kn&BaOz}vv)A?A28|H(JW%6PuW+H2weI>;0y^X6J>jUZU1k>lYCaUK z)kyEY%67whUcPs7#g~iNOOE7a_>$K@J(r!7QW08wjvLZE0WBW%3pjZe?B&8hqYs}4 z2%X?T{|G!d>NzdOu-}eL^8+DNY+O=Vsi)Hi!O_}Yj=yhOx!w@pD83Y? zWM_>%gwiSqWFQ{W#J`H1*vtU``CQ@kB)J0&IGuTTzqePt4?aEl{=_I5{) zpDG@zrjhydkSqT#5$O{2k1{;KA?=aXQf?75Cb23;E6-H%%x+A-RW=!Va<3~e+7|*= z6w@8PHr5XIZdKI0o-mYujQYu}5861sj~;tzJl-oxX7B;sRpBepjMu05yrJSAF?tze6bt6iG_n&+twHTBnsxbR_R-4b*k^`ZHH?{*LLZ8QHZYMY;Pi~PA!QgFKA zIIg;o9Qm$ZzNTAx^4mS1lH-`{v)g=|u6q*Bttnq)#klOSif5$VtI&xz;@x=6x$to7 z6Oeb$LOrZ+cI`bZm8<68`!?dbxWcc9xs`E_iD}<~*qv`|`U_;Gnj$(dOzQaF{gxL$ zG)mjaI9sg6Aq}yueoWiSLw=tY0NVS5HbA zJ+SrwZt=?_sLy7TAQ^OoR9`b}_U77T&M7woVGefp7k42<5?}Uu*mnO$aGr9#5`=5? zsp`z|nQwe`@e=%E;2sMLQKF;L#$>R&xJ7o&u(|12(Xf?27j+Q#Gwr+xvU2qv!gkf4 ztqdQYbwKVj+@uWIE-AX)YzBqf3j&vm+86{i4TQ}9iT;I9(%D#o`>qa^u6cc){R%HJ zWya>=$`=pT$geCe&%7~zq!pz(olLt)co_9 z`j~qCA&a>Vi#P%1T04eUjS#xmp{ezFJ=EQ{!*IvRA{{)~P*pF@=PN%Lb`u`oRiJOU*&TWg zedsCD%59#Md3SsJb>4XF4#!i5A@0kwGx8#i>MZibDs9$;X&)kYc0dm17!g-VluAQQ zMwVw=+VBCI^ev{8o3EFYxx?2gI?m?wvg6V9N#S<96OSEfGHfd&^T;po)-?)lF-F|_ z%c5~5?rlfRqvMgCBG=!yiGU)5lm7Y8^nQ#vz(j#FoPoT?eckBET~z6i)dp(#74tK^ z>u#w3e@BD$FTlI11+>0l^izP?geOdItD?DwVCl|E!<1o(M*u*~uD-B$>ovFnV zBtl6u;;1s8GfK{eA&*X8AQjURj_y8?Kd@Pi3_mRl87I0tk-dqCn{C(!d_vcE-DDin zr+GZq;Zcd8&ItHjvO`vnW}JHU_+pyG4S7M$5``ucc2ns$)GhYgfekL!=z2t=u%Pp(-^I8?lj}6)Ae)y} zXs&H4?j8dKw__#sE`7_B_ElF|bCp1?vJfeXFtBz<_nRORCwi{R?~zf+pTT@&GOH$Y zHO$2(?G{JAEUdsvanJ5z@prhpmD6!3ml4?Fh&)F8;@|JDWqjk~;F;Vo45?Vlw4pO! zjm3vGp&%=`!WUz8F<&@cB{e^$zc)gN)0rG0uEu(T1&nz1=1vGB_^{ zcnVukKe4aE(_Ip&v4u!xg5+NpfAnaeW?xDaSA`veniVi10UjVF#7zhT@x#2Jp+!AT zO4KcDv%PRp@4v@m9+Is>X62jQy_1|9?yIWTA{wd3+}%8uYSl1yRPCrd`R|NOeJ3j1k4+M?ak1^H2A<(BC{ZRgBcLWo(6Lwp z3re%xjszS(ckAAbeQte1Fi?=|Z7I_E90J4JU@t$qX7-j~@(nqW zv80e#tc7Z>b~DjGtMUQBk;!ZTAMZ~Mj>EsS?XWxesa(b*Xq10oa%E3`?b$<7u>2#x zKh5sm&R#HMLmki^6iC8~0|BJ0VMNSyb+SLGlG8kP>)`RcM2{|aQ&+IEAGw-qMb_FMbVZTo)%%fFv zUswt}0HA|&2MP>(fr7*VdJgy=(N|2nskA}vvCN3?s+kno-#F8oJDZ;unesT)+`32R z!i2GM7f2=j=`ePF0EFI5eO=V+<<@1mYW`7m-!P8_BLM_AEgqynQnrKN^r4;HrFLh1 zO^{(oAXCDE!$7KcFx;iDC_ zhWB5;o6h%02H;;dpLu%lxUP7Hym5$#m1U33ED%bckWwVS{q7gD3B_A+V!-Ex;4NFo zcz~M6n_ijER`<}|^4ZUHi-jLdP+gX(s`tO=4#142a$l&e$$fX~#IIZwc?}bO`1Zyj zc=I!aZlhNFiWDLyd_eiA5H3K#3EZut(mWHwXE*)316p+ShI&8FSl&6L}=zMAs> zuX4Fg`i4=?t7>E#yjSu|E1l}Ts^Hel!fNz((`sD%MW6h#ID+o6c|3=R^QB6D!_X~$ zj4Yt)^0`_G!C4C{nm=TJ7g|(pSj3(ZR!lQhv6_&`yEv$g`FW-{Pw$Jy(!IO?oEns7 z(t$={JyPmZt2^bJqxLI9BKsq{@&$#;FY)DxM_`3;QP=WPnJc#_MfwV2A24ZI>qR>!rF6?(Vvsc)qjT)3>t5c^ph2q%3tiH$d!<@{>aaJF?wcyXs@b1sbMUvNq{d5@4mwAD0tHLqS}DpF zz69aOx6gEQLbx1jV(N8iJI&pIo2tM**IO*{jXXWT6|KpMV+@DVspFtaZy|_YjaJYW zzYH-qZ}V5=4-Tc; zQEj#w7jB+rClgJ5cFS4ZzbnWegs!T4=GA-qpM!N;muuX}fkloHwnu;rCU}BUc0hZ4 zX(6b=P(pS77;WT;uk#qQ{-2YoyvVWNJ^?YpapWXniXEp2^X@S<-AUlI@tg$;nqQlT2B)s=+2UH&%Uan4K!!2`$sk7(XhHOrMf7p|{+cxlhIu_z%JGeQ zRZZyb!MbL+@R3|G17M&9pv%5WNPk2*6+hFX2TJa+Gec({b4G9GK>s7o?H>n_H@&{- zamyyoD%S>@uk5S5?{ez71nEoVkqVG)Gfhp;ac{lD=^T~KLX|#?|9&G;5YI;Hmp2^!vFFwyyRFlbKEmU)OV}E ztX|OKeFv*5kTs5LHEB0nD`msu9AKTJh1Y02z43r~!r8)UaGUXBGTWqd&Uz78(N?tl zxTTWh{56`>Ge}!8@?2jIwC_`0Z#Jl8h?p52&NK7-QwXYi#sS3)I#^__me>v6bQueB z6hC&uCauK^dyrfk0N0=q%I23>sJyQKtg%<_U_70rsS1X_R(xk$^G0>Y<4u)BMLa2lm610vB6lTS&XT2rZ_@9;i$v9%^B&|tpiN|ZYRAB zwq992-@%l($u5g9vhkGg2RWvJDBr|TX|#}8j!AFLc`QujUW?WC!T5&IM}I$MuDt13 z5&l@ZWtDOrwU-0udTOKHzP-BopQ32mKZhn);_)mf3NG}V$JrSNn5Mn7$iQ0q+JJbb2bv>~# zzXQ}`_Od_C3D?Srja84m6wnAT-Wn{mER5hE|K@asq^v?$z?^eB9ZWVm7o;KB@OQA~ za|Bv(s0iH{8sm1^V=uXd^Auz;=wR#UY)zU+Xo7GA5!7SazA~SaB~(rSE=`<$O(_X( zfyPDa!368Dk2(7S!Yo{i#pO=;O5Lg857-o&=s7tA*kG@DJ6SMj2ddrN^f=ZeVN_#% zFs1G%f}z3HJ9^yLeaG58Z2yxXfYnpCTZ4q z4%1QpU1ZR@@Qr}5hn16Y)~xmYqawIo9e_gL$=zlbNq+~DSi4nk{@)Hez{tZik=d9{ zf!G8b81i=wy+JgQw#pw5iVIv;buqbZh$go=6P*B}F<%?^ATS)i855Mjd)spv=bJ%0 zx7zT2TeguWj|)uT?Y@z3?xP*=_ZZs`MlT}b?X7T*M_)Twxc-chrW#YsPCnq6vi=jT zew6gu)HlQddG$o?P`bRvSzMu3rmzbYF1Yc9_x&o6kKXbpdkx}2cjhVj9h{^Yll3xM zFVkJ?6Gv-TOphmdvWI3$=o#FUHf#Il)&w$ZzArw<`dlK>M`2sBBwY?IpNVtG{Tmkc z{?zleZR}?ULyiP4+M;8{5f*D&7w=%XyU8&|PUd_B8MaD#W4nWcjNz^zjj3yzD~}Gn z@J@!bwfKV$6w(4UvH}!DPhF8S8Vqo&Y*QP7nh2W>1kiBX=Z&{t7GH7IQF_%KdlcSk zZ?(w{YNnY$;X)S!q;>04-+`=WwVd65*E&eK4xFp~zG0DW;`56d z69F|0GGf|CJ<72*OjXn47@L4}cx=n1H05Ud<^vofW~vevZY{ePk@CU5*iJsx;ZaL> zZZFEbwZL9O0D0T9+wUp})b8Su_k4hIt-W!tmELS$--@e@02#*7jGKkfJgSCk@{y3_ z76+Q~q>zi-b!R@M)5+Cyx880qhGvX+FrG|RD@*QN4UcnqR>8qkP^<`PZfsRzR`40$8m|OX96;TJ1A>ERcn2W- zjfKWk>2GKkeTsov7>7;;7n%B;$WM0e_6}G+TLzb^)@p<(rfR`2H6E~MxxC|FwQ57A z#$6RgZ(qdkYEtDaICUWV2X~Ju+E?w3aGWPdkY<`)e}2HfFM6A;b2_-BHxzG8RZQ zP020ks-g)|lc(;SJ!ldahU%$3{klri;Z}E$BqlG_^1N1)r;Kw}i=xN;vR9SP9wjZ& z8pcSCoxg#s8_-!o%lqnJ)#E*PeR3|ljk%U>n|!D$GHLL8m?RV7cjrWB!uQ{%O;Y!Q zd%QK>cYml&r=EUR@ox_ZoQ*cslb60B4Ds)b6YFZdCXiC4cYg@Q1U+n>q@9u5lRfvT z!seLa+Wnk-_^D@vU9|2FL>PjkJK66~=&AwFcH(gAgJKJ(a@4Av_B-D>dNv}ha_FPF zOXr7A&n#B0nh%xf1Uxg0macXy{XTca!Ycpk?a*{@arW8}?N;IMrzt~zCT11KH@p>l z#lH}DcitxpDu;Vc+rDorP%~Wv?I+UYFY*(GAzwYt-)(Q}@48~~w#?Q3t{Pl%;MsSL zvGvN|i$Sj}>D)#XQWg&B3;oRl~=sNMu@9Lb>0eV+z-Z}^)^)G1A`4j zKkDp$^62eHJzZ_t4w2rndj>cDPw%gR-WTI?N=KheiZW1gKVR?I zl&ip)s_2+ zlfc>|5oedhxwFJA;dzBK^nm$+;-kZ0}zmRL> zQWi6LZ*OI6WXQpMT*wa{QJggJ>`HBfk%NRy;iV+kOATqItBrS_TTRH@SNABB`z7d# z7uH7V6mGTJDy+BN{Vp=+W|n*1#Qbb*D&f-IZlF~14>nyno;f11E>DhuR9=J+_bA6H zyJ62g+;eR*=5hfa_^$W+HF<{t)AwaxFUN#|D^lR^Au+L=%qL&Rj$AIKyS1Fvny)qN zc?`w1mpB)B4l-0j>LYqVMWMIz!E)Y%ePNaleV0;Yo+_SDyKW~4646wp=b&!e2T-XZ_Ay?n zKeMW?%LJrDVhm@RJ&Ob*k@d7!P1WKb5;#o&JA=Qk`wtMP-iab$+e0OjonkcXhm}<9d^=7bw{notwl3HSQAbxL6QNMj4~yyTBh|GmP70#P2q9+_P68-o%aQ4)^VjI zz9b@bBsXc+LFIP`#AezsyRmzG&u5Ef%e%i2rzTCq(Wy+$SE|UQw1q;%V@*Nxd)@_- z$<4qKU5)R6(UjKIT8X6y`^4$jN?O(60oH9CDG*)C!pqk_5D9hYJbrn|=eeY%i5Qtpw?XhgE^7tT$zCN!1CHF|PznXey$K*r5 z)cC%mM(Ss~r(~)%tO7;j7deWBD_o48TG1HmeBiHzw@#E^#W5Bs_>etSem);79<9s! zoj;JIy>Q~m;B9am5pr?BN8=y4;o+Pfva(Y|7&|8Auv+6DJ^=!4Y`OTJKU=-c%v!1j z%0MWg9%APU`*rj{%GYl7SZk~mhdM6HhiSqsb~-2gtHY~2ib z+^nFyIHxdF;nET~$Tt2;7iPB_hC4}r;-xVRe6BnU3{tx8yH$s$XFi-NBb_t5r3F3; zaJYXw_=BR1>hP?0QPkO?FrW9#3AeCnnDtnf-YXF>jNUOz!e?_@f+am=M~S4(?7_)Y zv?Mrvqdc;r)JhG~ncco0F&BT|T? zLo&>^KN>7^ztw4Pwj<<($%6bFVut=EYB%IGh>a*P`!sYwnvoDzN^>Hl>4yNth=N@B zo>HmrggIgF>~i^DD7QQGwP=XPg8VKtU7mC=>tK7*lJ=FQ16F}zhl)K8)INHN$-;I< z_`X)2ite@{mt)Xzf?>?|83|V@aKd7+LbU#u6C{Ze_h!mAmdqv7sB2@luOe3KwQ#9+ zh>LME#!Y9W_U!<3!cgj{%bkX29B*b0p9+@eV$!=B#zX_M2X>xAyEUOfuzbdWN#_vAvCxKjV$R%Rn!;>T_xDn0?IZ5g!X5i8^p^NseUeH?=ib; zI_fG*oP&+wWd&*(nJvy3-rcZLMHZ>blU3nk6!fd%0=OF3FYws}Rl>FLJ=gwr?q@}1 zZhl+jFYsEuXT~PeeW_z`>FTS+0K`!2D_9*<>_XOuQIC~NEn>H#+fxzWi=%r>d7zSr zfkMP-3hQJ2X_GO&($1U$FHmLMP6gGYz+$P@HYma9Dqsn0sj8h7TUjkwd6~-TzO5LV zYD{KHDrzBr1*#}JOQdG&0S<5K+*#4)Ztl$8nY7n<9;i}!M*xT^1~p^g87k9u3af0% zp*|%))gzC!6{Z^{mjV?lvLu*2a9!s@X#>R{b1G_~df_ZViIfV7dZDpOahs}?0u;H* zZcEC+vg}lN)w}uapA>&k6~G+P>zZIv^;D^c9;r%-CAR3;VxtxKtT#}Sz*qbN{EOhg zu296D&Z#)oVWw3TSLeEwYoU#HII!V~)j9c5gKJ}WrQfP@Rd&ZWt5qITFTAQ&;Q`@f z4182z5ZV!00QF%YJe(!D2vi|#DSNB7d-uU>^%MtHk!~N9S#0G@kfqiE$n=PUAn_bocRQ#=aFZHFRKrWn6RhgcXFgdp{y7gwwt}Lk~ z(f6EUX1INvhuDS8@+x6?db560bkW%6N_RAD&ItWM^5e?YO92}OZ?EbXcp3zr+dsn- z*9Y$+DqD`*a>O;l8^J)cwPt?n{_y=BZPP0uOGZW+IwQ)128 zSp6l@+dmrdijS)iB#cNAySr5a zEWjIi?2xMzvFC=0|L*IN`4X}EiY$x)3!|8uI@>aQSSwJ834G+Z@P{}8J6a|8CD3x* zPBCFrIYGQ;^^iojm@=2G&;?Z1iZc%7s%}*)@c)k+DhtfHWqbL^NR%I60w%t@kHiv3 z9Cjk(B`2ztrrAoXb1Fn{*DSu~vro#CbB0S)mqb;=d<~IiJC)TyrRQt~9{a{1RV<{| zXRTU^1&mn)D!*e#1+ipXL@mYcD6ayQ-~-A;yL~}?`N%a%R{&JI4m_y)qxFkQBV7M_ zo}Q>w9e331_2}V~L$)vVup-6=Zl3#}@C+&m;!@)unxhTwM(8Pw56p_)>b;NEUB)hL z5@a8ER01^`S$k?VS++F@p?gRlj7Shb&R$2luuJP307+oG=2!oZxA%-o@{QlWK@d<` zq82J5&NQ_!HMil`GDTB!Rk(NI$n7_AfLk1ynii&+HZjdy6{xwg++`a_X{F`Lv>`XY z`_cXI|9jo9`+m&p0?zYuUR)>V=Qxfxaub05O47~+!0{Nl5t7?;-jR=7B+O3&bnkF4 zN)mNWGPqEElYsil!MSSpBYP>DrI?$oeB?0g*B)E>4n2H=f`|)Cl+LyL2sF-eFlH>f zZq&;5Ea--PmUpcu+$5lKNxJSN)8wN5$L8`AwXz+@KzXLQn=eJmVo`>76NbCr zJ9tb2VlMuU!VQ?M(xibcxIHs@;7x$RB?aMXp6Dt8wFKCcFl8I8Y`5YoV==wQ=kuwK zYkB>(@-qr3GC}yRAa>OkKk?wiS95$@q_m{Dc)gHC&n8|FpkF=9=FEy3Dd1OWGVXw3 z(otMvE$#&u*Uyz+Cb&&R@ud|ltEm*nCu7e1R&r?g=R(KVisx}+BW(mdv9&cVs9O~9 zeAGoL(VZ#s=>3>)69+F1-5^RG6u$Ur@J5u*&x=c{$Q-K8o(=q1t!Q=z^d>=WT>&Qw z9{!*p&-Qg|fx$J+C77Sh{j$aLCHIiiqOSy~_mIGrK;fBS<3dGLn9@<^`PI(*s}<7{ zmEbe}gMTt7b>KmI88mR%LE)ZQ{OOgrRGFpBIh zS1xy2#E(T?1WE+KsJrH8UX>ne<+>^>91a5rYbxM(6=cf}e%dp#cmGKBvbmtfa{-ze z->(%X0Q`S6n{E#9FKDGhAwYvJ?v#}favX{}?+b31hFi_J@bA|J@i|fEtPI81 zEt~|ht95XGO6Y&t6`&w&p|rx;R8ysaAwZQJ8u%_iquE#3k0AAZwrfkFd6OnRS&OW; zJkrB^-k2{|GAlz=Fv7bXRFWz+_$Bc)I$CV&fQHm_i`Qm)zeCHrY%bqlOEP%LEzA-el3sKH zq*m0Q&yVFFiW3p8=3s8x%3M((%qt}C%{ct+8J#MTavcI4)^8OYW6k^u>vGvYz?Mv_6E`(ZcDz*1NU%=d-#8=V&|A1VSDD zZ-a!9f;8?We$dj0ii8R&;Oet<_iErE3Vz28UEB=(O+ip*Ee_tv5=lZ^fuIL;15L$g z19uK5q=8onl8P=e4d%n??F!SrYCwe#=xd@M@?~^+M{0cW!-Bg5DE~$w?sK~Yd)xNR zA^FzXiW&f<&s=`Ec6OP7gH<&=1NyBf3P-r^sWO*g&B}6~VS+*;esC2N!454(Xg>fS z9j%3R2f!!H{SJ6O2%zzST#0Z}Wu@l_3J_m0?mFTtgEdc43&5~DT1|Tmr@Qt$YYGf@xpYxRw0-_rf@I5-{L%DS_z1Karwc5FSd5B5# zZv{y;r5ha$zYSjOO-WMECCM<8IViEF^v&L8AABvHtly$A=e&#-C~$8=AIfCFiAk%72(^UsI4N@9Ow>_k6p# zoJ|U9epVU)?RxN5D@{`FkiXpSVO;02>Zse@r;v{>|BQO-SM#(&N^Vesf%p!uyy8nRoT`4#H>`fbU1(ssFxkB^GoyIWjM1 zabvT%2?hK`=A>aA1l@*@P`DdK5sol7saKd**MEBB5v23n`)N~LKTVwaTRg;Pp2F*Y z<)mi3jC&k}WBwWNcbD7rm8tsut$cP!N&!Csl=;NP2>!#>bGySS!chI_rz^3ViYkh~k`m@$sngFW_h*N4Dn# z;)<2L_LgkeJqUfa%EKH4_mborU& zNfrGzKBmm^{i^=!)_wormU5R)jQ)V0Y2B@yj(iHs+Ogex;$>)R<+)<0kO*8?0oybC zcts)Tzeo7{(pq6WjKQ+eawT}i?DbG(^7B83Vt>Q1yeZy$7W4?dNBHzL@QQd*Rv9DA&jNo*O|! zN`@IoEw4t0%4(-ehf|H#LniK>sQd4|S6#%+wWx2csjq*Ay?jjjwtJ`Z*Yfzolk)ps zT#noLIDFOeiPoby>iuVxXFf)zCdYjrYKoV4dfdIUu{3$>%;@7siG-!ith}hs?91`n z*MwC(>Z%_{8T>5;W77Z_8*#lpGR9<^YI&7x;-KhcdVc{dbNts-27mZJb=^`YlSEBP z8Fbw37L>NM)_^5pWqJPPIRj=L%21)Qtw-l~yFV2DH>*TJ{iOZHQ5|)dl;z>=?hU)N ziKxX7rR1-Ny(zPQrE*QS>RtS!G&BXW)uil%QyBd>lLS=Cip`i5O>Hg+n=<73!fdWy zje?oQp0}<}q-keg&Y-TnKVni{S7e}P^yR&sf!ZM_vuDeTR*1=kjUq*vr_4pe5F=+W zc6lLV+)*xdVLFrqo^v$$z?+1NoDSMRRyYk=l^!>U8Yp!lNqbH?-*FzusQZP^NVn0L zDe*noH4S)aobS2|C4sL9sy zBog}=v3*04=Hu*z@ojH{5q{^EXG-sWb;Lh{ zj{TdD7l3!S3rz-@91z;%HnY%-XJR*&yEY?{KS}=f(+SZya{{HV25`2-EW86bWy`44 zO2fk{4B#SqyfoJU>yS1JyjG7zdXTl9ji>0L!qW60lS7$xg(i+)=V$Z)&I5j5GMg=? zq8JYrsD|;5SDrrR@{W0A-l?;hA2`1gSkcKPJTuwX;mh|7asGD#Wx5uNX|D6_h= zuKVrw?+q(5-m0)jS9w0!@`5HCN*7W+T)eJdW$|suN!ePm?%f@G4wtJ;(bv!EW63@< zy4cc#(c+Q6X@+vk+jxqXdQbVEC&Es{r_eVecm(1Mg<|y&Z+lYxx0Itl^57`-i-sfnMM`3BIZAfYF<^!iA1>&2(8CJaZIDmQX5SQ0G?{bnsb-+?js5chta!i>j$r<>!DT`?p8hwX-h(EH3`EgWd00 zQ}LYQBH11c)9=M*wRc8Ycep^XjuBr3dpq#d2Q{HHJ{`||BZQ?n)mCcpdZaVbY+pyO zag$wbWWf?wW@J7WeAUf-*=Nj)HdyX$P*EV&$Jx8hhU#y!AbPx6nV*9UokMe(`+a6_ zCr4)(ZH?z^O*17oW{w(fvMq=Mps`4f$VwMp9(`OS=UiDv_sjca?0F z=EuuViBRd}lfBK_ot1w!Wynt~y>Q!zDvI?1!l)es$$E-Ls}m=?H!0SLgt@}h&6|XI z9>Wm1{ko>YTuvzwsjRfrz^Ffo6&X}DvRqTu~qyhzkm z^+^T9!uIz#9GkGhzvJCJ;Nxs-<(=tuFGUNceQ4?v_vVO6ws54M+#e#VNAqQi>au@} z+MC{n@zyi-KV=2H%@=V|Ee@G=cdRGEeP2nxW{Ka)xN&?X?6Rv|Z$VW4EKsxbt`fc` z$kjk#d>6M4#J$lwYdSZM48Xb`(jy2P_iLcMu~VMQ6=Pj5is5msAe2*1d|b|-A}s18 zesmC)I_JC^A@NFX-42q{k%nZ1d-u;WLoY2f7xLF{NUSE z*txTh=jFpZu2s?f#O90UNuBfuQcvq5Cf@v=$wySSJh-rY_fO}a?zY?gGI{^}WZ$-w zTr>$Owu}fqdE{?pYRBKjGqyUhKX*^*WjNd%b4wcP+x4Zy@>$SEidZ*6tbzsEQI<9! zL2q+xZ}C@QLOp5%U{D)H>=H+~ssRG66Zc8GKxl;2N=nPmxD7(nl^Vsj_NMQ=I!qaJ zgDOd$9CJHKkv&NkmT!b+2;$sG@H0KIp$Dm(55r}Yq_?1uW4aNWJ+uenFhRar6FDZ+ z&3)fs=8f6I_msuDscGdDNDW5%u6D)_RJsF_rb#Z$Nz6dk=x)KPT)`OF(+YRn3omUI zEzJ~KDCr6%k`|-01P!AX9OTC|$&1B8@0qBW2WWTK!rpe9dF2z2+xH54%370)=B^b( z)QcX|idF|f!|`%o3?k;039nA39*VLMQI|McOeiir14t|}4wVyAmt3@9E=Cv1HZzU6 z#R2AJ9WUh!Nb+%Y5~|YJk&x2#sIt@kWuzgH2nKXgp{QrAG`D2$Qe(Iu-}9oiLD^rd zN_T}vQMPAy_J6O;Gsze)ZE2hE#DWuFtT$s*SIjRVTgtg@DeR?axw?X>Y|=|;;c;-` ztXe5{r-CV6nGjp7-y$@_Mr}~ULR7?NVvrKp$dWJR76zF^GqPnl#s0CEYQIo!bX48l zsbWiCzQ0p3arkmu;^lUG?F7kln*=|tR^)04YIe`1Hub_{kqCx*WnJZEL;w7do$4{^ znhEKeQ~EV86Kh_+tkRpz*oZ@YsC1s@2(L6&4S%T^@ceJwi~n6qkh!Ml6)9(Q?T0iP08rQg3kw1G0L^>glR`iM5CDLI0eoTb z|G^7BU?U+EKvZx=7=Zup+xk7Ij7kW2zpLG+t0j0o=74fL+O^p!q`o`KO|bjPvflDB zcE9adcHyn$QE}|2XU#qxdv^17&RwrKc>0i3uG$Hf#1+#(qgo+nLY0Q-Me<);>pZNs z0~870__1iQ&q?NYte+m?|KNN5??>{#zv2{FS1@+L{K1L=d=Z@5=QCUyjIS=P7Rc+l z;ELY!wq7}xbP~chjB;5x-t7MrQgYvAc!Z>Qy71HRPY42c@+u~7$4~7Db(UHLu`Ev%8{d(qO}CqnXPf?L%VAIW?zFV}I|poxOC!SnhXO zE_uXKLt4Dy(S&s#H{0N9ME=r(eNWo|tD64rXTnb~6Qck3OvL}sOl&)eO6>z*L@O`d ztRQ88TjVt8kRh%Se-8KT;n&89FVJuRggJ=Pu^_b&&(~m7}7(+HC`Vcp#g#a z|1Jq1@BtxBz#c*6`TsLsJ2s1(0V)M}4pM!^Gto*i4nm*B>+-Pjv-XP3N>+sY2K&o4 zCG~oqDASwDu=>f?;Agv9-sQI|o60m!3fWsDDogj1GCt#mE%)g8S(g}i4o8JJ;@cX9 zd$}Mxmm5}z&aw@I6H0n+X_Qly0W-QG;|37BFQh)<(8eMxkese>wUL$_LbmC;)>MF{6|^cqmA94Mmk{l zv8n`voq>fj>g4NXtLKF(^@?oA>zzyf6~V5%947sfT|b;7V`6<%s5tVQN{wPmaedU! zAvcuvId7Yo`RP#d6Gbg*+w?|A_3XlX) zltNaRoZ((k?Pt1^BZme#E>K6O5N+NOzs8ptXXQTElf`|zWy3t<~2^?RruwHZh@s7O^Pe6{y(a<2tWc*1Kun2|12p?V!zKIySA4BDV^f1p>5%KdqUW| z!RESwB6v-9tkC`Xp;EEZ)kbk8rQu6N|KV7Jl7*4W1~FgX4Yk}Dy-Laul{?zn=uERu zQ#kN7An0`4@jy)#1#El#gg)pC=< zi{1!I$t}KprY0nESI(iGJ=>ctp>eueVr766g);g8vnqN>t>`Vbbes2=3g=ZzImaM; zS`@`kknay1fIrQ&=J@1YDmruH1wM}#Sd9*Qo?(KgNh}^md@W(3RJqN1v*$9HO0U?~ z-(@P4X*GFpX-`5?$U=!6pMOaXhL8WVTr9i!hJZZI>-J19{(AZEdupBKtE)#kc?Exe z?q%8RN-cc6pd2{xHXVL=iI;)48GI|jH!=5(2H>}^rj5D<mGjkk_9AR`*5 zGDc03R@uIEQH-k<=2GK$HSLsWeeH2|kI7Nvvw+!|@`dAVSF8Dbl)@vQd6!O!2US=G zm@QRk5d^wOITTh%xFEYK)Bp`|l-vk_NxN`RPm+SajoneD3 z)4&AF)ob_pYq&$1;;1hj`vv(y-Y&!yvS4udJ zafHJ~+CSNVnk}$j0be8k6aVP%v`<-CzzMol_AH9VEUNCH=KbseBO_p8%GCT}F!1E=;H&}2ITLEV{rU(cO&P}_fnM`$ z4gA>YMi+ksYwh6R7Fc3cC<+=x?v*lWZ0^BqWuMkXP+eUsG-p!MH!wNE;Q+{iL1t9tZ^q*hX1a1( zE$r>L4=8_uKeiDFKT;=d-}=f%uMq{=5Rx>zXz8E5%yqs4QO5}O%GzmJreAAC zFoSb={t_5Tcv$o9i(~K;Sx;=@qV}w?Lm~@)UCq}1Xw4=C)lnh5uX_w6JD6`#C1`gy zDj;M22MW#>wwZ%KLQ+7||0d>?JEP>ABz>hm5^aqpoRL({97Qqe<5+In;mmAh5ql!T zth3oPS^zOF?ZaV5no;2)B+MEax);JNjAzdIPWSd2f7dRMwSin70x+~VJU*NXzaj0{ z#3gpu7My3(W#279^daIGPp0-t&q%_MkT(Uk*@2}d6syC7w8GeGCEPOu|Kn)@NI<4# zy?3URWL+AmP8DdFC3GxQ^(ocHlq67LBEhA*^{kq$yvN{1Xp!99iK*k0UHNP`wt z6-{WYm7X_X7>#KoBLLS-9UFlk*E?TDM_8Udp;%!6883)t_2NE`^})r2v^0e0op)+o zOqYB`BxC3BKkUA$XzVn!PJ|{*w>E?V%lChEi%x)aD!&G}55M8R*=lRo3PgQi=K1`+ zw&%q$i%m+CI8M#)!4#sw6ynSn21*&$M#i;~si<+mH5ntmMZ z(4KQi)I4wTp4y^_d@Alwhz+8xH!FHsNp?|^C5tI%d?Vk4uvxaI0ootiDTQM3opk8reA-p6r8AOL`!&o;{%CLdi*Po$oIlc4T;E z*%t%vWj0M0jt@_HO?}>)W*0uVZR;jj(Y_K705Q4Eb`mXZ#YDsU*MNPS*@5E=YJcj|={LDY0os8y{OIKZ&h1_{+_U&Z+O* z$!6%d7d!rU=c$U4_PXhUcD8iGC(Z(gVaW3>I$t)A8?9IfX;(l}TkG&Euz@4Qn7|(k zz^7lypwmKlf#cBK+~$L=X}_IHhV4Fow=79Mq1Oa*ti{I@J8l7JL|BZ9ap`JmY# z^y7``l5?T&OwS%3VEpjQua7Q_6ykYyHiw3Num977`g|T_7<>q7;PrvM( zb@6A>v&tt1>fP=!_cI$$zg-S~{^!G=-CtI<7WW>Jvpu)l_FSLIK(Q~P2~$81!5OnC zg(>7YHjiJB$!0xieuf=XTwQ@w^QFh4P*m~}VP!T%>Y`&))Bs9RX_iYIOi6iV9S-82vs#|A*n%7QEDQN-457}uTN~by)i~$(BSy$W^53aYQ$WsQWCSI$HM|3-vM0lQ@RZ z>lao7fc9aKD|{-VM%-h8iuyGMm)k^b$DpK7T4_*di)TQxxUx|oBigC4~ogFMpq&>|l9bx9;wO_Ct3CLBC!}=}3KL}!7(MYTEvIO}ItH3rlM@Ou3TOC*(Utim){k~g{WF4r7Z%dtOClWmQw&J+RI}3hV|^tcwX5 zFV(6iP=;8L1a?&{>$t2HUT;j~l`VYX1XS(wY2Cii2_6C(jQmD%b8ts5SA^Y;KCY)w zv;Z`yVInrjDBXUfvs>D8mH<`4tiPUCnq9EFbuOwG1Z!f3l~q&tUy$yBZY8Z1JuO19 zY`ACOu_YpE8(mUS2l@U#{3ECFddU!HX{{W6Z9|NXXQ|Bz(18%tO8?cZ98Z^Kp$a0R zI}!PrgS5L*HZ@)LgJn=i1HED$EGI#4eSuT~P}@{bHg>O1$HA(M-e5r9%hENe2CB7GRYUbR(8Tc!HW9(8+%?=6ar4aUhr$$U2y8}u8 zxr$O$yI$D?DizRy*r>lOR6(5Hx}nVXG}HuDLrI}%y0_$jq1QjVQu`2HYcymWhHS`y z|01I3x+>2|sHCI*d7DVd-)Hya);%*YyV>x<{<2Edo~W%$lh$|xDzf;fc*lO^ z7U`zO7V1-cj@r*QmdPFquoX4Dm6(5(0NPWc6`Yi`%508RMSUa{I1=nwdN4h9Ft5R| z^Jg@TnqSBq7}-S!7EiwB4YfCG8If(N*RStz=%x zZMqPU`06C$`%8=B3FfRd@;Mtmh(@#)-xO>U$9Xq*xmOSDw2q6j9{!fsARt~12FwHQ z(L?>TL{M+o_xsR^gQE1|uVruTF)x1KlDXCVgNPzxO@gEEEE7+8)gNCV+G{i62OlEG z+4l$88oK)f%XsklRVtrkeOfiAR_WfRS3P7r=MNPre*Su)G`r2V5+wHEN`2?_(aM#X ziWa+SG4HOnNG;K_}t^Lz_-%-W;#%B z$*tOntpfKd-rjeeB-(Hp$5Xpmk}IS^5=vq|P_)0gLqcqSaZ6~udjIRyUGuh=p%VR{ zBDqZHDit+E1cAgs^*p0zX+rOA0qr~=Rv(f}xLhkcj4Y!-N4lyKsB))-r1$+ku}}=w zIEq*29r@0ILAnKR?idj&p~rrtK^6`ZJT+GR7dgVt*KD`7@BIuzH*@dIl9IfnIe&{g z?~3I~CVE{}W;d4GCuUr4@9K|u*Pqo4z0MMQ!aSO_DtsqEfkRLJz79K54)>dvbE68! zOYgJyrOl<4t)`{X_i+f^VnH1AVHNd-*woyN2Ku{(fnGag7v z);rJ-zrhbcMvH)y0b(mWBpaQhxTfZQ(P%2j5PVdb%>qu{fI_BkbcvfER@VK4hRbj; zc`fKN@PSXH`XF_Zfc)`u2X0niIC=^7YL(NV+1i*gt}%xA%|g0y1f`=0iC--9K*+EH ze~tM`7aJ?R&a`_ZWX(f-QM}4Kl=EXu&!M z?V$CNmAlr5j*Ej{zZ1<^4g0r`)E4A|6>;pvIoQE`Q{u7=+eb_P|gri*&rspq?? z7r*Xwe{cMF-mCq@hwmv9Umtx~F2LLO!!x}ox?xNj8*vaG57@0i7*X+K^1XZDGbJd28r5h9OMSm zQO*QavHJK`tgw6V)7#EGqle|g{4S;MS$2nq;+3}i(Uvw;ActH^}G=t64L?s`?-K0>H+qZ5=JAX{Zn9zwa^;YQ)FE7+LREw4rO?SJL2P zQ+l(3V#@5-#6rq0;LR;zij|_x4iB|R6*lpQERLamQbZS~=d~x0Nok9hdO-i}tQfbU zzON#8iE!f3zE5Kz4M+W5V*>|7!0!aSJW>$!Bi!kd&__Py`#);%U+VXtESQ}T=neVi zH*}y?Bcw@ZF1$9|4@G~iaEdV2Nx&)n?!pWc@O0jv{*y}FFNYhAFWaMtlu@nA2 zow0jAJbl*o{oSL)f9rR;#Lu4L=<)G3)gEhp{RMJI=s3^yfZ>Z;XZouJI<*%yrWYXp zehod@R|n+lrNsL?5EC|e9YS^4l*c5#`|ZZHxDdEb!fG0gJHO>dYda@zTUd8={$cc| zD}Nal6W!;1-D972HTUbLgnaSzx}|L+ifekUngg^M4c8%M@9mJAKU?rtRqWv@4=`k} zapF`T$JgXfgy>zQ>EF_#Hf}ZG8blv3URS8GECGWq9LS`#XJz(2KZs9wHvf?4K1e=@ z%cUMi>F*AOu$05H%?nHv`xLrqFs1B1nFO|F(SpJ_3cmBzM$!!2VKIoVkc>7>|VLl z&ufsPiv9EF?|WEkop=ytnRk99Wbdao?{iOt^?jlSR37@o{JO1(HZA|72O*K8Y*3=3 z*H1P_e#_DkIZ!g2g)v_fp1Ge4Qf;SXpll3$v-SpIZzYP)18uxz&3<|1Y9)(vat^xB z_!S<37zPyEs&)jFI@uToUOXAp5qRkg-7u&!xS=EH^0|J);F|c)9l=*GK#W3a8LFKj zbwxHtq1P`3b%x%!O8@QXFCnYL4{Ny5W)yzs;pfiq7w>*Q$W}ajy7ZpkEt?Vlr({f5 z+TUh+9K}=#g171czbTt?qS@U$q*-#`1kRPk3Q^` zkAn|%QF+#K=R2MC*vor|`Ss+u(Eqr$c(mmHu+$q%H0M`QfB0;j!nUbk>_P zQ~J_$Wl+Rm0tX1!`F!I@zVel)vzS;x6GrYl(G-sMBel_<7e+_O$Wj5o{ey<^RSg6PZd#>JAF)F(HyEX}6b$F~9se0I1ZkBE3AkccGz_sPK#s>B$Ra{c$ zarbO_<3)5fOi(5E`6w%Yndx?$Zb@^*Vk1MV%}(p{tP14C7z1LMtr{tE5Ym>-Fd`~; z0lXAtMz|VPJ@1Qa9%XzgU5C;>HqC&>>UHyS&2XJk!sm|x-~nP8 zk_HNLKkc4+x%XzrFZ7mgTiJ`I*A|_hnY9X&8(~#bp!Yrm_@zr%2u zxX6Bx4Ko9m#I!ctoqgh128AVHZ4Lj&N!(b6`}(NgtR@ZQT|JLuQ}HN>c43Uqyu9WE zEJ`3q`E_%zEURkHkhO$hw)gHUo*N{%V=(b{nb>vHiL{~S!X!>F?uV(Z8u}T?n(8mN zLbWx1sen9IcB4qP>D#G+9Y5^G^u1t{A*oIpGGIngPVFqiki2%A7IJOh$~M$^icdqB zylaG=^ytUD63%mClkymXr+v!b2^~IQwr$#zm{?ns~i8{Y%+sP0v}tFmDj5M{P+iYLgPiz*qN%?qq@cGasn zyArbh#ERg~zl!v%bM`GtASmHa?%E!qm|w?&>*N!w2TZ=#qEa{KaW`Uway~W}o$uRm z<&6!PCXCx#&T?dT2W{CKG$i>BMfxujYP?lzA@#LaRy)cj}?-AxdfT& zbw<=m)JIQV$!G7lz+c-~ZEG8SK})ODnMFjbcKyq3X)xBGfVdJpM(RIq|2d-J6BC z{Q&6lnau~t%Il0uCq88YGA*ncD~-Cl1#XBA9<0B@T{Mcv3y_~G-NuI zl;$s0B6`%{woH1doWU&jNEUAaU76j1>NKgBQyh= z#1vk9eTU@TnfjaI%b|y6;3;>KNMnnQJ7&17qk>NH5=!wzx1g2BT1`YtwLvLts6W3#h zi5&w_E_Zhc0^xg2%5xbp zXc#tx{<#z)Ny1>*w~As!@qo;PcIeSenhb&F%6t%D$DB?BT3Rtuc}Ffc(i{y;RKRGA zM^-cpYOIzH?gL@f7!N_vvsgw_1@!MV5z>jyMGno-2QudZIx*5q^Pq(cG6aBt!?C%+ zL`JwEX)2`<3pTz#|L`fOL9TuvsdeB?m~PuGM%)+(YgaH`0ang$xX?#4r$PmAo$z*s z!TNwkeKi)qNL}j5+U`kdgz{aMYGv9@LrPFs5*Za0x58(uIv%nPFB3D*DPYXw+>+%*+kbdWHZ(Bh^?Xxk^u2dY}lq7UkMB zJqAjDrYS(CB(*arL|ee@;j=KaUnQvY|r zN6fBJv$SB+@gC0w zc$-uT<6C8pB1iK^Be1uQ5mW(opo|`~W29`;@73q97pyB~ZxIckQn`%i3c8~pHzYP4 zd>drn${;t=;=8oEZgavVFFv|$!JDPoueK*s8B{ySQC>Q5|6||#2R1w$aCswWsd4et zrl9~k>|X{$NTTw%tJ}2esV)!y_7Luf zRMvqzH$msOM-n)a9EImfId-yI>bPm=w=vJ`D?o+cHtrs*(6cO6w7~muH_k2q8+HIP}v__c=)M7VvN?w9t!YaEf90{DIL^ zkxI=nVlfEAHPy%QG*#&ea>AK9&0VRn{q7{_D!0V>ad%GgF8cty#U35Q%OEpZo0iF-x_;blU0j zC`8jB<>Xc0P{kRC~nX%$DgrRggJnHb-yMj#=$uGN5O(>7ng(Tebmym7XXDX-LgHDy|%t%T>;%pXJdb znMdN8U1vS$d@owS;P^qCH-)#mlPC;+cmh3`LyyniHwGFA%#1WY!1xCcbm3mCby z6wRcEl9i7%*yB7P=dd9$+l+*?FJ}koc0i%vv@elqN(tztv+Z=%Q~9=s-)fu6m8DrE zlc8Uq(U0~+{nU^qOWjFCMrZ|{x;nBMlY6GcF1CUmJP678-JOmoCH*@=XM>Zr8S!*_ za0TQlM+;l4BWzU$`~7yv3n}2pw9iAR*!|Hnkh4n=x;G5V%gXYBhGj#-sSw!R`OIC$ zc~%I!e<_X)y6~CYJU<)0HXFOOJQ_!EK4$PnxcbCvI;HMG>MDc6ERrG7QIQk#k+7!yt!ui_HlJ zDKM1_c4yL;z$M9?|ESROtI#7_O)=fk%|x>dH&rrn}!n2V{5dPhUCT7(k_D+qN5B&O4hNl6!op&BH9b03a06 z_)z24HTZA(WDd=Zs%78!S#oS%vZCOf^7oDJhyMe74BfdPXO|$KHC^EWn;c zQ6b_kjS&QBtQs_e4L;Eh@ivghuL_4T=|>-K9xbAq3kmtLHjmxgycf6pwDE0VBc!7J zm^Yg)<_|Lop`T;li{?R219bMz0$n(CD}87LHq)04dHnpoNytyZXZg{E-<6BBJie#_ zqel`LYlj$T?dY*{z@yB@n8AjKBzhp>vEq>0l$?vC+K?y-Nh z`uEbI54QR-xCD7T>S0H^WB94u-(5RuG9z#x_+CfmW#QKgZ!W2Ih9h)}acy6J-ovQh z8~okPK;7`l$sB++%+)qkSFN$2N2OsY=v*2$m&V~hT2C|di65$X+A4RJTKRcmwD>`Wcx>+Pr{eu@4(+c`xVIPCd7>-F=N#f% z(CJFdssA$m&E@{PYWLC;n435P;pY8Ydi(F|+&^)xsgU}9^83FP1MwUXL7+8*)7 zA@OF0_(!gIt5W>)hWOVH)e!E5kOv6#W6fKDyfYx!Ka(D|Cx!)AF;5y8k?GCzSMw>H zU)JtBL!tu)=L0!Uixnvargp8`-sQ%7Zdy*1>J6XsMy`6vuj#+2vCmjtT39m};kf3? zZ%bS^9If}MJYX6G@xom8#f9?g<`#Eb1x1Jcse%meChn8c4?Onf`NTEDU{=Hz3mF_K zIo&5)#>{&xA7L{JDck(-eTCtQb?@aF;*>bs>>4QHk4;=SDZRnGyUcSJetSjv>Z$N8 z&eZc-&+_d@epxP#-P{ult@H4!GA4!!>4=KkB>ai72Z!IPA27$-2A=3OTiEXqWTm)T zwfPNqAB#-6j6ei(k3Y7Lq@9C(TV8%>T0Z8LdVT0PixgEQr|5;kY1m4~?K)VRb;0Dl z(t(BV|8wzm=keTe^a-wq+_QxaSBsUJXpi`cmE{5Z$3{Ki!wzo(`U&j$$Pas%h}t)P zGv1Y21x7c!w9jpOxHaYHNDT6~U#y`N*^H$HJVPsn`8@$?Zgr=dZqDg16jMzj5?3(hbeV0jxBfJ zMcP)Zhh1}*7X|d1f37;_mn{|&htJO#-ki5QbgrOhPY?P2{y94<;PIDUk!|y#{0G7Bb?Z#q4W|My z{)m>qN!hbG=mVJ1o#@GGofmY~=osf5EZJD!}0qz9e?UHGIl+2Nmxtk@WP?T@=! zYFzBJu-xur+*xt#rm2;ehCK3CD_GBIv+8b}!c>f}ulYxVyTdv*kK6;~>bG9_TksKU zeok9?!5@4Qj%D{)T7K~T^-+Awn@=Z%O`1k&c1h zf7r84H!Uv8SF%ZeHaJXX5o_=&f!BP$0B!P}0i{n1r7W$yRHOL|>WD)*fTnZ=}s& z&Wy1M{ZrX$5lm!p7X)9hoHtNljU~HVrZ3-|yrA~4^!&*O zVs2sLh|y1pG{rZ&NB%fK;Qc%d{I=B+;TYp3AGhG?C)ARmHZQ0gtebe6=#gJ^$}~pj zoVLEc4m5;Nj9cR(EiM_!bbG-ZXUvM}-4qRHa8L55wn8-k5H(Nhx1^4|Kh~|I=Cilo zg~dNVQlyM)5R!Wr>HWMn*QMi1JRGLXieGht)wycY=+%+)8HSY)UWUcV*#{yQdxkW6 zmp?wRKX*PoBoX(u%L5TKRg^Lib@x82NZnNd99|zySTXdpm`EwQdn)0eZB?>$-Yev* zJ^}6}XK%7^B=S=q7(YvRdbNOeHlahOqyBgwKMID`FsyncruEyb6Yu=;!fJ@WE%!xg z2eCssbnMPdf$TQ}QAZp3sz0%Fq@hgzU>-o*aeysdS?YPeSxTCL4RUNO&1Nr@CsV^b zom-eJMRDG)8ogYB?eAix36KxbB>!Vs8){$ z<7K@ZwV6|%PE(@!9mkF-%?WQi3Yo~yB`*-ubeO3x6Y1osQ>EG__O>KBy-$h};NA!L zB9dMedEPyVo7L-kscZ5*^Yx=o_T1)Jtuj!OR|N)plT3VJ=Snw4XnqAiG`|}n4R|Ew zjR7o{MAwbsP|G&xo*mtr#V5OTP}s5o<6MWCbpTWSXKSw0Pz35EwFw@?XWFdu?`H78 z)E~mLEIKDIL(%BnnsCE$5pzIr5gh5!Gdch)XC?iq8~%yiHnhQ&+k3tC>Z_|T=ZjXa z3VOb1T1{BBf7e1~l4LY{M}pdC1M4$+l&?B}R<&@WPQd0fS- zj{w2u|J8whn1DI{!C~^gP2*0Gq_LxXWH^8fe%+O_EcW^6pB11ZbxQ|mo&}Sgd#WJK zrnTxvwSrRT>joJ{uGsfXRKgfT);|xpu;EH4Opp^M83og2?whfQ-`ZvbsPhYN)SYb| z_(bap-6^1+!==OomP+12=C?wvre;m=hpu*;%pzhhDSRu;6BkAMbt=T{qx<51rz~ha zNdo*l;J4Yc1VnjXhCs(l?3_j>hdxs*uzqs3U>AH zWjnjEN7FQ|t9(6#B&(W;p*I>YX9Tu}V(8ei;5Yx8vm^WdJ9VW{uF?T5vQS-#7ksvcWT z1hFQMCc>;o^t5+?%_DMlGz*$qds21DOA7+~c$V4-nb;+8s$xIO{P_8=z)nIdk7rqL z6^(eq+)6;^2mz54{%GABZW!XkV_U?tbft%#8dVSE30%g&HYFhjC4#0d!Ssg8zA=U! zr{;P%OV5}6J|9e9=GkJsZNfk}D$Ay0m#v0Jn$~5<5VpRg2V8j3sTX;mzHmoSPs{|) zo~td=lXVh;Q|^U2%!nyA(w_1(;0_@Wq05Iy;EPJ#y_nhUjw(v?jf}H z*loR7d&(m&37o=D7{{(sydMO))U{gnsQMSNNi;W&~lkW|4sCNw>>{)LH*UW@j&@|ff z*%H>gd7eAMlCm1f)*q|ih;WtM)@{9j@Am{wX%s^O#hk$20Re57aYGQ;1o^SpPF;zM z&ea?Z{@y5v(FU8l$;Y*WdT11UBan~;=AkvyUNLp-r!w`f>(k!5bH*Je*oi<8ei`H- zSxFi~(L|70>l6_JHmAlorm>QvxM}_d$G2ntdq;^qBGL};8H&|Ix&7yq#GV5J5slP7 zApk+6I&=Y%biH<~5R1twJddXnQfyBHl6TighqEs#YNsr?%MmE6??5sd5O{XaOFs%c zJ{w;lut!rwdIS3gDc*6fiIywuXJ(T`tjxVg zee}FKDGu-DR$$$Dn90+boxJnO-e|WkHLCWFHA295l^aQer|x|H#M_W(IIeY8Rr;5g|t^= z?Skd)GTUZ>MF|PvHLvjmd}brwqQ=L`5sc0jQ(cq~Wc9G|@eET%8Pj+Mo|s7EF?KBb zI*hREu4=T{h1=UAupvObc$VrPB}%K73{Bu%0!HR>LNC6z-87b5BAmt?ji9t7LXLn6 z?HzmWc-){!n+|QGFhM|>Do{!eG}HA~wzFVpFz)zf^UHsx?GcC4Q?)WaQ9^y1=KTiY zbV_v-`KR7K16$ygFmDS&xpM_OYs|pemQrl?LaCW*-SzClM5$IH3>oI_K(F~)1*|wO z5QmVlmZo@LiG~AYGs!-Shhkd=E@>3_{L@>33&xC@$aRGRq?_q1dm5-B7<6?WVArH5 zjbj7@e^s348_iOKimTazUU8E`J-})n+-O>@@1@yA_+~LFaEKUy>k3{wxqeavVwcpO z#P^nd7Fal9suM}J5vJ2+m>m%I4#f9mD8*pXh)VQ&z2EhSBCyo_{Ohdbt0yFaauRXL zw{+RpqAG~;;+b2hZiykwE?Zz-qHaf*D?>+F1sc~W%Q-)1LdlDP140+15<58w3AuKO1Vw zu}_;K@c=vW_J_^(h0Riu*KxkJZAOQzN|h0wRY*Kp5y2^`F^q z$}(~T9pn>;(FVhFbN?c2U&u?lFi-_rX&DX<~N zIA-ps{Zy#?;xN3PB%j8L?%{rD{w^s#I}^YN$;R~1j=$A1s1l0H{My4AisUy?^!KP! zHmhZLcr6o0XaPUJpgQi<+A<#fi0+Riy|WOK&O#<_<4NXc1<&({GJ6ga^3rJ1Gk;F7 zFUC|lcdb8M2isJbq8WUPdho5%caRMiNOIM`S^lKM@+_L_7|>w&N1y=zH>s)OcL z80;9(y0r$b1S#C+haKY)Y}>Z^iUteK>?%^WC%D>%NMABiaqckNd==+h0e*Hu+zU5l zJEu)9O~`#&XmhR5tSbX!CkqL8tPkH$4??eM9|uXMafGSBiAO=6`1sJc=fDN9iz&sx zaaL!5(tMNctlMeufersCrBaw`lv|?}$K9-8&-|g-#&jBg*7+h56#q(dnz@~lxnPCu zU`gYw%!-KL!3B%%rUlz;NWEERcP$RaI+@0~HS>sB>1LsKXHR^zDh6MkYC3tR-?%x# zVh(H4K{Z~I!yUci+H8T$28B;i1{l81^A!6Di$pyY$25BGOR%jiiaHFj{R7rW-*gRp zcA5ckh1I{k-eY%4fVl%u`6KJ?VIc~9{X_reSE|Bv3BxMu!d1o$xlR22dLqxfn_^eR zFOOW!7xHXcujFQIO(`ER{?q8E(_$Gg^;gKSxwBLDSBE3ZDo~z-#`oDQ3#<%#981{v zE;c4t^JUJmbnuryr8w_>$9>cbUifC_z7}jRcgLiGOR@Re4o2*ijdL(vMGKDi>a9e) zy*FABqvU9$p;pZpCODG>sa^|BTcC$GW1M-e@W#!k4Bu$66fy!-r~hAkU}x-Q(~59* z)ENj{;~1Wv^SC6vX@NP~O8N7!vlZpgCWa&(iklhRJYrzq-47N4}yQF=%IoKna zzx8a7oqEsSk#^f~4s7%qmR6VAWcIEO8=8~C$Mfk226@%@<*iH^)B?wD<*zviEYoyfMta}{4gU85eFUY%& z79|LRmGN#u0CsqX<*%*_3v~BK@+wflhXo(ngR@@pLim!rAuc`kn)H=7j?YmntPgB~9RmsZ@E~mJ0pQN^ z)wyW`{qOKw$xc^Kdn4PF_XzI>MwJI=jTgS|7H`-&o{$~Ax4%+XCBnisV8r-3+ZnJI z6Jq~3n02xQ^iq$FS5%fY>x_<$vx(Vn?d$qs7f79Lb!1VH__X)-jjxtZ8MaH{JBQt{ z6%^-g-xVc?b>bW%zU%M4G9)kq<%Q)mlDB!}Pu7iC_Q4?i9`Z_dm6U zr8oO_uUu0omV5aX3=`D#pD}7#h`!N~*N<&qe*P!~++TO%2kW+Bz7E&H$RDNY9A|7Vs>>#@gBJ%V%fWMH)O>91u?&-q(HxR$dsgrhxC5-Q{=l(4tR~s z1cIexu23?uGi^3I(B=4ZRpIxKR@c&Py@N~_vlE`AA7{{-G28#MyRONkzs}h1TgLTH z%x)27#s^eRuU|SB(J?)OefI6hQ!T~T`Dc2}iO9;A`y_mZf-!=XRXC!Ew7&ZBnHjX{ z4`t_DHEpgH?iaVJ#fl$ zoMviEz^z8?z$+Mz5XIAiZlB<{br&!=(YRC9;YSAn?&|02lr9d!u3k%=G1E+OO`@r1 zEo$ZPEyR3shyBZS3rkWs`0Flbj9C!@5FKSoRBo5|RMv1FsV1jQVXwCqgrhVmPmfGRQe81{%jrA836ZHtm z$6=aBylhJ#M^;n%&udc&eFwq=8YSH-?;jZ4K2sq5efnYov`!%ipmikby^o1ZPWIRX z=(Y6LTN539_;cu*Q!OFS@^$HeLwAXgbWomSk6FJ)3UuXM5CUtnBudrEN-azyC&BkMAsmn{fzV3(Td#|3X=Bwrzk35*OCtUO!xx8b~eD>9q zCx2jhYoqElb=vbZ&#T85+p-}Sp0~kpR)aoKQvYTmV=RrNbkV9%ObG3z`{A&s2l#_~ znd(`e-UYNHU35EYu^y%?y(ebG;cZW20~%ewr^dJB!5l}}4LP{`kLK`M%MWs|W-f_t zXaM%>$0i@^1X6x3biM1ZF|MC6%-0?wCqBkvF~wOCI>#c_f-lKGWyeag>T_PuGAaXc z@*N8z=MB_raJ_MhH;We;yHZwf{LdtY&6Jo)ezV$jlB=SVxg^otm{3l+Od#L9HYS%+ zMZtY5$#q&6p_o`V52jDZfW-3KMUY9E(9xWz@=N{{i8}76EoIUOG?P|D-pX#mZP1F< zf~e8fss@#SwkJ*NKQlxjSf#}$cs<)4 zNqvrsZRmDIpvLTBai2?Q31}y2=D_V0gqK@c)m>nc9!RIk_ep=<#1;r)8vwTK#?#DJkYhGt`{v{WJXo>zS2!3Qc{QoJp^;msI@i+q9Q4nvgu4Mx!~# zVJt;1?XW>s+s^nj7DmfA-1%GE{YTr3q}~}`(heYnTD)OsoOoWR*2511;XQq0Ry7VM zE?b^lqNp480`=XlBX^FNqIY)WLVrWfHD&Ag?CAoj)P_`OGqlK=*JsNZoSct&FO^4) zhBniG*6el+&3nA@^(a$4LWHdBx||Bad?}U0vZpn2`Th2*6lH?M&9O=IwB-dN*FS=l zLleAgdw-l4X5W-_1D@UeBF{AT_DcBED8k3up`r(NBew1V0{g3V$fZr`sLVWHM3#a0 z4K1rqDq>*U67s#OMe-;BgW@8w7A*Ry<4k@{znH- z+P(79H2my^@%3)ujC6GGJIlcV*AfZ%&&GK4X_nXYc6^g}$aSCmoWHSAA?EwMH&u#G z_fl|E61!_rez_X;wO(gqg45WFVlBg`{`(fxx+A6NgfQBp_$Jc^B7;&_vDGQwCu_HK zw&-X!8)ue~0JKwi?YhFN8JKaEQxp}suesWrVWIZ34MmFlUxyjO2}a&~`$6$n|3KT; zY%jgPa;cnRufEI3)n@zav$0AiM!zhEsTjYZMC)kOR>Ss0D1%?sOZfef?&JaxJMxbz z?quxwJCH#nZIZ6G_1hEiglTX*3#{?I))OWhmJ43BHZ1P!4{2xi{8b7yF+5{Kw{SIU3 z8%K$Ob8o&v$L)K-JC{7Z{w3ww|4Ts{NyV+ZH}#uuB03Df&rL#i<^HMYw0tRGBY%Z& zqldGLkIfu1v@PlVyl#fFy4>)5cDet85CKUT(9ul$FV{KmEn;9LliE%A?SkLa)=p(- z{i2<5)(BqnII^x0mYeA!srjGom^M1)a~5#0NHZuJ_eZ1(k4FpnnmNE}R!=jlMSZAF zdW5U_P1Ma9RBJ5K++=2rw`i`CX>=<38&~sBW8(y0)1xO)tX8XTOZz&d)wal=`1D-$ z4=`aC2900-L6vOki177uxIf&zJWlC>7r!A1Y9+dcu0-Gw=Gzl+)%0Y|G5%z-2|69D zNqwOis^_+Sr{fqhafGj_J7v4b!Lb5n8o(OAfSSL!?a4b)!@%3)$(m~M{;s;jiAeC< z7mJ-Og+Y1uT9P#noU@9$g-hSAX$=FGb#{O&%kaR>D{7 zsTDO)) zD__yLM|nv|>H;X|yu#*}s*nPYnQCFF+{*DB)gw&3e_VJJ1A^r%mqe;cTs;HVaR8tp z5mm#|Qf!Ax>uX`dn6gE6a4(T+w@B?8Q?cFCkOn~IXsPo=>eXB%QKab#Jkr8bG&R@g z)>5-4XUeY*)d13xw6J5QTfPFVg*N44$saXPjc2OyFH&t4qqVc=$)`Z&F`h+Cs$l^^ zk;PQZYVg3PsJvt(cIIk)j%*B9eZEhlPo!Fg45AB_uV6H4BhiXl z*idd|N3MJgSDhEBo<)`u+e;d)$S!3B1eLF{PCcFIhT2;y->##WMOGdr`7lWGEI#i1 zN=z9Kk;GRK=IDfKVS`oz3mCFVd^L$#rh%)F{7RW#7B`!!6m-jwK}F|~b;yUX=TL|+ zE$o35(_oS6y1YaOqe?Q%Wj^&i9c=118gutMYYCVy>7P2yDjatoA=P}ju z_;TB|u%=`pUuXdXngx3)R3DR{g-O-+s9Xf9t_Essk~Oq-WLl_7?_c3EMHp#4nVSHm z>NR3)f$VxY_Cjz&Ry(fzxjb&2tYzt{7m`;%*op6TD7@>@4w1Ii->LYDRM7^d5}>OF zG6RV!;{71#SiS$iP4~f@yL#n!(ixOY0+fE!RZI7X>&)er;Q-sQT`zQ@5ouoUa$z17 zNpY+0_dJzb_{u>f4izBvrvO*DP5<|iDBW4xd*>-!mPhKShg}D>to6Sl_J8TczXG7p z?bE(KJzm}&0i6{(9gqNLikD}FW#du9=BSsfT{{syyAZuY;|=aV75y`X?9CgJvj@^F zeSb`Ov3qvKb$GC&rIHLom7#$X9`1V6{ugLoxgGw#mceXSuY-AkQF@*U+J5KDk6_V9 znj1X^jNOR4iT5i!C^~^eB`2FV4)R{UXV%ZoMg>I^_M2XC^0Eq~NvxI^WG`~n^tHB& zqX1H2CYnX{!Q>0g%DdfmDF!YnLPyF?pIAj0bVNMgh(& z3#RPAh5b19r`k__@=Yi!8wY{uL7-{emSi|sNd@qf=Yg8_A`EylQp-9@FFndgxr-K1 z@`9^Y&sXz0#HekFQu*wwHg_4LH1%^(HdCod?+1m?J{czS(*6DQu&ocwq5 zXykG0Uwut~lxT84Xc(K6v$ENJ<3ox+Qf?_{!&Op^?x$}1k!ogh%qruU-Th-uKaRbA zQ%R$yUW!R0{|I!;I2yQpzyAg;_(xi#O?vE}MEA5SY^Q%o#z2ieNNhDhWp zXuragXi9EGM z@-zL|GeYG~NbK%+mS-z_ZAKJwkK5+xos|^C2_g4swZ`FzSc8m=K++8bQ|3vgY>upo zT~ahlNhioN^(r~G00HW&MC2n}Zg^jl}S~IM} zmV?~x2srhy1Ovjo4Y;IZ$y7At2aRT&e{JjY9ash5hc*5>;^=e4ck2gAW5^7RQvz_nT z+(d)qD?)FW61HhR5k+sSDkdAKzLz_!0{RqRFmV%nP-LU}domtjiXRuL z_N7%SmBRAKxN$Phd?=O}iJLjm@|KHhCoAnxKBX5P=p%;sy7B;9(ZbYi9%8y zR{Ss1h3ERORrO@Xvc@R-B!YkPH?xf8n277 z4JzRsvt-<)LvEV=!~5!i`cNp*&3$~j8h)s-`xl8pQcpBir*C_BE=tPrjt1v$#w%9n z(((WOtcTtts5P*zQ-RYolG^eR{@*X6IPKZ75qm>koqExr#4&>oGk|7^>>hsq`$wWc zdKef5=v`Z^!WygZ{pqVckOl8JK-*(<$mRxDGYd($Q|d_JFD}%fy#OUVml< z)#bikid0K;YhWGw0_|Zp)jj+D139NhxK`qOP*UjbjHU)CPl&-sqFaPHhbB(sj#u|L__^!6zdTy0 z=8<-$%E;x=#3|b|11Og--|OokHgVV+(tjq-R3V#jg=-b3UdI?)^}Du9ggRPB@|==8 zWK!hWafqJkU#{kgz}M!WQ_1_xLU(q304n3j7~M!!uWEHQXncv{c?!8pd;~8foBG^S z{l>)wF%^A9p93T13oY9C*(aAoxDswQn~QUsd}^gidd>`OclxN_uoLF~L4Zs8d1X6Y zYY+$_#)Ta#oEUf=`+VSz=teZUPh=O=i;v-V#wC7^)ta_(mb_&*@**;})hc+MzC0{- z_5e64l>a&Ms{Cm9F>%`TY&kdk6cg7`ds#=SfD$b=6`?~+&U`&nu^VT1nr>PW?Jmcf zFP_d_6JoGhSNU!eN2b3WHJRLf%6rvyTZiq)y&D()_NGa>XC{(R)z|Sg+_0DRG_Sqt zaThBy0aEr%IyO@3H2pN%#S(r%q{BY0b1>*4KJ_9+<_!I3<(bZ1d;X_2s5(nl$3~8_ zb1t;}H(dA`pTw0mj8sYjp5R}Vg-RBxqAV5}CDEZROT1@MXaHHcqepq{8fJ<2_c;mk zA{Z3})CRK3E~$y(%FU5;nzyJ=0-SF42=dEW^3lA98K{E}4kX0Ca_Ld;!pI+sXSL&r z^$OT$%g^tMv!kc}r<;xy@ww8wiQ(mCY4u$}&-KC_tls69_C{j}1(xr8tYkboPtEgm z|6&DldLf-&ernRAger0YbO9J+knhWO>~e%ZJv^spWythdZ%nOKAlO3Bw!aCGSJ5!K zqH9)X7*J|bpzD1i<_%TO;$mKVP=#BuwuSfF_;C|5ng-etb%SCOq2yTX7)bf-n-WS6Cw zc^f~O7#$?o{(n;$MBWV; zjd*UwPDp)W|9$w_OJ^~nqe1E0{T_=yio?%!%*HquulP?dOFM0lEQ*|<_omO0ZR6#4 zy8yV$$P8}$?)PHV^7E|0Aa{i5T) z@*%QLL3aeNE)YKN^>^Maw+EX}<&^KT+ikh6(PpD?t6Wq3@>sY|A`nA;`|=0|DL(HNF2$?my?W%hp5(Pik-F)&b#c&ye49Z8yt%~+m&Go;g-}>bb)>Iv;xX{srQ)vS*@o$Kj*Jum1SxO zHcqQ&z`h|6^%kuwvs)TA(PLelM7>G04eN6-Uw?eEm#rShiID3iqv!+EhoipiH5{mP zvhV6wznxfSu_!{4m=Ng`65UEOze6pAt+^o$!|P&d*P9IxOCz4vUJM+*f}$zvDtbL` zu3%6St-03Kr<7Bw3%(sIH96vG4^e*P>lCPOMTh>qsEZ+p$3(cFU3~>1Aoh_N0WRmV zG@>N1_>68HuI?_(-jol%9oeIisZrx3EIp6x$$>qO_sk)(iVoW*d28~Sdc)isWgTEu zGyZ|IzHbUobc4?)^n!tHrGkWI0baE1pSN1sV3h*S&*1~@*3FQ+q7wAI(J&Y70jUEs z)4P~^$=0jfBI7^ORL5Ini+N8O86a8i+W^ek=lWf>2^OO`#?!Li!+5#G_4JPcm^0E_ z?yjn?jQf0_Q|l|4<5|z~vtA%XS0t(r$b`LX>=$q5pU+y144nt4ua=py-9;pg4M4vo zCj)hIxK2HBe&U5B6}lqS(H#Baw*Ma=?9rhk#$T!GbC?A_ruH&m1$3B0d#TpRB(N&l zDOcUTOg&jxhkr)$=}ctEWC|(jnqS{d;s>nTK8|=ecJdGMi0O3J}tjddQ^A18^t81B|^?!tJHWfV?qP(7o; zKVF^zXrZH5Z`hBekWXbzlL&2jPR-*;M}YSkztQaZYO?mFMqOwlr{5(H6X8(6K3$ub zEBA$qO7tZ_#~8CiL2zYley1f)kp3T^Vp1~zb^k~hw05Cr3F6*Pb?G7ms^V?V?l#nJZ z9mkurow`{zdrwF6BYjPLp^{rnCw+gk%1L!92SI|bmj7=_;voN|qlKNQ)%_jYPcKVq zeLTj*VPcze#Xwn0rSXs}99YSJU96Z2-M0Na{=Vo+`;Hok zw8uXEeG&fhdwgr-&Y+$))X|B#nx8~ZOcbMVJR1a!3&?Fu!mza~qBS>Wn7Gg%_eLxQ zefTD(ouzH~+&FuPXJu@nZH&S@$ZIYH=+aHwoFPc$L#;l(?u5aRe_cq^PXd&@U9mPk zo*-osM((>TJ_|moSXf39kgcuvg};mvc&NS1J^Uu}=qs#-^rVEVoSf;OMc>`>E@;>WrL_@|B+<#2%lUpB5alxH-f$R>{_K3@2)>@xViAT5$fw$;9g3=wjXo!FOlWe3qI zzT;|iuL29WxgBAKU%KK2B^c^R(2r986B-U$Ml|FCKU3U8O1v zZivuQ$Q22aiiFfHgX|fRX+*<6Gf?vkcs-i&$bkC5m9fZ^@{7jqVc5-4u}8fa3jk%2aC~OCL;(vj2Kxggv3#0iy)}N z5o0k4saGmjNQJVA1PIH+tQCP#LKf1bk{O5s81hlqVed%Ic|gJgZR7ytv^&j&UX`>7 z*m2XmCU;+-Ly& ziQ#KqX%U*?FQUpMmcX8uWYoE;nOdQKqmfD*sCFV=MAd<1puP!rJtxSvb7b5ZU{V^Y zlL0y$V)VKMB<3K03gxO&r7B7AD+JkP21@6?p?=1`IW#<-3ge?u8%lc|6~M1YP?iJ! z$*pp=W%#5>nP?0BX`ZZR0!-UTrdCG+K|urw#K=m5{uTgfTVnFC9N8Tp_pU^4oF^NH z-YX=_6x^4yVt`FHEWC-*)dq68Zis95;p)L?cPi|AE9!FqEG`=Ub2Fj!{~4DD*OrkZ z%cWO%=>~#xw}EmAT-aY-AK*m@bwq{>sOFBy%+U4?(ul0w>ZYb@X*Q0?OY?i1X4IOS z69{&s%6#B?h?J0AKqi4}7?od8Ij1$KkGjGD;YKf>6lv89iRHAKdzmV?522n3O}tA$ z1pw5KWw|sExK|if%mL=8fGbNRAiA6j!BPte*mLso?n3Cd6}hN=PcCzBh-hV2qOSL9)U`f4lTGA=CsS##Eg6~@8fi7e+ zLy<%R?eSzk%)yDNnsci`LxK*YayLnWIpvf**+MJz)Qe-1!tI0v}vYI&7c5 z?=#0eBhp|G3oH;p&V>=^p^(bEsGqHq##3zO~@+?Wqa>ue^;;36)Cs6f0;7lTZhR4;;2Y)7dXSabK z|3b2tcaV7QvZJ<2E7h$JKw@o$z6mw_S^EMG{k8ChOCb2;)_Hk8m-^APs2+ql-z8?Qw>y5T05^3Ims%A16!JIn~b#MfsnxfA+b%EB&JfX_48Y~Lp zTGtw-U&`o`0MbGd@^{nq8wI}nIfX(aAMQvyX4Jwlpl)kf?%pN!-Mj*T^4o^#fP^ z+TlpHj2Y0gvo-i4HNibV3SxW4ie$9GK@JGb{Y@@|JuuxddYMWGYp0qd0jAqrnI8$B zxtkhBBZy-aFh}9B4R48c>&|9CjV%D&J<@F$dH&I~0-czk>jN?>5rfoP<$g)rY?Q{6 z&{_pPUg#;(E6A}#-+U}Bd&i5|=-9)*g8vUaTioodGDn&M#6l=V zOZFDw^dhmsqOA&ZVUWyLFdNRcWyq~zspm(^0N)VDk^1_BQtcX$WftNpgvqgc|2h9mcUIExcT@mUsJf4b=v`{aqr*^K<*0Z z`s6-lQFPAF<^05tS0kvJvl4jiHbW7Erz~}Dj0t0Z-nT_cf|bITf@wb;e9HjIlO&~3 zt!*kH$PvP$mki{O5?_dNiROue%7*=_TBt>aTqi&|qj^uNj^`J^t(-szC?9#tm{oKE zes_WAv~;78=WI1$*ze{ETdf?+M!n{^Tx+wwgCRP0XVb|PnK1cpXymh2U4J(%@9thd z4dr(hoL|d@it~8~AW#wjx@l%`UrRg?Fj|#zvZA{x{qF=kuvK?meP=aTbtq@qc&*wVcg_JG*mJqA(u@qv7UVj zGk#1#NIyYT6XX#7a91b#yP)B%hyEb8NZi`CA#8FKfWLcyKK7w{8PDIF+6)R&ar?)A z2~m~i3RGgkTVA#mRc0;=eI)?73`o;de)+}nrQDbMCPdtP09b-D6}0Y7T%P{A`~-~a zfF3c19M+M&jrvO4!Tuyh{uR#s@E6(Sq(jN%c9URP0b3 zFZHH?cHrRw^tbs3@ar(2E+m6ieelTlA1xL+kL=S2VKB@3JFNWcf!GaA&%F5@rH=fAdzM_8M9O~Z)%Jb!nn1}2Mq9eLL zJcyE=qv5OH@9qo`cb_*lgf$@3Sh#Z!lKmkm>Z(tRgQd0&%ALLmyOQ&9I2u+yEB9=z zGL49TMVr4uNO8Y#)+uRZ(O!Czwp_KB_>Q)tNAEx1q@M1lJ+-O&<2v%8VicDFGKfO) zN!k+%jZ)5-%9F^nR*>@tneud`(&IgtmOgslLwyAJ%JM$z(0r~B(r{UNmf$RYKzQ+3 z#kc|`WIQqTzw!b$U0Zhee?e|zG{Ha5m~mar0&3#G=V{VEljlh&uQThO$50j7_LH>z z|DGV1N|2~c=T^cKL#hm*=g;1vmh19~^kb4m-cJ+Zc-h^tLq)ScejNc$8=LX0eh~lX zp!57Q0BxiwzF^`hbG9?<%b4QNJ>bws$1!@Hca^3OVl2L{?%%iaGFoou#^UXEX-I%W z)~4`Y^!@Fh9v`!E{I_#;N5qqq-H9*$#DDqpe-zz&JX8N42k_l&!`y~!!#4M8HTOH4 zx#p5vBB~7`5nr%_R|)OG;P2{r=r!|D4BpoXs!?8mV>H*X6+eNau80Wv8-~G5B%^c0WW$NQ*PncJ%eQUehqbFE=rpl;S zbqF)2l#=@UA7kF>{as>D2ngtT;N+m&qr9k(@814S+L*szB=dD|WDsqzI@7Kb_%0p! zuzu+NqojM6uPT4p`TEidYkw_eN#QC~?N96t=8-RSn55h;gHy4FJv}uj)&Dd^p72kn zh=rM0X{w5P*R6(&d$!dsL>PvH^Fhg`U6;~$=q%X32`3ONaw`TVhW{RTpn3we6`CEq zl?)RTH7kMPN`u=t<;kB)t}>T9%apZ>H0NMf`e?;VS5h9{fy(MWm}o|e{9NQ*P9Hzd zxmT5&F`rAy;n-bC`BKF{f_xs|(DU%uZ#AY|@}sX$6bBx_%0 z*r8Wy*T{ZpH{dZ_?jd@(E9%w-3Ev*rF~YZgvPA7ep50)&u6MI8dgbByPL35Gq+@`&`#tWZJ^ta-v1-L!-hvRm6R(DwluMt!nEKB# zn@xL_VlTED#vZ9jp>)HKr5ndS(Ma6tZiZr^RUfedl<2PaK<6)AFwzB-elOK5=v6YD%-z75+1s1ibgYW0Eoc=p4YgtndM6vNut*H#C z1Af@xriQ0ptF`DJ2W*i^MLRtljh%}VAlSr)+T?KzHlFe)zgG^scDb7L^9T;dOFjN* zSet&65WQ&eDQstD`gjLdg;nxUUiRrF`wU@ z7OYgM;@+PTlV3z7&%Ziih^~6E1RhELSwrP5(dp|^`(e=WewI05xdsIx>ms&xt+pzJ61gJ9ew(HFl|Qgo^Va3zAy$|`jepcg0!@aJ1`26$yz_YFm< zc-2>JH$~0s0&%Y$F6T8E-fZhWSg;Mxx-}&uW@#Y7DuIxtN4@#$?9S0;4(Y^~&3u7G znEl0k*Hg%W!b0!Sv(g=PQEbZnV}@DMIlbdT4V!YNBXtz5O4$$VA!X?l*SI|g^_m`? zqUaIgzTFk*B&Eb@*iuEaH!NrESKo!sG!@r~nbyB-H{HnM3|MTyh=0~ciNTdq(#3zB zC{WKzu5z$WL2|y{m#3n8W;6-d%-s_b0d67|_XDw9l`rOXy+h~zNFsn1wZb#EF&(31 z2`zP$-~fH{-K?1LZ*}{`JB|MA&8)aMl3iPLhDZW>N{QfOSJO$q4<9``w0$)Std(%G zh+i1A>vq%->JHW}Jd|}o^YBsI9-)h^N7@YF*_fj{*ODyMRk%btGk^k1np2V!IP}qU zg2cM+GVFIN+8sfeznn-?875LQ^ph{e@iR zw5el(8iH+w^?MoZky8!_pG!S#J{@aiOBg$|*#&xBSEt_LFDgoqC@N{2u0l~^&ecRE z1(~ZyY_xrfZY5vJn}&ovr?Bk7*MKK&)X(Uwj9N~(8(pG37bL74b6UJpiwVudZuc|I zS4g>}L(*Y9$VHDChx4bK@o2d|NX0)dfvBz~dCtmm`vb#+wCQ$R(|lkWotPOM9dYRF z!ludWQ>05)wA%>9U(Lgp&+UCg=Z;=eSy{~Y@?OWufMxA0ywTAF7ZE8ku=Fdi6L(27 z*Fw`;WV9YHn6C5wvm1EdIi}CtL^ldjNDzDK~Lgi zTGnOnJ=Yax&-tejN9<+Jm_MN2+>ZNvD!=mP8^@44zcU%cDcBL->MLr0`32=-ylmuY z4@5_O)GHpb{;bQ+2i-9YibnSM9t{=z1{g@12wbLXfkfB4Op#I(juqL*gR5q*gh&)Z z^hqSbI!OlD`~urrb->YXIcvQ*UV zC8X_Nhs*_F#3h0XRC|W(O=Anh^BT|UzluzPIZ1n^-IZVR89xr7YQ_MJH<^yLDb(WJ zJ2{JXQfcYw1?SS1^rG38$2fYs^_}4eYaQSC?{F^ni0#xO_En4ZvQ%1~6D<$(7_{e= z=f5kKNC_BA0E}5REa)b0F19~@=&wH=Dx_%28QI|%m%Zo?NF|jAxwGsf>J?i+8z!(z zEjkCb8sx~O|KVX4zD(!s?6;v(coan9G|Za<*W*D;c%@Ti>|{Li5+E~p3U)4(dHS`k z;cAb2Om3MjOj!ejU4h)5XX-Qd-R^>&oGR2gR2W|g!2>`>8%%ThZL_>`^Y#)9jad$7 zIRe1uKFk88KK_A*Qk8`9ykK;+a5x-{R|olJ@S#xsq889jG=sar9CBx9jh9C9Sjk=4 zI!&Tcl}1FLS}9^q(n{9V-64ucOLWV%V3S*MU9jXXSo}&s%`ercz15qKFSE{VK=u0h zVMVri;{`3gEI51PRHbUjHf9+QyUBiZ&fsZS5XUehKKTlw}0L(h>RAF z=(oWa3lPxf2Xg<9=^dHXF}dBB@$O~)+Y@F=6A*>&u*qL6BYm)~cxwoa z+}_sF-rq4Rc<5`6ZkjqP6d{l}d*iuj)8MSx3+tMfAoJy_{bRfe^LgkA2nb6QXd$Xx za$^uf9}xjrL_91V0OJSun{4){Z}Lly3Q+Lum^5ald)Gl-S?||6dTeNk&%NLC2fiv6 zqM~b+J>jY;8nkNI=_xRQ0ufIW1~1UJ zD+~ZZ5p2T3>_fH+ebaLJfL?+zE8Y!u;qv|XMXLlNE8c-+Uo0Z%ho(8e;zMCk=UKD6 zd9HP=b9FHOKjYk37pkP_X;R+e=cV?*L?EA*C+eSVHBKAIy5P&Ct%=F5DavUf<+tIr zyvhV3?CaoNH|^s4yEe%i@I*>=N~KauclNPAFkUt6g3n{nE3pHT_Z0z*%nnu}?{OTU zER~n7uZQ`^9e&sf!t}6`GF(?7;~UE6?$7j$9nqfMu=nMU^`xGLXjDb@+crG?Px3b` zl>+-$jqx9V8#%C|0$H?O7>$sZSjp_j0S4q$o^ybG@n@aOc{my*8j=NzhwDX7;jr@E zyIExy9hs?hEXMjUZDC*3Cd#AUJ<*sIYYa<@wu-Hkmt7sv>tpT75t5(6&^opbCI6`$ zVI@{#%6x^ae%6yk#NGGM(mr>l&Y@s2?6Oomk;Q@c3BlyAsOORF3O3!1J|iT$S&2l~ zdn@YS&r6le9uAv+5M{0`vQ%ko3)359QD|kKl)CgwboA4qMZb+(1@9Q^Fznh{##cO( zW)H>{Yd-W+O692;>_}Fvl^s@?K1cAvy@lJV44hlh+iUbna1hPjQ2a_mmh8I!^RN0B zj?|CMqY+svBQV%iM>bOX1%*&TgW3Az9voyv5w9#7dnB^^lPDemT{&$&4{rtb-(D=d z1UQO6!n){F+CFXOJ$vZoa25st?knB@kpomRf04jv;fz@YT$UR`4jbx=WdpJ5B9R*k z|M7rCAMf!!u+0l%jo#ejML9@U4*gE1`HJ?Gy1O%;2OV{uB%v?<13$bSUK`WL7jR)E zxuuH%qD~DghKf(pIJxM!U8d~D_#!Ca6m0_xG!XrC^m{%%qD5UM zTM~t0oi&Cv<4e!dSmwnA1IbWYKkLqg{P5i-5D;XBhoN`i>HM7eZ0V@5#momm0W_0T zIwfN>-g%65H~ekN6!S8oT5ZccwI%1003>$&O}P)ulW>bfVy3hA@9&j?IZzS#2 zF$==4#>eKJmngp(%T&JkHpyoo1*JIL2L6>(8GnzJ3fHcpwVqj-ytCt;*pK|L_-$ao z+cfxb0^e`Edp<#({rj~zaTh^bIco5>!j*T>=rhhwTq3RVO}QJ(skqSmYL%7?6IBPY zlD|SLzD527iJuz!<#1m0uX5C{dc^YwL!XED#tHXkShq4*N5*sQ-KV0F3isz(v{`cM zG$gH`h3EwOQdo;;@>0ZE(!I5sZ03d5qE5GR8U>=w0s0g#ytvAW2vxszDg!DkC2HY!xzdzCNy#Z$`S0GA)aS!V&TlhguSgIJ;i<@;;c z@=v%^sPLbA@Bd_9#u&5C;#rS+m}e=*anf2IgbU_p?Gjd4lyS2|ME#+5Upr&2(bjBw z9Te39j9P)kjSI;Y3#_hFHNP_*&R$T4^D$25bj~}Ew`Iz zFKr%p%wwKahyB$MjX{q&B|Mz;Ws zkks1~X^(MM3XNVi!f`sgKF+;lq%#G_;-5`E6 zW>^a}BqRHoFj2M@*c4p9FS#KN&hqY*(roJmw3jQQATAV0jXKDDD$8;9trc*f_7?Os zFZ=A|zUhTbS083rCDaejFrR|hs^hS5h+hUYypl55_2r^|u9Q#2h_JfcuAV;`>&kDqX260^##%HK| zd!794h(3v04?;o4Z$YYDK?mv}qu=49!Rt1hb3D7y}&7kx%!z-ad zg!Rcy#7HPdC{fIgon;^Ge&n~LUVoNTbi}p2XJGG8Xjp&vm(#|9F=Dp;S?Bs8rv29} z+QH6sS$$nHascq5uIy7j(39*e^C>M__h-kA$kzud{yhK(@tAy=m2b-C&J_a(;ov^T z&(5eXCn7fZk{&@I#Aof}Q0C6&m_45PK$U3@X9$JlVp_mnE74&-Oh@9)&nNt>+#%}+ zmH}VCe0@=k8D|{9M{R$B7=?--_xt+&?AId0BJUB1Q=R?vaMa)BDCa3KKut`J&48TT zfZlM}>@OklvN;v60I9?p3C zCGOoQ1Mdmx56)Gjt=Z?0H`zdoJ)S^l3ttwFASHnh9?B%tWjPhECIZ2uu6ZNhzfL@5 zklxFgI|$$}GO2Z0+?qJ!m;8uV74T%lR`LZ!LiXwC)nEsKEfaQM4fJ%EfDr+_9x3C7 z%j!z^e;1r}cO8dx13MA2kMzfbVqsuSkcCf#)$J@Nx2&MC(8#afzoH1n&Bju%pU%a< zxm^H^znv3c8Rmy6xRQZ3dVz_zNB{Rv_;7s^EzI6eaiM4~(r@5d3L*Qr?f!B!tD?6v>a$+ znP$mJ_7CExfOos`KX$h`z(O3CarjEf*V;d*q!T;MwdX>j+RnEgH4ruVReEm3{`s%i zD8+JIN002!A!6s|_)nBW>V#O)efy-ElOK({|2$Pkb*t?@zEM4l`#W+QSAQHd9J%uiG&`L{yqU`WA;Qu0jbzvPdpk0sB3 zRqt;y6b%xG(PRrS;(cj*6xQ=ILbK=oPX9>UwmSDs&5w4t|3wG?CB%xKm0doWpF%O; zeNp_4<%4nn+15cbDw7WS=bwX$DLS`AD{z^jvcp~X#ZGof6FgcJlEi8hv3mj9?JpyX z$5^U|8=OxQ97|(&hUeWh;#4Ou8HS7!ReKgEYb?(_i&uxsb_9{YOx#V2zwZ-i-!m?HEY@lFX#VWOY)AAFc-IQ(d${k7ny z7o8`$h1d0=I-JkL^gZDpu3P%3o^xQavr^0(XLnS)MT8-+VwP(K*mv^Su9aNn`sSmf zMQ?i)>st5PN$bal(wBGMdWN(v{ikR=%Q)FT=DMz6?n z`E%oOn$)dV*J{s!FxT8g zMKGbh+5cEA^&)#311*h3)|l0bf*0jBYm3#YUbxtKL)Yfge*RAL zBLX8d%uOO}cERZ;XQkwfwXHeQnNUx7BY8vUy3_Hy7eE|FKkSZLTZ_SjlP7X~Ikltb z!M=G-^4gcnAF5Vgj9|p`5ny4|leR?3tFFparZ#6|!H#`Zs9L;0(0<)bq+x-eeb4v9 zwF7O}UH)8sh*ta-KjO0ccLnNOetTSU%r~8bHs~u#CYt|6X-ng zym{s;&nK4SdmY7YBK6bc1dCs@3$kPb{`{@w2NYCl68oR*+-v<+)VNZvzmB39H4BN* z8G&$xutf7bq}UPlEjV7N#4!G;T|52gb$PLWaIKzk>s)yvzPj{;mNvJ@jMfz4_D22Q zekrlsK|LQegLw1a$0*D6(h2a3Vj+ZkAC#JaO zw1UTawSS%@sk#eLzEXLn|&G7J8U@;R3I)^+SU8d z?AubH(;wk^Hy6vYtJj0g&Bj+U76;4u;@C?X%=~pdY z0QgYj9#`(juB%9ePSN_QD6FjV^h0DI|InlnyHm+B>vF%%6U>hL9c_=b{!s)n{7h>m zzqR<+JpgW}X-dh0* z=ZODO1U_vsF><}(!t)!m2nrob%OQIn*ItaB5LHsHZ=jj|g=*soRaS>bvxb}mCO zX({TQ5Qn2XH!m7lextxp_AOAPWt6E*6(}Xx%dY{8V9$gRAK5GmUUy+ae+ zC24oVtir?&GEya6ezhskQg2A&%E|L|y>)*56$J!c`U4aD25^k+T2img$~7@q9Z^18 zlCLSzvY9pZBpsSl&_L$b@?q?Cj%P|CN5)J{NxAmpw(7pab5-L(6W?uGp+1?wG<9!q z{zxOX15c{(S1wnydEo4k`6@0$9BkAPh}#H1?h;tXN?a$OyPH=kIbFxpDt_MFvAtsV z^QF6%bUn21brsp2JF4m4t?n55>1ZjT#&mc?z9s9DG6Y#@*G3n8Qv5+zxmD(bv;yLJ zo&5~I2|YeP+SF0q+IUMx)EuGM#c;D(EPU038n>=ks>{NDqvRzujamQm+AFsUG0;V7 zb1wyEzwWRzb#*B{ZyA)!@0%)9A(+yg7oE=_dIpYYRn6n5Y~PApfM-d~gRVpIAm>L? zR|^WXZr_`{aO+t6G-`dvS zL@06ZG;%Z7J?Bj7T3y7CAMqYEo2_uj(+L@9k9#>o3S%dQWBtQZ~m4uTZ+F1QWE-=q3KmA4HR!D3TW8nKP`NEO8SaAsA#Wl6LEsav2|qA zRnnd!PUFdv!RoQ7`1@1O$6w+reC{j9tCi=L1W2cd?>G3OP#H<&VgpVcp8f=MKmvep zgF1%UhJ;A>U!wq?B+T;DE+T3Pd}ClO%;fu~2yzfc`PlSSsI#QVvlHN3c^_t>&tEdO zDlBh>j_O9#LxVzZDIe~E9IWP0{W{bdty?oyu?UDW8?>*7zZ23XF685&XlmO(qNy!G zQ1b!ptEj8Yai``gvW5}C|Ab`ZB3SUl#!{8wuWK|4RK{KjGoE29?{EZS+SDM~ zH0gjb4I=-8BX(99j(tE8Qw=iVCeL-tJ&&;tn5K%=f-NlQEipzh9nYoB)6^~gjTP+( zL2TY^Vize_*xnoY>3xfsZNihiS(4B#^YfT3b+M^MiNavrhBTFs(nsGhh3S8|h_OU# zk%$}(YN~0qel+P z|KvdhS4_@Cnym>fjl)dY(d+QU0vQ1Xr6|sZ$e%s=P~0c@n3?;7((sA59|cSKpsu16 zeoEomQ01uk+^eE+c82h$S(r&pBQs$IEdTEPKjSuW(!lF(Y|RVdZwikJ;${c2ulnns z52u;NoB#dzyPpqJ6c(cpWXle)Y90Bd&r2n*2ZVL9X*Jo(zt|v)oVY|b{)QCi0nL`c zX6n`msfY0-M#6OvY~Uh#=KWaLTyplsar(uAr$@OO)n`@ao~2h2eXGY`;ZI$`3)Ret z*f}SqzdHLA@#sU{gQxJ6oBoFf{WBe(llnQ46JX0eu2l;IajJys^~5-I?Ee;3C3)vQ z`0$dAIbq6tf^k7*9FeV{S9pO?SY!JSNko%OzwxUy&# zvSEg6!Xen#Vtf5!0NxmU(2I_4ALJkUme{(ws${^2e$3FYzs$%Vs13K# zYXXQvGR@||#x`8zVn!gIfiBN->++QE9`2Z!9zAmPDDtZ67n$*ym-)lkJ-M4gmmAa& zVRP>Lo_Je+5P7E|z8qZL%&V?Ajc901ETO!xkgJ7;UA}bMBlDEx`K$0}PLl7WWpdzR z{`5~A8(hhlK{3D)2z*zZIr?X6r~{z1tD;>85DWT9xWv(mAZr#A%R@5`670n0Wlo*A z5`VlI`>y`K4uHuDBedeJUMNh5=ZmZZ9Gv5t4>k!r^KUk{7YQ9X)7)BCToE<<5AXH=9YyYDJmuhz{#dJh0XbSYP{*+W_Kz(1pa%Ur!sq9MwjeTAGkqbBOVcGFZ;)H#zFL@xg#EM86C+f0Ut6%QNQfKeU% z4r(GY9Iql5NDC%%#%!zP+yhl99Op(aBv*0L>n2}00`9$pD(>aQV#l5 z$N2d<@B0U^F~kk2-*GQv)=HmiSgG0ZFw=>=A<5ghJcl~mt{HE-dPC-@T3-wCCEb@%M z?J$#Ju*KFb{u;;|HTvU1^Bddu*68=6JM6Bx8RDA?*ERe3Mp(8q6I}`-v{V^ z=yYxX`EV6ttvVET=q9_A#uz|~);iZp%s)B_cr9mX9mHp^$|0YI_y zFF!9w;t!8Kt|EWJe=zBtohbV&0%A`JKUPgi>)|jv-7!S6Z1uOjl3;0n*vKUrki<3hWFq$; z58$d7li+5ZoYiN!%P=PF;L91rKZhM2l4Z_8Uhw5o?RpvETFeMrscBkssl{}KtnZ^^ zM48g8%ka9I@!tos{>`x;9~jRz*#gU40wO@wsZYdExAW4`rRJ?Z#Wtm)SY?@5RonsK zk*!6$1J>Y9g`zq0WL@>}Saqw|z&9_&GQW}AOIp!icy; z>)iCbRv=JFW?uVYVorXITK+9$6myX)m1vMU1q}+wLrIc-Yj2)x9zOP!;kPaQ`PIAa zw;`56c}cShg3WjCWc_u!C73kO&R7MLMxPOClN zycM-(E0We_kpXVQ|dYt&JUBd zu@kSndyP`9s~-oT%qD#GfNy`0g1A%NX00No9`eQH zcw53q{T@{OJz=oE?T4|4Rc)@&PdELW!@=Q0MrNVw{yXQn?;Tnuz4u>uX=kEnP|;*HVg!inR2 zN558gCcFW&DI;ncBZDx0(mBVIn3haxqCfFQ(W{v z^>=;OP8uLZ^EC_l=bPpGgKikE*Q_>~>cr9HuY!Iw6ZO18W3^Uh&=ql)C2zpK8~EM6 z9h|fynmS|({&7~zkax@EcT|JhKBs)HrG6-7*X*wUZ!0#@Xo+D8I2uM}NDXl0Oi9u_ z(q7;P4)@QEJ4)4O+{>_!z$cKlIUh)Y{E99STYq|R!TS?x@DZtx$s##QmK(#`fn0bh zM6~IENmk2`o6)(R&6fIu*EawvmGwqEux=>vl|R`$evNnPPf?QOm>Cy)_Kzoc#EK5O zBBgIE&bpfNJ)%Us5`?x)X3!A%r1cYb&k;q12Kx_Rxr8cOo^iTqT`-XT)I&<}T9jO| zvOr#j3BSjq0MQbJkOQCyYIT>t?0#P>1#U&PTW5ErpCqTXy@^pL2pD4g!>#=7)jmx z`Ab0C_#pK`p4!n!gvr*zfc)M*QK#>*uO3&TFB+y}62fNMeQziFDcR-5{T?pKaCfIj z7=7Ka^`my#nN%A8+k{Vxz9S%Qb2ofSTyg!Vq+~>H$idlIyzYk=#8Wr0trf-@Id@?P z#l9$;(?+6uBWq*j%uB`npMaS)iN7f&l%hU7e%6mJSLs2y0l(u-v%@8=^Ty9(tna7| zVlrA9ucY#u$)I=&JWxLMU2>N3eSb5F`}fv$;Y_LxZdJSoE=A~3E5~d-oWRRr&ws>5hw}#XH{mJjdnEJx^Nij!&)#p@SZ#LvlXs9$zP?$;CalVb4vj4!-M3b4C21?p}4?KE}1M*Zx^8@eO<;~hmTOTk9EIh)b>D}|#w>KGRsR0$yv2?tp zeZM;4UDd~$y*rB1z7*e&HE}-O_e+2Mds<-hK0`86ZlMyQFYh$r#zmZ5;C#HaiU5Jc zh!21^B1S8`hP(ftioI+)Jr2H{@`-e#L3x5=Q$jL5t%eKz#(tCktJH0=WYAF}sp>yz z;O=$ehUijt+JvA@iTz4T6bFj4i5nJr`Fm6?+WG;vJen=rJ#tfjyDEVt_8Y@ZS-JD^ zlK;U2<92cheJyCA-flA9fJTSmVshPH3ogDZF{^P+oalI{)w`r1n^2>0ztGh5XLC*J zLlbNp#=GPVHgV1z4h>+xu`3`9)3R0)=lV?AFHPME!G^8V_Ablbk-n~Oyc=q-HeCnx z&Vu7E40tsg&b0O@b5wXSV|ee4YhO+`DtahXD+1_~ny~61PXn>h9;G0-_sJoVg-j8p(58^nB@j0mPR$ zoD7IlsA>v4lXRZGfBd$n>C)Q%RdA8T6qN}{=)ebE=jKGIj!HF^BB zFq?yt{}HNNbU%WM|GkK(F84gEjtJ29M?d!Y-edM+Ge|$q33tTKihN77tZG_0Jibif zPPzyA5NJ4ZOQGOBT-o?H9u||!7KmNqVmBQw@;fB3*sp}`nvxXz zwo&-}4uiH`XK$V;1NNG3JOTY}&*=mgs0k@o?6l2WeL7VX#3nki8iE~Le2b#xR0O7G z$ILzf>QT<)*rutnF2Igh3Y&r5&9S#|WA(U1#@ezU*jWZ83CazMCQb6&XcE=LttJ=a zKgF`{5If_xv?o~v*bydSqIljeMvN- zBe3@8xE%tt*iCmI$8Hc+|Jhu?VyTR}?a;BUFMN~Mi|YXb%9?%Wv~o9A?0yjJkr~Cv z)TKZak59#yN;sX;If&iLV3i+$6s7H%gR^@j#)LNeCCvM{*ge`&-H$qAxjqo|&)uvU0``BnyU(YS6F8Z%0Nvwvp*IFQl;80y943btQKFIhIs4W@db< z64MpX5Z*p!6|vdQS0yUKf7_d0nlDV6cv2My{%SQWT$HjKj2DU|(AK&UPAc>KWZhS@ zVKcEs6{^5w3(U+=rrx#MYwr+NA={+?r*f?MVvlm^t3*8w6k{YqN<-e>!PntMN*}ic zJkKG#=ELu^fkUt1jM9oGSmFq|rE(=Sh%!}>Qpp%2I@p@<+>x?F47vRUP9m`#&FA{I z@!P{%mRtWnZD7dl2Aq*!+s;p#Mw&17LoHrx;_sF=D)Z=L29%(ObSb)My&@BQR0fb3p>rt1YmDaxE3VGmWq-4$mfq zdJd|OHOe{d9XNm}1)fUIS`_llYz%2gz57NesXu$tD7SlL%o_)98vVke)+kL3!2j$QTp#(%tjsa z#s*I)xA;CGMW<*pP!cn?)2#kx9WFP-m~v?vue&(JE0ikf&{O)wpLBKGP1kxwwxKaB9q6#kO%B(*bqP6U1`Wpsw8+bUJN_r=9v_VH+DduP~M+dG$c zpu*2*op?daFOVsM_w^F-L!h`d;138;vT+{u7|DPU+ohIwh81BC*MA)Y=UU`X4b-3rv{7lK}Nb8OlR5WE-- zH(C%3-1vP9tX&=rzetiF0K&s4mTnocXCdOcEkM5w$dCORx5zKU+AYVOw2i|}GmD`g zt%W`o7ez$hOv!DJu7eIviN3NHEZIn)1qldAK(pL#9dc{Sb%Wn&(|C_g6fhXZiZP5xzx{Aq-MUx+{#9k)!EF1!Z!*qfKnRc(6MC7;@k z`%h<5u~TkuGZ0#e7b^uycqqt}D#$)l!1c&?3oELXDoSk0`+mF{;3z*ulJ8u+ejpbo zsEd)-4YJ8J`i%8jlVL{Po*RKfn4 z<`d-p=N|iCmhSh|m4Aag@YX{kwORN~j9WvOYImt}tJZq7i_qP)Up+Nx2IJ54CfJneORv^?NJ10!0y8AbqAAD* zKC#-QnTJO;b6$;rtX#MCO9Ak=1lxgjbTbE86QUTyLpE^G5nl~%mnjxV!lTIAvz`{I zb{B`Xkt1r{)e44x(aeIP3o;V9p#&F-RezsnhZpF$&iMw{LaAmd z#+l>rehN`T#i(;EeU;MZBBawi%j9&l@`!T3NOnPP8l@yBX{xiH#)hlS#V~!$_j1h0 z`qXqCx`}$Yk&YqMyB-HaGdYtKpv&HQ*s*W6CENM~kI>Ea=qX9t^=r7tBq#3@vBqg6 zRgx^`?s0_CJGdc2_B!G?ZNL+^jj8jJ^gI|7f%~Lz|Cf$HCkHoh)oTZ7yV5A>J^yP1 z3E!fa-k9eXVWRctg@QKrhqDn5RB6+Cp|B}YZ=iI~5x=8U@yhi(TZK}k_2^4L^Z_6u ze_9*XVEan}D>YAsJr2n|;{S~eHBz1lvpbH8);MI@GGiFh7qG+m(LUQb|mNtgy9g?&!AoLe~U{E)(h z3)9pex5AIV**WggXu5SC8)*;{#+Djjq1KNG=>YwxUgPWReSAQ*^d{QtptlPc){mF+ zR*>@lewbg#+M6Jaoj)V;0%1+^zpQ{ZRX~VJ>x5j8+PEf})+gXuhxtD5a@^kTs1kG~ z<5`5mD0J8?Ujz4zdRk*IOSUj%UY~4+tCw?l6yUC*Xt|183dVI%v&)5H`c(M=7;b~4 zK3;$2&<&KNwEc=#>}8LT45F3k?Gu6Vu`jz#nmO1Pt&#)r+7uqJkQ1h}A zR6ET`(znydCOhOi1>7em{P^`&M4MtB9x<&D6ez0gftO`^%b8vX;x1!{G;G6o$Ymg| zf)tU?gb_$`!_=_kV1X7Ojt8X0NrY^YLX!8DS*oC?sVET2U_eXGut({=(CMo}V&ini z2L&AeB_21Ly|8acTdZ|0Ah!7WzS}7-fXh;M=@^{zb!S=j#rYKnwL|p zcNJMspF$PbqThSRuMPzmm(@W#fa=qHJ(1=Jpc{=-gCsq)BSvs9=#EZ}l?lxB83o)Z z=cHsN?GiP6$_P7cR4}vqJ7rnD|CLhzIF<&i48)_Sfbz}tRX3(O0k-GdAyDWi`O&@T zve+5i1W7%qx&4I#ZWwrW@0+ZTuViOpfy?6MAJ!MgWzasmzjwDihg?OTQE@f%jEkK@ zSSc|cH>(O={Y0kq#ID=RpB9`~CmoZW`ODnHdAW&s3F~7`*F7sY6=YWqneA673(pC+ zIwhx`B@aN$%dKNu3Jlmb`^?YRCSFYXLc%JekH4G8{4+5t%aDuyA#Yd}$0fz1d%cAu zO7y(6uP)#`D3;zC5Y-^;zKcmRVAx<&A$P=NM6%;3z}vS>f34p*8ZV&Fi&08i-FR&s z0G4ocBfK~kaWhUJx>2KfU%G>>g2bp$M1ckJ);&O zjV(I&v!R;7j$5>Tzhm8@KI5v)J}g0&O}K7A!R*${(eMKC+ginYZ%&-@zfWcFvutrM zcrF|WNNN8)Kux%l+n@+30ywDQIV* z>-$sCJO%aK32%itk=H=nI0vC=Cg?z?-J-|*XlP%sQ}>@F#p**l6>v?42#+_2@+gDo zI>{vtcAO*@lq&uUg;k!<+tdBK#ltnz|IflRNg_)JNkKqN4_&sIE@jHe7tHL>ZIrA4 z?qdVcT^!l|dGwt0{!25172v1V5Y~q#oF+h-*Lr2fkF_Rol)CO?e$&uJki>k1AIaD z+a3j~7RL2f&y-FZVD!DkM$81=c;`RQ(+)2$Br9P0sIpD-$cXtQiMv7+;H&@WvJG?@ zBs0j;c3;K3L^W~W=nlI78;(|wrjQ(xDbf|x(@g==mpJrJlcpd>IDRen`(QPN{-u%$M|AtOn>3DN7 z;{F?Db2p1e6^4F#j!s|y<#EvHBL8~$+W{BuQX&N@S6(gg#k-*L(qj;P zF2DKAc4+cNkxYMg-VP}-Svf(z8 z0miDmKTg0i4qH@o)SVEjpN@M%AjpNzXQP5!=9#jlbh7&Ax!%K8f7jyL6rE#xtuY>1ewU$$M`25eMMNy5-bT0wJZ~ePsR=;M+uJV?f zfE?2wf3^dxK3B(;V6d%8E*6I^tHdm303}(Hd;g>8KBJO;`!ImB1XPxLD{fqc8#jvP zHXNC&!jY?Tuha@e0nLG<)Y8I{qpZ+MZT>+_ZHi@PWrd@{va)THhvywHIEV8)+;Hx5 z-`DqZt%*&JpUi%Ub}cpxlGJ_?MGJJ#-i6br*D+gjjA? zu(366O(x<#3=}jzlo)pPAjjT#JJb>iJR&-nwA;9XCr^1rNK!<14-qdmH+oq&r$Ap zd}I%y+$Aer(?!iCbNpM`gURO6X^G z7ZzKxRn(r(HljWL8kOp$hwrkfb34|2D=`yJLRrdwmJ_}Jd* z@9VZTJEq(ouDI`gNkX}PHwuqOPKmqF4k{+0BnMSP!%HbXO^sWfDe9vg#fuw)V4H8L z&$c?hy>1sWX*YN7tUGrcX5sWlND4^W|98o4&6haf$U;gAJ-d@eR<)gMz=&!r$&jUqm zJJPVF<{~Fsn@#-Xjm)ET6E!Oq?fm6B(pa=#h{OQvDDj~oe#}w*Hc+*?1%e9<|6xK*v zv~|}2Oh?5^bhZd!V7-3R@RdGl&mV!#_l-#h#c*)eN|)|B2IhEI;Y9HOorSs+=K3$Y zCX4bx@B8g;6SWI+vQ}W~o{NS$okz+uk^~6rC_Wy#txsE;&76y78mD9E_#}bucfXr8 zcB|$=^@$o!{b>$FAEn4o0G*$3nAu)WIagL~^6k=x#2fv!rA1&EQ3OQkUb>mFPHlIM z;oD`H)#YR*YUg%Mem=GxT{4=e^+>qI1u|B(Blt|*4}h=n;!JI!AGr2DyT%|=T# zf=0~x+DG!hTiQrEt5K6451ec>k9FuQ4#FhPR}^Z`tOp(Q*R>z_F$nIJ zwNeTq{(CBu{q|FB0e4x!b*d%t#mwybpG57q;y$Z_ZS;NOE}aSxSnV8@&OCQp*40(R zX?EGX4E}Xn+&a`{cCog2{QtNo%;mK?TeGFJ>nj$P{B*`38}Xq|`I@h*B~9~mG;&YO z^0C+=;+5iVu-4oZH02Bb@LKkVqw9c4`*DT3_WXTV0?*rZ30PY)-!<@&=u^r|9ogTs ztT`v1a9Q(2``fK=r{MZhUPX=GJVy$h0f=VtGlBWuuadq_#fhu1XEf_=mA~Ll6}P0w z?zc2A38urfCi$q+@h+VY09YViVqBX)&}Fes9iWkBG_-L`IvWI7aC#Q9*z?;a#hcPb zv?~J7KX!dzN12wLKNL1`4g1CGTVlTqRtt^wwdKdsGp;1mk;i+X1Ne34qB)cfvnwA| z|Hf)Mv?jgUaQqE`Q~-5qzB1)YJ&-1gJ~3>c6(!J&y*cSjjpO;_Zfh9r1Qxol)@J1y zp8G+Dv9pDhmme)(UZD6Mo*KNN8+=h$<$CHC$Mnj}_vqU5>st~(4I)6Oy%^8kd)2Pl{+P=^be-y_(ex|~7Wyio5g+M4i%11dAd?q{T>4ddt%x>uBVfWiGqeV7U zEu9TY<%Bxp@%c{QE9E3^siyx)2)^!9eBFu$`IAd6=dsQA){>P%RCQ#0)e|sa`zY^+ z=~v2pUV9=;yH6|C-Zw)=`#N+^KI9qpBruHNCE7-J zW(4}RhUxpxI)0-0xK0IVWlm1$Uc&-q!>F=fD2X!2Uey!t_%)uw4wPa!%~Cs2R*_wH z<;T=7Y;kOwX@rE2NEeOmt}H&^#YoZEM#h<$uhyKx9at^jq2kT@5va(a!sgby^GjZF zUtFfE<#WI~r$vxU6Ah4C())q*b=K+VM44T5W2gIjDS1gG1w>)1ttzCoTs8jm(Ipkn zF%A?@21ihNB`;u7VYy9K!=F=#y+3HL_)DRB!;(4FyQT8E3?TZ}qyqF2&Dk^b>WL>roo>!Y+OL0z#_;b^Ub9pQ-G3?bqJ7>@?7N5pxvSFT|cns?|4+B z2r9`Z=YeU36cO@Q7AlVebtpPCK7x4t8eznd-K30q_eoXSmHZ2fa>e>e0Q7cDf*~Wy zBn5pxOGfUI?0Qy4x}sVvr2KD+-1SH05@Ajv8rGP;jQ#j`;;40wJlH4_Ma#P-PY!z66kyed>6@MIRV(Cfq)2>@&mg)04oXTDds?5`hu#3 zs0|SUO28MBeHMrbp!$rvcIi{`vQSdoG#jP!3b~zHuKFN{AX2cP?2-Kbr1fljuA?LR zV;1Vndb9?};w=X)B7%y!$T=d6fKhr6s=5EYcD+yEf{XZxN4EgL=rXz4Qz0!jVT)|@ zy=9;$>u7sL@}X^JZQb}55%!jE-AAq+Q3QSZ%4)9{$eDnyPy}cC9yG!zZ0BYCr)(8M zCcmPR|5F5u@bt@XAgpGWb0Dx#w5xiZY|X)b#rixPv(cUm)-%P}-HhJAkiJQ!FSd@G zBN+_L{TiV}Tt7T(k9K6DWtxpF9@j;710M^mj}bx3T(gnFBCATn@Yh~X$W0++2wupV z07W$_AU=$NKUu3i0~DB6BtPYli5zoR4($g;-Uy47NGK?2Y}E*$`-vJE%skpI47GV! zs9%N(8`bT8u*DL16vNNc%a-w+ku?);&rs84vkZ^CiRxg3_P6Gx%b**mASpDsK|~nw zWR88#x5lPBrWmN?I<5(of_tHB_`MWmUc7Y#R{(tXofh#X&C?af(d?|{)oWu$Pa61roYa*Rk;njLIyzXdj8 zGr!^Y%Pe|?^r#oiD_*J$A*+DlyP-4=j1YxsZP}_Sa{ZDrXhtA2+ z;}d=uslRGsY9KC0TKy^oht`ZZkXsY{$zeiyq(rCH1HYg}S>> z2h_{J2J@(V>?w&42Auo28IP&|xQ?zP+1g{}Ax~tXx6E&h`E$m0KkdeIC&B2W==)fE zYo6R!GCKFv>F?4SZ);}`$VBSk{@02$BVvt+NE-#{z6MA#V7r*hmEW_|($@Y|A=+Cu z>h!}}i&Yz)$H8_2a1jRe8FM&$H~JkhTJ20pW=E4viqbW%Tr~$yC(1qNZJSPIpG`Qj zeb)cSY2c1%)UGt*J06#KxCN!UYaCD@-L#>i^K~0Q4LtdWS$+#5)R1>`N@duw*V_Yr zpjWewEK<<-u;|xpP|7$exy#U=+ai%piR9Y=jvL~!sGUztT$50%fQw=d>M;d(v<$SJ zA}6_(g?z?F`c7cO!uS7RBR573HR$N~0Jt>(-lBxC06;&49&KAzU&AB$7=#eB-7@*2 zPC$tn+w7kZ;j?YXq4E3-)&>#7%wIp>o1`ecQo4l!N3eI;Y$KuwkoaZ1s_Rqr?^HQrRi{MA`Ye=Pe5Xj@A)j|8RfT4@JVfP&rxkwE zu&y8a>eC(4Cv`B17VL&MT=!p>uGHIYVs@x&1QOOGae6lk+ zHGt{Ttp+yQjUKjL!6O>k5YB{MdXl_&TyCtd_Y>Ll$Rk-(Q`=b(-?xQ^DX=H~KE_~N zv@yoUW#z%`u{aE(Qw8p)PCJ^9izYZjj-)=$7#SQDP4#>@)dPg zJyMX>sg-c%@rKecK;Fs)-p)o|S84c9b0BIziAxKA2s;$E>TrFQdV_pd4lm7#qf4PJnO; zBF01)aCQsmUN!QnSLaXcft4}povbS_7ZmNeSKbP*xRk?)j}eUT_NHGDKT7mnIle#H z$Un>NH_pV|0K(TIjmET4Lu8rZ1lf%zC^6@b7!W8~#s0Tmh~9ZtU9a=7j}7|uBiS9A ztb18y{~7DG*xW$*sU{?K7RAH1jox^wFKgG+Re*r>^q`gyd+{clX5VQ@w0NhGCt$Oo z#Hgoha_FB#1u?7Y{%uiX~*t>bgKe%(+`2t!74k^GN zJa$bTG;`}l*%dd??aphBr>>Dl8_@mQ3I#f2vru_%wZEss9sOJ9Y91NqZ*@w}g*E;r zqU!Ky@jB7o0QDPyG_g9Se|9*yFv7Uq(3<)Hprkf0M6&K9pK}rDZx(U91LtH=&)3mr zr4KuA2|iL=svz55Kcf+sRKk9XO%zzr~jS zr0~0FL#_9EXFdwtK}73+CsYlBesuL}Gn!9GnK9gd_5k?=$lQOe+8$YWS|3VcJU-&F^ zX0Tt>zt{Tr>-wt&@pm#+GVc5GqJBYo*Ywvg^zIY%!Hwq%@z5#G$3vM;nm2Aer5JgY zVi7xIy0Q9?v$9gn>VE=SEe`5yyx_oI$l_SMMfkvqAE*e6yhpb1N*J{I_v=1Xy<319 z!pL=J{T}rQep-d@3$fMIIJf+E`L*WlN&S_cg}Z9Wik&BaoV$kod;>H`yt6j=;fDy> zPW?TSDc8c=FQva-%bzvmCuYz;_E+r95_?QyF;0@|4?& zlDu~PN_QpZ_*L-f_s=S8k7K+=j|y^r=1 z+56)Q?jf{9=FX20$;_mRD4`$*m?(qJ`#pR%>%kC9GyfOoQIXgNYF_fLY*D^9{`igE zZ`Ynw)zA9ZgnU~&b^8~W)mrfL957#<)OI7sC&t-dk-p;B?YSRNRfvvjQIXiSoZdbi zRx@J1_etZ=&^?IQpYu;Df#T3HCc$a$}N#;#E#pQ`e!KR!IYnD%(# ziJ{}Z=p&4neJ-vW=eO7$c)I|&^%u=*FZk8X2iy`rzn(0Uy9arY3vbT-dDj|IOILI) zorY_b53cRJ7DzxWQR_j>6Cn@hp4{=h=UV5#zP9_FcffxK!;dy-j{_Tv-dex9DsJG# zS132Ak1Owc(f>v_R)YAGVs@TI)4w8O1f-ly4V$WA-WkgdA-H}HFcHuxEfXhrYx}p{ z6eYBn=oKkjZza*I$bAfL`tPlFSydZbeIb{h^lIZ59$?_M!okU#h0w#BI`cm3!w5Rl z7rc$51Cm&W^S{pYY^JBbt#)821_4<_ugg6;8x0*8xSI(H8bmKrPdZU@1869tZWm>Y z_dmGs>DGZ0z))YTI4b32(%ri?lgeR$Wrf(Wdecj-IfwO+l`idv%-9~Ultt?zmTvoS zsbs?kdjj$p2jpHnuKEgLB(BvhLAj3yjLR&~56oMlDoE81b>w_z8GO!fAL!B3Cv z{@2>uIMU!eHGC*i+~c^Zsyx0WH2d0_fxWnun>WeQYl9;tAEJG3J{aStv?ou-m`Yhw zaW)w#yb}DnaOBAw?Xb^fKGWSf_kB-BM( zoFYaz#ynCnqRF}{(_r>~K-~v4^mpU<*bh@oyS^UGnOkB#peDu~m&Z10;VT|Zos$jc zR5t9Fk60+u()oPK5VgNAw8WX|e)m(CW_g12q;bYG0aF!HnW!zzW11GUl;gdvw0l4e znrm~FlE4Lop9G^=Kb+Tnpe51Yxr%Q;QBgC*&8)nlU*Yz_lg(P>1pe3v%V@xw*o4Xj zzu^Qc@`#mzLVh_e$vb+ShI3h5jg^l7x~=gKZ#hd*-{4GkICSH->{|`3Kc>unORe;$ z0;N-VZQB|8hW;Vm+U0ld$&u|{3oo74rTpCHK0(uYP8r)O=mVmOrp^IJKIGY&A^+SS zEYrOyO2ieZ7mW)n_itNNXqh4@P^n(d5xzQw<5BntpDLZQz_^uP_4x2EM(HE0MsEoO ze+DaiwW1UCxe9fCt>XN`f(-%B_MtFMA1YU?==M(firUJ^xkSCru?g z^H@tcyRpw*hJuFq=5Zt$t_dZ7! z@piYvy>%)?puT1?+4ozOJE}d8wSY)hhMD`;cO;H_iJ8$(c@X6N^uZKxdw)03!7~EbiIek4ODGwyeD_jg8(Ptg)at?zt5s9V7FE zwO>)z7hO`*ouzwSeF|1mc3!W(^2uRon_1*WQLnUA2QqS_3q>Tp^}a>}H7^mt_TiKF zjBcT3BRl#n0Of?+i}GWOTwUi`3>sA5y!)c^PP`w}{YGeK-BE;=!E@nQ+s3BZ^7@;1 zZcb1x;Mz>vH({zp_nknn(}H=!`q~1xVB#F zp79ZGQ>qV!=@!=7RX!`N01{W)Cbw*Ub&iLqH<%c(PL?md3sy49N|XC6GEJJoLAe;C zNIRpu5h@py&Q*CT7Kv(FAPHk;Srao}^$HI=BQN18RtfH>9=G5U#v~$!Qy)JFviXkC z)q4`u^(qXBokLXF`??FWWt^tPCtk(O*kB&Zs_xO$%G}eOXVic$5hZqF!o}B9&oX^y ziNj(bi15K09f%D$woW+adb@F;X>R$l>$;_d!Nog`!wauApKQ_p{Rp)a=cT}B!93Szg208p5C5M!8o6ir9UPCf< zzHug9BeSozICWR}16a-O*xFx;enRun~h+0WctRPMWe#hh@Y zj|2-JC8muU6cDUsk70i;s~(t#+9e#xR#(g6$^_smGS{nS4H}HNW<^oZ<5w@gQin0K z^)p#lGPn?*mh!AA=0P|^@sl-Hz)>266>w#AN}>CCuykC#3a0KTZ786A2;G5AU|q@Q z%4{iuq_)7$&kwmeA4|qGr4Wv#arL$FUil(ZmXpJ{k_#iuh)`zh^t3_QPpg>4knb+{ zB*3Ev&0d2?a@FfXC^on7@;Hk!=e`?cA~dvt@!nSEW68xW4R%?6jUV?gOR|_0p(p<; zEQ8qe>T-Vs*#-Lxop!|_mm>Ku5KAnMvVR;(j}W;>u{1NqkO)5+V%Fh+GwxyB3f@>< zgkMG8X-pK^Eau{6e>T6EDg*8ZlJkyvI3Gz)Jd)zlQ`W-k3ui`*@={uy9v{A5+;ZKw z&&}*-lRA;X|Ezg@PyInLWexF$rQdKyu-WSDD^7we2#<-^WoHY_WO5z+#Q#lVgbHtpvFU%?SY>P~=}@~pXBm~F_PPG4YdKd+=)y2n+jYwRem1P0UJ~DT{f)Uh6e74u6BB6eNRl|>^?Y47Z-&J#25&Z`y_g)Dw*d>Fd*EcM9Cy(owQf3mb$n5W>8 zCV>Si);hPa&buBf@ndMfYZ0;a``eggs*N_W;_qw_Kc@eqRJ0`bXIH`=OTEu21?^GD z2iBF5yUe_z5v>Ohk7!q9wtBkDvHiHaUHWy}W@X(&sDft=CZEShd32~wGe{egex<`J z{;)Y7`F7)S#8f?^j9JCy0XMD=-ZJUS_9d#I(bowY7ZC(gl%OT*IpEj ztn*;?;rs(hTi*md5I2SFVmWL|g&h<@eL)ZNC~&oa<6Rw09UZj@qB2tf#vo}IvzyA) z4_jo{f3n@OA~f#K28}|x zBIY}et~HmiVbcp3!zM*Itu7P3{bbTSqg|bar>AW&3)wK89k7%v^mqf=q|egwcOB)3Hpt#g2xPi4?c57(P9^D$3y z^o7kd8poKKSdZE=18|)W{dtj8tX@UUpS>M{NzP`;ts9g?T*}gxn3w%W`|x*I9st+4E?w)R>v2 zvdmPby4lWPEVDIu_L#9u+atOA`LJC?IUO_pQ4wu-Dsz7eGtVC8NKtG8Fk5Swg?_Mv zbwNY01*5O*Ew$S^*!ElnY%EX8=t7lA5|#yS&5=MGoOV1I*OqMRAyBTtdI)ZURv zZX|1{$j@Q4;W8I?Fkk!Nn0#pAC=`66%czAR^Kag`-Xvc-i9qeuEP@tLm`n>0o;C9B zLA@rvVooJ`-u~I1xbC$h48=;II|#O>F29$;yxG1hAIm5PEhv6_N&$oh6PUH%qSaiP z`5Ve)gC&x~vjVE1KLO@#vQ$94t97h=?a^{kDl=!}j(Qej=t+bQ4VaM1%oTIBhRU}v zrmn6-(K}yCA18_8IKEA?P_=Ji(v8`C%7e&x@i{3jk1c~+_TBRrokA8V?iQs|mJB%H z+6{&kqSicprB+_Se`@EB6EE{e8B@;`@Nk&Hxfv@OEeZb0c|n0V3e8W26%{eB{AHva zI7%eKF8DCFruDgEVF0DOg>a@q-u!{rDJ(OPHh}K0t{McVcipZvfR~4?6V;B9n=u@^ zkSAt|F^e?ksk#t#2xPyZf?NezNZ-~fzP?CXoI+RGb&Pfj9jlC3t?lNlt0`tuixl#g zbHxHLZa52SzQ0RWZZ(BZlWs2k*$_9t?W{*tZ6UFAsine&L~~_gsTBpDxVh5iL*(-K zdP}TWk~YGj2V!M{$n?3iR8!$+LNHYX~p6FUod+gaI)`BCvz z!}LE~$R=VJD7T$q1K&i1&)sJ3(hMItxM!qC9TMvHt^`u;{LUgOtsGa@mYne%UIAa7 zYCitq>;%vjlRB0RIXDsLJnIRlMEobEP4hB1zD3 z`Y2Y{w&y{@IDQKU)xV6UhfTd530apx%lMCWcnr)LP5?I*K`J8m&D8>TsyBlMTUL8K zgcFcwN6Q~=!LhbvBU?Yjo(8#L(uu?tXSa9iBXIw$^uFZs`44aOO>?@tJSy<$dj+ig zs-8KD8!8mR_EC})i;blQ?xakGj1dM)1UJ)xa%M#)CSZ(O8em9!mb0jP+)JWk*qlA1np)t9PWhiZ21~Br>z8XU>eM z+Y0FvI4rcdch^X$EdZ8>g-(C}HC*_6WTeHE`TKJ3?<*s}uTK81>L@yM_jkS5>3$#E zXxvu*ZDwv(F=Kbeg+sruZ~t@S(68~rKi+1{uO%Tn`+hl{1`XEyx%cKzQyuRwDc$_HxB0+Ty{dfmx~7VX-`{>eJpWgOK6qO7 z-;(3MW#4}*BgKyTj1V5!mSys)`QK`0NmXIG&$|0?@4xrG|2{AO`v{Y)s~uW}mG#8D z{p2h8ni6$*8TfL$$n)NJ;O z*Y(F)il$)$shi06rcEDwo|4f@c1TV zz>HVpsX%kJ{2P`n4^6_3tL}TS(Er(NwlAzV?4EcfeOu%9_9Xk!BYPfK#tIr9ZCqNL z9ZY>ZbYSD#z~hnajoy_@O$pC&J7%~1(FkAVcNN0Ef7QzCJIV*unaBjyrv=^IClBJ& z=uF?yZ7;XHqJgK9j`&!b4&MHGGUcvLW7I_GQ_h>YllsNbv+H@D_Ygm0nq2VtV%m+| zFQ|W8H_eR-95-$5k2T16I9+qb`@|ng{o`bQ*u{f8IC0Hd)zVZ7lqy+fY|30nB`;1x zuwgeGEkOVx_0O-5hGynu6AWN4XAJ2joAeN=6_@3C@CPuotvHN(kx$i9CkT<|@S>Lo zv;ZQ#Y)pVy{~*d)|A`l2oD4o}DK~52`63&pgBhlR@7qjTtL^ai>0>D5kfW7Qn+Z|l zBn9Lr^`&Z+ndSu3#neRRzK~zga@$43m*s4Xb40n;lhWlHgE*7yo3@F?%g9=LLKDP( zabwK5ajOGU*q)Gm)LZdZs=p~aIG{I{ZR#dlU!A|{$+J%Et5tFbZPVqx!iJ|mRWPk4 z`hBtW=FZPOhMZg80wbSgt;?M_vrdyPoyix6THn0nC7()}m zw-q#f)KjJm{O--PeamgmO&}yk9>1o45;eG981s@zr+PaLX}g)v-4lq}t=69c>si{aWKz_wI2b zSs_04+Pd3sR^wQ+X2}=Z6OAWs_Mhe)D~(KB-mpcTba6-M)Saj`y427wXF7b!P^&oC zYiF!e`(v5^?mpY@uRPhF0S!~Mb2VcBusRUZUSgaHp*4*q&uNaQ=~HBXl7L6WZN{$7d! zV8_7cFWeZ1l?QR1yaOI(@$~dc@l~MWzmI)j=Lb+S-vSqAAnMbq#twl{IOxyEdNL2Z z9cvx|cK*BGHtqI9B>3X~u@4x-C+k&n#}F>nKQdDFB1rgoVC`B{%^_{G8t2a)$Q~aE zJOeQ4;0h${=V*`d@rS(D%+@7Jlps_td~4-Xn#pU zZzpN^*I%x&!l+`0DYB*eG@ifj+Ob9JI=1x9=0B{M)Lk*_8J?;g%k5s?%jIp zt@swSGC^{>6JJ~R-T+=!Mh40gIs3nuJ>MFlCL^&h{O>TH;e zkRn?;O8fx8R)xBAAQ-MRqnRZSXDzZ5mm?C=@v^Z8D3C5c>X&~r6*w$Ufn3A`2T_BR zqOh>1@`>G7@Z~xYHeeI-Yq-H8+|lS(sVtxGFyA4~G$!hPO=UVyM5Ant`VT7bl{b$8 zQ3)bZL{8uXuc5}?#=nU&i|dmBNnk$avh3GzgJ&@c>zCQVe+_B!c2jQh&KPZ1klq(~ z#qnZ7bMSk)!#{$KD}A^%5uC=R>uRehqTiAf8pznvr@ee$6EZ80gx+=xcbKw{G<=HL zYL(}ukkv<$EAFq{QP!goUQkJ*P{R_{`Z`fp~0 zC+*T{ij2X+_{7ak0Ueu|q&>N>!zR*#=<3Nu!j7CTuN;CsFwd6#&5iK!3Y%4jp6w1P=g`#j@|c*bFZ%06;q)V#kdO z+jRU1fDFgK(+_0=01`E`c^IJc-rjxtY|7;p;uU24`sAuGGTJz-;zY#);2@i(u&@Z! zh#FH*np6b-iI>&D000r3GEnJ9;Qa;v(-}iFOav7X$TdP5%(z-dc(#Och(-q1K)HQ> zBb4mpMb&H|&TpuG)s}uWzY%|xMi}a zZh`$(IaDM7tei>&Tl9hAY_z3iH>!v@swdJ&lWsw!!Kx~NtjmHC)E=JJ?+xe!YW4J4 zW#H5{07<23K=s_yfj|>oKSc_DN#%+9l;ggR<5^iUy4_S5YIl6qegH#P(gnQ*G)LG0 zSjCcYu#%=Q$1QPot9nF-oB?Vf3JHR!JXD7{)bbgLZVJs=jXEn6=*I_*5fTE*(3oGj_y1 zIM3AXYSk-cFn`AIHA-tnVDF#8ZXL^JL2?EB`P<(Kxsv;BkE?K zA5cDe9)#W)7~^kWM5H0WDrcg6OwVE22J`VM5_QPVMnHCCxq)cy22D%68xkBbCQ(1J z?rrWRQnvD@A^-bae#b|jiEE3LbAdG$G9ehl8Tqk7uKbF;fJ z5K;$`$J`adhRgp*OTVOESVU4KdkF1tJynseN-b^D@AjknrET9YUG87hl&dK4^e_W|wtu_<1&5R2mD(>e7%|T~eP;m`CWCC(Qoq^x4Tm|f#4oR%fR1vWg-+IP!Si2KZ8&$bx2KG+dKT5ILoC6P?Wl_dUj9f~G;0OVMD zl8{8gii9Mjx9MK`w^owu*)a(as2eA+F9J&iKtdeYA(g&4HL%ib%wDYLR1S6sDqH^+ z1IXZjZ?K(ONQ8NiB5<1m*UPb5@U22%k1IR=7pg-96aIjmsNl^}PyMB6FVD-d^d+H` zWZMUjDE zNm@m!^=qMCL&GYMs{)T3hD4hUFP+NLdPYp}J*#B_5?L%6yaZs;?^Sj+9iK%s!qo-( zMbb4u3!HzJy-qb2YpEktkN%|_&x1B&z}6dOmWZ-7|AahcPaRi*9S&p@1hyv&?8%^H zWuR`Gg1tA`j%{ckC9pvR>0I%&<;>VJFeX8C`vI@ND%HUNsx}dbY@wE%y$@TU$#7wT z5FT1c{KmZxuciUGkdi2#PAN~3$k$najs*f%2u9xjY72FM#mXpPUzzv6Fojh9HqQMY z7i+&2ZC8y8QD#5agY%FpJctBG-D*Nq8r4}L0}O~DnSsa8)3&RLbzbg=YjS|Vyk=Rh zuZ=1qFpH>%Et75HLydU2sqMA<~!EKmA=6(9d7Jdbzb5zlr5?2I5u!CCipfvfOkYahv@1+3Ev)x9Q|piJ~M(LKa; zcjX$w8alF@Xa7~;(k76;(|rZ(F4a)+Y@KefJEq)?3w9qDV0lYX$~37+>LDh%-6gqY zy>?$9nYL+SgnXw3l6zZn`jWtjENh|Y?GYr9+be@eHF1JNFtapQ5!hvx+R5V1F%8JlAfQ3}hZR;tTqg$?RMPNvouLZ7CrYXNjguQy(X8~r{1f`$B z>2t5mOXE)r5N*GbTw6%)EK~Oduw7EqLLA*qTkQS^?0$`IX4wHhP1-95@t7q!&k9am z!eAokZkDEH1+SfE`OWQ1Hpc`~cFz@?n*IXp+Ff>hpIl}RowCzMu9WW4P2yeBFjEe$ zdkx;=7VD=1Jo|{9yfWq1o#OEaT=GId4nBS%G}cT}8|5l}@;>GS-D);y$V~+?RpvS_ zEzgBnja5H`_z#~=7=2_GSDm)$bAqAy?Tht6=1Z@S1GTPRPiX(u8Tq91x`OtQBx@&p zlqahVlHcI%1YldH6s*5SdC5j7a6mh@f%_xDJMz6;JkxdNJZ*_|t01tQ5!f0_!p<{v zXM^#sBs(MeW{3dK^%|%U8VQehsM0j26l}79eC-n-nt+~Oo=QF&H}a%HFuWoo<6t-seXSX{K$H%8 z%KM=q7{6_|rwVF3W%76jjEDz4Ur5iF^~pqYJCNb1XVj2!pd^l{SF{}-#|!@jhYeQW7g-HFohJfVy2|px(C!SEc zb_i6H?cGHCs97nFZ0`zo5(?b9!EXP+4seJ|kN_Vi@F;)p0V(Uqk-^LZrG&AQv~KPq z*va(+fx575mTJF3TK;8aUz*}hq3;2_^;i+uDfcUl^9XAK0(GL`2EF_e*a1s&z;AL- z5=^fHuso96AG(tt-L{D||C9tB0}#Yuw>;AGERyT^KK0bYzgh(ZjzG5a{{pTPflf8? zl%|s0W=T$#0-JJy>%x26(*~IXJR8aS8#gJ*oOH|eZt_PbPbA07O&INnA=$Q&-kk!w z`~@T8NbY|GF0(J*y#Tun;H0MVpE0l_7Hrpz6QAP^|LufVSjlZ7{eB|w;DFV{jm~0$ z1M7oap1`9`&;X(tl!FoNq(7=}Hix7g>ET5KJazjr+}cQXE&DzmG*ka&(Dl9FWszq* zE|A`V+gO5~{M23MJ=e0A6wdO@$HDHSBvZU_DngELmcF?vGv;!5=RdQ}F~at~(>0&_ z+tUY6dL6fk88rWZSABDBcIw+((lx2HiV7idesSC$Y$lb5Ic2s% zBwO4&WmCDrqC{J7x}C&My7_AEte92NR@HGsp1k(fR_ux7fd){ZpTe|UNRlcJtxpA@ z`>3R_`(=Ec&=;P!s+#4RUg;2sQz)Ju`93-haG1S)^WZ!DqMGFwB9a2#A~!wb>{%Aa zgDQs`84&|Ncq1{}U)|$jlx-o`#>Pz6bS&3^*T&#UJcA~Hx2k#|p>gK|l^Xwe^-}pX z4G8fbvyP_9UTZc*P|I1?k!wjhV>@zbr=rsN7$U#`H@)Qn0C~|9h@l;-{uE`GWUL*Y z>`9cJ;zJ1l18nZDD>rvNB~f-xt~d+a1~Q#+WlDZSM6$B0h;Bz%_ZSBdyscbn6ix!9 zVzl6?|79t%>Ke2ketM#P+Rzp8vv*>e@zRIBZ)m_>8O zUNT74K;Xul7X;4bKvMQLcR#wg;oNFxhECr(m$dm7vbMstXA-8{Pm`ab8EJ+nldFuLi6OybCit>9>695^9y4DvqB!wS5$8LYk% z;eahL9rZ`7Z+2TRWAOoMMWpYly?sgFT%yJTC#gpG44CY=TzP>MnP&3=I!0``MUx66 zpohxvs$e^nTiIY^5JFF<1%XEpD4D>A?xDj91@0`o?tk@ zH$l_Q(}&dxk(!f*8Wy7lvDpSGgEkCnjQ?oTxABk-09boWA5X=&0#)t4R_tO9I?(N~ zB)px#mO!#y2Ti4=V7*C%3F@v#L{mGk4Whd2hxM5NlHJ8>Voj(@)MrWj@xM=&?bbnt z*Sb8a`nBqZKHC9+aTS2-7qB+Pg>3)>J5LZ7RuV*1!h#?RL*}JCaQWOe3>Ab>G)H=Z zu^+PK|I+6Ie{0RWXG%2Z&r>OHdoKoAd?1dve% zNLP_E(F+*0f()8+UVdJz>ND zpo(3dCduxl3{PXU3fIS5*|rn!dD|oJtFL_P@2ZP#eRR#0`M_`1(k17Vgh#K?Tvnui zI?BP%^1=t-dyHBg+VW{zD%&T%?DQ+J-Dp+-lTIXD>b#A_1bzE{6OP7vJx!p??~;)v z3z$!pFS`Xq%fHU%d?Td3iFreE7y$U5 zxx*8={(p`dR~MQj0dKiJ8#Op zIZAr~MrmJe0t}}}QfhiCcgZno3~>`|DZZ8^H0WZicChbW`iZFsOdF*M)qI2AEvH$A zsW=AAmAib^IO)Fq{lk*;pYn?cnX8_suJBH|d#23v*MMlcJo6o%0$V@uj(s@|06v!B zVHN>IuehkCwz+?iG2BX$w~3gQv{g2AxsTZ;BDa!kj5fERAZB$u#R1Q&RWxUG)S6Ix z%O((%h}xw{#V!DeO}Ga#;BFUHMqcPB?H)@Zcaz^D5E$AhtBzMB3n4RQxP&%By@5}) zI;7UXnAmBY)Qp2~ak5;bfPgCI7xU`Nz+>$JAVu$(av<_pBO8I!?)SL^HPkq|F3X9y z&A?!$7Scd8jI!n-Dd?lous8aGWXmSwPOPGVj9&kr-^~!xQ6LC{Aalh6maSULZI!)q zw>&C9e~A0>fN>`Jh=V0@CDlvWs?0iNu6jAtt%Of0A7ATcTqyZodKPQx2puf>X7`B2 zf2ZpfX8%uNQ;uYl^lo9d2^)5e&WEG?|G#Uhra$p()C9#E)a8MQ}o)pr$!Hm zs*G;Mbv?XRGMvt?vA%oa8kr!6c0cp;viDIXutNtjkZvvQ|x+c?`7rDnG~H( z4RAAA{M;?y96&Q>|{wu`@8Dn?S~@9 zH@OT!V&hv&mw@H4%ju*4uZOSffZNXAVrpq?=9R%TzEt)wOyBTfttyb%&3Z+;{0{i0 zySIAV)OM|ush2E;LYSAU;4s}nQTZ30{Dt{x|J<({Os~r)s^6SQj!Y%%9JnZJ)va>n z$(uHdV-eGmCVdwgdUByn^x@=zF@OCF$`@ytI{2zA_F<#TPr}_r;tLAfw)rGp+7^)6 zWKn5Rqy%G`(71+Udk-pa)-IimpVTeddpXlCYS*J6mtPsxn=kBcZJ*wja(rK8blS5k_GYTUi#!BxH^c%GQasn|bA`>>bgU1D>GfANy%>)?|w5ad_J=F zO7x2P$))DXLr;P|AC$&;IJ$aA=|4q3{k!??M@d{EMN^}bEBW}4*u9N>RCfM8VaH+& zI|PW1=P{LbhwU$0lph>n_t6L?37>I-3Im7^_rJ7m45KV*n|^k65<6{(u$H!BN}9cot^W{d<1vx_c@ZVh{UP_`LRdY`sg!%w4%GsP2BkSkf z+^H%wcqqtujsm7mPHT~-nSe%mia60y3QS73g7R30i>8$vsB(~W?)3`86lge{F1hzs zP*EdZO2>npe9Gu4*Sq!wNGyBW&5DD0Wsnq3n|N!1!Oe|%4NFU>6BvxJgCtSe?_uA` zdv2zw3IK7ECPO5dBnjLQR2oe|fTG!x`U=-Ys#LP136;%x5iWYL@9jfjf(pZ_cFs9& zwpE2$L6fE$ATcl)t_Mg~DzX%kY62@0Ihe@@PSJPuM`?HR^CGL1^B&d!O^aaABdw}V zaU;kp@nD6O24?*@|6OVL{Opl|lq>O#DPudW;8JH$ujFs)UDzeIh{hAp)5&{zd-EXh z-g@^@fFvG>^aNugI&wuL*kCOP#H@A>_Y2T%c&8!z%D@4C-rRHsoXHH5JdJz*EYy7E zZMN;ppGvy%EL`G7o*dcN!B!B`ex+$DX_ZGidaBbr*|bw7tk>D!Vb;7>2mSXo7?%k@ zfbm<;_D2+P`{7L5S~>cF2sC>eGj|l~uKA=KeJllC zgWubcVbcb5@iq`-AN{njpbU5&4?k{@E~KJuntA4w2yv+wEJ*-DjuAgdm;zi|h$A;S zYCv0Jwd6el1PI{*Bs}RtKEVj49iswNL|3)51R8M4Kvs@UkG>f-ac~>^9@DMB?3z;; z(|Lq^dW{1elS;O?6k)#BKHJ!LsErmGV1m){`mJ3QX%7_sZhTAz!i8!25h2QOOF$^U z9+*j-1?)t*ubIt_eHQXiym7+=;iuf|GHi!yxFx-za`?YsTHkDM^QwQ26jLtWHFbQ( zCGh>tTcjeGH15veUx%^<$+1NXM}XC#y)vbVJ$u`g{M1b<9WS&KYq+tNM9g)BJ4q#iA)r@2uRGD42^TEwbg_(m#@A(iR?+nQfLK(LeE+*SB9^2T@9O zgrU$j!o8bZDk`4cv6?#8Aw@XJl+rC-*P*w)7S}~x09vBg0VEFon5L(qhf>zhLOG)W zyPa13+}kUoX1pbiHe36wKGi(wNEJ4RGNIg6NfLEEw(RC8p=Mt>;^&VK9g8*?f?~$Ra+T!X&L=p0e$h4HgJ>g<9 zq>y|iwolm8>QlLuGF@GBQUwN_h6he7i?Foxrs0}&P$C&roWi&Gyg%HyGCULyXFDkm z6A=I+gmVvVMcCV$f$jl;k{skmGPr;!G9HYgLIIigL{={go6o!($h@$vJxjA^?JY4k{0wxv_LOIc}%QoNDRhm~i@hBLDWKRtX!rOm;z6&=FR2l5aI zJa`Fbejw*yNQX!EhDAv3ld@DE-7m3Ik;jm?yWl})VACjA0FZAuXBlFt$pWIY-P{Yf zh=MR|av4fQ=g(}1%+1Q#5n&hl~ zjD`Q!hwT40^0#K-*%{P8G>R6#RJr$hWhAusS0J;@esW` zbeSq;llT)zb%q$>^?cAZF-7mA&@kltQ}|_HH-_>rF<=P??l+@!&r&cqA#+E| zfA42aBiFx>GqSNfa&W)46+uLLnvb%h0Mh`-f|Ecy1_F;il^irmwkQwPviliI`yqi-;0EpUBz?r_#p8)L%y3K(G_QCs)jZav#uSo=`L!Zn< zWBX-avA+3ofAb&;4gjbxz#{p=yk@`VaXsm=EX6&BA^_-221pcZ$~-=xM&?S!0Gue~ z<6qkmAAm|D%6x;g@M@O#ggtB7bwL5za z-~An08yWUyGpEWn;r=rk0oUr&K>L($Bevu>^?63 zZ^Twvg(Jkx2C4u=8#y9!;e~r;5_cTY!Ng)J7oiT7-W2ekWpWjkVikgyh=>#zvW67H z?oq>c85Et=lJYWHGfOea8L?478^`4h=lRh)$_FhkUOZGkBEq`sw0PHP7T{BMK+x|H z=K!5p2c1*^U%C3lT%b4}s7psEs0M64zhXcJiUWXh+{+?0HVo>RVE}w2TtgcmcD*7@ zf)45w5mzH3(l{D>c#Qr%fCv!+<-)Cq8Z}PT()Ngy8c`8|_-=BT7yzii;S0A~K?e3~ z0EW;CbNE~)+~5LgYF1S(2l3n&h-!cYlBXxhVBJONqiGma93av|S0@sI zP8^dlKn)d=OpSHWp2`ysWk1wdIgqiKYJWm5#p);sgoiL#!M zZm6_JQLIqLKBCyw&iOAe&t-|qd$ip&q+AH*$n)B8Lv7OWy$Y*9rNG)ZLknGN-{d@i z(zO(vxhm-k(EG%=%t%|~=7tiLE`CfCR}Yl-WXOe#<8W}8nq}GuL&k$4Gt`D#vOH;> zY_L>@8&$@7SW1VKJ+ZKJUbIX*Ns(>+>5@~>;^W@hqr>;0&}Gs(6$=?sWQM#sQ*mY5 zLqPEJl@*g`1gFSlnenPq^xFzUkxh~ED3f2MC_QiUe2zY|uUb*uOS(0XG>AWyNmnSn zAiu|ux(94oY5O%lD<(kw(t+}ROL77hFr9&F2P4khqQ9NNp-dSkfPC7t*nFGyleYBA zvYX$5=Np*&#@aGgX3j4&X%lT3Ux8912h~c|Sk5-;@7+>^IgKlV4jDtrb4G6ZnmLHuP1(W;zq8=o zFyUC~aYtPhE&@vj4&XsWX}yLRIG~Kow&aU%5Ydth8M&`Vwl82r{AD%ER<@B&l*XEcQrsArA%e-P04i8p z?HkpP;s8XV0l4YQFMmm|O(TwS@8$Xf3yZ52!N9&g^O(W0k$Z3qN4StI>=9x6E*1vm zK;qgZAoy`(GFXoc19P?eu8H3E4L+uU5vxJIJYy?1gR=V$%H1Md-vSqMK~`Nc`g2p$ zX`u3GlRUhR9Z+n1w?>}x=;+OW&OZIu9BSWbAqBk7+O)J!*?wwL|5u8}kw;4rH+a>uzH(xx~sVQ@KTuozh0y7Q{NvC>M|<&a}Qni@S>VA;JnJTP4zVFYIj!?8S7vCb|XaA zTVJ?_D^n%lzY{8|DcCzK&I@Z~h%)vkK+>y_!KDjWP_E047!M8CwGlp;7do~fBzE( z`AkcY`A5_1eKv>7%}vyT(~x+wSS@K*s0_IMpJ*BvXkG(Kj$S|$b$vcnZfkx1Rif3m z1(lxuqEU)*qN6R4$-QTegUs6`%s8QaTOycgw0J27QU-bgNbFyQ){tQk zil7=G2H?irQUS=dK@@-?RWHOvxCg@w+&NbjdKi*6d2TeW^Z-RZUX%?@7oSyDDs1b% zB!*~ZD7;qY3ElmEAISgEq0p*)Z2<%$lqq!1^gbjDHAX22wBgq?*UxIUz6;&RbmXB0}6$wD{eYG!^}D=Fv!`A=V! z%MLLV-TtRwr7S-HlpU3XNzTZR0$oOx<;{Q!uPw6%Krk#tfy7rFpHV=y65?H?UsDtb zraK=$9q_W29#B^JS>!57vDULZzPu_sz}U7vs^H1+ll~%pC&>=rThi#hz+DFZ{Go&~ z7#?VdTMSifaxoR(3s2U+-<2cG@HWuck2Q-H>-|`h-|5>Ij{cbc?fUASXWCkq>a|Vu zDqTtn1!L#n+)0;``FiDJw2NNt(ck;>+x_*ty0Tmn!z9dHB+$9SSyk)mrzY>$$?JpK zB(8fmSrQHXM;(6GT}!fU($(qCoqu`td1m?Fn`#+P!{34q&y-cj9}2I~?&Ej$+?bo| zy&_?eD{69ZVeppDn+1f|Pyc?-(VNESiVXv@ZW{HwBV{5!juvUyKROb<88}{c<=as9 zpUAZ&_r}07l?P9Le2__cr1HG>R)pX4Ny&yKg_j!_d&sw%hdxDp6ofvh#SEIM#u!8_ zRW*Z3Lt_T!V-%$Rd1hWm%EK|^RK``4$>}dbz=*e9bO>U&4FZpt{zBhf)&Ri7O-4nYAxX`*M;Y^`?7l%b$pn*xCNnSqPm0C_T*&V(PM1A*WuF^Pbp zD#EO|X1JDUl{7-aUmPUACphBp}~lQ>2mts6H*ArrLuIK?I;P{Aiqvx$}#*}E+am- zZ=zAQ^uutRx1_$e`25TDJe8ikXWmy7+c02mM80-SP5<7U9bzG^ms!XBdw)L)B5xin z-j8y#M@}A;@j~Xl20)(=7G?#B(?&&YY;!{)HkJH4eYL?>&s1ub2Q)u+=ta^U#{RE zA}4FxEMr$cxmd3hb6xxYTlzS|7>xQnd*gCoEa=C-#zeSE_lqx%hb?`if}3X2kPCCeSDg>6y1AV<1Gf|FS`K!A%2g&W`SGj#Z}r`|u`(}N zZ(6=D{)sxgJG|wxWCzd8KWzWpo&i~X55S$7O8K5-0-2sgRhep9)n(KR&x%!#cRpKp z&GP(7IT{Xo-HKUqIJ(40ekZE9n*#}xU-yzfM`myriSBgzcU&aT28 ztec18_<%2KoPeGQcI$!UNhz!GLA zAQ2&Dag9&EtWE~BxTvJ-=d zy}s(x+P^jx@AHZ1|md-2mxZfkP3y`RPH1s`#mDm&5lA zN;hgNfr~+|rfaXW0tYIO@`Z=#Khbb0VkfK+Af(9y0@mm5>gKa63_o7W1w06xhHH^> zN9l4qv~IkJrwh(uR&hr#nY=_n$4@eG)zkiVK-vAY`3_kfTJ`bsyWO`fB<`kMSk#ZH zdAF}mzslxFrE6B->qIE3%HeX&$-8GDa2pjcx}FPqG&(%gd$90Te6WRn@H;g+Me)zL z`jM-g466CO;tx;zLvBDf{^LzFJR;EEoc&g-c_s33{P&>qe35akS>)a1{k0TkF$AGd zc1)XO>46sYip-RfdP1@h>CXV;iYx{9UsL4HNP9iO56E|OEi)X3CD_)3r?KCv+S037D z_L8#o1tp!B-czz61!7f?b$p8snsQSP4N-D+@6U-(25Xf2(z7EXz=+BR$C2rbT;20t z3SVx03QQh&-f|oY8z*%emLq1c;~>SQqSpymO!Y9~lwoFCo-K_74u|`!eZ{_4*O5{bR=rVn&zUgNY`{PHi>_({8lr?+Xx3ShZH#sb^Un zn;9?-P!}3oVjYfpHuRQ@m;X1+vN*Myd#-tB(C(l7MPG7mVz%m|vzF2FHG|1JOr8WZzTlbZxUNYk#$>bS*@YNh=(NWTgU&oo;oUJa+h(iA)N&dYkyeXrN0*2hPK=e!$+1mp`CNM@^l9F z_j8co-BIlG7z+B_4nFSPA@>f?I+8fmc+G=R?MiiGBv1`GbCvZ?>~}WI=tFNC^ELR`LtEk@;tG_S~NI&|zihQS|QguBnYeM6%o{ z7J3~2ti3B70*|G39~nN86QIeL9qO?&Ut(lrn)23z16dYNaI)B*WTiFUZkQw*vQK3^ z?}y>DiGJ4$Z|;~@7FZnJ`JzN1jT61|Z{$I0(o#_B3!~sG zJYniE*og~4j~QPLFv+&|9xAZZ9@UJ%pnn5IHA%Rw6HQ;0BcI#^R#hDZVnXimZ0rY+m+O&X$# zFB5Av#<+D6O5;Gy(q)$lAdXEs_MS<*$zXS)AOZ-iMnqi{ax*8UMz9ZQUX7L&v&yjo z$<>2y0@KKJm`7mBbVF$Jn6MmIONR?yq@rcI<;*#-4>DIk;fiYYB0IyVSOC~Ua1;0e zG{zwd)Tkr%uTbTuPD^pMaWwaYL1Bd zMMN)QP_snTI{kOfqhM_N+btwSz&FwQFY35(s#iZxzx@ zB=kB7^dAoDHVb_0Cc2|O_kam|p5*3Q ziT*)CZ&R;^%_IY~WER(v?{^}$Na*1hvDP#+4}(5_6TQVokK-f2F{t+$XxA4gNl1Zf zdbq0A4Zki_@1fFP7?E#Hk!yg+_thvG9kcQQq5V7J4+i~CJVKZOzBY^^MThLvBX0&= z9-Br#jY9wBBDFAa=J?~kcOri8APpNrO-%IN$s%t^$oFK?&vbMLxp1{AJ$Ogjv>vGx zi~d}Me)<*tfu|Wkf&Pl&Xz!EC(L>Xcl!WtV&=<7#BUZEW=K zVbtKT@N;sw02%$XoOb}rlobO%A)~!_5M=MD&a#`-)h>pWeIf`KV?Q^f*_vgMj*Y3u%hM5(RCj2RBRTh!qlghl-Q} zLZav;zcHu|K3;U3&DbQA-Tj4BzbIZlj96tq^ez-LWs4N_A!TZiYTB_GH1sMPQ8Fyt zT92w0fiH~+>t%xasp#!`^dBmE+^evhk$(7$tStdC#YQfW&^#V;f?oZQdhNv-^lvii zIk8~~gZ|4#Jvmr$(yYi$yAkuesD$?5yxi@5o{e@ba%8#2s}m3YM{9KWV|#J5(Ltyp zf2ZPHR+d{_67|}%S7nD?F%WaIPzJTQ`lE=*IM|b$t?E(rlT^3Fg+n?FrGXHAI!KWG z@tZ56HhnhtM2sUIwT(evrwT38(fOJYW~U)DgeS#xkjhD+1@^-y+Od4khgdQ2I2-+o zPZkkK%n!~Yx5(&fw$_pt`YjvuKotCjSKC7lGs26CIf+E1gD%`aPmx&G_wQD}$as7L zGG#_fZUIp^sBJ3Bn|CO37`07Cc~5Ik+=oPLhfq>W~qd(DKXi{VU)>uc7D>A=PflHZ zGA1Ka$N<;Pin7yTTGM9_Z=iM9h;2MNmIIuh)%LZMNH|mgej#r*R+Q-2Uh|^;u4(J7 zkL{m!8&4KzHFy>!Hb1yLZ+GEg#f9JsAJI;;)CZ?xjjgkZ7<+p`z0HS@f!(UFu4r&LF@~UmSCI3HGTl4yD z$Z2B95 z1ecsaj|wU<_tS2JiOycfMc}Rby}hLwkzd^)mWtaldBxfRR7o-6S#PV^R7J5qb63oBReJA6^;Uk2sb|M(q$#ue@Wpx&z)FLJOoz>jcyrvT!iTU@$(sJsGvdx$Vdm z`btH=V&6w*Cp>K%{QS46nGyKT7yX@w?BR3Zr%8n6kRn2>$<^yaL8qTVnktr*8#fUT z+A7|xw6>!Y+TC~GR8PJAX8y)+>)E4!cG=Ct9VM=sciOK&pO3j^@4cU6?Tzgl4|4<{yyACx81-G&vJ`zldOp7); zis|5yyThnUmmdZM#u;0p>sS8UxA$lP)1BQhwkaB(vH7Um1HCeh@UNHJzk+HnKxLmJ z$S-EZS*dmivCGLC9KQ9j@%OXd%V9xYa!17--{p#nWWKS z=Almy{;S(rO+wdwf}~G0Jj*(6y8z!m+4=qJir?gF{3p(`JZ1}G#ep~hV0YQY%^1-P zvQTpHS9wa;FOINMwcXjtE_GyhFu9dS7mh8Fi;QoWV1H)Tf4(|dQX=~05B`hWGIVkO z=otIUpCjpiroXrVz(ZuWMIz!kUi3-*Yv@|c$KqJk>gg}kI^^f~ZmKiC$y!p0vFq%a zcib7=S~K29*Qj1Zbqxg*{vN~V$ve^AHZUvK2CmseEDWQxQqgnV%f>jkH=g($-{eS4 zZ=If-Xw|fG(IsEgdrn0z@d^94$>_IuLvG1}o5irZXtoC~`#kQAQ9NxcJ_+={AMSNS zfV{?wiO+!lP5kfsk1OL}uY|6Dmi*-MEe5{TXacz!*A0KbtxWWR`wWAP30=&!w`pc* z%AiT6&&dDE4t&IvtG>7#a{P0!!n*?RDxAh2=8Ws>PBR9IW|M+*(Xk>Qp zr-(0~iEUbRO?}K@W2o$NTtfVfBKfcp!-S^x_07w!l0238?@4r8s~xDSC{U+E&(rbT%q^h)TH zqk2~^D$m>C)J^f**Z4~iMm=JUjK(b#?7ng>#VQ0m`uQX$`jSf{_)Ss$@x|@hMq#DJ za#Q2Vx`pq$!|8q&W!1K;uOydey?}#Ra3YlXdj)1Ed zU;X4R|0IXsNxGCC1OeBxOQzTeEhD5BN^X(SyU5PTwg&lSPlYkS#Q%-WvC(&1tqFAD z4FG04xoi98>=_FhgKB!!&HC-(_{m^HNG1AQftm}wD(L2$Pah4LrTrf*NWyn_rqd z@1k^|#GLnDCF^#;m(Ty=w$~TlRG$B`m+*Jz_m89J6B9!})JtGq;i15cdqJ(R*}jxi>Xy3?*9t_) z;>cV^e&i~@y1THFUR4H_#PwB5hzF+wpJHo!SvVgz2g|BZxN0h%$!l1YQ#r|J3mNkQ~aO0V~am_t`XTK?-HOLdp=I zgL6wip8IBP@;;`8H?AskF0A|P>6WF>Mlwg1CKj$ueIGry8gb^GJp2d%`aQA<8wDXrt4MGn^fYHMb?KdFSR3NCQ$Ih0x`Da zQehBO&ep>T1Pg6cQ+IWq)*sCl@2yjoQd(3FC=Q)$W|b;kS_zU5d9TpH~T>-_rq((yWxy4&$9mfg25R-A~% zIiB*bu6;Vd)!-|hr*X%Q|hpN9Y?Tf#DK_jND+ngYFPpb?d zL}d4G#kbk0e4WEtudnIRKDp@nczr@fKcd~!omY5GX`ftaTZdISWGcN=E zIA@8&GlX4vGNE==`Ig>uaxsJtX}G6i!5l%fk}1qok0OQJM#|@ryu{iGIU(4!kngiV z5wjCHmuafP zeGjbA50KN2A!nA=fE7P;Ao{P)oOt;aC`XeDF-^Xjnt4w<>S5n8u}8%0+KT%PZ>u_< z(s=B+I~Qbo9PEPfXP})wx#EZR=@>t!h&-@Ji<)xiwi_(VF~d5mMm6c2IJAQFGo1;U zIF@Jm<bq9^{D+gx6Lm6epje-c ziqrpn`!|&EbJ2T?##R#pRa!@bCA5@{8F^Y($abPR9)k4JqCS-17Z6mitHPzWJd<%<x>=BZ56!qHTt0iApycWq@V9R%OW)~!Cj7lvrIYOVJl)>nNkh$;x4fZ3JJ_h*GB>QV zMPa_)#;`@}=Gn)Gr}{sbSk9ac`V-o6`}g+Dns2$BaSoK711;3Sbv)N;?)x$ zrKBl9mVXg5cnfcLV%GmdHiIKGd=f0g?j2-J2N1gC> zi|C6W`x-s-;W$qe;fUrUuv5&;sqa)Wn{@Z-6k+`0d6hE(Ve&=z6(Y*8iorM++ z!wA>M-TO8p9-ckA`)M(8>py-1kNnuKO!-|#mJC+SQf$CdancgE z+LkA8VHE>Qpr=WZvC`L3TemHRvn^$GZ>j%P_xtoejSWlfS}UDaE3m>*tE;ehTAIpP zORSBRY)IR_My?j5sOSD6M5mQ;h_y+)^^b4+nx}yZ)BC8t>1u%F!v;^UI3wfd7=V*t zy$!1|!3g#JS3d$ZkNpz4x%6Q1Ov@cnYyIr@XAg}vR#CkMM*RAlD=En zDbmte(E@I{M;#oVOmSdE2X;pX!YY5eTe!ETWpMDWtONkeK$Mg4#LlxtFUr?>RpmhOyJyIde%0%aEv?S2 zA=bs&ur>nBrwQVLW%1h_pvmbX(e*4^QJOs*;zNR&XuZ6^5Lyjl`8Pq1S3%XDz^wda z1+riO4Pr}#+Fga2nK~m@a^-r`;%P7JDVmSg z5}ytX8)k)3AMRhZ>aJq=b6GTpH23MZ?$biiJusDW8-*NTz!Iyb)+sR%(Me|@Q!A?H zPdaT^|IuzHWsNvb4zAK3|2$(?pkwONc|z-kU;_B$spIbMimm^3zWGn9(BMIaq5ELu zbn=lI2Gf&ehAB9-kHrBRlFbVPJ&O(dRT8&F6N{jI?HUv53_s!kE&W5_Gnl)u zK$tntLqmvk{Dz^+xwCt~-b;pKKsQG>gZC#Nc(wd@wlx8JyY94M4$zmE&v*B{F)jRn ziZ8?hTB11M8;(HFbeHaQpyzM_S207P8RE>tISqI(9h5D=OGfp;LZ&~2j>``o@67*x zs>uD5#`{TE=BE+&{?F#a_PXxRAVaPHotqq-`a6C$pX=q-1$1IdI=V?H1g1InrL8J> z#BtNKi^PratYat69B*C zDaDPf#HzOkrOH)0fX6&x$Fx;r0-*}^(p3bX6SFY05>^r$%H}+D4lF~8P2*2fCbRiU3I=Z*99FX zroB6(^*mu@Q_4|6vCJ8F+Dqqxft{Dlui0OhFPu)i=#G3U#myG%ocJ6Y-k(lADf=BO zenI#}W?w~C--54Kf!p5kj834~y5Eh)SLo-Bg?Bm&uD0`Qo;_mg9zduyx&E7(^Y>HUqVQ#I=B=idpI& z(a7Q}eJ_A%5ttInIe=#83 z+*!=G2)Zs%5qyFQLxXN61{LK7-TG{Ltu*NNtDrkWW`T!M_^JkMmgqmKar~2(i_QVt zn#qS-4DJsFRfGmtKF^bD0vQmPX5bgtdZuF&q~AS7hxT+AV@Dt`2@V|XqTr{-m(G^t z>GmJ7B|(T)$ym>o%F;_OAAR%n7rN&JbADB2wglxzP4}OPWu@(J*=~C3H>?|momk*9 zPI(G+=a3#B7`_mFtp=JJ&x$u^`O_U*)4#B@<1(GZcQxFuJR7v6K*g)1NT*i;7P%qjQuliI+qRp~{ z+hP#Rk0^915PFyLF0LYA0YwE?p4Xs)iB;g6RUmT!B)bdfRrEHF#Ja?R#WsZw_JC}!VW-*>nS9TF%jqV#d@Z) z+&dF+R6IHix&RC*f<^|IVLYv) zUa9;PD`6XU$pIA9!;(CoD~DmxQzvjw7C%h`-$%gA)72GdDKR~;_VQ%OwLoQbgr&?- zFFrfVFI}n%TB$H?{x>a(EriD+E9$9RryBG1X`H?|JdE!}g9JAXMb?AgUB9b*T*#m(U6Lw(QbQO&{v~R-s%=)sr_h3c{}oDP z5Qsv@v2G94SQ1Ax4*iIXf3tNp1pYoA))bgdq797KcH}Qj_}@ilW7A}%6xuPYq&L%Y zp4C@Q|N8wwA&T}uMqE7tuSM+s4?PC(qvbo}8Ps7`cvbY+`{*0zW5OWYeLc`2nWv{1tEq zLCi~nZ&Vc8)bOGb#?1R4RIpgu*t_yw}P=8r(J$uCMh@-ts2_?r1+~-1tl@#m9V-6qbtfxP@6YBa==cmQ z`CYi7qE9o2B)3oe7gItlnAcyr^D=S~3e@sarJ55H`CUt=&|e7HLy<1(593UJe14S# zM(f3!uFt;CQ+0h5AJdy=J6iu#<_+!;UU6=yF7757;kUVR+&P(PpF>>XRZEOx;2Uw9 zf}pCm>kVB|*clah!4RtiE|mS>g}elCehPEnukmo#vm7zCvA8kzX>0Lm&2fJ3CCqZ? zoizEd@iLZDGWK4&YJumyj81HO&$%4gnQs(} z`!;IrdSrc2L(C5x+<4|Fs3P1YV)O6Zz}bB>L`QS{f2zVvLbKSE`637A^LF)lQsQWCYVhXB&eFR;i><0(@IXXE z_t5<<{H;%RVh`v!N7p7zWYJG-x|fdTz5JCep&><^KC<1Zs^w%feh_W3yZY4CV!QQ% zva7;^Y;Apq_}N-PFwt$@2JwAusp{np;!Cc!qn1t@!Sye-(FNNFj~jpVe#b{>1$zsh z5I^lLp7}CVtxPK|75Oty{dD7Pc~odh@_@k*Mj{iZUte4xTT=B&7z>o>>`;9}mq3|* z(KYBv4OuI%?UK20r{T4H_~iO)`bC0R)%{Q7Ke|fA-DwWca&tFQ%gBN?v@9`!)6AOA;8@G|iOoX_{fF zmNw018GLS<%L^~E8MgKEKX|gRq*eiQ&H8im;$0@rXhhOgji6ggK72|nimSpG)!O)w zE$?VMO%c_Cp@noki2z?w?IsqkmDeG0H{iDAtp5+y-&~UdQscodxkQ4--P_(folaq^ z-Qmwb`hQv_dTw@IJO65DQA6X;<@XXP9Y6IZ)K4K=)!^ELKh(eA59|zBXKa=~d>r>B zj%76*zy+%i7{?t!Vx`l>vUzmUYPiyoRY4ZC;-Ih*x$E%ftGR^9D<|LI9{4@4pTVy? zkPI5N-+o=mm1!rWL60TNE)i3p1$wD3MZJ)<*Ph^vA+RIm9HEo-2k#qI!gZak6j#a6 zI~i=4j>IjrykAy)4^v#n^j@QlY5T4B+ymM=atu;(^Sv@^wu&lH-&2$Ss^FB1pTl+K z|8sQj;Y|PUAHa9AF|*D2xH*<%%=ygbkVA6Hsgg!=N*XCbeKvDGlaNz$$hkr)r({MB z$)OZUH4;LaLpfFZ?fbj-|E_DhcI|q-@7Mi&JTYrQHvPYds9t8jWatDQ=D3({2e4GM zrND;0D+MV-L&9nVxaky=|5&TFn5$-n|BMCy-LrQjjOK?=5EuB}$-Gu+OfwIeD$Zyx z5rc5IuwDe-8R9%gA$0q)CLRhF0OA!wTQV;8_VFpCQzV@=GXjVah36bVsG}`#KbZ@{ zAv|`Z(dkpxofCbD!`^#t{m)l|9 z0qBjPL0xB=;TX;Yx_wsIqyU(ZY#TZhk(VP;zujj?SEk&hi%lk&+d z?;mNHre3=e@{@QfyV+7=b0*o0MajOl*Ko7hYp~L5{-6`Tod*r$A~{L@ zK*jwNK%M5jvTL-j7;`NcMd&wjx4BAcrO45&eY03t4J?inDJ;u z7JSxHWQ?kEC3fv&gEE0fgJmHbP?3H$9)x!4o$u=AE))u~lwJc^!XY0egnHxEi&(X} ztCNW9^>ntx&(p{MeaWf$7{vH&W@cX0WSA#*3ONxTg6JS-bO5u+75Y^ukR7Ij~d`Bul>o=&5 zG)1+o#uJEG39y}OpouJlYRn4fLlg_ZBxuLYW@F9Gl;M&}&5nFqy;;#Z@>~aHuS}Z= z@zff!(C9W70%;gTC^x7D&kP78`$ZEk&=buX-|O9e+d;Q8BD|(SBLMCw0~upPi3mRI;(# z_(Z{(d1T0nrGx@^ve`>bExRRo@ox|MjJ9(55dQ|`0^YkJoWrwYX%=RDlTbBA&jvw<>Xcyr1ed(F(?Gir=MS99dZ~Re7>{#v zyl_yjXm?&zlWN#zdf^by<6H5lI3o2}sh`M`Jagf| z?^!p=c%8=C*!MBn{V}8cI-3- zbC3e1UlmEox0Gj&e&vFC;xgjeScaSDZ1iV8^Mw^rk5TCcpVq>57uz0xwQyz}P0&m~ z4fx87$7=zu-cC?RsFHq7OnkBl$bRc4DXja9c%y@MwVcgZz6do6^&k{Rs@@p$GV$#T zo!Y7WPk3T{BH4K5EV}WFF_H|t7A#t=@wq|Lrye{dAq#$OY2pValAbSQokv>f*UpUo<+7jWJ6oJIpxufge1Z zI)0U7p1q4oVEo3fXDO*r6AoeMR_q`|NTG{x zjH|o#gkxAYEiX%4lO4wBtM*uh0In~*%!0RvhzgRDaYc>T`y-=eg!Bq1sqGHn=7Sg8x%>*c$&#jFPAQ`>nktsonCtIS+&PUEudVd zPQ+jZC`P8JwNXvcIg{apl-CTM#VTFWuw;EvY$O$9uy}f(p}#JoQ@m*R`5g91ysQ_6 zufJFN*Qj1zUUVe&#APs&Nml4)n9op;&T&Ed#tkM1DpHN53U2)vH=$JqDUGODV608p3^Or>P$^=la=dZ-pmDRMv5c)5k#T%pZrkC= znFu@JYseYqoQ;8r8#|@iIH%J3{=03Axp{#69QVDB zFE@ymF0(}MVd}wvyJ@o}#%pk%z%XtbdPX^_7Akb6pW%V*EAYjw0|WC?j4 z7WG{|!fi>n)Qe+U+Ja4J!_UgVdQ+DE@lfP?09VD5u?`r{vlQuCd&(UsA{AgvaB)(q zu`2?~0Q&yZgkT{ctQ&AF92lJzXt_v`sm`*Sq8qK!kY&ngP-JeXljFq|Lfq536;`7#n4gCm#%&tG&&5e`4~l1bQ?m`{nzL>-_gq5Qrj& zMomGxYmlsw#p@&eds51MMXm^R@O_?>0xJl~_Y1jOR{4I)FIrX#M-!1-r zw=%f6;d^mwa7pL)lD=RLy;1rmxNP=&*+Ovn>i6=k;Cl!4P8_}G&$kj=B%-bO3IHfs z6BGeirTOqR(0ePF?D%@gkzo#%$5%-@tM_Ix$OH>*1jD^Q$gii)ML|i7!&-XB^YRNz zVjG+jSrM2b=Xxss)k#zq(Temb3a`sRFw)$jAG+CNw zF!r3&p+~8bwxRB!^WPRJ(6lCPh()6&ZAgy_1*N%hxKN!Yxwu9*7C_kqtg%CLWsN~+ z3%9fyfNv+1oHAAl&er6_zlRK&!1t|3myOh)l9%D zc=oZFgFdJhh<`ieN zqZZZzy}ij=)`+IQN+vaSouQJi5V}78u-(RN@yjWb)Y7~TEEe~`iM96d zPwGdBM2lhW#iZlH)x1YZz&-#F%d*hMgLMoTIHkUMO=~`cgOV*Me}SMB?Yb}E&?m=* ztRpDl1+``@x+B+jYP|JBZ4eoj=B41RCB(p)sn-PSxzCKb2_5$2qAX_5*Z$Rr6#8XJwce+h>u10E5<{my>`+1d^)RPB`||>l3n6pH)VBQFaV~T< z$j}S?U4jdVI}FbgQin;5Tiv)L!AqMKL8Cz!KPAI>`D^@KBbv)7n^vcx)yCH zlu~m^@0%Q`rlsNDWtwIRRGwW3GN;eTK+$r*Qs2MDsTZJ$a|`Q(R(<>FjNmcje6tpb zAZ?PTPWt^gaga8$c}T?E&1s7S0f(ITw)uK6q z*tkbdq1yI{JaL^j#*1KqT`RE!x^N_@X5ZgAVcW?{?Ziy832NX`L4xp4un6jk6D!p( z!;*`tZ6TB49X9lFfA3>xL+0-cL3D~BaTV^b zQebi^1fgOhmSnUDHjGm%XqF8?uQf~oydD8~{$!tR3{tcW2w*ArfRqG~q*lv^tO zL`y4@GA1LQgtW^Vu7mY*0B67s_O{BykdS~~D@4BUSqF!Tm%Sn}_2ah6*&eG)(bw(# ze_dP|g%i~fIlVHr$w$1e-`}$G*hQnH)(TW|P0Ox24_YC-KpH*TPPRzT?YjKyp#?ia z)00mU(8|x#*5cJ-N(5gfEHx{oT|a(%++UU!siW6FjJX?Uebozv3a4ewFzi-#cFF zHTFEc@~Bssr1kWezGJ6~>mgq=87NjrZOdtOtBR;P_XMg8(!x{qNDN&y%a2QSr_TeE zJ-~V_UWH)z>92I$jD_$b0ViWwEE#qfWTEB2;M^bUDuCtH67uRdVspy66bOn4OB@TN z0Rih>v2vjGX*pZAM+@K@6OIgnp5rU92(YGu1#Nv;m-dO6BXF2+C2aCmMuDzUy?+O0 z&z}RjJ1A-hh{4VDQS2XTAgD)iY;IISA8s!m&)|>yPBmB`y$a~mV8v@R#q>_(97BMy zN*3DQ3_S<1npIPXvxSx|RWFpPtHw}JIQD3}PrG?QXT}1DuvGk093%tQ4YkxWVc=#c zS=#Z2RoXN^Py}ifPg>C>QT1#YxCvlqgO^z^gE1SVh-UnNFiI|1YV9PBGg(>+vF%Oq zcRHU+BplOoW@yy`_cpc1Ht~vTR2?D**=8JrWi0+SqLqLi79{uhTi($Jw^v1B*9Bc_ zAm~U&)f81{CGqAqPjQn4ydQ#O(gSrFF1rc7O5SH64A9lKaS{a|&M331R1k=?t3G2! zwm&8U^ty~}N1IN%8iFB{p!WO}^%#jDx(N`SiPt7F^qeiVZ2R>2-SaKMdU&cv5#h(uQ*aQ^-io1awE#SZ%%s+l*&$J%ORiLvoMJ#=hv-8s};hM`NdGXo@;hiU#3)?_%c zIs2X4tDm|GHOl3%Z1Q68v+T06R9z+d$HFm(-2de5Ugli}QT_d2iczM=5j0`_a0$^kZ$<9cbYG+y|gV>+#x{z0mt&;$K}% zV%ft1-PhP6DdkanLoRR7j$aIO6>gI?<4#f~NHag5gX~n~GOlhZ2i9#n2M>vKF{`S| z;=1XC7O{SMAm&$3^8{_-x0rgfOL7-tOifKN}$p&>-geET=BseeM93M5HysFr@3xlR0~}E$J|mnfYcU)(^jg zjeA&6=W+WlkuDnhFZ}7u`EP&kD9Fq?!=$e)aMo-&qunGKEY_tKbA6#=8FM{fcg?MS zogP>sQ6LGscf*3vc9bKu-08JCbvn81+FZS2<;PH0e{516*RoX7I?rv~wT-*ArQQSc zzsihy81%dTpN5|jug`TPHReWpWtK;@&L1y}*&06D@@&d)?E`bMlJ~2XXMHW!`Pqk~ znA#Wh68dM?TWksf#Y^_fulMuRVrrk)Q|ct*>qD>+?fkIv&vm)ZU*l}mmnGS6+rv&) zOGLXUVV@7@D%M=4UpTVTF+%s!POHB!RNAxF((iwv(Rrd&mAg8u^wMaGELTwb<8U35 zlt#@Yu|8J7(yNIKRGEKX9S|BGx7KccedELN+wM3QDvUll*NVB>R1f6lbnE)}1P^h* zwAfX`x6^#j*=v#!p9$Zk)UDEfmgan@SS}a3Bxhe%^bZ~=6}>uHE8beQCFoqMk|Oz; zt{ZDoBeh97lc04QLIMn6n9P@k5dvkYk&WcvK{f`=B&k?`Wo?taB<3uCL(M!mJlb_0 zetO12v}YS$ zIjUT$#5yg>@z2odKlObE%}+8^gW$qkQw8Trb4vbWf+g9_wx=C*HM%q8rB{_)yO-V# zPtK+L|5|w|zeR&-N8X1=)`78aaYL^Pt?`f?QBME`IUOk+58D&d#V~fe=r93p2h%=hKOwimFSkY zAb*~|ZFo_lrk{4ii~Kp&}OL6OZuQ zxVQU4J5S1CH19$Jw(Mc%A?~+S8@|9SK?#oCU$F~A8B-A{*%)LJ+50S1jO+|K%d(f$ zp;yGbp{GbRG2yR?BKlGYCNRW8_U2fQ7 z-UaKeEA(p*rsayJ9v08@X8^!1x2!RdYIWQ@MrbsVmeLG~P)Lx?G9Uqj1%fUplsS6} zSOwXfBv$#=Fz35TxYTH-yo5YhgU)$IcIjibLzcl(RYs(fuu>_iPl=UB-C#F`W%V> z<+^(X@8u3ovZ`Nx3jN;d+6d+b32WVH@ot*`23O6BFhtUFzQb`kdFS8t3h~WzwLC2sS^oy^ z6Ov_`*W|`W9vKl~Pk5wJjc(iEj#3W5Ra2wlU}76k;u-l>vJk%*|s3W5Z0ru@I!l)EJfUc zk`e4(C9ym~EGvr(WM^89?}v`LbUn>Kl+LR3DBU(zYw#PpTpU6Cog1QQUFj*V${IThb zI*UDfhm6+^Z!A!K6wf?s*)hWYtpDs-n)#HBIFT-Jlpql5EA`THq4UQ_KjO0`S+pN> z?&Z=kKc;yfh-n5!<^fRu*aIYjeym?CFv00=$ zn?w}H2J3&OOVMP}69eme5OU;k`rHORI)TiReYFvGp%|`oY(f9K)q%WaDw3D`=B)99*<&e9pIm=_m0|0p$;u+Pc8b_y+%1^)yfR=o^as zIFQv`p*D}!l0T)Tcw5Ui=#~T1fUH}7*czaQ>p-dzL+Ta3 z^d3-3W-|=$sQqhb-JnUZlfW5ED}MGB!(DL7Qc!E1NB+zbn$NOX2RwG&G&vqGybFOv z)X8=d){J=mb`Od)2#N~+9N3YSP|3zAqD-hb@qm|DuX#;&?v;d@`O1E)o#N3T=i@fj zE$}-2Nsg@8E{kzoS7g%d@>eCl%I>aOqaG%l=?6;nRNQ*wQeIbs*-RBpr@=!BQd-$s zBOs*{79tVxqCR1oe>SBg{52t4ha6D?M>)NKgc%ViaTV7izYc{}$!WB5bL?CA3iixZ zt$zv%+5rkTG>slnG&kuwkLKSwKa$!4Vitmd!LH<&)}$05SFs}3zo19{TMp{YM?Qg} zBd73#j|Z3R!8ln-b(cp%X#LsySb;aDI#$xXTli6;+A9Irm{zOv_;x4dSQq`+C5tYt z?PE&<1Egl?dfrhFqC|e)UP$k?*?BcTfE7$zo9%cEap{t{pPcd;ZPivFx9Zzd=E824 z?rwH+oeNhUxn(%5XJU!6T_$0eHs@s$k&Adjz@IKTwv6=$o}=|+7w5$}Hf6l7*Ts4M z@}00bAR02D=W?HWCWvdaS0J7s)dt6css;qII=4~;GM9cVjQK2qCE7MjYzaSgLY)#e zL%WrPo!yBTxtu)x?2G}XE zuiTP(3daIPI)R=yffxFyp2ZcXcoTq^TA|**E~4PKM=5sF@0D);ASUKH2n7bHFR3@# z;F)05oGc=^NvSs2tbu+^UHSIQ_o}ffYVUf(D9Q%wI>)vnoem>);5%;Hn?h9-XFlOG z<-n{+sJc%Mh6TX=0%EM%qE&QVhVI*uuLWNutRHv3=2>{{tp3t(2s8y~)No1rB89V{ z|DpO=g=4+B7=_UyOUSVsn0T9Cd0JbmY#fwmlRlg74h|%S#& zP^eF{)$rmat~w}aTWTVnk%U&@?w`Wa1&q+6bGI))7Why(k7ZIm?lBMt(*k1ia3}+z z<7jn3#wHr*vbxjHE~gVe>0tIIRU?06Y4hJ!BVk8g-4XG`#OPcP)VGk2im1prT3Y2f z|5OS7(AI;Pz^qq|AMhqyO10b<Jo(sMra6c*WO?+PdRDQV;y8`OKMfym85Y4Rn;Avs}4RN>a4aXLL(&nsx{t~Cci-!pmnN_ z?P*LA52Ep4SD;~ed&G~RmRn+0)aVrc{_TnRD2FyDfugIE4`rWH)}v*(?EA6y56tfD z!2j?M<>7vDNRG+r{uxR8`*^+Po*BBkf&&A!_EQx<)m(6El;#l2T{PN$b6ks># zm73)j%M;6rXcqoeQy^C#0OMuNTLKnoU(x{GHxwDb%*j9_(jlw1f2$uz2<$!ZpJ154 zVYa;yn1~~{k~2ZR=R+y~DvNKK8BXr$`9V%2t=mIa5(5)0p zb4@7j_SMr4AtQz6B(fxpDun~0p@acZ3kF<{r;i{zAy`2Ji?qF!G0~6;n;amDO8E6* z6=uu4Nc2ed(Y{d%P%uuS3Vy-->tGe@YzB>4K)0OKoY>t~n z5C9N#=9i_ssW_i2*alxTph7U=5hsWX>jWCLQ}}m?Xp@K1GxFnzSe+HX;~AicoRqku znk4#uYIk5YpMPe$gKTHThsSf`i$LifO6yu1+2=@GM`X4(n7g|I)68*@r$t8S!M*ew z)swfv5usN~} zW4h(4ugBim?}g>xPe+|1pPVTW-e2WD0_u_7vla~MLrV|EF3``D=R6&ph_vySRH>t9Mm`ZS2lL`}CMrz?>Gq>o$52UuD)S-VozoPV z&V1W0dR}nc7;e|pwO8V|>^VN}BMSt9CYa(@#puNt%%1Nef4>wt-v2W&!s{IF%uo9i zRjlh#2S~tqKMM+C96LwQ@c@YL&4)JsINX(uVxMA)cbo4r&Tn-b{#*uPM|<@9=HK}d zFRjlz{;KEPxdiOWVgbIK8b2B4r!G$o>~qR5|AD>TM@f(4es8?KE$Z^w^qOzlABL|T z(=>*qv~VFA#?82m2#@^e`4BpyVAn}d+f(=HkEtf%5)9SP8{s5e;HGyiBwj>acc_We z883f+Ih_Ns((uy!UjW9dX-$SC>LG&g)_A{tei2P1gH8~QbOyqexE!W-kQYjxV6~*J_zbn+1<7G{>~pyh(pKNw%l|{ zA?l;ASU+rpYSVr;cltadUD~Oqdw+Z7ZR7dzp67?Vtgo-`Ilbuld$?W(XnCuC{+XB~ z#6Za5b(8!%lg;j{NHw3o3^112eqkb#)g*`@vkicPT5G-9nfR2a$;w`j%J+D=7c ztsyIwWCLfvEVo~{9i&lNd%iDXhOT5Rc(%Hmh%h9Y67a)ghqZWUY)DPpk}q4Gx;Bj;C87#fgYlZSrFJ63Ag^{*ZhyN{cTEmLRdvU*#1! z4al|PYi|FF)GyMEvNqUgew*ruXRmA`%|6idrr@tRll7X?*0*Cu;hSh~(*_@2a+Eu$8K|V$U9=59HBGx_nWTS&? zoIu%56Sv0<9%}YmKK~iV{l*Y~>%PDVqw>fSeSr}bHRB;@$eR%siYoc-+9-|LOVv z*oijF!<@z-uz_px;kXv&R(qpC#?%rG%be0VXWT!!GFtDB{-@yfsm?{~R%z76{xU6D z{a~fKFf1m{vHOIx690d9AV_Z|3%E+fN=vRYe&^k=N^|vA3RNkXyGx;SZ=X)7iiTgvzt$fWPwH=OYG|+!KIM(IDuIl$fuW z)X?5rfKs(H&zgz^fkJ$`;3$k;d3e#*O3+d;js0(s zj@0@oEeNp$x>(@Z`G5-U=$!IRp>VDNp8L=+e4-k0lE*X-cO;;`QH7O5S_-piiRjC;%!`O}hIgd;*~-oBf2T zOgf}PMyM=~U!-xbjCZ*;uV7|LuWRj-LNBvV*h^mer>%U9-b(X~?qqZx0E|5IG6x-z zYjWEEf@C@|$tDscNM?f2OVI*0_7O@Z0I)I#M)l?Fohq8}Acgp|vX zbwHTm)kS{mXaNBHNFGuA?qw>NyIm+g8^1164K5Fz~R7?oc7w6MSoci?9Lg@r zq)S~OW!~)n${%3baAzs?Rd$H52}w8Iefq;#6x6*f@LPl5nxRa`d%S$T?g`IJ=y#C^ zzn}H;JtQTc@cuoKDzz#DRZD+WE-~YW`8H&EB|A9D(e?t)TrS{dG%52M>1*?-sU82i zGx8eCuVenAI;w8|6L(D%IYta>xJu!S7oM4zI75uy_`-kmOh*RNUmCS;&W2<4J9hs* ziWePaLXG$6%MPHwG8yH+-({MZ3<(Wxiog{-XI>?nv?v8DE(P%(2nJMgGA%Im2wjEW`ZrXk{7qQ zAaQqy|KAw(20pcBT}7&b=^vAyadF(`bi1ee)?wo(o|xnd!CFp=W8lX`VK z#yj5g!`40;ejK`M@W_-p8+hmEg$br^Nk?#A5TViZUSK+MW^G01zqKFLa$X|*LSynACQ9$+B%jEgkw%)7B z$79!b7)A%>`%jPD3NOnJyt8v3mgzLM{U;@M@!q!K3;8kgny9nicL+CboOW02GZSQG&PEy}JOuGKXpY@>K%cG5#uWvWq#<>3}YQ6dScfI8&-!$%ni3cZt zK2+`A5PxCJk6jO?(qRv!=V-pLxN*@ddp)&(w`puC z;doY=V$nYyH-Pa+!Esmh-oFwNQPJ-|l_!Ya^}GMK>awF>p?a)BT6M>t zoOj-M`*FK`eB##&t;30r?0?IIc#N7aR2oO$sn@@x<$2i-4OW$L9&Xj4=7Drca>`7| zBT<)y<(n&Xuqsm^>nZ5wMNj)&2(B6Ay(I^oAuCsii+Dl&@HcKZUb5ju zveF7AN>9e41*CunDLKcET)6e$H0cm}>zhr2@$^k0gIid|YZ8jLmUpR+bqP)erN>}Vse9Opu z%>dqcG;$IREo1S`lld5h5ML(ZJ(-~43h5{DF(%{;@NhO6K_&9d<2iepeA%wC`UAW( zWVkyT0j%QdZx)sC<(%iQBN0;lWEnb(uDGx8`jV z1KTrwqA&XuB^C}{CUR%}h)()Glo@23RHPXFbLhs)!b}gFEM{RsepFUFH0!Ha4m%|& zGCGG_S;({(+R5S_V8V+h{xf4i&a}roeJ?fdEPlvBN$#^zi$pyJ;k;6~)-E7+tuE%S zt@c|cs&@8>ug}+`qjXXcF}u&7F1%TtGrueHZx&5OTM@adGcTh;4#*(Jk-k z0&sBRn%)hr`YgrNyhKSF$q2vw6ht z(rW)lt(E5R7K!tgG;`UJAvJ+nA4Ig+&ggjn-!uzVF)zSz18;4imPvf?$Vh2l)KT%m zc29_OJ1FYqt*f$p9PVtjmyd-<{bnIQG_#Rhlft@WJ~j(^q~)k-ynr%^&&&_?jfI#Z zBOT|FXSEc)Sz^sws0|u&jl}0emxpX3=b90p+{HiR&o-V$E)$XKy=d|9f`aKnN_64r zm1{BIi~NQXE*Iq`i$}0i3%K?ZDf>60hKq7;+<@B`?Wf#}_?|htmzlPoz&Da4I$Oc3 za#tqidj390gJUtGc{`mEeG@!k9MS?%Y*Cs2jl^kqaQ`N1mL#VM zfPMztc@ms+bs=yP%{N3kp`PdToge%r2epakQNZzmDF}%P=UpZ*&KX=iAvDws0>*>0 zDM-&8@wfXWga&cq1RuXITjjGI(#ZuiONK#qBuwzgJr=U5sw76HWUOB3FN4bfFZBZr z?FlORloEH+py*0R;W(`DR(-|add^M$&Hp|WluFRJI+G4lZmsXpMxR|ROv`>Mo?u%< z^L$pH2~XsfXcQW$kd~-?dJtA?12LsR&J(#?a(G|R?s~BP6EVE>KPa-fWFdlYx?ZqB zRx-Ld9yh@wvf0p?q_RLpS=>Oa(6}|pX>W7*vT^4uW$$0CgesBYkP03plKGyq@atUU zJ~8DHgZt|?LQJb{AAllHkk9$?Y&z!|Rpv*=pgy5bcZ!nkh#{-!Xr&y4G{yBbSgLM(Q8M zJjNL%+_jIcIul`*Ug)UUs(ho-N;TApg{pbhs3ikFg@!4eL2#n%0}?W)rtDvnK~JMB zRq;nxWf~&iNZTA-F_GcH)uitXAT#iw05s|lhv0c%a!5iF0pMzuP+>EO%tY=x3!f9< zJ1jnKVsXD9$CZsMJLpB)3(5%8Aop2(;KQyv(VC2xg@QJXJ!W2bQ^zfmg^9=^Vp zwB*I^HZ*Sh!_y^Xbj$ifoi;t&h+596 zNsHyWBlc9t6I{_NQj7<^!lU+Bs3rjKEfDWN_lL&`NN@ZzE&`7#4fcbEic1IIMmN9C z0a+7~AGa|_{MuJ@+Aqc+57Ef%L$Re^EpQ?@Z^Hg5Q@@ZXIP&E3z1Ws##)<7+w@g*Z zzgDuPB#S_^oqmIl+Y1{cJ1f*xyOZj#{z*yfYHW!Ld|WtFhf~eo8hozW#DLf}o{(xY zKhZEIInXHb+zbuPXTtl4&r4Zcf`(5Vna_s+;4Bz2{8EoZd{048zcPi#MUw}b!bWW4 zigWoA^cQB-0K07~_kQ_YOTG)oD=DXCZdeuBn^6-!%hcsMQuUo~<}g>N;!CRois=+UbZc(eCGG zUnO>QeGzMT`e)c?t{;4@wKuLiOR>#NZD1%a#3mg=Xyz*6Sj^Q@Zsx<|Bi&M6ZM<#ru-3BTKKxwkIor|d(XJ1QHy@pN>?8H+ep5f)q1#lg(<$`T zg28|J#iPf|LY#6S*U|7kXT%E{?_C_1h77nXtqmCT3ZDbBX_ZuWg=FL56dJ!Olkb}x zolR8OqxEzTf>Fn0d}%N;6RL~5T-@^F?{-`u6U^Aj#~3#~M{jDy-ILmk=Wl|IVtEcFFU-eRlIRU?j3~_7&n_n85cH z3mu;gk9=PR+ZMn0=0Npr6sKunon3)WqY*GZ=!QDNbzJ=_a6j@x)1vIx4P-hsllq6}(Z z)^~nZ_=dXK18SsktY{wKALL(L&AF4XZ)oxP=6Lninp>?XaLb+ClV|OR^I?Zxr=KIA zjQ!Y`xll(_xO=(pRQrmeB#92$(wCIusH^3?oTx2MlWZ@6Ip=P z#1o-YImitFYJ-HVWAUv3n0;Z46@G9J4Ox2{Tu4HGV?KyPBUhT?>ikPJXmL?F1#|{t zg@shVhnxhMufQy7I}pQ9`Ki5pawyc#W+bsdacykU;Q9B;n+t#|+d9VURsR+SMnCA9 z%swn_P1x@=e;v&pdwVl#*NCrsptPQXWL^I9D(ojq?fLwG&1TAr05@kYM;7G4zhpt9 zD<-(=G}8NMyr(AG_%@E)QRZ~_yUbkaQXgkcv| z)U%RW1 zWIf^4=J)3mI(hW`nHG?DDAx5HiR2Mf94gSec`#?Ex#Co;b!{vz*iGKCT0FUR-L9?9 zwcfpAsckiX)jb_w74RTfNY$(2d|~mo)PnUhPcMJ!NtE>5@b0|!@e@vfe= z*adgf*r$F$ZbK8JgC!yKg^ES?y7%+g<%YV_u4g|3#x7!_ejiRZ1WerLEb#sizZUZT z!MPVnn6tk_XD^vgj~zy-Sxe3CJb4U;Xg-(KIdx##mY=6B6Cs{cmT`DY9XPp__Ibwot>==9_z8_Z=L{)eVu z)M%42MAW~T0FzF@S@0;jIngunoEZf~A!S^Z+|G(WdUUTrF5hvr9V7?$Oqj3`IiH|; zTs*M4<+!BbM|ib@AGyLZ(`u_lLyDy2*Dsmfbj(Jf(7)AA@m_+Ky>e}JtG()@eytP7 zo-O7zJ?w;NJ7^9nJa*6?S7ZNt)tyH?b#i+q;q6c+vnj|}?_;OnNz>iM$4=&KZzq%X z1-I6x2H&SN$NtMB-PW_B$KQU@#JL<*vjz_6oI0uht?js+9hDb$dPEskA~$rYk$ZKh zPqrvxh;m1YB=RaH+21GeiPV*cM4@MLt%iYj-5;dU-$fJvEgVbI>MCsQZ*U99VngaE zupDxV>}frB-MUj(UU2DqhhI2R$$fImK=|DgKhp7gaZ`5BTsp|kRf6jIzj%^D|8T6- zxDCp3dqxN=>B~*prDdNVK46QoTRrvTDv7@*lS^MUsPyp#zBH`8kp22Y0Q!=Ce1%|e z4bO2`DV7(sG{OiwSnQ~PVLuBfx$@F5uqX{@SsIN{6;i*hoa8z2G{ox&p7MA>Rw%5E z{<1V??(~^ixAK=urLi+EV)`-@leHybM|zU{(l--RlSzNB=}SNR^nO_ihhxa5UR)Rs zl#YyBBxF;zfuOG4dtXRTUi0~&BKm`huT|dtuLs#hN{CD5Np@404w$@S zpq~e`{@em93vH&aoZl|h zU*U-1@D{)q{dq45W3-tWojsVcDn>|=m6XZSB*Uo|hpSS86xk_Rl<#s)dcRD{)3ag@dCrNKIID5hGB&zz zfmtUw2O;VN=Y8*HMHnz-8LA+S{tD;F6o$YuH`angC3bV`#%#8-8hyTkH?NjX& zE+rr%y|gil_?Oyjey~Tk#;sF}{HP&cl-CrwU}MkI5CBBpghWIIcnzAh=7JKY@B-Vt z$;XCl?HWAZHF$nY7Yrf7WBcXBegaC(4uI*5{$7#4tZ5V4LH5l(hSvX4bnnqj|9>37 z&Dds*xr~NwHg}Tdej9D(S_nxh^>rttxzD9+#^!D=m4w`qq(Um)w3%zUOsSAGmn7s; zlCFOH{kfg9ot^ER_h+Bix?i9umzNJl7BMmc-%ArzuD!<2tK5dbdzoozU zi$zDm7{Dj-y_(7dv09FrAoak*MdcTVWt~nZnikF7*`lIOytB;v1#3fH7<#vV`XlL5 zdl1Wd4CS?=(~bD2F5w#nCJVUmoR2`2HFkFsrCK6Upw?VAw zdcs+@i`r4sBER>Y){7RO+P-PCItq`#Ur;6XGtcf#X-O>$cWfS4!cg5a-HhiHM~Io` zt1=b`d*{$EIz%P)?!_(AyPaq6N)%+8b#NsUyg(W9#{h=w2Jn=! zIz=wufpCfi#&&cod~fWtVA7#pUS!N~b1=Mu@-B>4r<{=5XZD01;2JjZs2J;FN%hb1 z@CZ@-9({{&Zv6Pf^xX*0hhHqKVem83fr_769Bmr>+1YGH(E_qpw~AYkJYS~>`m9W- z){_bn<0-q}cT|`_NTrU|p?EZVlc~`oMW;)5n#r4u{0eh`s&*rDx)`~7dyJ^?m0ci=Ru-*i=I0qEeIXbu zW=zc9)lIq&w)UZmipzbI#x|VU#rh_*M>^MDI9(j;SfFcCEk;-eNQI&* zk@%g))~HAnkm7fFKhwVVr#Aq2CQvmsC|(qH+!r3&=r0c2>@VEs$!MzyG;nYhMeEl< zP+nYE-}PoQH%#bw?X{1Ing^;%PUt^nsYONFDivk>ZzE`GDw59WwqG}-tn*-CMp=|X zG%@?88u`7nbGqebjU+#%A9f0ya@d4a=<=xsgcs1KUOo1`3&cCIQi;sno{R+IgQt^^ zJFT+b8M0C+;DgnV{$`Fo_#2$!!#dL15^P05M*;cJV0Kd6T&h1ub#GO_@t8m(mOSoC_9 z1CT}Dw6Y(Bpg3Z25aW#;u+HQ3!WKK1F{5L%iihHeopScr7Dh~1`+4bsM~_+2KD9n} z1EpRAnljv^#f*}S97HogArgx1*#BRBMypKk9jwEvcib_uL&6D%lrV=|T@3$4W_%Vn zbz2yqVs?hnwJ%Nr38_tXVg+NFeh?;o+_rR&BL~7uO_nem1SQz<)MR${^@w`u5{nG9!qr&%Z83b>!vPHKkz1fucaGfXw_1 zVupw)o|YNx!we#VD5}q&9v>JH8{(I;FQz&-?qm)4);pU_6h(A^labsQLHeuTvb#Pz zqhU3HF1l4_yv z!}@7-FwyRXNd@>Ig>3F?Z&6RS3W5;^S$dPaM|Z`QYJrv%pou#WPb>WW+tT}YrTn5R zszcP82y$&^dHGcP@)+vX%@j@sNsvjcW*uR>c;s=AK6H7$h^Nnim==f8F}^ThXbbDQ zltsu*$%qA(-^l`a(VEVNfl@kHp+u+TN2FXDJ)j#l_JUPiN;v4}FaSt*qcHu-`qjtH z0{qlH@mcThf*!r>El|^q3zNID6KVSSNmhHL4X66Rr0k22T(>WFSqZ5(SMGuX@Z`0_ ztWqC(M8_ymT7R=npW(CrIT9qhT@hqqqu+Rl1Is3bF@rkpsf&opvTvqPnD5lw5iK@+ zC9Fe^OFpE>yZHr4P?w19l)5%{;NF<}sP3-Vf&QiJ+^`C&P+OILC~>BZ?GB8uCdypq zP#48Up7gx$s8Qn6&Of#e2bfn6x}r4>3^>zIFS3$oYDhoyu`t(Tvt9C3&^fBm(5rj5 zoP*qEu02klF13En9`<=n^RFi2sW_?U5|P)?2_m9MAME>4h~XIXOX{A=E4O1r7}Iuu z6;butIb3}SPvRU%VdtEsb$?e(*_$F|5S0c7yw0+FawsQ@?p0l8?g~I+=_HZYA=t6) z9C~iCKGhu@9R~KK4LG=>P59->*jooRCW=iahWowlB@a}tdl9It8`+=$B2ze`B6@=! z+20&Yt#K1M@-TYrBMB5<1`2a${jg9JQb+b&*P5{-FRb(&JXyg=rhgbHp@o&GeJ|IC z-tf&hXx-?P;6mEAerh%AEc;j#6%|c@U?9wJCh-iTH@h~ilB0G6H zjQOzj)?U}Q`qnROfmdVsgQ0$$RBVMeP*@iPQ;47-0m$W5ySg;Xjd8=D3QElC^SryC zaOej2;q6zEZqCb~XrJd7!SSc2I zY1OQtX28M4OSn=!OKkTO(yi1+W)X?x+;7W$4o;(0J~Ga{c~kE^jTOJhqTuhyo3qxw zu+pefMJwR*Wn)V2U~wtEROElDer=q1aGC&=00XD_HDn|8tDj#vzp*z4k47yL=9Vs< z4`Wdmg(zd85+?%)L~-Z^tB+nW&{gU_ZmH|LQ^S;FsG8iy|C@fY{6h#L9kJtd@r!s* z%sT6-#ZjXy@6>hBlJfN4g<1Uu39NetT5Z@rPXbF}L~er<{8({Fmf_vo!RyQ@k&(JC zW)z3n$VAW0p_iGV0(lfR^K3uUGOP{uk`c8CI)FFAh-5@yS@Fl`C_YSGzr2ea zz+vG-KUTasIMONm-p6YfJ;4;b_zCt@6c=E=I_GUV{~;QLjtCZFhmoAQ>4)jz+svVt z+Ckf(P=TaF2Q#LnA@3xUmBUdbehk+QK1gAnjKYTTKmj4(cqBNWWgb1e|5*f+(%2BJ z3J$LZMsVo|-3_Dp&*P#Fwa?Il-ABirnTcU6;V{|0`=3&F7G|gI+(z81(^`Noo39!U z&=It1RsJC){^%_logT8tyuCkn+124;mMU`5Q&OV;Fk}1(BaOIt^qP?sQ8kqU%EPm?58q1}oC}+k;i`l)LC2$H~tjum4(PE$B4kT!EuJ(Lt)r>e$iOLfZ#a460 zJa$*FziL0VtaMo7-o=s_=ZILz@*n-Vs!kEwHb* zGc{=H-@R*p-mLvySo^oNwgXxh`A@pjW|d=;uXkpp1A`gt&3!*yu)c8Wp2FFrA}E9< zv;WrFS6B+*6J;m_^L-U%3W``+*WvWGpgM??b89>MoZg5Ty0;Btk1uiaXwpjtV5 zBT6om9e#A4@^UeH%(-CtJmP_0v{6>RE;3qvCrySkyl($+S?bbPeSbN95r(edw20Wo zeV_bZkA`?pR>C$x?oxDqvRH(!>)sfUNhkAmr~NyAM4^7{jVwT97%Qr=6zI5Kp9SfR zDvb`_&{#Wdkp`83#{I15#{T?b=(((Q{j*;fE2hKbE#D&eILn#81m*(pL^ZQ&2@?uX z{l8rWly5p_-$AYQXR-3p>!5HSkau(FBlluP`OUB?aH#uA6LRg*lZ-*to5v?W4ZHUypMzd;tq5hHfGAdi4>%?a1czFKKhcR!nhE0x z%T>&yQi=E2SwZU>LH%(z&705ryz$uqOCGg4b@U7yiOh(luy)#hTyD!upt4E=avcSk zILq&uXQfe#Vj>CyoE%mZhe3T7ea}f0zb-x)$xIjrXKTd9ANwHLefmSc@Z5S5&=>u_ z;9I;|!d0KGbJ{GzNR9^Li-->*emVY4-X$@;xT z*#;=F!uplmhgh*4!H<~=Y6B&8SF>{aW3v|`3bV5F+3tvr^tf$mf61j738FY0w?98M zI6C`5h{8ea&zYZSS0`rB4wn6KqD{5sKg@^9vi@%u3pu7Wsg6SrJ1>>gX|1bg{k;6+ z_lKmf_NXTkl+kmPe`j$tmCm%i@HbEKzLNic(u%oC>&TWOGiKBJdE zAnkxGb?1M7<+RyYF2kM%`}3d$*Og`>(#ku!b}V02My|(|8Ef>s?s+TxyY8Fj z;|~;iMs=#J1C+ceJ4L0dfp?W;BGe6x7CkU{Ynf9Izm8;=s2^z(4E-L_KUozbYF&F+ z%(1(3XRPtv+sK}iPaq{@jk69#wU$RIf9xP)233wZV_saDF|FMM`d~LZ=+1N#vSe8_ zTZX}!&A(R3_cw;XKIJ#OH;m!M?i=WQXg1jstF}3 zpP8>nW-C1=n(Cgt`uO<;_0{jEZrDnLn-hMl-ck#_a}vEQs)%q$> z8-lLh+pTyCFBW^qx-!h~3h2o=8NSEB$vl8`)XQk({CqQ`&`i}L6NyY-1b`$47GD)$ z2-xmp$g==Z(9WTK+@r^3eUYa>{FfkUEbSNP3c6}%&|)u}>MW3+Q%msqj0irm*$Y8m ziQfv6_dewxRFd`=n4z5HHCm!*w6u5({aHXBF+5ycf5~FIMGotAgd;L!vshNMyI95p z4DzSbS~Z-%*Cf;*zHqW3OOc2u3L&K={n9yFlVhoS<63#LZqtpXN4huFlf=CZ4ctA% zV98z?|F0L>x>>C~nH#p8nupk7J~fkF9OBq@Zbo>7N1yq!@y$MqMUJ8Coo5As5>W_C z53#@kd+p0|QYYyymJ|2u3XF)VVo@f`9di*@pQY6VC(ZGqQdUpz%N6Y1leVGnz7|A)AM;U{Y?Mv@01J$#8fVt>DUz?GO`A_y+X(_`OzYke0`_6#|)V7WUnJopWx&LPpS6pCO zQOVJuw{dvVS(jR`&}5!FQd*F zo@_tly6j82>t=dZ*Hg;!^}@gYipraAM4DHK8+KTjG+imQr)JBh4E%`>nY@^-5A#J(L_rgaeZ z&Jj%l4tlt;OTMioQ$J|r=8DW7U4e%91czk>YOPZ07uGsBeGywF@c8i>P?V43{;r}7 zWJ@h3bgrv+skJb;S|D@h21NSDoEA|B?33LqyF|g+N{(RQaD5dw-(%f!A8OD2}b_U7G`d1 zoy55xomNx%j3%_F=3NV0A2}TLkSCNxs_}+ z63w0Ee4mG*N2-%*9wLx>j0;GmFq`t|1L@r&iobnWRsfv?)AAQoHg+g;+V5oGS3Ak@ zPB9x(`grppNh=#*C4*;eJWpC`*OEj zoSZxw0R5xd(ae$yIaOVU`I+S)DICT**9e4Z`+%6!bTFb?lw8@UYQ5+WkA>CAan1X* z&*1txsUE)m-E?)1Xkn;Jy6jNnX=|sNi|VwRf-kflEMhb-af*RL=h5evS_^{W(&cBi zrByZpa>LAdicoP!+`xtO2%jL#1kGN%9so~iCQI)9>9}K#M@Svk?o#-~VOwdxZT|@C zN8L&4GjcD2Ms4F!Fp|daC4&Ml?R5Eh?3CGYPch5(IhDptd##J3vnMfPkoO#Ly2nP= zf!pa-A4^>%ojeND)B{1`v1F^S8A%tUvutWlGO+vNM?3D{M3RXDnMW zM>Rt;ic!In^@Ti$n7y#vzJ9aI=J$=#^dca6UXZCt+$v}MV`Ts80Gn$XKwL6-7rK$U z(km@e!V)HCZ5?FVh9g!j086y7JrRpCIS7$}rhZxsrhFqWBrfo5Iqh@#lDoTuni}H1 zxq;2s_R_X5YM6dxH#WUSC4mq4&j8zN9l4VLj|&1SkKxzvOdzGa+b?q31k61w0C2TI zO{F|AQ!j{~qZ$(G8D7B1gM z+zmt(F*AeWXCKB-@t&1a#SFL2e7nC2WcXBvbIUIZo=&I=%AcC|8r|N=k3}7+ydXaf z3Wc8#>J@oq^=6R_20~C%u)v|0Zj4Hqj1iT0Xkcqix~TF!HR(On3=XtH6vgJqmNYYS z%arx;2O37=?)KrGXh2joP5vA84D?MsEAC04;tq`qHRj}}w#<1rcXTm6a3MGPM8I>~ zj;R*AfGsJq&s=x<&eP2$cVs!$AoUI$!L$!(-7$yx*dYq@v++o=^C?NYiDyRE(8on< zP}}ZcJMNL9SO|2%58r1!$t^B`B`NEKSxGqIreflTVSC*ikywVP{U5`&qME!jF=v&h zN^e50$sa#eAq|9cqZ`|9;7t1zimI>iB%TxkFw;ea;p|s0KF-qBpU?E3*Xg+3qj%K6 zYBw++rartyhQQ;lrdV&#wtkp{cYC+QSdEpAm|%OY-WWhSONf#}^Vpc^;G#3B-AdMK z77<;7e16SPUzxJz@T|vemtHdnVVB6=BCs%#hS$6s_8BhnUPm+_P-#pq2eEqN!sat9=KkpQz@`!mU!0-BYPpo8y;f0S$nff`{%-P8;pK7G@g2c?coH#0Vi zibyzyD1d98bwp;7u9`vbP_&Oc%`sWwS*UZRxbTJx(_JQF(t~JNH<2|c9JL}Z$Dvd;YgP4C)l6smM)`W5UBy7P zd)+JkHgn8iqmG%P&-~Nn>VbqfvW+@Wg36m%7m*S{+Yrg;<+JUB8GjpxUgp0j2x5!} zdAeLCp}E6E3LTAfKrWK7<6OxLmBhHW`>Es%X)%~I!}<@oFe#Tvku?F&0($)tgk1%Xn7<36KF-wMWEzua6C8gtS zGw;hYw?ldubcXrw>c|0-45)D~cYb#)vUhw<}_oeV)#*Qwr) zDXMTFV_E<-fK*?YLSDU>i4Hn|7U_y_#+d}Y7tx<2)Qfs2gRtzQ_zadcg=ZZ^w#uxc zM|bN!aR9%}-i+qC&(O3og>h!$9&YujaSrlhBs9nI|6-^*%wpy5APsNJ885cFB@$sv(4Co+Yg8xCWn=A!;pj_o|6#AvLW1_Wx`p6=(M}Lvft0 zv`$kNu@xpa&Big5lM6auGxk*z6_heFeKIuqWuzk&ZOVWFXY62XTmQZFM@@vE;d-2# zR($buwb^|2V${EJGGTFy=EN8mvxUubX+K4gPZ*YZWSd9^s0^rlAI*Qy!{@!2I96&} z@!`SX?E4uSm2!$)cEl$i7y#hP>+#y!$yPK^YouD@Js(W^f0Djk5#3B=eo(hrsZ?U z*i9)|29F98lkyYw2@)#k>U~IswRh=o{6@XwK4CI&xeEC>ia8If>VKN7COwx0z0S0 zK&jVIJzl<(4@|qu6nQZH5fFFkTBvq8Kef!6bIisU2rXN{3uBnWXiAsKmm4)s)J}o} z-WPOeot*AdCtfJAQ84fDmt7axmqoVReDQ?OgT1Nt|CO$+uwc{3Q08#d2=Z>sgT}B* zlNJwCk#yw_E;f=8v6uX&C!F67#1K_>?9s==Z!cK1FF1A6Fn++goI=7BFltuW()U!% z^ay^QoVWzLw*ZWB>%*!m%3N@dU%1)1y64%}azSb)j6S7zI(^TCC}>uJkSA}oHD)E` zB{BeS)ft-O3^U&@0<1)M5bVncO9hel#L&;phQ`v1YBR`YlCOznkrpBY#Fj%geLuK9`AXR6FG|XEXl(q;&WBp*p&-Ajn*7dIKEz-UEg4w5|n~dyMBS@yz>Q z<-QC&L%m{6)3!1l^?pOF@mA7zuw&PHY76sEzA$X+zbIKCqy^&AVz#6q#?fwr4Tnp*A9mabz@*PSp_+NwP>Ic{U;o*4p2|>aCPEiUm9NRVjhUCe zNK`$aps_zr4ezxUX?pzB;RCk&?N`Mu`6%oc*D%{~?N#AMD&;kKI`l?%FPGK)wcvd?7bp*WyEp~ z*(MIyscUcKt>iCy#%Sm!*f!EMpv(Q|O|e6G@uMvvC$FztsC_`K0Fyt^HcPFDub^S% z{k~+w?bZF8FLV)zovemh%FnJoW@JF#%Ef8cKFI1#Al$6|%qd^4MqD~(Em~{-qrD{nM(rnr*}{B}t><^+E~p9TVFf)7o$NQJ`T!;f3b`N5pWPXBOiI3u`>Gfv_p%na%@YS9k~^Lu!3FB`#x+1X{QMMRT9W{VQLfU%C&Fjwf%f*cyD{W6F-ypYE3FV zpLF{3Dm`7xBZTV@1`U$8hl9>jma`0D{8-=6ahk!2l4#y7S<`iM5?jR7tK7fZm`V9~t^;6&oFgXE$= zWri*DzBNfseq^MPGX|1)X4~)h7wvw2)H#e0o>@Te-X?Q);_~LhoqG?RY8Bp4KD0#x zuLTX0EvFbdY}#Bg(7KsnpR#4ZD^yWfGyK4c*UEgoBB_@phCKf8yR5wVr3W!lcO38a zVy=m9H$B*H8?oqkQI2QYAZHsWuJ~(T_SZTIA?HCC(N+e}WPYDx9Bw7)!iBOG3lvgn zoV#OB?R4$v`I5DlMs8K(m5CWDe{Uet_9PjszvYTri~J@FGMtSW&lx;j#QFq@JfbpE zMFW^L{xS3G%I2BBGJE>!jyo({9Et#7;&_e}-g~FgkTq{;GfmIswRvNv%Ld$?9IRuU;ZQ8+L^?^?B$7C+(wG^3Fi0wc{045zCMnP!iTe5Z-M`}{k z2OlP@K2D%ULfJ&D-tl1vheIy!!|urGCVa0rXfS#_+5rzDUF(vK=DNJ$UAZsueR(1ezcqn_>^G|KnTd#=5Cn zeNxS|YvrZ+*g{u!bP4jr_E)?)6{*;t{J&(nXr5WhcH^~eGnuT)_+J-amvux36svz) z8Oqg?5WklEZ6*7gc`F2t(RQD>8LA@=N7?WE1Kju~b@i^ivgFdP>qUVcb>{l7A79E7 z%R!V)zAiD#5_BWGS0%&(HkWMT!vmbkkM4U7HCfuSKj;yt)R|Q2-t0pPkbjywbpD^( z$K0d;o#>x>|1M;Ymu!JSz->SkT?jktul|LGS6~#9@~_)sbAnbl7&q z%DLfy4t-IF%FdKu>|isfo#f-xAL|pcYvt!seyq*(UD|*3{JGyhHa@+5b~P<+X9oat z=Ku5Y3UyRFTen+rZ-r_APuB7Xj_$L4@)PKgJqJ;^}gVM?|ORX%!^Z?q&s^sy3 z1trRSQ8pT1Oi^X}trtO2;uBm}RkHVhem1@X(C4Z$Az_FL(mXJu)H|lF+KUW|UY4z` z9r$#W+W&c>LUTDfv^p&ya%|Lb=LQ#bu9sUgif9bOzYrfKE7W8Ux_f3C!^fQC& zn9OH@zAGdeKU?c6tvpWq7sWlOIkDqmgYw74%S}ybx1S#&`y5Oi~2W-951K9CZ|XQt*hs@CmgRPzx-TpG9@fF z|2QYi{kx(Yb@#4HT7xsdB=OgcPepIM2d`iC_bWAc`%)9yb2aVPXUEoaFZZitQX*Q! zt5P@pPhCx&#Vt_Bh6g?+Zq0cV3{Z4z{kB2LOK%HPQ0gi^SF)5AX9_oU98|vS0h2td zCDS_84jH7=_x_{9UBZH_1dVOo}qfc%BArub{7qGG^>K%+9;M zq;9T`!we0vwyyH+SF2RQpE=Y6fGC=3E_2Rh9@8wbyVb9w+2PhLl|SowRk!=~tbVFt zqB<_gl*{+Y)R$MO;C02t!edl~s}l5-usPS;`Zqmj|i&b0&2tibH7)IS%x&WM4_ z%RcOEbEN{$GfEpJKAIGtMj$EVbHcK~OpGifZk(*5GtaW*(+g**8M~GQeQPgwd!~g2 zMvk4`V1_fjElFY@WwEJ+sGqyo1rQG-W*h@Yt9Pj>{V4RRxGd{*&( zwRawsFEN_#-{ik;Z(43y5VIuw}WI!1_~OK%R^#Z}BH$4M_!(H~z2xkxHT@#P#Tey1AB>rl@%n98O{ zj}xE7BmHTO5zLJ|ugKw|cqgXW*XQ}}E?rN3dt9|za0M|LbBZ({abrtdrHRa(VzHC5 zy@Hq>6wW8}9H@S|Qv@jcej;*tL@!iw1; zWk8o&1sw)1WXbT?d*rM7y@~6zU0kYz79_oVu0ZY1^I-jiT-#xYk?I*DQSSr;@ZZ~J zZRG`XM~lv)yob2&vTxY8&FgEj+=+qm`wxolPThdHYEL|`FFS7J0{E0&jg{EB9|kgM zXoV4l#rp-?ba;}1$%Fgyw=1dZQTtr8cWcc+J3HD{LnN90jh51-)1U9q(UJb}E8{)G zhdOfH8MnM@+VPZv1V53CJ(L=#Nfwup)RJEAD+4OC@Re=$pCg(PcI6NB2=zgOVsO;M?J4W`ZadoNN>62^>@dO8 z3r>>8G2+#LnOXc*w+Eq7!Dp^7&B7BO@FWXXiRq6uRsMT%E=T%H3J?b(vR^Rhg7}06 zBEd5a_Ry?2G2w&Nj8|g*v%}Rv&kp^y*1xH`!H3V z{LUZ{GuU}^6aMV&sN@sk?`v33eN#`a%WqGPKmGA{jjob9^IOYT=4=0f>DWI#Gs{n>vrBjBC8%gB?+?Vuk<7^%;Bbbx<@O z98Uo!wSfETq+SA4RvfA8{^-Uo@G?+*L(PZXB2g)wNF~bUg+b&4QG>)kRrp=^D7zlE z?0VXwO%>eaa7Q+EmDV|19W8%5DUuV?iQ!D8t{K$7X653Vhm-448+iD43OsFSjUoaY z0iF8awl7Dd_@uYJGV6W(r`KrOlei18z3{Ik--KE zw+ba<`~GFQJ*_U>1tQ7ZANlCX3F@wG#oKOcV zUW!J)S35sFgLY`N4)8+?xM-yRmamq?3QguK7Ke_p93;vh0Pyn$MAPV}ke4>t9@!}z zhKh@u)q_d3DOuG@Ikic-dt%^oinIRc6)gJwn#E+D21THq*=C)*q5W-izq*}DlArWA z4s(&Dd1(Vle)-oSMmq9kgTBn)ysz5%J2Lyb+H`);$pYu0RinHpT?vY(%o0&W3olV- zD0e1cx40qlHJeD8M+><0gkcXV$D&P^Q*}n`LJ{s#GwR7K^!*x?@2@gU-{tmlzqg3; z5*-EFi@#t1^1)#QTvU@DCdpIcvzm`WxMA`w>u?Tnic2+Dm7rmjXK|P|uI?AL31eFW z`|E@)94b;xD8p57s^90Ru1#*p2-(K3e&5!mKx0Ii(h`|XtiLd=s1Q25#ZQFNhOj`kF2JFGoSlMw;8vscbL0Z`g#P2cM_s;#vEW~(2t6(bJt8{=P=_q zZRf)Vq*4u)9^$teWnmNmXkHT5)(@}E!2-dMYl5ts`+xi|I$m82Oiv7a*}+dYHg z159tZNVbsB(tI=UAp-!NuP<4CrX&;lH09*3E%LHXeh&G0m{=&n56pNoUAO?woK z^*6-$pJ(wNPn?jfmFo@hln|Rj0EF*`_VJIrAE@+l20cqspQNKA0s9JH!ETe>04A8J z8C2>H*Zl)yC6YVRUsLsq=Y$lxu+@8W1o`f0abE45@T;*u;6BV`A~>D`HBd87MKA-|3-W_WocKNG z_yd4umJ;^6DFg+eYsC|`Vop5u@>LNBWzBfIkdFD>m0R`4*y4_;ia|PNFspRsM_&7d zTI+TVs=HK6!w&V8ghrakB#9`N@-Rwa)<825k#bnfE_A2fWzEwbI-oQa?Md z0zp&N$_{FK97?Qf>zxBUJ^R|F->ZQ<0ih-{jpj#)=NUqD!Iq;I7w)H=x?_r&rk8XD zc`XCM)&3#&wTY`Fj6UG#g*Pz#;lMfi+9xXDKGMFJodqb*s*G<+I;7?qYFwOPn=ZWH(XTd=O^u^ib#M%1TLmWIkI7I zWDR+7fp>!s^%`}=Q=|o2u`&Z63@8+(eO!jKLy+ci_OX4+p z1eF}0-JS6Ih4vLQ%jq=_LM=)c+W1w?ykt!nm^{%umGfs%Eggi+7_Juy7 zrg!&D_{W-XD>qYsPx1@7aI5t5xp#bgci%_{dO-S4HoL%;y3tIoET%^8Hl5N1_(@nb z9`r-6)S#Jkmg|gCGPq_%4W!5Q4@$>O&#?Oq^CCpfe&33}gG66CWEvfC9(+5vVJ`iJ zk7X^;QPvz@?Uod)`eE>Ek;lWFLL>9Ky4|hI={uwNe>)zp>W6~XW|TXyU-E(??C+EN z)Iggw%mP6E!0x3dmvR_#|M?y*`NlinYH%L6bm2rp`7867|G@q~ZYfUBD6R`W#O?Cz z`uWgj9y3OU>(|I3x!O%MsWGBl)`Y@fwbTlhWjYI;nn0}JFzz)mU#e}n!Y2<(>iNqX z}2`{*Ua5Of3<#(yYB`6a7)KR_|qb){NrjCO;I-9snCE&b(PW@Huxns#kc z9NO4(uGC_+)Dm`aIx)9V$mMd)Ol#|36Me?2s}$|~o~#KE9;F1eOl5HplcY(-efPed z#>cU@wpFT4FkiWf-3~KTB3Ik|txMV9auSA5zQf*xj%<6>#++{e%$sXff7t^=;!=%D zr};8)J%GFupiSfV@*ok8uaOh2f!NZ+>6uTH4~*)Q;Df|^t8(1Hjb?_1gxkBS=%6EE zTS}$8{9Ebrr2&e@0@U6eH&l-MNO?Qt)B%+iT*uMsx~~9~VC$ovtTmq-rfi`DSb=`^ zleHzu3=$>3UUa+;ZQ6&EcLC@hd-!PiGPntQ>l;zaSqUCj9NS+m)m>0QdD3@qvPDMu zKc~l_DVnT%O_Rk>oA7EhncnpAgxaCsO|NOa6E7ua4dH)&K|7AiVQ?@nJ&8vE6{k9= z_8H%Xpy;(a=#;R>os5~kT=iw*d7k<;j~SVC&sVGO^2}x7UpZ2FcWr3N(gBmQ<~@?s z3N^PAcNI_G{e-$Aq0Y<*7O$eKv;`=2{_K=~|_mk${({Z zgLeCizK`=f@d_QYlUWx06g|yV!tjkgkkIA+Xw!7}H?gXgIP^c#*db8ppXG--lfL?o z7Sz?F$G8tKZIFM38ge0F9RLgmfFI7l2sPx=vZwAdsM(r#A4%xr@%1jr{tW_eH_4 zx&9tm;;KV9_<^2%@3^Oyn^4cu$EIc!Uvkld3MO}PD%1Xhac)5`aYqi#qAvQ!S=S$r zy#M+Z{X=KL?r{=E`aEXRU&-_^#RrW6eH=UVo_f3A!^@F+NfF#J0a?4L`X^2)oMU-| z`*MgRJG;}5@w0O9_ETJ~iCViEwTVMh0%DSsrBhQB-Dw&j>MA+Pbwx5J`~Xbb4Ad|a zU7^hM7ExNqVa{Lk*baJoX2#tu1oNCEdw!t^c3#h|7Tv_n7uYL|0T$$+DX!Gy(yv87 zol)sc$IOz@>3~z8JAa1zA*bnR&@-Pw0ZQPn{HFU?=^G!BvPC6An^;d^9pG0s_jlD z{x(-`cQg8F^5$&x;ln{Sz4@r5ZBMg1RsGb@POtes-9r}Cn~}FteneH>McR*52mV+= zKTUe?)LKV%gG*-`6i@Iz-Fog`0Hu%lvqpR`oDk>)pF!x_!uce$N%3v+wW5ujtKeAMGBrNEBCo5F090H$70g z=R{|o#odLW3InU3u*vK${?+I>&&16tt8hku0Q>i+O5{sc;y>PX{PeRFr9k6Xp(8>S zjr${0?)M$gy>nYjk`I2I{m%>oOZt3;3J-buZh8G5Fde+KpSpT~@>O3xD~xa8w?lf? zCw1u5L`}4N4(rfl&iE$j?V|CB^$U*3@lQSEh?V*zLkb!AH#R#HdV2ei&3iyA2F9EJb|`k6Ek~w1ixj!qbY1u{ z?D1vZ01>%shzT^ceFJ<&*qUb)C@P-wF11s+W4$?cVT53n8RIGASHUQB`ab_^==@QC*+Z1IQb%8#7mX4bO3Q*plr>j8 z^nm1YCWx_jXyRpEm`Sr?uwjj5tEl0RabT02xv$)a;ZZi3}#(^YEoggBEX$@l?4*ogJXo)RtVuVG)yuP)5u18y{&THYKV1FKDx(Z zxurJJ=;sr)t0CQPlT%jfV!FYGva=#mlnp}2XKUW#A2@t`(`eZ27xnTXs}L6#)IK}{ zH=J46#UHZy(!u3jRm&-bo9&5gPdAeQjSCoWGa?nG@_Zn{R#LM&Msv2r`B5pG(T);0 z_pgf_P&%Qk~j#d>dwIgF# z#ELe=qPbq?Ww)QwXQ*6zxU_ohsJ1B{($_RDljo?ds<@+2u6Tqa(-`H{1>5Q9CH(W3 z(nr)ldSr)@&O233S zTT?yy`Q2C~%Fw=XFpCi>;9=(RnHcRN$@cYZn@U0E-pH8-+iYh1NC%5hMF;PHE{gew z?0f$Y0P=yYqf%j@eTzO|*zM1bGi(neUb|eKh70+KJSv;RABs!Sm)m?i6$T9c3riltmhqLG7t>v4ru<3hw+~thl)0La-k>t))~5-sezCE1jO#P zpCC}{RfibXn_f;u_7Xb<(w3ezAOfro{i;q3Ud#a+zagV)_zaEvxZ<>@nxHCM86AfS z*sgqX8q_3E_IVLJo`RFWcLU72yp6GbwQ`|z^gdO^Hn)k-GMXm<@T0w*nfL6E{J?_u zh_u4Y9+G9Y+FWFBi|n%EU?uiYdifQs%Su=^_oWtbEMg{)D&2QF%YbaPRU_q`!G+xq z>$4ueSKE9NsG?L3HY+ZIok;x@vrTb;HqpvcsDa|(=Y1BZeigcJ7w_(!>^0immL5fE zMEAR^8aQ2&LY>kS&dK*#?=;mg@dDhXA6WmxU)SXlrpWkyC#E{hJ;Smi@L{=+!>8Gq zT}r|rSLa5ONmt0O0O2s{3qNt>Y#{lXmha}u)zO1SpK;w^Ro9H5Qy_0`(qY|Bw?hjdg(jcQOm7ZOuv2p(tTQ{+1GoL^Yv%D z)%9Dmo&Q``=lF^1MMW<;9Tr1+`OD9+9p|TO@*Q2gYJQz?TIuB}_i$-q7aJ*BPQu;d z&2b3=jSh0+Vx8Go(12>~-Vhy0#JUJXy94fNC<^=^NB17hg#Z5m-0X^7Tx)JK_e-kf zQgdzYm(X0BT$=kOgwT>|GdAQhmn2bh&9&x|RO&M(my#%zN;P*$LMn9GZ{Od)&e?Hx zIotcZU(eU$8T<$6qQJMZcL~Z1!*z!pBhs&#+$$V&`9dO)mt*uJ1TArV?x?&`F!M<+ zy(bf~KRf%aNe=t|T-vP4w+5i3-hFHgn{TFzR?hL-e4Wf!w=<&AYCjtFKbNIF(TP;V zgoNBXGZ&(u(BKbWmPADBs5v=%cpy@p;nIXN;2fgyArG8WsL@T#sEDwiN=MVTCq_wCRxEFrLXP4<6eCSjT^o&&VECZi@4cmb$ceNz_0L#_nRZVs}w4o zR#kIjpXbnpD?#D4Kgz4AcPx02hZHPQ@Ck2wZ>GgawN zd-yo^vDG`il~}-@lM2mh`a%}~nY<-B?6%;>H*2cu9D2E*+_x1rX~SL!P&ty>sdJ zaL9M+{ZLi=``c^=B!`-xRuTf%n7nDq70JM{?FCUglgv|JXviwgK6zTvV{y?Sai^^3 z1_bnm#?Ogp=PpTIDdaK-?zs!7Fb3bSfu3~-LbRlZB_nTMk;k1zElENm=s-L+c~`xm z@!Bb|2G~F%GMq)xW~A#jr0>Bi%*eup0_XuWeON>y4Wh7GEjC3~6O17XSV#Z$$CU&r z$oZrsXxTJ#v1RdxZ&XndgoG-0yQ;XGHpo)>X;Il;MPTP~?!HF0q zu!T=j>QkK}Lo5~&({?ND(RSAw1k%{iugQ$+D)%2$i@GXUsYmLme*QB)55uoG8Yx3Oqg5+2ted5j1qlOe@pVwD{60X0Mq>HJTTv(%3BFToD( zH&N5nQ~vG9VTy^`I&uMrT*Q(xf{UiK484g!e{19ep1f?kOf%J3LaH?6Dl|MwY?6%n zHb%9NBL5mg9FX*tE4#EkR@xFm#!O04#;&Z0!2TOf|M0o;)3E%CEp&~8Dh#>)hmAal zRuClB0m{daauA&OeCG3)Vzv#s_FIXLFqAWe(Z$;54_4SizHriAX01JIZ3_xOQK;qaj0|}|v--N6r zlEyR+Zh(dhIn!k#c;D{q-?(gnm&@)A<&iY+hJ2{_!4Su!brdyIIs$)|xOIu`F4-Cb}yS%aVX1uMo`ckaF<>qb{8U zFiaX%D^kway?gq|-Gowf$~~R4inV5?hmG0LXCl(*qWF!d+RdmNneSC1yoO7^+vXr;vv<5mz*OSCi!qe#$|rb)t4~sD&}HSa3#6 zu~+Ygx^ojUnx#=vq8tNO{4HlVwH9*ay~%OCXhD%jIdQA*{b|(8h>}WTy<$RrKP9ac zi_9)UJ$i+F&bB+foI9qIH{OR?4MH`53b1|7-^auPc3}s?8tzCZe6KB@!;;ihN$WVu zAM{?K@w!3uNg*7^6W|-{IBnG%C3;O>su4MQ7akNh3FNiY)irzL56*U?-m^qcL_?uVrFGgsmps z$%&$^(v06V>-UJxstX_TY))_Ze8lwP)UFM)xbRdkudMz^weW3$zmG>ss8!}(3kJm8 zY^J<%??9s429BAD><^Z-nW{*Wp zLm+7cWn3*}^ABpH0(y+t{i!-mfp8Hnabl3!y7#-s#ra8|B=&xB%sFOv^Mq0}E-G9$ zmKZizN*fd?6b5a&Jdft65#o`5n(!%Wx5eDupGi4W+0Z!bkvyf;-y($~C6_ii;-7J- zWRCc67UCrvHODVWd)s#Zrsm0T_4(_h}3A=}Y2@TuN@IMJ&Kf?u< z8DDy5skgRpDE^pO!LAkE3i(@!VzPzeckzq0WYjMEZwmc-+@FbpI6i5-OsOj#$!9|_ zzfh%;O67MnzP9P<@z%v(Vs?Y~8vpuGhmaJIGhUv#HFP**Px<^gCKD=YzOq3(QaE=) zT3Xl{`t)kY<{d-j5>0gtL z*@Yljc1*xo@Uv_i>7KMP^2&&BKin*BE~hg&UF};B(M_sd-@~rbGEQ!9X;R8QKdDQ0 zM)0S*ze)L28sGoAXRwIlh8|se+>voy$6DLi`c<*^-oS_6f&-r%~i$B5SqYv zHM{S`!TFSQ)v}8&yebX*h5rRdi*%~5U3}MA!>I6Cn!Az4paEc}L*h`T+R~Q=%vmFo z_{`Xigqz3-3KvvL?CxH@^LMK6+5WT3R~IV5$0*B#k7TbdVuDAT+Bg@vy^GhwAy2bS zu=V3^%Ap*+Q&-Q;i1l~LmG&-HIt=|za4}f)>y>9r>YaXelcJ-2;~w%46BL?%1k%{* z>^VokQmFZrm*4e--#E=3JLQ6|rxjn1^AH9sQzUKd1j0*Iv@7Xm#2pY$s1^07Ao_Xc$>Dmg;HGEA8$v6AB zWz6b0J}rMC{5PanA-ZgRm=!fKDW)V_wTOw1&QcBg>+xW&TkDk1SrfmtZHG!LA1WX> z2A3Aj*|#mF3uy=2u%95z@u9 z=xH0Do2Ze;cgqXUWyrKz^~0vqM6+t1pc#m1wEQ*vJgqjR;B34^C{S-KYNv<|R<(;B zA0BA)p)wOg$7J;$h?=w0-Bp8 z+}(xIM?VKCt9Cj{FHyzf1;I1YC0q8EV>B^mSbS2QMD~6iV=W9Q*zpZVesnBdJXVz# zX^tK^^-=2f*;iiz>-F5aR@aesEibG-Ej=-ssbhrBIby`sD@`8Bieso&H9_5VgXTN# zEQVLDdMoKEjMo$~QKMMuC_mKMZI|ohhI(n{fFE*4It#A=UzRkO#5g1EGV~(96D3Rr z)`u>R@N5MQR(i|psIyx}O7mGvi>WH;Svl0MUqYWQe$W6TGNZiBfp|oMIvj?8Dx>i) zoZg1BT=&+h2CG3VZ-wP25MN=oDUeLOe7@5opz6|+vxQe;r2yQ&lhGD`&6qGUt1kd-PAi{=Bs)kapAqj<_o1;XP;4>Lu|^X zSymNZpn{dE{DjG69Er!e1))HNNRr4igPhFN**C8S) ztzMMeB0sA^F5EANK9|?sup~}_g{Dq8n{g~9*wp4 zN-cUR+_vmVZLv|Rd<=EZHfcU?ayBW2Tz{LYsUIx=)a3J$v+4a_L_DVk(^ldsYg@Z+OSy)^(K~ z0!(n2ta`O#5`6yG*r4TBVZjirf7dqE!T(=dK^or%Q+m)qvZd|K`81`u?=Z%Rw>D7U z$-Z5UtU_Y_R_Ylc*ZOT>y{_u=c*Ev?7 zE}_B3VoUXxCg7urtGqJ09JP%L8Rk7pB9eQV;s51 zI>~gyKPsz6MLOQEn?+-?bRHI)ovengd@qDWW71e=7vh%IWfBt7A9rVj4l&{;8DUGH?1}vtBG9)%!0guAv{c3?h-iK5GL94v6`bK`MG6fg&L7J)#y= zut&o^1Ar(32lV8CgM}Yb3g~0CtdfX+GFtI(VVPSbq@n`if&-FBnY3szFLI_gBo^T~$)4lFy7mOyDQt1lAiH*$9^ zJeBkR0)qEGyK&(Y?uFbG$5LI`d@rohYgRY>c-YLm#OqfgE9tcoFHYeKZ2j4c5l+ zo^)C;Gbl?Eb&YrS%*OLGz|WP6KaD`**C3^dSF<`mq%9~3o$9gif`&D~#c4SjT39BP_5TzP1z#{s*el!+}Y# z8VxSUH-1rp8QqgrGVCSU=p*sU zA@$Xu@e%dFd2FnvYM>^*lLQ+|Z44jD4stgpT`om$J=C5BxIBBdJgIwLL-Ez{v1^U} z6Jvu4@{=62PuNQVea{>O^mMX{O1n=`Kl@iIEYqhzM5&@+vO!LW=j( z?qs1klbp!OsEPu&V$wTlWMu1Pf!g6B8BNvr?UhyEjWC3%LDcC9qo zw%u`i&~PWkjFHNbx-tzC0MkGZ6AHtU&{&Le}qrq)7l-BCsWd8QB=Pu6$x6 zzzaP&^^!QT#}({EJl;Ub@FHit`0Dfd+2v>vW`J1snBEDKX1z0$_Ayva3H#ajFx`s_ zI;3}EvopgB2AcCGhmXj4ErA};`A>}T5~F0qNB+{Y^3(4bCx;*(#P?0llVvP}HZlPx zmYAuyM|R+Jg|XM+b2Rh?ujR)87Y_46SzJ)cc>3fyTnr7k`YdgVPCU<|!cy zJSmXY$^WRq2e?K;5;h@m6Le`z$l-q>pS?o}m{9B2WTGg-{8o_=DE+}f#KnC;SmdD#h~KI3*q4v;Sya7 zA**50AH(BT!%tlZjafyf{k?P4LN2jO+mkkp9=)4#zCFJFy%?XuVs?d>UXU<% z%ye^{$bv-XI*IOUi1bA3pjM(PESH??J~d@3Y!i+)6b2OpE!&-sfcHeV+_EpxihlYv zS_X3Rj8A08>fKNMz&n8_&5862>bdCav+)Bor>z@jyHAc4UH1Kx_W&d9H}<8ff-#GQ z(v!WiKQ6D^#pn+J4sq$G@#AqvM4fP%ca1U~2=DW!X?r*zFUk=w4rm`I+PgIZ>Tz<} zDB$t+4`gzdU&gQ?DcXPr3+P~a!Nl`gUtQ6ipL!jhSPUYuo&_Gv^=4&0{V6!q{)k+? zEA(Kq?=8mH=($*X*VsL!ahKy(J07jp(>abo(A5-ZoX9+@Jzo!&8HbxOj*2)R#XOtE zR2qf`i^Q0mWB!Qy_FuS+5+0R?WAaNB936OcYC}#bu5E;==N= zDU-}4bVb?{G?Ap)aByXTL#GTuJ#rIbZ>3vNK*C(i_j9KV?xh>52tZ!w=AA$prFe+& zDV@>@s<(_0lzz}WbXjhQzF?A1Ar>4Qrk~+AQAp5~hI+a|Qm(4Msm_^{f?^PlJOt%muEWpJg`IBjcs|Ef#?7hQV<}Z7n>*UMk`2YU96)}PoqVyRr zyF8RgD20E{^#BqiR<;N4}a}Ez7jVCO+AiE{BS+x={#E&&pZ!c&*Zj0Jyjn@1GhjKFK zR1YfQfG#Ak(0)Gw1DkbUhNWgWU^72u5uG_11d4$4?4x_=7SyL3gd-IIj{ivJoVj;# zk^{@w6Dk+_L+c0|iGu!iDx)Bl-$$7oS;`E=`DJIC*Ll?EW3-lZ9m!t5Nk4YGt-xv4!4f z_wvmwDRsjT8`H+>p`!9VM+@Jk_Se7!Z|h2>%m76h(tAROLW2zGv!VSO;W|z`XTplK zT&s%9x@3n&^a8I`_=`PmF1~u#W$#1YuY6f}otndj*Oj9Ir(Tp5`&c4BY;7)G*}K@^ z*qIu(s(Jgw&sC*A9;*`sU>A3;*t?{d`$iKX{|^(eU=4XU%s{P}jB( zv8f`v%Gl`=29s<$${MXIxwItX20tR#>uxcbK|gA_J*EEKNFce1LZw!C9<|(A0tTCP z@g-kqtdFQaH$U`5{iww(-ijDbE2&Ytv^C+Gubkv`<*M?R6`K+9PnY{`uwPd~o)*_? z0zij;PN9!lOy}Ca6Mr_<;b!6 zjaq!pu=4e38S^aIYpmgJXY!|C1|c~#H%q)G;ELp1E{z#`NFS@{KpoOWPo8kz6D4iq zQ!?U-+AokFq-%WFhdvcwSn`~3|M3CTZ?yJjHpudG=;;D)(mE^GEU}A%GJlG`Q!Ky8 zr;p&iX*4}Qct9h_&2ru!0NTAUS&ZCm7e8HWLY`QIbs4{KbncY;pBnlz5}03s9Xq&z)BM_t;Upy#XAWO@PhH#@(>dVdge#gN9FM3m|DN=K2=$f(tdy4HcS`Kd1IKg{<&h4VyyCzKj!?# zfqmWFaPs=N$EV!WsXo8n-g$F^uG~eJ@u5t6#PxU{H5c@BxS7d*Qs19Vn+Yi}TVi)0 zt-pzgy2FPiLT2-fmxpQ!_Qcm5wOFm7=bQbUD|Wr631|x~K6c-ssKo2|c7U`UrRHGX zFII?blrEvT;L1-ccX zYp>QUxJU!VpL*>O9j~s^M@iSy_4FE#MKI}_8-HqC5eK+Lo3;&($(`rsE*tsA(fwSW z$-VMhGPm1NHnks?JL!&_0(_|qMI?(dIjgdaXPSmfqmE2z*gP3#m|du@j_DVHzG2H? z$?U8%lj@i&SpbJkTJJ>>2h94~i^CpOdQo@OGj#l*W;%@jl@dknp)zJZ((+ID<5Z@p zuDqB8R7&Kmc2_e~GhPzt$5(g%8hKfE+NzD%4}**j4VsgxXtFKX^N&p2q`0j7c_XN^ zUB~fp=@LU@>2GT)LE}Ui$dogSnO#yu-Vzqjuc^zLxQHs7(z3~&PvlFNY_-t| zWx_pj<-a5c0XCjWw(e8qbd=?!XV$2y$$Y?5Bsyu14iappqZ?@{sVR<$WZeaLW* zt!b_?48yfo`c*b)IKc&)y3m8atp%uDfegd8*Huypo(El^Ad937#e=a;0V~YIrC%Fi$8dwI^;J;Z zoNDC{{OiL?uhpV7f{gmJpq32)>C{FmWkefPSS}>)1+Rv6T$<4!j)`@@6$MkMgBIn5 z=^E5t>9R7=f#vbO-7lWPPjxsP61QQ7VKo&0+e0kvA1^p#Bn72NdYPjSyjGaBj`bNC z&~p)3<=`}?v&9-2@*H>6IrQ+Z_3l9iaMun18h?V z92j^jmOoRK&Zjs5&Pt9X=l_W2&3j7w@TXC?vEXoZDb%BNR7wNQ-~h$fVs4>cAPwkD zy;7bPzsX9!Qj3-Rrlax#X?rz%Bt)~c(!tO&LU}w`tG@ifjawCTATE9D#-jsR&t8pP zS^oH==2$y?w>wm-Sns~dTPHUu52P_w1JcH`(uQ0Umqwpb{uK`q^ROy7YhGsi$QGd0 zvfTG%O@pDspq*}(EKG1LwZ;C67f&RW@3FN}8YThKj0xiJjoY$hn+FZZEKB>U{;ZXk zBI=QuaDx8IRRZ6k+`+#^NY1~fByYipE;t;DvCKxM`^R^mq zj&-mc127JJ)EE#&h#B};BR!U^P|di(6F1zI)`B7)yoGJ#4O~T>#`xZOyB=9Q+z0fF z1TO49a}V>n1?CxY3-Y|d>$-DSI!>heU@v;Wv@`i-(fkBvjoqJc1jtC9Q&&*ff&_g& zkT1&`R@Qywgvd|zCY&@@+0hV#_g57pVt*;@+x_4mBSBYts|YD5;n?9Q33;}@edBxc zzF71fxLRi}rScUGf{XM{1hsH;wQ7@a)%b$M7#qd8wHFqQpyKlPGb&f?tlWN&!>!I1;xM1M-Jy(&Hmhe{BY&;k#m2VA3pk7 zSHJOlR#3R|kNLm}_>C{SYxvcBJPwW&8MUw-H;w1v#-5)B`CGu1o>#!|BA3F1MXFpI zp6USaL%?%Kf5Um(#|RSAn?ZXB#5npOlKd~d5*d063@@~WuUXfzE5@^I|7pS`=X%Z8 zfS0z&hiiGHbrAn75XI+0=jks4m}9<2ZP!FFAW7oX&s+p5~+8Y3a#pCjnd79I7EtUWg-HJY*RetkbD;2NKRYq4o2VXb3$ADkpt^bwM< zvO_IglYY8>Cjw65S(X5YjdExI%ESKxn;*01FY`(e))p&3#bx^83Z7*cLm?j6MZ#Xe z6)yL_I@p=YzE(NEeH~XeH@4Q@PZnNFE>YdCR6M0BJx)0>F{bjIFst<0Kv1-pYAmm zyk~#6g~T+fBcIHgOCL+Pqu4tx@s4j}RQo|hU@)@CwKl0mT;d@2|H)r)N#`D@aZ3|_ z{#n_q0Vr}{sxAuzwVyI@^^eZWfJvi$y^1Znd4-{m#V<@@hv*jl@cCg;L^#R(MF^CFHK5R9uF*SMM)HfG&)vreAuTb{`urS`lVG7|&? z9XG>@qY#?6r4jIF-ITnZ9YUXHYFjJ%EVO=_t3G1uIufMZRicZvwdkaint-l9RIl2- zG0qtFn4lW2(D6$Ea~xAuukX+%(3qp@pX?>+!8VC2OUOlXQJOcM$(>F^NZe zZ1bf7XvW6qy+E3WDy+Pc4_!f3(&hqDkE*H}75kl+>jXH8-A+8iEZ|Ieo#; zBqbz@=5r==HtEsa+3Lk;`75XYe6svmV=2jZ;}WEo0Q+5lrdZJR$1rQX(2H5mU08HA zs#U0}4J-=lLDG1U#^=P=K1M7awg5Wj)Or<#N?^t$p5(&YYiYIGXW>iC3p%^?!APR0 zD8fd3PNDjPv>R@Ek#;?*j3!T|9hyMy-&A&zwaOO_uobbw>kvaTZP7YVyrk5HrKS8h z<>IO!TYo@SdP9|5hMJ(ZZiGv~aa^x+35WPL=KA#9beaOuF<{0k$%6iwi`k>k)Mt$z zPU0Pw1e#9Sj4Xu(TL(HA)&J|~hJ4H@W<)wxz|7aY4%2!Mb44H5Vtl#YHvW$(-D+l& zH2tRfy{o`|rDc{CHgYjXYqEHjaCa$@-a{}4TuYzcq^KDmc&OG|+uzDfN%u_Wa#C7; ze&X!EmDf9VArw-CVR(R9@N`G!Cu+;AnRCb~nmQ*~wKZCsvg&>&@y4GYdL80lekX+8 zes_X-{L7u_!Bo+5%Z(b5zQu3;LWsBba3l!s4=@;;5L?#>@6`xz$Y#62a z)Xozs(t|Z%0oeop9OToDBDwGW(#`s9-dj}P&<$tL z^D6ZUt}|>$mvy*nTr5c5fF&|sPnD`vt9~(RhO0M&*k?G1m}(JO#5563p;ur=gZ%pWY<@-Vq;%`GH6@{$~5x#g31!?OdB%H=_TV zgmem=7gO|ZE@{amXhpOm_nh%qR5sc3`Tpw9ZFpOPPS^6S)xZ()&i7|EkDp69>9bXn zEn*$e)8T+CXVx4K31kiwg^-Gu5fj@Y(S-w zyK<6qT4yA+pP=3EWVZQYgm}zUL(`1pay!??vI2;Tv@gZe?&bpP)xby>Q8SG?QxWTG z&CFxVyJO@}RbqK=uMpL*+m!!OZIvh0`vqAjYepwGM)&LP8Wxu8q4U9t6ysuf)9FS zD1#25$^iTXAfA?QPS|TMl6a+G_-}Na_*5-y9jb~f{C?8aXg6u-4R>Nb)15bC*(hkX zeKl=fT)1^-JNk2ZMBC_%vlVesmp78F!*pH_o^}gaDX-aSRM#&K(K>c*&+UEaZ*lvc zhRFF_Ye%LhmhtrG?JOaKYtCWo*I}&{bWDT2bggxK!wpQS~ZvqdORy{uP5f6BSa|ITva!DY7Dgbgc-K0=5eY;y1%dTTE9Rn;;} zsFGL6?k^L0cvYU9mzA79VE>pVUe#{)^R!u7F>NSb?-=wxNXF!9?_p}Mp@#Taurq!v zTQj#`qk|XXj!a<_KfeD0BJRru)%Eub$h^Glxoq}eqly!t0hfrq) zL^##?{qr^}3GgtNnrZ5vuZ834NKci{qMLfxl27U0+$VA7ei+Pb1eiDFYd*%)ls?V35cBkk zNh=*U5qT{9y)+$}KQSySrp8nllJ~a{HDg=nRNOdyTpEv7_VuDvPr1d4L`}O|3vgrd_c8W9ZY{W-| zxYQXvHlO^OZ=2i8BPtkRh(|0mc<`|s0N>7cNuqZ3puQ2FDc=?I8fZBIy1==buRrRF za&&_>yXnN+QV*GFj5!B28e`$)TQ(U_ftH)9z5>TFOIx7V-Ri*ibkhs~W`CQ{#|arQ z#fC#dp&>W5Uth6}Bmx$~jS(r2%1s{K>K?~dTSOpn&No0{r>9gX|4 zJRWsyD^c9<>$`(#I?_AaKVzP@w?As%d$GNF_MpzwgXr5kafn~Hgo!`nggWh2HbLt> z{tVBn1^)+`-2}8wbNn!3V?31PG(o^&Sxib+-hC%SuX95jx^WBZM?Y6j2l@Dq%}lhK zaT;p>3a@^ge(#%&AvNP7Q~L3g@63#iiGa)a=N1WXVe1_L@7MoLziDGEyJi))v08p( z1HWZa!MhjVEhFOP4G*)MpjMk!_rZPhS$|Vrnp)^zCnBjn>+Bt4VP=i z@pSn*r*w6Y&o2ea&unx8^(;Y8&Ae=62Ja~x>c={^+j7$_{Zo$fx5fYbvgDL!V{P7L z^?Wp@_qR7GXiONqIC$=hs=no##;2(h@*!^{?teAX49vdSSl}0vkf{CiexzSWv%^39 zuA6rs9*lX}HRq?e8h0V0SKNF+eO~b2PV0M>lL6|tYaXcw^kU(VAjtuBP@k*6kelrz zmpA|XLMO=F$3G4G)Vq6!J05NQXK7drQ#Mam`*Z1L=wWquQaGD{7Dh2M`qYJW zAWyzt5Y3RGi3;S5D3U?enG*5`le*)vRvEy1I;o-1A#R3farfEUtRvDH1dR7J#)`94 z9<)-UacfB(T?oA-;;zyBwj<(MC_=Bg9Xp82L0c&FhlTWOP%-mP?FPZZVGZri?EK2r zy@$w_4E-T>cw^}E(x@hDfrIpQHLFT5vCW}pBNIWR0^?aK2D&We8ln>{32S)std?xeaPWDY1bTqZMC}qt`TO)in^Vk&a zmGLi2`lrXYNSVrll-*C6n%B!_a`rw#&*mC0yyE6r{6o*NR2L3@M8`A^UOzJ=#jH59 zJU*y!I8RRA{A83?Jb|(J@T}+cQ*o1v>`YAgQgt4KGh1^xu>3Pbow3_JdS*D{M$`93 zsFLyVsk4#S9@rmyU*943KKRzKrQ+AlSAmKag2@Yts|7b03QUKXv*8Mn>7PO4cO?$K z`_c_osaWen98UYnl{!(80HHB<_bX^Fy>tW>| z6W%8(f4mO3sQhy>>_+9!cd`E||C&nvRQc;;6hw63$?O0Cq7db#W~+7;5^Ott)<%`EAUQi^nenst7UF3Zl8`V}r!#VbPiCECzL9ic|CoQWqxm5whEEOIN zFc-GJq_%|xbBh;l=^umU2f@1=2b%&Du~aM z+DpuW=~_3vaA?iwEXah#T$6b@UnHTXE-CQ`^){Ms^X)*b3%*+IY(KM2!CzRoB$82& z_EuLuh=8R;4qEm|(Y4*w$7NZJD8w7z=~7oLC$J&t z%*J4;{UP^7erBiIh}oP?Z}Z4H&Qh5{GP?4qFQ`L2_YkvKDXGS(a3HP9_jXnvte+rV&!o zK+;MGrgZYtp=mJakPsQzSp(~DzcrdGtTyOvsItysGs6DxWcO>lw$70R;=Fo;?Hc~S za)_cQDwD*zbV5HUI}x)NGSuy0;Yf3(w}>e03^|y1s975Kgs41kcta-v^V2x$7X-j! zN%T8#hIzNT%G6p^p^$7!TLQ`-@h($tTxR3jH!;6BgO=@uqHwS%X3O!U#ZM{3T^}jv zN4AHu?eadlnpYJfN8LQ7Jg3zZ1}$beSh9m0G+tpPuWnQA#)7seV}yr{choha^_81zl$W&fc0E!}om67R~#id|dnbI(t5)iK}5{niQC zODQAj)jM3M#Z+PL3u%eN#;i=U<%EK?xsaRR90&d_(`(VVYNZV})P$vDnu#`2S%n@4h z*M>|b9a7n9a4>IaI|_NsMe?(l=C5fXZ!Vy^UiLs^U&ge_da2(%@2ctHkMzG0*6CE6?i;ni9iZ6;xYbs1H$Q6NULH>=k979aM+FQWkz@WfQZ&{q$*^!^9*fIKt#O@5KwuE;wbpAZ3gZtfnix%}fZ! z=*&ER$>!|eHTAOY6}{{=xnWpo|@am>^TryNoPXVaXAG%HXuGczhR zr@n!+mWo4WsRe3gWkqIYW_`hV%5cc6%)m6wtZ+!p`o`tA?t}kYcdh&MuKR>1do9*E z`|PvNIeWi9uh)0Uawj$;ABgXu7D;~uDJRum3>L>0o@vOyulGTB8SZpHW3Yu=BtiFl z_C;Mc#a$(mq@8?wkOfClbWV)Cc|n>KYtH;91JNaP*Js!-1uLPFO)Ah^Lt}R8U+$ji zGwOTc23U-X`{t038o9Tgskc~cy^I^xHJvX0klYvX8k`3-X?%gOpflv6Xg%x)!flzr z_O|<$o!@UVny8Z)su&=JYh^Sgw}-xc_FVWvS0(8H`jA~uDSGz8<>K^(BEKzljdyHbGy`MvCyMs>T?<%_eKPy?Rv>5*~YcAu&E&I;C4C zaY=JYxKZ=Pj_wMIrE0Qdr77SG6|T#qx*zyV{)`Y`MZKLwL38$fglj{R*!TtBM+Y4z zaDnT) zqB<@Bm%Xo4yDo{|#Yo!+yh7FF3uS`%-fzMi$c*mt zGQ8!Pe{2hR7jh#`%^cu@y!#)iPWmzo=5rStT{tgWqfe9Y)Tr~y+OX4z8tk+ylUR=-@K}QCg!TQh7+3A_Jo^aO1N0 zSswlX@Rfvs`I(3B0iq}3@+xM%}`>GPCrgqjq#+I^~eHV@fqBoiaRLrBh!kg4(KdWQbH;aTojmPg#|^gGNvv z9l*Cy)fRz2X%vEl4=NJkM0Dr!KACZ{CYQHvqYwWk#CvK<|D!Fz?s59~qB{}&HsA3x zK(!8bR~aI9Q^EL;Dii4I; z-KerBnUK$wPhu#>EXca?lquw$RPv5GZN*p#!HuB0vaA*LYV|;?m-L(1`>-V!NoiIcP>CKq8$L@5f0U7s~s=3L~ zTw~+=*hr@bFb);JwWPTT#J|vb9V15#Vu>|2$+$Klev{F)Ld8v-=)5k8PxcTNg&LzL zHwSolc>2M9A%16(C7mU~su5Oz_-pLn@h&0LbsG5XCHh55+KU^zjj@|-9Fy^3g{tdu zMx*O-wp9(RkE+?hySML=4WLjzgnE0)1i!?fD(F+AjqeYU70gLk!id317u^;HehVJ* z5r|dZ!9mZdi7so(I)prBH>-Zu#6HyQlX@y*Yj#i_dKi`TS=k|~<`fS>XUX<44!&kV zLiKygP4FL!;XVrvXH=>XIa^&T@p)2E3y9&uUup2E~myojm^ms7dj zh20Xiaj6G?k~PP*V)mPfac4yGZVIMgDM+r?yowir_;M=y`!}43 zq14W9yOgMgy$Dt1O%*DItWxpyo#uYt5uH4WaJ`9`i;a??#Yj(6h~ zHpNdzUmW6>-)v>&Nu-x;Q!TLhrCO1wi!@x_o0?fLyqAIs2uELZ`5t$Jl|EPTN-5YCZy^ zaaQ~T;px*!xOFn_02y?jtVy>xfJv88D!_G+u@&ZbFXepjIf;`HgYS4`J$xL|oY3-J zh#O)b4VA%~--J-eCte9P{%S>vwR$Q_HOdn3f63U^`}l>&5ZUcnVjy;yq5MTlvF(9) zn?*;YPxk%?ug?E;5AFn_{%T2Q^Qivbgdn;`SD?NG)!ZWtH&eDIWDNRU!j6-i?sE^$ z3+3YwIH&{{$(EhT#2zTWQ4?|cK|Ow)ciA@^Z(9r%5h6cPvF%#eX*PfgtX%HEtnxJc z8u0=uzS$5`uJzo2D&1!MItU2qAe256G63)Tr-b}ihHZ&Jc7lfo7vlPO*csu`65wVD zWTxyg?gdX{Sjgw^cdQaz6$^3gS|{d!t&*6g!3I{q`}S80H_2{GV^~rIYNHnw-RRI^ zbsux7T^%f%zrS9%w1-oThJcL|kh4BW2$(=TbIAw~#5a23xKuGVOkcB0D5C*}q*Hm{ zhn!2!p06xT5JxtCW#hO)4K5GYb-yz8?c!%4wmw9~`lT~oh+AN9?%rRQL8g}yu!=i4 z|B|r|E%>eEoh6j%#gnNNuG+NL1C@&&|4O0%zQaqP%b`(Eb%(so-LX+8zR&4FTX`6l;cYEs_E zzD7zx>xEc6JJ*KHTyA8(hfi0W-8arI>`5CF7*Xatwfa^r&*fLG()j_C60DPLSpZ zOMmPvyPogRk#krP$ekl*82V!YDbt zxDv&R_>oR`)H~oEf3np}*2bbxbDVA|;S4Jx)T#&oN2Q*v#}VaAUpj}2K=pDMfAE>!P2KiH@ZG_#FYgF~+%Z}w(8!B3nmsQ`t=)eFQGw_Q* zO(sx!fzZv;0^9|lR_Mqx%Uf;b6H7pi8L2%)A~q6Cou1X$(wg)kNS6?H-|J5W*FgNJ zc&}af>kNz{6&*Qq=LcCmhM;!mB380n`p-E@WoRwo4z`|+9p+(swA9xqZ>;kZnHH>{kAZiVOj{l+=L{h(>{VJH0$*10`-A^_@julk-7n>!JX$k)!pyn26 z3PIYBD=%PZ)>ChrCWt@eX)TGhRBL`dKLmcRau44mA)ssRa_)G;9)_=6|1e?rRbC28 z1cEGRJI6_=H3}MD+!?{0U(&+L>&WN=zZJhPys&}21AxYy$2$m5zfEm12fmWjs<$gO zyrwEarnke>kpLc2I|!$$g=)XP3x5B(851m})jh6pA)h51r-6{GkzFF776Im~mFd5J z<69X>S#3qw32YE(&gMIIiXy#Yue3n!i_Df=lc0^M`M21}_J691O|e@*!j!Z_@r-6m z>e|lNo4rgbX6M{G)o7A4^RIRk|68idLn^{^^*h<4L|d8}`)fuB3}4o~badl$LWeH~ zVv_drU4mH3-)Vnq>axu;?XB^V=dm$C0-yL{{PU~M_sbkxhv2B4EisW+&TU7 z*^?h1xfybr_mkCzy~I__%%i8S-&VI9Dfz_HamUC{scN6=c>b((cKWIK;0WSlyN^K$ zGrs)C2Lj&i^_)&HDEEx~@Q~SzZ^n4cG2O;2kjmoJqe69OgKZzJNs~|~gmCuku#&*q z*D*rnaIV<#oVbg$-(J){?*!*f`M){~w+1@NPw|MJ_A9nc!gEBQvqiSmOq!N#etYRF zOJacPG!wxiU9NvY7Fh?>Pg1kh4tJr^iT|T!iUWedvL6Aj zFXxv8tX@*zK8^;-Vi=D)&Uq;Ud#vvkfFN)y0Ywv)-&*QT)YV<}wsE~l8nFGDX{v*^ zZRGaZiYKKq&bbFX9JX6(z;u>bT+*Q`85_RQyJB|#r#JDVmc5LIWLx|g? zP;cUP0SR}}qGB{`n?dGPZ!=v0qtO0?ge+#a%70X3KRHwSYH!NqtuUqe*;+4EFZ5aQ zegoUwZMtPjN<5Hk|5T7GeEfM&P-g3nGO+C3$&4c7QcO;#?y>;1pNUu|=Ca2K6I#1| z@*M{ptjbEgZGr)zPMD(j8tB35fncu;F@TYAdyX}LMqO%u^v>Kw5)wpuxm+o-Gy=$W zDV0ahWS7<)8ky5z6Kg;(eUboM5$3dy1=?|EA`+{HST*zb`>>dYOx-P(>mL z#nnn-KvvZZ_O#MUK}N=~*mE=w=cUiPp&o7GfxBFdR5&4Pa)Rz|w;tal_IZZZLuk0D zpN<@9-atD_J-2OO=~$Lj=p#0?TzlvZg1a3uHB7nj5Nme*Cf9Wfn?zV<9%5J8@U z|4GlP3c@JQ5_M&)7Tz;{t>m0No=%0XLvba(Qv2bJ znR*umT$MRaEw0}rj|~8#miuzd{^_e$g@ZK1t}4nb3i^(DI;t;i=2X)gZk?S1;Y)JK zWpowRVLAoo<8+IzZm06Ryf}kH7X#4Yg%sOx+tVE^ z$8n0wsi9`Q?&fOmes#gSR(P%MmubiZX?~|b?MKe@vr!46E*k++)`qE-XVgef z2;U)v+h=*;WqbVfpY6w%hPRlxp0kN+Z*xZn6oXSG3id_-7#YM;1VSDv9MpkGoh(76 z^!42=qJIEhyox&AT-FL#P&7XJ7IRQM(`2;R|Is=IkkL?IV_ib4@Xql4w=JN{(Iq6u z%$QtWmkxnqLVGn7epmD*6+lb=MtZ%w_od?Je8qx^sSb?L5y>@VzHa|ikG~{pp(i?aQ?0Wy-OPDp#26( zs^(!?$&qiEiarsV5#SDjRcqmC=BI&A2XgF4Rog7uYc(fj&+eUMU;oi?3%lhOf~ebs zKgjCs&DPad9V$kpW&Y9}zmubnRP)23>aVW0_7K(t@FdC)jN_L_g$GRsjM(Oo2~qE3 zj)cCm>8MOjxv6OxI2c$LDc)amBDcG3OcvD7In7CZH%Iyuy=gfD_cOtu1!wtT`w+5p47R~FTDIX&)4?{ zU>ujxz>9sTta@h2k^KrbNc=}7Lvd42^FxF7#g3cEyO~1l?}{E*^3#Ri7CarEiL;{?<>X02LM!w&e?=fb#<%r2uw3ohI-}xh_DN~deVOnI%?&eq;FmkBo7Wf8A63u>UQa)AuTkvr|b$>JJ zpNborj32JV0r~n=eiD86w3k7#+x5{iJa_xyKf5Dt-_8utZt5dBayXGUW+S(VE}Bo& z|D*l$hrZ(n8qzNY?w%qdXV6F`1LP+rB4rj#r0h2-G1z|k5JHHf>FcoSVsx8y%R_}40 z4%zv~S{5vebpmRExo?J`f2(|(?G?o9kr*BaH4lLO;2^`$$e(A6Z!8pPK8(vdzoq(5+S@Bex;F3Vc70sAO!tZx0=Z=VX;TQ| zoGGb}-gQ*-$`W}%7mM2 zRuDdD*)Zg@XM8Ikn`cJr89QPs%`<5KjGqLr9oJ}*GLXdjiDnGHZ3SPlHWLwU&7^Mx zi_avf2@dKd1-U75rA?mrw+C14mvhc4b}rsa%CJ&!b>~MQI9^Q9pJzekilx#sjM~Dr z3MxDtrF_1T@*0lk8D-~LpeyPx8%}^u{K^H*0Z}7Nct0P$L_^Io;hhxgI}JN=qxl9F zv@JTq2L?{2xZqz`{oXz}N+y$&_ci&!n z@YHn2rxRlb^oama7)_>KgeXoxjV?Hp`4BJlYaDkj#B~JeI0i4c#Y<9RU7UoUtU{g3 z@J*58lTC{y_r#rV{|DKfQdJLnQzYE96#~?Lijd{R1F>Xedgc|G&XDJyLXa}WaU1F+ zpZY+GObZ|JgRVPB^lx%Lm_G8)X9D}jsEmGpq=ESD+34;PLm8JxHIQm1d=4!yqDOBy z!}Uk0S6tzH>yzz|ld7NiZqaghA<%>hL`QfE#Dc`3Tz{U0S`f(H?U#E&k%RfA1|G-w zg@P{u33y+Mjcc%}BhEks|2rDRqM9TzTxb2pPjYWmR6Q z|2h_lfrOhO8$W|V{=|Nw|B_TuRTgTLcpxoD`J;fiozSpKmofL1PDaCE9Uv0`h#|0& z4*|zfT)bZ&HbFP5qX{w!^)1ALFcy@~)Ue_|XLGYwq(LXasC*(d+M;mZShUKl?t3um zd$5HShqysU&H@x$#qSE@6Oo1r>h1tY)LmExS6VY~H%FOQI8fvss_T0KC7>(MbEOR) z?_Xh_lYPp(k)OCFVwPcwL5Y&?eC|yAmq?OH2}B<4Eatr9SjML;%7GgB&h3FohVH@b zTNY7hSPHY~Ogdj>H>Fk3-SNAt$D^Z7rJwvFJh69vvLFpU^z88G zXD--_R|1k#l^9Tl$ZSduluScz5?$<%8t-c9cy%<5^HAz{Jo1%{dJ_F{J`2+SNQyX) z)Cd86A4Afa{y}&9LggN|0K*mE_g}|ijp%R}Eje8-h{TlY6d@)B5RF>M4Zl-IP5zxB zH90+txGc`QV000bqP_bIMXPKD^_GrWLBn1p7)^1c9DyL}wh&m!ws8NerM{pjCgLL+ zK3$W)(Jgxrh%71%{NS7J{Z+o+M;#E{fNVoz%usiIoX-heeo{?I6q7cWYA=$(PXF8Y zbg#bu68&tsL1zX`GSDALkY%HTh zDxbe!7j0l{%1VSi?apScs_5-VEgob6%hIn?ALgpQdwPZ9gjJ8b=@F-uAGhh#Xv8O2 z03caf)EYB{#Le`TgLJv4bj%8QDq!%+FYO;J=uzsx5it18Dl(ZrW-FN*<59N(R%YU) zT3&6!ApL z2q1jmU_sQij9Up-kE;v|H(hR-kXp$MsWJztL4ev~G)~Bg>^O%a=8_A^s7*Be83S~E zdurJwzjZexHkLU;aS%Gb#$)QgaHT1yQ6pR{qJ(13`}c^Vff3DdlWt%k;@tSzQDa!_ zE=pdbAzqFW)JfJ7Yt_q>F5}$MGSlLGAN78LZO$Wv3wFwi?~PdwV5Cc)5g-Z+Gt2^l z4kpwSQ6fnJuoNgtbVhLwlRkE%0VmJhN$Yddd z4?&_XQRK~5;U7it?WspvjvbLPLx$a+7{$H+Cb*0*4rMo83Cwxm@g%B21|_>(oHU00 z$%LDbq@A@9Z_HtK2+Q-GNbe23O!AIZmh-h(2jjo}p40seCr^GQ$tIAX4Wgs^Pn2za z@L|7TiA?Bgy0c|sZA(>CMV{&uUEw1OmPm)bBB0g*g`jg;V=Smx1pCBtd+O2to~|&3 zh9yv-4xdl~pT>`@C6Ap&jlYxsxYS&uE7PEcy5Qg3vfX#QL-twcr=N60iVrk_4jp86 zOw+5ojASHRt|F2Q{7&`nsTQ`$1%D}I^e`-u1)UVroz<^Nov*!~AVM{;kgAWL*v>z( zQU*aEDpdnOaeU-mvOYnwP)d<0qR355!1F0GWdMfuA=XrJj$+fZ!2l>Y7Fpy2O#vX7 zHBSY+r`NyoE%vw7r{>89c45|0F)WCLk~)%zXbzAL=Kly5fTQTA#<(o~XV08FenjUrto~vwvmbHBEUR4Mk2kfazzFHC350McJ4ZJ;JO2)~rnOJ=x}FK^_A(Q`0S z$#-jQKm0YRoaTwMwt!gwGanwh{{TpdoEmf0rg~mO%QOxD@xQz0P>1bl?3>EKv-dSy zKK7m9beua?twsp!5e|wicQ|(hZY+G*NV;*@?yyNoSV+!|I0v1WtW%rr^ZB~+9({(Q zVcxB$=dPDRHT{s#8vJ(NI45@_)Ae^sMa{CRvmoyPFUtQ<0 zeU}U_0j%BrPyI6L{(D7GoG#W}YvD%Hba76#EqxQ3Yct_qbp2-N;Jo^4w04QffzU_Y zE#o9o=GPHVG< z)vG(aeT6?KC1mJ|-JgBQ!Cs=|1Ixz*Y=vr%5AEA-#MYP^UQgq{m1C>M3iB?9hO{LR z{@8b*)ZXX&9Mhz=>}P2FGXady!`}~Ct9F5ExR_;@7^M3lr4<%6Mf^OU>oS!k^Vhwc zI>^PzYpbxS)VANZvOU^A?An_m61sF3*grmoPyRKf#4nia@2x!P9tvzs>IvOnvXrD2 zToAwVa94ow;}K8m&s8V#9lzu=t?i0F9>0e_fPB1LHC6BsQ#|~1+nx*;?R(m7Q^%or02{AWxdrs$F81x_teQu`(CJ4W%7_vR!cQ0F9+9I zr>%fXGQ4i0h7<0qkv%?D4An|*<>_BP+tJr2gZCld+PO6Ad+ahh^G}$$&W_ua*quSw zhVsTf9d|80ES%_kl#&_h(+5#=?Y)&q)6Ij1Prkj!HhW(jHTgctClhyLf;vl_&uIi! zC3jdO14nx=CM;z;&PDg^nJiYjz+h;IDxeO6VnpmvhQ{=1sidyuqUf{+H>)J44_&7# zlx!p1TN(o4p3CZ!%`~qc3*O&`wNSC>zLfVBIh>Adq@BxXXthrcaQVi*$0ZJk#Y#>`Z9k9U7|}CY(7`z;W_~w;dg4tDKO_WT`F2VSpAI}fLa516k&6hsw{{#E;6u)$@UqGla6a#(ggjbET} z#~{2q+SRtFxK|Zjd$KsMzxbW7G+w|vz9Hox{V!XmBC_tB^IhoUd;r)s-V~QOc^Fam zuJN6xkB;HNnVq=8T&-^(2TR-}g{^15qY8YsQbCllXA$<|#R zR+&8bVK0pfyODX)A|KuRX;BMxE-Zp3765@+xg=>*bc5CFFShRM zjvrVn{;}YK7Z-zxLycI*rM#}R4!;sb9(=yJcXvJ@$UaEx)>-u)HjR_-pk8+C{pRtq zaT>C)HCC3jflpnQes=&#{aX2?`-4m9wi<@!zW zA)-qU;UIltBZ>R^beVv8=9Z>b~ua+ z1Q#-uxdAecSs>dFYXge#E6l7NHf#u9@d_`jt>ettfx~9ZC#@7x-!ZdGl}7M%rNYZu zdP9Ks%YHXo{Z2pdC}9#0O5A95e8;W7?3}>O@~%wWXgtFv_ZwjQ)iBjA!$_bUZWYk@ zKHhN~_QXY>N$R~yp_ES03Az1%D|&N>h@MjUIXz853c5j(7@n9>ltetO?=0xBKHOh& z7!m&XZi8c9K_z-sRuMLFbSHX1l7lVVslQ$So?69V$w-u{KZyz6bqOnLYhKZO&3Qb- zy%K}oH>eh_BU7&hr>g4IwO)Vm=Ggm-%*XH8EiVpT_79GL_=6q)EhA>w7|DfWa^7^w zFjgC1UOW-v@teCiOD+f&9ys9E@lr+zw64GGeZ?SYOw2XUVqD9#H4o{E6Rkwe?D?oW zt}^9LX*%i7ICdpK|IVu^!?#^Sp?(74khhL=Vmk2a70Omuu3tvONeqPksH;r@ub`@W zI%3SL_cT z9<2MaUTw`!Fi(iipPjpn93C5sKC<(J$5$F^&(D0;@Z}|@!J)UJ)JpsKYY%3>=Y|^5 z)~_USeth`O`@IL%_I(anG_p*-k4J@mU&(*aF6x^Tx`j))9bFmn>nVBjCw$I6#$5jl z46K~p`>~``P7QYG*mIXDG>gW4ag9V`NR-$``@65to!Xl=QT>ldcfwI~@PMAtS_xD-DR}p*Pc|5yoVq@R-{7!~xS{_ib74nT~2nzf6 z%2{)oASbaQBfr$X!6W@;MpM(fz3;yMD_!?o5&N%#(^J(lo|>_B706V*i-#TO;UtO8 zHJ&Eep=(j+WOPm(tDaCt-tx^!;M}fgkRrjd&o)5Qn2;k5Ps!mqXZac5$Q>QLD{;}# zlW5*fUB}K2hj_tdQ`;&-7|5?RJBcHKjAfWK>hDD7B<4c0{X6YuJMEVosxSmnyQ#WkoGe$a1YFQf3+PS2 zc3o1Hz(_O6Fp#R7OJZ|xYNL!)XYcvh-hb9yj~Yv<9(ca_yEon3tu(?KyZLX1Viz3% z(E0_ImI83Qa}I@0Dyr3VrlUIX*dKnmqG#1l7@JISOz;er+JM5lU_%=>9HMy zZ`Ke_8!-E7{dSZ7(`fo~t&?y(Ozliol$P_3-STQ%E8a5Q7XrfYf3|(Tsi-HH8t>b& zTHwxbM=LAB48xgMtibO!Rq8!DulUsN`^Jdcu4L$Cu(HICYzWvXZrXQ#W$g&*{~XBw z>k`=+H~+tjB?gs_+J_701_Ggo?hA)r zs15`y94RV2mm4v7dc0?#gW-w(`)A&;Sk-V_4lM1s%f8N1NxwOdebQ6e z?uH8r9R0)^CyJX~5@sSP{~z~TD0rvTPJpsxkccINA)48%-3D%uu zb5l_`GsBdF*kAusY8ptvm<{IM5f(>Agb`YhxNtNXR$h8ux_;|PW1#|((yDm+_h|SP z130pphS5q_-m%y6@1gZm6^%zZrM!;LtBaim@!+>Ro|EN1_L0^+GxQ7InI8vLzTIxh zJf&!YaVm(ykUdpO{TXgHFO0`^Tq?5N#g#6yIb2<;+r50#oVPMPn6|K8SF6XHqw~XC z?_uy zE)2HIa78#P@<6JCJ~|f<9*Xu=2h}+f!@azvEc$#p!46PdQeRV0vbZle6g=*Xc2@BU zhX%+~2xbMOVJn4~d&jICd-KIUz{{wK;*fd|FGX_B4k^3UOJ;-Mh*F2N<0EtX3SC_I zQIyHz9DGv6viC`l^_^P{vOqY{38Ux`%FN@mDWd<+%_{>?091o5r2g*#f_3Atco{GS z$pGQ7J98k_ZfORmwYx5=n#D}@J*@35B9MccRh#PiOAY+*g!MPw9K1q|7^rf8RR6Nl z>TC?w`V19AASnd>d9zCJ-X>S1{d`lQ!9R0=(Acl9%(lxD0_FwkA6h1xk^ zl_ADtd>6svb7HsY`#k6S#g09-#E49bqymkc*q9z|i=@8mJ2Y}m;ETBKNXub)WR^QE zNk8eG-m6D>I_ig0o;+Qh=hu4N@Os|%^NM?tTa%;erVDis2}z?qo=&j(-0-Q;c75Sf5lJ>6 zQ%%qnaWP-*e2z~Ny8PBu!QysnA4Gj)Y2iQ17F`+JKPHX6v|ewmy>Wy?|8&%5oueZN zbp`$}?K94yl!LANUfIk0^`Vg;7fOrl=@8il>uMkyYI!(c0cC%i5Q0Wl)O8~9_c4~W zm*R)7Zcia6E`GVi$~IhVuvvFTqm%g&MaG5iD)8YJ+Tt$I_7Cx;my(?d%A7FHx!q&; zopnzimpJK53)P#B7-?%V|c$^-zw~F?75}oUP6wsX@Iy3jfG19d?2cO7d>5ldHhj6#PAITgEm|x`f-VW z>c6y!ZND}_)LAt2un7R;m>MOZoGG(C!p>H6U#oikX!3i8m(uozCDGn}y?|_WiUG_i zMX8$(f81}srn>1Y;StiYqhdA9(?M*pOgO5V8Rs5u~%=3Ui)6x z=3oWF@?)PP%KAgyrJH5MZoUSxI38|PGDfpfMQn-nMp{E3wPFFeN7DP-u zv)A_V!;=QKjLNA@XUhy-w(Qtuwz1d-Qz&=6R-?#`{b-GF?d+dVSm6PPN?3#yp)3!( zV9;xcKV5jX8VdDn7FhQ!BMyiF#!5V(;l9b|rzSh19KXCa?Jz+bKt9O^V~XwG0c!*t zBy5%gHRfkMefMD}ME5pX>WMEhwf&REHyvl$YI=rESZDedwA+8fpIZt}8}1wY8rfY} z_T2BpF6!#?DvmV2IBx-wysO4IRWYwIL+(y#WUK%0qVu@SjI<3c2uSqIy+*Na9A;-dx zuYeEBr~<#$x1jS)gQg<zMK)=4**EVup32q!I)kc8EHyD(f9*($|#oO&vU1Gdof(nWzNbCB5 z_NI}*SWI#f|*P@4;e3D zN2>HV$_^AC0{k_ ze3xn6+1S*!dYA%`N!FR*3N;tJy%I4zkyELQKx=l#9*m z#LinuB}<2Yo_O9=JgfYPp+JH zFQN5T>hY0S3ODR0De62m4a7(@aNR!yMP-nD%ZcX=)72iic>NS0KT`HiyV?kIj2s=1 z?eW`UlThEFMn8g;eXd}BK0#DD`p2w$1ZKdK%c1)MK=nV7?&4;tzGkGXTXLb!Hj_k~ zWoF*Bq!0m<@v`UK=mev8Oy(db8y3q_ z;C>1*b^$rflG)J7bacB^9hvzzgXYzGX=w7&@FW&xiCXu^mR(7eWZ6A@F(hVI&F9<= z|FkRNXi7sG)iV2NlI^ipLqmBiodcIdfL6HFK8o2#%bb~t9h2J-gOXqh?ObYKe8q&Z z({hd)`_L8>k&$~LtMx)ZGxy?TZiaN8Xm_5iPo7?A)igN&+m1x|Wp0-6t7Akp_t`|K$b0Ss&;{*hqUPV>wCqS-N%s;G9SRo&> zgjXpfeq<#Fd?Nhf#@IL}(}^cep3B}q!*vNtfi!8`W7k-@*9;Y5eQ3B+5LmKfUyV+C z$&qTzg&LrdzbL3>5%QT6%JOzxhm0Mq6ou#vsb+@#lF=|ghe(nlx6h@HBxj91Eqkk0 zA8u3s*81{vvTC+`+91iyuvTTR<6J~NEKriHpvtV}mVFVLkND+oCtBI-+?a3m`%-b* zNRp5yqAro73~PZLF%7kbmOZ%+-x44b0k(Yk@+}rJkb5O=B23(HYxE52J6GCj!@Sqb zYBC-5)d$Q^C(8L=$P2-!zEkR4M|EyP8*pJNN0BY%aLr)E_0sZ}1izwA5M5M0%LKoJ zczmbJimw>ml1T&=%YNd?r744SS(fv4G9} z?jYWUUxHm*QFp}j{{@Q5+xA4=yqR>Z;Lx42keRH=P!1%O;}KmyngJDwP~Sv{Ul8Fb z0$&pvqU7;)6QAoFBm=xN%^eLN=EDbRaZ7yoOA)-ur!Z2jK`ATS>6Q04+u$xKT2)Q-o?^!XJJ?riiK<-ULa_-2}*~-7vn-@xR2J5%OtM< zsLYGLcGFlyXRhkVKJ;ENQu`7L;F-`T54y_<&tTbXr%SnnB^_I9`pbX*hY<3c@M3R@ z;hJ{HQ0jgONhXDM?t*s67Tx!?zznR?({99hVbmU#))O7JuN4?d=aUs8pdUEM?|kG} z3Ud9C-!K6w5rxvg;217K$VFVuPI31^2t|mQ(!Msa38LB;ben*jra+%yU^lX4>^njE z1c$GDWV|Qx72VYuCij`!|BZ#5;`MU?yUQ1lNN2iHV3I_KPVRa!Dk)caWnj$i8@`P9m~$2>FRGGe$txEjyR< zhnD!rSwrW;$#}~&!x$oBj?*8XhI~thUSxo-@k0d!xy?(j?)s=**yyvF8vI18ERvU< zBMmHy5OD%uD-rBvdp}4BzoxJEbWe|aNYC-K5!LDu>{%rvv=8N}UjhJ@LV^bRZ0~#e ze{po*VM)DzAHYEr&;WNK0^;6=8x;+lI5IRdD>EE9%G{c(0#Q+OXJ%!7agVIjtZajr zBS%YQ|T#~Ekc$Xw|_98@&h|YC^WO7beQ$bBXPHcZO<^9vfa%sv?dplGZ6?LSr z?5X{`NXX;g)}}m=yXlB8GkIW5okoXb(ji&Oxvl<^(6GYkGt#N$kW3n+p69tE0&!AG zlin}?gElgz`OJ5`{gSP&nDo*aV^ZGu+~Li$t6GjbY?448mrw_1s!z=92%9w0Q7?2i zk6%-+HQk^DTL%2J_~r|F2b)rx&DES|fNIk67tKd}Je@c0$gmbO{E|OZUPS*S5Xsf}qE2*$RQ~KkrkV2dZP`C?vIgRZ+SUoH^TjaBUH13z6Py`E zHx9Iuzhl~Iy^BQ}KPwMgrOb$!Cgh}hd9Xw@MplH=kdRTB;M1mlApx4yESG^C@wR-P3C|N6jUv%~DpU2N|;eYAt zZ?`;J$BvQcaCNYzn2YdSS2TL(pxUCWdbsX;!q*-CpfmWGH!9nswt`pa^w&d*M=a$R zyYyWD`we4}%y%PRa^N4jynhLf^gUJG<*o_Jao_WP$IU~3>X=e{$`OAQ9!)$`=|lJ) z62{zh4hY(AS^8A9UI3d=ki+;UPE^k(Zk&yO@TngvN@jVoy49gn zb1LMWD6!``qVW{5jKBXAdp}h^q{}kH@rOiv25PqVi(e?554uknA+)gcw>c$y!3XKyQGd^6>Ig06G5XA0`C zY(O~wl-p~QqxoY#6_=olzF5?au!>e!)(=Snj;7c`I@Ho>UVwR!IT4n!Q%$?(e%2_B zQgT7-z{8}y{Eh+HfsR1-KH=x4j=jr=`t#r#?zKT{VS^=@9r@^eUn3r$H9Ztk+_;;V zHDJZTH^y9Y%pRp;2e=?u9Vul~*j0%4tT=sLd?+$|WXjVIN4VN$!(%o)I_);q_UdJ< z+u%j(qMAt%WoIQSF!67)GE|{P>!q>1Vx23z&e&LI=JGA0LGsn9-A!!_zoUv+(iq_J z?nk%1@M0;MC5G`?eC00ft9O*QD>#H`d-c6jx#!$hPo0yJw=UuXYEL{~`>0VgFv=^= z{rsCnQr@y4SMUbf3%B0=LgFE(J#KHkWFK}}vnunm?4l*o3i_xqf<~AePTpW>m;1s3ho=-~ARDZaK_hF*sBjEC28lOyU^k6KY;9S1)A@G2 zsdRyJ8F`h`@Stjc?zsNL?3Kqios(a!h;?y+l+e8Ui1iX{YaQ2O`}y7ja*)fB-#mAd z_stbStdB@J-?0BJc{3$Waaq_~Kb)bk6wyA9l4-=eT;9k@x8C185dTodHaKx8)yHz8vXD`v6^LxYWb?_V zS-$=IS~16`V}?tAi*WjvXtlew(J8Nua!M1PCVI;!jgjA<&-?=SP{alf3=+3Feu)d%(?B?sBAqaM5VAb-`A!My0gyRO{X?pWbOIv zuK1<4#dwk3;szK)}!Q;QI3BRWE z*|7uWDmN*GLM@z#-fF5Pvt6lx_;#cfn=r-4d;Q>0Jv3td4Jrvwt@z@yU{Z5{p9GOs@B7tLS`y8Q zOmSd8gG`Z^Dgs}B>7=$i{<4!mxtLBh(>pW22T=Jq1IV+$c? zHU?*>fC%?=h(V|TY)_SxkYzlv%J-B)q?_NWy3(jNPGVWz@n`O-3C~}1V3}r9%*@gz zPal#FM?NCBn_U>iE;sbM`FE9M_h~E0)He`Cij7$V1{%u=F7Raz;$*J2ta*@|sPSvL$*JG`j_SyJ4N){?hgM8kw$HrjweA6j#f>uix7sOR z0Mb1-11nI}cFdZ18geEqLjC~y45Tb!$nZvC*{I{3y>A=W!seI!3I06h2j|sMz|*8DDxWPq@s z-E_VCh5rj)Z96KL^g=iiImg7L_o)Vl(Qez%GOc{%z*Oy(;*)Hi+QQV3)3PMWGeGYW z8OVwcyik@GJ^i(%b zt))xGZk1fNPme2muW!(*MQD~F>Txyf1Mge*vkv^rv|I`Da^{e?CJpB(aV5#-*J3}% zD;Xbf)_6#!AQZlDcuxI02SRv|!;CL)M!VnK?|G+w+kEf5M#sF2A$zU#6vxt-C>Yc} zoh=*I#Jkppr|dkw8x$}#uQ80glo%w3VAHv3)j`}l=pwu7gnIOEI>h2N4Sa}yM(z*O9{xa1Coc!%7K+v|O+l^Q$=@kj}Vzi(M!#6Hj)74e~tJO|_ zj|3Z5a}nzXs(F99hHUYgvH>-qs4fK)1t}m;|GqZ*_41%A4G%xj%S0HKyNTw=g({RV zk9%~Wf{Ho(2t`{GVjnsn-_IlsNQ&bqZ;gs>HgZt;kfmXdCSCJF@nI7~Oeo14enGRb z+ow$ZWzgdgZ#6_nr_0rw>Bk)-61Q4&plBvk#)vX0Yf0I5{pPfv?B%2yo!okfvguwq zlL)_XC|tp&ondHiSn5mBQkkDtG;i3+nq>2^Ykg_9LEUcc$h@gwLSPyoJ z^BVXd26*ls0>2@h^fR5MOA)-)YD=%)R%i&LDcnX`ikCD9rIXea1tzMTq`pCC*=3Zo z(tHpwn4%KeBKd%K23n$Gq}d8SqkQ`1{<{Vs>}Q?*8jPIF6#Q8&xtmNzwYD0!sE z-Kv&d5@?CaliOtEc(5l>OS$S#zM7o++Iikc&T`t6ognr7oAEw&i*{ilOAd`iO0(}m z(va{h0>qmGbUahG!@oiX%{p^OwO961_B87RK{q`C+}>~Xbf3{r z0*p#%$->Jh(ettjAUpd?wF($WK0th+kCpyPEAuo9#bu6ZGd!V~SOt@nWiqfBK2Kn! zbMp0l?niT2$Gbr2n0(dikT^V3mCis?3hqB(4o;`BJkp(&sLV7zj(unrwt5ID7bvFgA(ilM}jjskfXH0>!6_om7zqPp;fQDU!3*5`E8Vi zdzs5E%phRGH0GgY-rOB&eG)5O1kNVq@6#cJ=iS3Q;AXV;SVD_-ca8KnM>GeVoxqCL z8vH#9iQC{3M?m8KZqSw(N?P=N9RTRhpZxcDD3aeP*=*l?xkQIu`Sun3-R*pOvbv~8 z##~6cf1Z_10ngrsVv!arM|(~-wCt(6HsHxP!iS{wDWJP@`7<3%5^!fG%T|I>N2_`% zp#BIj2w6uW=~4_I0Mr2{@*znzhGhe}zWm%?pHW|^^sGU}eHSP98f2Y{=>bn!{Q{Ev zsAUaFX1HJXIVxX;510RoP}JcDoX<_AvXXGDdBuWk1^cR8E^=XL*C;E44?dQ|S+`k}eAH?t_mAx5YChX65@2<_@u*$<38_;DRZWMPpiwKXF_eW{n(-8I-t$-B6&tz^7;g zXHxZSak5Wi%Ik_at&zqvHTnm7Nd-Vh$u@&P2A|Gan1meT1CsfyxB?)3fEC);G!&|P zj4)i~j4zHEc?p1=AhC@2g}FwoY$U`4eqRR%X6%DVMp5MEDgOaLmOQYyVqM>dB>$b$ z8}bTLO@yNF);0sS@8hsC`f^b;JcDFg%y#|H#D|@2p=HY2plZimH^B|x&hnO-lf9N+ zQ=m!#Q?}%qG8hTd<+%drL?76bkM*gMP8wz<*BJIzK-M{GwIi&9`xUXY+;k2rl5&d( zZ9PhR_GQ?+z(}%g0B3Blj`Q=6MnA}8gZ~q83>_e6pC zS2q5q#c~`U`;dLwNsToXvxl+lTvPz`hhqJ4b@#)u4tDp+!{DSEwX*IfuXF}uMj?s# z+aUCo>p`sJxcn>y2z&z^qN(^kVuApZw!5&adfF$R&>}`9JV{P{9!ni>-~jKQSGQ>H zS_^P>&&kvO{v>i5l7a^zmvb{~SiV6(2X^bP1>i9#HkO(T$wQgA+JTW?6H1z z-R*!%>f{Zcbcz4q?;MtEwnb_t#H|hZZJre&;mn^&XCfhH1(-vk-Qu~5NzGcl6aIdu zpB_9>lE7yrO}pf!2Y(h7#&L92*NtoKp85TO96UDij3WQ4Vs~|{C)(lhmXT+UpLV11 zw#OHmRgvJJupVdAa+l|<#AS|~)?J5D_nkAD>V2VVU&GJqLh907Op>T>A8Sf65Eq z6!d-@QfWBfB|BG`ZY@^@sf}&Rk!p-LMD2$2O3Zw?bl zZ2cfgub18a5YO3+qv!TMZrSpHC2rGoZy1HdZoKRdVni<6;5J#Rf`DtOzTZaodoK%m zzt8UgFOcf4-f(LTB}u~Nz`o}Blq5s4FDtW~wv^^B2|SISrUP9{S>6SQl9A^{_q*M`Jx8UF9H-@acL1%CR)t zn#n~W!IrDi8gu&cveIJ1+FjOtxhoY;*?is=iFzHql%^*WG%%M%6WBMO(Lq~eZh(V= zWc<7G5+2iH8e32K6{@D^pWFcN<3r*}jBFnnB;%%P$i&vVTiZ%QXKF%oCDGlD=rms$ zH_n}XjvbNd?|p~CSqd{>Bitmb%(bKYbT|2it_)+`(*(fQ)03>DB9%8WEHWNs$(BCe z2RQ^_;sN1JH;Nu=pH3*x+k=-0q#0Tx92=gowEc?-pKo5lcqUFmh$joB^8?>ckW|Pk0#!Pam=TPO%&X&la|we*Rv9cAvC3*aTY)4SC~1uvJes zaK3SA_C)0CM+G(0Z&1taS>-aGZuyN_(caHl>B9k28^^9JFmOa|38wpJF=q~6;nWle zT1VTmTcZSzvncs${G}7s9Q|kI$xw2ip;QJDk{hn*9#b{27AMLK%(IcqSTEmNt2GI= zE|UZ#=D_FZ@YBzq9G)i6&BtE~+Uq`7yYTmLvy@cIFe@qO9FhXGrhkxqzxRUgmIEBy zxMZ+W(7VG0EKT>VTjP8SUp#62QP|`T-Mk7spV{L}Yog)e;1uw}fr!z1*{kj|+M7pe z;2*_$4|0;GS!ag*ElI52lUr@Y1u0ZkN)SX+1_E0EM*yW14i)Nr1)JZLL*n=Rl6s`7 zAUL5AEBBlgnI2x!cK0Xk&fGtt&>)BZb#_N4SdWqKbQOwuS=mBonD|Ark>A}7zmEle z-xHOZylQ6EP>QFrvVvH6cIloz+b|Mv_cqAvQ+;$zZpMaR2I1b(E{MTa)~)hmyRLqE z0LU@e2|QfVc7)_~H`Uh`+FDWy3~L*x`K$eg9ET5Lo#MQ?N&@0xZ?u0^osF>G_NwHA z`x}|wxE*_>+y2e9imX4^jeRMNTx(g3_is5moyx>9PCZbp)Y;-+bF1|3T5g}=)NQbM zhF!8;Q#zYLE+V%c zc`?wdZ=_~(&DQ49@d8NWM`@+D?TKxy<@<#?w67W|zKu>T21`C?O5}{>>Zp9R+t9x4 z+f3~hzE%7@l5Ux-mo}$}X3dDG)fe)kDpFN_$f|$0XNy?L$AA8WWvyjFuY^|9$cJ=F+xpmS15i0-!A){B$}0BS6YAs4|(#wD4pE z0L+s}g%_PWh~kriea}lm(q_Sj*>poBfSE!mJ@<9DIE82RIa!6nhyoO3Zd|ys0nrY6 zka@|fiNZCib4;UE>Lglxt|J~W_Alo&PK4awBi^)2%mI0npqAE8X#34KojGNA^+R}T z3uOe^BO1RO04hMG{(PG!CB^gX%J}~JgV4N3XR3|r@dDo(k4Cf^wmc62>Bu5eH>Tmv z6;gRRX+K}=>}pWplaSjw;-cJrKg$l{l*E+boYS3PPjP#Zw_ch*Q^hgk zljsD`&wO!s%=hNv(Y+ALBI>p1K5zXRPR`-u*OJRgGfg^~zrK!NuS)HhLe8(B2la0p zQi>Q}ChY5OfL=cS^Xct4G;^<0w)LBh$Xcxf57IADViy$SmT|4;ht6n>xJ)`^tw^1B z1A2$tPo4VSGU{PAxDPK_h5J-UdVW7GD8s_uGn#!Jzj1gW20waqk zLw3Nx4x+Ty6G=@8Ude4`;n{e>`*w<|;m_&tEiQ&BbH0vWB(U7fP0Lke>Ir2ukK+B>XOn;;$_o~g4LD4(0B;1wF> zo&L0igD=bku8-UQG3lN3axlH|e1Dc{1|dahm*WD(vc&e&wB?kxub&FS zX=RUPiH!*Aic8p2Y#B%J9U#eN{{Z}vN0jlyci}zkDx|kvjP(h*)U1FGT5m~q znYUNWQXZpNrskcw@9;f9VD;-SXcu9o>f0Cpoz^#l0?PL1oed1WG5@^rr9!ZG`jc6~&K@L=F)!ihLt0wj&Z2p7xytsSW7OIU;Dp zF4eeOU1h)oNa=&?3KBz*j3|HINENp;8<5tWsB|9oTc3vw-@UGU=D9vs`@+;VxHM`tM`&hEaDlV@{`sO~>ydhHS9b+fEOVjRYW52Zx zIezUfJ84pV^M6vrYGe6tNw=C$y(^j$W}Ryi;q+MuH`|ET`zIQ*@~28$_c1lTr{^~R zK3jGY=0cM`I<(`CUpX?jUqig?v7_O-yg2AL2yIZ{3C~e1%U*6Q|HB@)kn8nK8EYy3 zS2N`G)?86vBy;fTd0nT1^YZ;AuJCmc#H6uNet$L3(2$?M<8|VhN)BhMxDTSIuv^-) zfQJGF&V_mdIt4nbN@&#hLxa?wOzu0s0m5$iSB5IEQ))ikf~gdt z1CZx+PfX><<4U|>V?z0qfGEjS;hA1QV=}GpTHK$l-;Ad7z3}hq!_=|DTexyD_hpe}Rt^2+Kk{6N#ye_qP7!xkhc; z)lKE9-rc{9vibfRm)gkvdhd1qb~jcVT5RPGYL4!kokvUVPg0kJ@=tX5xQ0ED3g>P~ zYP4|gW^}&Z8(Qhiv|Rlgc4&suR{2wH-9$WTaQmC8{;vX#l8EDRaa|}smDC2l%w~~) zb_YmY3XPdQV}%vc-l&4_{(@ylxbaz2@3zAi{|Q+3K30!XZ_e+zo~vux+C3Q9&eX^) zKCAYe|8{2G=GMKAm1}qY3;~t4vpcOG86(`L+c_Lt@%$XU_2BTcfr$VG7=w=4>>|| zw;f|3l2brxksQB86Tgx~_B{G^d9KM-McC;y3Vfs>rS-mFU3o|EV|oF&U#fk^TRSGY&$QL>#W zK0*vjyp!oV<}XyiN;je=+L&btq@p8Lx96Uw50==-!jI7APLFhfO&$c9xZ3gFECC?f zrGO<-u;b2`+6FE9NGtB)b12?2zoc=p3O^R4>`R`qpq7*-C4?hs2Bw8m_yjlPYhsni z#+-de>lg!sxr7+9NEihLBrwr`9)PuJi6sFB=CZ_VV7&`Y#`^>{s1~Y&>=>yyCIY1X z1nElnVeXcr3mS6R+-hyF*lMQ9dsRtwNZ{~)qAd@)eGJYYWYpdwX4g(zmx*+?gAhQpTcW78s^md1JTYq{& zSB?=K2;1BDt+UiW8#}-;G^W~Eh61FgED>w!A5MJP5+H+aqPhA3omWpt=la4x$_52w zIAQKa+5(x_x#<^hGhQL^3LVl00m)NN5zrigTquC&*$HI{ph)Ulc8SMXYgagOqT|@1 z)$!N$ot*VNE=7g>F9zIw@LgitRL^@)VOxOG0N|X2W)#u$gC!u8^cPv53>6@Z&Oi;Y z)kJi<;ud)o*EJy5JLTP&wZ^twuBw&BNfAJF?1?+|ZM{{ll2AO97?BSO)A(YonUDg> z5QM<(i~O3#Cm+#2jD&nV7#Jt?l(CU!=>R`_7RdP0R@OA6D?OCZ!lD|Q%erdfz8SGD z<8ZJX;xA1>a>c7?7S@J#H~pt{r~aHY2wM(73;<+ zx1Y^)wE`IlW%$%j@`DDwo(7X@Eyz`IOT2!-1aaxdS~t8u=&!NU2p>D6J| z%DL`bZ7fFHVrA0&@tmPq_>Imp4y!zygrT!3{X~J7X-%skEH*lQ*52`>amS`M3AF`A zb#bP<;6?rT-d#=!AS5`V7tQVw4DK$^bqQ>83u)?ty|AMcT8pH%n}8gkl_q>m_v$9k zIvuZ;Ca=;k^(!tHrMF$|b-CRc(L>U)bkg3r*yJ0CMRfHO75w*T1`q_ZzFV99u)6+w z&3>PYtO`K(Z6JF#0w-wn4-F!^t_^?J- zYvaN~1pEAV?w`;-_@YAe&qX46K(~e;{Ly@9Q! zdJ*m|5x#nd16vM<=tV|GIwi@=cWD>0#YIs^^m^L7qT@o8I*Sf>$Q>%uJ9@L_Xvktr znqGJCdySaJJw^viLx9+2pkD`+y8w)@*1N%%SK6;jXz)r5T!_2Ch#G7$c`7g88Hr)! zNm|}jb&$S`jhJO%^5@AIy``h>r<09pI$WdD>!Lg(^)ZR$)Q~8%r+ON{;8xg{Ms}G) zpNqYn7i^>7p%#n@$rI;Hgne<|DE;Cjt~P8ZK%{bf({&eS9Z zqm7)?0d#oW+6(a9e*$c>RqrxeF6rbl165EMC+~L8-~+T(PjcVUo9SBLk_Yy&v6&Z= z+8DV&oPd#~7gTI7m(tSKt0HcX?_aj>4=b5%OV1(a{AgiJl5^5pJ+U8x>h&_EBHv9- zX7n;0R!2*#T{n+iY^;r8&gm4$ZBZy^2EUOe1aj?GLH5Omu~#_O13bbo+Ilt;*4giH z&&95{7SrCk^Q{gng6YIzYGqdhOaa<^d2h$G6oPr|Fc+82fQu7hUg%N1Zsyw?%iT?n zRRMD*57<~~XPmU*{Mi21Nbhs(l^?;3D{nil*qm0|%21zXVE7ERd_5S=rST-J^XhUQ z;YP!Wt~XSQd~Necm)91AkMpUP ziwsrZwp<=tkJn-^Zu$q$x&OO8euaw@kbB!=&NVFj3H5$>Z}eVLhjJ|P8QC}k=4=U& zN`Ikqu_NlHPrsR)3)e}`@h#6Hc=bjTz*gj9PyKNHfv@VUvrab?Lp13fet)cIb*Glx znRKR-sXIKy*}2QO5Wuh<8?;p!817&CLFXFbT#^;M?e3SL3|GVY0orsIyDFFFIQeZv zo?S19$Z|$5o@_2Dpy9#92bY=E}ixufZ*j6sSfN9?aN-c4* zP&sze&?^^h+%wn_FEQ5#Kn9L&FGEhNN$7CmF@0LlIfBdckYg`?OTEl7f|chGC_z{x zS{|P>nbo-#j5yl!fZ_yenwm z5nJ3g+v(4)fsKdUm=bgTtzI}`mEvW%MP5MP-sf`1=Nalb$wI)x=@vM;vWTw7M!zmM z26HXx&~?Jm=xHekPuXORxuc5tO353B0|ifRh3s(oWr5gU0JHvQB76MGZNjd@2{nZl9A5^vUP8?wpsr?B3FFVZQeRRkN zybfKo!0AMlJ_PuX|JKew;^1_khUImIcW58`nYs&}p;xsmO>5N}Wf89WHcoCzZDfO7 zDMOmn1C+jHJNHN~GuByKVVXftap~%u3-Q4t`b@*yikcN#0AIa3I=@_+s15N+=(q>& z{R+TvBmiK)N&GHF>aeGRWtmsFXY4mmSIhNBNMpp9jj|pjDbgsJVv92QP%d_HVpqG} zpRn20<(DD_u$7B)$}t)4$LT0^Cnh_5)cR0Pw-NCO2~Qkc=64XCi2`P}IoQzH-DRGR zisc9VBza(wD!>_Hv`Se6so5~&qI_H!EYe8%dq>6>J44D^6C7&N1Qi|Lvt2TUej7 zI8BK9ZV{Pg|EkTRqe#?eBi*C>eOmIgd@|+OpXdgqJ!z1cU3DNj!>rbS5WgS38~V-P z=Bqu{_Ht5W6xi0u)>i9l;6n|ViHqb=P=ubn>YeO=Q{Uc#ws!(B#D3jnMt-S>Y7Gz> zB;_~;GU2dMI^QV)3>2Nrq^mYQ|Ct`lIPjH(#5)^Mq!I=5*iEKRinBg32j$vInK`}7 zDDSV$!MN%E*1w`-9fiZv36UHca*B?UP_sc&n3~qezjYX@bHO}gMHs1+zOf@%0@MO! zBS3#%B*TM&7y~IiSdMzFp3bdiwP4`3K5%cG_&Q2j;?(BoPBZ?#SsZq9QyieHN$2RL zl9`80u|gRfCJWr@1;QIXdZX$TmjS>^0Az9AfXp;j^yr1c_AAUlQE! z^v)+l?pJT5FLIipJMaou!#GT}f^C9qSDC@R%@=k^)GprMvs=PBY&8>b`Nbg}=p$-0 z$TcN}zyh90VS?H3M2fo!8-vixP{eSKL&BPU-?(=f1jZk?Z#o3ILjOUEfYs#StU<>+ z0kSyW!R6&8{8KYK9;8%y+qx|hm!ZGFjaiYq?IcmfrEoRer3w!?os9A6ul$%>1-p7) zN(M*k*Ph}Qf!0F(?=;_S&LE1VDDObTggcH^-^V)#ZHqJEDg$1{pbPg>cli$PPhpNu zr(V#3JJblS9I7vxA{js{EeEh&=gJ*pWw*`~GM+rq9!|U(BqurR2GLSjg*%J{0)l_* z+!ht>yYH>d?y5!PkABQJ@$Gg|lO3P~c;i5S-Y1*FDH3v-Tif3J~myRE68nj)3G{Y2y13gdVVb~QVL zdS`bV`LX5b&5vB&lzyBF`#^(H;}GuM(5;lqci*WDSyCR`TQSw6Z)tfy`u4)bBAQ7Y z;q9n(F<2ha?gYJ=;1PSpJo~XdHoXlusV{f%c{`#v?fWExq~7OVkUh@Dp5#QzW9})- z)ve`GXeWuiE;hwyk~#gaa7xi?oyq_PVeI;+*Ne2ZkxOw0U{I>9NXlUVbnqe1N?=%< zDrI*Mv_1+V)`E=hg}4zw4#lp-drYgx4lVg7J2B?&hESKFX3RzR5qN&8$+U0WPKy;Q1>#mZiqDt~^p78AQVdp~@eq%aj# zG;p73Q1+%Lc{T7kvQ1&|M)nt#gFZpbDZ8^@=PFzR<3kM2du|>(daLx!owR3RIG>GO zjrQqZwFbkNI>lauj?1Dp&DkE>Qd}O zrOo#>I2*{~U(B%7hid_`=o5pC5+|mWu`~L~z$9~9_MD%NX>Q=KyER^rIsRyy<>k=x zS&QASEvMGSnfm`7rO_nDQOgYP=KLc_(7-R`&6IAoH8OvP0$ zW0H~{!wSexLs^xfQ;9>E^w@R=i}b>-RZU-*5vl4p|7);VOQ9(ALe^(4xL`SCfLw80 z1Z1&x08do3HqX{a)iu9JTvEG~09#Q1s1w$z=5IMKJb%1*L>q1T&Kv^Uf7DcU>z5x^ zLz*dH4GJNSsKZ{tt@qZh&n8dq-1{bV=Gec-(AvRX?}LsN2brP>M|+COBz`L$;>IOl_1EW z3;_dTKICI;01jGFJC7j-?b#ym5O9ZX{Z5%^Q_lDt6PcH@$q22zxY%B@ocT4TW$08w zmozq@zII6i6>jwWeD*5Ypss7kJ!*f4K0{SAeet%3wS5s`SQc3@6Lqw5bYJHKo%F5| zY|n$cKNl+_wxDRj)oy+4xi>cYFn`%1&GRRw6cPVrLw!{Ws=nQ3b*6v*wShg<;17k` zzWC+wVl1J20Tb|%VensiiuH;{{=_8YNA{h4nwGasfCtyA6?u^JkLXlw=O;_;kUarA z#kc+Hkr8U=&%J|o0Jq*M+g=bCkWnbdI=Y-O2vf514DQaU6y)4W?h67!Rj`wa>gY|G zS+f4)#G!LKR^`Q$Rp4l2(V){YkD#~Ey8@)sj-Ao)eyJX=!%#5Z9Q_8y4v6X z98|Kf>!7*n;=j`ef0=aS>~)25OB+LW{kR<}23mHrlr7ToJ?9heg(Jm$fJJ0f!&oO> z(ggKR^(vnfab*kStz?9DYygCn^spJJcRo2Eea52&QdB-3|dztF`)yyZz* znx-!L-|}GISBAVKBI!Lo%p%$=GVyGX#&^0KoK7u0Q3HphBc~lVtL39M%-rqKqmBz? zt1JN%x!Zd$+*wHMA&eY*k3V-J$D=HA0F=D3JXD*2FVsGiL5tH^ zCA`}1IcbCHhHHGz9y;0fqu_YMN<5DF4*l+|UrAh5BPQ=$Y#0w@jRRq*yrJFeob7m2 zgqMU9#W`!L9>PgOt0-Xet7Mf}1(4bZUZ$srUU)H5J8eo3VwcGx}zQz zCS=(t`UE-{w+HsX&ntnJgAfbyxy2a{)?Ga8I>%if9C|wC?|3Xo2(7~lzs|X`%vz9YDs8~}!rn5Gj4AjY{cvTN^vlc|m#sz1uC}ECDk%*) zNZzpWm+12fNFvjH3XrS5EI6IM5svoADmV2yEiTP!WA-*Z0xiJ$Z4;KmF^yq|kW&@% zNdQd?5_AajL{55liWHaxsQm4JQ8A2t1l`mHYKn|1yt!#?S=jpshwhUCR<;lZfkU1{ ziHIbcHc}GR_eykCo3bY>l}(T3O|JEQm#~VFr95o ztqW_E6Fvto*BgxSPaPpG*7YSv#W~xcnY0!=Y(3b) zUd`8C=F6UV2^!tDRkx+M~NJ^-BD|M$ZBujDt->3I=g*bRbgFp^uv5 zVO}C#Uk4hUdzpe1yOZcZ*#@W=oc?c!NN0d4WUOa7p!V27Bd1j|Ttz^a0L89E(PT*_ zhh4mm%mpXpN(IHvs|9Z;ll!PF`)M*soamEgu2;Hh8EU46=OX3?j5~;G5gW7FfXV~h0kVz-# zG|2G<7ZeJxxkHpt5=)%ZTI(-%S2_n%3c|}&(mkB|y8kj%e#ZZ(aaZyO)CPl~!@?%8 zrVMO?PK>%cCFLT3^}t%h-oz22)uvXn$i2Ua1M3ivuIJO5j5a;}sphvnGU+>9xPiqHJb*wYRY zMw+m*1l=TOpsmr@wdIQt9T0mkor7MlM^kYs{Bl(*fI701pAexe=9$^gdT?gR@>Bq5 zFK3K1`i@V=1akjw`l5qAO>Z*BYYs5CH41LHEadSOID`OV!u8KVd8g zV);*icZS4=ET~7QD1!Y-;#fsXpZ9%n(ad3mx3zTfW+*x^&n3>|)c}wf%Gp+$3;Y(nTuNOru9r=H5`>)JN+!gMMcP8yXJf+^TLyHVXq-eb>|6SXBQJioT&4^ff(LDK1J-Sa* zy$6V%1;z(y6OSE*nY)6Py*2Xx-)w~*L%g3;tT99dDd#HmyZ1npH|wz~pyN8L&X!WH zB}4vFny%bu0V3}B?+?xsKydADP>mcG=VfVDYPMv7j1aOD=uuyVl0yM!Cu1i@0{tt< zZ6Zazj~PxpxM-;{ZqhBK;!0D)iL_pi>q7M$D-ES+Q{a2#cLtimR{KoW@JT||2Ee@< zpx{vC>bftmUI&|tNni3|3gbB+HLe0+9Jbs#UCE5BRK1Aakfi)$)Ts188zx#OSGt<4 z`-+UYic=B4mR07|vqhuLUT)=H>cnd)H`6W)$a(pXyOv;|HZ>pHu>giGb?^J+DFj~&<8EDNg9T>h8mUgdW4JGXdp_`tv3Sfq8=H@^n8j!r;s=b_ zL<(Z1sSSUw6U4wS3#$l=XLN+F)6r*J+-yVFh3SlKPkkdMzgx6D`{RGqp#`|slZ-AG zDh&)+nT`{Bg{3XJ7L@|^uR_TuO7XgE7NH3Wn>x3@HDmR9KwGGl&w$mx@V_m>=$=+( zvlfv4cR85Vfyu^`R9!5ei=vU?_T5feOo+jh^O}Fu29!DdEfa&c|HIp6ZQZ%>2&xLw zmShAo7cpIoZ5)P#dBz~?Wtwlg!CRtLlYUHyvKNv_WNeA#1oubPc(Hl{JfNI%GWN^!&+dQS%8{`C% z{7p^&2Ouq_xS)?6n79pVsE8}$yfOR0?lFZpuWhU3kFdku3BwNMLY4vQQ<^$_1)=*3vN+vrCj|I>>d~Gs17x=0 zov=Wo%Asl#Zb+(4?W5a`zg^(a=EMAb*s;*)WNpbHZc~9C*3~Ztavd-K%xZ7d5sYOt zWqMprlDB7Y`#C*eAesb0eyRT?2t4-Yo0W`gV0wg0M}GABvzrmy?Z2hPn@UkG465W) z_kRqvuAm%kmSU^zwXj#J`yJZ+2bervpLDFt-tuQ!A4knXLX1h#LC9ztTmCta`}>38 zGhp1aXMJxO1T&DKR!hr?y-L9k?7Q-UyFg!#b73~>K=-O}1OBZgrQhO6U>#nid zt{ddyBy}Z|8<2Sz{A)F|FxJ>{G#YDGzgeKC_9Ho4yn7w0>}&^##25f;!#G<7!rf<& zoc!K;@>sml>O<7xOlbf z53FtQysaNg&B$HH$R3Z$ORr{P7_kZTspSEEghAVvg0=+<1yeGusL)A7IXubT4 zsu{T3AhjW(tJbf8&>KZT?tSxQ%zD)}Y)jSuQFQ0=O!$8sz<00>yIeJ5=E_}jU&EOD zKBGc&6qPh*u4)WJawmnFP(&I^D)k+6mOC<%=BUV#t3rq0e*f;@JwEU4^ZvZw&(}T` zB)1+=RLwrO642^j89N`K<^5dWSE4w8At8BR^ceTNi8^wq{d_#@#^&syKA&&GMe7s6#y~#6Ar6~qLY#j4YtQ` z0;TS`gEI3r){kohl1Uflhu*z8jJ1EVBv|P}s??-lH)Kyem#^qZG7V9Ra7Z}hd>cB- zOX@b4>I{$yy)4x$duZYCea&aq*I4Ct?ULP#{xboYmtJ_@ahKMq?ASv~cPK>e=K*CP zHhRS`YN741jgcjybo1>VGk+V&Ca<__9ae(dbuP`22Ci_y>>=N=3->GBpn(=@(T}2} z$)3OL=8f{re8BgTl`BZmZk|>Sin>p)Srh>HpCqp`XcbGpv{nuZU5Ie=he{^!^}4G_ zgj6HB_XX$heP3J?v1fE8?mSW9DByulD=p%;+a;+J0v)Iy4apl1|6)TEYwb&NF^$sa zOum}aC<+%26(kc+>r&}p_L=;;#D~ypvJI?-d zE!#C}I)9=};Zz$Wa9aOcM)%TN=@-?`x1(zkFI&%?L_y4jk7-D4z1-e7UoPp$gK^2^?hWLABvGp*K2B_&mJziqFw>?Qn(WMHtF|s8EZkgg>B_OiY7Gbw{;{hGos%gE!x}xY$l`Vo3E=>c?RAX7xq9xXz(=$A za>}2?om_f#RoJlJ){%U_H97h3k-Rj^y9F(V+y#;G@4uh5ZGS3qb;IK5wkQ8OtUK_w5`e? zq|Lue)-Cw=j&|Mu^?6NPu{x(EV~VcH{Cu7ch1nF$Z{7k|PT0YNcK|}z4{qhAl)&+Z zhu*o~ei^zQpFQXi-_45FHjg{BOT7Otz9RLUV z^AB5}oIg4A^0_YVVl=4ogQxb_pYd$jso?9*KUW&3;Dse7@zl7YY~d9w!4auD_ei$& zCr7+*vt1~7Mj*1#WcF;@#x&XD^N#|`E>jeP7JS&~Y&x4Ay?@7ZIaTkImf=!6o1{zT zMd32XPD5;Go&=Z5?Q^#r5xl8WlxZJ}g4OzIk^&CWH)HB;$UCigbg!x8TU)Rt{DL zZkOWtwbgpjY<30gESz?Z&r*72SlfxPFh+JToi3rFjxtR7_^@wvNu}1hC6z-4l>7MW zrYki-K1&NZqXiG&nlXg8K@~oOu)7l(Vp+@z+8a+(Bct?%Mw(zhD$U&p;{ZT`v`|#*t zbCPv*UKVvr)MGyHo=>2asEH2p*l3~siOC30u*%PD3C0OLCneXUg~1##JNG2YC1UH1 zg|q%SLQ($VkCO$D0-4iML#L9Lyzd9zoD_v;Td9rD(*2eXzH{81DSGEjT&Nh;4>q&x z$Xs9CaDlf(>-R4ZN_d&mp4a)(?ThS=?{|uq=WQyEoGw58^vd%T`5YC1MH^X3znz&w_)B;Y|q&r`NcZcD6i zwUMYkqhyfYFDB%ht(B*&guY6)=V9dAyr}E7m1l|BNu4z7*IEvS7K$>9e@Koi@h9H5 ze94X*n>Y4mOI~WLRNUyN2@lM|O2?uE3Jqr^zcMn^nQZ;uVcz9^QmBthGZM+@!G1K( zlzhEm9O)`&wpZJ(wPucT@IgQmGJ2k?&hug6frjIlyLQKz*;j+V1sqcKh4b2-5k4sR zt{rc>s7R4F%7WeDLg2Oqe3*SI$%N0d()4}1m6A`INEOpk9C@>&ky8z+z`xOMRlF9~ z_W*LNLnQ8ByJCXvJ=%H6ZnN$&tl{AbNksx(bsYj6|9T}oab~Mpx zl)!Rjlg7!Dg9n}>lSF}usn5X)5&z&A}9j!U0qV*gAlE)B& zehc)5UxDRXMM9)@4WNO6u87N=dF&30zVXEkm3hPFcr?HUDV_d6avFgxB!4wIS|rPV zYhGJcUJOluG^JJx>_f`|cMM+yK;j?unhiJ{KxI*L65Hg@+^X!19Ii;0ylz=#v0UqN zRd9?UxOz6hH(7fpIX6C4UX0K>=a8{iz?dZpZxat+AOpa-fK`!?$E^jKx4m8`ugWYA zg9Qshu3ueXJD)#cZMLSFU3Z^IkOYaUFPi5j)U%PxY91o+PNY5oqNOj|6VkzbQo!o; zxW>+O)_OsVV}c-RKITeO0jSo2%#+J`eCOf-*VWw8T%Gas1V^{yV(W9*zZC10-oOJ- zl=Zx~IW`6j>t14jdu|_F#qA|6hsny0qTX^)>3{izb7S+^cZ`88%sj@#2nd~kozz>T zg7K^l>5}~=-rIpJQBvjok-4~2TD-A7vFMbS>xo%XL0h?#y-2x_i%?Q%bBd(rFX>aG zwt_7iH_aJVHPzfsR(Q_x(dUL2IO8^9EbNTmGZybDzE6Bv!5UyJ>8Dax%vc* z?n{7$iG-mpt5+U5=N52zElNR(Id`an2}T{Gq`B7fs$p+lSy9k%0?w*2$v0dN4gv?p z*lK@`NC&7ScL>@ElYHj$=-)uJv-r;vMBAgh|Kg~G(0dS`aO*f9AoQ`GD!yI=B}}!x zO3(qnQjY61-ZRfB<_e!XZG<|!eDJS$GqMp$IF1e zPy8`^V#KG!DR-gjjyn+PzAoNV&eToqaYdX=QG%>^!3Qek<=Sc^x zl!rIw9$|SY!>$$)s1OvUE-fWFd(k|L2?&tj@kHGQKSy$7bX+VoLrveya`KaBr2-|b zF%$+QWFh9hL>J9Sl2oa-SSAD$dpL9zxy|?uf0*UhuDv3h<2>E1=%Q$}8@K;+UhgeU z>J!Yy0GDvn2B(9auSqc2`~9?v2S{)MJ$LubbDiO#;w}j6kV|gQo@(0{sB2g}S z4$ZpCB1z4_pwC84+Zuymu~`}x8QJuli_!Ckj0bI8jU?_RER4UToQ&tZ7e-Rb=Iz1T zje!Niui8})K#M|KOgQGqXr07grN_l=JB6z^!ud>ghA$hk0upd72Nmab$_=@)f!y*S z31qUl_WDL1C60aQv#o>?x-MV5tsWb^-)(STSoQ8fK_MOZ<7yv8;68X5V7WuNIQ2mK zU{OG;g_B<(^5QSV(mMJp)r=Ow&z=Z->l(MU5lEvbTx&-qSRrRA$bn+iN3NOK7sqWJ zs)}X%Im&UHh@8wrM1=6ddm)*?LoW(L9Di9J(6aLSiSpJvT7pAKM9%qhTR@K z_3z4eDk?tB0Z&c(F^oLj6WMvdtVhpLFiIj^PXH;qj|7V&8`{BH>&Bm%841-_n((*} zElypd$QizHFSN%t1?e?`45T}wD#B;loej9oB>)$MmdlS+@N>CHA+z; zqQM~`aCswYnk6p46ChcBKk$c9mH1_ z9L(#i3A=tUZ-E(9VjhJzM|_+>E|8Jp0mwxP!bB-rdMRIK*CTWXMP$J2du#_ALzE}A z6MMlNCUKvM`aO(#&C%CqEByi#{$ZdV0Yw`@s71il-+8Et9XMNCaxzcj`&iA z+GnBcZ=ik=Y4XRRKZa3t@p8M&+y7jzeHINYRk?ZZSE*#gwd*M;&Ev(sdBRz<2)Sd> zs>whpO|Ku+jAHcZ-y8AeEYxqZ0Xi8xfIFDmcgwI*kP#n-^|8@}Aj zr97?*ZB?oI!Iju08$_0n`}5x{%$PmGBP=I|)edQuea*bo zV~2R+243W%zTnj-xTx=pJYyQTZTODGZPdar@*f^PIV#HS6CBxref$-E_Z(uEANh}h z^efqizwfwZk%{_Dgns%d$%}&g2SCEK71aVQc?_#PUCF(}_e^LkiUnK9=6JaVMIgLBZVHJ^5-aJdYybSLM!3U15AJ>7(C6W?|y!}=N9t4K*5&% z;~%P8me6vg+JeD~0@q6-URcGZlzF}iR^vYdMEQD#-g(; z^&MI047DyblE04Uppu2+soDwd&=v~f^fN>+!0ExLFpVo@=#aVq=9AvdG{f!R2*3!lh&;|0HSx3F&B2GU*^x*{J z?^V7d$9$q79?B{PdP>?H)6tFRujQpp=lLwC(A!u-kl&JoVS%?S1ota~gNI)%u#qws zY+FaQp<$W)5(*OV7Bob>SgnN%pQIv28P5gfWbDuoCgWwxI&G>4e4BzeuxmVt7EDOj z{Y1gZAJ-XHdv(N(FPzfSc3!!F3U3!ePLPER(^SbU!Li}})(MJ099O7`7;rcpT$l&{ za}CjihLB1N+Vnt2%+VOa%8AViFG@j;@pv7JTzoh{n|s;Ny!u z)FM!**2IN#sEBtgA)Ijw&k!vkBNk60Cy9cOl+W9t1&3V|IAp>6^Fpz%qP#eIKOyAD zVR$kCrgKf(4&Pi_s&ozXx|U+2xgw&`Ol0ZfH_5aUrOk^o*{05BIFG1*BEbXK@B4 z+z7S=eUnF9*9ynvyE%=UkN1b@x?ZGs>Caaiev}nbsa5*AQ^#9yc{-_eRST`4sd%JX z*5cj}WL^>!&~z?PT$700qaKJG_57l)pvi10lN~&GU5&4CKv-Cb$Qn}Z1Lu+v16)28 zJX(?&@Pi!stW~N`64y0#K+qj+MfKV&;M1gfp@GMYM(wsXm7H$ep8?D0_+`A!^E@~4 zIOZ!MQ>{r~TIu=501-dp;w{3sx1V&NTOYUT>0*{4iFr)htSuhAgtpeAv| z>%xFfrMmM+{k}-+vzz0VqiMu(@w0w>=RbPb;on(UoN;}mp7RJdl{CE82qOIzGeTf- z2=M&WyQc{7W{KFR4)C985B>^MCo8RHjkiXRMp7*zk|I9rCaJ~!RiZu8Ui>^2d|~R8 z@0h3bpgeoxVL4}YG`$3IY^4*-7Pnu8~Tu8i;kJB3^RejHwz`HuLsfry^ZKKDZs z{DG|gY_AKMuc;#ba#Q2{ZuLH-b6s>kj{|7Xw%<5bM+BL=^PLw%p<~>H*QS2#MVo7j zu$ssN*<9&0k82y}#n)!#o$rh~&MD>0sWi-~A$8Qah`#_#Kr$$980YCWt)4S)*f4KM z`Xq;qw!#UtPy_~i`HIOxh1|BHM{|)o@Q=jwuf_0>kLKLpg{|hjdPhXQtwzTB@=?h` z(4JZK!LAktO#k(~x<6m5l%V{jFMvB8`yanV9QhjM{FML(+xnpviHK2G#5a8WB+fSG z$Rh3E44y0WcUa7nx6k%S+iroA{%GDk2=$kN3M@c)lfS48g4y?PTc{R&&l99r>SPcfP6^?J6(799(|o=RT8{shm@3jAeg8 zBggXKVP#7y;o?<*7jtOj)G*vv?O!qH*;)?C6FlD*B)E#=+c;^;aGeLmSfHH)K$ovPU=NT{aajZYr65J#dP1JAHGo ze)GcMy2gK-4M(POI~r_K+?<_w?w-)l`WW1^5%u+f z%uh4`y0yxbGQod$@WHQMdLPB)?gWN@xs#Z1XyC~^ zhWz!{kH$`*&3?n{av$-FdJYqWwCm5-?x;q;At6X&5tbsK?dP&$_xgJ7B&_s3xEtB~ zVUegrWzLuP2j-#K=?~);MC@J9+T87xdSOxEa5$OYX27%qczc?azoEicyD;+RslC*B z(+A`l_Mya%Y#WrsvZT`8e>3qRSkOn=!iNgS;yR_0R@!Z(=Y!d2tS;}3Dal-Aj6~R! ziHJa*lKw?(U=!0N#$M(qk3J~ZzZ;0}_&r?ru-lxI55+oAdYe>gN6)*y7LZ6uz8Sxs zY13SL0K^+ri`_JbW>-#u@-1_}(1zQg8^2wBnqohX`)KUXxvK>0*J~XQt-PT(sTwSM z1{1qxr-TW%H9R7Rr6|h@NS(u9dXtu=JmDMl*IiWrOJ>O5Ng$g8p;FTyGkjyMeydbP zdbfLX{lZ{X&KUm5Ds;&cv({~|{U$shd0IzIRe)>9t(Je?JEB0ya4lilew zb;Fbjxx~2S3bvm|S3TLFD34KbzAIvs_Kn#{j5uX4+BPe5lf&T%l))Gd~aLH}RUbD6?7H zeUVl?%(_)p*1!j1!i!FdB(t&Fg~CW>b5zngZ-|SV+_58yz}UK|+u3&LO+}%?Q^7Kh z@^farJ~@|@NMKEdyz~#NC)M?2$=!?|c~|lg5l67hCTx5;bV7^hYjJ?dv=q*3*OTZ& zi?*=tDz38%CYF+gf4^nRD`*NBi&Y5H*d*aH*Hqk>StYwg1+1KV8c__5P8bGbG7Lm~ zw0QZx%vAMhXvU7jra95J!#OE{Z9@V2*}+IKt6G?y?VNCnV~PYOfR4`t9mocBh#LWg z?0o}*bXk0a_1PTP`f%RD2F5h}^qYFi@7^6{{`alZbQ3m1FAb~Rz|`^PU$1OxGdOjA zoBgCh>X+s_2jymt{miuat-c)hTt3voP1kj0*R^s41TxwdMppc#m9Lc0bzcW4S+}z# zf;}^$-^^MjaVyQ1sr+#9!1B1N1*7#68v`AvFmAzIYBTPh<5yXvKKGHls5)jT3)%n= zAFkB^TIekb=PqxHnaWq#nvCVcFZJp;evPwK$REl1+4)48L$xs$OFlvfFLFI*2Q&B< zk%MQw6VSD_A}o%SzF@gwCw8D(o9101JK+^Z`y~Z17=RqJ&^tH~Uf z7)q;NaqJ0rS38uEn(y|IO`-j~^|Cq=)+3j>^%~T*`o`74z zRUP4ZyoTwpykbDCoZ;p|s(3I-=0|Ij5vLFp#@eUU#xl5`iMr2fBG;R(43Awd`a_$jwf`0S(nPqp1yEUuRxePh39#Z8Hv|1D4swbsY;@M_i^DG8cUW1d1bk zZf_7#e}Fb3WLKJ)I=H2YdzYETWKsYih)Ue;5EJ);>yp(hDMY z#b^ZpcHpi^(=yDlGZmBSY)HBlb0fHd*8TEm&E*(=^D72(<8gK?%@>s zHGAq^x5}62dAzk=58&T!dDBL#^VuWSM<3r)zq35#_iXFIP5bWRFMDUR;iHV!S!rHV zR$qMm3DJd zud3NE3_HdIa~4wKTeK|;7%=zLd!mcIP{WpQ`QikyOxTw+?DVie3?mUet-@9D(sUAnVb;gCLMbpvSZ{h*3B&`fa%MxzS^%<{349f4zRlFDf0^r$ zsg|W>v>ajnt+KH`>czuDB;?2gY-t|t+?_{3%5~RXR7c%OGct18#iJ85jXaGER*Wpw zuk~yx=iL_k9GDxkkEbcs1HZqeQ$mdiEa9^y@-c4UKqAD%Aj{(+kjLl6*FcZqlB4or z6~pO~IEWZS9>LQTsq_t&WN*~N$#xuKw7FXApcoE%d7ZEYdnJArf?ypHA*TOHKphfz zO#w(?0V!S0CiX#W%jn9I58WjW$u@Q%9Dsh<1MHCnJhh1Oz- zL|wqsVBZ=qElKHoczu5ZR!F5Mtrwa-r$@n3I}HAF?5Bqe1J3nA<6x;6z+H!Fn9qFo zg+B*N1xhc*>GjuwVw4;7+kwY%(2K6%iDNEMnm1)TD~Vj&zGd)Gm^!r z&wX!|+8J0)Hf5d7#vJ1TdcElh8T6AynZ5)~|030T7BE1eyBOac=kw~lVA{X^MIEn` zO=pOG88yIjJY}}iWTO6l2qXP$&Cp&w6{f9t23+$f9e|$ZSTbW+Wr)tDDw=QwYacxj` zgovP_i6!Y*chZS(ps~#AoQz~I1N$9USaoOqc~17#n&c>^U3hN zS04W{#;bUYLmJ@u&z3>zsl0nyjKE%ng0?CTz`yI}2J`AqGJ<{;qQrp)gaYI7&$y;sE;8rI- z=R0f)9qk7lauyrYM+Zkn@%mqs%{PNw>iDHrl;Bbof}i;#p~dh{?2 z1`@u_qn4uNBPY8h8Q|!}NA4nS`8YSJc!!P~k6mEzcdAuvC1+Dj`V<_4uGoaBpU^oXF(dv`4?v9skf1$%u zM(O2`BBXe ziSd@n>Y#zFh6wZYp3ro>mfYY=aj8)K%R6JEVgrYo``u2Dmnf6O)jk?Vvkij#N0PkU zrInADdo|ah19dxzVUB#0<7`{MQ{$x3&*OaxAMFbrgEjnZRRkt|ubuJp%&AEZEkC9; zmlnmkWxDb3c84T({e9)%dQ}6l#60LFmQcZdrE|fY||`Ns{?Ffz3Rd*QK3aBkp1J4jQ`Cmd|m!vYu|9L633;$509*xX=*F==;6V z(m!pQUC;*%c_`xJvSeErc}s%)tdbNx62 zA5%8j_v>`}JN-B#er_iIlA@j5zZJ99O1$e#fZH(}G2$tkXeEE69on3ES!Y zzpo7&3HNf=_z6>!)Q=jL(QQpRr}!xk|H&`OduVJVPNVx*41LGXB}vzX$hvh!`s7LO zsbrI5+OFW(@DN=Xt*YQK6h8Z-lTSK!6nmu*<60T#1Bun6 z5qzN3%9DrOGJ?s0Y5OeC8p9CEFd(7^dWtG>vUNb?$cLVj_V_ywpZJ|j^ZA;044l#+ zVa1Y&X7RF`2Qq2o44dYJX#jt@8Z^#T+WxVQ|pS^Y1mk7T% zw^w??Pn&jzT{}_JHRyPtE{ykze&Wa~y7}|H_S1edbzi+QR9it2SvN5-+L=6Pl55a{ z=b76z$>y2rJGXaM$o~e;u|1jj>g&p9SFo;3G9D?#_#-;>8?l z^3g)NGfiNxR$ihR7wF4@ZXJ;I!j~L-I>DvJx)#(`45h*-P z)-do{Me|h(1>2qsi2Ogs8oV%amP)_1TUxO;SFQC8|0Sd9aL}36@U=Ch+Bso=z?vKp z7>KE=KVo4&d5FlrOu#NDaObt+@tgxLw5B%F2 z^87foKeOd@CeOIXI!O0|-OwQ^D$u&^;HBd;wR`mU5D<|FZ8&Qemzf+r45bX`KhOL& zc2@nLsfQ<7*xjdGZs*B~dS_TqvJtK%fC#M27l1tmnhY~Y<&-_{8V21R0U#yCp4z$b zY4NaI?~AW2fwJO(@Gy1%$N2KBQ0RrlM_-+Dx6i=Bd+9NlVVNJ0onzp?3L}8-YYvN_ zzOR!RxKa#yVGT$(x)LnCnmQW_jjEyjCwnvEA~fh)hB&|>5y$WO-An2w-@U1HalB&S z3Bo5i`EqgS1N&s>5_%GPLtqptIwT^0g3gN}<2^r$kkb-fp^v}W!1kpMw5KYiJ~+Dn zIzn1{zApRp3{uo5FI$cZ42Qjy|8y>YK!k9_*RBxhY+s>OEG9!$TC$7eW?gq zkJ{2aN>2^-cgM}eX4rLw`TGEVQ+n$jX!Xd3(=XxH+Oq#= zfzQ(=%gPUYmli5-VW{amxz0lsgj-By%F*wpz-ELB<6-=9xnl9ZY^WuAgYOxt&H$&< zOQ?_kDL7+|Y8xNkd6l@j4oKd)*wvKy;|>tmK^l0TxCYwTfkr64rSlS%nh)msh~vEP zjMPmyyS$P7y!ls1Y;(jgai^ww=Yd#8dCXq%xKHhq0FlU_-(GnX&5g7r{AvS6Eb?Vb z>XO6!6s_K8lW;LJvr#P|Ib_sc$9T!ZXP-T#irW06KvjZGaX%IiqlaiERwfcM&VFq! z<+m{fFYccJMxA;hrdjs6j$Uuut1$5G^U30|%yRQ&|K;|vBd4?pF=aLTNf_{ju9z5X zb80*1ypgt*jz#JS{FF)37nT&g{*qBlb?eEwhC3%8#;kB2Buvbd|Bn4G*?!gL;=i_? zSIgC}Z#Fa~{ao6p?vXiq_hRC&-5+ls%v=VKhTOTT?iGTg3f_O<7bheccj~IByH7>h z!N3w;PW$U8&V=v%q+G)HUXru0z4$D|ccj0%$Yn2^#x}D`P0q1dEsH`LeUCfs;Ex9K z7Bjsc(U3;Vd2;foER0^Rk&VBu3n6}6EX#PM{#{PM_j-1Y@mtoq3!LeD>vYCi^pZ0^ z;BbVM;VSv855cd6?Idhhzn*Qn#@X;eRK!`@`v*;VDBt`(UHHy8cfZ$%o1SYig-!XU z*iO^Wd@rw@_#vWb$e8dW&CcY9!Py+cMHX#JM~&J8#;s*bx+tj#>HpTI;-`5`kq zWn;LxB$`?2f>#cH;s_W34zHBobB#8%*tX`Qnd&G2vM;=RMm(=->;2Z=>aKA*>_*%lAJHs>DIR89ly zY)^w<8c+6Wqh8c+2d$WRdqumLP4pgeT<^|F7&7bDFZ2}geNs8J)oJ!$uA!YmzJ<=; zHt-`+&AftKlav>>*)7$dDv^5aS}(}+Tc;K;MKU>CD5H~5*off3iaeI#ZZDFRmp84V zD1()-xqCwQk;MQhYW?Iw@(UwW6y83wxQ0gse*Kt^q6f{ zpe_SWOVhaRAJ_Hd@zHFx2bEF{)5-b%Dk;(TwNDwm89|-zU5<<;+n5zZ9PRuIhBUG0 zrYy~yn2aEqAGTKhdQI7%<2%(>w5<@+BDt3dK}S&S?S^}@IY*q)VFsZPA<>^M+i7jMayo+rTRAz1su8U zkqEcc!;t*c*Td~%Z%fj3t2E*E{V<|IYo~TY03w8wg7mNhp_P-f&pHNS5?Vn9?L?w3 zS*}dvDc|8u$~`fwF_HZe<-;rF=cYQN0;(n^t+g+H`aI*Ki2(`o8i~>16xoTgle0Lj3 zXI)CJ&{sz#%K}zLZ0yrp3AIHE8Og4JVyPm<V?z&>Ys@t|9 zBq~0m=2)fV5DtdA{pO~c?}4YkBh>6<0??iOxCVjcwZ^|>_-y;X@S0)am(Qcw(!3$KGjcu1iM;=*NQKHSV#np$s8Zl_|LQ)pQcuS zP-+avmTWMu+;i_){}(4x5nmnHH=75q z^H#>CyhquF|02?@AgN+QdTggh=J@?i;B}FZ5`#D_8 zIV3;l8LvzxPAw=bg&`C@G=!U!EE!ci}nBnO4uq-xOrK9iB(fWg-_u zCm8P0uPF%f@p7#9rfhi5>UFx~f@LDcpx{7b9LHE@Dzo+l=0H^Sq{AZPjDZm*XZ!xi z{v~icXN0??Nnc*(J8|jO&DNh<>3}ls&xEOV)Ul&eQ!hWM{chs?ydIRaFEq28GcW`)laAWb(%b3R`8So`_S6EQ$~b2k-Iwy{HFh5*6+El!k`8n zK()(cdB^PvgJ*~aN``mo!U3h-4v)djn{2`tt-FT(kL|Wf=chXkUzGaA)I?ogkzf3B z$VT~@)7I%asj1ofanGWV>-UXKzPaBu8n1hO@bn3jx<8g)Z)}#;j8iY-65Lk_B|PsB?p&y-1f)SgpfFqy`-qI9@h7& z2NCd;vN$Y*vmJYBH#!SI|btbv3CXXJ!noCu^MuvC%#D8ta)en7G8sq+&$!*o1B8B$pz}I((tKWUyy2q%e)K?`eHa%=rt5ZjnW-hUxB<7j#)~AqjOkNO7I;3kLLT=_TC&DYimSq4 zxM!+5^~BbQOLZJ=-}DKXA1QW_nSwf2oEG5%OaZFzfR642;B75_lW5R}u&uC`?Vkj=rVi5Jaon-1u(|EzZv_R8f zRJnBBaSVr{_(1n8ks%6htF|5T;-BrboU2p84x4kSwerRQlA zRCSwl_+ZKMn*M|0p`fD*^9aE%g{%c{lMWm}5ts(lI~Sy9nj+o$St+I1;EjdqqPcLr z+(MU}3YWw;ImfD|>aMVlG{|u;*g9IXjaf8f(^-if4l-q? z_*i80Kb;X=0-JC^0+QL~eymnnBAYWSv~eFs9m?64`G4IoKMuF=dgkK+-`5LH(b7F##9Dt(M95ez=vKmx}g)skRg zufGt2*|+^*9;x7r{(j>mnq;bMKtowcUWWxVLAf1zG8SVI*drUn*YX_`+qn39H z4tn+*dbVct6F19Gj3(;Ed*RCSTMmWR9i%(w zJWBW2kC2Dchi#1(z=mPVo^73_Pr!SQKEfr*#w%d0Hf6Pk$rs=$MhxK$)wDxgpfmx* z`#ehv*~%sHP|D_W9yMq96MsVSXEOKMuJvj7uCO?;cQ*h_Wv{!Y@(H^N$I*8C?TT#& zRTaLZax)dnz)@uW8>(Ga36@oQLZ;E+nuCV|D`1?UEStUiBzq7YAXR$e>{(0i)qfbb8 z2WbSnU~sD-VH#}6BX4Vx52=IKh~U*!C#ETl5NG+Yo>ciBslUiJTxiD`tl^YX4*5)6 z9RsKglm7Fuz%BsQhUJZi+cQ(0R`IJ75L!(R<`EeKZl}S8=+|ZToG-+{ zWU`)P87jyBmf!mRFZ_>N7$X9F7TnrnTp-j~oEz%6o zkK(xg_FU|S78BwM=HaE^tEbXdzk8N_|I-B!m}KL(71rk(){a5Hw_xcNC7*=xdowaI zou9;q=kcM$%vz0&?h-({C4vex;#*O|-jb{*bsVen-@dqk`~rDax95jnFUAOT+<6cA zo_76+K+#&K7IT09VMFX1gNZcYGY*!2nG)%NoaM{yzU4$zgdT%e5H@ zxGk9UR&v%%f%Z}LtchhsAaAj}hCOf8AUBr0_mf|-lV(ywQd%^}=2<*%Bkj5Qml_rw z)nRL`TPUw!ZttdPsFSqUJ8;n{w?%4G#mo&(SO~8K>FBWe4xCsvnb5K&Y43mz*UX*r z0;;TcsD1!pY}utJoGsxg>NuJ8wxg+YA||w{B1T^ka6$U?)@b7P*d(%!ELwz+(xy3 z?P{L&zEW=_em+^F4^Xwd=572e15|=>VzsrYMxzDzQ=&gDuS;S&%TR z3M|m!l{ezi7OEv6l~fC5SBABxxl+9a7ClGMASn}$R{RskFhH7?G#wmRoeT7C5mQaI z5HCqq`9rdopK!>Cl18(&SfGRGK>U7sQ>uks6IhW2_{i7CJIqE3p()p$gcrDper#`!H)InvMbZm$2vD7)#VT^1ZvopTWoOV;2e2kKNY+m?{fAfvqF;Q_&!Z zG{%zWSm=q;)EARA1ih3QDH5LM%2iL)VR}doP#q1{p+3>@y&uS$G)U^rw+b ztJtb}AXNqr6z$zc|4^(E#Wz^Ekz}ryhe^FIao&33QV2@)pdYRW;r__DNBy`qOO<4H z;KTGZ94tax?37AC>gzDQXpm}E%3;rW_f&J9iR|eT<7IYRg1Dg#s~37_F0NLOCV2%o zfR9fkOFLLvQI2LUwyUPr;oJMex)fGrO25fw5)1KG1)dvgfi%+g`f$DIY zcGbATdKih)?p$i2oM)lbyYboJ>CvR^0Mx>!_^=Cu28l&#W(e;a;z-T_tw&l5I-x{c z&x0=`-==vA>hVfLC|jq5Zy?J~pCU)En0tJ#ryXyjgn8mPJ7iMdxA0U#UW|Wul@v;O z@EJX(Q&jci58HTQ__j!|U^F{8m}UZ#HmxDiMA2w8sEA~`x>Fd%aG_g4!=Pa0O>hFMIe6_{W=1XKsu&mep7ocYb)Xj)Gw*2YG&*6Ie3Y9 z>U5Icwi=OKNH4AyOH_f)6iC|S>W%+Vbl+h~y=@%8L8gifSD=Wv5=VwB&D3zu49y&6 z2JW;B&4Ht0sJLgtObbV4%g7cje>ifcSz1|{;Wjf@Lo17y_uq4I{&}wFJQwFa_x<@Y zoEB=@?MDqIXj@Y+4)B@V#?3bXeICYz&)Mvd^|a-yRViq&wbU*NbTnJx$GP^YWzfzA zu57T(kvA;k$_~9sCp+60c88~5&b8ZQ`q+z|wk3gfRu{j)yOlPAl=rpm-&)a{lx4Tv zR;@?RxdpWm#rrg{6meC1rB4EA0!z13INX*Guedb=w*HcGUrzBbMeG`L5BT zgJh!T!m^Vc17te_+Vh5DPAUy?-)1pYY<|}mX?tlT3jTP_X zzA&o%D^>bc@%Y!Ko(~VU9&AZzWZ*Y=?W&J6eiLS{>klAHxgOUT=g*c*+NXS4c)F)! zl86lcy7+YxW=goH?O{AYQ+^@s@BBG>&NSwB?zx1Y)??4zO4K)9P|XOf;@t{H6nHQh zUtnAJl~dQ|ldmz+aE;Vojb+wBSp|a<9&LXFIZFWe~LWqQ%YP?WsREa7i&QnGdV`qL(xuCN5P*?T~L*eRp!9_maBj z(aIyy!bXJ5N`Hi$-Jpu$wj02(7hN z#NkqTjU55GKv?wr!>%(Q7p`yJYWb?iwFv7s=z1}^jrLrYFxUgDrWpHz3$e_~B|a*{ z$q?~S1eD3`V0LqBGKCL)yFPLDch;xBF>tHNSg7sNt7Kp!2pJOw`qhc7UIoYB`IQp1 zX8f4e?hENn9*3(k$7CZQuBQsFC}Brqq%rL@5nC~3EMc~$)-SL1LBo4C>SD@3!qM&f z?|Lc`ODSvd`4queM&cmhvzSrMVeDDHNa{T%$~vsu5HhNN_+0z z<{1Y@UM*-yu${R7!FV$5bCYfpxxd;7y91sRcj5SKLyRB4SO3UI)7k3l&EAsE|FlKq zuQjl^(uj}80-p5gKfnCWJLE#!JJ`_B%vD}>O{eYbyO`;7KQ)-tgr*!HAGO(wx-^Eg zE12(a_FC3rnVXUzjT%w2^HVL)NpgRJQQVPM*GAY-%S4L5e0e78su(fX}wjh@mZRnm!_@; zn=eGERhwxXi+Bdp=rzg!6AT_&!Uzi|oO63t`5O;ZEpJqN~L#reuXB@+XVB1>>Q`)(=LNY+MdlY76jH=)uH>|v_Z>t-#dYl1p~&eD3~rQm0(d<-B1 zqtL)Mi!Y16DUs=PooEq}7Ttww-_ikfC>q~ zXK5q>6bVQOYJZlNY?9D5ZJ44-$mAOLHDWg9CX~l^NAuQjd&=5cK^Fk*{9ntR_0{NH zBMKafNJM8b{6V45>vLa-A=@ofkm1uLkMG;zn}+qvm6P0D3SU;*EYP1ag*qCe@Q&a) z(A5W(Y>hN+AfXzAFga|jIYIGLi%cobcpi?MHElO54v<{h-Q%eFD+r1Rpn`%sK$>rZ zS~EG8wVv;}_=ZZb-U1aoQkt!(JLgQb&f@fqhU40&WQfo**nWHjHQUT-M^2)`4u2q` zmG+^`=3)B{6*~TJj2qEUz#%7vA4bjVHqL9I(mFtDXDYLF8|toQSl7c}jZm#clzirB zxSA1wqhXvSHA*_ia)=QdbDhfj%?J)-ARcpIV>KRqX}FRTC~cw zzsKxJ5l1382_+}24ddwII8x9z#H-6mMjk|Ik6k>BHerld})|$1febD6c_# z9gd0y>q9~SUG`%M7akwJ>2PM`uw!?7u}@{KTpGE{ZcIzIQreU})!MnMfF3=!KXFJkwvkT>DiT>eP{NIuRRbu@?&t~)#Y`h$L;AEP>I@g9x}B8u}jype3;c35CF0E~CP5&pFh zh=@55hb5}*e9KTG#w&wDOCwbXi8@DDNBFQZ<(;(*Si4XCWo;U+Z1cTbb<}FN@>j%` zbcTlgazaV2xLxC$BraN8vSFj(&DC5JfMvUDODJnOu=|&P?4&Vns6y&e#~QsAIZ1o> zukw}NSLWbWQ?<;FhF6AF4LUv)=zC9!6`yh;vQ4%x=zP}NA^F-t?xv?5t^6APwLN73uXPGk zwn&}89j_L|oGlzXn zS^!iyj&~Nc4ajcC@H#D&E|V~p%1@AL%CpzYEM*%Y!Z2D_B>pYaZ=yJ1ai*B^^La=t zC1#-uL5zBVjZ!%b{}a3u5i zi7oBr03~lNwEYY*Q(tT5%snAfY;Km{%Zj9HOj%u3RIo@SPg*XNF4B@aZQmH_LnI- z9t=|+H!P)BGV7rcU1#ugJXzhr52rP*ZAsHwszhw{AfRsa|!vx0h{fMKcnS62Wo->Rmy8|F~x-WR>i^W zi-$`gCv|ozKD!F2P36!b&Q#6jamO6C^o1GUpr!Uii+TzP&AqwE)PfAtG&Z!1++!C2 zMrz+3G)8GZ{?#5U%=&$8rgmeNE7Tz`(|)W+9Qe1`D88iK(ycR~g_TZK1OOnJkS#Lf z8jIt&_ykB|nfiD7>&tDci{tp-LEz1$(``W2%{q`(NtfLCE9A1XdN<0z8T@nXx|wbX ze)O{0W*{kLtHCRv<_O((5ct86p@QvHr5)phR;fNw4vVPF@xi^7WJlK ze0ANn?`oj^gGYrz(dQ=)U49gz*&WI?THg#Cf4EjIkYeHD_F;j(p;oWI2S_?wtDaQ{ z48HYLyY$$c=om?`#G25!TdNd%>p~DCi%NIuz5rN``FN`MW&j0r7>L9To6u;ueYvvXGOAz3@ud!!CV(kjyamO9jV_`b zsM`y?M@JTMYR3pMZG^$`MMt;-rW>vxVc>eplym6#kogEnyf0{tFHaIpFwS*H+_Jb^{<}LeEDs}S5mvPt(jApp zGDmX@Um9M2-$>W=QGi3osl&CJ?c?gCJdMJ-%CTC_@4!8#r=Q40*cbXvFWgRU2F0AH zANdJ)a}WCi_fnFf~6~V$t1OnSE$U|XyO1kyb*R?b) z*xBhd47%?o=qH^%XBh}$=Q&nQ_l zG>=p>xhJ!UaN>^rD(KHL5&Fh_E-Fg1nf@#EI)Mpx()sPj#5Y(zbk9-7*f}UG31N`dVYT6-T{e&Z68DLBPLWHBvS&%M2;1-J(C}P@_(h zm?FhfIvNBOd@f0&dGlt)&bWM~$TNNOi>(>eK=k3I|9Z0t1KH-CQ$NB`ZZFs|gOPRV z(QC`?wOQJMGt1gOaT=qq*8geYrBEpUhG_`qcQ4zMcOBY1oYf|FHF83|(N)_cmRh>F?VSE{ zKeTWDHx!@apfDqV-Y?N8COLf6MUm=bIbl?S=_&2}h3|a#yWD-hK-+Hb-5)nZcu&Xv zTEWk25z-A^0*9XwCNcR_hx*6WOz5V}9L3)j-)!pTiw+yHi0Y4y;2j-MrL`*)bd@)8 z7Ukc2bG`%|+k5gp+yBH}&+8)O${>!w@%oEKKRd-SvhG{HN?5Pe+$Pj4yr-Gd>iU&$ z`cc`fTv~tf4Y0iJrEk642?Nuu-F@=d`)g9(1X0nE@9O}&#*Pox`cm&UL+v?H(d?>E_BZ;LV($qeSVecI?#>e&0P&% zzlHdLTD7(gtOA!bsP%7{PAX`g{RbqFT0;s3R2N{VSeo4tEyL+I;b}z5bDf2K1_x5> zpqW~vh;h|ciiUl3VA$S()}<(5YS*$z<9jWRN=$z%XY)+2L^}DjAaiKz_pKH4#zFe( zZzQ$5wZaI3*82=1^)pbDv+k#KI&P~recl17!G&3jtB;K9eg|rf(Q)tyVMj#}vd45Z z#WEPB(OXy{?v7_4(;uYo90b+{>igdUT5~I6WYo5zH*FunMv&=*kr`Y!ZtH0F%i>`h z)6|2ncJKJ%pl-8v>QbcO+Y8eyL3r==|M+FvuA`2 zoc4m2vZNq$zp~p8vDz@Oav@DUR%PcLL>X9V^;Dow`%QRM3qP#ulRt&u{GAJy1S!;4 zC^v&~gYQjm3_pjqs^15q7$S0Pf!h}B{prHvx?#9nATD100SM?m$KUnI0_xtXxSQ$Y zYi%9CG~CCWW9n;i=;<~>$mWXgo7=kn*c*dLy+E{c7^H5Jp3$TiDya+OZvSI;#NU#w*X3J2icOLNG%o;89mmFGmqeLwwp^vV zy?fYLU3(xAb>XGs$>pus7PjSTEly_7frW8(;p4{@KvhE+J>;44`k7DhyA<5DaIa3K zwL)Pxpy%Ds|L|9e-+wH=2Z^$IpE>4Ylgqvv&exq~&wB3vPbV!`?i+*arSYzo{-cm3BPac&%2Ab}UJ) zBwdAlgtESq{KS)hHh--CfY-|Cj~3iqZVs2Ou@+XSxTB7KCo7Um+|m3w@X%KWLK03Z z>81wMIqCbKdtPJ(oi$V12w~l1N=F`?<~V&}*MD1Qi%;6!k0T7k@^^)hOqHl03joXn zu6Qt7afOTJoELunZoiN#{z8r^)6 zE5AxyD(kbdaCI}VEM?~noQ7nZTWF@dh%$cyGq`g+QnLA!Yo?>8txiTJdQ^*$(~cvV zXbR~2I2%@r$){YJPQ~F*@BKA*u`C&20KjN(%O55FnAAXQ?z#N}874CL+S*gL9m3?J zTKDK|g5$r>Xm+q|v6tf*;oC>(OW{8T8|cqZMs|(Tf~u~EUWb<6c=q(yg&Mta!{)GL z!nk)cFvgEIl&-S*8XvhVA~D2ojOn(|fy8UNz`EIwPovdn9l5t1xll!k_P=(vL8zU- zrEcs-*Rx^`vWs-+k8VV;KVoXpCOWfJLm;Y$tNK>NOFKT*(yE67O~Re=RWt9rpibJw zZqS#t?Xy0Z;v$c0{64oP_wq``3RX|O8|s3@(DYW$2iSn&n_LeD<3k{FDj3_h@LGNi zc~Ge9vh9t?e~Hk1D*EKUy42mOw7Vg1J`de@oRDMu9+2HgeTF2ITGEEek!ZYk9{AI{ zKk7;_owio0bIACYP&<#^ma3-Q_)q55(d@zC2U~-~i#(o-ukL|#x1AiCe>a(I?NMGc zUELM(@`fIPfQd^gKX2H%ko0RY^lxB$xkrR0gH(04q_IQoH~s8}t{!ylr-tn>vVHl7gwlg`;koS z$SMDTL(`{&qOQJ_>z>;4!cbS)w?poJjJX2a{3dsI*4T=`(OU9+sAs3o@S)inCTFC` zex6}UK(tROmF#h0nX1?*eXeY?T<=zbr`3Ev-7iOeCU)KN^M(^&$%V!9QNfMVIxXIf z_<=7pj$OrM|LFKuWcM{>Q$-DHM(2f&W*b!@pUJ#3DK|PL?chq08PBo#)}gf9(6Ujj zti~Xs{)G))d40EHY~yW51qwD0WW6q`*RDyPp!Mun>24n&Qbu|vEjThV+)7e+;tM;h zbcHYYs96kf02g&8GCh{bK9UHDNct6Tb?Q#PT*^R0vHhUM`PrQ|t?4L3-4H+2j_=g- z&NYy4tct`2z6f-@x=O0DzNLgjBPNzlZMvp7o!74WZB)s-(pDrYiaQhGAFXhIc4w8F&V^g3#LQRu54+x1+Xj~Q3Lt9X~DpQ~H2ogcnk9~5y; z1&esMAZ_`*Rng?DP%)f5pz@Z2H_NXpr`?;>i#B*Cr|W-jwF1W3Ev9lA9> z$j!EDWd|{ag|{sWDV`G}GcBAzHZpC@=PuY#z!vC7A?!c(WBB)-Trh7P3R8*$s^OT@foB4eJUdwSb& zZHR^m!Be8V2jfmDQgiXq&bD!Do@uQ%=x=nj>djXh<)4dxO@q7>@~Rs;xDI!n2&+t( zo->vkDXu4+2?~?b&PGL0sa_()Wik&}sV3b;^MhGx&j)2wzt?NHs^wb6e=edFDyn^J z86y&l<5c>PUq$+ML3Goj zW&^S>s{-y7niVBG>!>jKPWnOzY*NU$Vah9?ZC}QVyB~fz)Vq?S-iFR`XmD~qYtbmF zsdGf)qCoX2(%AS9BX_Ot>8ix8!wiP$B^kEQWs}OW&ph+3@XU70Wqya8+^e%kgPzHb zgk@<1TIHwFAao%XyeVIiRcpH6(Rm-zxF|+LkoTglO#YB(c-0WU6L}R< z7aQ33{!IXyOB1&fMjAoBpnWBowoXwYL_^<)EMA^vyKD&Yu+`^?XAyIgn*H6X8qJTY z4vm`Ox!nO|=SiepF5{rOX~4S{t+v_I?Uo;eS?bEB3K0Q)+vgiG#?J-MeFTfr|1La4 z{q6l$!!I;J7M?C9&BE#_Ey9{RPfr*JJyID>?z*zMM6hfz@;OcW#XnE9gBu>S@Y?*qcAoZQKYqj?DA*R*k$)n>+Jh`=hpF(|0-H z9!C>wMeTjUm!aZHhbDF@#4d*u=+ZE7ET3K&ZcHjYhmFvv#~ag;pUwiIae9y)i)HSTxc;2$>$Vs54@J}~ zzNX>6Rzi)wi*vkaPK2K{82dsOoGCUZoGmRkO|?bZqE%4SxzYFYJQfqr|MB#ISKH0J zEDn6Hqd6#Qed(@siutIWs9kf<@99ICqYL%BPpakEcW=k+5)2WRg%1)hU_pXTmg|po zX*50XQ`&~po;1@TyE0 z!-3O!sLWoc;FTbkPa*e9D&HAECr5bOeX{Sgaa7`6JxmAOo3A z-DM@r`&wl8105@C2M4|-eq~v&GL9xXV5OmG*l^ip7HV;L3q{%Fjxq*3 zj{H@sa7$GQcb|UxhrMPeN=&vt>VSCAvFE50GNg2q#Bv$2&O*H@#b~&z1k#+_iB1iy zM5Q`21HPdz#R7P%13Hk%=<3)Kb$sHIX^ z@UU!d`$5@y*yGEYy=ABov6AU>vT8Xad{!rFO_{=i@p7HDo@v-%V~3)YUr|qf7iBGg zk1G8@a3&J>Hf#N`ii2N*Cc;r`Z?i5vQ^2jpCDKvt^vP4DE}W#o>ZMV~|pKUm1@ zDX=X-zFRRt{u#2FX8K<$)ipu(SqxIq%*Ze>@QALSZY%O%uC?1+g_NtrQT&K>i#=q__pW2co3N=4y_o8%*9F z2)a*AS!N|I3C{L%v?Q|Gc!;I>nlAFIU)ty?jT_RCsfWmZ0dkchyDJbRU^%lHm8pK9 z>!ro9wx4!$JlP0h<(xw3=Iwqzg&bn+fk#5e09FU|HZ2PjQcsav1;}>|Rr55t zug^fI#L|k7Y=5LXmx@&Nt+9Q0+?6gX9+Gkr2m6(1J73CT4rzTIMBF-6uw4=9)+Gl% zMQ6w&-?r)8w?Or~>sgk{oybGRFWY;>pho$Qd;CbB#969sWui&XZ?sIZFZlx*6of%JU9e83P7p7H~c8z zynKlKMMU;is9-ewLvux$F|9Qh1o(~iiivov|t zDy60d7{(I(M1~>V9R{Jb=eZPKPq~>kd0J|ZDZ)x%@;^yYls>|RD^-H`&yMipcNwd4yo%YhQ=sW*l=LiDTsEy>|Ox$^>3;*8hT26vz;OrMNGUa zn`t@@l?~ex1Pr9nV9ETOFQjEHntaFd&C4v9jpKRP1ST21f3wT^;nnP@+tUx4J zg%(&w>4#8ZgcW1cR!}TazJD3h}VDQSVBr3#ua{KFj`hkGvAC>o_C?<7&0$87XuSHXHwtleJUCAE5^K=OK3AKeNH7fBGQi>bish2%%HGvDK!6&JCjBL%S)|L@ zK|reOxB!|DCT#I5LrpXId+Jn(ajL zE`0xe#g`aDS*zOUe?He+2^%6?8Z^ZV@q~P^d=f92Ek(_g)=+QX1)f*Y@P+ODsT9J8 z7skmw?YngdbH{xD9jiaK`Eh~{fn4$9x>!SEPCnJ86m}JjxLok)O*vh)IePBrE!2Ls zDE>p3I^udMOqQz>U)uWnJf*GdeorMhg?0PJpsZ%AOHcwNqVMiQCFpfVv%z^eI^#m? zqpnO_qvgk%QT}%g9uWV$v?~45Y}0n@?W-+!^GsQVAfBuWg~*LDN9R8`7^y|OnxEIP z()(D~P1ugUT|l)KpsVoL@4nmeQM>zZufcmI)pL75pD|e7`rf-LC$HR>Y4fW=3 zZ_zeY3~22ZwSrjVr*Bo8+xXob;HZ)l4B_{BB|){l9fiFw3iVGYRg_)ds_xKjI%rjA z99CCYIeDY}c2)Q9iGKMNo3eubM(;k%V+><&?-gUE&dgpTIiV#(;SVh(eYC&x$-vUW zb8YsE6}J~{g(~AuY;CE7I&7WOBgj9ZkN`hx?lN*Y>SCqyi_zx6m$rlVy$R>fq5LEC z>Tc|eW)E!cC;nJ?PO4G4xS{kx%`jNe_weP4dve$ko`-zOx;Iq80Z>WQjNh;}hE}fhP87TjC;~~E5j}j{7OkQ_GQY2C!{e zK8_Us9Vyj#S8n(2)PZ;VCh+2ARCq4E*I1s zf47&2Tr5@K{(gUdSG*+)vBW}NO#cwW;lEJ@d@TRtmm?oPKmGXX zrpg$le68;Iy&}D@8a_)OKmFVF?!ek78GA7}R17WFGdwP)e0;5r0d)_enpTkGG}&J_ zi_X}JWt+tJkB>|2lpKZep9P3P1Mg!u$0eIjOa#c3kXj~;$0khvP4p>%E2s*s4A}$0 zH;q&HI7{*4UG~%dq4C;fgq#D@ z`&y<$#->C6P16W7VfHf-p)*k@W@0YP#J0>F9-E2(H`6{0IY5N?QM?mPW;+@n`xvvS zO|#JsvnPsGk_Kkkq4DWHv!=kg^p?47f_J*fEH8AHVgK2A?74CA)U6|*mu`Np82Id2 z{P|S;hZp)Uu9ky+$>3ajZ(qjz0l>Wf>Rjd+q^Jp#|8LfhGPe)?qD}d8o(ZIIU@om? zwz&y%wPnnqz3;#I&*cijqNkeG2c{&u7du}ZH$BImY(EA5W4bk{4ClCI_{{*j``?2L zO$(*hM_}0?qvfv;{`Tede5^ll>$#8j!dTbTg^3?X?{6*BseArgt7PJ~G8^^%YPbpSx^zZG@npiSCKem38E|dw<}=rTc^beYf5N zZlx+*W$6T7q{IpkLuiHBB2~#=G$K_~;U)RU!HX*0fVBj>Ah%FGpQR=LL-MaFJKnqh zT>aO#Z}(Ev(WNE(#3q7w-o=HL;`Q^l))(7)p0_N0$o%Rlkgp1jYtB8Yj& z?{okCZrHk<>^Q4l3acl}#fevf9hV&h@Op;4G8(c~@_{Ch&dkELf&g;Jkh-_tM@*ynRyTwV~6xlIoC-%9Sw3V%e<|-S>BY5@OYN zTv%v)DeHO4@|uv28| zm8fl*uzp(-Qgklh>MHg-@?ZKI(R;(U9rFH1F;jUB1 zeSB=IEF8VMEr2f(kNB!vK#w;T%>>QLTSSkS2flQqZZZu62ymuhKCDlV3qYHSOV^6j zr5O8rU#I-IvCcBdpCX6Ba+KE@N&@O)Cmz@d1jG!2<&^CK`QKVtAf@iy7f&&&+ga8Z znH3zKOiDK`%U7b9TUWq2u|s?s^HV4Mza8Fy$()6V_HOaW%lwpy=wzu2&@S^chJN~*M;839!ObuG zUQr_Cn>$g$yn8b^qnkk)K*V^<>7XNF;RXs zH|hJh>+bEdr@p$7abJy_^V{C(SL-6e&3j%r%kSxZOoSxfA9C(j_TP;$x_!&XYtq77 zv&1%6_^C1I)a^pXpmSAhwQK`CNVDd~8=nec*tyszg$A#mQ6i~wldcJ@d&otke<@l%qft2+cC|RY9f)#>&x>!9+gcbVqhQXYjlsG}S}=?(r@upM zpAaIaMqm=#eBq|`@QVz%{)N;rc9&~Snva{p`GZBn{SmJmW^wpayXIa|&k2*Su=0|7{%NTUABbI1EK*Jq>W-^G)s{{!+0@SJy{RzD-a#W zf6;eCW6-h?X9vVy%5G&ptSmT-2$m7m0lX)4#y#jDSC*FUHLMI`eH^68M?H`>JV-1_ zVd!*s7rTX*2wQ|BCY?2LkR{-hFVi3=v)J@7flQ}H1Jp>|dypZJ!FK##aAF5;U_ty2 zK0L!%*Rd@yOL`Sv_R!+mEP<#^ac)z%6$ z=;)&9*#j%#3MTKA4*u;hIWY{V8crIBT*bh78`B=^t5(NzL6DJ+a;rVrUPZ=cWfA)$ zcVB)raFGOtm#Hg{K6%)e6cm5>3rK%lXkF!^rCW0ruZu1=yXtvBa-?iTc~8Bej$tEv zo>}D;?AkZ=p!H_Hf9Fu+mSEl<_m8Jyj3SliU2%5&C@Ax;ypMD}WmFl_L{mEjl*#QU z5yR|rvOpOmi*fZvY{`|HYaCq*43tc*Q>uZxXym8{c+=`|LxOBQa;>b#l&Nfdr4eBu z6?5B%qb)LWM-LC?`e5nkOtedwega6B{*_$g4N7nyhizSwEz$rx0F-7>CzPnQ zz^Wl&q%j@5ISA0QPHq2$pxL1YiK$Qlh^RImAqlYv(*gWsD;m@Cc4dYsZ(_mSya9ke zAH=?aVb0s&hk;o% z+>@YAJ+mH=zXdjbV4=gToQ;UkZCBRbf;gsYGZRb7MmSjoD6AI9TMkQHPPkm zh&ou6f7hCsl>A5pNMnrx%X9PQ)o#B7zh2q7t>t#nAyJzwY4gM_5_`hvP8hCH5UjZG z3Bo0*PK|s4x>dB?f5)<2?W3^M>^appTr~^E3hFFK-auWYHNazuD;D!wC2?pFu8##4=O4vAKQGmA?QC__NBOP|XYZHmc8B3=#H*!ef%2>8 z=vbZ22@NmKR_iJQ>kP0%@BaBJ#CHTM%u$A2cDosh7L~SIW1YfAqH zkhgI-?)vh)>xZJVRf?I7I~5YQ?AhE~JK=v(z%}$$TC6Ja2^l}K`mw~&WTx3;kkSK}@}v&cH3AdS>S z4)QxK_^pYxf#EnOUpPT>!9gKx<20;9s$3ji(G#yg0f~%r5ct#u)M%~D=&xOX=2GCg zP(Nqq`q53^K|trbU3RG?hom=X)=Xo~*Z6~NQYxMEGL#3n#(12C7Q8Rmkj8dB%E%-z z!1K;p!V_3PDuN6g(BaFLQk#_B#^Erq`=jBn9Dps*d946N^65sxE)?F!mct(r8#wucR~si3Sf!oDo!JCzcj*Y5C$FP9gBfwHk#w- zvQpN0$46R^uk%vpvfQO|r68N|geUd8GDNV_2d<5 zWj)g=Y&%ASWeV|mM%T`0S8W@YmkNltOC3*)z%*)Int?UtYWlkvu;YAKFb)69&^0_u zcuwt7Nj;_N_f?f7>*w1Q6Q{1yEezQowr3RxYbLD=)H`d;;1dkZP1bBD8c@snVbPG{ zQZUqtNhk(ze1ZsZl$D9&){0_eQhZc%!h7|Yd*E|$c%wABZ8C!EEtxZ)e2G}6$7c+$TWbwu;(ugDzmPj zQVBL|e9SjyBZ#0Q4_PxY+0 z*1pGF&u-iO%HWh3U0D4<`CB_?o|eGmsh=EyUilEiHBBQN=~ zy!~leiy!`b(g=)}f|b_1Og=0%hR45sPOUP>0tfEA%HAu0WeBp%h02G6V98V%Q^;eG z%ZuEBaoxPFU{O4khu_Y#Gl0jC;M<=-Asf8(bsj|^JPqL3l6lGNJSLx)O64Wz4!F@S ztHnSyEp{_lu#9eAw5ToDJU6palJmE(En$S0(Aa9jgl#Y9F}iaSa$$lJ_sh=_R?rP6=n|Z94}Fvld$fXPIJar zW-$f4tu+r)M6aTxkHD`Qt1`a~Yu*t!FIDs^5&ewn2Rl9jg&bhVyE~dR!U=qE(z;R# zAG2>m!}l&O#276u;Z51k3RU8LGB##GhW-n}Njt(i|=7a1A)>~$LyxCL0Vm1rzD zTE>{knO47~R|~a~;TTC*;oG&H8P}r)5Pvcxl=d)^=pUTjm3ufRhLsZyhnTb8cHPc3 z1c1n7(9&nH2>{eAr&l1Zpapf?Gy?r9p}0MkCaaH(t##ZetPPC!5e(poKg(SRl7|D= z9|GW1PZ+u%NUleTxj@!MBn#Y_c~<$_2%e>>Ljsb>EuR21HcpA;;6siW9v+%xn}E=r~xS7X${aD=gU*tCKlH++YJCkW6B`H%dHU0sz|= zf?%i~+>5+n$%(HB`qchB9>+oF7lYEznPORNDY$Q3cK14%)Xn;Jh$V#{01UuS8FrDZ z%Hkc^(l=}U?tZBTe3HuZ=W}hSAZ{aYm#8&zE-!9ACzA%V8ZjbMK~mK6820{`kUZta zoFEHc^(4@o2-7`KeX{aS27`Cc14tA=xU}8PmT>dZ1BuxCg9-;uDY@udH>biOcy}Nk zo}B`4_HqvF?|~hn4q|Ck*k71>A(hF3?EDQ2;twQYUtx(k)Bd6_zTEA2-#a836KmKB z3XDtvDw8-zggho395o?ROUpjA4>G87VCr*L+B)nQL&DuF13D@^_}BXlm+6$*2ulWJ zX^YrK0Nx)+>q!$@1QY#XdZlL*g>sf2n733xI25YuL#UqteyNVG9RJ9*ep z^!Dm9-md)7q0;P#``Jh2yW&l;*?(DbBETXVfDmuB&+R3_L(JR(Yo@ibF*439z}s&< zC?*St27KKIsL$=FiR3#p(>1CkszMdEFWl zuy!!_s|i6QYR)$Phxg<7C)per^|3D&;!6cGQ?gnkZ@vq;``&i+gKg2Xo4gckmI{E= z*p!z)*Pkf9W-~~Suaw9IKGMAb&=~p)8~)M1mv~BL8IoDb^Rm8@DacVK%HhT1KMud( z3JFjM?4}<)7{YO2!1^56R8JX2QBEckW{bXhYa;ja&9N^BEaA_1@j<|Y1{~#OXeN{Q zESP=RUC9OBpc@3-Rm#gCZ)hng*5h8dLJST-Jg>I$HI z1qN%g5Tr%|y1DmntNh>vyRmCCQoC}bFR5RLk4Casi;!bzT(l z)Yyse4VMA0QokU9u6d*4QIgYXC3zW0L7Ipc!EEK^0wWqN!`?|=Cg#pZcmnqe54wZ(5!?IOHl1LKkyFeG#CF z-Hg!wDOU}pzRG!{QcNOg%%~lt(Ft9G)?`}qbk6gl;JOV|1J{42bM`DVhZEGS21)Ps z?qW09n>rIi!atvzI(Sb7yOjCDDuPQk(aL4n#{}r)0>(&$moS+dAP+x&md6}8B8cD@ zM6!&59%4cd3czoQ^i*FY=2b)egx4M!sO|=R+o!F{I-T=Biq1Wn>Hm-8yP07(_qlB5 zPA*M`xwaXh+;gi`8> z`JD4PpZELoem$R$N0{D|J;nva!%wT_ShYpQmUq4Z!*V|*v|e68z!@o-*km%QZmIyJ z1*>-kz+~@c*LZIq(|A)V=G9J$(QuShHi4-+?qxXaqZ)ZjE^V&TeJcFRJe4xuI7%X6 z@jE1((I>os#4sKET>~F0ohivk*xqc4(wCMGG;XgX`pW>B|?)4asw1$*-G}#bsZu zRhK=Z5tJqC7vX9)E~F3tX3OUfKMx}Wo$qe$bIrTxlU35KXq+~DQUC5j#2u)!0CR6; z@QV+Xa37P*TKKJ~XE-twT_C5_j0()tVnwiT#or&AOEU`?xzT)gk8jIZHQh^@XeYUos z-^^^4&}s7n{q1l7VQkk2O_CfPYW1Tvm~J)CrS{uo&#a~@)~LEM9WOaEbAUwGBnepFocvA5`$nI&0wNmeCC6go}u za_}Kn+(udaKJimM9_t;hAIv*xu~6j`%j~n8szs0F&Cd<>CUm7fxMTa{JT*C%RQ(?gPfc}D?=`SG2D<_C~dIxU|e72WJ8ai^>Ra(UzdK< zSe0KpqBP|e2z;r8M~2vkIXKprf~32MgElf?G*^l#uQ;TL}F#@$7O%6 ztJ{|Ia(bT6)2XX+*NS<$YbY)mUx^Sh_O|wq0dItjO8&m=4hR9hghd2K%X%o0`Ii6( z@m?Ug?M+!omfxmg)9&?PTg10%aynn zvk7E65qWRvM_P>b|!X)*DO zhIvew`g~loT+ocGW4QORhra$tpQWBw3`&n-iH>fBKirb1<~FHI({c>8OGnW>Ofa`R z85~b~L!nLhg=2y;b9!!?mJRa5?vSzzP*!G-ShFX)@u|tMm6MNzIwu02 z{Y{I0D5Dr37~6f#yZ`i<%T-C+4PL%YGg|7?)FDEO#gW9%m5RP)%g@BA7QZT}YMhk< zwJBA7>}IvN6>ks`Rd^c*Z7Ysb7{-5d5fdNcAnYDhP|ht;-G;l|)7RIKwyRQ(=YsOG z#zan-o@#YRjv$B21b2(t;A<)}Hkor8an;VOLv0;p6>YgU@kdui^euG^ zC2mUkN{wKk`x7;Nw_zQ&?|_$+T5ijd!(F)_S`0%(BH6ch(@tReGoWIkOPLab2FIk9OUqZxN$OfUeebyOJJq`!zNCqw`6xF&_ z7*IFgQANoMU^E9TQO%Ix0K|e}_=uCTyipl^f!Kgixj*<&_eR-;s{(d^pkj^jp6cr8b-=YI7%0KQ-dVow;*QCA6Q{VSQd&(i?rXrHV&Yu90t( zzJiw3jU3F{$jkZU>xk;OotB#rhYE?-b8f}w=kYwR$I3OgRLwhJK0WNbqDH31En-(NY$SL4w7kNX6*8S zjMvG^e3(uVg8^0zEJt4EzI;(a7l&_OTs7(|ffD17t7RU5C;#WIiDBpM%l&?!Ipp zkh0^GDrtSs8h|(n1PHkW!d1`hWJOE>;H#N2*Le`Tnh6(^d~eRAL#Qz&1*B&L1*q~* z{EK`fYm5g$@HCKEi)?(#!N<3fF)(`!R=H_ec6VHpRI()x^5i6>(nYAFSPb6X&yFAl z(rfl{#{)!#lLw1^0<-xktFgs;8`V?FQ=ONrS^!5~jlS0R1?LG*j*b~C^TY0ShNXd;Mp^E$w%yYb?{1k6_YB@Jg9T`r6a{?D&Iz4)BQ=lW{L z553}+$@V zhMtlst-#LVqrGYCM@haUSCOe)O##{(>UZw3o1~Pb0hq$=nY7xwgbeqA=g6Fk-R*{y z-|p4rYd?Sj?XxfT>0b=6{D8-W5uvai@~rt?WjT16D9K#`M&*n5Wlt0tb(=^0w)<~A z|Gwkih_f$V_9LC`Xgp63){9ODLSgoP;}m!&1d!e)p3SJ1rhxIu z2qe?BhpdTV>0y}E)`L{v-rBWGYI-b_bcX9H8E(kKI)FeNJ{q6`Y+@dq$0n3R>geDVX`D3d2tK+%Vl3=ZGfe7K+0NH z)?~URLmk-!vmCpntfj<_V~q&`607$2R!b7c1ePfj`1xQN4%m(>=-~0hMg+UrfQUSR z$sd7jt=~o0(lI_+p3SliIqWk7(5{9VlxQL+CB8F8E%SMVLMjQ~COAJ3n>X;z)?a3o zC*ZR*IOLRaa?cb?e?SV?B(UXBG3TA&ffTDTD$*^Z1fAg$J7&IJ%rfI#J2sM8JSnjD z1WB%nONIz`_kfS_2T8T&HG8%|*S8?Zmf|xKy%9<3MOg)DN?_RmR z(^YMW|I!>ZDB_0xn3-H_>IgRJ&MoP%?GZ2@-lVTNnav4o!ax$WN)iy3?F?(@`HpX? z)Mt?b+exZr3b3~~b88%9xp?iTm-h~%Yk!#1d6w7oM-F(7z9*&~or8(z1jt~SRX?}J z#E-c_nnVr>vQ&G%f)D@Lh$=d+jc5bL>A6a;0u+6+4O7yNxq^xF{8V`$vY7uOELp7W zrt%1X_ssa7q^kDS@m+c#>=+PNp(u-JgRI*-FH+8IBf*}}kM0R$zHXvfes34wpa8<$ z_gx@EJ$aBg1}KCF6Pd~nlQk1kBs>`q1^~ilICUBp|hll_w@CJEq&E=XofG=opHjIxvy+s7IWj@}8W0!D{}}4)UHs zp7cziLQkq%Lc0u^fo9~WhdXMKC+t)9%NCQtTI5!&9%2BX5=qvzOYyb^$cYT7O)6Jn znODsDAXN&`6#y~hi}wHlEn<(jK`Wf1Dqc{Vwxa3@Rl`YY!2Gdemi+&d3OOMCYOq}~ zRgcrQLoYcNu99p<$p8R-KNE7=_U&#S zU{}*6tJ*eA8+%g`OtJ-x2QX)t)GOIk-9Iet6jtVB$bhuKw&k|IUb2QW%XULxp(^v& z_mySSUMqIn!y^KlKdgupN9kf#3Q4e=0NU9kC>zcQlVjp)K|4~CO{+V1rP%Law;7L1 z>vKSyD^wAV_2zchz1SIm&H&Z6Rj^C$3t?>WAV?hD>TC-z3XB!sWxQ;|X)7~tKYZ8O zW~nksVIRD+t&GbOoo{Gr39QGcHX`VrVW@K~lQaXiV}N65M6H zuD2Bem>K~qgn1w~?v7!YEYVH#&?wW?lLb}C^1|=v=(Nqomy=cz3!Wp@L_&LA7q-^V+XmLn<>a6GOT7oE6FqL$OM=kEQERe`9k(lZ6ue{G)kVgKfBvD9 ztq4;62V8O9=}o;rZs#&e03O(peDmZw-%mV7KDTyeOOC2U8UL- zc4mZuCK}V*s+l#!U0ajX>m2AscCyXPiGV-cXI<1hy=7@ppz?;I%fZ)HZ zOx0RBmm>%~^-7APb_Z2-hcX5ol3LW=DURn-9HCRJ;p@dVB_?>yS8`veRvRWHK%=>T zqiQ_(@X341Tmk;5d*ZM&#DOgH7&!_T&Q9$@WUMH44Q;8fcLIv;z`Dks{m6 zvME|bpw<#YX_Ds)-~$st<7|p7EExoOq`LXgav2b0U>>|5phz~ab98hd7S`730!kSL4=ITof=}Cry14RsPFH2;IUbjFD*SeBPb+mkfxjMSdt)XTQjG?Dx zu96Q_N@##ZrIhI)O+=fnq*5$vSytqPlzS{IF3UVy z98RQK7lKW8I9pc>w48Bpn`8?gl65WBJaEc7FkB_xSvs0;-YT%^q1y1kOZt~&X8`(z zRO@zd&QoxrI?SUWQz?*z?*-emN0_%z%?CWJL%}4Tz@}4R&0!e^-pn{j-SuYE3PL3{ z2~4#-E^-8-Yl|+6pyUE8_J9vTJgtXh`BS1OkYXx=X?IdzHB!wO%+(bl9746`2(G4x zAzj-tUUZ-rC>C5+;r9N=R)$oW6j}febnVhh>jba~7i?75?k z%6cEYUxBURf~)(e>ygtWIcxpEo7V>TEGkKd_7t|rw}hRuvH?LZ;=3l0( ziNGLmfm2ehxP8k5>JC?ln)m}@>j4o^<2xxmGoj1u4x-zaxb}ZWXK#Hv)>iNSmB^co zo0O^7UvR*1DDE!xe?>dB)wW$Wf&+KVOyJ3@#@Ra!S*8i+4~kQRf)M{f>_cQ2SA{xLVaN-z^ z48k)`-ACRCT99w57NRc9UVRDiW>t z_ytXisZ+S>bl1AfwJ#`>$nsd%BItEsQ zj|+ld?trhQXqZX3zS7tp4$wHJ4@c?}cCHjEn+jiL`x$)Lyp-Xio8fVKZ(Z`k&oAx} z&VVLc6Mpc4x4iqAdkN9AC8{+Fd*BDw zgJ1jf+DARLTsu}+)E(64ii!Im$QJBSc$N@*yuUut%G_=1jJ^KB_LK#U?bOW3W_FgG zM1ig+-ZnfR(14kQ$IOQ2&!-+PHvi6*%xdvDVtdx(i%*5~LgS%K;hOMd)>j#AN!jo7 z^0`O*kJxQ(1hvQM+rNL_Hm~9n4aoHRf1-3+=8b)par@Y*XWyc}XaMYBCp7YPI=Nhk zaWbRd3}ztdVW;uKG`cmrt^1S>r2Fnp2mMu*e)1oMkcL}p>r(x%E{13&Us7X|8mv0< zo!bZxGnaBT@m;S!muTp9Rd?#wWWU*MaNkESEn-H($x<~TU0wD3Xic#7C|uUa2p3)r zbTvf%?sUWFmLMMrGI`}t+{_>GbgSvdcdp5gO+N5=u+ep|R!efKe!KIFOxJ_nRzk4c z(-Hi`c`r9q(T1Ac7uWPbWxJ6RLmxMYg-xE8W>V?qiFyY87u{n&_;}r`XuRci+LlKZzeO;11?m;8bZXrEfckid=z?v_Zut|x{9BfPDb8$Gw|ux zxOZ|S?$9^ngWx(93*(jH*6iu#4@Ef>u?MhOnPP!y-X+5b9n_WHf+${?LV$(p7Xm=V2 z9oxdEW)Z3aY{k?S)*Y2mkv)#7Hppv~t+PFt-K)ElJ@^~hX9KpsyoxT?!kxd)q(`Lr z4}_{Erh8El7FV{CRP8!)53Mx*gU1a#Uh6yb_1Sm%t6yI<_x+r{u%@88DnRTGTzmQ1 zy(H%O$ivaK4*mO+v0Z}Sk9B)3y8<({4bnqWq^~e;T}DSu*nGQtY|?1H&NeDjDMwVu;`J3s5Cg|26OmafBes23)#)O;>IJKfMxb}l)iJpR>oiujUzRsWH5uU}7< z#V|g8|9vWj@V)F@Td&8_Q|lvYDpS0tr;h&HQoH=jWZJ0ly#^jn4oQK#dIFI!{F%~2 z*a0GRmr;+~#f@*hD|Wgsv;ryEzxYc>^)7)ARcPWis>N+TG~|YClV3Aq?oHTUQGX;; z?-{ceOrIR+*r~W;l(sV@2N5&YtO_-ZMcfl2nV9wtZ3^hL9sn52W$GDvrn|+_WO^9z z<8c~(MfZRhC`Hn**j_rcn%P#;f+kcX%f}G{FoVUfy2khAoQ#`QQU7d2>dVVz+)f67 z7#%8+GvQ}8G~ef=S@P)qSVz6#vOZFWx%T?yoVdA1I3*XCM_%U(nkuxOa`D#==NFW2 z%;{2;_Il;!7giFr|1J)7?61!+s*C$*Kv&v#pikz?OmMMLzpj&Y>izu3b06VY!JdQ2 zg5sCNPbPWST>W?Hc#xv2O!?_Lmq`y!wQUTU-gGgJE4sgZ{cAoP#hbI!B^HS9o>ZoC zYpUCT`>zQPY8$_O?N*oJan+{qj_mlj`-K(R^iPEd6lROmzd9p5wfc(k44CWW6LYw( zhH2C$jWA}!+&D2fV}bsKIGMtCzL}`@XKvH&c#5XdajT;UZy+){n|m9v4^)%Xh{Xev zRWP=CBrA$@E9%eXx{Jg*Dwa>DPulY_a1ba(@ z)Zb24_`Q19ZlwXW-}&oRr@cV)UqYlA#3!wYNiqK;963J&#zokAJ5qMkcenFY|0UcI zoNWXhU!|&jh6$Q$i$s~mTPninrC@)Y0l_7smt$M(K@Ux)e}xfh-u1^)iXQ!myE|F7dRcerheWex?_?$o8r3RLC^@Oet9@M8 z4WOgni-bX4OdIcZ-i@|E5ekTpeCl3xYd@dAqkS##%rLc%w^$#3`^{*Jvkvs52t(PG z@va7Tg_|ZedMZQ~962|ucI5k4yA5Fl0V0mdL3EHlN zl+z_N^+|iejehNF^{Lupb&CCOy+y0H53%pp;5t$9vIXL`XGF2@>tmylsW3bEe&v^S z?!lLq9a_A$Z;PKIv?~;HAUdn&HKW5W(xMdg9zIR%RD)Ja!)Fopz#JK}w~3q*OGb8_dNsL_4?o)E%Js;B$`zFDIbR1P4Nv=LbhrkHwqP@ZlCbKaa;~*h^o$X}n%>+f-sbYU{9h*vdVB03vz=U0X zERm6UzDa=8!k@J?04)^>Y-X)|zdk;a<-^xM)4r5x7TfF+UTZKid{`91-;Lc_-@UmM ztoW2Suk-`ECu-#C+3!=ru${v@nvZ-hbVKO?;qfo%pI!wo|o* zE??!Ln?ROr1gc;>RsM?#NMJOy3suAVRT6}fxwje%ouoIlT$}2kJax5O$4ydl=M`Kh zwbWJW)m4{(B2L-2CZK#FSe?Oxmr#D_d8$4tm+jLMb(%)c4}7<&HS+=A{|{|;!~k|5 z$<6kJy~s70Te)%zEs=O@MYSWka5c3m`VkHBwUwLFSU(i`TJpG|dJ+Q>r>+=FSAeS{ zVo$z3`(^v6jE8PGPi~2Vi!8^kQ`9!f)o7HYaDc)lU2UC?V~g{C3041VlUTZs`@vUL zh}pM6SG!&gh4nc<5#o%q)L>cIMW9+F|L57{pP8<5Zep-nq3lmO`a84Uo9RAXEsFG2-+AtGK%0sX5v47w|AO*Whmo1G^ z9qlp)zX-?=;-;(s2$-m${!YSn~|vRe6_oL8R_J0sWx@B zb*6}PsrE_uIhXykaiDB&Mayfw9^Ef~c$fCkUGQ<_MD}WHAgcP)KvQ9ag#J>CkKu*z zb)6T{dizfPnXVo&M@+$+idWvQuM`bhydy9^#XZEf0m7FVK!;Eb#O%_`vqBX0VF7szG z_A2Y;xM83&o8GcSNtldL>CIQ2R#$7{;>t^zldg!XJ3~)V6)zN%K4zhCBX>17{lUA?Mba`$aEs1!M>Y15Lzr{yQncVl-+W~@7&>~wtTX;!wXyUmnr z!Z#=55$5U&|Irb4f;plY3)!&^XHL%x&DQ<6^WK$z2V&sxN9GgSbb)F`ThV znQju-TVdCJ1tMO|86a9oRQ#fL_P{p-7j4tECLS`9nAsLg*A{5BIDb*cS*eRvzuX;7mbn%830FB|MaQi& zRY2~Z3TEBeTG(}_s*Z-bCr61U>*nO;*4yiIm!`T-!M5QiX#iQf7)a4hwHbA^`+X>m z+4+bslZ8hGl*{JNO4f5Ed+2Jd>Y?$symInp0%g_G{VdsaDk7FIx%=M-A+8K4c2+d> zqc4o^wJ}#VW0Ez0sQ^CX}-7>rphpR;t%MP zIS7BBDDmWqa&|i+TUNv}gX9?Nf@%&;(9t@#D*pkYZ1qI8P;zBiyN#oF)?4pb80>z& z;*ej0a)(F2NPOKK}IBrCLXpu`I z9yORXvtO3DJ0n5s5jE^lp>zd?P%0h&O7*j|uK!qPsyL?!R}p6w#8K9h!R?X0#9yso1(h@eRQgvAzL_yu*>tA_UnZcM!jg|o+ZV|2$$w#u?b`ljuhXvSGpn@M`x(}Fi*LSy+(T{1TO}CX@DH@?sSEH{6e>-z{Zqwd2oDLjKO1!#4u9H~XOaPya|9R$!`s>6D&-)O+ zygOG%k}h4AMjdUA&v&|)aK<(9ue*6d*7*xO$r=2Gx6Kz$H3vUjx65%S&i@QCgTvZH zc$A^EYb{UzX)qoL3lnMRPeNC(0=bK4OM381_k}URXRzx)6}?U64La61L9U;!b|s;N z#}JE<=56pzoQl2nwXnS~s(v7B=`u(zo#>yMz*d&tKYvDFGR(_s| zn-OA{#>=#?s(KFj{dYz!**CzNjwLo+e@{`3R44sY&*I}nG-#B3x9SRC@zv%*r6oci zY5UAjfKEQM(E}=EvsL2*sm4m0LCq1Bbt-R5|4Q3vUMj5zGPfPq0tBD&+2!c=oT$o zbacJ+?-dsL{`8X1Dt^en5_90H#A&y9jTXjMOcoCjwpCn^cuksn?WQF(AE=hUq0Hec zl`yd~7NJx2k#3}J&rKDF!5e%fX!~QFoVxV|q1EYdu_}7$MB<_MO3%6Z@}CaiY<@qu zc9JC(oLqu2A%m1!>DYj?*vCR$q6NAI5Oa(P3DV9^q~CH;+-3ah(0jOu^{v#--?p>e zg-d59>=D&;dn;rg$9pIz<*A(e_ObGE(w_Tn#m-4b@2TXUP`;yd;Lg(j@} zK56YZ{^Yofv8US}vn{nFO9*?Q;#r}S6kRfs2R)m0*P!k0pwjuKU;j0WK{-Hk?0(hc z*^8xk#$)wR73sR6Cc@iya5>fYb3ya#eC1rrr}Iyo2ZYZIO~m4cusEQYA6|^cxprU4 z7^d=NTG;nxpD)0B`%jD3OPnF_QaMF!QrH;7dqz|d-1+sZ`n`4Y ztuoXbAQomXQ^qGP0~Ox2+ukn}pOjLSVb@^FClOL6NPKOepXe|afh%XoiQ31=bJNMBgwO_Zr8;BE-#8O3H3{AqI~ zXMig&LpwUl9E-@4%nMg@RapxJC+DpnSh;DHvM8-Suo$#bUwK=PPyJwq^?X&UL z;Vb$vr5bOG=AN&<@a1S;eK}7m;*%=9-pwt`$KSvDaXHZOc;w*E^NDJ{@#2qH7XJ); zlz#eBvBW5Az1*00<1JnP@4Ww)!Bg=g&L#``HrAq}|e{Pvf7j(=5Gs>M!>s7uTd#nROM_p6HgJ?vWHV_V3dLhH?jC~D|) zll;f9CA@7nUn0a&CZqB5K;Q0#6uj3bXWq8lXgM}S{ff)PO*KUW zGrnd9^Xq;Q((jqFf*t;{AJ)n_u}2-}?EO9nFSf{-k5pd@rVak1C`jhXl&q+I*i`ca zDF341FieQ~O}Tt=`MqWH5>aLDc0=3pPmezD2exJKnBeWdn(63rekxo=*>%&C-j*S! zkE_*N6{XXpO!jWfYiYd7)!dmJ5;jQhN;9yGgYq^{ZGfHXbrKW6Guom_k1l0 zaZ*XGPwS}g=^Yn@gto|4|2wPzL?JmR2Ux$Z&6hM3Ztih~o5clPwq~vJSjw4tZRt2V zJO~=kvPtVP{W>|6bL=$%1fiPnV*7W09Ba%ptR?>JmwYW^lv`K4e+_8W|Wey*&ZU-FHm$_=ltdY54?WUwdaqM+D zE;@$GI9`^tlDOZ+*>^$9-DhKUkNW;GJWI|e;F!Gp$%9&+i0aAUe*d6<1rGAF^ZTc5 zw>D;a*N8PVlO^=|g%7N_Ne^(!%Du1sEF7JK~ zaiWp7W(qtWbdR#&XY@mcP_}DJv$c1|2ksOZ{z&LrvisIFgd*`R83k(Tt$naK&o@H$w|_L;z1A-1Crysx3H+JGq29A# zg#=nMSbOcV#a6=J8va>8j4(W(jTT7iwPsVLw`~}3@XjyLh|6~Ezo>4K@XELDcH7yl z9=4fUmZMf;Z(9ssO`I9mzHZekSM3!7O8V~NUsdtFc%S`T$hH3tmdcNYChMQscc^=- z`uhHex?!*LeQxnnXW!?IJ}hKD+1BUW?L=3aR!;0=aQIVXZ2A@jG;d3 zuUwY99!&^vvz!Z9grMUX`}-`ymx|<&WVo!m4VE7wbeIx@(W+ypi!b+yoAsbI zb)-AVu!Az_VNb;J4o`qrRq7VP&u4e0(#0qFRp#!?p z0%_acDM3nT|GVQe@@&bhGMy|Mt@)YVchPc-^46$$qVTBRByXShlC1pw>Pr1amniqi zTjPCcFB@vyMAY)3%4w*!))Ti=k&(Am-ou=p)~$K`cUNPkn$h8it=BP-b{3rqu`cSL z(6j+0FCs*Z=ea9t!2mGOR#zgN1Hp&$SO&u)!OVQNVKo>+&WtT2jFnUV1*F)( zgV0gc6vTWp=}GH4JJA^gFWLUqAev&KSOZjH%GSNA|jdRKOQ@P}l;jGn=!zr~LfwEIDGlPiTT88>E~nV>h>wMMx%%QYSsC5Nxy zlDlJEs_$OEUQzxl#ab1VjK9%oUiXrr_#>eM?>VzqhNq3YlBDl??Vxl1f3-CoO*&}F z1Ae8C5Zbf4{W-;<7)jyo!W{BcW_>MlGA!gC-ae(rX%3h>?$6`8i^iePN^ z$tC~)Gzzq|B_j%9MHLX^##t`6La`|iCsSRjYapfKN^C8;(@RfEu7aSjTuIVZC_)lo|2?vU^&bz zOs~Mj<|vGM;CX2MgVL|rpKZP*_S*yR-8j7OxZQg#iDIp9Q5RZuNjHnzlB1e#t05Mg z_bGRKl{HoF%vo@aNE#|xX}WX5d%+_sX}H4pVU0&lxZ8x2M|tSU$lWUQ7BAjK$os|J zJ(cq%@JrI$*6B|98G{MGw}tL)QJS{~tED^dB08T%J$i5xu^iU1IaXxGA`S4RF1|X@ zC;iB*`tZB`r8yC0+4`!5+p8BMEA4dMEpM9bamwAO zFu1VryC_mUxC&~+5V90Lsw3+?#chg(YA5$d+(-nZ{d@(0BQKGp%InjfTP4hzAH5yo zdlikVHohHSwE2A8{oSp-SD%cTHOrapcyrG5!fMLSR^b;Phy{bCT7!pLjq-EPFj&$X zk6~zgY2+C$3%f|#?%2hnIp7(5rOzU^^00KSdlS`|Fr$KWmd@?CuZf*?#)TGO9y_H6 zt5&f?Dz1CwMiuILdZfK$`5$!B>yq2b-1q*}!z}M!+<(7@??3-8Q6v7o_BL+pS4Zs_ z{rX2SO+jCf0%`1kM|2qJ=I?}#ke(ypKD6OY*q&GKDntLgUjX9%uD&Wx-7h|8kKC4V z^f((o@Y5{%He>MR`608w2p>jr`~_KOraUY*Ulw({0r`d|)y)>=c;P0i)=@m<4^PxI zPqJba{^1zv(JJK-J$a3Tc*K+XY@v+qi2f3d`Zj>5Wk|l|YAg-VH{x$oU~f zVk~OcoJH_<93$?y&XEzVE^%LELaKc;Lne%Qcs}*$W+VoK@%II55hOGV5gG~V?~@TG zGimy0$u%}=%JY;72XU7IH=IoyC+nk~sLw_11PoY<3;#htJ#$JurWH!!rRR`B;e5&O zG?ZW<=^zmKi-(LNGmb)1t*)k*By~+5mIi3=K_}Bbpw}nEF1IIB5sP1Uvr4aUzy5~3>^@W_B#X=l%5!XBIF$b_r zqC<}L!F}T856%mHt2g%;C7;`4dFWd066%- z6-e5Zz-Gew0P=?Jjini+h^A}%T01R7ii?+eHhv?bA>)V16&nsL`5}Cmem>)X_e!X;MzgwvLDW=U$$$m`S_8KvVjrA;H(ZXRHlOMpkX?7f@x_iU8(0f=l3O5PGprimMT zxTLa$yaIrR(r$(Vpfs}A;^z5z?ewVX?17IE0s;OLE!rHxw`jhT>$zPLQ9UkKFS``_ zlJ*}bmQs(E-ucLpYc9numaAo2Ou4ZAPh`EOrB`@nOqgVSAefqW1Lyf}U%p}exX zu&T2V-&J{du`*8Mmik(0fD+-k5aGfG>2pDk@Tg55;!Lsf_W`&G8>GjEydSu9VqD_+ z8p4KMRZT&CjV5O36>2cSlWbJcZ2sO~DN(W4EZ-IfI9H2W6-Q+%e>w+V{#ALStEMzu zmM(ccz=f735;70Kd)Ww)p-J(UCMo|u4QIa4q4WC2h^2i){Wn-lTx?*F@WlwDg7>k)aX3J z1)!Gv4YtTi_kPgFqEW(KhKnLBJRb4M7hJm?U0<8;u|-B1V`@@ZnKxi%l(t;29r)tgf}Qol*8i@;~Yz+JV-AW(Mt9RJTCE;j9eHj`dr$;Ie&+1$wzq*<5x%NOyN%oiA15%IkvaYH5 zd9{A0<3nYy{w7}hk}(nx)hp@qb6Y;l{8;=YgBDrELzfL6-|K#opOyLLY-w6nOx?bx z4 zQ{kCsk``7GjesWA$aW{yXAOSNf^7mJhAHtb4Lr!9mkRYWBw;osvStA2P_*LaD)P?l z{mmG|zvNdTOQ`A9z1Ch}DHiHiipO`JRK%tB)2PC;KzykIhCcxX8gy6!!F;m5fB~8+0gZ53e^a6&#JZQ4 z`mmCaAs%v${5pGE8a5xTaK9Zqg*N<5mZ*uwv@LnItFpDCZ9z9sljQnKueBWk&_Q*z zC;%cOyf;uWdyWv=Q5b2-1i$5Q638BA1c?ncsxz896dw1r_KiVZW^;9YtreOu1OMfT zde(t`PeAnopvtR?7gams(8QS;e@8N?6o09oJ8)1ocbO;U$N`S7q6%951O1V|@WV-Y zk6J2ZuX!W4qLKf+o%3ah6Stb?y5Ahn86Ccg`;19{I}7>5M$LPw6$eQbb8dIf4`G?$ zVSv^oSt5!6-}``*avefrz>~P3uyBOjGym)udq z+}b7}f5bSH-WaVs`3~QKaT-JF3aD2JsLkjSk)a?$9BgYeVD$7QLkYD!b7g+O*GC4- zE&yd2jX-LkdkavHKw2|waZBqk8dtQuBW#{c3PG|`0a8^N0pS7Pp9f5 z)P+|WE^uWI;!sUS#lyLO5O61#RmA|^@d5Lzk>6Y0P0K%yx=I60Q9sD=oj)fRxu|IX z*cSk+l7>PR-r!;xjYwfL-i%|aJ zkrJL15G*@|Y+7-mF%UTgNx6mEPjIsHBfKRCkksk)ccISjxADjis|aGBJ?<|uk$cvR zCh^_#4f{xIzx%4#&amYS@ntmTM>GfK#lf`Rq-ai&Opic$QwMvHN1q4YF}X^{NrTrc@ke{YEsg1<@KjZzrRIn%42yMn*rvKO|k5;tWt4pt+ zp=y&oR(Ne!?m(9b#4XNu*Fwni@{B$|wdy(YsEuh){r_0J0a+wSt9Y9QaBH9Ne+{I2aa^Rh4_=ygG7l71MG;)D~{LDs>x}Q$k z{{DVydsF^^@pKOn2r&Sl37LO1od;a&w z>biFAKuEfisl_pm+^x1<$NkwWO9G>^8a49lA_HKA# zf3;Vod*#8AMc>*352HT58~NhTrEk9!ktobwA1Ed#LJzAH()+8z`maHL^Uw~&5*20~O6%BW{Hk<{8 zO+RD#>85sV6#6!_R!}C_gB)FZ)URT0VzTK%A@H13({{A$O0#QB17TWf36sQf$KHt83i)2ow)@(CgX813+aAT+S)0@-wq7Mt z-%ulnizNZEYEDu{3F;}nMXGAgWL;UrjyHH^6TGCYU?N&3BqVJquT10)KM&_na$L@R z-AAWKX_Y_|Xq&*^%V$q^r!m}vJ~~R7J35|=xzqIEPzQP&@V@e>v@ZwhBPlLO5TB|0 za7BqU7FnIvM#gaNdt-SMH3s;bjp z>dI|VI=b35Lmz$V3dOA!|5BIA4tR*{w;b2H92TRyRCsQ2SMGPM`ViJxHKEF-qvkxE zURRdBDFVr|`;ewxn>s`8-#7=@xLben%lMOx6tP;J?C>w~DD;nMkm@HQ2P>T=DYLw& z@|i&gjBjAtb2Wv>#++^6lZ(%FQR9Ci=+{XMXo?{2XM;euQMxP{lj`BV{lxhjMCj1QaMkXRqqkbUNVRPw?O9+U1QVwcL6H8IYQB%YCpAqX{I%EC|@NXoxLph&+l zu?#KvV~a}VMj(y8 z_~P?o99L*F-S(=npenV1(%?F}sjtxFY&G(Czhbl1*BN=q9=eFpyeRo+;UY#;WaQU2 zx=m_1O|P7DafS(2*)uNwbkGPgynf75M+#zRiAVqBWpgPz?gWT`<-s%uxjQ7Va(5k~ zg@iV;#68WlCByB=3kL{T_j6-FXmqTz9c!f^qm3hBlsaiu%4EoiEvW2tWtYK(XtZd8 z62E!z0FjU@7)Ms_*XxDbCKaD-W?g-NP}}c9)RSg8#C7MeHPn62Kbq6(8?16$uWZ z+u!4lstt^>2~X*I2+74e?C?(|A(%0;%CAbuA>Wyz45p!L;iB-N zm)vRp+iEI5T%1jJ#byhRldhvT7{^Yl{2{>Z>mI%L%t1ZOI6oA?5w(X+`kyxmN?4Cn zyvc&@he$~#PN_X^Ym2R|QJ(vFx9@RM>}jzea&bYrSYCM~Hx=qT|Lvy1(=TnH^K+ud zY&!6&BQ7{x`pcpWkI101=qkeu5o$O92|MfKy!dNldEZx!{P{fMmEnvN-)O5Mjw@_s zF`(GW5$uLDQX$0%X9X{CXw*a^Vy?wV|AIvd#%jl-F*+>Wc{GG&GmJSe&<-s8R2+@7Zi`?@;p5nt zbKe<|s7Ne4eMbYOTyg$e^=`&cRN;}hHuk}fW;f@0h2wdEsGieAk<>pNbZN@Zw8)-l zN*_jf&4+I7fh^u`#iO#RY_lz2$#fC7R|4Il_=zaw^Pf1cyh(;7PUG3{w?<$ zXumHs(Gu$Sf*yyFM3Qv=OdJ?$ho)m?zOu-!L{_>FJwXSGdJH|buC;O)Cm+k+?PXGq zzqGNwk2YePYP*n6P0ckdegW3}{51U{4>C*vCalmi2B5o-=-Rer z>X8~oq#NgVpclrVU^j@|Le|AL=)Om0PHprH*r(hHhE8erMV&|SRy`NG=zR-}@KmVo ztb>#i{kwXOIsg<0s5P90rcCLjVocG3Ni{A#qmdpP0#nFvbSZG`W(w&69;B8iDF3uP zs!OqjW%&$H3tWWUcc31rhzb#5zcx@nJVlQM_Ctc@bScj3j)$6^JdKVzt}W}-03(=1m zb|cK~W~|$-47U}+z}5Bw3QFPWdUv^_*lk;h=Geh8!~i$1@a|H63(c)+33!kp?AHai zyryu6V*bUO)-=>mt2fpcWsts6b$!Ux*6M7qU>Z(`j$!TGcf_xk~c z0ebWdOQ;N?V97%H|*p@f^V5uKvhY-6> zK05$CH^nJr0Rx3}(3`o7R5jP%5~e!(@krk$R?(eCasYxEZux2wSd+%|x{HPVGl1(o zRsF-E2l(I~-V;9GRr~(Xt6MGs}3(6;(K4|1q#R57;&HL70XAY!f~l6U<}=pMzDUGNC5s6G}!|=KxdB!~JjN0J9!Lvp3<^ zbI|0e2iPoOomi+^VZJ)kGl?~!wk#Aw{J%$gpc+=~59I+h&kN3n>%#GJf)zoHLsZ3+ zx|E``Q;E>(x#`p{zXlg+nR0=W43$oYSRKiAj7P<|ABdlVzD2>A{`4_C=hn_7;lkvd zvB0CB0|`pkY+0>G-TouAsX7?KROKA42PW1y_R*i6Pl+SO*gAvbB4`+$dM5j_=K(*) z+wNph%zEQ)vJdrZZ(htd=-C|a8?Z;o)=d>WvTIjeaC6rxJNw*to<;}v zp+8I2ZHLo;jH`q@<*Ac^0U>mQ$I!$)Netli^LSMMG`-C_&)yNLW6;1amyR;>2kKJp zz15Xddy-)UZT>57YQ#PlGINU=)FyYVdF&8i`Oq@C9*NC1xQc(cnU!7%4bZ7k0=!Ok zIb4%ERFyhx7W*jw&p?lIPC4sE(b7O+r94=dqHjr`iG5N?@-b}#*%(oKWLVh+K-sCc zyQoi1p+H14&9esUp2~urw%m6z@@*z7m(0qgg$*cS$O%()K_US`&E@M1tO{|kTA&-U z+Fun)eys=D_)vj=E7Y-rv}Ui=7#9dcNtQs9dJIdDF{1}~x zq`3|pca7E(pHnq!fhLT}Ibk6c>6nMtXH!}9UwW`Db9#ki*Jogp>v4MoFMIoKHhbFD~HqYNB;28If=n~nvNB{x2hX6XryL9c~ z;gIYT*zCYDsuD3A5hfgg&Hg1u&6&yt{-nDTC%iCMebxg8UV;2!*(Y}B;YPydmWtre z@$-V6$(@2-p?R@r?wG*OmN`m3v;ZU|ij-wLMkD^E>oI6vZM4jA4RfPY-G?r%IAUh0 zqJCF$LOZCMYDxjv@oXPj)%$s38@TK_EqX|@_JLcu$*DYfhCXjT0qOg53|!Vja|dXB zW=MLhfK7>@5N!5|b>Ue-W^^0Kk0%V$$PU2907XEaU9??7h*4A*xC{;c%p#vcLBLJk zMu32hFx62fPY=eT!&3>@5aEYMAxBqe`mCAIUgMNSPL=UhFIIFEHtT-ABytQy{dY2i zKx^hc^osrzj?L2Sg4j4kJ$wZUSkH>$3Hz^KDIAb&|3Y(Tft_H(hefh3{yP~21IIfB z!UfT+Z4m5Z`q_bM?`(t3N6;V)u*~I5MGRzaPQqwM<97+9xb(Qq4DSLDBF>W7xp+kJ zCFFaa9124|#e$|WXsZR}w5ubEf`(WfsF6`txJ&jgaDOiAW7*y>AIw&Ld;`$F`lt|G+wUT>_+`wN(ybS(7WYuJB} ztWzp!3DKzEKi8D7S?^xa_1@5tUuh$0#e%=$Od{PD8D`@~Y2*CIFW2AZ0Z;ne&JeKh z(ezjtp>RRRDi7)p5b48RPbU}~}Pz8Ym&!q3?U(wSpfw(aR%*`KHB8Cd4YuHk`% zWYc%h3ti9@lCZM?7I*PaMx4C5DltTQ&xe|L7WB<$ z{iyXHQE|}2Jhgsp3u&Q9G(YK0~uX(}J$_u~*qW}JT>EElMEczr)nQ}Tq*5^o=O!#?f9P0*}1>#ThQq)O@`7cpd=sK zqAEMnQg;0Me#v7tNo%XP2D3I7WYW%Ri+-@zk*DX^W&uBg@rRzKZoD5hRcuA?$GE~4 zFqb7Y9_=Q4Sz9i%Xv5&p1@p`9a#U?!R3&e2BH()Tt+eg;brVw~H9cqWx&QLp@6#Cc`1sA-3olN_Y zDn_KdrN9=Hnliq)5Fj4#A73hh&(WHFA9UyVJ;`0)Q%d(eqGOc zBBXIp{4^0yey)dtVN%|3StPZ+?;cHn%Shq$uS)2HX{9WtVaD$RnADkNPBsV@hbo_+ z%TKA$7CRhv=E50+5%klHuOlsqSG{NdyKF1eE;DMgK9=Zhv|;z7*!uYNWeMl+OVpwC zwc|3o*U$x0V4Ct*u7-E)3g)%1p1T$spS3+eEwWmhGQFe;0@guneoV=DTYv1M7W=>H z3kF&I*3z#-lcKd{M_dQ}N1Xd{aiO9A7N#fkqDkbL4$Sw0^B(*dV+1~qYyB%c_>06z{a7V51=NiS} z&7lyXjXtXSH|&-eI;_ih`0#K>GQw}R(RfvEdM&Y7y+F&Cu2q2Xk2Km`l_E;TbW9Xm zomji+V!hJ{I>-|K2`=}URm>{)b7YTsgm!DPZ=pZ!BuZr0ZSXwpKa;@nmS#1Pxr&4& zhbZe9SP<3n$IwK9qA^KosB5({T${bkip*CETw#lck>tW#LcW{HKqOC?f$B`3+`)-x z71OSdM%fN`OV}?hv9%E|mnMquhVTilMWd*p3Ay3`<1u*K;LU26(QbkNW%7XGU;N)C z+!aS;ZB_#+(RF0j%kFCjNYduL$Mxr2uT3WO?n?$>z@$l*53%`4G!4(h(o9dz+CC#b zuv^e6H8PMKOf!|0dw+%#MD1UXQq%5hV@NC1Vtci!L6Yr^emXt??mD2%KrAy-_ zrwxQ*X-EYdpKydt6h37d=_ZyjZtYG2#(qo{E&f;1eXT=7b`D4jd9NmARA-c>7p5k9 zc%@gN*C^X0qg3Xf@lB-IBKo`0Gv?WWJ^R_WAqn+m)$8lU83A~ZIiQyp1kAUVWsBH6 zayIuvJVQ?Hv6~fz2ue%&a^)XRHZ=Ahh^^~W7X!;T!8qVN)6SOu3qJ5eKHsx zK{yZa;=K?4{`pD`5%V^A5hW)E?(cP2AO>nbKW>yUMO8SpDK7~DmY?n;1X?t_-eWbb zvY)twUI2i^V%qv%tP^rSOgUTlk*LA{JT%K$6_$FXhPJ3yOX zn5&czu`uI^4&-dOyhxZd^}wc~pswj`KjaI3z6&rYS|q(oJbFdw?Al_y@VJl7R*AT{ zhb$~SB+Fo(p-Jf@Dg7{0^#vUC<__;Mvs`zwJ>+;j-4DIQx&W(-4i;y^in#= zLr5elp4FOq$7vYLb`Qdc+%s6bU^;6UcmC7ccS8HSdO!P#_Xp4tj2;w4+#y_>4?w7m z-1c%Z;!qa&;(k*=sICjHwl4q_fQ{OfQ*vR$2l6E@5H*rQ`3rWBeM4=8K1+FC=r`X> zuKL{bu*|EGyk~_hDRSywV=-?r-E6BU(?>(tTsC*#Ki_7r*Mv(y1i`prn}$eBjbmjj z_CsqFk2trel2@tSdsncTf&1G>u-B}*dh^fqenn~Bm`forIH_2%Xc_&}D@W@kwk{s` zb)@uLSmWqO-u_GK#!iKp&T82|8i+;=#3U!)BKeIg|jtjki;kIS^P?gJlh&NA#tgWA3x1HgmY zgv1GW)zutR+b2>JX*VG%$9I8Hy)_o~b1&~!ZUD!6Yojnq?_*NC>#D~vN&H?PNcTH{ zjvhm4HEoVaya^G!(rWo9iJGc&nD~(XL$8sHMO|_Z&f4RQ9TKZ?EI+>4a*JGa`;naL zgwH+?g(LTeKU>{XOlGE&j}h+yMb|TlOXvkw75zVq44;TD3v*0mLlTzF=W7i3aRo^ zv$_Q@OfFS`q|NP8S~q!t&zM9+xO2;Y6<0e;IU+BTyru7~N1pA2LWiS$$Nn=eV1(a*cofmgtWM@8 zS}vn^0Dg9DVcZmnGd3HxN=ri+nT+yf)HEgw+U^J5%jCEKv~?`E$r6|D0uoaWzSkPi z%NNjuvaC0rJ$y7uc=~cbW&oZ>5G3j_@m7_Esuh()>t<)Rf0GFx^MRN2+hKP(<)mLZ1cgXJYB6goDMX z7fY%iR?ZcBQs3G^-_})@HUNy7g?5#_Qs`F}mgO^n74M|{d1=oQk!XgUv-AMPle^1N zm={1^Lb5?oTR+m2A}x`X|SXtcpQd$V_%M3_C3ulR*y-@$?P(ryfLRgxVn zQ`L}<@g{%DqoYQ9a+Ppu6)9ZOKI|*gNyX0bf21xiSn-$K4P!3bN-S=k@V0SpMgLN0UwNZS$S!1wx8}p+F z=txVMON0Nx$$6{3D~}lg&}S@@F}mVNj%yLk|@!(#cc&FXbEfNSb@AGn; zqX+ig?-(pA1s7Y#s<0@gl~jK&6@72kKbm7=#yR@shG}Il*TXFwDD-f>O1#3QQJ7-r zf!FDzq8nc%ERRW)97n;`xx=z5v(ME|2!GP8pW>901<6k zU8GX`wJW7L+}!wxI-hrk8K6>vQ@x0?(@jPFg9ZB1M-9~H69KrCC9mx-Tpm(Pt9kRn7ASGiofe95Lg+Jxh%{O<{h7-ajOJz|rFnDkCp40M^LdzU8kAMhW zp<%&d56^#)GvjuN>VAmeaq;c%oyxYk2G~E3kY3UDM{m6$%RWW#OvfseEuj(t9K$(` zi-+$fAM@))~#MaZ#|0?~99W0D{RmnlMWmAWe7em7+h45g0aVnntXQP?=+S>-y( zgGn7tEu9drp9W@`>mYpsBTmL}!^-hBm3V^BZvHudu!YB-PApVq45vbfnaC22l|CHJ zI{Nku{rDMtPY&K0B@r}LDe<(i)K>vY zr}6uacyF(JN@X|~?wLJndlkX}zX|)lqEHk#Ja>D z=4k1xo@J1(-(`*Ve4O7r^X^v*QBmPkB}AK#)$Z`NSn-$QvZ4paPXTglc7)DUbKz!( zgVy`(eDDr(I5DGMfe)<_?M(2BxqY+OrVXSuJGpZkS7gRv=ZHvzQRp3e_rRxa7tIt@ zfskC1gIqcFZ&~F!K*h!DyxvPYEJw3&5Ux{bt0TN;e#`{sVoL(C*Q=Z5h+pz0BVz~RoYUiEx?Gs{aQudV&@T%zJ&3nW`g#5yK;T}Xmf9M4g+g=VR z!gR17196IK@5#RWZ|`x|#YKDJGgcnu)dt6Urg)n395c;;iONAcT7VpbYy4S8qLOSH z0NOH$rp`;Dn>jWJkcf^fg2}R4p<1$XL92L6uF9{vW|xp*>x{N&p6_-Q$M;{qH49|h z0n(~m+qu2seH(X$PjdJ!($hf|{}=bM2XD*7zqWN24=J<;dPp|_Ov1o*a((dT5Zgc6 zo#v(Lvw<*e&S5YouyKzV;I-Yl5Zq(EWM)Ziap`;EK|zJI(N1>?U0UvT)Y*&*(UFxX zh;kGc7K`4+_aq7ZC?%br1+h<2Vy)t(Le|Y(IGBcy@1zrrmA@IE9Q>3%!u9miE}ZdX zaZJDtNTXhhBu7gFr_ETDwUGlPp54L&Sw!WmXIC0TA$qo{_D0POE~|ueKd}Y}`#+rh zQ$XY&5K^|t&SP`W=Ox+RaLjh!MB(+$45~yt2+bWe8NgrrQl!VWy#M4H zZ{@R3yHG^Tkt#9Av5eaCczPmM&$au=uvX5}8$hA7DHy}VS}lNnS<`QIc%M~iQWA{A zjR6m43!woNsWb+$SN(4uO)GldQp^V;g`clxiunlzlRW-b0vjGU<4+*aA&DQ(c=v*L zDQF&0clNmv7w478PHe;lF9HqBDh#H8m?hxwKRi5y1GMJ6A(543J0jK`rNYPs&u$R` z%^7fm$UaiY7~Z_QT@kwv{oJ#DT--QA98Cf_(zu;reWu;UNDsjdkM~y)mL3gI>8`N$ z5K}i~yyq5OMSFI1 z_axz+8Th@^y1`?)t2(U`o}5$HN3B!AO~(&8I$?gKN?L&(Ak&nuefYmPDCUouF4s(j zVg4tqMO$Cj!{D1~bhNJX?Wq)Jjn`D0soucz)U~x}_ERV8BnL>cP{h9Wk+zKO@%7c$>A)X(u z+{-ZCQhNkF85Dmu#|npy zr53*H8b$f}ugsmMXMN_^dwpK%oR%tI*9_}( zI?xPjC=Q=$+eNiuJPQHPBOlQdC&;TglU-bpO%>jn=#q+oU7Y`z(#NvwhTFruZFn}_ zV-gqP10>$>K@KPX=al`9q+RHt*FqK99FVWbQ1+5z`4_zCB^Ug7e@C%<&K1dq2^ZVh zxcTKH(BoO7qaYgtW3L>1`q3S(|Aom`-O{qFrJ!Ap@SbXmt(5#f-PjjA4JQ75-BDL8 zh(7HT6Gqk8D{9B&XdqQyCLcv_bzSBCdV1f|9znZ!EUN)FQH6HD9rWIE27$m(3-`J2 z^#a+IpFthSzxVP&cA^t|MldA3ygO%?(Vk~o?r2A&9`|`av^HcScDfJjpkpZdy$gJI z(FP2MAS!{0y_{Qgnbe%M+EEL)0jew0vCiF5tEI0~ex71B(b~!hi>{G)3Nk?)7T3i4 z8`?Lofe|hoH-neoJn<88qi_VZh)Mf;9c+)_uyywB;2~}XG(%KDry2F_1Wa&()*wNW z9#K_9p<*Pw$Kw26AkD_k_TS${feB2 zgnu?NX?`;jR7lYeURZh1TIF`h7E*ofA>tS(m7D5f)(AV=bILeG-th6l^wX4NQXBZy z+L6Jk?+fw2E&WTLqoU`lpI(to?g;`E9hK`QG#2ZnoUt zZ}^>P`mA`uR3XPIWMgsg^8QTph4k;cpQaz4+eKf@`1$SQn}?aIndh~QVyEvz^BXq= z3FeZ1Ik*#*Ub8Irt;{MOu)sAV^n_wm&^QQITScsgp*KUcuE1@8RJyomg1U$)VDNgL z_z|;q42ruFReAg$Zcq8kpmbtY#w#GGK_NU!gzh{)c(MZEZQEQF;L!0*Tw5qqS7a{) z2rgC+^H_jmg$D8J=yjrYZEOr8!3A3817cWwB(^u|t;6~XApK?Imrm$~2}|a_?)EEu zPV&)U;J6G}cKD2m)1J21V8>z?tx1rdQE6l8E9=k~8i@T$ee42vN*zMcf4!}xk%Pt^ z93>pw(iOQHdz&F^dWY1Jw@VRhQ^QBk--F`ASJ!pHLkrH#cyqU=H%%@Wpib`=Rpe;KbJ>3UuUpu1N#ebL3{!6x5cX; zKf_s(D-QcTOszb1r|!L?pG#OS)UK#|&vHQfjm26ohpj9rY9ko*%2i9)aU%15!*#ai z%0P_ot@PN!8?`wkcmsOb##swH1+zM@5i;*~ox#hJ5ztxXW^@XJm}<7B>F0o>7RWLIriB|9Tru~%uB^`{($21Ue>HHXk+z$N+wB! z)j`gy{})gfpBZT|i~1PiY%?!aoW|AQmbo%$fI@E(bdTTD76~82t39>9#E*)ZEU>7_<<-7>(*X#l!R#2Lzk3zjO|H&|c zax1%7exhB1^i~1Z04~wRm&};rsJw&G)Hf#7tkfr%FqHZyHzV?j>XLW4rVa=FAn3v>AU}`8tU=#DjVUf+d9F-f|6G^}8|? zaLa!3*3TxgSKXn&rdQe`4grgSk7fc}FUmEC%Y6zNJQQ@lMy};l;HN{=GeHk~ttZ=N3NY(4Q;e-G$dFb6H)zMvS(+xyVpdhaD$M)K&#*)rM} zwa&QF#pw>jC1sRzWHn*C z<4uKR>a*WRzEVps1;$n^R%zxq`U6XUow2v~p&ko3R`4gj=D&6xEpKf)%89qa+-G2non!-{o zD$Z8Sc=xjh`MkC{E+#aiMz38%_07uH$hpIj-*zflkS~suBULpJP+GUsh*6eZ^U@~f zQLoq8d%3xy+IpsnkC*4#@|+6hw9j4XGkV;bcR!!6dCltisi4GnjR>&15nsf6;9lh^ z)RA4i!~#*v*YPQz79&L?FC}Ca-9V4j6(!nI>ivqEtN;F4w1F!19DQxlF!^a&{MASB`hKi`cE#_5#YDHM$*nhGrw?x|q&TKr6QKnWc6T@ySiS77pVAcq*=~S(ouQn2{77h@ zWm?lyqD+4JU_o{lNA<{=ENc4WzxL*LG|*wMJTqS3I{KaQ%Wk=(_RS*nztq8f7f)aQ zZx>}}H^nhN)DBht0~+zhq_v%TQ|D!HU1@jVps7mm$!))W6I2$1BCMH{VTb$;K(2$EkJ~!_&7LQs=a&fJ^ ztd)v@M`1J+Z$}S>8?}p_js+Xa_kRfx5rVi)}yalZt>=Z>1{sv2suUQ0*q+`W(JS-yrx)S~^_=O+8O7GJ;leHEVY z-V)pU1My`$S{vfzCG73ZBeZ@$JNA8SbSPbN*yGC^qrEUSiKP_ccB=Q}O|Ks`;&yg1 z{Fs*ri-kBOFiZIgUTRX!Oc(<*QiR|WSPEbGzh3c`4P4dydNJ!5y|p@(UNzKAc-k8K zPd!5TK0J}p!e4SwQg2jw5st3MqX*amsT7SS=RC$4!z1w#Bn72j*zm9m;VbQ&hH>breaknA<9Ce}^W#MdH?PcZ1^(#)zGJ9eGgwUD zA_=OCl7WUIcSy3aYttMPJ7N?e~mPn`*k0d4asjG7NdVV}5 zv>s}OG`&R-aFKFR4zh!6^a30GoG&d97JF_(`uOPG1vO+TMmUuz^BSjHx!`!0B(cU4 zYryGVdb!zApjfu?rz&3f`i4krJS09}>AsY{KXHa-!pmsYf0Teyc!_#AuF!ICmC*+M zP+)k&h_^*#Q#Ss%6`;N)=#7``3-=hQWWv%}@NS;WgLQ=nzUX2Byeh7BjU~as-LeG3 zSY&}^s2aqQdKZrH(-84t$sYQsG_`5a#a9(Lv$j6sNU&J8nj#Eh7lHjh5y&NhgX+}G z$Y3Eg^m;gwKvHLpC@)Y-29}f@H&uO1R2TRHAjip%DKnF+6jdr3y@`Gf6q_0*MF_6e z$fy{AW+@4Ll`pF(H3b0+U*hZT{_r$gG(pX6^0!R%Z}{my{WK8MX8&x{V8g%LEtb1* zug$VK{mVB=;0WiB>1(ed9+<0eEpG1z8N&(v183ItoIWd_YT38X?Cz4mhyZ~VG(6oD zIIwl{>3netOJu+1$ptmlt7^gzz+wWV5gsAT!l`nBP8JQtYes6<^P#dh`AMM47d6!p zoVXuWd?8#l8|V50WbuQo5k!);0LcUa5Z$f&tC^6yYO3>UlACmeb#j^#LhHL=wL+b1 z_p0{btOxnpx;RbGX6NE1MWy3=SL)DFxIIU~kgIBT6~;qIiHYZ>lYfSB?oB@KqXyR) zkWa6aGJOxoe8C-Wd$kJ=RF2%|cY57hrW{f>_E<^whfd%(r0D_0j-IRW2i{8K{mom= zwnQ>m&{%?~mq5K_i)LUyILbMF$DqHcDW2dt@nOHwp(X-yaWfui4rXfT6*IyAHc|4IYe=RGERWQe9dfTgZF3x^C zpe+}yU$LztA6RG{AXDLgS<3Kli{hEly&IbmaWA7LyaR&;$AzK5S^xrDhdiOCa7X}m z@`4V0ck<(+cMno~S!~z*PB%v2YW?Z3Ph@m=C!|sB5TF0+J#hSPh3Wtw{-8onhktl* z$xT68KqR9G1VoXhQe|1v>q!q^S(Podqx4AYA9czmv=;(BHGq3awD#C8ytE~4Y~E&>0f8uUs+yIal&Dry{eaB746WEWx`hq zGIuX0$xNa4S3os}w*VnTN!h*s4MmDSOtiWjfV=e0@ikhs3oEyiX%$5Azf60xD&p5C z9ae|DSSPwjQmJ4<6SgUKnmSC}IjaTsPp7Lh6ih-~bM_#qGqVuL(>U}p!hQc_Y zMTd|WbL-)r7KQWs9nbQC=QudkA-=zWy7iL<4ki8nVKYkFt@>2G{D-v-zVHJQ&w3?A6( zBThbbI^`GW++d~hP>8IkkIG%rbQfLu3l0t7>u<{w=F038r-{WxhwqhTi>47Tn~+ZX zk>Xcs<&qP>hL)%znc?CkgVF&|C7kQ;V!apE_q9#Fow6I4BQKl%jTieP+I~)SzQOE!*6J+t3EnyFlCkbafi@U@6zNU3K3R!so|14LRPiE{ZShsm0C*nt`;oJuV(W%3Hn#t zp1HlZ=a)zBTsNG;5lPa`U253tm?ggS9w9N8@dN+rs&zC}cV4E7b1O?uD*dWMb(qUB z2M+%p4LcVs$;GJ+)DiNORF~AQVKweQ1ExgxhlXSZ@&(>V1t5)h&D5o_oPc;c& zi$CWbk@@-VN0a)OhaT1X*6J4enupfixW<)u%pi-=9{t7&D}{eWHt%xu+l1e?PAUa| zH8J?C7%8gU)0&4rhK1Osi!J_ieBLSGuhIX=0zO)0UH0S_0JU??WQL3!0x}A0nxV=D z5g5etUh&5Z~b-2|AKqV$uCrnfDu&b?IT^NZf%{cv49D0_myux(kF2TEj=$q_z zB2#AjJX%Lk{Z>Q93>^C@|Hu&eMA)kJ)6XVRB>BS?WL^6cWt1@VQG5l8X!oGox1zgg zw&ZVF(Z<__S65pP1Py#RG*s_{nzrd!d^>b458i>TsAV1BzI;HJj)My}RJL@8QZkGt zOCZbom5H)=;bZv}sI0+VfSAR5)jNV5Bc@XoW_&jTzZ=8L<*AiKpY(V`7F`9%5!7VY z2&sUs(cLgxq@(1ftsI&U-+^`nVQtfVi{xcVTIX6sW_)oecK5@OWW<}ezb~O@duM-E zpNmT37(Du&sw|UU{6v&`z3P!Ta{1EwkMyUH>r}>)tDm0!JJkBL$s%glIrWJh^gsK4 z8&~Jw7NW|_GxM4e?lc9bf!pv`?9+--E_!ofL~ITPOxl-~t06Qy9P%y`idwI0lG-X( zD_lTXDc`7G6`S|wU!4vdVIKHQEIT47_mE^}7Wh{vbGAOqGd{b-#T(sIlTY|{bBlHl z7Zi>zv>#c13V#t5vwf+vdT3H->2Lj^8e5h?dx>Q$pH){my4Y(W-|{NI75voh<%{>K zLk_`5KTe3P9I1KyElcS^66OS2c{^N1-g#=7sy@KBOrTtpS$q1zwxx8w$m=2Zc@M1Q z=-TC)&v7ju!(+B}>Q#OLQ9g6h!t1NLo1fzc#Mc=518n)!s<`c=ov&-!R%gav=dDln zd{%z90lc%E#}cm!SF$G8lStBG$BA9w%{_I;S3hq+MK^H=rBN`wCPG5oJ1$A11Nm{j?%X19&LJxPVSkd?dY6uEQjb*FxhQlTMa z+gZRPd)fcbCn7-^|Jx23LM zcP@592z|_1BuEvhMmi1++`IAevQgxVD%blrhp$;CuFekLzcpHmrNUL*IvU5XyOfQ1 zNaKsIW_r~h6j$O*+h17Cb4ix&SYqm%g-3n6<$cUPW1UOW3|UkTy|A;{2`ZyC`Q>7{ zKYzXS<}S6nsK@?}K}3zn@peKRgj*B<&#tVzh?egv%@ePXu-o}8k@Km`?Kv6_ z=IcV$rr%EmfXl$ZI=anvhpB{RRB4)*-3C}aRGbjzUu+k5b@AN+Bg^ZfNj$=RaqI81 z_luNqK{_i;ntaSkUCy36(e+L&0AAX5w|RXOuD|1~C=%1>KdPtXGjr`o$=x<-yiqe^ z*}d*2R!BrQ3?_%rXN^UR1qJ}|;w}d#qXoWSys$+5)g5m~C4>8t)?Q5P$Esb~@nGp- zqSmK8AAvh#a^Q~BnNA}!s`ojwXKg|fB|`DS%|jNSRt|i)i{O;+@)!=sHlJhAX-6)> z!TyVASzWO^rDF>D<_#=rYukdJ&;Ka8_jsoMKMvr#u#I+ct+~%Fm(bjY(U^NGw~DCd zeo2~;du_&sT;`f<%{8RHbEzcNn9xmb3906;Qq3i)l;3`T@3F@@k8}H+^Lc+>&o`oB zn0QPR3s7E533qgGPQd$K9J2h`U3;SvY%RyKDB)0uPVZ(s^0aR1eO`Zo9njf$Y4lbn zR6O3+Fh`bVOGB7UX{Ne~hvN-j9a074yKI+?-4|OZZCdNd~m+-xLPzqD=RQM4mY--|Ct@GGnO+y8xe5$ zs?e<1UDLVb=p%~D1T!(@?P$rPxDUQ#B1oLg5ya$}7cDDH8Jv&C#WMh47s*5!`ReOQy`11@0@+@~0#b%k4n}_N$$r-*FP=wC!f|SaKIyG3L%{ zVj3+ZnZMgmvwtI~%cV~hhcq)KS;ENV6`In{%77JrEzgrjVh~_Z?^XT0M8SN)uayBT zq$Eu{Ip7ds73w?KBYZnz=wj(u3A;{$7QDlarq9|~Y(*h2jl1H0c|kEJdck&$+*E5p zDY$F4DjgA^Xf@-2cw4QMjMyXgiBl`4;h0@=n<95g$MsN4KIjV$eD!ampVjA)?2JB& zw0$oal?8x#^LzJZ!v-ujp=s8fTE(eGut@*N6N zZj=sgIsu*Z^Ww6>N*i7b^YN(60-m4|1J=P@vk@6xxeHd9oUA60u!!VIu+057Aw1tL zSMT015jNXnFtjEgH#0APCSq2!K;K$5DnNFj)S4xKL4O)*4wXeN6k?CUFKa{W>Z88V4K%PQf^dia` zzH%^pKBhum;3|G$(Z8I@%(MRohQ$IrEJvw1VWq^Nqy;ThSF2O3XRQn`gJJnW`8jnQ zBQu4E;@9;Nr$y7CXQ!J@_Ld{!V{{B|z!yd7)mlk0Ej4Y8Krw(a(zB1Gw$QjpXqm`O zURaOILm$8vKAY?}-)d#%tk%@HgM&wF6?eZfh0!J!#f|X;66=i&-FS|$p6v@g0+wjb zA3<93d1ZXIZBg>P_Q}>SCug^zR#)b20!t+oA_Y$BWHc%vt;Y1A&NnqjcB<4kM{XT6 z5Lf9ctS87!|8``^Hor*Mb`d^Ao=bca%ftTU8-(fB!q zpD@N%3JJPX14h+11GV{wa|`-N0_F{h<8bn|N%M+s3MUjfbx1&kwv34VFrnE;*q9Zd z6clt=V*N-MDZo5#0E)pZ7=C~o+t1sWx!jt`#0ab3hs zp2fur{VSoS>PGFqJf#^uC}Gg=}J*egLR`?N0wd$`TXT%Tci{|?*VgXXX8fC3e`H_cV`+r-shw@yBYuTd2mV~(*Smzv7faM9L_#*M2kbWns%%G z?W?Tti?dG%W&RMG=GVT=>|l%d-wmkv(Rhi(cs?$k`OD&hE+hP#Lp8Khsq6fR}?56}L)BO{nK;{waSb zwX8ex%OuroS8MC<&Z(anjL+TWAx}0ipMHBej4_I1n>K3tzlAck?keRaQ3AfujA?Ig zgZCsYsVZ%TGE8l#D_2}9zP>ZN^Jdg7?}23CK&pbH!dt%{mo4J!t>FN=DMiSO0*R+M zSYOy649HMDIP>TSKZ@g2#=m`>Dx)sa8NN5yGBN0bP+#*MXq?_#Wkz0J* z?<_wRhl~3iqV)-I?J?vo89}01b=^GEeV=N+m4vMqGrxxDdmBA)4gTyJ^xxWXfmG+& z4w@2685;oqbXU|TryQ~MfZF+g1YG`ZczL24I)p(=$6nsVBL1vjmX1bMldvR$dyA{h zx0AbZ6;$X87UCTnF-dU$N%DkkGbrecR9pt4(?!ZCMkCfe7fSuNM0*d?xBx;P^bgkm zc|r3j`NC3yGFn>IE74b6T#E_vWkOr{h;@=$teC_>bkf;PlosLmce2Ry0uYuNYvCnt z8S3*5nzmMtns!a=cR*u#s_Xo?Ge6)0=_`w$>^y)RyC!se8@25gFvx-xl5+|$B83zv ze>4`e75hp8yihE3NzC}WYrufv`Ae?CD@@ch1sW_S$|s<1VHn#Q6cA7d&<>I%pZ!Te zLL4$cW`bBd^J@bIzM`DN2&#FbEawIO9D`b5BE;DIJG5W>? z&@ET%S3EsEI#dgb6nv1b@=k2H=0OAxvV;?nWCsEHdNEYcQLZ%2yL5-flyr#Bxe0yG zfXiZi^_j;Wxg)p5P$hi&PgeG@M}}qQMPnAQ-}In9i>RoTs{HA~0W4w%AOJ)`+bS()BR z$@G@LNQ3eLp7(}D>X@Q2?7di4!A~qAw^uYp1?kfkc1sNYn6zj99VA2T?aHa!>5g7Di-Krev!uLL|7B=qx(RELK=6F;9gSkwi*ZuyCwM zFyLTfm;`~4zs*DZxmeAXz13!Z>$V%Afk_%5`nUq6RW>}9Vo-lMdp0FR6^f94JQZUO z;`<1^uuII2gZu|j61#-r&!Rr_6b_D~Hu(9%fg(|Ud;UR$sIFey6cqIM9kXX@?tT`s z>nO2))K^ypW6~b66Bw|8!VUo0(*ar%yZwicx+JW$!$ehU4*fv!M^IZNXi|b0 zV+8pZd&suQ_7hXxm?KJw*}eQneBWmt`$ucD@Ws93vZ!@7D!Dq~76ujNcXXR%J;QGn zp3NC72__Mcs(Up4+WvBZ-^NA&M~XCWs54-ndyi<_^+a}b{?-6ao^JQnQ4l*l>> z^^PS{j;*UAm+{vv-ZGI>Og$V0zJWn4Goi1t?*4xGWaq^b4e9~reY3A2B86DkSe#Pg z(^#%>yhKkX_XkHTLiQ+GVz6CW&dusc57?Lmna~uW@uObM%E{@76!BpR!}paX!6Y%5 zVzRKd8~9djj~L!}RI`d}z!iTfFVZdJ8>V2)gXCdFviMOi=X8!^VK&Laz9L*J7pV11 zSg=?btQz;3`N*cGm&VGe>*6{AAYZ-i$hRwPkVJkZop5=nLcui0a5#V8^+)dP_OoR< zdsU8V7&;%SzJ=58!MhH4*!U=0>ls+cB+XnFRUQZq9<+25qRl)GyEiywK1dxM6p+7b zgcCfpL6VCe6=b|faD4X``Gq7B@lt|7Hpqt$G*&)u?tZRM9Wb4JF4K6`CZ9|%5b_g) z-C`k(E}>S6?&3)hfgF**geFp;zMSWSl`o%nzcibrnE+of;6)bH1ct$XvIcF7*c5&1 z2uW4_mpiX`@|t+75=( z3ve~m0~aS%EG1G}-ij#uhGa_$fahf%qBTht2S&c8*6Gc^8mhP|bPV*K@ zz#{fi5yN8e;FDI?x-VjlP$oq;cKGmXa7pdcV#Z_<;kjKx_$vfo8QB*imikC+yz(va zwB)V+juScKPP*b)EX=+g4t%ffCkB7-iX5~?P6PIwB$KmqPK6WT9|0dWH^l~IU%Y;= zBPL|hhJCI-Tl<%fd~r=Sw&Un8KVzvL=#v9;AxW+pI7P3bXhj zwvP~_u?j%A%SkOoycp&nrZ|Yl<0YY|-=7H*A-9Q2JO}qb5@4t4{J*0jBQyGua|c_) z6^-8Owa%zemC}DC#E3=KmY{;I7eaav2QPkb%U4+qSlA=AZvxYkjhG?1BDM?v!&*rm z?1}BDb#eLWVf9!0C;9uKZv^0eS{wG-B->TxvTHTFI{UQuwKswT zYVw|(`<=7od_7p750k5nI#s@SaIMDY!zsA$XM1a-Q6^#>&{n6gVzjnGQMie__#DrI zEW2W6usWXpqSBWU!yhEH1WKsb^3d-Z`?Zyr>)*5dmzV2+I6_HMu0WnQ&@4L@34mzc z-z!%wad=3)=03l+<|H-(5=k}(d%xBLoDx7_~%S?R_3KGfMTbrPwDh~D~ zhYI-nqJI{PRFLej)`z>g3v(Bg&PsSlh@;)s4n}bGBgHiDs~U5JBgG(=m8#m-YksbL zjns=xi@mI-&o(MKzAQ)yc(XWTKy&$vWJ|@lD3cYA{&$W>$K$jaW^x??^hBmodJ}$t zwcsY8idhCtEZ`X@(4*WSB?b+-<+D1y zKTx*W;HM>Q4rT|?1~Yv;orqz%}>NM1yD}D^?jRnrwz)3F~3}|h`HwdLLL+d z)oURG#Z|Axx-z*}>c7t&liRrt*Cz-QD4-J3u_H+*vPkzovyq=%k*~-lk?%~}NFBk$ zxE`@GKy|R(13!I!{GYd(rDm~ThJ(0V?lVETvP#OWHu7w{^xgyi4ukqUJEOmhS4)QM zaV)r^TS!*6M^-(Ho^_oKb;@T{ge?v?S%l$1#JwkKl4Oa42p zfH6ClF&1~!-wxw9`RP_k>IPW@OP{SZg*6w-7G?BiwVK_GQ7l@TZHMZ;evtBk)FP~; zn4IJA{$>3ii-@uaOIm_Z@1;A{U4kdrog)%U<()?p+cM>DR+7SbDsmS~da7@|W;uP$ z3L8vVQo^jS(6t&K%LHQUUh?)=dIoCUtd8k&vn8$_T@@|qn($t(j7s(XqWIAXfk;c@Jcu(79`L;ARg(tN8%8M?7iGd*(h)@}OH z4?P-6DUr8}He{ za3gMFig8Bcdl=-fqEs04M(mGY%ZhP)DwJto?{kYD{o8Lq;c`vv#p|BA22#w}_0}IJ zO5TL!)ySr{?k+3(?9OUjzw|9CTU~L})!}{GPq+IO12EM)HEQv&0n)TiGf?jG=Q1IN z3diy0^>Z`ByqT$RTDE-3bMJ2|hNDvhva2_Z zs!}H1zzp-`zYQ5^_om8~B>ty5`dtc}sF*xn#t2O2`!NQb0(kXHnQ#?_{P1a&9XmI8wD%{qkIOt}1SHLMn*~2 z&_-^pk%8BvO1^0UD}DE(Yq_@~KBmv>>wEPd`n-mW*!GuM>4aMHg(Wo9xN3HcCcvxS7M!gfuyfMay<+`a~u_eQI&ob%CP)An_GH2=z_aGLwk7^5vWF!|FmKM zV3*9vNuDGsJac?%Fz)v#qOJiJOk!C6bIT3l&*hw5ojOFOAYzLPq;=gE{kKaxuJi%+ zo|T8FZ?qdkscDLkH21(M?9{NG`EzDH)XC>=;H&Z;s^I}XJ`~P_OBFp#dc znqyu>85GTO74G#5b2o-TXC{D%GcKydxmUg6E+dDd2YaQu2~f8Ps)5LqpTZW_!Ez}I z8O7x8HKtGv7j817(o!`O4hssg`FTNg02qyDZ`v94A~Dn^TNh}f@L|m^&Nl!(gx+t( zw03uVijn_S>R{~ZmldXVR3U829r;eY;}Vl7&ugTuUJT8P)(KEJ+c%HP=-s`FZVaX@ z4%1XLl|}5xvyJYb(uzs0Y3L)LE5`s1rksV`3-Mez9#%3?N8c`HvRCS!ri10T>gGy$ z$^7Ncea?f{*-y+rtAD0c;Np9-&T+)+%L;=vx|Ka0BLgyi670i*I(O%co0uRYFQWm*pGS*H?6hmKZk5fze{BDMOCbv`wB}cqmC&i_l~G+sXCKHde8Y z&~u0cphq{3YNpLn|KJ<)oVpg3v^p0oJH^2g|8eAg#zR%f>|>X9XH*qpLcfcuRokD4 zY|)+1thZ!RL8bq|`3(npaaWe<=y~AXFEHBb<6n7XDQed)Ti7UHf*!jQpb!tkikge( zU2!4CInP^{K9vu~Bn!d9y}SzrAba8tZQlj&qoUpR6?b_{@@~yAMJyJS#LwVrWg@A8Pt(Ig%z>!v+;!86bVdvS!C15Mu1x<1S<0W4slWd!Ub#;$Hq7uNXm+XrwCq;z4ei zO1THAs*1E-4lVw+hQPR*3U_bUn34YEsdTPdH4%s z+sNq0p?lCSuK7K~+lNk&kH=D!AuWwi{Qms3=swjNE(U0Nacq5aZeDie6CAB~9lKT^*T(l%A?@CMRNLBT3EAz@N z)LB)fwNfF=Do%a!AXnmBKp#H7>t4NGM?Y^jVewEnmJ{oBOXWZ(-OB4^+UMc$H)hsA z<8O_OSQXm)@{HUxgMz$^7->|~V>+a72i2MrV0x5igMqZ}Ebaz~#cB#ZxOm&YoYJ8G z`9rI$4~9&IK2e|M$kld!6$%NR_;4lHS;CRC=ig!gvnqpc@<2qf#8&puCDP@8z*g%K zAC;76oPv5FG79Bv;E_AOaIZ|PBKzmnJ9}G3J6H4x6oWoFi zqM@eDg2+?C0e^1Q)f8WF6sw!dC5zQYKYy}Q3x4$=)q$NhAwo;t11T20U&2v7ehO-; zsVnb~lBtCzG1H~koyi$=X)Lm3*Z+Q;S921f)d8K&&4ea%=u%`_lo!-XQ<lPEC+& zqAC6&_B^4@+*)a z+F(2r8c!mQJWN}>sEH1x$7PpkX8?`8=#l))7*~dFGUtS0Q!t*IO7rsD;wQY3DE^F$Czr0*2D+e*Z?n z%8@SiC?l2yM#l>!G(t~!0gc9>cl)Sep(SKkxhZtj1*`+C7`ko=|tTLoIQ8Qu} z%a!OrUr(bPM-1S>~%00>p`AP_bSs0NX};sheF4l9+}b)9zF^?DurZ zT@LU=r3TKgt#uZ37m#|6%}7Sel(?w}xugd8_n%vVHHBu@lp^b$x}P4l5c7D{(WxA{ zX&+N4lwYH!;RW;`W<=wM?b{K8oL5_v!vruDO;AeWq}7&Vifz(m#qhsI(ELz11)d(? zsglTclY65RuIej;nR|6PBG$K4c+e6* z)8x|UFyFF>;oG}H3<1(-Ooqm?(k^*14gjE+Idpxa7d6h-^}Wy}+Rb}Xs-5F4M(HJF z$1Yde=-*ZK#O=d~o@!sNkOSgn%67Bhq~V;?2gYG{by6=7^eqWgERj0?3>rSHAkRwE zm2y4v0JkA;>!`(z#u53r_Gtb!i>ke^QeWk~fEI9zGy^RVQN=0zS3}OJzI9OC@gcJG z+bH$77gLm%S~6rEuP0KF=!~IH9XX$q84{Vm$Q4EyhMuxpN>>YoUV;g`7&foD*qp_^ z-i%TAaT)z7UlCUE`eNfT`Qfw#HZ+d&mb6l!qoN7;3k4pr&^H(c*V{k6HC#e+J@8&I zjb?vVT8rK83V$=q-N1T{GNJ$@VWGp~x+9Wzb1sxKq+?I+J70v((d|!$#$l&xQ=n0k zInizDB!2qMlxaU$x`8Sj9a?jwL;IFcy;{&!^&eIxhf`f0=|PiquT~A75uY$!*%~!< zQtY&{~*neGJO*PIRiN0o#0VWFqU1@kcedj4*LXB9$M-)#SSxq zFh}FwL!)5nNoc5)CL;kW90PmZn>-$H&e$oIUbo8y9*z|;44r=TBi(OBh&^@FGm8;{ zq5HAZBlyYzA z+O491BNKNi)DV(s%w!!2Mla4hQBrs$r4-`%io0HZGU6-beEkEpM&MKc`jpYz-*-R$ zdHQh&fr`01{5=bLgabqm_Qf-W5SeGEU}>=hO;N1oI>O{PSt1=2=hYNFt*Q5qS zZv#WI11F|k|9l=UyFFD=Jdi|5ugwA`?e4fM4i2Okk*>tR!xDXxyy#dKP4^Pm*p-GY zwg2aTLqGC{^F`2y>f&HmTA$46J71^sV(Rle%n^;(bjpu@!m*`X8^hETkbl~)varZK z2CrQAM1s3B$pMb-KEI8n4E6{7*GR4Q?5&A`)V;il)?_4aH%n2dQk|(ENxmnOeCIYB zT&^MnqrgdTNZhu&gZfB2{PZcA_s(yi_hUr#FD*!@AU4JV(DA0-z?beRmA3F(AO5~i zgnjV3O-M7c5?=xxU!`k404XIhF0z-JZ$WPlLh!yCM7@ z)_&-0*nONEoeu`*X=XE6LYXSNgu(O0*t3o|LjMJ0vX_5TuTv%pjxL$_Pkc-}v63Df zde~YJ#skG*u6JO&_MCZ9KNgtU3v^*Y;~W`R1QHYby{|l@R%~*Q-Xvlo+iMJ0~k_-vWpa)@TE0TG? zeFB}$DmQx^ukonB-JOozKtvQrLVg$=Kl$daRM4Pwp2|vbJQk|HANXz$G=YDNA0Oms zcR0B;Xb}6}F~4}3Qy|4`azoroLNC34_4as5T9VUJ3iA!&_=A@m3%*W+N+;-BV^x}) zRx+Ovi<1?RNef{`1frL<^k0ERQ5n-+ZP&vt>3!UIBZ+|thsD#wDCw}8yTMf9ocZFa zsR=Yk=#BjeDqYftb0KV4DD6_FHm@cm1L903Gbx#&*bDZJeEJd}`IG#&UfCbZmL)UG zfzV8{-ij>az;J+6XIfw8G3h#JoI6+wM)!Tlh`@&J>E{g%^Srx*_C767VcwS|<1l^y zCB@TYc9#|cxBmlNwMk?P)sGn%htFzb7`}$WQeHqQEI1euzJy&zZ&zLz2BzZ zw+%144aBg(gb0QM@1Q(M7-v3^T;N@P`*VfD%_LW-MQ9Z30aQ({Uk%Qnep*-TU}#%4 zXcJ$;RDtgCjCjm#>}jK`@#aD8wPeSf(v*O1#W~D82j#+iCD4{B?kUXmHb0SzWP~{( z1dX8*I!hPd$V=QVP9a0*t@FDc`8fTOaiNv%y_r_8O;98uq8sl>ae(KxOI#xfZ|%8i z*pB#8s51e$ODz7dktKec>U2`w83ROKkbB-~5KS-#3-sdgMF$6X@sA`;Xw?aJQ6;oFRc?HM?U~ zD)CENr=rl<^rTjXddYspV_}%Qh_q{vbDWNggWtnBdx%b|$3H^?3G@ik%lJ;bNK!>2 zjuD7~gmF5w)f=DP8nP~@pYlIpXMkq{Xu*#0SJ%};OX=aH^l6Tt$?mc6_f%@{dB%A% z{Q{x*cve}tyk&D_ajdx8$h`X5Q-Ymn*wJa&HKJW{RlkVcnMmD#_?(3MDaa3it#*OW z{W}_l07+4GfA#bL`*RP%woAy3Ag*Fgr&?B=V@D&7m#7I11bif_)bzGcJvk#HAINsd zOHRK?KRp=17)VHGBPg31#gU6-C6Y0smckiQyAV)o`_YeWvfzDs3;BWu^s%x2@QWu= z9}UxY$uVsvi0S)@o1NAbTkvDznAi`q(f9n7k-Q?H;3=qk;z(x-J?VP#0Q}npPJ3 zCqB&e1(vRpFa8Pp=t1w)$%}&-y6v&*&z?xX=a2lchkKhg|Ll4s@6`u4PZ=Z6bjYYy zJW43Micu_8duEpL`HrRP$^WifMl%YffYAII!|*rF-rR{M7+3B1^YnXfU*378LK=Qk z>#SoRf(f7abXWM1;nwQ({pj!C{#tDF=LQN7UigRqz4`fV`-SiSQbKb7--9aT?8irO z_i(6%?c9G>zgG)UR`aF6nL}Env15nc)VT^Nd|M63Q>$DoLLK6AcxjSO_2k7MExaj$^gLtBl7c@`wKSzGb&(v4cm zuNK-dE4J@Vh~@sR4OEIw3D;Y6YI{Cc){YFL>HeLeW!h+08Hyb`ImE5BNR)c2TopTQ zCT6}H;S?hJc4s437Q6-+H2*ao7i#rs@K>HBZrcV`M0mV`JhWWYPsDuIDSDmrOW@QI zE@eIUYm~o(IdbTCM=eCG?!$tu=)^V{b#_lwysXjBo#AYbh} zI#Jc?H~RTejD>+LS3AF}(BW*A$iUI7gH#4h{Tq*VjPiG!J7mRQaPvewo*|x1+36n3 zJ@gi4E2g-)KTQGNgLOp0Gpe|+t-=sRsfPbb1V9`f6#P^Rf{xVj33KZ41CLnnJl)n=bF#z1lZrh)s5zuHllsfj6QftE*&E9 zdU8yw(C=oY-z0PQgy7+$2-A_nuaB616!HM?W;^lO&Zf)VxkIM+*oZ>4hmVgU^~+duVba%vz+yilc{>XsaO(^Z(Avqw!czzD@b3pBGYVO<2TFG6&fWdS> z*pkJ(`~~A+7$0~5p?J#^PZBb1iNm8GHAC9A`;AkB56ClX6u#mHFzmP%bCH8`?^o)dn9Y~}AsLO;5!5n90^vLDg*&w2|BBjPV8EW#k#EEs-Ti1`1! zzIm1doIF{x|5|mwsg1I31)s1h(Z>zQX3iqc!)p%WU<pP#XEkvZ_DOo@&+NMt4v+Rm|nTJuEckw8WA#qwg*25{-G@d2}=g=6{Rj3^;hS{ zvWW`wrS=MKL4|6iz=Cq};-T`rk0M=YX_KuAW{nSWqkXxKscm*RWD}CiOx?#r+aD%zTKxE-?W-aJ~|)={sQqUGXoN=T7njR?nr_mKeL^Cp49C&@$wFJW5hmILOo zEDY|>PQ52xt^0Vl*~48S0einw-Tt_jqeM6WY&cwv49>8Ir#{F>r%{oSWDq>7P1#5P zsR#iO0%j`tw!h9hFo(we5eKaS_b)=K^^2kGXH>_6Ih%l+wZRODO_G8or< zYwLNn%F8$Z-ANUJcLK&)=6=FFm)ky|{;I}u2J`@cc=A6naJQcHE#h&a>p2Se9*@=0 z;H2#=GFnnT&iM~M3q0M_1rk#CyOUt#EsFlBfZ+h(ku2iTstQnR&Hb*CXSafurmxjq zx`sLYG;-JV-HWmF`(u0N&R@OQUduF}q#{W?Yit0fiZ#cAEZ(NZD-2-mAN>`~CD)pI$ld`?&3g_*^X}O=m$_^1+}z{q^lEri6O5hB^U# zBk^0HqK4#;{YOi_n%wXW8k-2Skh5(z-OA6M>jywi5};P2)(+chv(H@nhl=mhg7kLx zTDV{O`d>%=q6%`Y<5|>3#hUN(i>GE5=OMi%d3Z(bbKi!KU2k8IKT=*Xyfjk0F>Kvs z4MO(;glQxvQ_$@dx5BRR20`%MbjJl6Q69aX`_5KdK)g&rD)PotNS&~YwSp%JZEmgH1%XnThq6Mv4+BD5>{VU9i5Az=IsZF%t+` z@on6X%N+YX;(BYD9^G?$873%yS7D2l9^~=TZ%_XuFEb0f7d}ntq4_N6TvYIlQ@mn0pF9ZJ@f#(yR>^r z(1ll}s^_=Vl;Pnp@C@`3^T4DO{N%pw&vuGQXUDYOt&kW!ZQMjoTtma93%VaeE=UFL z_oEC)-O+6B)FnlH0QH7~-lP#<*UsuvX#2uq(#>Damy+XZ zK3;!v^KboQD7XuC7F;$Cu&5r z8YgOIR3LxfSc(N%)NxfiCAN+r#l{6m{gdyfJkg>164a=tbY{>0xDn3-NVPGX<=q$9 zQs-T1aA$72bw$Ag;3b(e7fXSd#2fJdlGOCsXX5$%YKNoS+4KlZl^Ruc+XmB-RXt*j zT>$VpEO(|d#j{ik+kAUzq1I)qrZov1v5i#4!^R2p|4J8biamj^P@Jrnm*!UdnF@*934Z5tfHv z;2Jd6IFCSZWYHimxp!VPi*B%4Y2d}q9-9T0a~M( zd{<~6wsxa~i$@1sdKnBh8y=)lKXOJSs}&TCu=Z&lUM2Dpp1$ z6?<>w2X8kMm8uaZ_@vG2K^ufY8ukMhp9bOqtanYvVL{m1I1a&ZoQvu@_A%_W=>qpf zjDH9Kqm6f(;V&ixfvKK;mOHfS4(>j>1A;)j{{vp+xTKrqfbi`x90V6po~^$jXuf3p z$YJSxs6SoqqRpe>(<*k;tH*l?8g*c+MwkIR5Mj&hjNjkQ0Uu9wKw!Y*bs3g*OBP~J z<9P%LH84K=FkWZEX|88Xjb`kRJfBR=$#A@zqH0RWG%pGY>Ejq=znCj^ur3uoz?pR| z@I7rHzR&TkFY;8?noQGzkfo-&KhBFWPEj#}YNfq#E4PRHf&|yOx@KS6&_w>QJ)aCc zQ9y_FX2{@E)f{^<9aUlaSyl*F$Yw^u|9KGhs8%n}}0+xv$-_vbHj4h4PN)s`_i6 z5;On}B)VwXB^v`ZntJG>$q!AfXA@y8faxX|hj~`KSFt42FFLp10ENDGCm zy7l2^Xf@Ygl;?|9jT21O_9}*s6`N}{hQ4rl6}D}x2;W?~5E;(sn*v<-sl2Ey`Dyr& z4tFfA-%<>GQOa7OgSKlaAoeDEwQU#d;<*)nr;+99_mH%M7$VNM&xn8X5=j-eneEt3 zyrcNBpvOJIxumjp1zb-5y>^Z)H0E~QUOdgF!o4@O>1^(|)A7ttg^&YJwhl0cPJHmL z@(Rl{kzY1*5vn}mP@WD9qAMYVQXT73)BI)rvyt7lQ~DitIPd5*y;wFghWi{1AY z1ll*LNtD{Vi(ctb1=tK{Yh{#KV|c)Qp&S!3p=0Xk|;Q z&CQ>ZIFCuAI@UDV%siL&1&UGLc)S;iO9f)^sVbe;*%`&)Fs{Hg-q(FX8m(Ei^VG7B zy9e1P9W&Tybg(x0s2L|5Pa)#5+A$nQ_%B%~j)s^osjI#AF{v~nSy?gNOd zP&-Mq*-cs0Bxq)aW-bP`c=_44x4>e7`>~^BVt=NJX7BkmPjSi}1#GGc;LP$|+QkLn zE+(x-o}4i$&#QLd#6x1so?bSc=X zh5P=OcR_@lsXSKH#lb3>Yd0sP&E`I2({SUo?*5=lMc<^ydoYc_otZB->`7@J^#@3i zH{B=g+2isml7h6AHo6d|W~~tLMkzXU!|H;spMyfQy#m$-L!nL;FsA4|fn-7k)`or9}^TkQQ4)V^X~a`7!Tadx`IY`!#ES9MUo z#QLkk*qy8_hZA(`AJf*jX9mP^{Rzd5m+nJX_U<#{(=1uEg9}9fz33`T(u`{Km~J^)W0EO~>Rve139OuW7M4vMjMr%z2N*XJO;{lF@db+( zuEF;FA8fB_Xgh({YG-ml3=TH$;C6eS^=nr5H_CD{o#}2NqV2vDVtUPPM4LzO(Le{I zMzG5i6UKWaI6>$onxVOpTaze<~v5#7R^UswPvi%-EI~UOF0WC(9G`B&^Mwj ze0tpwjTc!&!3DX!1~6!JyYugctmBv=$qV5E=CZ*DTtE>jIGh$0 z#Q?q=uqa`^*42UBSgHCTOs>@=4aWoeALkoY@C-CB*w^+7#es10u@+=*_bIw8fora5 zY7XbRO>opRXufe=>-hVPu#x8mDIM@z+5^l-y72&sH)v-6xW)^y7Pq)j z@pQvRuqm_GjIwEtBmUXGsFBTeTaLz!Z`-J4CNXR@Ugo)}f@R97xJn|nj@#`>#66@5 zPLb2nVsa5p7B?HzNF2DVGbWUZE8M`hjNyE^8>jmX8@Y@xosXY)np1um)p3ogzzU6K zGFl*9cB~oS#;lU7x#ozb5G@XM`P0C{`!^CbZ#9ksbatS*bwq4wkE@$u6&W(NSJYOg z&m8^KfCVFE(W`l%>fQjF;b{lBR}aN=b7O?98|o}0o|_3BDOh-RX!UpU@PH9-FGI~J zf=x>^yt|>f$0PzKIrYqZfV+Dr;%O^~gIncVaJZ3Ymt#K!-@D6=($+5Ffn&n^V&-60 zLKd&PxrPrtJeRnHm(Ze3^G24mKFjfbF_&*3j>ik2Fy(K*i$oSJgHei80Uv72p@jIGT zJlEj*HI*G`%j5osleB}HwgoNVL!PsE%F+-Ew1tg@*MTBj4>T>*S8v-qi4#uIv_$%H zEdyx^p#+UhcvyvVO0&zeEB1r7_{crSAkkoWsjg@!h`%>iPy0(y{5BRxg$Qy~fS>P0G$YKH!ojSOiW0TXhgA_qX0HgRupEqT@R^ z+Rg&BJRK&OW&kVlIxKbh7THJ#r3syK%iM zFq{N1!zWyvzOwPJcs}UagbSvs!Saj!g){dOw?AFhXz<#@%d3?zV_((d-SHd4P2T5A$=Si?8nY}N9OP~?AF_r{ zwvcy^A9FA3?Jx9|uGa5deDTtG z^7yV|etqQ?{;WErPqECtJY@74qY@?j=O)Z>`~gG3UrMH~Flv2PL+a-K`CRs$O_t{M zaGiW1nM-|b!VVh#geAqey+jSUh=!4GH_-GZ*D4bF(}Hp0=QV8aH&T?-Ua37-t7Q-5 ze-hdowW_RJB>T^)SHy=EwN!R#{ZnvyuX}2BS<=$%l7yX9nEmz3ecsh9Y)KhJHg?rJ zq&&1P-yZc2cDM#|VLi;@q107ZnsQX%RV3qr`CloR56P^Fe$>}L{pFRC9;hOIToO*- z8CMSNmM`QfSBU;6(+Bq%f3~b(=lXm7tyCc?hACa(1(ZvflnL!VS!@G=^parq_Y-#? zx7HU1O}9d?JGf>kzf7EVS`v3@(E3uf`LD@uGI3P7LDG9L%tP@=U+qzyOU#72!t+bd zpz^q?6qBQR!_Ss0SA=LD-j=R&%F<`ZFmLheq|b%dl2#JxJT*?RniXKG|L$VsS#&gP1lS zA22F$9&@wh$&=NMl@V=W4Wf$c6zGj$_igBCQYRHiCvTeF%us9Q)enWt^n}RS9Y0kq zS2y<{SlYcgbNM>-KKB5`d+Wh~oD*ckR=zbg>NyLak+!LDf&Fa1lzdhrS0QP4dUjD( z?@K~(DSP0k3Z(9%_u^S^uY945`s480zL;Jf6*~9hw~kSyZ6?#IEj)X1=_)ly#7N`@$!oqqhqa`eiJx{rY~LoC-n%kxYuP z5f8X#P%4X4hae*UN70@5GyV8+0N=e~wmF-7&fMn8t+{VaB%;1U&fK}FHrJ4wT&0lY z%uxxU4Y>(X651k3(vl<{e*66kdu*S_KJWMI{d_UTA%kG-jHJ+~HmdPXd#-PniN*{4 z$rt~;U_-O!$ue!`MqBrReSar8c;^8MJ3zEeJ_(AKUkHix$qR0-g6R@~3L6x3XcYuD zcmOv7RZ|}1{L4>+i8x5NZ zme{TbV;&vVp_1yQkteceba%d?*mq9?dtD(-KN)HG1GhQ0nl;pE#Xiw zq_3b#7(7AGmmBRXtC9~s0to05CClQyJ9 z{_-PH$iqgr0uGpM1$-9b48hLGi}ml4vP^5zgGZ(FK4Y%yyHYJOZ#du;x?DTAGsln4 ze;5=i1(kMf^W+KyF-m@5o%@>$^5RnmDzpi7ja+XoY|^YnJXX$nIwFs9PZs)mhFjU1 zm;z0{TWo)jiB)o7v_u}qVUViWsj@>BW1N`w6dirKj%WtcFdSf2)f zs4S(}__PZd(j@QQI2e!}VjD306spqJz0|z$BF-;v`BGhU(XVBeHik;vzEiTY@6ED| z9z;Md43M71WXkDlWKj7%zjNBOyo>aydV;k-oBMfmFoLJdTcEYB+d^ zx+;he$K4zF#Trp>`p8L8K~v&*w$gSL2TGq}dV0@Uj?>cudF6!AvY`W?d=K7uIwDQs z&4BXF!L5+9of3X$JEpP2 zgFfx}M!XVpp63B6H;G@vC2rhOSR`PzU%*epFyo`FGX$co>?d~A1Ta&-L_2?DUEWGP z!xG8X&h^eHi(Y$p&u;SD3Fix^B-S#MUBK@776LSn!*FfMw zVI>7G5W6_FOs%ln3X&G19YWfpwZ^TK?YFvS4Umar_g^`+SU)svU}h3|(^1IEeW6T^o??<1)=>vbdNgEx@;_tDm{|UF`1=owh=7^1d4f)a|Z^8MVgns+`?asBo zI^77`NQRxKl!RiCq2nc}y`=62g@i%f-3N^oA7zhOs`%VSiq~x8!&8)9{O~ar5;IK* zG64OGDfON%T3gMBlU|<=wvxi@$5lO8qNEHDCX{97hBxE)EhT2W47QX5;{b3xT`Iel zPV&-mV|K=w+?QecvjdX*)%knM!9CS{0rq^l=3u=_fhM^LYDF{S7ti`79L^kLg7sD<-tUaI@m<xcJh8|LOT8yCNeTYrec0G~{7fw(gCaUtEf&Npz9spmWSG7M6macOGnEaV zF6<^T|31j$>ShKeQFiykwA~+SLq|D=6cu8;RjWsKO(cRXQ~tE;#yeS&tE^a(BKhrU;&iFx zsp3$U=qrEt^POgW$qaih*$5o}{*3hi6nt$%?ie=B?BVbDToW zGA_8eiLNinQy$q{D50mNU__vpI~+MqSB69pLSPa!MMq&S zq930o+faRi^tJYaZUcHB(Eo`#eF|+!)0br1zjimW?B0h!&&=R9N$fe{)%trv8%HJ* zy%d$7@1-+8Vtm<5F&l0|D!5X_85GnmIC7sN zaJssDooiPn>7HZa3U5rMeJn)j(YiT}AR{uypv<`49(^e=1X^J2N z>py+o_ofYO2!(!OS2oL$0QIbD;hAx5-x$BZ5+zs)ufC*zbSIw-g->>rJD;Ac>n)aV zaz(IB_nWD1rY1D62vo%9S#tTj>xSOl?{?t~PKJ{x(wxyHdC$ePrsqfjwr>Z%;Q)MV zzx1ARex@kwkDTlx-`NYY8M;L{O1*gMmhsCIC!ctoOtH8?MT-G+!WWn#58CE1^LI!O zVf>V1y+AQ#P)PPAhmp17y417DrVC`;$vG2S241yzxHwhHy^CTF_CgyCtz@r>JC@?@ z_r+Ofd`lg80w3{MslX=5{B_l$Ms(qBu1bdUV8yUU)x}u^%g7V5`X+pb>>p4>i|~4b?%!F1<8qFSpds}s31*T)x?7^zuaf>-XemrSW=){Ek{g!;aIrUH2^x+A zB>z~~FGx`0fLC|!4{_Bdn6;$BEBZ0hYCdJJh}+SR_JL`E2kSAMV(g74i6Zd;D7;rK z+W$b|`9jFpg6H)N<+(E!qU_YPll}<{ogT?OeV_mf@?X1>M1J-0XA|Q8v{fUbNjDov zS0okGnEu{Xu1oAGa+U7TfY4+WYMv}|n2y>cOsJL|YIGitAn~r##V^QYssKg!BhNke z|JA>s>9HqH6ttA!`gaHs6o!!ly8OKKN`8jnF-NwI!R1J}S>YZ|STIF;9w; z{AwB~Ig@m=6BJvkxgm*h&u`RkOY7pApCxw76w3J|q(143h#hNM7txK&7QcP|jW07t->7k#9XP5lfzFfUI_ar7w2 zHPU$dfrR~qq?OF4`kO?mZ~B=j4i}y*DoDsM*5X$!>IYL~U&bd3Ti#=q?v)?C0O)O$ zyjIE3^@+8-lM}-cS@Dt+ozIM3MieGT@jYuvV*z>}F?C+^!}^&L)76}hPG{HpXxx5% z#|7d@tQtHwt$~uRF$%PDB@4fQ&&_o-=&LK|++$Po-wg*R&g-ruw^e#qtupqX9gXMgxlb9N>M zTnVb;{|keesvxr*a&4%&Ul#uZ#^inO$cq+9bGg~ATTvmyAylZ*{n|?`SxtP);N}@n zQ#loM-}28qEOW6f@;Jj zk_s`U%jQqxmwgrVKU|jmiHRTZxcdBjmigik!I{D5G7 z4t$`>0y~9lGjwbo;oxWTumG)`39ea$uU)`@QC8;H$`t4%VH#7UznX6{SiZQ0&+=R! z7LFa<%_#asu>DeZ(_O7i)bY5c2Uk%-N5!# z3;mOm(ZUIBxh#a^ZjT>TU$334p7BonuVUl9q!7adW%mPr`|zRHLue_;*Wg=CW%Ua> zP#_igx@*a~r0&X+WV5s)vbp-jGdgdD*mc33=1M5STU!EBqA~EH<&5RkZ^Z+Jg!Bd6 zSrVC7I2|jMjN%*-NqwW&UfmcbebUf3J6RSj?uB`@eWGX<_z`%1S5nBO$Uyn`>xU{Z zYc7ccw)UbaRJ^5A6%T&##>YKY8;bok*MvJwJ~s5e!<+EESwn^Q zdU^8OueY(t3qtQp!^F)iP)lB7GGPL)8uAFY-2er$Vpz{TpKPBCYN;UEL12V;m0{Y> zj}tYy{_k_Ymx<0C-6VMt1RK-&T|0bdECYpYB_KOaKCR-QCqX~r`w=*C**|6j zEfPB>f)@@d^`+TgADt~Pv8-cv?bF^lBx-bFL~C}--)Dz3^%}K&6cu;jJB@=989cAN zDqLjH95!fI)BZ~j-wf&HDbtVJRGs@y7h2XyM(MoVC5s=>MdAqiPF2Z2u>-*5%KpS( z$d>8smjHLrjgH# zlgHI7m^b}7tVSyx3tc2*)o!;4C=lhn{lhNQ3k$`wXinyp#-TFdx(;On9?#+mtuYRg zD(?&|4CCq+>+;TvwJM;bw%tE?_Fq0z$TBaRvEk9)+IieG;^PNZPGGE-y--P7k=jyHd-qsPBdkE_<4*V8pSj|M>{Jm{*5qZh`of23A>`P6N}gWd%7(Ds z&2P>*5pmF;a~cY_N=$j*M-`8dA-Ch+J1TkpoVJqhFLUC4gZzj@%jZ|6>t)C~pO0Kj zt1;okFY@LYZIcVkonLQXMq>x=b~GTA!Wb)ZMg38x}X0<~x6GczEi>ne)#t=p5D$ zS`=1sKfER7Ibe;$L{>VRJFUD)$j9TAZbKu6?7roH; zWDsl&e+Gb4^5x4Yj>cQ_&>>uJwtl0^+VWkLS|_4p_5z6KA|}fanOvnQQ$;AwRIfdX z%rokQbSEo(o&Sy!ll$j982!18bIt2u9gKDtl2w>49&+IsJlRHb&NHmU-+&xrD8sop z3H%gQOwhns=+m8kuCU(SX}hpKmUyga;>@~Fu8P*1Xo>!`=TG_2lp$xd;fiNb&WS8! z7ayu<#!OiU=`W27=wz6^Fxn)gOzHmk!zN6V$0J{y{2K1#puODd^TN$=@mPxTul0v{ zRycQgjuEhw%z5-!%hLVD<6u)m(djj~A!nYP)! z_#LgQwvd7uW+3zxpF*w9yeu zW0ToeQ^b9OIa4$*8#bJ8ZzZuJ=yUwXqVp;Jm2B_}BmNPsqEnS6&JdbSSn7F02I;PY zL7md``3o!L!QXA4lfaI;^huP z8J##4F36Gf){!c^A(&z_M6kE`)aB&rRaWVo7d5dc$BQcK-E-8Lx4+DN$dnc};o`uo z7wIP8vMwLYa)%{3<0IFl#e$Tw^UBslHz(I5<|Q*_vs};-AIhf@1dqPa;0AjPQBFM| zf@wW&R97vT$|CR}u8-*ai_M9gUlaeRD@Zr(sHrdic3v9+-P}?~1z$816MYEJ(*j** zW`7Z85wT%OwqEdR zGvLpc)icU{FIo?lkLdL{p+3zFdf0QIHkav7!y%_cUlWcB`%qaksftn6$mmj9;XYd2 z(^POVa^*@?S!<$p9b)BxO|7=0ukL}Jwwea!bRXtj-S$xsPI;xjN6)*m36|KW4YxmF z<=q_Pul?0Eq8a5afddQ(y&%Ih1{gi%x&gM8Zh14V0PdtAAG=@4K)pZJxu5?^L#J6I zhI{yj{^=>W-}0AEO|*As1WBC``ebGBY8D-hb!k?x8#PX-$T@hE17AI$uJ)b&qNKB{CMy^ARVL0o8o(L*TTSn2URjVRJ^|?{+@u{LKbDI zpFaMd1;R|1Mak>f9~9pxQ&{;2gcvLiO8niV1|RLsdR)s$QGge7O%oE%CM=o~p?4vM zBoEhX?D<%V$@GccSrm{v+l2Swi1GF}70`;Wg+Hr{2TT*3p@*2tl@pS^OYQgv#kHrw2fyTS8GQBR*W_!;hSa*bsD)XSz>oy>1P z4g=B!zt4;qXnk9K3ZRJU{k2Np;erI`pQ+P0pR2qYWqG_7Abepe#c=ILs+1@A6z&7n zc+x5F>atq9AO1n`niEP|L`zbZ-dIH3JDQB$zAH{`p8-!gYO&_5Y1Vc&quR}Z8` z-`E0m|Il-_WG_NTSyo0^%7+*xSwKMHyYYNG>YArCv}tnC;1AtM5!s0P#u$l=2+y@J z7#IE*U{w*0&qiH~d$xFQsFWiW9C82_I~Q_8c(HwPxJG_*c{8y5x7YPxFH6ymf)Jx| z^?TS6dEv*F+nIusug#BA(0nbIljh~A{hpo!=NIVcXMH|>-g?jnso{s{WWv^_h#EJbvYZ1I`3n}>%; zi>%38=^+%axAr~PRu72hR<2l7Ix0&sUg$e@>19D)M12y;F#ow`9FMiVAy~-IdXAsY z%F7S&6rtl&F4$;f_>l+K-^7{AU%eo)oJ=_;qhqDl<#k<)a_e}~lt{ua{;WXzD{Bi) zW_5!C*?w9+LYzmPQYGKGi>N-rmBiQVrU*7oV-_M0N`}D-kO7`+LY-x)hPCAdq3bDP zF^ldr3IO(Bc#7!8LAuHwJ~rz}n#0R_c)664Fh6lcK<+(7tgt=4_3O$rnn+x{|=KfR$uQ&5`ym>nMg8$3b##=HrKuiduJZ+k7FVHl~YhRX0MB^PdjiFKn!O% z<}fI^pWIUb+op@KK}_O19GBT+WDG;Z1^}tVbHm+Gj5g%yB8guoV#2++rpd_NQmKDW zkW(zgvtd658MRS`HGPR~W1**5=(4t}DPCN!!^t8)xnG2HDAzlg-Q{?ZkF>B-`wz@z zdki&3gxB4_a^4$0l^@I2I%_e}qb%!|$mmXd!bA*o*ec2b0IB+jtR_j>kYIJC2@S_% z>+v|lHqI9_i9sN<>3n1;(Ryb9T+O<|^AX9e9-5uu_^&Q~h=t5+v%EV39i2gfPD7+e z6OP3t_4`wfDly!bo+M7;L)A`0ssY@cZPaXR?B%nuaWL2fDI7uNzK?(ewINrDsC625 za}~T^$GF51& zy+lEuL)fq!)1e^G7g(8_EOcC`!W0qwCQ~Y_yeRyA?k8(rKmH1%PySPxw+}w4#%31b z$+rmvj){C9JQ1u^1suijm(gSmF}KevR4-fC$OhFQp*Qio;j)L?&tsB7y5`^6FZtFt zUwX5tR_@;nl}=gQ^~rmrctZ_x;p^_s}rGZEYtxWC1Vq6-bi$5tT{Zv zi>Gn@A)%`YAPHV@Ha}XgnrEU7y~n6lvc00e*oGV>Bi{ogKQQimX>9#H-nv+S?+*c8M7*`wRgkK9 zK{vc$v$0i|#1VJ`^8&Qway7n9<@!Utx2@V_&MgA!NY?woui;ih8e%K_)I5f>OSVIQ zksBS0Vv@Nl@>})o9-q1N*z%Bgw&}6Q#N)5Y@k6-l@MEY~W{wuXLwLQ(4aD_o&YgZcqr_w^p9OmyWut=pV? zU^?FV(e&}=oPO^0?sB`D{>JXg&)u>?-Lk*C@7nd;yVP_4dQU@BPt!zC%jcffCgLrR zLh~^*H;qPwxu5pzfo}=y0_2WU1Q}kYrdnLL6`qdFt_$|yP=<-96 zK58Q@8-vijLFC_7Jp(}euzT>af^LR=28tbMg3zDE*YhkBam@`KBDp_K55j%>_Xhgp z6bD_O4(j#xn*@j1fM6EELnH?My$8PTjq20u*S-MIUvbabr!DEV96Pw@rw8oo@$SE{)Y1(p!{=Ot$%!$*7N26Fu3eS2MjQCiy5VWLaC+JNbe< zl0t?P`VerD_KE{hGx-b8f8LY3!wUuDnjH8&Zt`?098}qnpZK9FG>)G|qY&*OxZ*5auEX0jnj>53*2mz4Npa z+c_fu$JRSR zdE}7&D)c(3e8ymATv8LXGUQQtj6jB~I%z~}&fRYwz}1iQBf*sn)bUy5h0C=TG-#!1 z{Ili7Ceb<7oR0O)#p$;THDWLCMleHzZoa_`xw`d>iRzv7Nb~ZlyM>02GMrP$;+Q1G#bL%ah?>s?cVV^Fa;p zI&#{L_BsN9_s9aXob<=`RDpbp&#KAacCuZ1-xA+OpQ<{6<1bJj0CFvp72PMI8t@!N zZJgfov-+@bvIXZIXH?S+M>T-!Lq30@;TX;;ow%Yjr|t>!8|(KHPyj5>6<*lx6BpBy z->Nyb;jk=_q#CFG?vTFh>>^k};H)G@Nd~;@t(5=#dXc8G++XSPa(7iQV3jwR((;`j zM}J#-<6a)k^g9^|6iU|e;^Lk~>RlYj37Wg^Fu~aT;3*z1|Mmm8d@0*usmfuLV;Va+ zq9=Nl7L?of(0;gtXG0_7UelM?5#sZ8w>F}7-nbi&%KTj#)2~ztNBzd2WB@CvPS8*i zeEuH%s4}0kqzb0?GuDO-&m(c7PzVyiIQJ7Q2xImGkMtwLW2#{07gu8l91Ud7JOagU zT{s3`Zu@292!pWxvXaaJiy^{;NU)3vg4!i`C>b17^~p_Ft1=Llg8Nj2!?J;%ew|sL z=>_)6D<*u+5cp*2wu~+Yc`tcBX{e62~lie-7>>U7X|P)yBZc7|vS{V3+iG--yGs*{U!Z z9#4LD#DK-o6cZ_1HieKN+-^hBmuKSJ$=M=rZg&;j<}78v)b4-$k^zolA&%9=~gp z@4tGVbm3$5${W86bIJYtp-ublPjA}r;eD0&>m2C!v-dS&?~Y#?3~SvFM3-JWxyi^v z9nt~{%28h#$VIaC_ZiesxN_?OH;dS;#)JMi<8odDu|0$OLSVz+sLCVMyBWS0A7N@{ z8b2Ot_^~P;UikdFk^#H>xeXmjAaYl$9j;(zstS;-a8zd%ilhA$Ghh9O0@oG}&2NU@ zVj;g&p(+pN{%my~K+)^C7_aq}XPS2xPWbSL@8G2QO;kWE+Yhgd|m5+5oT8=uSzps8deEjtl?b5MRIlmtT zet6-)mv>?1FnasVgNIdqH9e^zhN5BSD?)1g)EYlxS z^Tfn)|1yE)zgfTUizoh@y?;v)b{Pb_wD-&Ec1-`_af!fUeFVaQjdYd?C>mr?2}^HA zN-#oA3b&FBv$Ag$XxK?sTzQ{){7&4e3I0xakac}JaU)($JeIfS{_QyNa&-4>?`4gi zxwd4JilmKC5co*X?1+?jVf}z;3<;Q=>bo0nh0f+p2Hv_dW|_9L>dszU(-D@E=#@nMM7Ne*YR5>BpOrn%1~y(QI&jq7O*7YpU|FI{O+d=yW?@R z!OFzB%XTkgK{ns-NX-+iB!XUz9lw)!$drSLcg@}xGa|8(&O}DM3`~3R&HbC*S_L1) zk9~EQg+0u|vm=#c-xo#)g&jL|-+%O0`S|TI>P=OFEP6@eQu&5>607^8_^;^}-m$!m z@{iUD>%93`zoJ<{nt*6dNPFZzFRJpw)w?@7@@F)2=WK79spx&EZ_4cs5fI#Qe6Mfp z@;*ak6?-vHPsF|Fi}G;U#Vn(}w{3S;?$&WI)Q z`&+S_ZRx3SY+S=>UVi+yQE_)-o0*Y+Esi57|M}|ef(93Y-4(w8c=C9AmI)CgQqXN# zU94Faz6};{!<%7MBXWbdz0YX3Sr{=)j#?s=!9qhsGoI-mw?pwDQN-yH*%HZGe|b6N zr_m8zVms1bS6Zl4-jqk*8SHA#4$sw78~|rEnD|Lwj!RRc@~<=)*6P=f^SSd2rHjaS zOe*)@yl_k!W}$V$CflbMdzsYPp&|(PtGw$Y_9f0rju~wDkXfF)n2)tu3r@nralAEU;*sUSBJ zXos|LSb}^bio?!5J2YrK03k{ zE7M77C&YsEo5SMWFCS*cxl4vuc1P>Lz)itaobt2xswq`JNushdxQtx$q zvoKH7i{W$XN4B!k(nVTaV$b_|vjZ7)l|Vb|Vko&SAq@wRJTt+b8Aw`%Tj zei_(@4E~bChOQW8Gqla(Mb6WBrxck+>5i%|!4KH2PYfVmWfw$ynV(n@kQX7kv@thm zq!%U|{OwUZV`fDE9HJt67^O5tX5zYNP|M)2;xDU^Uz43vW%kl;?E^M7f(C|59{W|# zP9QP*)uuqMGL+>IMQX7J$v+<}?6R=n=LI9X2BfTXUN^Jx@RaMs$Vh;sYC};#bYdi`4s|hQ6;kUybq$Jbu6i?PvDd+FQV>hNC_b5541# zPR=;Ve}5z`vBY>{uuEB(G4HD6VA64nZx3SIQpEn~otAIo4{DL2aGmZS(Mwm)zT7q; zLMoFVCw9J1=gbiKM>xv$M6kay0U9FLfma;X+FSNPfe zDcGM^s(!`2;F!TKCM9br<(Lw{Y^S5z!Q_pPuoq)MV4w||uBLg3uP>tGF-9JbVf`Z<2pOdYZJ#F(O z=G}>dmvK)*%WuT0+H}~(GJacaw@?#p_*K0DUDxu{C=YSULH!F1p^`XwEQ$66Lp}5D zb}&L&+nVCV7CKpqEi+w+b)dU7yn%&?BWi{BWG!6E7G^FG*ca;h{~gh~3cnfd~) z`$YyYaI^rnOpm2OBu2#~uDGg) zDoWLHGmyW$7>`kEG%ZEg+K?ZZ(ms~X&j2c1f}26qMM;fGo3IgJp-~`=mkiXDSGe__ zqS4s*7OZ`N&$w9W`74hcy@6bp%c%84DJRj#MVXJ??;4%WelGN<}VzX@(n!~Qo0 z{2$B+-pZCcETv6pu^)Qqq^kbIgw7(L8zx(+0RZ^vc)9Gw&QND=(R>K6Ig~I1)(=Q$ z4~d3JPmV`%|0=pSi_bV*dvpyWdS&$F+u0}o64eNZ(rcHqO(xZrH7%Fe4;QR;@_dRu z7MV86cc&f7-z8fKxXGPbnPZnDj88EkLM&!dLUHZB0UdnvN667%aJUDrC^03P&9DO0 z*SNGrCbMPmDap##cq~$s1d)_6{m(itHyId8BLovu!$ni0@EylJC9cH55+3q{%&9JI z)Z}mJiHP*eqtuJmR#6&HHDnZBe|2a@Ax|`SU&D-+@msM6{jmWO9@tTR1T3#!vk)hl zd-{p7h)gOV>y_Aa}Z}}(rIFB@{>T!yTWgLoI#kC zw`U)i{KP&Tw9OfbIF;&hD)N9DVJ)!`0UE?nmE?)Xu`@rFXZ{9_1w@=esvN7n2~Q%x zv{Nf{&r!l>s8OtjcTvejsrvFs0s+JGS8ewc0{J&OafM_q&PwlxsOvU>A{OD{^_fx# z>gmADlCEPSCUAT{mgBM5ivZ_0j2Ay$j-(fQnm^#DoHcWWJZIcGYln~-XNCU}gxE|;dpcWvMef!pQ8MK{$X!0T8}|Gy&^m9d(4yj|LB6 zc!Fuh&d`&u%Q_Exso^vrac`>Z`^fmv{PIg~wwO!nNYA2yiP?S0GpE+-DFhOg)DH2T zN8;+i5d?UYF4czk#Y5%#?%aVqs$+x@-Gn@_fQJWEuUtCeQuR7&6Lv$^_~hgHyxt;%1$*-k*hR9(nPv+& z!?!&*EapKj-PMyz#bwThG!G9KT8Po$l=5`c+v(l5Pc{yrm7XaRV8Uohza-oM0nsLm z8Xv+}_QY3HTN4(k;cV;Z9K|ZXE5z;0)dBF&QJ5&1A{-z^8Rg5JR1{@E8wmHbC=Z@Z zf_+TVh3k9oM;?I~V%ae>a1R<#by3r{J9%6Qv?>M1b>Z9MUnM|ZTxkJCVvBv{<@Mvz zrDt9DYCX@|J;>IsPGrH-LQqjR$_lgf5(%)SASCZET|afb=F!vSbI_KhS|S;qlyPo~ zp^^Vty`-HuzijKD1;0?XBFtE^cYCT1+E0l&d`9U&T|gdKohh4 z2;JM)>Or5Npq@kO83yH}wp3t&duy%x(=Ssdn8Hi-lsyw@Y`}z^*!@_{xq0~|Y}M(+ zwz-ie%H|`uH};-G2efm^kdB2o&>*Uvkkk1B!Br3oGPVcTe)45X>xYq_EVO?3%MCKn zyXy$u%zb=h>h1THS0hu;$NqTqK7VU<k8qhbAv77c2@#Zq=bua!udgbz78XpeloEIn9Gj%F6o8SrsYxGfP^<4izQzb16 z9f?n{c+-6xJRAX!oZ)G7A%59TrPjj<&N`DM()IQy8D!tfGrp>s_4foe-2C9ksH1@; z5Hq0dp*p`@BG%?chZeMja>jZix(c4)27h2gRqAF+OfgR^`$$^UX1EncB967yKTOr~ zmbuL>i%LD~YdG>!?r#G;9tRI)q({{I{VULtYdnubfloy_YRIJ}Hoz}L_>7RVrQN9~ zHaxJ{^xk@SRF#j7_GA4Eo_1&Y^~PV?Xy2XUTsM35wnuf{<&Tf$@F|N|m)s2gQ%hL) z)H+L;er)Tw9jFM>C&RA-Bx1&>SKZ(`Q7LhoaOHmmms!+EH(vKMd3Oet*rk$dKo5VM z`W0H!RRnC;8ib?4Vr)XLW>CL0P-BvTZY+535;b*{dTkMY&FyKNC~Rf;NGaAPgpm$2 zaO#fTgs;Yw?tphL<6rTY!LDV%0kbNn>!H*fnUAl`-<`aYZ^Cc$_{6qA z0PI>BHB&Uh_1B#3GRKrmfkm^8gwU%QT7mIYMy?1}9)7J#|7IvsG(5eziW)|yUg?4u7?fTqqweqod9bJ_vnT}l z^Z${0VXt8Z3dw<8`70N?5=PVK`mekFbDE2tGdn#T0cLH*aa%G zhO!lNMPhX0v23X>$i>n0>o3xMHzBU^*s4;f5rX(DCMC~5ji~!`Q66M)a6mko$n;8} zqJO};_Y}M@2`l@1yCmW8=bGBp)WBzpm?C$9Q>n7cBQY0Q5|GWJ4 z%9MOEVEW4HN6qDte@@A|Ej2TncjQI$p`iylQJ}`4QEFPQ$M-sW-8Z!xaV{oV95aAd zzjWhY;Zzj`e<51VlWCF|s~oJ&E!|&Kj8`ERbxG#e@ras%G!8F@o9?WXRSv(xD+Umf zZjwdtMrJ#u!ja-4Jg>;W^|cWxl%~|hhPm3o+q{W_<=BVb1J`u%b23@@Pb0#ZqZ_pW zFRMl}ElBhEi$vdnyQ;_D6ZB>Rhf3{ahar(MYxCG6)SUTZXZrIzN5@sqi72(_jY*&7 zpnuM`t>h;B=Jl&63nL9Ch)KweWAR5`qi6mq`Zi-DnWKKP340Uq;j_bK2A9nZ4V+@H4A{%XtX@ZL9OF#|v?f z7}M8F&zi(hR}Fu?emHUWRO?lv-}^i72J@bs@BDMP|8>p(tJoE!_s^}CqABe+&CaKc zmudKS@xNwaA}Is(&UYy-DkmgUc+Ztpr;9``R#QJmJYi6!3*BnMu(_o}0`KM@qED*s zTz;XKF!`u5lUdy*8QZ)P;FHI0!M&Sr#_L{N@FXp+w$ScenRJ{<3&=r-5vA#X_v@;a zi4mV0sV)64S*Wher|^wzxqpq2Xa13bKE#~&1RYac+VEr3ts?e)`Tg68yA5wku7Dcv z`)|oQ)t9AI$X}?suCY{qH!rAOzP9M}xrTeC-W3gXHzSuC?%zokZmbs zdxx@^yejXp4mrJrMnA`p2@l>gQOQ~2%v?8!*j&0(i}_g1Tdxks1;!Wirn$E*(Q84; zoVahsfk9zoJ)cD|@%eKcSg66%`XcQHimm+oq5i01nTzDD1PcI=b+X=g2s}71djm46 zzNoJ;mKd@9E$LCi&G8|mlDt&Jk>dU(TQNXuk~CW9+rrGqiD$RGkS`XCJWE8M-h^QG z3lS~)KgnyZ4hdDsSyIH8wcf`Y)|rtZ+EMI0?~qKK5BJN(?nVGjjsK9AyY4tH!e$}oxhwf_Lf2w#_$?BA)6UswCwcALShV|zS_}fpEcJN&%BIH zk!quvjtd~cx3iRsJ*RE%9qHd%n`}c}$+(N)u}K!*ZEH)U0MT*S)f{iq^~7Z}!N+$; zId4Uv6Ep5|-un%Iv>bu<9}Uw{XQUginn>>=@dg&*W(Ipe)QtOc-iv-^Ft4prP;Rt^C57#WpM{&=0{HSt4)CFk|PNhF=jze5`_s*u#EgP4_1 zkttJ=LxlgL?xG-~Xk_p=V~;KjvBYPA85A5#GPSKj`v^akiV6xf)|!1O;zi~4CSIvEN57e5HQ0) zx_Mp8?t;#0%?sINE5=iS zq^mV=p8@z-5kqI&#MmwDtQKBy7rA>_WA~nxd#SV0aC?%XM_Bp|{WIDf#4o_^_$Do- zow*8ID>eGgILT*W{M7f*;&86Y!w!#bh3T9ZkKUc;ak0~)TKmNn!~&3+G?d<9Ga`dS zzxp6^*xgU2EjlCN>9E>Y4jd*qTm^~MX3jwr;t(_Qg7AZ?&xV}Wt32EtlcBt4%n@sE z)U|89-&{yRP`l|gizEdgda)C3yBKY?=w4CuFWME~oQJQvs->P&gv80OWL)wToHyEL24U5k$!*}p+|M7dLQ@GDVp&1g^Cc~2Vw9Opp+ew+s{b_vY%j=bM(wGS)P7Uy$`Hs}%IJ}IQ0*ug zOj65~IkU6oe5G5Z%z{Ryt3SlxsVK?{PfxZ%JF3_fxv)$&aLvye`6_U;tm7kTZse~8l0`xwn8%uw*t8u6Zn7o_`zbTczmGXg~L zYCT2YHh*fa_23P8F<PF*F{VWMl(Oj4VRGcQ(vkU{|NE{~u(V&b1w3iP&` z$~PD8siYVD89GQn-`DUqdTJ^2jKrX!>*(OJ5&Z3Ou=O&Uwn z6E3~T)FFbXb9|`)pd*o`4=bdr-)!ZgzV-|<`8sz&#@bX;VjHqK9r%%Il|Fl* z8mQyL(*Da;<9cAKnYuym4M-qG;z5=+^NX*es>17E`i`&qoiGs~dm+`NhdeiSh#<*> z9%P|r_pJ`_ztE|Yu#mR2rs6Iqg=GRdsZc41r85Q;@W|$K?7@U~X|W#*=fJY{bCN}u zzN4{>2;dzN-46j2g&>eY|160EBFqi!B!V=W1@<(7v!5hc^g-9LRNk*t;VWt@L5;0c zgmup!EWIlFf|otVQX=KNb{{Y?!-Ds|$>W!d`NkUb2h?lRu^E=$|)4S56rU1dQ- z2-Rx)4J$$4>uJuLR0T90XTs9-;rIiX+VLSK($x3zeTRk^mZFgaCFqHF;8-*E_}V+C zAVtGc5Yo;oXl$!ZMeiWc(e76fOvLL;1lrC~ErReqbb~yh{z|Majo(m>~rOJr_J0!~H9NWRI zU1H)Qbkr4N*>-MD4u8Sc46uWbpO0ClQP2FT39#*0+q!Y7i`Dgc!#tnZHoKzh2jnSM zBC1^wRbkAL^l#WvG7tRH=O_=fUZz?ZW_@mT5&t`E5G{{YY zqx@7S5!p00{78dRZPGO~+V@N(d`NyVV@nCXu;6g>7$` zCr6^$R8#yMvWiP{jM_D*{uG-rs%1oP)F9i!j#Ht)RElTY3E2*d?93YKcw{)SU100u zn6U}QQ54E*z*dW3Sg^oM2sRgIv15Da3jW1*oo#6&P{($L;otWb8RH~@6zby7h+1Y2#3ejx&;cy2DbFw)9q*M1qfNn~! zUp1ypF00Lq>uImM|AW*5e3qTnF?+Lx z0|$ZDEf}4!m$w+yja0>U#60FlnvDV?Z3JvO>@>|}TM(A6#8RE!MOZNcxYGjLpc~fB zVEaz0ynS6l7qUgnV9Ot=wXbGtBm89Y!v;UjzP+bC-V=UeoyZ%M+ruL_JqLf~>o`B4 znoh}wo$w}F^}R0!S32I5kevAK#f%0W$$W9VW~#$aH|&|fRB~lGN3k8NyZ@YRg$a`l z1J6RE{OIhL#=eB7REg!PGD9|BquR%^RXkaN&+a%SjN0=Ale~`>LB*k$)A6E@CS3CB zRZ5@C{E2@3oln7*v)-YX@%P692P@b%`CbnG)GwXywmoCpgw5^j7vw5Upz`mG4}q`0 zVKbxI!++K6W?TO|FL1MhnDb;ivMY-L zl=72o6$z=%VLM3dIT;u_{?o?L3ERKP?ncAX2hwR%kovYnsB1d=Lr7kGDk(~Bt7o9Y*YtSzi z$bF<*2dOUAvz%yx{RStAR#)}c_S(-iJ{e})@~G@KP;kZQ6%h+o!9#J{V-2s$sXC?q z7*T!|(8~hfFVQa?$w2RKv~LC5R8xgB{#7He-OqOaH4N6Ny;bs9<@T%E%$HOfF_&rs znYK@inz^808~s(xXNMTQ(@GyScN@4e2R3QF`nKZaB$thQu{#8r-K9Mmd%EAO<+feF zfaaI)bxE48(0O2-+MWAt153a+3Do9+Ly%#wkN$H2ie<&o^nV@p6@tyVo7OGr&mE4n zC_A5>7g#-YZW#!-Y&Sgkb)S7F=(xFz?P8g~9r;GYhhDDktq} zqS8`FyRibDQTB7kFD7$Tdr}kl2DNm*Grug%Z;IIFn11x1kxdbGVOB6)Dka^|q+JI8 zxeG9c$l=_#?+QNC3>zkt-D#&_PUz{(EIxGRF+R06|;F0FteFbc#3Noew zV650llCLzq#k5JJ650VMiLb~#F>xrA7^G(t#FF#$HZh;Sl_0Q}K&fbu;utVKb$(r^ z3l)LoC4tncDa4>g8_x311i{gLY&8)>2`$*kh$yP z*r)zunhxDFYbS^6BtD+nfNI}Df(aZP-Ho^!ZolpJRd&u~ihk1gu z^%!Vd3RUe2^`1iGF>RpzrjCC)`}?1Tn<$sk6u}i5l^}NFm_oKkl^!DgWlO%F3LNYX z&ZI@O+;0}&y2XnGXX{72anEmqpLImpISQx266RDnDC9m9s1pIw8EdnHbxhUd!0B! zElLF12&vZ6U`t+vg$Q&r2qN=AU~%c8beP^jkcE(H+X>Q*b=1pIAF>e~WeNxY zpyFLt;O^N*mSEp@smD6TPmE#$gk&qbc)fhIG!JC|3v7N@9v3f=6tm(7`KF4UrU!Fc zuV-IR1sg7|ZySts$Y<-l+hsaO-Px)rC$$4s;XgfmpDA}5Q4n`yc)7dKrm>Nn3n1>3g@Oco#Nti9HXW$CPq*>G5>b1ap$ zUFaYITn3CHyj9zOc2pkd;N0=htykOdk)i5{!GWvSCInVKEahqnNj1Pq{&nkIu?=yi z^LO%2QtyF$eqtjFd4#Rw*{T!tp*8`0x?c|4543u!z;Ri0Zw|v!z6?7DJLxsu= z>foV(NZ&l?R0HFL5!+uNd_G?*pS?_LtLKqTgo4;pn5`T~nJ$6O-~ADzf{48J$Q^sp z1n_N)W9T@Dk_E;Bv3C!!RK*+js|$|Ua#>v>fI%mFXBgOHe&l4XpjcO3OUR^f-Z<@U zkJC{Yc06G@haJHyyT1q95WxDe;KOAKBfENaTGw}0@H{$NJkLm*$eS8+$)y~!MHd)G z^>8T>D3Br2T!0kc}tbrRAAJ;+1~$*b~%z{_!mf zsyBmdqA4!&yN4;!&e}lqUGmtqOQ`k-IqnkVi;{QQM?cVM1@QiG@`7{w`z__X!wqD$ zshrKd596L9O;m3N*5{e|0}H=gicBBheSH1p7tn9<(ccE8Bhn-U8^u6bd5r>{1lh!&En|DeXn`#_CT<%)?YNzVQwc-Onuv?a9 z9n04sTXg$z!eVVodsh2FhtpQ#71~a@bY6zE+qcUIM3 zYk%T;{9C)`r?1acobuoqF}8f|=VhivNs45~!7K$&nIUZ}T7G2mDJ5i8(GC9?-IGe` zipFLUwMQHG?3y|F`rcWU|5B7Mucn_ytK&N>5@wycG zyZUZ8yrQ@r2$zk&2glno@~dGnigom>`3yIme2?dUGIJ_Yy6Vey#6aoBHtMub+s7LqIy&m zB3J*wQq9ra7Qa$cdD!{*vufsHexYiYS_T-9UFP{Nx6if_+fuc899@;;Pk*f6K9WuT z;o&!b4{oIw1<<=4RvKdNzyITT2>i5r+vg(xwSKnz>FFooJK~`MKhz0r+*gmzlkOy| z*jR~G6sJ2w6kXNNtS(37o_PMl;?{B4K3RmF$_svC+zd$ii6h5_=e1Zf9&GM&@Ih6luO!b&{pvg_s1l|7I!bEL4En)R*Qzt^Y(Nf6fab7pl@nb7p6)A! z1$`|&T5{&$K)7oBl9KAMVsm>(fqWae>UQM0j|w3y{(e}$-S&)KFY4s3Ek?%k$`1@E z6qUxv_NFP%m2+GSK2_vI#pjm9&}zz46#RlHoz;tymDJj4Ot1kT-z+I6i?u;K3sJ)F(RHBjfANWJy zIUHAqLYX4tkL7rakat?s<@zUzsl>hUXe?|cBf$>5P1Cmgif2;uZGeWVEfa{UxSCd+ zdq>k40n5&T+&oUpQhiu0c%4zj&w5&`7ONP(8tfb273czUnM{$ge17)&$+4uZq#1dK68ilVa)p0Y zTF`{%e66el4AzpCteLWwk`DQhRh*J+&sAdY6|(UT%W~%HGusJ}GPR#p9p+Ir_k*k{ z2HzHw9mcwPFE?o!m+op)7}3tSyT~+9*{4vKU66Txc$+4f7T~aGmU;f^0+%QgzUcqp znbm}rYQ-YNa`B#=ondO}T~<%K!MVqZ{sQ$cLmfNUW^h3S?Xc(jlHM3RN=q23KD5;A zY%{k~a?yVtZ~kF;y_bnAN%tuKJeX`1K*C-aW2t>{b2L>>srR=xiV{Bzig;K{dvLO8 z2)RvIIQlBr?{bR2`ad7nw=GALjz4ANG5Xc^^EV$VkA1;+bt>2WI){tnoKE^FsT=IP zmnj(LD#f0LVVhatJ?&cRQ=)y-Hw76sLIQeWEP0_*!60cqD|VUm4ql*RHV%=;_0+lO z;~qSVMI1RRyMl1DqRQSN=D=@CPaT_*$q47j8rbyD4Pe4loi4pde0lM7ja~_CC2y|Z)p|8Yoj-m`yCS8daXzc8lLt`IP)^j4vQkQD z1>=^F$btv5cC`-)l~rmxY-XjDnESnM3_R#0*hDygxkFVK3dNl$x9W^zHQEXf&wJTE zzlXMa>Xu~Iq7l`?40te6o_xm;Bt1D>`FFW$=h6RQ4mWKxW5cLhXau7@4KkX}il-fS z9MS!(J>aaEzguF0CMht<@VX-(0^)r>#nk`yQ#sM7`jZA9Z;H7d{Wnc^d?OkEJKh*? zH*0(4ysK3azlX9y#;JF`N>}>i2Ky(VK<$YsD@?S?V|T(>YmIdnJvEB(P%VeEqs&{W zE)cIgkQ!jd*4$Bk*mEw}Ls#LGT?NN;MOGN_g7h1A%dKB`+TBypkO9n#~ zE)QyT&o%7-GBMg82|GP@aqP1wXv_6ZK4DIIaAPdlR#W@MZtRC%sOd{9 zPFdy?NgF~^q8vr{x%*60W4kP$d9G_9*gRpBx80y4X~g%cGl-Ar0mE(NV8;}!@pU$8PK`QyTAhVmT?@>4BL+P2G@G^6SxR9>SiZ7El3Lha?&e(<{!Mc%&GDWlHss@x<;suTL7&0Wp& zqkqpw{7LU%KPH~Gi?+115JeC-CN?x~)<&qJt08SF>rB;kEW8ECPSH>Z;BOfMsz29I zaHPn-JQ2HVA-1AyUjwktG3or>(wrouaXe22)rL`)j!Un6z?yk5r-hWn7lvpGg>=XcWZ$9?K4!5Qa z*%I{{zsP5=c5XG$3JMvN)(|k(>8dGZzKhpjdLZvs;EpAx8i>+O)6N*7>yKveSl`$w zeZMN;ztd1EAozoV*mO+r6;yxRFNVqU7m{ zO?0*FGPN~fNC;27WpS>;pzYr|Pn`>Qe_mcrNKEhS+^*6Ok^i096~vS;UB-_vwXTqq zmuNS(G-c+WHXR};6jD?To4;s=l<*c+InBPxk>LNdx3%$bf+MG!=&vBN()u7+I2?}$ zN-|1>kr~3yPHAYmW_WZ~w6smR+<@vGLJt5+BioyiZDY77pT2YlowqEezl9gU`pesr z=%M`7FN?acu$jOhO3-4WeA;&jio7q4@WadzdEre_(TPM`f|Fa zVK?&6r`yt0T|dBELd>m#%A#S{KPbx^J=N`x}5F5J+?-U+9#NAY6<8zE-i$%gT+5fII9`JRT5F~ zEuD`^yO~xfwNmh!F;u&0?mYM;{#B90Jb`kId3X{U({O&Ug$~A$)|adAjs-ZTalkJwY94&agPR`D06ODIyVq;1QIH zfC>f!cvqIjG+kwx;xx8xuWHUA<&QG+bLx0z3uNiQlQ;4J1I>|-l*gvV&28?z{6xQx zn&fC@D}Ij&tx@KC-|+hxVXL0^;j?Y3NzyKgqe^Zw+iH($ z|ErTsURHf*XWhBcolH|tsR#MrSG7NH4+U(WX3EeA#>=1`yl&^#8S}7GIT%%SZSQv? z@Lmz+7ZC(Eq)bj}s3Gp}e=@T_H)yE(r2&R|@S0{zKsmO7>1_}YSxz^Mg5M0&gn{@L zNkHi3Grz_jY*SlK?BPj1lTu<3!3?142-g43K3@sU-s__qwlcI;4@Q_zf)pHtim zb{wW$o4K`elMW?2Ii(c9kMorhX2eK-NT#C5?0KnL#n4rAf&^w&+jXX!T%p#weLdm^ z*fIs1lZy|ar+0%@r%TnQ>54Qs?CZ}q+0Y|{9{26~RG0r#^JD%9`65|qKen~7ROSxM zXU4vlF5P@pW~@|wisGZ)YSKi()Cy4?`qOOb&)olz6t9zKdkmk?m{;=Ac7{2Zlr-m99spg>P1Ej6P#ST^37~Z3?AsmR2?m z>~++Z_i>i#EY(P8IiE`s!&*yC=9%&Vgy`uHs;3+eEc38K1o<+UQV$QiL~wo)x6Acp z!u{b1hJs7nE7&FQp;uCCm zLh$5+|1!TNwldC-@nt72%H9oEZ9l8nr-2LkTeovS=yWUKJ@r-t@7`wuPWze)aT1Hl zlv2Hg1!;8N1->bmJiV%+{bMQx_FtoM`@hVnED|)_DEPmnNl?RZewl-it`PE9eU+ywqNwFSTdG+q*greR z&I@=nm!*!RLvmFxgdvAcZRVp5AE3MjzUlfRY=&F^u=GaoxW)(67QyLZ4K^iY`onPU6;$*i@eS`gE-$(VLnc7h9t0ju&b86Mzf9j5O zopBAdk(qjypyViv1t{+38qnvPikoPgjfD#Q@E3 zE&dcJr1U!-Ee+u|ni!k-50Na}ry~CZmRP_0Vu2r$Xr+iffLp1>KVxxn21;2D-WAFY z*G?fO)E1fe_~|iY+k~GIyxX^4iEMv=Imn-nIlq*9sBZbMVlCSpM)#b|uETCsN^tboq zO#5i-^&i?W$YFfLDOG&WgVRfiwQ3SN^<^lR_Jv=2^v1&X9PWFKjT?4ZjZhaUR$;-8b%dcDL~ORATk-rB3|$9ab)KU1<37BwH&t4#q3v%}X$8`SJhk~U|!YYns~ z=YI$l5|5sExsz~VV!UqDTkY}L@5?W5w10U2LX$r9Q7Tzb;gPp3<>R%g>N}3^KbBX- zyAayDpIls@u0OD~Z+aI&H*{SR*jVEAZTN@cqG)fK!L`@?PIRHoAGr`O&4N*8YF+&>)BSv|WF6D`Tu2 zvPN6wV@?mIKjQrI%m(M}E>?c!4WOjkwiU?B8=Dh<_MJly{>(l6eX891c%6RWv}gL* zoY+t1WX}CQ`*DErZT1+@7jFB*KQApxSI4*A%z1`7b@6*Vm44334zxS%8z<+T$M{Qf zuLFPJ;X9A*4&Y3CliB;;7Mi|;elk&yn9Ez}uqkxZ#|BAhsTr-Fx>t&T+h6_{L$;KdZe!SMB$1Otakr-fpz%#%?0p z+Lx^l_H6^R%@bL>Z7&S@B-{QZ+;^0vUihGcecEDK?)FwYW|1{$7F%?*$tyK|HjqV)L&CvvKFNg4KF2=R$D3!KpZ()%fzHea`tZ-rgo#0>wD% z_i0J#wx09fr)>pIzxqyno4PR(^`i95$GWw!J?-&!fK_jYF@Ki>`3uWzFBGoOZ-4Cf zgVb7630CvwR%IasZ1`PB?Nx}?hvw5BQ1Ugahc^YPmVeW=ww-Wi$apvXUcBFX#sA-2 zFTqHMZXD8uP6Ass{(H0^T`_e;ujGgDzNe#e#r;0Z+&fK}cp3=?!GE07Ubg>{0A3BW zN_336vEfv{AM?;^>8tH%3wyWTg&D4!x4z5GM-H>3g907eg4gcpjaY%Gtf_VBYY?JD zM~c?0_*WKfG7u(*wHgn-)?ZqEf5-J1Aw3}5!{T>XPF~#eQ!%Tw@2iLC*Y}D?JcyUH z_Weh@_4fERasG`y>(I&ht+YBf{P(!uDPWh^+pWVhBG(C8*4WOc_y1g6~_X;=J=nYv8jSu{ltjQDIg~jM0 z2wf%PHb|H+|eHqoB_s|h$)Gf@Qo`(6=6uR99^(F*cSz87Hdx(&*D+IG5{x!Sf zC^wk)KwtwY#WkhZ%{`g`c>zkK_=GBV2TfeS+tSNO+Of=o8fCx{Gz8Q{TyihnJDQ$&K3}1p z7X;sa+Vu#HSBB5o1F=yYK<_eR%Vc)CxzuW~*uUWTzY?#|4kV2-_@F+J1K+gPQe+by zF*4(JrX&yxomK#%oP!!Vtg6%6!S&ISD=$N>>u(s&_gWX7zbsN@WBav~EK`fGWX&qQ zjfWX8SGOxym&$cXdKMG-hTcw*mvD;|}YJ&=B6EJS)l{*8k6%(YGH zP{o@;`0TdSG?a~COFR*o4f>7no9#yD6JXm<_rrWiT(=YOw%EzsD z?n+seImz{qZR$)B7DKLON@qH@52&N~hG^G=M?yseG17Pfh6toV%_>*CJxC-Zo#UkV zCOO*>#M+*x6lDH<-)meNZz<2p$rK5!Jlttuxy{BKxEIg(gAt}%1 zV!k!dQoN3>0N_3McjWilzQWK)w^8LqSCCVR_@pa!XMH~%ps`@Tqp&A1TmC3q-*CN*@nn(q?fK6aP?&L9 z!bAO!e*-N(IKRHGUKIRuwVC1aihnKcV5#;H;K_Kd$m7+;cZORPU#n*DO;+h@WtZ=C z7^g6A{G7dSrXKVSEOy#jsT*_DH-a`(jEtLLd zqsqHvSNfC93`0~&oRZV}>9%IVz#T7Oi5mtz{-X!=$UF8^#(nf~IrAe!0Q_v@AI=1NSs z`P>Ns`{#&@{=a^>!@OkoTv+se)Nx~~V`H^zkKNjJ*HoK7E0yQMw1OA4o_#vH`yvbe zbiK9j+1I$fixuB#vhSi{h9o|;{O9Jc&fPY*OR}!hIGX-*pr|A>%*dhO3BH05GZ5!M*=vLJT_y2G;*YunJQ7mrK-X zrS}hSv&?6Ek8bk`kMCzOom(BeBQCm*sTg&t?9IPoymoGAIQEImA=`&)mH^lp65J&k z?BCCPdJlG{AE7C9eOwCl6EU3ttawGJFMx4z=E{Z6^uv64PzQaVdgYQ_XAV2X#%GIri@IAzgFP*2xB2+%QT`fT{ zgR5Dei5X;{P-xu6dLC@M_v$K0gXXpIobQk(DBae%xL6IQH~EXSHm2?8Sh|Dz_iC;k($9PK`L|3WYGDH z!K>g!aX(Hdomh8|eUJxTwaQ#}%iM~zt&`xIO+L|GYQ`k&zi4d2aPIwk<~y@+S#0gS z98wBhex6``-xs{lk29oPb6&jZre7=STnv?Bw+ zgJ}VvXQF`+t7LIBSVaWzh=yaNq5A|ZpU$N|J{dFC8s_HGOY9gWnv*BLxh5o zbJ`;>kwh^ooKoe&(p4VTvf@_BKJZ&kZg^WkH4>8Dk9pTr5Z6`sFA0qNj)`zjZ>M3a zd5LxVSbSu`14VER2Zy>^o?GB95ob4|vAxaZc8PGNb^e8tZv3p`#o9cUCEPlAm=D+KxUw1avGfos_TGtk;%$L2rQ{kZ$eA_xRwW@NG zUgTcGvR*|GNn@^?M-wLO0-Mmo{m3#`&dEQrf_>z7HSrUrMaRitEm6@xfeO^ESVsi# zY647j6~Fo|yPpg>%0*}OL%e99hA5Di5RuX^rP7pCr3`y2=5j>ih<^8Ezb0T8302-- zt3w0*twEPDz_~#xfNIcF!rgjQ-E0l|IuG0(r2cY~#wbdx{+i044y$`p_qi4E0X%M(d-`?hq^k;l%|gGJsI&{~-MU zpC*JN0T$8(JnjQ37Xh_MAax!bD7>;62WS)laR3mMB+;7zUH~YL2ekyGd|bQ&;i777 zfiN;akqq>ThHqg&jNDsQT|7}DROz@tGPgN ze`Ijj5pw(yW73fW@h=>{^GLLVi8)7_Dos>JWX+?GXmgsRwkeNY1qW{7S9S4m$FRT8 zvbWheeSe~+mvUxV0W3jE2?BZ#Q$Fy_9dxInd{OW`p;>$KFysKIy@Fvvd;xsA&7iK} zl=d)w$*Zk( zPjpEDXj32D2NdT6qWC=Ziqo|NNIi;{(((aGi-2$H{!93)Lp3{O)dV`{bEk_7%y8M} z%z$^NlOOV=p3|f%av-HNsZ1ZE4p`3~!(9&vQcVDiNLIEfS6< zP1hG%Nt0qoBf4mqVFtR!$2s%}{2>QDL~su5f4R9oBwUy_>NE0O8WCQmYV{J;L`JWY zac{|Q9&(XwkUe!|bUy*pMU#pWoj>{e?ZYNiAQzbyh3Seu)8_|1=d*v*2h%OW(K(?# z14w+!Xr@r#{wXn@C)GvX(=Ls=Wq#ku5c`L*oi9Yc^_hHBPk0w0wdHJRHchIuslc5F zO|>816AYi+OWs1&eykZC>ofkAF^)HBwz*bx&M+yZEHR3=bC`yi7spP%0Yi>Rni`^A zmalgrA67kc>;N6@{A|;?_xGs6>vuU(olMo19k()DRjZU5X7Cw2(`Sd%&_(FkY&rwo z(~ou`Kr+%~I$O}c+ZhL_$epREhmn2@0*yB$41*vwNW#30#@yfq&e~)8Nt2#fr{m{k zFOc@|n^b`&h<+c;Ljb`ukWpld%4!00d`jY?rR1drRj~l2z3Sv z%>Prg317$}EwDIAtT8BGhFyNvvBANRq=~|&yl$E8UpTn=ChR}P$`5I* zOSyD04=cEbE3m{G+#3(Nj$Myl`Ln4XTdsOJCVw8KxIxAqyexB$rt^n~`*RYvL_%6U zx?1u8C*ojM7%K}hXp0$$6+p^F-1q&DNFuQ!{%CLewTYwm;l7D5Kl%k$O{ksx?@He= zt1`l0dn&xMN&lL@$%1~Y0n7gp%Et$k|B*D(V~($g@G4B)UC#TzXWs|iZO|Nca~D&+mr4z&_*4oKM+SMw6bEoDgp%S z2B==W=XArjJgJ7O`SK%Rw^yNbTE%e?PT#vILgRFjQkkx979EjBtgA z$9r0lry*U8e4;$UH=n>I!-xs{&rxa#e%jE8Q%d z$ox_>Q=>`Y`S^mWUN*5UU9@};t`^-d3Ckx`*38`2dT(V6ygSG-pmSTpn7*BaO2=vU{D z^277xKUzSW&l0D?%R>R<9vLW+NUXrh8h%7z1%Xp zuAe;eI!&lqEH;>7`no9dXEglW`3WMMup7?T_q|Qyh8BayfqJUv9{N|kxsnYiQ#sgJ z&Bw-y?sX{Pdye()JL}~U7;G%b;y(}l=yh|NG;02O`uxnBpTU=NgGb&W7GC~*%o5jc zea}E1`Wc*55UfZ$_s`s-sVhF{BZsO;<0sctaIGx#;t@xbj{<5+5xJK0Ma> zllv@f@nr{~`IiuEvSqOc0C)LC!vZ>Y(Qr4sd|x*R0Z$YnSYOOR zM8mIQnZ<{bk}zyM6r8t-q5+WTAV!j#EYa~=R|Ss`bn4_1BzaSwkf~#*#4xNgp!`!H z_Vm&cWeED@^zAm2G`31lCk^>XSI=?#<7I&F%y+GEf3~c=sh}$J3AomhFcFxM6^(uHseiPbm4*W26 zoPvu-z#+g=xH3y)mp2b+Et1Kk`)femgI<=74Cu0lw^;=Ka&;i)G)jFDh*dv-_KBar zhu+@Kkb21Iupgldl$*-%8X-;!CVV82hlmr0b>hj_C zNi&Y*p_wGj$RV2)Ik0(xR>n4 zb8z!tnc;~*L|~$;J>*D%$Ceb8a0XD?kdNKI7Z@yaL-7u34r3z}N|f-90=%!G&nJNk z)17bbbEkIxAP|Q+_;TyM(ru|qQ1}#2!Mt$~+dsirEmK+xuN#RA*=u;HbvaLSe7NaK zJA*uT7mSYLz)dCuTa3p79z{bFNk!~~gF=4ZP=WWkW>L|)SUF!t%R-&q@OIzgT%e=x zhsH~4o@EPmL430bA9m>;7V1fajnW0fZ132kno^!y%Xlnm5f3Vp0&w%5XeMcgD)SM} zq!eTH;aJB5VgQJ6awJt-$YVEglT43W?J@qbeDo~=ieqq1VwLV7$kCu4vn-R`kKIHG zZ(vq=4`pc$eP(R_&qI;%wnk~vJA87sjzh(~lGGl9}vQ)DNPXh4FPA$W4? zoszTMZv{`FK@4RC(nRhkbnSuZv5PMuWq_?l`Mr&(e$@p#OC?o*hCWL2UmErZ!2j>7 z0f@vfaq(e7v;iOwUh!85fuZuN7r|G-iw~A@0Ir0PrU-%|z>fd)Ik|D4@GT3lodb{? za#H#qdv6&OXSZ&Pw$Tj)m*50u&@F*Yu54`GakkwH6T%74;V$+OMfGIpHz|p>bs4k|IwvIy7L0$wZ|H<|!`q^D%5{ zA>P$=H=Z#J&R^E$cI~JeN|90TnI94TE}^?3G4e95Cj{>U3)B&4|J9;cTeE1G7{ISW z(dvQ5?-GW}T+xZu64W99RlDi#_XT$`3i(Kjx|&Hdp7tSyEmjY z+)irjt$cw+&4t8bpTuHc$I{g?eYzpBmhVy_f+vC{=5Z^UC_n3Y#e8_l66M?`W}Xv= zpIEZDn$?~m=Mh;MQgTq<dgw~T1V*%w zG|5%3f78+;x&;NtbA@HOUrLZPlT;YQZ|5s0Ki%$%WdKcT@DFilAXdL^P@RMaJskRlhR$%HLi z(JL0Puxuz=lTdY^X-f}6iwC7v0|`iCox5V1X=$*wv#vcrrg}`kHOv{#JQ@pp)Dxq& zl}fD?15ZFxF9?Gb*+u~%XH=S(b)Od#%o7#6Q%Dge8KVQPLIlD>v!M&9H)opV4pnb@ zDu7xOZ~U9eAHL|GQA4}HnIsTR6yNIXe@evXX2;@7`e`Jw0F=}k#l+NvJe=VQ{eoVI z=Z~|ig6`x58nQ{#OJ2DZ5LH)5H%q7+4aiVP`r6&Qy#iM{^}of844ipWtACSHla(4x z1+l0V;F3guF?Z2mr4Bg47U;k zy3>QMMq;q%Wor(k*-(H9E}+xIkRunm%@p-fIR0Jz9f)V-N9Kt3^ayPG!PSa6XpgpU zjigIe>kX-CCGDWYhBPM3dpFr3Oy^rqJdi1h-8ACBAleHNsfGgK?lFwJ$OOcJ%(4?; z&M1g8VD=_j6%Zk?-tGQ8Rv=LBl$P+;ATjB)g`j;-fh2wu>>E}6NT16>j~k#_R&wwF z*$uXk*B-^>V7h}-yBE}=ano?VAJiXip^xsoTfmhM8jdl;BcR8{395(*`N5^GTpS+z zZYEoSYqP-^bH9a&Hwh1Rv&4z_YDpsk-gsn%fH1UY(#e}XyD;qIUh*f30mi-i}RP&06h;hxwQu;5EBwBjfz7jg$1{{74y z1F}!^4ImNE(x4g@K&I>Z#$2fJo+#4-ZEa4p!+Mks98(qf{`m`tsGDl`3uw*@T_AIm zStwK*(bRq}(ZCH}GQ-^Qj2p7MBToXT;{|e&KuDcCf!7!rIGQdMRM`Q>l^lMz01z)k z548ihxj@yZ2=-QtbQk!Ua%8xD$Mbkl#4xY-a21zYNtsy9S|3_Dup70$I&wx zj$|i(z%wHF9aAVBiRg`MJJK0{)lAz53R@_4r00X^W_ zZ;^YN{o%Ny3#L(_>-7O5n$4YMGd+>prZ}!V$$=HHN5ga22X>4_<1UW=nC^Q=k0eQp zA{>B*Q5VAp&;zn1Jjdc8&M+S)nAbJ=2MU6b=Lr1QiH>lRuszt*Ler-`F;9D-zwBO3 z(I+eS0cY*CsZB}!7Gm5d7Kpyqd9=Qfo%mRi2sFCZrUZh0>YvA#nGTP|)Cea#NG^Ex zka_ix-O3&l?(@M9#*oAxbOg3PnerAL5%lk}B15t{L43rG_#t_RV9TzbYWaZJh^WuSUdNNXUKBwButS||{tTS|>}2BgOsZ$8CwU5|2?Dp9P* zvFdDf2!z~|YkO{C75Gz_Ma)2C8!hV@o%{l7F(H_iOVtt)L7Hul)rzJE)bg=|O35Jv z6M1>Zkyz=Q2LTd!186ri6xYMcL>X2O1F-x*^g|t~B&dtwXRxTXm2{xK@d4m~TfBO8 zTvWWiCsf$MXh9LBHq6(d2T&G6sn^V;G(XT51AwzpM3N{RYdYM8H94{P53vzYN6?5T z=rkh_N0MQU8wG6z3)h2R7S6IbTc-|NSS88D&~XU~Y1pVhLnX!X?WleupX;AiT+^Kr-P(!x{RlCVopD{%n-%@U#CTkizI2^*A2tRzXT9~PE^YVly{)Stn>Nyq|u%cbb6Q;M^_Fe8==VulT1k-gA=ysf)!+?4W+qH ziK727%(Xr`)EOonyGJ{yF`7N+`X-U#(;RVPk{j;k9y9k5?`E?Rp=zLpt2x@HJ|-MM z!u8Z-bRzm9njL*23VqM!l7H+ur&K1tYp{=SwkI*%Q95O*EdW0+x6fjFu3IByq z^x>Vc9%eQm;RK3yy+BSNJz4wX?BkETfrUOyWVdd#kpaUoPJxrs^@^^;z5elb_qKu9 zVCD;Gz#4xaCOf~&Q}UHmy>&@))-w;ojiKX>;Nglnhl8Jz>Q>HDI(2ZIB_@fT&$;Gl zEB~Q*J_1&`jk$>Wn3(*nMziDU{dJU)5>BUAgP`l25t0v&CtWlJ}#Ufu1spdcU|24)2pD zcf-VYq_>w*5AS6);kX`09dCik8pAiz~j&G_{kF zy!DkaJ8e(xs@Van%}-@#dkr$YQ8KMKw-Bb+!~1|mH0n)1Kv9iAni|x&0MNf)=`V^` zdv&Ln2mr{&JS2%CfxF6IOt;;cStE(^$c73WGn}}f*r{jombU zyWYxOzPnD~!UZepMH6EWVFo5-`GP3xvBU3R4#zkzan)D~QEh6d4iXHZb0q07ign>& zrxk5)9UZP0ZIs#&Kx%U)JfS8u((d~$c)Hg^Z-e3h%4|YdqJ%E~QcAP^So`eT+WKal zFWCP&#>foFh&7_0c=qJ|sYHLd4_B3iT@F#@N1m68BxeDE!!~-azlQ^0B47|1Zj@m0 zJFa$^FD^K>A5F%LPC+koZt~tLAyOiH{J3Z*fSRqyoNX?G^-5*1f%;ukclY4)Y7Pm;P zpR_3jrmpr=*C+Z(Y;+mzvH@>n7bp5#HSA%a*dZTGO%ZL^6l0{G#lm!LiT#5KZEdVc zuZDJCfO#W;cH7?^5ES-mgk(%nrfEnfFh+qp&Bl3t%Qz-@nAM_w$G@o8PfsC;#N#xw zg%(#lcn<;vgD50_hsG8#2*P$zB_ZoAcFN1@z6Qb7%Kp*@p>D}fSx0y{mlMNJzdzbd zq;W)4cDv0Ews$qr)KT};YNE23)1ABF?lfiy4K^Y0YEA!s1pEJRx+Mq z!)9l(Sx5Gd(Br-1qJ9>?Ta>ig1qUt`RezQyG zGd8d66Gv5kbAUaKkgYaKz{-RALw#flK*)+rIpTCZ5tr0~aamEB8J`wtCm(t&+8djO zldKvF;NieG6eiwQ&X|TwRs)ru_{T-`=$ArNn$^-y>!1+jG#->#-yoPqiTsmNtDy@3 zMS_2q&l$zkOAM42a`kE~+IuFX*rE4<%Lq}%e$RiHJ#6a3R}D*2MXt@#Co3I#TJ+qq zz^P{h^a8hg6w*D@k72UElzwsI+y^TslPHrSzcA}0kr?jB1w2`dPbU-_L`2syiB z%^@68Y~;*@n1mbczfMYp?y@b88~Uh-+;n1wl*0XNb>%9@V!#qNzeGOqV0x53g&b=& z>iZwqWJieK42Wnk1nw!uAlKHZ<-SAg?lY9W?w^pr&OscOy-XBQV+b}yj;CeL zc&2NdEFhCv{9|!d$#ei|_hoK7`x6*^O^b;XE+7U>IwFoUBm}*I*SJIk8$D{-y*jNQ0!ys0o=-mTFIZp+3x z<`e64)8hNuvZgG$a)$&M2d@2JxH@PqN}y`<`2un*lmu8bD1A}rqS@09LdT?CjA2G{ zKTigdBZW#M)}_m>+wf&@a}D|xiu{{&rA&?iP^qisEkeb1gXNc_9mV!sNn0NhR|Y6X zUy6*2>uULYLfnp>6)C%M`ufn$Ig3u$k>;I$)EeSr9FxD-o)<0Yw1RV&w0<1~CcRZY zj=Wpe#dkh=3n&^Eon9!0Qd?&$YG_r6{xDeToDh0OQ>n(9r1HSzd!+Iwqtew`3HIJm z(J91qqR5mp2!gaG5lIsHx`?N_l&9z6=P!NIJfK@b>R@z_ipv3o6M*O?5LxB&8De0k zM?q=9)TzC&5w3nMiIPO6Ir^#u8-$%+D7Zu7LDD3xmH$Rr4@u|^P9(@)nM_?`%)X!C z`(1kGL6W2(765>b0;LH2ZbyQ$%#)g2bYi6!`|L-J#~v@N`5XZN?wsaMU!!>gP(3Q1 z(>UPg>qPdbl`D^vc=l`nU|=%BEAnJjG62(`narg0NUp#>?y&nR8Y) z7MeK5>r@zBcqFkc>b1^>r=Hv>hR8B}uUGBP2d`M!K>FD88kMPbv< zisbtW*Or|k*u#35?wlms{vN)|^n!NG7EYx32g8WA$CW@$jNIBprZFeHCX=7DfztH$ z+`YyvCcy-<-C*5U!YGP+f0ZSt3PI=z_1RcYNQqv2=Vi!jhY6GIq@rv34K5Jb+VDoW z4hXFWLH&!shECrhxG9SzBSAoRV=|HqNExX8m|E20v+EoQOBlpw zR1K<94kVP*6Toxa+ZV|NO1Ws+(YQL7t+yCLB>4JiFoi{dqAoCd#MYC^*um{Ty%-(Y zewrd`j*T%CffJiuj1=LDP9p-t@frwFVjckx!=YO^*z+HEnZSghN?=-3Ye2an8lA2TP*l?*4?qaXSEk+hJldtVDN?#0nyjbGq< zpH0(|p@GQ(ttA5-{xDf+ZX_iiE8~G0G19d#PAGa4J83ska(UxJK&%~&WV@b$TWnfb z5cnZ(Rg7dS6D#LBit=mhP#RfVvQ7O|Gy-O?P!jiVeIhlE_yP2 z9}72a#ov(3<7?b$1wbrti`BflUB$H30+;RpnH;5^ABQg6IEA6=HAZuWSxE!B2?b9$-;o*_f zst3#-4`R(#<2|DgTDD|~_5GBzWD@XoXa!*Kw5$Q@q{z=Q zDAb4~ROJfs@Y~NqFI=WyMA=su;;*AXB5M?gel-&DVsTw-_@dNH zkaB6HBm@FU0DU~iAf5#v5vo@q5=}^{F0Y0paE{;? zwFdNMe5O!j3@zjXDB=A9+~vO#15q}163NNeU_?6&Hn5OsJY3$3m4m^BVjJY#O* zXzLn_F(Jpp-iSP9%E!g2W<^>+v~sr6oo7l6zlx9)n>P*+5(*Z!{gEk$%1h!?5VB=C^umsWyF!)bE-ZN-aU|(%LqS;s@>`#Kz zP5IRxLJ06Z?lxg|s?IWk3;;kvdlZ%d{ue5b;H5Z(r3eFUB`8n@ghI6Be@Pn$J-$r= z>E$E$2B437RQ>IbND*}Qh_IwNhCl%IGU_PlKBaH8;%b4vJ7SS^+ud_(b)^Stxs7Do zCWPBB=9Ma&7pM?@A*_F?xZ2}aNIx2PKd(oNj0D1HOdz?9k&f(D_)MbMoM?(~Wjwf* zYP6^@fDow%OR^~vVl8hA5t!zFrfp4O+hK)u1i|?i#272_4C0Z1vT@!^a_oKYxgM!} zYnknS(Ne&p!JbD-5Zl@>wyMhZf7s3T*v1 zib!&FE8aoY?>G(G2}WnT3Jf@9?jQlcVXhq;569s|cCT`F%QSYcVf#TTYK3ayjhLnRuW%x1_|2@ z`jrIFy&9!qWh^cb>~j(sDG}IodXWE0OauLNkib}nnPi*w?MIG?of7jOoRO*(ks~E~ zt82(r1d(W@e!11>N;V{)!=fKow0v2#D;nYL3<%^3cR|C*B7F5??mjP#^8mzGmFieO z1nHrY1+bY00m8M{R*FP8Rv?|{2`N@%%nOjpWeBB#Xzx8}WRHOWce+xUqRy8{$IA7J zNbJUmjlIZhT*f!*m!AL&TJ};J0r~VurL*<3ySZPMbKvXr;}6_c=B;w)?|cnxe3gG$ z8NRv`{KI7wuc`pVQ^d$qtW;6N;rdc|i_e3-q|p-Vs#IoNwXWs*EMg+)YvhG9&nt7{ za_OOR{P(3AK$65>UgbUp&-eErdQ_rASD}WwoYFo`3a_f9=ve()M}hkD7HNk78Q@^zj;i08y^vJnzl3q3TZX z8j#JwL$Z!?8u_yIM}@%BamU|dSDY>?mmeyFRJMO@!djmbw)v|5xd%u4KV>r4=ol zt%CgJ$cWnM5yAY^Cyjkird{h?bT}74#}iXWzl^s+r>cSd{J@Snh-N)#_dEE$`@I`HJPDJclAm6JX z3nU(@FB{=K<0wHz*YiK~oMsau;B3I9^SYJxD#@?M>4#5gc!h7)V9$91+`K}I1@~q= z@9x%9JJnK_a2Clcl92$(Jx_4J?(IZELU$W(M{euM=1&NYxGA{gh`=_3C0!H{VH?yIkO;KVzoiLzJ8{0moY_%GyD+WLfFaGg=9gI zg<6pUjwW7u@==VEnRknwyn#XCW$2(VzeoeK1R3Ues9j0vl(L%#&?$28qOqe zB|!+d^%_7P+N8fC`1{Aq5H~Bi8@=FsqkR8~&Wfg!R78JhF3=yKFKgZ_y;YGz{_6UTRkH zp|?A_FsJ(HV0dYKPuvOflKfGV;ep$b*@anwe|H}RRrn($raJtvig2Na!n2QWyH5xJ z);jBuRgVR3kV=)bqf)HG*stcC*k_)s?+?9E=`gf()sbbo;w4I90MTu*ads@;}0iZ z_f3hGq?g#IIl)N`r5nia zgFOk{>Ow5Z&M9F+E++mWFp~Vt_Wspfi6B+tjOXLKqAB9uf`M}3mLKg~{X8U%5-!{0 zgEmF6SAfMbt6OtZs?#{zVs_tTPTig-hV*i8gOU$giC%bx-v%0;N%>j$IPLnd1&B_H zi|6pRVBQL2bl*~#wDDQA8V5*h+V0~E?Yqm?o19gv{-yxhcBJVfdW`XisE?L|T> z+D9_Jq@V;WYW(QO3s|%0qibEEpMJazWhv6H4&W(*QqN6JDyo+&vwp_Ex@j;8u)Pu@ zB|+0@DZ$VC+?|x@J5dDJ^{8^fQn@C!pwbzHY=_$CU90)aXz7@~nO!o-^-3tyx zb~Gc~s{(?JkAg}Sf?E^8=DuxfD+nzp{yF3%t<(8dmZO*M zF$g{bs`2Tg81N_S6ezqa^=`f)Km3u-(ba%%&;+ZjD4pySom_!*=zxsW^sY?fbdz8B zMd8D?H;;bKkpK2^J7HG1R!9DxR%m-h{)6+yb!Lg|=Q~v&UddGIYUN4C%8pnIQh>2n z3%W)F9$Pr~JnH{F4gLtTiMMBs<3z;WHq3Bz_9)+Bjw z*GN{ty3?<|(KGi|uU?tAnXlx&?tcBu`@8vVD9_C+jrm_6mk=a+!0xj~Bf5aKBe|%f zGgYQH6F)cKRbTvh_8VusKKjvZ=e9*>58cm0SYU!?aF)~4@J3nwlt0}E=Z>u6PBIFc z2~K+^vR|^~uVLX=3Ed(0oryaYIkbSQODN)T`EZNd>(xJVPT`a3?a;e5kLdpB`Mj$& zltD<6N_ws>n81^b1j;50k4y~B7 zQ%&czkXEh~+8N0e^6HkwJJ}k@Cky{{zBuKmU35Q<<3am#7sFS&MXDLn8LkhiwdLeL z()i#QvTHm(*W29wKwiZBAXhm)-QD6X8|A*QTbk2{R77|Sf4h&f`KzZJ?aFwj9=&-k zNx~n^somyYhI}U@q&I0a7`S~-MdhEf*k~W4yqh`0M=q??8L4^4_+<|Jes!JAP^R1q zfA^)g^Mgs|ZH-fPa<6~!x?S?EMS04^Kx>u*b$5!tl#5$s)jb>x^K*L;CM~ft9rSiO zY`HaPqAVfgQI>pO@MTA}x?#b$urAlV-L>lZX3Q(fSJ#^G=r#rM{xm4YH&&!^)6cY53RGv96(O`tT^7WL)=XeS{o~Ds@1Nr2h z&f)S4``4qx!Ur!>2HrYP6(0)&d_qqYB#R!yHLE?&h1;YrzDr&zELHT`9VY`3G_Qa|?E9+Qy3xIkOq_as}@Gy*6@57c(4XAB~sX z+rG~&J?Z6l=TYtFpI`Qw)HYf1Thta~0x;h|a6o`t03Qc{3xtB)0|0Pu0k^+-mFf$7 zF(7gt%i;Q>{umNgjhAW-#qSfSMO>GM8%l;!n2_=G>W!rz(zy()EI%}sjb_2^Mqa8n zm8HLs^x5~tj>c#&Kwv-*u9EJ5EKy76u^MTvoPMQOqLHWZrfRm@H0N+Rmwbpd#JWG8 z@C7kL@@wbmDyz|!nx(g%TO)azZw2nx271AZCF<(d-i3Y7lW}`nztJB{&iinzwP9<> z=frzTEmPohZ>P(D@NK-!=04wER<7$JNn#f5L5m3xkvQm!+ZV zN8{aHKd<^n*JSHt#1^=1z=B0Za+75to)K$_rPo|!!nwCC)@t+P8rHN zvvMc*am&q24pBSz?n~b}GxKC>@teZD(95s81w_4VcDbm#u6srH`0aE>vEuuCCHHx% z7)nx&UB8xbX|ylrXZ!DeeMRbu&-$t`({;b{D9)U%>UGQhzE70_{*V3F&2#um;XvSj zz8-ZD6A%yp#J(O70QO$f|NH~M_kVCp{vsb4;4kv=Vaez7H}Zjr|9kQY+adl3h5s)o z{O4we|1;9v20}E3u#ql$zx$-;WH=ui=>&I>F<=;L@R?FPJ&zJ_K79Kq^z{6O+Jh){PQ%*s_5CC`l&nv_K;h z?lV#vcj~BTO5;>qkh2I)08OE7DZ$VN|d>nl6H3eN`#)p5wxktatqqWf@Vb*I126yF{` zwfq^NG20%rG?=u^_5DjvrSXdU$V0ikA&gUWZ$Fu|Z(<;vWnTVgsWDT!GCyVe~+Xkiqw+`;DdQ&wlpQTyqIQt3u9fM_$sLt-j6RBW{mWZ+fNuQtHm(x36bA z_nFjvyV*3(oCet7``PL|zTAd6I;0UfgF4297-Zd?s4EFBWANqUpw}aYkBvF?)GOjl zo@7K*@^(l2g^B5KA?V{HA+dQ zGlLi%hOY2~i88~tNlm+h_IXBlJ~-)}!JRK7g}{S&cI8jV=K_5#=J2D`!^y)mQ-?}7 zQx@YH?lj+=1veIx8$E1pC*Pgu?Z!YEmx2SoPUnQbt2GX_SXd3(iwj7}j;6g%@O)yv z8n+mDSU5O0Yej0AjrF;@!hZgj?@YDUh#0-tg%G7=gLP$3I{QEIuq9>{ z1$=zKtj?LIwmE3a;eVx1COd-y6RTX`Wew+QY+lpa|8mZ1O#7piHB}|Tmo1GK@-JnK z^1tFDMWco-f5TPCcr07taR>|v-kjPSfjn$d;IH+8vKHT`?z~*2Q*YcJ4*P5nn26hd zw>t=1{zk?Lz8J}XT6Dks(6pod65@CI&4t`qu?Xq#LzH&L!JtefM_TcR@2WwiQNcsM zKD+n$OgQO1ruwXI1_kOb0lnvAIV_Cegh;bXK2yS14{APZC9r06g>A)`MgjTPx?R|g zja6jegJPkV(Y-y)Um3c6tPQy4Xdl$j`du$eLY$BU+L6qm&Dse>~eE!9O_j z(Md)|-2l1N6?k-5bO&rKHdz1;n$UNuTm4E4P8zrG>cDN=IXv#^>hftgtQ_5si+Q`7 zG-SP8?KdAtu}uFqai4w#8SQD7X(oyLJ)_u{ zEjO%IdjHv|daB^TGv6@Ri+yc+vk&IK&Di+I-xv&auh3pqm=s%nuPVD^bhKROhgs$S zY;ydtC(4JYJZJv+QK!WF5q>vu6~edA!>e2lBz&yj$1rm`wn^?grxxMqmgVN2I8D`P z*9q{SIsHpvXZz13V&m_BU1A@iOEKvj-e@U$RN=8GSWipRlvOEsK+(3@f?y2EZx7q^`549;emy%EMC zi(QuT+1uV|x|qhBYd&is((0pv75e|&%U_8zIa+0t1p)8M9($PgL&ybd4jf^8{t^x^j-~rnB`EYF`_PyDyYk>^@z|K6l?} z@|%C?F6o>^5%~ElrmRSnfT=UeOvO#{4DAKVkK+Co(j?MW0ZfSmLcG7{)Tt9+U$*n{r-%bNxk}eB{r-mGS}?7*z)^_vAc2`c1$N> zPU(?yr_ZF$c0;l18Z|HK^_N_eC#Ib0o@%*+{PeBvp8y-4pw=4eSjp7){cr2;y$icu zPV1Xo{N}`%vc6bt;_+F`_u{a|5EIg_A-TrnzVMG%5UZmu8shuimAr98{Z@fNhWycf!uymb8wT=gEMDpgGHr5wADlutU2fDTPHA?rKi6dSF4^i%!#A_$hl?YA zKaJhY+a75Dn9XS}Q~B}u`87Yl~k`1Dve3AvL_ooc4?u+#e3G&O|%u2ayza+fnc^^;7Hi+}& z$)z({@8Vt)5w$l>bh7*!Db+(l#QS<}`EQ;;ESXcu#^vzZ1B|RszMPGVW|}H#$?!QW z6a?1S`x0wiwl)zc`j$&ReCdFnv%Fr_@lF<4u{dS@7a^q80SQL092lV|f1m3SC86VQ&N&cGv7L0W%y# z&M2Era{sO0S7F!XZ2deIMm%J^mg$zId~t^kd+w~;%nSvy`k9MPG1x}yAWQIGcgXEAV1st1 z`cs9DXT5a5r{(tGUpV|QNO^W@hwLi>}M_g?sG)3i7(zSf-=pr!Ni`25hYj_7ypmHXO2 zKnlHpRKw<^tnCaFFrhw|Ld=zIl7U_zRkOvu#;9F2o0{*$#ugC1FQFnCesjKoG&5e4 z*JPVRe&;r}lJ*5aV|AqCOAFUbN+^K?5d`9`D`?5G9rA#0i#vvH>3&YjQ51&(MQRKz zts9Xfm+uY#E%Ma-6M@lx)G934UeWR|&cr|xP!?IWSP7YOasvozup{-m`4&g7ZeZVq zkd;>Ad-iFy6DuKqDxo6Q)5w5Xj4Z29b9{O!5HR>H=xi5}sTkGG<|N*5S1g{w z)u=!_&*;sF=z(#C)r+SOXfyW>>kXP*Oj?vi|IpLT*O<1-e$UnZeD}br+wb?` z8)?HM%TD1ho24)29iP2L(VbNQbKsMe38chgFQvR~Kk?9n-wjly6Sd z)Scqu{-;RO`Oo$Jvljc$^?}nZXYerJ8^+Mche|s@qQ>#$X=a6lGfO9HWDT~bShp(eiIcd_L*TIzb z&)6W9-VZeD2jgiG#_OKXTFMq)S)mu=TjGhDJvO@4??i6#Pt}Tjx>y>nTk8(J`K(`6 z^rq@TqmFBK)BSNqX^-WFS!@?Rm{F1p)a?$a!B3$LURXiG%JKIakgPBI=ZSRJ*mxVi zTD%(k;MSVTe!y#jv5t57v2gL{w?wN{*!CQeY<}pC@p?m4O8Q}ByZ74s3n%;V?iI+oXOK4K?liCq@BiBWPVMYEd_)V%gbB$PSQAOD;zGvmUJXNo07$4Ng(~g2eEe1 zZX1=b9C8)FhQ1;VXd^4CLFmH9fLUjj`YHRVD2owQZZ>0_L1o}3`d>5i|5j-o!6L%) zzjV{Rn7_KVVZHU<7-&K^_dgKf#oo%s4uhTP?D#t(U3a!lu!tP){~eLK+ntJ0?^As}Lh07aCS(lo0@HZsFUDJ8b*6?NR49spy=RHtKz|B z?Za*-_}H)K)rL;bc=r$AbWpIWByX;_9@TI8wy8r{EaaVY0tMmPMy4Zl@?7?|!zt!i# zOW)c=Bvi)pD^G;34N_$D>|-A3{n$X^$zDl+dc!?! zh~&Sc^p~Q(OQDgH*E8fgTv?GUI&#;j{{Fa9%7&Nmxjh(SdA60aEt$*#l12X!{wO5p zRz0>8Kdxu}#4Zbn-Zp`3puh~7zP5M_lE;O!X*Yxy&oU)L9UO8@$=+~8IO<%KYdZ>w zIT`pk`0YM;_^)w%@xR3sJt6fEOv$eVv6v!`hyRZ0X+!nqUzi^M1JeW3_Ru&^>~tVW zzeC>$uqt7;aQGa-=PCAN>&57k`Yl6l?Q*0^>_LDB_M@kSkNEFamgR2mhv^aT@rB}s z8l9#i@;{ddcFjbfyu8ca$!GzTv)t4 zTwSY+ct7X)tQ5aJ_LBfcL1t|+!9zTw6|z$IE!lFyBB<+ zv(S-6X!N*Zf4;ZGN)didxngch2pYg2-bRkIl}PDBsQ0$X86)_j^py!(I-@`03(X)v z9`y{==Jx85+sSgb)+KT5EzM`2qc}Ox{q_^vK3F)v80yOYc!|N-ZQ`kzQ;t@g>0sf+ zjENmQwqprZeP)cLOzf-})JIUDXFP4?W*CSh)r=>yRFcIga;dA@$X|#NQR?gdS`=N# z^^N#o@NXrIy?+g;fB)?9H~M;F>5CJzr+y#%%`twz2Z$a{izyDi{7Z=!ek9FE&wNTP zn(`kBqbY{SVFbhbw}i3tF_zEjFmX}jgKnX8Odp@?xwB4@hSQwZ)cNjog zOmDD|6Jz@Nird|i_!HXo^PH``X1@hCN$C&O^B#GA2S9M1MTd9YEc6FK-q2#s77;>8td>Qv6=CdS5 zS*D5tT`X0R3``Gg?-SC|#Mx?-P!?^Qsrh9wJu}{DrO3En^Tol~I-1)d*>cr)CrkEU zMYI2HT)z5mf%SqL{6{4)?^O+Kup`vG{#zwbD(@pCt@O+EN&a80)GBM1!576$A)ik# z%+8oesNs@i1C`_)y0Nl+HvQs!AM`Z&6S`%8c;YmM-ON;SZ$?(k~rFxo#J>*pgFIn*0v z{J)O&M3L|EhX`rc!eXe7KF$Xbyqe6SyQ-P4bN@c0ed|$PDfRPw=at?0ucv>mza5M$ z`HX+fEA-tttU+q^+0p;G5xU8MkVqC5-j}&~Y+@A*wX%V6OjQ^X%g^_qRs-cWP#CP%6(>%rzk_Izsn~>r72BUQIF4t!3B%SG&s5`sgKl9Xx%>=t2lt$Nt-&|i{x%H^a zRi#QP!+b!iJ>;}cF(mVQURQX$-k#NRW=wv-O+~L-8VIK@@PsdI;k6MDG2-~xtD39? zn#$vUjM86jcgLFb9nTtGjXkHK=M7~0u#_R9$0@1wrXx#mO~HRv4anUW%D=QbaUxqq zxBKbgMeyRw9&2rigHuYb_`R=@HJx%6voX$P<7PV|?l)iGQasY}gblK0W78lbs61-xso4ptKLa7@u&wn7=ee1B5zw6OKDgQ-}PPZnb zhd<-drUl1N6bXkBX&IDGi@Gm0dTeF7n=w!b6shv>Lk1gzug)tUbYR;WA06xO6f(N5 zY4H8SE*Xj1BT28_z1bJduC=C>lGI%t5(M|34H?zF?04eLu&IdU{E!e(sY=EqX3O?H z^9gm;C^C#O@0^&Coe?pU8iC_RA|5uNGhOCF4kMbYHH>tXOXKVV{#S`dq)Yy&8wJQ79IKUokiu60Y=~Sp}}I0|%K7*2%RZvlk)As0o)6>{Z8# z=}&T(p{CYa@=4dr_<8jhWBKz6J7Phmaz{e~w$mOkW1cVB2)nN@S+r%xtOGgmyANk6 z99&FMeHlU&`bd16N)rlV4BsUo`?Kd#acnk_Yl^2T`Va0UTvAhU@`_0|lt)VZKkU6{ zP?OQu_8XFrgpfv)fRxay8hWUPUPXEl)F7aMr~yF{P!bXdASE;b1q@9=ia}8kQ3C;~ zA}9(XXy`>mKvcxSoBwmpobx^(&dfV!&Zjf)=P;RYuf6WQ_FC7zet&&XrfXZvL#AJc z!%r1O{sY^HM1XaBE3e)%Ub@=;SD#7y<}J;uI^-niib*}vQPnRP9(*tpR`%dh&bLAsd4p}o*5dGS&3fp|AqZ6YVHnkqNb!+^q?f9Cm z^pl623K_lF2-17qSe10KhTt3z15fY?5$v_$_fLBEyBuweT6F&cekX*M>*Gz;`<^?B zeMFh{K`TeYjU0~Ck&&$cuGP=I< z@3kJbJfgg_uyQm1Vv_8$xL+DfZ;Rsx6T?P+eUThV_?Kc=cx8(UolNq2JH00fe)6_A ze5$PH(7`Xm4_MRyq4`0RX^Mb<;zTSV&z4A!J)Z9E|Db}r?}&2! z-(iOSKPRc)e~ZJPMR1xiH4wr-e(+^^3`Y*(_bK5X?p4=+|7XV#tYebSuNNHD@TrZS zMNRzS=<+)xE$ZF^SA1yu{fEB$i>_COJjNRySNcD@#MeyOUcdW3qeAVf+)<|o%bvB^ z8jr>m@nBII9a36~2(8DuF`)3sQ$OXtnv>%#;ZN)kO#hbfk_)l?>hlplf4_Vv`g+Xl z1Yv#QsHw-EXYm`oQJ+(@%b#API_PtYj5LDfrq7!0l-%Qs z2VPz@&(UF$e}2?(YOXZbH-r{lyL5p?J8bb+ISp<8 zvxJ)L{_V>=7#*WO`_kwWnZ`e0_<35xF*~Y3mdcGRs`Sd_o9v?*NP=R3W7_!~b8Z*U z=4yb>f;aNrB<-*fQ8_9&?d8*AFrsgq_R9DqAZkzUgviAYc$p?pn(bkD@oXBQ`n9}i zQE`k&cA%p_U9KWVH_hMQa=Eg=m7l`M$cJ_O)5v=%g;KZN#|7D!cIw_;z1;SA9{xW^ z`2VrO`QIP>uPebU`Fokzf1T3({x5ZtD_Aiwj*R0nQ1bgT)tiI5(`vEr!33xI8+G%}mlL-MHV=TxFmAr?h7K(SP1e z|7n?)+WG>tQefeWjO9} zl3A**%ufgI1*V6w)3}OQYsD6aXyv{PMeBHQo<~LZH9_Z2@k^WYgEt70O@n>+Sue88 zX>eJm7XI+=zsZ-c>kDPq6C%25J4Q5|Xv7t=u)U#-aezVGyVBlZCV^ZKCl1z)ENu-X z1Rm@1_f+kEcAWMu%x=x!_t}*I69JE^jbq7<5j>t{2{apv+XenRl5ZbO&)j?U>|pfC z*}iMR1#40?$;XjFx}Fj+n^%v>ysd`vr{XXaE?NSJ9=h*v>|<}f*72eLL%#e-JGn>d zVdR@@eJkP+y*K%gOX|DVd(Pc_mhiW{#!dLxi7e+|YaJQxOz5M_zq=Y8#^n|kdVqh8 zM&UDC=Uqh^FGr6%j>;+mAeEPd;H#0qjp07M zmn}<`dO549?xMC0<1dXqhH#x_yXFgk2LD>BQZqfL$$e(q<4S!|uQ%v4>5m08l#aQm z7f5rVG#H+*XYS}Iap=F~%h$peO2QWC)@t8*`RFUZhO35j12K-HM+7B;QVl-EfQC$e z>EA!@8n@qzrt)L-KKwHHJ>%vTRh4Ub6tKJWD13U=6P3LBzQ997hjq`@;upud=PZAa zjJ8-3Ctwx<_g>1Jlot@XBevn%!6EE=P1Uk(1H z#phOmeO`8ob;?EI`{^{<#dfJ|X?0YAjl{z0H&>kZEic->F9lrNy5 z+$eR}d?hnD+w?!9n_%vrGcs6fTS8P=<<+53 zXQQd{*JmjbBZT1Ul!$lt8UPo%nyqlg)Vf=xJNhHe!V#%%NM9GdSLWYG-?+-wKlq+) zzD}XNH2BmK{K~A1N7PE&9p1dGAkDMn>292gV`Io`)^o ziwk>lUwiDHZhQ$>vXwQQ3Y@ijO!?Uo#nbryCujEW9ja^Mqan`~4 zz>ZcTLaAx=#h+VEeA)M-wbJK5a8&{r%KE0O`OodVcSJJ|1%y2rC_=lKb9m5tKfciXvJw_Q23?r)U?1~ULb^bZIIp9NsB+|U!+lDr?Rr-z-5Gb z7^?&BJ*w@7B*vVBU;`?OzWxh>T-(|Y*~)nTFLBINtvKlN8BnJWhXvUmW^3ol`*@JU z17pJgGG?DMz(G7Pe(OMD;m$Ddv|Ika*aNmX>h>MHTvUzD862NqZ@!j`5FNxpl$nC& zyC>{B8!PD0%FZ71iRSEtOr)-_Ly@6AfHsYMg}b593onmC$K!$%wK&!$Yt1OrKrIC* zm@8qXj(l!_gc!iA1?$rY3ztGp;KRy^c}5rui?fM60^SH8(m~|tNL-dcdD>8I^M*545e^T}2EJJA2Q+^EFh2Mk8S*;}keAsIMj#d*RFx&1~WYvCN}KR77LhuIVT z{QyK9Y%TFc--5w&&%sZZmv@q{3!u7EuDPfx9qk!BY4WXPC;6!E38J7JizW7zeB#X( z85zw|l3j$^>${TjWQQCBFxFPtS!ex{C1(ltCWG#~NE4Z_^2&7| zzk>zKm21_VmWcMo&zj+KG4p}#Fowm5CF)#AmLk!Orq`8Q)5&&p&(yTSw|8Xa#nZ6; zN@?29M3CkoRWi%O9)jy=p){}J#wTrieG_*=bhmPtnID9Z){%Cu7*xtzvdM{KrJkA- zE1iu?l}`4|HMm5RS!C^1eJ0XLZ55E7VR{(25_{%{@UZ>u(+)SoF9h$S0YJ{I2 zPAagL-zG6MN^^5+8gD@=#uYS9xaCH7&dLp_SBhLEF)nm1%H#kT7Ug04@wL|S?|Y9` zcx@A8C`$65YpqUt5D|%^T+t`Oj!3!Yti*C_nfkO;i#y)Za(tuc+dT0eJvdCtV0~F+ z5)37Db!12vE9{+KPcf;-BOgW!B3{Fwx@JJwnV72Tso_*9ArG)oNY&o!>=eRQc=l-? zwNS_sqs56DjnQtY_`cj_bjw{ZAPyumz4T(5jLE3jnUPssN|p7Yz9kPEDE*L{H;5y( znKzv{U#5pV&|ZOz9j}rdo3}H*QRq0SV@`GR%i^L%+3#(~PUizq8fyrEyiehXy+9&C5GfPVqqUyJTIn{UQ!} z1;O6Gx1k6BHD_O<kS3Ax{-g}S)=s>RYLJ1h_Y~2|Z)q6tPR|bP+f3O;#f5B^# zo@&bb?3u=WY|aUCah2a$x7YW=hoPt)u9_o zax!W?VK=99NG0}ze<*gHG?!of0sl7bq;w@TML{8x)^ZKmFypSo?9lN_>9sI1-K~B8 zF=Pe7a$jjV4F;$ZrB*Ej)6U zb0)e7^=ln{i-|8I(!nq{yDfY?>97_+a}IY-yh6=K48B$%);J08NJc*?d)78j zZIY4iijW&Tn?T%Nnx&n`a4Ou8wid8M9nkxSKLsG6tbc_ zI0z8+9gphb2u~5w95qylJE)#{rE?xxcM;u=zf@ergg<5?{4v*kMT`s7@3EvQWWPBK zg~$9b(Hr7&$#g1gcYj_;vr!l+;Dt_zgDvw*V+l?4ZjMrXULSn{&l*uDGGMNT@kh!WV#W{~LNsl$k3Av|;DpA_6-cjIK`B|4j5GweC3+ zRno^2XlJ6P0Fdv+=t(#2Yupmfh@vn-*yP`7C&`kYXiUWEvL7|CbmoLIsb*dl&l&}A$E4I(ha4@sLj_qkYq zgNX1ZRwA!q3^;J>QRIGc&;Y>j9|5B^jZp>&7cC=m-Z071x1-@9Xbs&0K;lDyJsWSs zWy=An8oxNvB_M-5CU_Bpo*|<co$OG6j7NkQwFpnl`g z@f48281nWqu2yu zrz_R>3lKXP^lGy8G|5+_19S~%G|Ynhy#qODVkj}PXAQsyK5-A4p+B;lr07EU3G=f& zzccj**B+f|5OO2%iD;(iISeZL8>$y4c?gCp9lH?%f)q2MB#xjj9yZKj&AUmfYNe{z z-!s5jZ?50d`CtqYM12Ev9YmnNkeZ6E;SPF!x5AP4zZ-c2KquW8KoF^ax4&hj1RY+A z^NB+zSEANAmD4PNkDQKq#fKq#Gx~R07j%0*R0*x~xN&A^uZaB`B%wDL75`A9#NWOT zBGAv=YA%l=ep65<0iZ}LbQu5?$Meg%3L2;APqX3I_1?_!=zJqNe z;M?MSG2R$ZARe(NPlb_zZc1?ZoQ7V;Uo{eW{FTzNsQ5gM3%YFqxfUu`2~ z`%eqSndoc?p=IH9KbBD$ZlDOVPVYJ_+YWvt0KCjXAE$$^)z%vH3N9vG2h=eQB%2{iSNcC~c`crv9Y} z5iKG=N{v!xjj&quy%3StqMg-3iN(w#1}x(jexMcY2*D0Lr*}epgxu=8w;SXnBAZL2 zC<}VNvv;zRlC^ax18b3l`FFTn+S!K@z8~9Aw@AiCWR!zmZa}G()aM&g8+&0V+|+r< zy(X|DgZ^hK8hVL9v2oM|Cb&rD{?OpP(4+6Z4|nR2;77M^KGj6h21Q$xihuLrVMNWo z&fe$Ceg?~8zC_e-H)JdTy+jdec?p{3pxgt+FD0l4!ElM-jMzTy~uLDj%zOCzwJ+!pa&?xU1qH_4S3BGs3)Ty?hd+6 z%ztK`_6sL`EbQgD%Yl{Jv6{;hQ)8^V0}sE;h-#55VNay}ZphCAMGu;w>nS6@{_rqz z(;gM=XOE)434nHGh7CwJ4``g98s?Ms5Wk5?Z;nmH@aZ!C?AV63FL>k^<(YR}{yuYz z%$Jb`;Olv25`iSN{R=hDM)VO8vt+c!8Hkqo>=Us!ttM|^?UG+_HzFF|d|T%b$hQ~c z&YCEV+U(OicYbu1e8c(j8__M&kM&W4^4mJR#Q-zU=Mcv4sp?BfbdA~KR}4RE-VKOB zxJ-UYws^T5QIC1&0=t>z)6!U!6t(-ME2&1)Rr7&jCDiFR5|wfT`?(t$C91=R1PZmO z-YA_p1iVBNzK)5k=vOBa;RC$IE3OEV^YyZ_BN~7SQ3mLbFM5H8sQZYZR8IU;{j|w9 z#=#-~4kPO+QFtcm>#$H!sPMyfi{Q^6$`jE#*G0HTC*M}BTzQ6YstG?VhMok>b*&pT zXIiVZp$3NAYl}d(2&f62uxeH^^Mr~_`oSz0eYPR75_O zs&j}kb+3Ju+H8N}QJL7PrCkiVkBBb%y!Tody2EWmvh10z9QMoScp1wxNrosPrH4~J z!si|Sy~_YrsJ9-7T%v_@r)Gebvw+?ib8P)Qs5@7p%2o_n>(Rv1#p0J^tzP zpPp_Y=q+aA1i`qieM^}%=lr4N*|Ar64C3cHbq9}>#-W-6`iCVSzBNo;V-a0d<#f9q$4UbDq4_vlb9mNTFUKlJ(MebZ{_W`2g$fh@~=^< z@p$?%)0kbkj$WUydo7}YQD&8=4qy>#u6bntqQiR;$%WKf_eXdAGy1_%B<|1sZv9C& zKZG~sf=@k*%h-+ZI<~P--jw6WVgHsyrM{BrTYDQ|z>c0*b{yjSV_o|7TzqV+Z=Z*8 zs&?YH{ckxPVRFyHv`YUtchV-!FUFJh1X?^LWtGg5wGZojX_Lkgv^%(`q@O~pg07El z0Zs^ptk>NZqaM+-mQCyrhr!G~3NgWQ6hJaVv#D0`*>-{0hWtX@ww-)*Ub9-cWgOw0 zvfAdr?J^VQ&h6A^LyvQeaqS~eS-pGp4KM?y|4FHkCEUH1q0+P4e#->Kb}Y~ZDRSYuh>3FbwfPLG_2L)=37xfS=G+sP!}yxb+Zpffl*VD6$^2*LV* zQ0(S%>RV$^Ph7j(bd@Nd>$X3v{YSw$;7_{bz##VlA_r=qE@Py zxT$_WoUE>xIlTG)l>C*gic{r@e~cHOQWYigCHI@DEV1bQL1D^r{qF9ra;tG_H?vH3 z9Bwkpfr9&p`Lmwi{o(WW~e^?#sh5P^a$lxYJD;(QChMi?w+IW@QqXO3je_K?M7o=f<u(M>9en8rm5&{Ds8}|6{h0Ac@dTwtF5#I*a=2)uPI+fi z1|HNp1y$rb_I#AGs~$UUH1aKe=F-~<A5{nxuJMdLRW z#`5Hx#dP{LrZU_`eJtT>JWh;Gv5o24Mp3G^8l-&~+B!acd%1zM_g5T4(anukLk8{2 zKhTiyS}AHdUtDofodY&o9l3qbTj0tx>jT_17@epdaWu1^QROgmBR27stvasT+zX3} z73heRCg+<$ER(Ta3-Y&}-rhmXX!`YOY8nu`Z}?2#7YCe>{XurTd*wkk$vDKX+r;PI zT!;24OJPCclAXmQm4SRg0avuj>z*K&goc3jCbioc@!Zi-BqgkOvVhJHfu^YknYbgb zdrUaPPi~6L9or$;Pm$IUWq(c|71&$s83D+?!sB;rU_nT~pmwrXN2FO=s`;vAvl=Q{ zwyho{6u}-CHlB0&G{KN_oVjkhK$Ao#kESTb<#?NEo_a+;sb6D!D8lE>_5HgaO3d4X zgpb?I%Df2haRP*9&oY&;%E9*LER{UHLhEb7R7=gJAT$58Ii1`R#Cd#`)DS=cJrriA zS6;!1(za%mQH0Rq8>rAwnq)gWb!DLL*Sxy}(3P zZ+dNiT&`CW4M2pZ7Fr4mwS)wa!)%kU8hXkUl{adOM{gwX@Qthk96dDKJ=S$l*mGt5(y; zV9~p|(g|s@(Heu{?&)*uiRyH~92XeK#i?9tW_srs7=HF2SenwsdZET{bvE7$?5176 z2886ZP&50fi4SK(1f3TrB zS#h-D_z$LylN>GQGD0abFs$cbYef+@rc?gX{(1AQ+*3&uklk^kyOs}tX7AlSPp9?%s*rB&n;ek#d*<@FewJ^0e{ zFL-EsyT|By{%F{M1mq3R{PXEH>h!pb)MCgNA`N%?THIU zpMJe!Soly_X=IkQ>}R(g<4&C{OP5wi5$}cZ_(*na0Z2N+%@;`$$tJUB3~gKO2={_c zB_%7#R4loRHZhS=Az#x+ccEkqM*s|s3cL4>O$dN7V!{{~+!*Y5xi_s~vK!+9iE-X9 z)s6Z5VjW`k31s6u=X5bAsTf@Bkc{U+fXW=4QpSK7BN9g2(7?H1pyy!V%GzWJ7%ddQ z_z#~B3khK=Rc9Ff+Ga$>rHM4S1gk_pgQ2S)UIDv6hT`Lo=842R5y;Mqb?I|YbKkP8$> z9O2Q_5%W6y)pI0{{%EZgoF-SFd=k%yB@@X@;8QrLUtEDA3v?C(rE6YwB^{K#Lp_CI zoaGZYYXt%@jB{?50$Y&$lI!PS(0xj2r!frU2DpqH{j3A@LMtb1n0{^@Vyai@&9wc{ zpX-HVgw+Dc;=~VbpnuLO!JgnV1Zbf0!Sl6{=ZZq4Nk|m4A(tb7YTWcrI~E4@aDbfOvDM?GMmeNpDYS>cpufMR&^@0qT zG9TLVo^;W)DAbJC^$)k9`vK0&@j2I~Gg~vAjZ1nyRy+bv->;ORyY|w=0m*X;0?#6# z+S;AT4gx9lnLRB<60Jb?pMeT;n)0}c(J;uYH#Z5(Os1r3VPR&xWEef?aWw1|L1^Sp z`ffiyy+zvs%LAGY(~>wKym~sZ1#w6*Zz?lK+CkujqCAdJhIa!Q6z5{ohSYKgCD^V{ zk4R$KAX^gH77OMK!a;2V{4X60l0NL7p;-$u=T96tRIGzQo)`SBHoQ-}kX7vBe8S~L zWJZm@KprCFH4QG8CZNZm%}@5{vm5UzyC&2PRhp&C1;Ar924+WTX0@RAW+lnnuf)zE zE7VQ&fFSd@Lwei!anqTHZ>7inDLr)kEn;yC8wRt>7- zwT*r!&+JY4Cd9xU-WY>QOlu;1hhIJIc^l_x^f#T*=xI{sX>2~4942MIGuTkve_BdJ z%70Yt&0!h9gGQ34+`1>R@b$hjC!NNUx;ZLQ_N~WDmy26oR)WGyB~K$bGU9RIq5(+L z*6V=ow}Efp9-V)C?5IFwFEqXta)?8BU4q2!r0)6hwwCv@o+m%%|1PZ1XYmO_C<=O_ zmG0~(*rTHwTK4Xo;22qAEJ|gpl1H`YFn#t)KflT-*Y>^Qso6;8UaT35R}qf7`XG_1 z;yM70akEbl9H&T(Q&q;pIt84zQ{gdC=v<$7%UImL@wCG6Vn^a`W~Rdh2S#LEdiwl$ z_V@9eFXLL5Ml6TwFmESbiXgX{LFiP+~)23 zo1y+5`#f1H6O{%NRkjn=-V-&U6Sra~ZpTh2uD>xWIZ`X}56>h%G`j^xygt%)bh0=0nNw_uCXCjRka6j0iQ|`-ohm~2iHw-xo0YXx zZwLPW4-QZf-rpL?AIJ>64d_J*zdB?6;3Zs*AaULe>QB}kYYyDSV*`^(N1w*R``^M# z-Js`Tt&PP-PYNeaZyXtl%~&|ow7@?0{^`EYg>boH(3HxvAr<*J`Um!&&aEvkRQWNe0cc9yRmHIdEsQaIr@HViKitrhV1KPAof+}`0-8G zW&mli{4pH<)}@KSgaf494D|O_n580u{#`O#5jYY zB{8;{|Zv>SVexDlHjR(1YC3Jd+n2|SIX`EQg;5P zWBmkY6(Ieb3@nQl&V!s~f=gY10o#xmKj^9{=(JA=S<8XssLEmc1B>>5UZtU-_|kW+^qqA=Dq0l5DXQ-J9x732WSbR(JhDxS}!n z5+ve>2d))(27B-vz_wEu%-`)#V<+kzfCg+qquOwnE6)^_53gorBmi$5Ju7VH0F6(} zhgw{Z^;2RLj@dqF#Y@aSk4Rm^PMulMiUSy3cN91~4vkR{0=bSJ`!|!{3wZyl8{! z(s3IFZn2)=Qm3u7&t6lXpZ)t>>GIar{Q609Y7llaPUwwnQO3Xw#!+@~064#ZJ&rdR zeX(*?_-w}RgUq^uELTco*nXfV8M1pS?UdWuO|g%kuV5LP>u>l?!EO%%jqGars5&Vu zHI9&di4FB3s{R#gisM04!XdH)(9@i-;3ffsVaRNUZXArBC8U9Wof^s6;xD|ArDftA zwk5onTnmW+Ko8!1yk9Lh4?tcex~uQzUwRkiv3BI@>%yfgqE|o13_Lt~vp9Ny^)ks1 zV&S_d0so~Kr)FieMRvP=I&A%Bt$?0GW={na(Zsg+BmWkvwiJB9Q66oCWuA|9_qtHO0Aab+ecEIIp|fN5BmKW?HgnaB2aSMYDv_9~Z9=aTLoF zpfP?Q)3T{v*z1VH0ax>CSXZ3u=Jy!Dz~eEML#$a%Hmzwf*~2z~B?U8b03vy(pD%pp zUs*82(`XKj4M~cS{Oq@L*YE&vNm)T9ZGquy)?h)v&v1y@evak zxM9I7ZI1}Ky?81?wDsJj52JLQSMl#c*n2(`A8|l=h3+!AUyB+*@!r(SSjM~BOYs5J zlNgBxt*jmik=@2GFmqTlRt(w#*vb{Aof3dPPZtp9lqLGT#wwhg7zOhlGcIBo@yxBR z+4|U80dW!@Qgv_OR=#-EkhmY!?+&!^ysWQl%!>@kx_xgu$3XjedyZ!yo5pDPw3k%X z3==j@695x^xY?0FpZ#=DZI>)Aly9HKcbE`Yv{{-{d_fl%QPuEJPPfW*HS+-{t4*3G zeCz7Iucl?!txS41FU;UWwZ%!J^J2c$mAx!Ut<6^Y+Q+9CXP3G?W7vwBVcX*y#N3$( zc(KHz==md6Vowvs$$>|w2alN_JM!e7O21ONw3)AugVmFWeHaXp0w3RV0_hZ@Gchz>07KNIBg#P{pk;+$+yjMGkSDyhkK>-Dnm$+r3I_@in+wM7u+ z#FNT-nSI-dTWc$0_s@O(XZ~mVOv-EDR^XB6@$(_Z=>qpGDA?(BnE4OHn@p3{mit3S zG>n9U@jRcQX0~h-=c+HiPuY>aG^~do0i)&t!b5wjK=H z723eSj8WuAi`+EiVhf0i1K#+9FX;Q!Or{d;JHGY^_?S^<+ zYVB(JyE;(jj@# zrB;{nk#MQpsvN?1NUL|j?yd8V_-&3@uZ>%{-n_)!W(i(}0gi??FThTomfKyQQ+f&C z>frI+cLF`Qh3rx>l*%XdR+7O<{U2z|Nkab6tIq{or_5cKz1bzin}KePwg;=!vsV(8 zgoZ|dX&7_|O9}N9dP4wZGSu$P)!S|33RCwts=P7z9rI&Kscv z2Br_*!pG*8TFG5V8b5KmDYR^z}l1917Bnq|A!R{t4(LwfT z)Xd*&Bk0RKn$^!?hQ%Kp6f&q!-m4m8!CuPYpLikdJbUw*ikyT$T%*+pna-h+7X_2t ztXKGgoD=xAcsA`=zNioyu#ug_pMW#0UMtZFNNbcJWOkfk`mq`PX?sDgtF|-~(2S|^qB77D3At&G)n(4EV@E-Of*i~=`V-u-RNlA#Vac-;E6B9zf=388!{CMVRja4 zA}$G|I`T`kqG)vCVEaB=aYsWHzQfWwtBWM{$IV`kUYB$EkF`i)xPx)Be_!BRkbFmN zpqq4O{37ac)_(caz zS~*BC4udm7*y?5&SIB&4rb_8E5y|9LH?5@?7DH5;w6^!9EA{B{f)-S~K!;KUPl$lX zcg0uJjyksY!moGa#Ib|(hDYsPjXMQ3EO*7qe-KlB$oTY&qa#_{WP9^k!#pjzQt_+N zQ>JnXGAhxhaXT=GLugcYs8C|cAQcvCM~?OjxaM9*y=Wv_F;wYT{RNI4y(yBe-=h$m%tagY|%2k(*In0Cn$ zGF08gFb=j(XJxNc$uBzqqkbsl+@Ma&?69F45dd)X7R||kPxJcTclgww`-%pH9*YT) zoFvOPat}Gm31pIx!j4^15ZM0vRzP3~sj2E8&JHmrt!!{>P8RODX0F_Zu_ZN~Q)f2j zJ_Lfou~6fUI;uf?Tn-|3+mHl~@-RF8mx1h*TWCsw08N)7FjEH37ak*^8pnUUxmYJ@Y zD#d$%y&CMGtaFJlnRl&rhKVCs99wbkTbRA{(~X75@ycL4Td;p+I?Ic0CH=Kk{ebk7 zjQBrQGWErDW!PX&tc#+$ zaWPuX-&q;p{cZwA6xBVvZ*Ybus8KqCY8ll~AmEn|4h9KlmeGpkyJ2YcsI1d|*0S3; z`vYGd2T=CWMDuaGwuGM}=|=>+8Bzi)Q?I-%*O*Evn;4;co2dv&Ge~}A9b&|$4r0Md z@`*O7Djp)Jgkhz9_=+XX(x=ywGABNL4ufdKxo0N~i}^d&cH*0KkP)pQ`KhqG`|dmD zoTHx*El7J|wj+{VtS~4Q;nQP2uJa`vs%T(UXKA!KlC3K1g1mu%4o#+EfBnXQUnYHIXnfI9MX}A;XmX8?7gOTXuj=*9bJPRy1zh zo9Aq=yXzowAmj4`$UUO4X&zO`hr+E$(f>KNW}6>Hm-gSRHbX~FUmZVIdGGYH1pZ40 zlCSTOu@3CEv8^u-rJoQaw$?=WKLV;WEA0*QO%VBWTTaGoP{xe!0^B|}76Z#N*CD4q ze?N`z98Z=38#Ou3M4@BZR-#3{FU;0EknNi>WBsMk2lm?dcDN7L@@G%66Iymh2&a~6aOKJbiY0wMyNcHq9 ze1zV%l?kicl$>ckVyW-O)sK|XFXq~Y($3mQDeS3KxWJ(FUQ;y5s=EY7%u)3kKxTCy zonmSiX3ytZOWPPLK06k{1cdfkt1$rx4&ZKFC4>oNIs%2d0Eo1yn;McvT|~qv08Wy& z2(u35aPWUX=7?m7HdqKpGbUTZ{B8DlB&+y!;^J@xfgNoHAmm$U=P(`nucxkpZmtXx z8YS+_=6a1eJ!(5n=34pDxt>g-+9*y-Ww%3uBa>UrImiOwcwS0! zpVSm39`ea~qg2!OOh^L&#iA%?S{qZY7wpS_qdaL&w1)TYfitbl=By2uf~~p$x|m7x zIGS-MB?$+{ux!+0gU8ZoQMD;(VT!>-aIhy;VqBuoDlm{R#kE+qwtvetnzIZ`--C%8 zBQQBCY>;W@jNua31a|25W!g}Bl>@ju`tmLp&LJYhIC`0WamHCvFRax9i?#MZeHnS^ z>K6gqHcF7ks0s&1%Qq{mro8ZM0O%^;JTIsgBz@~Sl_uwKJbImC+$9V5OAbi|3Xy1` ziuvZUi&2KD=H=ENen96v)L&APD3X)aUY{Z!b zdYPD6g}P5=MMq$JNiBHpJTVmxE8ntpxszd6H{f+yNiuz`;!O$qMo~ zYTpYA1l*}A>zOL6SY@cGaI8zh&q^%}SmP1F?~NN;eK=SvprgN6rviivtUR`+;!Cj% z;1SjEZgFSm=%doiAS=IPHrns3)fxuPr}+zBfV%-aLgwP)s@&cw*6r`|h;{k!ond+; z&+a|Ed3@~N{$t0RL03`>Em}cO*C~oIlLlB(D;7t0(%Q@+SuLZ$oSy6>E+DzBrZsgH z5K4onS3+FIjOn{JzDMSXC_zlCW%(^@^+0M^{A{OVMs*i4yc47XmUW2nCbYb;PYscd zw)EQ%Fa&=F3EDH6C4NbB$dKdJN{>|No%1%1br4r5i^8UO}=xMpS`x#AGE z>M5(z7e=dGf=jSnK|tSy&bJy}zFqQx#sUbEwt4BT#}DRT|H2@~1>na-oMS;jA@qxK z^~XgE$7`H_6oZVJAd^v&MabLJm^~weTM)`83j_@k$i2LB6c>at#FtrV(+=#ceryz9 zuD)tKM>7tz6z%4ybjj^7x2k<&Qg~lLx?vpsVP(?^Pg&C0g$v1iq9ry`G|Z~IU1|&n1j=D@WX-??Wr@Fk zX@*Cv;a)lB*SQuUAR&YVVK`J`u*!UU^(V{MqIAh;l=JZpDE}}2Z)lr_b`mbh-;S&( zxw*(jYM@&MIt7a7!b)Z;Fx#JHmqqsUmSL5rJDAJGYiB_mSo%1m9^;uW?@zhCypkt?%cU>=)+@8Gmhr{ zg$!l7G$Mv(v2;#^a`>rAH$k7KLVlk_?!LHl=**b~6)Pdk;9Tg6Y|HDuVYhC* zi2dUt?NN|98|b}hWiiOzdw-A7DoASspfvo}&;h7gu&LA%E}<=k9zXqXgKUB8G7bT0 z@^7VJKi7JkK>(%|j?;q%=gLLZ9PW8lIy#Be(k$XYSA>c?qHG_{(acu+?Is5-U9I6H z8zen>;GJ0abWoXW4P5nckSES?z_ykhAcJhS@# zSnkBV#umkUyuTpTKMi8wV@(Z(ar?e@wMFxXkqJQJkf+GM;vVyUDb zkfwGiIa2mdx{*(Z%J!n!s#5~&fH9M3xXj&9z1woj4uP@ORCr*0G;a$&40%%Iw6`de z(xICMddIeQF16miGZ%ls_VhB%xB>8CKh1> z2b9Mr&}bOo-yj0@(^&8zK|@(qbd@( z^(i3LOAAq6*@P{cQ4A!po$S#|_61l<;H;mK;HDg!`O^C7b$n}dR^ql3wNz|oKWJW4 zr`N~wc%QZA=nwH%Mwg%WIMjBqm%p1=gCsu)L-K)yT6y!dyrQ>fFBUhOHLUp7>olmo zxw#xuTSE+O0`0r32bcaI6rFoGlm8pX&De&WoM&bSXQD*X!DSl^v-JJw+Q zDh#>6A%}HV`9FN^o-m{S!-NS{dDXcE(zVFzIL;+$%DlJZ(DyB**{CEY#xxd@Xql$& z8j;z%wfs)mD*Zi2b&*v7qtJ@0%~pmBfXAz2b5psdGpWyo80YT;4-WVosZFJ5f)2k? zc3UEcpRGL}>0zQO*_XRyZrypv!Rb=os$pfVk)6ms`#CFKg4r#gPP^!fX`P{E9aEo6 zH6N{(a(%8>T{aW?if>Kd9~(NVed3UYNXL5OLAEfQO_IewwP1~`?r!L7MNBFk@pvI4 z26-y>NuO-0E*2bMRuT^yo80?T|GZ%zR-jkxc{_~QFW1VBn>8* zum75aiHzgl2;Y9k`hCpYYm-`4e)7xhWBX?)UkAh?Qq1DL%bpr`G}+Gs9S`_c`}-0s z5)=5t{N5m@!J1?5uqr@Ir@)-(>GLW`P*<94E3?{o(Bv1p{WA-JF=7|s9gtyzreiQl zZuosC+G3|_!!4F(%cWnpO;*2q(p4>paFaI)YTPLme5b|cdD!`ue{Jt$8c*6Jw)}Wt zE46AUr(tk#0R<0MwLk?rA~6GZIlUCL@=v}4koN5WzyAUKy~{CSx= zvncf0Mp9%*XRme)QxwW*d53e=!^WMW|g>xtF=Ne6}^rAFNt9Ro|qQM5H{J$Ztk znCKIj^jjR27k}WERdLi2!-y}QlqK=R2m1#?^eKh26TOedpn1QMHD5c=HOLX4Z97L= z{w?iDf4@zB=KspT^zP=i#?g+_<^s|telV(Yl+ut_@Q;v6@Uggjg&zE-@AUBV*ueuj&%v3Jh-8?- z#8SXp>_ZfcKknu6_N2a)+>P4x+{a2-ys=-Jwf1O#TEHK!=*2(T0-$l)$Jqo>C*RNG z0iT}t?pU3ztV8Cmn%JFvC-Rh0=U6o3J{wXo zWE%IL=35k$iF%(*3?;`UmNOM1wmw$-RJt}TMbLLlwe+=aYrW_DrU>VVXdukjewe>w zK~I@E7_*cgg{M~5-o55F^5ki{b=Gy8BN3fnT;B>n&k5jD44qSEHtZ)VqEdZIFVE(7 zrhFm0-ZQ}js(EM$@4aWbf9S?A`E$XmYWFMa`^$@B>%0M#XwB-%Vvn#iLSD?WgGQbQ zMeKfI>`*m8W4dDsT&Nr@0Z(yQJ`2u?n)%b4AD257crOepgFxgIq;8NJdia3v_hcT7 zq$nBGI?ZMO+p)Tzqm3?mR2Z|!1LbVLfqu42gYgrUK)XBNq zK%?{WW2&C4;V|_h8cGIfOa=;aMF1K!=$h)iOMFApe?h*~___G9>eoHSMKZoADDi`0 zg2-bXL{ALwt5bQz(xjUw`8nET4Tp*!`JzuC>2?puW<7hRt#wH`^PQvwvj+VU4)-pAI=VW6M+KWiYw9*l-q(2FDj zCT=Lau2i;QL;``OwW?xclc#>%LxonS6nliw8Fylr@~wNX4_OBp;vL(*l3<=?pR zu_g_CVTE!(s?tVV zkiUKD4XC3mRcp9c_@mN_OpAM}i8E3MiL&8V8^-;6dJ-kM=)?>_%0|JJ-r`8^M`Bs3 z_K%i54_8t35zRbGP-YjIXelz}1$$ zto+tyj+|Xv%yTSP&2#ljD!lN8@iKBrC?1TZQ%*aFqxqlO6wA`v_B?(e^KVZ*2fch3 z9OTfUTY!#+1Yl!XdNJqx56q`aT>8N%zEQv-UF20nGdb^19!wESzOWmfp~^a~j2F+8 zPCkkm5$(kOq>4lv{wRqK7LNCcnSB9oEn17!Fh}tKDvipp%`S29r@mg(^hPs$v^s8K za_rLP(?cDqVo>0KtvLKZj_9na=7i)WbQ(LzOo@qY$PD#` zD3o=)Pj~fKdBwH2Gy5UQqBTDJ_b z*V%bsI-C_#1yl&3118g|vwV3Z>0fzZ?bVCVSH^^7f9G*6D^e9=CskxYjcE!K41|m1 zO_`}^ThzLZ@X=vwIj2;B&N>58Hc3!z&FME2a0*andq4*p>~6oDBQm|S{pC($@v14E z$t&8HX}U4szAg&H z+UtmELh{X%H})4+`=MvJwuUl*mO^77?nj=8@fCWCmWN6$$;;oOg*Q5NB6Ht0KsvP` zQuLzxud}U%H+22kK%+UJB28Au$g|@;%FJ2GgFAD7SqNf=|GKAQ{DD;nTRf%+bWtPYpkmmUXt&C!I?hvGh#%=&gWsKi4eN7q8(_;Q`BK2->7F zry_{`2J22$s&v0{3-2u>wKi)*TyeG0q7h+00&(X*a}6 zbuneHP+Nyn9>BeGT{jLbt5xft0o0DV+@r0wd_|gA{ z-KCzCKaUGnL5Ecj;tg|e^2}4fPL20Z{it`35-9^oBy1Ahib6adU!{y}%5`t)4GCaP zP$K@MtuO3=H-C2R_HVCbP~sioRE{Wd3j(U&^C#PRIsxNH;`C;_WyZRnCPaVjHTNXP zU#}$r>w_VCR>dT)R-9M*JGN*QLUg?B{#YBS$IA?hJD6k()qutIcFP$OFH?j?wMZQN zSa@cX85o?$6r_vYQj#mE9$O^4>>4`U(A@HaD&EFyjR&PIW&~OMltT(e%C1Eu+}uL~ znEvF!UdSdZ?FgzAW9NqlK*xMvDoRZeFSS_2#*7yy-3n2IJCKjW=u$aZ4eE6dCQnliP+b?c<}A zD*3*ybeyTSsBQ(i2TKl2QM?H97KzVjw2b?fm2d)h!C8Qabm)*BZpgg8TCU(1dEsdB z#p$_7e{=%Z5_*K5KrT#hcy*=l{DWJFm^|fWJ(B3)J%(`Uw`BEB$T?`VRi@z<5 zWWc?HsKJxKGn`;~akfwfTc-6&&qX_pf@EQ*)^hARcSXDrKsdE|S0u`-*Sw4K?6sAI zdXZQ(>w_EEY1ie|Us>%WkFlm_m***I_JdZ1w2Zi!)3~9&KX(~N5?N<^MFoF&K;9?J5TQd9s17}Rp%rGR z^TB#T)+#{Zh!Av=Or9nnWV(H6RM8o>>b0AzjY0i#b#{fJp4oWl(30W~OmvKnS>+7O zL9mPV7lu|d+MF}lP?r!Px#)NkPazP64Ic`|91wx*B`B~6uy>TXAqFa%JQ$*a{HTdr zW~|7m$>6Q!4wRfQJnvrY-$_3&8p`9!={lgljX=~uu8V`aLoVVf+>ZY1xoTMjXla=Rt{zC~FH%vgW*%O*}T74JZ?~PZT<771w&<{9h^x=+djP;J^Kh0(-!&d?8lYIrQ>ZId;;%B))-I?75O6=pxU%Ia zRvKKja!j+=&?5aedeLv`yubG1#~o!*Y!&uuIJ%CZlwqUzvRB#uF?OsJT~VsING6lS z8HEJgE<>q~r%=N{^8vEL&MIC5^I?@&mcp@Y0=k%henXxv;H2$xpkw5KU50#o`5*lO z%mW_oB@cH<%(z&5spM;vs#CxaK#|SEL7dKKBp43)>8yW$VW_;XCQ~s?uV~3{LE*z4XgtYob?5Zj0grYba=73U~nLNi(EFqxf)?d?f3us_a4MX>7Y2*(l2CeKN zR0F%Fzwh_O{8qYOwvYq553Bt)ysn%xvlo<1#>qX=djZhjU|?FQ|ETwgFZW@a{1mb| zXp%JYua4wYCAR(&x{CMTXkfP{h%oGjt{|vgu@p6_=y82SVP5)O!xrPb^wr@yyB>1Zu>f^n*?RIwd^$tBd;>QO`^DWc!K z1Dd4Wvt;}Cy$=>ukpp2idDu-dZo3p0;O8{(S-gjEM57tEMSj$!g#~5cwm6^H7>Zsu zBzDP)PO?KkIA;DqdLTb^4G&#F9vqbdu^9EWpMPNdMUUuUy}-w*bj)9Z(ww$vAqO{C z`b<0lvqr%2=R$EOe_`Bzx>#~lX=S(>hSCn1t@niQ5CvF z6&|=r%W(hTSt-tm{${5t{_ zuei%mqF8<3D-71*U^h9~AIWBiQgGXxe*v4K^O0x2GEh+Hk8J{Oo2PR_Y~SBfEIfxm zbnu%`cTd>DQ07f3hfnf3^-W^G;lkc!vbca`HSmQmEC$g)S+szITl5P8?;G0QQ^Bv} zotSq%Ia_*+BaASN`ms}rRX*HDPq^@@*>?nBpZg?_)|)}!!g@VUK-x=hF>sg_hxZrH zI^Bk6an5gi$9Uex{mnGP^=kd)U}wT4o<&`9lI0O!d#)~sor*l~*X)^whpK)a+$zPb zGirV?VyJI`v0(w9QFc^Ghnd_$~5VLSdAwo)j zIp%q*Xh^Qh8BwsiaI}Mm(hLU|x-VUabJdR_{>fUZN6YS9A5Odi#OC0JOULL`bVkzg zPtGUb^M=A!ab-r8_(!pGXAqE=SYhH9SmRp5P^7nk=d9%u^TuD7`6Fj3yh}!o2u=aNh!Etos-uxu(z0uOtZ^%|SDH9u?i_0^X^iR8%VmGd8K1 z&4E!?T(ExV9v)_>RB^ALY{!wLV@y;VC;Ke`lT1EAS3lvi{K7Isww{+W!o$4eDQuQR z+Uh9CxT8^=w;?2{G6IH_kEtifb|KX1Y=IO^flo6?W6(v^ISO@T#Tq}9CP#|UqLLQh zld6o6m)`MP>L>O zxPDxbDlS#*B4YygA0`I36p+ym$ahjT9Mb6W9ezra45bM_43o1@#c7t=v!|lF!VO*h zgKnt!-6Ty&uAYGrLZb!Js1>RL8&KZKk;8H-0EoBQLUIe6xxE~Py^B6Qh=aRQP!^-q z&$ynHVd!I-t?A~fw}a{8q4^X7)j%2LdJ#<|KgHhw?=3|a^B!h(NEI^fpSX&q?s)F) zmWyhuypC3=BUzjlg>=wS?SS%LfPxU2e0Tb29WQ5)&_rZpz27Gm%0mYLo@~5<7WkpF zOOM3nqJ@0i(w)#V3dOuDXlofrG6x;c$)>SoYW)-f6Fh?j6LY1QAwNt+KB|s$a-j!a z?1vWSycO?M<}Hf<$dSpjldB`3GRhz|Y`N9rH#t0o4nrFsMY&cVSm5&q8$vCqAOu7? zy@B`gOa!uuj3GT!JVKU2nHs0jWd{@~FQ=d^aY{Pk2dI#}qn?$z#jKzO8;4ej8HgY4cv@UjXh>`?>lH)M*m;-PG+ zyX$#T88v7t-eu=Y>W7D1p%8`8MF06R>>BT7yJgjks8$UfocP7V-Kv=_)R&~T9s&f_ z2=(bb0M)ghOkI3Eem@m>ZqT%Aey;bbNS=zONBtl%UBinYDB_=vw5qLo9b_-{)%r$Q$k8EGiH2gg5MK> zrPp^^e)ib~&nWlKvyH&$kdh%rY{z5Ky*8qeRUP3?GtcQgzRY&NLO<(n;-7vq#@S-5%GLgClVQzvvlt#KXm4=5k@XwidS zi-`tBRooe{xgPrB8dazefA0MqrRy!<#-dnYrnzQ@(lM{<2@gGnl)o5!-JyB!Na2_^H9q?czSL^f-y#I-*e9q>aP z05FFOMQrPp3RYY!u?t1JT^x&5KbuEBx@ls~kl|tupr;yeyZ85i$LKYS$~&HA$vDfS zV|+lBlF;J;g5tL?7B-RRDZ3WB6IBprp3=G><|Vdr-XhO3WPRM+SSB2|47imTB-+He zYbxf=aKLRDb(s`?rXN3*dcAV<%JuPp>v^HqxAH&yzW(V?x5YU2)DC&$*Q0ymj)yEC zo}&11S0@P2mqgJHywW;BY4^;|`1OBNul~(m>l2ZM*mD#D$U6+GY@wg*+@tLehjfKH z(shFt=f+=yb$ebVK^0A7A$nz9sZ!?>Yl8ME>7Q(G?SJxguXFZwl8%W4C{VTgwvJC* z06#B)s)^rsZn`~nf29jPrx4~;yd$;YBx<(Xgeg%c9tjv3g5bQvNY(s2;tP zpN!_$mYljScaq7Y*#1j6mW;gynL9$N6&w+TsIac_S>j;n>(nOjF(9X?xGSVo+=U2(q`d*}G_!sk2w z84iK@fpW5e6w*3d{jTk9j`iL1FQ+Jyp{{oBDUx4JPUh~}>1W-eF9&E8d%*|B3b_B6 zRY%Vje?49v=pcUfey-^ORsRAxE!q1zvQ>6fr3HSf@>iJX5c=K%No}Qwxvt9F`?pLU zQt}-Gg6@*qkH33_I8&qLZxhy9d5?rSSM?}RDBez1x;q5j;1yp3Mmd?c4bx4?68x+( z5>-(Hp%=2GFY*ZDa)0Y|s0qSp5oVH_QdL;I>*a84d)9+1}#NfcotDE5; zS_G7rFsMEgo0*O2!-uUOmwp!{mNq?Z^;ofLBJ5S-$C(Qsd?tD~uckkBikts$!G0>w z%9WRNcmK^%OSPn4{oJLk)pBEd<--=gXO3oC^wn~a@S?GVx1YgNqeN?C_Z-WWq8bjto8-0XX;w5ta3X_vbG=e#E_vOM1Z5mWNlGIS#b#S<0Y z-g*K*xLO6w(CIXa8xw!MKJSWUN&LOs(17huQ2y@wvHwKWyGOrABi|m1n?-VH{iYjl zo;=&5RUb0_XU z0kmBO#jY3knT$uR4TJTJ-?LN`0dg%Y8+~pT!beC_ z*&xq$sV9pBe~@`r$=3yR>IiVJ{b}r-958<9cUjodJT|Kotnjk|ZpzmTQzlj=7`f&l zB7Oa?yr(-KTAM^%+dhr{Wk1XZ0~bRbm#aD&LIziLHLNm++uGiS!3gkJLkLuQr*I zD4OXNk+;%z=WTl(JJ?|hO2X>i%#DT*=|_mc#Ic4(7@i-`*R*{AmHVb+OS((+CY-1oK8>VM{+n{)SsSiruO zVc1|zqnEDk(@_=go%^|7%^^Mo*ZRl2Y~@-?Jns2E%_YB}hDx&fgkE~9>oNkP@IlkPrRITXkSpg<#HE?kZ)yx$+I<93oL#Ishn`b3P$;Sj3` zYWwxGns+(vzh|wKK33V;y-fi+4g+yr!z5S;DV{9o2EWx*3jVMR-8)xK`(0IiOgG?F&kY z=#T~0j#MBg#519P`EEAZ-V!!90OYGJv8$7~c;qVE&J2}2**c3<+V<)#G6|L%qYki(}9BHmn`!*i@a2b3l_k8`!UpL<7Ouw<*Gp>6+O84yG z@+?Tr^%bnw@o7!+rKZyg@1j!x^9^txXE4N%n|yHB2yvx70pk&K7(Z6};>w$HrKxjv zMsNB{m8$@X-Wa|GT3!@m%;mJ_-E&=7o;?q9SJkFDQNECXX{c4qU!9 zk6YTlXU65h%$zkqRmOH^yYiWrbjnQ_(F+fgW(%TjRw%AP!15i(@3_{ND>b5~4h=LQ zViG&yU46YN3Q}{DEAPZ4qQDjH_@=A&K^Z{|Aprb!d=^aIab18 zG>7PhDw#`^iFsDMtPhQ3t6*_oKn6cX?E5x^BJOOKpzA7NUE#k1#S4yE_$# zLRKapIWW`-GGBu79Njk%5c==xTiunx3$M4%J^cF_XLv8<-?i_Di4&vO zT$&&Mvm|_m^Qj2_Y0IBfzSxBgivy9GyOA%k)jq$u_uo>RK(6Y z?3Np_2#L6}AF)nE@IC37Y&}G?+A9&@SP9}MU93zVIKxfI6vBE?;osO24kdus)QF?^ zG1|$9DZIQHNw|fA_|26#5OFS=3tvJ;s|vw=f{p@DJ1>_YCRsMFTs%+m+)j@pm#At? z@yHQEY_CHvk)0BQB`l)_h)m=kD)LGthOurTx((m;43XYG@cS0xEhUmMhImi&IuIP9 zw+_jiN4h_>)?Galn#5)#A zj}G0bhr2eRym?7ut%x7>ZojyGKZP5Ei}%waL5t%yqvRK5G~ha~VRpa4XQ*szjHXFpC*#yx$B1Lp)ClXp~4X-*tw3g#5Y~W$9 z4WO^b?4Nf4KOz-A(ZnK3#CSA^??Or94p`qOm<>AOoe(hLDV%K}-xDCgpn1(*N~Vg4 z(A^PJR53ai`WxDnDQ<#xfnhx+Uc(@=F**luI#PBsg0Mir# z-C4JZsE7XebEU%be!?nbl`& zr@sqHgq47*OW?nU;SQZh*0VsUS`{wtYX2;?XBcUracr^Qgsu0M- zNWjOe0n4X+ErD3rDko}6aP7r3X&IeM5~}s$zmSNIqZD`wIQ%C`5e7kwP%w+PL>7k~9q?jBB_QKF<@(}HN7S3df5+{6THe@w{F70I`9Pe- zRVTfg5YF_iW0vJltXagJC%^CTSx-De54APh{TJorRPi^sVxmXQF%2<8-)lgD@8IE{ zKP^|Oh*c6af(_ifC9Eana_fNDN3WVEM@0Pu56lH+Q^hjzFi}(`L%-4~pprNlAI$*9 z?No+Y1r$J%Y$buEbdw6A?^Ps1BTv}QO+dy(gn1JXe-tbOBsg4&$N#l)kmAE4Km{j6 zv5)+xVMjntO|bEqj?0$%2C#kEO)jEUx&4tqpvYAUe6Aig#e&Tv(|4$_x@RE{01=O? zX+f$xxDivxsZ z4|);)*wn%FE)rijG*y6}hN)5lzENWAB!LfU4!kP{efRT1nGs)D2p;~xPLIT*;`2Pp z6IXoeuQRQgT<9+%LSCZL(jLBV4k=rOSfzvatV4cM5sfTiN&#Y|KA?{p*?R@<2g&%w zeTM013~z;MA{Do|5(P3X#x>=*kfyJVp>LAUO$Bv3e_&anuXW!&S8yiFqfq`Z^gIQl z@9orMSaaRmD)X0o#gmZsJ*F+$?k)CL4T62@Dn7K#Qw_r7O)V$kb987fMZ|6KR-6yw z`dxVvTXcvO{o>Na?Y7o0X|(52m7_kgkrlw zm5y(ZW1cQ8czX4qm|i!$uA-S=_TnvFI4}tDN%18bs$n1m|3`e?7-~Y18@NNNiE6hm zv}Y6{;VUdX4I{*M{VP~F?GFiFrXj$$!2i%;dsuLZ{Q@2*;6pv)^KeRm1c$F(oF)eQ zd&6%L{}N>@CYd+1J&fQ{M{H=$OKdm`gV@9)v}^BekxUV8jQ>jDVL~@R4dQ!BK+E+4 zfV8j~4W=#wlLmpph%j&i)SrR+JnU#d2d~y6I;p*m2b=KdaHP?DP##C3>QO6zBgom2*zmn++bR?Bitd+WO*_?KIhQW0jgy*upQ zQ=*_M$jzIQhV@70wm!1ge2rqh-3c98zK<9+Rtax}{T&v3We`g&u*?@eh{r~ZtdAw4Mx<)n z=fzT;5`id}p#h%7A`HQolQZrScw|jkH%GNy1WZYIHuoZ4;$8M12q;V3@a8*H^Mv25 zK|Q>S9v9?s8FpcVjmm3G#_ukR?me}($p)2ptOyHxa;_r#@?+J)C zYUx(ads88d;5{mq3cvzNWFjJU3tk@n|Dmcuv5*rn+wbLs!bC3i5f6T z6icVRT5oy_4X5o0zFV;d&Cd}FLJ|tKfO!g{1+NIrkwIWMuFjloE))*u)m{=!5c*b> z0oEQlOz4KUaKBuwhib0!w(`OKKSr0Sa~}mM*}En`T14g>r6hyGlx{>iCht!jKeese)Z z{Qbo@O;4|do_1Y~E~>bCbJ4YAF*g0Q0g?~Y00GT}AX7yDcO}Tx^2saL64e7FI+B3s z^#>cosl=204Uzq+88SE4x{CfTIpi!B?wK|dYTK@dmfu~pNp5ot!;V*ALOYnOu?zu* zc$x*i-{p07c3FZGaPR8r?^&>W19?uJt{RJ%EJ1^<1>av9V79CA=$rnZX9fxnkw11RYzDaGD#uBE zdp1^ew8$>O)x}iyE2Zqn8B5*%NOjjo&d09)J3g^0&@PVGo%t~F?KoaxYcKq&$yn^i(a(8`gWq(TiU3-Eh8l@E}QU0`e<=?6leUwWNof zPBA2AaqUHnJ8Icyoi~#4ON>A7Z4vdZWu*Z-{w3|qpN|c=e%()Pd!iNJbGHr`q49zw zADs3^D+S}={%{~w_T`91k+w{lwhHFf^Sz>B>sK_$snI2gg%{ua>A9(laujA>7?$X? zL{SCQOm|J-vNA?9AB+nLILA!6xOO(>MdHwiUEyFMotz#0qklsMzv^Xo?@UOvRw{9_ z)UGJTlEBH0c~crx1aWZ|PWD)>wv*Ns}A zWSPGjAb)||#qu{~_RA}jYJO$0yC=n}D6Y(*lqoX;=(NO+d1>4`N7F1zySUr%1sl8m zET#C$?i9F4HMs+j!@p>`YI{@atm=KwODzDEV?{y<-Rw(s&n!Eh78HnS1@^Dh)IRhS zuhzW(va@D-Bcz}~CGhcy3GLs-KPIM|nj&-CMLDugvzHzpXStpow2}W9IIna=d*jFW zCK zZX%I?sV-T$P7pQ;=wOp?p22<|dVcnwtdDMlLSuU1SGM2ui&Ab*rbVWI$zt)9Sh7O0 zjF2Dr-o@78w_<#O7vM|xRm%-{4G0H4s(~-)?~yX_r*qQ%>^;9sQj3^=x8;BSksP`1 zNn3p4M=>@L3twZTWOa-w(Tct~o0ue1vH#o*Fa!N|MZ_ca99Z}=M^99}DDmR?-%|R$ zSOK$CHOXPAw6~a+#$uHY4vtw5s5<&S88j+l=CoZn(^yd)Q$Q$wb9wns5GxB}AhX$; z>V4p%9pUz^BTna->bR@*%BQ2}ZOnf(Kzoe+q$(gbz=M7_qGmeLMbXx^^+6IIr73V` zHU!Gd%8XeZg0j)#r#Hh9afO{1ya^wk3_RWYu;Rw~&G^#Ry4$jmkCILpy}=yqk(CSo zHLU7*R-P|0m~C~jpLOEhG~rm_lC^UD4V_crJb3kwu7)#iH+-OnCC6y+s9F{5CcW2m zdIR=Pr*_{3e}yh_pvd8TF{MvSAmd4bnLmBiG(s>uzUY>5fqoiOz&^3dCBSK{)7Upp z^6h9Psh5xv`&X*QP2$P<=saPi+g<6V+FBBssyy*e#&(aUe`h$l0{3;BxL(YChZznP z0d=y$#bac+&UiU~) zgbKC@IR=vk69P6$6#wO=nC=oXBE~wg+xDQz+#K<*;|WU9LP`j%BqD|l#7y=j3+CU9 z;N=dIpsBtT!``gEujBJk3Bq<3yIC0*5>G2_m-MdZC8lWDq$U|tGR=qmK$rzy#%dwJ z&Yyb2KG#ZV^h1S7-v$I5i@=5X_iZnVSpQz9A~&|}%z8F%hOb9p=~B1;?uKiYX)fco zW85p$n-OQbYMl)}Xc%^opIj~RSDCxPusu=&idyQFS7nV-0vYQq4hm#D?7yrs^|}P zvQk$TXgtgx$RJjnhLb&;h+4u*b0e8?3qahTNxMT6S@qXj$=KbJ9&w8!3H(dj<(QAv z03AW&JZ{yhwFZ{*sXjg-xLvbVpjT2;JemmQS+)LU*%^;H+>`rLj{8fki}R9t1%Hu=S?#i>aBA-#qwknsw|b>9$4s|K(}Q$~j7}=~q=}CtAue|LPUi zOgY2}@!y!Q>tI9X7s;$=ow(P;MW`QD;@YMaMhp4r)=z-Mz+Zks^rBkBWjDog^}&P} zyiUNKJD|x006UNFtb`JdUV#eb<^@GGIxccR1|J@cLvg74j zs7BAPWThpR`pCUxS<}sqh#V0qm#+WJP-SJoXo;PQ?^sC+tGZc9|++Mq3rotRyV`l*b{fgq8>lF%qVaDlHJl=$LdeOhM1j9fcJG!G{U z^`?_8ZR$JQR_J%M$4J10dQtscj)d)`rA7N@^Ru6_-^$O-$ma#Wg(?V(*l=U#RTRdx zi$`FYu?gswDk~$q(;)A4|JhbyWu&Pj)V)arlDXb}ppgL!nzWQOpnr2UU0d^5ie;Aj ziyB!j961}Ikv55!g7Y?3s_tW04>FyNoe139P9e7p$&?uplfoV>U2 z{phib4{?4HEsE+Z`rv0uwczCZL&9!0#H5$M5{}j#1IUe685>w;h5Muv_c7L!K0oeN zHD|vNKUrvE{+N|UT{`LKflu1MjLHZzPLMhHl22$mCJ8mKxJIz)OL%^iBbwCOwXm`% zswD?rS<#H&EhR-sJdO8mdDe27AxHIZe=YvB7i}2(tR?tA_?2hM!T%jPE1_KVq%6Es zN2qI$TE`(^D5=Ae-7H0_R3uBeOY}P^$RslEhCutjs^>Boo#7QIW_7E854mk#OM{{p z7`>=eRVG8cA5!C>FsU6cV`hokR=|@wWL6(Y2Xx$>1E7%bIwysHT!u$$GL@Q+rURt% zl4EHpq|z3t*tQG6R6Pb~*9S6Q(vh>xSr*za$k7xqWo0U?!X$CBZ>+Ss09Y_Qj^{EIyBM-G4$fTx*8cR?StavC0LIr+ zy{Ur|!bx4~KtUz)XzBQXd}UVQ%l+x*ex+&w1qVb@_qyLKzrs|CWxhO@>e|FAM|GLU zma)j>1rzb3&bD!14;_2MKK!OdzRXtm7U}$ofnp=!9)1OiMe1R5+#5UECMj`-Z8p}E z^oE_1-q&JmpIU2wquoCJjs497Mx1H;%)fnU74{7bK)`l-L>1_42`G|S5>}<2)MbC6 zsjug%Lwt` z+aJE_a9P!{@`*$3jAPxZ&zbh z0c+6d%^Y)l{nvRI>N0{E)UR+JHFFtrb{Y3|nFw`xAL}xi?lM*AGF|J!(h(MLMvt#L zVyjq8=lB^j=gh7_&n6eH%YUgmhfD)Ook0>h5Zt_>Y^NqPnjeHRDZ}5}ojGqZZ!8Jrn-ZWh`qj zkhVYu>q_(zp>HCFBx@OGDVkT?j8?8#p3$`5p0>{6P-%lK`h$!Fm<0m^ey$SxRll(V^*n6iVa>QPhQUgji)_!#qU#Z%oy| z2u}l+0>F6YZB+qAw>3V8yT+c2ljFQnCU3mg?Z}`~QX-=V!U|B~ z_TFX$l}Jc(rzEFC0Q;nZFH+re86}a?GuNYMqJop}78n}OB}Yc5MAK6)+k=Dfufpb? zQIO;~I@m_q4L>N4A5MS_fIab35hD&LqUhyT!Crv$bo*oR$&HO4j1B-#_9eGP){hwE zc$7f#C;@*G-0_cz;)+I5zdT=C?6oD=0D=9L@EO%mdAv4mO{EaAipZ64fSCmHbTUB==nz zijr`iqOpI2`^8Z*C~ZpqEA>>9&L~RcV*P9kHHFCLpjjZf{rW1eQ}#aejWvh%E1vE6fy1{j_YeJ&Gy{yqn_3_u|IvPv|T8@O#q$u?&u4 z`CW8^T%0UA^#_cpPmG=f5B!5XE7MfFbkv2FvKc;=;{^yAzJFoqWB&HX7z#I*!3b;x zUzx<7Iu1Cyo^oj^;952MQXg2hru(W(%9Xs7d4t#5Qz-%T*%nHoQ%Rz0^vxhVH?u0< zt}5^-vLJwZCQj?K>dCn*D9A$n_!FV&=;#!WS$X4~TQnL+a2|4wbnmFv!Z;TYYFrwN zX3Cce%*;1r*+5$Ttf*7QwnMT(;Ax}XUg=SnMB#8m7hJh3BiW=HNes5`V5yY}VU6k0&jMuVjK2A}HCn8wbe z1>uOvl+a?aHDAE~=$o{?YrMcUqxSeq#K7ThmvP!Tp8MI1UGb;MD-qYu-$Z@?JLY0T z3ISYze(?;-Zve+o-?bHse4`fIDJ;bRA2!-1b>t=nRaKoMelhA|cvPKgD+5=h;)uTB zx{p8Ht4dmitINVt{OXVT)4(x8`bD?jtgt0qSfXC+L=x@WZX-~@jrJZMc4enr%$U7v zA8$%cG-ET!#H9D-iP|K+K{ucipDudqU7{JyY8@-$%u4bo5y`kZ_bPu*v{Cd(o``{$ zq8eJvj4EP=+8|R!OqsG66v(3|cW6e$tf&Cs84u0Ep`#SZI@L0f2Z>!KU(+cQt$R!`JikUq7M~Gq=2gxjPYe z?wh*--cC~32UqYV?W<_d;J#WX0Z#3jb0DU%sn~}XWve)argSOv&M~A7V4Xb3B59tk zs0Z3rK!O~ zORa>>-NWWT$shq%hrl2k8k=1-z$_^;*Hv@{q%mP^{{6q~%^AM2X`UNB6Td-8;{(4?@a^ z*_t}}oa^1W7X*6>|^2fXTB{0B$})%ZYdih845@E=Ho14+WUL3e2+qH zqm1!;hn2j>AEkbudf9aH*tqk@f8(M{Yr1V4&906R-dHU>IloXhdgX20=WV9to1>oo zIp*1R`cq|hQ{0_vjxJ#vS2#DUES|EyRT-1RX13d>t(j!W{`V#jaW{FyAL?6 z{AUpV=Ifca&Cl%4e(4mjahTb8ReuBtP|S|$dFid^?W;Dl(`}KI%`sjT+xQ{F48W__QG;?`Onx35VTgp%6_c*)y;bGIn4CYxCMv}zx9G+shi*|JH zePokND(-VGLzK@%ZC5E@tSeyBzGhaHQh7=XFy=bfSx53o^ zaJ=WfeG9uq``&lb$_3Z*?a$*}x_bVHLH2Y7?XsO6__EXOYsH&|WaSU6ou&)xu|-aI z|EjX=SJM`(%9m|=+p_B;WtUSykJDxcr7z0w5xpb#{H?#@j=pj#>v7WU4ZNYS>m)GCF*4V* zE_AT@lH~`>tv&7G_=|gD_c+7(pS5O4j~8JK4FcUM8o?_Uu|U+bb|?VPSYztrb`b# z75VbJzBqsBkJ{xnOw|CJ|L9V{Z2i{SHg_-9{ZU4z!rL0%uUv2Wfob6h`S>~SSN7JC zB#yu`YCn;a<+dOcoR>$pIEBHE)kfti{F6n=FCN*77lP4CMQ-37`IhNzprbQjya}7? zh|2-1APw~-T1AJ_r>-T@BNXgNLSjK3&t~b4+fOZ+VI%`|bR9-gjTmxTlN1ugKxd*^ zMjax@^_2VJV>f_FIMCp=vFxOzVrR!K-^g<}?Z**Gck9wf_ z+nlhytGq%@F+fKN3_(J9o6|xKpz*QUZfz0IcCcS~2l#qskJ)r0vj%i)9(pHrm|a(Q zG}OBqnC<)_fJ9f55bgNgu4BwXdSTtJE$e9Dd$ORa1I*Z(1VWZGF{j7e!RDb%ta=L0 z6tJ@ZH&dNmSJ7~NKNBZA@$U8g`814n(h=-8%>w5!@_*@}tYGxkzSzB*rF-A!1wWd) zc!xgd^5bhUzGg_p-H*KOOly>Gb(i|k99xZKBT zmsTSiQ`laHM{?BSFlqeZs-HR8Mrqc4r$<;Z%>{BKX=6Sj^(b;Y*#f8a2 zLE&otH112Rll-7Wm!+)#cVQ^_vr9ECr8#@6mqW3(k)fXXes8yFkkZnuh4!zU=SEl! zgTz+(5=0VOq-680ZW!v#Q7H&I0~FG4sMkK6Upv&jg>TO)&W=Q=|GyN`!p}5d0KfC0sUYfh9(`^9wB$wNn7am_NKr|> ztdTG%bjo_o+I&u}P`%7qZ%W*4*HT;<*F1&Df7)+lez8DHOn`=ct~L*Hm*obtt990C z*_J*LdBI|R(#8s}g8z6qM)krC)vd7~)}u3WbD`I7IDj?n~9o+W7N?xh6?nZ!(9BQaeyIXKxHW1iiaUrhFj}%GdII3-QAh zDh9J7aqB+MEpQhQ4kR=z@vs6S`CYO@%B0_HPj*QtY|fukt=c6h-)ahKJv2_i^$t*M z_}wU$nT75;DciUloOO6cq!(S-Z0;k>U+_VyHwf5sOyY$&Sybl)YtY06I+S#eS6I6< z;+@-Md5Jc=`s{c;n7vHBaIUL{wc_qoaO2+9xf#Q|Z4jU-rxMC8DEaXT}^JjH!?D{C!jha*Eu_8;4)`wxuXYI zmnPotI3Z<#5p1Sqg}eG6me*z0FfmlcBBDv|OxBlJasX_OAf#L5KbD>NV>eO_h^Zwx z(jhfT@Z9c-O&kCQ07Qhc)-(@Z%29SU63QZOYI{U375@)MkV-RVWLnqsnQEa09hc;VN(pw5$*pl}>E7`WL| zWE8DXbrVP{p~NhJhz6rBYbN6 zAUMSYkz0iZvbFneN?%AFSTkC*<%eI8SYX^Qx)uI{wXTS80nO#Ul20e%u_iAeyPaJ8 z&S-LE&=CMuO43A9tdX5@YGhP1LwCN9h`p(G3a=SXAzK@`2O7AJs4JL+EN>}~dZ}bQ zK`}#mDt8GCjVMGmImXw6dKJ8ZKY*BgZ4(Q?r~%RMMJ}<5Y=)?l#8yijb**rB1i4#V zMcFJ1Y$k>ff9AH%1Cc}+(x=C{ot$Ds-WN-fBb^|;61IZnRt8p-?#USIv<`JYe+X$D zqm-iG7nj04c>{tKWW?+54lnbXktpDviB}jyXJfT3xY3rg<#G zAtf{2N>UaWw|_)n8(XAp7KDgp;9HB@08E_@(Y8S?;ESq+2Ak z#5f>F^|E$$m}9gn+YedmzL(?v-MruSYp8J?08tCL9ixow|E(#&D^~%R2~{(r0>_ZHHP5XosHw5qN5^v zi(+|~nu!Y{X0g(5e9mD~WIM=mtR-E32tG#hnhYIuIgn-A>({PQdiJ77Fb=ad`cku( zwaHRDSyS$Vbz0vxTAJk$lS^ys!$t8|u9Ag6M2ws@jESZ?*A%z=8Hp0Ws@$K;>_wH+_ykMIMhWjYxWNOz*t2c}GAuF!svXof&|22!O=Ybmt28UzHgPcNNkvE)O zpdNTuNKa8e!`|aK-v~QIwXO)b_ldQl&u-OVdtiHV@D`VrI|q|@gu^*JHdZKtS#fk6&fsZSR z7uZe8<5XTLy1uTFG+{zHf1gNo|_c8elgAem5K?&JZkbz?b=vF7Q;XFI^#W+)nmleY0G z2_0dB1;t5;A>P0JVi*f)fBckbd|B?gyICyd^exsb7u#>0+4S%E-7YAa81$?jSo=h@ z;|(1lsdfuzL8C=(Gc3MJQ`}`shjo_5;k#}g@6(7)ZYb81XXR^Zkk$#1GyBc92>Ebk zqxK()+e}k3K)Crd1(DOdsY_l56|K@=J|3ua?b(<;xY53%p?B)Yu`+L0g0<04mQzB{ za0Sqws(8!Ot1}Q9NlYNRY>ZhPW+!m*^GchW0h+-9_GNo`W30QO`;?{brvv0ax@R*< zSTtnVt$h)9FQ9)Q;pNkBF`q>?{U#VQ&_8yOh`6&{w>+f`7c{K8OUy9mE4s?V_^>S9 zD#(M8?XDb=>b3<<%sJvi{yjSX&~ zYVDl4B^Uz%J)v`MA3wBG@bmTO$M5PTzyymmqf<+0{A^m=opL>@RVp{Sl3U?YEv1LAgk~IFpX`n2CPk-XYy zRU&_sSh`YDPKoI0>_O7!pTGHF%I{}KCn&vpy`qj;qdh*-TEScS6lkusgNilgYyiqd z?uJwFK4scfl%=zjZJ{DQ`N*b^EqWU7&UhS0t|lL%YB|rG%zr>}m~8M^+_|Gr1FX#H zOtzLmfA}W*9Y?%j*!6kZA3KhaGT3~I?x0^zbV6WPAc_zAOJG3-0L^;v)=~!N(o|CS zy_d<5#QTvp_0NZEHQany`BU9iLq(JZh|4Ax=_c+0oVCv zaGPKVX#Cgs;=||ikjH|<@weAAOs+%_VleXHPjWv$^)>9|nUmjQL0iEa`n^>unA(JMQ%y{*U{$x*UDmNAN2=WyTv`S1u7D(R?V*+(GTYHw zLA2kS;P`sOSzhLm$D5`cflC?rdH?2BulSK4R|f-`T4PUvg;N{X zn58*_buHa=Yen1swCh0wU9-oMsusP3ovs`(?6A*A1J)C-hc50;PY#GK9{zO*=k~3M ztcinR2u_U+pSRJ4el{!V{VKSl)?E{w>@hM@@NiSlFE_dkCS5cGW~-X|Hs-wBVCAb! z_#l09Z`54PGIhP>L}ze!?>456Q{tbWOHqZfzegSdLCc0%m#?c%`|c|D5KgXN>n8mw zp5DpvWw84m4EPmaaWoT(-Zn#hH2W62AG4>UN;G|!rH!cElaN6Vqdrb;QnR$o>R?E@w&IG&wrS!j)R{l2K5 z|7`=-<;-X2h5%9KhQq#}W$Ig4iPsNnZbZVJ-;A4H{*nSR$RZNM>aL_NI{6pAcgu^= z9QMgYK8{&F1uK&LYv8HMl~ZFVVUp&3Jx(q7&eim~1|ZC<1p&Qxo+h28c&14)SI>-? z=l8@<@~I7nzQx__yi#ic!tATtau|QBL_$;~4))pFgF7r$>3;yLYFP$G4sW;>}zlhCD^qI=A)6D8M#e34l z5uB6K%gVKy(Gq02cBIcN{){{DR$Jn^Mm}6VDKMvvij<~gQtjsJbLidbdq(RSL?0Y! zve)#oR^kgE!v2-wx#HKf_N<-Z4vi7o_A7wunvDWY&6+A|vO#9TYM3d~2;AM9tC=7{ zI_GSgilkXNZ_mh2UUo7y8>gpr)yL7t%y{pgy@$g*KM7^9%a;e+ec4dM`+72a zB6hM>Vee_qDN931ty;AH%aYodw(e^uHHD81bH`f^v(^{y9#SCU`%Dz@39jCDOt?0z zjqUd6@U^s0#fPu;J5a20!(0z;HH!1G{#*xo+ncRJa6XyQmG+ICMG1AyQwmLsPXBIL zm)ULdNbQ=?6z`kWG?lk8EiWR|BKp+awd6ps0XE{w5I1OsVhp@-f5P23m6P*dH5~7P zs?jBbI|Y8a_~&hErh%BI;3)4CbBxO0 zwj_v}uNUtOq29x0)_R!ck%yL-P~+(kSSj&^b?l6F#gm*E*D12fZ5sM4n-z35gZaQ< zz4(S@gRhzShozDSd8y)QT)TyadA}-BIm^UPo@&40`x1IM(@0D2(Zo)O7tv{`*B`=u zy)&McXQ4m6YeQeCI<*9Qy_tn3aZs3$5*g-b|4`t=ky)!#4W;VQCHSj8yH$M33TXBE z`tj0(P9?-Dqgt-c?FIIt+a>vVsKuVg3!}Ud?uGP<8mPN32vIEuGLexUJmM?cz!eOR z9ijU()H@S8wez@?bb=&yCzdGZjqZL;+pz3ue7E=kDQBLxG@<@v@enG#o#J?bMYbQC zF==h!;l2V0=Kl6u$Bh#rP!vUQ6!CdX9YaTcnrZA|#QCqDr7N$X-~nxI+F~Vq+PoQ( z%2VHX8Xbv~kO>wmh4eLfvTc2BQKb|5Y()*rxzfXBS-&-38x^ENL?to9kOhfAnUb)M%(Dvk-hhv^zS?>r1jg}Av-+2i#~RGTF3j(GqgbQ z0zK;;Y>G|_NFCwTuqQwkz4wA&_&Yjo2XN{SWL+xl%w^?!tR z-<1jr>oeFMoA*6a@gB>qkhgzcn#=`99QPXOBIx{&1Y4iD?COeBDgTw}X%Rs~Icb<2 z+QRiveEUe}LV&j{b8HBGQe_HyyqTqWMggSg5`t!LuS0)pe{N0XRE~27@f|cjWW|G;fK{XlJ3nVviipW!g3Pkn>R(9Sgpv}r`i$`C|0st0F1U-GP6c=vSu5v- z*EBo@Ea88WJbiOdV`>nyx!doL)03Z>*rjkxTYR7!@h3{RS@*g_fUvFMDd8wHq?tw| z(_u_)hfg=5Bx<>)WNJ%J&-#GB8^~8#fJGO!P&D4}IC%A2nWHN2|Fx}(^a3`W7^UZ+#KiOEnF|OQ)@B1(OL5rdJ@#|DhYGSQZywCeHOD;U~|1S zs+47x9n!qLH4(olj@J$R?`liNdcr1LgED->A~-8JVW$R-ziZ!1fc@R>`w54YZtZ8z z+9w*l-#}~deox!Y5_~%vlIhxnQr z48O>2q#xg+^}8Z_)45gt`DU^9dOgg(e{h}3H$28_-*OZc1wD4baF-d-eQ0h7>0(4i zi8!xZUZoLI{W=db#sZxlm6j)Kx@x+ZXV|PsiVjT{Z5rQghgl^SrI(4&ZeQ5^7G>Ss z-CHguG4;*_1cGCY@VK-oCi8(wOo%)>?mbu8G5A>bTF{8@s`!~ZSmWIEd5<_DzDI~K zRG{an`Ni9(WyluD8a@E5TcYk$Gvg6)iXZ~u-MHu+aU`9&I6`u!CS-;*Z$(e*uIlTe zEz(W&yFA*OMm?mrcIjgk91Zydb8D|d5SIdW!L=bo16GnGD>@w>KmT<8f(4){nejWuiLV87a`htU?#d*rd>BfOS z8Oru@zgdXu2kQP4j4DlWqrd-q z@qHO8{rybip9vJi+@+#KY6hQQl`Uwzul7tmUIV&xRNAyKNF)g zUf4WYcYxfy>^1T%;Y@Jh!;D(|gxnnj>V6QqBmk`{eYYB*0^jU92eH<82h_DJO+Bm?+d|+Qv#j{dThML3%+2X_#p{ zMs|EF)Zn@syR{G==iAsv<RtITcjY{xG^{I%+fodVTSiSdmkyh(ErTRF()KCy}sH$b*n(brQc!VM2LbA=~J zyY(i?I$a(iZpRclczTY9{d1UlZRU1qG_49)@Cq}zmDl{6g6h=AZ;RY|fVFN5f+wpR zrP<-fVrNJ@Oyfyc>x_Ty-Mwdxi3eF*q;a+UPwep(;bOO^1}{(hMXQ@x^RQVuznRUJ zY*>Q6$#-C|gPImjmSA*mO7DY&Ycc%Yf4AN$bI&;Mt%{A_XEU8i=0VvcKDQerL?Z{PxlqyNLcYoSqh;&<@c34NP)8p=DvH_wVAK zS+aIC_&`V9mEV%z7S{VQRu)_cF2R<@)jZUddetI)i4SgfUe=FbfMPFz5NSqq8v5xG5 zih5ERv?+~wDp(e>+QMvHgTVz6dTs7x=?Z>LSTGEt*s^zSt_9qmx|@u7_Zx^adq70j z%)>9~jqoDcUj+rioso=)OL($tm_Z>L>-y3)XM@w9qV-0nK~h6xZnEv za#&PTe>34hSO;%#q*EiM{0O-QT0+LdPaZzAhNmC#Aj;Y0w;rui_}@YuO+zRZczW9M z{B*M(KZ3M9ApSo)e1^XDr&3$BGM}qFJuz>qcdcrgo$vcz4chlaUqhTnFHJc$UOn~j z6Dn&|yIEfg3Ph%KihmnoZ6(STSP7A-QbIAz@x{<2TFnvK84~5O?YkLV zgj~a}XKJUBQ45TszwP#`Bn|W_?VJc~NV~~&hLQtVH*SZKcptxuuaSxlANY5pHJyj{J-{=*nBE@J@uCgUM4{xqKbf$z+)M(e!+%j zV8dZ2i@@J1Zd(4i56dzmqw5jcU8?ITPCV5K)NnPz2&hUpJpyG`>rhbc`gdx6tC%IQ z@jR{D678qj7{7wJu7{bpG9bFte^nqLm=wro3_- z=AAkL+77sU@%}p%4QHbTfI97R%_iUm6u7GUa@9+%t6`@+776kXwM)n|NmQgXi@jiE=%ZRioLjl1@-b6~L&o547Zk~GLD`ABBN@H_tGWFqtM_uahd*UL zIom5I$16ruSMAa#X|o^OqksDkEe&8*i%a|%axaMsbsN;nC-lX6hgG{kFTBtj?SKN7 z`dJ8gS4YaXs@~G6GF|VN@8epNX!{yXJ*V7lYB~pN!plG4{0$AO{0)9qkzO8M6X(Re z)cG~A`NzPvvmW!4SB+{6v!*{~EL_TVADHubY1s2}t54H`{ez#Y`gcVd_Jj{S?l9O2 zvfxAqt>8@A?gPhezYew7EUgK*+vwwynKFk`PYdyt)NN43`-YL(saqexp11o2p zbqCHoofwLh=pTBe`z?3MW#%>R!?AyZt~Y8qlM8pAUTVaBd2sE^;}2i{!!L>sEIx44 z@8RJ)CG*d(jklWOU4q^zJy)^Xs8=5tbpETu?B1`YnS_2GK9=}h_ViLDP3zoiHt>9) z!2wJT({*ArFfZnZ^;@ao!DZ8ffy))koAp*~4z4)JuCM&SV=aO8TR#T2c&Olo&rP4I z{vJMR(U4uTd7^Br;r1$@yVc$K znzE&NHLJ>7{xo_t&bOtux6~}CG5qot#fl@793d#U2HtnY@%X}I?>%1Wb<+7Y-1gS` zp&Fl3i~TRk4lCmwX(K+vt&O8ip~WDHvLTcsYo>|vba%8hkKc=Z-MGK6?bf>o^ywE@ zcRaZL{&CvM!u!4lcRv2dc)PuL_(mTsKT~PnNN4-qC^ieDhg+;z>gfqYMt-PzXfXSX zNy)d;N!dKubmMIu{#LTx5$4Tsw@&X9>(Jpe%yi0|ylD<@XHIGT+l?P*+hYEUcsbLuN5z z_POQ-;?uEA4MY1@bxe42gYu<=C^j!s%_#t4EQGwy%`#Fj3s9N4IQPlF8AQdeX`=25e8DK1rCGW6NONP`o2Fg$*SGk9yQEA-cC+%% ziul`5V6lh#(UxAl*2v*c)w(qu*3Y3~ZDyIp`IFTJpvUj`;&hJN4&Q!UNbU4O`Ti4W zDo2b(z%(7OwxQUxD&U=tT|T@-nY)Kqgcm+>hT%ze7!zi7CHnPe$w?Q7n`!}?!XB-| zew|R&$D@5zmD4VrJufWp{OKW#ptpYF$;6DEZohKCA|Y1c9agT^3BTOg7;t~UZ9>2~ zjNILYGahoAezE9Il(y`0DGEJ#E7h?=RODzE{pBWw1evEOse2kR=j0?xlHCn*EVbmo%vM-2gBNbfg#_CUp3t zjE)OH*P4EgaBJ0nmLp~;|E$lR(9C`GOhM&_jKSQr4D2@C4j~8IX1jGo_)^gj_$iXN zZ0i_V@w$l+nI^A#b_$={+t@3^mPC?*!+deUQ-jOq4FYfO{r)9n2t@BF31Y|vF5!-|UcWHAzn73x zOfzBt=>$jvb08mpWoSx5lsxJMx^N}~nEaL2r9q21m@j>sWF2OD zqBVkrY8)Nk>KijX{RqTvuGD&(^5Y(4KkKT>_x6oB8Y|oCokL{IE=OoX+4w@<;@ig` z;{DxLHf9L(8r$$1VZMtC_j123#vQ*u){73ge|hKE{j=)&S>q%KTmTyU_IiAqglTef z2wAu|XMW{uLcs1hh$|9={1E~%#PhP0-=4v;VzX>RBfgX8^<#D^r2WS%VY?tfSoi!| zQn&%kYes?ftTQf_KeH{@xQ`35LS|-2oNlGqe!}k+io%K z0pJbo0(m|=6O&Wjc?Q(U2_Vd!k-CE^Zz?ZK`FVEZ5$b%7r-guY(IO>Mow2Tl#Sfi| zzZ{2cA}N@=lk>d!VP>9ikGcFo#b^(aRtKN8>l8hgW^1V3!)I&x0aZ-(THr-Ko~9am z(Sa52Ynj?_uILH#ryWEZr2=xyrqfv0$*1u0&`hKH5{Olbf%*xonl0mwA|bR9n!@NN zR*?&W9hv=>c32l0v`KuX=O^X_J#yPp@I6?-G9SsKAsVFchfqkx@Yz1GQXK#)v`^3q zgjBs%^rguI=25T2N~ihuqCl|h1VO16i+V*w@~8@F_DL>WMLD$e@e+(LjoljrPUW5- z;2_&biY}xOJX~jYEk=TcwsBcPJ~PwP6>+v)1b4Jb$e8eTJ=~d$- z;BZ1~%h89!NADXXy|K3ss5#nfbF?%k z)DQtROhn0g0nn#)ut6fK17Mn~4!_c+WM;d)00>CNQsoiTdvBhI9t8N(!I{bcZyJco zzwmJd;Ee@54cdni!}a(VqG>=a#*Vk@08LWS+87B(2R`!vL~o$l5)p6`ggga_dBCBBe4Iv&07ry^o3KH0WN}4Il>yNC#@I9xI@$2@ zZz|>!7beWI*vLo9J-s(rOi8ZIS3Y8M7Pv)#{>jD2eqm-9u!xedaU$lI6!UQ${egyY zJ%MkgaqpeFxHhtLDTOu&sb z5^{6-o)fY7>uJ7s%yMVE^JW~5U9`80%d4#(&&`dks|l^+*4G`2C#2R}blw12i9y){ zz%Bsp#KgHSLMZREQ?>n zu<2t}xtWL;v5MYl3YingRN@7jpbN<)XzOX%OIr@$S?W?OaGiz`?(+{ z30h1)Xd(r)p5Aes4t#42=s>v1{;LF@q{FHK0Muv2f2z$YzQx;y4z8$CG18_1u)_Gn zLBF3c92HW>Mce`0(GbHo{VGu-!4XsdfB+KamF8{%90jEz#FU=Bc0l?zM7LLV`qVdhCoJ+K*L5JX48lLn-65m1`T1$KFSZ+W6Q z!A^?&%|K6aFh3dBzEWZKLhzvY+fVA4F0H&(J-EVK6Dbe2t5q;i6F&F@0QH5)C>O$D5;}zjH7+4Tg*lnjl{P zLO@IS=;SEJ%e%n?0Cy?lT3l1xt+BXf{RX3l8c7- zD~@2iD<2>C(f_!1l*E8R<1vfe4$)=Ir@^Ywz2G#l{n{Y%M}$62+bJkIx7F*WtY%e^ zy!U3Z=2PDnIi|R}BnwgYOzy++&baM){{ovU=^#@9K$)Sim+pM-zVd4+^03CSq~+k^ z%=9Z6$k7~R*B9nd&xYr7$YFreDH<$|bXq%EAyEuX#fH^#p(#{YWUL8|fxOTNwc{$j z==m?WS$DQVVQp6aJ_^wx0?yJ7cCD1i6cq5J76EwMAPX8vFI$_1X)+8IN$>&0t$*r@ z(KOI$q)Y#HxQf7S0}bL$0I30Jid0BPu#Lu*gQPZ~*C3=utawOE!EcWuhz7XBDF&Fh zaJUBhX%GXcj&5@4^h#&??K->~ooHH?s|Km4OiVlQ=%V77YP*nrSMMx2cYAoxk1bqxk$?g#bePw0j-%AA@Kq@ zL#*_JfO*OoE?~f>v%zKJCkuiGM=ne@Lzna9a6zo)uUyQJK{QXkBrssJ;bd~T3hhqaH)%$}3l4-(Er4)<3(-h3G6Gv8KgTd+r1 z|GuTJ_J$-Uy7Hspq9tke{m+-3oBlW`TICiqja>wQY&zVE010I%G_QX|gP^@cRD7rT zQ<_o*7Wz%u?42e;rp=V+n<cX)gef`Ui-WrsxQO3WI6sgkBV>7r_VSJ^%)tgsEc{V&#ty{UDeC@Nx&B2rjQI zpcFo!%n!I(1!TboPzlBVZPC;R7y>we=4Jqe`ofMIzLN;F6M#2c1Jww?JGeg3An-mC z2xkDWd`LdOWiQRRbq0FC0V;H{au@_^&|$A^5c~E3x+>W^)>b-Lhy#7U%KysNG9Xu; zLi7Z#ZyS+O9Ej85xQU3ei~JKHI;4iKRLudso`n-={>+sD;>K62;TY+lqB-`E-Pk!< zG}Qjm4QMnJ{h`=0Tm|f|jz%BVH>aYI-AYCTd4$D><-tlY6EndFU9VN1BMuvHVvy`d zK8hE;>-A&ap?^tH=2Blz256Fl`A#)A=r}5qz9zelga(gzyVg4LElGTkgdxXUZ){|s z*0GoyU{f> zPDh2m;{Ns1jk#kx&0~L(VpQ$$o+MBoHmHs7AiIeX{8e4vSR{JFD`?N1;%jj*-6|^&$s34ui0`1qA@`@bV=lozA~Q2ysF62o%0v^Ndyts~>q! z;v+J;pZy<2=i<-w|3~rNY%{mH55wGYNpdHK&0Hh7Q&DrxHIv(1$}X75y`)^4Ye+&7 zqVHzNrG$`5ato=1BwhXX`vbPeXOG9{{eJI#Ugtc|7>oIA=}=r*K@0%!Dh^B}6@kXj z0sI!nsz4#*nZjGetLQTHP~e->$Y)zG@3_oGzWc zSCs0)vrpZjfHQ^V|3r9Gh9)4DSIknOIm<3)$!y}3`{$aB2gyH}wcbre(1$5oVvF^{ zBNb+6bp9RDx~O%o6BT(-TVMRuR~BOs(9~yi-%a2}KX$pk&d7OVVDP(%y=&l{Imx<^ z98aru>q#EUdX-l2>@4<#F)HRf-|74Ms4D?i#R_6WgaVpH()4uLz(36Jq6?k&U;YUeJytNqvVRq2lWatDjUEB`NDNiXr zwfJ~*=Vf?$&`!acRc}~le?^k_l}fnY7xUY&0?E^B#OgOIxuPR<%W}`0+z21^XtNG>GBBm#7OJ6#F3celF zT%wD2yY{)?921TZD!bHYzxY6`ZQ@S3c2>P}PTbDoA!qsCmtP+}+IsxL!!yP`j4yg9zi@>HD|Qa%FP*nOqScN?1o37#(SyGDT}%f!z)wQmCaVZyEwlE{rMc znN8*MdE~5?kvHX%>b_mQ@gieFYhGTQFAA$}ahEEVv>94(PnxK%BQE)3`nBFaEI6M6 z-_1?No^%}!b3tHga(P=-csGW|Gf3K*7oRQ5{bVusvv%8V)n{63U33tr+Rh{AS34#A zf|-|1RHytU*tG*8W&d2jj#Jg#hU>zH-RK0G_JO5#J>fw=yLOToplnhh8A zsTMx0^|;s_Y^}hhdL{k>kfq6PLF4Se2yv&axYtVJt}=<+Te>wUoy~-*#Sw68ybQB- zy!4X(=&7Zpa|d%OBZ4aYv&+v1QY*C3zM!$Ub&C}P*=p6Ag;w8R35QOzT%tFB2gTxz%S-(ExJiE z;(i7AFXXLkZXv}*Y%?-buR+w?U%cv=mIjY^zla<$O(4?`4k4e0T9K#?4^JTcoz=vz zzAXN~i&n$_s^x=28L4N-gut0u=le%Q2CY;8m%S~aT1cAVK2<=5L*37V^%DJij@&z_qzyDF*<=97$4}PxO>J!0^l7b&)lel%=*V8!mZ3Ou#)O}IS zc#Vh!7U5fqt*|KFN@a;yxQ@w5c>FjoWiG%mX%T2J<{}6+@)y9!$Z4a}IFV zs%8s8MwTN-dTZTBK9@9{h#S$H__SO<>k3g5zId&!f5tQ+^uA41fc(46DB(VmpxxO* z?;qr+*p1d)T*{tNo5@b^!iN#B$(b8E#jV|e4R+t#Cx@GwBtw%wu1Lh+EMwNRX*lo( zoN0DIV2LaRK{i0Lj42|_w9{*ClEgImOOH}WWo6tVmMswWil3Esv4TLD^YR#dU-6h| zfK!o~W%-)_`Oyn|jkf?mp)qd$^?9J5oRxp}d2<=I6xw!*B6tlB5{5uqx}8trjyQ?5 z-<*k=~-zd9T&?c$_bjr#@96ChzI4gk>vfP^T0vRvh;ns-e7 zehCG?4syRM(jJY->4TgFrX%W^4IwB1sPhox)hTfWm&Eg4)-ccBOoNbPojxk#8;@K5 z9YI7yI!Z#uVdW$u7>r^;4FNzaTou@EA))8;k5`Ml@diJgVZmQ&F^cMzMtj}^8O=tg zmc2a%nkO}X?)nRzBirCVD&6baTsNOeI&@h=nFsEnlr2)}-*I;;FY>!(ZYo6W5hTJU zB_KcRy?K4!z=^)-0|PPapDfP*$qPq6`zZ?cz3d)-@Lq3gJNG;iEOp)@Sr>h8U9!Tc zx5PV2@Kr0v;GdEZs?nwx>W2?3Grr=#^EG#yD)>t_Qt343Z;> zaG{TZ`6a>Q2c28l;x?rj?a3;zusim2sdz-j)mENcHz8%O%~O8eyu3k^83I-bQ^FpD z?eYP1ZFo)FttK|by1qf038HrboJ+xtiZsMN9ITzGkVzA828sg!9sYdRXuLe$>c!)H zAPj)62N&0-iD2l@GihZe2rxNaXb8a9LOFc~QV-X-wbfBokfmmauyO{7TY&*Y@YOBp z=6o980)SVW!u|L?nt9^y#-8zP#e7=5F+A!UUF2$KDhmL{^&>lh8v7hAIOUi(O;`;K z(1srYfJD7%?hbb~z8zlV)lBa0j2kx&U*uB1@`Hym`bHkiA_bS!y23K^u?}6YFCNH= zii%xe!6r_txa;2g(Ix1pCiX?RaJiuJ%Qyb8{GLJGZr}(kv}FJl0);l@!ERQ#RO(^( zuQ!~Ln{43`slOt|6(viwem7`I03QolW~7t|i%_VjOrQu?Vy&lY?6-9g?kiCr%Y+qb z;}|JO*j7C+IzMgo6jWiUFc?SuoeAs%_0%gdEbOWASAnQZTY*`NofzyuTbEM{bIo4q zg7-B=0CKN2FJ+07>}eX>MKJ)n?;_A_ydbn*(f_p=dOTwW!_bD`{7N)eQ94jLQu<`|<;`<% zG(Lg#jw?y7flYiiju$liw?-H(C@9|M4EdaPXm$Kg_bx9>y)O0C0|g{_op01+)WUql z;tUgd4$eyL1nFsmw}@t{@N~xqY0X8t<R=A6dhI}(Tacik7fz@?8-4)q zP`%A8fSyUKq|z*AAFX||VkyeW^A5PA-S9ufaGS`uea1|#o~o?~oKd>IOc@vrD?YW$ z9|MrbP=E$RSn{~_ z7;VdG|oLu%o!`jx}Bn(<0myqS^#R{ij%i8w!F>T(;N=b zCBFpVzPssf(?>gNim%)g$4o!@`nxSh;KUAMG?&MM@pm>s=N3Ff?+5*X7SmSOw1j*S zYLef(RSybeLeC(XcydOt-IMxdpdJ}|gKeHT{4A;4+c8u%upX=p2kUjx#y^W+RmeEZ z0@~!G&eV5Z`TJ04DAOhU;3Npdp|+ zptKI)Oe+tyjoY5KPw|>H!p4HQebkltG%0`Miw`&ieV`gS9gGAYwz{jmo~?rdBLP&K zS+(_tR|dAv=w8hNQy{gs0H%S4bZMX=S@!7`c#aB!Gm$EPu6E(l5`RBDL;>)uQ$WT5 zSO`ds35+kzYVM@M>aPmzQ;`&oj5d8V6a+y6h1cKB0P#Z8LRr82r%)6Brf#AZ(v!!t zlf1nK>SfhBo0McE?lUfSg0k<4Yjat<+}BkbY=BAU?_g+Mg2{Aem^g#6 ztc+<5m|p|cy`?hFJ3V!4A#R`h+S?q*2t<*H*p`eF(oZR3awHbmfCM%PIepd-LMCdt zJA?H~(&E+`jJCK+17m*tK*%8+CUXn+ z*U!uCVI>)7Zwit`?awC}!yL31+}B+`mW)t%+)P5Mk~=e`NoM)tj+=-7>-lp$w|4bt zz-(3I4WFgpyyxCo_mslxB=Q7CnIAsf|Ew}r0Mc{@;<%guCOAkD_3^PT#yKr?ALgwM z<_8$cU&t3>oZYkk10W8W$efA$Kh%QU^K0fnZ#78em znx+p;2Lm77jla3Y51G7R=1zgC9^{@&W*}KKE`JD50p8 zhK&r=i~rIg9?t3A&W%W>MuTwYOnT_7cq6CWcig`8{;!8SXr3F;29*|y09ke^-Ed9{ zjQorcrvTLIecLnAT*fVLXJ*k_+g|M7O&&Tcd@17+(t7ifif)x3{{x#BaC#iz6?wMi z<={D>JurNh5ub1EIm9@&r0LdzF-T`5ehj&j&~LzhcFVzuxtI)$RS25^8mJ-%Sat!M55gJ1Pg;^VdQ-G?`<%2 zQdE5AGMT*jeT)$?dmGh~{?6IML;SY*F>T$pt)C%`Q=TH8B}W(^sFrmwso~9}aYjVQ z%yj1k-ph;=ikMi+wNwhwzl3{(g~?cYB~lm?t;mFhLNZc!`fO9b8myPe*gYG?w*lP< z{=na%;0+Zx)uE8o611r{AbhsKH+cQPBr0);l$=?Z&sM$+XVl*Xnt8)gI$`JY6+-IH zXCF~XiuR5k6pC>gj)vAx-`R z;^C49GWzMjG>2ciAr~`(yfcD_^m!g0$VGJ^vppf1PB#=;^vo-Dj@2cp3sfg>l-quV z{c&iBH`Hu6c($wFj+CZ1OKIq&%3vV2A&};Gz#?`!vTFl6I&iKH@0Q$oPj^J-{ji#6z?^WM$ld z=lA-EP{O3yk;)gZ)3QalQx0&xBE4)cjdua~xFQRHOn)PrET%mdjkO@9xx zga1%hPSb${+cC20om7nya?ovhFr%EJL^)3U5u!vddQZ;yepk7eF>m*uw0A}l4raFf zWZ%9rT#Z`+*&1i(MW!4u5?D#(5*W#ODio!AD&<~6N!@#LZVUycmyv5zsK^3sKxbSMp?jB`^gO19~0t0Sklgj_bF;% zJwx}z(bX#qou^a>ZP>FP6BhP=>4&eNoW!C$ck>Cz=N@twc!J^hua&G6?> ziw0z-g1!tC9mF@wb)Z1y#_Cm2Uo3gcdm0(yf+>W)iSlEB^Rh}n|!4aHv&9${yS!xzVbN)11~$qs$oHV|HL!KcHw1^e@k zb@u5VN;yF4+UJ`OLkla9JaF&#Uw&F}$G#f7exBHrdbdO;#`@umqK}wwx3apBB-8J> zmwj6sykydA-f4O#ijXNNYw2U0vYfF61a`-EMORWF2mxu$b!Q?chvQm<#4w3?Fao9x zS8c9MJjevWYTRHh3;TPG{{0w|z6M^nKcgMe2~Y%*r%n(7@vc^Qpkjjlc9sUeh8u4T z<8S*rfn#u09N>+8D;o-RWSu3$kr;ruD?HX40CpUw0(tBdB;DWo5h+}~%63se?+^~i zgK)&Kd8B^r3FX4j+HA?xeo4*4er! zWLEADaTSl9b%B*d&-gK=L!*nHZ%cmr~u>WzJ-K^6nvvgR}{iXg*gsSIg&_J>y<-bW1ei@oM+r_Xs6 zjl_g#UpCwGO1^o*lbEHFaqE=dQ(wc^(TVT8`n-!i);ogiE7MUS?g!gdvpwQtCEa=6 z{=>>i6!t@0<6>o}O5wux{<~zxH7nsn3vn$WEWo9|zD)14*jjb4)~k4zSSn45fdi0{oeQlkq$!W)x0}3stqw{^vB#X`NEZyiGio9 zz>PCMgO0eV8&$~al_Y}?={_EO)G-i!vm-57e7EMZ`Cutp%2yYK0Etcb7^cDuvPszMcp)!nVGN> zAblb2qk|Vq;Br4ltmZICbDo-au|)Kajaj2fEjcf^3DDqlNyEK*W2(o#z42u2#s(?W zqv>?}-S}@B-W-Hyb5`8l=YguHMjL0^+uH99IE30R-n#x}NIYEtV+FNoNmFsBfgN#b zcI!zllm3knRE^kC0S-*dhK)ZNj^bI{gpGT>HZFBJ&J))VCR zhMwwP2z%Y4alPU0r6Uoqu8hql8QdIo{NzzsQ7| zPtA4|&e4395lfC*rsu@-E_F)$_wPtJ=^%V+q3uKycXWGHxM?9)4#n=bzUwKexybvw z18%VZhVygvWb|&sQmuAo^(}~=J4dEty~(@CnU2k;p++%Kb!c=y(o58F$b0a7NYk?H z@4Y7MKb?F!KT)2qYslv8T|l8GKrrY>y}Y^ZH6vcSXZv-SAEZjDx@if8(-}GYPnSoA ze^saGW?%0Sy;~E{d|7o}&o5loD_hoFJ9hB0Yb^fBgZx)l*UY|ky}0~Oj|o1qju%a0 z`J1b{$~TR~NZ)uQ?*1@>n}@Y`>z*urqF<-y8`31kW>jRbB{}@!TnHFXJ}O+7J+Yx~>)lxH6n7)~O~{F_Z8I_R-`y|03ww9`bX4E!c4gwd&p{{mxdQfw z@Gejq4tGd;rosl(jWt5&S4nf~Pux!&raL=w-c01%=(V&P+IbaCy8$h=8x^vhOK*kT z%D<}FxHGBDoxmR6H)44q=}F>j!Lj^|t_FoGn#(+I2BC%#<+A>nGH-`E4Px6ErP}fD z1xC&X8xCDRu{|A(K59>)O80T+^ie7Y(6;<2^DV!;OC^>HV`3)|%@cX?_0;)CDt!EH z6GA`dm*uwBe|ApQg)5#^fv#>nHAXd$U2kGZ{T_OHj78~>yVxxHqGiyaPcA-;pMJ`z z9wD$L_f(4fOKtCAMqISD6U ziHb@sYwH#>YpF?DSZ$6(2haRX*FVp1%RV{vH|XrC?<^S>TLOYd8qY7AWeExt2&HHL z_xCMtIhwbgeWHm5-9K~w0LVtLD4otsw*mhg8ZQfz`(t02qF5>hOuu){)3 zu_pJ&B`YfgZsNt$mk@s{_~I3X77AFGFgz7#oomc5l|;MPCE>&>@I72_Cy{?@NoR&z zo5G`V+F!L9cdQ@7QNi=q;5PS5m5%Ws$)^P%!oCYQ1pl0ltCXORC3Y5kR16Q#V2ajL zO=iKGP4>Ta>VE~O4g6S-fmz$CZS{C*lMAVPd%TLsF-TrN$Y@`#YWBqbb zGq82~Oly}6p-tMx(#^U<-ZOe-mQs>eaQjfwqHLY=W!{RvKhMdWwi0se)9UO~Rs#xu zevi3GoZ}akJ#fsDng#0W6ZDM17+j$gKUmk8fF0+O@;Ev7Ky?7BiY7rndRf5atzzNb^fl|DD;g^yy(g}vgU$D8&#zdSn=A15Ly!PVT_oLbmSc(qlTOn*4?goo zX4L*4&*`o3#(Bm1mi#>W<-y;%$Vve_iCJx7(RaqD75=TgvJ12wTbu5APPpvhnKKt9 z;P&Ur?c?V4G}(HY8EJ=LYoQjrR^YliipCG9!noo;wOa|~)6AZMHJF5y4+IMqO|Aem z@tlJ#lQ7?IQUgb<( zkS>c}um`qS=a@BtRrIaLKG02T=;q!H<_lo#7L8cwZ#YFLQB*IcaYXESf`Q9wRYc)> zutgc?82aP%2f~lPa>!1qahZh0E@yh0!(DfFq*Bubx;a|ig2^#CSfGFPOOwu|-%?b! zSRh~_oSVA+2uIHNA|dx80by({utobW(0Dy;Mpqm0<~p$jK$VK6se2zcTH$E>s7?f~ znRi?9<2YQ(rG4*2QL(lq4BYv4n=XJ^h+p|{E zMAY5}etIaV=8=ENX$CD+L%i-@?=jHY&;{9y(z!06zJ{1%jxuBfc z_~~^)AGU{JJV%J>AehGX+4jhpa-n>z5Yu{&2^Z~HmMhwiGh85;ZP8HA#mt%X*YD;t zH~O*p9D`Uw(>TFQKlF67in$%rVS%F36kt}uF(7e&|18+Ni~v7|AFH%4mOEs+Vr9BQ zJ-)@l^sk$e2nKfU6 zz=FMvru=;fCe8I3*vzrX3_@?-0o=c!$|J!xz<&Nb%rPmuV2UB+k6EcbBgBl=a*4(T zg@lJyJeOzgbmrb2lv0z?@ZFrZ&J4aQwd1<=t9f%%>lACT`+KupQf{|R{ny-;$4>We z4%~IvY5u;%BTn{0ssYg{G_Al8O;n%!fd<}hYmMcv#eEdrSs)jH@t+TVB#wri;`ldG zrAzQ0TR2&(4U;Ln00nG5L{Kvh{j?1*S^%3V6NIlVD}Rm{mDZkMH9c#F@Y@mQ%?aYy zs%7)(PTHR>Ad&AH@zSsH#H)4X58X9 z^MG#2`gt>9xbsBJU%jvM!nb%4(+EbC5z z%~u*7D8PS{)MKB)i({Xa`oZQ{jz~2Nkrs{Zyt*O?;w2O2pU_>W2xcTLM{=_{ZS!1- z4oaDR!-*!fa1_-8;XlA|xT{pX35Q_fgwdKNTSUS0_fw!b9fDER!Tv+l>8#DQ?aSd^ zSvzWnk6!9K&+S*(+fep8_ElZgYwP&Y@2fk<&5yQkDj&V$=BI{74pI0W@rU{?wLXKi zh%}Ku1SgT#nKMVtWGE@@#JC;f zcjjcez$@bPSZL;^wn&lo8jEGLPB4k(74imQxvb!PN~9PNF@-c08%6A@nWb4GAlCc< z%cddb+ClfWK@H#-m1?p=FpAv}xl|;&H7|W1B4|fjKf#qqg^?5>24H!^?m~x$lF<}U zR@>4v;=%(8_F8;mQrg3=wNNd~K z_w!$zRyv9oH4eV}tnhU93A{q@wa=vg>}{hB7W-a9G_1D;zTG*RdTwXtBHCd7-%o&O z1W@f+pC*7K`B|Pu>(9)Z=i<_M;^qzC`kdN2V>Cy=J_MWB(52z$KfTT{SqED`KC7`G zjkQqcks%4E;Z0V+#-G(D`1|-B=*0L?(-Jmxd-x=sWBv_*z|zhKa|}t~$R8cn%Ot^r zY9zPmEv%MexXz_}0{|(HCUPP;;6XAib5IO)-eqDkPln8PuPP_HQ|5|3pnvIjv0VkCe{|eW5bUG2B1Mm6 zr_)V3)ZPl@Rj&kk9dqYBrXk^EQ?_t3qZ(I0?+%33!mtQ6s-w0&?xkg9oMdVi_K+aJIQFtHWAE;g#3f04<>d-u4@gn zB1OX?dch{RPF0@#d&4?PH}Mm9tJ_0F(32h{@Xykmuzlv|BeZA1*bvY$8@l;J&gFw6 z$5^Yc?}1j^z$P{H`*-Nbqx&KTozfP@s&7EtGc09*&IRA9tY@tp|323iB0{1bo1@1; zch+thXFZ~4Wm`LY(@|@jpLl}l3a9Rotl>k*bEp=A7`?)3Bn<`+e_w*5xJqB*NYi^gBQf4}U zK+@&cAV!&4+T3jOD{a?vAdio(%x##K zSgIg=q*X83Y4%RfSG**cO&9!1dSrx~ZS?voBB%-rz&wV%5Xlvr*zLLtUSSq-d+XDe z{U)Y*k|s?GMASv5s};o$AL??waJxfHtz5aGKyg6ax~ZG}!0V`3u5|h5E&md~|B;E$Zcr?6BAOlcW}i-%gtTr^g0%&r4qoGsEs+4-MZvKe`cy&YF8?`s2%d5^C7xP;`~n zd*iOdg|CN;QN$&DVZxR|Ix8y+z~TBnyOxx*mH+P^4BJ;t58p|&704_R3GB7mMpbZ5`5*tUA1*IaK6&b3Xhi6Q;`jvz_Qptdo zG41Ffqo;~l$hC?@OBZ^1@+^DV;>JJx`|+739Ru4 z(7zWxOxR-5l_%{myX3VB5-}5a0OOvZu-kF|G`3B0MKlT~;@Ysbkwa>jnO?VuJ z)K#zV?3`(+y`j;FFQP{1$YdP0>j_RbdnXmh<2nCRRUY@c^*k$e{?>4ALxk`HC}uN@ zEukT$aO}NuSz#Lo>zaA0=$C6~*4s0Way*{C+Y0Y^>t6Kfg6HX&58wALMBe@}^(IEB z!XPsI=$_YNY0kT2K>-7vzdknHpa1o#H9_+Ayv2#jkL33Dt#6#1Bvru`W_>T~W%tPl zMNL~>eJU4g>1QS4Fh!KcC2tKMf}+Tk9Z?IE(EZoP%|X-rCuaT8d(5XvaCeAV6SsH; z2gPnKUUg>niCw@KOn?TmY!A3a)7$k=O`j~K2~0ngWjpsP6>jHJW0$Pd*P-T1t^79H zim2mVw&Tyv^CB`pGJ9lhQ%pgY6RDCi9Q`IwL!@1?U5$6OUdTvo8-60QT5f-R(1y%} zlevJ*7i5T1#6)h=Y=A@f@)s{3qN{JPj+#2>i}kdeHZUnbxX&&gNnkU~o)iq&V`+S~XP_XC-xZuc4ZW9X zOP~c|M~tH`4LEpiW-=VkNS`czoBixl67OT*`JIFg^*WsdDYJKxCvQIF)M`GEJQ30!btenx7U*++B;LWV4Kd6Rs=>%Ij(`RfWd9M%B zTq!x1ut;jy16v#aDslf5S2th%C3BXJl2}2tytuE@i22PvYGbwh0_HIWyG`Y3Nq z95{XGxX`V|W!XG!xW$8Qr`!%lxxYXM{*>bJr1~}HN~fi$P+MK^7dZb4E(Cj`WV~PC zo@k)E6@m-^i#>~rk^K$hk8p9j<{~C9amfbJB4We;uUhU~3k(ZocWHNn<{w5b%`+|uBN2IH`w7@>672AW_?-Br z0Dm882)9;C5d97T3#-pCnQ46&J=>QiN~a#}cr5sH%&4~wgXHFm1mal%ayw*(NwEvh zWM#e77mTg$4BnT^C6JLvgo`&$2>u(S%Z`;~m^Me>PVFbkd}bcKG+oJ98`I@o41pP5 zM$kha63|49Y%eidFu~bK4m#LhorTN@`5_|FUuKP{<1p(gI)nP<8hP9I{sEfRJ)~ z^z;jy!4Ap3`Re=ehtHORq8w#0_< z*vI+J;+N%nyLWQFX}sSWYh!y@iVyvS!~}oRPYUMu*`k59L#k*cEW$0pi|P6whElo) zzke$PK#fY+yngjyN#giS((EHek9~vVm%oTP+*}l?fe$D(<8Zw-4Lu6%G-(o`s%42K zP>e}G#41k8(k|X_PAl-mO5X}LJQu| z8S|glmeOw*!X|u=pQPbCmEp=SIYHVzUKN|9>%(u#{4Ya`_M#`L4O4ExzAc$SR61% zEf>CD=X|SuogCh@no$1l`=kFN*DS);qf(8&j6~j5IpT?hRkpANr*HzEe#AMdph-hJ zNo!K;xxw)-pWfvCtT;(-#tCS0v0atfRem;?>99tYpd4Pr(OE=Jf!|o@-~3l&%BO$+ zywD&LG_(a8xdn~ZhQ+nq8oD1jvsk`RDI2(6lNOOkJPayN|Fv*(gQ;@R!PuL_%l*=j zpHUF<-!v-ZZo)*qE)vfv?N9mDQ=54Q@h$w%xA?g+_-T^B>-^KRN4tlp2me9)x|{J% zSI2*M*;et_hRm>xKIg2PB(>)Y)@lfcbOtr8B>XX#i=Tqp5DjvFuUE8<3Csk8- z{sgQ33DZ@-eo_6Vh}Z*X$-lI7%pHxk{EJf<)r3NgJGus^IVe4_(Av>|yTa{rdA#jk z<#L3*(?Zt;qt!}xjx6eGeP~PKu5?dg2$9K^qGLohowsuNSWLJeo?Ba5SuCxAdr_WDb>_#;?nyBb zpuUAy)v1PxanZJw7y5uQn!v4QE#Z@3I20&z;TtiGBH4+Teun#IqavLCfzKo6qvhy0 z#i_k8^lZei+4&fYpAReo^fabc(MweMeLwksAJOJ3>R|wJq?J5;SKj=iv~)hKS)p>* zPyUym{1lKLJEB1DqO|b}}{g3o7Ht*I*{~K8DVce!Hct(5dHPa*^Y4*34>=!p73eO2Ug!r68TF#&2+l2>1I`FMd6ojHvx39n8x&bC zi`FTvE!W_$kKUi17#Ek_^(D~<+8qb_uk&n^3s0Nv1>hwl3iRb~QKKv&vK6b%jX?P~ zYy_tf{)bm~MHxDTmw&eC@@6p1J5GvJFWR>Ncn(0?tw`aVz4of0h3xJ*zff)!uRByL zj6#@Gc#pkf-l6{@B?zQ6^Sk7JIQ;`pk%1lcuu!_K9bqqG!Z7mH_~{$?IyG2O>PmA9 z6>-xpWYtsl5H0vS72Ti1L_L5q7thW6k$4m2cJRuPJbL~tsb4^Ow4~*BrM%b&%;mn8 z4E)J|5GRWlo=FY5?6GiDH~p1Zr#1JN>!Q3y9Rbtvai<=|eawsexf_=NL{X!W)@I%7L3sUH1M zEolGhgmF#+JtN5I;DUvFB>z(#H>T*4pC9lr^kJnr4akEQg|_*5@ED6tL1kPq;dV^c z6jeAwGqJxI_D8*Ur}E@~oyo_&<4g;0__%rxc!AtH{ik;xvOIIF6R+7zY0u7PEK9)G zF&8(eGDNC)F+QhQksuMPx`3DVriwrG!wd~-WU&Nh7SFX%#a;cRbO&WgR!;51G2|}U zoyfw}(d;8#$=40C3+%&>brpTp3z&Fxt@mf?3l#2WW#oG=*+0PWGXKL#in9_;D)Hfq15xs?4)WDUre@q5^tqac`E5uE6_>g5l4I z(qnk|mnPAkMfvrQ+WWi`{eH3+?#n&{N{u@?OG#-ISE7fgB2B2G?CZ?xs9!jTagCdk zVjk7^-n7NXYMTAJ%l;Kmw2D5E<}EsLXv=a&$>IN==%Ohi{ahzsmJ zExb$QOlmc#=3JC@o4eZ9g8$K$)*MUV!M-j`x&E~hT>4A!dNQZG?a1%yN2J>wj3wfQ z!#Vf)#7mPEE~c}Q$$KXiU+5m8##RrLuO9u~?q}LjD_HfTpnc7$Bii&)+}k8wK1^h? zcf9FAXL@pHVq59&0+%bMUDuPl-XXhwPTaj|+FhI6{ryGyTbHy3)5q<}kGmc}?*09k zZQ3)C+%s${@9?;1!nAk#42*i8_eH5OB&zpA@{^BejN@(IIv<5n77(2jzUBpa=K|x5 zL+305oOV92-s>0-uKYmXe^K!&M@7=BwNxvm zTNb5!BJ}x{WtuAoe6cdz{~8HkxMihu9~C{MfUaVT1Y-Lx{dvkLRY@%n+poT_%{B%4 zD2Q#`p1orMK9!-E0~3 zI~kS&D(R2mfPsNe_xuKSal$q%!5CS1t7%+uaEqn6%X40j&rxzr}vC z|50X(Dzk$FM=YM3>W%b{l3CE;bp-_M_(>b6AyNz%8vUXi8yq`%#z@_gKetC{tXdpa=V=8q7{)P zMH*`GSl(%$*YzYKchK^CeyVkTJR%oftSa(2S^UhR2(tKO#}?5uemT2rX=zU*+6lk# z)C=F(V)_dw$JjqY&+LCW`1e=XK`g#<`gu8^3XN2S97yTIITBA2i^I^dG$r@P$=~{Y z&m`PGYou-cPx#MzKW3;v{-Cy{_-ye z=kt1!7g-F+4)G4olhb6JrXo~KKFebr)cSNz>|E2c>+MPY{Z9bfxwY7zEn|_3?b`Y9 ztkmL)2BwUCL(j!a#{mx|@Tj(_A#Q#XT_h_ac|AFJSu?@SqFPEA7HO+nQbHC=U6lpFYN$v^N zW-_-}s3d7_MWoRUNn`H0Oere$nY)BWDwW!A-}C!#f9-7NeRlS~yk3u|8;Oe(hiT0= zC}dWR$;i4IXB&7~WqWiSoXb}jPRfF5=6 ztIUM;pf}r7`;JnJW?EmeKr7dn%VZukvlN)C1-p{rS_4mTr+#&28gu zr|v)L{w;>2bon8jK9jbhE3L*F(RO2Xhdzmz0QLESjMW`6RLrA?Ue>?3zJbMR!`D}B z2=o$|g6BGwqP#Zq%?p$Mk3vzq_StYkwGJZ)(%-jbm(`}~P&%ot&wa$X4@7#z_ka}( z<9k7rYYSPe%)hhkL!RUpWow={_IT)J z!JG5==3&~kyl_y=OCcMiwnf| zauCbl=iplNdUS{vUPi;Qib}@Kliw`cHnEN4rVZv(If6eq=P_bwF=R3EH($^4K z{@HS`qaS)K`E3zgO{N?Epiq%U-^R?=8cGpn?`U=l_5?Eu++^Cat(2iMC-BmQEf9qA zZVHz0G+W9}f*&9bZSKdsQMG|9xXStq%8Zr0F0$BU*dz4K|2(Q+`|)4##ecuQPT2hA zC7AovNv=b52ufp+dy}4-;uKv6sYWJ$Z4tEcvx~s^#cW@q7UX?9uuFKc#v93%f`}Q9YCp zT~nJ5?bmcm$oFrqk$RBZuN#w45WHR^^8z}6%TFkb(5>A!kvm{?FX3`*Y^~gX&_Vo2 zLQ!&at-{w_{)Tiyaprn0f2M1QAd*PS){Q8yaA7s6_T+^fS?nxZaItqwEGcWQ3yBS6 ziSJt!Ny(i%)XuRph3b@kcUMNQ({t{ZmFN*#DRTFS!+|4-*B0Yxoit?THSd4*NxvHcJ7#$pc{5UZOM5tz_@e@ zaFTtQdgpteQJ;GcRfUJCmg-^?_dJrzzN_X~f132Tn4esyIu<5X#o>GD-;@L$Z;xAV zvxprIQU7_Y+T9qUXt*(;mV7ZMD>Pp_7jeh(>MQr@lcEKlHDJr7p1r_MAGNVFSNziN ziQLdsyY+jK8gPv4YNME=|R-%0TMI0t09fH#jU8(9Nxv_toDB(IYI zu*17hbZ`8nicb_7Eu1|T6ADRnJpCXTS_2pMrD!*h#jbm2?~AZ|P&YymGxnw^OSYC& zpH2=tJfnkXAwk?dl)Z{8OG5W6<(bDOA0R3DydZfx42M#fxh+R{+5K| zQw+>H0R0R)fbo`PPj2Qw(h1HM)`RFIhDsQL3Hnoc1(^L7v~T)|c0iNvrFRBONa zg`dw77|u2LKu5D#KyezArSQqSuS;7N8Aw{_TK%4bY4d-v{}O~RF%DYn{6U;9|B9XZ z=wyK@3`rKWZ(>_e&rLSLqd1^u2NuXwuQ23nA+J`V+o7f4I4m5eH3z>xbm{Vkm`j*C zqfVczZ_R%w6)C5U8LSA{!_0k(&#Qujptq>r>tc1|k6DPZ0W1OSi zSHO}9s}`fGm$eU;y{cJUo~YmQsQ!SJlA30ZXac@pw+H|`t_l>j2sz?@n9X-7K(H&l zklOF0EdPi)36DF@c7p&>re2%ZX=Y)zXflf+kmKj#%>^c>1D>9IXElOA)a(XGv}{nE`1eCxqKC;_3e7fq#i~ z<*QTta2ZGH^xG+f6_e1l24#t)5wcwS7BFv#e5_vp1ou!;9N27IQUw%e6fP{|1|3Rj zTY)h;eVDmGTUZ($aJ-Ou=GAwX_Q!>A@hJg_Y}$a;Vo#XYc@=*O|0bIy9`5k4970MP zw94-S$}^d;59<0b<`ra`H&CcV3uv}YE(&wXfFD_W+NistRnM&RBjYoACw%@SPrCN`Y zf#^OgSeD?_z~y+bnlAob|Cuj=QuHo+PZX_c>6ghR{L1nybc;iR(f_Iu>GqP#SY>@| zAd8mlnk;nhF1-0CvSl!7FcPJYJ@uU}91hYnMu9-p$t_O8{PWP)wlJ3I(S8l>Bikzb zY(_Jn<`OO_V$dZEF$3A6q?l(|VbaiAviJ0pv~`g;-_Qg8)grw!c8!nXn6!c(&oQTj$V)%=AkqkEIX#1szhroAi zg(epbJeHw74;%CYVHm)D>v&> zT5bw0a)L(sR0BEGR)9z4{a}j19s{pI4`rt6ZFnP=1&X)u2#QPo_vm7TX@Ua}1FOZJdFJ34rq}h15Fn%|E*oB-cEn=`L zuFuv~+A2glqF$|1Rb39h&Apu6kfpl{zV{Sv$uL~pMeH(QrfJ9??&X-oyko0T90u7_ zwZt&F*g3E4z#YMRP*?{}^aWEmg9yUY1hv0=^!gfo;|riDWI6-*nvLJZB6I}Ap!MF5 zuM4727P@80RfWbDwHexEQC{*zdqMDn*TQwaCFtA|6|{NtHfbXM@=keH&X7OR8?iRG zAAAMKV3;*BQu0yA-FUcMnS(J0r+NsqKrgpwbtxnX=L@*I@?0zGkNDbhp)b5e1@=J> z(9^gY1rIfK_m`V~XCh)qz%GK=4{!J-pDWRg*I-f(s__czC~%!!>71e121!_*3LinGo`1|?xjDygK5X|Q!$RXZ0*VI96TN9ClR1{a(<|2O(M6QKjlm0B; z^GkVxfS5-i)FqH|Zix3NAAR<@?*d2;8_wYxexnO-Iov7;yQO936;yNU-EIjxR0M60 zTwuaKGET?+ki?P9)bne!)Bnd8{!Z5CgMf2927H!rdY1+>6r6ZlM-2I0_`m4(( zdn2e1kvt~;E!P2ug8hp}uG^uO5|MvNFpy+`x<35EZ#>6VBt1ri*XHsnUOUfk|1KR7 zmW0X5NAA+_e+7`oHIcs`xlGdIYbubt{NP_oeaF2fGCzUE(1ye~T-7iqV1@ZZc9-VG zpKy^+P++f~s6G-bpQge`{6fps2sDvl0_?-cefFAF2Y~-W7JY+4EHJGaX$~v;(DyOc z^;<}`_WfpGWlN&)FbX!tOUI;<_!u!nug&Ea2lgMayMk{UbbdN?Z)V!k-Y^SYhRBVf+FpjHNh9olC2 zhomkC(lWC3|18d)lpxS`H*8DxXVA+1+ni3?sb>&mXT++2AT@tM9Idi$<)PEf^QvVI z1ma_brpG}|2Yd3>UHuO|S$uq)EEn2j7n$*dJ^1+4%O|J5JUJu!G(qQSlKaz?Q&0Ix z>vK&{GhRMD|K;gL(RQ*5yLt*AiCm5^TcQZbYZEhRlb_zI>GglnD! z)U9-m0-kltJ#$v=Viiaee4ahkk)c^g_q^-~@excX2$QkTKuLE>aKg+)3_iZ&kiG<- z(H^$dQGH4#|3gRGBNqtP6YQo(&4+OPzP^4to!b&5j-xkPd7DQ@BUc zy#@CVND!(Kf4mW%01Stj{P89$CLX~@a97f#iMj(bUD78T^ImgEA$v~u<+cCu`t_;> zEYFV`vKfeZ;>$B0o%T9Uo&f~ou#%rR9(W?cc`G+i3{)pjB@@Urt0+01-o<~6ID{P! z1%T-D2v?|C1s1t*g_+Q5ay=ei$e2ursVUfu%#59PyyAfd`(vr2npn>WX;7xaml z6h~9j$0C0556NZg^EvuY=rbX6GaSN)jZq=HD>DUSPQK)qKNzwStD<3V-QP{0`@(J^ z8Aw=lr6`C=S+28AEQy=FS@7Ftsr#GRV$5xJ&Nf|hapW08E9k;r!S?H~Sa=4o!3v4D zI;1kE<$2YWK!=z%!rv*g{gfmWlq3TBB@C_rml()*+(fghW04n@{lcEiT@kzEt#vs= z=o($Pm@s6mw8D^E`WWPIg6P)vZ!2b=E@v;RO||=YE?zgQBFC4$eE!my1S~}*zd9&o z-o0>W^4KO$vS!TB!e_ylyShpNW$TR_>#1qdKhBOxP~!ZZjU*yT!sS?Dc2_|Cg@wan zAT|xTMe2P=oyd(mwg1M4o~LhEv%;KUnn;-d)KUmX=((1TgHljXr9Q(@9P}1*qZ$W2j6FJGFT71d3bxqA&>`tWND4N{ z$N^Pa4Xvh$@D<-%%tCM|gv5S;OA$&JfcmeS3cDg-9W>ehMj{0pY|H^0+CYm_&yNdZ^~*ADrQq;p*2u=noac%fp(#w`Mb zP5}{V-#&SY!+va6f%ZP`ARue@TMB%qx?T+6NBOf`}D8e^B zg&7kd`9zVX2f`5W3mh(9y1^vl3?rTXt&tA(m>Q0xZMTs`O6Xuyxi5Gcgf{VwkG*~v z6HAH)o4pXJz(I)|_rf!~ZfAZMY$3@+VFppOfeTeVE_JK{@f(Y=iu=3M{6&;pUWxx?1^YMuO|IzKS>f}slu>g0d~O& z`xU#KH9cC`IYA1inEI91KRAg=J{RmA{~m}{m!zxL!Ft^ zME3nqs#v3c={1vMN8W9p7`zZr zt5VY@#i@kRD;gac>o-;^Z>N6|#0ae17#vA!1BB_-4qS2WNasxE6m($b$yd&9yIvw( zjb{p0Wf;xfcMWL(Nn+wgiLYw4$KU0Os)uqSF$ves4OZ!|e0GAXpChT=TJydir4aEW zwjo!i<(%_qdOJYlb}|zsN)32*-WocipbVjY!1Lj4!ur4 z)$;7e?^6txbVh8OySrG<$&mELj=ym)_s@U2Alj0<+BrN}l{OPPs8H~J7?k@q%;nBl z`s^=_>dYL;mwD(M0ODpQx1*uTd0eL#mdyRNqVW8`U(|*hHb#jG=b4iaj2lbwklX1; zC!(aBcs@Uu(%zFHis`F2oR7%c-OxxtMe**+d;28c2m3B}XzW7=8(KU5mIwC2`|j~h zY9wa-7`|hI!H}aoK1z5Xs%#e*sw*-#Z6jOJ&8`>sMW3eZ-6A~N(*Oq@oxX^1Wc-Cd z9H%H4?vS(PtQgY2U&The!>)H7P(1z)r1+U#w*Km^xy9!Lik}!)*LMSo&o)yOF7`Sb z%>UGL(9%x5c+S6WevsmtS?rN+Pqc1mwKLNy4nZEV#fOwso^5BPOmU?V=1RpT37h^6 z+d||p9Q?dMtAh7YFNXPiL-ve)o_Oq_uRIVGGHZYFrzYf4i9mMj?EW+B(NxDzSL$^=)`b{XBtOs2$r_3dlf zp%xSA>)K!1A$1~W@1=7nGWb2n`>CA!pEuT0zr|BwU#fNAeNXV%h=u^alGR@NtjAqi zxOsD3?C~F~@XA?-Fl*+OZ0~CatG?AmS#6y2%3PL+RqWjtR<&gL^mC+dH=ro~&R|hS z<$`!{dzM^VD@u)HT#>{iFDU+iLe$sj&{L|>XEFIaTjTc*g_7|-^1Eq+ zDtbHBsvM5#3Q&HHeqH%$es&M3xXyK+l;?R(tbQA96qfr_nvmJ!e zYLc=83K2K<21E+HsR4{E$!TT~4_2Rh&Yvn*&ZMYzlJ7;tpFwSlLsZcDkocVi zjHqswa%^jUG=EHZJi1A(FVQS@-CiNTy;sVc?467fQKq_0)o3qhy10rc;{u($s^-8s zsWl4!@Km0>FU6=Eg!~Z%z`uWl2okhI_RwU^d)ZgeBudH$w4lrm3a(mXALxi~zFE}+ zHBZix4{w`)*4fh;%g+<#4>?(Fx3YrfY+IUK0{8I_*C8_LwGyxZmN9ni!^a;6if`ku zPsKLnylWX|) zxg9@M0k+zlyL@ch8U8Q(kk~A@Xe}G0m){P~xHEU%XM00ohz>&Qim7LM)S4Kl%{0eW zLoEHZ&3r&vw8waud3m+ON_6wzopUEWqK>}4xtx60!qD#s-A&rm@fcxF-J)ZkBr-26 z2OQ&_EjtyukDn0W#518wr^AJ`Ty0@ey}SmrU~S5ecrfyicS#4<%eH|{uqSe%QMxSH z;p$@fmjQD8@=E%K>-<+J%(g&4ws@Sum zDeHMM1lxy|TJHgi^tNRM@IJ8eC4|e}e zFXIQWZOgGy9D7Vc)=-mNO{h)eeQ0nRSUg2z;B@AwA?Qqb0sK4k-D*GLS9zS1rm;c(QI^zd>+l)+{0)yYJ3Tv+-1;x2S1-TWn zOu-)w;4CemqiEjV)92wF%Gt|W*wGrbHk@?519w&ZWzW3t<0W%MmRXctAl@9IXD z!d;PtURopx@!$koNe}A9nVc;NlNxRGR033=wvIF~h zGr0eh;iG5Nv*lo?_AChx^21Ov?k;{3L@Vw_x#JZ)wN6K@nGRt$8KNDtA4J$xf4JKgq88i(~JsEhZ8;=PY zg2x5sT+c8|-KEAgFo^b7ONUMJ;(=#e6!$AbqE-c0EX01t-?>S=DW7S@Q;#T%?uA4L zk|mUAI@v|C#OAl>Aa3p2&7DB51@(X~>p@~KNehy(ldBVNk8g&lG-~?qqiWBvcyqRy z@!&dnJsUv>LYD6L1exyFkhs7?!wObG8Z|L3$9wm7F3rKM&_3-m_(Ps9Kv|;9q56}E zBPUTQ7kYyvR-3w;6R~Gs?tu23LU zqJ~aMT!dvlQoS3fk9LpFbh{?9wT4otKHD7LcLUY${(PFf8ZS z;6#hMAVP56l;|OmAo3M|$iF?s#yYoL{0o9Rc_nc;f!G?w9VoX)UME7@YaMAf3sgD4 zh9iZt(Wd8yz<*+Ms)r%5(FgBZ`WYScGd}kEDzwr%AL1%7%Ip~NQ)%b`h-qNKDc+d( z;V3`i&4FQf?i$2ygPO^K#5dTUDa(F+qxY8p&@dOAN{3|5Kz>S6A8$3hUA^0rfpPv= zqPAo5xfOISbgVBnw?Ff8KsYjvKz>kh>)e+AsF8hZ1p}X)Kat4_I-M)YWv$_a46iEe zkf}oV3a$6-2lEduT~TXn%)&e$3j$Cg10mKa6THOL2K5_#X$=l0f*|gfJZzi7k`elo zZ}oq&{kfcc(kS&j{a&p1bFCgh)e`Y*oa;$xKEYFtA&UTw8<5QCUfyTH#poKo!3nGp z+?|E|s?0vtL$y=$KhLJ7qJ4MR1N}+)s!(uv2Q~LTH91gdrKGkq0wVex20kc5@1maO z07;;%NIJDKm^D7cw$in1v;{=(+I!5rNfyff_?kovq{ibwq)BRA?ky=J!{uS=1g6bM zd*zo7a9!8qqV+b?=bUta?|IZK?|ic9<<}|!!-c`V=c9dtD|5QG`(#&D9#Q}q{nNT1 zU;S~dJBOaKOPM+C?Q8NesCy&m#l|DvUjea4?(!IhX_F+j;N?h`fmov`#WgS|jtD8( zrQXKTW>Jv1q2RIaIYj0)qFm3>(wA>@EsXhur2y4$7?P6Pu^?=mfi{-%>Fp`QnB%&m z2%~hu8_%>VbUgU)XE8IYs?{uu(QFM?{Ts|_uv2dUd-hG9K2^UJg6K4_9IpHMurU16 z*#0YHp;(8g$7AV@qJ~VtC~i(_J0zv)aje34tgDc}62y%GvVemAQ!!5z>Q92}IrRcC z3{YT0j$A7h?(6*Sh9dsn^o5?oTeF7)O5lOSvQI}!zv&KS&U9s8oltA0Cb5IZHozyD z)Bm~x?~(vGTJ{M}P6`9ctJqP*x;PlX9jW+tD{d+;=HS>>$vxJl#xGZw}&6ycmAkh?)%2ENrmV6O=It|OB0Vp$`dqa8OGhM z8*ud#`q4u=hbDU-g;HN61m$Oc(4l>hMOUUlA&BwdGl3H?Ho|TGg%dVqr*p{x#Nuxr zVtXfV5d}=(5m(>l@`chT7riOb-04&8jk1~%=~$s5!#qj0KuH7e10DZ-P22f=#EOn- z+E&hDwDLkDK=CNV+0(8^GC;#aGKSVmX9(%ceq5N$#u#ysM&e`6O zB?$dcX!%hG@xY=5l7;_#+`o4$Z>7woICoLj+t-}{*{^*lN$@FLJY2AQnmaYErPKSt z=hFdg_w<>|VUj8y9JtwUFi}hzJ4E@Cm*ZIkKnt7@=R_4)DY-;i{5b_aH^l!>xfa|7 zIX81;ls5NC0FvK#%}~}gIdHtm@Q~t@LbPVfY4|((ThogM&YeeWmxgseH&V`h0JoIR zC(&UoxbBnf^Y_NO_ZQ9S4V2q;Q@@p=TkkVu@e7d#G4A-%PJhUu;onb^NHvvDgK2XSntsglU%Tpg{GmxENW_eP%{1qY&8kVK-m zBqt}t=}O)ah4Ogq3<9`s-90R@2mokW*q4*yO-*6v6!bJ2PC=rcz|zFUnvV&mY&9h` zfCNubZMnA%W%J=MpM`^f`~s>it)PS3o`H_a+YO2C2e=WaNzCl`XuKX{UcJ#wDOGJS z57MM9j>SS!bj%m-1BC5`yhZ9E$Llk=XD}_~6W)+`%_>zaIe>YqA{#)v2O)hQ=LyEG z9;`Mua;<7d?8uU}=Ns6&R%IGWILMmBwbTy`OsrUgl6 z2%Xh`LPJqqZ(EA%R8G%4V9R2=iCM$2Gy}Yj~qXw zqj;ml(;KoTO*OtIi)EioT^*N#f-@OZu`{MhChTgi932awxy5N<@QwuK-Lze8XD zbuqxI=2?gT;ZL<0e~=}3XJEnN?fGRW%S66h&jH^|6FlQeZdGSi_}!N0DH1qBAp+gK z-6_EnDKAc6{^e14&j{1(=fIbD<-I8e8BLXJ{dA@cEa;niJS3By!;9{r@Xr%Os;xCv zb1uwKm8$S;;}fK#LhjFV?)Q4ruT$d%Ri{*e(HGoDu2n{NXPpAAD2+c)J$H#gMRHvFmW8~}zMmaKWll`SCH59!q@ zE9irqgucDV$-?cnq*7k%Kq(LDXa2MtjK0rjw;{Fry_38yWv7A5CciG0=lHkn=ClgE z9bT4g$TE z?q)YW$ZcqmB)+{lzMU-g=NvZ2e=Xx6=|}OjtrPc7#qyDg zlzioeoHHoHJ4{ftHwON3$)p2PGA0X`P=OfzRQYvB>zUNZUK#z4TE;5a>mIpBi`qFd`hAs5;qBzpFOVow$rsqE1Zuf)nhDB2ZjCMfskOCJauZAefV zEW+4iCC{rm8D?$^=3AE6LEAIGuim#9YzcYJ%jk~T(+N}m_#*ww$Yq_C&Ht=I1aD0- zuT6Yv<9}zmF7vyxp$qx;#%e`Wo_3D%mgb5@76; zWyZoi)y6-_T)C7#m2(m31-b6@jghN<(}imv9Tp4#& zJ`AsBOHP<|bVS|U=eQ?9+5hIWsh1V1O@$|V9ESqUnSW!~R-cFe29}dg)ccj2i;8En zRJJ$^qiMqT1;(vc=uT{rmy6#JSl~ZLKXb}(xR>>WCY5EXw=cTLob;yD6AgPye3`I! zL#o(nJ6QaqEk607m)XxH!2vT;E2zx7R4nOu!mmeukTdZ6>`IH&t|K5VWpm^4%^$aedrE5w^Hb9-xFQB9b!J!!FA{@T-eXC`T^AXx8vk=bH{ zUuk$@*3^R+JfJ*-36cnA^gu*)eS`Spbq+C}*layBz|`ZV>aW6nQ<$rFX63L zvw(pu^G9#Tu6V0k^@Pgm{Wq1)e`JS-LE93~8el!Qcmo^UTcJeKykUjCeC zpkH9W(b)yxF!PQa^r$C?IcELGh*Bzn)2vrP-tN~GhrL=&ny_A^-+4d$Wfv4=j}P1) zA5{AD4UX!&5;kGI8gDCwOk+IsvMe5|e{KFNn?-pDt&hKK^J|gfRbTcsyjTq{xMpf_ z;M$<4&46}f!AI;DzYj)59|Cyrc(0Xk5zp%>NfRT#*I#>Xe5JSB8I<~6kYD<>`_My# zSBHXgWkg*&Y`O~19x*As6uV{hH9JueHob_?4aVgxAic&v&3IX+4?TWmqd*2E9b_5KND#<#z z1HvS051n{q`~1f{ihLYUQYA3E_+0F!_aYZ!zWcc1L_3A-9y*BYo|e%%AFB|@owAAN zz^=~4DP9et{uB`honB-qoa2Pr5(z~Y7%cfe(0$gMR}ibZQBr@=A@y9_jth_048E*F z@I_aFXLiFC#@?3)ZBOzTgZr|Lw^j#@g5TUs+NH=(?wiG1r?sA)!UZ)&Q)LpU#b??n zirXcMm;t3aaNB~olml8#=j5<^m_cd9Y=oMlI3-|86+P$%MYhw0!@L({Uvv6ZNX!Gx zOSaN%rjtp_l|oPdYA8xV7UEDI6#Q<89z)gCbglPeJzan(O)~7L$%0tuu5*})G}t$LUL2WZCpJY8@%7HK)d+XC z?wV_lOneAUhdOGyY~>!4RTVzmE~vH5vAZ-yM2*c1n6$JOx&}MZ?_m3jL>h84=J_=g zhGR#p{s@I9sf6OHYPt)*7d8x3hY7(OZE?2wwp>vNh2dy)Di3z9_ll)sV83zu75GW6 z9lTK6PReDj@Tj;wG7{>j(L$gpb3*I)t7&RQYkS|1yDFIyxMqVR7oLhxk$cS$!amwD zIZp~dBcj!-;?jC8OHv6rB1m~y!o5liWZk`{nI(Eo0PJh2A~%E1k=-FqYsYi-NCE2x zXr<|FG}rx8A4s>#*1bUQ+dR94IlPk)g7oPe`wE*bLlRnM`HG-aH1ctp366TT~hQfnp$WJO~aa4=-IV1(&r=YZA`lF{v!6X}R9GCzP zV}9&_=JxA&!r22_3sQ1^m9%$gf?xJ5Ms`u>D|^s*edg-x8oI;|(;44?Lr}ht*sr&Y zJ$E!1)JaeW|MyUY_~X?=tpNGJ(L->07}Mbr7dztnB((f->~(Y>$@ZG?p!M6(977q^ zQPXP)$Ad=gHBaHkG7#F3pX+u~5B3=lUwy0kTN!2i)ofh&veD_kKy={V?$|8v&BHTF z$3XI^PN;!NQpIuD3284gC9fiY*-rJl+;iyzX;QDPM|*5?<7Jg{ySMC{U@M@B{cj+E z-m0xi39T3HBc>)v$8&w;{31F>@uqwGo@H5l+OGQPluv-9_I;__x!?lJ?J09rmGjoZQPf96i!%s+j(h!c3g7Mg z`i3!xnPmTDSp`$xSF2o*^6C}gKj)1aTEHyg_S?tfgdd?O^HPfC$61qTXyU6+yCI7s z|69Iauv{@8bdl1X6gJ&SUooq;*HBmb?~;J6G)MEw$P^%%Bo&If1r_8~FTv+L8>-jr z9z?iV=tJ+bl}`5vswX~6X>eCS5nn`1T*T}=U9kF^{-4Evy#9`7 zqQ|C|f2f=8DfOMJ1W5pXLR&w;zrOhSvE=dtGo)^4@&5NLg;(vyj#aR=p^FjQiaD06 z?q`0#uC@MtZxE?Jpno}3H;LPH+iJsfK4DFrB|UvBVWaKJoE2ct!yd_ zBCn`C==%GadhzShne)GsX8vvdXTw{0a53wWoW`7@J&f*%KIn*YE=%zRr1D;OT{$=^ z-v_$T2SAMSd>jCg4j|v#lYv-3D%OceWM&e1SBSy`iV!>E<$CPIjja8gGJzP5oi`mY zKzC3j?`zJ|Ew@Wj7=>Lp(i_16wa`&5L{tv(#T4CP6bn_K^P%0q|HZbz0fl=+k@BSnyZg8;eseOSz!twL)&L~ zblyfiLjTDe!TiL2H#K|T6OwwWwsy+SVM>R=5fE)&ZNPk}lxO{c3k%B15q2gE*Ef6v z>{RV)YMndPoG}Z*^9#NuCyu^g{(F-Oc{~Z}QF5XAN)B*MP zSO$zN<@k^@Go||%tJLv5^Ua}wua+D6=AXc(W%LORkPrx(-^^HIVL%k{a>e>?NviLBqe6GR~Ezz$Gz3Lv)2lxT1|-y3Mq=gq%e zxYoroWO$xgA5r;Bv5Ey*aO|TDmPqCfFiXnyIuPFqjVJ-x1bdipnZxZM>p<2UJODM- zGaq|hqM2mOmkTo~|K)m^yZDZl4dT~XM<=QO(Li5zrS#Kan{}R+M3BtlR6bkKYQ_m| z2_vVLlK(|zET1@95oMoKpPzmr_*Lz(tf-r>PTsoHnBMt0v*k0{gk!dO_q@3vp z;uM%9X?vmGzCJVeQ3(&^H)C%;W2cd(P}?VfZ$}#OACr^FpJ!NkTTVePKs7#RH*4Qn z)Y$dAsR|fNs?aiA(;;n!x((cY28=tZ9Cz+V)6F}JH%*$4_I~aZsbeCVIkIuxcRnw) ztc7DPht-w!Jm8#Br83#(+iBzS+_-cN7p<#u8;;Z696=9TsG^Y zm~#6?;z8DZtYc~b;ph>YXpi0zFQe>BR!o+0aL=K5Tg^JVx3<~rHG7M8fH1Q+Avp^y z2rS5jJZ^t!!W8J60oWvfMzP4B%rKEaun67mpo4vE#K!b{koioHNHhA(s)P9=#cVd( zlg4C^Q`1wK9Hh(9Oe~ zE0mTHwE;y88|BUAL_I;7+GXYSD&Mdh@44M?anU84h}*Y6$Au$zn4(<-`3SrHQ+5Zs z$P?h^!>a(xMT%isPA`Y7%;`DN%rw&M>7bdv&LJWujF! z47SG6UWX+CNSs^YDnD}7YL~Fwsyi3P6xD4Yznrtjw*#r_ zDqj2cid0V9VUbw>d(j#{6QN(~{lK8-_4zlFJ9)dh zNYx#?j14}$%4)_UTGiDgPP47{o8US zYLIg53n0X_?aX4Xtc$Bv*&#QFBI}tO6F}S04`-CWvP||~U$e}T20N0R-D*_CE4j4Me9mt$#e;z4nGd~M!?`(4eJCBKf1Ip z7|<8odLbjFxcg^bNs@#*00tWjmIR=pvrby0IZD~=drz%C*k}BgV!dnVn`}2EL@~`Y zJU(ao^AQXC0Ai!C9h$_Vg5O~YiN?V<-qHN6n(bnvlPO7U(j&=AiK(|QY@R-aKTwPn zez5E8hd;V$qWfV-#Qk^fU|K-|esMhYaz{Maoqp+p+Syw3!lvJ_54`pUNLU@ec=Vxj zN2^EfQI=kNoQ~#Mq(}7K-g+N#M>FDB3`5YuW!r{HGJ&4ake{%j3Alcw$P_O{S?;@z z6m9$|6kKX=^|H0%h3QSx#B-JQ)^w1K4=efU8EgJUNS#3F6@l|stc#_5+WTC?Ms|$= zz*Ghx637yk^3jglIdO`6cRCds*D3t%$)%ug&1dk--BA+PcHM(4b5*+B6_qdBJk{>R z_oQ~+38xFayw_y2M;S~PqQsr~Fa70#+u}I8!Kz-G%sJ#9%cP>E;`bZV9YIr0B-+T{ zYL#VD=2>57Z?WOl5%`St_IF~MMf=^343_C(nqVoN7XS9#X*v(2M(VN2&T5>o*Ol#i z{H0}(VE4T_y)HUf@6L1@;&@m8+27Qs zMo+2feP>dKicK!K>Arp$bG9P$lKlmD#fKGPjF+dncZ4E!&{(!2b3 zfp_{)QM%Nc%HYBYb!*Ei^KKoTy^*^%UZ89VGKinP-aW&^_GAg)!ba?R)9rI%GM*l3 zsBovta%QPJyJ8V8S5#cD8J!b9;dWK$$dlw>;*q0;R_R@7w%=UGHTLb-b_k@%Sfu~h zl*)X%jzzey=15nXp1$?`Bo1ahJ7ZYmf*#+=YXVaIt9#}5Db2?Mhv zr?>BeoWFju%J?>})jP>OUZS(GePZECgh~NVPDttU%x?=^2XFbaI?E?y9R~92s;Ay3`?LssFfT>0N+l-{L-oJ*zp;J zxzUb9qTSmCe3UIjW<6AXng2R)!=KBkhAveyU=MMLl?OXNHv4k1)49)DI+T-MjvFsN zd3oRbOPPbXo5sha5*5Mw5iO<*cV4%+uXT;aj4X}7B;04)RCASoR_qnJ>kWH&dzy)j z>K)wKnJt~L{<|l^CQO{leXc`R6<5N>=gukKBjI*#D@$Ke%3+b1K7*W5$wnxKM9>t* zAS70O(WNf)e2R4#rz1A4uabk-?5~D?sBGUEexsQu>&;QWJxZKP=sYkt zD|uwMY(u>JXS(|?KxaQ>E*(7F6D{;thC>p#A(v7nl!P|7Bxx=oUH04W zzwM9h@!8|E&+WX=dA>^PEes(?mKYw2=Qlrhzq)(t^OWoQZL{uGtnWQHH2*%=w)sM8 zc>eKovG}%a>#g6Tm%nje;{Ka&ZtwgU%O*2vRcAYa6T{~MyE}D~jdAxj;b)_7=ybhL zb#K1&%5DaGmISUduBd znSvvAjA{Siyb&>d5gI*tOB5&sDU$pj*{}g(*2sG0XJ3)y$gILkIgVRh+|Z z%wE5GWn=F43*7Jd2cNI}UU(+K{Sm*^x%y}6%}$*&^L+oSe^HJ%tzWXG;j7|qK zwbD_g&_92Vs3iWY@rL8n>$Ms=DVx9Qz?H0bLLJc=ilxG}Jl@TX>tI-Ew7Xesan{cV z`f{)IUkXx8UxWw#d8KbZn`Kt1D32-8m$Rnx<#WP1 zR0jdcC6YFVfT(m+L&fx*ZlzGAAV7$H;-ARKdY%N{!)%oS=aeG^i5>EQW8R97i zZ|0-Yg?ih6klXuXgb1rPMV;@$3@8)=PFk7N2AKEkUo9?*FTJBrXzkd+QABvyzSC@O z$ykb^F#WS86uXR_6>(1RBcw^q*LXJ#tsJ+YD@qp|vUKK37|6cwyEZwz_HZ0@a@QOw zQXJFh8uJeXg>xgYb2JZ!QPZx!TR`P=DJ+NKrmlTUa&1do)-$-7bpo7ST$I)g z!iw-7ZDP^x_8&h z%&F15zzd36`D#jAzz4lUi*}Sk%9>D#!BX(-H`PzFQKZ_ztCf|b7UuN#+i1l!n?ysr z)^bX;cmR)Iptd6yzl2~4)EHX8HhI!-SB&Sq>*{C15n1b@LlY<{VG4#Ul)$9GM-!yB z+`}O@K$eJ6hwlft+RZ4+{{;|GpSfKJ%Nl|cLaCUw9OxGLz--&BcH9aqd;jCT2bZs? zKl>5@+MZ5j{?r9&_6S@GOQRGH>bu~6@|asQOyPlIMOcxBJCSMp(PTJWqY;L=p<+ro zB-YiCSRl|4Q}{j_P*u?FZdpl{L(4^8xE02g!C z;i3Kg_WE)6o4uWF=7ITB4M6O#7N~u?VqtpNBfJ~2-F9gap%F}!GZDBtED#i&>ePoC zLVw;f4Epk z*Z$M}dO%N+*3%CwuIJeFD|)s z1`ML-G(jAe7z<}-+i_#oL(jlUkwt+G-IeDXJ;!^HX9^}Uzl9!z#Q>!39~dkN?cwnD z_Ck8Mi`MiX4}`A>nJ(?poZAMy5%C*^ua{6Kv4>9Cg%UofMn;UKee|#hq!(*}U2uQ> z*B*)Z3V%E3s`H)g*V`z${?Tm+kzo?t5H20scTv*PU^x=8MrK?+o%ge;PSUR0l&N+# z6Uxt#kK@T9c7&GYlrF24rJ_@qp2;K*m)Yus*+xgSITeUAhLRfs+orf z1<-fVEZ^H_3-^Y|e)AZ_yFIK|c7usonLmDTJnUsY zpV~9~L&qMFWiJ92#->D+pT863EG_0?A&4nVcmyWA9$9d>A_-i)1U$Nhjo zt$Ib@0?+vmd=uo`Nz0vF)b(kJ1&$G;-kSTR5r=5ix4Zu>z+_$WU09|7|4&NuTnqB~Sc3`J>% z0S+Q-KPuMN@x*7CyqM#w2U2p~WrG*KC@v|e1@ay>zG+IS#)%19z69JoU@p(qGLQEt z5P(?`VXQOdn^2mboQzPO%6v8M#2Y#D{13JS+4^mh`c(8Fj9`0Mwvo@}@pcOhbY-@b zwgDK(ZpZq3Xm? zj+WR7N2JR7AC@%~QNwS|&pP3P0H!n^!d9%MZ!n-D3m5R!*5amY8G|Jvg2PKVj-hDi zs_`9wP;fylag@gigq@q^W>8udX!tu3u5qp@oDSYr)9-&|A<>}+U@VA3ypau+6%sogbwd!BBcBm6- zi{kzHY3;jwZZGe^$s#a-s(QIv>yAjvmaFdr+H`S~s4(`|d&YHdn(W3R#(Og)Lo`&G ze`NL=b_DwgR!Di(tKGOGLDEYyiR;IwkWi!4?HznI zjcQm<&g-lusoeX=87LbAfDekcnoVe$2`WI@s69`vSd$BY$6tt|832ftrJW zHT`RlNM)=sQx_efB^2qb@;%oWgJ+lZfs4W?k=7ScIR^uEHU#*R0UaM!!+jqV{g|d$ zgwUls1Ge3t%CwG=manWyl`UqN(>dWGwo!_ag z=3BAS^<>EXZ~uT$q6q8%)^jY{P*7cG5F9Akd@*qA4d*Y_%1Z?{<|;Ba_pLJAFz9CN zC_UHP+|vKPnd#jIVYQpvfD+|CA;wLuO|%>(Cnbh|qzrm6R&?JcKC#}8;Q=we{$3Iy zx~detZ|PdCxi&k-PQX6f6v|Ee1It~!@aK(s5454ZoC&= zkSlre)AtZUD^$AMEsq^`QY!Tr5Io4;5-;1!Q%ZNj*c;#ss3|i;$QC?yiLirC0)M3* zQh0D^t!8%&9lXMmyyx%GRHK1*(~dwFvJ`@T*7&JhFttmvqEQ|%1kNeFGyV}{V;*T1 zltdss45<>jd0DzI3KgZ-YNgw-=4!&uFNaTsL}^cJuTTrN{g5w6IHGXpNKiBR!UOA{ zjObe{d-@ub?H+jNW@ERV*e0#qo!vCaD>Qmm5@`WA5<~)3UeZNP9Q!(0IVeNX{gp`PjDLf>Xs7I$OyyBbs9;bb|boSe$RQX3AT8Z(S)X?_Q zVgf1nqylk52~#PrI>(9oMhYr^dFW_9xYX=i3@IXb<%s2@1gtXT8qjPOa6g3(w&k08 z0+UQYS}Xh$q+_|d*C3W=Se0oVGF@@8IxLmPU{%-f=qccoeb^SC4}>rp;HvEeI_XjL zC9_~00VjnBJt?{2_(RJ;ta+5|6~1W>BiA8J&2#I+6bgDugll17QUjFR2$&rfdN(gQ zC`{O0&D-fF3+bffViYe5?%NXPWPhq=sCpys521 zfap*$^FW*dFkV(yHoXp43q%9>7xltrTM0T7qBj7(+O-MXS+hW#=)!isR`YgM$B#-f zo8|PW6@HJfo}vpz)U@pP)~6of8wYa^?82^wYe9f$L+Yfw%TA@FmQkQ)@*cGeVB=E#D&5_N|8NMRjp%Ntw@qt)>mtR>-z zKtxykDyf?-w?hbzq=k4aB_S!`qnm zm7x*n%(}I<{6n_~05Hg(G#qE+Xa^y%VeRVUlc3L*uAliImU3*1xBV6a?o$A$-w7$M zhLCP4|4h9T573+lz>4uXJGCB0JZ1mX6YD#@tOsu%5;aZ(aVO%Y?uf7>e06;YRK=dz}CHSkaG%Dgo`)kE>2EO%;h+gqU%LR-+Q+ zJ`mSdUFV#mF$lyleQ@K|7$PHgrA~X4`h1L_*&)K-slKdV*~ao&Xsd3ukU2k~3e~U1 zOr5Tp+J;@a197IdTwy>L0jMPa>YaXX%TQr)g}$in@V=f)m1oc2%3p9bKN_S) zA*jfR@N5P5QFVA5pxeP&`ntC`UqNj`zVMd3Qd`SEQSYZ^c@@5jRNHk1qE?E1oDZY_ zIjMz;ltw9Lwz4Q&pqeKiN#nJ2j^bPJz3u5~iVpq7uk|H`uLUTF$J^wgcZ7=EGL;p4 z4sjxI4zEJtt3a^*cj@mQOV1oCssR2Y%eJ2}ikwFlaw~Y1FyP?kz-UXfL4YkT`2cRz zNnk6}uUD0(y;sdKtEUM2@vFLNeN^fZ-@{`=*z2)#VK*K0oTpQS%pvvbn$yp6qg!^*Kg+ev2IHvU zLkF7OZ;ey4w!Wu+P(QeU3(dLl7th?BQc^V`MRa$!oQU&(xOBI4l85uCle_c2RcnZ$N{@;C$UJ@tGuCLYo1E>7+xxjD6^IwBpLQr{muuAOY9LHzkip8OCac642%G zj2BnFe;WUey+N-$JOA=|)PhIG-@o6N5B^xY^5ggT4+%~TIwXc(6)SueqjVNQW?|vk zi(f|cJN{LMld|;Bevi1ezwPBF=9dTmJ*O+(SdN3j(x%5=M=TOd7I(d1`|OM>{&({J zVQHbIFwWyGhQuuPxNV3VfOS_J7NwNV}^77RVK5$Z3=YFDFlmE@70G)qF zAW9BKrLon@8luW_ok@N+R0W8i`95&t$H5mzjQ$zz@8(vwXZ!1Vr_XXbucxn3UPgCk zetLdpB9#2+OIBo0v7xH>ew$)~Pnl7K<$l83&yV%JBI~jm2B>h0hZ#LG16knCtIf>w+CL-2i~|6TMq85p|slqziKA9-8(B@5>tFGZAH0> zm!`i3*WCI1f{wjY1@Xr;KS0I%%BY_h8s%Bv1m9F@X`X&vZgyp^}``$Iz`n;>2gef#n`K2lS_{(B;Btb2EFG--W|Vr9&UFQ?q!;Cph;2N zS?6@BTg#bg+TIzjM=-e0th5)^1G@M@e`J1aV66%N?1=qI|EpmoT^5V;(D8eZ8soxd zF+fJI-M2F!mnf4hHM{K6?2|9MoZ=5?9YS4!fYpUl?YnF<1!Wr6e+Dz0`vE?yJHpy+x>0lIx|?Ae1prI z;y=uI+5?K=_G^Pu5;UoNccxKxn;z2gqoh=Cm&0;cMtk}e5#6g$%wB$DHPaDMWS7>M z-B2d!5HhV+hh6#{#xY?P$#UC_UKBY@)yLPl zT<*NE%jzGntj+u%CxXe^_jZrg6-%bcLd#Uyv4zL8by+nIJ+-{-O|Pe-i?$3ID6}(n z1Dc%S0T&<0pcH?dHYy`FqAQ$D00AJl*ZwBrqd;Ia(>Cyq;GMI5BiThYL`Wgtv8V-f zsD^Zi?vmPQ%KfE1h|^v752Ez95u z8S!z{47Hso6t3;KyODg;l?Vh z;%J;xx(A9~<%y(Lb`OdD+*$re-LsA7_kMrb{>JjZN9-5&DX}4)H)|ljRd)*kzg;$V z*e}bQxL%J#SPydI6!Sd33wM)fph)Ye{h!guaiMabe&74)CdeCcg1@36@$T=PMpkhf z@(nv9cc2zu_$TkujN31LNE^^_8SZSA+0l3Ut2akRy_*NIrMZ9e?u3`nK`Oiq@)Qw; z8Wa?q$jQWr1k9~bL12lMFG#y82c=ONe?DXoFBcUJu?%H^tXwm-@`%~c9$?|&EFkPm ziKn7LsOc3UU2$l=(>f*Pydpz(b8WY~b+;2TE_hP0@1(P03$ft1N}YB`OI9@xyfZ8; zLMytFxdq^k4cxD%8AF3ucXym817Zo*If2fb%NwZMsAah~sQ^4g=9e*0T9@ zZmu2XJSG8Q%dA%`yfeHae5J zJKEhc*6EsV$4QOF1{u?4Q~3I0zGk#*jk%cfR6na)^F0@AVBFJwq#nrF0hHOK=Jhg; zqNg(LQ?~iPcv(L(DDXo)=qHZwnoOM0N-TG^a*mc;?%-)o$U)UfH_;ff^WH%jIMO-b z{E^a0-1mBjR>NXxHh=(c7j{Bl_LmmTcvXLx1#7VTcPT2VO0&Q_%uB5cPjGcrKERkE zs*3$j#!FOwoaP){d-dV@#?QNM-?QpV6hX$Wk+Pc3D#r`!3x7(hYQLr7RxSNa_N`J) zc8nahd5({Yx6V~so`qVF#W{c3dbmHrF2{fIsCd%WEiSd?!o5;H%QIT1VGQaxMKxgJ zYj9d=v5}t^bGpponA`m0I~U>$Q#GJAAw-Xz{{q-&vOtg(FDJ_l5i(&G)clLrWj{4% zXkqmbwerrOew}Q~)32%4C&?Tai$!UklZBruy^Fi6DHbYDx)yB6&iQINjP$|gtF%0Zt7aSp51eq@ z#BzKEe5_l}2!BtTF{29ePyeY=HsZ<2#r9hVk`}^)z0Nxb70(leB(4(rvl z%d@{ZP}_Ne?Rqu?Q|NcwQ7k%d1LPyW&q8zh1M1}Aa+93ZN#T6$;@WV;Pj>?HGSnZSCMihc^%VWugP z=G(6Qqn_nZ&{&ew@i0djD03x02zkUh6SKnYvQwdsc6LT+_k=-g<`_l2GqtpJPN{Wm z@%iM@OkCgJJmtFh!jq+$Bnj`%$3Pllaoh#_vA)yh;LGp-Md<1LT<@|d<0Dd3Siy@S zdl9_>nA7ExTEo(*tVfK@%0Z4+$#JMPjTMJ`-BQSd&d1OA-KQI6K znWiMgV{)6*HU1_Cjh9Wb{oF)Z!%H9^FF?Ch4iG%)H>uOsQB&~Rl(=;~MaSlB-FuZq zWO_LWZ4JoS#A!uZrI*_Ui+~0lR5=YmwLH0O#{r5!f@plvuHC=RtVbr@(n^%kSqh>W4NW6ir1eqT_^xrka3xV#o3Zp9-hysc8CZjFchqKf*)L4ILFNn*N97ji_5 zG*U;6(vic1>Le-c#X+W0Ac;Z3%1p#5Cj#O}Cb2P*od0 zk4E%};fWEb=V&uaHQWT=`12#=TOxg53HS@y@GBni290EfC)b%BswXG9-_Qn>qu$`N zzb7-J%b79d%pXx<2bNGT2@0lSi6!_XGMP-Y;L0oQKz1e|e({hLuFN3OZ;1#q6e|1z zpi0;>N;fjA&<;e3f&_wS)^&9?-?v#2)XdfSNS5sl0{4sKeq7p;#`PVg%SgRTFG|KY z0A#-|GEEt7%~ed}Ac+x5A*3B4bmRsA>3vGc7kWlSIpPG$|3QQ?CLkBvkws)8qfC$D z;c3#3j<|sv5Tu%tp%*ieREo-eL0Io>K^YIZ>r0+g&y)I~GaQHok@Z?&{1Ld5!a+)e z$P&6Gmx%g>&JJ{P{uiy%&p7uTeRwfIX*LDb&9T`pNcN{~-Ck!m$w7S)J4-XHUYDlz z>6>+MQhrGHzYvew@9y#`*m7VUwHt4CXc5J~Ve@pkNWb*Vci!PCWso&p-sat53p)H4 z5mn6r?vId5B_LiDZ%O7N@9aRm+))Y|;=@txIuSy-v2c^+2aGOW+T5R}x zjd;fiI3z*N#@TH_j9lO%$4QQGMbJkne@2meIH}&=DNAA_e$$aLWZC^ZDIB^lJ6yrh zOD0o@{KZAMJkI(_LamSyC%C1XbG0txjo$Zd zc*tLXBZrsc?UoZ_?~$WboJ4!~in0t)9v=0Jj!s)b*#n~bXT8<$na_yBFO`6$hS&xdiR%Ov z3DQ1Lst!5HoLxsI^K81=33U|H9qmWf$jA^U=nppPBVFcRf9kj@GIk0aLV*PDy&fzN ziBblAVxtyF0seH*?o-#C)fJJNX$t*_mG^RYU3T)tas3oi%?b%vpQrHlIw}l`s-o9u zKGsivQi23RLib*$k~DWj$gR*(Z_$zBb`W>?up0-~N|N^r)TeThQfOFCWa;+Nm?@{~ z(gq?OMK#i8KG9H z#LA;2q+xc2Q6}Qks!K{Bm_bo!AUTEXs2&qsj^Z9(qakEAZ*c&ETDdw-dxH~&3D1AI zS_goV0Eg$%urCiQ(b`Q)c1_p&D-VRrNjj~FbP0SFk19K9b+#LCiiX*QEBFhM^FsIr z4WWgP=zs6U@`lq!qyciM5snS+R4y&g<1-ueRd7B82>HSZH>v;|@?br5ganNgQA%ZF z0=|n;ABDa?%JPTa#RFZkRc{zb-7q4Do*E%mm{&|Hqq(j@K(j)J_ zZdguoL*p886Jn8Wx)&N{YQ*Kr#84Xg*)kRa&QChBn=Ri!hp(_u9e5K{A?xB}nUuOH z(;#&V-kmQ*Pr=E;H$pexPibpU&_1w`L|Uk+qFo{X{lM8R;${o`C2`qd;?#$et7tp z;T|JJ6B2v_Ul;b@wdLspQ{=RhK94k8xq;U<8VyRVha8Yv{h^ZK6(=3l{L~fw@BzoPNmy87&l$Cnw3?IZ`*N%%@M=qh- z$!*2VHsfCOW(e{p=b%m#N}|^Onu#Ee^-9tQy!YL^+ zAUwz*rEhR!bkuscMb({%fV8s_pSXx&GE!28IKSqLb^27qmbu4}spAw0ggWKU`p-<# z<@umSd`R*pMDk?%%Ye7Ad+=F%_594FGpF3&3(~~CrDY>Js}~$a0=ZQZ(v*fwx2x_Z zmVVW~MfsS<%=J(}?2Hk^lPwTK6orKq-cBnd6N}he-hW0egwEcLg1yuI3%gJvzxf$T zu{G}(?>MeGYlDj*Ge9(TR0+rQ|JXYkuDh(hx%K$YXSO};gzr4W2f8~bcTjxc?xhW` zEfCZ}`n2W4gFwHbiYU}N9r3PnDBN)-@;Ot@B|A$-|sVN9KJZrBH*5m#pGD(g;pYCt|B zy-{v={(};S?*4#}tb&i1k3aPJlW!`3AJb0Wlxj7eG!kixU^Wu#*e8csmh9bexORUr z`O+asEC+ON@}B-`|N66h^%QwDp$K6@ltMRRQk%&{Bqk ziLe(qN+qD~y%X?^2_5V^y|IbyxXB612=JNPGzV32SasJla!k60E=K%|LXHXH-V@k0 zr5RPx0RNth!#8B9z)>mo?s^{bH~o|;AGG$)3c+YUe%8RZxpP(^-f zJazA9>&FmxbrC4=rp$BpN%g;QHWx(;TkXJ|v1;3d(UG-e)>c9L= zgt<#w74p(um+AG+TB~dL9zC1OcME%(??`&u{S9Gb58ly7H0^VAB!+>njo!@ z13U}Lb)PiQ(8z+YTklqf&?`AKb z>nuyeD?Fqq+!E#iL{pzh8K4V)f-d!G7i1u?N{!S8oMWU3d}5Y)w+e@oq?8YAF0A&j z`>_<@o&Zut8Zcr4Fd-&^fI_B`4sFYER01s#EIl;GO|$<-0qrJ54Rm=iWCk#Bb!2G;_o4^J~km812{kPN6imQY==U@8`O*B2SBg5@+tX- zkyNe~ROjHIl%?r6S3RyC{F}D=ee4BG=g`0Ojiva+yd$UzriLj6f9uPY_!L?O)NSJN z7i~$nrxPlfnR)d3shQj^tOXelxq50r#3W#F)m>L86k1!ZeoNS9o#XD_x=gK5fL_&^ zGHL9+1}~4Qkv>mgX8j|xv#+Fcyu2FIXHq*nR3JyYaLL4hh04?8sbE`A;iO#W4HW3RU89Ue~+8NiBWmaV-Qdj{b5bX^tB$>mzLF!WOn{F(o_sVCo_4 zPCh}PQs)$ez~_-C`3X1a1g2^md#Oh^oI8E;& z$(p@w>N4T}QY9lxuDPF#QlasHvTj1n9Zdb3DFzr?9b_}c zv0tvMqIaY=StogxSHV%$INVjB5*xX2RjaLkGZts;##c{E-h2D*i-RB(Gj^SSLxpfKVyt#3LX$XXAno0%(l!rGk zL`vB8E4NY@U)#|hzG`l&n#R`(DH$SJ&E(1lhyQr=ZV<1eO{5x>lFKT}uaGI3{Ian& z!X}l2g9OQ|3vEjU=LRFNe3+~ek1EXs>cj8%yt+NTNh)tjL)$c%n@ACL?zem7j;94x zMz0p754vFA&|jMS58c?=pBEZqH~1jS&C=s92r878140$^LP{fa$MJrOvx3@GTFto* zT33jt1zR^oTK$4SjcuFq5;(_HpT~~XrCVbK`gWJ2~@?{gJYLuA~( zDW>1-vNP=OR1(pnyY$>P+ZN~1h<7z_-f}XY?I$HSnpiFbc6+`W*nU!@2-675-Xd@+ zJ=5P2*mZ;(GIB$v!49ife z7ZV)agX@pA0U(CtcH32czLrI;-_K~FEpL^rVqcRr%06Ul9+1sw6l$-tyUdfn6y%P% zSTr9+j9*sHj2(`kjTt&emI!S;l-kusXjdK7F1@y6wyU*kK%^`E1s>^Nj&@hF94=RP zXCxxA`3+Fh;2R~0ZTD~u_YU|cJqfz9I(TEJ?A)#&7v7x~PA1mXc$h_ng7y#%bk?mu ze0^uycdn5V_ot;(p3a6|7|vAsc)EkibkbFh7X^=UJ>j;ZqI38e+-f&8{EtX-zI0fu zMSkOPZ|O4XgzJh9seE_9k44nLPy=>nd|PNx;+=%Ali1Z3=$7(&Na{-a?bYaSj(~zHOFJ=oCOD9jh386Lm{A+7Y)Bi($1rU|F+txbnz@tI=yzHoZHD|KU>QvX zLsP{dEq#}+C}lO=(`nV48=fCRREi&J;4^i8w0zvd7HL@UC`#-DZu^HtMMrA^FyzK@ z`>BAz^m-8Lb3iWB<&@gK*^AiDG#Ju3{$kX}Or66ZKY03LsE$b|_AlpF?9@b2Ozm-F z;;{SCwM7I^RbEYcrLv#9AFxdy+?-qd%|dC_ocJIt0rj=AX4y1~m1uf*jdzsn<`5Hj zX=Lz*`-61(m7D}_4R#^A%l0iF;U~U@xAuH#{eBUd(&B<0iKe|xiAN^ZzLj&Eg}k5X z0g=ilF%4mNbMF9 zmo{zuZ2iFi#m~bQ_9Kgkph#_HUvn4hw*iI6kNn0A5Pjff#YkFuoliB%!$zgQ*tijZ z`ap!*zKdTtXMZRAgY5gA@8S`*Y89fW+3TBlO~+2&oz!lhR*Ga3PMo~et`2(a{!H%L z665|Kos{)$-Ex6l{*iw)ccgbibBhaU^ zxkz*(e)PxJa^kvG<-gD8QuMHIhfRqAPRL~Tf7pH)jB;ZDUAe6w3i6nZR&=OrYpOsI%_2Op!K@EaicPNq2{UNO$)0>oM!@w&daz z?QP>9$JTp;Q|JXryomYl01piks3NMq2K&sti+H)X@JP;`gi%iqV*O_}G~($e>bJ&C zPo&{?uA^#W!>sc+GmdjxGhCpN_-C0sNUR-nPx%XF5d>1{=quG#xvl=?FMLU+oMnPNqk>^eyO>W)|Go6Px-+TWt#%G6(JDA1sODg zw(oZehPP{1<{dT9!6fEIjNaCeimB`@@?d)ird_qx!C-?A&w^Q$gS}J0_VqHkc|aof zrBh2rm~SUj_)#~TMCdgMQ zczKcseUQ?#W|+Z_?0H7?Dpo1t6!Z*Rzv7%GytVQA;as+*?f&5oAirGRrxbg!gTW~+ zV7tC7n7@Cqvg)d<*3Hr?T@9a7bJ(3k?Dv$0V|d{9`z^`ctT?gB-TSYfcD!yKeEn?7 zCwL$5xPX-!&2)lgIdLJK>(`&}FLHH7bq4o#W%&kY!Vktn_W`ms? z@Ed{3n|_Q1Mk2^cp&QFrv!Z}kTJ-!}3tWDNz4}o5X5@ZRQ;JC{?dr7{)?MzK&)~O0 zmA9f5Ukow(r1gsw!6S%@hcL@~BJ1t!{;IPCY1RHgilLSC*!ep3c46i15Ad!JkDY8e zU_TDnmi*sB>20<`-)iD67P-v08{{L%@>qu_ruY3B?E5>lYh+%XGw(g?`|6)Qd7<}u zQ{!uy5P|Gr0VGKP%@)8e3goT}Gf@tfJqO8BYK6)`0b_e$3$_wU_3aAr?B9t!ocsoeY!x z5Uin2!KnDI;I*r|*TVv=r#fcp87I(ptqO8!fUV}4*las! zZ2g^^zCkx;vrZbaVmXh7dxi|Lj$bQgQu|vE!e+o`OvxpLh z;E@2eleKxY?1K1^-668WXCHT!WVw6F7U|M5Ewdk9nY$Fl4z+&vTHpGEvG9gu=~lr3 zRKUyNHI*kD>+I74R+IB9Gw%$4Zl*=02*W>u~;X4ufpCHL%;7;7+F#{6I2W4@QPThhXq)1)F@ zeD>4Bt^700+3p%s?j6+6}DSJQk4}LvxsG{vTDbJUen1Yu*%6 zgh_=;&rNS`GmgWyx!CU4pn$77Fnh>Y3=Puqj+Ktz65|C$8Wic8+*Ec~Pqbk@FhgCq zFI$P&rsZ$uLn(-&?4zo_yHS;=;VDbkJ#<}vV5oSEW@vm?QV)BBhs-djF+I>^`hn7~ zr5c6QGhr-=LlJSm?BHx3rTu_Ci5)3CV7fKq^B7Aw=97Phsdk!0rgdw;AiYOllq7#Jd5=QT6)ZQPP_vZe|xsqwFBrzGt|_kJm6=g=Rkc84=EFhaRZ?(Up4OBS| ziD{(b#MubO=F=3}{)!7-d91i-W@J5cx(9kxLJukUf9OQf%Jje@u>p_`JQA&z%+As&Ll8;O^f0JZ^vEz)T#OK&GmcB5goW z??OwT+GD0lD&Kx)YXLJqg=mEKgVM@b{v@C_;h7&nN;Y2f(wKKBMNH%a{UD$RK(ns^ zkQEKY_*2eSh6RQ}lPRo|_+veiGc9~4CQ!LlgP#43P+aBbWYj8SMFg4txfB1AL8Koy zYHhnO%Fqx1_Pqa`^;Bk8vLdz=Q62_FNF8x;fVQ+k%mJD4fG6G5GCQ|z&RLjw9vhb{ zWn`TW_qP?46{s}MYk=Lqma9gY$;H;&`eQz54Ijhcfqpqr<@I`TPQWQ9!#M1ak!!Rq z8Fbmp-e{2i%t=LE)AS9pRF%X$&4Jztky8gAQEpPaXKiUU3ptI?OXx02MymKf&O1s1 zw#2hV#JH|0po4f%>}4+tWLJBOALtUwm}%KiSYR^Rg@qhbemOh6NK(e0?)O(6d< z^mvN_Bp@?!xTkY#RNIBuah|}I9`)?{LpG)0glILXK5lJ1w*+hNN>-tH&6(aWeieFQ z(32P`^8tyX(xX!6qENSeZyev)l zBF9Jec=zXSTINywsf6v&&Yw^2PBOgcYYlR&8U>qt1T)?mnnX%XC}#=|2B=?-ue_9& zsKKIITaqdkY26SaH=BlL*-umO08s83Ri;9AY|gP^Efo#oom8ScMFg~KVRCjtk9x|o zN}{^Mn6!1~xq7Ye^@DFTz$b{%hTYIa0E=9%*#v{e36F?tF3$|a6I*2xx>>;zpgc|} z8$S$bhO`p}ka!a0T|Fb>88jsfl1usWGg%s0!91PABDHLdi`L$a+!K}0O7~4rcr@@&VW$EmE6DU(r|5d5~Kh=QAZJ*6mG$bP84HTxR!uHghZ%Nju zWBNDGO|RFGDD)NYR2kqv0me4zOUr?@Q`dnTKIS|Qq);I z2{C}&jsHBV!lxQztQq#?9&CqR&yH3hFIzh_;)qN9JC!poYY!@KXZviHOqv>gvPt^( z?&8zX&0l);qqw>4V9)zj=$H<3L{OeU1}ufrGfP|J3se=Gq?X8 zTz<>e7`w2`dbfDyv-O5~!!Gh}5m(96loyC9|AxOFn7fAW25z5iaH zb!jvw*I|{rB$j_I1nt7vCsz15&b3lex@Y4$Noy9<84Zb{E-Sj;#QrKXB)M zy#H<}qxJTrrLDdxYEt0k@Fy%G0P$u%!hf?qJe=$1v9wgLzfTDaGGD(RQNpvnR|~QG z#r^$38qt1XmnCa!SV#P7WDpDTR>LAH6Jl|?=+^K1%0&)g)U0;%x9_8)9hVZDXXii8 zufwZ1R+bC3jPz@Y9By?0T&*mYlw9B+S3pI&7WCpc$&=r-du{$k=>tV}^HWEs9adG| z;?arq%755dg+a0zq$v?{XAh_5*3J)G;-L0x_Xql}2;&RY9E>zNj50KLyeuTKIS^~g zTYvMwqSNMjCa65dKun^Z?#1@antM7O!fu${X=+P&#$fIg0Nb1wBXFs7O2*!k$Rm%9 zbryu(EdV!Y>Qv96UtABz5htjIcYTh#y{^&)X&%A#tXxAQ=gqA^RQgm6Zqn0DDV%)2 zr6Ss3HSB*B-FZCIj~@r{&9IFf?&cVC<*equwV9hVXGk^okx(I5wV7OrA(9+(AE}T; z)ORyyCxs|!&V;l?QL^8D|9$@4=kfUL^V!~?*ZcVb>qpMz+-~7hHYW=hKfxm;@(D-T z-s$n!KH->z8o40Z4B0Fln#nYu0xz~^oa%r5YJZLVFPgyl2$E3Jo-(>0cTJ;KH1Bc? zi%a#(_8!`3%Uz;DRjcRS)hyfVZ!#Ftyt$={#A7j38uj=Vz)qK@h)9|t$XUpY9Gz^- z@z?{QQM-f5IfV$z@*3%0hM@VrYo4PI1pIdNrs;lLc1X*D!tWTA{l+hNbgc5}#RQa7 zA2~OZT>OIZN0^p@2y&HY`8z#eec~kxdX9WG$ zdjR{AH<2D+Nc`3U)HoQ1Gbw7%-sloMQmW&89zBS8!4Wii!ppeD)|@h>03mC5#7Vl6 zIJy%dj3syv*$Q3vBp=F1%DlOIy`@#Umg=EZNqH@GEIN! z(9$AVT}i^gL41Z}+Wqv@RkH`yey&0#w| z`DK0-Kda@pafV)MK0IM+0Zp+NvS#x0y6yX<*gJt{gZ$JFpT=dRJ%=n-Tsseax>5DL zOHeyq2N4*jtQBFy{_|XP{OROj`RCPHhbmkJz?!KsQfbV&FTem-a05S0Pe%Nf#hrevQb_RINs z>()3w&P`~e$|dN7QpNbGAs+eYSM~zB*t!V_a^|gG<+c=!4InR8 zN*>2ADPLr|@}v4m0==UmhMnX3!IoAa-slTj#%;@u+3WVQi6JPI-+Xu7znXHfkSyjpeag&k+S-P1N5+`GEfl1KOd%2K z8CHW<-*pfc#+)Nsb3o$_QKUN^BZy^NnHbNH4iC^}@gA#=&*KoDmy`q!8xc%@6%lx? zxnKi8s_B-iTgU^F$~OoI>USCx)uJpL*k;&tf(_3BGAZ}+jq&NFc~K?3R_@4Zd1t{l zuk!zWI4~hSh}qxJKtDsJn`}Z`TNIkw~yK0L}j_J);%pZ_-c!5z0M~eKr`kx zblv%%T6+-3bOJuT6LszCwbL&-&xTtHu)ahc+f4x0f$z8l&S~J7Mw@L2r-2i_GeiO$ z^I@@-YDok^``;;KfnXj?SRyD);uKtk`Nw$5#o8ORr8;j46}%8ttXk$mMs zhHOQSxX}5TDA?6D=M3q$SQS{Ofs@%3@S^uE%Px?cce>dg!LT1{OJ^((u#`Cf*p$^S z-OB6cb?%YrlTMKcBN_mKk%6WZnV8Ev?y)A(Go7Qr%jGO(j}yk4w|i)itewo~{;BGc zc*&OI#wqB2av2*)5|_l+(|A(r8QtNTS0en#6{c7 z@g)Z9D4h}>KsaYrQWJ9-G{`tEo+zdhB&A6fudyDtaF+0k;Wuouo;fDjI@PBTOpvU_ z-MyCTSwi?+9%xpc<~%KtOCHgq14@o5IbthDMQ(_j07W{u=)F6_E>hMduO3YMIkYH3w_MFta<8cX<>jgs`T8V1AY25o z@02I)V0E9uziKx&W3wDtla|UPgHSC1p>eWmS(Yj8^`U~{{BitRlhY81C6sc8nxhbZ z%@zfyS8T=?N#90Bfnmd`iX*vKiG3>GrP7VeqbWfS7znZvj*$c=hS`XcS(a%a7`<=l z9>}bbLRe;D_n@{rc5huVY13u?l=Mda&mTR$oN2F@_rQm-nX3F&@ED4832;z~c!&HM&n<2aKQDqmmG{&}Y7GY~=Gvl)?J#De-o?%3N_5bwFJ*9tPSAEdGY z2kFC_<|pDVFjaU^CI^RV#7jobn!)lR6;&2xAXJbHHCB0|i^P35p_txoEw-p&!AKPl zP|96y%r%Al=mwg-B$)Gu(_B9IRq=~304NyMY@B6Y0zXkFq&k1Y+)wEt^yR_$d9}m2 zhZbLRfY*&ySRqnC5m?{l51=$b5C-@1QCz*N@0pr^67u|Ij*weMH2w?a%39K>l6!zV zXqz#AzL*`pxCnlWQP#Ej;u{=ATL#VuH5J7HyqW>|iwT?%hp-{X4yDon)1@8d-egrSNL+IdV5bN5zR!8EGhcoAf(&WG{Pln=7Ei+Cp;_TJ^xg z8u5Cu1QR-eH?NC{{no?4Se8-KUZ-9D!1~F?6_E*#fuBud@TWw*%=ke(C{@)QWFzNo zYrSS+41%%ATP2`N&gu_dv#x2{h%s>LB!Y1nkC7#qX+yJ0{dY@Fr*-r@Ia7rv$p)*4 zbX{xxG@`(_#+}?FyPNz!y7@20IS+*ujcMnp1hLGtZ>m{_7ag=$b>MDWAcqlWm_;nCXCd0kEYNk;eT4ok481iW1)tyv)EOZ2?kPGfj}-Q zS(fm{&69(EWxd!R`YQ?f{JK67k%)g*_1`dt6{W+tZr*nWzAI+WsaB$q8bvw_n)!EV_lNvcuQx+15azhulUsV_~?i6 zwJs7&U2B;tZK&~juEQq4@!6XLca#y{eS=G$cLo6*XL*=kjO7%JasO@^8=&JoV7Wy- zIt3y8JI8M%YTia&818eQV;TYS^|XVUZC^9of)^pTjB8<~it9pJ2n4o|RZ!Qx&N8ee zGn$xmk5?DBj_bv=Xe30!Q}Hif5qSAU3&>rsNKAX<5%L7}jGTkhAoU;vu(U`u>|a^u zMBZbQwP!-PN`DFG|K*?1J^6O^CB2t`#b(R)dRPXvrgeSxYjkusf+fcjB-uR_HgrlC@UGGZTrYSmH;Us53{3+Q07qI-+q-!<@fW z92Ua`-hv=T@z_YJsq+}pfjaVXUMNk`r(FXk0+>55}UJ^%_S0$2uAo;keRj>XqqfidVVKDlmOva#N8Zv*cQr zBX&|&{Cjz_cV>=puFCx^d<)XZTSv<1=ILF*`xxr!?MBa>4$r_^>5GdG({17We7Y$t zQ^q56PM?3wUAfS+qTeTQM<10v5k{EvnJ*G_!x+u|AYaeAgYl^zOqE(OmaaBP*N@7? zojm_IT-;xza*7X{2|@Vb>*<6JysCZdX2I=Y<$i)Cju8Ld)7WXDy6l1`m!)};%GDCL zcIwxyo&z50A;D%gLyDYU4uB%RbeR$RCV+S~7|W-|;0WC(aglj@k19B2#k*a9-e@`J z^H~x}peR#s2rRZtoqe6jzSWO__6}{R9&@>5K&4-l>A}+~x3S)Q7eyA24eN3J25i=w zd%9WrB2>(yx0WXc2k4C@M~BSxznYALJDb~aE&!|=9F{H2LC8HH z!*yz9Q#D7-;5bgx|FV=0jCv@6;BOOM^7YIGyGOFlah`=bzjK)qC zspfi%L4JJI3>L;|p#YCe_HXRID9Y5@ey3e?$ zm8z$$Y~DNR3;<$qRDEZbE=S?cjzO{Rngl z=4?Rg7tR+W79XUBCM=vY_MC7z^TO_C7M6PqMFqm zo65lPS;M_7eXC4yTHxvc``a-K0fgdFTED#qQLz_-sCwXK%^*z@a=vyJGX(7lMafu%Ypr$1g4`MHJLM%=muV zESwy`S?NuR3zjQieMRsL)Ej>n`7x|O0&AJVc53|%sZEdvw#oNES*B6 zZ4+8!1Pms}z-5dw`&8ba*hIlnJ96WtexTwJ_deLlO75w25(ij4s0$?FM2%Tr!A z@i|JQwqzVoDhE^}VBK?X^$f6E%b1s53Ck6URu1cxD!DH+WVdjd0YxE^4pwhuh?)OK zRKLO>s_;hk{h9^#N7A3I`q(%tlxI>7q|DAOl_#g3r#*ZfvC=P}>^;}sq!K`1mQQJ~ za@9Lsn`m3=M4yQih=A#_o?VR~4`MAmWF=rh)s$svn}7lPhZ3!08R(NNRtrQ=NVwts zYZBz30`9y$1Z=z9ruNR7HDZT0;L=;>L=!h14hrUT<^|KO%f0<&{!94VCVP1j2m&J# z*?l?K<}j~^$H0gOf*z|`LkDtSQ=QChmb)`h$4;E|zdiO0$Tu5uomS@=ZUua!@sK@t zMDL(R(PI6G?n%nMf7ap?uL}iV@CX=DEs^LK!sd`hi^|PY977aRwx;bi>8o=Mm4-U)qIT%SG~o=Vm8v1v z<^b}Ne3I$(ABCW8CtT+d%2zMt5e7M*0KOw$|WueJ@OY@G$YmX9eQ zYhJs}=}tGi{nc7ksb#@T?SlvWepMwd=D1$kYP$cb$X)f3 z49mxTc~^D{(=_QIh4oR82N4I3onfIrtfrao;}KXAztpE{T17K0_w5Q$fCm?=&WPrP zjD{E}DdjgN(7{O@Wm#gPqomN!8~x_j(SO-4Sm!ix_o)T>so}}p$p6n<0*^RFye$+u zSQ0f;Bi~PQfNgQr zwnu+a`A{u%?Oifhng3e-IkqsYzz-;D5~z3~^RCrrEf@5Ze_q@;%Yp54tie*Uc>}5~ z$Z8z27{%Wg4;FM;VS_Dq#(4V-5JCKNA*f(GpM1`OYWN6DWM&khwaklurg?a;^d zTLjy8JPdr?@1=xkrF;?+3=P2CNC_LcV%#NoAh_*5wuOT(=G5>=A7tYAS+AW@F=%z) zwF~`Jxf8fy#@oOar8IoTTFH>=iOHK8Hjx2?Z(%T!VqS6!E2yU*CNeyROxa?|&|`&k zroISs$u44ovr|w^z^{^GlLZBA4Gb}9pGPV?BH#cSYKULH*)hfvTPEPuX8n;h6E;}K zzz_Fu0Xm=?eS6#R_)JD*h!f<)_`%ysWdwz#l3LHtS;!t$ z{%G|1cT`)qfY+sFfe3omrZb4Hl7&tPpy684%6-yNAd@62rZ2s(+mJmWr%!_uI^@D zYo+8R-h4na#vXRBx#hQX_*VBT$&%ke0`M!XEa^BhMbJX%l){LF-hMt`MMSuHTktsMr+%X6C(N2Cb%&20~HXtMA zfhcmTR0*r@-U^Z|xRZ8`B|S|V`r6T95UR5%=cjIUmfYcT$v&{ZL45JfOLopsfeQLf ziLC)qr%2K|W?*FJh`xP0!pK?R4)dN}N>&@pdpv9~kA6o_KJFMQl6r&tn?3kJJ4yC9 zCELEk*(Nc;s{b_udiRrWy1{uHp)EHf6cZz8{DF|mcXb?o7gp|2y)_egSnG007QQRs z_wuB-@X4jEVyme_Y~=87S(CF%d47G4VL6wEwx&WmPuDOmd9a4rtr?b2fC{OJZ>l#} zV~wj9uxe~TfLP7ci2nJeOMXi46#j+x*H=X_iSs=d?;Gem5!Hbz{?-jknl4m#2YI#T z4{xG}zQ)?h3AE)8^wR_#R@*#kO&*1NF!AcoP9o3r1HiL8*`|GDTIlX{n+iUo@-AKo ze``B3yzo$?f;;HKj*aZR061w$rt`__p~H#WvS$Q-pTN*YXX|DP#5Fcs@h_qLhel)R10(56q%B*kZj$N2kIyc;eapLqvl_wfQRCC74pR z3x3daZtg}1Z}Gk1=b`&CgN{R9H8PW3gSsM1ey^e{ewH_6$DgHAJ&mb|_s3SAG=QJs zPx;G1$LuVB@s!xe0Uwev?@;*fJm)kB5hKfFUm$AL?PwJ z;L#~OCB!%8(Ug%XlttoQQ()3z81Ljj=p;vbp|ZKW1dgV1JVtSSjw?pznNHFJ8Eb!m zdGT8Wv>k{~zJ5_bS4&~DYR4F~eWhi*V*rOyQ^0V)Y&+WrSyGic10Uj)1XJ-jN_IQ; z%Cht49EyPjqhUR>wUAbS{eTAwn?Q7j_VY5j`yx=`^tZm=#b5F?h0}b$?dN!HcZhYS z!XLcAcSVKNQHB0Fc8`gU zRZE$Sk!fkt^CF@4nDQ!kVhme!gQAd5G1gX*O(*Uc$H=GpYwaIF%Mo{W{A)IuSFZ^3 z&H~a9UY1~GK>WUCcx`rt0?@P3>EnKp{{xin3vnj{!~xdwLH?pjl&eAhU;;-=uS!V0gMQ-(ei}9c%0vMLPyeF&!uu62`Uurlcv$ZAsz9NeL)8Gw7)~ZS)0fTH-#J!)B zD`krH;(5Q74`tJZUh12U`OB(P3A1+MfwgrQ#4)hIQH~sROFm& zsbc+oJ+sFT%_OPdb&@P!A$q=mBoHXl!Ss6JFRe|HZ3nt0Vk8^m(2^hspT8_=OJ)Yp z+{{*qq{uEmlr8X=-1-_5!;lag_vxX?h{W+O?T~Zvu;4bEBhH}@pf8mOdSn22oPk(n z974F0{;=SglU|X7QdiRX$LV3$2EU6bL1kLPC?tUyJ(KOlLxz@Y_M4UMPkUjh{Ca4wUP^ zM0&P?7hFzSFcOry6wLx$=1yLcy%hgRs#)ShG?xh@aRJ22v!OR^l0L`l2nNUXzJunx zN338>pKyYjQ!m?GT9tVZ-~Wv%2J6i{j*@n{H~bj!5@S$Z&56MX_K^`Q@yTqXgA<)P z6-vDH)1`$2msp3_I|G8EQT7d&bn6WxUa?i)N`d(fUaSZ>^I1i6Tua6Evb^90xS#}#p!O|9Gb#CX#@sU(_mI%TO2#T%7)cfU<907lD&A;t zYc16{^Yc;&w3`+#m2_U`hWYm#3IJm3SuIkXZ|8}>uS(3O=ew6E>vZS_0A&9t%0r@c zBIvT1CW;&?OE$4kl4WUX=!jtlXrFH5LlcCWY^h=|~AAs#Ev_ zFoO1Mnb;cFtNhaJ7_elbhl+GkLia7zF8d2U&!1N*Oe(_4j%d4^B%w@7#k=FwYVJTr zW8W8)ty!0yxLqE-Tkzvn*+hFcS*q~3iEhkvIehonR$??ZvC=3nKhEc8eImVF>z3Z_ zTbF&h-&!loFcCz0Nyb4QyDQRSSF{TuT2L-T{5qMLNc z&ih6m-yW(5l7oTmTzYb+r}vea_T9g|6Uk4FWFV7u2u5Q!5KraJsPIu?t?nS0BrF)s^J*J|0pK3}UFYtQEysy&4)q&GDRKR%j zfu$zbZ<5mQ(A$5^uWuqT(Ku*ex5ve6uORLu{kBto;k(D-DUW}i3>`{j9azZWnw8)F zQlQ||b#bOUYOg=keBi7hE5CQ7d?s;A<#~2=Yysx#^wCy)|#%cq5DDy+a-=)Q`lq5-Q4=#eRFSLw1{nb!Qd-zCqKb+&T4EVos?l|L|Z~#wJns5F&E9VEXi^uB z8VDQnhnsy~pT2ANowx8G5d7(GLzJ|Z_lxm~heKL}F1P&zCReQAoSq>uOPd}VJrGCS zJEJ%WsY6sgWz0ud$L)BAOk``NE+sc)-W#bG(ke}fXbWf3nzGW%WiF_oPLE`cY3Rmv zoJg&MN4(ZFn76LKe5wbr_Q4@P8+A)LE|cXFlsu`vKj;nev`CrUay$3Z_~-YrfrlHf z4(a~J|0o&YQo$R~dUto0|LZw=Q`3I&8pGEW^kdcCTjB^iO; zgkVVO;{l?H{qA{(3_K`{E;e#LL&`Z_{tFjtfc_ay*c+GJFyGb--z7NsowpIy>1VKl zk%}V(u_$$2dz3L`d-P5S|0V?Oz@Y_ELJEc(JlD&2=TA6vd0)dB)7lZ1zdMv&EF!Xg z9fwWNh#yx|8RunUZZdcwNmKtR60CJ5@VKT-P7_med%W;OLbBmjj`{BycNfzgk507= z&#&AnFiM@X=@T|82^_@a@$(Iqdz^9|u<|oMxpI^wW=-oDtMF2P^l~11FlyCgPANzC z?Fv6);grB+eiX-hNK*KpVVES=>xcG%P*WyVCdsdgCjGSZpomCF887!a+M5+@y^zu= zRs6f|Hzyr#)ip~I`|rT#{*{oFjX_cOGMz>lyReWm-J5k-BO zvR+<_&MR+&&W2%&-_Y1mE2Kp%-kgqdfxVIRA2eQtJ$z~Uy?5cYNiELTTJl}XyVv6z ztqZR()xi7=lP|S;NQ9~BOTX%qc-E=P2%H`8HzZ$`^d|xFOvkl^*+#_FTHDD3MymLpUD6;g1=_med zQA9Dl2BBpvVf~u7Ayfm=ff0mQM!U6y8T!|C)-fSVq`GF)EpM;;NVX*rVgCOM} zi+aZmNwgZ|eYNRcclAZcqKny-HWe8bS#;LHc)j=M8?$v9HLF{MGWN=}(_9P@$J-oz z(})-AZOc7}t%cnCn|`9TEjNlx0ViRG=0_<^rRXRK}gZ5gbH(!T#B1(DyRf)8RJs zi}&Cr{YS3iTEOZ)WEdxOK^=!Hy(GuSZ^WQRalNZ8LIm>cw3l7p4G*<=Z4al=l`rPY z2p-+!&FEe($nOr@9eoWnLK!b8mq-2#mpNPD;3rIe`Ul-n=#Vg2zK_cX7eG_5gki4Io{pW2676 zvC82k2wltTfPF1$8L;e1xSExL+ZcQK##mF|#eUJW)F>kV|+zD z*m7^|1_}U_+arPH1L)vODIp>}Hpy%Un5(i^C;tZ!j6ESroxy%XU*`!=p{mIEQmi1e zWa6Zdqho~kprQ`I%dA+``Htp6!A^BG3;ST?B}Pr@rid4uCp<&`s{7pb{FPlgvHp5_ zWhlBi{!z;}qN01OJw<{E{|?D9B?nwTAK4&1#&6}!{m#twZ_T=}J7uSql$;fgBglq> zhV*K6;AgxSU6x0O%u;nS@ggyYJRo)RneKO+-&X;`z6^uS3;e-m+6(AE#u>sryLXfT0n#Bm5F}Rf zS+<6hEn9ucB((~9x{Sq8`FCA)z&{J`JufS8Zm?nBmES;a@Gu7eHf;AdL&204HWT=T zwA-4K7)kCj>&)ow2!4}%n; zUn?tkcw|P4IVtp)P6jS0Pum6#dPh&5e_yEjIqc%6A&G}y9wL-~wLThN55DEqHni^^ zarK_!Y2}a8LK~fr1+wzrrw8gM*WarVJl`b2u0rqb3g`ABnu*DaX z7A})&9`nBE`ANJ}MAV6sDd)tJZGZ=+@{#BKOkTu~J<#w_`ng}Nge{&Quvkta9*eP- z8gsUSk?25uuJRi<148ATVpgoIq{3W+hL!e*cwKy&Fq_vV717G~^3oIen_b4Gb^Ym$4{l-*ch$B$#MEP|+9CDeLG(qHg1Nw!1!NlPHO zziI=V+}nrX-CS4J?)ZpuZ@iz4k7)XIWnlit`;Tv0+RgaC?YjT!_+u3Rnu{dkK&R7# z4nDLwX0jw}Ks?pO#~(Y2NNp1$jh<+I?EjYuDg?x|i+Emk6^O%uT^IsMB9Mep*awO8 z2SiVwh(Et1sbCDSRJERocb5~{}u@iy}7 zG0?U)z7Y;GtLo?{8giX+hA!c z=Q4xi7>J!#7*~b?-{Hwp9JmI9_?>v|$`~}EKD2!)aTkCHPZh;-&Z`3jtB4s6JCM?! z$k@@to;0vB3bsW=7L&prtD!<-F3txDf79cAkEy@0Fb#m9L^?cWBD_WdX>{{UC`D+D z|L7*}tOi|h349Pw$_XYzqeLEZlP!j3oaV>HIp77S*LY)#<~i zw;lV1ovA-JU5^pHcx4TeXFTX*l}Uq+oSpBaxcifLu<(>j^b*m3xj^JYt91+$-YNod zGEzKHLV;_DzYv8j&=B9)CLAL2M@(u-ekv^WeA>IzBRi-06shzbx4a)xk~a7sB;qx3 z5cgT&#nlGd9SZnju#|&OATmzmhoKF2luRCiPyUoR(IqwN52g4c*NBKE2BOdv*@E@@ z-6bxn2p1UObtJ(LpFqAN%YFTFHm1=vzW}~RyXlaH912#>=6JD0{9Q01OeGmy5&R3o zV1tcl@5@ZC58fdolBn`Hvg-_vkBdXHM3AdAzISxwR}sOEE{{7WvJuRvDNH_D1M!E5 zh*2_bzi{hUD{?W$-cdDdg@LGWKlya$dSN{B1%QZTdbyW?aYbj&LIl<4H4NCW+P82j z4jd%{sVzpnrHd0K;&{lc4n6qaDD0|6?&qP%j}4LN!rZ?@SNFlXNkO?>0gZ|nlZu~> zI-fPJ@R{U>^ymFcPylp$FMhpDi>nA2k0g2A1Ub@CeKZ04lRLO_S67fkxIcLAP+@rbU%ZB#mR>ysB);(vU5{d0Kn41Xvt9lDg=9SU>!r?h3-Qv2dGF zNWma~;b2#xpmvTl&c0aSNvNSKvO1{t7YSi>NzJtZp<|R>PL%Y5YN$SfZIF|NWr1=;P!r;kShjE~ z^pbBXlF^|V{ivk9E_jy#zxGJn80Rt<6St0qta1<$3^?~69sXE6yhgpWd?@NY;AT^I zDX<3oomhJ@0@*HI{~`vd?2Dx~-wDtOFVfBFSC4yO*!+touHA{8rtulmvLf2}ppu|N zKb*sr%ziM?>O@co9r2faN9C8zmUP9Y{kiRuylzMVP+s7=@{5vPWa$<2pSkSt z%HN5VI~lqEH0a!>JQ-b@mF5E*=_r2V0;ml9+B>@BSDFDG@{A2%VUyfWm@YD_WQ;N9 zyq6;MGs7Z6tO8 zUVmc{RpeR~0HVwH)Qgz5s*%Lx`0R>o7kabF33mI*kI)=|8jd7x@E(Rd3w_b5`OH|d zApMfM<6RH?vaTn5PoCd3$C$4$1fJ=rE8Oz9Q~>7!kmYp2D3PYW0C)sluwwh(Ty|bb z@D-6q?cI0ugas=N#qTW;?y-~3ku)n84_sMKxLXBLA$?jS9rtGBiA6pzK!kDE$CeHk*Pr#a#85V&V7%8i2#(V~0#cjzD#!lbx~# z+OP>?3bO4}qC#f3sl%nPt3IGtw07f5Pt#L1kU1I>PTH@s;ZYcm*CPJFO{Aq+-CVk6 z_9*YZiipAm5JjJ95h+L@{}(;P!>{}bc8DXX(sJp23O~}ld(?0Mrih%FF~(vCbK2$> z?8+0q)H;MeJw=DeFEQDf)_@$v7N4(%Zn6=ZMQ|AsJmv+0*d>0&tTd%Kg?hKNBNJpM z$3!R^*KENKo&Ysnkh-~cpfjfXKhd&MVF>Kb-7l?owdUalUglg3;;#ro)RjN{x!W3f z81UO*fpkRa1ncoHNgTP4+Xf!#QW;U#E?9k>_gc0V7-sHYR$Wckni?a)WND0-7z z9`nWXjynopv!BPOnd*vPt=_{dP2YR_kUwV0@QU6O3zpyx~4amtl`q{i#Zyh@v)F#2&W#&!~q@67nC95y#2% z-eD@j5z}nJzbcXkR^UpP;UTTZ1wTSRW8S`_X@jSIOdqy`ZtHgK-49%R)9ZBq@bii% zYtJih^cp-=jB$9eH`P10*jx8%`jc`_1zu zp_j-+V%TCd$Rq!7I*urXE%lJy9)y)C*HwJ!jq=UlH5D*t)b-8a7pvjNKve}3o4%{wCY(ut@ zgV8>G@$IcwlF#Z8QXimGH~7lw1q==EHMW*IQDB;5Z* zAgV!zYS;*=(+TzO#w$$+OZP;C?hdN(gmn&NjWZY+-hCQA8FZ~ZK4+->?$F3IESf2l zJP}<^zcEg-a2VyiE*4IV67FYTm?a6w3eGy zUeTlF+jRNGqxH($=;=GBdhYDoJhA+5#wx~~4Qt-_QN zREHsh=y4k9^!LwOM z;k&`rYR2E@Fk^G{f)zG=$2QUMEp&DtK95uRf_b}OD{+DhpJPlRrx4$wtU20mllCM`>U4NB_F=!#bL0MSgVmfyk|&w5FlzGN54^ z(ytW$4hNrZMR-k=w@pHSFs^T442|B+*Y6?UV?@4>!r!=fhAV1gN8wz7K*a0QB!PiU z#BS#pDeTl9EE<2!00&k@=FhefR$LIh-Uy|C@Vr(L%Gsr=C+0pC;Oias?|Js=fM~Hu z_^E#r$x4$vI@`M7u3B+f{7K{n4Zd~_emNdF5hx~S7lUPAdQ}RO!Fs_Qg~HvD--xE4 z4uIOpQroSF*w&R~Q`mJbG7~BR`P&KAFK5 zqxb0@$mQ=yQ4JA44r1x*e*HLdA0V<)pyHtO>WsNLuFN z2Ec7k1X4L)cFZv6G?ymsn@p{l( zk-MAudaQ>H_G;#Q1MeE%oNlD4QO5BNTW2ONJHGo0E}egrmbR6dr_yWZ&YCC?XLtmE}#?b3bQ0+~5| zF{TPKCGKW*&t1m#L&tj$I-e|38K(NLX=!z~n{GtaJmAAWrX z#VWSU`B25ucu2x6SElT^4&^9Sq&n1n4k&HdzU)rNppc--N~pFf_l8 z^+VhBECS-F#~4%CDdoH^)WBTl$xV-&I)u-WE&2WEpQY#Pk=OM%?NtgrE;t;_cjkiy zm4=7h)~JIWgyvT`58if}`2&WWuE@7}nni{Lm&QET$&iaGXky(f$Yv|uKL1)rtt^t4 zErsY6{75gm(3LNc7hLSmd4Vr$Dsa@ilUQHao{+G}y=`+hc1!GWGb-e{m08_eDec6S z#oIwI?E@4sTg00!SDQ0|*IbHk*O!Kvwy9R;S!K65oW8~Xwnb^xd+@d=UGKbw{NeNU z9=gZp@r4&(L)DOSDRSZM>J2S5KKTia%F zQ4KI~UOlJ`I^eBFZXJ*&e){(af=&OLUN)54rtD~j5e%S(6u2&UfGL2*+y0EOyyst< zTbHEWvQwv}BKuu0mPMwUc-W>_R;8&ubUSyGTY`1j4*#M_1%g&?6E9mo4@u~@id4Py zbS(I+#@e!1JtoID{0xM|)XZ(}$If3v8F+UW*NZkuaZt<9^ytLi< z+0$mf_b!eSj_N{DUf6$Ik}9SeS(0wUtFyD;c9$Jdgu8dHA8|#I$f(&q4uybnCQd9T)i-J z(taPG_{IJ)oB4ZR$@c-!?h^Bif67h2xl0;7FC3+Q<-I$RnAxR`{@2tiC4hb~y{JF8ia zRAr~eIZc0ER5nrhlouuCtRyS@xMFwu+l{k1C+FNc?i#)w^QBRhGYdMZjRS_SXeiY# zZ+0pEef1+ZVeO+}@)lj{keE#_A@HAeqJwkDW&vnU#n~8&yBWJl^U<$W`rcJ5xmTm` ztq}zE1@q7~0(xJl_TW(?2P3by_Am98oE$etD3HVFqhRHS)lyXzM!pr)#1=#s@4h(x z%kf6Tma5*luk9yYewN1H4LR~S+~F)YJF4VOS&gB^P8q08zWaIo)CL?-#)T@=L5Bv15zv2#nYJF)-7jaX4<)(ge7I1x zbtlJ!)0TI61ys8eHl)&gX5{!^ zO=68)Jl~K$;K!4SjW89x;9A|nKOT*?p3Uxc5uSBTZg)dG?`{`rtYn@5VgJX`o%l2T zKL8xxY_?&{-CQ$Qj?mo0u$ePQbD!1RM`&`*QEfIhlADmqol25ax;LX%q2nydUr5`KklLv31SMzQ@WU=IHw|uHSBu_lH~d=tL*|+N z%1q7C+9|TWCZaLMNXma$b|S|cQM^^}RV7_Wfago({QH`wb17uaX4f6T2RfB#b-;>p z^Z4C>BNd!40cO!b?12L-`-w^rXZUH1Xa0n4twBEg23+s(;zOC{HfgO zIfdr?naA8^N6O!S-Tl1o?B#)Ug$d)QbMi1)O2od%KRQvrEzX+YU2v~79u~P_Bj4Rv z@_DLJc4Ui^kw{`{zQHe4`8W4ZCCf^oCQ7O0k2*|(3s3$eMIz*sTGfQBsWo4kUhV<3 zJhk)w_KDgA%NztLwJWU^+_0TH9j+n0EqXw*Tc%9(VlC%gayR2lI$5^$wi|fb?3l&9 zh>E5d)M`K2SM*MP{N#daP^;c<6A%Q`1 z?l*sskNd6T3y+T5AU{9QmX0JvY60m|OSH$faAQPbo2(9QoF}vqPg%=0C(fN^&@EmW ziP2u{pX$oIQ3+n9WTnqfp~iT&n_NjjF&MgE1l02c%Ge4Gy{+XhyG~8|EZi)0Z@Mjl z>=%5pdD^G3-NfRnG>9Bti&E=@r*=h@7dJOB^z^tu^qp&^S$raDEf|V5T(`0RPL>u> z`lsi(QmOGGE2TJhw{trXXf%<#@0dHB++3EO_iwBgoUbz7TzkwuP-~Ka$n_*X zGMMnht<07Dvv@lgzQi;?elOC0d;zuZ-9GH334HIAZfG@s%jxjWYHm*y-XH{MzClN% zwXxnL?yPz@nWUEaxu^@=te4I)i{n;K&-datsz69-Svvf z3>}d>v!FTSM%ag3EzOO7i26-)`DOd^T*ji7s@C=Px9i=%w0G)YYvcBYu`k;cv=>l6 z&_n-pdqq5?S!sA^>kDxU4kUwrCz}n;M6&#mw@)wGCX=9{RnT2~pusc_RDW+Il0$)k z&>)*|m3xIV553nOp4dlEoME;9F#eNRsVoplsAH{NhL#JOFmBKvJ*@o8(CK)VZfn~) zw|oO6^jJSDcibkIbTY&jksf)LfMl%=v(oyFd_2UGhFMhFLzm0vH%Y9O>jf!hZ4JeA z_x=ZiU+za4K*NFHf+julft$G$7Ftzkth!W~M{alX0aFFgMC#cc)NaL0RK8E|+GV>W ziv0^p;hGlI7|{EK0?ngBjuT~(f`Z>F#BmepWATn-?jmRaYtj!i-XNLIe-P2>G{LRp zP$6FCvYzCE0GjBIV7cm7WUvGdbQ28=h909retc07!idg&ZH8|gB}+IqRMrmL=C9|Z zt)IUK12xDyQ?LMxrn2;zqUs_;6h2hj5Sv4m%+})|o^&N)2mYOest>ZVXxFspK&z!f zoqMcIvW<+tD#>u~Z0~^ayeldg=!@b0k?7O}i2OueQ!Y0mEf;+cbwkCM*DOiy;1~)? zgz9+3*+l98iYgfXLL)T!VFerLjAki^(F5|(uT`QWg2s{Ff=rmhS##+4fWdblUx6lSwCGq(bGv|StoYngUgGwh;PzL{ z{Vv|El6*zGAM6J!ST2@||5GW`dqoDPJ$8v+ApfK&ysj7K{t@W>Q}1doTYPr80to|W z_Oo*03&#YS0Y30l=` zXURc8<)4Z!vhjFU6#cM#!;tjKwLkh9pJlLv6*E}D_;^{9N`Etb`_Xp@m8W63=I@a%8BN$WY6iJ_flKr2tn0&Dx zk9HtGmp`L(PxfEQ8{4Uy-@bgE#@rVj?Mcfsp8n19MvGow>;f@{httLS#_z?9UsLV@ z9g%i88!f6n4|J#CG6kX@}SPNhiU<*NF@8*CRWal zggERfp>*v8lIgv)W9Tx*)=uqEhISmLHK}v?FJN(Ee2Fm zC7OJXl`&qJQ_iXmhao$6pfso_8u%;}XcN!M+bVoscUl=%pu-fEq<(TUHR zX4Dr2Js65n(7r2-6Bv-0w5Ce4KSn^uahL%drcJPQ)Q#GiqYPI}fqxGehdrk%(_+IG zx7lJP+jZ~hWSsY5dh;2KNs#dsky7)SbPhDft#DxQ%q_IACzS)usp>5-4?0sEsxT_`*6hEP|2;h*2#6eZ>u+-pYZ*>nHWnHB~CRuF&|UH<+2 zqQAdO4HMU&U%~Tt`xls!F}t?{>4GT;(DTF49u@WHccWQ!H!)h_P8lvx+nZ}V`8tTtt>I%K#U@QFVe|ILW zl569yGdw?Z?KrS`Y?eFT;P4Gbp9SN*pV&T0kSYh{=_cyc1Ijxv=B*_fuLe%?DykV` zY*aza@L^VXd(|e!@qa0fu^F&nB>5?iC3h4uwC7O=b{HPr~IF;yv5@~ z+kZaa%m*g(p;>$o+r2h}!?MmZ%WaydqR}J9?GK`X(z55%_|SAtNZbTykWv^nM3<+4 zf}TNk7j(y#vvN7CqX1TJlP?@{XO;uWs)IhShGxbW_No=tc(SN==x-D$yub zKc!B$isrqoWi^?h>g2U68i5GZbU8 zgIQ#Lli_U<3ig&a9?Jd#nY|R_isPrySZQu$+JZu=9xGu8lult~2FGSKO&q$EpLZ7$ zPj-Et&Wc4^4O z&2#^RArsnOFTg`_?71A|=j>o;v_O%EW%<}IECQtL+*nyl;2mC-y1$w@;4ntzK z_s{LU$Vel_wki@A!o%h`^|Fp7kqe{6PLQmZAjBeycS*7t}a z3#Vr?FF8&wK`uIvPY2#6=&^iudr@Ifs%McxUE#B@;WO6??%fnkC(UQ0h0tr6wfHSa z$L`OWb&y$!KGMO@zVE`LKVLaSafV}_N@FWf^8 zSG@Tgwo-VahxM2INbVryLnqLa4b^T;8l=T(+;j(j-g3f{;d)tE{*rawgG5M2?jyD9}XH$$Y3! zdmtXNkbymO)GI#~yXfTIA;twBP#aSSc9R9n=L8otw^f|Y7DA7fGm*i-qk`zUh`S+E zPyXdX2e($FlFPpQU^AtrsT}M*{d^1zo-|JQD_~J*9+|mNXEx9l`}AlDeHFVXlgo57 zK9a{ib?8q1!(6Du1&gnDp()y_Uu6dM0%9KzLn-}p*MmjN*pOVZ9A200kMva+fzsFb7!D@Ep-d@3OW-SJ9#q^ z@EW=u_spX(?1$(0%2M+`ma?Egx#SBu;OK{Pd8GPxxmebzIi&Z_*MWyqR#?&H?2+EW zysb>iA;&Dt_nLklZba#AtkwE3D=Gf#>^R}8pD>j>>AnztZ7ZM|y!)K*-##eK0&P(9pl)%Y` z-||SkCI0rlp9qhC5DxCx%<+Yc3p)d0%WvxL38`tlnux|YXvg)UuB?pYKZV@~lNU0+ zE}r_T+x*Dy-S42iEZ6kp0Y&Is2rzmEDls`g8H1)FZ_RdY6D0m7@r!YX2C@Zddk#h3 zCvJ$pOY`03Y3Z7Rc==%G&yRgUEkyd^L#eFXa#63oq8&8Xzu!TXdOfCJM0Sa}a`^~2 zv``N53F#)Dv2}!=Hbp_BP-tLa9V-tnyal#mWVk`Q(7>c|7VI>omgBB^L)3-?(ynd4 zUSyQgxt59+wd-Lfp+B3SJFOsHmJ<(+?l+Gdf0W*@oYJIw^~Geu%=}Mvlo`oBr@zoc z@a*XLgLb(%8mDmV+%5M+?c~d+uPVWHrPLiuwh-)dSzG->TfeTlAv3o5>sy~F3TUJ| z89uE0O-70(3``onwOZ`Pa(?<%;&jVL;wfD2ZvE#*hwdlWX&*Rw`l@Q3ri0c#&v}>W z8f9T*$%{BC_WpC4=YM++ET}xlnREPnZScy$`_$UddCtb(_YSy-H@GSmB8*t!%xS#- zxci)KBEPa=KqhMHe$H8vUPI8gcfua|*jFE}*J>6i1>cOeIFmIN$YZ%*>be~Ft+9(x z+3EFBQPvEZpj&pj9#i>r_N1$r>oetxABPTSU43I3&0mtg81eMneM<54e_=0+ zg74+N^b9mPJr;f`X0*}hi@bc~DesN7kdxe27n#%chhIy*PN*|F^6QNb@8n({W`5EE zqwP0s-Q3yiYWi*F$0%AOBcQq9fX+^Xe7i3S8l=3AVcTwd65k}>ns!5Tx~OoHuIs**t9q9iCb}YPZ}JS*Vm5-MZhQ zC)!`bSuy5%egPgQ3*XD_YDHKIv5Eemy{E45hS3beAEk+7(%DUhKg0b&@QIz1qo!uz zNQTj5YIbvr!fv3G)mER}e%!2f72MGKZ0tVFO?Dc>b`XXvK|x}-;_Z660KxXMp+if- z+dZv?bY&eNWY2k{7iuQizx|zTCfl`6YL>YX$L!wAS2)QEs~HH}-od3u=G$Auk~-%Z zuEbvc%=Rgx2Vl^!!tib%qSfEQD32r6fL#a=1x2o?_hI8urqa^N5BM47IgC4Q%Kf>D z)`ty01WG+q0c1Ei`@G!+Bkebhdmb(e+p|0a8q?Njoa9h{%c<#n8lS z9~4tf)*Rnjw{^<6nF-ega-~H=ZJ9#DGrPfMEU`4km@U6wL(BB%R@JiyeWqs+HUWmO z59`%(qz~v$UYq~Fi;6(Wqxh%nmq+fz7hrK_q#c&$`w07sYS+zz8;)mu#AlXxrAi5} z)%pbtxr6<4EUgD3rXbND2n4>oXT)wjKA$L)*k#tPyazxB!57kXWRCBxw<&?()@TEz z-v9%=L!TB~rFLzo^|#{aBcI;cy=99Hif8KGD(&)?r%Txn#HoRHEiIarCL_2#`5P~; zk{BM5**pz3JXYgvG&g#YB>BdcUb)Zkc3(dJ+fsz@?bx0w1lDO@cfut$T&tn&RL1px z$9{fd#hC~@l>__oF{iL}=w$0TIt>r~(4+;Iy9kteYI6G)76@&_KepaY$Va+;Q~zD} z{>Q-!%9+8MqI+n-a6`ITNV$Nt+Rrj42?laz268?W1H~X3%FpqO=3n?oEjJDWiKSVT?QpPHgWbwF&?PSXcDGsb|JsR%}s>IEjcGHW?_4cT3kyt|I zND>oC(@@)nv3l|8ZBI&gl9APIF2=0-!|`YczH_Io;&aMXbuFT@)m1k%pjqqasOq1l z)B7U@=c&vAHf|hmCQ_gqIw$aXqYB2Y0c|*RH&xSZm3ivN&PNqSsCGHF_2vbpR? zJS`0iV3>6^i;4d;6^)38+Skf>A*nyiXGpG=f0;uh(uFf?l`pa9rxkMNJPs)&BF+ak z1AlkXWGAVGU4~2sh2M7Bo<4)WNyuMM;OyGOP60Bi5mcO}XuUQ8vm&G;!YHfsUu^Uz zy?Daue_Eoi_^vn%JzrCgLR{%oxe`emsuTN4vl!R4al?3^wHK7T&}TGFOv=vXS00j2 zM7&gmfV_{UnMHC5`_>a~y)Xo!va7Gy@lBd}HN*JaFDedyKEHl1V%0xjq-!4d0V3N; z0@3PNc5WcB)x8Dvmu>_=#d=wG`n*1nDgGI&J+06NMip~_2*5e60o9 z)>730laL1J-_x8qthOyEg!uQ1Nct}%MRe}Jl3xM;gr4yo?mac&|6=EMc_ERQTf80k zToxk7un~~KyZSNg8*j8!Hb70sOp8iR_~@36cZv+Sb#)3wQieQE$4lkQlt3@AWl`JZ zkPJ0hMy!ArBX!$Rp&tNoNpF#B#y@u8T+9D^Zxppr?p)?2=Xs1o1kLcFmh(QP%99qT z90AaYf-X|8?I`Me!opHNmdjIjd{yLWxg5(9&`Ye+RbO~(@YWDBmR3Ij3h&?`OQ)}YY9P8T)NI;MZE%(fSX`zYRc93 z#B3NLW*1>A_@Em*=t0~Qf!R5?BbW;Nqc#EKQ{m$;_*D`$i=Q7KiqKdHHa1 zPQvQ%QBebb>_hqHg#@Nzq?4GX6lzWYe0mrcj**sXd{DkVM|g}g)-6AGKic%? z29{iKRQUxmrH=lM_4>;DaN9Ry4Eqh?1BH{8YjdTs(md-y8f28J;l4BvQr`bSQosAm zfz_LLboVS3+D~&Iv)Z*$3s>%xvgR5iyP!28HGuGf){CgnfcHd45?eN8H6wovQ$KZukn(xK!pB1iuk<+zhIuj)EOZLJ5I7BS&0>oMUF zP1J1$nQnV1OIkpW#rhzWtLpSLB;z$gA2$?vYl6WQ^%BiMIEMI6ec% zF03Lbkv*SGyF0;|j2&T8oJq9Xavaw))+E#^%Ql^kc=kr_%9 zt^$pV86n!o6B8!!n?2r=Os@3?&%CE0b9U_V(5tS9(uOs0XEMZMtwA8qRbW51E;;Ee z`Px9~%$_-b0sGNn8_|N3uUuE@0-&>Jc-ZLkX<(4`n;q|zFoi5~rZDQlVN!11y7w8@ zSdhN|P{AZ;?k&i)zoq4#_q`f9>mHSX@KRd==z$%4FHJcNUev;&ncu6?jz7q?E}kf< z7g(s;;8a@yT&pgH2%Mwlf1*FCi6#k+%5Qny>8kL}7QR@WpMbX4^U;&D4D+rX5HnPU z(>MZr>mW4b$p_BiR#aVwhVNkmuD&@rZnCfH1F@-(h}CB30O-SZp0A_d1j{h?mF#*L zd>}2x3)#l7=bYDlML!+^%ANy4HY4GbreXO-<2fZ$IMK3ah!X4u=f7pHd+4S=UhL#q zEK0uca#9;Cv(k+m@|xM496y-U|aE1a_dsj zhv3Tg7G!wT1~K%~2fGa(#;sD#v%zfST|hiIGa=~jXVkYR-cxmDYjd=EebEH@BApd= zQ>>!lq}o_Jz+&TE*BVW;pBLR36S~a10L$nnTtoaO0GSMNOpS_cPQuCH_rWr=kF~lkmE?1#IPmic;<~YcfJzMn>Z~%0cb$kmalxTT(|aGk$uCW zImA1c?PBIQ&z62&)aQG7jkELV;+GiqlRO(Z@yR+zYep>0J2vJHHns_%&Nd}Pr?YoYG9DV?-xZnd!wa68U;S<+~;lt5Z@v_X1QOcQ(h8|}Z#JLCkI z?_{Fo^>C_sV-{6oYSCsoZT{Is%E3h28KOP=5RS$}uf074lWPcMPj2fxbjxSNoKouK z*<-yLa+pb2-SpZQ2H@GSapf@2Sces!-6BJ0P1!rP#5L6d=6m3XV?q-J{_UQoUe`Hh$m4j#I3NQ zSQ>G_APJl9_-BgljN^r879E&>cVPA1?B92E@cT84)O1d&KP4{p+W7o&n3m9;ip&PPY z@-z1vj5Erend$gW=5j#6!6hZB+8rf09x`MlTmo4qsYxY;;9$dAYwtWTU=G1Ggd2f9I~k*}ei_@2P9S>@=@sc)72iHZ+6`rEVBp?K>sL* zG~t~*wU>LoFJQi+!J$=6&kBVFehy@R{t@~P94;q~J+~1`dd=~V^a$n{m3x$4}rsZy*Hi2*H8vep$GxMriAo*;Pq?!{rj1G zm^Z_YLR?(pS+u$6b}n^tb)|*%E&{1J!SM^2Tc+EdOtr}u=J9~kCeF0{E1}Zk4+llw zA#qbIs(SCK`T}kMJ^;jdtEC424V6wN3TAr z_@OWXG#{L^l=dgRASRZ6wgxOD!xpT|y?%Nrn?5LQ72U7qY4Ymr=~rygWha!d5;XPq zNN}y+_v}5R!7}?7fOVca>!y^em}L<061~aWhsP-qcw(t>S65o07Zy#4F8Rc6?Fy3q&;{A}ODx(2hQZ%@x&{#Piv+=h3zY0#X!hyjg?lR&Jc zgfsF%w&AU*t)-+uzS@`doaO^y|>7&YH|L z_46lJc)3eC$6@m9(+~5}=0t=2;9Z?O{iplXv%%Km-ZK6`ea?V3Chg7h6u47~?Y-;N zgm*?^bu9t_D!LTM9B4i$g>3^tEs_BLDkil(h#4XYY`xPRtL9Y=CST^(z5S~p z>m7<6AN3G6%0Z@RpF4=hCpmgg${;Bhf-hhHw??z3ez61Z!1@F2ic6cgvffFK*57gQ zruTWvLB}@DjvwF39QyjmN4d0#gxa!sY4EuE0 z00*z`;da)0Dt$~?14!FZLR%TOqymy4N}o zZ)>#Wt!=h{U2AnkQw47q3PCO<-d~qzB?1=Ihm%Mbjk zb!+T(G4jFcY*?U{ONqk8`47W4TQtyKb^W2sZN{29E&-7rN4AABM(~5%%d?I$tuCju z)q^~vJg$hBC@@Cfo?(eWU-ia`jv1XssGYu@?=X-4WL2+pyY1C%ZV;63p!)gu4ZpsY zN5z=M@9h$Pi|Xa6$CHO>75OjiPP~Y0`oLX!YZr!5x{xV%?u{~Dw zVv_c`T=qqR#^itcnrg=$Ts+mCyy5eyPrE;!bv}I!-CdggU8oV~)K}RrqItBN2D~)l z`$B6dnN+MHU%T>|dFurDk|sQD^U3bQJ>8V=TJ-;Xw9X!DD5@TB%TdFeVTsWzN|NL#u1Ne3}}+Z7ePR033_F4ynH zAkQT{ZP4BrxN<&?hMu@bUZFphGSx7@pq`}-l!O=$Jc(1Y2sd;*m9YV25&w)wdgB7) ztEFHmo39I@fkJE9vw15|;_73B^oV-*GhCoC@;eE7K7E8@Vqt@k->;aQ>j6|bHe>yA zCg>0Iw_JM|M|NHov2FGS24c#p(?I2~I$qJIWD@Ys`{9-l11Y zp$@*tdDqN@mVy`bAV)V$T&LeT%EAkyXIh~1N8y)>9-LVI-Km!PC0}|Z zAj|6HHDqADJnHCx$!p0;N{=>b{kamW@#%M^3vTh;nF;ayvY5K=W5eW=&z`1AWur$_ zF5f{|%{(tnWooG|y z4X=X9Yf_m>49)efDAk2{SNkQCbKe1QwO@7nB`K6<_#B<+Dl2Qf6WaXPGnz(U3Zp^% z(Fs5)rLWnKvCPMkm=PUF8^+DLp9Drq^H9H*3Rh}hi2Xw|5>8!nvhlrjC#PpY^(yG~ z$w+gpzAlan)?k4BXabcfKSG9`dBphWXqLei5>-F-IFo5jg--$dsrmzQwf}KJcK22@ z&K-3{PZ3m};quEaZm8}#0P(treBdS`~JguzFov_7$nD zcQQ`=XU1~5se`?$uu5q%_<+s}L8LQ@s)kQo&7@)KLEL?TX3-~Yjgh74Xt*k{gl^c- zVwk5fjM@ZCOSMHH^7JkiyV|(gt)=6+_fDaHmOr*0RrF>m$r|A)Jnj+!5yJd>V7+12 zoxf8)Wyj^)G)|SuQO3piAEMO%@S*nOsl;New#rWq%YKtvMy2sWIpOaCeru8^x)w^( z355>Jgw6zo2<0Dqs8>KDg3=F!2{pM4>&@$BC)S8+eUYrI9W~6hffaRwE048L1)ATz zfl%0*akX6{4fS@>kpFsElWlT^M>@?_K|2#M8X21P7o`3R*;diNcIt4udHZ(1t91$% zNz}Jc|Ize1d!D&ah_<(R#nGe8Wg+fQ#J@BAarjm+m92ZPB0lqz3ZfG z{#HnSIC}$fn&Vp5BF;$Kh*BRGXuzZA%Bq*69QEG1I+Oz$S~nKd-LI)(|29hvEqSM5 z@r9oCp$N*oR`s@~3h%&mMDDn*t_9lJK>%bc&uF0jx)r89n=5-_O^1$>47_-WMn}T4 zvabJhwcxxoeY7;{Mn(#uWWQI4Z1{jX7X8RJwqYi>F-m$UvEk$M%2UcB16R@}Aa-kX z-(vzE>f<!B~& zn^gWILn}SDVQlH__K$*PLNX!p!*7Q2JucU@|BUaq{9DW^Vp7ew)WoAnA#xnA1oD1K zDbzGTX(=MnPuT8r{_N7H+|3X!=?jAMgd>^ib4E><0>VitK$k|#|rzlCX@B$c-lb7-OlBbd{LYcyFt-^HqbqU5~mjTjsTw5Ma@ z)Cof^1ijo@*T&Ka9qjno^F-lpmuSJ+U%SP~m;ysX!rI*@flHV5Y@%}DrAML}QW>u= z173Iw#RGdH6@Es+r7z)&V+`-ByrMuRPX6>YYnuP&^qx&W6A1R?JIZa&Q&`@gO6px1 zvWYZjgO3OI*}@l;-|}5BOBnWvV9iVDi;lX{&9K6FW3gB_QA7SJ7`>xETsW7{kd+B6QF-K_GUS>+N}F+b57!rir6 zrqV)KeKY#o-m#^Wr}Ad?kYO3Jo1oI$tmMgso0mYH_A1Ags&sG_S7?Sgi06< zn!V;P5>Rm&e;v$#0_eLg5k${NC=Ad%1&K^gVCxFe^&a?Xsf)~jlnNOLcLOSl04*v3 ze-}rcRYjnF8l8y(mG5-5S5FVpVif*M`PZf+rcF>ZZXQkIN!DrrgQOMBHUE*D<;G*Q z$v{Q&)#|mT`I{PI6D_befVFajObAfAyL{7-fSB!(>*iRlaTGfUqOCy1P-DK$obm&% zic`7FO=*}7SE+x$^1U)~(Y?P$rDZA*ipCmdv=7o@sS4x>Sw0iJviC!8gpy4&BuWtT zivHGLZ*|{(#SkE3yd5G!-{o7T(neR96c9)Zd566lE>}0qK_Y%fguwgd6Vq3Y*c2%= z5kxO?74c9bc)LMUb7P6lzhDBiy;Z6osCtJW1M$JwXl#+`+X7FyO5pl#3>4_>>Nxi; zknnd|6o%q{>P%Qf$!cnu9?JV>PvK}DivFgoX>3?oRI>QHxWl9_dd+tpuO||2C<~pB z{Qh4|NFo46#cR8ly7>AU>wVKo?!|;hB}$F_ax=B51n9IMX{!Vnv_wKL#Ax}*8km1+ zZ_zXeJbK+t9Fke7n<}ecucwpR1UuLJR&@|}(AP|FzroMa>m@tFAar+>K=15xeGR5( zA^^gFu3bO4ve}(b3fU7NYix0NPZat4Q&TZPq?U*oMAJ}ctTs%j?%h39d7X^jTrTL9 z>VoxD?hYw{%9>#&pWDNv9kCZsff~;y;by0Mt!`GDp3&yJRFwh-^}c>E^)c14xK8YD zQpL2KS}oAy;)5H?S6!;~Bz^>kzA&7d*P_zSYyeeW`4lwz8n1wMU+gvCZ{`7$Yo(zL zu-cFTHgoM7apt)#JC-0$bHq_<^SZ zq~8$KdkNNBPjy*-*AG@{O}ucctStKd+|>2Dbt?$wMpjw{p56BXC*dEM2oMOko!{H{ zmi1N}KEERMRR67kzR{$8@pJsyDx6NGbJ(P_LyGW|<`3t%YL~;4E=S~D)BIht`Y;r7 z&^Q;EZLXPXcmlpp!>+1jf|_9==hXNb^dbf-DRW=Xi>=;m}tRO4@uMThqX7j!wo6 zFWoeYkQ=Z8yxQNn!NmyGz>!wp@18XQ!mwL6T5%%Uw-v&90pX8p!sGhddM_wZxuOm? z!e37vNZoMjjZp0XD)EiO-YXpXF%|qE;Lx9`LqY|zS%xQ>V*;8cBQ_WKn&u4(5h{v@ zVkRTB0wZ;6BQIAU*rON)-1IlAjk2ANa!`yW21dKqMte+0-|CaNgWu`JwfY81^a-M) z0%L#PFdR~dyx12TVi6a&X^hy6&93#`yY_WdQ@n*7<8Udy2rquT*0nw}dI%cini7|l zp7_in5s_)CBHsoBg?yVj6#reXA|tQF;*hUt(A6V=uf9JfZ-!Zq*o-N9$|UhjYmT*4 zn%&w=(dte76?5eE%_D@`Lx(IVSx<#xDKv>*v_y#jV!sUQZGt-rj^r-H+--{AbL(h8 zZH$sujGv;I=`XFoK=>f%=ny&W(`0aN6}x4_V!Ui1LB?$`;j6Q& z4N$?8u!bbclIZeJcPXe=5RD=fkjZ4XZqda05AAHN-`hL^wQ6ApwB5|2{o55~S))|VmG$SeR&tPaKviXW z%>1wPR+6CWp#a4`JwH)gl+nZ-)(R2oT#~zKNT2HY&h~PGA7EZ_`}QUh6v>j zpj_yrusgX&ytY~S=$$Jcl#gGq)UKR`HIcy|1tLw>P3;0m3I}XTgDaxX+?q|BaFl34 zOH^yfYBq~`tK4vnkk5%Y8+9w*ouE`rxS&$o%l6Q5W%WgZT$5St$xzkr z^dprGHEQN=^FWmH4a~AY1{ERgcKOnecF0IX@XRFbcEkNYxmWx3u=BZHgwcHA>mv%b z!tTqN7cN>2zEtVlHGfU~OFw*CGx63~osL*- zgtFp=QnbqY1(E)9045f+$r)yGQw-rr%9AdK&=qgLd4SF)sh=t#iJ z5yF|GlK_x700bk){7O99x-(YuGG^;xs($0eIYYVpz-bh;I1hfI{W7l2#@ zpe;1O@|J|SK*1gjk`(~NIRIrEe3b(}DuDE7XZh6v{OK>`nm};8h$^SiXy-ZAkbJln zx*M-hOBU06E3+FdK1eghF;vQWc z9$H#N<5QC9D-ba$`{%)yAx*3NM>il)bF|7j$okJryhYtv=1`?gM#>OsJ}w@R=r((4>4?TPMongr|+JiTAekt@3-C~&w1y91Ekts#$B zmmX}I7S&=Y%*mS1$xL!!E<1Zbx6gSTLZAq8(dvl7rZiEa#2eb0BxehX9t(4kU^hw0 z6Xbl~%WmM|G<0TBlZbRPSc(R?c>(|<1LSv>IJf{uD@0F(yk-R001Yzu_uMZ_#8OQJ zCKweH0MG#O1`Z6DAM-F^Dnt#vPnv_Lae#7J`{XMI#*3;>NNdsjMY zfK4K`eO29MG|P|{zLP~+d+Q68F;#!l>YPrsyE=1%h0ohQ%OdNA@*%x`+Vc)*YD!>z zJ+oA2UnSD+dDUXXpms{icVwTql8J931zFI^^2bE?Kn_%FEX6rh>S!ps+rYvfq*d?s zX^D>g=!DF4Tz6C~k#ABCP%GB9wro**=v};YO|{;Xd1i1K)vX^^cD z=bs*WvWqKPWq9@SZUtcE&-0#m>0<@HFZ9pjydpK`0Ysa+E8YxgtK+u5k?>SuwV$)@ zO>kAQj`vzquq-XO(lxST;)cA_=@8Q=S|ylBp-XC%H4|j@r&^8}E}a@7X3%lKmuUTm z_CqzjWPR5G7Ntf$szk_+5i>k^wpI{;PnU~SFkL5C>69P?S|d*yB?O%CGIiG~^6@tR zP`S^hUZ>V{l-gd6@txHvjR+0VsV~p2-+lV9qjg7p*mVD)nj?2Ux7DRhKap1GMMl9D z9T#t(m&1=wjF^w=wV>-<>zf~IoenphQozF!6TF6<{A$f6+=!>N$8;hdnU3Q?UKhu3 za+0QGJQ$3=^vV&{OjUh)(lg6`a2%3^orj5@MCbF>vhGy^WZ~|q44Hhav3E(##c zkidYcEarZ4Ku7erIhwJXG0<~{J_C|p-bs9No0lRzkyXc%I3jE+SoW+>=@0{DXmnlV zlm$Gh%%-H;Y`@*+VC#~Db0Y(RU8f%twf`;~4CnEvW{F=D&D zm^Nm&O#VLaV4)52vH$(|$EfA{y{g4}?P)-%-FJ>%8LnnbPCOb9=at&A|NI*@bI0>L ze13(4cusq$41~3}wvW&W`DGF`YTf)^Zp2slXk1-FTCHMxXRd<=PjT-vHmFl z32}lMp9H62>SMeAWbS8>TT$PN5K?+{hkr%h%FckNr|TA(!krlX9PGUvKkh;CPHg>c zC)dfBBDo`l!kr1Fwo9qEspC-!S_X({d-)cmX%Td3+jVP&E1AB?b7mZsTa2FRSbD=Y z;cK}5_q!00Qv#CSyU($_uo{f2BNS~?ADukS?&B_d$^>`zSu_cxp99d zjY^-Age0vZ;XS>_=g*dwCU(70{mRrOoYD^QiRWraaRC}|Px0DHH`zo4uYyy#tUDb5X~bok5@2XgZh*R>{t zQ+b6bgP2DLo^B}jow`kTFOOZ(VDVe)DFudb0;O!=}^cY5Oka( z7Vp2HJk^OG)NaCvV_QVzkeo+N0+Uo3PoUPG`X{8DOgM5*#Q3h?2pCuZo#aNVQAOnq zNkYcCuc?}ZAA=x8ymVW3n}kM!+;2~j8@X<$Tuj^w?I$NBAI`R-){%p06w0Z*d&G;o zeVDlK>u}_Vwwv4icXm&GZn3*KN~?3qwv!sS^6Eh5CbS`k(x*GR3rO?l)?@9__;$yO zAo}cZxE^JJsoa!*cr*U+*A;qM^vqhi%&e8XFzRb0sIBFhGK$l<^-_EVOs!HRX@#g3>o%wTMx%_% z|BCAAX)cM^Yw5?*RfX8S30@~d(S;@@5_p!EbW1F!NV@Ubn7A5g{x3BU*rvFrA00|=ExSkOiOJNVzFA!4jK84Q^bMSsPINGn)1jZ zQcANSTt*tD9X6)*!(h>Hg#$P#)D0gZfFOQ;hhWS;<1v6uRbYK|NhdI%h$s>~%a4yQ z4J-m?(9lT?Frr>j*m}E(g9HWL-zPP|HOTNJCO@>fUI5DK*tDm6!FN2&zc?!+p< zhW2TcHUDhaQYk)fk}apfYonmipAw1*satZAC9|K*cuPy6TkT4{{8|u+??jsFh9B%0 zeMvm$QhwwoZcg282IuQT`k*OOeMVmM4zh3^DmN5)?L_G_-Xl@AoEo;d;p5%5Ue8aZ z_=XfIV~8z{mm2j;G)}&pUJ^;L1&dcmqA%6-8tEa}j5oS--0CG!<$8mso`bj*Gj2(I zZH96YNi@^|g}dF(T+ARc-G7uK{<4`mCy`%T_oP?+i!GZ_#Wtcf`7*K2OKoC-8)Z}~ zd8Xqt)zgoZb!pZ@Gz$O=npfvMX7`N~{$r!_4+JyR3Ow_bY>P_s&s{=GvHRy;1zzm< zDn9S;`hgvkX~)BTTy^feTIkky*YuOm+h(xCT4htjQTJNRdos=ZX~oi79_TO4$nzLj zDarH))88pB$oWu5I-C#kz%OYP&u&Fv<4ADj4iR^8<$3_&+9#sl6WDG{1;wnz27`l7 ztj6lQhX=|8p>2H$t0|T>E~e8GN7t=1)`JpU<+;ObT;nM2Fc&8Vm_`J93xEQ~*21_`(A5Dac%lwxa~>8?53%1#wIkS- z6Cf8np&1JpqisZ#0Md_O*W4$0G&=mG-x*mVz~%(-(!;ay5&V=04jjPhx`yCE!Z;*9 zQDa~mBn*Jr^3wRR5z)*u7I;woDgeP@pqPyN*huWdvmgQniHH2QhEC}~`HAOv53#@< zJ%9snf?&?agRLo@vV2L%931bqvE{`jGO3d1JF%g%*^h5}i^fQ6A5SX7mz~=Q>Twd@SlHRa+C(lVsNxQy?ix~t1kuLW z9geeKnM5fN3>4|?S7|8s??K$vmwpgAWr)WWnvvIoIn)VOZ<(&7W&=B1X@y%Jo(WqC z=1P{eQp_{^R1BUY`G&xB6mXmeOfE7`Pq77jJF#3D;NzEJ0pYkZ^2+ge@bGwYFV1)O zTJiVzD~MED8V#a=Xa6T?@j%N0>+EkI5VIQ0A+s%_KxF?$M014&DG#M2SjOw&IQOyW zl00zSr;3Adl*>}UZ#7?At3e?wC*$g(78w~Y3C zxXMr`_*YrVM49Y5MK*ca2KR=on21ng0H+UE&pYnh;q&0H2}+X$PN4|9UZwyZhbYlP zC}YgFm3AuhOH1%REY45x#YNKQP`YAN$gq&b%9(Acf;t`KZKoZSRG!_nE)pilG2U2Qh<|B^>Qcg^|n8rp8 z`JoRPoHRQrb$b5JA(s7mT?q>Wd`VwG8^_@< zvMs%kTy3scIc^pN^eYMdig4w{cb%fRszbk^eoo=-E6lFE>Qe4qczeGtG33 zz$t6r;kxV3cijeFM8I|uIWuV@d}K%o@nSP6Pu8CUC|er) zJQ$mR=D_H%wVLH@~w~kk6ubLdb;g;H7m{}!%sz#3=luZQ7Gr-(kXn>R(2kqVlf)2;CC`xKq zPi0dwK!(Kgo9mn-IAl&UQ~-D3+J==A2APjT3KKwl0Bc`m8*PR;)TfMQHt6N$-o4oV zZ@=LWIcl}PQT;*F_I9OuGk9XW+;>u_+n~{^F8^yDJX0gurWoma9i{2V_lSh{)@=%K zwVEk!+VwX+z;fugLTZ||Qxz@30`5I8FaF&ezcJ6nLOUyy+DaK@b-ej62A7Q?w;t}w zsXIRJwzt1j{Lo)~A$IlaQLfg}q5SU-CFDE^#h2Cx{$oCM+}2uO7bmO+w#L z=RJ(f-_Sp~m4}}3i@I2G-RHIdYGja)=ZGqg6evNaT$0;Yfas47a%6uDWVLRX> zWw=a7FA}cklMR^!1GPtH-qBp%c~8TSw@0UVUNL-i9!me0?rAmM{yr-xB~#93IWS+j z>c!`t<&I9X;XwCkwu?A~6A?N}1apaiJekxm1hmr6u95&1eSfv(?bE0hWXZB^9|@U( zSCo(7dwPcb;qKF;^Bp};g|soqNet&J;{6O|OJf6YC=vA0GMi5pnDGP?um~w^y)zED z0av+4SyAOc7Z4-v-OmkXS8BHg*xaN^5N)-MX3 zjqZ%ji`>-#Igk)?3^uj4*@Fp8@%09~rAVx9P}8X>{8iLGlZ!%nNlbw(C2?6X*xEI@ zR^W|28Tmd}`^2U^D#!aAjRfwJe3j>dJW++GP~7F?MmXwVC04hKFusE1UK8Q|G#`IX zbmZjQWS>s(3?2QMI4GWCcuLXG>W%hhGuJQe=I)Z08t!;n>#?Kl@UVY zRQ3L;+HX?=m^TN`_1C*#Ad)TYun>eHes1Ri@sj{7_w?=5+r079-xB~{Vvj%`=rImC zjGIYR(zu^j6SfV>XPm$EY?eEzek2YgNCdDXVC)f4?#|Lae@S|YInA8oa;o8_J97Zp z6P^Gk$sw_MZg_%iXu|3@XkNG2<@3q;!-V;L23G=OK7wLiOwr?vm~N`Hdrz<0k=LnOCc24|qt`=U1k)*n2|v4b&Z z2W78IUmSIrxXM)mz)V3L*R_Yi>oVr9!SW59hP z;s$n&{u{bHdteQMHsU!I;lg&TO&f!XjT3bvz)PBuk#bM3luTr8t!scgaoN^x{v0~< zwy)_5XE=fl-+wX{+ps+K3>iOzm4s;&Vl2nmc6`B_bhbq>Q2yb}nH#l$**YVY6Hvpr zg76u9@|=g2G3hA`ry8hLtJa^NU#+>+%n)1(ev7?#ApxoQb{9K5+$KnT@6$J6L<$nn zq2=A)ZJR2a1de&~$ud(w(Ke6Cpl?{fAd)15n5d;=2x-?czbW$|vl?68@gyr=zn2B5 zlK|?kU@-^0LAOC~SV;FCpC|`L-yCb5^{$ohclYn0g=6QX7w+5VgdoCQaS5dTej%Z} zr%7WsR-)_R2xgY{z$axIa#`|p&6+xk_(tKKHjZvXhzC)Fe#@o@!0pZ@HyMxLpA zV-$A?_Bq{kK{ydr9*-7g$67hh9(%>JBHGhkkhsoryX?X(u81efy#`=H0a#X9@8gK7 z#p-VQ8n>uM4>><^lO2{Sa}Ot96?ISHrlh#si%=0!QvFipmD`F(ZwaM!+lV_5ZNX{8 zUH!ULei>@FIj2sha=O$F>VvceVy2mB^0>bS&YIaBTHc$WXCpzhTvBC^+-C7p**tn{ zSdRDUk{a(sddSz4N75bc@!i&M%IV5LNLMB?7R>IYGH}vPYC$g)vMgV=2ej&oMQOdZ z6`NPJu*($E5Ys#r14ighzos3*79bv6Pad*MxqfMj8=j>y(^up)6g25NVRxo2w&Tz~ z@tL+q{pFS7S?}5-0v^8EFUQA&$IqpVF^%cr@=-{l;zXY}>PG&nKjSg*@J| zU@TbjMti;IsRM8Te?(rH7Q0vdj#c}W2IeACJ`n(Cxz&_~6qpMKx274Cm#uQ|FUPF+ z1>a`3(sxzAIav^XTe3eZ{TjP8`)TdJp$fo=5GX_Y@`iaG{2~u<6SD;UBBsKUJ9YF$an^1DC%{>uHX)+m>WXbuzaQMmQlX5f; zKnM@OOA>-pDx4aiGSy$(S4s@&q?+6GsQEkcB}YUes-fH#RYX1Io2Ei0((;d7G?l)zP8po}(l)!kzjhr&P1AZ6N(Cl|VtvH{K^E2##Wsx!{SK6cS<7)#EPTgVDo2f0p1^`si? zRX4L5-{lrTx~Nh(uPlh|PQ8su5(whd1|gkLaOHLfa>W0xA4(_=4TJ;S5Z48Uz!(B1 zc)QP-F?vGuFu?{JP{^_&@73;2<1F1X%V}re(O;Ww$|rX53nzOV?%H-2>hO08oegwT zMtmqbRw(XOvn`?APBq#xtA8&;=2%RyG5p}4xemaLR?=z=J)MT_SoFm;BF%7~8>x|P zeF|G{ohzf>Bh$#hAB0&W*XtXifl5T0D`>wXYEd{ukXfAVngCBK{wN>i^IdF>cSwoobx$0YGU zDOW!++%!}HEQhpEw}={0bYw3Z4IU~3OM%#UMHjHvxNb2_3rT@)1|;t@;7Vljk#~4d z-acc(T7<2*pd0Eo2OKFUA>90!id=K^mP+P)ihnHF6omW17f(5JyzA!n(YHGWBZ9c~ z=wQ~-%O-$>aobj(7JSX_IKa?Q!nbjNF#U*kSQ5N)8agg;2IE_VXR8vfkD%a>TH`*GoE+#v>){TCi`0akpmK3 z@n7WC%l)-5--TheeH&3GeJ;?KKVNBoIkp*(K%A0$F4#c5f0lyOu|Z`njAfJUw)(4zKw z#k2Hg6%QpX(Bz?1*;DEoTmHGk^=ipd0?l~!b^2#nNztGCgW6Ng?}LVJiJOcdPzCC~ z#C=8f>NJ|^SY&5>tg@PKjk>sKc}CnHY4Hp_PyHnfH~l$m455gG zF!))Q1+(Dkkv2^=nv}?HT6DX$Kp+&XdY@(WRlnpmNtaSj)K~Gl(|-L`keos7oinGT z`COWg-_E$cqU;xN*S$MM?!lef%?nN*-o!cgmP>EWp1d&WahhQc^<;ttEwSK$Fv0uR z*r+yVQT$@((`4!D*=|W`@C^EZmLDiJ`R^^>*LkVkuz9Pi>ZAU{aYMMvK-Lu0V9&Qlkmd# z>j$*0)scsJ8k`Ce=mVWBC(aN{F!yB)Ng!n+uRiX}84h+78>YMX30!^I~YjIf{@~zhtj@j2un_yqx(VpH!qq-2`22?-ZEwe`>{!&{ zg6LuM;Lc2B#m6hs1~&s}DYvSwtWEXyl*B>)Wp>5-!JV;%BD1MUY0qPAX}?Ek%u*iy zKy?u$_r-R&&{M6r(w2BnT5KBp(hxi{ui#1=$cu6R%B<-O9WHTzah$+kBEn+{aAYq$ zh^`u*nJFYhyF!O2rFF;dKf8jUsYax>?{~!uJ=FWf$3taHAU=zy!!Hii#Lc#9ABVrW z)jVBT1Bm1(Bj{`urb+wHK9&`3;^F^6dJNMVBellX)3j=|&OT}V9hKwoyDdPeiiI}3 z#AF;mx}(Q$p6uXVNF$pibO+O`-*&gLz7)^*bQw0boh}q(ox#Uc6@qI#JM z30w>!spX{ZfnUbht!;1q-o`Cp0NwHIRWy8P-I!FYg7*DlHtQqX* zApw9PZAkcDnbOVAU~m{n#I`Ka8!VDQlHN~mPN8zOld-c6M*w8aXO6CFP@GX_|3W=S z7*xR%Y`zX)=?z0^hNc7&%X*T4exn)&z$6G~Qo(trpoh?e`<0?3Q$&Mp7-_(;vZI{? zLpOSHTz*Cv_3}l&y;D|_AKWmZI=F{S!1r9ha8BM$iM7quHNyPqfk!7`=WZFlJ&txw z%b9Coi?!`NaE8w}XWJCh%`$bJY`}_^}iY+i$7d-L&;P@E9R#ORJ9l940ZWMdSfP5}bd+mNxs#UJFGt!imX8!oH0l znmSYWpF)vECpJcDmr7}8@%*8SSxUpS!KoLNHVk3JP&>97>t&^-BY@ao|B8R3PI+NH- z%U^}3rB)#BhYQlNBoKk*B>RSKd#W@&g{__9M50FE+ymQF{rBYx`q&kTjn)oF=tF7M z2$J>q6gv)hJW}2csG#To(w4-IDXU}^(`-p>ddd#5tS1RvuXIa=bis3Rf1gJHAHiOgCcqmPVPO%|S z@kw-C>8y#1JRbsLHBKcYP;t#{n*~&4^2B>4sJLG@bo;7JSd9n+;_3+t3xk~;hlq#e z9}cymaqHBe1Xxfr_4sdi)^~}WG#HL~H8dgBZ`~>=i{qvP?8XQheW zy$c$r$`C0w2&lnlugu!_-A&;1+S3_Uo~(-$hoSipT(eOE)F_RSS`WsTdXnEub+x}w z4~FI!=O{Byn~J%H@lN>mf^f}LR;$!8CRk*|(=Y*wZ^s!YK<%&}J~cQWTJz~<9XKg` z*N*Hqamlhgw&~<`X->A^IaJw-;5zZ=y|2nMALl)R_&F!>XC8_ykr)=~DboZQn8fRy zGzq5uWO8f^QQ5a#I8t3M8y1Il7cm#e=G80>JI`}c!OHvEEZHqWoErItys#1gK&W67GQ#_hxX@h+NDf zxdSxVL3R>V*iE0$Esb9&GrSt-R%=b7z|0uiCqsPnjP4G-SdtyeRUk|*NgeD^#-4LBliA)D;w?oaDNN8Hh{ToXZg&D`#M&)TR zIL!l|cjn^fB7V`^_o$bH6k4dkJ4=QoqcWoHMij zH23IBP~WHQj&rde&drT|`2gEumV}oJY)!dOEC}>3iYs)wZ>`2{O(t4Bp{HEU3+#er zc<)B}%GTCchvDkwD7Cfv zZSid=S2Wd*$o7>eDnz^NNh5B4!Iq^a2#qGs(iS=3+PE+=N9*kb+U0iG%)mEO)14#m zJt4uprLHgh5_`EP_N;yiSj+Ex^!Yd+w|8h)7bA2OjGQII2mnL~(9wyuKA8sCSSjA$ zb6(5Tevul5?^`^Pf@!&WCFR`-JvEomBJF6{83uK-_WS9zSZ3TOANUVH!MIyGd;YpV z0^`psF*}-$0O0MIn_RI960t#5F}Bm+nXBZ`dt{F;@rXgPh(bt&;Lpgf-ch{nFsiq?w<|*Um}*jJgcpCkgJ8<@Zx`_bE0Bao2W| zz4oc``!w2q+O_@ky8Vp7pHln5GKmAj=M$(Pu#8hM|8%4%3AC-fk$d#u^w)&UL;lOY zi2;H!=7Z~y4_-kwF(rcs6@qbgM>h`lP+P&GFn_**paebJD|Cl!+KrP#GY ztx22k9*|Mq)gV%G5cVn#cMx@D=lcDaE{{(>v_Bp2q*sR}e6QA@UAX-G@xP4wmv3H9 zxib4tz~*0abd5ib<~DxziG1WCgGsirHHiyjeRadV@TyNA`&8symahl-5{=^$;7gN9 zc2I;o7|tWJ{}tOqW#jbP-&YHOG#9c+*?w`0-idXZHpA5Kd;IhE*;(y|Je_RmXNq{OqysO73@D z9;Uty~vn>9V z0ICk0Ur<|boh^K9Yj^HcOUa%27j8RJqMj@2rT*U+7eE?6v^J(PoD8W7+)CZ~o3mG+ z9_)k{D6j4QJyW;!^K0DU#^Fh&U-uDNZlB%f1LJx9Ih}uOzVY%H^ESNnbAApK;M9Ej zHnaD+*nL;cgGcMn%Lf|-H-CT2o_vw*cxdwP&##}~zE&OlaQo3+OFeRSkJ-!1US4}D z^n?tz1&XI1fLzu4`wfeX=yO3Ui{Qg5Jn{JT*Lb@r3?xlLJ%PZDpQ76s{&tNMiBed^ zEe2E?BOqKxQvk)rZwIj8G-Bd|c-X$X^&uZ+xu1$~5+ClRDEzaP3bmOg_2w#ax%N?Y zdq_PN+_H(+O9C#!1xi^!2eyiDAP^+Oq=x}9H&WOgGaf75nGFn?%^x%F>?3*$O^sTJ zIewmv!*Imf@`h$<4fI%MkNE@)P<{+d;pQYdH6uhVz3o+0nn zRoxI^)|GW1J9D>j)pn!tUs;Er%QyB*Di4O0o}Nw46jt7NSo!FhD<*eOiUaG24SUlN zAzKYoc|i4tsdVo1pu~^Lf(DeDQ4jsK?+yhVm**9$OH+L`ZWh4f))>H{=wZ*datFMF zvCY!daJ3NY)QWb{elZjPW2O^$jO@*`v}Wunqe>or!q*FH%B;6N ztzrT)WxZz?N3~yX2f)x!elkUFs7RDkqm)o4jEG-i4a#1xZ;Hncbmi_B=InAq(9D8Qulc1!lCP@vET1 z+*>l@9w$uJsNT>h5~I*jv*fRQso9Ti)RFFcAC9>NR_2}}J}$fz`((Anz39pPX9a2( zTNj)3ez`umeevS@=1o_UB)oNEJ zkRKw%KRp>?kBaN;S>94QIrK6ALD6j^*;Cf+1%%TD#kSSv=te@C3$P^gteFkl%7n<_ zcJp6X4;pqv=F%A~>mBAP&a|DJxK2vaiJA>?2Fs@d(?Put09n)Ic#~Gn%kb&tO3xMf3xLX4pE|hkk@QCM{E~ zpCZ*ARRj_LK5nBOfXx$8fk-SV59*Gw^l-}%;hp2=+(VHs6G|;aH`{L;rwKuV`ZUE? z0JuTx&m1#_adsTxw&A=aI*D}aiVC<_AGnrtA&DZInKH=n3}JnYf#+FE7&K&7=R`9p z+2@T0wRWLT^@=UBJh4?s4=Rz}$r$O^c+`^Pc6aO8pz7mPD$*5^!ube8b00mF5*!Tc z7tg{&hoh7YmJ7YKgsRibTECh5vwn{VlDQYLx413>mb&m1$hn4Ilsa?Zm>-Bj5r9@8 zj|}}$8R67!WS(82pHNyHgdFc%s;Fd|qeihg3F6d0}Swb&W-? z8tVK3OuT^!wQpY%Ut^kc7f^F9by^76*>;=SMxkR6DEPH{HA7q^oA@~S$fUXpiXwtO ziKTJ8Bw{tjKVvo5t9zGcZ5(%cAjaG2N4#y#kOAXa{yqW6eNob4KmE}c&!!o?upQ;! zB|#=@ut$87ry{q7xQ4S^xVFY^ma&%_IxnAyaU!4b4sNsiA@}J1A+2UpsmXq&JD@D? zGXJK#!AXPO4vmv;IlFK2Qp`M;PWaA5Z1n zG(|{JVPcSrM?(k~@TeINLMJdQGf@_XW9v}k?e1)miu92I{yGYY!4eNc&^&*S%HfQ> zg=8SaM_96r`*`|Xj36S5ZmqRJO5qLn6a9^$rNVFeP#!#{?w2Z}@Es{m_ist#g{X$x zuQ~ZTYY+-TZH5L>F44Q-X*&`~eB+FquJ!LD_+N1Jy}TUOn!3%U!7{qyS$r$H899X~ zUngNwkNcT(+7XnD^2bXfXR@o97|fj6KaVs z(y~;_^a~9q?Mjx;)oK(*^L6AuR(qkqsy^@VRLz7xS+=~2B#kXWrR z#XI9TlbdfzYa^~2ZEV<)p3W?ZcCK5>-*}yK zaSEb-VJo53qbu4sd17_Er*eM*72-u+i@sR=V91Skc<-Udno?EN(Y0ewer#5$$gCyq zi%pGlVnG5}kG?YR_eijbRfH!ackER9<{*e zTQdHB@_n)J?v#VOOvy*-@^`=9`+liEb}jkipVy)a(^aRdt6rHc%IsFP5CX;|r==82 zKwVNQ1B+ieCH~y;EmO2g!I9C+cx+OS+H#LdYmWe~o7YneRscSrf_dDjGjAZXwIdWN zgxLz=z2S#MTB2I~bP4%*J~JV@g-Jp$Y8oqssUC4c8)u z2#=EgO8SsesbglFpz>6&QDaZ83gk|BHJ+spAvhWZoiYu>m>Llb8tu$&Ew|c6Vqz%< z<9R0U-fIx-cEo(eZyy3nXJ;h-*Nlzs zVU7+Z0nNlk@UcaCXP&>@GqM6DZ`u}>?%5m$FBYg~D#hJYIU(z&QQ~?rz-@hm@Ii_t zI^#A1VTa6*iuS6FnoD+)P%^eBkRlpm6gljIi_Vf}2^VS>Y+Raa>}^4<5$mB&&VL#( zNus2JKwnoNx>>gjr^tu}CZmR=y-YE}Krl>3{=SG2@-60vsBt;PWHzwZ!N+78P^t-x zXNMw&Df}i*0@JQ%O4-NHB6MfLM@LuB!XS#XFDx4tI^SClH3BHAnLNru&(*`2fMGa* zxzc(~!VY^=c0L#f31NSg?#WW~El;6re*QW@4 zGIMYPiO+Ud{q05C$_sU(&~%E4_wDeIRU;iM;}6nd8ViCQH}q;rnn9u9Y#$a?Pa5yT zP3%5jI{dKh!{>ewZH0AOr;UwW3M(Ys#l?V(I3FniX#5uKvfcUT0A zLhjksVLOg-PXW59LQN8#?8A(o2vAiEPChZ=-czSKP$AcF;y1rSwYl&u5!qF}+FK39 zvZ?Y8)*IV&xW})xo5watB@K60;VIKMr3)gs$IXsr$>Q+!f}KF+X>#zed`zosDsrIP z)dQDDs#!qmERu8^p~}l<$&pn3p3zrnKJQ}D>;$=VCPO>K? z!60Ow`3e7Z(?2C1r@M1%88V#^6UI`|BEU}YH);pvB0kqgS?6DtTT%Dtp6%vO??rA3 z1*e7?F7u+cdt!_%+HW#sTxZ(vbn|ETmW-y06Dhil<~PY%=O0LN86EZ*4pENg;U77# zE<{qUtMMb7d(2Q66MI-pdCd)t0Jo&K8hcRvdix<`rB_Jo+SxIL;s!gcNm*yZUo66z ztI1KkiJ-((aNoGZr>ZQbI=NN+NA=5{kf!NJ!k5GwCT~Yr388Tz=G1ur4ed7l(?1rM z8ve5PUOAgTUPXEeB))F;ajxj-9#uC@{O>yp9pb#%lYCjv9_eOql@>(W6D+%b-J#9V zxW+=BX(l#n9ybJ$b46hQbGy!7jj4Ls8i>iLMdTj~q#q=R$AZ;ttw5*5LH)Ub9;Qam z)qV>lTkt|ucUjO%{pOivu{-eqNdFy##dH>*C5s19eq z!ihmr3Ho3#R4*S@cG$o6YRsE#pfp-r0ScUWEqS_5?F*=IqfE8=w_P*Xv5D>NvWfu? zc0m;$zkM>MY36|_!o?De1J8{qRl1o$QbWDokQAp_6sj*t3DVWG6eCN1LI1@bZy`H({|1ibbTWuEMw};f&ERuaU|zllJ$P zeRv#j!k7^0Xf&orpF#2|8;|y$R@*s!zHTJ(aME;&(*;R2o(IX6w}87M-Lj6 zg1Ntubk3?{&*b`-QY`h%I5%(U_xBpQdYBNQFHJ!9?Os_{PG~tL@KdljT|v? z?H~$P7phT(1ygcD2nA`c2kH?(?o{VNG+FkVd$Gv=X^AyuY^1dII1)8z{cssLvsZ(k0+T^%THZI z=hx}(K-X?rCn(oANEr$_+SnugPL<9F#rzp|=M@wLGR{Co-rw}&VVWr|A6IB6*F;)# zZ><>vt| zBYZJQS-QEABhCeiu?4F`E#!+hbwj1<>)S5568*omU3&1*kq3RzT&KxW?;h7Tny=E; zT)nAOw(_02>hs(4J%ew z-9021<;m+WG39jTIWv|$#$uPU`+z(_d*2FM&OGjd`;`UC`ZxdC%;2~}vHDhgzLuscUC9c}g=%JJx{pb!17^`&!Y z9yR5lt?gg+#c5vqsPsXm)^x5WGqj0%?AHDL2J3^srM1Dx2AQ6!EJ!e|SFfSY;7dKc zMqbBic0c&x&E&;hFL-pCvZ`vpufORV6yD>XUCqR|!TNht9n_55_9Lknup$-w@MBzs zSI6BoD=*&q(|0@Cd<`Fk{tj^Hcy#|)JTdw{#jxq{tI7ym8=YAn^>j6cZm`|=qmyC~ z+JD|f?%9R+Aot%lziKPpNqGG8>GMNF2E6mKcgN+3i}LyHw|(hjWtVckx^*n+l|Ed- zz3DZiQZ&r}Byax)J|F&84DV!IF&d(E4&^2d+I*p2GWyB~64#>~wNDY>yHmFCwACYF z*v4@9qtVz}=h#=H)0m0j7k|D^+2$JkZV`&`K6_D7*!a~^<4N6TlcvUX7SE;}jo)}Y zd*f?79Bnjx!FVSA*~}H=SxDss&3NwGv$-nc`MSSYNsgBg?7*$3^MlXcy)u5U`>f+B zTej};x9HB7OUnbA=UT&(-=j?y1iKcN;NzKkBM*OlxTQ2M{Y*JRDNVv;#iMJ5Vl1V9 z`Qu^o;?gtbx4)}!kygQoWU0R^RVEvCCJfr;JGse9{Et2>C*RZU`aIQ@pkPGz|Kasl z!zWk%%UzRg`19?j`(I5DlP;I*)qF@sn0CJYbd09i@k#z%_fO~h5~h!z7QEut43LQX zfPVh-is?Q)Y{%mYIR0Dx>hC=YPwMgL^}{!EBW?HZ*BwY~pMH3G|D)-@wJYW1rmGiB z@p{~PeQ3MP{%4$GK}A#D9q`WO}?C4M^U&-ony6iu|e@CyDImVa#UjM zt?8ztUgkx^nvFe0YEHNJlz8M$J@$I`DEN5s`O{D1cUIp#y>`L(`4tdcz{qp$MP#>pC$$AnMTIn}v8D~~-hlOw-Ied@lq zd7~oun7iop$l8-PUd5?w8O^VMe$|UMLpk+v+o?D`;eznJ?D;~VHtX&3O^tU8aCRzo z59n27_AIMpwU~)V7rpM2Ojns0lFql^RoFc1+S0@7T>aYrPGc&vMM5`br$Nq^d)0MfRP(jH%S-Lr-opoW+g&om0gZ>zN87*E@2P9*XBS4jP+OSi9y;jB`qnKz zXYcyjO8DH=>$-PIg(u7(*SH@48uJY`uJAbvH|luM$LXr~TdU}mjgy1h8@H3jlSXqD zGT)wigpauDHBM(1SvejT`L1EHrV`UHjz0HhHZb48eQrIhc+d6Z&t)wuZ{5@PROIS{ zn@8{;FBNMZTR0Lo5In3p^Dg>zzp_PjL{Zz6K)hS#@$)Nh_>U>iH3-=B4WJ&(gdBHM zdrxLpn`KfS%6@+wnjYNv^thGPYn{uW55=+pnJd@EFWJ=!GBU|lp3C`mYGrOkQ`v3z z;=V%d{GYkH>#Mm`t=wBI_tDWmxmKCDb<(mZ`Mk?0q?U7j{Z{^oQ=e+}Qw7~i%5qL^ z+_`h_)SH`4W2ZhhJ=rpNQ~iv~YqMq8M+pl^9zfZ^z#*W51QfvBfCK;_B7sbVsBJUz z`IS#RO5XJZF@2ofrd@??q*Pa&f5GV6p%&@Ei<{VsqEEPMYzxF4A}r^eWM7m>dURE+ zMajJ^)wyt^;$)%xiR;F`uwZ?@V5b5b8##xA$+Z*J4%H^IBE=i7x7=EMtjdc&yVsuX zHb)`;-=k3b&ruu#mH+1`Cl=2QYGNC% zYp?5%)#)^4d|T(0ckGfo{VP{#rqZ}dMzTjn>Ey%ETv$utkS(8_zg5?Jk;kDJ>t`tr z;H6vV?3*lqFRr)9d)zzK#Pe)tLHfcpo%lrj%WLVeJEsOOelG|bfOFp|J&4${yPCmy z#6|DrNGz%}NIbQ2)1h;I?X%#~#h?r}`#o7TJ8LPE%<0fsWi!3!IIT0&_p~g#wn9w4 zDtWd{JgcZ1i8X$@wKDpQ7QEPtsC6HVdikqWHa%`HgN;WrAjG-Zr!AOgkV9j+?es;0 z?9PB3V@gUw-leky$`28%_vB98b4KA92*kTHZr*Y(A#UfUXH_s=0#N=Ew=~}i#+~`Y zd=m2*_so&n0k3pp#cC?2vBFNJ&(Ym9O0Kb|zeG-bc71uiuX_Fwdx0N6_zP*DhAQJd zE9+!aZ2jG8^G~m?FXx;Ps$pm z{2OiFOz);Z&`RDz|FO<7(#I-nTWD4L4&}hFMc!65EY*I@FYjVuAw57 zM|P-K+UsHx`@`koGHt67`?A6nha39w6OD?kb&l7pGk>^>?5z<>?b8h$3}VCI+_r5B z>CbRE<8cpPd!GMy@mbG$kC!H=h51!;Sh~RfXCMA=2m3!S{+EsAzvB1*e--Nsbyb=#JJj@bDKtsqYe7n4h@jE3IH70t?KJLC62_kQh* zYpP$f4b!9O$4YR~BQ+<#eSBGA5c-2}pLhL5rA6{Rt&6Vf<2UWsB!f$98eY~q)gm3h zfovF2pX45en|z^Dl~$uF(YJ>t+Ab_~NOC}+N|TjFd*i*jW2a3o|K1%&K_H*!$`Y4e z-__0a)*)_hybrYM**@KOaZx?h?QyEg#h>@`+k<{+WcB^*S-^TxGYyj8TVK=3(2ed2 zQG|ib>b_pzY&_){I`H^xKSQcBxe(@K_~BXb6E>-@e+|!kTYG)z;9+uPJ$8Mt(8JYK z<(+=Qr^RbtgJ(^C|Jb?xZQ`xRpZ1Q+3tFDHjd{~5qc`?>dLutJYB~hJXS3qP;91v= z7^~TS2}ff&1l+JP=_^K`W7%!A^h#b<6;$b z2i5LjokN8_$JXYjZy^MVMf%vEMA!A>wa2q{Vhi{-jBfK3hFSfZ+HkwWMs7@V>SNF0 z*F(5p%_zol8N6sEbIhDOB`<0>t@QWgv>m6z=j~5RGZ!Sfu8bwD%l>+pTF5dEc>l0& zYrZw|aO3r7%bR!KRH=`iY6x|#5D`+&Q29;!KiGTEx2C_R-BpCj}1HkgBuS(7bg~w+pw~KoxJ{b0!hn>keuR5X?2|v2#ZrDmxV7;uh1@C=+P!LU@>SuZvXYnPgz#T5 z(BGX6Wwo#ix<%+dH=dOxtPP|)Q|=nHZZZt6COv73<;v^I%hr5k{p@52hB42CFj*1P zWZIgfB$UOpqw-8|b4J1S^Tvy^wcMLnK9Up#>jjio+nJiG|1{-Ui=}T52s*!=vSmZw z_1ohRRNrcIw!;XqvBA(g6mcgD4=sTr@w3I=wwK;bPTTpLMEKZTe{BGbG-~}_gY7Pj$PfymTHv-Mf6+JWSMUc%$72WNrfQ(Z66kO;?$8T*Uy)&hGR)PB%6QXS+uqB#{Jc@U!~8Kaugv8q2|$=4g<$Bip}Z`tuxO3_H_t+}m*pQ{zTMmc zW)t6@;mcMnwDq{7^OJ@Jb8(JLPGXeRuvhiJPwq>qvDKlctd$|XQ%T#se4{#>W^`ko z^ly<42IiBtM##J2D&~Uf;Z932JOE`R{7Q3jWe!F{y*BX*=v!^NsebLZ4ajHKOK8giRoAc%6~exu$k%D*H8Z4v8ojog@`LXHG>l?7NzVF zdt1?b@&=Vy-=AtR2j2Fz#>JAiv~MUl$T?J8F4)Kqn5s8zP&cJSqQVUg9fr@r3* z9Jt0VZ@0Ah-r4?R*Y48r@Fsmk%uVb1%FE0NnGt(!&!tz_LI16!Bm9>wj{mo|DEd!Z za6A3W7N7q!M^inbGTN&?zWBEs9i3h9Keol0f4z26)i3s%&9^?7sxm%M3#(gGG!Sj1 z$N=rzHtfZ-*LI(Sh&Ue9#?RUzW(O=+dU3DW!NCicY4dGIX2SMTprc?fb1X1I)ub)% zAC{bYH}q+;_V!+ggNxB{XB-2M5RaMSgk3+HodVbsrv~z$r2WlsPcPSVRSt-9c#A%K zJ8Mp>nE=B;<&$yubL+$+kQqLdsTq9dkAHY!+dA8kHxo~Oeu4Y)y#ScY_Ts~n^JUTi z$+OowCkGF_D_ovJ`HAOBrWUirbsO|AUG*P8L3vGB#ya z77k|I|EtPj_AQwGx&P=}@SR`|ZV&dP8B6|0-$E?Uww2?tmuZG9(^^8I(nEKdZ?jVK zCw0Tj{@ljg;FJ5K<&x1}j%zjb<5hau;*PTjk~DrnaMvsq>wv}+>pquqBvslaNnZKe z#o3#s8B!l053ziVd|#;@*u?c?7&=#BT9$E!Gs#9Xq;c}I*Yju8`P?L^16$}1>S8}x z%CfxpuD=yBx+nQwO@#kdQDgGy-f<1@<;43!(~N2ORmun`ny~pEcHz=J<=mX=$Xd04 zAz%oOSMK5Ef9}!17j0g)$Y=Qc+DPX8{YWL-bdjcz_~#MF-c%Gxy z`wO4?rPUWSPo!3ZvVZ;9jvZ;Fn*A1j8S&!_;b%xM7J{C;bm}I!oBCG&dyz_c=rtZ0 zVJuUdG)uEhC|ts3XYl4&;^D3>#q{s%lekp2^7`=v&OO^xF|xa;R5Zi3hhbyxCXtC= zq^Zn%iOcYK64+!yzQl&vN2x?%#l+F=PqSH=g^J5Y^@N!n5~Vg`5+5v+seD36FFxx5z1!gQj0Ya0D!cQ zit^aZhh8JNl4>&Kay5T#?GJN_Yis)$pxX@wvFhO}qk2QMV|;)S+Kneeb(pQH9)odH zu|_YE^FFCODtL3sPEQ(6#j`U4iNC1-FBs@B6u-!T` zkhpD#_8V$`Hk1@-552n-23HEtl3CaKxw8*xurKe$s;-pMp@LSdcBbf6BL|}r=%+Z& z5(TDtLhEJ&m!%G7_}-TP0?enNk89Kw4T^I1vt$oSChPdT3y%&Alo8A^;WEc7wvb_l z>Zr8GXg;gvFAAUE-F}!+eP!zRU%AzppcfHX)2U;Gh29ScUuZ(t;+U-$w!A17$q~K7EvX^K@gyc)_h@agQ~zk`i47_Hk_#K8 zteyzhKkzcPg;JLsV(Ke@Vr`6DBNt%$M@d}2bQ)^(Y#Rwu#PAm(?>`3{CanNRyJlnm z@$?Z;qgFxg%e{$=g45d(L;QOG~p_Kz3oW>lO_r-b5}p z3BYm2PI?N|Zw?MvL_V%CuCaPQV6UU3{3@PC6Qc5!nnocw!n%m6C#)*DtgD|X0{{j= zytCMcj;+;y=#s9ATrmC+c#PRVm^v*<|9ByRll^qRBwFNdQLY2KYP|u}2T>9FHUd_3 zMurn-YpOpGqCm}G4-?9%!t}PbwY_LYnzy^$i$bLZhkFY9MA-|!TH~pH8%>_JP=6E_L%!@@*8;P!gRIYeUX9MzHz!k zU1-5kQ6E`QGT(b_uXK0pltE|RvE|k8??fj!>ab^>V4jkyqHntTwMzwZGf-m*2(AVr{-lb1rl!t zx^D!HL(Rt&)U7xl*!lUvulccnoLGRwU{hATF;DR_^l8Y0zDd&=V4bvcw__!UD7b^U z7|`Bx-hi8~yd*IBe3Tmt;je7}{w%-1B%7+CA5phZq z>?Lp~INkY#r`|tJ!vKTATwS@ifl8mVnm%p@aH&xM{2a|76iXr>yXADhP@t7I@NCecmZ4K z6$63Wz>iG0Wjgh>L9$>YAZQ0Gsy=oaA{>@45Y;SRp9-*lDGW68Pz9mJn8RCSC~XQT zwo4_+_d7CIKc!AFrj*1Tg<;~96NSL}gtf1gmf>UcLbil%HLsg4bXeOnT0?^D)n(|} zw;G%usbD=;Y*iZM^4&S_o%uvtW-p(0OPIMP@^$LR6hbeuV+n$)DrEQP@F1ot-MffQhJ4bL0dry%JfHY2d9%h`HB->#TloPv&Pw_mYz z_KAVq8}hDe0Tj?g=A7ek00`b6Ex|-f2y|*!$Y%d&e6qX^ozDP@FEWzdXbBnpf4H?qhcw4cBML*CB%Pu{Wc^dB=`d8m|gZ`== z7QWB*pp&?9C_afU5-G@qctD1PaJ&#HsyES8QZ9IdUc;9m&%!4W(5MQc=rA%_4;D?A zM$nlJnPklm55PfedSXtiAX!M$U12u5$Sjk^F&pwvtfHaa)lfsNy#&}X`KMiY8v>?v zlkgG6xtIWq#z748~(ve<(z`*Od;!~IPVig@VbFcUEzU>DA+jG&@U z0dGq|v#{3#7?46!*ytGNw;hbc#I*rjRJ|!|4&k+^0%0H^ZdAw@7J+e=Qv(Rtdqyl8 z5%+NmY0$$rxD){IVM2DQc3*)ChrnFg@M84Zj|BEAroQ&cxbY7Ebb=u zOJo+-St3gl@|{VKMZiDPqBh!swGZGIykWo=_%Q*#i~#MKLjK_7_fhcLYWQCi3}B@3 zmy!+qpbI*J>N2ZE2KOIZ_%;R3S_yx?51k3eUP8c*$#7Pl(}y^CuWh0UAk@+A2-=CmONI&}qoy3fDmVM!>i5 z@Z9Bd0XUeXR&LKCG^V8h#X|nMmbHw!HNgkjUOV3+1$zm$EcW2uCBT1TbPw_H_XORK z&me!OFgnfR#u41!J&T~G3z~#Ad10f+r5q=7fR&(CYIbE0{E!N}P=L-&gkg$hK2wuz z#!g;7D8viFD=AlUt6+eR=x?;*Uu3StU7@0#)5G|9{ZzBKT)KHhG=xVjAp)JHO%>WH|*^x~_bPfhLA1e8lUI5aGKt=8tfF z?u_}3gKyfxKP6d5_f>$B;2RhnZT0w+Q0>-+Xj!_9Ituz52YYGG8RO)wnQwfAfb|Oj z-6^o2JJ4s94x5gp6XuX3Y7(%8b&djGqX923OCl10#S^ecIqIuNP}bLosb{ftzI&S} zxK|X`mQYt9(>-_=81VaoI-p`0b8vIUHaOQ7$V3*88>nNDus<|dI6m_q1o3c4zmM}Q^`J9ILyDc#^BV%*!kXSEn!s?U54B|&8HbFVmpJ- zC4(Ez~B6#n8#*dhU9W+LC^311;YdUxP^luK3l+BFy^Oc^%B2!4-% z|D?dKv=$&WLmxYU&qnj3P>^dtf?3YV(GYYY<%$^qxT2c!X%@1Kf&bX?KEVUz`wrjQ zfwVCoUnO#{REn?R;m2gyH~}(;fFI+pC8%5)MdohO2ouLN7%RZQwOC>SFHm6w)BYfq z7Yg4YL)&oN160@#GCZe0vZ_VYf)0a8GcPmu8J(2q&Rc)`Ve1sF6Y zgUae$4VooLC4PW0|7#lGP-iGwd;6E85qV!Id0V88E8W1s9f%X+R2iaFyFr@C+1ww4 z4A+4_;RD++dBf3ICp@&9jI8k}Ym!4K?m+W9A(LZ}1`1dme^UE3@RKi$znlG%t>W0A zef0S0r>PL_bv8vR#7C;&9U1b4d~N#}(dPM@%hS2l%n~+qkXaF!^ML@F+%bo1oC`DN z@;rpi(71Kz`MU-uX}(4NNDYl@+ocfOK<2;418p#a}J~3MJ{3Z z^Gu;2obTe5A6!tKg+88uOfVpgxGpg@;YDhhcMp5ZMfL>(d<_9Q8j4?XLlb33PJjwvU2Wv$C>!RaWD1O(^_Q@m+OBV*nU1YrAOpxWd7a1jN$oM3Es z1mp4KW?;zIm2TUVz$$uS)?HBHmY17jkTxVV((2jkJ=xF5^r{(XV-no(!62PW=Fw~5 z9RnUimp;5U^0&2RXLH5A{jNSdwJJeaKOv)aDOA*6^GvQGra2W-1R=yVG3FMX$ zf>rxCNBj5s2|&*2aGHLDGx6Q|`?rJa(;wqoD|gg7p2Y_92@fe3AKAjz_XK!j11HGA zW)UzhW3Yf7la&JBMsYlO${I<49go43?@H{^9_B-?J+@U7z5ZNo6P7_{MUhzx33>4w zGWf@%lLixdEq}jKTk0;9s_xo_Au}=3L5Y_4eBsOZSdDLR z-5sdK0GHAWRv+8Gz#&=;z?xJAHn%@(VaBD%axEMgTiUOPLFC8_w`aaf5^DwxoVfOR z4EE7B(VYiql1d&3%Ch-*@|Zm*N*aN56DgCLImXO*=9@PscDfc9ha+IdPhjzlNfUSl zZcCZyFmdA+)~SZuF(C>|IIFkVHoO}DJcvyi3zMgCTvOx>oOsmhOSRd6DPFod8wfA( zbXFihNAB7w<2&||+zl&id`e>K6tztp{40{v7YZce`aekrf7ns)qP;`mK>0oPNyih@ zgOJZvfayhl+{)24#!jxbA#W{ zq~ODQIJ$w$6!-8!gIM^h!hWgX95G)98w1}_3Lt|Zw}82rZwPx-cjr3= zw!#A6N5cOhzy?@Eeh=eb;+@?oqdXELk8Ojp@m?7@xO4{WI|?d$oW-h+gymb9OSV)P z)1k_y4wEKe3z74epR(rfz`kQ>)unG0ZNZ&%*lYW@pD*$|5x~&|aMQ>}Gy^o00Mv1W zRvf6$ljY~X`-2Sh_Qn)guJDH%v>NxG+6aKx;Nz=mjhB%ZQ3%L2zHZ-PK_^@G@Al3+ zPd$2S+}+={JMseSY}I-hB|1VdQZD#%3+pHa{uL(@`x8D(yYzhv^0z}QsR!3cmBXME zP@?ivH_fF9Z*|G6OTn<5>!vFH69ykoRye{E2tY-`+lg}jL%m(E>ZB6XEn_^pJQqyx z>*SA;Ix9Q2{KpH@IjlnrOpq($2Cv*4opgbieo7Bt-6F>l`+0qG*k@UMPoP9 zAD?{q<<=E;wkvrf28CYr{OSZQ0=-S&kK2B0igvs6r+|t=Ly;6%;yV?(I~DoCL5MQ^ z+-&^XDhr$mKHg-&Vr1NEJ7=X;VZvjOBO07e0W|8&8&?!Z;>}xQCE(%lDcF=H*0L9- zW6C>i(GPLk^jAP0;79Uph68ZvA>DZVK!veD%i|KZfHBS@#yK34{)Jj*I=3K6GJkIP{TEYY zfT3;=#1vsHqf2m6$R*F90>0ZK)`!1YD(eQ$Cr0iu3{p{Wu|&2!c`kMNJ^_@I;ESPE zZWAU4hB1}rd)hcR^= zAySqlPryd`yu6UpgGs@*uP^f0)B|``%d|u00kRNs(9z@-iKBCz&wVs0^u*%Q?@gK?ULHZED|`&a(9Pa(dDW53nz8l z&Kuuy^H#}vky~Q`DNb?z=+*MTNwa~B-N}ZYXH!u-KBq!G)~;*g_gYpfZsfYNK?Fwv z*K{`jrd29Mvayb)F$uMD840DSfa3VC20qCGcWg~7ZfHoZsmE;0%cRtY_TCq#`zcyL zZ|+sfvVXKX@-4T81P7dC`Ctwk}&=#}R050>lvRkYWuB(RXiog8eTY8#N18bGe zMJkE4j#;uoQ1otzt{ZzU{l^*Km3klMQJn4G8H%$guUbWP`LC8ox0}P>@L!TneJYSU z2rhqB@36^Z(!*Ft*N$@U7moq~tc*7aXw!-iwWyWyxRh~*@U5#`TTcX2I_{UBx#a3D zRL-*d@U7)ok__k#ZK-Z-3{-4iBD_&T>R0B}Zksg4qu!Lpy=kGtk|r^I;?evGr_&^R zbL3RtGTccpr04=`SzMn&YszkF*@G0zk$f5ZFHvLFqL$AG!^?wviZ-5iT*Rcv#aNy; zbh`M6LNAQiN;Bo52`+Yv-Wrgo6uOo+jw^AWI((LbTN(c$7PT^N){L5sHb0jbfNw2# zk}QK42KFediiXW~tR9P=HQ(Sa&#t~KK@YX3_?+^cj_!vze>E?r#S>`2YM;LA^`N^$ z^D6B3uKm`u4L>`fDPH^Tr!Tv9;fEB_un_}a@wi0Uda0c~0v@;$oz-v28Orb7@KB5Mh z&BQvMXY**Ewv(8~nPEi@r_QrVw8X6~p1SR7B6v~uyyI(vh>rwk6aoJ_oW@}~fcYrH za#*bAKIEQfVV-O8ST3TB$jzH!Ppq1+Ht`RzbUm^!VyuY7Y5~O$2bjRqaagczqUH&E zMA=r7{@-~5?;ee$N}drBHTKjY5)8!a)G~i1ztPBg46ZR;t_|Js62j38#2kO{PFbPS ze(%4nw}?0`FNR8tWlaRdh19tlrKeAJJC&Is?@$H|fgg~RlV!L^_J1>7MqG?{M+CcUOg} zuZvSFbziq`F-6B;7YFe)-GfSlde=<#`rl`J1=Vn1hx*kS7l9TT!Tte9rkY!o*|)bm z6MP?EzWZ0XTKLQZ31vT!{s=G3JFQxrDA=c8a+$ZS<9c>*sE`(i*Ry-eP{`&O$!dQ- zi%mV4cZ=4qe^|)`X%NNl#Fj69ZOK?wPYT_o89`O->08t>{?-?`bCDk9YIshLS`+ zVZ7Csb>I84nPGt10C2Qfisp=a1xBN~0O@KFCl)LAzS3WS$_9lLRyN3G;$>Hz`MJJG zR0u54`OhY~>v^qdi)2NJXj>uR^1C_ZGb7P4R1ep>W4fD zqwlR4dSy2*bRCL!yutYpUAmN3FB^C#_WroYRM`oo zo9$k87?7^NWb6Y9h2$wrpx}@`uZE?g~#kA*0EU=ejG4_bmYO2))syXCTGaD<; zN+;@u&usl}{Uzj5a{6-YUkJQ#KO^%uZ;^X4KoHl$g<_e!f;t8B)8bDCh<-YUn zz#?H>;^pZFRvOJqLcuY7rDz^GEuyDQcrBmz$(JY}zhx0*jigYYOt4A{4~RBT;2E_} z0VPVDqYo@ozWWtj)8TpO|F*c=w%b%^iz=V#-s}!i?tN|{QC67+sOT(Ve51(N zE|9yoIn#B{8?|t4O}fNp(TB6*v;wGCR9d|-2jW2io-&UZu>S$bI+kP^c{C9~lAhho zI&I{6s+ZQM|8jTg;mYE5P=ru7K1#Dx%jm?0MzBg$!ilH+5~9|UrmBSr8GdugA)?>R zX_QOjllRTZT8kr93W7!rJ>Jg&vwh*;PgfMA=WOj}1#aCF zTy6&kO!XAr$|o+h(YvMA+~G5IrfscfI3X7$vg1;#xeSi4&n@fU+!o>n-R#$a7;%UT zx&clsQbHTras-xzJ3GG*ovq$`|7m(=;S?Q!gJuv#wI5;5t+n>5eXjH`NKk?g`I)Fj zUdQk3nD=Se+wnZaXT=pQUif>)olq@TVgB*{){oC{#os_mwAXR11PV0XOKYAz4;+1DLeW2und8l^D zGrmVo;)kCktS{L4SU9DNDCFvfol9sKtmpv@?ej3v5ZB41CLK-E*kfZ>W&6gAI2Q0f zn=1Rlq`PSV9YvD&9{(8biLHIPJCzBXd-V51PCPX!^8w)Neij#Nrhav;0C%f_qMAw~ z;H#o;RtZl8tys7ofHb=wha|nH^8~fm`1u?7ZDdvNsukGss@sxo&7^2@W@3=Sn*Sno z-4$QY#2uch#=Qu!OhRIMAFX}?$sm!r+^^l z$=9Fx{2Ax!EO{2*$#-zH8X)z9Eg_LPZBRw%<|Y>=-X-S!k#1XIogw zpCu@U*0b741N876UFjWvQ#(tZcXYqgD&Oyj^#iZ%GzOqy38{cU%)L+!a0miC?+y-O z0qYQS)}9!6?kkO526zmBW612hg2qs!VY6!a!(W{pEUaJivU2gwu^cI@4GC+-<<)j< zRd(Pb%JXEeffOT1W*VQKG7*O+#n8aVaTIM6+fxUX59#;7%n$ei++wZf&}kM}9F;W0 z*^Dv+$DzPyokc7#AXl?2Ng9Bck&MVmmPug8yaW3abw<%?QSBsOzw^`1m9g~=(?|)H zKn_4&c4tv;P?R`7xi|{PCe8w*n6XPLu%1Pe;%6k@j2ZDV65{6*PPZqXw#|v(K}o0Q zx+6iC6J_citKDE=rSkNX0IHNYs!5 zKl0=ZO)<;4?^x_l<2^q99+jri1VHh87KIK7Mk9>V5&{{d_F2+-J!oudgG(5P>e|RH zI&oNA*o9`Mo5A%bbTlR!`{b}Q_Mp=V0>L=jT=Q$}YvGPN9DRWRzhZ%iqkz+~U~8lT z$!qFjrVh3mDrm+8=#iKR>OdB@kz!g_5Tw#8sf8N^r9EdBlGcl>)8}35ucM*ISu&`7ikQ zatqzSx@HM$4#Y6(RCPjSEdIH&M1tcOXSgkQvOOu52~S2%#8cQJqe$L@)tK0!&ji8a z7zRn0GU8bG?a@(oxU}5;X(tzkxGiKPZ4g_btcqUt6lO!pXX%D)an4oFp{6& z0qEGuNrx19nxELRkUZCwZi$-U$3Gnn=cr<0fXu+R7$9gW;BOGejWzJidf?}j2)WdL>BWA{Q;Kl}L*3O~WZsSxg9q#F=nHPq7+ySA>q+q(pzFyOHvvyB@A8H- zm^eTBpXIOb-TA%fymiErIi%1KZ z*Ch#x?G0uLK^T!*qlC)Av?E}Kbm}a>Eil6wRG$gBwP$}-sZm)S2#J{$R${%;-h4Mq zG#1x47}6&kHR1QWbVNH3mzlsH=Mb8T6n9PzqNOlpk@D=oL8%~tKv7I8xYJ@#EF#bL z(8X)n>QAV(G1-)VjqOK^>BHxay{Uk!l*U^)@HE$%+1kGNjk#mnLylIdw9q?X&jkbV zIr&Sqi`sw1>8=1j1}TyP(sQ1jCOGxW8{PB(FYP6}7iqk%eima(Du$%s@I>R5#+XAU zUn$u?l_b`ZoQW5UJ0zL3vAZHc5f~xMRBq24rf1-<51`?OjT}n@=y}v;{cdKnkWV`8oU4N~GV-{4iag@b;U;4Kq+c{guPO zai0zTFBt$o93|2Zbd>`XR_{_{orq$2;e$`H(gGik#irOE-W3?jijgPbIF`K;f~=#Sr<~Ua|(`}^7I9mts`e_j2J0cw%O^190La5CNb&Ej!4k_xUkexfU9I17m@0vxqIauPlw$@m(R@rXAB<^=8bPB-J)1v0xd5j z0s=eH3+QTkKq7Y7J`1XfZ1(cgX+@V z+XL*2IKt2_p)-6DuopgLQ0WQqSQyBBpg4oiUD+FQPOJE46v&kW^!=&XiK`PnrQn{@ zd31AHCm9^;NBUsG?m{^oCpavbqrc8)j9(+&zXBlMG?JL^{q~(*9hn9- z*1ASbPPHjKbDMg$ocj-&S1d_K5ZPnUnc~F&{qU!(n>S5xz3?UM`cv7ho-PVM3o+ap zcvTM4JzNaHUS&K+o|UgHqk*dulj&4S_-qbl7JQ3?y&gSS?zhL@Ns1Q)7ySmm87RO! zm};FS1-F02R43t)Ve4F@$6p4RtG4I95CCFFR+$Na&>e7i``36gfbR||%B%;*nkTy# zwuj96*wL7>Mv7CeXiF4CNpN6TYeH~isrfTfRY-Blxa9d3c1gHlCNE^K;Ex-x7uD?i z{i#?+3aUTHdyNFhbJ>{T3vMU1FOWLyNl}aslHF{-5ZAx_2J5oq#ZnX#35~Jj%%=@N zgKg67`l&c{WIPAB%9$Lwvv=wKlvzo~m=+)A4N0q__e)XAal(Lh=Rj>GMSU~re8E<( z>TAgh-|gblTVAjx{vq8Ocv)={5o2~~mWfT>89aYIH0e{t!1dSh81tc8is0J!OQ*`b z?#rXQ0hUy_Z+q+UKT+^_GWaJ}_|_Q7%RwIBZq`}V7@K(Jnw0Q`5pYZoGN!#U^M^Uc zVl$E~`}={0>SWTTQBv5WEa5RWCga!oD=!kAZ~UXc|1Rhs*6h=0rf$%^A;)pA_KSNF zow5r*S_4QPu^9>aEwU|U*XBV;O31AmV8ZUV+*5^@?v7^R9rkg3B&Q^GCcn4 zpj}c-(V2vStlJE5Fsj66pX9kp+Ld^4dxsPtm?w+@$JcW*332gJq^v-QIL+jm!qF`} z>E;f2OM%yt0=|XbtG}1zHO?mFL%K~(5vT{?cfgGw@^(?pw*6)f#kA5`xYC{5tSp*^PLfqSIy$zLwM2dd;Ypc<;to(P}+28hWqpUxlja9fBhLNRiH@P{J*fjx;U`FL`Ut=a@eGMrH%hC zJNWv@ykX`^N9DW!h~CXpmRRu92)>+~dK^IG?YD+niAFzka*R5APf}Fnc-M^Grpz$x zaq6Eg-bv2vTI-KxjVAX!jq-K7wxv#bZoEA`*ykScbJ!kI$&*LuH~|wyTj?JBwe0Z} zXg?0$nr#pvZM}KZs%w=tJa|ifA0>{&Xf95>;mI?(pEsFY4;oEih8&@Lggd=|Tw0!2|@#0aP z>G1{zY&f#&pbZM zTjX+CC}sXq^a#(2WH!s?Dla4BBp#?%L`!uRdcbja>b4DL{~Ef1DfOI?AMIIdYpyn9 zt;JKmpRE>6>yWKYySST?CjVeyp`hU68=&}mWdDr%T^5bBSagjf?4l66!=zf7Y)&tE zsQuYW@LW=uwT(Ji(gxiqKZr%rghWcusN1R!qesIp1J5lwpD4bcBmgi`Ta~WK(kw!W zaFsGCz1HaLxu4}?jHqfb{F0lL&0}4pDol;oz52G$Cc1jCBWC!4jLIJmbFijZjH=oF zq-l_Le1QbIlR;(+mXF;8Mk&qvc&f;O%J8++O?p~hecqBcs`*AT^Ybdst=R;E zZoEYOdtkVb~`L(imI;wm?A~3lQ+NKlWp+h#S`vR#iwMPlj!h zaLh?L)h6bIU;X&afrICN6IM^PO<3~aXuy_kIB0Q#`=1{CQ`8to6nc&_vq$b3EKu-Q z?za7yvDT2?w3PC2(4B`1t-;pEkpAgOIew#7B+&E-b?*rhq%MysmvK*$(RJq?e#=-wwR5t5IHWG;Z@?U+mmJ-GC zi(Z(1K1+&ra}e2I(~}YSiq~RGJh6*-{()VEy=m?a_`JEou_*t1fQv&KbMg)NKF2yT z&2>UrXSHGU`h_A@P9wPkWQRsBlZENmA0XK`U@WZaH{B(x@uXq6Y#Hu*VQyt4mxV2t zr7~lU*~Xfhd>W;@z$882zhAm<6ZTaJ^nR`XJ)3O4U^r8QeGHrW@<=tD)gUWI$XBZX zWRWDS##!LnEj611f9A+l_K#Y<%!HP4f{8S!tsSgmjvxw>al**$UYrLe$7Yx2$%0W2UIL1-3i|>Rkh= zU}mh}ux6esBpYkax@X7Xh!1L-1>U|YHXAFKNXqWx!O1^tyV44 zHFh7LckhyT(!#TDr?cVl8fuLu&pM}HoQ-@U@_l=$t5BU+2aqe3-KkkeCMWteu76PV*#g30~)I=dAxc%hK-m|xry|wtVBOt6D zV`X2Hqfu!$+oi-7%|K#7O;?famBJT7!6qZh86!RIgEqJKJar(;3Jx7_$gjJlyAlMX z7ddM${#7aZ;0H2Za({93l_ZHX1Qe{#UIYduGEfuXD0a zU;TkY^Tt|C`-8@p!M2*Bo0nFDrdwaCKMZRQbbK~jVtlAhUFX`uEn3M8H#9a6)!1@7 zoE#kn1=N;jT6=CPefY?xQB_-ZDe#}4eM8@mBOg6K^EKq8NpL7%Q(HVJ1x3C0=~De< z=SQ)Wo0m4ZwpJ3IORh|fqXvr@$Ti7x(H$= z7ccnoBQR+=T+V{gaw6&_y?G8F3oaEpchskK_R4M3i^~^Q&_jb~_GNNvR+i>8EJWY< zDchx+u9$(f6JKWi(lg~MIGJKO}0Ea<3&I1sb}w zl(GYtukaQbs2CAdo#{GDK;Of@CJ6OWDb+kvu}D-zn>TuT39=svf#5Y(@7;-pA+(ILVNE)5)Mneo!PTpXIH zT{@$&)cbh1Uu%n~!@>`Gh#OE~ux=pFq~K0oF6XGDfP5&aISZ3%Ra|c*xi^I3Gr;IB ztX?aSNugD>wXEPzxfn8KCni!!c%wT>|6?X9P%NNl%)?0?)0eI^Opp?5CF)zbU-M5? zMFUSa@%V@e(25KE%8o^sYEQ1L_XC?RK7tG^Rs~5{r2sKk zDS-&CUl3NUfx^8Sy0{4&A{?vV1k~^Xn)v`VDT%ZlmruP!JsMWimZ+YO)ngFR`Ad63 zt|I1=GT$xL%fT^Q##L{*#-r@!T0s?CNEI|zr9Hv#Xy~d{wM?R9)R@##nd{}X-bb&k z!;%m%Mz_K&P`%fY!=U$fm)GZB@wN4ZRlCpp#!E}dRj87YGbJ*zte(99sU_>-ODCXL zA1pu7BA;6jJGWQb2=GD8dS2_SwQ_Uo{NU}{cU9Ts{iAsn?I7?v#xq6NM_{HKsW!bO z4LDN_KthgLKR6C+2>@U-0RMr+kIsvZ9;QgPL?N13B};->6CKS3n;S4fw$k;j<}du2 zwXGq{TV=Pr$n)Lk78rXMwu2GtSh?6x=YH0wdim2M_Q~6aKE2_I+O3s3WUL-yDc6=Y z`V0}|hv0NJWb$5B5!Zk|g*vU3NpnDx7`u*4Iuo)BBD3IGeP5Xs|NX=Si5qg&7^CNy z_p|Ra1v%$9>^mXxd^?V87m&hKt1${c~(6OCt;pppRZ%0}&4MTwO)79Tx zWPJiwa6VPoZIi&4N#+FmF#Jl!gF$==K#V3JI0{{a6l&Ugls|L)MZ$feU3uG zWxlg9>%}JP>9=LvG*;Ayx!^{1(E@W;MF4au@En3(_!OuWB}CE&YBv#e@EZda3 zzXySO;a`4V!QPHC;>8=Nh!z`C=qiU^?*?SA=Po+d8wY=_yZ+Npr4*~xx}jx7r~D?G zilxaU5vx3s)CMZW^;pr;Njg*@dd5&I2`i2tI~h8&wA-&v!D?)APMP)m<{WAw11&3w zGVK{RO(5Izz#BfP!e*1seg1)dsYV}&Xhep7?|myaW5pQk1Dgx-!XVSf$3Q`)0j?%P zk*XelC0s%hYmQaFcB@npb11~w@KGD^ZUQl((<~|+s7+3kPNI)DU{!iqPR3!iX&dH2 zKy4fl?iHX>LsxeMWTz6fS_2waOnkOddS?wMB$RZ>z*nh__>0V?^!_Sgb5$?tOma_B zy@5&*P`ic++fOtjvueB1Rh0U)aEWJv?woT=Lq}tG^srFr+Q&izmKH!rQ^VO5$zek| zuGB>@qDm>(MY5%8Ot>x!HLl0ewIh`HVdw&TyqkeVA-qhPFZ2nxTUDxz8WF2g#l zbd+=gh=A?X4zzIWR`39FPSS3fzb@@FimJitCt(Gwq+msI`f9`jGnZF?t#>~I7dq)G z7ptapM4~~|C&YRFnIm!j7m5Rv42e0R-z}a11*cW5sMCb11KFD5%vmL zHAy(*j8Z4lxco-Otu|E^6h1DTnMvGsOJC=UXb=kHo9k&PWc@0%|Nl^QFaAvbUmU=9 zvkkksHnTCzEnVi8yYGf_*GMQ`M#?3L+~!hkh9NPRG?LtMDb>;qsqbb&r5dS_%1}wt zNFsgPZ@+(FdvA}=-k;CT`<&-%47Vr@LFP9?*xow)_W2ztcU>()dPux1-+4ALV7oD$ZJi`?6w5(uk#z*v zoKdJYNwJ#+JCfKWpB{_b&E5itN86UxrH@733-{CAR7SI`eMDA#urn9D@T6DC5$r5> zb;@MR?Nqdk5YY9R1d-4_01<3wp!l~k*mB- z=4w3ZM@s*Gt=i3Y*41$nn_%Uk>>u9jQJL!oCUS?AGDUyp+`{68_7ftzc=$Gm$Y2mM zR-}j-Va55eCj~o$oY6KUa*EBQfx%BtQcWgIG?a|Yq#s3 zv0x^FUo&lIe^~hRkch4h6C(SG{q8Cvrw&);1ZA5Da6n6W>{<5a7BHoqy_LaU8nHSk z$Jz_o`q`k3JQri4`2C3dx&u4=h@gfeVHGzc&=$mo1l_lr4=ejt&dJO#{QY)#Yty;s zi$}iSJdax%->Vb-BVl}Q^PZS}W5eIH!3#Lu6B5G{wv)v_J6RSzB7>Q&O0z77Ns-My z`1&W2Wt2c^5}-r|HQwcX7624YvgEhljZpxFoX2rISH~!@Qfx8QR<2~b%1ke8dHdY2EnEnX8FJhiYE_xdcR*-r6n$p{ll1A9cfyy~F3HnVX_i%Mdu>zN<({JSX$O`k{| zpC-Ii_Oa~nunpb5$l9zdq)0M*+-)TBZn|4YHrR=D-F{@JeQkMo*WK~teyVX2@-sD~ zhyP9D>gXdHh`p<(VPh2~Aa{%G_9aGSxq{yA$wKFRVyG0)$TXp;3G&Yq)0%`N$|nuj z`tjz9Ev)?Lq`i4D|J??g(zqx)A!QWoMA`6oqdBk6FbZHc z3U(&4p`$_-XSr9LWqH;0%v(8{FCv>fF3JO!Y95{Cxkof_D}Qb-52t(k(7yY~w)d6C zCMCZKZ@P|hQZ^4SMw*fLKlvS6vqw*qjtjnBsbrzme6zam*l5A#V;72!O&8~pEu0zP z>XQ%@kL{c%0v=f2Q@pCNO8eMLiGWX%e12_nmeDlmXCJ*10yndrdPR&~FJfOeh1T0# zK_O8cHVawBme1IRlW_=c*6G|Hoi9{%7gwcC;%$>)*4FR2hvy8FvW#N?^rdF$&$^TT ziX5%<-C|v_H%f9(e|K-B7*nL*hFm8x(TdLg1y{}704&oKUAqxQ$|o?Wc=I{UUzW8L zTgV54MuA-{XPG1~386217Bxr9t7U^5gyv;T8$2`WoAr=E_V* z`Mm^ha_gQ$xx}r36f;FmNg}5Ru%ea7X7zXKZw*95^oYd&c0CY`h`EUtHS>Q4m` z+cGq|{rtrDaYRv-Sy$s5v^^HL-XTL6HVF)D+cz~bagIB!NJUR4>KyrChic=c13fwF z9>x=r)z?D1ZrApiV1C)k?VaoQJP9{4w%yWZ=%6#&GOkI3O~qeN8O2T7uv&N7-wQ9 z+WhB>eeFYwDF;+V>c8t20%b>vZNgIVWI^QG`!S#ke@9EkPmfoVb;j=>M3_PB^Qj1l z0Un}wL|w5o!n4fSzbUY@l!$TsKL4uB)bdhiu?#wwcD@)_s2?->@hcSkvEVTLrxfr7 z;?6IScI`g&i~RN+37k;SyEj1g^%WGrz?7yzo{sEQN5qSoHmp{#)zddyOoiC=>m|GTi}pLDt+rf-EA~F` zs@guK(BRSXdT+^<7;j47aR~7X*C2%;Qdfu)kS$Ohig9n zbxgrS$QN7;?O!7}rLoKR8Xfumo>6dIgTw@q9P` z*jTHc2a2?C3KujGPUWTfn6WC-`BythZSf@Kk3D4DG98kqD}0Yvs|aq5DCtGt>LEWu z218UHare$hT{S}|3S2NpWo`aFYGyM-ecF-LDg!Jdt09qo@g{$FgTv)!{iKT#0Z&X@ z+lHT*wW=$^lm48*T-Bdoz;vU@sx7%EmbG9U7Bjx#0%K{&ST|$*F|_!C#Z*}7FZ=}z zCwk#=Thus{s>mtnQ%)&T75lh0bns#Xrct@F>By0|6NSR+s8E7UR` zeQ~%2d~S+bk|LE2xnDYsZGhdL&NlPCbkr8PC11aLtXbRsy?-P}raP{$u9U=UzB{$}&G=*7+eMvQZ4MqC*8+tKa zks)opbLGQ|ma?9}m!%KVcj%_7Ta=CD5ziUF+O3c!tO(ZrE+>Ys%tADFjYjHfc$X4Q zp?f0q6%>vMS63QO7yB;jMoFpHrzZi3xmB25HRhkb%?hCh6`zL0kJRG^dUSq-Y#;cv zV}nENF`OxxZ783ovF9~u4+69F1BM>1l=L7LUvBvKPqO+G6Zr(Yz}=}w@62v4NRz7Q zdk=pXfl!4&2PXS%X)JU?6cfL^3bS7_M@SDxMEqPmTjBQ!an98J01N195;*WM(6JuA z`K71R`$fcLau)6<&;3PjBKk?5*QxCedxzh@yuCJJtl){^I6o<&u+)KwlM*PV6p$T< znNbNN%h>u^r3m@papFnWiRo?2`rdQT_Ih8LDPKq_r7avgVbZ=YSkt}H#DAeo89z~0 z-sq)~Y;ip2ZDWr9y(ghvQRO@A50~#va}Gn5@k+q^ZSj!OAxT4$mfgiFcxkqV&o2Fg z>h4ZbNg;M5Zs*V0mmczN`#uaCVxGr>aubTD)?O$M?0PS$7I%B@R&p_TJkqoyocs0g z3q@oa{Fh0%%1bR}^K!GMHE}8JwpG9DcDTr1rztmO28^4W#>lwaF>!xf2|++b^tN;> z|JEZ4rXIlYNjnTI&Ma$hK5*;CJSBu?U85#n&gTSz^!T8u3>(4Fn*Q3~gSw#a9N|B01@akwXM={8?y6N%4_x109#d z=;LkJc1fP+nW1U@L=ZdhcB~qSa;@K~f(pV`mu>jPI8=XXTR%LmH_9WUQs>fZ_k@{4 zct@hL-p~m0`2ITl3e(+w1UUXn9_#bL!`Hz#=H<&6(>uG$G3bDGUYk|ixm&Trh8NYJ zbX_hl`}pJ7W^^CPruU8u{?k6ob?BUp89q0d9G9EE7TSm0&;|Rs zkSYw#uIYPftVHtQ@uKamsJGxLEq&G|Kpsf|Ks2rOZTqoo5!#VLv?f3LN4HFtt-jAd z_v>xc4b4|ABwny}cfp8rRo5hJb4dDyQoh$UjuSEJ`z6)KY+mltHT_;X{ujfYdR6)T zpk98#s{xLE1=Vpo&&(71^WffB<`q#>6m5L6$m6sNGA`agTQ7FPOD|6Y-wPJrc^DRHZ1^{CyF9_q|Okvt=( z#yNYo@zU)>IfjZwyoq?XTv0BJ*phlI;@H>l^N%j!{ZqED9SbaSxObyF zE-pcl^fkyquJA2vd5Qe)WfXk>rqY&5`_XIrpZ{^;a0Fb*e-V>iqdOZ7g$j9>9 zF9Sz_o71ZBEVh=eU;-$hN!L3a10gt4EkkLWTo4pMbU3d*XrIj}3e!WX-^tqHZ0pIcux=i2St$f*HGT?O>`9#cVEX$HQPT@Scd zc_N=N*g*J&aWA{I8Po8m;k5JpTzgMyR`gy+g3Q+auM5c3_LZ4TopDyBv~xG);3hU| zH_r&;F;tP9t!LdWbg!N$fzi+;g&_e);nhPBHp%s3*{TPZ$xO`PPpg=C0F^v|#p!P6 zV4rB#80YVhxQW55NOn}sp4*d&fi#^m3d?X#@*rU!?<0w_-DeYZ8JBr=C|LvE`0e>V z{JyCh17g8HG@@e4j80L&x7*>a$J`rB#z!)4qphv3DGGa-kVYP7@A0|p-6XKqH{%_a z{+vf=Akbbh?D03LZeAaik>Fd6L`EgC-56{27 zbBj2?39}=`yGtGRF3Hm^!1DyT)h#v}*nAcE_Sn6cXproyJR|+O!hW(_sQ}R>`T^l;CC7b^6o#~-8K>wWCd!!=28I$?T)K1Smb zT)m!l>?2ws2SyTV=gw=>r|`^Y+CdTnd3RJVS6e`xd!jeit*7p+uXvq_>k1plxIX;Ou6P+p)&(f+E=ydJixrLWMiAqJqS zqpy5XsMRFF|JBp&V3|yzFcVaxsXDb$Pc!M3)UGhy@i6>#39gqqw-kmW-nH@|N>aiv_n|Ie8kc|VioAk8l;maEhpuG~ESv`ECRCNP1??7?7 z^W6NrBq|1gp`moEfd9rb)qCUR>x=x$((cmJ21sJsXNMLxPETyx{3XAQ|`W?0DSMyE{xF zhw{5T;>+q2J}`&hX7?H!CYar8htCpqezSC!B+^x(?r0e7t((pt7B1=&{!bk~4g}-s z9f|X$%|HnJP1{wYwU;G2GQ<(xzk1lak5R_Tkt=n&^IgPSC9+JY zdmE_G9gfwpwCFF@)qkmL4=23`S{VM2I;#;hHz_m;b*JjE)>-Pmsk*eV3vfkzc%S8Z zn9kgyN_4)N2Bs_IQQnG>uw1;uLSLa;s5=Y9s6MJ|nbTdN`u(N)P1LE;4QoJpIy3Sz zFZps15&tKQP&%*60MH;gx~pNdxjOA0I;=HHV~I+m7_WT zS?ppxo@eUF{;+)NjR}9kb^$C_s_D&Ap#8dDFh9C46RP#QPH)e!1y{J~6#!}?kxqe4 z{?y?DYT<)){M1W8f|0WbxFx37a6+hyi!eGQ&}_U#2r4}vrK;sO6crIr5hT#+E!7R$ zeC#^v!xs0Ay8N=d6TsG^#<$u#(!U%lRK3^bZRkupUpsu)5n|dL09h>ey*XT-H*BME z=R+wGQ5A-3)C(|3#&M}E+$*gsEOoj9JXeTggu#q+HTYrp=Rm@9iFUQbFRr()x(+`K zBn;GP8`XtQ2(*q!@d7<8K%!Nvw>7yLN3srSrtNy1sLHesG5(2bvm{@kYc=ZOYOVLm zE|alb1NF8#tq4^(2pI5dQTNK^9-1ERx}N-Zq0z^&Nju^1gt3JwqHF4Ku|mA*4ECx} zYiX%rgsJruNDvG01(<_4FQiT~t_Fxs;kq*fnr%R>9r}s_x<->kyH^k20mS)GyNe)j zC{?LBOpAA|hAEKGdEj5y5k~874~xC0k+5Y!&6Oe+^@%phuXgdKcbhf}9& zUKgsT7$Pc!xJ|$jAD2UyS-6P0&+!7yD-x|GIxMYL?Fx0Ty!Z_UmJABCT39Gy4z^9G zIqPwM-!-jvaBzOz;mblKN)v9v!u@4QLm-G7K&|Uct45j%1Avfmg}APluef#ED;k6+ zb@C1A$k9gs^L03qFzOZvjtvVi{Ianq8)gCwXl7xXkYtS5?4Q#%}W} zFD2L&%BcY6jZ7oxbpWD=c)AVhRZt7mVYo6QK+N`^_7BI#D70`aSUm^59G(s>1QJ%^gZ|+Eu2k#wN8> zKa-$|P*OSiyM;tIBiAbb6g0zqltyxSX|OL@t@qN?1jYZFy`r6Z_VW#UC zcb8X?Q7(~o$XDf#P_yt|P*%COU20`%`L5L+GR;`t?oDM5utUL{;@n&+FKc=4?JT)r zQE{!P%BJ~3W%l_qCrTddDbG(Ue&$~7U<@8wtI7$!_@%Sv+gP<_KjteHpT*jc6^7@V z;sb{+=BFlS*fFL%Yafr*Y|yy$|1HG6-Y~sh!`k2UcfENP55G4^04bQWuwRrAwn*%S zd&-f&nd{{j(R(jj{{EoZbveww>2P{e*m!;P@1_J?#UA@a1`}07#XqMK#PW9mx*r-p z|0=B}F}=02tM%gV*1F$K-ZocSaSaEn5^GSfK??G~YF0F^oMV%4CB5x&SKG7SZA0nR zsW#Wfy6V06@{IaI$bP2ZSnH}$?79JT;45VC74P$r>wFc5n;IE6 zweH^}+~=nqj!neDBhE5RGp>KNYu9x!+;acgnaK>B3vD;-$qYez?yp;h+C>T$@805Bo_(pIDFLXxE3` zzs-Kzc{!uYroW?P{r=u{FB6A5H%ZW+0CbeYm1lc8e=wCttQAK9n0Y|ugQMYO?GA74 zl82Sm5^ci(yHit<7YeN zmy6K9TljTPzd!!bD?#}Uy708)eM?x&D7CNd{GDgD0(7<4^~t-7%#P+pD1Qi#dL~-C zPnucJXr1s_STElYJ1FY*`nw+U(DBAIyXwh0LiQ1Vq`uA|Fd?~%7f*jZb^d9X0I^KO zfLIS$#5F(r8-FEAOWmaF#38i@;!BPS-r*1bvQSb1YJ>@^aO?`v_g1jNkUQS<$5CPl z;eFi#{*O@O4s?W$fdVlB;npD!P-KVurS!+c6Pe{!X?=QR#uahSzJ7gs@9z?wsaGUA z0O#hUefLk)H{xT3T|qKBQ+q{1Xs_TwriUZt4eepNJ$iziJ;>)m!uv3dw*5SM$ID96 zk6|HUocc}@rd7dl)CePtTzq#qDv?gqUIywcuiUrVPq2O9WfV@Z`lB*<(JKk2v!bV+ z+jN5|5bxB2_SC+RWj^V@=m`;_(C_TkPflyUn>zjkX>{?}q1x9k$Ey!9)#ncH(MT4o zh7lI-JkK%Bbfw~-gyAi`Y)2+>!vvj4i9AgapZ5w5L@!YiHczW~;F&cgE^et8jw z^%%cfz*Mec;qOjIh=iKqDy`liXjYi+@=1x)$wVdv-L*wGq;5)>&M4bKm}2SFPTrdmu)jmH8x*xF;iL6yyU8UR^7Q3Mz9#*n+Osfx;e4H%DSk=#ahHPvpX%33eY3mA zu;S6Xo4tlcSG0R;67d!4rNRcQW|u=f=3e2pP5Qb=x*1=HTK3c)*9iR-{n4*f-9q*m zEudf2L0za@qMM0HcioSi$6tl-TbkWcu?ad|i9z}X%qJg*!UU>4b@(T&N%R&(6Ob^$ z`h2nm5C7mr$7=S~;d>+>FSx1=)_u8nN=xa0;S@}(Pcrw0iqDmZtn^2{yk=`{xHdI5$Bxwd&!OvebwY?gNI=cyyE-C z`g1A=z5Xa|)5AD^n;&!4Xt?@@AN#iJu(l|`A#e3)KkyYVl=UccB~D)kKoCOo>6`K#wY(R%XyqX@E# zZZ>t3LF?1I|Mo;xe8=;uA2?{LoZtB_ok*g>nIxcF#O0yI~K>ElQ#$kx}tYTM_Hp(bD{`Gqpqo;Q2fr_Y)gIXbH&a{hL)2j z?H8inx@-rqL|GUi1cJ5&0Kule245;3540WQbh~wbsy>?UXfIgmOI* z6XE~&&`g%+?Q*gICtt;(a=x7km?+_G4{+2L_JVa5Mnx#|tF_@zZLBw!y)I)ts`a%0 zHM(o3)7R`0B1*1sqAecBRt;KQEN?OKiLw9{JAHRl8zhenChoM~H>nZh3jc3Flx0T0 ztie%}#Lt{>f8NzZrA#D?i=k_bw&DX8%ZD@?2igm8{DK&9)plqly&`aXpv>@wqdLpb zg>lmKBj3;~ns)7Bz2|&j5^C6Q$FmW>5l`t6(c5X&QKU-$w;&Xv^jO+ZgtHx36IXPn zYw4m31ZBn6FC`Su=pXtJSBsV2#K+8kmd3w^zq#`GnBPAr?d#=1rGIuKh9?^$ivp%< z^ES1IsK&X!0p<6{-gy9Rc7=aFmuJ_^vM&O>J9-LJkXE zeaXUoKXe@w7U8E>A2ehE%NR>~lbKqYJ%71&TUiGMw){ zA_@JL=t3}35jZmIpeyOm{uzva=q_eKUSbD+g=B$^JE$r=TDEpIm+IenbTdqmjnn^y zv6L1cy_y#s*5!{*n^*L5#JV{y4I$)~9@Ipt=6v1%LP&lA>}dzwc~GS&!)GJa5#I0I zSI5%u@Gq#z*Ki5q78VM!Amk9L()EO5fX4Q`l@lL;rePecY}7@!^U3f(9nxa&>>kw= zfGhmlM~K>%_|tLmY%OVh54p`$aov(#q10-qafPKE+~K0JgMrZq_{OYb^!~=zo771t zNVYttT-~3mdiYDp@DvO8dp6e$Kcn==%!O!Fm%Bv*JnPBRM9v)g0l-)d=+-7iLkZt6` zQdB^F*R}2d5o~SYHVlaV#A?C#Hw%B`K*3$1vFEZiV zw|V$R{BFxu^2K1(V{-FG0BS$vvm)hp|NXmLA}f!}JM6yl3mrQ@jXxFGvJoAips}Sn z#K0-cEr@a!k#^mn00MT^t?b#p#6*?0%>3pr8(7Z@FP#^NG;$-M@V=v3ZGo;kZrqi( zL|T+5ScpD=Hk5qAE;wN%LX8P2{Iv5Fxi`DXaE2wiM1WKt5dg8jTNNDxAL}W*95uEY z8az4&K}7mYl9GPu7AJb~VC18#TYQqk;+2cEtWoIzrHw4SRCDAXO;5Lv5#ozO9sp~_9iNA z&_I5+0rhL|1$*bQyMJ(Dj^Z$79cI4y(-4^BU*Wr>QPbuhz;%Xw)c4;Wy5h^}MBb9I zVQdE*|LbEF>9wSYE>?#7-R`#qgqsbU$8juGxwW)0d!3CJmlVY|uy(8DT zq6MQTMxPUA9leV;t-JK| zxP4Gq*w@@?LicR1-Gl_i@Ytky^l#trLrGBr_lD9thP&-N7M{dEL|`9rFWc+lk$79A zC1!9kr*9U8&A8=Ffm~%)qbkK|gKr4$Y2cQ4ic(6gD|+-8tlE^t#<Hl9nBgQxenx z`Qz=VWqWy#d1-`n*i1PeXtu0?>~tnQ=23SzQ1%rw)Vm1&)I8Bc;X&CIuvQuvS@f!; zIANspsD`NjQCx$0k$<-Nizt|*l~b|oiA%8Utec&_&%t-c9Z{7qPrZLg3)wt&>L3A~44EdZh*7922`WV}6=}{? zaF_rh_v?|M=hI=t!1tP_`=<#nvAwoF-##C^^=tII$F@2}f>OaG5C4q}BmC{b#@-f* z?dD1smSid@oo+Zh&DOo{=YtC-`&syfyd9Q!r-LcP>FwJ)daTFI<7HI_v#poewPSkd z^o~P>-+wJ*+bof{kK$gxlP2-Hl{%KPU)gaITl5EnAAA!JrD0gY7y*JE)*-_4Deg`G ztt0=nb-)uHDd5P6HKJ>(mFCrtNLvh8?l)Z(`*-b7Q0Ukx-}YLWU=l!; zl6&xTE&3fjcsC7v|A@NBqSDpk zkT>l-pGSs4k_G=4J@05}GE`9iiILM{^;H3SmgfCNQHtL#s+xnS*$2H;c*Z;c67&j1aZs+ja@9N8M6MpWYQFn@!JD?L|C+HgO2@$sSNw4 zrX^y6h<*xylDJCp<7!)@&}pWYOP(Ue0J%lWn9f8ELLs=?b00Y7Q&P9>0)?QEhys7_ z>3A#B9y3$Z(08V*ky#?@A_Z2)ME;P<{x31!pwd>P^6N^84N(3JFy#VWyu#4e!(dgD$V$%y z)2QtfX-12!{I4_NqjZCEm~sIhv>lUXZ|jPUKyDgEGVdV1P3{pb=f5q5gkcbIvE&s)DN`OZXF^P!Ws%|M^$8e zrN?B%fpOGRCZehbo|nKg7)qB@M?+$#LidYu8L{SE@$~93URaTfF=}-ZC8ERPn6Q`e z=)ZhKixB&cton}Pelgy7mB`)4R;=tpUDHRV#Bls<_RjH@k|v>SaqA!A1w{!Nb&Rj7AfLaZ!QyIR!dK{anl=Rke>I1Y6Nc}}h^la9RKy-X2>LE9 zpplDes#kRZGw2E`DV{-XFBJ_{P!+U*i?yi#0O;mu{nk#U@LQl~WYr}y@}d+jq-ie1 z^D9eKKJ%55YvIX9(WVI-_W%BW#VfW`*Lca~GhK;6RD1(qGIU#-2+ChA-Ppz4^gwZ0t=k2F6EmD8jRPZh8K z_CV#BqvTli8-a3Q88+Sg}SG{ZDw_o#iPC<;12T8%M=DoP|WLPoTC zN&#J@pqH6P{#6H?*8(eQ!D&O`^>8LGAJ$f*`&01nz%9ANTpaKElDIzz0VdVL_nK|{yokqvo{|L$ zqd_P;#mm3BND=`YLr0F&75542O~jciWCRomJ|9Nt_BpiaD$sNXdRO83#63>g_d3k_ zm5$UYY9Syd7^QJC@^s+&Vs?dMduM1Gl0*YL)&gC|s+N1e7e78RrIAd;2rN~J)dEW& zROp%QXTRMc=X|v+6it|7Tg)AW#4YBv&j;esqNDzw0R8?D(ry59g0Dml2G`NlUd>{< z!}Z5A9KiJ(o^nHfNR59nQPNed;BL@dsQ#Nz>h!^9zi6nL_0rum+J{pOvbWIhH)hYDLoQx+$z;^D06E4*9({d&LZDK9cjvbB z@zr$nbDuK!l)-s2f}%6iO~Viy;eZYV`N)+m7tEA}3iQccY`S7at)jvmWYHfU(-D1D z@OiK&&$bb`T7disK!q$Hc7LP#<`4P`LalAEbO8iDeyZLQrIWOvEEFpqER`9CP40@p z{8P$BG({<%Pq8Y1oJ?`e$6@u6M z9C({S+Gdzjp8-~H63}WkKEaIdy%0#}NnzxEmm4}?pJGf)xiW(jT8uKMAk7Q!n)15n zwNe4ka(|+0*Bs`u6MCZj+v8yLb>s76pD6Ra{;L#(HN`SLuEcusbEux-@k~_joym@X z4)WIW=bLYKXriryAzqh2db(ik_o%Pyn6dj01{)L`a#Xa2kpHoL7o5zF08lfSPh$WS z9+tdqt4eyw2VAZCKXzaAD@PQztegK*nJ+-x6)1lQQ&|Nh<-}z{7)?aW~ z#LkVOx0C(fM(g_4u)XJFZ!I_ukr6YsTR+xv-=Hvl5Sh}SVDaR?>SN2-ly}Y0OUa%= zjUGU^lCF&J^8iy@@wB_~_L18!Q+>hrGFR=RvCTL3sj$rN{uBkjYcHT{ z|0lZ5UoMc`%&SaU<6p*Xe16&0*bzG99j$io-xJB#jHoF^?;M&JXJ6e4Y&e7r{kfpm z@Y_81TIT#xulUDvof{f-@t3D}>!G(ZR<5@K!8^|0N?&VA{-m72iwtHh47XrmF=G!FI$xxc_ET-wCNirs024_Wf`v+tx%VdNX)}ihVr)=zjLJ zF6zL_!eOg7o7B($`YQ=jWz4VjX&z9$eYrYgcmPfFB7mXoO}}P-K~Fx*x#Q%uI1MIkx6#FnAr=obi{93^sM-f@X9)qye#?j zC@Toyekt(^11k10u8r+ zJ!V{~QQ-|LJh3F_Nt3%Ihq<^$?b52uN&oC&nMPHm@wf7iV{=zGv1h-+Y=C`R&ff zp@OS5M+d|N#{lLd_g$braA?EFGzdp_WueSXC-cdWXi~qbl5^*KsrQ!dY|R)Cf9^$( zEJ(zBWu(Rf@OLdz$x_b_aOi}mdok{bymyxvUX`nJcdW==?P5G5TPMR${mJcDtCf(SiCHR)k*>>d{nb*Gz=41b)w?=Be z^>NS^W5{ap)_*@u*v;iFtEeqloY8Muqeqk6bBvn14kAB8ES2D(dQpBUva!YbHBv3xh)@)rh=qr=QiCmxDtnAzB z6|9OzSgEvTIJ)M1>$>0+>;LFuW3(?hb653kl`Hn|On1)ak6Mg|p)+Rnx zE|pOKs3+o6v&LGU{&RbH!|HYRKTUmlOwjL4#F~qXsAHp&@{Q?qTa&}&&- z;R4f?S@7AG+hB*Ku(OBWZAo>=0)8*-VP74%od4VQRa^U=Ybi-)K6l~aCO`erNu%LB zSsu{h(}t~voyrGdHzA#eWp#NP0syQxkK?@5;?4&8(Es4j1H{~{!4U&2x3IL=qzM>s z`w*ebLwHe4waU&7Y&1Y>J?Th5Gq|q!X}YQR<1nu(h3{In4UyE8PgKm`K?A57&SNd* zcB4~PboZ!#_EcDLSTEBp=xIK+{qCJOU>IhB-*4Z0bGV|Et!@8`t>687_x4$!9j438 zaX|%v%$&B%9%)rOHD@CbHt&?nrI9XfMVXBvMBG^Pi}*Ra=8f5UOh_>$9#imGnpJ;H zV_<*%4GFdn);Mw@wqH}!y z&ZSxTSGrTMtxH}}H!zbJp=N-c$@k$oL9hxR%Vr`^i}$}dM%>ieZB1xh49 zG$`!MF`mK3Pv*B6-z1+tj$AQe47|ENH)LkxmS|%($hK}xXcNaJ?s=c|y1+L3l?LY! z9X6zSuLlpdq)%x{=p3_S30s!osby=K!A{c3TVbnF8fVJ$uw(u(YtH;Z;M+S4Xwt~x z8P%t|ZI@E#F$6MCxgT!1GfUR2yH+`yJYpf*3p4qjEg z{dsjH%H!5O{ZsRWfRZSS{@2Y;E+s9vs6%@1Ho92fNTcFMVG1UbXWSX|?_R;$mCNa0sTe7v_Q=q0D9)=20Q4ox&y)BgvJ1gYAY%b%}vL8+7?buPmfDWo z-~T+RYQWMY#O{O7YuV?|CTh&23h(b=22B=@?gZsqGaL}%G|mwp5By59jFGxYcL_HW zIzisCefeGQ$vP1e#vFh;NzIYi*K;~cf?jhC>zU}%hlyfNf`|Gy+bcFMhL#?j!pWk< zJh)WAN*I78k6tB(5$i-i&UiyS({77$<5tUCYP{PG+^y~UB2n>GN8TeWoEbJ=4qKO-dfhXHVpt;UX9`tDEFJ?>xj+@-#H zl{L_wePUH5$o4!=icF?8)4YuW4jDyOU4w(P-YV++B0Ai9dKv3+|M*7G7R>edmU~=p zR>@nzVX86tkLH31_`QK0K`%Z*x7q(CyWKliYj(rQ6Who`|E9`n!NF;w_xYrjr+2jj zTjG?9ad3q+TlJJmV#`~>H4IEC5Znd^=?K`}wxZOG?IBi`8Xou4c-hke7L}OemzO6N z!V+45$EmDXtZhwNbw9PE4p@09-1d|~SppNt)nlFR;G~US#}O5th2&~%J z@o?TOB!C8K-Bpy;V4M-diQ*Ms2u0P+UP%1|!O=N@|p-y7&-a0*Q4t z8|K6%l1HH@TJ*knU%eA!Ctb`{r=aaf{ZxjzVk>9mZMmb|euXQ{^N2*ETD*t)5``nT zZ(*GjK%1eC$+=`QSVa#QKFWnOHXjvmCaAgp@u1qJ*_zqVgixwCkyEgo>%33Zd5PkL zS3Ne$NnCC4)j~nivlC`-`N>-Je1bKp1)8oO+1De|(G5URas@6$artuAVXps7THw5*55! zvZS+jl0c1lkD(`My@NBkIebC&m`AFZorWtplCdp)UX3xpcK0#TX%NN&JQ67ivZrow z(;ISbE2&07b;o+X2-xv}fdm@lRCG~8n8qhYw(dS?O8)kL{(GtN7y<4C6~Mtsa+Gtn zB2Nz%1QxUR5!f)6&6m z{wvF&QGr2x&Z!RQj73M%CUw39CC}n!48l70YHqv6A=dS4@WE{q&I25LE*_SdhYT5T zXmGF>x_AJo&^Y;UK?@KI0Ed#1DSW}bJmodL8(!O=r-$UKGg%q}*73Xte{a2-={S?b zhcW17%+efVgROFo*uEBSxeEQS)}dsTbN}i6dJ!;z&*_-YR)<3#^I`wk_e(7tzf+63 z0Nqaoia)|Oz4)SZBVQ>dgvFf8PFcPF?ADX#BCo9FyuV{lu5WVUC!Iaa(;Z;~u^zx6 z*{bjzzuKLcLt7p5V=ANwII*)3FF4-IDNjQVwsJW%BJjd)|5b7B$llxxZx)r?z~H$v zc9+|=b(w&QNfgfLErl&imR#JO4;VR3=bWN(>?y1ZNO1Dk=hs@Y5-Fwum_6$7ToJkG zxaqT(`>0MWFrGmmc2?Xy2`#*!mm%;mG&j&U;B(5)Zmfk6xB`l6S%b}_*G}L zg=b36Sv=DU87=-Gwe#=v8+`Jd?ZMI)dUfUixAf+YQlQ9?;tWbquxS?AgEJms;#V$w zos{P_4AUMY*&nr&ht8cc;gCJvsPoz3_LuL|gN~2xyl@Wnb}|37atlocxDXO^+dIK8 zud>-=z5Ml{29~d2Y*EB?Va1o+sm{-Bkc?}qi`0^h(l?c+$3uxcxRWjH*_wXZ<=~7Q zVCFT>@p|_Or(iQT;HP<50`Z~9arg_dC|L~d^aXAaTuma9=As^%J*_lTD8piNb%pnt zdx4f@SZ2pIO4k`!7bnx>3Tf*?3R{%bOIn2<_uxzbVCS=e;XK`R6IeVPhTjuXWbNa9&icVZ9Le)Ii1HzkU|}{D8E{zaK<=h)PGVkt<7M~g0hlk8laQyB&X_zsdgU|?7Qf0#=0&jX+>auU%JV** zsTwu{piPu<6r}`5$w>rwB;}PSwG5o-fW-HVHvUmA`D1oNz;-Btomhn?kj>QEo?IRD zdO_a0d}6f8`>b~~a^a>Xy$>4Samd|ei%uS}#T(h_ovZ9J{w}nrj;EUnhn;#2wWJgu zEkBb^=2$+j&xCW(^Ls&R!TOM5Tn9E_2gg=+vYppUCrXilKu+B3)CAV~lLz#0E-ZmI z1FGccl-3(-PmtF%bg7)MlP+s_@h0d$^q>YB~{qYz1alhw~af8=z4knfFRsRp7k&Cj9i{3^LpN zU(>883s3NPcQ7HQCyS=ilhb0j^ul;g7VSCuitmZwcd6@f$0+RiMAr;d-Y$(?eYJAg zu@Wj-KV1**EB|Sp$Tlx~X;aloTw2(B=gDb`Trz^4I;DApCp?zaqt0Mox`ndcYD&km zX;xpF?nKFoCN2)^70s|u;dN3GP-a#|0-$qh8h$!fJ$Yc8S7%|#2K)rjCP#r~x5C}J za94P+fy5-^K6X+o3kznBbQUmI*r{ap>2YCxFU;N;VO)-3W-ae>TQFLU+?UFfBf_%9 zhWvct_Sc%aeg&yrQ0;&ayDigQrf=_B3@5C!PtYj{D(pv3l0xa(!$R;e=hXO@}1OmcAW5CEj9Pl z3jBEM83MpQJ^u;oSYT{iF|d+ue7ol6MayC|035Ny}%q+O=$gVG%LE?x4;wA5k92V$wx z)wF}gpN>7t$rxw5RW%tF9js_&hCT*v;p8Yaz&>AG(uT4YyVg`Y-Pi=(u| z?<;Pl<%Pbsw^1pa+@=y2|kNxrE zDJuW{V4lzMc>&E9!XNk{Px)tM18o1K>hAr2{gbm2LbcU6Fr%mqla{w)J25lSb~qg- zHd^%$miP*rI?GX2)(QxLXM zrE;#Eg6*T$q{g9aiiJdYuxtH8D*wni&+aadGT+fY#viMras;BH+=l-FN#&mGahNHp zYPIljw&C6Z=nb?y( zVtl}Pawg%oR%LrVgS9x`8U=w84f(ro9GR}0$;fHc3(8A4@^w+dplDaSXE}E^WUSUE zdD8H1u0g84Cy_=AJ`+1CT}SH<)E_jBRlJ=&&v_xL-^5ky%=Ns|gc{N_anE&C`?FeE z&A!x?CU+Wh_+(#a_N|SYyWl6)Iv4giOGv&AYF{Z48MidN!^~R-#n8SgN!}FS5V-pA znBnsbxoXWA;zy8+Tod%bBPZY7jpvlt_U5ulgt*OceF6Hp^6uiYTMD>T3y3dSS_0x0 z;7O`RTbl-dn+@43_fQU(cBApBm1P8BTCUmRda?B@3gnEU!D5p;>1CG8nDtBOQpg?= zr@X3cA|?6ULEEoR@I99Q1T5`gglviRL_ZAbX<&H#sr|+A{DXU9ny&jBWlfR}R!Q1$;$!{CTfaXrJ+deJt zU9OW-Xp?%q^KXgwwvr2K?4cXJjxPtfy7=z_?y4qqPOyXlzcp;OsmcEVOLH)KSCjRN ze2M5_O2@!x^E^e6-=N>=R2<(FA*a6Q;fr8{=*q%9IjXOw9($82eJ;2#w=pM*&6_+F zmC3(5D)g!-P#wvGLoWiVRd?$$1lqdT=;F|N>dCNpVaL?$se4~3NWL^5oOdaL?;m5g zA#sLn;-XYAO3ENcuyi+s6CM8go&!w^8m%`0-aaU+!m(-jtyX@*sH1I-YehQ76C| zb7+b4ZeL^BPaKvss6=>O^eX7bjO8F{-yYMP5D3nmN3;$~I40pTe|FSCsmgPZLw>T4 z4+tjTo1VV4M5>%6ygesa7v?J6J$w61fx2&FcY_=?Ll~-*5F+g=q?_lZhP#pH$-uRf zU3+5Mtgr^cb=e>hkM4hF=%9FK_uT#ty$|OMf^0pn*Fxh2lv*EtXc2Pj=JfykcRp+s-bJjCb2I{S@-M&H5j9?vHL@h_6SVNX zuhls>$oJ&QiYTz$FeO)rJ9#`}7k`4SN`$le7hv$Ce69;@@$2!6E?OV#L$xRg zB}eiEMD(q+y2sl$oZenn{p>=x6~1Uz-8cVsYGuf7AK1KRKtil;4_<-UP%ZawAaZwDbIA0@e^4qQKH z8tUe_s8NtIWPaqFBxL(^Wa){Tg^TeUIJ=E!nDBSz^{Bmi&UfBD0jw+(8q~zgg zK{*tDnex!ODU$PmXw_ZbDTVZXyyXSl2W&O|KYj&Uf*x^y)rtM`DA?V#nkPA???Od4$m)XTK7KQYkd5|$NBe8 zw>twlP6~aby?aA$_w`jW<@-MFHHz51bK&lI%6+@ndwqZQqdZMAC+_V1%-oH7cJbIT zjj-u?-^qLaFCRsALF!K&x*vbES=j+}|=1b*;tqtqy zHJxLb)*X>sA=7OTiwM*27yM*QCi41>oPIGsj>|`KuHGq9jyB2R&p-IoksYzrP^Vz? z_Pd#&cli}?Fyh(%&sW;Z?Ov6OatoplHjsy%-d!rqRi15jtaMdA_ZgE+Vju~T5RD<} z>SN;kCKWm`adD%eFO!Ag*^DXsQ?bq766IMxVb;R+^yPkra*D$6z6%Md6+EcJ8ynw@ zeVYxLBkxvM6~|Jhn5l37SXR+y18e?$t>|rM`=&(UZ6uDKm6?r;32cz@IjCFMm^Gp~ zUN2LHmpXf<0_xUk8;E-sCf!3r`U~<5dSI5VNvk(KQ^339Gd9|6j8?*@jF2pkAFW!2 z%Q4{=PsUDsf7!Lu=a|WzN$1a-S1zDKt(^5V4u$6%`*nVjlmj7*f6QKaaN_MoY|fJ- zX%7shh%w$LJ4cvlxn`&RMbPcs3nMNhri#)&n2mic#?2$KLGLP$pia2pwEo5&U$%TF zKysxdv%BA)?E5AH+rLq8Jm&V;`-AZj3RG*0rvm1_$|l^ugF5jIqXtO0km>M1E|}A} zBl3)QByegNz=(0LZ;c|5JA!gj<1PbP$wlH~bG{j1-lHrSf8V$8A+!E;<5>PnC@mGk zgWB^T6foF@s-WkRs>st+p+OxfGNBagJTL8(8t5Mn5>0`}@E~gdB4|!C9b(rZKwc5- z;0kRkSy?V}pJr6B(aw&`0x}PG=Y`U3zOtGH%X~z6b>^aJTaN9TzzSbyzL&b~h(NpN z)jP(%JH`8ctTP=4Sy8ofL1YlNMj)op=4Ox*~CdFaAY(qu!GsQ!maVQRTJnQ!o6 z{&CBkO! zrt{ug8&E0-J275QN@=<#M9-e9kShsKB7<=MUlUu*-T7=~ zuYD{Np~Fz4F?B-0HY?6#9`dCu)pi+T-KyOiS^wT4s^`PPj`ezVHSLfDZEZJAweC8N z*@%y$+Aq!>#Kv5z>U_HgHFNi_a7OC9_zS&D9X?|ruyA4Nrua=Q=(u&cxDC$roz2~u z*q}?0@D7FT5yB(QbafZ2QLS_t1PGw%0vy-0-aS&$%`xCGz-fQRuX6|rAJGA_IPvaK zx$DV*2N)=*RtkWrFaY60<9PmsYca9$AgLfg6AzY9;ftgQe5oD=;_o|6Svnz~3ZUr{ zwJ}D;%lM|3g3WUy=vy)JimMbgZlvpnf6ijf-=?7|=vL0Q`=md1ei zBN2ajN*+8pJ-@26El3JOi%gM^rh*LzHV#t%w|9|}3N}MKlk5db$t)8z#B>_mDW!`g zLO%;@Hr4@bEI!Z5&8Us9WzST$Z%(4?!Fn;jj}-T-`sUfxFU9h#*96u;KtRf1erIcq z$JtN4Z>Isjt~9+fohy2KN1|FGUiz;KpXYxdg9@7Hnv>414$VgvAZQ2cCx zt@u5X8~>p)67R_cOy;%6CZCru4~n+doBX853XSv9$=IZIR}Lyp3O%5O1}oUl<@14J zTbK{yweb z%8S*?alRbAQgs@nHa_dr%21vJZ7XLgje}HM85?x!t-^daj)ZCtU(O>YZ!bf6nvbC~ zRBHJu!wkiucg9|fo=Uz-&tbKBicN_wE{8gNk)c9hAjauN?ai|Dbk%6S;@`{40O;i1 zW$lV0CAhTBEikecV-!=w3m1aPc;;PW$D&x0E&9sjz`f=4XI{M6j%|E8nasg zP2ZNqgFpdz1OVVE5{BYhF#i2Z;b#)hsgMWs#8F;1)-rCr&vfI1U7WOi002rsKq)Vx z^s~MAuxTpHkSZa|lZfB}D!h#Xr~jp6z%Kw46l^uagmvi6)qu1Tr3oaawg*^?bJ+<1 zYkBOXO)}=4T*daCmfiqy1wD|~{-W(k_KfClByxktGkm7e0BewIL9EJs*wVyxhmoA~5K0apZ z2IX%*S|^nMd?v>!I)$l7^bsZUwVRwmb7s$mxMG$WIy|Of1XzLRbiUjLL+5K9nbZ$u zszRT)IX$?L2f_P;4F)SUYm4_SCy1*@c95LZ{9V7)8536+YFQsY%wx%$k*H_{mh;iA zjHx*Z*seet3iXSsR<);!OYc6=;xbK&P!iRTn=&rB*Dy4Pjoy&j^&FqJm%MHL9WMiq z(X_1#X;y1>jO-n{By&GpQ#$JMSmOKVt1c&0HY~+BqZ5?IKmSYLBWY1&Za=Ue1|tah zM6s`_$5ahsTpH2gAU~VgJFBHI%_$HIAC~r!+~9RnqO-u9%rdu!m^EE-7ym>8aFUov zHgvXFXL|WWodi+jIaC=k1xZ|zE}|s1Q{;kn1Nn3b=JD3;D#ZzINIY(~?dOYl{i{@wQ5_#9ye==x_>LR^LN&D)d0Juw8wx@5 zVlmn*hZ>engnM3 z5XX73p)DqiUo9Fs+f5602qBJL&Q^mEyXh-(6)yE75c^?){V>Fy=WO2(xt8&O)CI9J zO?Bvkm<=lvcDb6@q__=I$kSri8;S1$*$qOhYXt@N@t%Yq1l9K~3O{j`8ED;@<|cLAMX9$+>pu+?_9Bi-_< zhfGj%EzhySt-tSxb{0{nKIZ=4cg%~I90JREh`mr78_E>py^$}S?T7+-qZ!}x&W^PL z>uJcYmLKtRP`ek9j@Us|BFljTsSjn^0XO#uoCBUGBL5RBw=f&S9}eTrmfCITC#xO$ z@w8W@B8LI8{mtEc}cvSvb-oTcbDlGpJhyoa{Ak56p4pa0Yh^5GTdvQY$Qy4AQt$IM{+yOJe;?k zh_ZkRju)k|znw96ao&d5u<(Fb;=7&nz!omf7ErUZ?g9&W8{niW# zvXjk!=Hf?)2LK?}>~jzU4)eU=Y|-*?+t zRS$KXHDSgp-L>-l^)rF^Jav2Rf(mtZC{7WZ%iizBYn&pZ)}WNjEU~0J@jrox82WXm z>`uFg<=1TsN<%F9?>NJv%^eO|!*k3@>NPw3GgK@T&4DQVNLA%IJNF4}`&ql*Kuj#Q zE7S^hh*?;1?a^jtfWwy^9dyeTXNP{4ZL9OB-`gr%Du%*3H37Ll;e0=v6}v>YT6R{d zeqz7!=w?97%FQj#}r(IUcei+9<(FTyUbV(PU%yin- zS+(Qqmvo4@e6zd=ZB~Uf#7tYT&sRXQkoanVYqfB;SUX4p2DROaMznubLr1vO!t}**yEU$zby1XAhR8dYGf!rmC!P- zy`Bt_A}>(( zv5J3iY?fV_61`VS=po}$M_$fJY!SE6aHkO@yJDLn`8e z`lX8*tG#YGV;H|#O*MV1B`>%(0xoYi8G2Cl%Z)aXNrC3bhZa@uLOrI`@i77GzUHQf zPG!t$*`ag(KAvyO)YAQzRWoPz=%A&arB^uN{hlOO}=NyhHu2bU&wZv&ayQv;s$JxV@F z1i_wmHH+Z5}=;F`O}@iymqtJyB(o*Hg)YBd!F?V>Hf+<(EDC3;otTs z`$c()G;;ANXmZoy(4VyE5(n%amx@2%PrfN(*o%4(Rvl<=jiyJwt2tPE*y^a=*-ZKL zLv<|q6CDkWG=8pg1jQL)*yOS24eJUq<~&V}dhl$pk75(5NCa}i#WqJ?;wG@Jy;CG* zpr0LBD{O5%7u$U85=tcvxYeLdCtGUmi~_*c>@jsudtBvB{;Kmii@?KFf1Y<-!9&YA-Nuu5xOiR2(53REXwqe921&==*P4S4TD zNyj%thOS!x9dWyfCw*I&;=hnLFV`xBgZ_ej=-7RVd@xF{i&o%@MtE;k5-W;I0mDq6 zT&P#i64u>q&msc}8*h-*pSBWx=*A=r*GmRdU5*S=a%YKr@JYQ9Y2iuu!M{XQ7(sEV zXhH%M)UYir{eh8EJyT*32fd#;gYbSX^@aX0V%gNs;a#L8fhW#u;_i_e=_<*hH#)ik z5ZjG1?ZtI2%#zNq*$m)979OfS8m9<7gso|zP9YgvaL0QA5L&Q?D*xB`qpe&Pfk#pK zvjs!5V)19D8LGeV4^dkJ2q6oi{@I@;?1{ayhG+|On}wgK+APWBXd%f6ZR}$P4hf2s zc*%LD@4<8VHGjZIK@wv1xU5KakO&i}&O0odBL0y<2umV$+p1KlFNc`_Uy2htlzJ_i z!$o*f7*(rOkva<88Stx%Z6Su^H90ieCdC!A`J*_i2ZAH%$&j|+DkQ8Eai_K2rQ-de zD)ZT`ldUX zC*E@9=gU^cRec|RNTLZz`3wkRp7+q9KS|=@2|M0bm(B&VJ;6&7g~p<>B|k3zt-z-?(H@eJ{S_RO;ys+ zI{AYLGa^$Gc-RstMM+j80{9zE(#oNLriv*@ssul%`xjg07NS;o&{=fucRSy*qzz8o z*We{+EsZNo#DW!L$%w}f?biLLgRg+qzm4ZOvRJt2X!oYAt%vf(wsmHzNR?~zSS(4Z zG}93BaH{=<%&(=1YELb@3>Ejp-+J07vH3Sut!r=}799SR+EKOff6@?C=stTVRTt1+74dsh5PVx^KZ%iXIOLIucLAOFGtWH z-=38)YTe=GBsW}Edc6OaYeu5GW3z?G;c#cIH4{EOn#H^|Nx z_Y8Q#jup;bYnS=iJ$Al-vgpp8C8hgmey2`AG-RnLsVzRzmr{WEo50hAGd1;;G11db z@`ALyd5fe=n!*J|=7Sui)e}2eB1`hI!$Z@LZ<-A1S6#EvLgMGU&~XtCa=EEJs^*vH zB%6M~>W^Oi-N50w;wd+yh&=TwfAHJJn4FkZe^JZC z=C$!sh!ofG?b;+=mRl^_cNG@R$jvKQmc`oTY1@?yvVX6ronIIULCUG+Mg-E8H>s+V z&D!NO$}0M44_|ee?};r`vn{v=EgtVP8RssjFH)787}HlYp4T#-XX#c8L3s2P7-@k^ z15HlSR5urt+TW^g5Q|$QUvNMDV~QZKBh;xVoyjqf`V?cjSwm@nkt@r86W^h}siDr) zR{v42meHYEX{6E(L9794>wH+_!LW7-?v+p4QIt7+d?E$9m$!5N2337Z11%iUe6FEB zg;~C34Ep}GZA%B)BUJgpSMFZZgyksfEx-A!q1Mk*>EQ{nz94qYG6CD>Hufr~z16Vf z)rojnDO0&`969T;7=27E*9&y=@ge^**>6`5&cxHm!JWM`+R54G?s}3IKe2xM?kgVis0<{k%`?PysOo3v`0#=8#rkm{2z;$TZL41W#Bu9y_390g-~*=B zulWzGM&Tbp2ot92CPPWL3$en>>*6QK{-0b+2z!jI_rG8aR_$k5pR7=i@tXL@fcMm^ zPJtYrRj58^VD$!(d=yA2lk2&|DkkJqnRXXHc9&qZM)~0 z+tR~oU$?0{)PHIxB86k%I`6yFbXap#`aeyGApj=w{H0RiE{!^#Oij7cAE%}7k+^^! z7wkiX2;F7f%)XFKr1vcVfs*~a1|1XD-FXAU1^~J*5~)v-uy9Aih#)Q<_L#fPR9a6E zrNTD*NfYQ@(=sfV#{7G4t{({uXxc?38#X;>wgze=>3|gtLZsPZfjx(Zes`4){xg}H z)G%q(g`KBPZBk^~2XpmejVHdS<6YFJ7os-J{%Kbz++Y!Ih++@eCtMk!LVq(6;{{BFg}oW|8DYGbpM`ZMMBx0;A+%4V{{fk8#S`CUJ%bjp&yx37ChOc@jHz^+8+AJ%l5*Q=k?hU9lMxgbA%un!!Gm1M zlIJcAx;Q#nv7|hlXh7Js_>e}IT<6L}*K0IuC`M?vmm7EW%P!gCRUTZM^TKr3GUD|= zR!j!ySX@>O_>w)|a^vx5?0~_|K!a^_pHGG!z7<75l`MiwcpuXwtp_fr3k~DF7UX9B(Gfaco#VLy694~Uo15*~CL#F@+Gz7@=5O1k+VNP3Zu~qP6@{_`?Jg;JH z+eOv&dc}~=7rMnUu@7S3cdBegsssvi_pOv$@($CF?o76+e&{@72(?S(Nhe1?7jl&I zn-EvHDr=)xeFm_%J3oy5n0szzH`F;lR;+D2kZ0I@NDRyN&7?ANB>NQ6PBo1Kis&9n zMGLAm!bbfuLsE!7|87m`ujo@G_8V%D5!F}kV{ht0{dzEPGfBfb-ajSza2d&2!3}47 z{LapU{H^i)Davgvj}U-;S#u2dz!N4V_5(soqZU>qH_3 z0QqQt=>}{{?_`=>Svc=mnbsH*`b*27im5VITpw*2)Vf~9+bPgg^E99*9+1`LrUag$ ze*wVDSV+nSXn>BeKMYagx1KzVSZ-+ZX5a4SN+~VC{w>6_pP7++!ty3cRel>M8TS+u^5Lg@2ASuFmO;Q z4-YcWr^hN^Bs>}BETNWZR{NZeZjcUQbel$=W|#rCye%u@%|0QjZxL5wnY|jD|G@0e ztwzJLP`ot?QLd-TEEUz66r9~b(1HgJ16)sheR~c$P8ul)|9yE~p8ee`~`OY>C#r%5g=?e$M zRh8K!n3s{|92JAcNJR71J}*q9QE-1(cI)MwAM&~IFH#~f0t59t7OkO316{(%9~LoG zS46xw9<*KYaYK^}qyVlajV@&o5-yKA;1M}TqwSQ{uTCfKt5cqzhb zZ#)l!eXG{YsG$VOE_~_+GLjA?rR>PtpWs%Hm~FOGZ8AJHvCYxHPm)z%f z{_I)ya-eGhskvnmS(J1q+ju%%wtUiITSLK7K9NquS1|~)UtC9sEAk&F?FySGDq9n5 zwel85rR`Jq$4)_gxWLr^%=a;Xl;F;p+1}*4uvR&g67MIJ4)Ea8y0rcuO2~N{`X3iF zD})bmrO5Qta5D%A{(XQ+-@$v6eKncLYb_Oq2$+z+T%9T&IA6GKCbkMAudBXCc=15G z!Z)VE*KPAt}Wc#qo=s3do5YCta7CZc7)-q&bTth4+W=l zzAPwF+E8f{R*Fw@K8r>BW<~cI>BR;0=TxcT3Cx%nQLq1NTQYcbYB2S$qFS!*e zs=BsNP*Np1AFXztA*rva_^w_pSq0X>59!uG|Ih{g7pXEhNBgva|P5E)2Pn$ajzLvrp8CTEtbRrA&qQ`CgAJrE|V}9tpc~aFAnk zA!X82I($g+tHe6H3eOH{x+`+t^ON|*J`G7aq9cpq&MRSrJZ1d zTqH4aknNGv+JI8b-?Dxvu_o6wjL;f(|L@dMG-aRPUh%}ORi^EqBOmDTY!-ZyLuKjL zr8S^ry$u8DgaAsSyAH&IkpqCyv_?PyIvy$VnLnEN8lF|;zE1(#|B_48k(PcWt(cPt zI=PG#!n6D-{?KT(6PF~UP%g}Ta6mp^6-Z9|h0+E~_qZTI_K)git>@PP+4WHkAYJt} zmnq>5ta$32ArEN7oZh|Nvzu%m_|$>V>zWC(Bv(AOjgL?aakqyqj!{1L1Ppq5<|O&r zt#!%xIjnaGeC=jb&N^BC?%MT%V%m|6bGX>Qi8BeASsJtbA~g4N5J96_5BTyDcRGIW zXNi;QX}fYLBDA@`!z#BC>mZtUF7mund=`p-^>lTesq>EIM&^Yy1hO$CMFm?C`xZMIN7aL$Ge& zx}qO4AunQ8>?u8!$Mzt%+(~eJ8>BJ5>rV|@pyT%qY(uNf_0EXOzW9AQst=x56V4X} z{r=j2;M1SP2%XaY^?jiI{i3kv$6+s|kxir1!{@=EfE6c2i3NnUW&@H` z&Xk9hw`2oSQsVi4fgqyRfzb$*{@}8a9*s0*K!zRBeE8gWfvW=WL)X?3A%j#%=*@2j9!=?e@zEHeO z`0GnSL#1i-O^x$3-BEEw%86;ng{2NQxv0BBI|!tVRQ2fSD=SSSF)gE6x!w=bFCQuD zJh_k07uozMD@mT-2wUa}o}_Wu$AL}ttzj7X_ktCpgQ)mF;R*Nw^_g%6j~z~!mv2Ws8x^PZ&LXD?Y?GTnK(z+stDP^%JSdV){Y zo8*txR5?dM&g~@s)+mXy(U9oku)A#QmG6XpIa!)(7_P*c4J=PM-(hL=r4H^;sbP8R zLV(fU<~G90!Vmwk%W4Oj9^TPUgiA&}ciK|Z3A|T1Bz@n82yXd`4vgTyD@a7k=09k! z=tCK&dckTN0BlwE-M07@7kz)JLiZYt>j}e<^wDr7+u_^&_urPuXI0XniM*Xjt0u5I zQPW*z0sxY01)wS%I`#;Vr>ZH=y5R~@;&lL$!pnYi90I5iL0CEf)u#iH!4K+cUJV3Y zVSa!f4dI&;1>m~?iPBIIRxMIi9(bf%Gwd?7!XosM9@Q*whyPEG3Ov`#g{xCQ8uHg5 z@-#ZZlYtTmO91i3umn*EynCS~jUq85myo{7Bpy^=2*53PPZaPx?Qbb8T&FD_u>< zp%il9JAD>Ws-8?GQY2Cm3x#X@vvho}6?)e&2)`2DiTh&0MRh_tcCcs2vYCqZtnEPT zyzXkzA%zL|So3;sp@y5}p$-KdP(0r=yaT4;m;UO2VhROzB%fdFmkNc)d*qsT1iZ@D zbCSvM5F;u9Dp9xwRArY-dhYQq2pH+*I>Wa%`jOnD)Y}3~}e` zl~+jP{tm534_EW{XGOl+RNQ%g7xzMccu4l|3B~(h9pkU1Ev)lW3V+#3v;<5nrvXLY zvB&4iI>I+xb7`L^Six#EZnvEhy29T=XMpmiH%%06!U=TN%X2J_js>H4e2F1inC903 zRH^C}sM<*J&w16b^iY{AC!ojMyydR;LXN!t>_2s1h&guFlKnTK@l)8{zgG9pwrs{3 zWv9EvQ_+$5<>Ut^Gdj0+N?oMnZg(;*umv{wO#H#+?B z{@(#r`_HeGmKu5HJIQhgGM^NFs|V2oWw}pTn$YC({Tffdh0Az+IvGn`ggas4c`VAk z`&w#2AcipgFTo5*iE_qWjv%8^r^4X3=x(g4oydW1y zJ3aeS;>Jt4y%eZ3EjEbb5I})KL$eu^5~8B|Q=bpTLIO0NZli+<9yoXg*DQNn-obq# zboivSDS-XO#a=HD`gStMW9#?^JjmNRdy)wmCSu3%*5BCRc@A!k1K(kt5&IQqx}LkA zkY*;nujP?F^5XC%YTo{Q$ey2yucy%30E9N2w@)Km>7~@0@9{JOWP$;)B%UZ-$UWG@ z(taHpOntQ=&jQq@)zIRD7nKjAuHMHVw! z+|dawqJa%70hcZhh>f=R80PB_Lbw1%2*?5D7z!vUIeXvN()AVz#Vwr9IS0uZDOEFV zlSc&QxU!<<@-wm(&I1IqxN-#>e3JAwgWgh?-cqH5e$zC6*WOYCA?APU*isId)CH~@ z$NoyhzPeEv)_e9h+3)8#+JJX9%BCuMPgNAMIObecSV2`^W7W;~Rf)f3BF!E?}`YmRAIL9+u($2SJ^tEKoww(UmLRV@fgth4Dx8`NE=AUmZ>}xHW zZ7uoTdONrh6JMX97`~WRKkAt|(p#N`YODL*##L%>ux)QrYCRJG%_Klbl>e$`V5kv2hPcpfy?2FHYDEV)a`Pa2uSSg<(jbeiP+YPj4Iq??t{26aVUVH zey3*#*f>ct!P;ylu$?r-VN!v~#AqBj~-d(n?V!3m@^Bzs|*aYEd!R0q( zc~=TbFplgve+4Rw=F^cUR|N>pdM6l7fyd#&b%!8rOC9runG3%~K}XEp z6yQ;p_n9{^2L9UHwAvF->XXmhu12-IxNv*=Pv3i;?rzkjmveU+;rF8Z z?k;&%`*EN(Nj-%Im-`Qw)M$lOnO|9Iz0sr~6YLL96T<4(y)HhvedHQ=ik{nfA-wf0 zltzcAabcrE1NdLN*9PHn{2RZ8H0&;Ir?_T!ddoG48R`%(sGmv8(m=zxC zMeixd%sZywOcyxncW!it%+S3QeIzi^h z8at~e{X|C|$senra^{Y0Hr-yKkN|0KhQ)LdC`2~REALG%q>5+tLL#b+$dg{wylu14IRuD$o;@>wq)>;Zrh;h~?DAB=kNjlEFK z0E|XKbpevyT|0;>s3w|ZizcR?hH9fBCj+7ME>tV2Z&C_%c^ugd+Q%_N-0DIiRnV|h3H{GQf&WT zzmsB5L#n<)3joQ~b!i8FN-JG_oa57cIZLsB)=fv>z9xQmI3*Zzk*;4z>EIwB_IR;h zEXi4dA`kc-`XjT!LR|zf>L#y8JnIStM-Z*yE(TsQgWhRa5ufU=lI~qhM6Ldy}m(|iRo_X0Ngi{;nsldt7WLAc=Wl6vBN<49FsYc>Lq0~ zzx=5T?1W7pSFyW*`$WS2o?PFEOW!Do zT_}6b?7DgK$tV*v0kZUfwO0u|;RdsDm2BecnV!H;Zv1;Y!V5co-$meiB`d+Xf?s!p zcRUukv<`` zBcAEhD|hZ=;p=GOPb|MjED3j_FkTeCK@i@ivw!{7ix$?~B?>PSbsXHib%CHUkIgS7 zUp%a4BU{|(6ouI&;Y*XkiRgnfhJwYJYyXW-+0lgvpv`Ypn+hKU zPi+myDDAM(!apXLpNa+j=l-tl{`}eB>m50tDhKz5PRu_z@%{M4?*X^JH+}woD{9p3 zB(wcZ+La6Yt0Ui^ze)Ysz{~v;-4f){>=FD@Dtdw{(j8%E}M8kX?C-4oPh4c;fQ=UaHtR$oM$n$0f2 z7fYc2bYA9*rT2C8f4jnMC7Og5!Ou3rQ;Nr4J~v+Fg|Vwdt*u<_LGTt<4%Zy!B<@(8 zeMQ-Ux!e)*Z05Gwi~lGQBDC-v_5cIo+-_UiSwttct;dSw#s1!YbL0H$;2whRzrP7f z*|b~9zfu@ODPK=sHY?b(V6GSWpzR74l;d{c9EfiEUKa3JtIeqCg-@4*Mi4$59yNCO zeB0|jbraRr*Z6&9->6UD!`!yf%5VMnrt0`Zzf29^Xuq1^C$|cn9^DJL6E&60`+H_% zuG8gJdBhF>FTu~Fbgz#N`|l8XbA%M^D+9iU4iqAfNNqjR@oyoq`7i7q%@dQ+TdEws za=+p}&ROqFr@Z)SA+Oy}Zv(lUsj$4`e>(w;Awx|G3nD=G8PD6E^jFwX=ByCZ^|90C z%2%{)eqmK7$AI*x!vh|u%ZqHKPRppviXV166WT5L@_qMr-e!H(;l@ern%yB5)rj|` z&qhaeE6YVMIAS0O50g_0=lswbkZ>`tTG(Swm4@QY^o5rosxm1TQ<*UdTz=&6oJj?v zE9o!s$u>dN*JuPxb*^&!rS)6HlmjTtVu?Y!A(?*wg&NMibhyFE(&(*H9DeI?Ln6C3 zL~Nyeq6&ge@lY!B7;#*x%7*-;$!GRH2^aHTtR7N)VDxFDwic_w1C_`!Jqkx;{I^ph zS^ne{%Gt32GiL3|sLStC7SL>K@d``SYXpQP_C6Rh+w<&1y?60yGWh&SyW8uT;DpC) zXuh^9?yp4KpmsmM?;D>SL%(CE?sWPEo;xw3kM*V= z_Kj$&Fn#@TIIfX=Le^B}Du+ofP4fREC-tPOfAL;yLU7ERpsg+ktNn@Mi$1;&#~KFv z`nUPKU|B+w^t^!V0m(pE`C8fTv(yqB@-?N!&LZP7Wjb0Oewrq$F(%;zICAOhIUCvE z)NZgNU6D?bHuUUMIYS&xN#ubZuAqX|5oH2JPC?jAzz3Srh4yJTxD+Vzh2M_qO!Ed?3EAlq{(dfOxv$3y&MCsNA30+LouN1baX6fTG zNv|TxvOG%qs&rou=d0V5!$FvJ6MNUoWj?4J^}G8J>C)$-2~qc#BNEtxQ}$02b&g)Tto5M$P^q2-f}TYY zzh-ZN@z;)Z)Ny{}egAMLt#13HlHBCfgjx7Km%S6NN*jo&i+=RNjJ_~LC%893Lc*#F zJN58#R=okVp@?UIMfzUVr-GcOyLf2Hiq*-O_Lt#&h(tN2wSBbr4MFdM-E8%s>mIS~ zJo4i}$yeAxi(8K-ns^oY*5+siBoB~r(=v)LY1oD~Cq+Yv);Q)(@sqHyW3FMy@3}?4 z8XN2xNxDTG!?X7Sl7|QWJ2d9q5_nJMgoETZwe(J2yiT3+y1nbLZe6VMl4D%sht}lT zXSKt%s7q!99_cwc)wFT>*Q?+w+d2HW5}-UcM9~k?D~R)$$@=*l?wsaL3^BY#O~pP> zZ>p95QR1LBJuDgj-X#r-7_bevr;{?86igrqn>NxbR~R6L(FStH#?(ma1ljS!0bKBT zb#Y?JT{HKcTY7SVt%Fwj$hFIwhLn5n6d)12(~eGP;%-3(T`A}rKi+IxMO!|=2DN`6 zBN!?|k%+PesWtF;dYBx2%k5)I?&6_^0>I(6D>B%jd9(+sI;CV;Zk-?u_D$)})!dbB0fRN6cBCVQ0o2?mNb7I0yGl9X0n`W>#MK(2>%#K|^umKk z%ZP$Ne6q0(=A|Uwj27q_B4sH7g#SsCl7YoEfDYP0=W-d)`DQ~KEYSO5gutbLA1$sl zc0<~kCn$zmN6%@WHx9v%zk!Z<8S_&zL1K?y?5NOzhr**AezS!#fL-#X? z{i$kAzVpKDlVO!1>%wQ;Ln#}Q8NRerEDx@_r-Z4G{xH5 zOI&(=rz8(Ol$#5S^Qc0=Ae{TO^HH?(M0iF*{U;XVvnM67WFVQqeci&8p(aWLG{qwu zfw(4N4djZE=Xi<`B{^XQ(EqMM!?Oz|t@Dk{ALn;FCIi4MI?ye^7#2gj)NP+QuHApw z_Eme|-KIYKZl*<(^WLt7YqrJp>xP5ooIcyS;roAvN5a%YmLJ-JUs(y>bg1lml=$j# z(8CTN7r$%H_o{d_x_GqdSWjg;Z%+aF4KVjzxpZ-7!Q?L24JGrnA?T1)TL}9r?tBF; zfo1d2JDZq7O9`+~a)ithrP+>7DI%j2*|fAB-V&IYiyAF_??_q-EhfsD*a%JPf>0`R z?FGQRODG~?^!y4Wwgsw?$9J>_Iw?PzLZVr#jd-c^IBr5t_fm!VOG_QI4kjMtRnU@J zxM#ceiy4KU?OZw)dX6sosly#CZjRqB1wm+?n(oZC~aqpSjkc)njopc6*#Zvwm zP_T~t*9F~{HAf>I$#pCa`4qv8lR(R&!{iavWEMKF0h;Pa11strS#f?)`AVqpVOOQa zkgo0QJN%PGLwJ8Tc2cro%Og_2)5g|w0Phm+-5338_=vnw*YpJPN}tcA;oU};)-D&7 zDjsfT@{>w_?FNcj7mx07A&Zur>9!mfR&Qw)$h?Ju6yQe_LFU{8ivP;Qt0~qM*%n@6FXqm!Y zQR60`RUr5bQ@o8MCi$Mgj0rw#4MlF72BnTXn2*^6G$gns8+)K3;gn^jLM5bt(Q^id z*0t`wl%sYWs_F_)9PpA5xOpy35(NO+sz5?_c>f+g>emfTBhurOD2dlT%BzYl<_7b@T>)cTe1G!zKkD#2;GcW|wzT|Xp&9=$-qKUAM#q&g4FBud z{>SiX4D!|QhKz_loW+&?ubwF0Ig(b(Mc#=odY;ez(B6ALO4fQP$84nFb11 zv7VjB^Pe{_y=KNQnWmd|I2|{AcI@`e{6)EWd9Atf z8qc~k=c0(Y3vMo2W&z%ez%-Sf$<22?ZytWLSvW7bAak~pc%m=Iu;-6i5c$o*s3o?? zQt;*b*>01q+3eA>`M|PS(Xz$bveo|b5y*MpV_Isql6&j;hFCDDH0{m79?l=8}7XVT&nKvVXBG)3hq{y1*$4-^=bQ=CQ zA=R=r?hL+kN}G}cMo855UoSFA-h8@ywMDrQ9hQAQICL;vl_ zv1g|)$9r{rjbz?@?=qsU@E|zR0yV`O#VA=l99=3I2^T9nW+@ z(T~=y<&f){g?VFy`M+{`Gmp>l$W0&a7djM~5qUZs@1NAE6Mv!`arUIxiPh|xk2lvo zx(82%1VF4)z^7S|b95?!l~p(j!(bq1HXyah)RDGJHHp+SEXWx&#O#3c6z?rme~WsS zMLq2Zv9M-?U9Ko{O&&)o4xxgA@v1htTFN8e{|$Ol^l<-p=c3H3XGQ@&_|;pGExJ^U z^&+h93{-xBcCkfN8z6SG8k}?h&9vU)l8O=I_Noo!h!SW<$<~D-X!uiF(Hhwys=s3s zN+Uo`M&4bq&yTLAWwt;*dMYMv&=SWdMJ+97AWLH3oh1uDc0cmB-8%DOZJc4Wy=)(A zx|n+-{A$7mHO_G$-Q-;XJ1ZW*OqzqlU}+&)%#}Eybdut^DCnhj=$U_f@eK-FW01rK zXod;x@IjuLt7L`sxuh;cSsyLJ(c->OP+0KCfD03HC;Vk{IG$%H{-RpjD}Fn?r*>q5 zx4ENvW`RoIzkBQho*|kUNuL9pK^9&+}pZP2O@bB3_^W*G}Ds5M7c5(GN z^oNrs8UUiCj)@kxrjc?ad9pOrq-$m3;HRNxUDv+{TpceeMi6-OT6iUhMTnH_q;%Ka z=(3K{ukuiSBQ4`7G>Ij85@Ix(M?SR! z{dG-&ONvfS=OaW8rIU&gQC$}ih}(MVr*)!2Hs1%-p1vnx%aYpoFy1D! zeR3i-qXiM5=I3T2cK=9X$?IQU3uz|NyY~lw{ql;x{O`aln%!aicgi8NC*XHU)bA_B zz*D)5F~y{WgDvDGavY&8V?suJ;WuK3H=_dT1StDw2Q+X0>Tq>$^28^n2GQUhY9!jG+&)wJrFKhZK08Gq~ShB#HAd zduE=bdcOQmkD8acV*YJ0d0r7O%akL=>QXO9*i{;xx9@oCwdQhLnzgN%YdWk{p8tE*SQs3V9 z|8fG2!W`kIBK@cCG;5*I7W-HK(bn6i_=jNrw7R#fUYfX0>>rcemEo)U=eGZtCf>w9 zd{n2YXSUpbs~}-v%-@-*ERD=Z60xS8`&DPn7}KoS4&Pi1mEZmcCKr=$qL`<0Jw-8J zy%8ZPlG4C*$Le-Tx|`1ue;gI#Xx5II?~Z`r=I>Xk=WU`gr`#>R_0<+>t^L6l6qxw6 zh7~)vB?uulfNIreg}xGm%r`5%C|M`?zgKyQ4(!jDN7ozpxJx}(_qoya=GeO1;ZILg zZ)g7csai$mH*4_m6^u}GabkJ!Dpi-n=gD%TrbV5tcdQ*$>j*p$VUADSe>MIF&d#c( z(dv^~J)Xa&&Vnu+&!(yUJ#?zlgu#({)A;Do@y(mh=AF(o_r$^`9uRlu(bX?Co@us^ zn*G-77&}yIduvMg3K(uE2tLyyC`o2on-0&5J(^!4YTQEoN`BXo+IU>d^UTu@?HI=M z@R+9OMVt3~?k%NbZub1!)Q*~v&A|5Z9qz_5g>L88GY5KpO56|)%+MW>In%8>i1e0k z84Q_tH{FN1k)b!Ne!pAq)l2fiuCEHyLVwioU55Ucsa%BUIWw0x?XPhHmIf1ca-UVl z9qy)9Pr8}^HJJ8vu{3<+8<=T0bL>oy;p~a@zlL)mmn@CmM%>6Wn#Zo+FnV|P*}=4O(etj>18?jc&Q8W3u#*E;yzRkcnhhl%bZFh`AMcd`cAr2_s z9WdSAyRl1#%@0QGd~s@kO`07HWX3Ji#3zQy zv7!b~W??J^MDKXNE}^B&ds;cav6d|}h4On=6h$WHt2@CcX8g6n@g-r%eLB=sPnFKy zTGFgKD#VE`S%{Wq%&R~SgAMBw8koi-zg0Pa{3mOEB`u$`=>S{olomc|;5RwUCM#B+ zDo$x)VwJXpjrZb;B)H+moYoUwp#Xt_m}UNXFQ$na^N3I9C)$NSN@!4Ojp9z0+$aDq zdZ~&UO$?K?_K+}|lrD}K>P2~!q2RlK;tWj?ui&-vgD!@hu+u&HUtJF7e!#+v+>*fe zd^D@!QZ$dE3S?}^!2%FhE1B49`5cgUvq)tqM6A7H0PG^vG*O)98d~n23)IvS zVISt8rr2uWF&2e9c_Y-S8JDG~sRQ4JsY(ZavrhU`E0;D-G7Lzy&npR2V55P8q3C;^ zGAa)2A(|OyddD$FXbJhVf~x;UWh6|mqgpt#!IMbHOJRk{&W1P&{(D*UjSwz7cHkgH zAY6*I_f(wDS~ZXH5PEO$i9^57rDE$NgEV7*)CgCIvFZo zpj2+s#+{sKd^;Lnp5jgd>hVwU>Gh*!epC!bsYg8SO!M|VJdT(7+6tet1@X4zJKe}1 z;`paN6@w)QI9M!96eW+pu^ctI@AYq9bTBw9vu+$UmT9OpkW*yP2Bg6(zaD z^dbM(6TatLAJy4~_L(ATi->fJ-Z)w{)_kw{{kBBv&5~@{5fLiRfYL1Y2IIwO2@;B0 zMjfQYCcgga^E2`>L-+!5jyPVJ(S#Smme^XD@Qo0z%#tIm9jr9O{p<^vmam4~r1AI< z`g&lfg&I#mY85c5GTGI|GuBG}SwY5ht+?{RdSZgl37GhkA$#rXcA+i&15GyEgu+2| zZXdh!(Tvrj7Mf*=?wIm4TF}dG@Kf~n>ypnVxfA#O7XNe$JQX8ae{Dec7eoXDI6-WF zD-~L&M)Hc~wuBeL;74O41XWY*;+hrH_7mmDs^xUvne@5iXMi{ciL*Q`u z^g}zBaNa38&3uH|C~H8u;%T%bNx&6^2!ccw^qlUdmOoH5!|?XC)M*+uI0lPQ5ZxY> z_l>6PLE$^5^{?8tpgl&t(u z0<=z!2W;39rZC^0(^9%#5_3jd5?3i8I878D7F>!gD=D^G!{q&ApgA%J4K#JI7f397 z2GvGLnB0Bv?dG@2qryNQQ|E-@Gvn!M;D=;&*V>|xDjv!EbO>w|=bm@Jx?ryXI^d5N zEt)0B{xE?WrGyBaI^d<9h~N`eYps~FsJUp;Woxn3Djb+tBhDn!Ea!oz3CPa%3mkLS zO}uE-_VVh)<}=6NKuc&Auy3E)_P6)Hf<&{BrL6;pl(y}UJ)ukmj!BqMWvkVG$QOlQ z>9zv?iW8sMN~pu<@(hor&U1kpSvk!BR>H&I@1<#qT09P>Eg=tTNb~YAzFUFc=|YJj zKaigTpr%yajC0q>aw~{I6NBpOzCyPUYa7(IQ_i&TT&0#xj`g5PO$ZIluo7WcVN7-j z&+-x|NGGpJvqlClGWg1mf815r%gzqwZdEPo2_V-;xUc>NNpCRFYBuOD#u1T;v)CY> zrvi36)>f&xtUi*=91fX{vvM2m3_$Zf?fWsuP!7maVMz-j2>HBKf@5eQ8@o_9JHscU z@)ORU;pMhfP!U+A4?;v(0z-O(7CTfehUyp6t`@h#NZ40PxML*!swIOlQjyhCu^8#( zYUv9Y1hpDbgpnz)mbrzItq<`N`cT-4@#zZ5rB}<2VUXpcHg9AEW$kXBz*Q3&Sz2x% za_l6D-0}Wu3~FgwM1;5ih6A!pEAXmy!M2A{g&cHisw^Du&_mzQ~Kx!@MLpI?MxRb|gnRx+z! zW^f4{&1Kd7kyEzI23C-QRSX_LR&-?=h%hBR1RhA>L>g_4hndE`bKQcMoOs!u0Obss z99&VDX+3q@4<>7`j_F>MacMj%D#JNH_~;Qb}=B zpENGR6GU>2D?xfqBxiRey()@X6UB^3LCL#|l=7J7Qo@Qr#%Ql*6P%ERjd2yzESt~F z7KGe!GakUJ2H?$_m}Yf&12wsPwx7_DjVX~5@f>E}H2%r4RK|d58eShl#Vfbj3VHMz z6V`qj;`LT2rp{my68UV=npq{@2+-?$OC`}>HC_#e?(5ZAvC$^-IA{Pxu}YE$V3BE@ zd6a`#A3%dM&9o}ROZEW{O@oe@fcP6$Eb1th0YU#(@Mf@S8#>)!kNKSiYI|GrDa7V) zRPlbmQ4`jX!<XQcxnc7n*Aoj38dQ$I>J3L2m(n<0;O|7B-tpd%5tp|u0~5C zpMI?#;t?msko@!C-`oweq1%Zw4TWMfu|2wkM6c!w4;Fw|$J&S;&>b$Q-sqznZ{W>{ zIR366%PtVAj-=l0qt>_1^Oj5 znU@W4=OoU&1(}L4HEcnP42oim!qFzc1;;QGG({^MztBpNtAYv&;zK&{`iWUu91`;+ zSR!qjZrokTeF{xYrkR9&oUnaJ3tm5)N2i36;epRwXlQKyl!n)?0hg1mr|b0nb@oP2mz zF%Ly6fT8CFY)N#`VCASN1I_wCCM-&M5=Hi_wZRg%S6sFz0&mFqhj%}*c{T~E{wGH# zX!@in)3C(mZqpUZGPT1RSq*3B&U9?*uP`kDO_?RVT-s0#v6>cBoOQug?N5$d&pV5u zK>j9MAtK1CLg`TnMfRG2aMj_qw59%;2k$Qzi2E?aMS$k>*0Pnon$x|~iK;KEP9L8G z=@1!Q=2>q8ZxlsRPo-GhQ??SsH$sj#oo0^hH(mR;1+KRViFqJ;T7a+F*V3c6u;7iw z0!Y{Tfg3<0ZXWod@>obomg^+Ye1lS$A*xi>pfA{`1k>svOU2bw(?|$YwO%F7b7*Ud zB^@8S_+Zcdi)Y_zVB4}(Ot0n$4>kp7E)|=WF=vIQsBor1CW$tdxp+yzc`QK3asgy` zT|zp1du_mby*dAK(o~eBtMM2}rDHsR?6LU?vSssei)!Y{8VLwRN? zpQ);#BTNvU8t#aFp$pL&mxG+y>AT1L)&`P$tZUu?D!kkx|KY6uBPFG>-r}c3ObQM@ zXZ>=F$XErLawYA8dD9`L-ZZH1PMrY+WXnI2JE`j!(fU~mh^PcvRZ?)fTd9kbtCzK`9GR;#B;%$B zwo9aUzY;`v>SU+MvH*QM{}>TL9;`fGd&EXQ1vscdmgox8Pj^gtinko0z^bjWf}7kR zS`pqu#^u8 z{i@Dfqa^*49_Oo0bM__3d&`D%f+f8cSjb`GpbNaQSP&7$2Pm?NO)5NE(f(+^!gQOoHiwt*2Xd2L47O&U}uC?VS;Eya2`PD9)k4Sy`i$A=E zKT>eq_%Y>3BEFH+Y;Af#IkJcUMLd7x0B#+GoLeOYSc5Y=(X|D5M^5q6|Xp2*CrgjDjeCQePbjViq1gbb|%Zh+!Ix9Eca6wn3~*g7LC(U08JA z-|B*#I{Nvq-)p>WYtMNIasy{y&-xxQvjyOiZs0Cx!JiV%%xHZz=aw6r%4%zmiv}4! z)jWE2)n5`_>H=W!`v5)Nt7^_Xbz%U7vw@!R4F0XED!BRg{o8((CoK8V*hA6EIi;9_d`akPDY5wTcvq$I5AD@5r_@a3i?O9i``ID>9p4>KniWjoxH?IN!gY+E? zdw!$U>t6SzqfmnQde`nFgHP|8zy0HjbR_u8|8nFMJX0pi&T+qe?57`|?RGt5J{y-D z#~}~&^1D6gCoer~H&5*QJ@D$cbIP9q2MZq`V1MABfR$%HeZMBzVr}mV0oLWnt?$4bym(mcKr4I zlQDkrK|mK78FbH{o@bs>HeQe;qy`vws0_(WefXG#Bi$LsB;QYnDq4KoeFRd{mq8@b*@7j;+bL z`YgG2yt%{+-;_624WQ`!oYo$S$w-fP)Dp22|J&P6mw~^znkH8B6&qhPlk3=NVHz%>_7( zlRfTEtuq_SUxM`!?n8%wAb}aThuDTy$`4oqPX7AJ+xvqJNpCNvlmPWka5^E4=|6Yg z-@kh9iVsCM##A`?OYq&Hz__4%+7}s*cVO?R&AZxy1C6?b)n~KXueX~_p01ubHTdU6 zX+6DgvwpxFhfZ#;KC?b{!aQjq;8{KtMHO|ZjFwP>K?8?UUonV7$L<(alVIGFjp<_! z$iyzb2%9{E8|$|sNckc17si}Kl+n{3P=(CgR`>hulgBsBvaW}oQiuufo)}ah3wjM< z@-!!hlvH?{ayt1_(LU4BIe|AtzmZ~e?u9N0=bIftr2)5V{w8))9!EdQi!$cYlIojaGg~{$v$ON`kH4QSI-b&kX5=ZKH_-H_kyIR*#nd5oo(6jq5@7_N5;`^YCdyYoA9Bc2T z>IpL)&^>C*M&Ghi+^+6jzx;nb>yHU(-O(=(d3S0Ja+BeuUs6Qf1K2q-u@!9WnSlP| zCkrkyuBNTwa)uLTt7~D;^LewN@+pp63fec-lC9BJ^+S1m`x-WDQM?*FxpmR2@m0j# zV>GKg8)20S0xB;Vd&7lFmM~^F{S0S>`;|Ua+=x=WeU9kJ!+Cv|IX$!zT5Hr0fEa$O zdIQlb^)9^A*J4acF9I`bDRq_)B88pTezaCfj(QeZ>J&dC4M{v$m?M~xb>Lrxq;KxEcYZ$HJ+EN4-siOBGn(i}uW`IVgME0@Pd z?9w+{*X6ZL`JoDl<#7XlPt~=qES3;A!cpn-*A88a=ne6!oK}rjxSzCas#|rnr)1xR z{Z~nn!OB5K`8B18&2XKohgRlD%TMN!MokCrbf%lT2Ed zlJ^NE&#wVR%3J!-{}`0_M0NF@l!AqSp1fER8?ARESDfgNc(g(8s@Isg+h3e5*L{`;SxCGk<(JV4}_&Tlx{Dfz5_)+1-rq;`+gTf>wyt6g3 zftMv2z@BNKR%={*q~x($=o@ZB{6;muc<3?29?QO{BZ( zCTi|})`cC}S>VHtK#}MJVINO0WJttajo^66J?7A_t{rC)_Z4m^>#_<2NR^c+ zrW*BOY~Bu0Qi6Fzg1Sx#c6mUZ0zz;1Oe>0fMe|wgv}VunDM&B9gqZ~yQgaNqLPT!_ z^u^!voa~0&)uiecN`@b@BLa{AG$i69v;-dg1L|xP zg6fK_R+5PnP$;PQWI0E^yj6Sp;Ea2_qbBE%}b8GtiWSYHS&*>91Il0G=&(o zs4tGRgxA%y8-NgzjR2^zEA<#L@qECSvTT{VnA+JtvrpvO{*(Gn5>DD#lHDdbSS-dB zIZ9^Ry+1g6iak*j3$W2Psme~6#TBO-TZ_97VsU5Hzp^FpN+}7|wk8%^$Ih2AB_60t=}oiQ=ew9P z3*&=nk_LIiKYpE`cLvT&Pv!BSYLFAx=#^|7Ii`DwX)kdPsJ;;g58vT;@HZK>+QJB% zYbq%y+=)@GXy>n5SV!IrG053PkEVuG1U`&I-SYZ*nc*N_t6M%|DfLB%Q%>==rJxeY zemU_gphMpEv!>Te!{0PBWim$ikOLD7f^K|K0!0wr%Uf@g1o6p*Du}y@UPVdDOqmd> zgBby%UNpypyvN&`uVW!?93Ixrd}LSUswRTo;X$HM+&b-pfXpv9KK$J`4(O7gM6&Rx z3dC7q70xSWkqQ+$D^hH^f+@Cjcq?Q*ClFte08jhFL~({3jAz!e5h8enP13-TN#$Ek z%6HUP#s`ml5{=8+0LiN#-hNe429NJ(asfFFT9wxp$9p}TdVOP%$ijq~Xf-UqXE8)g z@4}P*xMC-q?&7+`=+y^(M^Vj?<{VsLTyz;cRFqsbtUlVJ-e!SR(mjBI)i4Z$m z%*jZJ)Xpak#;=sdrPe9x={iEJntY3GKY&pCr1rND4pr824k2S3;DT8bS{t*MJWR%) zO{o04ktFit=DOnRSZv@I!XG?nyusji95(NxEAy^38mRNB+BG}I4#0RJ!pD0-D3eZ4 zY#{r?*3*eRunn|FH!jk-{(@Ju%($AZ#b=W~HnAzY8o~;s>PZ$a%H?ygeutdDU=Oc3^c}GB=>j3Zem4Y3)aXj zvh;@#xq7m!BStZwE_AtC<~kWUa!RH|SEe9JdxwPFVVoimM9hScPn8n*@d|xp4-!D6 zJVd61A-9D=K^~$ZGk*dUvO65Yekqk#Yg}c z5`E-jq1k;9pv+aayhgNJqRq)Uvh@6pC>^Kp3n)1bgYBUGJIK6GNC-#>?_~n-*6T^4 zG9NueVJ$=!0)&_2uGe#SNLkS(I3WT$UW`Z_sX~6zl^*!Q$a+=oSrVczPS!U2WZ#;?GzRe4P22{E{z{f> zE(xFm1Yco%^S>g8p~x(@m{;}120TY4z*c6JEqe$kGE{i1ruUmo$T6=raV$o52?KCb zJ1Klh_E3ljwOW;pdEZ5}c-d|-`pr>IRI&n(;$#V`y1-tKNA6f(uO!!{5O@J(xo(U$ z%Td$>B=41lw!xwPVPrx{{4gHpx-X~>pr99l_n#NcsT%ch2n>qJ*k z=NP}S6W}L=jaUo41;RZ5&`=UoGa5C2>2aOsObpo+B@p4fo_K3pD$cVs@vGry zG7?L^>qj36CGbYG zASq}_iAKQO^0?TjTvei*O!cpsGw8kkQ+_O~p6zHb6mtl=Hyq-Y*oxdI%WjE7cC3%6 zbE#t1PxLB2xC}kF`)>r#^9(b=<7qO$_*}2ZH%>(p(AWu2Q8QJA{Sbx8h-nF5wG@EJ z5_#W%F0+P1ZqN;nxW_7wM|ZQmg*H$t3<*cNoi|H1o0(2jh8%K$d*vJE^&7Td0!ITN zjQ|cZl3!7%#(3txptSZEdn|%?m9PPS64gdr>@znFT5)G8x-VqA1!t1M2#q6w%gKAL z4G>MTX&2iul>{bKXJmyazWx?fYIOQavigqg({2WJgT8doYbhx#bbkOfw26sEL%h(u za{^P&M?qB*kZ5c887zWl2h&f~HDF&DCQCGwV#F0*AL|*t;T{6^RG%2c32UNRU#m|!?=h(Z|_!`w8edeQ-t!uS>rw>Q59Hz7M zQ51lY8&C>f=NaEwlRl0%g+?^#~-f=j?_|a zd!rRsm-&H#y3Xra&bZmK6!Z=FW(zMmPL_Ypkn3j1Z#yX5@>XB#40g(vzpN?}ispjV zax3*E;ULX39`cJZXQQpfy&BCH^F&SXp>f$KUsZqes*+nQ5b&vk+$u-bBoi0t@m*x^ z=qmXxUG-2BY@IAoR}q{x>T?!$o`}A_6LQL*ovPVUm(rhDkNZ*nh*S9fpzuAyV9n4! z*$&$S!>!kn4f{NvE=HniFp`cG16Ylm)o1u;45H2b950XHq|5Sjh+H@h zPUv)jon}odmf9z3AMD#EjK^1DHpR*$gs+~l*pRDIMY*!|6A$rKxgtYr;$`k_2CZb| z(-JJD6LF!zeENXftHC4g*Bi-&D!oagqREmWsGX1rVjcf<$Wg~obhM+%bhTVehzOcT zpCTRi3k;*vWyV5~9+%obRU<2m3o6emDtx~VPPaOxnJ>xE$6{5al>&kXMlOXe_WhZ=1UXa$`J=OumO}fTcPCF4UK3CgZ%PK>w6nl z_PqeZ8|0i52x?%$g>R!NF)6urHbU|JvU4T{7b|#Ae9Jj;=voPMQLlb_<%z4ChwZJ)D)lnw&&9~iNPb=<%k2?t zqFFa+=R;Euxw(Jcm_8Ob|JJkC_;uI1-5&6akbhv~deiSaw`SkCCdTYg3PEg=%&07WuU5@h=M&*w7CIJhE*@JUD+&c87sn>VzEX zL~em0OS_nFOK3i-auL+iBCziVuA>u|ApUy-V>x*eX5dwyu$iMIANZ>RUM#I08EOqD z;N(U^%sdQ5wrz3i7-ZbDE=m_j9xNAAH@m3$?4G4mG=27+Po zW)BqyZd|hq=dCsEd9WM_VMsk?%RBq`TrO$b2pp(wmyW<)?FdQz8L0SI?v~JJeogYl zv|Zy8#cOvkTEE88zmAQ!8diN)=9sNu6avWJpVl`7)2df7%+@gGN!q#15ajWmH?OPZ z4u0J9sPut3zymOHBS6&ke&qi+x)*;Y|Mw5zX0tInIX0)6Q_eN#Vc5)>)@B6X)uFGw z9@ylQe)F6Pc-5wXrd&1nx8_cIe@qRy*9$|7D(Ag56O@JFjBRn@@<%0>C_^(XdPc^ju+)4wapl>KR&zOl>G1DlXeD*g9M z5F#&x@^q5xg@${0xh2PMBobr$rE#0V`&z5s3Z;v7D5zd_GM*v*w$vjXNi$6)-5g0k z2b^=i_6swu@T|d9J%AU)leCsVs5WC=?B^TIplS9H(A)Gs?* zY&{W7XNassFUz}d{*Ek;-zR#iVePr>+|Es)CrB83ZnvgdKu}dXPfE<>A9pLjCpdK^3VwVG$HF@Dz`E&O+XhSGs| zj|a;gLEyKaBh)&7IbmOXnniRptTS9Zo}dTt~! z3TJY2@aTc3`(Sp<7uUZglwPOWdMEg~y%x6pg3;d;ztm2`L?(5~uI%J{V$P;YKZ$Zck{_^UpV=FH?aD1Ijh$>=jS*5^Bueesm zN8+A91*Ju{SH&gr&3eU?$8Q$%@$YE{{rBVoZ^@hz?V*uR66+S=mR~et746G2f?JI} zerh2sH~ie+KwaNRC#N8UHm_*!{TcS+JS;k9Pn+{HPm z-XQY>Q6ZS*>4zUMsYd7*q60kkSy#)Ix;ll!$&#(s8ioOJ6!o98+@YSw4KX=t;lrsx zTV2S*soTAZg{fZ$557B^OI#igZPrWvr9$}8q%tt=xb@Y~bnEU>q}4mgv@WQ|nmg7+ zRKZ>WqglriXH0&mF*jF4lm<$Qf_Z<<^NfVFo2QP+|c3OT7C5e{xWXfGh7W zX>IaS5SI8g-RJ+$KIf7{a3G#CvFN}`$NQ{m{Hlj&JJ8b6TgsU4IERxyVF%7t2MMtr zBeB60krem+#v+aY{~pj##x+I$81ISJ{=YAc@Mg?gY(6lIa$pkQ7uT zzQJ!c4YgI@XrPOIF~@d!@Lp-hjj2m&H~>TtZG~Zb`N~GYqNq(A@8esbDTAXz5w?q* z5MxG*Y+~B)aPN5#;WnIf5YB-lUa(tG(0WsNiQjnIwcuEry@dHu0Y>1mA#u}m%(|Zo z_D1Q`Ce;4eS4xLh+UcbqYzuQmKKdQ8e0}{VH3YTI>NDLM8wxQ8a*% zhAQvn7UGXM6^=4YO_TPty){~4Fxgj*e*yJtEHbh-EZ*&$S;~LDgIou z%cvCSNn8$=r9Sk6RdYxwMFt|wiN$&+qvAM=75>6+aFRg!$qXI2^IBate{U77DML#y za6C-A#R}r5f-&zD`b@S2G7exw^M+%6u=5;Fj6<8;CK0VOJt3bo1;i{Y*qL+`8;#c0 zM1S4_n{+F&Ev;{X8+Y&F2RZif8Nu?)%y;hc5s0?y-0ePdGjl$+{L@3EPSX|U@VMij z0-^bJ)5+h7_9jn?3)0lQ&F<%1vzXdG0($Nf?tizf^?v@Rh%+f~%iRN|JWiD=Oa9E^ z71q02?mR%AU*=*KaWh^KN`-N^&F6k$8RJyB?5Y1^6#w-15h6&c+!w}}pU1Jtx(7?= z9YQjoG1hQ?RVWpuqFnV~|0#v`JIee_q@Qfa^FJhH?Aj7$ZerK;H(#S*3pBr9=(EhK zE=Ia8DK0rxM|-xUpWabX{Hp;$^xYw!-Bpq8w}{v3YL320<3|iV0a^T3YApY|{-2wD-nB*kboX++-Ku<7|iXI_L7VKP%@}5jhe7ZYzQnVnaQop|eE9G79mA2K7@F8KA+c zsET+ZlvyvFAqK2RVY=BKhciS5h_G>u{Bb-?-57hVU-+r=r79-+z8G|L3w|;T-X;JJ zx)n2kLM-DD^8)ZhtZ_IE29ZX*9urBTGA;u_g*<`$NpwE5B0s#ja8EcFP%anB7A(fOB+vv^pC->>BDoW zB0~bAN3d9hU&Xaq@J4~s3u(Yv;>oxmkzn7fH*Wbq0YGOjB+^ES@6in`h*GxXh$wJJ zQRWg35sHUh^TdRsVEr^$7}{MN0BR_Lu>=TLi(u1ZXC`s5k_8)yYN>1eIVMLjlm$^f zTAXki@rv!=Pz`PpL(HfbQ?5X1D7eHc_z+ImW1G;_U-);okcYigN7N>upi)PLHk2~k z(sXZm93G&E{B#Gg_zE9e2G1ixIJltI)*=@Oi9iz>6+kQrAcmOWhlwIBL780Y)x|AX z87uYh+O_8*l^o5=emYQajZe&7^9BI}zsX|t3|whIJ?2%%F|qfrs0G5n(pLsctDp?A zgS)`^sB!ho7+L5x;S<*GwP{r31Hpn!q}>~8)S?Z4WPM(Q6dWTPK3x^#B{|CQg2rk3 z>x;EZ*=xH2H%?1x7gdI)0ed(H<|hI;$3eZ%+ z{nFG#wU1f#fgjihN^;O}8N=MuQSP84%-h~H;6}WpgPLeX8wTuj!@Z=+JEPVZDz9=( z+dWyjH>a|kb8F}b5PYYyH1t5fR28qrR{2Tl&FU&6W-{0D&du;Uw{!1kErQnu;I^lv zpS{0@0yRqLH)6#bA9~wA2$k9QA1F}(p#&5wk!{S+W_pq&szC80-*Vezi}!t1`NBj_ zW9zxVMy^)lh}pqc$;vOEh#4*L^-#S38>LpQrWsl6G?Ww~cFCHAxHourSV`nt5po1q zC;#dr+u-=w~iq=GPS6D=p zFoz9wc_U*xCPEiEajy;{BdaWL4y(f6n>9{+xFD+ZhcyfYRk=M}&5Zf+6H*D>b zj3}k5Ln#CWPODQt&}9OtVuGAsh?05VY9rbv@vwFJM@zKxql7b$&Ru%+wih_UL@ZF? zm+@^$+U@j>eF=$(l_K~kP2@hQJ%6LUQ1o%J_TvmuFr--Ug!$tu+U=oiA(V3SRnaHa zJnbj7&QES?E8pLKe5>&Z=O`%Z>681SPakMMZFYXzdgke)OHUs+K7Bg$6yw$OtnvE5 zdd85`Q^Bi`y01O%Js#OF+A*@xQPbEFC}-?1^=$C>Q@89~*{@7dC&J5(r^Ahr3z{A8 zu02z#$(~DjrXkoV@6lQM_UOhL>G=(%ujYiUKOH|WJ%0_p-uYDQM~YG&MI@o<$@jON z+sD~5v7OTTiG@UwTo&QO)8|eaog1c{rMF5V@`RnnPT4#*M4ma9#gXmmkV@rX2uza? z&zG-tPM_)8-^KYQ%GHbT{^Hzm&_zkC5%C=d|9*#{W5=an||Xj7MVQ%|T%Pq+>@ za7*3 z`mHwmNVA=u@*U+mU0Jg|rwP5eFs<;8{(#}WZ*l|C5ren=lpNWh!|cI4f{)be{tIFc zI@0=lZ}vUN>#2>1p$j1S#$(*8=cNRt<9S1J9>bUY2CDXy`i47iruGJQbW7$9P@0AY zT}H+>2P$-WdPN6^<%hdm1{d-Mmt0n& zWZZAU7(V${e!}3{cP`8cjd zmPUcZmVm;ykpJo+e3Z2cCEV`q=g9YA{ej^qVLDDYaZ6550G!7oLLU}EONkH-EwQw_ zkOVhK6nlhJ_44b`M78`B6&`OfN8PVGxj&C1uRGOh@z&(oc=Y*6+rK^S@UGa70n?Fz z8J*dok++{^WHecRefN3Am2&W==Z1};4g5!K% zlL&t`X;PFa9(+^hof}fL0kO@tUu2czY0!;)+<7klwRN?p3-N{h{tFY~@=@)#W7i+^ zx$&X#w*0qutKL0_&pBFj{S|r-)CLB$C=>wnIHIQq4p!;bn*W#M)1RhPL3 zpJr?=m)=A!6Qd@43sz!um-XN;O#d#m%ukwJ-*|ktqy69J1J})ff=|yHK^9wro<$y<^qC>%bgaV{uF*oCcX@1xM>kVR@cmeET+$E&7RuOSW9XGr@dqC>*DQ zdp~wV4miQq7-0&p(r^m`!Y{{6(xBFNUg~NJ0}_P4L`M2`HT8OA%R|@WyvSe~fNH`{lbaOdf0dUmH}l zNJ^C^`Ln3G#UA0%gD5K!#E2;+yioC`suC6)cCkpPt%jXAP?iNVKkV0geUqrTGhy-L z`TRip_2r3+o89N<4t@Fiu5kW^>t?sk_t#P1wd8-44sTL!{Bw8RIB{{M@5K(s^~cQl zA3v?0ZVV3^vp)q0pfX)w3cebGma2PI>coE?RU&5*zVah6B89lhB`y|PU!!|W&TrgP zJ=(7__B7?Syk$l^^(GmcI5Ssjg1qr898aweR3G)pyG)|@7PTR(u1MY59O0I|59tiV zl?ePQkFMf>wUzxVm8uQQJ@bn<)1dhf7y2}HE*!7Zl{xz?xy_^9@3i=*)>cH|^qnI} z?|^LF)wwhK_UDY1!!sYcG@)aLdh%pCUG}yVyNB|XJm>T9&8y7+R4xTH$b4IxylHan zx{l1wsaLn$Clmf&jr-737x=bd_ISd^O#b=N0tMNhpWm_1cxF{q{)qihpj29Lw>|dz z2X1Thhxxfb=e8Dm3e``{?G``t?B;T_bTP%XRhfDYWAlKl?qRgbKu@Bm%BIkYj{3?AWFWAePxh-C4C;$2oM&^=bRTUURfnmZ=;F(2>89I? z@@6@G7;QC)JRCPW&c$U#XY-KB_`T9dm$f|Y&u#jP!}rYe=OX%_n4FV1fZv?9adn*= zCNx`F0RMi*Z$8zT@demP+vQaQ^Gs`74#J zEOsRHiV*r>YGTdv@_&~;U_v4!;b7_y)7zX(te?8#f0%@Nu*cTpK5_Ug?!&Fv-Uh~X z*K!+o*$e%TYkKx+78m!{S88;@&VF4C6*3uI>D5;H?tZ&Jy9lO!zpdXM z^}$VRMj|W2Cd3sM!RkWrnhl<2%4B)D5UXnq-e)CE#*IzY)b6xj61^$qX({2~9%KWL z^j)&!E>*OZF^-o7ndaMiP82A1PTjnA!ZR+&Gv&vxQ%t&aa#+n<`WF%9J`;m*(r9h`6PZP9&J~_eDVmZw zU9G$s2D$Md`d~_?l>Snh=y4ai>;Mxuw{BPPw73hC^hf$#B~vPS8YumiU)t-BZC7d~ z$JkQ2tj=+K>?U2VI9LKHxs6D*Q8~!V2I%}26lKRF0t0_5e9k)c@Z}Z6`O(^{{{A1_ zkE)}G&1|arTn)_UP46TOa+HQM(6Y8_#R)ne=eA`NxC&pRLXX-6h{yGIn3#^9eXSBK zGm>a$c&pgli3(H?FTS*AGXl2EMoK_4E3>ANii>PgQ3;!VrYu;-`50eZ1Qgm&uPJK! z+FE!Bvfk_77UtuDb!5E!A^k-^IhMuxO$-CGTO)ZKsqON`Op!~HIT(;Jvb^C z7i+DVE<06R7~9QuP)!6|u2yFQIlXa)ehN&gK}XR?#MyG_d%ZIzS1h*2&IX0Z^qG}w z6rUapc|mypb+6k@`Rw>rCl^<0o@N!b#xwV$&6Uq#<;_aT-^@k=)y-cf9!_2Lyzxi= zKk@0UOD8g-Q;pY1smsAO{R__WKPwmp?JSkfty(!m4nS{nyD(;%qeR2oTWl6TcX%&$ zrFcM9(Bv`kSz4pDs1nq2jZ~N%-$g}t4B*#MbXicB{Ev2qW{|0MCR|Ov)6Y&kK0WtJ zOD%%9#hZZ9lU);B<0^%F-so3Kx>L^ zw4A>OW)N`|KwUA=N8|77*GlH$QW}v9>QywLOFy^vBW)st{oW&$#g+e1F<|j(5qztB zB!=kk0;dEPcGd;A9Up`k`6S|S7Oho@xpVlw!P&;Id3U_>@A*Bra_Gac);ob6pTG4x z&V@UPRr*T#4|m)l7+&%2NcwcZzj}jp@ZsgB^Fk5lKc$@51Ls3mYkg2I$g}t?ivwignXa}z1YP}%Lqq;D;+X4Ay4Wf6TL*w+_U&`Elg`E%aKIX;ZMMUCb|4Y@x@Fk6zJ6LrLcPMA)YeZ%b4xa-JDD zsiNTOQ?7cTvZQY8i5DEzUtAbRT{J+DW=kooT3O$R_XLr*qCuU~MF-!A5U?a)D0egW zKMB{^dqIXn@!z7qh32gviW?ox{f0}~o>$2{lUm!)65T*13Se3~&L5Z$xp%b6`P6Q2 zH2Got<%r?E)#TUD?v394_G=y-1cK@+mldd(Zt(sgU_lhfi4HDiQ-E7CF7e|&j}G}V zDfjg3kAL6qTwec@q@KD6zqotrgT+T4jijGyDstwT>L;8@bW({xR#--@0$s&tU@p$5 zI}Wn*@_5HP`xCp9rCQ&sPo3ZJFN_Y`NZCYL+gsuHmLx;Cin4WkFGqnOvzA)LKka?y z?Ih{LJ^#MnI`!xK9UV-4bHFdFYyZC9y?B1})VsWQ_Y_Sh9z33(5tJW6JJy$=z)`8S zGHn8(Us`$pLb)gYeY<_}@2A5&y(867%g_0L2+{wVXlcBsR=?y3f&?PSg(&35HVp5i zH$VN4#&+fG19v}%b`W9wRyuweag(0|OGLp)V)C55TuX5RNz#QRVF zP<8_yr3vYlWqL0Nu4tv(_jl>qWNKA(-Ed5IV+lD@pMMe%)CsY&2O{M%0Q_lgna%tL z0l}ZgyWZ&*ke6$14AUXpR}Ewc8196tY@5adune`=TvEa zaEIgx5R9LOw4w{8nBbElkbgj=JR9i45;_uZ8^98B5=d7xM_Hgj<|t^b2hbzY)`t(& zW^+mMc0oFJ!5P<8+ta;;As!W+eX50MYE~+n5l`uM)w{+E#p@eS6`;ewNi_a?cbzjH z%T{D13D_qs*bL-g+-4!sG@CEPO80P-w>ZzLL>B!N z3v!OwNjCtNwa~-cA!paRKLTveqiwfofK&Vom#r+X&4QRfNP8mVEPk+dw&a|zRvRtN z8(p5vX2flEJZl$8;jinadh6*ChJn|?gy~P++%sA2F`&YqT}6~7@~NUU(Q5#!~7B%H|=bc4U+>s zZr+2yt}v2)!GwO`!Z469mO*VQ=YZ&^vzhxIK;o!|sUnaprz|r!pb@`Sp9M+6y+5`qmEpPuvZLlG_tSUd9Tn+^ou{q7Xr!BE zA3oF$a&ZGel7xAi8O|DlcC5^kzTl&5`W0xo=24-bF#c4H&~}D%51W3GneqH6#6x)0 zl}f+el}7Xx3JJ>!@y+BpGHvaWupyKI(d2PRc-HjSuI-8p*M7P-E)%Md<*FeVdR)%2 zC^IAs9ORoxK;w1v=!P!f0O5(a{sAei^z%nE10BG}*FXl@1i+tBS7En9{lG!Gp{HA4#;|ZIHz{iki0f@}C-sCl~tX4X%AAD(w5w4aOsPXtb z36jEwBtBzAwX0P{h(-v!3cm~Ci?i|>X;&(xuT^A83PVG#h$L3&y$!dM4idWB4a72C z2xCA@rt49SZX#1SA#BL@;T$$XUEo zERm7C2F0Q?&bEUMvPmgQZyvhSpN1XP(KNrvnXmX1@a1m+``S^D1uy=s8;LbKV3DWl z26RpY9e2BXk^*vKWe|%hWfMV?gY8lkHU|Lc#p+9{ETCgz2C2P0PUF&qFCc`7J4X>R zT1Y2qFjBG^&M3c-u{VKY1)Z8Na;gywnDOS3hKC1pwIN zmq8d2TPL!nePmABteW{<+d~A(R7MGd_;4^~3>8heb8Loit|(KRa&5VT5$!7u{-%+z z;BkPNQT34F4iYpPn>|O%)LsA(*0T6pCBof6=OWM{H^%vT|JNO$B!`@}OaN{Re1QqM z#BYnRO`~Eh7i3>0(W+H(K)W>+X<5j5=6v-O;|vk-x(t*w9k5ju;&d;Ba9lXVT{k5R zEN?SB#F~(zfL^8x>3md~@l89qiwa?aE`cE4{-u*Fk8;lU8t)G*QdI-SXqLxpeSL)t90V<-=asV`P_qvo#~wp}eNb`< zVB@olL)~1>2!*4;*PXnaub;kp?_)~W^7b=EEUGp1eVU`&-Fs_!%JqV=)R}lJtUlk^ zE+;L(lrq@9l9ZSs(*$tZs%I7ejtksNNCevn)1@5Jq}UHe>(kEQpaxisBsPSvC-XJa z!0oK4tnBCme#T-Sy7Sq>n*=gLhwU2&`6s(Xq--jr{Cfa@+VZh*tjx);b+fF4wpQ)qQ>s$sW& zNQF)wJC@JL+LUwNs=p|98RsyAbbK4(kg0{5eQ;po@f(;t8hn)U_rEJho*$G-u=NI_Q>n;@aoQ-%%;T>l{ORr~@Riok3HB zP=a6&jn61V3CmN(7J?w-3jVSA8*=++_kQ&K{T%pZD>{-L08roRy+*lozD4K)#L;0W zB5~^pWu!G5aH5`(G{(4)xMM%cxF8JqJhy55IRbD^Ck}PIeLNh^+vQ9d9UOboOg=WY6+Tw4GqBR7G!q^0=>bbD~ zf;J$I@0~hi$xbhv#V1rVBiGLx3U6BzD3RyJ=ubNmN)G-yzAtuZR!arBKD7{(z#NFH zpj;_2txCa$TnyKG^fmNR`2Af5&W)a*71);MnnY{;ZXDO|3y7v(Za}qObb~y~j4L<$ zsqc7BG2ooVxpM`G&E$5kXSj$NGOi^ zf)oE#y9iu3_#dyJVDglVLlh2T_cQsTOM-tT6tk6ubj&(xlGJxG6>Fb#D(?UWouRue zB#H94;FD*~eIssK-6%w#OqKiz5R_!DSWa+<+|E{=J9~ev_Z$&o#0I#lq`A^W4L-}C z#)@0d?Ljzc0VD=RCtZpO%GEd*BVs4X8pb*NZTGtH!q4>O^SGwypMdD1&_@nu#srk| zD>bDq6c&Mxlx7Ye6eK6ybT?FjpAJ#V2iOwj9PuM*H~!eG2-W6^xnBYp5UWr50%+Ns zb&NSd^Xi+SzWa)ui9dZ`?yAQG<;DCS23)Dy{S<;ac$;<281L%Kv@rc7%I;TTSSC5PzriqG#Gd4Ei1d zZ4i3T>o0^Z^{mL&2mkb3^fB0#M1hYD1_u<)ERqEp9N&isJxtvKZ~NwQJuFfl2H_n6 zkvA+(hq7tzlb-?z&iJMShZc3-bp%qnDny!h-a(^(&0k56_*nTYW!}fZ#RC#mRrp19 z1rTy7zT{C%!`zwMYf%anj_pm8x8ZHwQVTm(jU{#2R}y|Mz(s*su5HP?PyC~fCHjZs z%E#U`zt&Yo8EtGnYZkiViofuuro65o>RpSZY;aKt(sE$|AcGzn3r6bUgl+iUqh3lw z24gmK9!zsYpk&-m%D*nqQEy9s)M9;#L-tUwsi?`-emGro>0lSSHqT(fw>IBM&lYOo z=4k8f?J2c*-Qs&kv#a@+rmg^mjfHOo%6LgYuj$WWvXc$&io~e-mwwMt!tq{}7gCN* zMR}GNg?c3ee@qLK3%Ci5y7?DLY2^OP zQk+cF2QMZO=7^lNk^l4zCA2MKU*(LN1};A?zOeVpM9gP%7Wl66lj`mZ6@qZcVe=%S z2#*Y1>T=^kN1_~FSfa0ZakaK)mkLxP=X~!!`}zLb{mwsM-`;=D6YP*cRCjwGE%ZEO z=nZe{n7n$7H!bcCn}$7x!NgyVIdX?;hCIa95={#ULRQ|RrhY{^!xmpaCHoO&!(^mR z_Fpbnzr`{FX|drJd*yoHdC!VtyY;np*GUDX%wykEgO8aMWCf3Uek7{WzJcN9rZ%_}wCjvm*`tOP4i6A(cYSnhw zWM+rgCz^nGR)G9A1)|B*0TT9yj@`X2VT%{b{W3INlWj-zi*dvap@IjjLSfbrNBNPg z6hTSskDzbm0E8Q|lJ2-YyJaN+?n20F3L>{yxgiVpCBilQ=Gt*NfjU5$GL3Wv!9{kC z+gLi<#!j7GWO*tR5Hmg@jF@7Ipt5k1Y9+!xGbEX_!>1KCiG5fblVa5}xAb469)qia zH{X!-ay=@Qr5eL}w1f1F2@7cfD4&vs3Sls;ivvt!^+3K-FX4{n$~;=**_nigoj+CQ zB)*D&F56Aa)1#HxrIuw3Wj_EPToy)rZSVWIMe&MEU6LE>cd#4m&Qtiqkl~htunRGH zrDYCcP}5%LuauI@!^;?xfdR<{j>2yTKS$cafL_5J@K82`J5^GcyZ}-Ak065VUTfA7 zG^ps3->-M+^l@Ct9BKq%M?wU6RPUCTK$U(rlyh{Z$EgUSc{<<(7x zPQQq&F{oPKtJ!z?qsm#2l`D_WoZ6s{<;1aSF+bV%<^l$#X0NbJ!Mgz2*Qdwm%7)cY ze+_b}_2{)>iR(!CAVK}k6Ev(=@mIU6srB|yR=Q!GvVx|gbGSzx&&D9|i;k0R!Ur>q zo3h-1aF0p}n^XGU@V42U=HZm^vBc}$HRPiWo4F`Dtz`VRlfRbdwe_jn)<$n5W{pJ01qoyDQ?W05Cuh0oLdEpAGhiL11dRHG_#_ejjDTj+c{R)C; zw`&&IO&)o!EFr9&O(J=h`JgMlHs$*31oOW4q2;9@L=Ee}Ou=c9s{omiU4MhhYLT{H z)tl;obcGAI87wI!$rsdKt-N}VYb{eZ*CiqkB???R)nD_lI^j$hFB{lU0TNE~<3ITJV;67So-oZQskT9|p2kilz@pUb8k5tylPx&2_> zKU%Mp0`{0r-`BKegPEcMJO5=ol6Y{O0P@nkKnTu?R10?sr{?58Ob_@omu0ylhM02P zxt}ti`?Fy#mOM@a_1w+jfB`!vs{Fpim}ojCm-i=JeG4~p|EB@T4is@*8( zw)!kBmdS9?J!OR9ctdjHN4ME*C?ih!7Qh3DTKN0s z8)shSCDg0P9==r@aZYxMeP);sN7e8t*-N4!ZU2}HG9jBR zzo7xU>ICn#H;g#-fqmPO{GWQ^VgBEriY&t3vaH{0o7Wvb5*)!VB(TfX^6Nx~a!IO9 z6@EtJVn^1oDZT9EFGs|_^fMeH3Q8nxxQge*zw$;)#djitEjBdYv{_sQWD%x=5`o~b^`X1@)L>~+(Jj_6^^a|B8G)uhw2L% zC#!L;Z;XHVn_H|R*|FJeE|}N_StajV@`2OXOo&fKR@}+N4>7dqvv-LPlhwiuWGs(N z@ZtKr&fiwU-gN6%oA(&^IDT;-lHu;RWvR*&57@@r;kyko-o6*mP1T1lC8cWOwrpF= zqL~p6BTmCDjV%N2y1LIQ_b)#C0(D?*1l%6IwVJRJpgr`bcTZWl?g(hc_L#x_8$1rn}b5H0EDBn8k! zk<~K*dTv}}KcId)M^udWHq#Gi;zw5c`tI|BfWjEs*oCZL!7&-0=Sgz3pvuNXvg9k8 zGY7reWUYO6+@r`12O}39Vw|1@S`fH~Tcz89F8F1-nIB-^-(uNzvZWgtYI8$^&BiSN zEi|lQswyyw;MEbA9d~i;t{auzWx7l^Vf#4?0QOCH>HE=*!j$!g<>w?xQgzk_6#9V! zWUVpGDoapLpv#ISsE_4e!9cZ#Zgv7BEfifdOjyfT*uEl77evNwb-6qt^-UG%!nofx zR83syx_*F{)iy$Kx?u$W()aH-yM%$!byd?aL?wL`eOw?7gCc8aq#OFuPc4uP{K)5$ z9AF?G-LeXZAsiinbxjz}x$uoF9X0$i*9=A92c~0~Ls^-EM`FqQySfgSXK13hDw1iM zv}OHxLAR?m@Lz(4AzX}ypbCn+OBKiLTDy3Jx*)i!=v#>JRqt&I%ndN_ZDYxzkGqLu z^5}d()_Rj{+0QkIFTt?MR$)LSEQ_!S#P7XQ=_XtG0iguzWIp7z1+;29W)VX6b+eWI zI%j?oR=P>HnzpAlb=ePeP3YQKr5-a&eEnIHV?>>?)B#y!a0z(KGkn^UdZF-iU{Ic2 z5Z}9Np_|MC&!%59XLh}#0q|2?t4+F1H{G-eHX=4de#ti7vRh$@MLw-{CBc}3*B;sY?TV!c-;NpO|FHccIxLj(-tTU1+*d*9P=7_ zaFm-Ex%xQN`_zT~1Y_VymJEtYwq)DmsdQ7-Yzx(CD_@&bgXEw%x7NuL>6%-*@ z-+u)(qj61(PFc)CW$&cP{!r+u3v6m4o5a)2)+Qf?38R>Fa0%I%O7C6e8VxJz>^fT1 z1My)_Cgtk(cz{X&fEgZyZ+A?&C16bL9n2%+_vq)!=nwA+7|wcBM37A-?dkzt*qdH( zf%hkj#6rlX3l6_YdVL`;3j=x!p^h5vJ^XM_wEVqgiVhT`N|%2WheGCXF>6C;pj zaOkvpJzZzdM=C^j!i_9S#h&4 zx^dY7%RG9#8%TeFYnIK`O^`F!`E)CN#yrevWr}R75p6*bLsZyVUCBR`2}cTancceS zB1uAL)9-fxE##qm|H`RkY6Qz3Fi#~LCvv}O;nY7W)Z&iTb#smU?mKR=eI(P>AF-BMTZ=?aG*)^gY0i_Sd(=tjjWJeEK8+Zs&RWLndV!3B2)m% zq{+GDm@(hS)3_FUTmu?FCZTK3a^9nYq%f8y$0S=$H|@JgyF0@*T}zV)=`L$054rWV zb^~YPeBoP&W z9wzS-j|OOD1GP{A;#lBqHFEA}G;)nIagtnEc7;qSwece5c->oA*C>2XvlY-Rsz_^) z{Am6v&rmYUj6gQp9pgV2PWpZ}S0kb80fEIfAEHjjk8}9Rw%T5RZ1-4;ypOl^vvi6C zpiKhW8c;(f^z<|P+f<;+avG)raHYSN0274vrw>Ursj3Pe^c$9H2Pkwb7ljG(Rj+UR zfoPX<-7&5O1t@xWOsbM>RY#Yp-i826(WEX4qn9JVn&V zcBtAGP%(7DhXENiWK$b1eGh^!QCQe6cBxNOpgouu6jYc_Q(!9h_NUXZJi6>{TJJL1 zn3;QF8mODbRfVVam;X8EDKbFtXc>{p}4W z0{_o!#4+l0=ZySZ#M(Lf1iCVl9etW+2-?m{1C&+(g^EEUE_C_(f|+91WMsmye_mog z04t>W886be2a~32U=2r@pKK5 zibv*Cb&r1M=wi=S&ydU$!-5()<_p|2@yd-f@=ExqN+eG#EzSmB(Hpkv2zQ~MFw{UM zh#Bm=XIGbB$|P2o5VeMZmM+|G<>Bh2GwHNzd{9^m2eFFH$f|5EUuC2{YG`B+TS$KV zw@ow!G42CM>R#Et6#?2CWOJuW3LOxKcdw;a2HM7>Prl=p83IM{XT|Q~QFTNuUqd_d zFBW0weNusD0uN_6?Tjgeo()-@$^LYjrt6Sz<=A}-Awr0^hRP>iJ8UvkM5MfK;uZtBX|ME9c^NG(f`&SD)IJXwdTmli zyT9Ge9&75tCf-12r8r+T4>SGhV!GcOV7ki_+V4j>F`4Z7xApo*37eG0sqQG4fS&m> z38o>K)MYKzLN>RdTY3RSe7ot3M2RJ!zDtD0eX?a3H|+l5)4?%=SM0_OodtL?c>FQ( zB6f-r(8!N$!~&al#GqTaR(w)4C{J_iXl|5m?7K}H+#_>z{thP{9AF)_?unz}5nfy? zU;XzVFHZ(^bA<0%;t~&Ea$vcFV5;P!@0_lz(Zwc5;)}RehQ~$-f*m?^@SZfHh;0%t zEVlwMt)!c>3B$E?L+09bR@Z2oE@+|bCRDa%*$Ps3QJs^}Z4 zSRz9fHi2&jTH=8sSY7LEI+*s^42QJEpSJMZ*~3R$vOGRrq0{|EP$0h3{%qJB2&pFW zgG+EOTYCDMX?oUoUxjxaOtCz7eS*5 zFM(-4UIATS|K7EKc^6`QE!%yri+eW6T&r;YC6j`9>-k%A{KoxSt|_d;(@j zsPn6eL$~3)UaL%ArKEdp)QM&(SLuITG1nWW@}i|)VwVf$FDvu@$J2dBCH4P*02fg} zWvOV0fZ)hoxJpe6w`Q3;O)D_dG%K8$qrd?;Qe0)G296w=Vp&CX!?|!d_j2F&`FcDf2O`g&dDnH}&&tbV;H_?jq}6|iuh#QHwU=(7 zWDME8^@> z>i5rH?j~>Y?9MFq;J4j7b5;9QL_aEVJdme;zC(YGpBWNRtF!-e+0DGOYv;l;GijEF z<#N$nnQJ2*U&G6x(YG9NBMUt&{5g=?$~82*H5~7~dBgQ_>bRE{(*+fDJd^b;YpX1w z{eF0*hbx^3QnJ6It8wB9FfDJcS3gZs1vwaAD%bF*@BxNDxrjA$UT$GWmKL4qN`7Fn zer;@QFdRE6=(w$kW}0{?q7SZxX~Z_4pb^n!t>9}B9lb@*oN=kB=dL;x#n1N|ccNbG zvv^zl!o&7IlqBrcsm$tKaoY+qkZA;TCxvDKn8!ae`r*6W4uP(T&!UA4Fzt8rW7X7V zulb5NJQaM+^LmoZ9SR#$&rQGeX^_a)KD3{R-EFY=xTkxt4ok|GlI9F7+qqzAU0#co zmkVj^tylf8^6`~PArL)Y<>A%(noE((4fWTndJSI69HN#sPuy^QaO(-i#h5X%v4su( zSSY{U|J$KjX23;dqo!_n53x9L$u4UY`Qq0o@$~qApbuxdBb<#}DfL@5&aTh_S8JxZ zxes1lKWBV5J8|F`CT2)Kygbh1ABe48b#+P(%OBLmdwYr)EL38H?zOO6)l+rbZw`YW z@@a&v<)u{rpH_v|`d=P@dj-4!3SK?ODyIqL7AsO#dd}d)sbztvmhj(z{=y`v!y<0) zzaWrDCO((uHDweBdIJ0Y(UUm!;GES5+NCReHfc;)hmU_8@uxf~IK%64^0Zv9KRD}I zLBGpFgKi0dsA-y&|3qQ`BVt&YD)lPy-O(!|vbp+p#3fHirPRgY-12 z6l75pz#@WjI?6l4kOS0CPh%Jd?7XNg;DRt>blJmDd*!I<3~lkmpnXbV3orM*#(&=O zKII}*z2yF5Tx(xf2p8WXsMi(9l5?_syhz?7fRd-Jj>kbw-|TyaP}q0Gm#DA^fKYVr~|CI+?Q&Pa@b3M`C73 z8gg1&rsmbd$W@>yyXq|;KjT-~LE?azwrc!;+Y%9z;Pu{TkAog(DZC$J8RvM)df#=x zJfVRsW~lizOD%MUx9hgLn7Yp;gBO<8nbH1=z<_mv-kC$}@*gI!pKtZIHH^I7^Q{<> zs27r4FXQ6;nWgO3uBGwO6NqW(NpBb@)b3A>^zE7R#fs>S3ggTE_ow_?&Z{(0Ykh$l z^^MxSBCXZ6{m?Fd#8*_K`mca~??`TIJf|9O^4r;#AB~75Emc1G?ba4n`WSOWfi;~7 z!>^z)=@T1lp`c8&w@|vzR1vze*?-l)=aqi;dtEokkjn7&z6wD zB)P8Tri5zY&txsXUvBk~Kh+$&o{NHSv)d9lt(!B*p4nsUl1qo9TppS&X?+0L%o>}^ zItd_FiRd~~xr4?VsWimVi2OIxO#Ih&mp!i(MFnLHrLV_(RRnR*zhugStR4G}i-Ih# z{1}5Sjj{HtmB@%~0yIaGkowRxq4k!h-ndPqZ+aq^Y2^fu9+#7;H1+})Fpnd16MCw* zc*{D8t|&!v+XAfKMjW_+8Rw~5gkafFCCd_-CT@*YXivIZFHmEW0BE6*hhw8;Ac^#T z8__y^XN{B^pwneaTEU^)<5Q!g?!cn%2nvn(M(>)xDFxOaOW(C(5;W!w z(?#?cV`sfHtlK2k4YqGu0kUqi_DM`BDsB@vrB2G_(IKYk|Ai@L6 z#h0T{>x1%XqxVwE9ke@YLe8DCxTK|-zI%3VE`TP0Bx05E#UeYE!&mYjd6$Fl>=@Wt zwol0?pbx)7F}j=dYuHT%hyRIm39dTLjGu7ejv98y^z%+DrR=9!&d^xOhjB+=&Evke zXB3T{Z#FQmhxiZ~`iDZ~@>^nhRARz&_Z&Q1l#sTKUm6cBB*Eo3ES-0&E_s+eeTa6g z8j!=`+g0Actp!pLa)8~Vue|!a6Ari~j;-}L51ml&pssmQc=qFMxHav_`%{4~=nw($ z$i;7(zsdc6H!HHwiRMRjE}K=XqkvI-_$kE2X9i0>7g6Lwndy7|+7W1Xh@(vLCh-ioL`dQb38r$dPjE^Q{3Oq=l$v;+N0DEuS^x zpLpP}Q;||arN@A%W`J}FYughd)Sv!yg@OKDH34#GDrw4%bCvy(D$o#hBdY8=MVlt2 zyu`y#F}6ra+_>45>E&${`j!MOb&wsxoPj+wr$g(;{Nv$Ac*+w0w^4G1ICi95B)^R+ zyGyuZ007!$_w*J-|1N~mRSznpgP*kEAKR(wQPE=zxp2b|L(GfQt|92=mqso4c7~!9 zL-7G)ceAz}o%>GWhL#hN-{`1u#x_@v$X?;wW;?}iWJOYyhL}Gm8UVG$jN541AR5C;FM16uDFMk6vq^ zu+taS@c`sjBKDBxYDf(>rcd>o6p~3*UbpM9Y@*pf_fM^Yz*JeZoyli_I;a}5Mv>jl zQ)`lR5F(W+RTVS(L7`A@8bxWz9*ed^;Dw0e;IEP4U+b&6i89}E_wlNzvJ`^ah7f<3 zid+%EQ9^YA6TPqI!d4~l3dNle)fWZmP@VtTr7c@U)L5ETlOiHD6>TK}O(pM*b}|@ zg?#HJ1a3tLTL0os7bNX?uB0$#_(;j9$J6S|rDUS8OU9h`wz8@dJW3ipG4|N;V=xGQ5M&45DzwP=oT~)vF z@TA#o^0!fS#x4JdUqmE$Ypurf5aULM#*`3ts}I$-f?pDbzB0rYzrWKwOVavUD(b;P zGEpC>#DvkIF{=J`EqHVTNQ^p}vcvVmjx5Zk@O9E@KUbmsKc4cmp(Ty1gk>X*sh2}C zRC@dI3&dV-5#D3}9u{ep6j26#Oc{wW&_yI$)ZdYyF0YJO2U)0&K?Il)ST{T;sK* zryZ|cRS$)baeBC}y4-|x2>iHME|>v2PjEpr)K z*-~nr^#hP%g}42Lx3f47L$8pIodMu5KCdl`83JFb3q zYnzgKm-!Z-T=iGQU^WA{kNH|aRGXSjL}i6OnZ<>D$1-O%CWt5z6gM>+Sn(3q4lwd3 zU_^l0GEJ2k1}-m$NFghCGjJJqBrhegzuJfaSP{cK?1|di9UEh1RYKjshgsYcstTx@ zC=g(pO7JtYY7b^{T|7H`A60@2F>zJnugV7`ye)*FGBu04MU33ts_V~HOR)$^P6La# z&1#q~`SDK}89CrOd~v_Ejj}0fuc)t^xhfNx(}DmE{)nqxSSwMo-Rd(`9MYHgE#v5XJY^DK zw|yTj?-(deU-ALee;0d2N~whUSr1du;|v@bq#MPHY8cWNQL)`z5Q<81;Jq3E;FE?; z4>Ce3ULAB}G=%Lv{mxERY5%tRyVxg9dkVQ2kq~ryCBY@_-`!ap>KK074$}<4H&YLJ zhhsfnM-SU$N?+od7+)g=s!!|!uG~@UV$_Gs$#)CgWq;zz0T!{{#2n$Ao>!u<6^TEyDkP9Wv6OAyK_L3ZPy-UDGi>> z;RFa#s9E_iZvv?_T|G0+xZT@R4r)YI37Azx*KouRE=UJ}s=XbICb-y{nD!EVfHaYF z0i9;peev98I%`uyFQDkaebys5RFA6SZ>Q8q2kT7~t4ODRSzsszvQ_3-ooH|)1?kG; zxDt_#^z*i*MUOH#idI4+plT>pWgGQ**zyTIE7Y>+^1=I>Nt0gAR_Tv=p?a3kH7>lJ zvg;cUYw%Tre5Kgu%4K)80~7ZzH2^aftuA~~yY@Bk8UW%Rmj!OjvmT*6Xv^1 z^3)^bvwP%l)Lh6MWQuQ4<`wlm-l;W8yirO8X>N`B(Rn`UU$DGN@`G$lS)EmP!`8gH z9mZ{_DLY=0x6FeEhcc}>`>I{m+*<3ia(xmIs=DV;P1m6t`k9SaS-jD(7f4K#LQ+%f z)Xb{~`tKi9e>_Codu)!MZA~Xsxui7>KX_vEU{5mzJ1taeGzN`J1qy`2z1B@Hf43}_ z-Ozc{{B!cwcJy?uAJUkkb&E$D?P9{Q;D zF;DHm?VyMEu0DMDuz^j*WjE<$C##9Ks!M#whc9+LEV_Z&p=h#bhocbdUS93`^rq{J z`UT}6C5lj$Vy86Cg{CJ*u3Z%*t5kHgC!14(Pr*aN3KZc$Sz zZ$*ytllqS)SCTp&=S&aeV|||*fKr0%s8e*l-iboYfkX=O7DJt*y6>BrdfTiUpx&IX z-X?II-@0w!(Q{%mL*1I%l{`>;OTOjxv^Te7#G0zkr-nQ94T3rUt~1mFgu*>e^EB+> zjrjuhG<_yzOd03>czZJwmCSp0BwW-=*`9>pIaAW6G3(hC>_fzpDc4(XT*Xdjf+&;(K>U`d? z$rRnQVYKeB1S=R+&z!pVcC4tP)UuDrCyu(O(z6NZ?20X%{|uw0Kpe<{C-NXj<;>#Y zXFsi|c9{mAA?U4bgHQJ&%txog8$r@S=+IxU)2Wknh48yFSf(%1I8@!}i0@Lr#yDW> z=Y?0S6Bo~6R zzas;-FVx@L{pR6Us-_j#Ee^cpzPO9u=;&L3)tgk6Zo#|T-intPpE~jCQGjjRYC$7X zpY7Ba*0oIy4#3f@OII;k;6{1DjrDq`lt8@$hx zcFW91KgIo3Aae$O4dAy{Ln`RCwwlw({--WMzWj-}Uh2h@ot{m?I?@4eC3V7smk%!^ z{Btir#Iqumd{Gx`^K+Juk2bF_XUnmH!bRG(-6@;hha1?f3w@d->)MB`7MxQN~i&Ivezb6xdh zM%wFjt=+Lk_Z(aGCM06E-iW;SWlGygV7qd+yJfbAU9nMC*K&k( zM~yl;&${V6rx|wlPSA0y*2Sk>haCL=2XRX^^(Fu20rQ{sRIsCMs=~LU-)T1%SPOYe zc(JXIMaWsfhuxTG5PyLXq}mcyqTCeJ>*V5uVu-1)1$8jM`A`*{FX zF>Q80ucGsV404cT_Jkz-^%I+_)47PS@`G+Fdz0&h9=k}H92w$I`Fc#p>g^m<#j zxrF+3iCX9e;W=bEll zuLWJYQ54notIAH^bfeT$(U3z2+kTC!67DfHl4}9wPXM24{cI-dBMsX?K*T|*0()5J zb8xT9!8MLFJhh8?)arfd{HXi6jZin6O`8|X?aGCctnOgPB~REdrCgel^t`Vl)DRWz z6hxxmJ0!eO%LSxt6j;W}+pI{caJ!m0(sJ5Oq&jtYL9ycO^u}?)K=m9)8+MHvrXT*RME-=+h3v?P(yDBNJDYjaul^FG#*Z{NC`R zUb4eOTQhoQCf2k(p!&s!d$ajMLC)=4YwZ?LgKdjHyoRIK_c{D%QqH&Cwd@NtYKsQS zz%6@eS-XA~19#q&TjzoU->wl-pgi-qiw_$P_c{<}Cyq%H!0aoRBHgIhJ$BEz{y_+> z`jHMQege`DM!r_Zru@Z63c!b?lk}mA!S@*s@+MIMYw!1A&@cXTdo~>yJ4nc}ov^!P zZ`G^}lXFozu?6VV1l0H_l1^=}#c14-tj+WQ5Fw?=~yXCL7KWepo67{mt7fL>xxgn&m<#<;nRX=V!WwlYjafHfJZ%dz8tHzCw^$52P zKAa40P<|uDvg}|$N!l`yI5yM#mWj(5$77gRk~vd4hZW(PuKt}3-gzVf7SPTF=hidL zq@U%|{%T>TIIqFw1sD=r&)+3-cRta48d*fs?X2Pb8GtsV#TX zs9L^)3)*pu3bW?aK*;>Q9pBX8k$NF&j3N$Sn0n%uW5ayMjg--1mJDE+$ zi42XyyreiiE3N~DFDRG2D}7ABEZ&T?0pflJ^dGDPKp+urx^zXC-QxgeVA&jIwDgFF zWO6wyxJT8rQE0l+suxw78~=S+4$7hOT*xow#QIXK-Or<+yFHdcn!ABo;eN95OAhKb zbBCuI1r^C14yrE(`b!P6F;Uh}RY@W_1b)_kC$gt@hA-O;?@RZf04wKRKM^j;WRSGA zuKjJx)c@>-dTz{De!a%DbbbJ}@NBv|_y(VFZPus5nyB^~0*Z?iT90ndz~DCFV1w5nGW-?s3t429sBBe2cjEjQKHS=%o8p zAvrs0sR%n$|5&RMlHnPA3{4K`vq<<2C5=m|Oq4nwN~C0++$Z4;q`GyY%E4-r-8V3Y z`(T~%u#k2lW(~#Kv9@qo)wo)HenPCfbFZ9Q_qKUVzGsgqpK$rBz zhiVg1uO>d4k0V{VHc{xeW4e}=Ja)Jv5TRm+GOagxo$Gx}O)0mg@!;t43fk3fZ~(mf z-+Er8R2Asxe5iMxeM|J;YK{L~*(T}TIpA;sak zcr19&Qgr9}H3!KemdlQs5{ZJDp#hn6*}Xu``LZl?)vB@Iy8Yb2icL07EXCS)Q*DQh zOsV?i(I1w-Tj6ml=^D%D*L=i^X=>4yy>GmlJ4&Q+?pTbm~fn5D#^^wo+@}(t*&nmOFYbyxBQf@0qHL=<5v`gD^IHu zuHLsrduW= zpeWtvZVnI1W1)x#9m$WDmzu&;f99pQrpu^g+2N&wFJ4W&>k^houmtfKCzp=hZE%xD z2#7)1OERFIC6*0IRvdTy%`r?=x1Cw2$5-wnEtLx4J}a!|_oVV_{L7MerXLuHGW9?B zC2rzgg>m~MiM^_uZ*SWCF1Xk@&Q<$MVQmjVvWwJ^#IhSJZ_B09Pqg(G&tJAtEk?Yd zORIPRTk8Ds@?5MLz7<{0!31#zGcIK@59_XL{IVE-Wzg`PkP2OfD3F->=tE0BIShFGP+!Ix?4 zV^*G_p!eicWZjs}F_>x0-W#tGz1)MTi-=cz$M`k)4=()OjCXSv)CvH!G zFH+#`4)AZA@iZbr#D@-(VB`=)DMhViD{hJh%C=8<>bWm@CnC{1Zjg@nM4_zn;bI!R zek0_G65<`*_mfEdyFdXvtK2J09VX`&l_2h;;4ippuaIxgO#w_Y8vYvTaq^D(C-a^MR!RxR79@Plw&p4R8}0t$8YM z_FWM2SwF|%(_dKp>;2k^DCA!t5n$qjXF7oBcU;68 zA=rcqnxr5$={kiI5`%S@A%&xIVoS)Z(RWX{#L?UDrj9F>$yP$V;XsE4m;4elO{mFB zd^oBe{s{>WCaA+&q52$|MGE349hR<*{wReGro%!4;i0WCM>f)M4AuoWKS_fvk&p{q z+x?2b8am?G5_C{hXmyJQEs-pPBW96XS4BL6w2Wl@@T&;+da?Q)&Gg+G_M5Cum#1tT z85}8)ou4C2k92UQZh|^O2r!DCDn4T-9^Xjde(xDt2ayt z01CNT+8k+pDc~d$vB-%$D1s-_(``6uKj`p?c^TR|JjS0?LsovtzhLEsbCbxZ zltMmZZ(I@VIYzww`Wk$V>t`LVfl8~Ikpcy^LE}!qGQHvkq;!68;1yCJ(;Gq46rzyU zlDMXQ;A2wpFF1YevKvkIMgM8b0ATu9&5>UiZy#9-%{GIGHKdhxWJ&M!k)0 zV$9O);1n`0SW11@GfgZ8Zn~jtDM(%+Wvg!>jwj#s7`uTqy~Sxbw?_>@CvB5Ro8>C> z*-T(DC+jO2KDAcAL4dVXorHMF5|{CfRzVvL=bm!5UXp5kVtrE5M`=kU~tG{_%?IU6Iix`cXap(N!sW!AZhMOw~7vL|<-mdVZbstbNm-`|ZcJ4#UR0 zYFN%3luS>L^n^dDrjohfRW4nRBdy1gNxB19DB-DwAQrfgU@4H&xaQYgFg=kbP!S&P z1OLsh$hl!jr5rL(QrwBzVtMaAMXF$xyrtQ@i^B_Wq;5~ImNQ?6I=Z?)b3km2K_dyb z{l>KXvJvk%(i_Q$WiH5q(7a6X_Rm4Atie{+;Gf6fALt?4_C)>U>ujob1$lcD=f z&r+M#d{p8|*8fn;G+Wh2dHc|#1xJh25htB4@*)&Em4#R2abatkX8XLzQotnHBXkB3 zb+XmQt~O2?9!YXFy)_ifk4@CavBHTzOO)>q@k9cW(I=x-B*bfz_1x=T1ykD_dv8l;uhlP7u7rG2c0xm* zy-1~QKtTbWx}BQ9!m=A~O1r&es2q4z(^HjWh+dAgl^5_5;e|O27kLAOlLZzLVh8w+ zafH&hbk_#A!-=;DT1%kA-ZFY5=&X4NMjCW}x}UnHjOuod=v04~h!`ekv{!Xxgy>mN zpO?}({5TpEof3Pzfsn31! zgG+UzfcO-JNGWSEN4m8S{^ud4B8Y$S3jUI&82)DsMxxyKI0pYj0VR?iMRZbkXbCN{ zx4%Vt6w;8S+W}wr{&K?CbvV%JpO6luJf>KNj7o?5q0JWA zhdcB>QNYK5HTzBIGxRt2D`4aAAG4%!WKWpS7_ci^xQCjgX%rYCa{9F``0@&>3nA_oe+eqjnu(HM9<(9L-8hyyIwnV@r*93P z{G|+R)$y3Vg0kQr?Fii8iG^RS6{}v|IaRfBbyE;F5`_3Fm0DJW_{QIAI1l@cG$)fF zfp)M_6%bWQ23iQ;K3(>1U;d?#@b6=A)_b2bz#W$-?f=}ltCFdn6c11Jd-{{U{Re>e zn=+lJEU)S|Hm?Ni68QoawVHMwQZAHNtkALh)TU}n)Hg=VaiGNl*$?-16Z?Rgws0%m zg<*h9MB}56^2r-mtcmB_70!V7uTo2x44uGyHdy!?ssED?i|6gR{2wCS6K>iGf6uoT z^PxwppUgEYd&2I|9|Sg#kmjq(Pm(yR`g^j;>Oz`c@9dhYgBl0g zdo-Fg40tBe8i9^**gAZS6wD+}$u=S@Jm=M)N{&O&6TQH_mT+dbkx87Mo&YjP3!X*7 zKat3tqri$FL=)-lrYY#H32=S_sg!i^`Kh*<)>rD4W>2>ugkCsKU(nS%Jr0xob7Uu`yi;i___5L?Y*e2V;Fe9#McnSj__%e3Ue{?Xv{|b+sEv6wWS~fYkEE!oG;v22Bxe>@ZDURVnO_5 zF}8dPDmF0Tq-{z~D&Xe_^82S|L0`D1FHW%k^5MIhmDOvG`!6s2d%0ysZ;)81>prtk zb6eT--}XP3rQeMG5Z$yG!fockUnqzes?cDPt-UZ1#&z?Ev-=yl%s+5C2>WNoG4;l|U! zePuQst6E#qKajCS<8Rdip1!pV@}oP}T=D%VKu>QpxEF?oDG@wgH0Ya}fo>(Qo4@p2 zUO1{0|4Tx54QP2f9YGdJ6EAPal{T5@)So-MeJY!+@MToNPisz~eQ+oth?qbtIr$Yd zmtH46U54kI)@^LwJrk_b;AXr_DAYUB6+t-*&!8F~-DN9YX&Ywkrv>Pytxg`Ry}h+9 zX>;@Y*Ly89Hp%?yZMgO}wpyI})hp3yAE#}Td&i!`bBe>{qkd0Z(J!=#xOnE*#Qg?$ zWoLfMhV~Qaej9YIHs$&1{H5;ZvbeBwQmw$sUbGUuCCLE`z$n?(@0cHTAKu0o@eGLg8F(L z^7w{xW#O2e|IUS$C$B|2^Hr~9m{zHjTS4-xf7>6w2H*8f_bTeSA&E5pEc~i;?TWKT zd^<&vN!=kGZA2KFqz$JmKht`8;j?CcW$M(l%e9%Bb11eX&#J551~ROIpIs@aWkSEN zUk9PD4~FBmNyI+SIw_moz*opRELz`jA%lMqm4 z%BJ1-%Hk#0HcTOUT*N16H3ykN)`7g=?G^_YUY-(b}B0< zu8M#BIlJhaDW2`x15g*^vpk=#aMHje%&rKePc9#Wp|JrCS~r*!qN-v2afoZv}g1!$sayy_wrRA7~iX? z(tKZb>h9oU^>at0zkHcz*z5)c)w?rg2!)bhnDf)D$OS^t+>?jj#Qx&pT^rG`n+>{X zvB;G@cP#%G$rbl!f_XmdR{6g;AjD=Moen`2pt;g^@*$jbgQ|NSehW&sXBkF~UagFM zT9^Rd3xdo96vov&bF0)ZhqhLQCuSN{@E>p9dUi2UQX}MVk2wYM0eX+m?zmc4mWG8ku9iE!2uNn3LT=q|x?$WM}7qx>ds;GI%1A`Iq8;9l( z$;gle4)`KHaDAE(5iThfUnEQfsJ^UsQPlP>Y8Eo3duZD{@9FCx}Ea!7;cjP z*u0r2cn$0IY`(~^~?Jn z38&p{4e7cz;?^|jtvry;nB&eFMt+J-5z6=3(S*GTw~BABL~KjH^3|0|cGEKl<=5mW z)1}f;H6r;$vaI44qH)^GA=M61pTUP3Tw{h-z@?tN#i4@y0`@+m;IEj85BhgAL{iF9 zK|x0;c8DZF_d(1R7YCxwy+V@a_SfiM?P3Etw|$z(iB>s}Hs?}Ilce33+oN6C3YXM% zsm(=BKDYc?jSj62tjLnLg#UUpf{Sjd)0eK6^dDG{1*gTiWicXWco4i^?UBv3fi9*TZUW3gR2 z=kDvQ&->$z{PqLnT{*DiX)W|?H+gvP@|B~rJ-CF#lTbbtubmejp&1)2?gHMekrbV8 zZuTGSetuVGBSUe6hd>W(UJQ961BnlCY5L~_P9*7@9183M=LE`zRirEBdoF92{bpN@ z)--P9>ZYF0u%ad21Wis%iV1fe(1Yw6%K$qk3&O>z9S%FEo*6qk#t(U3;Q zk#tWe60?l#ZJau!P1gzgW=mDf<_jLHiJz_b47jezn@bt(dhS-bIHq-TMDQ}SsRtJc zaoXJ_g#G2XdF96V=J>C{mF!Q3|^?TiVSf+t(jNJx~r3RpTqj3h84Ei8V^~O{Y8QwR_6o zd!=LtH(jC+IX3Cs1c}>?VxEN_JEpE(G4Le74u%^zFO~>!R<3wNnb^ z`HQ6`@S$!O#cFYcGpx&y9HsYG?Yck5wo`H~X^+*i@H`bZ{BL(+lV-;%vv5%%w}sy% zQ1vkCzx#S;iTl!jil+bdKX;RvzBKv^HyVWAZxdCUd1aIH^_aZD5*1-_NZ!Ze(5-XM z4<4&81}u}8oS)2^z_9~sSn31Fs_K;mp;4gsevf}e7lZkl++>9S+)~)5(t({Ux*@Z_F zm^y*@Gh%)QhTd60>FzZ^Zzg7}-j;>c1K5;pf1b-&+Q}+y+Ed)S!fvyoN(;~gMw^gz zYM@9Z0Cb)PHERMW@iQ14*-O8`0TWl_DZBf|vQGry%Z2b+YY2JiMlHP|S>dWdV1bhm z91j5|9bypgv(8#7ZB0}BjDaYPWoX*7TI(zJ`lh4m8Tk&Zcrr8VYF74D1N>OJg#U^l z0MM2_aeCF~1M}i1z)KHqYBT`+>y5+74D{OF3t1)Gso7SsH!`KuXq!2HuFhyFVC<&V z&FE{d46IiluoBQ2C*!0~MOim`JL5%8r`NjC$P%4-Rstzqg=-JvXgii?si0BuVtU#3 za!V|!AzqOEAFnUSidBqkyL$un>Nog{+U}d=OqFA-Ze@k$hiS1QFgB3ckOnxhlQ@1iz z0`jhv4xlLN+sNQ#S7g2`3a<=$mn2i$@~o^pjo*qtVlj|yxlCxRn}&tCu;3xhA;YKEc3!9KT`;xkt}@Mol`Te z?a*ePPm;Ozw>^Q+!no&bICSNs3p6(hP0A#;CSJEy_bx!%d61bPPI1|qqrGqP(W$I# zk{TRk+CS4KpT;-@D*svSv4FS{09t*)>9t3;_lHvHP zk21n~lUA5ol%J3b;Aa5>JTH5!4Wjtz*SOac7{cLkUeO>pmCk~>V@RcWi|&tA1i)r% z3w!l~Bn~sU#{RHZ_rGsX#c`#E<+>-9ScywaH&@m9hJl-o=rRH+*%cfJk@Y6aS|Hh% zS~EJVSW#NCJ_4aoq#w1(@^l5A-DD-NWvXg18I~+Ry<$JhfkgI|rxPCeR;a5*a^N9w z^u+y<<-Gx3in6Kt$wdumoL*=3?j%dFKP1x^$(j)(S@oMv$(yV*q|6HtPy)TEK+5=b zBRGcU0h7sPVhx5aa5;C;&_j+{=lCFRh-~O4xS>@x zy5ask4D@I8-LvhWzyRjQ`WN#8#;h-RZ6FWBWghSXAAw{B_uP(cLIgoTM zWY>`^83_TE{42L>fU+8+}eDwlLELv|@*_}u>8r_tn$MS{923dkF)efAr*8dt@ z<-uWfM1vnW!VI#MBj~c>;!U}v`lnfz*AmD~Zyitw85FRlE>-e&vi5MMZ&k`{=IO+Y znpEufk8jgkb4VxhE(lo7Q{dyba+`y}O9n^gRx@mPSKeP?QF_Tx8g0bTEKR&U$XtaMSgA}o|OddFvsBa^tv>h#o%Pgj9rA*llj$&kt~jjZ!D<>f@` z1yc24gY6~7WeVaE@X0a!AB-iJ&pJ6X<2=J^w>{n<{ouDb$- zaQBa_B(ftmQN~A&skUBDL(eL#yh}czRGBC;lCb0B9-&AP^ zTr4?d7%QtCQp$hEa**pcoVygoJzBLNvlGcpqGYgxn7;a8U4XO=pA}~^lez{j_`^bN zf-Z=Ws;Ys2kR@=EW%$ig%%cf&sT|hXCGb(rAjzZc^)y>~P71^qO9E^EP&r9jI0clx zJy-XniKWm6J`yn6CbbxgR+wJjyZ;|$I{HAL{t@h8iD^SR4nJF5Jd#+Soj>bp|C72|r}*hz*=!dGIG*&Z#h-PW27Gt~*Jg^} z?`2r=WUiK--R=o4^sK7b$2vtTLyI!wAgoB~i!N)R_(ay|5f+UunCE3v#Fmm%CFEcn zv){w`3TNSrC+hU97D`~nda`1dnCvE&;39yM#fnwc%Sx1?1+bb=vrfBa#_F-| zbmc^&KX2xJiKT+6xzaa^VWr=dYFEsO$g@s~U8dJ6Or5wm6#6QA}_ina95 z)AUvM&*941p!QfUIB~+2SdncY!o^N_-YbSUNr5}J(h^9l(DsLN-sxwMr(?%5oQqG5 z1Ty2KSc2QR==!#&z3|I+tQbg!^8$b@6@AQ1$BYA-o{2(S0*cA0_0CQ z^Fv13tbKL*A1gtRpVP6L7pbFq9IrG+(MDzncec~(ey7%vh@Zf~W+E_B{II<)&{mie*GvRA&bRsiujcK>tIgY>@bt}~rrA3g| z6D+|&QVE~f>`WjlPAb-WXFAQ2g>ET|qchp+ptw!u_@TTLo*RjYU=)IRB}WNQ2E_|N zH1Vnk|9LJ?$xRj00{XQ0KFfmuem}DsB@W1pA+YxMFb01x*Ka&=(PRBo0PkuaK||8R z^}uniEXmF8cQ>A5IKcrLpJO+f6?w}!{fTkUuie7N{)oofgJHU!GVY}rc7kYvkYPxX zapz=^(fV6*SaxhiO^A$H{a!s2pcAFhPAYw6UsVG;TX;l^jO0e5@4pZL+&GnCOA{|V z*>;A?hoj5lb}2fQ$~a4^A#u>;kgaZsGG^_%{~WVV5C4)p-&sG@Ta|?-8ONYc9%4Yq z^zF`EU}WG~`=04nJ?Snd&W+q30bNcq!se78fPetfN=q{GgZg!_78>{KqFc^yM$3vH zWJ00tznbn8UbkJ2=npO&+VZt2-;HuktXf}YsWl+BAfeCS zepmhs%)THERx%10%TgwYY1$@BYeWv3irOzPBLmLEI6)#uzAhD%p=}~XBuK_W4@2#w z`QL*z&M>@8QBy{Q^7VZTEqA4qLDS5!efBwu>$hatB_%EGft+@fc-!ft-a_L=HJ%YAz) zVV7cZBmREyiisix?MX~eOqof!4~dx4-(Ch<9h2LbtXt1>EC@fmJH`aR6;PP+;P{uj z8Zqb5J*u{6)4e&`vn!Q0-i%{1!qw71tLFLKboW5i;$*nK-3gxE-?z0>d&m@a*?IW&UNyQKYH>QW(QipJ zPdxg6G~N3@laKoca5Fa64#?Te`K-)&&YL-w3Mne}-jJMHGocOl`+-J_ZpUvY9yP-c z8$*YK0)u>4MqN$U#_uA`mFDl9g4WJnd25~}BU_P?51FEWznk^L9wD0QHH4M}&Lf$MMN0_AwN%R?UXYay`njlvC4c&9X zK!e>rwf@HhY0k&9qOrZY89iIvKC7KY$}!t@=!LL5fkjPkZGLnazb*Og`+cd&At7Ey zZ1dIOuosty*L0s9n0sOH`tRT@{&iEPF~N5i{pP?6--2$L*Ve{ErvD`YH8{<{W7gc(GPqIU zjJ3&VjWoweE62-Yz1T?RL84r(Z>f`%-|w|DxvZebJ1B29J#v(o_BZ^M|AQMlgBXF5 zB=tg{1m}sJQXBJ+IZ_Q}4Ntbx#-}2`A10Ec_u0nO#O=R{nXlIbw0^o{^$)X{ec0Aw z>He9U7M}}3ha)J;;i%AMMDo8jY}wtLmaEmZui~1I{#U89ezW)Bwtq7)xSa%FIJmR% zwr%c3O2%=}9;M~c5$pWEruy;bCMz?O2a&t;}yFX-7AH7;5hP2zB`+COd@2frkq}TL4Zwx>pgH)A`5d6)-8|Y*%R(!ry8MOZ{A4V%hF6H;+A-8Qm0jR-xU2Z3KI%TrE zGQmC;N1+g*7b&E#N(Nq{M_>J9C66;Cmj!yO4=%n^v9A;f;Ud_}J~LmWW^o#sks<7Y&w#5ho!=*R8Ghv+MWMz0)cI6G5&^r3T-HuDPh#fE{B_qZ&rec1VPeUu z_}@~Qv$Z7Wfn}~o#+y-!6}JR&a#1VO3puAf+G-aViH6Q%lPya*-Dw=Q#Ik!Yy6}Xf zr(bG;w8FCavg@(@uVZeDbp@E0u19u9O0wrMv8u!>6X5%wCCSU7t=UhjYrcaHobo-+6bhYxhDxVh&_|(H}+n z~sg z5R#(T{mV5H4v4Ogz;851Syc5onT3&c8xPheKQSE+>6OPC3es!Fu--N+n{b=!)u3|i zJgdfr^z#8M#UFIAUO=3T!vNlI7OQDKL(Gctu`kV<@P>kLnS3_k#e5Zj*Rz`V^s`!> zzWha;+?rLDjhe#b2!)qA_oiS$H@EJAPJMb^Y{?&wZ9i)P{Ml~+IKTAqnkggEn#+W3 z#x+HAw*RAyX%DxgW_2e^(eET{bI`e_-PnfBG#`@_f}Q#KAw`B68dmS)PpDM$!}XY& zfl~PtAvIzIP{yHCMw5q!MWKQ4$i9>1`D6|?&!ok8@I}6oj?>bE_YI!qVBpAvPO1H@ef$v2y zB9j@qUGX19m`wKtrv4ang891+qv$bf!D^RZu>Bms4RJ}sS99Z6NQ(R= zKCTUND5w=1!hl>R_=~;AKDHbtrxS!xh-r+o;XEOB08)@A<8a6{UI;b$~;s}vG$R$W#g?{QE+vZ{J|XCb;^x&;KAZv`yb=h zUhiywvFwD>3dLC^=p5TU;CJFZY0a(&6Vh|H5g*@wEGG6j{bJef@$Eajh07ysImrZj z*OE)ouoySFE`sm{dkm@AihQuHa{c_{u&s)tIrg}+i7(UzXg7`5qB}_CvuuKZs36i4 zx2Zga0A>YfIo&Uvad_hZF}4e%CH1t3I^+E6?8HivAI4$0%OkmABdepBgh@T`%N=!;T6WOIA<>XX6 zuM!(S`qnzA7<&@;d!G0FTy(-yT&B}kSx&>3xYVb(bUcArmr`Pzh<~a$WHmyuX$6`= z@y1nn8+A8+gNNlT%gPO}OS9*996l#>cG3iSm>3FX5NLA`Zyp20m;m2TV9$25O!5VF z-6>B87n~wMvxf7tDh?kfPN^py6BnbHN8sZ=0xj0rc6AJ6HswqX-dG54-bJzT>33o< zOlMOq^?|zjd|zzA4r7ZXOVA-&g8&H4I{mFLTnyafJYJqZ= zY_$5YyC8f2$8&tGR4M|X2Ti}Is+1u>Rt*3u*D-=f3k?>fzTE=me3z8YH)lJI>3C-1 z{r%TvZN+7KI7cTuL}<|Y zG6kc2LD!}H;4{{>mw2;24W8vVA6En3dD#acN!kPeb@LO91NK=><8F=f89J!tBE^bI z!6X6`iorK3SVkiiHVld}iFHj!TP&So4Np*Y?^M@LVAx2*T{;g%Q=BAIFgX2_TyUt75+>jjjD|Hsf;6jOlsT5=3J%i6fQ%H_2rZl3 z2VZ`bn&rF3d$!{&PQqQu1r`YfX^-GLMFt#29HJ)|*Sa5C`jU;#%385ej~*i7QTCKc ziouOMOZA>^q{@-z+Up^H(nP(Mmc$1Q6dO8TnJTGVm3M1Gz<}TR6(uNIE+E>9v*N>w ztzI#!r>*(jUR4?Papg8af}(w$aU2$!%22;9_tZksi6)@QSh-{AoI1&}rV2t<Xc_wL{X)7ozt$isY?Ly=jTT$pjN=?2KnLZ za+ag`D86rh5Nh8=G80*9t_H}gJa}jZn}u-p9njeS?(uB+tW;-k52w0VdZ{3!q6n_S zd+3Rz9aT9wH}+u_R+xGIA%9A6bGFdwe2FE(9vO0Tq)wrOl9V0HEx=>i3+M$bH325X z%jHxU2<~PdTYWNC`JTFuVD4?egfc5`iR^Q+@?z}Rg}Jk@*aA-lKVj*C$D%v6y9IP5 z-L$(L`0B5%8|6{)Me~)4h^>pSeR0ZA!JWWw%G0>R>v{aMsVmwCMxaEuPlbRMqW`h} zO#lsLpKNHboEznXntdgx0(#dAZsfnwr7}Qq72aEn*M2S%BV^SegB_5dtVtrbA8(7r zt4%U;e|bxcGc{bsr1HsfRm|**lpdq1x&uJS_9ezWHNzmR8Jlu15(t5^cz0E0oud*4 zORMDWEnp%J2CU*o;X*RLPXP#fMUtZwIzgk)Q8phS)0a^H7c~Y7wxLr{+cUBJHnwsB z3Y)7&^^>h@8 zr;Ij=;}G6tjky`ak8@8D61qd(h687d7KSg*%Qp^H1b;GHl7c_xZGBmkz7U*Iq8=D- z>(2TP3bI&XVWNES>a%gTDaLLIatzXi*vi$)$t4IE5+!Knqiji|r1nt0mV!1~X6}3q z4;oJSHjm~Ot{HFVWkDREiS})MV8jYpN{a7$nF2O;P5hJRe!y~GJYs=OFIou{Mt#*oK37*8^ArFe>@^AYK&59=j!XWjMAq=QX-tt zKSP#9o>~#+)DK*7^J=gW146?<&_4THM=q(qhEy0ms_QQ_Jl#E?NHI)cLg<~>f=BR0 zYtaLJrt3tzfag`N=~=J7?_!u88ypK4513DfJNtXQPPG%wo&*FDIr7z%Qg`x)3>PJ7a%L(Z0>S`U9o-W z!YH)%uv!nvZOr6^m*I_}pSJf{$wE~J67zY%m!5lk2%rvAbW)~bqtX<|NvMFshsn&= z4ik6~%Z9;Hqmr`9`3vmpX6Qt2#bqd4fU?0d5-6S*Y+<9!u5gOxAiBzW#IuNlYGbPe zwXJLW>TSP$w|x<}Z`P zMU=RUX%@{AK~L*X|F@Gd1+*pr4WU5&g2M-!CJw&6XYi@!TCW+SvC_5`e~qFSZom!y zX=cB7HNvVVLT^~A&z_IK*S?5D)9lai^Phuwt)M%$Rg{W8X!I@D5J{YtI_s)9<=!0L z4BC|b5aBKUUcXw}YKEK7pny~Tw z|576{JQ~Vkh_xO@SJ`4&=v##be1@CBwJ678NT)2;@y6V(BR%M$@YcPDUz4pI8Sm|D zL;s+u_D3H5;6MBrVRubazJ4Qvs7`untyAegwRJhayuQUixD59a%7FWf6jlin1cAF# zumpQ?FP!4+Ib%K!&oRuO3ige+ILd5W9QIY+(eeGcclP^NnE}}nes}mzv~~ zerr&-GkVbT`@xytes5y^wYvP3kPp{>2aaRUfA0!aya*e)4w=+&O}cBQ8kaIo(!3tQ zhlrs;B<1-aaN-Y zcc83qm?^bAaC_H(G_fZ9;<8c-u3l;|&>N56hJ4~=# zZsj-MZ1tl>>c3^e|7%ruOig?Ne(LLZg}eGhZz|)BU7|=@olCZ04>L=vSU}wMo%*3f ztW%El@2pDaJSAS}yN)}?7mnoFT-*?nmn6P@Wa%MaY%zY}U6ECq>XK`-w%22?Vu5FI zCsxPnJ+l1H>Y9a3SDq<(=op%-d%Pv!O{8Lo*~at(x6RLd9^le{uWtds($+CSIqKFU zU-rr1iAT-9aUIWWHaJ<_Scuruv%m1($k7^ANn;)S^jsDfYn|i$_GEgwsmsS&=YeN; zCC9e-IsXM6gw@)P_?Z$(l`QPno%e-MDX_(j#gIYYO}9r@R#>q~5se34FjOp?^X8-x z5qjqv>ioaL`w{U!yUGqdAs!=`v(lZyln_>mi!o@_2^*VnF>dg;maIhBDG}5)xAp3zqpQEQ zq^3gr=*8FT+YCXLX$TQ1J<_M#2Hy>Rt(LUNuuXevX)!T-fE3Ftj|ik5wRkcyL@p85GOU zD|H6xXe*=0fewEE3|;BXvpH)={J(kXy=qUlnXG*k==be$aKR1ngDv#v)dL-wHMuqy zrrLF919<&~`%Yc#zIgI|^~Ryx*`MqT@4477_owJAi8K15$^+NemHM@tpiQ@81jv4R<%#-a`e7)V`tD5pw%JRcN6Ca%a`YyB^6(7(qdmA_10Dkz9-{B-|O4{c{k@pje zV9JKL0J5%blb4qAn+EEWcl1r|utlel|Z+Y+p1R85wRy^WI0wlYm?T@{@ zw)S<#_o?<;z{A+dw#P+@JAbP99aLVmBFc?z%cyXY*h#I0`B5#Uc>8K{X9PFc86o+P z3=p<*0rsMcUo~qf-I)I(?kIIC%46oqKR{__&U?AVM^aAV;1N{lG`d*TDV0+Y$Hg_e zY4VB}o3xMv4O$Q5EM0NgvEk0(^!;hH0-?j5(25mVO_TjcOy5T}%@)QG0v^Wa_WPJb zt&iS4W(SbE=Z+UYanHk9Whn5r{6psdv$iO*mQv`UL!HtgmHq$8ht4)67X_zy+|K0> zHh=c@+6p8p=1J-*fy0~?C8v!O86??17@DQqw*D)zwNQBn4=_`@KKj%?-%ndV zhk%Y=hd_%P50$8&LsL&+~GVEkpUT|60h#{0(mExcQ`f6f(HB60FUUv3*F_zr< z+TQ*c7SPelU;bTd4_{Qwyx_)f-RWCUuQSXD3ZQs!WYtaenGe*xh;qNvocbrlGlIQX z(tC#rqa~{pH-5oDqka4-A2TB`21wl=DTJoUI@DiR7xl&@hpm&-g(_ewp+G7rAtzDZ zgc7|ZfET*qiN4llh)P;_HQw6Hx}xqc%XCSySk2A~VlcEYD-PBx9*ApD!F-<*-?RwT zPWhD;rL_oY64w)* z%;#5NLD~{xSod>hz&f80WZOO-u-(}FaPt>l zUPnY)X0GJJ%{>;0;h0PeU&xA~N~;(u3)^jxQzvV9CCJS4`raM|C?D06=OTZLKyv|e z*VZ)?TY{79J_AxBHOocbL=;(WMVMUWJR$!Oxg8heS7dAhS9)}jV5O;ITzS?08J9X6 z7ej^LqL!H*?w+-i#O;4S1H^oHcL)p-NPA=!p|lqRw)!`kA^Gd>`G5I6_GAg550|2} zEC3VhVfqB92Mc$h585s6AlNNQxY6#OjDH^RTax8v78W8Q-*Ef6_5P^cR)?d0jIij zZyOhCu0#t$sU=w+)vQ|eS$50SY480Z?Pa_u&guVvW0SAL4?neB&ut%&pZYOi`n39{ z$7v7ACof71pVsZrYu-NyJ^RfPAK2<--YULMxTYqbL3B6k0PI74r^$WtNg_$wLnCPZ zitFyq7LCl5+YbX8-@AjYrn56I2iaqlhI%X}OR@vq>=iz&NFX#hFyh-63T*1_PaVHA zV)wn6tLC0LPz_kWaivV*jk`_YF#ir3b=k~Yc^rPy?1QS5QfzIsA=qezxge#0m08}KB zROHz{jutv5BH=OkRm|4yS4t|%mj>e5%*+4@MnuM?>CQ-uPmg&a^Qm}v;eX>*IVO)c zQ~vXojLThdGTXJ5Lb=QA}8Bk%JH+!w40A`u`H0^pm0 zAUyY_riQ_3x>*gOO7iWR302c?9`0z*NL2+LqV6jY1hq0?D*{kmclAQJrWf}Vp;SG= zQ5^#kyG(8>yc)ko|8{W;B&Duqs{qc8qGMeeg-W=gQNo5%Sg9 z@=Agt^oB17Yb| zwvpPGO#@8ixv=bWg-dE5)NWgDse2e{aK53I&RZU>R&XOry5SyiOB`R>Yg{r^_kK4X zl_MW7p>-!kgB+=Sr%^j&OM4-UPL0$lXwSK5_c!VfZRuxt>WoGncyBcIP~u#Kve@v@(lkJkQLWR6=|^F*x2-nu|<=y#eQQOV-wN+ z`Y!_iqZ_KejWqn?Vd~gqdiJ|1(b#O?n%4Oyvy0!&E*qOiUonquGQaWNoNSD_eFbyp zZVHNjrP#Vi-T!Y6WO`={lXe`w)?@nfyhYh}Q@ch>D^IJRqk2!93|gu&P9IfNO_wLqEzDc}g2EkF{a z8Rhz+0rj7dh_aa5cjG|xgx>8h4renAnirN1)*&fDu3aTFCjqYg5S>^yWR@ZJ-}rzT zZxkBkr9>tfMjla7)==E=vUt{Pd0A59S=mr7lNXtgz<}}BA#I1058c6?67?4@#VLIz zZzrvwt0rvQ1Qg@yJl?278GzX^;*pFos~LaSKH_>$CLh;4YYaxz!&k;j6mxLrKB@(; z01WokdW~|tWZuC>4k*H)=Bb`!?X2$GR75FA5O z2A(i9e)nPCD;vwKZoy#P67mukp$B}>d zOw*FAI9DPkGi)-?@Cue5&-#ILkg0(!{kO#vx?Ge$;G(N(+B#H zUC$gQ*oxaYqge`WTt%s`By8=rcns5Rsr$tWplb2QBd7CykbO`>$^N}b0~4@?d>?8X z=NVT@U^5eT0+mXcZS&pFM#%Vt3VP*LRLxa%qX;Sh|9)N=bX_H$P;#b18bRl)cVvly zYLOZNIp3^Uo9sRD$w0V9MUf*t z-jM|6_ukI}+EzJnre#>awR@fAT&_@{JQlX~X3TPBFqXPDC5cCvWlQBVyuml+-E{ zmyO8ELvG;|CA^LO1f;OP_(xf~>OQ!!zbKnJA+u=0-nj&Ock zYxu0p%?BGQCMH%!Ch#|FloTN}AYd4Rx3lcP&4^k`yNc*VBjc^|4kke0#fHhT6 zE`xG4!E&7i*?%=}=O}~F0L2X^pJ7G~;toHTa5?t9#pG82xu780P=zGv;*C~;@8+JF zSE*-6=K$omjJKupv}B9??0HSmoST159K`Ka1fnmm8tZMp7v%%8!vLjqoWe zm#h%rd^6tfUkq7k8i2r-S?k4>eeyRR?ox=rsswboR05ct={4=Ffw`po=w10(`9heb zOB(6snkLR)K+dUJWXM7;hbR@vdoFVO1dJAQXaS)FKU_81!U$AABL z(SHRQ{)zj_iAT9Cln?Gy@NJJd6?r}&n?y!7iYj1Y6r5TA1Ac3Cx`$pbU6 z2$YK0eAMSiRm)DEve*`Bp9x8x`a7IN+P6v&TOsWO{n^)+Wb>&VQctoGt=vD33!ha% zuHaDHYI+2Md{nH|IZzOY>C!=dFs>tcGgZb!nZGy=?CL?~5J6!_TyvRz8yw^a{{;K3 z!}fa#FhB?Z_~9<8e{ylZG{jIuvF$O$gZWo>JCIh=KI1nmJ- zJmp+mPbmK?ic)8W6hDQ>;*_Rw_8>)VWXnrAqL^6&Xwl1nK#*;8?vPmT4(+On1yoR-zsa+z{{e?D%$y|l3>zRrg1AhB)O zMx6&bvO-O!AI3zx;3&ZGwU<%*-4F~#1>fiqyOS_UocJJVN~e5#og^+v99J`{Vv_oc zkppL5xE(qM0|5{>ll_0bga?BxjMbn)e?Py(7@TCt8*Ow3Rdj@bkt4CKO4BkmJWO?v zrf?rdNw?L&_R!5r9B?*SXq$brp(Nvb0yvDRxcGTy9l&>C?Gb`SA2^D$C5nSgX}Sbh zpTj@EVIP!3=ap&d*9zbkzGC4s*w2Hhg;hi;%Q;bomA`2jQIH(b(L>T`%I*ah8-F;8| zZJPidEKw;+`x9Yrwa!5WvDUZ(F?qP2FAyz~z|w#3puWHQWWJpeIe~<{{?%L;IzpIb3?>hEg6+)v@vk@In%}IAUe^ zgqw3skDV6suGjC%dby|38*^=kFQoOp&On}N4{O`{FGrm@{4Aay)Nc<9A$3J{`oFWd z5|>nb{BihMEhI*>;!p1SXUj9ylS|i6QvEYRf32SddM;M%&&B9>vwDyC4?fdB+xS-o zc(VP<+G_WM_S!QF5^6-cS~{a@b;h9C*xerQCmjznwLjVYx8QxqIzR6@?vYD8=ly_+4~dIDlRa$h@*# z-gM|X-Sk)b0a9BT+yFJug*SS|xpy2>nBSu8xZHIdVYQqtk{xFZ+kcv{M)2=RlZo^g zww*4g`iKY8n%)|_Hwq`p&k6*-vz!_c=bS;CT*-xAdUwbD-^Lg|p{B>jiRIaw@0RoKR$u3F1zfCu>r*-px%!r5 z+PCa z4j8=LmTmVIC(`aBx_NzRSys<8ml8j&Y#%>jvAf9o__o?KV!=S!aHJvAcGKOH)wD-l zaDZhEHXXA)`-Qa+8h)1V(|#Sf``jktO<3eqKC?8ggFaW5W%l&^t5h4VJ|%8$uiO(4 zt6DV98V4+FH`x5}-MRuR-=j=Ibh^ZVV&TCPM{Kz+Ti<8G?sT7&z>>y}+3pPD5w^b< z7v36&NC80p5&QObj6k>cnMMvf{9FsT|1!5=C<+9wrsl1WETN7lA3{{DLO#itHRN;I z;+rn;^OMV2=h6GXL!_xTFLM(M#Y)gLO-4DTDMyM>cK!1QXR~^t2YTpAza6Tt^*Xco zKbv{QKkm*ssqVt835uk20!)^BGP5A&@O9oC7mR7W+idNM4Nqhb zD6hdbl=@hIbK2QbwXf*th?>RT+JAC3-uQr7gjs(`ul1mJLtLF7g&Fe!Ffo;hs}cei z)6UwipU?WSS*DoZnSQ|UTK)4cKn2YN*xe!_)^nFThfYF1*>&O$E)5-3`s5BhgO18< zD%eue!-DJ9|K*CugNMjEi9=20()_Jar^dSF*&KAY`ro8G4A|C(msKTh|06H?;#@MIfpN5pTU{WOJ#-DB}h(G(fqBWGCGR!(y7Yb=CXmAy~urvKYx`UFd?T$ zYa93ztH~x?ftk0g1*I3J{fr!@EN}chB+g~@nnFKkdp%UMaZ+>AIw>F|3#DAJ)%#+W zH2Ek~vc&apXz|$WeD-CRdbt=H&`7&1QzS?7ydxcNJT5>{?_z`nok^RS^rSTLN3Q3d zIa=5sdfwn>AH6ivrL4(>RUZM?kbx|Vjgri^+dzf)bYb{>0wOL-P&kze?oP-SG;UT? znsUKOjMLLEm;e1A>y1Yyj`{fw9E(HGHuJ+>>GP)Des^y-MBn%mtr zuR$PcjltJ6$*?eF9jH=d+T!Hscw7fXW~}OSV7FFgkB_QUBeh$18*Q9t;^-3$5JYs& zzpUz1*L0+-(yXFg&e@AoDQWc`u`lZXJuXLF%60@$dabB~jIJZv?!+pQr8m*5* zFPJ1y!dox!G14wIIuUWpZQ;=TfV0g2Agv+?c($wcKm1xnW_)v*Liw}AL+swMtIGKH zJc09eJ5{chgDnbs_XygR{L%cq4cC;jjvaI28SYe7h3}*j@Kbl7R=O9Sz z@6v$}694T?0(e<*R5gY7KA?b1$8_K$HP$%a*7ZTEB&7qD0#gC+X2(P=tkbnufkC0Z>BzU3 zZKKo{30ZVFYM5HDpRfnVJ>1IibsE&Hz32MPdcI_ZbUSLIIV%=hg(;!tJ(&^&`jxk! zKG7Yua!285I`$fdF#%arrpS@zaX%8*)$iiq^ihm-WAZ!6_4NjLfVHY*!BDUHFP-W@ zBnBzeZsOa_L4~^6i>K3_(nJ49Q@XqriSBO?kqG;Ix=7$2LoGXR>d_cB8Pj?5LUAm6 zIF9G*FBV9@ZMpJn!!nsDNAbZ)c)5&(9*A0TFlZk=>!cm8k3Vjz%rw~mAP((KL2=>9 zD0dQt0gpo!p5E|rtEmqRQjTd`{UF-3i@4fK6pjaUnnR-XkU@eL3n^lup8ydV766gu zU&#|C_XIr)AV&O2?+^H~mmB@%BDBH$AL(~r1$2=hr@uV(>92{AIynO~Ws4x{-E||V z;Oib4>8Q?z9;fPBWR^1ARn*sJu?6mmW=2IN zT(ZFZg5V3BYjB^J_(eTJ{O8Y^StqCjDWP`oMCC<yL&C2N6={i$$N-N8sMnA z?nlN|zC`&=(B=mlzCtuX0)Q8!5VI6;Dh=f1@1wPFR6(kLMBJ8MdW7Lm zDm39&)|A(P}j5iCEnIA9|@f1nX>7(kwg&v{e!t#LX+X5yAnijS4h zEq?4X+|2np8Qjzj!>}*+*x!tG$32wRp*bNc(O31{g;z+3Wp~Hk9Q{u;fR1u<$O!+d zK=M3<&{RPpDdi0fVAyvIH46LYeps{$P$!0_O6UwqU(7br7|C^7$$|Ly0@bk)4jUFd zqGw38k=NAaOiB%3xFt`8ZmR03cNy2-2AWa@hiI0n&*NYIj6bDyy=&@{4i)wbjhMN1 z+EffaC#*?dzLh0}fG<;bNpN-LbW?YsDKwl#JAx4)zf%tWvm&=7skgVS^b?J^C#KlX zH%}OPvpE{?Nyu+vzN^$Db4HPR*@D0m?mTC$dwAD-(-Od8n$2rx8+DqPu67a?V1***@BULoa!7zCO?Dq(4OBw$4Bw|b1WmiLV`RADv z?z)Tavd9L(Po(T%e*c~Ch$vm|K_yyLyHz~g9ZX;g#fXW-D({=sBOWs|jITXGVm5K^1R85^{z|y55)*|}f zsEBC><-Om9)f|`}!M!jNR;(T6*9hI@Pr}7P=_!G6({d>)at$%5j#Rip!fhP^$JLRv z6Wmi@+532;6BSQ%&i@*LUOx25my7sS0B+$+v9yfC@6?B`%D$a+<>PxhSa_j;Oi~`{ ziL6{KR_?vKD<{yuoQ}&8(36hSPiLl~N-a7Yp{5MOmOBp)?uT{srFR}3oU1y5Mj)5D6c zix~~zVHm>GnXS9HYmXgW>B6<{AkNXYQPG6=qTk~XC1Wz*NQhBtQU0d&Dc87)3!b}l z_}|f_-(rYVhU8c-qK|P5BL>-WM|5CqY6%A`+65=+2nS)I^Ray2m!429I>*o@ib?Zw z?BxJz&8o)x{Z(`-STIAe;@<*r9g+S1rUju_ssJqbk~`df>7M?dg7RMA5H)VfU2Bzp z`}pkHk?+#Av1UkV;1~m8Z`JJHW60k!YwH)k3}}2=U=b4m`%F+IB_R9S%toe;+kP+! z+6Pw`fERy;uQPye7!BbBqgO%?zi2)DJwn4Sz`g{V+|XzUKZ9Q;*wp7kB$@E9?h<7) zkNiu{{uF~ntw{*2!c)1JnN2U=h&t>vFgOswW{5 z+FFNp++mj?z%M3Eo&<#4Z<+?2q^(1~u{lhd0@Uvh-y`TjXo?R;lHA%gk5m z`X43ba=GqZSerT;wW3h4$i>T=eURQbuuDVKMj|$->g4_9KBug^{rSvwvw{au^e|Y5 z1li#tGWR5MPMwr+fPOI>(mNjbjUG7^?~|x*ut)<>EQ3BOqa(dq!Y{Yf>6E@@`JUN2E{wm^Z z75`+PL3^}qC$<$TV8Tb>_ku=tBH-3^GgCB_Cs>AnH_Po%+fAvEZ7gCzMOsMS#Z>wH zPZIPE4*rMqg57MRLohXs5Ke=@jaB5r2VisADu0w=gr(@WhfAM)q3qJ@lrG$!<}!x_ z2Y(5`9&5{)97>!&Y~0U)e~-j$V&PWRc$x15@2rQG-odwP%lpM2Uo8t={XX`M3nS>4 z8VVx@S}K-DDjpKe7T(17W$0#Qq=0|%tL$@tIW=~Q7x)hK@O-M61A2%>b9BhP^)SyLS$t3kpA&iI0|OY)Hu7^}WH`ip)Ekj#GxYfi zB9~n{U1J5;vhAWz^$Zy=Q6XU>GQ7Z&SEcot>xw5D9RG~8=)URx@UHR~R^dvY@L0sB zDY3`zjRv0H7*IPpzolXu8zXbSbbf^fuOihor6bA&ZU3PBche1b#8>+K{Tw(4`}XdL=<%aV#b{ArAhK*A+1#o^i@; za5)uHJtF#^bnxExN!=zf<9+MF^%c{14jSK&4F|wj#Xwj`T{fAPpY8 zBy@rx8gILlMN0T56iwVgA8Hbs{w}YpuS7yYrGMc^>gV^pJ$iGH znBWMmr9c1Xcd(r)jTwmvx+e=edI3WNmAHQ{=0b%r^qNyy-wBZJNVK(k?`eYptj@f~ z#_vbp6b+xjBi~728IlTW_wQ#vcuKinOuLU6ezVGXqgwmzH@js0bYMGYWb>Vo;pK9Z z2dT~7$FNMvhbZe_C2NHSX(#`$bNu_U!N7+@o3>P>=%=BOJ7&!d) z-CIXfNfyt)$-}k8HU6w z$uH;dN6)298<&pvYCOKH?#S0rdn@{0-}*WKWZ}iZbNmIt!2;Km39dtjVeS|IJg|s; z2QM|>Bk!p~)^lsgwl^|I2#cL5xP{_9Bjo2%Yr$u49>bgiWc${K*1FU-Q=9F;j%nAj zeDACCu-nZna~LQHg*oT^nYnUy;B6UCgWMnpdVA|$`^1}T2X^gbJJu&C_q{AvZo?WX z1QaPnudckgJsg5#jgX=R)V9Iw@Jwfv|LF9qf@D;&>xQ>w4 zK&7a`*0m0KRBZ3VYwoF^ZAVBE6w^!YWz=L`oLZ8@yLY3@3g7>oA}ZV%7xibY*4LJZ zIMEBhN|(gE#PqKhRvQ{Ab5p>NLZ~%Fo%r=Hi&p)u+7}-E&@O@&-*`y8)GX|sLVk>P zF?@`Q_Y(ZtbA5J{ zFHZt_T3+kXC#2*diz6TQ^`K(bY2RCBV+6Vi=7t;ejF2GyK4VC(8$Ic0O@QOc{*V;F zZN1?(XVj6!&@9}CxpL5>t0w7nNx_iuGM~K~*2VGfo{S{J^E%^K&xF7Dv2!MZB_-2x zo*ST^R1`y75O-vx9EMFY?hsj$^}mx_MqCE2l}feuj~?hC$byd9Bpbm%U{@E=qgZvO z3h4N{cv`>i^|Q_yxY{axWa9V3epF{J#_hiwYRC1JuI5%>Kpjf#KCDXqp1mxdR{&%c z#jjqz>t>fDw%?x>!awUR_S^5zZRfG` z*yDW8=dttoyx-5)_yxrAy%j`a!=AC-=2Le_qvxp&QKJtSN9gr;m6~(Jcl$~p zZ8$WkY47sx)Al{x{iF702Ubq2?HVH8v$>Sj2Y=(K{GbQ7Pt1OQBJZat(CFotP0w2Q zzZ5a&C81$mLT?r)=bE+M_A@eV;Le>!)4)bM_~v&#fjSAtiVw6Hoid))D^9<1wld?I z(t;C?M&KJ(9g-@-l0C=OQ@!~+)UJK042Kxx@<^6JKa~W-#1jJ*TwAZ_F)yyA_A>;b zs<-1sR*U)S|M{iE?kWPy+lj~aVl$lAC*OBvM9bSLg|7`15y*zF7(HZA_r|9k!#-0< zW#@vrZ0bq3_s>04+9Z;0{6@R2^!X4k=36?}dZd<<>SwGvM+@XCLtL&!v?`yKMlLqh zaHfQ6#ok<-o(R9Z`ZkZ$!jHlBRR^cM{dk0m8 z_CvC-<@KUsjTsNz+y5_N( z%Y-HTepb0rkQO|9b=jaXv#YST^sKJDCZy%HNruP$-FWPDd+>89NLfm&0bflDkDokf z6T=5%yxR>gE)CtRDCh70bC2S1?@=~`tX3?PV1D>f2$M&at#=~REyen^JwvwB=r z7kq}6X&%lpz$}8Q=75^8FivgpnDO@ZI@*&fjgqFyE@YBS+dD=S9x~8@KT+sw@j3{M z!Laq$J0N{AV)XThj}g*=I{~qEU@u-bekoihfhpu_+mrH5XyYmIEA>q@lLEKh`qAGW zcedkTC)mJ&w}Se^JyCDuxtf++VzXGDj}O1GNhbxoWm3TJ`7F&(BX?Y5BB7yBuI|Ol z{`ODUwTx+!_95!h3V8TncbPBbM{2V0+^kpX5O5+LeTVs^>GAoy8pztQ#=?9Z^%x8h z<`B;FBo_(1yE=??skX`tpay4o2KiwN;xm)^|b3gu~^)zg$%DM2D8kmKcj= z(Boau_G1oX4Ob$isC`1Nh6#eBh{l*lGeO^vCoa$3`eOeVU6Gkwr}#h3MjLNJ=O;#79=A39DT=w%q;E z-!Mc(rfNU;AO}fYAEgmyO z-w2hnn1q@WS5gcHj@?=3?m4KBf~@%@EpzF=@L(_F!Py(@*Si;(H8RXih)ySu7Vgd<(Krk7diO9drWg@<^N_nsSDh+lX)nGJwk18V{P1|IT~W%fJB<^XKRR|u^zILo-Txf% zu3kv~njGd!6|}Ljb^hbib=BFK9r{_wa8+MQ?Xhx*!8G~Kfd>w$i(SsOX=CNi zRdOUZ{V^3kKRxXB{eXJD^XI{vRD|p4B-Q*0$Uj_1FUR6L`L&;%rd|5i$P;e9-#hX8 z#niyC$H14W#a_WCS-79ue~70D$LE>@=Mf$|YirOK`(7i_y!LX^X;8?b`px!3r0M=0 zO=#t|!@Gqyb|Rr!Ne;+RzII$$%O=G1zhxOflYSHL?Sw0#f}OEQ$RcPQ;+LB^knl_% zqe(x%&uh@Y;Vz@!qSEo>m&3xV@bA`$k0bD;Z3oJm%NYakoJIJ?K2-%iw+qnDBMl&SH0;Der+0&irRm*$1VxAQ%H>*<{4WzOsgF zmsm%=h|`FoKA&u4IZ+RRrw$fClHE8oxR zx*mtj8z>(c3B0hWrDU(?p*mPL50PD8bCdut87OZ&)M1s`*wrS7y!ot87_lznm41?) zu)Q8QIC7`B+u~ow={-V~Jxx}xPFwAeAqr(KqAw)g@8NyOJ7s-{Gb6^Ds|eOAVt=OM zBSbz8^iO<6p{#s6!D~dIy>Agwgl)hs!b=v*)3L@_KCEPMbieG%zMtj$W#y^lChN@d z60*u|Wkg9F;^npG^AXM4WC4sEedZ!!BdxMKuC%xh5h@tfCztMLm6N+cUefbpddL!F zIcB6bXP|uVSoyvA{#l2rvz4RSv>QkF>Q$Jiy3oo8fjhggP^ePPwr-Q`RYZ=W$OEeS ze)pk4UU_w)hZ7cYuQ#A9wLJWu@jmfb_NC!sX1O#$UXj-qTKv^DS9wbijwP@HZTNN%M_F9nc(ku205r>@5y~aV~i!o7z zd;P1!KfWR|2nR`V$Ct z+avz2^i?t+{BXXfz83LapsnUIc?ng1aI^z){m$IbSZ+m!{sfOG@>eYkWX>E4nn3KA zmHsCMW$@P&SFMkXQw>!XVf4hPY?3hc`n%(CAq%H2v_x)iQ>nb%iZl3A7}NOypG(vUgwk!u^4xD_X#lTT6yJunmp2pV0Z1bD zc0Lx7ODn7JSM$$==Z!or_*s_G#5*((-YkS~i;mr?YA&yfRY|A|6h!r9T|ljoDsts4}6?TlOrS z0C$qkkZ7<>K5YE38jjA(u`eI`Qj7a z%QEON&sk6uI<|#r5WAD8Q?=xH+Q<3ZYo1hs zZR5{8-d;vV>(trK9`aAVqgp!hA%;=$67^=t`|-xO$Sn*OJf!>l;deFBIHG=6a+akW z?1e=XT9m&H=3Di_xZB}D0v&=Byj2JvyiE7mdDPN6ZYvCWd>$0ZgeTJjqpMSce9TX$ z-LqzJu*kdO0TuiJ_`0yuLG%9OGa!SIYKKP+|Msx0q#P?L2s^Rql`p^G2KbGT9og97 zwCRmC0OlR_m?QS@&3Y{cI2(P`H>AH2E3IcAZq)ucO=5xY-5l!yjupVs7U)Ql&}O4? z{M+*%<{DY1s#t)t4bIUgETlhqRrj;p>gR!{ac@T>&OJpA!k*djy1|=oE@)oR*gmXk zaM$!A*L&}{)%n?l*s29VB=9@!ZHO+T3w=ATM zujlNY463Au*iFC5FKZ(q70h#I?O`>%6kHVkGCDHNj@eLJrt>B^11qln4;w@c_BfKF z2vt&x3<&6PUFx*sGz_cvxxT@~sV(0<8lCytaVaC2t!R>}*?BW9hVqVAmQD)UW=DT> zOPt2D1BYr})Foxz7_PnjFEuE9ZD(V`t_zvDu+~ zySF>=PN|Qy?++h1iFYmCcHSXftu-v`L~d3cP=-7rRjT`FnMlKXu@2Zt=*$I8m<$s;+*AfNK`@8&%^jM!HJ zPfA4Nq?}a#`Ruqvk4Q$|0d~?v`JSIGztS0u2>k*nq6qMLr<1Q7kuN`&t5XZwiXEed zxIuT_{&H@~K=*Wd4DaRM^64N3_)mYK6j6ZOuw(SI@%hic5(~`o3VtT8HLoqOJW*hE zzQFp{O1>3%V_aEyMV5`Oxts`32G*>(3rQ8i`HNbYeas2rywpB93?naCv#B(7WRu6O z9l0P5g$CdG=aZK@I)(u+pj#Fb%8_{8%`|w3eU^7#VPMJEBV`4&6NSO&3qx*w&6v;8 zloXNE#7dxU(I2jrq=ulAW|8Cm7)fh7i8FiIDkV=l0t9tuJ@x z$#*i;cjX(Y+6f?b-8I2_yNb5%`VqrbdVVfFW7qE3A1kf9_TJi6{9xA)IEVRkSBZQV z?7{|?5tFlq$z8|fZD5veWtQdrEdIo?Q$!3B%x$}wwhU&~1NqOA^ShE>eX{t$41CM1 z)=eu${Hi-&IHr2@z#_+j&n&3tSkO6k_P_}?ehR5|Ef8+(WA19e# z{k=PV^-NoaW~babV2uXOKC5Z`NZzwwxmTM>%-@0L2_FM?pN;+X)9zI3(_dfJbWfM8 z^so7utNyFO=%~Q}7=;Ge4}h$&<{Iu`Vxc;Q{EVfIB<1*=;T4Ye?0tJ$bJ?V1UjT7ne^cy z2V+BLS|?#y)4vL9MNkQ@bF5bz_B1RnJm4OYJZg~?m%L2#yEoQ~39Ou*gb|0@1CC<{ z!ReNdx)MGsqJXQrCR&c-2K_BP_#=16AS30UIc#9< zF?u`m+sCzDk3Q1HOm^xSgx%dYPrA3iatX#>&Yejxc!3DN+ux<3_9mqY0xOr2x&)-6u)17iGU<3dHPlmc0lQ`Vtz(H z|-Xc+VKOu5KIycJtaM|*QK|P5_v~Kf*eZFM+rWalF(BQiN z*Rlg&u(TZp#ebMNRBLlsyHL;Lmm-{f?T-fTVw6kE#SQK!FC3XE%smY0_J!o+6yV&0SO*WM}C0k3r(yY%w(yVF5k+O3#)6!eIecQ-rK`4LZ?b*4|V z!B2Z6>QPYh#cT1p7fXESU&2Xb3S^&ILFp@1^$8XYBEM`|rxSq_jak$YG?nyJJRL_Z zZsZ7u&PSq%ip->$f)L|x+v@6-`)Ari2ay4em5$XYjn`4|Lz?!3C@&j?mS%}dr199y z9HYj|Oiu$f|MTJlpWn{SwWEK=IszL^f4uWkl|MlHsi`d~AAIj;9V*%25kF^kreBlY z^T2KAei+a2^I4d<-O;uF-wQPzXK2rtjr)3& zN89TPqPZTwSxz7Nf#LYG&-QQr*P#2wveTuW1aRw_b8&lrn_tdIQTau`f`8%mAS*c0 zX-8jU@voN=C+9twLv~L0ojWo41N~^z2X?w3ke>q`)vM?rBwz#`VU%mm3zfzWwq$YK zfDOe2hzd=(s$YRbVn8OWtSStX4s5VVQUVHxpaFBo$Nz8<-4(-5ElH}or>MC5Ot^Dn z68z}}H6)nkl2fBgIiQi6IHp_EiF=p_B^KzgH9)T1)^`cguXFO>hV zp2o?MrQjS^5$LRoy0&vbm3JJ9(S4=4-T5KGxAVSEwvgLz$|JZ7L6`?^&Rw^|ZQ?J? zZ6bhqSZNaeYus&R-lFF)z(#OaUmFt3{cQ{K51a!<_B`}6r^%e#ch7YZiq01~<=8YmPd@*AJgujKa zdKQ_ARBbo*#9dabp^1@Qh>qr_HnmE?&rnP#tHpMzB-wNI?O7l&io7?YXJkG6GcsUN zgxdN?Tf<7us?aQC0U4%1yfzsUjbWK&G0JWP(AlVBGHd*x7@GJQq=FUz#cNrxj}yES zD0}x4B|JzilQYt)4K-uZH$He`K!}^u9*q-2yk#Jr`p&K=mTAiG(6xI_sF36yQCg)K z<~0D?xl@S5pJV8_OcPOER-BzPGT)klKvioPge7n5mi>c*A`dOGIm20;c8-=8_$KctOQQ;hWC*x4<838O2Da@uf;-Xb@dBCGy- zk!R?>d&ABADN}DG#8|(#!Ws!Dl?-uB!zq=46U3^?9(IJo!vkat5wrPyJY}H*p}duJ zu3{OJl(VU(WPVn&E!?lVmWG~hPC62kbs>$v8L`wX8rWU{RvQq7uJ@=G>x5A}I`t;9 ze8&YnOPeW<+scEQ#F+X%ZuM;?=nu`a$mnj!E@T$285DJ;q_JkLW#)MH**lXv0uKB1 z3_Cr+HnbLpe7o%Y$0PE@LQCtD4D;&xi7=ZE-E=f(PbD3m8Vb>GTI{N?WWZdcNocN+ z>)mzQ~{e1ZiXy#Ztap)vhS#9 zVx&R5P68_!O`7LTxP|vfp+5k+DxU!*eI%TZy`-q;?nXjC$`Bv{NY%R=tj%WtzGN|w zSpkLxd}bpE0zi+&NxmMg0TYIRl1DuB!S-;AR5Da=QtT2G$?~5OfvHWN`tGuF(?^l1OJW*_j=M+ zvF)xW{F%_(dr_lyEaRru$SlZmyl!sK6cztYdV4H&A3D=ni)23%;4P#Kneb+DpM=A1 z3+&?Eea3n{#z^$cMD?zb*G6AifljEavo>Y3`X6Qc*Dio+8B? zWz$Wiq|%+Hxz@M+@l1&q^Tekfsy$Pc^|;=BRpOCA^=@kQwxL5vF!fZp>oUr(m+U+Q z@n|3zz&M@*5ZP6TrF;s|qxc)3b?LjSjbHD2aR&Z255d%k0v0X>#$eUEx zZpyRbL$d%y8-w=_g%Ca~-*-p6AqRH%#OERPyG}kQf8MwUMLKdnzMwCj@Lj9h!-y!} z{O^`#@}Et<{vZfWOtdE>k?f$j5RGZEGmUG8(_jf^?PYvt8pPS1Ys-&K#83>~xz2R4 zQ`5L}oWvyb9)ZSPB14?NwlCR81~mM%WndRF_nimGqH@mIul;P02tGm?85G;%Mue6U zYaRs|#8yUAg?x&ZGl*0rwzZ)m0d36zb{5gs-F3`5N_!vlfok#V>lMZ%D9Tdy?@b2F zNx&A-Yvgq?XcaxaCcU!3;D%*a*qEv zWO(A`3+k&2fhZHMPq)OyUCBqP*l0~eY1DYli!RB8FF$Zys$e^dsXl~P9SxFk?2xj% z#3#YuCo^E}G}R~7pHj&2p5d+?;(D!0qMk_B@#07yVSZ;J9aBbYor61?IN4H`>CBV0 zGp61O>2->0>vzIP2kNy-`K#Qu6I7oOiPsRdLp}ppQ|14jMfF+b zDzG=NY00{oC;y3rj`pM8er?`^rf!81t`osU$lWz80hGc1gpV z2t}bJJ|htCzBgV2X+F#@?LXA-4x{U^FB2EIuAw2Sg<@~-g>_8}EiL%N+8}Hb)n^6* zjGCp2#f@#vtuv4%-Cv~`Qsym$DZXO>_8=BQdMz~@|-3QyZ?yLzFPE;Rwj(uK= zSDqtI#z$1f3$~BDJk~YVTq4yh5`6@{ZThAk*9W6T#`4s5l|GibEIxd_s=7C4sSu3H znKX4#!J@fK-c%>Xzs}*3>$@LD4JAAIQI`l*^8~ON_K^Egkx3}W)LG&@A~v4irv3P7 z%Ce;caFm2ou`W!!D@f2Gp!MQ}P#hWDK#o2R0{DI@X?!r21u_vriiH*?LRtdZ7zkGi zXDN<>+P;32>^-#;EXJ| z4ciLI!unC}M~i_9mK9l~IU~C4DL?-3S!5`82ZP;T)LbdoK??OSLckyN;@f)~%I{F+otTy5ua^8#1j*W* zvb8*_BSB(s@pRo3%hFqU4PjK-hFY>y9Ballm2qrGz@GEeO~H4RogqF`RBv~#DU@T= zr_gsLgogWwzf?DG-v4K)yFR7kT$eN#=HB%t;ZK2ypubV=&v=FqIWO&1P*6$K zxWrkW04DTuJg3v>s}R&raB4f%itw-fCGM6;U)|5biN9R6cWl!f$&ZLlsA=C00mO2o zDSAfY&RlP_a%yci*G9@V@rHP>LcCMcP*-2EJt@iw5}$4=H~xT4cdrxL%sQ(3S;Atf z+N{Y>!b=|xewy=qnu?w4t|^GGEsIwba5kUg+7OP|&fBaFZ|k^vBq>g!u#!ExL5ujF zx+~Amxsz(oAr2(#n@mRX_2>8tN!7u9Mv>{TUH&hBnVL9`zX}~8wy;$E$WU*JZq9?K zD3N_A)gJ0=KFu(fg0}Ow;-}kf`<~`$a9zA1Z$$pb@CVoM*j7av`6eLsv4|x(-52G4 z;i!_HS(BQXJE-p$x+(EdJD9IDADwDSj&>2l$=MJ0u^=dNzormeCA4rSW1@~bq=rwf z*MSny`zl1}aG`DIg+y&3ApLAjW7Q1Y0g$ZJU)tA{vw0}?78ej0DFj*$L*j($Xdyl% zn`8~aG>~ELWF;Gr2{cBRumVdEsy2bHh9&r$kU2I&G`|xIuq*_f!PoA%+}Hv*3n5UH zlSP%12^lo+I1TLupe)5HXoO{Gq3Fd!i&ySBk-j!jwBC*>u9L#b6#}R!`1c;F509EQ zG3-7M@kDo2+$KAga(xDtH@QMOqPTE$J=_H1Ge)(LSCty{N!Fp(qig~+Td3dkw>#_l zsR{ulro^X$s@f~`e5A3X)X8%?R6|Ne6+(Q35IpK(uOV-`etSA;_L<|u=dNe3wyN+Yh#(@v9j_APl_@uiC zSm-*kRYRgZtP`39c>dCf?E^w-7l zCF=(0oceV0CKvTivghPXsQTtX#IBfdR-8f(J1_+IimzdFl8&fZi0$HJ&igKhQb zY3-@7FK@I8ev6%LxHiryZ_j>j|NB5)iqj9(zG}DQ(o2vD4tU%qdRqE|h8B`+C`#RA z^n3!)B03%82b%#A3t2YmA~cK431`)idEe%7;HeNWM${J!QX8o47zKIyK7b>CUCZgO z_7a1TSHT1^2@8Paum^A~$XaXS!G$OKNHP)&g1Li3^+CMFPP;%5*ai&zQGdQ|%V+G4 zyp{(w#x`J!9B1ph&eoLMR*>hiG?^UFIcTxC6#lDfGEQiUk&{K#ivvP7ST5nQM+evt2u%Q5V3o8A>$I zB-1-sT9>FkG|15C^XRAC56F5Fx@!&di?+?^Q?P~_O6&!A#y%CzMo@dT{7^QMh8JpT zypx{t#Ugq(%W}%xbkJX;Q>>Weh3dtQC~9-j(f`}=z$Eu2#90V@$4{p2`t$?*Ffv7) zerC<@{Z|C1$cKcG4vL>fH-&zB=lTx;6^*}5tVq28CHpkj0QWE@VXy1VxD=b={Suqlal+cUqiR@}VJa;f0hY`*b7`CDZV)&6nCrc*U4n2(cK2Li20XkUojIga}Q zxObZwO5^Ly&p@#>Fo9j83j!~{H!S2jpsD6q_CPvPBWJ~0OAO*=gZZFCUb}V4R~x+4 z;mc%Y2kMs;szlMweGGcvPh^6vNOEDps)U;M5Cf)qbtF#*s(wu6jnl>(&c<(A%4IH3 zAvP6-c~gMd2*ig#jjYY_?z8iq0@`kUX@mG(ES9av7;~Kg=6kO=8&_~&o~YRk<6^10LbM?QUAhmX2d zS0pYx;pr6N^h6l-0DtBV|1lmjc)mqaVcE5m{T7Z4+3{QWtLy5K`Ts8KzTI^`&*-m& zH2<|)!oE;pKYka{VuDiCJMEP^gc^D$8wZ{LIsY%s_r?IX&rIpdXdYGhGk45aed+qA zc6Fx~nfPazjf3AYdy~&YI%^sp`s-7p>ZtnpCi#Kt+Y2KkKd;H{xoQr6^aZFcse)W( z*Nu$yC3qf9Z;lprw^v%@cXtJgQZJS^Z|mGNtP`?q(T=ouY|~zo-gR||K==?cSDDte zWD=&lNja@Kvz4;OU(0yXR|V+DCh=VC7TXURRE+@2KF|qLrKSMw2My3Ol&V{V3VfAO zgsTuR3Hdk~;u;`GssTDJz#K0@9Jnt2Qyk|BydBL|uDVtM1_hEL=tx^Nk~4s^5hU?U zQ}>-LHNQ+CJqd==2=)HUTvvcxYme8@ab^4|M2 zW!sS(Pn7~3!qW~Q)X<9mhL}unoo4O;dnW&j{Bf+Z2C*Jo4nyZd*;`IHJBTZo6UGYa zbGGUxmakAr{fqCZSAgz)u5KwFcL*2j4{Ln9RS|<;H1wVe&1@?p1)JSu+srZj%{_lx zbk@^XIUlZ803jZRn6+Phq5TBh9`kFe^2UkY}` z_uhSr-@CwmYseJqTN@u556(WDzTB2^Vm~GpcVd5k(CnS^-=pTOLU_uM{ZJ)9J-+V> zdsQHqxO>Wgz!XAS_cjxsIZZf&lum3cL?oE_G#{|10dLLuxE{dI12; z-{BqHgVoU4mB#i$CIijyz^6XaIVA*2)UH1A1!S6?-~Cze`O0W`FrDq&2-N9>vxbXd zHc6%eq?1Vl0G?n&-Q@zP89`#3D>_Jve6RLI{KQ&WXq(3lNeCkxx$4NWD=GqQ(sc*G z7y%1vLryeZBwKxkIqd(F1wJ3gfk5q9092qbm;AI=gnbn~D@m$O0wwF67nBMqsLjU& z1!ObF`t2jBKj{ekO=SDH4Y!~Y>*u{vSEZLZlI{+f9A9~O@q{IhIFoWOj6hPU#N7|T zeMZv!d^K?ioa4cD!4~r%t$k%^(iX`uQw+znHEiFH3_7;9Vb1l`(0#A5-AJ@drna|F zqO)g$YRH+@7amSyIBmM;IOC|sn8BQytx!V99j=bPeGJd3i@fS|%8AEKW-S6jdD7+=dt#L3aL^e?VXfj3h;$t(Sw< zll?0ofE0YkW*QCLHWiB{qawN+0W)cZ{4X8V2#!63 z8xD@`st?~3#a4zBkbZ0ebg)pY%IRaP+T<8NY6nOpHjvv!LFvXxG#&Y+D)Y<{f1eda zZUeD$6DmdjQ5UdIr@t=AqU8f2;|>y1TTDpN`^iKY1K2udqjAQI*LwJCkW0k@oq9WW z4zF8#?9xe%sO#K1zx2l07DcHt{wwV^*ZU{`+`bRQpl)A}m07KWYH#!f)CyZ2$IFL8y=O6Cp`kxnPhOB&HTxi4k~LWNRO(a65B%rimJTg#{Wa6;L)tJ8*F1W z+el_g3D^nuhMoLc)!X{+17lu)HB?86%5=|3*laOz6Ml#_?LuI~Y5Yxs3H_I{n-!nO zlY9u!IYVrk_1=;Cb&Pqcr%`kEPQ0-ZE_02y330<(iSG8oRY>1g2g9>kh9?euLRaZs zWoice>+`3Any%Wsoiyw=_>X|V4o5uOE(ki-Vk&_9|NAVsWJKYRN+Cq%jwkPm z-}aom+M4_RS)10=E9Wm?eUPzNR8h!A+PDuXb*m*1=@gaKf<1n$KIQqE)T{SxGc_lo zpoFSpYFDJmn12lF%=i4$Vtjgzskg`z=xgW{_1QU`6Usk-*Qu;ZFFtt{&pP)zpbfl> zc^g^=ys^MYwZknA>)6{%5t)>Y2ANPy06?=G6M}YS768!j-{7%X6qqb_TC+StBNvp7 zQf@nO^0_IRbU-amJlA2*%Tg5pkegh`hFKdL?~ICzPwX{@w?yqfik?xQ5N39G^&^I; zJ?x%r9Cv=6=KSk!CLqLhx4-~&u&rBPsl(r-sxZIX_Z}Axxm>)vL*KJ)?By7<`RO1D zUj=b)k}R=oHDuS;!a)@Ydhqyd5$V^7FZF4n_|k>_w2G>Iit zGc(3TvR=2apj{xNIX2U0gnF&ZfF_VTVL!%XjgqXSrSLkj}I3kOB0<3)&KP2{$ebPwu)fo?fP}};8K`^+nIz37IopjNW^NjWG znPvy_8c0Fgsf{GVJlpUqNmx37Tol-elMqHEO7}aX7`nlV$nc#ogb8TTiI@TM^-vY} zl{Uj=vVA&7w-2I+o7+81gyH(sp3maJHI)H#n!V-@t9Fl2sk?+7nCox#DiwJ%Bsi8> zL<+NQuQr&R#Z7{A26-mnd4mZMHi)hJf!ZSmVIP3B{-y+^t02zJA`r6<$z+Y`yLvmp z{X%2)M{WJ>L^)`iHI1CT$P2q{RneDzklj>sY4id&^CN2{|5*GPcA*_L+2o3{3fG;n z#2Nn^1#PDvfF-crC9q)hittP4CI)IS42yH8w`2D&lE1RB#q0yYzN!Pz4bN+?3%XmD z-w_sSbQ>T@mhe;m2x>W1Z%S&^m8wq@5r&uJl;7MKr`?PXii`{eq1mWlA<~r$D-eRw zvucGfRmDn`4;}iO3`7y&W`O43%!qatn8Zfe5D+`ZkUAiZL}E?-`8vm{IKqNaG5|&^ zlA-_w8mVXrj#;SPy#EupM)7736ej@xW&!l2xEA4XQ?2!yUKK!~(d>^_W<^}Zi0nBC;LXt7OiilBZx3GawrR3pLQ z4-K(Nuw(+9seypo;sD?b`d&ElUVp(6qKnABiu0bbgUUtnXi0C*Nl z`(>NA-UT=vCuG zs1GkL&4@H7v{3y?L~xjGzlqxt zzk|tAIY(G;vpw`6Fw2s<-n#^k0eOuR(R-{=Pafej9S*u@xV`Lkm9yuk6_DX9KFZf8 z?2gYFhIR{;?P~#N67z0~P%%-eV#;==NM8f$-S}0*`yrmsPJQywd86M_&bh@YjVn4M zufwcyOOS2Kszyo`_^0hrMbK#L50`{>Z-?swy+0c5HwDKLg5Z&;vU`D^NTeA%cyPoq zu{tD%60Fyz-_6EU3LPz+^}9rx?|KjPcgwHeRM~6auFP-Sz-Q|+*;p)beG7o3Q$j70 z%FnT|<00xZXZ?pNs-!B_jcb7BPDrR!?V~_{k4UeoZR;^QcpwchBPTXcv>QcwiL*K_ z^$}`9C~H!`u}$|h+vY6niz8Tqx2zv|W0WNTjZA8^5cL{C`Xf>`ompTAP~E=y!W-0C!h=ExnY%Fd#$&lPplAfH?*MT2P!i}}HHNB;bkq!S|G8|zSS;vwC zPj|ljf)lsl<|%o-;jfnol(oBx}UmMEV1V7uCQ>leYLC zQT=%$rh<#GVe6k3=~S{_v&ia#w&aWVOmEZF82)DW-)#9U1ve|A3k5PpX`>MUbqA_l z1>h07Lw=f728{pJ8d^hd+~z^AQo5%`x;FO7Gh`4 z9V{%>A^C6>3!dAng7>XjkjB`TA;@ozPH`fj0!<&5gGWum%U_6Lz1Un>ERF)I=xFuW z*s37{k)8eq?8KPSWB1Py9x2rSHlya*e}m2Re$N^%1G(G43PaJS2u*W7YxrAH?gujZ z2r}}0u9#U&BBgq(M7*+?@r!8G6=2I0>MegEeis=Ii11dN=s*=DAleYJ$0)2>rD|H~ zToQhTV&r?R;6{??o_J$Umg5Ss^T(_K9DQ=#S^UJTp>MoVz#g30iji-d9pkkTnPW&$ z>uzbo|4r)o!N%VN;lG1i+kfj>y+8XOTldm}5qK7t`<8g~n%vNtXq#IEDi&?bB(ZS6 z+YBd?jK)2U!csKV9MlVpNkbsqYLa2AKD=0DG^l@`ddMY^(t2CGE2 zhaD^xl>d%`&950qU|jYbj=9Z@OFGP({*1cHtUP8XeCSnA9I4uSu8LaJjPj~}jE(A% zD)9*538|7NE%sZ7mLN&r=2`u1s7`81r)OJzP=Z`hIc4m|Q-LcqO)1pC`=CsS$)V`P zP_)7|Eo2H=6V%yHQ&(7UHCmlY;;l_%gOh*^Z34;tfKv5;~WNFP{NcLXZvtw0Jc0Ee*g3 zz?X3Mt?6K8De>`zaUFIzi?^8D1Fr(4VA8xRzoa8UzWtUAJ18^s`;0rePm0(*;2)o@7gy^mjodV?Z^ z0iu5BENN_9lTS3bmSoV}rZsWc*q{QjOvj#UGdM@l8IWoSVt1GM>Vs$XuC*C-615Ay zkQfAYW>WhlB6bYWN}bINAJl4P8w`N-Jr!}kAe}OtVUj?SHGd>l^QQN#9jnTE^D0RekIKbA0wiNUiEfmPd4gTD{vKf-f=@s=csXTt9JX^_Ybab z*6W7LggU21vpp0Y)aP6yiq3aK<4(nJ5+!I|zQW9Uo1-m4tX8g@xz!e5nReMjyQNa( z{sUnht=b}Pd;XS*56Cg9UT+~OrEjf&vGE|FZZrEdjjinoLWj@nlSwsWC^|b6v{ryG zTX9<)a(`uzOdh8GIWKn0N~pIS7aMU#0O<&aV7y$C)Cr4r1qfg$8cmnLZR7v`IYcrI zM6OXAaL#sInKFTY+&VzdlCNFcvw{*cFCqcJUF~}vs>Jj z{~pj|1eAlLX$EcwdpWQ|$bd6HxxLiP-R;e1kMpC=p3NPOD0p`AP~4uQ`iHi{mC|eN>YGj`COdvh zIh0L8Lec&hhqpDg_cy&gp80+0?Fkmx>M=~0cDccqr~g~sSBnBW>=$hk)ffe#xYTW| zOfKYhMBK(iVWSrl&C*dCK;z zD8mab7G2SCrTmTIs^oCs^va&cs=c{r&ZWZbd~TEq?A_Ua{JRy>siICvzFlBVf3(57 zir)uTW_ELHJ=1^g`gr5#caMbpN4@+{w*Z8V>{gyyPMeOp{_|EK@<(@PfOulZ3<>{z~JyM8fqmTNx#^EG6R z+V0w@;F(je4`rPDB?&s;yYkTU)M&$)Qjyy4G5as!2OK*HD z|13zGKZmV*y1M@FZ_J&$H*bG5#+L}c+*;T5=cn7b)W7j|%iI5~stAC)u{?N#0PIBu z6kR}2sqF@3$3xEm^XXG2EF$iGU)fcw7@kQdSpS70v9L=6rD*2kfcgcl;tQ3k?XpsP zn`6VtG>QImbh2WrP;FO}2Lww7!wCSWb502Svg2%#&O*-saQlX8AJ1TL8l8ULFgU+B zc&uILF;r-~=kq~Gl+uEbHthJfCl$TS!R~+S?NlF8S-(43Q$E*y+vD2j8m}26{Ev~q z;iU_;tQlk4(EnIF&%Y%9KTx9xI9Sd|&B#3(Xt_t2d!)G1)cWE!TWD^raN?F+ISXg5 z63v|!?yXqnXc(rsQyiIP#o_npoIl_^=E;o$uls(#ug`U%!S$eBa)M=<>gRz1+cGCxKBUuO0boUKKSaGAXRh?UFoVJhI|^ z7rx+hR8>HZlI@)&bfSah*X$@oPPS1$$;6%?XN8xE@Ac5s?zB5)hO>(Ip1bHLd(SK> z>r*GU2{l%K$eOF%?GkH<9xpkSkB;#rdM1vO-ctm3DhG7bs+)zGwr&D(QRg@H(^KC9 zB|>S*>P1|v@zihLAjT|2b2IcT3c4uqL&F5MrC=$ZTP#@1U5#_pPtiDvTD$ysULN)Tl!vFFnfQ++I>8(27bB5p!0W~+@FS8-|p-3 z?fksQ^q`QO&;gyVr_x`|b(cEF*SCDDYL_^x5GQJ8v3AxsKz|9?;V4^oY zU9ZG~e&vtB_G$O?&8DX{ncZ?;mXhF4@WxEnlgG}Ttumaup9OsB!cHeeo=OkRExkUU z?XJ1&mLA&Ca{}?eL}$|`-GobyM=3N`lM##v-kg%sXywuk=1UKvdayrFkj`q2Pial4 zHi7&8fzLN=S9zPw$G_i^@Ur|Y5%H)W-BkZH8XvFD6~%3B+TbMRk`?(CpZ2mUJ)A)0 z)bbP(k;aelEDq)05HT9@k`zQ#7LtNj7we2gWfY!vlt(r&T{z0=6!YG|!9 z|Dp8QiL-0$g^ulM7qikgfP6KD%FTzb!XB%?$!vPb0Yn3$NQzulIkD3d=uiHLTk`HK zBn8|gGhM94G<}5HCb}5U)W7Rs&_oX_2UIz2AlkTSaiL}qw7YgBxlxy!M?qci(R^ZooS|C$P*13oPzpm|{jwm?Wi@Xi zz>E`p`Vj=})Gac|0LdQgmPpgkh+?J@-QW@F8*Pv$2W^D$EKWp4_Pn{rx)lK3r}MaQ zc?joYV&Y>PM$K@S1X4l`C6)w*p1Ma14|0dgt>e++rkCpTu^bMSO`Gm0EBF z;!Ys&WUaS0ag=@QCx*qi5y)!RMCGq+jVWR@ie%I;cBYv$+}gWX|We zYHwayxc`Q?xvRTw+p9p2wHMYYb>{@JZ^j}p{g(}?&^ldKeqx=W{JcPDj3Qpqpw=FiaqRa6O^{{ zPiBGYmRld_?M9`C#RA_%6ocoH2!;NKnle0TJ6_E+xIzV@P#E!!g}(R9=AOFTLk%qa zCmKFOP%m^qFql^_=WvbCZv0{pe=^`hbo~Hh$XAT}Q3zt5icju$#$uvDxriSWcoCV% zraOBnHlQnrF90WW1@|gJ{WpVnK!Z0hP#@J1Oe_z#0MHK)c^eD+O@%^Bz#CMAeD2xb z&a}Zx?&KG83&?|^dGJG44U>mR;@nW5`aE&Imc@(~jb$hN6r8eUf(eI;5b>osp zY~a;@P!JQ;2Z{rH1UtkA5x$8-RCw_{P=3guAXW$9t=Wij)fiPD=fhn1cRb>d1_yAn zC7{XkBm@H+yW|L3q~X7_dt7++pLDqH&sdv5wRs9$))>A-L^z|)vQ=P208pL+bIT=k z`@@fraAoo_pV_!^rutL`DHTQ9R?RZxNr>zxIbI4c)wuHPC#hsG%hoKBwvrX(oA9P3 zqP#fE`l?1qD=8h7qbi-?!1@($e_YL;$fZUF#Uc6nA<&^2plN@$U4WX{5BLu{tOn0p zLB6|W0x2T$bWxqg@jOLzo)pYIRV)vai1>yBDPdp)1L(f|!+pn;3O75#dH7Z!sE7hT zz#xhl$8;#%Ogv(X#urTHN+Q5DW_cd)yB|;xp9mlg99IMN`aCuBLP#2*GHn^}{EfiF zwxl%!5I=G7eG%&w0%Dg6m0bdlqY*<_L1r{yIw5}>&liZiyNE8l7psfXK+vnKW*Ouz zTEUJzgfz#qj6M7P2SSGoDHMT+W4!SM*bxQsm@1kHh|8jIur0SNN|J^XVgvvb3FNUN zNGY($Fx8=8BLduWFrM2MBJ?ve=W#+e_pM82IbJ;BxQzb-e?=PcpnHB~cWaawn~}P% zBn0PX#{zQ>N=tkcax_G->dxU1qtXYLR8;UlI}9j}z)K@QJ8`_>j4S3hgniyQ9-v_o zl3u)B<_Z+<`*B_`^+g|^vVElrO`+#5kb}BI^9~$^bTB9;hFc<=OCHM`avr*|5>sIW zl}6uFAoC`A@s{1-VK8AySkA&?jwLGME9FUme$=Xb%0?(+2g@UmmwWISvBA8G#d-hF z-AO>P{lE`b;7`l*4#-exrjHVad$7%S;Vb+Q4R5vwdQ;({c0Rl&V#>Iy$5?a10&>^K zDI6UMz&kX)4jhEO^OT9DsA1HAO%LaLrDqWH$p=8CAuBlwe{*_+}D7dJt z_(Jw~ooT|OTm`QhRpr||9a=GH+h`B~H#`MWLF4OU@U1aY5{4hV z&P)5kS$0!`q?31Bv zd9efht(&hIu?7_uzlldM$*|tzz*`nZkKJlBa9rQ0h(QX+@dkWBz0gDb=ZO&a_r#bl zbe=E@q$TdbYd}N7q0Ga|w!1R2YrnIeinW_awqJM0ZGE_QZnyZm;=_WP>=i$Ws%H-8 zwc3;9H4gK$I0{~IMzlA{)q#^`&5S{OH-YCEAcR=G;7yr8x5q!J(4DsW6E298F5#*~ zp3uYxgSfmC)eZf*T&~2-d0gH?K;tLkF$DnZHv=9_^_fwKGO_{IqSOAgy8H>PTy~1m zSZQ3s*4We_zEi-U3|_X}SbLRU6@PCR%d1M|9AZ%r+eq$38zD?w(63mVA2|3l5hfZ5 z+YNy8NVWvNlGLC=Z@hcBL4&T8wDur7pBvkN~oEpxSG^bwtO2UX{U*2qM80j$Bd9*p>^1D^6M$PK~@(qCDCq+3STF>9M5gEqEx=ol+IpkT%^6R zwP@<7=lwJLG=SrcX!d=9}3GbMIH=4Vc4tV*L!aH;!{5B ztFCoc;-zyUeK$ti3PL7MnD@On3U_nu{kA^g%;Vv*S?cLZPxkHi`Eydombw&9HKcI` zVtIS0e6KKkc}$QBjmvUaIam{skFB}YHSl(0;2}To)oA(;YP?cX#iyITUtS>=HU|9& zjZF3DSskwfj!r&GMC@Z=esn`e4E#6#O=sepFsI?|uwjkDVSp=;(~`!j4B)P%DN&(~ zw?6O|^Y*laKgbOU z=8l$dr9$^uM8p&Z-LJ(XjZS3(;4?^gdHKvoXmP5`u^`(pcpfbH#~kSlX`p=e?`Ame zYTvL$X~y4I)z8~Uawf#`+v+TaUnXm+KbX2L;G~mw?c4MJDo!j#y!?>i)Z1Zk%#s2w zr$Y-+d~q1iIb@kRQFUd#tRuBysS6l`aqA#+F04r^6JUh%&=3-0nFhKJzG{Y*Q$>G1 zLh~u$UCBU;7D7Ng~Z4mUZIY>om{-BX_ z#WW;vw|BW{YW4Xr7XA4b6DCd9H)2%9@>h4^od=Pt#_HTv71e&UY6jAX)(#z~@bt5E zTD(#pmEUl$Wqg}S1U7tt!Qm8XBy?r~(R~`B+A$;gqNj=j*nn|g1JI7l>y>^xEQc>0 zRlj&Y{#7~c`?=R|on03*@AtosD6#b3+KaqBA?tCl{`Jzot^Jq}1!uOPpR-xm$o`e3 z=I_WcpC$k4$s)!amI&cGjB=oXJ``0}P#KFvx3^RmI;At+OFtA3@gwl4SU|n;kRSp` zH`ML`0}saucDYQMgumd`r%Ge2}h5i5(u*jUV#Fv#gp%^s$hQX8>1uR?#rXE(_ zAwvA9S+_&yEsEwz%Ef8zP*ML+GJ@!9SO|eYlt3V z+o9(M=Y!)(1ob5{goQ7n5)0oWH*F3*8?dk$0&IfJ`wq|JpWHL@&sUkkQ>Av_qowU) z+AGshDI8Dx{`}Ui_*TZraOUVlzR%jDr|q>zhZ4MVnG?5DQFXc2zj#z5u4?wBf1xv9 z|2|aNGBJygU!S}GmVHaZYc26jjVd(OaxGC_i0S_gFL1W(3gSC`=sS^D{cZ9(fqf54 zOuzMM2T<_){R1Y_WebC-K)Eonc^hVaLx*Y4@(_!F)SLf8ip|Jdg!`*VaPX-|RdE?? zKlqd;yh8!?{tJ8?XS*mqo`UlM>})^HjIx4CTsW+YZ@a(9B8Xe+U;a;96)OaO-4H*$GYp)q8hSe$v#!a87PI07nSwV1J;<>xi-m?13m8H>q9x;iQ^48;rbEq|QZ@fgd|{0}bPcK+L7 zp~cG|$(nWRqZEUJf1Az+w>~u8{?cFM^7GDo=Y1AfB69!B#}cENtx1pMRJ8sRorjk| z^*(YMm&OW0*4#FdcQzMBAlIeGZvNWTR5CwruM@dK6H;KoVrKNJeymQ`ys5hyE?z`m zgKkTN_pT|NLVp7IJlWp8YJTE7_>y^HdiP6`_}%^EKGJfwhsIBTZ`Eu|m=mz6DsiX) zZb`obH&CKtUVr2m`sIPyhEX#ywCu!h@^K!_?7!jD%^yU>(zNG9 zNA5N0A&%Zv3fS@4H_WY<2~J!RRGey_NKt}W_X|CT;xzwu*js-%6n|m2pa)X5w=t1v zvbVD?O4InPaeGQlCX3nyR;(nRZSUn)l~2T=+_+L$P5YYxc{eC#-omQh=4`!a_Mwz`}=;P2CxY%Ppl&k$h=lyWd1SPFs!Ff0u z&Oksn(2_IVudZ);M*puRC)wmcw=zLX;&>S^g)kVC?M=DiEv!TEWgj1YL0$UjZQ0h% z-uYNWLv-;sz^+$UQ5!>&y@?q%Q3PDfypMdd7g;==*PtqN%1q9eqI$}oA^GRF1_rHF z?=AY@xN0EARS+~auB{9cQaAeUne9-O_;S>y8ua%bUT{Q2d(-@Hto`>ZZ*ny4EWXLU zYJI7CUfa+9=klw&Z&+Y)LhZeKVz)m&IfS&cTF>=da1_VnIAbK-i5&4LKiu9)w8YcI zGZGq4rwrwiLOTNA`4iKX-zv0-FSeR>7lVh-kq}Mq&kPg>qLCl|1isTYd2ZXF_oXOA z-1)#Y_|qfD&4Uq(?&8BGpSrGRwAOaX6ZaDYpxoac|7Sr#MJBG8pRS)WDN|9sD50E; zpY_{m>blyR}1K0-JNSnt_!gtN`SYi z>afC;Pn<3K@L+n(NiMg<=otOK-@yKKo?`AZg9^rRV>j<4XU&W*V}Ct=Zh4E%Hzgy1 z7<{zY51NVk6|xu_$|>B1G8V|JB#kOFSwxDK6>n3{MTIMqNshhlB2BGEXM-n`75|hR zI~j@<_>G9V5Ge`X&Y^Kl6XMmSDHTLY0-=mO+)Ch6NQxJen4+aW?EQ4-!jGz>IQ~2F zhMtnbZKlR*Zy%+{dP*No@s76y5g(sX74dmOM@#=907`ZO$U$ zwiy59gVMcQVGfa!RSiRfgzN7LSJm%|d&-%f^yQeHJUo1!q7cDYHfv}8xFA2Bf;-kp{(@GQ-kO@sF=X?pQ&)1l3c1;Uz zR4?q1Kt(@FF~Qmw9DNeQ=*my(*6)`s*5Y||we0ezrz+Gt-7Wd;xKuklPEMfQ4U6*L z-j=m{cCJZ&QKd@m{MV@}>o`CA@}xIq4RO!Tgn^-zTK4u;jWMp5vn_glU#j&AsP-|s z>HI$5hALqMb9%3+mj0ooo*Ei3c8dNXC zA2C+k?+l3%&gFP{YBtOM|dOyUm zYkIo5rSH3NCLrEnwi_OXj%QtXu~RQOHI5eZh@-w(NWrfbgM*Y!VPJl!+ZhjGZ(kF= z2IpfEgec)bb{L6#itqfU^4)MRd;V24-&KZNqjpK`nJcHL6=@ZZF}>T<)2)|}^XLQ%)D$tG&9N$Fxow1V< z?qNA6HG|>A3$PGCJY5^L&rFNN$DDoTVDj|pjoSg~s`1IYb=8=m+pad^ z-&W(pM!mM|S-2ITE`)hEqp28J#_ghVo6ynd0VrF2auH78gcz*|c(CnmM-sO=WR)ty||mgMJGPba5WUhJ7& zMnMV(Y~TlmQk7@VnL?i|q~Bld`SIc>>D;Oc5;b^9v4&i<^wABnaVBW%c5MW6@obl8 z<}zk3C!%6QDRf!=%dcJgpDMOwvZVCum5l#P$cXNk-P%%k!K=vS{{rVk4Gpj|{h0Wj z$@Cj#EXoF`t4ne4ke)=t$CKuZ+A6v## zrnljuGZ91LAIg@LC$X)MXJ?E3>5#xd{ummE*RwgXdx%iT?V*VsrT_nwlszmDNhQ$ z2X3c#aRy$xWY{JH#R64~Z33RpME80J_WMA^%?vyE{y;MG9)+O5I#i$q22$h;7Tk}E zID`aYLE4qT|3XRWl$SgO{2}c07zJqQ1bIM)=ui`yud3u@w%8JV)QWGGdtx}Orq~UkssyLG9+JM?i zL?khuQXQ4LIS@i@jikrl>oVg0${%tF_m_X%dA`9dw$vb8$ZWBW6>C5EcQPwJWw6YC zxV#XC9*hZ2fOrD>OXVS9bg-u)C#Et!n9Me`k-|br{-!UxS2F^LkUy2AU{i2qp}A2C1TGfL`$b^tG`Hh>r3kGdpoxU{8^bp7_f}2ME&@jwU!%=|Cg;o0;_gZW~(B8k)|3#@mO!2LJw(YXEZKg}x%f!@wuEHhKlL|lHo;yM9 zYn-UkY0v^@6`I<>7**YF|b|FZMXgBI`LBOYA5~`>*3y_1C*>l;m(H%-kO#!bDpu+{E+i~V7?WB>Ym=ah}i z`xwqqDdCpOGGcD_4rhLhIsBcn&3=DXSYGc(Ssjn}N5uD`c`qBBibNQq8)f99`)@3-kY-(+qSO`H9&iwS%$`O1#n zp9_30qjhH5Gt~}z#_?XceNg#KxXiO#&wIKfXH-64x$wg#0yIl>kX{lj^RKzmvoz!V zxALCwY~0$704ya0Jle!xipfZHFC%q?z8WxRQ~CZOnAi94Z*G21jNH1(H!9qg7d`f;#c zY9M?Q9WLI+UuK#iaoNvs&PHY==al2?!j%Bov0SygPYSPQ%2^fY{s;Eb6!NmkFfoz6 z{OjF{Rq^FwJsHvLb^B6>`s+sd*&A2NuXSC5{y$ey$K}Y$0pMU?1s8w?;`+ar_y6$) z9)KWQ*dfRX;AR0>JnVN$>5AbNRCFDr7Wa^lf?9d2o~QZ}Q0M(V4c0FjCkg8&{n79* z8_JY7%ds44C?9!@@fa>Nds#77pmA^gQ=Z_`Ap2N4@8tkwC7og@EW)28urwTFWw4vF z8mKr{$$MXPD*SC_U-h|EPBT9T+3A{NBh}YxY^xn!+*%wivS_(uA+EZ+{=BQl%U;|_ zR8NN6FujG4(DTT^p%jfYVhE7LW_V04Ni_E-#!SyFU9H4_7f4yZ;=$kP36ZUeiXq*U z&~WG48kDN@ioqUifmB)CdTi`4NF%R{VwV54l7tGtZ1k zS5nSXFU$xTnK99cC*WG@XhP0x4_lb_=^a8vNyr|k@N2VYLHExrr@8golTUd9;KWg%3Z(tkImoxu{MOe&%J{Lt1nYt zLhpWDpqpu~3o)A?Hwbzr7a2k^6iUC=k@!t|OVA=~ zGEHytdcV24>GG!P9A9=(>|2YGpvL|OU&*oOcRtx6bhq(3NaTZ$g4PtH;^%qYHkcX{r=bKUX8t9Nl`wpc)-Q|T`5Ek zC>tr)>wUz93@6>WpU81+iitoO)`BsB=;Kp>coZAcx%bjV$MRW}ungi3hOHA}jp7P* zQhB+9X=2J92Q+M>$H~cc7#xoT3i)Dz3Qi}5qu7F<*kZ7<6XKXZ0DQ8IoaAnYu1o_P zfJ8XJ%0k=-uyUGXpVSGbWC?=&BaAPZ7B7vC)7e@`5uRMN)8Rh$zo(d>Pr%@0LDRk7 zdIZ6j7N5H*y7YA~U0Av&U@TV>Iz?ayYkOQtx6%beu|{WIIl!Wovwg$8eWJvuc$X~R zJv>UNy~{?MMLY$U=j_qBT$Vfg^3>_N!%p((SX}*8x6BJSu;R`B2}Vv){3l|JQQiDt zvnnrG5+Uv(oe$zl?7~27V-;f;?|;I6#OoZ4hse94J&phIT zmkdPXH+>w4O=&-?Vgx?XA<`C?vhJ<+h+$UqIBwEXBUz0-&}FlzGh1#5+g?+O2Fg&a z-#_hMN{`40_4a-!5z_H{U;JxsyjV`J4#pBFo=b~iHym|brigqq+z^%ctFb=f&Gilh zV~w0BH671VF|W9D=(kBqlX33C=bztDD9`pB=r)cW_Kq& z4&rUNKNxgts?{JKi{d2`EX$Uxw!olEfFuqItwi%fC|v z^8Jc_S#CHEXvrz_ddXW{EqADB5u2}X4k36Pe=9GcN1jBvmM=;$Y4K+~AEg9!tP3c2 z-_;oQpSp)O7N7L37IbH*gt;1sGz=Pl8|R3pd8#JHZB-Y(Zl5zacIx;7U_kvt6e7UB zT~a9&+_veT=6f0_zDFI<%6-@EwX>94{gO zHN?zC(e$pD(==N=^-dTK{)+-zTlQqvOCR*JH^I;uruGlaU8xL2qdGLB99}NP$5ZKW zfP+6aa9APSudleTz8Xu!Q&2xryYqD*c$BojO6~)<6fw~gld9^ zNsz#MlA%bD18X4Rs$;_K$BHt_UQx2bMwpNvY!HlcSpm&sHVey{y!8tMV{ZmASk59U ze3QbHqkIC(&e9(EC?SPZ?D*M49|HhXAahFNVObz=9|PY3TTM0Qfe zx%Y@T%gG?;R&Fw*fLTO%xrgfxp1n)v+gQ4dG&(0(&$;b*dw-d5fc4(CLu|4ul~^I= zeoc1gmQLZIlHm*r*a{HGAQRX8g)Z3${I5q$Kx_cG?YV$Cm3mI8laOztPf$6N zBoRNbb~_lv4wGGty(wx3{7gnL3D$Td*a1Ka*6@rz34^UV6Q#_g)Xr9n~VbTa1)Vfb1OmmiVB8%_zuS)nqn4)^QmAmJ5dnnn~zF_Sxt z6YR2$t=LpS|XvD8f<-Kyl@=AQnApo9X z_lQj|9ihvBT_Dr&GHAY#tp`sL4x%^}X2Q}$pnfARuWJ1#5^}lHRSC@_Bgdye0fSMn zN)6~zgDI1sN_DrsUwBsIoQh5&p^V0_NNKQ31no|B51y_7hA`eMKRHC_0 zUWv?!63u+VqnfVan$M5&8#N1*CTpx#E^0L=kP|$PJUu$ij$QRiyrEq9i(cMq5C6?> zavKV5dm`AW(;*5s9%(}E0cMhm9_NafF|ywR@GE$DpTU#cUo%}mxOJW@KNg;h`#w87 zgm!`hIQfCac+J<@8QGc8`XI|8`ptnE9Hm=xlbpLvuir)^76@WBz1+k$PIh;Doq`BY zLW+hz(7^Jt@a+GqgBdqsjD;`s`e{?tNZvUn;7H&JCzd-RxyNvt?`1u%#zBt%f+_&Y ze=tk+KcLKrz)u*2#K(HJP2%oV;A1Aa0aK6o0Hwb>=70p^vCug*TsRnhYqtEqe8XQv zxFaDM*$paJg-H|Odu*x@2WJPYf1_JGwZa0O5sqR08i!Y}S6`WjRI+G5@BAi5ZNx{U zGkag1j)Z-t$^ULo1o2n>MAw5SV}D(OSY67krB%C#!W3}8w=|a}_JSJE(*TH$I3^i# z#f3@Z#xT_XVxfECBEADbr8mf}?X?|Yo_kpx&56SP35_Ko34-rC8u~ow5xzY)YbFArN$v$SW6*peHQG&8 zB85PeI@|6eB0OEi>^A|vmc{!V=zF@r_4i?`Vjf}>z?Xi+{f*|*h4j_5cr8Cn_Hz&) z>j6rWVMHIEW&h6aO^u=$Sf>cLD&tw23-Al(rpzD3Lkv%j4KSCXWs^r9QoU;$3y;bG3+!T^2K~|7M=Z}@XtQtfbc{@3IYzTVE< zwUJqs=cgZv@fq(5V6p z82t=8t^kw9Lz?M4hR)9ONU6j|=&_=y4)t`rPTidPT{eaCh6JA=PK_|tZ{4yoD`O*) z1DqV}P&Z_qKirI&l$u~M_Vj-eu*WXh-1BU-x|8qQ|-9LaiHtIs}RL^Q}S&K>Ukct~UIyOGnj z?mitYYuK{yo&SVJ{aR|e3ll6|JDAFy%Okkqj(3yVqjO5n%Wr>}ef2?I#OcsKjd9e| zTQmkz@!c4)num@LNWW>Bl_3h@**kp$jRuR0LcL7dZ1rPkn0lAV$PY8J zpU_A=Rz!ymo2rl&eJ8C%SP-@qK7XyGs?l2mHZT{s(EO($Boi@D75WIi73~Up11e(u zy}Z`bbbX}Do$vitDLjbCsYK*-AgW(|?l9&PbBZ5G#Us|~(79#UFT(ph+;OYPX_B^Y zsN#%}{*0nb&N;YA^sk$l6rXprWNP5MSlDBmBzdmM*rYSbv2(NQ%vle`xkZe~Y!B$` z2bf_PNc#`sE8)Zv)nE++pTV@g^IxcxU%hIy8qOL7#!7TFeHLpN`p{8pep&F{;IYZn z`Ocopqb-WK#=m(jMb`DVJDy0aKYsmD*LyAd`g+^n&iAiIQOTdAg-_+=ihket6axOd zUjgpHLXj_p6d3BV@YsOpqHC+4y9{~Z+Vu*6zLn>+wbUmaJrnRvp{@I}%xmG{32a)`{utRMB zyd3;->(k@E7F|BSckR;rjz(yo=94Bv!&q8~O(w(odaF&En%y1WD_gD8;+FEh2rAxG zfw+|AI%^d=yArircsh9xhq$%1Y(y*lMt}L>86wis>VdPjSjpBQ0}*Cf5jVL#f`qC) zEM-sNI>_FCe{y@?Rn*<(h$8Hl5<{^5LIyAAFej z^szsDWI*Y#;7M(ClLG0@dH`Z0$W2HU+pVlZG;)q^hFC?k30qagv zJLrV!a+#>y+eGm2>Gno%;4*psoVgaJ&JM7P0*wFE9LY1(e`Akmb?*2nB{mPd$Tax~ zj+i<7<%6Ep=RwmU9b(mNn+r8yWhGnVpj88bMpzmAw zs_2lru6ZL;Zs36F$rV&y2bwv6Ln^)`=;v&e!dJuMOwk(Vw~s4l5#%`572L?N34ugW zWt{6P^=;eKhkTcx*bhpPUq!5~mJy?(Ctrns-)9~|dfBo!48Atu)N=_vKZSoMK<++8 zuf0?)CH_8^=Fy7SS+=?4UnQXv@vTIWOF$|fYd+XNj&)yXM3)x;>aG9{y z{rCIkIV=!(noQ%`Hb~d~&hV(~Vs2V&U*tR2i!p$yFHw8onE;^J-FE+H62a}iyz?Z} z6uV(9C5aZDqQjFu;^F}frD~xS_2mP1`jk~*V_AF_7YO%N=f<6?V>qfot z>`7#EePFSuZ81qga0j*Z^rnHsz%lzPVX{whX!J8Q=}>NnO(1zeCNJ90Srr_x^=L)Z zC3L~qr6lE&xk5#u*0#Jvt9~Hc;D?Hpjij6!;*mJL5ODm?da+!ASK-x)G|AZjzO!ws z4SZND|4>7hAiR<6iHKF@O~<~iUnc2y1kc}T7(P34>*e?rV%M?Abxk>xJ&s4V=yhmR zaT&^%s09)jb@E|7eS@da6H%UBtxtktYZBVrFwKw?=d(scqB&OfSe%bQ)t0 z=m2(<0529<>Jy8fcb2=7GR#gRtByO%pZ?J*9NTkp12gRrN=&`KYH;$1wy-s7Lt+HU zfom|=^rYWDm$r8ke`R2=`_CT{fs_JY-TQcvK;dawf@`Tx4ro)C&bVi7sdL4eX#eqt z5x;RE+;5pz{o{ynyOl0pTh*;e@J+7JJOvt;f4Wb9ru%?W0yfJtxrmoO7I+vVE|YBi zFbM#zi^V+HTuqj|f&zN(mwK}kqB8$gf>F5cz#2MK`;T&}kWevvZS|UN*^h#IXf9pD z0Mf<6R`L16eH2?%%sMry zxuqS$dIe{2hCJ<2SiShc)m2jLm=VD3eE!_N*tgxUmc0(_AL;+`K~-(ixo%<$0295v zxwh@xP#^_*a&m_>LdY?9k^ql}dsHul8$wnoJAIEfvh^ z?n1XmvC(_riMO;^_16pW!t4pg4JyqMV3Y448DN){C#_}ZOx1|zqY3l$nM9N z7)C=$l=xc-Jwo1bVhH)J8BYfG<_MCcE;QK_pWsoc_1CyCSPXX+Im(00?bmmdAOF3S zBqpt@plZbjzoQ=qDdrxyczUFzAgxps&xn$U_e&HdE{HCoRxjE|!&>#SPAs?f8%hjx z+)C+j{QYQF<{&H;gOk(Nz@Gc>Sy!CL+FKqCCy-vUsDY)7U=bImPmp=d=l0$uZmh2a+LXU0Y%RZgydhMY#2gze|gJy?AyjiS{r6dW^ zkW%YSSv#Vs^d1csMh8mJ05OASxwthdf#`j9V+3&JjWPx((KzZQb97$LB7QH!9|!8_ z*BlSIonMsw$x{OGyqjgeyPiZLS*>ymn@$6&=Zm>DmFa`m0S?4*NeL+@oJpVVpYGy- zj*>|_#8Y4mfarDdW~^4qafoVVm(MCRTMp1&-Ch zo|o8V-jMji_3rLJ-cLllU)*3gC@svn^yRg<%Nt#Aht?L2qCbMHfnK?f5eH3Ok9D3L z?uWgdStgfWg!&6U{88Xju3RPe&jXs5TaZ=JNQ?UR^{q3mA1SKRldXx)$y8fPY%J^z zDcs$1m4Ex8_OLYQ^}Q!I<$16S4g?Xfu?x7iy6w%6jDN73;p4g}9?kJTj0XewHoHV4 zbw>~EJP8?G<13NFC;n^so4e#u(s}r~cF#+kL4 z9WoH{#rnnW@sRud$j2*;p?|x5rG-23r2WN(s-K|&t~-SVh$Zx!u{Fm-OYqb0{q=V%4W@o7L!GYMD`&&|XB0m3Q&HsG!zx?T&JtX4G;lQ@; zH!<#5Y~!MO!q?BbtMy3&)%OoCSnDOru#UbG|HUsvvSQr3si+D+{1FrZ<9LW=-gnom; z8EhsPEJ+!txOQJGGnlA1I7@HCj0&j)QWOb2=efFsJbTqgbt9(^rb`b(|8Cz;X4t$GKn7>%)-(2r?UlK2>o&$Eh9+#&DBitlMia zVZ(C|2f0e_e_?B6Hkx&z5I&I@<%1&;C{*jy>6V7C#+8jWSDZ)zNUEKo5rX4{KMoRfC|}Sq^l>ptvC{NBFm#v5P?2?UG=VdE>>_|SmZfWr}5V_e{9R`M(25sVr&VnCF&pi}qkTml=6;6zXP{ zwG^#HY(6P8h(gERuOvN*?PLkH#y`+VkQXww)NjzwO}!<5uF^@`lbaOiL<+(|05OV> z%Niw#?3gY1PAm1e{B88aL-fQQV%&dGvQ^}`+w1}@1`<#S{_ko!?H59AofJwg zi_eln(_?}|6MXm0tTsDEDL{WbB!nCv*^!2$%X?y8aC}SC&jbZ7XwH|BB2c3bOMo|5 z<8g<=+#B(?sFsU89Cw)~F14izQHmo`q)McPPA)0Z2|T-C@qZ|~7k8%L{}14su?;&p zwhc4qv!)z|VKe9C96~jRB&p^sRGYDl&`3y%W*rEX-`>4C&X^kum8FV@3zq#*>QpDcETgN54RCYr?y~WNe#K4*Be_F~kH$@$CKe z?|XK!VnyH+#QYBZS{eZIxqc|I54@Y=g>KD`6S0pGFL#hHtZ5IseqqxH{u_X-fIe^n z!#jZw_A3v-PVe=D=6W@ZKi|WQo#G_(T}GC?Ra>P#2_YE`B^?dSBSf6`@9O@A8dOJ7 zG?&AP;W$sq9!W!d(Fi;{#a`6XQw>((@-^NvA%4LcsvQV4lpPRm{x4q--v|2ijI)pC z*C&Q)Ef+1E50cjo*sv@=`99Je&Kgp1}yS8_) z&-nZA-uL_1T90LwZ)(Idd_8(ViSFR+FT8g&&F$cg7el`JrwF>I=b0z_IJ03L+Rq`U zX@0jPisDfh&)r3#G}tj|?4vQ9(`jIW#XuAne58Rb4g*HDjy}iuWwdg7GRzud*E}27AVdcP*C>!nQsWI9(((XS)66R^uQ1t8CcO_5pkrf| zNb_7iWNrQ~*7;!4H5y4Y==d+D}KtJweTJI3l0U(ndNNx-YY zy*YPx?vb$Q16lBcJO}t)r>&e6O_PXMQ_+y}(J&S!dx8fRFo5zg=uAG_W=t2y$Vnky z75|{voqAgb;G9N7;ACdQX8!bt%d=#~C~ig614seCNcuC9yT!5Du#y+$)LQJU6tF1# z!_}eJbzwH!XY*yWrs2E7prd{Wof3HfYK8Mr^X6J|_ux$FIaiXlVyPv<^fVi}e#roL%i6NSt;n?*c6BC9s$>P-nW|3wKcFt3Y zXOZ>q`M;?2m)_SQ07_WWBm+fhG+IO2XRvBEY4vb_WlXdsDS%WOC~lp)w5M5p5x6Q$aK(sQ>3boq)HV#BDcwolACHUt4j5PLmA&^%N zv3X8ugtGrdaFX$yecTtn{y;dh`o~+P?ybEUKb_warMy=kl9HyM9L#24EGG%T$!#R<8TCS-2igB%lo-F%_Ms?p7!z`oX;L_8;X zD(~P~?;TGqt;*R(pY#(5In3w08zfF9k;DG7C}A%;3t!r9E7d$m(Bp*mXt70P^oHWv~`G&o(vk*(j5ifu9KTByu$f2{t;XD_k z4z|%D$a{$k!jH@-GADt*_E;a1MAl!Xm1NR_Sf36ZapOdbZtnX8_ReQU2~yqCAyrlo zPl5EuHE^y(plS?wV^CxO0|jV8{3X@sqF)KC4PSmY7G+(Wc&(pE&N;Mc9YsGC^{L?m z|HWB97QOXP+A207ZTNVDD|&LX?CQ@Wdd6cbf?-^d-8}xbSd7~5`$jLNGCl8sP?H}~j zsHFzr{)JoTkeqAIVYYPpljQnjJ>3*qju*MaZpi3L0eFofWBr>A`6M))%FQ5hT*()m z+5O>|gU=g*NBX#w)^k`|Hs+?U>LWr70Gj#h+g}y#ttw;H?SE^43Dfri=H~S1<(G}U z4tiLtg!zq~JyvJFPJdD04&$Cg8!1b))tRc>GiBF$v~t!C!T0}IG1)2`uCmQono!(? z)O*>K@BaRQ>N?@xTj*EQTYm2rPB%w3ob=|%aCEWe?BYKEI*nlaQ|IY%^EICiJc%<% zQ=~8r4i2DwZ=`GmIl((p`#+@BI#;ZHhzbdW~nm!(;WVC#5Oaw_bDd1yY{K)u7ylQ{;Z3IC2 z{`o6c(5GI1$=K1*yLx7(cw!;y-$k>)ruj2oO;HN^}X0?JYxNpo;5oq`IY?ki&1Pc~6v#H>DmPi7P zmUdi;WJl=hGC@|rSzvdbQ5tB@d&~2JM4mIFGty}zK<~U=zd+!l|9v^qODQ})e#m}3 zNg}!~x}okov0nLs`0{T{yimeGdhgaJw*EQAmu!%B1Rk>{pFOcev&nN$HTrWFzGz=FaCNk z>`D3MtK?0hR+RUrn%l#>^OdC~)s~ho&>g5s3Yd_e9 z&3+%!ZZfnTwEIynaaf*2PxQ7-i{W{ULx0K!+lzckon%;oWO&K{EM>qp--sYKc*HY` z(;J$5dzeUYbGh`YSy>KoG8UkLMWyBUKkq)Ja)vmYYxE?osQz&zlC+&9FJrkj%|e{} zvG0Pn-I6giZ|BEp|54|R=f8$!-kRH;x4b7PE+GA?1if~gK$UnAO12cd?6yl1o#osE zm@?+VQpO@VR9t5I)r}PN5(hh)bR(zUI^txek1_445U>9D5 z=wT-d?7x#(5Onh+?L?RD>)(57F(ZU_N4Y>=flyo5*%^9;2U=q6o*E zC6Td$&f^b%UVgHgWBZ;6wJD~^MASzn?YixwC+S$|$p=TA%9q z1t&w#QE8irYOT0p*RTjwg?7}(U4~fIhCq?6oevVGX5~A{oD)$R z+N#sexX%m>F-br7(%X-e{?=}7&(TY#OHMd56J5hvClzo436+-uuuYvtYtGas{MYhc z!>F}_^pQHhkr1HyptCXBSQs|!bEBOmxA%;J*WSkguB1iZ!V^i6m~0OTbVWS;*a%N; zMe>@aIat!PdM+lffuc0PM5YDT#@RJ8tt8e5&Wz4ryyjgTu6@=sZ5HBw#z4%2JI}?V z`mi#u#3#CIh0%=Nin>b>-M<;X6=>4YV3*3;v9qvPiUpw)gw3x=z^cfKv zRnDm^AB{rS6hExBV@VRYoig?d2=XeU_@e+~yV@#`)~+dAqiG>b!>tpvXZ*JHd6J~; z*)oyhlp2%V>AKij*rIe;i@1Ptp@(TS-06#26e$Fln;|oesXMVn`7W6ar30&!z70AQt%z}q$yiO?;f zdmp}2XC7GpO{gs%hIl-uC*ei z7{-phb=jHIeZv{tI)qV!xz3kybHA8sg~<#yIONLtW6h$QKYX@bZPOCYpVC*h@ZwTD z4+lc*vYEyD9`MreYGz9V2xd@yr?=L!HkG6)Wx=Ju+ehz|c3IJpGhl@N&+{Snjd~B7 z{kkrY-_c|6Qp8{;=1H4teq6NLuZ7$H`4XT>(X4=p?5AEMYyWu|>C)XN$oG8(-1rif zyvI2|iu1lO#WeuffbVGYQ)9TA89Cj|wYYZU<8ThqBXdO{42^o4(_xx>l3MdHE%pAR zQ`%Y#0wV9xiHhuZ9LL285F?7F|DV zSGoJu0Bm{0)zYw#r8uvl`T?2~$PlO7@uT~()#fGJs#0;cZZf7k>z;-fMuYFnzNnP4 z4ena#m$@422(l1#UVjEGeDOq4^*4>9Qat(cLeku_#fZRMkW=lDJjW?RwKo1bhLpsF z>7Qu!fDb zY^jGzX@;v!a6ck+nG}EP5I6Y&XnI}tHPop*2VzI3Mp*Mx=|lHNs!F^B^Slcsu}7oMX-Gm)hqlP}$QxI6la$Ok{=GU1=w%)kW?5$XZx zN*T+_E5;&FNs)?e@b(Z|6OC|lBz5=5GytsyLIS>A=gV;31lfFndNR9AL$`-0IULCA z@>)e@-XuR5WbKvQd%=7<&{Mj5)7g5OWjmFHq4z~qBgaQ66%P(_Vi;d8QO_Am>sG7& zcMZ2^T^Y ziK>=>YVQehw3t{?EU>5tyl8_~^VGhe++o2ilBF>Jif}^C{SZ@jU&}!3s@i`^)0Y&z zN>=wWb9#C*!weZf&bp6xtsBxFu}kpYApmHp%d~8w5Gt#+*RTEu@cb6pq+$4=+-cPmc#vHT{18wA-dW@QN-fFI3xL3nH!`i8 zsp`cb8)B(Fo#mGo1X>h=P88Y;vcLjw8yXGr;>PLTpou6dqdrTACKkc6Oo9`l_oiV8byuljLMQC7oRR^!bsN{PZ^m@pjWjAXyD za?3g!(WR9HV(av3<08f@Mbfj>oBU8YekU~!1PjhrVuMQ7dwv`5j~0pTaG_oIHp|MB z_4F0hs^qZ7YmG7`UYCf8N$T6YCb6G+=xPkI;`n7v87D2vI_+KoV06KuQuNJ29Zvl~C)uU19};TT9#V0Q zTxsd49W9BHbR-!g3*`HVC7fvOnBO-+Renx(nOXsl+1Kjxt!<^|M-0Af^+msh3Gov`S&FAwqtP;kM8{$mOjgAI0W)VnX9UIF-S#~hWuFTbanYF|!0d+(UJk2JQHOHVjDf})N>dl0^Ez1SR;{C+EZ zbkf-Sifl)IKb7c2?SIW8#;F@8A4$_;O1%w+(J6ZC+lr*53L=2ky8oBn#+^LqaY+uYyU2c7_LgDV@Csl}PxO9zVEHS157E8zGndvj2JTQ+V2 zdsg5Fhhku6ib50W{lzig15ESooeBC%#BPXZZKWNrUl{i?!`J`1YR{Tv}aJ`?>ZeLH6OZD=iNvR{T*fd?pmhx#B`}nQD$6Uiwuk> zVb?llKJ~w%>@F`_dl+K$*$W--wur8YX8Y;p!YI}Sf|Of=5WjwC1aX{V3i2>s`v&_y zR;6^<#w7HW5zE3rNgau z6D`7I!n9+^kG>YN@$mZ1zIS6)6-1V8xqF6yN(^@F{pUK`?6^;NCFx$m%)KUqbrjkY zl#!pGxxdBwhr2wFEcb%N(JfqPzX9&cB0Xa1@&sa~U8?EC5+Zp?7l`uQOKN7>=>PEh zAIO%m?%Vx!_ri(OtEQ~qEiA+GRlj`XzJ{nIZ+q>p#lc-Vm$Am=oh5ENe^e~=O^Tl_ z)qm#?8y-t1S;DYf;^3TxVT{D;tfT?4)L79)X&mQzXJ?jj380SQ;+elu4T_;zK->** zEqN{z0H;Fi;Z&zzn%g+rkSxtgSHJ1k5fDes56K4|q!6SmaHMy!!8$|;2zenSPIVcU zcNsPd9V+ShRRcRVTTU+vt%EOH^8mytmT~v~;v`A4mJp>MtxZ)bD2F+vsk=unOBniO zsemXmjzi|Hj)vJ;yVJDL59A1ER-63Hk_3x$F=lA`T39C4zuvv&00qRNo)a;4b+UA` znV5ynMiK~JPRZIQ?`6ECs_?Pu3(Lc}nJNOA<4?R3FwP`2JMNk`v97!yE0qe9*qKDN z5%rA5?B&*k*$OQDZwYO(saJy&>?-estTA-(RARG`cf4$WTX)q5P?vOaU1fWx{Ksxe zuF-pt@r~`DKkf-FFY6dBJMEqOw9>rm+0SpmXIz43D=V_7C6PgEcUh_TjCTu-&yf-> zoo+vW5+qmulOUe1BKt9%?%-5(x9&>rf6OvZOVuZfE$NR7SH25KCPgBF62r<`-`g`& zn1PWtT$a27lRgU8Do^4}{ro-yT4utGkK68;sMUJApTob^1sjfJFgr7c^Avyb*zW@ILEcC3Q z;Pz7PDj83{WL_;`9VH*Mjt__nJoOdr+8UbuTU6#o}$?KZlhRy zuWdsPuq#O;(rEvll$iIeokT^e<@Z}uyO>BNbd5tsYNPCvgwJOL+TA-X$o-+c+pOou zoj?6ua`17qgkefu;aZ+cPguYmgaaef&UP^R&Qu(yIY>WW%6?h)&_!9hu=-bu&Ayrn z4P4X5Bg60o``RgiA0}pCNidqq*pc^6#G}6U(VKI z8)Q%*%JB&+?`&G!TN=i9v?La5IwNub+#hL7xVFVPBTcX$szc20~ed2!R*U7AZMlS$VB> z702{PcYp~2=Vor7b+pwBnWA|dxf7;1~2Yn`L8}z8j&I!xJCn=5M01er|TeRn+d$MzLIdW32R*Q z3Adl-cFxfB#i*;wq5xX0wdy1b{EZ&UbKlIAT#5_xsIe6gwdULN+p=++|V_gKFT-K)u5 z-Pnpu(WdFW2a7TpZI4B5pw*T#gQJtfEivrN$N8i4fBEP{SUV=1r^wU>O7+piO?ZKl zHeo`iDe=Eqx)1!D)T}EJolW{S3Y(f_v((l_ki#I*!6_kbN?hUW1CWfLVyPu7_P6{`%@kR?g@8lx~{dRgvkE5~M?fC}xa!!6O| zPy?Mi_VPsP+I&gUif@7Smys~5XYO{daYVYXqN1oFssH~h^Ec#oZ{&d)x`Ca<_rDe4+7Lqb-j6=?a0 zXJ$jD3vHHX5S}Be@?RSu-zw*CEtlVbzDygooSs)L?>5jn+zk{5TFVr}TK&B*1j^AF zAVu1&Pdy%ph(*=9*ctkHRRmZMShyvwiS!8L02xSIVLGp=%!|0MDbN`o)aem;r(LO~ zy)6q%7*f;@7Q0Wat(gHJFmadjE}ooEgt1nE2oE-Hq7G2(T%%>{O^WEN;I;4nrde@~xF;I6wd zb*9gV8Zv_b&u6sj;F1xH4Ijn6@I)Aol^!G+ukrca0Obt<$Nu$9S?%As824j)!~E!Q z!RyW{qno_lEAi)JVg!oO7+0m{AgSw>EW@yg2)5xr~sr;Xvt{KU#XE!4fjU&}+t^vCL(FNR7VZ}Iun>>@~ zQdmX{LvomwYa9V{H1NJOa2qIrdmUaxcbdb@G`QOL$H3 zireeE_=;PPl25r>UiU4?+nQ5>fxC#SYv+^0>YUa#T$O$WgX*^G)TYvU&3#TGLwy>b z+eSfAE3%KG2Jxn2@s8OdA`hD#QMuB`-d(9tklQttE zBvIEdA>Al?;FqMaJj1_8+(P(NYGJR%gr}E(jmN&`ydj%ca{nU}mamkYI|6s>EKUj5 z!t|HBG=DV{Zw^0P2t)1PWlsL=;cv9F8-3B{di+{+=HR}${HK?0tRYXAv2NUZQWByY zUK;Im32!mdd;dKU0luf@!B+B8Uh+j8CDlD!Z#85cTg^Xtdk#C?>QefJDRz+ki&>O;z8bnPP^zFC;D0@~-jF|3`9xh73o~ zt`6kmPZ`;C;|#U!XRz?1>*g5m$be7K-xj>iUTl~q?iU)4iscntn)IBgsD{|{D9Lw& zXWvgl#hMKTk(Ef5?~T6vMx<-?aPz4bNEuRALn++puf+`Khm#%x;g1eT=a*>fww>l4w}vp5R&Gxvy}&D%QWv-%lH!eje&;!Jgn+pXt{94Ze)nbJwj) zd+J%r#5HhWc;$SJ3ihk&J7Hv;CioG2dNq1_p=R3WMCBk1TMJY(md0+!U3YBw)Oo^1 z)ul(ZcLgJu`6Zwnk02|%L6x&l-dfP?KEd`scvPjT6H_Y&Ji&YMy|A&G{fprq2P1nu zzdo)ESASQd+TMv3bmo4W0VAL3g*6VEQf>u5Ra*w)T5CSE*6h+Wh;3Si&#c0)03ca4 zCZ*2m9-6n%&TvPNddW5QWuV&n49>B0a@tr*(5XJ9F%$^EY}Me?W?8n79t?a?ChpU@PtJ1s2r<)0Jl>M1;XXB1bam7gEj2!MrY!^_y zSPJTjlcc7$2%sJi^vt&JJ=-<|4d;xZR0+&_&fyyWGP8utNl$5>s^7G3=} zP%K>He$L3Je}0_CRR5@PC8S5W!YmM6gZtUJ<8J`z5qKqr9{SOMQ4~-gWV8!^M0Jaz8gRZ* zmvUswM}14D_D#35Pjf)7FsO-G;O{3j( zv|-s4(UatPWX?K`tk6JF9RjNL)nN50&Mj{6;u)0}=Bn&))IT8h8~(B}91_L+P~kOe zT!XEo6jy?v0z8^uqdGF9`Y0T;41l!v=+#p8s@+v^V}7vzxFVnItD>aJtI^+FH@Mpa zudKmlQk0JuK)^pRVbHEY07f}^?=W-in+GPo8&(>Qt=GUx)VNnBAoh1+OEr9?vSi&T z*hdsG)vHn)uC#&(+CF50>^_ODpuqVi_Iy01FI;VksrCY>x;*^3`w__%wV;{m0Ezx+Q|$70MlHfK-z`b55YEcDmzL-f@`p~;*XaF(Pv_7 zH6nB@vGo)zy5?ZTjJhAi@A<@zW({=x2d!r@PQ@ArhBZ`q6l6s>HgI_o9geLGKi>d? zf|W&JFze)70VUWjW}uLXH3SD1 z)u?O_*7*LXfffkh!1+=B?HIAQ*&41I^FyT)h@6cX9*sD`yr&9g{Y zXJD^0(X}o*4dQ_~piYainJ{1$2aM3OjJOt#U6gkyt-;b}PNxZ!o0({QzG4eyuS0V9 z__OqW4Yh?y6`M}e_dOQN%-5J_xp-N5x_OIuUPFZ|JftvuZ zE{1HkW+=Kx^X%K|&2Q&-V zcut5OK{6p)LdhqPxg$u;lM-u&u;Yz0aiDZl+Ur-eq^zdIeufrv7Zu6?0 zb=7k|wD*-uq(}ygsaF7*e+#c4EN>iSs2SdmnSWJq3lCnlmU{P;;DL$IZo-G?sULK; z9NAwR_LPAp>dLZXqBWP$BXV=rw6*nucwEeFElacz8g-lpG_cXZ^nUc60Zv-NNl`i6RIaQU3D z!a?{AVbgrzWtoL`xy7kw`0EQDx;2UOnAMteY?=lkq{^b!Y*s`5s8&OKnc)hyj1CmGVZW}FA{HA&WCiI6*!Kse>$NxC6(_IhwhlIAVwm|&D zk-kxpeAdO{@eO`as96;vyGdfb`o#nIFNgBW{I*a&tK)Vhpf2jInC{Mts~W0;4$G1hbOkW!%cBwa-;rY=HM!HHn8%}Pe@8VAOqkn_S?gDs zjJf2_P#{IPW=h}x@?D~A$2O&o8~lCF1b`j?j#@2KIs(-EB(o#%43E<97zmT@%{A?euFqZdv2s*KKxh z?w)>ArwaQ9fYHcR&XsTaA5TA>Kr9HVj=r9Lb>L0iy|*)V?>?M<2S1SLc=_F$-TQD5 z6z%!`@89=8dy&)`k@OQ0{GUkf$=hpWnTOS~$_EFqPiC&g&0HhP>Q~J+3M_E;rlwD3 zci7K0#?2|!%^94TwY8t|#fe5$UIpO>Lf?%Zvj6a=p`+jK~K2@^7}FN~XJmb;e%X&3@6EJHO{KbZhh7jktw#l~*~cP)WCU z7My1aYO{iaOa0SVgRskgUtR70H`ev8ukFp!uS*|op|jhqxG$4iZ$INk6Aym+g3JDm zD|m3wQsycPtp5Jy+po_qcI@~EP7s@Mc*zqY^^z(}+%}jX01#+^2C_`mKZ`qL*%KnL zrD)yP0eXVAE*-J1VlQ1zUNm^O?tSRTe)VkacMo@Sq>IT=+JC=_&V0OjaNzn$HPjkkaof~|ejGQKWzE|tNaajm*g7;n-kpJ&_9!a_jkls=~u%Ioy06=p~$;@q;hroJW_s$%cicKcetk#JO z67TKY=(W8Cs@4(B3#)ZKg;=Q*lGx;wMMhL2#S?*%-B6MKfxy5AS=QhG8{Aj; zk7U4ey_5R&Vb8+RlEcp~I>%19-AuQLE0%fQb6L4g7m0S(8vy6od>+d+i|Prr;<_%D z?mCry?gpH5q>Q{?pYh3Sd@09Ske~5#=s?F9fv9Y-WBBz?&ec=*evvY-^=rHHd!B)# z))KmIJHO6!P|4UTs#gq`0z*_7z%DD1%fBDLwnO8fyY`9BtUb{4Nj<@@aXIpBUyK49 zX{p$&!&;A?$(FL-=M$EA>f=OMVw--A|A8bRKt;>g%oSkOqMwr=GNNCmY&E?KP~;Nv z<-ukHZgXLvtyMA@GeZAxac>EuQ!4Ro8cPNe;FBeNOp;Kis1nyomfjb!$&gm0;av`^ zy_(7afP-mScm*Gq9tSJsRgScdYHW-&O4YsIPxh_8KvJ1RK3Zv_=+nJVZH-=FJ)h|@ zMVNd`(WHOm!Aw zMMe(xNSv+J8p9keRv=d1Mp`c!sBFt2S&tHt_Vx3w2e?!jVujkjE3-~SlEol6U6rKxVmI>G93UmxqAzSqiCa!{NvU>a_P zI+M#OgS$t0e%Z}UA=73}he&Fo8q6ho^ldj%!dGm(Ae zz2<=wbqR@2dZ7Mlg@p?gwtl_LvvLVGjq4W21qQxYPx&Z5^U6d% z`vAWaoXH1TjtGv#6w5`>H|p8iogCL-A%?(^G>nQeb$ty0yr@TEMh1a{-ufNjZY3F`7I$cCs+?QI3PO{_uVv++OU;tOIuSt{!r9Adq1 z!7+0XOh(R4KIvPhCIAT4nL~UjX;6@PTMWtLmf z)-n_sEOn6&!nA;c#uG0<9(D7wCHn+tx7zVGHAqy|elL#xJYn9`aV2Gk=8;)OMOleE z3>|(xO?+?h#fhho)DKGdS)8U2a^29M+lF#Ul&7ZvYlA`Wv+AJAm>*LT5?;<0NQFY9EVsnm{Iy`AItpPVvStpEnNXR>z> z9@V|A_q$#FU}>&qqDO0lP)_vESXrU@1l%{m0WJAWo0aNCr12bk7l@^$&x(zbem>}WgLMh6uV`%AB z_x=RqwG5x-$?XD2LD6`?4m?0&@EJ!I@Fl@QK#>9ap3hiy1Q8cnV_T}hyI1|-DvKkI zgVkVDJ%!LOR-s(3%Fh7AD9c03n|m|ve=&CygFdGhAhN+yVxwDHsGv2x!?*8A*M)TK9IQ{P;VatgHS zZgeWwtRN;y(;?fyQK`!ZVz*F(2!}>X%2i47OvIfsZZ5kkW?(M*M+St!y$((<@(*iA zVxI8U92fxZVPlpexsQkCj>19%G;YHy_Y}@<-vK~(h2|* znAXT~CNrd3oh%g0Y1~9U0DJ%452I0mBqDgc>>&Z*5U>d3ZH&_@0R||NU@733qm-%W znm(^h9@MZ0kZ;65pd{qMD5|19>Yi?MH~_`2Q(ZIV+Be}L;$~&Y7V41JAi)@(9iUzf zklKd^0Ecc-k686VuA?34ctbOk5I1__&we2wzmFi62xq4VHlA&;9r{Q>A7Yp; zleK5qoL`zJfx! zZXiCj%DiWt^wh8u8^n{Vhyp0`NIBb14zU7&|NJCLpu@ic5PNoH=ZjV1r+KBktf{g+ zL*VV>m`+e^D}0-l?Z$8^gjno-_X+VFu-nkB zU^0RJolQ4POXzASkc7}3lLHhs3Y6~C6{ZUQ{5(0^ck&Ilz~!zHMP3(1m*5BhE_lh* ziv`XA*^Ei)rFp+t6l`b}CPqnyM_{cqL%kckX+Az6zclP%u;5Uc=rnFx?n&@PFHaajp~ zZmi&tKh+{tdVA3NIXos*Ffc zThl-&DaHt-3Kb6*K}(LDk{xkZ001OMPAyDI-MBA_sRkSRq-$2o>=B9Y{D{q|_!d`? z5&-}lal3cljVf^F;ek(r(w~%t32!84^2%I!nK39SXCDclRwx>9`kwCTi6f_91b~JG z$WILTCIi_bk92WSpKV1h;bWwjpnL-I4=PW6UQ%4x_1O=({4Hx&k;F@Y$r=yoJ7qoP zVroH_`A$b}6OgL}9r=TR)UdqrqgwhF7jy+Beupb#r;uwX z8F4aDY7Oy+05>9_2xP=xGJ*q?OhzHa`tl}uTg-1G7yXb8c(pT12&s6aE3xWJuJ<+o zB$jihso3>a({b8avsGB9d-bbJrduckNfaa&u}AS$K#S^MJmmO@FK`|uW_rxvtBg$uS_Uxi# zy}?4zfAYqlB8hh+$OXET4DiYiAJlXr^85b6=lA>#izJc1k#euAxGBh2KTrGzJ=fWg z#dbzeY_hIgK)wR(eqOHrMl2cDft^Q>XMZ?87+~b-EjB)ky&lT}=lAX{VqfsI4^w%>X9S&1FOx5(Mz-L#Q-eGR_BBM9)02 zL+ZDT6msMidIXC4cp!OJamW90bnnqj|9>37ceBlG%zbV%_iN1kuFYISjofd|B~+>r znM>IPL#2^KE)fZ-+!95NNlHm>QL4FA=r&U6@@>DJ-=905o!!pov-kVFKCjo~Nrj#f zfaM9$5)L55i)71nD-k_Y19WTxl3s_{Zl$GjX_z{MdOM^*V5w@PQJ7J^}1(Xj0q6h%DMyfe6 z`(*pMf&_pJ8l*x777*ZS_=}o>7iZE>So?wVS0%Z!lH(J|QGUtzkW)*$nh_tljh4ER z=v_}o^3ceSglb#~XofCT@B>*RfDgAjeImmi%1CYtq+V0RQzyh{_M#c+R!B+8Jvwr< zPVy&R^4ckpaS45t3$6*5dV{`mVFIP0D|zqNQLz%KN$QE+Xs{?^b{SBY25=M^$~7EV zBU-ZmkMhS*DN&B_7(x6jCuf?yhXkzt3Xo7OMO=R+d7PX|pol*rAYYKBHmRs#I`R?0 z9OS3=>ev9i4mQY@{K=P`Zlxll8_qdMnS2w%?{OtXVeSlaDxQv9E|hE|!-^)50#P72 z0IrXKEaGdHI0zORvB-5Qz<_ymCY%D;Su#q@&@}e^m6`_09ss`1``Gs&IyXeZ*%+_m*XC4eX zeWXYnN5l83lFRVNwzM3+rlQu&C7(TzX=-h`VqX|r^#Dg~t$cg~I@1CMKa|M011V{n zNi3e(5 zCaXs8Uu;~x^w6Dq2&__&c>Dga>dz|_|x;2H|CoCA^XMxK2sYq)$v5C)Q= zM}h&MylFTAtKlYTtEhrD4DhVeQG$s%kNQX)5l}*5D7ej%m>V+Mal!j zZVL2Vjl?w2PZc=;UpxYV!&nA@r)D5(bs!aLB#Huz#R1B1(?EP1bqYwH56~3=?ZWlu z-%*rs-N^ynDg>bKL>cK903paezY!!qpqtoT5jtiQ*9}n@*!s304&gAZ^&C!2j}#i9 zDL~wufE(3i6$3z?6g{}b?W^;9(j98QPap{#kP+AZlPm0Vo%5H==yx2c_k7}P%3cG! z(;`_|EkyTiQ=}#cF^&Y#B&GMpwp0dRQizxIqWTLd(2wLhC$bgI+Cc_{s<#}FjTrb= z9IH57l0XI%2;?QY=rnm!`yD;#(ElK-Urf4=pCUN|oeLHvB6B6*-vv$MYX=D+E5PhM z>ecN4k?t+|iHtHpgU#xI+Qw3kq?Pe?z>8>d1p(xFW>{o4ugRdaIb?0V#CL*JTl)@) zxCW(*sH&%6We)PEDAJV-COt>}5=a(tKucRvV;qxasy~12&Y=fStf!u$bg&!z%mB# z6cvWWL;UIP04ns(%<;(?HyDm&h!_2@LFMoivbExstHPTFmJkw20mXl!g9k$DBCP|# zBqmtw#I0NkAQ2A^_Rg@;)K)=vlfthNr~rj_h?5s|BM(Rrf0Vml{`nO#Km26NNyQU5 zc+Ld$umI+Z7SB)ug@dVhwGLGPNDwBT#Do`5jO%YqrFm<(9F}@ZJwo(j{36eP-Gaa9 zL%!RPb|X87p!#rw} zB*fJnW=OFOxH5IGHU-M>M1FB8mM{}8e4~iF7l|+M5D+owJCdZg9@>f^zCo87<<2wE zQo;$O<1O?QT}su;Z@EtD0|4y#`DG9K=c8oBCN%OMV4JRv?BthdTRDj+%I6299^t_@ z)jWp<-p(hfBA&a6!}nBu($TvY#dvFFnz&U3^Ev#$5>b3Ouvh@qM3_m6plqFlJi0*A z^|$ix%ToLaq~b|Qn!w2n8}!I!d8c!6W6lS+FMrl59)diUouc0TEBQr}U-_%CeE+8L zW1*}U-bR`W(xZaTpn);Ch-LWuDMH&*0@6wmrF=mAv7g$oJ(9&0duqA+M7HeMOXL(z z;`kROQK|RZ?;1&Q^kkE89#p#WmYBO+&ct&QlP?EnR@tk<^qDQbXhMi!pxXno@pj;9cKKZ~W$PMtbcJ*K$Z zjwd&>dF$9-p=Ggp*yVGjUpdbMOk_gAHC{(%vNC|ZYDW%|G5{CmIi|0Lw?-z@Zy`t+{_D4Vs; z(8<@F4)IV=x_4|z-Rb3{gp0~FxGNzphyaI%Z!$hes}{kRRkJ6&%)P?fy~xt4{|3LR zo)q{6JkMU~;JN70@E(__${>&wO^_TfCjb4pyKP?3YW$^RHwb|9-SQPcEs3H zzdGwppB(~X;2?=JS1~D?{-MW*UvVOU#l+s z+?TqThToU@dcfu_{Z(LZRPKu%Af(l0eZqO!hyomw*POT=iL} z!)GK`I*q{k+i1#FnL4y9q;Ex;FQxB;pT6RNt7tXRa<7Xn1~lqlzB=(GWJz+M9+Sru z^5p)kws^|uyGZ1<-C>}Js*72LQWvSX+%`5|;=1Q-%42Cy1ji`Zpy&N)L#JPuCdxO&o zng>k+FXB)B`uzDe|FX#uN2fYnYjKkxh#oZYo5n*I=IxK;Pb_#-SJkX&ZhHojg)MBw zXz9rhmwut!C|3v1p4?tm&zBzUf}i-ttBCut0DUe-UY8dtbW zea+UdsI>jEf>IG|e)OSJ@iDE8l|&CG#DlZU+=~Yq6V(6XNAKKDK6{d&B_L9WsI8~IV+RgxD^_Rkj3nqxGae9t<;%fKTG^Botz*D|g-eLvJ zabb0Y*1ha^wM6cU@qQR>Wm%~@g=z0NL-Z?o9B|5OrZp_kBzDmwsN4K0!n3hBa>sBm zcl{EeORqgP+W+AA63G6?bCiKSanI@~+ot=wsP~YCz2AcVqr7E$5=CXosfOHnl7@d} zhTQjWGW0IQ-Gr@ytoYjbf|@%&wqM$>{FbY(SdQIbOshA7KpE7qe9x4nX@d5kc{*ps zaszyLN~wGX@d*ieaBgU)8y;+2ZPr;~)evX5H@-jfN0&#z(F!+*u*pWD_G3Jbq&!&w zom7Z7Y4wVOB;a17zD(Y_DP0dq$EbWBKMs?HXox3uanY-tjH=TVNkz`k&dgGvY#A3~ z6xbqm65X4J9G5OD1T9sQ&#NQ>z_L`j7*&QM*hKWy0fChkbj-o@sfpM7 zQ}>@50!DQ};7Pbckr;qj9Uf$t#5L?P3fHYHb-1``Vr5|_?w%r`>jcCAQVzgBm)#Bm zZUYfYbrC=W000O8NawBsWKzyKz1fD^)|o&3IqkO-HbYVVMP;k$ibmBTq>$6em(nA2 zb{;3pvaWeP%Tykcm_m}ApZ-k%{+zlrQp&{sq?~7jl++0WSI$ce_z16?j>N{_7WIHo& zjWrXyDxME-bdG*_bYvm83^MLvvs+2>dm;GDg1*am)LMJuq<@0?^8T~e9ou8S1kuN` zbincZp|3m%-T`Whw~+eijORfR(r=i&&EVF71(ZQG@-4r=c6y;XZI zMtQJ#$o~3wco1?~NlOK)=($i)GccMkHJUK3Ftmqd?XAJD9EIlZLGzKAbY)^Z~fA+I1SOj_0F+73vyS3c?P}0OCG@uRy&^K-J!&NUP zWpV%zf|yOg5ZZ;B4Sq(vQ&rMhH-{9S)Y`)RDhiE@hn`)%n$V%&o~WP~k1(Y(lpIdXwv6 zo_mag!GTZP(t_-^G$b)|ufG@&fQagBG>%dNYtTF4vTj@aZ-XzrF-JxqmpqQp4aL1M z9?rYI-*l;E+a)e_@`vYFJ*d`P~$_Y5@r|A!=E&JVCfQ0*){3D9B^P zKsGcqYb(2VX>s4(0W}cK^2r6pMfnFfVve+{(G&NC-ul&C9T~MKktr;C>52e3gNipm_wqbQeIv z=K$w=>8M12J{1BXfX6m^fck(Jp&(a6u1*N3mufiSXEQlp2*D$0r)&TmaHdvG>m1!8 zKr9v`@;^M0h)tW<9jECQW%{`_DPBXkDR z6?n9{_+tnoNx#%%RTG1`ljW&#?i$Qgx>(zjafl03+t5>8&4p-)ZQDtOa$#AXc?vwB zBQ9?@ndLEd;hwkV4q(5j7t;_8%MO9z(HG?iVp&{RXaNvA!SX2_K;{Ce+c2Q;53G9Y z&Q~yK7f#H(ci7@wSvI}V()&)PKumG1;lwsnj_&A0gJty&MCSr!Kjva8256N7ngFJo z3oyp9Kt5!YR+k&hV0crUmc8Lli_l~G>=d}z1+z2wjr?A1nD?km+@p3XXDqo_QqCBI z`UK6UvhC3_B2P186c$&27JMrvQrOG1CwgP|g&%i%v&`dKufz^D;;R%RS|5xrTmY_j zCQV=YkEA$FcnY#?dLD59_bFdJTY>_&>2x$uomNmbBx+mHv z(%ZB}I%9}ssDYxVRr~q21n0U0Z7o9o{97bS%6=`8K^!zkwn+6C@4a+^vQI;id(=@8xZ|k@I>!b z5HH@Lx|LE~ivuGHdJg4AaSa@qzH^`AQ@g8k5d{j4hFHa+c6!EDJhu`|}l zWqHQ0YLN_6SgeX2Q9am)lwMN^)T0# zPP!I=E+JYoE8xy^tp?u4U!sj;f7O;O%f}Qk;wS8Zi|TK}O>nfnuk?#?Wp)>1M-}Du)TDKd?OCKUzU^IH(t~0<8`p6+4CI$l)sh?CbOAb8~&x$iRHq}=Y$ClZ7U8w6>7~eEJZfbp0GNp)hLo)1+syDo zn1)kJ$ZN`xDdFnA~2cCibH~_^f_op`Ilq$sqcavC(xFUcVs`( zoHe@MyS%eD0(z=H->^5(N+`M@_lqeOKGBAc(%RV>95FjDi}6o7TX9_t@60^2eE08q znWjNB8ta%n9Y#8T-{{&)b8k$`e>+>`xj-MY+!CgK2xB+L!mhn5;oH;wz{e%x7oYQh z1e#tDR}xEs9IDITy-L7xfo>s{16zGQcl363?Y2)PRP!i|r#rGM5;En92cd z^#>>N9jQ8l4+g6fo9}MZo#B9swsf~`x->a&r~U(JI!IKeJBJ3$ZPWeGxw{0px&^s& z`eaSxNPTkNE&({Oj-kVGOFc(6+iFHUU_g7p=82#^&ABhH080{EkDN2|QwB)m0KZk~ z63r?Go=Al>ze!=qsSu0EKmmAFKKK48Kzh{gec>4`ODSB<#Ra8F2UdYGCeM>5Mif9^ z&5-5_{SA59QR0GMhE>r)L%=ZxiS&pOof?T;&tk2@=0AoZUgEG2|((gFj32*2r!!(4V| z2#mU&pPUGtvo8?&y)+Drie|4qh9zJWH7^eAYJsHzVAK%U^)A?6wIDqO7!?Q0Xl7eU zD>#TODDxO>&tV;_aHsWb@I%y^0a1lpnd4;-m>HP4;cip*GtPp%&dAeaWGAu zR~4AbkHLgK@n{{S|_^QaY!I`0|FuxG9*{uB!Z3m^v|RW`ggtu_ue>Vfk*VbsT#-- zi z{UQ&Zozl*c<3e+2Fe{3B&}UdS{`x#Gp9V-cImbQ@pHHXQ6-shF>vMTy>=Sda?SCH% zH=tP*0rY6hQOs^Y>fPOF52zH?&E0guVJ4OE75Y$QT*Ht%;o;5p)FafC-WPKgayV|j z$Pk5ofMrs&vTkg2PO<`#-v~Pg2-vtL&UP zc8=#GtDD}re75L%$?;_GY>>$j)H@4rC!ZA5n*u@h&FrnHui4b2IU%qM24%Xy4=hf6 zjv)VOtAbS`%=8&7)f$EM3_X#k0RlD|m$I|b`!jco2JeCUn(vtG`a1%Tw*9*_`h%MIyhcZ)5R(P zCg;_(addGyK!T7VCS0YTRs@#7=%p7j%J$JE=jbYR%+fIU#R@<(hE$aa2lDA+&GgDW zzo4F?hM89V<}3w-^>Ibj-2Hqg zRX7Tb;)9xE?OSC{ynCT0H=v<>P}(ri-4nX}5gJ1V?}bCXDe4$T-a+dAgK#lX6>O}$ zQggQ?_HVFG#ce9TX9q7dXt1#SNV?pRpV(J)JRe$*MLy!L=M>?;j`aKWM*} z`~wxyLrJ41Jw2E7iWePiET)x~!nw&f{&klR$X(%PPC9JUCD2t{(#=npL24Sgc4bhm zMtiZ-u*v6P`1hg9J`c^kM&q}C1fCmSiJc6U4GM7eQR!{z7u3mDHcq`Tgq_nCdOa}0 zG+euK>xf!LrtR9><}T>NU8;7Qb-T$-sJOVZeEyl^SNN+-`tpf|IGmzry2@M+grbgVC|nHL~ZTSW63?2%l=^Z04&vz zp%+O;>H0y?-_;J!>_v0wV3_sp00OrBD$yqAD&X=0F6CPO!-$;@^CZ#@(>Y%6WeO|@ zAD|2n>1bJ3B+&Joro30~S!+p=itY~pekep2X^T}K%P(6hc1#^*alQ+6Jn~N4A`7pa zvv|`!2;F&bkAt?GSSd0-sLcP=Z(DzIN_@fEa~jGf3Mbq1evG7$ZxfB*Tzs&TL(Q&yNoA0G?K$} zN0$aJ9?H@jRHokb+Cm;lZpvg&+QFaFwXy(?uVb>XidU@?r)yGKXCrii+5_L zyL+UtsG31a*NfV@=k>ln=9h0tY_jHq4yU~yYdMoP_r>Z|eg5vVcQuaWu&@7|Woy;; zE(y7#x;2z>@z@hqvmyJ6HO+qSdG|fdtaK%ke3Epcm>m~~rj=1)=UwB9`cC-g9{F_v zMBxJ<3L#Vn2r8gMw?5qJ-=7cl3G=^#3{KAfp7kf}cB|V|+L!%4>*V~K6|1OBmcnz> zHv>Q2CI)vqzn)tk_+>Gcx&Gj1{!7H}|!QR2#L;fDkR%^G;6;!ufaJzTt* zE^aPh=rl6{Qx0$7EU+#X&43w>PUHh@hm?;9*dSNziep7DhP#CQ;pz5N#N+ShH(*!m z@-18IC9_tvRPgvE$oKRc|B}s4#{@)lj$nwWQeS4GrIr%v;fReS^$d04;{2!J5xXU` zv$AqAqL5{*^W}E91LlEDIi3kir2s5kHPBA!eJY72rNTe;>RRwoFY}uP87oBF?G8z+ z>7xu$HPh}(ht$dH6!o73HWqNz<127ba+A-t;BG$-Z_;_HCR*azb_k!L|72BHF9~O0>!;}grg$#i3Q~ouqe1#fL7*-4- zg9VhU+(5C*gHP%azzTPV_2;}t8x5LjEf%C*ljkzajzyC7cZC=AYFg@_?o}#rPhOs^ z+B{cjD=H9fh)>jl(k>b9KR`ZpaJoU$s%2NC;ohqC0Evs!M+RLN<~GZ3H~Zf@7Tz&I(hLlxohq&su$Q zQ`YBN*oF?b|6*XPmz%Na)y$ndgS|I)&IqsWmOV5-7W1Qh*o&!b`MmJi$so(T@IBIh zd2r4}l!hA@oVYWquyEwC!`Z{(X{CY!v0GNxc87dU0B+PjYQ3&IrTnGa+2tHQ;_|JU zIV7MXGj!zgbl<6uhQa6D!dpPMYo?zXr&~xwngsP^+2W09g?m|nqp{e{0+IYmL?lms zb~36Mahmo+f4aB>I^E26oOL*RoNj(3JW}`Y9$9dTh__6(dXFggJDYiW86mfcmE@=t zNyO5KvSA9k{Q5WFU-A^flg@TiIj^?kZA3DR0p#h=$hciEDvEUkC!weJG2DCZ+V>=# zzWXyb$5CT+54HBl-fEEpqp4C8(rzmJS;U>TuZK2rJe=MW&t~$M2OhR9@ARjhIRV(d zO<<&W#h_7HPhzoBCq0Ox{jZN#eju9ZKXe|Jwo-D478{>{Igb-}Y8}m!TTlGTQcpUY z+25clt-=>Ew^zQToWYWA6>;mAYtC4pFx} z0-av^z4|KdC17w0Pwxx4tylhal)Zz0DrP|5_Eu*7u#RrD1TC&F;8B@qTQBzbeeW;p zgT1*rSRyK`cX|G~yH(mqPqp1gEmd`3YLIfo{*=EN({q!si;Ig#(x;ZO8xthY8@R%l zt|7IO+U{%q^=H$O%tx2TW1FpB3uBaTVn%Mb+urcIYq0mNZC%X|%WFoG>v?}tn7i;p z3Q3|Sa(Kq*m3zCZN^zR!uFVj2*+8|I5)yKbV{vXYg}ky^E#oV*b{6V43Nt7%xo{h? zBAQ3%`8@eW$@D>^L~Dm9f@=r<`)fI?`K8zUvV|&#f|;BB(Id6g=5|(b{SQbwxn;jh z9s6|@U*TtX;VJOLIJe$|v|+6+d`-=_1#@f0L#G>N;$DC#nX|Y&hxKSg`I&UFYiilt;S%q}ccahHEoKeBl!|~Iqa0bN{*UGo9_6S9ZlGO1*^#%X*nL4414DEs& z`}x!Kfh#VNxh~vWMHkk1_7x1xI_3^hSW*OW8t01YW$4T?cSSIXq51M`G3hD#A_?npT58OQ?H5!`_1a8OApFy7Ke51=FZEHklRXCid!sM2@L^HDZZ2eLi;G=#F&TEz zO^ra)Bd(Xs$MOk!{X7RB7i${E$@qCcpR3gm&bkun*!#*cm$lcm(sY97=m|!ux+2?# z9HvP&#$nwL=yfwZCqCGD7;N26a^$+8KJ63gygI+!vWNDSHi7ZDx zOXev_w9G-40H$p$rv;KTpXJogGv_ogGAKO^$_@pFUBI$cl9qEk`1k94S!0p|U`6OO z%d?+jCik6E%jG!&R-C56*3~5EzZ6{5iuIdVXJ;nFeo*!)%WMejMByRg#3b<``}Rin zCSK_yZ@p=j1BQaEU??|>ydsh_grs~&Ld69M8S2Tt$8PqDj>1U@k#(aFVpI7)C_XQhO z8WW8;7Z!FVxjN?bcdkm@knt+h1P<139^8Dsq;>p?0q&yJ9Ls$PEc+h`_7d!5*>Jw( zy%UG$_E`Z_L2@2u>1-7!HIkhBdEV|SQpg&a0hWC?$w@WLX)Da`x4ICe>1uqPM;Kz+ zx3fHppLL8bTP^S$7r;*KB!}%7=V}rL<7(Uo_UdHWx3Nqg^K`gzmb%(6+*G*DtbVry zhpl+06|kA-eiV`=GedF^iHiVjCk`kq&eL{<$GXK!Sz>wqqaY!y6Fofpez3w7@Qdqo zOCP-h?|IgZ^qFL$-3qv;1$^{)lfAZ%V$3VtFddr;wolc!EfWoNy;JVt?d%nK4ZK`Y z!s#T~*%fRzx$DR*FTIt-S_j(kq1Ay9kX$kyt~QQTmKO&-a&=Ff*<6 zZ3Q6XQ5X7k1;bpBd2^^`D#%b|vrb1KDK3tDu-%H1DALSHn}H#$4UQ31)Adx ztv&Zw)_ibrj*)I;In9ymQeD*ejJh{q+b7fVjjVnvR^sZQ)v(Gd5#-l>!J$82ITd8D zZ}dtYh^gi|jq=Q!2j%sLYyc~Usw+pO&B>tbPEt7*wr|#W+@z`}PV-pBfc9~9}z zlKC}+L%+8D6x6+#Z^!59F(lA+Tx-tCRl_rO|K1)35N#%!uv|hu2Vk12YdlwUVNrC3 zUKc$yN?Nw$Xi4S{+2*pabzIC1fc+}VhOZ4%IP?M-bZdyES;u{{2(TNK`W>qNJPnMX zt4WQ1vG)vNm1vuB0K&_4TpdrnS3n?Epk|xueU(piSm9Ycxh5OpjRXK|J|FVpbG4t4 zoRKUj-y1cmVb;qS#~J&LaBV4irlTNp+puBhk>MY1FG3{5w?Q3zBEmk$y|ik8du5^F)ve>&k!I%AKGzaCioRMXO=cKw;j zVfcmMv42T|62Yt^L)MWY1p#6(Ors}5#-D~1CoazBKB;-hv!eo=t6@?;p!1JF*`bk` z>J|G6p3`)E2BJ!~ndMC9t=SWib3-ig8_FUB_r`m#V%EW+VJ%#^1!vjOP@B?6{F}|| zp9Ns%h(f*5Awo0Bxx&QdWZgRGNm41Vt&wZJ%Cet$mQkp!tT~JzgViKK=r*o}$kFBx z_R146PnvoIAv&WxCo~JnAs`y*&@GCs>(|2(jPIM*l-Ge)cSx4i>PS%!pYaiLOgN4T zTzkocwh^T3cuu`H^>1t3Pjg42!5xt5bkB|YdLEunlyB_385b7$5+61j1wHl(^sKE? zv)z*S^qiZ(p!SM+aQkr|11qU`bJnqS-^)9q0?8dbTfFJ9zDP<`XT=Y>?M{BSPixj>(7D2$d{5 z6y){(uJWw@LO>@ck8S|gQc{9DLH4wYqs8x?hRxQ;JAhi(WKZqIe(gBEYlG#-gluk# z7M_eIfTa&MRCAc|i|;WFFl-jh`tvOHZ&|8-uuV0O%ieU3FrC;SSh=?L*R!nJL5l6C z3+{++>=19c9EnryFzwb4*md!wpwl#1t^9Op{`z}cN1o2#Q>fsW(*|hEpS4jrEn*+0 z#%gP=F16dfeYcPO1|qydi;I{zvZm`?U0U8%MEo&-V#z-I2j@ngpXi_aWiaTPEw z#!p;KdR>&K@jJ)HY9_&kPY$KPQ=K5m*=f6MIdKjZK&j;&io<8Ekw#KTrtqRyYIAMF z!OB7Vq*VR;Q*P;7R@#)RmPNbi`S&KRMNN!Lb$E&NH+*tGw?b@?imGPHyNts=ZpOByIs7%Ja!y%w^Bnm+=M|PCorGO@VyA9BQnJ9U|B+~* zx$meoc&}#re(Pw{m@`Ma3bRyV6AsumSU=xwP5E6`+~B@{-|>=T6Q_m7`o}L?XFWsc zF;tS6Mt_G)pMZ?RfU=*upufI3CNd#+en|1Gi7+b@g)npd)Ez-Y;ol@4X{U>;@HSQP z%aPD6=Y_cBm&CsmUWy*>#Reet>=q)9#Mnhr!(CCXCauNTxFyIhk z!FQvl%wFhg0>v{dgk@(XGR#BQ`hpd$_PW}uWZeDW5A&#w zLk2zQZ2B!I$u8^T(?bufGXX&9vEP}x8$D*-vZQ2R@CRYl-tL18pnaWooT_W|rXyhmCJXsxn3-y_y z!BUSb2k@DPY8d?MEzByF5WAy(Le5(VYdGc=dUo&4#u`(E^%P)R@X`fkS0AOES)sEfQpp6(L|eEd{-;PRIa zyz#=~284_TQol(E>YIi1C@}l~Bn37n;vD zIM-_^mayHCP^o<}h3T9z6n>=VFQ@97*&XV@)6p=guJ6IqyFSX_<}$4|=WZ9glMf9) z5$J32zIZIn@!$cAFE3*lCwh914E(3CKz*QgVIigCy7le2w6q`AhP9`za7^RKF5;g$ zPo1{XyYuJB>;|38Qp;Kog{h^^YPdPtJnz%PdLP`jsmbCe_l9ESGT5%P*#mm@8OT(9 zO#0kB4V(Egnyn_fgT-MJ7c_(&YN?YMqU8A@gUja98;wHekE<8J^@=c@8@y0gyZJ#VkTgtQD^hs%h(eY&D1Oaao=7A)4ZF2ha_6&9Ns$J#5yhxEQRqILfjR6Evs# zT%Ha;Bwu1v%*LkAdR10b-st>$DPwx=kE)~dO^x%Q$emY@W-^aAz{7SL`QCm$ckB9# zC5GC`?u05WXX~_YPR<#J8?5flkCoS;_N8{by-s`g^grxh!2|V6e+9{r&XKDPx6dF9 zxy|FStbJWk`}`4qIab#W5`^)!^_!0p)OYp0vieaXb%6ijNJ|~tc^n9>)-ZxLdOmzB zV4O`Svj{!56U5(smvaAJcm5BTUpzcgL|n?s#FyNh?zu4vM1 zJx=(07E`yts@l0gyKO&p2BUo^tG()aQJo}i$v|vj6-LYqhM2_hyoC*m4i`&m^96M2 zRZ5A%V2R{OpJ78c0Ll9I)dyLJy&C$Wkr}3nF7rw+Fb@nVro^G*b`P$P3PX(f{3Rk2Np0R!}|j zII-rV*-clSZXY}0j+jTKp^qA(z8}x)|2rsSnKm!~Gxe9l)_JMQM*;86D-Ya={^4HU z+kZxeNifZFs<(c4z*FW4Mcf-*7!*7>s8cJ-Y_jDkq;f;0v5dl_&h5UXy~8?)$u><6 zA8`&YW^7-=_L?ARY#X?!Ev)&nGG%4gA-;r2a*1+Vb-(!UsuI?%R+U`)8;WagXXez`Q44uRb&NFL5sFc=MIVAUp#igJwEwc`rd zK|5b^LAZEB^=xyZ_Y7dFA_gQi0G1dJGCOl9AXceKzaTK;0X#glTX~$~h8^Bp`5E)E ztgF#CF1W=vLekxG5`qR?S4s^RbGm!+<`sW=5275WLtKP;F(~x=GM#q9%foM(8Ri z^SOrN6~Er0nSHd%ECt*&t}i!2DrEc=_^S5L=;RF3lnYr=cS9faEzaDeUb}Pe@s19S z&sXB!@f}_~dJ^2nYGp7ExKMtd++Cr|5cLw&OF7R!=vzB)k{sK9I&+1jt}*KYy#I0U z#+P7WFM7n=*V1PJ%GT+7dbs%Lj;@z;#pNTtY1emX8NGbHzTNdu^?I^q+snPq7AHJ^ z$m8`s#!kkZvUvIJ)6uf(<)qgNW1+K~<@e9W^7S*a1_pJ@qm7hD$YX|hxH~MP1cYfM zpx*WR<8Tr0-wpJXKmC2GW)JIzitK#YqH*ViQ|%xVAEwH8F3j4qS*4gfq%i6^(s+S! z+Of=r=5I2-)f*A2k*+*lukgLuEArspOUg4X<)6=I;0p`5v8sH)Lwn~4$>Ky02a1Ww zxljpT-}H}@;G_2Q192W&ZU$nhvSc~rvH9_U|-g&w^848g#DB5 zm(r$e1~!Y*2e!#lfBCm-FZg4fzf``>{;)G={Z26WtJl8Y@AlZexv#fx4HTMEx6rdkU47vGE?;!sn?>bIBb+u}cN3HN zFG78zzX5wXnLGaWij|+<^TX$3xeWDo_t(EBXs`ttd|yYLi<9#oM6GfaE)tbF^|JlV zrf37X{6(e98cK14lAbN52MJPf3`})2#$^!MEM@7eCr7JSDj!sYoEr517*c-dIQrM?8_{fG{{v$)^=rnyXls&gCamH9D195*BwMJ@J=IKB8+Mnr4{cW1CYPu@X@oeOxG4d%|ey^YW)1#7JS99hDRi_u# zryFJAM&eweI=xYKM1!L3E^WMD@&MG63ey^O7198TX(g&J>*GfjXK#2+w5_Uc0o7ES zHK=qM&17Y`pu06mR>iE`_Vam{kCml+ZWG4N>mQPTQKI%L`CC{Ap_(DtibGypJlZIX zHlWg_M_tv7qu;OMRQ|;)$6w}ox~hWe5v>4O{xCLE3Wfz@AIHhi0kBPqD(1an%e5B~ zU}!GLQP~K3Swnp(T4tA-MbmYJ+w+XX#}&-AM^B{Xp6jXYd9HS7Quk=-r?3v!B7Sq( zLAA|#mGa9_+938*w8ktLHbhrT%E$2*cWnWnwoFLDCN|R)8dUF`4;0(IUkuOi$p$^mSNNe%VK#DB-VzWYzATFG=xU%AEIFc}bh-=6$K^~b}` z;p=b6>qsY0)F1i>gf=biI+VQ99}t|Yp*}r`tiCM!FP;N3QDt?R+%K^MOxa!lD~nxM ziS67x?V~0kYu~WfKKh3IMzoS{#}&C_UKm-GO@>+{2iB=!^BMp**{ePpO2j2^E>8Pke{B2Gz5pb(LdEAW->|+j zAxI>xyEk9s#x7ibYIh*T-lmM?Q1&Wp16#gG?L1}{O>lg{kVq+l-Ox~nA)N9T2KGn2`tekcZ}sX;i`0OG3Ha!K;ENX!2e4ugxP#bEcr0Y-oZ!++ri(l2{`(N^vw-{rfb%jxEn*2z!}Yc1In~WU)!sUI3`Mm$ znVOHnwx;MFq+kepr9JEZ#n2&^1aM3pLh`)a`7RBb3-*(Sd?!PBuUx=^HEoO77k_1z zd$#uWQNu}A0FUzl=l5ip-$DeR7ulDQISqmH)4mVf6+(m%CC|Em7_Q{yC6#U?=)J`~ zrVK+m9a37ae_cj?T}yP-Ac!v4xu^_?rjC@H_Zbo&2da+})wY1jLo%k1{D5}y$fxH| zl4aDsb!KW#j{q$2Z)f)JQ;0vT6=k#>c>5d-q@nqGP(f}*dUWxqq>gd^BK99p&7Mg7 zP4>-v7L(Yd7DPl@J}7+8$kQ#$jKL`hfOSiY(#qaM?;o;O-LFHA2k3RX*pT2D9%57}K}M|}O1G;`kW?lkdrP+IU$9|lfp zAsWkJ>^j9)U1zAQz~N7DDsLD^AiCHm3~RM9o$0Q{7+EZ< zRH_gtr4NMd9nO1JaCfOSI9LfhMwS7jpk={YQJr#^RJ#JJ(Crk}JUAHK5%7&uDmTWa zY#%~da6Lm``No-95*4D>ab=@4p0`rAvgNMmnbJ=lx6g9peHFY{Dd_&_`H>{S`P8s} ziYzx~aLigl!=w{4*B;e@6s#!z?iu2J5 zY3$^~Pe#?J0RP!5@|!#_tE!Mvj4yWTzSjprVpV0C7=>)2xZnH?8PQv*k?-d zdbE8rg~DXQ`rB$dh(>MH&@Lddl`JUc<<;t)-JY6qYqIWpAvT*Vme(Oshj}=afXXWs zjd=*JpcFmrkW_A~zN?Asek^5ARwCKTZOugNj!3X5v{?nIl*I}Gh z6)pdh#+X(ERORal=@+V@okX9ZQc-=f^uN-lk^*{MusX--+WY*h&<2|apEO8Bq3(4l z%SR`C?zViDd1X)!wk*Bnnyt*G04FJlP0BK@+_9iXBErAnah2>=shmFWC6g_^HY4v# zaGDr{b$3WTDghs7O2cGp=*yXBlnMhHuFbMcgWfkf=T5d%~TnEqEIVETDRiV07X@+$uDSX=lf?!DtPjn%z3~MDFuJIs|Jf*I5F_ z>B*M>|68@}J(zmfN|fD#%WPv{#|d&;36iaxFsdNy(|6-D4+a>Q$h@}mN*((n>Ssa4 zUhqtBAXGwBt$9;kauwgJ)XHb%rv$;9>_hJ; zO5|_4tLA4XSYm)njQ#V24tQjxm(*et^Ml#UQ0ol$*!h!m|8jl#Mhb8LjM?k{@@2{3PfS9EpY zxnGJ(wsh1pfD_^yr4dhI;t8eN5@kWqmYL zK}z3CB%~wY`;6@I@Evs^X7)qPpAF%RTTspisKL8wW2YFv^)r#*zhE%@9OH@JFrV%W zj8%%PLt{l>w%UnD=lU8S4BWx`^xt!MS~+wVcWrg5@9D#L_wiH#Imf1|_vPBACdm}% z`{uC~m!e?&tdAD4cP=UOmeJ&1abkbZzA1+oUTi`^jjsAZJ{CVl$r@-J3wwOu)WF8< zBl+Wzudg5e*_w%!6zH*&&6A$KeQ1T)sm$qJcxw0k%Zr%bTVZhfxiHk${Owb{&ms4IA0d;7nN~d7Q|YAX^$c9F^|`w9?a@DHU!FCBJ7+d=Qu3vq z)tRWv-p}m}{8)Fdpxvbm*;)Da%j?MXkJ04`2TDkrl}Gml6Lgd^@C)n@FCsHAIHPwr z<_ki2B?8$LsA?5E9%i`ArV6E3x{J8DXLg0EoKz4&+KiX-t5<|?K_zj#`4V;~-QQ=D z9jmJ{Z{XZZdz7=5XSxV8$vLwedpv-Utkp8kb6Zh1W!^1aShadS%h_;cKHJq+eIdsp zQSwuwx)=Y5tqq&Y*WuWxEK$h|N%MK9Z~jKvngIw34u0M!5v0zT6xBzm+F_wM?)S>l zeKJ^Mx#U){!*Xeo>Z9edRKwNfa)zzON=448ODhlZ{U5DV-iugWd00ZzSgoqayR=$e zRr%Wh zBx}RdvSKik=)za}q<8 zjtLUEZQ5F!%%;`Po}Bg*Gn>8Ue_JEFBj6=l)M1AW8Z`V0d-C4&&whR0*?%mS%2%>pTBu}Xj39w55TY--UE05janqN#;KGextA!>5ufD%8y=Kcwr zBGlqN9c1UvbPxx1uFI9$>@dbO`89dyZR{4Owxnam{b;2*;gIozm_v6)6TXeZ%AY~2!UkhF?P79(r2PUq4@pDZoO3iJS?9j%dStn zD`IKn8AX*YnYTSrits$vy}>HBS@X<{+`%ST=+ba<%%+d5O%=g=PX{hm5{h2Pw>!Gmfb2+R z8B24LJM{NTGj2E!%6&CHaak=Z<3^OO{GZ`&q3>Yi)v0p%{rY+HI)%!E10}wZWr*3^ z(hPTjZuHR3L}F8B!HtUJ@;fBELxsH{bJED2{VKW%^!Tgie&u)e*>sByFGTyjABE$C zs?3;SD$Z9?;yIvO+miD73Ecjo1Dk-`q9C*@08$4*5cF}pKy#H! zY$isDC%Uc)YvSby%5D$EdgHa;?-a~tF?fRKtxBUOQqYs!s3NQ|`1%{j(c(tBzR7jLsave+AhhGE!CyQEdwl!T;s&iGbV|;nIw|f>V*qFbHxg`8hu`%4 ztZvdM%81b~IN1R}e(Qx8Yvp`cH2L$qAtqk53eP9gOB6`N+2A6*QqU#2SEOnvhgX3a zcFG;HTc{rMC<4#rh%k8_wRdL$*;mf;k? zWT1tteSCn0X0@$LAu=X^HbBRN@3@s4Rgv5wyNk0E=V{_`UxP>xy}Qgd71G4;s~~3+g7Au`P&}qXZ!(3xhyT-qN9b1F+f2|fn+diU??n6S2omEcP$KBNdlUdl8J`u{ zAlm6|Q{eC%D|vQO$J+edfdS0K( z&1gmXh&4VsJ#@)-Xsy?xo<}x+%~$QI{k3y$bPGml5+^1>N&M9!mn+SLIcC2J7@D=b z+T7ru(6n2BC2vJT*Tnhx%0}oMZhq@Yn_F&cHKas)q-!xaYx1`VE zF0l|IsK8-guWx{kt8EBIl_;Tm^C9;KB)oJpIaBlUgy^QZsrxP@ee4U=^Z`dXOvZi)zMG=6*i=0;W0h398d2x`Bxxtkw2`Jt*y@D?4^BNZU@ zqIOSF6qAYtQf|~ql6i1sYXToZ2+B3;FDpm*KIC<;j}4$JxBfzGV~~*)9u}Dkmm;SC zlKqkHfKVS4nsFQ`BPj zwYRhIT>z46iWMe;CWhq;T|s6H2>Kx+oWY~R;E5VWD4evw0uWpT@D84*!4LeV6n@)^ z?CU}E_YgI&hrD(byj#y_FT{HsKw*~|zyIO&pBv)bCU%=F#lOfa9~e3CTMy3=7~txG zcj||8{U|Dx{s$}akviXVP1*|fBL`Ls5d1=x`bL&q zsYv`qM!aGQv@;OL9=LZ5%YVbeYU%}aT9BVyPX_GVW};FL5%{uLWL*p&5~pXNM;Dbm zGr>e24BwvHLS$zeaRgY{TmF&j!`wS$q3MeFS8tykhJ3H=WV}Q#0w6_|P#huD;no|n zK1dGU1Xlw6U61VD)VsdzIKoC!Ps!`x1=4&40%yFkC`e`wH}(Pfizb94^Jg0B?9?N< z*5EEl7vjZ;2ReQmM{v9FFj83x4t%FecrU2f>6af8&KI6NiC7@vU0iu5T@hbMM>qi9 z7!1Kp*yQvue31-0)+BjBA7Sm8Gd~QMnB$F~hc6E!xaRMKD7EAm)hz zhd&t!gRDR5XJoT&(mDbzVc|h0x4tIiWBw1c}l|M(xyR?G%20+xP zWO2w+`F{526Lv3!`-+6;3rX^skUxbKfk4V1gbNq)UY;nB9yR@SU6JdH5dqK?A*er~ zK&r#^9!m1%oR4XKz8Qe~Xj#9c9}-YgL+JRaYxLB)d#3OVXxH+ACm{An^x9}ViGZxhi6I+ z+(jK2@MTx{vz0QH6iisW$V)Fv58qOw{tDwWq80)b)-x4mj<#~TV-`Nw4KJXg!3zKG=#e&@N^CD+h_J1CxqM)g0n?Ibt#BQ zL6LKr=l+&Z^&1-GVxO9J#H}-td$|p%PZh;Yo-UD9bcm<_)C)ZG1WmJ%W0#tbOElR$ zZB+Yv7-)Fyp~=&~m@BHnj6be!tu-P#7`S9LbiIL_fDHdtFJ-8MUtu5@NcBG(z5hGg zX6WX8rRTZ!dxa4ad~6tAbywix?d(w!e3T8}A|jnUM0M(YehA50X7WsM8DW6KVPQ~x zee>3Ko2DCYIN-{(5EI7~l!(quGtKw}aORx7&CoYRoECca@C@Hu46-N(L8d0$Xt2kv zA%`}bRWn^ihn?<+djxBU=-}a2Q4e%g5W7UgTbUO{^H_c1c7>L5qmH

>tRgFHDW1XS(?mW3&`O%Cp~Lh?_G$9icFG68FW(6#6Xe!AC$Ctlq8c(%>3tJ>s4 z4fLgUxZQk-h#nQPjd>h3dAQ>+o2o-heng8g%s-wfE* z$l;s0f!wvBHAw-oY4dm4Jh5!}RwI0QS;GYZio=29NFZPL8=E-sy&4C4Ubo<)MgQr; z8<{Wq$spmAV6_=cB!(9&bdAfJ&W3`-_snRx&1f2(j~xI$1;c+)VTm;04d(ebOn|6A zs>e9DuiZO#6Bfr19@XA+Y3``z9**4UyW1aR5Lrir`7FR+h{hE~iA;f+v#qu&7Z$hgSG=8U8Mw3!D0Z4hD~?O{@qz(^s2uE9ge z$hU8u`yvramzWwngfh+NvzO#0>tMLkBVz;VyTt{A70kY#uSeq$(6^)FTgD-vHetK> zu&*^RqnSznrG77<QTUeoft%%TAwqY=xa_cP>i4I@gdYe9SqK!@3dQ$9Q{202gRKQElz&Pr zp3BWWGnsQC&OJAFpfbUiR!@952u={#qIr&)_s)=nK!wpT<2gyAwfwAcNOC?nVz5%p z?&Ks-=`%ZmM1}0`Yx{9b^b+Y;0w3oy)B1}lgmD^bGnx7d=t2Sy!Y6U!q3SU4uLZ}N z<_VB{UFTgkc#yxfpwVb2QPYz-Lh#xU$>alKa|ptsg$W-EA0+ZbpThqkAm-*tAgPPr zW^mT^56+Y;dP@OIh*3WG{P%kv)f{>M^$k`bzcaa9Y_<%G&Kwo5#;aJd!kFT;!g_Q(+qoxG$*ODso%kPF z=V8LX#&o%5qCdFuVsv-YD@v!Ou4vRxvQw_QcMkq~(!!&fYRg+)^^TVen+8xR|NPDq z?Ij(!<(K<8&jojU?%=i;3Ax zOzJka-r&rmWB&1{$$Jvl6}3+w8D;gZlm%A0D`o1N2>2Fna9;6Ev_+Wed9nC>u)rYy zcH-hpMObBvO%^~g>8V6^Y1=rJT&U&azT^<$%?1=1ux#d4;w!V#rEh0Ne~3_7CWYN1 zdxx)TJV(Yr+WV3-&s4_0yOdt8!Kabi6V}h@ppzzyhRjXICezJ+F6aJ2pUa}UjYX)x zYVWcAE@dRH`a1KWYv1|Ux(5qQx&!EhmOt;zu?MRM9uMwSIy$u>ytx}QN>I2QJ9c>g z-`H{60en%olSV{kT$ORk>F+IoT{QPS&7t|Kcl6iBP!EO?Dp|-<4D49B`Fv9Ttw26i zY~G#!a%qmA=~P+rV^CXENA?{-<=P78GWr5?8kG^zGw@d>@}Hkhj$Q?iQxd-!Yo>H* z4qscXKHk9pLJ9a0@>2-x>m3bEY5}@kNKUgg8duWkqbe+B3>0$1aubCXG52md10|)3|l~)Ra_Bta2WV)3CtC}9UG+QMgFo1n)@Y7(X@HvYw6$;4e^Ss=WHYF) z6D?>%O4rr@qVE!K@KRLeBZRJ=l)A;E=L89^0; z834KKRTcObDd?B4hL0~49PnkD#L3i#JM2kt&k6OaZagfE)CFXd1j);0;z7SVp~}U# z)dd(JUHcWOy;MjTG1BIIVU;aY8jY_TQS(9zOX+1(0SG=L!aYPuY`^QEx=jPW2NTtn z6SA5t<+H8hN@Zr$tEb44JMA&?9tJu*HnhgKanJIqv@MmRag5vRy1DAzDO?5H>yoV0 z{X)jSObro{<|ai#fNY5~(o|>rfDhzuLy5LTw0NH%_}Kf$j$m*sMs(kGS`JZ=%2^Rf zmO)NuhiF#IxMg^u?5bE+UO!a_v1vWURTEmFYZ3|D5#{oK47gX0>ETNIOm2`RpS;#@ z+cTEpy2VbLs04{oebYkr9u}mn*%gMug!6#&Z+>d(G;ZnHV?qFLy;1>?lTVVJC_;2M zNRT3ja!_gtD`wVNbeqO(JZ*L8<9BTuEb)td>^RT6^J$#6$Id_$|7zDmP0e)JN)jBl zE|h)kP7l;U*GK`;;`8Z+F@(k@xMfQ|)7R8_iY<%M%>Wz=Ocm@}pE#89?Io!+mDMnD z1deFJWrdh(D0UD<_T8msk_>~8#SKds`CTc6e2Q(H?PB~zW#HqJ$GQlC`3T-e(=va6OsReCo{y@4Y{O9)Z8IM@I`;!GjuSxaAm{PPnI8HckbQT1CK+{)s~6(|GLHo z|8kjG(eoemL&nT9PTfEHX<-|mFj97B=(PKp1>%p6v0r$zIx_QH*g%`uc7-2O%{Z05HM9C2mebB|_Hh>HPN_38!sra`JvTgu}wh=L6=g z=P!+1{kTg+CNbuvcQc`12=zSj+>=H_7?&rPV5Z8ZNr* zrx*KlPOfE#CC!>B7213ys1^;R+q82;^Q`~*bi7NNx8;BRmllLBeD7qpvX&Pd{BNT< z?DEnHe!@K+7AS@Ke4ijm>zm}h)jV&re3}1e1i%t2ZgnszFMxOnsmHLxu548BlNP`k zU^AxOmfvoopTns?AH(v?o6m)JkyGT#y^ zRjF==i~}3mQ~qwiReWi^z~+W~xe$TP7-c0S#0WpDCmPE>sp zG5ju4z3y}YIh-!Y>yHdR118}tZ`=o%qLl9AwQ_n!dLL`V0vlcc-xgitS>bDayZ&*X zh5~!GG63Nd>6c1HbPr~jU((VLL7;JIVXdNuo^a#t3_RA(-??Y6>>bIL-ff1QxE0dR z_h~jaqqmz&JjIZ*sh@$Fjs%T(HubH#zVKwgQDZT zE4=^}%E2<@G&-LCXvx$r7OE1E|E0^;3TX~eK^>XvR7XC4DE9pKf&+53Pp$#)8L-dG zm9UeMsgfw-DqEqB6Lr)SJ=S7{#yIf#*|dif@V&+M3n{lpj0@;4QdUWZCxuf2?q{fH z08ADHg-itBoadW}q9kPcS!-RZ@bsi@P{?k+>;nA?5o}uY+{#q_GFzaJri69lDa8j5 z#KQf=GtYCuaa7f<1{!e!oY-3PMp*bKS+0>nEqh{j7C$5ts>?63M#AgG$Ploc!1*S z)Z&+>uU-&*?}gB}=Xk0M!b?I$45;$hB@6>{?3BA&Js8?K80Jhr+$pT;m7mg?N@R;j zeuPuY(sQxUEQ!o>qv`z16y>gLnoB7?f=c)If(J7}!Q8`tGH`3_j^9(d3i{wO_yQjY zLC2R9ic2T@7GJ87h-F^C*g}w3Q>ksb3F=B8c7Y>TZzN3I8gl`hodCxoxs5qiDF>Y` zq)`&7UB4M}DvVUhHuCzx3^$Bi?-DnEJe|?~>L-tOSSbA*yFGomA}n0lv<0rxkQ_z@ zHwzWzvuQ-<8;OWlm`B|~#l>z!wZUwLz+5|HADOltTTw63VvS`2`AiVF0J-Ss#RNo@a84S`> z_~m=#=K}g;-;qyKhc2}MJc!^pF|f=bcn{gxU;Ir|P0yP{`F=FOX#us1y;aas7!o14 zbP*2s1;=&fz1;QOa;BYG1z%tf`=#D2?q&TH5l4!NCWMrEv0~PP0g|B{_Y9S_nCoFDFm}zlk_mJ&4k9)|z>78%w;jFoxgq_?rRX zTQfBaJHdgi8a>AK2hP8J_$E747jJn;cz9bT77La*E`Ad8J|!98L3&$=bKfPp%g4F9 zqAD1rphG9>yPxQjj`!OkB4N=s~Wi)zJ z^99l5Yudo0_(r#cA2zXsvO!mL%K|qiKB^ZZ zNon;|k2GVpy$eoELfk(bJaq}I4k!x3rx{GY(VsZsM@>&efbX>GB9g%x#dQo-KEZqwGpBGZ@ ztnL_61Q@{p7gE3rwLZ|l4uasEjqhuD2N!7-Q}Ni`AKx>6{O#k{E<;|fD(r3(K!@g`JP7(z%`~usZ``*_)Xc&hx!HJBp&GE)*B=S zU_&V*QvLq?Es+A5+Zf^4*xa%y^YS!;!Ri}&ptlra!>4Rf(6p+Bd&3kY=M{C%r zQ^j8>HG~Ng(3V~njsK=aPlnU4*Mj`T=;Vderx$>yc%tFXH^X_N4)0Q%#cRl|qGpV= z2p;IPF9<@$dTggh@<3-wL4nu|twI?;i_$cv4=$FTlmT|3+!nlPo?d{=uE}8*Qe}ZD zq*D5sPI@pq8R)kO8f|LDfF2FQ<5xI!){)&@D&N#8`=if$E^ z?D(W^PY-z{q6N*A6$4*(PS2EgO9Q0N27sial>~%D$(qJ|u#E@Y+f1>vA~( znPu;iOp))+bPOa*j_} ziwaUGh@5>-WjRCyRG8(UD3TpUTs*@RHe(70R4@&WXP5S#(LjKRtv@$m`HjKLoMBYl!Jj#S3lv)dSgBPcgOD4?%6*ufuhX8BvL07hu@Jf} zW1Bxn?ZN17ow)Z-D18cSw3Lgx4m!jm&ejR>a3lOz5SNw=4j_CMu>)lgbGOhM>5X8= zAqbiXO6doOeg~&%<;pAwuhL``&Fc~>KJfz%6#S2fYq_zFxhdi9#~q~=$~;T0?(3|B zE)0Q<_HSKq$;As4Uen68So(2=sI03WVRvq);n~RA9ZFcgTMG(KRH*RHD<;P6{a`tCQtkb|0aWGW;cD$J@_Cu zHr!jNw-$-au{is4Ar+jl3|eiZ@ItxZJ(qx)~ehJE1tbw@M@|h()nzFW#Z~osIHfIpK<%z;`p-@ zMb5U!uFYZ25BOBu#og5bj*o2a?d09r?2q-|&~9;#wVB0$uVK#<6Y*Zv3RGX~3tc2D zn3zn?{tG<67kM!Isb?vBllfvx@X)pjQ2q?{aPdd;|nrMj!VhCI9GO09DOHELN7y7pH80QeQ)jFG_x-l7?}+vVF0Y z(iP^E2)?AI1z$82o%4cg%vT zcgDjqVy}m)qBwaOZuXgZYt$l8+UZi(4t?v0#a5bDiN>)_fqqNJ+EJJ}X8~ArSJa-_n&iN=E_)c5#sj22x+8ddrw|PfdX97`cJd+Ie71{<{URQ1L^TUy5{k>c6RB+TwzI})lY`!H zv)OIFe{W@gx!Y^8y4tR4iMl7HmEXLFLiPukVs3b^7_g%9+)TB)25 zVPa5iI#zUs+%MBFCyO;uL8(Q8>K_JF3vyAW!oc!D5^mK!i%n z_0!V2d~ph>*ve1r{hTvG(V-wDL!Nl00&k$MYem}XqL|@ZZd`8egvUYuWuc{ zbKY%tm1!Nj3bbjt?rOO?Q>0smEqu=BNnIo^3;fLuyRV$97{tspsGe6GAyj$?k$KR5 zeye=f5LI!VAZ!>&#l3B`gG9uNCbl~`>`i{Igvixz{-v7j5JAXTT2@y38>d!7d(0FG zoG?GB|KmJBCsFpGV3|b~quASAfq;=lgGos#w$5*{w~p zm>q)OG1Abb3lpj+5)lALw!qV>Z&8-f0njc_g*=PEQ;fM{k1~4Bbsi?<LDIHf_@WXoBx1E6Y<>ypB}o7(Z7_$v__<|nzN0_o7irtFm?7s_T;rcG zjDf4P9kz##^7Jn~>{NyL+$#Xaw+pH&8a^+o-BOAfgX?&4rO_3E1E0)8cRmqIlEQ17 z{}#DPNM{$zUo8=OJ5-Ey?eR}ownx9_nTW)Fq#({OU&E^PJDpXNzp66-L#bjs#Kn&c z%he7N)_p@&+ZLez>E@z-BXd2p(AH6&4^24}E%V6$PoKKGAO=^(D6vVd0XeFelnQ}n z4l9Jv=$^U+j^o>zBWJuqgv-Kn-M2mK&Je%XU#WEwt|7P+PM+2I?KNi6A$sLv*Qnwk zmJ+Z$rXX>p=N6C7k@Ti9(jJM4#1mZ1GfqfK$J*z;`qc+{GQ+g0(-GAkTC$WjlxUd0 z_TTUH&j%ajwIwVl;4-ehiNS@&uQT}DdiVQvmd};^uSYFRh;!?G;AqjO6E0-@s`cyW zl4xv#HXeJ^OG&ncm7n&X?4m7id7P1>kXMN;`7*(nVqQ9}B`9ppqJZj@*)0lL;L!Vh zxNWB3-^`Hkg^9iroN`G*mnz1e3AEfEhR)F|!M-dL(urx4l=#fE3TJaTAmu5V^E4U1 zoMn<%Duk5YfTWk?ycz)YU+}*LG97y0;m}zcMyG=oSzjRp@x}zc%p6uRX|-Ki^6_Jx zBGVjA-vpGzvolfsOam`F5#XWMFQlcK4IIlzIU#tCWRRw%QL0<+*Teyr62kUqVfU1J zm86<0o?3GtEj7HEJ3U^e;ak&MaU(B zaKbq2wXm!k6fJKhBxp<#hBkTOkVC!tG6(|bthznhr|N5RX`oBL8Zwvr2YL+vz-slF zgtI0}YYzOe$N2zo8)UPlV^PuoWY)VJELGi~%`=yTEEe8)cHENe<6;4@n76keQySYn z>kb2HL^ny&@ynhL%KPwWQSjj^?;%=f7uEESy^gs3 z;uMc+mR5axO4_jzV7A?F*~AHM1nQ0vpX4z*Qy^W_(&Nli4?RiAe}L*)uCJpHb7LvB zmw*cO)rvl)rv2A3<)S8!2rV-}`zu+XT6>8ec{uI=^+}=~`!Eo<{P|xIC+H+Z!*}qX z6}3EN%A*I}*)HbyloJ{P)UC5KsIZR=3HGk$GO_>%+MTU>j=b2jOVf57HI#8Afd0J; zeg&l}Zn7-6S30|DeTCto6##84(A3}Fw3=$o1WpbTj(wo+zZ87WlMi3oORjg@L{TkX zbFc<>_qZTeGGOK@S~G#uK%a&{fmK5uKLyyPL&4TJ?9GQ>Vrm6c`@4;aJdSCI{Sg;? z_ta0;#G2T1li?ri4SGJDqyXV8ys1^c?aYK7#okz)W2`rCT@HNNgSOiCgK^0R_Ba;U z5ic%T1xU79)Sb_YVWCwy8D~_0hW=oI}Y)PiZ~cM=QNTfJU~U5$Ue9s*oGW(jxoN&l@xS zV+WQwxNw3ik?KC-U|G&F8e>b!1V>e1r6`pBrPKoj!q{Ij=2lfPO=WG_s5$G`pZTB1 zx=h8ZXzgTfok*Y+67E>XI{;RRKpjF`x^B6>*8JSs0yX5|FFZkG( z{RFXM+XZeW@)D6PEgo-gLkHe}i!wR1PXp z36rE{3Dwevz75ow@7WJcD0@R80h@C_C@r-Pbp6>QT_jaw8~ zHFq*#;dkpeHvBlwq>{!5m^gXP+JyS*1zEd%uC@Q9$IMM~1rZ8}} zZ4Rqz-XE|O5`?e&*Xv{OFRMG}hfKJftBKmFTpq`W<&}Rr1c;BTuJv-#n%kjw>vM}#yz>T*lLgZrYB}4DoFh5@k8!tHjO_z9V6piKzDc00gIobhti-a@V3OD`-~G7?4; z6b=1q6Algwx>>%Hd-^UV*NWPyb>fUl5KPNX<_-|ks2(L5J**Jz9fCMO1_r0ukLGYp zSdF^fWQDPyx+wV@8B#Cz(XC9l=bU(0D;H4Bq+MLbp^HwZk^V%9CPDL_BQ_I?mUZ2< zf~;kUdf-~%rzRhoC-)Gg;`R{Trka|4pL}5!koGG_d+0QH+`hsORkhk+yS;SrSCKjk zDEBO?(P>GBz%ctmm7ei}!!ms#_1^}mrs6$@a0E1MncnXta;zFxL16p^joZC=j*Tc- zp;*l;=TEpDAyPl-ROiMj7F|_PdDEw|67C`ZkQ3sV3yge={*YlKEcC6i^re@v`si1^ zFB;k?xdB1ZCc9F!I_}sPrA&Zfp1nmm(4w3g$~QjAJ)+0mV9f5|9!B+j7S_kpqE53q zsIa>Cqc_P{Mkbf&^YP#^uVKQ+=bk`>>|G$?m%MKUTlnrGQxM>ZWUKVqZD39h_hZL-R7TJ0IX9XJNG#>O17wLe32`95oZAOr>R=Tv52 z4>DS`GGBDj;!Qa|>qiFnF+#%}Oz}IMgcbdCZBb}{ZFyKQUGbZd@mAz{ zmFbb_>Lc0yD{NyL?MNNau)?;J@-a3h`hCVyQrb5mP|aM%D@ZJGC|rF15fx}VMFUH< zn3(!4d2{Pnw>l|PO?oKl*I@1w;2+tS7B>C+rayiL#avkA2Kil8`V=_$Za-1RB~ve+^N@UoJ%J1?mb%VCZMF#+F)Xmu7-Wl8^rELMT$;jER~8e;i_Bw1UN%XpJz2V?(NK7U~FF@a0Z z51DNH-29V&_yN$Pq59C*gldhsYP%QV5zfHHGlEM#o=-yQ^$})G{d!B(16UdJ<5wB8 zFt8jTo!qDwYvTN{yXI+-r2WI?QvaXpEY4LRglKVROJ1`N=dmNBJX`k)`vL@@5rF0eEG}oZ2B+l zKLx?UsJJew0!^?djAN55rl=cA+A#dN*W#n-{$I1h-{D_0XaI{T*=OTRuoOf@s18k^V??{kdJIZpM^K%nExH}*PK^{v)U z2hwH|3kzRI)YH-D2_o=-+?n&!tJaVF?YCCXtJ?|$?j+$fV8!zJ6+47>ep!fS>=LmPSz`cPDeg6hQXy(ll}VS5i(At?(U;DAQG zdzG@;{%iY-IAwOBrF68^NlJ3>cRk^thyO&+OlrB}6E;D`idLD5S+t%^fcbWLUvxrg z>f@^hb8f>a5iC4sYN*TtnBJODyX$9uK` zvHf(Z@?UqnGw&K}`v@33&l++$lMsAxP0)Gwxqx>vPri78WBkVtGv;7QOocAzTLc6t zY~gP$qi;tF{QQ&q=hr!pGlJTIRHIv@=*|_NCcM^m|3SjgQck%dvHKv=E-+gNswQP6 zVDd;AY!n>gY2wW>ukpH6XH#L%CLOs){Bd{co?<;YCpBsE{`q7xq9mCIw261Iz!Iz~ zfEKIvw;zAKfC@-M^`w3NIs|qc$pwZ1056v8$sR_Ok{)%l)sxY!nVscdU2f5qy)B7( zv6^7f-;LlEj*YqLohsbj&mUa!lJyFOK85%FhmX1Q=82OWfNF ze9-#m=P}lJaQ%(@f^w#j$Lh!`=HP3C&TTXQIt7GooSlu@h&?aPV@N4}+AS@ltSgCI ze_zp8rBK1e(#zY~_cjpo|EYwHP2W3R@}5I8jr!1;yQ)$mUGiyR?y5=%G-Pjb22f_8 zMmzU|d$L1>nrnVpTcVff`(1G~%e^2=`)To;f=h#HOSA9E#RPP@n%m)iUSm3GUf>a} zts3`8mt5D@o>lqG8F#DszP{eo1_e1FNAh&s43BEGrLCr^2-SwwJWJgPVf=&sB0-{l zOQ6*}Ix@1EM-{uq##0xbpOVVibB}&CSm6nuEaw-d+@2OYqNqg*wyN@=i?; zsnCTa{TeyTBj`w$OVC|GsZOYf)nv=*>f~i*;U*eBIO@iQJPMy{6$o6qk!;tp)=DLd zfN!R5Ue|DVQr2?%hWi`)2MTFZo>^eg=q^KhO}|);n@MTi68*GTk=(|AMk?&e3#+am z4l-}RS@B~skzJIq7I>OPOKuOl8OKUq>y=Kfb3sY}bJbKVcrGcKi!2~G-;5ej5v!Bw z75X5=$gw865PL0Iv|OtEb_<=*9%+-g?=d52Ox ziMumpXE`Y$bGEI2`ef4{9Ri8ty*y7_hagV^u3uaQEJ;{z6V%YMmH-nI;`3)C@Sc5# zW((rBwHpdlAZw;KV++VgEoArb5<2>5c)hb##3ewrEG)1vp+NCJRfAT%3^k23b2Y9a}k2fldQ<%UTy2pl(m4wc+!Bt4LG>@8# z%Xh#;eQu8RvEH_m7AqT=3A|dsX9ci&JSZ=)Yff>ARdx1m zmSw8+5?<639>-6XBWX(*viN78f2B3w&_ZAiW{)D`;F z1sHkJQ1HQWSGx7kuqb{RAiu*~23xRHTK2N@3^bH$Z^UNVIr=QySscHlP#cN}A@;?p zNP-L33}JhJZ}Cq|D=Z8E7AI(7m_WSj3wZ0T<_`}}nNGM`kF^wBbzM_C9K<-eQd+cj zCKKJw9znN_-QGW=1$r`3ZB3#AZ%7 zfnCpH6@kEF6;CQIw$I|-hdeN4&)q_+#n7?e@K_z8%uJdAK9m(~{=H({t@+A*e5jKm z=Ui^Pnlvy%{5zUmk;T)ObVVek3xTg{g;|n@^9g*Gv7Xt((mL*07$AL1{@XRFdpXcJ zriv)Sn3!ko=B)Xr*KL>XY_;f#@J{P7gLsX&Eg6>lVH$+~?CP`He0n1xd{e0)7VNSN zKqRMWDlOrc`s{|`4L3M2r;jJKbR5jf?0N#3=B^i@AnLj8Idt5V!a;6nuEGpnYNI{Z z75&IBm1U=Hn&)J5fHOMS4^;YMF0V0`T2lLFPKkb(z1hQNJi(&u3>lD3-oce=j-rEI8o zdQNGR4ld8(0U3E?jB}qA-ng!omc*phfg0N<+>25r=YlTRx$Ag#{ySH4-apX8oeVHa z{Pi%Oq5*2v^0djJeCQ4XDeaMUdF~Opaa@k#pg^!4h^Vrn)f~O9zhbF)!v74Z-z=Ux zbTBWj_xEiq>Q6X0+;Kj~`P^NS0kYR-u~bglsM|poJ#gWOO38O=GZgvd;Zt83A3Gbj zPtMQATF(xDPGt(3X6qAkBE$=3=5NU(@6HBE2iEF^iHL+D!8U7wMZq#qky-4g{5M3I zgrRqSfByPat34jZX*4y>t;mV5FyUGkkV^Wu;kS|v^8Y#YI;=CDE!}rZHnur2lVyZV zED^zTyOizx(*R7Atn-_JFP%8hG6m@xMkG{2K|K@B^jEpTT*HYgYEhUN+E$TKoMG&+i(PLd^?Akr)34$1r@|+)%ASW>ceW?py@R7i$1V{>+x|&`MDx6cPRHM%n6yC#S1R} znC^@-d5ZL@zV%o*4UB_q%GWvG!oYQOOj|dKV+o$hW^YqG-<}g)n?jt+OaF29zZp1K zMqKf$OU;=GlW4hl?4NR5|)re<;6> z>rm`czByhPSNwAJy!b85D!$!iieB9F5V%>I1U?|}0vOb!x}=u~HXp<5zw-}7txuq> z7td`kH7%lD69k`~(yYZ*b1=(v&ZCAhLZ^M+#qZjEyUb(EcUhb}-`2A!=folLU8*;U zXZuXM1?s6?eQ5VkFv~cPCgU=PadY$w&kU6GVV%_}P3yyj$BQdMGcmk1TJ}mZ9ekEp z!+&7tGf|Y6CDz?q-@t;6rdo;zLi`YS;qk;MOc^_;yRi-*tk%!QjPZG77rWPpzf)}4 z*SexC`ny#Is?jcpOh)Cr#Dwb`CbJ}8Q~t{dzCB4nt>%;9f}pa%Me@q2Sgu6B^3tL$ zCes!(#fZ~;u>Ls^j&>=p1G;}CsqOaLW;Y3Z0GQi zC-fL=lK{-NfM765yn}*SZN~IakZyV}`088TTgZuFG?6x)SSoj6SS~uGH^8}Y{aeO) zHIk$tc#I_-0+6)>h~LEu3Kzo(6nRTq1YM$GtvkdHAWKjdj}fW9OA>dPQ6f>Kn{%1x z)heqs3}yQ;o3FB1?wx^D* zosO!cT8s!(5g%tMu%zetd5W&PNaV*<%0EeD3K_l0j=_Q~@URWTTcx_W{W-(>y1^c^Mg+K^0-Fno3Gv{g zZi51blAQhavk<|DPTN>%kvJIxwx;s>DR_|C5B}hqE+P=9YsuC$^>!H(kRmF}fC8ic z3_JZA)}i(o&K$Ai+1nYumr}8xwaWLl;tBh@H87^gCJ9?kBgO}hZYgaJ>qHu9nH#I= zju@1v6Z(x^q@{HDTOwDAe9bwt>>j9Ipo||yVpGFr#v2E`z0Y`ChmD1955qQD(DK{% z8NEgyybUjwI-VGFG>+&cht$=!?8J<`yzu}O#0nTORJf@MTIOU(ukBN02V}(S<0MCi z8bQl-s#3J?d0(X;VK+$dP*jTcUZWTXCWqjn#=O^su$N2(9B zh53>R+D`Pv_MvDkmq*ernWtSHN8Q`X@#H#?9|JR@jPS!6xR4wdXMPX4g!dOdp-C^C zmnOX4*5N&jFK+cABy$h##P`LxI4{_ph^3?U_`n_gk)V{x6B8Fn)y_)kqKrq(@N%y^ zPK2&__k~TYo~dI@&yw1^K^#MISGg}De#K8lYgM{(&C%q$w0AJ~`XyiYFH}r|X;4)B z(XAIgrS_jP$}wLDeU6x(?VWYL{J56+sCE;pB%(2xSVx;e>)r3XsWXD?)rNQ(-Oc&rv=7PdF1$Bu(aY#JHVo~}T{NGvB>qB8% z>RmjquL@&W2TQhFT8KU$)ElRutD{c?!aO;ro@*1xhNHKvIo$4Ep{wy1Fp(XpJYDAL6nQprH*K)CL?5Ciy=oGxf znC;*iK#3c;F?+zaYxUjn;S-x|6uodChZH)ud-zA9t@hE7dsv5$vT-NNZ$&+dvp>rJ zK_gS}k}G-}lQTgTm*P*nPdJrC+h&9uldd%Xq0`_L#FYi_n^A+p(Kxon^b?Q)o8S0- zo6A7eu3%+a5+daiPf1tKZ>A(|#5KH6eIR#1`!0y6j5)q?VtEE5eVr3bl6gUe3Gr!$N1VSV`aknKAdD<*Njh*_CVn*en%-XRc>AeG z=9eBEExvO!|Gs(g)?V;5v4lq~`558~zJBb(eSBlwDSVsAI#;3H7Nz(U#ly|0Q3S-9 zfhfgesE(QMnL;9d3{<z ztjhB8XrcQZGYVD`$RjCzi53K>Acb}cDn7L0yZProiKIW~b;R(j3>b)nO}=@(!rH7L z?kK7KdTr~6x;Q`i6FM44?P@Bd4 z2)vj&dHw8mqx1Fh|3>6lGfI_gt+Vrgo-3mvvy8VNZ1k+MQl2fHYKQ1%pnGS~ z8hx^$s>vqCO$^TWzhCp4$6G%n)lSQR6d9&Chi`C6ktTr7Hif}^s@Tk^`zZ{rWve@M z-hA(-(BEFp76m6$Otu5j(5CWqoEr0%GxOV}orPA5V~Cv8XW{W=cE>$R=e_rtC~hi7 zk>dP2AGOO?6j-~fTP0WXGcMtG!?O?fhC8mZKhmfl6L{w;yHrnfji%<7=15#LP(0p( zT3y0dn-P|)oTTQ1BystXNgijHuigt$5~?y=5(I6NMrAEslF9VmK>0Og-@`MkeVBs`~bhb$cMX+xBSv8+?RZmvG*|=n2zhG1mutho+yuB(jxf zD00~BqL!O;xrw30dh zXKX*%3LZA1tklcqgCS5OATJFI$1At zcDefPwcV^p`iNMah*iz;_9m2jkm5KX&BE$fJzMR$i{7Otc6TW)VB#@<75PWq$FAC% zXBzcByf5WeYce^b7~AzrBQ@F&4@~`oNvqNc;=a?Kwx&scz9aQH6hl~_HXdpmu^0NF ze|kqUU6?=~$9N53oTlWbhmX=9#l*X<{(z`h8(hPHV){p|F^8{C2SkuQc)zd~**P4^ z4f;+&uWn5TV^Q6&JL7+5-FuH5{gcnjei*5g(K%e*9h}yG?WbF)cYfTp6WLN<-cNO2 z`Q=+Qsej?d^6-hb`8G?hQon5YcRqOj_F!UkELpXiGOQ~Dtz;`0@cW3B(f!Kk8*JG4 zK4~T!)o=UlDMhXsJO7R=Uk^aVe^sgtRJf~*j6dSAZ$^P-yY}CVLf6*}S?Np3zk7|U(%!`B!JvvR&IKsIKt5U>TKY;P`{OBiE1?|~$q)dmpwbq(+NCUSe#g{Ef?lT5$E>CE+2-WWdfZnewb@kTd#0c->RCULC9#W%qQ>NT-OEOP?N)j zyrHkebKPLBKAy!k^Tb-V(a)}1xxQ$&K(WoT^oFnG(dvf?Gi|!lap=8?Ee{55d9WZ`0@%g|FMA#VD%^hWo(#j#I+KfVe6t0yrzr#Hg$Eu8?paxvouxzR~N9*^2L{j9-5}m-`J+2N~-(87cJDO zgH~2v;}&5q9pc1OFJfUfTk*5LLA4TL$2%He^=nnJ&vh3<3KABZ3o0JhPj>!@Sp0r^ zOK@smCl42PyyDz54f)WG%?q`mV*9ISd!&y>ZM|xL$ z0|3=*kRQG_8hsR3VqIRoSE9dMaoIg-r6LZFn=toOgwDqP7&ICn&z-dJm$pTw@6Noh zAo8cPq~q?=Gp{Wcc;#Df{9?{O>NcL5e)#6VSh@XM>y@lP40LF3#r?pm@U3F&9hQA< zeo#=_IgTOAtHip8wJsyRgzOWxKN|b+u%vmDKpoBDU$9!4TX#?0Wdi7uoOsHk%O1G2 zutIm6Z}X+-?#qCUJo6fsfDj_`iR*i|V*np`{hp?J#B6=a{_PFn8GOF=E)#gf=xvj6 zyFN0kF$eb}PpZWFTjN7_<3T~u5*2M16%XsJidOzvl>22nkJ)m2IBwftJ}M`y{O~{X zcTwJ(2M1!CW+9V%&elDYM=?EfN-G5FXnC;Ms-uhIR|5D;vO&`Y{+;I}^RrdQxneeB zRmpta$!6Rzk7qE%hCv=(_fHlOIa!mf{LAx5&qVfv=Nsy$);f+p+chVE`k?{Xi`&}&zhPb5r3Ut=p5fD&=?`cNcsttyrU`(-2*^z5+z^CMMRSE z{_TPB zhVk7p%>qK_*ZYs49faTOwdMwjqQmptzp;d%e&SUBFK5oW9frz!`eYrS zY`r?p_>B9fTzqzhE4jhSH6}47_ig)n~mAw0x|E^;z7SU9)x zliU|Wm>C%W_1$ykt|y9`O$ICOiGU71INHwinSod>3-x;${&z9FKjZnH8dOiB>#Wb4 zTPr>4g?CA=@nnjS7P4wxgVDV}d!YE$;Ds%lRSKEp$SSNmTCbHBNek8Ly(a!b2;fUVkK*Pi3`*vf?boO89$nY#wLltVdzfA3cG z{BmHK=rz}s>av9DnX0og_s{4DsfAj+>Q>lgroXGb>$lKyU%=MYRja$Qdq&121BT{B z>Y__uknGy7c|DSKT)z?}F5RaXIyP81_oCO$!!!#~X0#Mg1&oh}vq=2I6c>IQU>4c9O) za}2NWlMGh%sd#l!?ecj&Hpsc4DpQ7qmlc2ElyUdWQO$Nk#hnRv>)95Fq}rwbZdu&7 zjmUj-k<93vg4x@(nC1aBWI7DRL#+!9L{89aMfzS#;C5SJWH%3t{q3ApmB^ag9dnA$ zv9_j9f)G)3vK(;Hn|OEhWl`extse%tQYL~=F{Qx?yrF$r&pN%lCNd>-2|P(CVOaf; z!*|@1%`vT%ERKg(Jc;q-4~gbo?kR)7tShhFa>Ni0y;y14ECgbk&>Q+%LBq77Izggo zWn7v8{}K+iT(mx$lzi(+uWno9Q(AFao_)4{%6FqH4!SZe?zRK&f@DevmtO%sM9B%yM=lfrp^p38>sI!Hvh>&%o{U>Y^*sOU~ zNV;7aIZE2KSoTEdKIp0c(U_Be%t$Zokv+mtK*(xU;*w0$VI^LZt&vV$aY&PjOwTgO zrV>EVWO3z>!CpWN7D~eOcHf$(ZP!zl&m^AixK9~8dJ23bCH@L-lMphoU|f9eP{W}i zhxu)Pbr>pF3c7VTB%U>S7t8WGAcbO<^&2p95p+N3boYgR!fu8m~CUj=H;mNZ@ zLrBCi8E3mMqz6)o(mKejplDW*oZwLlN0#smH|*~a;vWqW0!G*eg)_`FCd&}3Sh3U) zu~mbB3W3-#_5G+^cS9yjjELqD(0{}s9TZ>z9ueP{k+USGeOg9G3Vz#2dD76wBq`{p z030_gX~l*87J&QG;cG*ptIXg(0&pl>(v%*Lei2`L*=I%t?$w6>V~hBB?xN&*c#pK~ zqNee18)Duo@o1R$Hce-rp`LU&*pLoR0%A#AHOFio@Ix$Ob4XNy05ru5IxoZ{?Ua%a zSdKnKyc$ZYbvo*rm0IzB|CMVgG?4p~^C}HVdEz1w(F^4{7bL!$@3{S4-+SL{uUR9;E?) zkB1Gf$30B&vQIoQTJP{N$uw#qou%&omX27%XDlaX%pMTgWM;(AWV{oOB|k3E69f&$ zO32y5ddMMHsnA3%QEl@7)YAmIM1mptJs8wQgMDPeCh&0kgtI3@Qz9t9_guvqvf$%# z!3r+weQYRZnF94gTHzt@=*4p9q_NvP5j`Yyp9s)^=wZ?t`7stYiig!+rYf3R^A*>n z5lKTlRMbv%D;92U0N=(#=9q{#wDk8gSqI1C*G#j$`c%TWPz4LvJ8|eeZ=pcE<_-Zq zL4b{{!$MAnTDG9SZ;NQ|gsNtNqxW(WHFLGssSnS`8&D!GYqJ>dpz|Z5+63SYyS%S) zXRc~Fl!q1Y3)d>ahK}*)Ma|`Nbpu)<8urPLjj-xR=d*>&LhC_v_tJ-@PA=i`z20p$^*YS zmM)beOQ|*QzXXWYWkwo9l`Wu#%KSjZ8ETpT_(wZ{}O<0%t)HzAp`c%Jps4^ z4aNue-fXGs4`AJC@dTNLt{Dio;w*m>`yUQT%x~H8dMfAg? zChQLSUj0q*v08^UtC&=7A!hg@srWIV-N|VdY>Ep@ii1xZz>eaPOY(HcuB;>WrU6;? zLQDN-KF{@R_L=L6@`$Z#?|f3FL@%@+ZAd8~WjbEZtGB0?@^1kvu7IxR9ybsPZpb@! z{f2UWns&|Tu{&2gQ1=%PDn7o@vM2MOT;)3k=pGYdC@5r37QBSTP18|9hR2_9GtUHO z$c8{xo#THpFAXnV!rwVjB2*otkhKfDGip7)T(YEm42JoCw30HBrSCa5kHIoPd zu|E|(T^8Y zgYfFV)0*{l$_;dGxr+l$?lyx4fS0%!j=1`o3{k)cU?X=|H7R-#_*H43l$~D+TvceeHXod z4cC5W&sCSJHiH*5rQ0!g5jB;vtXzExIr}YMFd70hr^A1)!DA}cBK&{x*zgUoz_G6L5dWK}dRU8jqpzCqn zq^a*r)B3Rc*I2|i0TFHTjRG$G$a+$$j*2r zX}&J%6fxg(nyz`f?r5tX^s_OrC_4wOZKHdo5Wy0+xpkhLid+Y6s z5>LZTlGbR@njujJ876KDtBE`v*9LzwBw9y{C*N$?)vo}3=oaA03fXKIpWJHl{BrQ~NC2>li+MDAI)ZJtHl)5mkU4A)LrcKx z)(7g>VH)1BnBlBBZ^RlQK;DeS&PVDC!uQq@O9EmH77y~s-$Pdb{u7HBroVhEfG}@Q zL`^a%wz;zN@B(pQQoYQF*u#%)U$aSKqeJTB+*e)v&&z7HI*Oy)atqrn(S(KX(ylnX zykd1pwmV2H5(%W>N6dfMHK~bJ`M~dxM9W#1rMsZnr~iv85d8B5F+l5Bm#p2wC!RIy zP2G5LD$BcnINiX2t(OOnh`QdU+LnGHA_UbqgzLLep^ym8H&#=~u6!1B;z`NRKA}sN zc~+?z(``5A+N$yjmeM}>`3S{}BczOsMZC0q-lP5wT{xWt=L^v4WoaK`b!5ksbLOw4 zvehJ7E01p=0PTzs3gUAq;`d?1DzD5w8m!5@SeldWrF(~?K!5DPnR3|a&S zhY*_rBCnHmTWN~lNTP$+-g?5Ccf|iQIxHHhhB-Mq`Pbifk>PpH&tt0__=SsLv4+ko$~vA30-ZGtBvVt1(#r7EJ0)W)9HB%Z502bCE?2zf4^j?O3cK< z7YQr3GvHH%fd~WmvH=v$0e+yt->r89;$h3{KI`l7uXwmtV>;CU{#^jE&V^fq8h4xV zrDx|=7OW8uUx+Qi)`?mKuZ-RJKZ@=>o~i$j1Ndfa!!~ovurZgAOU-?*ZRSpe+=^;0 zxnJg*TeaD2?)OSUCbwL238CAVTZJfuZd)XDquW)q^I~-h1srq93 zUG}pU0WUpQe6`fNyRR6r0{HkdO7s&>;v-cIcq0S*KA-nZ6D z>3oB}r6ArR5y|B4$b0Y&0({5cwwn537a(zmY52xXXMqp%G5xSEU_L*md;wl~S&UFQ zEoX@pec}N>2?R|Q8?M!%mk)nxRJwm%7O_5auqF+@L4|KRHw8%|=H0r@s{On&%|QMZP15=~G0OixH0qt}bukwpt$sl@R4_eo_3d^HuFS!J=<@ zhCCkl+&{T~o6W$MF(wmJcpuJJRBU!^-X8Zky1EgTx6Z2Gp#S?>@M^J0=~r3WhLie4 z4t%5TesjZ-Cdzzvt@UrzSEsa;-+9lauC5j?cKhqb)p!ARp+z{+d;-J?R^Wt#Uc`yg zDTxM?pp-3W5dre(yVFN6;r^?CYrjb?cKp5dxv=l^-wPn&yep0D-eC+8LazlI3mj-F zNWB;)x%}$W-)5x-)(%?Xfy&eUd@vv&#{;W$_@9~n&JnharqjQ9>NdM4%H4tAACo)lQ!6Op!Gy0kUkc?xrt@pCtY?>&K2JYP^X7r*xK+}@)X|D+g( zbyjIAj(xcFEo`PnYEbQ2X~}K}z@{uWi+?!`y;^)y$m+8UD!#wC&{_zo)0mqfZ1vwRB)wKh zbmRW>Z{1Il^$VWumkV8eY^y-Oy?qdIw94I7DM8r4QH7=6J)sa?6_*wMjqOlL6p~k0 zNZr~uuG5)cKYLI&;M*)#?w0?y18zM3lZ(M)+g-y$#?OLp9x^@nUTVbjUH#2zv#C2J zEQeP^?`l%tTz*%R{(;}1E%eb=-^}*xQ-dx$e)(5-gVFLH50?X@Mo%49=6a4EIp|gN zL@sVUxGI^K15r9N!xw>;5iY=;%x^P#z5QZGjeSm>IaKC-^1R4`aNXqLsX!_1nZc@H4H}9z0 z6CPZ18Z}XnD*L&$WS_O~V40rP(uylQc`3N!=#AZ&({!14Uj>b&K_iL>5cU*u3~ zN6>LH+m%zOY_m{BoJU{P{RUlyGn(S?K0&>d?D7LIIxTzXyM0+&%h$OZ{~(Ywqi}R>~5p zXRelTGuH^r-!k2OvA$cG_hxuWY*625=ku9NMaMHJHXfM>W zjoL4=U#Iqi4H*6~Z_~~OfWA3i9{INMsCm{1N9Nyq+pmk|nUOnmj3~@2|D+7v+$c!l zaV1)% zQ>XmBpCR)YRNvdKru-WUh9!FLHwW^?mIy5K8$)}>Er-#YzTlwbrqS~N6&M@J{Sm?d zIgNmnpZWs*hCA~k65qrSQbvq+>)8-BYi;oS1jJH?J#oGstMGeb+^iovk%bah`dw_V z3mVBvP?u&Ag)$Y)heW(gAdrgUajPnosgM>TrpOj-mNi0m(#pKt1~wfvZ#^BaSN8F9_EP zOmPBa?(2*jGkVp97>ryz=*xze3U$b*5%#T;IoYAELGss*23~$B3-Z{xE-h_!RIH_| zD2W_bTL0pRWZ+Cr!W*tqQJ7MHKdmTZT}^qnGs1cd$ZQ_jr-JXax85r8YTX2(#aHHR z1dhS!k(H8l+?$(d>0OZbs+!V8tj4tpZw$7dhAA3Z*DA@?!cy7Rzws=k>30kTN|5q* z?5IQG;FZ`L0xLoArKUdMSwOs<GTnpT;f!0q zN;V5!yw>s)PqBVNQ(jSBQ3|r79D5w#xefqA`Y4dhmqdP*2}H%N*zLQ_$kD4dlumPC zTo@;*cyYJKuG#i2?nBCt2I+APz3J?6t4(523c;)WQnQ2AtD%C^x*)}m>w3@&hG-=% zA*CNF4yO2r@Z=8_sV*UIurJ6$;;}h2;m%7ZZ`kYGYsNN4YbWxCX7Z!_x!1~sef;jc z#UNL7(*ysAx%X!j#Z>^aWK#vjQtl5$`8hp*!yJ^-asq$tore{|SgrjA*|4H$6+tgq zp%ajZlrx?F1N6xieITB0+cS7q&CaBomLFM}A3D~p7t<~cidp4iauFV4HM2#D_?Xa` zFbC^<0V?_l0rJu3Y+dOKVdII*7CvN_b!FVoobEfLZKK?lVkC zA(0Wr#PP7;+(e;|5dg3uk1AX}F>ZOT#b z0xH7&wzO=0D_cyz8N=KYjJl0GF=^afZS%vdkT|-6{#p$2Bnr_(*YPNIDiP*3BT76& zDm{7DQ7bJE2B%gFx4P}bc2&t^C+aYnfh_Z_?YCd?j_)kTX<%>3*K5QHSmLf5edz?nz!yH1UC1@ybJhr0#;fJHl+})&GNII zy}P;4mv?*v`b8yD+`hJC3qz0Ih2S}yim?ex#T}%%+kIOL_+sGw7)RjpX}s+Iej?mL z-!PF(7SCH&y#?q<{EBN2C*_=k*IpW|cWXiQ3w4wgjmzgO@3Z)BA=;y8ZN5IBTnfV? zSs8AuOMcL57us?{2b6eQ+p$&_K=*y5w_L)3*;<@l0b26*$7J7M>=gf0E4Hs&9KNoc z*q|pi5C0& zNjomNkKUV2tyoqQZm)!M=PWFGu35oxb*Oxs1`m@gUs@;!l6Exv{sz+{y(mRc=$Hfi zb(0lNpxq$>t;nngIyZ87Kr5tC6zBHRb7=u;S(X43SagZVa<4APC6`ge??O)~>xeTX zVV&uME6?T7Behtr=BzMsmQ>z_rDk9t5)$slh$XO++#o~jt5ruqp<1lOnX!ZkCb76q zVTKVa(8(Mjx7gsbGlOsgdMK9VYQu`BfDOZP!*=uYX~)2E%}mB}t>qRtjw~Y12gWY4 z(!(IfI@TGscAFIs z5T?vP9;%stU8Y{x`LQ#-oZuAHwD^80QvQ-?8 z6CpmJJ%tg2os9R*S{uN{VW+F=!4_^N z=n7#Xy+Kpp)vCLc9nID8Wg2?061KoDDVE1pfPP2_g(KX(q!|lkh4iCP6kHlKs~`b} zg)-xOneW9|!;{R&T;MS%B-Rn4LYkti3wQWpBcZIQ6tf*s76mF&u22!zNx1PO2iFh& z*5hWUof(c~1!&3M>Y14?xk6c=PUr_$WLE2Nm|YB3nj@qO#=2o7iiKwJM_lgugAaS; z;y##s+Z{ADWITZm2!*Ch2~LuD0$5taCU8dIlcMY)Dp)b$$o@zFMS=Gh6l-r~J7RMj^?)+@p!yEPB|jGwJ()hjB+Oi0*_iDTX2oQ8q51{qTYcOIu(MmADwLi$0f`Um zQAlBCF<7TNh4TXYvrudcIAhHTD9~pU*X?>i!nd56H0MlhH^|u;@Nr$m{REbj2gId< z`FEI5@w-UD5uA={J-Y~L&1Fq2*P4g5q%E_~lObu)`=ifuWp<9d%Ygs&+C8fUW3F~ZUQCjUSRi02h<(cqN*4B2ZDgczY#R_je)b<4u=av(e z1hHxcCM>g3P#VWRvJ%3$4z;WZJ@#3i2r4B6$OeisK6+|{j1Ax zxu1nGTdb@qNLot$*)2#|vlwd~3{dmys$~7yK-wdFA^`jU>^?vA_v<0vD$NCH)NR+8 z5eAtaur% zc$;gf)e%Vm`ZxjYv<`$*=hOWlX@UvC3?OO-a&m57bPjYTyZ=08A{Hu>z!5`bGc%eY zXZpb>!@x=XkPwVH$Bz~>)0GAl{M}&6y58ptP-oAD5XY?ZT2n-qY*ieK=mZJni9}NS z(`L-ajx$@2v(5`Zd^gtlewO1GspC${KH5k60796xMjDN2!v_km!^{g741(`-|3#*j zP<+Z_c67l6W$suKZH6QwS$AzM`~U|JIRcB|1}A-KIH<{I?M!nH zQ=s)ypfbO2FKhd=u~fHlMkXS4@5Cuth>j#|#j#)qW*$T;^48;*0(m1SO-{4%J(B>h*+Om?c zlaZ8cbzWu|YA!FG70ZjH%n0iMg(95y+iyW*Ijl6Q2(J=~g6gDTq1WB$k;UN@XnB-Z zZX$9xg~zPf56OST?Adu{G0$AOm=zDu$`5S%QOGL##JqP8T(!xMN@b>H*@UcZbD1RN}kVUj19n(2_qw2119(I)|rtRRT~ zuE}~DAuKB-OsTBnBfR@eGuW4MDE~Q__v=d34l_pUPzrLzs)Kba@)3(5G>zUcG< z8?u`U{RKp-(^htGpl+Ln418T!dKxSRpx@tQ%5J%)lO2A)?Mg&}KZ*NCKnJzNK*qkl z{0Zbo0h%p%h^Nwq?i%G*u{?Lqpo;lK$+Qi8O@b7JrE=ocAJ*UBQx`bEQY(ne&VLt_ zSV=Q6+S$bg=OE{cXk`eKm|~+FWX74!=4A4jTTSivAA;e#J7;9bj41VmvYnA%7RKU1 z<_RfJA|HVzRD9stwo!PQ8bhIJmI$GW@?-KZsmq4mk^X<7^xaH=rm0$jGYR0S1~Kdf%1 zblEqh?U2KLCFu;kq<33@p&bePzKqY{?S3d7Wu5-EbOitNgVJ3uc#!8Kha=v(HTWAZ zZ{E_jmo(n|Fpyp@V_%*0W^40gkOT?U>r(OnA35T_Rx}lP z#58pdKu@q6`GZ6zc9uOh1z98>wSM|NkG}W%k`%YWs#ThK!r0Z|i1ow>QX^30-no!U z;q(c!Qx~JF#hQM*pEHa--<{exkDv@l~jLWHF+~( zNI6H=YH|o3Qw;L?fjn6};Z<{<$Jz6F(HVbF|9*-t24atU&=GNoHuV~#t=s+)m|t7=knx*BvFm$14{O;7qNk&_3v_hR@QfHrA5N(PVb)XX ztU{75`Mq3GC{{1(sB5@9!Vi+)b9tgW0+&Bgr6yZMw$&U|DUB4C25Si&felj&&$*HO zZ=p-Ev!jKUQF_{&ix5)^pqm)wqVQJyuvAL%-IpWzkX^Awj#zRh!%9Q`XY+zt3o&;b z4uewN(1Mu8h&hEDdMe&=B3rg_tUowJua{*xwha@|(_laPJ~bY#C>&K}WX7!;@CYwV z0!Ey(+coqtu9?3UvjxbI$Qi=P49^N3hZ~lstUKHRn*jcSpdpTs!y9qsgS`#V!Js!n zZ<8ekkL|}uXh(=?_gM68aom1XIG8ogiW-j)qLC`0hN%CFWi2xm=6cr57kvgs9fhyk zzw~#|ZDJ;_u3}y}GF3SM5MT_e^4(Eng=|{1=i;_xpQ0XWX4@spTs^z>HgjZ)HxVM^ zb++uo!#xj5iV|Q#NU0H!KEgg{L$WO`ap1D~6`Rq>icGJ`zYey8zJ*ug+oek`!)}*e zM<%xEqqmzKOgk(T(TRZ=f(pcRd0RKibEpM43AdANe*O2$t^3iy;rTW80`RGt)6mw& zZs#XH%tCTfh4(Xbz;?nkDZ@4EVR%6On-Ynpp*g9oPKbV5DQQbfLu77|m6^){+4a+% zg!gw^Ee~A@Y6>Y-Tzz($zk+pd_ZvCaCDD-rhcb_({fgv-U466g@+=dv4*&$H4XXN-||$zURl zTeSRU;oz5^qVW7Z#YYV;5ky;-l0MKCG(a}qUub?SzTa@q$W?Ygjm}nusFEuFu(46w zW?BzPv8|zC!rzrQ*R#^FRddyFG1uIJL058CeQsXQ2XpVO%9oWh(p2g`RG%=uusZRi z`X#NXsqXOA`H1oF5yypl>aPv^i%^a`n_anawt#vqhp0t)t5!MuQL-?f8F(OYcA%>l zn(Q?fcx%?Q-@ZYSvyxyX*d1%>D&dyv@*zyH<;kJ$_@h5ja7` zmzLe#C!yF6XGO*7X3Nx})!&Hr#UU*>f4FG5EFI#lM~5xV&Zz!c`Vi}&=yl{oD8s%#)D zn0}CIV$=1_hGZv%{<9+E>V;Z(PP|FFDVB@d8aA46CgqQ}j&k=li{?!pZ-06G#$WD@ zhBA|#$>UodQW;<~e_)Ui{cDL3(vzm3{>TV0B#VEJKH=3PTdv@CrI&rUFWN7zjZmOo zGME#UtS+^!j=uBDxxp$iV&w@}@{y_rat zGT^TgFt&~--syrvdetylG(CTi`Q+o4B>DjlrM+Q`8v`Rtcdsljff_oipAS`gPE;qj z)xMO6S8rfY6I>PZARI?9UDEN4H1y=NOiRB%EM+#yH1Wa4d z@t26aIdWTx!-2OXM2v#|c5QRM!?7?8ziDV+l9cHj)h-O6QG3aR7@$2vm+=Vb_#@W7 zRGD#_zsJDEwH$LmmS(#3=FmS-Wd+Hs?cGEt$t;5|pDiy`<1$$BBjK_Z7T#8zj1qg@(J;>G=xm zf)Ec+n&O0wnR*WCa^Af~`hnFqyMem?Ya>*TcJV&53$y*B;!j9L+4RDnYQLt0hxF`& z8#!W&&-VYQJDcV8phQ+;Zv0f2gu(iiV`h%}8rSd7_@B7`#K>FCKPxQQgQ?JFgI9Ml zX)c)6D|9h>Vig8D#i4>3!f(qTzpbr%dnc&UzVVSiO$kf)uG%wSk>i@7X8$K>*=cxr z^rH60>nkt4V?JJdKovZv`B;~OF#W(|dm0oxhaMbTy=)dH#SmN_Nl&oh;p;$77=3T) z>Y06eBshZgw8LvL+^Wzejnsf4f}*(DsR@VwzBK0Cgd!o6D$I6uRc5z3}+3Ef5uu*Hed>Dw z5hQ~qPX(eq)`Ds$%!Ns`>nr`J%lq~K@kUu*4`C=Q$%w!;gk_$6;uaM6ZW8t`zrev$ z7i2^r87>Y5XO^5UT>ZyJD5335WH#R8MD~sX^c(00-sBu;UvnQ=EBA$&&k3N&YH(Yo zRX*2Z1myBTqv5;80e&q45h`K*{NRNPN{OXraV$Nf(ZmJkq?1i;;i2vGGz(tkjqT&l zQdF9en9$a2QvzSjma0k8{SFp0g z#W{v6QETv>=v}c2zTnl*$CGxz2(-`BOLBx05Yavg%{9FfDLL}~&ciBJrk7MR(ZGnF z8}(2uyABU?wbhf@7uPnt;hO(r(wrkZ1S=58s(RTB6I_8nn}WG2zOUC#=FvXnp*fA)%XL+d_A~SfI#D4yxo^Q9kFSv?q?8{diwtFOMNa@FDi9JBnmmKnC??f(lA&kB z-POj$9Ag9ne82{H<@*{ZoDQEnGzu_&!KEEnJ>bYSbmZ=RF)6llHGf;%2w$w!mN$yh z9o81wl+x)wtS>78feDk2rm#*{>WV+1ZLB)=gk=(I0T|b;&)3`gq?B(}9?0wmsUi1? z@h+cQ17Z%@Xjan|ENw-WxaMS^KIF)^QqI9*j#>}N66$*QqB!QGnpMBgt3@Bw%e{6| z2N14wDwQO=C^6R$x>{iC_r%SVN5VFpMz@lz^8@1El&bGsv7P~e$5c|IK1BV|OukGr ze?hl!8%C|ryxpW=-%u!D#_3wQM;Ecl(~_`}2+Ku~ZY@BG!%e*|;)gC8afVHQJBI`Lf>f z7tj25+y=J(Rv~6o>Z!f?H<0%o!xEXd2G;XhZVZs=1?vs%Ckw3H{L3kJZ%wzp15zrcw%&uoP%!I6kl2Wrbv`J$S43hC_SJ^5vUYP4G`W;Yp-cckDO4eq!X^UwYy6rWfDVs-A0*fi);5 zl?J<``5ZN@lfdKMYbkbmtXpW>U{(tDtLsYk0j{2(CZvfVm4nqMvmVMOL@M13$URbV zaQL8O7IjrKTFb`Rm1GnJy20QY0*qvKLnvZpGmQqiM?^i=oQ>-1wYnagAB?u}Vb3i9 z=8w1U32Z+ja>8&TQx{3E;c+vG0fnnjQ2;R_KDpt8ve3QhCkr5Rb&@lJgu>h3bA(v> zf()?S3bE-e>(iA_?Uk}~_72;A=%<_Lf_7u-E}6Yp9bR|CYw>YpQY5c8XpU+)GF_kv zGF#&oC$0a<(3-ytw9vxSr9t=|KVz*iu?n^&r8BlFaE)MZH32e}NyjgOep`BNtc}os zjz!-BV|8I+fPyIM$XYK6n_YdZtR?EjZJTnCLB0BcdL&|=}vAU_G}lO6w$1_>o>xwWbOR9oBCy>DDe*02nN!J-LYQf2^`-aBhz?F`ru2F zS(T>aj5zu)b9K}|>eg6t;n<#y2dl6TLHLt1W?aa_^kTEJvfD%E=t=jjPgKSJkJ9)8 z%^d4Lbh)8yheF6)qNMdYy=L!3i*b8V69B)%ee9`YutTzPlt{i#Gvkqb-;-KqpS+G1 znB_v2e?Wo*t-sMNdq4+!xLfuj$MKBPW(Bhhr=l|P3rn`R`r{$ZmvEA#gNtj`p3TwX&oCrk9hX>QImwS^;w12NyFO`Y-x1qdU#c+sDo49 z-k|cYEJU{574=;g4gU#J(O`zs_wC!4x?VMu;BBUEH^sfapR)Ta$E9S(NfNjICp_}< z(a?g!zkjs5lnRgEI`^lh!3|2fc<_Aa=a-SokChEjPB(gfzl*keAj|vH-df6NJzTZF zOore1`IW=DfR*oRvh-C!ntp4E+hZIG_x#I)w*+V^-4Dk7tNsf4wEq%C;rr6fCjHlg zf@GEtylnbvFA5r~lpHSYsC2jB>-Q^i%^{`dUtaw5^w#H4%VXuI*7^qOmaI}MwZR8& zAYR*d9^|vdij0&#d{KVau8=xAHSlHb;F{w2=zxt-N&8oAzo$itBuKtn<%X5otmU6gvXMV-m9Z?9YD{vy@>bZLUkQrJx{IUF; zmS;25?c$Sn)dYneEm7>f?eVIi_&+R&6EEkz+W8mm*Rs`HkWI=N8ALeLbb%kLbZCtZ zRLFR9Ir!d{K*HPhbH8%l+YMIk>&j00BMKQm@3B6noXpXBql}Ka4jC%=k~&_Bl^YJI zTqJ*Os?3#o&(t6PcC4w#O?#LxX|gogq;FE7JKJjfd)rgljZ5TT?Hc@~F zsyOU9mI=Ogzu}7ayQ@i)mm3i;5;s%vc~p*?V(i7#|1=o6|3VZkSG~WKBrUr)mA$5> zUxymDY%mpLP!AMY#7>oW;mLFR929YKHq9TS1~)VmEpwrF;u$HvYga;eZy##Zv|S!p zJB{1cP&~8ym%bOB_|IJveKZOPxqMM(_>nv%iXYYgrf0kH@^lcd@`_95DorXDQS@)? zoo!udWh|551`fWL8qzszt$eZ|>|yG!sz{}Qni8yHAmd7Oj7~m_cxS*Kj-BL;U2*gF z2crXz3kf%7sbRE^Ld@zH3|dx&4@?0dx+#Jx-=z`tOHjze1sWozf9QzZfRH}Nol_Z3 zQcrj~ZKGRX6yK)pfbS$3g)|jToDMSF!w2qjwZB=JN|%MN&=hO#jk{@dC zJ7FJc1o1`iGc;lXg)Rlk9n#(mC<<`X#e3^Rm_`hn{pxDyO-FfCr8szOeV{sl0{$km ztFMfm;YTlQRSq`0H{*xJp>&@8+J|SvJQ)=f&v&exmjyan45Gi|*rS*X))*b01*xmB zL58eOs^nos-9pw{$JAQ*a66+3m22t^rltB)N&uVkYahTrh7J2eki{X8dN2klOAlWK zDHY+%4i$faNAnJ;j6M)}U!GYu_FW+Z!K#~{XAlbmh-6UfFs|0oFfo`U^{!{4Z}5Uq zo=kz_TG*=TOmA^tubT1;q;KikB{L^n961T^V6mv*g?7I#&wOvMh5yCf4aXnKed#OW z0C9l3TW4M~xeh#V&%MARH^0g1`^FL4@`wV5150eCD@0I=dyH3=eJCUh2T2EC$X1DX z^x$BN8(ro@9%P>{@w}r4Ll)X8Sjb^9nSM7EgN;a}*uZ)Q4|MGz!lT~~`@)aTOMi+N z+1KAJdV5faC{XoMI_V0CpkZ|mR^;U0`ciMVtig-l+rW0&zKS}&k59jAKR3U)yx1pb zA2e>EVcI;WD4t5{^9HFO+qM>%ORveYkb(<}{R&t7vg!fu&F$bG19Dx=o>ly1y>$$eRHyVG7A!~7As9EayG`Y_Q8msi9OptuVs9%sHvXlIWipAP z7jf)TdZYSWt=C5iC`%_XE0L-{jKk`9q*7mIg`F9uf6yreUn-#(={i)j@6YP_<%8b6 zhWIE#&rkdB&CY^}$k*#c?O?T9by<~Lho+-rZ$*~0#mqPAL+S1pEKZ5Zs(?c}xdE-5 z5moFn__3H6G2zR?nii=9*OLh`k!~U~X}1s#f5&~@QQ)i1&}*jl?C31vXTL)FPuA^i z_q?W4|MTzyY;ww7tT;|0_N){HN1*skxq)b-WYq3XvxBJF+S+*hP^WTXM_-Mu($L`r z_@jon&nWSAbuV@w0I}H~R~_ju2ZRz(QH=Dzk#~<9cPJ@(bR0RsekFT5=c9~C==aw5 z@b3yE+=az1`q@_-&gqwyls1^9J<%~m&xx-Vl6&l!(K|JYcQ+bMRMjRUPkrqHhlI0i z_!m$KXSQED4ga`F)cBnGoPul^U=~8;L0Q~7EBU&aF5q+*Y9~{zjes9$!h8shgh9Lm z9ma6epU=i#URJzxW@Ml}Hu$+ZxNiq~H`(fo*n>McnoUTA%nfGTixo_$+RusWjKXtO zL1DKVf3(jRd?`Lqy>aM_`Qx-7iPw)*Z+hL@{WafJlXL>4f?C?L>+St_RNZ?;;r-WJ z3XZh=xRGo3NBZ$@skJ##mRy*#M7mr~3EYqR_tV+eD2e_0XNrH{4JxDB36#@QiIbZ_ zp2zJ?79CR_9I5$oNYi9c=W6OyY|Yo|#~BT$KK?A+s{+A!8mBT=gduKt`l^Y1JB^HYURA*JB2 zOkED=zxCLwzsGMmo4ukH##z#dFHLuUcHA)e)^YXk$1}UX&sGW>TGk;fsjV;hSI_@t zS&Gt8!g4Y<8h^wBM2l@k+5wU{pezN*E!6GVEdr|Ggy?h#)m2DuOGqCFGNypcIzd)j zARCOm0+$R2rM0zK#1uJYr6_2TH0?a~9YQ=B| z930(XBemjn97#-p}2`d<_vQXsk;$-o)#hEreJdbm~IC+Rlm8P%vqg;HR-_SsN${@O&KMe zOp-h#iZjUx%8*1ocES6Wh_c-GJZs!@M*HWgo1Afx#OqGQ_eczhiMC>5>_Rdt^)b@= z2)=&v6XdhG1Ng?Rg}K?5U&T7P9C-c^N}VX8B^g{=E0@n!n8u3n+{Cj5nLaFRk^|Fv z0-LE7FD8h^3`<@kz)U=(8+dA(PgG|Kuxx_(+O`H0Css#Q)ii+3VE3jwi~D=Plx7v* zcZsKVYu?>Lzl;l_0OZeIR}{v{ZBv3K0(S^w@XLh|4ja=v^utCE+|!}7E7?3TqvOGB z%!r_6Xeci4swl2%XkD6wqrx$aBaZ)Qir7%hWV2$0RP`M;<_2GjeOS{+O6OVJAeF4J zOjPVc%Ew9W8=cxW-md&r|NhPwM4893LP8Mo=7Di{xf2=&2P5@UTc9nq>P7nc>_T)0 zRq`8E%w=4cd&rPoC~QiF*8;@WctVFuf|y%i6CSV@Ac@9`d3NLMqyW*7B9yZS|Ee&lm+Q_ z8K2=vXwv{GW%@^;kU#Gf@9?d+rOUcig7z1^8r!ElJ#+^ujnNz0Q@kq3`o5qL);YU0 z?T#r}3Q>|XjeaXlyu6kBga35R!{E@n_OXCH)z~9^q z0>rvI0No_n9+!!TurERAI7Bzi{Q?_c@cj!F1P;zrR#Mylg|A;ul91V*aCzPZuIH;w z5(#>VsDN7eO*R@Ke%kT2zL^PaD4G~6U-XlBiawU)JRbsuC&#n}q8bAfqJ|u#4Nd)LdpjfK zhh;RwdhF$n$~eqQDbGsTb)P=v4Qr;V$=98h?=p5E3$I}ThqoXn`cAics_1S*B&kB@ zcmNXv%APoxQ+?vh84W+IR2WA{ix<)14Rj@o3Ijo?ZE)@`0SM)TCVqf+uz=$i0iJx2 zeXWoT7AR9I9L7U9W1$sfDbb5zx5)rYTC@%sc%x4^URp39R(n2`fGq`R)4;XVC`^Em zwa2utu?mHZx~G!B2~gVPqYcIdZk#hJ8&}1X1!?ZN5@yp9;i#b^UrLiP*Bq`=)7Qei z`NM!T1}ECdX$8oM^s|-6*xIN!;Bg^n3g=l>P;}!3xcjX$zpg<;OyLEl$1Z)JuX>j3 z-WUJRR$`s4q+6J^7LxLA3Za-_6Z|Yqwl(eV2=q7T9vR@*+q+i$QK@&OeFSL7cUjr_ zp3)JKn$99esmN!u5ezs);2Roo?0CkK1-rMvYrQAKjT{Ro0oUMnAO4r@A_x5=OEzVk zZ+*C2*t0mJBiR*y{DkVh>iB@iaf;iWj8n){UyUtN#$1mk?@=>MJ<+eUw?9y%PyM2y zm?sa+zy|4r1_|ocTWros2RRG4qTSuYN-upsRGvs`%>AgRk!j=HGb{YANsjPxYR*J44gJdl!UJSo9?9}c{Q zRr;hN??@G*wW&7;;{-5sKUMq&meReG*ulx$ek0be3vM3MsP(m0S8k! z_i`7RSYdNQ!^sQpd^IuVi?_9&bf?5Git^W!UWQo*cRDOQyXC%i$ysCyZrK|H-ATTI z33YpwhvaNkU^TUvZBWNGS*m-76)Je z5SzYOl!FDT0wuM`P;)d~hz!d-COmV~biPPZoGkf?BgCu~H?IQyBa6CX@9XbLO&FFE zsg=6O13B{`djOJ3mn2VB95=1dtVor=CziAkA{)gDpW%nk0Fz5OigPLoV0HawBIbAz z&c*>V4a7_nF`ewwh=+UTh-mWw^fDjwijA@MDGsDc4F}A;9>RaXi$fUbT?_!z*Ep~EFF^jBOVxskqW4}=&TehK>&4mUZ1hRz z{3>G9KXz=?&s`Ded!x z2RKrB*l+r~NB&3AT}L(fws8P|7Hk7nbi?QrMmG*dg9u1UI6BoyPC#7HAdC=EK}Uy( z2#A=!(IF_MqJj)T1VsgG4Box}?VO#nowM^i&%OJ;uIux4Iwn!28rw(!ylM|?dP@*U z{Q@@p4Wz@rlSTw+Ur*Kwc>#ll)q@{MB3!wcLIWc}f=aAGb&{|vck!YQ2mL9R_XI@- zg6cRU5DuJ0g;A=ZIwb5kin%nzD}+~zI^M|Uy91uE41oe*IuwceWO4~-Kl$JO zSvN_uz>V#dfoyJi`@P%o!?t;Dp<1t+KS?~y`1SSg5w4|JLjJoj1M0#euB86yTXB2? zMYxoG-@Q1v5+24E_2bU8x!ylX-add&|GVsFSkF#RB(?{`lHXnPvWZ zKXvWG$q*|qL&;t7dF|!dwC|r*3dPzE5N`+?|NGF4${7^l?A2Z?YskBp`a@ggdU}a$ zTeA~|^e75*^}&@doTcABVIf7NAI{H@qjyo5CrtZ)olFXvYWZ^L z-kq6i%V+U9JC~ok9h+_ZH3aIv*x=lEw#nmgO&&vFHNSg#ro1_S_aHezZuQ=)%}w$O zHf%pHuBfsjGGm(BX8T-6I!;x+>svsSy}&+)>}0vOR_|}sIW&ENXhQBjY>Kq17&`cz z)Z~BoD+T7}{2}?R*s)`WlrWZX*p{mqc6wDsHQ3G1 zAPvS`=a5>h?etu#NRA+%`eVmcmzIXWvIx5;u7ia_7Hc=#4iKPE8$^!+%wf13b3cR* zMre@+1Qjbl1RI(AyZs1$SA0KMA_LC{<_((8>o{aW1;C;N-2p^mAafct7CFs^A`G_M zH6Ted+1I82bP^$=(^x04$D(?+sD~DoS6I}QJK7~&v`tfm0AU2su$*9)yFG6z zD?=we_=N^r8kc7=1kN*2xNdXo#HO#ESVToQa%^!G&FxSvM;Xnz3Ny4W_X|p%8eCBH zMEo8k};TP}_XI_rO4m~)f0jO=zdZCBeLn6UZA)_1xvpe!(= zH%H)x-G5NiIA@SH`Lfg~;v%F_p@mv6Y?@blXGUayt^6Dbb$xrvY8}_)XP#6OR;bj= zJd);Yp(c3PayPu(S#_FC6pOAK)_$VLK!!dt``%aY>2}HW@uB!-3&p8}_c?2}e(x6* zpBP?p?Q%8$exKn`5-#W*h^IXNa_&G)!%2)qNrNy%>-+p%akvFoXpTK$4l6B_3|Bm` z`O`r)+#20Od#7&b$P=_cD{@E*mHNUB3!jK=63`v8+)s4S*X}PkF}*7HnUe4PxE3>Q zqQvtYaH6u`tIn8qdX?R7%?Pblypvn*wSrdHR_#F=vL zwD$c6^%5nWwn87}F|O{B_5y7Kd}SV(j1~wM=jB=6Gv8ozy|q9-L$T_L@F-{UW^wYG zpj5M#qM{Ah&7LOT?urCB5aDPX9W}Y-uq8+ZG?<`> z`vc+=1Y03B619dN9evcK6?k^Or|}SuFSNx*v9(38kYuYU-zE8S>m~}{0Ko86FTZC3 zL~&t0_?o|iICKar&Gd%685>>XL>W(!Av};-w*DvGlCSYfGO?UCiTNGOh$-66DX*W; zk#p`$-r&t}k?G@oRJ36m2$pcj=Klhz`Q-aEnI1A90^dOw#vixc>V})|GQoEeR-}JK zkFJwCi>3$+s9_6;cb{Tib5cu*HxL*#Cv=0wquHWPwNUp!9*Ce?sBGB`;Q!+YXGp>4`vr7wVCQ4dDr#1yI$ z|Af)^S@N$*{jVg4Sl2&ZMqomL6~rhD_8K>T7L6l43jjV)S2zcmLJuX_bkZLYKX4%5Di$k4O8Rr94)K$k(g1 zK};LD;8Xixm@N*xHLG+$)vzsst5M{Y+3VYY)Nx2IHZeWOM%o52Qp;~a2G4$P{h1qS z4pu&jjgmz~xzwe+rS){)XCz(q_!o{p*g5Bhj2=I#UbEgB33aB&mMb(eCu>z z-Q0w)LXdCn?DjRb}GsZ)F5Qule0C}xQRUo``21G z#}cF(z0wI*kF*@OKZ6fz1jPhoQ5ggM6uwCTYRfyaI@DhvC@E!+*At) z`=0bAjwQo>j5|j8=K(pn7AE852g)*J^X(q8vEIXJ}KucBW`hv@0Z6>EUOS(+W|apU3)scZmKTkzSz^?ny;OEAZuc+b|r8vZ!8f zGOZ%1;64@A)R=!NFe!JKDl0&yo0_@F-sujny$$Isrl~5*fEkX&ot={sjC%d|Wgc(hJk;iv;cY0MBw@JUE2A zJ6J0$KDZ@*(g%2w0uqCO@(2h%7NTGqQ9u9{QxU@K<8GYe9F-HigcGk-c({q|hp32D z7U}`O&%lDWn~vBLPV(aURLBMZ3kdH#2_Dr3e6#n#xgdHc)SZnS*+!1w`ED~$?TVgq z7UZE45cS(26?YGVPUr{;dUTpc{3izI8)bq|KoGny4bl7!4Fg4_gCj7%hh+`1e9ry+ zlJ>|r)d->5M2pengK*60?F7HC2P;QqG;U-2SxM%-wDUVjc`ITJG0ab95!wTCjV#*5 z65G09#y?{wC1Bo7OgUwZ(xevGY#$`p68EOjvF=bb=!~v`fQSPB3KhLIjsC=u`36t~ zbSc@*V)nD*W7E8BF}`clTz?bwdO>X6@K^~;w$2#y9gB?Mfo))k!rw)bJJIcmYRLfR zCkM$Ehg_p#goI^kn$b-pjhboXezQPQoHF`%r-Xxq1i~w0kA(gtBql3ze9j1~L&hR9^DEOEDx*ZJqFOTrTBvzWg&*Hlg@7-LI7Y^dD}OMiM!hJ!>=hM) zgDH@Z6+KbaG4viN6uQPpBEdpfuo|{nD?!2=kIdUe4w3lMNU-}ojKL6>Ib19+MT#|Y z*>*#zHj1xc7g_iAve#~`n+Z4$rx%3J#sGR?mX0#OL+{l7X9S!DcvJ{Ho}~Cx0Ax$j zJlYA0$Ab;<@O{v9E*}x%PDSkGBgAtN`~+`r4pvO)L_HI*b1$&u0jmH!;;Ha(79TH; z#|eLuUlGu0E1P&*#7WKfXoxs|rNQN3u(lZ_?i%&<$ z1Hb|(0xZuRZ0laA`W~wiOXHVM@bpfQZ4LA6_V!LR{EXurFjbhTEqg;sTVY~0-D6B| zCtCU%Pi?2nFJPbfVHQjT#_-asx07PmT~?xF_-VXfsF-V5Ta#(t{>0*9Q-Na+Cc7pn zw-}gN>d}SU5}$8@pR+I@046#Co%F8g5lL*1ifQ)1oE4)8IAL;(mG_y7GCi0*LhJq> zOL2jkavEB;gDc}Nl~F!jW(UCDcVb>KTN5v$e@&wZIH4;uNGSnG3$y$ZAWCva?;mO1 z>%@rH@%|k3p^8Y|w8rePDr7=3PQ^G!_$GTwocZl>{#ow%7e9!vMny2Qp_w&x?!n6*XhXpF{f`TUFO(UrVdxf> zh7`x5@yO7WizHE%-+NWUEuA7J9dOMK)Q8T}*<3Am-t$Mh`loCbLCcK&d1YmgKaA52aAS?-dhz!5YLbd}?{t3L!H$JQxsJ`>0R#>h0UUe_s6Wk4;Isx>y z)*&+R%d;-SG0Fn~PvF5KH~>oZtcw)Cxf~8aUuAQ_FoJN&p01ZU;w62`dpn zstn+n3QPA+#<6igN_fxjz7P%bX!@S?_4}lk_uZSv0%(}APB~o?zh;HW3;q%we<+s+ymchG zc@NXReK7iE$v)-0qcd|~LjcjWgVgtdNOtn=>;G5l`(HcxzhgIxc1XPM1%#;z_YUc? z6=T>c{yyF3xu){iu~K+qD$0bMw!Mvc(wTNAguk0lI@ueYZy`Vc)G8w54l4Tx?LN&heRse6T5MkAq%1s^&&U|0Y$YulQ+hN0%nN zD5)GzM?$I|fPG^eX}@NFk%eDhRf z<+rge&gdIIiT&ZBwm>{$h|^ubvAQ!p*7YHVEirD_qG2VDxVCHAN2{`p>v`;-Z;z{~ ztB$)t2E4K-Zg6z?vO$ITTTYylQqzd8KL^&0j+asa5Xtjm9N@sdaxtqn_Og3pmBJ+g zvYiY8G4DX!L5kaah*}S18jyv}n_wXYAiVot1+VS`L)6xzgD8^`m4HlH*-GPp;HD0iB!`Fr=~ z2j%f7^e+NBIT=0vPApXd;^EwNWG{unk@qV&m(q#lU?F%9=;_zzWPhAv$jE2E5hH9r z-A_twQ{o^~Yb(~iH3{|mb~eL{1m-6A&=I$=N@UczQdvzrD%G0zj6bA+{X97rQU
k)^CxO^!51`cv0|Ww% zs$i)D@z}`Q*hRwfqNkS12am|vDX=zCSdJ!Mc50Vy8$XSKh*_iw&V=Y^bl zJV+l8B?1r;683WuOv(@tBg2&Ow=n=n)SVZ~SrvG`x=?*J2ms=?uN0C2tH;$ z>S|2xFHgNvGF*iDld1q@vfes$f}|g5LpZ!&HvwC!>b~dh6QSw)GY#wNxg}}y>%2iK zvLL^=eaQRQ1cxiYqj$l>4YK|GSPJFOZ{Paz2WhRLe^x_39kU2<3-wwN`7C$e30f1s zwot0re^%;9{M={QumL~Qr5Bs>r3fI2E+BqhyzbIxLvCE z)2AI99C^bP(aw}dv_l}pR}W5ClC#!cEbtbQe!a0g`UeBAKmDEF{}Vpw|1fPTmPG)q zzw+?WEufmF>d3Z>K(9S3Z;sjFi}_*GY`YQ}^e}PXyKL(#La@R1)c$+RLhGZbJ7>R| zd8drKJ(-l8!b+xkX2DB@EAQIBr4d!fK5O=VRJ`ye9YxoTPyQPfsZtW>(2tt$J6iKF z{i}7P^6HQ$qbB21|EMTfB9RWacs&l6OZTabQ+y+xsPHgEtsRD#{Wm^xB|T?Fix+qI zMRT>L4^CM&eJw<}7kN;FX+BDxCl5;M-k-5X#aWyfmC2nH7*n9x&WhdiQtTw9Hi|f0)R4r z5lC5>iXA0?#}g7ES*F_4=lyK4{yAa+m-54f4@0LF+={1d*`2t9;+Ho_){b$W7hL^^F^0O6x25wIee@!lGKIj+xNC4VK~f;x zA15#IubCU|#~1J9UU{jN123b_SPYyx7spaeea>+$VGBb}RW!=NCr1u{sx8LnwZUHC z^342<(OL6EnbmGr)dA3c@ku5__8WfG*xe-Gi)JmA^xHmgabBqgMVG|~ANCydAc5|Oc zov9$2a3i_jkh%o*E!!M@`Hnnq5p5W;9(PXFD&FjkRzJ8mLkmz4s{AfKW+~VeU!)nn zDt$}I&aA80b=DiIzy@G`f^J@ZYvn~k5276hB|0~3Ro!nQV_YFZ5D;C~W)tbp8W6rl zP&W9w-R9udib$r678632W--e+5HUpa{&&MMKh2`M0#D@qx8cgq}MxHkc&*8#8C?Jg9 z5*X%8YmnnLF;!xnCdf;nmb*U`AU%7cjUXZ4WxX>MxCzwEyF_1cjDEyzFqLwug`o&T zYARU6M)rG;l$#C*FZCNr$2^wHP`q4W1I~)LzbgBda`6=Y8~W_mdbvHegVp@|lB-Jc zJWsYqExxj^if7fy{q`HS!4IR-$Q^Qj@^VeCl$9RTi&3;-ap6r`$(gM|xlIner2v~l zUR2zdD_t7Rnw+^klmLa-FsCDb&6FfmugYz>^Bt+~Dn7lHEO*=+j!Sw2mG)AStA6Eh zaDJ!wY!<{yZDJ%#;Z;d`6;bwgpRH&&9C}>IQLgkGTqkteCGG>mAmE&mZHhW<7F! z&y1Vk)kb|@&0v^Ys6t#w)+x6_bOKk-Rmv(lI6F}?dZkzH-@;_X+tOzrd%s<0FV!B< z8VFdvJ1F<2WzycKyZG^^Fv7vuP;)*lJ85e~A8*&RL(5u2$Pl+7_?(VKyoZGFnL)XY z{XY74PoOuGJtzpt52GB4T2o9dD@hA%kS{lI!poHv(;F0(9v~;}Rd`GN3mU3kZmkDu z^f@K`@f7K#^2q(<@IsTDj*%?oGpigQs&~fS0%1r|3dxwdbUW&a2q3cpe5<{Aa$&q2sAkCAKi6p-flgA;& zWD-#zQ{udArFMdGLM~Rd|h8d+j|V*`pDpuqt&eXzJazNTVu?0SAd_W-akA*^O9E@5g$4`M#BMA z6sb8U5p2sHnpRUku)xjt=sgYrSgloOndhb4X#l$q#2i8aR2*f(wFQtvs zq&kP(E5K0=!%pEwS-gO3A1&lhZrUB1J9OBUXzR2!f*AeCtQ}gPwU#VR`0)_-J&PHO?W=RZ9)NXeRNGVdU>^=bf32Nf?2&LqPu`r z+3r}AMH8taNYxhR_aI-+A#i|Gj#}Q{gubo-|HFmBvyR}5uWU&wNVSjNNTogaAX&9W z(`?bI$(R7Q(#i~+0=otz-FanOKo=$*)1mp|YBDuLpz}YK9!@))$q>2v2Y!EO6sA{P z|H@1@k0#8KDaoU8KM=e#-Wupo6h3)X+UW*ee=%XScYZ>u_R)tu#847Orj&TtvrJc_ z;q~S6@vKqYi+(p}n`iNdEV>7t+8z?h8a=2Xq@+I8q;=ICd}tJJw!is2jXO z`_e+!*xoNT`RZ6haJxxyd0q4vIV62is9VMWo#HHR=PLP8$ilO2g`o12np=N8-VQec0f)aR<*A8-4G<87IFGF(Rc#u)+HxVQzi&tDN%AHbSw%e; zcRQuLPlID$@hbll(w%XS8gZYt2hBe@Nz0Od(ohEeK4hOIK=s%fIeDL!1)}ng8SGZr zYUH`YOCLLU4k%9Ko}#)*O!aWJ$xI5|oRBX}LS^{Djj0pj=ZTX}o(@j4ZznyJACy*9 z!_H>RZi5f0-15|@nUP+aZCR{cE}B>!Yt;NUrL$DFp*4qG@zhZ~GAi9|WI21_Tb{1> z{t*cox2B#WW>W?hmZOdnb7tpkJ~Ye`&IwvJ9vV?UWOQckp!fVn1^56*iFkg-l&9S3 z+Yy%sUfhG8Al*^VwRzUedF`=jf9O;9^CG|j=HaIz{ueL#Zvj>dAO}Y^M?CeECf3vY z=@I2TDK)T&h*5}3m20_(o6J*f@n;o->K;7#UOe7mxB9{#2!x!OahaOqg1u>dxg@{3 zm~#%DA+-^>oN#f)3EdB5=yefpAWpihR|GIk`J`MEt$vyBCP^LS(=Xi)`W5)KW zP#pDW&~U)i^cK?im`E?FQB3@nNm%1_?%&b~Z@;`-3xRsx>Ll;1>__nn@YFH0)Cj&$ zv>Ri5QugC7jz<)vF673!`_>;*?tRvgN_twW*^nw~k(KwCQN{wf}hZ zrc6NB+d~R1fQ=f6-yMLEhbpI(3-5W;H3ROxo#pz73C!FRePby#55s@v%rac24R-HHDJG0CiJfDd2S{Z)HQTF5eN5Y~*nwNU4-JwE8EBY}F9!Fu zbsspdXHb9j(5NHWf&{g2KY}$_F{1=ePhQ!@3o96v7$2f5R0S6r2)~o@`z#XD7PI_1 z$V=2}PU1?aNY0{GPN?>$H_{I{XU>F9OS{62e5I$MsT8{cZXH-qDUdvv+yY$9*Zb`k;&7*Qq1v!+2hyEB+;Q_E8D z)I9iU#5-<%GQ}^4V2hC@)wury$;?y2Fo)OZlHT>ia1eFMDWi=^gIV zJCQ4{-VcxXG`)%}j>sN47EpXA4T>ea(7yzd6016X6|XkdzMP+S@A5M zYmk#B1)a5KC0<#nl=d_VoYI-ws|R;@HFel3BJ)J_n+nqPoK1#N^b6N$j#30QIJyVD z+-cvP(g;?@GjMqus?3dr`vWxq{R=zpzBU$@2Qts&vY^?*><^Y1+BnMS9Ed((WbSkV zZ4nJWBfdF8C?$>ySv>r(t5)%9KmegFytKdfh|mTPKfXiMExD>V^cXfY zoOx^AP#DMDOkiy`iifTi5nqge%y2xOomm#bLc;$0E>B()?{)H#9b-5u*`0ClbZYiW z8_2UW|9NX}@)(ZULW^Qy$=uQx3mV`E&+5eX<_vULd1<^Rb!GZ~{b&93PnrB;-Ou$H zJLi-4QjVCLe|Y)FbzipZmFv9G8JnyVHuA1<(8J5Wf+JAtCp8dsYXr>oCtNNs+HvV5 z@l~D%i(%FRmSsUK5T{a~nHjr7z-_r9c!pUg#1P=ca?Q1~4mdKzoW*E)V?Dy55w>;5 zzav(MAkN%s9wp0+O*!QMc*w%><6nQmEhtbgwM0t}eS!@Fm!Sn)KwVj&t57(|A0bQ5xy6PjjJ0o}op571 z3dtC09L=o?p0Oa=D!AQN`i(JiYOg8O=4sepA1%w5$w!Z!T#<>C9SZDxOdcQFwv=%T zSblG!px@y}j$U5mY2H}YiZR`yS&n4~vU!MjhBS_Tr|HAAp0)Itc8WVRIvQ?R3_n6G z(GJZ`iH2)-g(V;4|JVvT=Dr%yIl=k>O`*U~IELz+Wy&n)%DzL~+sH|czLHi2PwmV> zzR6SIfTKxV!8bQ2cOQOo45B@F-OU8f9-*8j!9%Bai#faDM#ty+L1b#~3B)y#y4+M2 z?CL54N99Rk=2n%!lStXaow{6iJazhXT3#;K9na|dcy$m|U6LzuiF-rBHxjYG$hj2X zAICYVDs>F9AEoH(l>~OyFq`H?O@n2PYp~YD$6#mtU{CRk%^6M$Nl=KyEl?p4)5O56WO_xs$!ZdMHUlTywHs zD8A%8X^Q&~E)IQjdH0v&uXi_S&)Auis`radu*^}=5f;2UC-C55v3%cufD%Bb218HAZ`Wpqx-L9t@et6b#Y_Rx1y3xm%y}l=5QfZ0n zi><9{yb2IEl^|{}mEKwtyi~OrRe#+?C-`3a+e&$2WOLp#>;8Dt%MO^!2afeS9@0V# zDp-;2e6;SRewJ`~bmBBL_V$x!&wF&^myR4ZyVgQ;z<*p2dZKJ%0?Ly8tb{-*pI~*l z(JS#|3?=pKatHBP10jsn;t=QA*>6J(IQDz1H^Wr*dKkZAk%8h9%T+I30n8e-3Z)q7 z*oCtEk$1#a5N#yrF0eWop+s~7D_@IXkUH|u5{b8%$(?_0oI#ELkC6qguhrE4n^_;g_X#gtyK5m5h zgr^^x2#u;c^IbZrDmYd>zKn%Lf$pbI{HACC82+*>%-{pQlO zj(fW=uif}>z2N1Ex=3e95#KS=pzx7!L4G_NE5zq`^ZmM~-LBd^N?e@{33I@Y0Z#b=`q{OIVr;tN;qzQ5M}`tFBDe*Tx6 z4Q=1EFxJqJLDB4aJs0hc_?@i8OW&1iEZCrzn6D%X}?~| z@M}Ms>0YEr4s+qFK82xJ(BYbn_Ezh)i0`x&>0fz*Snv)y!-NP?^Xum`;HV^Q19-uk zlFtxfD$rYs5){XQJDyDNr%7JfGBvR2_nS!6A4S-@d%w~tnDboO01Fj4GXO+>AQ!biq~)(c8LOosPVnZ))t77hv3ONtCi zn7%Bf+>r7Sv%EEW5Uj_fORwEvq^C`QF^gLT3c#D)>Cw;x9zD4cBes0ii9 zT=Fe>cUk~;jqPLkULN(&&Mp0ypp#$+x%f;5VRNX)I zD6qF4O@5$`1$4Us-8C5_&&d6%Uk8m~BX)b@xx1c(DF{7IgzuiMe;m6YZIaQB_p`Tp z4MHS~X4U*AN2$HBF3I?+*n4y7h}l=C3nJgY6xab=1C84}%!!d*^P4`H&^MhkKv2M* zS0fcuZr>3GNpOW*bz+)8!u>UGP0JY950tTw|K{6Mm10w4o}1`5^)!X7#hmtNo~wCX zasO)BXZHsmhRZTlwynjrRtkdvMX}~>Ix_3R z=v_w#*-P%S$ISA5be?epKB>L6pn$r(8|^w`YOe*|vsT$}$ZwT8d%cNt@HRcF=bBUr zkR`i4tvj+edXsUkK3K`cztry;^?AFshH%aU(ge7tsRfkboc=Po_lN>-`=}{<<*iOG zQPQcJ|3rY_b%h}Us;0``WbqUxqc03=f!D^Sjp4<&InqA}_DAR5EEaazoro3BQh*5{ z)bBpJ{PLT2Y9gP{1nbj4WxOlp*N2T?j}0C`a}2^?#l^UI@V7czk~90SEe~*>CpM$k znpZS~L4#(`x+=dlJ$GrfpF3f2*pV*ynuG|HekXR(k%6Q$AqBxz+OroOR4bxA$#3LnXi7@9ViQ>?A0Hd&GZ+_xdZkO)jmWEW#uP$;$;)G5w2skC2Bhyf$fFv=b5|^!Dt*$hPwVm z6VrDIZvf1~&jSXbOk&S?gUnOHh@tGjyY-_>#BJpQ+pt!Zoi&VT$Taeo2}9U4^>CV2 zW5nPmqNpYlF-T*hOkP=E((D_GEA20vfklh#t09^c?pw^_66!Tb2wwCe8~wM|(-}`{ zlA#bzUp4PocKm0IrQ#8(^JP$^1IT!H1fjH9wGM|)L;I^PHyYn)ZthTo=pWK>%Df76_@+C-6 zVwUFi;v$E)j&!4X>FJVihCeC#D_d4NS37(_bb%_UM%zYUx@5c$9|-6kFStmyHR1rs zKb{Zf0cBTdGb#uf53$D%=9`ZE*(X~IBEby{U^LlUgo#8dL97-AjSN=!IG{SGB5M-e zVu5JpYIEC!W;}Gv_%E@x;+bMQfUN2_T7Z!&Oq;v&%Zc)CDCmG0hZt>#dmGNWW{u;Y z_2u;pTh9ubKg4aq=OAA485N)*ZeeXP=$ov0Bj=!oU(5PwL0;z-jhjdo6RQ@zFpJC} zK(dVcdnrzWm-b)OAiY2$8ytnx0#biD%ijFhJ`jC+&@^w*qzZx+?H8#S98VI$%!Bkt zBy2?eHCiBM)m%Gv&Wr^yYhfIyaD?A^u~Rf?(g|_Huh=?5O{<2?D+Wzi44eDNRMugu zK5v&cqE)<5SU=k!W9|R4!X(kG8sexe9Vi~^CtvrU_ncw2w?4JjVlmvbCB#->$ad=x z*HAMpBAWH^+qwrMnLc!GDUlpukGI+9k<{EPw|Uq={ZnUx8?#)XSO2uNa35G6Vw2F3 zs3Gcc8Aa9<4|=}elp3O!VQ2mQIe2~5GPA&-4W>|A6{)gh{xa;j6R!2`NMxo;bg@d* zKE2++h-H?EGc8s$Pir!qU5%fOJU&toH;Im;+hhD_s5cx!@M^|Wsyb;X$4(M$GAR3g z@bXt8zQPgdN<6p)F`6IUS|T2-fIL_jC7?PF~@RTed)Q zdZ0fyFQ&bRa7jK*$`J;K=HK?ts%6mRC((4Cdpg2M{lu^u8%_OAtae-%c?y{QiHZnf z9F)Fl^-`(R6n9IfC){iIKo$z+yyp1(Z;@;g5^*~Un!LS**!esx?8yz}BY3ywbKDQx*lsLbLnVIQ=|HZcnv5R=W^)jI%V_1Gl7^Zk!A{h7wfdD z3$#Q<8ZO`6dQ@3+B658+C;k}j72#pz)6x$lFq*WTUEL>z#-on5Bae6$hK#Un`y`Kk zMTVGtywmO&Ky{gxRPmv}E`dHyw3J7=UcV=!f@QfJ75+FU*fg64YZExW&{QSx`k9W$ z^|}cA=N+#1T932tT)#K&bnNGpPoHMcHg){L@h313{RZekaqWXcqB@QNC;t#1^dAW7 zxqPn?9zP-Ws7>XB8EfK_O4ZBf;}cD0ms*|uKbh&NgZ2~Rt7By@o@n1p3qn|3T8F)> zJ1;yrd*b8B%gtwD6FImDlTpH_P1!paE=9(Vx1DJ4h%xt(+=bP6IYkBuTk}rX(UWx4EhuMazs1& z{e<(>m61Uk^|z8NGqW+no)=CF#ACfVi@=HLhf?bWH{#n_)c#MuZOBlUZRim)&*uyN zE2VHg7)#r=fNb}w72Z3g$5&2=5$f@UG_I^a(vkpX1Xt8LUO8U3O2 z>^Rw2o7`>}Xi6dK|D?-mZSr6K{4=r@qRO2T+7a3(o)UK15f0Eo>Fl&G#oeZI$1B4+ zvpy{(>xvZah?k#|xV-Z__|%?r){B*nj;vF^ubh&8v?D!tN@i3M_3D)DhaK53r{sR` z$lY_x0PW(066B?JZGetI#bu^hi%%UuW4K-;CC| zs>k~|z|iQ6QFo&Gy)WjEa_))rPyO*kvV2Y=KI-htti;YHTBhq;QS}4Xx?k~WBkrkO z9PbX;&eFA68hoS2JE&rIq&@Ru>uIOQrr+@vabN8dlN{!rD*DkSxFqpUu-+J5VV*iG z3O#HwpfO#3Aet`0K8|mtsjvsQe+d++{l>lmQ z6_cGkNwT$QA2d@N;=-{etAzJ27#1x=vqf90jKRmZwn7h%1oJeSF2-4N*yq*<4Hu&# zf{i3XjI3rqd#9&ddq9dQ{6Q&CmARUt9yExn0?E1$%349bQkRLHM2*D{I4Z-2z_>jG z=#hqot7wv)^pk&kZ$o9XIw9)uD@s*^5FYSP?He&{pm>}}617E=-dd2r(&x8{7do~x zjotbua&zlPeZo#({+VCjCw{fpl0_83pL4$-Y)p7^T4NH=WZNQ!=h|(tG{_mN0hA?D zw|Yo#l%O%@pvR)xHW1Xl=IiWhop6zXVH()}O!xEUuB*<{R<6WwpMKK~NWM>RgoA!! zs-aN|34YdCqr7jZiE{bgugl$^W8Ogwn7mjP!)j>uAe&%7_JZn4W8MzlXT31lfS9o= zf8qy*4kV(GM14J*kw$>mtA9?o_-OY#@~+dG+|cyB(q8xRd_)-hp_%pb;`MnJrU`^AhN0l$>d zd%n-_R{f}syugXP`&>{=UV-B!$*ImX3`@k_jHzZ zBzgY6{&Hry`|-5c-y5r@{l0(9hu&U2`^2<87>PAA`|8P2zk7Qg(B%*<)ab>P3L~cv ziOgGSPIdcCezDkp;*0dlvP>E<+<@#By_g)dd`>fYyJ$ITMcInm{`2zg@@nR%51Ge+ zhck+QPhZK>VNy#uRLT3Vi$@71QkeiwvaeYe8g{1Y(OLHS?WJ z8i-b2#8KLo{%y05g+E_KZRcwC8hrlud+_X^Li^ABnOESiiS0zSiU%?o3>zTJKzu(G zcQ5KjwSuaf+4b(I&o2nFC7c%lQJc#LE#B=tg+SMqZMeI)NTtmorEw;In8Bd&$txDl zCbk{zF<;il%Oy^K|N7!c#6+1{{wJ-pq?IQ%7UvY~+6-C_*Bos1xs@go=W{*aPRh4E zk$AtGVdIsC>HDI`kKT%V(VP5R^hDsD#LZ{7(tR~CmOGygxRmxF%+7E^|G0P#1z4r; zJZnvi`h3OQ(&FC^d+yW9z2px+A2Uq0<%)+2pPF`D&IaNoKlGg#*==M+y2Midj~cBz3ZY0frOGqD25h8?;4tP47~^#1O#b@ zj))qhHw^?5K$OsnpddxM5l}$^Lk9tkhzg1tnjnH=qxsd`?B6;2>@#!EIdks4bLakX z_kYQJl9}Xr%X-(l-t|1kQng2aOD9HudeP|d;F3&I?B?6zE zB!-zVQu5W$G^RF;+T#CYp*MN&qikvAe)eJoAL8WSn6|DGp- zH}|DB=T?sJ>52rUGUu6wR0Cxafl?S;WlznQ(_YNee}d6Ml?NLEDcYzMksnIS`J|;h z+qSj4-LDQwYc<0(lMD2<|-@ODoR7+Q{2=<#zlqsZRZ?g9F4!uhrc@I`cq`sJMzy9 z=jHjy4rk8<-@@5|tES>}K}EjBb0L)(>Q)T5l;Stxt-a!JBksK`etUju|5tNZuT07O z#VOMR@1kG&KG2AqOF8g9exD{{7M(7 zGMr23#Z1K;rHk2`edwhez4xU{*G&JSm&MM(%9it;%p`*26<5sdZe}+CsbVL|)nJFg zM8l6|fq=!AjC}gc$HELu`P!|kAKUon4pl4U6zdH1LtW{oLdt@I8Y#hycmk!UvH89= z;$_+|K?qKz+bXZ-rQh|<`|rSNwQVGJfMon))+kCkall_J_G7p0!IZ7W)yk0g?Ix<* zn`+ymyX&d9C6xLd_1 zqm;9e5Q<6E7_Y?oVZPhIa9y~-vd0fxF1X(yF_tgl=jI6tp&Sz&N79o@pYb!4J}E^?B2 zHMwU=-glX5002@%XK&>wILaGOvTT$A3s)m^ylG^TL~`jMthCAE$c9U4b}tsKlm%AW__647Y5mQ1IV-)R9Ee+R;QgLx6|EGa0#5TO&odvz}i zB4wQhy0}J>PMvXrWqx}QV<#`MMs_^nHmEF=3Pk8JP|*Bt#}LeD*|gi5g~S`fV`lOP zhidGh5s^qw=2sF28>*JTRsEh1#MEQWVc~Qh)2^k13jjA)B0U?}ce`YQAe-sdUU(?B zv+C)Omu_~t4C-Ie26J~QxJp`XXrVGV+s9U&)9DhG|23P_7)UEI(#naR`6y``gG8*e zuRiXzO!%cTx*KNHnuByJGg>Jy8C7z7&?nX=1sX8;83{i$!>;A_W}zV~Gf{tQ_gD#472~uK=UqP zes=K+P*V{JEp2yJ{`su_2>^?#0?Dl6X`$249d15U0=M3SB#@XCv2-5H-WoXY$`6rF zNzu*_&CTdWZ{L*7Yu8`10KQYtYwDjACs#HB5ej@DzxRP?o`9>hK6R+$?Ut~@b*@~) z_|rT_NwC1s87~S!C-ucZ@woL8& zdcX0#AZ2!BZY*z_lJ2`oBh)d3H*VbGtGlJYmpdqu4dTioAhGGTi1;wMarkzGVsJ#D z&P|CaDoWtm^z(_N+E7nPzOT+_t1@G{j)=kPRgp6U z<6Cvs!tL2V@|Z7Sw$>Zpa)Zbt&p|DtN8c)$YNvf4tg;=_y8^|0Yb5Zc*!vZ^T_&0Sf6SjZp z(9wu~p;KWNFq5!&hbC5}o}27b2?2`aBpfwQ{5-L?f7EC|BUgSDMRMl% zaiP8LjLYp8T|a5+H+m&b>d5`P;F7X>>h=Cp^Ujz%mt{7-3i1PF_jvhu033jZAV7uZ z5a1vHz|R3x@=Mz>*pDgvB5E1~jOsxeN6?|LfgzWR|D+v0-{A62A0uKZ*wTO;l}}P} zZE`F_$iVYt?Ujc5GvD`IH;8)Q8TUoeFu#&h z8ys#QY0dtzCZc@2Psw*bSM7DBDR)47Ktb(PM`$kiZo!zHsFJ^R-#f_%p-7wFG$)>= znsbh=R=*e5?kan;Q?&Z?UmJjUssebuIG)%PXD?5mpR z-Ra(n+fQOlAAMPw?4<=S4)WKX9KATT->H}t`!kylB^wZOg5h^B7&R)Sy?oC%k)Zf( zM2R^gcTm~2rTJN!M9l56VefACtv)rRuC(^`2_j^f+fVgZn{Oa^Y-x)n=9LHl0R1orH)xfPDU|jUe?>Sh74!B zp7m(M*PR#pT@>Nj;4x+9DCZe}>op;}!DXAe8;Dh0?#T z6V@p1IzeLh)A%CoPTW3J$<0tNT3?(5-5QlF|2`*W-@a^@vP_Im_XHL6Cg1{}q$gac zcv1xM?yDH@_~=x@7xR7Nj7WodwPo}_a`##+c7a-FT-cj?89r> z3$}Y~5AS0yic72zXK<@#Fo2A`QgDbo-9mP8EiMOt#BX z@bR1aQA*v58d7SaHn~s#X)HYU=+dmNRgssD>V$&N?8>A1BIVZ!Zi-5gJSR2gT76!K z59P_(gy>&0cUw!Tgyox)*Urq4~?^{8=dJcMk<(+?Nnq!TMF*+>V*_+qAtb z$0^SBMUPf#eTSPZ_a2~#;C!NvoA%KOmM{g~Kt$B8?7e|hy>yE=#uGjP_B!8Y2FsJ) zz8eC0yQddCGu^EceRgy|$X(XyBCy)#$mbrBXU3n#P*05}=%qJ3UcThov(j;Z4~_>! zzRqzKK1D#8u$iEE-p%E5AH!gQI!B+_#<~mmm`_8cD@CdwOD_HQ^{mx@v)>qiV<=(A ztUe@93Pl~|* z9(%n17JCH{R@EWe)1PzS8bqoc0<~lIb@Fbif1}KB{crzz|9|waM;P~<|K+vy-X&0* zp|EaIrMMv_rC;!W9MQ(N$X~6#7YX!b+eEJc>O0&#*`cHz}+OfK0SC7Qx zi>{m0yEa=4zj13m(PrC=;*)ZVaH;aY>D8-tui2|PD5|_pqGV;hA#9@W-J2tt$GcJ> zN{zxbB-HK8dmp)12WFbw>Sv_uAMTtbVkqpDL618k*HYtx^N0Uw^XrYjVeWxRI_1)n zwDY&FzGC*GA2#8MugUF9+WMQ8A8=j^>9L?UXXgYTJlfxITR!_aEy7u!;j={|-lSD;JL8j{gFO&P|76r0+oO_=}GY|4P6K zA}ZVj9J;TY`14;0ST4orf~u>s>rJns^}_I%4K^K0?vsO(glAPCJr1&<)&V$ zR*OxeoajmX_1<*fQR3VC=LQ;o9>v|!;m)o<|4xYh5@3kO<2^13X$jDm@JbK1_hX{{ zUKdyH$owt&YCEsj`k?mE{`$o`W+0ybz~p~gPygqG|NTvIB-gS2%MMWezdDw=GSB~d z2RNto-#O<0f3X$-hyW^ib$R}+dBhRmHjlV_XKwT8f3bIt@Z`12%Ttl%(JH$bkY8l) zMb$_+Q9pHE@H9_WR>$gKkzR_RjDuTkL5(wJefiW3(H;xUJ5uQovoM`;!exEF5&7wP z6LApLlBYKRz=$w>(eZ@Se7hv%X8k#SU3sL*`=PwF=3;-C=R!}TfDuXYbszr&NhK44 z*5oz(#bizt2+u`!I(~e_MjRlTm|W8+Rmc;$NWJe534@a%3qn8 z_5FQ1U(z6+{{SYijrrD3glF!m{Fg89c;ciuG!u1mX=cV!=E56d%;V~@7*2;yCHq{S z^-P4wfomszP{!<)HPS%*x$pThmh>W zboIy}w_VrTrN}#o`!iOPdG%(w5(=5vRq)KL1uAf`CK)~iIxt%r<*XZwNgq^LsSts} z``^@Wn46Fz1r9*7(?Lq#=a(i0`^r)$bqXf=h7|Iq7lJ8s%RjE&0oT!|%zo!Ay|sv& z>UgFt;^oGR{BKdR8!WEUJa4ndxz6zpO( z9vz)?JGqb7n?)Tr+s8^98RyOpw#TZA}WEeSP!` zDwkfDBd3SYFy->B|4pa`w-afGHV^X95%LGWU=ia#A0P_r6a+ljHYW51JXhge^26GQ zKKGa?6mSmvsoO@dADEl0K=G3-J7M}oD+fj81rH~Ue&ZA$$*j-gPY|`|K@8;~Vmhy4 z^IWYA)k+W+3(n#{*D6+j3L8Z?^d~zD&l_1B$ZZqmJ@PxVa$|b|L1N>{;C`T*=d3Zy zpJBBv^~B{#bor2Izd)LN#X`@E(F)Q2;6B5wor-*3Wrg!x4j1S_U`dO$4X^Dunf78$ z7%?ek!zDemH5p31dN!IOW8BH-64Go`^zP#xoz@ zl$wpqO{^HSU1!*ujpT`++*ek@>taxdJzIzTr}?NXVZDddSMkgIs`hO8lY(dHq}XQl zKdPZ&TcC6`x38E*eh{j0ud*Phi+H*?A|;fcj&rP$dW*g#`!?hGUg?6&F1DJ>D0fp~2mn@X;4#`>7`SLA#^>)j zYIZ(sEDHQos`*8gz3>@lprmHGg;jv{f%cjRlDrg|F>U1{pY_gqDFM$+J^bFqF_F%X z7cqt`jOATD%N6c(IyPc^AdRAC6^I#bu?1fh0fo+kFg^2ihUGxlRE5-lVJlkh^xeUz zDz#kwNbcw!+u@LjSb{TI5ZVNwqB&t$(Os2_%`iRs%liUg?%Bq2K!~9C$O`y)!yd4_Q<*U5xOiCX|Gv3g5YJq858T z{(6KvTC}?R_zie=Dv>ID@IYXZnys17Q0d1J0H1*w7J764lynst&gW<|ggsXQeOm@e zCCVO2o~5sNdGs9fY6aK#=U&_*@)0l-alN0z(p#_+=^eL1ZwgYR&Q{$OMYZR?1o$f4 zDuon*En(T9Vf1o~jL8h3ZD}n`N7`_FH|x1ub2bvoGH>>QEu~Mwd==%>AyZFmH%}D# z^1B*A-?mL%2ssN*5S+tGyl0#h*bYN5+E`FvMB^HzhO6no@HKjx&!DRz1Lw8K+g6ImtVwn z4d{Q7MVQ<=snoQYu0IxeEh&kA;WMy%i;lgQY9z>Ps^PS(*U3pi ze&m5s!|6!)MNdn_!KPG&E?IhD{o=v>szcO%Mh>YEB(uUls?7wXzu@gSF}4fVopnc> zL@Y@)cOeiD@8@!D=j9jiJLw8+Gur#wF zVUUd?Uot4meDi|~ZKs7SD%A6)tYcAGdTl{+sbSxMDr{99@JWKlh4!*F6@ps=r#}VQ za#Ut;Fj90Tda8`N*gr`Lw(E1WSNTV$3rBFhNRg5YPT%R6cXBZ6yLFb?q&g~(Obh;2b0Vps7OW8)U-33kGuX8GdXRL_RJCBc7f!4nJAD+$WhB))zmIl|U62N!jqh%>cNYUEJ~(loNf_pXl%oiTFi?za?L0k-R{nf&yLS z6#%@4gyyY2@Ak`rf9Je+5e*m3H-&_swT)vFg@mGz-*sYptpz`jU#ZdULyOvn<39 zQVs_R8V49LSV7hVQ#O-dl3=oFeW(V)ucr$Wrv+t`-B>tW$JRP@7LO8@oYcYkml&3umwsrQX04GYI8)#5Pk%Y02>KR`K(@hJ4|+ zSy>15=w@F5Rlk>EI4_+)IM_!|RbmXHS4ZbF60uFsG{6e&aH*L|2Nx9JmC8a#@_Bu5 zy4F#JCY)c0MK)rdZq~EJC8<_D8V|>n`{`uk{$Pbj)xrNT@gixU+ua7{S;mzBZDf>8 zAydcal{qB6VUrp1m332U9ln3StevIn9In+$AyjW^?BR+pHz5}7uj_OP{vgyBTSDPh z*EV92U%(e!B%D?DHQJ-9p5l&Ut?E_*bk!~BA0&eDx_Ac*OLkG6CsntLByG_JldCHx zvs#}?RJOUOzG1fUizKbFRTnG;E+>|L-D-XnAfVA{A2!5 zU?aiNSsx!>b#$K0V+;hvRvrCaFHa=HcbKq*Dj*9`SSSV;_!06@HJUnf;`7#tV9o$2 z9^0<1UL+NHfPDnPK|+U+@QFk%NxoZ#4X`mR?6P4orL$a}n?=|j%ShEFfc6S5cWSF> z69@aA2|qb5f+t07SHWM9p>qI)yQQykF?5fB*w{kc--3SLLhLYwaE#J^H`+HISVC!% zgQu!J4)(ayYmkn(xtGKt@Hz4#dYJLK*peT}u;wz%JW+7z9#4Bh(kPI(&=o#`hfN>_ zV@dcy5&6$mi1{jCBn@<)%brUle2B#0s$du1!e5i2F9GL&vPcFbfwemL5LRdqaDSU+ zIok+cCm~j_H5}xjFtZQT?*$K;U5)i)t zh<6O=bF$~&mN;-@<8@4kUhULF?b8XcXzAY zf52Z8g~o~Sx{MYPASnDvJ%1g+X)V-c7h%GNb^n6(5QX}PT+<;45;D_U_dm0t_i?Zd zvLEK9cPSF_jTE))1^-C4)yjvLWWau3hh9!Vl#mQQ`D@GjNEzUvholQW+KCS33*&L%s2At~Hd zL7D&@V#{ve0r2h&K}B8=kaDAy3YkatEuBR?d5!h~RQ^ID-ZP-j0FPN)jqdE>{j)+t z_>ujpQ2v(!8(Q$0OgI|}UnIc_Jsw+?J^t+t3->nT1GauF#jc?*^y&%BjKQZEkN-R} zIvzBJNJBh*c-&j))G8J>z6JYEL}U#F!5{U7iSp>Vm5#&{8v>P8tw$FrDzlGM5A#cQlwOk661>!vLVQ%X;a-MXE z%8sqYz$U4ncU46aXwQki7QF8}%5@oDfc4{4flvL0 zC(xA(s_uWP0*~^6>XFYPjPI9Z2wW)U$!2T31BluAAEe$z8GIM(v%9joCD*hvwMX(0 z-#*BS?#g<5I-5*UJOEGJhmTbem8I!l{c#OPt`|ftAMpw zuUICCD_<}f-Dhxd78fb%d2x7?$v?*jN5;pbA_3GrPsQ_fhIq0(af|cFur586%qML8>_ZWIlK{?|k36 zgD=wuf_!yVw&urd5MTWLyIm1J+3>=ucUL=^+W;X+fRK|bOp*w(i-D=rCAWxWo zB;qR(-m=w?V?}*uj1ZAvcYd92@~_VGm_VA z)P~60Hul8pOGq}3%o9t3Z?Y`=`uT$9;n`cS%L$gR0NAhX3*RFIXB6%m6tN@$5eh7U z&rJ9)SL9%RsG=Jxy%_!*3Hzw>a+tU1cnseH`AtfW;%979IKbilPL3$g$xUP(N?2r- zv*Pg@N2AT4)qx-pZ@4?_ZS`}8QvpnY(Y#AA?iH5Ue*vR4y)OW0-`zOX;iGq-&ZEcR zNu(Ps5*t4^J`8*xky{1dtWwzNkWOGf9-{NaL>~3Q`L6(YfzCV=cmr98WeDTEbmhev zFQlT(v8i)`6D;^D(%vHLR>(PNb;iBzD%@x=ZU>2o7X{rnMzqkE+_Co*rj-<3vxok; zjlLt%&F(cG@(U+uePr^PSBt2SHiVtfCImQF)ILec%Dac2nIke`xC}XOYF04m5MSuT#&^ljHHQTC8!A3V_eFk8z+MZb!wf98PUhd+sTGEc^ z%S;KkFao+~<7I)Eyb|1DYfBHLhO*I4`gUl6negTP!(-Mb*yK}n*^YXf-y`MwxlKvY zg`Y+0X()&i?VCm2n1o2COx(^GaNw>*>+D_g$ZHcNhaBgtIpk9N2Zz0~OHC$MEO&Ch z33~t9P^6@4Q(F>u8%_;+2#arvLWQ0I;@^!aBC72RJjM%E_0G|e1T=8d>* zdWN{y@Cg-TtuC@^T4$m{zidMpYi?EIi6kiPTFkb6NJdqF-Eha*8L})Gn~glHg5APh zk^21iRCQVMx)$GKv|Tr3STY+>Q<40%J5391kuX+_jz=rpNUqPL_bk0X^Yy0WkpCe8 z1{v#LmOTHQ0$D5O3drka{-!}LZk@SZpwO3gK?Pkku6)B@uvU}m?zO?|RCtnMS$Sjo z+hn=ujb_bfVq?*xaFZ(pd71dxQ=u|(7k_JUnoL}qEM!vpo)aZgwo|Ps=YQJMuJnkn zbh;it$|vTAVT|9Fv0r0?5c)=0s~A5bVBl)p-#n!Zx|P?;%>*NfafL!h!7~}hUU$nK zMpIQ?g{4VE-kRVo9aK@m`rSIPp6imBBAW3$v{F5FtVSle%SGPZWO7XDV61o)4xo}42snpuF z@3Q$2<)((}Y$8MWc16_F$nfh`win|#>iH>}0o@UPZIH5fmc49wvQ2SWt)$U6jUu!| z`FKl2L>)gkG5~X?FP7cCCzHTzTsWzGg0Nh6e#~%GI%d6bG{2#up}HffO5jZ`IzrVw z7k#LGv_y=Fx4jv0vLV$WX)LM{C&J&y;q-Zm)-kwWbS=wII+>t z#QM#Z%H%eeLRDIc#N8JP+4vJOxFdgPs<*4Ai`AM1hs?{9H}XQILp8KOU{&kI1z}pV zs=m8UUq4hi?_;>T{MxzS$`zX*_LL;7ndBH1X^kw1nWu*o-a16P$Z*tbNK5KUr=YHC zKXBrsY;ID-pp%FL*laCTz&c}{b7Y51YY(eYU>Ab$R~LYoS(l>3$w0C3-?q*{>DSaI zFR0GVU5n}IfTu(Unk(?o%$~XoDgaWY-d?daDE`L(_YXY&=UoJp12pItek%RBYLtAa zK|%*>XWn^+MUfLNMBH7%Y!hvd#HZ2}n1Exq%)$4K?BqoH2oXcQl7Fm z<)pWBB!6y%n(vRYvcWaw^cwib6NB1K+L_;mdBJY&sN!&(`WZ7_B38FhF5O&a z4>>BHaZBllFC%#kFKyKG{6GS+#n!e~N8UGxSBPqz*rD61%oiHx zS7{uaW#M(UWD)kYWNED$J81j!T$)9vlZh*@>BfRn^&(V25x9&o%o$Ay)p65vR zaG6uqKnH(#j_Piam85-c9fDk?SvEYZ_9sV7jHp)w#9d9f^tp;MxiI4UFZR=_lT47S0tZC$PzNOr5CyHu)m z5{WOZ!A(`{B3mIJ@HnJ$=!C$Ig9bsOe*vc8;khB zu)WpLI1$iP0@34311n?|8e%$Jev@Z#UZR39PhHpNEg?$yM{Vw^^6|>QsSRZ7qp^uEjS{d~G|dwdr>^ z&nXXzYi_D*AZ-OvZZ&T4yT0~d@N}dD%}ar451S-C0Z$a)zh`al_*!D>Plr;EBsE+;7h)%I`j3OYvH}n~$l4w%xGPAr z^^g(Rv(d>n&xr_fiR=ycDUgVKmG9{6Ti%KY?Pt%4Zjn>6RlSAVNN%JdZ%IxjO^K_L zsn5K>veW1M6=m`+ZQE-8edG$Z9>HvgoOj?Dov0M>ZxP3>1m)>!3d#!^-En3`Jw9=RIkFH<+`Tz3;{w zRxGqDnc5~y`9sY#)BSebZ)5EaszqXYj;qeKrBt3K!Kn#}IR5nC4hoL#9mb$EXFByF zR)rBjv$yNPS}^pz>huhC^<6Zcd4f@yS9rRiF+|fdw{-oQV7q%c5?i8|>}jvPfjaaI zx309ySek_JWA}~$bw@pn-GNv-ukje=uU#&=8OX|caNVIy^5wBE2bXSyxa>|l^b*Y3KUfSYO2f+u3W<2N-q(tNE*B`!QO9lsbM7l0v3FGR~4@=EaU- zFR%dT&ro9+hG#pQZwxla0w4CuWmSVTvcu$0TUkv!$;T5iVaK@S&;a)wjh2oKrNO3& z{f83*kDk7vJ!n*s%|^#Yr;!NFE2?RvE{L)SjfAC*yV4@ZsGNXq{dZcZ-m^w~4A4R~ zwRj0=PeLPWtWG39HVg0C>rb_hha{I$KZb*;bpG#QHeA9~BYH+8LFRmB@At^kFapS8 zlH%qa??K+SiUsz*CcFMwaSH3_$C{S z7tH?9AdQL`CZt>QHQ!wJ?h|OnNhTk}Zzy~!$UsIxjgU7k5bCOC`%oQMMP7idyi&zP zjuISG(EyOi7T>noAiVvqN;vFhH|;E!Tbc}nA$2tcwGYc__pUwWi_Qt@DZs_2hlWAE z^rs7*Xi^69qBMkWMKU!%Yw!M$wq5{QlOV|rBOGE6&3{Hb(5Du+bs%!f!oso0C=+o^ zyI(&$^?DDFJ~^X&BC~rEWiE;7Yw15ZU0jwZbnnW*S{m$p{4rDl*mqpdx2E)n zZm~YEkoITloE`AfELJ)b=!WjZW|e9RsMLTE7qCDq(FN0xrrwa2Gh-*8CmO@fIAh*f zN_cP?TWZUwJxe$M(7JwxP+}}6P$NVQCY&%uTfdVPa2-Nn8v6X~Q_CtKb(88wc(9@( z*ePgKj(9LOKCA3*`ZQB3JF+nw&C5v`qlMvXC0XEP70DZAQc+#Hqbfq8S4LjnvN;PC z!1v#}$fWsWfqq>OQYIvB>qN(b;myyDQ8Ojc|1@_IEK9O)*b*{{o^&xRb*AfK+1zN{ ztP%0s!^wvgNhss?8r&puI(C64D!y<<3UY}_OJTShx$s{Oqpjw-*yI4i*2Gs?GS>1m zN;D6eFwA9Yh2LVir)A6&ho5XYC9i?Q%z<(l5Qpz@Z#?x_moAo$lrYqLc&w~5?D>Hd z=Ustb=PPagSgNoF4;H7{u|=Izk^6o3$fKSP{DK3|BWU!N2^y*Yb6WiLT2@4+Yq)?G zwt<3t{zQ%iQuL(~`6-+|bF-BK(+>c6RD9nT01pWd4=|{6?zuC5Chx!#kqxYtjJD&D zn_~rzLd1iIuDlj4eUOZ$?KL?riA>tl)%^JL#m1@*zP$yK(8j4bX`kQ?+TzohMM`6V zZY=nXmpO+gXfT=VH_5cOx+s1(DVqUER0GdQCa|*`BC{ZTB*yh^_KRE9Dy4=H4B^VX zU7ETl!Dynkw2SBbX8MH~d4)Os#Y~`bRwlCoDK+V0lxSzfEa)$C9XgiPTjXiudAu_0 z*@uNxH2H=oKX|BrFhvop=tMQjoQ|Noe$Tmq-^vSRIq<~z@|YIuT%=lASe=iDL}Pu? z=Cq_;hyxzTLEEL`Kh+9M*`X4Y^c}@pRCvtK(ahPCq5w)HK-M%9;}9km#SapY1)jW1 zi(x^P0cl_nb5UfLxhE|y6HHg}>jq#G;~z$^&FbYy9g7x0)4|lW^beKJ7(BEj>;yH2 zmNEuO_B>gbJbguA-s&^&DK-xVKZIscZYM$f0%q*q(&844jJR}N6G#+^DlW@cM}N-# z%2F6G}goqDG~!7+@3?Jl^~ zE=Vj3WaR_Yn|&A8g}UTVyM(1l;xfhXsaOk$(>HibgNf0uFRF`6TT2TfiNv@&{1Qx0 zoTY`UEPnb2V%zA^jca56a0V^B2IUL2S3tbkj{N|djwJ3i^1y{gkWK(ZlTzan=<%G) z$9O}F^?dv#^H@&nRk1b8SRCa;Mk?G$Jc$W8r!q6WMm4^7Rj$+`EIjAnH6UsXf0G4B zNz0O%rVa8Q6$gpNuR#v3FH1ILMV8*74$#8si~GsfiYvTS;eOE!2bZkV;HwI&M?zT@Zj z>jV?&8HLwU_kU8K>~Rw{J$aUvy#8^bDEAnHZ!eLkkE1oIpt^~l)|+UrJ8Ovs^4<-> zFg$fWzUa04#xVGXPFwa_2A_8q*wh&D9Xp*!qy=+jAy|TmDz|m@B$j+{3px4aWm0E6 zAyaU$R39x8E2qrLzKo;!@6v+9XqOvkg83O_o^#oasY?xz7(1{Zo_f26X6WST`yA}OON%HKzw2Nq zvHfD_E>-*t4W9`_s=^k{vtC9}gU7%_3)El|_XS0T;#Pg#P4}J~V<_T+JXP(!Q5C?w zb?IUBP|II}Z}?sSg_t33Py21d=Vw5h&ZL)}c~Y;Cs-Bsna{u1qr2>N{ZgYgs8x00O z%~}f+jtc|(ZDo`{qDAvtDA@#cbMt@vuCQuT>IM8}IGP$_N26gOat>)xU5CzRMvTL; zfU6j+Z>c}ydo)qWvlQkL;^EZ+i7%y^aH!M7clxS5gMr6R*Z025%Mf>o_G9yrO2g7L z<>>CSdg`!_H-&Ol?F$W8DfGVi*yH;ycIWG1mmOdvHlO;lq6%gze(lO6&y~QFp55pp zp>#Pce+6Qcs%q%}B~ z?wo>bw0jRei6eoXF8t(tx!1t~cLNV^eNvH>pBqgKqlIKf%+EqngbUVMaxRv_FN{Tn zhlxd!7-(DujjiIW)j2c_bSf>Lyw7)vkr7daC2Pivg;ghJCcHrpjOZPYS)&H=Q_lcw zlS`x4{ENq%A@SrxJb~#+;gBG^3^zR0GLmM};4>orJA6?h6c?JZ3rV(1O0?sn14>*U z((a&$u}qq5{kKJ@)C*g*7)HAoo_eVPVxvO$H0M?|)^3|93 z_e9xXUzs1AjmQ@JyY4S7Av3MS!3T$vPTjabx-&zl%)n!`pH=SU@pceX9<=2rmqLV} z7`?Xr9luK>-!DS@K`v+7>zVL-Thoq3t&VVY#1z4o*Jzh!X&JM$ov#p?GHw>2r6DCR zZqcFu{8(o&irW(!X>r7Rp)?duM6NBUOp} z@vVTGryuT%T2EF`O7HlYUSHqfhYDCt8C`xF05u5{^&hB#B$%YdeUAr;8SAUm) zVKP>n6w(5fF-|pT|k}PcFljuYEAKHh~W?iVy!yp268|e}3@wli8m=9Vqnfy(NVHhD@i0 z!QX}-&jJlJMBax)zEifp1W^R?>hI46795?*EE?h}(uhB|`mtQ|>gf31i_=GU=WBAw z3q9h4YKON6b8~dJDOf>dfOScL&WIxX!0iRHy~(cbpj5c3$i!puNEKcGc($LCGtR!dLEu=`|vq9lAT#!-8fUeugI09@Opj2}1QtOY* zYRCd}%!KruV&9SwymY|KV7wHe*R5@&ad%iUNuzySa>WW|J&U?#wAtC=Y|uguqKi<2 zqu|Dy4LVNBoMavT6G4ha>jtlVBE4X>nJ-`%cf(Xm8BSq`v++hn$5jP`!e7T#*jB%v z8TM`EA41Q+)SBv@zD2oO6kK);>5X4|?qtByFnZNfow?+Mx$>P1IRaa~0yk)%HKd1g z=F&k=_0fO5&%=gtC{6h~5(O;yLqUs^6UqrpTfo zt;J+Z`%CY8q432l`DG*h%bnX}-yp53)X{CO8bqlO$rH87>8TZujzk0TihgSz* z&%I(~dQAF0bL==$4RR^CK$*MIpnukyG z_*EBAcR#CMk}PK17_7UMn)?V}StNV=D?PUz&XPw5@mRpqA;-g;-n+yD zu8<}VpWZI84nDC9PYwb(3@5&uSdJ>Z={6YjONe&(K1d4ZxkRemU2q8}3PqAYB}i?` z;XeOsH!DHXQ&kiOnJX=z(khh*J&10qhBuwklzG8UgBR63OZnb$bHu>{8c;Xz&CcmH0fnze+F$tAd#XfYjg$0yxH+AdV)P)-qgbqiO*q0>F9= zsX`m$q21x(&v{HWlhsKSIdp%fIk_6IU3un^KM|Zp<@8sp`fbY7#iYPboP)8Yif zq;?3)7k{O}T|-j;)TxN z=q^tmIO1?;_}JRfOHB}CA7Cv<(EhZ!wg&TB9oQWkhS?sHY2K=b%ZN2G{vH$>&jwc&>si_}fd)VCUXzwQ zOZgl&b@s&Ijf{uYU;_g+1$!aA{@B;B(De}~mm1e+C$;(9g503YD%yu~8%x^^^(Kw- zgKP7Hm=^x6OTx_y!);iP+>EQ1kbQ47uf8rvj|9T5C-MPLZnu}c+i=xuS$GoWJ|aGB zF1CIB4d2^pLHm>@$=STz3(^K9yw|?v-V_93S$Yi$Ay-0PH_`4dvd7-}YWqe>`Po!g zN$j#-#MPXoW_`yKJNRvuFrLzvUi?cnY1zR2?HJ6d`Mo> zr{31xKRpQC%J$DoBF?^VOky_S4|OCLJb3vH9)Jv0zD+&(^_lbT9R(_Q2dg|ut8}QG z#JsPvGgpgous>nvrFg0S6eosnwRNNTgGp`W=VvNFwPh-l|2#kt53U$mSxYtN$=o^4b` z03XfcIxj2-{=GUmfcn)}(h|-2Pg7=V@pEs_wWDEKl~WdtcjZSC_jsMW`tZU&SNoA_ zQ`aIzep$-B+P`~`=05CQH2e7L=D9Q9uYK?RY$vpwWEpH$ODmg=E@d0G9XOterYiRD zdyqZN77NQ%#r-qI1hclb4=gv$L#s9vU>igOCKif572;}fs_-S4n zY$n<8A7A=LeJokTX4(f8qjmT9#JRq4P56Ib_Wf_`)&I69FS6mDylPR4M$mY>;r9C9 zV5uTt;MYO#?H~JvuU5|4|C=`y@=xFR@cn=G+vPGb6QBPl+!opca5jJ0LWAzg3Hf$C3JrhQ z(#HI{f9#Gg!Rt#rv7lN=+y(L#BlOjjw@?xqnP1U1Jid-=B*%iLe@LXSu zikwBz_sOur#Ic&^VRFz~UyQ15HpNgyLjP@;%vqwrb^qF13cIFju-VE={co3g_}a^J z?Gf|x9ene&@OFl(uZ^l+Yp85qc!$%xOy#_0)?tN?@OGxq+dv~z=>e0_n4uI$CgAdw zwpsWci`;QC)(vEdJ;g<<2a`kD|Vow!a46cmjj=|tJ3 zrgl(|=IYCLj#b>#wXpko1eV9ZW=6OmDeB8px159O^dEbrsOogpQuKE0Km(=`PPe$V z?X%^EDxb!)2CPg59?MAhJ)iaVP_6wEhOFziDsx2Wzx7-P%$o;H2J@^@`Bo(Z&jKBq z2VKl}c-6h?KCy>>GX|_I1|Bn2%?tVd8d>x}R^SH5bYfojML@^{CCfs7N8(D2HIcLt-f)DgY&O z6f7EKhxu?d09pYgRWe`%4iKzD_TYlW0gxX6T_KBP&Vj?oihd30K>*Z(qqJRXyFGA9 zfeb5Sh*glq0?A++Ams*2pkBbV2-*JqIupuxvOUM;6C>s~qi%9gkSl zCo7Fx+d#FOpZl|gN={>L7FxM}HA;-?S_xlIEAcNHAKr%hUA3r~3mIw5ZK^N#3ePzk z6Xx;JxA4oAk?7D?qFf#^%UE1hK`YE7fYN(jUvEI?%qzQ7_4LGWnHg|*<42phFhXUd zd3~f(WzPey`i{lZpy=^Hz5U91x_4DF zR2Mi%Xw8-7D6AYqNAGqc>MIJtRF&F;tYhr}z3u-E6%^d|gHBraYvs(5&D=6AqO~rB zXjj?^hjvf1QZkpyCUi&t8~7c~3P#1?8d)@_n-6}*^cu*7FX!klKx~$x?Z^GPDp+>8 zj>Q^r&B%TdpH;`n)^{4%Z8PwDX1E<{mP?FhNOJ1qP;)b-tH@0KgJXOp0Yw!{#`;kX zXoX?o$ZzUb9n3h&PGG2j`(7hnY?eu&G30V70Kfs8a7EHNqUiwMX8F_>^V7DFD>thT zbpm6{IA@lL$JRqZdYn%|@oHLRY%Znn1O=-_Rx4)0{4((WxOl&QIr431oqDAvve-(b z*d_%}W~lBMq=SKDQW9trmIVQ2IXPg@Mo1ljoR%Dnk}0Q;AvmFaJ|K#w4QqF?gZDp) zlWlM7EOWYU>Q*$-#4{oGjDgG-U$EQnItYv52G8%e7{=OUzuNq|_g2E!g|K{^e%s-J zLzy%m8KP{Z>dClV;bPd`=&O?PLuX0N0~%ExXSE#!jKMreX4~7JI-$?)-gy#OyY(D3 z+F>3ofOxv&SUsQ^FY>ffZ^T%`*Xy=SQ1#X&!BlVD*u;u&45~jx7%92u*7jVPSze>a zw}igF@V<_?$^Ov&&Z;urU$v7KA&&Jj-$^gRYTh=Hp-$v48@Hw$R!xQ-WVFhAW%$^m zMw!RIrKGdzeq3Y5sH|k-uUNy&BO$-lm{=z+QjV#Z$ykAhrQ}sgnsi8#K z7QhT}F;@l4nNMP96?2u-8DbH@Vr={_QHEwZ2SQ^2#Yvz*0BZy6a=HzvjIrxz`c%mg z?Ogl%Bpyp8uX^o7!T>9YoqGy|dywEeTrC+PsjwM{W-xsPH$yqD1^3vx?^5kFYzuDQb12-Gn10n64;u0STYk7`Lq)77I$f+5Yjt; z`3UR>0o7?oo0&q$;Y1`r*)tEa`=V&EMXSr=W+Z}8^nm>6!vs%x3?kr$pR@9&oS0tR zfI^-(>z@kbKHyr2{EwSX~6im!>Lh+(!eYn0%8>G;O%xYWuX57 z<^$nH6ReC3_TxYz$Z#6~$^dR4=3v1ba2e;ENVk{;*}#>6QDU4E`3(sKU=haOQ@Bjc z-{vgC`i3EMl>Pbvn>E;iG2qEi zC1-$gxfT*aU3mc)hybt=2GA5PAlffg0l2Y23YlcQ9v70Dl%%_OYJ)4K$J8MJU?;G} zfI&W*0wI9a7(n^`9yuyVM>-@wiuo=cD8C$WbDJr;`Q1j`6=`zM7CPX3Wv+J^Y(*dV zQ3bK8gIJm%&!B08H}s?LzKpj@ zQ0vqk7lorml{n%4ut^ofl9z2Amu6YaQW@UUrR8AG%eVH-Hz)NsJp4&)ny*ADb^a|FP~J_eTahSp0LeZrp21 za6DwO0=IR%|2f}k5E1ZwN#v@dUFviBz4?|)53g%*&DgAZj1$6QV8Fs98pyC%+N#G- zj+qET-?=%NM(kF~gxmyM@kkN1gk#dULm%Jz>kWKf$hQ>qqs7;w5{7qcJwRXRiXGi~ z%-(D&|Jl4RMeg-+?wTNC;z3BzqnKpdBc*4Ksy_Uyu$u7jus_@o(#;`ub1)?CrGaRd zl715tbIF4+xi$x5-WOv%i1BfU)At|Eo!qZ%GhpK8u-i%BG#J8Hf)YF(O{qdh6EbVz z;DGVMSe}NXsfDA)kuq&6#I!MF;?qf40$3i?-;%v7RnV`pz>!9%0487+Lci2-Ut69- zw)uog0l0N7QkqPOi%ebncJ`Yi^QH?}9RQA^b}nJi&Ls@RauYgIcVRg93S%4Bwv`0m zFMQimHIAB>=%N8O73;u$d%qFaXlByy!>}`3Jg`10oB^tZY_;x<=CMZ_UT< zjyY(>lrJirXHpU{s9G-8oq{#;-##Hf2S}WhHBG(W^kh|I^msXKeIoLHY9xP-5FZ^+x^;5c&I|f{uDIt^*05Srh8S{ zSIr;S?GlY}+j|mQ@VzO21@8x<3=iLvBWpey`1S3>|G0uRuHxoh_0ePo^=;LW9P zH{#R(&Jkbz{B;-+QM>wP^lE~9u%=Pv-Y4b>IJ+~#e^~>|3z|l!drsx_<*fXo=HA|K zGQX=x`NR9I?*BBNIajT3{#v0d;y37`o_B6IB!9-I;{LSc>h?e1dwxZB$zt5n+2{(Wci2=3Ry#l0KiS>GqE{viCG*;QjVsZOj? z2XUDtIv=wuP;O3a5B`j2QB-|NmKmWfXk0e7KIWx=Y~a(_7r6Y!TKVYQEA{dRX(h0t zJKMJ)GJXMxE|oM-_ao(AO$#7Qbbb3{HygK4H$^v4FC8R+j^8|plSf53Qe1Z3EFT!m z4FkJgVl#_S9XwTtmWn$WVFLZlJ?Iu>5ss8lkq^zZG!SAO3r(745$Dy{x*ch5;%@f~Trzlk zxGHW@6*%8X4})07b^#y+xedrWC`)k2cOrIR8I}eh;DQ!*rm?ojL7^tY+PIAa-dS@a zGl0%RekyrVC=h@k&CpowVkI0+#QgEb#@bSq>GMYGF%8#Fzxa}^c(i|593HlItKp); z*$m>9(+gL6tJP9_>R+Y^#D*T+^lgOSNL&7rec8YD{Lu9i)7?Mu3AwtivL5MwhOUo- z6a7Y1rWx?7M`up`S2^GE=U%l!NAr-dX_%dxa+p ztu*EK=2CLf=-WDz#-}<Fea*M4ylokm(RH!Xg=HdBJ|Y*S(W8HOXavD&EBR^?|)PNc!a zD<@1)`pc6!W)JRX#P3jljka7RHwYJE-R2b=-xchc-K-@bwGC`i2mf{x^ZjU!IM*28 zk8|K#E!7A96yTT!BY+|*c*ey{~VD|AB)gmKC*~OWNg&IK2^&{o! zMT0AT+Wrs^7fFxe8l@xQ4%*$$vLJ{<*9S#h7z|J_4-9W3JHBSL<`#m*W!$0x0AQ;3hJk&SGHx0GjC<;YaB(^C zke)wFoKPdC+;-4Qs4HODHS3A%pS}VLS!aq=tb#DR8FI8FQ0G6rXveP(&kfo@A|@co zlE6V-Hkk#Zk;V5}m)%@|16SGAN0rt^-5yL%TaPtI9{DjSS!dSZ)29ZMGx{N50@%N? zMpBD#UX@JS*SFq6Jm)x)w`ih4d~1l%Wl#_^Vo=*|Rs2jKh@MI+OlPaQoXrOzd}*jN zne$#rM(=Igm>K^oCMf=948<^#ijph%ox)*9>$5Mc{kGM_?(Ah+{9H#qdjfQ>nhaP8 zp3BHh(_o<%L$+_9Q{uQurtiLnAo|P;Zvdg`ckVihZ?}VY`Ud#6+iE5%uMtv%Y`9h+ zJalcpFq2fQihCc(WttWv(g$}0chRC~8X4?4ql&8}fDklBr5t!@Zjtla`&s2+_%oiP7}>zVYljuB>6`)bhTZ%9r(iegyl9Q3^`dw{yEw_l&j_T&Oe$ zMPM>8cFtLdH&%g9f?RA4%3L^d92`iN%QUI4&XHj^!HeXw^}7jP{;!(kU!=O=##DyY zf{E9!(doeiQFsJRnl(i-Z*q5^)GMHgT@dAv$h%g9Xo5GCqm}w+sDyBxozDMnxp2U@Is;Q=)>f~0_ag3LlwVF zg<$BU+|-46`E#M}k`pE9=Z|k5|C8&=QjmfK#<@zD9UQaYmcS~ds`lKM{d6EtU`tP> zJ2JULCLvQ8tj)mv5~yi&R{x`rjD$z?qdBHaD-KiK0drlROU(8*%~^Eutgz7mw^_Vu z#iJmH8$DTgUluhu(zWpEAzQub1?MS{(bEd%XQouYqc`f@vDP7-Fe;Q(p^9JZ?!VWX ze0~j63lBX%WY4D5-5BI4^c|y0(FsbML}fbTf3ajpHWB}Uh-uUo!&OV05W%W#(puaC zE61)0rpU|}d>~(|nEAAdlRw-{9BVG0M1_joV-g3Vk%C`V{AACjoaYLYekjzab*`nSvan{g%~y9LPv`G%Vx|^#N(Hx zG2S)N)446v9v8$1CPmgWVfdRbfff-i>GE8mIF}@*rUDM6RX7pBgR~VZq!xpKsRsp> z9h0x(`pfbC0B%(r6P3php=L?iqCL9xgC_RQ4v)W|xFB(ghGA0_#7q-j=Pb-N9hsN5OAQ70ax*o*v!LV8OQ|&a)tp`0!hl! zL9Ycam2X4xzz(mZ}`b}lMa zmMB%%1okA;{6KBRU&?B{4mM64T@%+5X9J=P0L}oUIN;Vqq#60(px~HJs2C1d?Y${A zGqD=$fu8r$T14Hgak@Kk=QK|X9!IpIhCaQ-%rKzX6Ts`(gyX}t>$AiZl?0j0+<#}m z+8HWvWA7dhZI81~o2{-|b>GB7nXav@UCR`l$I1^nQmb1;Yf>V8(3Mn4{Lvb|u@t)7 zm!Y^Bs@xxwywjq%qN+;+DNTeb&oGrgFmVf@EhUGoWg@QWn{5^MejHPZ1d`SR$zbc` zBap8K4ROLvMrACme;FkE!W%gqitnIk4S;vf{Wh2{R#M%)&Cl9k=1v=~PjID{rKHvP z@+%Y^mT!KxPH6*l!t;B{GQ-SZQlB0DXam3rxbgw){64LMC&N&p3fz~P6hJCmh;z$S zfprpfAB815knqPzh{yEuS-K%JY<7Zz=TIPuVB=Rrd>5s3o2bN*z|nK1f|9j1GDV&W zrur~HFHOA)L}G_9D0gjJ{JPD7r-&)~^z`KPj6nSAMVot*UahVwaE`PW2d1)9lse4J zNQ)X&`=>Jhj4@Dd+$vv+$sNM}dcJ%H5i0-?CIZP&eW{Pg4-+*~j@Uw_3=yGks6q{2 zUciR)_kDnB+*HfB&1RsXoLzeWaVQ0v)+zz#q1hZLgC+Y70Gq*;FOX@XF5-FYBTK6& zHsDbnkCo-r<5cckZx1PEM^^#LpBR`xk1sB4s1_%F3#nupCMixMT$hYet0C&CD`!pI z1~$=`Xi%KENaLD}oG}ztx<~(}>&HPNwRQRDx~5t`ZIX=eBP?w(K0W{_hclLj9f^Pa zpoCDY0ue@rcNDWFbfg>&O3R<9;b$rOkXxdyd+>;6QMd0(8FX)I(t2>s@y%-G;0>z) zKECP2;4*Vp9cK47r6(>%^H=Dm8Rnd4HO|CQ>nK5HnTZnyRy(!PO)p7lz4)sAEmVGD z6sr>DIv5SyPfDI9;`0(b>%#HJ!%t31`HMtt&H8E`QW?5VGI0tw{K=P3Dw-Pnro1h6 z4tkNq%u(KCDkK>Ow%*k5bN)gvgC#K; zihn@-rD2BeWt#OxoUDN;`4SE^U~F%bByI&*-hL?|a$90l`f_K0-TGbR(_%Z*al4nr zw!8P*|L;{Sf2AdlP$4=E^CHVwIU_z`JQ#qC0TwN!^K=<(@nWVz9C2?R2bICC3UpQ| zt(NY%a5?&MKs{eFc+>q!%dCOq#FLgAHADq9zSP}-4{Muf6Ck>D#w9N3l`J0#1416D$;8(@tFy;I; zXGA;!+O&KGh1E*K`h|ewjTsOy8$t%^v-2=kv;+rJEti*59xuP~(63_2@HZ4BHdIhb zglDb_q>2LE8x%IHGx&yZTE~7N3mmvJ74KsOsy_}ad8z5n#EB0a*k5fN0GfJbrqz1F z`0fv*Cs79<{y5lkTQNQ*_*qTxw;Yj8M*0W7d;n3#im7n@ThbfjkON?mBv0HcigH&) z{!6B^LQ2)vkHbPD>7*+yD-Pepr+uX*eIn z%gigbPi4K1(q5yOAb1%_r~)7#@Rm83&`=^Q;(q&+2N#b)BRVC#p1XXHm3e8xn)_<2P z1HQ;Owka-!Vu;oeL^B8tD^Gl{Pl#pg5AWX8r0Kx@2;#+Ls6uE6q4Ef)9TE}>ErWwZ zlO$VXPv0baJ$k)MnkT1CP%o@cd8Fetw5uM>xHwx&{o!*~v;6G2`lf$00Q(!yuma+F z@G8a`2m^hI0ErDF)UZXXTx1ZOdQ9hK#Tm_OMEuIAcVy;)eH3nPbXlao`Z3+iD>@d^S-_SXuM^Qod1ex2DkoE{>uVPLs2{TWJ)b5G1WHWtg5GNU9?K3InniLz7yK zb?+Wa=J2e(HIOS#$Q$UvO&A^T@8vm$!Y((+3;4=7KAyw7cZa9vRlN6!90_9f-xxdi zA=An_9OI^|pmf(-<)Zd^V%XnH5;NXPO$><;MFd$T;N}=`yBR(cV>-ljH(ocZDJ}UC zs#pfLU=SQew7k_$?VgVCT8NGerCYoKA$SR8qveVOSeGvW_5$iy%IIrAYG0(mmQTY} zy4R$#dRhrRLoAyWp4DB7HFrS~9GbCQ9r_m<9dqT_t**-~*~{PDFCVdd*%n}#7;`!N z(v&dsR6ur1#WD9wB?kr)Vqa&+?3?6>SS-eeB1Hq33dLO3goA7&^XgqNkjRjH`AxEz zDJ@bB--o++$&rC9AVA5m)LO!xGflPmG^7&|8_&B9CO2QAVPie+To;#$ zjKr#hMtXv8zq(xiXrx{hB#9+AoRqwAI;~#2T1tn4T?DpCnT_+mmP=`(ad~I`8A#ls z&#zya3ZQ9SCNiEt4Glw<`N85H#BpTTD++!h!G0I!I-m`H&lEgL0mO)ml5m)UA7NIm zsRdY9JZ;l#bxsv}1ZtcEyZ41jj#hs!?ODr!JQ#G0wRL1AjS}713Rr>8&(iWf2u$EA zi5X~r^Hq85gxNV2SXbyhb&yB^8U7K3G1G=?Q7pG>;8vg$v`}YXvVwr9f2*4xTA*&T zaomdgmdQZ?6m-FFYOEsdnOtWp=jjWkL@WlbfWyZzuLH!Lr$pzB7`&Tkl&1%WQk9zk z-Hcik075suxnwB7zo-`P>ldSPc2T3`*jmtET*amLVss7)71gV(B08$Lvwkhg8h}+> z_qA0U8z#_kAhS;gHMuUu2h|^mfs15Zl+>qHAZ*?n%Z2wc9)1Lw)r6W$+eG& z*ZDmg#*YrYget(wwc<79T z`A4JPfbY)dHt(3(9Yx^s=5fYbP{>$}2Qnt0KrXGIx>hpaPiKL0z#} z4$940+8|=~6E11$z-68LesuQMU)h6Cj>-KypK#}t0&jbS2zIfjAq~hX(Ln&h1?0k2 zd8GkB*RL83b~J{#fz)B#}=Fe68;f{ZXC!vUnuZq%8)nSb%T*8?XC zPs=w$C8*Br&wfb1vauLY0i}ZSYQ><=0SZEPe<{JuMEGxgusZ+J`Jm1?QYjyD1CZ4B zqGt*mfQwMs0y!Tz`B^UbU;6L1L9nDIPI&6SrmWlyw_L1~zWtTF{C(vK}6n*pb^;03;rYXu$uHgJ(%~$kG3D+uB zO4QF?FhU;gP5qtwxWYy~_7P$P ze?**=zfI3isH@c#gVk4gQ-`FC^umQjwr?#;aF{oOhVi2o!M@LIhog(Z;-zi-ifmW{ z;L4GTGZo;}I(J!*93H?VAZBO27pmC&Q#~9J($eN>_id?N)vaP?A6oAYm%i6-6AHnJ z(-^D>O$(r;%69E|X~zCb-TTlsMgLMmZTr~8V6l`=O%%r6@3ZO=F997@I(YnihQi`M z>1S%rO)PJ#NZ$T|-ICY$9g^%Q!HAbu@=|6aET%C7=6@NE4#}ldj0sdYIo_CC(C!L&OB`CS*rir@_^H%+j`=|wnD=F z)vcxYzRwR1##epM9yREB|LX6ZbYCY)ifWFMu`ATuO^yD);xn*J^(nXSZb<7_RM*{8 zoH-eEL7?LW^~yQSj!4}z`Dx*wlmMrpDI2g;6;|EH*?7uEb&pnEbB(K{%^YULWGb`Y zQ8H3*_uk#H|8^Nh#2i`YiXO$hbPkc%d+rK^3? zj5&?L+?hKtm;h*VP80fRlRosp!?!Bl zL@uPkE29m)Y~*u({QHi&?aoNN5Km_*uC|F-cX5#kh3$=cqW(d4<*Au6C_V*3WWy)TeG& z+b5D2Vu}ZFuQt#OXy%oaU`K^Fa#XvH_9k@YWc2)Rkw{}dd6zL3c_tTb_Lia~U7f39 zLCv&TUN1BddJQNr8V^YI7o+gk1@a#%hHPJe;MGi$7g0*1TQ?XLgaGd^&qina#Y)q zP?N;jdHhc~|ERXk!q8U(vbSpx7{O#==mbROUWPOp9y*>Xh&?RmXR6OJ)#!2;l$66n zlrw)eN2_xwmEKPS=;@VPwFv0 zq1SeY);3{eGUve_@k6;}s2m4;IfWwbC(z;onK{vJweq((gX#_?h#1dWX=`u>?)Wky zAhSlgG0?@N=DEwoq){=W)7hrck-PJNYU$~UozSTdGR{PV%nDRBYAw#Rv<=H1ARnF9 zDz$N%4Mm=NS}8fq5VbR@mjEhQs+jgnjsZwAw{ed*`~k}c`V+;{2ZeqH7`dC}dKt>i zsxxh%BJ$$V+&yG$${h3qk|TXmG?)k9lkF16QBl!mf>7b51G%B~K{Elg0&<{TFk3Sw zCNmf!0efP=m$jY|FH(_Wc+B!q^Z8&IJ7*ge0#CM9u;Tf@A-DrUrF)N1YgO6rIfyX* z6QA0{48Qy?clke-xXURR)>CoD$B!Z5maFA)`cH29X1LtOfETicUzAc%UpJA|Z!(vN zPF#vK_PCg1zxBK*{huQq^K-~Dr3@VRdtTXF0;Q*7!&S*7D*YH1vESl0B=NK`2CV%j z=w$J9{n;L{ku2N&uy4?m7oje1I-D(2qElS=#Q`N1s{M*&CSBecPX~dhl zlv`~G@R~fD{NIZLyRGUS=0vUHc$%~YBY6JoEUV-Uso~nS+#IAZG3>O&d+{A#PZ>%rju@I0jsmGS{8_34m~iR^ki7VzB8v)|&voFwvZ>=MR=&wxS>iJ-vRNf`AKmp8N~{dC#Kg z!;F}3H~;LnjJxXTOhm*#N7*!iha@&s+;@S0*1a35?Ix^-%Py1jRTyMgA?8inbBcR1Iu)$z2X|AbYFf17MtO~8wHYi>8o0` zRHf+CDgeTd15PxzhH9}>@+|<#5(a=*NId0J720Kc3l&m81&Jz!p0ou$1QXaN?;a$8 zqrQP{xGY-M2j|YJ_GeY7BxVk+Vn$W8Ho2Z z)DjK#o`HyEsGtHB$Qbc=WYlL8>IGS(i;nEV>;WgCCukBw&X-(^UDM{{n-`^+nB){milq zEGETX@(^e!^c2nHX~c17Kw^fB!ipl};d(Yyke_Es#1JixT9+Qf4=a*{2=tXTFowP8ROql!z~Rf9RO{ZweXD71r{oUEeg`zs)X8{$ZU*zAXy$miRx zCn^^2GABcC+>;)D4Rd6JEq5gI+Ave<#ro=tc5NV+FBg4CHh0YTS+Ic!wxk=T%hz6{9%qA8o+RnAuX)j~g>qmDQ+jU# zq0d0@Q_!7$5Khm;C_xM!iGlB@tAFc<=<=X60s3=H3?Qa?(Fb<3M+hd#S86i~P*RZB zPgTdo&H_p7?Joql_(eq8HCpktFIw!O4F&6rYb18=MIXq1`VAuh$~oZGB6U^2i9Nqw zDdg4ELfwQ{s+Qz&AB^?eZe6=r0=?4%o|5;m&m&Mq62Zwu3t|wBL(#B^b@uSlAc?0>62>e1|Q#q|2XCB4U&o9CJ#^S8`-Co6TD z3YJ?${#@~>MRl#$UH{Wk27-K;M1N}s`-!_U!{F@|1|Qx=YilnH}o4J4!r~^uM-aWIE6iw?1@qge_A~<+U5{DY84*u#nOA zd%3YF?JhaL)9rK%(9?Os1ICDI@g;$*k+rcl$dVCC`7lZg$hK?}1f9`J!@D8C1bY~sy&iUK! zn%|xOx9DV3xADQd1z$U?bbHE=_FOpKqpxV7aJ2Qx*Pa^^4?e%`j2dnB8Ey8ZLapf% zOn+1RHoN-#uEBi=UyNLQy}Rq+Xm{O};>tI371JNZjd1aZ{^~t27|9C4#{T}=^6TLLh-3X1xiBVM)JL;N@Dvis zhDWyDP<`9)&xXfN_S+){i$^;so`cSDgB7O--J1u21K4PvmOY5apT$czM!GN5dpaui zLlhq$ob8_(eS8@4g#Gn#sOJ;BlH^?($!Gpgj*dM!w(=waF_fq`lOO57;10iG5YJhsp+u$ipojdVC;o)+6w zRx}TtzuH|4g1RU7ReFx({2jh(^Yr7^(}HwiVxrBHb7MXKJPIAF?%ws}wy%sl92Yv=fjKL8IWh(F=2W)=uzK#YTuvc zzLR6)F1FM0Y0qrlJ@$P6%)e#W?>}LiH|=(i@(aR$ZK-XDON1cTqlPQb2oi=|9vmO+qUJQb9(?tvYUTB$D>9OD7S+%x5LndNx)#Zniy5@834t z-gSC3phS@HvAYkNt;E;px#hLh-3Fc6+d)0W^rs2GqOlCeubzJLWidzrc-5vdHC-RLj5H-L%LI393?vajaPhP|O*%r73b-@iMKUbx=4<|n% z2~ofxf-*jcn78?y9a-^(>Yo1;|H7xYdoeHsnzj1Ds&|oa>hbp%(H4Mc$N$sT4V?@W zFX^4Q-+%2RP2x63JikwTkVL2^#2Nt*EwV_x@mt9)4Q)W8UqW=~`FtCQKsf(tVq@gj ziFfNQ9X>5H1Vv$WLr4`t?KKX@UuOqwKt>3^RDWicSNrh*E7rA z`t{v?jUF6$Yq4l303B$lH#3*CSsAdP!Q+#e$(Ge#y*Ybh+bohF=+6iKQhP1-~YHJT0s)^maf41 z)TGeFs_9}W82DG&oyUUqXXFfW7d#e#TkzmTlVWA`PYGaoBLJRC6H`qP@u$Uz-+UU& z7OB7tXpvFRjcZH+_;G>gW%l@Pocyb^H-dpYyE%)e6RhwM zs~GeK2K~RoBH?vMs;MXe0X>XHFB2r5o!gKTlH4h)ocvE=Y=F0BN zFDqs`r+P}i%XK}BtRJ4fns^{vPuJYwQ17Yrx8-{-e+z!Z{O?1S^{;Q^+#K~+{~Zim z_j_^%CJ_)!YJY$JvZCuH8%z49$C;MNF8>a6M)qCzzZ3cXZQ}A+`Jrd^hu-}>HrsRJ z+v59ozY=(-@%NuJ?>Ae;C3t<>`Z4-a!@#D(rX3L!##N|a<|YRi9=1#W8(4CIBJ})d zdpdUY{lojuf@Lzu%gs}tQJ5DxpEkx-Wu8BfCI|vGZ=7Dz7Q?44w+~&Co13GQo)i#o za)JogYXaOjNNmg?BboOI--kZj~!;A5u2W`)$~& zGR^&bEzPq^1QQUp4{>iN-VWjp8iBWs*=7Y@6yzf+PK`*tT$h+ zcy{t?&h;N_Up_mYXAHBH(?ja^QO-0mOHH0OCy)F2dLL}L`_S`IeD^%nc5PZ1c(fd8 z@|J$)Wyk9j{RsKRfbloFPz!1qcr3%&Yp ziQI@M&rwQJm(Ocf?!n4uE5q&v=T(8*OQ2}K5k9HxDzZjRKBBnV`>N3Fz#Or-Z2Ze0 z(o~HoGG6=hcoarzVk`=O=I51$>y13$X`LNTwn|w<_PWcbs9Z{%*Ny(GMt*3?1VwM0~xpviA8j|$#cQOb5?LLD}p{Ouhs}cyOHwUZzF}8u0XYLav4qzR%q|t|tiCQhmwguvPw!}W_(twq>h(~Wu(GI@Fy+zo z;lH2GsU+_S`Ba#8>q^M2rpuQnHkYsPuOfcdxbBUM+;{cef<}CSd*8xplBr*+gXI}a z=DBq6uDip|x_yL9%}o!|a%GO~bai%b%s0GEMdp7ILZ;TxLWHs;wA#iY)L|0iq>K}* zlBSUmug_yN)i&k!&Tzf9EBawaLU4f;;DJC9EX}kruIu+ zCc8>qcB|D;8Nb|7QsZ)4wiN5>u6$}IYrE`T;BvmPEDh)vzg|+5x)kc-Ol4VZtV?PN zc(uRC+3)}=S?ai&(w_)-saArUgLphf(AJp%W@1U|DuVoWN2{0Zxa%+#0`llbIPOQ)TOx|`g_npS7YHeJYu zYptE^ zm6h+b$8s;d3?Gbc8XpmzIx?*zL|?g6jjP;!I_iza?z>IPk%nj7bw0v_CRrMr@lSpo zvG7hd`xIP)jN@emjD^Ye&-5P`cbw&FOl+f{h5s>5uVlLYV9fh_*`%(`E4{7 z4NtWEk<^?iV+=Xd`kdNiV50c*QMTQy>cdqF{z~SGSFHulwX-pS=kJob&Q-zkbxtXvXI=;eh)e)?8)j8|jvXVqZKF;*W{n{93F*bS2 zpx%%Iwr!`J|IwUA&hbnGUSfA#3{^RFrup%blB$XTjp?M^JNG{Y^qwm zgqW%%={ym1>+w6YDP()?$#48;I#7Ac2v{s!GuGh?K*UO446>AZjzC;JaC-zdcJ6NPIc(?sN!vQxoH9s6Uv(*3Nrd={NdiJpz;w z9I_l1=-QfCGRT1d0P2YnOPwx#-66OHvd za_K+>oPgm=tIeRPjWuOWw7nTO+0nQ81~y~YKm8QibNhhZbz8p8AfRWXNZ)9v&Fp>G zXLGDYqK$3E)4TGo_Vf?W37GvlZtLd#>SI|C;V-hF&FY#<4w?__6p>bQ+U!U?@X#vo zFzJDF&0P?}^4kK?PF?;i)}+@12!BQk_DFkZT1IMMs$ii>PEh@hn@VVM7$1Y$BA2%Y zujMN<&M5j@ULeVr_Ruf?x>I9(8IOP`@HojNte&jG1V+q2qnpd?m|%$>?7gF){HF!{ zi}t*Ps$ej_XNmh5G>HxoN2jYekna*{7>5+8U_+c-WS^o+JTUSZYTIXK4DKKl3Aou!_U?MjbSn{2ID zn}3e2DGwFjvNk;3ev6_yK4{VgJ8m0j`||H`=Hy`Kqbs1HkCB)})IG_9ZfV;j2_feyUxIFoFqzJcAfBftY+=^Z-1yn=Gsi5=bEj zr^7F*r}TG&pEp3$gZso6wy3n0UyS2s6Uy^28Xihv4TcZhieY~ zdbm#Mu+ms&>VIV5SrRSLgtmO}Ui_FYP3Ra|a|R;J(romiB?i-umfe$zfL!B1fBGN2 z`aDC9nL024LG5Wuj`D0}L%=RYjuD)?>B6brI^%oPnv@p4Wxnj+DyF?JQ}l?>10TYBv~rh z^s^;v4atNRR8;w zCv?nPGBk3N8V-l1>mSMry{~#-Rocx3@e1~t|E|oNG5Mco+S{E~|9iV|)s}3l+EuLo zgWqMgbx2ovoMP*e^TFdb*rU5=F!_z(pVO4yq!YyAvC2W=qz>Akg%BbgvRhwqZIf2t zj}iGqyL3Pog>UjEtwN(bCXo$fzX)1l$EjpGEgah`8^SfZLAge^fcMa34)nSM_0Vr9 z0t<=nhu-8Bi7Dez=PwA`q{a8&yEX&e$Qa`| zX!}0Fr1&jyn#nTo$Ew`4eV@poZhuW3^5hk#kNlS)_^jEe)As#lnb&nXRg#&d9Lm0K z@;=$aA|K5c-dyy=_U!AYvJ$n?oZrJQumv-N0e(oX+57EG3sxj!a* z@WS_0%}f)*?}Evqk5+UM5l9;6+y(GWUw7!&f1fIS`&+e@jt6RreO+K|IeK%U|CE z630sm!&3Qgrz>$%+~TPhd73!y(tKY!S?}?_qfXUcY_!UfdVS3&$XzGs zOTnk7lIQf5KR!12`0KwJg_AQ~Vdwl%D<4C;vQAnX39d}hb00Sa=^q!U?SQ>-pnHHo z+DXfD>S!b@t3yxEH9<7g1ER(}>fFkkNT+S_@gHcQW5Yk&-{$LRTD)I(E0@+~$>)2dPh8V?zjEgZ%$- zgEp*v!&j!6=gKGai6z-RznxssKuPrhJQ-@Y*WyqS;=Oxpz~GgZ+xa*7=U;ZYu+&o| zIY8rhh|M7NS#6FAfV;A&p-f1BFE!LDHEurSe1>y{{z~(F*ziW!$iJ{r$R#%h{@5$X z#WHFXpLlfhAx3z}_EJcFtjC3|kZAx2TSmQH@BWs|oAyA+d5NGPxM93i$CwuSGG+Qk z_|hlt%Y}!3P7c4cZG)mi3=?MWzJbQA=6TJpvkgKfGKB~SS{s`yq0{w1&wMY<1lk3M zu2t#Fi^87xYi4K#m)JU*4!@9k29JxRSz4(pbC-xvJuO5pJCS{ z;dzm=cOokV`ynzBzaCuPT{$eJP=Y#VyGMu@n3q?M9i&D`|GJGB3ElFXX{xz| zdl-HEW%P*)uNLbX`N$BP?>SbbV_QZ)HWGHsz>(hLKTe#BalagM#`@*SGvI(k>ZvDJ zY~zmGsl{yQ{wx`)-FWds<$8>tLahIh-FyxZ(Tu))NqK*$F(^;TqbA*I$KA6J>NO&$ zy)zxy7qYd~u7ZsnUPV8H%yf4CtiSz=)f7^b{LO~vW2<(Yk8y0mow%#CZ7n#DEdZ?3 z!Q;sXaUBIG!g9>zQXM(G=N!_G0x0vnxtM$&m*zA_J|3O2m{ctg0?w0Mn&wFVIymhN z5C*?|-Y>ua+rfEs)K?8o|8%&n>Y6sYV-Q)sim_bNhDe@3GG#yo@I8m{<_#@Ohe%OvC>zmab>i? zGIGwAT=a}mwAfwZIn&Z#V|Pl9k1NfLR_&iPimQB?*g2B;+g%x)7_-U~?SZe88`@rK=gOn6 z;{UonQn@b|Wt{@kh*B9SR6SL7q9N+gP@2U~Ph086v1}#X)%Kyj!@V!%TED(iwySa| zgvUgsoZUJCF-h9gW~hT~zn}D%)D_J#0-8 zK77^S%XrTPv}7?wLh6Yj@y zn@1m>&t8FdCFB{@IN%mDpC`T9mXn^5-LghiJ~(;&VRCs@$JHWH`#413p@h8>7OBZJ z$?G4*xaiDS^1uH|WiRlEJILZQbNb!|-4N;^rb1A=`PsLf@c)z|HBC4BTeaiGTziX=O21nUPXn0Oy#Av)e?v43A7VJxc z^=@Wc?>il>wfeW2as!KjT@kUYA|;b-qweN2&m(6Ll__QBH(y=Sl{u2WGdOD83=LBb-K zP%Uq~(y@fKD#@J6w~f6bWCRwe5YjNQk>^N-VCFDvZ+JSv=yyHXPVMKM@^R1KrpNPJ z#UZQb`=q?g_4-C)kADlgR(1679rZi%ZLjqwyxZOwFL|R*|!sTJ>z1)B2hj>W9&#T(DQZM%YxVBg_WuqI_J zM=K8TmE=uI*aic->w`~ZQ|Ip zT-|M%kGqak`xe^Wl=P^N_PS$d;`F%}Ki?{>#g7#HqfnH#XR3u&u>c0d7=CJEU#~u^ z8Y*hxQI+fFF(y@HmfiV~YWm-#1fR&z%WtQ^8D#xN{k#Nk5ZC84{~;eLwzz-Et4$CA zIAdpiLpMuLq8kM@UuB7;9AHuv$L2GVcJp3v2Vi$e_GY6jVS4eG>qioxPIKhkXlAw9 zZoXrJOK@HseF^ck-rlOGrBpzv#Wb5_Z~4_v_{Cr0_=s{2_~eSYklYA4I*U%(jm2qZ zVzT`a%CbWyFG^n%6oxQj&nL%3A~tI*65!C@`c#p`W{MP_#0eqdm~bM8a_r}5ulc{o z8{J&QKf2TY##eGKjsrM#aMR~Xud`_2vRdZIV3o8yh{ao&U8DlO`M3SwAU|= zBrfXT(LM?i4v82_+0nlRS-1dO^Z=t`Abf`E!LSJC@fAcW9rp9W$L&cA-zhqzROt{0 za%ODxrbHlOs>IxW(DA5dU~&I?&E{s^2v-qYr&p%L5tQ~WeJzb$^*yvKJ>2~j`c-6*az555vGtbwi9uEGfNAhZU4uwp& zRTPIBrk3BY@BD#Fx8XaaW_-scR z9l|V}8k3gmxU4ABKboMCRHr_rOIY5MKDD(-PDyZh8~dK4aMBR zro92k0uIGlKnmrHK+ky49H0GF>x%*_)U$gHH~r4IFvNvl^tI#w@DYS+3k&#HJDCSw)}Fe)K`46GB5J0?OZrIrlkkW zhjD^KWbgF#-Z`A5+eVOk42N27;&PW%wgf2gcO+bhIZ4dFsg7KY!(;ipxSDGDOeb_Y zt6BJ31cfIixEI6R%!}gQMmW>tTS_HO1r*-eGh{ zdlY2(i^EKIGtU^ny59fW?Eo*R?=xwQ-}Z!E;rG6mFHs>CERm#x=oB8#OrPm;^8F-x ztNp=qU5p59hORk5Lw65SJA9&Jba8z zTtq1dxOtz{a;K>0hA;U2jDQB$Bm1&n&|UWmuX+on%}6B^>`i0#<#JZ5<32;mip*;m!Yo>v=e)&b|AukbXS?EkN0k z=y!zv@sC^c%1H#HIl;)+-o({Op(;PQM#fP|pyM+5z%ZC(qAn!aG9gMu!9@8jFx^Ny zg!v3GFhf4bmT}%mkxv*ROa$$Tg57N-{c7K0KR9x|h9aWUBK2f52mg2RlX6l1YFGX3 zU^YS#;H{(GTy6yv|5XjqP>9S3Pe_#gy= zr3;DD0Y*%pwr^Robhbqg!J;28T9tMr(_S0{gCUCXudv3F`~s-dD;*RIt~A6V1$#J6 zf0=E80hvkT1Zq+&=LjVy>{5sU2X-OLhQg`Z10t4lU=#QRzR4fg12|$JX0nQ7H{s1W zl%)RS`%Q$LDav6Of?V;@y5?hk>IcnbvOF=x=rv(4m32QR?@$kzv`@vCJ4&R1kz9rA zD)0k~ec5%=&OgX~p5rO%WJQE&*HoEY{gf(e^U&grKnvJB3@#Q#A@{4CoUQ4ruoduT zTlM$|IS{PB&c*HX1Cd28QWQ~C6jGD3Jmy}E=MO=%)zy?1Iyd}Ejvr&0c6#kx7T^$ z78PKviUHhcTI?(EfjOTL9=&Kb>1HfR|~t~soojl=Sy?Jw#dCE|m9n*M`A-C2MKh#Eg zYq?6mV5$fe%a$Crx#Y|b3qjZ>=pee3;HrGI381$_uqYc~6oxc-^-KI^OVqDPII#%r zu3OO~%A}g=XCXDacD2c_Uco+A{cM#Qj@i!}cg5MQIgJf+>n-KI5-Ma7K62w@O+v&( zIZ4KH27G^zm@d6wN~ak2WYxwlFMb$!up6R+6uWIS&tIuAQ=|3lA6o#nZoZd?Z_;WV z4}EdoMx+yn2*Zi;uo_!KyezUx#=RoA#vxvN*ywD#d*~FPvdo=Ys_JfcQ{xFj`@R(L zKxF2YU&gu$o%F)*EA5SNZ}~;s(XDGBe!<5p3fKut9W+YNnQQez!pw+vo&AO>){oj7Q`| zx85EIzS(UUPcS|~;ll939x3{P>;-o=rk+Iu0^xgjgJ5=nN6HcHTd%h#4jHhyI&&i| zSj%B`xGH?j%toXcr_-^a0Z)N#-h1i7D(~d6*Z~`F0gKXgjiko}H< zHB5bjz&mLKuKB39hEls@qwb_-na?(iW(!(Y!X97^<7*Er^1;UWY^T`sor@$@r*&=s z@|MwDwcRG_t(KGpS(=9|&Sa^rrmXj-D1N;sP7jHv9~Ed;HYc$J9Kco)OK3Xju*dB~ zHKeAfCCwQgVKhO)l>Iak$o|V#{?nW~3%v7`pl$-RmL9cAvKK$CXU;iwGLRzjpc^bb zB4EKrGALIT0B|haVs9<;gn*?s!KRmlDx+9thwj%CKHSF_9Adq_d8V@)tMitvcQ;Hz zdQ5qH%S2&a!h|f&Lx%M;B?Ix=%iTI0kg7Va@oMw7wk_tb==09Vt$~!GF9b7UWz#&x zc+w`J9_L78S5t-f>vhd*^xFMk9k0?46;ck&L@D8c6_y5IejYoRH(tWDk!Qd4jQg-} z6G=P%sQR9S40`^=-&5i>q?HeBoy5FrM1p{K$;nj0<(^PjHn>(@{doehY@!X)9^a*MrS-Pc)osdjD=qF8x@`Bm&q42qi;!Mf_N_;b9h0x2k& z9)ZqEf_>4^kTlEuZsvdsJObyJ70uAOE6Aq}`SW5?<4Xau$P8Al0`GdA>wVdN z3%~^^Q&63lV^@YR84!X-G!K+jfin5!M$IwLyJ9r^u$o_I_im=m^f-tcFV~gyq5IjE z+Eor`x6J?gam%>>Teg3nulXulKX5nsQ>uY$tb}LaSrPEfy^;EUk@;G7(sNPc6y=a5 zW-Dzm={tb!{jI$Dr!*@K& zLjTfq?c38B>AiYp!u3}SIPb_h#XRhnjMgr0Khw&DAW$5H3LZA7P(M^3R~ng-c)Ciy zUqsAp;Ojo;+UK}}(;AJxN!*Har~|LNoT3wmM|hBhY8uH;LIqO@f)5JJdceA`OK+-& zIjp}*yI_J3<8oeh2T`Rm>1`-so1*jpfta&Th}MwIdnN%faam`Mn6H8jEi^^c@eMUk zEL}TrOn~lYM_vu(T^dNk#EJIDrb8TrYVej# z1k+IrES_Mwyq&vQG?keUArcpP$295|$hH-vEWi`qfFm;ZJNutz=%f5+_A@{4$Nedi zBq7(LKz1u!1LQe zg$=_#Ik1R6RZ-eeqJF$(>1o`N#{spXZM9hITC4$mcy9~9mF~(g0m4iy{Pi;6p@YeZ zHFRnc%o}H1#y0R?@A&bzV3&#do1&A1mrEBI`+bqL$7lAJVp%~@(f5`RqO|Nh|MvPS zPLlgg&Z#v&G-rY|YPt`(lIO;JxI3=ua^XRpu-%WwhhBdxlnZ*V826o?5zq!7x(n8{ z=vKyp_u46bf_)~%XH3d0RnrMMtRz@doQZo&=)eABIyU?aPXFbQ2z=|Cx zzj&L8iMNbCQ}LE!MJyzGk6LGUK9YTWv@j*A9F#U?q-y6;8)=KUDePbeN9V{|WH%aU z-L*7$=gy==pZd3d+Dgj%>dQvW?J*%3n&9OdC!P*AFC+Xgeq+{5Y5wv`3c&L;cEtbh z9~otN^O*I?!(kl{D&*0Q6&zB`@c+rrxtzpQHZj}n+oUcR*`uLiz6MJDwHG^oq734P z4votd7Nr;(w49~!FIyuhU5_YFwtUP2j~2rJ_OYd(#ci*=SStCdimE)7Ay;`u3VBb? zaiGL7QTmeCqtJJcWBy2odq2JMW%^N~%w^vfiTk@h|HwoTSrmR5qa=8w|EsJ6*}hu5 z?a>=*MR%Mc$9K0qZ({D5Ts-zT6PM{oxcA1pL`fKZ)vRDml8-O1wf5Zkx^K}}Ucb9= zS$>&C5K?tvNV>7M-f1}4G8}|JpqgK&Io$+H@mY9c?6>z%<9_`^CdF?p4U`&RN4@aZ zJWze8@NM^nXPxdXCFB0~-Qd4LH+NsYR4`T}F&U7l;qFt$fPvYs*gyZw@9}{`IV{}W zLJor}_t<5$flt2%^Fq`XQP3lP(n9Q&q?>oaD`{wA_bYf%MM1CJrA{$!8v9&9AL`m) zv3_(KqOe~n$3lES<%W0RfNEuu_@H`iMd6_4{Z8>A?MHKkLpm@1ioeFZLL3ym)_Y?i z@y1}vyXcM4ha`z%lTQ^z!)D()B}O{qnK&av5feyL>d6xAk@)qs=mcI%GHT?0qpNEt z;YUUBxLhcFBh%F9xtw%2)Mou5aPsZ3)<4~H>>KFdA!ct(nVRGfFL6o;PZ{Gyt7U*(#Xo6oOj z2B%-i-Ix3j{R@~-$yE}=*$P8_CIS^Xm7;KwG zvuA#RJnroJ@)>DS@!z`X%lQ7K%H%Ho!G@`heX6{-kesO%(mE{w+V5yy<^#Isc@_Y(e5%Jic zZ{_w?ca3^Ji+o(Ka3py(Q1)zx`c>SucY~L7Ah$Ht?nLVt3(~IayrY$ePGqvUA>}Q9 zbWorKwL4)%6QO4K8l2}xhd-99I>kHt)H|-S`cQT}P;I>3)2}>fasQyd3BC$fm1O}a z*UH5+LrBVq1pw5D`^YmDAS4rOr$<~sqn-R^^Cr-GC5-frhEMn+2RoyV7NHO(UdZZ4 zj?z3iuYN2Q@ekVv6|AGiEK?ME9M1U)mzsQ)Rps}NkTHt&Fi{rY(9=5#674S#iOJT1 zbnV@4sBocFKB5S35(HmPcRx-3vhMbS*{7FThM4#kAh)!xps}GVvh{%%GQ{k&&?bZD z_IaU0!8D_iUrZIQ5b$$-3MGPQv8<8j8N)|2C#v1YCK1S=^7|}ZaF~xKC&(*Yr>X(N z?%DsFNpyQPv7(f)ugXZ`Xw||>Y2NR#&BL}Bwh(*lK#L*?gj6~}tu}!oMFq8xHyu!` z`X?eu%M^KAlCLKuP%utZ0_nwO8Satu*1mvm{R_5}eV+mj?5C8?{GB&V&X9(ifEBjO zY@Gbjxk+UKHw-)dgr6QQJ!G_%G1PNh^j$%o3`&f?Ha>T6xj^JXhf3zpGN|SQH!h+Z zfb?8GC02Z~#8r1pL^JWyHTJM*1qT^iQ2UbI@5SS{c8S!3caMes|%y{Sc! zbLs3M$mdmiqu&mta`3|J^FR>#8Bq9AhvMx62fXb>t83luT1ZJh%|h;-Yi5!$P3wm>P~B2u5F!^Nq)Mn45s<1a|HcT83tJiT#vPxp|f+rU`W7D=3sO_iHHHa7o? zDZSfFJDdrxKi{Jq`7^@a^iCBtj_U+n;y{eMw{owJRySU5Aj`HpizLSHB6hsij5ii? zuT<=|f8q1?cG(tA90enn)$PsKoXw9H*76aZ?5+A+?!2x?TA}3$7>J-0EFhN0XOo>?o(P9F*s4XwNhtsLY zjoj|IyyahEGd+%W7j zU`Ftgyig|y-XnA9pmyqnKZ!esPdK1$4V+Bs7pF)8SltKTysjEzbGb)cFlJOY3f%!( zdajp@&=#q)})vIe;98|)QbfXHFd_N(2{&A$}>JQC3{q^Do)VT+r(U%qiB z|14&%)GwP}d8RZgqow4Lw)8(}VghEReG)DCqr+ZLV0~%d_uY#WEj+Ad+82MPX&BRi z7jvhRPuID4QmuRBQ zOFBkA%mwlTUy~j^>+G|fZ^=ze-F@n&-e>iULH_tx)hWu8j9FiRp#vQb{UX{UdsM|o zAOWSVyH2oq`_WRWd@P-c6M8^DcDP6udWMM; z_%}9k{kL7;L48VAVxtcw@1j1onPJ5Q>TT(@XMTF4WE;|)8J@~Ud{&2=-9chTrEF4JlZ3jGjq=+Vcv#aoa_*}2tJxe8WJ zcoIeC8mOD^Axk*1W=U?QA7YsQJ8#OHAkPBGismzNxP>$f+e|Ru9?Mbs_us1hL#mDW zG9)yRAl?M9KQJBE6%Njy#anP}je8=!qT(qsSw?)K+oYV(_-fQPz<&M_OE6OR)#9=V z&9s{#M6U=63XKhqnmaMQ1%%2ee|%xm8p$uUNR+pE>=6~u5(;epxAJMzPOT*7)7dY{ zOT!U_w-K9sVPXGv%9#+Km`~R(r&l8uH>pQvyqa;#|E<3Bu%n#Bz01CAA^RE~E(bwv z`pLO7@r6VLs23ULC!3xp-{F#;=6=eInEk=I-2?20Y~f|{L#q(cCzsN7C;$YKanCL~m0Z$V*CQDJjI9-?80 z@5)_o9N_7HS;FsLO>mvczur@$%UGU)i~+c%JBt-Jz$o<5un1U$MM= zb428C)}?K-#lF*|wk9)6a{nK~ z^jPBjg5;3W-ZuHou+rK2?D$MH3~R5z^;<6jrAnZDo6MvRT#P#!@f)Y8GnP1hkr+Mz z>t8^jU6i(PNC4xMz!y+Ks{)7h7JbmnFUM{l0OhqCDvzxrN!y8wENRCys3cGk z7^OgEq?h|6_i)HLTO}V2opUN$PjsX`nVAV+RMtY&`}YO?BwQYYiPp$Eua?3@>D-~1sNIp zMw}lqH+bkY8k>G*{Mlwp6!)sBynv=hL*jhmeha@D!Guz$UWQQ7)1sF3>3Z zphfy20}-x++FYOoSIKTOP#l(g`GQ<)5z0f;mB~TiGr2eS*Ebdv!VhQoE9K5|FG`i< zeM01?Sg3wK)S4f1R1sO|r%fV?c5~N%KdW_yarA@e7QRY?c@e=C@OBeRZ9)<<0nwvC zg=++f9vq^Z3}3>b2dWHTDq)|qWZPLti>yq^k&StvJjzvWZUME->W?SEU;80O{cJ1q z5w97t0=0ax8Ypg96cvcbr70tqRZbU1XNnBtm73RZ$a0+3O9pD!4?%sXDo$g={CSxR zsF3@JIz_qRg`RGPQYG2u!-5>uPi~s=_!*F|yo&ENaB6x%uAC)LZAaCQD<5q~Hj?2k zlWp<3re+L8zaOHt4dHs1uY-e_Z<9~=gO{`3ZZcfWRbZ1i1x{KYlO)gcaG0)m#JmR< zn29u7z@rq;E*$vP_-lwT6(xxPzT|b?8v?MkqNNHyxH=04n+V=!CRLHo$y`#u{Y9=q z5R#ga`>d|gDht)^C))^g_~wUHZ|D2UT-PL|*c(&N8@PXWTfT*`1auVAY(%n{U zq>=(ejxC5+&;=kD)$k0|KbEwr{y+(f+rXc#iTp4R>>PGfN0DRk22WaVsD9Lf0Q`_& z56HHaoV!d7#6MiqCK;jmwW`@o;kDmbe7pU}CHq_MsB(to2{mLiV&V`shu#nn!3Msy0Vg`Jn<~#%!2Q&D#!_7 z>(1!+P5Pb3KwcLBZwLV4)vS2u%o`_hzcb@|gZ{j?8KpZUo`0ddAIZv}ss(&^5FI36 z$C$Ux3j@t=v-Ou6TBnfed_=pNWB0p<1V8)do`^EpZm$t}~S!-}}C;7-^xo>{G@|lcyY=lia&H%D^YbFE>MX+uevirjzVoIRn{R) z!|$xX!#qK}g0f%JQre0Te5KmGMhbB0Ct>akX|)$Rz?Nq~75DRnJ&LesZ3uCJz`}(P zIkHaQ1qx@RhQZZajc*g!6Q4_Bhd%Su|aQzT<=Q_WfMvo z1xEeizNZl+9qXo9lCLiyUc<{e*OA4wxRNIc&(EK{IWZo!PHiU_sb$Ddaz=;mzW`-R z4$9E)Xu%v5r3{`4JU~OLfC{r@{8V(Z#v|>ozg*f*T>ng#X=IKxqG3!xBjg9F1jt*t z=t>X}P4VXq{E57J-Vi>rRRQ8ny?8wyn;iQ_dhgBm4rU6@g!lu9Z~^p^(7a3>&;Fiu zQ+=A7{lX4hBto{ANi6*Y=9`a0s^G0sf74`#&<=D7?JP;DL79{Uo&4$yaE9;Z8j{08 z&N7gqT9F_zoz+;$QbpcwKZP|#(GWCpXF)zZE5_pBIBk2Za(aRHzdy|uYkS90(>X#mI$ZFls|6#4u%3W+6#%i9?i(F z=uR_Wi!a}Zz__#%sVamibemsp?Mv}<`5RhcCEJRK`2^8(PetEkt@Tf!{wezW1l(0i zS&S+}g#lrc%&sZso#%@6B7IX8ezKm~juKFhAjPa2RsGkGjlcOtVm~Fcnc6(rLjJ?a zxo`|T$Q9;_)+CP4_XYK@OM*8Wa~Vzpeqyn zW8u~m2vR01ke2ra+_6%x0#!%uINX&V{vG(y7`r4PIxoKmA;&f<){k}5-W!_Y zfoIlP{GV8;IX`$|*ubHrJtau}Cg!82ZsMzYqRR63f>W^+S{`0hZ_{Qq9 zSFxK2$V0?;vYeieIvn@tf<%z4PW@YZ1?dky7aI;;GE%5#H3~H$cKi_7#ftcEzG+pR z_1|2pE46|KKGr~jccZ1&-gkY&3KtxFc>ejrQFVMW&%Hx`M?1%27v&(xuVhJZJ0fL4 zfOG5Ry+x$B)xxWO`CW53*L_a?T&L-;k{jjD_LGX0VmaZ@x8<^qe2L=k1)aMjOXx-q zz6&ELqAavxaN4Sq(l>LfdkjC@%Rl6}C&dXqfILu)3=?`gBfjb&+ZQvJaK>T8>TE+J zwtwPoe$xGiA90AVg+@|F(h@5P8O1#sYMuJr);ye0%ncv6)T4{s;A zvU>C|Ix*`gT7KDED|Sd;n_qWJQNH(X&i+yr$R{n|$=6$9(D}R6v z1b*zBIWL5%4<){TZaGu~RG4Gbrs3thBHRak@~x^bFFS?!bCkunrfw_w*2?+yb4SCA zp*EM0d&i82rP2TXyT>~G(ag-Y!el{A6>c1}z47U}jLwN}IBV@qQC~|y=hZoPzQ44s z+t0CBNi*5~Q;NdoLtQPmXh+Vy2(c|}kJixewF=gC)eO|g@2ig6cYg)v?-_ocIO5)< zq7mVHw^AUK_&fLrBL6@I@7C=Qo9A0E=Qq)a{4J6$AM^Y66#AIKfK>GF)&=^IxLtee zE|tZ(Rm1l*>5KL@l0RVPMSSLN?lL2I-jW3>awQL4YQ`c$@)OS5>)){qcZ<$#@*DK+ zbS(6gOXHd|4K57zzYD!k$LEa7&gbSn!lA11zYN~o&my?AM{cZr8iI~YNA>o6ozl0h z_#_bVXSi0n!{4(j?rMDS4ce(M4v0#t?MyMsnXdR^|GWKgf3r zFj9N9h>1mh$IL-4CcS9H6tUq@7_iM$UA}ykS#(NYWmOlZVLQr28Rw#Zol5xSafpG{ zO|KR))e_(`so$2bcPtlw{bu*@Tzr+!ojc5&*=Da+~mD>=Aum0}y179CKoG*llTV%5*%Mmc=@ zcNLf3ioFM+9C`|NI2Ojg%p;27T3$s%JoIwRZ_8;+8%$cJ5Imw~(~1*8Pt#ltG)_nn zG!Hz|qz*)h71bY_`vLOqVs2$Wlx6tuKN=OlG?7YVI9Jv}ju zK6L&3QHwpBn81KMTh+5cr3rPi7j8=x=m=QUD-P&?oe2=p7H?fCFR)>u1+9Lft2YGX zEC$c!+wzu_KnLT{(&R5SwKmDPrd#)22R2>_rdMD}T@v?`=M2 zNq+RSIzzoNILvBow30`Zvw9`hKa@>3hk5*%TFQIz!;OIX)qlnP&a;Q2;0!Fs`Mi+@ zKn#2!oS>|BGR`(4($Q*V^o>jD?=p!M>*Qxerwl2{bt{%(tu+!AQMopEE8~-=L#}v8AK+Ze?TYxV9ajF zED#dSsYVWvJWZnT#qd!<6otcjjR4;)bnewFi{zZ&8I#?9N0xa^XNx?I=a1)5E~dxr)Jm%(3fuBl!TKb9gJpDvDG z^gFiD;V6zM=8ly6CEYW3&g?xynPm`)ZvsKa@CzrP!aMmaY_2%#TNENR~uW4~!$5yLRt?I~iGi zx^jc(0hg@w{r%@O9pXkg_;v`wZiZU!8RoNHHTktn+|BoPL=Y!Hrs4<(&5af$U3VH0K^LeEIFrnHG7`WsrS>3ZBZ7fhs(qPaoClDE6wlS7# zPbYa2vG$#@;*>p3HNphVd$MmXx25 zfLe{dMIVP9mzJZSf|)EIPeSBAR(G;7j}18Sy#pq5j;&`QOEPLk&?IsmGnGIxw}OR ztrTGmlNP1PvD}~&t@i;zM}I80-I5pEKW@&)6ZE;h!6m^#$%qG6 z0HSH;Y7c;TpJlO(R-a{lk|bNH0D98GS{4taUL0xMz7_JHfS^pzO3d}MKkqPh3yp_d zGuk!iJoIi|IK1--YQTZK;lho%=y?Pw0W?-P90vu`cg1a_o1VRWvl09J&xg(V0(?}a z+1Z`PnW#c{%fS|yr%3?vClhM4GTs^YcL_P{!OQBvf`n9v!nap|# zkK?usZew`X6RInzBN&BnmR^a%3+=S$3OzN-`P1qGYxI*SXzP~#q@Kl^bs0!xvc+}l zaYmfugc}{TCqB%4kCg&}gX0HLi=sy)2ma{(NER8~D(lrG`UxJ3fH(Z&J0d*SEDV~} z&YdxnyRBB85rhtae`uyzRN=A%c@Dr65XVo$9;Rh00O2A5nytxNq=>)Az+>ki5*2B7a1R`XZE%f#5rbg*}@=vdRzamu5qRZdEM( zY)#*@st6f3(67zeB|!}&yE4N@d*t4-3N6HaG^bA%+xFA%nTC-CT$$bSz=tm75Lc0S zZ~RzfPcV*))HGk7U=pTAg~tno&W=0&1eid9&gJI~J~sv=je%IVG3}fy|OA@6T zDROHHxz;Y2TL?*o$R)Yu(nW>F7Z<^y z2>?#rH+wDT6oM+PF8`ohj-?0vRT4Y%ENJdL^!K6A!7e1w?;O5Jgd>6a$QG>@0H?FT zOg&YOE$TB{^f3*-07g~qy-YzT`rs3NJrdPR#Rvdo%==JsJh+({Ib4kTMMK?@aza8N zqd4)ac%5H-)H;PF`$80FAdmJ@eK{(jM}+?Ypwx@^_Ff}_LhS{U>5CNT0!YqDAK^WB zIveQa?&^75QG6TA+UJL=(=!`qqjvdlcDwFM9qJoRuKI#t< z={l;n%0qD};Z@$4A2`-e9_mY`k}UY$IuoJk@B`u8Z^W| zF6wU)%Iq0xhl~2jcEuM7|ENP*mpQF+QBydyX{ff~)M>aFSxa)nG8BFnp-PF=D6*;% z9aVqg(tlj_dA;neFt}I?YPSYeR(q@)-M`jO$gjpB=4Kx zI>SSK`mYYPQiLWH!R}foDc-&LZw@Oa zK_*}k(MhP-NK6Lp7>0rTMMmm6YEFDa@wpkPCo+e$`Ov9cBMJGyPvC+@MHug`F0h1)AcaR&d8t%Mx{9$K)kZe{l$}aO6M08KVE5GCkIB zvgCXbTIoF^8ZW=YM}DhAjqbHAS;j0n1v*!wcSe>{I6S8D10I+rUYt)x4)PBiuh%LiBfn&7zw8EwXCf8_ zXdqT>iHnHF?w4Iu+@J<{)H}S9zN%fXmBK}=zZ9stqH|be3eh4&3^~U`oHD%pn2em~ z!mk4N1~ZX+vQo`Lb#~`)$aw(bL&D{Yb%+J*o}S11hwG64kqcM2a4nw#tdr^8Ht;YR zIaego|50)qi}*V1$RQ(V`K9FFrPE?g#7vm>J<-16{Sy>qPo3PVD`F8>IDZ%Ug)OYW z(VFEVO?nHmX~*~q$Q2%PK?G4=S8Q-XU<)FT$&@WnbMKWuiuql-z&4Cx76dFKCrl70 z*$PTmNXtZj)olB5wuDh;9Ix(+0jnlPu1;3{tM~RA#MX*64a=8wV*8nzZq;K%;O@z zk)QB0k$rq=9|=84&bi=cH6JN^7Kw!`WMmsPDXQ@y-4r=T&E2glQ|wjjE2^}!-9P*i zeIA6I=j|D71CLUWLlj~Kw{Y%mMF97#@HhBh&%!yb$OIY5;npivA?L=Ci*@k#TluE1 z8wsBqEe`K<9)-U(5b+x^!ihnn0m4yKq16v+b4(bsNSIy(9R}O#ih~2hgi`>*UH~v< zs7R}Up#Etujw*yMg;B`+`tG1+xo1-@=x6XGHO3_f0Pw}4XCY*8wjo|tRcbf<^V48k z5ksKe`PY&+_JC~z^=UE6wq$Tfk?`sJ)fQmCb3u(Mg<4-}dfjN&m%aa0$vx(< zD--zabRaY}(A5zjoPraMBpBzSYB(!cpdc?tVeq~0TOl#JliJ``0o?;bDz|32{eKXqYzL1v$1$hqQok^i6)BV zQbaPuplAPJ?f~5KA2(C?f=`MG*J`~{)_?g%_Ei&@3guT&ER zO))Uwh?&JV)cY!!Ee*W#tlgvPSu|Nle5a8p*I`ZQSUse=!bQ!o9ZP5MLyd158*K<= zwh!p-pBT-?&nbz-{RzASZj9$n$*sOmpy8OEJtcb8#sB-?cCK2$~wOQ%M2=Xsa z`b3)6(Po>=t3-13ldz%AW6st9#ZFTR@HiK>L18s!K|-{ZujhBAq;ps^0mH8bKOj2B4do82X`T6Sq2PTE@Zo!)ST?zF>i zZJPUS+a8L<6sYxt?O>z3)t^|K`Ntznwuq zO~{@PHm~83k>g!>a-0$H+z4&(xodB~3HQ7lw*fTN_xK>}k{F%GEz{@DIuHG7IJ&Aj zggx_KHSWE7!TT2s@Mw|#G5}e}GuJd9)~q?muR|{I;f+qigvnuxzr#fNk$0XDCRZe? zs9RWj#OZHe@2E&N|9}yD=&<<*w=*By<34yCkve{{&vWv_yO(6v(gz>&kG^L-Q)pbycihimv>|JZQB#zMc$)uLvlvlOB0p9h_bK+-m_nG) z$)b=-oy%pxnmIL^C)q+Kr>z6?uiQf&dCcV7-l+v9>s^X`Ro%S~PzZeBLV1y8ide&KcbY1*t#RKF{9N{B!dQEMyY-kJtH5 zFRO)D(=W8fMsY+uq-sA8+#EyHHm49H-HZK23N?4XwM;i|PIpg!24S?+G1IFzdGaor zYA)kj^0WE_qsC{yY~~ih(kE5^P5n4CbH8Rr?E0L8uJX~kxud*UlHRmkVY`=@Rmbw! zfqyd?m$|1hGXXt@SIuYV*1mWkCr%+h1#Zk+TktL*d4U!Zmuh)|L3$?t7PJZ{jYDS4 z&Mto2KX=|`;@H3frErc>IA_5FA6}o6bK!;l8~VJBI$o<$^L`=znBIr^>7-gqui%BA zHGJa)Gk^~t=EEa-M{l^y`b_ci z$q%`BO?T?@=aqZ9D}?ox?%u$Q#P9Adkrug4xa=P^3)VB|l;20|WHCZ%>4@vw7 zNx^JvH)ury%2%*rUyBe->N$asxy)Cc<%-;uIH~ky0(Vq%)JL#Mq2`=899-=JQS?|4 z^a~l;Z0m7?ikKHv2 zg5m@r+$$BqL(F24GdSc_CMl?X6S_Y8_N=YJlW)3jHqRX3{XDZNpd0j`Z0t zDr0rQ^_!UG>J8+#INjCp>&s3DR@I(-J8 z9r?~h4PwRq450ve2d7$Nh5nmp(@<+pHH$T^h=KKGJ z{oYz2mmMy!zVOK~aHz(%>Xdo(_rQ^A;_Z7iPVPF#pZnL>-u!){!lN|gS>gBbXS$Ow zqaXEtKYdNxt33g6z%Jio!>9A6yk(-C=caG(ZJl$Su^x^Y8VMKYLC|Wc5@m}#LNUll zJ?+x3WhjVtTQosF@4<>~D^Gcv8wyA3rBAA$>`?D(=*6krF!W*#rf zQQI9mEzzZ+!ScSQ(+T-&yWNkil@j^v#QQ-5^^Xd05AO@o2dYieHET*`4%dnexA#2R zdt_Cs_Hla5p10`Za>s0oZASLkHOJ-*bV{CZPP0{bX$?0~UIR5eK5$yD+EM1Vvp7!C zfTMp{=fzyZ;e&4=27*BEl9>l;3|?D`jn6NYJ6@;gB`i!`q)%sl3JzQl^C@cX0os)d zF1+5+hJXeLBHs5)P)~c`i}|M!(pyH0jF%1Vn6}G8Uo=d6^#d@3-5u`Mu)8Jjv}zenmegado6T8{&!%REYW8J}4E5Hr&GovlAIg@yRZYx; zbX`8{INP^|NZp!vbVY9atm3}heG_^I67fFCYUNEnsX8$;2Q(|{+Mow#x*>)X!Gi^n zksmW68P_)3E(+bFVHaf1RiA0QANxs9sXRfQzE~Jox~h?kd+(Y2Aa=_0LW1Im@M6A8 z^_ttgxRGP$g^r88g(MK&G0;TiN}S(EtrUk#nAps5!`8s`+7fp)DtS&mwn0zBBWCrM zYC>K#ND&pW`L%p~JMkr}&}FAeB=O>_XJXyq4?0eEw)AT5;e}qSzH=q?SGdQyE_>~h zuObhsjd@*v!AL#Ry}R$vi*F;t-@VR!P&>ErcKqQCyyAQN?T}!5&=jDi>kN6rJ^c7)H76=pTVK(*2Q5ZBoX>G+ZiQ zjHD<4(;_$bL&w@HK6lCCC|KLe+VvpwCh!d$6$EcGLOJoUP%d63Iw%|wS4~2grXq*f z$BbE-=Z^*}i6hbV`cDf=p{1Gj=8?ea4xItg%~Y>;A1O|JT7)D`)wY z3QN2TkA~jW>5%f}5X__wWzCDMR;4ty(_9JWpO(h0*YX}=qjwsU)>Z2a&Z6Jq?euep z(vo_{By$&;yE;KWdm90X`(laax}WBvtF57+8z5$Keu?$`>vmJFJxB7>EGCx=&=4@F zk%W@{-vj_F#2&rOXUd%fP|RnnL_p7HX)XdMb?(qjDFJpmOYVj|$~Cyh=gIvMhQWY2 z8KIej8u-kPzd^TJZ}8a?{JO3uL8bUk$AKiGfogKrZqq3hweZ#}B8JD}2<35La!bz74hYEjo_*r}(FEbRi z5^`9sm$+RgW*msWAG@^1a z9PI2ZSak=z7EV#Sa}W4zsqteaOjkSygtXKk}L z)aMRN4|i=7-QsWT=(sMM^^8^$v(bcyvU1Wa4SbC2;VVGe56UH=723TXt+O^CJf2&WEA@7yWd@8i((&h;2S@^wEXSCMxzaDH%Z@jll zfasj4Up})QAbG~taMA2_OutI`v+$rYp9sIEfiN9MhtQTGFC*6EpY(kuzdr?1ga{PS zzC52@Lx|eMRx0BZ9cJZV-PxQaiLKB+Fzx|Nio~W~3}ZAJy}m2|UJ~qFx7>K9Wp9#i zI~eQb{V?}}j)_;G=-3t4=Lf^B#g_$=ZxG2{Rw^YnJ(uP7ktc3mA{*M{J&|Tp*1jUP zUhc~P`AQ8)B;BvwQ}yS>6DNZfWp$XZ&d>Q=}bB3r+LtS45s&+Rc+F zrRc{PLEwu`Fvl4ZqiF*y2dB3gtb1o%Vyg)e#yTsH!jC*8!c2Y79#**k2g`JQEQ^kn zHRg+>+-;4!zx{$41!OW#o+~-2<))wQ-JPinD3(*Ihcq4|!pLuwP~<>wy*nmL(V@?r zUZy@W-ndfxt@btL>D0Q1toz`f#Pk86)>Dtc-)Fzv{xeDNy|(ZB>xIg7<4Ko$KbJ8r z)I{UvY4b78L7uOWp>0$B*u;=%{`9?Tl#=~}WEd&8P0Y(W3p2fKZ_uu%J;RrnN>NR% zJ(HRu^CIl|GF|B5StjhokxYy4d^>}C3dkw;c`>r=a_FO*%Wpq$I!A=29flpnc=cHP3q2OrME^v{gMK*pD&u-J3G=r* zvF|7HTLrrJfW(RDm(!86uM6ykY%CAxsJ%DmJ<_$8~*|eQ&or@zgaTWKaGOhn^8f-K6 z$Ps}QAn0Ohva$#LBv@2#3A%WdS$JN!;1o+M320E!A(OOAUn1T@6X}kMdu*Mpjc{Ps zG@C{u-Jg<+t7w-AP;1Sz{5@<_!YwwfHVap>ytMl2#Z|k%qz)6CPO!EX|F~9=wz$_H zJL|soozJEhXKeOGbp|nR8O0vd66B;=ldMX+qMvs4`M>dH>{(7tQTEXBl6(}_@#2RT z$ds=f!Yj+B+8O{Diq!5)e>!jQyI5|i8x=rvZgvC!eBGI&ob1qtwl`|D>&F@N0uIXF zdcwHhrF5#ZbK9Xu%pn8vG|#3-yT|^{Tt^F;oJuFBVxPjw1( z=+1U9x+V zZU{`k<)Zx$kF56GA9**m_3jH~fH#r#CdWaJ4SY#RR`hq!12U>4U8TLJX(XGI9Z3SM%%9Y8Qf znv8#91cjv#3=8YNd-@(!LB%z>;Vlmc3XNn1aNl;2^CPIRpdzPEHV|6`Ch*@M{LXbQ zeJ;ZlUakVlb(0Uqap5sThr)-A6OJEr1Q}zYj!Q4)6VlLQ_*e&+{912!1?Vs~5fuza zH$ksclTXC3_FPGk;U!*o7%`t_s0v}Q4zTOn(7&GWf?k;Dv11K9pd$blL1kT2|KJ+T zx{6I0oC9L8&`>n%5_z{*W(jhc%!f-fk)i`n_h7}~4gpW3q5Tsx zh%osN5@=y)Op%O)3LHy@_@JTZ_|OVyev(8rwQtVg^04jPrX^-S_?+asz;U4RA+IM-{ ztgsZ!Tc%W&5IVBEEU)`||9hYg2!oEN2vkjSePHrfK;Vf=-||EOuSe1ITN9C@CSJ$6 z2L2kWi1Z8uinr2%XfDlv&Hd#Z{lVnkSlmgcvQcfsxX#<7H)6*V=j`XxJTV@l5eS*e zGcFDMU3-DbnY9KH{_cUrxja7e;9P@1mW7_CoPHh-^(lcA*3ijh*h&#B2FG$(9SWi% zsC5Zs2O&QyEG81R6*EuQ3HT+k+L`(v%7^+C=lm_A)xw%FCeh4hp4W<7aGLq z6av?uNb782B<6VLS1>x~>6&b?Qy#?Bf8cT(T@wekZGs%;f^ql(ES-#rOpJ4Yner!w zTFR8kO#7yI`$!u!I0a3FhO}TCTr(~bPw7U&b%mLlln$$=cq;%?qlT_k#I&!Aw`wYK zhL7XwnD*UZoCm$CpmgH|(<(CFRG2xdoZ49f8c|72Gz6R1#ecidtyH}W+@Hp>!qU(G z8kceag;lUl;F6Ui6F%nzwvv-d5|y)EEspJgGayM!NRz+!k3^0 zQ7MA^Q#cOhie+6(f<ps`;Ft@t4(`i%137qAYvt{OKDWZafo#^WiGf0Gm^ApZ%gWT~j!gW>z0A`zHfyIFX zDXeQW)-?)?!WXW7hw$ijj@+ILuY)G8Cd&{L)z){tBRmqj=YVE3C*Ad#2p+WXo22`a zSfRn*N{C?9!CW8H$*1l{bwhPCA0zf^8c<+yY^apS1AA_nw8wPN$A#d3B()0Q@d{X^ zKQvxP_&P->J4tXyNRHupS8`z2ajdAd`~D#;0(Bsi%M#w3A7*2F9WPuN`0=tQ{lXY5 z%HwWy)90Q>)4O?#$BJQ5nJ`i>%g?`7u?Yn0VBMf8--%qLILKnjVD&~=bP_9SN%|Tf zp5T^YSvVEs`q9d6G-V!yxyt%f#9Bk=k}K}Z)Col|Nk`L^<7)OMLl_}k7|GiIH$}So zCeU*%z5OmM`A4EkYqfp2NX!^3fW6zsP1zeqluDXH#tE}TlY#E)Cke#i3w$UQz`7u| z*OUFuiUtc4%aFpt;;0LWWbn~f&>&Tl`39jk3kz+ktL=wymsN%6H2v_V#7lWlbDRb? z58~&M7?>wu9uqGlnVufI-*+V-mIsxi(Yv9?ca=(Yn$mn#`P2Aw>UaHWD3+XT(__jX8O zU0Q-1_D{T)*A}6}IC_3}F$jO|be?Ine^J^pq&Fflf(vt97I_l>Kzjg85Kagi6Ij!a z8!Q5)x}gk;NL(f?Ix|6rtLKXY&nD4d4+Ii6s%r)ifdeeT+_h}ihTI#qyZBp!>-Vf7;=2!%a;E<>6rtpt2hlb6>8%Nb?5?0sQ1SBpTsmx z9QcXBV0Y;*l-n1$BM-wVVPh~6<6@VJn{Hg%e^&HUAE2h{Ae0}BkVL=W$?9B(Mi;SU za=OtTHE8zYK4Y-@A847kuoS@0)x=x==a0*) z4!kWk&?&F&3`oVi=!%^wD}X3uRPomGwBXqK_}2=$6)!Ptn>85&%hnBh-o33n6KQ=Y z?Z;VI91ps`OWRV=0)h38qQs-B>3(e3HDZPo8yYuuGLd{T!YEmW8W5eA=tfKU!b;%% zPV5d6e$W*jFv|$-hS?lrDUN_Ae1(0UFf*US3OcjHGJk8-{BHh{9d}?a+!;oRMwk_S zY%t#aX21K)RKY=i`jXEd+5@>Dh0#%3RLt?M7?elLmun^8{!9XdV;X$$zjj%(t|rmj zTVESr)b78dxckrKvB&Hui?E9+ZmZiFu%d`xo6}XsmoY6dQ|{!|C1t37%=!p*3m@u} zc5!O1t+j)^!78}WVl?Rn|hi@QI!CWqcY zUi_DDv!#_e&ooZ5x0TCX7EyK(x0lY<1`n7@&S&5BlRuL)WVg~rJmScU_YqOa$$92_ zSiVhJ@`&z*a>=6>lXf}B#z&sH9Y5Me>vxM*K6DJxH}P#i=}erod+dSR;U6uH#(Z2& z=kpBaG8c)BpZp@fzCC%4pgwchc&R9N&_woaoyYl$71=0lsP zLDQuAlS9SJz!S&d>uoQ-#(tl?^X2+q=^QlNXavCAUsrt|MMzUF$J)tU*iE`5Iz_u+ zS82qfDjc2+#vebD2f97%Vjg8Ln`~duopYRwm@O~HpU6IHMhDyi9s2!L>7%71tzIR= zsM-}}UR4bcIOlu-N7O;}?&w)7X&@M`R~?<8I>+}r3_q!#2tzIMvXOdq&R5@SZk9ju z^sC+|s)TlrWTT8jMPCVGoMLwLx)o9h`aLT5`(=wSyT6zUPwP0Ip@XY_B&GL*N4lx~ zoyR$XaBRxOkR62)%tu7wIRAUO7@VL!EZNsK|qYOIUJGU1uE z(RK$(1dcZc4Vn{X_zq5eMLYwsiyl`*+*1i2W~-0s+jMzNWL23o@XNQ`<| zRKdv#mw7s{cqL znN3$SOan&vM;!HL-64N8B6~@%8&%CUhs&-AY|OtSjiRDcC7E!Gsg7qUrR@FR??ObH z)fyRWp6o9QOrA_*X!&w5nvN-wV<+RK*ze$Y^>)~ehiy_5H(^+*$)F!Us-?^;k=d?Y zSh7GK8&ky1Rk*+-+a6FWtQaSFiRP$N1 zm8{grjcKvoA}Av^*mxim85VzDW}&GgHU0bRk0UhkwY(JHQnfCV_x0%!%}SVWk@jkU z5X^1`rcVSctR3Q0@waCK}55fWP>L*d^&xp^!jY^OwavHO#d zxAINrM3Vem&m5lZ4XfhwWctG{5;_&qLnE20{hBF_zo9jc2$izG>g>&$+ip@jIE-fE z9zml_I=1rs9q247BZ~&U`iXSslQ4_0%k}IVvJzLvXU0d&DIkM=OJws$WRSJW+=yw~ z86wZh_E@C$m7HWFd^gFoVQ<>2rTS7;a}B5CmG5sixT(h)3R$cJyX~IcgpIypSxn7j zc;~CB{au1(`~!l0=1LCC2%ij2VIyzs$804o&Z5%n}aNS5tUd8Bq|< zQ^*-tGL;X1pLAP!T-{p2hq|j9MX?4?%ub1J9x88sI2*YOu*SX@zvH)6T{aM>8&;w< z`PKD~NhB7kHz622zfd830^MoZt(Sh;`Mj7U5Tu<&Pot|Ai#8KGas5R@W6D;0yV<(e z>r>$#1R>!JhfbVnj+H4Eygyp(vt^1H^t1<9ZWjHYf%PrBJ3Oq|2jM69CabiG5O}f3=s3K6kKFy8?k6R|fATPSa%~={Ko1 z1~R3T2UaRWX_wQK$$+DXl9nt~{2^!m$-c*v>|L z48N!WgywD=YfTiWOOK<)DlyjI?*I;jSOCq@l64xp6Fv6U{V7K-0c=nQeoi_j9m0`5 zCbh}VFa92A$v>uZXyBgF3H;?Ju$uMo#@CbU*Nv|RZ8kER*6_qXM?NphOC3q58vUJk zvswJz<@uf0Mnc!#wOww|!IEZu%Ff^X?C%9J5-X9JXu=!6Dn=0f?|ObsH0~zpZr;jn zo(p^R;xhUAW15ovuK7(Lj2Ltp&e~*Q%9EZ4txJPbPi@Vr?wW9!x?9DP@}}Bfj#ynx zT)v~$H9v9TEIe^2BTfv88NkV0R=oc7;nkLvv%98a99`MlPjLi(CsrruD^reNLXi1on9DHAL&dKFs##tqiC)+*8 zTQ_sx5Ecxc{Can_^;_XCVTp9`_fU50R!y5a(skD=)?kYF_{q~st;&4*iur%+W8qzo zenx)A6_jC}l?tvGbyB_?cYayN>o|6aJ((z{DQI$W1QD7Big)hZCx^*=6 zdPu%5zx7+WFm1Ok9^>)lcfDU`T;Fd!q?^j0jh|<>H-1X_%p4svLf=0^YbBox#bHnokeR^aWP=GK9Q{nU z?eVjLJb+3!m@wgW&I>G%OO2ay*~MwwUl08HY6l)?;(cY2wFlxp0ML0>=sbC(+g=r~ zb`@t3#vu#&ehP+YU-Sa0G&%fJkzecaT+9QaAzeBq@jf3M`x7XFqlf{kGgyCXH3F!e z-lh`P{`2;ON{1rB(B}g_O}Uh0_LO5<3N{G?Yy0x9c$~W+JrwDcW>8eLzV?7TLR0a* z8MV9h_E4G)9xd~?P6Imh{?2}ZeYhimDK9bY6+!ym5}F_Jm;{^px8r|6e+fCLhqY_E zoi@Pve7~(&WRmu9NY6KrO_Yyhn(uJZ zxWL=M_EH|$yoqBr!ldL3MojxaUs|2Ia8tPTyoncmux_q_c1pbhY%#{P*o|dco6hP- zrl#^7`=5c$yE!T&B|U6_b_WUY%stTA>r@%IX%2egJ9v!BGYwHW`OnVm`S77q&_ODv zYJy}2FUy~N@MJEDf0z5csSJCUYm@JzGyk{X<$m?;>dU>(Gz9BGZ$frwL2 zF;p_!EyqZNeyPKSqtbX1B`@A-r!?5B{7Dg!T&Tj2dh{f0!ge=wK%;j)^zmZ!z2r>| zFCS-ysx!zG`Zj7gduM*iC*h*EwU^&>mEgoZJ2WwHfGl`mpMc?`u$kK1vo+FcevRV*-5%%(MY1yNc!iVk=WvQUalb^u){wLFm*iPtwZBSxP^8fm&2ENjQ(Hjn zJ(&uQ#a3DK<9iqiNSke~24TDo5=FVSVdEJ(Y|w9=bLAs68Fhw*lQkOGPON2IQlZN% z(J?&1R5Laklpq6O$n$9O{tWHvb|p99^@;ewT`o{%TV1t+F1hpdrB3O%3Q%5MBQlJk zlgD^2yboT{rc}hx$!u4uurg>!#ccUgU!iP6CJ*;Nwm934^#aySihlab6ucz+IpWrG z+mC6YK@rpfqG-CYaDoPY&TA9R_YqZZ_dCK7Rra%GvvI!flro9Sw`dx0UuEw=#$!6( z#^0PmGM!@@lb3ux(ByFpjZABb0+U>RE8n7BGrm$W4;8o*0Da$vg|BA0TM4dFgo=ke zzL9<}xGrVqUb9lhYt_8mIg)9-Rcfo9L>?Ve(Pp$nGF5Ny zShfP4O?bQ>sEMa+9lxaXTPMb`l3;lll`S;hX)`|&< zGijzWHjp_2wJwMlq> z7qNkf(#+hn1<;IikT$hnu|G`bZA@0b_AeZK?-q+H^qa^4a>Py z5}}#-Unlbr_K~X%M?m}P^$!!@lkj8OX;`qCvyFWv)2Nwgnx^oi^#C%SLx=@OWQ80; z*R*di3_LTDFN2*;+IWa7Z^E4LS?w&DAk zc;$PE-5`-EIsdr?f)`T~%?$}zxR^sigms*$=2!%wo>#tq{+_Am%s(8~9+_749(cs; zEZmF_5-a6=g6O;l(G3VA#6<8R9y4-a9!G@!de1TK24y)<2sT@7K4bqUrXd@E&L^42 zl3vs3CjA`z)5GXY=H`zim8Z=Ae%G3Lfa-ws!|eht7QFD0X{HQLZm<(?vNF!WzUn05 zn}Gan2SO1T8_6;2U<$5_BA*B!1DU7ob4HSkl>amGz0W8hS#)qT>u}CCOYxgnqus3# zg510`2drHU9Z5U5@|=X*!l51X^y}J9lPKmvOjqa;X)lf=^cE@tEPK@*j^<0Bs~5bx zf&bdXR73ZNwMq95Q4gj&)iz^$f%pn+#%2l)IUslm7MV=Vze$8mQQ<`rE|aZP)aUn> zqYV=$K-#Ox{M?AI&!XeG@f?$Pqyq!sOL^cAvG({Sj%72)w2nla2J2IxNM~zGQ?m3O zn~>$NU$QthX)ueNTzfq5h1?aVW~LcB$$0M573h#a{hm+jGAp{E2en1WW$UGGIG*j_ z8`t%6b-=8SX|#?S<*^Sffp0W3kKIc&uUoJw1vz~p*~IwHC|B>@jaGzvaTJb&kY4s? z!|x>?flb4#5t(em9S-;l1W9!>+1c{GN5A5Yd;XE;{F!M`M1!`|4msQ2ERqws#vu4J z`!IE23uggX%W+u;8?lMvv0x7_ z5Kb0+Hx9Ogh-oHScrhy->=n~l$ND_wb9jF51nOs)IfbF~rc>0J>C^=_lQOvEORArS z#8r?EW!l8QXI8U2PT#>sJq-!z1nYIO4Ir7?{>0sCcEAlgbdci^rY2CT0e9DCJ-y33 zX*O!QZF@=8j4E+jayIudUG$vbNBUs_kq#cA8SUn0hjh-Em)blPme$L$Q7p7EUt${N z=<5z%EBdNGwRuZ>?rYWEw%~S-{umJL&~Cisd}xFyN(Fn+fFidc1g!YS5t3RFU}0|k zkQWH!+-?jJ*9-dOef=tL+y+6bBf%f;&jXpJ!Pq&0W~(Gqcze$Jths;1AdhWivxpCC z=Sch)xqa2v10=X7YnDpmwYf)2*+x0>W^ktB9NpER)9@F>WP(F*W@4y7rASU>6VvvK zV&4av3FMe*9S94s)`xWBse8q8m^r6Ow^8jzMVT z;%B3jA6a>{6WGWS0Nr7RnH;}o-){?1S z;Km+89#8DW=YSgA3)1;Ud+b&A$sK>?Vhs?)WUF;zW(N%8+rAtlEl?E2#@ecyZ<%T{ z4?@67fHocZE7&4{rti&FJWGxv$m1gl|i)`yCG4ZE*3Nm-fj znPy?_(q42Gxok6aclZdLkY8#HXC54DKlt{~x|blpa{Vx>U7v5S-wyyZaLj2;ZD+8N zGs$4iW6GvL=t#_t!VB`#eHFFsFKbEnbG0!YFkYI?p^7%?JS&54&O6GCWN|jhkW_!# zdVk-3O!JVL?>=-GsBrf)(_}kXoCnmZ17)7nFmrg6JY+n?xgU4h=5a^bbx5aCCT&P; z`c)z4wIRuy3q(?t)oh!9^(4>p>E`*Ih8i}u87y#pRU?`f6TclD0qE9%M4k#jc#_4) z9YaBh{{A=FAs+>G7~m zzY3trEwHeNv^?Q*=hOJ<)lA~+u@>};ef3kF5@jFH; z&(;#Fuxi>pY!c89Hni#ZzJM(;>9wr;tt4al>_(Ro#12n64X0Z1MsXwgBs|wjv;#ma zYHD}+@>FV93{>A(J7s<~!j(+}&Ygq1Z!Mp(o?bosI)>xGuH1)`Ouyk6FoLz}J!^i% zNKCc*+rX5mkru6k%+dW~oF|-GEoSOg;aKF|R1lb}Xa`3$ulLAyC|!j6=&Tr3)r0KP zl%Ci`FW_*J09n+7yY8B5r{9iIEZOLKe?rLvNb>I>f&Ir{T+*f=PhsLyS%+{$?4Yc5Ff8fwSzg?;s4e3bnTa5kF)Y+sFCrQ*j)N_vvRG6 zy+E%_`r52GvhDZaqC5Ves$5eKOP-+q`;lSz)<)-{qJMf!aaUK7`TH?r!1D)jW4{E6 z_xVJ1=;_s8e$w#+F}UQbKY(3r7;&fRd$Cgr8w50^#}9Lu>Oi&fF(qWcLinNf86UN^ z-;+85aB2s_ewZFixU}VMe^Zev_8(@m!aqwX5;N_c;9Kq1QK8s`S9@@!733rK{N4~? zSE$%fy-p6J>vn#>-@P8gVLuPxLwhv}aiK8Ew9Wg;l}!`Yo<6awGw)(QJud0E5s)On zH=DdW;0C4&tS0C?xceA}4k)=7C1_hMj?8tOsq-#Av8olmxlwN2L8Hv?KVlGm@vh0G z6R4UY-92>$dg7H2J&X+XRHQv4A1)Nd?|lU;bevPFNsr(=CPG4&A9rFdJJdb1YmN0P zE4x!ypm89mw(J9!dR>!|ei1kSW4~KBLC`n~5)ryhu6XQM__*>_Zy}XR`C#ue(*aJj zU#Pdwl^XHzd*DCi1U-;8BBCZ2j%)C{{owjjL02r9O=_oXCe%WM1TDJrc_Z`IyEhL{ zoJsf;(rq+k7_+@c))dY7<(ZYj!Q~joS6O#rV(T6QL-_oG)Bm;nTL1jt8z9Py-*!-P z5JMQOqGx?qc3LQm1Sm8n`cdSSp@fNF4v0vuNR=#NU z{5mU7r+l#xlP-)LQIhN9j_7kYGOkAUiV(>0=3BQ=2ti8nJT-HLMtd2%>jAdPqQNZi z9i{Fqn(mG5Rw3&f8Ieu1@|%Lu?-@N2C#ygYw2ZyQsshrJ-!Au)ZEqYjVu3k(P<6P{ zeT6KMe%+VKl*x~G44{h4bSs_{WZ3`U+G=^`&&qGGyJPqYPx91l!e^GwNmlXqB|V;% zf1cN6;=sNcmo}@MluU2;+O)&s;WFQR(oD9j>iftu7`F+EWxMzxY~HlYD*Eikl7h6p zXPHWa|772fVx&Dfp!e}`WN&tpix|s%sqv2d#S_d6yjl4)!G6-+mT@5ubYKE)L%=*V^+-B; zqYZy%*?siYXqjt-rf(V^dHYGrSgjmI-TD&TsPbA9De^ns<5Er+LG^DbhNPHvOZj|@ z!G)tPwo8TDt@|wGoUJ|Qwcd*+7H51{vGe$kG>50+Eb%=WYE_v>wtZZ|?s=>JOH9`} z2`2jq50JmrZEwjI{TLgc#UOTbEI-|Hf7V(eyKwc41eN?CJli^USP#!1tg-fw;kF z_QTY#X8TT1X(@?g%(_bj_A-bbyEvQKn|ha2EMJKyMdou5EB-J{M_Yy;;9JHX$vJ2K zbXwgs;8x1kBsO+sJffKyE*zR`EGV8LGq>dL+Kl(DZ=_pjbZQpMUC>y$CF)kGFJxOc zX&UizpWN!4x0~ZVbA}Z|x`~c$#RC7_Q|iC!aYPT_WJ6eQ`!w*1gn0))eTl2505F3= zy`xx)-8qa9YU8y7Ajr{=w_qhtvpfE8%^u75k=|V^V5L5i^r=gebr0X4(MPhlFRluI z1d!d~+8M;lGIz&(B6GU482mrv4<|;g>#Edu*V>CwSJUt!C)nyH?ia*oGS5py)Ctar z=o#7f6w2N)MYc}OLzY!8Ibt4a{G_BE=ijb-v~XWS|DWE7;cL_p`y-Y2a|7PUlv*Du zSUQLJr-pJ3Qi=PIt?Bc$k{zAHl)e4@sqsDUVa1ol$buhX@*|m$zE0vZowru;o~i+F zn*wC&X0-0HGhya)ZOG}!!lMb#?i{-NRqGY0OFF^>Z1(hgc+K>)+F$v3{nzzHE^a@4 z^p%?6I;Jd0LBZ(#Ve6iXwb(>D@iY%CCnH$8k;TZ^x~}^) z-!Yk6RTC(q7dK86aT?9!m-_^#%U^{P?!4Qj!L#G`Y0JOVi%RxB>)NZ-vNGu@nuSf@ zmTohq5S5K->;`so>#CC2yy0hR1;;tR3&0oi7Icm#Jv)Y&S`Q;fCX-me?h?8;GHk`QbH}3swZIb>OKqyjpdU?2a!4 zRjF~uB}iXZQSsJ^b$a^#Te)&uv_$jw;!snC@nRH1J-cjiPO4H2Hufy}LW)@88=7E` znM9qf zHT`YG>Fvv#9zw9ai`BmAGv`;{Z(Dsq;ve!I*?(Gx1F7$r}yUI%1Jv^!e(>8??|ceK(SJ1{QoGr^FXHmKMvqK*oIvghMBp~YR)9Ix$owT zQq7U8@|`nRwHY?|oT;ce5>mO6O0_wPs1T(bxhhFQ6kYr6_vh#D_viijeBQ6m>-Bgh zZ<2BSCq#|Ocm-kyfdVp+fMbJ{R;#3~RackE=pE}fQ~-y_*V_)_*wXGf6L}v8@YE`y zSu5HKR5sQ*L1~5Xt>@Lr7sp(nUI19L9?>}+x~->ttLj7}@6ZcJ|B_~vOX$F5TO}z^ z9517*Nu`9xh0N(b(_GREB1uvTB~+RS=}`uo5lT`;3IQJ<0q=TsonA%Q5>!KaY>&*(~~E=){V~`lv0dz`ZxFO);00&|5JUaAgBVJYQ6(H z-vLK?b|ZM?2u_u-@F^!dC>Jz)^$OWPG6eBZ#lId1_XNpI%_$#VzQ&`P^SP?my*3?h z|60^f&7OrjoRDAUiUU*>OGFiF3VrJe$0PsSGt57BiUFn3p{aA*!wiYpXHs#&O2?`p z-CRYs8iNyNJ;#v2f}vLemH#lXx)LoGwT{Qa8EAM=cF6cI$sfZuC|V5O@uc6e{!Bd7 zrA|w%}LEdLy~55adl4745@O9w11%*Z#}16Z{)Fo(2Iz5CH+$;siYkrd-C9<`wyL`nRh5-70ybwQ9k(PgDwypL@(?m=_M?MT zuDw}|fhR$sR}~{g0Tv^1R6EI0=}rX@(anZf42HA=*+Pl%9OaK}AO0O#c8D&a$v=eu zuJ=dWzn3pW@DS}jh+2dIC#Af?FQbcT^GGuvpP0!qUEZqjSE^D2z8{@4IrgEncV?h= zXby*+$G`4HXa`A8=HGe2$BmIqml+sWRWUjMr`e{s`blcGYM5&6QZ)3ftjXGY*myip zz*zQDn&8XpigfetC=Ky(6Xb{q72muDjf5MxibBiNB9?##t#2}XqH3~p56(4~F$3H! zU?|kjKR159$z4`v0|VT2l?=nkBX;(dBIh{SKT24tn_>Zld$18M?Y;b$!6(xo%{W6OPA{?Z>lg?J}7R`T{|(j z7pfU;68JKep1P{tSAYwhbfq6Ec#0-@HBfnG_*;pCariaqUx7?1xUzA-@AE~fDx+mHm-XzlV*Hr-(@AD^d}Gp z-=b7isdQlR!U}QgfCGo2Ji~YX%f|izJ_@2rm3%CTc_L7T2kptX%lR3oOi02vzcRs8 zEB%?f&@ZuXYs;!>)OHMj*mF-g^4S>xd8TuR($80(`F3#(SOZSBY7bOS^Rt`PT<-$% zSCVjXP{wV75}loOqhGmMB~3&7!DdyOTrjD@?zoAc!I;Sd04>15tf?=#Y2eq*F@S6t zS)oxyp$I4=l5v*K6(_35H>)VtGvpwAZ$~xMKV#G>T`_$IhRCov*bTR4U{*-4DoD4S z0?|z_h=0Zy^^{iB5y?}HpJ>!q90u0XVQzsWJ^0~1EGbd7WuL$P8`95dO9Pd}voK)QCgTC-KUOr@iZufU#@ za;^0#0<>zRG=Cy$?q*>0kC@Njm%dbWt5^kSvzw+JXHuGoQK_`TyHvli|M_+d3lO0C;BVu3)eA}O zZ!bLjeeUeL>uZAeaJ#8#9biN7JTrKsOzFs|v{^P_`lg|o_VhcGe<=sfslyg3bE=J@H&x6tY1%t_|U#XaD+m)Y-sTP_^@w>OP>e(v%F)JThdb}{Uq4gJ`@ z;fE8YH^poDik?EVI!N@7s`B5czfnn7GTjmPq>ARp;`^mOgCDOe3D#8(Y+UHMGJ03B zQzfxGUSTNo>mEIG^Wz(2JxR?BmoHm1^s9@_uDTUg(dpU^y!Sn0j z{cnNieNh zO7)N2PZcw&8@gzG@?BS!(e)RV7AZ6Oo@(}m8Kjfy>sfIjMO;!5UPP*={?$d->xUm^ zo7{MPGvGn;-wW!?9vSY>F72A!SRvm*RX*uH;MElm1@4Lqxu?ug7Eb5<2BGv=G*E1>+vMp*Z zzFH48Go;(|I)XkaG%UYu6J@q2`gaX5D>3IhKj-!%H2GCR7j(Ggs;wOWC=w0Q0A8fN z^zY?Tk?#&krirSigEiNu+J?koEn8JdapQr5x({#mjWWbk$Ee;IYfM$TNq}Qv22KMA z(Q92=pLcemNL^7kZiI-yiM?C`*@U-7uy-1ToGAHJrKRd%W-)(dmw|fRYfn4xd(@M~ z@q0Dc0x|i_e5;S%>mib%O*I8(b{0Dx;!`V3q+Hw&EegDKD!9NrYSXOlBFJN>AWZsg zCfMwEvr)LUNnFuOiz;I=S@iT2^Wa`R?Zc8N)P@rpo!lkt>@*v`H|!Y&2eCs%*D1Yf z%@b)~4n#JYdw7-gr`_09JH`j!fUA^0B_w$l2AJ-2)l3`?`DeN-u3=FPrTH3Ba>d!C z-oTL%ie_Jd?2>Ng`j^mx=fuv~vGJPlkgIv4I@R>boSxRZ51m4Xn| zj>V!3@QRCJWk;@rXkBT|4A&OAqp_&{3Gla))l)%JUu`-*_Roz+y$exc9#39Jhbp z+Aw^{;;UIttF1{oBX9pVZZM>eG(6&NHNAHD=64^Pu+P&IjyZ65o*wT)Dk zSM$@-R&O`rvgA4kx{vj~czge=Aty=XAy>5>^F)Hu$RkBfBO6!X`B!(YLs8Z4R=?xE zf1fSx?Kx<+;TeL}pNng~+4u4IP~2To`_Ylo&52hAXDAO2-5n5_qYjL#YkiIJ5SY+z zp>c6Gq;&-(y1TF-z8;u_|159b>afeEk17+p-=WsFyZzd=m*=Kh5bz2{L82Lp3BHJl z-Q9On9WbY`Mt3lwlDb*71jT>athb~?BD*Vu=}dq@+em8WsZLgCbGTA?LU=*q9~&h> zGs|)nDDk86vofrmH9xVA)XKk=igfB0*N;Y~c3xL1^@73K(FMu1)$s}<)1RgsIoMi| z^2Wq*#mkyS3N(how;K*tr|i-ATpMNI00;ATb5{;HkI*OkSu&FhyPp%mGC3Bn#4%(f z=`9$a6do|K9bXVK)uaI&w3oPU@N8_1B>9E5XhIuS!_jIyPqo2N00G&^`O1G6THX>4 z)46PScH;rU{XG9E=wpn?Mu-^+xck$H7-ozM$vYx0rXGz-q<};P<&tE2t1j+TgRZ#P zv)){>bdqt8{7aHOmJP;gl|NHzaK7fB$b%)$_9*O?E)5yl=a!fpS|MP=p%+H4W4W{L zsHt2FiC-010MHf|FYKzAg@h(Sx#aa)_JpVGYu8tHTtf-7N(!c>9ImToB97EdsDFV0 z!v7xt^(e&fQLeFQrP*Bl>qB7T1RqJ|)sTAkxy2UUfGG4s4m_#ysxd|otGEu@mp|PX z^tI{lDTN=}&p?s}Z16v*cJTbSSxFNMxB?1OVWk-^NSXrUuJQc{-`Da}DwvXqJRAI_ z!10J?j|lKZFT>fwCy8TB;lf~O6_otcTD6qf++oKEk&=4tErUxwOSmuLm8~HOwH8F( zWN}abc3kl#FrT45RA_b&hFoTda2fc)z+Ik9YlBSN zJ2lv}&n^Qy1sCetb>?%2W`&vS2G-y@=)EGV&$?!x<_V%nimZ9fZ6C~7Q&BcS38-F zifEo97bNNTNL4PSt3D~Z>>dz=-C{!xc6%(63H}J@TOf_J5qJ<6ggWijdmwW}I1r(V z3DmwBTsfhO4moIU{h2Fc!t1I$tS z9a=r<^n~c@k$!3$KESlk*i*!p@S3QC+%;foW~Yj|3g-lvUN+jNT5@e}gV1h`WziKR zJvZ**q0f;f{q?8B_Qt1SY6;&%gXkuv| zgVLoUB#ggw)yKlWSlcY?y}|N=j^W+|&R!y?4}utO464;7pa@8WYr{qTDJY5h8yOSY0p$$)Y)bz z3eO~=Uwk2|>bi-=zYf(}Fe>`;!YY?F~JJUmP+t4p6CUx*n%qB zXAQPmN3SG_?RW;s#vWcO4EjSenMaGK^8eFHa4jIAwy5Z}X1E4Me2ao2n+m1Mv{+FK z6MzIFEKS=Hwar6ps2XRyK{%_Ue-0x%ns=G-j%;&LAhP2U4|c6oJ4*`OL{HmlM*c`} za1hj@K2byuX?X=wEEkAc;Xp7f1UW%P{pO;!X{ZleXpSUtkaLKvjb0-n2n*(s1mxx# zYKMScBt;`iwMotJ5sh>^HHnIk^5LNph(oAIJLIq_no^AXLA4ZGo7-#1-dVZp8S!C^ z{c|K#-h}NkTD0#aI}4^gwm`V|qC*NK{xL&~Lt=V&O+#5AQPT7_@cZ|j4N zhO#DW@EtU&h#J-`YqCQ_IHrNehf&|Th)|-Kdx&pnq3JdNwH_o(6rc&8Y0!-4;}QHi`vaHAkq;pgU&Kw;4VPc@EVd@j@lkZHaG7w z8y3r%U{CHvCQ%eD00{Ot`zyirpjPlDdQm>s`VHFbOx$7al2<5DB%ZTxnu;-LhX0|U zW++gEuMyshxk(Az)JCWd9BX51M~xtV(GcqB00A9&tR^KlTJ%#h>KiF`a7}+)L(+gM zaibjdONhNvoqwz)S`3SQp`mCyxmyI}iLt}u&8T^<*cXmtNC{{Tiz-?39Ol@ck_Hph zt&_cx5#H>d90bG&tw(fOq9L{bnL&xjdaNW+V1!Wo#4doL`sq3(D)eTE#4w%qgNI7< zk^4$OP4n2MrSMHIYG)Rit%Ek9AyU7?9gEOsz9YBkRE&X+`gWQQ7P)^1^^}GD!M%_l zf^^4LgeM_OI7lHN61jsm;lLj*vDar2>uA)XO<*JsnZ8ucTxXn9VS)HaOK%hUwJXTFE7>0qyzgh+WKrP`UXUzt0%PbdsY<@RplL9$_{Ow#dlF+uK>aGL?t0vyG%fB zafKYKLF=ros~=J=616Shzzs;Epb^BcS;iMSa?>^~(GT3jsTEL>>Hdj!ShfLA;(Igq zCyh;)G@B#Xf2CG0tyzuD`Md(*oG5l{G~~zTZ1eu2JvF!;E^@fo{*?@@C|aXs0QnJc zy=1_=tsl&w>xzkCrN?MLW|2$HNOw$#b_jNXAk@uJM$0;yUf>(E_;ngmvvKdvn)N4p z=rXnLQ&=71T^1uzR*w${Vn&>h6^eHx#lvl@7C9NTwHq-aCpNO+H(T+m0KV3p;nL1CsbRBRG*GQk;b969d2J zqP_qiBmiU)jpFLY3RNt=7Q|3$(^hBqU9tz526x(lGJ|9q}i^ z?x>ze0wCuH+DUyIxiaf;d(5qpaOe#es7F=*=Yuw&Bev1!WF*0ZB$R}}{Kh&7HA|=@ z0+5qWk(vsfupP_kP55t`kcGXYK7mZ2T#X((g}96Sz(v}KxSgAm{enjA5<$g&w-PUT z@WWrRzwnj`QS9w-&K3pPN)vUgW*BOs@!O~nQ72b#*+=Y&0@=LU?W~L)?Y?(2qt@k$-u}-%oZ~P{kIw?Qa3( zN(Oi{vtX&px?vD0A%Z;u)BZ>j3k5)`&__#*FlHPl>rlv%?jtT3$R|j{)*7-yh}Z*Q zo&G44h^!qcZ&Rq*(!r6l@Yqhc_|JzWB(VYl@|S>9_jvKjHW8Ufz}gMNcX+6}W{nq< zN@gUnZ#BqEq&>-N2xDp9xoo(TI%*w&u&eve!2|q?U_VKLn$Sc$06AO3^_4*IAn#r| zfW7|@A|f3zSPkjr`ti37lL=x4M6sL3jdS}EZ$%{XB*D4E$bUrS`kaUl7v^Mvw6GN` zruQxc-Kh2veRl@=J5!d?W|Jg^v!jXDH)#=!V39Q6;!)f0ezFlpN^+-Kyv%RqTx?E#l?T#3fe@r&O(I9>;h4#yX0{{ zZ|^J@YR?eM!Ja#L$zFI|^x;AV1YEy^P;l5O)bbGc5M6wgj`}!jgS~JZR@+7B=@Ij` zx8p(+=;~*rTiqihBD}-)6oXz92tH23*Y2yVtic;NS7aOrk_@`ftejqRTjnRTm%P1m zTvz}aa)a(@=aRfSjQSwd3O8WDI;5n{kvAN-%~@nWMOehJj-u-h(?J28hS)nG6QbjX zW^8uAV_GYsJj?WQ5Ne4orkX3(a|fyR7cG>*|5A)xJVgeGHA;r)vbj!wV`Kv*r1OYK zJo@NIE~J5WWR)hC$Pqr3k%vfo+Io=#Jj5ItIkN_5QulH$p=Q+F1K;W{{)Rn5hkSnU zh)z4E@&@&p1hp4{V4o<)aOsK{M5XTl)N|ewg>kzhYW5@4K`M>5ML^xzL{)V47p%dU z^vgeaWf1;5#(e@D`VhXczH`FC+X`&h#o|Adt+Yj;*i6#A~ zvp$vQN48|dVchH}B4b0Lb|mOcbtIAKVMhn)pDCa)YJU#HPhSur&O&ZXP|S*MdmcTk z(PlG0jM2O^tv8JDxIz0A3LS8|CnYLkfRO0a8}jw1^lcJX6C^F~c|TtDdrw4mp+FrX5E( zB1~d44=f~^O-@9=m{K;Oim##*-D?r07h2PO^iPnVe=?V=lq6!VBacF{eBRzyBv4-w zsE(9&xZ1jH6PZkSq)jy188%qHpS|~vE{P7BrJ)Y)wRzqMBbJD0qY;lH&Qijr!fWni zcbCysCBlTm=rIU9li+X-Ch3MYOGfnrJ{Ni*PyFn@8l`EnHr`d^G)sky?K&PTV2oPi z9DZ_oYO))=NGMuRASyJ&-P@18XCP+KZfRA(R~%H#U3m+@nBgfg9im&e1SI4hLWd-_ zK8#E}EE)yS0)I5$Qz|kZJAQH!ai~pPoja>dKwt+9P3YfxZ{Er37k^JhP-#=z6wwtf zYJ`3<%FXCKMbs7K6^|HxNdlSCkgi=Ibu{4%B?Fbj0-RcELBqa{~7#1{_C+FEy*IQ^h{`Ju4BwBsHBTyOMG3o#Jn6 zcj4n^wn$=hEbeMkPkGdX(KT3TGe~D`EYVgstng)?e+ypZVli)L$K}B?b-#cE8swtJ zWVTDV2aWcliA1>XSeBxW{f);2v1v*f`QR%qP@6R6b`7<}(?7U?*p0;6p&_4%O7FQ5 z5@jGFR}L!&?s#0U&8Gx_fIf+O^z)f2iG*G#MH^X zx16QYz&gnE!d+MQ3-#xJ3&5oX6NX;nT#9hgeKfmL@b7K#ooGV7%f?EJ+7m~~2HMt2 z26zK?YUr9*PC)dJTea_#7uBm=lYT}8rs*_)4i2kxoM|gw{BSa~jF3x(?-@6{!Mztb<|M=M$b1KcH+M)8bV)A{rBtV zJKs+UXNJM^p_Nwu9XK>r!U_m=#$|t;R)eT%aLC_Q?j8Bz=%Mvr%%IOs)KA(oRi~nR zZJ*!F+;fNB_>TlSMAN)_rn)GL<_cAEOt@=)a!h@wed4N}xZy+u?$D(UM+5F>{D$ntHdwTID9o*R$9)(ph zm&j-oK61$xpXw{w3i1Bf;813nRCuV!?CUhN5|hNS9ggix%2$kE^sBL=!nzl@(@s3e(VPS)0M=bdv(%PbOlH4>fHJJgfx0{jnajw zzQM?I;~q??5gMd*;Au}QOMmd66Daun*TO-wR5s%`wLi#NHS07|`6QH!l2BCR1X~{CDFlj|Fkn0$?IcLvh&?z<7PAAe3S5huTn?Ssx25-W4 z_eXyxNA*`-$GcKI3vuUb^AfJ6Ho8WLo?2XRv#7V;w`riSJ1R3wpsa(dK0gtIWpCCeYzuuUH3KRiyA0!OC-J&WHXtRq()h z-1zrHRsk&4h8DISlb~Wl<-qr5RLTGLgP3iQ#ayNql!~@XowMWA4@EaAZaWuBUc;aS zUq9mhPO$#{2t-+W8;IG_?DwzC?GYB9@Y{~Bk|s(D{)0KW$F#I5zz_K^;x~BXY0JY!3EH5NXY(iaoZWGuLcBD^B!unp(Z~>0Bc)ZX@K;zgN=h*t{oqXbiM$iBWy0iWBs?(oZD-!p*H(IlG zT_3DDo6XlN)ABc5S$gmhKhRQ7AjDMqfYctHY@T4av@Zbmqzb~3U)NBT)-K?1xw%E`me zrIT-J*}rhw3oICO=wO(Jj_~)4uuo`hL!Ldpr%vmr$TXj4p#F`h;S%~K7PDhYm`6jg zrcR>oHlJj_s!9{7;^geIh?6UfpyyR zZ1B8*$2Z~RypI_J`k25nb3V2pAvFs(;sd1jYqz<8UuB&*-}{0fA-0Fz40@nP2-&|u zI%v@jR-SPbPCb!oB(gsGRgPhi#8yhE|F7lJmh;MLURkBC zwM_5&ZExzK@|2IUSO3CY)4a*UOuVsQwoqD|sK&kOW$ka0WQY1D#P&R^vlue@+>jJ| z^egCem%R%|hD1D`Ael|V&gGme-|3Nd7n56|LoJ3G!Z<%`M1}Rl$7wt588lZhvr$mO z2pw`!`t8?mOm1ym+9jhKEDsNmMLG4Wi%ymMKgU;Hq3PGiPtJ50r2=mi$=-|{^WURH z9f8Ms-^Qz{ACp`LiQJm@y_+T9uM7*s%D{79;K&WT{E zC=f$#D*|sKw|m1_?^a)3zqj@JSU;m6o_6HxV117p)NtuMI(f>`z`@#a4Sq|oRP`Lw z5(U2CDRS`@4%#yjzE}Lm&&u;qNH5V{OTRenB#ekokt>t__#mJZeQ8*tNColIXf|b* z2x+BB?wz7!==E|H+?G{s{JhnOiDCyLXUleVIYYfxn2N^9CGT(f1zpq^JATB)0P9qr z)cNJ>%D3h|nOhu@FDuNaWB1ey=@wckaCy!QvGpo-HYcjj>%V?LBPEy!e-mgU+tJ)t zInF=#IrZtZqZazYfs1-E&qY!71!TA3ipI(!OHjjg)7Wb%bd84w8UBqL;}HgOBi9e) zki;rT;!OqIP9=CR@3|*9#1WceR*@jo$=Hm5;`ZnowC^YonNi!&WMYPU3;RqWG?B#enybs_;d&PCJ?{oj@E{897YiQs4**bt3z9Z)onj{&Ax(4eVw2*MADWi#f60aB!VVP%q{V4wdfM%%-L98HVfE3m zAS^fYydR6)nIDNpcP)!NG;dJh%eoPiA&x0>^fg|hNo1wU0k5V}-2Xvk~33!_NkWgJ1%YJydy-g<; zx_v1A~%mXUTLb;c4KBa;v?Y248*~t|+!z z%voUx>fhQjqN=JV8~YOgB0`rfgr+38haF1V&P^foeA9mVU(;^4dRCHS#?kIwmth&0 zP9+Q*BI0ii2!NJ7DAA*V?c0k@ zK!cbIC%+8%LHi_}9a}Nlpn3g)sMbaUWA^;YK5VL_RDXdC3}Y9>Zb@RD=YhLP3K$;meZ%_U~)ijg*3@;d+99SzZWXMYX{?kNjZSO$#8T5WT{A}axX8-*B=oYs&{5eZdvpYPfwj2?0`8=Q{0DyYc= zf1YsBd6htiCi<}kdQe7a&zJtfy8%cbvP9K$v9OHWhIv@duJtUprss!mJ|vuc_bhCd zmEyR6Z~ei7V&kAJub0ix|7c($5o}bSHab%JY6M~uK6$rK0{aJg#xLVM0Bpw{6{HSp z4Z36+-G`V^VMaX20`bDN*@O4|pl;sT+4snovW%}$uZokoJ)PY@^-VL;tk#Q}_f425 zwhNzKqnIbL0v)w1**VGme3NcsG7Vz1%_4F$&#tjfY>!wP>pbda-nM2r%z}usAis&H zr-p0t{h<63m}uJDI|NZ8fJw$eb0?-JlSle1+l6i}Rv+pmR7|;$QefZVR}F=@SLx)} z*cFHcfJxLo`gG-T=PNL2m`PgFr*Xl*zmk2gnI=1C63dTS0FIvF*~N`{`_YdZ(QLW( zNaf#|v`hUay3mE~g6&b83n{Ngfl5D<3dh8<^~|7`J6R_jE3s4yLCS2VeZ?`)a2Bxd z>1q`?0qt7mG}i0qT^B5Ft$JNd^NI7W>!XcVZd?`%qDjV3(mx|aKPuTwYlCQP^66$~ z$7x8Z|9HzjrRZVi{87=QH5Svm@Q8*94!|nv%py7xdY2whZ&v8BgM3FS8i1hT>H3Iz z>vxH;6aedI<%|p3^XlK{j82PZDW$7!#29M&=hBSCEvN6aj%yJR&_@V6k@zO~5U|#L ztym(A&N$GT^~knVulcy8_v$-@t=$rMW$DWO;{gChVxV=OpcIRB+(A-(7 z_iw_zG75%Ps9p7^Y&7PUswq+B4y!E+dZ)j0ay0m9W+1zqwN;CZOehrMxb5d6B@}{N zfCszoJu~@{J27HJhzFfsyYQc%8m(%fHBiPPs{0?$Ac3Q45#vwg`<`tc2pS0eNBCA( zmh*CAkL=0aZ0*lyy>(sc#9a?R6S&sp=iP!P6M7UTxSo~hL9utwAh*?WStm(Z8gE&* z;yy4m$`p7CYmv+Abnmy#HAYSlLL2kw6GqGg^nSYwYlo$%UmE=D)_L_@6IJ&!IY3uk zXmZixj;Le*>heFCUdv8^dO9NMInXzf>qe%Z!iHHS-%o`M*qJqP(Q1*6iyB1_5ygEn zm)QJ4D{HvTWiGF^y6R2uJuIVjB`YzBbu=U5 zjX$)%H-}#{QnIbWysV(=AyksnN%SMnvKaj-EK+|syhsrkGw>V%O(jAb-XiyUptWX! zL9}I`&r6}5mE}vY|2Qmxj{pMS&-!H35OPqAk|`Rhp<~ti6@JeVZ;o3FLKqx`7FV*Y zmQR{*Ln02#ESRxe2vrKyuJ~r~7?z{J5s9HgORJy>;gAT!m6m(L_kUJ8n^&b5(}Uw2}+jm3se8D z7!^C^!BK(;-T7|z{?oI{F+?zITAv2Eoty}<2sQAfLVMJIHt4@Qsk9iX{log442~pf z`+4&W8$w>+PbkkkbEYtsa6GO^0oM#k>H4upugC~|5jz{1qyZmHf@T*$b8h3KhNGi+ z&^Vaip)yrVWmy6sJ(iQ>Q^-1nWjUUn*!PeX2rzsXeEPur>s%HveC^`RKy>pVh07f1 ze~xjYo@Zm~F{ALxxZ`Keq96~BB}BbMGoHfaJfQjKp(jtVpB;qy-q`KBc7|U56p7}X zhajH7;&;zDcJ=stubk45=I& zqZt-CR8o5X?Na+u3Vm_jqFptjc&r3gvBZkZSjs?bS91vIs~8V&RtIz}JtD=siVNlV`e3lt(mXM__c?do zmZU3=e)h95+i9xFOiClmvGD<2`gJvneOf*VO9`6tl>t*$PO{gb_+lW)3ZGxuf4^ogs`r z?s+Q1-|Dy%W3ube^z8cV_SA)^{^?UHhvF!RH!I)*RqYo^2BXej*aEM`J-whhEHcK6bG|um@Jrs>M|mg` zc49`!rM9aX)eEBL_dP@l*Xbgoyr=uMRgCHkD7%|3Vsh;K zoPEwsVC64FuOTyoBv3%y#1vJfFRr#?o-Qz4)H_pV)U7` zrse-8XLwT` zg;&W7;f!A1s~9G^M#~H329YB4!{AFK@es2b`L1&D17XW!*U!aWr&Q|tG#qAH)XpD# z-Ylx|%WM30+7{c6{m$4;$1283Gcs;4d?9ky_indwQ%t3v<4fl^59UqEFQ(i$GI;6D zV~}Zcnv#B?#L0;sRnwO2qx!*$UnZVfo3<8J>Yva%>F;bks($fd6K3xb_m_sU?G;M9 zB3w?sYtEL{Yz51oWci7_?(o&H09>?C)1Zy9^`r4_>^UI!l#j;^`TG;`M6z!nSU8cveyk;tPfhV=q54BniM4cnloKR~ZYnS<- zV7}{))M_A`2oa0ev4jEcc(iWBpCXXID#iU@EiuA}QCD;=I zBS$T!WeqDyF{|f7gNt}n?B9NIqH^Bx&rkNCg!z9CR(@o~qO&beu)m{S2!F6gTx%41 z2nOgi03x!ynx_H@Q#1JE_}e!($e;{+dH>|e{QF67_I4O^TrQ{U)z;u~Z~HA)B$58d zmv>PeA?6TP(IkkR|7GHb#ReI^YtmkF$&Y0|VSq}V08MGAv|SttunO9LY3#A-mo692 zu_)T2QVLEC$yv`&o()z$-Sl*S5kIJOjE-FgB-$QPKn2y_i{~kw)EXtD!fLR0*E$@D zo9p?nA}YpI9(#98G78+!AD+K=CB8neb>q`4LG@Zre0Cry@9biatYm>{fyCPltYGTF z-6!!cj~?4xdVTrI0jKCuhhwJ*%8E+gsW5?M-Rh|02j79&i*;YuI4_9D_a7uI%VLL! z8VM^4lOcP5tNkg8icw)sy$O%3sL+X7TiH9ohnwEK0AW(tl;PSJ74u6nbgIFgG&3_5Gxqy8-JvB)oPUNIxo3Qd8DdY#hM>p3?>0U@bDikQX5p!nT5me zgXF-NdVcrKG>Bii#fS)cNqMw@pdkBks!vOGJ3Ue0?cz2BCL1LQHdQ9|fgny0_(;2(gtPT5ZEUC<0B0WS7 z=ufFD9^GSnifKv$8vwe$W}wg$K#_BbyGKP(BHf~Om)9^1b+`?28?;9~gU~If250IA z0QGH|rXe;)`lG)wWL;yh=_#ghv$fJ%+AgZJ%(CyGkEjkBtTSaRSr6O;XSVR{Oc#4z z_}Lf@d(8RU?p+kd7LkwfM6na1d+A3U`vCfWZ#8U#;6!WT?2%;IF-Z$*=|iE&#k9)B zlV^M-y#+x1KTH$Of?7bva$%qp$J!`F%~T((=M5af*~-*{479r)RC_|o7Y^`1hMaD9 z0K?^0T9P_2vdLPeD_dX0hPY-O{EiWj_SEj(wPb(rUT^RoIuM+XMGupSA&aK2U_+8* zeC;9PM7PW=nYgH7I0h7*2O5-j6G%NK1g88j&~&#AA<+rmpC;d6LkJK0(*CZllqnaT zyW9Ewp8M6#KPHBwRSZDEhS|rrS^_fEgY|;6;(rCjTYDy$YsFDLc&HcKWJ1OQq*T!7SW$u?$a~JZR`?cB(lZuhtl16e%8mW*p=2|Ku zNz&X(rILiy_q*SI|8I}&kL{fEIq&!T`Qp*cu@{fkOt1ckI^5-Hxp6sQP6!WaSY~;+ z$*J4LL`QCeahnAFLz3o<6A(P%a5uqhj&?3_-g3-tUENli%qeqNw<@DqTZtde(|UBx z_gpUU@LyW#jQw-6!oeB##d3~KGwo0`-Y~t!V^9FM4zy@{(Q%FcFC*|jq~_q7M1D^G zAYN+*sCB;Sw5#3SJPwA*HeV(9FWVcwB;n?oZTo1rIof9v2Z?Zk^*ZqIb`zhiHLY2B z*-W+A<{0|W z*dUzwz<1Lx5H~5R%>?!@UXnHnbG}Abaxj;?!f6)BKcl01_I$9mndN5sTz@&?FpIUpq z(H&w1q`VY2&*fNDidzKR`m*tcu0B>5fo2TCUDyey@>-nl`%i~LDqjh~8NgEQ@s2!# zX|pY~fik(yXZqX*K~I$c#_VZGz<_=P)DYbY+YsZpd2bp!vat!$O3|v1OFho0 zd!VV+KmR4URdwG{xx47g{gFF=%XR1PJ3Q*Yl~(7%AV&eBmTYZ z>N5zrO2WcRe~9bm;3MGl$lJsd5-BgKw%MG>vI#Z5gXu%7^tDAzyg%GVd41%Q8Q-6s zEGlcJ+0=ZMd8-O1i1ldKMO-+L&uv>&a*Wrh6J%A7v#QY5Lw{HQc^}^l7+tpBCD#n<-%r%F z`FOW4=w$m^to8L<__bS;ziVxqzUa>C&(D9?9J!U=ub*;&eET%)acQGs_>#GL{5c%J zV(25YYkoeSAo3C_i{<0RF5Z*x)wq_UX1KQU|8O9cywQMx(=z_^f2+Na!^3+c zc+Fr1k~=N+FE2^xpch-GCFKADKLqyOq&1{P#9Rb7O0xzgYi0!Gb&xF>yVeL8}5V!K zZ1-3Jow85IJjCOV4jpKq1Y?G_M>y(CJZ21Ng9M6_2l$e*)+qacl(#i^;V@CYbcS`T z@<8TQTA4A>ELre#!L44^rNBd7e;_aZ-7&&@^NhuUM8YhS|ERL`zm@%G^YK5K^ap2k zZH=~bFPNYa>40O#e>CqM_SkkHT>l!Ke9Ve$6F`7SeL@y812oSyB>oY4(u#`ziuHOb`bxqe1#eNykb^?uCS^nK&FVRKSdh54BHaF4jjv8=ChA0{y@J0pgMXF7_l>+|volj`~U?$uZjn!%~G+&6b6NSWJ0 z)NQqdIL5&=lU$(n3{8XhLZxcTR7llDNY|zdh#3;Vuxb3q3`kt7&EFI#lJmTaV7j_y z60N^XZjprEzA|nHX&$iHBN#=87Dn&o|9QYOG}X_+**=KH*6P@cT{TGDi;RexmguAS zZx7!2lJ{P627spo4yuMOfaP(zfJ?Ajf^RpG!#+5^#6}a#o4R08nPYmK4$EI^= z>vGqk*PJ4-FcnnG7G1EO1X>|83gmiv^E^s#9rVEVcqt(MAS5Ed=BWXW6 zeg(#K2%IcEHvv4{=41bhN3*b>8i;JcU6j_`HZdfwIgkB%9aAjdeac2;;hcrNU)M;* zu?y%nnhl#^#HFH)f!UoLIYTW8O^Z*%0%m)J+1NAM*>D?YjuUeK(w;f} z(Nd1dex8?*%dw#V5e*#6O2OeRw#g<9hgELlrRqQ691iBtM+DlxSj0kevK0Fd*U(<5 z>#0rNx0$oDG0xS9lTUqW_a^OyFAInsqM*Aa_0zM;BWagT()3T^MM^0e_G2d5PG_#m z7b$(VIY@Z4Ye{*0izj1Zpn8KkeLJ~xAtx*1_k&{E!?^+8nZfUOeWb0a*2>DspHp`E*|E1NzpuYd#_{J4zs?UccG3!5;yz4 z>2R!$9~93)3haUR-bQ^{dzptD`=sU%Tzf42V!P)q(4KUOxcj-Jbs&skl{G|SmR1o_*$SoO!S@1{7k<0sljUoZ>BfS{m5o7Dg1f$@1-BxN+jzlM;f{ z_u6hIR86x@{HwBcfOh((Ga$CM|5R9o;fW_JH8u%kjb)bfx6TMMSL)R8kAm7q=kkOH zH}ksxJeK1Pe0xLl*IP&}e>>Ee+}fuZlVec&Lv2(Wom`5ELc0wvjozfitT)u2^D=K? zs!l{}U5|aqw<;30b(%!}bhjLQNUoVGY|$MXAFWLp8F;Rg`ME<#FDHgIZ0+J~%qL8@ z0>Q-!+v%g|E;cUedYl)Rp8`MQc|(L+$X%|T5U!mmouc%PC=@zR z)QwqryBe<;O1c$hCb_wtH!i%}Q@p6;?Pj&Map}4B)7-lrA7*E~>&-r?Z@c2b4qY!y z6dzqybC%ce_B6NdmGnBI^0thh;`Fc7Oo!tEmlhHKm`{V1kwF{R)yV-NdAjN)!-|;i zB{xAl(+d^{T1H~{9$Hp60GO{}EcXH37O&KL>&~D=8NKs)=+C-)^O>ySy zKU$pr&Gy6KFQj*y*HOap3g&^>blJso0jEU@lz#*^g8na``V{zteRZT#3YOkUrz1b2 zGo3&At0={=0pL2Qpk2+m=Lz+MM&^W;l9oF9i7)+F3S48oLF_IDEt0?cPENgF^g+m2 zl3+gRzYMKM(rjDk6}eDKNW+=+3!664&6e8vKHmaIE3yXpOzgQ*&r$S=P$I(?tm1lV z5c2dDgEO}L>|Vayhcy5)Vc7FVfP{0)$6+~M)fBqMV_JVSd#*z*UzxU0>a3Qr=XjlW z;WE;>nY<&abzZelz9f6^*o(SV%+Dmf{>RHLA?ljh%-fAe?k;KPq)b+0{dd#2r{Diu@0zE-n4Wt3 zG5XJjnZm0EnosDsMrC+?i!W9#Wa#3{umGx5d3R5>_6>#?p8vPWk69@2}Yhb zH)6R+r9YDkw}oXQW7O?c#B|gNicjP=p?1Uk7E?KG%orqnKvvEmH~u?m=pFI$gGc;{ z=gqyhjKbuGc&T;>Q#a@QHlS!kx-OJ|33}kCCqiQ928u-TmKemI*H9>NEv>VM%O~Vb zwuDra6YZsCOqxDwgr__wG=iJ7hQlQ~)th;25Mp3J$A$=JS0IEUbv@AGQ}m|8fTLM9FNL|4oAO zd&+hEqzobpN&pW3US4nwDbB3S5jt?o&iosoxUFF|M3>0%=g&jXBcNd_!?Zw>Z4TX} zB?NiY_SgtjkiO)gmmElXfDQm+CaI|1058aiHBjmd?07+8RCA?^k-|WjlAYW2n^L8N z(jVZUJ~qr^hK+x1KZ)95japfBw4EzZQ~uO#2Q8GO=`z*$xls`WGDUP?<}?!U#Vz^6 zhh{4W;`I;2;>>nNQE!TtsFj@4(!>Z*f)$G1!>D-|YCfRho8mRp0UDpDiZa{Opz^wd z9B1-*P)QC`JnYEp{{n1Tu&wlc{&YTEbgE}bK&hzgn7S6PNAu{`q03jHN}hM9w)i#y z5j=&epj~!JUS>(*Gk!FAs-!4A*%Yc)5<&&Ux({7~uS85|9?V1} zyI#qVlRshpxW!`s`M2uJM?MPTGh_Zmv2@PsPX7~c)|c&v69Dj$7L^~z z&&v1th@F(eLp zVv>WA8sPM#*tK!_ytL*ISa*hxuG^=f(hysf*nrUSly#!`XJny!^q|c5?olJ=f~d(P z3vzr!$YQf(MFU}{4O#U|%lh0J-_@yfzfws5dB_wGYIuNC6BFY-m#}y$c+A}IRcwY` zT|^q+Er6Xbx8%wccPa>hhyMkef_^O99@J7cOn#PA3kFHFI+7Q#B+JV*J*7jY#rP5(S~pqO8Hh!?Qc_Bmmw$pAcvzz0fN zZQOV*@H^<^C#|5Ldrsyeg9UNyL-CA;5_O$G#`_TrvRcZE>xTrM;BwH5#9Y({vf%WL zn(}j`*oe|coDwcVIUr8rY7D+Gqg%Ug<+yXv=cW3T23ZXVbpWdnU%Wdgr9L_osW6`L z-geFG{+~nSbBJH>MgFn!>e)nRyu zRF$efu2SgefBfa5|HdnqM?EjrE}X;%5tPHO46O^kyLe`3r8RP2I&Zn8uu4Ne2(J*U z{o&V2_X}DPT?(Pg?P6{!r3Q*G0W9_niaf!seX#w}`7cxieS{!>;k>O;(5d3|_1aGh z&HzI4JH)Bg7}amj!8Vgr1HDR`7B4{E`Pr7uUN=V-B#}636Li!laeGB6t>$;kv?rtM zBo9p*T8JC?oq5zfF;{sWfS7bcf1}FY&)vHieraq`CptqvtHaBKF0W8rDkXZ$1eBDsV5D6Z~G{I|7vm#Ref%s9s5AUzLPc&1WZx=&HH zW6{;%=QX7G{zU9Yt0IrMc5s4wP2(y4JR#%`QoULbHBUwLvc%qnDA_;NSqzaUF)?H@ zbT8FDT>!xzKrIhAd;p+lRpi?9gUC$DnGiJB5zPhohYQKf0?=?cdMre4mg;0m&|e%7 zQ!GI(*2xd4g2JidJXD9+dw~1|Rmm5LCW|dO0BcvtDwc4rM|8LLy19 zsi=8d>Bk}Rs^H^fq?l2Cs?4hRqY$%nFzCH4Y9m@Vog%L1g#L_tOu-;tE(yLKkeDb0 z7liPms1V0Lp=JT{py#e+w#4j`;FN72OEi~DRV@1FW40}7nTnY&keUV{OAkW30bgd@ zQS|^tZk+-oOj|uyiK`+XgLsKu5`PHL^J6N=iEr)DBn}zKybY1&bCiPusKq7uNKH^L z0NuDckF1ycF9i8X1^qlkZgK$Scn1?hlAgCk4aK@azM&>;VPrgl?I}Z|hz$bJ4Fk{w zj1=$rfWi`J_a#8aSzYz7I68kRy0=3Ty`?nUw(GSd__j`otDBw}eqa~?#XfgW-@LkK zKUf|mY7)QFYxp6xJri?LzEn9}-LS|GZRX3-J5z zun0ly9WJI@0NPCoJ=-ej2axfip3k`x!bj@D0Wx+fNVp)F&6e;Bkw#N>1td*c@z|r1 zP-v2NI|=J1X(BpkEbMI{YG)F0O2t_cifhUq6u^GMAO;0M1pos%>X-SK`hihZr2<%j zPXELZHsX}(Hd`jVPV($jHAoekkfbZKB2EOzkO0zhR58s~Q{kT?*95RV+!fx4D42iL z_TwvdbqNB~m_q!p-IC!K0kE^A^^XRuemzz?)D#hF3jV3wei!pRNe5|U+HqdB8!zD% zB7JZPl8!M)u0H0Lsf*cSoRbR@PJbDe=FD2;8yW*odYiyStnT-3U zGFE23EOp|8@v@AaYca#)?)jr1K|W3&Fcfx(x|hc_kpxhRs-}tGA!#D7i+<#uSH!PW z?NHdK884^&wf(YuP>!pHv`7Hx4P)G$E?6}<;~0CzZB#Jm*Tp09H>}Pjn|nwT&Pf^8 zVqIe6s|uxvUB(%mEuh$Ti``qnb!B>=VvpRrl2J=p zi1LRJxj{B`kS)tyLO-V-QMz~XRu}Gdr;FPCW6HCGrY}N`{KCx2!z@j!cV31O{KD@b z!>ol7i1X;~$-5g%CpH+kKZ!M}euuQ~AH75lw;hiB$1f_aJc^f<+Jc{rqWMKz-wbyv zmz`O97(9-u4Qa2P38ni)mTaDk-3g-ac(u;P-1Uon;1_#~5&Kvsu5SEVC>x3f$ix9; zw5f3Q#PFV1`eCMVD}M1G%j3VKhAqv;|MZJWDnGt%;VjPNAhF9e*94!3}Y(i2uFgwW2TU3;Nq2m3F9JM8q-ml5y6P{IsUz7+RVdnIh4t zqFB%om4T7(4v`ls#ehK9jqBr1n29~3D0B}YA(%l0JgUs}**HK5y3wu=*N2VaL6u;WK z^UEn2Dq&rV8Ue3m&%R4`3!C+|n4{h6Qthh9cF|Ph6P~>Q#fI0ScfjV?seG_c;i+Wo z@6ID6zHDG-C$elD^juX!m)a3U<_mxYKhB&qqlLttY|%#Vt0-lPmjq*R!YAY6{+l2(==4*wpIMrtvK>LYX)=f zdw^muReCSYyEEoWoNeJK&Q zn5vUZcFVDoWG+=as#9#_LzZtUtD5oz24wRGq{996NeYvDF6h_mhEJdcGbn_* zxzeSEGuD))3`c+X}ag<3ZZU`a=EER^N24e4(52PKa_$FZ#Z1fJz&Gqn(9Yb{HWQ zKls%6`R3?rDQ_XXnoL0fA?K7b%kMbV{G`_0nD5_zmC!!0KEEU}UlG|BqP!KdQU9yz zVuI4F3SzSQxTCo82iq>d3TmIKa5l}F`%HiTRsMFKQu!|oQosHMpgPYVwg6DplQ2~G zKyTK`!!wR=Zt^|hW@}*(k2&yLNb%-x6?sF2{A+cn-nRyQdWtbLrChjTwuRjUMKR_E ze-l=&1w1xevs_+!{75m&#Rg^UM)d~gpo;`}xjM~}19d_kN8lio>wf&SIk=~sE2dlw9w*L$o zG1&l3y{U~_O;pfB3%!-wC8D3GD6(vo1V5uI_aA@OXj>joI(Xyp>*rT*ce%&lFVHjs zCI+(V?jO$;99XgK63;nOSmUi}sOZ;_|LN8!&v!H{+eKg1Un{hWr2<@wjSN>B zu~k^;an*U++wsSM#O&SxWqEPs|Av4FHEQZZ7l-OX?(Qj!*eV6|sMWh-&9QByDJ4^jbUAQ47)DD16n@b=C>9sByp{aDBNrCdCSFih?9lO^1Fyw&g=3LM5 zVZCdLF~!3_kp~88(hc1@ahK4~Z53Gquph9KsqdhZA#KkAN_`}P-L z-RuJq#?c;&TwkOXh^YeP#}U1p&SMS^{O-lLo&bi2D2G-Fk%rrXhe^<+GwGIUp#sum z8a6u}sb@X??2;_*-!zr?Q0bphef}S1f#3tm?icz+%EbJN?2WR{ZoRR&{AyQmTl0}# ztT1n;e-r%ZNWl?nA{%<*%taODo)34| zV0aS$UEpUlN#ya!a`qygD$u}R8$WUY2BI8kZD$7C^XBrPG%j7KPcU2D!9Zgh+3`-wt z-y6LNAryM^iD5JSGOwQC+Tn*${~WinU^1qtKt9wk;b`K{K07kQ83 zt#U?1O!li|-eG}xccb*t4>LC=@Q&_}dVhVHyBqu7{her$(@gJqvC*%A=t0qI0sz{@ zW8LI;>3PcwpYC4%v-fkQc(T&6tPFh2%_x485qiO0h~}p4k4%D@&hvzT_TppV zw24xyxx{CN?&?%Y)2EcBkA^d@VV{kQ1+br zoEr`l3qnel(2b{>>k5qLNS80E;sr{aOvZv=y5ZhH>%ndB7>T;j{+Xl~=E=w^-JBEm zFMF6@b2rhnw{o?E89#kQyJS2aFfAJCR$6+AvXU-&34J|5OBVhP;{tYg*n9bfF?fW1 z)Owq-6$qocPCvt~3N5&zdZayt_2(&sP}BQT2FE30jKeOWQ*hI5rq||TBD7wo|Gb4; zfU14=u@c&Hx0!PV-O;#N9Rt$^KM@wvRV`eB8E1C!?Nak%um?p;+U6xkjv)e z_+wPobjm=?tBfc!zV}cW%&%cyGLucbd{N<|$A9}Rlg|F0u*}Iy+>?(`t7vx>RU;>x z=ToYAGbH&_tzc7U1H_CH7&OM6P=l1`nBEMtc(nw;ESD7X!ozQ-e4eD6&iGxMy`tv! zoiS{@C5}QWY~fkBss6aMQ`Omu3;T)p^j5Kc>65#gA^^=AfZ9PG{otZvET9 zRs1)4)V#X8ID6xKrYnGBwoy`iZkwje>vpnmtU#iz>QTr~qn0zC3W$5_kVV$$;mNV$ z?7l{CccyB4kPq$jwi^0`w=*=q4sm8q6;uluwV9X_g$b!C+Zk3!`mtbR@1}cdDHRgzN#=^}8&X*5+(agUM*lW$MDE;C} z*7uem&oVug_q6HFf>jtSlcW4{3}mxahd5WjBbY9Y)uYJB{NxQF`d;s#`F=?ec7`kd zlS{XG*;RaLwJBu-DPsA2&S6ZWw7h4Ts@^thAGI$oKbl|%^P5r&V182GUmraXLj?NN zBwha#DUgg?^iU zLQ&b)?pTf5jd#KMF=Prv!tY-3t^j?hT!I!!21(ifku zPwAu9EE(~@g|IR!vL~#wuK3JB;2EB~qLa;xIH>b@lgr{J7*}pPQqT#6>IvH6B4dg( z_L6J=Wkg({Ov27CsL2K1;8;9wDF80R(Z8|qK9D#fVf3JBnCFb5sBXl(fs7Ad9hHPeU$b;j= z5rY78o<_Lv7_MQl#@r*zeg$upp6_-G@+>XjqRyatq~xE3iSYhAN1rjl$hhUmCB zVOqprwW=is$SiL9osMAgVcm65)pu%9Trd!|tU9_YlXKDRF-GVr@vF9Fz%gE55{4=ulE732;R^uf*`neUJN28toi%Zd1F+$j zgsO+FB+JGUXjC&HcnE2d^EbID>mm@n6HT|6HMo>FVS%o2w#ASG5yu+%8OlVJlUqo5 z5@SUPdtVsJ`xcm&GPAO@%5pTVy^Oe4o5(*B4H$2$JdEJiGnzu2&QE*Od?r^=tL#y$ z*}9^0L_x3#cKFRg-KCFK3yNzf18`&(V-PCz`(D#lvU+d zc)Ga~8qsnch`NvWfH~V1XHJB5O$!)b_srs$COJw9|G)nk^a}i%tMJCu$*6n^nmiY# z{A}z9tf1p%+QcEnZ(}0GZ^sJKCd14ptIQ6Ty|j4rjGt;3;AlKoqVXa+Pi%b*Y(CWL z92#&YdeB=0u08cDv+{<*Ya+Pn>%d%I^j)-~{Bx^K@gmR>X9@M>{IbJGkDaNZq4p|Q zEc&N-s)rK@pT9PPt)7PzCDm}G)|YHq7oyp6!8GF`XFYpA=F4=~`cwF3Aa25w{{o9Y zkB^SN`RrK~8_rq!%>=EWni3Q37v&3|(+9uK{!JPJTKu~Ui^Rz2l3+?^aP$LMQwJP# zPiIW%cc2i7KEFSus9J9fOO=IE9eqbCGw>25W z(1LwrXnZC)%{880_;C7(apo5D^fNr{V>x1$5zNObSJ>HbFhZ@#d79<*kqb>Wqy0g` zT2oJ7TZLyZ6mi^Bkw~Dyq^M=8k_{;QUcIwJYB(oJc$IH zgbtJl&aoo?la4&QN2fTWrZ`FqL?Kv$Fkcq^#sps;6y``FSXf0KQ>0AG!Gsy7QyR6q zspu<^M8dj$#e^R(P5jQ4ht+|BKj7(;8hQQ-RIDP7B-VZp{s|zIDT!zl0K%xE{B|^b zTeky}7Y8b1sp_~Yf4DydgJX&i!eDoYgmFwvr(^7g(gdf(AjnG{hfVc{R9Qqb5okcPV2)@(?m^_mp$ZH^ zZ3g)BGED42Jc;7ko(D@20FlVT5NXJ=9iQnsa`ypLoxuYaUWwVAD#GJMPc@LCAIUom zC>9JXBq^?NRrfrLIhCrlFEvqig4z_ptDXpggQkYR_b)ztiYXzHl?^I1#+ZQH2?$6a z`12qPOY&i+!j~rD-?{J&BwXgQvhE~Q_ll|Ove#k(Msq;eO2Br53C{7BmjR@0?O1|saD6lfSnX&UxA7E zr6a(IF%n23(9D4eiXMdN5-a6D@$Hj;nilo0k&dd zDs#y{0_7$Abq8LE_YnmEUojAySe`m)T0PUxb_ppGEC5OxE(#V93Mz-kU?t;PobNM3 z<|%^JNJQ6Y#%?pbTB~*=UD$ysa-*YKq~Yw&B(zf;NWm73t*iPoGM3rWx_H52Hv9(? z+RCSDiNfh5ljm$;Fk5(BTh;{$-)F)jDVKFv&|M-T`Xgn-#7biCuzu<>b%r3Q2fE3I z2S!L>Cvz8H8>L{Og{P zWwChhCkA4D(+H9v9BB^SVdnOD0{`BGlZchtT+liOG0i-4+K2gj5;kalO{C;V$XwVs zON&Cr=yGkNn|X>ioSc5*;q%y{EewoSjxwSG5q0!zxh5*EIk%T^+ApV+=%p)=|BD4N zn5_D?iFm)+ELtM?dK2N5oKRgIHKHSGS0ZFH>v`htRUQ%!r(!HzBK2i~hE3HvthoLb zO>~YOf3uwQ6T&kD7nukMRXKzNVk@*&_b6kzSGG12-I2hE4uuZ#fT6 zVyUB-m>;of{h!;}L1nJHh-+-I%Pc{N1hASMQyx{;!VUT{DSGghq2notb?Dt>w&%0S zBOc2z`zg_y5QNf4gjM2LQ*{_Fui!PdZlBjOi=_zto& zC`kib4xJyZh;uSP z^c**g5da;fVx2p4FHETyRn`@5M{iIL^X@^gvzaDT@jZNeL&*K3Q&o{AC;OVBc8Ks` zq)gTU*~}1_Uu~nuGnCE%^EHxj^!3IE5@6f&}?uMQ_xRO$JX*Z?-}JVwLlvVV^E#G$Otruj!Ki z88~lANNRw0LE0n4{*Do?-WZojoBwFln`hV)CV=Dz@T8}_u8)&^K6o@~0lv(*blgzH z*#xG`RfUAZvs#s>f?{)S9(l5h;jv)yLGqrDR5P>xOL2E?FO97QvXyU7{e8t=CAyoaOv=jTLyP` zSul8=vOyZ+`=*Ei9_)7)>h(j)?ijG2Soehmy+wg=7)g6X*aQ?9TWG3FDgKWLs~AhJ zY;%6fiU?dku_~$*O0|RoVU@oEO~|odCwY|KL7&*DLC*+{Nyh0-E{uZ}@uf(Fs$AKl zz+#j@cnXX`NNsBl=nf(1Nx*eq!L@1Ne7Qi)5Fh6&FyBg9m`+cG(dmz546rX?+(b50 z2GMT-zh5EQ$yPd*M0nz&{O}|G^=5DMx<=V9Tsk+n{{rwmo{%bJ%zj$yS_0ok!duG) zEe8W}1HfxOi0>>|AG2J~)-=-V(Xrdl7B-#<``dD#N-c{~MSS`pp1B*uy3a^h3+1q< zi$9C4^e64KIu7xVZa^_Z9P&}CD(#v0ag*Ofn2ySm-;A{Rj3;M_Z^4hc25EKNg!@hM()Br|q4@M)B!2Kbu=n)9&`(%j`}6fl=$gdIN><6Suc4<} zbteVxyRRbta8q{3uTlb}sZ-F%O+@8n{0<`?xB5=+;9~p>PTeQ}58fbY+e zTMgbf`n-R)$=tg%+)2&auL$NN(3_fE7Bi7AZ;74|l5jIf;*pP!!h!E~+LI16*}=x~ z7eyq#M@@^WBVlm?`Hu>fX|C!b$-?(3u(vGO90rcngomz;@mYM0N=R`?K{3`iJZ7zK zk+)*iu6vCLtN!P}jKHDe^=gzkFm-zI5z*v7^8_z7 z=|}06WK3@5GV`0fYkp(kOChuPEZ zkTu_8v<{8Oc(PosxA-V~@1@T2k7DqRw3sjd{(JP!q6OB4^6gC83%_HxttOCv?(>S! z{n@*NRXU}{<5!aQCw#}-e0Ah%=9r*iTX$vih9l3qIlEBDm#U=6H@8NM++*8t=mA|t z!Zx|hg_8W%sl9M%$)x=&fu50m(S2+E-HHs&d{+9|xAEzr?jOvap~z|XrteqDOx^pR zyk#|w5!n9T+lm1_!Kg)EA!(>dekXcmP$~Pf0r+Z6!;eUGmWB9>!+KBNjCL&*Vu9Dr z)SBNmv#t?ux|X>$POm*hnRC~7SR8Mv2GDY-mD$Uls|S_TTSn2xNZP8%1uBhLATV7Oq?@UR< zQ6@?56AHhj+Me&e(Lui=>#e$0efs|Rh+@Wur<27pt8kz^YlELqFBL{4pw2vZ`9xgy zVmE3N4y|>0dmI)v@$o$5mP0R@`?Ol(;&&xn!es*c{8HNH`AA`{T)VaF85ZWvP0X`F zb&7l4BzS&EWScnHkwS=ME7-};RLIp>AqSa$-Hz8&X0!!GtPPhPOMH)?PGQuB2B;iQ z@h@1KWn#mdTID7^^#=S(JE=C(h30OdDw|GE3n74uB{RG zoocct0JM;@P-1}P$#W^H`3Y8P-gi=7!(bv-%c5A}f>1_;qs}#F9^WTjoD#}Q_GTiL zjv?w3ug9Xd?&Tj{Pl%Gs8c_+UhE4TERi>)-CNNQIN9rN1-Bdumbl(*CnrUAILm9x7Zr%j z4>CiEx0NgiPABd+kSZM;Gg%y!VY3@m2@+>7tjK}Bb{g{Fi6b2~7S>u8b>k4EVXmU? zK#t4zPB)t;Q~JvVH?0uc9+|UAw|9rMjCpo|2Dy%l$rlS0;`co)1-Dh1%}_M|-tDa) zlj^=Y79>>9_}!JG0!z@=bttff5E(+2$;%37-dwp#;zFyw>N}2giWemhsbL$M6irA) zd_q(j-PRWI@j_r(V{%?%@PzM5%qum>`z7rYKI_Ok|Jdv6 zrVd`NE&QpkQi@UB>2|^fh)5}ELqXv=$~Fr>9P3DG${TE8mBf7(A>@d+h?1|igZUA! z@=li*-Bl<*3eYcg0_#8q26q0qdydVN?_GZ7!Q+eKAuY6ke=KA!ktymk2?Q%rJ$)dQ zQkeCZAoKEQ4sNsK_HrKez`IES-2|3P{i$zZwh8WYq$P|ui;n=keElC~SwC)J1+6ED zktK$RWzH|DbD`i3XL{*MF3bq&k|R&D^$2LD#vuWLV~&wUr5bBj^(N>hBd;5x@uwoO z0>>gic2B;1x4pC4REO217S`+PK{I-GCAM8(W96b7=-T z0U(*0$lWgL zzoVTr5x)I!lT%8+iS&*CLYjKIJ+vn~p=RNoH=aqo>@K+eI%uZG4jup47t~ZQvKN@J#uo5ce1EJJ( zIHQF^^~SXiK&5^$MWjRQq+1X9rFYi}$pR28e4f1fF`z_SDCSvZv_vmjA7 zcC(w$WU48zk5zKe;)rj&R|54C)+Zf?D}|IO1pX!Qc~j{RqncC~*YL~@^+If5Q7%w< zgADvfLgTW}CQgSkF|B&%3N(u!Fn{IA5v}!87i=ks!mlW|v)SjLqz?IH24jcIe+WEj zOD{!THH@fPvx@R=r^sEf1Bw2v$cbsADW%AD%Fo!A;2S7mzBsyd>OH^vrUwH!2mG+H z_V<$(fa4p>;y7jlALC2WTXr6dBW@~Y5vN7*xKWKSj2wjq0mR1uC!_HB^?d4G$)MKc zy172T?3>=k2KbS`6XN-$F2kt(vC+dMTMKd~@P0ZeWe|DDcGz~v>?dX_^n5BKxA0>4 zP)4)DY(jC$>Hu$2x4GVWNY0RTnD%<%%xph)sL6Qg|*<$qej-Tku4rP*#*l&A4MBQWxc6IYK7d-67F&ceV2vVL$GI zbxsWV+n-WX{)RhZHAO9+3$+jxx-c`IStJ{ia3U|7JeO2_K$S;uQcc&Y=hO6b{#5a zKX3QsKCkhD&7ye0cSnEoot5WC+f#58RxkI2pt8+KNpmLmhT^ZRL^IM;hPtC6_$-dDN&$3DQ%(gu zdY3LMd6aHqA*C&;emkJChXgj#h1;)yv*+j$>Ed#f{47%IUxI8wAYDR8&@37p&H*p; z6yRnwBa6F(x=Jz_oAJvu*q4xG{~Nbkwd=9-@n5%xiXvzT-TF^m38u2a-y-U?rDNVhKl)8F8#U(q^7XYn{l?9zy_bigEV_A4+j-qOs7Zg4Z1TyeNR9m0o2Md6h{#@ zl-23WIL|5@k3~YWHgC&ygR+S_m$vife}d3+MRG(t>aEMfO7K859gmTmzN$C14maKa zd5PrttmhggUvTcBr={mEO?PFo^3E?)tr!|;T|rBpNIr?1hwTE#M~{*wX%pK0uo%Ru zZmq6dS2`oVBO6pM@8mjDn}*4E4$ga>EM_(NAcZ^1UkNiYtjQn3X-Xhf74WgmypV38 zhP~qHRpC%}A31t7q*ADX(wV{)4usNyN({NZ{G&MoZ5Xz;1^W&2Q6~Sl#~6qBRkpt>D&jW>Od@!-I{L1HB+qnn;Mc0(qSmO>QEWC(L^3?6?vs4VPd z&T+PCfbx$ls5e?@eym8HSZ{Zg1J9rmH=zXm3*sBOC-=dYU%;89Tz(PTDgd0#glgqU z_(WH{>&*N88=TFD23cSk(e8;ouU3q>eLXY{=J}i6YSULP~8j8W`O$u*D7?t=Wz7=Bh3z9ja?|0 zG&M?wn(2*#kYnu2PXq=t$>6gh;Mg`;@+Lh_+nKH+ED;E<5Xd3R-HOJ+-6|aC-NqJVM`}hV*HrF#VhMRy>s+5B%$TY72Y3uCRwDEke6^z#B$E^ z$8T`bCiwaQ!)N+v2Csnrb%35m$_>0wfL?kPGpBW%+07(+r87qy-q2YbcPzF;73J+{ z(4=$by5)`kadhY5P`&^Ez|SmZGn;*kF^ip$-Pq37%D2=+jPwWAVKmx3zySSPwg-6;fPY-)FFiHU8LVUGTE-QP5(s3lakD%$bF^ZTN&ruTd!PJ&LgvArR4s? z{q*zxZ-)1^tZ&I!u60^{I3xT^T@}dDNEN@mHaq|w?BCmujIFJB(s#D;0`_Qpl|l5& zhe_*Ba9}$1T6jiO2_g-d7FCpOQ4-jvzF~VUDX%z3fq35vi3E{ZeeUHHcv>iO7q>*EL}v7# z+%O8+Xi<_2l&Myq1bUo(HuUmjv0i0dE>L27;kwsJ!z{2QRVlvG*7Dyvuq3PYNP8$e zx3*-Lpr}MzRuK-%U?No`g)G{7=$ELcar7IW+Okko0G@>!%^X@2ar^G}ppsO(muWK< zA*d4d;*#7xL=+R5MJntLDlnppax-K(bcAMIvEzFy+djlj5W&4JXIYe({i`RjO0wx{ z2A>PsJ{@2pBOlkL2O+l&ofYtkAD*a9|3xx6SiVa|&j!(76A`;_^ztzs;M^L83!ToYG3N z+RsWuVcS)0lKYXl7RZhCz|EdfQVZi8argyg3nVynDplgZ+o_Tg{I#W|D3n;puxM#;*} zzDz=(&WhsXv~6kLSg_?&?$fQR2l$(*?nV646M#%1;!SberL&>8#jxbq6nzBJpHnUh z1xps4qk`h7+J{un)86?wSs689 zW)Ttg3O@f`Q?qXBl(TH!C4IyWn;v$QWmoQx8zFTz1dI7`8_uQ~2H$Rh?B9*H{-r}L zh1e1G0y6l20$!3)tAg|3&UT7FxfV)1EOU3EJITBMa5(0G-ZfZK`iJzv5U6u$A1i8^ zML_8eUk}=QGv`ovumBz)gkAeGa>3~9FVU7YV-VO4?KIq>L!mmJQ5pYY&yr*XpaAYK zgZ_}A1?Rp#TS`2jWGHlfZx#FAve-p}cVR-F9!mSstA{kCw^IWIg-f$-+HWkby?eFc z(PjSI=B4(`LZCoNEsP9!o|=mo5mE`2SOKAyvc!pN-b-E__{1MV4fsm+Ok>BDz|v1pdi!pBVob9!oWV5hRIj$b6?l&s#T=u zE>zAZRb^S-$lSO~>wsl}XZym+5qmmVU0VK4Tb||4DfE5a%-)ujTs8kac-PKLKXkLQ znd>t?^pWw((_yh66|viX?9#w9mM@TRoFbp)8_s>zhBR6cvwU2?TbdwTt@L3xU?Hzz z2hfip?~>NU&2I`RuoD)>&!v2?m@jVq>bAmo&OPT+LvDzCUhX}2Y}XRpVW+s8xHjE_ zcqelCk#nlAJk2J84ZJ?h#IW7adp%+p|Zs z&1vn!r87UrJIH4)R85SO?rt;3-~EDgL+4)hsXj^Dn_sm%bWVGe^n2|fe^<+^&1c_` zLCDI!_wXYPwWofOYt-^lAD*eJj_l3|3HkZ|iuY%fL@ZBFr`UM0{9w;JFwU9EI?(x^C6Gv`k!_NkVkQDF3`xZA9|F$kGE)q^5O} zg5Fbz(Q`qbXydFi=#Y4(%H+2(|x0)MU| zNb{RnPbHW!KaI{xTy@Ix5Z7{7m8tih?vzl<=P--GmhiLTYM;lfUbU@1pEWb}ec4cZ z{QYXB&7=0>wmpiWliMS=oqf}pH8D`MVj<>s?w78jf{j0y%fxZl)81Px+Ku#<={csA zx1$Urt9$;Om%p|je_Y4PH7c6G5S#xCJhFP_Q1Iu$*7aA@aGgOFbuOD;T)a&x`DAi+ z$G6#;->wQ-Pl?v@v_H)GF@x(#lD?QS?N0+|*V4+nTwdKQHcY>?|MKrl#fRNmtE2wW zvL`kO51GH)pU-}O%jeEq-R<*fpO>7=PAS9o`_4la`}eDF+V+8mdublF_ut=jANMsU z7jYu(ZTemmVG{c|1&TMhWMBHfs}clj81(ly`Ops0G0^O-C&lMzjFvn5mKd=%J+?sP zz*%QcE6Z7Bhd=m%uSmv+wI$31J?-46up)hQlIT#VfAmXkq<3=YQTwgQ&v$o8-~-3u z=qMq3Yu0X4mR3rqY03IB%c0#n0`j6xZol&2)PG^`-JUmm{H`A+)Ye%sk(}{wZEvmq z&U0r=VWt}j$+w-1?{C#GjSE@+w2#$$NsmDH5- zb<*c5Ci%Som+Nm6SO;_OvvEw)Uh6Bj(C3rbo{I3*Zm$xoCPg?14|a+lpayr@5w}qT zUtzSkrltCr!33Kb6JN>XE5IE^Ouy`>j>p&CBA$5-4$S^eKFUJ+}6I}T)ws!zppJ*YJS}MYoDHJ zSns-ZN&49=e;F(AUS_d%{}q#McZU(FAmlCuFnL4FS>~OAG{SXH8RhuT(Sy*35>9@n zsb^$LefonXDM0qM{`(pREx!l^qyhqYRgklzS1rUf!VkF*6kZ?3wO^KKJ@IcEMFf;T zhtgmY3Y2Id`>>ywvRZ z?FU6}T{jg&T{K~!wTR5CLGj_Gg+P*gWuG`>6XEuotA?U)1;zBa6|dK?c`Ps)jpvwm^PcY51JQF0v2hz`>q4|Tm~zY62p zDS6T8aviclgfbG}vq-Zq(|=0TxY1c;GicUfQOMGM7<$hp0RpW1D%SLA65-NC71n;d zLM)_*9xK9{d=Tgdv~OfbnIg9gkCX(`3uN$49a4>y_M15x)^MY0|6?{`PSaSJ(tq<= zQJV3;5LGSdSA14G!Fc`~8vj&Ol@6a{)R0R&6T+eg z|J)-&jOuOt7XxkCKr1R4O=;&MJh_Nn?ZCZ-Ypu3e zu@;TQLYr;i9W!c#atixe;9?|Mz-X$h1P1DeD`qgl8#eT)*eb6}V=pE;LR2}2qt5IWgJ-1gsRN1lLTaebZ zz9CumQ!%?J%L;z9(u2bXs%7QL%Hrb>4%BWjcl0>Fs9OVfWEva1M)h7xX@`;obc60x zQ(w&}{`z|ZwV!@%adN(E@i;c{c=y5?8gI#GhgEYpKQ1u~j=JaMqyalwd(gzt;6dZq z2J>it-a1b#pHwV+)*j4@*o1=Z58es>E@NPmLU~G!*%Qz9b*xZ#FgnVLx(lOXIRKOd z=-~GlZpJ;pE*ko_l2#OA{6-*J761YxjK_v@;H?(mzDx8&>xV~Rgg!BH5ezr%6T#-~|PTzE}la$qG5)rPolINbCYf|SXlK5{H5$KQVj2TaBX(U*dKyjEd)un^WXCO`ixO61lu+H&6?*Doh=q3#u{>QvsWk9Zrl1Y zG28`>dcwEz{A|UP-AkTxGT3k*P-`o?5w0}(UwZ7DW6DaF4rx_4dHP<*?Rs3=E02(> z~!>lC1QA=`z^vnk{= z1#G5_w>6s2B(fC>(4kc7%w<6#kmZFiW)6qRWbZ=v29soT70}kgcdutVw7&;ste!to zrMr;tQdr=c!-w_6oazPa3;C{Xe6MS4WG>w}2TN#yIMuM-+xYIaFc-jgGL*uK;5Wqi z#PWkdu7^#u%mLR2DYvLdN$DCxlwL#tLh3hW(t`Z`M zo_r=9_CGfk4lZSe!t{pxG&*@M@Hk{R^nV8*OH5;IXZ)BbxYE5GW>y2UW(`Ywbtxy2 zr6wnrSus>4R?9+9MnfdF`(jQm`7#UHjyd7*3S+m%qt6a*fq$p8N;L3qS9gmjOQiLu zfF>s#25by)dNcg^WjxsNk!8E~-(`$CrH9c85Kxke1p>tOy$*9zLE%~pI1FYAbAU@t zWRZT_EJIJJlP7df7|dB!Z;UCVu2e~SY$uSv`qh{NN7mRPafpz9>c>JNRYqx#0Xp<$ zp9Gir#)961wd9)@@`eVvmca9fr~SAG1uPa)H^>zCzGqniIQ|($5J1<5f3mQUF7t$H zpnCV90LQ+5oTXI1gks?X@;gKUxF%nf zahTJf;XMd*&<^hvi|yLO-2Ke+ufScMOo<6nFN<>(E}!kN@NaFf{g_^F8B8^pRmZ4v zPBL!_=6#KC#2sZN4tRB|Sj>qPfB5i51ip#y(}|C40$moR?n!66hG0I^(iM|1>*CBbj&|=e;rFh%(Zze_3nn5iHjoT zqYA(B>{Ty(_pd#%YBHl|P2zXsC;lluaZOdaZ3mv;VQLa*hXnd0t5^~k6Ho&|Eo%v?4+8X-RuyT(Ljko2F)ClYY$bRO z5L39?`k)wU%|(N}f=ysKNnBL{szq7D6WYwNTwUu*UB3o3kc;jIO-#TzZ>mNpXae%k z7QpjJFlcuHFt}oNT>+56H6Mly?$O7AzK}r-^coL{5#vaZZ#&Eub|;!xfOB{I)SP-y zHRH)2%EqlLfpUo^$f6O!=TU%BD2?=KOJp~VW}@O9AR5*{#%i&$96KQ;ng7Q)d$JdB z7-oC4sJ>K~SsH+C^7k5oX1TL0cf(vW*dD`dx6($i4Rkaq@~UAw z)`oiy!8}%81cMk@Teg)oA8fg6V(}$1^r3S;-?b^(BaiQjT5jCC2^-4xUa2!{By}sb zVsfzUm|mUXZ7!V2b!}qTX}()di~cpXSKq9oxWKW6?=>v_`3FWEW0n5nGfmibIWVvC z^zw_K>!j2t0cKTO;MmQde#?rKi>&brDMmUA)bH zT39&D`?1ukp6>`}tG$zYaF5wn_iUC(o!bkPHe8t39~rJk>?GUf5d~ZB#CIQtd9_)Z zyqfcffvL!6rsplKZ-q&!9Hc)3bBk#y?YSvW!YC9uVA{*COM_Vt`MUP;y~MDc9itwx zER5K%vA2%VNy6VR0aVQkmNeE z6x&C?aa^^2u0uon|O@ztuk60sxW-2U|JBVgHp^mOre?5^3QwFb^jm#oFWturw6 z&$D1Br7CJI08+8Mop+Z^Xc*=%!z8 z7de}j&yfPrk+t^vN`B2-zE=kS;$JDogkL1hw9p%)5Vrf=108Ct9GEW2u56|1{T)*&#VeZWA3A-LF#2Y#(CodR#n>_%-JtYm#shP`Tg|R z4()P?V?6-#1L2-5y=xA4I$4fEFb6u!DTwXlsp>?5#(;;NR;p&5xbQC5)I@4W%nng` z2yCe{;bzAs$eyDwGI$sDg|F?R3hp?Vp2Zis9@3r@vE=Pe=Oe_1#2&cz=CAsINjZ&7 z6dPHyetqI5HKgh>b7ViLWGn>Q?Ua!${ter~(!#%X`B-`RA)E=-&I3^Zh;0FtND$gXX1(pvI8Or6g@db} zm;nH{a_r;orX$)iKt_G3IxTMS`yQd?x9%O^y@jVk3&Q2Gz1yVMAuL1Y8W(OAsuE_~ zc(K@(?cEQn*zAuh?DDHuAq1e{TPpvDI|O6Rwp!71 z&h-3uOkv_#+imZ#x7^mawuyx+RNK2Vz6to&!=`)2ZN3Tf?&|;}AjVP9+a)~x49LU= z-`k^L)^^uDkwI2}_^O$OzIKzm_{WiM+a7*HwMa*ea!tyYFBfxH6|(pF{MX}C;5o*x zod4}Hed)1!A@*#e=|Sh{Tki@Fb8Td7&mgF>b%eJZd1pDS=X>>|gmdf{4{lrLWjK;D zc@sJX+wI4b{BfKDKHJJQWGY#w7Zb$x?&TXP@~PKg-g$Yx?g!6y1s^fjB4oe{Mzu28fNQ1Gq%I5qE)dmt974)+##!a+x=(zI_EIE z5v!Wam%+gYeTY7Y)eZ5{Ll9jMP6T?K7RQ{Ju&%`8&U0`g+_&zMFR8yb^`_39{v{{w z(XSIr4SJ_%GCV=gYTcPPPVq6-f7W*P2eV7mmC4Vc^hc!xAGnZ}ZR}TUnh(u67%zWn z1dHz%I?;tWjOBf5tk{LeNG?*B_6_C=75_Z0OHe4=f+r+)I`(Sj`yqd-(+sc7KMw{4}K z3%$2)q^kK9t&XSv-lY;#U)x8$xr#g=fZh0g>OxuE#<+^iUk~L;-5LH@^A+=oq^Q$J zZtppFY*{_-GUD==BczV~c^>Gh^xyZ^1*0@d&g3l?-_3}E>E7Pcd-m22`*#-?%}=Fr zxRYMlt&3+-j&C2_Cx7fPzU%Qx8Lq0j%pJ7o5gGMApD-wmtnDRdJY^wI?i5^YLfoDD zuY?LjZ=a+k%pMHX^@O7Rsse{p^`~!BQg<*&1*)3Vz>H87(trH2If+yajMncH%Nb~c zuP99eDz^nj&2I>f>mqR^fz(wQL5*dZ^Q=G(a8Iu>Y0UPV{L~NeIr9b|WzB>km^W#y zGF9!*h8C3xrG|{{qjHMI=2Q#mzCn8_`|kheNu!>pdzEC!5>I9IY_up!UdX(Uqf?+N zMD@zGC(h&W2y7!Hd()-$v4;5<>rFax8d1*u4<`OIDphMV$RA3+->{1l-2ZB0=H1-& z#wWgEUvGx}arWAze0lZjhD}#(T!)RGtkQd*`7-o`|m54!(BvU=$6$Pi~`hSK_4fE*Pc+9T&&+z>At`*txFC~zOo|0HZ4H6{bGOC z$k9VBr%xoi^LB1hB|*mP*IsA4Mn*LsM3B7_ym!SOw0M||Yv}5f+gdCV!9x}+xV{3& z!c;uhXVy+-aoKUl@F=6|B$$isyWp||j~jXAK|=v1=6+<7uX9OnsZnc?riJgJ;xSEG z304>tf6$|@C85B=#Hh#mnr5lrQK(a$SR-ilR3qc;bk8!A+t9udo*21#gs(AMx_9nw zebx&5n+Qb$nyj=C)433~!R4g`HLW$3`% zgz$^!V4RbCSR9KI^tzUwHOanfg2gQ64+h2N!)YqtLOYGVF9g!ezU;F5~-87EV+z()=JO!nnO8&2|RLW0C??W zLlnVx)oyrsF_LsPX9lm^QZ`gB(7Gy`!8`SFjqAA2u?a%7cHY7Gsa)6A`qj1+6bQ8n zJ)tzC`|3ZOglizWI!$TR{jEM&|->4xsMWqmkIjo3%ae9$MM#bT;@&O8nOh z^#yuNaY_PLvDb8t#OCy@JDJ}NBe;!L?h?ZeCkWTn)PDG=xCTKMMRyF5v(E z^en$Urc?>ESV7!TzKgX8=#A6hUb}wY-f~W&c?*%=5@+Z(f^aB~JG6aqg5QLZm&Zml z9dP3F=aNc11czesJf(-5{{&*U4K*E*iHpMqhjcliLLVT!8PT9 zSTsLN9u*3+OVpl(z3h*8j;pdpfh)?-jZU475F28wEFby60Wi=ds zU$^||a^0w#k*Ql^XFHFzQO;!V=zggC?aJ|Rg@jZqDfjMFwIXvMqi0%K?rQm1I`}1VK=Vj9xej1h5Hv0HqNTh&oBHzV&G) z2XnB15YY~SWB?F+d*A4k+1dw;9!MaO7o9_nJT<=ctmaKtt1FS~k}rd80TxzoIa5Gx zku|{10Pi$~8WnI3KBN!S1q8Ll3h<59(BO?ea<_cn{AOj;_W6$QuR5RVY#Kgy-z$Nk zjxTP!^iJ#8&lcF7o=U>yarO;g0gsR;+;$IpaQb)c7TTZ3hkgDr@MS*d1^u%Jk<|&r zWMe1M-`XAz(Zl}Y*pN12m;lMEz3+7q!dLP8uolJYbjRQCG`!(~3RIE)q#)b1g@ucm z%w!8gq@N@8N+Nrzk9BG{rE-H;E?K-dF>tNf<+delyhX`3$XbnTI4@$UOCVS=HJ4Pg z=u)y`u(3V7WS4A9(D>?6@^&$9UuT#&(^_$okl*_BV(U7b%c~~(<2q6kN6ixSxX2Me z?@Ct)f`dHeZ&p3Z)nP>mcA$10y=%Q97v^1_gw*?%{m}A7NUVc*X62@pmmoUN?w`ZX zS0F#{c{W8l?)mSg`L@j&10kKm%;J5WO++>)9tCVjkMvPOYc$@4D}zxd78wPyP3Z@&Yha zyV^YhoYP?I#mA#bIG8SDdnvfwg@YG@=C&LsDj02eTx1u45BA|n0vo1V)Uoy1N74;t^+o* zS5IQAx$4zw6fuJ~AbB)>VJ|e~qwc5nhuatmo}P;k(e! z2<7O{vZz$KBJ0_Ke+;$q`*`oUk%uh?ksR-Eket<|mBCSKW)*9TE^(xW3SL2mOe3w- zH=Hi>Osc2{kQO37C+a)fjh>M;G!mRPFzo zM*8{V`cTOqPAVghYamPcn5aScz@Rn9xw*_mWYD$CEU22>kK_?*xYHDgKwvWGNHqdC zJQK$R--}JZm#1m5$@pk_*7s6ti%pmA(N`}-O>ZiwQY*c*7$uAA1u?ZFm&=f-&^Yoj z#-q27(RoT9IWKNanTn%^XkD>JmkALI0J)i^MSosDV13eP`TAk&h&)x|{3UzqD!oQD zF@w|4B-i+Q(Ru!Hl3*P1XWDrFlGCgZ+Hw|=B7}4{LW=?1#l)Of08q?9*nvcoGV?~E z6Hx?BIeBc zP8;X31RW|=9Ah!I7w}XU=DH-(*53j=RN?FWfm5Nq2Bj{;yA{&OO!uQKRB^*Wq zENbHddA;nNEsr`2q4;L112#83t{>L=g@kFG{E~8$_Adck7_0 zHdJkzV>r#4x_FqZU>qoLQlnc^`{bDM(O&T+Z7Plw%F#R`Gw3YU{xwBWFxF-{spUi5 z26>D!?w%lyrnj1olaNW*WQBnSq#C$|qi4Kq^)%1mp0dRycaTcFf)ay<4oNhD=xRa; z?k$5q&pNO;aq9z%=8~lIswLo=iEKJff6NI{FMlr(xkO%}v~pAfto$g^4F9xXQZ<|# zZWi(^)?)fcmga`fsJ@hR%Y&Lv1@k{L+K#0;nD4tXJn!uD%@G_kg8t%K8OuytIh!Wb zPWISj2b|D@E)f&HYyj<<%tH$;1yd?kdM zI5?FKZxQVDjLQrZK{7brCr*2ZjjAVGZv1f-8(94w6QDWHVvO+0YDW{BA!OjFp?5Pm zmBBE&)?UZ=Jq|Y>2u=NbYzkha@vqcUl6DN zR89*I+p9P_--)7>Li9T&KGUMWck;DeKll1iQ+rrl3m{`EZqH$sfnbytWa}~|GOQQv zc_F9feOd7hphA@-^1v?r1u;8M$FS3aQW{5U7L~r`1sJLqSDSPV4R#?MwEq}W+adY_ zxqm`8Ul!#x-in?6TF(vUymE^~(5k4HJjze@BbT(&lG)EYfHzb9xcWszXUQ_=m;-V}l zWRg0>ApR-dI0CW9>Q#se}_I0u_$lmp!czd{F&y4Bn6&rWQ9C#v}?}_I2A+~aLumaJZ^!&A914%=;13(N$WagzXzT) zgSfK-$%=^0o5o}ff&th+pA<;dMBs+;u)ss2LFj`d!+nLo$sRkiCZxrLA_VkIY++m z5wbU~lZq|u{4Ft*iDWVY#SsQ5uN8?Lhc79`29eHWuJV~wJY3}Amo@RAlf7kgX zPQU3;^&JWADKE@$j{J0wVbAi-i32r1b$)s;ZOU=5ocmr>-u+of>ImD?_ai!Yeu3vc*u<5hzn;$^-$j zP_-Bht`fs29Mq9Sn3)i|l0HZSpxT^)WhaGRO2fhE+i)@+sJswB?SkzJRk!1){!zVT z--cTO=cn#LW@S2Wg;~p7wW$nr(@HS(Ez}cy@u}x{lME{0sc2XrO^8W+YoGE9NfpDb zIS}gcmJ5jho%7QFFJuJ=(!H+^AcFfne7fmEwMfVL*95j9`t@zS3HOHT!r5 zVg{v)aRZ*F+4Sf~T@z)9XZT7^X^gwl+mCBtQ3m4-U-2ldEW5L#6J=bT9){s7hG7>= zqX0sw6WOCsp9B(0=|9RfrCejG!e$4AG9af7GAP#a(jOZ;hPmX&ag)y&CohT&deXs3 zy1^i0;zbj#W@pt=gPfe4GhO<&HMfT$tj%-?W}uw z^Fs2&I774l>03(-u0fJW{tQW+zv>@NN8IhjGmdwPkjLZ(bv*4J-sE$MLAb<)OV?hZ zqz%XotRcE$2Kh>Amz~7G{m$sExVaa0vsDLF7v%b2-8`l0)05IQXHd%e^R`^Qfi-%I zWt(Y=?xBym?$@M$ogbvn-jdU_C4T~TgBA~TyW{+GKNv(pP_nbA<~#ahqlW?C4XzpI z^ZxvvFcI}A`B(#L1j;_Xw?xa-J=Mbgv{oTef5YI=b4FhUB{0qDCUL88nX%XE?x?J| z$44D)x||+_8$Yfy+Bn{HQ)~3me~h@P)TlELaf~%hLna#*IGT1R^B5aDu+erAiDh>6 zZy&sV*>)!=^DEiu!VweC3=@6w5gR?nL@^W6(~iPZ{Ea$39UdEbPIm=>(8DUa)Vw%- zSZL&bNEa|ba4bM^`&dPFda7zahVgL4gpW*%6IZrAuDk9uJ)njo!w(yoS~PAw9dG3i zz)?0`JC9pvQT9b;nJ;Pj6;hVnId|=A#e1bTl9>7CTVgd*XRj>|NZM&q%+n(g!Miz@ z@6Ran?u5F}upTy@Vt=}mJyUkTQ?YmKFch2af0u}TG7KY_GR1H<2JgQ3jBihgP~$Fx zA3M&^`@6Q6e$MWSFAi)IN*tEDzx5UPNc_XF>xbe>3^>5}^HP6R7M8)fw*FJ0-i!zs zfmx@)XDL_qiS%d294ip(2U$px9cgJD)>+mPuuDt*SfE3G?6j zEW0tC^;GZi<4`?zUnFY>nl9h4(@dQR_S=Ub3=rsA1@Ou&6(`a8^4-MYLDh-WO@lCI zKo0xEd*J(1y`whQ0cg$e2Sn=Cd|pT1W)3Y(ZzFbYeQ@oODmQ{sS+R(DJuR)&Z%AB$ z_nwx0O}X(_7veWw5^~gyXlQJ!Gyb2R$mGc36l%mhWnP2sIGBoGJ7Hj;<}ulkUAlhr z$fu*fCA_Zvd9r|gv&3S9-}sj^=YE@aOQ83g{;UxP()N9$&8_wt`8)o_gZBpZwDJ4H zy=!K_Pw2*^-yEx|x;=k5?6UWye)`J%$%O+|2mX0TUj6j>^WRFxAym7%o~RDM4gC+& zW40q)A|{jDO9}aaCcV`6#oN;$q+k3iy7#YSWg-rxtsHZqJA^D^j(M=ik-_?D;!Wp3!#Na1M1uQ`e>l zSU92U5GD4Zh6>OTLKOgp**YArO(Q|nP>R6oZ|wN+oVqPzx~>p`pep@H0jU=_ajm^w z-F?_N)!UL?Qhud|m+;AOi(Q45J#^y+IF$P8Fk#==DD`IVea~=)zvp;W&g@W$^A(H7 z31;68Jsghv^J86rqr=q`^C!%lFQL1(#XH7iJx+AGfqt4%wsyBa7c@~tpCDIqU~Vmy zGXdzJsj#?)wM`Su{~a&1s{g-erE%R%Au?5EAkJ`RCKTdkvl~{0-Dm2$8l6IW2xW&3=`Y4K`UF-TN`7b?vFL{|PL|kBACe*BKVTG$hYgojAXF z&8XivttVL#&ON! z($PzWHf?c)Lqok*xtGh|H{YW^>XPKnn?KBcvBlXX?D^KJ^NyQZTnsj@dQj|qVS4Wt z%DY{v3aO*lggY*5-@Ng@RZCpQwNC|P6*_l4gV%BG0<>ExzHXbIXo5{avB|s6BkXb_ z*R0OiG!gsy_+X~B1^Gq&dLQ+7S)X-oojGH)6#gjY#h#j5Z)`5@p6Gk)+PR-~1tf2`|=i-_K+`}v>$t90-FyjiSs{D*@kEcM!HgBQ0qVG|^kJM%^{ zu{ccKWAVGU^9wX)Q0-nq_*y$fZs32XjVZ4^o(>mBcI!G{o{6v?PI#HnZg;Qc(6d9M z6a#Geno|3J)f_~u-H3E;8_RrF6p}x@mmCKTzZ`e$6Qc;(9=67E~3NbXzYOk4#DgWA{+aGD3y9nG1MV8d!u0m zeZ3Dl%{dpi@SRB|-f6h%@~`wbL%kLExMJ8d<<~=7?0&}F*Ksh?lo$<3Z99C;?i{Q8 zn9p#kTDs?D+hs!E_-3GS>5Kc1Y^sHk{sVzp(XO*ur+1+V)14)5$5`dCLJ`ce+n^mG<%_SCZN}ECW+EQYZBB-&-Yr?GW_wxJTmoI1Uj`c+OdDNC~Kd3E2tcfo)8VoH; zlAEIsI!Ni%!)xz|Eyp=PuQ5WSn3-&%M0CiOxce>&mi2zdZg0_Q7K-ZtU({ zr$KzZ>Mh&4?1smt#KOPD8jg`0Cbf!ujEa_y6?MMWGLqO#u=4^*tD~5CzjXI(W5(9s zTlLPkc>XzTuRy&^hRFaBED(-E`aC*b=&3+WWZ?J6)F*^^RqVw{4i6L{$20Js?Fb9) z`28*TH+Ghp@#<3oyt3^Wkts%v6Ax~O99Z3-|EwfSgXR8Ih@Vy9=lb!JAhw~?+Fz`$ zQu5AC;=cg66qyd1vGctce{K;!&B6aH;>?(<>a4Rp1-LIDu05mdTnoNeY>$C#mW%N% zllW->kLl5%@Ufrm4yid~H1x zgDVa=G~JKma)@3|1O*437G`311Nv4-(C~LxsbW7Agq>h6o**QBKl$JMD?3=>@ALZxfp)o=bk;aM^=ZzS~!HS?bvzF)}?-x0L!qq z!>$_-`6dpD-Hktjfsk z0JY8;e)Y+OpoHA9A@*DbVG*podX6v#Bw;Q?pY{_X6A3Ck&l1#1&BX0Fmv%CmxrrfA zaO+|?>TmjS@7uBO1%yXLm}_{2L;xoX1v)o1^llR5io-}2@=H76sp9a)pd(73oAEYp zw*E6aq6j?dpb_(B-exX2+4yF|kKm*BuhN+(ssnVz`~U$}&S#>Jcy<5(oTLkVnmG+|VLDHCJH zLRID_&R{K^l1y0W$F=vP9|?E;5a*-~;8y73TNJ2{4E)K1xypeg^a~>HIX6T`+?N}U z+;jtfM~LG0qsN6Im@D-)AoKxe>u*`>R}SG7I^hu!rFRAT20Wax?eKB^dJ_noa*i;$ zI}BG>xVYO(c~JOU_msEmDJRh>WJ=rpRxR7$3(u`C#1vcKtxG=nQ&{n%?R~3I-W4X> zP%~5Amdwjg)l01ETKBM+-o8`r7o>Q2=Tzcm7j!(n|LP|Gw|yKmf7+6pZ)j@y({lz zmP`=Z1QN;~+DGOPJ`)kkxG)P9e7hURJwc4kDv-Am>brPg?!GYE5y-xp@1 zt0yqUHmsYqxGaLkndZ9Wg zMNJ8&JXs5)Zy+35+pH&n9T8l*(w|}v37z2*J_&H25$etxPxzAeJsN?JwBQr%I0cd0 zp9w4i3JLRK)S^zygLbTCmoA5cR7N)<_7G8fK>RN{e(Q=R*X`wZo12$}_?w^MmZ7*` zVti*Q>^MO9NpC~)pwDHsd^@8)0b#)o{r}i|@1UlmuHQF30n(@oKtYNkR!*MhE$6v&&)j+cIA`w6 znfLEsCNq0|_gZ`JwfFk01yR^4K11ae{0kj3#%ff;f<uJl{Q7sngI|0*Q->FK1&(r<;aaOC1 z9y_a)zdsTH@(#;pNje8x9fZ}6%eB-+m)Om=oKLGQ{ncY>(OdYYyF9}EgjEu#y4C-c z)tkbWLr;3~Q`m-I5KbEC6b^g>4=vc_>8yt$4+Nq{pLwaHIwScy&D(?{+Af|#uARs1 z)}!{P4>XK@3c5fpVAHQh=)%_+m>Je#xlQCz2@pyeWK~gKS$y7er#V6nMQ; z8+Wf%FX3;=;ZZ+XXutE|a{QC;Jy<0y(%~R?a5nNM027NXI0pcG4u+~xx#|m1#Y}@T z78i%R{SnZ4=4j_7&GwvZ$hc|#Dic-DfExy5@t+|H{7BF?=8%}dNeHjDb3D=tT+a$u z_CZG-@XKWoXV+R?k-q0;d+??`B{eLU+A9vfTX&mEcwGF3G#F(OJyv38K-w){oT9ak z+5qHOjroHmjXKF=hb`Fo3SWTD zVlnIGnD1=#3?0tXIlO@!*-n%ChHNH(7qlaw9<5gY!ee$w7(<@0GKJo+))d&)QN&di zm;dzrW5#Gy-_mre(!rcyWZhsZAN)|HmqqWrw??&dB}b0U&i`bgxV6v4Xj)=#TH+Bk zIAjmtbrKHTs@cDXEZt#nk$CtuhWfvCf}fTJY>~LPom%)5QuhsuA;!hyugx{i&7rKc zC)SA*FG1iq2h0+wvY5doY&w6AF!*hdC357AXC2n-&x?ph+*!3;e(fPUeE!|E zsf)4T)XnlrEcXXiK?k`lYqy(d5?NVXx7ahitG9SDtw+;gR)3=fqCMJQH`6-TZFn&9 z`P`^=+HBYQ(#x_QCnUZB^~@9tG2+~lk?*#Uxj6({iiPjR75}&X$@5)vy`PTxy+?h= zVIH-30bKp^eurEjsC^*aYwAY-prigYfbRW9@3=trrIUr^sHpsbhpL2QOMn-D{=5^P z3k18qc^1P?jKRF9z~ZS$hs((d^jBNVSA(741qQ|fezCp~$r={b*UA6Yq1jm=RjP zd+u5fQE|g1qi)cwR!^tz`=c3m$Y|eCcR@{UXiV?+kELJNj4fTiEDpD#Iv~!Re!%rS zJ9ALfTHz!C z#H|aOBuj*1SNrJ!Rn&epHq50j^o4K7Bo$=m1WnyUgt3&`#20Gr!Kdp{7%e$G7M3!M z>eZp=GJs?Cn0>PUGl;=W7xt*@aaBBGos9W{uTMb?eg*v$46Hy)@XS->WZGFAV?cEKWVzSe*c8;&~2CFDo<1 z5BkXZWi)ZC{up>nz0%L}NY?;cC?QZ<}qKeL`9Qa1?G^YV&~g8>HDT z(&+}snT4A2YCFt5y-0-b%VKdiLNH}a>8FL54JurU3L&nA`;Vyot~!${fVIMtCm>Kd}dZnD>i zYm1a=Dz#-YW7LSRX>Cbg=mUG?x>DCV_-QBmj9A*n)}Ro$hnp{IdT9^_?kkJjl<6Vo z94poc`&fH7C-DQRLtyG_9ghuU#X-z>c&^6y^ZHa=WHI|#|AiB}vDd$#pa1&qL+ZN9 zb>Q6W}QlN4tzUmD|<0qFL=J~9Li=N zV*Syjo$~I1+lNyrv>Yh{bM%QIm{uC`{mp3PyMx9RWabZ}BFdWjM^SR85@%t5klJ@A zs<#7nJ7jItGF^iG0aP6Q*}+)UuQRLfPWUEZp+vBJph7(KjcCQ4sL#AdlVW{MWSD`& zcfG}fuwP{`xQx`#j}wIWMp9^BFMCTQR1WlsM>M;QZ~&JnNgb(Ucdr!t=_PF5&u_J9 zxD)=k!RvO!=Yl@I#(BO}*?UM32qXWI>!XP81FODHx6fVN;$~#og?9PsJsNyU%=*T$ zryC&2qUepgGW$tV89RO_$4o-}Pxq-L9%~x*wRzCAZYIj7GJ~J<8#mV;OrJQX?>}Mp zMp^WPl|@**pxuY4Z{IGE;swL)-ETYzwK-=fEqGdb-b5cJmb(dj)+1lTD;TrE75GGo z!jvhA{yOD-`1;RKiKI)rs~<(hvdN$%&#$ZSBKg^yeu-|sw>T}ZwmXdHuKg~MNsJ}i zd)09qR6#82Zo)l}1Fn)JUahUdwdSam2 zRzm;O$9{naTOSX}#FFESqGiPoI0wnd=jTRjZ?%+!O>TWG!pAb=y;FOj5rwDbEZi$g z0s4r7;$Fd9`)wlZZo%YcSWzyD%~3`NhNwz#}{+ z?*6w^4w~P-e(69R)|%M*y__-LqZ=0Xw)2;Upq=NBHzIGH!t7!uoYMubhK`w^{u4TW zW(gJC6=G8g7p-hWYpz!d`Y|N7?Y#;#X1UuD$FmQ96btDbSkA)5*7p>60l2L7JqsPY zHijvb#e=Jj7t0I0?zEJ>2+&NCDGGl1qx_&@h86;@oxNHv7Sh`ylY5Hiny1KiUxQb+ z`JIOQXT+)iiT>m4Au^6zP$}wD z7tdcf*ww5zb1e>RU-m(44zEvljTh?!dZ`ag+kOJkdb+O;-=NKiJ`}Df=yeMS_R1|1 z@vu{$Oi&8N+aN!#_4lYrY-Ch^@HqTu&zSJHA!OikF=qxn`=oY6GvT%S!D3>9U@bKu z8fn(s%!HN|nc!4SI=F>}1%zt>F#p?PSdD|Gwnoa(FC9E+lkh|Z0U+!TFAA#_2|aFm z7l!0RVPwOgE(-v-9AlIa8u`+;R9QdqeVUIu;Z>ZiTmHSWG{qodqI2t5O6>a%SvLo; z_&)hjzITJnsfX-Af6yi3GWE3^+8SKKe#AXj=7fBZh0klK)hWpG;wBMUmbB{OVE8eqhdO2hBP1_+ zA^6<#UguLnuWk9s`$6DSvVke-DKr0PEi?tzph zYfQNLH{8W76_NJ}$Ez3QRb<=UNp7b!IwivDuYW^%m>X*JO^=_?zVCO5lNuW|%G;;w zKauy+7qMeK7*9hcRvOrycF+`QVk8_~H@iWAyW2}1+Nmd6+KLuRF>x?MmVDs#lg1Z; z!;OhcpULUb&Wkb^S_Ur#gcSdBzMHgLS+!ny*=4P&W`4K6%5K#RctxQ&8*=zJt517n z6m?wj^=U`w6_55SV(;Y-G_&ppUR{sA_zAVM zpf;{&4YL0l*?01nlM|1{xFJ7IbTsjhLmm>~_=HC;%2xy9EeD;4yzF}vyn=4H{B{>M zZ|cHlVCH-Z7cNQ*_4K3%WnTU5frC5r>n3f|(_=iPjyepOdj;nd`#n2q?C{cNzdZP6 zUCbp#OFI0NmuJ>N<0Ae(fj+>SfV`m?FO>?1p)2Kng0Q;?)v}yduBSMizp6i+$|!ge zF7)}%)+;Xp+>sS86B_dEcV^QAN%6rw@6fI^dz}-_-66|LG^fEy)B(rWx0gdJw9nR_ zIous!7~jkNe9vd}QekG^j9+EdZFT$1t=Em^VRimjKTS;c25d0+n*(iq!xrVs{`TsnD$IUv!Gnhih(2&Yy#bv9%nKJ zw6Yb_a8P;0ESi*U9m$RvFQwOkP$j#~zBsOjnyueFhm1qVNgRKE@MWUL_45X9xp&lSpn64Ev&X?%Iy`N;0qt79&1sm^ zd&b8pvo^s4i{kCS+6%-?kKH>o;A8yIR47+o>)s(dc(mq&BTbP!?I+Zl4K(MKklDNt z_#CxQT}t*!^arb{8wWgUuO3&cmU)(;6%n;`?0V!YI1L`f@E={-%HW-n6whovg)aJ< z8P)dT(9RyGvDtgr*~0fYY#dx`#hou$(!daF-JZA|ixMvj$#~Krs=2$bgs$8sVZX49 zPd{*RjFNORx#BGULGwVQ+L+SYf{)j}x9|U9`RRy%tv6OP;YC zV|;Om>Wbsn5;omAr^;^J-yrd5+-V#=HJSoPRGkgG$ z$rw1IAO83!O?WdYI+;eq0XbJZD4!(sk*C7=#BcFQVh|7?9V$F^G*1I9ZX$C@86n1m zL^i_(4kB=}v=|e3?Dpx}!p9pR-BXW`(|xcSBjU zz|9m6RxcVLu$7EaR;0 zKem}kp}-^RO>d`hP^dlpWAUM4`SKK_AeP#Sri$jzzAnbi&zdF)$lkSJdAl1XRYhji zuj*5rVR2JD-U&u&zlFlFT$$tjZ$$^Pe;b_?R!_inQ-oCOkqo;bT?`xgQ>yf7^eY7P6Ab4@&rrdn!VJ#ZYOwgjkmaDHMw;g3s-LRW12> zNS{k5Bb8IL%4ucX$2*8ai!aYh(T@J$uo!8f$ypS70+)3He2X3=Osm433C>9g zqGX2)bB1FbBfAe5E-jjp6*iZ}M&sL%169W*jHFc4`vj78mzbZNtYs3d^a!dk#ANI^j5)jCM^O1dvt|PqQYY~55@p!ls%dcK2?8o{LYq042fo1 zdHBtHLnRejyibyjGfP}swMTJGF|N%-R0r#<|GZGi`0V*hE^manFAHqu-i0Q^~Jc7pM5Bc+fDh&f#{u!xzz0W;`ZE z>kcJc`cot1F^NAwPhyYsrmEtQ<_ZhX@v90ALmDNP7DA@ zOgJgb2hIU}SLJF={e9pOSlTYg<%9PA zd?o6MFcBO;<`NDnXjS6ObD>BQ=cnz_o;kAsapgAS2r|vI4bDOJM)ssj*#pm-z+)=m zF(xzy!F4bF;yvvnWb3rFF5ubJ{2RoaFZBt{wLtmD@L&%8zcOBz3FA9vVQ9!*izS&N zAOvE9Uox*dk;G+Jaos-2)BqDrpnXSGMde)N6@Oo40n)Bd&|SG9)f{Ks+-z1AOTt>j zsL{MD;Zd9KO6-A`g*#16fR_i)a-8wtkG_&hpatoo6N@V89IMrz`9N|Z-lr!pSs)t0 z8?(u7Rei&ncI4Y|Ke4PM-p^rQ!})pJ%qdu-8<@ZqS|k&Ow@)X%1W1 zhZayd${_$L{;gfT=U{%$>(ZSk#@6xMNI2WC1}6@GW)^2kjQ4pAwaN1ksPbsw)e4@3 z2eaR9P?OMda98_8G6TNjSL%A-+`Ru(nv|DG#^U1Q!lhyFtA8JF&Frg|ggf+7u84G!;z`{Tw6&iMoc)Pw>K{7vW0Atj=U^k-Y*0x5h! zCeX7iSb`ONyZCK^(CXDCtE%BE?XHc&Ca@S`?eDJ$4`AGd=T{mhg#$^nFNSl~9`H#` zRvdthZb_1$PYSc4k&M&}=Y5~)c$UpxVWHO*cb3ExU?>3XDuE`mP}8}*97{NTGI?FT zIqBPLJDNObcDZhx)gN9TUo8hxR-pwRPoDMKU%KnK=01EJBjCRrupz_W7C1@cAZ)`~ zwB27dZ!!jJJJ$v9iKbfc_Rvavvj55amgk#E*G=G&>q7qhz35=j_VK`6y^ScHqPt-M zzlQ@QZkyU;+qsfxUpoRGzS-z6-_UDI2$D!{3U+y~dZjLMH4FfLCa+G$4f*=vw28DY zm*D2ap$^6u#o@;4i9o&+L0mTERlA&M1pHO|jn7F3#TfA|m9(>eWpQM$)_U4cR-q4} z-5U_ER~2V#VjRR;e=825khvl!^FC~RZWjsS&kUA(_%Lp7)Vz&$=)k6$%qC139F&}U znUQOxam2gneN_K;`-&doEO_-g(BgzhMm9F;3JY?4B%Tg1F2FVMs!@8F!OSL(yDsaz%Tge#xNs%e83HNaRlW2 z9?hGY1-DC|Q`d%Ci$an-hLN`I2Y-jUM>p#&s>v zy5#Ul+Lb-kxU=6(!y}6iQ%bhwqVpE2;I#MK_=dJDRp`?JY%YH2vKCG$65V1{!)l;o3m zx*l|RGb%oJS0X=&Vv=8S+2fra!k$dKunvzw&@%IX{_XzwB`#*594AAfrv@dd zCAro^2`tcIQrvLg{-Wtc_;!^>G&M0z4kI7S7mTBYN}YKd5wnzcb^68M_HvLs0wg*a zr{jaNC=s$^sp^;?6M(QghRLR>(fnvABO9q zPk)(zejSYY?YYM zCGt7fONu*!^KM!3X|bvCwy4C(vK&jjgZFc7tR19vP3?6}6_|_JgK|MD0uVtoY7c{n zWaf;V+?SKGO%S2vADQNUx7dh2psmrNkNc9Z>Y2u4MH$VEmo4qbk-qxeFTJ5WU3o84 zPvo+RA#0Q;l^L_z!=vF6o1=RP^uAYPuLx{}B(RB4^-a$lLFClzNlSTI01(2}HTn7| zgI_+37oFLrZ>jwS-`VAtEpfZ{(V+57ZDaGddieDM>SZuSS8c01-xF2{K|4?I4@-r! zt}u}!8n-}ZEkp&F6TQoBpX{c|Ij-?_d6E?HD>ppDn7 zE7!2o6*IW>Hy$jrHOsG{^>_NDPFNcRc3^K9eU&b;Q$JMfifn_c`D+qU{7OWL*vPrhs08PPx7{`Iwus7R^q_D(>?O%434;lpcY$wdQX-%L|im*UvV_*RVr7?2rlxN zej}@!^4KCRvP|;uuNC9CsZrW&u!s2Vy*_;j9wu)j zleo$lidn`*>`#SW=)awu`3Qa=g+0(1}I%Bm_OcW zdTv@dzw@)y@x#_K#@2}Z7KlV-(&{Vk^N;f5U%4O2G10Vt$yYc%>m_nu{p>@#lafP< zg~~0LheOb#w-*zf)nadCR)x-uUi#;iMhwOx;k<_iFN1u=SxBg{TJc3_dv9tbe7j2*0EVr^=B9pMH>^oa&HFsK^ zU!S|S65A&kEo)P4QGhvw&N^Z$)7_Cg-*#IqWd3o)hO|YhGG^>?RimtB$r&z~pkrg@ z=p9qk@k492A4etOjtuszlng1o8j|0 zk*D5RqxQJ7pbz)_E$R$@Evz&gz3{-Xj<0>|y=34U2DwFieN=L|%CRr%TefE}oVP0f zhwp}IVk+lRj@r=6Fl4@`cvA7_vu)EKKOH!+;F$`w_$qze)JQ_-#vAWR1zoilc$F(} z9;g^R-|*7;B5&U?)?QTcGEDo~#?q^H+NFgq#QpPq!9zbEOQ(c?O@;Cuard&WcYSh+ zua8H0@rg?mQF^OahB+>A_^3@=9z+m)sM4M{@~brx&qN?*uh==u*m&9bznN6TJ{N)r z=Gi4*4AgGR8W1=c7KL;l#2&4Gfoz+R;lDJ2*Dql5yCyy2zVP zy8ou6Q&bFBx^&>IgB1Pk@M%d+va+5l* zo>ZGF7akDq2MGSU>1SVgVMxd2py06#D&W6`{XZn^|NrhK%W?I?|Go(Bb8!|yQr15g z!G1ChZMrso|F%hkdu!OVuZpL=zKu>a$JHTKnPO?_&?}@zryt%QymjnLx@Jl+!z>RU z^0Lff=iN||hWD<(9{k%F>ME-TL)>l^7>0y^M*M4meAi>~IQw5P9Mr%%II-eqMuFZKE zc5b?KM=dBN**#5CjQai{tJ!l`Ij#G9=X;z}!VQh9b4IsLrJfFX?j;8U>2i9+ey(-2 z^zMD?*Ta-(yP5-Y)tqm?)B=_G@<;Q^&d1UHvlnzkSHf2MaxU1OQJht$tS;Pg>hsh2 zwYycmGd6SKcXR8t_bT?~+Wg7IA!~blT|w_^PoBLr2Q}o!5~SR)Si{Ml!-Lhlhl0vnkmt9&p z!PeFJ0xGFHQ^|V0(fCoBY4$H>-JYxxtU7wf{bkX?o%yFX6)~*|ri~S6i`02GKCkY0 z5##k!hJQ!eu9)99Pd^owEwH9l&X?n3_;Y;Ct_m7kn{3t1l_98xIG>n$6NlCqd>qU3 z*5C1{nCTn&KMrq9QD;AGu6}qMc=-ACVakg1&&H%23DWRfW5vew0Hokri&&E6J zgmTK^GPRr3nqodNrR4f0opi$7%Ayj`1}v3PvYqG(S__trjptQxL8cRQlM=Z>jaAHs|c2)b)O0`&Sc0 z2=128HbPkSbCbOl;UENpR@-EV+nKqm3+9U-FSta!FgE_i>atOo*E#=}Uv2(XV1s|v zQT?C^XVJWF$S3dIj87rNW4Yd#JUL#>3D?ISguohyB!QrTGvKZ2}S5D&*BpJvakjFtNIaKni$uX3V`5{6~GL$=MIEb2G|X>)Y$c zX5N-N9#t)x=&H!Pc;@QI`8lWGyR~P<&XKi#UU(?p>NoS|{XOr@9j6k7qVD|g5%DGk zHQ(lgr^lW+l&EEQBW`6D7qZV;GpnCYtzWtAmD-J?wZL?76qR2AMV%=6>d$^)!x4L_ zK&R(cSKk2R;#(=(%TFtwRxN9O3)bqd33@BmK3dh8o|CC@eSnhy{G)X0BDZ`Gb4Yui zsi%ihr4yX44FB=6LDD;dEwwjrAp_E*^rXAjjqek?9Z9)4BiehDAtO3l?N-+s^K>+b0RCMb0-#dWtD|c1~-TQ}^K#SR$x%|9M+VUMC3l4)&HlmNR1`gM~>I( z8sMCEA(Q->C-aEzH#C1T_2JxH!{g%wB^7;Fo!#*r2^C1W+QeBUWcNhEdN==w<|mUb zL*CSH;WoOa<3t18tx#oCVbxH(#VB5&5)R{1mv}dea76WfoD1yR{ZwO}`?u0nZ(bHG zoc-5>f%|{zHwf7Of4gTVq3J*LJD|wXPmb{)`sLMe^y_K-H~mhQnB`$zI?D!LFPjxX z!?r(1^2_Sp)%X6X67}_x^?kzviK`lcayCb8N*r&l<@!!k8a2wyi8LwLl^8xqJ+#J8 zb8K|9>!du}seM^;=~J&u?12@>(wNn#KdlnSF0^}e{7k$}fnqycuj=S%<$reX_7nW@ z+x+#mS8u^D*9Wx)(%zM&XFOmrf(kxw=<5#3$gO_~KM>CNF7x|v#&_wbipcms$ETtDGj!g%%C^My5~oM} z`Fk$3YfzEA70dc_HIC_K_>`Ha0r0%yA5XY%J)^WZXWedEdn3{{UFB2}u-O_`=KCt~ z=gHoa*MCTu@AmQZF628!hQ3UyYy9Y!Lvb!2c*B(`h_|kB1$z2kth+z(d{;#D z)i9*N)=g{H;+ZR3&tUN+Ui{k6`-6p{m$RilY}eV?c#_i3ecP0NO}uc$R=E4~gj3i_ zqo$ZIfUHVqHF>(m`gV|wgTYX144aGq(Op;r_f8j%~Yp#b!#2uJ#C%xOf3C@PJPc@z? zmI6u~zt}oH@byxO!xNN1{E5Pe4;kWG$VD;RAL^ryntR0Wuj7>j)v%bc%6sRIepGKR zCi4Q_N}VLiy&V$N+)Q3a5n7TmKDi!u@}o#5<$}x=6Y9mprVp{ zBGbn5Ax=hbZFZosVx)xNp(o`q=6)boG^OyjaHw2gIq{xZvDwZ0IW=|{UBj%yIJXX{ zr*Vfqu@t6?+()XVKTXtjH1P$_V)5)=Sc!=MI3!PTX~B`xb`Bu7Fy_x{(za{VIeRi?O-gR&njNb9 z{`w3&a_7!EaaV6L@O4s8s`Yo~c>9FLiIu3jfaURrPm2N?HB1)eTVC%QMZ45@NOXtX z-gmv$zR_$XZ@d);UvAVPLgxJ&Aj(CB4T#NPs2H5u(J**9Q z6Mc2ddi4cdNN;%!gpT{rg|rNO+!L&%AoBz)FE2E7pDfIWRvov$M>w@WAVveM7a`b= zG|6)()xOGRQw{+;^eHCuxhVCn6?;DPYSoHMxOiUflAcVIVrwRB+6+?k5>!*n%>Udbd`>E<-L`sx|UHcvJZhA@@0ot2Oqp#R>d#c z@^r!zP`}l|7Xl#_# zYj~cLPQUAQ(6o9Kd6srt?QdGwiW&LE=eZi?rTzBs+Q6N<`x7%ApR3=OcK((h;8B+` zbbS_;@5@_;)JMu4=V@2_0IS=!IGUw_I{m~hdZMPB`ADe~(IakN=mkC&t=~9er0M_Y zwy7>vK4P{Z;S2L!tcm1;FOU~QdK|xzDH8Lfn;Eq z&IY1;Y#N^dh+D`+Sb#?_J6IYAX8tBf31Fd0wjD86M5<&z38b4J!h2`0OK?-)c)i;Y zDzxIlKh~0L5`zN^%ihr^Q}eU1tX-ta5j6@#XW30p`Hz*Iv~-bq z-J*3?(>T{Zo=o%bjV)=_C7mvkoe{E!sM_BXo$8OzhgpM#nK-~s7VTPd-h zd4(Gu_2xN_r|vULg{~H=Dfyz~NHMqd_#%75{{~f^A9UhA>86T z{BgZx0)$(NmyoxS@jAa3-w8-CSMt4)5GGlWTP80~$%7xXwdT!JLRm1GjW%cFynp$a zjwgi~nlgdtRxDI--}(JjeTKyoTxk5vJP9!>G8FI2OpxEi<(QM^TD8DO1aajCR>^4s z6yiOeO=UoUT$*1X9gP2dsud}r2gSO@p*IZyM-UxQSwfPb0O8gFAIL%MRxF&9lW)XJ zJ-U$+3uIgXNmDz)Z%ni8O{KUK-ku&L zhN{OU!@LDj1mvd!0MBy~FuYnUALpi4DV61pr*k9lmAZV@z7xWbV=%mrNJg-;h8X8< zyex|fvnE2HZsPjXj>jGBBubVn0FYkHt(>ch!b2hs;Q7hE)7irDQ+`l{QZn$sD`uid zH)H?NtI^NG`);0k(!hSTWFWfSd7=t5YRTa}Vb3$;ZzhrZ_UX!c7l`p{2Y@gsfPwbH zT`s;_T>rBAR8|XX8F!DKs&;MX_K(jW4y_Br&gE}sr`pn2oMU;ESX3T2pN~56ce#ys zcSr*Xwn20p>;gc)__g&!a#T+cDe9Zq@o zX^%K7a4r)iO+ha*QN?sW0R&DBaP2J}{+bcLf|K33pjzwB^PYr;n4o9yT_F(94^a zODt6JX1s5hgDRV6eiPM?lbJ6k-i*7z)fd2>NDeZJxr87G=%-umT%PPubJ-1i7oNVp z9C%Fld;wHEF-%&j1FXmf(bynP*>rkOfEK3&xDRS)ebkP{)rRMwd68Wto=igOqJ2`O z6?_DbN~0sku~}~kT;|pgUwhOz7RAD&_*#$>IX=EDN4=qPbCnSifPi3t z`S=G-b3At(31|Ekk+n}nm;<1i16t{uT8?yx9S$*WqdhzZQDJHv0Pu>kxL$STXsL5& zFkun85n!ffdkFj~9@z8&lBfi@!_s^Kj!wpM1=j;xXp~eM%#8?3XCXr9fCPM`4;Csw zMPTXy=&r~+a9;2xyy7U-kPvl;9L05yQ0E?5i)vBf zUl=EO!%Uah7P513!3~)2B!ewHVrE6`Y!CWRJ?7g! z9`kLpXpfwB0SKW`(R*~vF9N|S2OY(XgT2L!*MppZ;2u+SI}j3v!|bup-5+T>PDi8D}3Ayakz|-y5mI>|rsrbea|e{)u%5)PWJT$2^7^ z7}8OMYGu7@v|H(oE7tm)>h&!GLror2&+@qixue-AXupJ6B}1F7z-3enM5Oo!NpE5$ z)nrj*n8m<|aFCq-kXzDkWYeen!LLaeMQ*}LL8NU+z!fO?`91;ji;cd8J@l)b+^(iS z-<;uJmfl@Ko=cJUPLP^zRyZ|L6>zuec2xSJea31&y-XzIt_GG52=T&Y9%q7d2r@ON z8aSHhHs1Yi%1COL)4@K4ox3Q6}kE&&e98pJgGs>%~MUNFgI}#9QS#XbfFdb{*fCaRM0ut&qZf=4-h+HZF zDCd^Z2L}Ugf|-j5O(r~sZBcU)et`b)ml^oa&xZp?5fH2y5XXIe6E01FWzhkKL}9)T z@WW8J4B*xoB9~`9= zAS^Tb5K)8{qMXSntZk80Wg|I27V&ZPM?y4vJt63v0|mff~?5B%ZNN%q|hLk44m_3O<`gMUA0% zS?DOfmUw`-Di!sEi21}uHfXae#lpdVI#Ao)b}^ zRLpde>K2hR{|V?JI&uNb2zbeBUanWACy4!04{NT9IeFG8q;7+{Oa5 zYB(+3Ww$zq7kHcuI*Q}s#k%CL8a0@pq7#Ax7_i|PH62TKdu?V zqQ+RrRISaU*yqs*CSJ0qh5dSrC5q0SE)ond`1p z1GrZY!7_m$Y?B}XJYroBB64+<0e*x64-r8fkcNqvAuQGP2o4}r4{5JxIKXh@WgxuINs+75F0^lXpd^;0A{W zg^IuJHO~PIVD&@m(ckOQQRK@C1g& z*^9byMUTLSiL9ViKB&f%p5dji3b^~C`-PzMmtf5lG?y0EY#Y<5gmciC{)$B^(7n6} zXs{=j-97X^soN>G+pM-cuS`Uaz+I==ljYoV83-O^Oii(-)bOb9fL>B!;2)X(20n0< z6Q-Lzt3^WXk}*xplc}koyCmiYi|b6n1mZ?*-bc58?~L2222rj6h<6K2>L?Rz%L)ne-EoBLLJ08`-sq7#;2Ypn<3` zbjhzr9jLja3w^}vU=s|JTohDDD@ zIBA&qV^&D8JF>zAJo*O}%@tE-?Sj%OlqZnUm%}($1uZ{tm_pXwM|hijy5BI}pg|A~ zwtaioF=*>K=Fm-Dm9GfvtEjz5L0LSCgZi3yxxjaS@>lQVwdDEn=(h7Qf^&0Q*;KFs z1NCDQ9llTUQ^j#@QZb5`j^?qr!Wdp$pLurin3@&AruEifZqX(x<{OJkfgyrtz+q`f zt*#H?4(5wz+%^}%#r4fKL@#FodS^KE0;lCShj_*2QKI&2aR5WV1(oVid(6(Y8nhkr zErElv!tV5HVMFO~%I5d$CGfD#vu$4Jo#%!MBp#*k_nvy)dv)8UZQZ1ewsI`{j)}aT zGgg89>{FFY~(%OJ?^gXjH)aF?T|0Ce=TxC>U`R1VAuUtE@K_>RTJ{}Ww?|8`~j zgZpd+)>XOe;!i@r2mH^z#G=62<-qcX3*~F})S`@z6T!+le{3yHU9dnXY2YRn=(t}$ z_B?Q&ibsiZ)lG{ybj+5-;vZB3U^UXY3GWsL9ZlL;#`bZ`NoC8Y4E1yHs8JRj5R0_P zz79oc=;pK7XO1}nJP$T_o&~7*1W*U+6D+C6trTY+Y#Hu`$hZwk@)#5>B`fqlI6C)m zrr-aM?__h>nDc37b3W&Mrp?IN2T?>d=QDH49Lf%CigHX6a;j7kC8tiCNh%5za}5^hO=94d$p?x}A8I#-48lK!W>clQp( z#T8BR`#wv!h7dwpR3aT-MNB`~Pqe-jaX_Y^7ZzjwFyf8WH#T1g{Nd5NhtJEf*N23B z!P{J=FI&0!*xi%oqJPcY1k&{TZ)I+mOE>;Zkb%=pDtVn$(Z(Kc5ToEdY+aF^YhpL_ z@OinMSab_I-Hy#Zn`?L5U2dmZ{2hp5kq!TfwEdfdLu$tiycK# zJKA=r^pDswPx544$iAIAS>I7H(MKl_hMViYaaoe(2Si*YdGG4*#cc<{3Y454(Oly(HcegAC1Wk`RBs5C`$2y`?Cl{@WF+~mJO;08 z(|Xwv)u&d|nHOQw#z)vEmv6f}CmcLH{EjrVb}BIO*|jylq<0F^lR@tt%#Nq!R+}A9 zpL*~vko@ji=j561AIv@`^Zk4GUWu}#0pdYXdD1uGhBwaIT@d<{c^B@l{@=pxik!M+XSxrJ7;h}L>yZrL?(ks3WP5k~m^IIh@{>)J>1E4{_ zes;PC`#}|WesgjBVv|JhZH}CFNs-oc<{ef&%~kJ0SA2+ooV_dsrY}Vf6A%|G zTxn{WS*bT?i{&>aJYR5ih8t*2QxLqvPy(ex%FafM&ry4g3eYFs5|xxABOoe0yAOV4 z$G?i}{5YKqy_zQRE8RKb{R{Ogk|d=1)f9X8&YrLL4(C~&o(BGBy){_cQky}Z{c)AJ z{Y(7`H9xi2c8{eA%AO86moXD!A#jtewPH}{3y;MAFwCP%iPZ`CE-C!GMfXi|Eb{09ML8{UK&a54Rdbuir@1bg;OhPA|f?{+>%DE>V53o z#^zo8y*ZXU`12APjl$|ZP~qWFk>FS%Xa`BW>KqZ8vf<3MD08$~V&|0r*{DBVj&g7F z3VCl}UIn9$=2CMyWNrhqVpQUWHBbMBxbAbqMKZD^^y-nvD@NLr4BIhLMgSJVzdZcB zrQ}d6OsODy$-4y4i)>O>8|2;La?;;N&I`D|Lf>d-nmKvqoJzf&&b?Q`+Aw+S*Z_fGxd1e#EoC;@TC;Dy+Ag}L#H9#XH+bSH`usIsbh%Ly;{duCLQ_c&G;Eks?j;QVTWgM(IxKC& zJYp;}I(ppo6-XjFiQ3^4AMLAbC$L^?GM2g~tj2FA*0(5jfBXVexq`ztxoFyDLWQag z;XZj^LO$Lc(mb~Ne#%sz3M~V~yOM`cKEt`#oG?ICIv=pi@SH797vaogg!w+eLA+okPm++Nkg=tH8 z7ZX;_#nwhuRl||9o@Mn)i+Bg^;7#|$x!|PES0B>GoT_g+K@A}~+)%hO{6|g$3SsAH zbz(*F^0beg_r^`n^XG8ay*+Ma+`nbl8;#Wlj3`O}8E~2qDSxo7YOI^y?0#yiRA5TU za%=Xy_doiv6me$+bk~LM-3h?KQ-X4mqf013(b6) z^y1I^YeuE3A~-d#&CQ%Zm+0)F;Jt~0q#Yd zft)a)2|D3GNIyF-b@kkrnvw=y{DMjv`eMcaoUn2&`)v>MqI@hD^azT3@xqjRuU- zp;wdk2zK3%JsJEeLT~1{1gzk!+JE+TD7Siw<$pZyGEpdVP`Ss0ReZs?02fizDV{n& zn9R+A=@ZlS=XJlOzsAk7ADYv_z!9PzfZ5dq^aMewat@tBn1{O{P#rALo ze!lCS^=f|Y>j{=^E-O?i;)~{oTD})Sv#92?G|Q!&@FHmBFnt60G_&$D{{4;3uQv$b zrey%gtX4L-H7Bxy;XA4RGrygwQDs7G(#w+zZm7I4AmFq_DMr#klpL#8N*Rmd(51mB zu15HQa|LhSZK7C_a=@O{B%@B`aA)@Ltz!=#T+%8~8lW92f}AO(0eE*GD4#xX*2?{M9E6W+3TRa*>Om!yf^8#n4r$Oak%kPw?Fmusv{G7G zWIj2WUa&;Z2*@*ugxGSyRs**>_$d}7ImxEH#7s&vmeR3uEtiAnHEhaWvdpuR+F2KUj=fezS`1T zp&}e0j>OE|wGevAjM0BA*#%W>gP?FK-&(<%Y~Z0Tq}VO0#{j|)b3r1KkwvasWfy~Q z>VanYcu){mKOhDGLTk{pyJ%WXhV4cNl)Ufi0O?5sOwXuBnPErZLEUsQ4~SykC*~Ty7ZhB_7wGt5Hluz6=`%10dzPO3*qts5QA=lU|@wTi!Q) zL(UT-5e?m`kUHuQ3;-b0S|Q?Bo*e77(D^!GEdJQ_mLXiFLZkHB&O_-6=l-xc+mK3D z?-ED#{;QwK=(UD>$3lS8wNJ%~Kr9*5#P62ik{jj30B0JVsD%#Ks+)8{Tx9tFG*R&s zMieWjrRY_v>Y0dO!sGbK$$!$Wa`3^865!1 zV)qx!(vO)L33DJ8%JB1%n_z(pPnIdb*90c7b^S(#i?d;=p7i}DSD+;hrX6AsO#@_60`mbP^bD9Pd6p6~ zjKdku>HwNd9#CuvqRq}x87kSqyp!Bz>P(|?Q@8PXBw)(_T%lO5Vg=o{7O0Vz18L$1?gGcjxqKCLi&n~` zUCPxP!c0N61w2c42xt$;BsjI3yt#*yiFK8z++o5W1OJzWSI7*_vJN-1PzgR z9v%e4@Z=WCaiLkQ%oH3{WW8Q5s9a#CF}cYyZiyJDuar6PHf`X13I=)t2X%P{OCT3H z7BS`LpeMMwu@ynrGa(sGuv8p00LMsag=P3Tehtn^Z(^o8K?62&gPQ08njo{L(ez1Z zKx=L!4tq);ybmx|%l3Il*<;GI@+oI9BQU`U1Lspo;3Hx|S;+CwU0ARua|qAnKAh_-O4<3u`s(@RJ9}bx4*u1B+Q@^=A+S_ zgA|v4EqeLURN$6~>IG&LCOEzpmPvx)n%YPt$v-S=jFWPTCs@;9s(srAUq7|N@t3@P z?~*V7!^SV(aS_@a*YUQ9^6^*IVg4+iX?BiuONk7W2sj&+-@w1L3SMVqUc$u7i zM}BBA9w{gQDI58J=z$9c8kGmF-##{6bUC64`ZmX3U4!OR3$>lUAH$z3pb4_pU+y|C z;Z^~SY2^!8xpb|VZq-FMY4VaXrm1y-y=0;RkvUd4NG}#;j{!Hv3#kFX_&mss{+nvJ z94ncT4$tW8{n1S|5HZPukbFCp;RhWW0N*aKh9Bs*AE;I;7eQfLX#nB4&OR@ol6l9J z6Mv(nhpo(s`#^vfAiB3ruoInounYLBsBe@)^P*602Ik$xmpq?yT@6*spdH-> zqAL*UWwg`U)H@8?A&l2u85*REue0Np>Mq4g18C4Sbg~DLHOc&ucXGd(4$UTyW=u84 z7cnz6U;@T@y60foOUyGYWQk@nB*l`JW<2~JMb6!jfX1&ZHcps#4X#HS;KK>A~BmXJhGCXt=eo5srG9~ zN%#gVU8Y`h8FG3U=I>do(gY&mNWb;+(rXp@ejQpj;5QCt@)`m2sX~Q>Z{Uc!tVpJ; z$Ws~%n8Ia}D_}fFP_~osiAa%i51(a|NvAxSXJi!jX^~=!>oDVE3%t)Gt-hA6Fq4G3 zti1KqqLS=dhH(ZLmJJj5$#^MtloE%{(pa44Qt6V3nSOpj?9V*d(z%O^DdEz8h8esi z_-(t9;m6p;<|S@06KmC5HW;vj%%g5!azB0{j@(P@mp--rW#d-Fnd_;VF+aAhe7Srl zRTaFH`S03;_E$|T+Mi6&hED`*O!g!xs_4{mm{SNn?|xKdRMe$YCozim|2P{__)ZkL z1RfAQ?8NXs0SzWXj`Yg#SP~AC>I(ny8J=9A zO5v07=;_yy9m@LjLJ*Kligc0fJ6d3`}`Qz&YN`P#~{yzvvJ;D9_eD7!`pHh@6p+x0={#S1_w{I>4O$pD=wYpFTikL&~`dEUrO4t9Ws` zwNd~H;U~Y@Ffrq!0E!%U#V8c83?N^9O}>jJ$oeTZKx6CWb>KX+nOAtn*@8=e?zKxN zqasQCFnhWhn!=aZ#hC52C~nAk;mTOmchMh)k~aQ4{rQI!3ANebOPpjxWTRdAd6>An zS`_M0C^HcQBjKRIn7iNOzo-Ccp*ZF#9)!sW7P;i09@!tG4?DG+mCSDLlwth6C=ri?og%_gY8kFe zP!g$u&7$G}u(1SYDu(IYDmu)i`T&?IL?%rJcEah--z#EAkUXvseM-EP1mJa}8%NQw zn6v*9Fu6ETUbeYRBH{VEVo!KuZz>18@aZ6iSY90PuBEyszKn$1`?8=sa6t(Rx~$f6 z`A*WlKEqYj(78B!eypwCIJT-?%lY3pPIX*sHpb0syVeQrX{@rP? zY$3pGIp6;tSm!FThKKX(ZJKI;R^zc%`RPiOV>}{FUyB{B2wkVZ4-x;#}y3#q@L!oCo zW}@vt1Jq{PbZzQJ%)<%Yj34nIt8#C@hVP|Ck9)VLEZ?ho`R!h}O@^vu?9{#RS9xvT z;%{SR4s%*V6w3t%(>{$p> z9;L87o5Ph6pi2h!P~)RH*E*@;*WBfo?ewZ5HyA zlYxEd8>@5X8e;H$h~;vl3C@R4m?13VRr^U&)JZ*~8N(G+u`d13irPMYCBV54$v|gt zMWH@kHYt4QdnYzUL_E~q72kFku4Br1*@Z^gr#?!4V<^X}WXkGWSNh${n4CQU2c7LB zz{9!4jxwXYt)So={*f?D#_)*md5vEjO)~%aP4v=FpCr5?z9otPLo_{?U z#PuTa80f80qWS=XSah`0`-qgYEl2{~caPAVr@RKqke>6{0Wcln^y>WB9Ma2&;-q32-4-l;le2D-a}2&g7Z8z2$Pz~`)T&fSga~8p>rS@f zd6aG2?nF7er9TKcGv?{=AukaC;C9TU_3rX>#J1$pg3;?EwCrkI_{;+Rg805ZF)+ts zx2Xa8bn((T0Djn56tBE68npVLb11bX!L0GUp!P0@Z=ICnfKuAM z;AG0eZZa|t*NbOrC_WJwHromikvQx3OwDlku##KBXPuwVbduT%rU)k;{me?ZYZqLn zV;UwV{iF~I0HCBk8)mz44wRLkl8|!zYaT^eOLPnB$Gsx=s<+?%x9E8%>rcPbo)26o zYH^$}3XzQ&7T`s|GDe(G|0AUHS;Js?o(V#|3onwDqwHOq^_d?_7TFi*y;t7x=rez3 z-mBwVo-sl9Rb|u9+G`5lujpU>Y!Gy|W1G+D^6RW{16hj~Fuwm{5~`|DfBAD1X6A%F z2j)efER>dUQgP%=&5DoXV?^X&<%PhIjq6c8Y5$NVTW-oWo0r`q!>>c%4Ku9(26v8a z;Y8O59BtRV3NuxF(2Y2$gD3s(lNUI$+Ibp>jHcDk3zk-_OkH!dSb4=d+urC7zv--; zW+vTYd`<7PrW1V$l0s0ypiA}YJU%5zJ7 zIO@wz<{dD)Z@1BhNA|j^m&}6|YWcZOkGGaQXhymB0xdlOaL7Im@UyJZ=2P@Uw;Vsb z8kdXCA-kF-;zj7gV3}RQyL*8_NIHNc4ZA)0%}1a~^-D#%T|(HJ{dvwOE;+96i-KG^G;}bNl^=t&Ywoe|1T8 z?U`9&scV;)ZzkSdn$%D`+T5d}m(rm9VcEO0XX3G*lY@A_{=KqBeXlh~>VxC2yf(W# z_tue@)eZ$+_?Z+Qt9ObmH8WLH))*GJoOC|&Q}?LZlYf5?P}2P?wJ2CP)O4c-aI`}^ zXIAj++91h?!v!;e@Pv?|Go^W-h9oM422*=;QoRXU9hV;MduZwBiVr&MLc5+er*4V_ zH9vX%x$}{-nsz?8d0yewZiOs5NbJxbw^44b_>vRMvZPtqtuLYBEtPFJ0Tk{_ii*p+ zi8mZ8UQoWoA!!X6d{ko69p&Pz0SQtfHQ- zaN9iE|D65-`JY`C2jk=F?jH&KerC7-*y^<3#ji_uCdkjrpBP7P-*c6;!8;h)8t>)^ z=Hsg_YaedD7jsw~?6*KrqZ?P2g>Yn6bu{KKr;*?uDQ`r7@f26RWoj|d)4 zw7BFte`+MuxT^R(d4?{5-2W`tTr6@5`TpoLMuBSmWgZQ)~u54@$DVt(OQo}*UZ=xoT>&JYP0KjL$rlU(}pHnv;OCx%X^Qo zt+3e1K1b{w3Oo;?k{xZWPZ(504sVzUrjPC;DhQ*-ty@<##{`X$@XSYh3$=LoXA$z{ z*C*GFGoxy=qtARlk?yv6<@Y1is#$nI-mcj>GwyX>KASefLA}9)_{+QDsdSU9@ZPzZ>FMq^Eo-Q<2JZn?e<;*L7eW<*4c}u*C zt6cu{o%T*@_ru5gVSmGVAB;WK1joyn@k=u`&J~V}p`YQ&wC#c>pqk1B^uMQEn zp%|IvuHJtfAvx0Kd{OA%{v0m zBG^JWFN{Mm9-r#;oiwTl7L5d(KDytL5d8&|FvQN|1TO~XSYYTL#NaGcNJyKY1{9On zcz!yCIO!*=zEg4hIzoHykm~ghgM805Uw#rss2%;$|F1Y$*JJVMW2NBfOJTJCL>{qq z7J3hi?bCp^Kv8|X!67w9w~*E(!5Ra0=stFkW!KS%)8D4w9^zQf&~29p2dn6Ll4Dk@ z97}*Fm`b;u0Uz)=e^KF?g^EwB!5Czx&TB$h@D?$JW-k_qH`o6%qFQF7LceBCy)#R& z9wa0hN;D@DgcWlCpsHZ;;L^0N5(W!I@|QKuBb zo@l;vzS%fbSQYL5A0Jgx#ZDVVKM+pC^3MTa(EYhTWk1VJvat#odiP0}>o zz}91Q8z&979J*aDSepnkZ06jF1|`h_G>IIOK(N&U-Lyc%d4*~<$+3ikRh>XOO?2By z`mOdRD>z8N7;LvjZ~uGy$VwA>kAAe~kl2QusSns<5^PPPoA}+*9B_tD+S!bOEgE}O z+q|rRM((;n zy_(a#bK~pBk0;%k*v5%GqF}3N5i2z9RjO2(5O@Nh85pt&q}BNl9RWai5k*Pkt5ziC zMp8~H2*`d3R->@%TEJ-IfHq00IlsJWE$gAgKHFSljI)+&d~}ux%Asnw6t~JZZ7;W^9;UcZ)EBByoRax8P3g(3Co?FMVd0;A5w9Te4SS-}^U zJ2-27<$A$|;WR5Q*aCi=6ZUnQ#k5=?Xs-o|_TE~09o?)3lrH16C$ec{0M$V-FOg;; z7p%sBh)n>dEYXbLZ5Cjsz@>C@f#@o_Et#{q?yyCRi_ZGm?v>w2qT4osgU4|i0~{L_ zLSa2?xr45-^y+3G2jim>It<*T1>xBV_wxqEbZ&Uv`6xM)@Q>Dq>!aJ0(N((&@`!^T zMX?wkHg5&*2bNjRfFa4Mg<|eE>s=<+pl~GJE)0x$B;Xjzv%Ts6`ur|s?7hXOjd!+j zLfJ~yh6Yk^_Vp3BTg4PlT)LI~Cv}cdecURdzVLIu=CKh`5#vYcQSTO8^`a35qt);% zw&q~3UKSn{oan!?7I%c8`sP!I8%QR5^aKlsI^bhgu=1jhIGt^-|#2s#$fn{)x3bS&b){M~1ULy`pqyCJ%T z4?%s5%0aoR7ojl}JZ~XlrwtT;_a0fVgK)$aY%CH?w>2y* z)0)>Y3iHprnmM+Cgg|MkJSEnYyM6Eu$D=gVD4)(^J*!&*XEVOqVNGBs?g?hcc=>)2 zjOC~wm4|Qi-q8Z-Jj_4P6#o4V#dwKeMfs7Hft6X;vl#|A%QjJak6GlHWj^|G;AE`% z_TAf4U@JGeToK=kf2l+fQ)!8vpl?k_kKMm%dWvMO)73G3a2U+1TyA~$!|zvEbneF` zo$fGTbcB5PE_`Vxf%&0)BAIwDs%+6HGN4=7S2XtI&4cpdB?OuHuN@U4Q>FLyOOML! zSOdk8c*#|~CIEc(H3;R`c0-}q;SF6)ha8@@nNo@n8KYW4;;d8b0>F!s$h)TGPNhd$ zuB8j)fb+5yW*KydZ(?WWS8$dxLS(R$#R3?&$5>4EYSn_Y+6}T5YqFKGlx#Xh+}u}4 zj`j|$tV2c=e5{RlY3yX4d*gEMPZvZpNFg}KvKf3O?!Bo*M&6&Kz%+(eBq*dA+_Xrz zlI76p8D;_`bd*^N?Mk1&1#7^sq5b+F;ickK_+Q zwcACY3B1}X$xr<_Wl{GUeB>$ODzlB0BV`8Be145CI}njn(Y{HuM^yB>Fn=zMu6SwO zG~?%qs_d*5IL0IhzJrj(B+D}im`u*V2=zti+5fI)_%!w`-^sWw-BtU-ZrHZ0!<63Y z4iZT*Y49|6tKh7Dm{J=j9HUXElY!sk`%|^7AeASvGYbx-t7+smz?@tef@DF@gm1c zL}c)((B8v{bhh}OSlSaneDRf@4v{Ypdrhp@^6T;0QIj^-k|exRSMPy6JH0A9)FZ&m zibC?yl!3xWj~6cAvo(9h0u0a5P4m9lq(oajc_gl(X{jQdSp+bl#HVUOg{^6>0Vl+K zsOAe`jkid6B&bPl=O9wW8g4h<$5Lj|w}spgNOenVC~m{^t=`p6Ne|>d*AfWSFms)! zd!rQvJLF5{H@^L;3wuiJc^PJ#Bizd0nYlLq%-x)zQU6j?dX&Y^E~^G(?8dz2r-36 z3$g`EH-_JOT)iVH^l33wEM)Rv8a>1E#h*gQTd}WM5{aN3NOR^7@9xLDJHel`%V7}{ zZs}Xx*OzqTr9Pw^F21b8A9Zstz90R#$>u6U*U~6zs`==v_@UpX@za%Y%v0wrI={ZV zQ8@oE&>BmcYrC}1Q!|(+e;RFzc=x0_Gws_aHdFdwO;-B%FE^BbdRUqy|D4HOeQ{C9 z@3zgMdj9mSzV6?zOq?!9)OaMlg6CO#&=?SjBThj6b7U61I&+duhb2ayYwpY^FDou8h8WM(bl3B#+2eYuyXQs^>4d*>m<{F9)X$9A2j=ccq zN_YWr%)M0sezR$+c%j9^)wktxdciL>o3w7>#ZT{0)p8|{ zV1kNTu2ZqiZNbCfs?>>~FI914&V0<~jzG3>Pb{{MA!|~qs+i$4QpWna!n98pcOmF z0<%iKfhKpI4X=zrr|at_j0!@bD0DjPbzXle2&cGgpniqqbNzYW1rp}7e0-OHI?uK@ z#kdl$*Ve`GjIDWoCF;6?qi*V;#+)Kn@%!P*sDVvUG;3@OdNt!^_pvImHtPWaRQV?3 zO5EU0b@YRWFQC`U-z*F$7ulCo!s55unAI`Y+5J4*UKG^ZY-)28b)CK0=BYk6y?7|K zDILnQ?G=9!&A$}Aa0{0T2s_#oK*PCgQkQ*P{1YlH zw(c?Z^Z27+r_VLnlWl61(e>12MH$9^dUJJ5OFW7E$~iBJ1^nXtILkoL(g;{vtCqD=%_lcSF#t+~;Cczrrxw zN~{{2DfVYpICWPU<@M{i;Oi02nT`2;+wD3f^E8%HGrhnJ?U(?M20FfgUD7vwuN-2je`jQm z1G$>d%S|^O($_I4yz;A2{9RGMvscE07{7XTf6ZR4R=jXZl`?9C*thYTAsC}W5S`G6 zS-vbr@a|41slH&i?Z2WTTzOch4vd;e7XEzM_4f2oOQKj&5F!Aw7~9$kHEb!$>Eu#` zqpY4=46@G$QD*T-t($IP*ZEIG`bJ-x#Vd^NyiHEwNEKz4H`>0d@|m7%`hsIxJZgiR z5OZNyd*2#WiTXzvHwdSy7O31Z7%x53EM7F2A9yeELP`}K^{$qHqt-IQQW{W3y3b9? zBfY`p*G~`bg?9>0xix?*4?li!|MsK2YUuPA)8d#Xhto?Ht!(gd+?BI1|6<30M1Z$ATmh1&UO&)CP`ud5&$vjhfds?b=w`5K? zZ>H~BE!3BF5-!oq{j(zlRcUdOj4lGngsQ1M$lv(Ba!k|!F9SESOS}&S=SWVnGJRCD{qK+?=9Z7yO!MWz^rol zWz561V~dHSrN`Y9D&JP`Y+r>zqrUx{r;?wvlg|}JKjQB>Q+o&jr?nMk1kU+sQ-Egc zK#}tO-=>cwoN2f2mg@N){`&67HMIyNV(G))^+|^cr;Kx_V{;p)r>tq^9K1@B-4CQLD)r~{N|I?P$xSs+Ur%o=yy=z<2F9_#s%?Dd+VL;zxX!B zeeQqi9{+h0cx2;0p}n_=v|SGNi3h{TdhX)Kp9cYB>M0ny^doM+^?IAIe&0ir7d3jd zUmi!~HZbQ#HSHA0SVT(R7}_25pIfEx;``#jkNj_r#%Z4ztQDzVaxnWnQe2aA?LhV0 zF^St|Tlg2Mb9D3*nG=8YK1S3%U9_3=>UeVO-xWC)=d;G2X+qf=BnukCbQEHd3Bc@qg&EIwYZWFPFgPFICoYiXguTCj^ zSkH|A^(3L@d-cz~FL=e@dD3h)(UUIsnw)y^z=_SEyP0CFBA8Jh>uI#3`qyj^kNUfT z+mC<#{YF*HniaWf>OiSp3;32im#nT=)~WX`S>*3I*X&>8o&SEcT|K=fZL|6Q=f9t9 z#WS0QSNA^u{P%3=>X{#Rul`+2+yC=a1cEl-x9)Mw`fG9^ar?^elRHda5!MIrkpKd% zy<0euLBOw%!ryCOS@^6RmpcT20llSSaDR%qM?G;x@FkK-N)kvjrd)j{%I{EzQuAz%J5U!mva z7H4RLKCF5}piW;9sK0-Y=jX#~gbzY)B1Z<4KTk%1qUIrg-MjxG;MX?bBl?JO&ut%F zdPnHL3|$8b7oj>gid3S%cKg?i6pC{D_c8xpfpe>b?)bTeNpc)~O_yIJez*i7+Av>T z^XlNSLzP9y&wV6>fq}S5qWIn0f`d4OH$+6IPF$w$xt^{-FbfXAi#v@V7Tye&uncY*tDugNjW#|`y9C+Qh@>CI8mt5g(mR@4rQ+HVP!4KILg0g}0O zvLK)c5vb4-3Ni5TU!f}G&5Ekc%AR3pM!@+uY86&z70R*5ZI<-JEc#=eu;;SY{55C` zRImT)4vIor3t5@W$~wMGrQjp$Hn{=oAAVy(>w zacGi`4z5KOM~9tpRyZVV8lx?DT-PkhXoU3kAh2wN^0k8Y9Vcpx|MW)hd!3wy7{76^ z{LGwY@{pLhI{hV9@g;UGn26fODpVoVb!JsqrP56o#P*GAZM-mWpX;*1!CWN-KRQSz ztB$8zlLoBtoCF$XWh!VOdJ8CL8QhWMIv)Osu@!&yN*RyvZX99NawK?Xxk3w z8;pX9ejBs@?a%)Ahbv*&Z-mM&~I2Yt~iS*yvs@xUQBYq9%p!;Hf4qLo- zFzs#?D;#riNcC~{{kFP=Za2oBt97-QOTUM8>B4DdDVe;Z8pifEGUdqrSDwp!kb1jq*lFJKmY$JvqzCIPAAaI)ll4c6lo z9@Rff6zM>rKO0#p3k>2!F{Z&-Qy^Yh?+IRUcvevdtBKd}E`AX3VjQl#sC;lIpnu%y zzt;zYj7M#KJ7jscZEQNQ(ukFOYy&3*_+;#s~uOku2x3erbfmQ4cvZHn=tWuIaaZ)W1Yk#Vf zUr;$eSj4GLyrlkw%tWT%JQ!xyzD1QE><@X%r^{!c`t?pqoRRMPQvm{H0UoAj_S_De z{1DshI2HHv)GI;)Ux@Ex378u2zz|Tx^csI{9eM*O-<(Wbqsp_0hgVrB@;%LD*uo$l zA=k*?8>F~2t7dd@^w7Jo*gnO42b&+I&O;GDoTTC%q{EIMJw1OU5O?wLxMbRL=b1G# ztCXMN0T1{qX-<<^6y)xIi)_0@rl^*Y0t<_RN*}o5-F)T+dIE@gG>cjSD!#@xzkEj_ z0mQY$6~w@yLz42dTPfLJQ}?6t%^r{Ien>mra9hQ3_e_vECTT^ zxsInYJtycyP!C>v_xHODMpfp7uOMj&9J0eX60E_`J$lY z8bp$P=!0IWJedvuhrgg0+Pp+5e2PW&U}alC=lzeS<`c!TsM2~`r`J4F*)js}R8Q+( z4t189^-haZ@OJ+D=KS$r7e8FY5^G~W*}e8Tpxq1MUpV0Aa@6f(KCFL1S3_qeDgBac zZ0hGU`KvJ7pNKfHkIQ}?`0Ly|QG%}6TVJuy&g;i^1A@A*JpOg1?p2BjveH$yYUo$h zNcZwmIr!PHvMc)4vlca)9{ghIgmeidxo5 z%3U7Q=ac?jhqbI%&8XMxsn`8oZ(!MABKPpbsRo=hTUZ$s(#Hv_T~{u6Os`mOPfy*3cM-RqzbsL8R?^>lEy7*>mvGHl^K zL0Igp$~sn|IR~x7egzSCs>XvuEukzT>Ehe6gZbUxW{bW7A38jQ>P?_LS#0aQjn)S2 z6Nbco>@}zpKo(7x99=lgEP8T$@7cSHuzPjr=v4PaikLA}-)KO7mx}IU!;b{{3-8_E z0yteQebhxHb+TCt8t}0oMJ`Z|gp<2&{xF6`cpg;VZTQ4US+70loNj2d43+`7@7#^* zAF&>y8$ro<-RWLsZzHshG5tx9LLeVsELDwRJu^lmy~4ts;BS_(iie5>Tf%C`>QE|J zC{I6b5ZL+>uh@%)Z(x)d1;0-jD-P5Nx*WT%s-oBv)A9eDcEO;nY;@_;`ApUJYlhe(=V=o@hn2m&ai)Usi&94W^FeK7e1fh|q z-=s?L$If~{b#z&E!ZQZld0Nb(zawey5R-LhX##m;Y&&P09yUe6_9(by_K-0ZLfJv} zDqJ42nK!XTeg2LvnpKNO3`SWTSUCRXF+AxUMrPwU8m)}l26zu1F}v{i<=S-6eXM*r zR!fOOm@W6BLXu7}-|PFj z6YK1s)FrD~-jnaMjYP(sts1`lA3=)$c5iA+p-{FGCx71Ae7x#8KPGms2wNMkK(R5N z)C-t+^8G+C{Zffciot>DmRD??!WIw}jXBi<&^~5^Ix_Sl7iG3A`{Ii-5HQ)OOj7N1(Mjz`2nQZ9Yc0Hyw?R7f`k$jRlhRQCHn zyWW5fJXNshw zS6gTP-V-ox8m_a?m$Nyy9rj%2-YT1OMC79~3gyt-nwwB_O%4)-d-zkYu%D`Z>vIe& z&+)lZc>jZt=kdPhFYH?KuXu=x;ndQhf%WmX6p(r~=T+4YL;dCLbYsIu{ z9Y_fB{?Tu8(ijJd^|7@7s%4*`s7*m>cmE%3ymX=e_NCvfutl=XT#3pXL-Nk#nr|Lw z)H>5c)qOqMHM1idN2Z9T@r(dEN8Uwx%rJ;FLA?PYUD%d?KPX4c!>KOn)HBZ^o9!8n zYZ^PqK_n3Z+!9IpS`i{_`E88n3IL~uez5#8d{`vy<5cb?+qG3+U&PyO@Py?`dvc-8 zPaT3}R$1TS|KsRh{F#2=KY;IKV|H??InVj5$@x6yd}@vn)f{q8E9X;f=A0Z0iJAzZ za!8>QCZtGCNz@#Y97ifTeD>S-_aE%B_qO}mb-%9X#a*v9Q%@4;K2x7>ur!o#%+MY$ zKWhu~;tehj$hQx^9(QG><$1ed7uzJc$O@SHpQ8XXz z$ZSV&bK9sx#JxwKawG0{%*JNOS0F5v?A-za?6H2+*B~hR&>}*2+KHa07%YFVCQ{%R zkfRWefO3j$tyima?3<_Sg!j}47cqLDM`g#WUnlj<6KZlVk zwX6B&K~ucqV#XbgjKoa1m?L8+-HtiO zPI;Za5<7k3+(_*EQ*jKzD*~!6A%))kZt`6cAD5i*MlI%4J%|4gCYOTJpuVUTWJc04~VTdjXD;yC?O zH3RP&0qffX*!0LN+G?jn{Rtq^q$2_6-(V3vSxf@_LSd3SNIVw^H--48eXB_;`&|an zW`GVQQG7%!TjAE78}KS_2sVJ7jr?GVd}L>%o$1dfK?%!^BJij>3BcXR0e0>j^gLNyCoXWok4Zx3wIOzPV@Oi~d=7IVD&YdDPAlLtPz``Hv2x zQU}diXkaN5kkoIs4Ow_6Kh+P+Q{4>Hn`}j2Y*3YYs|+FnCJ-q)_8jAl^3kt7J;+2x zxb*LyEaS{-QIWntv2E6%+23W9Z>Uv*sL2@oW@|y5U!c^V&M@vuE35=N&F;5yxY?RO zzM;l4e7=0p;a4k)G80$;?xksDUwwCDAW)2u9b)=6clx2%J(#I-zj{m&zkjDC+JPK| z;W?46c9kf-(%A=3vyhJM^yjH&Bh>9M!-;R?jJ`BX<~1KL6Kfun+*)-uc4{odS}ooE z;SDoXjYY=;BDB5z-Au8vd-{NDZ82d{NB$QFDK9DKUk?%m7oJr+<4UQ3bD zc)8I#IPvo!BK+pgWC8%h(>64$;6`#y!Z8v56+u%=E#~DLxRKZvFc)L~K(hiBGStRT5IS2gg@6 zgEYa?=(6cR$u{eOQMXr+@TaeF+dH_kuBfuISjmU=ihV8?(u3C@IQL0;6_Ya*l?MRNlT}!UFQmy_vP1 zVhCOCfb#j3y2L)E_tm}}G_5S#L`u?C4T2=eV|Ide ztZ&IFSXeI0UEho3m3IxSu9HqPSlnZsyH9<#Uf6i`5^{q)I9#;m?k7gjy6gj3;c~E?zIY^^|I0MA`xU2c3&N3u-tB>z8UX{80NgK$n?GQ%k8UxvB-PJ; z9I;;fEx!E2BJ=^QFaAC{)T7dz$_+Tk-mhA|lZ-u>sku7&PKuH)C&2>1jMijM6B<)? z^3J71j4Nf}W^l;LY-_WVtr>e31=-fTw&oQwms7|!sBJ=)>`W2b9rtY9@!anTPIVOI z7GDh`M|T5ert^>8OLx(&gN5$9}=ZU?SK|kDr{1E-aWB?D|r98 zEv~cL?dNLNuVamlX=D^=0HvwFHogK@CqU;+WQ zQFt~v&e#NoOb9_I*&ga2i~lUA@Qs50N7VSu4%zzfdf+*XAUOe znPjNNSR@FncBo9+b1_Z}gWBV^GFKt51RbsgQ=Q7tE@f0#{bVgN+$Ie^>6sDEf?l#X z5s-e=Uq9}!0p64+S+9w+LQz;-a`Z8j>V5cHaYo&lmtZK(gnQGM;w zQh$bQ@^G|b(!k~TxVaXP3Bw?v5VeU%fV5~4p|t9qbLTs0F{?CRK~$0ec!UOe#g57q zh~wgbi+HLvL%?Lf6W@}zNrH_iV@DatA-q6wX#Q7h&aXZGE*6|ZNgtWEliSJs9FsL$ zgbHo}Iaf;xLysQ!rg}DH_!$T!_VDI1U~^RTCYdj{hc~eWLk7@y@yG-QG=YuevY2Pe zGM^l$owds=3(kw4p+yafr~#0&3Me`Q8qVV1Zt)B&f*dEK#4aF(b6_9F z0leX4=nxtGAB(gadezqFq6g(zJqG5B0~@l5!tw=<1_HWc$cwj;nD4xrVH|XMkIi5- znv+2N(}EO%fmzgq9bC{JAon}YTT?q&VNrMsfG!IgWe&MyAW!4>?$6;UU=wb4KEvymMqTrRwywH27e}?*^J8D z4V60#)XU=;gcigmUV3k#v~iGnu!Bmm$I{uTT^4^3w!GgHz0pJC;6uLy(7Erp6*$Vt zQhL}ENhTQClOQ83)RYhU3jz7P2c>x2WJ?7-OOx0vP$@y<@tW;}kZ4KEsq#k^}{xRx7sokNeBfROcs+w=DXi%C#$fQ__yCLFs zllylA?K-vKbOs-|IX_#NncH+F3w#%keAOe=Zf_hiE7A-5nVdTz@2+dMyEq`y>; z7l?a{K}OVbRbu|JquMXSn;!!o=!3yu8p(SO4}Pi&K{DPg3$1L zs#^H@hk5IGNf{bgA|wW?Ca6V#$L-$BX-a|XA2t&J`?Y8ooHw@y@k1|zD_XpNPy;P` z4Whm7^o-U=PeA?O~!p~ z0kDiN`W}e$)Q@UkO_jo(H}1zH-&2qiEr=3QK3)KP?+Lt&dc+#Q+r)B^%!4--!fvSv z8W3PjEr^jZL_ePIIHmn>5p1gvJx98}G=}~<*7vqv{GbIb<|EY5)cti`NbEi8A0wpB z(EtWg(;a)Vz0l^I27ht_JjXzG6|y$>qsrIH{22)Vf-*BE?Cj)L%5)Hf<>y~X=3puZy< zmC2nrC_JYJ1ef`skC_Oscc8yf2mgF@`!AWPB2eI#i<9*-{qO=NsaYlac+&fw*QU`hbMI_KjaV;MJjcvPa|t-#(+bRt16F=-o&` za64#%irxYE$n=6|s9Z@L!7KJQ*aW@hdvxHvN zrkHLtja;Rms`0HBCj}RsM#+dHZz?8KOa=UUMiPxbe0I`@g1~GM^xgF5Kk(>pc{kTh zj3j%(mm(hC9TBPNHBc)g;R`Px(YAJf@7#vGu~P^B|2e{U~1MPq2r{rO;peW zPvvsH4v;*V!ZUL8((Ae@;01vt0lHq?NDIiv%H#|pB75mE#Et7(0+%TyF~WnvfZ-OT z;F9D683FKQAzI%C$4)vr(m5`2W41d~TbmA68Oxg);(T%ifyEfSPyP8;O z3Pz(o8%)@6x)%w6k08yCs#HQhuoOyz~b7x#EQ$^6QH5w!#*>mK-P0%FV+rBjYz;%{^5?4cG! zt)sSL9->A_kiQhYfNx=6M!X`?nS~?pU}%2}B8k8^(S!WNMUzQ97mY$kscWAZ$hTvB zSKvF>ebKuVq;@BwmQ_z6uYF)6Kar54=7cx83x)HZ<FpBlRyKUsGWSUvOft zXM)&f6NXzLZOpL{G!o}Cfee4gKz`~$PLTOMS&GOQ_6D90rL@$vnr$CKoPz4@ASV!)N4AG*{ zcMIveP|JHb`p;Tyv3<0^0C!tkBD1=%-ltQi=#Xps{nKrcKiOZt4{j>Y$NgbD-&69q zWnz6)yluU~HW=x&^Rrsp9ilRh<+epjVujo9rBrXv*VGTmyGi7(&GWy{XFX5(_4K6u zh2r;5uW5WA@m2hO8gZIud*nv^u~2ggA)LeXS39+JG3`CiZt8VdP5gmd;`2N)p{L0e z;V}>9Ih!}1)86g0wtM_LdNS^yXUF@$bJm>~*9WSzsvexIpUCY@6Tb#g9g;df39#fw z6MU59X}|qpRmtN(W}AHDkc~nqyh2Ir7n#MQmojP$%iN-@E=#7!ZVWOaQ`TH=V@qZ3 zHFotFgxrd@e8;+;GS?c|TcV@#rc_uy&7wGA!yfulwB{-=ujwa$X8~m2yRQfxe+_%ph`1M4VWY4B&Z)l{Kl$x!YtgpwiThKnZ4w`}{ccD_uY4K!l!V`@T2>q5 z!nMVTe29fY=wWWoE))`GM`|Lbi~+O7`neN7yeI9;t?xwlLtyx9@iNWt3UPCE@!A$^ z`JlNPskL>X@eNx3*@rgntDR#Ub82DM1=d-~ zmp+p)PIZ2==aBfMdyaNgf*|D{(J%Tu(>VNiL39jJf=#lo0wo9~KctJl#|@ekda1wl z4AWj`+vxXMp_4aqg9w1*rZc@)A~&|AqSplCj|zdNv7&V-bq9wQ_RW$F7`qlWvn1V&_d=vul*i4ap<*aR z5tnhkq`zQMJWc`8;Qxf@5K=6%J^gukrm%K{45DIalwE9@zkp%#9oa}Xu1k}xow()q)<6bOal?S#;Jkoj`d!e;{_9@Sg&ug z8RB%G3}|-s-9l?VSTW!OJUE7j>Lrtv;#mFlzqn&Q_$(OH+gT?+jc)s9O%!I;3omVb z+;5l89}b|at7gLS03Ag1s|m9n8d#WtLqzyynLlYa+Vp#8%n~>j@5RbX?gtC0;l7Bp z_@I96$@3xHZL#n$X-eLTID8Q(Ra^IxXNMuNPlc%^6sEn;D3lCJO@B5clOsFHf{!#v z?x&=UB=mr|;Z2}AH^Y1Q6trf1FVl?mOG>wYP}~};07pa=cx*g?*5R;6)swEPHUMFz zJ{F*ipu3kQdk(Q%vW(j-ka2VCqI+S}B5%kdoU&MUlXVMS|BFSzvo4}U$&hMW0s}_U zAcCt_ZL}lB6<-wA!@mr{j5^s<*z6^#pFL1)003fL8E7z)uIQ{GQ;@9l&hgmX8=X!J z(a}3h0{Czgr~0bll5q9q4x)_+rHAe*93rl$Q_Pr8-*{+tXzv zqfUGsnuMfd$x71GZyt!v?i5g-axikrLj&dw;}268$kpF@U+V436p++M0!uruYm>=` zOyrVoy81fn1u1{|y?k8Jco>SP{pv3h@g(`SMrq@_MpcMP;4a zE*>ad&{ho!6Um;vRErbl1PSN7$*yLFh!oQg*o-yhosQRCtyXLRrakFLz$&-pnmJtVBpwd;?sT8 zlTWh@12lf#T9%Vgyh~GWmO=!BYho2<#?D^OsLyx1qmLKyD*<_h@ z?(8YPZ&7<&DTtf%|9Sz#6x8(n=Np=);{3sK%%s)j8= zJFn}OUV0S)_@uQf&*5m-c;StN-#h-B$f|iKe|uKrm{gS9G3;b@fkFMN(59_WI;AA< zZR3?cOHkntqP2#wpq_NK1clk|yphK8n>UJ*qru*x(8!t0$o*?^3_WP8-W>;#nJ`tD z$&Dmx*147p3qYF4{(a>fTA26a?DMLW8CWdifruS6H32q=IhxRub*4eVxA3}W0}$Ji z(c1zswoemVg{A_eRbBZb2(&mAkl+xstNO}?^~{{h(oJHBSc7MH1DsixkO?I#rQu<6*r*6S=aIaqRe79pEf z^Cy#grxnQoJS_@r%QVhfV+bC)o>}iGVzX-WSCH`6Q83327&QiqWu@6on2f$w{Wpw? zz`Xpd3`@nrN~pBpPFO-h`r4RwmtnaG0OnqM(<~I15^NF&m9vW%r+E_U(b~V$5pm(9`PNFv~#ts(m1Y@(IbNrcB zIy@Fn@^EsQK77aoJ6J>lBv9+}xg4YO77uGKnCX2NK9rbwpTTvz+Z~T8G#SIRm9;ym z1u6T`X*Ki2isGbVw7VSoXSBIWS1uPZ%?`JC(hmDFVV<#|{6Ym4KrKdy5|mx+kxJ&*WaO}6pGhZdz8I7rSCoQRDPB@LLpD#SZzT{bcv&wWbtf7O@qd|6Pd z+|!i^aX;wJ!}U!j_qjU2W4=tZl{2?ie**W6APPu~zWZV}8}=6g#Ws%UvIwVz3h7Gqgdv@hH3 zejoZn&-{15D0<`cr$s=&m}f5tLw=Jp{xt6&{gszmzCYuYY72LHIbhG$WyD+_V zq12&~E!$c?00|MEK?clLOE>hW4!#VIYO1O4)6R>o{=_KyQ&jaj~n z)s6C4i2E4yNOzXe2gQ-XtTU?+cN|Za0*?na-Lg#qsxSikkqdSJ;>i#nMn$g7eJf+* zl)|jT?eFQ$imQPFp`k;caT)8557T+GM#|ydcCPL0oKDWS#`8t>8BH`Xwh28?ER~We zdh*4roPACos;M0oYf%2!HQiy>6_;x76^J>m=4Nm0R{Uy4jRf&pg-*{_=jV_gbECEAFf$*i~KWgY>&s1zz&4W3(9#h487JTIk7WtEsI6^&)&8611*_Zr6xHZ zBu81ul|mwnY46m=1FHfXoCMRS$y`-@NvxW|=QwdqU zJTm8-AuW+zpE;L)XU?+jxCTX77ct` z(N*L+vqZsb4Ditzh-8t|eGwb!Ix#1GX=Ge^P&v@#HHM>-Rh3GDejCeu zjf!NLiTPxfDX`cNVNux5Shi?qDCSz5Pd!)LTupc3&9F@%RV&QuaL)yeSC_b#vYpUt zqAkowt;BMOc&upS=8Gm>H+j!TjxFiKV;#cOj2qXXe`S416Yhx#khgZgv*nNOr2E!S z>g@s`PGpGOEDkpWeM$3sYbd^@C>&7-66=%%6SIoGjpFXp_&Q2 znkCGDbgW7$Ubc!Ka+yBs^nQMHExW_bDQj(m58ne( z+JY2Jn9mzEHaB|tc^DsYr3XBR5KorqX=U|Zp?NTb0xeV$d$Ij!!lJe=#L(7TOnv!gBSyk>Kn%VG2XLw3P_`Ip)8bolF zg&v?`4w17ihGyr7MpW~u{gjTzlB||!H=e+RN7_Uf;GR9k#8c5P#WJ#yR&Ob~QFg$$ zRzNpp*ad)=n5h3{-61T8%rnl*BgpX5@4OytS3G^AWbe1xio2wQmyotWlM${NOKOt- zq-c4+P>t6z1?$;PrG=B5`m--v(SbNxw!Uk29qnDU#)&B{SSkS4*+)AJaue@`h1=22 zVe>}!aWwvG+BwBHrvRt3RZR)Nx6Me-N4UWbrV)lvZg!#CG_hOOG<}T0;hlNFiS(7zhB*~_bV0bF6w~tQ2b3t2kPZtll zJ}_nqAj$zXM)#Np9>|}NWa@;?rz+UZM1`*z!Di25*d&RNQo;F6J{v&#xsqxT5t6d-khDaFE5swX=Q~mSa_zQ7a^vSwI>O+Nq{&G z(Z4j%mL=u2sX)~;FyjVp-JS6yI!I0|-II{v(g{s2%<{)&co3d>8!t8MMy@a*P3~D9 z?C40!0+s=q#2!t?!JNqu`*KK)YTxD>)SjGPW+V1k17yk@=Z1r_6EaBz9uM+iIe0o5 zoe>mTd?q{IokX9tqaAL}iYkYgZ9sNzQ$8z${up;o%1E92a<;W{`LlOJ5+=*#e~544 zqbHj8ocbfnA<@TRhU&6X?DnL6s3Qqt4=B5cRUAF}MWq^?90ohZG58)_ek~GTDuRQK z<9R%OIh-8G^KFJv>=LaL(!)rij~WU@cW(DjIDR#cB&eU}Z}RlPog%}>CUmywK>sK6wNE6FF2 zsr%6LF69!4bYeYUH~ZElyZ#47*|80D9{=nd;Abo1UKhv8M=$TeJ9f3}AACsM8Wl5(yIH`6jJc%Y3f{pyo%s} zpQXFjf4#W4bDtkyvNzdfmljls<9J|oozvS=&y(RkD>eFjFqHL=JpsB5-u_zbzwU49 zpiIB#$v;UN*Y4bms3O@WL>0 z{K*rqXQRHcJEyOl+2_6V=TxBQ$7w?^R zP5v2N5P1ThsZsN5<{hnyz*VYIXSecVPiq_TLFgI@y+=P?Twc{ihdX>IDbO`Y5oW6X zeKS2B`5Omj+M1;@aVO^Y+ELh?DV(2ig8Ffc2YW;NiXUi->|(y$a9qsSOJLvxl_T8y z(%`_a{H@9NWjd0MSJ$r1$Or>l1+1U{aHs5anrK~lV6ji#^^n`w>nbAJKGfYf*C$#} za4`Tvq_&osSJHW2W+9BW5@5%SzZBm7WKN3xjyBol;J)M=r5NrM2nigdjT-OZrd;%+ z*qFPux;=fPhOxpH^><_bql4v^9)jPRfI6a43NP%%h}T~Ii&Jgn*}?dl-4i8S6MeD_URSZ>ev>E3b(K@7FDql`Z|t=%P9H^{gc z_hZFQ3IwMtsk*T}YR({=TbL+43AYvJuBxDyMBKL3-9>wkM>V5usHP=~Q69Soj9Y67 zd>v}isyY&CvMS)xbZlU0)UbBLzCvXUpDS!!(U3*gSW`c7LBF>-Fh2tNVSLoc9Q-fZ zSS&C-@2v%R-bJ-$0r2`(xztCLK{&Y#f@X16+w;Z7Hp`ri7jV;LeCr}j5>-_=fvQuu z)$VX5Tcdr{IIT+vse3xQ2#XGFGA%IKE)2AP3R&oJKKBr1#nRh&b7j(aEn6Rhs(2H9 zOxrk#k9f4z&3Rw-SjpdnqyFe1ypefLjop>}mo3i5pD8E%73Q1iEMsIy&ET3zF=)@g z_b`{PSuNMUX8ggg$lJ>C(W5i$`Z2VC@3w!h%R&7=PH(x(da(+)kYMo_0TiV(xk0VMB-Oe<<*k zN}6CLjz=xDmp=ec7n@_1RRX|4ot#=B-I*!-;vN~((Az@g4PXrPI7F(USFjpqtpqJn zjZKtSqpzl`82Q5_C}(k=Y(Wf_1am61#3iz3ZAXjH(Solav#cM}#(6p?A>|+*< zlnnc8!ybeNOOehobL-}Tz;2^gcZaYl5`sb5r$LqiQvSJ8s6}f~7fAGS%bo1P9XRsn zhzVp+(J=0v4gP6A!nhjNWDSD_uR>Jq{Bw+iAuw`+m9oSuy4KC~ynKsVf}N=CDFq;= z3TLgXSq+sU43a%-Gk?2?I?MxlQB5&H0?-gkO{cVL39Leuj(~d4%m55wM$#gHb%j~A zoDs~hl7qQsB=oYxI05g#kY^rmHsmePO|{iXpx*E~o3A$vSU@b)g3q4SoBk$G&ZuLz zz-6fK&?D~*DXMbU?(&johj4&kI4R5Xge>Ae^$C6ZgIw9yyO*#Q(dp@hcnuG_ zqFptgcF@bKip^=(VRl&=7w~sfPpUZju8o)V>7;S*;f;Qu&tFeeG1IXKv#1<{DOXba zmjn!W4@-QNpKb&VCZ1XZk}}qwDi6e-3?>a0C^HpWL0-*?UrPMmPfaqya~#c0!}-3c zPF4-+w$Kzf%|SciQ_S5-+{8?liLzFw;GyZZOzVxLX6R(2$RYcz%@x9_^0a3wO#R*4 zY5`TSbdyfH^gJM<+$#A)x1ydAm8ayKX`7RGo!tmXD$p7d`u=0z(XYYsg5xj5lCXmG zJcV7s8TJnPr?>zopxTnZ{|q_+`D50(f4kW`D91P79bIo8y{54m^y|O<;WMYSZ+zTX z(Qhw%6;Y~6Kr0MJKe>h*$7xpPxd6>hKwj=3msg zqjvV2W1!K*nc{i8rUeY&Ll~%#(!C45mq})SzviN$+vK~scARN6-FEW`IsoV4`qt=u zH!1=VP8hV`Hk#>^(rdkZmb;M3_`~oiz4jZM8zDsF+3}lt9ZhF9BLa;-itAi^#EfZ_ zj5hxGIX||u#5C$>>64FZryh5|O|_6RIaIf`GX8Yrp@;VMLdBlA39%;?QUB8T?>jt; zzrlNo(|f7p?&nCi&erWKlq7Qr=O1{+vv?vBkVgoo#oL6P#(=X>N$z8TINE-UnZlEyi0Lb4%zRaYwl#Nr+k&vNqSZ0 zuvceZ_0{#)!K7BykEY`@-{2g>^Ic>47wx{?@jKEza_&^@ktwVGJ@3{)1I-_a+9%UO zw%x}6N&c#NV(Joj`tAJYznHogu3yh(C68Yl{nagfaV}aZ`NOg2`)TG<>&3THptsls zO633eJQ#+(zfPUhY>|_GPnvP~wUwCt^_gSX;NYw^*Km2sT{3Hw`jJOk{UiUsA6>^% z7ZYE^WOA0IRx;xMzR5DL>r*?qB=X|fmh1MP4E*rNm^-o zuTCiaLZySCI#?e^yvyoQr7(}0r0HE{8fFvq86c|!cmM*d-vc@<57v*N>#Gy50D46b zV9lFEyctolpZ|#yQI8DP3u5XlBYlz58nTr#xdHN0HJkSGIN2(k;%$y{(xTj{0NZee z?WcK#fZNukH+HWtTFEZh|CB;b-+1SFTTyYzE=rcIvgoK6pt=~O`V%0&YN@&0r;fE0 z>tP@QKCMi#9*?{>NPlUDze89>#1O##f0<@`O!J`;Q>={r(Pd|wL5n@2@etEIfyb~D zoVv<1^Z?RQBn|cjswUG-_L#bM4)7qNIeyHH%`{v6A5VFdEK^LO8SXQ=gs0gu-E5y| zNWDf%XS%I$htHTs%4yY;R0S6O)FRXTDHx0Ml!rF{hBAJ=lwUFo z7%K`6o0hcQt+s1h3A-(SJc<<>F28Yo#pY3+y#veX)H0{*M=l-NMLH0gU`zf~eC#&u+c*36f?|$TVo?lAlCu%u2*~9q%Val|Du2 zp%AD4{C1|4t@MKOp(^rgif6m!ixj^)fWE<0zsW8(Iw(yu4;yq*5O1# zdxeB8Ftxpk{ammouPZS7gvZU!U#GEFY%!SC1q=T50&lVaaogHK$v zqECbM`a=*NG(C*XGC^#eE{?8NH1P zKNEE!pvdc+?dj#54TzAMZup)P^w&@gW>b4r z@LDM9TlYor(8apazNVKxQX(W8a;QgGxKG9It7f?+y7rrE=8Z@SJ!gy$V@EX5A$m1a z?H8(8uWKnZF6}vfO4)Ev6}PIspbYBU|3a7~sCr~* zj1Awl+Z^4{XmgQxuc2~bwt6;qvoj!QUN7L`MYXLD%O7s9D8ZEuigBHBw;$J??Oc?x z>wXY9epYH$ChkH+d-wVkS=or6D=Z`Yz?qv1zo{ZUy^DHVOQ7cZwca>+Fk&Vopcyco z9qxM4LJPV!F-6##1uKREv^-pl*=ZVBG4g>ZL<}>OdQKbBv_C9=uvK}`xbAg( zClaN^aeA~3*sc?EbbUOm^-r-$JZpLG?%mcTU%+T))Crnj zcU{MpNPe7c7ZzyyZ&qt=rL`;SEbHh60+IWIKZ~b>G&exk5A_Li0qvmxvj__Q#ar%y z!ilza;9VygB}56PTdaO+$Go$UOmP+L2dG|Usx*PM{$96u(}pTZ3um=$C$+$6VyPJY_j{ChLnNG@XLLbM4nM*r6~cvtH0=so?ic3-9^<>n7tIkvfN6whtl?(Tbp z@3C#JG{K%;r8jBE20+S@z2*?$%G8g$GkksC#QH-U3O#AEl`s2Nh{pR5Tdrz)6<;_w z^iIOa0!g7s&d@~vekog4;zom2dUUpjV|qcBAta*VD$`(fV`njv+WFV+eimM!z{LQO_x=M9=-J;9oQ_gaoy-#K+^-XAMJ|7;&N(&IK)3k(E=2QZIm#t_wjBFc}R z+#Y^f%e;gDrPcu?TbSlC5E~NRQJx4VTfv>^u9cJnsGoqafZIZdBNGtut0iK6*D2zt zL4r?6jMn3#wWDM8DQP>V9??xu{m|>owM7d!i!7oOY_giKOFtiN{Mf8MsNdpl{3XTM zKkYkVzmm)olPAs_DJkhU{aSkW*f<$C+tw~^lUPLTnmW|t85j#)|8YGemUFQwvF%5X z)L%=D$i7233yd8tAUgJMFF|*iXxdCX+LET;8E!@(#)YPN_S1D+Kx%$q?l@oOgPqjZ zZQ)FS>ccoq&i&4rG`iU8Lzdp@0isSbNS#ddd_zB>@ttS|LpXs?HxluG4dXv?&+x<1 zm(O=eDV>xKDgXFO-}m0NpGn2W2RPNPQ*Ya4nVVH_JA4M?-v?{^36abGXv8gbgeg90 z8Pu=%lO+A%;L*C6NDGJ^N zdq3-y#Xi&dUXSVq(bOBX-3Rs~JUVu_*T4fMyzW33<4#B>dj}CY^?nWHEwAt|#YU{b zZla<|I%sh$DZJ|5CrjMFqb(9IlpcZqv`xzocBp|b1wHb8QU?12QhU-Ke~@_V;M}Oj z{hEmTM+`rXJ_XctFa}I&qm##9i;4Kr1XEO8!*4zmQbMtSdJhW-%}jk0&>{ecH6i|) zLm9?^^sh4U)W4I!J^M*2*QwVj%v2~O8XzpWGO+$tu+m`t~rs)RJ_$j@C zJ7j$|x0cs3*#>D=UQO88XhuhDJ4x5%m zKYsnawPLsKTm65fB^R$VkHkBsmdGu&MR2LmgEr}J#%igY?J}`vpi7XlKO4V1QoLwf zwi_vM)?R*3SYw@uBVOoN9)C4lpyGSG`L5QIU4`N4T&JAqdWY-U zmriZi?*+Z7!e9Fo^Wj3M%MGcsYm?r(if;8r^td0tMIyO>qF$BiCLcO`q9fwNqu4)( zqUP@N+~P)O_d<#v*eCo27uSCCVVp?~a0&=M`TU#~2Vd7&cdkklXOi$&a#&a4^ssg4 zF87Rd>Pp`1TRjW==pi^&*%$~h+knZR5AtA$NN3{Sl@pSPh`WQ_WbKnI5B4C zt=LKO1Jg&jBw|&H#~av95{0_e1wT`Zw`B9yxZ12!o@x$Ar2Z8c!evMl56MP6Au(j< zC?U7blI_BH!q*Iy5P~(vu9Ar}7GK5ee;*ZmgD)d;+}?0oPeLO)Q+_2QdaZKbZ!x`! ztkG&PRS?>7x9429D!w(yO5#*Z$rye?UHF}q$jPhkY$Q|n2EZ_f+nHFC+Pl0GnjJ1A zW0`**y;2sE*CySZO+}_WJWpPm@;aF+GVOh)N@QFz?3u`Wzu5U}?@y&xje0#S#(H`1 zWSPc!R}|_ZA43bA`9GY#Q&l<}e(%{MOZ(5=i@B9sZp1<7^4{vLuop<~wE>azi%PlRsN*ype{Dd6T#=aeg|GH|vZ< zCRRcdkc{Dt8V?H|YYPa)N`|P*sV%5>dSCydrdY$VCrLaH%7zV0Za!K`js0}}>&?_p zM{-o{fc-4`yWC#U)Lqy5&@=`Zg!a%e^S&Rq8}|6O%_bLi=Sr5R#Op3!TmB|?|7Q&D)I+}!i~HYm^pF<$GBcS%cF8U;sm@=Ip3e04Z9A1RpzDJ;kaX2YqX>BhE2P`$_U>(LFx#X{JHf2 zys4JZGnrYh|VZJ4mPSSVJH!)2jUcO8qk|H-ceS zj#Yb%J3tsd1+<=@t!}kjXL?kG^ljjXbc@~O{c02o076F5soh02wO@+%bTbikRa+y5CBN3o2YO%ekiZ?I+j4%g@Wllxy*gGz^+0El3@6#?3T5ug?W! zB}l?>Cx}!yovm=>4^wlhdfZ`j)Hi8643-OXw_D)nGAVHNO$ys_LQ7-DV|8J;uR%Tb4b@ra6zM>eu(KH zeDXXszgD3h`)`EjG;$TS_#+H6_2skulGJJbuOVTU$^FlxCSdgSt#udw^z7;_25-D$ zC|vTW93E%nP~{!?g@q5fZAr-81Btqm`(JF8EEc4SHDw(Y`~8L&7zn)Nh~gOk*4A$# zRCM_Xf7fZZ;nJzc>FcOujZP4%RgfDIz}0O*yC+-NX0uwk7*8V5p7L~uHDy)T?jID1 zSuA*cFYq2iYq`9)ze1NEieI2Ww~px-9Ai7Ho{~~cTdU<$(WThY5w|U6mhBqEiHafO z6l+0xM*CI00rzaz=9aiKiDMJk3L~*HpMy#n;bMCQnYIU}ktPoMkb8hoc~3USmu!gt zL+MFtE4uT~YE zB`O{w9Ud%D6L)C6yp{PuO2E(RWm8qJ5g`_0ViZx~1tXMF1L?2Q5lRKa|3gOcTNjM} zQNc1_6EE6mXZq-hoL7rcto*i>E*~GH;*A-HqlmgAK5DxFdYd!Y<1S_Ysv-1h{ItFf zM5@}ds5&&O*S7P{MZw41Dy3x+UP8rIaMbz%kP&C;3r2H_{J1`*!vye-f;?!3XqGk>h}X2Obk^kT;Daq z3Vi07F|%kv7^;0+YQkw=0z5M;^XL+QHW!#Wp=a4^$|m-+-sgzkl% zS~rF8_#wCu03XRzy03NyzVfwLh-3jPp6rq?RKZqdc~}pITDCrZy1JT_zTpMa{~8iv z!`7UXYnZ?TZ`FM|0({aYoesME{kNbRKcIEkk4R_ha!ERKKterLP;M?$R)AQ&Ov4tr z5)&xzc~BpQZZSs%&x3jhwI}%+8pe&+3 z@CiOLnWy@Bkhg&=(dg)7FjiX=Un++8MtdwjN>#GSfQZ)~v zqE@zci!XjdsABPF+zN&9et{S&fxH32X+*^+q0V77uv5p+tm=It;mmeFGg#x7wgOx( z5n_IYWo7E(9$@<7b!Wc_Zl|T_AnNR^-c;I$SI!FCy|PT1uJ)P3Za$$X#|J-C@pU;t zmr1U>ID{WS9U(JP6R33oxHr=Rf|u*D)wnSr?gKhH^UGg915hE4@gS3~4nEDz%`ZfA>TET~J62;w6Hr3!sLf#?N(R#%{} zw_+X$9Nq~X2CSFezz+j;%NRO!)wqYdiTcB{^>sRBQk`r@RA|%tPJQNo)p*K@n|wz6 zEe^IgQg36D?n4NyjFEJH9;drOuZ9uCNI1OX>}H-T_B0GvS*>$Tgsb16Q}2oTbr0WN zty3Y=i{0|R>4sc4wb^%H*T({{AUamMD{5*+E%xUz&-*%q>iclfQsY|XA$A($HM~31 z>vh@TemeH%7oE1ESoI)|b~$OQSM<^kACy;51U&kOh@jxD%azmHRICFGQpw;xU}Oku zU~ff)N&n8tmjs*5f#*bo8K70PL~U+X?M2>yOZv$lAcPu@wM_7|8xs9TD!gZ*F)2!& zlP4Qx4BQ{!dPTYAC(ZcHA+)(~{M7QH&JS0^A~duT{s0LJlDM;(Dq|wTkAZ+L5n)I_ zlgU=Q2jzvS5!yM;_hNL8qj*272_r!KFCcb+d*;50@$Jv}c9RUbPLL3z7vR#y403I! zhK15Ki*r=RO%-YEFj;7ZwgIGHL}=ASD z8LUvMhW1Em7Bv(b!Rz()($AGz*Xo!io#h2H%c>pXs?_gP>l%Lv`3}%yt_=&Is49Kz zp#FsckzP%HaKJV7b}3;YN|&z5p^5a6v)G5#>U54?Iz#^Ul9ZENZkAO1N0!c#CZBDt z)~$T8zHUb6j!0|nDCQnRX8{CNpz3z&)exT#od8d z_2X6`SeohKE>(|tFuYi*hx9(yF4F0bdTPPR>C@K003PDm)nrw0b244&|UB8wOI$n1@5)46%Ez}7Vv2oj?UYbUmSNb;w%p&E|_c`{;CTI{dQm0!m2$x|cSxh@{9 zT)p_S@6I(9K(nZKNvZk;dJk}(sGIuOKI)^psaQ<)sl?{A499yt7uudW`lo-|m=3zX zVUm_z2b%+EU6f)65wU)U697uG$_F@l@~jz?HTm|e4I zNWK48uiY@D9p|zQ(zZci(kDu&^+6xkt*__7xMdvD>3*@3SJ!?fO9&*pBg4=`?2F2c zonax}M=rJ(Id{Dp?@r6ubozXE>R3-2R?H0%^Dc_>#>9m(Y_GI2tt_OiL!oQFCvD@A z%$XCE(%KE1BYdi6*3-y-RVS(CLS#%Mg>Cx`II;uw z_uM=W$_nXsd>>F}4)3RgX-p5YUAM@A=Rt;@_Y95?YoXqq zP`4{ZcDz=A+>zqiq~57c!@Ub3&Y|q*m*2xJy0-k8IJeUN zOr!wGlHvxco&SMe@4kei-Pyqu!WW3B1>&`9GU5AZ-MuddUd`{{G46>SkYfAvu`MDU zQ&E1y#q}+`$?kgm50Or}_5Hj@5DO_UNZ&r0SoCP+wcIv1{de$9sA79Hp`RnNKG2m1 zfXsPfA5t%?IOqlZ#WCMw>#N6-Cd}mYB)J~9_X%zgs3&YSI0J%StJ3LYV9P`spVd5C zvzKr@sFHc*dk7ogAL^aAAIhanJk3Cy`_-ij0I0Uu| z;j=y#Al)~5VLjGIE1Q8~?IpAZZm{?x{2!4CF+=+ke%F$ltHu3Fqf1|6*&v?7v@pE<3w zqJQAl2Z!(m-Eol6L$ndwxOk)|Q+B~nLw$|YKRD43($l)dgSO(rg{vk%j#z~ZtF0cm zG;&!jT_0ntpAU3?bst8&_(#u!Pec(tFKT%D59W06P%22D7CGyMCFgn=c@#mrGxcy< zX7K`XF7tQaI)i7=fDqmJ778fM`$ z8GY9*Z_jjK1R0fjhrI)>WQjk=mi_jGuh`a-A3mcuU6>@U;#kEgTbin$*zGT0agpjyNU=x4y%#&Jp&M$_p|@1(W& zEg+M%ZFBFV@3qGt$~CR|?x<}%@g*JiyIs-8@9Njq^5pQ4Ui+!3=eG*IFZ(`z_Ar`tJn-FElsP&VNXjCTBNauez9nI^Z`cp!Q?yE9bXG?mr? zA(%a6up4F%8VorcHFwTk)6T}ISa)X5SA=+~>nvQgFWxwcmnD12o z?l4pyr;9!j{>t}b+9vCAb=x4T0qH`Ub-||XUokQoe4PW8Qx0Y|C#MaHuO4D?0odQTN3?o18FBnV1eMm{QJc zF4#I;Coy*+VY;I<^bNcBZ#NZ0XnuXDt%{}B;8)o_*27l|_wDbYO=Bv*2=ozaiYhzm zP2J!5>?!cB`(hCVgE|JPD&P8gQ%8O{IME^ked2I&@5M08lNZQXTDIzx_~PfG#ccJ@ zE{M-TP^&7-wub63&9Mut)W6xGVdC@Lt|H=L0)IS2T?XWC zc`H@%=5uj#Or9;#>{2pSF>YSmZPUI--J?1*yCI;*p^VXa`N7gzLH-qsBc4z9zKu7e z-tHM}knlCa!~DZDN;iZjqEh;u1J{Dw@ljP-iF3|aSD}~FQk;Cxrb_+$h`SYyUt4XO ziSLYo;`6QUKRjw`Ad^rxFBLT;_d9Q11Gt+hwG>u$I^$cKc^d}0K$HfEsifbXTo7sh z>1-H52JqV29=GMe+EU8GV9&N`pvEb>b5J$ky=ErP=cHsA$IdnYZA-eG_1GD|hE}G1 zQ_a6$<+*DWbCw)#YvvP>9rr@ai;O3nTp9cg;DJsFFGohB2ZcmFnUOS>=OX zpl1J+87k6SSOvS=LQkxF@G8lTX)2OWjEq&6CUe)5T#Wdp@oqclR{W3sUnalGd)r~| zC67=C7N%XE4VgJXQcx!)pZt#Rf^MrXLO%OkOZd=0#Y<)W+(V|H@ZXNF_j(?unAHT( z`LaVJ=63R#zz<99m;pi7mVPPnmBqP7$2}0C&V>O(#A7oQ=4KbLN`g; z_yk`8mCT%Q>RWuIdt88@fkD=JNYA9OU&SMXyR6EJ^83?45Y@Qt$~XObSTwFic|^CP zd?QKLzaE?T$IWDgubcqx!V!#M2QoiRyKSgdztjrZ*G@IT6CdIwK{jUXKq}Ls4t9ds zv+Z*c!rw?+>f92Z=-y}W3~zRVx4E8*XuUz#Sz|+qG)ivOkfDYdEQ7ot z$5AzasNNum)g66}9fS9f^Vu7AZERL{lh*27yt6}%Nh!Fxq<~`ayBxlWkb;>a%n$xs zrvbk+k>rkT9>BgW+v5sGu61aPWN)xsh{)QTIic1Db0dXULrF^BS}iqaydl_gMj;&S zfuJmVR^^Ywc46p~*Qh3kGfiA0WZW9M3gZ6P<^pU2SK5efJT%>1AfP#`v0)I$(C7ll zWe?Q^WU^TMASyU$q@(q4VdFbfjZ#a5_Xi3Q=C1hBgX13U6lwRQ4m~?KP3|Ky{&G$qFGgP}#wwxtjE#}&LXeq=U_)$WJn3@MeJjpM;2R|o( zRFOry70DP-@&a;=g7{Z^lw1XyAg<@_@_A2zPG;<3Y3>+aLd|D+zrVu0YUPv*K!yE4 zk=SyQ43f#y-sA`B7({*%gjrG)Ha4JM@lS!McBkAUO8E-w1q#16`+O%UZ8?GBcB>e% zmA?~F)inJVE2lK~pp5sRLrUVmv7x4Hxr_$w(V}A+S&kT81{!&_L}BqNu#<^eLi=nx zg4$k&2%%)NI@LS*sAZy(E?pUI1J{*6Xsht`XwY@Z;W;#FtqPTBb7;(2^^=5TQ45om zEMVTKhUqd9znMr+VJ>4iajptkN>L!O6M(_JNsI=sMl6yA)CmnHF3^Fqf zKhvW|L8smDfUmGoub9b|d-#xKKI}Zd5}MN1X;+(sx^my$A9!rN1kqaudE?@7Ndle$ zpvL&9rxb;cq(D10K79gx`2Mz0z%ifUlg{a&StDK=>*z1OGdxZ)Y60_T-1sf&z{C+^ z^Jm0AYcwz%B@-xnXBB%gk-v#Mf8IaxLCYTr1hw!{OLQeWw&AicF3EcLs(@|TOhHB< z*Z4@pu=h|EYED8xmZp$g(53)HNe%2K557i06%x1D10nD0)!srgWxw}i>9W-(gX^&tKO#U>78m&q(lE8m-op*0mrWWOtX2!2oA?7oUSG18+#o#D_N^b9k z7Lw9cszt9Fgu4La2;kUtc@L)pElmAAs>_lE3WW>4Eqn!LIqHQ#fkZzSvxuDLBfm)k zR{&d5z&W=$3Mcr;6`_iyJ5H`#zK2zADkeMdX6vs&LA_|Lf59O8*GR4;gR2Fn zFCb_5@HHVqmyY};L|D>_f0E#p#l=%O7nB*kmFf8Sb_WYTa0mstMnV=q!HfksbrN|@ zWB>SlH9FmCWC4$4DLMFOpr|H0JY&GkN0RjIqSvWF6O{h`gw?snKwxq7QIlzx$QRsg zmC4$2+Q^ozy#27Ui--LpDQEq{`UU20Fc4%aJ$Ez`^^UEapQHSWg``N(yJ6HE|E51A zB+GaUnFOm-MAU1;=861lU3FRI+U~-ZJ+WQ#e~Ws@4%Jf|*qfmEj&C|M2!A0&)*2v= zw*=^k&|zX#TLAJet*NUoMAILX8-;4&SEA&~t175;0r7=tckIsD=W9HV64WOmt8dr( zH++R@07^tbO;rKk^40!RubfDZX9r)hqtwp@o0iB4+Z5Cv=8j;A!eT1zC-8Cu_k{7r#>iNqQ1 ztyySS&lMs-zuo4ATATU`R{2PsR2)zv4s4@pM>N@*Ldd5Fe-RjY>E4fbynlS(eWr+S zFsu}NNW~K1A^QnHH5*z$+|2Ny$Ul5|$~#0U2{lPeTode!cm^WXFL@C^~BvKwm zLDusXPN0z#pvsTximy=@(m%1sC?21qpFG+Psz7Tz-i#hvUqW*WnCtXgM$5aX1|GGj zA#{zbR)qL7h+q+`Q`nwnLnxB5s<^eeB0GKsSWCE$(!byvX^K+E?oZDI4KM6n`s7QR zz3llDSwd%c0QX{YQi8j0|CZc#1t5o3_qYN;-DN0Eh?&q%udJB;3k^4;9q949J4LU7 zSi-I??j`#89ekJmz8jJ5jw1>3<|UWS1`)pn_dvCf_uZZPQTMY>inA|@^|J0mV8_1; z%}=YKCX6he(N7E}r`Nkl5_kk@2LV{G)@GSoNpIu>22XBd8b!D!T@CK|qpBs@|ztRy=}QYzykZIx<= zvyi_@{I^9tAKcD?{fg4&SVtC7k}A{+QH69(Ty|=-{L-j>huEy@sm~aPVuIS7sPRTZ z{o4xvNk=~HS0T}m%Y*QUZmV^XsNxIc(s%Wpc@N_DntntFOOg+$>{cfURgy-P%F;pa zrb*j^8)SThvy$1l>4)!k^|$=C7sot`x!Z4Nu>Q#)?X_^YDC@;?blaPYZLg}z-uWoU zH1E8d3unZUo3Ei3Dc5a9pos<4>0VIJ5tNv%kh)!M>1RK(=q%V*Lbh|H0C>NMi2jQD z-o1mvQTh$PP`Xuk=b!&sF>Ds6bkWshpEbl?eYFrunUsx@DN75nTR+_TbF(5yqBx+o zYOdFutT8B|{?-~4>Vj_XX&@mk{Sv@4eV(oekq2xMx&p+S1itfC2<2$UC!HIv`%T@S zsc!U@yy<)NlMU~=0j#k?dF8)O5xnjMbRBT&N;DiEv_{$<*P>JEBlm;%u)`P8ZeItH z^104=336~!dtaM0xvsnSf$Dnn=qvz2VwzE^kep`)Cq4LzFF1>DysAUb9#J{)3MRHh zBXXADyHwO~Yo{eySp3WGPO+J(I5pEyIiuXmm-h*uxkOByyB1RfHzKK$*jJ}%AM;75 zc>!{<3i=!puu4SUwS0H?R9~x;YAwUpj55f#LdaID_HE1reI5-aGtMniD9V1I3yuwt zP|_!X35cpt@!_HOJvF%Mqh}}7SCbIaXWqA7f0WBlc_)ecQVO1?pC+uB)#N^N%l@#j z8pbU{+}-+Zb`p79&~Yx!?+299c zb3)om^dM$Gh|RvaKv!B_Mu#pV#)(J?8n!qm{myeY_&{3sME$BZa-4)5h*O9;E9UqwJ=?^zO(THo?kOF4%;XQ~6(sFj`cRCx+*H`)2=53o>?wN$DY+7&IZ&SPH`6WDF-+gQ5 zFPm^g!mn;At0Gi)hb^Tz#4kxMgK8Xde(>n3uR($D^4z6YTmwa9L?x@t2t7+;W>Nt0!@e}6yxA#w{Htsy~v`hAB_c{5e*@P_Y9Q~5g5Pi+m84(y# zlDi7cb}&fDs^UL+WrAImU93ezy=PRjGiC>_xmQw8{5FAvcE04cj=PM>pAvHJ;U3kxS=$G&JZ9JG4@kg0mi^*>J9S1O+P9<4y{KKNYvJZYvTbBhvl{8Z|Gb zF1dSDeHHNO0N#2Hnj};&_1l+j>f?Tj`{hVx)u0vT-Y8FStgR&<>M3bHBF_{EIR&wE zR#Ulctm(;1sr{B9-=}DcjXCB6FLIvQ}~lHA{*abJ6&ye@7{Ch z?(RJYGi?Kdk6gJMxbIk(?VkNfr(P@FyW@EELaaD>s_g_I(mcoDNpDZ(i8iV6Mc%h& z#V2j%51|*0u&H9azf960RZW>wf@Bi_WIr;|5-=BNmHuFf0-8NnGn<{iTz|dp`+`+7}LESszDl9*8ef@-)5~ z8y{p+X?)zcE_p!71eZ$Qd(Es%<2TRz`reM1>nGIugDVby1oHHlxzBpeE8U_@(NFwY zcSQJTDQZrqLiXab9_wEbPtER_Z+^4EO}it)6rbuC%ZZfXCaL!~_Yifl+l2}XXKdTV=>n|DvX?n=Z}{K@o-%4PALO3+Iw)12gsObscO3VEGD z+a4H4o789JLQL?f(~D>qRnI!Ik;d-uIJ`Ea)UQG_lvI8!w*Gv*9{+3bq3zhvs%=>s zLqSIf2W*(7TY|GLYvUej7i(G=hR!a$*-|gcY-^$?eD~=2Qjt|{cXeS zL;ydaZF{KN*;W_h%`b9xW`t^75wAa(xIJlY#9d1@9yvT|hMpEeweAKLMq{sr4^PW0 zuSMxHqw;E;oH#U;Xxu!x5*9c0D_BwXLMiP}E#a>iy7kARdm0<0NNNPGA1gwg3il(d zv7noa7-hOYG-I=`75x>+l@+DD4hHsxLp5upRhYgt}YRZ(sf(YumUK(q}IZOZ0JNWA28HIfd~flU9$Z4UWdzCZ5f;{HV~gvjf!?7C$C%Q^Ih3MLL((DFapi z8F6Y+8>uWNZ(Et)wQ(U^J58fUxmd`JUvVb1Ech#5Eb2Qw=WP3D)o`1?DrkDJ zgYfw_9Qjg;iudu@-S_q)5gLq&Z}3(9n+LQad6FhFUK4CNz;*3nWlZoL-I&StE$os( zx2#;f-7rR6i1sVrv#+%Z$J`ykt5_$t*Y$r9Jm+LeP7?7r;ZG3MLHWze%S|1GVS#xj zU5KFk0AX3?rotu8P-*P(OixL=!>Yb`+r44Js5s^TWpB^nL5+%&QmEGNC@is|8aLG6 zqk7dYWL)b_YmaMe{Mpoy)VI|-Ss?c);pnnBXE5m?U0Gd3Z;BBI9`2z4 z^YuvIz-Q!IDOm;sj>YC920EA6^*BBi{_ltOlb=rW0gxhitnj+tQ?8H zuS56JAjpcvXeiRCR&Hu_gFn*GP ziK&vPbw+es^A};^U|xAwQ~$Q&=G@au0QFvhB4)TlF*v|5OIi-GxJfrSs2HmAo>XbG zg3diuXOKYwIF~r96a0haP-r3slGI~~WQKHT?SGJu>0(LdIadeNNa{cz}NxR zy`j1vF+E$#IM9s;6Kp2|n=Ed;p;~ZFA7>uRX{CP*n_buc3eZy{QvI}^axK2u zx0?uofhn}NT3OcyiB0;>am+9b{N$ivB`1n$@_k$1 zS(yrf=KRI{!*CGl{Rq!~;a8!#FtqcZtD6;xvB+-<9WNYQ*%NLVm)v7AJh?6lAM_-o z@~6C+22B~vJbm4ulMUSvrv#t-e9=G%fPT9{JuGwexNwd&e^TE^;ppdm1DK|&G=9yF zk;sWlTf(#<2i8#VSlEtwUog~eI{(4Ok_-&li5hsiRdVK}M}Zw>W9mSS!c|P^rEe!b2Ev!j)$kYp+Sw8dhQ7p}HwyXL|2g2ok&18M zhi)Na(>}I&T%$=(KhZJw9CU<#(^{)vCT@z|g1(rCKJl#f+HC!i-Sh7YKzQMY!L2V; zc4?;Ve|QTpo>IL-ra|~a{ zwN_T0S8<%&MZRHu_9jSVrz+AMc~I>v(g+Y~hKsa(YI3rjlsVLp#oNIg5yr^L+VQLo z`K<1oh`1icoaR-OBQyluL?JH$z*XNJV@>SpBIf}Fzp9BX0;)#T(=ae{&A z*mmr35l*8+d$N5KxWmJ{4+~ojCW7IImNjKP0A&nLV;TTVNwT6LJ<%>aGDUjr4IZ*62MO-dlFuGtkVb&_?s( z`I;0LlTD>ml3e{Ffh@<$-ODrRF$Q3lUdQOi9?6bDf1Ex2z+MvD+>}Qc7fS0Z%?u0V zu41_Z)@o#BycH`0d!g@{8pQ1#5pXWL}7 z_qhz0{Tw_i8(LMdy`h|tR4n?D-=EU?bb}4AR2gLKa^pD6{$zBGrlcx<#4EV89mCE{ z=0lIS%I>X8@vgn|)IC2JGo59jzkZ4dPhs(Vvo{dMS;^(RqYEy3%pTqfrai9Ve*D!m z9)rX-C|HxY<`GCD8|c6X%RxkM{{5w0n#61%xje(W!OzuHS+5C5B5_F`nwW;HlY+uX ztRLiVpSq>u6a9u)c?Ncj7waPm>UVM7tNgra8EEPY_Z*V9&Na*zm*RtW{;J7{ zuFANUSGZo75zW69a{l>R9nDAH7BLW+KIYk-s?m@@PJ2Kf9)Fy2=L(Ghbqw0Ew@%jE zI~fq*3C9b$X@k68l4cJj`&f^D%g}@Xx{5ZcZ$g}bgtue0Ec$Z)IaV6+ry#Mv4 z*DYR(*cTc7Z})5t;do-8vHm+%`mz$`O7hPk}P2Gxv(8)H7T|6^uSjaVSZ6p z_t-x@oXvY7hWZ;kHo)+_R53}bP_vwUSI?l@GRIhh7e2C~ZmmJe@=PwN(Au-9I3KuA zpt5hFGkE{&kL02NAv8H+Z}ZU_fDy#C8G4EW>F<5(^?;YeeG5l3$g@oYCP zZyNmcj5>zKZF4GNq0RQiUFzHcvClL(q*E$)d0oLSSSDye2xS65d-FI^+2yN6n)pEw zs}&k(`r*=sp32M|qXv)@?a|&95%D)XPG376{ru8i4z)^FNb>;V?H+naIdasqS^!QD zqQCU6l(E%U?L-6Y!cSvP?{-=514sjCyBh^24ggK2>3>%N3QpPZqo$hYrt<;$4xeqj z=Cd89Z#?iT z{&dBScijC3bpD}qec_%DD95Wvk5hL1H=FVB5?a5TLze7v90~m}6N((rzz?!xB)mAH z*T?9`&jlF{Cn4P&hFWa1B0lF`V>U2OC9r|q+6 z&eZ*y5hLV#tG=rpE89JC4w;@EZGM#mQBd0}C2JXE(V>@A!>a%q3( zw8z_vw;ne2Tv}32u?SbUzeDw#^gD#rUSB4+Cf!#1A{U5pBC(`>v zjMLjbla&-t+%I8G?L$8Q2E6Un0*wXePB9NA38C>p9g;b+lZ3X*Ly|l!4Jn|8RerK4 z(4?q--ZXGMj*4zuMAoQ%I`LbuKK$sULAV^`8V6unvX>zcv_8T338pz*gcp*CC(Bj(#g{^4h^8~d1PWkI;9mHM4xjP;7qRUFK*zF zTfu?+%)TF*&)K$4=*=dBTq-7mB1zw(=kG?$6bwJOe(!c?1MQ^gnJsxhTN=2!(%YLB zRx};m)D3#|&2v)|(2))fu#5IVnHqi>UwZfw}}BN)@+= zo_AvP%!zWyEMxL2TgG8v(7{CD=P+}5Var1rx!z)LNfhMY;-j6tycnT|$0X;75PcF2 zJ;sg>e4;aLX%-nVIRWF|9N6e>s^$gY&Za!1qUUxFfUc2MXOM~ktc>+A#e-UYO)#)` zP$rEI-ZI$M@@jH|1fmGJqmLdt0KkrDea|4?M;0%Vrs4k`9|XgMdn~NzT{;=WqXz`+ zih`bMg(&kl<{n5U^Ml3?NHSV8fmD*@ab%BA(0E`YXM=0znAT>pn7iXX+(9^#l=jp3T;v^u zURMz3NYITWVHTD75P9$5<(s@R&c&2fUZO+*ZO%xdv5=Y2%tBslgjkoDnbqSXX0l>P zh6-nRiTtb+<>%8_=Ra>i?h4|?J%AQwLz(5+a+b1!VpSsh^~v2@eqOxaO`&gydZ$b^ zlF|p0<<(zF39yJ4+j`HgB=a~axphB}0k~lxQHWvj_!$0Cn7ZJKE|x7*Ohgk3%b^J) zv+>t}K{OW6T{<*-gE?4W{Q#dBq^P=%ardaDZEMy~9X<=qyOnZ5SMoFgmQkAnO=dxV z4e0pT@#+M5NmYBq8p&4s*Z{-ak$Sz~^w zPefVkR`9XYCy#yo(|qhhU?4+f+Y4wUB$>`b`AOfLheio5=r%x33wUvuj4O9}Kthhf zL+DJRwaJLZDGz9jf54p8ULuwA&PyA9_4Um^N;+%2NK*y*7^Uj{pOHcys~lWu|NaaC zk|@Y~Y!CGTsJ?gk-8Xe1hW|+ymSvz^oPwtFGY3hVpN z?|A5yF;+$hJ%hI zO>4DFb}g5lL>ZYHo5jZxTGMT>`rkM|nfu_>a!Xur**p$U+}#s+qx#DjIqSz;+teeQ zbe^S=HHu1(%vU~6S!mhsX{Fg?og#sp$n@SssnwqcZ?h$&P z{<-nM-Bw!${et_(^Y7Z0g|Ah;f7qhJ=P=_}?icJn)95-~bpg5_^N6)L=agsZf9X+V z$Ly)FPaBUtq>xR!BTmeJxMy&)M?v%oNqCTU`d~?qW$&`=QS!1RxnSysm_R4s+GK5B5avyIxNgoVL6PB)CkBevJk+(3m--W)Z<`k^@8sU= zr0lo-<+HZ4e03xfiJ3@LQ+J(f&D?pO(y!D(S~Zm^9f0Q;1HoI?M$~s+c>aE(0RL*# zuEEuFL2%~QcZwZ$YfjD~KX~tSt?%YFNy2+F*Qdw1f(86NR`g?aDbnrz-IASKY>lFZ z$%x)%!>ucG7_V4YHpAD~ef-sqs2A;p@mWySJ?*$F=-jUCMTR z`cv|n(Q;&$gWjQThp7;MkkZI>$G~YjEk>5ZS~lo%muT8>CprJ2`lhYZE4J0T)2qrc zj_{V*z10W0m&4Ajz>QwKj*`7CaJ(3rf9GY+k}P<|#`5EFZOhBUgZbpAOisGNxd9v9 zO+Wh$m3ERS+?_P>xSc-c%Va`fO0$0rILwV?qO5N0>I7~6lMfo$`tGx{EnGmFRDrwZC%m_^6b?Qcidq14+y8wi zex@97L$YJ*_tE8uy3y><`pCkOPje3Z53hVHW#TsjPW6ig+M`^;%WNQeZlS;sSC3z@ z^QkpDtA{0pvOfj^l>!9{69MZW&&5jpUK-p(Bg&q;_r4tN27zL;mGMV)eYaLtx1Aw} z5vJ(Ud*6VC{}N%)bJ@@XHeHVlpVg`>2FoyYr5Q%Q1sw=ID^-nJ(=Idr=3EnpKtC2u zF(|(_B7ZzSQjYp=zXnBS%UW&M;!9dF)P-{N;%x<{}T87!Fsz8KOg_dhS1eD z4!80Y7U$F5BycmFA)&*2EVI#x5p#q)08-iZMl|No~(&Mr|@MUchACsN`G}0nPni1husX!+_8{~{sx)-j21`(?(~Uo>^CXILOa4I@vV#EJXQrg)C` zr(fHh%f+1z3AC(OYSM79NP8woT#)&#U268t`CzzyMLD@-lruA}o;TK>SzAH}mh^s` zr_-H9B@wKaYi}C;BV$Zsk;0-%UKjf-!FuVp2}g8geONcaO#hzVgKVt;huzZv%cl~^ zXc zS@pEgtmfVumhsUh5d0ihbc_@v4h1%(6gM{P*czHiq`NxB(p?ZSAcgqv;<5^b|2(y{ z)6#v)Y7{4>5dtt%==t-`JS|c%dO4YU4rOi70IF*vn{eLuMDOFbB}-RX#F{B2MA2OH zli5v$UzTGMt&~)k&icFF+cK~Yp!6D68cuajrSICmxz<4D*zM2L)lq=nDj&9@Q$}oX zT^-jOZYU{lo7*i@v(ejBfkB%|UIRYRRoVt(j%}F#o&Czq-+59;6`X*DE{G2^h8v|| zBK9s47HgOcKbp-}QSE{zRbvblKpYn;)j2~7h?T3o)*|QqIuC1+HqzJL4vKsZRUG<<>PhlP|rac^}WmDaz3ODVWh8Iy% z?K^$>)8tZh50Z2L^XQsmKujBI%T?e(o%6yu9^JkLDfW2ju>Ef@?*3OP-MT0-;si8- zSYk61$Lo1z2xv%a7?*P~fe%^D%!Zkl$L+mXiRbDMNgP2zi z2df{n$;&$fA+O8g6z{1O)ewiR^mg+Mj;Oi9?y+UP?PE%o3`0}{`N@99C(G9i+%OFw ztFr^n@%51ZnYajnESNbQ!Yn7i>4Mo&Fk%T__;@N36 zOqBV}mm6!+ZF$7DfrhU=0Qva8PvKGaSXenqEbuikqX1#k4mxS9d5TsNFSz`C^CLEE zU)BXa#?q0!tww^ZtK~ImY8oDyAtYvP028}^q2T3S4KEr4l2xgpWq!m2M%iO-Ig}bb zy74ufZi((&CuZ^mZ9PIMzRnH7?pTvtq!}StBilmdh%JoBOD|oTlzj2er4a!>hDPPV z*1N6sVnwsg(RkWIL6m~YYYDoNwi)FY|Dn#!Q{fVAXy1=K3o?MsaF(D&J2Lp0vLV`s zkA(yQl)8p7=V!DxO%2DBC#k6Ce$}?KWD@<@8Nz*gK5=ESiHt_;SfIZ;dnxB(9Wz zz+JP*2q0Gq6}b#D93M8OVUCwcNc^iH6%gA)f)sN_O9I=&OG9}DOn|aE%cNm_2}}oz z1p7b3Hyli>J~10XFc60Lw;%dC2PzmO3>!i113fP}n{zG_z_up+rNbA@gr(%_q*Q&) zWPorPlBO0(hHkz7x>Urxff;5wq}@Zxo)q_F&zjG$Z0r=abVyZvm<%N{J8(G~`KMWW zqi5MipD%%sv}6&P{~<4794|AM1*QW28zqZ01u#QoNS^>JN&z2{e5<~jB!d)|6;Aue zpb?H9@3sW73(GGTY*SnUN-63K1MVa+nE(!^=xl?KDy3N|_eQwy32RLnn3ANtsiM2S zeM_zodr(fv)owkiegm(((Bc)-RIIEux9JtVWh`WQsPNQ#bP*so2{I<+pj*-XI1I<) z$e{<+=8{=?*Q>>)lBy+=UVE|-0Ik{t7**qkB@G+@&XGM@kJ{gmXPW8!G`#YCgmrXS zhE8KPUqs1ASbxw5LQ_lz$sonw3liQSQVz)HAy2m&3v78Pdeh7f4-zwc3%^ulX6b{K zJO_g?8E#_Mxct;qm^FABrDlgOVrN{)#ri0I2dK#v^zart+#^sXwqWwT!Ykb%erUl4 zM-buR6ez&^zKY?njCGx+3P^DxHGUJL)BmbV-_*j91#0FpFXwJa&i z(I1MReUTWA6tuhxkc&VR31U(rGo4yx`FvOnoVqIJb2V?m6tW1=-^S=I0wCpBo+AK4 zrQmS^NRRJDQ4+~{ux8N8gLBeJ-%m4o898-^CBBMF0Hq<45>Ng4p8Tj-*>f!zxJt1Qnb)Tuqo*<~!?@H6-ye|yPQflq ze4{Sq!`t5Il9d!1d6@ShO0!+uKPcI7l{C@$RtW`BQBb%`9|3({H06jGHf9rr876z> z3~Sh~YtXWh&eZ5bfI+ty)O{?L0z%pjD-nRB`01_@z+)NQQ*D-CWK2!Bw@>?!ny}gH z7>rn8i07%O`3OKKiA5r*uFs=^Yem97%0KM(rtKvblg{D3MUX)ZNQ2p=rKSGrbAOac zqZwAA*x#xSFq6zK#uY)mScGxmXR&{tqxT2&>@z6JDC?T_rpD%ruB7U2!{IBu{z_yVk2dm3NlLN z9OywP1GtKO7sz<&bVb?an1!JQn2TD9#k<27>F&5o-vtbsiS8*FW3sj2ZgF5%THkqV zpVc-D+ge+ctTPi#qo2({g{0_@S?&bMmfz2ql!GNGUR+fvKEvp22dwU6l3$y~(;Tyj z*}A{S4N;I0E{WSaZiZ^f1vT>QETh(X7&R*xHq6;}rvb#mK<{2&H|kuA8xpat0VAv<+c?ML!x(19((lGEsxiF?yo^5>)@cC9 zRuNZXNPpIV7qm$ebt=&9Z2e8MbB`l3cSzz4+@}AqLCS>|KHKi@im_#q3KUwZv>T_-L1b_7G4s@w zZjJ2TyF$O~KN-Hv$0|pEe$!k2fYNS(APgIMn{XZul^eUr@3^d`t@dI?9`;<`*mcr9 z?$&<-Di}x$Ss8nDe6(!Xxw4Lh6e{EyrK{w080%?3$f|6$|Vd^%m#l> zB04DA_SXXVj??Lc=8U3kmx6?f1GDz2&c>8v&_aP;lEJjhNxU_a!M1YnM@(*yF4{IUDX{ z0c5%SE2_2os*}r~kV&q)=AT}^{Aps>z;r#A`D<8*;&t_f*hBu`yMiJkTWiGg-WYvR z+wqz%n;{uvy6ibFwteJgi^r1#V{a1Jl%3uWMm(Fm2>Em*15Df@3abqNv}AEu?DO?v z9YMJAj1Xp%-S7Mxy68JH6h3~rDfw3QDZxBr3Kg=g@Y ze;0j8*~w)#$f(lt$2iqTvp ziqZS25}hRDumkfSwnse)dEAdJi+ilD>J*7Ki4@t!)mDx#4Qp8@%efDIswK&Jo0Pek zUH>=D?uTk-B@0IHQbiS&mAzL)fITD9^7=+k^hXTxS?xphUUSvqEAFHw2kpnYzv>+{ zxJ;k*e1x07D_5LlHSU4w#V~R8+jz|A{UK}LjgtM7-15iH^wAth7Jt*_yfu<7H5>!} zI>%DF*FMQ)x@<_#yX9&w6{<-EoF2TC7r&9Lblxu+VL0HUG*cVY4qPG zH{(B|rJ5C;(!Y!9nlFYK58jOS@;6>?_F5Z>x#=HElIj1_G3Z9E*uOj_V>9~T5I+;J zToRBxjMDi{LegFs2a#acOc4vZPNu&&Qf%TRRh-cKrtO5AuNqY`!(V$J3EvN$S2<-= z1h003#IQ$fm-~%fPE(_S_lq$7$*%^SK~MnD#~d?*aa5y3IkDyI7u@S81dMC;_gOuo zTi(?EVX6gSK@@;ird?f{KWWgtdxj}2yIcX|{ue7_FRkHKf@L%)Y`=;uFQ*9B@4xJ^ z`NjLa3Atn{2Oaww#y;w4@`w1LYySMvqo0y->VhT1M*bLshGBkh6QdlA9(`~4d0Zs^ z;OSb;gZm&Prg)7;`YYb|Wk2rOoXtRXWK84ZxyJOE-?_&-pFybh4JMMCQ9?fcx0AcH z(DOI~fr1LWff&RKeq#9MyPP;v#fy{p^m)>o62Cbnhzboa{*%~b2>_Z5c|4DgAtbds zMBl5Fk|zE=C)AT69RIVu@f7a&)+j;j;*cf(h5P-=`lP_6fznX7M^~w7{03!V?()~> znp|ED7d=fprHy{k*}0l4bB*4zlpWX3D_XWY=fy&LWYVK;`Sxa|?*2u1AMNe8#ziYm z2e_2={j?UjiKBJeVk z7m|iP%6s>vCaLN7kXTD!x$EBRvKRkVVc6)eu{pJ|X)aSAi1N>v;HqwZX8%O_mep(` zcB{WIym_F`;X&0m^F@jBr1b>m^q!FIK=J75SDa}a4`R!~;_=&-mXh%HiFCS{5gzsBMZ{m{^b&PR z|Gjp;&bf3k%^Xa2I_ks3R;Azq1L}XLbp$Ob3a=Qe!8$V6RbjrswNmZ=PNcg^yc>@Y ztvIoziagMYjAglg6v>*8PGFNQcj@m}?q7v4vZdOO62=fddd#~jqI?xw2;ZTl<94ax z%rK#MG+#(Y=wI(^6==chN;PP3tW;_sErGT6`Lt(kQ#?vEn>EU|0VB&(Bzay4>W50R zHuGkw%ZReo`YMg+c)KO4mLn3(5-i&Ipo(wO{lUGsgP)u-{Eze;MPx5}){5L(Y>Au0 zsm6V8D`11LQtr5J``08j=%3yHQ-k?T$9UnHOnSA3`&`#VXjt1L_ zHP*ASgW4YIBz~5xLR^B{b~>_>hHyOHIIDO?kAsS;DX9>^m|S(t`ox2Wcs#QhYHAMD z#_jcDOH_4_CqncAxz(l+!jNO6Nm*X)ZeMV?eC7L+hrIHWRabnP_?P|!8L(*k=$F{u z5n(s(#Dk|`Hc`C2^MbIdB&RSUV{1({RpQq*F)QC@bZ+?GM7p`Wt9#o0n`Jlzt7zp8 zXDP^ml#1wn6M25Yh{z@%c0cM_TXoXQs{D9(nzHKFCRZ63qGSVc2sh_`A%E`1Ly)tf zeae#+ZVu5!!nx(_$RYAYdBB>6{)p$lD?KfCx0IX*g2CNqrL8V5nd0%pu)7fF0^EkmC_&*dluP0APARru)k!@)~j;Dz42|Nl!| zTgQ9JeW7pTVCnEDf^VNst6W<{Bc?6$V@ifaw?#P-@m00 z{g)2TYTk~pm~xQV(Kvz~Hw=o{u16f|jV03@s*c_@f(OSX@iVwpy#2a$_rsZ6n|u}- zuSsH`;1>Gt4$E-Mv$@x!3oYSRP=|pH(NFHI!5`Mf8nqh4B(mO&@kzSg9F!JYZnQM= z*-H`m$tPMKGD#0(YR_A*JQp6U@={-^u_<0HNNg^mRPoCCDy?$y4W&3<$GiLr%kcH8aI<)qC2bTYysC$G&CcYp|Z1mPx%s%(LaJg?KR5cyRG&nCy z%+ZtiqAcA?x6BV&UlrDOeqdtyN+LF>;?<13fWxiNaPla~52q+b>-@gvYm}dkBPi*#&bY{+@-Ak zesygImltDOjL5!J?e`>^WH&+zJAkJg?#^GC?+1ygor46473Wa6h3vmXJkvvoc|D!E zcMvPiZm{8!VyGbXWZbw<>YpM3Q54DG=j@pANuh-iaS!ohc5LlX5`e%jE`|ksUk4`PWeJX?`J^YmN zbIwX08+baF-7R9mJyArTn-R=T@t$|4fBp}c9eYh)=ubr1UxLYWc-T)%n8>2cgfBtx zZ*9>YL}%Jhcyg3>0z`z5BIeoHb_uCRxNjU6#LuWG^OSRg)Rl4=T@@`m>wED-2H+P^ ztbcVf0(CoaXz}*s6EIP!m3hzqm8}*`VDd&`hlGCyhBNNMec@nn(HlY`Bftc5-vRoM z)>p)QZMW)qjPQkgz3WchRPhyD&ENKC2ROJe*Gw9NX^39>z0S>GJ$XJ<#Y+BpJwr#3 zZ5&M2g$Wi+A8SP{Ija8xSwGO&H@HN7Xy0fZmx6W_c59=z*qXm1zAChe+D}CfDS2WS?6ZN2@do<1oUf7WLbvgIaQq5SHYD4 zKWN^dB%fc65ZBlc{f!eYVOpnA#Lj?11yJ<6Rk35q{0Iu;cOe`>_>3sl%ED@bGduzw z)*K=xsdWS<*1lO$K!{9P*f$#PFUPzP$5+}3RbYsPt&?aFbtsmhKu7Eny6hZk5TP`E4vzhh0Ikt(pb`dWd(N3G>;LW^`r!cS8(vj{wCwZeaaiV4K*bu-6t z%g`uRlcCkz5g?n1lpXY!Z{?4&W{K3^R037g#N{&M32y7s77@S zGc!4$5XXWLW6Ev9xC}>y3|<|orXfF0A#0TbDJjIEDN=_PP~g^zBtwhPB7H!S%35C9 z&_C9VjD5@9RtnFFhRi<drQ~oy0cd!LDnpT2WhCLvk|L1DLMCX= z*Zal&0A5P8(qsDxFp*DfjblXyd>rvl&-wFN6zJc1NV_ciBtYj2**^pTb4LqHJQn&Z z2|3A+QIQm~e=G#2LVRMZ!ubSZj>XB6d|-#!Wp*uDs_wPNmx{CzKPozUn9z7|Uya0Tx!eEWEX^J$|@;?8D=HBG6r3yic z;l~t9?KKUw6qi!8^4YfwQ}qfaL_PpcVYZ%k=$j*dtq~uQPZj83(V%O9?j2!bJ(7UG zb{2L7LinhBfLi||!Z|G>UyqhTE5-4F276NpcM+NGcem437K_W@OfZrVOLd1!Xr90Y zZK{*bV-qt=szRX#TqeY{h|C+#D^h^t3MsyPH^ohV$*IbPQ$?Hc=sK88K_mPEVYRka z#Arj4ud3RH>XI8#-9G!@eRd|k9@t&IGe0B8F>P80Mtmt|a>WX!9@5LbYTincK-$q#;N`yIZfTz0P_&>!z_%r!A2ueL7keM<#r!DoU0l#q zNGQp^7g|#!TH%#D#d34{&_wc9d z#XN4l@(N&AtqTJAmkghT#Gd#s@C32H2#h{a_T3I_xgLYv3&gR764(7UdL+=VBaC$8 zo|J`NG{4TN8#?Aok7UtFBb>x0^abP&xATq06^HxZ&`BVj#666=@s#OC!rf4I3;csO z%7Z%bJ2&{B1BInbf`MQ}-???NTbv8@>iZwJ)^u-sZK*rvCgR$_?xtd&*%h!SA_qAC z*G0CQZpuYimZnF28pAihddh5d;xwv&J(k5D0MTJZz$GQieaCI1i0N|dY?h)~jP#El za9d~Kih~ACAAzF%wIcJilN}N=txdcLpf|}~ z0ba{{M5d=NEFUbl@+#nRJ}%#K>CZdV%m0oigkt$so5h~5WnWYhFN@6Q{8{h?4o;#% zR8Re^UU0v!g%j!|iu6#0!l)2;p?f<| zYkmr{F)OFa3uMelOT`K1voN#zuZO-{uHif*dtJNFomeY0;1dY|m;042*Vifz)I54h zuXEU{Q%|hdAE-Avt4AXn%n}={1{yA%H8>y}T@o8T1{!y!i%3jOSCD=F$c#{ALoL23 zHt|8izyt1|O=Ih^|MgwJ>d~COl6z4A@5V|y;cxa>Zi%dDsbbVnSyZIrTS!qVHSBR? z9<86Ct+&o%C}(nG$o8qq2iYjOMNc^n&-Ta2=&B`%D_Q_s+i@KoCF;ugd7xuy>GI<` zHa-TI8qK>RtTK2e@5V^g+{6dec}#^gN6OcWKf5k%5dCqbTMOJI`0T=UNq$rQ*wfe` z3WaZbz}yen^Xa(zmDB?(CNLJ@lpzI{sO;4-kiQ|^%PI0iKC92=nNR4i2lp!Jy}#Dm zGexxCVY!$jpO#iZwN_#~Q_9hr%DbT-KFEn@P=f{Pc(-wtOw!`v7-hBA!*R*%d(WQ4 zdfmVIUuyyY21dhdOJtDF0%24E|23WtKy`1jx&iL_&NJT4x7`7itQ`O@a4nSSuK#-Y zO21cMbjYRp{maAyAMgCgUr!8vGZHCHKO3^%uQ6Drh(X{$>`^h}ygRh!h&80J5*Yw> zu~j0XUF6yQxU`z;FN0MtcP?iiQANjpU5ynToA8)ye8y2%EA{~=M)Rc0yW-Z{&ugrs z#oTco=f!Tj{K@4{ToN&&`6i7y zRTjQplYJk^If08pTzTPQX}&u-BQ6SKLc>&R;g3WVS|wmik}%|&!gH^IDuyI;E)S#`DQm%foK<_f1B@L2fPb|Gd_7P7zeAPiYH(C+%O+kA~UV!1`)4vd#~5$%0*p zS|3j8P*aJ;nR4@7C;nDa&LS{v=%SEu8cyixWeMlP*_)z~rcyiR8ag ziZg*MG3rKLUW5MyAWiwLQt9tMx*;f!uWq6dy~Lv;>_ywrf1Ccjztnrb_tpKi#^RVK zSI^G7y>3DNx%TJxjx*K_ckWVTxRo6q z*!RbLS@|bh_r{f{No&R&jm@poGB~Z+m)`^|v~K=5AkwP>zurR-LAaP#Z#wKC5-8v1 z;JY{e%j!?Ep=SfX)EL<+=shUcn(I43L;-yfy+5%sp6s%&Gr#uNY>0jCC6IqSMG3$P>|l8RH-QnzrsB4~?0N$CH{c zqq+~6=}Rh#QF%sZ&XxH_TeeL_-iAM!oy(&5m-1|_-Ud`Z4Z^;c+P$ zo-vqOB-ln5TQP(5&d4MmJ1g(VY2$YdsLImjmL{tlyAdqA5uN7iR%l2mgCQFluzAKK zo-9r7R^GfYSW3w^Z zw@=pbI|*XgKs&2#pce=JJm#$XnNz%RQSZTmXpRSz1*DNX)puHM7VZ(aX^VU+`?=Dq zMzEmkcAHyul%uNt-HQ7MfuE|=?HZpnOK19D4>GQJx@%MRJaH@JH6r}$b2>DM7I(NK zPmXx1-fKwjCru-%ABwFlZd548>wh9|Xd05(_&^%pMtEV(t7Djaz0LI=6Wz1L;k@tr zwl6Pb*-xJ>blm3+;B!35cQMtaf1`ZMODIs%G>3 zW=;4|SUj)wZ&E0V0E8sP=HqSayx4!e9$n$)RAaPow`g$SSHWk*c8ROTp=0`epB2Nq z{J9Q0$1YAgv=I&YDs`!#OPxjSSxnQmM)g;k#enFiErMCB#XeEOIY+1$|0x7G7;}9H`I&oj+3~* z+2`53l{D+#wfd7%&+EN2<7!1A$smZWNd+5ON*+{A>v5=4GZ2!68Z+wuE)caBD1^%( z3RR=?69?-_xR>_~cS;8CY~u3%qo7^z0Jiv%LLGYZkaP!E8ULcahVHQ-1zhhSZs%mF z@-!{vi7dnMx`XCoTfW5{M!WQ#%|jiXX6%ASPICe zWKy{PX>P*@94wl$u9&F61o82JS(C}U9E0iS?F(4(@BD=7fgouab+)VCM}@kY7=xrH zP85L(8SmWCDQ~{(lUpx-fKTCG0_4eP#7by)ni)}aVWEaByy1}nesz&7p{HS@A?{{| z2kN=}d_<@h@0bRK8yXSg2iNwnf~3ur<0#}(pjV*ouOWj7lgAd4Rqysj8mD7d;_Z50 zeZBQ|q^Vc#wDOM;O^@I9(x0LU$}(Ss7U=gPBosgVr9qzKMw(%tl>^e7;HMV`W;UeI z+l7Ujfn0cOnhT{4%7Be>M|3ioTk;9WP=HXTKs`;{4UujXT1}fPN9Hq816h0ZVOdn$ zZ`lAn6zz~>yf(i=;ET{h6EM4XMzYL|w5MVmtMT)$ihHXP4L0A&TKZuRWGGmc`dZC< z1{#v0-c4fRsLPNHhoK-VQv*-YFVAI$IFknbxD;sW8~`DUH)g6xl%;u?uwQmDV{q(td`;R510_w^k&DDXA|ZA*YaYP)036#N zDjMjH=Jfsz6UDASYm=aA9MtCBG$b*%HK!Xg8=V&=19%^&$~c9E=Es&x2GMmGr0W-w z|8`BjU5q~&=dV7@#cdmguS?;u~*!O^Tb8%w99 z1BhV*Li}_$=WtZuG`kT0(DE*CZuea7xXlNVR|Ox3-MLk~M%dWWOz30FyHc(qS*dUe zl2wJTmdy)0gP6`Je6=wILPlT+tN(H8Zew|?el=gXE!NwbaL73kzajp96)fSH0y3MF z79U@B;mjL-m{5n}gVL%hPV59NE{0N zE6Hgh&ytCH#}0XHd2S*@`GdLzbLU}BpoCd=Dmm_LfpZz*+Se`byu%y5Yu2h#7y{Yz z2n-%9;~XgSKjwn1M{vI3f;y34ztea-M&QE*Oxp9XDH^Vm*NzozI`40%5RbeuAHC(T zA88U}FK3tY;O4TwU5%dzYD>=SNwlgv?(L?tDI90b=H5nkipiBvb=o$t{sFU~LIG>yGM0#UIRKP7Zm3m6MAEli}k@0(;E4Y3V-^B-7^SY}wbpkTxs=jdw}8*%X- zC$~ID0=~|gOn!?04!|e7nUAlk!G=Yze?G5=PGx0cPEdpWCd2OHGyfDo5zfpwfW=1& zNRP%wTXpv~6Rfpx2B{0YXUiFAOKOcmU==QM5sGPqM&=fdfkj66y7)SYy z6UwjujYd6D7>4v9Vob`pgolP*82R#3naI8mo-NnQ9Q4m{mKAaoO@2+fe0QBJzbe90V zx)^8M!z;(am!J@ElTG$kM!YW0>1-7mN089A&q&u}V;{MJWWZ5pMYDCY?SloiG@y|Q z(9#6x4$X^8k8_I1s>slWk=erK1e)pip!46@K6FC&C=6FJ^wb~fW-sw5omaaP!nieA z_^|iII@9Ev{|MzoJAfw0&@zvTZ3482OQ3E!Cz~yIUV%%SkPtfp-N9C$@6Ii2WS}ZF z4IDvJ6xareXyXSxq_M41U<;IjudMlbo7d4`VF$PTAI*1SP|%X#iX8$cW3#xrTDDsN z-I}dreM*=LfH62|6qbmeozM^5g(n4k{0W7I5kg;Pujxy=!?!riPy&q&1<(0z|0;l- ze-W)ac1bQtr5f`tO8p6R}4#bq-5yX??VOj3^gR|v`#d>q43ofeT=TMEIczn;SeYtRy;fBxm%{^WCMa=F z2EmRR%c(Tj94qL9n&t?F#buQlJ1hT&J#3c@o1vw1KIO3fX1#$*q7xuH4Dc_DAZ@JX zh&9$x{yw6swY@bYk;`(6#zqIYmdlfM(PUqL3Frirb%_k~RO3G5yu6^m^bNM&30o^* zzRLm4qNhRnu;+$5wLf6bHIdt*=9H_6wvFnY%=0p=UY$j+gZm%XeJDu@I?L8p>QYXZ zYmsi?)2ZL(OVO<)c{CK0NhN0RsC)$jskSbuw)(~6XtmaEbB@PqRlJrQzFzoJpZ?Oy zD3%a1*lkuw&7PTRuaQ0?9a>(d)Kb&h#i58&)#|bF%i;}KF-?R=+fnX@o!z}rS(>W< zAY}`Zez)`u8K2l%qGqFdExXUuM0K;1am(00HkM_D1my^eZ5A<&quf@>wLC?O8Qvh}0iGNR9gWA(96$)yxagKJh;N(B_q0P%qV_Vc7?Tsr1{qf8$!sP8rL1dmIBU;z z3q(b-b9D|=S%_Y&A++a>K=4r;SX?BP+or2Dy8E771MjbYFILv6hF;avH3(bk zs+LaC+o?mn>{PUgmV4H%AkuwFfpXp}DnR71*zb~r$4o4|P#G?~n?tE?Rp}*9zP(lG za{|-%mmpjl2$_{zKw$I+1EbX zV$MchQsd(II0{YZycb{2$^bmmR-wsFSsN%VGYPJ=J!Xt1G}nYn55>Mu8~eh=wxc6j zTvg(m?D91NmZ8LD2w?t9bDB{<{~;8b;P(^)1Wyi(8#2V9n7dh zROGG+7A;S~cv3$O6*p=YU#Oa81O+q{shl~EO6hKjV7()RZfGx3rwXERQG>X+>U%(FscG&0hOocGY%{K~p@sy?O9#A}) zl|TmHDD3qfRQ3K(`L_q`eFS^VEc-_;mAvH=Nux`lMZQmDQExjlLQTfdJfNIT?ZL(5 zPC>T5nCrGFpcOS|T*Lwn1<`!S3F}wAr)E>wWyC=boKW{*cH?rSqd3E9un-hy!k?!+ z{;FSR*>&HuZ&ToHkoMM4K|P6GPnus)tlxWIjM#f_7pQVv@4C72@6A6X?sh6T@5MQzXwIoQ%kf$L z2`Wo2Mdaq3dhjGXd`)D3?e3)Ag^4$^H8?xg<+>xq4jwd$7BkPqH|YZXWgnXc0)JBb zKx1f|C{T8PSoQjHK%s0M__+I+4=;9nhvxG(qKo-J_U_?QHFnppJXF^6Pbzo;-Kb$MMb@91DN=Jl!3 zp#uMUI@ zf?7I7$QoN@--rboW{?1Lg@TDCG`GpE}@Q`^WnGK)G{kjRddh(`85+3uviLwd)O{l@F~}d0+7s0b{q_Hzyhe-s49fQX6E8`}?Z7GwQBQCA-vG^3;BN+-r0+Tg>5c z)xVhrs10)Nt9hKz;V)|SCj7WwAYql*yC<%!*^j?&JlH?$Up^vN5zeKX+?uS~@0oak z3t2>&%4KMYCLt@1PMig5>mk`a%X@4o+GmwRY%tfNpR57~1j1#^j27wqz#ac{%=t=1 zbifSc+@+jZcG1P{6!@`a3n-mhS$A%{>O=OUtOBl=kcYiZp4*x|dlYUJ{!)&G{*95v zDE*RZ;RU6x6e*>tPlP)52fwGiHI;Sew7w~7%=l}L8hjkNFm>UNbMzGQn{&8>xk&8s z+#|v&&e1vnz*KLQO|hJ}xuC?94#yHC(}eK~xh;3_Y_ZOA>JQP2!pv32{W40IdL1u4 zX^(M3M7dZx`pEAe-0YY^i{eq}s-zWQ3hRc%Qdw)GsY%~64VNer zr!XTWlSR0SiglCq< zwz~D5?JbE*Nyp=9+-T_hyl`IL0_Kg2s|VFFR?y>OsF;9XnXnEAoBdp_wtTi0R8ZGi zI&Rm;*=68O;O6s5UGF-Yma~06h+i=1(b@hJIsF?)74j|Ezahc(M*#yNTIt4T*BbIq zG+T>%Otk(rzV+cGtY^XX=Jmd3yK(>Vckfsr9IZ!ddE*bzTO6^)y94`O6!74bX)hva zw;JZ={q%`o{O`zd>AOi$FO|1EBVK8~Ns69+9QX|EzT3rG6a7-3wI=bX0*q}&-WX7N z^SI;X_HuCkpNQcbZ*IkZxcTEseD@u}+xT^Z6ZpL6{RCF=Ta{ziYQiVoPf!0-r$0jM zwx#PnJMDe4_4g)iSny7g*_bZ<_n62VolIdSj{u=-WrYDeC*$dl<6Gz6+`04j*AF`V z<0nSeUPi(#>dC`vODN)Ol;G*2+p}N%_Q|{rSeEm6^xHq2B#})ltI;W%E6qMdS_a2{ z32(yJWS^?+k2`ne)CB&*K25U$$2rEt?4V6cdZc9cxrnP3_XnE3)4gVPn~fylQ@~oU zRL2I}R&>zMi86FYLsFWka($cLYO}R(7W-Od{wij#tfM8)Ojs2w^I1EC(#{W+D>;0( zSFTkOjPj2zw^{6pH?%jsx>)eSO|mQAg3m=%ysy<{*FoQEm0=^Twd}dxl}-1O+?1gv zgKV@wLR!MoU~#yn(Z~!mI7JkO1ae-Dz!ly1mVrggDt#FYVNr%JiQt~J*iUt5@qMeD zGvZtd^S80vz)j4 zrOnL;nJ!fRWV5Wfj`i~h)VwQs*-_z0Gaa2{Xu$2zHG<_o86Q()uGEp>S}14EwF)el z%klpm>0o8aq<>nQmzlFwid0Efxh4eiF@O1>hcT6fa7@}|O~r9!(t(O64*7QDkx`2M z<`+jW?Dj>O~a#qREZU&{3JO}YvCEoqyB!8hA$Qh*P2Pc&)%%!=4G-IUr z^4&i<{+fU#x|_7Ra)0K0-}!$OoqIe}{~yP9v&{^1pSjKbl4@?5`qeLdr;`QZ1=;-EY6Y_s1SP=kwV`@RaknWijs@YCUV*l=d zj&WhZu-}zRgh;KQMlcofUWiqHq}CMI!0j-qq9FX_#j&)Du^Rd{PgL2XB;5gv`#^k6zR%6SR-9We5V^}~ zm3du*y<@ypdy#M%`94$yRwnFJTMTLaaVF#{qkU;lt^j&{a8`A+9@0Hr2nH7q%3ttJ zz^VPNY;(M(06w2!^}SoB3v-PV@vdvvs##^Oy-O!vc;D`Q_1uf6V9iJHu=&(r@V>43 z!{X%FVP(1uczUOY8E44meSjEBYhJkhU997Z_S|@*G@Nxm1?RUguJAiGY;$hJK8os% zwj^qau4}`RX5R)R84Xfq!rup!KP}X7Ph^-f?jJBN zR2}4rDzds519SCFG%ATe^-51<#t~Pw&p8{( z!$NYQ_HP1YL-o+GCW?o{r>4pm3%Z)~{ulQoOdZeev(xgqIbwf3V9&Kxci9!Zb=m3X zo}so)9oG(Y2lW;DO)8$!H%{&5@yqPd6p#ksKySsj7Fh0Fi{=M33qRv5TYYS1)Dq~T z@f1kOKKDxfL;c7an!dd&+*I{5K#6&5#JOeJtggHOHvvdI zklt8GUsm(mEpe;TEzA2(qsAWs?!Eqygayr6`pq1yyHbWZ_e@*kcP_K%$33O-C0)&W z+>r|Gryn-*jT;nTip>nYqWxyw$H*8DM=o!C5fY)UehX&Wz7K-y@7Mf@^}tU7t80{( z!o!VVwCCCxS%g;2cK>7EG!!_D!+5nmRdD=Wi!nO)qDhU;V!c6J7*HN7!8~E^7}kv0 z(q<3Rl}OD+WICBg4~S=H1Smtg`p~*H`%CFcQwB#>6_Dp{>YAu%g)v2)EKv>$uHjvR zCP4E!up|J(q#d+_4CV2mG+t?b#w|4n7$*S5q8h23=5s-p4z=^d)TjI{n?ZBM@7)AR zJ$i_dt&L92!D?gHD2%Q%r6_57x|~L*q~6NnK)TY7hyI4;3ybU5l+_;t!sb|)U4Q|S zx+W$k^$Y2Y@zVTSR(>3FWrgmX3Y&GdbZdbP1eMs=)gd?GJA+Tk+3N+^H-~xYV6i5r zx(VK$z=Skb+Cm-Pt1zWmhg~SH7&82RTlSae=pvLnKHLy}(1Fpumg<|xApdlnAnQnz znMVjL6B6C8zhsZGmAbrMWjipC&B`Y*Ei#DF1-dp!*GKYhA5co(HqJR_+-v)w(uC7x zcop_amlCZtzrQfO-C^l#S%f4wQ!r2x43{iZDqbZDzxJmS?rBG8nXS85Zn^ol4o8}C zw@nPb{;jlk5D1=W%2F)bVSBo`)lH{R63xAvCv?1R1lnh0nV-wb<*+h)N-%`t1}WI& z1Lv@F33nrGe6Y}90q8(IGnvbbo??i$TN?S0p^01LF_dBxxQ-?c%=*PjAVck| zm@0geK_4-t02)tb+SlAU`L)b{%G;~fZA6dhi5rSfy_Po$#niFTt|dxbW`VzvfhUOP z4?6;2X-&v-dsz86377Q_`>kuybH3KV9g}xqxk8E6nnC2o8T#Q131n|?oW%CJQNJx# zq5zr{2MrTmDMcfmKtO>6XcP$=WHc1Ab%KG@kDy5`PANvw#GD%t8O@{!Bn}8A8~~@w z$r4Y38BrW)3WrG%-&M);#{eKJfkfOCGr67_#fF4sfd3-FQh!-r!>>HWK)I>RM4SO| z|9I>|Nt^lotXzl{geZc#b#aJob#N6dpoqdLPU>Ujke~;J#Z(I9AoYSXi5Wk|Ov;5G zz=0hXOEFasbMV8#VfRBV`}dT&Y5Id>9zat@p|M+jtd5g@WMU#Bc*a4dTmE7QnI7@FV^J}k!{42T#8oCbvE1B4zr{KO!Pr=Sd`K0GhbS&COU*>!GpdKgBF%wA8 zlEUK{oJ5XAPdyM4ECCLx587^J+lqulp&#pfld!7lTnlHuOJct7_ls7A*xVPdJ!S~m zUv~u*y7lC5uSB=E(nu0CX*AGH0vs1OoHh!}5{Stl(4~G>Do5fl&g*?4Fe>+kw?HS_ zhn_mc%EXQb10mn{LgkHIv3-Tt&R)Ig4O-2+5yN4wzIPJ+hO18%Wo@yJtg(*H!SeAi z$8kAB0dr;^c65!E3un0{;=9PeLu;%o|JiE~SqaA-U$ro!pR(cnVH6gsRCHGKtfSaJbJ{} zkW5b=74!Slwi$!c=UAzvol0iM^S}C%>#w2fi<(j-)=iYpS62 zh1uh~FPF0KLC?c@Hf!WB><9;Th+BRh@Lz_I)%W<;Q8;T426ov?X$PKlBo}5Ypqm)6 zj*j+Y#GTN)tRD|pzBf*rkXc8tu+7)37lW*Ha=ZQvqx{3dQ2}h{*Re{H*I_A%!N0I| z6NlUxSPnsaQEsIISV!Z|XSFjJl&KF1EKeHnW21s0jUJV|Q#3iyV|AP!zsCB}06W~e zbTpL-duCfvd_fFJ115UV|AOjQTV85(( zZVr}Uu*_V_`QH1mG=WWg7hN#QO3uB6rZIZ%8v- zi~zONUjwWo!ths8tV??(wyhjEQV%n~QIX}c3Y(FQ8)w-+g+&O0vgTOnxg=5YwTw|P zPrB$sVZ@PkRtmdIHTqgUo0ZXW@JJl23sguT!9)QuuL@|eU`Nt-2C06{Dz}_OJaDtu zL6G=H!s9aVP`k3{mBdjx=zuinSD=;#noq;X^T5K`%t6*N-+kdLwWD=O?OM&V5m)ODcm;9Ip zweJrZ!7jJiZy0&y0$53F&>WP;J_^5BaNxtM+lJ??6;+y`_Jn&r_X&~WhI*HAO0 z*b%fVyUJr91)&uN%dZ*{W7^UQjRm+@Cr?x;HFD(n_xG|yz*qKZ+X^~}VVw%d*?|Hm8d1E21;b4W>rW#_V3ajAmfWQFN#A6=Hnc^{h2!@)}cqk~QdV4yc8t3qGJ& zw*9#f8=LYMXOLioV#$REt{vEi=DT1Z15pjSIQkPh{bE(;JurSS-U+upF`|%QbNZ6f^ z_fp3eOCJ&!!dZKE!n(YG@o}GjRD8~-WM(Y9$+kM3b7Rz3?#dorRx<4nFX(DV!KVT) zRCymTViYFgonWN{SXrsJns$X4DSo+V(2>D5RlJ&<+4pe~Y7w%Sow)`z->nggGRpFT zN&hg*Es0Z1WEw=m)ZRkdQkW;gft^QKT94x5u`FlQNk44-d)s$)*@21~@mbgf9XNyJ zJsr>iN)SFIel9(*jTH}Iph>_aRKn$f1>Q|q+SX|_hcT4Q3P`{Ev4s`g2TFF4&^pUf zA|g&rz5k&Dv*$dt_h*SOXmKaKwvt656)NKNi{n_fWPd^`OuXRz`U)`sMoi!JWB!a{ z{MBd~W+Dg_M%fvES*4wxn$~W+LAmdGO41TTRAQ|oGT&wSUwq~OJ5vARsb`xweiB7p zV#WeK=aoQ90~B$oV7jx}E4Pg z`?uez-uuj$J^A1JJAk05DVzN7=XpjYL_Nn$3ayB*a;=tJhC63`uSik%^$AZ}=3SL* zns@vUZ%%2G{mV71<~KW}Tt_N2I+du{o}AqnNw?3!#;+ya@Y5MTABD*6?=HpIChWL> z*Ta-^U*}y^q(u;)QPTNgJ-+-3IPtl$4EwHqW;$zfF5 z@T6}wsE*BnD>YO?gTeTpU0}Gc5%O_`CqqKPCQk=yADXYtMDDis+3=h{j4!AI?fS*h-QQdrxVPit>4=7owv)rh zWgQy31VswQT@kVl?KA#Gn2!Qo8JVnq#KK(?SsRt@w@MSXUA=vEO4@NFv&KcBBF_9RA>OI9?$mlAr3}p1GA28s4?T+8TanX*qUFY`af(unOdGKeJm#nuvKjmg$B%5!_fV|r4 zZ1g@r_Qu#-wTq1BHv^}R=dJ3Z@t0K{Q%?2htov9H3WKaSmSyaEi^#)y9$3JZ>;Rjq z63|fNmLRaR^67@tsvw%*bL97J-Os%%Cw+E(x$POG#eWnFL`HBx=F7vU&egcum0YS+ z_0@%H4kwY0PV+kzpC z+71$K=+$ehzs12kJ@YD(MW_k=I+CA-%Y8;U8+-)BKgmP2;o@f5!QbLo7J=2JFlFvQ zc`S>6j1F}8D-k&l7fo^xthwD9CH@r7xkSZszjp12js;20tJ%_J36}jIxGldv$pyVn zxr|r^$l2DUN$%jX)1E-8)UH02);M1sA8#*dvzb<50d$sqO2>Y#!SZuB2o24PKC9=3 zrQinwj?y7F*p|!F_MfB1!mErEy-~2r+ zEP>FUJNn?6ln@L5Kb49Apu#=$6)UcpY<|62C8$*D!qa;82_ZrDQ%MOviC3c2#U(xH za@PKAhSbP2(%NL7qG$#f?IYF3|ALQjYUJTx?;*N=qCSLAEc8&P%VBhd@QycT$1SY# zPKx=rdtBzs%KeA-Q~>-yvXtfux?bn$|9l?ku23s;$dO7NSZLFyW$B>M1fNCHBfF=| zDp{PtyA9W4T9wxyM(WzlkKRLCTV_;LS14-4e33xT96lSXCw)+&=~6&!={CP+rc`rB zhf}4c<^fAtSbgfZMy1Xs+`%)L-{OdMQLg!6%1!lkc6VlY8#70&8Uv~1I?b7N4d^!w zzP$|86?Cszf9!0N{HjXha;gi~Beni)c{mJaOP1n)93Zg4Ju7n34l~-S_%xV4L387+ zCZ}_z+}Y|+cO_j!)cRNDM!DB;F52>`Bw|2&?@k42R;>Lizn067>zS45>VKYFtqqGD z&xKUvwnk`tZZEXh3XrMP%kEx7<~euLPNqQq`u*Z0-4RREk0Q?r-V2kQ0o01TKf3RJ zZe3qaI=MF=Nxa^de#H(Nz%X6{tJ-RhIO6w!#UMr%3=NF{ER^@@FC#j^VA(<8srYrJ zz1kNNGUv@+Sk!oGJ>6Q~vn@}W`gX6h(%<1%rhy06nsV~CkKt@dr>n9G7)qCXN|QfH ze@wTm)%f!w#cFTCtY7%Y$PE%}mu-{j2r|;WgOh%L$>q)M;CgkVo>Ds@kIFM@KJ$$R z>)$C4R=eIJ1MoA8*+?7ux#!*ewUX}08Y(Hjo=^3MJ`9((7SPP;L)brasux8JM;h^K z7nj($;31^xbum6aWY}gBjR4MdzVpgWWRhjMitngDmtUv`HoTG54Y*IYs6hcQse;tugLwArqZtc z;NI#wTl9>`DGU-*uh>b5tQ zQ^J8hGmKqEg_t=Pw})U;?#qiPHIeZ?9g`KEz|zuLu%tnw<09AzLcB3M;XqNdw}Rd} zQ+Dfxw_^vRPYH6{*u~v*Ft=TrM0Od$f`_<+cYWOvqx)RH&~)ZRXC3tR4<9MB+uSFg z3fx5l;|ut>qeOf#(Mt(wwl$Cmt40h&@cQzUC4co+P9yODBaclrEluyyPH=%z{qF|aj? zhg`!r}9$wE2lP)13+pXdER)D@lO3^p3zGu-1%40jKA8aJoD-u z%ZRBnfF1LU?Qt}}ehJGe!dkIzrl(3)2SQBYvqFhV>ZlUCC<_<4G?Q5(nLYpY+%wPC zJ>01i7)zo}*BLQi72n4z7IJ+Ry>>AD-kDy=61r&Lfndpe8!q2rPTzq7ZqA%@&n)VW zuliw3`nJZ{3MuNWTl(3ALJ=UU@1gEO09N3-YjwGmHsx5yS0csyzlI9d1^kGy(+)ihX^u;~V9yHLsvvy*Knyh-Xoe;E*J6OKbuHiFcy9~CBI(uUx z=t|~u2l_svihWKeSE})gjUf=3x?%@X&E4a^rdLq|z`;Bk(L}IT{=mg3m?xMe)R)F1 z{ljDYR6W_WLnUB$pBCSf7w;6sn;qtttp&O*B4m6pvqOH;Mm4sy#&J}1PAdI;DdLt- z!;866w<;z3Qcq;byZTSZCx1>|K`BoE^g*nV?XikOL)>Y-a+iDet%R!sGh!lZ9rz?z zGMMjZ$=|O}oJwn*>v-r9Au1-lEM4es^mKe*U-Qs-nx0k1&{%^=T8=uPE84L#4qK6l zKlS`|UivHR3*v}A{%%dmbnD<3>=i-`muQ7&Sh#}i#4KYx*gQDV?vdL&UzLfD2exbA zU6B3E{nA#sdkkZWSoeq0Z6`@3?-Qezyy_vcdSp^nq1F0XHwV9g`G!*|@ux$9BvT1n zC7q7@^G^04(^S44Y7+McCW94IVkcYYW{Z}+i%;^mI(RWL{^$N&aBvNhi5X?0-rS4| z78nI3RDiXjhvtC*a;g1QQ>B z6WmC2xToulL@|yJsuwKH1#C1E?C$8wh{?9~L_f zpUH=j{bh;3XpITw-d&o4&B+eA2@Z|#SO!j9;abC6*Yt)?e*xRK^Bj~y?xb9FP-;3v zf$?UzUdu%DKd@ncs0_}A^(%z{OyU>?@KuwsK|w(R_Qf2Hf#%kS5( zwcNV~H6k6G2dy`@>ev_d1&<@b2T3%BF%Mv+?tQ(at0?*s^uzHu0oRKf@pXplyC~w@ zY`T`NO>wrEHi~zvk^HvkkHEuh+v`zERq8uM!iVL3aq@1~!tfo)L*ca;Ly1E=D$pZHm zDAH~I3VSIEAJv6cz@|20CTY&^WzF_kI|TOq$?K7(Jx}UbrGxpZK*R{i@HZ5^3Y#w zDo7WLb@J-|`zb*8TU!^voK~{EihFsk0-p-jAkBmR(cVxS>bqUyP%{TPCtH~B=_oCL>QZG^H zn$h*bur8to605O(R{P4}fso@me=BB47?k4X1zVtIj!&I`q0DoIi{=T@bC+$8C)!db zqnApYHjER_eR5(0{)N^Ex`mE?sfK|{2bvTljo5Y*M7#Rlafsh*n-bG-{g(Px*~--g zNi*m(g#if2KB*ci1pKu;E58(VeVCzO@nJXSyrSXDm5?ufiA+7pnL9LK=pv@WnPJQ3 z=eH1TH%Fb?!T2H|X7Z7d=7imvv*g3^n?i!&02td!$Z8SM&MksX)OR2K5nv?%+ph{! z^i&-G$V_v&$A^ff*nyrHQRTm=NWbY zP}ap5v#*j!0^f>9$T}M+?K7Ax=9gjdR)YC}4eNht-Zp0}93kMNA3dvnwl(5E_7%~u zMf1y!Z7H|#0T-g&!oXR3ew?3KnGDFeQRH7gaNAOH^vJUDgMJ%iDvyo_yWgHFWV-~x z5BGCvs^QONtMBjW)rsa@@-%u%c*PAE2J6;~TK39;zX;F8FM$(Sx23LpH&B|F_8qMH z3a}~xTNQi*#&1dv%s7;R&kUb{x-uMl!5VC&On=~sJJfff?ns|Ou~C2%KT?kOb^MQM z>0hFwxMh>h_`Ce6eyc%SJGfbx5;*?5|5&ZTD7c(gsJTiv<$|3!jJv5))-<>c1%ySq z>_W>MGIfoPimg9GyJ#f5e<5!VgTc-Yxy;xd4*oCP#b$!kH|KSkQDSXhs0kVD{SN+` znN>ie+fIy%S)L#6ouIxI7zV)&hG=%@Ycx0vuL*|m#$yW_+}fxx7&2%vL9tdBG&;Ie z&hYIDZUzsWfbLU@x3lgzLLAyB0%46n*613iHo~0|u=yI#X|(X#3qHboE;$mH|79ei zHP;R=-4s%c$#gNKxZny@Ey;r~E|_io;V3}5Hyy1}GtMLDzy@pLuTzFI^~dt+YIdc` z^<5uwc6aC69gt`7wVwmUJbAq^K6#AgI#5>h0{x==fYuimmnc3KU4RYe85w|&WkRt4 z7xPTy^?G^6XULf-w~sbZJZ%)uE!3g7>?#QB3x~@rhS-}jf;lJq-asW>3ery%U|aK@ zO73Qdjp(b4{`a@ll;C7evbOetradg#d)_?yW?)Knlj)q}PZb1{9rTMZHZ?neES z@<0M0w+cQA0Y7t4BI+Qf>CNorXFIBRMdEn!xyMznnj$sP#ne;R&RY^_itn7st6sPB zzq(u@-8NT577^As<8RAhBMi@(%=blOq4xPRrayyQx=FT2mLjm>-M$y@;M{7$!&sm9 z;~e%K9^k7~m<)D)_|&a?F}A8%yx#x|-JY$@_B`tt{!foukc~LGL#wa35uh}k z*mkWW>t~Pbm*6AL>NV>NHIlk>19|UB z<$B*AY4&^A*9fKx-nsY=yJCmPwa1=5^KPjw?w)ovlYzJsW#S^$e<%uJUHMDQX*mdHC)5 zjLn9z@~rnwEX}aa{GAd>o79p1ANGGxLnt@(>LGbwb#a5Mf9&n~V=KqsvI|ai@FWdW zr}WO}N7b@4Kd*OOs+~ztuNl=5h4IcFodFVCj**^wXwLjwUY3JKpNQ4e`0zy^YWVLs zRkdLKCrk72`?PLTE2LOP4;?G=(99Rc!%*0MQ~61ZbtzBvi2C4%0Spx#qm`%WnXId> zNrhcF9R4Ij7rVa2x}8V4jT-P=>yEvc^Rn9GdVX$v!su+#^|yF+rcWH{(=QtjyT&rt zIBox&t`SR7{u}2{*a%^hqPO4DwBb3$Po|)&?;3lH2)~mrFH{-l0=RmF@*>lr0bUz(ybGvw zRoIDdhuk|(_f}%SdR~{h<_*< zrKv;>J#nCG!Y@oBy8fu&J)@fM;z1M+Ox8-o-9hbxc1`YRcS{m~Ny2MkezP zOpKiAU%k2~FZ}C$*wkkK{YIMzwX4fDZM<8t7gBn+yGV1_kG%cQ=2pzO%*frQzig!{ zdZ5>)UUjWXzXjhW%H874>MM+wRPmJ<=C-DFv91Koo;Xl+Gq@<(Zk+Cst!R!M!%HV* zkFhKpV2sKkhWx`1;f6xGEP2W=@GUCHLU`%)wo#7e78!aZ?y-#7{*Ot!YN4xhfeQ08 zd>1W|m-DWz=?a-fcxgc0ied*z$B-kdwxjce{eqdaVc%tUJXyk4FkO{f$3TCiu=E8N zEp%+&VT4$iO2bS~PJ1NEraQp!0nkarC2H{4rKcBXk=ctM66V{7?H){P8w%M9Z-lRA zr{u&Z^ql`+f-q08>J~E zdst|0R${&oz3O~wpO@e^gl@#mP#iFuc(5Tg;1)75Ex z=V-9z%IN6bs-NzgmQzO_q>stO(rQ8u zH^5PY)sQ%k>*K{nSWpo?r5=?JCa z5a}1>g#8VrWm3x&`7d0UWyzX$)EP!f_NxW#klf(mE(Urn7iQj22u_*GaQxBhYIxuI z%1&)C9{tUq^mo1@LorHMu^VcCr@F{sfR+3N^}gs0RmKXq?Dz@KQqvO!f@Aw$Y1qwp z%ipP$F&MZ6ZJdgA`Z-@gwY&&l&Gp!|1Hwoc{nDo~K75~vsLaMko|;l0vWZ%ljrRX2 zzuGwBI&D^VWv|Xodw7x4nY)uYsYC->arBX;v~uRpoo#&u9=3&+*oaZ4B6`(l56QS; zle``{1sSsbZX1y8%I}$~GqAdH+&9@z5+xvareX7+0pqI}5uSw>a{*6tdx>g$@Vn)? zD2w!=_e4C$)o!s`P|n$z_N@`S8t?)%Q`Roo{grjhpvJbmEa{>@j6HM^sJ*l!uzR^IDcdFJQ9I?n zey&Dh=wI78#}{9#zL$MEwifpIKSfJpa&@9xYEzhSC9`~UeLV8kUQ@g{d5_|i`uUh> z+XGxQT&VHhLd=Bpk(}#F&V6w+xOovf+l2H5USue0fW>fz8urj7tr<2`w7zd9dS?2K zbI&^xH>?$d1?s~=b-JB^;daipr(d!KYY z`?mfBSFKSyBiZCVi z*x(sr@KLRtxA&W&VSNsK&Bqo$YWGVJQ2kS)vJ1Z^smb}h7X~K2oEH6QBDd%W*ibXU z-@D(27=M1)#tM;v;ZhTDT<4sQD1lIk{q*mjGf>ia)o8_AvFb@)=kvhv8!oQ9Yp%f~ zu+Rk+K{(4#_WvhUvo&CFoc-yBAEsE}-CkLh#aheW{)#Q5t$A9^q8=17Dad+zs?h zUB>Q!UZrZSEc?3@=?vi{d>@MXIX`fQz$FxTUij}lXLQ%qaIUuL3KQm!MJ;M;HOnCH z3Z;&u_UTkX6S<1-owaJ3IQCHxk+GSSbE{OMKq{n6?rbacI#o-?pr4xx@s@+{43OIm z5_P7^7=mE-smO96q?!Zp?UuKhR+dUdC~$t&Y*&0w)dH;&1E)W6ak5t3N|88d3=UK& z2M}}IDHMt8%bL63BQh%!@~H~3I_g_=joizwI|5AQtB@Zn(C;`hwP|wW)9UXgHJ0Qw z-|Yt6!fAe(*8D7|^)*22N43`PYI!<9?Wwlf%(T{68En{FBh;BE-;5Zf$<+WgRw1d2 z-Owbe#sh8HtKC?SqU4)YjjL2e>p;EB?a-)Y9b%+j3ta3hQts3Cn{)Q{)06B2s6TDW z3zRp^2sHFa*UWirC^{x@#0WHErI*H-Be|tU7vm-$bdQaCd2}TlUAw0J&d8WoB~@|V zq$k~E{)=I(y!uORR_1DdbII_=j%}0j+j{~5PinS5f4qH3e#ehjvaifj;OTZrK)n^Z zM&B}ju{wD@&}g2y?VY)n==yd$DDKU&#snQ*6=?9b2B#Zj{(5Jv!4vbH3KkYY7Qf}- z0IDik8?^|4T~D&`eqtFEsGCGbn*wF~C>Q+{c18A-wtDSKe6s71g7uO)Mv0@6@x=OA z#>78aI6wh^;t9S|!KOCI=5(#i*(Wv^6l|>n5xq1-I|*?$2+9MP3c^)XGZCp zCt3kBng`AFl6%030K$!_rUTQi7mXx0c0%`lQF7q8dKbBArNE_TK-yRTc`;#|l}0=L z-ROa_q&J|BHP6=pq=TtmzItA_pOhoFxgQj|_GHeL79GiTRut0k)NM+xJQd9rF9jE= zRxIMBqTj1cTbpJnK`-3M(&d#UVhD@4Ly%hg;_yCr_s?Ldi6_1-H258^r`<==?x_GR zCHMWlPNJp~SRh@kkE&`JSbEjc^^wnn!K@~ot=i91*_-M5w9@Ncn&%Zoe~V9YcYtcm z=|Sa1uqvJ!ll~!8$+d=yY+DZ0r=GIZQSEb9D^&{ewF-2%LR;QI603rWIUzwxfu%H+ zemc6|sVJS5y^KVg=Clo}7A;1n zQxLi7tR}v<3~KRre4rk*YlSr&BwC>h`08~ zem%rD&H7=HvQx$F_l*N%H%JA_rAEyPNpuw#UOMl4rksxADd$uEx3V1cvYTcl|DBYM zqaoo>DMSc0LjY9132YWnbF8&n+3+&1cwSi9y(!-VSa91~DOh0tyH`$B@2r|aR{~IC zUL%g&RXKWyiYent3N2k1T$CQG6b$S+S}yS0-73Z8N;fPk*Ey?JP~eE!Y&%#Y|k;6kJfekbR+p$vzSQe= zKg}sgulPS8BV5Ydx)8R>)z&E^v7#i$=9Zb&kPB6_*?4FYn$L8n3I+oikY6;#wGpEjr18gg7v&#t`=_`M+6(*S{ zHDcwsw3fA0f3UKl3U)gr|4uS6B=cGClZYSZ{zLD^1WTNsFI~^Yv;kGyC)0_xjMuX_ zaw(R#(!6pHskQ+XqFfFbx*RycCaumMiu_^QLV>@xH5jRuF)08kp>O>XSJU%pD2aKvw|UJ6{DqNs@lBDjE< z-{L(CbSEgmxz1M0N_ER%b1c{qTd#E6Sz4gvC;-X`00=ffUI0WjNlpa9KYZ1~WCDVz zk~O~pNH#zb3)bO*{`A7bp4Ex?1jV{#nNe)t$nA5>^-WjVGVck}pbwhowUKLtdk=5B z(As>RfE!;FLL*>0TrijLNk8)k9dILV?vkRju&Zpu%H`Q+ zGl`NU2}^)d3ZC_$Wn|uEP_m|pw9pzBt`jO~$$rBPiEb60b*xk82C#XD*$C{8vOap7 zG-3ra?A|MJNz|=gc44ODZNcgri@`MZAn)9z>$&Y`U3vUBnW}w{Jv5-VFr6=+PZhY*Kyz# zZ5ep(wZYG_``lI$wmij8S!d*-;wf74mP*+&69azCq36C$ z3JcMia!=vIY-uQ!nElEOAlYdhVR%#8R3P}x1|TC&Y71okQ2W6Fi~0^ZsPWKVG+wx@by8%Y>Tz%TCUF*Xn*keSW7%z5gUeScr1(v&)vRi~Wynjgd5%O=s-h+MkbAYFZk zu2$3Z1y`@@uRWQ@Rlcf?&MuTX#lzSFmG00t8=GW;*W9o2)P|PDbb474o7{B!ja)l* zbDxu1{V~$qTk-Bydn%>g46Hn&Etv+8Jx|@@H>tG)v3j#x9vpTp117RDCRL5JBup-% zzV50xXT8s}29;S;^IlMi*FXg7si`q+)FrFUXcK=s{9qPBD z6Ozm=OHj+h=#|atvvu3g;SbH~EtAN4b5>yl)CxIEdS0pAbHehh`>AzymyxyR5HI=Q zZM2)zO5f(Sv-s4x&8jD`iV^=CX{yQ^_L-dJA|_DRpoH=GM%C)Qu(Nub2j#IZ7DK1e zy1_RR`IaV*_P>NKj}ek8e&M#bfG3g%&!&{yTCM-rC0f{Z2a_#Yc-fz`)TR->mGr9f zxXAqzW-EUFMuy?D^0TR@jZFWkr+-;xDjLu1`C6}+j4`u_I~H3v^dOW&xf%LSPUGHD zIon5V#yak&7OcFED$!Y%vpx#amQVbNw|%Vr-#w?DeY%7G<;E87iTHY22UC(@i%_5-M6CmfpF z5m+}Gs|7H;sB^I_R*1dtyi`0@R%cj|E@iiq+NxsY6G=I z`8xxlQ5=XC5M|Q_s$Og&DDH1H=F0jUi(Z35(q~mQL}f zUCO&NCLcUr0n3`ccDc3aghM{5v|nA!=yCihnzJbP_Y+J_*h9be$U1&*4V)T&y+}kk z{hi71bFh>w=9_<=Q8&M_Hpio8UA3XlIDG5_|8QJ(Jo4BH&wjNV53s9t+4Zk0(!Cr{ z4wRjm9URQqyZ6SoP>R)@j;y0e&-#YLk$0!m(jGm0iaTV5dUE+;%qs=ioi6)Nh1s0t zO^w<8o&cXXxbesj9e=}f`&?>ZOIyK4|3jJFwC;n)!q?gRu7xK(XjvWTpR`{8mHFmB zlkg)8S~C(VC)Ly8QZ8_+?r$|Q1D8B1o)YN!&lqGp8c_~XHp0}m%l*p)H^mV6%Fw+~ z^O`i}!ZkV?UEpqc$_yESB`SyD9~O^BAVk=tB-JMbCZqjFr8|&~)Y>96WBuv!RX~I; z1q{#$0fY>3AWH2t33nlVk2*FGK<3N46QBx^FF-uHQtVT*gtKm$PmzpW(26?TGR3LS(@TEjt7pyMqw?* zY9Q>0-KPMVBqdRl#6$Rk!_#i*ggS=icg{IbqjObGRHW)WmgFEXJN`MqO&;ZX>VlkaZf1+>q9E4s zju{Hu*QD`%i)G6(lg>cTXqxGcB6_PU^GYIB$JU0s{xvamipo{ia2~crZ8EgxSC~g$ zg$kqEJ2FXp)mP{S+osxvCN37eh2Cq|XI9?6z}FZ-KG$EN%H|cds7}{E$LD+9Nd2d) zxm*IZzUf(c=kKyaP&J^W z_RVyW2;hPps`kxf*D77em)^Iyal3d;_To44JIe>o{KX9PH|~%2Vj%_f8Eb0O z@TDx>wMQdQQ1y8+T>?!W)VNdYhHO?jEj)gx;PtjgEzS97g%7{qmJK;b>5y`GYi4cs zRQmH)TjFGgD(mi8wO@u%rE`ZXTh2pz<2`n~A1r}RANQLii35GlB%36_&>54qg z=N&`EVI@?kqCX8p;sSMPF1ow?NB0$QL9q62AXZ4<=Z{6i0cb|2)&Qs(G*A{TqATVn zxq$_qps-*!;63;-P+b6!8YSql*zVhrJYZHJ0E(ksG7XIYM4(+XB?y3+t!an>8>om4 zppmFF00_nXA4T`#&(#0N0sQP@n;DyHbD#UAF!#IWPA-ik6wNJn%_aA~jbZMFLPfbJ zq?Hm3sh?zf6%r!@ z8#*ujz3p@4S@*2llt9@qA8 z4{z68a(wI~Ze-Q+e+^vKqK(%sTE*XsytY?UyGOqz;X1+<6Qu~_ef;%`n z+{l*rO@yC8yGIw>2;Zym$zQShU5uTPzcOE$geoP(y^$||_&K%uoVQm}06ta1w&sCw zyMJ*iih6~mVb2en5J(#i3|Vo}N>(fWxI41jQ+8ox@sVWm`ipD3Z?YaG)joU_6LQN+*30g3x33mk)FniM=0qlRu~|My)LJH$YP>B^FX(9}s4HzKGd0|*mR zgA)*m0LTrec5xd}Cqu%7fWr(Mt4W@a&M+kR_&y!DYM|;%QF6z@LMcEIhL@KDH3G}% zQz#__kQosYii6b+f(kP16Km|%9bia2AVpVCO9(ZxQiL?C1Y*FaMR(1e!UysE{ffNgEp)xTuA;yAaRRcFi8#nUM)&e6#~3@-kiQeqZOpvJN=(xx`X`A` zjg+8IfxnwVQGO6jLeK+ruu{D-mnm(lgtF;qenTQ2&l^NVX#>!Bg6;n7~M z;_q9A8IclH@u+)AHzSYe`*1bSfg|Q zDU)uh_I}Z&>onEQ{maX7_TOOuq!MXii3OzjST$n!(f;5Z|sFVykhfd{aCs zGdz+w@YZYi&TCb{a_9#47sihJ~BtmgAM(Zo}oURp}8mBZ3DU>!aGVrrchu9FaR*F5<5)= zQ-FGIPz4i;B*5}Xz<=|$@t3b;+bO~bYC$B_O(ya#1Mz?WQ6__YjLdy8Fbp0kO9!EA zRK#&e>q(x+H?nDV(8wG>FzGb;OL(tH#PE3X{Zgsy5Ml!nqEA9*1@lq#Mf52-9~F3xLQY_x zB5($PMP7k2NQL4<5V@xURnKm6QM+WOTt=D5FAofXQnZJ;(JkVwsAimWBhlhG_riD& zC6{N|`&gHNU)7*DYG9!yf+dY*Z}0ooTc+OaFj%0Ymp4V>pq$m3ybG(Q=Vvsx=_vQv zlsQm2V8KII z(?@YIFGd9c&-)6;KT^Y+heupw^DS8-4FtthMfis?$aFG~Eg`3<+hEs_zZOrt7{nr_&a=^J1-I7F(m?)bjp^*I{&Jzb-0%|TSJTdIAo|T=e#8yBdkaDSNZm6r*KhPX_?ifbbpf#ehD@C`11z!7{%N{aq#Gkae?*G$2aO5&fJtZ zpF7UoeTaI5fp*IgZ4%V5xl^Y!;b)7gTI;=VG}Gy%ziv`@PwP7Uth0|m+ExzCLTVB60GB_-$583cDv|-p9}6&p_Lo z@?b~5wP)>KYRPjcPrXk)-1{yq$b=VSKqxXog~a3V2KQw%w^ zEks}~Zk&O-TLZt~b4MuQPBBGHGWBvR6xv3@jbToC%t~o`z}!1w@SeLGzwf#c!HM{e zQwG2V22`2Ao;eoXG9Q$S&0a6K_osmsn4cu=@wo7wyQ z$?$r1A3Rfoo|bI&FMA{;23sK!mni(Nar~b)8|NR2Ejpotdn7sIs18pr*J`bwME)Y9 z+utS8KSqsy9&|}Uz*ZUPckCyiKp5yfKY^r)wj9HUX-tCc*7_T~SDXMJ&l7#wPIJvI2rXJllK zMKF5}vL5(F8W2wx-(w1>-Zzz#F#l0|%lq=vqs~up4^v3I6)i4<;j`_&DD%^(!CTVp z9WPklBxE#nV9%Kx)FIqq4JJ6IK*38~hENkwJ)3vrDc=;EuZJ(EmdW>mDD&Ut${c4> z-t*z5W0#9ice#9~$l&<_X4}(~Quu6ZH77+wI;3E6M2rm22SNe}ico^O5=o&Y64Z9+ zN+h6YCC@`3Dlh&CK79s&Q$TtTv)-iN*ThOnHG?Jb08b5Iy#s0?0Ev1b!gwTigH?`j zWVi6z>pybqvz-wQJU!moAOeW<^X~3(5nJHDtZEa5yN>^S&pu{C_(KnmTx?DdI4h1 zF;xGO!fa(Q*G}+^qzGKxL{wSuUjK(U=%I5Ezdqo4whq+4jO&kP3+$8l(|r>WAjsPq zG{Xej;nVu`;f%Iaqh1<@{sVpSgDxJw0cn!d$8RKceVjGg&?e3t>o!Q8dvmKx`!rl& zohJSpC(uA-Zc&g0zO&1}HeS|ZZhpO$9@5J2ZNKZ=9`z;FIPD#)5&I%0gNoj7>4f5KTK3mQ{$V$pp4%NvVWq_0Ekw)>=>ak2X#6B)ZLAt zJ2GpR#w)C<31SU3ce)bqDr|mS8@a2QDjmFygkjWvoxdtZKT;M8R|24fRG5(-93X`w zW}w1&pdJ_E{RmISg@1i3M(XA^)TMi|Qlrt)%L-7oae z$7jYh)xw)d*-b#;<@`nkyqdyWjhE&1KVw#e;36Ji!UF|5cbfH(y17?Pf~Pb~I&L5Y zj@*CmgROX1252lb-_ag>#t)NTztFdoyXVq;a6-v?LhLX4+a_9Uh=ZB5tA8Py_P|M? z=Uq6Jxjw_a9VlNoBwjv^_MzY7YJxdGYd(L)F)I-e9(}ar74Q_Mgs)5}iSak*zbDr| zKRHM_UaHx2Df+P;h!6IfSCz7WsMt8^xS9~R3V;+GFU9OnW~t2&@Cw*&ZR@v!8eTrU zFym>o{}atUGQX`i=itt|YH?03rYaLuZ&z9%F8X+2W-=HRvp;p*fB*LX587Yr+Z$S_ zdQ8?95d%>-u9;NeBS*CZ;Sq=;fU(VD3Ivf z73~pG_o%3)^mp6ALin5O(~iwVE$4oX^rX?Db^%P5*?QM#2hxur&4<{dx zrk<63UY0Q3TPtv{<1VJHOsNQ~%J|wzi3hQ`n@vg!r8c!GC#RC!Tm$STYIbZXQ%NFG z63X{lPaL>ee>qIX-?{fuyVn^Bj{pFSkeOofBfOe&vjuS(mzTu}*fq3DNQ?W`pr2Ls0T&bx#7F-DW=Os@)1mpxD1pZ zz^@P+DXKk0)lvQeuaaWGH7z$!_&8$$q}r<}KRWA*B3xA3!193Qt1!p->2iyCH3cwBgT= z;5Odhjj$-YnT-v{Syr7Nwv@}pl7~aH&TJ>ci~l9uy>ZPWfRcYR0TvcUPxzM}A~Zc1 z@iJGmOU_XtqOY-lFMiW|s6aHJ%b_au<4u;~%3v-i8|%P$DwF#B=KOW}=b=L~3EK{G z^Xf0>4srKRyaoe8t*#kWUf9@I<_2dkb3V%i={1A04-PxN(XC8EG^hlScMTX9^lpB> z7HKtDjy*SiIjC)clp%*@$bhhLyX8A7*qZQW3c z+Bu{^K9-aqbIgIU%Q)BTi0)bm?FqSd++h#yANlVl?b1l*GkCSUqH?-O%DUSSsv@te zJkznx%9a}OeRAZa$i3O}ZxOl~Ao2Vg#z_Hwr4~+F4P46U`g!`Sx+ZRlWG~ANqBbVB zQkVpIWTyl*Do&LkNmFa z)eHZ_CE&SJ!6b~rkz=A`(agIb?)mj=s z)r$X+_pm~PHvdUI1o~wqOb4uTSS3x>#!-DDH=3X-)~$-<#aSy3GxF@sz@kOmV}c^| zCQ!i~M1eFY)#Jq*tQh8aG8`-~m5#Jk1&iM9%2GGll+&?mcQo3GupERM*O7rDueyO40>7pfp)wFFzE)ve-~p!Mrnj#kFV#6s81I`PdMTcRc(rG&--)~)m7ofH!PGlf?k;RM?t!C z&t83Si*xMZmmtv}&2ZDH+1!XJs;uo+VQ6ST@r8R-Y%T7o0cBOdl)foD*JW?sIWZB` zrQmy+%7+283rI8a5`;(D8X0|j%;&cE7N?p`#*I<#T+@dN+%#iYA}>EyP{04~l>4f7 zaS8@fl^qstPVwm#kh?A2Ukz8kcH;_Y1KPY9nr&GPnoRNnpSslTY}^h&rGge@ej3pv ze#J3)WXKeRBKyxFEEC*fm;&^!M6mNe3RvF8uS>I&ug`w`ZWVX_H7YXY{11W{p2;Ja zLs4dR_-#W2Bqnj$@|zSmAt^zk0XTqxZIOb^tk5Y~s8)j zxuFLvr40T9(82BtBqAme7I-*dbQyAgiZ|7HH_Q0 zbA5fsrrV=d`Y(IPVxy$<{5nf^rN$X~ZK617aqd+0jJ<{D9nr;`ft=*mFQrXa-L%?v z?d0?sPwzd6DE_Zz0ZC4dGTqefO+AE`-CTh(!CsKo4-i?{=ONQ+w{Hbe>s?z+F6(@r zoKgcOnRVHn{2sG;VL(A)uF_esi&)etV*%w0}g=a8ss<&m)!;R@BG|HRb_YI&SKB4Nc!{G;l1Pc_|Ltt+1D}pu@~_G_;mI3@`JG_ zNDtD5tEa0t%fB+lK7HF9x%w9zV2QBG0eCZOo~5bLvZZXH+lgoWR2LCl3#V z5vf?x@JQ~DQmFoB1~vtO`t5_(rDvTX!$Lx{gDW$i_dtViup?ZJoee&T%OL4glbltaP7UKIZ48Op*`A+tWX zLmw)MfV9~=rX(gPt? z!9JJuWw;e%UYWck<^1hOivZYE6&}yvx#`3wMd67DXwp;xmF9Fy;!;?a3ahs~=n6Lt}QDZkOI1QeFgXc%^mPEkf zL*Zv^;9kSo@k!bLl5UYXUbOHa+F4u{*$8e&zfwU$#BznYc=$OczMvU(l1mRhN2K*W z*nV3m;l&fLN+XQh6G*nl_E0!HB#dsKM}o&;vlS`yn;p>q8gde5V4g;_SYqZs%t)B3 zBl!^RIN>_CLae#nkBivT0Z4l9 zGY>QP)n_>eL$eD=gYk5pNC#Rdw-<=UgxO=U zR{kV2T0-+6**RMsCyfiut{vc2VT1Jdvf~&7W6Z~k5jAgTEY^M(ZaY277sAh33+!Fd z`jc$&mjiOyE`9uK-+4p#_P;w0z(d^hAIDd~6MjV5*L;^kH;5Mj2C-oVGkDB!(oLmV zL7OkmIKWPJ5&q^E!Q6_$62;GmRNi_B9#{Pg$N+k4VS+j|!7@oi1|I?-Tm-9hr2}1n z{vWuSks#1T0UJ>ucnSajYU3FNdvyL80F0*y;3<6Mu^kWn-xt9Ef&!)k`_OT8Nv^P? zu%;!{goV)N&5%b>KsiVEQ51jx-Yv-BB}28!N=ylvLI|pf%|Hc_#s4UsA5*4{q9{0w zV`cz{R%OR`6n@dM>kS!-SS#oyfR{-D5kUtE@BdI_N!gA8gn`MLqdz$!4R;R~RCNfA4qOKks-Gl-XM%(XuvodCy}N~U zGS#sr)1C<#%5UOYezuiRJ0kTapTS;9{sndhfu8xGtE+(Al~xJkZ-zM1p=L(B?G72( z<_yb9s4Y8Vj8a>}uJ!ydhf>jk(uc_d+5pEN#{KMnj#Ia)sE-+$6q{eyIm$- z;Gk$h_vH^2nvE)~EztMgxT?Q9mBAC|@@A*zAQ@uHpsqfDd3p(?x#Dd~hTsuC%N}nz zgnRP16Tey>f9nM~$d46ZC|mCVb;ePRnQ@^*ef+`W7ly|qH+{e}<8sa=u5)ksG%P!K zntn&-9&jszVR^LFz+IvZIEo@T^c_EszJ@A*47HMo1luzxcQhSMdGQ+AJ>CX?jQk5fBUsqmJgN3#de!$uWpM7Qx!<$O9{A-KY^Bqe z9X?({G4dXL+LJroU*os-;#1=-=QkQ`;H4L6?GiNF_p=cR;>VtFz`gmS0v%L`!`OdB zg?|rtUyt~p80vGwmtQdY?fz@Fh$j1Z{-i4!`76+ie(b)Hh>|1ieUpr~j9C?;i4lwX~AQ8Q_7bsQ{}eKIIuOkA^2 zQH(0={h^#Oe^B5g$EZZla}In4ku(es*}G*BohzCHJKqc!L1tPe!E$ur;HCvaQLST^ zw57qKwO!EP4z|sipy@y6uSFIS(Lp@BGmf2$PMsFc0znR*i?-8?M`26E_DfpR{)eI` zrLWB?mFG%s_`B#V!9Iw}?E14XJi%RACynZ1Op3SNyqD+vkc*(nmd|Z|@PseFPPDtm zasbCmUqXyu+iv-a?}DbqnM1W_+{&*71AJ=%K{6!ha2Gr!hj!(1C#gm(($$~#juyTr z6Q2+g*}jjBD_w(LA+trSbSk+zLDnIBhwY?uw-)7toq);HPnO`O{Ady=f_XycZL`RCI>A zW`DWd^yP|O$mPy2RnuScUBOTy0Ij4bs8YnFeH$;Wczg`Iy37}IH?wFrwCM`eg#k4k z=N0MvqRz;4%b{)}B^ zZ%eH_TV8*;yFLc{I?fUMI-&eE!*k?S^l?nlihw{UhY)qiCam?0>&))jsODGUj;~K& zM!`L!K0c0gboCy6{B=%wW8PxrO;c2V=kR}a8=wE!?7B_CEec<0vL)Toy~>}K6G&4p zKYuWYE~;LC@$&RmdGu>o^f)$R``^ZoGiPt_MlTPfKk}R_7lOw!&c-rEuO0jL)7M9e zGW=T^93Kb-1xOunJcYwq9pkLcyDb@S$YEZvdI=R{Wt*1|x7bpl}c#cT@;qnFV0E;0# zJ=tp;w+UNoX;P%5+f%Z`ykMbIr}c5Lv#PX{inK^Co?qt{&wu<@`CkmoHC#Mo>+rYe zf6rXf4dSWSW+f8iUn<9ZWFC-u69fNgK@oBbdC(_ENWr{8_lq08VO?XLy{JQ1d#`gIY04 z^HbSQ?aKcAA}CFH=Yn61+Wjx#hj*m4&aNn)v;4ejcVQ={c-`TRmrYX!j*x*%%1F47 zk+<<349hTMYj|@i0~cA>N76w;3~ItS+)Y+M_`jDsR(hY?Z#P}y$9aLUHX zKYs3Cn9ppy&v{;&_XQt8fvwt}%*f&FUbY zghb~cdwt-Up}AOWcG_@jgjaU(3M{Ev(y3;RThVI!`RwV}i|_x9{%-t?F!;G)v6GhV z-P*h{zp!gn;Ta>wRi2ZZKJ(*N%?k8EH$2e+o;tiw;Q^B=Vos`8 zv4r%i4{1R_9tswE_GoPT*z>bDehGlQX9}VvD^f4J?x>Bq{3+&Q#W@$iaDn)MO`Meq zlp}p=hC%A5@$o2E4dVlB^Cb*p*Hgvk4~WB@K(Jlw@4L#6u3a%9zJ}>NVjw zl@9P09iQvZYVpS)u0_u^95+ra3A2((fBUuLzWluR$%XNo$7ljoY8kMY`0WJO4<_*o zNxqJ;f;m@1mT;}QZ@vl^J%k6&v>ZUAF}-HVM#2@(-HqbcrV14rf8fxj)6XqkL)x!M z%OoZ@Ab(<|yNT@GOS%uS#rI<~$4aad8izMs*`2Ar%buUPgIIcr>4RwBp4gXDz&Hdb!h7mK)p)#LBxa=8E|yEjZ}!t1fT~w08Ft zN^B*P6-yn}yBkVmQ}h}FT(8*JqR+0><>UJsGH7TEvk79}f!Cxw^DXFiSBqaOuh56I z|5*DR{=KL>X12H9QGEFG)Dje3KG1R0gd|d8!~dRJY_IdFF^BG#wl6A(dGnrHd?kGT z*wH$X*Q8OipA9#c8(vN^xe3tBvZEHUt5kKqXJ;?Dp#^7*3rDOF~*Cgn!ee*8j}1f(OKY$ zJ1;F>dQ>XVEwjTW2lZpqg*(imu5Q`Ulkg%^&rv6(f4sj_3#6vBh_pm#&fuTHf2b4RvUH9yp)aCGP_vAbTa2OBo~{mgBXgHAjxVkOF>UM zBTH$;e`S&vv%)OO+X{^k?Hw7kn7mURv#6|)KLOL7(h*3&WGY7r@;c@8UnxX{NzRr` zmn!RBxwUylw^vReu9+n*Ka#Db=mWda02LqR=0PYv+L?WMgg;bXm6Qpq9+(*0yAJk~ zRrKrs)#StVG7Mbb-^@6=yhpm!9%V?OiXxD9FA!sdkcx)=RLvYNnxjbT&^hZy2FcaV67aQjS-KT`Z)y>1*~}t|-nd`Y?E|$R$>pqwK}KXjB^L3M5qjLUV5)`5DCiwhiAIP9wZDl z>fP!25jN^WwtS_p$E1!lQKV2pMWN5Bc*Fa7$uHoqyf?pYGX-s1VhwdczI9cCJ$h`93=wb`ya=j@?>49_W!hS9sg*=yqd$d>CJL z<@*KYl=IPG1mMkKu5lo6kuk5}Lc)PtDxUb-Se z2pl?>vo?M4=5*?cbxCunOo6w`L2{s>ioUXaM>RdL_pS=8l`f+!a-8b(5+bVa)u*$4 zXI<$w$#}ZoQgz<4xO1X@Zl`(3eEd#uM(FP4FQ%Vy&-~4R7YfoZ5Z0;0HE7&DaaeiZ zc2#iv=eNj#icfgI!vWF7LpP~><-9)<11sai`sfo4|8Cp}Sw6MW6xl8M*LXbl+7~(A z_*VwoXUA{8Te$}RP;Vg{+U9-h$E~=(**84pnna(Ks^Dv#;t^T+ypnux>^zVCmmfCK zCdKlj^qC((%bn_sC{FM(`OD-g^1U0rUn4@^Nxs`iFnw(P5sO)n`M*S)BZ%_z()n=Z z)X&Cb_l1~&)Q`zL8IQJZo&E2(Bn%|GXNi1SrIJ{e|BVb^59A2Mkjm$MJG*R>h*`&- z7o-FB4_xe|W$DjU$Jx_jt;(@Vu zqYmubp7{Or`hL1>vx~2?r}RrufZW}I5mkBlf3j-jb!v~Dr@ejZ!cI7Z4G41)ykV=i z`Xo7Lkf8PpXkEqo3E#<0rb2v)hGJ#t0H8iKVyH*$Fk`uw)YRLY6ta13;w*~ue*FZR z@41guI#kY)Kw0C*K?zKzfoegG>MPOEe6&Pn!CYUd`9L0O&N7K>4_!L#LcK2zMS57z zEP^mn(~a@{?%JLfMq)BGBV15aPy~blEU}d!EP3v0j3;Xb^h51(QUf4Ui8kyKOIs|4 zonl$cK+J8%K8)8!&ek^1Q6w6ux9J)9WnaZEzfl*sC4ABqb!JPxUj#wMuAUa9Z zoqJRZ^t`SNoSh_+ajGz zYjY+`AH~9BSVn~R|HZ#L%vO<}vXpMN6z#IKp7uZQ3bi`JYQSDQuO8r{txC&Nt#q#V zsozYE9^Myh&DfQ=ZKvAyLp@u$^(b;J-StYA$-Ftw%3Yl`4(&{9XRJq#@`wBGt@a+d z-Y`ov>4h63xMSXdzo!4g=KO6W)Z>eFZBs7S7iL5rvDkzd8^KX4UWZB4?8f1+U(~|` zQh(R2pYK!krUDygAdMbKi|3GpT^s&k?i;ps3+37AESQgo@Ss)xy*BH^7g_F&1S3pj z)q9ucKd6U2+;E;Y{590W7p*`0QV;h+Qbn+LBAr@lj+m&92JC^&)7G!_vP?Hw#zr*1 zP^Ym~$Y6qXd;glXpHzdZ^}{w~BX0D;97WLvtriNP8USR$*Ns1g*$sff-%pRbkk;v+b?w^13p*K(aI7(((*zlLD%8D38D) zs$o1;Nl$W#WNk>I`e`5o)2zS1&VEU-RZknL+3YtQ9yF=4Hk^U65m13pD}zdw34>~q z!@{GUaXo2u3N^BsEBt^DQCK>9C;4%ZP2}0l1lE^;i@%ImhKE>dkCh!xa@gif0mr>(=K}Y&R9XfqCmj$l!4C~?QSg& zf;P+FpDJReC=xT4t$DPj&FRv=5bTvxLjdUP>pRjnC>w4z@Ii|B6iB*iHc@pjI=!!D z_0mYS1OFyL_RYKKV0TfGW$Aa?8F~k;2Pk+s8`1S?xnlzsCh3xGTS(`s%FP(*E=$2f z%S!dmDy^1kCqUpZXoJ}G0|GWeUFG6!Et01|Vf;{mcvj2$v+DIDc(Jz%Hz?H57IAjE zbY@@FP6$z=?n1yC#yU>KX^W$KEFx=A!r;XBR&mJ>LS6NW3M?OKWAxytf=g0T&e$ZZ__)H$X z%+AIaIrdinIFTfMRC)^e+w>*H|B^hp1)RIVmc# z0QQIIr4y?f^CofG*`G`k>zrQ3d8FvhOvEwXD!yFbu@}E@rgGn%8{GZ8>H6+oi@2U` zdc;JO?%)buXmr>by=C<9dyF7a6=QAG3t2T{X}1noYy;R#(8-Q-qFpwgtbsc+`W{;M zeLv~@eZKGa?Och2{)g#Jj>pvw0@Vp;oH|k_c0)gR zMt?In`*Sz6VmEl`T#FJ2YX%O-GzCNWqu<&1*GruFZ4ht&ApWS~xsc$v(=k7CVsG-E z3qPFLqJQoj?LktpVRFR-0pAD7Hy)(iHcWl+Aoa=55~5PtnBn<156*uw{4Yew$~~Tu z@j(4$Ci!%GIQraw2fET_jWSe>-UQ1XsO-G(TQB72bE@z;CvxatjRzSaUD;=iXj(rq zkG(WzK(y~EqV0`J;$!|L|Kxl$Id|ZoQeL7_!BAJh*xvEC_n5s@3mYmqcq4P@L6p

had2;CRo$vA(1Fp?7rEgr6KH!3-?$8e21as7MN(N-ZE zrs8CGrAkkoR!`}PzH^%dEYPnoW%+|BQfrhhfdVVAK?m3rRZ|}HDUdWOgIlOsbzQ&q z4+Ogc!d3PuyffzM87FvH`WEEWKlw4drx8G%&+@~R1O^=K*+X9+FHbbCmo>es@;j}S zWZXd2FoKw3Z<$`S=BR}7+*C~0sIoT2Mwzxz^_@knHz|@qER)Do(<;b8V!n=gW>QdU zJCm_nX)FJ)=hOCU;|2(^c2kdXTih!f?VltZ;nM2cVLRJ#$7;>JrQ@!a8OyLYHEGW;mbrm^pvp=k=AwcJS;ovK@g%Q;W-5!AW6KKw5 z!z^W1ju_=kd;tF;%53EbRF_ysz-+5o2Odqxo=*zQ@1LdaW@cz8zLSDo;_52q!z}$% z{R$YC3E@4yD>vpN>u|5NUM5&A2;w?Ry?7uUI_IfR0xRi3?%$)T$#TJzyeGYoafwom z_f&I62IndnGgeF=M?VroTa0VX(-j`gYgsIec1*spHf4jj3n8Rx#_1^Pn=6<-thQDUE*l2P=G4iYtT9^l159NMiCTE3s0p>3@F=bY#guFTpE zm^EQ&u#a`mN&Y*HP9q5a$#73zIDB}={;-<5xdn-(BW7u`LN)AiL`5Dq3++$LfoGRk zCk+s)ZbG{Lte7(%Yn*zfL?>uoPCu=|DoQ-fS^=qZ%Uix3R;$z@80}X;oqN(2N)_j{ zS9~9bYeP*+j7sJQE*#MI6v-(Gv@ho9`AuQn7aj7HT$(Pflqep#ggfpTr1olQwAhdn zvpm&Z7IO6Z;dGd&$;D8&dixUP<2@I{j@>v~Yj?@yQuy)K6L-%17_mOun>Om+b|}O3 z(*rDrbZYdCtBYVRS419*+Fm;Udr*&f8uh+lYp#;e@>ian4ph;(@ zI7|F+YK8W<4ju)0RLI`E+Pok{+#US5poO&#^jQHl_Y>P%bfQoKA2d6#HH2!F2x54tU$ zxCihRB^3KTKL2ZTt>eL2pS`?og9u2 z-|GFhvAQ=|Z^;V|ciC2@BLkSjf5ur~ydo!_9`G-48x#*~n;4Y5)w0pUfJ(Hsb&yog zO5+F0a^T;lZbHm|%#<}FezN)6vO|!^;ME83c+e_4Y@p-0@~bO0&$XY%voz>zq`hoh zUedt9pf1Ij0e1FVvOeEe=){9h(XVtnMUKB09Rbhbn%$56|X*G&$#znP$PUZ z%)VH;Och*}Hm+Tdc(`K>r{(@X_xPkiYO~rtiP?;hA_H|t*`$MY*(YNjz1H|hVm!T; z4D(i&P23shJ8JoPUG3i#OrhqXEhod7 zz99+TM{|)%v|FMZH-b;Ziy4NM{J3jKx9;q8vg~v5Ub^HRJ-bxl|IzWiLpQ6hG-ZQ# z2qi+yk-MC{IRd+jZR#Gn7M{m8M#X66-_Ca375$ti;+|70IgSl`y>O|sGqg_PSt?v6 z)$?ZG8n@~`FR*lW13RAeuBr2F<(Kw%8xOZ$o;smA3AvA{p6#`Np*r zlkVX&DXaT5sYr$;TsCDrSBqB@cKdTxM2q8}Yw=7{;@ekBEpj4Hzq$>*>fn5Iw>mSb?7MNHK;tEcX!ULAPuJjDid!*RCyWH~kc|Qp6psuG}YyK1tGrDPK{7kSY zEHfija70ACU0WcIdty9ckEW~X-}d9uX67<>NG}$vTKe8m-xiUjd&QrotWUNDFYF})W#QGlJC1Sf1uBZF4|B-J&t(^}D1dCd<5)GhBsGW&19FGMHxHIkA`E_g_9D66vr#297Obm3_Q><>wv4tn7 z7F6#ns#uCYn^$U3G;+-8kBvRzA@MZm!N`d6rB_E#U!lR5g5wC-G@q$xiblKGpJIjWB`xn)+%c_?2 zJ{wPTzwm7;tNt4Q*>q0)X!6UlYd`LNHs88@^!!HIb>_*C!ypM_y1>P&mjm9oP?!*} zr>m+2FI9mgq9Ov^h!BxqvDN1GFo|jDlK__eUURmk**qzsIUPp@XL7JpmV%1MZDgd7 zj(O7*K2le|UCfnZ)f*!A!cQFqNd#mpw}rfJ4uRfe@}FZ`%WPBNrv2%>7o%;_AHCqm zs^1F4##_-W`z(d7#0bQbsW*c4*Ssgft3neRieA!b6YDX#dZqbs`*;bnkAfCyy@42? zHAk!Eb7=4gOXerO7;&LAQ*=d6%I@kYVN$|-#I^ixyBZjikR^#Di7Dt~2aF0li^1Lj z?fQ6IbEFF25pDzG9CKE0K1i;J&2-r%&<@$ z{&n1aac(1SLQPP2#*$y?LyqJ+2{v@AU+X8y-eAQNJsH4(!aPdtRULo{(Mo^mZ+XWe z!^yduTUHPi+jMz$3_1iaRO;9adl_pdkXED6Em^IapUYNGE*4y; z*z1JXV9u_yWah`M)mL;s=C=_vz9Ov8#Ndj~7f_vE=q+S2H%0?&>N~WrI$vxWe@%gR5jhc4w7EsGw~ms`kgJ6 z&*X_;q`HV6u~HWSQ56T6VtbYL6;GZQO}aqgoCRD5*s>oIwOB9nVP!y}1yr0?#X5Fh z*g0cOl^Al)xSnqL}>6=4_o1{atF28E-FHhYvhpB4(y7J*`f?-zxDepWFRo7Btx-qC{ z-Dyl8*4yQ5q}a!!36+;LT7z9*^nl7h7o;m|(faMUX#0eL_o-q5?br9C3(r<9L$EKC-naXfs1diw#Q?S z$LI0c=ka;G_x`-!&zFe_pa(0t;T4%RB8QfJ;vCGVNCsqhteLym48&#+VXk+zSNt9` zDo!3Nxv_PG*Ovd{e%yIh(&giKin>!M87{l072R7uxRdE=pGAA+`L57lsqUim1_#8R zqzwBwCC?N6ij^mf!&YjP&aXH;__#x+8Lx_?+;2JG4wp@@)ae#@#F;itOuzrS*Acp< z!QO$E9TvtHOC!=k^rMxfF#WOW@l4T*q2yQJ@9YPFNr1Db7rTZr1H|v#ufLha-W`0# z{jbV$3!EfTjbPD1>Bg@rjXb3#Wtm_ukjNE($NSW1TRS>r0Sg`YHS#@I7$C9^Ca!HVKL7iL~=D>oxLZ?7FKHVyXs%g#z_zA+9`3>pcaQvO+&wak@ng z8)79B96M(ReuC2TV;Ay#?Yh?r z{}57Iw-Yf{5ox5zud!|Ph10(B6!h!Wq`P%oi^R?agL~OZ6Vx*Q(GkwNghA;WtqiQI zoiwhd$)*;z4v_X$Ufv|3pYh~dg;4MAl^)QP^rK4o)*y#_eX6mN6?~pbCsDq-M)Jw( zZZ}IZ*g&dr@D8U>BD5yf@1=y%ec9`=Y?&p!NC4#a>Ky_WLRr(36on#JS-%#6XG>LY zN4Jm|kYKEWQ}DPATE1v3mOyC9w|{dZ7PAuD8gozavw_l&Sf!u$mHuuh2^nI+aafU7 zEMgNYZm293r!3p5thlMHY^b6hr=s1eqPMBSu2*=ARyA)`9f`c&y{;jE!n}mgNYSI0 zf;m=k>L(gb>-Zq{gJBehd#+K*dxzH7jSxQGls1$Kj>dvb0r4rm>>7!=;; z8&|*Yo+0k`r3#9e($h`-jY|O;1axkVJ{C}(a191Ebp>&0|VNO-4iS%LlKg7ry{es#y-c?4v9Tn z<0($?U>8ph{1bvr4~8!g6{qZ$iknPJyflOC%?jeJ-yXAQpor30kah+-SlO6LHBO`G zjWwhW#5gn zTrRd9dgcA!z$MY#2}lr2jPC7rWh?rZvx-E%br)PAz0dKFr(8>kwKjbHpbxW-r-r&F%w7m zZJMJ|iZg7%Pij07A7t)}KWJq9quf6p3&S6~YzWe42@zVT$VP_fr5emORerekqyD^t zhMkJ8og)5oU|)h}R1R}Z2%{z>Y1tlL`VflYNp3$p6-^PX2AJGz%?~C>H9t`7y_`63 z+p=iArT4W(Xz>{$UqX{ak?3f_%o4**r@|*I?9&*~1{0X8v`I~C@-_%cuTd1$QG#h= z7|OK@clIPqF*kWiO!mJ2?1Iy#&S=&|eN;X>o)oQIX;yA4lD}nLlN58f;!-37Y0pz) zuw~PU=x34b6M(%nL|NS$m@rR#)s`4nrU|R9M=lksJW2vT)b!k=c{*=2{EOUQ_oAT< zx$9-}swUd!>^lg3=c1ESE=nfPm!;I0rq(B?-hGt%-%jd%)3k@lX^$VJJ>5xTo2K_A zrwdkBUp=y?=|Ttu)saW%qu)q~sK{L6iBG>d|K(Bmo1*=*L?z7pg}=w6zdzbvyKqsY zDg?MIh^wba@yTX)z9{@`xG<-s^%w-5NbW9Pm5T*Hro^acZBx9>>71nu5v&srAJ4Jm}jGt4U5HV`au8BkZhWk|VsSh*5 zw^QgQDnd#XMiJUJUpL2jz0MqoCAI-K_EOP_t;Uep3PE5vR#yM*m#I(U!%#&GQSKF2 zj?^zVl#5$aR#?L-s|hJy)xePmu>md#Arz#XSoy`{+602_GS%`oc!0|jZ`iHcII)s& zOTjT0+Rb>{NenwLbTWzxvK5B17*D&2VW0XGH*Lo+v7CRNjsy?x#dF>DsLb4&%ryJ@ zxJBP#an-IiWu`I?)_sywbNzct{paES&aHE!wc)eMXh*GMy~N3G!uVHvZ$}ICA3t|@ zRg4T3)M5Z;QBtdg3@->nqiPiTd3S5BD%^7aN9M{utJ|$YpCR)e`E@o~@{7NfT@56> zn>E%`ExvV94emYF>r-Zri0QS_TESdNGLIO zKm*cMr&z`jbdFb&dVTueS+aVX@9~r(M{25ieL&L@O9D}>Mrny$yiud{3#dgRNO9N| zK9&mYqV+d!J?$WZ3vo&v)H?a!?e7t~*Z{9_;h|1(7$<+%dsTn;!~=6b+*RVet88g< z&EpjI-V8hO1BNGp)PG(oA)9A}Z`CLc*{-fCOXkZy>a!dTH`!|*+7j+{6 z(xN)D#HnFW^IE^Ry(o6>#^SR zyZWVu*pGVLelU2mM45FKQkSiu|5(${p~_wI=ijI{iB8xe zp8Zgpz{1V!c@vC1RcTVql9BCJ zAm?=OvjXd&NJh4dtMZV+hnIabZ?9#{H;fvYYQx=UHmpDXIREkI(~p1ueiX9df-i7I zo^cWXxZ*ZEsS7;WXFQQ{vZBqL`Bzi*XLFi2Wc6(3NAgUAvgS>0+XR5ruA( zB(Zl{{^fk$zm*4l%PUFLm`{|7XA1=RGyH zmrn-Sf76VH7)6CVTl-cz_4?n}bG@JAKRNn`e4PpUdgeN%1@lehBYw!{yMhJiB?uDPFN}sc5 zcWVw-Tz&4QDzb|R|8?-kTHVFpw0XyzkKa+xLloS0BmVt-%>VOH`iqY2Z5#XIt z``=?1|J})$&+CyenEkVIkw1yi0LqdIIATe9v}vkncggod>ne=S&JM}$<6bt)UkLr2^+Jur^P|=XW zuaZ7=s~I%@j^}VdPv@$fTdw#s&}Uh4rY*9(lG>E;k1dK&G}RVzp8wmr<#l|P8;RRL zZFV>I)tCLxPALSa$MyV3wCqCNy!eR^fRKIC5!M?cdmvuEvaW9H*gVDB{~i+J_6*kt zz+2bqh&J16A@1*b&DaEY;>E)#drI`M!u}dzU@0gF zJ41e5WVSgYct}?|{&PfhYN2Pi@aCAGIO=wK$cp)Pb?&XZIdgn+NKjNCzSxGh3)4~=1^T4l#x{-sw)Y77CR;oN5#S=rnA2#LnUPkRdC78xg{nU1BvCeIEOCy;4 zb@kItzoLRu&527cO`WzmPkbIPZAW~2y7TU>ewV0rjU&n$>$-gQR}jb%vo)#;Ezdn4x`nTh+U!5*h$Sm6v;`?Rq~fxW4q1FsQHI>c#DjcD%^O=Zy5_U! zSRbw<>=ExlNP4!c4~ymSM#o_R`vP;Z!V!TpBRb14-|LTxzR4AJ77b+w0SAr%s0K2T zl(8SDg8C?hL+sauR!F_$HT_Z#-$z@^gauL!E`7U!a+c6x;D>Dqw?2Cry$OE`+2X~r6A$B;6S zm0XA!-bh4A$`0|C+i%KrMp~wZ$hyfOQFw#@j&Lc(3G@o1OOU3E0G{X|`i1#;Y;g>s zTkgZM>Y$okmrPk{a690I#+WBE#!n^dh^yV!)R@S*s?2gO9sGWI8FHp@USZYtg;`4t z%|+TNeWC8{@#+mk5Z=DLdMihLLP8ufO*Lm((af$AAxew&c7c}qaBs3inrce0vf zz~;UTpvUNCg&(<4Gx$r3b+$~ed8yxV2G@C24oI3W>5=w~mpG-a=L9ay?S04$lrY@u zlA5O_0Dov!WF9hPrA~Do%bcY^KJFFYpyAnBO|G3{n`miQM@%`2m{w#JZy91V!dYhs&uQc1d#E zJm#?k383#; ztwN)AT2AgjP(n${=zLr3Lx>Gn7!p^tt@PU#XS2!{d%rQ^EqY1&=&60ZHAj}%Cgn_z z9k2mBB({6MiO1vSaALevqG0Tel(*P7A^pTmBf%>;ujXCFzCZJbYYkxB1jku^iz4dn zXAm1{o1en!Q7Df-W3E;stooN za_xQ)i?4Piskm*v_pP-mZ5^*n?+Mkqw@k2Mf9Xu(kZZ+G#{)C^eRyG*w|Ge}TXmI) zN))KWY%`a*%LbqFv9BNAOZ2c1(6lM(A+p1^F4mjWq7N5!X@4Mb+CS2wsi8WodrEienNugs!&ujH6>!>g|SZTE@C6Re=! zXk=`F@Gz0pyVZlKSalZ(TED0Nho=RZC<;$q-}j5&?|*2c`}m)^; z#Y?T|Gl)zyx}y29D}i44Z(l|tj(*y*+tWf>=W=~VNC!vf&$~R$F6Vc9AM<vA8o+RjTfJeUNn2kH&nbqQpn>9<_Kz~EDwm?WPyNPf{_TWiUfI>O_Fn;10V1AhzMi-&{m;rFi85Bcn<2v=_R<>S)}k zz=T8YWCE|FQ9GmX;T++vDWsN)n!xqE1n{$3Hzq8pTA^W5yKprYFoF$SW}rR-{LaUM z8$LxHVTAkcB9bUpR(O!lI<0j~u_7h-taAHsBkSoXX!Q$~dbc9?u`Zm!{T+0!M zM*KaUJT0ZwFKlkf$9_<@n3e<(w&HoR$*0p-BpsBOx&3oEX{y^`rD|BHURN!9hm^I zsV5?B;%Py?s6hsVJbEdHq%()5iI;*BI#73^0Yp9tsW6B9U<;?PY{Xlm1-Tu|6ciI@ z5r|JHB%dmt)~0Lay;naepgXH?Bi{hT5*gMVV+9Xf^S>UKy~7Fqawgxd{Nm?NUQOh} z_h-(#kuNOnocA>j9&b42ktG`_VrFJQdd9iXJzaU>XL9~-(hX1|&$^<$2xNtXiYN!! zC8M4ZPO(f69FfhNl_(!Kfqz{Oc)E?`qD5hgc?W)Y|7YfOT2_bXRvCSQ7-e1&8xh-Q zRwEaA;b9dKa(wS9wBpyL0_A-nXEqrZjJz*CuGNu?LsXux&cr&}g3O%7gmy&?aX6@7 z=y$H`9^otR$(FYGE7jY`5=sKPAN-k)ddG-)4Ziv%Jh9H)vOeW1v;J!Hl@s@5uUX-) zJ(L9wG6}0##Gt?qW!`$WlFwQ>pIV9}g;#S_^d57I>MCYPS_$^-Snu+}thK zE8Q&P|CCv&fex-C1g*2@PN<9ZjH7J@h{#H<$Xao^3Z|d4b9qItU!{B}aCLlIvV=n$X^CLV8{pD=AE z@=ohY#Q_9$+jjvEX1mEPl8eRMve(RR^n_&G(k|KJl>NjbT9h-_MoScOb#}{yKd|ic zDZ)BT@`Ee4dpmD`Fs=Rwxbrf_pq+GPsWfqrknnn|RN4H}WP;A$x?)BiJcbU{y$030 z3z>eY@RrFdkT}i4@l4~c3aWW&QFVIAMbobaQsigrDab$w4NdMoZ+0k4vxvf+8w9_5?gFKvB+S%!nq3uXwfSY z$T51-D+blLo7ydP^aw?G1Rd^~O8b^8X&gaV#^QCuMNT=xu_~G0=+Mp#pnN>ad>Lc_ zK>ng2kGHEOXx=yT%1hbtmoB&;*I4Y^0Uxdqe#f#;z=MLcP$k%$L>BV2pIkn(>#U5l z6&`$?j|T^N-Z&6JbD~2zICv61-iji8iB6wfPtM>(s{yk4Xo0ln>zo!-cU9hCJ$h!z z6DS0#q`=$h$DJrZHA3DGifGl3hq%@9Sho=A&WacB9wx7Nlb;+r(wiUmJHNA$lq{Bi z=1McjzP9_3x%7+5)PSbFpL`^S9vS{I!$ds_^LDdlL41FR{Re2V;R1ocD&xft*LTLL z%&t*W3vp`h*)Y5h32CtDK5#4H?_{EWCUlh*aqhM?G$HfnsE8UKc#V@WO-FsFi)sN9 z%}59$P4s@#i5~z2>Nj(Qp2Q)zKatP&!M)(n10@Q8GC-ppE;4XE`DWdr7xHSc{8Tk3 zz=2(o;G+aB0PI;klD-$nW`)0}01Ifsy_A%{Ku`h~xkEy}1_ITXqF>gLSZ~RN_YM8^ zB6rH+YK*))MvMvU^Uq*l83nnHMs1EF7uJ!Li_$Weg%i;S+8IK@)d%=kv9NTJhksBC zTUMi^sJ?A`Il3q{OcWK^eMLkub>-2+cQrk!>~QUN6RSt}$-{EG!P9q07*X%AE5obZ z-7@Xh z{F-)_={=sR7!`t=rNAc{xzYW8Rs@leQTQMUu|Yu1FyXJb@J#;tUITzw@-}jmCDt{H zDC|cjV&y1P5#jw}GoxV>zg=}$h+SLM3_%QZ#p3CSEGvST&Qmy#P8l18zoNtMYgfml z-p{YTPY_2oBq4iPVjOy(&~Mix4lzFf$Y(6E*K~_3&=e;Y{)a7+%{Wth2GzMZP#8(e zhg|*26C_j*I^U!sOLqee1cjT+ez~nsBK%n zpIj93bRd(izGUm>e+TskkAQ)7dd3i!`U3yZQLEU;x66cIaZ&$9QGXbxe~+U6a#6Cd z6h0TR=%d>=KCvY2@s{#x-B#_k`iVD$L)#UBx3fQPvXFlP$d})>Khe4E^{0_B0hx>j z6^Vdk3kdCH@HrH7v{fW8+hCvwP`CNTXs;3A`B~M;87f%xsr~lv`nqpjRIXWuk4|3w(7{*y&|5?*M9$2o&nV5j?<`s#)$5gwDja+@<4jUu~XW%g;w!lDsLW;3*$cyUYT^QtK(3e!L&*;mbH(2B#DawR-rrlE}zXI`z z@b&Q#L=x6=&ujUw!^j1+=(9GsRwAv0fq;HQuGyY-iL<Nh?y5mc_l z`%UBy4%xcCxgRBlPeY$bX34zS;PznQ@uztg=`=!phQNoC}VfoeTESL%9=za&$Y&Q2K!i1pG?DLk}1$Jet1{eztbH z=)BQVCUcxC$>Q87cSWs-7thJ>6Vm!;?lfZg^1~aE;ob4BbRhfI?u>@FXL;SiZD)By;r<$AHHsrEhlw)TN~FZpe*v-b~zMIljsyt(IcmnU-XXGnIXzw=uE`^hv)JkJ)AXjysWLuBI0(moR{ z|7Pcba{fz=wrj@s=S!G&sv6a?$%kv$DIOK6R_dd7hpt#?-bgo3Sef+ke{tjF@1(CE zo?e9Byxci3%S-gozj!hj?z^*AB$mB$$%wo?eMMRE@9x0W;ZvKA#a#eY{6I%H-J=_R zC|&5&_0;tfkepi-in5)Feit*p9)3vww$Q7z7&Eks+I`18M;#5Eq>hK)ciMYO!Qkl@ zdQeLQH!!BDl)m~{^Jd!Dh#Y<1h40LR&;DJD>D7wVQ~(Nn^)L3 zKz?VZ$*(310aW@7>+LV$xi)2OULO1VjE@~QU2J<@L}^eKv4V&=A{6YO7CpCh+M1{V z8H}ms9sBOE;pr;$ux!#ddGX=#Qy0Mp{7!-E5+^@q6}eA2pHyhGI4NQ+eInvceY^kJ zdwms-J`Wb#1I|4Mn+C?dP&b{H9dt51nfT`Pqm#)W&zE`}tbbtA5PmFryElzC@Q9Vl z1Dg@3P>l|P1RFLl`k7?i_;K!^UhGGjI)oI^G;CrPQe?W+F)x@57%GgLkkx>s#?P;w zxZoM&d0JiZfT2ohgTzS4wR8REXRg;IcEC(#-)df!Iucf;m3zv@!m9FGfW=aII7X2E zedl&3KeFlGEHmQf2lgjf5zElG%ePB00TESoHfdg{>xbmdKKhtr8AI6^_i)x+)(@U7 zlz#7pXnES=Ia}GMb4>GKk1z5|Yj#~}M4@@B=$HJ;Ls8L%=;s}^!1{_O@goPJCy(j# z**sAzckt&sauk?DiPwIeB&>qO5D>1w+Wmbt!}ne{(yBvCc=B(KQOw}QZF|@Cf})K&yI{z8 zx(qtg#pV~(CRMFihpr*w1EZCsXO*1qQpIcoW)249;AvY-7x%y%`c#-24WNwr#(iN* zUboW(2%)|#zc7k{X!q~yuwMf zoR^$8$TWfLw{gPRlH4nHc@iMC(*U*lcVE;mVP5G6t2QgW-yua15r3WDZ~1i$X+jSx z{2eQW6m*-Cxk51EJgV-Ds@UbRjqIe}<4QMuZw2J6rwnWz1=a6$b?|+C^$q_IM&&aP zY0Y3j)W{&K^_rq1ITyni27s=*Ng2YF>`wbWHW`(7DnCc1@;O87@L1jM?;wk*Zy4(yFG%FkGM5CJRG#5N=MfzCM zmgA1rXPFr{KZMBYnDJalULdOk`#q=rHXfe@RH;zx6n~;=eq?lR^1{5Ff!=OpJa&dnT#PB;}F4lkB<3H6cZ6-B8+gL zRss@0WiAABm4!W-X!u6l`D=^%+q$6!+3JW3l2`H_MhK`UC%-0D2IjWy^M%g&aoi8c z|MY|Ion8iE2*9TafXOp2*`+E~%E`Y9`>mHYoOF0SnBP_XXF4RkNdKwi%! z1GK@myKCl~6_c0Uk3V^(NV-*f&2!29fu?Tn;*w*-$!`_Yy_(X}ZkIqUovW>nfmn1gd=B)ZbEmipLRsYQ?OWmf#m3ewX17`n& z&5gR4Q&_NJHC2c=0~ci8W!-tZxm(Ne`{He#=~AyspD0zM{6(uX7N^|%bTz&e5b+4? z67@xZu#3&;*jv~<3ma3W&W&Wk1;fG;2ZVt#l2do`aWtG0{*%4IWu;6OYws_Fqv6&D z(mMA*OX?TWJI?Dj@MBIbWXaf+ce>-I1-Vxf`x9Fdt#4bJPW72eX;~jqp6wd*R;bCR znys^uCb>!Ay9}3z%*U!;&5WbXz${F-!qVb>xz4)(90clV(Z~gd+DOPi(+h?1+QWy2 z9^Y-r-XCc0{pd>8bYJq1q^IXD?7X*niurcWjV8j!P&37}T!r8{2B`GiV+E6d)5au< zup~)YVViTtD@C$cx9>(D|g6YuC%magQAE82TX^0wq2|(X(lIgWvPRP6gs1tKxtJN zC+C=MHz9G}DcOpN_6S!4ly_rY#pmLbpilY6mbHJE&O(}p#}1D_89BLp5t`0T&TvTE zs*@!L(GGTRJd~>v@D-ykY}C$iBNz0HZ5cV%*ypGVYpRM{yENm_rtKFlK}zPAXoFAn zzM&5Gi>z{84z?)IUg>*3`RI1ahv<*-5`2E_)K!OwkMp|ZxxEM1ZPFkn7Q|IGY>!;4 z%-mNQp(0W>P;r3;(dm$UuEq(LU$lMk<_8nL*i(WvBRd*5D*cN}2tF~AZH@s8XZhem zF>vK#r{CEc*2y_+l#-Rw|zIm1hCh}pMyf>W^vkU7OW(l2We?7 zGHvpvuk9d`-O6e<^C$KX;%}5qUm7#G+jpOx?Zv8F$ zRuTKg8n#xo?5m&MMvgtkQKh@bO!y_TJumZ=P0D)AZ#gt@pEt3)Ehc)b7aaDKHjRk% z*hu!;sr7yd@2Sq~vG?wE3hi}H=yl2JbuH_4yVdLdr`)lv_s~S|;jS{hF?pJnFcVM! zjTAkaP~5e0*}KiEo*|FLIvvUC^DA>&V^LK)gb{D$WpKbZA|P94CYP8$=$a8=T&;ua z4>5N3Ekj!fHpWRnY%cX^bzj7-{=-(vwOYb5qgf;^s6ZuMR?Yp@2>CydN}(kaXt91^ zWjj&)eXzh+JI5+1W>N7tXdLTBx)n4O;8IJjJ+9QNJmaqb?;fpeE&cQ zc~?BGBTLlkU}RM-KeY<_>TDa&K3{NHQQT7JG|N&y(h=KBrA>_2S{R>6;?w%7#z1&T9R#!k1hDbIs_97xh#95 zFjq*B8@0pI^S8h8p+;BTBZqk?=QJ!kSX>lK&`BfHB49ZLRt_WpifSxqc>A)mZBRKu z7>Ccqnb~LHGM`#K#}jBu5zv?_XsYdiplTSVLlF2ol6YVehZfCn7xsoJU?I7^0&do< zWi3~39Wpvjk-{Dx4|S=fPzeC_Ags{1qfi9L;ux+$p||%*+pG7+2G|BjG7f6OHQ4q7 z@e@hVP?!{EIp;j{|MIIhr?XcLhVeVpr$T)(N>ArP8q039xQ~#*ihQ9^4y~dav|xv zv~$ZKD_2O8K$!z%UDA<|-vC=S&?VRLBa)IB&Om}AEw%#^(2xN;j%1lyLW{SGoY~2h7Wl*GPYij#0(X#@Glv|WL8If703a2 zcaMY}b$uKat!v^3y;|0#kW!*kFL_)jGjS9eGYUAxpd~Xvk}&9b*!cG>5zU#`{tqWd z^QbPO--Ue2j|n!p`R^qqdN@C-GjMrbqu`2ET2DvmeK8e;;3#&L55LLG@72r=^^h|kaQ08m;iO7OxATj4e)uB_!lE@-b7*vVR4xcgrRcfFyi6yY}TQiv(R=0 z8q^$m%HrV-vhPOMH5@4en#HnPwjcwtcEm)_Jv@RS-Q&mVy*Y128)a!FElwBzy&(e_ zNd{y|V!?%(+5g~Ej(sof(0AftSpsns>k3KPrNvae^0my%_%bl&e@_idB`|5J%;$Y{yO5ur0jkP%Bz&zPQ!6vtQIsL4Yj8DDXink9H8>!0l}5u@uU51;>R6umBRzz z;b8N4=If&6li7gxjA)1qq%AvX)9lH3Cobfg2-x$5RMLZO{ASk zfGIGu!h2|Bde((4;~i2?mWO7_RjAN;%&rqpQh#q&12vk{nPv;==>B-e{!n!~sJ#Fh zx11BRo0EwDNa}cdU~VFn0j+U*TQGK_kn-{ZgO(^mBiTZ|2L$KKWxOVf%=#~xoOK~V z)wP^PV*TG~4EKQkupmk~&-0CkrKOSJeJT(4Jv$z>4o$Ce&1Myxt&(_ot!rQ$WFRq@ zvUM$rSg4<=`pvfC4#+kVJE7+R~Ybi97ylmsMCo z_zT_fIm@}jWqi-_<^1;Lg8t>gspX=j<>Kw-637Z&dZkoj<eHx(n=WU$;boE? zMpm_iEtf$axcM7XtGQuDK5QXp*IOX5d^vh{N);{945I)Nb@cIYX01&AMrL2D*ZHv8 zdE;F(Iiu@>@IGc`bSY+QzLY=@D9aTJT2@IWTPl^=261R9jI2kq(_j6Bf*Vwd+ddD5 zz0q_PRvJC~4AS%GtjN}DWi|xeT1-p9(^9tBRNIMkI?e5Gl)QEROU%RhzP0zyeAICn zdQ2g{8bkQ$>}R9-lBy+tOzs=@e@@HcX@mI$2{%8XC5g>>_thoGw}IUE<>xaGbpnVu4KjfV4-cQkWm@Jl z#hu7mk32GL2_TEcv71|5C=gL%kbV zQ#rIyJX9wZ^@cSrcQ{wdFDDgG3+4VlDm9+9@cnaEJj`u}42_~M45mS#8_MyloHR1@ zy~cH~gFjLUv}+TaCqHhQa)*$)c6Pa|_(HFJf|G^jlYa-a0g72HtyUW3t}N)yq3#3E=4pf-^eoQ}0Tq3*Zd zJC{aKY6mthTgD4}c_b2`ig8UYN)WvNPW!&O6H4E#&}4q}@dRSXnV?5xk5FMOKErf3 z%a@bA9~Cc;7Y+=yE_D@(8Kud3P{XFh$;%qPENJR7=CzrQ$}dU_du5TFlLY4x?Nta*kpOG-wof#}|6x z6X)XxaS|cxA|4n-@h)8y3h3=j?SM!h7r?B+?~%zn0H{-gutn9|bmrTFy?+j+3u`V5 zsne|g-ciX${~WAdSmUUCBvvzv2~KufJk;ri2bE|Su4P;8Z=3?S>p6Uc|V zK?o-2H*V|hSzHW-B|vcPNa!;%a>R!;eiT;dzOB&7|DZt+6pJZe-lH}UQ?fL2 zs>T-*2WFr87*x}n4e#!`p~5Fjcb^foIdiNauO67fAup>fk}m~r=$`7bvy$nDCEml_ zm2;YC7=*UCO5~Ur_dTIC=h$WS`r?}n^gceZwYubOaHm8;L{i%;90u_n!RN<)8vpO? zj{a;{>dxku&pZ3MtPJQL{it2s9KSbzuTjj}uE7H5lIF3NsGo*QLsza_@&06qO2`Hr zc_qBv_u}$nD_LRoJn|#XWMf!-@J&&#`S~|YOjq({qJ;kE&4_DSZ&aL%6!LC&AHR1D zaovg(75MfNroM_FHt@s+t~s*Kuiga-60W@KT+agT_8hrsJZ}qmIJi@oY@OCscuxl6 zyXLhzQ#Wi3KJvZL>_;!qHSntWE;dWt-Ap-K%Ac&9BP;NeX^N@jw|j0X6MLj{dJR4F zTW(RWMp_CT?=$(r_%vgn-NW246F*J$~(IjDOjiU{6w_vJ%52kpQf zl{gfaU(D ziJszF@Q6?e5BuBBV0F zOpV1fhRc~fjeqLtVQn($6L8*S>O`_kmOKOY-9!I@ovh0ld!#cf@6%aQo*>alf@DA5^3CW=s~vo1H`A&?eAv8o0v|PSMC}Q>p{egr zb0uNQcFOE$GcYGf3!8q_%gAT(FnpgB+rfNi;_)T3+G_^B5>C?@L;HMe|1()`bLGfnw0fH2zPzM$8U zDLx?rv=H=-LTB!YzN&Ju4ufW%r3}dl@=Z~`o~VlyAoRHd1|Fi-BRkH_IWQzARkpX_ z{!3etGh*WG<=S?&b*}tQhl}a$5E1g9dG*VCPBA&Ar81;C#WlQ?^#U82)Rw8R948EC zY}`q01}c8$iVJp45SFIbY6YYDX$$kgo}ti#ZA3kp-sRj}t6-bZr7V>|W%&<3U2Ha$pAZklsCP}fSd(wJ zrY-=BVc&cvt7%%dI4+#4dBA|S%!-#*?q)Ni^(rJg`K=BY!yosN=l*Ew&+DEs zEH_7;U2eYo?~kS}aNj6Z?x={}x-#0bu4(0Qu8LDbkGj4mtw@b0UPbPeq5vTtff-17 z?L0MH4J|>6h^}OU+>Z@-x{;Lk^(;_TqLdM55B2P&gfAV;=L*WeT4kBvP?rw?6LZ5` zFft3I?k}ofvOWRFH&GS6c<`$dnG)|y2S2LW6-Ic6$dGZF8X7`5cis`Dh8rLzmo{KT zaemu>G3Rvx=l2~)*1RI5-fs$|;2xJO6`hH5vqzM*?onX6=v%>bgP%(JeZgsqWPR{~ zM~*UTAr+MT!+V|JRmYqEAelF>6$FJ~-(_?$mCa0b@W^7$6aokSu}j~c=)`2LY>Zs6|YB~Q&07i9yERU z68GrI>|cFykIwAIrAJ*$*85WpUS@KJ#h7?k=1+rML`|`XK%-oZC~n9UXq1tG*!y! zMssKexD11yQ1v|>18c#b%(r8a4aQl}kSl|qtB1JYkKk(;g?tc)JW(H~8yjk1&bZC> zxlTzolFjTZ6`7Y}G2ZxSTfO%SBgW>ig_3@c@(g+sB=U))0;0~x_x6#m{i zB-%EHO2i++8BoABU)jYLczK+GZBG0p`@NIMIq^)t4&p1@d;&UChV2I)5$nm+(V7!a zWfasXv2z73s(2*ez)68l>cX^_ZpDHXgJSkxZxm5DRZKP8B^KWZF$w&+iwI`v#l#)g zFk72`VG{i13p*`WRX@Ydbo$LJIhHWy8w?zBmX1ihr8*K4L+aumeOo!XZj1WHfgS)2 z8^x<#KKxI^>5`YeOvReGv?>*j#_@{6@sDvP0I0L>h|ytAPnvY~A&G7rJkGCnJDtr| zf46~LR8^BI4}~FJYtoauGF=+?AA*OLD!Kb>fZtBjEV{XCT{D4KzAWD+W;y+ep9s`9 z!8sh56)H(29ocuA;Bt678I{@rl->Ky1HNo$#&WQt_Y_RBjD~tFb+N!(AJPS z3uryzV9jx`^mA~S0mFAQc5-K0ax*K&6tCjIHp`hNijX;NjL5#6kBbgm@f&bacXGlF z%Y~i;g@@pv%$-}p|0C+&}X z6C*i=CXyr}m6Sf4IfoFEQyVHtLMl4>?fcj7-}|wD?)$OpzOMUyy|3rXYYeb!8EhLl zc_b1`=1o1v%ue@g^S}3Y>}p}z8uGWVs_IX(@`$*j3tnGpSjqsNqp1rlpS3%NFDC`@ zym$mQD2{Y%w`peCa67{UbS(nZ6Xha53dFXMbd$=z4LgejRcsBijeB3R81Kc`ce~4%z%9hnk^)<{;4$!*&n_7>6i-M18|~+)Ge+?R~Op z7udm*FNN9@u0(aZ)qT8oBCJe7QsmB3z>+wH(U!uzvBFE8M02}d?G42}<@;LgZ$!%j zQBDe%$HY+^n$)&8N5=q?c&2>^OS>uz=B;!|{McvM%sxcBt$?iNpd!ZO%Fd8QaTzJp z&W5{aBpzfZU|CM|B|K$Ei)+`vFA7j_It);-ZwE*cG_+23r#@AH4V5GUd0R!iE=F%k!oWaL2&P8T%+U^jNqi0=unfD|ZmZ>axG(S3G}wZsVO|0bx^(P?^Ejyl7*MT{ z`RI0L$~>XtNx&b?t`Z`;i*_^BOZaeCU$T$wjum`l0a3DaB zX{g1raO0cxfUrq@UP-+r!m?IVM*|K>U&N#Z&fOs>XfH;XueRgjnDWN%@|1QFZsaxX zZcx{bt9t3xLAO{{LeQ%0La@#ak=RwbHn*MO0CM+X(rkDaPlM* zi!UfVr)Q?uV`litpzb<#3}|RbwjlEHRqfz0=fL%f@IF}`!w>$4ZtE<5v><}bs@f%I z#P0}McTD|d{PeZ882UJtg$2v7hE&)^^fV&h{pGkuEo#pNnOKmMPxCC7`I^u33DE-F3F9XfEZ+GPATva|7)REYk+Is$v-0HI+f^6FwU^un zNfEta3%n33mOxwujhp{x2_`I(BWtJR!<2SKZqpyE(a$3?tmr8!T1rSZz(UJCf7BV~ zO?Kddccuys7BLK$KUSoYE+1g%R5A7A^z;Q&!NJU|(>#tBKWjS2)E{`EM3)v!(yepE zO*)!8k&F7<2roXArSx~AR@Ex{sd}~M7m5C|4 zI*``_Vnwta)iK-$cO@*sTwiQwWkY%#P%QI}S^Eu^RlW-PPl){xSmGe=FAS6b0OFoQ z6q#BVwKUTQo#9pOCF1;VWAq>Dc}&l{o>7qw6KgK zq4V-1cFia4MK0cRRb(>AaQwc*1k1X{cfu4@Ih)c!TFRCgwn#SGn&ewA0`JR{&=#Ep z$`p{nci@0`O|#ZNfE_se{14gYLnp=^+^uM&Rsayg23vk2kC%h31?2iB7xS$5WBVW2 z;;#j>ReM@aS}&tLC3`kN&gP!#FcjaXCc-C{XT3_cg@L6AWc=8>kvW!Opfm#39%A5h z@4^v>DzH9#n@)Uw&jk+k@KBf-c9x;@er+Mn)V;NEZ2Z2+_a(xog)AHPEa>%v&fbn? zY|7_f%ya+9zR4`&GRr~Fm#|pw7ysGVe`Nn?_^u+>`ioe58f*Vwav~jU`DM+%nPuWM z`6Eg64(=l#yQlw-`hD%4fmiE8Z6{875shGpl8Fg&i+_4;(piKe^4<=X zvi*I5>TPQ_*meR8F`10-;NqwGHWO3-dik~+2NSt-yE!aEGTG)2OYzOLS74}>6Vz4e zC82}$X8`O#$B`R4eExt%I;714^s{lV=W`buJ5;Z!*t^zzuZE5v2YR#Hr^@QU4m5t? zk!^~-AGuUSZa1^$d%^a^hkqK$xVYX|Ghl}ybD6h6_Q8#f!>>^YrTI3noK>}5R->VQ zyPe?HU@_k&kYXR`=*gb*so~?Folw71R_Fva;q!mk%-Z<)7>@_?uyq%px>{Eq(Z% zMo|ua#|}3?@OKH;TXnN5;^QBZf9}7>ZFhX4>Pm=2iH4hvC(bgK-vcn|xy>SQ$a@!9 z<`%y2IF>`*Nt=9DNgxGcj_s-76JoyE$0wwdtw%fT+}b-O zuL!(g;m)zvp5f$7nJ1Gthb%HWIM7PfSr>itFo1!r<6F=fS!3CqEYTWYE9^J@3=V1>7HqsLi>c52ga!S)UNMB3|DxR^YcgsYMI-gYe~z1n7i zJkbi)Vz3=7jO2&J9waWWy)@TBSh2t%^N zB3aKVt*E2Pwjl=I0^CK(85%P~cJb{xSmxgCS`r4Qga2?@3}#5q zH2dZ#WN3)B8*s@E-VYlLzwh>Bd8YtPEOeZhGG_D+i>ht9O3SywvtPV$w=@h~fftNj zXWh#ehY88;THeggBaA2qN8flbPLHVp11Z)_MV>a$i3IHb@8RMa5$Ac#il#wJ21d>C zrfW`L=J|a#W~mgtGN(J4ivrX2+C##@Xw`U`VDi?F;tEp`4#xMHY%ertVwSVK9*HPv za>WBW7WZlKIoj)U+zb1teXlxk_a7Oqav4($n+?A8hNWn+V=IadqJw+#SsHYne4yw( zQeT+Gf@qT~jxvl|SoVguydGbWXk>1Vk*wI3oeP8eUz5#fBp97!Hu}Td@17Ff8Ykft zY@7dmfkmhR!s>`{91Gz4u+rbzoV&H#Z<~ih4Fi?V{k_m@R#$8za=T0UB`3h!E6%cX z5>89?OTKREfdq**vRw<=A0Lh@ziI-O)N2<_-G3HXe!GKYV$_SzB@^f{!o-7O zuOU0UV{kA73u9u79M6mGD*h-b`<^Es8FL_+f3w2<_*Cls#r(J_zQrg>w5euVcX07U z8g_BmCa&G9mSLG5WYv*j^fmYXQHFadAKQsT0@`g?eIAnJ@4w>5&+mGxm@2e4G9|dO zK6hMx@Nx7p#OyF@WWpUCU!(owdW-y4gBXtNNtS@J#0Oc1RRI5ufR?{tlSn|~DiOnO zFDfzbqQ_h)$;t+qA?oNFN!wUUlavdENT`m^OlIv!0_lEh_|sVF#4 z@d*NMpjPxnH!-aHH#0p4skd<3*v(VCek`1<%ce&j=k99;8~JwJ z*=4Yi@xQ1X3kypkOoLG=fpD%i{OjAYs+L3gx_+3&TYV=*+gdp5=u_pE8MQV2Ug*;? zAhJ^_fUSUJC(ER@jn#CXsFE74m8q3MO`U0rqntisdJvJ`m-~J__jh3!RTfL|r%eUa zL&&(3lkcZoG`1n4RCSx;THoZk|IlyN+f+I#4UyII6^!P}rsJ@KtII-u#DgObmBU^_ z!WZMzVX<3-K>r@r$n&IxwfBkrD>6Ym#sxrT;VGqzlYbXJ@p6rCK0(XH+GVDlnsiDv zMWiL?CTp7}{$Q6K=@0GX#Q$VI_3!bUX*+i=9DFwxjVXL09g5-ynD~vQXuW&8r~7v5 z>z!46;buVS0sCo!%0J)22c?@en*w)_TrEjS|L-gAs_*W8Fq8A7Qp7}I^fD_=U>Q$u zp14xX5D%)J<=rl+UpLe)ZQ3u26jh6xQ`22Ehnk|w^oBFgNp~Z#eswB2H#@7^gtU=hgckslgPyCKh!hWvLTd}ppYR*ol)J?Yq}nTmP# zZOBPCYOzXWt7HgYKE^U4aiFnSGR)`s{Q+aoNk4sQdcrub3GM(I~tD_ z1$)?Q>w-Wz=aw_NRs7bujF%tfYI*s=w$!tDx!QQAf@38IQ&kfuP05X&XolW(Zy$ab zaj%Z$mBPd&s;lyzQM#ydoMqInl(dkmb@<8;pKj|Ee>az#=R?{_dAt7_WGTw;y$gf{ zaktw#Z0@}1{dh+sW}vo2BY;i<$87j~l%mMDSKPR(V+6`N6Qk;?K%`GJb~j~uv&u$V zZD}bj)5XyqyIOKTV&gaKTveT0FAm{5s*RY40DxSaGi+E%3@&byaku=z}mE?%E>PG8|z`Av<}Ff1aibG;ec zF=cUJPhh7y_3Wr#NXjXL`nmh5Yr_v9%umB&b8>Wiuku6d<>_y)NXWw*!|oT~%Xpb(<2WmAaLPA!xaNxsRsMQd&0jbmjl>guFrs;+9tbPaXTBs9JeV^1es)4-1OM+~G)cYG|C|1kPx&~8r_RZ0EJK`0W7 zHqyxY-bK3U0{2eH=}RLd=+y4Hy~l4}aK-+ydJT7!F1OJFHHG;V_}-2>;Cp(^o-HiV z@*`oI`zHRbFxt)~hbqN$$KzAwb3*nu?D&Mf7Pi4FjNE%qeXOthkueK=VulqYw|0}T zQlXeoQ>oI>0s`B+DBq^Qjx4rJNfqQ4BpnVhZ=mczII8C)OlUyBdZ9$^#t?4Ew@mO~`hzhy=K}K;UW*@L|;+zN(&W;ZE@QUh+WZ zy-j#e->mmFD*-y4u(g>=^B=mJIb#}FMmfyLDtgj1FnEgoJFQ|>nB7r!Re6iziltLz zE^_#>d>IcXo&Bt^2{QIQJCyJ*89rE%{r@iNL&xtgQx&$L4s*T6fsd~FWW;kaPBrjN ze{s8Q3xLU_P72y!#C115b2w=OtUB;p^NnW*3Z)HHScr7B->Aq*tOF|)oB8n9hv8p~ zPkDR_y6H%#KpomlE=d)?E2Od0cFk6*=tcU$wkgzd%1{nHtNpHu2LTQ-@K!6b@s>)b zY9?|*$|H8X`-f;I9Z^~EM~MDx0htM$%2=cF|bq=+)JcbmcT>ZruN zkkB?+7m<(+9#><;q>wtMqgf$-YQH0)=C2C6%h$NFvw^N;;p?nmgs$Ygs4JwM%kOLV z4Cg6Bev~kbYZ^k#-^No}R(FHpr#(`AixFU?r{(2;0u>* zmtSTY-<)ntrr#|u((o-_2l>PPJ>7mA`A=Ut{2s}2rqc2}z$!3S>82;QG3QKh3?Uew zacMas=fZO6{icg_5aknNYG^LZS*_P zHifbqU9i)VptI3Y?Oid^f52+z=iYz?})T*D6Ig@1n-II zYI~^JY1b9#60{JCz5CBKda5RUIXM*Vd9uj}Utl`pSkfIXA#Tq>*)02<$9*?nAMWAPWJ%W^`kb}-6!DsW_XMJan&oj1eh_R8%mTRQOM*I1+Rh%8SK^j%`2D3l_dFac(z0H4}ay%#f{ z;30^2rB?ha;pRTx+io>OM7>Zt2p)+OKM*;R5467{Oa>y))__os#mNyxy2%@0(Eg#= zM$?26^oEDnHLt2V2fmMDJCK$-LWc5{vG1lx#e~nfV33>kxc(3^0MKIj(%T?J=K%545qj@mXxAC^y}oj61Yv^OF`Gh&g{1v)$UIKc|C1d#cw1kcUi=TmY%*WqN$1c&YjU3tnKsgYO#v3C&UxD zn_1!Pr~kZK*y@77bhsRaI4LjhDH^ZV-}wAqL8CZi@F-WC;_XsGGY&*8mlUY~W@?Kc z_KrnIVD#$t0(ck=-Lf#A3tqV5m?8G#q)1GHgUfM^*Hk4SD^@wWB1kz;h+SbQpIh4#N26`ah4f1u zQ~IEe6(P>5-FwPwlf%9e>0H%19dUx=I68#Vm8_CUS3RP!38|DCR9EX4N;OAo|H%@o zGQ@(Y;yU%}4(YF5^tN;y(`SX4{Z!3Nj=`mjGf~7H%M7d=PxZ>2kzVE$76{42LAU@+ z7K``G5YU?{=goapuBjEkm4$T3?&oUBYeX+lHzb(ap6Y7!2hJ3ZQcM*TT=}nj@52y{ zW8-{P8bvFfrE+90KLqFIlq6QzRNy=X{YGi3=!r0Fg+z6yv0p9Uy5oVZlLgl@M2gX7i3>p7~cRIDS_&K`ovV>;Eve!eBd z8b+$N`mBcR+Z^wAo>G_lcMZ|cHU7@QWPy?UDU&NeOvs6Ir5VK5D8iyZMvjC$hsW-x zqR{H7KlOEkQd^!i5W@>{)SWiCvnX)Te`1F z6(9YsWZ)k?&nQHov81l@VN@w5e1qT!JabIR>MW{*7PUPisG+jRnmFeGir%^3O*R6*j*kmoNvHEcR zaiPe=Y9V1t)b}jW<+xPOF49sv;&O=Cb+J3x1`@m-2Q#eD9j`!$tz7nEI@s*USmvpY z_`;dOt8=`U{zxA%RX(O#X#?ORKW0fC{EsPa*J+NAsfTsX!w$j>-tl&iQBdtv&sw2H z6j5Q*5#uJ@?aRRQlXuf`NZNZ$7{dW7RQ<)n5+B)K{SldKb^L3uQ;0xQ#7BZ^`${zy zPikUkdEuK(xsFPS7NY*?+n5O+W>JK30_8jSlBZ9bED15j!`M8gG(g172`gmty<=|c zZtjSAx1hGIaa-9vqkw7kh$Y}=MZwPq5D=QoBx`n5sDORud78lQXPYOE6RY!OOgK zT1@~%O@Oixidfm7R?F(>xJn4q%WYPe_(PoP%;Fphxd=FKvW$UlGL+hA7L^a$a?5RL`8aS2ggdL}%Tf5Zz7|l_Rd|Y3mL)HFU!fU<< zvHet(+->EnG1zfNQfbuXG2oP=kNSjqu0!&z_67s9eA-2ys(8v>#1rfYPiebOVaNKz z!nf1|OCOa!Ft8k+4NWjH$@^GpuJay!%=%L6`;J~lI3eGU~M%^ogs$FJ(BC#EeM*B}11#8%Vv$anviiJECka1wW(QU~? zocBOhQM>P-r_zrqusT`#cxyF_gLwQ?Y$-2>Mp0d=u-}V-)d8zM8e#{5fL9-6yx!W0 zkmGU^W>NkA`DahM5y5i|)%4c9yU$whPqhyJ=t3cQBJgfmLSUf zGS`^65%$~HeVhLpDJB)>J_39ULc1=dc9DwG zqX>p!8Qct>qK!IFG8&ZxR7&S5=xG?4yOG_ztyRKtI1c*%BLr_ipmV!CHub+ES- zsyD4DHLZXK!dkohb&OOpRsT*?@Di{7yN{$?V6;66X4dolDGYR~Q1%~VRm1OnKUY@a zBHED$`(+bIoG_@TpeWQf7DMjCoHan%!6206FN!h0h}U_(L!qo~Mg^lkC$&ibvc&a@ zK>jtJ`BjfYIsz5^d9sTXI}q!?xAjBYrYuA}PpO=zR6yE+cx4O(YSdAOUO$k~QAej! z!_d|GTtUxuyWTH=zHMRW*aLm~%+XCybKfngg3>x<7Rgq5e*P>&Z`+m0FY6_rXc>kUuJ)0o&}o-e)>9=3KA^=`X7J?F4= zEYa$N%t1}W!pkEcTz08)9Y~;~*_PO^>ONghXFqkmDDZdziQ;@Sb@=qPac_vgjlvy% z15@50VV{5bTBebYM}#uVS9lI<#aO)F?40j^dyOw^JKnsnb@Zzy;_D3ar|{qAvEaFi z-M?;M?r;NPrYi!kjmOTAFfcS}ktM?hMr2H%DGgDX1*&>{Uy9MjO!6+@Q6tlEDzglg zo0pd&$?*LZ`@X8Hdj5O{m>X_A*AVi@_J1zw|Ffv@Ypa4ED?xc$a<&P6fgNz0^Dik$ z|IeasOPW{r7h6P6KF>H)alN%e2M@cY+aX+nd5mkb31 z+n=oVX{Bk-3C6!3X*)N)zREo)<|flAht&N5OQ3!js8CyP@H4sD7XKmUu-B)j7Q*4o z(3dZ++CEvCd7k(?TQY3SBIw#`2VmXy>H2%KD?_;jbvr6|LW+a_%eH^^ZmL*t%z-=XY0LM(%#`XKUm0)PFg<|NHm%&+p&cND3WT>Rco2w|JTSekg~Cy}-_K3~{T@IXU_1gU7MS=8sM^o2`h_z&Xjtau3O9>r0dhJJzzH_BbwVVBBe`Q8ccF4hx z*YC9ZE#1n@OSqT&sLvw$M%yo?#YzbokBD2B=OphHrCWs^tCEroiflryL>+%LKKr9% z_r93l+hX!*r;GF-py_T7Sd8muLF2u_tO? zg9=MFih8WRG`K=c>MY+p_#k1$8P8cBR4B&o*O!D`bu;n@ygD>59b2rv4%s>UE31pcKbnOVz zMjL50l|) ztm5Q`hEjL6n5r5t_rrK@5Hoge7G-1MWH5g!ukP`q^-CIQu$p3J zfXmly{k|CgetE@*iY}2x52$DUXej3_blObHB+k8@YkFSvf+!`cZBHQ^BQ8jhdnhN* zf|anRs&1bc(p38`=q4?%U45!r1>vVd9sW_>FBVl|Hi^?1b^jOXT#E8v?=;(AxjBh6 zGUl)7m~MNnlI8Oz6@r^1D;|)3euJ#iya#CYYYh>%SgH1B2*^YnolC}ml4es=r4;7zSceL%#Cez z`vyl;iqFB7LJq zC6{t#uGT(bqeZo}ACxr09Ah*-xe_CCQnhKc+{?{;1ToSZ#$@Cqu;*}Ho}cYUE8vw< zXY1bUgA{vmb7(E|*tN)R+sDFM^roZPIx5Zbg%D94!@mI)ZP<=9A_BZz%8ho`lqzfc zSeMIG6x`P&ei0ur&6Dx{GrhdNVeLS>TELNh#8v_x-)SHIBPx6}(kbBHq(O;)j^>vy zZg*G3jKoNiw9RB=gpxG5XRqYGNKM~+#O%bLQ1mDRxO1@)NkeNvUT(K^?|xAM!3yYz zIYRpWhyG%CE>naui=$lvS^v2^)o#%hVNDeU;cTLU?fcFw|Hju8E{9}^a&;I5Lb9s_ z%6{T$N*%sww266agZIqtWe-GR4<9Rt7sD)Zt1ru;)z)ZxrJ{%#XD9fWu&ciEqa28_ z-8}Y7P2ZJj#Y0yH3(BjEzNiK5oV;r0Cps!Vp^`KG%2wypd8vDmxlg*abbre9$sJhC zp3!qif4z0;xn$ePCmz|==3P*9IbnIbC7>m92xV* zdq%2N1VI4WaqezF{SUD@(S`@fDr>3sKN^u|=0tbxnYwKb%JoWjJD~R28!WY7U1={H zhbmWvz%nVR;!OSxJ9LNbI_WB!63N?2Ptyo1OO}sx#QtnZO)<3-()@&k5^D+6G$%VL zT@!M{9VFRmo8#J2ODc9JosVALvwvpC6G!Z6hqIqU4HF;7G%-(H%Qbv&!g_WrEO_JT z^(WoFj`;^?&YXWm3tCbCPN;qZHY@zO*EuerAmOLNL!Rklqns_eWDua!FdUd=62E*) z=GSq%_2Dczr*vN`fKT!VATHLh?v9=lrGNI=b4@|mA4FH{A|}F)LxitQbmJF(qwcQE zt5O4j`pc#{d+GqFm7cV_Whiiz*de4H;d8Ccw)%khXBH;BNVj&ZBInefU-duf-I`$o z`0f{zN(%p6Vf8^ds-X?8E3Do(-5D z`|p~LRr{-;wO=d0OP|y|o4TE}eodDU{idf)OD*Z!r+YV0NfeevDQNB}#qrG6;aK~Q zd2BCwwaa#MjeRpT)3dD|^h%{hIXUD`S>SE^)e3}XoCfwg+xe}f(bbFjENMK>IY7S= zWZz6ybL|G|_`gfQ3gj^ddLECC`FxiU3RIs=+Z>7bx+hgAkWqXh-dd-IOq~7`8FT(w zpo8t*r;4zcKd&@reKRg!g}S}qpL~3b4hq^@q;L|f$S8#}$MTG(%yyXppm%7&PXSW?4MuW5_tc(8_6QPc&qmm~CYGK~Tx`;{ z9FqKoM;72UUwI=%ZXU@JX=5(4zf+{4iVyru8V-na{kZ2N2RZKz&cvUi{6xM}y!2m{ zr;u{#Hy56sYev9Hen~UF!#myMjZxfxdE#79tS%$!Vd(Wc&b({q_ps9ZtL^^&3`L~S zw@1?+9E&%W2;w?giMty9-jz--Jk`x&oGr5ZK2E>1$Vfvoi`}%}&WXBPAo&8RPPTL_ zTQZg+ZpAT5jg0--08>^}C(^}jV?~2B&aTG*s-A>^x*Z2 zV$K|BjyF`b5%i9YTn0eCX`Q=WbtRVxZX3m^`alaPl8m7}auvy5!%6pm7ZXq^_1)kc z!2cv!h(7|efNTD+jfnF0HxQH1eFLZVz_Y{&)MDgYt~I;~^qhkHj*@x}$vFW{qy4n- z^iR*KQ3s?QimhQ#@(Hhe8T#iBG0umHWt@6fkY4yPz2=SakB~x-0=B`H)+V}Gaj{53 zskq=x(UbN<#6)gI2F?#9cA-IWb*Yo{V&j~;hMl&wl!W5YLS$VJ?~jpLV9j#d0C zvSsdaN!vQ#pns=So-^~KSiCRPy1G!ZHC{R@J+7$u%C(%b@0XVzpFEduWlXqpBsBxO zR0DDp$Ms42Hk5eK#INQTc{E-6N^}2?PllRG7E%M|Im*ynT5Bcf{Pz18Vi- z5^9nU)|7p!zYtaA{k>*;Qq2$7aIDKHHqF(NA~`>VSX)J|uOdFOrH*xj&kn(*ZINpY zi04Gamj>9_p$BR`C{sG@EBA)!kff;mkc9%D!+SJQP%^UMyQ@f30t>Ej_A?5;j6!|` zAeTAtBkubSjlfp`a9eVA0S=*{f?S~?>T?Ne>G#3C4}7KVrwtA@S=OtxZo4FxJW_jB z4d|^t{F|8V`rzle_^(nmkyANRi^U6*4}zwO{r2R1KS$qjhz7Xw57(y>Rkr1}D`GSX0kqoxAWbDHL4y24IRm6cT03UmK zi_<#5J3c=x!;2(llUI45K|0b>fhaC%8E0#DV%_3L_08r)E5drq(`Se7O=@y&4VDWA|c_)HKzL|c5csmOSE>}<= zL{Z)HkLu;0EizVdXx^Kb^<6K`rJtWL ztUIA#9pCZogbeR%W=fO_TgsNM`0rt2u>lp5fQJc*)r&(r0OowLk+x^l zHpyU|!nYkyg7^W;L3^KL8V-Qpu#qbiC1Mu*cLU-;x3MuJ>U{%sCI8%g+Z~7OI{V+M z``B4XH9Zdkb_dpVGqt)u0*^(^=^yGw1?zRRu)0oi5lLeRAy=wlmxlEp_4A(SxH>~= zjovd&-Nkji@79PBO|SuqQ$^W_82PM&9fXH0*0R)23@|I7aVf#v>Juz_L20a?PpSj@nitbt3@ z-TKrQFN?d06{RGle7MZuNmCn+`jO&uvVFZT-!2b+g}wT?_R@b^#*QwE<3O@r{7_GORok z_*vNXdSMu2KeCoJqJMt`S+R>ngz9_lFcrXl<4%8T9#G?fgI6UE<;wnik7O4hHvz~f zT!-Z% z5CRTjm&YhQRC>N)!k`PWPdFM36zj7n@Vf~2zdB~wjv@de^Tm$ezK`6SJJyv7e$FoY zMMFH47CTErY!W9et|He_uoei3dL5aPBtT_L1)g_Hq0w?3XukneOz)8xhuri1Y4g+bfi> z?>3wB#nWweqKKxBAd3LxJq}R$ML}1p&C&g0T9;%QV6dL(3LPZ&-CD=gn!*+TY??h< zEflHBlvV3DMJVM4*l#*Qq!=sL4?0sc0sxS`65wN&CK}IXn$YhD0J8=%;G`W`Y<{$h zw3vDOf@ynUY?4)KP*4S!3Anef3?4e+-V$$E_&qYWZZdvXU*tcnev04%>{!#*kM5;&5R zc=$Qm^$!%pHdk6@Ei+sIdq+fkq#@=S;AONyON!K68vH{;$n5M=MHY%kf%F0pyL=HL zC!obIP4>@T|0i;HDDSVsxpEcS16=q$qU4PCmjyO_`%B$f09;5jUs#2YUiVUic&5~fc7A(p4OQmyx=`2zSn<;#Kq-UN6T-YxZG2vNXm z{mc_8`BR;}p}If)3s9%8IPAS!AX-q|7;u;TMn^W$%!=zb_B_a_2A8cBgU;3dm zAluUZhmWTJK)#Ga9Bj+}-hlkT9y4WM{XGP0{eqqqARoseAL)JdY5=_)Le}LX{l9qr z#KWx?ND%*@e<)-3K+?^X({rn@iG|8R?~vc1?*eGtvq#Z_{~O?GrwEwuP$k!nh(3XUqlKTuH6uwVW#fs??6;l%@Q~gpXtb7f}ie(k?)I9 zB6&FafoQFU9A|^*=J4v9ziWZ;^w@Jhxrlhd-YkK14-r;C;~Gngu^JwZiTpl1;#R&_ z%{fA+2{CIm>M?%9^TEH*r)bq@BDcK}Pwpc=(h-m9y_&ocW7)Nz@Q4Kf>O;-8wfp+l zcbO4CSBzLbmA-aK3$=2liyd>$Ecvo9F=ke23+>BF+0LfMxy-Pw4>P`L0|yBgeoPMQ zZz28L5HCN^c^qEec0M6Ktd0?*|MdJ;_3iYRn%<%3$5X}c z{Xo34-9-#(XzfPqlM35dp5ZG#IBb8=lD-IhBbiD&O=N@_hEyMZ5#0=*ix=BAxp`my z%-Dm7ce8&JH`m_3x^wj1zl(pizJLAr?%nof09cMj1W8-062*4-(MXVwO*N4HA1dx( z&w1aSYkxA7Af4vEz%Wj|VrW*AjvwspE+f+QKJIcCBk$~ZcqDnJr1CZ}LM=~lIz&7S zVXK>^96|@)Nc^CFI~7y-R2S>)=0+7qw_I>7g-M>il^Xqn)D3%xuO%szh7IGyWmh-r zZ){Lt(REFZSuZ6YO`MiC-dbwChdmlnLroz~KXp~b+1-fIvZTSA_LR`ZMQuUCD(xia)N;&F@Wt&dnyt`}8YmK_^`*|tm89Bh&6 z;kjbZ4w9mE?72)$N2+0lBZcq1%1R*?8PMd*?@yI^`V zA;uk8=e5cd?~u>0iYPMhXV+)qx%do@R!Gn3m&BQwnsmFsPaO|;*4MO`UVQFu-eK9h zl;=fw6Sb54Yq?*vEBRR3`hP8?jS#;NjZmdEgp{t@*><;(l<0Lv1WGa5yJOejtvsj6 zV{U+35~|C6x+>^}bwil1&$0X0?l+i%Q_&!CaFzkOZ46;NGJHpAJ9C3}r=iD+@*RvJYyv~ay`od5;g&6U#QFaXy2*X@E)G?aUHrLg`Z$uQ-1Trvdoh>+d z&J3R{A}bfW9Yn2{_p|ox4QW)8H{#ryJ3Gm$k+im z4&x*uYn8}6d9tp~B=m$sbc zqL~?2Jyvo;O+7$i9?TkaD##E224V-E&*xdPI6C?PQiKJ~*r`_t>kwraf9I z^+0$8fhA%^wFV@PzhGAE^Rl~v{M{sU+w9$!*IToo9nE$(T&IY?UDeXt=7Hmy_u+5% zU$KixcpX1lsq(fm?*BqVTN zdAtZB{gvuXOFd8*svUiBAYuGu<{7N0&%CibeQ{L^-zmZB5cLS< z7rEGqjMqDVMiARXC7sFeT^t+^Cd>JK!4$x5 zV+Xa+s=*;UpW}Ex;v3qCcXbQUhD>ZcRoW5&lpx@M`U`6hV$TwZ+et!H14ow+gdC!El|eK2m#=p#3*18i?+rKFtBU`ILDb_&7Ryu~T|*)@qX z*~XPVpB_SR#Y~4+yBb)QmCOMA)k__rD80xygB70~siR`*pg8ayl_ufl-O#8WOlq@% zO&dCrg8oT^DmHnxUA9V4+6;7+S#)X3t|vUw5O>5yDk5-U*5ZsvsKa2RGTLz7XM`>b z^JZtgkGl$`PnaMUT|fsLSeR-zi@W^---+8HY9EDXVBU1-q_yVDC+%RETO;CvXAkCM zdYb-tX@AFnxC905dK;|~k*pgml#Yn!gPWbUCbu;5tl_rlA}n|Uglu8)EacW0J;OCs>sJKtu zu#2%HXrp+R*ix$@$CI!xqM|5@M#a=(v6J{T6++-M{^9L}iS8pmKDWsl7#xWB)qYQ^ zyUEqzB}bK~I`P3=pjA z8G$*uvHf?qC`j!hjhw2;W9aywMzS_4F~>6U4GYfvOIi-aep!SPK#xIZ*gBVnpegY$ z9AxX4oC$;|)-odS zY0*R6nnf|1H`FCY1aLxZTdFi_n8)zYbDK{4TT&19t9|&?dDICS$#&AV-8G*n4R239 z6A3-PY8JN$AqL8Q$bcrULiXdtecigfy={MR8LG9Z-!i4b*wA=AsExOSNx$pGY1d23 z-Jl8ynG)Tr@pr$hKDXm^d9UY38-Uagn*WSP?aOe>u+zhFRIaH@?Av-+$YkI*?~{61 z1}JslJs=(}=G1F{qGY7$DP%ym!whGzU9Mfc**^!LXB+%`5e+gzL3X0DM- z%XRLXxn`JaDr!S0mxc)4He*9>AyKNiBo$JrRO-8#d+tdp)h3lBO;jr7x8Faoea>TN z=kxiT^L{^H6fJ+d8dQ^a{)Vj0Z$z2f%H5@JHkR_T?qh6|4%nT1K!x!R;?TgQ9Dp@$ z2T=q(9cFwqOV@@3j@z(pvdLcDG_PSPUY5qo>8OF<60jo9xpALv6I>{&{GSOzi)IE8Kf<^vf~-wL<@2HU7WW{3Jt9{+qm@cMTAf0!hO` zBJ(VMqp3hMD#&T9H)m*ujxe{c)1@_&IM z_~aY4;^2r7j^j3E@x(Gd#B{O**(R69a97-q7(j46zSJfts)fjb(2sy2?@Q#L1jU9- zeByHs$v~3YIMHpn_P9o~FMe30Y^FpHJjacdAO79;Ecm|c+w;ilvtSn$h^K4NR)eRa z)nTQc5_Ng*37i7eU_$o-5t$*)6amM{gRV=PW@I3Ty|{-7kVA1i?}{t8WwPzV!1NGq zt`a1gVVw7O*!XsCd_QyL(RXR0>sC0;+wz;c}mO|@YMZEKKxT5O*Mrg zR^l}GxIFj$s_)vlo!TwW|8zV*Zp5|5ygHExA6bz*!qCe=ke1}xDL9v0oXepxe$gZO z`R0F!_XapD#Sd{3!D}&cn>8pz#V=qi_58<5d{Nkoe zbB_>->(kGUctOqrcR#ZpPi}@L$w2<=xSUM&N1Fow>zFsI9!Sl3&)&AF4o(uNeT-16_Q!vD@x$ktPiQ%1+U3?9A~xnIKo!tZRDQM#sg zYVM-C?VA6hh0Vuci;E!nly1(+?2+WBa$?cHHG3Ivzx%4(}U)9#2zYr+}ZJCGHeEIZo z&gSl%*~c?4<$Zv*d=S2g75^X)8p?ee!CC=yU%3S`O&Yml0uIa_`SiuJ2c7D`qLFib=P72` zq1gQ4D`nV`KU|}ShEnYJ;T_09L@dS^m_kraxC!Q3yN(!2ed zaaWvfs^!oIinNPelK&`}^Ev&7es-i0>&HRzvNtkwVm2(#wOp2U59g+bL7p&uNKTMF zI790-PRe|NE(3Ikz-{HT8Eaf>Y4F8RZj!vLg-VtAzsSOA`L0sAl&W1*rd+z0x5_R~ zYM5`j7bK-L*T;2>V?X#Xm77N8CV0u!#O>`0pFW%NRJ3`MElTdom7;4{Ln%vhG0#Cnb+_Uco|QdMRq#OX;&!u#GBEKN3vIDF9q zl9V?ukOw8=xqj4~B&q#Nl->mZ=JTA?4Dgf>@NFvx)tMdNR=AaK$v}`FYd|J2%9avv z3R7+$hHV-i5*@ZD)Ld$4vuQ|(bm2`IV;gUhODzRQmwrykkPRdH z*8Zq7>^Ah`>H;kZA~3IF28Z^z$q^P?g&J)L@lr> z{F~4vmC8mnf&PKGr5mK&EU#Bv^8l14$O#5mEhA?~^7}NQOB!MfQ7gXa0X>XapqtB2~@YhJAP%65q7+?{!EgO)lL$ z``}|pCf|t+{F)a4*)<=N#%t2wxz9JF`Bp`KSY>!V#s#h~9k%~K9OOjlq{{^4Bp>W- z&ONa~g;+MRNEzJYRr#nk(7zS1I4pO4&%O5@;l*uila*7HD_!x8sfIOo_SAK)yi;u1 zuNE!hrt$ACz2Y97ZfKjArYl2Q|Kp~OWo|vpU2FNT!<)rHru58NxE#s)VdN2RyZi7s z#0B_x@DuFaKjODntNRybPcX>G=bcZ=K#o_Id_(WHweZO>LS1rKI4P+=dqeF+2WR`e z)Zs04Ra2>itCun*_h$dKCrg#wFz|orh!v{W@>;!EINc+=# zdCWNUql?4hx0`$9Jciqj{2F0->rO3%agK_fh7BK$(q# zv)eSGI9BWahm~y?8&NFQWM*IWYpXp2_*wFgOnln)?cMLoAuT~yV!kf51OjwO$~2 z?1%8$34<4iY9*WJZ7Walaud@H<^Hakmn(t-cU?ZSGqU<}<(`xmm(T9Y)@-cu6ODO0 z{?JzisoOr|D5{H6j ziM&&Z_;hyig`w0@E9PI}8Ps0u+fps)S9Xch6KS0t)Of9K%+h!rB#Zkzq&nr++ol44SOKMeVGAaK;>ZJP#2v5gU0 zOmVxpGHRd1FUU5K%#n+dZPhvKK5h2Vrv)*q)_%$&;8CzjdJ>6r28Vw=CnFpDa3B_`93xPV9^iT_-pym;YU+c>qU0c zrs`;GoTa}*NonbIOp@al`Ow!bYUJ;AyoR9)G_ZuJ;QsAv*5HsrJnoz?O0o=d!f!FN;Hm!k==y-_-8Iwkw@njiH?j$S?b^R+CE?ptyG0|l1bAuKf3a)g>+_9T#>%RIO>umX zE}o?rjst1U^C5!`l-M0l&(%;tJDQ>Ca@Qf-CXSde<~PU~dLC)3d}O{pPY)}~D{fs) zhG9j-z%?GHy&|PDfpIO!Z(hF1&ALTCvVIS;cLYu3p0T4WUB_6D>wRko#vGbbsK1M;Z?o<**`6% zyRUMOaTlHSzZFw?yi|HOw_gfzKM@soxKM_VYUbF}49fG4%yK-l%xHW^Bn$a@YY+t56v>eNK;5 zlI+>&_gtrXQbtv}1spa{El%&x&J4T;u(`$E*3~3d&f*Jp&k!N_bRpX`E68GPmjQAO z=y|Tn&+9p>LKCWi%Tza~2LF zZl}xYg0l#!+d3r0X{KcD7h@YlyH#-!vbz+!hUCD1mSYoXsoYC1J)7J#NQ^lUhLnXw z4xWZ52McuEMJ%(<09aZx88cX27x;1+o{%Hgl;m1@i&3V6FF3vXIa2NMgwdvBL+@0q z^K@eW6_g_h!hpqF`=36JEpASDzyIl&r$cuTC}>ECW#1mbQ=TedX#v_2`J9DFrdq|Z zdCH`Gx884uyyQ;ziZ-;H;{vG!q&@BD`biC@zkPE5sz>-Qz8Lu_`^nYGTi~mFWv8KK zB}Rjgze;q^xKdrNuO`r}PU*Ah47id36_O1bV`$BG*4OoG!9aI>_Ip8|<};DXp)z;a zo~MEE9v*C5zRzxh@vt~!Xzb!mmEk?$uy-b_mr?ozuA|p(m{PPb_vt2zKWdP0&y74t zSZj6PvOrVT%i!5jfKV@iQc8o~y)R8%N6HTD6rhK_S^oL z4XfqPZoG=0)T*%{X+(79g&+9awmVzDA+^@zHTbEaA7PgOzna{ap0>H^Ed~N(0B`4m zYPZw~WXlio+cF#Kz$Rh6@iMHwjOvbRMF#^7K_s=Y}`=GTnocc#?N&Nek(eKu9NAucW&%V^hZ_jXJ1qtGA zY&6_oUSoJ(PO1bt1-GIsy95Tmr!3J`2HFC~jx&_w#a9%;cAxlMXT_5Gu+*gECj|8s zjK46K@|#+JWPS**;b6!5LFx@BZ2o>ewDISi%Z5Usjob^h!bkh|+!cVZjPoYTGEfHD zg$lBe2(8pe(swcACZFW!N~g81hdt-bhW8wJp_TFe)uUvR4t+4nifuOSy0w`qsFuR2 zGje}HLhG62T;=Y8oNgtR=^lQn`}4!TuD!k!+RE&{#GS%Vr;o4#2l6)$UafIzoB7#^ z&ZqAgejPrN=2~|j zP)1-NE5t+DX8PSujzTymVnQ8o@D3ZZPHUhQe)CoxL-e|M`Odt^HIvqcb977*Dugtk z%&lQYJElR7RJKBEmvzPD;sq|YLw)HJw(c4GYf)hYvx9yjSh-cV%Y5uPx#g!f+yjk&qM1QU`XxBABH)eOZ$UK!ywQpE0kkUA~5^h3WK-SP4Ixk-Hx0Jo_|p zOQsSG?dqUVHeW=x%BoH$Q`8-O+UKdtOwviFZ~(7_zf4q|mn(W!rMvejt#fqWZ-Xh> z7t4t15I)ngbo0Y*X8dI`vNT4K0dSZnJLz0BuB+P^Y$2ydu)%KK79C_qTJ{I=>@2hQ z<8mG4w{G#x#(k}7uvL+h6-ZIWVB3t)k*9r(*lShkxpY;qWPq{(YP--qjh6l6Kap)^ zNXp?PJ1JyaBRtVab!rCLOQ(I$U|d-v^TenFhsA1@Ie3$dDK&(OWbB8oG<(mx*eJjd zO@ZRwj`O<%^#RPA+NiB=HWDVQOp{giHorKgV9=1|7vmf5+viR$O%WUi;hM>XgJ#m-Aj=1*bzzd`7q|2qt>)G^fQco&$j}V7in|M zBXe%|z__No(tD|!NbpkAtcF1^PH(t4&iFYRz!pS3#$D79@^7pD8^_Q`)NA`O;+=J9 zxR>iU_i{@3Xgorsr{iJ7P=s5(H1Mt76SwPeO`+B#OA|L6&Va%g!W-4F1o^5-0p09V zPW|0Hkwj9XKlax;>~T1Ty2BuVd_HIbCj- zOSYY0%V6V(ar+f}0&{K+uyg9Kpop5bdu46 zE`~c-fV|xE@(l&}s)Q|_^LugR>w7_l4NZZjps^iYrzYYiwtktgXaTxwZI6>t6freT zjh!=ug;H^G(%Y^Ipja5QB^YLh?4zM5nYGNP-;2&Vcl%t8p19fIW3O~`&gj4arWg@0 znA2}H?|sdReDi@)>p0smjvrSBbeskqvIE%Fz)TAb6+5Ift?cGcr5oM++sDYS{hqgX zAL#jlLv#r2XV?zYdk;-#t0$d(#d_MWBc80S31lwW&$FJ_@o}9=;c-<>j&ecG^}6SS1d$UFmWZ@=&=Vy8k6Tf`#gpQ|)0+Nx|1Km-E_b6*xdxUt8{&U0#7 zn$KNILC*5q6bfMq)Dfq=cdlZxb4EB8mzcx*P~@%vpJy#M3vvBPTh{XImx+EC*%x^- z2pW5d^0`8@$M`Wu@dev)NT?qMC53U;dke&+GRDvx1E`Nu#whtqCz5_1x8R z6adW$@Kp3-_la4*${N$;ui7(M&u3+<)@A#P3;QSJp$Q-tkTjv6T&C!n0WJ?0sepLm!wZ{sn zU?ci!J!bKwbljR!Q{%UPtNC-6PPQ$DO+dWv`%Yi@cR+<>KuD}}YL*(pWUFIt&e3lQ za#-FJSwt*oxh98PI*{^=ZNDzGAhMSy$y?B~+usL#g!(%51GNjTZA7Zj+3P|l5s1K> z4(l#0nG`x4?r%a?y4A2P^~n~FZ2M^0LrAZ!=qd|U5nDd~YHj&RKe8o-Y#v)@I4ZRD zxm#QmD$hGeP}yt;qa1Bds!^Qqw7%?o+-+;GdPx0ea?|JXZp3oC(8^S3 zHMHHSL2{|3?a}P#O)K%fm!Xkrv3OawWg+J+V+XWwAHmClFa}=BZFUYb%8847{tO;x=&oD=ifkj>gb8oX`*B9kZG;W6PGeOd1mkUukw!3Msy0jg>Z5#p}Vb~^CuXhU`yvc0lQ1)gU z0mFYPgcBrMnsnjRvmnn7q4T8hUUQ=JD%-5J;n0^TXim1vx^PNi#yR1FbS|M;K`%PC zb?tDoL@3|=(Ifalj_mXZUo6!uB|9@NIZHs=cecIVCFiszoZ8>++;GIs%R@1m?a~1X z?qZs)3Z1OzUgD1~aj#txK0h$>ogR?2@916#-DG!N;PhVb!}o~i~1Bzq2K&8bEu7AwWd9IO159h?+Ka^)xev)GPOp=*&<$+m$ zh6CZg)LDJMe$S=i>`xJ2(thaYcVW~o>Ex<@JohW$Ner+!S@WkVoYI9hS(~~eEL!we zVX*A;wr3rR$chK8^j|~%ym=_K@&2Y;hc zpqP)VNwseh+8qOJpH2u?^){*q-%z$9+c*mKIbgGW*~~9}mT_!Tni*~#G*;$llfX7} zi=gMY+RRkiR|#zzvNiuab(zty&jD?ty4tu2SE*M~reuPeubmZJx3E)}sD$(qo-XaQ zi523F9-1bAtmbV^eO(#+uP(u)Ly|6Q2HBP-+-g-|&+eeafh@cXVQpPDj%?pqBE||d zb{%Aoys6cXG)>F4sbbqV2yJQE+ZZ4V**zEnXl#RQkLxL*-XL2lA)sB>al&sDpWJad zSaX;3N?Koa-?}ZdFBJxVar4UoThl-`6gH+qhw9X2okt$;K2C6B55FiATKu)FV&#K5 zmISpVvJ=~NS0nV!IZ6=cLKvh!D-ne zpqy&`4S9_@dj2a5b4N+IuvZ>Z74wQJUW4TLSu*A)uaY6H)hL{t_dlP=4=-$d9C!SC zr=y^CH({6$P51@(yuw(Rx@=l&e|Abdc;1^&IF&TSofpX)WcaLeN#tfggJMv>)^Kk4IcSbNE3OwY3#H(qAFOL?YED5y3 z2KjoqK3inz4Po?^eW%roGYH$0I*$}(-{snB|GVL#UM4NZ45$ZF3Q_#rUXkuYFKDGn zx+)suXtR0Qb|>M8Hk+nCbECuoU@>EZ@VSevZDO6zIr#0s7Wm@@2T4b^=v1xquOwh( zu5P4deV)8eO1AyyA(6m%%?mYPQ|_j(AOLM^Kh%Lz=^Rk_b?n`U<7a7hob$@Ubw-DL zkx4%Hc_ipi?$ke0G66~JG`1Vc>YRO`A6Zr6u-wI88bDHwiW>B@-aWbYCy-jqLrP3G zniR3pt=PNzFNL>wZyal&^2lp>zS7f9=J?Rt2W|jxc8*W&wKvnvh&=6KCcaycrCNsD z7KAUmi7M#uD>7k-mRvq}t=#}`H0UXCOti1p+Tne4-8CG&__aaU!2xc~)`W#GL*kmP z-b3OJw_Eokd?s$$d62a#rz4A;G+soXiKu)LW4q^iUR=qd$xGeFJ40?m*L>SAAG~2^ zlz&i*%$PyFTIXn|wPqZa!%qkx7{wx`ox6KG-w)07+;Y0vEnp%K^knatv3-(wV|eGT ztpBXN!(-2fRPD<89AOiVtHUh5$-EI3t9@uKhn3?g5^%L}8tKUQ6(M`8-&aPQ*pT{w z`!D{wsop$rQ9 zzd850_0d1nVp|VbOP)AA5UYJ$GVYmp#OQw7A{~NNxqaf@W38{9W?!|nBLWr%#+%0K?VsKrb<>z~j!%iDBD>V=7VlQ0mukKZ%llEQs zJ{55i^J6%p$+yTJ$`w4HZaKH-=bPhKs_&Z2v|X@ycG3m=Ywpax6Cd>d-KqRl2`s+& zdx4z#Ci3&0w-^5`J=(yoOM0{~t$!PK`7e3VKUDi~)P~cp1B-%_|NZ^_?ea;igU>a-__*sT0p+nNLN23AU6zA#COX@)^fzLP&iK7v+poB#| zY)L=HYMZz?4Z7Wj*u-&onOsELZK%*Z@j=I+`(|=slZ7K~VE2PN*(PHEcm{2@+%za> zVN!=jnPZull*@XH%eR{_Je=pp6?9+Dm#);jk35J_Ox@A7Q`1ZXVcIpiZ$NYl$Ap_u1k^337#OSknbCnP;7Ywg9^;Vw2jcM%#%Wuc+ zH$Hx3u;@h0DHkn|fE)8U`qKc-0-kczw^FDRdc|V2yU9!8mV3s=9J>kqCC71T9NMa4 zA~!SdXj7&}<5vg7VG$oPobdG8i^FxvOc5t-9)y0E6SIZkp}5n2REzxwoN1Jq z>nBSNy&qg;x%b11d+NTYaUI@>J(4;@EmX2Ob}vb<(wp9C9c3Ma z(v)GzjQSfsav=L}0kFK*@1+Ot?0|;WmK0b7xA(V`ZMwI^p2U389>Db_#9xOU%9*W8 znRB&_{`@K}CrbTOZXwAVP@J6c?raSJh@CxMvcEHCzxa2r=mCJ%3#e6mk>TmsPw#*{ z)4?pu_oZ$r&#}*W))t%_5$UkGbtK_5_J=(9V2P0J*j~SZZ3#Aot1TC2hFKMDoZ13o zP|=_oy*awz$c{8J|<+3L`; z&rTnd6@xO>#;h(6Ar_4O73q;b3Bnd?!E zuT`=oE!pe?@*1(`GgoXjc4wV3MYpcb8iSG8-9m>(gBB=yRG4!2SL96Pq1f&4lz7 zg>He#hp&N~$61hpUY;fe#_<>DK+>n#>XsYNB+G#lpqQJD)KWC~>YT2gT1z7pmdO%x?wm zJhH>L4BhDUkx+# z(C>=Ok4aW5c|pL?-e!Crc_JDX$~Uf=!`Y|AbbMrKUcV}^9gDU#3XLijQ`_)4VF5YucHd!H{3CIH4#F17WTA z|Ec@6R>kRX!N@01M?GK7fMC(mwXq!hVi0WSt$Knu?``V4`Dnqqrbb->z3y`%Lglq@ z*NOI}@i~vB-E01lOrelsKIfs}fojsKY8G_2+?>+UE?nF|32TAkH-WV_StI__qq#$e zaH6jkU9hrqu(`ViQN6xa{kh>Zn&uP>*~PQD)#LWfyFAO07RDzWOCT!AWeN% z2m679p}+?sneB_>Q}PO64*fYraHbUp?ZD}-@>P&@8dVcJUPLA@3(?2va(uxpY%Devm;_`Taz5trch51qF+hLlsrq{OmffDPE_| zQxzapIm+fN6^RV=E?d8quXvBH-LC^}z{|5n2%#d)x|lIVApE=n>BM&H8YToOMpv0) zA4tdlV~Ie+As1?~r6kZlJ-L}&hHJE^V-aLk)WRcyBKbQCwrSrI`__%(vc(vV8Kzf& zoz@`?f=DXgFy8=L!3~br+6ap@6(bgm(yH&Z6}rYyX+N!XD9R7aQj21$xfM+gMd^3( zU|2e0lBXCv=W2DZUeadxX1lVMJA9Bn{h?ONJY`M33%cctrk4zuA+qHqVJz}>w_L`o zlC-3pZFe_Rf9#zh2tpIAEr}m3(ANh?ar!wbpP4y1zJJZLA!W*1pJkxVt@_s_`?~nh zgQsyFG&GB>I1r7#q>I|WWY`%17ck*xlc8pMQp#4voTNO&qa@AFm~OmRRD238!z&AT zRHQ)qQ$WE0xH(YTo`9+{MaM*KpUzu32DpROlh>qUKL9j}$E^O!Lb_xSrUL08A;oSQ znM}OWZ424ci0?EVjdFd_Y4q(NIj8!W8X3$l0d^9gImEPnph_YxYO@zGBC&QqKoy#; zY#)g^QI45gLGd6E^IE-sEcxdo=gV}vTA|vM7@aLfPp@dd6l;N5K6mrbGg5g{f|;hH zjAYLjvOCttrL^I?-_7nW!LVEQ{D%<*Uh$27Jh+vG=^$xL(FLMf%*ER3p?A100Y;>Q z6$vndEHwttvCBYnQjGamd-q(e)~cX?0R}PM&_TbXJH=nuk`Z`1Y*Dj!b-vHiKg-?} zd{~e&iRq$aoLb!0ftopLo?Fzk0{c9s$}qhwSR)-XExre=-O3=sAJ<|SYSI%hO`|R9 z7ng};pZaiJaZ>&kyXq}u!5&iVVqjY9LC&?LCygNWF|mh1Fs6*|7AfQRRQ!LWvpE>U z>DN0j3Z2x^?iDmJXqwZ~@k1+T_~>Z>%KS38k*>W&!g$eDc9=XVj*=_WIY|4CzE9Gg zs5K!_jAUy6s|3hhjEvHqAglQNo|HnV0Q5O8Z5mnp;Hst+oVC~S87?LIlF)lsF^@^` z#k!l#EX;#d%p_e?ausa9QHze-gq8Ygr2=g9AulFTsl#gDYXLfxWmIpvhr!%D4ZvXO zJ02-QyIGhvK{Uf`=L?d?Dsj3or6_^^+>oVz0Vmf)Ck6_Q{>YhrXQ3{J7>xjK$+v8~ z#*?a?*xuUa6V2oUiU`T7_ozU_Jn%1*_OK?{^*LQLuozNSi|Js&I&}PA3D85hu-9=B z@zQ@{kg~?$=4l;_zCiaDATYBInQVZX7HEZ%yi(gSje;tpD5F8T)1wNsDIm$vJ<^w@ z=Jhe+EGck^hn@gvPU-AxVW~{$>=O!BBl(-ve9_&E?S=-=jK(a2jWHS7&hJ&Vek2CY zsPBDFLPc-9x6#l*&xiuvuNG|`;~LV@=IYon7IF-LAu2j`>m;-s#&iqL-MyWZq(G`0 zSd)mgr*t%Dh}VWzz`s(lBOkQ?HRBd>lyfZYszuwc0BuRFb~hj^>5ew@=V;UOtVgVE zH0I_X;y3Gy+A&HPbm3L%_d%&XyeP)5ictxR1dI0eX`R^GQ$240+A{-jFnyQYVa@(1 zPZ|xqN*6FfDD^m7sXMBAB5rS#CNB=4QM1H!>hEpiLZdms6`fPk|}EiSU>R{eHNfCVuj@r zwCc?Bu73dmOtz6#r8hC8@SoI<40H3vXR#*?v2S+%Wr$4E6M5pzu!wxfE%D-Ak~TP2dxmr{leO}=Nxlm(RjLD~ z@!rn>;JUh){*0-b7X3iJ)(?QEdPm`9x^0>?}ab{FNp}kVB^pbq)iaSXFc!;1&h8L7r5FdqjM@m53Rq3IajM{ zPe;vPL$~rwB6)z%B(xU^{!gqW4O~<4U_j4L*lMT_X00fn!w@fe9 z^ie)nt69mq-!I5L6NZ_Y&{)O6^>xszENxeSbH;PG3>ic=3VV^I3}$uuT)&cG1TGb? z6^^2>(NQ&m97A;Mgie$hU2FX&R(GBFdm1Y-B^?x@7+}mXx(Wq=UIY|sJyW33HIr)I zDK6#@6+XFDtMXk&b56V{1BG&GA3xn7?fi89@iIT>v))B;AqIM7ZbT&%A29mTba20d ze3(EjtbXriyZi(g=CFYEB`)74D@BVPd6=$!-Ui5Lz*`W&X2{TqX%+r`tg7$49Xbd^9Ibh=V? zyo|<SKqJ!qU?RqhbmMY$p&0xb{m_j9aFTg0F;rxI1eG|mkc~Zyd^4Q3) zYE_$8ivlfkl2QgB;YO0)7Xk4{0Il*1%MAO z=stxKqEm@)1P`vzQDqyo6bUW5M#r}4D>fSp2Ckzijf&B9&9d5}Z*;ATiEW=w}gd%IfhIM7v<~peids`7H&KpBpjrX&=We^ zl{Z8AP>vXVqPM1&HK6{`KtDd+im%dt(e!p84SY#$i9UYb-egn8z@ixSSQbLCd*}h}#XXzmsGIFNkmb*H(_=_PXGX>p)_IK%T4=t74^$({a@kWmm<{4uTk3BzV6^vx>cFvIY!pN>#9VBm{ z1O3x)#g>E=a`2`3ofX+SrP7A!%O6PI zy8Ci^)ZzO4E!$tx))rYl%K<|C(eDX@wVm&FJ7->?N)yb0)lSFiPBra1awy_L@%Dn6 zhgU56%pKvx1x6~a3->|c0 zvWlHwAiYpf6A91H`BgJQr1(0zqY!L8$pqT2b*Sc*Ze+~Spw_%91B)-ba){#gQXa?Q zms@>Jjlzx*l)jG#3|jXHdpx$W=#quUaOK?K@TID%#x z#2_ofPIP%=&aF#twXgvYD6@Oc!|sb4xhoIlSdOd5KNA&_eo)H0PvOG~j4AHS(|#wD z)HGiwHJx!&58OX>6Xv`yJwD$uWb=9P_Lzssm-b1&&u%K=4Z535XHrajwoJTuue!N8 z&$7fxQK<{GcO~So@#c*=Jsj-9q#oQjP;Q#4bbU29KQvuH+vNP6mQuN)djDeisGX#j zwkb{=SLRlMZ;)X>d!pS5AVqz99RlRQiT=@0hLejKF_K2e0ld;g=f@ zY#ZP-+Qga2vPbn4HU+8dM8B9gT;`t&cY5KdOI0#qfM48kJa&7O5R&7dK4sF0f{)#J z$MAMsGfl1Z(~Z~}rWAGNa*EQ`v8WOPONPbP9OzH=w{w1NpuKV2k3TlB?`L%AsI@ok z>W|N14mZQ1RF$U?@JwE{Z&(mLw8R+lj-R*ucyhOU_zsg?A+Eq72!u$>D6rP`ybvSl zwN-T(u`iIRN5=8?eXEjX7BKS@(>7_`3hSA8{I22{g}fDLf;KJCz%7^dIpS|(_Kno$ z>562akC|Mj3BWdhCWlxO#&x>oS((Jp34T@(k*!g2);>&br(V_%!I&K21j2n*5gkfMb7CgC0h)I|44oV<(oz&N%{`Q(E zGkgl$-xH18DeXcp8_U~SM0eo1`7f(opGFG6{o4eyt)RT%~XVf4o>Q!)30m5tj4c~ge~Diq`egXYB?ln zZunEA+I6+rYtUQ}GNykE>@^1!)|T8f`3ULo{(kEEP?s_)Jd1}zEv z(wE4X9rrhZ0uTl1lTp~mzp%&a+_xPSpGy7k?(Bauy=tuY(tTFkykbW!+(o@sK8>Jq zXe_xXWKzc#X{o(7^!(A!HnP(3+oxXlo`!R0bNBxyay9qcbU%|am2Jx5N;DEYiyw*W zBq+_$ZjBu`YB^ex!FB3n6(m)=qWd4b+=ytu3vc!9ahM_oPxF)`9W7Lq{D2>w?lMTfnfF1K%k~};GQ?4@NUDQseVL4MzN&&ZFvo8AzJ63iMxWC^ z06dk*R*T6S`DFj#!PMn5PR@g#b_F8)@Z4``xUXw?^9TDznG(~O19^qTRz`>0C$Ovh zKFb}tPDLr^$YYs()@Af!Oqoy#|8&d8DhubnIgM=5|N`X9|Yxp7?|B^^Rw- zkIRI6I%mrgGekno^M$0XlJWCP;Vg82nVd<-nSwaAB^3j2Ago(Zl76e4ws26LfI@L} zJP_8f9Lnvts;C6CR9&tT>$lExTUU>c%yQG2htNT0YdbCDPp{d8qx}*t_PBlsngU4lg9@CfKaxahvx? zz=u#^@Igtg-I@h_p8;bkBCnTSFS8zz{cbF$qql@iX$R7GV z#&wzo6yX`o(^@?!_*@k{0l#EUD3x8}B`=-jt)llvUd@)BP_Phg%dO2Y!O)4}Ih?I> zuOy!)7&L_p30M1%7r{lsLSKIA9>2l3_R!oy>Bx+p_V11z1eJnk>E5mWhnKe^I&?Od zn#&$aQhgoKnW~>uS_;W3g@n61=p8SNibzWnURi#r@Tkl__1AQ`f^TxMeC$K)0?xx+ zt1E0O?Z;tjyxd7nt;LAA=wYQ7K#y^+aD3f7qqapJ=6bqVK5AXt;!>XhxLnl!jd^m7 z$kh!MmBo&2fV{X*WBZPt-`BXdlm0Q|8)HL!h|~Wy{K>F-(cN(kPQMX`1aZw@ehQTq zWvS16_iY^noI8%2S$R3awK@H{C~Ii<)HkN*v8!blvv|648T~It%=f$g8{|SN36M;D z(zdKgz5Ozebj~mGE~JHJFA=>w99IFw)_ag7q%%}9pPaSpRXr*m*i~{4UOw=aUGOha zQyAb-a&Hi6XjPo2wH2L~#jl6G=6f17-YkL6J}*q~uE)ZK4V)CfV4%nT^lp%tmUU$d zeEh6I71QAt4e|c$?wG0LNwcIHa6qErCTk{$@gp2hjBV7%_gX@217wLr;43CNO+r20 zBh9}{R{BGQ5$Gm@yKzOmJKgb`@17eU+JB&EcB>UYUL9=as~0wk3v!B$<^n*Ye7|u7 zrsYQt6`4z&MidYg${D#ky%gBYBs>!`Ow>}Uf<2a;{12QkqMNWWxxLqhIv7Khh!SKr zCq9kI@Ww0j%fJ@++OJOgK)<0Q>Nxl@XqPxX7XX@M!X-Gb1K*QO?nJGC9iuB1^>aXh zYACPqLk?%606&8q@e2R<%c!sq_=5Tj*lULU$J^Es<(s$jAZzvr#S7j+c+k7*!8T9 zQ=P&v0@g0@yPj+9`!Q^>3t`Pbe<4DaWvQ8CunmOL)ol1zhC!==2JcS6lT?KZV+xgH zP$^g`meEN(68MC-v*@F1axEdwk#<$u8fC{Kn26dMRjBN*E-+Pi|kGoZz44Xbv$%NqRkJm-p5owS$ zl6$~T!Y8TsM^h*u8hkvf`-cIeF;6Dc`K?H+MDg%+nN8~qrHu(5{C!)DS7Y?ixsx&( zRA8KP7O_0STcJd9a%felt5#{#olm;i+@^!HP!pz3Qa#~ar>nn5aQsKWO zN<`Y(K*EK|T^B}EoC&2DUgm=cA2p=%-t#foyCbm2GT?#`&eLp8Hzx#`n;?5fZG*OH z0}ofxPg&U?NMx$1se+q$r@oaY%-br6rIr_8smB{xWobLtb}Cm#Z$cgBC^c5^*_bvhW5D(wq3xG#{O z5!Fl*U9oI6JnerJ-TNa`{~rhN-E70`;ySmPTkiKe!)Cc(T5e4)jTA|u+%F$yV@U2K zQIteUNK&LRA-CKrm1-^_Nk|vn_TBdn*bnD@w)1}PbzZN>QyO9@mR2u5P4Zl!T=2%^ zf7Z|6JqU4zBE#cE8!6_aU3xlqk$8dgVI?SVhu+oW=N+@pr^jK(fM64@TohY4y$?Ck zAKNrT6&*pZl^T8eN)-lz-)*5>&LV$riM%^1bw!oH^@1EM0R?9uZNd1A^=pa}M!r)> zVL$LRQ7n0~=B1&MQ(HmG5VrUFL9JGwO=56DaPdD$Tz*F4y?y~9hU-G6&FdJENpD!* zSH$@rqTrdpcyir`N$ZjylCeMhNAA|V*5DWF<$g*a-OIyGy;I1!Cc67Ao!KS3TL*aE zSphbAswG}UTkQIy<%k`1%jb&_sm}6vmFCy4)ZIeQW^%xJMPc3$u!TKJyo4@8lZm;g zq3d*E`l9|1ipb~xL$i_#wU!Hsp}+2j8jwxaX_pQ*RMv?$uV|(T9Yqq@s`@nO>$Zy* z%1|;gc*$@Swvj$zU!^cyw*zPytFM1rD*0m;xxsDUBBp(wM4tRnmhX~M6@8#->*B#O z#dacScRlCA3WKUygZp&NBS*{MQlw(F)afTGu)=7q7CIMEYuItTEwCh^^JyX zjTUgG=e<9wW1b->|1gg#7MFWfaO19_9auP=5pd)zpJO&TDUN(agC=dGczwz;I~Z^) z+oNpzR2&A}fX@8vOBt7zIcO=7KkQYI1CzZ5d%Yl{4iNLsMQzu@C?|!b7lkig(l}0( zwJnDPvypF#!|f>oWf_8({jqMUF?t6>-U5(yMQAZF#L>_Nnj*4i)gS} z7fTQec#*O!tV{+%>S^ri&&-#eh62*s@yVi1Me5_V%I$db1WaS_q1z|{W&|5)JHMb=ioETg6nq6B0QrRP$l5OtJ=9Kjd*h{;&5cumEDw>J<8}0Z6_b>>Qt<^JN zg@>%BG~>-7O2SvJxjVB}ZYfpk9_@H*2IuPc@!kO{x>&qWoM0#&q0;(HybcZi zidv<>cts#0T4dW$B&_ZKXyOmHusSh;&oi%G)ywqvs-0^~~Zj#gQ#$xWK+IBqD;zPJ>*npLc1PBkDh=K}{$E z^|S-oO9pUJRN2<$pg3D4QXEes15`#k@IkgFw>We@1B6ml(cp^wMWZgDCneA3e5uV5 z!LUB-?~66N2ETUGqwMi-roNG(dTr$q_el1wH6L@L$SW|iTBqR9mhz8U)I;!tae&M) zUQMGGx|X4>H-olnmfuj3;d1<|Und|iV4J2B8Ue+9t^I(~;?Y22kgN!C^5t zJCfRodd@!VO)~#RVM>;Q-kY3T9vMXNp;%8a))O@|iBqS+R*8~dTmo7gL7}1u!_}cZ znPJyOnN>Rxtqd^lp3e!Tk$vB@dSBD#zCQ`g(XasKJgw~C@9ZUzb{qO4@OYT%2*`6p zI&nm9jc!{X^@A;9LNibYl&BtawCCo%?H6i7BZoo4O&Rts-KDQ)o`ZMdmoXyhcs2CZ zK!s7EPGbgnM?}-+3-|A%|LW>&jh302&-X6SfQqeIOdT)heXLRo%Wc!3VDHC{s8O>BB|z#5ZqD}#TP)|Zi#SzNtA5)ZUK-L??mW$3oseCJ}EMv!PhNO zDc?}zPE>BK$g3?8yKhJa+WLu(@V#afujqvbB_y^AJv}2{yD@pcVp`JjG^HC6B#Yuk ze>^pKop;Cw!u8?PxHpynGT*km)QS;1JIMF7BJc3t-|zt=rrm+cvX;B|=8Ht;i&%S; zaX>@mZ$uO?1C0oQ=0u>bPl$X#8*UdZQa;_D>^?|A$nc5T4{WL4urDvq2ozlyKaadO zz`geskDNzuUO9Tc9f<6+LS7k0F5r>N83^cAW|05qS4AQVT*60+&8bKc$Tj3VTZGF+ zylh9azoI?>ug%QRp>!1Qb~ZYxaC6beq!odQM|%5XE4^Y@r`aK4f>~fx^62I!4jHs6 z8O3!m$)fjJzv2Y;J28-%W;g%F2e5{oUz^HJ`p(aqKw8c2ysHxn(n6K%e&R>c@-DW= zHQFQJw2ExLdlc&bj9DjE8-sc~DGye9-^udXM?U^31C|&lrFsgryiM{lh)R+~Ef(#} zXCN`hk*CMBPc@fcE7bVwZN5VLI21zg-Zg+8{5+3G_8vmvf=uup4HdP@-=e+DTScTn zv+vrrgCnEydOHKe0in@WBb-iZBzm<~C2|U$5;;hp_p0$Z+`5|8@9^D zO0QLq%hqZCATr)-l&kitmZU206VpuMzB)}&<)@x%yqkxwyTpZ0s}MW?cHcOy@c6%W z-w^kbW&hq3-uG{Bq#{%i{(Ib}(V^2%`gA=G%?qJ1E z#zrJO`@WF))Z8Jzt@*tbq34cEGw@;pzn@Pbg`Il?7xen964ZD7L0Dfi@1HXWaeA}Q zvH8DsMV6kYFX$>V<(Hzt6@>GyV|Dq2mfDp)WGSosZpq?8ae{u2h>0#fqV-bx>yHO+ zF^l>aij%)LIf}{cJG^fF-_K&zZuWG4a~-k%nr5!n;Upi02c%>QA@gxqt@ghfPX8BHhn`n5M&)NP01=JG*yRmnUmS1| z+Lyww*}wTkzrjf;I%+Jt#8y9jRcR~{=4_pqLzfcui4-bKaoQN#pGHB1O^LI&S@OEk zzrqAU|1`0RBN+XC;zU2i4rTt&CGY$zG64?{5M^PyRWv z8Y~x?pjsf)Nz?#$qxgN${efKvW36@{ToVOtqFy4{x2E0<#WFJ_D5cnx`QgkK|Y^-2u8 z7^?X~zEJUpOhd@c9IXk=9ii%uhf;T<^SEhE=^0L{(o{S&t|T;7@Mt3b=FhOIXphH( zlKOv+8lyrVN;_7cfKG)J;%~!2wr;-b{fFx-ep=jX9#XO5td1F(QcKphlb|;xgM1;VQ}!g+;8)@Nb3p zT9@$oUu(2m+N`5m`;o#O;QgB7`2wOGmhFBA^${?{1Ok?QBgQhTrstlEfx=4IgKqt8 zBK`qcu*7hdO((r;Vpxza)FH4dzSYL_n)Zz# zZLSnMIvgy`=)!tx*0Tjx>fl+|Jk&~p&#|5gLg$8utNoIkx)Ec-NZzu5gu@%Jjq*ylzrrp|Sb zCIqhK3`OS26dCkIQ?H376QO$9Cob={WvU%65io3gDM3{Ni*+E#`u}xNpz$Cj0{n^6 ztNT5!55Llh3&4Hcmk&bc=;EVYTp)*iE_9Y>pmumiz!2fb^ig4m+XFIHRU*s}g0^D+ zo0mGkuVf!L*?LZAb zk#u=ZrRFY2n68@SP)cuzBn39=iemQ_=Iz|=Vot}}zQ z`0pS?qIoh}D+9P&UBtw06xf*;jigtBz)bN9n0ff;{o&o+uNEufp5*tL?_Q{>=1RiN zPe>yEt17~7L(wJuZ`B?{u}Jht#92FgI7eqhjYT z=k_6*m~rY+34kH7d;c-!(`m7D0LCxRoNkM{;@GNt*mWha!Y)y4sfQZ)GOAP4e(j5i z&b)-8M%KN*_m)ymo+Ait1Nf#W$~_K{#O7}qp{z4clb@j)Pb88&|Bc^!NJ_nTtf1MrF3+kg{2!eCTG(a9Aa%5km>xzcgkU~bUnbui5R z^pMUcr-F!?+>IKd+x>f%@%Il=!1`MtKCv*=ROlYr-F`{!Z~+{V*oR7~%!FtVfk<6( zluNXV?XOCfYU{FC6u4k+{JYZqyC(|Ls*gJLUq0Q(i{I)?>sJ3e;%IFH*`QsSeaqYb zvsIy2Eb&u$>xql#_ek8CoD{;c!s(>3EUlO$UI8m(4SNq2dqLs5%I!ZK`Xol^D7??_ z6-US9>GJ<#k0m6$Bz6tx^X&M!qD2#RuY-Oan7E6GY*bcB^GtZbdLdZadQ@gS+`)V; zrf`WnP|`;gIP@f_Or=N(Tc-bO{#%ruH3Te4eVf9?%)6cwez(PPOkFI-f&D8@NM3Rs7YP@V^+3cQ??H*nX zA!g7|1-_rx`|{uB!Kp`IE_nRx7k>Y9$gy|s9;6^8)=h8!4ey=nwrQM~8RDyO$8^N| z(J_Bf`47X{M!E-?A2n?*HJd9LJu)~y;r0IS7Z%UlLN@)^%lH3?+wywtipcu-CFu3p7w=b8=~puD zSKi;R;@z(r+P|-(HSd$TT8{;GfS|eGPOGe6d$wO^xgR%6dhDk!hbGHawwTJ24R>>u z&>V5&yy?5G>fSwi;zYC5{yqlTn*&6E4+%UXyF0OAA@vhgmrS|&PIn@i6N z;<3h+!8~$))e}Ofg-z;!p7)bIPp~VE=>Rf1B$uZ}gSd)om3(^Q9WdAz@}xoC$mL9x z;Vt_;qk#(9fwDKZjxTq0FFFMOcKE0~c*K9;Oplh10VCGi(Fni@^cR}fd^|p#D-**? z%z-6lu#zd_@}HOqt&XY9tZy<^VU?^T0Jd++L6SV+E9ZDsU0YwDp+6~TFa~z%V!GBc z35`I+fI1EUaqV*Qf`AGj+KIAHVPAc=KBs6H7C2?#mcx3`%t~#|3Y4yjh{l|q zbbfr$zS-OIwww^29|uK*#hJq*z-SjVE8eLnIR_RGhtak2W|Ud+m9XSm7JmmmGwF7$ zj3cAZXt5flzj0|{(rI(BL<)1?qC+zTWSvu(N)uR#aBooQIkim2W}s#cLyb#vUjAwB zgG`*%9$@|%zqxGFTRie%+2sh??dPQlpJtDld5=5Bb~-0uUHF`pudFlrwVTX-^aISz zr2E-DnXd3GkD@GXCFo-UUU!oDvqRv=y6a^&Jsc0OI`Qn{>;&+b$D?kZM{NesWDW{% zV~yi9^n7eM+&y3r{vvfQV+m37Ps8c(wd4ToMSDJ|ZA*}u6{K+C8y314r1x1tF~?IPmX zx};yX4gE#8+Ve>MKocq}t??O6wnLn)l(y!2P774f2zH-j61HZR*+G(52Nsy9#|OM`C@sKfnpP1Q-h^o zS(H`?fAM0>1-&UAr}keC&478=z)~of{p|-Goaxv!mbCkfAEdaz%gglxJxczn%PAp( zdii(6?@mom2X8gPM~zwJ7`Q zoph0XP1SO~B9M9)qOgU3k5i z7|u$gdcSo68O^$2P2rzh@_nlzc<*rc|a=hxyPEH z93JS-hG*9J{cA!;J5f_6v(K_wVaNP$*WYeY6=>7}`A@PUKEUg#xsFr;f1-dxEqJ^n z=V|$26D*VTll9~;i~wi)xggB|5UUJbGc2>kUWhPv*s9B47v5Z}de9y(aP9f9^X)E& z=U}%Y0lzgSu?sZab-=oaH>)(s*pz2pYD8PtGJdFJ5s8-_GhS;oO37g%Lg!(#SE-Pl z$+)@mH1Kq8VEe}{=a3C0mTK?kfZ(-e&;0TM%ztxxOTALPRH+6s{=DBQqhPGD8>=Q* z2ON@^9unV9~^K95k~-byi{xu^#Q;_2lS3ASg12W$+&?@h9{}PkxdU zE0_kG5fVI;;atJZk~7gsp~52gx^-e`**HO9Krp%zcDD9HeXC8nv2e9IE3FoG3IGnx zQSr^ikCrluCuAG_xX$@?xY}K~12TBG%cpaxIG0 z830(0!i>{DN~$<_8p(+L$%+_;mewvFAGRpzzHlm$6(k^-gon-jER=B)NTjkzTxfcS zBb^bRqz;S1!;_q{!{E8eTqtB${>(5diA&2n*24^(EBvsqDi@-8enBGs1moBQ@~mgY zy%F_C!ByWsmN!$C8eU!Ty$$(H{J4Aq-y3}H!!1dh#R}I&)fRnxG$Y|BfB9HR(LC4# zMDF--LliN8G!&NLG#5V%X667x0lCTQ!~DRSg(Q`99@dI#^U@|_#Pe1+>#=qY9BHn1~R`%*^q<MZwFsUBh_Br>m=%YMQtu@m)-Hf`piNx&QM3`ki!<))ViDnTKb@6am5j&g6%_N0SX3j;r zzYA?%qLYd?PZpJ+fd!|{J2mwM%)$#L!aq-*H)}3F)-uNv^&k8o_9efADxA#C_E>|Q zu4JVGV7V#VN{wKz@L9aq=JCsOduK9_Votc$f}M*()}e@;cub@|LyH2=9Dtq3FjDJe zeGXzB=VoQ!2Mgtm{3^AmOv05HAsGbYLdZ!WW;9NO6uZE^14QB z;g}+U6SdhVqO+T{Q1x3mr;~n=y7z@`ZWBz;$gF-UPTRg%;pg{dPttZW0Qw6PwSL8B zTkhp{$=kiE`$@8g4DV^L=gFU`UTwZ)d#1;eC#HHl#q4 z>V;1NI5+8hSv!n+(>M<(PGO3N2#5^Jf1LagWzITAq|Z+QLMUHOE#zAqc~i0seEja@ zdZUi`8k!g;L~_gzn**k3KjipdMZ-;-2y$tEHcjtXmhS| zhYPgs!kozw8qmx<+jacp6S|K%EM}7N_yACj0!y2O{*DcSlVC(A`oX1~AAlrJJn&vY z;W0eWQ+@dSEp5?OW-=fry(z?ej~CXOb20w=>jh_^3KSc+HwZNNsrNLGKkWXZwUQ~^ zd3J_2kW;5v{wTR3n%W$E3um1&lhKU7xO@cR|6?V18h;|FH&lk*I?6g_f1aZM{?(hI z1MeRtzipY1Eva{Ukh(Fe@)6>C0HYQ%RHAe8yY{Q}@bSX|{*!qB&gl0eKA%i)Kj}$+ z^X~1ZggbK&68EmE&i~k?a$+z`I@K4p{kscPyM21FhM}Vj-oMXUb4DK?R(}h5(UWAn zK6~@f-KfvMOg3JI(rag=3TWJP`}rQu1(Cry?1$Z4&H^N-D(=U;wO6d_V4k>E9(={X zImp_tOH9_SL}jd&(r6cWS4t1XD;y$jG{13-6!_Ri0Nr~Nb~4LfZh5!(R`KumLeG}P zp5X~O5@hv*#h&~k`#|XdBaM6?hRM&KuW;AGatT?Me05w3Ump3cbXR2G zxc&wkzO^E&aC|j8{&eK#)pK9`1da0V9LKp344z2%kG+n(_jd4Y)FXH0;7gqIN9S$L z&CjAnwsJazq&i)W%g4W-Iu~HN!8StO-ks#H{d(K#V_{?T6Me)6emfLj*eP=Y9@}`tVSCsU#|#}k+%E% zhaocTF~GNdjCS;$tb+?{4%n{HZuw$pZg(ffJ6?QkR@LqHUe+i1mzDY^4%EWDdYS=) z7QaL9f{-)2=GUo*(BuO)4rhv$ipW~AjlkOPiY-s!&HP?Id^nz^O20iwL%td7fquO+ zGJB3DDK6KIK2Cy1jMGs)Zk*jLgPeP=&O*1ioIl^}TBcgFO_vW3M&7MqY(W*K*awDp z4cas3nb`G8-jFpP2TZQzh)b6|i)%O1Rr<$2tL(uD^HT*0vr7ca%+ci6UvVhpxDC+_ z;kV1VqWj4H#AYkGyqepQtR0@5rkuSN8guV1eJfj1D^q5As^I@~kqhRRj^4SvjkFV;mcKv~MB*@|w48~EFF9UMEf-Y2Zj_vE5thL}uhU*y6NXLCvCKEN zka1l=`7Hp`>{rbB&-Vrr!K8N$Eir?u_RsJ{Hp4Q}VmKj@3TvhhPxwNx%wW;cHK^4_3@WjC`PjiSzr)e`f|RS*#Nu1QIb$<- zJDHg9(E38@k0z2PN;(F>=^@!A^C3&*D9%f`fTTAtblv8gNmL^^RM{V9vUc6GcG+Gi z+Y9-n5lu9`sd6L&041y`qGH#wsVG;ew!|T;`v2>*ZAha~IPCb`jM?!a-h~%7EfxL` zRTFxZ{hprb!<*9v^v~@T9&La@=c8X3@6uqFTt&Y-ze|m;OsPH^07&i;hcq`y1?lP$ z*tKDp;p~q>m%#Pvst8A$S!uboaz-LAaU)vow>geW*Z4$z;y=zlmpr?!13cE!J2!;1 z>M7I^xqZYG|4SqdUKsD&lxhAQQ*aAVCo7qmrMlUn7D-*ige`myJbVr-@u~c}#rbN8 zb)#2*hd9kXtL?}O`SUX8ea(RO~{oG=+|hQt6-WU3NoGkD@frF+bynzdqWCjbP`E5b|v+`7u=5Q5sv z+QLm&v}A>MUa~tiNU_YrgsryxTOJ%cD)~aWs_Clpf!DpzCcD26>)?q@g=v#=` zN_r7Z!b5Xt>x_}4FfU8)H`a0fVJReL`I?;fE1j~tyZ!<3tm(4<!EGF~s)w#n9+XW}N*JNaJvTYit3KE?b&pkPLx&c`-5jXv^ zx3{I^EtEb`I3X?2p5wBIh!jrgVPIBt8-1||c%pvnf9UK+Gj)R1i;zSGZkG$DAETN$ zaBcDH+A?7pn9XP^yI1Ji=CP-`q@iH)G&;$!@a!WyX+wS92l{qfu}0U7;w9Hivd#mF za_QM=w(*MgvF5{;UNgLT!nA{}rN|RG@cFt7*ubrb3k>u2mXCdMYczq>O+RpM2H1b+ zAfKvLd@K^mSNr3MvyPHlTy4L@{*1r*%1}+{q!B=P$j

ei7`Pc&d}=8-Z)`BW=jI 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 literal 489732 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 z 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�yQEVP zvWqMkMxef@|2#ZWyGYHXOj?&R`ht?zP4%i$#d}%(#nIjHsQGec$F*pIO4&-wC_)Hr z*mx=P$={19rNGc0|2ee(B|9g7lHcF+kNw<>{tN%Ob;R}${9^^`U9De0w#HMC5>o6h z#O50jYo4FLn}*ddIt|M37aNDb8~+ykm8fAYvqL+lLAh36F03w^ zdxO{K$AT4j$)*ti|JYo^&hJ^G^Hc67kbl2&%#g&y4&)!}Gn9mPrODOhu zL|G|NoQN2(43_~yl)-YrK7jXU$ksANQvnQ7g5|nLnu!w-qAaOALTnysCjVB=WG@XQ zq>+XlNJU7i;&$h_zjVE%0DJP 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Ï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 OfL^J=q9+&tkp3UK$`}d& diff --git a/docs/demo.sh b/docs/demo.sh new file mode 100755 index 000000000..eebbd856a --- /dev/null +++ b/docs/demo.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -e + +cd +rm -rf ~/myproj/.* ~/.rtx/installs ~/.config/rtx +PATH="$HOME/.cargo/bin:$PATH" vhs < ~/src/rtx/docs/demo.tape diff --git a/docs/demo.tape b/docs/demo.tape new file mode 100644 index 000000000..749c50f11 --- /dev/null +++ b/docs/demo.tape @@ -0,0 +1,76 @@ +# VHS documentation +# +# Output: +# Output .gif Create a GIF output at the given +# Output .mp4 Create an MP4 output at the given +# Output .webm Create a WebM output at the given +# +# Require: +# Require Ensure a program is on the $PATH to proceed +# +# Settings: +# Set FontSize Set the font size of the terminal +# Set FontFamily Set the font family of the terminal +# Set Height Set the height of the terminal +# Set Width Set the width of the terminal +# Set LetterSpacing Set the font letter spacing (tracking) +# Set LineHeight Set the font line height +# Set LoopOffset % Set the starting frame offset for the GIF loop +# Set Theme Set the theme of the terminal +# Set Padding Set the padding of the terminal +# Set Framerate Set the framerate of the recording +# Set PlaybackSpeed Set the playback speed of the recording +# +# Sleep: +# Sleep

+ @jdxcode's public key + + ``` +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +1wxfuzN2+ao= +=/CHf +-----END PGP PUBLIC KEY BLOCK----- + ``` +
From 32b19822b32cfd1e5110840abf1399296f28b03f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 14:10:39 -0500 Subject: [PATCH 0617/1891] Update SECURITY.md --- SECURITY.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index 2000cdce9..2059614b1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,64 @@ # Security Policy +rtx is a convenient tool to manage developer tools, however its model is also open to potential risks. The following +are major areas of rtx and the security considerations currently being made and what needs to be made in the future. + +## Core CLI Security + +Development of the "core CLI" is done on jdxcode/rtx which only a single developer (me, @jdxcode) has access to. +Other contributors may only submit contributions via public Pull Requests. By reducing the number +of developers with access down to 1 reduces the chance of keys being leaked greatly. + +This does create a [bus factor](https://en.wikipedia.org/wiki/Bus_factor) problem. If I suddenly died one day +or otherwise wasn't able to continue development at all there are some successors listed in my GitHub account +that can take over my account if need be. + +The dependencies in the core CLI are a security vector. I've tried to be reasonably judicious about what dependencies +to allow into the project. I only select dependencies with broad usage across the Rust community where possible. +I'm open to PRs or suggestions on reducing dependency count even at the cost of functionality because it will make +rtx more secure. + +## rtx.pub + +rtx.pub is the asset host for rtx. It's used to host precompiled rtx CLI binaries, and hosts a "[VERSION](https://rtx.pub/VERSION)" +which rtx uses to occasionally check for a new version being released. Currently this is hosted with a mix +of 3 different vendors for CDN, assets, and domain registration. This will be brought down to a single vendor +to reduce the surface area for security reasons. + +## rtx plugins + +Plugins are by far the biggest source of potential problems and where the most work still needs to be made. + +Eventually we will have 3 types of plugins: + +* [core](https://github.com/jdxcode/rtx/issues/236) - plugins that will be hardcoded into the CLI. These will be +official plugins for the most common languages. +* community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. For now these will +only have @jdxcode as the sole contributor, however this may change in the future for particular plugins with +dedicated owners/collaborators. If you'd like your plugin to be moved here, ask me about it. +* external - plugins owned by other parties, these include plugins in the shorthand registry. These are no more +secure than installing any random tool from the internet. + +Just because a plugin is inside of the shorthand registry (so you can run `rtx install foo@`, does not mean +I vouch for it. I have no idea who almost anyone that builds those plugins is. If it's coming from the rtx-plugins +GitHub org, you can have more trust in it. (See the owners with `rtx plugins ls-remote --urls`). + +Over time we should be able to move more plugins into being fully maintained by rtx. I plan to add an +`RTX_PARANOID=1` env var that, when set, will make changes to make rtx behave as securely as possible +(e.g.: only using core plugins, only allowing plugins that use GPG verification of assets). + +## Privacy + +Currently the only "phoning home" that rtx does is with the weekly check for new versions. It does not send any +data (except its version), but using the IP address I'm able to infer some (very) broad usage data for rtx. You +may opt out of this behavior with `RTX_HIDE_UPDATE_WARNING=1`. You can also audit the [code](https://github.com/jdxcode/rtx/blob/main/src/cli/version.rs) +yourself to see what it does. + +I would like to see some basic, but public analytics information. I think [homebrew](https://docs.brew.sh/Analytics) +did a great job of doing this, and we'd have a similar model where the data is anonymous and publicly accessible. +Doing so will help both me and plugin authors to know if we're building effective functionality. It's also a great way +to get buy-in from organizations to do development with rtx (especially at large tech companies—they all _love_ numbers). + ## Supported Versions The only supported version is the most recent one. From 7f214dc3d3e9c44e157832d6236da5e84c398725 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 14:11:09 -0500 Subject: [PATCH 0618/1891] Update SECURITY.md --- SECURITY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index 2059614b1..25f3243cb 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -3,6 +3,8 @@ rtx is a convenient tool to manage developer tools, however its model is also open to potential risks. The following are major areas of rtx and the security considerations currently being made and what needs to be made in the future. +Please open a ticket or send me an email if you have thoughts on how rtx can be made more secure. + ## Core CLI Security Development of the "core CLI" is done on jdxcode/rtx which only a single developer (me, @jdxcode) has access to. From fd579142ccfda12912ebb85fa229dc1873359c13 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 14:35:55 -0500 Subject: [PATCH 0619/1891] make symlink shorthands non-experimental See #402 --- README.md | 3 +-- src/runtime_symlinks.rs | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 08d4a4eba..102ad76a6 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ v18.15.0 - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) + - [Is rtx secure?](#is-rtx-secure) - [Comparison to asdf](#comparison-to-asdf) - [Performance](#performance) - [Environment variables in rtx](#environment-variables-in-rtx) @@ -977,8 +978,6 @@ latest -> ./18.15.0 lts -> ./18.15.0 ``` -These are currently experimental and only created when the "experimental" setting is true. - #### `~/.local/share/rtx/shims` This will be the default location for storing shims. Currently this functionality is marked as diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 81e7c4af6..bd9b3899f 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -12,9 +12,6 @@ use versions::Version; use crate::plugins::Plugin; pub fn rebuild_symlinks(config: &Config) -> Result<()> { - if !config.settings.experimental { - return Ok(()); - } for plugin in config.plugins.values() { remove_existing_symlinks(plugin)?; let symlinks = list_symlinks(config, plugin)?; From 8ef9ecd5296cc3b0f842da4cec5ab35b3f47e1dd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 14:38:55 -0500 Subject: [PATCH 0620/1891] added rtx-java (#401) --- scripts/update-shorthand-repo.sh | 1 + src/default_shorthands.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index fc25b0a19..bae7039d3 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -7,6 +7,7 @@ rm -f src/default_shorthands.rs custom_plugins=( '("go", "https://github.com/kennyp/asdf-golang.git"),' + '("java", "https://github.com/rtx-plugins/rtx-java.git"),' '("node", "https://github.com/rtx-plugins/rtx-nodejs.git"),' '("nodejs", "https://github.com/rtx-plugins/rtx-nodejs.git"),' '("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"),' diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index cf48fd45c..f98b88091 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 632] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 633] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -637,6 +637,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 632] = [ ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), // rtx custom shorthands ("go", "https://github.com/kennyp/asdf-golang.git"), + ("java", "https://github.com/rtx-plugins/rtx-java.git"), ("node", "https://github.com/rtx-plugins/rtx-nodejs.git"), ("nodejs", "https://github.com/rtx-plugins/rtx-nodejs.git"), ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), From 9ef3a7378bd29b1ae3df0981aee351bb467a1fb6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 16:42:28 -0500 Subject: [PATCH 0621/1891] show full error messages --- src/cli/direnv/exec.rs | 4 +-- src/cli/install.rs | 4 +-- src/config/config_file/rtx_toml.rs | 4 +-- src/plugins/mod.rs | 42 +++++++++++++++++------------- src/runtimes.rs | 4 +-- src/shims.rs | 11 ++++---- 6 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index d56a5cc2c..568bb0ca7 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::{Context, Result}; +use color_eyre::eyre::{eyre, Result}; use duct::Expression; use serde_derive::Deserialize; @@ -37,7 +37,7 @@ impl Command for DirenvExec { let json = cmd!("direnv", "watch", "json", ".tool-versions") .read() - .with_context(|| "error running direnv watch")?; + .map_err(|err| eyre!("error running direnv watch: {}", err))?; let w: DirenvWatches = serde_json::from_str(&json)?; cmd = cmd.env("DIRENV_WATCHES", w.watches); diff --git a/src/cli/install.rs b/src/cli/install.rs index dbbc369d5..53646003c 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::sync::Arc; -use color_eyre::eyre::{Context, Result}; +use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; use once_cell::sync::Lazy; @@ -167,7 +167,7 @@ impl Install { } }) .collect::>>()?; - reshim(&mut config, &ts).with_context(|| "failed to reshim")?; + reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; rebuild_symlinks(&config)?; Ok(()) }) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index f69fb854f..bd995c7f1 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -4,7 +4,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::time::Duration; -use color_eyre::eyre::{eyre, WrapErr}; +use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; use log::LevelFilter; use tera::Context; @@ -560,7 +560,7 @@ impl RtxToml { let dir = self.path.parent().unwrap(); let output = get_tera(dir) .render_str(input, &self.context) - .with_context(|| format!("failed to parse template: {k}='{}'", input))?; + .map_err(|err| eyre!("failed to parse template: {k}='{}': {}", input, err))?; Ok(output) } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 28eb06fc3..4d8964eba 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -265,10 +265,13 @@ impl Plugin { pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) - .wrap_err(format!( - "Failed listing remote versions for plugin {}", - style(&self.name).cyan().for_stderr() - )) + .map_err(|err| { + eyre!( + "Failed listing remote versions for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err + ) + }) } pub fn get_aliases(&self, settings: &Settings) -> Result> { @@ -281,10 +284,11 @@ impl Plugin { let aliases = self .alias_cache .get_or_try_init(|| self.fetch_aliases(settings)) - .with_context(|| { - format!( - "Failed fetching aliases for plugin {}", - style(&self.name).cyan().for_stderr() + .map_err(|err| { + eyre!( + "Failed fetching aliases for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err ) })? .iter() @@ -302,10 +306,11 @@ impl Plugin { } self.legacy_filename_cache .get_or_try_init(|| self.fetch_legacy_filenames(settings)) - .with_context(|| { - format!( - "Failed fetching legacy filenames for plugin {}", - style(&self.name).cyan().for_stderr() + .map_err(|err| { + eyre!( + "Failed fetching legacy filenames for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err ) }) .cloned() @@ -316,10 +321,11 @@ impl Plugin { } self.latest_stable_cache .get_or_try_init(|| self.fetch_latest_stable(settings)) - .with_context(|| { - format!( - "Failed fetching latest stable version for plugin {}", - style(&self.name).cyan().for_stderr() + .map_err(|err| { + eyre!( + "Failed fetching latest stable version for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err ) }) .cloned() @@ -399,9 +405,9 @@ impl Plugin { .stderr_capture() .unchecked() .run() - .with_context(|| { + .map_err(|err| { let script = self.script_man.get_script_path(&Script::ListAll); - format!("Failed to run {}", script.display()) + eyre!("Failed to run {}: {}", script.display(), err) })?; let stdout = String::from_utf8(result.stdout).unwrap(); let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); diff --git a/src/runtimes.rs b/src/runtimes.rs index a654cf2e6..14a0b098e 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -5,7 +5,7 @@ use std::fs::{remove_file, File}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use color_eyre::eyre::{Result, WrapErr}; +use color_eyre::eyre::{eyre, Result}; use console::style; use once_cell::sync::Lazy; @@ -417,5 +417,5 @@ fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> Result Result<()> { } let bin_name = bin.file_name().into_string().unwrap(); let symlink_path = shims_dir.join(bin_name); - file::make_symlink(&rtx_bin, &symlink_path).with_context(|| { - format!( - "Failed to create symlink from {} to {}", + file::make_symlink(&rtx_bin, &symlink_path).map_err(|err| { + eyre!( + "Failed to create symlink from {} to {}: {}", rtx_bin.display(), - symlink_path.display() + symlink_path.display(), + err ) })?; } From c2feba6c5abfa9d80d9e0238e785caf37d211a87 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 16:43:38 -0500 Subject: [PATCH 0622/1891] chore: Release rtx-cli version 1.27.7 --- Cargo.lock | 36 ++++++++++++++++++------------------ Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 919f87ae1..19b6f381d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,7 +188,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] @@ -268,9 +268,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" dependencies = [ "libc", ] @@ -359,9 +359,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" dependencies = [ "cc", "cxxbridge-flags", @@ -371,9 +371,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" dependencies = [ "cc", "codespan-reporting", @@ -381,24 +381,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] name = "cxxbridge-flags" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" [[package]] name = "cxxbridge-macro" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] @@ -1493,7 +1493,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.27.6" +version = "1.27.7" dependencies = [ "base64", "built", @@ -1669,7 +1669,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] @@ -1813,9 +1813,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.9" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da4a3c17e109f700685ec577c0f85efd9b19bcf15c913985f14dc1ac01775aa" +checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" dependencies = [ "proc-macro2", "quote", @@ -1899,7 +1899,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.10", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bd1263d2f..f95e0f7d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.27.6" +version = "1.27.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 102ad76a6..c3a9ada3e 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.27.6 +rtx 1.27.7 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.6/rtx-v1.27.6-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.27.7/rtx-v1.27.7-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index b60e913e2..1d0fc96aa 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.27.6"; + version = "1.27.7"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 0e7891f9a..923349fa6 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.27.6" +.TH rtx 1 "rtx 1.27.7" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.27.6 +v1.27.7 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 680a763b2..7483940c7 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.27.6 +Version: 1.27.7 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 6b62eb2c45f6d52274bcd9980ab796a15643c8df Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 16:52:38 -0500 Subject: [PATCH 0623/1891] java defaults to openjdk now --- .github/workflows/test-plugins.yml | 2 +- e2e/test_top_runtimes | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 17f6bfe01..9113bae5b 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -65,7 +65,7 @@ jobs: rtx exec -- elixir --version - plugin: golang command: rtx exec golang@latest -- go version - - plugin: java@openjdk + - plugin: java command: rtx exec java@openjdk -- java -version - plugin: terraform command: rtx exec terraform@latest -- terraform -v diff --git a/e2e/test_top_runtimes b/e2e/test_top_runtimes index 3ff4e630a..338f509f2 100755 --- a/e2e/test_top_runtimes +++ b/e2e/test_top_runtimes @@ -62,7 +62,7 @@ rtx exec direnv -- direnv --version rtx exec erlang -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell rtx exec elixir erlang -- elixir --version rtx exec golang -- go version -rtx exec java@openjdk -- java -version +rtx exec java -- java -version rtx exec terraform -- terraform -v rtx exec yarn -- yarn --version rtx exec deno -- deno --version From 4b60489c961c5519d5701aa198ab202c4ee36665 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 18:48:30 -0500 Subject: [PATCH 0624/1891] use most recent install for @latest and other aliases (#408) See #402 --- src/cli/install.rs | 10 ++-- src/config/config_file/mod.rs | 3 +- ...nfig_file__rtx_toml__tests__fixture-4.snap | 1 + ..._file__rtx_toml__tests__remove_plugin.snap | 1 + ...le__rtx_toml__tests__replace_versions.snap | 1 + src/plugins/mod.rs | 31 +++++++++++ src/toolset/builder.rs | 18 ++++--- src/toolset/mod.rs | 5 +- src/toolset/tool_version.rs | 52 ++++++++++++------- src/toolset/tool_version_list.rs | 6 +-- 10 files changed, 95 insertions(+), 33 deletions(-) diff --git a/src/cli/install.rs b/src/cli/install.rs index 53646003c..e1f7c52f0 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -72,7 +72,9 @@ impl Install { fn install_runtimes(&self, mut config: Config, runtimes: &[RuntimeArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); let mut tool_versions = vec![]; - let ts = ToolsetBuilder::new().build(&mut config)?; + let ts = ToolsetBuilder::new() + .with_latest_versions() + .build(&mut config)?; for runtime in RuntimeArg::double_runtime_condition(runtimes) { match runtime.to_tool_version() { Some(tv) => tool_versions.push(tv), @@ -113,7 +115,7 @@ impl Install { return Err(err)?; } } - tv.resolve(&config, plugin)?; + tv.resolve(&config, plugin, ts.latest_versions)?; versions.push(tv.rtv.unwrap()); } if versions.is_empty() { @@ -174,7 +176,9 @@ impl Install { } fn install_missing_runtimes(&self, mut config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().build(&mut config)?; + let mut ts = ToolsetBuilder::new() + .with_latest_versions() + .build(&mut config)?; if let Some(plugins) = &self.plugin { let plugins = plugins.iter().collect::>(); for plugin in ts.versions.keys().cloned().collect::>() { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 5804d19d3..939e60fe7 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -54,6 +54,7 @@ impl dyn ConfigFile { ) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); let mut ts = self.to_toolset().to_owned(); + ts.latest_versions = true; let mut plugins_to_update = HashMap::new(); for runtime in runtimes { if let Some(tv) = runtime.to_tool_version() { @@ -76,7 +77,7 @@ impl dyn ConfigFile { .map(|mut tv| { if pin { let plugin = config.plugins.get(&plugin).unwrap(); - tv.resolve(config, plugin.clone())?; + tv.resolve(config, plugin.clone(), ts.latest_versions)?; Ok(tv.rtv.unwrap().version) } else { Ok(tv.r#type.to_string()) diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index 38504bd2c..20fea82cf 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -119,4 +119,5 @@ Toolset { "~/fixtures/.rtx.toml", ), ), + latest_versions: false, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap index ccf4993ab..72b2e5609 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap @@ -9,4 +9,5 @@ Toolset { "/tmp/.rtx.toml", ), ), + latest_versions: false, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index 9b4be7bc9..734da11e2 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -33,4 +33,5 @@ Toolset { "/tmp/.rtx.toml", ), ), + latest_versions: false, } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 4d8964eba..8c0854f8a 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -199,6 +199,21 @@ impl Plugin { Ok(()) } + pub fn latest_installed_version(&self) -> Result> { + let installed_symlink = self.installs_path.join("latest"); + if installed_symlink.exists() { + let target = installed_symlink.read_link()?; + let version = target + .file_name() + .ok_or_else(|| eyre!("Invalid symlink target"))? + .to_string_lossy() + .to_string(); + Ok(Some(version)) + } else { + Ok(None) + } + } + pub fn latest_version( &self, settings: &Settings, @@ -225,6 +240,22 @@ impl Plugin { } } + pub fn list_installed_versions_matching(&self, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9]"; + } + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + let versions = self + .list_installed_versions()? + .iter() + .filter(|v| query_regex.is_match(v)) + .cloned() + .collect_vec(); + Ok(versions) + } + pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { let mut query = query; if query == "latest" { diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 7fd9942bd..bde10e1d4 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -9,18 +9,16 @@ use crate::toolset::tool_version::ToolVersionType; use crate::toolset::{ToolSource, ToolVersion, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct ToolsetBuilder { args: Vec, install_missing: bool, + latest_versions: bool, } impl ToolsetBuilder { pub fn new() -> Self { - Self { - args: Vec::new(), - install_missing: false, - } + Self::default() } pub fn with_args(mut self, args: &[RuntimeArg]) -> Self { @@ -33,8 +31,16 @@ impl ToolsetBuilder { self } + pub fn with_latest_versions(mut self) -> Self { + self.latest_versions = true; + self + } + pub fn build(self, config: &mut Config) -> Result { - let mut toolset = Toolset::default(); + let mut toolset = Toolset { + latest_versions: self.latest_versions, + ..Default::default() + }; load_config_files(config, &mut toolset); load_runtime_env(&mut toolset, env::vars().collect()); load_runtime_args(&mut toolset, &self.args); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index d48d87882..601649d78 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -42,6 +42,7 @@ mod tool_version_list; pub struct Toolset { pub versions: IndexMap, pub source: Option, + pub latest_versions: bool, } impl Toolset { @@ -81,7 +82,7 @@ impl Toolset { return; } }; - v.resolve(config, plugin.clone()); + v.resolve(config, plugin.clone(), self.latest_versions); }); } pub fn install_missing(&mut self, config: &mut Config, mpr: MultiProgressReport) -> Result<()> { @@ -163,7 +164,7 @@ impl Toolset { .map(|(plugin, versions)| { for version in versions { let mut pr = mpr.add(); - version.resolve(config, plugin.clone())?; + version.resolve(config, plugin.clone(), self.latest_versions)?; version.install(config, &mut pr, false)?; } Ok(()) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 3ff1243c0..7bd343a81 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -43,10 +43,17 @@ impl ToolVersion { } } - pub fn resolve(&mut self, config: &Config, plugin: Arc) -> Result<()> { + pub fn resolve( + &mut self, + config: &Config, + plugin: Arc, + latest_versions: bool, + ) -> Result<()> { if self.rtv.is_none() { self.rtv = Some(match &self.r#type { - ToolVersionType::Version(v) => self.resolve_version(config, plugin, v)?, + ToolVersionType::Version(v) => { + self.resolve_version(config, plugin, v, latest_versions)? + } ToolVersionType::Prefix(v) => self.resolve_prefix(config, plugin, v)?, ToolVersionType::Ref(r) => self.resolve_ref(config, plugin, r)?, ToolVersionType::Path(path) => self.resolve_path(config, plugin, path)?, @@ -61,6 +68,7 @@ impl ToolVersion { config: &Config, plugin: Arc, v: &str, + latest_versions: bool, ) -> Result { let v = config.resolve_alias(&plugin.name, v)?; match v.split_once(':') { @@ -79,21 +87,28 @@ impl ToolVersion { let existing_path = dirs::INSTALLS.join(&plugin.name).join(&v); if existing_path.exists() && !is_runtime_symlink(&existing_path) { // if the version is already installed, no need to fetch all the remote versions - let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - return Ok(rtv); + return Ok(self.build_rtv(config, plugin, &v)); } if v == "latest" { - let v = plugin.latest_version(&config.settings, None)?; - if let Some(v) = v { - let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - return Ok(rtv); + if !latest_versions { + if let Some(v) = plugin.latest_installed_version()? { + return Ok(self.build_rtv(config, plugin, &v)); + } + } + if let Some(v) = plugin.latest_version(&config.settings, None)? { + return Ok(self.build_rtv(config, plugin, &v)); + } + } + if !latest_versions { + let matches = plugin.list_installed_versions_matching(&v)?; + if matches.contains(&v) { + return Ok(self.build_rtv(config, plugin, &v)); } } let matches = plugin.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { - let rtv = RuntimeVersion::new(config, plugin, v, self.clone()); - return Ok(rtv); + return Ok(self.build_rtv(config, plugin, &v)); } if v.contains("!-") { if let Some(rtv) = self.resolve_bang(config, plugin.clone(), &v)? { @@ -117,7 +132,7 @@ impl ToolVersion { }; let wanted = version_sub(&wanted, minus); match plugin.latest_version(&config.settings, Some(wanted))? { - Some(v) => Ok(RuntimeVersion::new(config, plugin, v, self.clone()).into()), + Some(v) => Ok(Some(self.build_rtv(config, plugin, &v))), None => Ok(None), } } @@ -134,13 +149,11 @@ impl ToolVersion { None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; - let rtv = RuntimeVersion::new(config, plugin, v.to_string(), self.clone()); - Ok(rtv) + Ok(self.build_rtv(config, plugin, v)) } fn resolve_ref(&self, config: &Config, plugin: Arc, r: &str) -> Result { - let rtv = RuntimeVersion::new(config, plugin, format!("ref-{}", r), self.clone()); - Ok(rtv) + Ok(self.build_rtv(config, plugin, &format!("ref-{}", r))) } fn resolve_path( @@ -150,12 +163,11 @@ impl ToolVersion { path: &PathBuf, ) -> Result { let path = fs::canonicalize(path)?; - let rtv = RuntimeVersion::new(config, plugin, path.display().to_string(), self.clone()); - Ok(rtv) + Ok(self.build_rtv(config, plugin, &path.display().to_string())) } pub fn resolve_system(&self, config: &Config, plugin: Arc) -> RuntimeVersion { - RuntimeVersion::new(config, plugin, "system".to_string(), self.clone()) + self.build_rtv(config, plugin, "system") } pub fn is_missing(&self) -> bool { @@ -174,6 +186,10 @@ impl ToolVersion { _ => Ok(()), } } + + fn build_rtv(&self, config: &Config, plugin: Arc, v: &str) -> RuntimeVersion { + RuntimeVersion::new(config, plugin, v.to_string(), self.clone()) + } } impl Display for ToolVersion { diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 603d95c5f..ce17e4b7a 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -22,9 +22,9 @@ impl ToolVersionList { pub fn add_version(&mut self, version: ToolVersion) { self.versions.push(version); } - pub fn resolve(&mut self, config: &Config, plugin: Arc) { + pub fn resolve(&mut self, config: &Config, plugin: Arc, latest_versions: bool) { for tv in &mut self.versions { - if let Err(err) = tv.resolve(config, plugin.clone()) { + if let Err(err) = tv.resolve(config, plugin.clone(), latest_versions) { warn!("failed to resolve tool version: {:#}", err); } } @@ -57,7 +57,7 @@ mod tests { plugin.name.to_string(), ToolVersionType::Version("1.0.0".to_string()), )); - tvl.resolve(&Config::default(), plugin); + tvl.resolve(&Config::default(), plugin, false); assert_eq!(tvl.resolved_versions().len(), 0); env::remove_var("RTX_FAILURE"); } From 306d9740c752ebe3cd94ba20f9427636a1ee7de8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 18:52:47 -0500 Subject: [PATCH 0625/1891] set env vars to be string or bool #404 --- schema/rtx.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/schema/rtx.json b/schema/rtx.json index 50d05918f..3f7d5e968 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -21,9 +21,15 @@ "env": { "description": "environment variables", "type": "object", - "items": { - "description": "environment variable value", - "type": "string" + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] } }, "tools": { @@ -63,7 +69,9 @@ } } }, - "settings": {"$ref": "#/$defs/settings"} + "settings": { + "$ref": "#/$defs/settings" + } }, "$defs": { "tool": { From a4c49ecf559a770186112d54200a85e020041ce1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 25 Mar 2023 18:53:49 -0500 Subject: [PATCH 0626/1891] chore: Release rtx-cli version 1.27.8 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19b6f381d..9af6a68bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1493,7 +1493,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.27.7" +version = "1.27.8" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index f95e0f7d9..2f075a03b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.27.7" +version = "1.27.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index c3a9ada3e..be596b305 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.27.7 +rtx 1.27.8 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.7/rtx-v1.27.7-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.27.8/rtx-v1.27.8-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 1d0fc96aa..0d826a8af 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.27.7"; + version = "1.27.8"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 923349fa6..f88e329c7 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.27.7" +.TH rtx 1 "rtx 1.27.8" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.27.7 +v1.27.8 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 7483940c7..f5966973d 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.27.7 +Version: 1.27.8 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 24f239b16252ce48c0e8bca614705375f1c71deb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 26 Mar 2023 15:54:22 -0500 Subject: [PATCH 0627/1891] test: do not delete existing snapshots This fails for some reason --- justfile | 1 - 1 file changed, 1 deletion(-) diff --git a/justfile b/justfile index 18066f497..95f608853 100644 --- a/justfile +++ b/justfile @@ -21,7 +21,6 @@ test *args: (test-unit args) test-e2e lint # update all test snapshot files test-update-snapshots: - find . -name '*.snap' -delete cargo insta test --accept --all-features # run the rust "unit" tests From c59e038fa1dcd12ccbfe10bf3703c6bcb5213f4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 08:47:13 -0500 Subject: [PATCH 0628/1891] chore(deps): bump ctor from 0.1.26 to 0.2.0 (#411) Bumps [ctor](https://github.com/mmastrac/rust-ctor) from 0.1.26 to 0.2.0. - [Release notes](https://github.com/mmastrac/rust-ctor/releases) - [Commits](https://github.com/mmastrac/rust-ctor/commits) --- updated-dependencies: - dependency-name: ctor dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 14 ++++++++++++-- Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9af6a68bd..7ec3fd7b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -347,6 +347,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ctor" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" +dependencies = [ + "quote", + "syn 2.0.10", +] + [[package]] name = "ctrlc" version = "3.2.5" @@ -1317,7 +1327,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "ctor", + "ctor 0.1.26", "diff", "output_vt100", "yansi", @@ -1503,7 +1513,7 @@ dependencies = [ "clap_mangen", "color-eyre", "console", - "ctor", + "ctor 0.2.0", "ctrlc", "dialoguer", "dirs-next", diff --git a/Cargo.toml b/Cargo.toml index 2f075a03b..213929a94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ clap_complete = "4.1.4" clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" console = "0.15.5" -ctor = "0.1.26" +ctor = "0.2.0" ctrlc = "3.2.5" dialoguer = { version = "0.10.3", features = [] } dirs-next = "2.0.0" From 1eda8fb035a266d8d6d19dadf476336468f7aa87 Mon Sep 17 00:00:00 2001 From: Andrew Thauer <6507159+andrewthauer@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:57:16 -0400 Subject: [PATCH 0629/1891] rename complete command to completion (#410) --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- README.md | 44 +++++++-------- completions/_rtx | 25 +++++---- completions/rtx.bash | 18 +++--- completions/rtx.fish | 88 +++++++++++++++--------------- justfile | 8 +-- man/man1/rtx.1 | 2 +- packaging/homebrew/homebrew.rb | 2 +- src/cli/complete.rs | 55 ------------------- src/cli/completion.rs | 64 ++++++++++++++++++++++ src/cli/mod.rs | 6 +- src/cli/render_help.rs | 8 +++ src/config/config_file/rtx_toml.rs | 2 +- 12 files changed, 170 insertions(+), 152 deletions(-) delete mode 100644 src/cli/complete.rs create mode 100644 src/cli/completion.rs diff --git a/README.md b/README.md index be596b305..57bf6b8f6 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ v18.15.0 - [`rtx alias unset `](#rtx-alias-unset-plugin-alias) - [`rtx bin-paths`](#rtx-bin-paths) - [`rtx cache clear`](#rtx-cache-clear) - - [`rtx complete --shell `](#rtx-complete---shell-shell) + - [`rtx completion [SHELL]`](#rtx-completion-shell) - [`rtx current [PLUGIN]`](#rtx-current-plugin) - [`rtx deactivate`](#rtx-deactivate) - [`rtx direnv activate`](#rtx-direnv-activate) @@ -444,8 +444,8 @@ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ### Nushell ```sh-session -do { - let rtxpath = $"($nu.config-path | path dirname | path join "rtx.nu")"; +do { + let rtxpath = $"($nu.config-path | path dirname | path join "rtx.nu")"; run-external rtx activate nu --redirect-stdout | save $rtxpath -f; $"\nsource "($rtxpath)"" | save $nu.config-path --append } @@ -528,7 +528,7 @@ nodejs lts!-2 # install 2 versions behind the latest lts (e.g.: 16 if python latest!-0.1 # install python-3.10 if the latest is 3.11 ``` -Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local-options-runtime) to create them +Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local-options-runtime) to create them automatically. See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. @@ -963,8 +963,8 @@ ln -s ~/src/rtx-my-tool ~/.local/share/rtx/plugins/my-tool #### `~/.local/share/rtx/installs` -This is where tools are installed to when running `rtx install`. For example, `rtx install -nodejs@18.0.0` will install to `~/.local/share/rtx/installs/nodejs/18.0.0` For example, `rtx +This is where tools are installed to when running `rtx install`. For example, `rtx install +nodejs@18.0.0` will install to `~/.local/share/rtx/installs/nodejs/18.0.0` For example, `rtx install 0.0` will install to `~/.local/share/rtx/installs/nodejs/18.0.0`. This will also create other symlinks to this directory for version prefixes ("18" and "18.15") @@ -1043,7 +1043,7 @@ if a shim is executed. For this we need tighter integration with the IDE and a c ambitious, take a look at existing direnv extensions for your IDE and see if you can modify it to work for rtx. Direnv and rtx work similarly and there should be a direnv extension that can be used as a starting point. -Alternatively, you may be able to get tighter integration with a direnv extension and using the +Alternatively, you may be able to get tighter integration with a direnv extension and using the [`use_rtx`](#direnv) direnv function. ## FAQs @@ -1156,7 +1156,7 @@ and see what happens. rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin should be usable in rtx. The commands in rtx are slightly different, such as `rtx install nodejs@18.0.0` vs `asdf install nodejs 18.0.0`—this is done so -multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx +multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx install nodejs 18.0.0`). This is the case for most commands, though the help for the command may say that asdf-style syntax is supported. @@ -1406,7 +1406,7 @@ Usage: activate [OPTIONS] [SHELL_TYPE] Arguments: [SHELL_TYPE] Shell type to generate the script for - + [possible values: bash, fish, nu, xonsh, zsh] Options: @@ -1516,23 +1516,23 @@ Deletes all cache files in rtx Usage: clear ``` -### `rtx complete --shell ` +### `rtx completion [SHELL]` ``` Generate shell completions -Usage: complete --shell +Usage: completion [SHELL] + +Arguments: + [SHELL] + Shell type to generate completions for -Options: - -s, --shell - shell type - [possible values: bash, elvish, fish, powershell, zsh] Examples: - $ rtx complete -s bash > /etc/bash_completion.d/rtx - $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx - $ rtx complete -s fish > ~/.config/fish/completions/rtx.fish + $ rtx completion bash > /etc/bash_completion.d/rtx + $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx + $ rtx completion fish > ~/.config/fish/completions/rtx.fish ``` ### `rtx current [PLUGIN]` @@ -1624,7 +1624,7 @@ Arguments: Options: -s, --shell Shell type to generate environment variables for - + [possible values: bash, fish, nu, xonsh, zsh] Examples: @@ -1662,7 +1662,7 @@ Options: --cd Change to this directory before executing the command - + [short aliases: C] Examples: @@ -1869,7 +1869,7 @@ Options: --parseable Output in an easily parseable format - + [short aliases: x] --json @@ -2324,7 +2324,7 @@ Usage: which [OPTIONS] Arguments: - + Options: --plugin diff --git a/completions/_rtx b/completions/_rtx index eed069a40..1555c9d39 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -344,10 +344,10 @@ esac ;; esac ;; -(complete) +(completion) _arguments "${_arguments_options[@]}" \ -'-s+[shell type]:SHELL:(bash elvish fish powershell zsh)' \ -'--shell=[shell type]:SHELL:(bash elvish fish powershell zsh)' \ +'-s+[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ +'--shell=[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ '-j+[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel @@ -364,6 +364,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ +'::shell -- Shell type to generate completions for:(bash elvish fish powershell zsh)' \ && ret=0 ;; (current) @@ -1509,7 +1510,7 @@ _arguments "${_arguments_options[@]}" \ ;; esac ;; -(complete) +(completion) _arguments "${_arguments_options[@]}" \ && ret=0 ;; @@ -1731,7 +1732,7 @@ _rtx_commands() { 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ 'bin-paths:List all the active runtime bin paths' \ 'cache:Manage the rtx cache' \ -'complete:Generate shell completions' \ +'completion:Generate shell completions' \ 'current:Shows current active and installed runtime versions' \ 'deactivate:Disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ @@ -1880,15 +1881,15 @@ _rtx__help__cache__clear_commands() { local commands; commands=() _describe -t commands 'rtx help cache clear commands' commands "$@" } -(( $+functions[_rtx__complete_commands] )) || -_rtx__complete_commands() { +(( $+functions[_rtx__completion_commands] )) || +_rtx__completion_commands() { local commands; commands=() - _describe -t commands 'rtx complete commands' commands "$@" + _describe -t commands 'rtx completion commands' commands "$@" } -(( $+functions[_rtx__help__complete_commands] )) || -_rtx__help__complete_commands() { +(( $+functions[_rtx__help__completion_commands] )) || +_rtx__help__completion_commands() { local commands; commands=() - _describe -t commands 'rtx help complete commands' commands "$@" + _describe -t commands 'rtx help completion commands' commands "$@" } (( $+functions[_rtx__current_commands] )) || _rtx__current_commands() { @@ -2089,7 +2090,7 @@ _rtx__help_commands() { 'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ 'bin-paths:List all the active runtime bin paths' \ 'cache:Manage the rtx cache' \ -'complete:Generate shell completions' \ +'completion:Generate shell completions' \ 'current:Shows current active and installed runtime versions' \ 'deactivate:Disable rtx for current shell session' \ 'direnv:Output direnv function to use rtx inside direnv' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 05cc01dca..38d19f819 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -30,8 +30,8 @@ _rtx() { rtx,cache) cmd="rtx__cache" ;; - rtx,complete) - cmd="rtx__complete" + rtx,completion) + cmd="rtx__completion" ;; rtx,current) cmd="rtx__current" @@ -243,8 +243,8 @@ _rtx() { rtx__help,cache) cmd="rtx__help__cache" ;; - rtx__help,complete) - cmd="rtx__help__complete" + rtx__help,completion) + cmd="rtx__help__completion" ;; rtx__help,current) cmd="rtx__help__current" @@ -496,7 +496,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" + opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -931,8 +931,8 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__complete) - opts="-s -j -r -v -h --shell --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + rtx__completion) + opts="-s -j -r -v -h --shell --debug --install-missing --jobs --log-level --raw --trace --verbose --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1320,7 +1320,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache complete current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1473,7 +1473,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__complete) + rtx__help__completion) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) diff --git a/completions/rtx.fish b/completions/rtx.fish index 40212a2df..e4b79788f 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -14,7 +14,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' complete -c rtx -n "__fish_use_subcommand" -f -a "bin-paths" -d 'List all the active runtime bin paths' complete -c rtx -n "__fish_use_subcommand" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_use_subcommand" -f -a "complete" -d 'Generate shell completions' +complete -c rtx -n "__fish_use_subcommand" -f -a "completion" -d 'Generate shell completions' complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows current active and installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'Disable rtx for current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' @@ -166,17 +166,17 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from complete" -s s -l shell -d 'shell type' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" -complete -c rtx -n "__fish_seen_subcommand_from complete" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +complete -c rtx -n "__fish_seen_subcommand_from completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from completion" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from complete" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from complete" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from complete" -l install-missing -d 'Automatically install missing tools' -complete -c rtx -n "__fish_seen_subcommand_from complete" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from completion" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from completion" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from complete" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from complete" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from completion" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from completion" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from completion" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r @@ -660,40 +660,40 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "complete" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from complete; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/justfile b/justfile index 95f608853..8746dcfeb 100644 --- a/justfile +++ b/justfile @@ -35,7 +35,7 @@ test-e2e: build test-coverage: #!/usr/bin/env bash set -euxo pipefail - source <(cargo llvm-cov show-env --export-prefix) + source <(cargo llvm-cov show-env --export-prefix) cargo llvm-cov clean --workspace if [[ -n "${RTX_GITHUB_BOT_TOKEN:-}" ]]; then @@ -89,9 +89,9 @@ render-help: build # regenerate shell completion files render-completions: build - NO_COLOR=1 rtx complete -s bash > completions/rtx.bash - NO_COLOR=1 rtx complete -s zsh > completions/_rtx - NO_COLOR=1 rtx complete -s fish > completions/rtx.fish + NO_COLOR=1 rtx completion bash > completions/rtx.bash + NO_COLOR=1 rtx completion zsh > completions/_rtx + NO_COLOR=1 rtx completion fish > completions/rtx.fish # regenerate manpages render-mangen: build diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index f88e329c7..c4e4e5e25 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -52,7 +52,7 @@ List all the active runtime bin paths rtx\-cache(1) Manage the rtx cache .TP -rtx\-complete(1) +rtx\-completion(1) Generate shell completions .TP rtx\-current(1) diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index 14aff4c34..29e7d093d 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -29,7 +29,7 @@ class Rtx < Formula def install bin.install "bin/rtx" man1.install "man/man1/rtx.1" - generate_completions_from_executable(bin/"rtx", "complete", "--shell") + generate_completions_from_executable(bin/"rtx", "completion") end test do diff --git a/src/cli/complete.rs b/src/cli/complete.rs deleted file mode 100644 index 502c29026..000000000 --- a/src/cli/complete.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::io::Cursor; - -use clap_complete::generate; -use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; - -use crate::cli::command::Command; -use crate::cli::Cli; -use crate::config::Config; -use crate::output::Output; - -/// Generate shell completions -#[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] -pub struct Complete { - /// shell type - #[clap(long, short)] - shell: clap_complete::Shell, -} - -impl Command for Complete { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let mut c = Cursor::new(Vec::new()); - generate(self.shell, &mut Cli::command(), "rtx", &mut c); - rtxprintln!(out, "{}", String::from_utf8(c.into_inner()).unwrap()); - - Ok(()) - } -} - -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx complete -s bash > /etc/bash_completion.d/rtx - $ rtx complete -s zsh > /usr/local/share/zsh/site-functions/_rtx - $ rtx complete -s fish > ~/.config/fish/completions/rtx.fish - "#, style("Examples:").bold().underlined()} -}); - -// #[cfg(test)] -// mod tests { -// use std::fs; -// -// use insta::assert_snapshot; -// -// use crate::{assert_cli, dirs}; -// -// #[test] -// fn test_complete() { -// let stdout = assert_cli!("complete", "-s", "zsh"); -// assert_snapshot!(stdout); -// } -// } diff --git a/src/cli/completion.rs b/src/cli/completion.rs new file mode 100644 index 000000000..c54b00ca1 --- /dev/null +++ b/src/cli/completion.rs @@ -0,0 +1,64 @@ +use std::io::Cursor; + +use clap_complete::generate; +use color_eyre::eyre::Result; +use console::style; +use indoc::formatdoc; +use once_cell::sync::Lazy; + +use crate::cli::command::Command; +use crate::cli::Cli; +use crate::config::Config; +use crate::output::Output; + +/// Generate shell completions +#[derive(Debug, clap::Args)] +#[clap(alias = "complete", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +pub struct Completion { + /// Shell type to generate completions for + #[clap()] + shell: Option, + + /// Shell type to generate completions for + #[clap(long = "shell", short = 's', hide = true)] + shell_type: Option, +} + +impl Command for Completion { + fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let shell = match self.shell.or(self.shell_type) { + Some(shell) => shell, + None => panic!("no shell provided"), + }; + + let mut c = Cursor::new(Vec::new()); + generate(shell, &mut Cli::command(), "rtx", &mut c); + rtxprintln!(out, "{}", String::from_utf8(c.into_inner()).unwrap()); + + Ok(()) + } +} + +static AFTER_LONG_HELP: Lazy = Lazy::new(|| { + formatdoc! {r#" + {} + $ rtx completion bash > /etc/bash_completion.d/rtx + $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx + $ rtx completion fish > ~/.config/fish/completions/rtx.fish + "#, style("Examples:").bold().underlined()} +}); + +// #[cfg(test)] +// mod tests { +// use std::fs; +// +// use insta::assert_snapshot; +// +// use crate::{assert_cli, dirs}; +// +// #[test] +// fn test_completion() { +// let stdout = assert_cli!("completion", "-s", "zsh"); +// assert_snapshot!(stdout); +// } +// } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6ccd86204..e1c7bbceb 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -17,7 +17,7 @@ mod asdf; mod bin_paths; mod cache; pub mod command; -mod complete; +mod completion; mod current; mod deactivate; mod direnv; @@ -61,7 +61,7 @@ pub enum Commands { Asdf(asdf::Asdf), BinPaths(bin_paths::BinPaths), Cache(cache::Cache), - Complete(complete::Complete), + Completion(completion::Completion), Current(current::Current), Deactivate(deactivate::Deactivate), Direnv(direnv::Direnv), @@ -102,7 +102,7 @@ impl Commands { Self::Asdf(cmd) => cmd.run(config, out), Self::BinPaths(cmd) => cmd.run(config, out), Self::Cache(cmd) => cmd.run(config, out), - Self::Complete(cmd) => cmd.run(config, out), + Self::Completion(cmd) => cmd.run(config, out), Self::Current(cmd) => cmd.run(config, out), Self::Deactivate(cmd) => cmd.run(config, out), Self::Direnv(cmd) => cmd.run(config, out), diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f911706cb..85f9d0d5e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -24,6 +24,7 @@ impl Command for RenderHelp { current_readme.next(); // discard existing commands doc.push_str(render_commands().as_str()); doc.push_str(current_readme.next().unwrap()); + doc = remove_trailing_spaces(&doc) + "\n"; fs::write("README.md", &doc)?; Ok(()) } @@ -92,6 +93,13 @@ fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option )) } +fn remove_trailing_spaces(s: &str) -> String { + s.lines() + .map(|line| line.trim_end().to_string()) + .collect::>() + .join("\n") +} + #[cfg(test)] mod tests { use crate::assert_cli; diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index bd995c7f1..679fdf845 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -567,7 +567,7 @@ impl RtxToml { fn trust_check(&mut self) -> Result<()> { let default_cmd = String::new(); let cmd = env::ARGS.get(1).unwrap_or(&default_cmd).as_str(); - if self.is_trusted || cmd == "trust" || cmd == "complete" || cfg!(test) { + if self.is_trusted || cmd == "trust" || cmd == "completion" || cfg!(test) { return Ok(()); } if console::user_attended_stderr() && cmd != "hook-env" { From 6c2eb4615da44305941b1274a8ea61d195dc2e27 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:06:39 -0500 Subject: [PATCH 0630/1891] chore: downgrade required dependencies for debian compat --- Cargo.toml | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 213929a94..7afa5219b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,19 +26,19 @@ path = "src/main.rs" #harness = false [dependencies] -base64 = "0.21.0" +base64 = "<1" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } -clap = { version = "4.1.8", features = ["env", "derive", "string"] } -clap_complete = "4.1.4" +clap = { version = "4.0.32", features = ["env", "derive", "string"] } +clap_complete = "4.0.7" clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" -console = "0.15.5" -ctor = "0.2.0" -ctrlc = "3.2.5" -dialoguer = { version = "0.10.3", features = [] } +console = "0.15.2" +ctor = "<1" +ctrlc = "3.2.3" +dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" dotenvy = "0.15.6" -duct = "0.13.6" +duct = "0.13.5" filetime = "0.2.19" flate2 = "1.0.25" fslock = "0.2.1" @@ -46,16 +46,16 @@ humantime = "2.1.0" indenter = "0.3.3" indexmap = { version = "1.9.2", features = ["serde"] } indicatif = { version = "0.17.3", features = ["default", "improved_unicode"] } -indoc = "2.0.1" -itertools = "0.10.5" +indoc = "<3" +itertools = "0.10.3" lazy_static = "1.4.0" log = "0.4.17" -num_cpus = "1.15.0" +num_cpus = "1.14.0" once_cell = "1.17.0" owo-colors = { version = "3.5.0" } -rayon = "1.7.0" +rayon = "1.6.1" regex = "1.7.1" -reqwest = { version = "0.11.14", default-features = false, features = [ +reqwest = { version = "0.11.13", default-features = false, features = [ "blocking", "rustls-tls", ] } @@ -65,14 +65,14 @@ self_update = { version = "0.36.0", default-features = false, optional = true, f ] } serde = "1.0.152" serde_derive = "1.0.152" -serde_json = "1.0.92" -shell-escape = "0.1.5" +serde_json = "1.0.87" +shell-escape = "0.1.4" simplelog = { version = "0.12.0" } tera = { version = "1.12.1", default-features = false } -terminal_size = "0.2.5" -thiserror = "1.0.39" -toml = "0.7.1" -toml_edit = "0.19.0" +terminal_size = "0.2.1" +thiserror = "1.0.38" +toml = "<1" +toml_edit = "<1" url = "2.3.1" versions = "4.1.0" From 15be0a3205160d78b57fed496ded639a535f0ed0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:43:53 -0500 Subject: [PATCH 0631/1891] watch for changes on dotenv file change (#416) Fixes #415 --- src/cli/hook_env.rs | 8 +++++-- src/config/config_file/legacy_version.rs | 4 ++++ src/config/config_file/mod.rs | 1 + src/config/config_file/rtx_toml.rs | 11 +++++++++- src/config/config_file/tool_versions.rs | 4 ++++ src/config/mod.rs | 27 ++++++++++++------------ src/hook_env.rs | 12 +++++------ 7 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 62e6522f1..47efbf27a 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -141,8 +141,12 @@ impl HookEnv { } fn build_watch_operation(&self, config: &Config) -> Result { - let config_filenames: Vec<_> = config.config_files.keys().cloned().collect(); - let watches = hook_env::build_watches(&config_filenames)?; + let watch_files: Vec<_> = config + .config_files + .values() + .flat_map(|p| p.watch_files()) + .collect(); + let watches = hook_env::build_watches(&watch_files)?; Ok(EnvDiffOperation::Add( "__RTX_WATCH".into(), hook_env::serialize_watches(&watches)?, diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 19623a849..25fa3cf21 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -76,6 +76,10 @@ impl ConfigFile for LegacyVersionFile { fn aliases(&self) -> AliasMap { AliasMap::default() } + + fn watch_files(&self) -> Vec { + vec![self.path.clone()] + } } impl Display for LegacyVersionFile { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 939e60fe7..d860aaf9b 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -43,6 +43,7 @@ pub trait ConfigFile: Debug + Display + Send + Sync { fn to_toolset(&self) -> &Toolset; fn settings(&self) -> SettingsBuilder; fn aliases(&self) -> AliasMap; + fn watch_files(&self) -> Vec; } impl dyn ConfigFile { diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 679fdf845..3d10fc294 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -25,6 +25,7 @@ pub struct RtxToml { context: Context, path: PathBuf, toolset: Toolset, + dotenv: Option, env: HashMap, path_dirs: Vec, settings: SettingsBuilder, @@ -95,10 +96,11 @@ impl RtxToml { match v.as_str() { Some(filename) => { let path = self.path.parent().unwrap().join(filename); - for item in dotenvy::from_path_iter(path)? { + for item in dotenvy::from_path_iter(&path)? { let (k, v) = item?; self.env.insert(k, v); } + self.dotenv = Some(path); } _ => parse_error!(k, v, "string")?, } @@ -676,6 +678,13 @@ impl ConfigFile for RtxToml { fn aliases(&self) -> AliasMap { self.alias.clone() } + + fn watch_files(&self) -> Vec { + match &self.dotenv { + Some(dotenv) => vec![self.path.clone(), dotenv.clone()], + None => vec![self.path.clone()], + } + } } #[cfg(test)] diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index ce92b7119..762c0b0ed 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -217,6 +217,10 @@ impl ConfigFile for ToolVersions { fn aliases(&self) -> AliasMap { AliasMap::default() } + + fn watch_files(&self) -> Vec { + vec![self.path.clone()] + } } #[cfg(test)] diff --git a/src/config/mod.rs b/src/config/mod.rs index 30df0414c..a44daa8ca 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,13 +17,12 @@ pub use settings::{MissingRuntimeBehavior, Settings}; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::env::CI; -use crate::{cli, dirs, duration, env, file, hook_env}; - use crate::config::tracking::Tracker; +use crate::env::CI; use crate::plugins::{Plugin, PluginName}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::{cli, dirs, duration, env, file, hook_env}; pub mod config_file; mod settings; @@ -71,19 +70,19 @@ impl Config { let config_filenames = load_config_filenames(&legacy_files); let config_track = track_config_files(&config_filenames); - let (config_files, should_exit_early) = rayon::join( - || { - load_all_config_files( - &settings, - &config_filenames, - &plugins, - &legacy_files, - config_files, - ) - }, - || hook_env::should_exit_early(&config_filenames), + let config_files = load_all_config_files( + &settings, + &config_filenames, + &plugins, + &legacy_files, + config_files, ); let config_files = config_files?; + let watch_files = config_files + .values() + .flat_map(|cf| cf.watch_files()) + .collect_vec(); + let should_exit_early = hook_env::should_exit_early(&watch_files); for cf in config_files.values() { for (plugin_name, repo_url) in cf.plugins() { diff --git a/src/hook_env.rs b/src/hook_env.rs index 7bd85af31..a6cdf09da 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -19,11 +19,11 @@ use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being /// called and it does not need to be -pub fn should_exit_early(config_filenames: &[PathBuf]) -> bool { +pub fn should_exit_early(watch_files: &[PathBuf]) -> bool { if env::ARGS.len() < 2 || env::ARGS[1] != "hook-env" { return false; } - let watch_files = get_watch_files(config_filenames); + let watch_files = get_watch_files(watch_files); match env::var("__RTX_WATCH") { Ok(raw) => { match deserialize_watches(raw) { @@ -109,9 +109,9 @@ pub fn deserialize_watches(raw: String) -> Result { Ok(rmp_serde::from_slice(&writer[..])?) } -pub fn build_watches(config_filenames: &[PathBuf]) -> Result { +pub fn build_watches(watch_files: &[PathBuf]) -> Result { let mut watches = IndexMap::new(); - for cf in get_watch_files(config_filenames) { + for cf in get_watch_files(watch_files) { watches.insert(cf.clone(), cf.metadata()?.modified()?); } @@ -121,12 +121,12 @@ pub fn build_watches(config_filenames: &[PathBuf]) -> Result { }) } -pub fn get_watch_files(config_filenames: &[PathBuf]) -> IndexSet { +pub fn get_watch_files(watch_files: &[PathBuf]) -> IndexSet { let mut watches = IndexSet::new(); if dirs::ROOT.exists() { watches.insert(dirs::ROOT.clone()); } - for cf in config_filenames { + for cf in watch_files { watches.insert(cf.clone()); } From 3519233b9a8109eb0bb613886b8799466e8ba732 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:43:47 -0500 Subject: [PATCH 0632/1891] test: added test for progress report --- src/ui/progress_report.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index c9b3db17f..b6677d2bf 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -121,3 +121,26 @@ impl ProgressReport { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_progress_report() { + let mut pr = ProgressReport::new(false); + pr.set_prefix("prefix".to_string()); + assert_eq!(pr.prefix(), "prefix"); + pr.set_message("message".to_string()); + pr.finish_with_message("message".to_string()); + } + + #[test] + fn test_progress_report_verbose() { + let mut pr = ProgressReport::new(true); + pr.set_prefix("prefix".to_string()); + assert_eq!(pr.prefix(), "prefix"); + pr.set_message("message".to_string()); + pr.finish_with_message("message".to_string()); + } +} From a5246dc240d501946632f88aff488e979166feeb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:45:35 -0500 Subject: [PATCH 0633/1891] chore: Release rtx-cli version 1.27.9 --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ec3fd7b4..3a4856484 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1335,9 +1335,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.53" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] @@ -1421,9 +1421,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "reqwest" -version = "0.11.15" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ba30cc2c0cd02af1222ed216ba659cdb2f879dfe3181852fe7c50b1d0005949" +checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" dependencies = [ "base64", "bytes", @@ -1503,7 +1503,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.27.8" +version = "1.27.9" dependencies = [ "base64", "built", @@ -2527,6 +2527,6 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index 7afa5219b..2574ec626 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.27.8" +version = "1.27.9" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 57bf6b8f6..31cb07220 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.27.8 +rtx 1.27.9 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.8/rtx-v1.27.8-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.27.9/rtx-v1.27.9-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 0d826a8af..7dac31583 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.27.8"; + version = "1.27.9"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c4e4e5e25..2a653acd0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.27.8" +.TH rtx 1 "rtx 1.27.9" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.27.8 +v1.27.9 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f5966973d..37b62b837 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.27.8 +Version: 1.27.9 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From b36e4d2bbce0815dbd8713c93e308a315da1c3b3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:59:35 -0500 Subject: [PATCH 0634/1891] test: fix flaky coverage (#417) * test: add test for legacy file parsing * test: add coverage for invalid escape sequence prevents flaky coverage reports --- src/config/config_file/legacy_version.rs | 19 +++++++++++++++++++ src/env_diff.rs | 17 +++++++++++++---- test/cwd/tiny-legacy/.rtx-tiny-version | 1 + 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 test/cwd/tiny-legacy/.rtx-tiny-version diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 25fa3cf21..5eb74ad71 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -98,3 +98,22 @@ fn build_toolset(path: &Path, plugin: &str, version: &str) -> Toolset { } toolset } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_legacy_file() { + let settings = Settings::default(); + let path = PathBuf::from("tiny-legacy").join(".rtx-tiny-version"); + let plugin = Plugin::new(&settings, &PluginName::from("tiny")); + let cf = LegacyVersionFile::parse(&settings, path, &plugin).unwrap(); + let tvl = cf.to_toolset().versions.get("tiny").unwrap(); + let version = match tvl.versions[0].r#type { + ToolVersionType::Version(ref v) => v, + _ => panic!("Unexpected version type"), + }; + assert_eq!(version, "2"); + } +} diff --git a/src/env_diff.rs b/src/env_diff.rs index b2825a495..a684bb4ac 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -232,7 +232,7 @@ fn normalize_escape_sequences(input: &str) -> String { } }, None => { - error!("Invalid escape sequence"); + warn!("Invalid escape sequence: {}", input); } } } else { @@ -247,6 +247,7 @@ fn normalize_escape_sequences(input: &str) -> String { mod tests { use indexmap::indexmap; use insta::assert_debug_snapshot; + use pretty_assertions::assert_str_eq; use crate::dirs; @@ -341,10 +342,18 @@ mod tests { "TAB" => "\t", "VERTICAL_TAB" => "\u{0b}", } - .into_iter() - .map(|(k, v)| (k.into(), v.into())) - .collect::>(); + .into_iter() + .map(|(k, v)| (k.into(), v.into())) + .collect::>(); let ed = EnvDiff::from_bash_script(path.as_path(), orig).unwrap(); assert_debug_snapshot!(ed); } + + #[test] + fn test_invalid_escape_sequence() { + let input = r#""\g""#; + let output = normalize_escape_sequences(input); + // just warns + assert_str_eq!(output, r#"\g"#); + } } diff --git a/test/cwd/tiny-legacy/.rtx-tiny-version b/test/cwd/tiny-legacy/.rtx-tiny-version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/test/cwd/tiny-legacy/.rtx-tiny-version @@ -0,0 +1 @@ +2 From a2fee22f8f3d3fa2f1a4f3f9bd099c51c0b6c4b4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Mar 2023 18:37:27 -0500 Subject: [PATCH 0635/1891] added rtx-ruby --- scripts/update-shorthand-repo.sh | 1 + src/default_shorthands.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index bae7039d3..030eb903a 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -13,6 +13,7 @@ custom_plugins=( '("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"),' '("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"),' '("python", "https://github.com/rtx-plugins/rtx-python.git"),' + '("ruby", "https://github.com/rtx-plugins/rtx-ruby.git"),' '("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"),' ) diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index f98b88091..43301c336 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 633] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 634] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -643,5 +643,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 633] = [ ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), ("python", "https://github.com/rtx-plugins/rtx-python.git"), + ("ruby", "https://github.com/rtx-plugins/rtx-ruby.git"), ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ]; From 53ed13cc9173bee422eb51461eb2e5c421ba5dbc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 27 Mar 2023 18:44:08 -0500 Subject: [PATCH 0636/1891] fix stargazer count script --- scripts/query-top-plugins.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/query-top-plugins.fish b/scripts/query-top-plugins.fish index 5451f3776..1f63e7a20 100755 --- a/scripts/query-top-plugins.fish +++ b/scripts/query-top-plugins.fish @@ -1,4 +1,4 @@ -#!/usr/bin/fish +#!/usr/bin/env fish # Print out list of asdf plugins sorted by number of stars. Full list is # persisted to stargazer_count.txt From d2d91e1c33484d919c43ac55c8631afa42d8f3f6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 28 Mar 2023 23:09:06 -0500 Subject: [PATCH 0637/1891] added tera last_modified and file_exists filters (#421) --- src/runtimes.rs | 2 +- src/tera.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index 14a0b098e..e7f2ead11 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -402,7 +402,7 @@ fn render_cache_key(config: &Config, tv: &ToolVersion, cache_key: &[String]) -> .map(|tmpl| { let s = parse_template(config, tv, tmpl)?; let s = s.trim().to_string(); - //trace!("cache key element: {} -> {}", tmpl, s); + trace!("cache key element: {} -> {}", tmpl.trim(), s); let mut s = hash_to_str(&s); s.truncate(10); Ok(s) diff --git a/src/tera.rs b/src/tera.rs index 490cb6bfb..98a6b9bfb 100644 --- a/src/tera.rs +++ b/src/tera.rs @@ -49,5 +49,25 @@ pub fn get_tera(dir: &Path) -> Tera { _ => Err("hash input must be a string".into()), }, ); + tera.register_filter( + "last_modified", + move |input: &Value, _args: &HashMap| match input { + Value::String(s) => { + let p = Path::new(s); + let metadata = p.metadata()?; + let modified = metadata.modified()?; + let modified = modified.duration_since(std::time::UNIX_EPOCH).unwrap(); + Ok(Value::Number(modified.as_secs().into())) + } + _ => Err("hash input must be a string".into()), + }, + ); + tera.register_tester( + "file_exists", + move |input: Option<&Value>, _args: &[Value]| match input { + Some(Value::String(s)) => Ok(Path::new(s).exists()), + _ => Err("file_exists input must be a string".into()), + }, + ); tera } From 40342882cba73f2834737b63f666ba0f195d6a55 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 30 Mar 2023 16:03:06 -0500 Subject: [PATCH 0638/1891] removed unneeded crates (#426) these were incompatible with debian --- Cargo.lock | 26 -------------------------- Cargo.toml | 12 +++++------- src/cli/exec.rs | 2 -- src/test.rs | 1 - 4 files changed, 5 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a4856484..db37f8b02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -499,19 +499,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "errno" version = "0.2.8" @@ -1519,7 +1506,6 @@ dependencies = [ "dirs-next", "dotenvy", "duct", - "env_logger", "exec", "filetime", "flate2", @@ -1549,7 +1535,6 @@ dependencies = [ "simplelog", "tera", "terminal_size", - "test-log", "thiserror", "toml 0.7.3", "toml_edit", @@ -1881,17 +1866,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "test-log" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f0c854faeb68a048f0f2dc410c5ddae3bf83854ef0e4977d58306a5edef50e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "thiserror" version = "1.0.40" diff --git a/Cargo.toml b/Cargo.toml index 2574ec626..6c287e117 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,14 +26,14 @@ path = "src/main.rs" #harness = false [dependencies] -base64 = "<1" +base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } clap = { version = "4.0.32", features = ["env", "derive", "string"] } clap_complete = "4.0.7" clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" console = "0.15.2" -ctor = "<1" +ctor = "<0.3" ctrlc = "3.2.3" dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" @@ -52,7 +52,7 @@ lazy_static = "1.4.0" log = "0.4.17" num_cpus = "1.14.0" once_cell = "1.17.0" -owo-colors = { version = "3.5.0" } +owo-colors = "3.5.0" rayon = "1.6.1" regex = "1.7.1" reqwest = { version = "0.11.13", default-features = false, features = [ @@ -71,8 +71,8 @@ simplelog = { version = "0.12.0" } tera = { version = "1.12.1", default-features = false } terminal_size = "0.2.1" thiserror = "1.0.38" -toml = "<1" -toml_edit = "<1" +toml = "<0.8" +toml_edit = "<0.20" url = "2.3.1" versions = "4.1.0" @@ -83,10 +83,8 @@ exec = "0.3.1" built = { version = "0.6.0", features = ["chrono", "git2"] } [dev-dependencies] -env_logger = "0.10.0" insta = "1.26.0" pretty_assertions = "1.3.0" -test-log = "0.2" [features] alpine = [] diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 0891425cd..a59150eff 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -143,8 +143,6 @@ static AFTER_LONG_HELP: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { - use test_log::test; - use crate::assert_cli; use crate::cli::tests::cli_run; diff --git a/src/test.rs b/src/test.rs index e66f59ed6..f1c4e9bc1 100644 --- a/src/test.rs +++ b/src/test.rs @@ -26,7 +26,6 @@ fn init() { env::set_var("RTX_DEFAULT_CONFIG_FILENAME", ".test.rtx.toml"); env::set_var("RTX_MISSING_RUNTIME_BEHAVIOR", "autoinstall"); //env::set_var("TERM", "dumb"); - env_logger::init(); reset_config(); assert_cli!("trust"); assert_cli!("install", "tiny@1", "tiny@2", "tiny@3", "tiny", "dummy"); From 0c7a8aa555b39e197ed8d58761396cf5743879e7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 30 Mar 2023 20:23:00 -0500 Subject: [PATCH 0639/1891] upgraded to clap-4.2 (#428) --- Cargo.lock | 355 ++++++++++++++++++++++++++--------- Cargo.toml | 1 + README.md | 24 +-- man/man1/rtx.1 | 16 +- src/cli/activate.rs | 22 +-- src/cli/alias/get.rs | 18 +- src/cli/alias/ls.rs | 18 +- src/cli/alias/set.rs | 16 +- src/cli/alias/unset.rs | 16 +- src/cli/completion.rs | 35 +--- src/cli/current.rs | 36 ++-- src/cli/deactivate.rs | 20 +- src/cli/direnv/activate.rs | 22 +-- src/cli/doctor.rs | 27 ++- src/cli/env.rs | 22 +-- src/cli/exec.rs | 26 ++- src/cli/global.rs | 36 ++-- src/cli/install.rs | 21 +-- src/cli/latest.rs | 21 +-- src/cli/local.rs | 52 ++--- src/cli/ls.rs | 70 ++++--- src/cli/ls_remote.rs | 33 ++-- src/cli/mod.rs | 38 ++-- src/cli/plugins/install.rs | 32 ++-- src/cli/plugins/link.rs | 22 +-- src/cli/plugins/ls.rs | 27 ++- src/cli/plugins/uninstall.rs | 17 +- src/cli/plugins/update.rs | 20 +- src/cli/prune.rs | 19 +- src/cli/reshim.rs | 22 +-- src/cli/settings/get.rs | 18 +- src/cli/settings/ls.rs | 18 +- src/cli/settings/set.rs | 16 +- src/cli/settings/unset.rs | 16 +- src/cli/shell.rs | 23 +-- src/cli/trust.rs | 22 +-- src/cli/uninstall.rs | 17 +- src/cli/where.rs | 30 ++- src/cli/which.rs | 27 ++- 39 files changed, 669 insertions(+), 622 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db37f8b02..2238a2fc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,46 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-wincon", + "concolor-override", + "concolor-query", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + +[[package]] +name = "anstyle-parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-wincon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +dependencies = [ + "anstyle", + "windows-sys 0.45.0", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -157,48 +197,54 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.13" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c911b090850d79fc64fe9ea01e28e465f65e821e08813ced95bced72f7a8a9b" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_complete" -version = "4.1.5" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37686beaba5ac9f3ab01ee3172f792fc6ffdd685bfb9e63cfef02c0571a4e8e1" +checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.1.12" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a932373bab67b984c790ddf2c9ca295d8e3af3b7ef92de5a5bacdccdee4b09b" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.10", + "syn 2.0.12", ] [[package]] name = "clap_lex" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" -dependencies = [ - "os_str_bytes", -] +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "clap_mangen" @@ -235,6 +281,27 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "color-print" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" +dependencies = [ + "color-print-proc-macro", +] + +[[package]] +name = "color-print-proc-macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" +dependencies = [ + "nom", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "color-spantrace" version = "0.2.0" @@ -247,6 +314,21 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "concolor-override" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" + +[[package]] +name = "concolor-query" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" +dependencies = [ + "windows-sys 0.45.0", +] + [[package]] name = "console" version = "0.15.5" @@ -354,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" dependencies = [ "quote", - "syn 2.0.10", + "syn 2.0.12", ] [[package]] @@ -391,7 +473,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.10", + "syn 2.0.12", ] [[package]] @@ -408,7 +490,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.10", + "syn 2.0.12", ] [[package]] @@ -510,6 +592,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -526,7 +619,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "886b70328cba8871bfc025858e1de4be16b1d5088f2ba50b57816f4210672615" dependencies = [ - "errno", + "errno 0.2.8", "libc", ] @@ -557,7 +650,7 @@ checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "windows-sys 0.45.0", ] @@ -598,42 +691,42 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", "futures-io", @@ -646,9 +739,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -833,9 +926,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.54" +version = "0.1.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +checksum = "716f12fbcfac6ffab0a5e9ec51d0a0ff70503742bb2dc7b99396394c9dc323f0" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -953,19 +1046,19 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "is-terminal" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" +checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", + "rustix 0.37.5", "windows-sys 0.45.0", ] @@ -1059,6 +1152,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + [[package]] name = "log" version = "0.4.17" @@ -1207,12 +1306,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - [[package]] name = "output_vt100" version = "0.1.3" @@ -1378,6 +1471,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -1385,7 +1487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -1499,6 +1601,7 @@ dependencies = [ "clap_complete", "clap_mangen", "color-eyre", + "color-print", "console", "ctor 0.2.0", "ctrlc", @@ -1555,10 +1658,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e78cc525325c06b4a7ff02db283472f3c042b7ff0c391f96c6d5ac6f4f91b75" +dependencies = [ + "bitflags", + "errno 0.3.0", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.1", "windows-sys 0.45.0", ] @@ -1649,29 +1766,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.158" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.158" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.10", + "syn 2.0.12", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", @@ -1808,9 +1925,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.10" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" +checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" dependencies = [ "proc-macro2", "quote", @@ -1819,15 +1936,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.42.0", + "redox_syscall 0.3.5", + "rustix 0.37.5", + "windows-sys 0.45.0", ] [[package]] @@ -1862,7 +1979,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" dependencies = [ - "rustix", + "rustix 0.36.11", "windows-sys 0.45.0", ] @@ -1883,7 +2000,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.10", + "syn 2.0.12", ] [[package]] @@ -1941,14 +2058,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "pin-project-lite", @@ -2196,6 +2312,12 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" @@ -2378,11 +2500,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.46.0" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7" dependencies = [ - "windows-targets", + "windows-targets 0.47.0", ] [[package]] @@ -2391,13 +2513,13 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -2406,7 +2528,7 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", ] [[package]] @@ -2415,13 +2537,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e" +dependencies = [ + "windows_aarch64_gnullvm 0.47.0", + "windows_aarch64_msvc 0.47.0", + "windows_i686_gnu 0.47.0", + "windows_i686_msvc 0.47.0", + "windows_x86_64_gnu 0.47.0", + "windows_x86_64_gnullvm 0.47.0", + "windows_x86_64_msvc 0.47.0", ] [[package]] @@ -2430,42 +2567,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" + [[package]] name = "winnow" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index 6c287e117..cdf83d879 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ clap = { version = "4.0.32", features = ["env", "derive", "string"] } clap_complete = "4.0.7" clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" +color-print = "0.3.4" console = "0.15.2" ctor = "<0.3" ctrlc = "3.2.3" diff --git a/README.md b/README.md index 31cb07220..3e4b19e16 100644 --- a/README.md +++ b/README.md @@ -1414,10 +1414,10 @@ Options: Show "rtx: @" message when changing directories Examples: - eval "$(rtx activate bash)" - eval "$(rtx activate zsh)" - rtx activate fish | source - execx($(rtx activate xonsh)) + $ eval "$(rtx activate bash)" + $ eval "$(rtx activate zsh)" + $ rtx activate fish | source + $ execx($(rtx activate xonsh)) ``` ### `rtx alias get ` @@ -1436,8 +1436,8 @@ Arguments: The alias to show Examples: - $ rtx alias get nodejs lts/hydrogen - 18.0.0 + $ rtx alias get nodejs lts/hydrogen + 18.0.0 ``` ### `rtx alias ls [OPTIONS]` @@ -1666,14 +1666,14 @@ Options: [short aliases: C] Examples: - rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x - rtx x nodejs@18 -- node ./app.js # shorter alias + $ rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x + $ rtx x nodejs@18 -- node ./app.js # shorter alias # Specify command as a string: - rtx exec nodejs@18 python@3.11 --command "node -v && python -V" + $ rtx exec nodejs@18 python@3.11 --command "node -v && python -V" # Run a command in a different directory: - rtx x -C /path/to/project nodejs@18 -- node ./app.js + $ rtx x -C /path/to/project nodejs@18 -- node ./app.js ``` ### `rtx global [OPTIONS] [RUNTIME]...` @@ -2260,10 +2260,10 @@ Options: Examples: # trusts ~/some_dir/.rtx.toml - rtx trust ~/some_dir/.rtx.toml + $ rtx trust ~/some_dir/.rtx.toml # trusts .rtx.toml in the current or parent directory - rtx trust + $ rtx trust ``` ### `rtx uninstall ...` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 2a653acd0..4bc16ddce 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -131,15 +131,15 @@ rtx\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA Examples: - rtx install nodejs@18.0.0 Install a specific node version - rtx install nodejs@18.0 Install a version matching a prefix - rtx install nodejs Install the node version defined in + $ rtx install nodejs@18.0.0 Install a specific node version + $ rtx install nodejs@18.0 Install a version matching a prefix + $ rtx install nodejs Install the node version defined in .tool\-versions or .rtx.toml - rtx local nodejs@18 Use node\-18.x in current project - rtx global nodejs@18 Use node\-18.x as default - rtx local nodejs@latest Use latest node in current directory - rtx global nodejs@system Use system node everywhere unless overridden - rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to + $ rtx local nodejs@18 Use node\-18.x in current project + $ rtx global nodejs@18 Use node\-18.x as default + $ rtx local nodejs@latest Use latest node in current directory + $ rtx global nodejs@system Use system node everywhere unless overridden + $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION v1.27.9 diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 7b46ba5c4..417eb00ad 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -18,7 +15,7 @@ use crate::shell::{get_shell, ShellType}; /// Otherwise, it will only take effect in the current session. /// (e.g. ~/.bashrc) #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Activate { /// Shell type to generate the script for #[clap(long, short, hide = true)] @@ -52,12 +49,11 @@ impl Command for Activate { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - eval "$(rtx activate bash)" - eval "$(rtx activate zsh)" - rtx activate fish | source - execx($(rtx activate xonsh)) - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ eval "$(rtx activate bash)" + $ eval "$(rtx activate zsh)" + $ rtx activate fish | source + $ execx($(rtx activate xonsh)) +"# +); diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 8340970b5..3d7bc69e6 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::{eyre, Result}; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -12,7 +9,7 @@ use crate::output::Output; /// This is the contents of an alias. entry in ~/.config/rtx/config.toml /// #[derive(Debug, clap::Args)] -#[clap(after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasGet { /// The plugin to show the alias for pub plugin: String, @@ -32,13 +29,12 @@ impl Command for AliasGet { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx alias get nodejs lts/hydrogen - 18.0.0 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx alias get nodejs lts/hydrogen + 18.0.0 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 761f24170..9321b690f 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -17,7 +14,7 @@ use crate::plugins::PluginName; /// [alias.nodejs] /// lts = "18.0.0" #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasLs { /// Show aliases for #[clap(short, long)] @@ -41,13 +38,12 @@ impl Command for AliasLs { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx aliases - nodejs lts/hydrogen 18.0.0 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx aliases + nodejs lts/hydrogen 18.0.0 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 82904c383..561061f53 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; @@ -12,7 +9,7 @@ use crate::output::Output; /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasSet { /// The plugin to set the alias for pub plugin: String, @@ -31,12 +28,11 @@ impl Command for AliasSet { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx alias set nodejs lts/hydrogen 18.0.0 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx alias set nodejs lts/hydrogen 18.0.0 +"# +); #[cfg(test)] pub mod tests { diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 01afbbdde..899f44ae4 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; @@ -12,7 +9,7 @@ use crate::output::Output; /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases=["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasUnset { /// The plugin to remove the alias from pub plugin: String, @@ -27,12 +24,11 @@ impl Command for AliasUnset { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx alias unset nodejs lts/hydrogen - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx alias unset nodejs lts/hydrogen +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/completion.rs b/src/cli/completion.rs index c54b00ca1..348ee346e 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -2,9 +2,6 @@ use std::io::Cursor; use clap_complete::generate; use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::cli::Cli; @@ -13,7 +10,7 @@ use crate::output::Output; /// Generate shell completions #[derive(Debug, clap::Args)] -#[clap(alias = "complete", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(alias = "complete", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Completion { /// Shell type to generate completions for #[clap()] @@ -39,26 +36,10 @@ impl Command for Completion { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx completion bash > /etc/bash_completion.d/rtx - $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx - $ rtx completion fish > ~/.config/fish/completions/rtx.fish - "#, style("Examples:").bold().underlined()} -}); - -// #[cfg(test)] -// mod tests { -// use std::fs; -// -// use insta::assert_snapshot; -// -// use crate::{assert_cli, dirs}; -// -// #[test] -// fn test_completion() { -// let stdout = assert_cli!("completion", "-s", "zsh"); -// assert_snapshot!(stdout); -// } -// } +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx completion bash > /etc/bash_completion.d/rtx + $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx + $ rtx completion fish > ~/.config/fish/completions/rtx.fish +"# +); diff --git a/src/cli/current.rs b/src/cli/current.rs index 5fa1791de..016ab31b7 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -14,7 +11,7 @@ use crate::toolset::{Toolset, ToolsetBuilder}; /// This is similar to `rtx ls --current`, but this only shows the runtime /// and/or version. It's designed to fit into scripts more easily. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Current { /// Plugin to show versions of /// e.g.: ruby, nodejs @@ -92,24 +89,23 @@ impl Current { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - # outputs `.tool-versions` compatible format - $ rtx current - python 3.11.0 3.10.0 - shfmt 3.6.0 - shellcheck 0.9.0 - nodejs 18.13.0 +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # outputs `.tool-versions` compatible format + $ rtx current + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + nodejs 18.13.0 - $ rtx current nodejs - 18.13.0 + $ rtx current nodejs + 18.13.0 - # can output multiple versions - $ rtx current python - 3.11.0 3.10.0 - "#, style("Examples:").bold().underlined()} -}); + # can output multiple versions + $ rtx current python + 3.11.0 3.10.0 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 08d27fc6f..bc04504f4 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -13,7 +12,7 @@ use crate::shell::get_shell; /// /// This can be used to temporarily disable rtx in a shell session. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Deactivate {} impl Command for Deactivate { @@ -42,15 +41,14 @@ fn err_inactive() -> Result<()> { ))) } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx deactivate bash - $ rtx deactivate zsh - $ rtx deactivate fish - $ execx($(rtx deactivate xonsh)) - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx deactivate bash + $ rtx deactivate zsh + $ rtx deactivate fish + $ execx($(rtx deactivate xonsh)) +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 4c958f62d..1e1be26f9 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,8 +1,5 @@ -use console::style; - use color_eyre::eyre::Result; -use indoc::{formatdoc, indoc}; -use once_cell::sync::Lazy; +use indoc::indoc; use crate::cli::command::Command; use crate::config::Config; @@ -16,7 +13,7 @@ use crate::output::Output; /// you should run this command after installing new plugins. Otherwise /// direnv may not know to update environment variables when legacy file versions change. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct DirenvActivate {} impl Command for DirenvActivate { @@ -36,11 +33,10 @@ impl Command for DirenvActivate { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh - $ echo 'use rtx' > .envrc - $ direnv allow - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh + $ echo 'use rtx' > .envrc + $ direnv allow +"# +); diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 12e168e61..44d0067d0 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -1,26 +1,24 @@ +use std::fmt::Write; +use std::process::exit; + use color_eyre::eyre::Result; use console::{pad_str, style, Alignment}; use indenter::indented; -use indoc::formatdoc; -use once_cell::sync::Lazy; -use std::fmt::Write; -use std::process::exit; use crate::build_time::built_info; use crate::cli::command::Command; use crate::cli::version::VERSION; use crate::config::Config; use crate::git::Git; -use crate::{cli, cmd}; -use crate::{duration, env}; - use crate::output::Output; use crate::shell::ShellType; use crate::toolset::ToolsetBuilder; +use crate::{cli, cmd}; +use crate::{duration, env}; /// Check rtx installation for possible problems. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Doctor {} impl Command for Doctor { @@ -173,10 +171,9 @@ fn indent(s: String) -> String { out } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx doctor - [WARN] plugin nodejs is not installed - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx doctor + [WARN] plugin nodejs is not installed +"# +); diff --git a/src/cli/env.rs b/src/cli/env.rs index 37b6319a4..c57a852e5 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -15,7 +12,7 @@ use crate::toolset::ToolsetBuilder; /// Use this if you don't want to permanently install rtx. It's not necessary to /// use this if you have `rtx activate` in your shell rc file. #[derive(Debug, clap::Args)] -#[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Env { /// Shell type to generate environment variables for #[clap(long, short)] @@ -45,15 +42,14 @@ impl Command for Env { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ eval "$(rtx env -s bash)" - $ eval "$(rtx env -s zsh)" - $ rtx env -s fish | source - $ execx($(rtx env -s xonsh)) - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ eval "$(rtx env -s bash)" + $ eval "$(rtx env -s zsh)" + $ rtx env -s fish | source + $ execx($(rtx env -s xonsh)) +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index a59150eff..f32677998 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -3,11 +3,8 @@ use std::path::PathBuf; use clap::ValueHint; use color_eyre::eyre::{eyre, Result}; -use console::style; use duct::IntoExecutablePath; use indexmap::IndexMap; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -30,7 +27,7 @@ use crate::toolset::ToolsetBuilder; /// /// The "--" separates runtimes from the commands to pass along to the subprocess. #[derive(Debug, clap::Args)] -#[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Exec { /// Runtime(s) to start /// e.g.: nodejs@18 python@3.10 @@ -127,19 +124,18 @@ fn parse_command( } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x - rtx x nodejs@18 -- node ./app.js # shorter alias +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x + $ rtx x nodejs@18 -- node ./app.js # shorter alias - # Specify command as a string: - rtx exec nodejs@18 python@3.11 --command "node -v && python -V" + # Specify command as a string: + $ rtx exec nodejs@18 python@3.11 --command "node -v && python -V" - # Run a command in a different directory: - rtx x -C /path/to/project nodejs@18 -- node ./app.js - "#, style("Examples:").bold().underlined()} -}); + # Run a command in a different directory: + $ rtx x -C /path/to/project nodejs@18 -- node ./app.js +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/global.rs b/src/cli/global.rs index afc407950..e7c65499a 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,9 +1,6 @@ use std::path::PathBuf; use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -23,7 +20,7 @@ use crate::{dirs, env}; /// /// Use `rtx local` to set a runtime version locally in the current directory. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP)] pub struct Global { /// Runtime(s) to add to .tool-versions /// e.g.: nodejs@18 @@ -78,22 +75,21 @@ fn global_file() -> PathBuf { }) } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - # set the current version of nodejs to 18.x - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx global --fuzzy nodejs@18 - - # set the current version of nodejs to 18.x - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx global --pin nodejs@18 - - # show the current version of nodejs in ~/.tool-versions - $ rtx global nodejs - 18.0.0 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # set the current version of nodejs to 18.x + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx global --fuzzy nodejs@18 + + # set the current version of nodejs to 18.x + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx global --pin nodejs@18 + + # show the current version of nodejs in ~/.tool-versions + $ rtx global nodejs + 18.0.0 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/install.rs b/src/cli/install.rs index e1f7c52f0..817bded0a 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -3,8 +3,6 @@ use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use rayon::prelude::*; use rayon::ThreadPoolBuilder; @@ -29,7 +27,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// /// Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` #[derive(Debug, clap::Args)] -#[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Install { /// Runtime(s) to install /// e.g.: nodejs@18 @@ -202,15 +200,14 @@ impl Install { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx install nodejs@18.0.0 # install specific nodejs version - $ rtx install nodejs@18 # install fuzzy nodejs version - $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml - $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx install nodejs@18.0.0 # install specific nodejs version + $ rtx install nodejs@18 # install fuzzy nodejs version + $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml + $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 46cdeb53e..89e8d82cc 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,7 +1,5 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; @@ -10,7 +8,7 @@ use crate::output::Output; /// Gets the latest available version for a plugin #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Latest { /// Runtime to get the latest version of #[clap(value_parser = RuntimeArgParser)] @@ -54,16 +52,15 @@ impl Command for Latest { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx latest nodejs@18 # get the latest version of nodejs 18 - 18.0.0 +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx latest nodejs@18 # get the latest version of nodejs 18 + 18.0.0 - $ rtx latest nodejs # get the latest stable version of nodejs - 20.0.0 - "#, style("Examples:").bold().underlined()} -}); + $ rtx latest nodejs # get the latest stable version of nodejs + 20.0.0 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/local.rs b/src/cli/local.rs index c8fd59a1b..5e284ae8f 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -1,9 +1,6 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, ContextCompat, Result}; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -22,7 +19,7 @@ use crate::{dirs, env, file}; /// This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` /// is set. A future v2 release of rtx will default to using `.rtx.toml`. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP)] pub struct Local { /// Runtimes to add to .tool-versions/.rtx.toml /// e.g.: nodejs@18 @@ -153,28 +150,27 @@ fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result< Ok(()) } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - # set the current version of nodejs to 18.x for the current directory - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx local nodejs@18 +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # set the current version of nodejs to 18.x for the current directory + # will use a precise version (e.g.: 18.0.0) in .tool-versions file + $ rtx local nodejs@18 - # set nodejs to 18.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@18 + # set nodejs to 18.x for the current project (recurses up to find .tool-versions) + $ rtx local -p nodejs@18 - # set the current version of nodejs to 18.x for the current directory - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx local --fuzzy nodejs@18 + # set the current version of nodejs to 18.x for the current directory + # will use a fuzzy version (e.g.: 18) in .tool-versions file + $ rtx local --fuzzy nodejs@18 - # removes nodejs from .tool-versions - $ rtx local --remove=nodejs + # removes nodejs from .tool-versions + $ rtx local --remove=nodejs - # show the current version of nodejs in .tool-versions - $ rtx local nodejs - 18.0.0 - "#, style("Examples:").bold().underlined()} -}); + # show the current version of nodejs in .tool-versions + $ rtx local nodejs + 18.0.0 +"# +); #[cfg(test)] mod tests { @@ -200,6 +196,7 @@ mod tests { ); }); } + #[test] fn test_local_pin() { run_test(|| { @@ -211,6 +208,7 @@ mod tests { assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0"); }); } + #[test] fn test_local_path() { run_test(|| { @@ -219,6 +217,7 @@ mod tests { assert_str_eq!(grep(stdout, "dummy"), "dummy path:."); }); } + #[test] fn test_local_ref() { run_test(|| { @@ -227,6 +226,7 @@ mod tests { assert_str_eq!(grep(stdout, "dummy"), "dummy ref:master"); }); } + #[test] fn test_local_prefix() { run_test(|| { @@ -235,6 +235,7 @@ mod tests { assert_str_eq!(grep(stdout, "dummy"), "dummy prefix:1"); }); } + #[test] fn test_local_multiple_versions() { run_test(|| { @@ -243,6 +244,7 @@ mod tests { assert_cli_snapshot!("bin-paths"); }); } + #[test] fn test_local_output_current_version() { run_test(|| { @@ -251,6 +253,7 @@ mod tests { assert_str_eq!(stdout, "2\n"); }); } + #[test] fn test_local_invalid_multiple_plugins() { run_test(|| { @@ -258,6 +261,7 @@ mod tests { assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); }); } + #[test] fn test_local_invalid() { run_test(|| { @@ -265,6 +269,7 @@ mod tests { assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); }); } + #[test] fn test_local_alias_ref() { run_test(|| { @@ -275,6 +280,7 @@ mod tests { assert_cli_snapshot!("current", "dummy"); }); } + #[test] fn test_local_alias_path() { run_test(|| { @@ -289,6 +295,7 @@ mod tests { assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); }); } + #[test] fn test_local_alias_prefix() { run_test(|| { @@ -299,6 +306,7 @@ mod tests { assert_cli_snapshot!("current", "dummy"); }); } + #[test] fn test_local_alias_system() { run_test(|| { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 85e106a34..982ea60dd 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -5,9 +5,7 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use console::style; use indexmap::IndexMap; -use indoc::formatdoc; use itertools::Itertools; -use once_cell::sync::Lazy; use owo_colors::OwoColorize; use serde_derive::Serialize; use versions::Versioning; @@ -26,7 +24,7 @@ use crate::toolset::{ToolSource, ToolsetBuilder}; /// The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. /// (Assuming `rtx activate` or `rtx env` is in use). #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Ls { /// Only show runtimes from [PLUGIN] #[clap(long, short)] @@ -243,44 +241,44 @@ fn get_runtime_list( Ok(rvs) } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx ls - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) - python 3.10.0 - - $ rtx ls --current - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) - - $ rtx ls --parseable - nodejs 18.0.0 - python 3.11.0 - - $ rtx ls --json - {{ - "nodejs": [ - {{ - "version": "18.0.0", - "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", - "source": {{ - "type": ".rtx.toml", - "path": "/Users/jdx/.rtx.toml" - }} - }} - ], - "python": [...] - }} - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx ls + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) + python 3.10.0 + + $ rtx ls --current + ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ python 3.11.0 (set by ~/.tool-versions) + + $ rtx ls --parseable + nodejs 18.0.0 + python 3.11.0 + + $ rtx ls --json + { + "nodejs": [ + { + "version": "18.0.0", + "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", + "source": { + "type": ".rtx.toml", + "path": "/Users/jdx/.rtx.toml" + } + } + ], + "python": [...] + } +"# +); #[cfg(test)] mod tests { + use pretty_assertions::assert_str_eq; + use crate::file::remove_all; use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; - use pretty_assertions::assert_str_eq; #[test] fn test_ls() { diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 72153542b..eb4178b02 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; @@ -14,7 +11,7 @@ use crate::output::Output; /// note that these versions are cached for commands like `rtx install nodejs@latest` /// however _this_ command will always clear that cache and fetch the latest remote versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str(), aliases = ["list-all", "list-remote"])] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = ["list-all", "list-remote"])] pub struct LsRemote { /// Plugin to get versions for #[clap(value_parser = RuntimeArgParser)] @@ -56,26 +53,24 @@ impl Command for LsRemote { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx ls-remote nodejs - 18.0.0 - 20.0.0 +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx ls-remote nodejs + 18.0.0 + 20.0.0 - $ rtx ls-remote nodejs@18 - 18.0.0 - 18.1.0 + $ rtx ls-remote nodejs@18 + 18.0.0 + 18.1.0 - $ rtx ls-remote nodejs 18 - 18.0.0 - 18.1.0 - "#, style("Examples:").bold().underlined()} -}); + $ rtx ls-remote nodejs 18 + 18.0.0 + 18.1.0 +"# +); #[cfg(test)] mod tests { - use crate::assert_cli_snapshot; #[test] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e1c7bbceb..ec0b804ba 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,9 +1,7 @@ use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; -use console::style; -use indoc::{formatdoc, indoc}; +use indoc::indoc; use log::LevelFilter; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -162,7 +160,7 @@ impl Cli { .long_about(LONG_ABOUT) .arg_required_else_help(true) .subcommand_required(true) - .after_long_help(AFTER_LONG_HELP.as_str()) + .after_long_help(AFTER_LONG_HELP) .arg(args::log_level::Debug::arg()) .arg(args::install_missing::InstallMissing::arg()) .arg(args::jobs::Jobs::arg()) @@ -222,27 +220,27 @@ jq and shellcheck. It is inspired by asdf and uses asdf's plugin ecosystem under the hood: https://asdf-vm.com/"}; -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! { " - {} - rtx install nodejs@18.0.0 Install a specific node version - rtx install nodejs@18.0 Install a version matching a prefix - rtx install nodejs Install the node version defined in - .tool-versions or .rtx.toml - rtx local nodejs@18 Use node-18.x in current project - rtx global nodejs@18 Use node-18.x as default - rtx local nodejs@latest Use latest node in current directory - rtx global nodejs@system Use system node everywhere unless overridden - rtx x nodejs@18 -- node app.js Run `node app.js` with PATH pointing to - node-18.x -", style("Examples:").bold().underlined() } -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx install nodejs@18.0.0 Install a specific node version + $ rtx install nodejs@18.0 Install a version matching a prefix + $ rtx install nodejs Install the node version defined in + .tool-versions or .rtx.toml + $ rtx local nodejs@18 Use node-18.x in current project + $ rtx global nodejs@18 Use node-18.x as default + $ rtx local nodejs@latest Use latest node in current directory + $ rtx global nodejs@system Use system node everywhere unless overridden + $ rtx x nodejs@18 -- node app.js Run `node app.js` with PATH pointing to + node-18.x +"# +); #[cfg(test)] pub mod tests { - use crate::dirs; use color_eyre::{Section, SectionExt}; + use crate::dirs; + use super::*; pub fn cli_run(args: &Vec) -> Result { diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 86c3dd957..642a12c3f 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::{eyre, Result}; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use rayon::prelude::*; use rayon::ThreadPoolBuilder; use url::Url; @@ -20,7 +17,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// /// This behavior can be modified in ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct PluginsInstall { /// The name of the plugin to install /// e.g.: nodejs, ruby @@ -164,23 +161,22 @@ fn get_name_from_url(url: &str) -> Result { Err(eyre!("could not infer plugin name from url: {}", url)) } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - # install the nodejs via shorthand - $ rtx plugins install nodejs +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # install the nodejs via shorthand + $ rtx plugins install nodejs - # install the nodejs plugin using a specific git url - $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git + # install the nodejs plugin using a specific git url + $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git - # install the nodejs plugin using the git url only - # (nodejs is inferred from the url) - $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git + # install the nodejs plugin using the git url only + # (nodejs is inferred from the url) + $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git - # install the nodejs plugin using a specific ref - $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git#v1.0.0 - "#, style("Examples:").bold().underlined()} -}); + # install the nodejs plugin using a specific ref + $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git#v1.0.0 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index ef3f3eefd..a2bca7b5f 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -2,11 +2,8 @@ use std::fs; use std::path::{Path, PathBuf}; use clap::ValueHint; - use color_eyre::eyre::{eyre, Result}; use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -18,7 +15,7 @@ use crate::output::Output; /// /// This is used for developing a plugin. #[derive(Debug, clap::Args)] -#[clap(alias = "l", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(alias = "l", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct PluginsLink { /// The name of the plugin /// e.g.: nodejs, ruby @@ -70,16 +67,15 @@ fn get_name_from_path(path: &Path) -> String { name.to_string() } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - # essentially just `ln -s ./rtx-nodejs ~/.local/share/rtx/plugins/nodejs` - $ rtx plugins link nodejs ./rtx-nodejs +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # essentially just `ln -s ./rtx-nodejs ~/.local/share/rtx/plugins/nodejs` + $ rtx plugins link nodejs ./rtx-nodejs - # infer plugin name as "nodejs" - $ rtx plugins link ./rtx-nodejs - "#, style("Examples:").bold().underlined()} -}); + # infer plugin name as "nodejs" + $ rtx plugins link ./rtx-nodejs +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 7e66cedb7..0a4d3342f 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::cli::plugins::ls_remote::PluginsLsRemote; @@ -12,7 +9,7 @@ use crate::output::Output; /// /// Can also show remotely available plugins to install. #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct PluginsLs { /// List all available remote plugins /// Same as `rtx plugins ls-remote` @@ -48,25 +45,23 @@ impl Command for PluginsLs { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx plugins ls - nodejs - ruby +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx plugins ls + nodejs + ruby - $ rtx plugins ls --urls - nodejs https://github.com/asdf-vm/asdf-nodejs.git - ruby https://github.com/asdf-vm/asdf-ruby.git - "#, style("Examples:").bold().underlined()} -}); + $ rtx plugins ls --urls + nodejs https://github.com/asdf-vm/asdf-nodejs.git + ruby https://github.com/asdf-vm/asdf-ruby.git +"# +); #[cfg(test)] mod tests { use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; - use crate::{assert_cli, assert_cli_snapshot}; #[test] diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 1ca1cb3c1..bcc680e0e 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,18 +1,14 @@ use color_eyre::eyre::Result; use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; - use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; - use crate::ui::multi_progress_report::MultiProgressReport; /// Removes a plugin #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct PluginsUninstall { /// Plugin(s) to remove #[clap(required = true, verbatim_doc_comment)] @@ -56,9 +52,8 @@ impl PluginsUninstall { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx uninstall nodejs - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx uninstall nodejs +"# +); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 8ed2e6fe0..464108457 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,7 +1,5 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -11,7 +9,7 @@ use crate::output::Output; /// /// note: this updates the plugin itself, not the runtime versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "upgrade", after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, alias = "upgrade", after_long_help = AFTER_LONG_HELP)] pub struct Update { /// Plugin(s) to update #[clap()] @@ -53,18 +51,16 @@ impl Command for Update { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx plugins update # update all plugins - $ rtx plugins update nodejs # update only nodejs - $ rtx plugins update nodejs@beta # specify a ref - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx plugins update # update all plugins + $ rtx plugins update nodejs # update only nodejs + $ rtx plugins update nodejs@beta # specify a ref +"# +); #[cfg(test)] mod tests { - use crate::assert_cli; #[test] diff --git a/src/cli/prune.rs b/src/cli/prune.rs index addbbd98c..30a061d41 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -1,8 +1,6 @@ use color_eyre::eyre::Result; use console::style; use indexmap::IndexMap; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -19,7 +17,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Versions installed only with environment variables (`RTX__VERSION`) will be deleted, /// as will versions only referenced on the command line (`rtx exec @`). #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Prune { /// Prune only versions from these plugins #[clap()] @@ -71,14 +69,13 @@ impl Prune { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx prune --dry-run + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 + rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 02c3d1313..7def19cb1 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -13,7 +12,7 @@ use crate::toolset::ToolsetBuilder; /// /// this requires that the shims_dir is set #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Reshim { #[clap(hide = true)] pub plugin: Option, @@ -43,13 +42,12 @@ fn err_experimental() -> Result<()> { ))) } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx settings set experimental true - $ rtx settings set shims_dir ~/.rtx/shims - $ rtx reshim - $ ~/.rtx/shims/node -v - v18.0.0 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx settings set experimental true + $ rtx settings set shims_dir ~/.rtx/shims + $ rtx reshim + $ ~/.rtx/shims/node -v + v18.0.0 +"# +); diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index e5e58ef4f..285780e65 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::{eyre, Result}; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -14,7 +11,7 @@ use crate::output::Output; /// Note that aliases are also stored in this file /// but managed separately with `rtx aliases get` #[derive(Debug, clap::Args)] -#[clap(after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsGet { /// The setting to show pub key: String, @@ -29,13 +26,12 @@ impl Command for SettingsGet { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx settings get legacy_version_file - true - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx settings get legacy_version_file + true +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 2c69e7e21..3a47c1948 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; @@ -14,7 +11,7 @@ use crate::output::Output; /// Note that aliases are also stored in this file /// but managed separately with `rtx aliases` #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsLs {} impl Command for SettingsLs { @@ -26,13 +23,12 @@ impl Command for SettingsLs { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx settings - legacy_version_file = false - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx settings + legacy_version_file = false +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 1272bcc1f..80b7a7207 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::{eyre, Result}; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; @@ -12,7 +9,7 @@ use crate::output::Output; /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsSet { /// The setting to set pub key: String, @@ -58,12 +55,11 @@ fn parse_i64(value: &str) -> Result { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx settings set legacy_version_file true - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx settings set legacy_version_file true +"# +); #[cfg(test)] pub mod tests { diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 50e4b633f..b5cbf5a41 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; @@ -12,7 +9,7 @@ use crate::output::Output; /// /// This modifies the contents of ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP.as_str(), verbatim_doc_comment)] +#[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsUnset { /// The setting to remove pub key: String, @@ -25,12 +22,11 @@ impl Command for SettingsUnset { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx settings unset legacy_version_file - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx settings unset legacy_version_file +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 288d4c857..cb67c4680 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -1,13 +1,10 @@ use color_eyre::eyre::{eyre, Result}; - use console::style; use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; - use crate::output::Output; use crate::shell::get_shell; use crate::toolset::{ToolSource, ToolsetBuilder}; @@ -16,7 +13,7 @@ use crate::toolset::{ToolSource, ToolsetBuilder}; /// /// Only works in a session where rtx is already activated. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Shell { /// Runtime version(s) to use #[clap(value_parser = RuntimeArgParser)] @@ -66,20 +63,20 @@ fn err_inactive() -> Result<()> { ))) } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx shell nodejs@18 - $ node -v - v18.0.0 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx shell nodejs@18 + $ node -v + v18.0.0 +"# +); #[cfg(test)] mod tests { - use insta::assert_display_snapshot; use std::env; + use insta::assert_display_snapshot; + use crate::{assert_cli_err, assert_cli_snapshot}; #[test] diff --git a/src/cli/trust.rs b/src/cli/trust.rs index 802cdcd86..23be33289 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -2,9 +2,6 @@ use std::path::PathBuf; use clap::ValueHint; use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::cli::local; @@ -21,7 +18,7 @@ use crate::output::Output; /// - templates /// - `path:` plugin versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Trust { /// The config file to trust #[clap(value_hint = ValueHint::FilePath, verbatim_doc_comment)] @@ -49,16 +46,15 @@ impl Command for Trust { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - # trusts ~/some_dir/.rtx.toml - rtx trust ~/some_dir/.rtx.toml +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # trusts ~/some_dir/.rtx.toml + $ rtx trust ~/some_dir/.rtx.toml - # trusts .rtx.toml in the current or parent directory - rtx trust - "#, style("Examples:").bold().underlined()} -}); + # trusts .rtx.toml in the current or parent directory + $ rtx trust +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index e4261c47e..ff21f54b2 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,7 +1,5 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -12,7 +10,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Removes runtime versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct Uninstall { /// Runtime(s) to remove #[clap(required = true, value_parser = RuntimeArgParser)] @@ -46,10 +44,9 @@ impl Command for Uninstall { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx uninstall nodejs@18.0.0 # will uninstall specific version - $ rtx uninstall nodejs # will uninstall current nodejs version - "#, style("Examples:").underlined().bold()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx uninstall nodejs@18.0.0 # will uninstall specific version + $ rtx uninstall nodejs # will uninstall current nodejs version +"# +); diff --git a/src/cli/where.rs b/src/cli/where.rs index 892986258..1007cc031 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,7 +1,4 @@ use color_eyre::eyre::Result; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; use crate::cli::command::Command; @@ -14,7 +11,7 @@ use crate::toolset::ToolsetBuilder; /// /// Must be installed. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Where { /// Runtime(s) to look up /// e.g.: ruby@3 @@ -59,20 +56,19 @@ impl Command for Where { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - # Show the latest installed version of nodejs - # If it is is not installed, errors - $ rtx where nodejs@18 - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # Show the latest installed version of nodejs + # If it is is not installed, errors + $ rtx where nodejs@18 + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 - # Show the current, active install directory of nodejs - # Errors if nodejs is not referenced in any .tool-version file - $ rtx where nodejs - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 - "#, style("Examples:").bold().underlined()} -}); + # Show the current, active install directory of nodejs + # Errors if nodejs is not referenced in any .tool-version file + $ rtx where nodejs + /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 +"# +); #[cfg(test)] mod tests { diff --git a/src/cli/which.rs b/src/cli/which.rs index 7c3fac308..1c181ae0a 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -1,17 +1,13 @@ use color_eyre::eyre::{eyre, Result}; -use console::style; -use indoc::formatdoc; -use once_cell::sync::Lazy; use crate::cli::command::Command; use crate::config::Config; - use crate::output::Output; use crate::toolset::ToolsetBuilder; /// Shows the path that a bin name points to #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP.as_str())] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Which { #[clap()] pub bin_name: String, @@ -46,17 +42,16 @@ impl Command for Which { } } -static AFTER_LONG_HELP: Lazy = Lazy::new(|| { - formatdoc! {r#" - {} - $ rtx which node - /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node - $ rtx which node --plugin - nodejs - $ rtx which node --version - 18.0.0 - "#, style("Examples:").bold().underlined()} -}); +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx which node + /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node + $ rtx which node --plugin + nodejs + $ rtx which node --version + 18.0.0 +"# +); #[cfg(test)] mod tests { From f6c6e7138e144e0698b988ce4c92f871892191de Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 30 Mar 2023 20:25:42 -0500 Subject: [PATCH 0640/1891] refactor plugins to support core plugins (#429) --- src/cli/asdf.rs | 8 +- src/cli/current.rs | 18 +- src/cli/doctor.rs | 11 +- src/cli/external.rs | 4 +- src/cli/install.rs | 7 +- src/cli/latest.rs | 3 +- src/cli/ls.rs | 25 +- src/cli/ls_remote.rs | 1 + src/cli/plugins/install.rs | 4 +- src/cli/plugins/ls.rs | 22 +- src/cli/plugins/ls_remote.rs | 3 +- src/cli/plugins/uninstall.rs | 1 + src/cli/plugins/update.rs | 3 +- src/cli/prune.rs | 4 +- src/cli/shell.rs | 5 +- src/cli/which.rs | 3 +- src/config/config_file/legacy_version.rs | 9 +- src/config/mod.rs | 28 +- src/plugins/external_plugin.rs | 593 +++++++++++++++++++++ src/plugins/mod.rs | 640 ++++------------------- src/runtime_symlinks.rs | 21 +- src/runtimes.rs | 132 +++-- src/shims.rs | 31 +- src/toolset/mod.rs | 15 +- src/toolset/tool_version.rs | 29 +- src/toolset/tool_version_list.rs | 13 +- 26 files changed, 931 insertions(+), 702 deletions(-) create mode 100644 src/plugins/external_plugin.rs diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 47d7d6432..8118739e2 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -5,6 +5,7 @@ use crate::cli::command::Command; use crate::cli::Cli; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; use crate::toolset::ToolsetBuilder; /// [internal] simulates asdf for plugins that call "asdf" internally @@ -59,12 +60,15 @@ fn list_versions(mut config: Config, out: &mut Output, args: &Vec) -> Re _ => None, }; if let Some(plugin) = plugin { - versions.retain(|v| &v.plugin.name == plugin); + versions.retain(|v| v.plugin.name() == plugin); for version in versions { rtxprintln!(out, "{}", version.version); } } else { - for (plugin, versions) in &versions.into_iter().group_by(|v| v.plugin.name.clone()) { + for (plugin, versions) in &versions + .into_iter() + .group_by(|v| v.plugin.name().to_string()) + { rtxprintln!(out, "{}", plugin); for version in versions { rtxprintln!(out, " {}", version.version); diff --git a/src/cli/current.rs b/src/cli/current.rs index 016ab31b7..93f056575 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use color_eyre::eyre::Result; use crate::cli::command::Command; @@ -24,7 +26,7 @@ impl Command for Current { let ts = ToolsetBuilder::new().build(&mut config)?; match &self.plugin { Some(plugin_name) => match config.plugins.get(plugin_name) { - Some(plugin) => self.one(ts, out, plugin), + Some(plugin) => self.one(ts, out, plugin.clone()), None => { warn!("Plugin {} is not installed", plugin_name); Ok(()) @@ -36,12 +38,12 @@ impl Command for Current { } impl Current { - fn one(&self, ts: Toolset, out: &mut Output, plugin: &Plugin) -> Result<()> { + fn one(&self, ts: Toolset, out: &mut Output, plugin: Arc) -> Result<()> { if !plugin.is_installed() { - warn!("Plugin {} is not installed", plugin.name); + warn!("Plugin {} is not installed", plugin.name()); return Ok(()); } - match ts.list_versions_by_plugin().get(&plugin.name) { + match ts.list_versions_by_plugin().get(plugin.name()) { Some(versions) => { rtxprintln!( out, @@ -54,7 +56,7 @@ impl Current { ); } None => { - warn!("Plugin {} does not have a version set", plugin.name); + warn!("Plugin {} does not have a version set", plugin.name()); } }; Ok(()) @@ -67,10 +69,12 @@ impl Current { } for rtv in &versions { if !rtv.is_installed() { - let source = ts.versions.get(&rtv.plugin.name).unwrap().source.clone(); + let source = ts.versions.get(rtv.plugin.name()).unwrap().source.clone(); warn!( "{}@{} is specified in {}, but not installed", - &rtv.plugin.name, &rtv.version, &source + rtv.plugin.name(), + &rtv.version, + &source ); } } diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 44d0067d0..236d735ed 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -11,6 +11,7 @@ use crate::cli::version::VERSION; use crate::config::Config; use crate::git::Git; use crate::output::Output; +use crate::plugins::{Plugin, Plugins}; use crate::shell::ShellType; use crate::toolset::ToolsetBuilder; use crate::{cli, cmd}; @@ -46,7 +47,7 @@ impl Command for Doctor { let mut checks = Vec::new(); for plugin in config.plugins.values() { if !plugin.is_installed() { - checks.push(format!("plugin {} is not installed", plugin.name)); + checks.push(format!("plugin {} is not installed", plugin.name())); continue; } } @@ -110,10 +111,14 @@ fn render_plugins(config: &Config) -> String { .plugins .values() .filter(|p| p.is_installed()) + .map(|p| match p.as_ref() { + Plugins::External(p) => p, + //_ => None, + }) .collect::>(); - let max_plugin_name_len = plugins.iter().map(|p| p.name.len()).max().unwrap_or(0) + 2; + let max_plugin_name_len = plugins.iter().map(|p| p.name().len()).max().unwrap_or(0) + 2; for p in plugins { - let padded_name = pad_str(&p.name, max_plugin_name_len, Alignment::Left, None); + let padded_name = pad_str(p.name(), max_plugin_name_len, Alignment::Left, None); let git = Git::new(p.plugin_path.clone()); let si = match git.get_remote_url() { Some(url) => { diff --git a/src/cli/external.rs b/src/cli/external.rs index 06590cdfd..6de36104e 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -4,6 +4,7 @@ use itertools::Itertools; use rayon::prelude::*; use crate::config::Config; +use crate::plugins::Plugin; pub fn commands(config: &Config) -> Vec { config @@ -16,7 +17,8 @@ pub fn commands(config: &Config) -> Vec { Err(e) => { warn!( "failed to load external commands for plugin {}: {:#}", - p.name, e + p.name(), + e ); vec![] } diff --git a/src/cli/install.rs b/src/cli/install.rs index 817bded0a..7215e248b 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -12,7 +12,7 @@ use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; use crate::toolset::{ToolVersion, ToolVersionType, ToolsetBuilder}; @@ -104,7 +104,10 @@ impl Install { for mut tv in tool_versions { let plugin = match config.plugins.get(&tv.plugin_name).cloned() { Some(plugin) => plugin, - None => Arc::new(Plugin::new(&config.settings, &tv.plugin_name)), + None => Arc::new(Plugins::External(ExternalPlugin::new( + &config.settings, + &tv.plugin_name, + ))), }; if !plugin.is_installed() { let mut pr = mpr.add(); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 89e8d82cc..4b79fb157 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -5,6 +5,7 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion} use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; /// Gets the latest available version for a plugin #[derive(Debug, clap::Args)] @@ -41,7 +42,7 @@ impl Command for Latest { ) })?; if let Some(v) = prefix { - prefix = Some(config.resolve_alias(&plugin.name, &v)?); + prefix = Some(config.resolve_alias(plugin.name(), &v)?); } plugin.clear_remote_version_cache()?; diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 982ea60dd..d7d3fbfff 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -15,7 +15,7 @@ use crate::config::Config; use crate::env::DUMB_TERMINAL; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::PluginName; +use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; use crate::toolset::{ToolSource, ToolsetBuilder}; @@ -96,7 +96,7 @@ impl Ls { let mut plugins = JSONOutput::new(); for (plugin_name, runtimes) in &runtimes .into_iter() - .group_by(|(rtv, _)| rtv.plugin.name.clone()) + .group_by(|(rtv, _)| rtv.plugin.name().clone()) { let runtimes = runtimes .map(|(rtv, source)| JSONRuntime { @@ -130,7 +130,7 @@ impl Ls { // only displaying 1 plugin so only show the version rtxprintln!(out, "{}", rtv.version); } else { - rtxprintln!(out, "{} {}", rtv.plugin.name, rtv.version); + rtxprintln!(out, "{} {}", rtv.plugin.name(), rtv.version); } }); Ok(()) @@ -175,15 +175,15 @@ fn styled_version(rtv: &RuntimeVersion, missing: bool, active: bool) -> String { style(&rtv.version).dim().to_string() }; let unstyled = if missing { - format!("{} {} (missing)", &rtv.plugin.name, &rtv.version) + format!("{} {} (missing)", &rtv.plugin.name(), &rtv.version) } else { - format!("{} {}", &rtv.plugin.name, &rtv.version) + format!("{} {}", &rtv.plugin.name(), &rtv.version) }; let pad = max(0, 25 - unstyled.len() as isize) as usize; format!( "{} {}{}", - style(&rtv.plugin.name).cyan(), + style(&rtv.plugin.name()).cyan(), styled, " ".repeat(pad) ) @@ -198,16 +198,21 @@ fn get_runtime_list( .list_installed_versions(config)? .into_iter() .filter(|rtv| match plugin_flag { - Some(plugin) => rtv.plugin.name == *plugin, + Some(plugin) => rtv.plugin.name() == plugin, None => true, }) - .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv)) + .map(|rtv| ((rtv.plugin.name().clone(), rtv.version.clone()), rtv)) .collect(); let active = ts .list_current_versions() .into_iter() - .map(|rtv| ((rtv.plugin.name.clone(), rtv.version.clone()), rtv.clone())) + .map(|rtv| { + ( + (rtv.plugin.name().clone(), rtv.version.clone()), + rtv.clone(), + ) + }) .collect::>(); versions.extend( @@ -230,7 +235,7 @@ fn get_runtime_list( let source = match &active.get(&k) { Some(rtv) => ts .versions - .get(&rtv.plugin.name) + .get(rtv.plugin.name()) .map(|tv| tv.source.clone()), None => None, }; diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index eb4178b02..ff7934848 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -5,6 +5,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; +use crate::plugins::Plugin; /// List runtime versions available for install /// diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 642a12c3f..f8ac053c8 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::{Plugin, PluginName}; +use crate::plugins::{ExternalPlugin, Plugin, PluginName}; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; @@ -111,7 +111,7 @@ impl PluginsInstall { git_url: &str, mpr: &MultiProgressReport, ) -> Result<()> { - let mut plugin = Plugin::new(&config.settings, name); + let mut plugin = ExternalPlugin::new(&config.settings, name); let (git_url, ref_) = git_url .split_once('#') .map_or((git_url, None), |(a, b)| (a, Some(b))); diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 0a4d3342f..02fc9747c 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -4,6 +4,8 @@ use crate::cli::command::Command; use crate::cli::plugins::ls_remote::PluginsLsRemote; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; +use crate::plugins::Plugins; /// List installed plugins /// @@ -32,14 +34,22 @@ impl Command for PluginsLs { .run(config, out); } - for plugin in config.plugins.values() { - if self.urls { - if let Some(url) = plugin.get_remote_url() { - rtxprintln!(out, "{:29} {}", plugin.name, url); - continue; + if self.urls { + for plugin in config.plugins.values() { + match plugin.as_ref() { + Plugins::External(plugin) => { + if let Some(url) = plugin.get_remote_url() { + rtxprintln!(out, "{:29} {}", plugin.name, url); + continue; + } + } //_ => {} } + rtxprintln!(out, "{}", plugin.name()); + } + } else { + for plugin in config.plugins.values() { + rtxprintln!(out, "{}", plugin.name()); } - rtxprintln!(out, "{}", plugin.name); } Ok(()) } diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 7a5490f75..513676883 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -7,6 +7,7 @@ use itertools::Itertools; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; /// List all available remote plugins /// @@ -31,7 +32,7 @@ impl Command for PluginsLsRemote { .plugins .values() .filter(|p| p.is_installed()) - .map(|p| p.name.clone()) + .map(|p| p.name().clone()) .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 bcc680e0e..4953e0034 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::Plugin; use crate::ui::multi_progress_report::MultiProgressReport; /// Removes a plugin diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 464108457..4823fafb0 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -4,6 +4,7 @@ use console::style; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; /// Updates a plugin to the latest version /// @@ -44,7 +45,7 @@ impl Command for Update { }; for (plugin, ref_) in plugins { - rtxprintln!(out, "updating plugin {}", plugin.name); + rtxprintln!(out, "updating plugin {}", plugin.name()); plugin.update(ref_)?; } Ok(()) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 30a061d41..3b63bb56b 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -5,7 +5,7 @@ use indexmap::IndexMap; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::PluginName; +use crate::plugins::{Plugin, PluginName}; use crate::runtimes::RuntimeVersion; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; @@ -38,7 +38,7 @@ impl Command for Prune { .collect::>(); if let Some(plugins) = &self.plugins { - to_delete.retain(|_, rtv| plugins.contains(&rtv.plugin.name)); + to_delete.retain(|_, rtv| plugins.contains(rtv.plugin.name())); } for cf in config.get_tracked_config_files()?.values() { diff --git a/src/cli/shell.rs b/src/cli/shell.rs index cb67c4680..b35074dca 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -6,6 +6,7 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; use crate::shell::get_shell; use crate::toolset::{ToolSource, ToolsetBuilder}; @@ -37,9 +38,9 @@ impl Command for Shell { let shell = get_shell(None).expect("no shell detected"); for rtv in ts.list_current_installed_versions() { - let source = &ts.versions.get(&rtv.plugin.name).unwrap().source; + let source = &ts.versions.get(rtv.plugin.name()).unwrap().source; if matches!(source, ToolSource::Argument) { - let k = format!("RTX_{}_VERSION", rtv.plugin.name.to_uppercase()); + let k = format!("RTX_{}_VERSION", rtv.plugin.name().to_uppercase()); let op = if self.unset { shell.unset_env(&k) } else { diff --git a/src/cli/which.rs b/src/cli/which.rs index 1c181ae0a..fc49583a7 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -3,6 +3,7 @@ use color_eyre::eyre::{eyre, Result}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; use crate::toolset::ToolsetBuilder; /// Shows the path that a bin name points to @@ -30,7 +31,7 @@ impl Command for Which { if self.version { rtxprintln!(out, "{}", rtv.version); } else if self.plugin { - rtxprintln!(out, "{}", rtv.plugin.name); + rtxprintln!(out, "{}", rtv.plugin.name()); } else { let path = rtv.which(&config.settings, &self.bin_name)?; rtxprintln!(out, "{}", path.unwrap().display()); diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 5eb74ad71..7f0e673a5 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -8,7 +8,7 @@ use color_eyre::eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, Settings}; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::{Plugin, PluginName, Plugins}; use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; #[derive(Debug)] @@ -18,11 +18,11 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(settings: &Settings, path: PathBuf, plugin: &Plugin) -> Result { + pub fn parse(settings: &Settings, path: PathBuf, plugin: &Plugins) -> Result { let version = plugin.parse_legacy_file(path.as_path(), settings)?; Ok(Self { - toolset: build_toolset(&path, plugin.name.as_str(), version.as_str()), + toolset: build_toolset(&path, plugin.name().as_str(), version.as_str()), path, }) } @@ -102,12 +102,13 @@ fn build_toolset(path: &Path, plugin: &str, version: &str) -> Toolset { #[cfg(test)] mod tests { use super::*; + use crate::plugins::ExternalPlugin; #[test] fn test_legacy_file() { let settings = Settings::default(); let path = PathBuf::from("tiny-legacy").join(".rtx-tiny-version"); - let plugin = Plugin::new(&settings, &PluginName::from("tiny")); + let plugin = Plugins::External(ExternalPlugin::new(&settings, &PluginName::from("tiny"))); let cf = LegacyVersionFile::parse(&settings, path, &plugin).unwrap(); let tvl = cf.to_toolset().versions.get("tiny").unwrap(); let version = match tvl.versions[0].r#type { diff --git a/src/config/mod.rs b/src/config/mod.rs index a44daa8ca..e0a15996e 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -19,7 +19,7 @@ use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; use crate::env::CI; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::{cli, dirs, duration, env, file, hook_env}; @@ -37,7 +37,7 @@ pub struct Config { pub global_config: RtxToml, pub legacy_files: IndexMap, pub config_files: ConfigMap, - pub plugins: IndexMap>, + pub plugins: IndexMap>, pub env: IndexMap, pub path_dirs: Vec, pub aliases: AliasMap, @@ -87,9 +87,9 @@ impl Config { for cf in config_files.values() { for (plugin_name, repo_url) in cf.plugins() { plugins.entry(plugin_name.clone()).or_insert_with(|| { - let mut plugin = Plugin::new(&settings, &plugin_name); + let mut plugin = ExternalPlugin::new(&settings, &plugin_name); plugin.repo_url = Some(repo_url); - Arc::new(plugin) + Arc::new(Plugins::External(plugin)) }); } } @@ -156,13 +156,13 @@ impl Config { IndexMap::new() } }; - (&plugin.name, aliases) + (plugin.name(), aliases) }) .collect(); for (plugin, plugin_aliases) in plugin_aliases { for (from, to) in plugin_aliases { aliases - .entry(plugin.clone()) + .entry(plugin.to_string()) .or_insert_with(IndexMap::new) .insert(from, to); } @@ -239,7 +239,7 @@ impl Config { } }; if let Err(err) = thread_pool.install(|| -> Result<()> { - let plugins: Vec> = self + let plugins: Vec> = self .plugins .values() .collect_vec() @@ -329,10 +329,10 @@ fn load_rtxrc() -> Result { } } -fn load_plugins(settings: &Settings) -> Result>> { - let plugins = Plugin::list(settings)? +fn load_plugins(settings: &Settings) -> Result>> { + let plugins = ExternalPlugin::list(settings)? .into_par_iter() - .map(|p| (p.name.clone(), Arc::new(p))) + .map(|p| (p.name.clone(), Arc::new(Plugins::External(p)))) .collect::>() .into_iter() .sorted_by_cached_key(|(p, _)| p.to_string()) @@ -342,7 +342,7 @@ fn load_plugins(settings: &Settings) -> Result> fn load_legacy_files( settings: &Settings, - plugins: &IndexMap>, + plugins: &IndexMap>, ) -> IndexMap { if !settings.legacy_version_file { return IndexMap::new(); @@ -355,7 +355,7 @@ fn load_legacy_files( Ok(filenames) => Some( filenames .iter() - .map(|f| (f.to_string(), plugin.name.clone())) + .map(|f| (f.to_string(), plugin.name().to_string())) .collect_vec(), ), Err(err) => { @@ -407,7 +407,7 @@ fn get_global_rtx_toml() -> PathBuf { fn load_all_config_files( settings: &Settings, config_filenames: &[PathBuf], - plugins: &IndexMap>, + plugins: &IndexMap>, legacy_filenames: &IndexMap, mut existing: IndexMap>, ) -> Result { @@ -437,7 +437,7 @@ fn parse_config_file( f: &PathBuf, settings: &Settings, legacy_filenames: &IndexMap, - plugins: &IndexMap>, + plugins: &IndexMap>, ) -> Result> { let is_trusted = config_file::is_trusted(settings, f); match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs new file mode 100644 index 000000000..ddd393cd8 --- /dev/null +++ b/src/plugins/external_plugin.rs @@ -0,0 +1,593 @@ +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::exit; +use std::time::Duration; + +use color_eyre::eyre::{eyre, Result, WrapErr}; +use console::style; +use indexmap::IndexMap; +use itertools::Itertools; +use regex::Regex; +use versions::Versioning; + +use crate::cache::CacheManager; +use crate::cmd::cmd; +use crate::config::{Config, Settings}; +use crate::env::PREFER_STALE; +use crate::errors::Error::PluginNotInstalled; +use crate::fake_asdf::get_path_with_fake_asdf; +use crate::file::display_path; +use crate::file::{remove_all, touch_dir}; +use crate::git::Git; +use crate::hash::hash_to_str; +use crate::lock_file::LockFile; +use crate::plugins::rtx_plugin_toml::RtxPluginToml; +use crate::plugins::Script::ParseLegacyFile; +use crate::plugins::{Plugin, PluginName, Script, ScriptManager}; +use crate::runtime_symlinks::is_runtime_symlink; +use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; +use crate::{dirs, file}; + +/// This represents a plugin installed to ~/.local/share/rtx/plugins +#[derive(Debug, Clone)] +pub struct ExternalPlugin { + pub name: PluginName, + pub plugin_path: PathBuf, + pub repo_url: Option, + pub repo_ref: Option, + pub toml: RtxPluginToml, + cache_path: PathBuf, + downloads_path: PathBuf, + installs_path: PathBuf, + script_man: ScriptManager, + remote_version_cache: CacheManager>, + latest_stable_cache: CacheManager>, + alias_cache: CacheManager>, + legacy_filename_cache: CacheManager>, +} + +impl ExternalPlugin { + pub fn new(settings: &Settings, name: &PluginName) -> Self { + let plugin_path = dirs::PLUGINS.join(name); + let cache_path = dirs::CACHE.join(name); + let toml_path = plugin_path.join("rtx.plugin.toml"); + let toml = RtxPluginToml::from_file(&toml_path).unwrap(); + let fresh_duration = if *PREFER_STALE { + None + } else { + Some(Duration::from_secs(60 * 60 * 24)) + }; + Self { + name: name.into(), + script_man: build_script_man(settings, name, &plugin_path), + downloads_path: dirs::DOWNLOADS.join(name), + installs_path: dirs::INSTALLS.join(name), + remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) + .with_fresh_duration(fresh_duration) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-all")), + latest_stable_cache: CacheManager::new(cache_path.join("latest_stable.msgpack.z")) + .with_fresh_duration(fresh_duration) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/latest-stable")), + alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.z")) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-aliases")), + legacy_filename_cache: CacheManager::new(cache_path.join("legacy_filenames.msgpack.z")) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), + plugin_path, + cache_path, + repo_url: None, + repo_ref: None, + toml, + } + } + + pub fn list(settings: &Settings) -> Result> { + Ok(file::dir_subdirs(&dirs::PLUGINS)? + .iter() + .map(|name| Self::new(settings, name)) + .collect()) + } + pub fn get_remote_url(&self) -> Option { + let git = Git::new(self.plugin_path.to_path_buf()); + git.get_remote_url() + } + + fn latest_stable_version(&self, settings: &Settings) -> Result> { + if let Some(latest) = self.get_latest_stable(settings)? { + Ok(Some(latest)) + } else { + self.latest_version(settings, Some("latest".into())) + } + } + + fn get_latest_stable(&self, settings: &Settings) -> Result> { + if !self.has_latest_stable_script() { + return Ok(None); + } + self.latest_stable_cache + .get_or_try_init(|| self.fetch_latest_stable(settings)) + .map_err(|err| { + eyre!( + "Failed fetching latest stable version for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err + ) + }) + .cloned() + } + + fn fetch_remote_versions(&self, settings: &Settings) -> Result> { + let result = self + .script_man + .cmd(settings, &Script::ListAll) + .stdout_capture() + .stderr_capture() + .unchecked() + .run() + .map_err(|err| { + let script = self.script_man.get_script_path(&Script::ListAll); + eyre!("Failed to run {}: {}", script.display(), err) + })?; + let stdout = String::from_utf8(result.stdout).unwrap(); + let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); + + let display_stderr = || { + if !stderr.is_empty() { + eprintln!("{stderr}"); + } + }; + if !result.status.success() { + return Err(eyre!( + "error running {}: exited with code {}\n{}", + Script::ListAll, + result.status.code().unwrap_or_default(), + stderr + ))?; + } else if settings.verbose { + display_stderr(); + } + + Ok(stdout.split_whitespace().map(|v| v.into()).collect()) + } + + fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { + let stdout = + self.script_man + .read(settings, &Script::ListLegacyFilenames, settings.verbose)?; + Ok(self.parse_legacy_filenames(&stdout)) + } + fn parse_legacy_filenames(&self, data: &str) -> Vec { + data.split_whitespace().map(|v| v.into()).collect() + } + fn fetch_latest_stable(&self, settings: &Settings) -> Result> { + let latest_stable = self + .script_man + .read(settings, &Script::LatestStable, settings.verbose)? + .trim() + .to_string(); + Ok(if latest_stable.is_empty() { + None + } else { + Some(latest_stable) + }) + } + + fn has_list_all_script(&self) -> bool { + self.script_man.script_exists(&Script::ListAll) + } + fn has_list_alias_script(&self) -> bool { + self.script_man.script_exists(&Script::ListAliases) + } + fn has_list_legacy_filenames_script(&self) -> bool { + self.script_man.script_exists(&Script::ListLegacyFilenames) + } + fn has_latest_stable_script(&self) -> bool { + self.script_man.script_exists(&Script::LatestStable) + } + fn fetch_aliases(&self, settings: &Settings) -> Result> { + let stdout = self + .script_man + .read(settings, &Script::ListAliases, settings.verbose)?; + Ok(self.parse_aliases(&stdout)) + } + fn parse_aliases(&self, data: &str) -> Vec<(String, String)> { + data.lines() + .filter_map(|line| { + let mut parts = line.split_whitespace().collect_vec(); + if parts.len() != 2 { + if !parts.is_empty() { + trace!("invalid alias line: {}", line); + } + return None; + } + Some((parts.remove(0).into(), parts.remove(0).into())) + }) + .collect() + } + + fn fetch_cached_legacy_file(&self, legacy_file: &Path) -> Result> { + let fp = self.legacy_cache_file_path(legacy_file); + if !fp.exists() || fp.metadata()?.modified()? < legacy_file.metadata()?.modified()? { + return Ok(None); + } + + Ok(Some(fs::read_to_string(fp)?.trim().into())) + } + + fn legacy_cache_file_path(&self, legacy_file: &Path) -> PathBuf { + self.cache_path + .join("legacy") + .join(hash_to_str(&legacy_file.to_string_lossy())) + .with_extension("txt") + } + + fn write_legacy_cache(&self, legacy_file: &Path, legacy_version: &str) -> Result<()> { + let fp = self.legacy_cache_file_path(legacy_file); + fs::create_dir_all(fp.parent().unwrap())?; + fs::write(fp, legacy_version)?; + Ok(()) + } + + fn get_lock(&self, force: bool) -> Result> { + let lock = if force { + None + } else { + let lock = LockFile::new(&self.plugin_path) + .with_callback(|l| { + debug!("waiting for lock on {}", display_path(l)); + }) + .lock()?; + Some(lock) + }; + Ok(lock) + } +} + +fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> ScriptManager { + let mut sm = ScriptManager::new(plugin_path.to_path_buf()) + .with_env("PATH".into(), get_path_with_fake_asdf()) + .with_env( + "RTX_DATA_DIR".into(), + dirs::ROOT.to_string_lossy().into_owned(), + ) + .with_env("__RTX_SCRIPT".into(), "1".into()) + .with_env("RTX_PLUGIN_NAME".into(), name.to_string()); + if let Some(shims_dir) = &settings.shims_dir { + let shims_dir = shims_dir.to_string_lossy().to_string(); + sm = sm.with_env("RTX_SHIMS_DIR".into(), shims_dir); + } + + sm +} + +impl PartialEq for ExternalPlugin { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl Plugin for ExternalPlugin { + fn name(&self) -> &PluginName { + &self.name + } + + fn is_installed(&self) -> bool { + self.plugin_path.exists() + } + + fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { + self.decorate_progress_bar(pr); + let repository = self + .repo_url + .as_ref() + .or_else(|| config.get_shorthands().get(&self.name)) + .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; + debug!("install {} {:?}", self.name, repository); + + let _lock = self.get_lock(force)?; + + if self.is_installed() { + self.uninstall(pr)?; + } + + let git = Git::new(self.plugin_path.to_path_buf()); + pr.set_message(format!("cloning {repository}")); + git.clone(repository)?; + if let Some(ref_) = &self.repo_ref { + pr.set_message(format!("checking out {ref_}")); + git.update(Some(ref_.to_string()))?; + } + + pr.set_message("loading plugin remote versions".into()); + if self.has_list_all_script() { + self.list_remote_versions(&config.settings)?; + } + if self.has_list_alias_script() { + pr.set_message("getting plugin aliases".into()); + self.get_aliases(&config.settings)?; + } + if self.has_list_legacy_filenames_script() { + pr.set_message("getting plugin legacy filenames".into()); + self.legacy_filenames(&config.settings)?; + } + + let sha = git.current_sha_short()?; + pr.finish_with_message(format!( + "{repository}#{}", + style(&sha).bright().yellow().for_stderr(), + )); + Ok(()) + } + + fn update(&self, gitref: Option) -> Result<()> { + let plugin_path = self.plugin_path.to_path_buf(); + if plugin_path.is_symlink() { + warn!( + "Plugin: {} is a symlink, not updating", + style(&self.name).cyan().for_stderr() + ); + return Ok(()); + } + let git = Git::new(plugin_path); + if !git.is_repo() { + warn!( + "Plugin {} is not a git repository, not updating", + style(&self.name).cyan().for_stderr() + ); + return Ok(()); + } + // TODO: asdf_run_hook "pre_plugin_update" + let (_pre, _post) = git.update(gitref)?; + // TODO: asdf_run_hook "post_plugin_update" + Ok(()) + } + + fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + if !self.is_installed() { + return Ok(()); + } + pr.set_message("uninstalling".into()); + + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", &dir.to_string_lossy())); + remove_all(dir).wrap_err_with(|| { + format!( + "Failed to remove directory {}", + style(&dir.to_string_lossy()).cyan().for_stderr() + ) + }) + }; + + rmdir(&self.downloads_path)?; + rmdir(&self.installs_path)?; + rmdir(&self.plugin_path)?; + + Ok(()) + } + + fn latest_installed_version(&self) -> Result> { + let installed_symlink = self.installs_path.join("latest"); + if installed_symlink.exists() { + let target = installed_symlink.read_link()?; + let version = target + .file_name() + .ok_or_else(|| eyre!("Invalid symlink target"))? + .to_string_lossy() + .to_string(); + Ok(Some(version)) + } else { + Ok(None) + } + } + + fn latest_version(&self, settings: &Settings, query: Option) -> Result> { + match query { + Some(query) => { + let matches = self.list_versions_matching(settings, &query)?; + let v = match matches.contains(&query) { + true => Some(query), + false => matches.last().map(|v| v.to_string()), + }; + Ok(v) + } + None => self.latest_stable_version(settings), + } + } + + fn list_installed_versions_matching(&self, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9]"; + } + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + let versions = self + .list_installed_versions()? + .iter() + .filter(|v| query_regex.is_match(v)) + .cloned() + .collect_vec(); + Ok(versions) + } + + fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9]"; + } + let version_regex = regex!( + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" + ); + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + let versions = self + .list_remote_versions(settings)? + .iter() + .filter(|v| !version_regex.is_match(v)) + .filter(|v| query_regex.is_match(v)) + .cloned() + .collect_vec(); + Ok(versions) + } + + fn list_installed_versions(&self) -> Result> { + Ok(match self.installs_path.exists() { + true => file::dir_subdirs(&self.installs_path)? + .iter() + .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) + .map(|v| Versioning::new(v).unwrap_or_default()) + .sorted() + .map(|v| v.to_string()) + .collect(), + false => vec![], + }) + } + + fn clear_remote_version_cache(&self) -> Result<()> { + self.remote_version_cache.clear()?; + self.latest_stable_cache.clear() + } + + fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { + self.remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions(settings)) + .map_err(|err| { + eyre!( + "Failed listing remote versions for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err + ) + }) + } + + fn get_aliases(&self, settings: &Settings) -> Result> { + if let Some(data) = &self.toml.list_aliases.data { + return Ok(self.parse_aliases(data).into_iter().collect()); + } + if !self.has_list_alias_script() { + return Ok(IndexMap::new()); + } + let aliases = self + .alias_cache + .get_or_try_init(|| self.fetch_aliases(settings)) + .map_err(|err| { + eyre!( + "Failed fetching aliases for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err + ) + })? + .iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(); + Ok(aliases) + } + + fn legacy_filenames(&self, settings: &Settings) -> Result> { + if let Some(data) = &self.toml.list_legacy_filenames.data { + return Ok(self.parse_legacy_filenames(data)); + } + if !self.has_list_legacy_filenames_script() { + return Ok(vec![]); + } + self.legacy_filename_cache + .get_or_try_init(|| self.fetch_legacy_filenames(settings)) + .map_err(|err| { + eyre!( + "Failed fetching legacy filenames for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err + ) + }) + .cloned() + } + + fn parse_legacy_file(&self, legacy_file: &Path, settings: &Settings) -> Result { + if let Some(cached) = self.fetch_cached_legacy_file(legacy_file)? { + return Ok(cached); + } + trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); + let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); + let legacy_version = match self.script_man.script_exists(&script) { + true => self.script_man.read(settings, &script, settings.verbose)?, + false => fs::read_to_string(legacy_file)?, + } + .trim() + .to_string(); + + self.write_legacy_cache(legacy_file, &legacy_version)?; + Ok(legacy_version) + } + + fn external_commands(&self) -> Result>> { + let command_path = self.plugin_path.join("lib/commands"); + if !self.is_installed() || !command_path.exists() { + return Ok(vec![]); + } + let mut commands = vec![]; + for command in file::dir_files(&command_path)? { + if !command.starts_with("command-") || !command.ends_with(".bash") { + continue; + } + let mut command = command + .strip_prefix("command-") + .unwrap() + .strip_suffix(".bash") + .unwrap() + .split('-') + .map(|s| s.to_string()) + .collect::>(); + command.insert(0, self.name.clone()); + commands.push(command); + } + Ok(commands) + } + + fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { + if !self.is_installed() { + return Err(PluginNotInstalled(self.name.clone()).into()); + } + let result = cmd( + self.plugin_path + .join("lib/commands") + .join(format!("command-{command}.bash")), + args, + ) + .unchecked() + .run()?; + exit(result.status.code().unwrap_or(1)); + } + + fn decorate_progress_bar(&self, pr: &mut ProgressReport) { + pr.set_style(PROG_TEMPLATE.clone()); + pr.set_prefix(format!( + "{} {} ", + style("rtx").dim().for_stderr(), + style(&self.name).cyan().for_stderr() + )); + pr.enable_steady_tick(); + } + + fn needs_autoupdate(&self, settings: &Settings) -> Result { + if settings.plugin_autoupdate_last_check_duration == Duration::ZERO || !self.is_installed() + { + return Ok(false); + } + let updated_duration = self.plugin_path.metadata()?.modified()?.elapsed()?; + Ok(updated_duration > settings.plugin_autoupdate_last_check_duration) + } + + fn autoupdate(&self, _pr: &mut ProgressReport) -> Result<()> { + trace!("autoupdate({})", self.name); + // TODO: implement + // pr.set_message("Checking for updates...".into()); + touch_dir(&self.plugin_path)?; + Ok(()) + } +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 8c0854f8a..baaf1d32e 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,597 +1,152 @@ -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::exit; -use std::time::Duration; +use std::fmt::Debug; +use std::path::Path; -use color_eyre::eyre::WrapErr; -use color_eyre::eyre::{eyre, Result}; -use console::style; +use color_eyre::eyre::Result; use indexmap::IndexMap; -use itertools::Itertools; -use regex::Regex; -use versions::Versioning; +pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; -use crate::cache::CacheManager; -use crate::cmd::cmd; use crate::config::{Config, Settings}; -use crate::env::PREFER_STALE; -use crate::errors::Error::PluginNotInstalled; -use crate::fake_asdf::get_path_with_fake_asdf; -use crate::file::{display_path, remove_all, touch_dir}; -use crate::git::Git; -use crate::hash::hash_to_str; -use crate::lock_file::LockFile; -use crate::plugins::rtx_plugin_toml::RtxPluginToml; -use crate::plugins::script_manager::Script::ParseLegacyFile; -use crate::runtime_symlinks::is_runtime_symlink; -use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; -use crate::{dirs, file}; +use crate::ui::progress_report::ProgressReport; +mod external_plugin; mod rtx_plugin_toml; mod script_manager; pub type PluginName = String; -/// This represents a plugin installed to ~/.local/share/rtx/plugins -#[derive(Debug, Clone)] -pub struct Plugin { - pub name: PluginName, - pub plugin_path: PathBuf, - pub repo_url: Option, - pub repo_ref: Option, - pub toml: RtxPluginToml, - cache_path: PathBuf, - downloads_path: PathBuf, - installs_path: PathBuf, - script_man: ScriptManager, - remote_version_cache: CacheManager>, - latest_stable_cache: CacheManager>, - alias_cache: CacheManager>, - legacy_filename_cache: CacheManager>, +pub trait Plugin: Debug + Send + Sync { + fn name(&self) -> &PluginName; + fn is_installed(&self) -> bool; + fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()>; + fn update(&self, gitref: Option) -> Result<()>; + fn uninstall(&self, pr: &ProgressReport) -> Result<()>; + fn latest_installed_version(&self) -> Result>; + fn latest_version(&self, settings: &Settings, query: Option) -> Result>; + fn list_installed_versions_matching(&self, query: &str) -> Result>; + fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result>; + fn list_installed_versions(&self) -> Result>; + fn clear_remote_version_cache(&self) -> Result<()>; + fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec>; + fn get_aliases(&self, settings: &Settings) -> Result>; + fn legacy_filenames(&self, settings: &Settings) -> Result>; + fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result; + fn external_commands(&self) -> Result>>; + fn execute_external_command(&self, command: &str, args: Vec) -> Result<()>; + fn decorate_progress_bar(&self, pr: &mut ProgressReport); + fn needs_autoupdate(&self, settings: &Settings) -> Result; + fn autoupdate(&self, _pr: &mut ProgressReport) -> Result<()>; } -impl Plugin { - pub fn new(settings: &Settings, name: &PluginName) -> Self { - let plugin_path = dirs::PLUGINS.join(name); - let cache_path = dirs::CACHE.join(name); - let toml_path = plugin_path.join("rtx.plugin.toml"); - let toml = RtxPluginToml::from_file(&toml_path).unwrap(); - let fresh_duration = if *PREFER_STALE { - None - } else { - Some(Duration::from_secs(60 * 60 * 24)) - }; - Self { - name: name.into(), - script_man: build_script_man(settings, name, &plugin_path), - downloads_path: dirs::DOWNLOADS.join(name), - installs_path: dirs::INSTALLS.join(name), - remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(fresh_duration) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-all")), - latest_stable_cache: CacheManager::new(cache_path.join("latest_stable.msgpack.z")) - .with_fresh_duration(fresh_duration) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/latest-stable")), - alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.z")) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-aliases")), - legacy_filename_cache: CacheManager::new(cache_path.join("legacy_filenames.msgpack.z")) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), - plugin_path, - cache_path, - repo_url: None, - repo_ref: None, - toml, - } - } - - pub fn list(settings: &Settings) -> Result> { - Ok(file::dir_subdirs(&dirs::PLUGINS)? - .iter() - .map(|name| Plugin::new(settings, name)) - .collect()) - } - - pub fn is_installed(&self) -> bool { - self.plugin_path.exists() - } - - pub fn get_remote_url(&self) -> Option { - let git = Git::new(self.plugin_path.to_path_buf()); - git.get_remote_url() - } - - pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { - self.decorate_progress_bar(pr); - let repository = self - .repo_url - .as_ref() - .or_else(|| config.get_shorthands().get(&self.name)) - .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; - debug!("install {} {:?}", self.name, repository); - - let _lock = self.get_lock(force)?; - - if self.is_installed() { - self.uninstall(pr)?; - } - - let git = Git::new(self.plugin_path.to_path_buf()); - pr.set_message(format!("cloning {repository}")); - git.clone(repository)?; - if let Some(ref_) = &self.repo_ref { - pr.set_message(format!("checking out {ref_}")); - git.update(Some(ref_.to_string()))?; - } +#[derive(Debug)] +pub enum Plugins { + External(ExternalPlugin), +} - pr.set_message("loading plugin remote versions".into()); - if self.has_list_all_script() { - self.list_remote_versions(&config.settings)?; +impl Plugin for Plugins { + fn name(&self) -> &PluginName { + match self { + Plugins::External(p) => p.name(), } - if self.has_list_alias_script() { - pr.set_message("getting plugin aliases".into()); - self.get_aliases(&config.settings)?; - } - if self.has_list_legacy_filenames_script() { - pr.set_message("getting plugin legacy filenames".into()); - self.legacy_filenames(&config.settings)?; - } - - let sha = git.current_sha_short()?; - pr.finish_with_message(format!( - "{repository}#{}", - style(&sha).bright().yellow().for_stderr(), - )); - Ok(()) } - pub fn update(&self, gitref: Option) -> Result<()> { - let plugin_path = self.plugin_path.to_path_buf(); - if plugin_path.is_symlink() { - warn!( - "Plugin: {} is a symlink, not updating", - style(&self.name).cyan().for_stderr() - ); - return Ok(()); - } - let git = Git::new(plugin_path); - if !git.is_repo() { - warn!( - "Plugin {} is not a git repository, not updating", - style(&self.name).cyan().for_stderr() - ); - return Ok(()); + fn is_installed(&self) -> bool { + match self { + Plugins::External(p) => p.is_installed(), } - // TODO: asdf_run_hook "pre_plugin_update" - let (_pre, _post) = git.update(gitref)?; - // TODO: asdf_run_hook "post_plugin_update" - Ok(()) } - - pub fn uninstall(&self, pr: &ProgressReport) -> Result<()> { - if !self.is_installed() { - return Ok(()); + fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { + match self { + Plugins::External(p) => p.install(config, pr, force), } - pr.set_message("uninstalling".into()); - - let rmdir = |dir: &Path| { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", &dir.to_string_lossy())); - remove_all(dir).wrap_err_with(|| { - format!( - "Failed to remove directory {}", - style(&dir.to_string_lossy()).cyan().for_stderr() - ) - }) - }; - - rmdir(&self.downloads_path)?; - rmdir(&self.installs_path)?; - rmdir(&self.plugin_path)?; - - Ok(()) } - pub fn latest_installed_version(&self) -> Result> { - let installed_symlink = self.installs_path.join("latest"); - if installed_symlink.exists() { - let target = installed_symlink.read_link()?; - let version = target - .file_name() - .ok_or_else(|| eyre!("Invalid symlink target"))? - .to_string_lossy() - .to_string(); - Ok(Some(version)) - } else { - Ok(None) + fn update(&self, gitref: Option) -> Result<()> { + match self { + Plugins::External(p) => p.update(gitref), } } - pub fn latest_version( - &self, - settings: &Settings, - query: Option, - ) -> Result> { - match query { - Some(query) => { - let matches = self.list_versions_matching(settings, &query)?; - let v = match matches.contains(&query) { - true => Some(query), - false => matches.last().map(|v| v.to_string()), - }; - Ok(v) - } - None => self.latest_stable_version(settings), + fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + match self { + Plugins::External(p) => p.uninstall(pr), } } - - fn latest_stable_version(&self, settings: &Settings) -> Result> { - if let Some(latest) = self.get_latest_stable(settings)? { - Ok(Some(latest)) - } else { - self.latest_version(settings, Some("latest".into())) + fn latest_installed_version(&self) -> Result> { + match self { + Plugins::External(p) => p.latest_installed_version(), } } - - pub fn list_installed_versions_matching(&self, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; + fn latest_version(&self, settings: &Settings, query: Option) -> Result> { + match self { + Plugins::External(p) => p.latest_version(settings, query), } - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_installed_versions()? - .iter() - .filter(|v| query_regex.is_match(v)) - .cloned() - .collect_vec(); - Ok(versions) } - - pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; + fn list_installed_versions_matching(&self, query: &str) -> Result> { + match self { + Plugins::External(p) => p.list_installed_versions_matching(query), } - let version_regex = regex!( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" - ); - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_remote_versions(settings)? - .iter() - .filter(|v| !version_regex.is_match(v)) - .filter(|v| query_regex.is_match(v)) - .cloned() - .collect_vec(); - Ok(versions) } - - pub fn list_installed_versions(&self) -> Result> { - Ok(match self.installs_path.exists() { - true => file::dir_subdirs(&self.installs_path)? - .iter() - .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) - .map(|v| Versioning::new(v).unwrap_or_default()) - .sorted() - .map(|v| v.to_string()) - .collect(), - false => vec![], - }) - } - - pub fn clear_remote_version_cache(&self) -> Result<()> { - self.remote_version_cache.clear()?; - self.latest_stable_cache.clear() - } - pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { - self.remote_version_cache - .get_or_try_init(|| self.fetch_remote_versions(settings)) - .map_err(|err| { - eyre!( - "Failed listing remote versions for plugin {}: {}", - style(&self.name).cyan().for_stderr(), - err - ) - }) - } - - pub fn get_aliases(&self, settings: &Settings) -> Result> { - if let Some(data) = &self.toml.list_aliases.data { - return Ok(self.parse_aliases(data).into_iter().collect()); + fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { + match self { + Plugins::External(p) => p.list_versions_matching(settings, query), } - if !self.has_list_alias_script() { - return Ok(IndexMap::new()); - } - let aliases = self - .alias_cache - .get_or_try_init(|| self.fetch_aliases(settings)) - .map_err(|err| { - eyre!( - "Failed fetching aliases for plugin {}: {}", - style(&self.name).cyan().for_stderr(), - err - ) - })? - .iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect(); - Ok(aliases) } - - pub fn legacy_filenames(&self, settings: &Settings) -> Result> { - if let Some(data) = &self.toml.list_legacy_filenames.data { - return Ok(self.parse_legacy_filenames(data)); + fn list_installed_versions(&self) -> Result> { + match self { + Plugins::External(p) => p.list_installed_versions(), } - if !self.has_list_legacy_filenames_script() { - return Ok(vec![]); - } - self.legacy_filename_cache - .get_or_try_init(|| self.fetch_legacy_filenames(settings)) - .map_err(|err| { - eyre!( - "Failed fetching legacy filenames for plugin {}: {}", - style(&self.name).cyan().for_stderr(), - err - ) - }) - .cloned() } - fn get_latest_stable(&self, settings: &Settings) -> Result> { - if !self.has_latest_stable_script() { - return Ok(None); + fn clear_remote_version_cache(&self) -> Result<()> { + match self { + Plugins::External(p) => p.clear_remote_version_cache(), } - self.latest_stable_cache - .get_or_try_init(|| self.fetch_latest_stable(settings)) - .map_err(|err| { - eyre!( - "Failed fetching latest stable version for plugin {}: {}", - style(&self.name).cyan().for_stderr(), - err - ) - }) - .cloned() } - - pub fn external_commands(&self) -> Result>> { - let command_path = self.plugin_path.join("lib/commands"); - if !self.is_installed() || !command_path.exists() { - return Ok(vec![]); + fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { + match self { + Plugins::External(p) => p.list_remote_versions(settings), } - let mut commands = vec![]; - for command in file::dir_files(&command_path)? { - if !command.starts_with("command-") || !command.ends_with(".bash") { - continue; - } - let mut command = command - .strip_prefix("command-") - .unwrap() - .strip_suffix(".bash") - .unwrap() - .split('-') - .map(|s| s.to_string()) - .collect::>(); - command.insert(0, self.name.clone()); - commands.push(command); - } - Ok(commands) } - - pub fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { - if !self.is_installed() { - return Err(PluginNotInstalled(self.name.clone()).into()); + fn get_aliases(&self, settings: &Settings) -> Result> { + match self { + Plugins::External(p) => p.get_aliases(settings), } - let result = cmd( - self.plugin_path - .join("lib/commands") - .join(format!("command-{command}.bash")), - args, - ) - .unchecked() - .run()?; - exit(result.status.code().unwrap_or(1)); } - - pub fn decorate_progress_bar(&self, pr: &mut ProgressReport) { - pr.set_style(PROG_TEMPLATE.clone()); - pr.set_prefix(format!( - "{} {} ", - style("rtx").dim().for_stderr(), - style(&self.name).cyan().for_stderr() - )); - pr.enable_steady_tick(); - } - - pub fn needs_autoupdate(&self, settings: &Settings) -> Result { - if settings.plugin_autoupdate_last_check_duration == Duration::ZERO || !self.is_installed() - { - return Ok(false); + fn legacy_filenames(&self, settings: &Settings) -> Result> { + match self { + Plugins::External(p) => p.legacy_filenames(settings), } - let updated_duration = self.plugin_path.metadata()?.modified()?.elapsed()?; - Ok(updated_duration > settings.plugin_autoupdate_last_check_duration) - } - - pub fn autoupdate(&self, _pr: &mut ProgressReport) -> Result<()> { - trace!("autoupdate({})", self.name); - // TODO: implement - // pr.set_message("Checking for updates...".into()); - touch_dir(&self.plugin_path)?; - Ok(()) } - - fn fetch_remote_versions(&self, settings: &Settings) -> Result> { - let result = self - .script_man - .cmd(settings, &Script::ListAll) - .stdout_capture() - .stderr_capture() - .unchecked() - .run() - .map_err(|err| { - let script = self.script_man.get_script_path(&Script::ListAll); - eyre!("Failed to run {}: {}", script.display(), err) - })?; - let stdout = String::from_utf8(result.stdout).unwrap(); - let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); - - let display_stderr = || { - if !stderr.is_empty() { - eprintln!("{stderr}"); - } - }; - if !result.status.success() { - return Err(eyre!( - "error running {}: exited with code {}\n{}", - Script::ListAll, - result.status.code().unwrap_or_default(), - stderr - ))?; - } else if settings.verbose { - display_stderr(); + fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result { + match self { + Plugins::External(p) => p.parse_legacy_file(path, settings), } - - Ok(stdout.split_whitespace().map(|v| v.into()).collect()) - } - - fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { - let stdout = - self.script_man - .read(settings, &Script::ListLegacyFilenames, settings.verbose)?; - Ok(self.parse_legacy_filenames(&stdout)) - } - fn parse_legacy_filenames(&self, data: &str) -> Vec { - data.split_whitespace().map(|v| v.into()).collect() - } - fn fetch_latest_stable(&self, settings: &Settings) -> Result> { - let latest_stable = self - .script_man - .read(settings, &Script::LatestStable, settings.verbose)? - .trim() - .to_string(); - Ok(if latest_stable.is_empty() { - None - } else { - Some(latest_stable) - }) - } - - fn has_list_all_script(&self) -> bool { - self.script_man.script_exists(&Script::ListAll) - } - fn has_list_alias_script(&self) -> bool { - self.script_man.script_exists(&Script::ListAliases) - } - fn has_list_legacy_filenames_script(&self) -> bool { - self.script_man.script_exists(&Script::ListLegacyFilenames) - } - fn has_latest_stable_script(&self) -> bool { - self.script_man.script_exists(&Script::LatestStable) - } - fn fetch_aliases(&self, settings: &Settings) -> Result> { - let stdout = self - .script_man - .read(settings, &Script::ListAliases, settings.verbose)?; - Ok(self.parse_aliases(&stdout)) - } - fn parse_aliases(&self, data: &str) -> Vec<(String, String)> { - data.lines() - .filter_map(|line| { - let mut parts = line.split_whitespace().collect_vec(); - if parts.len() != 2 { - if !parts.is_empty() { - trace!("invalid alias line: {}", line); - } - return None; - } - Some((parts.remove(0).into(), parts.remove(0).into())) - }) - .collect() } - - pub fn parse_legacy_file(&self, legacy_file: &Path, settings: &Settings) -> Result { - if let Some(cached) = self.fetch_cached_legacy_file(legacy_file)? { - return Ok(cached); - } - trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); - let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); - let legacy_version = match self.script_man.script_exists(&script) { - true => self.script_man.read(settings, &script, settings.verbose)?, - false => fs::read_to_string(legacy_file)?, + fn external_commands(&self) -> Result>> { + match self { + Plugins::External(p) => p.external_commands(), } - .trim() - .to_string(); - - self.write_legacy_cache(legacy_file, &legacy_version)?; - Ok(legacy_version) } - - fn fetch_cached_legacy_file(&self, legacy_file: &Path) -> Result> { - let fp = self.legacy_cache_file_path(legacy_file); - if !fp.exists() || fp.metadata()?.modified()? < legacy_file.metadata()?.modified()? { - return Ok(None); + fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { + match self { + Plugins::External(p) => p.execute_external_command(command, args), } - - Ok(Some(fs::read_to_string(fp)?.trim().into())) - } - - fn legacy_cache_file_path(&self, legacy_file: &Path) -> PathBuf { - self.cache_path - .join("legacy") - .join(hash_to_str(&legacy_file.to_string_lossy())) - .with_extension("txt") - } - - fn write_legacy_cache(&self, legacy_file: &Path, legacy_version: &str) -> Result<()> { - let fp = self.legacy_cache_file_path(legacy_file); - fs::create_dir_all(fp.parent().unwrap())?; - fs::write(fp, legacy_version)?; - Ok(()) } - - fn get_lock(&self, force: bool) -> Result> { - let lock = if force { - None - } else { - let lock = LockFile::new(&self.plugin_path) - .with_callback(|l| { - debug!("waiting for lock on {}", display_path(l)); - }) - .lock()?; - Some(lock) - }; - Ok(lock) + fn decorate_progress_bar(&self, pr: &mut ProgressReport) { + match self { + Plugins::External(p) => p.decorate_progress_bar(pr), + } } -} - -fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> ScriptManager { - let mut sm = ScriptManager::new(plugin_path.to_path_buf()) - .with_env("PATH".into(), get_path_with_fake_asdf()) - .with_env( - "RTX_DATA_DIR".into(), - dirs::ROOT.to_string_lossy().into_owned(), - ) - .with_env("__RTX_SCRIPT".into(), "1".into()) - .with_env("RTX_PLUGIN_NAME".into(), name.to_string()); - if let Some(shims_dir) = &settings.shims_dir { - let shims_dir = shims_dir.to_string_lossy().to_string(); - sm = sm.with_env("RTX_SHIMS_DIR".into(), shims_dir); + fn needs_autoupdate(&self, settings: &Settings) -> Result { + match self { + Plugins::External(p) => p.needs_autoupdate(settings), + } } - - sm -} - -impl PartialEq for Plugin { - fn eq(&self, other: &Self) -> bool { - self.name == other.name + fn autoupdate(&self, pr: &mut ProgressReport) -> Result<()> { + match self { + Plugins::External(p) => p.autoupdate(pr), + } } } @@ -600,6 +155,7 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::assert_cli; + use crate::config::Settings; use super::*; @@ -607,7 +163,7 @@ mod tests { fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); - let plugin = Plugin::new(&settings, &PluginName::from("tiny")); + let plugin = ExternalPlugin::new(&settings, &PluginName::from("tiny")); let version = plugin .latest_version(&settings, Some("1.0.0".into())) .unwrap() @@ -620,7 +176,7 @@ mod tests { #[test] fn test_latest_stable() { let settings = Settings::default(); - let plugin = Plugin::new(&settings, &PluginName::from("dummy")); + let plugin = ExternalPlugin::new(&settings, &PluginName::from("dummy")); let version = plugin.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index bd9b3899f..1b9194eea 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -9,13 +9,13 @@ use itertools::Itertools; use regex::Regex; use versions::Version; -use crate::plugins::Plugin; +use crate::plugins::{Plugin, Plugins}; pub fn rebuild_symlinks(config: &Config) -> Result<()> { for plugin in config.plugins.values() { remove_existing_symlinks(plugin)?; let symlinks = list_symlinks(config, plugin)?; - let installs_dir = dirs::INSTALLS.join(&plugin.name); + let installs_dir = dirs::INSTALLS.join(plugin.name()); for (from, to) in symlinks { let from = installs_dir.join(from); if from.exists() { @@ -27,7 +27,7 @@ pub fn rebuild_symlinks(config: &Config) -> Result<()> { Ok(()) } -fn list_symlinks(config: &Config, plugin: &Plugin) -> Result> { +fn list_symlinks(config: &Config, plugin: &Plugins) -> Result> { let mut symlinks = IndexMap::new(); let rel_path = |x: &String| PathBuf::from(".").join(x.clone()); for v in installed_versions(plugin)? { @@ -46,7 +46,7 @@ fn list_symlinks(config: &Config, plugin: &Plugin) -> Result Result Result> { +fn installed_versions(plugin: &dyn Plugin) -> Result> { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let versions = plugin .list_installed_versions()? @@ -75,8 +75,8 @@ fn installed_versions(plugin: &Plugin) -> Result> { Ok(versions) } -fn remove_existing_symlinks(plugin: &Plugin) -> Result<()> { - let installs_dir = dirs::INSTALLS.join(&plugin.name); +fn remove_existing_symlinks(plugin: &Plugins) -> Result<()> { + let installs_dir = dirs::INSTALLS.join(plugin.name()); if !installs_dir.exists() { return Ok(()); } @@ -103,14 +103,17 @@ mod tests { use insta::assert_debug_snapshot; use crate::config::Config; - use crate::plugins::PluginName; + use crate::plugins::{ExternalPlugin, PluginName}; use super::*; #[test] fn test_list_symlinks() { let config = Config::load().unwrap(); - let plugin = Plugin::new(&config.settings, &PluginName::from("tiny")); + let plugin = Plugins::External(ExternalPlugin::new( + &config.settings, + &PluginName::from("tiny"), + )); let symlinks = list_symlinks(&config, &plugin).unwrap(); assert_debug_snapshot!(symlinks); } diff --git a/src/runtimes.rs b/src/runtimes.rs index e7f2ead11..c220e38d8 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -17,7 +17,7 @@ use crate::file::{create_dir_all, display_path, remove_all_with_warning}; use crate::hash::hash_to_str; use crate::lock_file::LockFile; use crate::plugins::Script::{Download, ExecEnv, Install}; -use crate::plugins::{Plugin, Script, ScriptManager}; +use crate::plugins::{Plugin, Plugins, Script, ScriptManager}; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolVersion, ToolVersionType}; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; @@ -28,7 +28,7 @@ use crate::{dirs, env, fake_asdf, file}; #[derive(Debug, Clone)] pub struct RuntimeVersion { pub version: String, - pub plugin: Arc, + pub plugin: Arc, pub install_path: PathBuf, download_path: PathBuf, cache_path: PathBuf, @@ -38,24 +38,24 @@ pub struct RuntimeVersion { } impl RuntimeVersion { - pub fn new(config: &Config, plugin: Arc, version: String, tv: ToolVersion) -> Self { + pub fn new(config: &Config, plugin: Arc, version: String, tv: ToolVersion) -> Self { let install_path = match &tv.r#type { ToolVersionType::Path(p) => p.clone(), - _ => dirs::INSTALLS.join(&plugin.name).join(&version), + _ => dirs::INSTALLS.join(plugin.name()).join(&version), }; let download_path = match &tv.r#type { ToolVersionType::Path(p) => p.clone(), - _ => dirs::DOWNLOADS.join(&plugin.name).join(&version), + _ => dirs::DOWNLOADS.join(plugin.name()).join(&version), }; let cache_path = match &tv.r#type { - ToolVersionType::Path(p) => dirs::CACHE.join(&plugin.name).join(hash_to_str(&p)), - _ => dirs::CACHE.join(&plugin.name).join(&version), + ToolVersionType::Path(p) => dirs::CACHE.join(plugin.name()).join(hash_to_str(&p)), + _ => dirs::CACHE.join(plugin.name()).join(&version), }; let script_man = build_script_man( config, &tv, &version, - &plugin.plugin_path, + &plugin, &install_path, &download_path, ); @@ -79,44 +79,52 @@ impl RuntimeVersion { fn list_bin_paths_cache( config: &Config, tv: &ToolVersion, - plugin: &Arc, + plugin: &Arc, install_path: &Path, cache_path: &Path, ) -> Result>> { - let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key { - Some(key) => { - let key = render_cache_key(config, tv, key)?; - let filename = format!("{}.msgpack.z", key); - cache_path.join("list_bin_paths").join(filename) + match plugin.as_ref() { + Plugins::External(plugin) => { + let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key { + Some(key) => { + let key = render_cache_key(config, tv, key)?; + let filename = format!("{}.msgpack.z", key); + cache_path.join("list_bin_paths").join(filename) + } + None => cache_path.join("list_bin_paths.msgpack.z"), + }; + let cm = CacheManager::new(list_bin_paths_filename) + .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(plugin.plugin_path.clone()) + .with_fresh_file(install_path.to_path_buf()); + Ok(cm) } - None => cache_path.join("list_bin_paths.msgpack.z"), - }; - let cm = CacheManager::new(list_bin_paths_filename) - .with_fresh_file(dirs::ROOT.clone()) - .with_fresh_file(plugin.plugin_path.clone()) - .with_fresh_file(install_path.to_path_buf()); - Ok(cm) + } } fn exec_env_cache( config: &Config, tv: &ToolVersion, - plugin: &Arc, + plugin: &Arc, install_path: &Path, cache_path: &Path, ) -> Result>> { - let exec_env_filename = match &plugin.toml.exec_env.cache_key { - Some(key) => { - let key = render_cache_key(config, tv, key)?; - let filename = format!("{}.msgpack.z", key); - cache_path.join("exec_env").join(filename) + match plugin.as_ref() { + Plugins::External(plugin) => { + let exec_env_filename = match &plugin.toml.exec_env.cache_key { + Some(key) => { + let key = render_cache_key(config, tv, key)?; + let filename = format!("{}.msgpack.z", key); + cache_path.join("exec_env").join(filename) + } + None => cache_path.join("exec_env.msgpack.z"), + }; + let cm = CacheManager::new(exec_env_filename) + .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(plugin.plugin_path.clone()) + .with_fresh_file(install_path.to_path_buf()); + Ok(cm) } - None => cache_path.join("exec_env.msgpack.z"), - }; - let cm = CacheManager::new(exec_env_filename) - .with_fresh_file(dirs::ROOT.clone()) - .with_fresh_file(plugin.plugin_path.clone()) - .with_fresh_file(install_path.to_path_buf()); - Ok(cm) + } } pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { @@ -201,8 +209,11 @@ impl RuntimeVersion { pub fn uninstall(&self, settings: &Settings, pr: &ProgressReport, dryrun: bool) -> Result<()> { pr.set_message(format!("uninstall {}", self)); - if self.plugin.plugin_path.join("bin/uninstall").exists() { - self.script_man.run(settings, &Script::Uninstall)?; + #[allow(irrefutable_let_patterns)] + if let Plugins::External(plugin) = self.plugin.as_ref() { + if plugin.plugin_path.join("bin/uninstall").exists() { + self.script_man.run(settings, &Script::Uninstall)?; + } } let rmdir = |dir: &Path| { if !dir.exists() { @@ -245,23 +256,27 @@ impl RuntimeVersion { } fn fetch_bin_paths(&self, settings: &Settings) -> Result> { - let list_bin_paths = self.plugin.plugin_path.join("bin/list-bin-paths"); - let bin_paths = if self.version == "system" { - Vec::new() - } else if list_bin_paths.exists() { - let output = self - .script_man - .cmd(settings, &Script::ListBinPaths) - .read()?; - output.split_whitespace().map(|f| f.to_string()).collect() - } else { - vec!["bin".into()] - }; - let bin_paths = bin_paths - .into_iter() - .map(|path| self.install_path.join(path)) - .collect(); - Ok(bin_paths) + match self.plugin.as_ref() { + Plugins::External(plugin) => { + let list_bin_paths = plugin.plugin_path.join("bin/list-bin-paths"); + let bin_paths = if self.version == "system" { + Vec::new() + } else if list_bin_paths.exists() { + let output = self + .script_man + .cmd(settings, &Script::ListBinPaths) + .read()?; + output.split_whitespace().map(|f| f.to_string()).collect() + } else { + vec!["bin".into()] + }; + let bin_paths = bin_paths + .into_iter() + .map(|path| self.install_path.join(path)) + .collect(); + Ok(bin_paths) + } + } } fn create_install_dirs(&self) -> Result<()> { @@ -318,13 +333,13 @@ impl RuntimeVersion { impl Display for RuntimeVersion { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}@{}", self.plugin.name, self.version) + write!(f, "{}@{}", self.plugin.name(), self.version) } } impl PartialEq for RuntimeVersion { fn eq(&self, other: &Self) -> bool { - self.plugin.name == other.plugin.name && self.version == other.version + self.plugin.name() == other.plugin.name() && self.version == other.version } } @@ -332,11 +347,14 @@ fn build_script_man( config: &Config, tv: &ToolVersion, version: &str, - plugin_path: &Path, + plugin: &Plugins, install_path: &Path, download_path: &Path, ) -> ScriptManager { - let mut sm = ScriptManager::new(plugin_path.to_path_buf()) + let plugin_path = match plugin { + Plugins::External(plugin) => plugin.plugin_path.clone(), + }; + let mut sm = ScriptManager::new(plugin_path.clone()) .with_envs(env::PRISTINE_ENV.clone()) .with_env("PATH".into(), fake_asdf::get_path_with_fake_asdf()) .with_env( diff --git a/src/shims.rs b/src/shims.rs index 08e61462d..884ee462d 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -16,6 +16,7 @@ use crate::fake_asdf; use crate::file::{create_dir_all, remove_all}; use crate::lock_file::LockFile; use crate::output::Output; +use crate::plugins::{Plugin, Plugins}; use crate::runtimes::RuntimeVersion; use crate::toolset::{Toolset, ToolsetBuilder}; use crate::{dirs, file}; @@ -117,18 +118,20 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { } } for plugin in config.plugins.values() { - match plugin.plugin_path.join("shims").read_dir() { - Ok(files) => { - for bin in files { - let bin = bin?; - let bin_name = bin.file_name().into_string().unwrap(); - let symlink_path = shims_dir.join(bin_name); - make_shim(&bin.path(), &symlink_path)?; + match plugin.as_ref() { + Plugins::External(plugin) => match plugin.plugin_path.join("shims").read_dir() { + Ok(files) => { + for bin in files { + let bin = bin?; + let bin_name = bin.file_name().into_string().unwrap(); + let symlink_path = shims_dir.join(bin_name); + make_shim(&bin.path(), &symlink_path)?; + } } - } - Err(_) => { - continue; - } + Err(_) => { + continue; + } + }, } } @@ -169,7 +172,11 @@ fn err_no_version_set(bin_name: &str, rtvs: Vec) -> Result<()> { let mut msg = format!("No version is set for shim: {}\n", bin_name); msg.push_str("Set a global default version with one of the following:\n"); for rtv in rtvs { - msg.push_str(&format!("rtx global {}@{}\n", rtv.plugin.name, rtv.version)); + msg.push_str(&format!( + "rtx global {}@{}\n", + rtv.plugin.name(), + rtv.version + )); } Err(eyre!(msg.trim().to_string())) } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 601649d78..b8ae3aaaa 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -22,7 +22,7 @@ pub use tool_version_list::ToolVersionList; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; use crate::runtime_symlinks::rebuild_symlinks; use crate::runtimes::RuntimeVersion; use crate::shims::reshim; @@ -182,10 +182,12 @@ impl Toolset { mpr: &MultiProgressReport, ) -> Result<()> { for plugin in &missing_plugins { - config - .plugins - .entry(plugin.clone()) - .or_insert_with(|| Arc::new(Plugin::new(&config.settings, plugin))); + config.plugins.entry(plugin.clone()).or_insert_with(|| { + Arc::new(Plugins::External(ExternalPlugin::new( + &config.settings, + plugin, + ))) + }); } config.plugins.sort_keys(); missing_plugins @@ -218,7 +220,8 @@ impl Toolset { .map(|p| { let versions = p.list_installed_versions()?; Ok(versions.into_iter().map(|v| { - let tv = ToolVersion::new(p.name.clone(), ToolVersionType::Version(v.clone())); + let tv = + ToolVersion::new(p.name().clone(), ToolVersionType::Version(v.clone())); RuntimeVersion::new(config, p.clone(), v, tv) })) }) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 7bd343a81..1839f32a3 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -10,7 +10,7 @@ use versions::{Chunk, Version}; use crate::config::Config; use crate::dirs; -use crate::plugins::Plugin; +use crate::plugins::{Plugin, Plugins}; use crate::runtime_symlinks::is_runtime_symlink; use crate::runtimes::RuntimeVersion; use crate::ui::progress_report::ProgressReport; @@ -46,7 +46,7 @@ impl ToolVersion { pub fn resolve( &mut self, config: &Config, - plugin: Arc, + plugin: Arc, latest_versions: bool, ) -> Result<()> { if self.rtv.is_none() { @@ -66,11 +66,11 @@ impl ToolVersion { fn resolve_version( &self, config: &Config, - plugin: Arc, + plugin: Arc, v: &str, latest_versions: bool, ) -> Result { - let v = config.resolve_alias(&plugin.name, v)?; + let v = config.resolve_alias(plugin.name(), v)?; match v.split_once(':') { Some(("ref", r)) => { return self.resolve_ref(config, plugin, r); @@ -84,7 +84,7 @@ impl ToolVersion { _ => (), } - let existing_path = dirs::INSTALLS.join(&plugin.name).join(&v); + let existing_path = dirs::INSTALLS.join(plugin.name()).join(&v); if existing_path.exists() && !is_runtime_symlink(&existing_path) { // if the version is already installed, no need to fetch all the remote versions return Ok(self.build_rtv(config, plugin, &v)); @@ -122,13 +122,13 @@ impl ToolVersion { fn resolve_bang( &self, config: &Config, - plugin: Arc, + plugin: Arc, v: &str, ) -> Result> { let (wanted, minus) = v.split_once("!-").unwrap(); let wanted = match wanted { "latest" => plugin.latest_version(&config.settings, None)?.unwrap(), - _ => config.resolve_alias(&plugin.name, wanted)?, + _ => config.resolve_alias(plugin.name(), wanted)?, }; let wanted = version_sub(&wanted, minus); match plugin.latest_version(&config.settings, Some(wanted))? { @@ -140,7 +140,7 @@ impl ToolVersion { fn resolve_prefix( &self, config: &Config, - plugin: Arc, + plugin: Arc, prefix: &str, ) -> Result { let matches = plugin.list_versions_matching(&config.settings, prefix)?; @@ -152,21 +152,26 @@ impl ToolVersion { Ok(self.build_rtv(config, plugin, v)) } - fn resolve_ref(&self, config: &Config, plugin: Arc, r: &str) -> Result { + fn resolve_ref( + &self, + config: &Config, + plugin: Arc, + r: &str, + ) -> Result { Ok(self.build_rtv(config, plugin, &format!("ref-{}", r))) } fn resolve_path( &self, config: &Config, - plugin: Arc, + plugin: Arc, path: &PathBuf, ) -> Result { let path = fs::canonicalize(path)?; Ok(self.build_rtv(config, plugin, &path.display().to_string())) } - pub fn resolve_system(&self, config: &Config, plugin: Arc) -> RuntimeVersion { + pub fn resolve_system(&self, config: &Config, plugin: Arc) -> RuntimeVersion { self.build_rtv(config, plugin, "system") } @@ -187,7 +192,7 @@ impl ToolVersion { } } - fn build_rtv(&self, config: &Config, plugin: Arc, v: &str) -> RuntimeVersion { + fn build_rtv(&self, config: &Config, plugin: Arc, v: &str) -> RuntimeVersion { RuntimeVersion::new(config, plugin, v.to_string(), self.clone()) } } diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index ce17e4b7a..f91a62940 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use crate::config::Config; -use crate::plugins::Plugin; +use crate::plugins::Plugins; use crate::runtimes::RuntimeVersion; use crate::toolset::{ToolSource, ToolVersion}; @@ -22,7 +22,7 @@ impl ToolVersionList { pub fn add_version(&mut self, version: ToolVersion) { self.versions.push(version); } - pub fn resolve(&mut self, config: &Config, plugin: Arc, latest_versions: bool) { + pub fn resolve(&mut self, config: &Config, plugin: Arc, latest_versions: bool) { for tv in &mut self.versions { if let Err(err) = tv.resolve(config, plugin.clone(), latest_versions) { warn!("failed to resolve tool version: {:#}", err); @@ -43,7 +43,7 @@ mod tests { use std::sync::Arc; use crate::config::Config; - use crate::plugins::{Plugin, PluginName}; + use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType}; #[test] @@ -51,10 +51,13 @@ mod tests { env::set_var("RTX_FAILURE", "1"); let mut tvl = ToolVersionList::new(ToolSource::Argument); let settings = crate::config::Settings::default(); - let plugin = Arc::new(Plugin::new(&settings, &PluginName::from("dummy"))); + let plugin = Arc::new(Plugins::External(ExternalPlugin::new( + &settings, + &PluginName::from("dummy"), + ))); plugin.clear_remote_version_cache().unwrap(); tvl.add_version(ToolVersion::new( - plugin.name.to_string(), + plugin.name().to_string(), ToolVersionType::Version("1.0.0".to_string()), )); tvl.resolve(&Config::default(), plugin, false); From a69244b077370e7c6592e05d626a551e91bb0f1d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 30 Mar 2023 20:26:53 -0500 Subject: [PATCH 0641/1891] chore: Release rtx-cli version 1.27.10 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 8 +++++--- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2238a2fc6..e86fd013d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1592,7 +1592,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.27.9" +version = "1.27.10" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index cdf83d879..1ac023b2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.27.9" +version = "1.27.10" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 3e4b19e16..fce884a5a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.27.9 +rtx 1.27.10 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.9/rtx-v1.27.9-linux-x64 | tar -xJv +curl https://github.com/jdxcode/rtx/releases/download/v1.27.10/rtx-v1.27.10-linux-x64 | tar -xJv mv rtx/bin/rtx /usr/local/bin ``` diff --git a/default.nix b/default.nix index 7dac31583..0752c2444 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.27.9"; + version = "1.27.10"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 4bc16ddce..a21aa4a51 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.27.9" +.TH rtx 1 "rtx 1.27.10" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.27.9 +v1.27.10 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 37b62b837..f6c1adbc9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.27.9 +Version: 1.27.10 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 43301c336..e4e22e7bd 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 634] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 636] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -146,7 +146,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 634] = [ ("djinni", "https://github.com/cross-language-cpp/asdf-djinni.git"), ("dmd", "https://github.com/sylph01/asdf-dmd.git"), ("docker-compose-v1", "https://github.com/kompiro/asdf-docker-compose-v1"), - ("docker-slim", "https://github.com/everpeace/asdf-docker-slim.git"), + ("docker-slim", "https://github.com/xataz/asdf-docker-slim.git"), ("dockle", "https://github.com/mathew-fleisch/asdf-dockle.git"), ("doctl", "https://github.com/maristgeek/asdf-doctl.git"), ("doctoolchain", "https://github.com/joschi/asdf-doctoolchain"), @@ -319,7 +319,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 634] = [ ("kompose", "https://github.com/technikhil314/asdf-kompose.git"), ("kops", "https://github.com/Antiarchitect/asdf-kops.git"), ("kotlin", "https://github.com/asdf-community/asdf-kotlin.git"), - ("kpack-cli", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), + ("kp", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("kpt", "https://github.com/nlamirault/asdf-kpt.git"), ("krab", "https://github.com/ohkrab/asdf-krab.git"), ("krew", "https://github.com/jimmidyson/asdf-krew.git"), @@ -542,7 +542,9 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 634] = [ ("swiprolog", "https://github.com/mracos/asdf-swiprolog.git"), ("syft", "https://github.com/davidgp1701/asdf-syft.git"), ("syncher", "https://github.com/nwillc/syncher.git"), + ("talhelper", "https://github.com/bjw-s/asdf-talhelper"), ("talos", "https://github.com/particledecay/asdf-talos.git"), + ("talosctl", "https://github.com/bjw-s/asdf-talosctl"), ("tanka", "https://github.com/trotttrotttrott/asdf-tanka.git"), ("task", "https://github.com/particledecay/asdf-task.git"), ("tctl", "https://github.com/eko/asdf-tctl.git"), From 4cf44d1106a0d0f19785e25e48971f081978bfb4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 30 Mar 2023 21:02:39 -0500 Subject: [PATCH 0642/1891] removed unused autoupdate stub --- src/config/mod.rs | 44 ---------------------------------- src/plugins/external_plugin.rs | 19 +-------------- src/plugins/mod.rs | 12 ---------- 3 files changed, 1 insertion(+), 74 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index e0a15996e..91fbfd6bf 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -10,7 +10,6 @@ use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::OnceCell; use rayon::prelude::*; -use rayon::ThreadPoolBuilder; pub use settings::{MissingRuntimeBehavior, Settings}; @@ -21,7 +20,6 @@ use crate::config::tracking::Tracker; use crate::env::CI; use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; use crate::shorthands::{get_shorthands, Shorthands}; -use crate::ui::multi_progress_report::MultiProgressReport; use crate::{cli, dirs, duration, env, file, hook_env}; pub mod config_file; @@ -228,48 +226,6 @@ impl Config { return; } self.check_for_new_version(); - let thread_pool = match ThreadPoolBuilder::new() - .num_threads(self.settings.jobs) - .build() - { - Ok(thread_pool) => thread_pool, - Err(err) => { - warn!("Error building thread pool: {:#}", err); - return; - } - }; - if let Err(err) = thread_pool.install(|| -> Result<()> { - let plugins: Vec> = self - .plugins - .values() - .collect_vec() - .into_par_iter() - .filter(|p| match p.needs_autoupdate(&self.settings) { - Ok(should_autoupdate) => should_autoupdate, - Err(err) => { - debug!("Error checking for autoupdate: {:#}", err); - false - } - }) - .cloned() - .collect(); - if plugins.is_empty() { - return Ok(()); - } - let mpr = MultiProgressReport::new(self.settings.verbose); - plugins - .into_par_iter() - .map(|plugin| { - let mut pr = mpr.add(); - plugin.autoupdate(&mut pr)?; - pr.clear(); - Ok(()) - }) - .collect::>()?; - Ok(()) - }) { - warn!("Error autoupdating: {:#}", err); - } } pub fn check_for_new_version(&self) { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ddd393cd8..98b650b36 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -17,7 +17,7 @@ use crate::env::PREFER_STALE; use crate::errors::Error::PluginNotInstalled; use crate::fake_asdf::get_path_with_fake_asdf; use crate::file::display_path; -use crate::file::{remove_all, touch_dir}; +use crate::file::remove_all; use crate::git::Git; use crate::hash::hash_to_str; use crate::lock_file::LockFile; @@ -573,21 +573,4 @@ impl Plugin for ExternalPlugin { )); pr.enable_steady_tick(); } - - fn needs_autoupdate(&self, settings: &Settings) -> Result { - if settings.plugin_autoupdate_last_check_duration == Duration::ZERO || !self.is_installed() - { - return Ok(false); - } - let updated_duration = self.plugin_path.metadata()?.modified()?.elapsed()?; - Ok(updated_duration > settings.plugin_autoupdate_last_check_duration) - } - - fn autoupdate(&self, _pr: &mut ProgressReport) -> Result<()> { - trace!("autoupdate({})", self.name); - // TODO: implement - // pr.set_message("Checking for updates...".into()); - touch_dir(&self.plugin_path)?; - Ok(()) - } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index baaf1d32e..9a68696d6 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -35,8 +35,6 @@ pub trait Plugin: Debug + Send + Sync { fn external_commands(&self) -> Result>>; fn execute_external_command(&self, command: &str, args: Vec) -> Result<()>; fn decorate_progress_bar(&self, pr: &mut ProgressReport); - fn needs_autoupdate(&self, settings: &Settings) -> Result; - fn autoupdate(&self, _pr: &mut ProgressReport) -> Result<()>; } #[derive(Debug)] @@ -138,16 +136,6 @@ impl Plugin for Plugins { Plugins::External(p) => p.decorate_progress_bar(pr), } } - fn needs_autoupdate(&self, settings: &Settings) -> Result { - match self { - Plugins::External(p) => p.needs_autoupdate(settings), - } - } - fn autoupdate(&self, pr: &mut ProgressReport) -> Result<()> { - match self { - Plugins::External(p) => p.autoupdate(pr), - } - } } #[cfg(test)] From ac0cfec7f222cf460abd6fef466e5d07bf5190ed Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 31 Mar 2023 13:09:21 -0500 Subject: [PATCH 0643/1891] move external plugin-specific functionality (#431) this code is specific to external plugins and not for core plugins --- src/cli/current.rs | 18 +- src/cli/doctor.rs | 28 +-- src/cli/install.rs | 14 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/plugins/update.rs | 12 +- src/config/mod.rs | 10 ++ src/plugins/external_plugin.rs | 309 ++++++++++++++------------------- src/plugins/mod.rs | 128 +++++++++----- src/toolset/mod.rs | 4 + 10 files changed, 270 insertions(+), 257 deletions(-) diff --git a/src/cli/current.rs b/src/cli/current.rs index 93f056575..eef8880b2 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,10 +1,10 @@ -use std::sync::Arc; - use color_eyre::eyre::Result; use crate::cli::command::Command; + use crate::config::Config; use crate::output::Output; +use crate::plugins; use crate::plugins::Plugin; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -26,7 +26,7 @@ impl Command for Current { let ts = ToolsetBuilder::new().build(&mut config)?; match &self.plugin { Some(plugin_name) => match config.plugins.get(plugin_name) { - Some(plugin) => self.one(ts, out, plugin.clone()), + Some(plugin) => self.one(ts, out, plugin), None => { warn!("Plugin {} is not installed", plugin_name); Ok(()) @@ -38,10 +38,14 @@ impl Command for Current { } impl Current { - fn one(&self, ts: Toolset, out: &mut Output, plugin: Arc) -> Result<()> { - if !plugin.is_installed() { - warn!("Plugin {} is not installed", plugin.name()); - return Ok(()); + fn one(&self, ts: Toolset, out: &mut Output, plugin: &plugins::Plugins) -> Result<()> { + match plugin { + plugins::Plugins::External(plugin) => { + if !plugin.is_installed() { + warn!("Plugin {} is not installed", plugin.name()); + return Ok(()); + } + } } match ts.list_versions_by_plugin().get(plugin.name()) { Some(versions) => { diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 236d735ed..f7069b330 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -45,7 +45,7 @@ impl Command for Doctor { ); let mut checks = Vec::new(); - for plugin in config.plugins.values() { + for plugin in config.external_plugins().values() { if !plugin.is_installed() { checks.push(format!("plugin {} is not installed", plugin.name())); continue; @@ -111,23 +111,23 @@ fn render_plugins(config: &Config) -> String { .plugins .values() .filter(|p| p.is_installed()) - .map(|p| match p.as_ref() { - Plugins::External(p) => p, - //_ => None, - }) .collect::>(); let max_plugin_name_len = plugins.iter().map(|p| p.name().len()).max().unwrap_or(0) + 2; for p in plugins { let padded_name = pad_str(p.name(), max_plugin_name_len, Alignment::Left, None); - let git = Git::new(p.plugin_path.clone()); - let si = match git.get_remote_url() { - Some(url) => { - let sha = git - .current_sha_short() - .unwrap_or_else(|_| "(unknown)".to_string()); - format!(" {padded_name} {url}#{sha}\n") - } - None => format!(" {padded_name}\n"), + let si = match p.as_ref() { + Plugins::External(p) => { + let git = Git::new(p.plugin_path.clone()); + match git.get_remote_url() { + Some(url) => { + let sha = git + .current_sha_short() + .unwrap_or_else(|_| "(unknown)".to_string()); + format!(" {padded_name} {url}#{sha}\n") + } + None => format!(" {padded_name}\n"), + } + } //_ => {} }; s.push_str(&si); } diff --git a/src/cli/install.rs b/src/cli/install.rs index 7215e248b..1d10363b0 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -109,11 +109,15 @@ impl Install { &tv.plugin_name, ))), }; - if !plugin.is_installed() { - let mut pr = mpr.add(); - if let Err(err) = plugin.install(&config, &mut pr, false) { - pr.error(); - return Err(err)?; + match plugin.as_ref() { + Plugins::External(plugin) => { + if !plugin.is_installed() { + let mut pr = mpr.add(); + if let Err(err) = plugin.install(&config, &mut pr, false) { + pr.error(); + return Err(err)?; + } + } } } tv.resolve(&config, plugin, ts.latest_versions)?; diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 513676883..29bdd9e99 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -29,7 +29,7 @@ pub struct PluginsLsRemote { impl Command for PluginsLsRemote { fn run(self, config: Config, out: &mut Output) -> Result<()> { let installed_plugins = config - .plugins + .external_plugins() .values() .filter(|p| p.is_installed()) .map(|p| p.name().clone()) diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 4953e0034..caf86a6d0 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -34,7 +34,7 @@ impl PluginsUninstall { plugin_name: &String, mpr: &MultiProgressReport, ) -> Result<()> { - let plugin = config.plugins.get(plugin_name); + let plugin = config.external_plugins().remove(plugin_name); match plugin { Some(plugin) if plugin.is_installed() => { let mut pr = mpr.add(); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 4823fafb0..ed8f7fab8 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::Plugin; +use crate::plugins::{Plugin, PluginName}; /// Updates a plugin to the latest version /// @@ -14,7 +14,7 @@ use crate::plugins::Plugin; pub struct Update { /// Plugin(s) to update #[clap()] - plugin: Option>, + plugin: Option>, /// Update all plugins #[clap(long, short = 'a', conflicts_with = "plugin", hide = true)] @@ -31,16 +31,16 @@ impl Command for Update { Some((p, ref_)) => (p, Some(ref_.to_string())), None => (p.as_str(), None), }; - let plugin = config.plugins.get(p).ok_or_else(|| { + let plugin = config.external_plugins().remove(p).ok_or_else(|| { eyre!("plugin {} not found", style(p).cyan().for_stderr()) })?; Ok((plugin, ref_)) }) .collect::>()?, None => config - .plugins - .values() - .map(|p| (p, None)) + .external_plugins() + .into_iter() + .map(|(_, p)| (p, None)) .collect::>(), }; diff --git a/src/config/mod.rs b/src/config/mod.rs index 91fbfd6bf..ee0467297 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -140,6 +140,16 @@ impl Config { Ok(v.to_string()) } + pub fn external_plugins(&self) -> IndexMap { + self.plugins + .iter() + .map(|(name, plugin)| match plugin.as_ref() { + Plugins::External(plugin) => (name.clone(), plugin), + //_ => None, + }) + .collect() + } + fn load_all_aliases(&self) -> AliasMap { let mut aliases: AliasMap = self.aliases.clone(); let plugin_aliases: Vec<_> = self diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 98b650b36..ef650c0bb 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -7,7 +7,6 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; use indexmap::IndexMap; use itertools::Itertools; -use regex::Regex; use versions::Versioning; use crate::cache::CacheManager; @@ -25,7 +24,7 @@ use crate::plugins::rtx_plugin_toml::RtxPluginToml; use crate::plugins::Script::ParseLegacyFile; use crate::plugins::{Plugin, PluginName, Script, ScriptManager}; use crate::runtime_symlinks::is_runtime_symlink; -use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; +use crate::ui::progress_report::ProgressReport; use crate::{dirs, file}; /// This represents a plugin installed to ~/.local/share/rtx/plugins @@ -95,6 +94,99 @@ impl ExternalPlugin { git.get_remote_url() } + pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { + self.decorate_progress_bar(pr); + let repository = self + .repo_url + .as_ref() + .or_else(|| config.get_shorthands().get(&self.name)) + .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; + debug!("install {} {:?}", self.name, repository); + + let _lock = self.get_lock(force)?; + + if self.is_installed() { + self.uninstall(pr)?; + } + + let git = Git::new(self.plugin_path.to_path_buf()); + pr.set_message(format!("cloning {repository}")); + git.clone(repository)?; + if let Some(ref_) = &self.repo_ref { + pr.set_message(format!("checking out {ref_}")); + git.update(Some(ref_.to_string()))?; + } + + pr.set_message("loading plugin remote versions".into()); + if self.has_list_all_script() { + self.list_remote_versions(&config.settings)?; + } + if self.has_list_alias_script() { + pr.set_message("getting plugin aliases".into()); + self.get_aliases(&config.settings)?; + } + if self.has_list_legacy_filenames_script() { + pr.set_message("getting plugin legacy filenames".into()); + self.legacy_filenames(&config.settings)?; + } + + let sha = git.current_sha_short()?; + pr.finish_with_message(format!( + "{repository}#{}", + style(&sha).bright().yellow().for_stderr(), + )); + Ok(()) + } + + pub fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + if !self.is_installed() { + return Ok(()); + } + pr.set_message("uninstalling".into()); + + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", &dir.to_string_lossy())); + remove_all(dir).wrap_err_with(|| { + format!( + "Failed to remove directory {}", + style(&dir.to_string_lossy()).cyan().for_stderr() + ) + }) + }; + + rmdir(&self.downloads_path)?; + rmdir(&self.installs_path)?; + rmdir(&self.plugin_path)?; + + Ok(()) + } + + pub fn update(&self, gitref: Option) -> Result<()> { + let plugin_path = self.plugin_path.to_path_buf(); + if plugin_path.is_symlink() { + warn!( + "Plugin: {} is a symlink, not updating", + style(&self.name).cyan().for_stderr() + ); + return Ok(()); + } + let git = Git::new(plugin_path); + if !git.is_repo() { + warn!( + "Plugin {} is not a git repository, not updating", + style(&self.name).cyan().for_stderr() + ); + return Ok(()); + } + // TODO: asdf_run_hook "pre_plugin_update" + let (_pre, _post) = git.update(gitref)?; + // TODO: asdf_run_hook "post_plugin_update" + Ok(()) + } + fn latest_stable_version(&self, settings: &Settings) -> Result> { if let Some(latest) = self.get_latest_stable(settings)? { Ok(Some(latest)) @@ -274,116 +366,34 @@ impl Plugin for ExternalPlugin { &self.name } - fn is_installed(&self) -> bool { - self.plugin_path.exists() - } - - fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { - self.decorate_progress_bar(pr); - let repository = self - .repo_url - .as_ref() - .or_else(|| config.get_shorthands().get(&self.name)) - .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; - debug!("install {} {:?}", self.name, repository); - - let _lock = self.get_lock(force)?; - - if self.is_installed() { - self.uninstall(pr)?; - } - - let git = Git::new(self.plugin_path.to_path_buf()); - pr.set_message(format!("cloning {repository}")); - git.clone(repository)?; - if let Some(ref_) = &self.repo_ref { - pr.set_message(format!("checking out {ref_}")); - git.update(Some(ref_.to_string()))?; - } - - pr.set_message("loading plugin remote versions".into()); - if self.has_list_all_script() { - self.list_remote_versions(&config.settings)?; - } - if self.has_list_alias_script() { - pr.set_message("getting plugin aliases".into()); - self.get_aliases(&config.settings)?; - } - if self.has_list_legacy_filenames_script() { - pr.set_message("getting plugin legacy filenames".into()); - self.legacy_filenames(&config.settings)?; - } - - let sha = git.current_sha_short()?; - pr.finish_with_message(format!( - "{repository}#{}", - style(&sha).bright().yellow().for_stderr(), - )); - Ok(()) - } - - fn update(&self, gitref: Option) -> Result<()> { - let plugin_path = self.plugin_path.to_path_buf(); - if plugin_path.is_symlink() { - warn!( - "Plugin: {} is a symlink, not updating", - style(&self.name).cyan().for_stderr() - ); - return Ok(()); - } - let git = Git::new(plugin_path); - if !git.is_repo() { - warn!( - "Plugin {} is not a git repository, not updating", - style(&self.name).cyan().for_stderr() - ); - return Ok(()); - } - // TODO: asdf_run_hook "pre_plugin_update" - let (_pre, _post) = git.update(gitref)?; - // TODO: asdf_run_hook "post_plugin_update" - Ok(()) - } - - fn uninstall(&self, pr: &ProgressReport) -> Result<()> { - if !self.is_installed() { - return Ok(()); - } - pr.set_message("uninstalling".into()); - - let rmdir = |dir: &Path| { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", &dir.to_string_lossy())); - remove_all(dir).wrap_err_with(|| { - format!( - "Failed to remove directory {}", - style(&dir.to_string_lossy()).cyan().for_stderr() + fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { + self.remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions(settings)) + .map_err(|err| { + eyre!( + "Failed listing remote versions for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err ) }) - }; - - rmdir(&self.downloads_path)?; - rmdir(&self.installs_path)?; - rmdir(&self.plugin_path)?; + } - Ok(()) + fn clear_remote_version_cache(&self) -> Result<()> { + self.remote_version_cache.clear()?; + self.latest_stable_cache.clear() } - fn latest_installed_version(&self) -> Result> { - let installed_symlink = self.installs_path.join("latest"); - if installed_symlink.exists() { - let target = installed_symlink.read_link()?; - let version = target - .file_name() - .ok_or_else(|| eyre!("Invalid symlink target"))? - .to_string_lossy() - .to_string(); - Ok(Some(version)) - } else { - Ok(None) - } + fn list_installed_versions(&self) -> Result> { + Ok(match self.installs_path.exists() { + true => file::dir_subdirs(&self.installs_path)? + .iter() + .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) + .map(|v| Versioning::new(v).unwrap_or_default()) + .sorted() + .map(|v| v.to_string()) + .collect(), + false => vec![], + }) } fn latest_version(&self, settings: &Settings, query: Option) -> Result> { @@ -400,70 +410,23 @@ impl Plugin for ExternalPlugin { } } - fn list_installed_versions_matching(&self, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; - } - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_installed_versions()? - .iter() - .filter(|v| query_regex.is_match(v)) - .cloned() - .collect_vec(); - Ok(versions) - } - - fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; + fn latest_installed_version(&self) -> Result> { + let installed_symlink = self.installs_path.join("latest"); + if installed_symlink.exists() { + let target = installed_symlink.read_link()?; + let version = target + .file_name() + .ok_or_else(|| eyre!("Invalid symlink target"))? + .to_string_lossy() + .to_string(); + Ok(Some(version)) + } else { + Ok(None) } - let version_regex = regex!( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" - ); - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_remote_versions(settings)? - .iter() - .filter(|v| !version_regex.is_match(v)) - .filter(|v| query_regex.is_match(v)) - .cloned() - .collect_vec(); - Ok(versions) } - fn list_installed_versions(&self) -> Result> { - Ok(match self.installs_path.exists() { - true => file::dir_subdirs(&self.installs_path)? - .iter() - .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) - .map(|v| Versioning::new(v).unwrap_or_default()) - .sorted() - .map(|v| v.to_string()) - .collect(), - false => vec![], - }) - } - - fn clear_remote_version_cache(&self) -> Result<()> { - self.remote_version_cache.clear()?; - self.latest_stable_cache.clear() - } - - fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { - self.remote_version_cache - .get_or_try_init(|| self.fetch_remote_versions(settings)) - .map_err(|err| { - eyre!( - "Failed listing remote versions for plugin {}: {}", - style(&self.name).cyan().for_stderr(), - err - ) - }) + fn is_installed(&self) -> bool { + self.plugin_path.exists() } fn get_aliases(&self, settings: &Settings) -> Result> { @@ -563,14 +526,4 @@ impl Plugin for ExternalPlugin { .run()?; exit(result.status.code().unwrap_or(1)); } - - fn decorate_progress_bar(&self, pr: &mut ProgressReport) { - pr.set_style(PROG_TEMPLATE.clone()); - pr.set_prefix(format!( - "{} {} ", - style("rtx").dim().for_stderr(), - style(&self.name).cyan().for_stderr() - )); - pr.enable_steady_tick(); - } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 9a68696d6..ccbc4c0e4 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -2,13 +2,15 @@ use std::fmt::Debug; use std::path::Path; use color_eyre::eyre::Result; +use console::style; use indexmap::IndexMap; +use regex::Regex; pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; -use crate::config::{Config, Settings}; -use crate::ui::progress_report::ProgressReport; +use crate::config::Settings; +use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; mod external_plugin; mod rtx_plugin_toml; @@ -18,23 +20,75 @@ pub type PluginName = String; pub trait Plugin: Debug + Send + Sync { fn name(&self) -> &PluginName; - fn is_installed(&self) -> bool; - fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()>; - fn update(&self, gitref: Option) -> Result<()>; - fn uninstall(&self, pr: &ProgressReport) -> Result<()>; - fn latest_installed_version(&self) -> Result>; - fn latest_version(&self, settings: &Settings, query: Option) -> Result>; - fn list_installed_versions_matching(&self, query: &str) -> Result>; - fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result>; - fn list_installed_versions(&self) -> Result>; - fn clear_remote_version_cache(&self) -> Result<()>; fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec>; - fn get_aliases(&self, settings: &Settings) -> Result>; - fn legacy_filenames(&self, settings: &Settings) -> Result>; - fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result; - fn external_commands(&self) -> Result>>; - fn execute_external_command(&self, command: &str, args: Vec) -> Result<()>; - fn decorate_progress_bar(&self, pr: &mut ProgressReport); + fn clear_remote_version_cache(&self) -> Result<()>; + fn list_installed_versions(&self) -> Result>; + fn latest_version(&self, settings: &Settings, query: Option) -> Result>; + fn latest_installed_version(&self) -> Result>; + + fn is_installed(&self) -> bool { + true + } + + fn list_installed_versions_matching(&self, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9]"; + } + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + let versions = self + .list_installed_versions()? + .iter() + .filter(|v| query_regex.is_match(v)) + .cloned() + .collect(); + Ok(versions) + } + fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9]"; + } + let version_regex = regex!( + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" + ); + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + let versions = self + .list_remote_versions(settings)? + .iter() + .filter(|v| !version_regex.is_match(v)) + .filter(|v| query_regex.is_match(v)) + .cloned() + .collect(); + Ok(versions) + } + fn get_aliases(&self, _settings: &Settings) -> Result> { + Ok(IndexMap::new()) + } + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![]) + } + fn parse_legacy_file(&self, _path: &Path, _settings: &Settings) -> Result { + unimplemented!() + } + fn external_commands(&self) -> Result>> { + Ok(vec![]) + } + fn execute_external_command(&self, _command: &str, _args: Vec) -> Result<()> { + unimplemented!() + } + + fn decorate_progress_bar(&self, pr: &mut ProgressReport) { + pr.set_style(PROG_TEMPLATE.clone()); + pr.set_prefix(format!( + "{} {} ", + style("rtx").dim().for_stderr(), + style(self.name()).cyan().for_stderr() + )); + pr.enable_steady_tick(); + } } #[derive(Debug)] @@ -49,26 +103,25 @@ impl Plugin for Plugins { } } - fn is_installed(&self) -> bool { + fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { match self { - Plugins::External(p) => p.is_installed(), + Plugins::External(p) => p.list_remote_versions(settings), } } - fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { + + fn clear_remote_version_cache(&self) -> Result<()> { match self { - Plugins::External(p) => p.install(config, pr, force), + Plugins::External(p) => p.clear_remote_version_cache(), } } - - fn update(&self, gitref: Option) -> Result<()> { + fn list_installed_versions(&self) -> Result> { match self { - Plugins::External(p) => p.update(gitref), + Plugins::External(p) => p.list_installed_versions(), } } - - fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + fn latest_version(&self, settings: &Settings, query: Option) -> Result> { match self { - Plugins::External(p) => p.uninstall(pr), + Plugins::External(p) => p.latest_version(settings, query), } } fn latest_installed_version(&self) -> Result> { @@ -76,9 +129,9 @@ impl Plugin for Plugins { Plugins::External(p) => p.latest_installed_version(), } } - fn latest_version(&self, settings: &Settings, query: Option) -> Result> { + fn is_installed(&self) -> bool { match self { - Plugins::External(p) => p.latest_version(settings, query), + Plugins::External(p) => p.is_installed(), } } fn list_installed_versions_matching(&self, query: &str) -> Result> { @@ -91,21 +144,6 @@ impl Plugin for Plugins { Plugins::External(p) => p.list_versions_matching(settings, query), } } - fn list_installed_versions(&self) -> Result> { - match self { - Plugins::External(p) => p.list_installed_versions(), - } - } - fn clear_remote_version_cache(&self) -> Result<()> { - match self { - Plugins::External(p) => p.clear_remote_version_cache(), - } - } - fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { - match self { - Plugins::External(p) => p.list_remote_versions(settings), - } - } fn get_aliases(&self, settings: &Settings) -> Result> { match self { Plugins::External(p) => p.get_aliases(settings), diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index b8ae3aaaa..c79c14861 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -193,6 +193,10 @@ impl Toolset { missing_plugins .into_par_iter() .map(|p| config.plugins.get(&p).unwrap()) + .filter_map(|p| match p.as_ref() { + Plugins::External(p) => Some(p), + //_ => None, + }) .filter(|p| !p.is_installed()) .map(|p| { let mut pr = mpr.add(); From 16f043870f83cfa341c9afa583b7dea2d325db53 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 31 Mar 2023 13:32:21 -0500 Subject: [PATCH 0644/1891] move mangen from feature to xtask (#432) --- .cargo/config.toml | 2 + .idea/rtx.iml | 13 ++-- Cargo.lock | 10 ++- Cargo.toml | 10 ++- completions/_rtx | 36 --------- completions/rtx.bash | 50 +----------- completions/rtx.fish | 78 ++++++++----------- justfile | 16 ++-- src/cli/mangen.rs | 40 ---------- src/cli/mod.rs | 12 +-- .../rtx__cli__mangen__tests__complete.snap | 5 -- src/cli/version.rs | 6 +- src/cmd.rs | 4 + src/lib.rs | 41 ++++++++++ src/shims.rs | 1 + xtask/Cargo.toml | 11 +++ xtask/src/main.rs | 57 ++++++++++++++ 17 files changed, 194 insertions(+), 198 deletions(-) delete mode 100644 src/cli/mangen.rs delete mode 100644 src/cli/snapshots/rtx__cli__mangen__tests__complete.snap create mode 100644 src/lib.rs create mode 100644 xtask/Cargo.toml create mode 100644 xtask/src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 73f82bb72..cc0fa5c45 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,4 @@ [env] RUST_TEST_THREADS = '1' +[alias] +xtask = "run -p xtask --" diff --git a/.idea/rtx.iml b/.idea/rtx.iml index 95fa9b00d..027e49820 100644 --- a/.idea/rtx.iml +++ b/.idea/rtx.iml @@ -6,19 +6,20 @@ + - - - + + - + - + + - + diff --git a/Cargo.lock b/Cargo.lock index e86fd013d..8d1eaba7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1599,7 +1599,6 @@ dependencies = [ "chrono", "clap", "clap_complete", - "clap_mangen", "color-eyre", "color-print", "console", @@ -2663,6 +2662,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "xtask" +version = "0.1.0" +dependencies = [ + "clap_mangen", + "color-eyre", + "rtx-cli", +] + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 1ac023b2c..701e0fc6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,15 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] +members = ["xtask"] + +[lib] +name = "rtx" +path = "src/lib.rs" +test = false +doctest = false + [[bin]] name = "rtx" path = "src/main.rs" @@ -30,7 +39,6 @@ base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } clap = { version = "4.0.32", features = ["env", "derive", "string"] } clap_complete = "4.0.7" -clap_mangen = { version = "0.2.9", optional = true } color-eyre = "0.6.2" color-print = "0.3.4" console = "0.15.2" diff --git a/completions/_rtx b/completions/_rtx index 1555c9d39..9dd43d7ca 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -807,26 +807,6 @@ Sets --jobs=1]' \ same as the first argument after the "@":' \ && ret=0 ;; -(mangen) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--trace[Sets log level to trace]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; (plugins) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel @@ -1594,10 +1574,6 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; -(mangen) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; (plugins) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help__plugins_commands" \ @@ -1753,7 +1729,6 @@ _rtx_commands() { 'ls:List installed runtime versions' \ 'list:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ -'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ 'prune:Delete unused versions of tools' \ @@ -2105,7 +2080,6 @@ _rtx__help_commands() { 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed runtime versions' \ 'ls-remote:List runtime versions available for install' \ -'mangen:Generate man pages' \ 'plugins:Manage plugins' \ 'prune:Delete unused versions of tools' \ 'reshim:\[experimental\] rebuilds the shim farm' \ @@ -2321,16 +2295,6 @@ _rtx__plugins__ls-remote_commands() { local commands; commands=() _describe -t commands 'rtx plugins ls-remote commands' commands "$@" } -(( $+functions[_rtx__help__mangen_commands] )) || -_rtx__help__mangen_commands() { - local commands; commands=() - _describe -t commands 'rtx help mangen commands' commands "$@" -} -(( $+functions[_rtx__mangen_commands] )) || -_rtx__mangen_commands() { - local commands; commands=() - _describe -t commands 'rtx mangen commands' commands "$@" -} (( $+functions[_rtx__help__plugins_commands] )) || _rtx__help__plugins_commands() { local commands; commands=( diff --git a/completions/rtx.bash b/completions/rtx.bash index 38d19f819..ca0d82536 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -93,9 +93,6 @@ _rtx() { rtx,ls-remote) cmd="rtx__ls__remote" ;; - rtx,mangen) - cmd="rtx__mangen" - ;; rtx,p) cmd="rtx__plugins" ;; @@ -291,9 +288,6 @@ _rtx() { rtx__help,ls-remote) cmd="rtx__help__ls__remote" ;; - rtx__help,mangen) - cmd="rtx__help__mangen" - ;; rtx__help,plugins) cmd="rtx__help__plugins" ;; @@ -496,7 +490,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" + opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1320,7 +1314,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote mangen plugins prune reshim self-update settings shell trust uninstall version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1739,20 +1733,6 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__mangen) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; rtx__help__plugins) opts="install link ls ls-remote uninstall update" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2271,32 +2251,6 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__mangen) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; rtx__plugins) opts="-a -u -j -r -v -h --all --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index e4b79788f..789b53f4b 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -29,7 +29,6 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest av complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_use_subcommand" -f -a "mangen" -d 'Generate man pages' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] rebuilds the shim farm' @@ -387,16 +386,6 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from mangen" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from mangen" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -l install-missing -d 'Automatically install missing tools' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from mangen" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r @@ -660,40 +649,39 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "mangen" -d 'Generate man pages' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from mangen; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/justfile b/justfile index 8746dcfeb..eef14827e 100644 --- a/justfile +++ b/justfile @@ -12,7 +12,7 @@ alias b := test # just `cargo build` build *args: - cargo build --all-features {{ args }} + cargo build {{ args }} alias t := test @@ -21,11 +21,11 @@ test *args: (test-unit args) test-e2e lint # update all test snapshot files test-update-snapshots: - cargo insta test --accept --all-features + cargo insta test --accept # run the rust "unit" tests test-unit *args: - cargo test --all-features {{ args }} + cargo test {{ args }} # runs the E2E tests in ./e2e test-e2e: build @@ -44,7 +44,7 @@ test-coverage: export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$PWD/target}" export PATH="${CARGO_TARGET_DIR}/debug:$PATH" - cargo test --all-features + cargo test cargo build --all-features ./e2e/run_all_tests rtx trust @@ -68,7 +68,7 @@ clean: # clippy, cargo fmt --check, and just --fmt lint: - cargo clippy --all-features + cargo clippy cargo fmt --all -- --check shellcheck scripts/*.sh shfmt -d scripts/*.sh @@ -76,7 +76,7 @@ lint: # runs linters but makes fixes when possible lint-fix: - cargo clippy --all-features --fix --allow-staged --allow-dirty + cargo clippy --fix --allow-staged --allow-dirty cargo fmt --all shellcheck scripts/*.sh shfmt -w scripts/*.sh @@ -94,8 +94,8 @@ render-completions: build NO_COLOR=1 rtx completion fish > completions/rtx.fish # regenerate manpages -render-mangen: build - NO_COLOR=1 rtx mangen +render-mangen: + NO_COLOR=1 cargo xtask mangen # called by lefthook precommit hook pre-commit: render-help render-completions render-mangen diff --git a/src/cli/mangen.rs b/src/cli/mangen.rs deleted file mode 100644 index f7bda1d6c..000000000 --- a/src/cli/mangen.rs +++ /dev/null @@ -1,40 +0,0 @@ -use color_eyre::eyre::Result; - -use crate::cli::command::Command; -use crate::cli::Cli; -use crate::config::Config; -use crate::dirs; -use crate::output::Output; - -/// Generate man pages -#[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, hide = true)] -pub struct Mangen {} - -impl Command for Mangen { - fn run(self, _config: Config, _out: &mut Output) -> Result<()> { - let cli = Cli::command() - .version(env!("CARGO_PKG_VERSION")) - .disable_colored_help(true); - - let man = clap_mangen::Man::new(cli); - let mut buffer: Vec = Default::default(); - man.render(&mut buffer)?; - - let out_dir = dirs::CURRENT.join("man").join("man1"); - std::fs::create_dir_all(&out_dir)?; - std::fs::write(out_dir.join("rtx.1"), buffer)?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use crate::assert_cli_snapshot; - - #[test] - fn test_complete() { - assert_cli_snapshot!("mangen"); - } -} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ec0b804ba..5a33456d0 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -31,8 +31,6 @@ mod latest; mod local; mod ls; mod ls_remote; -#[cfg(feature = "clap_mangen")] -mod mangen; mod plugins; mod prune; #[cfg(debug_assertions)] @@ -74,8 +72,6 @@ pub enum Commands { Local(local::Local), Ls(ls::Ls), LsRemote(ls_remote::LsRemote), - #[cfg(feature = "clap_mangen")] - Mangen(mangen::Mangen), Plugins(plugins::Plugins), Prune(prune::Prune), Reshim(reshim::Reshim), @@ -115,8 +111,6 @@ impl Commands { Self::Local(cmd) => cmd.run(config, out), Self::Ls(cmd) => cmd.run(config, out), Self::LsRemote(cmd) => cmd.run(config, out), - #[cfg(feature = "clap_mangen")] - Self::Mangen(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), Self::Prune(cmd) => cmd.run(config, out), Self::Reshim(cmd) => cmd.run(config, out), @@ -210,6 +204,12 @@ impl Cli { } } +impl Default for Cli { + fn default() -> Self { + Self::new() + } +} + const LONG_ABOUT: &str = indoc! {" rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx diff --git a/src/cli/snapshots/rtx__cli__mangen__tests__complete.snap b/src/cli/snapshots/rtx__cli__mangen__tests__complete.snap deleted file mode 100644 index 8f7f9d249..000000000 --- a/src/cli/snapshots/rtx__cli__mangen__tests__complete.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/mangen.rs -expression: output ---- - diff --git a/src/cli/version.rs b/src/cli/version.rs index 9c7e822ab..d0f745f3f 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -33,9 +33,9 @@ pub static VERSION: Lazy = Lazy::new(|| { format!( "{} {}-{} ({} {})", if cfg!(debug_assertions) { - format!("{}-DEBUG", env!("CARGO_PKG_VERSION")) + format!("{}-DEBUG", *RAW_VERSION) } else { - env!("CARGO_PKG_VERSION").to_string() + RAW_VERSION.clone() }, *OS, *ARCH, @@ -44,6 +44,8 @@ pub static VERSION: Lazy = Lazy::new(|| { ) }); +pub static RAW_VERSION: Lazy = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string()); + impl Command for Version { fn run(self, _config: Config, out: &mut Output) -> Result<()> { show_version(out); diff --git a/src/cmd.rs b/src/cmd.rs index 9f2302837..f1de7b487 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -11,6 +11,8 @@ use duct::{Expression, IntoExecutablePath}; /// # Example /// /// ``` +/// use std::path::Path; +/// use rtx::cmd; /// /// let arg1 = "foo"; /// let arg2 = "bar".to_owned(); @@ -40,6 +42,8 @@ macro_rules! cmd { /// # Example /// /// ``` +/// use std::path::Path; +/// use rtx::cmd; /// /// let arg1 = "foo"; /// let arg2 = "bar".to_owned(); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..050389f45 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,41 @@ +#[macro_use] +extern crate log; + +#[macro_use] +mod output; + +#[macro_use] +mod regex; + +#[macro_use] +pub mod cli; + +mod build_time; +mod cache; +pub mod cmd; +mod config; +mod default_shorthands; +mod direnv; +mod dirs; +mod duration; +mod env; +mod env_diff; +mod errors; +mod fake_asdf; +mod file; +mod git; +mod hash; +mod hook_env; +mod lock_file; +mod plugins; +mod runtime_symlinks; +mod runtimes; +mod shell; +mod shims; +mod shorthands; +mod tera; +#[cfg(test)] +mod test; +mod toml; +mod toolset; +mod ui; diff --git a/src/shims.rs b/src/shims.rs index 884ee462d..c6ec54082 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -22,6 +22,7 @@ use crate::toolset::{Toolset, ToolsetBuilder}; 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 { let (_, bin_name) = args[0].rsplit_once('/').unwrap_or(("", &args[0])); if bin_name == "rtx" || !config.settings.experimental { diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml new file mode 100644 index 000000000..cba1bc154 --- /dev/null +++ b/xtask/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "xtask" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap_mangen = "0.2.10" +color-eyre = "0.6.2" +rtx-cli = {path = ".."} diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 000000000..5effd7f49 --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,57 @@ +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::exit; + +use color_eyre::eyre::Result; + +use rtx::cli::{version, Cli}; + +fn main() { + if let Err(e) = try_main() { + eprintln!("{}", e); + exit(-1); + } +} + +fn try_main() -> Result<()> { + let task = env::args().nth(1); + match task.as_deref() { + Some("mangen") => mangen()?, + _ => print_help(), + } + Ok(()) +} + +fn print_help() { + eprintln!( + "Tasks: + +mangen builds man pages +" + ) +} + +fn mangen() -> Result<()> { + let cli = Cli::command() + .version(&*version::RAW_VERSION) + .disable_colored_help(true); + + let man = clap_mangen::Man::new(cli); + let mut buffer: Vec = Default::default(); + man.render(&mut buffer)?; + + let out_dir = project_root().join("man").join("man1"); + fs::create_dir_all(&out_dir)?; + fs::write(out_dir.join("rtx.1"), buffer)?; + + Ok(()) +} + +fn project_root() -> PathBuf { + Path::new(&env!("CARGO_MANIFEST_DIR")) + .ancestors() + .nth(1) + .unwrap() + .to_path_buf() +} From 62c570ad09536b6ea0ae228e3a91cf43d7d04ae6 Mon Sep 17 00:00:00 2001 From: Thomas Buckley-Houston Date: Tue, 4 Apr 2023 17:35:19 +0000 Subject: [PATCH 0645/1891] docs: README: don't untar Github release (#436) README previously stated that the plain binary Github release needed untarring. Whereas it can in fact just be installed directly without untarring. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fce884a5a..4846c9eb3 100644 --- a/README.md +++ b/README.md @@ -327,8 +327,8 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.10/rtx-v1.27.10-linux-x64 | tar -xJv -mv rtx/bin/rtx /usr/local/bin +curl https://github.com/jdxcode/rtx/releases/download/v1.27.10/rtx-v1.27.10-linux-x64 +mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` ### apt From 002acf930b8d2c0b080ca5f84e3b056d7fc9d373 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 4 Apr 2023 15:43:57 -0500 Subject: [PATCH 0646/1891] set RTX_CACHE_DIR --- src/plugins/script_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 46c4ed327..3aabd4692 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -68,6 +68,7 @@ impl Display for Script { static INITIAL_ENV: Lazy> = Lazy::new(|| { (indexmap! { "RTX_EXE" => env::RTX_EXE.to_string_lossy(), + "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy(), }) .into_iter() .map(|(k, v)| (k.to_string(), v.to_string())) From 47a5ac9cfd66cb5d565da9a0e3a3c78a8928e6dd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 4 Apr 2023 15:49:56 -0500 Subject: [PATCH 0647/1891] chore: Release --- Cargo.lock | 151 ++++++++++++++++++-------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 6 +- 7 files changed, 82 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d1eaba7c..9beedcb31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -237,7 +237,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -344,9 +344,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" @@ -436,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" dependencies = [ "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -473,7 +473,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -490,7 +490,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -926,9 +926,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.55" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716f12fbcfac6ffab0a5e9ec51d0a0ff70503742bb2dc7b99396394c9dc323f0" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1058,7 +1058,7 @@ checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix 0.37.5", + "rustix", "windows-sys 0.45.0", ] @@ -1103,9 +1103,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libgit2-sys" @@ -1146,12 +1146,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - [[package]] name = "linux-raw-sys" version = "0.3.1" @@ -1335,9 +1329,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.6" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" +checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122" dependencies = [ "thiserror", "ucd-trie", @@ -1345,9 +1339,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.6" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" +checksum = "be99c4c1d2fc2769b1d00239431d711d08f6efedcecb8b6e30707160aee99c15" dependencies = [ "pest", "pest_generator", @@ -1355,22 +1349,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.6" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" +checksum = "e56094789873daa36164de2e822b3888c6ae4b4f9da555a1103587658c805b1e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.13", ] [[package]] name = "pest_meta" -version = "2.5.6" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" +checksum = "6733073c7cff3d8459fda0e42f13a047870242aed8b509fe98000928975f359e" dependencies = [ "once_cell", "pest", @@ -1415,9 +1409,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -1592,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.27.10" +version = "1.27.11" dependencies = [ "base64", "built", @@ -1652,29 +1646,15 @@ checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustix" -version = "0.36.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" -dependencies = [ - "bitflags", - "errno 0.2.8", - "io-lifetimes", - "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.45.0", -] - -[[package]] -name = "rustix" -version = "0.37.5" +version = "0.37.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e78cc525325c06b4a7ff02db283472f3c042b7ff0c391f96c6d5ac6f4f91b75" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ "bitflags", "errno 0.3.0", "io-lifetimes", "libc", - "linux-raw-sys 0.3.1", + "linux-raw-sys", "windows-sys 0.45.0", ] @@ -1780,7 +1760,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -1924,9 +1904,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.12" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" dependencies = [ "proc-macro2", "quote", @@ -1942,7 +1922,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.5", + "rustix", "windows-sys 0.45.0", ] @@ -1974,12 +1954,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix 0.36.11", - "windows-sys 0.45.0", + "rustix", + "windows-sys 0.48.0", ] [[package]] @@ -1999,7 +1979,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -2499,11 +2479,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.47.0", + "windows-targets 0.48.0", ] [[package]] @@ -2530,6 +2510,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -2547,17 +2536,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm 0.47.0", - "windows_aarch64_msvc 0.47.0", - "windows_i686_gnu 0.47.0", - "windows_i686_msvc 0.47.0", - "windows_x86_64_gnu 0.47.0", - "windows_x86_64_gnullvm 0.47.0", - "windows_x86_64_msvc 0.47.0", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -2568,9 +2557,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" @@ -2580,9 +2569,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" @@ -2592,9 +2581,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" @@ -2604,9 +2593,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" @@ -2616,9 +2605,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" @@ -2628,9 +2617,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" @@ -2640,9 +2629,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index 701e0fc6b..6d3dcbeb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.27.10" +version = "1.27.11" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 4846c9eb3..c04ccc786 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.27.10 +rtx 1.27.11 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.10/rtx-v1.27.10-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.27.11/rtx-v1.27.11-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 0752c2444..3f2e7f9ce 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.27.10"; + version = "1.27.11"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a21aa4a51..708a6ea4b 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.27.10" +.TH rtx 1 "rtx 1.27.11" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.27.10 +v1.27.11 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f6c1adbc9..5972042ea 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.27.10 +Version: 1.27.11 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index e4e22e7bd..54a5331c1 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 636] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 640] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -163,7 +163,9 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 636] = [ ("dtm", "https://github.com/zhenyuanlau/asdf-dtm.git"), ("duf", "https://github.com/NeoHsu/asdf-duf.git"), ("dust", "https://github.com/looztra/asdf-dust.git"), + ("dvc", "https://github.com/fwfurtado/asdf-dvc.git"), ("dyff", "https://gitlab.com/wt0f/asdf-dyff.git"), + ("ecspresso", "https://github.com/kayac/asdf-ecspresso.git"), ("editorconfig-checker", "https://github.com/gabitchov/asdf-editorconfig-checker.git"), ("ejson", "https://github.com/cipherstash/asdf-ejson.git"), ("eksctl", "https://github.com/elementalvoid/asdf-eksctl.git"), @@ -350,6 +352,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 636] = [ ("kubesec", "https://github.com/vitalis/asdf-kubesec.git"), ("kubespy", "https://github.com/jfreeland/asdf-kubespy.git"), ("kubeval", "https://github.com/stefansedich/asdf-kubeval.git"), + ("kubevela", "https://github.com/gustavclausen/asdf-kubevela.git"), ("kubie", "https://github.com/johnhamelink/asdf-kubie.git"), ("kustomize", "https://github.com/Banno/asdf-kustomize.git"), ("kuttl", "https://github.com/jimmidyson/asdf-kuttl.git"), @@ -361,6 +364,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 636] = [ ("leiningen", "https://github.com/miorimmax/asdf-lein.git"), ("levant", "https://github.com/asdf-community/asdf-hashicorp.git"), ("lfe", "https://github.com/asdf-community/asdf-lfe.git"), + ("lima", "https://github.com/CrouchingMuppet/asdf-lima.git"), ("link", "https://github.com/asdf-community/asdf-link.git"), ("linkerd", "https://github.com/kforsthoevel/asdf-linkerd.git"), ("liqoctl", "https://github.com/pdemagny/asdf-liqoctl"), From 70202c09cf5851de64e2664ce24df25c6b57fa99 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 4 Apr 2023 16:49:03 -0500 Subject: [PATCH 0648/1891] chore: added cloudflare cache purge --- scripts/publish-s3.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 5e9873f9e..68486aa94 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -28,6 +28,22 @@ aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$c aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_day" --no-progress --no-progress --recursive +export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 +export CLOUDFLARE_ZONE_ID=80d977fd09f01db52bec165778088891 +curl -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data '{ + "prefixes": [ + "/VERSION", + "/SHASUMS", + "/install.sh", + "/rtx-latest-", + "/rpm/repodata/", + "/deb/dists/" + ] + }' + #aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ # "/VERSION" \ # "/SHASUMS*" \ From d63cf54171bb906f8c62d9b4e14fe56e6e42a2c9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 5 Apr 2023 15:12:04 -0500 Subject: [PATCH 0649/1891] refactor (#439) --- src/cli/args/runtime.rs | 107 +---- src/cli/asdf.rs | 11 +- src/cli/current.rs | 36 +- src/cli/hook_env.rs | 8 +- src/cli/install.rs | 75 +-- src/cli/latest.rs | 9 +- src/cli/local.rs | 4 +- src/cli/ls.rs | 100 ++-- src/cli/ls_remote.rs | 7 +- src/cli/plugins/install.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/prune.rs | 32 +- src/cli/shell.rs | 8 +- .../rtx__cli__current__tests__current.snap | 2 +- ...x__cli__local__tests__local_alias_ref.snap | 2 +- .../snapshots/rtx__cli__ls__tests__ls-2.snap | 2 +- .../snapshots/rtx__cli__ls__tests__ls-3.snap | 2 +- .../snapshots/rtx__cli__ls__tests__ls-4.snap | 2 +- .../snapshots/rtx__cli__ls__tests__ls-5.snap | 2 +- .../snapshots/rtx__cli__ls__tests__ls.snap | 2 +- .../rtx__cli__ls__tests__ls_current.snap | 2 +- .../rtx__cli__ls__tests__ls_json.snap | 2 +- .../rtx__cli__ls__tests__ls_parseable.snap | 2 +- src/cli/uninstall.rs | 34 +- src/cli/where.rs | 46 +- src/cli/which.rs | 8 +- src/config/config_file/legacy_version.rs | 30 +- src/config/config_file/mod.rs | 32 +- src/config/config_file/rtx_toml.rs | 77 +-- ...nfig_file__rtx_toml__tests__fixture-4.snap | 119 ++--- ...le__rtx_toml__tests__replace_versions.snap | 26 +- src/config/config_file/tool_versions.rs | 13 +- src/lib.rs | 1 - src/main.rs | 1 - src/plugins/external_plugin.rs | 277 ++++++++++- src/plugins/external_plugin_cache.rs | 99 ++++ src/plugins/mod.rs | 130 +++++- src/plugins/script_manager.rs | 49 +- src/runtime_symlinks.rs | 2 +- src/runtimes.rs | 439 ------------------ src/shims.rs | 29 +- src/toolset/builder.rs | 11 +- src/toolset/mod.rs | 257 +++++----- src/toolset/tool_version.rs | 212 ++++----- src/toolset/tool_version_list.rs | 68 +-- src/toolset/tool_version_request.rs | 75 +++ src/ui/progress_report.rs | 12 +- 47 files changed, 1198 insertions(+), 1270 deletions(-) create mode 100644 src/plugins/external_plugin_cache.rs delete mode 100644 src/runtimes.rs create mode 100644 src/toolset/tool_version_request.rs diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index 76eeda9df..849771726 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -1,68 +1,29 @@ use std::ffi::{OsStr, OsString}; use std::fmt::Display; -use std::path::PathBuf; use clap::{Arg, Command, Error}; use color_eyre::eyre::Result; use regex::Regex; use crate::plugins::PluginName; -use crate::toolset::{ToolVersion, ToolVersionType}; +use crate::toolset::ToolVersionRequest; -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct RuntimeArg { pub plugin: PluginName, - pub version: RuntimeArgVersion, -} - -/// The type of runtime argument -/// Generally, these are in the form of `plugin@version` that's "Version" -/// but there are some alternatives like `plugin@ref:sha` or `plugin@path:/path/to/runtime` -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub enum RuntimeArgVersion { - /// Nothing was specified, e.g.: `nodejs` - None, - /// references a version, version prefix, or alias - /// e.g.: `nodejs@18`, `nodejs@latest`, `nodejs@lts` - Version(String), - /// use the system runtime already on PATH - /// e.g.: `nodejs@system` - System, - /// build runtime from source at this VCS sha - Ref(String), - /// runtime is in a local directory, not managed by rtx - Path(PathBuf), - Prefix(String), + pub tvr: Option, } impl RuntimeArg { pub fn parse(input: &str) -> Self { match input.split_once('@') { - Some((plugin, "system")) => Self { - plugin: plugin.into(), - version: RuntimeArgVersion::System, - }, - Some((plugin, version)) => match version.split_once(':') { - Some(("path", path)) => Self { - plugin: plugin.into(), - version: RuntimeArgVersion::Path(path.into()), - }, - Some(("ref", ref_)) => Self { - plugin: plugin.into(), - version: RuntimeArgVersion::Ref(ref_.into()), - }, - Some(("prefix", prefix)) => Self { - plugin: plugin.into(), - version: RuntimeArgVersion::Prefix(prefix.into()), - }, - _ => Self { - plugin: plugin.into(), - version: RuntimeArgVersion::Version(version.into()), - }, + Some((plugin, version)) => Self { + plugin: plugin.to_string(), + tvr: Some(ToolVersionRequest::new(plugin.to_string(), version)), }, None => Self { plugin: input.into(), - version: RuntimeArgVersion::None, + tvr: None, }, } } @@ -80,11 +41,8 @@ impl RuntimeArg { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let a = runtimes[0].clone(); let b = runtimes[1].clone(); - if matches!(a.version, RuntimeArgVersion::None) - && matches!(b.version, RuntimeArgVersion::None) - && re.is_match(&b.plugin) - { - runtimes[1].version = RuntimeArgVersion::Version(b.plugin); + if matches!(a.tvr, None) && matches!(b.tvr, None) && re.is_match(&b.plugin) { + runtimes[1].tvr = Some(ToolVersionRequest::new(a.plugin.clone(), &b.plugin)); runtimes[1].plugin = a.plugin; runtimes.remove(0); } @@ -92,52 +50,19 @@ impl RuntimeArg { runtimes } - pub fn with_version(self, version: RuntimeArgVersion) -> Self { - Self { version, ..self } - } - - pub fn to_tool_version(&self) -> Option { - match self.version { - RuntimeArgVersion::Version(ref v) => Some(ToolVersion::new( - self.plugin.clone(), - ToolVersionType::Version(v.clone()), - )), - RuntimeArgVersion::Ref(ref v) => Some(ToolVersion::new( - self.plugin.clone(), - ToolVersionType::Ref(v.clone()), - )), - RuntimeArgVersion::Path(ref v) => Some(ToolVersion::new( - self.plugin.clone(), - ToolVersionType::Path(v.clone()), - )), - RuntimeArgVersion::Prefix(ref v) => Some(ToolVersion::new( - self.plugin.clone(), - ToolVersionType::Prefix(v.clone()), - )), - RuntimeArgVersion::System => Some(ToolVersion::new( - self.plugin.clone(), - ToolVersionType::System, - )), - RuntimeArgVersion::None => None, + pub fn with_version(self, version: &str) -> Self { + Self { + tvr: Some(ToolVersionRequest::new(self.plugin.clone(), version)), + ..self } } } impl Display for RuntimeArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}@{}", self.plugin, self.version) - } -} - -impl Display for RuntimeArgVersion { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - RuntimeArgVersion::System => write!(f, "system"), - RuntimeArgVersion::Version(version) => write!(f, "{version}"), - RuntimeArgVersion::Path(path) => write!(f, "path:{}", path.display()), - RuntimeArgVersion::Ref(ref_) => write!(f, "ref:{ref_}"), - RuntimeArgVersion::Prefix(prefix) => write!(f, "prefix:{prefix}"), - RuntimeArgVersion::None => write!(f, "current"), + match &self.tvr { + Some(tvr) => write!(f, "{}", tvr), + _ => write!(f, "{}", self.plugin), } } } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 8118739e2..9962e3eff 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -5,7 +5,6 @@ use crate::cli::command::Command; use crate::cli::Cli; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; use crate::toolset::ToolsetBuilder; /// [internal] simulates asdf for plugins that call "asdf" internally @@ -60,18 +59,18 @@ fn list_versions(mut config: Config, out: &mut Output, args: &Vec) -> Re _ => None, }; if let Some(plugin) = plugin { - versions.retain(|v| v.plugin.name() == plugin); - for version in versions { + versions.retain(|(_, v)| v.plugin_name.as_str() == plugin); + for (_, version) in versions { rtxprintln!(out, "{}", version.version); } } else { for (plugin, versions) in &versions .into_iter() - .group_by(|v| v.plugin.name().to_string()) + .group_by(|(_, v)| v.plugin_name.to_string()) { rtxprintln!(out, "{}", plugin); - for version in versions { - rtxprintln!(out, " {}", version.version); + for (_, tv) in versions { + rtxprintln!(out, " {}", tv.version); } } } diff --git a/src/cli/current.rs b/src/cli/current.rs index eef8880b2..a077e8153 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -26,19 +26,25 @@ impl Command for Current { let ts = ToolsetBuilder::new().build(&mut config)?; match &self.plugin { Some(plugin_name) => match config.plugins.get(plugin_name) { - Some(plugin) => self.one(ts, out, plugin), + Some(plugin) => self.one(&config, ts, out, plugin), None => { warn!("Plugin {} is not installed", plugin_name); Ok(()) } }, - None => self.all(ts, out), + None => self.all(&config, ts, out), } } } impl Current { - fn one(&self, ts: Toolset, out: &mut Output, plugin: &plugins::Plugins) -> Result<()> { + fn one( + &self, + config: &Config, + ts: Toolset, + out: &mut Output, + plugin: &plugins::Plugins, + ) -> Result<()> { match plugin { plugins::Plugins::External(plugin) => { if !plugin.is_installed() { @@ -47,8 +53,12 @@ impl Current { } } } - match ts.list_versions_by_plugin().get(plugin.name()) { - Some(versions) => { + match ts + .list_versions_by_plugin(config) + .into_iter() + .find(|(p, _)| p.name() == plugin.name()) + { + Some((_, versions)) => { rtxprintln!( out, "{}", @@ -66,26 +76,24 @@ impl Current { Ok(()) } - fn all(&self, ts: Toolset, out: &mut Output) -> Result<()> { - for (plugin, versions) in ts.list_versions_by_plugin() { + fn all(&self, config: &Config, ts: Toolset, out: &mut Output) -> Result<()> { + for (plugin, versions) in ts.list_versions_by_plugin(config) { if versions.is_empty() { continue; } - for rtv in &versions { - if !rtv.is_installed() { - let source = ts.versions.get(rtv.plugin.name()).unwrap().source.clone(); + for tv in versions { + if !plugin.is_version_installed(tv) { + let source = ts.versions.get(&tv.plugin_name).unwrap().source.clone(); warn!( "{}@{} is specified in {}, but not installed", - rtv.plugin.name(), - &rtv.version, - &source + tv.plugin_name, &tv.version, &source ); } } rtxprintln!( out, "{} {}", - &plugin, + plugin.name(), versions .iter() .map(|v| v.version.to_string()) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 47efbf27a..e8879bd66 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -57,7 +57,7 @@ impl Command for HookEnv { let output = hook_env::build_env_commands(&*shell, &patches); out.stdout.write(output); if self.status { - self.display_status(&ts, out); + self.display_status(&config, &ts, out); } Ok(()) @@ -65,12 +65,12 @@ impl Command for HookEnv { } impl HookEnv { - fn display_status(&self, ts: &Toolset, out: &mut Output) { + fn display_status(&self, config: &Config, ts: &Toolset, out: &mut Output) { let installed_versions = ts - .list_current_installed_versions() + .list_current_installed_versions(config) .into_iter() .rev() - .map(|v| v.to_string()) + .map(|(_, v)| v.to_string()) .collect_vec(); if !installed_versions.is_empty() && !*env::RTX_QUIET { let w = match terminal_size() { diff --git a/src/cli/install.rs b/src/cli/install.rs index 1d10363b0..8378304f1 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -6,7 +6,7 @@ use console::style; use rayon::prelude::*; use rayon::ThreadPoolBuilder; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; @@ -15,7 +15,7 @@ use crate::output::Output; use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; -use crate::toolset::{ToolVersion, ToolVersionType, ToolsetBuilder}; +use crate::toolset::{ToolVersionOptions, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; /// Install a runtime @@ -69,27 +69,36 @@ impl Command for Install { impl Install { fn install_runtimes(&self, mut config: Config, runtimes: &[RuntimeArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); - let mut tool_versions = vec![]; + let mut tool_version_requests = vec![]; let ts = ToolsetBuilder::new() .with_latest_versions() .build(&mut config)?; for runtime in RuntimeArg::double_runtime_condition(runtimes) { - match runtime.to_tool_version() { - Some(tv) => tool_versions.push(tv), + let default_opts = ToolVersionOptions::new(); + match runtime.tvr { + Some(tv) => tool_version_requests.push((runtime.plugin, tv, default_opts.clone())), None => { - if runtime.version == RuntimeArgVersion::None { + if runtime.tvr.is_none() { match ts.versions.get(&runtime.plugin) { Some(tvl) => { - for tv in &tvl.versions { - tool_versions.push(tv.clone()); + for (tvr, opts) in &tvl.requests { + tool_version_requests.push(( + runtime.plugin.clone(), + tvr.clone(), + opts.clone(), + )); } } None => { - let tv = ToolVersion::new( + let tvr = ToolVersionRequest::Version( runtime.plugin.clone(), - ToolVersionType::Version("latest".into()), + "latest".into(), ); - tool_versions.push(tv); + tool_version_requests.push(( + runtime.plugin, + tvr, + default_opts.clone(), + )); } } } @@ -100,13 +109,13 @@ impl Install { .num_threads(config.settings.jobs) .build()? .install(|| -> Result<()> { - let mut versions = vec![]; - for mut tv in tool_versions { - let plugin = match config.plugins.get(&tv.plugin_name).cloned() { + let mut tool_versions = vec![]; + for (plugin_name, tvr, opts) in tool_version_requests { + let plugin = match config.plugins.get(&plugin_name).cloned() { Some(plugin) => plugin, None => Arc::new(Plugins::External(ExternalPlugin::new( &config.settings, - &tv.plugin_name, + &plugin_name, ))), }; match plugin.as_ref() { @@ -120,56 +129,56 @@ impl Install { } } } - tv.resolve(&config, plugin, ts.latest_versions)?; - versions.push(tv.rtv.unwrap()); + let tv = tvr.resolve(&config, &plugin, opts, ts.latest_versions)?; + tool_versions.push((plugin, tv)); } - if versions.is_empty() { + if tool_versions.is_empty() { warn!("no runtimes to install"); warn!("specify a version with `rtx install @`"); return Ok(()); } let mut to_uninstall = vec![]; - for rtv in &versions { - if rtv.is_installed() { + for (plugin, tv) in &tool_versions { + if plugin.is_version_installed(tv) { if self.force { - to_uninstall.push(rtv.clone()); + to_uninstall.push((plugin, tv.clone())); } else { - warn!("{} already installed", style(rtv).cyan().for_stderr()); + warn!("{} already installed", style(tv).cyan().for_stderr()); } } } if !to_uninstall.is_empty() { to_uninstall .into_par_iter() - .map(|rtv| { + .map(|(plugin, tv)| { let mut pr = mpr.add(); - rtv.decorate_progress_bar(&mut pr); - match rtv.uninstall(&config.settings, &pr, false) { + plugin.decorate_progress_bar(&mut pr, Some(&tv)); + match plugin.uninstall_version(&config, &tv, &pr, false) { Ok(_) => { pr.finish(); Ok(()) } Err(err) => { pr.error(); - Err(err.wrap_err(format!("failed to uninstall {}", rtv))) + Err(err.wrap_err(format!("failed to uninstall {}", tv))) } } }) .collect::>>()?; } - versions + tool_versions .into_par_iter() - .map(|rtv| { - if rtv.is_installed() { + .map(|(plugin, tv)| { + if plugin.is_version_installed(&tv) { return Ok(()); } let mut pr = mpr.add(); - rtv.decorate_progress_bar(&mut pr); - match rtv.install(&config, &mut pr, self.force) { + plugin.decorate_progress_bar(&mut pr, Some(&tv)); + match plugin.install_version(&config, &tv, &mut pr, self.force) { Ok(_) => Ok(()), Err(err) => { pr.error(); - Err(err.wrap_err(format!("failed to install {}", rtv))) + Err(err.wrap_err(format!("failed to install {}", tv))) } } }) @@ -197,7 +206,7 @@ impl Install { } } } - if ts.list_missing_versions().is_empty() { + if ts.list_missing_versions(&config).is_empty() { warn!("no runtimes to install"); } let mpr = MultiProgressReport::new(config.settings.verbose); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 4b79fb157..d4fb7aec4 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,11 +1,12 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::Plugin; +use crate::toolset::ToolVersionRequest; /// Gets the latest available version for a plugin #[derive(Debug, clap::Args)] @@ -24,9 +25,9 @@ pub struct Latest { impl Command for Latest { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let mut prefix = match self.runtime.version { - RuntimeArgVersion::None => self.asdf_version, - RuntimeArgVersion::Version(version) => Some(version), + let mut prefix = match self.runtime.tvr { + None => self.asdf_version, + Some(ToolVersionRequest::Version(_, version)) => Some(version), _ => Err(eyre!( "invalid version: {}", style(&self.runtime).cyan().for_stderr() diff --git a/src/cli/local.rs b/src/cli/local.rs index 5e284ae8f..4e5da71b1 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -142,7 +142,7 @@ pub fn local( fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result<()> { let mut ts = cf.to_toolset().clone(); ts.resolve(config); - if !ts.list_missing_versions().is_empty() { + if !ts.list_missing_versions(config).is_empty() { let mpr = MultiProgressReport::new(config.settings.verbose); ts.install_missing(config, mpr)?; } @@ -292,7 +292,7 @@ mod tests { let stdout = assert_cli!("local"); assert_str_eq!(grep(stdout, "dummy"), "dummy m"); let stdout = assert_cli!("current", "dummy"); - assert_str_eq!(grep(stdout, "dummy"), "~/data/installs/dummy/1.1.0"); + assert_str_eq!(grep(stdout, "dummy"), "path:~/data/installs/dummy/1.1.0"); }); } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index d7d3fbfff..832665be3 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -1,6 +1,7 @@ use std::cmp::max; use std::collections::HashMap; use std::path::PathBuf; +use std::sync::Arc; use color_eyre::eyre::Result; use console::style; @@ -15,9 +16,8 @@ use crate::config::Config; use crate::env::DUMB_TERMINAL; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::{Plugin, PluginName}; -use crate::runtimes::RuntimeVersion; -use crate::toolset::{ToolSource, ToolsetBuilder}; +use crate::plugins::{Plugin, PluginName, Plugins}; +use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; /// List installed runtime versions /// @@ -53,7 +53,7 @@ impl Command for Ls { let mut runtimes = get_runtime_list(&mut config, &self.plugin)?; if self.current { - runtimes.retain(|(_, source)| source.is_some()); + runtimes.retain(|(_, _, source)| source.is_some()); } if self.json { self.display_json(runtimes, out) @@ -65,7 +65,7 @@ impl Command for Ls { } } -type JSONOutput = IndexMap>; +type JSONOutput = IndexMap>; #[derive(Serialize)] struct JSONRuntime { @@ -88,20 +88,16 @@ impl Ls { Ok(()) } - fn display_json( - &self, - runtimes: Vec<(RuntimeVersion, Option)>, - out: &mut Output, - ) -> Result<()> { + fn display_json(&self, runtimes: Vec, out: &mut Output) -> Result<()> { let mut plugins = JSONOutput::new(); for (plugin_name, runtimes) in &runtimes .into_iter() - .group_by(|(rtv, _)| rtv.plugin.name().clone()) + .group_by(|(p, _, _)| p.name().to_string()) { let runtimes = runtimes - .map(|(rtv, source)| JSONRuntime { - version: rtv.version, - install_path: rtv.install_path, + .map(|(p, tv, source)| JSONRuntime { + install_path: p.install_path(&tv), + version: tv.version, source: source.map(|source| source.as_json()), }) .collect(); @@ -110,27 +106,23 @@ impl Ls { out.stdout.writeln(serde_json::to_string_pretty(&runtimes)?); return Ok(()); } - plugins.insert(plugin_name, runtimes); + plugins.insert(plugin_name.clone(), runtimes); } out.stdout.writeln(serde_json::to_string_pretty(&plugins)?); Ok(()) } - fn display_parseable( - &self, - runtimes: Vec<(RuntimeVersion, Option)>, - out: &mut Output, - ) -> Result<()> { + fn display_parseable(&self, runtimes: Vec, out: &mut Output) -> Result<()> { runtimes .into_iter() - .map(|(rtv, _)| rtv) - .filter(|rtv| rtv.is_installed()) - .for_each(|rtv| { + .map(|(p, tv, _)| (p, tv)) + .filter(|(p, tv)| p.is_version_installed(tv)) + .for_each(|(_, tv)| { if self.plugin.is_some() { // only displaying 1 plugin so only show the version - rtxprintln!(out, "{}", rtv.version); + rtxprintln!(out, "{}", tv.version); } else { - rtxprintln!(out, "{} {}", rtv.plugin.name(), rtv.version); + rtxprintln!(out, "{} {}", tv.plugin_name, tv.version); } }); Ok(()) @@ -138,14 +130,14 @@ impl Ls { fn display_user( &self, - runtimes: Vec<(RuntimeVersion, Option)>, + runtimes: Vec<(Arc, ToolVersion, Option)>, out: &mut Output, ) -> Result<()> { - for (rtv, source) in runtimes { + for (p, tv, source) in runtimes { rtxprintln!( out, "{} {} {}", - match rtv.is_installed() && source.is_some() { + match p.is_version_installed(&tv) && source.is_some() { true => if *DUMB_TERMINAL { "->" @@ -154,7 +146,7 @@ impl Ls { }, false => " ", }, - styled_version(&rtv, !rtv.is_installed(), source.is_some()), + styled_version(&tv, !p.is_version_installed(&tv), source.is_some()), match source { Some(source) => format!("(set by {source})"), None => "".into(), @@ -165,55 +157,52 @@ impl Ls { } } -fn styled_version(rtv: &RuntimeVersion, missing: bool, active: bool) -> String { +fn styled_version(tv: &ToolVersion, missing: bool, active: bool) -> String { let styled = if missing { - style(&rtv.version).strikethrough().red().to_string() + style(&tv.version).strikethrough().red().to_string() + style(" (missing)").red().to_string().as_str() } else if active { - style(&rtv.version).green().to_string() + style(&tv.version).green().to_string() } else { - style(&rtv.version).dim().to_string() + style(&tv.version).dim().to_string() }; let unstyled = if missing { - format!("{} {} (missing)", &rtv.plugin.name(), &rtv.version) + format!("{} {} (missing)", &tv.plugin_name, &tv.version) } else { - format!("{} {}", &rtv.plugin.name(), &rtv.version) + format!("{} {}", &tv.plugin_name, &tv.version) }; let pad = max(0, 25 - unstyled.len() as isize) as usize; format!( "{} {}{}", - style(&rtv.plugin.name()).cyan(), + style(&tv.plugin_name).cyan(), styled, " ".repeat(pad) ) } +type RuntimeRow = (Arc, ToolVersion, Option); + fn get_runtime_list( config: &mut Config, plugin_flag: &Option, -) -> Result)>> { +) -> Result> { let ts = ToolsetBuilder::new().build(config)?; - let mut versions: HashMap<(PluginName, String), RuntimeVersion> = ts + let mut versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = ts .list_installed_versions(config)? .into_iter() - .filter(|rtv| match plugin_flag { - Some(plugin) => rtv.plugin.name() == plugin, + .filter(|(p, _)| match plugin_flag { + Some(plugin) => p.name() == plugin, None => true, }) - .map(|rtv| ((rtv.plugin.name().clone(), rtv.version.clone()), rtv)) + .map(|(p, tv)| ((p.name().clone(), tv.version.clone()), (p, tv))) .collect(); let active = ts - .list_current_versions() + .list_current_versions(config) .into_iter() - .map(|rtv| { - ( - (rtv.plugin.name().clone(), rtv.version.clone()), - rtv.clone(), - ) - }) - .collect::>(); + .map(|(p, tv)| ((p.name().clone(), tv.version.clone()), (p, tv))) + .collect::, ToolVersion)>>(); versions.extend( active @@ -223,23 +212,20 @@ fn get_runtime_list( Some(plugin) => plugin_name == plugin, None => true, }) - .collect::>(), + .collect::, ToolVersion))>>(), ); - let rvs: Vec<(RuntimeVersion, Option)> = versions + let rvs: Vec = versions .into_iter() .sorted_by_cached_key(|((plugin_name, version), _)| { (plugin_name.clone(), Versioning::new(version)) }) - .map(|(k, rtv)| { + .map(|(k, (p, tv))| { let source = match &active.get(&k) { - Some(rtv) => ts - .versions - .get(rtv.plugin.name()) - .map(|tv| tv.source.clone()), + Some((_, tv)) => ts.versions.get(&tv.plugin_name).map(|tv| tv.source.clone()), None => None, }; - (rtv, source) + (p, tv, source) }) .collect(); diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index ff7934848..ca0c6768d 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,11 +1,12 @@ use color_eyre::eyre::Result; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; use crate::plugins::Plugin; +use crate::toolset::ToolVersionRequest; /// List runtime versions available for install /// @@ -32,8 +33,8 @@ impl Command for LsRemote { .ok_or(PluginNotInstalled(self.plugin.plugin))?; plugin.clear_remote_version_cache()?; - let prefix = match self.plugin.version { - RuntimeArgVersion::Version(v) => Some(v), + let prefix = match self.plugin.tvr { + Some(ToolVersionRequest::Version(_, v)) => Some(v), _ => self.prefix, }; diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index f8ac053c8..e60dc0d0f 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -121,7 +121,7 @@ impl PluginsInstall { mpr.warn(format!("plugin {} already installed", name)); } else { let mut pr = mpr.add(); - plugin.decorate_progress_bar(&mut pr); + plugin.decorate_progress_bar(&mut pr, None); plugin.install(config, &mut pr, self.force)?; } Ok(()) diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index caf86a6d0..ad3dbd2bc 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -38,7 +38,7 @@ impl PluginsUninstall { match plugin { Some(plugin) if plugin.is_installed() => { let mut pr = mpr.add(); - plugin.decorate_progress_bar(&mut pr); + plugin.decorate_progress_bar(&mut pr, None); plugin.uninstall(&pr)?; pr.finish_with_message("uninstalled".into()); } diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 3b63bb56b..3f075bdc6 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -1,13 +1,13 @@ use color_eyre::eyre::Result; use console::style; use indexmap::IndexMap; +use std::sync::Arc; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::{Plugin, PluginName}; -use crate::runtimes::RuntimeVersion; -use crate::toolset::ToolsetBuilder; +use crate::plugins::{Plugin, PluginName, Plugins}; +use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; /// Delete unused versions of tools @@ -34,35 +34,39 @@ impl Command for Prune { let mut to_delete = ts .list_installed_versions(&config)? .into_iter() - .map(|rtv| (rtv.to_string(), rtv)) - .collect::>(); + .map(|(p, tv)| (tv.to_string(), (p, tv))) + .collect::, ToolVersion)>>(); if let Some(plugins) = &self.plugins { - to_delete.retain(|_, rtv| plugins.contains(rtv.plugin.name())); + to_delete.retain(|_, (_, tv)| plugins.contains(&tv.plugin_name)); } for cf in config.get_tracked_config_files()?.values() { let mut ts = cf.to_toolset().clone(); - ts.resolve(&config); - for rtv in ts.list_current_versions() { - to_delete.remove(&rtv.to_string()); + ts.resolve(&mut config); + for (_, tv) in ts.list_current_versions(&config) { + to_delete.remove(&tv.to_string()); } } - self.delete(&config, to_delete.into_values().collect()) + self.delete(&mut config, to_delete.into_values().collect()) } } impl Prune { - fn delete(&self, config: &Config, to_delete: Vec) -> Result<()> { + fn delete( + &self, + config: &mut Config, + to_delete: Vec<(Arc, ToolVersion)>, + ) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); - for rtv in to_delete { + for (p, tv) in to_delete { let mut pr = mpr.add(); - rtv.decorate_progress_bar(&mut pr); + p.decorate_progress_bar(&mut pr, Some(&tv)); if self.dry_run { pr.set_prefix(format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); } - rtv.uninstall(&config.settings, &pr, self.dry_run)?; + p.uninstall_version(config, &tv, &pr, self.dry_run)?; pr.finish(); } Ok(()) diff --git a/src/cli/shell.rs b/src/cli/shell.rs index b35074dca..41d48c7fc 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -37,14 +37,14 @@ impl Command for Shell { } let shell = get_shell(None).expect("no shell detected"); - for rtv in ts.list_current_installed_versions() { - let source = &ts.versions.get(rtv.plugin.name()).unwrap().source; + for (p, tv) in ts.list_current_installed_versions(&config) { + let source = &ts.versions.get(p.name()).unwrap().source; if matches!(source, ToolSource::Argument) { - let k = format!("RTX_{}_VERSION", rtv.plugin.name().to_uppercase()); + let k = format!("RTX_{}_VERSION", p.name().to_uppercase()); let op = if self.unset { shell.unset_env(&k) } else { - shell.set_env(&k, &rtv.version) + shell.set_env(&k, &tv.version) }; out.stdout.writeln(op); } diff --git a/src/cli/snapshots/rtx__cli__current__tests__current.snap b/src/cli/snapshots/rtx__cli__current__tests__current.snap index f8468a445..69c3025d5 100644 --- a/src/cli/snapshots/rtx__cli__current__tests__current.snap +++ b/src/cli/snapshots/rtx__cli__current__tests__current.snap @@ -3,5 +3,5 @@ source: src/cli/current.rs expression: output --- tiny 3.1.0 -dummy ref-master +dummy ref:master diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap b/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap index 73f17be11..ceae61a97 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap @@ -2,5 +2,5 @@ source: src/cli/local.rs expression: output --- -ref-master +ref:master diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap index 7b7b4737b..900ee3d84 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap @@ -2,7 +2,7 @@ source: src/cli/ls.rs expression: output --- --> dummy ref-master (set by ~/.test-tool-versions) +-> dummy ref:master (set by ~/.test-tool-versions) tiny 2.0.0 -> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap index 94b78cf02..41e660126 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap @@ -2,7 +2,7 @@ source: src/cli/ls.rs expression: output --- --> dummy ref-master (set by ~/.test-tool-versions) +-> dummy ref:master (set by ~/.test-tool-versions) tiny 2.0.0 tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap index 26eedac31..1498e06a0 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref-master (set by ~/.test-tool-versions) +-> dummy ref:master (set by ~/.test-tool-versions) tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap index 4a88870a3..0aace8b3e 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref-master (set by ~/.test-tool-versions) +-> dummy ref:master (set by ~/.test-tool-versions) -> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap index 4a88870a3..0aace8b3e 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref-master (set by ~/.test-tool-versions) +-> dummy ref:master (set by ~/.test-tool-versions) -> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap index 4a88870a3..0aace8b3e 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref-master (set by ~/.test-tool-versions) +-> dummy ref:master (set by ~/.test-tool-versions) -> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap index 8da1162e2..9b90e51c5 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap @@ -5,7 +5,7 @@ expression: output { "dummy": [ { - "version": "ref-master", + "version": "ref:master", "install_path": "~/data/installs/dummy/ref-master", "source": { "type": ".tool-versions", diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap index a88b0d8c2..65e52d29f 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- -dummy ref-master +dummy ref:master tiny 3.1.0 diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index ff21f54b2..430ee9b04 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -5,7 +5,7 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::toolset::ToolsetBuilder; +use crate::plugins::Plugin; use crate::ui::multi_progress_report::MultiProgressReport; /// Removes runtime versions @@ -18,25 +18,35 @@ pub struct Uninstall { } impl Command for Uninstall { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { let runtimes = RuntimeArg::double_runtime_condition(&self.runtime); - let ts = ToolsetBuilder::new() - .with_args(&runtimes) - .build(&mut config)?; - let runtime_versions = runtimes.iter().filter_map(|a| ts.resolve_runtime_arg(a)); + let tool_versions = runtimes + .iter() + .map(|a| { + let plugin = match config.plugins.get(&a.plugin) { + Some(plugin) => plugin, + None => todo!(), + }; + let tv = match &a.tvr { + Some(tvr) => tvr.resolve(&config, plugin, Default::default(), false)?, + None => todo!(), + }; + Ok((plugin, tv)) + }) + .collect::>>()?; let mpr = MultiProgressReport::new(config.settings.verbose); - for rtv in runtime_versions { - if !rtv.is_installed() { - warn!("{} is not installed", style(rtv).cyan().for_stderr()); + for (plugin, tv) in tool_versions { + if !plugin.is_version_installed(&tv) { + warn!("{} is not installed", style(&tv).cyan().for_stderr()); continue; } let mut pr = mpr.add(); - rtv.decorate_progress_bar(&mut pr); - if let Err(err) = rtv.uninstall(&config.settings, &pr, false) { + plugin.decorate_progress_bar(&mut pr, Some(&tv)); + if let Err(err) = plugin.uninstall_version(&config, &tv, &pr, false) { pr.error(); - return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", rtv))); + return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", &tv))); } pr.finish_with_message("uninstalled".into()); } diff --git a/src/cli/where.rs b/src/cli/where.rs index 1007cc031..87078b136 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,10 +1,11 @@ use color_eyre::eyre::Result; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser, RuntimeArgVersion}; +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; -use crate::errors::Error::VersionNotInstalled; +use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; use crate::output::Output; +use crate::plugins::Plugin; use crate::toolset::ToolsetBuilder; /// Display the installation path for a runtime @@ -30,27 +31,42 @@ pub struct Where { impl Command for Where { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let runtime = match self.runtime.version { - RuntimeArgVersion::None => match self.asdf_version { - Some(version) => self - .runtime - .with_version(RuntimeArgVersion::Version(version)), - None => self.runtime, + let runtime = match self.runtime.tvr { + None => match self.asdf_version { + Some(version) => self.runtime.with_version(&version), + None => { + let ts = ToolsetBuilder::new() + .with_args(&[self.runtime.clone()]) + .build(&mut config)?; + let v = ts + .versions + .get(&self.runtime.plugin) + .and_then(|v| v.requests.first()) + .map(|(r, _)| r.version()); + self.runtime + .with_version(&v.unwrap_or(String::from("latest"))) + } }, _ => self.runtime, }; - let ts = ToolsetBuilder::new() - .with_args(&[runtime.clone()]) - .build(&mut config)?; - match ts.resolve_runtime_arg(&runtime) { - Some(rtv) if rtv.is_installed() => { - rtxprintln!(out, "{}", rtv.install_path.to_string_lossy()); + let plugin = match config.plugins.get(&runtime.plugin) { + Some(plugin) => plugin, + None => Err(PluginNotInstalled(runtime.plugin.clone()))?, + }; + + match runtime + .tvr + .as_ref() + .map(|tvr| tvr.resolve(&config, plugin, Default::default(), false)) + { + Some(Ok(tv)) if plugin.is_version_installed(&tv) => { + rtxprintln!(out, "{}", plugin.install_path(&tv).to_string_lossy()); Ok(()) } _ => Err(VersionNotInstalled( runtime.plugin.to_string(), - runtime.version.to_string(), + runtime.tvr.map(|tvr| tvr.version()).unwrap_or_default(), ))?, } } diff --git a/src/cli/which.rs b/src/cli/which.rs index fc49583a7..deacb5e88 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -27,13 +27,13 @@ impl Command for Which { let ts = ToolsetBuilder::new().build(&mut config)?; match ts.which(&config, &self.bin_name) { - Some(rtv) => { + Some((p, tv)) => { if self.version { - rtxprintln!(out, "{}", rtv.version); + rtxprintln!(out, "{}", tv.version); } else if self.plugin { - rtxprintln!(out, "{}", rtv.plugin.name()); + rtxprintln!(out, "{}", p.name()); } else { - let path = rtv.which(&config.settings, &self.bin_name)?; + let path = p.which(&config, &tv, &self.bin_name)?; rtxprintln!(out, "{}", path.unwrap().display()); } Ok(()) diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 7f0e673a5..1162b938d 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -9,7 +9,7 @@ use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, Settings}; use crate::plugins::{Plugin, PluginName, Plugins}; -use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; +use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; #[derive(Debug)] pub struct LegacyVersionFile { @@ -91,30 +91,10 @@ impl Display for LegacyVersionFile { fn build_toolset(path: &Path, plugin: &str, version: &str) -> Toolset { let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.to_path_buf())); if !version.is_empty() { - toolset.add_version(ToolVersion::new( - plugin.to_string(), - ToolVersionType::Version(version.to_string()), - )); + toolset.add_version( + ToolVersionRequest::new(plugin.to_string(), version), + Default::default(), + ); } toolset } - -#[cfg(test)] -mod tests { - use super::*; - use crate::plugins::ExternalPlugin; - - #[test] - fn test_legacy_file() { - let settings = Settings::default(); - let path = PathBuf::from("tiny-legacy").join(".rtx-tiny-version"); - let plugin = Plugins::External(ExternalPlugin::new(&settings, &PluginName::from("tiny"))); - let cf = LegacyVersionFile::parse(&settings, path, &plugin).unwrap(); - let tvl = cf.to_toolset().versions.get("tiny").unwrap(); - let version = match tvl.versions[0].r#type { - ToolVersionType::Version(ref v) => v, - _ => panic!("Unexpected version type"), - }; - assert_eq!(version, "2"); - } -} diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index d860aaf9b..7b4e3d5b8 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -7,7 +7,7 @@ use color_eyre::eyre::{eyre, Result}; use tool_versions::ToolVersions; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; +use crate::cli::args::runtime::RuntimeArg; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, Config, Settings}; @@ -55,10 +55,11 @@ impl dyn ConfigFile { ) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); let mut ts = self.to_toolset().to_owned(); + ts.resolve(config); ts.latest_versions = true; let mut plugins_to_update = HashMap::new(); for runtime in runtimes { - if let Some(tv) = runtime.to_tool_version() { + if let Some(tv) = &runtime.tvr { plugins_to_update .entry(runtime.plugin.clone()) .or_insert_with(Vec::new) @@ -66,8 +67,11 @@ impl dyn ConfigFile { } } for (plugin, versions) in &plugins_to_update { - let mut tvl = ToolVersionList::new(ts.source.as_ref().unwrap().clone()); - tvl.versions = versions.clone(); + let mut tvl = + ToolVersionList::new(plugin.to_string(), ts.source.as_ref().unwrap().clone()); + for tv in versions { + tvl.requests.push(((*tv).clone(), Default::default())); + } ts.versions.insert(plugin.clone(), tvl); } ts.resolve(config); @@ -75,13 +79,14 @@ impl dyn ConfigFile { for (plugin, versions) in plugins_to_update { let versions = versions .into_iter() - .map(|mut tv| { + .map(|tvr| { if pin { let plugin = config.plugins.get(&plugin).unwrap(); - tv.resolve(config, plugin.clone(), ts.latest_versions)?; - Ok(tv.rtv.unwrap().version) + let tv = + tvr.resolve(config, plugin, Default::default(), ts.latest_versions)?; + Ok(tv.version) } else { - Ok(tv.r#type.to_string()) + Ok(tvr.version()) } }) .collect::>>()?; @@ -96,7 +101,7 @@ impl dyn ConfigFile { /// returns "true" if the runtime was displayed which means the CLI should exit pub fn display_runtime(&self, out: &mut Output, runtimes: &[RuntimeArg]) -> Result { // in this situation we just print the current version in the config file - if runtimes.len() == 1 && runtimes[0].version == RuntimeArgVersion::None { + if runtimes.len() == 1 && runtimes[0].tvr.is_none() { let plugin = &runtimes[0].plugin; let tvl = self .to_toolset() @@ -109,18 +114,15 @@ impl dyn ConfigFile { display_path(self.get_path()) ) })? - .versions + .requests .iter() - .map(|tv| tv.r#type.to_string()) + .map(|(tvr, _)| tvr.version()) .collect::>(); rtxprintln!(out, "{}", tvl.join(" ")); return Ok(true); } // check for something like `rtx local nodejs python@latest` which is invalid - if runtimes - .iter() - .any(|r| r.version == RuntimeArgVersion::None) - { + if runtimes.iter().any(|r| r.tvr.is_none()) { return Err(eyre!("invalid input, specify a version for each runtime. Or just specify one runtime to print the current version")); } Ok(false) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 3d10fc294..dd4d35693 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -17,7 +17,9 @@ use crate::errors::Error::UntrustedConfig; use crate::file::create_dir_all; use crate::plugins::PluginName; use crate::tera::{get_tera, BASE_CONTEXT}; -use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType, Toolset}; +use crate::toolset::{ + ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, +}; use crate::{dirs, env, parse_error}; #[derive(Debug, Default)] @@ -206,7 +208,7 @@ 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.into())?; + let tvl = self.parse_tool_version_list(&k, v, &plugin.to_string())?; toolset.versions.insert(plugin.into(), tvl); } Ok(toolset) @@ -222,15 +224,15 @@ impl RtxToml { plugin_name: &PluginName, ) -> Result { let source = ToolSource::RtxToml(self.path.clone()); - let mut tool_version_list = ToolVersionList::new(source); + let mut tool_version_list = ToolVersionList::new(plugin_name.to_string(), source); match v { Item::ArrayOfTables(v) => { for table in v.iter() { for (tool, v) in table.iter() { let k = format!("{}.{}", key, tool); - let tv = self.parse_tool_version(&k, v, plugin_name)?; - tool_version_list.versions.push(tv); + let (tvr, opts) = self.parse_tool_version(&k, v, plugin_name)?; + tool_version_list.requests.push((tvr, opts)); } } } @@ -238,20 +240,22 @@ impl RtxToml { Some(v) => { for v in v.iter() { let item = Item::Value(v.clone()); - let tv = self.parse_tool_version(key, &item, plugin_name)?; - tool_version_list.versions.push(tv); + let (tvr, opts) = self.parse_tool_version(key, &item, plugin_name)?; + tool_version_list.requests.push((tvr, opts)); } } _ => { - tool_version_list - .versions - .push(self.parse_tool_version(key, v, plugin_name)?) + tool_version_list.requests.push(self.parse_tool_version( + key, + v, + plugin_name, + )?); } }, } - for v in tool_version_list.versions.iter() { - if let ToolVersionType::Path(_) = v.r#type { + for (tvr, _) in &tool_version_list.requests { + if let ToolVersionRequest::Path(_, _) = tvr { // "path:" can be dangerous to run automatically self.trust_check()?; } @@ -265,36 +269,40 @@ impl RtxToml { key: &str, v: &Item, plugin_name: &PluginName, - ) -> Result { - let mut tv = ToolVersion::new(plugin_name.clone(), ToolVersionType::System); + ) -> Result<(ToolVersionRequest, ToolVersionOptions)> { + let mut tv = ToolVersionRequest::new(plugin_name.clone(), "system"); + let mut opts = ToolVersionOptions::default(); match v.as_table_like() { Some(table) => { if let Some(v) = table.get("version") { match v { Item::Value(v) => { - tv.r#type = self.parse_tool_version_value(key, v)?; + tv = self.parse_tool_version_request(key, v, plugin_name)?; } _ => parse_error!(format!("{}.version", key), v, "string")?, } } else if let Some(path) = table.get("path") { match path.as_str() { Some(s) => { - tv.r#type = ToolVersionType::Path(s.into()); + let s = self.parse_template(key, s)?; + tv = ToolVersionRequest::Path(plugin_name.clone(), s.into()); } _ => parse_error!(format!("{}.path", key), v, "string")?, } } else if let Some(prefix) = table.get("prefix") { match prefix.as_str() { Some(s) => { - tv.r#type = ToolVersionType::Prefix(s.into()); + let s = self.parse_template(key, s)?; + tv = ToolVersionRequest::Prefix(plugin_name.clone(), s); } _ => parse_error!(format!("{}.prefix", key), v, "string")?, } } else if let Some(r) = table.get("ref") { match r.as_str() { Some(s) => { - tv.r#type = ToolVersionType::Ref(s.into()); + let s = self.parse_template(key, s)?; + tv = ToolVersionRequest::Ref(plugin_name.clone(), s); } _ => parse_error!(format!("{}.ref", key), v, "string")?, } @@ -307,7 +315,8 @@ impl RtxToml { } match v.as_str() { Some(s) => { - tv.options.insert(k.into(), s.into()); + let s = self.parse_template(key, s)?; + opts.insert(k.into(), s); } _ => parse_error!(format!("{}.{}", key, k), v, "string")?, } @@ -315,28 +324,25 @@ impl RtxToml { } _ => match v { Item::Value(v) => { - tv.r#type = self.parse_tool_version_value(key, v)?; + tv = self.parse_tool_version_request(key, v, plugin_name)?; } _ => parse_error!(key, v, "value")?, }, } - Ok(tv) + Ok((tv, opts)) } - fn parse_tool_version_value(&mut self, key: &str, v: &Value) -> Result { + fn parse_tool_version_request( + &mut self, + key: &str, + v: &Value, + plugin_name: &PluginName, + ) -> Result { match v.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - match s.split_once(':') { - Some(("prefix", v)) => Ok(ToolVersionType::Prefix(v.into())), - Some(("path", v)) => Ok(ToolVersionType::Path(v.into())), - Some(("ref", v)) => Ok(ToolVersionType::Ref(v.into())), - Some((unknown, v)) => { - parse_error!(format!("{}.{}", key, unknown), v, "prefix, path, or ref")? - } - None => Ok(ToolVersionType::Version(s)), - } + Ok(ToolVersionRequest::new(plugin_name.clone(), &s)) } _ => parse_error!(key, v, "string")?, } @@ -632,9 +638,14 @@ impl ConfigFile for RtxToml { fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { if let Some(plugin) = self.toolset.versions.get_mut(plugin_name) { - plugin.versions = versions + plugin.requests = versions .iter() - .map(|v| ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v.clone()))) + .map(|s| { + ( + ToolVersionRequest::new(plugin_name.clone(), s), + Default::default(), + ) + }) .collect(); } let tools = self diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index 20fea82cf..e2d1f2d0f 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -5,109 +5,110 @@ expression: "replace_path(&format!(\"{:#?}\", cf.toolset))" Toolset { versions: { "terraform": ToolVersionList { - versions: [ - ToolVersion { - plugin_name: "terraform", - type: Version( + plugin_name: "terraform", + versions: [], + requests: [ + ( + Version( + "terraform", "1.0.0", ), - rtv: None, - options: {}, - }, + {}, + ), ], source: RtxToml( "~/fixtures/.rtx.toml", ), }, "nodejs": ToolVersionList { - versions: [ - ToolVersion { - plugin_name: "nodejs", - type: Version( + plugin_name: "nodejs", + versions: [], + requests: [ + ( + Version( + "nodejs", "16", ), - rtv: None, - options: {}, - }, - ToolVersion { - plugin_name: "nodejs", - type: Prefix( + {}, + ), + ( + Prefix( + "nodejs", "18", ), - rtv: None, - options: {}, - }, - ToolVersion { - plugin_name: "nodejs", - type: Ref( + {}, + ), + ( + Ref( + "nodejs", "master", ), - rtv: None, - options: {}, - }, - ToolVersion { - plugin_name: "nodejs", - type: Path( + {}, + ), + ( + Path( + "nodejs", "~/.nodes/14", ), - rtv: None, - options: {}, - }, + {}, + ), ], source: RtxToml( "~/fixtures/.rtx.toml", ), }, "jq": ToolVersionList { - versions: [ - ToolVersion { - plugin_name: "jq", - type: Prefix( + plugin_name: "jq", + versions: [], + requests: [ + ( + Prefix( + "jq", "1.6", ), - rtv: None, - options: {}, - }, + {}, + ), ], source: RtxToml( "~/fixtures/.rtx.toml", ), }, "shellcheck": ToolVersionList { - versions: [ - ToolVersion { - plugin_name: "shellcheck", - type: Version( + plugin_name: "shellcheck", + versions: [], + requests: [ + ( + Version( + "shellcheck", "0.9.0", ), - rtv: None, - options: {}, - }, + {}, + ), ], source: RtxToml( "~/fixtures/.rtx.toml", ), }, "python": ToolVersionList { - versions: [ - ToolVersion { - plugin_name: "python", - type: Version( + plugin_name: "python", + versions: [], + requests: [ + ( + Version( + "python", "3.10.0", ), - rtv: None, - options: { + { "venv": ".venv", }, - }, - ToolVersion { - plugin_name: "python", - type: Version( + ), + ( + Version( + "python", "3.9.0", ), - rtv: None, - options: {}, - }, + {}, + ), ], source: RtxToml( "~/fixtures/.rtx.toml", diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index 734da11e2..0efbd05e0 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -5,23 +5,23 @@ expression: cf.toolset Toolset { versions: { "nodejs": ToolVersionList { - versions: [ - ToolVersion { - plugin_name: "nodejs", - type: Version( + plugin_name: "nodejs", + versions: [], + requests: [ + ( + Version( + "nodejs", "16.0.1", ), - rtv: None, - options: {}, - }, - ToolVersion { - plugin_name: "nodejs", - type: Version( + {}, + ), + ( + Version( + "nodejs", "18.0.1", ), - rtv: None, - options: {}, - }, + {}, + ), ], source: RtxToml( "/tmp/.rtx.toml", diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 762c0b0ed..76ccaf6df 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -16,7 +16,7 @@ use crate::config::settings::SettingsBuilder; use crate::file::display_path; use crate::plugins::PluginName; use crate::tera::{get_tera, BASE_CONTEXT}; -use crate::toolset::{ToolSource, ToolVersion, ToolVersionType, Toolset}; +use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; // python 3.11.0 3.10.0 // shellcheck 0.9.0 @@ -122,15 +122,8 @@ impl ToolVersions { fn populate_toolset(&mut self) { for (plugin, tvp) in &self.plugins { for version in &tvp.versions { - let v = match version.split_once(':') { - Some(("prefix", v)) => ToolVersionType::Prefix(v.to_string()), - Some(("ref", v)) => ToolVersionType::Ref(v.to_string()), - Some(("path", v)) => ToolVersionType::Path(PathBuf::from(v)), - None if version == "system" => ToolVersionType::System, - _ => ToolVersionType::Version(version.to_string()), - }; - self.toolset - .add_version(ToolVersion::new(plugin.clone(), v)); + let tvr = ToolVersionRequest::new(plugin.clone(), version); + self.toolset.add_version(tvr, Default::default()) } } } diff --git a/src/lib.rs b/src/lib.rs index 050389f45..726e76e62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,6 @@ mod hook_env; mod lock_file; mod plugins; mod runtime_symlinks; -mod runtimes; mod shell; mod shims; mod shorthands; diff --git a/src/main.rs b/src/main.rs index bdf0c3264..8f0046252 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,6 @@ mod lock_file; mod logger; mod plugins; mod runtime_symlinks; -pub mod runtimes; mod shell; mod shims; mod shorthands; diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ef650c0bb..cf7b95a99 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -1,4 +1,7 @@ +use std::collections::HashMap; use std::fs; +use std::fs::{remove_file, File}; +use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; @@ -7,28 +10,31 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; use indexmap::IndexMap; use itertools::Itertools; +use once_cell::sync::Lazy; use versions::Versioning; use crate::cache::CacheManager; use crate::cmd::cmd; use crate::config::{Config, Settings}; use crate::env::PREFER_STALE; +use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; -use crate::fake_asdf::get_path_with_fake_asdf; -use crate::file::display_path; use crate::file::remove_all; +use crate::file::{create_dir_all, display_path, remove_all_with_warning}; use crate::git::Git; use crate::hash::hash_to_str; use crate::lock_file::LockFile; +use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::rtx_plugin_toml::RtxPluginToml; -use crate::plugins::Script::ParseLegacyFile; +use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; use crate::plugins::{Plugin, PluginName, Script, ScriptManager}; use crate::runtime_symlinks::is_runtime_symlink; +use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; -use crate::{dirs, file}; +use crate::{dirs, env, file}; /// This represents a plugin installed to ~/.local/share/rtx/plugins -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ExternalPlugin { pub name: PluginName, pub plugin_path: PathBuf, @@ -39,6 +45,7 @@ pub struct ExternalPlugin { downloads_path: PathBuf, installs_path: PathBuf, script_man: ScriptManager, + cache: ExternalPluginCache, remote_version_cache: CacheManager>, latest_stable_cache: CacheManager>, alias_cache: CacheManager>, @@ -61,6 +68,7 @@ impl ExternalPlugin { script_man: build_script_man(settings, name, &plugin_path), downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), + cache: ExternalPluginCache::default(), remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) .with_fresh_duration(fresh_duration) .with_fresh_file(plugin_path.clone()) @@ -95,7 +103,7 @@ impl ExternalPlugin { } pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { - self.decorate_progress_bar(pr); + self.decorate_progress_bar(pr, None); let repository = self .repo_url .as_ref() @@ -103,7 +111,7 @@ impl ExternalPlugin { .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; debug!("install {} {:?}", self.name, repository); - let _lock = self.get_lock(force)?; + let _lock = self.get_lock(&self.plugin_path, force)?; if self.is_installed() { self.uninstall(pr)?; @@ -323,11 +331,11 @@ impl ExternalPlugin { Ok(()) } - fn get_lock(&self, force: bool) -> Result> { + fn get_lock(&self, path: &Path, force: bool) -> Result> { let lock = if force { None } else { - let lock = LockFile::new(&self.plugin_path) + let lock = LockFile::new(path) .with_callback(|l| { debug!("waiting for lock on {}", display_path(l)); }) @@ -336,17 +344,116 @@ impl ExternalPlugin { }; Ok(lock) } + + fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { + self.cache_path(tv).join("incomplete") + } + + fn create_install_dirs(&self, tv: &ToolVersion) -> Result<()> { + let _ = remove_all_with_warning(self.install_path(tv)); + let _ = remove_all_with_warning(self.download_path(tv)); + let _ = remove_all_with_warning(self.cache_path(tv)); + let _ = remove_file(self.install_path(tv)); // removes if it is a symlink + create_dir_all(self.install_path(tv))?; + create_dir_all(self.download_path(tv))?; + create_dir_all(self.cache_path(tv))?; + File::create(self.incomplete_file_path(tv))?; + Ok(()) + } + fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { + let _ = remove_all_with_warning(self.install_path(tv)); + self.cleanup_install_dirs(settings, tv); + } + fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { + if !settings.always_keep_download { + let _ = remove_all_with_warning(self.download_path(tv)); + } + } + + fn fetch_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + let list_bin_paths = self.plugin_path.join("bin/list-bin-paths"); + let bin_paths = if matches!(tv.request, ToolVersionRequest::System(_)) { + Vec::new() + } else if list_bin_paths.exists() { + let output = self + .script_man_for_tv(config, tv) + .cmd(&config.settings, &Script::ListBinPaths) + .read()?; + output.split_whitespace().map(|f| f.to_string()).collect() + } else { + vec!["bin".into()] + }; + let bin_paths = bin_paths + .into_iter() + .map(|path| self.install_path(tv).join(path)) + .collect(); + Ok(bin_paths) + } + fn fetch_exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + let script = self.script_man_for_tv(config, tv).get_script_path(&ExecEnv); + let ed = EnvDiff::from_bash_script(&script, &self.script_man_for_tv(config, tv).env)?; + let env = ed + .to_patches() + .into_iter() + .filter_map(|p| match p { + EnvDiffOperation::Add(key, value) => Some((key, value)), + EnvDiffOperation::Change(key, value) => Some((key, value)), + _ => None, + }) + .collect(); + Ok(env) + } + + fn script_man_for_tv(&self, config: &Config, tv: &ToolVersion) -> ScriptManager { + let mut sm = self.script_man.clone(); + for (key, value) in &tv.opts { + let k = format!("RTX_TOOL_OPTS__{}", key.to_uppercase()); + sm = sm.with_env(k, value.clone()); + } + if let Some(project_root) = &config.project_root { + let project_root = project_root.to_string_lossy().to_string(); + sm = sm.with_env("RTX_PROJECT_ROOT".into(), project_root); + } + let install_type = match &tv.request { + ToolVersionRequest::Version(_, _) | ToolVersionRequest::Prefix(_, _) => "version", + ToolVersionRequest::Ref(_, _) => "ref", + ToolVersionRequest::Path(_, _) => "path", + ToolVersionRequest::System(_) => { + panic!("should not be called for system tool") + } + }; + sm = sm + .with_env( + "RTX_INSTALL_PATH".into(), + self.install_path(tv).to_string_lossy().to_string(), + ) + .with_env( + "ASDF_INSTALL_PATH".into(), + self.install_path(tv).to_string_lossy().to_string(), + ) + .with_env( + "RTX_DOWNLOAD_PATH".into(), + self.download_path(tv).to_string_lossy().to_string(), + ) + .with_env( + "ASDF_DOWNLOAD_PATH".into(), + self.download_path(tv).to_string_lossy().to_string(), + ) + .with_env("RTX_INSTALL_TYPE".into(), install_type.into()) + .with_env("ASDF_INSTALL_TYPE".into(), install_type.into()) + .with_env("RTX_INSTALL_VERSION".into(), tv.version.clone()) + .with_env("ASDF_INSTALL_VERSION".into(), tv.version.clone()); + sm + } } fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> ScriptManager { let mut sm = ScriptManager::new(plugin_path.to_path_buf()) - .with_env("PATH".into(), get_path_with_fake_asdf()) + .with_env("RTX_PLUGIN_NAME".into(), name.to_string()) .with_env( - "RTX_DATA_DIR".into(), - dirs::ROOT.to_string_lossy().into_owned(), - ) - .with_env("__RTX_SCRIPT".into(), "1".into()) - .with_env("RTX_PLUGIN_NAME".into(), name.to_string()); + "RTX_PLUGIN_PATH".into(), + plugin_path.to_string_lossy().to_string(), + ); if let Some(shims_dir) = &settings.shims_dir { let shims_dir = shims_dir.to_string_lossy().to_string(); sm = sm.with_env("RTX_SHIMS_DIR".into(), shims_dir); @@ -355,17 +462,29 @@ fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> Scri sm } +impl Eq for ExternalPlugin {} + impl PartialEq for ExternalPlugin { fn eq(&self, other: &Self) -> bool { self.name == other.name } } +impl Hash for ExternalPlugin { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} + impl Plugin for ExternalPlugin { fn name(&self) -> &PluginName { &self.name } + fn toml(&self) -> &RtxPluginToml { + &self.toml + } + fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) @@ -526,4 +645,132 @@ impl Plugin for ExternalPlugin { .run()?; exit(result.status.code().unwrap_or(1)); } + + fn is_version_installed(&self, tv: &ToolVersion) -> bool { + match tv.request { + ToolVersionRequest::System(_) => true, + _ => self.install_path(tv).exists() && !self.incomplete_file_path(tv).exists(), + } + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &mut ProgressReport, + force: bool, + ) -> Result<()> { + self.decorate_progress_bar(pr, Some(tv)); + + let settings = &config.settings; + let _lock = self.get_lock(&self.install_path(tv), force)?; + self.create_install_dirs(tv)?; + + let run_script = |script| { + self.script_man_for_tv(config, tv).run_by_line( + settings, + script, + |output| { + self.cleanup_install_dirs_on_error(settings, tv); + pr.error(); + if !settings.verbose && !output.trim().is_empty() { + pr.println(output); + } + }, + |line| { + if !line.trim().is_empty() { + pr.set_message(line.into()); + } + }, + |line| { + if !line.trim().is_empty() { + pr.println(line.into()); + } + }, + ) + }; + + if self.script_man_for_tv(config, tv).script_exists(&Download) { + pr.set_message("downloading".into()); + run_script(&Download)?; + } + pr.set_message("installing".into()); + run_script(&Install)?; + self.cleanup_install_dirs(settings, tv); + + // attempt to touch all the .tool-version files to trigger updates in hook-env + let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; + touch_dirs.extend(config.config_files.keys().cloned()); + for path in touch_dirs { + let err = file::touch_dir(&path); + if let Err(err) = err { + debug!("error touching config file: {:?} {:?}", path, err); + } + } + if let Err(err) = remove_file(self.incomplete_file_path(tv)) { + debug!("error removing incomplete file: {:?}", err); + } + pr.finish(); + + Ok(()) + } + + fn uninstall_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + dryrun: bool, + ) -> Result<()> { + pr.set_message(format!("uninstall {}", self.name())); + + if self.plugin_path.join("bin/uninstall").exists() { + self.script_man_for_tv(config, tv) + .run(&config.settings, &Script::Uninstall)?; + } + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", display_path(dir))); + if dryrun { + return Ok(()); + } + remove_all_with_warning(dir) + }; + rmdir(&self.install_path(tv))?; + rmdir(&self.download_path(tv))?; + Ok(()) + } + + fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + self.cache + .list_bin_paths(config, self, tv, || self.fetch_bin_paths(config, tv)) + } + + fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + if matches!(tv.request, ToolVersionRequest::System(_)) { + return Ok(EMPTY_HASH_MAP.clone()); + } + if !self.script_man.script_exists(&ExecEnv) || *env::__RTX_SCRIPT { + // if the script does not exist, or we're already running from within a script, + // the second is to prevent infinite loops + return Ok(EMPTY_HASH_MAP.clone()); + } + self.cache + .exec_env(config, self, tv, || self.fetch_exec_env(config, tv)) + } + + fn which(&self, config: &Config, tv: &ToolVersion, bin_name: &str) -> Result> { + let bin_paths = self.list_bin_paths(config, tv)?; + for bin_path in bin_paths { + let bin_path = bin_path.join(bin_name); + if bin_path.exists() { + return Ok(Some(bin_path)); + } + } + Ok(None) + } } + +static EMPTY_HASH_MAP: Lazy> = Lazy::new(HashMap::new); diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs new file mode 100644 index 000000000..19bf3452d --- /dev/null +++ b/src/plugins/external_plugin_cache.rs @@ -0,0 +1,99 @@ +use crate::cache::CacheManager; +use crate::config::Config; +use crate::hash::hash_to_str; +use crate::plugins::{ExternalPlugin, Plugin}; +use crate::tera::{get_tera, BASE_CONTEXT}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::{dirs, env}; +use color_eyre::eyre::{eyre, Result}; +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::RwLock; + +#[derive(Debug, Default)] +pub struct ExternalPluginCache { + list_bin_paths: RwLock>>>, + exec_env: RwLock>>>, +} + +impl ExternalPluginCache { + pub fn list_bin_paths( + &self, + config: &Config, + plugin: &ExternalPlugin, + tv: &ToolVersion, + fetch: F, + ) -> Result> + where + F: FnOnce() -> Result>, + { + let mut w = self.list_bin_paths.write().unwrap(); + let cm = w.entry(tv.request.clone()).or_insert_with(|| { + let list_bin_paths_filename = match &plugin.toml().list_bin_paths.cache_key { + Some(key) => { + let key = render_cache_key(config, tv, key); + let filename = format!("{}.msgpack.z", key); + plugin.cache_path(tv).join("list_bin_paths").join(filename) + } + None => plugin.cache_path(tv).join("list_bin_paths.msgpack.z"), + }; + CacheManager::new(list_bin_paths_filename) + .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(plugin.plugin_path.clone()) + .with_fresh_file(plugin.install_path(tv)) + }); + cm.get_or_try_init(fetch).cloned() + } + + pub fn exec_env( + &self, + config: &Config, + plugin: &ExternalPlugin, + tv: &ToolVersion, + fetch: F, + ) -> Result> + where + F: FnOnce() -> Result>, + { + let mut w = self.exec_env.write().unwrap(); + let cm = w.entry(tv.request.clone()).or_insert_with(|| { + let exec_env_filename = match &plugin.toml.exec_env.cache_key { + Some(key) => { + let key = render_cache_key(config, tv, key); + let filename = format!("{}.msgpack.z", key); + plugin.cache_path(tv).join("exec_env").join(filename) + } + None => plugin.cache_path(tv).join("exec_env.msgpack.z"), + }; + CacheManager::new(exec_env_filename) + .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(plugin.plugin_path.clone()) + .with_fresh_file(plugin.install_path(tv)) + }); + cm.get_or_try_init(fetch).cloned() + } +} + +fn render_cache_key(config: &Config, tv: &ToolVersion, cache_key: &[String]) -> String { + let elements = cache_key + .iter() + .map(|tmpl| { + let s = parse_template(config, tv, tmpl).unwrap(); + let s = s.trim().to_string(); + trace!("cache key element: {} -> {}", tmpl.trim(), s); + let mut s = hash_to_str(&s); + s.truncate(10); + s + }) + .collect::>(); + elements.join("-") +} + +fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> Result { + let mut ctx = BASE_CONTEXT.clone(); + ctx.insert("project_root", &config.project_root); + ctx.insert("opts", &tv.opts); + get_tera(config.project_root.as_ref().unwrap_or(&*env::PWD)) + .render_str(tmpl, &ctx) + .map_err(|err| eyre!("failed to parse template: {} {}", tmpl, err)) +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index ccbc4c0e4..9304873d9 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,5 +1,7 @@ +use std::collections::HashMap; use std::fmt::Debug; -use std::path::Path; +use std::hash::{Hash, Hasher}; +use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; use console::style; @@ -9,17 +11,23 @@ use regex::Regex; pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; -use crate::config::Settings; +use crate::config::{Config, Settings}; +use crate::dirs; +use crate::hash::hash_to_str; +use crate::plugins::rtx_plugin_toml::RtxPluginToml; +use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; mod external_plugin; +mod external_plugin_cache; mod rtx_plugin_toml; mod script_manager; pub type PluginName = String; -pub trait Plugin: Debug + Send + Sync { +pub trait Plugin: Debug + Send + Sync + Eq + PartialEq + Hash { fn name(&self) -> &PluginName; + fn toml(&self) -> &RtxPluginToml; fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec>; fn clear_remote_version_cache(&self) -> Result<()>; fn list_installed_versions(&self) -> Result>; @@ -80,15 +88,59 @@ pub trait Plugin: Debug + Send + Sync { unimplemented!() } - fn decorate_progress_bar(&self, pr: &mut ProgressReport) { + fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { pr.set_style(PROG_TEMPLATE.clone()); pr.set_prefix(format!( "{} {} ", style("rtx").dim().for_stderr(), - style(self.name()).cyan().for_stderr() + match tv { + Some(tv) => tv.to_string(), + None => self.name().to_string(), + } )); pr.enable_steady_tick(); } + + fn is_version_installed(&self, tv: &ToolVersion) -> bool; + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &mut ProgressReport, + force: bool, + ) -> Result<()>; + fn uninstall_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + dryrun: bool, + ) -> Result<()>; + fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result>; + fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result>; + fn which(&self, config: &Config, tv: &ToolVersion, bin_name: &str) -> Result>; + fn install_path(&self, tv: &ToolVersion) -> PathBuf { + let pathname = match &tv.request { + ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), + _ => self.tv_pathname(tv), + }; + dirs::INSTALLS.join(self.name()).join(pathname) + } + fn cache_path(&self, tv: &ToolVersion) -> PathBuf { + dirs::CACHE.join(self.name()).join(self.tv_pathname(tv)) + } + fn download_path(&self, tv: &ToolVersion) -> PathBuf { + dirs::DOWNLOADS.join(self.name()).join(self.tv_pathname(tv)) + } + fn tv_pathname(&self, tv: &ToolVersion) -> String { + match &tv.request { + ToolVersionRequest::Version(_, _) => tv.version.to_string(), + ToolVersionRequest::Prefix(_, _) => tv.version.to_string(), + ToolVersionRequest::Ref(_, r) => format!("ref-{}", r), + ToolVersionRequest::Path(_, p) => format!("path-{}", hash_to_str(p)), + ToolVersionRequest::System(_) => "system".to_string(), + } + } } #[derive(Debug)] @@ -96,12 +148,34 @@ pub enum Plugins { External(ExternalPlugin), } +impl Eq for Plugins {} + +impl PartialEq for Plugins { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Plugins::External(p1), Plugins::External(p2)) => p1 == p2, + } + } +} +impl Hash for Plugins { + fn hash(&self, state: &mut H) { + match self { + Plugins::External(p) => p.hash(state), + } + } +} + impl Plugin for Plugins { fn name(&self) -> &PluginName { match self { Plugins::External(p) => p.name(), } } + fn toml(&self) -> &RtxPluginToml { + match self { + Plugins::External(p) => p.toml(), + } + } fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { match self { @@ -169,9 +243,51 @@ impl Plugin for Plugins { Plugins::External(p) => p.execute_external_command(command, args), } } - fn decorate_progress_bar(&self, pr: &mut ProgressReport) { + fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { + match self { + Plugins::External(p) => p.decorate_progress_bar(pr, tv), + } + } + fn is_version_installed(&self, tv: &ToolVersion) -> bool { + match self { + Plugins::External(p) => p.is_version_installed(tv), + } + } + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &mut ProgressReport, + force: bool, + ) -> Result<()> { + match self { + Plugins::External(p) => p.install_version(config, tv, pr, force), + } + } + fn uninstall_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + dryrun: bool, + ) -> Result<()> { + match self { + Plugins::External(p) => p.uninstall_version(config, tv, pr, dryrun), + } + } + fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + match self { + Plugins::External(p) => p.list_bin_paths(config, tv), + } + } + fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + match self { + Plugins::External(p) => p.exec_env(config, tv), + } + } + fn which(&self, config: &Config, tv: &ToolVersion, bin_name: &str) -> Result> { match self { - Plugins::External(p) => p.decorate_progress_bar(pr), + Plugins::External(p) => p.which(config, tv, bin_name), } } } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 3aabd4692..92da7b1be 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -1,3 +1,5 @@ +use crate::fake_asdf::get_path_with_fake_asdf; +use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::io::{BufRead, BufReader}; use std::path::PathBuf; @@ -7,20 +9,20 @@ use std::{fmt, thread}; use color_eyre::eyre::{Context, Result}; use duct::Expression; -use indexmap::{indexmap, IndexMap}; +use indexmap::indexmap; use once_cell::sync::Lazy; use crate::cmd::cmd; use crate::config::Settings; -use crate::env; use crate::errors::Error::ScriptFailed; use crate::file::{basename, display_path}; +use crate::{dirs, env}; #[derive(Debug, Clone)] pub struct ScriptManager { pub plugin_path: PathBuf, pub plugin_name: String, - pub env: IndexMap, + pub env: HashMap, } #[derive(Debug, Clone)] @@ -65,14 +67,22 @@ impl Display for Script { } } -static INITIAL_ENV: Lazy> = Lazy::new(|| { - (indexmap! { - "RTX_EXE" => env::RTX_EXE.to_string_lossy(), - "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy(), - }) - .into_iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect() +static INITIAL_ENV: Lazy> = Lazy::new(|| { + let mut env = env::PRISTINE_ENV.clone(); + env.extend( + (indexmap! { + "__RTX_SCRIPT" => "1".to_string(), + "ASDF_CONCURRENCY" => num_cpus::get().to_string(), + "PATH" => get_path_with_fake_asdf(), + "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy().to_string(), + "RTX_CONCURRENCY" => num_cpus::get().to_string(), + "RTX_DATA_DIR" => dirs::ROOT.to_string_lossy().to_string(), + "RTX_EXE" => env::RTX_EXE.to_string_lossy().to_string(), + }) + .into_iter() + .map(|(k, v)| (k.to_string(), v)), + ); + env }); impl ScriptManager { @@ -89,14 +99,6 @@ impl ScriptManager { self } - pub fn with_envs(mut self, envs: I) -> Self - where - I: IntoIterator, - { - self.env.extend(envs); - self - } - pub fn get_script_path(&self, script: &Script) -> PathBuf { self.plugin_path.join("bin").join(script.to_string()) } @@ -114,14 +116,11 @@ impl ScriptManager { // if !script_path.exists() { // return Err(PluginNotInstalled(self.plugin_name.clone()).into()); // } - let mut cmd = cmd(&script_path, args); + let mut cmd = cmd(script_path, args).full_env(&self.env); if !settings.raw { // ignore stdin, otherwise a prompt may show up where the user won't see it cmd = cmd.stdin_null(); } - for (k, v) in self.env.iter() { - cmd = cmd.env(k, v); - } cmd } @@ -160,9 +159,7 @@ impl ScriptManager { F3: Fn(&str) + Send + Sync, { let mut cmd = Command::new(self.get_script_path(script)); - for (k, v) in self.env.iter() { - cmd.env(k, v); - } + cmd.env_clear().envs(&self.env); if settings.raw { let status = cmd.spawn()?.wait()?; match status.success() { diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 1b9194eea..e20f8c6e5 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -65,7 +65,7 @@ fn list_symlinks(config: &Config, plugin: &Plugins) -> Result Result> { +fn installed_versions(plugin: &Plugins) -> Result> { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let versions = plugin .list_installed_versions()? diff --git a/src/runtimes.rs b/src/runtimes.rs deleted file mode 100644 index c220e38d8..000000000 --- a/src/runtimes.rs +++ /dev/null @@ -1,439 +0,0 @@ -use std::collections::HashMap; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::fs::{remove_file, File}; -use std::path::{Path, PathBuf}; -use std::sync::Arc; - -use color_eyre::eyre::{eyre, Result}; -use console::style; -use once_cell::sync::Lazy; - -use crate::cache::CacheManager; -use crate::config::Config; -use crate::config::Settings; -use crate::env_diff::{EnvDiff, EnvDiffOperation}; -use crate::file::{create_dir_all, display_path, remove_all_with_warning}; -use crate::hash::hash_to_str; -use crate::lock_file::LockFile; -use crate::plugins::Script::{Download, ExecEnv, Install}; -use crate::plugins::{Plugin, Plugins, Script, ScriptManager}; -use crate::tera::{get_tera, BASE_CONTEXT}; -use crate::toolset::{ToolVersion, ToolVersionType}; -use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; -use crate::{dirs, env, fake_asdf, file}; - -/// These represent individual plugin@version pairs of runtimes -/// installed to ~/.local/share/rtx/runtimes -#[derive(Debug, Clone)] -pub struct RuntimeVersion { - pub version: String, - pub plugin: Arc, - pub install_path: PathBuf, - download_path: PathBuf, - cache_path: PathBuf, - script_man: ScriptManager, - list_bin_paths_cache: CacheManager>, - exec_env_cache: CacheManager>, -} - -impl RuntimeVersion { - pub fn new(config: &Config, plugin: Arc, version: String, tv: ToolVersion) -> Self { - let install_path = match &tv.r#type { - ToolVersionType::Path(p) => p.clone(), - _ => dirs::INSTALLS.join(plugin.name()).join(&version), - }; - let download_path = match &tv.r#type { - ToolVersionType::Path(p) => p.clone(), - _ => dirs::DOWNLOADS.join(plugin.name()).join(&version), - }; - let cache_path = match &tv.r#type { - ToolVersionType::Path(p) => dirs::CACHE.join(plugin.name()).join(hash_to_str(&p)), - _ => dirs::CACHE.join(plugin.name()).join(&version), - }; - let script_man = build_script_man( - config, - &tv, - &version, - &plugin, - &install_path, - &download_path, - ); - let list_bin_paths_cache = - Self::list_bin_paths_cache(config, &tv, &plugin, &install_path, &cache_path).unwrap(); - let exec_env_cache = - Self::exec_env_cache(config, &tv, &plugin, &install_path, &cache_path).unwrap(); - - Self { - script_man, - list_bin_paths_cache, - exec_env_cache, - cache_path, - download_path, - install_path, - version, - plugin, - } - } - - fn list_bin_paths_cache( - config: &Config, - tv: &ToolVersion, - plugin: &Arc, - install_path: &Path, - cache_path: &Path, - ) -> Result>> { - match plugin.as_ref() { - Plugins::External(plugin) => { - let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key { - Some(key) => { - let key = render_cache_key(config, tv, key)?; - let filename = format!("{}.msgpack.z", key); - cache_path.join("list_bin_paths").join(filename) - } - None => cache_path.join("list_bin_paths.msgpack.z"), - }; - let cm = CacheManager::new(list_bin_paths_filename) - .with_fresh_file(dirs::ROOT.clone()) - .with_fresh_file(plugin.plugin_path.clone()) - .with_fresh_file(install_path.to_path_buf()); - Ok(cm) - } - } - } - fn exec_env_cache( - config: &Config, - tv: &ToolVersion, - plugin: &Arc, - install_path: &Path, - cache_path: &Path, - ) -> Result>> { - match plugin.as_ref() { - Plugins::External(plugin) => { - let exec_env_filename = match &plugin.toml.exec_env.cache_key { - Some(key) => { - let key = render_cache_key(config, tv, key)?; - let filename = format!("{}.msgpack.z", key); - cache_path.join("exec_env").join(filename) - } - None => cache_path.join("exec_env.msgpack.z"), - }; - let cm = CacheManager::new(exec_env_filename) - .with_fresh_file(dirs::ROOT.clone()) - .with_fresh_file(plugin.plugin_path.clone()) - .with_fresh_file(install_path.to_path_buf()); - Ok(cm) - } - } - } - - pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { - self.decorate_progress_bar(pr); - - let settings = &config.settings; - let _lock = self.get_lock(force, pr)?; - self.create_install_dirs()?; - - let run_script = |script| { - self.script_man.run_by_line( - settings, - script, - |output| { - self.cleanup_install_dirs_on_error(settings); - pr.error(); - if !settings.verbose && !output.trim().is_empty() { - pr.println(output); - } - }, - |line| { - if !line.trim().is_empty() { - pr.set_message(line.into()); - } - }, - |line| { - if !line.trim().is_empty() { - pr.println(line.into()); - } - }, - ) - }; - - if self.script_man.script_exists(&Download) { - pr.set_message("downloading".into()); - run_script(&Download)?; - } - pr.set_message("installing".into()); - run_script(&Install)?; - self.cleanup_install_dirs(settings); - - // attempt to touch all the .tool-version files to trigger updates in hook-env - let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; - touch_dirs.extend(config.config_files.keys().cloned()); - for path in touch_dirs { - let err = file::touch_dir(&path); - if let Err(err) = err { - debug!("error touching config file: {:?} {:?}", path, err); - } - } - if let Err(err) = remove_file(self.incomplete_file_path()) { - debug!("error removing incomplete file: {:?}", err); - } - pr.finish(); - - Ok(()) - } - - pub fn list_bin_paths(&self, settings: &Settings) -> Result<&Vec> { - self.list_bin_paths_cache - .get_or_try_init(|| self.fetch_bin_paths(settings)) - } - - pub fn which(&self, settings: &Settings, bin_name: &str) -> Result> { - let bin_paths = self.list_bin_paths(settings)?; - for bin_path in bin_paths { - let bin_path = bin_path.join(bin_name); - if bin_path.exists() { - return Ok(Some(bin_path)); - } - } - Ok(None) - } - - pub fn is_installed(&self) -> bool { - match self.version.as_str() { - "system" => true, - _ => self.install_path.exists() && !self.incomplete_file_path().exists(), - } - } - - pub fn uninstall(&self, settings: &Settings, pr: &ProgressReport, dryrun: bool) -> Result<()> { - pr.set_message(format!("uninstall {}", self)); - - #[allow(irrefutable_let_patterns)] - if let Plugins::External(plugin) = self.plugin.as_ref() { - if plugin.plugin_path.join("bin/uninstall").exists() { - self.script_man.run(settings, &Script::Uninstall)?; - } - } - let rmdir = |dir: &Path| { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", display_path(dir))); - if dryrun { - return Ok(()); - } - remove_all_with_warning(dir) - }; - rmdir(&self.install_path)?; - rmdir(&self.download_path)?; - Ok(()) - } - - pub fn exec_env(&self) -> Result<&HashMap> { - if self.version.as_str() == "system" { - return Ok(&*EMPTY_HASH_MAP); - } - if !self.script_man.script_exists(&ExecEnv) || *env::__RTX_SCRIPT { - // if the script does not exist or we're running from within a script already - // the second is to prevent infinite loops - return Ok(&*EMPTY_HASH_MAP); - } - self.exec_env_cache.get_or_try_init(|| { - let script = self.script_man.get_script_path(&ExecEnv); - let ed = EnvDiff::from_bash_script(&script, &self.script_man.env)?; - let env = ed - .to_patches() - .into_iter() - .filter_map(|p| match p { - EnvDiffOperation::Add(key, value) => Some((key, value)), - EnvDiffOperation::Change(key, value) => Some((key, value)), - _ => None, - }) - .collect(); - Ok(env) - }) - } - - fn fetch_bin_paths(&self, settings: &Settings) -> Result> { - match self.plugin.as_ref() { - Plugins::External(plugin) => { - let list_bin_paths = plugin.plugin_path.join("bin/list-bin-paths"); - let bin_paths = if self.version == "system" { - Vec::new() - } else if list_bin_paths.exists() { - let output = self - .script_man - .cmd(settings, &Script::ListBinPaths) - .read()?; - output.split_whitespace().map(|f| f.to_string()).collect() - } else { - vec!["bin".into()] - }; - let bin_paths = bin_paths - .into_iter() - .map(|path| self.install_path.join(path)) - .collect(); - Ok(bin_paths) - } - } - } - - fn create_install_dirs(&self) -> Result<()> { - let _ = remove_all_with_warning(&self.install_path); - let _ = remove_all_with_warning(&self.download_path); - let _ = remove_all_with_warning(&self.cache_path); - let _ = remove_file(&self.install_path); // removes if it is a symlink - create_dir_all(&self.install_path)?; - create_dir_all(&self.download_path)?; - create_dir_all(&self.cache_path)?; - File::create(self.incomplete_file_path())?; - Ok(()) - } - - fn cleanup_install_dirs_on_error(&self, settings: &Settings) { - let _ = remove_all_with_warning(&self.install_path); - self.cleanup_install_dirs(settings); - } - fn cleanup_install_dirs(&self, settings: &Settings) { - if !settings.always_keep_download { - let _ = remove_all_with_warning(&self.download_path); - } - } - - fn incomplete_file_path(&self) -> PathBuf { - self.cache_path.join("incomplete") - } - - pub fn decorate_progress_bar(&self, pr: &mut ProgressReport) { - pr.set_style(PROG_TEMPLATE.clone()); - pr.set_prefix(format!( - "{} {} ", - style("rtx").dim().for_stderr(), - style(&self.to_string()).cyan().for_stderr() - )); - pr.enable_steady_tick(); - } - - fn get_lock(&self, force: bool, _pr: &ProgressReport) -> Result> { - let lock = if force { - None - } else { - let lock = LockFile::new(&self.install_path) - .with_callback(|l| { - // pr.set_message(format!("waiting for lock on {}", display_path(l))); - debug!("waiting for lock on {}", display_path(l)); - }) - .lock()?; - Some(lock) - }; - Ok(lock) - } -} - -impl Display for RuntimeVersion { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}@{}", self.plugin.name(), self.version) - } -} - -impl PartialEq for RuntimeVersion { - fn eq(&self, other: &Self) -> bool { - self.plugin.name() == other.plugin.name() && self.version == other.version - } -} - -fn build_script_man( - config: &Config, - tv: &ToolVersion, - version: &str, - plugin: &Plugins, - install_path: &Path, - download_path: &Path, -) -> ScriptManager { - let plugin_path = match plugin { - Plugins::External(plugin) => plugin.plugin_path.clone(), - }; - let mut sm = ScriptManager::new(plugin_path.clone()) - .with_envs(env::PRISTINE_ENV.clone()) - .with_env("PATH".into(), fake_asdf::get_path_with_fake_asdf()) - .with_env( - "ASDF_INSTALL_PATH".into(), - install_path.to_string_lossy().to_string(), - ) - .with_env( - "RTX_INSTALL_PATH".into(), - install_path.to_string_lossy().to_string(), - ) - .with_env( - "ASDF_DOWNLOAD_PATH".into(), - download_path.to_string_lossy().to_string(), - ) - .with_env( - "RTX_DOWNLOAD_PATH".into(), - download_path.to_string_lossy().to_string(), - ) - .with_env("RTX_CONCURRENCY".into(), num_cpus::get().to_string()) - .with_env("ASDF_CONCURRENCY".into(), num_cpus::get().to_string()) - .with_env( - "RTX_DATA_DIR".into(), - dirs::ROOT.to_string_lossy().to_string(), - ) - .with_env("__RTX_SCRIPT".into(), "1".into()) - .with_env("RTX_PLUGIN_NAME".into(), tv.plugin_name.clone()) - .with_env( - "RTX_PLUGIN_PATH".into(), - plugin_path.to_string_lossy().to_string(), - ); - if let Some(shims_dir) = &config.settings.shims_dir { - let shims_dir = shims_dir.to_string_lossy().to_string(); - sm = sm.with_env("RTX_SHIMS_DIR".into(), shims_dir); - } - if let Some(project_root) = &config.project_root { - let project_root = project_root.to_string_lossy().to_string(); - sm = sm.with_env("RTX_PROJECT_ROOT".into(), project_root); - } - for (key, value) in tv.options.iter() { - let k = format!("RTX_TOOL_OPTS__{}", key.to_uppercase()); - sm = sm.with_env(k, value.clone()); - } - match &tv.r#type { - ToolVersionType::Version(_) | ToolVersionType::Prefix(_) => sm - .with_env("ASDF_INSTALL_TYPE".into(), "version".into()) - .with_env("RTX_INSTALL_TYPE".into(), "version".into()) - .with_env("ASDF_INSTALL_VERSION".into(), version.to_string()) - .with_env("RTX_INSTALL_VERSION".into(), version.to_string()), - ToolVersionType::Ref(r) => sm - .with_env("ASDF_INSTALL_TYPE".into(), "ref".into()) - .with_env("RTX_INSTALL_TYPE".into(), "ref".into()) - .with_env("ASDF_INSTALL_VERSION".into(), r.to_string()) - .with_env("RTX_INSTALL_VERSION".into(), r.to_string()), - _ => sm, - } -} - -static EMPTY_HASH_MAP: Lazy> = Lazy::new(HashMap::new); - -fn render_cache_key(config: &Config, tv: &ToolVersion, cache_key: &[String]) -> Result { - let elements = cache_key - .iter() - .map(|tmpl| { - let s = parse_template(config, tv, tmpl)?; - let s = s.trim().to_string(); - trace!("cache key element: {} -> {}", tmpl.trim(), s); - let mut s = hash_to_str(&s); - s.truncate(10); - Ok(s) - }) - .collect::>>()?; - Ok(elements.join("-")) -} - -fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> Result { - let mut ctx = BASE_CONTEXT.clone(); - ctx.insert("project_root", &config.project_root); - ctx.insert("opts", &tv.options); - get_tera(config.project_root.as_ref().unwrap_or(&*env::PWD)) - .render_str(tmpl, &ctx) - .map_err(|err| eyre!("failed to parse template: {} {}", tmpl, err)) -} diff --git a/src/shims.rs b/src/shims.rs index c6ec54082..1745dcfeb 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -17,8 +17,7 @@ use crate::file::{create_dir_all, remove_all}; use crate::lock_file::LockFile; use crate::output::Output; use crate::plugins::{Plugin, Plugins}; -use crate::runtimes::RuntimeVersion; -use crate::toolset::{Toolset, ToolsetBuilder}; +use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; // executes as if it was a shim if the command is not "rtx", e.g.: "node" @@ -45,8 +44,8 @@ fn which_shim(config: &mut Config, bin_name: &str) -> Result { let shim = shims_dir.join(bin_name); if shim.exists() { let ts = ToolsetBuilder::new().build(config)?; - if let Some(rtv) = ts.which(config, bin_name) { - if let Some(bin) = rtv.which(&config.settings, bin_name)? { + if let Some((p, tv)) = ts.which(config, bin_name) { + if let Some(bin) = p.which(config, &tv, bin_name)? { return Ok(bin); } } @@ -62,8 +61,8 @@ fn which_shim(config: &mut Config, bin_name: &str) -> Result { return Ok(bin); } } - let rtvs = ts.list_rtvs_with_bin(config, bin_name)?; - err_no_version_set(bin_name, rtvs)?; + let tvs = ts.list_rtvs_with_bin(config, bin_name)?; + err_no_version_set(bin_name, tvs)?; } } Err(eyre!("{} is not a valid shim", bin_name)) @@ -88,10 +87,10 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { let paths: Vec = ts .list_installed_versions(config)? .into_par_iter() - .flat_map(|rtv| match rtv.list_bin_paths(&config.settings) { - Ok(paths) => paths.clone(), + .flat_map(|(p, tv)| match p.list_bin_paths(config, &tv) { + Ok(paths) => paths, Err(e) => { - warn!("Error listing bin paths for {}: {:#}", rtv, e); + warn!("Error listing bin paths for {}: {:#}", tv, e); Vec::new() } }) @@ -166,18 +165,14 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { Ok(()) } -fn err_no_version_set(bin_name: &str, rtvs: Vec) -> Result<()> { - if rtvs.is_empty() { +fn err_no_version_set(bin_name: &str, tvs: Vec) -> Result<()> { + if tvs.is_empty() { return Ok(()); } let mut msg = format!("No version is set for shim: {}\n", bin_name); msg.push_str("Set a global default version with one of the following:\n"); - for rtv in rtvs { - msg.push_str(&format!( - "rtx global {}@{}\n", - rtv.plugin.name(), - rtv.version - )); + for tv in tvs { + msg.push_str(&format!("rtx global {}@{}\n", tv.plugin_name, tv.version)); } Err(eyre!(msg.trim().to_string())) } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index bde10e1d4..4a675b85c 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -5,8 +5,7 @@ use itertools::Itertools; use crate::cli::args::runtime::RuntimeArg; use crate::config::Config; use crate::env; -use crate::toolset::tool_version::ToolVersionType; -use crate::toolset::{ToolSource, ToolVersion, Toolset}; +use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; #[derive(Debug, Default)] @@ -72,8 +71,8 @@ fn load_runtime_env(ts: &mut Toolset, env: IndexMap) { } let source = ToolSource::Environment(k, v.clone()); let mut env_ts = Toolset::new(source); - let version = ToolVersion::new(plugin_name.clone(), ToolVersionType::Version(v)); - env_ts.add_version(version); + let tvr = ToolVersionRequest::new(plugin_name, &v); + env_ts.add_version(tvr, Default::default()); ts.merge(&env_ts); } } @@ -83,8 +82,8 @@ fn load_runtime_args(ts: &mut Toolset, args: &[RuntimeArg]) { for (_, args) in args.iter().into_group_map_by(|arg| arg.plugin.clone()) { let mut arg_ts = Toolset::new(ToolSource::Argument); for arg in args { - if let Some(version) = arg.to_tool_version() { - arg_ts.add_version(version); + if let Some(tvr) = &arg.tvr { + arg_ts.add_version(tvr.clone(), Default::default()); } } ts.merge(&arg_ts); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index c79c14861..35e3542cd 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::path::PathBuf; @@ -16,15 +16,13 @@ use rayon::ThreadPoolBuilder; pub use builder::ToolsetBuilder; pub use tool_source::ToolSource; pub use tool_version::ToolVersion; -pub use tool_version::ToolVersionType; pub use tool_version_list::ToolVersionList; +pub use tool_version_request::ToolVersionRequest; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgVersion}; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; use crate::runtime_symlinks::rebuild_symlinks; -use crate::runtimes::RuntimeVersion; use crate::shims::reshim; use crate::ui::multi_progress_report::MultiProgressReport; @@ -32,6 +30,9 @@ mod builder; mod tool_source; mod tool_version; mod tool_version_list; +mod tool_version_request; + +pub type ToolVersionOptions = IndexMap; /// a toolset is a collection of tools for various plugins /// @@ -52,12 +53,14 @@ impl Toolset { ..Default::default() } } - pub fn add_version(&mut self, version: ToolVersion) { - let versions = self + pub fn add_version(&mut self, tvr: ToolVersionRequest, opts: ToolVersionOptions) { + let tvl = self .versions - .entry(version.plugin_name.clone()) - .or_insert_with(|| ToolVersionList::new(self.source.clone().unwrap())); - versions.add_version(version); + .entry(tvr.plugin_name().clone()) + .or_insert_with(|| { + ToolVersionList::new(tvr.plugin_name().to_string(), self.source.clone().unwrap()) + }); + tvl.requests.push((tvr, opts)); } pub fn merge(&mut self, other: &Toolset) { let mut versions = other.versions.clone(); @@ -69,24 +72,20 @@ impl Toolset { self.versions = versions; self.source = other.source.clone(); } - pub fn resolve(&mut self, config: &Config) { + pub fn resolve(&mut self, config: &mut Config) { + self.list_missing_plugins(config); self.versions .iter_mut() .collect::>() .par_iter_mut() - .for_each(|(p, v)| { - let plugin = match config.plugins.get(&p.to_string()) { - Some(p) if p.is_installed() => p, - _ => { - debug!("Plugin {} is not installed", p); - return; - } - }; - v.resolve(config, plugin.clone(), self.latest_versions); - }); + .for_each(|(_, v)| v.resolve(config, self.latest_versions)); } pub fn install_missing(&mut self, config: &mut Config, mpr: MultiProgressReport) -> Result<()> { - let versions = self.list_missing_versions(); + let versions = self + .list_missing_versions(config) + .into_iter() + .cloned() + .collect_vec(); if versions.is_empty() { return Ok(()); } @@ -118,11 +117,20 @@ impl Toolset { Ok(()) } - pub fn list_missing_plugins(&self, config: &Config) -> Vec { + pub fn list_missing_plugins(&self, config: &mut Config) -> Vec { + for plugin in self.versions.keys() { + config.plugins.entry(plugin.clone()).or_insert_with(|| { + Arc::new(Plugins::External(ExternalPlugin::new( + &config.settings, + plugin, + ))) + }); + } self.versions .keys() - .filter(|p| !config.plugins.contains_key(*p)) - .cloned() + .map(|p| config.plugins.get(p).unwrap()) + .filter(|p| !p.is_installed()) + .map(|p| p.name().clone()) .collect() } @@ -143,29 +151,35 @@ impl Toolset { .collect_vec(); let selected_versions = selected_versions .into_iter() - .map(|v| v.r#type) + .map(|v| (v.plugin_name.clone(), v.request)) .collect::>(); self.install_missing_plugins(config, plugins, &mpr)?; self.versions .iter_mut() .par_bridge() - .filter_map(|(p, v)| { + .filter_map(|(p, v)| match config.plugins.get(&p.to_string()) { + Some(plugin) if plugin.is_installed() => Some((plugin, v)), + _ => None, + }) + .map(|(plugin, v)| { let versions = v .versions .iter_mut() - .filter(|v| v.is_missing() && selected_versions.contains(&v.r#type)) + .filter(|tv| { + !plugin.is_version_installed(tv) + && selected_versions + .contains(&(tv.plugin_name.clone(), tv.request.clone())) + }) .collect_vec(); - let plugin = config.plugins.get(&p.to_string()); - match (plugin, versions.is_empty()) { - (Some(plugin), false) => Some((plugin, versions)), - _ => None, - } + (plugin, versions) }) + .filter(|(_, versions)| !versions.is_empty()) .map(|(plugin, versions)| { - for version in versions { + for tv in versions { let mut pr = mpr.add(); - version.resolve(config, plugin.clone(), self.latest_versions)?; - version.install(config, &mut pr, false)?; + // TODO: is this necessary? + // version.resolve(config, plugin.clone(), self.latest_versions)?; + plugin.install_version(config, tv, &mut pr, false)?; } Ok(()) }) @@ -190,7 +204,7 @@ impl Toolset { }); } config.plugins.sort_keys(); - missing_plugins + let missing_plugins = missing_plugins .into_par_iter() .map(|p| config.plugins.get(&p).unwrap()) .filter_map(|p| match p.as_ref() { @@ -203,19 +217,36 @@ impl Toolset { p.install(config, &mut pr, false) }) .collect::>>()?; + if !missing_plugins.is_empty() { + self.resolve(config); + } Ok(()) } - pub fn list_missing_versions(&self) -> Vec { - let versions = self - .versions - .values() - .flat_map(|v| v.versions.iter().filter(|v| v.is_missing()).collect_vec()) - .cloned() - .collect_vec(); - versions + pub fn list_missing_versions(&self, config: &Config) -> Vec<&ToolVersion> { + self.versions + .iter() + .map(|(p, tvl)| { + let p = config.plugins.get(p).unwrap().clone(); + (p, tvl) + }) + .flat_map(|(p, tvl)| { + tvl.versions + .iter() + .filter(|tv| !p.is_version_installed(tv)) + .collect_vec() + }) + .collect() } - pub fn list_installed_versions(&self, config: &Config) -> Result> { + pub fn list_installed_versions( + &self, + config: &Config, + ) -> Result, ToolVersion)>> { + let current_versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = self + .list_current_versions(config) + .into_iter() + .map(|(p, tv)| ((p.name().clone(), tv.version.clone()), (p, tv))) + .collect(); let versions = config .plugins .values() @@ -224,9 +255,15 @@ impl Toolset { .map(|p| { let versions = p.list_installed_versions()?; Ok(versions.into_iter().map(|v| { - let tv = - ToolVersion::new(p.name().clone(), ToolVersionType::Version(v.clone())); - RuntimeVersion::new(config, p.clone(), v, tv) + match current_versions.get(&(p.name().clone(), v.clone())) { + Some((p, tv)) => (p.clone(), tv.clone()), + None => { + let tv = ToolVersionRequest::new(p.name().clone(), &v) + .resolve(config, p, Default::default(), false) + .unwrap(); + (p.clone(), tv) + } + } })) }) .collect::>>()? @@ -236,25 +273,31 @@ impl Toolset { Ok(versions) } - pub fn list_versions_by_plugin(&self) -> IndexMap> { + pub fn list_versions_by_plugin( + &self, + config: &Config, + ) -> Vec<(Arc, &Vec)> { self.versions .iter() .map(|(p, v)| { - let versions = v.resolved_versions(); - (p.clone(), versions) + let p = config.plugins.get(p).unwrap(); + (p.clone(), &v.versions) }) .collect() } - pub fn list_current_versions(&self) -> Vec<&RuntimeVersion> { - self.list_versions_by_plugin() - .into_iter() - .flat_map(|(_, v)| v) + pub fn list_current_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion)> { + self.list_versions_by_plugin(config) + .iter() + .flat_map(|(p, v)| v.iter().map(|v| (p.clone(), v.clone()))) .collect() } - pub fn list_current_installed_versions(&self) -> Vec<&RuntimeVersion> { - self.list_current_versions() + pub fn list_current_installed_versions( + &self, + config: &Config, + ) -> Vec<(Arc, ToolVersion)> { + self.list_current_versions(config) .into_iter() - .filter(|v| v.is_installed()) + .filter(|(p, v)| p.is_version_installed(v)) .collect() } pub fn env_with_path(&self, config: &Config) -> IndexMap { @@ -265,10 +308,10 @@ impl Toolset { } pub fn env(&self, config: &Config) -> IndexMap { let mut entries: IndexMap = self - .list_current_installed_versions() + .list_current_installed_versions(config) .into_par_iter() - .flat_map(|v| match v.exec_env() { - Ok(env) => env.clone().into_iter().collect(), + .flat_map(|(p, tv)| match p.exec_env(config, &tv) { + Ok(env) => env.into_iter().collect(), Err(e) => { warn!("Error running exec-env: {:#}", e); Vec::new() @@ -292,87 +335,22 @@ impl Toolset { .into() } pub fn list_paths(&self, config: &Config) -> Vec { - self.list_current_installed_versions() + self.list_current_installed_versions(config) .into_par_iter() - .flat_map(|rtv| match rtv.list_bin_paths(&config.settings) { - Ok(paths) => paths.clone(), + .flat_map(|(p, tv)| match p.list_bin_paths(config, &tv) { + Ok(paths) => paths, Err(e) => { - warn!("Error listing bin paths for {}: {:#}", rtv, e); + warn!("Error listing bin paths for {}: {:#}", tv, e); Vec::new() } }) .collect() } - pub fn resolve_runtime_arg(&self, arg: &RuntimeArg) -> Option<&RuntimeVersion> { - match &arg.version { - RuntimeArgVersion::System => None, - RuntimeArgVersion::Version(version) => { - if let Some(tvl) = self.versions.get(&arg.plugin) { - for tv in tvl.versions.iter() { - match &tv.r#type { - ToolVersionType::Version(v) if v == version => { - return tv.rtv.as_ref(); - } - _ => (), - } - } - } - None - } - RuntimeArgVersion::Prefix(version) => { - if let Some(tvl) = self.versions.get(&arg.plugin) { - for tv in tvl.versions.iter() { - match &tv.r#type { - ToolVersionType::Prefix(v) if v.starts_with(version) => { - return tv.rtv.as_ref(); - } - _ => (), - } - } - } - None - } - RuntimeArgVersion::Ref(ref_) => { - if let Some(tvl) = self.versions.get(&arg.plugin) { - for tv in tvl.versions.iter() { - match &tv.r#type { - ToolVersionType::Ref(v) if v == ref_ => { - return tv.rtv.as_ref(); - } - _ => (), - } - } - } - None - } - RuntimeArgVersion::Path(path) => { - if let Some(tvl) = self.versions.get(&arg.plugin) { - for tv in tvl.versions.iter() { - match &tv.r#type { - ToolVersionType::Path(v) if v == path => { - return tv.rtv.as_ref(); - } - _ => (), - } - } - } - None - } - RuntimeArgVersion::None => { - let plugin = self.versions.get(&arg.plugin); - match plugin { - Some(tvl) => tvl.versions.first().unwrap().rtv.as_ref(), - None => None, - } - } - } - } - - pub fn which(&self, config: &Config, bin_name: &str) -> Option<&RuntimeVersion> { - self.list_current_installed_versions() + pub fn which(&self, config: &Config, bin_name: &str) -> Option<(Arc, ToolVersion)> { + self.list_current_installed_versions(config) .into_par_iter() - .find_first(|v| { - if let Ok(x) = v.which(&config.settings, bin_name) { + .find_first(|(p, tv)| { + if let Ok(x) = p.which(config, tv, bin_name) { x.is_some() } else { false @@ -380,21 +358,18 @@ impl Toolset { }) } - pub fn list_rtvs_with_bin( - &self, - config: &Config, - bin_name: &str, - ) -> Result> { + pub fn list_rtvs_with_bin(&self, config: &Config, bin_name: &str) -> Result> { Ok(self .list_installed_versions(config)? .into_par_iter() - .filter(|v| match v.which(&config.settings, bin_name) { + .filter(|(p, tv)| match p.which(config, tv, bin_name) { Ok(x) => x.is_some(), Err(e) => { warn!("Error running which: {:#}", e); false } }) + .map(|(_, tv)| tv) .collect()) } } @@ -404,7 +379,7 @@ impl Display for Toolset { let plugins = &self .versions .iter() - .map(|(_, v)| v.versions.iter().map(|v| v.to_string()).join(" ")) + .map(|(_, v)| v.requests.iter().map(|(tvr, _)| tvr.to_string()).join(" ")) .collect_vec(); write!(f, "{}", plugins.join(", ")) } diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 1839f32a3..983677e2b 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -1,217 +1,180 @@ use std::fmt::{Display, Formatter}; use std::fs; use std::path::PathBuf; -use std::sync::Arc; use color_eyre::eyre::Result; -use indexmap::IndexMap; use versions::{Chunk, Version}; use crate::config::Config; use crate::dirs; - -use crate::plugins::{Plugin, Plugins}; +use crate::plugins::{Plugin, PluginName, Plugins}; use crate::runtime_symlinks::is_runtime_symlink; -use crate::runtimes::RuntimeVersion; -use crate::ui::progress_report::ProgressReport; +use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; /// represents a single version of a tool for a particular plugin #[derive(Debug, Clone)] pub struct ToolVersion { - pub plugin_name: String, - pub r#type: ToolVersionType, - pub rtv: Option, - pub options: IndexMap, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ToolVersionType { - Version(String), - Prefix(String), - Ref(String), - Path(PathBuf), - System, + pub request: ToolVersionRequest, + pub plugin_name: PluginName, + pub version: String, + pub opts: ToolVersionOptions, } impl ToolVersion { - pub fn new(plugin_name: String, r#type: ToolVersionType) -> Self { - Self { - plugin_name, - r#type, - rtv: None, - options: Default::default(), + pub fn new( + plugin: &Plugins, + request: ToolVersionRequest, + opts: ToolVersionOptions, + version: String, + ) -> Self { + ToolVersion { + plugin_name: plugin.name().to_string(), + version, + request, + opts, } } pub fn resolve( - &mut self, config: &Config, - plugin: Arc, + plugin: &Plugins, + request: ToolVersionRequest, + opts: ToolVersionOptions, latest_versions: bool, - ) -> Result<()> { - if self.rtv.is_none() { - self.rtv = Some(match &self.r#type { - ToolVersionType::Version(v) => { - self.resolve_version(config, plugin, v, latest_versions)? - } - ToolVersionType::Prefix(v) => self.resolve_prefix(config, plugin, v)?, - ToolVersionType::Ref(r) => self.resolve_ref(config, plugin, r)?, - ToolVersionType::Path(path) => self.resolve_path(config, plugin, path)?, - ToolVersionType::System => self.resolve_system(config, plugin), - }); - } - Ok(()) + ) -> Result { + let tv = match request.clone() { + ToolVersionRequest::Version(_, v) => { + Self::resolve_version(config, plugin, request, latest_versions, &v, opts)? + } + ToolVersionRequest::Prefix(_, prefix) => { + Self::resolve_prefix(config, plugin, request, &prefix, opts)? + } + _ => { + let version = request.version(); + Self::new(plugin, request, opts, version) + } + }; + Ok(tv) } fn resolve_version( - &self, config: &Config, - plugin: Arc, - v: &str, + plugin: &Plugins, + request: ToolVersionRequest, latest_versions: bool, - ) -> Result { + v: &str, + opts: ToolVersionOptions, + ) -> Result { let v = config.resolve_alias(plugin.name(), v)?; match v.split_once(':') { Some(("ref", r)) => { - return self.resolve_ref(config, plugin, r); + return Ok(Self::resolve_ref(plugin, r.to_string(), opts)); } Some(("path", p)) => { - return self.resolve_path(config, plugin, &PathBuf::from(p)); + return Self::resolve_path(plugin, PathBuf::from(p), opts); } Some(("prefix", p)) => { - return self.resolve_prefix(config, plugin, p); + return Self::resolve_prefix(config, plugin, request, p, opts); } _ => (), } + let build = |v| Ok(Self::new(plugin, request.clone(), opts.clone(), v)); + let existing_path = dirs::INSTALLS.join(plugin.name()).join(&v); if existing_path.exists() && !is_runtime_symlink(&existing_path) { // if the version is already installed, no need to fetch all the remote versions - return Ok(self.build_rtv(config, plugin, &v)); + return build(v); + } + if !plugin.is_installed() { + return build(v); } if v == "latest" { if !latest_versions { if let Some(v) = plugin.latest_installed_version()? { - return Ok(self.build_rtv(config, plugin, &v)); + return build(v); } } if let Some(v) = plugin.latest_version(&config.settings, None)? { - return Ok(self.build_rtv(config, plugin, &v)); + return build(v); } } if !latest_versions { let matches = plugin.list_installed_versions_matching(&v)?; if matches.contains(&v) { - return Ok(self.build_rtv(config, plugin, &v)); + return build(v); } } let matches = plugin.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { - return Ok(self.build_rtv(config, plugin, &v)); + return build(v); } if v.contains("!-") { - if let Some(rtv) = self.resolve_bang(config, plugin.clone(), &v)? { - return Ok(rtv); + if let Some(tv) = Self::resolve_bang(config, plugin, request.clone(), &v, &opts)? { + return Ok(tv); } } - self.resolve_prefix(config, plugin, &v) + Self::resolve_prefix(config, plugin, request, &v, opts) } /// resolve a version like `12.0.0!-1` which becomes `11.0.0`, `12.1.0!-0.1` becomes `12.0.0` fn resolve_bang( - &self, config: &Config, - plugin: Arc, + plugin: &Plugins, + request: ToolVersionRequest, v: &str, - ) -> Result> { + opts: &ToolVersionOptions, + ) -> Result> { let (wanted, minus) = v.split_once("!-").unwrap(); let wanted = match wanted { "latest" => plugin.latest_version(&config.settings, None)?.unwrap(), _ => config.resolve_alias(plugin.name(), wanted)?, }; let wanted = version_sub(&wanted, minus); - match plugin.latest_version(&config.settings, Some(wanted))? { - Some(v) => Ok(Some(self.build_rtv(config, plugin, &v))), - None => Ok(None), - } + let tv = plugin + .latest_version(&config.settings, Some(wanted))? + .map(|v| Self::new(plugin, request, opts.clone(), v)); + Ok(tv) } fn resolve_prefix( - &self, config: &Config, - plugin: Arc, + plugin: &Plugins, + request: ToolVersionRequest, prefix: &str, - ) -> Result { + opts: ToolVersionOptions, + ) -> Result { let matches = plugin.list_versions_matching(&config.settings, prefix)?; let v = match matches.last() { Some(v) => v, None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; - Ok(self.build_rtv(config, plugin, v)) + Ok(Self::new(plugin, request, opts, v.to_string())) } - fn resolve_ref( - &self, - config: &Config, - plugin: Arc, - r: &str, - ) -> Result { - Ok(self.build_rtv(config, plugin, &format!("ref-{}", r))) + fn resolve_ref(plugin: &Plugins, r: String, opts: ToolVersionOptions) -> Self { + let request = ToolVersionRequest::Ref(plugin.name().clone(), r); + let version = request.version(); + Self::new(plugin, request, opts, version) } fn resolve_path( - &self, - config: &Config, - plugin: Arc, - path: &PathBuf, - ) -> Result { + plugin: &Plugins, + path: PathBuf, + opts: ToolVersionOptions, + ) -> Result { let path = fs::canonicalize(path)?; - Ok(self.build_rtv(config, plugin, &path.display().to_string())) - } - - pub fn resolve_system(&self, config: &Config, plugin: Arc) -> RuntimeVersion { - self.build_rtv(config, plugin, "system") - } - - pub fn is_missing(&self) -> bool { - match self.rtv { - Some(ref rtv) if rtv.version == "system" => false, - Some(ref rtv) => !rtv.is_installed(), - None => true, - } - } - - pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { - match self.r#type { - ToolVersionType::Version(_) | ToolVersionType::Prefix(_) | ToolVersionType::Ref(_) => { - self.rtv.as_ref().unwrap().install(config, pr, force) - } - _ => Ok(()), - } - } - - fn build_rtv(&self, config: &Config, plugin: Arc, v: &str) -> RuntimeVersion { - RuntimeVersion::new(config, plugin, v.to_string(), self.clone()) + let request = ToolVersionRequest::Path(plugin.name().clone(), path); + let version = request.version(); + Ok(Self::new(plugin, request, opts, version)) } } impl Display for ToolVersion { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{}@{}", &self.plugin_name, &self.r#type) - } -} - -impl Display for ToolVersionType { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - match self { - ToolVersionType::Version(v) => write!(f, "{v}"), - ToolVersionType::Prefix(p) => write!(f, "prefix:{p}"), - ToolVersionType::Ref(r) => write!(f, "ref:{r}"), - ToolVersionType::Path(p) => write!(f, "path:{}", p.display()), - ToolVersionType::System => write!(f, "system"), - } + write!(f, "{}@{}", &self.plugin_name, &self.version) } } @@ -237,21 +200,6 @@ mod tests { use super::*; - #[test] - fn test_tool_version_display() { - let foo = "foo".to_string(); - let tv = ToolVersion::new(foo.clone(), ToolVersionType::Version("1.2.3".to_string())); - assert_str_eq!(tv.to_string(), "foo@1.2.3"); - let tv = ToolVersion::new(foo.clone(), ToolVersionType::Prefix("1.2.3".to_string())); - assert_str_eq!(tv.to_string(), "foo@prefix:1.2.3"); - let tv = ToolVersion::new(foo.clone(), ToolVersionType::Ref("master".to_string())); - assert_str_eq!(tv.to_string(), "foo@ref:master"); - let tv = ToolVersion::new(foo.clone(), ToolVersionType::Path(PathBuf::from("~"))); - assert_str_eq!(tv.to_string(), "foo@path:~"); - let tv = ToolVersion::new(foo, ToolVersionType::System); - assert_str_eq!(tv.to_string(), "foo@system"); - } - #[test] fn test_version_sub() { assert_str_eq!(version_sub("18.2.3", "2"), "16"); diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index f91a62940..cac9a48c7 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -1,67 +1,39 @@ -use std::sync::Arc; - use crate::config::Config; -use crate::plugins::Plugins; -use crate::runtimes::RuntimeVersion; -use crate::toolset::{ToolSource, ToolVersion}; +use crate::toolset::tool_version_request::ToolVersionRequest; +use crate::toolset::{ToolSource, ToolVersion, ToolVersionOptions}; /// represents several versions of a tool for a particular plugin #[derive(Debug, Clone)] pub struct ToolVersionList { + pub plugin_name: String, pub versions: Vec, + pub requests: Vec<(ToolVersionRequest, ToolVersionOptions)>, pub source: ToolSource, } impl ToolVersionList { - pub fn new(source: ToolSource) -> Self { + pub fn new(plugin_name: String, source: ToolSource) -> Self { Self { + plugin_name, versions: Vec::new(), + requests: vec![], source, } } - pub fn add_version(&mut self, version: ToolVersion) { - self.versions.push(version); - } - pub fn resolve(&mut self, config: &Config, plugin: Arc, latest_versions: bool) { - for tv in &mut self.versions { - if let Err(err) = tv.resolve(config, plugin.clone(), latest_versions) { - warn!("failed to resolve tool version: {:#}", err); + 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; + } + }; + for (tvr, opts) in &mut self.requests { + match tvr.resolve(config, plugin, opts.clone(), latest_versions) { + Ok(v) => self.versions.push(v), + Err(err) => warn!("failed to resolve tool version: {:#}", err), } } } - pub fn resolved_versions(&self) -> Vec<&RuntimeVersion> { - self.versions - .iter() - .filter_map(|v| v.rtv.as_ref()) - .collect() - } -} - -#[cfg(test)] -mod tests { - use std::env; - use std::sync::Arc; - - use crate::config::Config; - use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; - use crate::toolset::{ToolSource, ToolVersion, ToolVersionList, ToolVersionType}; - - #[test] - fn test_tool_version_list_failure() { - env::set_var("RTX_FAILURE", "1"); - let mut tvl = ToolVersionList::new(ToolSource::Argument); - let settings = crate::config::Settings::default(); - let plugin = Arc::new(Plugins::External(ExternalPlugin::new( - &settings, - &PluginName::from("dummy"), - ))); - plugin.clear_remote_version_cache().unwrap(); - tvl.add_version(ToolVersion::new( - plugin.name().to_string(), - ToolVersionType::Version("1.0.0".to_string()), - )); - tvl.resolve(&Config::default(), plugin, false); - assert_eq!(tvl.resolved_versions().len(), 0); - env::remove_var("RTX_FAILURE"); - } } diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs new file mode 100644 index 000000000..8f199e973 --- /dev/null +++ b/src/toolset/tool_version_request.rs @@ -0,0 +1,75 @@ +use std::fmt::{Display, Formatter}; +use std::path::PathBuf; + +use color_eyre::eyre::Result; + +use crate::config::Config; +use crate::plugins::{PluginName, Plugins}; +use crate::toolset::{ToolVersion, ToolVersionOptions}; + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub enum ToolVersionRequest { + Version(PluginName, String), + Prefix(PluginName, String), + Ref(PluginName, String), + Path(PluginName, PathBuf), + System(PluginName), +} + +impl ToolVersionRequest { + pub fn new(plugin_name: PluginName, s: &str) -> Self { + let s = match s.split_once('-') { + Some(("ref", r)) => format!("ref:{}", r), + _ => s.to_string(), + }; + match s.split_once(':') { + Some(("ref", r)) => Self::Ref(plugin_name, r.to_string()), + Some(("prefix", p)) => Self::Prefix(plugin_name, p.to_string()), + Some(("path", p)) => Self::Path(plugin_name, PathBuf::from(p)), + None => { + if s == "system" { + Self::System(plugin_name) + } else { + Self::Version(plugin_name, s.to_string()) + } + } + _ => panic!("invalid tool version request: {s}"), + } + } + + pub fn plugin_name(&self) -> &PluginName { + match self { + Self::Version(p, _) => p, + Self::Prefix(p, _) => p, + Self::Ref(p, _) => p, + Self::Path(p, _) => p, + Self::System(p) => p, + } + } + + pub fn version(&self) -> String { + match self { + Self::Version(_, v) => v.clone(), + Self::Prefix(_, p) => format!("prefix:{p}"), + Self::Ref(_, r) => format!("ref:{r}"), + Self::Path(_, p) => format!("path:{}", p.display()), + Self::System(_) => "system".to_string(), + } + } + + pub fn resolve( + &self, + config: &Config, + plugin: &Plugins, + opts: ToolVersionOptions, + latest_versions: bool, + ) -> Result { + ToolVersion::resolve(config, plugin, self.clone(), opts, latest_versions) + } +} + +impl Display for ToolVersionRequest { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!(f, "{}@{}", self.plugin_name(), self.version()) + } +} diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index b6677d2bf..62353085f 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -114,12 +114,12 @@ impl ProgressReport { None => eprintln!("{}{message}", self.prefix), } } - pub fn clear(&self) { - match &self.pb { - Some(pb) => pb.finish_and_clear(), - None => (), - } - } + // pub fn clear(&self) { + // match &self.pb { + // Some(pb) => pb.finish_and_clear(), + // None => (), + // } + // } } #[cfg(test)] From cc5b77f90be7368eaf3f989cf494dcfbcbbdeb5c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 5 Apr 2023 15:13:18 -0500 Subject: [PATCH 0650/1891] chore: Release --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9beedcb31..abc7e0c9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -644,14 +644,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ "cfg-if", "libc", "redox_syscall 0.2.16", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1035,13 +1035,13 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1586,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.27.11" +version = "1.27.12" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 6d3dcbeb6..298e338c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.27.11" +version = "1.27.12" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index c04ccc786..80d17ef3a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.27.11 +rtx 1.27.12 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.11/rtx-v1.27.11-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.27.12/rtx-v1.27.12-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 3f2e7f9ce..e2c54ea60 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.27.11"; + version = "1.27.12"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 708a6ea4b..09c86f06b 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.27.11" +.TH rtx 1 "rtx 1.27.12" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.27.11 +v1.27.12 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 5972042ea..443cb9380 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.27.11 +Version: 1.27.12 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 31a2ab51855b807213b0adc84c34dda3a180b243 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 14:57:20 -0500 Subject: [PATCH 0651/1891] test: improve coverage (#444) * test .node-version parsing I think this is not always being called due to flaky coverage on parse_legacy_file. This should always cause that code path to get hit * added test for tool_version_list * wip * Squashed 'test/data/plugins/tiny/' content from commit 2cd6716 git-subtree-dir: test/data/plugins/tiny git-subtree-split: 2cd6716c5fbb7bb92c3bd2f681d16aba5141c91e * added env var to fail tiny list-all in tests * added test for tiny failure * added list-legacy-filenames script for tiny * added test for tiny legacy file * improve e2e testing --- CONTRIBUTING.md | 9 ++-- e2e/assert.sh | 2 +- e2e/config/.alternate-tool-versions | 1 + e2e/config/.e2e-tool-versions | 4 ++ e2e/config/.e2e.rtx.toml | 8 ++++ e2e/config/.node-version | 1 + e2e/config/.test-env | 1 + e2e/config/cd/.e2e-tool-versions | 1 + e2e/config/cd/.e2e.rtx.toml | 2 + e2e/config/cd/16/.e2e-tool-versions | 1 + e2e/config/cd/16/.e2e.rtx.toml | 2 + e2e/run_test | 47 +++++++++++++------ e2e/test_env | 15 ++---- e2e/test_tiny | 19 ++++++++ justfile | 20 ++++++-- src/toolset/tool_version_list.rs | 24 ++++++++++ test/.gitignore | 1 + test/data/plugins/tiny/bin/list-all | 5 ++ .../plugins/tiny/bin/list-legacy-filenames | 3 ++ 19 files changed, 131 insertions(+), 35 deletions(-) create mode 100644 e2e/config/.alternate-tool-versions create mode 100644 e2e/config/.e2e-tool-versions create mode 100644 e2e/config/.e2e.rtx.toml create mode 100644 e2e/config/.node-version create mode 100644 e2e/config/.test-env create mode 100644 e2e/config/cd/.e2e-tool-versions create mode 100644 e2e/config/cd/.e2e.rtx.toml create mode 100644 e2e/config/cd/16/.e2e-tool-versions create mode 100644 e2e/config/cd/16/.e2e.rtx.toml create mode 100755 e2e/test_tiny create mode 100755 test/data/plugins/tiny/bin/list-legacy-filenames diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 335a65eca..2e6510e26 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,20 +30,21 @@ tasks: ~/src/rtx ❯ just --list Available recipes: build *args # just `cargo build` + b *args # alias for `build` clean # delete built files default # defaults to `just test` lint # clippy, cargo fmt --check, and just --fmt lint-fix # runs linters but makes fixes when possible - pre-commit # called by husky precommit hook - release *args + pre-commit # called by lefthook precommit hook + release *args # create/publish a new version of rtx render-completions # regenerate shell completion files render-help # regenerate README.md render-mangen # regenerate manpages test *args # run all test types - b *args # alias for `test` t *args # alias for `test` test-coverage # run unit tests w/ coverage - test-e2e # runs the E2E tests in ./e2e + test-e2e TEST=("all") # specify a test name to run a single test + e TEST=("all") # alias for `test-e2e` test-unit *args # run the rust "unit" tests test-update-snapshots # update all test snapshot files ``` diff --git a/e2e/assert.sh b/e2e/assert.sh index bee99715b..b1f3be91c 100644 --- a/e2e/assert.sh +++ b/e2e/assert.sh @@ -1,6 +1,6 @@ assert() { local actual - actual="$($1)" + actual="$(bash -c "$1")" if [[ "$actual" != "$2" ]]; then echo "Expected '$2' but got '$actual'" exit 1 diff --git a/e2e/config/.alternate-tool-versions b/e2e/config/.alternate-tool-versions new file mode 100644 index 000000000..c942b3d2c --- /dev/null +++ b/e2e/config/.alternate-tool-versions @@ -0,0 +1 @@ +shfmt 3.5.0 diff --git a/e2e/config/.e2e-tool-versions b/e2e/config/.e2e-tool-versions new file mode 100644 index 000000000..ae660fffb --- /dev/null +++ b/e2e/config/.e2e-tool-versions @@ -0,0 +1,4 @@ +#python 3.11.1 3.10.9 # foo +shellcheck 0.9.0 +shfmt 3.6.0 # test comment +#nodejs 18.13.0 diff --git a/e2e/config/.e2e.rtx.toml b/e2e/config/.e2e.rtx.toml new file mode 100644 index 000000000..2c50026bd --- /dev/null +++ b/e2e/config/.e2e.rtx.toml @@ -0,0 +1,8 @@ +dotenv = '.test-env' +env_path = ["/root", "./cwd"] +[env] +FOO = "bar" + +[tools] +tiny = "latest" +#golang = {version="1.19.5", foo="bar"} diff --git a/e2e/config/.node-version b/e2e/config/.node-version new file mode 100644 index 000000000..7eae4e2e9 --- /dev/null +++ b/e2e/config/.node-version @@ -0,0 +1 @@ +18.0.0 diff --git a/e2e/config/.test-env b/e2e/config/.test-env new file mode 100644 index 000000000..3c0ec58e8 --- /dev/null +++ b/e2e/config/.test-env @@ -0,0 +1 @@ +FOO_FROM_FILE="foo_from_file" diff --git a/e2e/config/cd/.e2e-tool-versions b/e2e/config/cd/.e2e-tool-versions new file mode 100644 index 000000000..b00f5981f --- /dev/null +++ b/e2e/config/cd/.e2e-tool-versions @@ -0,0 +1 @@ +nodejs 18.0.0 diff --git a/e2e/config/cd/.e2e.rtx.toml b/e2e/config/cd/.e2e.rtx.toml new file mode 100644 index 000000000..99f0244b5 --- /dev/null +++ b/e2e/config/cd/.e2e.rtx.toml @@ -0,0 +1,2 @@ +[env] +FOO = "cd" diff --git a/e2e/config/cd/16/.e2e-tool-versions b/e2e/config/cd/16/.e2e-tool-versions new file mode 100644 index 000000000..35830be2c --- /dev/null +++ b/e2e/config/cd/16/.e2e-tool-versions @@ -0,0 +1 @@ +nodejs 16.0.0 diff --git a/e2e/config/cd/16/.e2e.rtx.toml b/e2e/config/cd/16/.e2e.rtx.toml new file mode 100644 index 000000000..1907f4e2f --- /dev/null +++ b/e2e/config/cd/16/.e2e.rtx.toml @@ -0,0 +1,2 @@ +[env] +FOO = "16" diff --git a/e2e/run_test b/e2e/run_test index 3386248f7..b5e7e1963 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -3,19 +3,36 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)" -export ROOT -export PATH="$ROOT/target/debug:$PATH" -export RTX_USE_TOML="0" -export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" -export RTX_DATA_DIR="$ROOT/e2e/.rtx" -export RTX_CACHE_DIR="$ROOT/e2e/.rtx/cache" -export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions -export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml -export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" -unset GOPATH - TEST="$1" -echo "Running $TEST" -rm -f "$RTX_CONFIG_FILE" -cd "$(dirname "$TEST")" -"./$(basename "$TEST")" + +setup_env() { + export ROOT + export PATH="$ROOT/target/debug:$PATH" + export RTX_USE_TOML="0" + export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" + export RTX_DATA_DIR="$ROOT/e2e/.rtx" + export RTX_CACHE_DIR="$ROOT/e2e/.rtx/cache" + export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions + export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml + export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" + unset GOPATH +} + +setup_config_files() { + mkdir -p "$ROOT/e2e/cd/16" + cp "$ROOT/e2e/config/".e2e.* "$ROOT/e2e/" + cp "$ROOT/e2e/config/"{.node-version,.alternate-tool-versions,.test-env} "$ROOT/e2e/" + cp "$ROOT/e2e/config/cd/".e2e.* "$ROOT/e2e/cd/" + cp "$ROOT/e2e/config/cd/16/".e2e.* "$ROOT/e2e/cd/16" +} + +run_test() { + echo "Running $TEST" + rm -f "$RTX_CONFIG_FILE" + cd "$(dirname "$TEST")" + "./$(basename "$TEST")" +} + +setup_env +setup_config_files +run_test diff --git a/e2e/test_env b/e2e/test_env index e33ba8615..c4214ad26 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -1,15 +1,10 @@ #!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" -assert() { - actual="$(bash -c "$1")" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" != "$expected" ]]; then - echo "assertion failed, expected '$expected', got '$actual'" - exit 1 - fi -} - +rtx i nodejs +eval "$(rtx env -s bash)" +assert "node -v" "v18.0.0" rtx i nodejs@16.0.0 eval "$(rtx env -s bash nodejs@16.0.0)" assert "node -v" "v16.0.0" diff --git a/e2e/test_tiny b/e2e/test_tiny new file mode 100755 index 000000000..18c5b9930 --- /dev/null +++ b/e2e/test_tiny @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +rtx cache clean +rm -rf .rtx/installs/tiny +rtx trust .e2e.rtx.toml + +# this will fail when calling bin/list-all, but it won't stop it from executing +RTX_TINY_LIST_ALL_FAIL=1 RTX_TINY_VERSION=latest rtx env >/dev/null + +# check bin/list-legacy-files +assert "rtx current tiny" "3.1.0" +rtx local --remove tiny +echo "2.0" > .tiny-version +assert "rtx current tiny" "2.0.1" +rm .tiny-version +rtx local tiny@latest +assert "rtx current tiny" "3.1.0" diff --git a/justfile b/justfile index eef14827e..d3e9eb5a1 100644 --- a/justfile +++ b/justfile @@ -8,14 +8,14 @@ export RUST_TEST_THREADS := "1" # defaults to `just test` default: test -alias b := test +alias b := build +alias e := test-e2e +alias t := test # just `cargo build` build *args: cargo build {{ args }} -alias t := test - # run all test types test *args: (test-unit args) test-e2e lint @@ -28,8 +28,17 @@ test-unit *args: cargo test {{ args }} # runs the E2E tests in ./e2e -test-e2e: build - ./e2e/run_all_tests + +# specify a test name to run a single test +test-e2e TEST=("all"): + #!/usr/bin/env bash + set -euo pipefail + if [ "{{ TEST }}" = all ]; then + ./e2e/run_all_tests + else + FILES="$(fd {{ TEST }} e2e/)" + ./e2e/run_test "$FILES" + fi # run unit tests w/ coverage test-coverage: @@ -103,5 +112,6 @@ pre-commit: render-help render-completions render-mangen git add completions git add man +# create/publish a new version of rtx release *args: cargo release {{ args }} diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index cac9a48c7..f93ea1805 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -37,3 +37,27 @@ impl ToolVersionList { } } } + +#[cfg(test)] +mod tests { + + use std::sync::Arc; + + use super::*; + use crate::plugins::{ExternalPlugin, Plugin, Plugins}; + + #[test] + fn test_tool_version_list() { + let mut config = Config::default(); + let plugin = ExternalPlugin::new(&config.settings, &"tiny".to_string()); + let plugin = Arc::new(Plugins::External(plugin)); + config.plugins.insert(plugin.name().clone(), plugin.clone()); + let mut tvl = ToolVersionList::new(plugin.name().clone(), ToolSource::Argument); + tvl.requests.push(( + ToolVersionRequest::new(plugin.name().clone(), "latest"), + ToolVersionOptions::default(), + )); + tvl.resolve(&config, true); + assert_eq!(tvl.versions.len(), 1); + } +} diff --git a/test/.gitignore b/test/.gitignore index 754d0d5e4..c3a61e0c8 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,3 +1,4 @@ data/ +!data/plugins cache/ cwd/man/ diff --git a/test/data/plugins/tiny/bin/list-all b/test/data/plugins/tiny/bin/list-all index 62647c735..b241d06cd 100755 --- a/test/data/plugins/tiny/bin/list-all +++ b/test/data/plugins/tiny/bin/list-all @@ -2,6 +2,11 @@ set -eu -o pipefail +if [ "${RTX_TINY_LIST_ALL_FAIL:-}" = "1" ]; then + echo "RTX_TINY_LIST_ALL_FAIL is set to 1, failing" + exit 1 +fi + echo 1.0.0 echo 1.1.0 echo 1.0.1 diff --git a/test/data/plugins/tiny/bin/list-legacy-filenames b/test/data/plugins/tiny/bin/list-legacy-filenames new file mode 100755 index 000000000..913e4303c --- /dev/null +++ b/test/data/plugins/tiny/bin/list-legacy-filenames @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo ".tiny-version" From 76e65857e333934b89278ffe78fc84dc6ec38fc0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 16:23:10 -0500 Subject: [PATCH 0652/1891] show requested version on `rtx ls` (#445) --- README.md | 45 +----- completions/_rtx | 16 +- completions/rtx.bash | 2 +- completions/rtx.fish | 9 +- man/man1/rtx.1 | 5 +- src/cli/current.rs | 6 +- src/cli/local.rs | 2 +- src/cli/ls.rs | 153 +++++++++++------- .../snapshots/rtx__cli__ls__tests__ls-2.snap | 6 +- .../snapshots/rtx__cli__ls__tests__ls-3.snap | 6 +- .../snapshots/rtx__cli__ls__tests__ls-4.snap | 4 +- .../snapshots/rtx__cli__ls__tests__ls-5.snap | 4 +- .../snapshots/rtx__cli__ls__tests__ls.snap | 4 +- .../rtx__cli__ls__tests__ls_current.snap | 4 +- .../rtx__cli__ls__tests__ls_json-2.snap | 1 + .../rtx__cli__ls__tests__ls_json.snap | 2 + 16 files changed, 142 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index 80d17ef3a..94ad4ee50 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,6 @@ v18.15.0 - [`rtx bin-paths`](#rtx-bin-paths) - [`rtx cache clear`](#rtx-cache-clear) - [`rtx completion [SHELL]`](#rtx-completion-shell) - - [`rtx current [PLUGIN]`](#rtx-current-plugin) - [`rtx deactivate`](#rtx-deactivate) - [`rtx direnv activate`](#rtx-direnv-activate) - [`rtx doctor`](#rtx-doctor) @@ -1534,35 +1533,6 @@ Examples: $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx $ rtx completion fish > ~/.config/fish/completions/rtx.fish ``` -### `rtx current [PLUGIN]` - -``` -Shows current active and installed runtime versions - -This is similar to `rtx ls --current`, but this only shows the runtime -and/or version. It's designed to fit into scripts more easily. - -Usage: current [PLUGIN] - -Arguments: - [PLUGIN] - Plugin to show versions of e.g.: ruby, nodejs - -Examples: - # outputs `.tool-versions` compatible format - $ rtx current - python 3.11.0 3.10.0 - shfmt 3.6.0 - shellcheck 0.9.0 - nodejs 18.13.0 - - $ rtx current nodejs - 18.13.0 - - # can output multiple versions - $ rtx current python - 3.11.0 3.10.0 -``` ### `rtx deactivate` ``` @@ -1853,24 +1823,19 @@ Examples: ### `rtx ls [OPTIONS]` ``` -List installed runtime versions - -The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. -(Assuming `rtx activate` or `rtx env` is in use). +List installed and/or currently selected tool versions Usage: ls [OPTIONS] Options: -p, --plugin - Only show runtimes from [PLUGIN] + Only show tool versions from [PLUGIN] -c, --current - Only show runtimes currently specified in .tool-versions - - --parseable - Output in an easily parseable format + Only show tool versions currently specified in a .tool-versions/.rtx.toml - [short aliases: x] + -i, --installed + Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed --json Output in json format diff --git a/completions/_rtx b/completions/_rtx index 9dd43d7ca..a4cdb0004 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -759,15 +759,17 @@ the current value of .tool-versions/.rtx.toml will be displayed:' \ ;; (ls) _arguments "${_arguments_options[@]}" \ -'-p+[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ -'--plugin=[Only show runtimes from \[PLUGIN\]]:PLUGIN: ' \ +'-p+[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ +'--plugin=[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-c[Only show runtimes currently specified in .tool-versions]' \ -'--current[Only show runtimes currently specified in .tool-versions]' \ +'-c[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ +'--current[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ +'-i[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ +'--installed[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ '(--json)--parseable[Output in an easily parseable format]' \ '--json[Output in json format]' \ '--debug[Sets log level to debug]' \ @@ -1726,8 +1728,8 @@ _rtx_commands() { 'latest:Gets the latest available version for a plugin' \ 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'l:Sets/gets tool version in local .tool-versions or .rtx.toml' \ -'ls:List installed runtime versions' \ -'list:List installed runtime versions' \ +'ls:List installed and/or currently selected tool versions' \ +'list:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ @@ -2078,7 +2080,7 @@ _rtx__help_commands() { 'install:Install a runtime' \ 'latest:Gets the latest available version for a plugin' \ 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ -'ls:List installed runtime versions' \ +'ls:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ 'plugins:Manage plugins' \ 'prune:Delete unused versions of tools' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index ca0d82536..420db6eeb 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2192,7 +2192,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -j -r -v -h --plugin --current --parseable --json --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" + opts="-p -c -i -j -r -v -h --plugin --current --installed --parseable --json --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 789b53f4b..afd6b1ae6 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -27,7 +27,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI a complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest available version for a plugin' complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed and/or currently selected tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' @@ -362,11 +362,12 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from local" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show runtimes from [PLUGIN]' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show tool versions from [PLUGIN]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show runtimes currently specified in .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in an easily parseable format' complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' complete -c rtx -n "__fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' @@ -667,7 +668,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 09c86f06b..b8d1b5719 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -55,9 +55,6 @@ Manage the rtx cache rtx\-completion(1) Generate shell completions .TP -rtx\-current(1) -Shows current active and installed runtime versions -.TP rtx\-deactivate(1) Disable rtx for current shell session .TP @@ -89,7 +86,7 @@ rtx\-local(1) Sets/gets tool version in local .tool\-versions or .rtx.toml .TP rtx\-ls(1) -List installed runtime versions +List installed and/or currently selected tool versions .TP rtx\-ls\-remote(1) List runtime versions available for install diff --git a/src/cli/current.rs b/src/cli/current.rs index a077e8153..e25673a6b 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -12,8 +12,12 @@ use crate::toolset::{Toolset, ToolsetBuilder}; /// /// This is similar to `rtx ls --current`, but this only shows the runtime /// and/or version. It's designed to fit into scripts more easily. +/// +/// This command is currently hidden as we may be able to merge it with `ls` +/// and it's confusing to have two commands that do similar things. +/// It will probably never be removed in order to retain some compatibility with asdf. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, hide = true, after_long_help = AFTER_LONG_HELP)] pub struct Current { /// Plugin to show versions of /// e.g.: ruby, nodejs diff --git a/src/cli/local.rs b/src/cli/local.rs index 4e5da71b1..cca6a40fe 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -192,7 +192,7 @@ mod tests { let stdout = assert_cli!("ls", "--current"); assert_str_eq!( grep(stdout, "tiny"), - "-> tiny 2.1.0 (set by ~/.test-tool-versions)" + "tiny 2.1.0 ~/.test-tool-versions 2" ); }); } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 832665be3..87f01473b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -1,10 +1,11 @@ -use std::cmp::max; use std::collections::HashMap; +use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::Arc; use color_eyre::eyre::Result; use console::style; +use console::Alignment::Left; use indexmap::IndexMap; use itertools::Itertools; use owo_colors::OwoColorize; @@ -13,32 +14,33 @@ use versions::Versioning; use crate::cli::command::Command; use crate::config::Config; -use crate::env::DUMB_TERMINAL; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; use crate::plugins::{Plugin, PluginName, Plugins}; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; -/// List installed runtime versions -/// -/// The "arrow (->)" indicates the runtime is installed, active, and will be used for running commands. -/// (Assuming `rtx activate` or `rtx env` is in use). +/// List installed and/or currently selected tool versions #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Ls { - /// Only show runtimes from [PLUGIN] + /// Only show tool versions from [PLUGIN] #[clap(long, short)] plugin: Option, #[clap(hide = true)] plugin_arg: Option, - /// Only show runtimes currently specified in .tool-versions + /// Only show tool versions currently specified in a .tool-versions/.rtx.toml #[clap(long, short)] current: bool, + /// Only show tool versions that are installed + /// Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed + #[clap(long, short)] + installed: bool, + /// Output in an easily parseable format - #[clap(long, visible_short_alias = 'x', conflicts_with = "json")] + #[clap(long, hide = true, visible_short_alias = 'x', conflicts_with = "json")] parseable: bool, /// Output in json format @@ -55,6 +57,9 @@ impl Command for Ls { if self.current { runtimes.retain(|(_, _, source)| source.is_some()); } + if self.installed { + runtimes.retain(|(p, tv, _)| p.is_version_installed(tv)); + } if self.json { self.display_json(runtimes, out) } else if self.parseable { @@ -65,11 +70,12 @@ impl Command for Ls { } } -type JSONOutput = IndexMap>; +type JSONOutput = IndexMap>; #[derive(Serialize)] -struct JSONRuntime { +struct JSONToolVersion { version: String, + requested_version: Option, install_path: PathBuf, source: Option>, } @@ -95,9 +101,10 @@ impl Ls { .group_by(|(p, _, _)| p.name().to_string()) { let runtimes = runtimes - .map(|(p, tv, source)| JSONRuntime { + .map(|(p, tv, source)| JSONToolVersion { install_path: p.install_path(&tv), version: tv.version, + requested_version: source.as_ref().map(|_| tv.request.version()), source: source.map(|source| source.as_json()), }) .collect(); @@ -113,6 +120,8 @@ impl Ls { } fn display_parseable(&self, runtimes: Vec, out: &mut Output) -> Result<()> { + warn!("The parseable output format is deprecated and will be removed in a future release."); + warn!("Please use the regular output format instead which has been modified to be more easily parseable."); runtimes .into_iter() .map(|(p, tv, _)| (p, tv)) @@ -133,54 +142,57 @@ impl Ls { runtimes: Vec<(Arc, ToolVersion, Option)>, out: &mut Output, ) -> Result<()> { - for (p, tv, source) in runtimes { - rtxprintln!( - out, - "{} {} {}", - match p.is_version_installed(&tv) && source.is_some() { - true => - if *DUMB_TERMINAL { - "->" - } else { - "⏵ " - }, - false => " ", - }, - styled_version(&tv, !p.is_version_installed(&tv), source.is_some()), - match source { - Some(source) => format!("(set by {source})"), - None => "".into(), - }, - ); + let output = runtimes + .into_iter() + .map(|(p, tv, source)| { + let plugin = p.name().to_string(); + let version = if !p.is_version_installed(&tv) { + VersionStatus::Missing(tv.version) + } else if source.is_some() { + VersionStatus::Active(tv.version) + } else { + VersionStatus::Inactive(tv.version) + }; + let request = source.map(|source| (source.to_string(), tv.request.version())); + (plugin, version, request) + }) + .collect::>(); + let (max_plugin_len, max_version_len, max_source_len) = output.iter().fold( + (0, 0, 0), + |(max_plugin, max_version, max_source), (plugin, version, request)| { + let plugin = max_plugin.max(plugin.len()); + let version = max_version.max(version.to_plain_string().len()); + let source = match request { + Some((source, _)) => max_source.max(source.len()), + None => max_source, + }; + (plugin.min(10), version.min(15), source.min(30)) + }, + ); + for (plugin, version, request) in output { + let pad = |s, len| console::pad_str(s, len, Left, None); + let plugin_extra = (plugin.len() as i8 - max_plugin_len as i8).max(0) as usize; + let plugin = pad(&plugin, max_plugin_len); + let plugin = style(plugin).cyan(); + let version_extra = (version.to_plain_string().len() as i8 - max_version_len as i8 + + plugin_extra as i8) + .max(0) as usize; + let version = version.to_string(); + let version = pad(&version, max_version_len - plugin_extra); + match request { + Some((source, requested)) => { + let source = pad(&source, max_source_len - version_extra); + rtxprintln!(out, "{} {} {} {}", plugin, version, source, requested); + } + None => { + rtxprintln!(out, "{} {}", plugin, version); + } + } } Ok(()) } } -fn styled_version(tv: &ToolVersion, missing: bool, active: bool) -> String { - let styled = if missing { - style(&tv.version).strikethrough().red().to_string() - + style(" (missing)").red().to_string().as_str() - } else if active { - style(&tv.version).green().to_string() - } else { - style(&tv.version).dim().to_string() - }; - let unstyled = if missing { - format!("{} {} (missing)", &tv.plugin_name, &tv.version) - } else { - format!("{} {}", &tv.plugin_name, &tv.version) - }; - - let pad = max(0, 25 - unstyled.len() as isize) as usize; - format!( - "{} {}{}", - style(&tv.plugin_name).cyan(), - styled, - " ".repeat(pad) - ) -} - type RuntimeRow = (Arc, ToolVersion, Option); fn get_runtime_list( @@ -232,6 +244,37 @@ fn get_runtime_list( Ok(rvs) } +enum VersionStatus { + Active(String), + Inactive(String), + Missing(String), +} + +impl VersionStatus { + fn to_plain_string(&self) -> String { + match self { + VersionStatus::Active(version) => version.to_string(), + VersionStatus::Inactive(version) => version.to_string(), + VersionStatus::Missing(version) => format!("{} (missing)", version), + } + } +} + +impl Display for VersionStatus { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + VersionStatus::Active(version) => write!(f, "{}", style(version).green()), + VersionStatus::Inactive(version) => write!(f, "{}", style(version).dim()), + VersionStatus::Missing(version) => write!( + f, + "{} {}", + style(version).strikethrough().red(), + style("(missing)").red() + ), + } + } +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx ls diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap index 900ee3d84..fe5aef32a 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap @@ -2,7 +2,7 @@ source: src/cli/ls.rs expression: output --- --> dummy ref:master (set by ~/.test-tool-versions) - tiny 2.0.0 --> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) +dummy ref:master ~/.test-tool-versions ref:master +tiny 2.0.0 +tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap index 41e660126..32e4d68d1 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap @@ -2,7 +2,7 @@ source: src/cli/ls.rs expression: output --- --> dummy ref:master (set by ~/.test-tool-versions) - tiny 2.0.0 - tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) +dummy ref:master ~/.test-tool-versions ref:master +tiny 2.0.0 +tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap index 1498e06a0..66c0cb095 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref:master (set by ~/.test-tool-versions) - tiny 3.1.0 (missing) (set by ~/cwd/.test-tool-versions) +dummy ref:master ~/.test-tool-versions ref:master +tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap index 0aace8b3e..625cf85e6 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref:master (set by ~/.test-tool-versions) --> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) +dummy ref:master ~/.test-tool-versions ref:master +tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap index 0aace8b3e..625cf85e6 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref:master (set by ~/.test-tool-versions) --> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) +dummy ref:master ~/.test-tool-versions ref:master +tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap index 0aace8b3e..625cf85e6 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap @@ -2,6 +2,6 @@ source: src/cli/ls.rs expression: output --- --> dummy ref:master (set by ~/.test-tool-versions) --> tiny 3.1.0 (set by ~/cwd/.test-tool-versions) +dummy ref:master ~/.test-tool-versions ref:master +tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap index b34587b11..9370d9faf 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap @@ -5,6 +5,7 @@ expression: output [ { "version": "3.1.0", + "requested_version": "3", "install_path": "~/data/installs/tiny/3.1.0", "source": { "type": ".tool-versions", diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap index 9b90e51c5..1f463fe1d 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap @@ -6,6 +6,7 @@ expression: output "dummy": [ { "version": "ref:master", + "requested_version": "ref:master", "install_path": "~/data/installs/dummy/ref-master", "source": { "type": ".tool-versions", @@ -16,6 +17,7 @@ expression: output "tiny": [ { "version": "3.1.0", + "requested_version": "3", "install_path": "~/data/installs/tiny/3.1.0", "source": { "type": ".tool-versions", From 9e96c2ab78a13d4df20ee8dd8b3cbbe8a064e68c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 16:38:17 -0500 Subject: [PATCH 0653/1891] use `env_file` instead of `dotenv` in .rtx.toml (#442) This matches the other config. `dotenv` is still going to be supported for the forseeable future to not break anything, but will probably go away eventually. --- .rtx.toml | 2 +- README.md | 6 +++--- e2e/.e2e.rtx.toml | 2 +- e2e/config/.e2e.rtx.toml | 2 +- e2e/test_local | 8 ++++---- schema/rtx.json | 2 +- src/config/config_file/rtx_toml.rs | 13 +++++++------ 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.rtx.toml b/.rtx.toml index 27f39c3ed..8fd7fbd89 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -1,5 +1,5 @@ #:schema ./schema/rtx.json -dotenv = '.env' +env_file = '.env' [env] FOO = "bar" THIS_PROJECT = "{{config_root}}-{{env.PWD}}" diff --git a/README.md b/README.md index 94ad4ee50..2a2dd8ccb 100644 --- a/README.md +++ b/README.md @@ -686,13 +686,13 @@ Environment variable values can be templates, see [Templates](#templates) for de LD_LIBRARY_PATH = "/some/path:{{env.LD_LIBRARY_PATH}}" ``` -`dotenv` can be used to specify a [dotenv](https://dotenv.org) file to load: +`env_file` can be used to specify a [dotenv](https://dotenv.org) file to load: ```toml -dotenv = '.env' +env_file = '.env' ``` -_Note: `dotenv` goes at the top of the file, above `[env]`._ +_Note: `env_file` goes at the top of the file, above `[env]`._ ### Environment variables diff --git a/e2e/.e2e.rtx.toml b/e2e/.e2e.rtx.toml index 2c50026bd..90d7fabe1 100644 --- a/e2e/.e2e.rtx.toml +++ b/e2e/.e2e.rtx.toml @@ -1,4 +1,4 @@ -dotenv = '.test-env' +env_file = '.test-env' env_path = ["/root", "./cwd"] [env] FOO = "bar" diff --git a/e2e/config/.e2e.rtx.toml b/e2e/config/.e2e.rtx.toml index 2c50026bd..90d7fabe1 100644 --- a/e2e/config/.e2e.rtx.toml +++ b/e2e/config/.e2e.rtx.toml @@ -1,4 +1,4 @@ -dotenv = '.test-env' +env_file = '.test-env' env_path = ["/root", "./cwd"] [env] FOO = "bar" diff --git a/e2e/test_local b/e2e/test_local index 291c75d2e..5bd8f024f 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -20,7 +20,7 @@ export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall assert_raises "rtx uninstall shfmt@3.6.0" -assert "rtx local" "dotenv = '.test-env' +assert "rtx local" "env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -31,7 +31,7 @@ tiny = \"latest\" " rtx local shfmt@3.5.0 -assert "rtx local" "dotenv = '.test-env' +assert "rtx local" "env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -51,7 +51,7 @@ assert_raises "rtx uninstall shfmt@3.6.0" assert_raises "rtx local shfmt --install-missing" rtx local shfmt@3.6.0 -assert "rtx local" "dotenv = '.test-env' +assert "rtx local" "env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -68,7 +68,7 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then fi rtx local --rm shfmt -assert "rtx local" "dotenv = '.test-env' +assert "rtx local" "env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" diff --git a/schema/rtx.json b/schema/rtx.json index 3f7d5e968..dc5b6acd8 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -6,7 +6,7 @@ "type": "object", "additionalProperties": false, "properties": { - "dotenv": { + "env_file": { "description": "path to .env file", "type": "string" }, diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index dd4d35693..4c683d26c 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -27,7 +27,7 @@ pub struct RtxToml { context: Context, path: PathBuf, toolset: Toolset, - dotenv: Option, + env_file: Option, env: HashMap, path_dirs: Vec, settings: SettingsBuilder, @@ -75,7 +75,8 @@ impl RtxToml { let doc: Document = s.parse().suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { - "dotenv" => self.parse_dotenv(k, v)?, + "dotenv" => self.parse_env_file(k, v)?, + "env_file" => self.parse_env_file(k, v)?, "env_path" => self.path_dirs = self.parse_path_env(k, v)?, "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, @@ -93,7 +94,7 @@ impl RtxToml { self.settings.clone() } - fn parse_dotenv(&mut self, k: &str, v: &Item) -> Result<()> { + fn parse_env_file(&mut self, k: &str, v: &Item) -> Result<()> { self.trust_check()?; match v.as_str() { Some(filename) => { @@ -102,7 +103,7 @@ impl RtxToml { let (k, v) = item?; self.env.insert(k, v); } - self.dotenv = Some(path); + self.env_file = Some(path); } _ => parse_error!(k, v, "string")?, } @@ -691,8 +692,8 @@ impl ConfigFile for RtxToml { } fn watch_files(&self) -> Vec { - match &self.dotenv { - Some(dotenv) => vec![self.path.clone(), dotenv.clone()], + match &self.env_file { + Some(env_file) => vec![self.path.clone(), env_file.clone()], None => vec![self.path.clone()], } } From 0bf591e77d0eba204ec3802ff2b4d8d274c211c0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:22:45 -0500 Subject: [PATCH 0654/1891] add prompt to install missing plugin on ls-remote (#449) Fixes #447 --- README.md | 12 ++++--- e2e/assert.sh | 4 +-- e2e/test_ls_remote | 4 +++ e2e/test_tiny | 2 +- src/cli/ls_remote.rs | 52 ++++++++++++++++++++++++------ src/config/config_file/rtx_toml.rs | 15 ++++----- src/config/mod.rs | 12 +++++++ src/env.rs | 27 ++++++++++++++++ src/toolset/mod.rs | 16 ++------- src/ui/mod.rs | 1 + src/ui/prompt.rs | 17 ++++++++++ 11 files changed, 124 insertions(+), 38 deletions(-) create mode 100644 src/ui/prompt.rs diff --git a/README.md b/README.md index 2a2dd8ccb..e9a1247e9 100644 --- a/README.md +++ b/README.md @@ -816,6 +816,10 @@ Currently this disables the following: This hides the warning that is displayed when a new version of rtx is available. +#### `RTX_CONFIRM=yes|no` + +This will automatically answer yes or no to prompts. This is useful for scripting. + #### `RTX_EXPERIMENTAL=1` Enables experimental features such as shims. @@ -1372,8 +1376,8 @@ the list of versions available for that plugin (`rtx ls-remote `), the l the list of aliases, the bin directories within each runtime installation, and the result of running `exec-env` after the runtime was installed. -Remote versions are updated daily by default or anytime that `rtx ls-remote` is called explicitly. The file is -zlib messagepack, if you want to view it you can run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). +Remote versions are updated daily by default. The file is zlib messagepack, if you want to view it you can +run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode @@ -1874,8 +1878,8 @@ Examples: ``` List runtime versions available for install -note that these versions are cached for commands like `rtx install nodejs@latest` -however _this_ command will always clear that cache and fetch the latest remote versions +note that the results are cached for 24 hours +run `rtx cache clean` to clear the cache and get fresh results Usage: ls-remote [PREFIX] diff --git a/e2e/assert.sh b/e2e/assert.sh index b1f3be91c..9e963def8 100644 --- a/e2e/assert.sh +++ b/e2e/assert.sh @@ -9,7 +9,7 @@ assert() { assert_contains() { local actual - actual="$($1)" + actual="$(bash -c "$1")" if [[ "$actual" != *"$2"* ]]; then echo "Expected '$2' to be in '$actual'" exit 1 @@ -17,7 +17,7 @@ assert_contains() { } assert_fail() { - if $1 2>&1; then + if bash -c "$1" 2>&1; then echo "Expected failure but succeeded" exit 1 fi diff --git a/e2e/test_ls_remote b/e2e/test_ls_remote index 0fd3c34db..0239677d9 100755 --- a/e2e/test_ls_remote +++ b/e2e/test_ls_remote @@ -1,4 +1,8 @@ #!/usr/bin/env bash set -euo pipefail +source "$(dirname "$0")/assert.sh" rtx p list-remote | grep nodejs +rtx p uninstall tiny +assert_fail "RTX_CONFIRM=no rtx ls-remote tiny" +assert_contains "RTX_CONFIRM=yes rtx ls-remote tiny" "1.1.0" diff --git a/e2e/test_tiny b/e2e/test_tiny index 18c5b9930..84f1f15b0 100755 --- a/e2e/test_tiny +++ b/e2e/test_tiny @@ -4,7 +4,7 @@ source "$(dirname "$0")/assert.sh" rtx cache clean rm -rf .rtx/installs/tiny -rtx trust .e2e.rtx.toml +RTX_CONFIRM=y rtx ls # auto-trust # this will fail when calling bin/list-all, but it won't stop it from executing RTX_TINY_LIST_ALL_FAIL=1 RTX_TINY_VERSION=latest rtx env >/dev/null diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index ca0c6768d..01b83a55a 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use color_eyre::eyre::Result; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; @@ -5,13 +7,15 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::Plugin; +use crate::plugins::{ExternalPlugin, Plugin, Plugins}; use crate::toolset::ToolVersionRequest; +use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::prompt; /// List runtime versions available for install /// -/// note that these versions are cached for commands like `rtx install nodejs@latest` -/// however _this_ command will always clear that cache and fetch the latest remote versions +/// note that the results are cached for 24 hours +/// run `rtx cache clean` to clear the cache and get fresh results #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = ["list-all", "list-remote"])] pub struct LsRemote { @@ -26,12 +30,8 @@ pub struct LsRemote { } impl Command for LsRemote { - fn run(self, config: Config, out: &mut Output) -> Result<()> { - let plugin = config - .plugins - .get(&self.plugin.plugin) - .ok_or(PluginNotInstalled(self.plugin.plugin))?; - plugin.clear_remote_version_cache()?; + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + let plugin = self.get_plugin(&mut config)?; let prefix = match self.plugin.tvr { Some(ToolVersionRequest::Version(_, v)) => Some(v), @@ -55,6 +55,40 @@ impl Command for LsRemote { } } +impl LsRemote { + fn get_plugin(&self, config: &mut Config) -> Result> { + let plugin_name = self.plugin.plugin.clone(); + let plugin = config.get_or_create_plugin(&plugin_name); + match plugin.as_ref() { + Plugins::External(p) => { + self.ensure_remote_plugin_is_installed(p, config)?; + Ok(plugin) + } // _ => {} + } + } + + fn ensure_remote_plugin_is_installed( + &self, + plugin: &ExternalPlugin, + config: &mut Config, + ) -> Result<()> { + if plugin.is_installed() { + return Ok(()); + } + if prompt::confirm(&format!( + "Plugin {} is not installed, would you like to install it?", + plugin.name + ))? { + let mpr = MultiProgressReport::new(config.settings.verbose); + let mut pr = mpr.add(); + plugin.install(config, &mut pr, false)?; + return Ok(()); + } + + Err(PluginNotInstalled(plugin.name.clone()))? + } +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx ls-remote nodejs diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 4c683d26c..577f047d1 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -20,6 +20,7 @@ use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, }; +use crate::ui::prompt; use crate::{dirs, env, parse_error}; #[derive(Debug, Default)] @@ -579,15 +580,11 @@ impl RtxToml { if self.is_trusted || cmd == "trust" || cmd == "completion" || cfg!(test) { return Ok(()); } - if console::user_attended_stderr() && cmd != "hook-env" { - let ans = dialoguer::Confirm::new() - .with_prompt(&format!( - "Config file {} is not trusted. Would you like to trust it?", - self.path.display() - )) - .default(false) - .interact() - .unwrap(); + if cmd != "hook-env" { + let ans = prompt::confirm(&format!( + "Config file {} is not trusted. Would you like to trust it?", + self.path.display() + ))?; if ans { config_file::trust(self.path.as_path())?; self.is_trusted = true; diff --git a/src/config/mod.rs b/src/config/mod.rs index ee0467297..c95d91a48 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -150,6 +150,18 @@ impl Config { .collect() } + pub fn get_or_create_plugin(&mut self, plugin_name: &PluginName) -> Arc { + self.plugins + .entry(plugin_name.clone()) + .or_insert_with(|| { + Arc::new(Plugins::External(ExternalPlugin::new( + &self.settings, + plugin_name, + ))) + }) + .clone() + } + fn load_all_aliases(&self) -> AliasMap { let mut aliases: AliasMap = self.aliases.clone(); let plugin_aliases: Vec<_> = self diff --git a/src/env.rs b/src/env.rs index 8e8189bd8..dc65f9c9e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -94,6 +94,7 @@ lazy_static! { }; pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); + pub static ref RTX_CONFIRM: Confirm = var_confirm("RTX_CONFIRM"); pub static ref RTX_EXPERIMENTAL: bool = var_is_true("RTX_EXPERIMENTAL"); pub static ref RTX_HIDE_UPDATE_WARNING: bool = var_is_true("RTX_HIDE_UPDATE_WARNING"); pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); @@ -107,6 +108,12 @@ lazy_static! { pub static ref GITHUB_API_TOKEN: Option = var("GITHUB_API_TOKEN").ok(); } +pub enum Confirm { + Yes, + No, + Prompt, +} + fn get_env_diff() -> EnvDiff { let env = vars().collect::>(); match env.get("__RTX_DIFF") { @@ -134,10 +141,30 @@ fn var_is_true(key: &str) -> bool { } } +fn var_is_false(key: &str) -> bool { + match var(key) { + Ok(v) => { + let v = v.to_lowercase(); + v == "n" || v == "no" || v == "false" || v == "0" || v == "off" + } + Err(_) => false, + } +} + fn var_path(key: &str) -> Option { var_os(key).map(PathBuf::from) } +fn var_confirm(key: &str) -> Confirm { + if var_is_true(key) { + Confirm::Yes + } else if var_is_false(key) { + Confirm::No + } else { + Confirm::Prompt + } +} + /// this returns the environment as if __RTX_DIFF was reversed. /// putting the shell back into a state before hook-env was run fn get_pristine_env( diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 35e3542cd..6efa25621 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -21,7 +21,7 @@ pub use tool_version_request::ToolVersionRequest; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; -use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; +use crate::plugins::{Plugin, PluginName, Plugins}; use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; use crate::ui::multi_progress_report::MultiProgressReport; @@ -119,12 +119,7 @@ impl Toolset { pub fn list_missing_plugins(&self, config: &mut Config) -> Vec { for plugin in self.versions.keys() { - config.plugins.entry(plugin.clone()).or_insert_with(|| { - Arc::new(Plugins::External(ExternalPlugin::new( - &config.settings, - plugin, - ))) - }); + config.get_or_create_plugin(plugin); } self.versions .keys() @@ -196,12 +191,7 @@ impl Toolset { mpr: &MultiProgressReport, ) -> Result<()> { for plugin in &missing_plugins { - config.plugins.entry(plugin.clone()).or_insert_with(|| { - Arc::new(Plugins::External(ExternalPlugin::new( - &config.settings, - plugin, - ))) - }); + config.get_or_create_plugin(plugin); } config.plugins.sort_keys(); let missing_plugins = missing_plugins diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 66bd7c324..60fe8b916 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,2 +1,3 @@ pub mod multi_progress_report; pub mod progress_report; +pub mod prompt; diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs new file mode 100644 index 000000000..ceac2760a --- /dev/null +++ b/src/ui/prompt.rs @@ -0,0 +1,17 @@ +use std::io; + +use dialoguer::Confirm; + +use crate::env; + +pub fn confirm(message: &str) -> io::Result { + match *env::RTX_CONFIRM { + env::Confirm::Yes => return Ok(true), + env::Confirm::No => return Ok(false), + env::Confirm::Prompt => (), + } + if !console::user_attended_stderr() { + return Ok(false); + } + Confirm::new().with_prompt(message).interact() +} From 294784be4be1f1df6882a56be3d05372a24e8aa9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 18:10:43 -0500 Subject: [PATCH 0655/1891] allow specifying git ref for custom plugin urls (#450) With this change, you can now specify a git ref in `.rtx.toml`, e.g.: ```toml [plugins] url = 'https://github.com/rtx-plugins/rtx-nodejs#deadbeef' ``` --- .rtx.toml | 2 +- README.md | 12 ++--- completions/_rtx | 16 +++---- completions/rtx.fish | 8 ++-- man/man1/rtx.1 | 2 +- src/cli/install.rs | 14 +++--- src/cli/plugins/install.rs | 48 +++++++------------ ...ll__tests__plugin_install_invalid_url.snap | 2 +- src/config/mod.rs | 19 +++++--- src/env.rs | 23 ++++++--- src/git.rs | 7 +++ src/plugins/external_plugin.rs | 15 +++--- 12 files changed, 89 insertions(+), 79 deletions(-) diff --git a/.rtx.toml b/.rtx.toml index 8fd7fbd89..67ce802f5 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -11,7 +11,7 @@ golang = { version = "latest", foo = "bar" } python = { version = "latest", virtualenv = "$HOME/.cache/venv" } [plugins] -node = 'https://github.com/rtx-plugins/rtx-nodejs' +node = 'https://github.com/rtx-plugins/rtx-nodejs#main' [alias.tiny] abc = '1' diff --git a/README.md b/README.md index e9a1247e9..1cafd019a 100644 --- a/README.md +++ b/README.md @@ -1719,12 +1719,12 @@ Options: ### `rtx install [OPTIONS] [RUNTIME]...` ``` -Install a runtime +Install a tool version -This will install a runtime to `~/.local/share/rtx/installs//` +This will install a tool version to `~/.local/share/rtx/installs//` It won't be used simply by being installed, however. For that, you must set up a `.tool-version` file manually or with `rtx local/global`. -Or you can call a runtime explicitly with `rtx exec @ -- `. +Or you can call a tool version explicitly with `rtx exec @ -- `. Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` @@ -1732,11 +1732,11 @@ Usage: install [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - Runtime(s) to install e.g.: nodejs@18 + Tool version(s) to install e.g.: nodejs@18 Options: -p, --plugin - Only install runtime(s) for + Only install tool version(s) for -f, --force Force reinstall even if already installed @@ -1748,7 +1748,7 @@ Examples: $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml - $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml + $ rtx install # installs everything specified in .tool-versions or .rtx.toml ``` ### `rtx latest ` diff --git a/completions/_rtx b/completions/_rtx index a4cdb0004..f3d5ce31e 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -677,8 +677,8 @@ Sets --jobs=1]' \ ;; (install) _arguments "${_arguments_options[@]}" \ -'()*-p+[Only install runtime(s) for ]:PLUGIN: ' \ -'()*--plugin=[Only install runtime(s) for ]:PLUGIN: ' \ +'()*-p+[Only install tool version(s) for ]:PLUGIN: ' \ +'()*--plugin=[Only install tool version(s) for ]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel @@ -686,8 +686,8 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Force reinstall even if already installed]' \ '--force[Force reinstall even if already installed]' \ -'(-p --plugin -f --force)-a[Install all missing runtimes as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ -'(-p --plugin -f --force)--all[Install all missing runtimes as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ +'(-p --plugin -f --force)-a[Install all missing tool versions as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ +'(-p --plugin -f --force)--all[Install all missing tool versions as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '--debug[Sets log level to debug]' \ @@ -699,7 +699,7 @@ Sets --jobs=1]' \ '--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to install e.g.\: nodejs@18:' \ +'*::runtime -- Tool version(s) to install e.g.\: nodejs@18:' \ && ret=0 ;; (latest) @@ -1723,8 +1723,8 @@ _rtx_commands() { 'g:Sets/gets the global runtime version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ -'install:Install a runtime' \ -'i:Install a runtime' \ +'install:Install a tool version' \ +'i:Install a tool version' \ 'latest:Gets the latest available version for a plugin' \ 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'l:Sets/gets tool version in local .tool-versions or .rtx.toml' \ @@ -2077,7 +2077,7 @@ _rtx__help_commands() { 'global:Sets/gets the global runtime version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ -'install:Install a runtime' \ +'install:Install a tool version' \ 'latest:Gets the latest available version for a plugin' \ 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed and/or currently selected tool versions' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index afd6b1ae6..fd32ee450 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -24,7 +24,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command wi complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets/gets the global runtime version(s)' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a tool version' complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest available version for a plugin' complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed and/or currently selected tool versions' @@ -322,12 +322,12 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only install runtime(s) for ' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only install tool version(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' -complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing runtimes as well as all plugins for the current directory This is hidden because it\'s now the default behavior' +complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing tool versions as well as all plugins for the current directory This is hidden because it\'s now the default behavior' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' @@ -665,7 +665,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index b8d1b5719..f23579f64 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -77,7 +77,7 @@ rtx\-implode(1) Removes rtx CLI and all related data .TP rtx\-install(1) -Install a runtime +Install a tool version .TP rtx\-latest(1) Gets the latest available version for a plugin diff --git a/src/cli/install.rs b/src/cli/install.rs index 8378304f1..85c0aa822 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -18,23 +18,23 @@ use crate::shims::reshim; use crate::toolset::{ToolVersionOptions, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; -/// Install a runtime +/// Install a tool version /// -/// This will install a runtime to `~/.local/share/rtx/installs//` +/// This will install a tool version to `~/.local/share/rtx/installs//` /// It won't be used simply by being installed, however. /// For that, you must set up a `.tool-version` file manually or with `rtx local/global`. -/// Or you can call a runtime explicitly with `rtx exec @ -- `. +/// Or you can call a tool version explicitly with `rtx exec @ -- `. /// /// Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` #[derive(Debug, clap::Args)] #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Install { - /// Runtime(s) to install + /// Tool version(s) to install /// e.g.: nodejs@18 #[clap(value_parser = RuntimeArgParser)] runtime: Option>, - /// Only install runtime(s) for + /// Only install tool version(s) for #[clap(long, short, conflicts_with = "runtime")] plugin: Option>, @@ -42,7 +42,7 @@ pub struct Install { #[clap(long, short, requires = "runtime")] force: bool, - /// Install all missing runtimes as well as all plugins for the current directory + /// Install all missing tool versions as well as all plugins for the current directory /// This is hidden because it's now the default behavior #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"], hide = true)] all: bool, @@ -221,7 +221,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ rtx install nodejs@18.0.0 # install specific nodejs version $ rtx install nodejs@18 # install fuzzy nodejs version $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml - $ rtx install # installs all runtimes specified in .tool-versions or .rtx.toml + $ rtx install # installs everything specified in .tool-versions or .rtx.toml "# ); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index e60dc0d0f..16f8c6c3e 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -54,12 +54,14 @@ impl Command for PluginsInstall { if self.all { return self.install_all_missing_plugins(&mut config, mpr); } - let (name, git_url) = - get_name_and_url(&config, &self.name.clone().unwrap(), &self.git_url)?; - if git_url.contains("://") { - self.install_one(&config, &name, &git_url, &mpr)?; + let (name, git_url) = get_name_and_url(&self.name.clone().unwrap(), &self.git_url)?; + if git_url.is_some() { + self.install_one(&config, &name, git_url, &mpr)?; } else { - let mut plugins: Vec = vec![name, git_url]; + let mut plugins: Vec = vec![name]; + if let Some(second) = self.git_url.clone() { + plugins.push(second); + }; plugins.extend(self.rest.clone()); self.install_many(&mut config, &plugins, mpr)?; } @@ -95,10 +97,7 @@ impl PluginsInstall { .install(|| -> Result<()> { plugins .into_par_iter() - .map(|plugin| { - let (_, git_url) = get_name_and_url(config, plugin, &None)?; - self.install_one(config, plugin, &git_url, &mpr) - }) + .map(|plugin| self.install_one(config, plugin, None, &mpr)) .collect::>>()?; Ok(()) }) @@ -108,15 +107,11 @@ impl PluginsInstall { &self, config: &Config, name: &String, - git_url: &str, + git_url: Option, mpr: &MultiProgressReport, ) -> Result<()> { let mut plugin = ExternalPlugin::new(&config.settings, name); - let (git_url, ref_) = git_url - .split_once('#') - .map_or((git_url, None), |(a, b)| (a, Some(b))); - plugin.repo_url = Some(git_url.to_string()); - plugin.repo_ref = ref_.map(|s| s.to_string()); + plugin.repo_url = git_url; if !self.force && plugin.is_installed() { mpr.warn(format!("plugin {} already installed", name)); } else { @@ -128,22 +123,15 @@ impl PluginsInstall { } } -fn get_name_and_url( - config: &Config, - name: &String, - git_url: &Option, -) -> Result<(String, String)> { +fn get_name_and_url(name: &str, git_url: &Option) -> Result<(String, Option)> { Ok(match git_url { - Some(url) => (name.clone(), url.clone()), - None => match name.contains(':') { - true => (get_name_from_url(name)?, name.clone()), - false => { - let git_url = config - .get_shorthands() - .get(name) - .ok_or_else(|| eyre!("could not find plugin {}", name))?; - (name.clone(), git_url.to_string()) - } + Some(url) => match url.contains("://") { + true => (name.to_string(), Some(url.clone())), + false => (name.to_string(), None), + }, + None => match name.contains("://") { + true => (get_name_from_url(name)?, Some(name.to_string())), + false => (name.to_string(), None), }, }) } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap index 29a867ab5..ed6fcbb6e 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap @@ -2,4 +2,4 @@ source: src/cli/plugins/install.rs expression: err --- -could not infer plugin name from url: tiny: +No repository found for plugin tiny: diff --git a/src/config/mod.rs b/src/config/mod.rs index c95d91a48..b08d55b66 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -43,6 +43,7 @@ pub struct Config { pub should_exit_early: bool, pub project_root: Option, shorthands: OnceCell>, + repo_urls: HashMap, } impl Config { @@ -50,7 +51,7 @@ impl Config { let global_config = load_rtxrc()?; let mut settings = global_config.settings(); let config_filenames = load_config_filenames(&IndexMap::new()); - let mut plugins = load_plugins(&settings.build())?; + let plugins = load_plugins(&settings.build())?; let config_files = load_all_config_files( &settings.build(), &config_filenames, @@ -82,13 +83,10 @@ impl Config { .collect_vec(); let should_exit_early = hook_env::should_exit_early(&watch_files); + let mut repo_urls = HashMap::new(); for cf in config_files.values() { for (plugin_name, repo_url) in cf.plugins() { - plugins.entry(plugin_name.clone()).or_insert_with(|| { - let mut plugin = ExternalPlugin::new(&settings, &plugin_name); - plugin.repo_url = Some(repo_url); - Arc::new(Plugins::External(plugin)) - }); + repo_urls.insert(plugin_name, repo_url); } } config_track.join().unwrap(); @@ -106,6 +104,7 @@ impl Config { global_config, plugins, should_exit_early, + repo_urls, }; debug!("{}", &config); @@ -118,6 +117,14 @@ impl Config { .get_or_init(|| get_shorthands(&self.settings)) } + pub fn get_repo_url(&self, plugin_name: &PluginName) -> Option { + match self.repo_urls.get(plugin_name) { + Some(url) => Some(url), + None => self.get_shorthands().get(plugin_name), + } + .cloned() + } + pub fn get_all_aliases(&self) -> &AliasMap { self.all_aliases.get_or_init(|| self.load_all_aliases()) } diff --git a/src/env.rs b/src/env.rs index dc65f9c9e..2a39e18a5 100644 --- a/src/env.rs +++ b/src/env.rs @@ -108,6 +108,7 @@ lazy_static! { pub static ref GITHUB_API_TOKEN: Option = var("GITHUB_API_TOKEN").ok(); } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { Yes, No, @@ -129,13 +130,7 @@ fn var_is_true(key: &str) -> bool { match var(key) { Ok(v) => { let v = v.to_lowercase(); - !v.is_empty() - && v != "n" - && v != "no" - && v != "false" - && v != "0" - && v != "off" - && v != " " + v == "y" || v == "yes" || v == "true" || v == "1" || v == "on" } Err(_) => false, } @@ -260,4 +255,18 @@ mod tests { ); remove_var("RTX_TEST_PATH"); } + + #[test] + fn test_var_confirm() { + set_var("RTX_TEST_CONFIRM", "true"); + assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::Yes); + remove_var("RTX_TEST_CONFIRM"); + set_var("RTX_TEST_CONFIRM", "false"); + assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::No); + remove_var("RTX_TEST_CONFIRM"); + set_var("RTX_TEST_CONFIRM", "prompt"); + assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::Prompt); + remove_var("RTX_TEST_CONFIRM"); + assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::Prompt); + } } diff --git a/src/git.rs b/src/git.rs index 736dff6b3..cf4303a50 100644 --- a/src/git.rs +++ b/src/git.rs @@ -120,6 +120,13 @@ impl Git { } } } + + pub fn split_url_and_ref(url: &str) -> (String, Option) { + match url.split_once('#') { + Some((url, _ref)) => (url.to_string(), Some(_ref.to_string())), + None => (url.to_string(), None), + } + } } fn get_git_version() -> Result { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index cf7b95a99..950a40c88 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -39,7 +39,6 @@ pub struct ExternalPlugin { pub name: PluginName, pub plugin_path: PathBuf, pub repo_url: Option, - pub repo_ref: Option, pub toml: RtxPluginToml, cache_path: PathBuf, downloads_path: PathBuf, @@ -86,7 +85,6 @@ impl ExternalPlugin { plugin_path, cache_path, repo_url: None, - repo_ref: None, toml, } } @@ -106,9 +104,10 @@ impl ExternalPlugin { self.decorate_progress_bar(pr, None); let repository = self .repo_url - .as_ref() - .or_else(|| config.get_shorthands().get(&self.name)) + .clone() + .or_else(|| config.get_repo_url(&self.name)) .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; + let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); debug!("install {} {:?}", self.name, repository); let _lock = self.get_lock(&self.plugin_path, force)?; @@ -118,9 +117,9 @@ impl ExternalPlugin { } let git = Git::new(self.plugin_path.to_path_buf()); - pr.set_message(format!("cloning {repository}")); - git.clone(repository)?; - if let Some(ref_) = &self.repo_ref { + pr.set_message(format!("cloning {repo_url}")); + git.clone(&repo_url)?; + if let Some(ref_) = &repo_ref { pr.set_message(format!("checking out {ref_}")); git.update(Some(ref_.to_string()))?; } @@ -140,7 +139,7 @@ impl ExternalPlugin { let sha = git.current_sha_short()?; pr.finish_with_message(format!( - "{repository}#{}", + "{repo_url}#{}", style(&sha).bright().yellow().for_stderr(), )); Ok(()) From ca0e07a752ffa5c85069bfa0bd7d4218aa06206d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 18:57:43 -0500 Subject: [PATCH 0656/1891] only prompt for missing tools once on local/global (#451) Fixes #448 --- src/cli/local.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/local.rs b/src/cli/local.rs index cca6a40fe..915dffba0 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -127,8 +127,9 @@ pub fn local( } let pin = pin || (config.settings.asdf_compat && !fuzzy); cf.add_runtimes(&mut config, &runtimes, pin)?; + } else { + install_missing_runtimes(&mut config, cf.as_ref())?; } - install_missing_runtimes(&mut config, cf.as_ref())?; if runtime.is_some() || remove.is_some() { cf.save()?; From dbcb6b87cbc81409f7bbbc7a66b449cb3ab94169 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:54:14 -0500 Subject: [PATCH 0657/1891] remove unused clear_remote_version_cache func (#452) --- src/cli/latest.rs | 1 - src/plugins/external_plugin.rs | 5 ----- src/plugins/mod.rs | 6 ------ 3 files changed, 12 deletions(-) diff --git a/src/cli/latest.rs b/src/cli/latest.rs index d4fb7aec4..45572edb5 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -46,7 +46,6 @@ impl Command for Latest { prefix = Some(config.resolve_alias(plugin.name(), &v)?); } - plugin.clear_remote_version_cache()?; if let Some(version) = plugin.latest_version(&config.settings, prefix)? { rtxprintln!(out, "{}", version); } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 950a40c88..7f6126d43 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -496,11 +496,6 @@ impl Plugin for ExternalPlugin { }) } - fn clear_remote_version_cache(&self) -> Result<()> { - self.remote_version_cache.clear()?; - self.latest_stable_cache.clear() - } - fn list_installed_versions(&self) -> Result> { Ok(match self.installs_path.exists() { true => file::dir_subdirs(&self.installs_path)? diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 9304873d9..7749c5b57 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -29,7 +29,6 @@ pub trait Plugin: Debug + Send + Sync + Eq + PartialEq + Hash { fn name(&self) -> &PluginName; fn toml(&self) -> &RtxPluginToml; fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec>; - fn clear_remote_version_cache(&self) -> Result<()>; fn list_installed_versions(&self) -> Result>; fn latest_version(&self, settings: &Settings, query: Option) -> Result>; fn latest_installed_version(&self) -> Result>; @@ -183,11 +182,6 @@ impl Plugin for Plugins { } } - fn clear_remote_version_cache(&self) -> Result<()> { - match self { - Plugins::External(p) => p.clear_remote_version_cache(), - } - } fn list_installed_versions(&self) -> Result> { match self { Plugins::External(p) => p.list_installed_versions(), From 42c727e6cb4e0f5ab168f973b4954bb134ecbdf7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 22:49:38 -0500 Subject: [PATCH 0658/1891] refactor: break plugins out into tool/plugins structs (#453) another refactor to enable core plugins --- justfile | 4 +- src/cache.rs | 1 + src/cli/current.rs | 29 +- src/cli/doctor.rs | 19 +- src/cli/external.rs | 8 +- src/cli/install.rs | 25 +- src/cli/latest.rs | 5 +- src/cli/ls.rs | 37 +-- src/cli/ls_remote.rs | 37 +-- src/cli/plugins/install.rs | 6 +- src/cli/plugins/ls.rs | 20 +- src/cli/plugins/ls_remote.rs | 5 +- src/cli/plugins/uninstall.rs | 4 +- src/cli/plugins/update.rs | 8 +- src/cli/prune.rs | 11 +- src/cli/shell.rs | 5 +- src/cli/uninstall.rs | 3 +- src/cli/where.rs | 5 +- src/cli/which.rs | 3 +- src/config/config_file/legacy_version.rs | 7 +- src/config/config_file/mod.rs | 2 +- src/config/mod.rs | 70 ++-- src/lib.rs | 1 + src/main.rs | 1 + src/plugins/external_plugin.rs | 402 +++++++---------------- src/plugins/external_plugin_cache.rs | 16 +- src/plugins/mod.rs | 264 ++------------- src/runtime_symlinks.rs | 30 +- src/shims.rs | 27 +- src/tool.rs | 324 ++++++++++++++++++ src/toolset/mod.rs | 49 ++- src/toolset/tool_version.rs | 101 +++--- src/toolset/tool_version_list.rs | 16 +- src/toolset/tool_version_request.rs | 5 +- 34 files changed, 732 insertions(+), 818 deletions(-) create mode 100644 src/tool.rs diff --git a/justfile b/justfile index d3e9eb5a1..3a4a8cddd 100644 --- a/justfile +++ b/justfile @@ -77,7 +77,7 @@ clean: # clippy, cargo fmt --check, and just --fmt lint: - cargo clippy + cargo clippy -- -Dwarnings cargo fmt --all -- --check shellcheck scripts/*.sh shfmt -d scripts/*.sh @@ -85,7 +85,7 @@ lint: # runs linters but makes fixes when possible lint-fix: - cargo clippy --fix --allow-staged --allow-dirty + cargo clippy --fix --allow-staged --allow-dirty -- -Dwarnings cargo fmt --all shellcheck scripts/*.sh shfmt -w scripts/*.sh diff --git a/src/cache.rs b/src/cache.rs index 229b43866..e82ac2f6b 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -94,6 +94,7 @@ where Ok(()) } + #[allow(dead_code)] pub fn clear(&self) -> Result<()> { let path = &self.cache_file_path; trace!("clearing cache {}", path.display()); diff --git a/src/cli/current.rs b/src/cli/current.rs index e25673a6b..3c33201ab 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -4,8 +4,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins; -use crate::plugins::Plugin; +use crate::tool::Tool; use crate::toolset::{Toolset, ToolsetBuilder}; /// Shows current active and installed runtime versions @@ -29,7 +28,7 @@ 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.plugins.get(plugin_name) { + 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); @@ -42,25 +41,15 @@ impl Command for Current { } impl Current { - fn one( - &self, - config: &Config, - ts: Toolset, - out: &mut Output, - plugin: &plugins::Plugins, - ) -> Result<()> { - match plugin { - plugins::Plugins::External(plugin) => { - if !plugin.is_installed() { - warn!("Plugin {} is not installed", plugin.name()); - return Ok(()); - } - } + fn one(&self, config: &Config, ts: Toolset, out: &mut Output, tool: &Tool) -> Result<()> { + if !tool.is_installed() { + warn!("Plugin {} is not installed", tool.name); + return Ok(()); } match ts .list_versions_by_plugin(config) .into_iter() - .find(|(p, _)| p.name() == plugin.name()) + .find(|(p, _)| p.name == tool.name) { Some((_, versions)) => { rtxprintln!( @@ -74,7 +63,7 @@ impl Current { ); } None => { - warn!("Plugin {} does not have a version set", plugin.name()); + warn!("Plugin {} does not have a version set", tool.name); } }; Ok(()) @@ -97,7 +86,7 @@ impl Current { rtxprintln!( out, "{} {}", - plugin.name(), + &plugin.name, versions .iter() .map(|v| v.version.to_string()) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index f7069b330..c31d57b35 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -11,7 +11,7 @@ use crate::cli::version::VERSION; use crate::config::Config; use crate::git::Git; use crate::output::Output; -use crate::plugins::{Plugin, Plugins}; +use crate::plugins::PluginType; use crate::shell::ShellType; use crate::toolset::ToolsetBuilder; use crate::{cli, cmd}; @@ -45,9 +45,9 @@ impl Command for Doctor { ); let mut checks = Vec::new(); - for plugin in config.external_plugins().values() { + for plugin in config.tools.values() { if !plugin.is_installed() { - checks.push(format!("plugin {} is not installed", plugin.name())); + checks.push(format!("plugin {} is not installed", &plugin.name)); continue; } } @@ -108,15 +108,15 @@ 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 + .tools .values() .filter(|p| p.is_installed()) .collect::>(); - let max_plugin_name_len = plugins.iter().map(|p| p.name().len()).max().unwrap_or(0) + 2; + let max_plugin_name_len = plugins.iter().map(|p| p.name.len()).max().unwrap_or(0) + 2; for p in plugins { - let padded_name = pad_str(p.name(), max_plugin_name_len, Alignment::Left, None); - let si = match p.as_ref() { - Plugins::External(p) => { + let padded_name = pad_str(&p.name, max_plugin_name_len, Alignment::Left, None); + let si = match p.plugin.get_type() { + PluginType::External => { let git = Git::new(p.plugin_path.clone()); match git.get_remote_url() { Some(url) => { @@ -127,7 +127,8 @@ fn render_plugins(config: &Config) -> String { } None => format!(" {padded_name}\n"), } - } //_ => {} + } + PluginType::Core => format!(" {padded_name}\n"), }; s.push_str(&si); } diff --git a/src/cli/external.rs b/src/cli/external.rs index 6de36104e..a768e40d2 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -4,11 +4,10 @@ use itertools::Itertools; use rayon::prelude::*; use crate::config::Config; -use crate::plugins::Plugin; pub fn commands(config: &Config) -> Vec { config - .plugins + .tools .values() .collect_vec() .into_par_iter() @@ -17,8 +16,7 @@ pub fn commands(config: &Config) -> Vec { Err(e) => { warn!( "failed to load external commands for plugin {}: {:#}", - p.name(), - e + p.name, e ); vec![] } @@ -48,7 +46,7 @@ pub fn execute( ) -> Result<()> { if let Some(_cmd) = external_commands.iter().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.tools.get(&plugin.to_string()).unwrap(); let args: Vec = matches .get_raw("args") .unwrap_or_default() diff --git a/src/cli/install.rs b/src/cli/install.rs index 85c0aa822..e5407d1eb 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,5 +1,4 @@ use std::collections::HashSet; -use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; use console::style; @@ -12,7 +11,7 @@ use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; +use crate::plugins::PluginName; use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; use crate::toolset::{ToolVersionOptions, ToolVersionRequest, ToolsetBuilder}; @@ -111,22 +110,12 @@ impl Install { .install(|| -> Result<()> { let mut tool_versions = vec![]; for (plugin_name, tvr, opts) in tool_version_requests { - let plugin = match config.plugins.get(&plugin_name).cloned() { - Some(plugin) => plugin, - None => Arc::new(Plugins::External(ExternalPlugin::new( - &config.settings, - &plugin_name, - ))), - }; - match plugin.as_ref() { - Plugins::External(plugin) => { - if !plugin.is_installed() { - let mut pr = mpr.add(); - if let Err(err) = plugin.install(&config, &mut pr, false) { - pr.error(); - return Err(err)?; - } - } + let plugin = config.get_or_create_tool(&plugin_name); + if !plugin.is_installed() { + let mut pr = mpr.add(); + if let Err(err) = plugin.install(&config, &mut pr, false) { + pr.error(); + return Err(err)?; } } let tv = tvr.resolve(&config, &plugin, opts, ts.latest_versions)?; diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 45572edb5..c7e09045f 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -5,7 +5,6 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; use crate::toolset::ToolVersionRequest; /// Gets the latest available version for a plugin @@ -33,7 +32,7 @@ impl Command for Latest { style(&self.runtime).cyan().for_stderr() ))?, }; - let plugin = config.plugins.get(&self.runtime.plugin).ok_or_else(|| { + let plugin = config.tools.get(&self.runtime.plugin).ok_or_else(|| { eyre!( "plugin {} not found. run {} to install it", style(self.runtime.plugin.to_string()).cyan().for_stderr(), @@ -43,7 +42,7 @@ impl Command for Latest { ) })?; if let Some(v) = prefix { - prefix = Some(config.resolve_alias(plugin.name(), &v)?); + prefix = Some(config.resolve_alias(&plugin.name, &v)?); } if let Some(version) = plugin.latest_version(&config.settings, prefix)? { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 87f01473b..4235a7918 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -16,7 +16,8 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::{Plugin, PluginName, Plugins}; +use crate::plugins::PluginName; +use crate::tool::Tool; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; /// List installed and/or currently selected tool versions @@ -84,7 +85,7 @@ impl Ls { fn verify_plugin(&self, config: &Config) -> Result<()> { match &self.plugin { Some(plugin_name) => { - let plugin = config.plugins.get(plugin_name); + let plugin = config.tools.get(plugin_name); if plugin.is_none() || !plugin.unwrap().is_installed() { return Err(PluginNotInstalled(plugin_name.clone()))?; } @@ -98,11 +99,11 @@ impl Ls { let mut plugins = JSONOutput::new(); for (plugin_name, runtimes) in &runtimes .into_iter() - .group_by(|(p, _, _)| p.name().to_string()) + .group_by(|(p, _, _)| p.name.to_string()) { let runtimes = runtimes - .map(|(p, tv, source)| JSONToolVersion { - install_path: p.install_path(&tv), + .map(|(_, tv, source)| JSONToolVersion { + install_path: tv.install_path(), version: tv.version, requested_version: source.as_ref().map(|_| tv.request.version()), source: source.map(|source| source.as_json()), @@ -137,15 +138,11 @@ impl Ls { Ok(()) } - fn display_user( - &self, - runtimes: Vec<(Arc, ToolVersion, Option)>, - out: &mut Output, - ) -> Result<()> { + fn display_user(&self, runtimes: Vec, out: &mut Output) -> Result<()> { let output = runtimes .into_iter() .map(|(p, tv, source)| { - let plugin = p.name().to_string(); + let plugin = p.name.to_string(); let version = if !p.is_version_installed(&tv) { VersionStatus::Missing(tv.version) } else if source.is_some() { @@ -179,9 +176,9 @@ impl Ls { .max(0) as usize; let version = version.to_string(); let version = pad(&version, max_version_len - plugin_extra); - match request { + match &request { Some((source, requested)) => { - let source = pad(&source, max_source_len - version_extra); + let source = pad(source, max_source_len - version_extra); rtxprintln!(out, "{} {} {} {}", plugin, version, source, requested); } None => { @@ -193,28 +190,28 @@ impl Ls { } } -type RuntimeRow = (Arc, ToolVersion, Option); +type RuntimeRow = (Arc, ToolVersion, Option); fn get_runtime_list( config: &mut Config, plugin_flag: &Option, ) -> Result> { let ts = ToolsetBuilder::new().build(config)?; - let mut versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = ts + let mut versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = ts .list_installed_versions(config)? .into_iter() .filter(|(p, _)| match plugin_flag { - Some(plugin) => p.name() == plugin, + Some(plugin) => &p.name == plugin, None => true, }) - .map(|(p, tv)| ((p.name().clone(), tv.version.clone()), (p, tv))) + .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) .collect(); let active = ts .list_current_versions(config) .into_iter() - .map(|(p, tv)| ((p.name().clone(), tv.version.clone()), (p, tv))) - .collect::, ToolVersion)>>(); + .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) + .collect::, ToolVersion)>>(); versions.extend( active @@ -224,7 +221,7 @@ fn get_runtime_list( Some(plugin) => plugin_name == plugin, None => true, }) - .collect::, ToolVersion))>>(), + .collect::, ToolVersion))>>(), ); let rvs: Vec = versions diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 01b83a55a..fdb0a5fc8 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,13 +1,12 @@ -use std::sync::Arc; - use color_eyre::eyre::Result; +use std::sync::Arc; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::{ExternalPlugin, Plugin, Plugins}; +use crate::tool::Tool; use crate::toolset::ToolVersionRequest; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; @@ -33,16 +32,16 @@ impl Command for LsRemote { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let plugin = self.get_plugin(&mut config)?; - let prefix = match self.plugin.tvr { + let prefix = match &self.plugin.tvr { Some(ToolVersionRequest::Version(_, v)) => Some(v), - _ => self.prefix, + _ => self.prefix.as_ref(), }; let versions = plugin.list_remote_versions(&config.settings)?.clone(); let versions = match prefix { Some(prefix) => versions .into_iter() - .filter(|v| v.starts_with(&prefix)) + .filter(|v| v.starts_with(prefix)) .collect(), None => versions, }; @@ -56,36 +55,28 @@ impl Command for LsRemote { } impl LsRemote { - fn get_plugin(&self, config: &mut Config) -> Result> { + fn get_plugin(&self, config: &mut Config) -> Result> { let plugin_name = self.plugin.plugin.clone(); - let plugin = config.get_or_create_plugin(&plugin_name); - match plugin.as_ref() { - Plugins::External(p) => { - self.ensure_remote_plugin_is_installed(p, config)?; - Ok(plugin) - } // _ => {} - } + let tool = config.get_or_create_tool(&plugin_name); + self.ensure_remote_plugin_is_installed(&tool, config)?; + Ok(tool) } - fn ensure_remote_plugin_is_installed( - &self, - plugin: &ExternalPlugin, - config: &mut Config, - ) -> Result<()> { - if plugin.is_installed() { + fn ensure_remote_plugin_is_installed(&self, tool: &Tool, config: &mut Config) -> Result<()> { + if tool.is_installed() { return Ok(()); } if prompt::confirm(&format!( "Plugin {} is not installed, would you like to install it?", - plugin.name + tool.name ))? { let mpr = MultiProgressReport::new(config.settings.verbose); let mut pr = mpr.add(); - plugin.install(config, &mut pr, false)?; + tool.install(config, &mut pr, false)?; return Ok(()); } - Err(PluginNotInstalled(plugin.name.clone()))? + Err(PluginNotInstalled(tool.name.clone()))? } } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 16f8c6c3e..a0d72fb69 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -7,6 +7,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::{ExternalPlugin, Plugin, PluginName}; +use crate::tool::Tool; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; @@ -116,8 +117,9 @@ impl PluginsInstall { mpr.warn(format!("plugin {} already installed", name)); } else { let mut pr = mpr.add(); - plugin.decorate_progress_bar(&mut pr, None); - plugin.install(config, &mut pr, self.force)?; + let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); + tool.decorate_progress_bar(&mut pr, None); + tool.install(config, &mut pr, self.force)?; } Ok(()) } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 02fc9747c..779ab46bd 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -4,8 +4,6 @@ use crate::cli::command::Command; use crate::cli::plugins::ls_remote::PluginsLsRemote; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; -use crate::plugins::Plugins; /// List installed plugins /// @@ -35,20 +33,16 @@ impl Command for PluginsLs { } if self.urls { - for plugin in config.plugins.values() { - match plugin.as_ref() { - Plugins::External(plugin) => { - if let Some(url) = plugin.get_remote_url() { - rtxprintln!(out, "{:29} {}", plugin.name, url); - continue; - } - } //_ => {} + for plugin in config.tools.values() { + if let Some(url) = plugin.get_remote_url() { + rtxprintln!(out, "{:29} {}", plugin.name, url); + continue; } - rtxprintln!(out, "{}", plugin.name()); + rtxprintln!(out, "{}", plugin.name); } } else { - for plugin in config.plugins.values() { - rtxprintln!(out, "{}", plugin.name()); + for plugin in config.tools.values() { + rtxprintln!(out, "{}", plugin.name); } } Ok(()) diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 29bdd9e99..cd197245a 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -7,7 +7,6 @@ use itertools::Itertools; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; /// List all available remote plugins /// @@ -29,10 +28,10 @@ pub struct PluginsLsRemote { impl Command for PluginsLsRemote { fn run(self, config: Config, out: &mut Output) -> Result<()> { let installed_plugins = config - .external_plugins() + .tools .values() .filter(|p| p.is_installed()) - .map(|p| p.name().clone()) + .map(|p| p.name.clone()) .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 ad3dbd2bc..862d86c38 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -4,7 +4,6 @@ use console::style; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; use crate::ui::multi_progress_report::MultiProgressReport; /// Removes a plugin @@ -34,8 +33,7 @@ impl PluginsUninstall { plugin_name: &String, mpr: &MultiProgressReport, ) -> Result<()> { - let plugin = config.external_plugins().remove(plugin_name); - match plugin { + match config.tools.get(plugin_name) { Some(plugin) if plugin.is_installed() => { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, None); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index ed8f7fab8..c26e0ce5d 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::{Plugin, PluginName}; +use crate::plugins::PluginName; /// Updates a plugin to the latest version /// @@ -31,10 +31,10 @@ impl Command for Update { Some((p, ref_)) => (p, Some(ref_.to_string())), None => (p.as_str(), None), }; - let plugin = config.external_plugins().remove(p).ok_or_else(|| { + let plugin = config.tools.get(p).ok_or_else(|| { eyre!("plugin {} not found", style(p).cyan().for_stderr()) })?; - Ok((plugin, ref_)) + Ok((plugin.clone(), ref_)) }) .collect::>()?, None => config @@ -45,7 +45,7 @@ impl Command for Update { }; for (plugin, ref_) in plugins { - rtxprintln!(out, "updating plugin {}", plugin.name()); + rtxprintln!(out, "updating plugin {}", plugin.name); plugin.update(ref_)?; } Ok(()) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 3f075bdc6..27ac1cb98 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -6,7 +6,8 @@ use std::sync::Arc; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::{Plugin, PluginName, Plugins}; +use crate::plugins::PluginName; +use crate::tool::Tool; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -35,7 +36,7 @@ impl Command for Prune { .list_installed_versions(&config)? .into_iter() .map(|(p, tv)| (tv.to_string(), (p, tv))) - .collect::, ToolVersion)>>(); + .collect::, ToolVersion)>>(); if let Some(plugins) = &self.plugins { to_delete.retain(|_, (_, tv)| plugins.contains(&tv.plugin_name)); @@ -54,11 +55,7 @@ impl Command for Prune { } impl Prune { - fn delete( - &self, - config: &mut Config, - to_delete: Vec<(Arc, ToolVersion)>, - ) -> Result<()> { + fn delete(&self, config: &mut Config, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); for (p, tv) in to_delete { let mut pr = mpr.add(); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 41d48c7fc..4b78ef8ce 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -6,7 +6,6 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; use crate::shell::get_shell; use crate::toolset::{ToolSource, ToolsetBuilder}; @@ -38,9 +37,9 @@ impl Command for Shell { let shell = get_shell(None).expect("no shell detected"); for (p, tv) in ts.list_current_installed_versions(&config) { - let source = &ts.versions.get(p.name()).unwrap().source; + let source = &ts.versions.get(&p.name).unwrap().source; if matches!(source, ToolSource::Argument) { - let k = format!("RTX_{}_VERSION", p.name().to_uppercase()); + let k = format!("RTX_{}_VERSION", p.name.to_uppercase()); let op = if self.unset { shell.unset_env(&k) } else { diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 430ee9b04..6e0d54f2d 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -5,7 +5,6 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; use crate::ui::multi_progress_report::MultiProgressReport; /// Removes runtime versions @@ -23,7 +22,7 @@ impl Command for Uninstall { let tool_versions = runtimes .iter() .map(|a| { - let plugin = match config.plugins.get(&a.plugin) { + let plugin = match config.tools.get(&a.plugin) { Some(plugin) => plugin, None => todo!(), }; diff --git a/src/cli/where.rs b/src/cli/where.rs index 87078b136..9cb7cff6e 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -5,7 +5,6 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; use crate::output::Output; -use crate::plugins::Plugin; use crate::toolset::ToolsetBuilder; /// Display the installation path for a runtime @@ -50,7 +49,7 @@ impl Command for Where { _ => self.runtime, }; - let plugin = match config.plugins.get(&runtime.plugin) { + let plugin = match config.tools.get(&runtime.plugin) { Some(plugin) => plugin, None => Err(PluginNotInstalled(runtime.plugin.clone()))?, }; @@ -61,7 +60,7 @@ impl Command for Where { .map(|tvr| tvr.resolve(&config, plugin, Default::default(), false)) { Some(Ok(tv)) if plugin.is_version_installed(&tv) => { - rtxprintln!(out, "{}", plugin.install_path(&tv).to_string_lossy()); + rtxprintln!(out, "{}", tv.install_path().to_string_lossy()); Ok(()) } _ => Err(VersionNotInstalled( diff --git a/src/cli/which.rs b/src/cli/which.rs index deacb5e88..898bff66e 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -3,7 +3,6 @@ use color_eyre::eyre::{eyre, Result}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::Plugin; use crate::toolset::ToolsetBuilder; /// Shows the path that a bin name points to @@ -31,7 +30,7 @@ impl Command for Which { if self.version { rtxprintln!(out, "{}", tv.version); } else if self.plugin { - rtxprintln!(out, "{}", p.name()); + rtxprintln!(out, "{}", p.name); } else { let path = p.which(&config, &tv, &self.bin_name)?; rtxprintln!(out, "{}", path.unwrap().display()); diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 1162b938d..4eb082327 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -8,7 +8,8 @@ use color_eyre::eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, Settings}; -use crate::plugins::{Plugin, PluginName, Plugins}; +use crate::plugins::PluginName; +use crate::tool::Tool; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; #[derive(Debug)] @@ -18,11 +19,11 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(settings: &Settings, path: PathBuf, plugin: &Plugins) -> Result { + pub fn parse(settings: &Settings, path: PathBuf, plugin: &Tool) -> Result { let version = plugin.parse_legacy_file(path.as_path(), settings)?; Ok(Self { - toolset: build_toolset(&path, plugin.name().as_str(), version.as_str()), + toolset: build_toolset(&path, plugin.name.as_str(), version.as_str()), path, }) } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 7b4e3d5b8..b80f76bb7 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -81,7 +81,7 @@ impl dyn ConfigFile { .into_iter() .map(|tvr| { if pin { - let plugin = config.plugins.get(&plugin).unwrap(); + let plugin = config.tools.get(&plugin).unwrap(); let tv = tvr.resolve(config, plugin, Default::default(), ts.latest_versions)?; Ok(tv.version) diff --git a/src/config/mod.rs b/src/config/mod.rs index b08d55b66..12163493c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -18,8 +18,9 @@ use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; use crate::env::CI; -use crate::plugins::{ExternalPlugin, Plugin, PluginName, Plugins}; +use crate::plugins::{ExternalPlugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; +use crate::tool::Tool; use crate::{cli, dirs, duration, env, file, hook_env}; pub mod config_file; @@ -35,7 +36,7 @@ pub struct Config { pub global_config: RtxToml, pub legacy_files: IndexMap, pub config_files: ConfigMap, - pub plugins: IndexMap>, + pub tools: IndexMap>, pub env: IndexMap, pub path_dirs: Vec, pub aliases: AliasMap, @@ -51,11 +52,11 @@ impl Config { let global_config = load_rtxrc()?; let mut settings = global_config.settings(); let config_filenames = load_config_filenames(&IndexMap::new()); - let plugins = load_plugins(&settings.build())?; + let tools = load_plugins(&settings.build())?; let config_files = load_all_config_files( &settings.build(), &config_filenames, - &plugins, + &tools, &IndexMap::new(), IndexMap::new(), )?; @@ -65,14 +66,14 @@ impl Config { let settings = settings.build(); trace!("Settings: {:#?}", settings); - let legacy_files = load_legacy_files(&settings, &plugins); + let legacy_files = load_legacy_files(&settings, &tools); let config_filenames = load_config_filenames(&legacy_files); let config_track = track_config_files(&config_filenames); let config_files = load_all_config_files( &settings, &config_filenames, - &plugins, + &tools, &legacy_files, config_files, ); @@ -102,7 +103,7 @@ impl Config { settings, legacy_files, global_config, - plugins, + tools, should_exit_early, repo_urls, }; @@ -139,7 +140,7 @@ impl Config { return Ok(alias.clone()); } } - if let Some(plugin) = self.plugins.get(plugin_name) { + if let Some(plugin) = self.tools.get(plugin_name) { if let Some(alias) = plugin.get_aliases(&self.settings)?.get(v) { return Ok(alias.clone()); } @@ -147,24 +148,21 @@ impl Config { Ok(v.to_string()) } - pub fn external_plugins(&self) -> IndexMap { - self.plugins + pub fn external_plugins(&self) -> Vec<(&PluginName, Arc)> { + self.tools .iter() - .map(|(name, plugin)| match plugin.as_ref() { - Plugins::External(plugin) => (name.clone(), plugin), - //_ => None, - }) + .filter(|(_, tool)| matches!(tool.plugin.get_type(), PluginType::External)) + .map(|(name, tool)| (name, tool.clone())) .collect() } - pub fn get_or_create_plugin(&mut self, plugin_name: &PluginName) -> Arc { - self.plugins + pub fn get_or_create_tool(&mut self, plugin_name: &PluginName) -> Arc { + self.tools .entry(plugin_name.clone()) .or_insert_with(|| { - Arc::new(Plugins::External(ExternalPlugin::new( - &self.settings, - plugin_name, - ))) + let plugin = ExternalPlugin::new(&self.settings, plugin_name); + let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); + Arc::new(tool) }) .clone() } @@ -172,7 +170,7 @@ impl Config { fn load_all_aliases(&self) -> AliasMap { let mut aliases: AliasMap = self.aliases.clone(); let plugin_aliases: Vec<_> = self - .plugins + .tools .values() .par_bridge() .map(|plugin| { @@ -183,7 +181,7 @@ impl Config { IndexMap::new() } }; - (plugin.name(), aliases) + (plugin.name.clone(), aliases) }) .collect(); for (plugin, plugin_aliases) in plugin_aliases { @@ -314,10 +312,10 @@ fn load_rtxrc() -> Result { } } -fn load_plugins(settings: &Settings) -> Result>> { - let plugins = ExternalPlugin::list(settings)? +fn load_plugins(settings: &Settings) -> Result>> { + let plugins = Tool::list(settings)? .into_par_iter() - .map(|p| (p.name.clone(), Arc::new(Plugins::External(p)))) + .map(|p| (p.name.clone(), Arc::new(p))) .collect::>() .into_iter() .sorted_by_cached_key(|(p, _)| p.to_string()) @@ -327,20 +325,20 @@ fn load_plugins(settings: &Settings) -> Result fn load_legacy_files( settings: &Settings, - plugins: &IndexMap>, + tools: &IndexMap>, ) -> IndexMap { if !settings.legacy_version_file { return IndexMap::new(); } - plugins + tools .values() .collect_vec() .into_par_iter() - .filter_map(|plugin| match plugin.legacy_filenames(settings) { + .filter_map(|tool| match tool.legacy_filenames(settings) { Ok(filenames) => Some( filenames .iter() - .map(|f| (f.to_string(), plugin.name().to_string())) + .map(|f| (f.to_string(), tool.name.to_string())) .collect_vec(), ), Err(err) => { @@ -392,7 +390,7 @@ fn get_global_rtx_toml() -> PathBuf { fn load_all_config_files( settings: &Settings, config_filenames: &[PathBuf], - plugins: &IndexMap>, + tools: &IndexMap>, legacy_filenames: &IndexMap, mut existing: IndexMap>, ) -> Result { @@ -406,7 +404,7 @@ fn load_all_config_files( // already parsed so just return it Some(cf) => Ok((f, cf)), // need to parse this config file - None => match parse_config_file(&f, settings, legacy_filenames, plugins) { + None => match parse_config_file(&f, settings, legacy_filenames, tools) { Ok(cf) => Ok((f, cf)), Err(err) => Err(eyre!("error parsing: {} {:#}", f.display(), err)), }, @@ -422,11 +420,11 @@ fn parse_config_file( f: &PathBuf, settings: &Settings, legacy_filenames: &IndexMap, - plugins: &IndexMap>, + tools: &IndexMap>, ) -> Result> { let is_trusted = config_file::is_trusted(settings, f); match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { - Some(plugin) => LegacyVersionFile::parse(settings, f.into(), plugins.get(plugin).unwrap()) + Some(plugin) => LegacyVersionFile::parse(settings, f.into(), tools.get(plugin).unwrap()) .map(|f| Box::new(f) as Box), None => config_file::parse(f, is_trusted), } @@ -493,11 +491,7 @@ 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 - .keys() - .map(|p| p.to_string()) - .collect::>(); + let plugins = self.tools.keys().map(|p| p.to_string()).collect::>(); let config_files = self .config_files .iter() diff --git a/src/lib.rs b/src/lib.rs index 726e76e62..fa30c5def 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,5 +36,6 @@ mod tera; #[cfg(test)] mod test; mod toml; +mod tool; mod toolset; mod ui; diff --git a/src/main.rs b/src/main.rs index 8f0046252..e40e91f1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,6 +47,7 @@ pub mod tera; #[cfg(test)] mod test; mod toml; +mod tool; mod toolset; mod ui; diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 7f6126d43..ea2946ea5 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::fs; -use std::fs::{remove_file, File}; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::exit; @@ -11,7 +10,6 @@ use console::style; use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::Lazy; -use versions::Versioning; use crate::cache::CacheManager; use crate::cmd::cmd; @@ -20,15 +18,12 @@ use crate::env::PREFER_STALE; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; use crate::file::remove_all; -use crate::file::{create_dir_all, display_path, remove_all_with_warning}; use crate::git::Git; use crate::hash::hash_to_str; -use crate::lock_file::LockFile; use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::rtx_plugin_toml::RtxPluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; -use crate::plugins::{Plugin, PluginName, Script, ScriptManager}; -use crate::runtime_symlinks::is_runtime_symlink; +use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{dirs, env, file}; @@ -89,135 +84,6 @@ impl ExternalPlugin { } } - pub fn list(settings: &Settings) -> Result> { - Ok(file::dir_subdirs(&dirs::PLUGINS)? - .iter() - .map(|name| Self::new(settings, name)) - .collect()) - } - pub fn get_remote_url(&self) -> Option { - let git = Git::new(self.plugin_path.to_path_buf()); - git.get_remote_url() - } - - pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { - self.decorate_progress_bar(pr, None); - let repository = self - .repo_url - .clone() - .or_else(|| config.get_repo_url(&self.name)) - .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; - let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); - debug!("install {} {:?}", self.name, repository); - - let _lock = self.get_lock(&self.plugin_path, force)?; - - if self.is_installed() { - self.uninstall(pr)?; - } - - let git = Git::new(self.plugin_path.to_path_buf()); - pr.set_message(format!("cloning {repo_url}")); - git.clone(&repo_url)?; - if let Some(ref_) = &repo_ref { - pr.set_message(format!("checking out {ref_}")); - git.update(Some(ref_.to_string()))?; - } - - pr.set_message("loading plugin remote versions".into()); - if self.has_list_all_script() { - self.list_remote_versions(&config.settings)?; - } - if self.has_list_alias_script() { - pr.set_message("getting plugin aliases".into()); - self.get_aliases(&config.settings)?; - } - if self.has_list_legacy_filenames_script() { - pr.set_message("getting plugin legacy filenames".into()); - self.legacy_filenames(&config.settings)?; - } - - let sha = git.current_sha_short()?; - pr.finish_with_message(format!( - "{repo_url}#{}", - style(&sha).bright().yellow().for_stderr(), - )); - Ok(()) - } - - pub fn uninstall(&self, pr: &ProgressReport) -> Result<()> { - if !self.is_installed() { - return Ok(()); - } - pr.set_message("uninstalling".into()); - - let rmdir = |dir: &Path| { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", &dir.to_string_lossy())); - remove_all(dir).wrap_err_with(|| { - format!( - "Failed to remove directory {}", - style(&dir.to_string_lossy()).cyan().for_stderr() - ) - }) - }; - - rmdir(&self.downloads_path)?; - rmdir(&self.installs_path)?; - rmdir(&self.plugin_path)?; - - Ok(()) - } - - pub fn update(&self, gitref: Option) -> Result<()> { - let plugin_path = self.plugin_path.to_path_buf(); - if plugin_path.is_symlink() { - warn!( - "Plugin: {} is a symlink, not updating", - style(&self.name).cyan().for_stderr() - ); - return Ok(()); - } - let git = Git::new(plugin_path); - if !git.is_repo() { - warn!( - "Plugin {} is not a git repository, not updating", - style(&self.name).cyan().for_stderr() - ); - return Ok(()); - } - // TODO: asdf_run_hook "pre_plugin_update" - let (_pre, _post) = git.update(gitref)?; - // TODO: asdf_run_hook "post_plugin_update" - Ok(()) - } - - fn latest_stable_version(&self, settings: &Settings) -> Result> { - if let Some(latest) = self.get_latest_stable(settings)? { - Ok(Some(latest)) - } else { - self.latest_version(settings, Some("latest".into())) - } - } - - fn get_latest_stable(&self, settings: &Settings) -> Result> { - if !self.has_latest_stable_script() { - return Ok(None); - } - self.latest_stable_cache - .get_or_try_init(|| self.fetch_latest_stable(settings)) - .map_err(|err| { - eyre!( - "Failed fetching latest stable version for plugin {}: {}", - style(&self.name).cyan().for_stderr(), - err - ) - }) - .cloned() - } - fn fetch_remote_versions(&self, settings: &Settings) -> Result> { let result = self .script_man @@ -330,45 +196,6 @@ impl ExternalPlugin { Ok(()) } - fn get_lock(&self, path: &Path, force: bool) -> Result> { - let lock = if force { - None - } else { - let lock = LockFile::new(path) - .with_callback(|l| { - debug!("waiting for lock on {}", display_path(l)); - }) - .lock()?; - Some(lock) - }; - Ok(lock) - } - - fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { - self.cache_path(tv).join("incomplete") - } - - fn create_install_dirs(&self, tv: &ToolVersion) -> Result<()> { - let _ = remove_all_with_warning(self.install_path(tv)); - let _ = remove_all_with_warning(self.download_path(tv)); - let _ = remove_all_with_warning(self.cache_path(tv)); - let _ = remove_file(self.install_path(tv)); // removes if it is a symlink - create_dir_all(self.install_path(tv))?; - create_dir_all(self.download_path(tv))?; - create_dir_all(self.cache_path(tv))?; - File::create(self.incomplete_file_path(tv))?; - Ok(()) - } - fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { - let _ = remove_all_with_warning(self.install_path(tv)); - self.cleanup_install_dirs(settings, tv); - } - fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { - if !settings.always_keep_download { - let _ = remove_all_with_warning(self.download_path(tv)); - } - } - fn fetch_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { let list_bin_paths = self.plugin_path.join("bin/list-bin-paths"); let bin_paths = if matches!(tv.request, ToolVersionRequest::System(_)) { @@ -384,7 +211,7 @@ impl ExternalPlugin { }; let bin_paths = bin_paths .into_iter() - .map(|path| self.install_path(tv).join(path)) + .map(|path| tv.install_path().join(path)) .collect(); Ok(bin_paths) } @@ -424,19 +251,19 @@ impl ExternalPlugin { sm = sm .with_env( "RTX_INSTALL_PATH".into(), - self.install_path(tv).to_string_lossy().to_string(), + tv.install_path().to_string_lossy().to_string(), ) .with_env( "ASDF_INSTALL_PATH".into(), - self.install_path(tv).to_string_lossy().to_string(), + tv.install_path().to_string_lossy().to_string(), ) .with_env( "RTX_DOWNLOAD_PATH".into(), - self.download_path(tv).to_string_lossy().to_string(), + tv.download_path().to_string_lossy().to_string(), ) .with_env( "ASDF_DOWNLOAD_PATH".into(), - self.download_path(tv).to_string_lossy().to_string(), + tv.download_path().to_string_lossy().to_string(), ) .with_env("RTX_INSTALL_TYPE".into(), install_type.into()) .with_env("ASDF_INSTALL_TYPE".into(), install_type.into()) @@ -476,14 +303,12 @@ impl Hash for ExternalPlugin { } impl Plugin for ExternalPlugin { + fn get_type(&self) -> PluginType { + PluginType::External + } fn name(&self) -> &PluginName { &self.name } - - fn toml(&self) -> &RtxPluginToml { - &self.toml - } - fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) @@ -496,50 +321,120 @@ impl Plugin for ExternalPlugin { }) } - fn list_installed_versions(&self) -> Result> { - Ok(match self.installs_path.exists() { - true => file::dir_subdirs(&self.installs_path)? - .iter() - .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) - .map(|v| Versioning::new(v).unwrap_or_default()) - .sorted() - .map(|v| v.to_string()) - .collect(), - false => vec![], - }) + fn latest_stable_version(&self, settings: &Settings) -> Result> { + if !self.has_latest_stable_script() { + return Ok(None); + } + self.latest_stable_cache + .get_or_try_init(|| self.fetch_latest_stable(settings)) + .map_err(|err| { + eyre!( + "Failed fetching latest stable version for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err + ) + }) + .cloned() } - fn latest_version(&self, settings: &Settings, query: Option) -> Result> { - match query { - Some(query) => { - let matches = self.list_versions_matching(settings, &query)?; - let v = match matches.contains(&query) { - true => Some(query), - false => matches.last().map(|v| v.to_string()), - }; - Ok(v) - } - None => self.latest_stable_version(settings), + fn get_remote_url(&self) -> Option { + let git = Git::new(self.plugin_path.to_path_buf()); + git.get_remote_url() + } + + fn is_installed(&self) -> bool { + self.plugin_path.exists() + } + + fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { + let repository = self + .repo_url + .clone() + .or_else(|| config.get_repo_url(&self.name)) + .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; + let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); + debug!("install {} {:?}", self.name, repository); + + if self.is_installed() { + self.uninstall(pr)?; + } + + let git = Git::new(self.plugin_path.to_path_buf()); + pr.set_message(format!("cloning {repo_url}")); + git.clone(&repo_url)?; + if let Some(ref_) = &repo_ref { + pr.set_message(format!("checking out {ref_}")); + git.update(Some(ref_.to_string()))?; } + + pr.set_message("loading plugin remote versions".into()); + if self.has_list_all_script() { + self.list_remote_versions(&config.settings)?; + } + if self.has_list_alias_script() { + pr.set_message("getting plugin aliases".into()); + self.get_aliases(&config.settings)?; + } + if self.has_list_legacy_filenames_script() { + pr.set_message("getting plugin legacy filenames".into()); + self.legacy_filenames(&config.settings)?; + } + + let sha = git.current_sha_short()?; + pr.finish_with_message(format!( + "{repo_url}#{}", + style(&sha).bright().yellow().for_stderr(), + )); + Ok(()) } - fn latest_installed_version(&self) -> Result> { - let installed_symlink = self.installs_path.join("latest"); - if installed_symlink.exists() { - let target = installed_symlink.read_link()?; - let version = target - .file_name() - .ok_or_else(|| eyre!("Invalid symlink target"))? - .to_string_lossy() - .to_string(); - Ok(Some(version)) - } else { - Ok(None) + fn update(&self, gitref: Option) -> Result<()> { + let plugin_path = self.plugin_path.to_path_buf(); + if plugin_path.is_symlink() { + warn!( + "Plugin: {} is a symlink, not updating", + style(&self.name).cyan().for_stderr() + ); + return Ok(()); } + let git = Git::new(plugin_path); + if !git.is_repo() { + warn!( + "Plugin {} is not a git repository, not updating", + style(&self.name).cyan().for_stderr() + ); + return Ok(()); + } + // TODO: asdf_run_hook "pre_plugin_update" + let (_pre, _post) = git.update(gitref)?; + // TODO: asdf_run_hook "post_plugin_update" + Ok(()) } - fn is_installed(&self) -> bool { - self.plugin_path.exists() + fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + if !self.is_installed() { + return Ok(()); + } + pr.set_message("uninstalling".into()); + + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", &dir.to_string_lossy())); + remove_all(dir).wrap_err_with(|| { + format!( + "Failed to remove directory {}", + style(&dir.to_string_lossy()).cyan().for_stderr() + ) + }) + }; + + rmdir(&self.downloads_path)?; + rmdir(&self.installs_path)?; + rmdir(&self.plugin_path)?; + + Ok(()) } fn get_aliases(&self, settings: &Settings) -> Result> { @@ -640,34 +535,19 @@ impl Plugin for ExternalPlugin { exit(result.status.code().unwrap_or(1)); } - fn is_version_installed(&self, tv: &ToolVersion) -> bool { - match tv.request { - ToolVersionRequest::System(_) => true, - _ => self.install_path(tv).exists() && !self.incomplete_file_path(tv).exists(), - } - } - fn install_version( &self, config: &Config, tv: &ToolVersion, pr: &mut ProgressReport, - force: bool, ) -> Result<()> { - self.decorate_progress_bar(pr, Some(tv)); - - let settings = &config.settings; - let _lock = self.get_lock(&self.install_path(tv), force)?; - self.create_install_dirs(tv)?; - let run_script = |script| { self.script_man_for_tv(config, tv).run_by_line( - settings, + &config.settings, script, |output| { - self.cleanup_install_dirs_on_error(settings, tv); pr.error(); - if !settings.verbose && !output.trim().is_empty() { + if !config.settings.verbose && !output.trim().is_empty() { pr.println(output); } }, @@ -690,50 +570,15 @@ impl Plugin for ExternalPlugin { } pr.set_message("installing".into()); run_script(&Install)?; - self.cleanup_install_dirs(settings, tv); - - // attempt to touch all the .tool-version files to trigger updates in hook-env - let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; - touch_dirs.extend(config.config_files.keys().cloned()); - for path in touch_dirs { - let err = file::touch_dir(&path); - if let Err(err) = err { - debug!("error touching config file: {:?} {:?}", path, err); - } - } - if let Err(err) = remove_file(self.incomplete_file_path(tv)) { - debug!("error removing incomplete file: {:?}", err); - } - pr.finish(); Ok(()) } - fn uninstall_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - dryrun: bool, - ) -> Result<()> { - pr.set_message(format!("uninstall {}", self.name())); - + fn uninstall_version(&self, config: &Config, tv: &ToolVersion) -> Result<()> { if self.plugin_path.join("bin/uninstall").exists() { self.script_man_for_tv(config, tv) .run(&config.settings, &Script::Uninstall)?; } - let rmdir = |dir: &Path| { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", display_path(dir))); - if dryrun { - return Ok(()); - } - remove_all_with_warning(dir) - }; - rmdir(&self.install_path(tv))?; - rmdir(&self.download_path(tv))?; Ok(()) } @@ -754,17 +599,6 @@ impl Plugin for ExternalPlugin { self.cache .exec_env(config, self, tv, || self.fetch_exec_env(config, tv)) } - - fn which(&self, config: &Config, tv: &ToolVersion, bin_name: &str) -> Result> { - let bin_paths = self.list_bin_paths(config, tv)?; - for bin_path in bin_paths { - let bin_path = bin_path.join(bin_name); - if bin_path.exists() { - return Ok(Some(bin_path)); - } - } - Ok(None) - } } static EMPTY_HASH_MAP: Lazy> = Lazy::new(HashMap::new); diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 19bf3452d..b16e24ef3 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -1,7 +1,7 @@ use crate::cache::CacheManager; use crate::config::Config; use crate::hash::hash_to_str; -use crate::plugins::{ExternalPlugin, Plugin}; +use crate::plugins::ExternalPlugin; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::{dirs, env}; @@ -29,18 +29,18 @@ impl ExternalPluginCache { { let mut w = self.list_bin_paths.write().unwrap(); let cm = w.entry(tv.request.clone()).or_insert_with(|| { - let list_bin_paths_filename = match &plugin.toml().list_bin_paths.cache_key { + let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key { Some(key) => { let key = render_cache_key(config, tv, key); let filename = format!("{}.msgpack.z", key); - plugin.cache_path(tv).join("list_bin_paths").join(filename) + tv.cache_path().join("list_bin_paths").join(filename) } - None => plugin.cache_path(tv).join("list_bin_paths.msgpack.z"), + None => tv.cache_path().join("list_bin_paths.msgpack.z"), }; CacheManager::new(list_bin_paths_filename) .with_fresh_file(dirs::ROOT.clone()) .with_fresh_file(plugin.plugin_path.clone()) - .with_fresh_file(plugin.install_path(tv)) + .with_fresh_file(tv.install_path()) }); cm.get_or_try_init(fetch).cloned() } @@ -61,14 +61,14 @@ impl ExternalPluginCache { Some(key) => { let key = render_cache_key(config, tv, key); let filename = format!("{}.msgpack.z", key); - plugin.cache_path(tv).join("exec_env").join(filename) + tv.cache_path().join("exec_env").join(filename) } - None => plugin.cache_path(tv).join("exec_env.msgpack.z"), + None => tv.cache_path().join("exec_env.msgpack.z"), }; CacheManager::new(exec_env_filename) .with_fresh_file(dirs::ROOT.clone()) .with_fresh_file(plugin.plugin_path.clone()) - .with_fresh_file(plugin.install_path(tv)) + .with_fresh_file(tv.install_path()) }); cm.get_or_try_init(fetch).cloned() } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 7749c5b57..8f41e5b84 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,22 +1,17 @@ use std::collections::HashMap; use std::fmt::Debug; -use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; -use console::style; use indexmap::IndexMap; -use regex::Regex; pub use external_plugin::ExternalPlugin; +pub use rtx_plugin_toml::RtxPluginToml; pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; -use crate::dirs; -use crate::hash::hash_to_str; -use crate::plugins::rtx_plugin_toml::RtxPluginToml; -use crate::toolset::{ToolVersion, ToolVersionRequest}; -use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; +use crate::toolset::ToolVersion; +use crate::ui::progress_report::ProgressReport; mod external_plugin; mod external_plugin_cache; @@ -25,52 +20,28 @@ mod script_manager; pub type PluginName = String; -pub trait Plugin: Debug + Send + Sync + Eq + PartialEq + Hash { +pub trait Plugin: Debug + Send + Sync { + fn get_type(&self) -> PluginType; fn name(&self) -> &PluginName; - fn toml(&self) -> &RtxPluginToml; fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec>; - fn list_installed_versions(&self) -> Result>; - fn latest_version(&self, settings: &Settings, query: Option) -> Result>; - fn latest_installed_version(&self) -> Result>; + fn latest_stable_version(&self, settings: &Settings) -> Result>; + fn get_remote_url(&self) -> Option { + None + } fn is_installed(&self) -> bool { true } - - fn list_installed_versions_matching(&self, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; - } - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_installed_versions()? - .iter() - .filter(|v| query_regex.is_match(v)) - .cloned() - .collect(); - Ok(versions) + fn install(&self, _config: &Config, _pr: &mut ProgressReport) -> Result<()> { + Ok(()) } - fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; - } - let version_regex = regex!( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" - ); - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_remote_versions(settings)? - .iter() - .filter(|v| !version_regex.is_match(v)) - .filter(|v| query_regex.is_match(v)) - .cloned() - .collect(); - Ok(versions) + fn update(&self, _git_ref: Option) -> Result<()> { + Ok(()) } + fn uninstall(&self, _pr: &ProgressReport) -> Result<()> { + Ok(()) + } + fn get_aliases(&self, _settings: &Settings) -> Result> { Ok(IndexMap::new()) } @@ -87,203 +58,21 @@ pub trait Plugin: Debug + Send + Sync + Eq + PartialEq + Hash { unimplemented!() } - fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { - pr.set_style(PROG_TEMPLATE.clone()); - pr.set_prefix(format!( - "{} {} ", - style("rtx").dim().for_stderr(), - match tv { - Some(tv) => tv.to_string(), - None => self.name().to_string(), - } - )); - pr.enable_steady_tick(); - } - - fn is_version_installed(&self, tv: &ToolVersion) -> bool; fn install_version( &self, config: &Config, tv: &ToolVersion, pr: &mut ProgressReport, - force: bool, - ) -> Result<()>; - fn uninstall_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - dryrun: bool, ) -> Result<()>; + fn uninstall_version(&self, config: &Config, tv: &ToolVersion) -> Result<()>; fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result>; fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result>; - fn which(&self, config: &Config, tv: &ToolVersion, bin_name: &str) -> Result>; - fn install_path(&self, tv: &ToolVersion) -> PathBuf { - let pathname = match &tv.request { - ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), - _ => self.tv_pathname(tv), - }; - dirs::INSTALLS.join(self.name()).join(pathname) - } - fn cache_path(&self, tv: &ToolVersion) -> PathBuf { - dirs::CACHE.join(self.name()).join(self.tv_pathname(tv)) - } - fn download_path(&self, tv: &ToolVersion) -> PathBuf { - dirs::DOWNLOADS.join(self.name()).join(self.tv_pathname(tv)) - } - fn tv_pathname(&self, tv: &ToolVersion) -> String { - match &tv.request { - ToolVersionRequest::Version(_, _) => tv.version.to_string(), - ToolVersionRequest::Prefix(_, _) => tv.version.to_string(), - ToolVersionRequest::Ref(_, r) => format!("ref-{}", r), - ToolVersionRequest::Path(_, p) => format!("path-{}", hash_to_str(p)), - ToolVersionRequest::System(_) => "system".to_string(), - } - } } -#[derive(Debug)] -pub enum Plugins { - External(ExternalPlugin), -} - -impl Eq for Plugins {} - -impl PartialEq for Plugins { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Plugins::External(p1), Plugins::External(p2)) => p1 == p2, - } - } -} -impl Hash for Plugins { - fn hash(&self, state: &mut H) { - match self { - Plugins::External(p) => p.hash(state), - } - } -} - -impl Plugin for Plugins { - fn name(&self) -> &PluginName { - match self { - Plugins::External(p) => p.name(), - } - } - fn toml(&self) -> &RtxPluginToml { - match self { - Plugins::External(p) => p.toml(), - } - } - - fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { - match self { - Plugins::External(p) => p.list_remote_versions(settings), - } - } - - fn list_installed_versions(&self) -> Result> { - match self { - Plugins::External(p) => p.list_installed_versions(), - } - } - fn latest_version(&self, settings: &Settings, query: Option) -> Result> { - match self { - Plugins::External(p) => p.latest_version(settings, query), - } - } - fn latest_installed_version(&self) -> Result> { - match self { - Plugins::External(p) => p.latest_installed_version(), - } - } - fn is_installed(&self) -> bool { - match self { - Plugins::External(p) => p.is_installed(), - } - } - fn list_installed_versions_matching(&self, query: &str) -> Result> { - match self { - Plugins::External(p) => p.list_installed_versions_matching(query), - } - } - fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - match self { - Plugins::External(p) => p.list_versions_matching(settings, query), - } - } - fn get_aliases(&self, settings: &Settings) -> Result> { - match self { - Plugins::External(p) => p.get_aliases(settings), - } - } - fn legacy_filenames(&self, settings: &Settings) -> Result> { - match self { - Plugins::External(p) => p.legacy_filenames(settings), - } - } - fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result { - match self { - Plugins::External(p) => p.parse_legacy_file(path, settings), - } - } - fn external_commands(&self) -> Result>> { - match self { - Plugins::External(p) => p.external_commands(), - } - } - fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { - match self { - Plugins::External(p) => p.execute_external_command(command, args), - } - } - fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { - match self { - Plugins::External(p) => p.decorate_progress_bar(pr, tv), - } - } - fn is_version_installed(&self, tv: &ToolVersion) -> bool { - match self { - Plugins::External(p) => p.is_version_installed(tv), - } - } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &mut ProgressReport, - force: bool, - ) -> Result<()> { - match self { - Plugins::External(p) => p.install_version(config, tv, pr, force), - } - } - fn uninstall_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - dryrun: bool, - ) -> Result<()> { - match self { - Plugins::External(p) => p.uninstall_version(config, tv, pr, dryrun), - } - } - fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { - match self { - Plugins::External(p) => p.list_bin_paths(config, tv), - } - } - fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { - match self { - Plugins::External(p) => p.exec_env(config, tv), - } - } - fn which(&self, config: &Config, tv: &ToolVersion, bin_name: &str) -> Result> { - match self { - Plugins::External(p) => p.which(config, tv, bin_name), - } - } +pub enum PluginType { + #[allow(dead_code)] + Core, + External, } #[cfg(test)] @@ -292,6 +81,7 @@ mod tests { use crate::assert_cli; use crate::config::Settings; + use crate::tool::Tool; use super::*; @@ -300,12 +90,13 @@ mod tests { assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); let plugin = ExternalPlugin::new(&settings, &PluginName::from("tiny")); - let version = plugin + let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); + let version = tool .latest_version(&settings, Some("1.0.0".into())) .unwrap() .unwrap(); assert_str_eq!(version, "1.0.0"); - let version = plugin.latest_version(&settings, None).unwrap().unwrap(); + let version = tool.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "3.1.0"); } @@ -313,7 +104,8 @@ mod tests { fn test_latest_stable() { let settings = Settings::default(); let plugin = ExternalPlugin::new(&settings, &PluginName::from("dummy")); - let version = plugin.latest_version(&settings, None).unwrap().unwrap(); + let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); + let version = tool.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); } } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index e20f8c6e5..c19038f4c 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -1,21 +1,21 @@ use std::path::{Path, PathBuf}; -use crate::config::Config; -use crate::dirs; -use crate::file::make_symlink; use color_eyre::eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use regex::Regex; use versions::Version; -use crate::plugins::{Plugin, Plugins}; +use crate::config::Config; +use crate::dirs; +use crate::file::make_symlink; +use crate::tool::Tool; pub fn rebuild_symlinks(config: &Config) -> Result<()> { - for plugin in config.plugins.values() { + for plugin in config.tools.values() { remove_existing_symlinks(plugin)?; let symlinks = list_symlinks(config, plugin)?; - let installs_dir = dirs::INSTALLS.join(plugin.name()); + let installs_dir = dirs::INSTALLS.join(&plugin.name); for (from, to) in symlinks { let from = installs_dir.join(from); if from.exists() { @@ -27,7 +27,7 @@ pub fn rebuild_symlinks(config: &Config) -> Result<()> { Ok(()) } -fn list_symlinks(config: &Config, plugin: &Plugins) -> Result> { +fn list_symlinks(config: &Config, plugin: &Tool) -> Result> { let mut symlinks = IndexMap::new(); let rel_path = |x: &String| PathBuf::from(".").join(x.clone()); for v in installed_versions(plugin)? { @@ -46,7 +46,7 @@ fn list_symlinks(config: &Config, plugin: &Plugins) -> Result Result Result> { +fn installed_versions(plugin: &Tool) -> Result> { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let versions = plugin .list_installed_versions()? @@ -75,8 +75,8 @@ fn installed_versions(plugin: &Plugins) -> Result> { Ok(versions) } -fn remove_existing_symlinks(plugin: &Plugins) -> Result<()> { - let installs_dir = dirs::INSTALLS.join(plugin.name()); +fn remove_existing_symlinks(plugin: &Tool) -> Result<()> { + let installs_dir = dirs::INSTALLS.join(&plugin.name); if !installs_dir.exists() { return Ok(()); } @@ -110,11 +110,9 @@ mod tests { #[test] fn test_list_symlinks() { let config = Config::load().unwrap(); - let plugin = Plugins::External(ExternalPlugin::new( - &config.settings, - &PluginName::from("tiny"), - )); - let symlinks = list_symlinks(&config, &plugin).unwrap(); + let plugin = ExternalPlugin::new(&config.settings, &PluginName::from("tiny")); + let tool = Tool::new(String::from("tiny"), Box::new(plugin)); + let symlinks = list_symlinks(&config, &tool).unwrap(); assert_debug_snapshot!(symlinks); } } diff --git a/src/shims.rs b/src/shims.rs index 1745dcfeb..394af210f 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -16,7 +16,6 @@ use crate::fake_asdf; use crate::file::{create_dir_all, remove_all}; use crate::lock_file::LockFile; use crate::output::Output; -use crate::plugins::{Plugin, Plugins}; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; @@ -117,21 +116,19 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { })?; } } - for plugin in config.plugins.values() { - match plugin.as_ref() { - Plugins::External(plugin) => match plugin.plugin_path.join("shims").read_dir() { - Ok(files) => { - for bin in files { - let bin = bin?; - let bin_name = bin.file_name().into_string().unwrap(); - let symlink_path = shims_dir.join(bin_name); - make_shim(&bin.path(), &symlink_path)?; - } + for plugin in config.tools.values() { + match plugin.plugin_path.join("shims").read_dir() { + Ok(files) => { + for bin in files { + let bin = bin?; + let bin_name = bin.file_name().into_string().unwrap(); + let symlink_path = shims_dir.join(bin_name); + make_shim(&bin.path(), &symlink_path)?; } - Err(_) => { - continue; - } - }, + } + Err(_) => { + continue; + } } } diff --git a/src/tool.rs b/src/tool.rs new file mode 100644 index 000000000..cea9fe0a6 --- /dev/null +++ b/src/tool.rs @@ -0,0 +1,324 @@ +use std::collections::HashMap; +use std::fs::{remove_file, File}; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::{eyre, Result}; +use console::style; +use indexmap::IndexMap; +use itertools::Itertools; +use regex::Regex; +use versions::Versioning; + +use crate::config::{Config, Settings}; +use crate::file::{create_dir_all, display_path, remove_all_with_warning}; +use crate::lock_file::LockFile; +use crate::plugins::{ExternalPlugin, Plugin, PluginType}; +use crate::runtime_symlinks::is_runtime_symlink; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; +use crate::{dirs, file}; + +#[derive(Debug)] +pub struct Tool { + pub name: String, + pub plugin: Box, + pub installs_path: PathBuf, + pub plugin_path: PathBuf, +} + +impl Tool { + pub fn new(name: String, plugin: Box) -> Self { + Self { + installs_path: dirs::INSTALLS.join(&name), + plugin_path: dirs::PLUGINS.join(&name), + name, + plugin, + } + } + + pub fn list(settings: &Settings) -> Result> { + Ok(file::dir_subdirs(&dirs::PLUGINS)? + .iter() + .map(|name| { + let plugin = ExternalPlugin::new(settings, name); + Self::new(name.to_string(), Box::new(plugin)) + }) + .collect()) + } + + pub fn is_installed(&self) -> bool { + self.plugin.is_installed() + } + + pub fn get_remote_url(&self) -> Option { + self.plugin.get_remote_url() + } + + pub fn list_installed_versions(&self) -> Result> { + Ok(match self.installs_path.exists() { + true => file::dir_subdirs(&self.installs_path)? + .iter() + .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) + .map(|v| Versioning::new(v).unwrap_or_default()) + .sorted() + .map(|v| v.to_string()) + .collect(), + false => vec![], + }) + } + + pub fn list_installed_versions_matching(&self, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9]"; + } + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + let versions = self + .list_installed_versions()? + .iter() + .filter(|v| query_regex.is_match(v)) + .cloned() + .collect(); + Ok(versions) + } + + pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { + self.plugin.list_remote_versions(settings) + } + + pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9]"; + } + let version_regex = regex!( + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" + ); + let query_regex = + Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); + let versions = self + .list_remote_versions(settings)? + .iter() + .filter(|v| !version_regex.is_match(v)) + .filter(|v| query_regex.is_match(v)) + .cloned() + .collect(); + Ok(versions) + } + + pub fn latest_version( + &self, + settings: &Settings, + query: Option, + ) -> Result> { + match query { + Some(query) => { + let matches = self.list_versions_matching(settings, &query)?; + let v = match matches.contains(&query) { + true => Some(query), + false => matches.last().map(|v| v.to_string()), + }; + Ok(v) + } + None => self.latest_stable_version(settings), + } + } + + pub fn latest_installed_version(&self) -> Result> { + let installed_symlink = self.installs_path.join("latest"); + if installed_symlink.exists() { + let target = installed_symlink.read_link()?; + let version = target + .file_name() + .ok_or_else(|| eyre!("Invalid symlink target"))? + .to_string_lossy() + .to_string(); + Ok(Some(version)) + } else { + Ok(None) + } + } + + pub fn get_aliases(&self, settings: &Settings) -> Result> { + self.plugin.get_aliases(settings) + } + + pub fn legacy_filenames(&self, settings: &Settings) -> Result> { + self.plugin.legacy_filenames(settings) + } + + fn latest_stable_version(&self, settings: &Settings) -> Result> { + if let Some(latest) = self.plugin.latest_stable_version(settings)? { + Ok(Some(latest)) + } else { + self.latest_version(settings, Some("latest".into())) + } + } + + pub fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { + pr.set_style(PROG_TEMPLATE.clone()); + pr.set_prefix(format!( + "{} {} ", + style("rtx").dim().for_stderr(), + match tv { + Some(tv) => tv.to_string(), + None => self.name.to_string(), + } + )); + pr.enable_steady_tick(); + } + + pub fn is_version_installed(&self, tv: &ToolVersion) -> bool { + match tv.request { + ToolVersionRequest::System(_) => true, + _ => tv.install_path().exists() && !self.incomplete_file_path(tv).exists(), + } + } + + pub fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &mut ProgressReport, + force: bool, + ) -> Result<()> { + self.decorate_progress_bar(pr, Some(tv)); + let _lock = self.get_lock(&tv.install_path(), force)?; + self.create_install_dirs(tv)?; + + if let Err(e) = self.plugin.install_version(config, tv, pr) { + self.cleanup_install_dirs_on_error(&config.settings, tv); + return Err(e); + } + self.cleanup_install_dirs(&config.settings, tv); + // attempt to touch all the .tool-version files to trigger updates in hook-env + let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; + touch_dirs.extend(config.config_files.keys().cloned()); + for path in touch_dirs { + let err = file::touch_dir(&path); + if let Err(err) = err { + debug!("error touching config file: {:?} {:?}", path, err); + } + } + if let Err(err) = remove_file(self.incomplete_file_path(tv)) { + debug!("error removing incomplete file: {:?}", err); + } + pr.finish(); + + Ok(()) + } + + pub fn uninstall_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + dryrun: bool, + ) -> Result<()> { + pr.set_message(format!("uninstall {tv}")); + + if !dryrun { + self.plugin.uninstall_version(config, tv)?; + } + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", display_path(dir))); + if dryrun { + return Ok(()); + } + remove_all_with_warning(dir) + }; + rmdir(&tv.install_path())?; + rmdir(&tv.download_path())?; + Ok(()) + } + + pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { + if matches!(self.plugin.get_type(), PluginType::Core) { + return Ok(()); + } + self.decorate_progress_bar(pr, None); + let _lock = self.get_lock(&self.plugin_path, force)?; + self.plugin.install(config, pr) + } + pub fn update(&self, git_ref: Option) -> Result<()> { + self.plugin.update(git_ref) + } + pub fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + self.plugin.uninstall(pr) + } + + pub fn external_commands(&self) -> Result>> { + self.plugin.external_commands() + } + pub fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { + self.plugin.execute_external_command(command, args) + } + pub fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result { + self.plugin.parse_legacy_file(path, settings) + } + pub fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + self.plugin.list_bin_paths(config, tv) + } + pub fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + self.plugin.exec_env(config, tv) + } + + pub fn which( + &self, + config: &Config, + tv: &ToolVersion, + bin_name: &str, + ) -> Result> { + let bin_paths = self.plugin.list_bin_paths(config, tv)?; + for bin_path in bin_paths { + let bin_path = bin_path.join(bin_name); + if bin_path.exists() { + return Ok(Some(bin_path)); + } + } + Ok(None) + } + + fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { + tv.cache_path().join("incomplete") + } + + fn create_install_dirs(&self, tv: &ToolVersion) -> Result<()> { + let _ = remove_all_with_warning(tv.install_path()); + let _ = remove_all_with_warning(tv.download_path()); + let _ = remove_all_with_warning(tv.cache_path()); + let _ = remove_file(tv.install_path()); // removes if it is a symlink + create_dir_all(tv.install_path())?; + create_dir_all(tv.download_path())?; + create_dir_all(tv.cache_path())?; + File::create(self.incomplete_file_path(tv))?; + Ok(()) + } + fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { + let _ = remove_all_with_warning(tv.install_path()); + self.cleanup_install_dirs(settings, tv); + } + fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { + if !settings.always_keep_download { + let _ = remove_all_with_warning(tv.download_path()); + } + } + + fn get_lock(&self, path: &Path, force: bool) -> Result> { + let lock = if force { + None + } else { + let lock = LockFile::new(path) + .with_callback(|l| { + debug!("waiting for lock on {}", display_path(l)); + }) + .lock()?; + Some(lock) + }; + Ok(lock) + } +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 6efa25621..03411e0e6 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -21,9 +21,10 @@ pub use tool_version_request::ToolVersionRequest; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; -use crate::plugins::{Plugin, PluginName, Plugins}; +use crate::plugins::PluginName; use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; +use crate::tool::Tool; use crate::ui::multi_progress_report::MultiProgressReport; mod builder; @@ -119,13 +120,13 @@ impl Toolset { pub fn list_missing_plugins(&self, config: &mut Config) -> Vec { for plugin in self.versions.keys() { - config.get_or_create_plugin(plugin); + config.get_or_create_tool(plugin); } self.versions .keys() - .map(|p| config.plugins.get(p).unwrap()) + .map(|p| config.tools.get(p).unwrap()) .filter(|p| !p.is_installed()) - .map(|p| p.name().clone()) + .map(|p| p.name.clone()) .collect() } @@ -152,7 +153,7 @@ impl Toolset { self.versions .iter_mut() .par_bridge() - .filter_map(|(p, v)| match config.plugins.get(&p.to_string()) { + .filter_map(|(p, v)| match config.tools.get(p) { Some(plugin) if plugin.is_installed() => Some((plugin, v)), _ => None, }) @@ -191,16 +192,13 @@ impl Toolset { mpr: &MultiProgressReport, ) -> Result<()> { for plugin in &missing_plugins { - config.get_or_create_plugin(plugin); + config.get_or_create_tool(plugin); } - config.plugins.sort_keys(); + // TODO: do we need this sort? + config.tools.sort_keys(); let missing_plugins = missing_plugins .into_par_iter() - .map(|p| config.plugins.get(&p).unwrap()) - .filter_map(|p| match p.as_ref() { - Plugins::External(p) => Some(p), - //_ => None, - }) + .map(|p| config.tools.get(&p).unwrap()) .filter(|p| !p.is_installed()) .map(|p| { let mut pr = mpr.add(); @@ -217,7 +215,7 @@ impl Toolset { self.versions .iter() .map(|(p, tvl)| { - let p = config.plugins.get(p).unwrap().clone(); + let p = config.tools.get(p).unwrap(); (p, tvl) }) .flat_map(|(p, tvl)| { @@ -231,24 +229,24 @@ impl Toolset { pub fn list_installed_versions( &self, config: &Config, - ) -> Result, ToolVersion)>> { - let current_versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = self + ) -> Result, ToolVersion)>> { + let current_versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = self .list_current_versions(config) .into_iter() - .map(|(p, tv)| ((p.name().clone(), tv.version.clone()), (p, tv))) + .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p.clone(), tv))) .collect(); let versions = config - .plugins + .tools .values() .collect_vec() .into_par_iter() .map(|p| { let versions = p.list_installed_versions()?; Ok(versions.into_iter().map(|v| { - match current_versions.get(&(p.name().clone(), v.clone())) { + match current_versions.get(&(p.name.clone(), v.clone())) { Some((p, tv)) => (p.clone(), tv.clone()), None => { - let tv = ToolVersionRequest::new(p.name().clone(), &v) + let tv = ToolVersionRequest::new(p.name.clone(), &v) .resolve(config, p, Default::default(), false) .unwrap(); (p.clone(), tv) @@ -263,19 +261,16 @@ impl Toolset { Ok(versions) } - pub fn list_versions_by_plugin( - &self, - config: &Config, - ) -> Vec<(Arc, &Vec)> { + pub fn list_versions_by_plugin(&self, config: &Config) -> Vec<(Arc, &Vec)> { self.versions .iter() .map(|(p, v)| { - let p = config.plugins.get(p).unwrap(); + let p = config.tools.get(p).unwrap(); (p.clone(), &v.versions) }) .collect() } - pub fn list_current_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion)> { + pub fn list_current_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion)> { self.list_versions_by_plugin(config) .iter() .flat_map(|(p, v)| v.iter().map(|v| (p.clone(), v.clone()))) @@ -284,7 +279,7 @@ impl Toolset { pub fn list_current_installed_versions( &self, config: &Config, - ) -> Vec<(Arc, ToolVersion)> { + ) -> Vec<(Arc, ToolVersion)> { self.list_current_versions(config) .into_iter() .filter(|(p, v)| p.is_version_installed(v)) @@ -336,7 +331,7 @@ impl Toolset { }) .collect() } - pub fn which(&self, config: &Config, bin_name: &str) -> Option<(Arc, ToolVersion)> { + pub fn which(&self, config: &Config, bin_name: &str) -> Option<(Arc, ToolVersion)> { self.list_current_installed_versions(config) .into_par_iter() .find_first(|(p, tv)| { diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 983677e2b..45984bc53 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -7,8 +7,10 @@ use versions::{Chunk, Version}; use crate::config::Config; use crate::dirs; -use crate::plugins::{Plugin, PluginName, Plugins}; +use crate::hash::hash_to_str; +use crate::plugins::PluginName; use crate::runtime_symlinks::is_runtime_symlink; +use crate::tool::Tool; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; /// represents a single version of a tool for a particular plugin @@ -22,13 +24,13 @@ pub struct ToolVersion { impl ToolVersion { pub fn new( - plugin: &Plugins, + tool: &Tool, request: ToolVersionRequest, opts: ToolVersionOptions, version: String, ) -> Self { ToolVersion { - plugin_name: plugin.name().to_string(), + plugin_name: tool.name.to_string(), version, request, opts, @@ -37,138 +39,159 @@ impl ToolVersion { pub fn resolve( config: &Config, - plugin: &Plugins, + tool: &Tool, request: ToolVersionRequest, opts: ToolVersionOptions, latest_versions: bool, ) -> Result { let tv = match request.clone() { ToolVersionRequest::Version(_, v) => { - Self::resolve_version(config, plugin, request, latest_versions, &v, opts)? + Self::resolve_version(config, tool, request, latest_versions, &v, opts)? } ToolVersionRequest::Prefix(_, prefix) => { - Self::resolve_prefix(config, plugin, request, &prefix, opts)? + Self::resolve_prefix(config, tool, request, &prefix, opts)? } _ => { let version = request.version(); - Self::new(plugin, request, opts, version) + Self::new(tool, request, opts, version) } }; Ok(tv) } + pub fn install_path(&self) -> PathBuf { + let pathname = match &self.request { + ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), + _ => self.tv_pathname(), + }; + dirs::INSTALLS.join(&self.plugin_name).join(pathname) + } + pub fn cache_path(&self) -> PathBuf { + dirs::CACHE.join(&self.plugin_name).join(self.tv_pathname()) + } + pub fn download_path(&self) -> PathBuf { + dirs::DOWNLOADS + .join(&self.plugin_name) + .join(self.tv_pathname()) + } + fn tv_pathname(&self) -> String { + match &self.request { + ToolVersionRequest::Version(_, _) => self.version.to_string(), + ToolVersionRequest::Prefix(_, _) => self.version.to_string(), + ToolVersionRequest::Ref(_, r) => format!("ref-{}", r), + ToolVersionRequest::Path(_, p) => format!("path-{}", hash_to_str(p)), + ToolVersionRequest::System(_) => "system".to_string(), + } + } + fn resolve_version( config: &Config, - plugin: &Plugins, + tool: &Tool, request: ToolVersionRequest, latest_versions: bool, v: &str, opts: ToolVersionOptions, ) -> Result { - let v = config.resolve_alias(plugin.name(), v)?; + let v = config.resolve_alias(&tool.name, v)?; match v.split_once(':') { Some(("ref", r)) => { - return Ok(Self::resolve_ref(plugin, r.to_string(), opts)); + return Ok(Self::resolve_ref(tool, r.to_string(), opts)); } Some(("path", p)) => { - return Self::resolve_path(plugin, PathBuf::from(p), opts); + return Self::resolve_path(tool, PathBuf::from(p), opts); } Some(("prefix", p)) => { - return Self::resolve_prefix(config, plugin, request, p, opts); + return Self::resolve_prefix(config, tool, request, p, opts); } _ => (), } - let build = |v| Ok(Self::new(plugin, request.clone(), opts.clone(), v)); + let build = |v| Ok(Self::new(tool, request.clone(), opts.clone(), v)); - let existing_path = dirs::INSTALLS.join(plugin.name()).join(&v); + let existing_path = dirs::INSTALLS.join(&tool.name).join(&v); if existing_path.exists() && !is_runtime_symlink(&existing_path) { // if the version is already installed, no need to fetch all the remote versions return build(v); } - if !plugin.is_installed() { + if !tool.is_installed() { return build(v); } if v == "latest" { if !latest_versions { - if let Some(v) = plugin.latest_installed_version()? { + if let Some(v) = tool.latest_installed_version()? { return build(v); } } - if let Some(v) = plugin.latest_version(&config.settings, None)? { + if let Some(v) = tool.latest_version(&config.settings, None)? { return build(v); } } if !latest_versions { - let matches = plugin.list_installed_versions_matching(&v)?; + let matches = tool.list_installed_versions_matching(&v)?; if matches.contains(&v) { return build(v); } } - let matches = plugin.list_versions_matching(&config.settings, &v)?; + let matches = tool.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { return build(v); } if v.contains("!-") { - if let Some(tv) = Self::resolve_bang(config, plugin, request.clone(), &v, &opts)? { + if let Some(tv) = Self::resolve_bang(config, tool, request.clone(), &v, &opts)? { return Ok(tv); } } - Self::resolve_prefix(config, plugin, request, &v, opts) + Self::resolve_prefix(config, tool, request, &v, opts) } /// resolve a version like `12.0.0!-1` which becomes `11.0.0`, `12.1.0!-0.1` becomes `12.0.0` fn resolve_bang( config: &Config, - plugin: &Plugins, + tool: &Tool, request: ToolVersionRequest, v: &str, opts: &ToolVersionOptions, ) -> Result> { let (wanted, minus) = v.split_once("!-").unwrap(); let wanted = match wanted { - "latest" => plugin.latest_version(&config.settings, None)?.unwrap(), - _ => config.resolve_alias(plugin.name(), wanted)?, + "latest" => tool.latest_version(&config.settings, None)?.unwrap(), + _ => config.resolve_alias(&tool.name, wanted)?, }; let wanted = version_sub(&wanted, minus); - let tv = plugin + let tv = tool .latest_version(&config.settings, Some(wanted))? - .map(|v| Self::new(plugin, request, opts.clone(), v)); + .map(|v| Self::new(tool, request, opts.clone(), v)); Ok(tv) } fn resolve_prefix( config: &Config, - plugin: &Plugins, + tool: &Tool, request: ToolVersionRequest, prefix: &str, opts: ToolVersionOptions, ) -> Result { - let matches = plugin.list_versions_matching(&config.settings, prefix)?; + let matches = tool.list_versions_matching(&config.settings, prefix)?; let v = match matches.last() { Some(v) => v, None => prefix, // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?, }; - Ok(Self::new(plugin, request, opts, v.to_string())) + Ok(Self::new(tool, request, opts, v.to_string())) } - fn resolve_ref(plugin: &Plugins, r: String, opts: ToolVersionOptions) -> Self { - let request = ToolVersionRequest::Ref(plugin.name().clone(), r); + fn resolve_ref(tool: &Tool, r: String, opts: ToolVersionOptions) -> Self { + let request = ToolVersionRequest::Ref(tool.name.clone(), r); let version = request.version(); - Self::new(plugin, request, opts, version) + Self::new(tool, request, opts, version) } - fn resolve_path( - plugin: &Plugins, - path: PathBuf, - opts: ToolVersionOptions, - ) -> Result { + fn resolve_path(tool: &Tool, path: PathBuf, opts: ToolVersionOptions) -> Result { let path = fs::canonicalize(path)?; - let request = ToolVersionRequest::Path(plugin.name().clone(), path); + let request = ToolVersionRequest::Path(tool.name.clone(), path); let version = request.version(); - Ok(Self::new(plugin, request, opts, version)) + Ok(Self::new(tool, request, opts, version)) } } diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index f93ea1805..3bb427f2c 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -22,7 +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) { + let plugin = match config.tools.get(&self.plugin_name) { Some(p) => p, _ => { debug!("Plugin {} is not installed", self.plugin_name); @@ -44,17 +44,19 @@ mod tests { use std::sync::Arc; use super::*; - use crate::plugins::{ExternalPlugin, Plugin, Plugins}; + use crate::plugins::ExternalPlugin; + use crate::tool::Tool; #[test] fn test_tool_version_list() { let mut config = Config::default(); - let plugin = ExternalPlugin::new(&config.settings, &"tiny".to_string()); - let plugin = Arc::new(Plugins::External(plugin)); - config.plugins.insert(plugin.name().clone(), plugin.clone()); - let mut tvl = ToolVersionList::new(plugin.name().clone(), ToolSource::Argument); + let plugin_name = "tiny".to_string(); + let plugin = ExternalPlugin::new(&config.settings, &plugin_name); + let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); + config.tools.insert(plugin_name.clone(), Arc::new(tool)); + let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); tvl.requests.push(( - ToolVersionRequest::new(plugin.name().clone(), "latest"), + ToolVersionRequest::new(plugin_name, "latest"), ToolVersionOptions::default(), )); tvl.resolve(&config, true); diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 8f199e973..f5a38831f 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -4,7 +4,8 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use crate::config::Config; -use crate::plugins::{PluginName, Plugins}; +use crate::plugins::PluginName; +use crate::tool::Tool; use crate::toolset::{ToolVersion, ToolVersionOptions}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -60,7 +61,7 @@ impl ToolVersionRequest { pub fn resolve( &self, config: &Config, - plugin: &Plugins, + plugin: &Tool, opts: ToolVersionOptions, latest_versions: bool, ) -> Result { From c2d8efd0d5ae6ae28b7ac6bcdd345dc3d43f8e8e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Apr 2023 23:51:37 -0500 Subject: [PATCH 0659/1891] refactor: autosort plugins with btreemap (#454) --- src/config/mod.rs | 24 ++++++++++++------------ src/plugins/external_plugin.rs | 3 --- src/plugins/mod.rs | 24 +++++++++++++++--------- src/toolset/mod.rs | 2 -- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 12163493c..8e058caf3 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::Arc; @@ -36,7 +36,7 @@ pub struct Config { pub global_config: RtxToml, pub legacy_files: IndexMap, pub config_files: ConfigMap, - pub tools: IndexMap>, + pub tools: BTreeMap>, pub env: IndexMap, pub path_dirs: Vec, pub aliases: AliasMap, @@ -52,7 +52,7 @@ impl Config { let global_config = load_rtxrc()?; let mut settings = global_config.settings(); let config_filenames = load_config_filenames(&IndexMap::new()); - let tools = load_plugins(&settings.build())?; + let tools = load_tools(&settings.build())?; let config_files = load_all_config_files( &settings.build(), &config_filenames, @@ -217,7 +217,7 @@ impl Config { } } - pub fn get_tracked_config_files(&self) -> Result>> { + pub fn get_tracked_config_files(&self) -> Result { let tracker = Tracker::new(); let config_files = tracker .list_all()? @@ -312,7 +312,7 @@ fn load_rtxrc() -> Result { } } -fn load_plugins(settings: &Settings) -> Result>> { +fn load_tools(settings: &Settings) -> Result>> { let plugins = Tool::list(settings)? .into_par_iter() .map(|p| (p.name.clone(), Arc::new(p))) @@ -325,7 +325,7 @@ fn load_plugins(settings: &Settings) -> Result>> fn load_legacy_files( settings: &Settings, - tools: &IndexMap>, + tools: &BTreeMap>, ) -> IndexMap { if !settings.legacy_version_file { return IndexMap::new(); @@ -390,9 +390,9 @@ fn get_global_rtx_toml() -> PathBuf { fn load_all_config_files( settings: &Settings, config_filenames: &[PathBuf], - tools: &IndexMap>, + tools: &BTreeMap>, legacy_filenames: &IndexMap, - mut existing: IndexMap>, + mut existing: ConfigMap, ) -> Result { Ok(config_filenames .iter() @@ -420,7 +420,7 @@ fn parse_config_file( f: &PathBuf, settings: &Settings, legacy_filenames: &IndexMap, - tools: &IndexMap>, + tools: &BTreeMap>, ) -> Result> { let is_trusted = config_file::is_trusted(settings, f); match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { @@ -430,7 +430,7 @@ fn parse_config_file( } } -fn load_env(config_files: &IndexMap>) -> IndexMap { +fn load_env(config_files: &ConfigMap) -> IndexMap { let mut env = IndexMap::new(); for cf in config_files.values().rev() { env.extend(cf.env()); @@ -438,7 +438,7 @@ fn load_env(config_files: &IndexMap>) -> IndexMap>) -> Vec { +fn load_path_dirs(config_files: &ConfigMap) -> Vec { let mut path_dirs = vec![]; for cf in config_files.values().rev() { path_dirs.extend(cf.path_dirs()); @@ -446,7 +446,7 @@ fn load_path_dirs(config_files: &IndexMap>) -> Vec< path_dirs } -fn load_aliases(config_files: &IndexMap>) -> AliasMap { +fn load_aliases(config_files: &ConfigMap) -> AliasMap { let mut aliases: AliasMap = IndexMap::new(); for config_file in config_files.values() { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ea2946ea5..00f903a32 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -306,9 +306,6 @@ impl Plugin for ExternalPlugin { fn get_type(&self) -> PluginType { PluginType::External } - fn name(&self) -> &PluginName { - &self.name - } fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 8f41e5b84..f2507c521 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -21,14 +21,16 @@ mod script_manager; pub type PluginName = String; pub trait Plugin: Debug + Send + Sync { - fn get_type(&self) -> PluginType; - fn name(&self) -> &PluginName; + fn get_type(&self) -> PluginType { + PluginType::Core + } fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec>; - fn latest_stable_version(&self, settings: &Settings) -> Result>; + fn latest_stable_version(&self, _settings: &Settings) -> Result> { + Ok(None) + } fn get_remote_url(&self) -> Option { None } - fn is_installed(&self) -> bool { true } @@ -41,7 +43,6 @@ pub trait Plugin: Debug + Send + Sync { fn uninstall(&self, _pr: &ProgressReport) -> Result<()> { Ok(()) } - fn get_aliases(&self, _settings: &Settings) -> Result> { Ok(IndexMap::new()) } @@ -57,16 +58,21 @@ pub trait Plugin: Debug + Send + Sync { fn execute_external_command(&self, _command: &str, _args: Vec) -> Result<()> { unimplemented!() } - fn install_version( &self, config: &Config, tv: &ToolVersion, pr: &mut ProgressReport, ) -> Result<()>; - fn uninstall_version(&self, config: &Config, tv: &ToolVersion) -> Result<()>; - fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result>; - fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result>; + fn uninstall_version(&self, _config: &Config, _tv: &ToolVersion) -> Result<()> { + Ok(()) + } + fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { + Ok(vec![tv.install_path().join("bin")]) + } + fn exec_env(&self, _config: &Config, _tv: &ToolVersion) -> Result> { + Ok(HashMap::new()) + } } pub enum PluginType { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 03411e0e6..34ec1d675 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -194,8 +194,6 @@ impl Toolset { for plugin in &missing_plugins { config.get_or_create_tool(plugin); } - // TODO: do we need this sort? - config.tools.sort_keys(); let missing_plugins = missing_plugins .into_par_iter() .map(|p| config.tools.get(&p).unwrap()) From 0b62cc1b0b2d003ee0b11c050a41f09dcf3ab16a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 00:30:43 -0500 Subject: [PATCH 0660/1891] refactor: autosort more things (#456) --- ...tx__cli__alias__set__tests__alias_set.snap | 2 +- src/cli/exec.rs | 6 +-- src/cli/prune.rs | 4 +- src/config/mod.rs | 51 +++++++++---------- src/hook_env.rs | 30 +++++------ src/plugins/external_plugin.rs | 7 ++- src/plugins/mod.rs | 7 ++- src/runtime_symlinks.rs | 5 +- src/tool.rs | 5 +- src/toolset/builder.rs | 4 +- src/toolset/mod.rs | 11 ++-- 11 files changed, 62 insertions(+), 70 deletions(-) diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 0963f8bce..7d92b9591 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -2,7 +2,7 @@ source: src/cli/alias/set.rs expression: output --- -tiny my/alias 3.0 tiny lts 3.1.0 tiny lts-prev 2.0.0 +tiny my/alias 3.0 diff --git a/src/cli/exec.rs b/src/cli/exec.rs index f32677998..28a60eff7 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -1,10 +1,10 @@ +use std::collections::BTreeMap; use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use clap::ValueHint; use color_eyre::eyre::{eyre, Result}; use duct::IntoExecutablePath; -use indexmap::IndexMap; use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; @@ -67,7 +67,7 @@ impl Command for Exec { impl Exec { #[cfg(not(test))] - fn exec(&self, program: T, args: U, env: IndexMap) -> Result<()> + fn exec(&self, program: T, args: U, env: BTreeMap) -> Result<()> where T: IntoExecutablePath, U: IntoIterator, @@ -87,7 +87,7 @@ impl Exec { } #[cfg(test)] - fn exec(&self, program: T, args: U, env: IndexMap) -> Result<()> + fn exec(&self, program: T, args: U, env: BTreeMap) -> Result<()> where T: IntoExecutablePath, U: IntoIterator, diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 27ac1cb98..152abd928 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Result; use console::style; -use indexmap::IndexMap; +use std::collections::BTreeMap; use std::sync::Arc; use crate::cli::command::Command; @@ -36,7 +36,7 @@ impl Command for Prune { .list_installed_versions(&config)? .into_iter() .map(|(p, tv)| (tv.to_string(), (p, tv))) - .collect::, ToolVersion)>>(); + .collect::, ToolVersion)>>(); if let Some(plugins) = &self.plugins { to_delete.retain(|_, (_, tv)| plugins.contains(&tv.plugin_name)); diff --git a/src/config/mod.rs b/src/config/mod.rs index 8e058caf3..3f1c6077c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -27,17 +27,18 @@ pub mod config_file; mod settings; mod tracking; -type AliasMap = IndexMap>; +type AliasMap = BTreeMap>; type ConfigMap = IndexMap>; +type ToolMap = BTreeMap>; #[derive(Debug, Default)] pub struct Config { pub settings: Settings, pub global_config: RtxToml, - pub legacy_files: IndexMap, + pub legacy_files: BTreeMap, pub config_files: ConfigMap, - pub tools: BTreeMap>, - pub env: IndexMap, + pub tools: ToolMap, + pub env: BTreeMap, pub path_dirs: Vec, pub aliases: AliasMap, pub all_aliases: OnceCell, @@ -51,14 +52,14 @@ impl Config { pub fn load() -> Result { let global_config = load_rtxrc()?; let mut settings = global_config.settings(); - let config_filenames = load_config_filenames(&IndexMap::new()); + let config_filenames = load_config_filenames(&BTreeMap::new()); let tools = load_tools(&settings.build())?; let config_files = load_all_config_files( &settings.build(), &config_filenames, &tools, - &IndexMap::new(), - IndexMap::new(), + &BTreeMap::new(), + ConfigMap::new(), )?; for cf in config_files.values() { settings.merge(cf.settings()); @@ -178,7 +179,7 @@ impl Config { Ok(aliases) => aliases, Err(err) => { eprintln!("Error: {err}"); - IndexMap::new() + BTreeMap::new() } }; (plugin.name.clone(), aliases) @@ -188,7 +189,7 @@ impl Config { for (from, to) in plugin_aliases { aliases .entry(plugin.to_string()) - .or_insert_with(IndexMap::new) + .or_insert_with(BTreeMap::new) .insert(from, to); } } @@ -197,7 +198,7 @@ impl Config { for (from, to) in plugin_aliases { aliases .entry(plugin.clone()) - .or_insert_with(IndexMap::new) + .or_insert_with(BTreeMap::new) .insert(from.clone(), to.clone()); } } @@ -312,23 +313,17 @@ fn load_rtxrc() -> Result { } } -fn load_tools(settings: &Settings) -> Result>> { +fn load_tools(settings: &Settings) -> Result { let plugins = Tool::list(settings)? .into_par_iter() .map(|p| (p.name.clone(), Arc::new(p))) - .collect::>() - .into_iter() - .sorted_by_cached_key(|(p, _)| p.to_string()) .collect(); Ok(plugins) } -fn load_legacy_files( - settings: &Settings, - tools: &BTreeMap>, -) -> IndexMap { +fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap { if !settings.legacy_version_file { - return IndexMap::new(); + return BTreeMap::new(); } tools .values() @@ -352,7 +347,7 @@ fn load_legacy_files( .collect() } -fn load_config_filenames(legacy_filenames: &IndexMap) -> Vec { +fn load_config_filenames(legacy_filenames: &BTreeMap) -> Vec { let mut filenames = vec![ env::RTX_DEFAULT_CONFIG_FILENAME.as_str(), env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str(), @@ -390,8 +385,8 @@ fn get_global_rtx_toml() -> PathBuf { fn load_all_config_files( settings: &Settings, config_filenames: &[PathBuf], - tools: &BTreeMap>, - legacy_filenames: &IndexMap, + tools: &ToolMap, + legacy_filenames: &BTreeMap, mut existing: ConfigMap, ) -> Result { Ok(config_filenames @@ -419,8 +414,8 @@ fn load_all_config_files( fn parse_config_file( f: &PathBuf, settings: &Settings, - legacy_filenames: &IndexMap, - tools: &BTreeMap>, + legacy_filenames: &BTreeMap, + tools: &ToolMap, ) -> Result> { let is_trusted = config_file::is_trusted(settings, f); match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { @@ -430,8 +425,8 @@ fn parse_config_file( } } -fn load_env(config_files: &ConfigMap) -> IndexMap { - let mut env = IndexMap::new(); +fn load_env(config_files: &ConfigMap) -> BTreeMap { + let mut env = BTreeMap::new(); for cf in config_files.values().rev() { env.extend(cf.env()); } @@ -447,14 +442,14 @@ fn load_path_dirs(config_files: &ConfigMap) -> Vec { } fn load_aliases(config_files: &ConfigMap) -> AliasMap { - let mut aliases: AliasMap = IndexMap::new(); + let mut aliases: AliasMap = AliasMap::new(); for config_file in config_files.values() { for (plugin, plugin_aliases) in config_file.aliases() { for (from, to) in plugin_aliases { aliases .entry(plugin.clone()) - .or_insert_with(IndexMap::new) + .or_insert_with(BTreeMap::new) .insert(from, to); } } diff --git a/src/hook_env.rs b/src/hook_env.rs index a6cdf09da..ccc361128 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -1,3 +1,4 @@ +use std::collections::{BTreeMap, BTreeSet}; use std::io::prelude::*; use std::ops::Deref; use std::path::PathBuf; @@ -8,7 +9,6 @@ use color_eyre::eyre::Result; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; -use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; @@ -52,10 +52,10 @@ pub fn should_exit_early(watch_files: &[PathBuf]) -> bool { fn have_config_files_been_modified( watches: &HookEnvWatches, - watch_files: IndexSet, + watch_files: BTreeSet, ) -> bool { // make sure they have exactly the same config filenames - let watch_keys = watches.files.keys().cloned().collect::>(); + let watch_keys = watches.files.keys().cloned().collect::>(); if watch_keys != watch_files { trace!( "config files do not match {:?}", @@ -90,7 +90,7 @@ fn have_rtx_env_vars_been_modified(watches: &HookEnvWatches) -> bool { #[derive(Debug, Serialize, Deserialize)] pub struct HookEnvWatches { - files: IndexMap, + files: BTreeMap, env_var_hash: String, } @@ -110,7 +110,7 @@ pub fn deserialize_watches(raw: String) -> Result { } pub fn build_watches(watch_files: &[PathBuf]) -> Result { - let mut watches = IndexMap::new(); + let mut watches = BTreeMap::new(); for cf in get_watch_files(watch_files) { watches.insert(cf.clone(), cf.metadata()?.modified()?); } @@ -121,8 +121,8 @@ pub fn build_watches(watch_files: &[PathBuf]) -> Result { }) } -pub fn get_watch_files(watch_files: &[PathBuf]) -> IndexSet { - let mut watches = IndexSet::new(); +pub fn get_watch_files(watch_files: &[PathBuf]) -> BTreeSet { + let mut watches = BTreeSet::new(); if dirs::ROOT.exists() { watches.insert(dirs::ROOT.clone()); } @@ -181,34 +181,34 @@ mod tests { #[test] fn test_have_config_files_been_modified() { - let files = IndexSet::new(); + let files = BTreeSet::new(); let watches = HookEnvWatches { - files: IndexMap::new(), + files: BTreeMap::new(), env_var_hash: "".into(), }; assert!(!have_config_files_been_modified(&watches, files)); let fp = dirs::CURRENT.join(".test-tool-versions"); let watches = HookEnvWatches { - files: IndexMap::from([(fp.clone(), UNIX_EPOCH)]), + files: BTreeMap::from([(fp.clone(), UNIX_EPOCH)]), env_var_hash: "".into(), }; - let files = IndexSet::from([fp.clone()]); + let files = BTreeSet::from([fp.clone()]); assert!(have_config_files_been_modified(&watches, files)); let modtime = fp.metadata().unwrap().modified().unwrap(); let watches = HookEnvWatches { - files: IndexMap::from([(fp.clone(), modtime)]), + files: BTreeMap::from([(fp.clone(), modtime)]), env_var_hash: "".into(), }; - let files = IndexSet::from([fp]); + let files = BTreeSet::from([fp]); assert!(!have_config_files_been_modified(&watches, files)); } #[test] fn test_serialize_watches_empty() { let watches = HookEnvWatches { - files: IndexMap::new(), + files: BTreeMap::new(), env_var_hash: "".into(), }; let serialized = serialize_watches(&watches).unwrap(); @@ -219,7 +219,7 @@ mod tests { #[test] fn test_serialize_watches() { let serialized = serialize_watches(&HookEnvWatches { - files: IndexMap::from([("foo".into(), UNIX_EPOCH)]), + files: BTreeMap::from([("foo".into(), UNIX_EPOCH)]), env_var_hash: "testing-123".into(), }) .unwrap(); diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 00f903a32..39d270472 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::fs; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; @@ -7,7 +7,6 @@ use std::time::Duration; use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; -use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::Lazy; @@ -434,12 +433,12 @@ impl Plugin for ExternalPlugin { Ok(()) } - fn get_aliases(&self, settings: &Settings) -> Result> { + fn get_aliases(&self, settings: &Settings) -> Result> { if let Some(data) = &self.toml.list_aliases.data { return Ok(self.parse_aliases(data).into_iter().collect()); } if !self.has_list_alias_script() { - return Ok(IndexMap::new()); + return Ok(BTreeMap::new()); } let aliases = self .alias_cache diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index f2507c521..45285363a 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,9 +1,8 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; -use indexmap::IndexMap; pub use external_plugin::ExternalPlugin; pub use rtx_plugin_toml::RtxPluginToml; @@ -43,8 +42,8 @@ pub trait Plugin: Debug + Send + Sync { fn uninstall(&self, _pr: &ProgressReport) -> Result<()> { Ok(()) } - fn get_aliases(&self, _settings: &Settings) -> Result> { - Ok(IndexMap::new()) + fn get_aliases(&self, _settings: &Settings) -> Result> { + Ok(BTreeMap::new()) } fn legacy_filenames(&self, _settings: &Settings) -> Result> { Ok(vec![]) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index c19038f4c..620ea8638 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -47,7 +48,7 @@ fn list_symlinks(config: &Config, plugin: &Tool) -> Result Result Result> { + pub fn get_aliases(&self, settings: &Settings) -> Result> { self.plugin.get_aliases(settings) } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 4a675b85c..b219730f6 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Result; -use indexmap::IndexMap; use itertools::Itertools; +use std::collections::BTreeMap; use crate::cli::args::runtime::RuntimeArg; use crate::config::Config; @@ -61,7 +61,7 @@ fn load_config_files(config: &Config, ts: &mut Toolset) { } } -fn load_runtime_env(ts: &mut Toolset, env: IndexMap) { +fn load_runtime_env(ts: &mut Toolset, env: BTreeMap) { for (k, v) in env { if k.starts_with("RTX_") && k.ends_with("_VERSION") { let plugin_name = k[4..k.len() - 8].to_lowercase(); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 34ec1d675..5523c2f84 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::path::PathBuf; @@ -33,7 +33,7 @@ mod tool_version; mod tool_version_list; mod tool_version_request; -pub type ToolVersionOptions = IndexMap; +pub type ToolVersionOptions = BTreeMap; /// a toolset is a collection of tools for various plugins /// @@ -283,14 +283,14 @@ impl Toolset { .filter(|(p, v)| p.is_version_installed(v)) .collect() } - pub fn env_with_path(&self, config: &Config) -> IndexMap { + pub fn env_with_path(&self, config: &Config) -> BTreeMap { let mut env = self.env(config); let path_env = self.path_env(config); env.insert("PATH".to_string(), path_env); env } - pub fn env(&self, config: &Config) -> IndexMap { - let mut entries: IndexMap = self + pub fn env(&self, config: &Config) -> BTreeMap { + let mut entries: BTreeMap = self .list_current_installed_versions(config) .into_par_iter() .flat_map(|(p, tv)| match p.exec_env(config, &tv) { @@ -306,7 +306,6 @@ impl Toolset { .filter(|(k, _)| !k.starts_with("RTX_TOOL_OPTS__")) .rev() .collect(); - entries.sort_keys(); entries.extend(config.env.clone()); entries } From 3d7da4e44cb0498999216b60688d064d3d51c9c8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 06:40:43 -0500 Subject: [PATCH 0661/1891] added python core plugin (#455) --- .github/workflows/rtx.yml | 4 +- README.md | 6 +- completions/_rtx | 8 ++ completions/rtx.bash | 4 +- completions/rtx.fish | 4 + src/cli/doctor.rs | 2 +- src/cli/ls_remote.rs | 2 +- src/cli/plugins/ls.rs | 20 ++++- src/cli/plugins/mod.rs | 8 +- src/cmd.rs | 129 +++++++++++++++++++++++++++++++++ src/config/mod.rs | 39 ++++++++-- src/env.rs | 1 + src/plugins/core/mod.rs | 3 + src/plugins/core/python.rs | 105 +++++++++++++++++++++++++++ src/plugins/external_plugin.rs | 3 +- src/plugins/mod.rs | 3 +- src/plugins/script_manager.rs | 105 +++------------------------ src/tool.rs | 5 +- 18 files changed, 334 insertions(+), 117 deletions(-) create mode 100644 src/plugins/core/mod.rs create mode 100644 src/plugins/core/python.rs diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 02bffb363..fa6ca1b84 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -30,6 +30,7 @@ jobs: run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" + RTX_EXPERIMENTAL_CORE_PLUGINS: "1" - uses: taiki-e/install-action@just - run: just lint - uses: taiki-e/install-action@cargo-deny @@ -55,8 +56,9 @@ jobs: uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RTX_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} RUST_BACKTRACE: "1" + RTX_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + RTX_EXPERIMENTAL_CORE_PLUGINS: "1" with: timeout_minutes: 20 max_attempts: 3 diff --git a/README.md b/README.md index 1cafd019a..d18928949 100644 --- a/README.md +++ b/README.md @@ -1990,9 +1990,9 @@ Can also show remotely available plugins to install. Usage: ls [OPTIONS] Options: - -a, --all - List all available remote plugins - Same as `rtx plugins ls-remote` + -c, --core + The built-in plugins only + Normally these are not shown -u, --urls Show the git url for each plugin diff --git a/completions/_rtx b/completions/_rtx index f3d5ce31e..c30dbd630 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -818,6 +818,10 @@ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ +'-c[The built-in plugins only +Normally these are not shown]' \ +'--core[The built-in plugins only +Normally these are not shown]' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ '--debug[Sets log level to debug]' \ @@ -911,6 +915,10 @@ default: 4]: : ' \ Same as `rtx plugins ls-remote`]' \ '--all[List all available remote plugins Same as `rtx plugins ls-remote`]' \ +'-c[The built-in plugins only +Normally these are not shown]' \ +'--core[The built-in plugins only +Normally these are not shown]' \ '-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ '--urls[Show the git url for each plugin diff --git a/completions/rtx.bash b/completions/rtx.bash index 420db6eeb..7f61d8e9b 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2252,7 +2252,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -u -j -r -v -h --all --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help install link ls ls-remote uninstall update help" + opts="-a -c -u -j -r -v -h --all --core --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2442,7 +2442,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -u -j -r -v -h --all --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-a -c -u -j -r -v -h --all --core --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index fd32ee450..92c30ba29 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -391,6 +391,8 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s c -l core -d 'The built-in plugins only +Normally these are not shown' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' @@ -436,6 +438,8 @@ default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins Same as `rtx plugins ls-remote`' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s c -l core -d 'The built-in plugins only +Normally these are not shown' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index c31d57b35..ae6dab911 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -128,7 +128,7 @@ fn render_plugins(config: &Config) -> String { None => format!(" {padded_name}\n"), } } - PluginType::Core => format!(" {padded_name}\n"), + PluginType::Core => format!(" {padded_name} (core)\n"), }; s.push_str(&si); } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index fdb0a5fc8..4f740d592 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -37,7 +37,7 @@ impl Command for LsRemote { _ => self.prefix.as_ref(), }; - let versions = plugin.list_remote_versions(&config.settings)?.clone(); + let versions = plugin.list_remote_versions(&config.settings)?; let versions = match prefix { Some(prefix) => versions .into_iter() diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 779ab46bd..ea5b5b808 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -4,6 +4,7 @@ use crate::cli::command::Command; use crate::cli::plugins::ls_remote::PluginsLsRemote; use crate::config::Config; use crate::output::Output; +use crate::plugins::PluginType; /// List installed plugins /// @@ -13,9 +14,14 @@ use crate::output::Output; pub struct PluginsLs { /// List all available remote plugins /// Same as `rtx plugins ls-remote` - #[clap(short, long, verbatim_doc_comment)] + #[clap(short, long, hide = true, verbatim_doc_comment)] pub all: bool, + /// The built-in plugins only + /// Normally these are not shown + #[clap(short, long, verbatim_doc_comment)] + pub core: bool, + /// Show the git url for each plugin /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long, verbatim_doc_comment)] @@ -32,8 +38,16 @@ impl Command for PluginsLs { .run(config, out); } + let mut plugins = config.tools.values().collect::>(); + + if self.core { + plugins.retain(|p| matches!(p.plugin.get_type(), PluginType::Core)); + } else { + plugins.retain(|p| matches!(p.plugin.get_type(), PluginType::External)); + } + if self.urls { - for plugin in config.tools.values() { + for plugin in plugins { if let Some(url) = plugin.get_remote_url() { rtxprintln!(out, "{:29} {}", plugin.name, url); continue; @@ -41,7 +55,7 @@ impl Command for PluginsLs { rtxprintln!(out, "{}", plugin.name); } } else { - for plugin in config.tools.values() { + for plugin in plugins { rtxprintln!(out, "{}", plugin.name); } } diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 534db61a1..f769c02ac 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -21,9 +21,14 @@ pub struct Plugins { /// list all available remote plugins /// /// same as `rtx plugins ls-remote` - #[clap(short, long)] + #[clap(short, long, hide = true)] pub all: bool, + /// The built-in plugins only + /// Normally these are not shown + #[clap(short, long, verbatim_doc_comment)] + pub core: bool, + /// show the git url for each plugin /// /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git @@ -58,6 +63,7 @@ impl Command for Plugins { fn run(self, config: Config, out: &mut Output) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::PluginsLs { all: self.all, + core: self.core, urls: self.urls, })); diff --git a/src/cmd.rs b/src/cmd.rs index f1de7b487..cad2ba743 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -1,5 +1,13 @@ +use color_eyre::Result; use std::ffi::OsString; +use std::io::{BufRead, BufReader}; +use std::process::{Command, ExitStatus, Stdio}; +use std::sync::mpsc::channel; +use std::thread; +use crate::config::Settings; +use crate::errors::Error::ScriptFailed; +use crate::ui::progress_report::ProgressReport; use duct::{Expression, IntoExecutablePath}; /// Create a command with any number of of positional arguments, which may be @@ -74,6 +82,127 @@ where duct::cmd(program, args) } +pub fn run_by_line_to_pr(settings: &Settings, cmd: Command, pr: &mut ProgressReport) -> Result<()> { + run_by_line( + settings, + cmd, + |output| { + pr.error(); + if !settings.verbose && !output.trim().is_empty() { + pr.println(output); + } + }, + |line| { + if !line.trim().is_empty() { + pr.set_message(line.into()); + } + }, + |line| { + if !line.trim().is_empty() { + pr.println(line.into()); + } + }, + ) +} + +pub fn run_by_line<'a, F1, F2, F3>( + settings: &Settings, + mut cmd: Command, + on_error: F1, + on_stdout: F2, + on_stderr: F3, +) -> Result<()> +where + F1: Fn(String), + F2: Fn(&str) + Send + Sync + 'a, + F3: Fn(&str) + Send + Sync, +{ + let program = cmd.get_program().to_string_lossy().to_string(); + if settings.raw { + let status = cmd.spawn()?.wait()?; + match status.success() { + true => Ok(()), + false => { + on_error(String::new()); + Err(ScriptFailed(program, Some(status)).into()) + } + } + } else { + let mut cp = cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + let stdout = BufReader::new(cp.stdout.take().unwrap()); + let stderr = BufReader::new(cp.stderr.take().unwrap()); + let (tx, rx) = channel(); + thread::spawn({ + let tx = tx.clone(); + move || { + for line in stdout.lines() { + let line = line.unwrap(); + tx.send(ChildProcessOutput::Stdout(line)).unwrap(); + } + tx.send(ChildProcessOutput::Done).unwrap(); + } + }); + thread::spawn({ + let tx = tx.clone(); + move || { + for line in stderr.lines() { + let line = line.unwrap(); + tx.send(ChildProcessOutput::Stderr(line)).unwrap(); + } + tx.send(ChildProcessOutput::Done).unwrap(); + } + }); + thread::spawn(move || { + let status = cp.wait().unwrap(); + tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); + tx.send(ChildProcessOutput::Done).unwrap(); + }); + let mut combined_output = vec![]; + let mut wait_for_count = 3; + let mut status = None; + for line in rx { + match line { + ChildProcessOutput::Stdout(line) => { + on_stdout(&line); + combined_output.push(line); + } + ChildProcessOutput::Stderr(line) => { + on_stderr(&line); + combined_output.push(line); + } + ChildProcessOutput::ExitStatus(s) => { + status = Some(s); + } + ChildProcessOutput::Done => { + wait_for_count -= 1; + if wait_for_count == 0 { + break; + } + } + } + } + let status = status.unwrap(); + + if !status.success() { + on_error(combined_output.join("\n")); + Err(ScriptFailed(program, Some(status)))?; + } + + Ok(()) + } +} + +enum ChildProcessOutput { + Stdout(String), + Stderr(String), + ExitStatus(ExitStatus), + Done, +} + #[cfg(test)] mod tests { use crate::cmd; diff --git a/src/config/mod.rs b/src/config/mod.rs index 3f1c6077c..6381f4c65 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,8 +17,9 @@ use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; -use crate::env::CI; -use crate::plugins::{ExternalPlugin, PluginName, PluginType}; +use crate::env::{CI, RTX_EXPERIMENTAL_CORE_PLUGINS}; +use crate::plugins::core::PythonPlugin; +use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::tool::Tool; use crate::{cli, dirs, duration, env, file, hook_env}; @@ -162,8 +163,7 @@ impl Config { .entry(plugin_name.clone()) .or_insert_with(|| { let plugin = ExternalPlugin::new(&self.settings, plugin_name); - let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); - Arc::new(tool) + build_tool(plugin_name.clone(), Box::new(plugin)) }) .clone() } @@ -314,11 +314,31 @@ fn load_rtxrc() -> Result { } fn load_tools(settings: &Settings) -> Result { + let mut tools = ToolMap::new(); + if *RTX_EXPERIMENTAL_CORE_PLUGINS { + tools.extend(load_core_tools(settings)); + } let plugins = Tool::list(settings)? .into_par_iter() .map(|p| (p.name.clone(), Arc::new(p))) - .collect(); - Ok(plugins) + .collect::>(); + tools.extend(plugins); + Ok(tools) +} + +fn load_core_tools(settings: &Settings) -> ToolMap { + let tools = [("python", PythonPlugin::new)].map(|(name, plugin)| { + let plugin = plugin(settings, name.to_string()); + ( + name.to_string(), + build_tool(name.to_string(), Box::new(plugin)), + ) + }); + ToolMap::from_iter(tools) +} + +fn build_tool(name: PluginName, plugin: Box) -> Arc { + Arc::new(Tool::new(name, plugin)) } fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap { @@ -486,7 +506,12 @@ 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.tools.keys().map(|p| p.to_string()).collect::>(); + let plugins = self + .tools + .iter() + .filter(|(_, t)| matches!(t.plugin.get_type(), PluginType::External)) + .map(|(p, _)| p.to_string()) + .collect::>(); let config_files = self .config_files .iter() diff --git a/src/env.rs b/src/env.rs index 2a39e18a5..e97d64b2e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -27,6 +27,7 @@ lazy_static! { pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); pub static ref RTX_EXE: PathBuf = current_exe().unwrap_or_else(|_| "rtx".into()); + pub static ref RTX_EXPERIMENTAL_CORE_PLUGINS: bool = var_is_true("RTX_EXPERIMENTAL_CORE_PLUGINS"); // logging pub static ref RTX_LOG_LEVEL: log::LevelFilter = { diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs new file mode 100644 index 000000000..dd6930ff7 --- /dev/null +++ b/src/plugins/core/mod.rs @@ -0,0 +1,3 @@ +mod python; + +pub use python::PythonPlugin; diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs new file mode 100644 index 000000000..676685fe9 --- /dev/null +++ b/src/plugins/core/python.rs @@ -0,0 +1,105 @@ +use color_eyre::eyre::{eyre, Result}; +use std::path::PathBuf; +use std::process::Command; +use std::time::Duration; + +use crate::cache::CacheManager; +use crate::config::{Config, Settings}; +use crate::env::RTX_EXE; +use crate::file::create_dir_all; +use crate::git::Git; +use crate::{cmd, dirs}; + +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; + +#[derive(Debug)] +pub struct PythonPlugin { + pub name: PluginName, + cache_path: PathBuf, + remote_version_cache: CacheManager>, +} + +impl PythonPlugin { + pub fn new(_settings: &Settings, name: PluginName) -> Self { + let cache_path = dirs::CACHE.join(&name); + let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours + Self { + remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) + .with_fresh_duration(fresh_duration) + .with_fresh_file(RTX_EXE.clone()), + name, + cache_path, + } + } + + fn python_build_path(&self) -> PathBuf { + self.cache_path.join("pyenv") + } + fn python_build_bin(&self) -> PathBuf { + self.python_build_path() + .join("plugins/python-build/bin/python-build") + } + fn install_or_update_python_build(&self) -> Result<()> { + if self.python_build_path().exists() { + self.update_python_build() + } else { + self.install_python_build() + } + } + fn install_python_build(&self) -> Result<()> { + if self.python_build_path().exists() { + return Ok(()); + } + debug!( + "Installing python-build to {}", + self.python_build_path().display() + ); + create_dir_all(self.python_build_path().parent().unwrap())?; + let git = Git::new(self.python_build_path()); + git.clone("https://github.com/pyenv/pyenv.git")?; + Ok(()) + } + fn update_python_build(&self) -> Result<()> { + // TODO: do not update if recently updated + debug!( + "Updating python-build in {}", + self.python_build_path().display() + ); + let git = Git::new(self.python_build_path()); + git.update(None)?; + Ok(()) + } + + fn fetch_remote_versions(&self) -> Result> { + self.install_or_update_python_build()?; + let output = cmd!(self.python_build_bin(), "--definitions").read()?; + Ok(output.split('\n').map(|s| s.to_string()).collect()) + } +} + +impl Plugin for PythonPlugin { + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &mut ProgressReport, + ) -> Result<()> { + self.install_python_build()?; + if matches!(tv.request, ToolVersionRequest::Ref(..)) { + return Err(eyre!("Ref versions not supported for python")); + } + // TODO: patch support + pr.set_message("running python-build".to_string()); + let mut cmd = Command::new(self.python_build_bin()); + cmd.arg(tv.version.as_str()).arg(tv.install_path()); + cmd::run_by_line_to_pr(&config.settings, cmd, pr) + } +} diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 39d270472..1b408df36 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -305,7 +305,7 @@ impl Plugin for ExternalPlugin { fn get_type(&self) -> PluginType { PluginType::External } - fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { + fn list_remote_versions(&self, settings: &Settings) -> Result> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) .map_err(|err| { @@ -315,6 +315,7 @@ impl Plugin for ExternalPlugin { err ) }) + .cloned() } fn latest_stable_version(&self, settings: &Settings) -> Result> { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 45285363a..03fda98cb 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -12,6 +12,7 @@ use crate::config::{Config, Settings}; use crate::toolset::ToolVersion; use crate::ui::progress_report::ProgressReport; +pub mod core; mod external_plugin; mod external_plugin_cache; mod rtx_plugin_toml; @@ -23,7 +24,7 @@ pub trait Plugin: Debug + Send + Sync { fn get_type(&self) -> PluginType { PluginType::Core } - fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec>; + fn list_remote_versions(&self, settings: &Settings) -> Result>; fn latest_stable_version(&self, _settings: &Settings) -> Result> { Ok(None) } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 92da7b1be..8013b4307 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -1,11 +1,9 @@ use crate::fake_asdf::get_path_with_fake_asdf; use std::collections::HashMap; +use std::fmt; use std::fmt::{Display, Formatter}; -use std::io::{BufRead, BufReader}; use std::path::PathBuf; -use std::process::{Command, ExitStatus, Output, Stdio}; -use std::sync::mpsc::channel; -use std::{fmt, thread}; +use std::process::{Command, Output}; use color_eyre::eyre::{Context, Result}; use duct::Expression; @@ -14,9 +12,10 @@ use once_cell::sync::Lazy; use crate::cmd::cmd; use crate::config::Settings; +use crate::errors::Error; use crate::errors::Error::ScriptFailed; use crate::file::{basename, display_path}; -use crate::{dirs, env}; +use crate::{cmd, dirs, env}; #[derive(Debug, Clone)] pub struct ScriptManager { @@ -160,94 +159,14 @@ impl ScriptManager { { let mut cmd = Command::new(self.get_script_path(script)); cmd.env_clear().envs(&self.env); - if settings.raw { - let status = cmd.spawn()?.wait()?; - match status.success() { - true => Ok(()), - false => { - on_error(String::new()); - Err( - ScriptFailed(display_path(&self.get_script_path(script)), Some(status)) - .into(), - ) - } - } - } else { - let mut cp = cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()?; - let stdout = BufReader::new(cp.stdout.take().unwrap()); - let stderr = BufReader::new(cp.stderr.take().unwrap()); - let (tx, rx) = channel(); - thread::spawn({ - let tx = tx.clone(); - move || { - for line in stdout.lines() { - let line = line.unwrap(); - tx.send(ChildProcessOutput::Stdout(line)).unwrap(); - } - tx.send(ChildProcessOutput::Done).unwrap(); - } - }); - thread::spawn({ - let tx = tx.clone(); - move || { - for line in stderr.lines() { - let line = line.unwrap(); - tx.send(ChildProcessOutput::Stderr(line)).unwrap(); - } - tx.send(ChildProcessOutput::Done).unwrap(); - } - }); - thread::spawn(move || { - let status = cp.wait().unwrap(); - tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); - tx.send(ChildProcessOutput::Done).unwrap(); - }); - let mut combined_output = vec![]; - let mut wait_for_count = 3; - let mut status = None; - for line in rx { - match line { - ChildProcessOutput::Stdout(line) => { - on_stdout(&line); - combined_output.push(line); - } - ChildProcessOutput::Stderr(line) => { - on_stderr(&line); - combined_output.push(line); - } - ChildProcessOutput::ExitStatus(s) => { - status = Some(s); - } - ChildProcessOutput::Done => { - wait_for_count -= 1; - if wait_for_count == 0 { - break; - } - } - } - } - let status = status.unwrap(); - - if !status.success() { - on_error(combined_output.join("\n")); - Err(ScriptFailed( - display_path(&self.get_script_path(script)), - Some(status), - ))?; - } - - Ok(()) + if let Err(e) = cmd::run_by_line(settings, cmd, on_error, on_stdout, on_stderr) { + let status = match e.downcast_ref::() { + Some(ScriptFailed(_, status)) => *status, + _ => None, + }; + let path = display_path(&self.get_script_path(script)); + return Err(ScriptFailed(path, status).into()); } + Ok(()) } } - -enum ChildProcessOutput { - Stdout(String), - Stderr(String), - ExitStatus(ExitStatus), - Done, -} diff --git a/src/tool.rs b/src/tool.rs index 918b14cbf..7df685dd0 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -82,7 +82,7 @@ impl Tool { Ok(versions) } - pub fn list_remote_versions(&self, settings: &Settings) -> Result<&Vec> { + pub fn list_remote_versions(&self, settings: &Settings) -> Result> { self.plugin.list_remote_versions(settings) } @@ -98,10 +98,9 @@ impl Tool { Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); let versions = self .list_remote_versions(settings)? - .iter() + .into_iter() .filter(|v| !version_regex.is_match(v)) .filter(|v| query_regex.is_match(v)) - .cloned() .collect(); Ok(versions) } From 39eed3d031f61a8d4b9c9db30e6832312a1c4d92 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 06:48:38 -0500 Subject: [PATCH 0662/1891] refactor: cli/install.rs (#457) * added python core plugin * refactor: cli/install.rs --- src/cli/install.rs | 200 +++++++++++++++++++++++++++------------------ src/test.rs | 1 + 2 files changed, 121 insertions(+), 80 deletions(-) diff --git a/src/cli/install.rs b/src/cli/install.rs index e5407d1eb..fbc0d18f8 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,4 +1,5 @@ use std::collections::HashSet; +use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; use console::style; @@ -14,8 +15,12 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; -use crate::toolset::{ToolVersionOptions, ToolVersionRequest, ToolsetBuilder}; +use crate::tool::Tool; +use crate::toolset::{ + ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, +}; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::progress_report::ProgressReport; /// Install a tool version /// @@ -68,20 +73,46 @@ impl Command for Install { impl Install { fn install_runtimes(&self, mut config: Config, runtimes: &[RuntimeArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); - let mut tool_version_requests = vec![]; let ts = ToolsetBuilder::new() .with_latest_versions() .build(&mut config)?; + ThreadPoolBuilder::new() + .num_threads(config.settings.jobs) + .build()? + .install(|| -> Result<()> { + let tool_versions = + self.get_requested_tool_versions(&mut config, &ts, runtimes, &mpr)?; + if tool_versions.is_empty() { + warn!("no runtimes to install"); + warn!("specify a version with `rtx install @`"); + return Ok(()); + } + self.uninstall_existing_versions(&config, &mpr, &tool_versions)?; + self.install_requested_versions(&config, &mpr, tool_versions)?; + reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + rebuild_symlinks(&config)?; + Ok(()) + }) + } + + fn get_requested_tool_versions( + &self, + config: &mut Config, + ts: &Toolset, + runtimes: &[RuntimeArg], + mpr: &MultiProgressReport, + ) -> Result, ToolVersion)>> { + let mut requests = vec![]; for runtime in RuntimeArg::double_runtime_condition(runtimes) { let default_opts = ToolVersionOptions::new(); match runtime.tvr { - Some(tv) => tool_version_requests.push((runtime.plugin, tv, default_opts.clone())), + Some(tv) => requests.push((runtime.plugin, tv, default_opts.clone())), None => { if runtime.tvr.is_none() { match ts.versions.get(&runtime.plugin) { Some(tvl) => { for (tvr, opts) in &tvl.requests { - tool_version_requests.push(( + requests.push(( runtime.plugin.clone(), tvr.clone(), opts.clone(), @@ -93,89 +124,27 @@ impl Install { runtime.plugin.clone(), "latest".into(), ); - tool_version_requests.push(( - runtime.plugin, - tvr, - default_opts.clone(), - )); + requests.push((runtime.plugin, tvr, default_opts.clone())); } } } } } } - ThreadPoolBuilder::new() - .num_threads(config.settings.jobs) - .build()? - .install(|| -> Result<()> { - let mut tool_versions = vec![]; - for (plugin_name, tvr, opts) in tool_version_requests { - let plugin = config.get_or_create_tool(&plugin_name); - if !plugin.is_installed() { - let mut pr = mpr.add(); - if let Err(err) = plugin.install(&config, &mut pr, false) { - pr.error(); - return Err(err)?; - } - } - let tv = tvr.resolve(&config, &plugin, opts, ts.latest_versions)?; - tool_versions.push((plugin, tv)); - } - if tool_versions.is_empty() { - warn!("no runtimes to install"); - warn!("specify a version with `rtx install @`"); - return Ok(()); - } - let mut to_uninstall = vec![]; - for (plugin, tv) in &tool_versions { - if plugin.is_version_installed(tv) { - if self.force { - to_uninstall.push((plugin, tv.clone())); - } else { - warn!("{} already installed", style(tv).cyan().for_stderr()); - } - } + let mut tool_versions = vec![]; + for (plugin_name, tvr, opts) in requests { + let plugin = config.get_or_create_tool(&plugin_name); + if !plugin.is_installed() { + let mut pr = mpr.add(); + if let Err(err) = plugin.install(config, &mut pr, false) { + pr.error(); + return Err(err)?; } - if !to_uninstall.is_empty() { - to_uninstall - .into_par_iter() - .map(|(plugin, tv)| { - let mut pr = mpr.add(); - plugin.decorate_progress_bar(&mut pr, Some(&tv)); - match plugin.uninstall_version(&config, &tv, &pr, false) { - Ok(_) => { - pr.finish(); - Ok(()) - } - Err(err) => { - pr.error(); - Err(err.wrap_err(format!("failed to uninstall {}", tv))) - } - } - }) - .collect::>>()?; - } - tool_versions - .into_par_iter() - .map(|(plugin, tv)| { - if plugin.is_version_installed(&tv) { - return Ok(()); - } - let mut pr = mpr.add(); - plugin.decorate_progress_bar(&mut pr, Some(&tv)); - match plugin.install_version(&config, &tv, &mut pr, self.force) { - Ok(_) => Ok(()), - Err(err) => { - pr.error(); - Err(err.wrap_err(format!("failed to install {}", tv))) - } - } - }) - .collect::>>()?; - reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; - rebuild_symlinks(&config)?; - Ok(()) - }) + } + let tv = tvr.resolve(config, &plugin, opts, ts.latest_versions)?; + tool_versions.push((plugin, tv)); + } + Ok(tool_versions) } fn install_missing_runtimes(&self, mut config: Config) -> Result<()> { @@ -203,6 +172,77 @@ impl Install { Ok(()) } + + fn uninstall_existing_versions( + &self, + config: &Config, + mpr: &MultiProgressReport, + tool_versions: &[(Arc, ToolVersion)], + ) -> Result<()> { + let already_installed_tool_versions = tool_versions + .iter() + .filter(|(t, tv)| t.is_version_installed(tv)) + .map(|(t, tv)| (t, tv.clone())); + if self.force { + already_installed_tool_versions + .par_bridge() + .map(|(tool, tv)| self.uninstall_version(config, tool, &tv, mpr.add())) + .collect::>>()?; + } else { + for (_, tv) in already_installed_tool_versions { + warn!("{} already installed", style(tv).cyan().for_stderr()); + } + } + Ok(()) + } + fn install_requested_versions( + &self, + config: &Config, + mpr: &MultiProgressReport, + tool_versions: Vec<(Arc, ToolVersion)>, + ) -> Result<()> { + tool_versions + .into_par_iter() + .filter(|(t, tv)| !t.is_version_installed(tv)) + .map(|(plugin, tv)| self.install_version(config, &plugin, &tv, mpr.add())) + .collect::>>()?; + Ok(()) + } + fn uninstall_version( + &self, + config: &Config, + tool: &Tool, + tv: &ToolVersion, + mut pr: ProgressReport, + ) -> Result<()> { + tool.decorate_progress_bar(&mut pr, Some(tv)); + match tool.uninstall_version(config, tv, &pr, false) { + Ok(_) => { + pr.finish(); + Ok(()) + } + Err(err) => { + pr.error(); + Err(err.wrap_err(format!("failed to uninstall {}", tv))) + } + } + } + fn install_version( + &self, + config: &Config, + tool: &Tool, + tv: &ToolVersion, + mut pr: ProgressReport, + ) -> Result<()> { + tool.decorate_progress_bar(&mut pr, Some(tv)); + match tool.install_version(config, tv, &mut pr, self.force) { + Ok(_) => Ok(()), + Err(err) => { + pr.error(); + Err(err.wrap_err(format!("failed to install {}", tv))) + } + } + } } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/test.rs b/src/test.rs index f1c4e9bc1..30dc84aa3 100644 --- a/src/test.rs +++ b/src/test.rs @@ -28,6 +28,7 @@ fn init() { //env::set_var("TERM", "dumb"); reset_config(); assert_cli!("trust"); + assert_cli!("plugins", "uninstall", "tiny-link"); assert_cli!("install", "tiny@1", "tiny@2", "tiny@3", "tiny", "dummy"); } From ef687b142eddf79045f7bfb6909de8a6948e4abe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 07:05:24 -0500 Subject: [PATCH 0663/1891] bug: fix bug with runtime symlinks (#459) if there was a symlink for a version like go1.20.3 for go1.20, it was preventing you from installing go1.20 explicitly. --- src/tool.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tool.rs b/src/tool.rs index 7df685dd0..863f19e53 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -170,7 +170,11 @@ impl Tool { pub fn is_version_installed(&self, tv: &ToolVersion) -> bool { match tv.request { ToolVersionRequest::System(_) => true, - _ => tv.install_path().exists() && !self.incomplete_file_path(tv).exists(), + _ => { + tv.install_path().exists() + && !self.incomplete_file_path(tv).exists() + && !is_runtime_symlink(&tv.install_path()) + } } } From 23897a0035c28b86484f5cd219d1effb9f6a1ba6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 07:40:04 -0500 Subject: [PATCH 0664/1891] feat: added config environments (#460) See #441 --- .rtx.dev.toml | 2 ++ .rtx.local.toml | 2 ++ README.md | 31 +++++++++++++++++++++++++++++++ src/config/mod.rs | 36 +++++++++++++++++++++--------------- src/env.rs | 1 + src/file.rs | 8 ++++++-- 6 files changed, 63 insertions(+), 17 deletions(-) create mode 100644 .rtx.dev.toml create mode 100644 .rtx.local.toml diff --git a/.rtx.dev.toml b/.rtx.dev.toml new file mode 100644 index 000000000..d8f9ce960 --- /dev/null +++ b/.rtx.dev.toml @@ -0,0 +1,2 @@ +[env] +FOO=".rtx.dev.toml" diff --git a/.rtx.local.toml b/.rtx.local.toml new file mode 100644 index 000000000..9fce2c886 --- /dev/null +++ b/.rtx.local.toml @@ -0,0 +1,2 @@ +[env] +FOO=".rtx.local.toml" diff --git a/README.md b/README.md index d18928949..07db0c1f8 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ v18.15.0 - [`~/.cache/rtx`](#cachertx) - [`~/.local/share/rtx`](#localsharertx) - [Templates](#templates) +- [[experimental] Config Environments](#experimental-config-environments) - [IDE Integration](#ide-integration) - [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) @@ -731,6 +732,12 @@ a different name. Set to something other than `.rtx.toml` to have rtx look for `.rtx.toml` config files with a different name. +#### [experimental] `RTX_ENV` + +Enables an environment-specific config file such as `.rtx.development.toml`. This is useful +for setting different versions for different environments. See +[Config Environments](#experimental-config-environments) for more on how to use this. + #### `RTX_${PLUGIN}_VERSION` Set the version for a runtime. For example, `RTX_NODEJS_VERSION=18` will use nodejs@18.x regardless @@ -1022,6 +1029,30 @@ Here's another using `exec()`: current = "{{exec(command='node --version')}}" ``` +## [experimental] Config Environments + +It's possible to have separate `.rtx.toml` files in the same directory for different +environments like `development` and `production`. To enable, set +`experimental = true` in `~/.config/rtx/config.toml`, then set `RTX_ENV` to an environment like +`development` or `production`. rtx will then look for a `.rtx.{RTX_ENV}.toml` file in the current directory. + +rtx will also look for "local" files like `.rtx.local.toml` and `.rtx.{RTX_ENV}.local.toml` in +the current directory. These are intended to not be committed to version control. +(Add `rtx.*.local.toml` to your `.gitignore` file.) + +The priority of these files goes in this order (bottom overrides top): + +* `.rtx.toml` +* `.rtx.local.toml` +* `.rtx.{RTX_ENV}.toml` +* `.rtx.{RTX_ENV}.local.toml` + +Use `rtx doctor` to see which files are being used. + +_Note that currently modifying `RTX_DEFAULT_CONFIG_FILENAME` to something other than `.rtx.toml` +will not work with this feature. For now, it will disable it entirely. This may change in the +future._ + ## IDE Integration IDEs work better with shims than they do environment variable modifications. The simplest way to setup rtx diff --git a/src/config/mod.rs b/src/config/mod.rs index 6381f4c65..75a13b028 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -52,24 +52,25 @@ pub struct Config { impl Config { pub fn load() -> Result { let global_config = load_rtxrc()?; - let mut settings = global_config.settings(); - let config_filenames = load_config_filenames(&BTreeMap::new()); - let tools = load_tools(&settings.build())?; + let mut settings_b = global_config.settings(); + let settings = settings_b.build(); + let config_filenames = load_config_filenames(&settings, &BTreeMap::new()); + let tools = load_tools(&settings)?; let config_files = load_all_config_files( - &settings.build(), + &settings_b.build(), &config_filenames, &tools, &BTreeMap::new(), ConfigMap::new(), )?; for cf in config_files.values() { - settings.merge(cf.settings()); + settings_b.merge(cf.settings()); } - let settings = settings.build(); + let settings = settings_b.build(); trace!("Settings: {:#?}", settings); let legacy_files = load_legacy_files(&settings, &tools); - let config_filenames = load_config_filenames(&legacy_files); + let config_filenames = load_config_filenames(&settings, &legacy_files); let config_track = track_config_files(&config_filenames); let config_files = load_all_config_files( @@ -367,15 +368,20 @@ fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap) -> Vec { - let mut filenames = vec![ - env::RTX_DEFAULT_CONFIG_FILENAME.as_str(), - env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str(), - ]; - for filename in legacy_filenames.keys() { - filenames.push(filename.as_str()); +fn load_config_filenames( + settings: &Settings, + legacy_filenames: &BTreeMap, +) -> Vec { + let mut filenames = legacy_filenames.keys().cloned().collect_vec(); + filenames.push(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone()); + filenames.push(env::RTX_DEFAULT_CONFIG_FILENAME.clone()); + if settings.experimental && *env::RTX_DEFAULT_CONFIG_FILENAME == ".rtx.toml" { + filenames.push(".rtx.local.toml".to_string()); + if let Some(env) = &*env::RTX_ENV { + filenames.push(format!(".rtx.{}.toml", env)); + filenames.push(format!(".rtx.{}.local.toml", env)); + } } - filenames.reverse(); let mut config_files = file::FindUp::new(&dirs::CURRENT, &filenames).collect::>(); diff --git a/src/env.rs b/src/env.rs index e97d64b2e..e8fe3ac27 100644 --- a/src/env.rs +++ b/src/env.rs @@ -22,6 +22,7 @@ lazy_static! { pub static ref RTX_DATA_DIR: PathBuf = var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx")); pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String =var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()); pub static ref RTX_DEFAULT_CONFIG_FILENAME: String =var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into()); + pub static ref RTX_ENV: Option = var("RTX_ENV").ok(); pub static ref RTX_CONFIG_FILE: Option = var_path("RTX_CONFIG_FILE"); pub static ref RTX_USE_TOML: bool = var_is_true("RTX_USE_TOML"); pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); diff --git a/src/file.rs b/src/file.rs index e305f49ea..b15038070 100644 --- a/src/file.rs +++ b/src/file.rs @@ -150,7 +150,7 @@ pub struct FindUp { } impl FindUp { - pub fn new(from: &Path, filenames: &[&str]) -> Self { + pub fn new(from: &Path, filenames: &[String]) -> Self { let filenames: Vec = filenames.iter().map(|s| s.to_string()).collect(); Self { current_dir: from.to_path_buf(), @@ -183,6 +183,7 @@ impl Iterator for FindUp { #[cfg(test)] mod tests { + use itertools::Itertools; use std::ops::Deref; use crate::dirs; @@ -192,7 +193,10 @@ mod tests { #[test] fn test_find_up() { let path = &dirs::CURRENT; - let filenames = vec![".rtxrc", ".rtxrc.toml", ".test-tool-versions"]; + let filenames = vec![".rtxrc", ".rtxrc.toml", ".test-tool-versions"] + .into_iter() + .map(|s| s.to_string()) + .collect_vec(); #[allow(clippy::needless_collect)] let find_up = FindUp::new(path, &filenames).collect::>(); let mut find_up = find_up.into_iter(); From fe6ff9006dc9d59b6cb5c6285b5020170a790db9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 07:53:27 -0500 Subject: [PATCH 0665/1891] chore: Release --- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abc7e0c9d..4448d9964 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,9 +368,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3c796f3b0b408d9fd581611b47fa850821fcb84aa640b83a3c1a5be2d691f2" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" dependencies = [ "console", "shell-words", @@ -594,13 +594,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -749,9 +749,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -1052,14 +1052,14 @@ checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "is-terminal" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1586,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.27.12" +version = "1.28.0" dependencies = [ "base64", "built", @@ -1646,16 +1646,16 @@ checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustix" -version = "0.37.7" +version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags", - "errno 0.3.0", + "errno 0.3.1", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 298e338c0..f06511d73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.27.12" +version = "1.28.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 07db0c1f8..0f01c91b8 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.27.12 +rtx 1.28.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.27.12/rtx-v1.27.12-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.28.0/rtx-v1.28.0-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index e2c54ea60..ffac6b6d5 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.27.12"; + version = "1.28.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index f23579f64..e90dcdbcc 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.27.12" +.TH rtx 1 "rtx 1.28.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.27.12 +v1.28.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 443cb9380..e0ce3015b 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.27.12 +Version: 1.28.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 54a5331c1..982a58975 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -145,7 +145,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 640] = [ ("dive", "https://github.com/looztra/asdf-dive.git"), ("djinni", "https://github.com/cross-language-cpp/asdf-djinni.git"), ("dmd", "https://github.com/sylph01/asdf-dmd.git"), - ("docker-compose-v1", "https://github.com/kompiro/asdf-docker-compose-v1"), + ("docker-compose-v1", "https://github.com/yilas/asdf-docker-compose-v1"), ("docker-slim", "https://github.com/xataz/asdf-docker-slim.git"), ("dockle", "https://github.com/mathew-fleisch/asdf-dockle.git"), ("doctl", "https://github.com/maristgeek/asdf-doctl.git"), From fe0e1c87e75e51e66913ad6197d99e68e27634cc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 15:17:19 -0500 Subject: [PATCH 0666/1891] refactor: use lazy instead of lazy_static! macro (#463) --- Cargo.lock | 15 +-- Cargo.toml | 3 +- justfile | 4 +- lefthook.yml | 4 +- src/build_time.rs | 12 +- src/dirs.rs | 20 ++- src/env.rs | 223 ++++++++++++++++++--------------- src/env_diff.rs | 11 +- src/git.rs | 2 +- src/lib.rs | 1 + src/main.rs | 1 + src/plugins/external_plugin.rs | 27 ++-- src/plugins/script_manager.rs | 20 ++- src/test.rs | 6 +- 14 files changed, 186 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4448d9964..ead25acb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -429,16 +429,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "ctor" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" -dependencies = [ - "quote", - "syn 2.0.13", -] - [[package]] name = "ctrlc" version = "3.2.5" @@ -1401,7 +1391,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "ctor 0.1.26", + "ctor", "diff", "output_vt100", "yansi", @@ -1596,7 +1586,7 @@ dependencies = [ "color-eyre", "color-print", "console", - "ctor 0.2.0", + "ctor", "ctrlc", "dialoguer", "dirs-next", @@ -1613,7 +1603,6 @@ dependencies = [ "indoc", "insta", "itertools", - "lazy_static", "log", "num_cpus", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index f06511d73..c0b7380a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,6 @@ clap_complete = "4.0.7" color-eyre = "0.6.2" color-print = "0.3.4" console = "0.15.2" -ctor = "<0.3" ctrlc = "3.2.3" dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" @@ -57,7 +56,6 @@ indexmap = { version = "1.9.2", features = ["serde"] } indicatif = { version = "0.17.3", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.10.3" -lazy_static = "1.4.0" log = "0.4.17" num_cpus = "1.14.0" once_cell = "1.17.0" @@ -92,6 +90,7 @@ exec = "0.3.1" built = { version = "0.6.0", features = ["chrono", "git2"] } [dev-dependencies] +ctor = "<0.3" insta = "1.26.0" pretty_assertions = "1.3.0" diff --git a/justfile b/justfile index 3a4a8cddd..5b21e4521 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,7 @@ set shell := ["bash", "-uc"] export RTX_DATA_DIR := "/tmp/rtx" -export PATH := env_var_or_default("CARGO_TARGET_DIR", "$PWD/target") + "/debug:" + env_var("PATH") +export PATH := env_var_or_default("CARGO_TARGET_DIR", justfile_directory() / "target") / "debug:" + env_var("PATH") export RTX_MISSING_RUNTIME_BEHAVIOR := "autoinstall" export RUST_TEST_THREADS := "1" @@ -11,6 +11,8 @@ default: test alias b := build alias e := test-e2e alias t := test +alias l := lint +alias lf := lint-fix # just `cargo build` build *args: diff --git a/lefthook.yml b/lefthook.yml index f731b99a2..731f3b547 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -2,6 +2,6 @@ pre-commit: parallel: true commands: pre-commit: - run: just pre-commit + run: just -v pre-commit lint: - run: just lint + run: just -v lint diff --git a/src/build_time.rs b/src/build_time.rs index 2e52220f6..da57b8783 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -1,6 +1,6 @@ use chrono::{DateTime, FixedOffset, Months, Utc}; use console::style; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use crate::env::RTX_HIDE_UPDATE_WARNING; @@ -8,13 +8,11 @@ pub mod built_info { include!(concat!(env!("OUT_DIR"), "/built.rs")); } -lazy_static! { - pub static ref BUILD_TIME: DateTime = - DateTime::parse_from_rfc2822(built_info::BUILT_TIME_UTC).unwrap(); -} +pub static BUILD_TIME: Lazy> = + Lazy::new(|| DateTime::parse_from_rfc2822(built_info::BUILT_TIME_UTC).unwrap()); -#[ctor::ctor] -fn init() { +#[allow(dead_code)] +pub fn init() { if !*RTX_HIDE_UPDATE_WARNING && BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() { diff --git a/src/dirs.rs b/src/dirs.rs index 1d6c15db0..ac653bc73 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -1,16 +1,14 @@ use std::path::PathBuf; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use crate::env; -lazy_static! { - pub static ref CURRENT: PathBuf = env::PWD.clone(); - pub static ref HOME: PathBuf = env::HOME.clone(); - pub static ref ROOT: PathBuf = env::RTX_DATA_DIR.clone(); - pub static ref CACHE: PathBuf = env::RTX_CACHE_DIR.clone(); - pub static ref CONFIG: PathBuf = env::RTX_CONFIG_DIR.clone(); - pub static ref PLUGINS: PathBuf = env::RTX_DATA_DIR.join("plugins"); - pub static ref DOWNLOADS: PathBuf = env::RTX_DATA_DIR.join("downloads"); - pub static ref INSTALLS: PathBuf = env::RTX_DATA_DIR.join("installs"); -} +pub static CURRENT: Lazy = Lazy::new(|| env::PWD.clone()); +pub static HOME: Lazy = Lazy::new(|| env::HOME.clone()); +pub static ROOT: Lazy = Lazy::new(|| env::RTX_DATA_DIR.clone()); +pub static CACHE: Lazy = Lazy::new(|| env::RTX_CACHE_DIR.clone()); +pub static CONFIG: Lazy = Lazy::new(|| env::RTX_CONFIG_DIR.clone()); +pub static PLUGINS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("plugins")); +pub static DOWNLOADS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("downloads")); +pub static INSTALLS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("installs")); diff --git a/src/env.rs b/src/env.rs index e8fe3ac27..07a0964b5 100644 --- a/src/env.rs +++ b/src/env.rs @@ -3,112 +3,92 @@ pub use std::env::*; use std::path::PathBuf; use itertools::Itertools; -use lazy_static::lazy_static; use log::LevelFilter; +use once_cell::sync::Lazy; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; -lazy_static! { - pub static ref ARGS: Vec = args().collect(); +pub static ARGS: Lazy> = Lazy::new(|| args().collect()); +pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "sh".into())); - // paths and directories - pub static ref HOME: PathBuf = dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/")); - pub static ref PWD: PathBuf =current_dir().unwrap_or_else(|_| PathBuf::new()); - pub static ref XDG_CACHE_HOME: PathBuf = dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache")); - pub static ref XDG_DATA_HOME: PathBuf =var_path("XDG_DATA_HOME").unwrap_or_else(|| HOME.join(".local/share")); - pub static ref XDG_CONFIG_HOME: PathBuf =var_path("XDG_CONFIG_HOME").unwrap_or_else(|| HOME.join(".config")); - pub static ref RTX_CACHE_DIR: PathBuf =var_path("RTX_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("rtx")); - pub static ref RTX_CONFIG_DIR: PathBuf =var_path("RTX_CONFIG_DIR").unwrap_or_else(|| XDG_CONFIG_HOME.join("rtx")); - pub static ref RTX_DATA_DIR: PathBuf = var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx")); - pub static ref RTX_DEFAULT_TOOL_VERSIONS_FILENAME: String =var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()); - pub static ref RTX_DEFAULT_CONFIG_FILENAME: String =var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into()); - pub static ref RTX_ENV: Option = var("RTX_ENV").ok(); - pub static ref RTX_CONFIG_FILE: Option = var_path("RTX_CONFIG_FILE"); - pub static ref RTX_USE_TOML: bool = var_is_true("RTX_USE_TOML"); - pub static ref RTX_TMP_DIR: PathBuf = temp_dir().join("rtx"); - pub static ref SHELL: String = var("SHELL").unwrap_or_else(|_| "sh".into()); - pub static ref RTX_EXE: PathBuf = current_exe().unwrap_or_else(|_| "rtx".into()); - pub static ref RTX_EXPERIMENTAL_CORE_PLUGINS: bool = var_is_true("RTX_EXPERIMENTAL_CORE_PLUGINS"); +// paths and directories +pub static HOME: Lazy = + Lazy::new(|| dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/"))); +pub static PWD: Lazy = Lazy::new(|| current_dir().unwrap_or_else(|_| PathBuf::new())); +pub static XDG_CACHE_HOME: Lazy = + Lazy::new(|| dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache"))); +pub static XDG_DATA_HOME: Lazy = + Lazy::new(|| dirs_next::data_dir().unwrap_or_else(|| HOME.join(".local/share"))); +pub static XDG_CONFIG_HOME: Lazy = + Lazy::new(|| dirs_next::config_dir().unwrap_or_else(|| HOME.join(".config"))); +pub static RTX_CACHE_DIR: Lazy = + Lazy::new(|| var_path("RTX_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("rtx"))); +pub static RTX_CONFIG_DIR: Lazy = + Lazy::new(|| var_path("RTX_CONFIG_DIR").unwrap_or_else(|| XDG_CONFIG_HOME.join("rtx"))); +pub static RTX_DATA_DIR: Lazy = + Lazy::new(|| var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx"))); +pub static RTX_TMP_DIR: Lazy = Lazy::new(|| temp_dir().join("rtx")); - // logging - pub static ref RTX_LOG_LEVEL: log::LevelFilter = { - for (i, arg) in ARGS.iter().enumerate() { - if arg == "--" { - break; - } - if let Some(("--log-level", level)) = arg.split_once('=') { - std::env::set_var("RTX_LOG_LEVEL", level); - } - if arg == "--log-level" { - if let Some(level) = ARGS.get(i + 1) { - std::env::set_var("RTX_LOG_LEVEL", level); - } - } - if arg == "--debug" { - std::env::set_var("RTX_DEBUG", "1"); - } - if arg == "--trace" { - std::env::set_var("RTX_TRACE", "1"); - } - } - let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); - match log_level.parse::() { - Ok(level) => level, - _ => { - if *RTX_TRACE { - log::LevelFilter::Trace - } else if *RTX_DEBUG { - log::LevelFilter::Debug - } else if *RTX_QUIET { - log::LevelFilter::Warn - } else { - log::LevelFilter::Info - } - } - } - }; - pub static ref RTX_LOG_FILE_LEVEL: log::LevelFilter = { - let log_level = var("RTX_LOG_FILE_LEVEL").unwrap_or_default(); - match log_level.parse::() { - Ok(level) => level, - _ => *RTX_LOG_LEVEL, - } - }; - pub static ref RTX_MISSING_RUNTIME_BEHAVIOR: Option =var("RTX_MISSING_RUNTIME_BEHAVIOR").ok(); - pub static ref __RTX_DIFF: EnvDiff = get_env_diff(); - /// true if inside of a script like bin/exec-env or bin/install - /// used to prevent infinite loops - pub static ref __RTX_SCRIPT: bool = var_is_true("__RTX_SCRIPT"); - pub static ref RTX_QUIET: bool = var_is_true("RTX_QUIET"); - pub static ref RTX_DEBUG: bool = var_is_true("RTX_DEBUG"); - pub static ref RTX_TRACE: bool = var_is_true("RTX_TRACE"); - pub static ref RTX_VERBOSE: bool = *RTX_DEBUG || *RTX_TRACE || var_is_true("RTX_VERBOSE"); - pub static ref DUMB_TERMINAL: bool = cfg!(test) || var("TERM").map_or(false, |term| term == "dumb"); - pub static ref CI: bool = var_is_true("CI"); - pub static ref RTX_JOBS: usize = var("RTX_JOBS").ok().and_then(|v| v.parse::().ok()).unwrap_or(4); - pub static ref PREFER_STALE: bool = prefer_stale(&ARGS); - /// essentially, this is whether we show spinners or build output on runtime install - pub static ref PRISTINE_ENV: HashMap = - get_pristine_env(&__RTX_DIFF, vars().collect()); - pub static ref PATH: Vec = match PRISTINE_ENV.get("PATH") { - Some(path) => split_paths(path).collect(), - None => vec![], - }; - pub static ref DIRENV_DIR: Option = var("DIRENV_DIR").ok(); - pub static ref DIRENV_DIFF: Option = var("DIRENV_DIFF").ok(); - pub static ref RTX_CONFIRM: Confirm = var_confirm("RTX_CONFIRM"); - pub static ref RTX_EXPERIMENTAL: bool = var_is_true("RTX_EXPERIMENTAL"); - pub static ref RTX_HIDE_UPDATE_WARNING: bool = var_is_true("RTX_HIDE_UPDATE_WARNING"); - pub static ref RTX_ASDF_COMPAT: bool = var_is_true("RTX_ASDF_COMPAT"); - pub static ref RTX_SHORTHANDS_FILE: Option = var_path("RTX_SHORTHANDS_FILE"); - pub static ref RTX_DISABLE_DEFAULT_SHORTHANDS: bool = var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS"); - pub static ref RTX_SHIMS_DIR: Option = var_path("RTX_SHIMS_DIR"); - pub static ref RTX_RAW: bool = var_is_true("RTX_RAW"); - pub static ref RTX_TRUSTED_CONFIG_PATHS: Vec = var("RTX_TRUSTED_CONFIG_PATHS") +pub static RTX_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy = Lazy::new(|| { + var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) +}); +pub static RTX_DEFAULT_CONFIG_FILENAME: Lazy = + Lazy::new(|| var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into())); +pub static RTX_ENV: Lazy> = Lazy::new(|| var("RTX_ENV").ok()); +pub static RTX_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("RTX_CONFIG_FILE")); +pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); +pub static RTX_EXE: Lazy = Lazy::new(|| current_exe().unwrap_or_else(|_| "rtx".into())); +pub static RTX_EXPERIMENTAL_CORE_PLUGINS: Lazy = + Lazy::new(|| var_is_true("RTX_EXPERIMENTAL_CORE_PLUGINS")); +pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); +pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); +pub static RTX_MISSING_RUNTIME_BEHAVIOR: Lazy> = + Lazy::new(|| var("RTX_MISSING_RUNTIME_BEHAVIOR").ok()); +pub static RTX_QUIET: Lazy = Lazy::new(|| var_is_true("RTX_QUIET")); +pub static RTX_DEBUG: Lazy = Lazy::new(|| var_is_true("RTX_DEBUG")); +pub static RTX_TRACE: Lazy = Lazy::new(|| var_is_true("RTX_TRACE")); +pub static RTX_VERBOSE: Lazy = + Lazy::new(|| *RTX_DEBUG || *RTX_TRACE || var_is_true("RTX_VERBOSE")); +pub static RTX_JOBS: Lazy = Lazy::new(|| { + var("RTX_JOBS") + .ok() + .and_then(|v| v.parse::().ok()) + .unwrap_or(4) +}); + +/// true if inside a script like bin/exec-env or bin/install +/// used to prevent infinite loops +pub static __RTX_SCRIPT: Lazy = Lazy::new(|| var_is_true("__RTX_SCRIPT")); +pub static __RTX_DIFF: Lazy = Lazy::new(get_env_diff); +pub static CI: Lazy = Lazy::new(|| var_is_true("CI")); +pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS)); + +/// essentially, this is whether we show spinners or build output on runtime install +pub static PRISTINE_ENV: Lazy> = + Lazy::new(|| get_pristine_env(&__RTX_DIFF, vars().collect())); +pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH") { + Some(path) => split_paths(path).collect(), + None => vec![], +}); +pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); +pub static RTX_CONFIRM: Lazy = Lazy::new(|| var_confirm("RTX_CONFIRM")); +pub static RTX_EXPERIMENTAL: Lazy = Lazy::new(|| var_is_true("RTX_EXPERIMENTAL")); +pub static RTX_HIDE_UPDATE_WARNING: Lazy = + Lazy::new(|| var_is_true("RTX_HIDE_UPDATE_WARNING")); +pub static RTX_ASDF_COMPAT: Lazy = Lazy::new(|| var_is_true("RTX_ASDF_COMPAT")); +pub static RTX_SHORTHANDS_FILE: Lazy> = + Lazy::new(|| var_path("RTX_SHORTHANDS_FILE")); +pub static RTX_DISABLE_DEFAULT_SHORTHANDS: Lazy = + Lazy::new(|| var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS")); +pub static RTX_SHIMS_DIR: Lazy> = Lazy::new(|| var_path("RTX_SHIMS_DIR")); +pub static RTX_RAW: Lazy = Lazy::new(|| var_is_true("RTX_RAW")); +pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { + var("RTX_TRUSTED_CONFIG_PATHS") .map(|v| split_paths(&v).collect()) - .unwrap_or_default(); - pub static ref GITHUB_API_TOKEN: Option = var("GITHUB_API_TOKEN").ok(); -} + .unwrap_or_default() +}); +#[allow(unused)] +pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { @@ -223,6 +203,51 @@ fn prefer_stale(args: &[String]) -> bool { false } +fn log_level() -> LevelFilter { + for (i, arg) in ARGS.iter().enumerate() { + if arg == "--" { + break; + } + if let Some(("--log-level", level)) = arg.split_once('=') { + set_var("RTX_LOG_LEVEL", level); + } + if arg == "--log-level" { + if let Some(level) = ARGS.get(i + 1) { + set_var("RTX_LOG_LEVEL", level); + } + } + if arg == "--debug" { + set_var("RTX_DEBUG", "1"); + } + if arg == "--trace" { + set_var("RTX_TRACE", "1"); + } + } + let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); + match log_level.parse::() { + Ok(level) => level, + _ => { + if *RTX_TRACE { + LevelFilter::Trace + } else if *RTX_DEBUG { + LevelFilter::Debug + } else if *RTX_QUIET { + LevelFilter::Warn + } else { + LevelFilter::Info + } + } + } +} + +fn log_file_level() -> LevelFilter { + let log_level = var("RTX_LOG_FILE_LEVEL").unwrap_or_default(); + match log_level.parse::() { + Ok(level) => level, + _ => *RTX_LOG_LEVEL, + } +} + #[cfg(test)] mod tests { use std::collections::HashMap; diff --git a/src/env_diff.rs b/src/env_diff.rs index a684bb4ac..9ca912389 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::ffi::OsString; use std::fmt::Debug; use std::io::prelude::*; use std::path::{Path, PathBuf}; @@ -60,10 +61,10 @@ impl EnvDiff { pub fn from_bash_script(script: &Path, env: T) -> Result where T: IntoIterator, - U: Into, - V: Into, + U: Into, + V: Into, { - let env: HashMap = + let env: HashMap = env.into_iter().map(|(k, v)| (k.into(), v.into())).collect(); let out = cmd!( "bash", @@ -75,6 +76,10 @@ impl EnvDiff { ) .full_env(&env) .read()?; + let env: HashMap = env + .into_iter() + .map(|(k, v)| (k.into_string().unwrap(), v.into_string().unwrap())) + .collect(); let mut additions = HashMap::new(); let mut cur_key = None; diff --git a/src/git.rs b/src/git.rs index cf4303a50..6e91b1ab3 100644 --- a/src/git.rs +++ b/src/git.rs @@ -44,7 +44,7 @@ impl Git { "--prune", "--update-head-ok", "origin", - [gitref.as_str(), gitref.as_str()].join(":"), + format!("{}:{}", gitref, gitref), ) .run()?; let prev_rev = self.current_sha()?; diff --git a/src/lib.rs b/src/lib.rs index fa30c5def..bbb1e20da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ mod default_shorthands; mod direnv; mod dirs; mod duration; +#[allow(dead_code)] mod env; mod env_diff; mod errors; diff --git a/src/main.rs b/src/main.rs index e40e91f1e..aa7f0c80c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,6 +52,7 @@ mod toolset; mod ui; fn main() -> Result<()> { + build_time::init(); color_eyre::install()?; let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 1b408df36..868201b74 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -237,7 +237,7 @@ impl ExternalPlugin { } if let Some(project_root) = &config.project_root { let project_root = project_root.to_string_lossy().to_string(); - sm = sm.with_env("RTX_PROJECT_ROOT".into(), project_root); + sm = sm.with_env("RTX_PROJECT_ROOT", project_root); } let install_type = match &tv.request { ToolVersionRequest::Version(_, _) | ToolVersionRequest::Prefix(_, _) => "version", @@ -249,39 +249,36 @@ impl ExternalPlugin { }; sm = sm .with_env( - "RTX_INSTALL_PATH".into(), + "RTX_INSTALL_PATH", tv.install_path().to_string_lossy().to_string(), ) .with_env( - "ASDF_INSTALL_PATH".into(), + "ASDF_INSTALL_PATH", tv.install_path().to_string_lossy().to_string(), ) .with_env( - "RTX_DOWNLOAD_PATH".into(), + "RTX_DOWNLOAD_PATH", tv.download_path().to_string_lossy().to_string(), ) .with_env( - "ASDF_DOWNLOAD_PATH".into(), + "ASDF_DOWNLOAD_PATH", tv.download_path().to_string_lossy().to_string(), ) - .with_env("RTX_INSTALL_TYPE".into(), install_type.into()) - .with_env("ASDF_INSTALL_TYPE".into(), install_type.into()) - .with_env("RTX_INSTALL_VERSION".into(), tv.version.clone()) - .with_env("ASDF_INSTALL_VERSION".into(), tv.version.clone()); + .with_env("RTX_INSTALL_TYPE", install_type) + .with_env("ASDF_INSTALL_TYPE", install_type) + .with_env("RTX_INSTALL_VERSION", tv.version.clone()) + .with_env("ASDF_INSTALL_VERSION", tv.version.clone()); sm } } fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> ScriptManager { let mut sm = ScriptManager::new(plugin_path.to_path_buf()) - .with_env("RTX_PLUGIN_NAME".into(), name.to_string()) - .with_env( - "RTX_PLUGIN_PATH".into(), - plugin_path.to_string_lossy().to_string(), - ); + .with_env("RTX_PLUGIN_NAME", name.to_string()) + .with_env("RTX_PLUGIN_PATH", plugin_path.to_string_lossy().to_string()); if let Some(shims_dir) = &settings.shims_dir { let shims_dir = shims_dir.to_string_lossy().to_string(); - sm = sm.with_env("RTX_SHIMS_DIR".into(), shims_dir); + sm = sm.with_env("RTX_SHIMS_DIR", shims_dir); } sm diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 8013b4307..072b14986 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -1,5 +1,6 @@ use crate::fake_asdf::get_path_with_fake_asdf; use std::collections::HashMap; +use std::ffi::OsString; use std::fmt; use std::fmt::{Display, Formatter}; use std::path::PathBuf; @@ -21,7 +22,7 @@ use crate::{cmd, dirs, env}; pub struct ScriptManager { pub plugin_path: PathBuf, pub plugin_name: String, - pub env: HashMap, + pub env: HashMap, } #[derive(Debug, Clone)] @@ -66,8 +67,11 @@ impl Display for Script { } } -static INITIAL_ENV: Lazy> = Lazy::new(|| { - let mut env = env::PRISTINE_ENV.clone(); +static INITIAL_ENV: Lazy> = Lazy::new(|| { + let mut env: HashMap = env::PRISTINE_ENV + .iter() + .map(|(k, v)| (k.into(), v.into())) + .collect(); env.extend( (indexmap! { "__RTX_SCRIPT" => "1".to_string(), @@ -79,7 +83,7 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { "RTX_EXE" => env::RTX_EXE.to_string_lossy().to_string(), }) .into_iter() - .map(|(k, v)| (k.to_string(), v)), + .map(|(k, v)| (k.into(), v.into())), ); env }); @@ -93,8 +97,12 @@ impl ScriptManager { } } - pub fn with_env(mut self, k: String, v: String) -> Self { - self.env.insert(k, v); + pub fn with_env(mut self, k: K, v: V) -> Self + where + K: Into, + V: Into, + { + self.env.insert(k.into(), v.into()); self } diff --git a/src/test.rs b/src/test.rs index 30dc84aa3..6d005312e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -75,7 +75,7 @@ pub fn replace_path(input: &str) -> String { .to_string(); let home = env::HOME.to_string_lossy().to_string(); input - .replace(path.as_str(), "$PATH") - .replace(home.as_str(), "~") - .replace(env::RTX_EXE.to_string_lossy().as_ref(), "rtx") + .replace(&path, "$PATH") + .replace(&home, "~") + .replace(&*env::RTX_EXE.to_string_lossy(), "rtx") } From 3bdf139b45db40e247995442d200f27ba96f9f83 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 16:55:45 -0500 Subject: [PATCH 0667/1891] python patches (#461) * added http client library I will need this for the python core plugin * patch support for python core plugin diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..bd28b9c --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.9 diff --git a/.rtx.toml b/.rtx.toml deleted file mode 100644 index 67ce802..0000000 --- a/.rtx.toml +++ /dev/null @@ -1,17 +0,0 @@ -#:schema ./schema/rtx.json -env_file = '.env' -[env] -FOO = "bar" -THIS_PROJECT = "{{config_root}}-{{env.PWD}}" - -[tools] -nodejs = 'lts' -tiny = { version = "1", foo = "bar" } -golang = { version = "latest", foo = "bar" } -python = { version = "latest", virtualenv = "$HOME/.cache/venv" } - -[plugins] -node = 'https://github.com/rtx-plugins/rtx-nodejs#main' - -[alias.tiny] -abc = '1' diff --git a/src/cmd.rs b/src/cmd.rs index cad2ba7..e666680 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -105,34 +105,24 @@ pub fn run_by_line_to_pr(settings: &Settings, cmd: Command, pr: &mut ProgressRep ) } -pub fn run_by_line<'a, F1, F2, F3>( - settings: &Settings, - mut cmd: Command, - on_error: F1, - on_stdout: F2, - on_stderr: F3, -) -> Result<()> -where - F1: Fn(String), - F2: Fn(&str) + Send + Sync + 'a, - F3: Fn(&str) + Send + Sync, -{ - let program = cmd.get_program().to_string_lossy().to_string(); - if settings.raw { - let status = cmd.spawn()?.wait()?; - match status.success() { - true => Ok(()), - false => { - on_error(String::new()); - Err(ScriptFailed(program, Some(status)).into()) - } +pub struct CmdLineRunner { + cmd: Command, +} +impl CmdLineRunner { + pub fn new(program: &str) -> Self { + let mut cmd = Command::new(program); + cmd.stdin(Stdio::null()); + cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::piped()); + + Self { cmd } + } + + pub fn execute(mut self) -> Result<()> { + if self.raw { + return self.execute_raw(); } - } else { - let mut cp = cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()?; + let cp = self.cmd.spawn()?; let stdout = BufReader::new(cp.stdout.take().unwrap()); let stderr = BufReader::new(cp.stderr.take().unwrap()); let (tx, rx) = channel(); @@ -194,6 +184,41 @@ where Ok(()) } + + pub fn execute_raw(mut self) -> Result<()> { + let status = self.cmd.spawn()?.wait()?; + match status.success() { + true => Ok(()), + false => { + self.on_error(String::new()); + let program = self.cmd.get_program().to_string_lossy().to_string(); + Err(ScriptFailed(program, Some(status)).into()) + } + } + } +} + +pub fn run_by_line<'a, F1, F2, F3>( + settings: &Settings, + mut cmd: Command, + on_error: F1, + on_stdout: F2, + on_stderr: F3, +) -> Result<()> +where + F1: Fn(String), + F2: Fn(&str) + Send + Sync + 'a, + F3: Fn(&str) + Send + Sync, +{ + let program = cmd.get_program().to_string_lossy().to_string(); + if settings.raw { + } else { + let mut cp = cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + } } enum ChildProcessOutput { diff --git a/src/env.rs b/src/env.rs index 07a0964..da60cfa 100644 --- a/src/env.rs +++ b/src/env.rs @@ -90,6 +90,10 @@ pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); +// python +pub static RTX_PYTHON_PATCH_URL: Lazy> = Lazy::new(||var("RTX_PYTHON_PATCH_URL").ok()); +pub static RTX_PYTHON_PATCHES_DIRECTORY: Lazy> = Lazy::new(||var_path("RTX_PYTHON_PATCHES_DIRECTORY")); + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { Yes, @@ -203,51 +207,6 @@ fn prefer_stale(args: &[String]) -> bool { false } -fn log_level() -> LevelFilter { - for (i, arg) in ARGS.iter().enumerate() { - if arg == "--" { - break; - } - if let Some(("--log-level", level)) = arg.split_once('=') { - set_var("RTX_LOG_LEVEL", level); - } - if arg == "--log-level" { - if let Some(level) = ARGS.get(i + 1) { - set_var("RTX_LOG_LEVEL", level); - } - } - if arg == "--debug" { - set_var("RTX_DEBUG", "1"); - } - if arg == "--trace" { - set_var("RTX_TRACE", "1"); - } - } - let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); - match log_level.parse::() { - Ok(level) => level, - _ => { - if *RTX_TRACE { - LevelFilter::Trace - } else if *RTX_DEBUG { - LevelFilter::Debug - } else if *RTX_QUIET { - LevelFilter::Warn - } else { - LevelFilter::Info - } - } - } -} - -fn log_file_level() -> LevelFilter { - let log_level = var("RTX_LOG_FILE_LEVEL").unwrap_or_default(); - match log_level.parse::() { - Ok(level) => level, - _ => *RTX_LOG_LEVEL, - } -} - #[cfg(test)] mod tests { use std::collections::HashMap; diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 676685f..9273660 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -1,5 +1,5 @@ use color_eyre::eyre::{eyre, Result}; -use std::path::PathBuf; +use std::path::{PathBuf}; use std::process::Command; use std::time::Duration; @@ -8,7 +8,7 @@ use crate::config::{Config, Settings}; use crate::env::RTX_EXE; use crate::file::create_dir_all; use crate::git::Git; -use crate::{cmd, dirs}; +use crate::{cmd, dirs, env}; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; @@ -96,10 +96,19 @@ impl Plugin for PythonPlugin { if matches!(tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); } - // TODO: patch support pr.set_message("running python-build".to_string()); let mut cmd = Command::new(self.python_build_bin()); + if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { + pr.set_message(format!("with patch file from: {patch_url}")); + cmd.arg("--patch"); + reqwest::blocking::get(patch_url)?.copy_to(&mut cmd.arg("-"))?; + } cmd.arg(tv.version.as_str()).arg(tv.install_path()); + // TODO: patch support cmd::run_by_line_to_pr(&config.settings, cmd, pr) } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".python-version".to_string()]) + } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 03fda98..f8c0a9c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -49,8 +49,9 @@ pub trait Plugin: Debug + Send + Sync { fn legacy_filenames(&self, _settings: &Settings) -> Result> { Ok(vec![]) } - fn parse_legacy_file(&self, _path: &Path, _settings: &Settings) -> Result { - unimplemented!() + fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + let contents = std::fs::read_to_string(path)?; + Ok(contents.trim().to_string()) } fn external_commands(&self) -> Result>> { Ok(vec![]) --- src/cli/exec.rs | 1 - src/cli/global.rs | 1 - src/cli/install.rs | 1 - src/cli/local.rs | 1 - src/cli/mod.rs | 23 ++++- src/cli/plugins/uninstall.rs | 2 +- src/cli/shell.rs | 1 - src/cli/uninstall.rs | 2 +- src/cli/version.rs | 12 +-- src/cmd.rs | 148 ++++++++++++++++++++------------ src/config/mod.rs | 11 +-- src/env.rs | 6 ++ src/http.rs | 20 +++++ src/lib.rs | 1 + src/main.rs | 1 + src/plugins/core/python.rs | 37 ++++++-- src/plugins/external_plugin.rs | 36 ++------ src/plugins/mod.rs | 13 ++- src/plugins/script_manager.rs | 26 +++--- src/ui/multi_progress_report.rs | 6 +- src/ui/progress_report.rs | 39 +++++---- 21 files changed, 234 insertions(+), 154 deletions(-) create mode 100644 src/http.rs diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 28a60eff7..96bf56d54 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -49,7 +49,6 @@ pub struct Exec { impl Command for Exec { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - config.autoupdate(); let ts = ToolsetBuilder::new() .with_args(&self.runtime) .with_install_missing() diff --git a/src/cli/global.rs b/src/cli/global.rs index e7c65499a..446a25b9c 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -51,7 +51,6 @@ pub struct Global { impl Command for Global { fn run(self, config: Config, out: &mut Output) -> Result<()> { - config.autoupdate(); local( config, out, diff --git a/src/cli/install.rs b/src/cli/install.rs index fbc0d18f8..9f32337cc 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -59,7 +59,6 @@ pub struct Install { impl Command for Install { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { config.settings.missing_runtime_behavior = AutoInstall; - config.autoupdate(); match &self.runtime { Some(runtime) => self.install_runtimes(config, runtime)?, diff --git a/src/cli/local.rs b/src/cli/local.rs index 915dffba0..1490d9cd5 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -55,7 +55,6 @@ pub struct Local { impl Command for Local { fn run(self, config: Config, out: &mut Output) -> Result<()> { - config.autoupdate(); let path = if self.parent { get_parent_path()? } else { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 5a33456d0..bce3df334 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -200,10 +200,31 @@ impl Cli { if let Some((command, sub_m)) = matches.subcommand() { external::execute(&config, command, sub_m, self.external_commands)?; } - Commands::from_arg_matches(&matches)?.run(config, out) + let cmd = Commands::from_arg_matches(&matches)?; + if !is_fast_command(&cmd) { + config.check_for_new_version(); + } + cmd.run(config, out) } } +fn is_fast_command(cmd: &Commands) -> bool { + matches!( + cmd, + Commands::Version(..) + | Commands::Activate(..) + | Commands::Asdf(..) + | Commands::Completion(..) + | Commands::HookEnv(..) + | Commands::Direnv(..) + | Commands::Env(..) + | Commands::Exec(..) + | Commands::Shell(..) + | Commands::Where(..) + | Commands::Which(..) + ) +} + impl Default for Cli { fn default() -> Self { Self::new() diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 862d86c38..e461092c6 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -38,7 +38,7 @@ impl PluginsUninstall { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, None); plugin.uninstall(&pr)?; - pr.finish_with_message("uninstalled".into()); + pr.finish_with_message("uninstalled"); } _ => mpr.suspend(|| { warn!( diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 4b78ef8ce..cf97a8dda 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -26,7 +26,6 @@ pub struct Shell { impl Command for Shell { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - config.autoupdate(); let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.runtime) diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 6e0d54f2d..60aebd610 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -47,7 +47,7 @@ impl Command for Uninstall { pr.error(); return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", &tv))); } - pr.finish_with_message("uninstalled".into()); + pr.finish_with_message("uninstalled"); } Ok(()) } diff --git a/src/cli/version.rs b/src/cli/version.rs index d0f745f3f..92939ae0a 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -115,15 +115,15 @@ fn get_latest_version_call() -> Option { fn get_latest_version_call() -> Option { let timeout = Duration::from_secs(3); const URL: &str = "http://rtx.pub/VERSION"; - debug!("checking for version from {}", URL); - let client = reqwest::blocking::ClientBuilder::new() - .user_agent(format!("rtx/{}", env!("CARGO_PKG_VERSION"))) - .build() - .ok()?; + debug!("checking rtx version from {}", URL); + let client = crate::http::Client::new().ok()?; match client.get(URL).timeout(timeout).send() { Ok(res) => { if res.status().is_success() { - return res.text().ok().map(|text| text.trim().to_string()); + return res.text().ok().map(|text| { + debug!("got version {text}"); + text.trim().to_string() + }); } debug!("failed to check for version: {:#?}", res); } diff --git a/src/cmd.rs b/src/cmd.rs index cad2ba743..29d047ba1 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -1,6 +1,6 @@ use color_eyre::Result; -use std::ffi::OsString; -use std::io::{BufRead, BufReader}; +use std::ffi::{OsStr, OsString}; +use std::io::{BufRead, BufReader, Write}; use std::process::{Command, ExitStatus, Stdio}; use std::sync::mpsc::channel; use std::thread; @@ -82,57 +82,63 @@ where duct::cmd(program, args) } -pub fn run_by_line_to_pr(settings: &Settings, cmd: Command, pr: &mut ProgressReport) -> Result<()> { - run_by_line( - settings, - cmd, - |output| { - pr.error(); - if !settings.verbose && !output.trim().is_empty() { - pr.println(output); - } - }, - |line| { - if !line.trim().is_empty() { - pr.set_message(line.into()); - } - }, - |line| { - if !line.trim().is_empty() { - pr.println(line.into()); - } - }, - ) +pub struct CmdLineRunner<'a> { + cmd: Command, + settings: &'a Settings, + pr: &'a ProgressReport, + stdin: Option, } +impl<'a> CmdLineRunner<'a> { + pub fn new>( + settings: &'a Settings, + program: P, + pr: &'a ProgressReport, + ) -> Self { + let mut cmd = Command::new(program); + cmd.stdin(Stdio::null()); + cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::piped()); -pub fn run_by_line<'a, F1, F2, F3>( - settings: &Settings, - mut cmd: Command, - on_error: F1, - on_stdout: F2, - on_stderr: F3, -) -> Result<()> -where - F1: Fn(String), - F2: Fn(&str) + Send + Sync + 'a, - F3: Fn(&str) + Send + Sync, -{ - let program = cmd.get_program().to_string_lossy().to_string(); - if settings.raw { - let status = cmd.spawn()?.wait()?; - match status.success() { - true => Ok(()), - false => { - on_error(String::new()); - Err(ScriptFailed(program, Some(status)).into()) - } + Self { + cmd, + pr, + settings, + stdin: None, + } + } + + pub fn env_clear(&mut self) -> &mut Self { + self.cmd.env_clear(); + self + } + + pub fn envs(&mut self, vars: I) -> &mut Self + where + I: IntoIterator, + K: AsRef, + V: AsRef, + { + self.cmd.envs(vars); + self + } + + pub fn arg>(&mut self, arg: S) -> &mut Self { + self.cmd.arg(arg.as_ref()); + self + } + + pub fn stdin_string(&mut self, input: impl Into) -> &mut Self { + self.cmd.stdin(Stdio::piped()); + self.stdin = Some(input.into()); + self + } + + pub fn execute(mut self) -> Result<()> { + debug!("Executing command: {:?}", self.cmd); + if self.settings.raw { + return self.execute_raw(); } - } else { - let mut cp = cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()?; + let mut cp = self.cmd.spawn()?; let stdout = BufReader::new(cp.stdout.take().unwrap()); let stderr = BufReader::new(cp.stderr.take().unwrap()); let (tx, rx) = channel(); @@ -156,6 +162,12 @@ where tx.send(ChildProcessOutput::Done).unwrap(); } }); + if let Some(text) = self.stdin.take() { + let mut stdin = cp.stdin.take().unwrap(); + thread::spawn(move || { + stdin.write_all(text.as_bytes()).unwrap(); + }); + } thread::spawn(move || { let status = cp.wait().unwrap(); tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); @@ -167,11 +179,11 @@ where for line in rx { match line { ChildProcessOutput::Stdout(line) => { - on_stdout(&line); + self.on_stdout(&line); combined_output.push(line); } ChildProcessOutput::Stderr(line) => { - on_stderr(&line); + self.on_stderr(&line); combined_output.push(line); } ChildProcessOutput::ExitStatus(s) => { @@ -188,12 +200,40 @@ where let status = status.unwrap(); if !status.success() { - on_error(combined_output.join("\n")); - Err(ScriptFailed(program, Some(status)))?; + self.on_error(combined_output.join("\n"), status)?; } Ok(()) } + + fn execute_raw(mut self) -> Result<()> { + let status = self.cmd.spawn()?.wait()?; + match status.success() { + true => Ok(()), + false => self.on_error(String::new(), status), + } + } + + fn on_stdout(&self, line: &str) { + if !line.trim().is_empty() { + self.pr.set_message(line); + } + } + + fn on_stderr(&self, line: &str) { + if !line.trim().is_empty() { + self.pr.println(line); + } + } + + fn on_error(&self, output: String, status: ExitStatus) -> Result<()> { + self.pr.error(); + if !self.settings.verbose && !output.trim().is_empty() { + self.pr.println(output); + } + let program = self.cmd.get_program().to_string_lossy().to_string(); + Err(ScriptFailed(program, Some(status)))? + } } enum ChildProcessOutput { diff --git a/src/config/mod.rs b/src/config/mod.rs index 75a13b028..783feadcb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -250,16 +250,9 @@ impl Config { None } - pub fn autoupdate(&self) { - if *CI { - return; - } - self.check_for_new_version(); - } - pub fn check_for_new_version(&self) { - if !console::user_attended_stderr() || *env::RTX_HIDE_UPDATE_WARNING { - return; // not a tty so don't bother + if *CI || !console::user_attended_stderr() || *env::RTX_HIDE_UPDATE_WARNING { + return; } if let Some(latest) = cli::version::check_for_new_version(duration::WEEKLY) { warn!( diff --git a/src/env.rs b/src/env.rs index 07a0964b5..fd0ecb53a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -90,6 +90,12 @@ pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); +// python +pub static RTX_PYTHON_PATCH_URL: Lazy> = + Lazy::new(|| var("RTX_PYTHON_PATCH_URL").ok()); +pub static RTX_PYTHON_PATCHES_DIRECTORY: Lazy> = + Lazy::new(|| var_path("RTX_PYTHON_PATCHES_DIRECTORY")); + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { Yes, diff --git a/src/http.rs b/src/http.rs new file mode 100644 index 000000000..f94120c81 --- /dev/null +++ b/src/http.rs @@ -0,0 +1,20 @@ +use color_eyre::eyre::Result; +use reqwest::blocking::RequestBuilder; +use reqwest::IntoUrl; + +pub struct Client { + reqwest: reqwest::blocking::Client, +} + +impl Client { + pub fn new() -> Result { + let reqwest = reqwest::blocking::ClientBuilder::new() + .user_agent(format!("rtx/{}", env!("CARGO_PKG_VERSION"))) + .build()?; + Ok(Self { reqwest }) + } + + pub fn get(&self, url: U) -> RequestBuilder { + self.reqwest.get(url) + } +} diff --git a/src/lib.rs b/src/lib.rs index bbb1e20da..acbcae9f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ mod file; mod git; mod hash; mod hook_env; +mod http; mod lock_file; mod plugins; mod runtime_symlinks; diff --git a/src/main.rs b/src/main.rs index aa7f0c80c..4c9750655 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,7 @@ mod file; mod git; mod hash; mod hook_env; +mod http; mod lock_file; mod logger; mod plugins; diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 676685fe9..3d629493a 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -1,14 +1,14 @@ use color_eyre::eyre::{eyre, Result}; use std::path::PathBuf; -use std::process::Command; use std::time::Duration; use crate::cache::CacheManager; +use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::env::RTX_EXE; use crate::file::create_dir_all; use crate::git::Git; -use crate::{cmd, dirs}; +use crate::{cmd, dirs, env, http}; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; @@ -86,20 +86,43 @@ impl Plugin for PythonPlugin { .cloned() } + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".python-version".to_string()]) + } + fn install_version( &self, config: &Config, tv: &ToolVersion, - pr: &mut ProgressReport, + pr: &ProgressReport, ) -> Result<()> { self.install_python_build()?; if matches!(tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); } - // TODO: patch support - pr.set_message("running python-build".to_string()); - let mut cmd = Command::new(self.python_build_bin()); + pr.set_message("running python-build"); + let mut cmd = CmdLineRunner::new(&config.settings, self.python_build_bin(), pr); cmd.arg(tv.version.as_str()).arg(tv.install_path()); - cmd::run_by_line_to_pr(&config.settings, cmd, pr) + if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { + pr.set_message(format!("with patch file from: {patch_url}")); + cmd.arg("--patch"); + let http = http::Client::new()?; + let patch = http.get(patch_url).send()?.text()?; + cmd.stdin_string(patch); + } + if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { + dbg!(patches_dir); + let patch_file = patches_dir.join(format!("{}.patch", tv.version)); + if patch_file.exists() { + pr.set_message(format!("with patch file: {}", patch_file.display())); + cmd.arg("--patch"); + let contents = std::fs::read_to_string(&patch_file)?; + cmd.stdin_string(contents); + } else { + pr.warn(format!("patch file not found: {}", patch_file.display())); + } + } + cmd.execute()?; + Ok(()) } } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 868201b74..95afa6d2c 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -361,16 +361,16 @@ impl Plugin for ExternalPlugin { git.update(Some(ref_.to_string()))?; } - pr.set_message("loading plugin remote versions".into()); + pr.set_message("loading plugin remote versions"); if self.has_list_all_script() { self.list_remote_versions(&config.settings)?; } if self.has_list_alias_script() { - pr.set_message("getting plugin aliases".into()); + pr.set_message("getting plugin aliases"); self.get_aliases(&config.settings)?; } if self.has_list_legacy_filenames_script() { - pr.set_message("getting plugin legacy filenames".into()); + pr.set_message("getting plugin legacy filenames"); self.legacy_filenames(&config.settings)?; } @@ -409,7 +409,7 @@ impl Plugin for ExternalPlugin { if !self.is_installed() { return Ok(()); } - pr.set_message("uninstalling".into()); + pr.set_message("uninstalling"); let rmdir = |dir: &Path| { if !dir.exists() { @@ -533,36 +533,18 @@ impl Plugin for ExternalPlugin { &self, config: &Config, tv: &ToolVersion, - pr: &mut ProgressReport, + pr: &ProgressReport, ) -> Result<()> { let run_script = |script| { - self.script_man_for_tv(config, tv).run_by_line( - &config.settings, - script, - |output| { - pr.error(); - if !config.settings.verbose && !output.trim().is_empty() { - pr.println(output); - } - }, - |line| { - if !line.trim().is_empty() { - pr.set_message(line.into()); - } - }, - |line| { - if !line.trim().is_empty() { - pr.println(line.into()); - } - }, - ) + self.script_man_for_tv(config, tv) + .run_by_line(&config.settings, script, pr) }; if self.script_man_for_tv(config, tv).script_exists(&Download) { - pr.set_message("downloading".into()); + pr.set_message("downloading"); run_script(&Download)?; } - pr.set_message("installing".into()); + pr.set_message("installing"); run_script(&Install)?; Ok(()) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 03fda98cb..72b22c964 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -49,8 +49,9 @@ pub trait Plugin: Debug + Send + Sync { fn legacy_filenames(&self, _settings: &Settings) -> Result> { Ok(vec![]) } - fn parse_legacy_file(&self, _path: &Path, _settings: &Settings) -> Result { - unimplemented!() + fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + let contents = std::fs::read_to_string(path)?; + Ok(contents.trim().to_string()) } fn external_commands(&self) -> Result>> { Ok(vec![]) @@ -58,12 +59,8 @@ pub trait Plugin: Debug + Send + Sync { fn execute_external_command(&self, _command: &str, _args: Vec) -> Result<()> { unimplemented!() } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &mut ProgressReport, - ) -> Result<()>; + fn install_version(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) + -> Result<()>; fn uninstall_version(&self, _config: &Config, _tv: &ToolVersion) -> Result<()> { Ok(()) } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 072b14986..014a71f40 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -4,19 +4,20 @@ use std::ffi::OsString; use std::fmt; use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use std::process::{Command, Output}; +use std::process::Output; use color_eyre::eyre::{Context, Result}; use duct::Expression; use indexmap::indexmap; use once_cell::sync::Lazy; -use crate::cmd::cmd; +use crate::cmd::{cmd, CmdLineRunner}; use crate::config::Settings; use crate::errors::Error; use crate::errors::Error::ScriptFailed; use crate::file::{basename, display_path}; -use crate::{cmd, dirs, env}; +use crate::ui::progress_report::ProgressReport; +use crate::{dirs, env}; #[derive(Debug, Clone)] pub struct ScriptManager { @@ -152,22 +153,15 @@ impl ScriptManager { .with_context(|| ScriptFailed(display_path(&self.get_script_path(script)), None)) } - pub fn run_by_line<'a, F1, F2, F3>( - &'a self, + pub fn run_by_line( + &self, settings: &Settings, script: &Script, - on_error: F1, - on_stdout: F2, - on_stderr: F3, - ) -> Result<()> - where - F1: Fn(String), - F2: Fn(&str) + Send + Sync + 'a, - F3: Fn(&str) + Send + Sync, - { - let mut cmd = Command::new(self.get_script_path(script)); + pr: &ProgressReport, + ) -> Result<()> { + let mut cmd = CmdLineRunner::new(settings, self.get_script_path(script), pr); cmd.env_clear().envs(&self.env); - if let Err(e) = cmd::run_by_line(settings, cmd, on_error, on_stdout, on_stderr) { + if let Err(e) = cmd.execute() { let status = match e.downcast_ref::() { Some(ScriptFailed(_, status)) => *status, _ => None, diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 0bead47c9..0714c925c 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -65,8 +65,8 @@ mod tests { let pr = mpr.add(); pr.set_style(indicatif::ProgressStyle::with_template("").unwrap()); pr.enable_steady_tick(); - pr.finish_with_message("test".into()); - pr.println("".into()); - pr.set_message("test".into()); + pr.finish_with_message("test"); + pr.println(""); + pr.set_message("test"); } } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 62353085f..4c7a4dd12 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::time::Duration; use console::style; @@ -50,11 +51,11 @@ impl ProgressReport { } } - pub fn set_prefix(&mut self, prefix: String) { + pub fn set_prefix(&mut self, prefix: impl Into>) { match &self.pb { Some(pb) => pb.set_prefix(prefix), None => { - self.prefix = prefix; + self.prefix = prefix.into().to_string(); } } } @@ -75,16 +76,22 @@ impl ProgressReport { None => (), } } - pub fn set_message(&self, message: String) { + pub fn set_message>(&self, message: S) { match &self.pb { - Some(pb) => pb.set_message(message.replace('\r', "")), - None => eprintln!("{}{message}", self.prefix), + Some(pb) => pb.set_message(message.as_ref().replace('\r', "")), + None => eprintln!("{}{}", self.prefix, message.as_ref()), } } - pub fn println(&self, message: String) { + pub fn println>(&self, message: S) { match &self.pb { Some(pb) => pb.println(message), - None => eprintln!("{message}"), + None => eprintln!("{}", message.as_ref()), + } + } + pub fn warn>(&self, message: S) { + match &self.pb { + Some(pb) => pb.println(format!("{} {}", style("[WARN]").yellow(), message.as_ref())), + None => eprintln!("{}{}", self.prefix, message.as_ref()), } } pub fn error(&self) { @@ -105,13 +112,13 @@ impl ProgressReport { None => (), } } - pub fn finish_with_message(&self, message: String) { + pub fn finish_with_message(&self, message: impl Into>) { match &self.pb { Some(pb) => { pb.set_style(SUCCESS_TEMPLATE.clone()); - pb.finish_with_message(message) + pb.finish_with_message(message); } - None => eprintln!("{}{message}", self.prefix), + None => eprintln!("{}{}", self.prefix, message.into()), } } // pub fn clear(&self) { @@ -129,18 +136,18 @@ mod tests { #[test] fn test_progress_report() { let mut pr = ProgressReport::new(false); - pr.set_prefix("prefix".to_string()); + pr.set_prefix("prefix"); assert_eq!(pr.prefix(), "prefix"); - pr.set_message("message".to_string()); - pr.finish_with_message("message".to_string()); + pr.set_message("message"); + pr.finish_with_message("message"); } #[test] fn test_progress_report_verbose() { let mut pr = ProgressReport::new(true); - pr.set_prefix("prefix".to_string()); + pr.set_prefix("prefix"); assert_eq!(pr.prefix(), "prefix"); - pr.set_message("message".to_string()); - pr.finish_with_message("message".to_string()); + pr.set_message("message"); + pr.finish_with_message("message"); } } From 6e594704c2497eaafc62552f041268841e086eea Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 17:57:38 -0500 Subject: [PATCH 0668/1891] python core plugin venv support (#464) --- .github/workflows/rtx.yml | 2 - .rtx.toml | 2 +- README.md | 13 +++++ docs/python.md | 51 +++++++++++++++++ src/cmd.rs | 37 ++++++++---- src/config/mod.rs | 4 +- src/env.rs | 6 +- src/plugins/core/python.rs | 103 ++++++++++++++++++++++++++++++++-- src/plugins/script_manager.rs | 4 +- 9 files changed, 195 insertions(+), 27 deletions(-) create mode 100644 docs/python.md diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index fa6ca1b84..47793d4a8 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -30,7 +30,6 @@ jobs: run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" - RTX_EXPERIMENTAL_CORE_PLUGINS: "1" - uses: taiki-e/install-action@just - run: just lint - uses: taiki-e/install-action@cargo-deny @@ -58,7 +57,6 @@ jobs: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" RTX_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - RTX_EXPERIMENTAL_CORE_PLUGINS: "1" with: timeout_minutes: 20 max_attempts: 3 diff --git a/.rtx.toml b/.rtx.toml index 67ce802f5..7d38cd569 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -8,7 +8,7 @@ THIS_PROJECT = "{{config_root}}-{{env.PWD}}" nodejs = 'lts' tiny = { version = "1", foo = "bar" } golang = { version = "latest", foo = "bar" } -python = { version = "latest", virtualenv = "$HOME/.cache/venv" } +python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } [plugins] node = 'https://github.com/rtx-plugins/rtx-nodejs#main' diff --git a/README.md b/README.md index 0f01c91b8..cdd1c42c8 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ v18.15.0 - [Templates](#templates) - [[experimental] Config Environments](#experimental-config-environments) - [IDE Integration](#ide-integration) +- [[experimental] Core Plugins](#experimental-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 does `rtx activate` do?](#what-does-rtx-activate-do) @@ -1080,6 +1081,18 @@ Direnv and rtx work similarly and there should be a direnv extension that can be Alternatively, you may be able to get tighter integration with a direnv extension and using the [`use_rtx`](#direnv) direnv function. +## [experimental] Core Plugins + +If you have `experimental = true` in your settings, rtx will include some plugins built into the CLI. These are new and will improve over time. They can be easily overridden by +installing a plugin with the same name, e.g.: `rtx plugin install python`. + +You can see the core plugins with `rtx plugin ls --core`. + +* [Python](./docs/python.md) +* ~NodeJS~ - coming soon +* ~Ruby~ - coming soon +* ~Java~ - coming soon + ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. diff --git a/docs/python.md b/docs/python.md new file mode 100644 index 000000000..a677dac69 --- /dev/null +++ b/docs/python.md @@ -0,0 +1,51 @@ +# Python in rtx + +The following are instructions for using the python rtx core plugin. This is used when +the "experimental" setting is "true" and there isn't a git plugin installed named "python" + +If you want to use asdf-python or rtx-python then use `rtx plugins install python URL`. + +The code for this is inside of the rtx repository at [`./src/plugins/core/python.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/python.rs). + +## Usage + +The following installs the latest version of python-3.11.x and makes it the global +default: + +```sh-session +$ rtx install python@3.11 +$ rtx global python@3.11 +``` + +You can also use multiple versions of python at the same time: + +```sh-session +$ rtx global python@3.10 python@3.11 +$ python -V +3.10.0 +$ python3.11 -V +3.11.0 +``` + +## Default Python packages + +rtx-python can automatically install a default set of Python packages with pip right after installing a Python version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists one package per line, for example: + +``` +ansible +pipenv +``` + +You can specify a non-default location of this file by setting a `RTX_PYTHON_DEFAULT_PACKAGES_FILE` variable. + +## [experimental] Automatic virtualenv creation/activation + +Python comes with virtualenv support built in, use it with `.rtx.toml` configuration like +the following: + +```toml +[tools] +python = {version="3.11", virtualenv=".venv"} # relative to this file's directory +python = {version="3.11", virtualenv="/root/.venv"} # can be absolute +python = {version="3.11", virtualenv="{{env.HOME}}/.cache/venv/myproj"} # can use templates +``` diff --git a/src/cmd.rs b/src/cmd.rs index 29d047ba1..bdaafc2f8 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -85,15 +85,11 @@ where pub struct CmdLineRunner<'a> { cmd: Command, settings: &'a Settings, - pr: &'a ProgressReport, + pr: Option<&'a ProgressReport>, stdin: Option, } impl<'a> CmdLineRunner<'a> { - pub fn new>( - settings: &'a Settings, - program: P, - pr: &'a ProgressReport, - ) -> Self { + pub fn new>(settings: &'a Settings, program: P) -> Self { let mut cmd = Command::new(program); cmd.stdin(Stdio::null()); cmd.stdout(Stdio::piped()); @@ -101,8 +97,8 @@ impl<'a> CmdLineRunner<'a> { Self { cmd, - pr, settings, + pr: None, stdin: None, } } @@ -127,6 +123,11 @@ impl<'a> CmdLineRunner<'a> { self } + pub fn with_pr(&mut self, pr: &'a ProgressReport) -> &mut Self { + self.pr = Some(pr); + self + } + pub fn stdin_string(&mut self, input: impl Into) -> &mut Self { self.cmd.stdin(Stdio::piped()); self.stdin = Some(input.into()); @@ -216,20 +217,32 @@ impl<'a> CmdLineRunner<'a> { fn on_stdout(&self, line: &str) { if !line.trim().is_empty() { - self.pr.set_message(line); + if let Some(pr) = self.pr { + pr.println(line) + } } } fn on_stderr(&self, line: &str) { if !line.trim().is_empty() { - self.pr.println(line); + match self.pr { + Some(pr) => pr.error(), + None => eprintln!("{}", line), + } } } fn on_error(&self, output: String, status: ExitStatus) -> Result<()> { - self.pr.error(); - if !self.settings.verbose && !output.trim().is_empty() { - self.pr.println(output); + match self.pr { + Some(pr) => { + pr.error(); + if !self.settings.verbose && !output.trim().is_empty() { + pr.println(output); + } + } + None => { + eprintln!("{}", output); + } } let program = self.cmd.get_program().to_string_lossy().to_string(); Err(ScriptFailed(program, Some(status)))? diff --git a/src/config/mod.rs b/src/config/mod.rs index 783feadcb..7733d39bb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,7 +17,7 @@ use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; -use crate::env::{CI, RTX_EXPERIMENTAL_CORE_PLUGINS}; +use crate::env::CI; use crate::plugins::core::PythonPlugin; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; @@ -309,7 +309,7 @@ fn load_rtxrc() -> Result { fn load_tools(settings: &Settings) -> Result { let mut tools = ToolMap::new(); - if *RTX_EXPERIMENTAL_CORE_PLUGINS { + if settings.experimental { tools.extend(load_core_tools(settings)); } let plugins = Tool::list(settings)? diff --git a/src/env.rs b/src/env.rs index fd0ecb53a..83dbbce01 100644 --- a/src/env.rs +++ b/src/env.rs @@ -38,8 +38,6 @@ pub static RTX_ENV: Lazy> = Lazy::new(|| var("RTX_ENV").ok()); pub static RTX_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("RTX_CONFIG_FILE")); pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); pub static RTX_EXE: Lazy = Lazy::new(|| current_exe().unwrap_or_else(|_| "rtx".into())); -pub static RTX_EXPERIMENTAL_CORE_PLUGINS: Lazy = - Lazy::new(|| var_is_true("RTX_EXPERIMENTAL_CORE_PLUGINS")); pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); pub static RTX_MISSING_RUNTIME_BEHAVIOR: Lazy> = @@ -95,6 +93,10 @@ pub static RTX_PYTHON_PATCH_URL: Lazy> = Lazy::new(|| var("RTX_PYTHON_PATCH_URL").ok()); pub static RTX_PYTHON_PATCHES_DIRECTORY: Lazy> = Lazy::new(|| var_path("RTX_PYTHON_PATCHES_DIRECTORY")); +pub static RTX_PYTHON_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("RTX_PYTHON_DEFAULT_PACKAGES_FILE") + .unwrap_or_else(|| HOME.join(".default-python-packages")) +}); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 3d629493a..40e4db47e 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -1,18 +1,19 @@ -use color_eyre::eyre::{eyre, Result}; -use std::path::PathBuf; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; use std::time::Duration; +use color_eyre::eyre::{eyre, Result}; + use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::env::RTX_EXE; use crate::file::create_dir_all; use crate::git::Git; -use crate::{cmd, dirs, env, http}; - use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; +use crate::{cmd, dirs, env, file, http}; #[derive(Debug)] pub struct PythonPlugin { @@ -77,6 +78,72 @@ impl PythonPlugin { let output = cmd!(self.python_build_bin(), "--definitions").read()?; Ok(output.split('\n').map(|s| s.to_string()).collect()) } + + fn python_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/python") + } + + fn pip_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/pip") + } + + fn install_default_packages( + &self, + settings: &Settings, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + let body = + std::fs::read_to_string(&*env::RTX_PYTHON_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + for package in body.lines() { + let package = package.trim(); + if package.is_empty() { + continue; + } + pr.set_message(format!("installing default package: {}", package)); + let pip = self.pip_path(tv); + let mut cmd = CmdLineRunner::new(settings, pip); + cmd.with_pr(pr).arg("install").arg(package); + cmd.execute()?; + } + Ok(()) + } + + fn get_virtualenv( + &self, + config: &Config, + tv: &ToolVersion, + pr: Option<&ProgressReport>, + ) -> Result> { + if let Some(virtualenv) = tv.opts.get("virtualenv") { + let mut virtualenv: PathBuf = file::replace_path(Path::new(virtualenv)); + if !virtualenv.is_absolute() { + // TODO: use the path of the config file that specified python, not the top one like this + if let Some(project_root) = &config.project_root { + virtualenv = project_root.join(virtualenv); + } + } + if !virtualenv.exists() || !self.check_venv_python(&virtualenv, tv)? { + debug!("setting up virtualenv at: {}", virtualenv.display()); + let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)); + cmd.arg("-m").arg("venv").arg("--clear").arg(&virtualenv); + if let Some(pr) = pr { + cmd.with_pr(pr); + } + cmd.execute()?; + } + Ok(Some(virtualenv)) + } else { + Ok(None) + } + } + + fn check_venv_python(&self, virtualenv: &Path, tv: &ToolVersion) -> Result { + let symlink = virtualenv.join("bin/python"); + let target = tv.install_path().join("bin/python"); + let symlink_target = symlink.read_link().unwrap_or_default(); + Ok(symlink_target == target) + } } impl Plugin for PythonPlugin { @@ -101,8 +168,10 @@ impl Plugin for PythonPlugin { return Err(eyre!("Ref versions not supported for python")); } pr.set_message("running python-build"); - let mut cmd = CmdLineRunner::new(&config.settings, self.python_build_bin(), pr); - cmd.arg(tv.version.as_str()).arg(tv.install_path()); + let mut cmd = CmdLineRunner::new(&config.settings, self.python_build_bin()); + cmd.with_pr(pr) + .arg(tv.version.as_str()) + .arg(tv.install_path()); if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { pr.set_message(format!("with patch file from: {patch_url}")); cmd.arg("--patch"); @@ -123,6 +192,28 @@ impl Plugin for PythonPlugin { } } cmd.execute()?; + self.get_virtualenv(config, tv, Some(pr))?; + self.install_default_packages(&config.settings, tv, pr)?; Ok(()) } + + fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + if let Some(virtualenv) = self.get_virtualenv(config, tv, None)? { + Ok(vec![virtualenv.join("bin"), tv.install_path().join("bin")]) + } else { + Ok(vec![tv.install_path().join("bin")]) + } + } + + fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + if let Some(virtualenv) = self.get_virtualenv(config, tv, None)? { + let hm = HashMap::from([( + "VIRTUAL_ENV".to_string(), + virtualenv.to_string_lossy().to_string(), + )]); + Ok(hm) + } else { + Ok(HashMap::new()) + } + } } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 014a71f40..f9ac84d55 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -159,8 +159,8 @@ impl ScriptManager { script: &Script, pr: &ProgressReport, ) -> Result<()> { - let mut cmd = CmdLineRunner::new(settings, self.get_script_path(script), pr); - cmd.env_clear().envs(&self.env); + let mut cmd = CmdLineRunner::new(settings, self.get_script_path(script)); + cmd.with_pr(pr).env_clear().envs(&self.env); if let Err(e) = cmd.execute() { let status = match e.downcast_ref::() { Some(ScriptFailed(_, status)) => *status, From e079202c9f6ada012b1e0e9af1a4665c47d379b2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 18:00:31 -0500 Subject: [PATCH 0669/1891] Update python.md --- docs/python.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/python.md b/docs/python.md index a677dac69..fa540e0a8 100644 --- a/docs/python.md +++ b/docs/python.md @@ -3,7 +3,7 @@ The following are instructions for using the python rtx core plugin. This is used when the "experimental" setting is "true" and there isn't a git plugin installed named "python" -If you want to use asdf-python or rtx-python then use `rtx plugins install python URL`. +If you want to use [asdf-python](https://github.com/asdf-community/asdf-python) or [rtx-python](https://github.com/rtx-plugins/rtx-python) then use `rtx plugins install python URL`. The code for this is inside of the rtx repository at [`./src/plugins/core/python.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/python.rs). From ef91f0f7d5a0b2d39fb5ed47ab97ccea90c6e72a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 18:01:46 -0500 Subject: [PATCH 0670/1891] chore: Release --- Cargo.lock | 16 +++++++++++++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ead25acb9..d060f13ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -429,6 +429,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ctor" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" +dependencies = [ + "quote", + "syn 2.0.13", +] + [[package]] name = "ctrlc" version = "3.2.5" @@ -1391,7 +1401,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "ctor", + "ctor 0.1.26", "diff", "output_vt100", "yansi", @@ -1576,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.28.0" +version = "1.28.1" dependencies = [ "base64", "built", @@ -1586,7 +1596,7 @@ dependencies = [ "color-eyre", "color-print", "console", - "ctor", + "ctor 0.2.0", "ctrlc", "dialoguer", "dirs-next", diff --git a/Cargo.toml b/Cargo.toml index c0b7380a1..875458d84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.28.0" +version = "1.28.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index cdd1c42c8..51f95fcb4 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.28.0 +rtx 1.28.1 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -328,7 +328,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.28.0/rtx-v1.28.0-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.28.1/rtx-v1.28.1-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ffac6b6d5..1b229dd94 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.28.0"; + version = "1.28.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index e90dcdbcc..9910efec8 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.28.0" +.TH rtx 1 "rtx 1.28.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.28.0 +v1.28.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e0ce3015b..4acc9ae06 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.28.0 +Version: 1.28.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 9328e96390b212ad144f1dab989e83c6ede0df6f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 18:34:44 -0500 Subject: [PATCH 0671/1891] docs --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 51f95fcb4..6d542526b 100644 --- a/README.md +++ b/README.md @@ -735,9 +735,11 @@ Set to something other than `.rtx.toml` to have rtx look for `.rtx.toml` config #### [experimental] `RTX_ENV` -Enables an environment-specific config file such as `.rtx.development.toml`. This is useful -for setting different versions for different environments. See -[Config Environments](#experimental-config-environments) for more on how to use this. +Enables environment-specific config files such as `.rtx.development.toml`. +Use this for different env vars or different tool versions in +development/staging/production environments. See +[Config Environments](#experimental-config-environments) for more on how +to use this feature. #### `RTX_${PLUGIN}_VERSION` From 5ad9a8521e60352eb1103c1628b7db54a80cecf7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 18:38:47 -0500 Subject: [PATCH 0672/1891] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d542526b..b61e96151 100644 --- a/README.md +++ b/README.md @@ -1323,8 +1323,12 @@ Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): ```yaml -- uses: jdxcode/rtx-action@v1 -- run: node -v # will be the node version from `.tool-versions` +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: jdxcode/rtx-action@v1 + - run: node -v # will be the node version from `.rtx.toml`/`.tool-versions` ``` ## Shims From ec7e16aed754b8d0d657f7765d3fa4008e7335a1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:03:34 -0500 Subject: [PATCH 0673/1891] rename example rtx.toml plugin --- .rtx.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rtx.toml b/.rtx.toml index 7d38cd569..03bd1eaa8 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -11,7 +11,7 @@ golang = { version = "latest", foo = "bar" } python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } [plugins] -node = 'https://github.com/rtx-plugins/rtx-nodejs#main' +nnnn = 'https://github.com/rtx-plugins/rtx-nodejs#main' [alias.tiny] abc = '1' From 3698966863be5485b6049869f34a2b95ea24e2ad Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 20:29:47 -0500 Subject: [PATCH 0674/1891] set json schema --- .rtx.local.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.rtx.local.toml b/.rtx.local.toml index 9fce2c886..7e0caf504 100644 --- a/.rtx.local.toml +++ b/.rtx.local.toml @@ -1,2 +1,3 @@ +#:schema ./schema/rtx.json [env] FOO=".rtx.local.toml" From 04a517d8dc065bc3a8f94c0c5fc00aaa73f81c54 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 20:43:10 -0500 Subject: [PATCH 0675/1891] fix fetching particular sha --- src/git.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/git.rs b/src/git.rs index 6e91b1ab3..4678cf591 100644 --- a/src/git.rs +++ b/src/git.rs @@ -36,7 +36,7 @@ impl Git { pub fn update(&self, gitref: Option) -> Result<(String, String)> { let gitref = gitref.map_or_else(|| self.remote_default_branch(), Ok)?; debug!("updating {} to {}", self.dir.display(), gitref); - cmd!( + if let Err(err) = cmd!( "git", "-C", &self.dir, @@ -46,7 +46,10 @@ impl Git { "origin", format!("{}:{}", gitref, gitref), ) - .run()?; + .run() + { + debug!("failed to fetch: {:#}", err); + } let prev_rev = self.current_sha()?; cmd!( "git", From 8ca30bf7074b6cc36b1d57263aadfa31dd796367 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:04:05 -0500 Subject: [PATCH 0676/1891] bug: fix config/data dirs --- src/env.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/env.rs b/src/env.rs index 83dbbce01..944490789 100644 --- a/src/env.rs +++ b/src/env.rs @@ -18,9 +18,9 @@ pub static PWD: Lazy = Lazy::new(|| current_dir().unwrap_or_else(|_| Pa pub static XDG_CACHE_HOME: Lazy = Lazy::new(|| dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache"))); pub static XDG_DATA_HOME: Lazy = - Lazy::new(|| dirs_next::data_dir().unwrap_or_else(|| HOME.join(".local/share"))); + Lazy::new(|| var_path("XDG_DATA_HOME").unwrap_or_else(|| HOME.join(".local/share"))); pub static XDG_CONFIG_HOME: Lazy = - Lazy::new(|| dirs_next::config_dir().unwrap_or_else(|| HOME.join(".config"))); + Lazy::new(|| var_path("XDG_CONFIG_HOME").unwrap_or_else(|| HOME.join(".config"))); pub static RTX_CACHE_DIR: Lazy = Lazy::new(|| var_path("RTX_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("rtx"))); pub static RTX_CONFIG_DIR: Lazy = From 72330ccb5c2d4ed2576b5909a19aa68586913fec Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:15:49 -0500 Subject: [PATCH 0677/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d060f13ef..d6eef3eee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1586,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.28.1" +version = "1.28.2" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 875458d84..7d001a3c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.28.1" +version = "1.28.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index b61e96151..8d9d787f2 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.28.1 +rtx 1.28.2 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -328,7 +328,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.28.1/rtx-v1.28.1-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.28.2/rtx-v1.28.2-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 1b229dd94..dd37a4060 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.28.1"; + version = "1.28.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 9910efec8..82ff6e655 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.28.1" +.TH rtx 1 "rtx 1.28.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.28.1 +v1.28.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 4acc9ae06..a0da1e1f9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.28.1 +Version: 1.28.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From fd5faf7fefd409f52e853c2d163bf5d680c4ebf6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:25:32 -0500 Subject: [PATCH 0678/1891] fix debug output on CmdLineRunner --- src/cmd.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/cmd.rs b/src/cmd.rs index bdaafc2f8..8916e5b1c 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -135,7 +135,7 @@ impl<'a> CmdLineRunner<'a> { } pub fn execute(mut self) -> Result<()> { - debug!("Executing command: {:?}", self.cmd); + debug!("$ {} {}", self.get_program(), self.get_args().join(" ")); if self.settings.raw { return self.execute_raw(); } @@ -247,6 +247,17 @@ impl<'a> CmdLineRunner<'a> { let program = self.cmd.get_program().to_string_lossy().to_string(); Err(ScriptFailed(program, Some(status)))? } + + fn get_program(&self) -> String { + self.cmd.get_program().to_string_lossy().to_string() + } + + fn get_args(&self) -> Vec { + self.cmd + .get_args() + .map(|s| s.to_string_lossy().to_string()) + .collect::>() + } } enum ChildProcessOutput { From 3188d0f213d130597a012a79e5f69a41da86c511 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:33:17 -0500 Subject: [PATCH 0679/1891] added ability to set env vars to "false" to clear them Fixes #404 --- src/config/config_file/mod.rs | 3 +++ src/config/config_file/rtx_toml.rs | 28 ++++++++++++++++++++++++---- src/config/mod.rs | 4 ++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index b80f76bb7..34393d639 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -35,6 +35,9 @@ pub trait ConfigFile: Debug + Display + Send + Sync { fn get_path(&self) -> &Path; fn plugins(&self) -> HashMap; fn env(&self) -> HashMap; + fn env_remove(&self) -> Vec { + vec![] + } fn path_dirs(&self) -> Vec; fn remove_plugin(&mut self, plugin_name: &PluginName); fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 577f047d1..8a099aac7 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -30,6 +30,7 @@ pub struct RtxToml { toolset: Toolset, env_file: Option, env: HashMap, + env_remove: Vec, path_dirs: Vec, settings: SettingsBuilder, alias: AliasMap, @@ -111,7 +112,7 @@ impl RtxToml { Ok(()) } - fn parse_env(&mut self, k: &str, v: &Item) -> Result<()> { + fn parse_env(&mut self, key: &str, v: &Item) -> Result<()> { self.trust_check()?; let mut v = v.clone(); if let Some(table) = v.as_table_like_mut() { @@ -119,9 +120,24 @@ impl RtxToml { return Err(eyre!("use 'env_path' instead of 'env.PATH'")); } } - for (k, v) in self.parse_hashmap(k, &v)? { - let v = self.parse_template(&k, &v)?; - self.env.insert(k, v); + match v.as_table_like() { + Some(table) => { + for (k, v) in table.iter() { + let key = format!("{}.{}", key, k); + let k = self.parse_template(&key, k)?; + if let Some(v) = v.as_str() { + let v = self.parse_template(&key, v)?; + self.env.insert(k, v); + } else if let Some(v) = v.as_bool() { + if !v { + self.env_remove.push(k); + } + } else { + parse_error!(key, v, "string or bool")?; + } + } + } + _ => parse_error!(key, v, "table")?, } Ok(()) } @@ -618,6 +634,10 @@ impl ConfigFile for RtxToml { self.env.clone() } + fn env_remove(&self) -> Vec { + self.env_remove.clone() + } + fn path_dirs(&self) -> Vec { self.path_dirs.clone() } diff --git a/src/config/mod.rs b/src/config/mod.rs index 7733d39bb..033d746b8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -448,6 +448,10 @@ fn load_env(config_files: &ConfigMap) -> BTreeMap { let mut env = BTreeMap::new(); for cf in config_files.values().rev() { env.extend(cf.env()); + for k in cf.env_remove() { + // remove values set to "false" + env.remove(&k); + } } env } From 41d8a6af392abee95f7cb0615f23770263b7fb55 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:36:40 -0500 Subject: [PATCH 0680/1891] docs --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 8d9d787f2..0fcce3d6e 100644 --- a/README.md +++ b/README.md @@ -696,6 +696,11 @@ env_file = '.env' _Note: `env_file` goes at the top of the file, above `[env]`._ +```toml +[env] +NODE_ENV = false # unset a previously set NODE_ENV +``` + ### Environment variables rtx can also be configured via environment variables. The following options are available: From 357c10a8fe0abb023662ff1c581da86faf7eb2fb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:48:01 -0500 Subject: [PATCH 0681/1891] default to warn instead of prompt for missing runtimes I think this is a better default and it will be more compatible with my plans for `rtx upgrade` --- README.md | 2 +- src/cmd.rs | 4 ++-- src/config/settings.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0fcce3d6e..4a22bc77b 100644 --- a/README.md +++ b/README.md @@ -573,7 +573,7 @@ rtx can be configured in `~/.config/rtx/config.toml`. The following options are ```toml [settings] # whether to prompt to install plugins and runtimes if they're not already installed -missing_runtime_behavior = 'prompt' # other options: 'ignore', 'warn', 'prompt', 'autoinstall' +missing_runtime_behavior = 'warn' # other options: 'ignore', 'warn', 'prompt', 'autoinstall' # plugins can read the versions files used by other version managers (if enabled by the plugin) # for example, .nvmrc in the case of nodejs's nvm diff --git a/src/cmd.rs b/src/cmd.rs index 8916e5b1c..691d4ef36 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -218,7 +218,7 @@ impl<'a> CmdLineRunner<'a> { fn on_stdout(&self, line: &str) { if !line.trim().is_empty() { if let Some(pr) = self.pr { - pr.println(line) + pr.set_message(line) } } } @@ -226,7 +226,7 @@ impl<'a> CmdLineRunner<'a> { fn on_stderr(&self, line: &str) { if !line.trim().is_empty() { match self.pr { - Some(pr) => pr.error(), + Some(pr) => pr.println(line), None => eprintln!("{}", line), } } diff --git a/src/config/settings.rs b/src/config/settings.rs index cbc197e68..c737c61f4 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -30,7 +30,7 @@ impl Default for Settings { fn default() -> Self { Self { experimental: *RTX_EXPERIMENTAL, - missing_runtime_behavior: MissingRuntimeBehavior::Prompt, + missing_runtime_behavior: MissingRuntimeBehavior::Warn, always_keep_download: false, legacy_version_file: true, plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), From f49f2ce3f0b626dc2340cb71d3ef087dc92fb5cb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 21:54:53 -0500 Subject: [PATCH 0682/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6eef3eee..5ee9ffe6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1586,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.28.2" +version = "1.28.3" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 7d001a3c8..3af6d4990 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.28.2" +version = "1.28.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 4a22bc77b..96c1fff9a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.28.2 +rtx 1.28.3 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -328,7 +328,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.28.2/rtx-v1.28.2-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.28.3/rtx-v1.28.3-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index dd37a4060..22c5d1bcf 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.28.2"; + version = "1.28.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 82ff6e655..d380b1fbd 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.28.2" +.TH rtx 1 "rtx 1.28.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.28.2 +v1.28.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a0da1e1f9..c43235073 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.28.2 +Version: 1.28.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 0417a53c112a9f5b2538861c1674efe2c086872c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Apr 2023 22:12:17 -0500 Subject: [PATCH 0683/1891] added trusted_config_paths to json schema --- schema/rtx.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/schema/rtx.json b/schema/rtx.json index dc5b6acd8..15f509045 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -150,6 +150,14 @@ "description": "disables built-in shorthands", "type": "boolean" }, + "trusted_config_paths": { + "description": "config files with these prefixes will be trusted by default", + "type": "array", + "items": { + "description": "a path to add to PATH", + "type": "string" + } + }, "experimental": { "description": "enable experimental features", "type": "boolean" From fe8aa605e3337597d0a4f79ec04c1f3bd0341ae3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 10 Apr 2023 14:46:42 -0500 Subject: [PATCH 0684/1891] add -n alias for --dry-run --- src/cli/prune.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 152abd928..9cd44b156 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -25,7 +25,7 @@ pub struct Prune { pub plugins: Option>, /// Do not actually delete anything - #[clap(long)] + #[clap(long, short_alias = 'n')] pub dry_run: bool, } From 25c1a50612c20dc73f23e588a73c99a792660aaf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 10 Apr 2023 20:06:53 -0500 Subject: [PATCH 0685/1891] bug: fix bug with uninstalling (#467) this was not working if you did not specify the version --- README.md | 10 ++++++++++ e2e/test_uninstall | 8 ++++++++ justfile | 2 +- src/cli/ls.rs | 6 +++++- src/cli/uninstall.rs | 22 ++++++++++++++-------- 5 files changed, 38 insertions(+), 10 deletions(-) create mode 100755 e2e/test_uninstall diff --git a/README.md b/README.md index 96c1fff9a..497c654f8 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ v18.15.0 - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) + - [How do I disable/force CLI color output?](#how-do-i-disableforce-cli-color-output) - [Is rtx secure?](#is-rtx-secure) - [Comparison to asdf](#comparison-to-asdf) - [Performance](#performance) @@ -1240,6 +1241,15 @@ This can also be useful if you need to use a runtime right away in an rc file. T of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. +### How do I disable/force CLI color output? + +rtx uses [console.rs](https://docs.rs/console/latest/console/fn.colors_enabled.html) which +honors the [clicolors spec](https://bixense.com/clicolors/): + +* `CLICOLOR != 0`: ANSI colors are supported and should be used when the program isn’t piped. +* `CLICOLOR == 0`: Don’t output ANSI color escape codes. +* `CLICOLOR_FORCE != 0`: ANSI colors should be enabled no matter what. + ### Is rtx secure? Not as much as it should be, though currently a bit more secure than asdf. Work will happen in this area as secure diff --git a/e2e/test_uninstall b/e2e/test_uninstall new file mode 100755 index 000000000..f2fbb5efe --- /dev/null +++ b/e2e/test_uninstall @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +rtx i +rtx uninstall tiny +export CLICOLOR=0 +assert_contains "rtx ls" "3.1.0 (missing)" diff --git a/justfile b/justfile index 5b21e4521..1501cbdff 100644 --- a/justfile +++ b/justfile @@ -32,7 +32,7 @@ test-unit *args: # runs the E2E tests in ./e2e # specify a test name to run a single test -test-e2e TEST=("all"): +test-e2e TEST=("all"): build #!/usr/bin/env bash set -euo pipefail if [ "{{ TEST }}" = all ]; then diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 4235a7918..37bca3191 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -265,7 +265,11 @@ impl Display for VersionStatus { VersionStatus::Missing(version) => write!( f, "{} {}", - style(version).strikethrough().red(), + if console::colors_enabled() { + style(version).strikethrough().red().to_string() + } else { + version.to_string() + }, style("(missing)").red() ), } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 60aebd610..6abe7d89e 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -5,6 +5,7 @@ use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; /// Removes runtime versions @@ -17,20 +18,25 @@ pub struct Uninstall { } impl Command for Uninstall { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let runtimes = RuntimeArg::double_runtime_condition(&self.runtime); let tool_versions = runtimes .iter() .map(|a| { - let plugin = match config.tools.get(&a.plugin) { - Some(plugin) => plugin, - None => todo!(), - }; + let tool = config.get_or_create_tool(&a.plugin); let tv = match &a.tvr { - Some(tvr) => tvr.resolve(&config, plugin, Default::default(), false)?, - None => todo!(), + Some(tvr) => tvr.resolve(&config, &tool, Default::default(), false)?, + None => { + let ts = ToolsetBuilder::new().build(&mut config)?; + let tv = ts + .versions + .get(&a.plugin) + .and_then(|v| v.versions.first()) + .expect("no version found"); + tv.clone() + } }; - Ok((plugin, tv)) + Ok((tool, tv)) }) .collect::>>()?; From 5b5a3c3f9e43847ae27737f7e8c3d869524f991f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 10 Apr 2023 20:29:24 -0500 Subject: [PATCH 0686/1891] remove default_packages example this is not yet implemented, and we may not actually get around to arrays --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 497c654f8..c6fb82dec 100644 --- a/README.md +++ b/README.md @@ -638,9 +638,7 @@ nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] # send arbitrary options to the plugin, passed as: # RTX_TOOL_OPTS__VENV=.venv -# RTX_TOOL_OPTS__DEFAULT_PACKAGES__0=ansible -# RTX_TOOL_OPTS__DEFAULT_PACKAGES__1=pipenv -python = {version='3.10', virtualenv='.venv', default_packages=['ansible', 'pipenv']} +python = {version='3.10', virtualenv='.venv'} [plugins] # specify a custom repo url From 7d5baabc4c1f48ccb2c003f921ecde901ddd1e4b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:01:03 -0500 Subject: [PATCH 0687/1891] bug: fixed bug with partial installs (#468) Fixes #465 --- src/toolset/tool_version.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 45984bc53..d97027057 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -9,7 +9,6 @@ use crate::config::Config; use crate::dirs; use crate::hash::hash_to_str; use crate::plugins::PluginName; -use crate::runtime_symlinks::is_runtime_symlink; use crate::tool::Tool; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; @@ -108,14 +107,14 @@ impl ToolVersion { let build = |v| Ok(Self::new(tool, request.clone(), opts.clone(), v)); - let existing_path = dirs::INSTALLS.join(&tool.name).join(&v); - if existing_path.exists() && !is_runtime_symlink(&existing_path) { - // if the version is already installed, no need to fetch all the remote versions - return build(v); - } if !tool.is_installed() { return build(v); } + let existing = build(v.clone())?; + if tool.is_version_installed(&existing) { + // if the version is already installed, no need to fetch all the remote versions + return Ok(existing); + } if v == "latest" { if !latest_versions { From 3065d3aca3fd191a8e06d75fef22a5d0e029a954 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:54:25 -0500 Subject: [PATCH 0688/1891] improve error message on missing env_file (#473) This could probably be better still, but it is an improvement. Fixes #472 --- src/config/config_file/rtx_toml.rs | 10 +++++++++- src/config/mod.rs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 8a099aac7..548ee7ba5 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -101,7 +101,15 @@ impl RtxToml { match v.as_str() { Some(filename) => { let path = self.path.parent().unwrap().join(filename); - for item in dotenvy::from_path_iter(&path)? { + let dotenv = match dotenvy::from_path_iter(&path) { + Ok(dotenv) => dotenv, + Err(e) => Err(eyre!( + "failed to parse dotenv file: {}\n{:#}", + path.display(), + e + ))?, + }; + for item in dotenv { let (k, v) = item?; self.env.insert(k, v); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 033d746b8..dfa8b354c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -420,7 +420,7 @@ fn load_all_config_files( // need to parse this config file None => match parse_config_file(&f, settings, legacy_filenames, tools) { Ok(cf) => Ok((f, cf)), - Err(err) => Err(eyre!("error parsing: {} {:#}", f.display(), err)), + Err(err) => Err(eyre!("error reading config: {}\n{:#}", f.display(), err)), }, }) .collect::>>() From 84c276295b434c1ecfe4366f37fb13864051e57d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 11 Apr 2023 21:54:42 -0500 Subject: [PATCH 0689/1891] core plugin: nodejs (#474) --- .node-version | 2 +- .rtx.toml | 2 +- README.md | 2 +- docs/nodejs.md | 90 ++++++++ e2e/test_nodejs | 10 + e2e/test_shell | 11 +- e2e/test_system | 12 +- ...tx__cli__alias__set__tests__alias_set.snap | 9 + ...cli__alias__unset__tests__alias_unset.snap | 16 ++ ...__alias__unset__tests__settings_unset.snap | 7 - src/cli/alias/unset.rs | 2 +- src/cmd.rs | 8 + src/config/mod.rs | 16 +- src/env.rs | 17 ++ src/plugins/core/mod.rs | 2 + src/plugins/core/nodejs.rs | 194 ++++++++++++++++++ src/plugins/core/python.rs | 4 + src/plugins/external_plugin.rs | 4 + src/plugins/mod.rs | 1 + 19 files changed, 372 insertions(+), 37 deletions(-) create mode 100644 docs/nodejs.md create mode 100755 e2e/test_nodejs create mode 100644 src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap delete mode 100644 src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap create mode 100644 src/plugins/core/nodejs.rs diff --git a/.node-version b/.node-version index aac58983e..a77793ecc 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -17.0.0 +lts/hydrogen diff --git a/.rtx.toml b/.rtx.toml index 03bd1eaa8..5fd9e2f52 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -5,7 +5,7 @@ FOO = "bar" THIS_PROJECT = "{{config_root}}-{{env.PWD}}" [tools] -nodejs = 'lts' +#nodejs = 'lts' tiny = { version = "1", foo = "bar" } golang = { version = "latest", foo = "bar" } python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } diff --git a/README.md b/README.md index c6fb82dec..cfa7d8fb0 100644 --- a/README.md +++ b/README.md @@ -1095,7 +1095,7 @@ installing a plugin with the same name, e.g.: `rtx plugin install python`. You can see the core plugins with `rtx plugin ls --core`. * [Python](./docs/python.md) -* ~NodeJS~ - coming soon +* [NodeJS](./docs/nodejs.md) * ~Ruby~ - coming soon * ~Java~ - coming soon diff --git a/docs/nodejs.md b/docs/nodejs.md new file mode 100644 index 000000000..6d518feaa --- /dev/null +++ b/docs/nodejs.md @@ -0,0 +1,90 @@ +# NodeJS in rtx + +The following are instructions for using the nodejs rtx core plugin. This is used when +the "experimental" setting is "true" and there isn't a git plugin installed named "nodejs" + +If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) or [rtx-nodejs](https://github.com/rtx-plugins/rtx-nodejs) then use `rtx plugins install nodejs URL`. + +The code for this is inside of the rtx repository at [`./src/plugins/core/nodejs.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/nodejs.rs). + +## Usage + +The following installs the latest version of nodejs-18.x and makes it the global +default: + +```sh-session +$ rtx install nodejs@18 +$ rtx global nodejs@18 +``` + +Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. + + +```sh-session +$ rtx global nodejs@16 nodejs@18 +$ nodejs -V +16.0.0 +$ nodejs.11 -V +18.0.0 +``` + +## Configuration + +`node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-nodejs` has a few extra configuration variables: + +- `RTX_NODEJS_VERBOSE_INSTALL`: Enables verbose output for downloading and building. +- `RTX_NODEJS_FORCE_COMPILE`: Forces compilation from source instead of preferring pre-compiled binaries +- `RTX_NODEJS_CONCURRENCY`: How many jobs should be used in compilation. Defaults to half the computer cores +- `RTX_NODEJS_DEFAULT_PACKAGES_FILE`: location of default packages file, defaults to `$HOME/.default-nodejs-packages` +- `NODEJS_ORG_MIRROR`: (Legacy) overrides the default mirror used for downloading the distibutions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var + +## Default NodeJS packages + +rtx-nodejs can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-nodejs-packages` file that lists one package per line, for example: + +``` +lodash +request +express +``` + +You can specify a non-default location of this file by setting a `RTX_NODEJS_DEFAULT_PACKAGES_FILE` variable. + +## `.nvmrc` and `.node-version` support + +rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. To ease migration, you can have also have it read an existing `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `nodejs` isn't defined in `.tool-versions`/`.rtx.toml`. + + +## Running the wrapped node-build command + +We provide a command for running the installed `node-build` command: + +```bash +rtx nodejs nodebuild --version +``` + +### node-build advanced variations + +`node-build` has some additional variations aside from the versions listed in `rtx ls-remote +nodejs` (chakracore/graalvm branches and some others). As of now, we weakly support these variations. In the sense that they are available for install and can be used in a `.tool-versions` file, but we don't list them as installation candidates nor give them full attention. + +Some of them will work out of the box, and some will need a bit of investigation to get them built. We are planning in providing better support for these variations in the future. + +To list all the available variations run: + +```bash +rtx nodejs nodebuild --definitions +``` + +_Note that this command only lists the current `node-build` definitions. You might want to [update the local `node-build` repository](#updating-node-build-definitions) before listing them._ + +### Manually updating node-build definitions + +Every new node version needs to have a definition file in the `node-build` repository. +`rtx-nodejs` already tries to update `node-build` on every new version installation, but if you +want to update `node-build` manually for some reason you can clear the cache and list the versions: + +```bash +rtx cache clean +rtx ls-remote nodejs +``` diff --git a/e2e/test_nodejs b/e2e/test_nodejs new file mode 100755 index 000000000..c1fd33a19 --- /dev/null +++ b/e2e/test_nodejs @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +export RTX_EXPERIMENTAL=1 +rtx plugin uninstall nodejs +rtx i nodejs nodejs@lts/hydrogen +assert_contains "rtx x nodejs@lts/hydrogen -- node --version" "v18." +assert "rtx x -- node --version" "v18.0.0" +assert_contains "rtx nodejs nodebuild --version" "node-build " diff --git a/e2e/test_shell b/e2e/test_shell index 7975240d6..99ac54e6d 100755 --- a/e2e/test_shell +++ b/e2e/test_shell @@ -1,15 +1,8 @@ #!/usr/bin/env bash set -euo pipefail +source "$(dirname "$0")/assert.sh" -assert() { - local actual - actual="$($*)" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi -} - +export RTX_EXPERIMENTAL=1 eval "$(rtx activate bash)" && eval "$(rtx hook-env)" assert "node -v" "v18.0.0" rtx shell nodejs@16.0.0 && eval "$(rtx hook-env)" diff --git a/e2e/test_system b/e2e/test_system index 23de89558..ddc28f19e 100755 --- a/e2e/test_system +++ b/e2e/test_system @@ -1,16 +1,8 @@ #!/usr/bin/env bash - set -euo pipefail +source "$(dirname "$0")/assert.sh" -assert() { - actual="$($1)" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" != "$expected" ]]; then - echo "assertion failed, expected '$expected', got '$actual'" - exit 1 - fi -} +export RTX_EXPERIMENTAL=1 system_node="$(which node)" rtx_node="$(rtx which node)" diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 7d92b9591..c2ad7b6b9 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -2,6 +2,15 @@ source: src/cli/alias/set.rs expression: output --- +nodejs lts 18 +nodejs lts/argon 4 +nodejs lts/boron 6 +nodejs lts/carbon 8 +nodejs lts/dubnium 10 +nodejs lts/erbium 12 +nodejs lts/fermium 14 +nodejs lts/gallium 16 +nodejs lts/hydrogen 18 tiny lts 3.1.0 tiny lts-prev 2.0.0 tiny my/alias 3.0 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap new file mode 100644 index 000000000..7234b7d76 --- /dev/null +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -0,0 +1,16 @@ +--- +source: src/cli/alias/unset.rs +expression: output +--- +nodejs lts 18 +nodejs lts/argon 4 +nodejs lts/boron 6 +nodejs lts/carbon 8 +nodejs lts/dubnium 10 +nodejs lts/erbium 12 +nodejs lts/fermium 14 +nodejs lts/gallium 16 +nodejs lts/hydrogen 18 +tiny lts 3.1.0 +tiny lts-prev 2.0.0 + diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap deleted file mode 100644 index a1012e5fe..000000000 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__settings_unset.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/alias/unset.rs -expression: output ---- -tiny lts 3.1.0 -tiny lts-prev 2.0.0 - diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 899f44ae4..2e660ef43 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -36,7 +36,7 @@ mod tests { use crate::{assert_cli, assert_cli_snapshot}; #[test] - fn test_settings_unset() { + fn test_alias_unset() { reset_config(); assert_cli!("alias", "unset", "tiny", "my/alias"); diff --git a/src/cmd.rs b/src/cmd.rs index 691d4ef36..200de1e99 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -108,6 +108,14 @@ impl<'a> CmdLineRunner<'a> { self } + pub fn env(&mut self, key: K, val: V) -> &mut Self + where + K: AsRef, + V: AsRef, + { + self.cmd.env(key, val); + self + } pub fn envs(&mut self, vars: I) -> &mut Self where I: IntoIterator, diff --git a/src/config/mod.rs b/src/config/mod.rs index dfa8b354c..50dc09364 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -18,7 +18,7 @@ use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; use crate::env::CI; -use crate::plugins::core::PythonPlugin; +use crate::plugins::core::{NodeJSPlugin, PythonPlugin}; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::tool::Tool; @@ -321,14 +321,16 @@ fn load_tools(settings: &Settings) -> Result { } fn load_core_tools(settings: &Settings) -> ToolMap { - let tools = [("python", PythonPlugin::new)].map(|(name, plugin)| { - let plugin = plugin(settings, name.to_string()); + let tools: Vec> = vec![ + Box::new(PythonPlugin::new(settings, "python".to_string())), + Box::new(NodeJSPlugin::new(settings, "nodejs".to_string())), + ]; + ToolMap::from_iter(tools.into_iter().map(|plugin| { ( - name.to_string(), - build_tool(name.to_string(), Box::new(plugin)), + plugin.name().to_string(), + build_tool(plugin.name().to_string(), plugin), ) - }); - ToolMap::from_iter(tools) + })) } fn build_tool(name: PluginName, plugin: Box) -> Arc { diff --git a/src/env.rs b/src/env.rs index 944490789..a9801fa3a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -98,6 +98,23 @@ pub static RTX_PYTHON_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { .unwrap_or_else(|| HOME.join(".default-python-packages")) }); +// nodejs +pub static RTX_NODEJS_CONCURRENCY: Lazy = Lazy::new(|| { + var("RTX_NODEJS_CONCURRENCY") + .ok() + .and_then(|v| v.parse::().ok()) + .unwrap_or(num_cpus::get() / 2) + .max(1) +}); +pub static RTX_NODEJS_VERBOSE_INSTALL: Lazy = + Lazy::new(|| var_is_true("RTX_NODEJS_VERBOSE_INSTALL")); +pub static RTX_NODEJS_FORCE_COMPILE: Lazy = + Lazy::new(|| var_is_true("RTX_NODEJS_FORCE_COMPILE")); +pub static RTX_NODEJS_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("RTX_NODEJS_DEFAULT_PACKAGES_FILE") + .unwrap_or_else(|| HOME.join(".default-nodejs-packages")) +}); + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { Yes, diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index dd6930ff7..ada18cfc9 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,3 +1,5 @@ +mod nodejs; mod python; +pub use nodejs::NodeJSPlugin; pub use python::PythonPlugin; diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/nodejs.rs new file mode 100644 index 000000000..7c25a78ee --- /dev/null +++ b/src/plugins/core/nodejs.rs @@ -0,0 +1,194 @@ +use std::collections::BTreeMap; +use std::path::PathBuf; +use std::process::exit; +use std::time::Duration; + +use color_eyre::eyre::Result; + +use crate::cache::CacheManager; +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::env::{ + RTX_EXE, RTX_NODEJS_CONCURRENCY, RTX_NODEJS_FORCE_COMPILE, RTX_NODEJS_VERBOSE_INSTALL, +}; +use crate::file::create_dir_all; +use crate::git::Git; +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; +use crate::{cmd, dirs, env}; + +#[derive(Debug)] +pub struct NodeJSPlugin { + pub name: PluginName, + cache_path: PathBuf, + remote_version_cache: CacheManager>, +} + +impl NodeJSPlugin { + pub fn new(_settings: &Settings, name: PluginName) -> NodeJSPlugin { + let cache_path = dirs::CACHE.join(&name); + let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours + Self { + remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) + .with_fresh_duration(fresh_duration) + .with_fresh_file(RTX_EXE.clone()), + name, + cache_path, + } + } + + fn node_build_path(&self) -> PathBuf { + self.cache_path.join("node-build") + } + fn node_build_bin(&self) -> PathBuf { + self.node_build_path().join("bin/node-build") + } + fn install_or_update_node_build(&self) -> Result<()> { + if self.node_build_path().exists() { + self.update_node_build() + } else { + self.install_node_build() + } + } + fn install_node_build(&self) -> Result<()> { + if self.node_build_path().exists() { + return Ok(()); + } + debug!( + "Installing node-build to {}", + self.node_build_path().display() + ); + create_dir_all(self.node_build_path().parent().unwrap())?; + let git = Git::new(self.node_build_path()); + git.clone("https://github.com/nodenv/node-build.git")?; + Ok(()) + } + fn update_node_build(&self) -> Result<()> { + // TODO: do not update if recently updated + debug!( + "Updating node-build in {}", + self.node_build_path().display() + ); + let git = Git::new(self.node_build_path()); + git.update(None)?; + Ok(()) + } + + fn fetch_remote_versions(&self) -> Result> { + self.install_or_update_node_build()?; + let output = cmd!(self.node_build_bin(), "--definitions").read()?; + let versions = output + .split('\n') + .filter(|s| regex!(r"^[0-9].+$").is_match(s)) + .map(|s| s.to_string()) + .collect(); + Ok(versions) + } + + fn npm_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/npm") + } + + fn install_default_packages( + &self, + settings: &Settings, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + let body = + std::fs::read_to_string(&*env::RTX_NODEJS_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + for package in body.lines() { + let package = package.split('#').next().unwrap_or_default().trim(); + if package.is_empty() { + continue; + } + pr.set_message(format!("installing default package: {}", package)); + let npm = self.npm_path(tv); + let mut cmd = CmdLineRunner::new(settings, npm); + cmd.with_pr(pr).arg("install").arg("--global").arg(package); + cmd.execute()?; + } + Ok(()) + } +} + +impl Plugin for NodeJSPlugin { + fn name(&self) -> &PluginName { + &self.name + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn get_aliases(&self, _settings: &Settings) -> Result> { + let aliases = [ + ("lts/argon", "4"), + ("lts/boron", "6"), + ("lts/carbon", "8"), + ("lts/dubnium", "10"), + ("lts/erbium", "12"), + ("lts/fermium", "14"), + ("lts/gallium", "16"), + ("lts/hydrogen", "18"), + ("lts", "18"), + ] + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(); + Ok(aliases) + } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".node-version".into(), ".nvmrc".into()]) + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + self.install_node_build()?; + pr.set_message("running node-build"); + let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()); + cmd.with_pr(pr).arg(tv.version.as_str()); + if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODEJS_FORCE_COMPILE { + let make_opts = String::from(" -j") + &RTX_NODEJS_CONCURRENCY.to_string(); + cmd.env( + "MAKE_OPTS", + env::var("MAKE_OPTS").unwrap_or_default() + &make_opts, + ); + cmd.env( + "NODE_MAKE_OPTS", + env::var("NODE_MAKE_OPTS").unwrap_or_default() + &make_opts, + ); + cmd.arg("--compile"); + } + if *RTX_NODEJS_VERBOSE_INSTALL { + cmd.arg("--verbose"); + } + cmd.arg(tv.install_path()); + cmd.execute()?; + self.install_default_packages(&config.settings, tv, pr)?; + Ok(()) + } + + fn external_commands(&self) -> Result>> { + Ok(vec![vec![self.name.clone(), "nodebuild".into()]]) + } + + fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { + match command { + "nodebuild" => { + self.install_or_update_node_build()?; + cmd::cmd(self.node_build_bin(), args).run()?; + } + _ => unreachable!(), + } + exit(0); + } +} diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 40e4db47e..6d38c5abe 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -147,6 +147,10 @@ impl PythonPlugin { } impl Plugin for PythonPlugin { + fn name(&self) -> &PluginName { + &self.name + } + fn list_remote_versions(&self, _settings: &Settings) -> Result> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 95afa6d2c..18b5b2f20 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -299,6 +299,10 @@ impl Hash for ExternalPlugin { } impl Plugin for ExternalPlugin { + fn name(&self) -> &PluginName { + &self.name + } + fn get_type(&self) -> PluginType { PluginType::External } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 72b22c964..c2ad7c938 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -21,6 +21,7 @@ mod script_manager; pub type PluginName = String; pub trait Plugin: Debug + Send + Sync { + fn name(&self) -> &PluginName; fn get_type(&self) -> PluginType { PluginType::Core } From 0c6ec7ebe821152842349b7ad09d209bed48589f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 11 Apr 2023 21:56:27 -0500 Subject: [PATCH 0690/1891] chore: Release --- Cargo.lock | 28 ++++++++++++++-------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 6 ++++-- 7 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ee9ffe6e..9ff6e05eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -237,7 +237,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -436,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" dependencies = [ "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -473,7 +473,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -490,7 +490,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -1357,7 +1357,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -1586,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.28.3" +version = "1.28.4" dependencies = [ "base64", "built", @@ -1744,22 +1744,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -1903,9 +1903,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ "proc-macro2", "quote", @@ -1978,7 +1978,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3af6d4990..6d0ab2685 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.28.3" +version = "1.28.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index cfa7d8fb0..6e9caa665 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.28.3 +rtx 1.28.4 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -329,7 +329,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.28.3/rtx-v1.28.3-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.28.4/rtx-v1.28.4-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 22c5d1bcf..43765a576 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.28.3"; + version = "1.28.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index d380b1fbd..ab0c9fe51 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.28.3" +.TH rtx 1 "rtx 1.28.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.28.3 +v1.28.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c43235073..c51e490cd 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.28.3 +Version: 1.28.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 982a58975..4cf02c43d 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 640] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 642] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -324,7 +324,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 640] = [ ("kp", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("kpt", "https://github.com/nlamirault/asdf-kpt.git"), ("krab", "https://github.com/ohkrab/asdf-krab.git"), - ("krew", "https://github.com/jimmidyson/asdf-krew.git"), + ("krew", "https://github.com/bjw-s/asdf-krew.git"), ("kscript", "https://github.com/edgelevel/asdf-kscript.git"), ("ksonnet", "https://github.com/Banno/asdf-ksonnet.git"), ("ktlint", "https://github.com/esensar/asdf-ktlint.git"), @@ -486,6 +486,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 640] = [ ("ripgrep", "https://gitlab.com/wt0f/asdf-ripgrep.git"), ("rke", "https://github.com/particledecay/asdf-rke.git"), ("rlwrap", "https://github.com/asdf-community/asdf-rlwrap.git"), + ("rome", "https://github.com/kichiemon/asdf-rome.git"), ("rstash", "https://github.com/carlduevel/asdf-rstash.git"), ("ruby", "https://github.com/asdf-vm/asdf-ruby.git"), ("rust", "https://github.com/code-lever/asdf-rust.git"), @@ -596,6 +597,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 640] = [ ("upx", "https://github.com/jimmidyson/asdf-upx.git"), ("usql", "https://github.com/itspngu/asdf-usql.git"), ("v", "https://github.com/jthegedus/asdf-v.git"), + ("vale", "https://github.com/pdemagny/asdf-vale"), ("vals", "https://github.com/dex4er/asdf-vals.git"), ("vault", "https://github.com/asdf-community/asdf-hashicorp.git"), ("vcluster", "https://gitlab.com/wt0f/asdf-vcluster.git"), From caef8acc57b83802e12e58a95c47126dad280e7b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 12 Apr 2023 12:18:40 -0500 Subject: [PATCH 0691/1891] bug: fix default node package install (#481) this was not adding "node" to PATH before --- e2e/.default-nodejs-packages | 1 + e2e/test_nodejs | 2 ++ src/plugins/core/nodejs.rs | 4 ++++ 3 files changed, 7 insertions(+) create mode 100644 e2e/.default-nodejs-packages diff --git a/e2e/.default-nodejs-packages b/e2e/.default-nodejs-packages new file mode 100644 index 000000000..c1342049d --- /dev/null +++ b/e2e/.default-nodejs-packages @@ -0,0 +1 @@ +zx diff --git a/e2e/test_nodejs b/e2e/test_nodejs index c1fd33a19..6784a9b90 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -3,6 +3,8 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 +export RTX_NODEJS_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-nodejs-packages" + rtx plugin uninstall nodejs rtx i nodejs nodejs@lts/hydrogen assert_contains "rtx x nodejs@lts/hydrogen -- node --version" "v18." diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/nodejs.rs index 7c25a78ee..eb994c412 100644 --- a/src/plugins/core/nodejs.rs +++ b/src/plugins/core/nodejs.rs @@ -1,4 +1,5 @@ use std::collections::BTreeMap; +use std::env::{join_paths, split_paths}; use std::path::PathBuf; use std::process::exit; use std::time::Duration; @@ -107,6 +108,9 @@ impl NodeJSPlugin { let npm = self.npm_path(tv); let mut cmd = CmdLineRunner::new(settings, npm); cmd.with_pr(pr).arg("install").arg("--global").arg(package); + let mut path = split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, tv.install_path().join("bin")); + cmd.env("PATH", join_paths(path)?); cmd.execute()?; } Ok(()) From d30110614d195c2928e15c000473bfcabb6f59f2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 12 Apr 2023 17:28:40 -0500 Subject: [PATCH 0692/1891] allow comments in python default packages file (#482) this parses it as a requirements.txt file instead Fixes #469 --- src/plugins/core/python.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 6d38c5abe..817b9fe78 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -93,20 +93,18 @@ impl PythonPlugin { tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - let body = - std::fs::read_to_string(&*env::RTX_PYTHON_DEFAULT_PACKAGES_FILE).unwrap_or_default(); - for package in body.lines() { - let package = package.trim(); - if package.is_empty() { - continue; - } - pr.set_message(format!("installing default package: {}", package)); - let pip = self.pip_path(tv); - let mut cmd = CmdLineRunner::new(settings, pip); - cmd.with_pr(pr).arg("install").arg(package); - cmd.execute()?; + if !env::RTX_PYTHON_DEFAULT_PACKAGES_FILE.exists() { + return Ok(()); } - Ok(()) + pr.set_message("installing default packages"); + let pip = self.pip_path(tv); + let mut cmd = CmdLineRunner::new(settings, pip); + cmd.with_pr(pr) + .arg("install") + .arg("--upgrade") + .arg("-r") + .arg(&*env::RTX_PYTHON_DEFAULT_PACKAGES_FILE); + cmd.execute() } fn get_virtualenv( From 3edbd903a7ac3374118971d27716f92acc1b36a3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 13 Apr 2023 08:32:28 -0500 Subject: [PATCH 0693/1891] replace ~/ with $HOME/ for env var paths (#485) Fixes #483 --- src/env.rs | 3 ++- src/file.rs | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/env.rs b/src/env.rs index a9801fa3a..d2f6cf410 100644 --- a/src/env.rs +++ b/src/env.rs @@ -7,6 +7,7 @@ use log::LevelFilter; use once_cell::sync::Lazy; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; +use crate::file::replace_path; pub static ARGS: Lazy> = Lazy::new(|| args().collect()); pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "sh".into())); @@ -154,7 +155,7 @@ fn var_is_false(key: &str) -> bool { } fn var_path(key: &str) -> Option { - var_os(key).map(PathBuf::from) + var_os(key).map(PathBuf::from).map(replace_path) } fn var_confirm(key: &str) -> Confirm { diff --git a/src/file.rs b/src/file.rs index b15038070..7234a1d6b 100644 --- a/src/file.rs +++ b/src/file.rs @@ -53,13 +53,10 @@ pub fn display_path(path: &Path) -> String { } /// replaces "~" with $HOME -pub fn replace_path(path: &Path) -> PathBuf { - let home = dirs::HOME.to_string_lossy(); - match path.starts_with("~") { - true => path - .to_string_lossy() - .replacen('~', home.as_ref(), 1) - .into(), +pub fn replace_path>(path: P) -> PathBuf { + let path = path.as_ref(); + match path.starts_with("~/") { + true => dirs::HOME.join(path.strip_prefix("~/").unwrap()), false => path.to_path_buf(), } } @@ -231,4 +228,10 @@ mod tests { .join("cwd"); assert_eq!(display_path(&path), path.display().to_string()); } + + #[test] + fn test_replace_path() { + assert_eq!(replace_path(Path::new("~/cwd")), dirs::HOME.join("cwd")); + assert_eq!(replace_path(Path::new("/cwd")), Path::new("/cwd")); + } } From d206899f61869a530ee532dbb24f07cf7ace6025 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 13 Apr 2023 08:33:41 -0500 Subject: [PATCH 0694/1891] chore: Release --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9ff6e05eb..3246e7bfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1586,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.28.4" +version = "1.28.5" dependencies = [ "base64", "built", @@ -1764,9 +1764,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 6d0ab2685..1720ccb11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.28.4" +version = "1.28.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 6e9caa665..be9956d21 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.28.4 +rtx 1.28.5 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -329,7 +329,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.28.4/rtx-v1.28.4-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.28.5/rtx-v1.28.5-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 43765a576..76ff90d4f 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.28.4"; + version = "1.28.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index ab0c9fe51..99d868375 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.28.4" +.TH rtx 1 "rtx 1.28.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to node\-18.x .SH VERSION -v1.28.4 +v1.28.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c51e490cd..c8bb86938 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.28.4 +Version: 1.28.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 3db4fa418a135402b7fbc210fd9b2ce6768895ad Mon Sep 17 00:00:00 2001 From: Lucca Huguet Date: Sun, 16 Apr 2023 09:28:53 -0300 Subject: [PATCH 0695/1891] fixes bug/typo (#477) * fixes bug/typo * updated snapshots --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- src/shell/nushell.rs | 2 +- src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 52bfda5e8..8132ff7b9 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -70,7 +70,7 @@ impl Shell for Nushell { | parse vars | update-env }} else {{ - ^"{exe}" {exe} $command $rest + ^"{exe}" $command $rest }} }} diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap index 47bdebf3f..def1b7f9c 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap @@ -36,7 +36,7 @@ def-env rtx [command?: string, --help, ...rest: string] { | parse vars | update-env } else { - ^"/some/dir/rtx" /some/dir/rtx $command $rest + ^"/some/dir/rtx" $command $rest } } From cfbec077339b6f74f0fc73b3a2483a0b7b9da386 Mon Sep 17 00:00:00 2001 From: Lucca Huguet Date: Sun, 16 Apr 2023 09:38:59 -0300 Subject: [PATCH 0696/1891] fixes nushell unsupporte closures bug #471 (#475) * fixes nushell unsupporte closures bug * updated snapshots --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- src/shell/nushell.rs | 8 ++++---- .../snapshots/rtx__shell__nushell__tests__hook_init.snap | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 8132ff7b9..5c318456f 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -42,13 +42,13 @@ impl Shell for Nushell { let-env config = ($env.config | upsert hooks {{ pre_prompt: [{{ - condition: {{ "RTX_SHELL" in $env }} - code: {{ rtx_hook }} + condition: {{|| "RTX_SHELL" in $env }} + code: {{|| rtx_hook }} }}] env_change: {{ PWD: [{{ - condition: {{ "RTX_SHELL" in $env }} - code: {{ rtx_hook }} + condition: {{|| "RTX_SHELL" in $env }} + code: {{|| rtx_hook }} }}] }} }}) diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap index def1b7f9c..234916a4b 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap @@ -8,13 +8,13 @@ export-env { let-env config = ($env.config | upsert hooks { pre_prompt: [{ - condition: { "RTX_SHELL" in $env } - code: { rtx_hook } + condition: {|| "RTX_SHELL" in $env } + code: {|| rtx_hook } }] env_change: { PWD: [{ - condition: { "RTX_SHELL" in $env } - code: { rtx_hook } + condition: {|| "RTX_SHELL" in $env } + code: {|| rtx_hook } }] } }) From 259526531e1f5d76cf6e2e239a40bc265a7c5487 Mon Sep 17 00:00:00 2001 From: Jack Rose Date: Mon, 17 Apr 2023 23:03:58 +1000 Subject: [PATCH 0697/1891] Correct nix snippet to point to correct repo (#491) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be9956d21..1d37aff60 100644 --- a/README.md +++ b/README.md @@ -400,7 +400,7 @@ For NixOS or those using the Nix package manager: nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; flake-utils.url = "github:numtide/flake-utils"; rtx-flake = { - url = "github:chadac/rtx/add-nix-flake"; + url = "github:jdxcode/rtx"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-utils.follows = "flake-utils"; }; From c9bafc2c49b9b2d7c8704036ca767cabbd8f27bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 10:47:19 -0500 Subject: [PATCH 0698/1891] chore(deps): bump clap from 4.2.1 to 4.2.2 (#490) Bumps [clap](https://github.com/clap-rs/clap) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.2.1...v4.2.2) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 52 ++++++++++++++++++++++++++-------------------------- Cargo.toml | 2 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3246e7bfb..0c48026df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,42 +37,51 @@ dependencies = [ [[package]] name = "anstream" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" dependencies = [ "anstyle", "anstyle-parse", + "anstyle-query", "anstyle-wincon", - "concolor-override", - "concolor-query", + "colorchoice", "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "0.3.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" [[package]] name = "anstyle-parse" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" dependencies = [ "utf8parse", ] +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "anstyle-wincon" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" dependencies = [ "anstyle", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -197,9 +206,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" +checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a" dependencies = [ "clap_builder", "clap_derive", @@ -208,9 +217,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6" dependencies = [ "anstream", "anstyle", @@ -315,19 +324,10 @@ dependencies = [ ] [[package]] -name = "concolor-override" +name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" - -[[package]] -name = "concolor-query" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" -dependencies = [ - "windows-sys 0.45.0", -] +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "console" diff --git a/Cargo.toml b/Cargo.toml index 1720ccb11..1454ff184 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ path = "src/main.rs" [dependencies] base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } -clap = { version = "4.0.32", features = ["env", "derive", "string"] } +clap = { version = "4.2.2", features = ["env", "derive", "string"] } clap_complete = "4.0.7" color-eyre = "0.6.2" color-print = "0.3.4" From 20c25f844311b6e07837f87d57b8646a4fab788c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:01:38 +0000 Subject: [PATCH 0699/1891] chore(deps): bump h2 from 0.3.16 to 0.3.17 (#486) Bumps [h2](https://github.com/hyperium/h2) from 0.3.16 to 0.3.17. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.16...v0.3.17) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c48026df..2f027f7a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -803,9 +803,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", From 91cd7e55d98d3640850877cee2bbe876d4ec3cb0 Mon Sep 17 00:00:00 2001 From: kendofriendo <39413174+kendofriendo@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:45:52 -0400 Subject: [PATCH 0700/1891] Update README.md (#492) * Update README.md clarify that the quickstart instructions are only for Mac * Update README.md --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d37aff60..ec0344e2d 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Note that calling `which node` gives us a real path to node, not a shim. ## Quickstart -Install rtx (other methods [here](#installation)): +Install rtx on macOS (other methods [here](#installation)): ```sh-session $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx From aff8618e0e18d32ec226dca2d892476008e383a4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:52:36 -0500 Subject: [PATCH 0701/1891] Update SECURITY.md core plugins are a thing now --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 25f3243cb..6e0f6a2b3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -33,8 +33,8 @@ Plugins are by far the biggest source of potential problems and where the most w Eventually we will have 3 types of plugins: -* [core](https://github.com/jdxcode/rtx/issues/236) - plugins that will be hardcoded into the CLI. These will be -official plugins for the most common languages. +* [core](https://github.com/jdxcode/rtx/issues/236) - plugins that are hardcoded into the CLI. These will be +official plugins for the most common languages. Currently, these are only used when "experimental" is enabled. * community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. For now these will only have @jdxcode as the sole contributor, however this may change in the future for particular plugins with dedicated owners/collaborators. If you'd like your plugin to be moved here, ask me about it. From e0626693d719308f9ac0b0f6df36870b8797ede2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:20:23 -0500 Subject: [PATCH 0702/1891] support multiple versions in legacy files and env vars (#494) Fixes #476 Fixes #487 --- src/config/config_file/legacy_version.rs | 2 +- src/toolset/builder.rs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 4eb082327..54e6c4e13 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -91,7 +91,7 @@ impl Display for LegacyVersionFile { fn build_toolset(path: &Path, plugin: &str, version: &str) -> Toolset { let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.to_path_buf())); - if !version.is_empty() { + for version in version.split_whitespace() { toolset.add_version( ToolVersionRequest::new(plugin.to_string(), version), Default::default(), diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index b219730f6..a648c2cbd 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -71,8 +71,10 @@ fn load_runtime_env(ts: &mut Toolset, env: BTreeMap) { } let source = ToolSource::Environment(k, v.clone()); let mut env_ts = Toolset::new(source); - let tvr = ToolVersionRequest::new(plugin_name, &v); - env_ts.add_version(tvr, Default::default()); + for v in v.split_whitespace() { + let tvr = ToolVersionRequest::new(plugin_name.clone(), v); + env_ts.add_version(tvr, Default::default()); + } ts.merge(&env_ts); } } From bfe89042c716a958ca6e206cf6757b3a1bc63d02 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 19 Apr 2023 18:33:33 -0500 Subject: [PATCH 0703/1891] node v20 (#495) --- .devcontainer/Dockerfile | 2 +- .github/workflows/rtx.yml | 2 +- README.md | 190 +++++++++--------- completions/_rtx | 16 +- completions/rtx.fish | 8 +- docs/nodejs.md | 12 +- e2e/.e2e-tool-versions | 2 +- e2e/.node-version | 2 +- e2e/cd/.e2e-tool-versions | 2 +- e2e/cd/16/.e2e-tool-versions | 1 - e2e/cd/16/.e2e.rtx.toml | 2 - e2e/cd/18/.e2e-tool-versions | 1 + e2e/cd/18/.e2e.rtx.toml | 2 + e2e/cd/test_bash | 22 +- e2e/cd/test_bash_legacy_activate | 10 +- e2e/cd/test_fish | 14 +- e2e/cd/test_zsh | 14 +- e2e/config/.e2e-tool-versions | 2 +- e2e/config/.node-version | 2 +- e2e/config/cd/.e2e-tool-versions | 2 +- e2e/config/cd/16/.e2e-tool-versions | 1 - e2e/config/cd/16/.e2e.rtx.toml | 2 - e2e/config/cd/18/.e2e-tool-versions | 1 + e2e/config/cd/18/.e2e.rtx.toml | 2 + .../load-first/.e2e-tool-versions | 2 +- .../system_version/test_direnv_system_version | 2 +- e2e/run_test | 4 +- e2e/test_env | 6 +- e2e/test_local | 6 +- e2e/test_log_level | 8 +- e2e/test_nodejs | 2 +- e2e/test_shell | 8 +- e2e/test_shims | 2 +- justfile | 3 +- man/man1/rtx.1 | 12 +- packaging/homebrew/homebrew.rb | 4 +- src/cli/alias/get.rs | 2 +- src/cli/alias/ls.rs | 4 +- src/cli/args/runtime.rs | 4 +- src/cli/current.rs | 4 +- src/cli/exec.rs | 12 +- src/cli/global.rs | 20 +- src/cli/install.rs | 6 +- src/cli/latest.rs | 4 +- src/cli/local.rs | 24 +-- src/cli/ls.rs | 10 +- src/cli/ls_remote.rs | 12 +- src/cli/mod.rs | 12 +- src/cli/plugins/install.rs | 2 +- src/cli/prune.rs | 4 +- src/cli/reshim.rs | 2 +- src/cli/shell.rs | 4 +- src/cli/where.rs | 6 +- src/cli/which.rs | 4 +- ...nfig_file__rtx_toml__tests__fixture-4.snap | 6 +- ...nfig_file__rtx_toml__tests__fixture-6.snap | 2 +- test/fixtures/.rtx.toml | 2 +- 57 files changed, 260 insertions(+), 259 deletions(-) delete mode 100644 e2e/cd/16/.e2e-tool-versions delete mode 100644 e2e/cd/16/.e2e.rtx.toml create mode 100644 e2e/cd/18/.e2e-tool-versions create mode 100644 e2e/cd/18/.e2e.rtx.toml delete mode 100644 e2e/config/cd/16/.e2e-tool-versions delete mode 100644 e2e/config/cd/16/.e2e.rtx.toml create mode 100644 e2e/config/cd/18/.e2e-tool-versions create mode 100644 e2e/config/cd/18/.e2e.rtx.toml diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ea0066c8f..3b87849a6 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -12,7 +12,7 @@ RUN cargo install cargo-insta cargo-llvm-cov # Install dependencies RUN export DEBIAN_FRONTEND=noninteractive \ - && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \ + && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get update \ && apt-get -y install --no-install-recommends \ # shells, direnv, shellcheck diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 47793d4a8..155c6790d 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -225,7 +225,7 @@ jobs: echo "$HOME/.local/bin" >> $GITHUB_PATH - uses: actions/setup-node@v3 with: - node-version: "18.x" + node-version: "20.x" registry-url: "https://registry.npmjs.org" - name: Set AWS credentials uses: aws-actions/configure-aws-credentials@v2 diff --git a/README.md b/README.md index ec0344e2d..a964d5128 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. - **No shims** - shims cause problems, they break `which`, and add overhead. By default, rtx does not use them—however you can if you want to. -- **Fuzzy matching and aliases** - It's enough to just say you want "v18" of node, or the "lts" +- **Fuzzy matching and aliases** - It's enough to just say you want "v20" of node, or the "lts" version. rtx will figure out the right version without you needing to specify an exact version. - **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. @@ -54,10 +54,10 @@ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish Install a runtime and set it as the default: ```sh-session -$ rtx install nodejs@18 -$ rtx global nodejs@18 +$ rtx install nodejs@20 +$ rtx global nodejs@20 $ node -v -v18.15.0 +v20.0.0 ``` ## Table of Contents @@ -232,16 +232,16 @@ See [plugins](#plugins) below. ### Common commands - rtx install nodejs@18.0.0 Install a specific version number - rtx install nodejs@18 Install a fuzzy version number - rtx local nodejs@18 Use node-18.x in current project - rtx global nodejs@18 Use node-18.x as default + rtx install nodejs@20.0.0 Install a specific version number + rtx install nodejs@20 Install a fuzzy version number + rtx local nodejs@20 Use node-20.x in current project + rtx global nodejs@20 Use node-20.x as default rtx install nodejs Install the version specified in .tool-versions rtx local nodejs@latest Use latest node in current directory rtx global nodejs@system Use system node as default - rtx x nodejs@18 -- node app.js Run `node app.js` with the PATH pointing to node-18.x + rtx x nodejs@20 -- node app.js Run `node app.js` with the PATH pointing to node-20.x ## Installation @@ -500,7 +500,7 @@ You can specify a tool and its version in a shebang without needing to first setup `.tool-versions`/`.rtx.toml` config: ```typescript -#!/usr/bin/env -S rtx x nodejs@18 -- node +#!/usr/bin/env -S rtx x nodejs@20 -- node // "env -S" allows multiple arguments in a shebang console.log(`Running node: ${process.version}`); ``` @@ -516,7 +516,7 @@ The `.tool-versions` file is used to specify the runtime versions for a project. is: ``` -nodejs 18.0.0 # comments are allowed +nodejs 20.0.0 # comments are allowed ruby 3 # can be fuzzy version shellcheck latest # also supports "latest" jq 1.6 @@ -526,7 +526,7 @@ shfmt path:./shfmt # use a custom runtime nodejs lts # use lts version of nodejs (not supported by all plugins) # The following syntax is experimental and subject to change -nodejs lts!-2 # install 2 versions behind the latest lts (e.g.: 16 if lts is 18) +nodejs lts!-2 # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) python latest!-0.1 # install python-3.10 if the latest is 3.11 ``` @@ -606,7 +606,7 @@ shims_dir = '~/.local/share/rtx/shims' # [experimental] directory where shims ar log_level = 'debug' # log verbosity, see `RTX_LOG_LEVEL` [alias.nodejs] -my_custom_node = '18' # makes `rtx install nodejs@my_custom_node` install node-18.x +my_custom_node = '20' # makes `rtx install nodejs@my_custom_node` install node-20.x # this can also be specified in a plugin (see below in "Aliases") ``` @@ -634,7 +634,7 @@ terraform = '1.0.0' erlang = ['23.3', '24.0'] # supports everything you can do with .tool-versions currently -nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] +nodejs = ['16', 'prefix:20', 'ref:master', 'path:~/.nodes/14'] # send arbitrary options to the plugin, passed as: # RTX_TOOL_OPTS__VENV=.venv @@ -651,7 +651,7 @@ missing_runtime_behavior = 'warn' shims_dir = '~/.rtx/shims' [alias.nodejs] # project-local aliases -my_custom_node = '18' +my_custom_node = '20' ``` `.rtx.toml` is currently experimental and may change in minor versions of rtx. It does not @@ -709,8 +709,8 @@ rtx can also be configured via environment variables. The following options are This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. ``` -RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@18 -RTX_NODEJS_VERSION=18 rtx exec -- node --version +RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@20 +RTX_NODEJS_VERSION=20 rtx exec -- node --version ``` #### `RTX_DATA_DIR` @@ -747,7 +747,7 @@ to use this feature. #### `RTX_${PLUGIN}_VERSION` -Set the version for a runtime. For example, `RTX_NODEJS_VERSION=18` will use nodejs@18.x regardless +Set the version for a runtime. For example, `RTX_NODEJS_VERSION=20` will use nodejs@20.x regardless of what is set in `.tool-versions`/`.rtx.toml`. #### `RTX_LEGACY_VERSION_FILE` @@ -824,7 +824,7 @@ installing plugins, e.g.: `rtx plugin install nodejs https://github.com/asdf-vm/ Currently this disables the following: -- `--fuzzy` as default behavior (`rtx local nodejs@18` will save exact version) +- `--fuzzy` as default behavior (`rtx local nodejs@20` will save exact version) #### `RTX_HIDE_UPDATE_WARNING=1` @@ -845,14 +845,14 @@ Set a directory to output shims when running `rtx reshim`. Requires `experimenta ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS -versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for nodejs@18.x. +versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for nodejs@20.x. So you can use the runtime with `nodejs lts/hydrogen` in `.tool-versions`. User aliases can be created by adding an `alias.` section to `~/.config/rtx/config.toml`: ```toml [alias.nodejs] -my_custom_18 = '18' +my_custom_20 = '20' ``` Plugins can also provide aliases via a `bin/list-aliases` script. Here is an example showing node.js @@ -981,18 +981,18 @@ ln -s ~/src/rtx-my-tool ~/.local/share/rtx/plugins/my-tool #### `~/.local/share/rtx/installs` This is where tools are installed to when running `rtx install`. For example, `rtx install -nodejs@18.0.0` will install to `~/.local/share/rtx/installs/nodejs/18.0.0` For example, `rtx -install 0.0` will install to `~/.local/share/rtx/installs/nodejs/18.0.0`. +nodejs@20.0.0` will install to `~/.local/share/rtx/installs/nodejs/20.0.0` For example, `rtx +install 0.0` will install to `~/.local/share/rtx/installs/nodejs/20.0.0`. -This will also create other symlinks to this directory for version prefixes ("18" and "18.15") +This will also create other symlinks to this directory for version prefixes ("20" and "20.15") and matching aliases ("lts", "latest"). For example: ``` -18 -> ./18.15.0 -18.15 -> ./18.15.0 -latest -> ./18.15.0 -lts -> ./18.15.0 +20 -> ./20.15.0 +20.15 -> ./20.15.0 +latest -> ./20.15.0 +lts -> ./20.15.0 ``` #### `~/.local/share/rtx/shims` @@ -1208,9 +1208,9 @@ and see what happens. rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin should be usable in rtx. The commands in rtx are slightly -different, such as `rtx install nodejs@18.0.0` vs `asdf install nodejs 18.0.0`—this is done so +different, such as `rtx install nodejs@20.0.0` vs `asdf install nodejs 20.0.0`—this is done so multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx -install nodejs 18.0.0`). This is the case for most commands, though the help for the command may +install nodejs 20.0.0`). This is the case for most commands, though the help for the command may say that asdf-style syntax is supported. When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may @@ -1300,16 +1300,16 @@ variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https:// Some commands are the same in asdf but others have been changed. Everything that's possible in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, -such as using fuzzy-matching, e.g.: `rtx install nodejs@18`. While in asdf you _can_ run -`asdf install nodejs latest:18`, you can't use `latest:18` in a `.tool-versions` file or many other places. +such as using fuzzy-matching, e.g.: `rtx install nodejs@20`. While in asdf you _can_ run +`asdf install nodejs latest:20`, you can't use `latest:20` in a `.tool-versions` file or many other places. In `rtx` you can use fuzzy-matching everywhere. asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: ```sh-session asdf plugin add nodejs -asdf install nodejs latest:18 -asdf local nodejs latest:18 +asdf install nodejs latest:20 +asdf local nodejs latest:20 ``` In `rtx` this can all be done in a single step to set the local runtime version. If the plugin @@ -1354,10 +1354,10 @@ To support this, there is experimental support for using rtx in a "shim" mode. T ```sh-session $ rtx settings set experimental true $ rtx settings set shims_dir ~/.rtx/shims -$ rtx i nodejs@18.0.0 +$ rtx i nodejs@20.0.0 $ rtx reshim $ ~/.rtx/shims/node -v -v18.0.0 +v20.0.0 ``` ## direnv @@ -1403,7 +1403,7 @@ easier to manage, I encourage _not_ actually using `.tool-versions` at all, and setting environment variables entirely in `.envrc`: ``` -export RTX_NODEJS_VERSION=18.0.0 +export RTX_NODEJS_VERSION=20.0.0 export RTX_PYTHON_VERSION=3.11 ``` @@ -1503,7 +1503,7 @@ Arguments: Examples: $ rtx alias get nodejs lts/hydrogen - 18.0.0 + 20.0.0 ``` ### `rtx alias ls [OPTIONS]` @@ -1515,7 +1515,7 @@ These can come from user config or from plugins in `bin/list-aliases`. For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: [alias.nodejs] - lts = "18.0.0" + lts = "20.0.0" Usage: ls [OPTIONS] @@ -1525,7 +1525,7 @@ Options: Examples: $ rtx aliases - nodejs lts/hydrogen 18.0.0 + nodejs lts/hydrogen 20.0.0 ``` ### `rtx alias set ` @@ -1680,7 +1680,7 @@ set. Runtimes will be loaded from .tool-versions, though they can be overridden with args Note that only the plugin specified will be overridden, so if a `.tool-versions` file -includes "nodejs 18" but you run `rtx exec python@3.11`; it will still load nodejs@18. +includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. The "--" separates runtimes from the commands to pass along to the subprocess. @@ -1688,7 +1688,7 @@ Usage: exec [OPTIONS] [RUNTIME]... [-- ...] Arguments: [RUNTIME]... - Runtime(s) to start e.g.: nodejs@18 python@3.10 + Runtime(s) to start e.g.: nodejs@20 python@3.10 [COMMAND]... Command string to execute (same as --command) @@ -1703,14 +1703,14 @@ Options: [short aliases: C] Examples: - $ rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x - $ rtx x nodejs@18 -- node ./app.js # shorter alias + $ rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x + $ rtx x nodejs@20 -- node ./app.js # shorter alias # Specify command as a string: - $ rtx exec nodejs@18 python@3.11 --command "node -v && python -V" + $ rtx exec nodejs@20 python@3.11 --command "node -v && python -V" # Run a command in a different directory: - $ rtx x -C /path/to/project nodejs@18 -- node ./app.js + $ rtx x -C /path/to/project nodejs@20 -- node ./app.js ``` ### `rtx global [OPTIONS] [RUNTIME]...` @@ -1730,18 +1730,18 @@ Usage: global [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... Runtime(s) to add to .tool-versions - e.g.: nodejs@18 + e.g.: nodejs@20 If this is a single runtime with no version, the current value of the global .tool-versions will be displayed Options: --pin Save exact version to `~/.tool-versions` - e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions + e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions --fuzzy Save fuzzy version to `~/.tool-versions` - e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions + e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove @@ -1751,17 +1751,17 @@ Options: Get the path of the global config file Examples: - # set the current version of nodejs to 18.x - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx global --fuzzy nodejs@18 + # set the current version of nodejs to 20.x + # will use a fuzzy version (e.g.: 20) in .tool-versions file + $ rtx global --fuzzy nodejs@20 - # set the current version of nodejs to 18.x - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx global --pin nodejs@18 + # set the current version of nodejs to 20.x + # will use a precise version (e.g.: 20.0.0) in .tool-versions file + $ rtx global --pin nodejs@20 # show the current version of nodejs in ~/.tool-versions $ rtx global nodejs - 18.0.0 + 20.0.0 ``` ### `rtx implode [OPTIONS]` @@ -1795,7 +1795,7 @@ Usage: install [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - Tool version(s) to install e.g.: nodejs@18 + Tool version(s) to install e.g.: nodejs@20 Options: -p, --plugin @@ -1808,8 +1808,8 @@ Options: Show installation output Examples: - $ rtx install nodejs@18.0.0 # install specific nodejs version - $ rtx install nodejs@18 # install fuzzy nodejs version + $ rtx install nodejs@20.0.0 # install specific nodejs version + $ rtx install nodejs@20 # install fuzzy nodejs version $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml $ rtx install # installs everything specified in .tool-versions or .rtx.toml ``` @@ -1825,8 +1825,8 @@ Arguments: Runtime to get the latest version of Examples: - $ rtx latest nodejs@18 # get the latest version of nodejs 18 - 18.0.0 + $ rtx latest nodejs@20 # get the latest version of nodejs 20 + 20.0.0 $ rtx latest nodejs # get the latest stable version of nodejs 20.0.0 @@ -1846,7 +1846,7 @@ Usage: local [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... Runtimes to add to .tool-versions/.rtx.toml - e.g.: nodejs@18 + e.g.: nodejs@20 if this is a single runtime with no version, the current value of .tool-versions/.rtx.toml will be displayed @@ -1857,10 +1857,10 @@ Options: --pin Save exact version to `.tool-versions` - e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions + e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions --fuzzy - Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 + Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 --remove Remove the plugin(s) from .tool-versions @@ -1869,23 +1869,23 @@ Options: Get the path of the config file Examples: - # set the current version of nodejs to 18.x for the current directory - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx local nodejs@18 + # set the current version of nodejs to 20.x for the current directory + # will use a precise version (e.g.: 20.0.0) in .tool-versions file + $ rtx local nodejs@20 - # set nodejs to 18.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@18 + # set nodejs to 20.x for the current project (recurses up to find .tool-versions) + $ rtx local -p nodejs@20 - # set the current version of nodejs to 18.x for the current directory - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx local --fuzzy nodejs@18 + # set the current version of nodejs to 20.x for the current directory + # will use a fuzzy version (e.g.: 20) in .tool-versions file + $ rtx local --fuzzy nodejs@20 # removes nodejs from .tool-versions $ rtx local --remove=nodejs # show the current version of nodejs in .tool-versions $ rtx local nodejs - 18.0.0 + 20.0.0 ``` ### `rtx ls [OPTIONS]` @@ -1909,24 +1909,24 @@ Options: Examples: $ rtx ls - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) python 3.10.0 $ rtx ls --current - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) $ rtx ls --parseable - nodejs 18.0.0 + nodejs 20.0.0 python 3.11.0 $ rtx ls --json { "nodejs": [ { - "version": "18.0.0", - "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", + "version": "20.0.0", + "install_path": "/Users/jdx/.rtx/installs/nodejs/20.0.0", "source": { "type": ".rtx.toml", "path": "/Users/jdx/.rtx.toml" @@ -1959,13 +1959,13 @@ Examples: 18.0.0 20.0.0 - $ rtx ls-remote nodejs@18 - 18.0.0 - 18.1.0 + $ rtx ls-remote nodejs@20 + 20.0.0 + 20.1.0 - $ rtx ls-remote nodejs 18 - 18.0.0 - 18.1.0 + $ rtx ls-remote nodejs 20 + 20.0.0 + 20.1.0 ``` ### `rtx plugins install [OPTIONS] [NAME] [GIT_URL]` @@ -1973,7 +1973,7 @@ Examples: Install a plugin note that rtx automatically can install plugins when you install a runtime -e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin +e.g.: `rtx install nodejs@20` will autoinstall the nodejs plugin This behavior can be modified in ~/.config/rtx/config.toml @@ -2144,8 +2144,8 @@ Options: Examples: $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 + rm -rf ~/.local/share/rtx/versions/nodejs/20.0.0 + rm -rf ~/.local/share/rtx/versions/nodejs/20.0.1 ``` ### `rtx reshim` @@ -2161,7 +2161,7 @@ Examples: $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim $ ~/.rtx/shims/node -v - v18.0.0 + v20.0.0 ``` ### `rtx self-update` @@ -2263,9 +2263,9 @@ Options: Removes a previously set version Examples: - $ rtx shell nodejs@18 + $ rtx shell nodejs@20 $ node -v - v18.0.0 + v20.0.0 ``` ### `rtx trust [OPTIONS] [CONFIG_FILE]` @@ -2339,13 +2339,13 @@ Arguments: Examples: # Show the latest installed version of nodejs # If it is is not installed, errors - $ rtx where nodejs@18 - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 + $ rtx where nodejs@20 + /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 # Show the current, active install directory of nodejs # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 + /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 ``` ### `rtx which [OPTIONS] ` @@ -2367,10 +2367,10 @@ Options: Examples: $ rtx which node - /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node + /home/username/.local/share/rtx/installs/nodejs/20.0.0/bin/node $ rtx which node --plugin nodejs $ rtx which node --version - 18.0.0 + 20.0.0 ``` diff --git a/completions/_rtx b/completions/_rtx index c30dbd630..548123721 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -596,7 +596,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to start e.g.\: nodejs@18 python@3.10:' \ +'*::runtime -- Runtime(s) to start e.g.\: nodejs@20 python@3.10:' \ && ret=0 ;; (global) @@ -608,9 +608,9 @@ default: 4]: : ' \ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to `~/.tool-versions` -e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions]' \ +e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions]' \ '--fuzzy[Save fuzzy version to `~/.tool-versions` -e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions +e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ '--debug[Sets log level to debug]' \ @@ -625,7 +625,7 @@ Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtime(s) to add to .tool-versions -e.g.\: nodejs@18 +e.g.\: nodejs@20 If this is a single runtime with no version, the current value of the global .tool-versions will be displayed:' \ && ret=0 @@ -699,7 +699,7 @@ Sets --jobs=1]' \ '--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Tool version(s) to install e.g.\: nodejs@18:' \ +'*::runtime -- Tool version(s) to install e.g.\: nodejs@20:' \ && ret=0 ;; (latest) @@ -737,8 +737,8 @@ by default this command will only set the runtime in the current directory ("$PW '--parent[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--pin[Save exact version to `.tool-versions` -e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions]' \ -'--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ +e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions]' \ +'--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the config file]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -752,7 +752,7 @@ Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtimes to add to .tool-versions/.rtx.toml -e.g.\: nodejs@18 +e.g.\: nodejs@20 if this is a single runtime with no version, the current value of .tool-versions/.rtx.toml will be displayed:' \ && ret=0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 92c30ba29..5457659c9 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -286,9 +286,9 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` -e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions' +e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` -e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions +e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' complete -c rtx -n "__fish_seen_subcommand_from global" -l debug -d 'Sets log level to debug' @@ -352,8 +352,8 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` -e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' +e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' complete -c rtx -n "__fish_seen_subcommand_from local" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from local" -l install-missing -d 'Automatically install missing tools' diff --git a/docs/nodejs.md b/docs/nodejs.md index 6d518feaa..54b2a9930 100644 --- a/docs/nodejs.md +++ b/docs/nodejs.md @@ -9,23 +9,23 @@ The code for this is inside of the rtx repository at [`./src/plugins/core/nodejs ## Usage -The following installs the latest version of nodejs-18.x and makes it the global +The following installs the latest version of nodejs-20.x and makes it the global default: ```sh-session -$ rtx install nodejs@18 -$ rtx global nodejs@18 +$ rtx install nodejs@20 +$ rtx global nodejs@20 ``` Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. ```sh-session -$ rtx global nodejs@16 nodejs@18 +$ rtx global nodejs@18 nodejs@20 $ nodejs -V -16.0.0 -$ nodejs.11 -V 18.0.0 +$ nodejs.11 -V +20.0.0 ``` ## Configuration diff --git a/e2e/.e2e-tool-versions b/e2e/.e2e-tool-versions index ae660fffb..b73e001f9 100644 --- a/e2e/.e2e-tool-versions +++ b/e2e/.e2e-tool-versions @@ -1,4 +1,4 @@ #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 18.13.0 +#nodejs 20.0.0 diff --git a/e2e/.node-version b/e2e/.node-version index 7eae4e2e9..e88320d7c 100644 --- a/e2e/.node-version +++ b/e2e/.node-version @@ -1 +1 @@ -18.0.0 +20.0.0 diff --git a/e2e/cd/.e2e-tool-versions b/e2e/cd/.e2e-tool-versions index b00f5981f..6de89a83a 100644 --- a/e2e/cd/.e2e-tool-versions +++ b/e2e/cd/.e2e-tool-versions @@ -1 +1 @@ -nodejs 18.0.0 +nodejs 20.0.0 diff --git a/e2e/cd/16/.e2e-tool-versions b/e2e/cd/16/.e2e-tool-versions deleted file mode 100644 index 35830be2c..000000000 --- a/e2e/cd/16/.e2e-tool-versions +++ /dev/null @@ -1 +0,0 @@ -nodejs 16.0.0 diff --git a/e2e/cd/16/.e2e.rtx.toml b/e2e/cd/16/.e2e.rtx.toml deleted file mode 100644 index 1907f4e2f..000000000 --- a/e2e/cd/16/.e2e.rtx.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -FOO = "16" diff --git a/e2e/cd/18/.e2e-tool-versions b/e2e/cd/18/.e2e-tool-versions new file mode 100644 index 000000000..b00f5981f --- /dev/null +++ b/e2e/cd/18/.e2e-tool-versions @@ -0,0 +1 @@ +nodejs 18.0.0 diff --git a/e2e/cd/18/.e2e.rtx.toml b/e2e/cd/18/.e2e.rtx.toml new file mode 100644 index 000000000..6e8bd90d3 --- /dev/null +++ b/e2e/cd/18/.e2e.rtx.toml @@ -0,0 +1,2 @@ +[env] +FOO = "18" diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 0aca881c2..4e5732621 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -6,7 +6,7 @@ orig_path="$PATH" rtx trust rtx trust ../.e2e.rtx.toml -rtx trust 16/.e2e.rtx.toml +rtx trust 18/.e2e.rtx.toml # shellcheck disable=SC1090 eval "$(rtx activate bash --status)" && _rtx_hook @@ -33,21 +33,21 @@ assert_path() { fi } -test "$(node -v)" = "v18.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/18.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +test "$(node -v)" = "v20.0.0" +assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" assert "$FOO" "cd" -cd 16 && _rtx_hook -test "$(node -v)" = "v16.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/16.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" -assert "$FOO" "16" +cd 18 && _rtx_hook +test "$(node -v)" = "v18.0.0" +assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/18.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +assert "$FOO" "18" cd .. && _rtx_hook -test "$(node -v)" = "v18.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/18.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +test "$(node -v)" = "v20.0.0" +assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" -rtx shell nodejs@16.0.0 && _rtx_hook -test "$(node -v)" = "v16.0.0" +rtx shell nodejs@18.0.0 && _rtx_hook +test "$(node -v)" = "v18.0.0" rtx deactivate assert_path "" diff --git a/e2e/cd/test_bash_legacy_activate b/e2e/cd/test_bash_legacy_activate index 9a03ecb37..3ca8a3622 100755 --- a/e2e/cd/test_bash_legacy_activate +++ b/e2e/cd/test_bash_legacy_activate @@ -1,17 +1,17 @@ #!/usr/bin/env bash set -euo pipefail -rtx install nodejs@18.0.0 nodejs@16.0.0 +rtx install nodejs@20.0.0 nodejs@18.0.0 # shellcheck disable=SC1090 eval "$(rtx activate -s bash --status)" _rtx_hook #rtx install -test "$(node -v)" = "v18.0.0" +test "$(node -v)" = "v20.0.0" -cd 16 && _rtx_hook +cd 18 && _rtx_hook #rtx install -test "$(node -v)" = "v16.0.0" +test "$(node -v)" = "v18.0.0" cd .. && _rtx_hook -test "$(node -v)" = "v18.0.0" +test "$(node -v)" = "v20.0.0" diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index 42cb29341..9abe9deb4 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -5,21 +5,21 @@ set -gx PATH $ROOT/target/debug:$PATH set -l orig_node (node -v) #set -l fish_trace 1 -rtx install nodejs@18.0.0 nodejs@16.0.0; or exit +rtx install nodejs@20.0.0 nodejs@18.0.0; or exit rtx activate --status fish | source __rtx_env_eval -test (node -v) = "v18.0.0"; or exit +test (node -v) = "v20.0.0"; or exit -cd 16 && __rtx_env_eval -test (node -v) = "v16.0.0"; or exit +cd 18 && __rtx_env_eval +test (node -v) = "v18.0.0"; or exit cd .. && __rtx_env_eval -test (node -v) = "v18.0.0"; or exit +test (node -v) = "v20.0.0"; or exit -rtx shell nodejs@16.0.0 && __rtx_env_eval -test (node -v) = "v16.0.0"; or exit +rtx shell nodejs@18.0.0 && __rtx_env_eval +test (node -v) = "v18.0.0"; or exit rtx deactivate test (node -v) = $orig_node; or exit diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index 6b88fddfa..b0809221b 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -14,22 +14,22 @@ assert_path() { fi } -rtx install nodejs@18.0.0 nodejs@16.0.0 +rtx install nodejs@20.0.0 nodejs@18.0.0 # shellcheck disable=SC1090 eval "$(rtx activate zsh --status)" && _rtx_hook #rtx install -test "$(node -v)" = "v18.0.0" +test "$(node -v)" = "v20.0.0" -cd 16 && _rtx_hook +cd 18 && _rtx_hook #rtx install -test "$(node -v)" = "v16.0.0" +test "$(node -v)" = "v18.0.0" cd .. && _rtx_hook -test "$(node -v)" = "v18.0.0" +test "$(node -v)" = "v20.0.0" -rtx shell nodejs@16.0.0 && _rtx_hook -test "$(node -v)" = "v16.0.0" +rtx shell nodejs@18.0.0 && _rtx_hook +test "$(node -v)" = "v18.0.0" rtx deactivate assert_path "" diff --git a/e2e/config/.e2e-tool-versions b/e2e/config/.e2e-tool-versions index ae660fffb..b73e001f9 100644 --- a/e2e/config/.e2e-tool-versions +++ b/e2e/config/.e2e-tool-versions @@ -1,4 +1,4 @@ #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 18.13.0 +#nodejs 20.0.0 diff --git a/e2e/config/.node-version b/e2e/config/.node-version index 7eae4e2e9..e88320d7c 100644 --- a/e2e/config/.node-version +++ b/e2e/config/.node-version @@ -1 +1 @@ -18.0.0 +20.0.0 diff --git a/e2e/config/cd/.e2e-tool-versions b/e2e/config/cd/.e2e-tool-versions index b00f5981f..6de89a83a 100644 --- a/e2e/config/cd/.e2e-tool-versions +++ b/e2e/config/cd/.e2e-tool-versions @@ -1 +1 @@ -nodejs 18.0.0 +nodejs 20.0.0 diff --git a/e2e/config/cd/16/.e2e-tool-versions b/e2e/config/cd/16/.e2e-tool-versions deleted file mode 100644 index 35830be2c..000000000 --- a/e2e/config/cd/16/.e2e-tool-versions +++ /dev/null @@ -1 +0,0 @@ -nodejs 16.0.0 diff --git a/e2e/config/cd/16/.e2e.rtx.toml b/e2e/config/cd/16/.e2e.rtx.toml deleted file mode 100644 index 1907f4e2f..000000000 --- a/e2e/config/cd/16/.e2e.rtx.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -FOO = "16" diff --git a/e2e/config/cd/18/.e2e-tool-versions b/e2e/config/cd/18/.e2e-tool-versions new file mode 100644 index 000000000..b00f5981f --- /dev/null +++ b/e2e/config/cd/18/.e2e-tool-versions @@ -0,0 +1 @@ +nodejs 18.0.0 diff --git a/e2e/config/cd/18/.e2e.rtx.toml b/e2e/config/cd/18/.e2e.rtx.toml new file mode 100644 index 000000000..6e8bd90d3 --- /dev/null +++ b/e2e/config/cd/18/.e2e.rtx.toml @@ -0,0 +1,2 @@ +[env] +FOO = "18" diff --git a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions index 35830be2c..b00f5981f 100644 --- a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions +++ b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions @@ -1 +1 @@ -nodejs 16.0.0 +nodejs 18.0.0 diff --git a/e2e/direnv/system_version/test_direnv_system_version b/e2e/direnv/system_version/test_direnv_system_version index be3ca8c90..4bbfc8484 100755 --- a/e2e/direnv/system_version/test_direnv_system_version +++ b/e2e/direnv/system_version/test_direnv_system_version @@ -8,7 +8,7 @@ _rtx_hook && _direnv_hook # prepare # use old node version on purpose to not conflict with unknown system node version -custom_node_version="16.0.0" +custom_node_version="18.0.0" rtx_nodejs_path_segment="${RTX_DATA_DIR}/installs/nodejs" # with nodejs@system rtx should not add a nodejs path segment diff --git a/e2e/run_test b/e2e/run_test index b5e7e1963..4a69ee409 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -19,11 +19,11 @@ setup_env() { } setup_config_files() { - mkdir -p "$ROOT/e2e/cd/16" + mkdir -p "$ROOT/e2e/cd/18" cp "$ROOT/e2e/config/".e2e.* "$ROOT/e2e/" cp "$ROOT/e2e/config/"{.node-version,.alternate-tool-versions,.test-env} "$ROOT/e2e/" cp "$ROOT/e2e/config/cd/".e2e.* "$ROOT/e2e/cd/" - cp "$ROOT/e2e/config/cd/16/".e2e.* "$ROOT/e2e/cd/16" + cp "$ROOT/e2e/config/cd/18/".e2e.* "$ROOT/e2e/cd/18" } run_test() { diff --git a/e2e/test_env b/e2e/test_env index c4214ad26..23644601e 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -4,8 +4,8 @@ source "$(dirname "$0")/assert.sh" rtx i nodejs eval "$(rtx env -s bash)" +assert "node -v" "v20.0.0" +rtx i nodejs@18.0.0 +eval "$(rtx env -s bash nodejs@18.0.0)" assert "node -v" "v18.0.0" -rtx i nodejs@16.0.0 -eval "$(rtx env -s bash nodejs@16.0.0)" -assert "node -v" "v16.0.0" assert "rtx x -- env | grep FOO_FROM_FILE" "FOO_FROM_FILE=foo_from_file" diff --git a/e2e/test_local b/e2e/test_local index 5bd8f024f..ea25bf085 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -87,14 +87,14 @@ rtx local --install-missing assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 18.13.0 +#nodejs 20.0.0 " rtx local shfmt@3.5.0 assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.5.0 # test comment -#nodejs 18.13.0 +#nodejs 20.0.0 " rtx exec -- shfmt --version >&2 @@ -106,7 +106,7 @@ rtx local shfmt@3.6.0 assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 18.13.0 +#nodejs 20.0.0 " rtx exec -- shfmt --version >&2 diff --git a/e2e/test_log_level b/e2e/test_log_level index f87aef233..b93f5564c 100755 --- a/e2e/test_log_level +++ b/e2e/test_log_level @@ -10,7 +10,7 @@ assert() { fi } -assert "rtx x nodejs@18.0.0 --log-level debug -- node -v" "v18.0.0" -assert "rtx x nodejs@18.0.0 --log-level=debug -- node -v" "v18.0.0" -assert "rtx x nodejs@18.0.0 --debug -- node -v" "v18.0.0" -assert "rtx x nodejs@18.0.0 --trace -- node -v" "v18.0.0" +assert "rtx x nodejs@20.0.0 --log-level debug -- node -v" "v20.0.0" +assert "rtx x nodejs@20.0.0 --log-level=debug -- node -v" "v20.0.0" +assert "rtx x nodejs@20.0.0 --debug -- node -v" "v20.0.0" +assert "rtx x nodejs@20.0.0 --trace -- node -v" "v20.0.0" diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 6784a9b90..274cdae55 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -8,5 +8,5 @@ export RTX_NODEJS_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-nodejs-packages" rtx plugin uninstall nodejs rtx i nodejs nodejs@lts/hydrogen assert_contains "rtx x nodejs@lts/hydrogen -- node --version" "v18." -assert "rtx x -- node --version" "v18.0.0" +assert "rtx x -- node --version" "v20.0.0" assert_contains "rtx nodejs nodebuild --version" "node-build " diff --git a/e2e/test_shell b/e2e/test_shell index 99ac54e6d..0b200921c 100755 --- a/e2e/test_shell +++ b/e2e/test_shell @@ -4,8 +4,8 @@ source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 eval "$(rtx activate bash)" && eval "$(rtx hook-env)" +assert "node -v" "v20.0.0" +rtx shell nodejs@18.0.0 && eval "$(rtx hook-env)" assert "node -v" "v18.0.0" -rtx shell nodejs@16.0.0 && eval "$(rtx hook-env)" -assert "node -v" "v16.0.0" -export RTX_NODEJS_VERSION=18.0.0 && eval "$(rtx hook-env)" -assert "node -v" "v18.0.0" +export RTX_NODEJS_VERSION=20.0.0 && eval "$(rtx hook-env)" +assert "node -v" "v20.0.0" diff --git a/e2e/test_shims b/e2e/test_shims index ba7a09535..008b8d251 100755 --- a/e2e/test_shims +++ b/e2e/test_shims @@ -13,6 +13,6 @@ assert() { rtx settings set experimental true rtx settings set shims_dir "$RTX_DATA_DIR/shims" rtx reshim -assert "$RTX_DATA_DIR/shims/node -v" "v18.0.0" +assert "$RTX_DATA_DIR/shims/node -v" "v20.0.0" rtx settings unset experimental rtx settings unset shims_dir diff --git a/justfile b/justfile index 1501cbdff..c7b62c400 100644 --- a/justfile +++ b/justfile @@ -96,7 +96,8 @@ lint-fix: # regenerate README.md render-help: build NO_COLOR=1 rtx render-help - npx markdown-magic + #npx markdown-magic + md-magic # regenerate shell completion files render-completions: build diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 99d868375..b9cbb6393 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -128,16 +128,16 @@ rtx\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA Examples: - $ rtx install nodejs@18.0.0 Install a specific node version - $ rtx install nodejs@18.0 Install a version matching a prefix + $ rtx install nodejs@20.0.0 Install a specific node version + $ rtx install nodejs@20.0 Install a version matching a prefix $ rtx install nodejs Install the node version defined in .tool\-versions or .rtx.toml - $ rtx local nodejs@18 Use node\-18.x in current project - $ rtx global nodejs@18 Use node\-18.x as default + $ rtx local nodejs@20 Use node\-20.x in current project + $ rtx global nodejs@20 Use node\-20.x as default $ rtx local nodejs@latest Use latest node in current directory $ rtx global nodejs@system Use system node everywhere unless overridden - $ rtx x nodejs@18 \-\- node app.js Run `node app.js` with PATH pointing to - node\-18.x + $ rtx x nodejs@20 \-\- node app.js Run `node app.js` with PATH pointing to + node\-20.x .SH VERSION v1.28.5 .SH AUTHORS diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index 29e7d093d..a4d53f072 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -34,7 +34,7 @@ def install test do system "#{bin}/rtx --version" - system "#{bin}/rtx", "install", "nodejs@18.13.0" - assert_match "v18.13.0", shell_output("#{bin}/rtx exec nodejs@18.13.0 -- node -v") + system "#{bin}/rtx", "install", "nodejs@20.0.0" + assert_match "v20.0.0", shell_output("#{bin}/rtx exec nodejs@20.0.0 -- node -v") end end diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 3d7bc69e6..c63beb1db 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -32,7 +32,7 @@ impl Command for AliasGet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx alias get nodejs lts/hydrogen - 18.0.0 + 20.0.0 "# ); diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 9321b690f..9dea69044 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -12,7 +12,7 @@ use crate::plugins::PluginName; /// For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: /// /// [alias.nodejs] -/// lts = "18.0.0" +/// lts = "20.0.0" #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasLs { @@ -41,7 +41,7 @@ impl Command for AliasLs { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx aliases - nodejs lts/hydrogen 18.0.0 + nodejs lts/hydrogen 20.0.0 "# ); diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index 849771726..fbfeb4579 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -29,9 +29,9 @@ impl RuntimeArg { } /// this handles the case where the user typed in: - /// rtx local nodejs 18.0.0 + /// rtx local nodejs 20.0.0 /// instead of - /// rtx local nodejs@18.0.0 + /// rtx local nodejs@20.0.0 /// /// We can detect this, and we know what they meant, so make it work the way /// they expected. diff --git a/src/cli/current.rs b/src/cli/current.rs index 3c33201ab..4de310949 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -105,10 +105,10 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( python 3.11.0 3.10.0 shfmt 3.6.0 shellcheck 0.9.0 - nodejs 18.13.0 + nodejs 20.0.0 $ rtx current nodejs - 18.13.0 + 20.0.0 # can output multiple versions $ rtx current python diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 96bf56d54..4de2d5a5b 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -23,14 +23,14 @@ use crate::toolset::ToolsetBuilder; /// /// Runtimes will be loaded from .tool-versions, though they can be overridden with args /// Note that only the plugin specified will be overridden, so if a `.tool-versions` file -/// includes "nodejs 18" but you run `rtx exec python@3.11`; it will still load nodejs@18. +/// includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. /// /// The "--" separates runtimes from the commands to pass along to the subprocess. #[derive(Debug, clap::Args)] #[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Exec { /// Runtime(s) to start - /// e.g.: nodejs@18 python@3.10 + /// e.g.: nodejs@20 python@3.10 #[clap(value_parser = RuntimeArgParser)] pub runtime: Vec, @@ -125,14 +125,14 @@ fn parse_command( static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx exec nodejs@18 -- node ./app.js # launch app.js using node-18.x - $ rtx x nodejs@18 -- node ./app.js # shorter alias + $ rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x + $ rtx x nodejs@20 -- node ./app.js # shorter alias # Specify command as a string: - $ rtx exec nodejs@18 python@3.11 --command "node -v && python -V" + $ rtx exec nodejs@20 python@3.11 --command "node -v && python -V" # Run a command in a different directory: - $ rtx x -C /path/to/project nodejs@18 -- node ./app.js + $ rtx x -C /path/to/project nodejs@20 -- node ./app.js "# ); diff --git a/src/cli/global.rs b/src/cli/global.rs index 446a25b9c..f20ccb5fd 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -23,19 +23,19 @@ use crate::{dirs, env}; #[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP)] pub struct Global { /// Runtime(s) to add to .tool-versions - /// e.g.: nodejs@18 + /// e.g.: nodejs@20 /// If this is a single runtime with no version, the current value of the global /// .tool-versions will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, /// Save exact version to `~/.tool-versions` - /// e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to ~/.tool-versions + /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `~/.tool-versions` - /// e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to ~/.tool-versions + /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, @@ -76,17 +76,17 @@ fn global_file() -> PathBuf { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # set the current version of nodejs to 18.x - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx global --fuzzy nodejs@18 + # set the current version of nodejs to 20.x + # will use a fuzzy version (e.g.: 20) in .tool-versions file + $ rtx global --fuzzy nodejs@20 - # set the current version of nodejs to 18.x - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx global --pin nodejs@18 + # set the current version of nodejs to 20.x + # will use a precise version (e.g.: 20.0.0) in .tool-versions file + $ rtx global --pin nodejs@20 # show the current version of nodejs in ~/.tool-versions $ rtx global nodejs - 18.0.0 + 20.0.0 "# ); diff --git a/src/cli/install.rs b/src/cli/install.rs index 9f32337cc..88e437045 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -34,7 +34,7 @@ use crate::ui::progress_report::ProgressReport; #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Install { /// Tool version(s) to install - /// e.g.: nodejs@18 + /// e.g.: nodejs@20 #[clap(value_parser = RuntimeArgParser)] runtime: Option>, @@ -246,8 +246,8 @@ impl Install { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx install nodejs@18.0.0 # install specific nodejs version - $ rtx install nodejs@18 # install fuzzy nodejs version + $ rtx install nodejs@20.0.0 # install specific nodejs version + $ rtx install nodejs@20 # install fuzzy nodejs version $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml $ rtx install # installs everything specified in .tool-versions or .rtx.toml "# diff --git a/src/cli/latest.rs b/src/cli/latest.rs index c7e09045f..8202105bf 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -54,8 +54,8 @@ impl Command for Latest { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx latest nodejs@18 # get the latest version of nodejs 18 - 18.0.0 + $ rtx latest nodejs@20 # get the latest version of nodejs 20 + 20.0.0 $ rtx latest nodejs # get the latest stable version of nodejs 20.0.0 diff --git a/src/cli/local.rs b/src/cli/local.rs index 1490d9cd5..69946b6a7 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -22,7 +22,7 @@ use crate::{dirs, env, file}; #[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP)] pub struct Local { /// Runtimes to add to .tool-versions/.rtx.toml - /// e.g.: nodejs@18 + /// e.g.: nodejs@20 /// if this is a single runtime with no version, /// the current value of .tool-versions/.rtx.toml will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] @@ -34,12 +34,12 @@ pub struct Local { parent: bool, /// Save exact version to `.tool-versions` - /// e.g.: `rtx local --pin nodejs@18` will save `nodejs 18.0.0` to .tool-versions + /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `.tool-versions` - /// e.g.: `rtx local --fuzzy nodejs@18` will save `nodejs 18` to .tool-versions + /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions /// This is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, @@ -152,23 +152,23 @@ fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result< static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # set the current version of nodejs to 18.x for the current directory - # will use a precise version (e.g.: 18.0.0) in .tool-versions file - $ rtx local nodejs@18 + # set the current version of nodejs to 20.x for the current directory + # will use a precise version (e.g.: 20.0.0) in .tool-versions file + $ rtx local nodejs@20 - # set nodejs to 18.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@18 + # set nodejs to 20.x for the current project (recurses up to find .tool-versions) + $ rtx local -p nodejs@20 - # set the current version of nodejs to 18.x for the current directory - # will use a fuzzy version (e.g.: 18) in .tool-versions file - $ rtx local --fuzzy nodejs@18 + # set the current version of nodejs to 20.x for the current directory + # will use a fuzzy version (e.g.: 20) in .tool-versions file + $ rtx local --fuzzy nodejs@20 # removes nodejs from .tool-versions $ rtx local --remove=nodejs # show the current version of nodejs in .tool-versions $ rtx local nodejs - 18.0.0 + 20.0.0 "# ); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 37bca3191..74898479d 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -279,24 +279,24 @@ impl Display for VersionStatus { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx ls - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) python 3.10.0 $ rtx ls --current - ⏵ nodejs 18.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) $ rtx ls --parseable - nodejs 18.0.0 + nodejs 20.0.0 python 3.11.0 $ rtx ls --json { "nodejs": [ { - "version": "18.0.0", - "install_path": "/Users/jdx/.rtx/installs/nodejs/18.0.0", + "version": "20.0.0", + "install_path": "/Users/jdx/.rtx/installs/nodejs/20.0.0", "source": { "type": ".rtx.toml", "path": "/Users/jdx/.rtx.toml" diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 4f740d592..5a1fb3d1c 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -86,13 +86,13 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( 18.0.0 20.0.0 - $ rtx ls-remote nodejs@18 - 18.0.0 - 18.1.0 + $ rtx ls-remote nodejs@20 + 20.0.0 + 20.1.0 - $ rtx ls-remote nodejs 18 - 18.0.0 - 18.1.0 + $ rtx ls-remote nodejs 20 + 20.0.0 + 20.1.0 "# ); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index bce3df334..c943a611e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -243,16 +243,16 @@ https://asdf-vm.com/"}; static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx install nodejs@18.0.0 Install a specific node version - $ rtx install nodejs@18.0 Install a version matching a prefix + $ rtx install nodejs@20.0.0 Install a specific node version + $ rtx install nodejs@20.0 Install a version matching a prefix $ rtx install nodejs Install the node version defined in .tool-versions or .rtx.toml - $ rtx local nodejs@18 Use node-18.x in current project - $ rtx global nodejs@18 Use node-18.x as default + $ rtx local nodejs@20 Use node-20.x in current project + $ rtx global nodejs@20 Use node-20.x as default $ rtx local nodejs@latest Use latest node in current directory $ rtx global nodejs@system Use system node everywhere unless overridden - $ rtx x nodejs@18 -- node app.js Run `node app.js` with PATH pointing to - node-18.x + $ rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to + node-20.x "# ); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index a0d72fb69..99b7b1541 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -14,7 +14,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Install a plugin /// /// note that rtx automatically can install plugins when you install a runtime -/// e.g.: `rtx install nodejs@18` will autoinstall the nodejs plugin +/// e.g.: `rtx install nodejs@20` will autoinstall the nodejs plugin /// /// This behavior can be modified in ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 9cd44b156..003c2b864 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -73,8 +73,8 @@ impl Prune { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.0 - rm -rf ~/.local/share/rtx/versions/nodejs/18.0.1 + rm -rf ~/.local/share/rtx/versions/nodejs/20.0.0 + rm -rf ~/.local/share/rtx/versions/nodejs/20.0.1 "# ); diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 7def19cb1..90c820809 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -48,6 +48,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim $ ~/.rtx/shims/node -v - v18.0.0 + v20.0.0 "# ); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index cf97a8dda..5d1ba90a9 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -64,9 +64,9 @@ fn err_inactive() -> Result<()> { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx shell nodejs@18 + $ rtx shell nodejs@20 $ node -v - v18.0.0 + v20.0.0 "# ); diff --git a/src/cli/where.rs b/src/cli/where.rs index 9cb7cff6e..e5d304bff 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -75,13 +75,13 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # Show the latest installed version of nodejs # If it is is not installed, errors - $ rtx where nodejs@18 - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 + $ rtx where nodejs@20 + /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 # Show the current, active install directory of nodejs # Errors if nodejs is not referenced in any .tool-version file $ rtx where nodejs - /home/jdx/.local/share/rtx/installs/nodejs/18.0.0 + /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 "# ); diff --git a/src/cli/which.rs b/src/cli/which.rs index 898bff66e..49a91e59c 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -45,11 +45,11 @@ impl Command for Which { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx which node - /home/username/.local/share/rtx/installs/nodejs/18.0.0/bin/node + /home/username/.local/share/rtx/installs/nodejs/20.0.0/bin/node $ rtx which node --plugin nodejs $ rtx which node --version - 18.0.0 + 20.0.0 "# ); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index e2d1f2d0f..223b8ee6c 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -27,14 +27,14 @@ Toolset { ( Version( "nodejs", - "16", + "18", ), {}, ), ( Prefix( "nodejs", - "18", + "20", ), {}, ), @@ -48,7 +48,7 @@ Toolset { ( Path( "nodejs", - "~/.nodes/14", + "~/.nodes/18", ), {}, ), diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index 16c08f5dc..fae0b15ac 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -7,7 +7,7 @@ NODE_ENV = 'production' [tools] terraform = '1.0.0' -nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] +nodejs = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18'] jq = { prefix = '1.6' } shellcheck = { version = '0.9.0' } python = [ diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml index a008eafce..2a0c1c46a 100644 --- a/test/fixtures/.rtx.toml +++ b/test/fixtures/.rtx.toml @@ -3,7 +3,7 @@ NODE_ENV = 'production' [tools] terraform = '1.0.0' -nodejs = ['16', 'prefix:18', 'ref:master', 'path:~/.nodes/14'] +nodejs = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18'] jq = { prefix = '1.6' } shellcheck = { version = '0.9.0' } python = [ From dd5afdc77cbbd33df6c16de0563c032f4de7129f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 19 Apr 2023 20:47:43 -0500 Subject: [PATCH 0704/1891] check node/python versions after installing (#496) --- src/plugins/core/nodejs.rs | 11 +++++++++++ src/plugins/core/python.rs | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/nodejs.rs index eb994c412..2c3262ff1 100644 --- a/src/plugins/core/nodejs.rs +++ b/src/plugins/core/nodejs.rs @@ -87,6 +87,10 @@ impl NodeJSPlugin { Ok(versions) } + fn node_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/node") + } + fn npm_path(&self, tv: &ToolVersion) -> PathBuf { tv.install_path().join("bin/npm") } @@ -115,6 +119,12 @@ impl NodeJSPlugin { } Ok(()) } + + fn test_node(&self, config: &&Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + let mut cmd = CmdLineRunner::new(&config.settings, self.node_path(tv)); + cmd.with_pr(pr).arg("-v"); + cmd.execute() + } } impl Plugin for NodeJSPlugin { @@ -177,6 +187,7 @@ impl Plugin for NodeJSPlugin { } cmd.arg(tv.install_path()); cmd.execute()?; + self.test_node(&config, tv, pr)?; self.install_default_packages(&config.settings, tv, pr)?; Ok(()) } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 817b9fe78..511b2f7b4 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -142,6 +142,12 @@ impl PythonPlugin { let symlink_target = symlink.read_link().unwrap_or_default(); Ok(symlink_target == target) } + + fn test_python(&self, config: &&Config, tv: &ToolVersion) -> Result<()> { + let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)); + cmd.arg("--version"); + cmd.execute() + } } impl Plugin for PythonPlugin { @@ -194,6 +200,7 @@ impl Plugin for PythonPlugin { } } cmd.execute()?; + self.test_python(&config, tv)?; self.get_virtualenv(config, tv, Some(pr))?; self.install_default_packages(&config.settings, tv, pr)?; Ok(()) From 1d72e686fd2a3a85aa9d4860b28f73ae12def864 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 19 Apr 2023 21:40:27 -0500 Subject: [PATCH 0705/1891] unhiding current command (#497) I feel this has some utility even with the changes to `rtx ls`. Without this, there is not an easy command to just get the current version of a plugin with nothing else --- README.md | 30 ++++++++++++++++++++++++++++++ man/man1/rtx.1 | 3 +++ src/cli/current.rs | 6 +----- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a964d5128..cdfb7f697 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ v20.0.0 - [`rtx bin-paths`](#rtx-bin-paths) - [`rtx cache clear`](#rtx-cache-clear) - [`rtx completion [SHELL]`](#rtx-completion-shell) + - [`rtx current [PLUGIN]`](#rtx-current-plugin) - [`rtx deactivate`](#rtx-deactivate) - [`rtx direnv activate`](#rtx-direnv-activate) - [`rtx doctor`](#rtx-doctor) @@ -1600,6 +1601,35 @@ Examples: $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx $ rtx completion fish > ~/.config/fish/completions/rtx.fish ``` +### `rtx current [PLUGIN]` + +``` +Shows current active and installed runtime versions + +This is similar to `rtx ls --current`, but this only shows the runtime +and/or version. It's designed to fit into scripts more easily. + +Usage: current [PLUGIN] + +Arguments: + [PLUGIN] + Plugin to show versions of e.g.: ruby, nodejs + +Examples: + # outputs `.tool-versions` compatible format + $ rtx current + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + nodejs 20.0.0 + + $ rtx current nodejs + 20.0.0 + + # can output multiple versions + $ rtx current python + 3.11.0 3.10.0 +``` ### `rtx deactivate` ``` diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index b9cbb6393..97f2cfce0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -55,6 +55,9 @@ Manage the rtx cache rtx\-completion(1) Generate shell completions .TP +rtx\-current(1) +Shows current active and installed runtime versions +.TP rtx\-deactivate(1) Disable rtx for current shell session .TP diff --git a/src/cli/current.rs b/src/cli/current.rs index 4de310949..fb4501ccd 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -11,12 +11,8 @@ use crate::toolset::{Toolset, ToolsetBuilder}; /// /// This is similar to `rtx ls --current`, but this only shows the runtime /// and/or version. It's designed to fit into scripts more easily. -/// -/// This command is currently hidden as we may be able to merge it with `ls` -/// and it's confusing to have two commands that do similar things. -/// It will probably never be removed in order to retain some compatibility with asdf. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, hide = true, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Current { /// Plugin to show versions of /// e.g.: ruby, nodejs From 4fba7fe950d3a7556df3486b8b29b6256f57ba7a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 19 Apr 2023 21:56:06 -0500 Subject: [PATCH 0706/1891] chore: Release --- Cargo.lock | 48 +++++++++++++++++++-------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 6 ++++- 7 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f027f7a5..2398dbe53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.2" +version = "4.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a" +checksum = "956ac1f6381d8d82ab4684768f89c0ea3afe66925ceadb4eeb3fc452ffc55d62" dependencies = [ "clap_builder", "clap_derive", @@ -217,9 +217,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.2.2" +version = "4.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6" +checksum = "84080e799e54cff944f4b4a4b0e71630b0e0443b25b985175c7dddc1a859b749" dependencies = [ "anstream", "anstyle", @@ -246,7 +246,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -436,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" dependencies = [ "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -473,7 +473,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -490,7 +490,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -803,9 +803,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" dependencies = [ "bytes", "fnv", @@ -889,9 +889,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -1148,9 +1148,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" [[package]] name = "log" @@ -1357,7 +1357,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -1586,7 +1586,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.28.5" +version = "1.28.6" dependencies = [ "base64", "built", @@ -1639,15 +1639,15 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.11" +version = "0.37.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +checksum = "722529a737f5a942fdbac3a46cee213053196737c5eaa3386d52e85b786f2659" dependencies = [ "bitflags", "errno 0.3.1", @@ -1759,7 +1759,7 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -1903,9 +1903,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.14" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -1978,7 +1978,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1454ff184..bbc106834 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.28.5" +version = "1.28.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index cdfb7f697..26f8c7042 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.28.5 +rtx 1.28.6 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -330,7 +330,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.28.5/rtx-v1.28.5-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.28.6/rtx-v1.28.6-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 76ff90d4f..67156e67d 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.28.5"; + version = "1.28.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 97f2cfce0..04350d10e 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.28.5" +.TH rtx 1 "rtx 1.28.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: $ rtx x nodejs@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.28.5 +v1.28.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c8bb86938..d3e2d6c04 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.28.5 +Version: 1.28.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 4cf02c43d..fa3db85f8 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 642] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 646] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -126,6 +126,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 642] = [ ("ctlptl", "https://github.com/ezcater/asdf-ctlptl.git"), ("ctop", "https://github.com/NeoHsu/asdf-ctop.git"), ("cue", "https://github.com/asdf-community/asdf-cue.git"), + ("cyclonedx", "https://github.com/xeedio/asdf-cyclonedx.git"), ("dagger", "https://github.com/virtualstaticvoid/asdf-dagger.git"), ("dart", "https://github.com/PatOConnor43/asdf-dart.git"), ("dasel", "https://github.com/asdf-community/asdf-dasel.git"), @@ -186,6 +187,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 642] = [ ("firebase", "https://github.com/jthegedus/asdf-firebase.git"), ("fission", "https://github.com/virtualstaticvoid/asdf-fission.git"), ("flarectl", "https://github.com/ORCID/asdf-flarectl.git"), + ("flatc", "https://github.com/TheOpenDictionary/asdf-flatc.git"), ("flutter", "https://github.com/oae/asdf-flutter.git"), ("flux2", "https://github.com/tablexi/asdf-flux2.git"), ("fluxctl", "https://github.com/stefansedich/asdf-fluxctl.git"), @@ -422,6 +424,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 642] = [ ("oci", "https://github.com/yasn77/asdf-oci.git"), ("odin", "https://github.com/jtakakura/asdf-odin"), ("odo", "https://github.com/rm3l/asdf-odo.git"), + ("okta-aws-cli", "https://github.com/bennythejudge/asdf-plugin-okta-aws-cli.git"), ("okteto", "https://github.com/BradenM/asdf-okteto"), ("om", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("opa", "https://github.com/tochukwuvictor/asdf-opa.git"), @@ -512,6 +515,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 642] = [ ("skaffold", "https://github.com/nklmilojevic/asdf-skaffold.git"), ("skate", "https://github.com/chessmango/asdf-skate.git"), ("sloth", "https://github.com/slok/asdf-sloth.git"), + ("smithy", "https://github.com/aws/asdf-smithy.git"), ("smlnj", "https://github.com/samontea/asdf-smlnj.git"), ("snyk", "https://github.com/nirfuchs/asdf-snyk.git"), ("soft-serve", "https://github.com/chessmango/asdf-soft-serve.git"), From d56bd474d40c4bb7691b7455c67ea78c7df28e9f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 21 Apr 2023 14:55:53 -0500 Subject: [PATCH 0707/1891] split coverage into separate jobs for faster tests (#498) --- .github/workflows/rtx.yml | 8 ++++++++ e2e/.default-python-packages | 1 + e2e/cd/test_zsh | 4 ++++ e2e/run_all_tests | 11 ++++++++++- e2e/run_test | 2 ++ e2e/test_python | 9 +++++++++ e2e/test_zigmod | 10 +--------- justfile | 17 +++++++++-------- src/cli/install.rs | 18 +++++++++++++++--- src/plugins/core/nodejs.rs | 10 ++++++++++ src/tool.rs | 6 ++++++ 11 files changed, 75 insertions(+), 21 deletions(-) create mode 100644 e2e/.default-python-packages create mode 100755 e2e/test_python diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 155c6790d..729a7dc99 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -36,8 +36,13 @@ jobs: - run: cargo deny check coverage: + name: coverage-${{matrix.tranche}} runs-on: ubuntu-latest timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + tranche: [0, 1, 2, 3] steps: - name: Checkout uses: actions/checkout@v3 @@ -45,6 +50,7 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@v2 with: + shared-key: coverage save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cargo-llvm-cov - name: Install zsh/fish/direnv @@ -57,6 +63,8 @@ jobs: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" RTX_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + TEST_TRANCHE: ${{matrix.tranche}} + TEST_TRANCHE_COUNT: 4 with: timeout_minutes: 20 max_attempts: 3 diff --git a/e2e/.default-python-packages b/e2e/.default-python-packages new file mode 100644 index 000000000..90d40550b --- /dev/null +++ b/e2e/.default-python-packages @@ -0,0 +1 @@ +ansible diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index b0809221b..4638f2eca 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -2,6 +2,10 @@ set -euo pipefail orig_path="$PATH" +rtx trust +rtx trust ../.e2e.rtx.toml +rtx trust 18/.e2e.rtx.toml + assert_path() { local expected="${1//$HOME/\~}" local actual="${PATH/%$orig_path/}" diff --git a/e2e/run_all_tests b/e2e/run_all_tests index ee140da59..f38b9ca79 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -4,9 +4,18 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" FILES=$(find e2e -name 'test_*' -type f -not -path "*/.rtx/*" | sort) +test_count=0 for f in $FILES; do + # split tests into two tranches to reduce test time + if [ -n "${TEST_TRANCHE_COUNT:-}" ]; then + char_count=${#f} + if [[ $((char_count % "$TEST_TRANCHE_COUNT")) -ne "$TEST_TRANCHE" ]]; then + continue + fi + fi "$ROOT/e2e/run_test" "$f" echo + test_count=$((test_count + 1)) done -echo "e2e: all tests passed" +echo "e2e: $test_count tests passed" diff --git a/e2e/run_test b/e2e/run_test index 4a69ee409..77f013718 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -29,7 +29,9 @@ setup_config_files() { run_test() { echo "Running $TEST" rm -f "$RTX_CONFIG_FILE" + rtx trust "$ROOT/e2e/.e2e.rtx.toml" >/dev/null cd "$(dirname "$TEST")" + "./$(basename "$TEST")" } diff --git a/e2e/test_python b/e2e/test_python new file mode 100755 index 000000000..cbd07fc19 --- /dev/null +++ b/e2e/test_python @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +export RTX_EXPERIMENTAL=1 +export RTX_PYTHON_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-python-packages" + +rtx i python@3.11 +assert_contains "rtx x python@3.11 -- python --version" "Python 3.11" diff --git a/e2e/test_zigmod b/e2e/test_zigmod index ee35694be..037ab9838 100755 --- a/e2e/test_zigmod +++ b/e2e/test_zigmod @@ -1,14 +1,6 @@ #!/usr/bin/env bash set -euo pipefail - -assert() { - local actual - actual="$($*)" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi -} +source "$(dirname "$0")/assert.sh" eval "$(rtx activate bash)" && eval "$(rtx hook-env)" rtx plugin install https://github.com/kachick/asdf-zigmod diff --git a/justfile b/justfile index c7b62c400..e5acda924 100644 --- a/justfile +++ b/justfile @@ -55,18 +55,19 @@ test-coverage: export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$PWD/target}" export PATH="${CARGO_TARGET_DIR}/debug:$PATH" - cargo test cargo build --all-features ./e2e/run_all_tests - rtx trust - RTX_SELF_UPDATE_VERSION=1.0.0 rtx self-update <, ToolVersion)>, ) -> Result<()> { - tool_versions - .into_par_iter() + let grouped_tool_versions: Vec<(Arc, Vec)> = tool_versions + .into_iter() .filter(|(t, tv)| !t.is_version_installed(tv)) - .map(|(plugin, tv)| self.install_version(config, &plugin, &tv, mpr.add())) + .group_by(|(t, _)| t.clone()) + .into_iter() + .map(|(t, tvs)| (t, tvs.map(|(_, tv)| tv).collect())) + .collect(); + grouped_tool_versions + .into_par_iter() + .map(|(tool, versions)| { + for tv in versions { + self.install_version(config, &tool, &tv, mpr.add())?; + } + Ok(()) + }) .collect::>>()?; Ok(()) } diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/nodejs.rs index 2c3262ff1..3c47256a3 100644 --- a/src/plugins/core/nodejs.rs +++ b/src/plugins/core/nodejs.rs @@ -14,6 +14,7 @@ use crate::env::{ }; use crate::file::create_dir_all; use crate::git::Git; +use crate::lock_file::LockFile; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; @@ -46,12 +47,21 @@ impl NodeJSPlugin { self.node_build_path().join("bin/node-build") } fn install_or_update_node_build(&self) -> Result<()> { + let _lock = self.lock_node_build(); if self.node_build_path().exists() { self.update_node_build() } else { self.install_node_build() } } + + fn lock_node_build(&self) -> Result { + LockFile::new(&self.node_build_path()) + .with_callback(|l| { + trace!("install_or_update_node_build {}", l.display()); + }) + .lock() + } fn install_node_build(&self) -> Result<()> { if self.node_build_path().exists() { return Ok(()); diff --git a/src/tool.rs b/src/tool.rs index 863f19e53..3ebb06401 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -324,3 +324,9 @@ impl Tool { Ok(lock) } } + +impl PartialEq for Tool { + fn eq(&self, other: &Self) -> bool { + self.plugin_path == other.plugin_path + } +} From ce33d62ebc333e66ed3132788d656fec33d3e6e5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 21 Apr 2023 17:08:03 -0500 Subject: [PATCH 0708/1891] add node -> nodejs "alias" for core plugin (#499) --- ...tx__cli__alias__set__tests__alias_set.snap | 9 ++++++ ...cli__alias__unset__tests__alias_unset.snap | 9 ++++++ src/config/mod.rs | 1 + src/plugins/core/nodejs.rs | 30 +++++++++---------- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index c2ad7b6b9..4c0f540c2 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -2,6 +2,15 @@ source: src/cli/alias/set.rs expression: output --- +node lts 18 +node lts/argon 4 +node lts/boron 6 +node lts/carbon 8 +node lts/dubnium 10 +node lts/erbium 12 +node lts/fermium 14 +node lts/gallium 16 +node lts/hydrogen 18 nodejs lts 18 nodejs lts/argon 4 nodejs lts/boron 6 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index 7234b7d76..6c1ed5eef 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -2,6 +2,15 @@ source: src/cli/alias/unset.rs expression: output --- +node lts 18 +node lts/argon 4 +node lts/boron 6 +node lts/carbon 8 +node lts/dubnium 10 +node lts/erbium 12 +node lts/fermium 14 +node lts/gallium 16 +node lts/hydrogen 18 nodejs lts 18 nodejs lts/argon 4 nodejs lts/boron 6 diff --git a/src/config/mod.rs b/src/config/mod.rs index 50dc09364..58bf50df8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -324,6 +324,7 @@ fn load_core_tools(settings: &Settings) -> ToolMap { let tools: Vec> = vec![ Box::new(PythonPlugin::new(settings, "python".to_string())), Box::new(NodeJSPlugin::new(settings, "nodejs".to_string())), + Box::new(NodeJSPlugin::new(settings, "node".to_string())), ]; ToolMap::from_iter(tools.into_iter().map(|plugin| { ( diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/nodejs.rs index 3c47256a3..44980c541 100644 --- a/src/plugins/core/nodejs.rs +++ b/src/plugins/core/nodejs.rs @@ -170,6 +170,21 @@ impl Plugin for NodeJSPlugin { Ok(vec![".node-version".into(), ".nvmrc".into()]) } + fn external_commands(&self) -> Result>> { + Ok(vec![vec![self.name.clone(), "nodebuild".into()]]) + } + + fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { + match command { + "nodebuild" => { + self.install_or_update_node_build()?; + cmd::cmd(self.node_build_bin(), args).run()?; + } + _ => unreachable!(), + } + exit(0); + } + fn install_version( &self, config: &Config, @@ -201,19 +216,4 @@ impl Plugin for NodeJSPlugin { self.install_default_packages(&config.settings, tv, pr)?; Ok(()) } - - fn external_commands(&self) -> Result>> { - Ok(vec![vec![self.name.clone(), "nodebuild".into()]]) - } - - fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { - match command { - "nodebuild" => { - self.install_or_update_node_build()?; - cmd::cmd(self.node_build_bin(), args).run()?; - } - _ => unreachable!(), - } - exit(0); - } } From 07fc504b1fa617015f87098f8176d3cb4198488f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 21 Apr 2023 17:20:52 -0500 Subject: [PATCH 0709/1891] Update SECURITY.md --- SECURITY.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 6e0f6a2b3..c864f39ac 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,15 +8,15 @@ Please open a ticket or send me an email if you have thoughts on how rtx can be ## Core CLI Security Development of the "core CLI" is done on jdxcode/rtx which only a single developer (me, @jdxcode) has access to. -Other contributors may only submit contributions via public Pull Requests. By reducing the number -of developers with access down to 1 reduces the chance of keys being leaked greatly. +Other contributors may only submit contributions via public Pull Requests. Reducing the number +of developers with access down to 1 minimizes the chance of keys being leaked. This does create a [bus factor](https://en.wikipedia.org/wiki/Bus_factor) problem. If I suddenly died one day or otherwise wasn't able to continue development at all there are some successors listed in my GitHub account that can take over my account if need be. -The dependencies in the core CLI are a security vector. I've tried to be reasonably judicious about what dependencies -to allow into the project. I only select dependencies with broad usage across the Rust community where possible. +The dependencies in the core CLI are a security vector. I've tried to be judicious about what dependencies make it into +the project. I only select dependencies with broad usage across the Rust community where possible. I'm open to PRs or suggestions on reducing dependency count even at the cost of functionality because it will make rtx more secure. @@ -31,7 +31,7 @@ to reduce the surface area for security reasons. Plugins are by far the biggest source of potential problems and where the most work still needs to be made. -Eventually we will have 3 types of plugins: +There are 3 types of plugins: * [core](https://github.com/jdxcode/rtx/issues/236) - plugins that are hardcoded into the CLI. These will be official plugins for the most common languages. Currently, these are only used when "experimental" is enabled. @@ -42,7 +42,7 @@ dedicated owners/collaborators. If you'd like your plugin to be moved here, ask secure than installing any random tool from the internet. Just because a plugin is inside of the shorthand registry (so you can run `rtx install foo@`, does not mean -I vouch for it. I have no idea who almost anyone that builds those plugins is. If it's coming from the rtx-plugins +I vouch for it. I have no idea who almost anyone that builds those plugins are. If it's coming from the rtx-plugins GitHub org, you can have more trust in it. (See the owners with `rtx plugins ls-remote --urls`). Over time we should be able to move more plugins into being fully maintained by rtx. I plan to add an From 0a4e55e55bc95cd020486952763f04b8c487a04c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 11:08:03 -0500 Subject: [PATCH 0710/1891] added npm shim (#501) --- src/plugins/core/assets/nodejs_npm_shim | 82 +++++++++++++++++++++++++ src/plugins/core/nodejs.rs | 18 +++++- 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100755 src/plugins/core/assets/nodejs_npm_shim diff --git a/src/plugins/core/assets/nodejs_npm_shim b/src/plugins/core/assets/nodejs_npm_shim new file mode 100755 index 000000000..51a4f300e --- /dev/null +++ b/src/plugins/core/assets/nodejs_npm_shim @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -euo pipefail + +# This script wraps npm so to run `rtx reshim` after global installs and uninstalls +# Any other cases are passed-through to npm + +this_dir=$(dirname "${BASH_SOURCE[0]}") +plugin_name=$(basename "$(dirname "$this_dir")") + +this_dir=$(cd "$this_dir" && pwd -P) # Normalizes the directory + +plugin_dir="${this_dir}/.." + +should_reshim() { + if [ "${RTX_SKIP_RESHIM:-}" ]; then + return 1 + fi + + local is_global= cmd= cmd_needs_reshim= + local additional_bare_cmds=() + + for arg; do + case "$arg" in + -g | --global) + is_global=true + ;; + + -*) ;; # Skip other options + + *) + if ! [ "$cmd" ]; then + cmd="$arg" + else + additional_bare_cmds+=("$arg") + fi + ;; + esac + done + + case "$cmd" in + # npm install aliases + install | i | in | ins | inst | insta | instal | isnt | isnta | isntal | add) + cmd_needs_reshim=true + ;; + + # npm uninstall aliases + uninstall | un | unlink | remove | rm | r) + cmd_needs_reshim=true + ;; + + link | ln) + # Bare link installs a global package + if ! [ "${additional_bare_cmds[0]-}" ]; then + is_global=1 + cmd_needs_reshim=true + fi + + # Links to directories also install a global package + if [[ "${additional_bare_cmds[0]-}" =~ [./].* && -d "${additional_bare_cmds[0]-}" ]]; then + is_global=1 + cmd_needs_reshim=true + fi + ;; + esac + + # Implicit return + [ "$is_global" ] && [ "$cmd_needs_reshim" ] +} + +wrap_npm_if_reshim_is_needed() { + local npm_cli="$plugin_dir/lib/node_modules/npm/lib/cli.js" + local npm_command="require('$npm_cli')(process)" + if should_reshim "$@"; then + node -e "$npm_command" npm "$@" + printf "Reshimming rtx %s...\n" "$plugin_name" >&2 + rtx reshim + else + exec node -e "$npm_command" npm "$@" + fi +} + +wrap_npm_if_reshim_is_needed "$@" diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/nodejs.rs index 44980c541..67d0b4b3c 100644 --- a/src/plugins/core/nodejs.rs +++ b/src/plugins/core/nodejs.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::env::{join_paths, split_paths}; +use std::fs; use std::path::PathBuf; use std::process::exit; use std::time::Duration; @@ -130,11 +131,22 @@ impl NodeJSPlugin { Ok(()) } - fn test_node(&self, config: &&Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn install_npm_shim(&self, tv: &ToolVersion) -> Result<()> { + fs::write(self.npm_path(tv), include_str!("assets/nodejs_npm_shim"))?; + Ok(()) + } + + fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { let mut cmd = CmdLineRunner::new(&config.settings, self.node_path(tv)); cmd.with_pr(pr).arg("-v"); cmd.execute() } + + fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + let mut cmd = CmdLineRunner::new(&config.settings, self.npm_path(tv)); + cmd.with_pr(pr).arg("-v"); + cmd.execute() + } } impl Plugin for NodeJSPlugin { @@ -212,7 +224,9 @@ impl Plugin for NodeJSPlugin { } cmd.arg(tv.install_path()); cmd.execute()?; - self.test_node(&config, tv, pr)?; + self.test_node(config, tv, pr)?; + self.install_npm_shim(tv)?; + self.test_npm(config, tv, pr)?; self.install_default_packages(&config.settings, tv, pr)?; Ok(()) } From d01d29ac65f778421e8c7315d94e9322f838efba Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 12:23:33 -0500 Subject: [PATCH 0711/1891] shims GA (#502) This makes shims no longer only enabled in experimental mode. It also removes the ability to set a custom shims_dir. Fixes #478 --- README.md | 67 +++++++++---------- SECURITY.md | 4 +- completions/_rtx | 4 +- completions/rtx.fish | 4 +- e2e/test_shims | 14 +--- man/man1/rtx.1 | 2 +- schema/rtx.json | 4 -- src/cli/asdf.rs | 10 +-- src/cli/plugins/install.rs | 2 +- src/cli/reshim.rs | 38 +++++------ src/cli/settings/set.rs | 1 - ...cli__settings__ls__tests__settings_ls.snap | 1 - ...i__settings__set__tests__settings_set.snap | 2 - src/cli/settings/unset.rs | 1 - src/config/config_file/rtx_toml.rs | 1 - ...nfig_file__rtx_toml__tests__fixture-2.snap | 3 - ...nfig_file__rtx_toml__tests__fixture-6.snap | 2 - src/config/mod.rs | 45 ++----------- src/config/settings.rs | 10 --- src/dirs.rs | 1 + src/env.rs | 1 - src/plugins/core/mod.rs | 21 ++++++ src/plugins/core/nodejs.rs | 2 +- src/plugins/core/python.rs | 2 +- src/plugins/external_plugin.rs | 17 ++--- src/plugins/mod.rs | 4 +- src/runtime_symlinks.rs | 2 +- src/shims.rs | 56 +++++++--------- src/test.rs | 1 - src/tool.rs | 4 +- src/toolset/tool_version_list.rs | 2 +- test/config/config.toml | 1 - test/fixtures/.rtx.toml | 1 - 33 files changed, 122 insertions(+), 208 deletions(-) diff --git a/README.md b/README.md index 26f8c7042..9e6be766d 100644 --- a/README.md +++ b/README.md @@ -602,8 +602,7 @@ raw = false # set to true to directly pipe plugins to stdin/stdout/stder shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` -experimental = false # enable experimental features such as shims -shims_dir = '~/.local/share/rtx/shims' # [experimental] directory where shims are stored +experimental = false # enable experimental features log_level = 'debug' # log verbosity, see `RTX_LOG_LEVEL` [alias.nodejs] @@ -649,7 +648,6 @@ python = 'https://github.com/jdxcode/rtx-python' [settings] # project-local settings verbose = true missing_runtime_behavior = 'warn' -shims_dir = '~/.rtx/shims' [alias.nodejs] # project-local aliases my_custom_node = '20' @@ -774,7 +772,7 @@ These change the verbosity of rtx. You can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1` as well as `--log-level=trace|debug|info|warn|error`. -#### `RTX_LOG_FILE=~/.rtx/rtx.log` +#### `RTX_LOG_FILE=~/rtx.log` Output logs to a file. @@ -837,11 +835,7 @@ This will automatically answer yes or no to prompts. This is useful for scriptin #### `RTX_EXPERIMENTAL=1` -Enables experimental features such as shims. - -#### [experimental] `RTX_SHIMS_DIR=~/.local/share/rtx/shims` - -Set a directory to output shims when running `rtx reshim`. Requires `experimental = true`. +Enables experimental features. ## Aliases @@ -998,8 +992,8 @@ lts -> ./20.15.0 #### `~/.local/share/rtx/shims` -This will be the default location for storing shims. Currently this functionality is marked as -experimental, however, and this needs to be manually set with `shims_dir`. +This is where rtx places shims. Generally these are used for IDE integration or if `rtx activate` +does not work for some reason. ## Templates @@ -1063,17 +1057,10 @@ future._ ## IDE Integration -IDEs work better with shims than they do environment variable modifications. The simplest way to setup rtx -to work inside of an IDE is to enable the experimental shims functionality, then set the shims directory: - -``` -rtx settings set experimental true -rtx settings set shims_dir ~/.local/share/rtx/shims -``` +IDEs work better with shims than they do environment variable modifications. The simplest way is +to add the rtx shim directory to PATH. -_Note: this directory will be the default when shims is no longer experimental._ - -Then you need to add them to PATH. For IntelliJ and VSCode—and likely others, you can modify `~/.zprofile` +For IntelliJ and VSCode—and likely others, you can modify `~/.zprofile` with the following: ``` @@ -1088,14 +1075,14 @@ Direnv and rtx work similarly and there should be a direnv extension that can be Alternatively, you may be able to get tighter integration with a direnv extension and using the [`use_rtx`](#direnv) direnv function. -## [experimental] Core Plugins +## Core Plugins -If you have `experimental = true` in your settings, rtx will include some plugins built into the CLI. These are new and will improve over time. They can be easily overridden by -installing a plugin with the same name, e.g.: `rtx plugin install python`. +rtx comes with some plugins built into the CLI written in Rust. These are new and will improve over +time. They can be easily overridden by installing a plugin with the same name, e.g.: `rtx plugin install python`. You can see the core plugins with `rtx plugin ls --core`. -* [Python](./docs/python.md) +* [experimental] [Python](./docs/python.md) * [NodeJS](./docs/nodejs.md) * ~Ruby~ - coming soon * ~Java~ - coming soon @@ -1350,14 +1337,12 @@ jobs: While the PATH design of rtx works great in most cases, there are some situations where shims are preferable. One example is when calling rtx binaries from an IDE. -To support this, there is experimental support for using rtx in a "shim" mode. To use: +To support this, rtx does have a shim dir that can be used. It's located at `~/.local/share/rtx/shims`. ```sh-session -$ rtx settings set experimental true -$ rtx settings set shims_dir ~/.rtx/shims $ rtx i nodejs@20.0.0 -$ rtx reshim -$ ~/.rtx/shims/node -v +$ rtx reshim # may be required if new shims need to be created +$ ~/.local/share/rtx/shims/node -v v20.0.0 ``` @@ -1411,7 +1396,7 @@ export RTX_PYTHON_VERSION=3.11 Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx as if direnv was not used. -If you continue to struggle, you can also try using the [experimental shims feature](#shims). +If you continue to struggle, you can also try using the [shims method](#shims). ### Do you need direnv? @@ -2180,17 +2165,27 @@ Examples: ### `rtx reshim` ``` -[experimental] rebuilds the shim farm +rebuilds the shim farm + +This creates new shims in ~/.local/share/rtx/shims for CLIs that have been added. +rtx will try to do this automatically for commands like `npm i -g` but there are +other ways to install things (like using yarn or pnpm for node) that rtx does +not know about and so it will be necessary to call this explicitly. -this requires that the shims_dir is set +If you think rtx should automatically call this for a particular command, please +open an issue on the rtx repo. You can also setup a shell function to reshim +automatically (it's really fast so you don't need to worry about overhead): + +npm() { + command npm "$@" + rtx reshim +} Usage: reshim Examples: - $ rtx settings set experimental true - $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim - $ ~/.rtx/shims/node -v + $ ~/.local/share/rtx/shims/node -v v20.0.0 ``` ### `rtx self-update` diff --git a/SECURITY.md b/SECURITY.md index c864f39ac..0a7aec720 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -33,8 +33,8 @@ Plugins are by far the biggest source of potential problems and where the most w There are 3 types of plugins: -* [core](https://github.com/jdxcode/rtx/issues/236) - plugins that are hardcoded into the CLI. These will be -official plugins for the most common languages. Currently, these are only used when "experimental" is enabled. +* [core](https://github.com/jdxcode/rtx/issues/236) - plugins that are hardcoded into the CLI. + These are official plugins for the most common languages written in Rust. * community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. For now these will only have @jdxcode as the sole contributor, however this may change in the future for particular plugins with dedicated owners/collaborators. If you'd like your plugin to be moved here, ask me about it. diff --git a/completions/_rtx b/completions/_rtx index 548123721..585899e03 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1742,7 +1742,7 @@ _rtx_commands() { 'plugins:Manage plugins' \ 'p:Manage plugins' \ 'prune:Delete unused versions of tools' \ -'reshim:\[experimental\] rebuilds the shim farm' \ +'reshim:rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ @@ -2092,7 +2092,7 @@ _rtx__help_commands() { 'ls-remote:List runtime versions available for install' \ 'plugins:Manage plugins' \ 'prune:Delete unused versions of tools' \ -'reshim:\[experimental\] rebuilds the shim farm' \ +'reshim:rebuilds the shim farm' \ 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 5457659c9..71a254546 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -31,7 +31,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed and/or complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d 'rebuilds the shim farm' complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' @@ -676,7 +676,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d '[experimental] rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' diff --git a/e2e/test_shims b/e2e/test_shims index 008b8d251..94991326c 100755 --- a/e2e/test_shims +++ b/e2e/test_shims @@ -1,18 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +source "$(dirname "$0")/assert.sh" -assert() { - local actual - actual="$($*)" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi -} - -rtx settings set experimental true -rtx settings set shims_dir "$RTX_DATA_DIR/shims" rtx reshim assert "$RTX_DATA_DIR/shims/node -v" "v20.0.0" -rtx settings unset experimental -rtx settings unset shims_dir diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 04350d10e..2c88c1f45 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -101,7 +101,7 @@ rtx\-prune(1) Delete unused versions of tools .TP rtx\-reshim(1) -[experimental] rebuilds the shim farm +rebuilds the shim farm .TP rtx\-self\-update(1) Updates rtx itself diff --git a/schema/rtx.json b/schema/rtx.json index 15f509045..9e12a097d 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -162,10 +162,6 @@ "description": "enable experimental features", "type": "boolean" }, - "shims_dir": { - "description": "path to directory to output shims", - "type": "string" - }, "log_level": { "description": "log level", "type": "string", diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 9962e3eff..805d06761 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -22,15 +22,7 @@ impl Command for Asdf { args.append(&mut self.args); match args.get(1).map(|s| s.as_str()) { - Some("reshim") => { - if config.settings.experimental && config.settings.shims_dir.is_some() { - // only reshim if experimental is enabled and shims_dir is set - // otherwise it would error - Cli::new().run(config, &args, out) - } else { - Ok(()) - } - } + Some("reshim") => Cli::new().run(config, &args, out), Some("list") => list_versions(config, out, &args), Some("install") => { if args.len() == 4 { diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 99b7b1541..3bc982806 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -111,7 +111,7 @@ impl PluginsInstall { git_url: Option, mpr: &MultiProgressReport, ) -> Result<()> { - let mut plugin = ExternalPlugin::new(&config.settings, name); + let mut plugin = ExternalPlugin::new(name); plugin.repo_url = git_url; if !self.force && plugin.is_installed() { mpr.warn(format!("plugin {} already installed", name)); diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 90c820809..a27801d30 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,6 +1,4 @@ -use color_eyre::eyre::{eyre, Result}; -use console::style; -use indoc::formatdoc; +use color_eyre::eyre::Result; use crate::cli::command::Command; use crate::config::Config; @@ -8,9 +6,21 @@ use crate::output::Output; use crate::shims; use crate::toolset::ToolsetBuilder; -/// [experimental] rebuilds the shim farm +/// rebuilds the shim farm /// -/// this requires that the shims_dir is set +/// This creates new shims in ~/.local/share/rtx/shims for CLIs that have been added. +/// rtx will try to do this automatically for commands like `npm i -g` but there are +/// other ways to install things (like using yarn or pnpm for node) that rtx does +/// not know about and so it will be necessary to call this explicitly. +/// +/// If you think rtx should automatically call this for a particular command, please +/// open an issue on the rtx repo. You can also setup a shell function to reshim +/// automatically (it's really fast so you don't need to worry about overhead): +/// +/// npm() { +/// command npm "$@" +/// rtx reshim +/// } #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Reshim { @@ -24,30 +34,14 @@ impl Command for Reshim { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; - if !config.settings.experimental { - err_experimental()?; - } - shims::reshim(&mut config, &ts) } } -fn err_experimental() -> Result<()> { - Err(eyre!(formatdoc!( - r#" - rtx is not configured to use experimental features. - Please set the `{}` setting to `true`. - "#, - style("experimental").yellow() - ))) -} - static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx settings set experimental true - $ rtx settings set shims_dir ~/.rtx/shims $ rtx reshim - $ ~/.rtx/shims/node -v + $ ~/.local/share/rtx/shims/node -v v20.0.0 "# ); diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 80b7a7207..6454cdfe0 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -30,7 +30,6 @@ impl Command for SettingsSet { "jobs" => parse_i64(&self.value)?, "shorthands_file" => self.value.into(), "disable_default_shorthands" => parse_bool(&self.value)?, - "shims_dir" => self.value.into(), "raw" => parse_bool(&self.value)?, _ => return Err(eyre!("Unknown setting: {}", self.key)), }; diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index afc7513a2..26351523a 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -13,6 +13,5 @@ asdf_compat = false jobs = 2 disable_default_shorthands = false log_level = INFO -shims_dir = ~/data/shims raw = false diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index d13fbf147..d383e881f 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -13,6 +13,4 @@ asdf_compat = false jobs = 2 disable_default_shorthands = false log_level = INFO -shims_dir = ~/data/shims raw = false - diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index b5cbf5a41..28ca801f3 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -54,7 +54,6 @@ mod tests { jobs = 2 disable_default_shorthands = false log_level = INFO - shims_dir = ~/data/shims raw = false "###); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 548ee7ba5..39da3bed2 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -410,7 +410,6 @@ impl RtxToml { settings.disable_default_shorthands = Some(self.parse_bool(&k, v)?) } "log_level" => settings.log_level = Some(self.parse_log_level(&k, v)?), - "shims_dir" => settings.shims_dir = Some(self.parse_path(&k, v)?), "raw" => settings.raw = Some(self.parse_bool(&k, v)?), _ => Err(eyre!("Unknown config setting: {}", k))?, }; diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 777e649d2..bcd8cea0f 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -19,8 +19,5 @@ SettingsBuilder { shorthands_file: None, disable_default_shorthands: None, log_level: None, - shims_dir: Some( - "~/.rtx/shims", - ), raw: None, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index fae0b15ac..fb996d02f 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -21,8 +21,6 @@ nodejs = 'https://github.com/jdxcode/rtx-nodejs' [settings] verbose = true missing_runtime_behavior = 'warn' -shims_dir = '~/.rtx/shims' [alias.nodejs] my_custom_node = '18' - diff --git a/src/config/mod.rs b/src/config/mod.rs index 58bf50df8..ff230b583 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -5,7 +5,6 @@ use std::sync::Arc; use std::thread; use color_eyre::eyre::{eyre, Result}; -use console::style; use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::OnceCell; @@ -18,7 +17,7 @@ use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; use crate::env::CI; -use crate::plugins::core::{NodeJSPlugin, PythonPlugin}; +use crate::plugins::core::CORE_PLUGINS; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::tool::Tool; @@ -163,7 +162,7 @@ impl Config { self.tools .entry(plugin_name.clone()) .or_insert_with(|| { - let plugin = ExternalPlugin::new(&self.settings, plugin_name); + let plugin = ExternalPlugin::new(plugin_name); build_tool(plugin_name.clone(), Box::new(plugin)) }) .clone() @@ -207,18 +206,6 @@ impl Config { aliases } - pub fn get_shims_dir(&self) -> Result { - match self.settings.shims_dir.clone() { - Some(mut shims_dir) => { - if shims_dir.starts_with("~") { - shims_dir = dirs::HOME.join(shims_dir.strip_prefix("~")?); - } - Ok(shims_dir) - } - None => err_no_shims_dir(), - } - } - pub fn get_tracked_config_files(&self) -> Result { let tracker = Tracker::new(); let config_files = tracker @@ -310,9 +297,9 @@ fn load_rtxrc() -> Result { fn load_tools(settings: &Settings) -> Result { let mut tools = ToolMap::new(); if settings.experimental { - tools.extend(load_core_tools(settings)); + tools.extend(CORE_PLUGINS.clone()); } - let plugins = Tool::list(settings)? + let plugins = Tool::list()? .into_par_iter() .map(|p| (p.name.clone(), Arc::new(p))) .collect::>(); @@ -320,20 +307,6 @@ fn load_tools(settings: &Settings) -> Result { Ok(tools) } -fn load_core_tools(settings: &Settings) -> ToolMap { - let tools: Vec> = vec![ - Box::new(PythonPlugin::new(settings, "python".to_string())), - Box::new(NodeJSPlugin::new(settings, "nodejs".to_string())), - Box::new(NodeJSPlugin::new(settings, "node".to_string())), - ]; - ToolMap::from_iter(tools.into_iter().map(|plugin| { - ( - plugin.name().to_string(), - build_tool(plugin.name().to_string(), plugin), - ) - })) -} - fn build_tool(name: PluginName, plugin: Box) -> Arc { Arc::new(Tool::new(name, plugin)) } @@ -484,16 +457,6 @@ fn load_aliases(config_files: &ConfigMap) -> AliasMap { aliases } -fn err_no_shims_dir() -> Result { - Err(eyre!(indoc::formatdoc!( - r#" - rtx is not configured to use shims. - Please set the `{}` setting to a directory. - "#, - style("shims_dir").yellow() - ))) -} - fn track_config_files(config_filenames: &[PathBuf]) -> thread::JoinHandle<()> { let config_filenames = config_filenames.to_vec(); let track = move || -> Result<()> { diff --git a/src/config/settings.rs b/src/config/settings.rs index c737c61f4..713dd9fff 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -22,7 +22,6 @@ pub struct Settings { pub shorthands_file: Option, pub disable_default_shorthands: bool, pub log_level: LevelFilter, - pub shims_dir: Option, pub raw: bool, } @@ -41,7 +40,6 @@ impl Default for Settings { shorthands_file: RTX_SHORTHANDS_FILE.clone(), disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, log_level: *RTX_LOG_LEVEL, - shims_dir: RTX_SHIMS_DIR.clone(), raw: *RTX_RAW, } } @@ -85,9 +83,6 @@ impl Settings { self.disable_default_shorthands.to_string(), ); map.insert("log_level".into(), self.log_level.to_string()); - if let Some(shims) = &self.shims_dir { - map.insert("shims_dir".into(), shims.to_string_lossy().to_string()); - } map.insert("raw".into(), self.raw.to_string()); map } @@ -107,7 +102,6 @@ pub struct SettingsBuilder { pub shorthands_file: Option, pub disable_default_shorthands: Option, pub log_level: Option, - pub shims_dir: Option, pub raw: Option, } @@ -154,9 +148,6 @@ impl SettingsBuilder { if other.log_level.is_some() { self.log_level = other.log_level; } - if other.shims_dir.is_some() { - self.shims_dir = other.shims_dir; - } if other.raw.is_some() { self.raw = other.raw; } @@ -200,7 +191,6 @@ impl SettingsBuilder { .disable_default_shorthands .unwrap_or(settings.disable_default_shorthands); settings.log_level = self.log_level.unwrap_or(settings.log_level); - settings.shims_dir = self.shims_dir.clone().or(settings.shims_dir); settings.raw = self.raw.unwrap_or(settings.raw); if settings.raw { diff --git a/src/dirs.rs b/src/dirs.rs index ac653bc73..7180e40bb 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -12,3 +12,4 @@ pub static CONFIG: Lazy = Lazy::new(|| env::RTX_CONFIG_DIR.clone()); pub static PLUGINS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("plugins")); pub static DOWNLOADS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("downloads")); pub static INSTALLS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("installs")); +pub static SHIMS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("shims")); diff --git a/src/env.rs b/src/env.rs index d2f6cf410..b468da3b6 100644 --- a/src/env.rs +++ b/src/env.rs @@ -79,7 +79,6 @@ pub static RTX_SHORTHANDS_FILE: Lazy> = Lazy::new(|| var_path("RTX_SHORTHANDS_FILE")); pub static RTX_DISABLE_DEFAULT_SHORTHANDS: Lazy = Lazy::new(|| var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS")); -pub static RTX_SHIMS_DIR: Lazy> = Lazy::new(|| var_path("RTX_SHIMS_DIR")); pub static RTX_RAW: Lazy = Lazy::new(|| var_is_true("RTX_RAW")); pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { var("RTX_TRUSTED_CONFIG_PATHS") diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index ada18cfc9..4fdca9538 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,5 +1,26 @@ mod nodejs; mod python; +use crate::plugins::{Plugin, PluginName}; +use crate::tool::Tool; pub use nodejs::NodeJSPlugin; +use once_cell::sync::Lazy; pub use python::PythonPlugin; +use std::collections::BTreeMap; +use std::sync::Arc; + +type ToolMap = BTreeMap>; + +pub static CORE_PLUGINS: Lazy = Lazy::new(|| { + let tools: Vec> = vec![ + Box::new(PythonPlugin::new("python".to_string())), + Box::new(NodeJSPlugin::new("nodejs".to_string())), + Box::new(NodeJSPlugin::new("node".to_string())), + ]; + ToolMap::from_iter(tools.into_iter().map(|plugin| { + ( + plugin.name().to_string(), + Arc::new(Tool::new(plugin.name().to_string(), plugin)), + ) + })) +}); diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/nodejs.rs index 67d0b4b3c..a7dafafde 100644 --- a/src/plugins/core/nodejs.rs +++ b/src/plugins/core/nodejs.rs @@ -29,7 +29,7 @@ pub struct NodeJSPlugin { } impl NodeJSPlugin { - pub fn new(_settings: &Settings, name: PluginName) -> NodeJSPlugin { + pub fn new(name: PluginName) -> NodeJSPlugin { let cache_path = dirs::CACHE.join(&name); let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours Self { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 511b2f7b4..50facff34 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -23,7 +23,7 @@ pub struct PythonPlugin { } impl PythonPlugin { - pub fn new(_settings: &Settings, name: PluginName) -> Self { + pub fn new(name: PluginName) -> Self { let cache_path = dirs::CACHE.join(&name); let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours Self { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 18b5b2f20..66be1d541 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -46,7 +46,7 @@ pub struct ExternalPlugin { } impl ExternalPlugin { - pub fn new(settings: &Settings, name: &PluginName) -> Self { + pub fn new(name: &PluginName) -> Self { let plugin_path = dirs::PLUGINS.join(name); let cache_path = dirs::CACHE.join(name); let toml_path = plugin_path.join("rtx.plugin.toml"); @@ -58,7 +58,7 @@ impl ExternalPlugin { }; Self { name: name.into(), - script_man: build_script_man(settings, name, &plugin_path), + script_man: build_script_man(name, &plugin_path), downloads_path: dirs::DOWNLOADS.join(name), installs_path: dirs::INSTALLS.join(name), cache: ExternalPluginCache::default(), @@ -272,16 +272,11 @@ impl ExternalPlugin { } } -fn build_script_man(settings: &Settings, name: &str, plugin_path: &Path) -> ScriptManager { - let mut sm = ScriptManager::new(plugin_path.to_path_buf()) +fn build_script_man(name: &str, plugin_path: &Path) -> ScriptManager { + ScriptManager::new(plugin_path.to_path_buf()) .with_env("RTX_PLUGIN_NAME", name.to_string()) - .with_env("RTX_PLUGIN_PATH", plugin_path.to_string_lossy().to_string()); - if let Some(shims_dir) = &settings.shims_dir { - let shims_dir = shims_dir.to_string_lossy().to_string(); - sm = sm.with_env("RTX_SHIMS_DIR", shims_dir); - } - - sm + .with_env("RTX_PLUGIN_PATH", plugin_path.to_string_lossy().to_string()) + .with_env("RTX_SHIMS_DIR", &*dirs::SHIMS) } impl Eq for ExternalPlugin {} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index c2ad7c938..461e841e6 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -93,7 +93,7 @@ mod tests { fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); - let plugin = ExternalPlugin::new(&settings, &PluginName::from("tiny")); + let plugin = ExternalPlugin::new(&PluginName::from("tiny")); let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); let version = tool .latest_version(&settings, Some("1.0.0".into())) @@ -107,7 +107,7 @@ mod tests { #[test] fn test_latest_stable() { let settings = Settings::default(); - let plugin = ExternalPlugin::new(&settings, &PluginName::from("dummy")); + let plugin = ExternalPlugin::new(&PluginName::from("dummy")); let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); let version = tool.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 620ea8638..43bc1b0e3 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -111,7 +111,7 @@ mod tests { #[test] fn test_list_symlinks() { let config = Config::load().unwrap(); - let plugin = ExternalPlugin::new(&config.settings, &PluginName::from("tiny")); + let plugin = ExternalPlugin::new(&PluginName::from("tiny")); let tool = Tool::new(String::from("tiny"), Box::new(plugin)); let symlinks = list_symlinks(&config, &tool).unwrap(); assert_debug_snapshot!(symlinks); diff --git a/src/shims.rs b/src/shims.rs index 394af210f..39810c17d 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -23,7 +23,7 @@ use crate::{dirs, file}; #[allow(dead_code)] pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Result { let (_, bin_name) = args[0].rsplit_once('/').unwrap_or(("", &args[0])); - if bin_name == "rtx" || !config.settings.experimental { + if bin_name == "rtx" { return Ok(config); } let mut args: Vec = args.iter().map(OsString::from).collect(); @@ -39,48 +39,42 @@ pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Res } fn which_shim(config: &mut Config, bin_name: &str) -> Result { - if let Ok(shims_dir) = config.get_shims_dir() { - let shim = shims_dir.join(bin_name); - if shim.exists() { - let ts = ToolsetBuilder::new().build(config)?; - if let Some((p, tv)) = ts.which(config, bin_name) { - if let Some(bin) = p.which(config, &tv, bin_name)? { - return Ok(bin); - } + let shim = dirs::SHIMS.join(bin_name); + if shim.exists() { + let ts = ToolsetBuilder::new().build(config)?; + if let Some((p, tv)) = ts.which(config, bin_name) { + if let Some(bin) = p.which(config, &tv, bin_name)? { + return Ok(bin); } - // fallback for "system" - for path in &*env::PATH { - if fs::canonicalize(path).unwrap_or_default() - == fs::canonicalize(&shims_dir).unwrap_or_default() - { - continue; - } - let bin = path.join(bin_name); - if bin.exists() { - return Ok(bin); - } + } + // fallback for "system" + for path in &*env::PATH { + if fs::canonicalize(path).unwrap_or_default() + == fs::canonicalize(&*dirs::SHIMS).unwrap_or_default() + { + continue; + } + let bin = path.join(bin_name); + if bin.exists() { + return Ok(bin); } - let tvs = ts.list_rtvs_with_bin(config, bin_name)?; - err_no_version_set(bin_name, tvs)?; } + let tvs = ts.list_rtvs_with_bin(config, bin_name)?; + err_no_version_set(bin_name, tvs)?; } Err(eyre!("{} is not a valid shim", bin_name)) } pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { - if !config.settings.experimental || config.settings.shims_dir.is_none() { - return Ok(()); - } - let shims_dir = config.get_shims_dir()?; - let _lock = LockFile::new(&shims_dir) + let _lock = LockFile::new(&dirs::SHIMS) .with_callback(|l| { trace!("reshim callback {}", l.display()); }) .lock(); // remove old shims - let _ = remove_all(&shims_dir); - create_dir_all(&shims_dir)?; + let _ = remove_all(&*dirs::SHIMS); + create_dir_all(&*dirs::SHIMS)?; let rtx_bin = config.rtx_bin().unwrap_or(env::RTX_EXE.clone()); let paths: Vec = ts @@ -105,7 +99,7 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { continue; } let bin_name = bin.file_name().into_string().unwrap(); - let symlink_path = shims_dir.join(bin_name); + let symlink_path = dirs::SHIMS.join(bin_name); file::make_symlink(&rtx_bin, &symlink_path).map_err(|err| { eyre!( "Failed to create symlink from {} to {}: {}", @@ -122,7 +116,7 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { for bin in files { let bin = bin?; let bin_name = bin.file_name().into_string().unwrap(); - let symlink_path = shims_dir.join(bin_name); + let symlink_path = dirs::SHIMS.join(bin_name); make_shim(&bin.path(), &symlink_path)?; } } diff --git a/src/test.rs b/src/test.rs index 6d005312e..25a7c2b5b 100644 --- a/src/test.rs +++ b/src/test.rs @@ -59,7 +59,6 @@ pub fn reset_config() { legacy_version_file= true plugin_autoupdate_last_check_duration = 20 jobs = 2 - shims_dir = '~/data/shims' [alias.tiny] "my/alias" = '3.0' diff --git a/src/tool.rs b/src/tool.rs index 3ebb06401..3c6ea8d3f 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -35,11 +35,11 @@ impl Tool { } } - pub fn list(settings: &Settings) -> Result> { + pub fn list() -> Result> { Ok(file::dir_subdirs(&dirs::PLUGINS)? .iter() .map(|name| { - let plugin = ExternalPlugin::new(settings, name); + let plugin = ExternalPlugin::new(name); Self::new(name.to_string(), Box::new(plugin)) }) .collect()) diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 3bb427f2c..cb6bb3d8e 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -51,7 +51,7 @@ mod tests { fn test_tool_version_list() { let mut config = Config::default(); let plugin_name = "tiny".to_string(); - let plugin = ExternalPlugin::new(&config.settings, &plugin_name); + let plugin = ExternalPlugin::new(&plugin_name); let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); config.tools.insert(plugin_name.clone(), Arc::new(tool)); let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); diff --git a/test/config/config.toml b/test/config/config.toml index efef629b7..32102d216 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -6,7 +6,6 @@ always_keep_download= true legacy_version_file= true plugin_autoupdate_last_check_duration = 20 jobs = 2 -shims_dir = '~/data/shims' [alias.tiny] "my/alias" = '3.0' diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml index 2a0c1c46a..c9af28543 100644 --- a/test/fixtures/.rtx.toml +++ b/test/fixtures/.rtx.toml @@ -17,7 +17,6 @@ nodejs = 'https://github.com/jdxcode/rtx-nodejs' [settings] verbose = true missing_runtime_behavior = 'warn' -shims_dir = '~/.rtx/shims' [alias.nodejs] my_custom_node = '18' From 559bedb36b5b756f9123c086e3ea9af902f7cb7c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 13:05:50 -0500 Subject: [PATCH 0712/1891] nodejs GA (#503) --- .github/workflows/test-plugins.yml | 4 +- .rtx.toml | 2 +- README.md | 307 +++++++++--------- completions/_rtx | 34 +- completions/rtx.fish | 12 +- docs/demo.tape | 8 +- docs/node.md | 92 ++++++ docs/nodejs.md | 90 ----- ...nodejs-packages => .default-node-packages} | 0 e2e/.e2e-tool-versions | 2 +- e2e/cd/.e2e-tool-versions | 2 +- e2e/cd/18/.e2e-tool-versions | 2 +- e2e/cd/test_bash | 8 +- e2e/cd/test_bash_legacy_activate | 2 +- e2e/cd/test_fish | 4 +- e2e/cd/test_zsh | 4 +- e2e/config/.e2e-tool-versions | 2 +- e2e/config/cd/.e2e-tool-versions | 2 +- e2e/config/cd/18/.e2e-tool-versions | 2 +- e2e/direnv/system_version/.e2e-tool-versions | 2 +- .../load-first/.e2e-tool-versions | 2 +- .../system_version/test_direnv_system_version | 22 +- e2e/test_env | 6 +- e2e/test_local | 6 +- e2e/test_log_level | 8 +- e2e/test_ls_remote | 2 +- e2e/test_nodejs | 10 +- e2e/test_shell | 4 +- e2e/test_shims | 1 + e2e/test_system | 4 +- e2e/test_top_runtimes | 2 +- man/man1/rtx.1 | 16 +- packaging/homebrew/homebrew.rb | 4 +- src/cli/alias/get.rs | 2 +- src/cli/alias/ls.rs | 6 +- src/cli/alias/set.rs | 2 +- ...tx__cli__alias__set__tests__alias_set.snap | 9 - ...cli__alias__unset__tests__alias_unset.snap | 9 - src/cli/alias/unset.rs | 2 +- src/cli/args/runtime.rs | 4 +- src/cli/current.rs | 6 +- src/cli/doctor.rs | 2 +- src/cli/exec.rs | 12 +- src/cli/global.rs | 18 +- src/cli/install.rs | 8 +- src/cli/latest.rs | 4 +- src/cli/local.rs | 26 +- src/cli/ls.rs | 10 +- src/cli/ls_remote.rs | 6 +- src/cli/mod.rs | 16 +- src/cli/plugins/install.rs | 26 +- src/cli/plugins/link.rs | 12 +- src/cli/plugins/ls.rs | 6 +- src/cli/plugins/ls_remote.rs | 6 +- src/cli/plugins/mod.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/plugins/update.rs | 4 +- src/cli/prune.rs | 4 +- src/cli/shell.rs | 2 +- src/cli/uninstall.rs | 4 +- src/cli/where.rs | 14 +- src/cli/which.rs | 4 +- src/config/config_file/mod.rs | 2 +- src/config/config_file/rtx_toml.rs | 22 +- ...nfig_file__rtx_toml__tests__fixture-3.snap | 2 +- ...nfig_file__rtx_toml__tests__fixture-4.snap | 12 +- ...nfig_file__rtx_toml__tests__fixture-5.snap | 2 +- ...nfig_file__rtx_toml__tests__fixture-6.snap | 6 +- ...file__rtx_toml__tests__remove_alias-2.snap | 3 +- ...g_file__rtx_toml__tests__remove_alias.snap | 2 +- ...__rtx_toml__tests__replace_versions-2.snap | 3 +- ...le__rtx_toml__tests__replace_versions.snap | 8 +- ...ig_file__rtx_toml__tests__set_alias-2.snap | 3 +- ...nfig_file__rtx_toml__tests__set_alias.snap | 2 +- src/config/mod.rs | 15 +- src/default_shorthands.rs | 2 +- src/env.rs | 24 +- .../assets/{nodejs_npm_shim => node_npm_shim} | 0 src/plugins/core/mod.rs | 34 +- src/plugins/core/{nodejs.rs => node.rs} | 38 ++- src/shell/bash.rs | 9 +- src/shell/fish.rs | 19 +- .../rtx__shell__bash__tests__hook_init.snap | 8 +- .../rtx__shell__fish__tests__hook_init.snap | 12 +- .../rtx__shell__zsh__tests__hook_init.snap | 8 +- src/shell/zsh.rs | 9 +- src/shorthands.rs | 2 +- src/tool.rs | 10 +- src/toolset/tool_source.rs | 8 +- test/fixtures/.rtx.toml | 6 +- test/fixtures/shorthands.toml | 2 +- 91 files changed, 591 insertions(+), 578 deletions(-) create mode 100644 docs/node.md delete mode 100644 docs/nodejs.md rename e2e/{.default-nodejs-packages => .default-node-packages} (100%) rename src/plugins/core/assets/{nodejs_npm_shim => node_npm_shim} (100%) rename src/plugins/core/{nodejs.rs => node.rs} (88%) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 9113bae5b..1ae0054a8 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -46,8 +46,8 @@ jobs: fail-fast: false matrix: include: - - plugin: nodejs - command: rtx exec nodejs@latest -- node -v + - plugin: node + command: rtx exec node@latest -- node -v - plugin: ruby command: rtx exec ruby@latest -- ruby --version - plugin: python diff --git a/.rtx.toml b/.rtx.toml index 5fd9e2f52..38ebcaeb4 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -5,7 +5,7 @@ FOO = "bar" THIS_PROJECT = "{{config_root}}-{{env.PWD}}" [tools] -#nodejs = 'lts' +#node = 'lts' tiny = { version = "1", foo = "bar" } golang = { version = "latest", foo = "bar" } python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } diff --git a/README.md b/README.md index 9e6be766d..0cadf23b4 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,8 @@ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish Install a runtime and set it as the default: ```sh-session -$ rtx install nodejs@20 -$ rtx global nodejs@20 +$ rtx install node@20 +$ rtx global node@20 $ node -v v20.0.0 ``` @@ -111,7 +111,7 @@ v20.0.0 - [Templates](#templates) - [[experimental] Config Environments](#experimental-config-environments) - [IDE Integration](#ide-integration) -- [[experimental] Core Plugins](#experimental-core-plugins) +- [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 does `rtx activate` do?](#what-does-rtx-activate-do) @@ -233,16 +233,16 @@ See [plugins](#plugins) below. ### Common commands - rtx install nodejs@20.0.0 Install a specific version number - rtx install nodejs@20 Install a fuzzy version number - rtx local nodejs@20 Use node-20.x in current project - rtx global nodejs@20 Use node-20.x as default + rtx install node@20.0.0 Install a specific version number + rtx install node@20 Install a fuzzy version number + rtx local node@20 Use node-20.x in current project + rtx global node@20 Use node-20.x as default - rtx install nodejs Install the version specified in .tool-versions - rtx local nodejs@latest Use latest node in current directory - rtx global nodejs@system Use system node as default + rtx install node Install the version specified in .tool-versions + rtx local node@latest Use latest node in current directory + rtx global node@system Use system node as default - rtx x nodejs@20 -- node app.js Run `node app.js` with the PATH pointing to node-20.x + rtx x node@20 -- node app.js Run `node app.js` with the PATH pointing to node-20.x ## Installation @@ -501,7 +501,7 @@ You can specify a tool and its version in a shebang without needing to first setup `.tool-versions`/`.rtx.toml` config: ```typescript -#!/usr/bin/env -S rtx x nodejs@20 -- node +#!/usr/bin/env -S rtx x node@20 -- node // "env -S" allows multiple arguments in a shebang console.log(`Running node: ${process.version}`); ``` @@ -517,17 +517,17 @@ The `.tool-versions` file is used to specify the runtime versions for a project. is: ``` -nodejs 20.0.0 # comments are allowed +node 20.0.0 # comments are allowed 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 shfmt path:./shfmt # use a custom runtime -nodejs lts # use lts version of nodejs (not supported by all plugins) +node lts # use lts version of node (not supported by all plugins) # The following syntax is experimental and subject to change -nodejs lts!-2 # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) +node lts!-2 # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) python latest!-0.1 # install python-3.10 if the latest is 3.11 ``` @@ -544,17 +544,17 @@ other developers to use a specific tool like rtx/asdf. They support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work in rtx and nvm. Here are some of the supported legacy version files: -| Plugin | "Legacy" (Idiomatic) Files | -| --------- | -------------------------------------------------- | -| crystal | `.crystal-version` | -| elixir | `.exenv-version` | -| golang | `.go-version`, `go.mod` | -| java | `.java-version` | -| nodejs | `.nvmrc`, `.node-version` | -| python | `.python-version` | -| ruby | `.ruby-version`, `Gemfile` | -| terraform | `.terraform-version`, `.packer-version`, `main.tf` | -| yarn | `.yarnrc` | +| Plugin | "Legacy" (Idiomatic) Files | +|------------| -------------------------------------------------- | +| crystal | `.crystal-version` | +| elixir | `.exenv-version` | +| golang | `.go-version`, `go.mod` | +| java | `.java-version` | +| node | `.nvmrc`, `.node-version` | +| python | `.python-version` | +| ruby | `.ruby-version`, `Gemfile` | +| terraform | `.terraform-version`, `.packer-version`, `main.tf` | +| yarn | `.yarnrc` | In rtx these are enabled by default. You can disable them with `rtx settings set legacy_version_file false`. There is a performance cost to having these when they're parsed as it's performed by the plugin in @@ -578,7 +578,7 @@ rtx can be configured in `~/.config/rtx/config.toml`. The following options are missing_runtime_behavior = 'warn' # other options: 'ignore', 'warn', 'prompt', 'autoinstall' # plugins can read the versions files used by other version managers (if enabled by the plugin) -# for example, .nvmrc in the case of nodejs's nvm +# for example, .nvmrc in the case of node's nvm legacy_version_file = true # enabled by default (different than asdf) # configure `rtx install` to always keep the downloaded archive @@ -605,8 +605,8 @@ disable_default_shorthands = false # disable the default shorthands, see `RTX_DI experimental = false # enable experimental features log_level = 'debug' # log verbosity, see `RTX_LOG_LEVEL` -[alias.nodejs] -my_custom_node = '20' # makes `rtx install nodejs@my_custom_node` install node-20.x +[alias.node] +my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20.x # this can also be specified in a plugin (see below in "Aliases") ``` @@ -634,7 +634,7 @@ terraform = '1.0.0' erlang = ['23.3', '24.0'] # supports everything you can do with .tool-versions currently -nodejs = ['16', 'prefix:20', 'ref:master', 'path:~/.nodes/14'] +node = ['16', 'prefix:20', 'ref:master', 'path:~/.nodes/14'] # send arbitrary options to the plugin, passed as: # RTX_TOOL_OPTS__VENV=.venv @@ -649,7 +649,7 @@ python = 'https://github.com/jdxcode/rtx-python' verbose = true missing_runtime_behavior = 'warn' -[alias.nodejs] # project-local aliases +[alias.node] # project-local aliases my_custom_node = '20' ``` @@ -708,8 +708,8 @@ rtx can also be configured via environment variables. The following options are This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. ``` -RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install nodejs@20 -RTX_NODEJS_VERSION=20 rtx exec -- node --version +RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install node@20 +RTX_NODE_VERSION=20 rtx exec -- node --version ``` #### `RTX_DATA_DIR` @@ -746,13 +746,13 @@ to use this feature. #### `RTX_${PLUGIN}_VERSION` -Set the version for a runtime. For example, `RTX_NODEJS_VERSION=20` will use nodejs@20.x regardless +Set the version for a runtime. For example, `RTX_NODE_VERSION=20` will use node@20.x regardless of what is set in `.tool-versions`/`.rtx.toml`. #### `RTX_LEGACY_VERSION_FILE` Plugins can read the versions files used by other version managers (if enabled by the plugin) -for example, `.nvmrc` in the case of nodejs's nvm. See [legacy version files](#legacy-version-files) for more +for example, `.nvmrc` in the case of node's nvm. See [legacy version files](#legacy-version-files) for more information. #### `RTX_USE_TOML` @@ -813,17 +813,17 @@ The file should be in this toml format: ```toml elixir = "https://github.com/my-org/rtx-elixir.git" -nodejs = "https://github.com/my-org/rtx-nodejs.git" +node = "https://github.com/my-org/rtx-node.git" ``` #### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` Disables the shorthand aliases for installing plugins. You will have to specify full urls when -installing plugins, e.g.: `rtx plugin install nodejs https://github.com/asdf-vm/asdf-nodejs.git` +installing plugins, e.g.: `rtx plugin install node https://github.com/asdf-vm/asdf-node.git` Currently this disables the following: -- `--fuzzy` as default behavior (`rtx local nodejs@20` will save exact version) +- `--fuzzy` as default behavior (`rtx local node@20` will save exact version) #### `RTX_HIDE_UPDATE_WARNING=1` @@ -840,13 +840,13 @@ Enables experimental features. ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS -versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for nodejs@20.x. -So you can use the runtime with `nodejs lts/hydrogen` in `.tool-versions`. +versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for node@20.x. +So you can use the runtime with `node lts/hydrogen` in `.tool-versions`. User aliases can be created by adding an `alias.` section to `~/.config/rtx/config.toml`: ```toml -[alias.nodejs] +[alias.node] my_custom_20 = '20' ``` @@ -976,8 +976,8 @@ ln -s ~/src/rtx-my-tool ~/.local/share/rtx/plugins/my-tool #### `~/.local/share/rtx/installs` This is where tools are installed to when running `rtx install`. For example, `rtx install -nodejs@20.0.0` will install to `~/.local/share/rtx/installs/nodejs/20.0.0` For example, `rtx -install 0.0` will install to `~/.local/share/rtx/installs/nodejs/20.0.0`. +node@20.0.0` will install to `~/.local/share/rtx/installs/node/20.0.0` For example, `rtx +install 0.0` will install to `~/.local/share/rtx/installs/node/20.0.0`. This will also create other symlinks to this directory for version prefixes ("20" and "20.15") and matching aliases ("lts", "latest"). @@ -1077,15 +1077,16 @@ Alternatively, you may be able to get tighter integration with a direnv extensio ## Core Plugins -rtx comes with some plugins built into the CLI written in Rust. These are new and will improve over +rtx comes with some plugins built into the CLI written in Rust. These are new and will improve over time. They can be easily overridden by installing a plugin with the same name, e.g.: `rtx plugin install python`. You can see the core plugins with `rtx plugin ls --core`. * [experimental] [Python](./docs/python.md) -* [NodeJS](./docs/nodejs.md) +* [NodeJS](./docs/node.md) * ~Ruby~ - coming soon * ~Java~ - coming soon +* ~Go~ - coming soon ## FAQs @@ -1169,17 +1170,13 @@ you should post an issue on the plugin's repo. ### How do the shorthand plugin names map to repositories? -e.g.: how does `rtx plugin install nodejs` know to fetch [https://github.com/asdf-vm/asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)? +e.g.: how does `rtx plugin install node` know to fetch [https://github.com/rtx-plugins/rtx-nodejs] +(https://github.com/rtx-plugins/rtx-nodejs)? asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. This is regularly updated every time that rtx has a release. This repository is stored directly into the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that -rtx makes. For example, we add `node` which points to the same plugin as `nodejs` and change `python` -to point to [rtx-python](https://github.com/jdxcode/rtx-python) which is a fork of [asdf-python](https://github.com/danhper/asdf-python) -with some rtx features like virtualenv support. - -Over time I suspect that more plugins will be forked like rtx-python as we're able to offer more rtx-specific -enhancements. +rtx makes on top of asdf. ### How do I migrate from asdf? @@ -1196,9 +1193,9 @@ and see what happens. rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin should be usable in rtx. The commands in rtx are slightly -different, such as `rtx install nodejs@20.0.0` vs `asdf install nodejs 20.0.0`—this is done so +different, such as `rtx install node@20.0.0` vs `asdf install node 20.0.0`—this is done so multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx -install nodejs 20.0.0`). This is the case for most commands, though the help for the command may +install node 20.0.0`). This is the case for most commands, though the help for the command may say that asdf-style syntax is supported. When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may @@ -1288,16 +1285,16 @@ variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https:// Some commands are the same in asdf but others have been changed. Everything that's possible in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, -such as using fuzzy-matching, e.g.: `rtx install nodejs@20`. While in asdf you _can_ run -`asdf install nodejs latest:20`, you can't use `latest:20` in a `.tool-versions` file or many other places. +such as using fuzzy-matching, e.g.: `rtx install node@20`. While in asdf you _can_ run +`asdf install node latest:20`, you can't use `latest:20` in a `.tool-versions` file or many other places. In `rtx` you can use fuzzy-matching everywhere. asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: ```sh-session -asdf plugin add nodejs -asdf install nodejs latest:20 -asdf local nodejs latest:20 +asdf plugin add node +asdf install node latest:20 +asdf local node latest:20 ``` In `rtx` this can all be done in a single step to set the local runtime version. If the plugin @@ -1307,8 +1304,8 @@ and/or runtime needs to be installed it will prompt: I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). -`rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add nodejs` or -`rtx plugin install nodejs`. If I can guess what you meant, then I'll try to get rtx to respond +`rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add node` or +`rtx plugin install node`. If I can guess what you meant, then I'll try to get rtx to respond in the right way. That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there @@ -1340,7 +1337,7 @@ preferable. One example is when calling rtx binaries from an IDE. To support this, rtx does have a shim dir that can be used. It's located at `~/.local/share/rtx/shims`. ```sh-session -$ rtx i nodejs@20.0.0 +$ rtx i node@20.0.0 $ rtx reshim # may be required if new shims need to be created $ ~/.local/share/rtx/shims/node -v v20.0.0 @@ -1389,7 +1386,7 @@ easier to manage, I encourage _not_ actually using `.tool-versions` at all, and setting environment variables entirely in `.envrc`: ``` -export RTX_NODEJS_VERSION=20.0.0 +export RTX_NODE_VERSION=20.0.0 export RTX_PYTHON_VERSION=3.11 ``` @@ -1429,7 +1426,7 @@ Remote versions are updated daily by default. The file is zlib messagepack, if y run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). ```sh-session -cat ~/$RTX_CACHE_DIR/nodejs/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode +cat ~/$RTX_CACHE_DIR/node/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode ``` Note that the caching of `exec-env` may be problematic if the script isn't simply exporting @@ -1488,7 +1485,7 @@ Arguments: The alias to show Examples: - $ rtx alias get nodejs lts/hydrogen + $ rtx alias get node lts/hydrogen 20.0.0 ``` ### `rtx alias ls [OPTIONS]` @@ -1500,7 +1497,7 @@ These can come from user config or from plugins in `bin/list-aliases`. For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: - [alias.nodejs] + [alias.node] lts = "20.0.0" Usage: ls [OPTIONS] @@ -1511,7 +1508,7 @@ Options: Examples: $ rtx aliases - nodejs lts/hydrogen 20.0.0 + node lts/hydrogen 20.0.0 ``` ### `rtx alias set ` @@ -1533,7 +1530,7 @@ Arguments: The value to set the alias to Examples: - $ rtx alias set nodejs lts/hydrogen 18.0.0 + $ rtx alias set node lts/hydrogen 18.0.0 ``` ### `rtx alias unset ` @@ -1552,7 +1549,7 @@ Arguments: The alias to remove Examples: - $ rtx alias unset nodejs lts/hydrogen + $ rtx alias unset node lts/hydrogen ``` ### `rtx bin-paths` @@ -1598,7 +1595,7 @@ Usage: current [PLUGIN] Arguments: [PLUGIN] - Plugin to show versions of e.g.: ruby, nodejs + Plugin to show versions of e.g.: ruby, node Examples: # outputs `.tool-versions` compatible format @@ -1606,9 +1603,9 @@ Examples: python 3.11.0 3.10.0 shfmt 3.6.0 shellcheck 0.9.0 - nodejs 20.0.0 + node 20.0.0 - $ rtx current nodejs + $ rtx current node 20.0.0 # can output multiple versions @@ -1657,7 +1654,7 @@ Usage: doctor Examples: $ rtx doctor - [WARN] plugin nodejs is not installed + [WARN] plugin node is not installed ``` ### `rtx env [OPTIONS] [RUNTIME]...` @@ -1695,7 +1692,7 @@ set. Runtimes will be loaded from .tool-versions, though they can be overridden with args Note that only the plugin specified will be overridden, so if a `.tool-versions` file -includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. +includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. The "--" separates runtimes from the commands to pass along to the subprocess. @@ -1703,7 +1700,7 @@ Usage: exec [OPTIONS] [RUNTIME]... [-- ...] Arguments: [RUNTIME]... - Runtime(s) to start e.g.: nodejs@20 python@3.10 + Runtime(s) to start e.g.: node@20 python@3.10 [COMMAND]... Command string to execute (same as --command) @@ -1718,14 +1715,14 @@ Options: [short aliases: C] Examples: - $ rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x - $ rtx x nodejs@20 -- node ./app.js # shorter alias + $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x + $ rtx x node@20 -- node ./app.js # shorter alias # Specify command as a string: - $ rtx exec nodejs@20 python@3.11 --command "node -v && python -V" + $ rtx exec node@20 python@3.11 --command "node -v && python -V" # Run a command in a different directory: - $ rtx x -C /path/to/project nodejs@20 -- node ./app.js + $ rtx x -C /path/to/project node@20 -- node ./app.js ``` ### `rtx global [OPTIONS] [RUNTIME]...` @@ -1745,18 +1742,18 @@ Usage: global [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... Runtime(s) to add to .tool-versions - e.g.: nodejs@20 + e.g.: node@20 If this is a single runtime with no version, the current value of the global .tool-versions will be displayed Options: --pin Save exact version to `~/.tool-versions` - e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions + e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions --fuzzy Save fuzzy version to `~/.tool-versions` - e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions + e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1 --remove @@ -1766,16 +1763,16 @@ Options: Get the path of the global config file Examples: - # set the current version of nodejs to 20.x + # set the current version of node to 20.x # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx global --fuzzy nodejs@20 + $ rtx global --fuzzy node@20 - # set the current version of nodejs to 20.x + # set the current version of node to 20.x # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global --pin nodejs@20 + $ rtx global --pin node@20 - # show the current version of nodejs in ~/.tool-versions - $ rtx global nodejs + # show the current version of node in ~/.tool-versions + $ rtx global node 20.0.0 ``` ### `rtx implode [OPTIONS]` @@ -1810,7 +1807,7 @@ Usage: install [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... - Tool version(s) to install e.g.: nodejs@20 + Tool version(s) to install e.g.: node@20 Options: -p, --plugin @@ -1823,9 +1820,9 @@ Options: Show installation output Examples: - $ rtx install nodejs@20.0.0 # install specific nodejs version - $ rtx install nodejs@20 # install fuzzy nodejs version - $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml + $ rtx install node@20.0.0 # install specific node version + $ rtx install node@20 # install fuzzy node version + $ rtx install node # install version specified in .tool-versions or .rtx.toml $ rtx install # installs everything specified in .tool-versions or .rtx.toml ``` ### `rtx latest ` @@ -1840,10 +1837,10 @@ Arguments: Runtime to get the latest version of Examples: - $ rtx latest nodejs@20 # get the latest version of nodejs 20 + $ rtx latest node@20 # get the latest version of node 20 20.0.0 - $ rtx latest nodejs # get the latest stable version of nodejs + $ rtx latest node # get the latest stable version of node 20.0.0 ``` ### `rtx local [OPTIONS] [RUNTIME]...` @@ -1861,7 +1858,7 @@ Usage: local [OPTIONS] [RUNTIME]... Arguments: [RUNTIME]... Runtimes to add to .tool-versions/.rtx.toml - e.g.: nodejs@20 + e.g.: node@20 if this is a single runtime with no version, the current value of .tool-versions/.rtx.toml will be displayed @@ -1872,10 +1869,10 @@ Options: --pin Save exact version to `.tool-versions` - e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions + e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions --fuzzy - Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 + Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 --remove Remove the plugin(s) from .tool-versions @@ -1884,22 +1881,22 @@ Options: Get the path of the config file Examples: - # set the current version of nodejs to 20.x for the current directory + # set the current version of node to 20.x for the current directory # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx local nodejs@20 + $ rtx local node@20 - # set nodejs to 20.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@20 + # set node to 20.x for the current project (recurses up to find .tool-versions) + $ rtx local -p node@20 - # set the current version of nodejs to 20.x for the current directory + # set the current version of node to 20.x for the current directory # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx local --fuzzy nodejs@20 + $ rtx local --fuzzy node@20 - # removes nodejs from .tool-versions - $ rtx local --remove=nodejs + # removes node from .tool-versions + $ rtx local --remove=node - # show the current version of nodejs in .tool-versions - $ rtx local nodejs + # show the current version of node in .tool-versions + $ rtx local node 20.0.0 ``` ### `rtx ls [OPTIONS]` @@ -1924,24 +1921,24 @@ Options: Examples: $ rtx ls - ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) python 3.10.0 $ rtx ls --current - ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) $ rtx ls --parseable - nodejs 20.0.0 + node 20.0.0 python 3.11.0 $ rtx ls --json { - "nodejs": [ + "node": [ { "version": "20.0.0", - "install_path": "/Users/jdx/.rtx/installs/nodejs/20.0.0", + "install_path": "/Users/jdx/.rtx/installs/node/20.0.0", "source": { "type": ".rtx.toml", "path": "/Users/jdx/.rtx.toml" @@ -1970,15 +1967,15 @@ Arguments: same as the first argument after the "@" Examples: - $ rtx ls-remote nodejs + $ rtx ls-remote node 18.0.0 20.0.0 - $ rtx ls-remote nodejs@20 + $ rtx ls-remote node@20 20.0.0 20.1.0 - $ rtx ls-remote nodejs 20 + $ rtx ls-remote node 20 20.0.0 20.1.0 ``` @@ -1988,7 +1985,7 @@ Examples: Install a plugin note that rtx automatically can install plugins when you install a runtime -e.g.: `rtx install nodejs@20` will autoinstall the nodejs plugin +e.g.: `rtx install node@20` will autoinstall the node plugin This behavior can be modified in ~/.config/rtx/config.toml @@ -1997,8 +1994,8 @@ Usage: install [OPTIONS] [NAME] [GIT_URL] Arguments: [NAME] The name of the plugin to install - e.g.: nodejs, ruby - Can specify multiple plugins: `rtx plugins install nodejs ruby python` + e.g.: node, ruby + Can specify multiple plugins: `rtx plugins install node ruby python` [GIT_URL] The git url of the plugin @@ -2016,18 +2013,18 @@ Options: Show installation output Examples: - # install the nodejs via shorthand - $ rtx plugins install nodejs + # install the node via shorthand + $ rtx plugins install node - # install the nodejs plugin using a specific git url - $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git + # install the node plugin using a specific git url + $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git - # install the nodejs plugin using the git url only - # (nodejs is inferred from the url) - $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git + # install the node plugin using the git url only + # (node is inferred from the url) + $ rtx plugins install https://github.com/rtx-plugins/rtx-nodejs.git - # install the nodejs plugin using a specific ref - $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git#v1.0.0 + # install the node plugin using a specific ref + $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 ``` ### `rtx plugins link [OPTIONS] [PATH]` @@ -2041,22 +2038,22 @@ Usage: link [OPTIONS] [PATH] Arguments: The name of the plugin - e.g.: nodejs, ruby + e.g.: node, ruby [PATH] The local path to the plugin - e.g.: ./rtx-nodejs + e.g.: ./rtx-node Options: -f, --force Overwrite existing plugin Examples: - # essentially just `ln -s ./rtx-nodejs ~/.local/share/rtx/plugins/nodejs` - $ rtx plugins link nodejs ./rtx-nodejs + # essentially just `ln -s ./rtx-node ~/.local/share/rtx/plugins/node` + $ rtx plugins link node ./rtx-node - # infer plugin name as "nodejs" - $ rtx plugins link ./rtx-nodejs + # infer plugin name as "node" + $ rtx plugins link ./rtx-node ``` ### `rtx plugins ls [OPTIONS]` @@ -2074,15 +2071,15 @@ Options: -u, --urls Show the git url for each plugin - e.g.: https://github.com/asdf-vm/asdf-nodejs.git + e.g.: https://github.com/asdf-vm/asdf-node.git Examples: $ rtx plugins ls - nodejs + node ruby $ rtx plugins ls --urls - nodejs https://github.com/asdf-vm/asdf-nodejs.git + node https://github.com/asdf-vm/asdf-node.git ruby https://github.com/asdf-vm/asdf-ruby.git ``` ### `rtx plugins ls-remote [OPTIONS]` @@ -2090,7 +2087,7 @@ Examples: ``` List all available remote plugins -These are fetched from https://github.com/asdf-vm/asdf-plugins +The full list is here: https://github.com/jdxcode/rtx/blob/main/src/default_shorthands.rs Examples: $ rtx plugins ls-remote @@ -2100,7 +2097,7 @@ Usage: ls-remote [OPTIONS] Options: -u, --urls - Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git + Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git --only-names Only show the name of each plugin by default it will show a "*" next to installed plugins @@ -2117,7 +2114,7 @@ Arguments: Plugin(s) to remove Examples: - $ rtx uninstall nodejs + $ rtx uninstall node ``` ### `rtx plugins update [PLUGIN]...` @@ -2134,8 +2131,8 @@ Arguments: Examples: $ rtx plugins update # update all plugins - $ rtx plugins update nodejs # update only nodejs - $ rtx plugins update nodejs@beta # specify a ref + $ rtx plugins update node # update only node + $ rtx plugins update node@beta # specify a ref ``` ### `rtx prune [OPTIONS] [PLUGINS]...` @@ -2159,8 +2156,8 @@ Options: Examples: $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/nodejs/20.0.0 - rm -rf ~/.local/share/rtx/versions/nodejs/20.0.1 + rm -rf ~/.local/share/rtx/versions/node/20.0.0 + rm -rf ~/.local/share/rtx/versions/node/20.0.1 ``` ### `rtx reshim` @@ -2288,7 +2285,7 @@ Options: Removes a previously set version Examples: - $ rtx shell nodejs@20 + $ rtx shell node@20 $ node -v v20.0.0 ``` @@ -2334,8 +2331,8 @@ Arguments: Runtime(s) to remove Examples: - $ rtx uninstall nodejs@18.0.0 # will uninstall specific version - $ rtx uninstall nodejs # will uninstall current nodejs version + $ rtx uninstall node@18.0.0 # will uninstall specific version + $ rtx uninstall node # will uninstall current node version ``` ### `rtx version` @@ -2362,15 +2359,15 @@ Arguments: otherwise, it will show the current, active installed version Examples: - # Show the latest installed version of nodejs + # Show the latest installed version of node # If it is is not installed, errors - $ rtx where nodejs@20 - /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 + $ rtx where node@20 + /home/jdx/.local/share/rtx/installs/node/20.0.0 - # Show the current, active install directory of nodejs - # Errors if nodejs is not referenced in any .tool-version file - $ rtx where nodejs - /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 + # Show the current, active install directory of node + # Errors if node is not referenced in any .tool-version file + $ rtx where node + /home/jdx/.local/share/rtx/installs/node/20.0.0 ``` ### `rtx which [OPTIONS] ` @@ -2392,9 +2389,9 @@ Options: Examples: $ rtx which node - /home/username/.local/share/rtx/installs/nodejs/20.0.0/bin/node + /home/username/.local/share/rtx/installs/node/20.0.0/bin/node $ rtx which node --plugin - nodejs + node $ rtx which node --version 20.0.0 ``` diff --git a/completions/_rtx b/completions/_rtx index 585899e03..07121c6f9 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -385,7 +385,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'::plugin -- Plugin to show versions of e.g.\: ruby, nodejs:' \ +'::plugin -- Plugin to show versions of e.g.\: ruby, node:' \ && ret=0 ;; (deactivate) @@ -596,7 +596,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to start e.g.\: nodejs@20 python@3.10:' \ +'*::runtime -- Runtime(s) to start e.g.\: node@20 python@3.10:' \ && ret=0 ;; (global) @@ -608,9 +608,9 @@ default: 4]: : ' \ default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to `~/.tool-versions` -e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions]' \ +e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions]' \ '--fuzzy[Save fuzzy version to `~/.tool-versions` -e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions +e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ '--debug[Sets log level to debug]' \ @@ -625,7 +625,7 @@ Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtime(s) to add to .tool-versions -e.g.\: nodejs@20 +e.g.\: node@20 If this is a single runtime with no version, the current value of the global .tool-versions will be displayed:' \ && ret=0 @@ -699,7 +699,7 @@ Sets --jobs=1]' \ '--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Tool version(s) to install e.g.\: nodejs@20:' \ +'*::runtime -- Tool version(s) to install e.g.\: node@20:' \ && ret=0 ;; (latest) @@ -737,8 +737,8 @@ by default this command will only set the runtime in the current directory ("$PW '--parent[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ '--pin[Save exact version to `.tool-versions` -e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions]' \ -'--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ +e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions]' \ +'--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the config file]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -752,7 +752,7 @@ Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::runtime -- Runtimes to add to .tool-versions/.rtx.toml -e.g.\: nodejs@20 +e.g.\: node@20 if this is a single runtime with no version, the current value of .tool-versions/.rtx.toml will be displayed:' \ && ret=0 @@ -872,8 +872,8 @@ Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::name -- The name of the plugin to install -e.g.\: nodejs, ruby -Can specify multiple plugins\: `rtx plugins install nodejs ruby python`:' \ +e.g.\: node, ruby +Can specify multiple plugins\: `rtx plugins install node ruby python`:' \ '::git_url -- The git url of the plugin:_urls' \ '*::rest:' \ && ret=0 @@ -899,9 +899,9 @@ Sets --jobs=1]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':name -- The name of the plugin -e.g.\: nodejs, ruby:' \ +e.g.\: node, ruby:' \ '::path -- The local path to the plugin -e.g.\: ./rtx-nodejs:_files -/' \ +e.g.\: ./rtx-node:_files -/' \ && ret=0 ;; (ls) @@ -920,9 +920,9 @@ Normally these are not shown]' \ '--core[The built-in plugins only Normally these are not shown]' \ '-u[Show the git url for each plugin -e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +e.g.: https://github.com/asdf-vm/asdf-node.git]' \ '--urls[Show the git url for each plugin -e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +e.g.: https://github.com/asdf-vm/asdf-node.git]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. @@ -943,8 +943,8 @@ default: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-u[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ -'--urls[Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git]' \ +'-u[Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git]' \ +'--urls[Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 71a254546..9410c91a2 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -286,9 +286,9 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` -e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions' +e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` -e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions +e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' complete -c rtx -n "__fish_seen_subcommand_from global" -l debug -d 'Sets log level to debug' @@ -352,8 +352,8 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` -e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' +e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' complete -c rtx -n "__fish_seen_subcommand_from local" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from local" -l install-missing -d 'Automatically install missing tools' @@ -441,7 +441,7 @@ Same as `rtx plugins ls-remote`' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s c -l core -d 'The built-in plugins only Normally these are not shown' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin -e.g.: https://github.com/asdf-vm/asdf-nodejs.git' +e.g.: https://github.com/asdf-vm/asdf-node.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -452,7 +452,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-nodejs.git' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' diff --git a/docs/demo.tape b/docs/demo.tape index 749c50f11..531a2350c 100644 --- a/docs/demo.tape +++ b/docs/demo.tape @@ -62,13 +62,13 @@ Type "http rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx" Enter Sleep 2s Type "chmod +x ~/bin/rtx" Sleep 1s Enter Sleep 1s Type "rtx -v" Sleep 1s Enter Sleep 1s Type 'eval "$(rtx activate bash)"' Sleep 1s Enter Sleep 2s -Type "rtx install nodejs@lts" Sleep 2s Enter Sleep 8s -Type "rtx global nodejs@lts" Sleep 2s Enter Sleep 3s +Type "rtx install node@lts" Sleep 2s Enter Sleep 8s +Type "rtx global node@lts" Sleep 2s Enter Sleep 3s Type "node -v" Sleep 1s Enter Sleep 3s Type "which node" Sleep 1s Enter Sleep 5s Type "cd ~/myproj" Sleep 1s Enter Sleep 1s -Type "rtx install nodejs@19" Sleep 2s Enter Sleep 8s -Type "rtx local nodejs@19" Sleep 2s Enter Sleep 2s +Type "rtx install node@19" Sleep 2s Enter Sleep 8s +Type "rtx local node@19" Sleep 2s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s Type "cd .." Sleep 1s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s diff --git a/docs/node.md b/docs/node.md new file mode 100644 index 000000000..f5795db9b --- /dev/null +++ b/docs/node.md @@ -0,0 +1,92 @@ +# node in rtx + +The following are instructions for using the node rtx core plugin. This is used when there isn't a +git plugin installed named "node". + +If you want to use [asdf-node](https://github.com/asdf-vm/asdf-nodejs) or +[rtx-node](https://github.com/rtx-plugins/rtx-nodejs) then use `rtx plugins install node URL`. + +The code for this is inside of the rtx repository at [`./src/plugins/core/node.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/node.rs). + +## Usage + +The following installs the latest version of node-20.x and makes it the global +default: + +```sh-session +$ rtx install node@20 +$ rtx global node@20 +``` + +Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. + + +```sh-session +$ rtx global node@18 node@20 +$ node -V +18.0.0 +$ node.11 -V +20.0.0 +``` + +## Configuration + +`node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-node` has a few extra configuration variables: + +- `RTX_NODE_VERBOSE_INSTALL`: Enables verbose output for downloading and building. +- `RTX_NODE_FORCE_COMPILE`: Forces compilation from source instead of preferring pre-compiled binaries +- `RTX_NODE_CONCURRENCY`: How many jobs should be used in compilation. Defaults to half the computer cores +- `RTX_NODE_DEFAULT_PACKAGES_FILE`: location of default packages file, defaults to `$HOME/.default-node-packages` +- `NODEJS_ORG_MIRROR`: (Legacy) overrides the default mirror used for downloading the + distibutions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var + +## Default node packages + +rtx-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-node-packages` file that lists one package per line, for example: + +``` +lodash +request +express +``` + +You can specify a non-default location of this file by setting a `RTX_NODE_DEFAULT_PACKAGES_FILE` variable. + +## `.nvmrc` and `.node-version` support + +rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. To ease migration, you can have also have it read an existing `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `node` isn't defined in `.tool-versions`/`.rtx.toml`. + + +## Running the wrapped node-build command + +We provide a command for running the installed `node-build` command: + +```bash +rtx node nodebuild --version +``` + +### node-build advanced variations + +`node-build` has some additional variations aside from the versions listed in `rtx ls-remote +node` (chakracore/graalvm branches and some others). As of now, we weakly support these variations. In the sense that they are available for install and can be used in a `.tool-versions` file, but we don't list them as installation candidates nor give them full attention. + +Some of them will work out of the box, and some will need a bit of investigation to get them built. We are planning in providing better support for these variations in the future. + +To list all the available variations run: + +```bash +rtx node nodebuild --definitions +``` + +_Note that this command only lists the current `node-build` definitions. You might want to [update the local `node-build` repository](#updating-node-build-definitions) before listing them._ + +### Manually updating node-build definitions + +Every new node version needs to have a definition file in the `node-build` repository. +`rtx-node` already tries to update `node-build` on every new version installation, but if you +want to update `node-build` manually for some reason you can clear the cache and list the versions: + +```bash +rtx cache clean +rtx ls-remote node +``` diff --git a/docs/nodejs.md b/docs/nodejs.md deleted file mode 100644 index 54b2a9930..000000000 --- a/docs/nodejs.md +++ /dev/null @@ -1,90 +0,0 @@ -# NodeJS in rtx - -The following are instructions for using the nodejs rtx core plugin. This is used when -the "experimental" setting is "true" and there isn't a git plugin installed named "nodejs" - -If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) or [rtx-nodejs](https://github.com/rtx-plugins/rtx-nodejs) then use `rtx plugins install nodejs URL`. - -The code for this is inside of the rtx repository at [`./src/plugins/core/nodejs.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/nodejs.rs). - -## Usage - -The following installs the latest version of nodejs-20.x and makes it the global -default: - -```sh-session -$ rtx install nodejs@20 -$ rtx global nodejs@20 -``` - -Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. - - -```sh-session -$ rtx global nodejs@18 nodejs@20 -$ nodejs -V -18.0.0 -$ nodejs.11 -V -20.0.0 -``` - -## Configuration - -`node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-nodejs` has a few extra configuration variables: - -- `RTX_NODEJS_VERBOSE_INSTALL`: Enables verbose output for downloading and building. -- `RTX_NODEJS_FORCE_COMPILE`: Forces compilation from source instead of preferring pre-compiled binaries -- `RTX_NODEJS_CONCURRENCY`: How many jobs should be used in compilation. Defaults to half the computer cores -- `RTX_NODEJS_DEFAULT_PACKAGES_FILE`: location of default packages file, defaults to `$HOME/.default-nodejs-packages` -- `NODEJS_ORG_MIRROR`: (Legacy) overrides the default mirror used for downloading the distibutions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var - -## Default NodeJS packages - -rtx-nodejs can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-nodejs-packages` file that lists one package per line, for example: - -``` -lodash -request -express -``` - -You can specify a non-default location of this file by setting a `RTX_NODEJS_DEFAULT_PACKAGES_FILE` variable. - -## `.nvmrc` and `.node-version` support - -rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. To ease migration, you can have also have it read an existing `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `nodejs` isn't defined in `.tool-versions`/`.rtx.toml`. - - -## Running the wrapped node-build command - -We provide a command for running the installed `node-build` command: - -```bash -rtx nodejs nodebuild --version -``` - -### node-build advanced variations - -`node-build` has some additional variations aside from the versions listed in `rtx ls-remote -nodejs` (chakracore/graalvm branches and some others). As of now, we weakly support these variations. In the sense that they are available for install and can be used in a `.tool-versions` file, but we don't list them as installation candidates nor give them full attention. - -Some of them will work out of the box, and some will need a bit of investigation to get them built. We are planning in providing better support for these variations in the future. - -To list all the available variations run: - -```bash -rtx nodejs nodebuild --definitions -``` - -_Note that this command only lists the current `node-build` definitions. You might want to [update the local `node-build` repository](#updating-node-build-definitions) before listing them._ - -### Manually updating node-build definitions - -Every new node version needs to have a definition file in the `node-build` repository. -`rtx-nodejs` already tries to update `node-build` on every new version installation, but if you -want to update `node-build` manually for some reason you can clear the cache and list the versions: - -```bash -rtx cache clean -rtx ls-remote nodejs -``` diff --git a/e2e/.default-nodejs-packages b/e2e/.default-node-packages similarity index 100% rename from e2e/.default-nodejs-packages rename to e2e/.default-node-packages diff --git a/e2e/.e2e-tool-versions b/e2e/.e2e-tool-versions index b73e001f9..0e45d0267 100644 --- a/e2e/.e2e-tool-versions +++ b/e2e/.e2e-tool-versions @@ -1,4 +1,4 @@ #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 20.0.0 +#node 20.0.0 diff --git a/e2e/cd/.e2e-tool-versions b/e2e/cd/.e2e-tool-versions index 6de89a83a..4d5dd711b 100644 --- a/e2e/cd/.e2e-tool-versions +++ b/e2e/cd/.e2e-tool-versions @@ -1 +1 @@ -nodejs 20.0.0 +node 20.0.0 diff --git a/e2e/cd/18/.e2e-tool-versions b/e2e/cd/18/.e2e-tool-versions index b00f5981f..085cfa216 100644 --- a/e2e/cd/18/.e2e-tool-versions +++ b/e2e/cd/18/.e2e-tool-versions @@ -1 +1 @@ -nodejs 18.0.0 +node 18.0.0 diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 4e5732621..06f137762 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -34,19 +34,19 @@ assert_path() { } test "$(node -v)" = "v20.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/node/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" assert "$FOO" "cd" cd 18 && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/18.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/node/18.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" assert "$FOO" "18" cd .. && _rtx_hook test "$(node -v)" = "v20.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/nodejs/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/node/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" -rtx shell nodejs@18.0.0 && _rtx_hook +rtx shell node@18.0.0 && _rtx_hook test "$(node -v)" = "v18.0.0" rtx deactivate diff --git a/e2e/cd/test_bash_legacy_activate b/e2e/cd/test_bash_legacy_activate index 3ca8a3622..53d175397 100755 --- a/e2e/cd/test_bash_legacy_activate +++ b/e2e/cd/test_bash_legacy_activate @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -rtx install nodejs@20.0.0 nodejs@18.0.0 +rtx install node@20.0.0 node@18.0.0 # shellcheck disable=SC1090 eval "$(rtx activate -s bash --status)" _rtx_hook diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index 9abe9deb4..32c2fb061 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -5,7 +5,7 @@ set -gx PATH $ROOT/target/debug:$PATH set -l orig_node (node -v) #set -l fish_trace 1 -rtx install nodejs@20.0.0 nodejs@18.0.0; or exit +rtx install node@20.0.0 node@18.0.0; or exit rtx activate --status fish | source __rtx_env_eval @@ -18,7 +18,7 @@ test (node -v) = "v18.0.0"; or exit cd .. && __rtx_env_eval test (node -v) = "v20.0.0"; or exit -rtx shell nodejs@18.0.0 && __rtx_env_eval +rtx shell node@18.0.0 && __rtx_env_eval test (node -v) = "v18.0.0"; or exit rtx deactivate diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index 4638f2eca..f992f0c66 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -18,7 +18,7 @@ assert_path() { fi } -rtx install nodejs@20.0.0 nodejs@18.0.0 +rtx install node@20.0.0 node@18.0.0 # shellcheck disable=SC1090 eval "$(rtx activate zsh --status)" && _rtx_hook @@ -32,7 +32,7 @@ test "$(node -v)" = "v18.0.0" cd .. && _rtx_hook test "$(node -v)" = "v20.0.0" -rtx shell nodejs@18.0.0 && _rtx_hook +rtx shell node@18.0.0 && _rtx_hook test "$(node -v)" = "v18.0.0" rtx deactivate diff --git a/e2e/config/.e2e-tool-versions b/e2e/config/.e2e-tool-versions index b73e001f9..0e45d0267 100644 --- a/e2e/config/.e2e-tool-versions +++ b/e2e/config/.e2e-tool-versions @@ -1,4 +1,4 @@ #python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 20.0.0 +#node 20.0.0 diff --git a/e2e/config/cd/.e2e-tool-versions b/e2e/config/cd/.e2e-tool-versions index 6de89a83a..4d5dd711b 100644 --- a/e2e/config/cd/.e2e-tool-versions +++ b/e2e/config/cd/.e2e-tool-versions @@ -1 +1 @@ -nodejs 20.0.0 +node 20.0.0 diff --git a/e2e/config/cd/18/.e2e-tool-versions b/e2e/config/cd/18/.e2e-tool-versions index b00f5981f..085cfa216 100644 --- a/e2e/config/cd/18/.e2e-tool-versions +++ b/e2e/config/cd/18/.e2e-tool-versions @@ -1 +1 @@ -nodejs 18.0.0 +node 18.0.0 diff --git a/e2e/direnv/system_version/.e2e-tool-versions b/e2e/direnv/system_version/.e2e-tool-versions index 10edede5b..7a49400be 100644 --- a/e2e/direnv/system_version/.e2e-tool-versions +++ b/e2e/direnv/system_version/.e2e-tool-versions @@ -1 +1 @@ -nodejs system +node system diff --git a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions index b00f5981f..085cfa216 100644 --- a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions +++ b/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions @@ -1 +1 @@ -nodejs 18.0.0 +node 18.0.0 diff --git a/e2e/direnv/system_version/test_direnv_system_version b/e2e/direnv/system_version/test_direnv_system_version index 4bbfc8484..a747da879 100755 --- a/e2e/direnv/system_version/test_direnv_system_version +++ b/e2e/direnv/system_version/test_direnv_system_version @@ -9,11 +9,11 @@ _rtx_hook && _direnv_hook # use old node version on purpose to not conflict with unknown system node version custom_node_version="18.0.0" -rtx_nodejs_path_segment="${RTX_DATA_DIR}/installs/nodejs" +rtx_node_path_segment="${RTX_DATA_DIR}/installs/node" -# with nodejs@system rtx should not add a nodejs path segment -if [[ $PATH == *"${rtx_nodejs_path_segment}"* ]]; then - echo "Rtx nodejs path segment: ${rtx_nodejs_path_segment} must not be in PATH: ${PATH}" +# with node@system rtx should not add a node path segment +if [[ $PATH == *"${rtx_node_path_segment}"* ]]; then + echo "Rtx node path segment: ${rtx_node_path_segment} must not be in PATH: ${PATH}" exit 1 fi @@ -29,8 +29,8 @@ direnv allow rtx-direnv-system-version-reset/load-first # test -# install custom nodejs version -rtx i nodejs@$custom_node_version && _rtx_hook +# install custom node version +rtx i node@$custom_node_version && _rtx_hook cd rtx-direnv-system-version-reset/load-first && _rtx_hook && _direnv_hook node_version=$(node -v) @@ -39,16 +39,16 @@ if [[ $node_version != "v${custom_node_version}" ]]; then exit 1 fi -if [[ ! $PATH == *"${rtx_nodejs_path_segment}/${custom_node_version}"* ]]; then - echo "Rtx nodejs path segment: ${rtx_nodejs_path_segment}/${custom_node_version} must be in PATH: ${PATH}" +if [[ ! $PATH == *"${rtx_node_path_segment}/${custom_node_version}"* ]]; then + echo "Rtx node path segment: ${rtx_node_path_segment}/${custom_node_version} must be in PATH: ${PATH}" exit 1 fi cd .. && _rtx_hook && _direnv_hook -# with nodejs@system rtx should not add a nodejs path segment -if [[ $PATH == *"${rtx_nodejs_path_segment}"* ]]; then - echo "Rtx nodejs path segment: ${rtx_nodejs_path_segment} must not be in PATH: ${PATH}" +# with node@system rtx should not add a node path segment +if [[ $PATH == *"${rtx_node_path_segment}"* ]]; then + echo "Rtx node path segment: ${rtx_node_path_segment} must not be in PATH: ${PATH}" exit 1 fi diff --git a/e2e/test_env b/e2e/test_env index 23644601e..524ad9ee5 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -2,10 +2,10 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" -rtx i nodejs +rtx i node eval "$(rtx env -s bash)" assert "node -v" "v20.0.0" -rtx i nodejs@18.0.0 -eval "$(rtx env -s bash nodejs@18.0.0)" +rtx i node@18.0.0 +eval "$(rtx env -s bash node@18.0.0)" assert "node -v" "v18.0.0" assert "rtx x -- env | grep FOO_FROM_FILE" "FOO_FROM_FILE=foo_from_file" diff --git a/e2e/test_local b/e2e/test_local index ea25bf085..7f98f130d 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -87,14 +87,14 @@ rtx local --install-missing assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 20.0.0 +#node 20.0.0 " rtx local shfmt@3.5.0 assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.5.0 # test comment -#nodejs 20.0.0 +#node 20.0.0 " rtx exec -- shfmt --version >&2 @@ -106,7 +106,7 @@ rtx local shfmt@3.6.0 assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck 0.9.0 shfmt 3.6.0 # test comment -#nodejs 20.0.0 +#node 20.0.0 " rtx exec -- shfmt --version >&2 diff --git a/e2e/test_log_level b/e2e/test_log_level index b93f5564c..ad5fec022 100755 --- a/e2e/test_log_level +++ b/e2e/test_log_level @@ -10,7 +10,7 @@ assert() { fi } -assert "rtx x nodejs@20.0.0 --log-level debug -- node -v" "v20.0.0" -assert "rtx x nodejs@20.0.0 --log-level=debug -- node -v" "v20.0.0" -assert "rtx x nodejs@20.0.0 --debug -- node -v" "v20.0.0" -assert "rtx x nodejs@20.0.0 --trace -- node -v" "v20.0.0" +assert "rtx x node@20.0.0 --log-level debug -- node -v" "v20.0.0" +assert "rtx x node@20.0.0 --log-level=debug -- node -v" "v20.0.0" +assert "rtx x node@20.0.0 --debug -- node -v" "v20.0.0" +assert "rtx x node@20.0.0 --trace -- node -v" "v20.0.0" diff --git a/e2e/test_ls_remote b/e2e/test_ls_remote index 0239677d9..8c05d2eff 100755 --- a/e2e/test_ls_remote +++ b/e2e/test_ls_remote @@ -2,7 +2,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" -rtx p list-remote | grep nodejs +rtx p list-remote | grep node rtx p uninstall tiny assert_fail "RTX_CONFIRM=no rtx ls-remote tiny" assert_contains "RTX_CONFIRM=yes rtx ls-remote tiny" "1.1.0" diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 274cdae55..91dfdeecc 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -3,10 +3,10 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 -export RTX_NODEJS_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-nodejs-packages" +export RTX_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-node-packages" -rtx plugin uninstall nodejs -rtx i nodejs nodejs@lts/hydrogen -assert_contains "rtx x nodejs@lts/hydrogen -- node --version" "v18." +rtx plugin uninstall node +rtx i node node@lts/hydrogen +assert_contains "rtx x node@lts/hydrogen -- node --version" "v18." assert "rtx x -- node --version" "v20.0.0" -assert_contains "rtx nodejs nodebuild --version" "node-build " +assert_contains "rtx node nodebuild --version" "node-build " diff --git a/e2e/test_shell b/e2e/test_shell index 0b200921c..2fcdada94 100755 --- a/e2e/test_shell +++ b/e2e/test_shell @@ -5,7 +5,7 @@ source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 eval "$(rtx activate bash)" && eval "$(rtx hook-env)" assert "node -v" "v20.0.0" -rtx shell nodejs@18.0.0 && eval "$(rtx hook-env)" +rtx shell node@18.0.0 && eval "$(rtx hook-env)" assert "node -v" "v18.0.0" -export RTX_NODEJS_VERSION=20.0.0 && eval "$(rtx hook-env)" +export RTX_NODE_VERSION=20.0.0 && eval "$(rtx hook-env)" assert "node -v" "v20.0.0" diff --git a/e2e/test_shims b/e2e/test_shims index 94991326c..b80447b5d 100755 --- a/e2e/test_shims +++ b/e2e/test_shims @@ -2,5 +2,6 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" +rtx i node rtx reshim assert "$RTX_DATA_DIR/shims/node -v" "v20.0.0" diff --git a/e2e/test_system b/e2e/test_system index ddc28f19e..68bc81bce 100755 --- a/e2e/test_system +++ b/e2e/test_system @@ -7,5 +7,5 @@ export RTX_EXPERIMENTAL=1 system_node="$(which node)" rtx_node="$(rtx which node)" -assert "rtx x nodejs@system -- which node" "$system_node" -assert "rtx x nodejs -- which node" "$rtx_node" +assert "rtx x node@system nodejs@system -- which node" "$system_node" +assert "rtx x node -- which node" "$rtx_node" diff --git a/e2e/test_top_runtimes b/e2e/test_top_runtimes index 338f509f2..eee1757bc 100755 --- a/e2e/test_top_runtimes +++ b/e2e/test_top_runtimes @@ -56,7 +56,7 @@ exit 0 # disable for now for faster releases # 15 kustomize # 15 graalvm -rtx exec nodejs -- node -v +rtx exec node -- node -v rtx exec python -- python -V rtx exec direnv -- direnv --version rtx exec erlang -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 2c88c1f45..52d506eb2 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -131,15 +131,15 @@ rtx\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA Examples: - $ rtx install nodejs@20.0.0 Install a specific node version - $ rtx install nodejs@20.0 Install a version matching a prefix - $ rtx install nodejs Install the node version defined in + $ rtx install node@20.0.0 Install a specific node version + $ rtx install node@20.0 Install a version matching a prefix + $ rtx install node Install the node version defined in .tool\-versions or .rtx.toml - $ rtx local nodejs@20 Use node\-20.x in current project - $ rtx global nodejs@20 Use node\-20.x as default - $ rtx local nodejs@latest Use latest node in current directory - $ rtx global nodejs@system Use system node everywhere unless overridden - $ rtx x nodejs@20 \-\- node app.js Run `node app.js` with PATH pointing to + $ rtx local node@20 Use node\-20.x in current project + $ rtx global node@20 Use node\-20.x as default + $ rtx local node@latest Use latest node in current directory + $ rtx global node@system Use system node everywhere unless overridden + $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION v1.28.6 diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index a4d53f072..a20325edf 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -34,7 +34,7 @@ def install test do system "#{bin}/rtx --version" - system "#{bin}/rtx", "install", "nodejs@20.0.0" - assert_match "v20.0.0", shell_output("#{bin}/rtx exec nodejs@20.0.0 -- node -v") + system "#{bin}/rtx", "install", "node@20.0.0" + assert_match "v20.0.0", shell_output("#{bin}/rtx exec node@20.0.0 -- node -v") end end diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index c63beb1db..951c46f95 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -31,7 +31,7 @@ impl Command for AliasGet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias get nodejs lts/hydrogen + $ rtx alias get node lts/hydrogen 20.0.0 "# ); diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 9dea69044..4b6da6d2a 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -11,7 +11,7 @@ use crate::plugins::PluginName; /// /// For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: /// -/// [alias.nodejs] +/// [alias.node] /// lts = "20.0.0" #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] @@ -28,6 +28,8 @@ impl Command for AliasLs { if plugin_name != plugin { continue; } + } else if config.is_plugin_hidden(plugin_name) { + continue; } for (from, to) in aliases.iter() { @@ -41,7 +43,7 @@ impl Command for AliasLs { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx aliases - nodejs lts/hydrogen 20.0.0 + node lts/hydrogen 20.0.0 "# ); diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 561061f53..0028a32ed 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -30,7 +30,7 @@ impl Command for AliasSet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias set nodejs lts/hydrogen 18.0.0 + $ rtx alias set node lts/hydrogen 18.0.0 "# ); diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 4c0f540c2..c54a67ed2 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -11,15 +11,6 @@ node lts/erbium 12 node lts/fermium 14 node lts/gallium 16 node lts/hydrogen 18 -nodejs lts 18 -nodejs lts/argon 4 -nodejs lts/boron 6 -nodejs lts/carbon 8 -nodejs lts/dubnium 10 -nodejs lts/erbium 12 -nodejs lts/fermium 14 -nodejs lts/gallium 16 -nodejs lts/hydrogen 18 tiny lts 3.1.0 tiny lts-prev 2.0.0 tiny my/alias 3.0 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index 6c1ed5eef..726ffd8eb 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -11,15 +11,6 @@ node lts/erbium 12 node lts/fermium 14 node lts/gallium 16 node lts/hydrogen 18 -nodejs lts 18 -nodejs lts/argon 4 -nodejs lts/boron 6 -nodejs lts/carbon 8 -nodejs lts/dubnium 10 -nodejs lts/erbium 12 -nodejs lts/fermium 14 -nodejs lts/gallium 16 -nodejs lts/hydrogen 18 tiny lts 3.1.0 tiny lts-prev 2.0.0 diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 2e660ef43..41d44bedb 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -26,7 +26,7 @@ impl Command for AliasUnset { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias unset nodejs lts/hydrogen + $ rtx alias unset node lts/hydrogen "# ); diff --git a/src/cli/args/runtime.rs b/src/cli/args/runtime.rs index fbfeb4579..911ea67ae 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/runtime.rs @@ -29,9 +29,9 @@ impl RuntimeArg { } /// this handles the case where the user typed in: - /// rtx local nodejs 20.0.0 + /// rtx local node 20.0.0 /// instead of - /// rtx local nodejs@20.0.0 + /// rtx local node@20.0.0 /// /// We can detect this, and we know what they meant, so make it work the way /// they expected. diff --git a/src/cli/current.rs b/src/cli/current.rs index fb4501ccd..2a9ab7e30 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -15,7 +15,7 @@ use crate::toolset::{Toolset, ToolsetBuilder}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Current { /// Plugin to show versions of - /// e.g.: ruby, nodejs + /// e.g.: ruby, node #[clap()] plugin: Option, } @@ -101,9 +101,9 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( python 3.11.0 3.10.0 shfmt 3.6.0 shellcheck 0.9.0 - nodejs 20.0.0 + node 20.0.0 - $ rtx current nodejs + $ rtx current node 20.0.0 # can output multiple versions diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index ae6dab911..7794b8358 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -180,6 +180,6 @@ fn indent(s: String) -> String { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx doctor - [WARN] plugin nodejs is not installed + [WARN] plugin node is not installed "# ); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 4de2d5a5b..6c1c787d9 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -23,14 +23,14 @@ use crate::toolset::ToolsetBuilder; /// /// Runtimes will be loaded from .tool-versions, though they can be overridden with args /// Note that only the plugin specified will be overridden, so if a `.tool-versions` file -/// includes "nodejs 20" but you run `rtx exec python@3.11`; it will still load nodejs@20. +/// includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. /// /// The "--" separates runtimes from the commands to pass along to the subprocess. #[derive(Debug, clap::Args)] #[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Exec { /// Runtime(s) to start - /// e.g.: nodejs@20 python@3.10 + /// e.g.: node@20 python@3.10 #[clap(value_parser = RuntimeArgParser)] pub runtime: Vec, @@ -125,14 +125,14 @@ fn parse_command( static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx exec nodejs@20 -- node ./app.js # launch app.js using node-20.x - $ rtx x nodejs@20 -- node ./app.js # shorter alias + $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x + $ rtx x node@20 -- node ./app.js # shorter alias # Specify command as a string: - $ rtx exec nodejs@20 python@3.11 --command "node -v && python -V" + $ rtx exec node@20 python@3.11 --command "node -v && python -V" # Run a command in a different directory: - $ rtx x -C /path/to/project nodejs@20 -- node ./app.js + $ rtx x -C /path/to/project node@20 -- node ./app.js "# ); diff --git a/src/cli/global.rs b/src/cli/global.rs index f20ccb5fd..de83d6fd0 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -23,19 +23,19 @@ use crate::{dirs, env}; #[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP)] pub struct Global { /// Runtime(s) to add to .tool-versions - /// e.g.: nodejs@20 + /// e.g.: node@20 /// If this is a single runtime with no version, the current value of the global /// .tool-versions will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] runtime: Option>, /// Save exact version to `~/.tool-versions` - /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to ~/.tool-versions + /// e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `~/.tool-versions` - /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to ~/.tool-versions + /// e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, @@ -76,16 +76,16 @@ fn global_file() -> PathBuf { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # set the current version of nodejs to 20.x + # set the current version of node to 20.x # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx global --fuzzy nodejs@20 + $ rtx global --fuzzy node@20 - # set the current version of nodejs to 20.x + # set the current version of node to 20.x # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global --pin nodejs@20 + $ rtx global --pin node@20 - # show the current version of nodejs in ~/.tool-versions - $ rtx global nodejs + # show the current version of node in ~/.tool-versions + $ rtx global node 20.0.0 "# ); diff --git a/src/cli/install.rs b/src/cli/install.rs index c85355520..4c0ccbcfe 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -35,7 +35,7 @@ use crate::ui::progress_report::ProgressReport; #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Install { /// Tool version(s) to install - /// e.g.: nodejs@20 + /// e.g.: node@20 #[clap(value_parser = RuntimeArgParser)] runtime: Option>, @@ -258,9 +258,9 @@ impl Install { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx install nodejs@20.0.0 # install specific nodejs version - $ rtx install nodejs@20 # install fuzzy nodejs version - $ rtx install nodejs # install version specified in .tool-versions or .rtx.toml + $ rtx install node@20.0.0 # install specific node version + $ rtx install node@20 # install fuzzy node version + $ rtx install node # install version specified in .tool-versions or .rtx.toml $ rtx install # installs everything specified in .tool-versions or .rtx.toml "# ); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 8202105bf..3ad6013ef 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -54,10 +54,10 @@ impl Command for Latest { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx latest nodejs@20 # get the latest version of nodejs 20 + $ rtx latest node@20 # get the latest version of node 20 20.0.0 - $ rtx latest nodejs # get the latest stable version of nodejs + $ rtx latest node # get the latest stable version of node 20.0.0 "# ); diff --git a/src/cli/local.rs b/src/cli/local.rs index 69946b6a7..0a6f98a81 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -22,7 +22,7 @@ use crate::{dirs, env, file}; #[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP)] pub struct Local { /// Runtimes to add to .tool-versions/.rtx.toml - /// e.g.: nodejs@20 + /// e.g.: node@20 /// if this is a single runtime with no version, /// the current value of .tool-versions/.rtx.toml will be displayed #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] @@ -34,12 +34,12 @@ pub struct Local { parent: bool, /// Save exact version to `.tool-versions` - /// e.g.: `rtx local --pin nodejs@20` will save `nodejs 20.0.0` to .tool-versions + /// e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `.tool-versions` - /// e.g.: `rtx local --fuzzy nodejs@20` will save `nodejs 20` to .tool-versions + /// e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions /// This is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, @@ -152,22 +152,22 @@ fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result< static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # set the current version of nodejs to 20.x for the current directory + # set the current version of node to 20.x for the current directory # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx local nodejs@20 + $ rtx local node@20 - # set nodejs to 20.x for the current project (recurses up to find .tool-versions) - $ rtx local -p nodejs@20 + # set node to 20.x for the current project (recurses up to find .tool-versions) + $ rtx local -p node@20 - # set the current version of nodejs to 20.x for the current directory + # set the current version of node to 20.x for the current directory # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx local --fuzzy nodejs@20 + $ rtx local --fuzzy node@20 - # removes nodejs from .tool-versions - $ rtx local --remove=nodejs + # removes node from .tool-versions + $ rtx local --remove=node - # show the current version of nodejs in .tool-versions - $ rtx local nodejs + # show the current version of node in .tool-versions + $ rtx local node 20.0.0 "# ); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 74898479d..c859f969a 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -279,24 +279,24 @@ impl Display for VersionStatus { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx ls - ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) python 3.10.0 $ rtx ls --current - ⏵ nodejs 20.0.0 (set by ~/src/myapp/.tool-versions) + ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) ⏵ python 3.11.0 (set by ~/.tool-versions) $ rtx ls --parseable - nodejs 20.0.0 + node 20.0.0 python 3.11.0 $ rtx ls --json { - "nodejs": [ + "node": [ { "version": "20.0.0", - "install_path": "/Users/jdx/.rtx/installs/nodejs/20.0.0", + "install_path": "/Users/jdx/.rtx/installs/node/20.0.0", "source": { "type": ".rtx.toml", "path": "/Users/jdx/.rtx.toml" diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 5a1fb3d1c..4bdd83c61 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -82,15 +82,15 @@ impl LsRemote { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx ls-remote nodejs + $ rtx ls-remote node 18.0.0 20.0.0 - $ rtx ls-remote nodejs@20 + $ rtx ls-remote node@20 20.0.0 20.1.0 - $ rtx ls-remote nodejs 20 + $ rtx ls-remote node 20 20.0.0 20.1.0 "# diff --git a/src/cli/mod.rs b/src/cli/mod.rs index c943a611e..1d688c7a1 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -243,15 +243,15 @@ https://asdf-vm.com/"}; static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx install nodejs@20.0.0 Install a specific node version - $ rtx install nodejs@20.0 Install a version matching a prefix - $ rtx install nodejs Install the node version defined in + $ rtx install node@20.0.0 Install a specific node version + $ rtx install node@20.0 Install a version matching a prefix + $ rtx install node Install the node version defined in .tool-versions or .rtx.toml - $ rtx local nodejs@20 Use node-20.x in current project - $ rtx global nodejs@20 Use node-20.x as default - $ rtx local nodejs@latest Use latest node in current directory - $ rtx global nodejs@system Use system node everywhere unless overridden - $ rtx x nodejs@20 -- node app.js Run `node app.js` with PATH pointing to + $ rtx local node@20 Use node-20.x in current project + $ rtx global node@20 Use node-20.x as default + $ rtx local node@latest Use latest node in current directory + $ rtx global node@system Use system node everywhere unless overridden + $ rtx x node@20 -- node app.js Run `node app.js` with PATH pointing to node-20.x "# ); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 3bc982806..4318e01ad 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -14,20 +14,20 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Install a plugin /// /// note that rtx automatically can install plugins when you install a runtime -/// e.g.: `rtx install nodejs@20` will autoinstall the nodejs plugin +/// e.g.: `rtx install node@20` will autoinstall the node plugin /// /// This behavior can be modified in ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] #[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct PluginsInstall { /// The name of the plugin to install - /// e.g.: nodejs, ruby - /// Can specify multiple plugins: `rtx plugins install nodejs ruby python` + /// e.g.: node, ruby + /// Can specify multiple plugins: `rtx plugins install node ruby python` #[clap(required_unless_present = "all", verbatim_doc_comment)] name: Option, /// The git url of the plugin - /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git + /// e.g.: https://github.com/asdf-vm/asdf-node.git #[clap(help = "The git url of the plugin", value_hint = clap::ValueHint::Url, verbatim_doc_comment)] git_url: Option, @@ -153,18 +153,18 @@ fn get_name_from_url(url: &str) -> Result { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # install the nodejs via shorthand - $ rtx plugins install nodejs + # install the node via shorthand + $ rtx plugins install node - # install the nodejs plugin using a specific git url - $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git + # install the node plugin using a specific git url + $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git - # install the nodejs plugin using the git url only - # (nodejs is inferred from the url) - $ rtx plugins install https://github.com/jdxcode/rtx-nodejs.git + # install the node plugin using the git url only + # (node is inferred from the url) + $ rtx plugins install https://github.com/rtx-plugins/rtx-nodejs.git - # install the nodejs plugin using a specific ref - $ rtx plugins install nodejs https://github.com/jdxcode/rtx-nodejs.git#v1.0.0 + # install the node plugin using a specific ref + $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 "# ); diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index a2bca7b5f..a72f3530e 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -18,12 +18,12 @@ use crate::output::Output; #[clap(alias = "l", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct PluginsLink { /// The name of the plugin - /// e.g.: nodejs, ruby + /// e.g.: node, ruby #[clap(verbatim_doc_comment)] name: String, /// The local path to the plugin - /// e.g.: ./rtx-nodejs + /// e.g.: ./rtx-node #[clap(value_hint = ValueHint::DirPath, verbatim_doc_comment)] path: Option, @@ -69,11 +69,11 @@ fn get_name_from_path(path: &Path) -> String { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # essentially just `ln -s ./rtx-nodejs ~/.local/share/rtx/plugins/nodejs` - $ rtx plugins link nodejs ./rtx-nodejs + # essentially just `ln -s ./rtx-node ~/.local/share/rtx/plugins/node` + $ rtx plugins link node ./rtx-node - # infer plugin name as "nodejs" - $ rtx plugins link ./rtx-nodejs + # infer plugin name as "node" + $ rtx plugins link ./rtx-node "# ); diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index ea5b5b808..2640e7f39 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -23,7 +23,7 @@ pub struct PluginsLs { pub core: bool, /// Show the git url for each plugin - /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git + /// e.g.: https://github.com/asdf-vm/asdf-node.git #[clap(short, long, verbatim_doc_comment)] pub urls: bool, } @@ -66,11 +66,11 @@ impl Command for PluginsLs { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx plugins ls - nodejs + node ruby $ rtx plugins ls --urls - nodejs https://github.com/asdf-vm/asdf-nodejs.git + node https://github.com/asdf-vm/asdf-node.git ruby https://github.com/asdf-vm/asdf-ruby.git "# ); diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index cd197245a..ffff4eba2 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -9,13 +9,11 @@ use crate::config::Config; use crate::output::Output; /// List all available remote plugins -/// -/// These are fetched from https://github.com/asdf-vm/asdf-plugins #[derive(Debug, clap::Args)] #[clap(visible_alias = "list-remote", long_about = LONG_ABOUT, verbatim_doc_comment, alias = "list-all")] pub struct PluginsLsRemote { /// Show the git url for each plugin - /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git + /// e.g.: https://github.com/rtx-plugins/rtx-nodejs.git #[clap(short, long)] pub urls: bool, @@ -63,7 +61,7 @@ impl Command for PluginsLsRemote { const LONG_ABOUT: &str = r#" List all available remote plugins -These are fetched from https://github.com/asdf-vm/asdf-plugins +The full list is here: https://github.com/jdxcode/rtx/blob/main/src/default_shorthands.rs Examples: $ rtx plugins ls-remote diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index f769c02ac..3c41d3f49 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -31,7 +31,7 @@ pub struct Plugins { /// show the git url for each plugin /// - /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git + /// e.g.: https://github.com/asdf-vm/asdf-node.git #[clap(short, long)] pub urls: bool, } diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index e461092c6..5ce980afe 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -53,6 +53,6 @@ impl PluginsUninstall { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx uninstall nodejs + $ rtx uninstall node "# ); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index c26e0ce5d..342a61e8d 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -55,8 +55,8 @@ impl Command for Update { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx plugins update # update all plugins - $ rtx plugins update nodejs # update only nodejs - $ rtx plugins update nodejs@beta # specify a ref + $ rtx plugins update node # update only node + $ rtx plugins update node@beta # specify a ref "# ); diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 003c2b864..d7c05d714 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -73,8 +73,8 @@ impl Prune { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/nodejs/20.0.0 - rm -rf ~/.local/share/rtx/versions/nodejs/20.0.1 + rm -rf ~/.local/share/rtx/versions/node/20.0.0 + rm -rf ~/.local/share/rtx/versions/node/20.0.1 "# ); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 5d1ba90a9..31bc7680a 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -64,7 +64,7 @@ fn err_inactive() -> Result<()> { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx shell nodejs@20 + $ rtx shell node@20 $ node -v v20.0.0 "# diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 6abe7d89e..8c219dfcf 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -61,7 +61,7 @@ impl Command for Uninstall { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx uninstall nodejs@18.0.0 # will uninstall specific version - $ rtx uninstall nodejs # will uninstall current nodejs version + $ rtx uninstall node@18.0.0 # will uninstall specific version + $ rtx uninstall node # will uninstall current node version "# ); diff --git a/src/cli/where.rs b/src/cli/where.rs index e5d304bff..de5687eac 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -73,15 +73,15 @@ impl Command for Where { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # Show the latest installed version of nodejs + # Show the latest installed version of node # If it is is not installed, errors - $ rtx where nodejs@20 - /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 + $ rtx where node@20 + /home/jdx/.local/share/rtx/installs/node/20.0.0 - # Show the current, active install directory of nodejs - # Errors if nodejs is not referenced in any .tool-version file - $ rtx where nodejs - /home/jdx/.local/share/rtx/installs/nodejs/20.0.0 + # Show the current, active install directory of node + # Errors if node is not referenced in any .tool-version file + $ rtx where node + /home/jdx/.local/share/rtx/installs/node/20.0.0 "# ); diff --git a/src/cli/which.rs b/src/cli/which.rs index 49a91e59c..57c5e9202 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -45,9 +45,9 @@ impl Command for Which { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx which node - /home/username/.local/share/rtx/installs/nodejs/20.0.0/bin/node + /home/username/.local/share/rtx/installs/node/20.0.0/bin/node $ rtx which node --plugin - nodejs + node $ rtx which node --version 20.0.0 "# diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 34393d639..9af87c97d 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -124,7 +124,7 @@ impl dyn ConfigFile { rtxprintln!(out, "{}", tvl.join(" ")); return Ok(true); } - // check for something like `rtx local nodejs python@latest` which is invalid + // check for something like `rtx local node python@latest` which is invalid if runtimes.iter().any(|r| r.tvr.is_none()) { return Err(eyre!("invalid input, specify a version for each runtime. Or just specify one runtime to print the current version")); } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 39da3bed2..ff16f3c37 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -788,14 +788,14 @@ mod tests { fn test_set_alias() { let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); cf.parse(&formatdoc! {r#" - [alias.nodejs] + [alias.node] 16 = "16.0.0" 18 = "18.0.0" "#}) .unwrap(); - cf.set_alias("nodejs", "18", "18.0.1"); - cf.set_alias("nodejs", "20", "20.0.0"); + cf.set_alias("node", "18", "18.0.1"); + cf.set_alias("node", "20", "20.0.0"); cf.set_alias("python", "3.10", "3.10.0"); assert_debug_snapshot!(cf.alias); @@ -806,7 +806,7 @@ mod tests { fn test_remove_alias() { let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); cf.parse(&formatdoc! {r#" - [alias.nodejs] + [alias.node] 16 = "16.0.0" 18 = "18.0.0" @@ -814,7 +814,7 @@ mod tests { "3.10" = "3.10.0" "#}) .unwrap(); - cf.remove_alias("nodejs", "16"); + cf.remove_alias("node", "16"); cf.remove_alias("python", "3.10"); assert_debug_snapshot!(cf.alias); @@ -826,11 +826,11 @@ mod tests { let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); cf.parse(&formatdoc! {r#" [tools] - nodejs = ["16.0.0", "18.0.0"] + node = ["16.0.0", "18.0.0"] "#}) .unwrap(); cf.replace_versions( - &PluginName::from("nodejs"), + &PluginName::from("node"), &["16.0.1".into(), "18.0.1".into()], ); @@ -843,10 +843,10 @@ mod tests { let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); cf.parse(&formatdoc! {r#" [tools] - nodejs = ["16.0.0", "18.0.0"] + node = ["16.0.0", "18.0.0"] "#}) .unwrap(); - cf.remove_plugin(&PluginName::from("nodejs")); + cf.remove_plugin(&PluginName::from("node")); assert_debug_snapshot!(cf.toolset); assert_display_snapshot!(cf); @@ -858,7 +858,7 @@ mod tests { cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true - [alias.nodejs] + [alias.node] 18 = "18.0.0" "#}) .unwrap(); @@ -866,7 +866,7 @@ mod tests { assert_display_snapshot!(cf.dump(), @r###" [settings] legacy_version_file = false - [alias.nodejs] + [alias.node] 18 = "18.0.0" "###); } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap index 740232f39..c145e1b04 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap @@ -3,5 +3,5 @@ source: src/config/config_file/rtx_toml.rs expression: cf.plugins() --- { - "nodejs": "https://github.com/jdxcode/rtx-nodejs", + "node": "https://github.com/jdxcode/rtx-node", } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index 223b8ee6c..971eaba29 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -20,34 +20,34 @@ Toolset { "~/fixtures/.rtx.toml", ), }, - "nodejs": ToolVersionList { - plugin_name: "nodejs", + "node": ToolVersionList { + plugin_name: "node", versions: [], requests: [ ( Version( - "nodejs", + "node", "18", ), {}, ), ( Prefix( - "nodejs", + "node", "20", ), {}, ), ( Ref( - "nodejs", + "node", "master", ), {}, ), ( Path( - "nodejs", + "node", "~/.nodes/18", ), {}, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap index 376c3376e..c76dd3fff 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap @@ -3,7 +3,7 @@ source: src/config/config_file/rtx_toml.rs expression: cf.alias --- { - "nodejs": { + "node": { "my_custom_node": "18", }, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index fb996d02f..00333c559 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -7,7 +7,7 @@ NODE_ENV = 'production' [tools] terraform = '1.0.0' -nodejs = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18'] +node = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18'] jq = { prefix = '1.6' } shellcheck = { version = '0.9.0' } python = [ @@ -16,11 +16,11 @@ python = [ ] [plugins] -nodejs = 'https://github.com/jdxcode/rtx-nodejs' +node = 'https://github.com/jdxcode/rtx-node' [settings] verbose = true missing_runtime_behavior = 'warn' -[alias.nodejs] +[alias.node] my_custom_node = '18' diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap index 78c5edcad..cb58ec131 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap @@ -2,6 +2,5 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- -[alias.nodejs] +[alias.node] 18 = "18.0.0" - diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap index 0309db019..08e7e7ca3 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap @@ -3,7 +3,7 @@ source: src/config/config_file/rtx_toml.rs expression: cf.alias --- { - "nodejs": { + "node": { "18": "18.0.0", }, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap index 2423c3fa4..4fbd85b70 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap @@ -3,5 +3,4 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- [tools] -nodejs = ["16.0.1", "18.0.1"] - +node = ["16.0.1", "18.0.1"] diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index 0efbd05e0..b7ab2dfcf 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -4,20 +4,20 @@ expression: cf.toolset --- Toolset { versions: { - "nodejs": ToolVersionList { - plugin_name: "nodejs", + "node": ToolVersionList { + plugin_name: "node", versions: [], requests: [ ( Version( - "nodejs", + "node", "16.0.1", ), {}, ), ( Version( - "nodejs", + "node", "18.0.1", ), {}, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap index 466b9f027..ac48a5daa 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap @@ -2,11 +2,10 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- -[alias.nodejs] +[alias.node] 16 = "16.0.0" 18 = "18.0.1" 20 = "20.0.0" [alias.python] "3.10" = "3.10.0" - diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap index e4fb6ac7e..824092020 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap @@ -3,7 +3,7 @@ source: src/config/config_file/rtx_toml.rs expression: cf.alias --- { - "nodejs": { + "node": { "16": "16.0.0", "18": "18.0.1", "20": "20.0.0", diff --git a/src/config/mod.rs b/src/config/mod.rs index ff230b583..9eed2322c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,7 +17,7 @@ use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; use crate::env::CI; -use crate::plugins::core::CORE_PLUGINS; +use crate::plugins::core::{CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::tool::Tool; @@ -249,6 +249,15 @@ impl Config { ); } } + + pub fn is_plugin_hidden(&self, plugin_name: &PluginName) -> bool { + self.tools.get(plugin_name).map_or(false, |tool| { + if matches!(tool.plugin.get_type(), PluginType::External) { + return false; + } + plugin_name == "nodejs" || plugin_name == "golang" + }) + } } fn get_project_root(config_files: &ConfigMap) -> Option { @@ -295,9 +304,9 @@ fn load_rtxrc() -> Result { } fn load_tools(settings: &Settings) -> Result { - let mut tools = ToolMap::new(); + let mut tools = CORE_PLUGINS.clone(); if settings.experimental { - tools.extend(CORE_PLUGINS.clone()); + tools.extend(EXPERIMENTAL_CORE_PLUGINS.clone()); } let plugins = Tool::list()? .into_par_iter() diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index fa3db85f8..1ce138b70 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -415,7 +415,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 646] = [ ("nfpm", "https://github.com/ORCID/asdf-nfpm"), ("nim", "https://github.com/asdf-community/asdf-nim.git"), ("ninja", "https://github.com/asdf-community/asdf-ninja.git"), - ("nodejs", "https://github.com/asdf-vm/asdf-nodejs.git"), + ("node", "https://github.com/asdf-vm/asdf-node.git"), ("nomad", "https://github.com/asdf-community/asdf-hashicorp.git"), ("nova", "https://github.com/elementalvoid/asdf-nova.git"), ("nsc", "https://github.com/dex4er/asdf-nsc.git"), diff --git a/src/env.rs b/src/env.rs index b468da3b6..082b4dea5 100644 --- a/src/env.rs +++ b/src/env.rs @@ -98,21 +98,25 @@ pub static RTX_PYTHON_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { .unwrap_or_else(|| HOME.join(".default-python-packages")) }); -// nodejs -pub static RTX_NODEJS_CONCURRENCY: Lazy = Lazy::new(|| { - var("RTX_NODEJS_CONCURRENCY") +// node +pub static RTX_NODE_CONCURRENCY: Lazy = Lazy::new(|| { + var("RTX_NODE_CONCURRENCY") .ok() .and_then(|v| v.parse::().ok()) .unwrap_or(num_cpus::get() / 2) .max(1) }); -pub static RTX_NODEJS_VERBOSE_INSTALL: Lazy = - Lazy::new(|| var_is_true("RTX_NODEJS_VERBOSE_INSTALL")); -pub static RTX_NODEJS_FORCE_COMPILE: Lazy = - Lazy::new(|| var_is_true("RTX_NODEJS_FORCE_COMPILE")); -pub static RTX_NODEJS_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { - var_path("RTX_NODEJS_DEFAULT_PACKAGES_FILE") - .unwrap_or_else(|| HOME.join(".default-nodejs-packages")) +pub static RTX_NODE_VERBOSE_INSTALL: Lazy = + Lazy::new(|| var_is_true("RTX_NODE_VERBOSE_INSTALL")); +pub static RTX_NODE_FORCE_COMPILE: Lazy = Lazy::new(|| var_is_true("RTX_NODE_FORCE_COMPILE")); +pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("RTX_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { + let p = HOME.join(".default-nodejs-packages"); + if p.exists() { + return p; + } + HOME.join(".default-node-packages") + }) }); #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/plugins/core/assets/nodejs_npm_shim b/src/plugins/core/assets/node_npm_shim similarity index 100% rename from src/plugins/core/assets/nodejs_npm_shim rename to src/plugins/core/assets/node_npm_shim diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 4fdca9538..b5162fa9e 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,26 +1,34 @@ -mod nodejs; -mod python; +use std::collections::BTreeMap; +use std::sync::Arc; -use crate::plugins::{Plugin, PluginName}; -use crate::tool::Tool; -pub use nodejs::NodeJSPlugin; use once_cell::sync::Lazy; + pub use python::PythonPlugin; -use std::collections::BTreeMap; -use std::sync::Arc; + +use crate::plugins::core::node::NodePlugin; +use crate::plugins::{Plugin, PluginName}; +use crate::tool::Tool; + +mod node; +mod python; type ToolMap = BTreeMap>; pub static CORE_PLUGINS: Lazy = Lazy::new(|| { - let tools: Vec> = vec![ - Box::new(PythonPlugin::new("python".to_string())), - Box::new(NodeJSPlugin::new("nodejs".to_string())), - Box::new(NodeJSPlugin::new("node".to_string())), - ]; + build_core_plugins(vec![ + Box::new(NodePlugin::new("node".to_string()).with_legacy_file_support()), + Box::new(NodePlugin::new("nodejs".to_string())), + ]) +}); + +pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = + Lazy::new(|| build_core_plugins(vec![Box::new(PythonPlugin::new("python".to_string()))])); + +fn build_core_plugins(tools: Vec>) -> ToolMap { ToolMap::from_iter(tools.into_iter().map(|plugin| { ( plugin.name().to_string(), Arc::new(Tool::new(plugin.name().to_string(), plugin)), ) })) -}); +} diff --git a/src/plugins/core/nodejs.rs b/src/plugins/core/node.rs similarity index 88% rename from src/plugins/core/nodejs.rs rename to src/plugins/core/node.rs index a7dafafde..0367ec76b 100644 --- a/src/plugins/core/nodejs.rs +++ b/src/plugins/core/node.rs @@ -10,9 +10,7 @@ use color_eyre::eyre::Result; use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::{ - RTX_EXE, RTX_NODEJS_CONCURRENCY, RTX_NODEJS_FORCE_COMPILE, RTX_NODEJS_VERBOSE_INSTALL, -}; +use crate::env::{RTX_EXE, RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, RTX_NODE_VERBOSE_INSTALL}; use crate::file::create_dir_all; use crate::git::Git; use crate::lock_file::LockFile; @@ -22,14 +20,15 @@ use crate::ui::progress_report::ProgressReport; use crate::{cmd, dirs, env}; #[derive(Debug)] -pub struct NodeJSPlugin { +pub struct NodePlugin { pub name: PluginName, cache_path: PathBuf, remote_version_cache: CacheManager>, + legacy_file_support: bool, } -impl NodeJSPlugin { - pub fn new(name: PluginName) -> NodeJSPlugin { +impl NodePlugin { + pub fn new(name: PluginName) -> Self { let cache_path = dirs::CACHE.join(&name); let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours Self { @@ -38,6 +37,14 @@ impl NodeJSPlugin { .with_fresh_file(RTX_EXE.clone()), name, cache_path, + legacy_file_support: false, + } + } + + pub fn with_legacy_file_support(self) -> Self { + Self { + legacy_file_support: true, + ..self } } @@ -112,8 +119,7 @@ impl NodeJSPlugin { tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - let body = - std::fs::read_to_string(&*env::RTX_NODEJS_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + let body = fs::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); if package.is_empty() { @@ -132,7 +138,7 @@ impl NodeJSPlugin { } fn install_npm_shim(&self, tv: &ToolVersion) -> Result<()> { - fs::write(self.npm_path(tv), include_str!("assets/nodejs_npm_shim"))?; + fs::write(self.npm_path(tv), include_str!("assets/node_npm_shim"))?; Ok(()) } @@ -149,7 +155,7 @@ impl NodeJSPlugin { } } -impl Plugin for NodeJSPlugin { +impl Plugin for NodePlugin { fn name(&self) -> &PluginName { &self.name } @@ -179,7 +185,11 @@ impl Plugin for NodeJSPlugin { } fn legacy_filenames(&self, _settings: &Settings) -> Result> { - Ok(vec![".node-version".into(), ".nvmrc".into()]) + if self.legacy_file_support { + Ok(vec![".node-version".into(), ".nvmrc".into()]) + } else { + Ok(vec![]) + } } fn external_commands(&self) -> Result>> { @@ -207,8 +217,8 @@ impl Plugin for NodeJSPlugin { pr.set_message("running node-build"); let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()); cmd.with_pr(pr).arg(tv.version.as_str()); - if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODEJS_FORCE_COMPILE { - let make_opts = String::from(" -j") + &RTX_NODEJS_CONCURRENCY.to_string(); + if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_FORCE_COMPILE { + let make_opts = String::from(" -j") + &RTX_NODE_CONCURRENCY.to_string(); cmd.env( "MAKE_OPTS", env::var("MAKE_OPTS").unwrap_or_default() + &make_opts, @@ -219,7 +229,7 @@ impl Plugin for NodeJSPlugin { ); cmd.arg("--compile"); } - if *RTX_NODEJS_VERBOSE_INSTALL { + if *RTX_NODE_VERBOSE_INSTALL { cmd.arg("--verbose"); } cmd.arg(tv.install_path()); diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 5f6fd7c3b..62655404f 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -10,7 +10,6 @@ pub struct Bash {} impl Shell for Bash { fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); - let exe = exe.display(); let status = if status { " --status" } else { "" }; let mut out = String::new(); if !is_dir_in_path(dir) { @@ -23,17 +22,17 @@ impl Shell for Bash { local command command="${{1:-}}" if [ "$#" = 0 ]; then - command {exe} + command rtx return fi shift case "$command" in deactivate|shell) - eval "$({exe} "$command" "$@")" + eval "$(command rtx "$command" "$@")" ;; *) - command {exe} "$command" "$@" + command rtx "$command" "$@" ;; esac }} @@ -41,7 +40,7 @@ impl Shell for Bash { _rtx_hook() {{ local previous_exit_status=$?; trap -- '' SIGINT; - eval "$("{exe}" hook-env{status} -s bash)"; + eval "$(rtx hook-env{status} -s bash)"; trap - SIGINT; return $previous_exit_status; }}; diff --git a/src/shell/fish.rs b/src/shell/fish.rs index b16a9a6ec..68ed58e6c 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -10,7 +10,6 @@ pub struct Fish {} impl Shell for Fish { fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); - let exe = exe.display(); let status = if status { " --status" } else { "" }; let description = "'Update rtx environment when changing directories'"; let mut out = String::new(); @@ -26,7 +25,7 @@ impl Shell for Fish { function rtx if test (count $argv) -eq 0 - command {exe} + command rtx return end @@ -35,21 +34,21 @@ impl Shell for Fish { switch "$command" case deactivate shell - source ({exe} "$command" $argv|psub) + source (command rtx "$command" $argv|psub) case '*' - command {exe} "$command" $argv + command rtx "$command" $argv end end function __rtx_env_eval --on-event fish_prompt --description {description}; - {exe} hook-env{status} -s fish | source; + rtx hook-env{status} -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description {description}; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - {exe} hook-env{status} -s fish | source; + rtx hook-env{status} -s fish | source; end; end; end; @@ -58,7 +57,7 @@ impl Shell for Fish { function __rtx_env_eval_2 --on-event fish_preexec --description {description}; if set -q __rtx_env_again; set -e __rtx_env_again; - {exe} hook-env{status} -s fish | source; + rtx hook-env{status} -s fish | source; echo; end; @@ -101,17 +100,17 @@ mod tests { fn test_hook_init() { let fish = Fish::default(); let exe = Path::new("/some/dir/rtx"); - insta::assert_snapshot!(fish.activate(exe, true)); + assert_snapshot!(fish.activate(exe, true)); } #[test] fn test_set_env() { - insta::assert_snapshot!(Fish::default().set_env("FOO", "1")); + assert_snapshot!(Fish::default().set_env("FOO", "1")); } #[test] fn test_unset_env() { - insta::assert_snapshot!(Fish::default().unset_env("FOO")); + assert_snapshot!(Fish::default().unset_env("FOO")); } #[test] diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 8216f3d4c..463b631f9 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -9,17 +9,17 @@ rtx() { local command command="${1:-}" if [ "$#" = 0 ]; then - command /some/dir/rtx + command rtx return fi shift case "$command" in deactivate|shell) - eval "$(/some/dir/rtx "$command" "$@")" + eval "$(command rtx "$command" "$@")" ;; *) - command /some/dir/rtx "$command" "$@" + command rtx "$command" "$@" ;; esac } @@ -27,7 +27,7 @@ rtx() { _rtx_hook() { local previous_exit_status=$?; trap -- '' SIGINT; - eval "$("/some/dir/rtx" hook-env --status -s bash)"; + eval "$(rtx hook-env --status -s bash)"; trap - SIGINT; return $previous_exit_status; }; diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 197f42371..206d3b33e 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -7,7 +7,7 @@ set -gx RTX_SHELL fish function rtx if test (count $argv) -eq 0 - command /some/dir/rtx + command rtx return end @@ -16,21 +16,21 @@ function rtx switch "$command" case deactivate shell - source (/some/dir/rtx "$command" $argv|psub) + source (command rtx "$command" $argv|psub) case '*' - command /some/dir/rtx "$command" $argv + command rtx "$command" $argv end end function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; - /some/dir/rtx hook-env --status -s fish | source; + rtx hook-env --status -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - /some/dir/rtx hook-env --status -s fish | source; + rtx hook-env --status -s fish | source; end; end; end; @@ -39,7 +39,7 @@ end; function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; if set -q __rtx_env_again; set -e __rtx_env_again; - /some/dir/rtx hook-env --status -s fish | source; + rtx hook-env --status -s fish | source; echo; end; diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 9f3c4abed..304662338 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -9,24 +9,24 @@ rtx() { local command command="${1:-}" if [ "$#" = 0 ]; then - command /some/dir/rtx + command rtx return fi shift case "$command" in deactivate|shell) - eval "$(/some/dir/rtx "$command" "$@")" + eval "$(command rtx "$command" "$@")" ;; *) - command /some/dir/rtx "$command" "$@" + command rtx "$command" "$@" ;; esac } _rtx_hook() { trap -- '' SIGINT; - eval "$("/some/dir/rtx" hook-env --status -s zsh)"; + eval "$(rtx hook-env --status -s zsh)"; trap - SIGINT; } typeset -ag precmd_functions; diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 197d7f098..4edaeef9d 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -11,7 +11,6 @@ pub struct Zsh {} impl Shell for Zsh { fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); - let exe = exe.display(); let status = if status { " --status" } else { "" }; let mut out = String::new(); @@ -27,24 +26,24 @@ impl Shell for Zsh { local command command="${{1:-}}" if [ "$#" = 0 ]; then - command {exe} + command rtx return fi shift case "$command" in deactivate|shell) - eval "$({exe} "$command" "$@")" + eval "$(command rtx "$command" "$@")" ;; *) - command {exe} "$command" "$@" + command rtx "$command" "$@" ;; esac }} _rtx_hook() {{ trap -- '' SIGINT; - eval "$("{exe}" hook-env{status} -s zsh)"; + eval "$(rtx hook-env{status} -s zsh)"; trap - SIGINT; }} typeset -ag precmd_functions; diff --git a/src/shorthands.rs b/src/shorthands.rs index 615371dc7..af310ea92 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -66,7 +66,7 @@ mod tests { shorthands["elixir"], "https://github.com/asdf-vm/asdf-elixir.git" ); - assert_str_eq!(shorthands["nodejs"], "https://nodejs"); + assert_str_eq!(shorthands["node"], "https://node"); assert_str_eq!(shorthands["xxxxxx"], "https://xxxxxx"); } diff --git a/src/tool.rs b/src/tool.rs index 3c6ea8d3f..25445ca63 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -263,10 +263,16 @@ impl Tool { self.plugin.parse_legacy_file(path, settings) } pub fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { - self.plugin.list_bin_paths(config, tv) + match tv.request { + ToolVersionRequest::System(_) => Ok(vec![]), + _ => self.plugin.list_bin_paths(config, tv), + } } pub fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { - self.plugin.exec_env(config, tv) + match tv.request { + ToolVersionRequest::System(_) => Ok(HashMap::new()), + _ => self.plugin.exec_env(config, tv), + } } pub fn which( diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index 8c5728e41..ef8dd85c4 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -77,8 +77,8 @@ mod tests { let ts = ToolSource::Argument; assert_str_eq!(ts.to_string(), "--runtime"); - let ts = ToolSource::Environment("RTX_NODEJS_VERSION".to_string(), "18".to_string()); - assert_str_eq!(ts.to_string(), "RTX_NODEJS_VERSION=18"); + let ts = ToolSource::Environment("RTX_NODE_VERSION".to_string(), "18".to_string()); + assert_str_eq!(ts.to_string(), "RTX_NODE_VERSION=18"); } #[test] @@ -118,12 +118,12 @@ mod tests { } ); - let ts = ToolSource::Environment("RTX_NODEJS_VERSION".to_string(), "18".to_string()); + let ts = ToolSource::Environment("RTX_NODE_VERSION".to_string(), "18".to_string()); assert_eq!( ts.as_json(), indexmap! { "type".to_string() => "environment".to_string(), - "key".to_string() => "RTX_NODEJS_VERSION".to_string(), + "key".to_string() => "RTX_NODE_VERSION".to_string(), "value".to_string() => "18".to_string(), } ); diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml index c9af28543..7fc3b293d 100644 --- a/test/fixtures/.rtx.toml +++ b/test/fixtures/.rtx.toml @@ -3,7 +3,7 @@ NODE_ENV = 'production' [tools] terraform = '1.0.0' -nodejs = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18'] +node = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18'] jq = { prefix = '1.6' } shellcheck = { version = '0.9.0' } python = [ @@ -12,11 +12,11 @@ python = [ ] [plugins] -nodejs = 'https://github.com/jdxcode/rtx-nodejs' +node = 'https://github.com/jdxcode/rtx-node' [settings] verbose = true missing_runtime_behavior = 'warn' -[alias.nodejs] +[alias.node] my_custom_node = '18' diff --git a/test/fixtures/shorthands.toml b/test/fixtures/shorthands.toml index c8fc91275..5debfb0c1 100644 --- a/test/fixtures/shorthands.toml +++ b/test/fixtures/shorthands.toml @@ -1,2 +1,2 @@ -nodejs = "https://nodejs" +node = "https://node" xxxxxx = "https://xxxxxx" From bf3fe370b2933700ac245f857e1b662ddf676021 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 13:10:32 -0500 Subject: [PATCH 0713/1891] add assets to crate --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bbc106834..54bd32cc1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] -include = ["src/**/*.rs", "/build.rs", "/LICENSE", "/README.md", "/Cargo.lock"] +include = ["src/**/*.rs", "src/plugins/core/assets/**", "/build.rs", "/LICENSE", "/README.md", "/Cargo.lock"] rust-version = "1.64.0" build = "build.rs" From ba6fdd1b8fc141765fddf5b9c18afdceeb5b5391 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 13:11:35 -0500 Subject: [PATCH 0714/1891] chore: Release --- Cargo.lock | 57 +++++---- Cargo.toml | 2 +- README.md | 4 +- completions/_rtx | 250 +++++++++++++++++++------------------- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 5 +- 8 files changed, 168 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2398dbe53..9c5173ac8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -149,9 +158,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" [[package]] name = "byteorder" @@ -230,9 +239,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.2.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd" +checksum = "1a19591b2ab0e3c04b588a0e04ddde7b9eaa423646d1b4a8092879216bf47473" dependencies = [ "clap", ] @@ -350,9 +359,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" dependencies = [ "libc", ] @@ -783,7 +792,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "fnv", "log", @@ -1103,9 +1112,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" [[package]] name = "libgit2-sys" @@ -1148,9 +1157,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" +checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" [[package]] name = "log" @@ -1292,12 +1301,12 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "os_pipe" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53dbb20faf34b16087a931834cba2d7a73cc74af2b7ef345a4c8324e2409a12" +checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177" dependencies = [ "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1487,20 +1496,20 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.1", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "reqwest" @@ -1586,7 +1595,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.28.6" +version = "1.29.0" dependencies = [ "base64", "built", @@ -1645,9 +1654,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.12" +version = "0.37.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722529a737f5a942fdbac3a46cee213053196737c5eaa3386d52e85b786f2659" +checksum = "d9b864d3c18a5785a05953adeed93e2dca37ed30f18e69bba9f30079d51f363f" dependencies = [ "bitflags", "errno 0.3.1", @@ -2157,9 +2166,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "sharded-slab", "thread_local", diff --git a/Cargo.toml b/Cargo.toml index 54bd32cc1..6bbacf8ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.28.6" +version = "1.29.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0cadf23b4..5372bb4be 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.28.6 +rtx 1.29.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -330,7 +330,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.28.6/rtx-v1.28.6-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.29.0/rtx-v1.29.0-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/completions/_rtx b/completions/_rtx index 07121c6f9..e34da6f21 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -16,9 +16,9 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -47,11 +47,11 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish nu xonsh zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish nu xonsh zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--status[Show "rtx: @" message when changing directories]' \ +'--status[Show "rtx\: @" message when changing directories]' \ '-q[noop]' \ '--quiet[noop]' \ '--debug[Sets log level to debug]' \ @@ -73,9 +73,9 @@ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -101,9 +101,9 @@ Sets --jobs=1]' \ (get) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -125,9 +125,9 @@ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -145,9 +145,9 @@ Sets --jobs=1]' \ (set) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -168,9 +168,9 @@ Sets --jobs=1]' \ (unset) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -230,9 +230,9 @@ esac (asdf) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -251,9 +251,9 @@ Sets --jobs=1]' \ (bin-paths) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -271,9 +271,9 @@ Sets --jobs=1]' \ (cache) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -299,9 +299,9 @@ Sets --jobs=1]' \ (clear) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -349,9 +349,9 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ '--shell=[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -370,9 +370,9 @@ Sets --jobs=1]' \ (current) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -391,9 +391,9 @@ Sets --jobs=1]' \ (deactivate) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -411,9 +411,9 @@ Sets --jobs=1]' \ (direnv) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -439,9 +439,9 @@ Sets --jobs=1]' \ (envrc) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -459,9 +459,9 @@ Sets --jobs=1]' \ (exec) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -479,9 +479,9 @@ Sets --jobs=1]' \ (activate) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -535,9 +535,9 @@ esac (doctor) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -557,9 +557,9 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish nu xonsh zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish nu xonsh zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -581,9 +581,9 @@ _arguments "${_arguments_options[@]}" \ '()--command=[Command string to execute]:C:_cmdstring' \ '--cd=[Change to this directory before executing the command]:CD:_files -/' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -603,14 +603,14 @@ Sets --jobs=1]' \ _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--pin[Save exact version to `~/.tool-versions` -e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions]' \ -'--fuzzy[Save fuzzy version to `~/.tool-versions` -e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions +'--pin[Save exact version to \`~/.tool-versions\` +e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ +'--fuzzy[Save fuzzy version to \`~/.tool-versions\` +e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ '--debug[Sets log level to debug]' \ @@ -635,11 +635,11 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish nu xonsh zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish nu xonsh zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--status[Show "rtx: @" message when changing directories]' \ +'--status[Show "rtx\: @" message when changing directories]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. @@ -656,9 +656,9 @@ Sets --jobs=1]' \ (implode) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--config[Also remove config directory]' \ '--dry-run[List directories that would be removed without actually removing them]' \ @@ -680,9 +680,9 @@ _arguments "${_arguments_options[@]}" \ '()*-p+[Only install tool version(s) for ]:PLUGIN: ' \ '()*--plugin=[Only install tool version(s) for ]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Force reinstall even if already installed]' \ '--force[Force reinstall even if already installed]' \ @@ -705,9 +705,9 @@ Sets --jobs=1]' \ (latest) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -728,17 +728,17 @@ Sets --jobs=1]' \ _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from .tool-versions]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-p[Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ +by default this command will only set the runtime in the current directory ("\$PWD/.tool-versions")]' \ '--parent[Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")]' \ -'--pin[Save exact version to `.tool-versions` -e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions]' \ -'--fuzzy[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ +by default this command will only set the runtime in the current directory ("\$PWD/.tool-versions")]' \ +'--pin[Save exact version to \`.tool-versions\` +e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to .tool-versions]' \ +'--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the config file]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -762,9 +762,9 @@ _arguments "${_arguments_options[@]}" \ '-p+[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ '--plugin=[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ '--current[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ @@ -789,9 +789,9 @@ Sets --jobs=1]' \ (ls-remote) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -812,9 +812,9 @@ same as the first argument after the "@":' \ (plugins) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ @@ -848,18 +848,18 @@ Sets --jobs=1]' \ (install) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ '(-f --force)-a[Install all missing plugins This will only install plugins that have matching shorthands. -i.e.: they don'\''t need the full git repo url]' \ +i.e.\: they don'\''t need the full git repo url]' \ '(-f --force)--all[Install all missing plugins This will only install plugins that have matching shorthands. -i.e.: they don'\''t need the full git repo url]' \ +i.e.\: they don'\''t need the full git repo url]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '--debug[Sets log level to debug]' \ @@ -881,9 +881,9 @@ Can specify multiple plugins\: `rtx plugins install node ruby python`:' \ (link) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Overwrite existing plugin]' \ '--force[Overwrite existing plugin]' \ @@ -907,22 +907,22 @@ e.g.\: ./rtx-node:_files -/' \ (ls) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[List all available remote plugins -Same as `rtx plugins ls-remote`]' \ +Same as \`rtx plugins ls-remote\`]' \ '--all[List all available remote plugins -Same as `rtx plugins ls-remote`]' \ +Same as \`rtx plugins ls-remote\`]' \ '-c[The built-in plugins only Normally these are not shown]' \ '--core[The built-in plugins only Normally these are not shown]' \ '-u[Show the git url for each plugin -e.g.: https://github.com/asdf-vm/asdf-node.git]' \ +e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ '--urls[Show the git url for each plugin -e.g.: https://github.com/asdf-vm/asdf-node.git]' \ +e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. @@ -939,12 +939,12 @@ Sets --jobs=1]' \ (ls-remote) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-u[Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git]' \ -'--urls[Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git]' \ +'-u[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ +'--urls[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -962,9 +962,9 @@ Sets --jobs=1]' \ (uninstall) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -983,9 +983,9 @@ Sets --jobs=1]' \ (update) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '()-a[Update all plugins]' \ '()--all[Update all plugins]' \ @@ -1054,9 +1054,9 @@ esac (prune) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--dry-run[Do not actually delete anything]' \ '--debug[Sets log level to debug]' \ @@ -1076,9 +1076,9 @@ Sets --jobs=1]' \ (reshim) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1098,9 +1098,9 @@ Sets --jobs=1]' \ (self-update) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1118,9 +1118,9 @@ Sets --jobs=1]' \ (settings) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1146,9 +1146,9 @@ Sets --jobs=1]' \ (get) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1167,9 +1167,9 @@ Sets --jobs=1]' \ (ls) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1187,9 +1187,9 @@ Sets --jobs=1]' \ (set) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1209,9 +1209,9 @@ Sets --jobs=1]' \ (unset) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1270,9 +1270,9 @@ esac (shell) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[Removes a previously set version]' \ '--unset[Removes a previously set version]' \ @@ -1293,9 +1293,9 @@ Sets --jobs=1]' \ (trust) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--untrust[No longer trust this config]' \ '--debug[Sets log level to debug]' \ @@ -1315,9 +1315,9 @@ Sets --jobs=1]' \ (uninstall) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1336,9 +1336,9 @@ Sets --jobs=1]' \ (version) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1356,9 +1356,9 @@ Sets --jobs=1]' \ (where) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1384,9 +1384,9 @@ used for asdf compatibility:' \ (which) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '(--version)--plugin[Show the plugin name instead of the path]' \ '(--plugin)--version[Show the version instead of the path]' \ @@ -1407,9 +1407,9 @@ Sets --jobs=1]' \ (render-help) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default: 4]: : ' \ +default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1787,10 +1787,10 @@ _rtx__alias_commands() { 'get:Show an alias for a plugin' \ 'ls:List aliases Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`.' \ +These can come from user config or from plugins in \`bin/list-aliases\`.' \ 'list:List aliases Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`.' \ +These can come from user config or from plugins in \`bin/list-aliases\`.' \ 'set:Add/update an alias for a plugin' \ 'add:Add/update an alias for a plugin' \ 'create:Add/update an alias for a plugin' \ @@ -1809,7 +1809,7 @@ _rtx__help__alias_commands() { 'get:Show an alias for a plugin' \ 'ls:List aliases Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`.' \ +These can come from user config or from plugins in \`bin/list-aliases\`.' \ 'set:Add/update an alias for a plugin' \ 'unset:Clears an alias for a plugin' \ ) @@ -2025,7 +2025,7 @@ _rtx__alias__help_commands() { 'get:Show an alias for a plugin' \ 'ls:List aliases Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`.' \ +These can come from user config or from plugins in \`bin/list-aliases\`.' \ 'set:Add/update an alias for a plugin' \ 'unset:Clears an alias for a plugin' \ 'help:Print this message or the help of the given subcommand(s)' \ diff --git a/default.nix b/default.nix index 67156e67d..20299fbac 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.28.6"; + version = "1.29.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 52d506eb2..dff25d42c 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.28.6" +.TH rtx 1 "rtx 1.29.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -142,6 +142,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.28.6 +v1.29.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index d3e2d6c04..07e2abce8 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.28.6 +Version: 1.29.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 1ce138b70..31b4d120c 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 646] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -102,6 +102,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 646] = [ ("cmake", "https://github.com/srivathsanmurali/asdf-cmake.git"), ("cmctl", "https://github.com/asdf-community/asdf-cmctl.git"), ("cockroach", "https://github.com/salasrod/asdf-cockroach.git"), + ("cocoapods", "https://github.com/ronnnnn/asdf-cocoapods.git"), ("codefresh", "https://github.com/gurukulkarni/asdf-codefresh.git"), ("codeql", "https://github.com/bored-engineer/asdf-codeql.git"), ("colima", "https://github.com/CrouchingMuppet/asdf-colima.git"), @@ -415,7 +416,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 646] = [ ("nfpm", "https://github.com/ORCID/asdf-nfpm"), ("nim", "https://github.com/asdf-community/asdf-nim.git"), ("ninja", "https://github.com/asdf-community/asdf-ninja.git"), - ("node", "https://github.com/asdf-vm/asdf-node.git"), + ("nodejs", "https://github.com/asdf-vm/asdf-nodejs.git"), ("nomad", "https://github.com/asdf-community/asdf-hashicorp.git"), ("nova", "https://github.com/elementalvoid/asdf-nova.git"), ("nsc", "https://github.com/dex4er/asdf-nsc.git"), From a560ab14f2472087821e4f8428d632251a85f6ac Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 15:09:28 -0500 Subject: [PATCH 0715/1891] added rtx use command (#504) --- .github/workflows/test-plugins.yml | 4 +- README.md | 183 ++++++------------ completions/_rtx | 56 +++++- completions/rtx.bash | 71 ++++++- completions/rtx.fish | 90 +++++---- docs/demo.tape | 6 +- docs/node.md | 4 +- docs/python.md | 5 +- man/man1/rtx.1 | 17 +- src/cli/global.rs | 6 +- src/cli/install.rs | 2 +- src/cli/local.rs | 3 +- src/cli/mod.rs | 11 +- .../rtx__cli__r#use__tests__use.snap | 7 + .../rtx__cli__r#use__tests__use_global.snap | 7 + .../rtx__cli__r#use__tests__use_local-2.snap | 7 + .../rtx__cli__r#use__tests__use_local-3.snap | 7 + .../rtx__cli__r#use__tests__use_local-4.snap | 5 + .../rtx__cli__r#use__tests__use_local.snap | 7 + src/cli/use.rs | 143 ++++++++++++++ src/git.rs | 50 +++-- src/plugins/core/node.rs | 3 + src/shims.rs | 2 +- 23 files changed, 477 insertions(+), 219 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap create mode 100644 src/cli/use.rs diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 1ae0054a8..e1cb05e01 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -58,9 +58,9 @@ jobs: command: rtx exec erlang@latest -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell - plugin: elixir command: | - rtx global erlang@latest + rtx use --global erlang@latest eval "$(rtx env bash)" - rtx global elixir@latest + rtx use --global elixir@latest eval "$(rtx env bash)" rtx exec -- elixir --version - plugin: golang diff --git a/README.md b/README.md index 5372bb4be..8d5b3dbc6 100644 --- a/README.md +++ b/README.md @@ -51,11 +51,10 @@ echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish > If you use direnv with `layout python` or other logic that needs to reference rtx runtimes inside > of an `.envrc`, see the [direnv section](#direnv) below. -Install a runtime and set it as the default: +Install a runtime and set it as the global default: ```sh-session -$ rtx install node@20 -$ rtx global node@20 +$ rtx use --global node@20 $ node -v v20.0.0 ``` @@ -152,11 +151,9 @@ v20.0.0 - [`rtx doctor`](#rtx-doctor) - [`rtx env [OPTIONS] [RUNTIME]...`](#rtx-env-options-runtime) - [`rtx exec [OPTIONS] [RUNTIME]... [-- ...]`](#rtx-exec-options-runtime----command) - - [`rtx global [OPTIONS] [RUNTIME]...`](#rtx-global-options-runtime) - [`rtx implode [OPTIONS]`](#rtx-implode-options) - [`rtx install [OPTIONS] [RUNTIME]...`](#rtx-install-options-runtime) - [`rtx latest `](#rtx-latest-runtime) - - [`rtx local [OPTIONS] [RUNTIME]...`](#rtx-local-options-runtime) - [`rtx ls [OPTIONS]`](#rtx-ls-options) - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-plugin-prefix) - [`rtx plugins install [OPTIONS] [NAME] [GIT_URL]`](#rtx-plugins-install-options-name-git_url) @@ -175,6 +172,7 @@ v20.0.0 - [`rtx shell [OPTIONS] [RUNTIME]...`](#rtx-shell-options-runtime) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall ...`](#rtx-uninstall-runtime) + - [`rtx use [OPTIONS] [TOOL]...`](#rtx-use-options-tool) - [`rtx version`](#rtx-version) - [`rtx where `](#rtx-where-runtime) - [`rtx which [OPTIONS] `](#rtx-which-options-bin_name) @@ -235,12 +233,12 @@ See [plugins](#plugins) below. rtx install node@20.0.0 Install a specific version number rtx install node@20 Install a fuzzy version number - rtx local node@20 Use node-20.x in current project - rtx global node@20 Use node-20.x as default + rtx use node@20 Use node-20.x in current project + rtx use -g node@20 Use node-20.x as global default rtx install node Install the version specified in .tool-versions - rtx local node@latest Use latest node in current directory - rtx global node@system Use system node as default + rtx use node@latest Use latest node in current directory + rtx use -g node@system Use system node as global default rtx x node@20 -- node app.js Run `node app.js` with the PATH pointing to node-20.x @@ -531,8 +529,6 @@ node lts!-2 # install 2 versions behind the latest lts (e.g.: 18 if l python latest!-0.1 # install python-3.10 if the latest is 3.11 ``` -Create `.tool-versions` files manually, or use [`rtx local`](#rtx-local-options-runtime) to create them -automatically. See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. ### Legacy version files @@ -573,6 +569,11 @@ You may not even notice. rtx can be configured in `~/.config/rtx/config.toml`. The following options are available: ```toml +[tools] +# global tool versions go here +node = 'lts' +python = ['3.10', '3.11'] + [settings] # whether to prompt to install plugins and runtimes if they're not already installed missing_runtime_behavior = 'warn' # other options: 'ignore', 'warn', 'prompt', 'autoinstall' @@ -760,6 +761,8 @@ information. Set to `1` to default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for configuration. This will be default behavior once we hit the [Calver](#versioning) release. +For now this is not used by `rtx use` which will only use `.rtx.toml` unless `--path` is specified. + #### `RTX_TRUSTED_CONFIG_PATHS` This is a list of paths that rtx will automatically mark as @@ -821,10 +824,6 @@ 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` -Currently this disables the following: - -- `--fuzzy` as default behavior (`rtx local node@20` will save exact version) - #### `RTX_HIDE_UPDATE_WARNING=1` This hides the warning that is displayed when a new version of rtx is available. @@ -1724,57 +1723,6 @@ Examples: # Run a command in a different directory: $ rtx x -C /path/to/project node@20 -- node ./app.js ``` -### `rtx global [OPTIONS] [RUNTIME]...` - -``` -Sets/gets the global runtime version(s) - -Displays the contents of ~/.tool-versions after writing. -The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. -If `$RTX_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. -Otherwise, it will be parsed as a `.tool-versions` file. -A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. - -Use `rtx local` to set a runtime version locally in the current directory. - -Usage: global [OPTIONS] [RUNTIME]... - -Arguments: - [RUNTIME]... - Runtime(s) to add to .tool-versions - e.g.: node@20 - If this is a single runtime with no version, the current value of the global - .tool-versions will be displayed - -Options: - --pin - Save exact version to `~/.tool-versions` - e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions - - --fuzzy - Save fuzzy version to `~/.tool-versions` - e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions - this is the default behavior unless RTX_ASDF_COMPAT=1 - - --remove - Remove the plugin(s) from ~/.tool-versions - - --path - Get the path of the global config file - -Examples: - # set the current version of node to 20.x - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx global --fuzzy node@20 - - # set the current version of node to 20.x - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global --pin node@20 - - # show the current version of node in ~/.tool-versions - $ rtx global node - 20.0.0 -``` ### `rtx implode [OPTIONS]` ``` @@ -1798,7 +1746,7 @@ Install a tool version This will install a tool version to `~/.local/share/rtx/installs//` It won't be used simply by being installed, however. -For that, you must set up a `.tool-version` file manually or with `rtx local/global`. +For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. Or you can call a tool version explicitly with `rtx exec @ -- `. Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` @@ -1843,62 +1791,6 @@ Examples: $ rtx latest node # get the latest stable version of node 20.0.0 ``` -### `rtx local [OPTIONS] [RUNTIME]...` - -``` -Sets/gets tool version in local .tool-versions or .rtx.toml - -Use this to set a tool's version when within a directory -Use `rtx global` to set a runtime version globally -This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` -is set. A future v2 release of rtx will default to using `.rtx.toml`. - -Usage: local [OPTIONS] [RUNTIME]... - -Arguments: - [RUNTIME]... - Runtimes to add to .tool-versions/.rtx.toml - e.g.: node@20 - if this is a single runtime with no version, - the current value of .tool-versions/.rtx.toml will be displayed - -Options: - -p, --parent - Recurse up to find a .tool-versions file rather than using the current directory only - by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") - - --pin - Save exact version to `.tool-versions` - e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions - - --fuzzy - Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1 - - --remove - Remove the plugin(s) from .tool-versions - - --path - Get the path of the config file - -Examples: - # set the current version of node to 20.x for the current directory - # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx local node@20 - - # set node to 20.x for the current project (recurses up to find .tool-versions) - $ rtx local -p node@20 - - # set the current version of node to 20.x for the current directory - # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx local --fuzzy node@20 - - # removes node from .tool-versions - $ rtx local --remove=node - - # show the current version of node in .tool-versions - $ rtx local node - 20.0.0 -``` ### `rtx ls [OPTIONS]` ``` @@ -2334,6 +2226,51 @@ Examples: $ rtx uninstall node@18.0.0 # will uninstall specific version $ rtx uninstall node # will uninstall current node version ``` +### `rtx use [OPTIONS] [TOOL]...` + +``` +Change the active version of a tool. This will install the tool if it is not already installed. + +By default, this will use an `.rtx.toml` file in the current directory. +Use the --global flag to use the global config file instead. +This replaces asdf's `local` and `global` commands, however those are still available in rtx. + +Usage: use [OPTIONS] [TOOL]... + +Arguments: + [TOOL]... + Tool(s) to add to config file + e.g.: node@20 + If no version is specified, it will default to @latest + +Options: + --pin + Save exact version to config file + e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions + + --fuzzy + Save fuzzy version to config file + e.g.: `rtx use --fuzzy node@20` will save `node 20` to ~/.tool-versions + this is the default behavior unless RTX_ASDF_COMPAT=1 + + --remove + Remove the tool(s) from config file + + -g, --global + Use the global config file (~/.config/rtx/config.toml) instead of the local one + + -p, --path + Specify a path to a config file + +Examples: + # set the current version of node to 20.x in .rtx.toml of current directory + # will write the fuzzy version (e.g.: 20) + $ rtx use node@20 + + # set the current version of node to 20.x in ~/.config/rtx/config.toml + # will write the precise version (e.g.: 20.0.0) + $ rtx use -g --pin node@20 +``` ### `rtx version` ``` diff --git a/completions/_rtx b/completions/_rtx index e34da6f21..524389866 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -608,9 +608,9 @@ default\: 4]: : ' \ default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to \`~/.tool-versions\` -e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ +e.g.\: \`rtx global --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ '--fuzzy[Save fuzzy version to \`~/.tool-versions\` -e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions +e.g.\: \`rtx global --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ '--debug[Sets log level to debug]' \ @@ -1333,6 +1333,39 @@ Sets --jobs=1]' \ '*::runtime -- Runtime(s) to remove:' \ && ret=0 ;; +(use) +_arguments "${_arguments_options[@]}" \ +'*--remove=[Remove the tool(s) from config file]:TOOL: ' \ +'-p+[Specify a path to a config file]:PATH:_files' \ +'--path=[Specify a path to a config file]:PATH:_files' \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--pin[Save exact version to config file +e.g.\: \`rtx use --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ +'--fuzzy[Save fuzzy version to config file +e.g.\: \`rtx use --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions +this is the default behavior unless RTX_ASDF_COMPAT=1]' \ +'-g[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ +'--global[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::tool -- Tool(s) to add to config file +e.g.\: node@20 +If no version is specified, it will default to @latest:' \ +&& ret=0 +;; (version) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel @@ -1680,6 +1713,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(use) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (version) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1728,14 +1765,12 @@ _rtx_commands() { 'exec:Execute a command with runtime(s) set' \ 'x:Execute a command with runtime(s) set' \ 'global:Sets/gets the global runtime version(s)' \ -'g:Sets/gets the global runtime version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ 'install:Install a tool version' \ 'i:Install a tool version' \ 'latest:Gets the latest available version for a plugin' \ 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ -'l:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed and/or currently selected tool versions' \ 'list:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ @@ -1748,6 +1783,8 @@ _rtx_commands() { 'shell:Sets a tool version for the current shell session' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ +'use:Change the active version of a tool. This will install the tool if it is not already installed.' \ +'u:Change the active version of a tool. This will install the tool if it is not already installed.' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ 'which:Shows the path that a bin name points to' \ @@ -2098,6 +2135,7 @@ _rtx__help_commands() { 'shell:Sets a tool version for the current shell session' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ +'use:Change the active version of a tool. This will install the tool if it is not already installed.' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ 'which:Shows the path that a bin name points to' \ @@ -2522,6 +2560,16 @@ _rtx__plugins__update_commands() { local commands; commands=() _describe -t commands 'rtx plugins update commands' commands "$@" } +(( $+functions[_rtx__help__use_commands] )) || +_rtx__help__use_commands() { + local commands; commands=() + _describe -t commands 'rtx help use commands' commands "$@" +} +(( $+functions[_rtx__use_commands] )) || +_rtx__use_commands() { + local commands; commands=() + _describe -t commands 'rtx use commands' commands "$@" +} (( $+functions[_rtx__help__version_commands] )) || _rtx__help__version_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 7f61d8e9b..f28b5ecd7 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -54,9 +54,6 @@ _rtx() { rtx,exec) cmd="rtx__exec" ;; - rtx,g) - cmd="rtx__global" - ;; rtx,global) cmd="rtx__global" ;; @@ -75,9 +72,6 @@ _rtx() { rtx,install) cmd="rtx__install" ;; - rtx,l) - cmd="rtx__local" - ;; rtx,latest) cmd="rtx__latest" ;; @@ -120,9 +114,15 @@ _rtx() { rtx,trust) cmd="rtx__trust" ;; + rtx,u) + cmd="rtx__use" + ;; rtx,uninstall) cmd="rtx__uninstall" ;; + rtx,use) + cmd="rtx__use" + ;; rtx,version) cmd="rtx__version" ;; @@ -315,6 +315,9 @@ _rtx() { rtx__help,uninstall) cmd="rtx__help__uninstall" ;; + rtx__help,use) + cmd="rtx__help__use" + ;; rtx__help,version) cmd="rtx__help__version" ;; @@ -490,7 +493,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall version where which render-help help" + opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1314,7 +1317,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1999,6 +2002,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__use) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__version) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2941,6 +2958,44 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__use) + opts="-g -p -j -r -v -h --pin --fuzzy --remove --global --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__version) opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 9410c91a2..d1985da8a 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -37,6 +37,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "use" -d 'Change the active version of a tool. This will install the tool if it is not already installed.' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' @@ -286,9 +287,9 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` -e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions' +e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` -e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions +e.g.: `rtx global --fuzzy node@20` will save `node 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' complete -c rtx -n "__fish_seen_subcommand_from global" -l debug -d 'Sets log level to debug' @@ -612,6 +613,24 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from use" -l remove -d 'Remove the tool(s) from config file' -r +complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file' -r -F +complete -c rtx -n "__fish_seen_subcommand_from use" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from use" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from use" -l pin -d 'Save exact version to config file +e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions' +complete -c rtx -n "__fish_seen_subcommand_from use" -l fuzzy -d 'Save fuzzy version to config file +e.g.: `rtx use --fuzzy node@20` will save `node 20` to ~/.tool-versions +this is the default behavior unless RTX_ASDF_COMPAT=1' +complete -c rtx -n "__fish_seen_subcommand_from use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' +complete -c rtx -n "__fish_seen_subcommand_from use" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from use" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from use" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from use" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from use" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from use" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r @@ -654,39 +673,40 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool. This will install the tool if it is not already installed.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/docs/demo.tape b/docs/demo.tape index 531a2350c..29b4e9527 100644 --- a/docs/demo.tape +++ b/docs/demo.tape @@ -62,13 +62,11 @@ Type "http rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx" Enter Sleep 2s Type "chmod +x ~/bin/rtx" Sleep 1s Enter Sleep 1s Type "rtx -v" Sleep 1s Enter Sleep 1s Type 'eval "$(rtx activate bash)"' Sleep 1s Enter Sleep 2s -Type "rtx install node@lts" Sleep 2s Enter Sleep 8s -Type "rtx global node@lts" Sleep 2s Enter Sleep 3s +Type "rtx use -g node@lts" Sleep 2s Enter Sleep 3s Type "node -v" Sleep 1s Enter Sleep 3s Type "which node" Sleep 1s Enter Sleep 5s Type "cd ~/myproj" Sleep 1s Enter Sleep 1s -Type "rtx install node@19" Sleep 2s Enter Sleep 8s -Type "rtx local node@19" Sleep 2s Enter Sleep 2s +Type "rtx use node@19" Sleep 2s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s Type "cd .." Sleep 1s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s diff --git a/docs/node.md b/docs/node.md index f5795db9b..27771c58a 100644 --- a/docs/node.md +++ b/docs/node.md @@ -15,14 +15,14 @@ default: ```sh-session $ rtx install node@20 -$ rtx global node@20 +$ rtx use -g node@20 ``` Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. ```sh-session -$ rtx global node@18 node@20 +$ rtx use -g node@18 node@20 $ node -V 18.0.0 $ node.11 -V diff --git a/docs/python.md b/docs/python.md index fa540e0a8..46d852072 100644 --- a/docs/python.md +++ b/docs/python.md @@ -13,14 +13,13 @@ The following installs the latest version of python-3.11.x and makes it the glob default: ```sh-session -$ rtx install python@3.11 -$ rtx global python@3.11 +$ rtx use -g python@3.11 ``` You can also use multiple versions of python at the same time: ```sh-session -$ rtx global python@3.10 python@3.11 +$ rtx use -g python@3.10 python@3.11 $ python -V 3.10.0 $ python3.11 -V diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index dff25d42c..840b1bbea 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -73,9 +73,6 @@ Exports env vars to activate rtx a single time rtx\-exec(1) Execute a command with runtime(s) set .TP -rtx\-global(1) -Sets/gets the global runtime version(s) -.TP rtx\-implode(1) Removes rtx CLI and all related data .TP @@ -85,9 +82,6 @@ Install a tool version rtx\-latest(1) Gets the latest available version for a plugin .TP -rtx\-local(1) -Sets/gets tool version in local .tool\-versions or .rtx.toml -.TP rtx\-ls(1) List installed and/or currently selected tool versions .TP @@ -118,6 +112,9 @@ Marks a config file as trusted rtx\-uninstall(1) Removes runtime versions .TP +rtx\-use(1) +Change the active version of a tool. This will install the tool if it is not already installed. +.TP rtx\-version(1) Show rtx version .TP @@ -135,10 +132,10 @@ Examples: $ rtx install node@20.0 Install a version matching a prefix $ rtx install node Install the node version defined in .tool\-versions or .rtx.toml - $ rtx local node@20 Use node\-20.x in current project - $ rtx global node@20 Use node\-20.x as default - $ rtx local node@latest Use latest node in current directory - $ rtx global node@system Use system node everywhere unless overridden + $ rtx use node@20 Use node\-20.x in current project + $ rtx use \-g node@20 Use node\-20.x as default + $ rtx use node@latest Use latest node in current directory + $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION diff --git a/src/cli/global.rs b/src/cli/global.rs index de83d6fd0..9048fa53d 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -20,7 +20,7 @@ use crate::{dirs, env}; /// /// Use `rtx local` to set a runtime version locally in the current directory. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, visible_alias = "g", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, hide = true, alias = "g", after_long_help = AFTER_LONG_HELP)] pub struct Global { /// Runtime(s) to add to .tool-versions /// e.g.: node@20 @@ -30,12 +30,12 @@ pub struct Global { runtime: Option>, /// Save exact version to `~/.tool-versions` - /// e.g.: `rtx local --pin node@20` will save `node 20.0.0` to ~/.tool-versions + /// e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `~/.tool-versions` - /// e.g.: `rtx local --fuzzy node@20` will save `node 20` to ~/.tool-versions + /// e.g.: `rtx global --fuzzy node@20` will save `node 20` to ~/.tool-versions /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, diff --git a/src/cli/install.rs b/src/cli/install.rs index 4c0ccbcfe..ee7042b47 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -27,7 +27,7 @@ use crate::ui::progress_report::ProgressReport; /// /// This will install a tool version to `~/.local/share/rtx/installs//` /// It won't be used simply by being installed, however. -/// For that, you must set up a `.tool-version` file manually or with `rtx local/global`. +/// For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. /// Or you can call a tool version explicitly with `rtx exec @ -- `. /// /// Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` diff --git a/src/cli/local.rs b/src/cli/local.rs index 0a6f98a81..0ee6b0701 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -19,7 +19,7 @@ use crate::{dirs, env, file}; /// This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` /// is set. A future v2 release of rtx will default to using `.rtx.toml`. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, hide = true, alias = "l", after_long_help = AFTER_LONG_HELP)] pub struct Local { /// Runtimes to add to .tool-versions/.rtx.toml /// e.g.: node@20 @@ -322,6 +322,7 @@ mod tests { where T: FnOnce() + panic::UnwindSafe, { + let _ = fs::remove_file(dirs::CURRENT.join(".test.rtx.toml")); let cf_path = dirs::CURRENT.join(".test-tool-versions"); let orig = fs::read_to_string(&cf_path).unwrap(); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1d688c7a1..954c5d872 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -41,6 +41,7 @@ mod settings; mod shell; mod trust; mod uninstall; +mod r#use; pub mod version; mod r#where; mod r#which; @@ -80,6 +81,7 @@ pub enum Commands { Shell(shell::Shell), Trust(trust::Trust), Uninstall(uninstall::Uninstall), + Use(r#use::Use), Version(version::Version), Where(r#where::Where), Which(which::Which), @@ -119,6 +121,7 @@ impl Commands { Self::Shell(cmd) => cmd.run(config, out), Self::Trust(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), + Self::Use(cmd) => cmd.run(config, out), Self::Version(cmd) => cmd.run(config, out), Self::Where(cmd) => cmd.run(config, out), Self::Which(cmd) => cmd.run(config, out), @@ -247,10 +250,10 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ rtx install node@20.0 Install a version matching a prefix $ rtx install node Install the node version defined in .tool-versions or .rtx.toml - $ rtx local node@20 Use node-20.x in current project - $ rtx global node@20 Use node-20.x as default - $ rtx local node@latest Use latest node in current directory - $ rtx global node@system Use system node everywhere unless overridden + $ rtx use node@20 Use node-20.x in current project + $ rtx use -g node@20 Use node-20.x as default + $ rtx use node@latest Use latest node in current directory + $ rtx use -g node@system Use system node everywhere unless overridden $ rtx x node@20 -- node app.js Run `node app.js` with PATH pointing to node-20.x "# diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use.snap new file mode 100644 index 000000000..4a5a476a6 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/use.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[tools] +tiny = "2" + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap new file mode 100644 index 000000000..4a5a476a6 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/use.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[tools] +tiny = "2" + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap new file mode 100644 index 000000000..10ba158af --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/use.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[tools] +tiny = "3.1.0" + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap new file mode 100644 index 000000000..4a5a476a6 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/use.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[tools] +tiny = "2" + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap new file mode 100644 index 000000000..9240e541e --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/use.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap new file mode 100644 index 000000000..4a5a476a6 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/use.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[tools] +tiny = "2" + diff --git a/src/cli/use.rs b/src/cli/use.rs new file mode 100644 index 000000000..deb7a8f93 --- /dev/null +++ b/src/cli/use.rs @@ -0,0 +1,143 @@ +use std::path::PathBuf; + +use color_eyre::eyre::Result; + +use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::command::Command; +use crate::cli::local::local; +use crate::config::{Config, MissingRuntimeBehavior}; +use crate::env::RTX_DEFAULT_CONFIG_FILENAME; +use crate::output::Output; +use crate::plugins::PluginName; +use crate::{dirs, env}; + +/// Change the active version of a tool. This will install the tool if it is not already installed. +/// +/// By default, this will use an `.rtx.toml` file in the current directory. +/// Use the --global flag to use the global config file instead. +/// This replaces asdf's `local` and `global` commands, however those are still available in rtx. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, visible_alias = "u", after_long_help = AFTER_LONG_HELP)] +pub struct Use { + /// Tool(s) to add to config file + /// e.g.: node@20 + /// If no version is specified, it will default to @latest + #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment, required_unless_present = "remove")] + tool: Vec, + + /// Save exact version to config file + /// e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions + #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] + pin: bool, + + /// Save fuzzy version to config file + /// e.g.: `rtx use --fuzzy node@20` will save `node 20` to ~/.tool-versions + /// this is the default behavior unless RTX_ASDF_COMPAT=1 + #[clap(long, verbatim_doc_comment, overrides_with = "pin")] + fuzzy: bool, + + /// Remove the tool(s) from config file + #[clap(long, value_name = "TOOL", aliases = ["rm", "unset"])] + remove: Option>, + + /// Use the global config file (~/.config/rtx/config.toml) instead of the local one + #[clap(short, long, overrides_with = "path")] + global: bool, + + /// Specify a path to a config file + #[clap(short, long, overrides_with = "global", value_hint = clap::ValueHint::FilePath)] + path: Option, +} + +impl Command for Use { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + config.settings.missing_runtime_behavior = MissingRuntimeBehavior::AutoInstall; + let runtimes = self + .tool + .into_iter() + .map(|r| match &r.tvr { + Some(_) => r, + None => RuntimeArg::parse(&format!("{}@latest", r.plugin)), + }) + .collect(); + let path = match (self.global, self.path) { + (true, _) => global_file(), + (false, Some(p)) => p, + (false, None) => dirs::CURRENT.join(&*RTX_DEFAULT_CONFIG_FILENAME), + }; + local( + config, + out, + &path, + Some(runtimes), + self.remove, + self.pin, + self.fuzzy, + false, + ) + } +} + +fn global_file() -> PathBuf { + env::RTX_CONFIG_FILE + .clone() + .unwrap_or_else(|| dirs::CONFIG.join("config.toml")) +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # set the current version of node to 20.x in .rtx.toml of current directory + # will write the fuzzy version (e.g.: 20) + $ rtx use node@20 + + # set the current version of node to 20.x in ~/.config/rtx/config.toml + # will write the precise version (e.g.: 20.0.0) + $ rtx use -g --pin node@20 +"# +); + +#[cfg(test)] +mod tests { + use insta::assert_snapshot; + use std::fs; + + use crate::{assert_cli, dirs}; + + #[test] + fn test_use_local() { + let cf_path = dirs::CURRENT.join(".test.rtx.toml"); + let _ = fs::remove_file(&cf_path); + + assert_cli!("use", "tiny@2"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + + assert_cli!("use", "--pin", "tiny"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + + assert_cli!("use", "--fuzzy", "tiny@2"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + + assert_cli!( + "use", + "--rm", + "tiny", + "--path", + &cf_path.to_string_lossy().to_string() + ); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + + let _ = fs::remove_file(&cf_path); + } + + #[test] + fn test_use_global() { + let cf_path = dirs::CONFIG.join("config.toml"); + let orig = fs::read_to_string(&cf_path).unwrap(); + let _ = fs::remove_file(&cf_path); + + assert_cli!("use", "-g", "tiny@2"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + + fs::write(&cf_path, orig).unwrap(); + } +} diff --git a/src/git.rs b/src/git.rs index 4678cf591..fe48baa60 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,7 +1,7 @@ use std::fs::create_dir_all; use std::path::PathBuf; -use color_eyre::eyre::Result; +use color_eyre::eyre::{eyre, Result}; use crate::cmd; use crate::file::touch_dir; @@ -36,34 +36,23 @@ impl Git { pub fn update(&self, gitref: Option) -> Result<(String, String)> { let gitref = gitref.map_or_else(|| self.remote_default_branch(), Ok)?; debug!("updating {} to {}", self.dir.display(), gitref); - if let Err(err) = cmd!( - "git", - "-C", - &self.dir, + self.run_git_command(&[ "fetch", "--prune", "--update-head-ok", "origin", - format!("{}:{}", gitref, gitref), - ) - .run() - { - debug!("failed to fetch: {:#}", err); - } + format!("{}:{}", gitref, gitref).as_str(), + ])?; let prev_rev = self.current_sha()?; - cmd!( - "git", - "-C", - &self.dir, + self.run_git_command(&[ "-c", "advice.detachedHead=false", "-c", "advice.objectNameWarning=false", "checkout", "--force", - gitref - ) - .run()?; + gitref.as_str(), + ])?; let post_rev = self.current_sha()?; touch_dir(&self.dir)?; @@ -130,6 +119,31 @@ impl Git { None => (url.to_string(), None), } } + + pub fn run_git_command(&self, args: &[&str]) -> Result<()> { + let dir = self.dir.to_string_lossy(); + let mut cmd_args = vec!["-C", &dir]; + cmd_args.extend(args.iter().cloned()); + match cmd::cmd("git", &cmd_args) + .stderr_to_stdout() + .stdout_capture() + .unchecked() + .run() + { + Ok(res) => { + if res.status.success() { + Ok(()) + } else { + Err(eyre!( + "git failed: {:?} {}", + cmd_args, + String::from_utf8(res.stdout).unwrap() + )) + } + } + Err(err) => Err(eyre!("git failed: {:?} {:#}", cmd_args, err)), + } + } } fn get_git_version() -> Result { diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 0367ec76b..ab5f905b3 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -150,6 +150,9 @@ impl NodePlugin { fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { let mut cmd = CmdLineRunner::new(&config.settings, self.npm_path(tv)); + let mut path = split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, tv.install_path().join("bin")); + cmd.env("PATH", join_paths(path)?); cmd.with_pr(pr).arg("-v"); cmd.execute() } diff --git a/src/shims.rs b/src/shims.rs index 39810c17d..ecacbe461 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -163,7 +163,7 @@ fn err_no_version_set(bin_name: &str, tvs: Vec) -> Result<()> { let mut msg = format!("No version is set for shim: {}\n", bin_name); msg.push_str("Set a global default version with one of the following:\n"); for tv in tvs { - msg.push_str(&format!("rtx global {}@{}\n", tv.plugin_name, tv.version)); + msg.push_str(&format!("rtx use -g {}@{}\n", tv.plugin_name, tv.version)); } Err(eyre!(msg.trim().to_string())) } From aa4c9948c5fb3b5de970026f6ebb2bbe53026165 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 15:10:30 -0500 Subject: [PATCH 0716/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c5173ac8..7282bfaf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1595,7 +1595,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.0" +version = "1.29.1" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 6bbacf8ad..e8e93088c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.0" +version = "1.29.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 8d5b3dbc6..6c06e2063 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.0 +rtx 1.29.1 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -328,7 +328,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.0/rtx-v1.29.0-linux-x64 +curl https://github.com/jdxcode/rtx/releases/download/v1.29.1/rtx-v1.29.1-linux-x64 mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 20299fbac..4f74a3c98 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.0"; + version = "1.29.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 840b1bbea..e98cf01d2 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.0" +.TH rtx 1 "rtx 1.29.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.0 +v1.29.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 07e2abce8..5051f07b9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.0 +Version: 1.29.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 7439589cd2504e4cb052a0b396d802d7bd22c7d4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 16:04:48 -0500 Subject: [PATCH 0717/1891] docs --- README.md | 274 +++++++++++++++++++++++++++--------------------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/README.md b/README.md index 6c06e2063..81663f770 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,6 @@ v20.0.0 - [30 Second Demo](#30-second-demo) - [Quickstart](#quickstart) - [About](#about) - - [What do I use this for?](#what-do-i-use-this-for) - [How it works](#how-it-works) - [Common commands](#common-commands) - [Installation](#installation) @@ -93,10 +92,10 @@ v20.0.0 - [Uninstalling](#uninstalling) - [Shebang](#shebang) - [Configuration](#configuration) - - [`.tool-versions`](#tool-versions) + - [`.rtx.toml`](#rtxtoml) - [Legacy version files](#legacy-version-files) + - [`.tool-versions`](#tool-versions) - [Global config: `~/.config/rtx/config.toml`](#global-config-configrtxconfigtoml) - - [[experimental] `.rtx.toml`](#experimental-rtxtoml) - [Environment variables](#environment-variables) - [Aliases](#aliases) - [Plugins](#plugins) @@ -193,21 +192,9 @@ rtx is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecos under the hood. However, it is _much_ faster than asdf and has a more friendly user experience. For more on how rtx compares to asdf, [see below](#comparison-to-asdf). -It uses the same `.tool-versions` file that asdf uses. It's also compatible with idiomatic version -files like `.node-version` and `.ruby-version`. See [Legacy Version Files](#legacy-version-files) below. - -### What do I use this for? - -Typically, developers would use rtx to manage versions of their dev tools for _local_ development. -The main purpose of using rtx is being able to have different versions of languages for different projects -on the same machine. (For example, one project might require python-3.10 and another python-3.11). - -Using rtx in production is less common but still a supported use-case. Usually a production setup -won't have different directories for different projects with different dev tool requirements. -That said, using `.tool-versions`/`.rtx.toml` config in production provides parity with local -development -so rtx is still definitely useful in production setups. See the [GitHub Action](#github-actions) for -an example of using rtx in production. +rtx can be configured in many ways. The most typical is by `.rtx.toml`, but it's also compatible +with asdf `.tool-versions` files. It can also use idiomatic version files like `.node-version` and +`.ruby-version`. See [Configuration](#configuration) for more. ### How it works @@ -216,7 +203,7 @@ environment variable to point your shell to the correct runtime binaries. When y directory containing a `.tool-versions`/`.rtx.toml` file, rtx will automatically set the appropriate tool versions in `PATH`. -After activating, every time your prompt starts it will call `rtx hook-env` to fetch new +After activating, every time your prompt displays it will call `rtx hook-env` to fetch new environment variables. This should be very fast. It exits early if the directory wasn't changed or `.tool-versions`/`.rtx.toml` files haven't been modified. @@ -236,7 +223,7 @@ See [plugins](#plugins) below. rtx use node@20 Use node-20.x in current project rtx use -g node@20 Use node-20.x as global default - rtx install node Install the version specified in .tool-versions + rtx install node Install the current version specified in .tool-versions/.rtx.toml rtx use node@latest Use latest node in current directory rtx use -g node@system Use system node as global default @@ -509,27 +496,112 @@ This can also be useful in environments where rtx isn't activated ## Configuration -### `.tool-versions` +### `.rtx.toml` + +`.rtx.toml` is a new config file that replaces asdf-style `.tool-versions` files with a file +that has lot more flexibility. It supports functionality that is not possible with `.tool-versions`, such as: + +- setting arbitrary env vars while inside the directory +- passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). +- specifying custom plugin urls + +Here is what an `.rtx.toml` looks like: + +```toml +[env] +# supports arbitrary env vars so rtx can be used like direnv/dotenv +NODE_ENV = 'production' -The `.tool-versions` file is used to specify the runtime versions for a project. An example of this -is: +[tools] +# specify single or multiple versions +terraform = '1.0.0' +erlang = ['23.3', '24.0'] + +# supports everything you can do with .tool-versions currently +node = ['16', 'prefix:20', 'ref:master', 'path:~/.nodes/14'] +# send arbitrary options to the plugin, passed as: +# RTX_TOOL_OPTS__VENV=.venv +python = {version='3.10', virtualenv='.venv'} + +[plugins] +# specify a custom repo url +# note this will only be used if the plugin does not already exist +python = 'https://github.com/jdxcode/rtx-python' + +[settings] # project-local settings +verbose = true + +[alias.node] # project-local aliases +my_custom_node = '20' ``` -node 20.0.0 # comments are allowed -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 -shfmt path:./shfmt # use a custom runtime -node lts # use lts version of node (not supported by all plugins) -# The following syntax is experimental and subject to change -node lts!-2 # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) -python latest!-0.1 # install python-3.10 if the latest is 3.11 +`.rtx.toml` files are hierarchical. The configuration in a file in the current directory will +override conflicting configuration in parent directories. For example, if `~/src/myproj/.rtx.toml` +defines the following: + +```toml +[tools] +node = '20' +python = '3.10' ``` -See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. +And `~/src/myproj/backend/.rtx.toml` defines: + +```toml +[tools] +node = '18' +ruby = '3.1' +``` + +Then when inside of `~/src/myproj/backend`, `node` will be `18`, `python` will be `3.10`, and `ruby` +will be `3.1`. You can check the active versions with `rtx ls --current`. + +You can also have environment specific config files like `.rtx.production.toml`, see +[Config Environments](#experimental-config-environments) for more details. + +#### `[env]` - Arbitrary Environment Variables + +The `[env]` section of .rtx.toml allows setting arbitrary environment variables. +These can be simple key/value entries like this: + +```toml +[env] +NODE_ENV = 'production' +``` + +`PATH` is treated specially, it needs to be defined as an array in `env_path`: + +```toml +env_path = [ + # adds an absolute path + "~/.local/share/bin", + # adds a path relative to the .rtx.toml, not PWD + "./node_modules/.bin", +] +``` + +_Note: `env_path` is a top-level key, it does not go inside of `[env]`._ + +Environment variable values can be templates, see [Templates](#templates) for details. + +```toml +[env] +LD_LIBRARY_PATH = "/some/path:{{env.LD_LIBRARY_PATH}}" +``` + +`env_file` can be used to specify a [dotenv](https://dotenv.org) file to load: + +```toml +env_file = '.env' +``` + +_Note: `env_file` goes at the top of the file, above `[env]`._ + +```toml +[env] +NODE_ENV = false # unset a previously set NODE_ENV +``` ### Legacy version files @@ -564,20 +636,44 @@ You may not even notice. > version files since they're version files not specific to asdf/rtx and can be used by other tools. > (`.nvmrc` being a notable exception, which is tied to a specific tool.) +### `.tool-versions` + +The `.tool-versions` file is asdf's config file and it can be used in rtx just like `.rtx.toml`. +It isn't as flexible so it's recommended to use `.rtx.toml` instead. It can be useful if you +already have a lot of `.tool-versions` files or work on a team that uses asdf. + +Here is an example with all the supported syntax: + +``` +node 20.0.0 # comments are allowed +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 +shfmt path:./shfmt # use a custom runtime +node lts # use lts version of node (not supported by all plugins) + +# The following syntax is experimental and subject to change +node lts!-2 # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) +python latest!-0.1 # install python-3.10 if the latest is 3.11 +``` + +See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. + ### Global config: `~/.config/rtx/config.toml` -rtx can be configured in `~/.config/rtx/config.toml`. The following options are available: +rtx can be configured in `~/.config/rtx/config.toml`. It's like local `.rtx.toml` files except that +it is used for all directories. ```toml [tools] # global tool versions go here +# you can set these with `rtx use -g` node = 'lts' python = ['3.10', '3.11'] [settings] -# whether to prompt to install plugins and runtimes if they're not already installed -missing_runtime_behavior = 'warn' # other options: 'ignore', 'warn', 'prompt', 'autoinstall' - # plugins can read the versions files used by other version managers (if enabled by the plugin) # for example, .nvmrc in the case of node's nvm legacy_version_file = true # enabled by default (different than asdf) @@ -613,106 +709,10 @@ my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20 These settings can also be managed with `rtx settings ls|get|set|unset`. -### [experimental] `.rtx.toml` - -`.rtx.toml` is a new config file that replaces both the global config and the `.tool-versions` -file. It allows for functionality that is not possible with `.tool-versions`, such as: - -- setting arbitrary env vars while inside the directory -- passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). -- specifying custom plugin urls - -Here is what the `.rtx.toml` looks like: - -```toml -[env] -# supports arbitrary env vars so rtx can be used like direnv/dotenv -NODE_ENV = 'production' - -[tools] -# specify single or multiple versions -terraform = '1.0.0' -erlang = ['23.3', '24.0'] - -# supports everything you can do with .tool-versions currently -node = ['16', 'prefix:20', 'ref:master', 'path:~/.nodes/14'] - -# send arbitrary options to the plugin, passed as: -# RTX_TOOL_OPTS__VENV=.venv -python = {version='3.10', virtualenv='.venv'} - -[plugins] -# specify a custom repo url -# note this will only be used if the plugin does not already exist -python = 'https://github.com/jdxcode/rtx-python' - -[settings] # project-local settings -verbose = true -missing_runtime_behavior = 'warn' - -[alias.node] # project-local aliases -my_custom_node = '20' -``` - -`.rtx.toml` is currently experimental and may change in minor versions of rtx. It does not -require setting `experimental = true` to use, however. - -#### `[env]` - Arbitrary Environment Variables - -The `[env]` section of .rtx.toml allows setting arbitrary environment variables. -These can be simple key/value entries like this: - -```toml -[env] -NODE_ENV = 'production' -``` - -`PATH` is treated specially, it needs to be defined as an array in `env_path`: - -```toml -env_path = [ - # adds an absolute path - "~/.local/share/bin", - # adds a path relative to the .rtx.toml, not PWD - "./node_modules/.bin", -] -``` - -_Note: `env_path` is a top-level key, it does not go inside of `[env]`._ - -Environment variable values can be templates, see [Templates](#templates) for details. - -```toml -[env] -LD_LIBRARY_PATH = "/some/path:{{env.LD_LIBRARY_PATH}}" -``` - -`env_file` can be used to specify a [dotenv](https://dotenv.org) file to load: - -```toml -env_file = '.env' -``` - -_Note: `env_file` goes at the top of the file, above `[env]`._ - -```toml -[env] -NODE_ENV = false # unset a previously set NODE_ENV -``` - ### Environment variables rtx can also be configured via environment variables. The following options are available: -#### `RTX_MISSING_RUNTIME_BEHAVIOR` - -This is the same as the `missing_runtime_behavior` config option in `~/.config/rtx/config.toml`. - -``` -RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx install node@20 -RTX_NODE_VERSION=20 rtx exec -- node --version -``` - #### `RTX_DATA_DIR` This is the directory where rtx stores plugins and tool installs. The default location is `~/.local/share/rtx`. @@ -839,8 +839,8 @@ Enables experimental features. ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS -versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for node@20.x. -So you can use the runtime with `node lts/hydrogen` in `.tool-versions`. +versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for node@20.x +so you can use set it with `node lts/hydrogen` in `.tool-versions`/`.rtx.toml`. User aliases can be created by adding an `alias.` section to `~/.config/rtx/config.toml`: From 2c051fbcbaad53453995bb6d713d76e400afc4e6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 16:13:57 -0500 Subject: [PATCH 0718/1891] docs --- README.md | 3 ++- completions/_rtx | 6 +++--- completions/rtx.fish | 4 ++-- man/man1/rtx.1 | 2 +- src/cli/use.rs | 3 ++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 81663f770..d5632d722 100644 --- a/README.md +++ b/README.md @@ -2229,8 +2229,9 @@ Examples: ### `rtx use [OPTIONS] [TOOL]...` ``` -Change the active version of a tool. This will install the tool if it is not already installed. +Change the active version of a tool locally or globally. +This will install the tool if it is not already installed. By default, this will use an `.rtx.toml` file in the current directory. Use the --global flag to use the global config file instead. This replaces asdf's `local` and `global` commands, however those are still available in rtx. diff --git a/completions/_rtx b/completions/_rtx index 524389866..c1766052f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1783,8 +1783,8 @@ _rtx_commands() { 'shell:Sets a tool version for the current shell session' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ -'use:Change the active version of a tool. This will install the tool if it is not already installed.' \ -'u:Change the active version of a tool. This will install the tool if it is not already installed.' \ +'use:Change the active version of a tool locally or globally.' \ +'u:Change the active version of a tool locally or globally.' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ 'which:Shows the path that a bin name points to' \ @@ -2135,7 +2135,7 @@ _rtx__help_commands() { 'shell:Sets a tool version for the current shell session' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ -'use:Change the active version of a tool. This will install the tool if it is not already installed.' \ +'use:Change the active version of a tool locally or globally.' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ 'which:Shows the path that a bin name points to' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index d1985da8a..a6fc8ea9f 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -37,7 +37,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "use" -d 'Change the active version of a tool. This will install the tool if it is not already installed.' +complete -c rtx -n "__fish_use_subcommand" -f -a "use" -d 'Change the active version of a tool locally or globally.' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' @@ -701,7 +701,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool. This will install the tool if it is not already installed.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index e98cf01d2..a33be1a84 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -113,7 +113,7 @@ rtx\-uninstall(1) Removes runtime versions .TP rtx\-use(1) -Change the active version of a tool. This will install the tool if it is not already installed. +Change the active version of a tool locally or globally. .TP rtx\-version(1) Show rtx version diff --git a/src/cli/use.rs b/src/cli/use.rs index deb7a8f93..d5e0e0939 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -11,8 +11,9 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; -/// Change the active version of a tool. This will install the tool if it is not already installed. +/// Change the active version of a tool locally or globally. /// +/// This will install the tool if it is not already installed. /// By default, this will use an `.rtx.toml` file in the current directory. /// Use the --global flag to use the global config file instead. /// This replaces asdf's `local` and `global` commands, however those are still available in rtx. From 07160fa309b824c1437dca07d4c53722286e3a39 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 22 Apr 2023 16:19:46 -0500 Subject: [PATCH 0719/1891] hide hidden plugins on doctor and plugin ls --- src/cli/doctor.rs | 1 + src/cli/plugins/ls.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 7794b8358..94d18a73e 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -111,6 +111,7 @@ fn render_plugins(config: &Config) -> String { .tools .values() .filter(|p| p.is_installed()) + .filter(|p| !config.is_plugin_hidden(&p.name)) .collect::>(); let max_plugin_name_len = plugins.iter().map(|p| p.name.len()).max().unwrap_or(0) + 2; for p in plugins { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 2640e7f39..f2f478bc8 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -38,7 +38,11 @@ impl Command for PluginsLs { .run(config, out); } - let mut plugins = config.tools.values().collect::>(); + let mut plugins = config + .tools + .values() + .filter(|p| !config.is_plugin_hidden(p.plugin.name())) + .collect::>(); if self.core { plugins.retain(|p| matches!(p.plugin.get_type(), PluginType::Core)); From 4cd1f93066623f240c382f7319306b71e15c1549 Mon Sep 17 00:00:00 2001 From: Louis Larry Date: Sun, 23 Apr 2023 18:47:37 +0700 Subject: [PATCH 0720/1891] Update README.md (#506) Fix download from GitHub Release --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5632d722..8835b0019 100644 --- a/README.md +++ b/README.md @@ -315,8 +315,8 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.1/rtx-v1.29.1-linux-x64 -mv rtx-v1.27.10-linux-x64 /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.29.1/rtx-v1.29.1-linux-x64 > /usr/local/bin/rtx +chmod +x /usr/local/bin/rtx ``` ### apt From 78da2cac5301b46ea0f1458f0ef3080059ad58ee Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 23 Apr 2023 10:38:33 -0500 Subject: [PATCH 0721/1891] make `rtx env` work in a clean environment (#509) Fixes #507 --- src/config/mod.rs | 10 ---------- src/env_diff.rs | 5 +++-- src/fake_asdf.rs | 8 ++++---- src/file.rs | 12 +++++++++++- src/shims.rs | 2 +- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 9eed2322c..ec9047f06 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -227,16 +227,6 @@ impl Config { Ok(config_files) } - pub fn rtx_bin(&self) -> Option { - for path in &*env::PATH { - let rtx_bin = path.join("rtx"); - if file::is_executable(&rtx_bin) { - return Some(rtx_bin); - } - } - None - } - pub fn check_for_new_version(&self) { if *CI || !console::user_attended_stderr() || *env::RTX_HIDE_UPDATE_WARNING { return; diff --git a/src/env_diff.rs b/src/env_diff.rs index 9ca912389..7b6684816 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -12,7 +12,7 @@ use flate2::Compression; use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; -use crate::cmd; +use crate::{cmd, file}; #[derive(Default, Serialize, Deserialize)] pub struct EnvDiff { @@ -66,8 +66,9 @@ impl EnvDiff { { let env: HashMap = env.into_iter().map(|(k, v)| (k.into(), v.into())).collect(); + let bash_path = file::which("bash").unwrap_or("/bin/bash".into()); let out = cmd!( - "bash", + bash_path, "-c", indoc::formatdoc! {" . {script} diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 5ce7a6ded..349b561cc 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -1,3 +1,4 @@ +use std::env::{join_paths, split_paths}; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; use std::{fs, io}; @@ -34,15 +35,14 @@ pub fn setup() -> color_eyre::Result { } pub fn get_path_with_fake_asdf() -> String { - let mut path = vec![]; + let mut path = split_paths(&env::var_os("PATH").unwrap_or_default()).collect::>(); match setup() { Ok(fake_asdf_path) => { - path.push(fake_asdf_path.to_string_lossy().to_string()); + path.insert(0, fake_asdf_path); } Err(e) => { warn!("Failed to setup fake asdf: {:#}", e); } }; - path.push(env::var("PATH").unwrap()); - path.join(":") + join_paths(path).unwrap().to_string_lossy().to_string() } diff --git a/src/file.rs b/src/file.rs index 7234a1d6b..e448d4adf 100644 --- a/src/file.rs +++ b/src/file.rs @@ -7,7 +7,7 @@ use filetime::{set_file_times, FileTime}; use std::os::unix::fs::symlink; use std::os::unix::prelude::*; -use crate::dirs; +use crate::{dirs, env}; pub fn remove_all>(path: P) -> io::Result<()> { let path = path.as_ref(); @@ -178,6 +178,16 @@ impl Iterator for FindUp { } } +pub fn which(name: &str) -> Option { + for path in &*env::PATH { + let bin = path.join(name); + if is_executable(&bin) { + return Some(bin); + } + } + None +} + #[cfg(test)] mod tests { use itertools::Itertools; diff --git a/src/shims.rs b/src/shims.rs index ecacbe461..33a9e6cbb 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -75,7 +75,7 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { // remove old shims let _ = remove_all(&*dirs::SHIMS); create_dir_all(&*dirs::SHIMS)?; - let rtx_bin = config.rtx_bin().unwrap_or(env::RTX_EXE.clone()); + let rtx_bin = file::which("rtx").unwrap_or(env::RTX_EXE.clone()); let paths: Vec = ts .list_installed_versions(config)? From 9d4ec8b98f30a9f262ee72ae400635fff9187ba1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 23 Apr 2023 10:55:24 -0500 Subject: [PATCH 0722/1891] added --json flag for `rtx env` (#510) Fixes #508 --- README.md | 17 +++++--- completions/_rtx | 3 +- completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/env.rs | 39 +++++++++++++++---- src/cli/ls.rs | 2 +- .../rtx__cli__env__tests__env_json.snap | 8 ++++ 7 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__env__tests__env_json.snap diff --git a/README.md b/README.md index 8835b0019..dbf0a7499 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ v20.0.0 - [`rtx deactivate`](#rtx-deactivate) - [`rtx direnv activate`](#rtx-direnv-activate) - [`rtx doctor`](#rtx-doctor) - - [`rtx env [OPTIONS] [RUNTIME]...`](#rtx-env-options-runtime) + - [`rtx env [OPTIONS] [TOOL]...`](#rtx-env-options-tool) - [`rtx exec [OPTIONS] [RUNTIME]... [-- ...]`](#rtx-exec-options-runtime----command) - [`rtx implode [OPTIONS]`](#rtx-implode-options) - [`rtx install [OPTIONS] [RUNTIME]...`](#rtx-install-options-runtime) @@ -1655,7 +1655,7 @@ Examples: $ rtx doctor [WARN] plugin node is not installed ``` -### `rtx env [OPTIONS] [RUNTIME]...` +### `rtx env [OPTIONS] [TOOL]...` ``` Exports env vars to activate rtx a single time @@ -1663,11 +1663,11 @@ Exports env vars to activate rtx a single time Use this if you don't want to permanently install rtx. It's not necessary to use this if you have `rtx activate` in your shell rc file. -Usage: env [OPTIONS] [RUNTIME]... +Usage: env [OPTIONS] [TOOL]... Arguments: - [RUNTIME]... - Runtime version to use + [TOOL]... + Tool version(s) to use Options: -s, --shell @@ -1675,6 +1675,11 @@ Options: [possible values: bash, fish, nu, xonsh, zsh] + --json + Output in JSON format + + [short aliases: J] + Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" @@ -1811,6 +1816,8 @@ Options: --json Output in json format + [short aliases: J] + Examples: $ rtx ls ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) diff --git a/completions/_rtx b/completions/_rtx index c1766052f..e1b0ea561 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -561,6 +561,7 @@ default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--json[Output in JSON format]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. @@ -572,7 +573,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime version to use:' \ +'*::tool -- Tool version(s) to use:' \ && ret=0 ;; (exec) diff --git a/completions/rtx.bash b/completions/rtx.bash index f28b5ecd7..bbb69c424 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1215,7 +1215,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -r -v -h --shell --debug --install-missing --jobs --log-level --raw --trace --verbose --help [RUNTIME]..." + opts="-s -j -r -v -h --shell --json --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index a6fc8ea9f..5f4eac1d2 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -263,6 +263,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell typ complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -l json -d 'Output in JSON format' complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/src/cli/env.rs b/src/cli/env.rs index c57a852e5..c47991123 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -5,7 +5,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; -use crate::toolset::ToolsetBuilder; +use crate::toolset::{Toolset, ToolsetBuilder}; /// Exports env vars to activate rtx a single time /// @@ -15,29 +15,47 @@ use crate::toolset::ToolsetBuilder; #[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Env { /// Shell type to generate environment variables for - #[clap(long, short)] + #[clap(long, short, overrides_with = "json")] shell: Option, - /// Runtime version to use + /// Tool version(s) to use #[clap(value_parser = RuntimeArgParser)] - runtime: Vec, + tool: Vec, + + /// Output in JSON format + #[clap(long, visible_short_alias = 'J', overrides_with = "shell")] + json: bool, } impl Command for Env { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() - .with_args(&self.runtime) + .with_args(&self.tool) .build(&mut config)?; + if self.json { + self.output_json(config, out, ts) + } else { + self.output_shell(config, out, ts) + } + } +} + +impl Env { + fn output_json(&self, config: Config, out: &mut Output, ts: Toolset) -> Result<()> { + let env = ts.env_with_path(&config); + rtxprintln!(out, "{}", serde_json::to_string_pretty(&env)?); + Ok(()) + } + + fn output_shell(&self, config: Config, out: &mut Output, ts: Toolset) -> Result<()> { let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); - for (k, v) in ts.env_with_path(&config) { let k = k.to_string(); let v = v.to_string(); rtxprint!(out, "{}", shell.set_env(&k, &v)); } - Ok(()) } } @@ -57,9 +75,9 @@ mod tests { use pretty_assertions::assert_str_eq; - use crate::assert_cli; use crate::cli::tests::grep; use crate::dirs; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_env() { @@ -110,4 +128,9 @@ mod tests { let stdout = assert_cli!("env"); assert!(stdout.contains("export PATH=")); } + + #[test] + fn test_env_json() { + assert_cli_snapshot!("env", "-J"); + } } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index c859f969a..225a69aa3 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -45,7 +45,7 @@ pub struct Ls { parseable: bool, /// Output in json format - #[clap(long)] + #[clap(long, visible_short_alias = 'J', overrides_with = "parseable")] json: bool, } diff --git a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap new file mode 100644 index 000000000..63869c709 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap @@ -0,0 +1,8 @@ +--- +source: src/cli/env.rs +expression: output +--- +{ + "JDXCODE_TINY": "3.1.0", + "PATH": "~/data/installs/tiny/3.1.0/bin:~/data/installs/dummy/ref-master/bin:$PATH" +} From 7ff837161bc25be8361fe663d67f9f1bcdb604cb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 23 Apr 2023 11:13:04 -0500 Subject: [PATCH 0723/1891] rename runtime -> tool (#511) I should have named these "tools" from the beginning since that is what ".tool-versions" certainly implies. --- README.md | 76 +++++++++++++--------------- completions/_rtx | 40 +++++++-------- completions/rtx.bash | 24 +++------ completions/rtx.fish | 12 ++--- e2e/test_tool_versions_alt | 3 +- man/man1/rtx.1 | 2 +- src/cli/args/mod.rs | 2 +- src/cli/args/{runtime.rs => tool.rs} | 32 ++++++------ src/cli/env.rs | 8 +-- src/cli/exec.rs | 17 +++---- src/cli/global.rs | 20 ++++---- src/cli/install.rs | 47 +++++------------ src/cli/latest.rs | 18 +++---- src/cli/local.rs | 24 ++++----- src/cli/ls_remote.rs | 6 +-- src/cli/plugins/install.rs | 2 +- src/cli/shell.rs | 10 ++-- src/cli/uninstall.rs | 10 ++-- src/cli/use.rs | 8 +-- src/cli/where.rs | 21 ++++---- src/config/config_file/mod.rs | 14 ++--- src/shims.rs | 2 +- src/toolset/builder.rs | 8 +-- 23 files changed, 182 insertions(+), 224 deletions(-) rename src/cli/args/{runtime.rs => tool.rs} (73%) diff --git a/README.md b/README.md index dbf0a7499..eb4e1fcf3 100644 --- a/README.md +++ b/README.md @@ -149,10 +149,10 @@ v20.0.0 - [`rtx direnv activate`](#rtx-direnv-activate) - [`rtx doctor`](#rtx-doctor) - [`rtx env [OPTIONS] [TOOL]...`](#rtx-env-options-tool) - - [`rtx exec [OPTIONS] [RUNTIME]... [-- ...]`](#rtx-exec-options-runtime----command) + - [`rtx exec [OPTIONS] [TOOL]... [-- ...]`](#rtx-exec-options-tool----command) - [`rtx implode [OPTIONS]`](#rtx-implode-options) - - [`rtx install [OPTIONS] [RUNTIME]...`](#rtx-install-options-runtime) - - [`rtx latest `](#rtx-latest-runtime) + - [`rtx install [OPTIONS] [TOOL]...`](#rtx-install-options-tool) + - [`rtx latest `](#rtx-latest-tool) - [`rtx ls [OPTIONS]`](#rtx-ls-options) - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-plugin-prefix) - [`rtx plugins install [OPTIONS] [NAME] [GIT_URL]`](#rtx-plugins-install-options-name-git_url) @@ -168,12 +168,12 @@ v20.0.0 - [`rtx settings ls`](#rtx-settings-ls) - [`rtx settings set `](#rtx-settings-set-key-value) - [`rtx settings unset `](#rtx-settings-unset-key) - - [`rtx shell [OPTIONS] [RUNTIME]...`](#rtx-shell-options-runtime) + - [`rtx shell [OPTIONS] [TOOL]...`](#rtx-shell-options-tool) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - - [`rtx uninstall ...`](#rtx-uninstall-runtime) + - [`rtx uninstall ...`](#rtx-uninstall-tool) - [`rtx use [OPTIONS] [TOOL]...`](#rtx-use-options-tool) - [`rtx version`](#rtx-version) - - [`rtx where `](#rtx-where-runtime) + - [`rtx where `](#rtx-where-tool) - [`rtx which [OPTIONS] `](#rtx-which-options-bin_name) @@ -1667,7 +1667,7 @@ Usage: env [OPTIONS] [TOOL]... Arguments: [TOOL]... - Tool version(s) to use + Tool(s) to use Options: -s, --shell @@ -1686,25 +1686,24 @@ Examples: $ rtx env -s fish | source $ execx($(rtx env -s xonsh)) ``` -### `rtx exec [OPTIONS] [RUNTIME]... [-- ...]` +### `rtx exec [OPTIONS] [TOOL]... [-- ...]` ``` -Execute a command with runtime(s) set +Execute a command with tool(s) set -use this to avoid modifying the shell session or running ad-hoc commands with the rtx runtimes -set. +use this to avoid modifying the shell session or running ad-hoc commands with rtx tools set. -Runtimes will be loaded from .tool-versions, though they can be overridden with args +Tools will be loaded from .rtx.toml/.tool-versions, though they can be overridden with args Note that only the plugin specified will be overridden, so if a `.tool-versions` file includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. The "--" separates runtimes from the commands to pass along to the subprocess. -Usage: exec [OPTIONS] [RUNTIME]... [-- ...] +Usage: exec [OPTIONS] [TOOL]... [-- ...] Arguments: - [RUNTIME]... - Runtime(s) to start e.g.: node@20 python@3.10 + [TOOL]... + Tool(s) to start e.g.: node@20 python@3.10 [COMMAND]... Command string to execute (same as --command) @@ -1744,7 +1743,7 @@ Options: --dry-run List directories that would be removed without actually removing them ``` -### `rtx install [OPTIONS] [RUNTIME]...` +### `rtx install [OPTIONS] [TOOL]...` ``` Install a tool version @@ -1754,18 +1753,15 @@ It won't be used simply by being installed, however. For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. Or you can call a tool version explicitly with `rtx exec @ -- `. -Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` +Tools will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` -Usage: install [OPTIONS] [RUNTIME]... +Usage: install [OPTIONS] [TOOL]... Arguments: - [RUNTIME]... - Tool version(s) to install e.g.: node@20 + [TOOL]... + Tool(s) to install e.g.: node@20 Options: - -p, --plugin - Only install tool version(s) for - -f, --force Force reinstall even if already installed @@ -1778,16 +1774,16 @@ Examples: $ rtx install node # install version specified in .tool-versions or .rtx.toml $ rtx install # installs everything specified in .tool-versions or .rtx.toml ``` -### `rtx latest ` +### `rtx latest ` ``` Gets the latest available version for a plugin -Usage: latest +Usage: latest Arguments: - - Runtime to get the latest version of + + Tool to get the latest version of Examples: $ rtx latest node@20 # get the latest version of node 20 @@ -1883,7 +1879,7 @@ Examples: ``` Install a plugin -note that rtx automatically can install plugins when you install a runtime +note that rtx automatically can install plugins when you install a tool e.g.: `rtx install node@20` will autoinstall the node plugin This behavior can be modified in ~/.config/rtx/config.toml @@ -2166,18 +2162,18 @@ Arguments: Examples: $ rtx settings unset legacy_version_file ``` -### `rtx shell [OPTIONS] [RUNTIME]...` +### `rtx shell [OPTIONS] [TOOL]...` ``` Sets a tool version for the current shell session Only works in a session where rtx is already activated. -Usage: shell [OPTIONS] [RUNTIME]... +Usage: shell [OPTIONS] [TOOL]... Arguments: - [RUNTIME]... - Runtime version(s) to use + [TOOL]... + Tool(s) to use Options: -u, --unset @@ -2218,16 +2214,16 @@ Examples: # trusts .rtx.toml in the current or parent directory $ rtx trust ``` -### `rtx uninstall ...` +### `rtx uninstall ...` ``` Removes runtime versions -Usage: uninstall ... +Usage: uninstall ... Arguments: - ... - Runtime(s) to remove + ... + Tool(s) to remove Examples: $ rtx uninstall node@18.0.0 # will uninstall specific version @@ -2286,18 +2282,18 @@ Show rtx version Usage: version ``` -### `rtx where ` +### `rtx where ` ``` Display the installation path for a runtime Must be installed. -Usage: where +Usage: where Arguments: - - Runtime(s) to look up + + Tool(s) to look up e.g.: ruby@3 if "@" is specified, it will show the latest installed version that matches the prefix diff --git a/completions/_rtx b/completions/_rtx index e1b0ea561..514e001b7 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -573,7 +573,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool version(s) to use:' \ +'*::tool -- Tool(s) to use:' \ && ret=0 ;; (exec) @@ -597,7 +597,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to start e.g.\: node@20 python@3.10:' \ +'*::tool -- Tool(s) to start e.g.\: node@20 python@3.10:' \ && ret=0 ;; (global) @@ -625,9 +625,9 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to add to .tool-versions +'*::tool -- Tool(s) to add to .tool-versions e.g.\: node@20 -If this is a single runtime with no version, the current value of the global +If this is a single tool with no version, the current value of the global .tool-versions will be displayed:' \ && ret=0 ;; @@ -678,8 +678,6 @@ Sets --jobs=1]' \ ;; (install) _arguments "${_arguments_options[@]}" \ -'()*-p+[Only install tool version(s) for ]:PLUGIN: ' \ -'()*--plugin=[Only install tool version(s) for ]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel @@ -687,8 +685,6 @@ default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Force reinstall even if already installed]' \ '--force[Force reinstall even if already installed]' \ -'(-p --plugin -f --force)-a[Install all missing tool versions as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ -'(-p --plugin -f --force)--all[Install all missing tool versions as well as all plugins for the current directory This is hidden because it'\''s now the default behavior]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '--debug[Sets log level to debug]' \ @@ -700,7 +696,7 @@ Sets --jobs=1]' \ '--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Tool version(s) to install e.g.\: node@20:' \ +'*::tool -- Tool(s) to install e.g.\: node@20:' \ && ret=0 ;; (latest) @@ -721,7 +717,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':runtime -- Runtime to get the latest version of:' \ +':tool -- Tool to get the latest version of:' \ '::asdf_version -- The version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ && ret=0 ;; @@ -734,9 +730,9 @@ default\: 4]: : ' \ default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-p[Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the runtime in the current directory ("\$PWD/.tool-versions")]' \ +by default this command will only set the tool in the current directory ("\$PWD/.tool-versions")]' \ '--parent[Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the runtime in the current directory ("\$PWD/.tool-versions")]' \ +by default this command will only set the tool in the current directory ("\$PWD/.tool-versions")]' \ '--pin[Save exact version to \`.tool-versions\` e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to .tool-versions]' \ '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ @@ -752,9 +748,9 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtimes to add to .tool-versions/.rtx.toml +'*::tool -- Tool(s) to add to .tool-versions/.rtx.toml e.g.\: node@20 -if this is a single runtime with no version, +if this is a single tool with no version, the current value of .tool-versions/.rtx.toml will be displayed:' \ && ret=0 ;; @@ -1288,7 +1284,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime version(s) to use:' \ +'*::tool -- Tool(s) to use:' \ && ret=0 ;; (trust) @@ -1331,7 +1327,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::runtime -- Runtime(s) to remove:' \ +'*::tool -- Tool(s) to remove:' \ && ret=0 ;; (use) @@ -1405,7 +1401,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':runtime -- Runtime(s) to look up +':tool -- Tool(s) to look up e.g.\: ruby@3 if "@" is specified, it will show the latest installed version that matches the prefix @@ -1763,9 +1759,9 @@ _rtx_commands() { 'doctor:Check rtx installation for possible problems.' \ 'env:Exports env vars to activate rtx a single time' \ 'e:Exports env vars to activate rtx a single time' \ -'exec:Execute a command with runtime(s) set' \ -'x:Execute a command with runtime(s) set' \ -'global:Sets/gets the global runtime version(s)' \ +'exec:Execute a command with tool(s) set' \ +'x:Execute a command with tool(s) set' \ +'global:Sets/gets the global tool version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ 'install:Install a tool version' \ @@ -2119,8 +2115,8 @@ _rtx__help_commands() { 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ 'env:Exports env vars to activate rtx a single time' \ -'exec:Execute a command with runtime(s) set' \ -'global:Sets/gets the global runtime version(s)' \ +'exec:Execute a command with tool(s) set' \ +'global:Sets/gets the global tool version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ 'implode:Removes rtx CLI and all related data' \ 'install:Install a tool version' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index bbb69c424..2fdb78719 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1249,7 +1249,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -v -h --command --cd --debug --install-missing --jobs --log-level --raw --trace --verbose --help [RUNTIME]... [COMMAND]..." + opts="-c -j -r -v -h --command --cd --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1287,7 +1287,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -v -h --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [RUNTIME]..." + opts="-j -r -v -h --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2119,20 +2119,12 @@ _rtx() { return 0 ;; rtx__install) - opts="-p -f -a -v -j -r -h --plugin --force --all --verbose --debug --install-missing --jobs --log-level --raw --trace --help [RUNTIME]..." + opts="-f -v -j -r -h --force --verbose --debug --install-missing --jobs --log-level --raw --trace --help [TOOL]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --plugin) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -p) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2153,7 +2145,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2179,7 +2171,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [RUNTIME]..." + opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2881,7 +2873,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -r -v -h --unset --debug --install-missing --jobs --log-level --raw --trace --verbose --help [RUNTIME]..." + opts="-u -j -r -v -h --unset --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2933,7 +2925,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help ..." + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3023,7 +3015,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 5f4eac1d2..0f68f9977 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -20,8 +20,8 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'Disable rtx fo complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets/gets the global runtime version(s)' +complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets/gets the global tool version(s)' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a tool version' @@ -324,12 +324,10 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from install" -s p -l plugin -d 'Only install tool version(s) for ' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' -complete -c rtx -n "__fish_seen_subcommand_from install" -s a -l all -d 'Install all missing tool versions as well as all plugins for the current directory This is hidden because it\'s now the default behavior' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' @@ -352,7 +350,7 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number o default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the runtime in the current directory ("$PWD/.tool-versions")' +by default this command will only set the tool in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' @@ -685,8 +683,8 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with runtime(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global runtime version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index 8412924eb..52b51533f 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -euo pipefail export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions @@ -6,7 +7,7 @@ export RTX_DEFAULT_CONFIG_FILENAME=.MISSING git checkout .alternate-tool-versions -rtx i -p shfmt +rtx i shfmt rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a33be1a84..338193bab 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -71,7 +71,7 @@ rtx\-env(1) Exports env vars to activate rtx a single time .TP rtx\-exec(1) -Execute a command with runtime(s) set +Execute a command with tool(s) set .TP rtx\-implode(1) Removes rtx CLI and all related data diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index ab62d9403..cd7865d07 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -2,5 +2,5 @@ pub mod install_missing; pub mod jobs; pub mod log_level; pub mod raw; -pub mod runtime; +pub mod tool; pub mod verbose; diff --git a/src/cli/args/runtime.rs b/src/cli/args/tool.rs similarity index 73% rename from src/cli/args/runtime.rs rename to src/cli/args/tool.rs index 911ea67ae..46884f732 100644 --- a/src/cli/args/runtime.rs +++ b/src/cli/args/tool.rs @@ -9,12 +9,12 @@ use crate::plugins::PluginName; use crate::toolset::ToolVersionRequest; #[derive(Debug, Clone, Eq, PartialEq)] -pub struct RuntimeArg { +pub struct ToolArg { pub plugin: PluginName, pub tvr: Option, } -impl RuntimeArg { +impl ToolArg { pub fn parse(input: &str) -> Self { match input.split_once('@') { Some((plugin, version)) => Self { @@ -35,19 +35,19 @@ impl RuntimeArg { /// /// We can detect this, and we know what they meant, so make it work the way /// they expected. - pub fn double_runtime_condition(runtimes: &[RuntimeArg]) -> Vec { - let mut runtimes = runtimes.to_vec(); - if runtimes.len() == 2 { + pub fn double_tool_condition(tools: &[ToolArg]) -> Vec { + let mut tools = tools.to_vec(); + if tools.len() == 2 { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); - let a = runtimes[0].clone(); - let b = runtimes[1].clone(); + let a = tools[0].clone(); + let b = tools[1].clone(); if matches!(a.tvr, None) && matches!(b.tvr, None) && re.is_match(&b.plugin) { - runtimes[1].tvr = Some(ToolVersionRequest::new(a.plugin.clone(), &b.plugin)); - runtimes[1].plugin = a.plugin; - runtimes.remove(0); + tools[1].tvr = Some(ToolVersionRequest::new(a.plugin.clone(), &b.plugin)); + tools[1].plugin = a.plugin; + tools.remove(0); } } - runtimes + tools } pub fn with_version(self, version: &str) -> Self { @@ -58,7 +58,7 @@ impl RuntimeArg { } } -impl Display for RuntimeArg { +impl Display for ToolArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.tvr { Some(tvr) => write!(f, "{}", tvr), @@ -68,10 +68,10 @@ impl Display for RuntimeArg { } #[derive(Debug, Clone)] -pub struct RuntimeArgParser; +pub struct ToolArgParser; -impl clap::builder::TypedValueParser for RuntimeArgParser { - type Value = RuntimeArg; +impl clap::builder::TypedValueParser for ToolArgParser { + type Value = ToolArg; fn parse_ref( &self, @@ -88,6 +88,6 @@ impl clap::builder::TypedValueParser for RuntimeArgParser { _arg: Option<&Arg>, value: OsString, ) -> Result { - Ok(RuntimeArg::parse(&value.to_string_lossy())) + Ok(ToolArg::parse(&value.to_string_lossy())) } } diff --git a/src/cli/env.rs b/src/cli/env.rs index c47991123..16a632c82 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Result; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -18,9 +18,9 @@ pub struct Env { #[clap(long, short, overrides_with = "json")] shell: Option, - /// Tool version(s) to use - #[clap(value_parser = RuntimeArgParser)] - tool: Vec, + /// Tool(s) to use + #[clap(value_parser = ToolArgParser)] + tool: Vec, /// Output in JSON format #[clap(long, visible_short_alias = 'J', overrides_with = "shell")] diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 6c1c787d9..9e01be4a1 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -6,7 +6,7 @@ use clap::ValueHint; use color_eyre::eyre::{eyre, Result}; use duct::IntoExecutablePath; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; #[cfg(test)] use crate::cmd; @@ -16,12 +16,11 @@ use crate::env; use crate::output::Output; use crate::toolset::ToolsetBuilder; -/// Execute a command with runtime(s) set +/// Execute a command with tool(s) set /// -/// use this to avoid modifying the shell session or running ad-hoc commands with the rtx runtimes -/// set. +/// use this to avoid modifying the shell session or running ad-hoc commands with rtx tools set. /// -/// Runtimes will be loaded from .tool-versions, though they can be overridden with args +/// Tools will be loaded from .rtx.toml/.tool-versions, though they can be overridden with args /// Note that only the plugin specified will be overridden, so if a `.tool-versions` file /// includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. /// @@ -29,10 +28,10 @@ use crate::toolset::ToolsetBuilder; #[derive(Debug, clap::Args)] #[clap(visible_alias = "x", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Exec { - /// Runtime(s) to start + /// Tool(s) to start /// e.g.: node@20 python@3.10 - #[clap(value_parser = RuntimeArgParser)] - pub runtime: Vec, + #[clap(value_parser = ToolArgParser)] + pub tool: Vec, /// Command string to execute (same as --command) #[clap(conflicts_with = "c", required_unless_present = "c", last = true)] @@ -50,7 +49,7 @@ pub struct Exec { impl Command for Exec { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() - .with_args(&self.runtime) + .with_args(&self.tool) .with_install_missing() .build(&mut config)?; let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); diff --git a/src/cli/global.rs b/src/cli/global.rs index 9048fa53d..2c7430b79 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use color_eyre::eyre::Result; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::cli::local::local; use crate::config::Config; @@ -10,7 +10,7 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; -/// Sets/gets the global runtime version(s) +/// Sets/gets the global tool version(s) /// /// Displays the contents of ~/.tool-versions after writing. /// The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. @@ -18,16 +18,16 @@ use crate::{dirs, env}; /// Otherwise, it will be parsed as a `.tool-versions` file. /// A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. /// -/// Use `rtx local` to set a runtime version locally in the current directory. +/// Use `rtx local` to set a tool version locally in the current directory. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, hide = true, alias = "g", after_long_help = AFTER_LONG_HELP)] pub struct Global { - /// Runtime(s) to add to .tool-versions + /// Tool(s) to add to .tool-versions /// e.g.: node@20 - /// If this is a single runtime with no version, the current value of the global + /// If this is a single tool with no version, the current value of the global /// .tool-versions will be displayed - #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] - runtime: Option>, + #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + tool: Option>, /// Save exact version to `~/.tool-versions` /// e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions @@ -55,7 +55,7 @@ impl Command for Global { config, out, &global_file(), - self.runtime, + self.tool, self.remove, self.pin, self.fuzzy, @@ -122,11 +122,11 @@ mod tests { // can only request a version one plugin at a time let err = assert_cli_err!("global", "tiny", "dummy"); - assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each tool. Or just specify one tool to print the current version"); // this is just invalid let err = assert_cli_err!("global", "tiny", "dummy@latest"); - assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each tool. Or just specify one tool to print the current version"); assert_cli_snapshot!("global", "--path"); diff --git a/src/cli/install.rs b/src/cli/install.rs index ee7042b47..2c4ec5bf3 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,4 +1,3 @@ -use std::collections::HashSet; use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; @@ -7,13 +6,13 @@ use itertools::Itertools; use rayon::prelude::*; use rayon::ThreadPoolBuilder; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; -use crate::errors::Error::PluginNotInstalled; + use crate::output::Output; -use crate::plugins::PluginName; + use crate::runtime_symlinks::rebuild_symlinks; use crate::shims::reshim; use crate::tool::Tool; @@ -30,28 +29,19 @@ use crate::ui::progress_report::ProgressReport; /// For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. /// Or you can call a tool version explicitly with `rtx exec @ -- `. /// -/// Runtimes will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` +/// Tools will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` #[derive(Debug, clap::Args)] #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Install { - /// Tool version(s) to install + /// Tool(s) to install /// e.g.: node@20 - #[clap(value_parser = RuntimeArgParser)] - runtime: Option>, - - /// Only install tool version(s) for - #[clap(long, short, conflicts_with = "runtime")] - plugin: Option>, + #[clap(value_parser = ToolArgParser)] + tool: Option>, /// Force reinstall even if already installed - #[clap(long, short, requires = "runtime")] + #[clap(long, short, requires = "tool")] force: bool, - /// Install all missing tool versions as well as all plugins for the current directory - /// This is hidden because it's now the default behavior - #[clap(long, short, conflicts_with_all = ["runtime", "plugin", "force"], hide = true)] - all: bool, - /// Show installation output #[clap(long, short, action = clap::ArgAction::Count)] verbose: u8, @@ -61,7 +51,7 @@ impl Command for Install { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { config.settings.missing_runtime_behavior = AutoInstall; - match &self.runtime { + match &self.tool { Some(runtime) => self.install_runtimes(config, runtime)?, None => self.install_missing_runtimes(config)?, } @@ -71,7 +61,7 @@ impl Command for Install { } impl Install { - fn install_runtimes(&self, mut config: Config, runtimes: &[RuntimeArg]) -> Result<()> { + fn install_runtimes(&self, mut config: Config, runtimes: &[ToolArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); let ts = ToolsetBuilder::new() .with_latest_versions() @@ -99,11 +89,11 @@ impl Install { &self, config: &mut Config, ts: &Toolset, - runtimes: &[RuntimeArg], + runtimes: &[ToolArg], mpr: &MultiProgressReport, ) -> Result, ToolVersion)>> { let mut requests = vec![]; - for runtime in RuntimeArg::double_runtime_condition(runtimes) { + for runtime in ToolArg::double_tool_condition(runtimes) { let default_opts = ToolVersionOptions::new(); match runtime.tvr { Some(tv) => requests.push((runtime.plugin, tv, default_opts.clone())), @@ -151,19 +141,6 @@ impl Install { let mut ts = ToolsetBuilder::new() .with_latest_versions() .build(&mut config)?; - if let Some(plugins) = &self.plugin { - let plugins = plugins.iter().collect::>(); - for plugin in ts.versions.keys().cloned().collect::>() { - if !plugins.contains(&plugin) { - ts.versions.remove(&plugin); - } - } - for plugin in plugins { - if !ts.versions.contains_key(plugin) { - Err(PluginNotInstalled(plugin.to_string()))?; - } - } - } if ts.list_missing_versions(&config).is_empty() { warn!("no runtimes to install"); } diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 3ad6013ef..2aebdc828 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -11,9 +11,9 @@ use crate::toolset::ToolVersionRequest; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Latest { - /// Runtime to get the latest version of - #[clap(value_parser = RuntimeArgParser)] - runtime: RuntimeArg, + /// Tool to get the latest version of + #[clap(value_parser = ToolArgParser)] + tool: ToolArg, /// The version prefix to use when querying the latest version /// same as the first argument after the "@" @@ -24,19 +24,19 @@ pub struct Latest { impl Command for Latest { fn run(self, config: Config, out: &mut Output) -> Result<()> { - let mut prefix = match self.runtime.tvr { + let mut prefix = match self.tool.tvr { None => self.asdf_version, Some(ToolVersionRequest::Version(_, version)) => Some(version), _ => Err(eyre!( "invalid version: {}", - style(&self.runtime).cyan().for_stderr() + style(&self.tool).cyan().for_stderr() ))?, }; - let plugin = config.tools.get(&self.runtime.plugin).ok_or_else(|| { + let plugin = config.tools.get(&self.tool.plugin).ok_or_else(|| { eyre!( "plugin {} not found. run {} to install it", - style(self.runtime.plugin.to_string()).cyan().for_stderr(), - style(format!("rtx plugin install {}", self.runtime.plugin)) + style(self.tool.plugin.to_string()).cyan().for_stderr(), + style(format!("rtx plugin install {}", self.tool.plugin)) .yellow() .for_stderr() ) diff --git a/src/cli/local.rs b/src/cli/local.rs index 0ee6b0701..f2082fd46 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, ContextCompat, Result}; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; @@ -15,21 +15,21 @@ use crate::{dirs, env, file}; /// Sets/gets tool version in local .tool-versions or .rtx.toml /// /// Use this to set a tool's version when within a directory -/// Use `rtx global` to set a runtime version globally +/// Use `rtx global` to set a tool version globally /// This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` /// is set. A future v2 release of rtx will default to using `.rtx.toml`. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, hide = true, alias = "l", after_long_help = AFTER_LONG_HELP)] pub struct Local { - /// Runtimes to add to .tool-versions/.rtx.toml + /// Tool(s) to add to .tool-versions/.rtx.toml /// e.g.: node@20 - /// if this is a single runtime with no version, + /// if this is a single tool with no version, /// the current value of .tool-versions/.rtx.toml will be displayed - #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment)] - runtime: Option>, + #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + tool: Option>, /// Recurse up to find a .tool-versions file rather than using the current directory only - /// by default this command will only set the runtime in the current directory ("$PWD/.tool-versions") + /// by default this command will only set the tool in the current directory ("$PWD/.tool-versions") #[clap(short, long, verbatim_doc_comment)] parent: bool, @@ -64,7 +64,7 @@ impl Command for Local { config, out, &path, - self.runtime, + self.tool, self.remove, self.pin, self.fuzzy, @@ -96,7 +96,7 @@ pub fn local( mut config: Config, out: &mut Output, path: &Path, - runtime: Option>, + runtime: Option>, remove: Option>, pin: bool, fuzzy: bool, @@ -119,7 +119,7 @@ pub fn local( } if let Some(runtimes) = &runtime { - let runtimes = RuntimeArg::double_runtime_condition(&runtimes.clone()); + let runtimes = ToolArg::double_tool_condition(&runtimes.clone()); if cf.display_runtime(out, &runtimes)? { install_missing_runtimes(&mut config, cf.as_ref())?; return Ok(()); @@ -258,7 +258,7 @@ mod tests { fn test_local_invalid_multiple_plugins() { run_test(|| { let err = assert_cli_err!("local", "tiny", "dummy"); - assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each tool. Or just specify one tool to print the current version"); }); } @@ -266,7 +266,7 @@ mod tests { fn test_local_invalid() { run_test(|| { let err = assert_cli_err!("local", "tiny", "dummy@latest"); - assert_str_eq!(err.to_string(), "invalid input, specify a version for each runtime. Or just specify one runtime to print the current version"); + assert_str_eq!(err.to_string(), "invalid input, specify a version for each tool. Or just specify one tool to print the current version"); }); } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 4bdd83c61..db3e4801b 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::Result; use std::sync::Arc; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; @@ -19,8 +19,8 @@ use crate::ui::prompt; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = ["list-all", "list-remote"])] pub struct LsRemote { /// Plugin to get versions for - #[clap(value_parser = RuntimeArgParser)] - plugin: RuntimeArg, + #[clap(value_parser = ToolArgParser)] + plugin: ToolArg, /// The version prefix to use when querying the latest version /// same as the first argument after the "@" diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 4318e01ad..415f78fb1 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -13,7 +13,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Install a plugin /// -/// note that rtx automatically can install plugins when you install a runtime +/// note that rtx automatically can install plugins when you install a tool /// e.g.: `rtx install node@20` will autoinstall the node plugin /// /// This behavior can be modified in ~/.config/rtx/config.toml diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 31bc7680a..7a2c7b6be 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -15,9 +15,9 @@ use crate::toolset::{ToolSource, ToolsetBuilder}; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Shell { - /// Runtime version(s) to use - #[clap(value_parser = RuntimeArgParser)] - runtime: Vec, + /// Tool(s) to use + #[clap(value_parser = ToolArgParser)] + tool: Vec, /// Removes a previously set version #[clap(long, short)] @@ -28,7 +28,7 @@ impl Command for Shell { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() - .with_args(&self.runtime) + .with_args(&self.tool) .build(&mut config)?; if !config.is_activated() { err_inactive()?; diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 8c219dfcf..80eccef3a 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -12,14 +12,14 @@ use crate::ui::multi_progress_report::MultiProgressReport; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct Uninstall { - /// Runtime(s) to remove - #[clap(required = true, value_parser = RuntimeArgParser)] - runtime: Vec, + /// Tool(s) to remove + #[clap(required = true, value_parser = ToolArgParser)] + tool: Vec, } impl Command for Uninstall { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let runtimes = RuntimeArg::double_runtime_condition(&self.runtime); + let runtimes = ToolArg::double_tool_condition(&self.tool); let tool_versions = runtimes .iter() .map(|a| { diff --git a/src/cli/use.rs b/src/cli/use.rs index d5e0e0939..a979f0fec 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use color_eyre::eyre::Result; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::cli::local::local; use crate::config::{Config, MissingRuntimeBehavior}; @@ -23,8 +23,8 @@ pub struct Use { /// Tool(s) to add to config file /// e.g.: node@20 /// If no version is specified, it will default to @latest - #[clap(value_parser = RuntimeArgParser, verbatim_doc_comment, required_unless_present = "remove")] - tool: Vec, + #[clap(value_parser = ToolArgParser, verbatim_doc_comment, required_unless_present = "remove")] + tool: Vec, /// Save exact version to config file /// e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions @@ -58,7 +58,7 @@ impl Command for Use { .into_iter() .map(|r| match &r.tvr { Some(_) => r, - None => RuntimeArg::parse(&format!("{}@latest", r.plugin)), + None => ToolArg::parse(&format!("{}@latest", r.plugin)), }) .collect(); let path = match (self.global, self.path) { diff --git a/src/cli/where.rs b/src/cli/where.rs index de5687eac..09336fdd3 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Result; -use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; @@ -13,13 +13,13 @@ use crate::toolset::ToolsetBuilder; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Where { - /// Runtime(s) to look up + /// Tool(s) to look up /// e.g.: ruby@3 /// if "@" is specified, it will show the latest installed version /// that matches the prefix /// otherwise, it will show the current, active installed version - #[clap(required = true, value_parser = RuntimeArgParser, verbatim_doc_comment)] - runtime: RuntimeArg, + #[clap(required = true, value_parser = ToolArgParser, verbatim_doc_comment)] + tool: ToolArg, /// the version prefix to use when querying the latest version /// same as the first argument after the "@" @@ -30,23 +30,22 @@ pub struct Where { impl Command for Where { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let runtime = match self.runtime.tvr { + let runtime = match self.tool.tvr { None => match self.asdf_version { - Some(version) => self.runtime.with_version(&version), + Some(version) => self.tool.with_version(&version), None => { let ts = ToolsetBuilder::new() - .with_args(&[self.runtime.clone()]) + .with_args(&[self.tool.clone()]) .build(&mut config)?; let v = ts .versions - .get(&self.runtime.plugin) + .get(&self.tool.plugin) .and_then(|v| v.requests.first()) .map(|(r, _)| r.version()); - self.runtime - .with_version(&v.unwrap_or(String::from("latest"))) + self.tool.with_version(&v.unwrap_or(String::from("latest"))) } }, - _ => self.runtime, + _ => self.tool, }; let plugin = match config.tools.get(&runtime.plugin) { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 9af87c97d..52cf05a08 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -7,7 +7,7 @@ use color_eyre::eyre::{eyre, Result}; use tool_versions::ToolVersions; -use crate::cli::args::runtime::RuntimeArg; +use crate::cli::args::tool::ToolArg; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::settings::SettingsBuilder; use crate::config::{AliasMap, Config, Settings}; @@ -53,7 +53,7 @@ impl dyn ConfigFile { pub fn add_runtimes( &mut self, config: &mut Config, - runtimes: &[RuntimeArg], + runtimes: &[ToolArg], pin: bool, ) -> Result<()> { let mpr = MultiProgressReport::new(config.settings.verbose); @@ -99,10 +99,10 @@ impl dyn ConfigFile { Ok(()) } - /// this is for `rtx local|global RUNTIME` which will display the version instead of setting it - /// it's only valid to use a single runtime in this case - /// returns "true" if the runtime was displayed which means the CLI should exit - pub fn display_runtime(&self, out: &mut Output, runtimes: &[RuntimeArg]) -> Result { + /// this is for `rtx local|global TOOL` which will display the version instead of setting it + /// it's only valid to use a single tool in this case + /// returns "true" if the tool was displayed which means the CLI should exit + pub fn display_runtime(&self, out: &mut Output, runtimes: &[ToolArg]) -> Result { // in this situation we just print the current version in the config file if runtimes.len() == 1 && runtimes[0].tvr.is_none() { let plugin = &runtimes[0].plugin; @@ -126,7 +126,7 @@ impl dyn ConfigFile { } // check for something like `rtx local node python@latest` which is invalid if runtimes.iter().any(|r| r.tvr.is_none()) { - return Err(eyre!("invalid input, specify a version for each runtime. Or just specify one runtime to print the current version")); + return Err(eyre!("invalid input, specify a version for each tool. Or just specify one tool to print the current version")); } Ok(false) } diff --git a/src/shims.rs b/src/shims.rs index 33a9e6cbb..fb4d234e0 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -29,7 +29,7 @@ pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Res let mut args: Vec = args.iter().map(OsString::from).collect(); args[0] = which_shim(&mut config, bin_name)?.into(); let exec = Exec { - runtime: vec![], + tool: vec![], c: None, command: Some(args), cd: None, diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index a648c2cbd..7d7ad838c 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::Result; use itertools::Itertools; use std::collections::BTreeMap; -use crate::cli::args::runtime::RuntimeArg; +use crate::cli::args::tool::ToolArg; use crate::config::Config; use crate::env; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -10,7 +10,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; #[derive(Debug, Default)] pub struct ToolsetBuilder { - args: Vec, + args: Vec, install_missing: bool, latest_versions: bool, } @@ -20,7 +20,7 @@ impl ToolsetBuilder { Self::default() } - pub fn with_args(mut self, args: &[RuntimeArg]) -> Self { + pub fn with_args(mut self, args: &[ToolArg]) -> Self { self.args = args.to_vec(); self } @@ -80,7 +80,7 @@ fn load_runtime_env(ts: &mut Toolset, env: BTreeMap) { } } -fn load_runtime_args(ts: &mut Toolset, args: &[RuntimeArg]) { +fn load_runtime_args(ts: &mut Toolset, args: &[ToolArg]) { for (_, args) in args.iter().into_group_map_by(|arg| arg.plugin.clone()) { let mut arg_ts = Toolset::new(ToolSource::Argument); for arg in args { From 743cf4906b3c712476994655629519cd9e9e958a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 23 Apr 2023 11:23:14 -0500 Subject: [PATCH 0724/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7282bfaf6..f35c815a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1595,7 +1595,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.1" +version = "1.29.2" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index e8e93088c..bd280f589 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.1" +version = "1.29.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index eb4e1fcf3..df5ad6c75 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.1 +rtx 1.29.2 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -315,7 +315,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.1/rtx-v1.29.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.29.2/rtx-v1.29.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 4f74a3c98..ae1404546 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.1"; + version = "1.29.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 338193bab..8a0c0a9c6 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.1" +.TH rtx 1 "rtx 1.29.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.1 +v1.29.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 5051f07b9..c8b5cd5d5 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.1 +Version: 1.29.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 763b0c446218b93db391d9847f056f231dc93fb5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Apr 2023 09:22:18 -0500 Subject: [PATCH 0725/1891] set --verbose for node-build and python-build (#516) --- src/plugins/core/node.rs | 2 +- src/plugins/core/python.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index ab5f905b3..fe88938bd 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -232,7 +232,7 @@ impl Plugin for NodePlugin { ); cmd.arg("--compile"); } - if *RTX_NODE_VERBOSE_INSTALL { + if config.settings.verbose || *RTX_NODE_VERBOSE_INSTALL { cmd.arg("--verbose"); } cmd.arg(tv.install_path()); diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 50facff34..919f8e633 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -180,6 +180,9 @@ impl Plugin for PythonPlugin { cmd.with_pr(pr) .arg(tv.version.as_str()) .arg(tv.install_path()); + if config.settings.verbose { + cmd.arg("--verbose"); + } if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { pr.set_message(format!("with patch file from: {patch_url}")); cmd.arg("--patch"); From 87bf7e1947b389b69d070e4112b816db67f0a8ef Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:08:37 -0500 Subject: [PATCH 0726/1891] move calver date out a bit I need a bit more time to get some features in --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df5ad6c75..acbbac5f2 100644 --- a/README.md +++ b/README.md @@ -896,7 +896,7 @@ rtx is currently a new project and is under very rapid development. Slight behav occur between releases. Features marked as "experimental" may change significantly or be removed entirely. -Starting June 1, 2023\*, rtx will move to [Calver](https://calver.org/) versioning (`2023.6.1`). After the move to Calver, rtx's design will become mostly permanent and you will be able to rely on +Starting August 6, 2023\*, rtx will move to [Calver](https://calver.org/) versioning (`2023.6.1`). After the move to Calver, rtx's design will become mostly permanent and you will be able to rely on its behavior for the long term. Breaking changes will be few but when they do happen, they will be communicated in the CLI with plenty of notice whenever possible. From 59da1dac39327ac8468f1cf382b28f4a0dea209f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 05:10:56 -0500 Subject: [PATCH 0727/1891] chore(deps): bump clap from 4.2.4 to 4.2.5 (#519) --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f35c815a2..72ad1c185 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,9 +215,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.4" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ac1f6381d8d82ab4684768f89c0ea3afe66925ceadb4eeb3fc452ffc55d62" +checksum = "8a1f23fa97e1d1641371b51f35535cb26959b8e27ab50d167a8b996b5bada819" dependencies = [ "clap_builder", "clap_derive", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.2.4" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84080e799e54cff944f4b4a4b0e71630b0e0443b25b985175c7dddc1a859b749" +checksum = "0fdc5d93c358224b4d6867ef1356d740de2303e9892edc06c5340daeccd96bab" dependencies = [ "anstream", "anstyle", diff --git a/Cargo.toml b/Cargo.toml index bd280f589..11c487fb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ path = "src/main.rs" [dependencies] base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } -clap = { version = "4.2.2", features = ["env", "derive", "string"] } +clap = { version = "4.2.5", features = ["env", "derive", "string"] } clap_complete = "4.0.7" color-eyre = "0.6.2" color-print = "0.3.4" From cfede0cfcc9f70bbd54e376906363f448c1f7374 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 10:32:43 +0000 Subject: [PATCH 0728/1891] chore(deps): bump reqwest from 0.11.16 to 0.11.17 (#521) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72ad1c185..150edbc9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1513,9 +1513,9 @@ checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "reqwest" -version = "0.11.16" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" +checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" dependencies = [ "base64", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 11c487fb0..a4b808c48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ once_cell = "1.17.0" owo-colors = "3.5.0" rayon = "1.6.1" regex = "1.7.1" -reqwest = { version = "0.11.13", default-features = false, features = [ +reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", "rustls-tls", ] } From 2841119fa0c8bfee942f571b3a87b7d3c00bb9cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 10:47:59 +0000 Subject: [PATCH 0729/1891] chore(deps): bump flate2 from 1.0.25 to 1.0.26 (#520) --- Cargo.lock | 17 +++++++++++++---- Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 150edbc9e..d987071d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,7 +109,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.6.2", "object", "rustc-demangle", ] @@ -665,12 +665,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -1206,6 +1206,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.6" diff --git a/Cargo.toml b/Cargo.toml index a4b808c48..ee6073783 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ dirs-next = "2.0.0" dotenvy = "0.15.6" duct = "0.13.5" filetime = "0.2.19" -flate2 = "1.0.25" +flate2 = "1.0.26" fslock = "0.2.1" humantime = "2.1.0" indenter = "0.3.3" From 4f81e1fb0b13d4b3b0f2a449a9b11feaf4ebf5a3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 1 May 2023 10:16:37 -0500 Subject: [PATCH 0730/1891] added RTX_ALWAYS_KEEP_INSTALL setting (#523) --- README.md | 9 +++++++++ schema/rtx.json | 4 ++++ src/cli/settings/set.rs | 1 + ...tx__cli__settings__ls__tests__settings_ls.snap | 2 +- ...__cli__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + src/config/config_file/rtx_toml.rs | 3 +++ ...__config_file__rtx_toml__tests__fixture-2.snap | 1 + src/config/settings.rs | 15 ++++++++++++++- src/env.rs | 5 +++++ src/test.rs | 1 + src/tool.rs | 8 +++++--- test/config/config.toml | 1 + 13 files changed, 47 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index acbbac5f2..03de1c0cf 100644 --- a/README.md +++ b/README.md @@ -680,6 +680,7 @@ legacy_version_file = true # enabled by default (different than asdf) # configure `rtx install` to always keep the downloaded archive always_keep_download = false # deleted after install by default +always_keep_install = false # deleted on failure by default # configure how frequently (in minutes) to fetch updated plugin repository changes # this is updated whenever a new runtime is installed @@ -784,6 +785,14 @@ Output logs to a file. Same as `RTX_LOG_LEVEL` but for the log _file_ output level. This is useful if you want to store the logs but not have them litter your display. +#### `RTX_ALWAYS_KEEP_DOWNLOAD=1` + +Set to "1" to always keep the downloaded archive. By default it is deleted after install. + +#### `RTX_ALWAYS_KEEP_INSTALL=1` + +Set to "1" to always keep the install directory. By default it is deleted on failure. + #### `RTX_VERBOSE=1` This shows the installation output during `rtx install` and `rtx plugin install`. diff --git a/schema/rtx.json b/schema/rtx.json index 9e12a097d..ba036ae31 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -118,6 +118,10 @@ "description": "should rtx keep downloaded files after installation", "type": "boolean" }, + "always_keep_install": { + "description": "should rtx keep install files after installation even if the installation fails", + "type": "boolean" + }, "plugin_autoupdate_last_check_duration": { "oneOf": [ { diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 6454cdfe0..a8fdeebb4 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -23,6 +23,7 @@ impl Command for SettingsSet { "experimental" => parse_bool(&self.value)?, "missing_runtime_behavior" => self.value.into(), "always_keep_download" => parse_bool(&self.value)?, + "always_keep_install" => parse_bool(&self.value)?, "legacy_version_file" => parse_bool(&self.value)?, "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, "verbose" => parse_bool(&self.value)?, diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 26351523a..282d7596f 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -5,6 +5,7 @@ expression: stdout experimental = true missing_runtime_behavior = autoinstall always_keep_download = true +always_keep_install = true legacy_version_file = true plugin_autoupdate_last_check_duration = 20 trusted_config_paths = [] @@ -14,4 +15,3 @@ jobs = 2 disable_default_shorthands = false log_level = INFO raw = false - diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index d383e881f..8561baabc 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -5,6 +5,7 @@ expression: stdout experimental = true missing_runtime_behavior = autoinstall always_keep_download = true +always_keep_install = true legacy_version_file = false plugin_autoupdate_last_check_duration = 1 trusted_config_paths = [] diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 28ca801f3..36b94915d 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -46,6 +46,7 @@ mod tests { experimental = true missing_runtime_behavior = autoinstall always_keep_download = true + always_keep_install = true legacy_version_file = true plugin_autoupdate_last_check_duration = 20 trusted_config_paths = [] diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index ff16f3c37..79b2c8a33 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -393,6 +393,9 @@ impl RtxToml { "always_keep_download" => { settings.always_keep_download = Some(self.parse_bool(&k, v)?) } + "always_keep_install" => { + settings.always_keep_install = Some(self.parse_bool(&k, v)?) + } "plugin_autoupdate_last_check_duration" => { settings.plugin_autoupdate_last_check_duration = Some(self.parse_duration_minutes(&k, v)?) diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index bcd8cea0f..3e6b9dba4 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -8,6 +8,7 @@ SettingsBuilder { Warn, ), always_keep_download: None, + always_keep_install: None, legacy_version_file: None, plugin_autoupdate_last_check_duration: None, trusted_config_paths: [], diff --git a/src/config/settings.rs b/src/config/settings.rs index 713dd9fff..43b061f79 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -13,6 +13,7 @@ pub struct Settings { pub experimental: bool, pub missing_runtime_behavior: MissingRuntimeBehavior, pub always_keep_download: bool, + pub always_keep_install: bool, pub legacy_version_file: bool, pub plugin_autoupdate_last_check_duration: Duration, pub trusted_config_paths: Vec, @@ -30,7 +31,8 @@ impl Default for Settings { Self { experimental: *RTX_EXPERIMENTAL, missing_runtime_behavior: MissingRuntimeBehavior::Warn, - always_keep_download: false, + always_keep_download: *RTX_ALWAYS_KEEP_DOWNLOAD, + always_keep_install: *RTX_ALWAYS_KEEP_INSTALL, legacy_version_file: true, plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), trusted_config_paths: RTX_TRUSTED_CONFIG_PATHS.clone(), @@ -57,6 +59,10 @@ impl Settings { "always_keep_download".to_string(), self.always_keep_download.to_string(), ); + map.insert( + "always_keep_install".to_string(), + self.always_keep_install.to_string(), + ); map.insert( "legacy_version_file".to_string(), self.legacy_version_file.to_string(), @@ -93,6 +99,7 @@ pub struct SettingsBuilder { pub experimental: Option, pub missing_runtime_behavior: Option, pub always_keep_download: Option, + pub always_keep_install: Option, pub legacy_version_file: Option, pub plugin_autoupdate_last_check_duration: Option, pub trusted_config_paths: Vec, @@ -122,6 +129,9 @@ impl SettingsBuilder { if other.always_keep_download.is_some() { self.always_keep_download = other.always_keep_download; } + if other.always_keep_install.is_some() { + self.always_keep_install = other.always_keep_install; + } if other.legacy_version_file.is_some() { self.legacy_version_file = other.legacy_version_file; } @@ -174,6 +184,9 @@ impl SettingsBuilder { settings.always_keep_download = self .always_keep_download .unwrap_or(settings.always_keep_download); + settings.always_keep_install = self + .always_keep_install + .unwrap_or(settings.always_keep_install); settings.legacy_version_file = self .legacy_version_file .unwrap_or(settings.legacy_version_file); diff --git a/src/env.rs b/src/env.rs index 082b4dea5..e212297f2 100644 --- a/src/env.rs +++ b/src/env.rs @@ -85,6 +85,11 @@ pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { .map(|v| split_paths(&v).collect()) .unwrap_or_default() }); +pub static RTX_ALWAYS_KEEP_DOWNLOAD: Lazy = + Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_DOWNLOAD")); +pub static RTX_ALWAYS_KEEP_INSTALL: Lazy = + Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_INSTALL")); + #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); diff --git a/src/test.rs b/src/test.rs index 25a7c2b5b..00ac89376 100644 --- a/src/test.rs +++ b/src/test.rs @@ -56,6 +56,7 @@ pub fn reset_config() { verbose = true missing_runtime_behavior= 'autoinstall' always_keep_download= true + always_keep_install= true legacy_version_file= true plugin_autoupdate_last_check_duration = 20 jobs = 2 diff --git a/src/tool.rs b/src/tool.rs index 25445ca63..efb7bedfe 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -307,11 +307,13 @@ impl Tool { Ok(()) } fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { - let _ = remove_all_with_warning(tv.install_path()); - self.cleanup_install_dirs(settings, tv); + if !settings.always_keep_install { + let _ = remove_all_with_warning(tv.install_path()); + self.cleanup_install_dirs(settings, tv); + } } fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { - if !settings.always_keep_download { + if !settings.always_keep_download && !settings.always_keep_install { let _ = remove_all_with_warning(tv.download_path()); } } diff --git a/test/config/config.toml b/test/config/config.toml index 32102d216..8006d1f52 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -3,6 +3,7 @@ experimental = true verbose = true missing_runtime_behavior= 'autoinstall' always_keep_download= true +always_keep_install= true legacy_version_file= true plugin_autoupdate_last_check_duration = 20 jobs = 2 From d3e5e414b4b44b9e4445938b11eb0360fbe31bc8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 1 May 2023 10:35:36 -0500 Subject: [PATCH 0731/1891] fix npm shim for node-14 (#524) * added RTX_ALWAYS_KEEP_INSTALL setting * fix npm shim for node-14 Fixes #522 --- src/file.rs | 7 +++++++ src/plugins/core/assets/node_npm_shim | 7 +++---- src/plugins/core/node.rs | 4 +++- src/shims.rs | 5 +---- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/file.rs b/src/file.rs index e448d4adf..ce5565c98 100644 --- a/src/file.rs +++ b/src/file.rs @@ -140,6 +140,13 @@ pub fn is_executable(path: &Path) -> bool { false } +pub fn make_executable(path: &Path) -> Result<()> { + let mut perms = path.metadata()?.permissions(); + perms.set_mode(perms.mode() | 0o111); + fs::set_permissions(path, perms)?; + Ok(()) +} + pub struct FindUp { current_dir: PathBuf, current_dir_filenames: Vec, diff --git a/src/plugins/core/assets/node_npm_shim b/src/plugins/core/assets/node_npm_shim index 51a4f300e..e3a0f1af2 100755 --- a/src/plugins/core/assets/node_npm_shim +++ b/src/plugins/core/assets/node_npm_shim @@ -68,14 +68,13 @@ should_reshim() { } wrap_npm_if_reshim_is_needed() { - local npm_cli="$plugin_dir/lib/node_modules/npm/lib/cli.js" - local npm_command="require('$npm_cli')(process)" + local npm_cli="$plugin_dir/lib/node_modules/npm/bin/npm-cli.js" if should_reshim "$@"; then - node -e "$npm_command" npm "$@" + node "$npm_cli" "$@" printf "Reshimming rtx %s...\n" "$plugin_name" >&2 rtx reshim else - exec node -e "$npm_command" npm "$@" + exec node "$npm_cli" "$@" fi } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index fe88938bd..dd7d1a988 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -17,7 +17,7 @@ use crate::lock_file::LockFile; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; -use crate::{cmd, dirs, env}; +use crate::{cmd, dirs, env, file}; #[derive(Debug)] pub struct NodePlugin { @@ -138,7 +138,9 @@ impl NodePlugin { } fn install_npm_shim(&self, tv: &ToolVersion) -> Result<()> { + fs::remove_file(self.npm_path(tv)).ok(); fs::write(self.npm_path(tv), include_str!("assets/node_npm_shim"))?; + file::make_executable(&self.npm_path(tv))?; Ok(()) } diff --git a/src/shims.rs b/src/shims.rs index fb4d234e0..ff05738f0 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -1,6 +1,5 @@ use std::ffi::OsString; use std::fs; -use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; use std::process::exit; @@ -145,9 +144,7 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { fake_asdf_dir = fake_asdf::setup()?.display(), target = target.display()}, )?; - let mut perms = shim.metadata()?.permissions(); - perms.set_mode(0o755); - fs::set_permissions(shim, perms)?; + file::make_executable(shim)?; trace!( "shim created from {} to {}", target.display(), From aecd3c3cb6a63029d5e15475b3677437af3809e0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 1 May 2023 10:36:58 -0500 Subject: [PATCH 0732/1891] chore: Release --- Cargo.lock | 52 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d987071d2..297dc0c07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" dependencies = [ "anstyle", "anstyle-parse", @@ -85,9 +85,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -1130,9 +1130,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" dependencies = [ "cc", "libc", @@ -1157,9 +1157,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" +checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" [[package]] name = "log" @@ -1347,9 +1347,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.7" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122" +checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70" dependencies = [ "thiserror", "ucd-trie", @@ -1357,9 +1357,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.7" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be99c4c1d2fc2769b1d00239431d711d08f6efedcecb8b6e30707160aee99c15" +checksum = "6b79d4c71c865a25a4322296122e3924d30bc8ee0834c8bfc8b95f7f054afbfb" dependencies = [ "pest", "pest_generator", @@ -1367,9 +1367,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.7" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56094789873daa36164de2e822b3888c6ae4b4f9da555a1103587658c805b1e" +checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e" dependencies = [ "pest", "pest_meta", @@ -1380,9 +1380,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.7" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6733073c7cff3d8459fda0e42f13a047870242aed8b509fe98000928975f359e" +checksum = "745a452f8eb71e39ffd8ee32b3c5f51d03845f99786fa9b68db6ff509c505411" dependencies = [ "once_cell", "pest", @@ -1604,7 +1604,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.2" +version = "1.29.3" dependencies = [ "base64", "built", @@ -1663,9 +1663,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.14" +version = "0.37.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b864d3c18a5785a05953adeed93e2dca37ed30f18e69bba9f30079d51f363f" +checksum = "8bbfc1d1c7c40c01715f47d71444744a81669ca84e8b63e25a55e169b1f86433" dependencies = [ "bitflags", "errno 0.3.1", @@ -2054,9 +2054,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" dependencies = [ "autocfg", "bytes", @@ -2065,7 +2065,7 @@ dependencies = [ "num_cpus", "pin-project-lite", "socket2", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2081,9 +2081,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -2652,9 +2652,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "5617da7e1f97bf363947d767b91aaf3c2bbc19db7fda9c65af1278713d58e0a2" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index ee6073783..340ca65b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.2" +version = "1.29.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 03de1c0cf..db66e288e 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.2 +rtx 1.29.3 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -315,7 +315,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.2/rtx-v1.29.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.29.3/rtx-v1.29.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ae1404546..bb784bc70 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.2"; + version = "1.29.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 8a0c0a9c6..f34b58762 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.2" +.TH rtx 1 "rtx 1.29.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.2 +v1.29.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c8b5cd5d5..729db3358 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.2 +Version: 1.29.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From e9d74c1c1d93f7cc4c17f004521939922158842b Mon Sep 17 00:00:00 2001 From: Thomas Buckley-Houston Date: Sat, 6 May 2023 17:26:10 +0000 Subject: [PATCH 0733/1891] ci: Add AUR rtx-bin package (#529) TODO: Would be good to refactor the code shared with the original `rtx` package scripts. --- .github/workflows/rtx.yml | 3 ++ scripts/release-aur-bin.sh | 64 ++++++++++++++++++++++++++++++++++++++ scripts/release-aur.sh | 2 +- 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100755 scripts/release-aur-bin.sh diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 729a7dc99..6db380e29 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -272,6 +272,9 @@ jobs: - name: Release to aur run: scripts/release-aur.sh working-directory: rtx + - name: Release aur-bin + run: scripts/release-aur-bin.sh + working-directory: rtx bump-homebrew-formula: runs-on: macos-latest if: startsWith(github.event.ref, 'refs/tags/v') diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh new file mode 100755 index 000000000..38341a6a8 --- /dev/null +++ b/scripts/release-aur-bin.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -euxo pipefail + +RTX_VERSION=$(./scripts/get-version.sh) + +SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') + +if [ ! -d aur-bin ]; then + git clone ssh://aur@aur.archlinux.org/rtx-bin.git aur-bin +fi +git -C aur-bin pull + +cat >aur/PKGBUILD < + +pkgname=rtx-bin +pkgver=${RTX_VERSION#v*} +pkgrel=1 +pkgdesc='Polyglot runtime manager' +arch=('x86_64') +url='https://github.com/jdxcode/rtx' +license=('MIT') +makedepends=('cargo') +provides=('rtx') +conflicts=('rtx') +options=('!lto') +source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdxcode/\$pkgname/archive/v\$pkgver.tar.gz") +sha512sums=('$SHA512') + +prepare() { + tar -xzf rtx-v\$pkgver-linux-x64.tar.gz +} + +package() { + cd "\$srcdir/" + install -Dm755 rtx/bin/rtx "\$pkgdir/usr/bin/rtx" + install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" +} + +check() { + "\$srcdir/rtx/bin/rtx" --version +} +EOF + +cat >aur/.SRCINFO < Date: Sat, 6 May 2023 12:27:54 -0500 Subject: [PATCH 0734/1891] chore: Release --- Cargo.lock | 50 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 297dc0c07..f08376941 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,9 +215,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.5" +version = "4.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a1f23fa97e1d1641371b51f35535cb26959b8e27ab50d167a8b996b5bada819" +checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938" dependencies = [ "clap_builder", "clap_derive", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.2.5" +version = "4.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdc5d93c358224b4d6867ef1356d740de2303e9892edc06c5340daeccd96bab" +checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" dependencies = [ "anstream", "anstyle", @@ -1112,9 +1112,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024" [[package]] name = "libgit2-sys" @@ -1157,9 +1157,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" [[package]] name = "log" @@ -1403,9 +1403,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" @@ -1604,7 +1604,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.3" +version = "1.29.4" dependencies = [ "base64", "built", @@ -1663,9 +1663,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.18" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbfc1d1c7c40c01715f47d71444744a81669ca84e8b63e25a55e169b1f86433" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ "bitflags", "errno 0.3.1", @@ -1762,18 +1762,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.160" +version = "1.0.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" dependencies = [ "proc-macro2", "quote", @@ -2010,9 +2010,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" dependencies = [ "itoa", "libc", @@ -2024,15 +2024,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" dependencies = [ "time-core", ] @@ -2652,9 +2652,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5617da7e1f97bf363947d767b91aaf3c2bbc19db7fda9c65af1278713d58e0a2" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 340ca65b1..5069708f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.3" +version = "1.29.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index db66e288e..71c6dcd2d 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.3 +rtx 1.29.4 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -315,7 +315,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.3/rtx-v1.29.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.29.4/rtx-v1.29.4-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index bb784bc70..ea7dbf4ab 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.3"; + version = "1.29.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index f34b58762..43658109f 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.3" +.TH rtx 1 "rtx 1.29.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.3 +v1.29.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 729db3358..ea44e878f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.3 +Version: 1.29.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 06a8d33710043b3492112afa763b1b3c85b3c1bc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 6 May 2023 13:07:22 -0500 Subject: [PATCH 0735/1891] fix aur-bin script directory --- scripts/release-aur-bin.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 38341a6a8..022a07c71 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -10,7 +10,7 @@ if [ ! -d aur-bin ]; then fi git -C aur-bin pull -cat >aur/PKGBUILD <aur-bin/PKGBUILD < pkgname=rtx-bin @@ -42,7 +42,7 @@ check() { } EOF -cat >aur/.SRCINFO <aur-bin/.SRCINFO < Date: Sat, 6 May 2023 13:11:59 -0500 Subject: [PATCH 0736/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f08376941..c875fb901 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1604,7 +1604,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.4" +version = "1.29.5" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 5069708f9..7ce5c0cc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.4" +version = "1.29.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 71c6dcd2d..26eddf598 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.4 +rtx 1.29.5 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -315,7 +315,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.4/rtx-v1.29.4-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.29.5/rtx-v1.29.5-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ea7dbf4ab..9415c15d8 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.4"; + version = "1.29.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 43658109f..6cb698496 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.4" +.TH rtx 1 "rtx 1.29.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.4 +v1.29.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ea44e878f..970241a9f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.4 +Version: 1.29.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 757cdc9db66ae88c54d43d3c428914f8f717554c Mon Sep 17 00:00:00 2001 From: Thomas Buckley-Houston Date: Sun, 7 May 2023 13:29:35 +0000 Subject: [PATCH 0737/1891] ci: Fix AUR rtx-bin .SRCINFO pkgbase (#531) Fixing an error after the first ever attempt at automated release: https://github.com/jdxcode/rtx/actions/runs/4902977788/jobs/8755243840 Error was: ``` + git push remote: error: invalid pkgbase: rtx, expected rtx-bin remote: error: hook declined to update refs/heads/master ``` --- scripts/release-aur-bin.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 022a07c71..4da2d33bf 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -20,7 +20,6 @@ pkgdesc='Polyglot runtime manager' arch=('x86_64') url='https://github.com/jdxcode/rtx' license=('MIT') -makedepends=('cargo') provides=('rtx') conflicts=('rtx') options=('!lto') @@ -43,7 +42,7 @@ check() { EOF cat >aur-bin/.SRCINFO < Date: Sun, 7 May 2023 10:00:39 -0500 Subject: [PATCH 0738/1891] fix ref:master versions (#532) Before, this was sending "ref:master" to the plugin which was wrong. Fixes https://github.com/jdxcode/rtx/issues/527 --- e2e/test_neovim | 8 ++++++++ src/plugins/external_plugin.rs | 8 ++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100755 e2e/test_neovim diff --git a/e2e/test_neovim b/e2e/test_neovim new file mode 100755 index 000000000..58f8981ab --- /dev/null +++ b/e2e/test_neovim @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +# TODO: fix this in github actions CI +exit 0 +rtx i neovim@ref:master +assert_contains "rtx x neovim@ref:master -- nvim --version" "NVIM v0." diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 66be1d541..8bcf30b15 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -247,6 +247,10 @@ impl ExternalPlugin { panic!("should not be called for system tool") } }; + let install_version = match &tv.request { + ToolVersionRequest::Ref(_, v) => v, // should not have "ref:" prefix + _ => &tv.version, + }; sm = sm .with_env( "RTX_INSTALL_PATH", @@ -266,8 +270,8 @@ impl ExternalPlugin { ) .with_env("RTX_INSTALL_TYPE", install_type) .with_env("ASDF_INSTALL_TYPE", install_type) - .with_env("RTX_INSTALL_VERSION", tv.version.clone()) - .with_env("ASDF_INSTALL_VERSION", tv.version.clone()); + .with_env("RTX_INSTALL_VERSION", install_version) + .with_env("ASDF_INSTALL_VERSION", install_version); sm } } From 4cc6478c818f18a06cae51b21602ffab8f84a6ab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 7 May 2023 10:50:45 -0500 Subject: [PATCH 0739/1891] chore: Release --- Cargo.lock | 17 +++++++++++++---- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c875fb901..026893cb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1009,7 +1009,7 @@ checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" dependencies = [ "console", "number_prefix", - "portable-atomic", + "portable-atomic 0.3.20", "unicode-segmentation", "unicode-width", ] @@ -1409,9 +1409,18 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" +checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" +dependencies = [ + "portable-atomic 1.3.1", +] + +[[package]] +name = "portable-atomic" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bbda379e6e462c97ea6afe9f6233619b202bbc4968d7caa6917788d2070a044" [[package]] name = "pretty_assertions" @@ -1604,7 +1613,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.5" +version = "1.29.6" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 7ce5c0cc7..a7f86709d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.5" +version = "1.29.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 26eddf598..67794ade4 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.5 +rtx 1.29.6 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -315,7 +315,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.5/rtx-v1.29.5-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.29.6/rtx-v1.29.6-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 9415c15d8..5da88af15 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.5"; + version = "1.29.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 6cb698496..23cf27252 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.5" +.TH rtx 1 "rtx 1.29.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.5 +v1.29.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 970241a9f..f4b18b85c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.5 +Version: 1.29.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From c56c1fa11dc4d248afbdca5f08df14f637b71e22 Mon Sep 17 00:00:00 2001 From: Thomas Buckley-Houston Date: Mon, 8 May 2023 17:05:43 +0000 Subject: [PATCH 0740/1891] ci: AUR rtx-bin use prebuilt binary download URI (#535) I actually ran this locally to test it pushing an update to teh AUR package repo. So this should actually finally work. --- scripts/release-aur-bin.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 4da2d33bf..f2f7d2bce 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -3,7 +3,9 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') +TAR_GZ_URI="https://github.com/jdxcode/rtx/releases/download/${RTX_VERSION}/rtx-${RTX_VERSION}-linux-x64.tar.gz" + +SHA512=$(curl -L "$TAR_GZ_URI" | sha512sum | awk '{print $1}') if [ ! -d aur-bin ]; then git clone ssh://aur@aur.archlinux.org/rtx-bin.git aur-bin @@ -23,11 +25,11 @@ license=('MIT') provides=('rtx') conflicts=('rtx') options=('!lto') -source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdxcode/\$pkgname/archive/v\$pkgver.tar.gz") +source=("rtx-\$pkgver.tar.gz::${TAR_GZ_URI}") sha512sums=('$SHA512') prepare() { - tar -xzf rtx-v\$pkgver-linux-x64.tar.gz + tar -xzf rtx-\$pkgver.tar.gz } package() { @@ -51,7 +53,7 @@ pkgbase = rtx-bin license = MIT provides = rtx conflicts = rtx - source = rtx-${RTX_VERSION#v*}.tar.gz::https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz + source = rtx-${RTX_VERSION#v*}.tar.gz::${TAR_GZ_URI} sha512sums = $SHA512 pkgname = rtx-bin From 5853b4f1d31bb7c282ef41be4f0c9455653f92b4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 10 May 2023 11:13:56 -0500 Subject: [PATCH 0741/1891] support .node-version files with "v" prefix (#538) This worked in rtx-nodejs, but was missing in the core plugin Fixes #537 --- e2e/.node-version | 2 +- e2e/config/.node-version | 2 +- .../rtx__cli__alias__set__tests__alias_set.snap | 8 ++++++++ ...x__cli__alias__unset__tests__alias_unset.snap | 8 ++++++++ src/plugins/core/node.rs | 16 +++++++++++++++- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/e2e/.node-version b/e2e/.node-version index e88320d7c..2a59cf43b 100644 --- a/e2e/.node-version +++ b/e2e/.node-version @@ -1 +1 @@ -20.0.0 +v20.0.0 diff --git a/e2e/config/.node-version b/e2e/config/.node-version index e88320d7c..2a59cf43b 100644 --- a/e2e/config/.node-version +++ b/e2e/config/.node-version @@ -1 +1 @@ -20.0.0 +v20.0.0 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index c54a67ed2..7daa3312f 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -3,6 +3,14 @@ source: src/cli/alias/set.rs expression: output --- node lts 18 +node lts-argon 4 +node lts-boron 6 +node lts-carbon 8 +node lts-dubnium 10 +node lts-erbium 12 +node lts-fermium 14 +node lts-gallium 16 +node lts-hydrogen 18 node lts/argon 4 node lts/boron 6 node lts/carbon 8 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index 726ffd8eb..8b788f467 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -3,6 +3,14 @@ source: src/cli/alias/unset.rs expression: output --- node lts 18 +node lts-argon 4 +node lts-boron 6 +node lts-carbon 8 +node lts-dubnium 10 +node lts-erbium 12 +node lts-fermium 14 +node lts-gallium 16 +node lts-hydrogen 18 node lts/argon 4 node lts/boron 6 node lts/carbon 8 diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index dd7d1a988..c9efa6c6a 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::env::{join_paths, split_paths}; use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; @@ -181,6 +181,14 @@ impl Plugin for NodePlugin { ("lts/fermium", "14"), ("lts/gallium", "16"), ("lts/hydrogen", "18"), + ("lts-argon", "4"), + ("lts-boron", "6"), + ("lts-carbon", "8"), + ("lts-dubnium", "10"), + ("lts-erbium", "12"), + ("lts-fermium", "14"), + ("lts-gallium", "16"), + ("lts-hydrogen", "18"), ("lts", "18"), ] .into_iter() @@ -245,4 +253,10 @@ impl Plugin for NodePlugin { self.install_default_packages(&config.settings, tv, pr)?; Ok(()) } + + fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + let body = fs::read_to_string(path)?; + // trim "v" prefix + Ok(body.trim().strip_prefix('v').unwrap_or(&body).to_string()) + } } From a540ac6d353ad22828bf554f52abc4a593e3fbce Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 10 May 2023 11:15:20 -0500 Subject: [PATCH 0742/1891] chore: Release --- Cargo.lock | 64 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +-- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 026893cb4..1bfa865d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.1" +version = "3.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" [[package]] name = "byteorder" @@ -239,9 +239,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a19591b2ab0e3c04b588a0e04ddde7b9eaa423646d1b4a8092879216bf47473" +checksum = "36774babb166352bb4f7b9cb16f781ffa3439d2a8f12cd31bea85a38c888fea3" dependencies = [ "clap", ] @@ -1097,9 +1097,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" dependencies = [ "wasm-bindgen", ] @@ -1112,9 +1112,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.143" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libgit2-sys" @@ -1413,14 +1413,14 @@ version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" dependencies = [ - "portable-atomic 1.3.1", + "portable-atomic 1.3.2", ] [[package]] name = "portable-atomic" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbda379e6e462c97ea6afe9f6233619b202bbc4968d7caa6917788d2070a044" +checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5" [[package]] name = "pretty_assertions" @@ -1454,9 +1454,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] @@ -1613,7 +1613,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.6" +version = "1.29.7" dependencies = [ "base64", "built", @@ -2063,9 +2063,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" dependencies = [ "autocfg", "bytes", @@ -2379,9 +2379,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2389,24 +2389,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.15", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "083abe15c5d88556b77bdf7aef403625be9e327ad37c62c4e4129af740168163" dependencies = [ "cfg-if", "js-sys", @@ -2416,9 +2416,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2426,28 +2426,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.15", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index a7f86709d..584564388 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.6" +version = "1.29.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 67794ade4..5497563d0 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.6 +rtx 1.29.7 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -315,7 +315,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.6/rtx-v1.29.6-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.29.7/rtx-v1.29.7-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 5da88af15..3e8c1a182 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.6"; + version = "1.29.7"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 23cf27252..a1a17e8b4 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.6" +.TH rtx 1 "rtx 1.29.7" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -139,6 +139,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.6 +v1.29.7 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f4b18b85c..18fa73fa5 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.6 +Version: 1.29.7 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 09aa9e836b727ecbcf1a910c431ad762fe79d3d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 06:30:20 -0500 Subject: [PATCH 0743/1891] chore(deps): bump versions from 4.1.0 to 5.0.0 (#543) Bumps [versions](https://github.com/fosskers/rs-versions) from 4.1.0 to 5.0.0. - [Release notes](https://github.com/fosskers/rs-versions/releases) - [Changelog](https://github.com/fosskers/rs-versions/blob/master/CHANGELOG.md) - [Commits](https://github.com/fosskers/rs-versions/compare/v4.1.0...v5.0.0) --- updated-dependencies: - dependency-name: versions dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bfa865d9..3b4e98b62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2343,9 +2343,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "versions" -version = "4.1.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee97e1d97bd593fb513912a07691b742361b3dd64ad56f2c694ea2dbfe0665d3" +checksum = "32feb3eb91e495efe5b6b2e3ca9d78db603043434a3a398a84b47de28abb2d02" dependencies = [ "itertools", "nom", diff --git a/Cargo.toml b/Cargo.toml index 584564388..9de9e7f44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ thiserror = "1.0.38" toml = "<0.8" toml_edit = "<0.20" url = "2.3.1" -versions = "4.1.0" +versions = "5.0.0" [target.'cfg(unix)'.dependencies] exec = "0.3.1" From cb84ae400a7817ed5d68153ec9955827cff3c3fe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 10:07:25 -0500 Subject: [PATCH 0744/1891] rename .default-node-packages -> .default-npm-packages (#550) --- docs/node.md | 4 ++-- e2e/{.default-node-packages => .default-npm-packages} | 0 e2e/test_nodejs | 2 +- src/env.rs | 7 ++++++- 4 files changed, 9 insertions(+), 4 deletions(-) rename e2e/{.default-node-packages => .default-npm-packages} (100%) diff --git a/docs/node.md b/docs/node.md index 27771c58a..be2055119 100644 --- a/docs/node.md +++ b/docs/node.md @@ -36,13 +36,13 @@ $ node.11 -V - `RTX_NODE_VERBOSE_INSTALL`: Enables verbose output for downloading and building. - `RTX_NODE_FORCE_COMPILE`: Forces compilation from source instead of preferring pre-compiled binaries - `RTX_NODE_CONCURRENCY`: How many jobs should be used in compilation. Defaults to half the computer cores -- `RTX_NODE_DEFAULT_PACKAGES_FILE`: location of default packages file, defaults to `$HOME/.default-node-packages` +- `RTX_NODE_DEFAULT_PACKAGES_FILE`: location of default packages file, defaults to `$HOME/.default-npm-packages` - `NODEJS_ORG_MIRROR`: (Legacy) overrides the default mirror used for downloading the distibutions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var ## Default node packages -rtx-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-node-packages` file that lists one package per line, for example: +rtx-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-npm-packages` file that lists one package per line, for example: ``` lodash diff --git a/e2e/.default-node-packages b/e2e/.default-npm-packages similarity index 100% rename from e2e/.default-node-packages rename to e2e/.default-npm-packages diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 91dfdeecc..d30861b2f 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -3,7 +3,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 -export RTX_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-node-packages" +export RTX_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-npm-packages" rtx plugin uninstall node rtx i node node@lts/hydrogen diff --git a/src/env.rs b/src/env.rs index e212297f2..a7bd1fdef 100644 --- a/src/env.rs +++ b/src/env.rs @@ -116,11 +116,16 @@ pub static RTX_NODE_VERBOSE_INSTALL: Lazy = pub static RTX_NODE_FORCE_COMPILE: Lazy = Lazy::new(|| var_is_true("RTX_NODE_FORCE_COMPILE")); pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { + // post-calver we can probably remove these checks let p = HOME.join(".default-nodejs-packages"); if p.exists() { return p; } - HOME.join(".default-node-packages") + let p = HOME.join(".default-node-packages"); + if p.exists() { + return p; + } + HOME.join(".default-npm-packages") }) }); From 5d3aaa7a466df021b87c463e6cd4ba66128636b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 15:30:12 +0000 Subject: [PATCH 0745/1891] chore(deps): bump clap_complete from 4.2.2 to 4.2.3 (#541) Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.2.2 to 4.2.3. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.2.2...clap_complete-v4.2.3) --- updated-dependencies: - dependency-name: clap_complete dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b4e98b62..723cb4a4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,9 +239,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36774babb166352bb4f7b9cb16f781ffa3439d2a8f12cd31bea85a38c888fea3" +checksum = "1594fe2312ec4abf402076e407628f5c313e54c32ade058521df4ee34ecac8a8" dependencies = [ "clap", ] diff --git a/Cargo.toml b/Cargo.toml index 9de9e7f44..0ac074f04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ path = "src/main.rs" base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } clap = { version = "4.2.5", features = ["env", "derive", "string"] } -clap_complete = "4.0.7" +clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" console = "0.15.2" From 30147713c779d604f3d6ff77173e6d9a84fbfe90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 15:49:03 +0000 Subject: [PATCH 0746/1891] chore(deps): bump serde from 1.0.162 to 1.0.163 (#542) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.162 to 1.0.163. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.162...v1.0.163) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 723cb4a4d..f2c79f23e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1771,18 +1771,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0ac074f04..abd7214e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ rmp-serde = "1.1.1" self_update = { version = "0.36.0", default-features = false, optional = true, features = [ "rustls", ] } -serde = "1.0.152" +serde = "1.0.163" serde_derive = "1.0.152" serde_json = "1.0.87" shell-escape = "0.1.4" From 22b8f225c6006bfa59346ec6208a06616eceba01 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 11:04:55 -0500 Subject: [PATCH 0747/1891] colorize tool in progress bar (#552) --- src/tool.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tool.rs b/src/tool.rs index efb7bedfe..f9a1be124 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -156,13 +156,14 @@ impl Tool { pub fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { pr.set_style(PROG_TEMPLATE.clone()); + let tool = match tv { + Some(tv) => tv.to_string(), + None => self.name.to_string(), + }; pr.set_prefix(format!( "{} {} ", style("rtx").dim().for_stderr(), - match tv { - Some(tv) => tv.to_string(), - None => self.name.to_string(), - } + style(tool).cyan().for_stderr(), )); pr.enable_steady_tick(); } From bcf376101841404e2a4656eb45bc5862b275276c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 11:58:26 -0500 Subject: [PATCH 0748/1891] added "about" help to external commands (#553) This should make it more clear what the topics/commands are. I also renamed nodebuild -> node-build in the core plugin which hopefully will not be too big of a problem --- docs/node.md | 4 +-- e2e/test_nodejs | 9 ++++++- src/cli/external.rs | 18 ++----------- src/plugins/core/node.rs | 29 +++++++++++++++++--- src/plugins/external_plugin.rs | 48 +++++++++++++++++++++++++--------- src/plugins/mod.rs | 10 +++++-- src/plugins/script_manager.rs | 8 +++++- src/tool.rs | 12 ++++++--- 8 files changed, 97 insertions(+), 41 deletions(-) diff --git a/docs/node.md b/docs/node.md index be2055119..6a3ac87f3 100644 --- a/docs/node.md +++ b/docs/node.md @@ -62,7 +62,7 @@ rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between softw We provide a command for running the installed `node-build` command: ```bash -rtx node nodebuild --version +rtx node node-build --version ``` ### node-build advanced variations @@ -75,7 +75,7 @@ Some of them will work out of the box, and some will need a bit of investigation To list all the available variations run: ```bash -rtx node nodebuild --definitions +rtx node node-build --definitions ``` _Note that this command only lists the current `node-build` definitions. You might want to [update the local `node-build` repository](#updating-node-build-definitions) before listing them._ diff --git a/e2e/test_nodejs b/e2e/test_nodejs index d30861b2f..3d16da6b1 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -9,4 +9,11 @@ rtx plugin uninstall node rtx i node node@lts/hydrogen assert_contains "rtx x node@lts/hydrogen -- node --version" "v18." assert "rtx x -- node --version" "v20.0.0" -assert_contains "rtx node nodebuild --version" "node-build " +assert_contains "rtx node node-build --version" "node-build " + +# test rtx-nodejs +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 diff --git a/src/cli/external.rs b/src/cli/external.rs index a768e40d2..59f9175f3 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -11,7 +11,7 @@ pub fn commands(config: &Config) -> Vec { .values() .collect_vec() .into_par_iter() - .map(|p| match p.external_commands() { + .flat_map(|p| match p.external_commands() { Ok(commands) => commands, Err(e) => { warn!( @@ -21,20 +21,6 @@ pub fn commands(config: &Config) -> Vec { vec![] } }) - .collect::>>>() - .into_iter() - .filter(|commands| !commands.is_empty()) - .filter(|commands| commands[0][0] != "direnv") - .map(|commands| { - Command::new(commands[0][0].to_string()).subcommands(commands.into_iter().map(|cmd| { - Command::new(cmd[1..].join("-")).arg( - clap::Arg::new("args") - .num_args(1..) - .allow_hyphen_values(true) - .trailing_var_arg(true), - ) - })) - }) .collect() } @@ -52,7 +38,7 @@ pub fn execute( .unwrap_or_default() .map(|s| s.to_string_lossy().to_string()) .collect(); - plugin.execute_external_command(subcommand, args)?; + plugin.execute_external_command(config, subcommand, args)?; } } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index c9efa6c6a..defaa48d9 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; +use clap::Command; use color_eyre::eyre::Result; use crate::cache::CacheManager; @@ -205,13 +206,33 @@ impl Plugin for NodePlugin { } } - fn external_commands(&self) -> Result>> { - Ok(vec![vec![self.name.clone(), "nodebuild".into()]]) + fn external_commands(&self) -> Result> { + if self.legacy_file_support { + // sort of a hack to get this not to display for nodejs + let topic = Command::new("node") + .about("Commands for the node plugin") + .subcommands(vec![Command::new("node-build") + .about("Use/manage rtx's internal node-build") + .arg( + clap::Arg::new("args") + .num_args(1..) + .allow_hyphen_values(true) + .trailing_var_arg(true), + )]); + Ok(vec![topic]) + } else { + Ok(vec![]) + } } - fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { + fn execute_external_command( + &self, + _config: &Config, + command: &str, + args: Vec, + ) -> Result<()> { match command { - "nodebuild" => { + "node-build" => { self.install_or_update_node_build()?; cmd::cmd(self.node_build_bin(), args).run()?; } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 8bcf30b15..7f8942533 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -5,13 +5,13 @@ use std::path::{Path, PathBuf}; use std::process::exit; use std::time::Duration; +use clap::Command; use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; use itertools::Itertools; use once_cell::sync::Lazy; use crate::cache::CacheManager; -use crate::cmd::cmd; use crate::config::{Config, Settings}; use crate::env::PREFER_STALE; use crate::env_diff::{EnvDiff, EnvDiffOperation}; @@ -493,9 +493,10 @@ impl Plugin for ExternalPlugin { Ok(legacy_version) } - fn external_commands(&self) -> Result>> { + fn external_commands(&self) -> Result> { let command_path = self.plugin_path.join("lib/commands"); - if !self.is_installed() || !command_path.exists() { + if !self.is_installed() || !command_path.exists() || self.name == "direnv" { + // asdf-direnv is disabled since it conflicts with rtx's built-in direnv functionality return Ok(vec![]); } let mut commands = vec![]; @@ -503,7 +504,7 @@ impl Plugin for ExternalPlugin { if !command.starts_with("command-") || !command.ends_with(".bash") { continue; } - let mut command = command + let command = command .strip_prefix("command-") .unwrap() .strip_suffix(".bash") @@ -511,24 +512,47 @@ impl Plugin for ExternalPlugin { .split('-') .map(|s| s.to_string()) .collect::>(); - command.insert(0, self.name.clone()); commands.push(command); } - Ok(commands) - } + if commands.is_empty() { + return Ok(vec![]); + } - fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { + let topic = Command::new(self.name.clone()) + .about(format!("Commands provided by {} plugin", &self.name)) + .subcommands(commands.into_iter().map(|cmd| { + Command::new(cmd.join("-")) + .about(format!("{} command", cmd.join("-"))) + .arg( + clap::Arg::new("args") + .num_args(1..) + .allow_hyphen_values(true) + .trailing_var_arg(true), + ) + })); + Ok(vec![topic]) + } + + fn execute_external_command( + &self, + config: &Config, + command: &str, + args: Vec, + ) -> Result<()> { if !self.is_installed() { return Err(PluginNotInstalled(self.name.clone()).into()); } - let result = cmd( + let script = Script::RunExternalCommand( self.plugin_path .join("lib/commands") .join(format!("command-{command}.bash")), args, - ) - .unchecked() - .run()?; + ); + let result = self + .script_man + .cmd(&config.settings, &script) + .unchecked() + .run()?; exit(result.status.code().unwrap_or(1)); } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 461e841e6..bba6735a1 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,3 +1,4 @@ +use clap::Command; use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; use std::path::{Path, PathBuf}; @@ -54,10 +55,15 @@ pub trait Plugin: Debug + Send + Sync { let contents = std::fs::read_to_string(path)?; Ok(contents.trim().to_string()) } - fn external_commands(&self) -> Result>> { + fn external_commands(&self) -> Result> { Ok(vec![]) } - fn execute_external_command(&self, _command: &str, _args: Vec) -> Result<()> { + fn execute_external_command( + &self, + _config: &Config, + _command: &str, + _args: Vec, + ) -> Result<()> { unimplemented!() } fn install_version(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index f9ac84d55..2aa9231c9 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -45,6 +45,7 @@ pub enum Script { ExecEnv, Install, ListBinPaths, + RunExternalCommand(PathBuf, Vec), Uninstall, } @@ -62,6 +63,7 @@ impl Display for Script { Script::Install => write!(f, "install"), Script::Uninstall => write!(f, "uninstall"), Script::ListBinPaths => write!(f, "list-bin-paths"), + Script::RunExternalCommand(_, _) => write!(f, "run-external-command"), Script::ExecEnv => write!(f, "exec-env"), Script::Download => write!(f, "download"), } @@ -108,7 +110,10 @@ impl ScriptManager { } pub fn get_script_path(&self, script: &Script) -> PathBuf { - self.plugin_path.join("bin").join(script.to_string()) + match script { + Script::RunExternalCommand(path, _) => path.clone(), + _ => self.plugin_path.join("bin").join(script.to_string()), + } } pub fn script_exists(&self, script: &Script) -> bool { @@ -118,6 +123,7 @@ impl ScriptManager { pub fn cmd(&self, settings: &Settings, script: &Script) -> Expression { let args = match script { Script::ParseLegacyFile(filename) => vec![filename.clone()], + Script::RunExternalCommand(_, args) => args.clone(), _ => vec![], }; let script_path = self.get_script_path(script); diff --git a/src/tool.rs b/src/tool.rs index f9a1be124..d74a9fe76 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -2,6 +2,7 @@ use std::collections::{BTreeMap, HashMap}; use std::fs::{remove_file, File}; use std::path::{Path, PathBuf}; +use clap::Command; use color_eyre::eyre::{eyre, Result}; use console::style; use itertools::Itertools; @@ -254,11 +255,16 @@ impl Tool { self.plugin.uninstall(pr) } - pub fn external_commands(&self) -> Result>> { + pub fn external_commands(&self) -> Result> { self.plugin.external_commands() } - pub fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { - self.plugin.execute_external_command(command, args) + pub fn execute_external_command( + &self, + config: &Config, + command: &str, + args: Vec, + ) -> Result<()> { + self.plugin.execute_external_command(config, command, args) } pub fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result { self.plugin.parse_legacy_file(path, settings) From 1baeaa7700b3762a7cc78ba38ae8b01e9df6f25a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 13:47:12 -0500 Subject: [PATCH 0749/1891] bug fixes with `rtx ls` (#555) Fixes a bug that showed tools that were not installed or specified. Also fixes a panic with rendering --- src/cli/ls.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 225a69aa3..e340e0154 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -168,7 +168,8 @@ impl Ls { ); for (plugin, version, request) in output { let pad = |s, len| console::pad_str(s, len, Left, None); - let plugin_extra = (plugin.len() as i8 - max_plugin_len as i8).max(0) as usize; + let plugin_extra = + ((plugin.len() as i8 - max_plugin_len as i8).max(0) as usize).min(max_version_len); let plugin = pad(&plugin, max_plugin_len); let plugin = style(plugin).cyan(); let version_extra = (version.to_plain_string().len() as i8 - max_version_len as i8 @@ -236,6 +237,8 @@ fn get_runtime_list( }; (p, tv, source) }) + // if it isn't installed and it's not specified, don't show it + .filter(|(p, tv, source)| source.is_some() || p.is_version_installed(tv)) .collect(); Ok(rvs) From a12e12323d85cc0e72f0988f0c0c36f69e122bf7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 16:49:27 -0500 Subject: [PATCH 0750/1891] added rtx outdated command (#534) --- README.md | 38 +++++ completions/_rtx | 78 +++++++++ completions/rtx.bash | 96 ++++++++++- completions/rtx.fish | 92 +++++++---- e2e/test_tiny | 12 ++ man/man1/rtx.1 | 6 + src/cli/mod.rs | 6 + src/cli/outdated.rs | 153 ++++++++++++++++++ .../rtx__cli__env__tests__env_json.snap | 1 + .../rtx__cli__global__tests__global-3.snap | 1 - ...tx__cli__local__tests__local_remove-3.snap | 1 - .../rtx__cli__outdated__tests__current.snap | 5 + ...utdated__tests__current_with_runtimes.snap | 5 + .../rtx__cli__r#use__tests__use.snap | 7 - src/cli/upgrade.rs | 144 +++++++++++++++++ src/config/config_file/mod.rs | 1 - src/tool.rs | 66 ++++---- src/toolset/mod.rs | 19 +++ src/toolset/tool_version.rs | 9 ++ 19 files changed, 665 insertions(+), 75 deletions(-) create mode 100644 src/cli/outdated.rs create mode 100644 src/cli/snapshots/rtx__cli__outdated__tests__current.snap create mode 100644 src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use.snap create mode 100644 src/cli/upgrade.rs diff --git a/README.md b/README.md index 5497563d0..e9340c163 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ v20.0.0 - [`rtx latest `](#rtx-latest-tool) - [`rtx ls [OPTIONS]`](#rtx-ls-options) - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-plugin-prefix) + - [`rtx outdated [TOOL]...`](#rtx-outdated-tool) - [`rtx plugins install [OPTIONS] [NAME] [GIT_URL]`](#rtx-plugins-install-options-name-git_url) - [`rtx plugins link [OPTIONS] [PATH]`](#rtx-plugins-link-options-name-path) - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) @@ -171,6 +172,7 @@ v20.0.0 - [`rtx shell [OPTIONS] [TOOL]...`](#rtx-shell-options-tool) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall ...`](#rtx-uninstall-tool) + - [`rtx upgrade [TOOL]...`](#rtx-upgrade-tool) - [`rtx use [OPTIONS] [TOOL]...`](#rtx-use-options-tool) - [`rtx version`](#rtx-version) - [`rtx where `](#rtx-where-tool) @@ -1883,6 +1885,29 @@ Examples: 20.0.0 20.1.0 ``` +### `rtx outdated [TOOL]...` + +``` +[experimental] Shows outdated tool versions + +Usage: outdated [TOOL]... + +Arguments: + [TOOL]... + Tool(s) to show outdated versions for + e.g.: node@20 python@3.10 + If not specified, all tools in global and local configs will be shown + +Examples: + $ rtx outdated + Plugin Requested Current Latest + python 3.11 3.11.0 3.11.1 + node 20 20.0.0 20.1.0 + + $ rtx outdated node + Plugin Requested Current Latest + node 20 20.0.0 20.1.0 +``` ### `rtx plugins install [OPTIONS] [NAME] [GIT_URL]` ``` @@ -2238,6 +2263,19 @@ Examples: $ rtx uninstall node@18.0.0 # will uninstall specific version $ rtx uninstall node # will uninstall current node version ``` +### `rtx upgrade [TOOL]...` + +``` +[experimental] Upgrades outdated tool versions + +Usage: upgrade [TOOL]... + +Arguments: + [TOOL]... + Tool(s) to upgrade + e.g.: node@20 python@3.10 + If not specified, all current tools will be upgraded +``` ### `rtx use [OPTIONS] [TOOL]...` ``` diff --git a/completions/_rtx b/completions/_rtx index 514e001b7..c8234e8a5 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -806,6 +806,29 @@ Sets --jobs=1]' \ same as the first argument after the "@":' \ && ret=0 ;; +(outdated) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::tool -- Tool(s) to show outdated versions for +e.g.\: node@20 python@3.10 +If not specified, all tools in global and local configs will be shown:' \ +&& ret=0 +;; (plugins) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel @@ -1330,6 +1353,29 @@ Sets --jobs=1]' \ '*::tool -- Tool(s) to remove:' \ && ret=0 ;; +(upgrade) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'*::tool -- Tool(s) to upgrade +e.g.\: node@20 python@3.10 +If not specified, all current tools will be upgraded:' \ +&& ret=0 +;; (use) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the tool(s) from config file]:TOOL: ' \ @@ -1614,6 +1660,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(outdated) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (plugins) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help__plugins_commands" \ @@ -1710,6 +1760,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(upgrade) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (use) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1771,6 +1825,7 @@ _rtx_commands() { 'ls:List installed and/or currently selected tool versions' \ 'list:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ +'outdated:\[experimental\] Shows outdated tool versions' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ 'prune:Delete unused versions of tools' \ @@ -1780,6 +1835,7 @@ _rtx_commands() { 'shell:Sets a tool version for the current shell session' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ +'upgrade:\[experimental\] Upgrades outdated tool versions' \ 'use:Change the active version of a tool locally or globally.' \ 'u:Change the active version of a tool locally or globally.' \ 'version:Show rtx version' \ @@ -2124,6 +2180,7 @@ _rtx__help_commands() { 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ +'outdated:\[experimental\] Shows outdated tool versions' \ 'plugins:Manage plugins' \ 'prune:Delete unused versions of tools' \ 'reshim:rebuilds the shim farm' \ @@ -2132,6 +2189,7 @@ _rtx__help_commands() { 'shell:Sets a tool version for the current shell session' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ +'upgrade:\[experimental\] Upgrades outdated tool versions' \ 'use:Change the active version of a tool locally or globally.' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ @@ -2340,6 +2398,16 @@ _rtx__plugins__ls-remote_commands() { local commands; commands=() _describe -t commands 'rtx plugins ls-remote commands' commands "$@" } +(( $+functions[_rtx__help__outdated_commands] )) || +_rtx__help__outdated_commands() { + local commands; commands=() + _describe -t commands 'rtx help outdated commands' commands "$@" +} +(( $+functions[_rtx__outdated_commands] )) || +_rtx__outdated_commands() { + local commands; commands=() + _describe -t commands 'rtx outdated commands' commands "$@" +} (( $+functions[_rtx__help__plugins_commands] )) || _rtx__help__plugins_commands() { local commands; commands=( @@ -2557,6 +2625,16 @@ _rtx__plugins__update_commands() { local commands; commands=() _describe -t commands 'rtx plugins update commands' commands "$@" } +(( $+functions[_rtx__help__upgrade_commands] )) || +_rtx__help__upgrade_commands() { + local commands; commands=() + _describe -t commands 'rtx help upgrade commands' commands "$@" +} +(( $+functions[_rtx__upgrade_commands] )) || +_rtx__upgrade_commands() { + local commands; commands=() + _describe -t commands 'rtx upgrade commands' commands "$@" +} (( $+functions[_rtx__help__use_commands] )) || _rtx__help__use_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 2fdb78719..9a45c6ab0 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -87,6 +87,9 @@ _rtx() { rtx,ls-remote) cmd="rtx__ls__remote" ;; + rtx,outdated) + cmd="rtx__outdated" + ;; rtx,p) cmd="rtx__plugins" ;; @@ -120,6 +123,9 @@ _rtx() { rtx,uninstall) cmd="rtx__uninstall" ;; + rtx,upgrade) + cmd="rtx__upgrade" + ;; rtx,use) cmd="rtx__use" ;; @@ -288,6 +294,9 @@ _rtx() { rtx__help,ls-remote) cmd="rtx__help__ls__remote" ;; + rtx__help,outdated) + cmd="rtx__help__outdated" + ;; rtx__help,plugins) cmd="rtx__help__plugins" ;; @@ -315,6 +324,9 @@ _rtx() { rtx__help,uninstall) cmd="rtx__help__uninstall" ;; + rtx__help,upgrade) + cmd="rtx__help__upgrade" + ;; rtx__help,use) cmd="rtx__help__use" ;; @@ -493,7 +505,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall use version where which render-help help" + opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1317,7 +1329,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote plugins prune reshim self-update settings shell trust uninstall use version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1736,6 +1748,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__outdated) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__plugins) opts="install link ls ls-remote uninstall update" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2002,6 +2028,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__upgrade) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__use) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2260,6 +2300,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__outdated) + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__plugins) opts="-a -c -u -j -r -v -h --all --core --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -2950,6 +3016,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__upgrade) + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__use) opts="-g -p -j -r -v -h --pin --fuzzy --remove --global --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 0f68f9977..d98aebac9 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -29,6 +29,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest av complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed and/or currently selected tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_use_subcommand" -f -a "outdated" -d '[experimental] Shows outdated tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d 'rebuilds the shim farm' @@ -37,6 +38,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "use" -d 'Change the active version of a tool locally or globally.' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' @@ -387,6 +389,16 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from outdated" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from outdated" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r @@ -612,6 +624,16 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from use" -l remove -d 'Remove the tool(s) from config file' -r complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file' -r -F complete -c rtx -n "__fish_seen_subcommand_from use" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -672,40 +694,42 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/e2e/test_tiny b/e2e/test_tiny index 84f1f15b0..cbddff57b 100755 --- a/e2e/test_tiny +++ b/e2e/test_tiny @@ -17,3 +17,15 @@ assert "rtx current tiny" "2.0.1" rm .tiny-version rtx local tiny@latest assert "rtx current tiny" "3.1.0" + +# test outdated/upgrade +rtx settings set experimental true +rm -rf .rtx/installs/tiny +rtx use tiny@3 +mv .rtx/installs/tiny/{3.1.0,3.0.0} +assert "rtx current tiny" "3.0.0" +assert "rtx outdated tiny" "Tool Requested Current Latest +tiny 3 3.0.0 3.1.0" +rtx upgrade tiny +assert "rtx current tiny" "3.1.0" +assert "rtx outdated tiny" "" diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a1a17e8b4..676b23cd4 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -88,6 +88,9 @@ List installed and/or currently selected tool versions rtx\-ls\-remote(1) List runtime versions available for install .TP +rtx\-outdated(1) +[experimental] Shows outdated tool versions +.TP rtx\-plugins(1) Manage plugins .TP @@ -112,6 +115,9 @@ Marks a config file as trusted rtx\-uninstall(1) Removes runtime versions .TP +rtx\-upgrade(1) +[experimental] Upgrades outdated tool versions +.TP rtx\-use(1) Change the active version of a tool locally or globally. .TP diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 954c5d872..2e5d71973 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -31,6 +31,7 @@ mod latest; mod local; mod ls; mod ls_remote; +mod outdated; mod plugins; mod prune; #[cfg(debug_assertions)] @@ -41,6 +42,7 @@ mod settings; mod shell; mod trust; mod uninstall; +mod upgrade; mod r#use; pub mod version; mod r#where; @@ -73,6 +75,7 @@ pub enum Commands { Local(local::Local), Ls(ls::Ls), LsRemote(ls_remote::LsRemote), + Outdated(outdated::Outdated), Plugins(plugins::Plugins), Prune(prune::Prune), Reshim(reshim::Reshim), @@ -81,6 +84,7 @@ pub enum Commands { Shell(shell::Shell), Trust(trust::Trust), Uninstall(uninstall::Uninstall), + Upgrade(upgrade::Upgrade), Use(r#use::Use), Version(version::Version), Where(r#where::Where), @@ -113,6 +117,7 @@ impl Commands { Self::Local(cmd) => cmd.run(config, out), Self::Ls(cmd) => cmd.run(config, out), Self::LsRemote(cmd) => cmd.run(config, out), + Self::Outdated(cmd) => cmd.run(config, out), Self::Plugins(cmd) => cmd.run(config, out), Self::Prune(cmd) => cmd.run(config, out), Self::Reshim(cmd) => cmd.run(config, out), @@ -121,6 +126,7 @@ impl Commands { Self::Shell(cmd) => cmd.run(config, out), Self::Trust(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), + Self::Upgrade(cmd) => cmd.run(config, out), Self::Use(cmd) => cmd.run(config, out), Self::Version(cmd) => cmd.run(config, out), Self::Where(cmd) => cmd.run(config, out), diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs new file mode 100644 index 000000000..7c36fbcf4 --- /dev/null +++ b/src/cli/outdated.rs @@ -0,0 +1,153 @@ +use std::collections::HashSet; +use std::sync::Arc; + +use color_eyre::eyre::Result; +use console::{pad_str, style, Alignment}; + +use crate::cli::args::tool::{ToolArg, ToolArgParser}; +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; +use crate::tool::Tool; +use crate::toolset::{ToolVersion, ToolsetBuilder}; + +/// [experimental] Shows outdated tool versions +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct Outdated { + /// Tool(s) to show outdated versions for + /// e.g.: node@20 python@3.10 + /// If not specified, all tools in global and local configs will be shown + #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + pub tool: Vec, +} + +impl Command for Outdated { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + if !config.settings.experimental { + return Err(color_eyre::eyre::eyre!( + "This command is experimental. Enable it with `rtx settings set experimental true`" + )); + } + let mut ts = ToolsetBuilder::new() + .with_args(&self.tool) + .build(&mut config)?; + let tool_set = self + .tool + .iter() + .map(|t| t.plugin.clone()) + .collect::>(); + ts.versions + .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); + let outdated = ts.list_outdated_versions(&config); + if outdated.is_empty() { + info!("All tools are up to date"); + } else { + self.display(outdated, out); + } + + Ok(()) + } +} + +type OutputVec = Vec<(Arc, ToolVersion, String)>; + +impl Outdated { + fn display(&self, outdated: OutputVec, out: &mut Output) { + // TODO: make a generic table printer in src/ui/table + let plugins = outdated + .iter() + .map(|(t, _, _)| t.name.clone()) + .collect::>(); + let requests = outdated + .iter() + .map(|(_, tv, _)| tv.request.version()) + .collect::>(); + let currents = outdated + .iter() + .map(|(t, tv, _)| { + if t.is_version_installed(tv) { + tv.version.clone() + } else { + "MISSING".to_string() + } + }) + .collect::>(); + let latests = outdated + .iter() + .map(|(_, _, c)| c.clone()) + .collect::>(); + let plugin_width = plugins + .iter() + .map(|s| s.len()) + .max() + .unwrap_or_default() + .max(6) + + 1; + let requested_width = requests + .iter() + .map(|s| s.len()) + .max() + .unwrap_or_default() + .max(9) + + 1; + let current_width = currents + .iter() + .map(|s| s.len()) + .max() + .unwrap_or_default() + .max(7) + + 1; + let pad_plugin = |s| pad_str(s, plugin_width, Alignment::Left, None); + let pad_requested = |s| pad_str(s, requested_width, Alignment::Left, None); + let pad_current = |s| pad_str(s, current_width, Alignment::Left, None); + rtxprintln!( + out, + "{} {} {} {}", + style(pad_plugin("Tool")).dim(), + style(pad_requested("Requested")).dim(), + style(pad_current("Current")).dim(), + style("Latest").dim(), + ); + for i in 0..outdated.len() { + rtxprintln!( + out, + "{} {} {} {}", + pad_plugin(&plugins[i]), + pad_requested(&requests[i]), + pad_current(¤ts[i]), + latests[i] + ); + } + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx outdated + Plugin Requested Current Latest + python 3.11 3.11.0 3.11.1 + node 20 20.0.0 20.1.0 + + $ rtx outdated node + Plugin Requested Current Latest + node 20 20.0.0 20.1.0 +"# +); + +#[cfg(test)] +mod tests { + use std::env; + + use crate::assert_cli_snapshot; + + #[test] + fn test_current() { + assert_cli_snapshot!("outdated"); + } + + #[test] + fn test_current_with_runtimes() { + assert_cli_snapshot!("outdated", "tiny"); + } +} diff --git a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap index 63869c709..0f16d01dd 100644 --- a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap +++ b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap @@ -6,3 +6,4 @@ expression: output "JDXCODE_TINY": "3.1.0", "PATH": "~/data/installs/tiny/3.1.0/bin:~/data/installs/dummy/ref-master/bin:$PATH" } + diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap index 2c986ca59..490bfa332 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap @@ -3,4 +3,3 @@ source: src/cli/global.rs expression: output --- - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap index 4057a4d40..931ef3891 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- - diff --git a/src/cli/snapshots/rtx__cli__outdated__tests__current.snap b/src/cli/snapshots/rtx__cli__outdated__tests__current.snap new file mode 100644 index 000000000..ea8cca771 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__outdated__tests__current.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/outdated.rs +expression: output +--- + diff --git a/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap b/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap new file mode 100644 index 000000000..ea8cca771 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/outdated.rs +expression: output +--- + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use.snap deleted file mode 100644 index 4a5a476a6..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/use.rs -expression: "fs::read_to_string(&cf_path).unwrap()" ---- -[tools] -tiny = "2" - diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs new file mode 100644 index 000000000..70db4d523 --- /dev/null +++ b/src/cli/upgrade.rs @@ -0,0 +1,144 @@ +use std::collections::HashSet; +use std::sync::Arc; + +use color_eyre::eyre::{eyre, Result}; +use itertools::Itertools; +use rayon::prelude::*; +use rayon::ThreadPoolBuilder; + +use crate::cli::args::tool::{ToolArg, ToolArgParser}; +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; +use crate::runtime_symlinks::rebuild_symlinks; +use crate::shims::reshim; +use crate::tool::Tool; +use crate::toolset::{ToolVersion, ToolsetBuilder}; +use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::progress_report::ProgressReport; + +/// [experimental] Upgrades outdated tool versions +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct Upgrade { + /// Tool(s) to upgrade + /// e.g.: node@20 python@3.10 + /// If not specified, all current tools will be upgraded + #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + pub tool: Vec, +} + +impl Command for Upgrade { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + if !config.settings.experimental { + return Err(color_eyre::eyre::eyre!( + "This command is experimental. Enable it with `rtx settings set experimental true`" + )); + } + let mut ts = ToolsetBuilder::new() + .with_args(&self.tool) + .build(&mut config)?; + let tool_set = self + .tool + .iter() + .map(|t| t.plugin.clone()) + .collect::>(); + ts.versions + .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); + let outdated = ts.list_outdated_versions(&config); + if outdated.is_empty() { + info!("All tools are up to date"); + } else { + self.upgrade(&mut config, outdated)?; + } + + Ok(()) + } +} + +type OutputVec = Vec<(Arc, ToolVersion, String)>; +type GroupedToolVersions = Vec<(Arc, Vec<(ToolVersion, String)>)>; + +impl Upgrade { + fn upgrade(&self, config: &mut Config, outdated: OutputVec) -> Result<()> { + let mut mpr = MultiProgressReport::new(config.settings.verbose); + ThreadPoolBuilder::new() + .num_threads(config.settings.jobs) + .build()? + .install(|| -> Result<()> { + self.install_new_versions(config, &mut mpr, outdated)?; + + let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + reshim(config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + rebuild_symlinks(config)?; + + Ok(()) + }) + } + + fn install_new_versions( + &self, + config: &Config, + mpr: &mut MultiProgressReport, + outdated: OutputVec, + ) -> Result<()> { + let grouped_tool_versions: GroupedToolVersions = outdated + .into_iter() + .group_by(|(t, _, _)| t.clone()) + .into_iter() + .map(|(t, tvs)| (t, tvs.map(|(_, tv, latest)| (tv, latest)).collect())) + .collect(); + grouped_tool_versions + .into_par_iter() + .map(|(tool, versions)| { + for (tv, latest) in versions { + let mut pr = mpr.add(); + self.install_new_version(config, &tool, &tv, latest, &mut pr)?; + self.uninstall_old_version(config, &tool, &tv, &mut pr)?; + } + Ok(()) + }) + .collect::>>()?; + Ok(()) + } + + fn install_new_version( + &self, + config: &Config, + tool: &Tool, + tv: &ToolVersion, + latest: String, + pr: &mut ProgressReport, + ) -> Result<()> { + let mut tv = tv.clone(); + tv.version = latest; + tool.decorate_progress_bar(pr, Some(&tv)); + match tool.install_version(config, &tv, pr, false) { + Ok(_) => Ok(()), + Err(err) => { + pr.error(); + Err(err.wrap_err(format!("failed to install {}", tv))) + } + } + } + + fn uninstall_old_version( + &self, + config: &Config, + tool: &Tool, + tv: &ToolVersion, + pr: &mut ProgressReport, + ) -> Result<()> { + tool.decorate_progress_bar(pr, Some(tv)); + match tool.uninstall_version(config, tv, pr, false) { + Ok(_) => { + pr.finish(); + Ok(()) + } + Err(err) => { + pr.error(); + Err(err.wrap_err(format!("failed to uninstall {}", tv))) + } + } + } +} diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 52cf05a08..3da442eed 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -59,7 +59,6 @@ impl dyn ConfigFile { let mpr = MultiProgressReport::new(config.settings.verbose); let mut ts = self.to_toolset().to_owned(); ts.resolve(config); - ts.latest_versions = true; let mut plugins_to_update = HashMap::new(); for runtime in runtimes { if let Some(tv) = &runtime.tvr { diff --git a/src/tool.rs b/src/tool.rs index d74a9fe76..65b24946e 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -59,6 +59,14 @@ impl Tool { true => file::dir_subdirs(&self.installs_path)? .iter() .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) + // TODO: share logic with incomplete_file_path + .filter(|v| { + !dirs::CACHE + .join(&self.name) + .join(v) + .join("incomplete") + .exists() + }) .map(|v| Versioning::new(v).unwrap_or_default()) .sorted() .map(|v| v.to_string()) @@ -68,19 +76,8 @@ impl Tool { } pub fn list_installed_versions_matching(&self, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; - } - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_installed_versions()? - .iter() - .filter(|v| query_regex.is_match(v)) - .cloned() - .collect(); - Ok(versions) + let versions = self.list_installed_versions()?; + Ok(self.fuzzy_match_filter(versions, query)) } pub fn list_remote_versions(&self, settings: &Settings) -> Result> { @@ -88,22 +85,8 @@ impl Tool { } pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9]"; - } - let version_regex = regex!( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" - ); - let query_regex = - Regex::new((String::from(r"^\s*") + query).as_str()).expect("error parsing regex"); - let versions = self - .list_remote_versions(settings)? - .into_iter() - .filter(|v| !version_regex.is_match(v)) - .filter(|v| query_regex.is_match(v)) - .collect(); - Ok(versions) + let versions = self.list_remote_versions(settings)?; + Ok(self.fuzzy_match_filter(versions, query)) } pub fn latest_version( @@ -237,6 +220,7 @@ impl Tool { }; rmdir(&tv.install_path())?; rmdir(&tv.download_path())?; + rmdir(&tv.cache_path())?; Ok(()) } @@ -338,6 +322,30 @@ impl Tool { }; Ok(lock) } + + fn fuzzy_match_filter(&self, versions: Vec, query: &str) -> Vec { + let mut query = query; + if query == "latest" { + query = "[0-9].*"; + } + let query_regex = + Regex::new(&format!("^{}([-.].+)?$", query)).expect("error parsing regex"); + let version_regex = regex!( + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" + ); + versions + .into_iter() + .filter(|v| { + if query == v { + return true; + } + if version_regex.is_match(v) { + return false; + } + query_regex.is_match(v) + }) + .collect() + } } impl PartialEq for Tool { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 5523c2f84..1fe7b8549 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -283,6 +283,25 @@ impl Toolset { .filter(|(p, v)| p.is_version_installed(v)) .collect() } + pub fn list_outdated_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion, String)> { + self.list_current_versions(config) + .into_iter() + .filter_map(|(t, tv)| { + let latest = match tv.latest_version(config, &t) { + Ok(latest) => latest, + Err(e) => { + warn!("Error getting latest version for {}: {:#}", t.name, e); + return None; + } + }; + if !t.is_version_installed(&tv) || tv.version != latest { + Some((t, tv, latest)) + } else { + None + } + }) + .collect() + } pub fn env_with_path(&self, config: &Config) -> BTreeMap { let mut env = self.env(config); let path_env = self.path_env(config); diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index d97027057..07baa46ff 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -73,6 +73,12 @@ impl ToolVersion { .join(&self.plugin_name) .join(self.tv_pathname()) } + pub fn latest_version(&self, config: &Config, tool: &Tool) -> Result { + let tv = self + .request + .resolve(config, tool, self.opts.clone(), true)?; + Ok(tv.version) + } fn tv_pathname(&self) -> String { match &self.request { ToolVersionRequest::Version(_, _) => self.version.to_string(), @@ -131,6 +137,9 @@ impl ToolVersion { if matches.contains(&v) { return build(v); } + if let Some(v) = matches.last() { + return build(v.clone()); + } } let matches = tool.list_versions_matching(&config.settings, &v)?; if matches.contains(&v) { From e9e1b475ecd633d57ab1c1e3ccec500bc39ceeaf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 16:54:38 -0500 Subject: [PATCH 0751/1891] replace owocolorize strikethrough with console --- Cargo.lock | 22 +++------------------- Cargo.toml | 3 +-- src/cli/ls.rs | 1 - 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2c79f23e..dbdffe64e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -340,15 +340,15 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "console" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "d0525278dce688103060006713371cedbad27186c7d913f33d866b498da0f595" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -1643,7 +1643,6 @@ dependencies = [ "log", "num_cpus", "once_cell", - "owo-colors", "pretty_assertions", "rayon", "regex", @@ -2512,21 +2511,6 @@ dependencies = [ "windows-targets 0.48.0", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index abd7214e8..ec14788a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ clap = { version = "4.2.5", features = ["env", "derive", "string"] } clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" -console = "0.15.2" +console = "0.15.6" ctrlc = "3.2.3" dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" @@ -59,7 +59,6 @@ itertools = "0.10.3" log = "0.4.17" num_cpus = "1.14.0" once_cell = "1.17.0" -owo-colors = "3.5.0" rayon = "1.6.1" regex = "1.7.1" reqwest = { version = "0.11.17", default-features = false, features = [ diff --git a/src/cli/ls.rs b/src/cli/ls.rs index e340e0154..f37eac5e7 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -8,7 +8,6 @@ use console::style; use console::Alignment::Left; use indexmap::IndexMap; use itertools::Itertools; -use owo_colors::OwoColorize; use serde_derive::Serialize; use versions::Versioning; From bd64c0e5a9bc5f50b730f5dadc530cabc0d8a332 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 16:56:30 -0500 Subject: [PATCH 0752/1891] chore: Release --- Cargo.lock | 215 ++++++++++++++------------------------ Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 24 ++++- 7 files changed, 106 insertions(+), 147 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbdffe64e..ac18a70b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,9 +215,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.7" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938" +checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" dependencies = [ "clap_builder", "clap_derive", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.2.7" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" +checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" dependencies = [ "anstream", "anstyle", @@ -239,51 +239,41 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.2.3" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1594fe2312ec4abf402076e407628f5c313e54c32ade058521df4ee34ecac8a8" +checksum = "a04ddfaacc3bc9e6ea67d024575fafc2a813027cf374b8f24f7bc233c6b6be12" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.2.0" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] name = "clap_lex" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "clap_mangen" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4237e29de9c6949982ba87d51709204504fb8ed2fd38232fcb1e5bf7d4ba48c8" +checksum = "6bcbd911d903a985de775aabe3bcef9b88e2a7d943e36aa8691617012d2b7731" dependencies = [ "clap", "roff", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "color-eyre" version = "0.6.2" @@ -445,7 +435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" dependencies = [ "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -458,50 +448,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.15", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - [[package]] name = "dialoguer" version = "0.10.4" @@ -522,9 +468,9 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -812,9 +758,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -922,9 +868,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" dependencies = [ "http", "hyper", @@ -949,12 +895,11 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -1097,9 +1042,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.62" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -1140,15 +1085,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1375,7 +1311,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -1436,9 +1372,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" dependencies = [ "unicode-ident", ] @@ -1531,9 +1467,9 @@ checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "reqwest" -version = "0.11.17" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ "base64", "bytes", @@ -1613,7 +1549,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.29.7" +version = "1.30.0" dependencies = [ "base64", "built", @@ -1657,7 +1593,7 @@ dependencies = [ "tera", "terminal_size", "thiserror", - "toml 0.7.3", + "toml 0.7.4", "toml_edit", "url", "versions", @@ -1685,14 +1621,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" dependencies = [ "log", "ring", + "rustls-webpki", "sct", - "webpki", ] [[package]] @@ -1704,6 +1640,16 @@ dependencies = [ "base64", ] +[[package]] +name = "rustls-webpki" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.13" @@ -1725,12 +1671,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - [[package]] name = "sct" version = "0.7.0" @@ -1785,7 +1725,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -1801,9 +1741,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" dependencies = [ "serde", ] @@ -1929,9 +1869,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ "proc-macro2", "quote", @@ -2004,7 +1944,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2078,13 +2018,12 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] @@ -2112,9 +2051,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" dependencies = [ "serde", "serde_spanned", @@ -2124,18 +2063,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" dependencies = [ "indexmap", "serde", @@ -2163,9 +2102,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -2378,9 +2317,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2388,24 +2327,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.35" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "083abe15c5d88556b77bdf7aef403625be9e327ad37c62c4e4129af740168163" +checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" dependencies = [ "cfg-if", "js-sys", @@ -2415,9 +2354,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2425,28 +2364,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "web-sys" -version = "0.3.62" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index ec14788a6..ba830e6ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.29.7" +version = "1.30.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e9340c163..ff1eb4cc2 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.29.7 +rtx 1.30.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -317,7 +317,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.29.7/rtx-v1.29.7-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.30.0/rtx-v1.30.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 3e8c1a182..6e9b528ec 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.29.7"; + version = "1.30.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 676b23cd4..b7601b010 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.29.7" +.TH rtx 1 "rtx 1.30.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -145,6 +145,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.29.7 +v1.30.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 18fa73fa5..bda86939b 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.29.7 +Version: 1.30.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 31b4d120c..c6cfdad76 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -51,7 +51,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("awsweeper", "https://github.com/chessmango/asdf-awsweeper.git"), ("azure-cli", "https://github.com/itspngu/asdf-azure-cli.git"), ("azure-functions-core-tools", "https://github.com/daveneeley/asdf-azure-functions-core-tools.git"), - ("babashka", "https://github.com/fredZen/asdf-babashka"), + ("babashka", "https://github.com/pitch-io/asdf-babashka.git"), ("balena-cli", "https://github.com/boatkit-io/asdf-balena-cli"), ("bashbot", "https://github.com/mathew-fleisch/asdf-bashbot.git"), ("bat", "https://gitlab.com/wt0f/asdf-bat.git"), @@ -61,6 +61,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("bbr", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("bbr-s3-config-validator", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("benthos", "https://github.com/benthosdev/benthos-asdf.git"), + ("bin", "https://github.com/joe733/asdf-bin.git"), ("binnacle", "https://github.com/Traackr/asdf-binnacle.git"), ("bitwarden", "https://github.com/vixus0/asdf-bitwarden.git"), ("bombardier", "https://github.com/NeoHsu/asdf-bombardier.git"), @@ -78,6 +79,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("caddy", "https://github.com/salasrod/asdf-caddy.git"), ("camunda-modeler", "https://github.com/barmac/asdf-camunda-modeler.git"), ("cargo-make", "https://github.com/kachick/asdf-cargo-make.git"), + ("carp", "https://github.com/susurri/asdf-carp.git"), ("carthage", "https://github.com/younke/asdf-carthage.git"), ("ccache", "https://github.com/asdf-community/asdf-ccache.git"), ("certstrap", "https://github.com/carnei-ro/asdf-certstrap.git"), @@ -92,6 +94,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("choose", "https://github.com/carbonteq/asdf-choose.git"), ("chromedriver", "https://github.com/schinckel/asdf-chromedriver.git"), ("cidr-merger", "https://github.com/ORCID/asdf-cidr-merger.git"), + ("cidrchk", "https://github.com/ORCID/asdf-cidrchk.git"), ("cilium-cli", "https://github.com/carnei-ro/asdf-cilium-cli.git"), ("cilium-hubble", "https://github.com/NitriKx/asdf-cilium-hubble.git"), ("clojure", "https://github.com/asdf-community/asdf-clojure.git"), @@ -180,6 +183,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("erlang", "https://github.com/asdf-vm/asdf-erlang.git"), ("esy", "https://github.com/asdf-community/asdf-esy.git"), ("etcd", "https://github.com/particledecay/asdf-etcd.git"), + ("evans", "https://github.com/goki90210/asdf-evans.git"), ("exa", "https://github.com/nyrst/asdf-exa.git"), ("fd", "https://gitlab.com/wt0f/asdf-fd.git"), ("ffmpeg", "https://github.com/acj/asdf-ffmpeg"), @@ -305,6 +309,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("julia", "https://github.com/rkyleg/asdf-julia.git"), ("just", "https://github.com/olofvndrhr/asdf-just.git"), ("jx", "https://github.com/vbehar/asdf-jx.git"), + ("k0sctl", "https://github.com/Its-Alex/asdf-plugin-k0sctl.git"), ("k2tf", "https://github.com/carlduevel/asdf-k2tf.git"), ("k3d", "https://github.com/spencergilbert/asdf-k3d.git"), ("k3sup", "https://github.com/cgroschupp/asdf-k3sup.git"), @@ -321,6 +326,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("kind", "https://github.com/johnlayton/asdf-kind.git"), ("kn", "https://github.com/joke/asdf-kn.git"), ("ko", "https://github.com/zasdaym/asdf-ko.git"), + ("koka", "https://github.com/susurri/asdf-koka.git"), ("kompose", "https://github.com/technikhil314/asdf-kompose.git"), ("kops", "https://github.com/Antiarchitect/asdf-kops.git"), ("kotlin", "https://github.com/asdf-community/asdf-kotlin.git"), @@ -339,6 +345,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("kube-score", "https://github.com/bageljp/asdf-kube-score.git"), ("kubebuilder", "https://github.com/virtualstaticvoid/asdf-kubebuilder.git"), ("kubecm", "https://github.com/samhvw8/asdf-kubecm"), + ("kubecolor", "https://github.com/dex4er/asdf-kubecolor.git"), ("kubeconform", "https://github.com/lirlia/asdf-kubeconform.git"), ("kubectl", "https://github.com/asdf-community/asdf-kubectl.git"), ("kubectl-bindrole", "https://github.com/looztra/asdf-kubectl-bindrole.git"), @@ -347,12 +354,14 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("kubectl-kots", "https://github.com/ganta/asdf-kubectl-kots.git"), ("kubectx", "https://gitlab.com/wt0f/asdf-kubectx.git"), ("kubefedctl", "https://github.com/kvokka/asdf-kubefedctl.git"), + ("kubefirst", "https://github.com/Claywd/asdf-kubefirst"), ("kubelogin", "https://github.com/sechmann/asdf-kubelogin.git"), ("kubemqctl", "https://github.com/johnlayton/asdf-kubemqctl.git"), ("kubent", "https://github.com/virtualstaticvoid/asdf-kubent.git"), ("kubergrunt", "https://github.com/NeoHsu/asdf-kubergrunt.git"), ("kubeseal", "https://github.com/stefansedich/asdf-kubeseal.git"), ("kubesec", "https://github.com/vitalis/asdf-kubesec.git"), + ("kubeshark", "https://github.com/carnei-ro/asdf-kubeshark.git"), ("kubespy", "https://github.com/jfreeland/asdf-kubespy.git"), ("kubeval", "https://github.com/stefansedich/asdf-kubeval.git"), ("kubevela", "https://github.com/gustavclausen/asdf-kubevela.git"), @@ -378,10 +387,12 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("lua-language-server", "https://github.com/bellini666/asdf-lua-language-server"), ("luaJIT", "https://github.com/smashedtoatoms/asdf-luaJIT.git"), ("lucy", "https://github.com/cometkim/asdf-lucy.git"), + ("maestro", "https://github.com/dotanuki-labs/asdf-maestro.git"), ("mage", "https://github.com/mathew-fleisch/asdf-mage.git"), ("make", "https://github.com/yacchi/asdf-make.git"), ("mani", "https://github.com/anweber/asdf-mani.git"), ("mark", "https://github.com/jfreeland/asdf-mark.git"), + ("marp-cli", "https://github.com/xataz/asdf-marp-cli"), ("mask", "https://github.com/aaaaninja/asdf-mask.git"), ("maven", "https://github.com/halcyon/asdf-maven.git"), ("mc", "https://github.com/penpyt/asdf-mc.git"), @@ -389,6 +400,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("mdbook-linkcheck", "https://github.com/cipherstash/asdf-mdbook-linkcheck.git"), ("melt", "https://github.com/chessmango/asdf-melt.git"), ("memcached", "https://github.com/furkanural/asdf-memcached"), + ("mercury", "https://github.com/susurri/asdf-mercury.git"), ("meson", "https://github.com/asdf-community/asdf-meson.git"), ("micronaut", "https://github.com/weibemoura/asdf-micronaut.git"), ("mill", "https://github.com/asdf-community/asdf-mill.git"), @@ -448,6 +460,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("php", "https://github.com/asdf-community/asdf-php.git"), ("pint", "https://github.com/sam-burrell/asdf-pint.git"), ("pipectl", "https://github.com/pipe-cd/asdf-pipectl.git"), + ("pipx", "https://github.com/joe733/asdf-pipx.git"), ("pivnet", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("please", "https://github.com/asdf-community/asdf-please.git"), ("pluto", "https://github.com/FairwindsOps/asdf-pluto.git"), @@ -456,6 +469,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("polaris", "https://github.com/particledecay/asdf-polaris.git"), ("popeye", "https://github.com/nlamirault/asdf-popeye.git"), ("postgres", "https://github.com/smashedtoatoms/asdf-postgres.git"), + ("powerline-go", "https://github.com/dex4er/asdf-powerline-go.git"), ("powershell-core", "https://github.com/daveneeley/asdf-powershell-core.git"), ("pre-commit", "https://github.com/jonathanmorley/asdf-pre-commit.git"), ("protoc", "https://github.com/paxosglobal/asdf-protoc.git"), @@ -485,6 +499,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("redskyctl", "https://github.com/sudermanjr/asdf-redskyctl.git"), ("reg", "https://github.com/looztra/asdf-reg.git"), ("regctl", "https://github.com/ORCID/asdf-regctl.git"), + ("restic", "https://github.com/xataz/asdf-restic"), ("richgo", "https://github.com/paxosglobal/asdf-richgo.git"), ("riff", "https://github.com/abinet/asdf-riff.git"), ("ripgrep", "https://gitlab.com/wt0f/asdf-ripgrep.git"), @@ -503,12 +518,14 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("sccache", "https://github.com/emersonmx/asdf-sccache.git"), ("scenery", "https://github.com/skyzyx/asdf-scenery.git"), ("schemacrawler", "https://github.com/davidecavestro/asdf-schemacrawler.git"), + ("seed7", "https://github.com/susurri/asdf-seed7.git"), ("semgrep", "https://github.com/brentjanderson/asdf-semgrep.git"), ("semtag", "https://github.com/junminahn/asdf-semtag"), ("semver", "https://github.com/mathew-fleisch/asdf-semver.git"), ("sentinel", "https://github.com/asdf-community/asdf-hashicorp.git"), ("serf", "https://github.com/asdf-community/asdf-hashicorp.git"), ("serverless", "https://github.com/pdemagny/asdf-serverless.git"), + ("shell2http", "https://github.com/ORCID/asdf-shell2http.git"), ("shellcheck", "https://github.com/luizm/asdf-shellcheck.git"), ("shellspec", "https://github.com/poikilotherm/asdf-shellspec.git"), ("shfmt", "https://github.com/luizm/asdf-shfmt.git"), @@ -587,6 +604,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("tfupdate", "https://github.com/yuokada/asdf-tfupdate.git"), ("thrift", "https://github.com/alisaifee/asdf-thrift.git"), ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), + ("timoni", "https://github.com/Smana/asdf-timoni.git"), ("titan", "https://github.com/gabitchov/asdf-titan.git"), ("tmux", "https://github.com/aphecetche/asdf-tmux.git"), ("tokei", "https://github.com/gasuketsu/asdf-tokei.git"), @@ -597,7 +615,9 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 647] = [ ("tridentctl", "https://github.com/asdf-community/asdf-tridentctl.git"), ("trivy", "https://github.com/zufardhiyaulhaq/asdf-trivy.git"), ("tsuru", "https://github.com/virtualstaticvoid/asdf-tsuru.git"), + ("tx", "https://github.com/ORCID/asdf-transifex.git"), ("uaa-cli", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), + ("unison", "https://github.com/susurri/asdf-unison.git"), ("upt", "https://github.com/ORCID/asdf-upt.git"), ("upx", "https://github.com/jimmidyson/asdf-upx.git"), ("usql", "https://github.com/itspngu/asdf-usql.git"), From 158362ab60b91ce6286aef30305216c416eaa74c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 19:16:51 -0500 Subject: [PATCH 0753/1891] bug fix: ignore RTX_VERSION env var if set --- src/toolset/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 7d7ad838c..1e700757d 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -63,7 +63,7 @@ fn load_config_files(config: &Config, ts: &mut Toolset) { fn load_runtime_env(ts: &mut Toolset, env: BTreeMap) { for (k, v) in env { - if k.starts_with("RTX_") && k.ends_with("_VERSION") { + if k.starts_with("RTX_") && k.ends_with("_VERSION") && k != "RTX_VERSION" { let plugin_name = k[4..k.len() - 8].to_lowercase(); if plugin_name == "install" { // ignore RTX_INSTALL_VERSION From 6bdd9b803911b70750186d545d0ca835ef4928c7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 19 May 2023 19:24:33 -0500 Subject: [PATCH 0754/1891] chore: Release --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac18a70b3..c766a6983 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1093,9 +1093,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" @@ -1549,7 +1549,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.30.0" +version = "1.30.1" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index ba830e6ea..11a4a9aca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.30.0" +version = "1.30.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index ff1eb4cc2..812a9c40b 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.30.0 +rtx 1.30.1 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -317,7 +317,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.30.0/rtx-v1.30.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.30.1/rtx-v1.30.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 6e9b528ec..007190cf0 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.30.0"; + version = "1.30.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index b7601b010..5e785309e 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.30.0" +.TH rtx 1 "rtx 1.30.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -145,6 +145,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.30.0 +v1.30.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index bda86939b..cf778d343 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.30.0 +Version: 1.30.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From fc6e2131f0be798e42a1af8f77876db5cf077b28 Mon Sep 17 00:00:00 2001 From: Torben <8199725+tenjaa@users.noreply.github.com> Date: Sat, 20 May 2023 14:22:04 +0200 Subject: [PATCH 0755/1891] Split installation in two steps (#558) --- README.md | 78 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 812a9c40b..9acdcbf0f 100644 --- a/README.md +++ b/README.md @@ -72,23 +72,24 @@ v20.0.0 - [How it works](#how-it-works) - [Common commands](#common-commands) - [Installation](#installation) - - [Standalone](#standalone) - - [Homebrew](#homebrew) - - [Cargo](#cargo) - - [npm](#npm) - - [GitHub Releases](#github-releases) - - [apt](#apt) - - [dnf](#dnf) - - [yum](#yum) - - [apk](#apk) - - [aur](#aur) - - [nix](#nix) -- [Other Shells](#other-shells) - - [Bash](#bash) - - [Fish](#fish) - - [Nushell](#nushell) - - [Xonsh](#xonsh) - - [Something else?](#something-else) + - [Download binary](#download-binary) + - [Standalone](#standalone) + - [Homebrew](#homebrew) + - [Cargo](#cargo) + - [npm](#npm) + - [GitHub Releases](#github-releases) + - [apt](#apt) + - [dnf](#dnf) + - [yum](#yum) + - [apk](#apk) + - [aur](#aur) + - [nix](#nix) + - [Register shell hook](#register-shell-hook) + - [Bash](#bash) + - [Fish](#fish) + - [Nushell](#nushell) + - [Xonsh](#xonsh) + - [Something else?](#something-else) - [Uninstalling](#uninstalling) - [Shebang](#shebang) - [Configuration](#configuration) @@ -233,7 +234,16 @@ See [plugins](#plugins) below. ## Installation -### Standalone +Installing rtx consists of two steps. +1. Download the binary. + This depends on the device and operating system you are running rtx in. +1. Register a shell hook. + This depends on the shell you are using. + Read more about this step in the [FAQ](#what-does-rtx-activate-do). + +### Download binary + +#### Standalone Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate script in your rc file, rtx will automatically add itself to `PATH`. @@ -264,7 +274,7 @@ Supported platforms: If you need something else, compile it with [cargo](#cargo). [Windows isn't currently supported.](https://github.com/jdxcode/rtx/discussions/66) -### Homebrew +#### Homebrew ``` brew install rtx @@ -276,7 +286,7 @@ Alternatively, use the custom tap (which is updated immediately after a release) brew install jdxcode/tap/rtx ``` -### Cargo +#### Cargo Build from source with Cargo: @@ -297,7 +307,7 @@ Build from the latest commit in main: cargo install rtx-cli --git https://github.com/jdxcode/rtx --branch main ``` -### npm +#### npm rtx is available on npm as a precompiled binary. This isn't a node.js package—just distributed via npm. This is useful for JS projects that want to setup rtx via `package.json` or `npx`. @@ -312,7 +322,7 @@ Use npx if you just want to test it out for a single command without fully insta npx rtx-cli exec python@3.11 -- python some_script.py ``` -### GitHub Releases +#### GitHub Releases Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). @@ -321,7 +331,7 @@ curl https://github.com/jdxcode/rtx/releases/download/v1.30.1/rtx-v1.30.1-linux- chmod +x /usr/local/bin/rtx ``` -### apt +#### apt For installation on Ubuntu/Debian: @@ -340,7 +350,7 @@ sudo apt install -y rtx > echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` -### dnf +#### dnf For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: @@ -350,7 +360,7 @@ dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo dnf install -y rtx ``` -### yum +#### yum ``` yum install -y yum-utils @@ -358,7 +368,7 @@ yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo yum install -y rtx ``` -### apk +#### apk For Alpine Linux: @@ -368,7 +378,7 @@ apk add rtx _rtx lives in the [community repository](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/rtx/APKBUILD)._ -### aur +#### aur For Arch Linux: @@ -378,7 +388,7 @@ cd rtx makepkg -si ``` -### nix +#### nix For NixOS or those using the Nix package manager: @@ -417,21 +427,21 @@ You can also import the package directly using `rtx-flake.packages.${system}.rtx`. It supports all default Nix systems. -## Other Shells +### Register shell hook -### Bash +#### Bash ``` echo 'eval "$(rtx activate bash)"' >> ~/.bashrc ``` -### Fish +#### Fish ``` echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` -### Nushell +#### Nushell ```sh-session do { @@ -441,7 +451,7 @@ do { } ``` -### Xonsh +#### Xonsh Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a bit off startup time by using a pure Python import: add the code below to, for example, `~/.config/xonsh/rtx.py` config file and `import rtx` it in `~/.config/xonsh/rc.xsh`: @@ -462,7 +472,7 @@ echo 'execx($(~/bin/rtx activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xons Given that `rtx` replaces both shell env `$PATH` and OS environ `PATH`, watch out that your configs don't have these two set differently (might throw `os.environ['PATH'] = xonsh.built_ins.XSH.env.get_detyped('PATH')` at the end of a config to make sure they match) -### Something else? +#### Something else? Adding a new shell is not hard at all since very little shell code is in this project. From ad5ed497e3b926394d4bc7ab07459bb474ed1563 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 20 May 2023 14:28:00 -0500 Subject: [PATCH 0756/1891] document non-interactive use-cases better I am repeating myself but this appears to not be very well understood behavior so I think it is ok to be a little verbose on this topic. --- README.md | 47 +++++++++++++++++++++------------------------ src/cli/activate.rs | 6 +++++- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 9acdcbf0f..fd3c705da 100644 --- a/README.md +++ b/README.md @@ -73,23 +73,7 @@ v20.0.0 - [Common commands](#common-commands) - [Installation](#installation) - [Download binary](#download-binary) - - [Standalone](#standalone) - - [Homebrew](#homebrew) - - [Cargo](#cargo) - - [npm](#npm) - - [GitHub Releases](#github-releases) - - [apt](#apt) - - [dnf](#dnf) - - [yum](#yum) - - [apk](#apk) - - [aur](#aur) - - [nix](#nix) - [Register shell hook](#register-shell-hook) - - [Bash](#bash) - - [Fish](#fish) - - [Nushell](#nushell) - - [Xonsh](#xonsh) - - [Something else?](#something-else) - [Uninstalling](#uninstalling) - [Shebang](#shebang) - [Configuration](#configuration) @@ -1120,11 +1104,20 @@ You can make git ignore these files in 3 different ways: ### What does `rtx activate` do? -It registers a shell hook to run `rtx hook-env` every time the shell prompt is displayed. +It registers a shell hook to run `rtx hook-env` every time the shell prompt is *displayed*. You may think that is excessive and it should only run on `cd`, however there are many situations where it needs to run without the directory changing, for example if the `.rtx.toml` was modified. +Note my emphasis on the word *displayed*. This means if you attempt to use `rtx activate` in a +non-interactive session (like a bash script), it will never call `rtx hook-env` and in effect will +never modify PATH. For this type of setup, you can either call `rtx hook-env` manually every time +you wish to update PATH, or use [shims](#shims) instead. + +Or if you only need to use rtx for certain commands, just prefix the commands with +[`rtx x --`](#rtx-exec-options-tool----command). +For example, `rtx x -- npm test` or `rtx x -- ./my_script.sh`. + `rtx hook-env` will exit early in different situations if no changes have been made. This prevents blocking your shell every time you run a command. You can run `rtx hook-env` yourself to see what it outputs, however it is likely nothing if you're in a shell that has already been activated. @@ -1135,14 +1128,14 @@ and `rtx deactivate` to work without wrapping them in `eval "$(rtx shell)"`. ### `rtx activate` doesn't work in `~/.profile`, `~/.bash_profile`, `~/.zprofile` `rtx activate` should only be used in `rc` files. These are the interactive ones used when -a real user is using the terminal. (As opposed to being executed by an IDE or something). -Because rtx only calls `hook-env` when the prompt is displayed, calling `rtx activate` in a -non-interactive session means the prompt will never be shown. +a real user is using the terminal. (As opposed to being executed by an IDE or something). The prompt +isn't displayed in non-interactive environments so PATH won't be modified. -For this setup, consider using shims instead which will route calls to the correct directory -by looking at `PWD`. You can also call `rtx exec` instead of expecting things to be directly on PATH. -You can also run `rtx env` in a non-interactive shell, however that will only setup the global tools. -It won't modify the environment variables when entering into a different project. +For non-interactive setups, consider using shims instead which will route calls to the correct +directory by looking at `PWD` every time they're executed. You can also call `rtx exec` instead of +expecting things to be directly on PATH. You can also run `rtx env` in a non-interactive shell, however that +will only setup the global tools. It won't modify the environment variables when entering into a +different project. Also see the [shebang](#shebang) example for a way to make scripts call rtx to get the runtime. That is another way to use rtx without activation. @@ -1468,7 +1461,11 @@ Initializes rtx in the current shell This should go into your shell's rc file. Otherwise, it will only take effect in the current session. -(e.g. ~/.bashrc) +(e.g. ~/.zshrc, ~/.bashrc) + +This is only intended to be used in interactive sessions, not scripts. +rtx is only capable of updating PATH when the prompt is displayed to the user. +For non-interactive use-cases, use shims instead. Usage: activate [OPTIONS] [SHELL_TYPE] diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 417eb00ad..ebf814e64 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -13,7 +13,11 @@ use crate::shell::{get_shell, ShellType}; /// /// This should go into your shell's rc file. /// Otherwise, it will only take effect in the current session. -/// (e.g. ~/.bashrc) +/// (e.g. ~/.zshrc, ~/.bashrc) +/// +/// This is only intended to be used in interactive sessions, not scripts. +/// rtx is only capable of updating PATH when the prompt is displayed to the user. +/// For non-interactive use-cases, use shims instead. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Activate { From 104ed987b24eb63d09f7169c7cd8f0649b7d91c0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 20 May 2023 16:12:00 -0500 Subject: [PATCH 0757/1891] `rtx use` should use .tool-versions if it exists (#561) Fixes #526 --- README.md | 2 +- completions/_rtx | 4 +-- completions/rtx.fish | 2 +- ...r#use__tests__use_local_tool_versions.snap | 6 ++++ src/cli/use.rs | 34 +++++++++++++++---- src/config/config_file/mod.rs | 12 +++---- 6 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap diff --git a/README.md b/README.md index fd3c705da..9cafa6040 100644 --- a/README.md +++ b/README.md @@ -2318,7 +2318,7 @@ Options: Use the global config file (~/.config/rtx/config.toml) instead of the local one -p, --path - Specify a path to a config file + Specify a path to a config file or directory Examples: # set the current version of node to 20.x in .rtx.toml of current directory diff --git a/completions/_rtx b/completions/_rtx index c8234e8a5..9168a0afa 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1379,8 +1379,8 @@ If not specified, all current tools will be upgraded:' \ (use) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the tool(s) from config file]:TOOL: ' \ -'-p+[Specify a path to a config file]:PATH:_files' \ -'--path=[Specify a path to a config file]:PATH:_files' \ +'-p+[Specify a path to a config file or directory]:PATH:_files' \ +'--path=[Specify a path to a config file or directory]:PATH:_files' \ '-j+[Number of plugins and runtimes to install in parallel default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel diff --git a/completions/rtx.fish b/completions/rtx.fish index d98aebac9..6ac03d18e 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -635,7 +635,7 @@ complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from use" -l remove -d 'Remove the tool(s) from config file' -r -complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file' -r -F +complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file or directory' -r -F complete -c rtx -n "__fish_seen_subcommand_from use" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from use" -l log-level -d 'Set the log output verbosity' -r diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap new file mode 100644 index 000000000..936e0a274 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/use.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +tiny 3 + diff --git a/src/cli/use.rs b/src/cli/use.rs index a979f0fec..dddd980eb 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -6,7 +6,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::cli::local::local; use crate::config::{Config, MissingRuntimeBehavior}; -use crate::env::RTX_DEFAULT_CONFIG_FILENAME; +use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; @@ -45,7 +45,7 @@ pub struct Use { #[clap(short, long, overrides_with = "path")] global: bool, - /// Specify a path to a config file + /// Specify a path to a config file or directory #[clap(short, long, overrides_with = "global", value_hint = clap::ValueHint::FilePath)] path: Option, } @@ -63,8 +63,8 @@ impl Command for Use { .collect(); let path = match (self.global, self.path) { (true, _) => global_file(), - (false, Some(p)) => p, - (false, None) => dirs::CURRENT.join(&*RTX_DEFAULT_CONFIG_FILENAME), + (false, Some(p)) => config_file_from_dir(&p), + (false, None) => config_file_from_dir(&dirs::CURRENT), }; local( config, @@ -85,6 +85,19 @@ fn global_file() -> PathBuf { .unwrap_or_else(|| dirs::CONFIG.join("config.toml")) } +fn config_file_from_dir(p: &Path) -> PathBuf { + if !p.is_dir() { + return p.to_path_buf(); + } + let rtx_toml = p.join(&*RTX_DEFAULT_CONFIG_FILENAME); + let tool_versions = p.join(&*RTX_DEFAULT_TOOL_VERSIONS_FILENAME); + if tool_versions.exists() && !rtx_toml.exists() { + tool_versions + } else { + rtx_toml + } +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # set the current version of node to 20.x in .rtx.toml of current directory @@ -107,7 +120,7 @@ mod tests { #[test] fn test_use_local() { let cf_path = dirs::CURRENT.join(".test.rtx.toml"); - let _ = fs::remove_file(&cf_path); + fs::write(&cf_path, "").unwrap(); assert_cli!("use", "tiny@2"); assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); @@ -130,6 +143,15 @@ mod tests { let _ = fs::remove_file(&cf_path); } + #[test] + fn test_use_local_tool_versions() { + let cf_path = dirs::CURRENT.join(".test-tool-versions"); + fs::write(&cf_path, "").unwrap(); + + assert_cli!("use", "tiny@3"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + } + #[test] fn test_use_global() { let cf_path = dirs::CONFIG.join("config.toml"); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 3da442eed..b9f64da0b 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -132,15 +132,11 @@ impl dyn ConfigFile { } pub fn init(path: &Path, is_trusted: bool) -> Box { - if path.ends_with(env::RTX_DEFAULT_CONFIG_FILENAME.as_str()) - || path.extension() == Some("toml".as_ref()) - { - return Box::new(RtxToml::init(path, is_trusted)); - } else if path.ends_with(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) { - return Box::new(ToolVersions::init(path, is_trusted)); + match detect_config_file_type(path) { + Some(ConfigFileType::RtxToml) => Box::new(RtxToml::init(path, is_trusted)), + Some(ConfigFileType::ToolVersions) => Box::new(ToolVersions::init(path, is_trusted)), + _ => panic!("Unknown config file type: {}", path.display()), } - - panic!("Unknown config file type: {}", path.display()); } pub fn parse(path: &Path, is_trusted: bool) -> Result> { From ba1e77a6a0055bbf78830ec38d651dc1da992075 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 20 May 2023 16:26:05 -0500 Subject: [PATCH 0758/1891] remove future removal about changing behavior of ~/.tool-versions After thinking about this, I think we should keep the asdf-like behavior to make migrations easier for folks --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 9cafa6040..c0fa17fe0 100644 --- a/README.md +++ b/README.md @@ -929,8 +929,6 @@ Here are a list of the changes that will be made: already exists the format will be preserved.) - `rtx global` will modify `~/.config/rtx/config.toml` instead of `~/.tool-versions`. This path can be changed with `RTX_CONFIG_FILE`. -- `~/.tool-versions` will become simply another `.tool-versions` instead of being a special file - that is read anywhere such as from `/tmp`. - (more to be added) ## Directories From 31c22c3e0ae700ef7fc8a92c13cd368bb2bdfb61 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 09:12:31 -0500 Subject: [PATCH 0759/1891] added value_name property for tool arguments (#566) --- README.md | 105 +++++++++++++++++++++---------------------- completions/rtx.bash | 26 +++++------ src/cli/env.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/global.rs | 2 +- src/cli/install.rs | 2 +- src/cli/latest.rs | 2 +- src/cli/local.rs | 2 +- src/cli/ls_remote.rs | 2 +- src/cli/outdated.rs | 2 +- src/cli/shell.rs | 2 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 2 +- src/cli/use.rs | 2 +- src/cli/where.rs | 2 +- 15 files changed, 78 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index c0fa17fe0..5f9a39a8b 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ v20.0.0 - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) - - [rtx isn't working with tmux](#rtx-isnt-working-with-tmux) + - [rtx isn't working when calling from tmux or another shell initialization script](#rtx-isnt-working-when-calling-from-tmux-or-another-shell-initialization-script) - [How do I disable/force CLI color output?](#how-do-i-disableforce-cli-color-output) - [Is rtx secure?](#is-rtx-secure) - [Comparison to asdf](#comparison-to-asdf) @@ -133,14 +133,14 @@ v20.0.0 - [`rtx deactivate`](#rtx-deactivate) - [`rtx direnv activate`](#rtx-direnv-activate) - [`rtx doctor`](#rtx-doctor) - - [`rtx env [OPTIONS] [TOOL]...`](#rtx-env-options-tool) - - [`rtx exec [OPTIONS] [TOOL]... [-- ...]`](#rtx-exec-options-tool----command) + - [`rtx env [OPTIONS] [TOOL@VERSION]...`](#rtx-env-options-toolversion) + - [`rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]`](#rtx-exec-options-toolversion----command) - [`rtx implode [OPTIONS]`](#rtx-implode-options) - - [`rtx install [OPTIONS] [TOOL]...`](#rtx-install-options-tool) - - [`rtx latest `](#rtx-latest-tool) + - [`rtx install [OPTIONS] [TOOL@VERSION]...`](#rtx-install-options-toolversion) + - [`rtx latest `](#rtx-latest-toolversion) - [`rtx ls [OPTIONS]`](#rtx-ls-options) - - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-plugin-prefix) - - [`rtx outdated [TOOL]...`](#rtx-outdated-tool) + - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-toolversion-prefix) + - [`rtx outdated [TOOL@VERSION]...`](#rtx-outdated-toolversion) - [`rtx plugins install [OPTIONS] [NAME] [GIT_URL]`](#rtx-plugins-install-options-name-git_url) - [`rtx plugins link [OPTIONS] [PATH]`](#rtx-plugins-link-options-name-path) - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) @@ -154,13 +154,13 @@ v20.0.0 - [`rtx settings ls`](#rtx-settings-ls) - [`rtx settings set `](#rtx-settings-set-key-value) - [`rtx settings unset `](#rtx-settings-unset-key) - - [`rtx shell [OPTIONS] [TOOL]...`](#rtx-shell-options-tool) + - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - - [`rtx uninstall ...`](#rtx-uninstall-tool) - - [`rtx upgrade [TOOL]...`](#rtx-upgrade-tool) - - [`rtx use [OPTIONS] [TOOL]...`](#rtx-use-options-tool) + - [`rtx uninstall ...`](#rtx-uninstall-toolversion) + - [`rtx upgrade [TOOL@VERSION]...`](#rtx-upgrade-toolversion) + - [`rtx use [OPTIONS] [TOOL@VERSION]...`](#rtx-use-options-toolversion) - [`rtx version`](#rtx-version) - - [`rtx where `](#rtx-where-tool) + - [`rtx where `](#rtx-where-toolversion) - [`rtx which [OPTIONS] `](#rtx-which-options-bin_name) @@ -1113,7 +1113,7 @@ never modify PATH. For this type of setup, you can either call `rtx hook-env` ma you wish to update PATH, or use [shims](#shims) instead. Or if you only need to use rtx for certain commands, just prefix the commands with -[`rtx x --`](#rtx-exec-options-tool----command). +[`rtx x --`](#rtx-exec-options-toolversion----command). For example, `rtx x -- npm test` or `rtx x -- ./my_script.sh`. `rtx hook-env` will exit early in different situations if no changes have been made. This prevents @@ -1217,23 +1217,22 @@ This isn't important for usability reasons so much as making it so plugins conti call asdf commands. If you need to switch to/from asdf or work in a project with asdf users, you can set -[`RTX_ASDF_COMPAT=1`](#rtxasdfcompat1). That prevents +[`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). That prevents rtx from writing `.tool-versions` files that will not be compatible with asdf. Also consider using `.rtx.toml` instead which won't conflict with asdf setups. -### rtx isn't working with tmux +### rtx isn't working when calling from tmux or another shell initialization script -It's been reported that PATH doesn't work correctly with tmux. The fix seems to be calling `hook-env` -right after activating: +`rtx activate` will not update PATH until the shell prompt is displayed. So if you need to access a +tool provided by rtx before the prompt is displayed you must manually call `hook-env`: ```bash eval "$(rtx activate bash)" eval "$(rtx hook-env)" +python --version # will work only after calling hook-env explicitly ``` -This can also be useful if you need to use a runtime right away in an rc file. The default behavior -of `rtx activate` is that it will only run `hook-env` when the shell is about to be displayed, not -immediately after activating. Not calling `hook-env` immediately appears to work better with direnv. +For more information, see [What does `rtx activate` do?](#what-does-rtx-activate-do) ### How do I disable/force CLI color output? @@ -1671,7 +1670,7 @@ Examples: $ rtx doctor [WARN] plugin node is not installed ``` -### `rtx env [OPTIONS] [TOOL]...` +### `rtx env [OPTIONS] [TOOL@VERSION]...` ``` Exports env vars to activate rtx a single time @@ -1679,10 +1678,10 @@ Exports env vars to activate rtx a single time Use this if you don't want to permanently install rtx. It's not necessary to use this if you have `rtx activate` in your shell rc file. -Usage: env [OPTIONS] [TOOL]... +Usage: env [OPTIONS] [TOOL@VERSION]... Arguments: - [TOOL]... + [TOOL@VERSION]... Tool(s) to use Options: @@ -1702,7 +1701,7 @@ Examples: $ rtx env -s fish | source $ execx($(rtx env -s xonsh)) ``` -### `rtx exec [OPTIONS] [TOOL]... [-- ...]` +### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` ``` Execute a command with tool(s) set @@ -1715,10 +1714,10 @@ includes "node 20" but you run `rtx exec python@3.11`; it will still load node@2 The "--" separates runtimes from the commands to pass along to the subprocess. -Usage: exec [OPTIONS] [TOOL]... [-- ...] +Usage: exec [OPTIONS] [TOOL@VERSION]... [-- ...] Arguments: - [TOOL]... + [TOOL@VERSION]... Tool(s) to start e.g.: node@20 python@3.10 [COMMAND]... @@ -1759,7 +1758,7 @@ Options: --dry-run List directories that would be removed without actually removing them ``` -### `rtx install [OPTIONS] [TOOL]...` +### `rtx install [OPTIONS] [TOOL@VERSION]...` ``` Install a tool version @@ -1771,10 +1770,10 @@ Or you can call a tool version explicitly with `rtx exec @ -- ` +### `rtx latest ` ``` Gets the latest available version for a plugin -Usage: latest +Usage: latest Arguments: - + Tool to get the latest version of Examples: @@ -1859,7 +1858,7 @@ Examples: "python": [...] } ``` -### `rtx ls-remote [PREFIX]` +### `rtx ls-remote [PREFIX]` ``` List runtime versions available for install @@ -1867,10 +1866,10 @@ List runtime versions available for install note that the results are cached for 24 hours run `rtx cache clean` to clear the cache and get fresh results -Usage: ls-remote [PREFIX] +Usage: ls-remote [PREFIX] Arguments: - + Plugin to get versions for [PREFIX] @@ -1890,15 +1889,15 @@ Examples: 20.0.0 20.1.0 ``` -### `rtx outdated [TOOL]...` +### `rtx outdated [TOOL@VERSION]...` ``` [experimental] Shows outdated tool versions -Usage: outdated [TOOL]... +Usage: outdated [TOOL@VERSION]... Arguments: - [TOOL]... + [TOOL@VERSION]... Tool(s) to show outdated versions for e.g.: node@20 python@3.10 If not specified, all tools in global and local configs will be shown @@ -2201,17 +2200,17 @@ Arguments: Examples: $ rtx settings unset legacy_version_file ``` -### `rtx shell [OPTIONS] [TOOL]...` +### `rtx shell [OPTIONS] [TOOL@VERSION]...` ``` Sets a tool version for the current shell session Only works in a session where rtx is already activated. -Usage: shell [OPTIONS] [TOOL]... +Usage: shell [OPTIONS] [TOOL@VERSION]... Arguments: - [TOOL]... + [TOOL@VERSION]... Tool(s) to use Options: @@ -2253,35 +2252,35 @@ Examples: # trusts .rtx.toml in the current or parent directory $ rtx trust ``` -### `rtx uninstall ...` +### `rtx uninstall ...` ``` Removes runtime versions -Usage: uninstall ... +Usage: uninstall ... Arguments: - ... + ... Tool(s) to remove Examples: $ rtx uninstall node@18.0.0 # will uninstall specific version $ rtx uninstall node # will uninstall current node version ``` -### `rtx upgrade [TOOL]...` +### `rtx upgrade [TOOL@VERSION]...` ``` [experimental] Upgrades outdated tool versions -Usage: upgrade [TOOL]... +Usage: upgrade [TOOL@VERSION]... Arguments: - [TOOL]... + [TOOL@VERSION]... Tool(s) to upgrade e.g.: node@20 python@3.10 If not specified, all current tools will be upgraded ``` -### `rtx use [OPTIONS] [TOOL]...` +### `rtx use [OPTIONS] [TOOL@VERSION]...` ``` Change the active version of a tool locally or globally. @@ -2291,10 +2290,10 @@ By default, this will use an `.rtx.toml` file in the current directory. Use the --global flag to use the global config file instead. This replaces asdf's `local` and `global` commands, however those are still available in rtx. -Usage: use [OPTIONS] [TOOL]... +Usage: use [OPTIONS] [TOOL@VERSION]... Arguments: - [TOOL]... + [TOOL@VERSION]... Tool(s) to add to config file e.g.: node@20 If no version is specified, it will default to @latest @@ -2334,17 +2333,17 @@ Show rtx version Usage: version ``` -### `rtx where ` +### `rtx where ` ``` Display the installation path for a runtime Must be installed. -Usage: where +Usage: where Arguments: - + Tool(s) to look up e.g.: ruby@3 if "@" is specified, it will show the latest installed version diff --git a/completions/rtx.bash b/completions/rtx.bash index 9a45c6ab0..654506432 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1227,7 +1227,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -r -v -h --shell --json --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + opts="-s -j -r -v -h --shell --json --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1261,7 +1261,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -v -h --command --cd --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]... [COMMAND]..." + opts="-c -j -r -v -h --command --cd --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1299,7 +1299,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -v -h --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + opts="-j -r -v -h --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2159,7 +2159,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-f -v -j -r -h --force --verbose --debug --install-missing --jobs --log-level --raw --trace --help [TOOL]..." + opts="-f -v -j -r -h --force --verbose --debug --install-missing --jobs --log-level --raw --trace --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2185,7 +2185,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2211,7 +2211,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2275,7 +2275,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PREFIX]" + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2301,7 +2301,7 @@ _rtx() { return 0 ;; rtx__outdated) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2939,7 +2939,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -r -v -h --unset --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + opts="-u -j -r -v -h --unset --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2991,7 +2991,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help ..." + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3017,7 +3017,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3043,7 +3043,7 @@ _rtx() { return 0 ;; rtx__use) - opts="-g -p -j -r -v -h --pin --fuzzy --remove --global --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL]..." + opts="-g -p -j -r -v -h --pin --fuzzy --remove --global --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3107,7 +3107,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/cli/env.rs b/src/cli/env.rs index 16a632c82..73b35031c 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -19,7 +19,7 @@ pub struct Env { shell: Option, /// Tool(s) to use - #[clap(value_parser = ToolArgParser)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, /// Output in JSON format diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 9e01be4a1..87bfa6341 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -30,7 +30,7 @@ use crate::toolset::ToolsetBuilder; pub struct Exec { /// Tool(s) to start /// e.g.: node@20 python@3.10 - #[clap(value_parser = ToolArgParser)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] pub tool: Vec, /// Command string to execute (same as --command) diff --git a/src/cli/global.rs b/src/cli/global.rs index 2c7430b79..58d35e77a 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -26,7 +26,7 @@ pub struct Global { /// e.g.: node@20 /// If this is a single tool with no version, the current value of the global /// .tool-versions will be displayed - #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] tool: Option>, /// Save exact version to `~/.tool-versions` diff --git a/src/cli/install.rs b/src/cli/install.rs index 2c4ec5bf3..fb2879c41 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -35,7 +35,7 @@ use crate::ui::progress_report::ProgressReport; pub struct Install { /// Tool(s) to install /// e.g.: node@20 - #[clap(value_parser = ToolArgParser)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] tool: Option>, /// Force reinstall even if already installed diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 2aebdc828..0ede8329f 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -12,7 +12,7 @@ use crate::toolset::ToolVersionRequest; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Latest { /// Tool to get the latest version of - #[clap(value_parser = ToolArgParser)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] tool: ToolArg, /// The version prefix to use when querying the latest version diff --git a/src/cli/local.rs b/src/cli/local.rs index f2082fd46..ba187b5a3 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -25,7 +25,7 @@ pub struct Local { /// e.g.: node@20 /// if this is a single tool with no version, /// the current value of .tool-versions/.rtx.toml will be displayed - #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] tool: Option>, /// Recurse up to find a .tool-versions file rather than using the current directory only diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index db3e4801b..318b4e93d 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -19,7 +19,7 @@ use crate::ui::prompt; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = ["list-all", "list-remote"])] pub struct LsRemote { /// Plugin to get versions for - #[clap(value_parser = ToolArgParser)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] plugin: ToolArg, /// The version prefix to use when querying the latest version diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 7c36fbcf4..78fd45b06 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -18,7 +18,7 @@ pub struct Outdated { /// Tool(s) to show outdated versions for /// e.g.: node@20 python@3.10 /// If not specified, all tools in global and local configs will be shown - #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] pub tool: Vec, } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 7a2c7b6be..763190cda 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -16,7 +16,7 @@ use crate::toolset::{ToolSource, ToolsetBuilder}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Shell { /// Tool(s) to use - #[clap(value_parser = ToolArgParser)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, /// Removes a previously set version diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 80eccef3a..0714e67e5 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -13,7 +13,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct Uninstall { /// Tool(s) to remove - #[clap(required = true, value_parser = ToolArgParser)] + #[clap(required = true, value_name="TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, } diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 70db4d523..4b27290d0 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -24,7 +24,7 @@ pub struct Upgrade { /// Tool(s) to upgrade /// e.g.: node@20 python@3.10 /// If not specified, all current tools will be upgraded - #[clap(value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] pub tool: Vec, } diff --git a/src/cli/use.rs b/src/cli/use.rs index dddd980eb..cf64283c2 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -23,7 +23,7 @@ pub struct Use { /// Tool(s) to add to config file /// e.g.: node@20 /// If no version is specified, it will default to @latest - #[clap(value_parser = ToolArgParser, verbatim_doc_comment, required_unless_present = "remove")] + #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment, required_unless_present = "remove")] tool: Vec, /// Save exact version to config file diff --git a/src/cli/where.rs b/src/cli/where.rs index 09336fdd3..abbf6744c 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -18,7 +18,7 @@ pub struct Where { /// if "@" is specified, it will show the latest installed version /// that matches the prefix /// otherwise, it will show the current, active installed version - #[clap(required = true, value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(required = true, value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] tool: ToolArg, /// the version prefix to use when querying the latest version From 31499b126135e45d5d7ed4da1b24662cbf0be353 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 09:40:26 -0500 Subject: [PATCH 0760/1891] added --tool flag to `rtx which` (#565) Fixes #430 --- README.md | 6 +++- completions/_rtx | 6 +++- completions/rtx.bash | 10 +++++- completions/rtx.fish | 2 ++ .../rtx__cli__which__tests__which_tool.snap | 6 ++++ src/cli/which.rs | 28 +++++++++++++++-- src/plugins/script_manager.rs | 31 +++++++++++++++++++ 7 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__which__tests__which_tool.snap diff --git a/README.md b/README.md index 5f9a39a8b..8bf115d0e 100644 --- a/README.md +++ b/README.md @@ -2370,7 +2370,7 @@ Usage: which [OPTIONS] Arguments: - + The bin name to look up Options: --plugin @@ -2379,6 +2379,10 @@ Options: --version Show the version instead of the path + -t, --tool + Use a specific tool@version + e.g.: `rtx which npm --tool=node@20` + Examples: $ rtx which node /home/username/.local/share/rtx/installs/node/20.0.0/bin/node diff --git a/completions/_rtx b/completions/_rtx index 9168a0afa..b7d5c40ed 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1459,6 +1459,10 @@ used for asdf compatibility:' \ ;; (which) _arguments "${_arguments_options[@]}" \ +'-t+[Use a specific tool@version +e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ +'--tool=[Use a specific tool@version +e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ '-j+[Number of plugins and runtimes to install in parallel default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel @@ -1477,7 +1481,7 @@ Sets --jobs=1]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -':bin_name:' \ +':bin_name -- The bin name to look up:' \ && ret=0 ;; (render-help) diff --git a/completions/rtx.bash b/completions/rtx.bash index 654506432..f8c236d88 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3133,12 +3133,20 @@ _rtx() { return 0 ;; rtx__which) - opts="-j -r -v -h --plugin --version --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-t -j -r -v -h --plugin --version --tool --debug --install-missing --jobs --log-level --raw --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --tool) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 6ac03d18e..a815003d1 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -672,6 +672,8 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from where" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from which" -s t -l tool -d 'Use a specific tool@version +e.g.: `rtx which npm --tool=node@20`' -r complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap b/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap new file mode 100644 index 000000000..9d5e4e14e --- /dev/null +++ b/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/which.rs +expression: output +--- +~/data/installs/dummy/1.0.1/bin/dummy + diff --git a/src/cli/which.rs b/src/cli/which.rs index 57c5e9202..debf0b25e 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -1,14 +1,16 @@ use color_eyre::eyre::{eyre, Result}; +use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::toolset::ToolsetBuilder; +use crate::toolset::{Toolset, ToolsetBuilder}; /// Shows the path that a bin name points to #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Which { + /// The bin name to look up #[clap()] pub bin_name: String, @@ -19,11 +21,16 @@ pub struct Which { /// Show the version instead of the path #[clap(long, conflicts_with = "plugin")] pub version: bool, + + /// Use a specific tool@version + /// e.g.: `rtx which npm --tool=node@20` + #[clap(short, long, value_name = "TOOL@VERSION", value_parser=ToolArgParser, verbatim_doc_comment)] + pub tool: Option, } impl Command for Which { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + let ts = self.get_toolset(&mut config)?; match ts.which(&config, &self.bin_name) { Some((p, tv)) => { @@ -42,6 +49,17 @@ impl Command for Which { } } +impl Which { + fn get_toolset(&self, config: &mut Config) -> Result { + let mut tsb = ToolsetBuilder::new(); + if let Some(tool) = &self.tool { + tsb = tsb.with_args(&[tool.clone()]); + } + let ts = tsb.build(config)?; + Ok(ts) + } +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx which node @@ -80,4 +98,10 @@ mod tests { assert_cli!("global", "dummy@ref:master"); assert_cli!("uninstall", "dummy@1.0.0"); } + + #[test] + fn test_which_tool() { + assert_cli!("install", "dummy@1.0.1"); + assert_cli_snapshot!("which", "dummy", "--tool=dummy@1.0.1"); + } } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 2aa9231c9..746af59a6 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -178,3 +178,34 @@ impl ScriptManager { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_script_manager() { + let plugin_path = PathBuf::from("/tmp/asdf"); + let script_manager = ScriptManager::new(plugin_path.clone()); + assert_eq!(script_manager.plugin_path, plugin_path); + assert_eq!(script_manager.plugin_name, "asdf"); + } + + #[test] + fn test_get_script_path() { + let plugin_path = PathBuf::from("/tmp/asdf"); + let script_manager = ScriptManager::new(plugin_path.clone()); + + let test = |script, expected| { + assert_eq!(script_manager.get_script_path(script), expected); + }; + + test( + &Script::LatestStable, + plugin_path.join("bin").join("latest-stable"), + ); + + let script = Script::RunExternalCommand(PathBuf::from("/bin/ls"), vec!["-l".to_string()]); + test(&script, PathBuf::from("/bin/ls")); + } +} From f3094cee2834574cfd7045ee6ac68aea2467b7d3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 10:51:59 -0500 Subject: [PATCH 0761/1891] add some test coverage to fix flaky coverage count (#567) --- src/config/config_file/rtx_toml.rs | 11 +++++++++++ src/env_diff.rs | 2 +- src/plugins/script_manager.rs | 7 ++++++- src/toolset/tool_version_list.rs | 22 +++++++++++++++++++++- test/data/plugins/dummy/bin/latest-stable | 5 +++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 79b2c8a33..d373fc39a 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -886,4 +886,15 @@ mod tests { assert_display_snapshot!(cf.dump(), @r###" "###); } + + #[test] + fn test_fail_with_unknown_key() { + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let err = cf + .parse(&formatdoc! {r#" + invalid_key = true + "#}) + .unwrap_err(); + assert_snapshot!(err.to_string(), @"unknown key: invalid_key"); + } } diff --git a/src/env_diff.rs b/src/env_diff.rs index 7b6684816..a1bac7a43 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -357,7 +357,7 @@ mod tests { #[test] fn test_invalid_escape_sequence() { - let input = r#""\g""#; + let input = r#""\g\""#; let output = normalize_escape_sequences(input); // just warns assert_str_eq!(output, r#"\g"#); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 746af59a6..eeef80ae4 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -93,9 +93,14 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { impl ScriptManager { pub fn new(plugin_path: PathBuf) -> Self { + let mut env = INITIAL_ENV.clone(); + if let Some(failure) = env::var_os("RTX_FAILURE") { + // used for testing failure cases + env.insert("RTX_FAILURE".into(), failure); + } Self { plugin_name: basename(&plugin_path).expect("invalid plugin path"), - env: INITIAL_ENV.clone(), + env, plugin_path, } } diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index cb6bb3d8e..8106d9918 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -40,7 +40,8 @@ impl ToolVersionList { #[cfg(test)] mod tests { - + use crate::{dirs, env}; + use std::fs; use std::sync::Arc; use super::*; @@ -62,4 +63,23 @@ mod tests { tvl.resolve(&config, true); assert_eq!(tvl.versions.len(), 1); } + + #[test] + fn test_tool_version_list_failure() { + env::set_var("RTX_FAILURE", "1"); + fs::remove_dir_all(dirs::CACHE.join("dummy")).unwrap(); + let mut config = Config::default(); + let plugin_name = "dummy".to_string(); + let plugin = ExternalPlugin::new(&plugin_name); + let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); + config.tools.insert(plugin_name.clone(), Arc::new(tool)); + let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); + tvl.requests.push(( + ToolVersionRequest::new(plugin_name, "latest"), + ToolVersionOptions::default(), + )); + tvl.resolve(&config, true); + assert_eq!(tvl.versions.len(), 0); + env::remove_var("RTX_FAILURE"); + } } diff --git a/test/data/plugins/dummy/bin/latest-stable b/test/data/plugins/dummy/bin/latest-stable index afe7d1ba4..dc341a517 100755 --- a/test/data/plugins/dummy/bin/latest-stable +++ b/test/data/plugins/dummy/bin/latest-stable @@ -8,3 +8,8 @@ get_latest_stable() { } get_latest_stable "$1" + +if [ "$RTX_FAILURE" = "1" ]; then + echo "error: RTX_FAILURE set" >&2 + exit 1 +fi From 8d11139ba172b28652aef85622d0280b4380e666 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 11:35:32 -0500 Subject: [PATCH 0762/1891] do not automatically enable verbose if not tty (#568) This was done to show the plain progress report --- src/cli/install.rs | 4 ++-- src/cli/local.rs | 2 +- src/cli/ls_remote.rs | 2 +- src/cli/plugins/install.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/prune.rs | 2 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 2 +- src/config/config_file/mod.rs | 2 +- src/config/mod.rs | 4 ++++ src/config/settings.rs | 2 +- src/plugins/core/python.rs | 1 - src/toolset/builder.rs | 2 +- src/ui/progress_report.rs | 8 ++++---- 14 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/cli/install.rs b/src/cli/install.rs index fb2879c41..65743d7ac 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -62,7 +62,7 @@ impl Command for Install { impl Install { fn install_runtimes(&self, mut config: Config, runtimes: &[ToolArg]) -> Result<()> { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); let ts = ToolsetBuilder::new() .with_latest_versions() .build(&mut config)?; @@ -144,7 +144,7 @@ impl Install { if ts.list_missing_versions(&config).is_empty() { warn!("no runtimes to install"); } - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); ts.install_missing(&mut config, mpr)?; Ok(()) diff --git a/src/cli/local.rs b/src/cli/local.rs index ba187b5a3..03cb3ee49 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -143,7 +143,7 @@ fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result< let mut ts = cf.to_toolset().clone(); ts.resolve(config); if !ts.list_missing_versions(config).is_empty() { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); ts.install_missing(config, mpr)?; } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 318b4e93d..6037836c8 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -70,7 +70,7 @@ impl LsRemote { "Plugin {} is not installed, would you like to install it?", tool.name ))? { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); let mut pr = mpr.add(); tool.install(config, &mut pr, false)?; return Ok(()); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 415f78fb1..e93ea851a 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -51,7 +51,7 @@ pub struct PluginsInstall { impl Command for PluginsInstall { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); if self.all { return self.install_all_missing_plugins(&mut config, mpr); } diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 5ce980afe..e080f53be 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -17,7 +17,7 @@ pub struct PluginsUninstall { impl Command for PluginsUninstall { fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); for plugin_name in &self.plugin { self.uninstall_one(&config, plugin_name, &mpr)?; diff --git a/src/cli/prune.rs b/src/cli/prune.rs index d7c05d714..7fa115d71 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -56,7 +56,7 @@ impl Command for Prune { impl Prune { fn delete(&self, config: &mut Config, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); for (p, tv) in to_delete { let mut pr = mpr.add(); p.decorate_progress_bar(&mut pr, Some(&tv)); diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 0714e67e5..8660be96d 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -40,7 +40,7 @@ impl Command for Uninstall { }) .collect::>>()?; - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); for (plugin, tv) in tool_versions { if !plugin.is_version_installed(&tv) { warn!("{} is not installed", style(&tv).cyan().for_stderr()); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 4b27290d0..8e6e4c77a 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -61,7 +61,7 @@ type GroupedToolVersions = Vec<(Arc, Vec<(ToolVersion, String)>)>; impl Upgrade { fn upgrade(&self, config: &mut Config, outdated: OutputVec) -> Result<()> { - let mut mpr = MultiProgressReport::new(config.settings.verbose); + let mut mpr = MultiProgressReport::new(config.show_progress_bars()); ThreadPoolBuilder::new() .num_threads(config.settings.jobs) .build()? diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index b9f64da0b..f9b440dc2 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -56,7 +56,7 @@ impl dyn ConfigFile { runtimes: &[ToolArg], pin: bool, ) -> Result<()> { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); let mut ts = self.to_toolset().to_owned(); ts.resolve(config); let mut plugins_to_update = HashMap::new(); diff --git a/src/config/mod.rs b/src/config/mod.rs index ec9047f06..9ffca0c6a 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -136,6 +136,10 @@ impl Config { env::var("__RTX_DIFF").is_ok() } + pub fn show_progress_bars(&self) -> bool { + self.settings.verbose || !console::user_attended_stderr() + } + pub fn resolve_alias(&self, plugin_name: &PluginName, v: &str) -> Result { if let Some(plugin_aliases) = self.aliases.get(plugin_name) { if let Some(alias) = plugin_aliases.get(v) { diff --git a/src/config/settings.rs b/src/config/settings.rs index 43b061f79..6856fab53 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -36,7 +36,7 @@ impl Default for Settings { legacy_version_file: true, plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), trusted_config_paths: RTX_TRUSTED_CONFIG_PATHS.clone(), - verbose: *RTX_VERBOSE || !console::user_attended_stderr(), + verbose: *RTX_VERBOSE, asdf_compat: *RTX_ASDF_COMPAT, jobs: *RTX_JOBS, shorthands_file: RTX_SHORTHANDS_FILE.clone(), diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 919f8e633..8b198f7b1 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -191,7 +191,6 @@ impl Plugin for PythonPlugin { cmd.stdin_string(patch); } if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { - dbg!(patches_dir); let patch_file = patches_dir.join(format!("{}.patch", tv.version)); if patch_file.exists() { pr.set_message(format!("with patch file: {}", patch_file.display())); diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 1e700757d..5a3531d9e 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -46,7 +46,7 @@ impl ToolsetBuilder { toolset.resolve(config); if self.install_missing { - let mpr = MultiProgressReport::new(config.settings.verbose); + let mpr = MultiProgressReport::new(config.show_progress_bars()); toolset.install_missing(config, mpr)?; } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 4c7a4dd12..85548e40d 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -79,19 +79,19 @@ impl ProgressReport { pub fn set_message>(&self, message: S) { match &self.pb { Some(pb) => pb.set_message(message.as_ref().replace('\r', "")), - None => eprintln!("{}{}", self.prefix, message.as_ref()), + None => eprintln!("{}", message.as_ref()), } } pub fn println>(&self, message: S) { match &self.pb { Some(pb) => pb.println(message), - None => eprintln!("{}", message.as_ref()), + None => println!("{}", message.as_ref()), } } pub fn warn>(&self, message: S) { match &self.pb { Some(pb) => pb.println(format!("{} {}", style("[WARN]").yellow(), message.as_ref())), - None => eprintln!("{}{}", self.prefix, message.as_ref()), + None => eprintln!("{}", message.as_ref()), } } pub fn error(&self) { @@ -118,7 +118,7 @@ impl ProgressReport { pb.set_style(SUCCESS_TEMPLATE.clone()); pb.finish_with_message(message); } - None => eprintln!("{}{}", self.prefix, message.into()), + None => eprintln!("{}", message.into()), } } // pub fn clear(&self) { From 7039693ff8df9e20ad2359e1a20e045ecd020ae4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 12:28:58 -0500 Subject: [PATCH 0763/1891] minor refactor --- src/plugins/external_plugin.rs | 14 ++++++-------- src/plugins/script_manager.rs | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 7f8942533..1dc83f642 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -118,9 +118,9 @@ impl ExternalPlugin { } fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { - let stdout = - self.script_man - .read(settings, &Script::ListLegacyFilenames, settings.verbose)?; + let stdout = self + .script_man + .read(settings, &Script::ListLegacyFilenames)?; Ok(self.parse_legacy_filenames(&stdout)) } fn parse_legacy_filenames(&self, data: &str) -> Vec { @@ -129,7 +129,7 @@ impl ExternalPlugin { fn fetch_latest_stable(&self, settings: &Settings) -> Result> { let latest_stable = self .script_man - .read(settings, &Script::LatestStable, settings.verbose)? + .read(settings, &Script::LatestStable)? .trim() .to_string(); Ok(if latest_stable.is_empty() { @@ -152,9 +152,7 @@ impl ExternalPlugin { self.script_man.script_exists(&Script::LatestStable) } fn fetch_aliases(&self, settings: &Settings) -> Result> { - let stdout = self - .script_man - .read(settings, &Script::ListAliases, settings.verbose)?; + let stdout = self.script_man.read(settings, &Script::ListAliases)?; Ok(self.parse_aliases(&stdout)) } fn parse_aliases(&self, data: &str) -> Vec<(String, String)> { @@ -483,7 +481,7 @@ impl Plugin for ExternalPlugin { trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); let legacy_version = match self.script_man.script_exists(&script) { - true => self.script_man.read(settings, &script, settings.verbose)?, + true => self.script_man.read(settings, &script)?, false => fs::read_to_string(legacy_file)?, } .trim() diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index eeef80ae4..b7ad7fe57 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -155,9 +155,9 @@ impl ScriptManager { } } - pub fn read(&self, settings: &Settings, script: &Script, verbose: bool) -> Result { + pub fn read(&self, settings: &Settings, script: &Script) -> Result { let mut cmd = self.cmd(settings, script); - if !verbose && !settings.raw { + if !settings.verbose { cmd = cmd.stderr_null(); } cmd.read() From 82592f5f7899323b5b44e07de54830a755600273 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 12:34:06 -0500 Subject: [PATCH 0764/1891] tweak badge color in README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8bf115d0e..5dbdb88cf 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ @@ -22,7 +22,7 @@ ## 30 Second Demo The following shows using rtx to install different versions -of [nodejs](https://nodejs.org). +of [node](https://nodejs.org). Note that calling `which node` gives us a real path to node, not a shim. [![demo](./docs/demo.gif)](./docs/demo.gif) From 9bdc9b570ea36d7cb87b6890d36278ca7a0b4b11 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 13:29:07 -0500 Subject: [PATCH 0765/1891] added test for plugin ref in rtx.toml (#569) --- e2e/.e2e.rtx.toml | 8 -------- e2e/.gitignore | 1 + e2e/config/.e2e.rtx.toml | 4 ++++ e2e/test_install | 7 +++++++ e2e/test_local | 24 ++++++++++++++++++++---- src/ui/progress_report.rs | 2 +- 6 files changed, 33 insertions(+), 13 deletions(-) delete mode 100644 e2e/.e2e.rtx.toml create mode 100755 e2e/test_install diff --git a/e2e/.e2e.rtx.toml b/e2e/.e2e.rtx.toml deleted file mode 100644 index 90d7fabe1..000000000 --- a/e2e/.e2e.rtx.toml +++ /dev/null @@ -1,8 +0,0 @@ -env_file = '.test-env' -env_path = ["/root", "./cwd"] -[env] -FOO = "bar" - -[tools] -tiny = "latest" -#golang = {version="1.19.5", foo="bar"} diff --git a/e2e/.gitignore b/e2e/.gitignore index 8de18a6f1..172c28ab5 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,3 +1,4 @@ +.e2e.rtx.toml .local .rtx .cache diff --git a/e2e/config/.e2e.rtx.toml b/e2e/config/.e2e.rtx.toml index 90d7fabe1..58a27e4e8 100644 --- a/e2e/config/.e2e.rtx.toml +++ b/e2e/config/.e2e.rtx.toml @@ -1,3 +1,4 @@ +#:schema ../../schema/rtx.json env_file = '.test-env' env_path = ["/root", "./cwd"] [env] @@ -6,3 +7,6 @@ FOO = "bar" [tools] tiny = "latest" #golang = {version="1.19.5", foo="bar"} + +[plugins] +tiny-ref = "https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4" diff --git a/e2e/test_install b/e2e/test_install new file mode 100755 index 000000000..0ff52b8a3 --- /dev/null +++ b/e2e/test_install @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +# installs with repo in .rtx.toml +rtx i tiny-ref@latest -f +rtx plugins uninstall tiny-ref diff --git a/e2e/test_local b/e2e/test_local index 7f98f130d..64c654b7a 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -20,7 +20,8 @@ export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall assert_raises "rtx uninstall shfmt@3.6.0" -assert "rtx local" "env_file = '.test-env' +assert "rtx local" "#:schema ../../schema/rtx.json +env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -28,10 +29,14 @@ FOO = \"bar\" [tools] tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} + +[plugins] +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" " rtx local shfmt@3.5.0 -assert "rtx local" "env_file = '.test-env' +assert "rtx local" "#:schema ../../schema/rtx.json +env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -40,6 +45,9 @@ FOO = \"bar\" tiny = \"latest\" shfmt = \"3.5.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} + +[plugins] +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" " rtx exec -- shfmt --version >&2 @@ -51,7 +59,8 @@ assert_raises "rtx uninstall shfmt@3.6.0" assert_raises "rtx local shfmt --install-missing" rtx local shfmt@3.6.0 -assert "rtx local" "env_file = '.test-env' +assert "rtx local" "#:schema ../../schema/rtx.json +env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -60,6 +69,9 @@ FOO = \"bar\" tiny = \"latest\" shfmt = \"3.6.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} + +[plugins] +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" " rtx exec -- shfmt --version >&2 @@ -68,7 +80,8 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then fi rtx local --rm shfmt -assert "rtx local" "env_file = '.test-env' +assert "rtx local" "#:schema ../../schema/rtx.json +env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" @@ -76,6 +89,9 @@ FOO = \"bar\" [tools] tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} + +[plugins] +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" " diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 85548e40d..09b7e9f01 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -85,7 +85,7 @@ impl ProgressReport { pub fn println>(&self, message: S) { match &self.pb { Some(pb) => pb.println(message), - None => println!("{}", message.as_ref()), + None => eprintln!("{}", message.as_ref()), } } pub fn warn>(&self, message: S) { From 3d95eca9d16b02af0e8d27ed0919eeee0cf0f427 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 13:39:39 -0500 Subject: [PATCH 0766/1891] updated ctrlc --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c766a6983..203ba4616 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,12 +440,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.2.5" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639" +checksum = "04d778600249295e82b6ab12e291ed9029407efee0cfb7baf67157edc65964df" dependencies = [ "nix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] From 4c6c075b3f67824bf4b717420821932265c06254 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 13:40:55 -0500 Subject: [PATCH 0767/1891] chore: Release --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 203ba4616..bd111021a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,9 +137,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" dependencies = [ "memchr", "serde", @@ -1549,7 +1549,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.30.1" +version = "1.30.2" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 11a4a9aca..e3c654d6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.30.1" +version = "1.30.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 5dbdb88cf..d5342a315 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.30.1 +rtx 1.30.2 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -311,7 +311,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.30.1/rtx-v1.30.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.30.2/rtx-v1.30.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 007190cf0..6be6984aa 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.30.1"; + version = "1.30.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 5e785309e..6e7f97b8d 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.30.1" +.TH rtx 1 "rtx 1.30.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -145,6 +145,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.30.1 +v1.30.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index cf778d343..6b32bc8b9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.30.1 +Version: 1.30.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From b486f135e8822d3a77de617c297a484bbb80f3d0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 13:45:24 -0500 Subject: [PATCH 0768/1891] force ctrlc to be less than 3.3.x See #570 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd111021a..f31997d9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,12 +440,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.3.0" +version = "3.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d778600249295e82b6ab12e291ed9029407efee0cfb7baf67157edc65964df" +checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639" dependencies = [ "nix", - "windows-sys 0.48.0", + "windows-sys 0.45.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e3c654d6a..fdfb34ff6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" console = "0.15.6" -ctrlc = "3.2.3" +ctrlc = "<3.3" dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" dotenvy = "0.15.6" From ba8a31ae386148e00d2f6102daa9c854c584307c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 13:49:31 -0500 Subject: [PATCH 0769/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f31997d9f..46fba3a82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1549,7 +1549,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.30.2" +version = "1.30.3" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index fdfb34ff6..9bf8004df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.30.2" +version = "1.30.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index d5342a315..1591fbee8 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.30.2 +rtx 1.30.3 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -311,7 +311,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.30.2/rtx-v1.30.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.30.3/rtx-v1.30.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 6be6984aa..740d819ba 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.30.2"; + version = "1.30.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 6e7f97b8d..196930ee3 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.30.2" +.TH rtx 1 "rtx 1.30.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -145,6 +145,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.30.2 +v1.30.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6b32bc8b9..bba639a50 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.30.2 +Version: 1.30.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 61d8ee7728e32d7e0b49b3758e744aaa239dc12d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 14:18:25 -0500 Subject: [PATCH 0770/1891] remove sigint handling (#571) This was cargo-cult from reading https://github.com/direnv/direnv/commit/a4632773637ee1a6b08fa81043cacd24ea941489 I don't think we actually need it and it seems to be causing #570 --- src/shell/bash.rs | 2 -- src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap | 2 -- src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap | 2 -- src/shell/zsh.rs | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 62655404f..f833b17bb 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -39,9 +39,7 @@ impl Shell for Bash { _rtx_hook() {{ local previous_exit_status=$?; - trap -- '' SIGINT; eval "$(rtx hook-env{status} -s bash)"; - trap - SIGINT; return $previous_exit_status; }}; if ! [[ "${{PROMPT_COMMAND:-}}" =~ _rtx_hook ]]; then diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 463b631f9..87e882e54 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -26,9 +26,7 @@ rtx() { _rtx_hook() { local previous_exit_status=$?; - trap -- '' SIGINT; eval "$(rtx hook-env --status -s bash)"; - trap - SIGINT; return $previous_exit_status; }; if ! [[ "${PROMPT_COMMAND:-}" =~ _rtx_hook ]]; then diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 304662338..7f0b514a3 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -25,9 +25,7 @@ rtx() { } _rtx_hook() { - trap -- '' SIGINT; eval "$(rtx hook-env --status -s zsh)"; - trap - SIGINT; } typeset -ag precmd_functions; if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 4edaeef9d..86931ea05 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -42,9 +42,7 @@ impl Shell for Zsh { }} _rtx_hook() {{ - trap -- '' SIGINT; eval "$(rtx hook-env{status} -s zsh)"; - trap - SIGINT; }} typeset -ag precmd_functions; if [[ -z "${{precmd_functions[(r)_rtx_hook]+1}}" ]]; then From b50b097932c6bc052100ed489ee759c5d118e782 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 15:38:58 -0500 Subject: [PATCH 0771/1891] update msrv to rust 1.65.0 (#572) required by time-core --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9bf8004df..0e8947b67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] include = ["src/**/*.rs", "src/plugins/core/assets/**", "/build.rs", "/LICENSE", "/README.md", "/Cargo.lock"] -rust-version = "1.64.0" +rust-version = "1.65.0" build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 7d8b4999fc967d6d2b0ae27ce2b8893f2e0ffcc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 02:30:32 +0000 Subject: [PATCH 0772/1891] chore(deps): bump base64 from 0.21.0 to 0.21.1 (#573) Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.21.0 to 0.21.1. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/commits) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46fba3a82..fe3d6cce1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" [[package]] name = "bitflags" From 3d15766df11134bd332aff0e9ca0446bcafc787f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 21 May 2023 21:34:44 -0500 Subject: [PATCH 0773/1891] run unit tests on all coverage workers to reduce flaky coverage --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index e5acda924..6c8b9d3b7 100644 --- a/justfile +++ b/justfile @@ -55,10 +55,10 @@ test-coverage: export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$PWD/target}" export PATH="${CARGO_TARGET_DIR}/debug:$PATH" + cargo test cargo build --all-features ./e2e/run_all_tests if [[ "${TEST_TRANCHE:-}" == 0 ]]; then - cargo test rtx trust rtx implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then From c6680500e0e410e577510d375c98ab80ce521a03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 02:56:16 +0000 Subject: [PATCH 0774/1891] chore(deps): bump console from 0.15.6 to 0.15.7 (#575) Bumps [console](https://github.com/console-rs/console) from 0.15.6 to 0.15.7. - [Changelog](https://github.com/console-rs/console/blob/master/CHANGELOG.md) - [Commits](https://github.com/console-rs/console/compare/0.15.6...0.15.7) --- updated-dependencies: - dependency-name: console dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe3d6cce1..bdad2c262 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -330,9 +330,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "console" -version = "0.15.6" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0525278dce688103060006713371cedbad27186c7d913f33d866b498da0f595" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 0e8947b67..5ecc003eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ clap = { version = "4.2.5", features = ["env", "derive", "string"] } clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" -console = "0.15.6" +console = "0.15.7" ctrlc = "<3.3" dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" From a6c345050a1ff6de5316f04acea6df555110bff6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 22 May 2023 19:40:42 -0500 Subject: [PATCH 0775/1891] added timeout on fetching remote versions (#577) See #539 --- src/env.rs | 10 +++++++++ src/plugins/core/node.rs | 40 ++++++++++++++++++++++++---------- src/plugins/core/python.rs | 24 ++++++++++++++++---- src/plugins/external_plugin.rs | 21 ++++++++++-------- 4 files changed, 71 insertions(+), 24 deletions(-) diff --git a/src/env.rs b/src/env.rs index a7bd1fdef..63390d236 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,6 +1,7 @@ use std::collections::{HashMap, HashSet}; pub use std::env::*; use std::path::PathBuf; +use std::time::Duration; use itertools::Itertools; use log::LevelFilter; @@ -54,6 +55,9 @@ pub static RTX_JOBS: Lazy = Lazy::new(|| { .and_then(|v| v.parse::().ok()) .unwrap_or(4) }); +pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { + var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) +}); /// true if inside a script like bin/exec-env or bin/install /// used to prevent infinite loops @@ -181,6 +185,12 @@ fn var_confirm(key: &str) -> Confirm { } } +fn var_duration(key: &str) -> Option { + var(key) + .ok() + .map(|v| v.parse::().unwrap().into()) +} + /// this returns the environment as if __RTX_DIFF was reversed. /// putting the shell back into a state before hook-env was run fn get_pristine_env( diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index defaa48d9..155fba77e 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,17 +1,21 @@ use std::collections::BTreeMap; use std::env::{join_paths, split_paths}; -use std::fs; use std::path::{Path, PathBuf}; use std::process::exit; +use std::sync::mpsc; use std::time::Duration; +use std::{fs, thread}; use clap::Command; -use color_eyre::eyre::Result; +use color_eyre::eyre::{Context, Result}; use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::{RTX_EXE, RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, RTX_NODE_VERBOSE_INSTALL}; +use crate::env::{ + RTX_EXE, RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, + RTX_NODE_VERBOSE_INSTALL, +}; use crate::file::create_dir_all; use crate::git::Git; use crate::lock_file::LockFile; @@ -91,13 +95,27 @@ impl NodePlugin { self.node_build_path().display() ); let git = Git::new(self.node_build_path()); - git.update(None)?; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let result = git.update(None); + tx.send(result).unwrap(); + }); + rx.recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) + .context("timed out updating node-build")??; Ok(()) } fn fetch_remote_versions(&self) -> Result> { self.install_or_update_node_build()?; - let output = cmd!(self.node_build_bin(), "--definitions").read()?; + let node_build_bin = self.node_build_bin(); + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let output = cmd!(node_build_bin, "--definitions").read(); + tx.send(output).unwrap(); + }); + let output = rx + .recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) + .context("timed out fetching node versions")??; let versions = output .split('\n') .filter(|s| regex!(r"^[0-9].+$").is_match(s)) @@ -206,6 +224,12 @@ impl Plugin for NodePlugin { } } + fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + let body = fs::read_to_string(path)?; + // trim "v" prefix + Ok(body.trim().strip_prefix('v').unwrap_or(&body).to_string()) + } + fn external_commands(&self) -> Result> { if self.legacy_file_support { // sort of a hack to get this not to display for nodejs @@ -274,10 +298,4 @@ impl Plugin for NodePlugin { self.install_default_packages(&config.settings, tv, pr)?; Ok(()) } - - fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { - let body = fs::read_to_string(path)?; - // trim "v" prefix - Ok(body.trim().strip_prefix('v').unwrap_or(&body).to_string()) - } } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 8b198f7b1..4e19ec20f 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -1,13 +1,15 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use std::sync::mpsc; +use std::thread; use std::time::Duration; -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::{eyre, Context, Result}; use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::RTX_EXE; +use crate::env::{RTX_EXE, RTX_FETCH_REMOTE_VERSIONS_TIMEOUT}; use crate::file::create_dir_all; use crate::git::Git; use crate::plugins::{Plugin, PluginName}; @@ -69,13 +71,27 @@ impl PythonPlugin { self.python_build_path().display() ); let git = Git::new(self.python_build_path()); - git.update(None)?; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let result = git.update(None); + tx.send(result).unwrap(); + }); + rx.recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) + .context("timed out updating python-build")??; Ok(()) } fn fetch_remote_versions(&self) -> Result> { self.install_or_update_python_build()?; - let output = cmd!(self.python_build_bin(), "--definitions").read()?; + let python_build_bin = self.python_build_bin(); + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let output = cmd!(python_build_bin, "--definitions").read(); + tx.send(output).unwrap(); + }); + let output = rx + .recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) + .context("timed out fetching python versions")??; Ok(output.split('\n').map(|s| s.to_string()).collect()) } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 1dc83f642..c2b723b3c 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -1,9 +1,10 @@ use std::collections::{BTreeMap, HashMap}; -use std::fs; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::exit; +use std::sync::mpsc::channel; use std::time::Duration; +use std::{fs, thread}; use clap::Command; use color_eyre::eyre::{eyre, Result, WrapErr}; @@ -13,7 +14,7 @@ use once_cell::sync::Lazy; use crate::cache::CacheManager; use crate::config::{Config, Settings}; -use crate::env::PREFER_STALE; +use crate::env::{PREFER_STALE, RTX_FETCH_REMOTE_VERSIONS_TIMEOUT}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; use crate::file::remove_all; @@ -84,13 +85,15 @@ impl ExternalPlugin { } fn fetch_remote_versions(&self, settings: &Settings) -> Result> { - let result = self - .script_man - .cmd(settings, &Script::ListAll) - .stdout_capture() - .stderr_capture() - .unchecked() - .run() + let cmd = self.script_man.cmd(settings, &Script::ListAll); + let (tx, rx) = channel(); + thread::spawn(move || { + let result = cmd.stdout_capture().stderr_capture().unchecked().run(); + tx.send(result).unwrap(); + }); + let result = rx + .recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) + .with_context(|| format!("timed out fetching remote versions for {}", self.name))? .map_err(|err| { let script = self.script_man.get_script_path(&Script::ListAll); eyre!("Failed to run {}: {}", script.display(), err) From a0b9bcebb681829d81d8ed29a1ad6d0b7adad15d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 22 May 2023 19:39:24 -0500 Subject: [PATCH 0776/1891] ignore failure to set ctrlc handler --- src/main.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4c9750655..5eb15e90e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,12 +85,11 @@ fn run(args: &Vec) -> Result<()> { } fn handle_ctrlc() { - ctrlc::set_handler(move || { + let _ = ctrlc::set_handler(move || { let _ = Term::stderr().show_cursor(); debug!("Ctrl-C pressed, exiting..."); exit(1); - }) - .expect("Error setting Ctrl-C handler"); + }); } fn display_friendly_err(err: Report) { From 0f1457bf2ed3318741bcedc5cf752665be0d4bd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 19:40:57 -0500 Subject: [PATCH 0777/1891] chore(deps): bump ctrlc from 3.2.5 to 3.3.0 (#574) Bumps [ctrlc](https://github.com/Detegr/rust-ctrlc) from 3.2.5 to 3.3.0. - [Release notes](https://github.com/Detegr/rust-ctrlc/releases) - [Commits](https://github.com/Detegr/rust-ctrlc/compare/3.2.5...3.3.0) --- updated-dependencies: - dependency-name: ctrlc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bdad2c262..e61ba3dee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,12 +440,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.2.5" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639" +checksum = "04d778600249295e82b6ab12e291ed9029407efee0cfb7baf67157edc65964df" dependencies = [ "nix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5ecc003eb..413f81b10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" console = "0.15.7" -ctrlc = "<3.3" +ctrlc = "<3.4" dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" dotenvy = "0.15.6" From 7bcbe6d336731a01d4431b955169ac374adb8f86 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 22 May 2023 19:47:54 -0500 Subject: [PATCH 0778/1891] chore: Release --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e61ba3dee..ffc82f380 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.2" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -1450,9 +1450,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" dependencies = [ "aho-corasick 1.0.1", "memchr", @@ -1461,9 +1461,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" @@ -1549,7 +1549,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.30.3" +version = "1.30.4" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 413f81b10..385a0727b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.30.3" +version = "1.30.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 1591fbee8..90203c026 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.30.3 +rtx 1.30.4 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -311,7 +311,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.30.3/rtx-v1.30.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.30.4/rtx-v1.30.4-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 740d819ba..b0d8741c3 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.30.3"; + version = "1.30.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 196930ee3..80695049f 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.30.3" +.TH rtx 1 "rtx 1.30.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -145,6 +145,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.30.3 +v1.30.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index bba639a50..71771fb60 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.30.3 +Version: 1.30.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 6486a5bf828305d6b7226ddb525c3a97f979ea5d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 22 May 2023 21:29:40 -0500 Subject: [PATCH 0779/1891] fix debug output (#578) display_path was not working correctly if HOME was "/" --- src/config/mod.rs | 7 ++----- src/file.rs | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 9ffca0c6a..85ed0d660 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,6 +17,7 @@ use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; use crate::env::CI; +use crate::file::display_path; use crate::plugins::core::{CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; @@ -487,11 +488,7 @@ impl Display for Config { let config_files = self .config_files .iter() - .map(|(p, _)| { - p.to_string_lossy() - .to_string() - .replace(&dirs::HOME.to_string_lossy().to_string(), "~") - }) + .map(|(p, _)| display_path(p)) .collect::>(); writeln!(f, "Files: {}", config_files.join(", "))?; write!(f, "Installed Plugins: {}", plugins.join(", ")) diff --git a/src/file.rs b/src/file.rs index ce5565c98..59aeff64c 100644 --- a/src/file.rs +++ b/src/file.rs @@ -46,7 +46,7 @@ pub fn basename(path: &Path) -> Option { /// replaces $HOME with "~" pub fn display_path(path: &Path) -> String { let home = dirs::HOME.to_string_lossy(); - match path.starts_with(home.as_ref()) { + match path.starts_with(home.as_ref()) && home != "/" { true => path.to_string_lossy().replacen(home.as_ref(), "~", 1), false => path.to_string_lossy().to_string(), } From aedbeba614d90dd87fcc2864753e0b1f4691322f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 12:14:54 +0200 Subject: [PATCH 0780/1891] chore(deps): bump ctrlc from 3.3.0 to 3.3.1 (#585) Bumps [ctrlc](https://github.com/Detegr/rust-ctrlc) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/Detegr/rust-ctrlc/releases) - [Commits](https://github.com/Detegr/rust-ctrlc/compare/3.3.0...3.3.1) --- updated-dependencies: - dependency-name: ctrlc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffc82f380..093224b1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,9 +440,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.3.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d778600249295e82b6ab12e291ed9029407efee0cfb7baf67157edc65964df" +checksum = "7394a21d012ce5c850497fb774b167d81b99f060025fbf06ee92b9848bd97eb2" dependencies = [ "nix", "windows-sys 0.48.0", From e38b4ed1118e6db5f97a56193f1d0ffc26fc1dae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 12:15:30 +0200 Subject: [PATCH 0781/1891] chore(deps): bump base64 from 0.21.1 to 0.21.2 (#584) Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.21.1 to 0.21.2. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.21.1...v0.21.2) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 093224b1b..9c7e2ed43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bitflags" From 4dbecbcf9f49574f239ea63379e750873d0682b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 10:44:23 +0000 Subject: [PATCH 0782/1891] chore(deps): bump regex from 1.8.2 to 1.8.3 (#583) Bumps [regex](https://github.com/rust-lang/regex) from 1.8.2 to 1.8.3. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.8.2...1.8.3) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c7e2ed43..6be542a03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1450,9 +1450,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" dependencies = [ "aho-corasick 1.0.1", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 385a0727b..ed1ead636 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ log = "0.4.17" num_cpus = "1.14.0" once_cell = "1.17.0" rayon = "1.6.1" -regex = "1.7.1" +regex = "1.8.3" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", "rustls-tls", From 003fcf256aa23693290526daa9d9276112c60a99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 11:00:53 +0000 Subject: [PATCH 0783/1891] chore(deps): bump log from 0.4.17 to 0.4.18 (#586) Bumps [log](https://github.com/rust-lang/log) from 0.4.17 to 0.4.18. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.17...0.4.18) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 7 ++----- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6be542a03..7b69d21b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1099,12 +1099,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "memchr" diff --git a/Cargo.toml b/Cargo.toml index ed1ead636..16b310f2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ indexmap = { version = "1.9.2", features = ["serde"] } indicatif = { version = "0.17.3", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.10.3" -log = "0.4.17" +log = "0.4.18" num_cpus = "1.14.0" once_cell = "1.17.0" rayon = "1.6.1" From 241d78ddf89e65f61f949dca7fa904d59a8354c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 11:18:23 +0000 Subject: [PATCH 0784/1891] chore(deps): bump toml_edit from 0.19.9 to 0.19.10 (#587) Bumps [toml_edit](https://github.com/toml-rs/toml) from 0.19.9 to 0.19.10. - [Commits](https://github.com/toml-rs/toml/compare/v0.19.9...v0.19.10) --- updated-dependencies: - dependency-name: toml_edit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b69d21b0..c26f67079 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2069,9 +2069,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.9" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" dependencies = [ "indexmap", "serde", From 7350f4e9256e562b60987cbf26888526c8c2ce69 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 1 Jun 2023 08:32:29 +0200 Subject: [PATCH 0785/1891] added "completions" alias (#591) --- src/cli/completion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 348ee346e..36b5afb95 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -10,7 +10,7 @@ use crate::output::Output; /// Generate shell completions #[derive(Debug, clap::Args)] -#[clap(alias = "complete", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(aliases = ["complete", "completions"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Completion { /// Shell type to generate completions for #[clap()] From 96bd8b200373c4b54e134da7a1911048386940fc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 1 Jun 2023 01:38:56 -0500 Subject: [PATCH 0786/1891] chore: Release --- Cargo.lock | 103 +++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 9 +++- 7 files changed, 60 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c26f67079..fb608b46c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -203,12 +209,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "winapi", ] @@ -255,7 +261,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -430,12 +436,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4056f63fce3b82d852c3da92b08ea59959890813a7f4ce9c0ff85b10cf301b" +checksum = "1586fa608b1dab41f667475b4a41faec5ba680aee428bfa5de4ea520fdc6e901" dependencies = [ "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -948,13 +954,14 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.3" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +checksum = "db45317f37ef454e6519b6c3ed7d377e5f23346f0823f86e65ca36912d1d0ef8" dependencies = [ "console", + "instant", "number_prefix", - "portable-atomic 0.3.20", + "portable-atomic", "unicode-segmentation", "unicode-width", ] @@ -989,9 +996,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", @@ -1150,14 +1157,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1182,16 +1188,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -1237,9 +1233,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "os_pipe" @@ -1308,7 +1304,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1342,18 +1338,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" -dependencies = [ - "portable-atomic 1.3.2", -] - -[[package]] -name = "portable-atomic" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5" +checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" [[package]] name = "pretty_assertions" @@ -1369,9 +1356,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] @@ -1387,9 +1374,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -1546,7 +1533,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.30.4" +version = "1.30.5" dependencies = [ "base64", "built", @@ -1556,7 +1543,7 @@ dependencies = [ "color-eyre", "color-print", "console", - "ctor 0.2.0", + "ctor 0.2.2", "ctrlc", "dialoguer", "dirs-next", @@ -1722,7 +1709,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1866,9 +1853,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -1890,9 +1877,9 @@ dependencies = [ [[package]] name = "tera" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a665751302f22a03c56721e23094e4dc22b04a80f381e6737a07bf7a7c70c0" +checksum = "a5ab29bb4f3e256ae6ad5c3e2775aa1f8829f2c0c101fc407bfd3a6df15c60c5" dependencies = [ "globwalk", "lazy_static", @@ -1941,7 +1928,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1999,9 +1986,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -2204,9 +2191,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -2333,7 +2320,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "wasm-bindgen-shared", ] @@ -2367,7 +2354,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 16b310f2d..8b89cc84e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.30.4" +version = "1.30.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 90203c026..4a2db9413 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.30.4 +rtx 1.30.5 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -311,7 +311,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.30.4/rtx-v1.30.4-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.30.5/rtx-v1.30.5-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index b0d8741c3..18cb7f907 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.30.4"; + version = "1.30.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 80695049f..f84c5b718 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.30.4" +.TH rtx 1 "rtx 1.30.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -145,6 +145,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.30.4 +v1.30.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 71771fb60..353b50e87 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.30.4 +Version: 1.30.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index c6cfdad76..4f4763eaa 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -157,6 +157,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ ("doctoolchain", "https://github.com/joschi/asdf-doctoolchain"), ("docuum", "https://github.com/bradym/asdf-docuum.git"), ("dome", "https://github.com/jtakakura/asdf-dome.git"), + ("doppler", "https://github.com/takutakahashi/asdf-doppler.git"), ("dotenv-linter", "https://github.com/wesleimp/asdf-dotenv-linter.git"), ("dotnet", "https://github.com/hensou/asdf-dotnet"), ("dotnet-core", "https://github.com/emersonsoares/asdf-dotnet-core.git"), @@ -484,6 +485,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ ("purescript", "https://github.com/nsaunders/asdf-purescript.git"), ("purty", "https://github.com/nsaunders/asdf-purty.git"), ("python", "https://github.com/danhper/asdf-python.git"), + ("qdns", "https://github.com/moritz-makandra/asdf-plugin-qdns.git"), ("quarkus", "https://github.com/asdf-community/asdf-quarkus.git"), ("rabbitmq", "https://github.com/w-sanches/asdf-rabbitmq.git"), ("racket", "https://github.com/asdf-community/asdf-racket.git"), @@ -510,6 +512,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ ("ruby", "https://github.com/asdf-vm/asdf-ruby.git"), ("rust", "https://github.com/code-lever/asdf-rust.git"), ("rust-analyzer", "https://github.com/Xyven1/asdf-rust-analyzer"), + ("rye", "https://github.com/Azuki-bar/asdf-rye"), ("saml2aws", "https://github.com/elementalvoid/asdf-saml2aws.git"), ("sbcl", "https://github.com/smashedtoatoms/asdf-sbcl.git"), ("sbt", "https://github.com/bram2000/asdf-sbt.git"), @@ -551,6 +554,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ ("spruce", "https://github.com/woneill/asdf-spruce.git"), ("sqldef", "https://github.com/cometkim/asdf-sqldef.git"), ("sqlite", "https://github.com/cLupus/asdf-sqlite.git"), + ("sshuttle", "https://github.com/xanmanning/asdf-sshuttle.git"), ("stack", "https://github.com/sestrella/asdf-ghcup.git"), ("starboard", "https://github.com/zufardhiyaulhaq/asdf-starboard.git"), ("starport", "https://github.com/nikever/asdf-starport.git"), @@ -606,6 +610,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), ("timoni", "https://github.com/Smana/asdf-timoni.git"), ("titan", "https://github.com/gabitchov/asdf-titan.git"), + ("tlsg-cli", "https://github.com/0ghny/asdf-tlsgcli.git"), ("tmux", "https://github.com/aphecetche/asdf-tmux.git"), ("tokei", "https://github.com/gasuketsu/asdf-tokei.git"), ("tomcat", "https://github.com/mbutov/asdf-tomcat"), @@ -645,6 +650,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ ("weave-gitops", "https://github.com/deas/asdf-weave-gitops"), ("websocat", "https://github.com/bdellegrazie/asdf-websocat.git"), ("wren-cli", "https://github.com/jtakakura/asdf-wren-cli.git"), + ("wrk", "https://github.com/ivanvc/asdf-wrk.git"), ("wtfutil", "https://github.com/NeoHsu/asdf-wtfutil.git"), ("xc", "https://github.com/airtonix/asdf-xc"), ("xchtmlreport", "https://github.com/younke/asdf-xchtmlreport.git"), @@ -652,6 +658,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 667] = [ ("xcodes", "https://github.com/younke/asdf-xcodes.git"), ("xh", "https://github.com/NeoHsu/asdf-xh"), ("yadm", "https://github.com/particledecay/asdf-yadm.git"), + ("yamlfmt", "https://github.com/kachick/asdf-yamlfmt.git"), ("yamllint", "https://github.com/ericcornelissen/asdf-yamllint.git"), ("yarn", "https://github.com/twuni/asdf-yarn.git"), ("yay", "https://github.com/aaaaninja/asdf-yay.git"), From 89eb3394e6f197323d164e7d9a963aa99346f6f3 Mon Sep 17 00:00:00 2001 From: Ben Woodward Date: Thu, 1 Jun 2023 14:56:28 +0100 Subject: [PATCH 0787/1891] Completions for aur/aur-bin and man pages for aur releases. (#581) * add completions to aur-bin release * add man page and completions to aur package --- scripts/release-aur-bin.sh | 3 +++ scripts/release-aur.sh | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index f2f7d2bce..9e951f55e 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -36,6 +36,9 @@ package() { cd "\$srcdir/" install -Dm755 rtx/bin/rtx "\$pkgdir/usr/bin/rtx" install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" + install -Dm644 rtx/completions/rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" + install -Dm644 rtx/completions/rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" + install -Dm644 rtx/completions/_rtx "\$pkgdir/usr/share/zsh/site-functions/_zsh" } check() { diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 542ed5086..7e80867ba 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -41,7 +41,11 @@ build() { package() { cd "\$srcdir/\$pkgname-\$pkgver" - install -Dm0755 -t "\$pkgdir/usr/bin/" "target/release/\$pkgname" + install -Dm755 target/release/rtx "\$pkgdir/usr/bin/rtx" + install -Dm644 man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" + install -Dm644 completions/rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" + install -Dm644 completions/rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" + install -Dm644 completions/_rtx "\$pkgdir/usr/share/zsh/site-functions/_zsh" } check() { From ab7b7a95a199e98f4b8337d5124c66645e0bd480 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:57:14 +0200 Subject: [PATCH 0788/1891] use shasum instead of sha256sum (#592) Fixes #590 --- packaging/standalone/install.envsubst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index cd4e3019a..82243dc54 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -113,7 +113,7 @@ install_rtx() { debug "rtx-setup: tarball=$cache_file" debug "validating checksum" - cd "$(dirname "$cache_file")" && get_checksum | sha256sum -c >/dev/null + cd "$(dirname "$cache_file")" && get_checksum | shasum -c >/dev/null # extract tarball mkdir -p "$install_dir" From 08ee05f01de75a7ff63383805d6295b94c353ff9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 1 Jun 2023 08:58:26 -0500 Subject: [PATCH 0789/1891] use latest ctrlc Fixes #570 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb608b46c..fba309de5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,9 +446,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.3.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7394a21d012ce5c850497fb774b167d81b99f060025fbf06ee92b9848bd97eb2" +checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" dependencies = [ "nix", "windows-sys 0.48.0", diff --git a/Cargo.toml b/Cargo.toml index 8b89cc84e..c2857dbc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" console = "0.15.7" -ctrlc = "<3.4" +ctrlc = "3.4.0" dialoguer = { version = "0.10.2", features = [] } dirs-next = "2.0.0" dotenvy = "0.15.6" From cbc3bcd3524ebee4f99d80dda47a8807719ff4c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:21:10 -0500 Subject: [PATCH 0790/1891] make python core plugin non-experimental --- src/plugins/core/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index b5162fa9e..17d53200c 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -18,11 +18,11 @@ 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())), ]) }); -pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = - Lazy::new(|| build_core_plugins(vec![Box::new(PythonPlugin::new("python".to_string()))])); +pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| build_core_plugins(vec![])); fn build_core_plugins(tools: Vec>) -> ToolMap { ToolMap::from_iter(tools.into_iter().map(|plugin| { From 51a648332b74ff6e3bb4cbd8f729211c77362222 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:24:03 -0500 Subject: [PATCH 0791/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fba309de5..366b6527e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1533,7 +1533,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.30.5" +version = "1.30.6" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index c2857dbc4..d4e49be58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.30.5" +version = "1.30.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 4a2db9413..3e7a603b8 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.30.5 +rtx 1.30.6 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -311,7 +311,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.30.5/rtx-v1.30.5-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.30.6/rtx-v1.30.6-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 18cb7f907..a371b5ad7 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.30.5"; + version = "1.30.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index f84c5b718..2c0c5e8b4 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.30.5" +.TH rtx 1 "rtx 1.30.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -145,6 +145,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.30.5 +v1.30.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 353b50e87..b6cc99f68 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.30.5 +Version: 1.30.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From af6b448f2c592348b443e0ada223cb79dc2f4118 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 1 Jun 2023 09:35:50 -0500 Subject: [PATCH 0792/1891] ignore failures with julia These do not seem to work locally or in CI. I don't have time to invesigate right now. --- .github/workflows/test-plugins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index e1cb05e01..da659c7b2 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -156,7 +156,7 @@ jobs: - pnpm - ocaml # TODO: - rebar install erlang first - - julia + # TODO: - julia seems to have quit working, likely an issue with the plugin - elm # TODO: - R install libcurl - nim From e71b5c5548e2102bfee754ee8e3bbf86b941be38 Mon Sep 17 00:00:00 2001 From: Mohammad Banisaeid Date: Fri, 2 Jun 2023 09:07:14 +0200 Subject: [PATCH 0793/1891] Add `env-vars` subcommand (#582) * Add set-env command * Insert a dummy env var in local toml file * Update command's help * Add an arg parser for env vars * Add unit tests for env_var arg parser * Use env var args in the set-env command * Update command's doc * Rename set_env module to env_vars * Rename SetEnv command to EnvVars * Use the --file option to env-vars command * Implement --remove feature for env-vars * Add tests * Add snapshot tests * fixes --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- README.md | 27 ++++ completions/_rtx | 40 ++++++ completions/rtx.bash | 58 ++++++++- completions/rtx.fish | 86 +++++++------ man/man1/rtx.1 | 3 + src/cli/args/env_var.rs | 82 ++++++++++++ src/cli/args/mod.rs | 1 + src/cli/env_vars.rs | 120 ++++++++++++++++++ src/cli/mod.rs | 3 + ...rtx__cli__env_vars__tests__env_vars-2.snap | 7 + .../rtx__cli__env_vars__tests__env_vars.snap | 7 + ...i__env_vars__tests__env_vars_remove-2.snap | 6 + ...cli__env_vars__tests__env_vars_remove.snap | 6 + src/config/config_file/rtx_toml.rs | 20 +++ 14 files changed, 428 insertions(+), 38 deletions(-) create mode 100644 src/cli/args/env_var.rs create mode 100644 src/cli/env_vars.rs create mode 100644 src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap create mode 100644 src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap create mode 100644 src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap create mode 100644 src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap diff --git a/README.md b/README.md index 3e7a603b8..9d16d86ca 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ v20.0.0 - [`rtx direnv activate`](#rtx-direnv-activate) - [`rtx doctor`](#rtx-doctor) - [`rtx env [OPTIONS] [TOOL@VERSION]...`](#rtx-env-options-toolversion) + - [`rtx env-vars [OPTIONS] [ENV_VARS]...`](#rtx-env-vars-options-env_vars) - [`rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]`](#rtx-exec-options-toolversion----command) - [`rtx implode [OPTIONS]`](#rtx-implode-options) - [`rtx install [OPTIONS] [TOOL@VERSION]...`](#rtx-install-options-toolversion) @@ -1701,6 +1702,32 @@ Examples: $ rtx env -s fish | source $ execx($(rtx env -s xonsh)) ``` +### `rtx env-vars [OPTIONS] [ENV_VARS]...` + +``` +Manage environment variables + +By default this command modifies ".rtx.toml" in the current directory. +You can specify the file name by either setting the RTX_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. + +Usage: env-vars [OPTIONS] [ENV_VARS]... + +Arguments: + [ENV_VARS]... + Environment variable(s) to set + e.g.: NODE_ENV=production + +Options: + --file + The TOML file to update + + Defaults to RTX_DEFAULT_CONFIG_FILENAME environment variable, or ".rtx.toml". + + --remove + Remove the environment variable from config file + + Can be used multiple times. +``` ### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` ``` diff --git a/completions/_rtx b/completions/_rtx index b7d5c40ed..7d426f1a3 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -576,6 +576,30 @@ Sets --jobs=1]' \ '*::tool -- Tool(s) to use:' \ && ret=0 ;; +(env-vars) +_arguments "${_arguments_options[@]}" \ +'--file=[The TOML file to update]:FILE: ' \ +'*--remove=[Remove the environment variable from config file]:ENV_VAR: ' \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::env_vars -- Environment variable(s) to set +e.g.\: NODE_ENV=production:' \ +&& ret=0 +;; (exec) _arguments "${_arguments_options[@]}" \ '()-c+[Command string to execute]:C:_cmdstring' \ @@ -1628,6 +1652,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(env-vars) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (exec) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1817,6 +1845,7 @@ _rtx_commands() { 'doctor:Check rtx installation for possible problems.' \ 'env:Exports env vars to activate rtx a single time' \ 'e:Exports env vars to activate rtx a single time' \ +'env-vars:Manage environment variables' \ 'exec:Execute a command with tool(s) set' \ 'x:Execute a command with tool(s) set' \ 'global:Sets/gets the global tool version(s)' \ @@ -2033,6 +2062,16 @@ _rtx__help__env_commands() { local commands; commands=() _describe -t commands 'rtx help env commands' commands "$@" } +(( $+functions[_rtx__env-vars_commands] )) || +_rtx__env-vars_commands() { + local commands; commands=() + _describe -t commands 'rtx env-vars commands' commands "$@" +} +(( $+functions[_rtx__help__env-vars_commands] )) || +_rtx__help__env-vars_commands() { + local commands; commands=() + _describe -t commands 'rtx help env-vars commands' commands "$@" +} (( $+functions[_rtx__direnv__envrc_commands] )) || _rtx__direnv__envrc_commands() { local commands; commands=() @@ -2175,6 +2214,7 @@ _rtx__help_commands() { 'direnv:Output direnv function to use rtx inside direnv' \ 'doctor:Check rtx installation for possible problems.' \ 'env:Exports env vars to activate rtx a single time' \ +'env-vars:Manage environment variables' \ 'exec:Execute a command with tool(s) set' \ 'global:Sets/gets the global tool version(s)' \ 'hook-env:\[internal\] called by activate hook to update env vars directory change' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index f8c236d88..16591aa02 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -51,6 +51,9 @@ _rtx() { rtx,env) cmd="rtx__env" ;; + rtx,env-vars) + cmd="rtx__env__vars" + ;; rtx,exec) cmd="rtx__exec" ;; @@ -264,6 +267,9 @@ _rtx() { rtx__help,env) cmd="rtx__help__env" ;; + rtx__help,env-vars) + cmd="rtx__help__env__vars" + ;; rtx__help,exec) cmd="rtx__help__exec" ;; @@ -505,7 +511,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" + opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1260,6 +1266,40 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__env__vars) + opts="-j -r -v -h --file --remove --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ENV_VARS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --file) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__exec) opts="-c -j -r -v -h --command --cd --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -1329,7 +1369,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1608,6 +1648,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__env__vars) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__exec) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index a815003d1..3f9ed7698 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -20,6 +20,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'Disable rtx fo complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_use_subcommand" -f -a "env-vars" -d 'Manage environment variables' complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with tool(s) set' complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets/gets the global tool version(s)' complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' @@ -273,6 +274,18 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l file -d 'The TOML file to update' -r +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l remove -d 'Remove the environment variable from config file' -r +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r -f -a "(__fish_complete_command)" complete -c rtx -n "__fish_seen_subcommand_from exec" -l cd -d 'Change to this directory before executing the command' -r -f -a "(__fish_complete_directories)" complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -696,42 +709,43 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 2c0c5e8b4..9acdd41a1 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -70,6 +70,9 @@ Check rtx installation for possible problems. rtx\-env(1) Exports env vars to activate rtx a single time .TP +rtx\-env\-vars(1) +Manage environment variables +.TP rtx\-exec(1) Execute a command with tool(s) set .TP diff --git a/src/cli/args/env_var.rs b/src/cli/args/env_var.rs new file mode 100644 index 000000000..2e4f27eb1 --- /dev/null +++ b/src/cli/args/env_var.rs @@ -0,0 +1,82 @@ +use clap::{ + error::{ContextKind, ContextValue, ErrorKind}, + Arg, Command, Error, +}; +use std::ffi::OsStr; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct EnvVarArg { + pub key: String, + pub value: String, +} + +impl EnvVarArg { + pub fn parse(input: &str) -> Option { + input.split_once('=').map(|(k, v)| Self { + key: k.to_string(), + value: v.to_string(), + }) + } +} + +#[derive(Debug, Clone)] +pub struct EnvVarArgParser; + +impl clap::builder::TypedValueParser for EnvVarArgParser { + type Value = EnvVarArg; + + fn parse_ref( + &self, + cmd: &Command, + arg: Option<&Arg>, + value: &OsStr, + ) -> Result { + if let Some(parsed) = EnvVarArg::parse(&value.to_string_lossy()) { + return Ok(parsed); + } + + let mut err = clap::Error::new(ErrorKind::ValueValidation).with_cmd(cmd); + if let Some(arg) = arg { + err.insert( + ContextKind::InvalidArg, + ContextValue::String(arg.to_string()), + ); + } + err.insert( + ContextKind::InvalidValue, + ContextValue::String(value.to_string_lossy().into()), + ); + Err(err) + } +} + +#[cfg(test)] +mod tests { + use super::EnvVarArg; + + #[test] + fn invalid_value() { + let res = EnvVarArg::parse("NO_EQUAL_SIGN"); + assert!(res.is_none()); + } + + #[test] + fn valid_values() { + let values = [ + ("FOO=", new_arg("FOO", "")), + ("FOO=bar", new_arg("FOO", "bar")), + ]; + + for (input, want) in values { + let got = EnvVarArg::parse(input); + assert_eq!(got, Some(want)); + } + } + + fn new_arg(key: &str, value: &str) -> EnvVarArg { + EnvVarArg { + key: key.to_string(), + value: value.to_string(), + } + } +} diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index cd7865d07..f584b96f9 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,3 +1,4 @@ +pub mod env_var; pub mod install_missing; pub mod jobs; pub mod log_level; diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs new file mode 100644 index 000000000..a566faa5a --- /dev/null +++ b/src/cli/env_vars.rs @@ -0,0 +1,120 @@ +use color_eyre::Result; + +use crate::cli::command::Command; +use crate::config::config_file::rtx_toml::RtxToml; +use crate::config::config_file::{self, ConfigFile}; +use crate::config::Config; +use crate::dirs; +use crate::env::RTX_DEFAULT_CONFIG_FILENAME; +use crate::output::Output; + +use super::args::env_var::{EnvVarArg, EnvVarArgParser}; + +/// Manage environment variables +/// +/// By default this command modifies ".rtx.toml" in the current directory. +/// You can specify the file name by either setting the RTX_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct EnvVars { + /// The TOML file to update + /// + /// Defaults to RTX_DEFAULT_CONFIG_FILENAME environment variable, or ".rtx.toml". + #[clap(long, verbatim_doc_comment, required = false)] + file: Option, + + /// Remove the environment variable from config file + /// + /// Can be used multiple times. + #[clap(long, value_name = "ENV_VAR", verbatim_doc_comment, aliases = ["rm", "unset"])] + remove: Option>, + + /// Environment variable(s) to set + /// e.g.: NODE_ENV=production + #[clap(value_parser = EnvVarArgParser, verbatim_doc_comment, required_unless_present = "remove")] + env_vars: Vec, +} + +impl Command for EnvVars { + fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let filename = self + .file + .unwrap_or_else(|| RTX_DEFAULT_CONFIG_FILENAME.to_string()); + + let mut rtx_toml = get_rtx_toml(&config, filename.as_str())?; + + if let Some(env_names) = &self.remove { + for name in env_names { + rtx_toml.remove_env(name); + } + } + + for ev in self.env_vars { + rtx_toml.update_env(&ev.key, ev.value); + } + rtx_toml.save() + } +} + +fn get_rtx_toml(config: &Config, filename: &str) -> Result { + let path = dirs::CURRENT.join(filename); + let is_trusted = config_file::is_trusted(&config.settings, &path); + let rtx_toml = if path.exists() { + RtxToml::from_file(&path, is_trusted)? + } else { + RtxToml::init(&path, is_trusted) + }; + + Ok(rtx_toml) +} + +#[cfg(test)] +mod tests { + use std::{fs, path::PathBuf}; + + use insta::assert_snapshot; + + use crate::{assert_cli, dirs}; + + fn remove_config_file(filename: &str) -> PathBuf { + let cf_path = dirs::CURRENT.join(filename); + let _ = fs::remove_file(&cf_path); + cf_path + } + + #[test] + fn test_env_vars() { + // Using the default file + let filename = ".test.rtx.toml"; + let cf_path = remove_config_file(filename); + assert_cli!("env-vars", "FOO=bar"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + remove_config_file(filename); + + // Using a custom file + let filename = ".test-custom.rtx.toml"; + let cf_path = remove_config_file(filename); + assert_cli!("env-vars", "--file", filename, "FOO=bar"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + remove_config_file(filename); + } + + #[test] + fn test_env_vars_remove() { + // Using the default file + let filename = ".test.rtx.toml"; + let cf_path = remove_config_file(filename); + assert_cli!("env-vars", "BAZ=quux"); + assert_cli!("env-vars", "--remove", "BAZ"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + remove_config_file(filename); + + // Using a custom file + let filename = ".test-custom.rtx.toml"; + let cf_path = remove_config_file(filename); + assert_cli!("env-vars", "--file", filename, "BAZ=quux"); + assert_cli!("env-vars", "--file", filename, "--remove", "BAZ"); + assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + remove_config_file(filename); + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2e5d71973..9992267bf 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -21,6 +21,7 @@ mod deactivate; mod direnv; mod doctor; mod env; +mod env_vars; pub mod exec; mod external; mod global; @@ -66,6 +67,7 @@ pub enum Commands { Direnv(direnv::Direnv), Doctor(doctor::Doctor), Env(env::Env), + EnvVars(env_vars::EnvVars), Exec(exec::Exec), Global(global::Global), HookEnv(hook_env::HookEnv), @@ -108,6 +110,7 @@ impl Commands { Self::Direnv(cmd) => cmd.run(config, out), Self::Doctor(cmd) => cmd.run(config, out), Self::Env(cmd) => cmd.run(config, out), + Self::EnvVars(cmd) => cmd.run(config, out), Self::Exec(cmd) => cmd.run(config, out), Self::Global(cmd) => cmd.run(config, out), Self::HookEnv(cmd) => cmd.run(config, out), diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap new file mode 100644 index 000000000..507049870 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/env_vars.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[env] +FOO = "bar" + diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap new file mode 100644 index 000000000..507049870 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/env_vars.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[env] +FOO = "bar" + diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap new file mode 100644 index 000000000..d552ab5ef --- /dev/null +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/env_vars.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[env] + diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap new file mode 100644 index 000000000..d552ab5ef --- /dev/null +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/env_vars.rs +expression: "fs::read_to_string(&cf_path).unwrap()" +--- +[env] + diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index d373fc39a..cd698e11e 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -588,6 +588,26 @@ impl RtxToml { } } + pub fn update_env>(&mut self, key: &str, value: V) { + let env_tbl = self + .doc + .entry("env") + .or_insert_with(table) + .as_table_like_mut() + .unwrap(); + env_tbl.insert(key, toml_edit::value(value)); + } + + pub fn remove_env(&mut self, key: &str) { + let env_tbl = self + .doc + .entry("env") + .or_insert_with(table) + .as_table_like_mut() + .unwrap(); + env_tbl.remove(key); + } + fn parse_template(&mut self, k: &str, input: &str) -> Result { if !input.contains("{{") && !input.contains("{%") && !input.contains("{#") { return Ok(input.to_string()); From 9954a17f49d4888cff8d32657fbfb9a88d077919 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 2 Jun 2023 08:19:32 -0500 Subject: [PATCH 0794/1891] Revert "Completions for aur/aur-bin and man pages for aur releases. (#581)" This reverts commit 89eb3394e6f197323d164e7d9a963aa99346f6f3. --- scripts/release-aur-bin.sh | 3 --- scripts/release-aur.sh | 6 +----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 9e951f55e..f2f7d2bce 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -36,9 +36,6 @@ package() { cd "\$srcdir/" install -Dm755 rtx/bin/rtx "\$pkgdir/usr/bin/rtx" install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" - install -Dm644 rtx/completions/rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" - install -Dm644 rtx/completions/rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" - install -Dm644 rtx/completions/_rtx "\$pkgdir/usr/share/zsh/site-functions/_zsh" } check() { diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 7e80867ba..542ed5086 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -41,11 +41,7 @@ build() { package() { cd "\$srcdir/\$pkgname-\$pkgver" - install -Dm755 target/release/rtx "\$pkgdir/usr/bin/rtx" - install -Dm644 man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" - install -Dm644 completions/rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" - install -Dm644 completions/rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" - install -Dm644 completions/_rtx "\$pkgdir/usr/share/zsh/site-functions/_zsh" + install -Dm0755 -t "\$pkgdir/usr/bin/" "target/release/\$pkgname" } check() { From 66b59e2af7b7079f6bf337ae0d1ebd9d6c210ed0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 2 Jun 2023 08:20:55 -0500 Subject: [PATCH 0795/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 366b6527e..0b4871e08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1533,7 +1533,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.30.6" +version = "1.31.0" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index d4e49be58..e28084993 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.30.6" +version = "1.31.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 9d16d86ca..29a6e3c39 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.30.6 +rtx 1.31.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -312,7 +312,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.30.6/rtx-v1.30.6-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.31.0/rtx-v1.31.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index a371b5ad7..01e9c49ad 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.30.6"; + version = "1.31.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 9acdd41a1..b4630f2d9 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.30.6" +.TH rtx 1 "rtx 1.31.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -148,6 +148,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.30.6 +v1.31.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b6cc99f68..0b46d9928 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.30.6 +Version: 1.31.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 1c96c26c3dfe39b7f3a765e6f1c6be88714d927b Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sat, 3 Jun 2023 16:01:18 +0200 Subject: [PATCH 0796/1891] display outdated status on rtx ls (#554) (#596) --- src/cli/ls.rs | 34 ++++++++++++++++++++++++++++------ src/tool.rs | 11 +++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index f37eac5e7..bfc3132e2 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -65,7 +65,7 @@ impl Command for Ls { } else if self.parseable { self.display_parseable(runtimes, out) } else { - self.display_user(runtimes, out) + self.display_user(&config, runtimes, out) } } } @@ -137,7 +137,12 @@ impl Ls { Ok(()) } - fn display_user(&self, runtimes: Vec, out: &mut Output) -> Result<()> { + fn display_user( + &self, + config: &Config, + runtimes: Vec, + out: &mut Output, + ) -> Result<()> { let output = runtimes .into_iter() .map(|(p, tv, source)| { @@ -145,7 +150,7 @@ impl Ls { let version = if !p.is_version_installed(&tv) { VersionStatus::Missing(tv.version) } else if source.is_some() { - VersionStatus::Active(tv.version) + VersionStatus::Active(tv.version.clone(), p.is_version_outdated(config, &tv)) } else { VersionStatus::Inactive(tv.version) }; @@ -244,7 +249,7 @@ fn get_runtime_list( } enum VersionStatus { - Active(String), + Active(String, bool), Inactive(String), Missing(String), } @@ -252,7 +257,13 @@ enum VersionStatus { impl VersionStatus { fn to_plain_string(&self) -> String { match self { - VersionStatus::Active(version) => version.to_string(), + VersionStatus::Active(version, outdated) => { + if *outdated { + format!("{} (outdated)", version) + } else { + version.to_string() + } + } VersionStatus::Inactive(version) => version.to_string(), VersionStatus::Missing(version) => format!("{} (missing)", version), } @@ -262,7 +273,18 @@ impl VersionStatus { impl Display for VersionStatus { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - VersionStatus::Active(version) => write!(f, "{}", style(version).green()), + VersionStatus::Active(version, outdated) => { + if *outdated { + write!( + f, + "{} {}", + style(version).yellow(), + style("(outdated)").yellow() + ) + } else { + write!(f, "{}", style(version).green()) + } + } VersionStatus::Inactive(version) => write!(f, "{}", style(version).dim()), VersionStatus::Missing(version) => write!( f, diff --git a/src/tool.rs b/src/tool.rs index 65b24946e..74fb2c00b 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -163,6 +163,17 @@ impl Tool { } } + pub fn is_version_outdated(&self, config: &Config, tv: &ToolVersion) -> bool { + let latest = match tv.latest_version(config, self) { + Ok(latest) => latest, + Err(e) => { + debug!("Error getting latest version for {}: {:#}", self.name, e); + return false; + } + }; + !self.is_version_installed(tv) || tv.version != latest + } + pub fn install_version( &self, config: &Config, From 4b649d3062d05c9b40653f078fae6772ad0c05c0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 3 Jun 2023 09:13:03 -0500 Subject: [PATCH 0797/1891] -n --- packaging/standalone/install.envsubst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index 82243dc54..c8cde080c 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -51,6 +51,16 @@ get_arch() { fi } +shasum_bin() { + if command -v shasum >/dev/null 2>&1; then + echo "shasum" + elif command -v sha256sum >/dev/null 2>&1; then + echo "sha256sum" + else + error "rtx install requires shasum or sha256sum but neither is installed. Aborting." + fi +} + get_checksum() { os="$(get_os)" arch="$(get_arch)" @@ -113,7 +123,7 @@ install_rtx() { debug "rtx-setup: tarball=$cache_file" debug "validating checksum" - cd "$(dirname "$cache_file")" && get_checksum | shasum -c >/dev/null + cd "$(dirname "$cache_file")" && get_checksum | "$(shasum_bin)" -c >/dev/null # extract tarball mkdir -p "$install_dir" From da025fedb73f5a3ffbc17930384130aa6f40eb1b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 3 Jun 2023 09:15:13 -0500 Subject: [PATCH 0798/1891] chore: Release --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b4871e08..d410b6091 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,9 +221,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28" dependencies = [ "clap_builder", "clap_derive", @@ -232,9 +232,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980" dependencies = [ "anstream", "anstyle", @@ -245,18 +245,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a04ddfaacc3bc9e6ea67d024575fafc2a813027cf374b8f24f7bc233c6b6be12" +checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +checksum = "59e9ef9a08ee1c0e1f2e162121665ac45ac3783b0f897db7244ae75ad9a8f65b" dependencies = [ "heck", "proc-macro2", @@ -272,9 +272,9 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "clap_mangen" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bcbd911d903a985de775aabe3bcef9b88e2a7d943e36aa8691617012d2b7731" +checksum = "8f2e32b579dae093c2424a8b7e2bea09c89da01e1ce5065eb2f0a6f1cc15cc1f" dependencies = [ "clap", "roff", @@ -1533,7 +1533,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.31.0" +version = "1.32.0" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index e28084993..a69c4f7c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.31.0" +version = "1.32.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 29a6e3c39..4de032989 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.31.0 +rtx 1.32.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -312,7 +312,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.31.0/rtx-v1.31.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.32.0/rtx-v1.32.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 01e9c49ad..12459a576 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.31.0"; + version = "1.32.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index b4630f2d9..70da821f1 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.31.0" +.TH rtx 1 "rtx 1.32.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -148,6 +148,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.31.0 +v1.32.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 0b46d9928..e2db44a34 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.31.0 +Version: 1.32.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 8936488d14d3ada204e2799c14bb84990fee8a16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 09:21:50 +0200 Subject: [PATCH 0799/1891] chore(deps): bump self_update from 0.36.0 to 0.37.0 (#599) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d410b6091..43863f31a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1667,9 +1667,9 @@ dependencies = [ [[package]] name = "self_update" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4e4e6f29fddb78b3e7a6e5a395e8274d4aca2d36b2278a297fa49673a5b7c7" +checksum = "a667e18055120bcc9a658d55d36f2f6bfc82e07968cc479ee7774e3bfb501e14" dependencies = [ "hyper", "indicatif", diff --git a/Cargo.toml b/Cargo.toml index a69c4f7c0..80541c11b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ reqwest = { version = "0.11.17", default-features = false, features = [ "rustls-tls", ] } rmp-serde = "1.1.1" -self_update = { version = "0.36.0", default-features = false, optional = true, features = [ +self_update = { version = "0.37.0", default-features = false, optional = true, features = [ "rustls", ] } serde = "1.0.163" From 342658d5e57098bece06dd8816bae045e9c5ed93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 07:38:07 +0000 Subject: [PATCH 0800/1891] chore(deps): bump indicatif from 0.17.4 to 0.17.5 (#598) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43863f31a..9c078fa2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -954,9 +954,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.4" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db45317f37ef454e6519b6c3ed7d377e5f23346f0823f86e65ca36912d1d0ef8" +checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057" dependencies = [ "console", "instant", diff --git a/Cargo.toml b/Cargo.toml index 80541c11b..82346ba84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ fslock = "0.2.1" humantime = "2.1.0" indenter = "0.3.3" indexmap = { version = "1.9.2", features = ["serde"] } -indicatif = { version = "0.17.3", features = ["default", "improved_unicode"] } +indicatif = { version = "0.17.5", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.10.3" log = "0.4.18" From f67a62e6e3c304d88b07217c8573cd5303fbfea6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 07:56:06 +0000 Subject: [PATCH 0801/1891] chore(deps): bump once_cell from 1.17.2 to 1.18.0 (#600) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c078fa2f..b96d4f102 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1233,9 +1233,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "os_pipe" diff --git a/Cargo.toml b/Cargo.toml index 82346ba84..4eb876d08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ indoc = "<3" itertools = "0.10.3" log = "0.4.18" num_cpus = "1.14.0" -once_cell = "1.17.0" +once_cell = "1.18.0" rayon = "1.6.1" regex = "1.8.3" reqwest = { version = "0.11.17", default-features = false, features = [ From 8a837c9934aa3f7face1dfa4d868b7ade5cf3471 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 02:17:41 +0000 Subject: [PATCH 0802/1891] chore(deps): bump url from 2.3.1 to 2.4.0 (#609) --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b96d4f102..ca7153ff6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -633,9 +633,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -910,9 +910,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1270,9 +1270,9 @@ checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" @@ -2224,9 +2224,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", diff --git a/Cargo.toml b/Cargo.toml index 4eb876d08..b0b178a56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,7 @@ terminal_size = "0.2.1" thiserror = "1.0.38" toml = "<0.8" toml_edit = "<0.20" -url = "2.3.1" +url = "2.4.0" versions = "5.0.0" [target.'cfg(unix)'.dependencies] From 20040064c4a40c26523bcf9cdf731fee53da8396 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 02:46:20 +0000 Subject: [PATCH 0803/1891] chore(deps): bump log from 0.4.18 to 0.4.19 (#610) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca7153ff6..57ab6bed9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1106,9 +1106,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memchr" diff --git a/Cargo.toml b/Cargo.toml index b0b178a56..a96a6f001 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ indexmap = { version = "1.9.2", features = ["serde"] } indicatif = { version = "0.17.5", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.10.3" -log = "0.4.18" +log = "0.4.19" num_cpus = "1.14.0" once_cell = "1.18.0" rayon = "1.6.1" From 9590fe0702722f931d0f5e1a21d1d5df17dbfd9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 03:13:49 +0000 Subject: [PATCH 0804/1891] chore(deps): bump regex from 1.8.3 to 1.8.4 (#613) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57ab6bed9..807598f77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1434,9 +1434,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick 1.0.1", "memchr", diff --git a/Cargo.toml b/Cargo.toml index a96a6f001..17f836027 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ log = "0.4.19" num_cpus = "1.14.0" once_cell = "1.18.0" rayon = "1.6.1" -regex = "1.8.3" +regex = "1.8.4" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", "rustls-tls", From 59137b359b09f8f39bc5e8fa81f48296292c3e5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 03:35:57 +0000 Subject: [PATCH 0805/1891] chore(deps): bump clap from 4.3.1 to 4.3.3 (#612) --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 807598f77..90bc001c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,9 +221,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.1" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28" +checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" dependencies = [ "clap_builder", "clap_derive", @@ -232,9 +232,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.1" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980" +checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab" dependencies = [ "anstream", "anstyle", @@ -254,9 +254,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e9ef9a08ee1c0e1f2e162121665ac45ac3783b0f897db7244ae75ad9a8f65b" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 17f836027..d7984733e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ path = "src/main.rs" [dependencies] base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } -clap = { version = "4.2.5", features = ["env", "derive", "string"] } +clap = { version = "4.3.3", features = ["env", "derive", "string"] } clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" From 0b9a73afe5eccd1b1a3db326f74a7394790f03a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 03:53:34 +0000 Subject: [PATCH 0806/1891] chore(deps): bump serde from 1.0.163 to 1.0.164 (#611) --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90bc001c3..5b9c96e6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1694,18 +1694,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index d7984733e..c9ce477e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ rmp-serde = "1.1.1" self_update = { version = "0.37.0", default-features = false, optional = true, features = [ "rustls", ] } -serde = "1.0.163" +serde = "1.0.164" serde_derive = "1.0.152" serde_json = "1.0.87" shell-escape = "0.1.4" From c3a16814e35a1748c5bc3144e20682488004944b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 09:17:46 +0200 Subject: [PATCH 0807/1891] chore(deps): bump clap from 4.3.3 to 4.3.4 (#619) --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b9c96e6b..d2ffb00bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,9 +221,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.3" +version = "4.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" +checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed" dependencies = [ "clap_builder", "clap_derive", @@ -232,9 +232,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.3" +version = "4.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab" +checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" dependencies = [ "anstream", "anstyle", diff --git a/Cargo.toml b/Cargo.toml index c9ce477e5..96513b33b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ path = "src/main.rs" [dependencies] base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } -clap = { version = "4.3.3", features = ["env", "derive", "string"] } +clap = { version = "4.3.4", features = ["env", "derive", "string"] } clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" From 5beb36b9e05edc1926dc2a4ade23adf1cbb9e3ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 07:34:07 +0000 Subject: [PATCH 0808/1891] chore(deps): bump serde_json from 1.0.96 to 1.0.97 (#620) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2ffb00bb..07b917a52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1714,9 +1714,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 96513b33b..9ef2549c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ self_update = { version = "0.37.0", default-features = false, optional = true, f ] } serde = "1.0.164" serde_derive = "1.0.152" -serde_json = "1.0.87" +serde_json = "1.0.97" shell-escape = "0.1.4" simplelog = { version = "0.12.0" } tera = { version = "1.12.1", default-features = false } From 90bc572def4db338f21befd6c2544bed25aa120b Mon Sep 17 00:00:00 2001 From: Philipp A Date: Thu, 22 Jun 2023 22:17:52 +0200 Subject: [PATCH 0809/1891] Use nushell syntax highlighting in README (#624) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4de032989..97ce0e719 100644 --- a/README.md +++ b/README.md @@ -428,10 +428,10 @@ echo 'rtx activate fish | source' >> ~/.config/fish/config.fish #### Nushell -```sh-session +```nushell do { - let rtxpath = $"($nu.config-path | path dirname | path join "rtx.nu")"; - run-external rtx activate nu --redirect-stdout | save $rtxpath -f; + let rtxpath = ($nu.config-path | path dirname | path join "rtx.nu") + run-external rtx activate nu --redirect-stdout | save $rtxpath -f $"\nsource "($rtxpath)"" | save $nu.config-path --append } ``` From 68153f4b123746a8e749cac9e60f307640ba5734 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 03:45:47 +0100 Subject: [PATCH 0810/1891] chore(deps): bump insta from 1.29.0 to 1.30.0 (#627) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07b917a52..5630715fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -974,9 +974,9 @@ checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" [[package]] name = "insta" -version = "1.29.0" +version = "1.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a28d25139df397cbca21408bb742cf6837e04cdbebf1b07b760caf971d6a972" +checksum = "28491f7753051e5704d4d0ae7860d45fae3238d7d235bc4289dcd45c48d3cec3" dependencies = [ "console", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 9ef2549c3..fba9d0937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,7 +90,7 @@ built = { version = "0.6.0", features = ["chrono", "git2"] } [dev-dependencies] ctor = "<0.3" -insta = "1.26.0" +insta = "1.30.0" pretty_assertions = "1.3.0" [features] From c35bf12c9854106a3f5fd1bab9559dd19cdedbba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 03:01:47 +0000 Subject: [PATCH 0811/1891] chore(deps): bump itertools from 0.10.5 to 0.11.0 (#626) --- Cargo.lock | 13 +++++++++++-- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5630715fe..9e5d573be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1032,6 +1032,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.6" @@ -1559,7 +1568,7 @@ dependencies = [ "indicatif", "indoc", "insta", - "itertools", + "itertools 0.11.0", "log", "num_cpus", "once_cell", @@ -2269,7 +2278,7 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32feb3eb91e495efe5b6b2e3ca9d78db603043434a3a398a84b47de28abb2d02" dependencies = [ - "itertools", + "itertools 0.10.5", "nom", ] diff --git a/Cargo.toml b/Cargo.toml index fba9d0937..b93fd2211 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ indenter = "0.3.3" indexmap = { version = "1.9.2", features = ["serde"] } indicatif = { version = "0.17.5", features = ["default", "improved_unicode"] } indoc = "<3" -itertools = "0.10.3" +itertools = "0.11.0" log = "0.4.19" num_cpus = "1.14.0" once_cell = "1.18.0" From b45a1f034dddcbe224ca3135d8e4fd5c74303fc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 03:19:53 +0000 Subject: [PATCH 0812/1891] chore(deps): bump toml from 0.7.4 to 0.7.5 (#629) --- Cargo.lock | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e5d573be..898596ee7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -542,6 +542,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "errno" version = "0.2.8" @@ -774,7 +780,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -787,6 +793,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "heck" version = "0.4.1" @@ -948,10 +960,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "indicatif" version = "0.17.5" @@ -1564,7 +1586,7 @@ dependencies = [ "fslock", "humantime", "indenter", - "indexmap", + "indexmap 1.9.3", "indicatif", "indoc", "insta", @@ -1586,7 +1608,7 @@ dependencies = [ "tera", "terminal_size", "thiserror", - "toml 0.7.4", + "toml 0.7.5", "toml_edit", "url", "versions", @@ -1734,9 +1756,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -2044,9 +2066,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", @@ -2056,20 +2078,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", From 0f0a0c32ab748bbcf7480d2bbb5843c2d7e191c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 03:34:17 +0000 Subject: [PATCH 0813/1891] chore(deps): bump built from 0.6.0 to 0.6.1 (#630) --- Cargo.lock | 29 ++++++++++------------------- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 898596ee7..c3428f6dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,9 +153,9 @@ dependencies = [ [[package]] name = "built" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96f9cdd34d6eb553f9ea20e5bf84abb7b13c729f113fc1d8e49dc00ad9fa8738" +checksum = "b99c4cdc7b2c2364182331055623bdf45254fcb679fea565c40c3c11c101889a" dependencies = [ "cargo-lock", "chrono", @@ -182,13 +182,13 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cargo-lock" -version = "8.0.3" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996" +checksum = "e11c675378efb449ed3ce8de78d75d0d80542fc98487c26aba28eb3b82feac72" dependencies = [ "semver", "serde", - "toml 0.5.11", + "toml", "url", ] @@ -733,9 +733,9 @@ checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "git2" -version = "0.16.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" +checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044" dependencies = [ "bitflags", "libc", @@ -1101,9 +1101,9 @@ checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libgit2-sys" -version = "0.14.2+1.5.1" +version = "0.15.2+1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" +checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa" dependencies = [ "cc", "libc", @@ -1608,7 +1608,7 @@ dependencies = [ "tera", "terminal_size", "thiserror", - "toml 0.7.5", + "toml", "toml_edit", "url", "versions", @@ -2055,15 +2055,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index b93fd2211..58f34ee18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,7 @@ versions = "5.0.0" exec = "0.3.1" [build-dependencies] -built = { version = "0.6.0", features = ["chrono", "git2"] } +built = { version = "0.6.1", features = ["chrono", "git2"] } [dev-dependencies] ctor = "<0.3" From 142eca9ab470b50c740864689461e962ef571837 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 03:48:45 +0000 Subject: [PATCH 0814/1891] chore(deps): bump serde_json from 1.0.97 to 1.0.99 (#628) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3428f6dd..7e127f3c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1745,9 +1745,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 58f34ee18..c98904295 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ self_update = { version = "0.37.0", default-features = false, optional = true, f ] } serde = "1.0.164" serde_derive = "1.0.152" -serde_json = "1.0.97" +serde_json = "1.0.99" shell-escape = "0.1.4" simplelog = { version = "0.12.0" } tera = { version = "1.12.1", default-features = false } From aef79a05cbbf04460f3e93668d8c4ebf378df2c6 Mon Sep 17 00:00:00 2001 From: Ben Woodward Date: Tue, 27 Jun 2023 14:10:05 +0100 Subject: [PATCH 0815/1891] Fixes for aur/aur-bin and man pages for aur releases. (#595) * add completions to aur-bin release * add man page and completions to aur package * Fix zsh completion path * Generate completions and install when using AUR from binary --- scripts/release-aur-bin.sh | 10 ++++++++-- scripts/release-aur.sh | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index f2f7d2bce..3d734a37d 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -28,14 +28,20 @@ options=('!lto') source=("rtx-\$pkgver.tar.gz::${TAR_GZ_URI}") sha512sums=('$SHA512') -prepare() { - tar -xzf rtx-\$pkgver.tar.gz +build() { + cd "\$srcdir/" + rtx/bin/rtx completions bash > rtx.bash + rtx/bin/rtx completions fish > rtx.fish + rtx/bin/rtx completions zsh > _rtx } package() { cd "\$srcdir/" install -Dm755 rtx/bin/rtx "\$pkgdir/usr/bin/rtx" install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" + install -Dm644 rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" + install -Dm644 rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" + install -Dm644 _rtx "\$pkgdir/usr/share/zsh/site-functions/_zsh" } check() { diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 542ed5086..af0f7326d 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -41,7 +41,11 @@ build() { package() { cd "\$srcdir/\$pkgname-\$pkgver" - install -Dm0755 -t "\$pkgdir/usr/bin/" "target/release/\$pkgname" + install -Dm755 target/release/rtx "\$pkgdir/usr/bin/rtx" + install -Dm644 man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" + install -Dm644 completions/rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" + install -Dm644 completions/rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" + install -Dm644 completions/_rtx "\$pkgdir/usr/share/zsh/site-functions/_rtx" } check() { From 552a74e509df79507f025617888859c83369274e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 27 Jun 2023 08:29:38 -0500 Subject: [PATCH 0816/1891] set golang source (#633) --- scripts/update-shorthand-repo.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index 030eb903a..df3d3d095 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -6,7 +6,8 @@ git clone --depth 1 https://github.com/asdf-vm/asdf-plugins rm -f src/default_shorthands.rs custom_plugins=( - '("go", "https://github.com/kennyp/asdf-golang.git"),' + '("go", "https://github.com/rtx-plugins/rtx-golang.git"),' + '("golang", "https://github.com/rtx-plugins/rtx-golang.git"),' '("java", "https://github.com/rtx-plugins/rtx-java.git"),' '("node", "https://github.com/rtx-plugins/rtx-nodejs.git"),' '("nodejs", "https://github.com/rtx-plugins/rtx-nodejs.git"),' From 42250425311478764a472980c3dbdf312fdefdf3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 27 Jun 2023 08:45:16 -0500 Subject: [PATCH 0817/1891] build alpine with edge (#632) Fixes #593 --- packaging/alpine/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/alpine/Dockerfile b/packaging/alpine/Dockerfile index 0cec8888b..b239b692b 100644 --- a/packaging/alpine/Dockerfile +++ b/packaging/alpine/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3 +FROM alpine:edge RUN apk add --no-cache sudo build-base alpine-sdk bash direnv glab atools RUN apk fix RUN adduser -D packager From 9bd6095ed0de68fb9e608377ca69f7a6713439f5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 27 Jun 2023 08:49:48 -0500 Subject: [PATCH 0818/1891] add plugin name to legacy file cache (#631) Fixes #621 --- src/plugins/external_plugin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index c2b723b3c..ade9fcd2d 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -185,6 +185,7 @@ impl ExternalPlugin { fn legacy_cache_file_path(&self, legacy_file: &Path) -> PathBuf { self.cache_path .join("legacy") + .join(&self.name) .join(hash_to_str(&legacy_file.to_string_lossy())) .with_extension("txt") } From 8ce9896317871f50eb9a240aeb04ddbecdaa0a5c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 27 Jun 2023 08:57:33 -0500 Subject: [PATCH 0819/1891] chore: Release --- Cargo.lock | 178 +++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 24 +++-- 7 files changed, 113 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e127f3c9..92ec52e0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -67,15 +67,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -221,9 +221,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.4" +version = "4.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed" +checksum = "d9394150f5b4273a1763355bd1c2ec54cc5a2593f790587bcd6b2c947cfa9211" dependencies = [ "clap_builder", "clap_derive", @@ -232,9 +232,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.4" +version = "4.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" +checksum = "9a78fbdd3cc2914ddf37ba444114bc7765bbdcb55ec9cbe6fa054f0137400717" dependencies = [ "anstream", "anstyle", @@ -261,7 +261,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -355,9 +355,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -394,9 +394,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", @@ -407,9 +407,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -441,7 +441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1586fa608b1dab41f667475b4a41faec5ba680aee428bfa5de4ea520fdc6e901" dependencies = [ "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -716,9 +716,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -727,9 +727,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "git2" @@ -770,9 +770,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -862,9 +862,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -899,9 +899,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1029,9 +1029,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" @@ -1080,9 +1080,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1095,9 +1095,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libgit2-sys" @@ -1149,9 +1149,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -1255,9 +1255,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" dependencies = [ "memchr", ] @@ -1307,9 +1307,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70" +checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" dependencies = [ "thiserror", "ucd-trie", @@ -1317,9 +1317,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b79d4c71c865a25a4322296122e3924d30bc8ee0834c8bfc8b95f7f054afbfb" +checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" dependencies = [ "pest", "pest_generator", @@ -1327,22 +1327,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e" +checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] name = "pest_meta" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745a452f8eb71e39ffd8ee32b3c5f51d03845f99786fa9b68db6ff509c505411" +checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" dependencies = [ "once_cell", "pest", @@ -1387,9 +1387,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -1469,7 +1469,7 @@ version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ - "aho-corasick 1.0.1", + "aho-corasick 1.0.2", "memchr", "regex-syntax", ] @@ -1564,7 +1564,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.32.0" +version = "1.32.1" dependencies = [ "base64", "built", @@ -1622,9 +1622,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags", "errno 0.3.1", @@ -1636,9 +1636,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ "log", "ring", @@ -1740,7 +1740,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -1777,9 +1777,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -1884,9 +1884,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -1895,15 +1895,16 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1959,7 +1960,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -1973,9 +1974,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "itoa", "libc", @@ -2033,9 +2034,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", @@ -2307,11 +2308,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -2323,9 +2323,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2333,24 +2333,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -2360,9 +2360,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2370,28 +2370,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -2590,9 +2590,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index c98904295..6bbffa005 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.32.0" +version = "1.32.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 97ce0e719..3c85e071f 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.32.0 +rtx 1.32.1 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -312,7 +312,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.32.0/rtx-v1.32.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.32.1/rtx-v1.32.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 12459a576..cca24bac2 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.32.0"; + version = "1.32.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 70da821f1..aa5f4b5f4 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.32.0" +.TH rtx 1 "rtx 1.32.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -148,6 +148,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.32.0 +v1.32.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e2db44a34..9e5a2de54 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.32.0 +Version: 1.32.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 4f4763eaa..340b497c5 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -8,7 +8,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 684] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -97,12 +97,13 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("cidrchk", "https://github.com/ORCID/asdf-cidrchk.git"), ("cilium-cli", "https://github.com/carnei-ro/asdf-cilium-cli.git"), ("cilium-hubble", "https://github.com/NitriKx/asdf-cilium-hubble.git"), + ("circleci-cli", "https://github.com/ucpr/asdf-circleci-cli.git"), ("clojure", "https://github.com/asdf-community/asdf-clojure.git"), ("cloudflared", "https://github.com/threkk/asdf-cloudflared"), ("cloudsql-proxy", "https://github.com/itspngu/asdf-cloudsql-proxy.git"), ("clusterawsadm", "https://github.com/kahun/asdf-clusterawsadm.git"), ("clusterctl", "https://github.com/pfnet-research/asdf-clusterctl.git"), - ("cmake", "https://github.com/srivathsanmurali/asdf-cmake.git"), + ("cmake", "https://github.com/asdf-community/asdf-cmake.git"), ("cmctl", "https://github.com/asdf-community/asdf-cmctl.git"), ("cockroach", "https://github.com/salasrod/asdf-cockroach.git"), ("cocoapods", "https://github.com/ronnnnn/asdf-cocoapods.git"), @@ -125,6 +126,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("crane", "https://github.com/dmpe/asdf-crane"), ("crc", "https://github.com/sqtran/asdf-crc.git"), ("credhub", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), + ("crictl", "https://github.com/FairwindsOps/asdf-crictl.git"), ("crossplane-cli", "https://github.com/joke/asdf-crossplane-cli.git"), ("crystal", "https://github.com/asdf-community/asdf-crystal.git"), ("ctlptl", "https://github.com/ezcater/asdf-ctlptl.git"), @@ -161,7 +163,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("dotenv-linter", "https://github.com/wesleimp/asdf-dotenv-linter.git"), ("dotnet", "https://github.com/hensou/asdf-dotnet"), ("dotnet-core", "https://github.com/emersonsoares/asdf-dotnet-core.git"), - ("dotty", "https://github.com/vic/asdf-dotty.git"), + ("dotty", "https://github.com/asdf-community/asdf-dotty.git"), ("dprint", "https://github.com/asdf-community/asdf-dprint"), ("draft", "https://github.com/kristoflemmens/asdf-draft.git"), ("driftctl", "https://github.com/nlamirault/asdf-driftctl.git"), @@ -181,6 +183,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("embulk", "https://github.com/yuokada/asdf-embulk.git"), ("emsdk", "https://github.com/RobLoach/asdf-emsdk.git"), ("envcli", "https://github.com/zekker6/asdf-envcli.git"), + ("ephemeral-postgres", "https://github.com/smashedtoatoms/asdf-ephemeral-postgres.git"), ("erlang", "https://github.com/asdf-vm/asdf-erlang.git"), ("esy", "https://github.com/asdf-community/asdf-esy.git"), ("etcd", "https://github.com/particledecay/asdf-etcd.git"), @@ -303,7 +306,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("jless", "https://github.com/jc00ke/asdf-jless.git"), ("jmespath", "https://github.com/skyzyx/asdf-jmespath.git"), ("jmeter", "https://github.com/comdotlinux/asdf-jmeter"), - ("jq", "https://github.com/azmcode/asdf-jq.git"), + ("jq", "https://github.com/lsanwick/asdf-jq.git"), ("jqp", "https://gitlab.com/wt0f/asdf-jqp.git"), ("jreleaser", "https://github.com/joschi/asdf-jreleaser.git"), ("jsonnet", "https://github.com/Banno/asdf-jsonnet.git"), @@ -311,6 +314,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("just", "https://github.com/olofvndrhr/asdf-just.git"), ("jx", "https://github.com/vbehar/asdf-jx.git"), ("k0sctl", "https://github.com/Its-Alex/asdf-plugin-k0sctl.git"), + ("k14s", "https://github.com/k14s/asdf-k14s.git"), ("k2tf", "https://github.com/carlduevel/asdf-k2tf.git"), ("k3d", "https://github.com/spencergilbert/asdf-k3d.git"), ("k3sup", "https://github.com/cgroschupp/asdf-k3sup.git"), @@ -416,7 +420,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("mongo-tools", "https://github.com/itspngu/asdf-mongo-tools.git"), ("mongodb", "https://github.com/sylph01/asdf-mongodb.git"), ("mongosh", "https://github.com/itspngu/asdf-mongosh.git"), - ("mutanus", "https://github.com/soriur/asdf-mutanus.git"), + ("mutanus", "https://github.com/SoriUR/asdf-mutanus.git"), ("mvnd", "https://github.com/joschi/asdf-mvnd.git"), ("mysql", "https://github.com/iroddis/asdf-mysql.git"), ("nancy", "https://github.com/iilyak/asdf-nancy.git"), @@ -480,6 +484,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("protoc-gen-js", "https://github.com/pbr0ck3r/asdf-protoc-gen-js.git"), ("protolint", "https://github.com/spencergilbert/asdf-protolint.git"), ("protonge", "https://github.com/augustobmoura/asdf-protonge.git"), + ("psc-package", "https://github.com/nsaunders/asdf-psc-package.git"), ("pulumi", "https://github.com/canha/asdf-pulumi.git"), ("purerl", "https://github.com/GoNZooo/asdf-purerl.git"), ("purescript", "https://github.com/nsaunders/asdf-purescript.git"), @@ -502,6 +507,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("reg", "https://github.com/looztra/asdf-reg.git"), ("regctl", "https://github.com/ORCID/asdf-regctl.git"), ("restic", "https://github.com/xataz/asdf-restic"), + ("revive", "https://github.com/bjw-s/asdf-revive.git"), ("richgo", "https://github.com/paxosglobal/asdf-richgo.git"), ("riff", "https://github.com/abinet/asdf-riff.git"), ("ripgrep", "https://gitlab.com/wt0f/asdf-ripgrep.git"), @@ -518,6 +524,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("sbt", "https://github.com/bram2000/asdf-sbt.git"), ("scala", "https://github.com/asdf-community/asdf-scala.git"), ("scaleway-cli", "https://github.com/albarralnunez/asdf-plugin-scaleway-cli"), + ("scalingo-cli", "https://github.com/brandon-welsch/asdf-scalingo-cli.git"), ("sccache", "https://github.com/emersonmx/asdf-sccache.git"), ("scenery", "https://github.com/skyzyx/asdf-scenery.git"), ("schemacrawler", "https://github.com/davidecavestro/asdf-schemacrawler.git"), @@ -589,7 +596,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("terraform", "https://github.com/asdf-community/asdf-hashicorp.git"), ("terraform-docs", "https://github.com/looztra/asdf-terraform-docs.git"), ("terraform-ls", "https://github.com/asdf-community/asdf-hashicorp.git"), - ("terraform-lsp", "https://github.com/bartlomiejdanek/terraform-lsp.git"), + ("terraform-lsp", "https://github.com/bartlomiejdanek/asdf-terraform-lsp.git"), ("terraform-validator", "https://github.com/looztra/asdf-terraform-validator.git"), ("terraformer", "https://github.com/grimoh/asdf-terraformer.git"), ("terragrunt", "https://github.com/ohmer/asdf-terragrunt.git"), @@ -617,9 +624,11 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("tonnage", "https://github.com/elementalvoid/asdf-tonnage.git"), ("tool-versions-to-env", "https://github.com/smartcontractkit/tool-versions-to-env-action.git"), ("trdsql", "https://github.com/johnlayton/asdf-trdsql.git"), + ("tree-sitter", "https://github.com/ivanvc/asdf-tree-sitter.git"), ("tridentctl", "https://github.com/asdf-community/asdf-tridentctl.git"), ("trivy", "https://github.com/zufardhiyaulhaq/asdf-trivy.git"), ("tsuru", "https://github.com/virtualstaticvoid/asdf-tsuru.git"), + ("tuist", "https://github.com/cprecioso/asdf-tuist.git"), ("tx", "https://github.com/ORCID/asdf-transifex.git"), ("uaa-cli", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("unison", "https://github.com/susurri/asdf-unison.git"), @@ -676,7 +685,8 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 674] = [ ("zoxide", "https://github.com/nyrst/asdf-zoxide"), ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), // rtx custom shorthands - ("go", "https://github.com/kennyp/asdf-golang.git"), + ("go", "https://github.com/rtx-plugins/rtx-golang.git"), + ("golang", "https://github.com/rtx-plugins/rtx-golang.git"), ("java", "https://github.com/rtx-plugins/rtx-java.git"), ("node", "https://github.com/rtx-plugins/rtx-nodejs.git"), ("nodejs", "https://github.com/rtx-plugins/rtx-nodejs.git"), From 7d4ed3979dab1a6e681280304847764f4acfeb1a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 28 Jun 2023 04:53:33 -0500 Subject: [PATCH 0820/1891] try to make it clearer this is a generated file people did not seem to notice the message before, hopefully they won't miss it now --- scripts/update-shorthand-repo.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index df3d3d095..66c5e64d3 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -22,8 +22,23 @@ num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') num_plugins=$((num_plugins + ${#custom_plugins[@]})) cat >src/default_shorthands.rs < Date: Wed, 28 Jun 2023 11:15:39 -0500 Subject: [PATCH 0821/1891] allow disabling tools (#636) This mainly adds 2 new settings: * disable_tools: intended to be used for disabling core plugins entirely * legacy_version_file_disable_tools: turn off legacy version file parsing for specific tools instead of disabling all of them --- README.md | 19 +++++++-- e2e/assert.sh | 9 +++++ e2e/test_nodejs | 7 ++++ schema/rtx.json | 16 ++++++++ ...cli__settings__ls__tests__settings_ls.snap | 17 ++++---- ...i__settings__set__tests__settings_set.snap | 17 ++++---- src/cli/settings/unset.rs | 16 ++++---- src/config/config_file/rtx_toml.rs | 21 +++++++++- ...nfig_file__rtx_toml__tests__fixture-2.snap | 8 +++- ...nfig_file__rtx_toml__tests__fixture-6.snap | 3 ++ src/config/mod.rs | 8 ++++ src/config/settings.rs | 40 +++++++++++++++---- src/env.rs | 28 ++++++++++++- test/fixtures/.rtx.toml | 2 + 14 files changed, 176 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 3c85e071f..5afec06a1 100644 --- a/README.md +++ b/README.md @@ -673,7 +673,8 @@ python = ['3.10', '3.11'] [settings] # plugins can read the versions files used by other version managers (if enabled by the plugin) # for example, .nvmrc in the case of node's nvm -legacy_version_file = true # enabled by default (different than asdf) +legacy_version_file = true # enabled by default (unlike asdf) +legacy_version_file_disable_tools = ['python'] # disable for specific tools # configure `rtx install` to always keep the downloaded archive always_keep_download = false # deleted after install by default @@ -696,6 +697,7 @@ raw = false # set to true to directly pipe plugins to stdin/stdout/stder shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` +disable_tools = ['node'] # disable specific tools, generally used to turn off core tools experimental = false # enable experimental features log_level = 'debug' # log verbosity, see `RTX_LOG_LEVEL` @@ -748,13 +750,19 @@ to use this feature. Set the version for a runtime. For example, `RTX_NODE_VERSION=20` will use node@20.x regardless of what is set in `.tool-versions`/`.rtx.toml`. -#### `RTX_LEGACY_VERSION_FILE` +#### `RTX_LEGACY_VERSION_FILE=1` Plugins can read the versions files used by other version managers (if enabled by the plugin) for example, `.nvmrc` in the case of node's nvm. See [legacy version files](#legacy-version-files) for more information. -#### `RTX_USE_TOML` +Set to "0" to disable legacy version file parsing. + +#### `RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS=nodejs,python` + +Disable legacy version file parsing for specific tools. Separate with `,`. + +#### `RTX_USE_TOML=0` Set to `1` to default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for configuration. This will be default behavior once we hit the [Calver](#versioning) release. @@ -830,6 +838,11 @@ 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` + +Disables the specified tools. Separate with `,`. Generally used for core plugins but works with +all. + #### `RTX_HIDE_UPDATE_WARNING=1` This hides the warning that is displayed when a new version of rtx is available. diff --git a/e2e/assert.sh b/e2e/assert.sh index 9e963def8..729d7d5e6 100644 --- a/e2e/assert.sh +++ b/e2e/assert.sh @@ -16,6 +16,15 @@ assert_contains() { fi } +assert_not_contains() { + local actual + actual="$(bash -c "$1")" + if [[ "$actual" == *"$2"* ]]; then + echo "Expected '$2' to not be in '$actual'" + exit 1 + fi +} + assert_fail() { if bash -c "$1" 2>&1; then echo "Expected failure but succeeded" diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 3d16da6b1..433060825 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -17,3 +17,10 @@ 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 + +# RTX_LEGACY_VERSION_FILE env var +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" + +# disable nodejs plugin +RTX_DISABLE_TOOLS=node assert_not_contains "rtx plugins --core" "node" diff --git a/schema/rtx.json b/schema/rtx.json index ba036ae31..2d05973c0 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -114,6 +114,14 @@ "description": "should rtx parse legacy version files (e.g. .node-version)", "type": "boolean" }, + "legacy_version_file_disable_tools": { + "description": "tools that should not have their legacy version files parsed", + "type": "array", + "items": { + "description": "tool name", + "type": "string" + } + }, "always_keep_download": { "description": "should rtx keep downloaded files after installation", "type": "boolean" @@ -154,6 +162,14 @@ "description": "disables built-in shorthands", "type": "boolean" }, + "disable_tools": { + "description": "tools that should not be used", + "type": "array", + "items": { + "description": "tool name", + "type": "string" + } + }, "trusted_config_paths": { "description": "config files with these prefixes will be trusted by default", "type": "array", diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 282d7596f..f4f739239 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -2,16 +2,19 @@ source: src/cli/settings/ls.rs expression: stdout --- -experimental = true -missing_runtime_behavior = autoinstall always_keep_download = true always_keep_install = true -legacy_version_file = true -plugin_autoupdate_last_check_duration = 20 -trusted_config_paths = [] -verbose = true asdf_compat = false -jobs = 2 disable_default_shorthands = false +disable_tools = [] +experimental = true +jobs = 2 +legacy_version_file = true +legacy_version_file_disable_tools = [] log_level = INFO +missing_runtime_behavior = autoinstall +plugin_autoupdate_last_check_duration = 20 raw = false +trusted_config_paths = [] +verbose = true + diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 8561baabc..1e83bc48e 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -2,16 +2,19 @@ source: src/cli/settings/set.rs expression: stdout --- -experimental = true -missing_runtime_behavior = autoinstall always_keep_download = true always_keep_install = true -legacy_version_file = false -plugin_autoupdate_last_check_duration = 1 -trusted_config_paths = [] -verbose = true asdf_compat = false -jobs = 2 disable_default_shorthands = false +disable_tools = [] +experimental = true +jobs = 2 +legacy_version_file = false +legacy_version_file_disable_tools = [] log_level = INFO +missing_runtime_behavior = autoinstall +plugin_autoupdate_last_check_duration = 1 raw = false +trusted_config_paths = [] +verbose = true + diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 36b94915d..c197dad2b 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -43,19 +43,21 @@ mod tests { let stdout = assert_cli!("settings"); assert_snapshot!(stdout, @r###" - experimental = true - missing_runtime_behavior = autoinstall always_keep_download = true always_keep_install = true - legacy_version_file = true - plugin_autoupdate_last_check_duration = 20 - trusted_config_paths = [] - verbose = true asdf_compat = false - jobs = 2 disable_default_shorthands = false + disable_tools = [] + experimental = true + jobs = 2 + legacy_version_file = true + legacy_version_file_disable_tools = [] log_level = INFO + missing_runtime_behavior = autoinstall + plugin_autoupdate_last_check_duration = 20 raw = false + trusted_config_paths = [] + verbose = true "###); reset_config(); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index cd698e11e..2efd03771 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -390,6 +390,10 @@ impl RtxToml { "legacy_version_file" => { settings.legacy_version_file = Some(self.parse_bool(&k, v)?) } + "legacy_version_file_disable_tools" => { + settings.legacy_version_file_disable_tools = + self.parse_string_array(&k, v)?.into_iter().collect() + } "always_keep_download" => { settings.always_keep_download = Some(self.parse_bool(&k, v)?) } @@ -401,7 +405,8 @@ impl RtxToml { Some(self.parse_duration_minutes(&k, v)?) } "trusted_config_paths" => { - settings.trusted_config_paths = self.parse_paths(&k, v)?; + settings.trusted_config_paths = + self.parse_paths(&k, v)?.into_iter().collect(); } "verbose" => settings.verbose = Some(self.parse_bool(&k, v)?), "asdf_compat" => settings.asdf_compat = Some(self.parse_bool(&k, v)?), @@ -412,6 +417,10 @@ impl RtxToml { "disable_default_shorthands" => { settings.disable_default_shorthands = Some(self.parse_bool(&k, v)?) } + "disable_tools" => { + settings.disable_tools = + self.parse_string_array(&k, v)?.into_iter().collect() + } "log_level" => settings.log_level = Some(self.parse_log_level(&k, v)?), "raw" => settings.raw = Some(self.parse_bool(&k, v)?), _ => Err(eyre!("Unknown config setting: {}", k))?, @@ -519,6 +528,16 @@ impl RtxToml { } } + fn parse_string_array(&self, k: &String, v: &Item) -> Result> { + match v + .as_array() + .map(|v| v.iter().map(|v| v.as_str().unwrap().to_string()).collect()) + { + Some(v) => Ok(v), + _ => parse_error!(k, v, "array of strings")?, + } + } + fn parse_missing_runtime_behavior( &mut self, k: &str, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 3e6b9dba4..3c04f3360 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -10,8 +10,11 @@ SettingsBuilder { always_keep_download: None, always_keep_install: None, legacy_version_file: None, + legacy_version_file_disable_tools: { + "disabled_tool_from_legacy_file", + }, plugin_autoupdate_last_check_duration: None, - trusted_config_paths: [], + trusted_config_paths: {}, verbose: Some( true, ), @@ -19,6 +22,9 @@ SettingsBuilder { jobs: None, shorthands_file: None, disable_default_shorthands: None, + disable_tools: { + "disabled_tool", + }, log_level: None, raw: None, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index 00333c559..d3250bb61 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -21,6 +21,9 @@ node = 'https://github.com/jdxcode/rtx-node' [settings] verbose = true missing_runtime_behavior = 'warn' +disable_tools = ['disabled_tool'] +legacy_version_file_disable_tools = ['disabled_tool_from_legacy_file'] [alias.node] my_custom_node = '18' + diff --git a/src/config/mod.rs b/src/config/mod.rs index 85ed0d660..f21fe1fab 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -308,6 +308,9 @@ fn load_tools(settings: &Settings) -> Result { .map(|p| (p.name.clone(), Arc::new(p))) .collect::>(); tools.extend(plugins); + for tool in &settings.disable_tools { + tools.remove(tool); + } Ok(tools) } @@ -323,6 +326,11 @@ fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap Some( filenames diff --git a/src/config/settings.rs b/src/config/settings.rs index 6856fab53..6fb99a9b6 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,8 +1,8 @@ +use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; use std::time::Duration; -use indexmap::IndexMap; use log::LevelFilter; use crate::env; @@ -15,13 +15,15 @@ pub struct Settings { pub always_keep_download: bool, pub always_keep_install: bool, pub legacy_version_file: bool, + pub legacy_version_file_disable_tools: BTreeSet, pub plugin_autoupdate_last_check_duration: Duration, - pub trusted_config_paths: Vec, + pub trusted_config_paths: BTreeSet, pub verbose: bool, pub asdf_compat: bool, pub jobs: usize, pub shorthands_file: Option, pub disable_default_shorthands: bool, + pub disable_tools: BTreeSet, pub log_level: LevelFilter, pub raw: bool, } @@ -33,7 +35,8 @@ impl Default for Settings { missing_runtime_behavior: MissingRuntimeBehavior::Warn, always_keep_download: *RTX_ALWAYS_KEEP_DOWNLOAD, always_keep_install: *RTX_ALWAYS_KEEP_INSTALL, - legacy_version_file: true, + legacy_version_file: *RTX_LEGACY_VERSION_FILE != Some(false), + legacy_version_file_disable_tools: RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS.clone(), plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), trusted_config_paths: RTX_TRUSTED_CONFIG_PATHS.clone(), verbose: *RTX_VERBOSE, @@ -41,6 +44,7 @@ impl Default for Settings { jobs: *RTX_JOBS, shorthands_file: RTX_SHORTHANDS_FILE.clone(), disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, + disable_tools: RTX_DISABLE_TOOLS.clone(), log_level: *RTX_LOG_LEVEL, raw: *RTX_RAW, } @@ -48,8 +52,8 @@ impl Default for Settings { } impl Settings { - pub fn to_index_map(&self) -> IndexMap { - let mut map = IndexMap::new(); + pub fn to_index_map(&self) -> BTreeMap { + let mut map = BTreeMap::new(); map.insert("experimental".to_string(), self.experimental.to_string()); map.insert( "missing_runtime_behavior".to_string(), @@ -67,13 +71,22 @@ impl Settings { "legacy_version_file".to_string(), self.legacy_version_file.to_string(), ); + map.insert( + "legacy_version_file_disable_tools".to_string(), + format!( + "{:?}", + self.legacy_version_file_disable_tools + .iter() + .collect::>() + ), + ); map.insert( "plugin_autoupdate_last_check_duration".to_string(), (self.plugin_autoupdate_last_check_duration.as_secs() / 60).to_string(), ); map.insert( "trusted_config_paths".to_string(), - format!("{:?}", self.trusted_config_paths), + format!("{:?}", self.trusted_config_paths.iter().collect::>()), ); map.insert("verbose".into(), self.verbose.to_string()); map.insert("asdf_compat".into(), self.asdf_compat.to_string()); @@ -88,6 +101,10 @@ impl Settings { "disable_default_shorthands".into(), self.disable_default_shorthands.to_string(), ); + map.insert( + "disable_tools".into(), + format!("{:?}", self.disable_tools.iter().collect::>()), + ); map.insert("log_level".into(), self.log_level.to_string()); map.insert("raw".into(), self.raw.to_string()); map @@ -101,13 +118,15 @@ pub struct SettingsBuilder { pub always_keep_download: Option, pub always_keep_install: Option, pub legacy_version_file: Option, + pub legacy_version_file_disable_tools: BTreeSet, pub plugin_autoupdate_last_check_duration: Option, - pub trusted_config_paths: Vec, + pub trusted_config_paths: BTreeSet, pub verbose: Option, pub asdf_compat: Option, pub jobs: Option, pub shorthands_file: Option, pub disable_default_shorthands: Option, + pub disable_tools: BTreeSet, pub log_level: Option, pub raw: Option, } @@ -135,6 +154,8 @@ impl SettingsBuilder { if other.legacy_version_file.is_some() { self.legacy_version_file = other.legacy_version_file; } + self.legacy_version_file_disable_tools + .extend(other.legacy_version_file_disable_tools); if other.plugin_autoupdate_last_check_duration.is_some() { self.plugin_autoupdate_last_check_duration = other.plugin_autoupdate_last_check_duration; @@ -155,6 +176,7 @@ impl SettingsBuilder { if other.disable_default_shorthands.is_some() { self.disable_default_shorthands = other.disable_default_shorthands; } + self.disable_tools.extend(other.disable_tools); if other.log_level.is_some() { self.log_level = other.log_level; } @@ -190,6 +212,9 @@ impl SettingsBuilder { settings.legacy_version_file = self .legacy_version_file .unwrap_or(settings.legacy_version_file); + settings + .legacy_version_file_disable_tools + .extend(self.legacy_version_file_disable_tools.clone()); settings.plugin_autoupdate_last_check_duration = self .plugin_autoupdate_last_check_duration .unwrap_or(settings.plugin_autoupdate_last_check_duration); @@ -203,6 +228,7 @@ impl SettingsBuilder { settings.disable_default_shorthands = self .disable_default_shorthands .unwrap_or(settings.disable_default_shorthands); + settings.disable_tools.extend(self.disable_tools.clone()); settings.log_level = self.log_level.unwrap_or(settings.log_level); settings.raw = self.raw.unwrap_or(settings.raw); diff --git a/src/env.rs b/src/env.rs index 63390d236..25f3a5fd8 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; pub use std::env::*; use std::path::PathBuf; use std::time::Duration; @@ -83,8 +83,20 @@ pub static RTX_SHORTHANDS_FILE: Lazy> = Lazy::new(|| var_path("RTX_SHORTHANDS_FILE")); pub static RTX_DISABLE_DEFAULT_SHORTHANDS: Lazy = Lazy::new(|| var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS")); +pub static RTX_LEGACY_VERSION_FILE: Lazy> = + Lazy::new(|| var_option_bool("RTX_LEGACY_VERSION_FILE")); +pub static RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS: Lazy> = Lazy::new(|| { + var("RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS") + .map(|v| v.split(',').map(|s| s.to_string()).collect()) + .unwrap_or_default() +}); +pub static RTX_DISABLE_TOOLS: Lazy> = Lazy::new(|| { + var("RTX_DISABLE_TOOLS") + .map(|v| v.split(',').map(|s| s.to_string()).collect()) + .unwrap_or_default() +}); pub static RTX_RAW: Lazy = Lazy::new(|| var_is_true("RTX_RAW")); -pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { +pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { var("RTX_TRUSTED_CONFIG_PATHS") .map(|v| split_paths(&v).collect()) .unwrap_or_default() @@ -171,6 +183,18 @@ fn var_is_false(key: &str) -> bool { } } +fn var_option_bool(key: &str) -> Option { + match var(key) { + Ok(_) if var_is_true(key) => Some(true), + Ok(_) if var_is_false(key) => Some(false), + Ok(v) => { + warn!("Invalid value for env var {}={}", key, v); + None + } + _ => None, + } +} + fn var_path(key: &str) -> Option { var_os(key).map(PathBuf::from).map(replace_path) } diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml index 7fc3b293d..b9b4aa5d2 100644 --- a/test/fixtures/.rtx.toml +++ b/test/fixtures/.rtx.toml @@ -17,6 +17,8 @@ node = 'https://github.com/jdxcode/rtx-node' [settings] verbose = true missing_runtime_behavior = 'warn' +disable_tools = ['disabled_tool'] +legacy_version_file_disable_tools = ['disabled_tool_from_legacy_file'] [alias.node] my_custom_node = '18' From 42f4d9e3299c87413fe4213df833fb8da41d63d7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:46:37 -0500 Subject: [PATCH 0822/1891] improve logging output (#637) show target always. Show thread/location if level is set to trace for all levels --- src/logger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logger.rs b/src/logger.rs index e52a12f1a..b89551f8e 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -34,7 +34,7 @@ fn init_log_file(log_file: PathBuf) -> Result { fn init_term_logger(level: LevelFilter) -> Box { let trace_level = if level >= LevelFilter::Trace { - LevelFilter::Trace + LevelFilter::Error } else { LevelFilter::Off }; @@ -43,8 +43,8 @@ fn init_term_logger(level: LevelFilter) -> Box { ConfigBuilder::new() .set_time_level(LevelFilter::Off) .set_thread_level(trace_level) - .set_target_level(trace_level) .set_location_level(trace_level) + .set_target_level(LevelFilter::Error) .build(), TerminalMode::Stderr, ColorChoice::Auto, From 491540bfe1358cf49d4efc4b3c4b482bd2ae4b32 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 30 Jun 2023 21:41:59 -0500 Subject: [PATCH 0823/1891] chore: Release --- Cargo.lock | 136 ++++++++++++++++++++------------------ Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 17 ++++- 7 files changed, 94 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92ec52e0a..50f2a4e10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -107,15 +107,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", + "miniz_oxide", "object", "rustc-demangle", ] @@ -132,6 +132,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "block-buffer" version = "0.10.4" @@ -221,9 +227,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.8" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9394150f5b4273a1763355bd1c2ec54cc5a2593f790587bcd6b2c947cfa9211" +checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" dependencies = [ "clap_builder", "clap_derive", @@ -232,13 +238,12 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.8" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a78fbdd3cc2914ddf37ba444114bc7765bbdcb55ec9cbe6fa054f0137400717" +checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex", "strsim", ] @@ -436,9 +441,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1586fa608b1dab41f667475b4a41faec5ba680aee428bfa5de4ea520fdc6e901" +checksum = "eed5fff0d93c7559121e9c72bf9c242295869396255071ff2cb1617147b608c5" dependencies = [ "quote", "syn 2.0.22", @@ -628,7 +633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -737,7 +742,7 @@ version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "libgit2-sys", "log", @@ -763,7 +768,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -805,15 +810,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.1" @@ -1022,7 +1018,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] @@ -1035,13 +1031,12 @@ checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", + "hermit-abi", + "rustix 0.38.1", "windows-sys 0.48.0", ] @@ -1135,6 +1130,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + [[package]] name = "log" version = "0.4.19" @@ -1168,15 +1169,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1203,7 +1195,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "static_assertions", @@ -1230,11 +1222,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] @@ -1255,9 +1247,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.30.4" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -1405,9 +1397,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -1440,7 +1432,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1449,7 +1441,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1564,7 +1556,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.32.1" +version = "1.32.2" dependencies = [ "base64", "built", @@ -1574,7 +1566,7 @@ dependencies = [ "color-eyre", "color-print", "console", - "ctor 0.2.2", + "ctor 0.2.3", "ctrlc", "dialoguer", "dirs-next", @@ -1622,15 +1614,28 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.20" +version = "0.37.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "62f25693a73057a1b4cb56179dd3c7ea21a7c6c5ee7d85781f5749b46f34b79c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno 0.3.1", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc6396159432b5c8490d4e301d8c705f61860b8b6c863bf79942ce5401968f3" +dependencies = [ + "bitflags 2.3.3", + "errno 0.3.1", + "libc", + "linux-raw-sys 0.4.3", "windows-sys 0.48.0", ] @@ -1648,9 +1653,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64", ] @@ -1903,7 +1908,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.37.21", "windows-sys 0.48.0", ] @@ -1939,7 +1944,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix", + "rustix 0.37.21", "windows-sys 0.48.0", ] @@ -2018,11 +2023,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -2453,7 +2459,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -2471,7 +2477,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -2491,9 +2497,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", diff --git a/Cargo.toml b/Cargo.toml index 6bbffa005..ff8145f9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.32.1" +version = "1.32.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 5afec06a1..947d5dcaf 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.32.1 +rtx 1.32.2 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -312,7 +312,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.32.1/rtx-v1.32.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.32.2/rtx-v1.32.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index cca24bac2..f105bd1f0 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.32.1"; + version = "1.32.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index aa5f4b5f4..34f91eb5a 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.32.1" +.TH rtx 1 "rtx 1.32.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -148,6 +148,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.32.1 +v1.32.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9e5a2de54..94c0b41aa 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.32.1 +Version: 1.32.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 340b497c5..cf1cad32c 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -1,5 +1,20 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !GENERATED FILE! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !GENERATED FILE! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !GENERATED FILE! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // This file is generated by scripts/update-shorthand-repo.sh -// Do not edit this file manually +// DO NOT EDIT THIS FILE MANUALLY. YOUR PR WILL BE REJECTED. +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !GENERATED FILE! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !GENERATED FILE! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !GENERATED FILE! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + use once_cell::sync::Lazy; use std::collections::HashMap; From 8a00c1d24e1cee3204cef77b133190c3d3bb6d3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jul 2023 05:36:54 -0500 Subject: [PATCH 0824/1891] chore(deps): bump indexmap from 1.9.3 to 2.0.0 (#640) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50f2a4e10..374354b8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -957,7 +957,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -968,6 +967,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", "hashbrown 0.14.0", + "serde", ] [[package]] @@ -1578,7 +1578,7 @@ dependencies = [ "fslock", "humantime", "indenter", - "indexmap 1.9.3", + "indexmap 2.0.0", "indicatif", "indoc", "insta", diff --git a/Cargo.toml b/Cargo.toml index ff8145f9a..0222fe98c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ flate2 = "1.0.26" fslock = "0.2.1" humantime = "2.1.0" indenter = "0.3.3" -indexmap = { version = "1.9.2", features = ["serde"] } +indexmap = { version = "2.0.0", features = ["serde"] } indicatif = { version = "0.17.5", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.11.0" From 7e469cf06c3ba1e7a2db33e319ded7dbf14202a8 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Fri, 7 Jul 2023 08:08:11 +0900 Subject: [PATCH 0825/1891] Port the "--refs" option of "plugin list" from asdf (#645) * Port the "--refs" option of "plugin list" from asdf * added test for ls --refs * fixed test --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- README.md | 4 ++++ completions/_rtx | 3 +++ completions/rtx.bash | 4 ++-- completions/rtx.fish | 3 +++ src/cli/plugins/ls.rs | 31 ++++++++++++++++++++++++++----- src/cli/plugins/mod.rs | 7 +++++++ src/git.rs | 6 ++++++ src/plugins/external_plugin.rs | 10 ++++++++++ src/plugins/mod.rs | 6 ++++++ src/tool.rs | 8 ++++++++ 10 files changed, 75 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 947d5dcaf..6deb449ab 100644 --- a/README.md +++ b/README.md @@ -2046,6 +2046,10 @@ Options: Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-node.git + --refs + Show the git refs for each plugin + e.g.: main 1234abc + Examples: $ rtx plugins ls node diff --git a/completions/_rtx b/completions/_rtx index 7d426f1a3..5c832c40f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -868,6 +868,7 @@ Normally these are not shown]' \ Normally these are not shown]' \ '-u[show the git url for each plugin]' \ '--urls[show the git url for each plugin]' \ +'--refs[show the git refs for each plugin]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. @@ -967,6 +968,8 @@ Normally these are not shown]' \ e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ '--urls[Show the git url for each plugin e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ +'--refs[Show the git refs for each plugin +e.g.\: main 1234abc]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index 16591aa02..313215d74 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2381,7 +2381,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -j -r -v -h --all --core --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help install link ls ls-remote uninstall update help" + opts="-a -c -u -j -r -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --trace --verbose --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2571,7 +2571,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -j -r -v -h --all --core --urls --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-a -c -u -j -r -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 3f9ed7698..e64282d22 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -419,6 +419,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s c -l core -d 'The built-in plugins only Normally these are not shown' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l refs -d 'show the git refs for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -467,6 +468,8 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm Normally these are not shown' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-node.git' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l refs -d 'Show the git refs for each plugin +e.g.: main 1234abc' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index f2f478bc8..2d207ef27 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -26,6 +26,11 @@ pub struct PluginsLs { /// e.g.: https://github.com/asdf-vm/asdf-node.git #[clap(short, long, verbatim_doc_comment)] pub urls: bool, + + /// Show the git refs for each plugin + /// e.g.: main 1234abc + #[clap(long, verbatim_doc_comment)] + pub refs: bool, } impl Command for PluginsLs { @@ -50,13 +55,23 @@ impl Command for PluginsLs { plugins.retain(|p| matches!(p.plugin.get_type(), PluginType::External)); } - if self.urls { + if self.urls || self.refs { for plugin in plugins { - if let Some(url) = plugin.get_remote_url() { - rtxprintln!(out, "{:29} {}", plugin.name, url); - continue; + rtxprint!(out, "{:29}", plugin.name); + if self.urls { + if let Some(url) = plugin.get_remote_url() { + rtxprint!(out, " {}", url); + } } - rtxprintln!(out, "{}", plugin.name); + if self.refs { + if let Ok(aref) = plugin.current_abbrev_ref() { + rtxprint!(out, " {}", aref); + } + if let Ok(sha) = plugin.current_sha_short() { + rtxprint!(out, " {}", sha); + } + } + rtxprint!(out, "\n"); } } else { for plugin in plugins { @@ -105,4 +120,10 @@ mod tests { "zephyr https://github.com/nsaunders/asdf-zephyr.git" ); } + + #[test] + fn test_plugin_refs() { + let stdout = assert_cli!("plugin", "list", "--refs"); + assert!(stdout.contains("dummy")) + } } diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 3c41d3f49..cccb1d373 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -34,6 +34,12 @@ pub struct Plugins { /// e.g.: https://github.com/asdf-vm/asdf-node.git #[clap(short, long)] pub urls: bool, + + /// show the git refs for each plugin + /// + /// e.g.: main 1234abc + #[clap(long)] + pub refs: bool, } #[derive(Debug, Subcommand)] @@ -65,6 +71,7 @@ impl Command for Plugins { all: self.all, core: self.core, urls: self.urls, + refs: self.refs, })); cmd.run(config, out) diff --git a/src/git.rs b/src/git.rs index fe48baa60..ee226672c 100644 --- a/src/git.rs +++ b/src/git.rs @@ -87,6 +87,12 @@ impl Git { Ok(sha) } + pub fn current_abbrev_ref(&self) -> Result { + let aref = cmd!("git", "-C", &self.dir, "rev-parse", "--abbrev-ref", "HEAD").read()?; + debug!("current abbrev ref for {}: {}", self.dir.display(), &aref); + Ok(aref) + } + pub fn get_remote_url(&self) -> Option { let res = cmd!( "git", diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ade9fcd2d..a8f886baa 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -341,6 +341,16 @@ impl Plugin for ExternalPlugin { git.get_remote_url() } + fn current_sha_short(&self) -> Result { + let git = Git::new(self.plugin_path.to_path_buf()); + git.current_sha_short() + } + + fn current_abbrev_ref(&self) -> Result { + let git = Git::new(self.plugin_path.to_path_buf()); + git.current_abbrev_ref() + } + fn is_installed(&self) -> bool { self.plugin_path.exists() } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index bba6735a1..c25fcd2d9 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -33,6 +33,12 @@ pub trait Plugin: Debug + Send + Sync { fn get_remote_url(&self) -> Option { None } + fn current_sha_short(&self) -> Result { + Ok(String::from("")) + } + fn current_abbrev_ref(&self) -> Result { + Ok(String::from("")) + } fn is_installed(&self) -> bool { true } diff --git a/src/tool.rs b/src/tool.rs index 74fb2c00b..993b86ad4 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -54,6 +54,14 @@ impl Tool { self.plugin.get_remote_url() } + pub fn current_sha_short(&self) -> Result { + self.plugin.current_sha_short() + } + + pub fn current_abbrev_ref(&self) -> Result { + self.plugin.current_abbrev_ref() + } + pub fn list_installed_versions(&self) -> Result> { Ok(match self.installs_path.exists() { true => file::dir_subdirs(&self.installs_path)? From 5b821b5ecf4a61be34a3db1011c3e25472cb36c2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:51:57 -0500 Subject: [PATCH 0826/1891] gpg sign install.sh (#647) I believe (since I have to cut a release to fully test) this makes it so you can verify the install.sh script with the following: ``` curl https://rtx.pub/install.sh.sig | gpg --decrypt | sh ``` --- scripts/publish-s3.sh | 8 ++------ scripts/release.sh | 5 +++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 68486aa94..b66e83a42 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -5,18 +5,13 @@ set -euxo pipefail cache_day="max-age=86400,s-maxage=86400,public,immutable" cache_week="max-age=604800,s-maxage=604800,public,immutable" -./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh -echo "$RTX_VERSION" | tr -d 'v' >"$RELEASE_DIR"/VERSION - -cp "$RELEASE_DIR/rtx-latest-linux-x64" "$RELEASE_DIR/rtx-latest-linux-amd64" -cp "$RELEASE_DIR/rtx-latest-macos-x64" "$RELEASE_DIR/rtx-latest-macos-amd64" - aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "rtx-latest-*" aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR/install.sh.sig" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress aws s3 cp "./rtx/schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" aws s3 cp "./rtx/schema/rtx.plugin.json" "s3://rtx.pub/schema/rtx.plugin.json" --cache-control "$cache_day" --no-progress --content-type "application/json" @@ -38,6 +33,7 @@ curl -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/pur "/VERSION", "/SHASUMS", "/install.sh", + "/install.sh.sig", "/rtx-latest-", "/rpm/repodata/", "/deb/dists/" diff --git a/scripts/release.sh b/scripts/release.sh index 96d465ce7..91d442fcd 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -44,10 +44,15 @@ for platform in "${platforms[@]}"; do done pushd "$RELEASE_DIR" +echo "$RTX_VERSION" | tr -d 'v' >VERSION +./rtx/scripts/render-install.sh >install.sh +cp "rtx-latest-linux-x64" "rtx-latest-linux-amd64" +cp "rtx-latest-macos-x64" "rtx-latest-macos-amd64" sha256sum ./rtx-latest-* >SHASUMS256.txt sha512sum ./rtx-latest-* >SHASUMS512.txt gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc +gpg -u 408B88DB29DDE9E0 --output install.sh.sig --sign install.sh popd pushd "$RELEASE_DIR/$RTX_VERSION" From cde7e5288c806bd721a612ec676796774cd124d5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:53:37 -0500 Subject: [PATCH 0827/1891] added docs for install.sh.sig --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 6deb449ab..aaa029926 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,13 @@ file, rtx will automatically add itself to `PATH`. curl https://rtx.pub/install.sh | sh ``` +If you want to verify the install hasn't been tampered with: + +``` +gpg --keyserver hkps://keys.openpgp.org --recv-keys 408B88DB29DDE9E0 +curl https://rtx.pub/install.sh.sig | gpg --decrypt | sh +``` + or if you're allergic to `| sh`: ``` From ea4d8fb6d59d212e6e370f9409caadbfb145b5fa Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:55:17 -0500 Subject: [PATCH 0828/1891] chore: Release --- Cargo.lock | 194 +++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 8 +- 7 files changed, 112 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 374354b8d..da35dce53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", "serde", @@ -227,9 +227,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.10" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" +checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" dependencies = [ "clap_builder", "clap_derive", @@ -238,9 +238,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.10" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" +checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" dependencies = [ "anstream", "anstyle", @@ -250,9 +250,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b" +checksum = "5fc443334c81a804575546c5a8a79b4913b50e28d69232903604cada1de817ce" dependencies = [ "clap", ] @@ -266,7 +266,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -360,9 +360,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -429,16 +429,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "ctor" version = "0.2.3" @@ -446,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eed5fff0d93c7559121e9c72bf9c242295869396255071ff2cb1617147b608c5" dependencies = [ "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -682,6 +672,17 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -702,6 +703,7 @@ checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-task", "memchr", "pin-project-lite", @@ -812,9 +814,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "http" @@ -882,10 +884,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", "rustls", @@ -986,9 +989,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" +checksum = "761cde40c27e2a9877f8c928fd248b7eec9dd48623dd514b256858ca593fbba7" [[package]] name = "insta" @@ -1031,12 +1034,12 @@ checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.1", + "rustix 0.38.3", "windows-sys 0.48.0", ] @@ -1060,9 +1063,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "jobserver" @@ -1270,15 +1273,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.5.0" @@ -1287,9 +1281,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "paste" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" [[package]] name = "percent-encoding" @@ -1327,7 +1321,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -1343,9 +1337,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -1367,13 +1361,11 @@ checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" [[package]] name = "pretty_assertions" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ - "ctor 0.1.26", "diff", - "output_vt100", "yansi", ] @@ -1457,9 +1449,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick 1.0.2", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "e9aaecc05d5c4b5f7da074b9a0d1a0867e71fd36e7fc0482d8bcfe8e8fc56290" dependencies = [ "aho-corasick 1.0.2", "memchr", @@ -1468,9 +1472,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" [[package]] name = "reqwest" @@ -1556,7 +1560,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.32.2" +version = "1.32.3" dependencies = [ "base64", "built", @@ -1566,7 +1570,7 @@ dependencies = [ "color-eyre", "color-print", "console", - "ctor 0.2.3", + "ctor", "ctrlc", "dialoguer", "dirs-next", @@ -1614,9 +1618,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.21" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25693a73057a1b4cb56179dd3c7ea21a7c6c5ee7d85781f5749b46f34b79c" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno 0.3.1", @@ -1628,9 +1632,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.1" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc6396159432b5c8490d4e301d8c705f61860b8b6c863bf79942ce5401968f3" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" dependencies = [ "bitflags 2.3.3", "errno 0.3.1", @@ -1641,9 +1645,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "b19faa85ecb5197342b54f987b142fb3e30d0c90da40f80ef4fa9a726e6676ed" dependencies = [ "log", "ring", @@ -1662,9 +1666,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.100.1" +version = "0.101.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e" dependencies = [ "ring", "untrusted", @@ -1672,9 +1676,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "same-file" @@ -1730,29 +1734,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.164" +version = "1.0.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "7daf513456463b42aa1d94cff7e0c24d682b429f020b9afa4f5ba5c40a22b237" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "b69b106b68bc8054f0e974e70d19984040f8a5cf9215ca82626ea4853f82c4b9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" dependencies = [ "itoa", "ryu", @@ -1889,9 +1893,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.22" +version = "2.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" dependencies = [ "proc-macro2", "quote", @@ -1908,7 +1912,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.21", + "rustix 0.37.23", "windows-sys 0.48.0", ] @@ -1944,28 +1948,28 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix 0.37.21", + "rustix 0.37.23", "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", ] [[package]] @@ -2064,9 +2068,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -2085,9 +2089,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.11" +version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" dependencies = [ "indexmap 2.0.0", "serde", @@ -2158,9 +2162,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unic-char-property" @@ -2220,9 +2224,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-normalization" @@ -2348,7 +2352,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", "wasm-bindgen-shared", ] @@ -2382,7 +2386,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.23", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2596,9 +2600,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "a9482fe6ceabdf32f3966bfdd350ba69256a97c30253dc616fe0005af24f164e" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 0222fe98c..a1b7c5ab7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.32.2" +version = "1.32.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index aaa029926..fb7f0bb97 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.32.2 +rtx 1.32.3 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -319,7 +319,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.32.2/rtx-v1.32.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.32.3/rtx-v1.32.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index f105bd1f0..e6eb72728 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.32.2"; + version = "1.32.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 34f91eb5a..e8dacc9de 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.32.2" +.TH rtx 1 "rtx 1.32.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -148,6 +148,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.32.2 +v1.32.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 94c0b41aa..0fefa7cc9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.32.2 +Version: 1.32.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index cf1cad32c..2faddc7a9 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 684] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 688] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -60,11 +60,12 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 684] = [ ("aws-sso-cli", "https://github.com/adamcrews/asdf-aws-sso-cli.git"), ("aws-vault", "https://github.com/karancode/asdf-aws-vault.git"), ("awscli", "https://github.com/MetricMike/asdf-awscli.git"), + ("awscli-local", "https://github.com/paulo-ferraz-oliveira/asdf-awscli-local"), ("awsebcli", "https://github.com/amrox/asdf-pyapp.git"), ("awsls", "https://github.com/chessmango/asdf-awsls.git"), ("awsrm", "https://github.com/chessmango/asdf-awsrm.git"), ("awsweeper", "https://github.com/chessmango/asdf-awsweeper.git"), - ("azure-cli", "https://github.com/itspngu/asdf-azure-cli.git"), + ("azure-cli", "https://github.com/EcoMind/asdf-azure-cli.git"), ("azure-functions-core-tools", "https://github.com/daveneeley/asdf-azure-functions-core-tools.git"), ("babashka", "https://github.com/pitch-io/asdf-babashka.git"), ("balena-cli", "https://github.com/boatkit-io/asdf-balena-cli"), @@ -92,6 +93,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 684] = [ ("bun", "https://github.com/cometkim/asdf-bun.git"), ("bundler", "https://github.com/jonathanmorley/asdf-bundler.git"), ("caddy", "https://github.com/salasrod/asdf-caddy.git"), + ("calicoctl", "https://github.com/TheCubicleJockey/asdf-calicoctl.git"), ("camunda-modeler", "https://github.com/barmac/asdf-camunda-modeler.git"), ("cargo-make", "https://github.com/kachick/asdf-cargo-make.git"), ("carp", "https://github.com/susurri/asdf-carp.git"), @@ -412,6 +414,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 684] = [ ("make", "https://github.com/yacchi/asdf-make.git"), ("mani", "https://github.com/anweber/asdf-mani.git"), ("mark", "https://github.com/jfreeland/asdf-mark.git"), + ("markdownlint-cli2", "https://github.com/paulo-ferraz-oliveira/asdf-markdownlint-cli2"), ("marp-cli", "https://github.com/xataz/asdf-marp-cli"), ("mask", "https://github.com/aaaaninja/asdf-mask.git"), ("maven", "https://github.com/halcyon/asdf-maven.git"), @@ -643,6 +646,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 684] = [ ("tridentctl", "https://github.com/asdf-community/asdf-tridentctl.git"), ("trivy", "https://github.com/zufardhiyaulhaq/asdf-trivy.git"), ("tsuru", "https://github.com/virtualstaticvoid/asdf-tsuru.git"), + ("ttyd", "https://github.com/ivanvc/asdf-ttyd.git"), ("tuist", "https://github.com/cprecioso/asdf-tuist.git"), ("tx", "https://github.com/ORCID/asdf-transifex.git"), ("uaa-cli", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), From ec390c6e0691a36032b965e926501c41f064231f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:18:13 -0500 Subject: [PATCH 0829/1891] Update README.md (#648) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb7f0bb97..0d459baab 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,7 @@ file, rtx will automatically add itself to `PATH`. curl https://rtx.pub/install.sh | sh ``` -If you want to verify the install hasn't been tampered with: +If you want to verify the install script hasn't been tampered with: ``` gpg --keyserver hkps://keys.openpgp.org --recv-keys 408B88DB29DDE9E0 From ad2498b8311c76aad585ca5652bb895646091234 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:28:10 -0500 Subject: [PATCH 0830/1891] fixing release script --- scripts/release.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index 91d442fcd..ca9a1b7db 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -43,11 +43,12 @@ for platform in "${platforms[@]}"; do cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" done +./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh +echo "$RTX_VERSION" | tr -d 'v' >"$RELEASE_DIR"/VERSION + pushd "$RELEASE_DIR" -echo "$RTX_VERSION" | tr -d 'v' >VERSION -./rtx/scripts/render-install.sh >install.sh -cp "rtx-latest-linux-x64" "rtx-latest-linux-amd64" -cp "rtx-latest-macos-x64" "rtx-latest-macos-amd64" +cp rtx-latest-linux-x64 rtx-latest-linux-amd64 +cp rtx-latest-macos-x64 rtx-latest-macos-amd64 sha256sum ./rtx-latest-* >SHASUMS256.txt sha512sum ./rtx-latest-* >SHASUMS512.txt gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc From ea8b19674964d54f863d50b9df137898f54c14d0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:37:03 -0500 Subject: [PATCH 0831/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da35dce53..a5f7eda06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1560,7 +1560,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.32.3" +version = "1.32.4" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index a1b7c5ab7..4620d1e8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.32.3" +version = "1.32.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 0d459baab..4ecccee82 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.32.3 +rtx 1.32.4 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -319,7 +319,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.32.3/rtx-v1.32.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.32.4/rtx-v1.32.4-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index e6eb72728..26e6bedd1 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.32.3"; + version = "1.32.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index e8dacc9de..ad983a1f4 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.32.3" +.TH rtx 1 "rtx 1.32.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -148,6 +148,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.32.3 +v1.32.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 0fefa7cc9..79b73f9ea 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.32.3 +Version: 1.32.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From e48a49987e344bc8f8bd21c5831adb9f93e3d5ca Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 15:02:11 -0500 Subject: [PATCH 0832/1891] fix release script SHASUMS is needed to render the install script --- scripts/release.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index ca9a1b7db..d833a4300 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -43,17 +43,14 @@ for platform in "${platforms[@]}"; do cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" done -./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh -echo "$RTX_VERSION" | tr -d 'v' >"$RELEASE_DIR"/VERSION - pushd "$RELEASE_DIR" +echo "$RTX_VERSION" | tr -d 'v' >VERSION cp rtx-latest-linux-x64 rtx-latest-linux-amd64 cp rtx-latest-macos-x64 rtx-latest-macos-amd64 sha256sum ./rtx-latest-* >SHASUMS256.txt sha512sum ./rtx-latest-* >SHASUMS512.txt gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc -gpg -u 408B88DB29DDE9E0 --output install.sh.sig --sign install.sh popd pushd "$RELEASE_DIR/$RTX_VERSION" @@ -63,6 +60,9 @@ gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd +./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh +gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh + NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh ./rtx/scripts/publish-s3.sh From 46b8898ff23010390d409a56237dbc99bb44a5f5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 15:03:17 -0500 Subject: [PATCH 0833/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5f7eda06..506a62d13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1560,7 +1560,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.32.4" +version = "1.32.5" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 4620d1e8e..9ac4b0083 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.32.4" +version = "1.32.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 4ecccee82..71d23c560 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.32.4 +rtx 1.32.5 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -319,7 +319,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.32.4/rtx-v1.32.4-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.32.5/rtx-v1.32.5-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 26e6bedd1..872355009 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.32.4"; + version = "1.32.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index ad983a1f4..2cc7cae8a 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.32.4" +.TH rtx 1 "rtx 1.32.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -148,6 +148,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.32.4 +v1.32.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 79b73f9ea..807d68f54 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.32.4 +Version: 1.32.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From b50c36cd23adbbc031d7b1466cb8fac8f7bd8b28 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 7 Jul 2023 16:14:03 -0500 Subject: [PATCH 0834/1891] remove version/outdated warnings (#650) These made sense when rtx was young, but I think that it is stable enough we do not need to bother users with update messages so much. --- README.md | 4 ---- SECURITY.md | 12 ------------ src/build_time.rs | 36 +----------------------------------- src/cli/mod.rs | 20 -------------------- src/config/mod.rs | 16 +--------------- src/duration.rs | 2 +- src/env.rs | 2 -- src/main.rs | 1 - 8 files changed, 3 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 71d23c560..08fc0bc31 100644 --- a/README.md +++ b/README.md @@ -850,10 +850,6 @@ installing plugins, e.g.: `rtx plugin install node https://github.com/asdf-vm/as Disables the specified tools. Separate with `,`. Generally used for core plugins but works with all. -#### `RTX_HIDE_UPDATE_WARNING=1` - -This hides the warning that is displayed when a new version of rtx is available. - #### `RTX_CONFIRM=yes|no` This will automatically answer yes or no to prompts. This is useful for scripting. diff --git a/SECURITY.md b/SECURITY.md index 0a7aec720..e34f775bb 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -49,18 +49,6 @@ Over time we should be able to move more plugins into being fully maintained by `RTX_PARANOID=1` env var that, when set, will make changes to make rtx behave as securely as possible (e.g.: only using core plugins, only allowing plugins that use GPG verification of assets). -## Privacy - -Currently the only "phoning home" that rtx does is with the weekly check for new versions. It does not send any -data (except its version), but using the IP address I'm able to infer some (very) broad usage data for rtx. You -may opt out of this behavior with `RTX_HIDE_UPDATE_WARNING=1`. You can also audit the [code](https://github.com/jdxcode/rtx/blob/main/src/cli/version.rs) -yourself to see what it does. - -I would like to see some basic, but public analytics information. I think [homebrew](https://docs.brew.sh/Analytics) -did a great job of doing this, and we'd have a similar model where the data is anonymous and publicly accessible. -Doing so will help both me and plugin authors to know if we're building effective functionality. It's also a great way -to get buy-in from organizations to do development with rtx (especially at large tech companies—they all _love_ numbers). - ## Supported Versions The only supported version is the most recent one. diff --git a/src/build_time.rs b/src/build_time.rs index da57b8783..9bad89691 100644 --- a/src/build_time.rs +++ b/src/build_time.rs @@ -1,43 +1,9 @@ -use chrono::{DateTime, FixedOffset, Months, Utc}; -use console::style; +use chrono::{DateTime, FixedOffset}; use once_cell::sync::Lazy; -use crate::env::RTX_HIDE_UPDATE_WARNING; - pub mod built_info { include!(concat!(env!("OUT_DIR"), "/built.rs")); } pub static BUILD_TIME: Lazy> = Lazy::new(|| DateTime::parse_from_rfc2822(built_info::BUILT_TIME_UTC).unwrap()); - -#[allow(dead_code)] -pub fn init() { - if !*RTX_HIDE_UPDATE_WARNING - && BUILD_TIME.checked_add_months(Months::new(12)).unwrap() < Utc::now() - { - eprintln!("{}", render_outdated_message()); - } -} - -fn render_outdated_message() -> String { - let rtx = style("rtx").dim().for_stderr(); - let mut output = vec![]; - output.push(format!( - "{rtx} rtx has not been updated in over a year. Please update to the latest version." - )); - if cfg!(any( - feature = "self_update", - feature = "alpine", - feature = "brew", - feature = "deb", - feature = "rpm", - )) { - output.push(format!("{rtx} update with: `rtx self-update`")); - } - output.push(format!( - "{rtx} To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1." - )); - - output.join("\n") -} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 9992267bf..792571437 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -213,30 +213,10 @@ impl Cli { external::execute(&config, command, sub_m, self.external_commands)?; } let cmd = Commands::from_arg_matches(&matches)?; - if !is_fast_command(&cmd) { - config.check_for_new_version(); - } cmd.run(config, out) } } -fn is_fast_command(cmd: &Commands) -> bool { - matches!( - cmd, - Commands::Version(..) - | Commands::Activate(..) - | Commands::Asdf(..) - | Commands::Completion(..) - | Commands::HookEnv(..) - | Commands::Direnv(..) - | Commands::Env(..) - | Commands::Exec(..) - | Commands::Shell(..) - | Commands::Where(..) - | Commands::Which(..) - ) -} - impl Default for Cli { fn default() -> Self { Self::new() diff --git a/src/config/mod.rs b/src/config/mod.rs index f21fe1fab..1f2651053 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -16,13 +16,12 @@ use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; -use crate::env::CI; use crate::file::display_path; use crate::plugins::core::{CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::tool::Tool; -use crate::{cli, dirs, duration, env, file, hook_env}; +use crate::{dirs, env, file, hook_env}; pub mod config_file; mod settings; @@ -232,19 +231,6 @@ impl Config { Ok(config_files) } - pub fn check_for_new_version(&self) { - if *CI || !console::user_attended_stderr() || *env::RTX_HIDE_UPDATE_WARNING { - return; - } - if let Some(latest) = cli::version::check_for_new_version(duration::WEEKLY) { - warn!( - "newer rtx version {} available, currently on {}", - latest, - env!("CARGO_PKG_VERSION") - ); - } - } - pub fn is_plugin_hidden(&self, plugin_name: &PluginName) -> bool { self.tools.get(plugin_name).map_or(false, |tool| { if matches!(tool.plugin.get_type(), PluginType::External) { diff --git a/src/duration.rs b/src/duration.rs index 6dcbef530..0e081180c 100644 --- a/src/duration.rs +++ b/src/duration.rs @@ -2,4 +2,4 @@ pub use std::time::Duration; pub(crate) const HOURLY: Duration = Duration::from_secs(60 * 60); pub(crate) const DAILY: Duration = Duration::from_secs(60 * 60 * 24); -pub(crate) const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); +//pub(crate) const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); diff --git a/src/env.rs b/src/env.rs index 25f3a5fd8..7d5c9f90a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -76,8 +76,6 @@ pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH" pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); pub static RTX_CONFIRM: Lazy = Lazy::new(|| var_confirm("RTX_CONFIRM")); pub static RTX_EXPERIMENTAL: Lazy = Lazy::new(|| var_is_true("RTX_EXPERIMENTAL")); -pub static RTX_HIDE_UPDATE_WARNING: Lazy = - Lazy::new(|| var_is_true("RTX_HIDE_UPDATE_WARNING")); pub static RTX_ASDF_COMPAT: Lazy = Lazy::new(|| var_is_true("RTX_ASDF_COMPAT")); pub static RTX_SHORTHANDS_FILE: Lazy> = Lazy::new(|| var_path("RTX_SHORTHANDS_FILE")); diff --git a/src/main.rs b/src/main.rs index 5eb15e90e..65340f660 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,7 +53,6 @@ mod toolset; mod ui; fn main() -> Result<()> { - build_time::init(); color_eyre::install()?; let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); From 21dfefca02f250b6ab111d226d6c8dca24c64823 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 14:17:13 -0500 Subject: [PATCH 0835/1891] added --missing flag to ls (#653) Fixes #651 --- README.md | 3 + completions/_rtx | 2 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/ls.rs | 110 ++++++++++-------- .../rtx__cli__ls__tests__ls_missing.snap | 5 + 6 files changed, 72 insertions(+), 51 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap diff --git a/README.md b/README.md index 08fc0bc31..6ae2445ac 100644 --- a/README.md +++ b/README.md @@ -1872,6 +1872,9 @@ Options: [short aliases: J] + -m, --missing + Display missing tool versions + Examples: $ rtx ls ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) diff --git a/completions/_rtx b/completions/_rtx index 5c832c40f..310869030 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -793,6 +793,8 @@ default\: 4]: : ' \ '--installed[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ '(--json)--parseable[Output in an easily parseable format]' \ '--json[Output in json format]' \ +'(-i --installed)-m[Display missing tool versions]' \ +'(-i --installed)--missing[Display missing tool versions]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index 313215d74..23665a6c9 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2295,7 +2295,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -i -j -r -v -h --plugin --current --installed --parseable --json --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" + opts="-p -c -i -m -j -r -v -h --plugin --current --installed --parseable --json --missing --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index e64282d22..9521ac691 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -385,6 +385,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only sho complete -c rtx -n "__fish_seen_subcommand_from ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in an easily parseable format' complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s m -l missing -d 'Display missing tool versions' complete -c rtx -n "__fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/src/cli/ls.rs b/src/cli/ls.rs index bfc3132e2..c4ddd9515 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -46,6 +46,10 @@ pub struct Ls { /// Output in json format #[clap(long, visible_short_alias = 'J', overrides_with = "parseable")] json: bool, + + /// Display missing tool versions + #[clap(long, short, conflicts_with = "installed")] + missing: bool, } impl Command for Ls { @@ -53,13 +57,16 @@ impl Command for Ls { self.plugin = self.plugin.clone().or(self.plugin_arg.clone()); self.verify_plugin(&config)?; - let mut runtimes = get_runtime_list(&mut config, &self.plugin)?; + let mut runtimes = self.get_runtime_list(&mut config)?; if self.current { runtimes.retain(|(_, _, source)| source.is_some()); } if self.installed { runtimes.retain(|(p, tv, _)| p.is_version_installed(tv)); } + if self.missing { + runtimes.retain(|(p, tv, _)| !p.is_version_installed(tv)); + } if self.json { self.display_json(runtimes, out) } else if self.parseable { @@ -193,61 +200,58 @@ impl Ls { } Ok(()) } -} -type RuntimeRow = (Arc, ToolVersion, Option); - -fn get_runtime_list( - config: &mut Config, - plugin_flag: &Option, -) -> Result> { - let ts = ToolsetBuilder::new().build(config)?; - let mut versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = ts - .list_installed_versions(config)? - .into_iter() - .filter(|(p, _)| match plugin_flag { - Some(plugin) => &p.name == plugin, - None => true, - }) - .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) - .collect(); - - let active = ts - .list_current_versions(config) - .into_iter() - .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) - .collect::, ToolVersion)>>(); - - versions.extend( - active - .clone() + fn get_runtime_list(&self, config: &mut Config) -> Result> { + let ts = ToolsetBuilder::new().build(config)?; + let mut versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = ts + .list_installed_versions(config)? .into_iter() - .filter(|((plugin_name, _), _)| match plugin_flag { - Some(plugin) => plugin_name == plugin, + .filter(|(p, _)| match &self.plugin { + Some(plugin) => &p.name == plugin, None => true, }) - .collect::, ToolVersion))>>(), - ); - - let rvs: Vec = versions - .into_iter() - .sorted_by_cached_key(|((plugin_name, version), _)| { - (plugin_name.clone(), Versioning::new(version)) - }) - .map(|(k, (p, tv))| { - let source = match &active.get(&k) { - Some((_, tv)) => ts.versions.get(&tv.plugin_name).map(|tv| tv.source.clone()), - None => None, - }; - (p, tv, source) - }) - // if it isn't installed and it's not specified, don't show it - .filter(|(p, tv, source)| source.is_some() || p.is_version_installed(tv)) - .collect(); - - Ok(rvs) + .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) + .collect(); + + let active = ts + .list_current_versions(config) + .into_iter() + .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) + .collect::, ToolVersion)>>(); + + versions.extend( + active + .clone() + .into_iter() + .filter(|((plugin_name, _), _)| match &self.plugin { + Some(plugin) => plugin_name == plugin, + None => true, + }) + .collect::, ToolVersion))>>(), + ); + + let rvs: Vec = versions + .into_iter() + .sorted_by_cached_key(|((plugin_name, version), _)| { + (plugin_name.clone(), Versioning::new(version)) + }) + .map(|(k, (p, tv))| { + let source = match &active.get(&k) { + Some((_, tv)) => ts.versions.get(&tv.plugin_name).map(|tv| tv.source.clone()), + None => None, + }; + (p, tv, source) + }) + // if it isn't installed and it's not specified, don't show it + .filter(|(p, tv, source)| source.is_some() || p.is_version_installed(tv)) + .collect(); + + Ok(rvs) + } } +type RuntimeRow = (Arc, ToolVersion, Option); + enum VersionStatus { Active(String, bool), Inactive(String), @@ -379,6 +383,12 @@ mod tests { assert_cli_snapshot!("ls", "--parseable", "tiny"); } + #[test] + fn test_ls_missing() { + assert_cli!("install"); + assert_cli_snapshot!("ls", "--missing"); + } + #[test] fn test_ls_missing_plugin() { let err = assert_cli_err!("ls", "missing-plugin"); diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap new file mode 100644 index 000000000..dc9a10412 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/ls.rs +expression: output +--- + From cb5b1ab2a5e22cca2b1c3a977c3ea79ba1dd38ff Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 14:34:16 -0500 Subject: [PATCH 0836/1891] added --prefix flag to ls (#654) This makes rtx somewhat compatible with asdf syntax like: asdf list nodejs 16 More work could be done here so that syntax works as well --- README.md | 3 +++ completions/_rtx | 1 + completions/rtx.bash | 6 +++++- completions/rtx.fish | 1 + src/cli/ls.rs | 16 ++++++++++++++++ .../rtx__cli__ls__tests__ls_prefix.snap | 6 ++++++ 6 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap diff --git a/README.md b/README.md index 6ae2445ac..88c1740dd 100644 --- a/README.md +++ b/README.md @@ -1875,6 +1875,9 @@ Options: -m, --missing Display missing tool versions + --prefix + Display versions matching this prefix + Examples: $ rtx ls ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) diff --git a/completions/_rtx b/completions/_rtx index 310869030..a86109832 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -782,6 +782,7 @@ the current value of .tool-versions/.rtx.toml will be displayed:' \ _arguments "${_arguments_options[@]}" \ '-p+[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ '--plugin=[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ +'--prefix=[Display versions matching this prefix]:PREFIX: ' \ '-j+[Number of plugins and runtimes to install in parallel default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel diff --git a/completions/rtx.bash b/completions/rtx.bash index 23665a6c9..417181106 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2295,7 +2295,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -i -m -j -r -v -h --plugin --current --installed --parseable --json --missing --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" + opts="-p -c -i -m -j -r -v -h --plugin --current --installed --parseable --json --missing --prefix --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2309,6 +2309,10 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --prefix) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 9521ac691..36f16a46e 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -378,6 +378,7 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -l trace -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show tool versions from [PLUGIN]' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -l prefix -d 'Display versions matching this prefix' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r diff --git a/src/cli/ls.rs b/src/cli/ls.rs index c4ddd9515..868c65d38 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -50,6 +50,10 @@ pub struct Ls { /// Display missing tool versions #[clap(long, short, conflicts_with = "installed")] missing: bool, + + /// Display versions matching this prefix + #[clap(long)] + prefix: Option, } impl Command for Ls { @@ -67,6 +71,12 @@ impl Command for Ls { if self.missing { runtimes.retain(|(p, tv, _)| !p.is_version_installed(tv)); } + if let Some(prefix) = &self.prefix { + if self.plugin.is_none() { + panic!("--prefix requires --plugin"); + } + runtimes.retain(|(_, tv, _)| tv.version.starts_with(prefix)); + } if self.json { self.display_json(runtimes, out) } else if self.parseable { @@ -394,4 +404,10 @@ mod tests { let err = assert_cli_err!("ls", "missing-plugin"); assert_str_eq!(err.to_string(), r#"[missing-plugin] plugin not installed"#); } + + #[test] + fn test_ls_prefix() { + assert_cli!("install"); + assert_cli_snapshot!("ls", "--plugin=tiny", "--prefix=3"); + } } diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap new file mode 100644 index 000000000..b7e229332 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/ls.rs +expression: output +--- +tiny 3.1.0 ~/cwd/.test-tool-versions 3 + From f0beeff5f7ac596e86822bdd30aec375a388f472 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 14:50:51 -0500 Subject: [PATCH 0837/1891] added install command to "Tool not installed" warning (#655) Fixes #649 --- src/toolset/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 1fe7b8549..d747422cf 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -94,7 +94,7 @@ impl Toolset { let plural_versions = if versions.len() == 1 { "" } else { "s" }; let warn = || { warn!( - "Tool{} not installed: {}", + "Tool{} not installed: {} (install with: rtx install)", plural_versions, display_versions ); }; From f3d0fa38a8abb1c5f8fd5cd6cb0df9f7fb3f2f2d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 15:45:48 -0500 Subject: [PATCH 0838/1891] added --installed option to latest command (#656) This provides an alternative way (from #654) that closes a gap where you could not easily get installed versions matching a prefix --- README.md | 10 ++-- completions/_rtx | 2 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/latest.rs | 16 ++++++- ..._cli__latest__tests__latest_installed.snap | 6 +++ src/tool.rs | 46 ++++++++++++------- src/toolset/tool_version.rs | 2 +- 8 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap diff --git a/README.md b/README.md index 88c1740dd..28d57b5b5 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ v20.0.0 - [`rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]`](#rtx-exec-options-toolversion----command) - [`rtx implode [OPTIONS]`](#rtx-implode-options) - [`rtx install [OPTIONS] [TOOL@VERSION]...`](#rtx-install-options-toolversion) - - [`rtx latest `](#rtx-latest-toolversion) + - [`rtx latest [OPTIONS] `](#rtx-latest-options-toolversion) - [`rtx ls [OPTIONS]`](#rtx-ls-options) - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-toolversion-prefix) - [`rtx outdated [TOOL@VERSION]...`](#rtx-outdated-toolversion) @@ -1832,17 +1832,21 @@ Examples: $ rtx install node # install version specified in .tool-versions or .rtx.toml $ rtx install # installs everything specified in .tool-versions or .rtx.toml ``` -### `rtx latest ` +### `rtx latest [OPTIONS] ` ``` Gets the latest available version for a plugin -Usage: latest +Usage: latest [OPTIONS] Arguments: Tool to get the latest version of +Options: + -i, --installed + Show latest installed instead of available version + Examples: $ rtx latest node@20 # get the latest version of node 20 20.0.0 diff --git a/completions/_rtx b/completions/_rtx index a86109832..2368ba6bb 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -730,6 +730,8 @@ default\: 4]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-i[Show latest installed instead of available version]' \ +'--installed[Show latest installed instead of available version]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index 417181106..96957720e 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2239,7 +2239,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" + opts="-i -j -r -v -h --installed --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 36f16a46e..ebce5eabf 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -353,6 +353,7 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -s i -l installed -d 'Show latest installed instead of available version' complete -c rtx -n "__fish_seen_subcommand_from latest" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from latest" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 0ede8329f..5ab5f50e9 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -20,6 +20,10 @@ pub struct Latest { /// used for asdf compatibility #[clap(hide = true)] asdf_version: Option, + + /// Show latest installed instead of available version + #[clap(short, long)] + installed: bool, } impl Command for Latest { @@ -45,7 +49,12 @@ impl Command for Latest { prefix = Some(config.resolve_alias(&plugin.name, &v)?); } - if let Some(version) = plugin.latest_version(&config.settings, prefix)? { + let latest_version = if self.installed { + plugin.latest_installed_version(prefix)? + } else { + plugin.latest_version(&config.settings, prefix)? + }; + if let Some(version) = latest_version { rtxprintln!(out, "{}", version); } Ok(()) @@ -85,6 +94,11 @@ mod tests { assert_display_snapshot!(err); } + #[test] + fn test_latest_installed() { + assert_cli_snapshot!("latest", "dummy"); + } + #[test] fn test_latest_missing_plugin() { let stdout = assert_cli_err!("latest", "invalid_plugin"); diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap new file mode 100644 index 000000000..30ec5fef9 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/latest.rs +expression: output +--- +2.0.0 + diff --git a/src/tool.rs b/src/tool.rs index 993b86ad4..caa656250 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -105,28 +105,32 @@ impl Tool { match query { Some(query) => { let matches = self.list_versions_matching(settings, &query)?; - let v = match matches.contains(&query) { - true => Some(query), - false => matches.last().map(|v| v.to_string()), - }; - Ok(v) + Ok(find_match_in_list(&matches, &query)) } None => self.latest_stable_version(settings), } } - pub fn latest_installed_version(&self) -> Result> { - let installed_symlink = self.installs_path.join("latest"); - if installed_symlink.exists() { - let target = installed_symlink.read_link()?; - let version = target - .file_name() - .ok_or_else(|| eyre!("Invalid symlink target"))? - .to_string_lossy() - .to_string(); - Ok(Some(version)) - } else { - Ok(None) + pub fn latest_installed_version(&self, query: Option) -> Result> { + match query { + Some(query) => { + let matches = self.list_installed_versions_matching(&query)?; + Ok(find_match_in_list(&matches, &query)) + } + None => { + let installed_symlink = self.installs_path.join("latest"); + if installed_symlink.exists() { + let target = installed_symlink.read_link()?; + let version = target + .file_name() + .ok_or_else(|| eyre!("Invalid symlink target"))? + .to_string_lossy() + .to_string(); + Ok(Some(version)) + } else { + Ok(None) + } + } } } @@ -372,3 +376,11 @@ impl PartialEq for Tool { self.plugin_path == other.plugin_path } } + +fn find_match_in_list(list: &[String], query: &str) -> Option { + let v = match list.contains(&query.to_string()) { + true => Some(query.to_string()), + false => list.last().map(|s| s.to_string()), + }; + v +} diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 07baa46ff..8b8faaf34 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -124,7 +124,7 @@ impl ToolVersion { if v == "latest" { if !latest_versions { - if let Some(v) = tool.latest_installed_version()? { + if let Some(v) = tool.latest_installed_version(None)? { return build(v); } } From f880f1c2ad0137ccfde0a49f351b18f80ebdaba6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 16:15:31 -0500 Subject: [PATCH 0839/1891] fix gpg instructions --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 28d57b5b5..1d48b7ca4 100644 --- a/README.md +++ b/README.md @@ -240,8 +240,10 @@ curl https://rtx.pub/install.sh | sh If you want to verify the install script hasn't been tampered with: ``` -gpg --keyserver hkps://keys.openpgp.org --recv-keys 408B88DB29DDE9E0 -curl https://rtx.pub/install.sh.sig | gpg --decrypt | sh +gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 0x29DDE9E0 +curl https://rtx.pub/install.sh.sig | gpg --decrypt > install.sh +# ensure the above is signed with the rtx release key +sh ./install.sh ``` or if you're allergic to `| sh`: From 3a17617a4bce2d7be1f8d6ced291c500c9005347 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 17:02:12 -0500 Subject: [PATCH 0840/1891] added link command (#657) This makes it easy to add tool versions created/managed outside of rtx Prerequisite for #643 --- Cargo.lock | 19 ++++ Cargo.toml | 1 + README.md | 46 ++++++-- completions/_rtx | 41 +++++++ completions/rtx.bash | 50 ++++++++- completions/rtx.fish | 87 ++++++++------- man/man1/rtx.1 | 3 + src/cli/install.rs | 9 +- src/cli/link.rs | 104 ++++++++++++++++++ src/cli/ls.rs | 39 ++++--- src/cli/mod.rs | 3 + src/cli/plugins/link.rs | 5 +- .../rtx__cli__link__tests__link.snap | 10 ++ .../snapshots/rtx__cli__ls__tests__ls-2.snap | 2 +- .../snapshots/rtx__cli__ls__tests__ls-3.snap | 2 +- src/cli/uninstall.rs | 6 + src/cli/upgrade.rs | 8 +- src/runtime_symlinks.rs | 2 +- src/tool.rs | 7 ++ src/toolset/mod.rs | 12 +- 20 files changed, 376 insertions(+), 80 deletions(-) create mode 100644 src/cli/link.rs create mode 100644 src/cli/snapshots/rtx__cli__link__tests__link.snap diff --git a/Cargo.lock b/Cargo.lock index 506a62d13..cb831df19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1285,6 +1285,24 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" +[[package]] +name = "path-absolutize" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43eb3595c63a214e1b37b44f44b0a84900ef7ae0b4c5efce59e123d246d7a0de" +dependencies = [ + "path-dedot", +] + +[[package]] +name = "path-dedot" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d55e486337acb9973cdea3ec5638c1b3bcb22e573b2b7b41969e0c744d5a15e" +dependencies = [ + "once_cell", +] + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1590,6 +1608,7 @@ dependencies = [ "log", "num_cpus", "once_cell", + "path-absolutize", "pretty_assertions", "rayon", "regex", diff --git a/Cargo.toml b/Cargo.toml index 9ac4b0083..dfd9289c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ itertools = "0.11.0" log = "0.4.19" num_cpus = "1.14.0" once_cell = "1.18.0" +path-absolutize = "3.1.0" rayon = "1.6.1" regex = "1.8.4" reqwest = { version = "0.11.17", default-features = false, features = [ diff --git a/README.md b/README.md index 1d48b7ca4..85574ab0d 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ v20.0.0 - [`rtx implode [OPTIONS]`](#rtx-implode-options) - [`rtx install [OPTIONS] [TOOL@VERSION]...`](#rtx-install-options-toolversion) - [`rtx latest [OPTIONS] `](#rtx-latest-options-toolversion) + - [`rtx link [OPTIONS] `](#rtx-link-options-toolversion-path) - [`rtx ls [OPTIONS]`](#rtx-ls-options) - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-toolversion-prefix) - [`rtx outdated [TOOL@VERSION]...`](#rtx-outdated-toolversion) @@ -1856,6 +1857,37 @@ Examples: $ rtx latest node # get the latest stable version of node 20.0.0 ``` +### `rtx link [OPTIONS] ` + +``` +Symlinks a tool version into rtx + +Use this for adding installs either custom compiled outside +rtx or built with a different tool. + +Usage: link [OPTIONS] + +Arguments: + + Tool name and version to create a symlink for + + + The local path to the tool version + e.g.: ~/.nvm/versions/node/v20.0.0 + +Options: + -f, --force + Overwrite an existing tool version if it exists + +Examples: + # build node-20.0.0 with node-build and link it into rtx + $ node-build 20.0.0 ~/.nodes/20.0.0 + $ rtx link node@20.0.0 ~/.nodes/20.0.0 + + # have rtx use the python version provided by Homebrew + $ brew install node@20 + $ rtx link node@20 $(brew --prefix node@20) +``` ### `rtx ls [OPTIONS]` ``` @@ -1886,17 +1918,13 @@ Options: Examples: $ rtx ls - ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) - python 3.10.0 + node 20.0.0 ~/src/myapp/.tool-versions latest + python 3.11.0 ~/.tool-versions 3.10 + python 3.10.0 $ rtx ls --current - ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) - - $ rtx ls --parseable - node 20.0.0 - python 3.11.0 + node 20.0.0 ~/src/myapp/.tool-versions 20 + python 3.11.0 ~/.tool-versions 3.11.0 $ rtx ls --json { diff --git a/completions/_rtx b/completions/_rtx index 2368ba6bb..7a24857ec 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -747,6 +747,31 @@ Sets --jobs=1]' \ '::asdf_version -- The version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ && ret=0 ;; +(link) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-f[Overwrite an existing tool version if it exists]' \ +'--force[Overwrite an existing tool version if it exists]' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +':tool -- Tool name and version to create a symlink for:' \ +':path -- The local path to the tool version +e.g.\: ~/.nvm/versions/node/v20.0.0:_files -/' \ +&& ret=0 +;; (local) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from .tool-versions]:PLUGIN: ' \ @@ -1688,6 +1713,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(link) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (local) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1862,6 +1891,7 @@ _rtx_commands() { 'install:Install a tool version' \ 'i:Install a tool version' \ 'latest:Gets the latest available version for a plugin' \ +'link:Symlinks a tool version into rtx' \ 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed and/or currently selected tool versions' \ 'list:List installed and/or currently selected tool versions' \ @@ -2229,6 +2259,7 @@ _rtx__help_commands() { 'implode:Removes rtx CLI and all related data' \ 'install:Install a tool version' \ 'latest:Gets the latest available version for a plugin' \ +'link:Symlinks a tool version into rtx' \ 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ @@ -2345,11 +2376,21 @@ _rtx__latest_commands() { local commands; commands=() _describe -t commands 'rtx latest commands' commands "$@" } +(( $+functions[_rtx__help__link_commands] )) || +_rtx__help__link_commands() { + local commands; commands=() + _describe -t commands 'rtx help link commands' commands "$@" +} (( $+functions[_rtx__help__plugins__link_commands] )) || _rtx__help__plugins__link_commands() { local commands; commands=() _describe -t commands 'rtx help plugins link commands' commands "$@" } +(( $+functions[_rtx__link_commands] )) || +_rtx__link_commands() { + local commands; commands=() + _describe -t commands 'rtx link commands' commands "$@" +} (( $+functions[_rtx__plugins__help__link_commands] )) || _rtx__plugins__help__link_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 96957720e..42d102933 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -78,6 +78,9 @@ _rtx() { rtx,latest) cmd="rtx__latest" ;; + rtx,link) + cmd="rtx__link" + ;; rtx,list) cmd="rtx__ls" ;; @@ -291,6 +294,9 @@ _rtx() { rtx__help,latest) cmd="rtx__help__latest" ;; + rtx__help,link) + cmd="rtx__help__link" + ;; rtx__help,local) cmd="rtx__help__local" ;; @@ -511,7 +517,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" + opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1369,7 +1375,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1760,6 +1766,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__link) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__local) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2264,6 +2284,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__link) + opts="-f -j -r -v -h --force --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__local) opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index ebce5eabf..bcbbdbcb1 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -27,6 +27,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] calle complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a tool version' complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_use_subcommand" -f -a "link" -d 'Symlinks a tool version into rtx' complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed and/or currently selected tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' @@ -361,6 +362,17 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from latest" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from link" -s f -l force -d 'Overwrite an existing tool version if it exists' +complete -c rtx -n "__fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from link" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r @@ -715,43 +727,44 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 2cc7cae8a..90dcc6be7 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -85,6 +85,9 @@ Install a tool version rtx\-latest(1) Gets the latest available version for a plugin .TP +rtx\-link(1) +Symlinks a tool version into rtx +.TP rtx\-ls(1) List installed and/or currently selected tool versions .TP diff --git a/src/cli/install.rs b/src/cli/install.rs index 65743d7ac..bbf0b1be1 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -13,8 +13,8 @@ use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::output::Output; -use crate::runtime_symlinks::rebuild_symlinks; -use crate::shims::reshim; +use crate::runtime_symlinks; +use crate::shims; use crate::tool::Tool; use crate::toolset::{ ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, @@ -79,8 +79,9 @@ impl Install { } self.uninstall_existing_versions(&config, &mpr, &tool_versions)?; self.install_requested_versions(&config, &mpr, tool_versions)?; - reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; - rebuild_symlinks(&config)?; + shims::reshim(&mut config, &ts) + .map_err(|err| eyre!("failed to reshim: {}", err))?; + runtime_symlinks::rebuild(&config)?; Ok(()) }) } diff --git a/src/cli/link.rs b/src/cli/link.rs new file mode 100644 index 000000000..aa544a68d --- /dev/null +++ b/src/cli/link.rs @@ -0,0 +1,104 @@ +use std::fs; +use std::path::PathBuf; + +use clap::ValueHint; +use color_eyre::eyre::{eyre, Result}; +use console::style; +use path_absolutize::Absolutize; + +use crate::cli::args::tool::{ToolArg, ToolArgParser}; +use crate::cli::command::Command; +use crate::config::Config; +use crate::file::{make_symlink, remove_all}; +use crate::output::Output; +use crate::shims; +use crate::toolset::ToolsetBuilder; +use crate::{dirs, runtime_symlinks}; + +/// Symlinks a tool version into rtx +/// +/// Use this for adding installs either custom compiled outside +/// rtx or built with a different tool. +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct Link { + /// Tool name and version to create a symlink for + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] + tool: ToolArg, + + /// The local path to the tool version + /// e.g.: ~/.nvm/versions/node/v20.0.0 + #[clap(value_hint = ValueHint::DirPath, verbatim_doc_comment)] + path: PathBuf, + + /// Overwrite an existing tool version if it exists + #[clap(long, short = 'f')] + force: bool, +} + +impl Command for Link { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + let version = match self.tool.tvr { + Some(ref tvr) => tvr.version(), + None => { + return Err(eyre!( + "must provide a version for {}", + style(&self.tool).cyan().for_stderr() + )); + } + }; + let path = self.path.absolutize()?; + if !path.exists() { + warn!( + "Target path {} does not exist", + style(path.to_string_lossy()).cyan().for_stderr() + ); + } + let target = dirs::INSTALLS.join(&self.tool.plugin).join(version); + if target.exists() { + if self.force { + remove_all(&target)?; + } else { + return Err(eyre!( + "Tool version {} already exists, use {} to overwrite", + style(&self.tool).cyan().for_stderr(), + style("--force").yellow().for_stderr() + )); + } + } + fs::create_dir_all(target.parent().unwrap())?; + make_symlink(&path, &target)?; + + let ts = ToolsetBuilder::new().build(&mut config)?; + shims::reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + runtime_symlinks::rebuild(&config)?; + + Ok(()) + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + # build node-20.0.0 with node-build and link it into rtx + $ node-build 20.0.0 ~/.nodes/20.0.0 + $ rtx link node@20.0.0 ~/.nodes/20.0.0 + + # have rtx use the python version provided by Homebrew + $ brew install node@20 + $ rtx link node@20 $(brew --prefix node@20) +"# +); + +#[cfg(test)] +mod tests { + use crate::file::create_dir_all; + use crate::{assert_cli, assert_cli_snapshot}; + + #[test] + fn test_link() { + create_dir_all("../data/tmp/tiny").unwrap(); + assert_cli!("link", "tiny@9.8.7", "../data/tmp/tiny"); + assert_cli_snapshot!("ls", "tiny"); + assert_cli!("uninstall", "tiny@9.8.7"); + } +} diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 868c65d38..fa9c5e19e 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -92,9 +92,13 @@ type JSONOutput = IndexMap>; #[derive(Serialize)] struct JSONToolVersion { version: String, + #[serde(skip_serializing_if = "Option::is_none")] requested_version: Option, install_path: PathBuf, + #[serde(skip_serializing_if = "Option::is_none")] source: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + symlinked_to: Option, } impl Ls { @@ -118,7 +122,8 @@ impl Ls { .group_by(|(p, _, _)| p.name.to_string()) { let runtimes = runtimes - .map(|(_, tv, source)| JSONToolVersion { + .map(|(p, tv, source)| JSONToolVersion { + symlinked_to: p.symlink_path(&tv), install_path: tv.install_path(), version: tv.version, requested_version: source.as_ref().map(|_| tv.request.version()), @@ -164,7 +169,9 @@ impl Ls { .into_iter() .map(|(p, tv, source)| { let plugin = p.name.to_string(); - let version = if !p.is_version_installed(&tv) { + let version = if let Some(symlink_path) = p.symlink_path(&tv) { + VersionStatus::Symlink(tv.version, symlink_path) + } else if !p.is_version_installed(&tv) { VersionStatus::Missing(tv.version) } else if source.is_some() { VersionStatus::Active(tv.version.clone(), p.is_version_outdated(config, &tv)) @@ -198,15 +205,16 @@ impl Ls { .max(0) as usize; let version = version.to_string(); let version = pad(&version, max_version_len - plugin_extra); - match &request { + let line = match &request { Some((source, requested)) => { let source = pad(source, max_source_len - version_extra); - rtxprintln!(out, "{} {} {} {}", plugin, version, source, requested); + format!("{} {} {} {}", plugin, version, source, requested) } None => { - rtxprintln!(out, "{} {}", plugin, version); + format!("{} {}", plugin, version) } - } + }; + rtxprintln!(out, "{}", line.trim_end()); } Ok(()) } @@ -266,6 +274,7 @@ enum VersionStatus { Active(String, bool), Inactive(String), Missing(String), + Symlink(String, PathBuf), } impl VersionStatus { @@ -280,6 +289,7 @@ impl VersionStatus { } VersionStatus::Inactive(version) => version.to_string(), VersionStatus::Missing(version) => format!("{} (missing)", version), + VersionStatus::Symlink(version, _) => format!("{} (symlink)", version), } } } @@ -310,6 +320,9 @@ impl Display for VersionStatus { }, style("(missing)").red() ), + VersionStatus::Symlink(version, _) => { + write!(f, "{} {}", version, style("(symlink)").dim()) + } } } } @@ -317,17 +330,13 @@ impl Display for VersionStatus { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx ls - ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) - python 3.10.0 + node 20.0.0 ~/src/myapp/.tool-versions latest + python 3.11.0 ~/.tool-versions 3.10 + python 3.10.0 $ rtx ls --current - ⏵ node 20.0.0 (set by ~/src/myapp/.tool-versions) - ⏵ python 3.11.0 (set by ~/.tool-versions) - - $ rtx ls --parseable - node 20.0.0 - python 3.11.0 + node 20.0.0 ~/src/myapp/.tool-versions 20 + python 3.11.0 ~/.tool-versions 3.11.0 $ rtx ls --json { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 792571437..b808f2e50 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -29,6 +29,7 @@ mod hook_env; mod implode; mod install; mod latest; +mod link; mod local; mod ls; mod ls_remote; @@ -74,6 +75,7 @@ pub enum Commands { Implode(implode::Implode), Install(install::Install), Latest(latest::Latest), + Link(link::Link), Local(local::Local), Ls(ls::Ls), LsRemote(ls_remote::LsRemote), @@ -117,6 +119,7 @@ impl Commands { Self::Implode(cmd) => cmd.run(config, out), Self::Install(cmd) => cmd.run(config, out), Self::Latest(cmd) => cmd.run(config, out), + Self::Link(cmd) => cmd.run(config, out), Self::Local(cmd) => cmd.run(config, out), Self::Ls(cmd) => cmd.run(config, out), Self::LsRemote(cmd) => cmd.run(config, out), diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index a72f3530e..1d298f73a 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use clap::ValueHint; use color_eyre::eyre::{eyre, Result}; use console::style; +use path_absolutize::Absolutize; use crate::cli::command::Command; use crate::config::Config; @@ -37,12 +38,12 @@ impl Command for PluginsLink { let (name, path) = match self.path { Some(path) => (self.name, path), None => { - let path = PathBuf::from(&self.name).canonicalize()?; + let path = PathBuf::from(PathBuf::from(&self.name).absolutize()?); let name = get_name_from_path(&path); (name, path) } }; - let path = path.canonicalize()?; + let path = path.absolutize()?; let symlink = dirs::PLUGINS.join(&name); if symlink.exists() { if self.force { diff --git a/src/cli/snapshots/rtx__cli__link__tests__link.snap b/src/cli/snapshots/rtx__cli__link__tests__link.snap new file mode 100644 index 000000000..709ba7b0b --- /dev/null +++ b/src/cli/snapshots/rtx__cli__link__tests__link.snap @@ -0,0 +1,10 @@ +--- +source: src/cli/link.rs +expression: output +--- +tiny 1.0.1 +tiny 2.1.0 +tiny 3.0.1 +tiny 3.1.0 ~/cwd/.test-tool-versions 3 +tiny 9.8.7 (symlink) + diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap index fe5aef32a..d37d8cb22 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap @@ -3,6 +3,6 @@ source: src/cli/ls.rs expression: output --- dummy ref:master ~/.test-tool-versions ref:master -tiny 2.0.0 +tiny 2.0.0 tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap index 32e4d68d1..e94646e29 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap @@ -3,6 +3,6 @@ source: src/cli/ls.rs expression: output --- dummy ref:master ~/.test-tool-versions ref:master -tiny 2.0.0 +tiny 2.0.0 tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 8660be96d..8d5d673ac 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -7,6 +7,7 @@ use crate::config::Config; use crate::output::Output; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::{runtime_symlinks, shims}; /// Removes runtime versions #[derive(Debug, clap::Args)] @@ -55,6 +56,11 @@ impl Command for Uninstall { } pr.finish_with_message("uninstalled"); } + + let ts = ToolsetBuilder::new().build(&mut config)?; + shims::reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + runtime_symlinks::rebuild(&config)?; + Ok(()) } } diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 8e6e4c77a..f369fd2ec 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -10,8 +10,8 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::runtime_symlinks::rebuild_symlinks; -use crate::shims::reshim; +use crate::runtime_symlinks; +use crate::shims; use crate::tool::Tool; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -69,8 +69,8 @@ impl Upgrade { self.install_new_versions(config, &mut mpr, outdated)?; let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; - reshim(config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; - rebuild_symlinks(config)?; + shims::reshim(config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + runtime_symlinks::rebuild(config)?; Ok(()) }) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 43bc1b0e3..ad15e660b 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -12,7 +12,7 @@ use crate::dirs; use crate::file::make_symlink; use crate::tool::Tool; -pub fn rebuild_symlinks(config: &Config) -> Result<()> { +pub fn rebuild(config: &Config) -> Result<()> { for plugin in config.tools.values() { remove_existing_symlinks(plugin)?; let symlinks = list_symlinks(config, plugin)?; diff --git a/src/tool.rs b/src/tool.rs index caa656250..7b6ecba2f 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -186,6 +186,13 @@ impl Tool { !self.is_version_installed(tv) || tv.version != latest } + pub fn symlink_path(&self, tv: &ToolVersion) -> Option { + match tv.install_path() { + path if path.is_symlink() => Some(path), + _ => None, + } + } + pub fn install_version( &self, config: &Config, diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index d747422cf..542464e5a 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -22,8 +22,8 @@ pub use tool_version_request::ToolVersionRequest; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; use crate::plugins::PluginName; -use crate::runtime_symlinks::rebuild_symlinks; -use crate::shims::reshim; +use crate::runtime_symlinks; +use crate::shims; use crate::tool::Tool; use crate::ui::multi_progress_report::MultiProgressReport; @@ -180,8 +180,8 @@ impl Toolset { Ok(()) }) .collect::>>()?; - reshim(config, self)?; - rebuild_symlinks(config)?; + shims::reshim(config, self)?; + runtime_symlinks::rebuild(config)?; Ok(()) }) } @@ -287,6 +287,10 @@ impl Toolset { self.list_current_versions(config) .into_iter() .filter_map(|(t, tv)| { + if t.symlink_path(&tv).is_some() { + // do not consider symlinked versions to be outdated + return None; + } let latest = match tv.latest_version(config, &t) { Ok(latest) => latest, Err(e) => { From be627fb27150dbee38f9ab17de5645b399767f1e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 17:33:22 -0500 Subject: [PATCH 0841/1891] fixed usage text for subcommands in README (#659) --- README.md | 32 ++++++++++++++++---------------- src/cli/render_help.rs | 2 ++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 85574ab0d..f4f459fc8 100644 --- a/README.md +++ b/README.md @@ -1509,7 +1509,7 @@ Show an alias for a plugin This is the contents of an alias. entry in ~/.config/rtx/config.toml -Usage: get +Usage: alias get Arguments: @@ -1534,7 +1534,7 @@ For user config, aliases are defined like the following in `~/.config/rtx/config [alias.node] lts = "20.0.0" -Usage: ls [OPTIONS] +Usage: alias ls [OPTIONS] Options: -p, --plugin @@ -1551,7 +1551,7 @@ Add/update an alias for a plugin This modifies the contents of ~/.config/rtx/config.toml -Usage: set +Usage: alias set Arguments: @@ -1573,7 +1573,7 @@ Clears an alias for a plugin This modifies the contents of ~/.config/rtx/config.toml -Usage: unset +Usage: alias unset Arguments: @@ -1597,7 +1597,7 @@ Usage: bin-paths ``` Deletes all cache files in rtx -Usage: clear +Usage: cache clear ``` ### `rtx completion [SHELL]` @@ -1672,7 +1672,7 @@ Because this generates the legacy files based on currently installed plugins, you should run this command after installing new plugins. Otherwise direnv may not know to update environment variables when legacy file versions change. -Usage: activate +Usage: direnv activate Examples: $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh @@ -2005,7 +2005,7 @@ e.g.: `rtx install node@20` will autoinstall the node plugin This behavior can be modified in ~/.config/rtx/config.toml -Usage: install [OPTIONS] [NAME] [GIT_URL] +Usage: plugins install [OPTIONS] [NAME] [GIT_URL] Arguments: [NAME] @@ -2049,7 +2049,7 @@ Symlinks a plugin into rtx This is used for developing a plugin. -Usage: link [OPTIONS] [PATH] +Usage: plugins link [OPTIONS] [PATH] Arguments: @@ -2078,7 +2078,7 @@ List installed plugins Can also show remotely available plugins to install. -Usage: ls [OPTIONS] +Usage: plugins ls [OPTIONS] Options: -c, --core @@ -2113,7 +2113,7 @@ Examples: $ rtx plugins ls-remote -Usage: ls-remote [OPTIONS] +Usage: plugins ls-remote [OPTIONS] Options: -u, --urls @@ -2127,7 +2127,7 @@ Options: ``` Removes a plugin -Usage: uninstall ... +Usage: plugins uninstall ... Arguments: ... @@ -2143,7 +2143,7 @@ Updates a plugin to the latest version note: this updates the plugin itself, not the runtime versions -Usage: update [PLUGIN]... +Usage: plugins update [PLUGIN]... Arguments: [PLUGIN]... @@ -2226,7 +2226,7 @@ This is the contents of a single entry in ~/.config/rtx/config.toml Note that aliases are also stored in this file but managed separately with `rtx aliases get` -Usage: get +Usage: settings get Arguments: @@ -2246,7 +2246,7 @@ This is the contents of ~/.config/rtx/config.toml Note that aliases are also stored in this file but managed separately with `rtx aliases` -Usage: ls +Usage: settings ls Examples: $ rtx settings @@ -2259,7 +2259,7 @@ Add/update a setting This modifies the contents of ~/.config/rtx/config.toml -Usage: set +Usage: settings set Arguments: @@ -2278,7 +2278,7 @@ Clears a setting This modifies the contents of ~/.config/rtx/config.toml -Usage: unset +Usage: settings unset Arguments: diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 85f9d0d5e..8a004416b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -79,6 +79,8 @@ fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option Some(p) => format!("{} {}", p, strip_usage(c.render_usage())), None => strip_usage(c.render_usage()), }; + let mut c = c.override_usage(&usage); + let about = strip_ansi_codes(&c.render_long_help().to_string()) .trim() .to_string(); From bb95d4e1af680d60cba9f05bf44e3e6279541bc9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 17:51:20 -0500 Subject: [PATCH 0842/1891] added sync-python-pyenv command (#658) This makes it possible to use pyenv to install/manage runtimes and have rtx switch between versions --- README.md | 19 ++++++ completions/_rtx | 142 +++++++++++++++++++++++++++++++++++++++ completions/rtx.bash | 147 ++++++++++++++++++++++++++++++++++++++++- completions/rtx.fish | 104 ++++++++++++++++++----------- man/man1/rtx.1 | 3 + src/cli/link.rs | 10 +-- src/cli/mod.rs | 3 + src/cli/sync/mod.rs | 34 ++++++++++ src/cli/sync/python.rs | 58 ++++++++++++++++ src/config/mod.rs | 7 ++ src/env.rs | 2 + src/file.rs | 17 +++++ src/tool.rs | 13 +++- 13 files changed, 508 insertions(+), 51 deletions(-) create mode 100644 src/cli/sync/mod.rs create mode 100644 src/cli/sync/python.rs diff --git a/README.md b/README.md index f4f459fc8..87a7c97ea 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ v20.0.0 - [`rtx settings set `](#rtx-settings-set-key-value) - [`rtx settings unset `](#rtx-settings-unset-key) - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) + - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall ...`](#rtx-uninstall-toolversion) - [`rtx upgrade [TOOL@VERSION]...`](#rtx-upgrade-toolversion) @@ -2309,6 +2310,24 @@ Examples: $ node -v v20.0.0 ``` +### `rtx sync python --pyenv` + +``` +Symlinks all tool versions from an external tool into rtx + +For example, import all pyenv installs into rtx + +Usage: sync python --pyenv + +Options: + --pyenv + Get tool versions from pyenv + +Examples: + $ pyenv install 3.11.0 + $ rtx sync python --pyenv + # rtx will have symlinked the pyenv versions into rtx's install directory +``` ### `rtx trust [OPTIONS] [CONFIG_FILE]` ``` diff --git a/completions/_rtx b/completions/_rtx index 7a24857ec..66a766dc8 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1367,6 +1367,83 @@ Sets --jobs=1]' \ '*::tool -- Tool(s) to use:' \ && ret=0 ;; +(sync) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help]' \ +'--help[Print help]' \ +":: :_rtx__sync_commands" \ +"*::: :->sync" \ +&& ret=0 + + case $state in + (sync) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-sync-command-$line[1]:" + case $line[1] in + (python) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--pyenv[Get tool versions from pyenv]' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__sync__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-sync-help-command-$line[1]:" + case $line[1] in + (python) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; (trust) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel @@ -1821,6 +1898,26 @@ esac _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(sync) +_arguments "${_arguments_options[@]}" \ +":: :_rtx__help__sync_commands" \ +"*::: :->sync" \ +&& ret=0 + + case $state in + (sync) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rtx-help-sync-command-$line[1]:" + case $line[1] in + (python) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; (trust) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -1904,6 +2001,7 @@ _rtx_commands() { 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ +'sync:Add tool versions from external tools to rtx' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ 'upgrade:\[experimental\] Upgrades outdated tool versions' \ @@ -2270,6 +2368,7 @@ _rtx__help_commands() { 'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ +'sync:Add tool versions from external tools to rtx' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ 'upgrade:\[experimental\] Upgrades outdated tool versions' \ @@ -2321,6 +2420,19 @@ _rtx__settings__help__help_commands() { local commands; commands=() _describe -t commands 'rtx settings help help commands' commands "$@" } +(( $+functions[_rtx__sync__help_commands] )) || +_rtx__sync__help_commands() { + local commands; commands=( +'python:Symlinks all tool versions from an external tool into rtx' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx sync help commands' commands "$@" +} +(( $+functions[_rtx__sync__help__help_commands] )) || +_rtx__sync__help__help_commands() { + local commands; commands=() + _describe -t commands 'rtx sync help help commands' commands "$@" +} (( $+functions[_rtx__help__hook-env_commands] )) || _rtx__help__hook-env_commands() { local commands; commands=() @@ -2540,6 +2652,21 @@ _rtx__prune_commands() { local commands; commands=() _describe -t commands 'rtx prune commands' commands "$@" } +(( $+functions[_rtx__help__sync__python_commands] )) || +_rtx__help__sync__python_commands() { + local commands; commands=() + _describe -t commands 'rtx help sync python commands' commands "$@" +} +(( $+functions[_rtx__sync__help__python_commands] )) || +_rtx__sync__help__python_commands() { + local commands; commands=() + _describe -t commands 'rtx sync help python commands' commands "$@" +} +(( $+functions[_rtx__sync__python_commands] )) || +_rtx__sync__python_commands() { + local commands; commands=() + _describe -t commands 'rtx sync python commands' commands "$@" +} (( $+functions[_rtx__help__render-help_commands] )) || _rtx__help__render-help_commands() { local commands; commands=() @@ -2638,6 +2765,21 @@ _rtx__shell_commands() { local commands; commands=() _describe -t commands 'rtx shell commands' commands "$@" } +(( $+functions[_rtx__help__sync_commands] )) || +_rtx__help__sync_commands() { + local commands; commands=( +'python:Symlinks all tool versions from an external tool into rtx' \ + ) + _describe -t commands 'rtx help sync commands' commands "$@" +} +(( $+functions[_rtx__sync_commands] )) || +_rtx__sync_commands() { + local commands; commands=( +'python:Symlinks all tool versions from an external tool into rtx' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rtx sync commands' commands "$@" +} (( $+functions[_rtx__help__trust_commands] )) || _rtx__help__trust_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 42d102933..a571d12b0 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -120,6 +120,9 @@ _rtx() { rtx,shell) cmd="rtx__shell" ;; + rtx,sync) + cmd="rtx__sync" + ;; rtx,trust) cmd="rtx__trust" ;; @@ -330,6 +333,9 @@ _rtx() { rtx__help,shell) cmd="rtx__help__shell" ;; + rtx__help,sync) + cmd="rtx__help__sync" + ;; rtx__help,trust) cmd="rtx__help__trust" ;; @@ -405,6 +411,9 @@ _rtx() { rtx__help__settings,unset) cmd="rtx__help__settings__unset" ;; + rtx__help__sync,python) + cmd="rtx__help__sync__python" + ;; rtx__plugins,a) cmd="rtx__plugins__install" ;; @@ -510,6 +519,18 @@ _rtx() { rtx__settings__help,unset) cmd="rtx__settings__help__unset" ;; + rtx__sync,help) + cmd="rtx__sync__help" + ;; + rtx__sync,python) + cmd="rtx__sync__python" + ;; + rtx__sync__help,help) + cmd="rtx__sync__help__help" + ;; + rtx__sync__help,python) + cmd="rtx__sync__help__python" + ;; *) ;; esac @@ -517,7 +538,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" + opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1375,7 +1396,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell trust uninstall upgrade use version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2074,6 +2095,34 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__sync) + opts="python" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__sync__python) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__trust) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -3068,6 +3117,100 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__sync) + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help python help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__help) + opts="python help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__help__python) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__python) + opts="-j -r -v -h --pyenv --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__trust) opts="-j -r -v -h --untrust --debug --install-missing --jobs --log-level --raw --trace --verbose --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index bcbbdbcb1..c21f7ef79 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -38,6 +38,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d 'rebuilds the shim complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_use_subcommand" -f -a "sync" -d 'Add tool versions from external tools to rtx' complete -c rtx -n "__fish_use_subcommand" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' complete -c rtx -n "__fish_use_subcommand" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' @@ -634,6 +635,31 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l pyenv -d 'Get tool versions from pyenv' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r @@ -727,44 +753,45 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. @@ -787,4 +814,5 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'Show current settings' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "set" -d 'Add/update a setting' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "unset" -d 'Clears a setting' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 90dcc6be7..a793debb5 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -115,6 +115,9 @@ Manage settings rtx\-shell(1) Sets a tool version for the current shell session .TP +rtx\-sync(1) +Add tool versions from external tools to rtx +.TP rtx\-trust(1) Marks a config file as trusted .TP diff --git a/src/cli/link.rs b/src/cli/link.rs index aa544a68d..8250cde65 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -9,11 +9,9 @@ use path_absolutize::Absolutize; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; +use crate::dirs; use crate::file::{make_symlink, remove_all}; use crate::output::Output; -use crate::shims; -use crate::toolset::ToolsetBuilder; -use crate::{dirs, runtime_symlinks}; /// Symlinks a tool version into rtx /// @@ -69,11 +67,7 @@ impl Command for Link { fs::create_dir_all(target.parent().unwrap())?; make_symlink(&path, &target)?; - let ts = ToolsetBuilder::new().build(&mut config)?; - shims::reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; - runtime_symlinks::rebuild(&config)?; - - Ok(()) + config.rebuild_shims_and_runtime_symlinks() } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b808f2e50..57bcf3518 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -42,6 +42,7 @@ mod reshim; mod self_update; mod settings; mod shell; +mod sync; mod trust; mod uninstall; mod upgrade; @@ -86,6 +87,7 @@ pub enum Commands { SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Shell(shell::Shell), + Sync(sync::Sync), Trust(trust::Trust), Uninstall(uninstall::Uninstall), Upgrade(upgrade::Upgrade), @@ -130,6 +132,7 @@ impl Commands { Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Shell(cmd) => cmd.run(config, out), + Self::Sync(cmd) => cmd.run(config, out), Self::Trust(cmd) => cmd.run(config, out), Self::Uninstall(cmd) => cmd.run(config, out), Self::Upgrade(cmd) => cmd.run(config, out), diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs new file mode 100644 index 000000000..c12cf6719 --- /dev/null +++ b/src/cli/sync/mod.rs @@ -0,0 +1,34 @@ +use clap::Subcommand; +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +mod python; + +#[derive(Debug, clap::Args)] +#[clap(about = "Add tool versions from external tools to rtx")] +pub struct Sync { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Debug, Subcommand)] +enum Commands { + Python(python::SyncPython), +} + +impl Commands { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + match self { + Self::Python(cmd) => cmd.run(config, out), + } + } +} + +impl Command for Sync { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + self.command.run(config, out) + } +} diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs new file mode 100644 index 000000000..f65400ada --- /dev/null +++ b/src/cli/sync/python.rs @@ -0,0 +1,58 @@ +use color_eyre::eyre::Result; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::dirs; +use crate::env::PYENV_ROOT; +use crate::file; +use crate::output::Output; +use crate::plugins::PluginName; + +/// Symlinks all tool versions from an external tool into rtx +/// +/// For example, import all pyenv installs into rtx +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct SyncPython { + /// Get tool versions from pyenv + #[clap(long, required = true)] + pyenv: bool, +} + +impl Command for SyncPython { + fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + let python = config.get_or_create_tool(&PluginName::from("python")); + + let pyenv_versions_path = PYENV_ROOT.join("versions"); + let installed_python_versions_path = dirs::INSTALLS.join("python"); + + file::remove_symlinks_with_target_prefix( + &installed_python_versions_path, + &pyenv_versions_path, + )?; + + for v in file::dir_subdirs(&pyenv_versions_path)? { + python.create_symlink(&v, &pyenv_versions_path.join(&v))?; + } + + config.rebuild_shims_and_runtime_symlinks() + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ pyenv install 3.11.0 + $ rtx sync python --pyenv + # rtx will have symlinked the pyenv versions into rtx's install directory +"# +); + +#[cfg(test)] +mod tests { + use crate::assert_cli; + + #[test] + fn test_pyenv() { + assert_cli!("sync", "python", "--pyenv"); + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 1f2651053..aa5544606 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -239,6 +239,13 @@ impl Config { plugin_name == "nodejs" || plugin_name == "golang" }) } + + pub fn rebuild_shims_and_runtime_symlinks(&mut self) -> Result<()> { + let ts = crate::toolset::ToolsetBuilder::new().build(self)?; + crate::shims::reshim(self, &ts)?; + crate::runtime_symlinks::rebuild(self)?; + Ok(()) + } } fn get_project_root(config_files: &ConfigMap) -> Option { diff --git a/src/env.rs b/src/env.rs index 7d5c9f90a..1b6125589 100644 --- a/src/env.rs +++ b/src/env.rs @@ -116,6 +116,8 @@ pub static RTX_PYTHON_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_PYTHON_DEFAULT_PACKAGES_FILE") .unwrap_or_else(|| HOME.join(".default-python-packages")) }); +pub static PYENV_ROOT: Lazy = + Lazy::new(|| var_path("PYENV_ROOT").unwrap_or_else(|| HOME.join(".pyenv"))); // node pub static RTX_NODE_CONCURRENCY: Lazy = Lazy::new(|| { diff --git a/src/file.rs b/src/file.rs index 59aeff64c..1f2063c1e 100644 --- a/src/file.rs +++ b/src/file.rs @@ -133,6 +133,23 @@ pub fn make_symlink(target: &Path, link: &Path) -> Result<()> { Ok(()) } +pub fn remove_symlinks_with_target_prefix(symlink_dir: &Path, target_prefix: &Path) -> Result<()> { + if !symlink_dir.exists() { + return Ok(()); + } + for entry in symlink_dir.read_dir()? { + let entry = entry?; + let path = entry.path(); + if path.is_symlink() { + let target = path.read_link()?; + if target.starts_with(target_prefix) { + fs::remove_file(&path)?; + } + } + } + Ok(()) +} + pub fn is_executable(path: &Path) -> bool { if let Ok(metadata) = path.metadata() { return metadata.permissions().mode() & 0o111 != 0; diff --git a/src/tool.rs b/src/tool.rs index 7b6ecba2f..53a20670a 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, HashMap}; -use std::fs::{remove_file, File}; +use std::fs; +use std::fs::File; use std::path::{Path, PathBuf}; use clap::Command; @@ -193,6 +194,12 @@ impl Tool { } } + pub fn create_symlink(&self, version: &str, target: &Path) -> Result<()> { + let link = self.installs_path.join(version); + fs::create_dir_all(link.parent().unwrap())?; + file::make_symlink(target, &link) + } + pub fn install_version( &self, config: &Config, @@ -218,7 +225,7 @@ impl Tool { debug!("error touching config file: {:?} {:?}", path, err); } } - if let Err(err) = remove_file(self.incomplete_file_path(tv)) { + if let Err(err) = fs::remove_file(self.incomplete_file_path(tv)) { debug!("error removing incomplete file: {:?}", err); } pr.finish(); @@ -320,7 +327,7 @@ impl Tool { let _ = remove_all_with_warning(tv.install_path()); let _ = remove_all_with_warning(tv.download_path()); let _ = remove_all_with_warning(tv.cache_path()); - let _ = remove_file(tv.install_path()); // removes if it is a symlink + let _ = fs::remove_file(tv.install_path()); // removes if it is a symlink create_dir_all(tv.install_path())?; create_dir_all(tv.download_path())?; create_dir_all(tv.cache_path())?; From 2572370f7834e173700eb414b2da358eb2d1c2f6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 18:25:25 -0500 Subject: [PATCH 0843/1891] added sync-node-brew command (#660) --- README.md | 23 ++++++++++++-- completions/_rtx | 53 ++++++++++++++++++++++++++++++-- completions/rtx.bash | 69 ++++++++++++++++++++++++++++++++++++++++-- completions/rtx.fish | 44 ++++++++++++++++++--------- src/cli/sync/mod.rs | 3 ++ src/cli/sync/node.rs | 63 ++++++++++++++++++++++++++++++++++++++ src/cli/sync/python.rs | 11 ++++--- 7 files changed, 239 insertions(+), 27 deletions(-) create mode 100644 src/cli/sync/node.rs diff --git a/README.md b/README.md index 87a7c97ea..ebf9a435d 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ v20.0.0 - [`rtx settings set `](#rtx-settings-set-key-value) - [`rtx settings unset `](#rtx-settings-unset-key) - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) + - [`rtx sync node --brew`](#rtx-sync-node---brew) - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall ...`](#rtx-uninstall-toolversion) @@ -2310,12 +2311,30 @@ Examples: $ node -v v20.0.0 ``` +### `rtx sync node --brew` + +``` +Symlinks all tool versions from an external tool into rtx + +For example, use this to import all Homebrew node installs into rtx + +Usage: sync node --brew + +Options: + --brew + Get tool versions from Homebrew + +Examples: + $ brew install node@18 node@20 + $ rtx sync node --brew + $ rtx use -g node@18 uses Homebrew-provided node +``` ### `rtx sync python --pyenv` ``` Symlinks all tool versions from an external tool into rtx -For example, import all pyenv installs into rtx +For example, use this to import all pyenv installs into rtx Usage: sync python --pyenv @@ -2326,7 +2345,7 @@ Options: Examples: $ pyenv install 3.11.0 $ rtx sync python --pyenv - # rtx will have symlinked the pyenv versions into rtx's install directory + $ rtx use -g python@3.11.0 uses pyenv-provided python ``` ### `rtx trust [OPTIONS] [CONFIG_FILE]` diff --git a/completions/_rtx b/completions/_rtx index 66a766dc8..f538d352d 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1395,7 +1395,28 @@ Sets --jobs=1]' \ (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:rtx-sync-command-$line[1]:" case $line[1] in - (python) + (node) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +default\: 4]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--brew[Get tool versions from Homebrew]' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(python) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel default\: 4]: : ' \ @@ -1428,7 +1449,11 @@ _arguments "${_arguments_options[@]}" \ (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:rtx-sync-help-command-$line[1]:" case $line[1] in - (python) + (node) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(python) _arguments "${_arguments_options[@]}" \ && ret=0 ;; @@ -1910,7 +1935,11 @@ _arguments "${_arguments_options[@]}" \ (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:rtx-help-sync-command-$line[1]:" case $line[1] in - (python) + (node) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(python) _arguments "${_arguments_options[@]}" \ && ret=0 ;; @@ -2423,6 +2452,7 @@ _rtx__settings__help__help_commands() { (( $+functions[_rtx__sync__help_commands] )) || _rtx__sync__help_commands() { local commands; commands=( +'node:Symlinks all tool versions from an external tool into rtx' \ 'python:Symlinks all tool versions from an external tool into rtx' \ 'help:Print this message or the help of the given subcommand(s)' \ ) @@ -2603,6 +2633,21 @@ _rtx__plugins__ls-remote_commands() { local commands; commands=() _describe -t commands 'rtx plugins ls-remote commands' commands "$@" } +(( $+functions[_rtx__help__sync__node_commands] )) || +_rtx__help__sync__node_commands() { + local commands; commands=() + _describe -t commands 'rtx help sync node commands' commands "$@" +} +(( $+functions[_rtx__sync__help__node_commands] )) || +_rtx__sync__help__node_commands() { + local commands; commands=() + _describe -t commands 'rtx sync help node commands' commands "$@" +} +(( $+functions[_rtx__sync__node_commands] )) || +_rtx__sync__node_commands() { + local commands; commands=() + _describe -t commands 'rtx sync node commands' commands "$@" +} (( $+functions[_rtx__help__outdated_commands] )) || _rtx__help__outdated_commands() { local commands; commands=() @@ -2768,6 +2813,7 @@ _rtx__shell_commands() { (( $+functions[_rtx__help__sync_commands] )) || _rtx__help__sync_commands() { local commands; commands=( +'node:Symlinks all tool versions from an external tool into rtx' \ 'python:Symlinks all tool versions from an external tool into rtx' \ ) _describe -t commands 'rtx help sync commands' commands "$@" @@ -2775,6 +2821,7 @@ _rtx__help__sync_commands() { (( $+functions[_rtx__sync_commands] )) || _rtx__sync_commands() { local commands; commands=( +'node:Symlinks all tool versions from an external tool into rtx' \ 'python:Symlinks all tool versions from an external tool into rtx' \ 'help:Print this message or the help of the given subcommand(s)' \ ) diff --git a/completions/rtx.bash b/completions/rtx.bash index a571d12b0..a38f71ed0 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -411,6 +411,9 @@ _rtx() { rtx__help__settings,unset) cmd="rtx__help__settings__unset" ;; + rtx__help__sync,node) + cmd="rtx__help__sync__node" + ;; rtx__help__sync,python) cmd="rtx__help__sync__python" ;; @@ -522,12 +525,18 @@ _rtx() { rtx__sync,help) cmd="rtx__sync__help" ;; + rtx__sync,node) + cmd="rtx__sync__node" + ;; rtx__sync,python) cmd="rtx__sync__python" ;; rtx__sync__help,help) cmd="rtx__sync__help__help" ;; + rtx__sync__help,node) + cmd="rtx__sync__help__node" + ;; rtx__sync__help,python) cmd="rtx__sync__help__python" ;; @@ -2096,7 +2105,7 @@ _rtx() { return 0 ;; rtx__help__sync) - opts="python" + opts="node python" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2109,6 +2118,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__sync__node) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__sync__python) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -3118,7 +3141,7 @@ _rtx() { return 0 ;; rtx__sync) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help python help" + opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3144,7 +3167,7 @@ _rtx() { return 0 ;; rtx__sync__help) - opts="python help" + opts="node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3171,6 +3194,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__sync__help__node) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__sync__help__python) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -3185,6 +3222,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__sync__node) + opts="-j -r -v -h --brew --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__sync__python) opts="-j -r -v -h --pyenv --debug --install-missing --jobs --log-level --raw --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index c21f7ef79..60d641b59 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -635,18 +635,30 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +default: 4' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l brew -d 'Get tool versions from Homebrew' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r @@ -658,8 +670,9 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r @@ -814,5 +827,6 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'Show current settings' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "set" -d 'Add/update a setting' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "unset" -d 'Clears a setting' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from python" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs index c12cf6719..1c1de0dd2 100644 --- a/src/cli/sync/mod.rs +++ b/src/cli/sync/mod.rs @@ -5,6 +5,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +mod node; mod python; #[derive(Debug, clap::Args)] @@ -16,12 +17,14 @@ pub struct Sync { #[derive(Debug, Subcommand)] enum Commands { + Node(node::SyncNode), Python(python::SyncPython), } impl Commands { pub fn run(self, config: Config, out: &mut Output) -> Result<()> { match self { + Self::Node(cmd) => cmd.run(config, out), Self::Python(cmd) => cmd.run(config, out), } } diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs new file mode 100644 index 000000000..f3b8209fc --- /dev/null +++ b/src/cli/sync/node.rs @@ -0,0 +1,63 @@ +use std::path::PathBuf; + +use color_eyre::eyre::Result; +use itertools::sorted; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::file; +use crate::output::Output; +use crate::plugins::PluginName; +use crate::{cmd, dirs}; + +/// Symlinks all tool versions from an external tool into rtx +/// +/// For example, use this to import all Homebrew node installs into rtx +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct SyncNode { + /// Get tool versions from Homebrew + #[clap(long, required = true)] + brew: bool, +} + +impl Command for SyncNode { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + let tool = config.get_or_create_tool(&PluginName::from("node")); + + let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); + let installed_versions_path = dirs::INSTALLS.join("node"); + + file::remove_symlinks_with_target_prefix(&installed_versions_path, &brew_prefix)?; + + let subdirs = file::dir_subdirs(&brew_prefix)?; + for entry in sorted(subdirs) { + if !entry.starts_with("node@") { + continue; + } + let v = entry.trim_start_matches("node@"); + tool.create_symlink(v, &brew_prefix.join(&entry))?; + rtxprintln!(out, "Synced node@{} from Homebrew", v); + } + + config.rebuild_shims_and_runtime_symlinks() + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ brew install node@18 node@20 + $ rtx sync node --brew + $ rtx use -g node@18 uses Homebrew-provided node +"# +); + +#[cfg(test)] +mod tests { + use crate::assert_cli; + + #[test] + fn test_pyenv() { + assert_cli!("sync", "python", "--pyenv"); + } +} diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index f65400ada..a78a2de68 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Result; +use itertools::sorted; use crate::cli::command::Command; use crate::config::Config; @@ -10,7 +11,7 @@ use crate::plugins::PluginName; /// Symlinks all tool versions from an external tool into rtx /// -/// For example, import all pyenv installs into rtx +/// For example, use this to import all pyenv installs into rtx #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct SyncPython { @@ -20,7 +21,7 @@ pub struct SyncPython { } impl Command for SyncPython { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let python = config.get_or_create_tool(&PluginName::from("python")); let pyenv_versions_path = PYENV_ROOT.join("versions"); @@ -31,8 +32,10 @@ impl Command for SyncPython { &pyenv_versions_path, )?; - for v in file::dir_subdirs(&pyenv_versions_path)? { + let subdirs = file::dir_subdirs(&pyenv_versions_path)?; + for v in sorted(subdirs) { python.create_symlink(&v, &pyenv_versions_path.join(&v))?; + rtxprintln!(out, "Synced python@{} from pyenv", v); } config.rebuild_shims_and_runtime_symlinks() @@ -43,7 +46,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ pyenv install 3.11.0 $ rtx sync python --pyenv - # rtx will have symlinked the pyenv versions into rtx's install directory + $ rtx use -g python@3.11.0 uses pyenv-provided python "# ); From 252b0d835631237c7bf8b9c90981b5d11156013a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 19:17:16 -0500 Subject: [PATCH 0844/1891] added support for nvm and nodenv to sync-node (#661) --- README.md | 16 ++++++--- completions/_rtx | 2 ++ completions/rtx.bash | 2 +- completions/rtx.fish | 2 ++ src/cli/sync/node.rs | 80 +++++++++++++++++++++++++++++++++++------- src/cli/sync/python.rs | 2 +- src/env.rs | 4 +++ 7 files changed, 88 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ebf9a435d..4f4308ada 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ v20.0.0 - [`rtx settings set `](#rtx-settings-set-key-value) - [`rtx settings unset `](#rtx-settings-unset-key) - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) - - [`rtx sync node --brew`](#rtx-sync-node---brew) + - [`rtx sync node <--brew|--nvm|--nodenv>`](#rtx-sync-node---brew--nvm--nodenv) - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall ...`](#rtx-uninstall-toolversion) @@ -2311,23 +2311,29 @@ Examples: $ node -v v20.0.0 ``` -### `rtx sync node --brew` +### `rtx sync node <--brew|--nvm|--nodenv>` ``` Symlinks all tool versions from an external tool into rtx For example, use this to import all Homebrew node installs into rtx -Usage: sync node --brew +Usage: sync node <--brew|--nvm|--nodenv> Options: --brew Get tool versions from Homebrew + --nvm + Get tool versions from nvm + + --nodenv + Get tool versions from nodenv + Examples: $ brew install node@18 node@20 $ rtx sync node --brew - $ rtx use -g node@18 uses Homebrew-provided node + $ rtx use -g node@18 - uses Homebrew-provided node ``` ### `rtx sync python --pyenv` @@ -2345,7 +2351,7 @@ Options: Examples: $ pyenv install 3.11.0 $ rtx sync python --pyenv - $ rtx use -g python@3.11.0 uses pyenv-provided python + $ rtx use -g python@3.11.0 - uses pyenv-provided python ``` ### `rtx trust [OPTIONS] [CONFIG_FILE]` diff --git a/completions/_rtx b/completions/_rtx index f538d352d..de6543b3d 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1403,6 +1403,8 @@ default\: 4]: : ' \ default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--brew[Get tool versions from Homebrew]' \ +'--nvm[Get tool versions from nvm]' \ +'--nodenv[Get tool versions from nodenv]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index a38f71ed0..920c2065d 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3223,7 +3223,7 @@ _rtx() { return 0 ;; rtx__sync__node) - opts="-j -r -v -h --brew --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -v -h --brew --nvm --nodenv --debug --install-missing --jobs --log-level --raw --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 60d641b59..eef4abe2c 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -652,6 +652,8 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l brew -d 'Get tool versions from Homebrew' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nvm -d 'Get tool versions from nvm' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nodenv -d 'Get tool versions from nodenv' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index f3b8209fc..483e416dc 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -5,6 +5,7 @@ use itertools::sorted; use crate::cli::command::Command; use crate::config::Config; +use crate::env::{NODENV_ROOT, NVM_DIR}; use crate::file; use crate::output::Output; use crate::plugins::PluginName; @@ -16,13 +17,41 @@ use crate::{cmd, dirs}; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct SyncNode { + #[clap(flatten)] + _type: SyncNodeType, +} + +#[derive(Debug, clap::Args)] +#[group(required = true)] +pub struct SyncNodeType { /// Get tool versions from Homebrew - #[clap(long, required = true)] + #[clap(long)] brew: bool, + + /// Get tool versions from nvm + #[clap(long)] + nvm: bool, + + /// Get tool versions from nodenv + #[clap(long)] + nodenv: bool, } impl Command for SyncNode { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + if self._type.brew { + self.run_brew(config, out)?; + } else if self._type.nvm { + self.run_nvm(config, out)?; + } else if self._type.nodenv { + self.run_nodenv(config, out)?; + } + Ok(()) + } +} + +impl SyncNode { + fn run_brew(self, mut config: Config, out: &mut Output) -> Result<()> { let tool = config.get_or_create_tool(&PluginName::from("node")); let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); @@ -42,22 +71,47 @@ impl Command for SyncNode { config.rebuild_shims_and_runtime_symlinks() } + + fn run_nvm(self, mut config: Config, out: &mut Output) -> Result<()> { + let tool = config.get_or_create_tool(&PluginName::from("node")); + + let nvm_versions_path = NVM_DIR.join("versions").join("node"); + let installed_versions_path = dirs::INSTALLS.join("node"); + + file::remove_symlinks_with_target_prefix(&installed_versions_path, &nvm_versions_path)?; + + let subdirs = file::dir_subdirs(&nvm_versions_path)?; + for entry in sorted(subdirs) { + let v = entry.trim_start_matches('v'); + tool.create_symlink(v, &nvm_versions_path.join(&entry))?; + rtxprintln!(out, "Synced node@{} from nvm", v); + } + + config.rebuild_shims_and_runtime_symlinks() + } + + fn run_nodenv(self, mut config: Config, out: &mut Output) -> Result<()> { + let tool = config.get_or_create_tool(&PluginName::from("node")); + + let nodenv_versions_path = NODENV_ROOT.join("versions"); + let installed_versions_path = dirs::INSTALLS.join("node"); + + file::remove_symlinks_with_target_prefix(&installed_versions_path, &nodenv_versions_path)?; + + let subdirs = file::dir_subdirs(&nodenv_versions_path)?; + for v in sorted(subdirs) { + tool.create_symlink(&v, &nodenv_versions_path.join(&v))?; + rtxprintln!(out, "Synced node@{} from nodenv", v); + } + + config.rebuild_shims_and_runtime_symlinks() + } } static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ brew install node@18 node@20 $ rtx sync node --brew - $ rtx use -g node@18 uses Homebrew-provided node + $ rtx use -g node@18 - uses Homebrew-provided node "# ); - -#[cfg(test)] -mod tests { - use crate::assert_cli; - - #[test] - fn test_pyenv() { - assert_cli!("sync", "python", "--pyenv"); - } -} diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index a78a2de68..2f737bf0c 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -46,7 +46,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ pyenv install 3.11.0 $ rtx sync python --pyenv - $ rtx use -g python@3.11.0 uses pyenv-provided python + $ rtx use -g python@3.11.0 - uses pyenv-provided python "# ); diff --git a/src/env.rs b/src/env.rs index 1b6125589..ffb5214fd 100644 --- a/src/env.rs +++ b/src/env.rs @@ -144,6 +144,10 @@ pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { HOME.join(".default-npm-packages") }) }); +pub static NVM_DIR: Lazy = + Lazy::new(|| var_path("NVM_DIR").unwrap_or_else(|| HOME.join(".nvm"))); +pub static NODENV_ROOT: Lazy = + Lazy::new(|| var_path("NODENV_ROOT").unwrap_or_else(|| HOME.join(".nodenv"))); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { From a5b80dc4100bed8ae3c357db7771160468e9e134 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 19:47:56 -0500 Subject: [PATCH 0845/1891] fix bug with RTX_DISABLE_TOOLS (#662) Fixes #641 --- ...x__config__config_file__rtx_toml__tests__fixture-4.snap | 1 + ...onfig__config_file__rtx_toml__tests__remove_plugin.snap | 1 + ...ig__config_file__rtx_toml__tests__replace_versions.snap | 1 + src/toolset/builder.rs | 1 + src/toolset/mod.rs | 7 ++++++- 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index 971eaba29..b7634f241 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -121,4 +121,5 @@ Toolset { ), ), latest_versions: false, + disable_tools: {}, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap index 72b2e5609..1cbf09703 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap @@ -10,4 +10,5 @@ Toolset { ), ), latest_versions: false, + disable_tools: {}, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index b7ab2dfcf..52eb02332 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -34,4 +34,5 @@ Toolset { ), ), latest_versions: false, + disable_tools: {}, } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 5a3531d9e..ad7a762a8 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -38,6 +38,7 @@ impl ToolsetBuilder { pub fn build(self, config: &mut Config) -> Result { let mut toolset = Toolset { latest_versions: self.latest_versions, + disable_tools: config.settings.disable_tools.clone(), ..Default::default() }; load_config_files(config, &mut toolset); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 542464e5a..862e11c60 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::path::PathBuf; @@ -45,6 +45,7 @@ pub struct Toolset { pub versions: IndexMap, pub source: Option, pub latest_versions: bool, + pub disable_tools: BTreeSet, } impl Toolset { @@ -55,6 +56,9 @@ impl Toolset { } } pub fn add_version(&mut self, tvr: ToolVersionRequest, opts: ToolVersionOptions) { + if self.disable_tools.contains(tvr.plugin_name()) { + return; + } let tvl = self .versions .entry(tvr.plugin_name().clone()) @@ -70,6 +74,7 @@ impl Toolset { versions.insert(plugin, tvl); } } + versions.retain(|_, tvl| !self.disable_tools.contains(&tvl.plugin_name)); self.versions = versions; self.source = other.source.clone(); } From 1d2cdedf1df4c631875d541f542edd5da78ecb8e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:21:48 -0500 Subject: [PATCH 0846/1891] allow multiple plugins to use the same legacy filename (#663) Fixes #621 --- src/config/config_file/legacy_version.rs | 31 ++++++++++----------- src/config/mod.rs | 34 +++++++++++++++++------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 54e6c4e13..a5b48e8d4 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::default::Default; use std::fmt::Display; use std::path::{Path, PathBuf}; +use std::sync::Arc; use color_eyre::eyre::Result; @@ -19,13 +20,20 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(settings: &Settings, path: PathBuf, plugin: &Tool) -> Result { - let version = plugin.parse_legacy_file(path.as_path(), settings)?; + pub fn parse(settings: &Settings, path: PathBuf, plugins: &[&Arc]) -> Result { + let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.clone())); - Ok(Self { - toolset: build_toolset(&path, plugin.name.as_str(), version.as_str()), - path, - }) + for plugin in plugins { + let version = plugin.parse_legacy_file(&path, settings)?; + for version in version.split_whitespace() { + toolset.add_version( + ToolVersionRequest::new(plugin.name.to_string(), version), + Default::default(), + ); + } + } + + Ok(Self { toolset, path }) } } @@ -88,14 +96,3 @@ impl Display for LegacyVersionFile { write!(f, "LegacyVersionFile({})", self.path.display()) } } - -fn build_toolset(path: &Path, plugin: &str, version: &str) -> Toolset { - let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.to_path_buf())); - for version in version.split_whitespace() { - toolset.add_version( - ToolVersionRequest::new(plugin.to_string(), version), - Default::default(), - ); - } - toolset -} diff --git a/src/config/mod.rs b/src/config/mod.rs index aa5544606..04367fef2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -35,7 +35,6 @@ type ToolMap = BTreeMap>; pub struct Config { pub settings: Settings, pub global_config: RtxToml, - pub legacy_files: BTreeMap, pub config_files: ConfigMap, pub tools: ToolMap, pub env: BTreeMap, @@ -103,7 +102,6 @@ impl Config { project_root: get_project_root(&config_files), config_files, settings, - legacy_files, global_config, tools, should_exit_early, @@ -311,11 +309,11 @@ fn build_tool(name: PluginName, plugin: Box) -> Arc { Arc::new(Tool::new(name, plugin)) } -fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap { +fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap> { if !settings.legacy_version_file { return BTreeMap::new(); } - tools + let legacy = tools .values() .collect_vec() .into_par_iter() @@ -339,12 +337,21 @@ fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap>>() .into_iter() .flatten() - .collect() + .collect::>(); + + let mut legacy_filenames = BTreeMap::new(); + for (filename, plugin) in legacy { + legacy_filenames + .entry(filename) + .or_insert_with(Vec::new) + .push(plugin); + } + legacy_filenames } fn load_config_filenames( settings: &Settings, - legacy_filenames: &BTreeMap, + legacy_filenames: &BTreeMap>, ) -> Vec { let mut filenames = legacy_filenames.keys().cloned().collect_vec(); filenames.push(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone()); @@ -386,7 +393,7 @@ fn load_all_config_files( settings: &Settings, config_filenames: &[PathBuf], tools: &ToolMap, - legacy_filenames: &BTreeMap, + legacy_filenames: &BTreeMap>, mut existing: ConfigMap, ) -> Result { Ok(config_filenames @@ -414,13 +421,20 @@ fn load_all_config_files( fn parse_config_file( f: &PathBuf, settings: &Settings, - legacy_filenames: &BTreeMap, + legacy_filenames: &BTreeMap>, tools: &ToolMap, ) -> Result> { let is_trusted = config_file::is_trusted(settings, f); match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { - Some(plugin) => LegacyVersionFile::parse(settings, f.into(), tools.get(plugin).unwrap()) - .map(|f| Box::new(f) as Box), + Some(plugin) => { + let tools = tools + .iter() + .filter(|(k, _)| plugin.contains(k)) + .map(|(_, t)| t) + .collect::>(); + LegacyVersionFile::parse(settings, f.into(), &tools) + .map(|f| Box::new(f) as Box) + } None => config_file::parse(f, is_trusted), } } From fe594d4a78cd1763a684fd6bf74af8dde1bce0c6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 21:44:33 -0500 Subject: [PATCH 0847/1891] alias nodejs -> node and golang -> go (#664) Fixes #560 --- README.md | 26 ++++++++++++++++--- e2e/gopath/test_gopath | 6 ++--- e2e/test_nodejs | 6 +++-- src/cli/args/tool.rs | 15 ++++++----- src/cli/current.rs | 16 +++++++----- src/cli/ls.rs | 8 ++++-- src/cli/plugins/install.rs | 5 ++-- src/cli/plugins/link.rs | 6 +++-- src/cli/plugins/uninstall.rs | 4 ++- src/cli/plugins/update.rs | 3 ++- src/cli/prune.rs | 5 ++-- src/config/config_file/rtx_toml.rs | 7 ++--- src/config/config_file/tool_versions.rs | 4 +-- src/main.rs | 4 +++ src/migrate.rs | 34 +++++++++++++++++++++++++ src/plugins/core/mod.rs | 1 - src/plugins/mod.rs | 8 ++++++ 17 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 src/migrate.rs diff --git a/README.md b/README.md index 4f4308ada..e907caef9 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 70394bfb2..c2e0162bf 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 433060825..5e1c83b6e 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 46884f732..2c8f32439 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 2a9ab7e30..e40e6563a 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 fa9c5e19e..1a75ad6fb 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 e93ea851a..df68f464e 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 1d298f73a..e13d50322 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 e080f53be..c82adc5cf 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 342a61e8d..e8ac9f112 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 7fa115d71..cdef2a64d 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 2efd03771..468d7e74b 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 76ccaf6df..186cbf409 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 65340f660..344951321 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 000000000..99cd54efd --- /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 17d53200c..88029685d 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 c25fcd2d9..2d7d09866 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, From 3f417a96653f20fb49cb6bcc1787f11f29ccc1c3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 21:50:28 -0500 Subject: [PATCH 0848/1891] dim inactive symlinked versions on ls (#665) --- src/cli/ls.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 1a75ad6fb..995b109e8 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -174,7 +174,7 @@ impl Ls { .map(|(p, tv, source)| { let plugin = p.name.to_string(); let version = if let Some(symlink_path) = p.symlink_path(&tv) { - VersionStatus::Symlink(tv.version, symlink_path) + VersionStatus::Symlink(tv.version, symlink_path, source.is_some()) } else if !p.is_version_installed(&tv) { VersionStatus::Missing(tv.version) } else if source.is_some() { @@ -278,7 +278,7 @@ enum VersionStatus { Active(String, bool), Inactive(String), Missing(String), - Symlink(String, PathBuf), + Symlink(String, PathBuf, bool), } impl VersionStatus { @@ -293,7 +293,7 @@ impl VersionStatus { } VersionStatus::Inactive(version) => version.to_string(), VersionStatus::Missing(version) => format!("{} (missing)", version), - VersionStatus::Symlink(version, _) => format!("{} (symlink)", version), + VersionStatus::Symlink(version, _, _) => format!("{} (symlink)", version), } } } @@ -324,8 +324,17 @@ impl Display for VersionStatus { }, style("(missing)").red() ), - VersionStatus::Symlink(version, _) => { - write!(f, "{} {}", version, style("(symlink)").dim()) + VersionStatus::Symlink(version, _, active) => { + write!( + f, + "{} {}", + if *active { + style(version) + } else { + style(version).dim() + }, + style("(symlink)").dim() + ) } } } From 9a9b92ba77e1a4703b936420ac20812237f17278 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 8 Jul 2023 21:51:39 -0500 Subject: [PATCH 0849/1891] chore: Release --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb831df19..e5e251ff7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1479,9 +1479,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaecc05d5c4b5f7da074b9a0d1a0867e71fd36e7fc0482d8bcfe8e8fc56290" +checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" dependencies = [ "aho-corasick 1.0.2", "memchr", @@ -1578,7 +1578,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.32.5" +version = "1.33.0" dependencies = [ "base64", "built", @@ -1753,18 +1753,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.167" +version = "1.0.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daf513456463b42aa1d94cff7e0c24d682b429f020b9afa4f5ba5c40a22b237" +checksum = "d614f89548720367ded108b3c843be93f3a341e22d5674ca0dd5cd57f34926af" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.167" +version = "1.0.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69b106b68bc8054f0e974e70d19984040f8a5cf9215ca82626ea4853f82c4b9" +checksum = "d4fe589678c688e44177da4f27152ee2d190757271dc7f1d5b6b9f68d869d641" dependencies = [ "proc-macro2", "quote", @@ -2619,9 +2619,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9482fe6ceabdf32f3966bfdd350ba69256a97c30253dc616fe0005af24f164e" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index dfd9289c9..b616451ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.32.5" +version = "1.33.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e907caef9..00cc8a60d 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.32.5 +rtx 1.33.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -325,7 +325,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.32.5/rtx-v1.32.5-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.33.0/rtx-v1.33.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 872355009..ca78f3b86 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.32.5"; + version = "1.33.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a793debb5..33d270de2 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.32.5" +.TH rtx 1 "rtx 1.33.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.32.5 +v1.33.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 807d68f54..7720a8ad3 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.32.5 +Version: 1.33.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 72b403a16565bbf62676ca9c6c1df864801ac375 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Jul 2023 10:36:41 -0500 Subject: [PATCH 0850/1891] brew instructions --- README.md | 5 +++-- src/cli/link.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 00cc8a60d..37e463aca 100644 --- a/README.md +++ b/README.md @@ -1905,8 +1905,9 @@ Examples: $ rtx link node@20.0.0 ~/.nodes/20.0.0 # have rtx use the python version provided by Homebrew - $ brew install node@20 - $ rtx link node@20 $(brew --prefix node@20) + $ brew install node + $ rtx link node@brew $(brew --prefix node) + $ rtx use node@brew ``` ### `rtx ls [OPTIONS]` diff --git a/src/cli/link.rs b/src/cli/link.rs index 8250cde65..019dc857e 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -78,8 +78,9 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ rtx link node@20.0.0 ~/.nodes/20.0.0 # have rtx use the python version provided by Homebrew - $ brew install node@20 - $ rtx link node@20 $(brew --prefix node@20) + $ brew install node + $ rtx link node@brew $(brew --prefix node) + $ rtx use node@brew "# ); From 3459c189a4bc53ad9d05a6ef507dd21db6546575 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Jul 2023 10:49:30 -0500 Subject: [PATCH 0851/1891] removed unused option on node plugin From 8e9935c502c020ad5190796cedeceac9fb5a62c8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Jul 2023 10:49:30 -0500 Subject: [PATCH 0852/1891] removed unused option on node plugin --- src/plugins/core/mod.rs | 2 +- src/plugins/core/node.rs | 43 ++++++++++++---------------------------- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 88029685d..c5f94e5af 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -16,7 +16,7 @@ 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("node".to_string())), Box::new(PythonPlugin::new("python".to_string())), ]) }); diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 155fba77e..a9f99c488 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -29,7 +29,6 @@ pub struct NodePlugin { pub name: PluginName, cache_path: PathBuf, remote_version_cache: CacheManager>, - legacy_file_support: bool, } impl NodePlugin { @@ -42,14 +41,6 @@ impl NodePlugin { .with_fresh_file(RTX_EXE.clone()), name, cache_path, - legacy_file_support: false, - } - } - - pub fn with_legacy_file_support(self) -> Self { - Self { - legacy_file_support: true, - ..self } } @@ -217,11 +208,7 @@ impl Plugin for NodePlugin { } fn legacy_filenames(&self, _settings: &Settings) -> Result> { - if self.legacy_file_support { - Ok(vec![".node-version".into(), ".nvmrc".into()]) - } else { - Ok(vec![]) - } + Ok(vec![".node-version".into(), ".nvmrc".into()]) } fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { @@ -231,22 +218,18 @@ impl Plugin for NodePlugin { } fn external_commands(&self) -> Result> { - if self.legacy_file_support { - // sort of a hack to get this not to display for nodejs - let topic = Command::new("node") - .about("Commands for the node plugin") - .subcommands(vec![Command::new("node-build") - .about("Use/manage rtx's internal node-build") - .arg( - clap::Arg::new("args") - .num_args(1..) - .allow_hyphen_values(true) - .trailing_var_arg(true), - )]); - Ok(vec![topic]) - } else { - Ok(vec![]) - } + // sort of a hack to get this not to display for nodejs + let topic = Command::new("node") + .about("Commands for the node plugin") + .subcommands(vec![Command::new("node-build") + .about("Use/manage rtx's internal node-build") + .arg( + clap::Arg::new("args") + .num_args(1..) + .allow_hyphen_values(true) + .trailing_var_arg(true), + )]); + Ok(vec![topic]) } fn execute_external_command( From b278c47e4cd2a5c2ea762f47b943e99bfd685f7d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Jul 2023 11:03:02 -0500 Subject: [PATCH 0853/1891] added core plugin common struct --- src/plugins/core/mod.rs | 26 ++++++++++++++++++++++++++ src/plugins/core/node.rs | 26 +++++++++----------------- src/plugins/core/python.rs | 26 +++++++++----------------- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index c5f94e5af..73825d905 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,8 +1,13 @@ use std::collections::BTreeMap; +use std::path::PathBuf; use std::sync::Arc; +use std::time::Duration; use once_cell::sync::Lazy; +use crate::cache::CacheManager; +use crate::dirs; +use crate::env::RTX_EXE; pub use python::PythonPlugin; use crate::plugins::core::node::NodePlugin; @@ -31,3 +36,24 @@ fn build_core_plugins(tools: Vec>) -> ToolMap { ) })) } + +#[derive(Debug)] +pub struct CorePlugin { + pub name: PluginName, + pub cache_path: PathBuf, + pub remote_version_cache: CacheManager>, +} + +impl CorePlugin { + pub fn new(name: PluginName) -> Self { + let cache_path = dirs::CACHE.join(&name); + let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours + Self { + remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) + .with_fresh_duration(fresh_duration) + .with_fresh_file(RTX_EXE.clone()), + name, + cache_path, + } + } +} diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index a9f99c488..85debe77c 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -3,49 +3,40 @@ use std::env::{join_paths, split_paths}; use std::path::{Path, PathBuf}; use std::process::exit; use std::sync::mpsc; -use std::time::Duration; use std::{fs, thread}; use clap::Command; use color_eyre::eyre::{Context, Result}; -use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::env::{ - RTX_EXE, RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, + RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, RTX_NODE_VERBOSE_INSTALL, }; use crate::file::create_dir_all; use crate::git::Git; use crate::lock_file::LockFile; +use crate::plugins::core::CorePlugin; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; -use crate::{cmd, dirs, env, file}; +use crate::{cmd, env, file}; #[derive(Debug)] pub struct NodePlugin { - pub name: PluginName, - cache_path: PathBuf, - remote_version_cache: CacheManager>, + core: CorePlugin, } impl NodePlugin { pub fn new(name: PluginName) -> Self { - let cache_path = dirs::CACHE.join(&name); - let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours Self { - remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(fresh_duration) - .with_fresh_file(RTX_EXE.clone()), - name, - cache_path, + core: CorePlugin::new(name), } } fn node_build_path(&self) -> PathBuf { - self.cache_path.join("node-build") + self.core.cache_path.join("node-build") } fn node_build_bin(&self) -> PathBuf { self.node_build_path().join("bin/node-build") @@ -172,11 +163,12 @@ impl NodePlugin { impl Plugin for NodePlugin { fn name(&self) -> &PluginName { - &self.name + &self.core.name } fn list_remote_versions(&self, _settings: &Settings) -> Result> { - self.remote_version_cache + self.core + .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 4e19ec20f..b79f1698d 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -2,43 +2,34 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::sync::mpsc; use std::thread; -use std::time::Duration; use color_eyre::eyre::{eyre, Context, Result}; -use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::{RTX_EXE, RTX_FETCH_REMOTE_VERSIONS_TIMEOUT}; +use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::create_dir_all; use crate::git::Git; +use crate::plugins::core::CorePlugin; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; -use crate::{cmd, dirs, env, file, http}; +use crate::{cmd, env, file, http}; #[derive(Debug)] pub struct PythonPlugin { - pub name: PluginName, - cache_path: PathBuf, - remote_version_cache: CacheManager>, + core: CorePlugin, } impl PythonPlugin { pub fn new(name: PluginName) -> Self { - let cache_path = dirs::CACHE.join(&name); - let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours Self { - remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(fresh_duration) - .with_fresh_file(RTX_EXE.clone()), - name, - cache_path, + core: CorePlugin::new(name), } } fn python_build_path(&self) -> PathBuf { - self.cache_path.join("pyenv") + self.core.cache_path.join("pyenv") } fn python_build_bin(&self) -> PathBuf { self.python_build_path() @@ -168,11 +159,12 @@ impl PythonPlugin { impl Plugin for PythonPlugin { fn name(&self) -> &PluginName { - &self.name + &self.core.name } fn list_remote_versions(&self, _settings: &Settings) -> Result> { - self.remote_version_cache + self.core + .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } From 244a9698ef9c9cde14785d1eb0e14fd5b0489061 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 9 Jul 2023 19:47:54 -0500 Subject: [PATCH 0854/1891] ruby core plugin (#666) --- .github/workflows/rtx.yml | 3 +- .rtx.toml | 1 + Cargo.lock | 1 + Cargo.toml | 2 + README.md | 24 +- docs/node.md | 32 +- docs/python.md | 2 +- docs/ruby.md | 71 ++++ e2e/ruby/Gemfile | 6 - e2e/ruby/test_ruby | 31 +- e2e/ruby/test_ruby_install | 15 + e2e/test_ls_remote | 2 +- e2e/test_nodejs | 2 +- scripts/update-shorthand-repo.sh | 13 +- src/cmd.rs | 21 +- src/default_shorthands.rs | 7 +- src/env.rs | 17 +- src/github.rs | 11 + src/lib.rs | 2 + src/main.rs | 2 + src/plugins/core/assets/rubygems_plugin.rb | 21 + src/plugins/core/mod.rs | 29 +- src/plugins/core/node.rs | 125 +++--- src/plugins/core/python.rs | 62 ++- src/plugins/core/ruby.rs | 437 +++++++++++++++++++++ src/plugins/external_plugin.rs | 28 +- src/plugins/script_manager.rs | 6 +- src/timeout.rs | 17 + 28 files changed, 811 insertions(+), 179 deletions(-) create mode 100644 docs/ruby.md delete mode 100644 e2e/ruby/Gemfile create mode 100755 e2e/ruby/test_ruby_install create mode 100644 src/github.rs create mode 100644 src/plugins/core/assets/rubygems_plugin.rb create mode 100644 src/plugins/core/ruby.rs create mode 100644 src/timeout.rs diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 6db380e29..134e6eb8b 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -132,6 +132,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-linux] timeout-minutes: 10 + if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v3 - name: Install zsh/fish/direnv @@ -148,7 +149,7 @@ jobs: env: RUST_BACKTRACE: "1" with: - timeout_minutes: 20 + timeout_minutes: 30 max_attempts: 3 command: ./e2e/run_all_tests rpm: diff --git a/.rtx.toml b/.rtx.toml index 38ebcaeb4..09032c379 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -9,6 +9,7 @@ THIS_PROJECT = "{{config_root}}-{{env.PWD}}" tiny = { version = "1", foo = "bar" } golang = { version = "latest", foo = "bar" } python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } +ruby = "3.1" [plugins] nnnn = 'https://github.com/rtx-plugins/rtx-nodejs#main' diff --git a/Cargo.lock b/Cargo.lock index e5e251ff7..84e9acd10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1619,6 +1619,7 @@ dependencies = [ "serde_derive", "serde_json", "shell-escape", + "shell-words", "simplelog", "tera", "terminal_size", diff --git a/Cargo.toml b/Cargo.toml index b616451ba..bd9b1ee1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ regex = "1.8.4" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", "rustls-tls", + "json", ] } rmp-serde = "1.1.1" self_update = { version = "0.37.0", default-features = false, optional = true, features = [ @@ -74,6 +75,7 @@ serde = "1.0.164" serde_derive = "1.0.152" serde_json = "1.0.99" shell-escape = "0.1.4" +shell-words = "1.1.0" simplelog = { version = "0.12.0" } tera = { version = "1.12.1", default-features = false } terminal_size = "0.2.1" diff --git a/README.md b/README.md index 37e463aca..aa4208cc0 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ v20.0.0 - [Windows support?](#windows-support) - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) + - [Does "node@20" mean the newest available version of node?](#does-node20-mean-the-newest-available-version-of-node) - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) - [rtx isn't working when calling from tmux or another shell initialization script](#rtx-isnt-working-when-calling-from-tmux-or-another-shell-initialization-script) @@ -1109,7 +1110,7 @@ You can see the core plugins with `rtx plugin ls --core`. * [experimental] [Python](./docs/python.md) * [NodeJS](./docs/node.md) -* ~Ruby~ - coming soon +* [Ruby (experimental)](./docs/ruby.md) * ~Java~ - coming soon * ~Go~ - coming soon @@ -1229,6 +1230,27 @@ This is regularly updated every time that rtx has a release. This repository is the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that rtx makes on top of asdf. +### Does "node@20" mean the newest available version of node? + +It depends on the command. Normally, for most commands and inside of config files, "node@20" will +point to the latest _installed_ version of node-20.x. You can find this version by running +`rtx latest --installed node@20` or by seeing what the `~/.local/share/rtx/installs/node/20` symlink +points to: + +```sh-session +$ ls -l ~/.local/share/rtx/installs/node/20 +[...] /home/jdxcode/.local/share/rtx/installs/node/20 -> node-v20.0.0-linux-x64 +``` + +There are some exceptions to this, such as the following: + +* `rtx install node@20` +* `rtx latest node@20` +* `rtx upgrade node@20` + +These will use the latest _available_ version of node-20.x. This generally makes sense because you +wouldn't want to install a version that is already installed. + ### How do I migrate from asdf? First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your diff --git a/docs/node.md b/docs/node.md index 6a3ac87f3..7b22f1fcf 100644 --- a/docs/node.md +++ b/docs/node.md @@ -3,10 +3,10 @@ The following are instructions for using the node rtx core plugin. This is used when there isn't a git plugin installed named "node". -If you want to use [asdf-node](https://github.com/asdf-vm/asdf-nodejs) or -[rtx-node](https://github.com/rtx-plugins/rtx-nodejs) then use `rtx plugins install node URL`. +If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) or +[rtx-node](https://github.com/rtx-plugins/rtx-nodejs) then run `rtx plugins install node GIT_URL`. -The code for this is inside of the rtx repository at [`./src/plugins/core/node.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/node.rs). +The code for this is inside the rtx repository at [`./src/plugins/core/node.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/node.rs). ## Usage @@ -14,30 +14,20 @@ The following installs the latest version of node-20.x and makes it the global default: ```sh-session -$ rtx install node@20 $ rtx use -g node@20 ``` Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. - -```sh-session -$ rtx use -g node@18 node@20 -$ node -V -18.0.0 -$ node.11 -V -20.0.0 -``` - ## Configuration `node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-node` has a few extra configuration variables: -- `RTX_NODE_VERBOSE_INSTALL`: Enables verbose output for downloading and building. -- `RTX_NODE_FORCE_COMPILE`: Forces compilation from source instead of preferring pre-compiled binaries -- `RTX_NODE_CONCURRENCY`: How many jobs should be used in compilation. Defaults to half the computer cores -- `RTX_NODE_DEFAULT_PACKAGES_FILE`: location of default packages file, defaults to `$HOME/.default-npm-packages` -- `NODEJS_ORG_MIRROR`: (Legacy) overrides the default mirror used for downloading the +- `RTX_NODE_VERBOSE_INSTALL` [bool]: Enables verbose output for downloading and building. +- `RTX_NODE_FORCE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries +- `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores +- `RTX_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` +- `NODEJS_ORG_MIRROR` [string]: (Legacy) overrides the default mirror used for downloading the distibutions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var ## Default node packages @@ -90,3 +80,9 @@ want to update `node-build` manually for some reason you can clear the cache and rtx cache clean rtx ls-remote node ``` + +## "nodejs" -> "node" Alias + +You cannot install/use a plugin named "nodejs". If you attempt this, rtx will just renamed it to +"node". See the [FAQ](https://github.com/jdxcode/rtx#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) +for an explanation. diff --git a/docs/python.md b/docs/python.md index 46d852072..6a1c7984b 100644 --- a/docs/python.md +++ b/docs/python.md @@ -3,7 +3,7 @@ The following are instructions for using the python rtx core plugin. This is used when the "experimental" setting is "true" and there isn't a git plugin installed named "python" -If you want to use [asdf-python](https://github.com/asdf-community/asdf-python) or [rtx-python](https://github.com/rtx-plugins/rtx-python) then use `rtx plugins install python URL`. +If you want to use [asdf-python](https://github.com/asdf-community/asdf-python) or [rtx-python](https://github.com/rtx-plugins/rtx-python) then use `rtx plugins install python GIT_URL`. The code for this is inside of the rtx repository at [`./src/plugins/core/python.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/python.rs). diff --git a/docs/ruby.md b/docs/ruby.md new file mode 100644 index 000000000..67b8601b1 --- /dev/null +++ b/docs/ruby.md @@ -0,0 +1,71 @@ +# ruby in rtx + +The following are instructions for using the ruby rtx core plugin. This is used when there isn't a +git plugin installed named "ruby". + +If you want to use [asdf-ruby](https://github.com/asdf-vm/asdf-ruby) +or [rtx-ruby](https://github.com/rtx-plugins/rtx-ruby) +then use `rtx plugins install ruby GIT_URL`. + +The code for this is inside the rtx repository at +[`./src/plugins/core/ruby.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/ruby.rs). + +## Usage + +The following installs the latest version of ruby-3.2.x (if some version of 3.2.x is not already +installed) and makes it the global default: + +```sh-session +$ rtx use -g node@20 +``` + +Behind the scenes, rtx uses [`ruby-build`](https://github.com/rbenv/ruby-build) to compile ruby +from source. You can check its +[README](https://github.com/rbenv/ruby-build/blob/master/README.md) +for additional settings and some troubleshooting. + +## Configuration + +`ruby-build` already has a +[handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), +in additional to that rtx has a few extra configuration variables: + +- `RTX_RUBY_INSTALL` [bool]: Build with ruby-install instead of ruby-build +- `RTX_RUBY_APPLY_PATCHES` [string]: A list of patches (files or URLs) to apply to the ruby source code +- `RTX_RUBY_VERBOSE_INSTALL` [bool]: Show verbose output during installation (passes --verbose to ruby-build) +- `RTX_RUBY_BUILD_OPTS` [string]: Command line options to pass to ruby-build when installing +- `RTX_RUBY_INSTALL_OPTS` [string]: Command line options to pass to ruby-install when installing (if RTX_RUBY_INSTALL=1) +- `RTX_RUBY_DEFAULT_PACKAGES_FILE` [string]: location of default gems file, defaults to `$HOME/.default-gems` + +## Default gems + +rtx can automatically install a default set of gems right after installing a new ruby version. +To enable this feature, provide a `$HOME/.default-gems` file that lists one gem per line, for +example: + +``` +pry +rubocop +``` + +## `.ruby-version` and `Gemfile` support + +rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. +However it can also read ruby-specific version files `.ruby-version` or `Gemfile` +(if it specifies a ruby version). + +Create a `.ruby-version` file for the current version of ruby: + +```sh-session +$ ruby -v > .ruby-version +``` + +### Manually updating ruby-build + +ruby-build should update daily, however if you find versions do not yet exist you can force an +update: + +```bash +rtx cache clean +rtx ls-remote node +``` diff --git a/e2e/ruby/Gemfile b/e2e/ruby/Gemfile deleted file mode 100644 index d4f092c28..000000000 --- a/e2e/ruby/Gemfile +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -ruby "3.0.5" - -source "https://rubygems.org" -git_source(:github) { |repo| "https://github.com/#{repo}.git" } diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby index 70c12462f..368038d82 100755 --- a/e2e/ruby/test_ruby +++ b/e2e/ruby/test_ruby @@ -1,17 +1,22 @@ #!/usr/bin/env bash - set -e -assert() { - actual="$($1)" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" != "$expected" ]]; then - echo "assertion failed, expected '$expected', got '$actual'" - exit 1 - fi -} +source "$(dirname "$0")/../assert.sh" + +export RTX_EXPERIMENTAL=1 +export RTX_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" +export RTX_RUBY_VERBOSE_INSTALL=1 + +cat >Gemfile < .ruby-version + +rtx i ruby +assert_contains "rtx x -- ruby --version" "ruby 3.1.4" + +rm .ruby-version diff --git a/e2e/test_ls_remote b/e2e/test_ls_remote index 8c05d2eff..ebafa51f5 100755 --- a/e2e/test_ls_remote +++ b/e2e/test_ls_remote @@ -2,7 +2,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" -rtx p list-remote | grep node +rtx p list-remote | grep elixir rtx p uninstall tiny assert_fail "RTX_CONFIRM=no rtx ls-remote tiny" assert_contains "RTX_CONFIRM=yes rtx ls-remote tiny" "1.1.0" diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 5e1c83b6e..f78838b6a 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -12,7 +12,7 @@ assert "rtx x -- node --version" "v20.0.0" assert_contains "rtx node node-build --version" "node-build " # test rtx-nodejs -rtx plugin i nodejs +rtx plugin i nodejs https://github.com/rtx-plugins/rtx-nodejs rtx use nodejs@20.1.0 assert "rtx x -- node --version" "v20.1.0" assert_contains "rtx node nodebuild --version" "node-build " diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index 66c5e64d3..c79adf76a 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -9,16 +9,19 @@ custom_plugins=( '("go", "https://github.com/rtx-plugins/rtx-golang.git"),' '("golang", "https://github.com/rtx-plugins/rtx-golang.git"),' '("java", "https://github.com/rtx-plugins/rtx-java.git"),' - '("node", "https://github.com/rtx-plugins/rtx-nodejs.git"),' - '("nodejs", "https://github.com/rtx-plugins/rtx-nodejs.git"),' '("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"),' '("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"),' - '("python", "https://github.com/rtx-plugins/rtx-python.git"),' '("ruby", "https://github.com/rtx-plugins/rtx-ruby.git"),' '("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"),' ) -num_plugins=$(find asdf-plugins/plugins/* | wc -l | tr -d ' ') +asdf_plugins=$(find asdf-plugins/plugins -maxdepth 1 | + sort | + grep -v '/plugins$' | + grep -v '/nodejs$' | + grep -v '/python$') + +num_plugins=$(echo "$asdf_plugins" | wc -l | tr -d ' ') num_plugins=$((num_plugins + ${#custom_plugins[@]})) cat >src/default_shorthands.rs <> = const DEFAULT_SHORTHAND_LIST: [(&str, &str); $num_plugins] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins EOF -for file in asdf-plugins/plugins/*; do +for file in $asdf_plugins; do plugin=$(basename "$file") repository=$(cat "$file") repository="${repository/#repository = /}" diff --git a/src/cmd.rs b/src/cmd.rs index 200de1e99..d4e6bb34d 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -103,12 +103,12 @@ impl<'a> CmdLineRunner<'a> { } } - pub fn env_clear(&mut self) -> &mut Self { + pub fn env_clear(mut self) -> Self { self.cmd.env_clear(); self } - pub fn env(&mut self, key: K, val: V) -> &mut Self + pub fn env(mut self, key: K, val: V) -> Self where K: AsRef, V: AsRef, @@ -116,7 +116,7 @@ impl<'a> CmdLineRunner<'a> { self.cmd.env(key, val); self } - pub fn envs(&mut self, vars: I) -> &mut Self + pub fn envs(mut self, vars: I) -> Self where I: IntoIterator, K: AsRef, @@ -126,17 +126,26 @@ impl<'a> CmdLineRunner<'a> { self } - pub fn arg>(&mut self, arg: S) -> &mut Self { + pub fn arg>(mut self, arg: S) -> Self { self.cmd.arg(arg.as_ref()); self } - pub fn with_pr(&mut self, pr: &'a ProgressReport) -> &mut Self { + pub fn args(mut self, args: I) -> Self + where + I: IntoIterator, + S: AsRef, + { + self.cmd.args(args); + self + } + + pub fn with_pr(mut self, pr: &'a ProgressReport) -> Self { self.pr = Some(pr); self } - pub fn stdin_string(&mut self, input: impl Into) -> &mut Self { + pub fn stdin_string(mut self, input: impl Into) -> Self { self.cmd.stdin(Stdio::piped()); self.stdin = Some(input.into()); self diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 2faddc7a9..b52bb8619 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 688] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -451,7 +451,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 688] = [ ("nfpm", "https://github.com/ORCID/asdf-nfpm"), ("nim", "https://github.com/asdf-community/asdf-nim.git"), ("ninja", "https://github.com/asdf-community/asdf-ninja.git"), - ("nodejs", "https://github.com/asdf-vm/asdf-nodejs.git"), ("nomad", "https://github.com/asdf-community/asdf-hashicorp.git"), ("nova", "https://github.com/elementalvoid/asdf-nova.git"), ("nsc", "https://github.com/dex4er/asdf-nsc.git"), @@ -507,7 +506,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 688] = [ ("purerl", "https://github.com/GoNZooo/asdf-purerl.git"), ("purescript", "https://github.com/nsaunders/asdf-purescript.git"), ("purty", "https://github.com/nsaunders/asdf-purty.git"), - ("python", "https://github.com/danhper/asdf-python.git"), ("qdns", "https://github.com/moritz-makandra/asdf-plugin-qdns.git"), ("quarkus", "https://github.com/asdf-community/asdf-quarkus.git"), ("rabbitmq", "https://github.com/w-sanches/asdf-rabbitmq.git"), @@ -707,11 +705,8 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 688] = [ ("go", "https://github.com/rtx-plugins/rtx-golang.git"), ("golang", "https://github.com/rtx-plugins/rtx-golang.git"), ("java", "https://github.com/rtx-plugins/rtx-java.git"), - ("node", "https://github.com/rtx-plugins/rtx-nodejs.git"), - ("nodejs", "https://github.com/rtx-plugins/rtx-nodejs.git"), ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), - ("python", "https://github.com/rtx-plugins/rtx-python.git"), ("ruby", "https://github.com/rtx-plugins/rtx-ruby.git"), ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ]; diff --git a/src/env.rs b/src/env.rs index ffb5214fd..b7b13078f 100644 --- a/src/env.rs +++ b/src/env.rs @@ -127,8 +127,8 @@ pub static RTX_NODE_CONCURRENCY: Lazy = Lazy::new(|| { .unwrap_or(num_cpus::get() / 2) .max(1) }); -pub static RTX_NODE_VERBOSE_INSTALL: Lazy = - Lazy::new(|| var_is_true("RTX_NODE_VERBOSE_INSTALL")); +pub static RTX_NODE_VERBOSE_INSTALL: Lazy> = + Lazy::new(|| var_option_bool("RTX_NODE_VERBOSE_INSTALL")); pub static RTX_NODE_FORCE_COMPILE: Lazy = Lazy::new(|| var_is_true("RTX_NODE_FORCE_COMPILE")); pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { @@ -149,6 +149,19 @@ pub static NVM_DIR: Lazy = pub static NODENV_ROOT: Lazy = Lazy::new(|| var_path("NODENV_ROOT").unwrap_or_else(|| HOME.join(".nodenv"))); +pub static RTX_RUBY_INSTALL: Lazy = Lazy::new(|| var_is_true("RTX_RUBY_INSTALL")); +pub static RTX_RUBY_APPLY_PATCHES: Lazy> = + Lazy::new(|| var("RTX_RUBY_APPLY_PATCHES").ok()); +pub static RTX_RUBY_VERBOSE_INSTALL: Lazy> = + Lazy::new(|| var_option_bool("RTX_RUBY_VERBOSE_INSTALL")); +pub static RTX_RUBY_INSTALL_OPTS: Lazy, shell_words::ParseError>> = + Lazy::new(|| shell_words::split(&var("RTX_RUBY_INSTALL_OPTS").unwrap_or_default())); +pub static RTX_RUBY_BUILD_OPTS: Lazy, shell_words::ParseError>> = + Lazy::new(|| shell_words::split(&var("RTX_RUBY_BUILD_OPTS").unwrap_or_default())); +pub static RTX_RUBY_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("RTX_RUBY_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-gems")) +}); + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { Yes, diff --git a/src/github.rs b/src/github.rs new file mode 100644 index 000000000..cc45ca144 --- /dev/null +++ b/src/github.rs @@ -0,0 +1,11 @@ +use serde_derive::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct GithubRelease { + pub tag_name: String, + pub name: String, + pub body: String, + pub prerelease: bool, + pub created_at: String, + pub published_at: String, +} diff --git a/src/lib.rs b/src/lib.rs index acbcae9f3..a9a05d813 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ mod errors; mod fake_asdf; mod file; mod git; +pub mod github; mod hash; mod hook_env; mod http; @@ -37,6 +38,7 @@ mod shorthands; mod tera; #[cfg(test)] mod test; +pub mod timeout; mod toml; mod tool; mod toolset; diff --git a/src/main.rs b/src/main.rs index 344951321..d9b5d6388 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ mod errors; mod fake_asdf; mod file; mod git; +pub mod github; mod hash; mod hook_env; mod http; @@ -48,6 +49,7 @@ mod shorthands; pub mod tera; #[cfg(test)] mod test; +pub mod timeout; mod toml; mod tool; mod toolset; diff --git a/src/plugins/core/assets/rubygems_plugin.rb b/src/plugins/core/assets/rubygems_plugin.rb new file mode 100644 index 000000000..634d12360 --- /dev/null +++ b/src/plugins/core/assets/rubygems_plugin.rb @@ -0,0 +1,21 @@ +module ReshimInstaller + def install(options) + super + # We don't know which gems were installed, so always reshim. + `rtx reshim` + end +end + +if defined?(Bundler::Installer) + Bundler::Installer.prepend ReshimInstaller +else + Gem.post_install do |installer| + # Reshim any (potentially) new executables. + `rtx reshim` if installer.spec.executables.any? + end + Gem.post_uninstall do |installer| + # Unfortunately, reshimming just the removed executables or + # ruby version doesn't work as of 2020/04/23. + `rtx reshim` if installer.spec.executables.any? + end +end diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 73825d905..a4bd32410 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,21 +1,27 @@ use std::collections::BTreeMap; +use std::ffi::OsString; use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; +use color_eyre::eyre::Result; use once_cell::sync::Lazy; -use crate::cache::CacheManager; -use crate::dirs; -use crate::env::RTX_EXE; pub use python::PythonPlugin; +use crate::cache::CacheManager; +use crate::env::RTX_EXE; use crate::plugins::core::node::NodePlugin; +use crate::plugins::core::ruby::RubyPlugin; use crate::plugins::{Plugin, PluginName}; +use crate::timeout::run_with_timeout; use crate::tool::Tool; +use crate::toolset::ToolVersion; +use crate::{dirs, env}; mod node; mod python; +mod ruby; type ToolMap = BTreeMap>; @@ -26,7 +32,8 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { ]) }); -pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| build_core_plugins(vec![])); +pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = + Lazy::new(|| build_core_plugins(vec![Box::new(RubyPlugin::new("ruby".to_string()))])); fn build_core_plugins(tools: Vec>) -> ToolMap { ToolMap::from_iter(tools.into_iter().map(|plugin| { @@ -56,4 +63,18 @@ impl CorePlugin { cache_path, } } + + pub fn path_env_with_tv_path(tv: &ToolVersion) -> Result { + let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, tv.install_path().join("bin")); + Ok(env::join_paths(path)?) + } + + pub fn run_fetch_task_with_timeout(f: F) -> Result + where + F: FnOnce() -> Result + Send + 'static, + T: Send + 'static, + { + run_with_timeout(f, *env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) + } } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 85debe77c..2cc67700f 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,19 +1,15 @@ use std::collections::BTreeMap; -use std::env::{join_paths, split_paths}; +use std::fs; use std::path::{Path, PathBuf}; use std::process::exit; -use std::sync::mpsc; -use std::{fs, thread}; use clap::Command; -use color_eyre::eyre::{Context, Result}; +use color_eyre::eyre::Result; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::{ - RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, - RTX_NODE_VERBOSE_INSTALL, -}; +use crate::duration::DAILY; +use crate::env::{RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE}; use crate::file::create_dir_all; use crate::git::Git; use crate::lock_file::LockFile; @@ -71,39 +67,34 @@ impl NodePlugin { Ok(()) } fn update_node_build(&self) -> Result<()> { - // TODO: do not update if recently updated + if self.node_build_recently_updated()? { + return Ok(()); + } debug!( "Updating node-build in {}", self.node_build_path().display() ); let git = Git::new(self.node_build_path()); - let (tx, rx) = mpsc::channel(); - thread::spawn(move || { - let result = git.update(None); - tx.send(result).unwrap(); - }); - rx.recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) - .context("timed out updating node-build")??; - Ok(()) + let node_build_path = self.node_build_path(); + CorePlugin::run_fetch_task_with_timeout(move || { + git.update(None)?; + file::touch_dir(&node_build_path)?; + Ok(()) + }) } fn fetch_remote_versions(&self) -> Result> { self.install_or_update_node_build()?; let node_build_bin = self.node_build_bin(); - let (tx, rx) = mpsc::channel(); - thread::spawn(move || { - let output = cmd!(node_build_bin, "--definitions").read(); - tx.send(output).unwrap(); - }); - let output = rx - .recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) - .context("timed out fetching node versions")??; - let versions = output - .split('\n') - .filter(|s| regex!(r"^[0-9].+$").is_match(s)) - .map(|s| s.to_string()) - .collect(); - Ok(versions) + CorePlugin::run_fetch_task_with_timeout(move || { + let output = cmd!(node_build_bin, "--definitions").read()?; + let versions = output + .split('\n') + .filter(|s| regex!(r"^[0-9].+$").is_match(s)) + .map(|s| s.to_string()) + .collect(); + Ok(versions) + }) } fn node_path(&self, tv: &ToolVersion) -> PathBuf { @@ -128,12 +119,13 @@ impl NodePlugin { } pr.set_message(format!("installing default package: {}", package)); let npm = self.npm_path(tv); - let mut cmd = CmdLineRunner::new(settings, npm); - cmd.with_pr(pr).arg("install").arg("--global").arg(package); - let mut path = split_paths(&env::var_os("PATH").unwrap()).collect::>(); - path.insert(0, tv.install_path().join("bin")); - cmd.env("PATH", join_paths(path)?); - cmd.execute()?; + CmdLineRunner::new(settings, npm) + .with_pr(pr) + .arg("install") + .arg("--global") + .arg(package) + .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .execute()?; } Ok(()) } @@ -146,18 +138,28 @@ impl NodePlugin { } fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - let mut cmd = CmdLineRunner::new(&config.settings, self.node_path(tv)); - cmd.with_pr(pr).arg("-v"); - cmd.execute() + CmdLineRunner::new(&config.settings, self.node_path(tv)) + .with_pr(pr) + .arg("-v") + .execute() } fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - let mut cmd = CmdLineRunner::new(&config.settings, self.npm_path(tv)); - let mut path = split_paths(&env::var_os("PATH").unwrap()).collect::>(); - path.insert(0, tv.install_path().join("bin")); - cmd.env("PATH", join_paths(path)?); - cmd.with_pr(pr).arg("-v"); - cmd.execute() + CmdLineRunner::new(&config.settings, self.npm_path(tv)) + .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .with_pr(pr) + .arg("-v") + .execute() + } + + fn node_build_recently_updated(&self) -> Result { + let updated_at = file::modified_duration(&self.node_build_path())?; + Ok(updated_at < DAILY) + } + + fn verbose_install(&self, settings: &Settings) -> bool { + let verbose_env = *env::RTX_NODE_VERBOSE_INSTALL; + verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) } } @@ -248,25 +250,26 @@ impl Plugin for NodePlugin { ) -> Result<()> { self.install_node_build()?; pr.set_message("running node-build"); - let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()); - cmd.with_pr(pr).arg(tv.version.as_str()); + let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()) + .with_pr(pr) + .arg(tv.version.as_str()); if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_FORCE_COMPILE { let make_opts = String::from(" -j") + &RTX_NODE_CONCURRENCY.to_string(); - cmd.env( - "MAKE_OPTS", - env::var("MAKE_OPTS").unwrap_or_default() + &make_opts, - ); - cmd.env( - "NODE_MAKE_OPTS", - env::var("NODE_MAKE_OPTS").unwrap_or_default() + &make_opts, - ); - cmd.arg("--compile"); + cmd = cmd + .env( + "MAKE_OPTS", + env::var("MAKE_OPTS").unwrap_or_default() + &make_opts, + ) + .env( + "NODE_MAKE_OPTS", + env::var("NODE_MAKE_OPTS").unwrap_or_default() + &make_opts, + ) + .arg("--compile"); } - if config.settings.verbose || *RTX_NODE_VERBOSE_INSTALL { - cmd.arg("--verbose"); + if self.verbose_install(&config.settings) { + cmd = cmd.arg("--verbose"); } - cmd.arg(tv.install_path()); - cmd.execute()?; + cmd.arg(tv.install_path()).execute()?; self.test_node(config, tv, pr)?; self.install_npm_shim(tv)?; self.test_npm(config, tv, pr)?; diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index b79f1698d..f6551759d 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -1,13 +1,11 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use std::sync::mpsc; -use std::thread; -use color_eyre::eyre::{eyre, Context, Result}; +use color_eyre::eyre::{eyre, Result}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; + use crate::file::create_dir_all; use crate::git::Git; use crate::plugins::core::CorePlugin; @@ -62,28 +60,17 @@ impl PythonPlugin { self.python_build_path().display() ); let git = Git::new(self.python_build_path()); - let (tx, rx) = mpsc::channel(); - thread::spawn(move || { - let result = git.update(None); - tx.send(result).unwrap(); - }); - rx.recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) - .context("timed out updating python-build")??; + CorePlugin::run_fetch_task_with_timeout(move || git.update(None))?; Ok(()) } fn fetch_remote_versions(&self) -> Result> { self.install_or_update_python_build()?; let python_build_bin = self.python_build_bin(); - let (tx, rx) = mpsc::channel(); - thread::spawn(move || { - let output = cmd!(python_build_bin, "--definitions").read(); - tx.send(output).unwrap(); - }); - let output = rx - .recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) - .context("timed out fetching python versions")??; - Ok(output.split('\n').map(|s| s.to_string()).collect()) + CorePlugin::run_fetch_task_with_timeout(move || { + let output = cmd!(python_build_bin, "--definitions").read()?; + Ok(output.split('\n').map(|s| s.to_string()).collect()) + }) } fn python_path(&self, tv: &ToolVersion) -> PathBuf { @@ -105,13 +92,13 @@ impl PythonPlugin { } pr.set_message("installing default packages"); let pip = self.pip_path(tv); - let mut cmd = CmdLineRunner::new(settings, pip); - cmd.with_pr(pr) + CmdLineRunner::new(settings, pip) + .with_pr(pr) .arg("install") .arg("--upgrade") .arg("-r") - .arg(&*env::RTX_PYTHON_DEFAULT_PACKAGES_FILE); - cmd.execute() + .arg(&*env::RTX_PYTHON_DEFAULT_PACKAGES_FILE) + .execute() } fn get_virtualenv( @@ -130,10 +117,13 @@ impl PythonPlugin { } if !virtualenv.exists() || !self.check_venv_python(&virtualenv, tv)? { debug!("setting up virtualenv at: {}", virtualenv.display()); - let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)); - cmd.arg("-m").arg("venv").arg("--clear").arg(&virtualenv); + let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)) + .arg("-m") + .arg("venv") + .arg("--clear") + .arg(&virtualenv); if let Some(pr) = pr { - cmd.with_pr(pr); + cmd = cmd.with_pr(pr); } cmd.execute()?; } @@ -151,9 +141,9 @@ impl PythonPlugin { } fn test_python(&self, config: &&Config, tv: &ToolVersion) -> Result<()> { - let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)); - cmd.arg("--version"); - cmd.execute() + CmdLineRunner::new(&config.settings, self.python_path(tv)) + .arg("--version") + .execute() } } @@ -184,27 +174,25 @@ impl Plugin for PythonPlugin { return Err(eyre!("Ref versions not supported for python")); } pr.set_message("running python-build"); - let mut cmd = CmdLineRunner::new(&config.settings, self.python_build_bin()); - cmd.with_pr(pr) + let mut cmd = CmdLineRunner::new(&config.settings, self.python_build_bin()) + .with_pr(pr) .arg(tv.version.as_str()) .arg(tv.install_path()); if config.settings.verbose { - cmd.arg("--verbose"); + cmd = cmd.arg("--verbose"); } if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { pr.set_message(format!("with patch file from: {patch_url}")); - cmd.arg("--patch"); let http = http::Client::new()?; let patch = http.get(patch_url).send()?.text()?; - cmd.stdin_string(patch); + cmd = cmd.arg("--patch").stdin_string(patch) } if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { let patch_file = patches_dir.join(format!("{}.patch", tv.version)); if patch_file.exists() { pr.set_message(format!("with patch file: {}", patch_file.display())); - cmd.arg("--patch"); let contents = std::fs::read_to_string(&patch_file)?; - cmd.stdin_string(contents); + cmd = cmd.arg("--patch").stdin_string(contents); } else { pr.warn(format!("patch file not found: {}", patch_file.display())); } diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs new file mode 100644 index 000000000..7402806bf --- /dev/null +++ b/src/plugins/core/ruby.rs @@ -0,0 +1,437 @@ +use std::collections::HashMap; +use std::env::temp_dir; +use std::fs; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::Result; + +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::duration::DAILY; +use crate::env::GITHUB_API_TOKEN; +use crate::git::Git; +use crate::github::GithubRelease; +use crate::lock_file::LockFile; +use crate::plugins::core::CorePlugin; +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; +use crate::{cmd, env, file, http}; + +#[derive(Debug)] +pub struct RubyPlugin { + core: CorePlugin, +} + +impl RubyPlugin { + pub fn new(name: PluginName) -> Self { + Self { + core: CorePlugin::new(name), + } + } + + fn ruby_build_path(&self) -> PathBuf { + self.core.cache_path.join("ruby-build") + } + fn ruby_install_path(&self) -> PathBuf { + self.core.cache_path.join("ruby-install") + } + + fn ruby_build_bin(&self) -> PathBuf { + self.ruby_build_path().join("bin/ruby-build") + } + + fn ruby_install_bin(&self) -> PathBuf { + self.ruby_install_path().join("bin/ruby-install") + } + + fn lock_build_tool(&self) -> Result { + let build_tool_path = if *env::RTX_RUBY_INSTALL { + self.ruby_build_bin() + } else { + self.ruby_install_bin() + }; + LockFile::new(&build_tool_path) + .with_callback(|l| { + trace!("install_or_update_ruby_build_tool {}", l.display()); + }) + .lock() + } + + fn update_build_tool(&self) -> Result<()> { + if *env::RTX_RUBY_INSTALL { + self.update_ruby_install()?; + } + self.update_ruby_build() + } + + fn install_ruby_build(&self) -> Result<()> { + debug!( + "Installing ruby-build to {}", + self.ruby_build_path().display() + ); + let tmp = temp_dir().join("rtx-ruby-build"); + file::remove_all(&tmp)?; + file::create_dir_all(tmp.parent().unwrap())?; + let git = Git::new(tmp.clone()); + git.clone("https://github.com/rbenv/ruby-build.git")?; + + cmd!("sh", "install.sh") + .env("PREFIX", self.ruby_build_path()) + .dir(&tmp) + .run()?; + file::remove_all(&tmp)?; + Ok(()) + } + fn update_ruby_build(&self) -> Result<()> { + let _lock = self.lock_build_tool(); + if self.ruby_build_path().exists() + && self.ruby_build_version()? == self.latest_ruby_build_version()? + { + return Ok(()); + } + debug!( + "Updating ruby-build in {}", + self.ruby_build_path().display() + ); + file::remove_all(self.ruby_build_path())?; + self.install_ruby_build()?; + Ok(()) + } + + fn install_ruby_install(&self) -> Result<()> { + debug!( + "Installing ruby-install to {}", + self.ruby_install_path().display() + ); + let tmp = temp_dir().join("rtx-ruby-install"); + file::remove_all(&tmp)?; + file::create_dir_all(tmp.parent().unwrap())?; + let git = Git::new(tmp.clone()); + git.clone("https://github.com/postmodern/ruby-install")?; + + cmd!("make", "install") + .env("PREFIX", self.ruby_install_path()) + .dir(&tmp) + .run()?; + file::remove_all(&tmp)?; + Ok(()) + } + fn update_ruby_install(&self) -> Result<()> { + let _lock = self.lock_build_tool(); + let ruby_install_path = self.ruby_install_path(); + if !ruby_install_path.exists() { + self.install_ruby_install()?; + } + if self.ruby_install_recently_updated()? { + return Ok(()); + } + debug!("Updating ruby-install in {}", ruby_install_path.display()); + + CorePlugin::run_fetch_task_with_timeout(move || { + cmd!(&ruby_install_path, "--update").run()?; + file::touch_dir(&ruby_install_path)?; + Ok(()) + }) + } + + fn ruby_install_recently_updated(&self) -> Result { + let updated_at = file::modified_duration(&self.ruby_install_path())?; + Ok(updated_at < DAILY) + } + + fn fetch_remote_versions(&self) -> Result> { + self.update_build_tool()?; + let ruby_build_bin = self.ruby_build_bin(); + let versions = CorePlugin::run_fetch_task_with_timeout(move || { + let output = cmd!(ruby_build_bin, "--definitions").read()?; + let versions = output + .split('\n') + .filter(|s| regex!(r"^[0-9].+$").is_match(s)) + .map(|s| s.to_string()) + .collect(); + Ok(versions) + })?; + Ok(versions) + } + + fn ruby_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/ruby") + } + + fn gem_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/gem") + } + + fn install_default_gems( + &self, + settings: &Settings, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + let body = fs::read_to_string(&*env::RTX_RUBY_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + for package in body.lines() { + let package = package.split('#').next().unwrap_or_default().trim(); + if package.is_empty() { + continue; + } + pr.set_message(format!("installing default gem: {}", package)); + let gem = self.gem_path(tv); + let mut cmd = CmdLineRunner::new(settings, gem).with_pr(pr).arg("install"); + match package.split_once('-') { + Some((name, "--pre")) => cmd = cmd.arg(name).arg("--pre"), + Some((name, version)) => cmd = cmd.arg(name).arg("--version").arg(version), + None => cmd = cmd.arg(package), + }; + cmd.env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .execute()?; + } + Ok(()) + } + + fn test_ruby(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + CmdLineRunner::new(&config.settings, self.ruby_path(tv)) + .with_pr(pr) + .arg("-v") + .execute() + } + + fn test_gem(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + CmdLineRunner::new(&config.settings, self.gem_path(tv)) + .with_pr(pr) + .arg("-v") + .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .execute() + } + + fn ruby_build_version(&self) -> Result { + let output = cmd!(self.ruby_build_bin(), "--version").read()?; + let re = regex!(r"^ruby-build ([0-9.]+)"); + let caps = re.captures(&output).expect("ruby-build version regex"); + Ok(caps.get(1).unwrap().as_str().to_string()) + } + + fn latest_ruby_build_version(&self) -> Result { + let http = http::Client::new()?; + let mut req = http.get("https://api.github.com/repos/rbenv/ruby-build/releases/latest"); + if let Some(token) = &*GITHUB_API_TOKEN { + req = req.header("authorization", format!("token {}", token)); + } + let resp: GithubRelease = req.send()?.json()?; + Ok(resp.tag_name.trim_start_matches('v').to_string()) + } + + fn install_rubygems_hook(&self, tv: &ToolVersion) -> Result<()> { + let d = self.rubygems_plugins_path(tv); + let f = d.join("rubygems_plugin.rb"); + file::create_dir_all(d)?; + fs::write(f, include_str!("assets/rubygems_plugin.rb"))?; + Ok(()) + } + + fn rubygems_plugins_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("lib/rubygems_plugin") + } + + fn install_cmd<'a>( + &'a self, + settings: &'a Settings, + tv: &ToolVersion, + pr: &'a ProgressReport, + ) -> Result { + let cmd = if *env::RTX_RUBY_INSTALL { + CmdLineRunner::new(settings, self.ruby_install_bin()) + .args(self.install_args_ruby_install(tv)?) + } else { + CmdLineRunner::new(settings, self.ruby_build_bin()) + .args(self.install_args_ruby_build(settings, tv)?) + .stdin_string(self.fetch_patches()?) + }; + Ok(cmd.with_pr(pr)) + } + fn install_args_ruby_build( + &self, + settings: &Settings, + tv: &ToolVersion, + ) -> Result> { + let mut args = env::RTX_RUBY_BUILD_OPTS.clone()?; + if self.verbose_install(settings) { + args.push("--verbose".into()); + } + if env::RTX_RUBY_APPLY_PATCHES.is_some() { + args.push("--patch".into()); + } + args.push(tv.version.clone()); + args.push(tv.install_path().to_string_lossy().to_string()); + Ok(args) + } + fn install_args_ruby_install(&self, tv: &ToolVersion) -> Result> { + let mut args = vec![]; + for patch in self.fetch_patch_sources() { + args.push("--patch".into()); + args.push(patch); + } + let (engine, version) = match tv.version.split_once('-') { + Some((engine, version)) => (engine, version), + None => ("ruby", tv.version.as_str()), + }; + args.push(engine.into()); + args.push(version.into()); + args.push("--install-dir".into()); + args.push(tv.install_path().to_string_lossy().to_string()); + args.extend(env::RTX_RUBY_INSTALL_OPTS.clone()?); + Ok(args) + } + + fn verbose_install(&self, settings: &Settings) -> bool { + let verbose_env = *env::RTX_RUBY_VERBOSE_INSTALL; + verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) + } + + fn fetch_patch_sources(&self) -> Vec { + let patch_sources = env::RTX_RUBY_APPLY_PATCHES.clone().unwrap_or_default(); + patch_sources + .split('\n') + .map(|s| s.to_string()) + .filter(|s| !s.is_empty()) + .collect() + } + + fn fetch_patches(&self) -> Result { + let mut patches = vec![]; + for f in &self.fetch_patch_sources() { + if regex!(r#"^[Hh][Tt][Tt][Pp][Ss]?://"#).is_match(f) { + let client = http::Client::new()?; + let resp = client.get(f).send()?.text()?; + patches.push(resp); + } else { + patches.push(fs::read_to_string(f)?); + } + } + Ok(patches.join("\n")) + } +} + +impl Plugin for RubyPlugin { + fn name(&self) -> &PluginName { + &self.core.name + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.core + .remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".ruby-version".into(), "Gemfile".into()]) + } + + fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + let v = match path.file_name() { + Some(name) if name == "Gemfile" => parse_gemfile(&fs::read_to_string(path)?), + _ => { + // .ruby-version + let body = fs::read_to_string(path)?; + body.trim() + .trim_start_matches("ruby-") + .trim_start_matches('v') + .to_string() + } + }; + Ok(v) + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + self.update_build_tool()?; + assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); + + pr.set_message("running ruby-build"); + self.install_cmd(&config.settings, tv, pr)?.execute()?; + + self.test_ruby(config, tv, pr)?; + self.install_rubygems_hook(tv)?; + self.test_gem(config, tv, pr)?; + self.install_default_gems(&config.settings, tv, pr)?; + Ok(()) + } + + fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + // TODO: is there a way to avoid needing to set RUBYLIB? + // is there a directory I can put rubygems_plugin.rb in that will be automatically loaded? + let rubygems_plugin_path = self.rubygems_plugins_path(tv); + let mut map = HashMap::new(); + if rubygems_plugin_path.exists() { + let rubygems_plugin_path = rubygems_plugin_path.to_string_lossy().to_string(); + let rubylib = match env::PRISTINE_ENV.get("RUBYLIB") { + Some(rubylib) => format!("{}:{}", rubylib, rubygems_plugin_path), + None => rubygems_plugin_path, + }; + map.insert("RUBYLIB".to_string(), rubylib); + } + Ok(map) + } +} + +fn parse_gemfile(body: &str) -> String { + let v = body + .lines() + .find(|line| line.trim().starts_with("ruby ")) + .unwrap_or_default() + .trim() + .split('#') + .next() + .unwrap_or_default() + .replace("engine:", ":engine =>") + .replace("engine_version:", ":engine_version =>"); + let v = regex!(r#".*:engine *=> *['"](?[^'"]*).*:engine_version *=> *['"](?[^'"]*).*"#).replace_all(&v, "${engine_version}__ENGINE__${engine}").to_string(); + let v = regex!(r#".*:engine_version *=> *['"](?[^'"]*).*:engine *=> *['"](?[^'"]*).*"#).replace_all(&v, "${engine_version}__ENGINE__${engine}").to_string(); + let v = regex!(r#" *ruby *['"]([^'"]*).*"#) + .replace_all(&v, "$1") + .to_string(); + let v = regex!(r#"^[^0-9]"#).replace_all(&v, "").to_string(); + regex!(r#"(.*)__ENGINE__(.*)"#) + .replace_all(&v, "$2-$1") + .to_string() +} + +#[cfg(test)] +mod tests { + use indoc::indoc; + + use super::*; + + #[test] + fn test_parse_gemfile() { + assert_eq!( + parse_gemfile(indoc! {r#" + ruby '2.7.2' + "#}), + "2.7.2" + ); + assert_eq!( + parse_gemfile(indoc! {r#" + ruby '1.9.3', engine: 'jruby', engine_version: "1.6.7" + "#}), + "jruby-1.6.7" + ); + assert_eq!( + parse_gemfile(indoc! {r#" + ruby '1.9.3', :engine => 'jruby', :engine_version => '1.6.7' + "#}), + "jruby-1.6.7" + ); + assert_eq!( + parse_gemfile(indoc! {r#" + ruby '1.9.3', :engine_version => '1.6.7', :engine => 'jruby' + "#}), + "jruby-1.6.7" + ); + } +} diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index a8f886baa..2014133d7 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -1,10 +1,10 @@ use std::collections::{BTreeMap, HashMap}; +use std::fs; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::exit; -use std::sync::mpsc::channel; + use std::time::Duration; -use std::{fs, thread}; use clap::Command; use color_eyre::eyre::{eyre, Result, WrapErr}; @@ -24,6 +24,7 @@ use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::rtx_plugin_toml::RtxPluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; +use crate::timeout::run_with_timeout; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{dirs, env, file}; @@ -86,18 +87,17 @@ impl ExternalPlugin { fn fetch_remote_versions(&self, settings: &Settings) -> Result> { let cmd = self.script_man.cmd(settings, &Script::ListAll); - let (tx, rx) = channel(); - thread::spawn(move || { - let result = cmd.stdout_capture().stderr_capture().unchecked().run(); - tx.send(result).unwrap(); - }); - let result = rx - .recv_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) - .with_context(|| format!("timed out fetching remote versions for {}", self.name))? - .map_err(|err| { - let script = self.script_man.get_script_path(&Script::ListAll); - eyre!("Failed to run {}: {}", script.display(), err) - })?; + let result = run_with_timeout( + move || { + let result = cmd.stdout_capture().stderr_capture().unchecked().run()?; + Ok(result) + }, + *RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, + ) + .map_err(|err| { + let script = self.script_man.get_script_path(&Script::ListAll); + eyre!("Failed to run {}: {}", script.display(), err) + })?; let stdout = String::from_utf8(result.stdout).unwrap(); let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index b7ad7fe57..d0e1504af 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -170,8 +170,10 @@ impl ScriptManager { script: &Script, pr: &ProgressReport, ) -> Result<()> { - let mut cmd = CmdLineRunner::new(settings, self.get_script_path(script)); - cmd.with_pr(pr).env_clear().envs(&self.env); + let cmd = CmdLineRunner::new(settings, self.get_script_path(script)) + .with_pr(pr) + .env_clear() + .envs(&self.env); if let Err(e) = cmd.execute() { let status = match e.downcast_ref::() { Some(ScriptFailed(_, status)) => *status, diff --git a/src/timeout.rs b/src/timeout.rs new file mode 100644 index 000000000..973682e67 --- /dev/null +++ b/src/timeout.rs @@ -0,0 +1,17 @@ +use color_eyre::eyre::{Context, Result}; +use std::sync::mpsc; +use std::thread; +use std::time::Duration; + +pub fn run_with_timeout(f: F, timeout: Duration) -> Result +where + F: FnOnce() -> Result + Send + 'static, + T: Send + 'static, +{ + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let result = f(); + tx.send(result).unwrap(); + }); + rx.recv_timeout(timeout).context("timed out")? +} From a8d08009be0112be0a1da65f2e899b1bdf272979 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 10 Jul 2023 01:10:29 -0500 Subject: [PATCH 0855/1891] added go core plugin (#667) --- .github/workflows/rtx.yml | 8 +- Cargo.lock | 22 ++ Cargo.toml | 2 + README.md | 2 +- docs/go.md | 41 ++++ docs/node.md | 2 +- docs/ruby.md | 4 +- e2e/.gitignore | 3 +- e2e/direnv/no_tool_versions/test_direnv | 3 +- .../system_version/test_direnv_system_version | 3 +- e2e/gopath/.e2e-tool-versions | 2 +- e2e/gopath/test_gopath | 16 +- src/cli/install.rs | 6 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 4 +- src/cmd.rs | 2 +- src/env.rs | 5 + src/file.rs | 18 +- src/hash.rs | 35 +++ src/http.rs | 31 ++- src/plugins/core/go.rs | 214 ++++++++++++++++++ src/plugins/core/mod.rs | 10 +- src/plugins/core/python.rs | 4 +- src/plugins/core/ruby.rs | 13 +- .../rtx__hash__tests__hash_sha256.snap | 5 + src/ui/progress_report.rs | 7 +- 26 files changed, 428 insertions(+), 36 deletions(-) create mode 100644 docs/go.md create mode 100644 src/plugins/core/go.rs create mode 100644 src/snapshots/rtx__hash__tests__hash_sha256.snap diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 134e6eb8b..6b8e3edec 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -38,7 +38,7 @@ jobs: coverage: name: coverage-${{matrix.tranche}} runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 30 strategy: fail-fast: false matrix: @@ -66,7 +66,7 @@ jobs: TEST_TRANCHE: ${{matrix.tranche}} TEST_TRANCHE_COUNT: 4 with: - timeout_minutes: 20 + timeout_minutes: 30 max_attempts: 3 command: just test-coverage - name: Upload to codecov.io @@ -131,7 +131,7 @@ jobs: e2e-linux: runs-on: ubuntu-22.04 needs: [build-linux] - timeout-minutes: 10 + timeout-minutes: 30 if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v3 @@ -149,7 +149,7 @@ jobs: env: RUST_BACKTRACE: "1" with: - timeout_minutes: 30 + timeout_minutes: 20 max_attempts: 3 command: ./e2e/run_all_tests rpm: diff --git a/Cargo.lock b/Cargo.lock index 84e9acd10..4f0d603cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1618,9 +1618,11 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "sha2", "shell-escape", "shell-words", "simplelog", + "tar", "tera", "terminal_size", "thiserror", @@ -1922,6 +1924,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.6.0" @@ -2636,6 +2649,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + [[package]] name = "xtask" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index bd9b1ee1a..a4b7450b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,9 +74,11 @@ self_update = { version = "0.37.0", default-features = false, optional = true, f serde = "1.0.164" serde_derive = "1.0.152" serde_json = "1.0.99" +sha2 = "0.10.7" shell-escape = "0.1.4" shell-words = "1.1.0" simplelog = { version = "0.12.0" } +tar = "0.4.38" tera = { version = "1.12.1", default-features = false } terminal_size = "0.2.1" thiserror = "1.0.38" diff --git a/README.md b/README.md index aa4208cc0..ef7fbb60b 100644 --- a/README.md +++ b/README.md @@ -1111,8 +1111,8 @@ You can see the core plugins with `rtx plugin ls --core`. * [experimental] [Python](./docs/python.md) * [NodeJS](./docs/node.md) * [Ruby (experimental)](./docs/ruby.md) +* [Go (experimental)](./docs/go.md) * ~Java~ - coming soon -* ~Go~ - coming soon ## FAQs diff --git a/docs/go.md b/docs/go.md new file mode 100644 index 000000000..15f20ada6 --- /dev/null +++ b/docs/go.md @@ -0,0 +1,41 @@ +# Go in rtx + +The following are instructions for using the go rtx core plugin. This is used when there isn't a +git plugin installed named "go". + +If you want to use [asdf-golang](https://github.com/kennyp/asdf-golang) +or [rtx-golang](https://github.com/rtx-plugins/rtx-golang) +then use `rtx plugins install go GIT_URL`. + +The code for this is inside the rtx repository at +[`./src/plugins/core/go.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/go.rs). + +## Usage + +The following installs the latest version of go-1.20.x (if some version of 1.20.x is not already +installed) and makes it the global default: + +```sh-session +$ rtx use -g go@1.20 +``` + +## Configuration + +- `RTX_GO_SKIP_CHECKSUM` [bool]: skips checksum verification of downloaded go tarballs +- `RTX_GO_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-go-packages` + +## Default packages + +rtx can automatically install a default set of packages right after installing a new go version. +To enable this feature, provide a `$HOME/.default-go-packages` file that lists one packages per +line, for example: + +``` +github.com/Dreamacro/clash # allows comments +github.com/jesseduffield/lazygit +``` + +## `.go-version` file support + +rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. +However it can also read go-specific version files named `.go-version`. diff --git a/docs/node.md b/docs/node.md index 7b22f1fcf..63030c2b4 100644 --- a/docs/node.md +++ b/docs/node.md @@ -1,4 +1,4 @@ -# node in rtx +# Node in rtx The following are instructions for using the node rtx core plugin. This is used when there isn't a git plugin installed named "node". diff --git a/docs/ruby.md b/docs/ruby.md index 67b8601b1..723613c67 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -1,4 +1,4 @@ -# ruby in rtx +# Ruby in rtx The following are instructions for using the ruby rtx core plugin. This is used when there isn't a git plugin installed named "ruby". @@ -16,7 +16,7 @@ The following installs the latest version of ruby-3.2.x (if some version of 3.2. installed) and makes it the global default: ```sh-session -$ rtx use -g node@20 +$ rtx use -g ruby@3.2 ``` Behind the scenes, rtx uses [`ruby-build`](https://github.com/rbenv/ruby-build) to compile ruby diff --git a/e2e/.gitignore b/e2e/.gitignore index 172c28ab5..1be8b4557 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -4,5 +4,6 @@ .cache .config .asdf +.default-go-packages +ruby/Gemfile Library - diff --git a/e2e/direnv/no_tool_versions/test_direnv b/e2e/direnv/no_tool_versions/test_direnv index d76115c4b..07ff633ea 100755 --- a/e2e/direnv/no_tool_versions/test_direnv +++ b/e2e/direnv/no_tool_versions/test_direnv @@ -1,7 +1,8 @@ #!/usr/bin/env zsh - set -e +export RTX_EXPERIMENTAL=1 + eval "$(direnv hook zsh)" eval "$(rtx activate zsh --status)" _rtx_hook && direnv allow && _direnv_hook diff --git a/e2e/direnv/system_version/test_direnv_system_version b/e2e/direnv/system_version/test_direnv_system_version index a747da879..7f4081704 100755 --- a/e2e/direnv/system_version/test_direnv_system_version +++ b/e2e/direnv/system_version/test_direnv_system_version @@ -1,7 +1,8 @@ #!/usr/bin/env zsh - set -e +export RTX_EXPERIMENTAL=1 + eval "$(direnv hook zsh)" eval "$(rtx activate zsh --status)" _rtx_hook && _direnv_hook diff --git a/e2e/gopath/.e2e-tool-versions b/e2e/gopath/.e2e-tool-versions index 58b446162..1799f52fc 100644 --- a/e2e/gopath/.e2e-tool-versions +++ b/e2e/gopath/.e2e-tool-versions @@ -1 +1 @@ -golang 1.19.5 +golang 1.19 diff --git a/e2e/gopath/test_gopath b/e2e/gopath/test_gopath index c2e0162bf..e9940e9cc 100755 --- a/e2e/gopath/test_gopath +++ b/e2e/gopath/test_gopath @@ -4,6 +4,9 @@ set -e eval "$(rtx activate bash)" _rtx_hook +export RTX_EXPERIMENTAL=1 +export RTX_GO_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-go-packages" + assert_gopath() { local expected="$1" if [[ "$GOPATH" != "$expected" ]]; then @@ -12,9 +15,16 @@ assert_gopath() { fi } -rtx i golang@1.18.10 golang@1.19.5 && _rtx_hook -assert_gopath "$RTX_DATA_DIR/installs/go/1.19.5/packages" +cat >"$RTX_GO_DEFAULT_PACKAGES_FILE" < { - pr.error(); + pr.error(err.to_string()); Err(err.wrap_err(format!("failed to uninstall {}", tv))) } } @@ -227,7 +227,7 @@ impl Install { match tool.install_version(config, tv, &mut pr, self.force) { Ok(_) => Ok(()), Err(err) => { - pr.error(); + pr.error(err.to_string()); Err(err.wrap_err(format!("failed to install {}", tv))) } } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 8d5d673ac..2d9478699 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -51,7 +51,7 @@ impl Command for Uninstall { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, Some(&tv)); if let Err(err) = plugin.uninstall_version(&config, &tv, &pr, false) { - pr.error(); + pr.error(err.to_string()); return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", &tv))); } pr.finish_with_message("uninstalled"); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index f369fd2ec..04140ae1c 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -116,7 +116,7 @@ impl Upgrade { match tool.install_version(config, &tv, pr, false) { Ok(_) => Ok(()), Err(err) => { - pr.error(); + pr.error(err.to_string()); Err(err.wrap_err(format!("failed to install {}", tv))) } } @@ -136,7 +136,7 @@ impl Upgrade { Ok(()) } Err(err) => { - pr.error(); + pr.error(err.to_string()); Err(err.wrap_err(format!("failed to uninstall {}", tv))) } } diff --git a/src/cmd.rs b/src/cmd.rs index d4e6bb34d..271a13729 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -252,7 +252,7 @@ impl<'a> CmdLineRunner<'a> { fn on_error(&self, output: String, status: ExitStatus) -> Result<()> { match self.pr { Some(pr) => { - pr.error(); + pr.error(format!("{} failed", self.get_program())); if !self.settings.verbose && !output.trim().is_empty() { pr.println(output); } diff --git a/src/env.rs b/src/env.rs index b7b13078f..e229e70f7 100644 --- a/src/env.rs +++ b/src/env.rs @@ -162,6 +162,11 @@ pub static RTX_RUBY_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_RUBY_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-gems")) }); +pub static RTX_GO_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("RTX_GO_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-go-packages")) +}); +pub static RTX_GO_SKIP_CHECKSUM: Lazy = Lazy::new(|| var_is_true("RTX_GO_SKIP_CHECKSUM")); + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { Yes, diff --git a/src/file.rs b/src/file.rs index 1f2063c1e..6d19ebbd3 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,11 +1,14 @@ +use std::fs::File; +use std::os::unix::fs::symlink; +use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::time::Duration; use std::{fs, io}; use color_eyre::eyre::Result; use filetime::{set_file_times, FileTime}; -use std::os::unix::fs::symlink; -use std::os::unix::prelude::*; +use flate2::read::GzDecoder; +use tar::Archive; use crate::{dirs, env}; @@ -212,11 +215,20 @@ pub fn which(name: &str) -> Option { None } +pub fn untar(archive: &Path, dest: &Path) -> Result<()> { + let f = File::open(archive)?; + let tar = GzDecoder::new(f); + let mut archive = Archive::new(tar); + archive.unpack(dest)?; + Ok(()) +} + #[cfg(test)] mod tests { - use itertools::Itertools; use std::ops::Deref; + use itertools::Itertools; + use crate::dirs; use super::*; diff --git a/src/hash.rs b/src/hash.rs index ad4636441..32f4ffe21 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,5 +1,10 @@ use std::collections::hash_map::DefaultHasher; +use std::fs::File; use std::hash::{Hash, Hasher}; +use std::path::Path; + +use color_eyre::eyre::{bail, Result}; +use sha2::{Digest, Sha256}; pub fn hash_to_str(t: &T) -> String { let mut s = DefaultHasher::new(); @@ -8,12 +13,42 @@ pub fn hash_to_str(t: &T) -> String { format!("{bytes:x}") } +pub fn file_hash_sha256(path: &Path) -> Result { + let mut file = File::open(path)?; + let mut hasher = Sha256::new(); + std::io::copy(&mut file, &mut hasher)?; + let hash = hasher.finalize(); + Ok(format!("{:x}", hash)) +} + +pub fn ensure_checksum_sha256(path: &Path, checksum: &str) -> Result<()> { + let actual = file_hash_sha256(path)?; + if actual != checksum { + bail!( + "Checksum mismatch for file {:?}:\nExpected: {}\nActual: {}", + path, + checksum, + actual + ); + } + Ok(()) +} + #[cfg(test)] mod tests { + use insta::assert_snapshot; + use super::*; #[test] fn test_hash_to_str() { assert_eq!(hash_to_str(&"foo"), "3e8b8c44c3ca73b7"); } + + #[test] + fn test_hash_sha256() { + let path = Path::new(".test-tool-versions"); + let hash = file_hash_sha256(path).unwrap(); + assert_snapshot!(hash); + } } diff --git a/src/http.rs b/src/http.rs index f94120c81..b18330628 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,6 +1,8 @@ -use color_eyre::eyre::Result; -use reqwest::blocking::RequestBuilder; +use color_eyre::eyre::{eyre, Result}; +use reqwest::blocking::{RequestBuilder, Response}; use reqwest::IntoUrl; +use std::fs::File; +use std::path::Path; pub struct Client { reqwest: reqwest::blocking::Client, @@ -17,4 +19,29 @@ impl Client { pub fn get(&self, url: U) -> RequestBuilder { self.reqwest.get(url) } + + pub fn get_text(&self, url: U) -> Result { + let resp = self.get(url).send()?; + self.ensure_success(&resp)?; + let text = resp.text()?; + Ok(text) + } + + pub fn download_file(&self, url: U, path: &Path) -> Result<()> { + let url = url.into_url()?; + debug!("Downloading {} to {}", &url, path.display()); + let mut resp = self.get(url).send()?; + self.ensure_success(&resp)?; + let mut file = File::create(path)?; + resp.copy_to(&mut file)?; + Ok(()) + } + + pub fn ensure_success(&self, resp: &Response) -> Result<()> { + if resp.status().is_success() { + Ok(()) + } else { + Err(eyre!("HTTP error: {} on {}", resp.status(), resp.url())) + } + } } diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs new file mode 100644 index 000000000..6059a3217 --- /dev/null +++ b/src/plugins/core/go.rs @@ -0,0 +1,214 @@ +use std::collections::HashMap; +use std::fs; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::Result; +use itertools::Itertools; +use versions::Versioning; + +use crate::cli::version::{ARCH, OS}; +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::plugins::core::CorePlugin; +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; +use crate::{cmd, env, file, hash, http}; + +#[derive(Debug)] +pub struct GoPlugin { + core: CorePlugin, +} + +impl GoPlugin { + pub fn new(name: PluginName) -> Self { + Self { + core: CorePlugin::new(name), + } + } + + fn fetch_remote_versions(&self) -> Result> { + CorePlugin::run_fetch_task_with_timeout(move || { + let output = cmd!( + "git", + "ls-remote", + "--tags", + "https://github.com/golang/go", + "go*" + ) + .read()?; + let lines = output.split('\n'); + let versions = lines.map(|s| s.split("/go").last().unwrap_or_default().to_string()) + .filter(|s| !s.is_empty()) + .filter(|s| !regex!(r#"^1($|\.0|\.0\.[0-9]|\.1|\.1rc[0-9]|\.1\.[0-9]|.2|\.2rc[0-9]|\.2\.1|.8.5rc5)$"#).is_match(s)) + .unique() + .sorted_by_cached_key(|s| Versioning::new(s)) + .collect(); + Ok(versions) + }) + } + + fn goroot(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("go") + } + fn go_bin(&self, tv: &ToolVersion) -> PathBuf { + self.goroot(tv).join("bin/go") + } + fn gopath(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("packages") + } + + fn install_default_packages( + &self, + settings: &Settings, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + let body = fs::read_to_string(&*env::RTX_GO_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + for package in body.lines() { + let package = package.split('#').next().unwrap_or_default().trim(); + if package.is_empty() { + continue; + } + pr.set_message(format!("installing default package: {}", package)); + let package = if package.contains('@') { + package.to_string() + } else { + format!("{}@latest", package) + }; + CmdLineRunner::new(settings, self.go_bin(tv)) + .with_pr(pr) + .arg("install") + .arg(package) + .env("GOROOT", self.goroot(tv)) + .env("GOPATH", self.gopath(tv)) + .execute()?; + } + Ok(()) + } + + fn test_go(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + CmdLineRunner::new(&config.settings, self.go_bin(tv)) + .with_pr(pr) + .arg("version") + .execute() + } + + fn download(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result { + let http = http::Client::new()?; + let filename = format!("go{}.{}-{}.tar.gz", tv.version, platform(), arch()); + let tarball_url = format!("https://dl.google.com/go/{}", &filename); + let tarball_path = tv.download_path().join(filename); + + pr.set_message(format!("downloading tarball {}", &tarball_url)); + http.download_file(&tarball_url, &tarball_path)?; + + self.verify_tarball_checksum(&tarball_url, &tarball_path)?; + + Ok(tarball_path) + } + + fn verify_tarball_checksum(&self, tarball_url: &str, tarball_path: &Path) -> Result<()> { + let checksum_url = format!("{}.sha256", tarball_url); + let checksum = http::Client::new()?.get_text(checksum_url)?; + if !*env::RTX_GO_SKIP_CHECKSUM { + hash::ensure_checksum_sha256(tarball_path, &checksum)?; + } + Ok(()) + } + + fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { + let tarball = tarball_path + .file_name() + .unwrap_or_default() + .to_string_lossy(); + pr.set_message(format!("installing {}", tarball)); + file::untar(tarball_path, &tv.install_path())?; + Ok(()) + } + + fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("verifying"); + self.test_go(config, tv, pr)?; + self.install_default_packages(&config.settings, tv, pr) + } +} + +impl Plugin for GoPlugin { + fn name(&self) -> &PluginName { + &self.core.name + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.core + .remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".go-version".into()]) + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); + + let tarball_path = self.download(tv, pr)?; + self.install(tv, pr, &tarball_path)?; + self.verify(config, tv, pr)?; + + Ok(()) + } + + fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { + Ok(vec![ + self.goroot(tv).join("bin"), + self.gopath(tv).join("bin"), + ]) + } + + fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + let mut map = HashMap::new(); + if env::PRISTINE_ENV.get("GOROOT").is_none() { + map.insert( + "GOROOT".to_string(), + self.goroot(tv).to_string_lossy().to_string(), + ); + }; + if env::PRISTINE_ENV.get("GOPATH").is_none() { + map.insert( + "GOPATH".to_string(), + self.gopath(tv).to_string_lossy().to_string(), + ); + }; + Ok(map) + } +} + +fn platform() -> &'static str { + if cfg!(target_os = "macos") { + "darwin" + } else { + &OS + } +} + +fn arch() -> &'static str { + if cfg!(target_arch = "x86_64") || cfg!(target_arch = "amd64") { + "amd64" + } else if cfg!(target_arch = "i686") || cfg!(target_arch = "i386") || cfg!(target_arch = "386") + { + "386" + } else if cfg!(target_arch = "armv6l") || cfg!(target_arch = "armv7l") { + "armv6l" + } else if cfg!(target_arch = "aarch64") || cfg!(target_arch = "arm64") { + "arm64" + } else { + &ARCH + } +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index a4bd32410..6d87dcdbb 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -11,6 +11,7 @@ pub use python::PythonPlugin; use crate::cache::CacheManager; use crate::env::RTX_EXE; +use crate::plugins::core::go::GoPlugin; use crate::plugins::core::node::NodePlugin; use crate::plugins::core::ruby::RubyPlugin; use crate::plugins::{Plugin, PluginName}; @@ -19,6 +20,7 @@ use crate::tool::Tool; use crate::toolset::ToolVersion; use crate::{dirs, env}; +mod go; mod node; mod python; mod ruby; @@ -32,8 +34,12 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { ]) }); -pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = - Lazy::new(|| build_core_plugins(vec![Box::new(RubyPlugin::new("ruby".to_string()))])); +pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { + build_core_plugins(vec![ + Box::new(GoPlugin::new("go".to_string())), + Box::new(RubyPlugin::new("ruby".to_string())), + ]) +}); fn build_core_plugins(tools: Vec>) -> ToolMap { ToolMap::from_iter(tools.into_iter().map(|plugin| { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index f6551759d..86f67381a 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -184,7 +184,9 @@ impl Plugin for PythonPlugin { if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { pr.set_message(format!("with patch file from: {patch_url}")); let http = http::Client::new()?; - let patch = http.get(patch_url).send()?.text()?; + let resp = http.get(patch_url).send()?; + http.ensure_success(&resp)?; + let patch = resp.text()?; cmd = cmd.arg("--patch").stdin_string(patch) } if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 7402806bf..3c0b10827 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -217,8 +217,10 @@ impl RubyPlugin { if let Some(token) = &*GITHUB_API_TOKEN { req = req.header("authorization", format!("token {}", token)); } - let resp: GithubRelease = req.send()?.json()?; - Ok(resp.tag_name.trim_start_matches('v').to_string()) + let resp = req.send()?; + http.ensure_success(&resp)?; + let release: GithubRelease = resp.json()?; + Ok(release.tag_name.trim_start_matches('v').to_string()) } fn install_rubygems_hook(&self, tv: &ToolVersion) -> Result<()> { @@ -301,9 +303,10 @@ impl RubyPlugin { let mut patches = vec![]; for f in &self.fetch_patch_sources() { if regex!(r#"^[Hh][Tt][Tt][Pp][Ss]?://"#).is_match(f) { - let client = http::Client::new()?; - let resp = client.get(f).send()?.text()?; - patches.push(resp); + let http = http::Client::new()?; + let resp = http.get(f).send()?; + http.ensure_success(&resp)?; + patches.push(resp.text()?); } else { patches.push(fs::read_to_string(f)?); } diff --git a/src/snapshots/rtx__hash__tests__hash_sha256.snap b/src/snapshots/rtx__hash__tests__hash_sha256.snap new file mode 100644 index 000000000..9deb56f47 --- /dev/null +++ b/src/snapshots/rtx__hash__tests__hash_sha256.snap @@ -0,0 +1,5 @@ +--- +source: src/hash.rs +expression: hash +--- +0b0debe521bb0f275806469aa295bb0fab42f0fbd3a1bea15b3f7ccd06985a4a diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 09b7e9f01..63f2d084f 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -94,9 +94,14 @@ impl ProgressReport { None => eprintln!("{}", message.as_ref()), } } - pub fn error(&self) { + pub fn error>(&self, message: S) { match &self.pb { Some(pb) => { + pb.set_message(format!( + "{} {}", + style("[ERROR]").red().for_stderr(), + message.as_ref() + )); pb.set_style(ERROR_TEMPLATE.clone()); pb.finish() } From cc2538214faba77116f72d1bd96f64062beaf04f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 10 Jul 2023 03:29:39 -0500 Subject: [PATCH 0856/1891] added java core plugin (#668) --- .github/workflows/rtx.yml | 2 +- README.md | 2 +- docs/java.md | 23 ++ e2e/.gitignore | 1 + e2e/gopath/.e2e-tool-versions | 2 +- e2e/gopath/test_gopath | 20 +- e2e/test_go | 15 + e2e/test_java | 8 + src/cache.rs | 8 +- ...tx__cli__alias__set__tests__alias_set.snap | 1 + ...cli__alias__unset__tests__alias_unset.snap | 1 + src/file.rs | 8 +- src/plugins/core/go.rs | 11 +- src/plugins/core/java.rs | 325 ++++++++++++++++++ src/plugins/core/mod.rs | 3 + src/ui/progress_report.rs | 2 +- 16 files changed, 407 insertions(+), 25 deletions(-) create mode 100644 docs/java.md create mode 100755 e2e/test_go create mode 100755 e2e/test_java create mode 100644 src/plugins/core/java.rs diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 6b8e3edec..eb136a27c 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -67,7 +67,7 @@ jobs: TEST_TRANCHE_COUNT: 4 with: timeout_minutes: 30 - max_attempts: 3 + max_attempts: 2 command: just test-coverage - name: Upload to codecov.io uses: codecov/codecov-action@v3 diff --git a/README.md b/README.md index ef7fbb60b..59581f33c 100644 --- a/README.md +++ b/README.md @@ -1112,7 +1112,7 @@ You can see the core plugins with `rtx plugin ls --core`. * [NodeJS](./docs/node.md) * [Ruby (experimental)](./docs/ruby.md) * [Go (experimental)](./docs/go.md) -* ~Java~ - coming soon +* [Java (experimental)](./docs/java.md) ## FAQs diff --git a/docs/java.md b/docs/java.md new file mode 100644 index 000000000..f5ac5f1fa --- /dev/null +++ b/docs/java.md @@ -0,0 +1,23 @@ +# Java in rtx + +The following are instructions for using the java rtx core plugin. This is used when there isn't a +git plugin installed named "java". + +If you want to use [asdf-java](https://github.com/halcyon/asdf-java) +or [rtx-java](https://github.com/rtx-plugins/rtx-java) +then use `rtx plugins install java GIT_URL`. + +The code for this is inside the rtx repository at +[`./src/plugins/core/java.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/java.rs). + +## Usage + +The following installs the latest version of java-openjdk-17.x (if some version of openjdk-17.x is +not already installed) and makes it the global default: + +```sh-session +$ rtx use -g java@openjdk-17 +$ rtx use -g java@17 # alternate shorthands for openjdk-only +``` + +See available versions with `rtx ls-remote java`. diff --git a/e2e/.gitignore b/e2e/.gitignore index 1be8b4557..7425c8c2a 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -6,4 +6,5 @@ .asdf .default-go-packages ruby/Gemfile +ruby/.ruby-version Library diff --git a/e2e/gopath/.e2e-tool-versions b/e2e/gopath/.e2e-tool-versions index 1799f52fc..58b446162 100644 --- a/e2e/gopath/.e2e-tool-versions +++ b/e2e/gopath/.e2e-tool-versions @@ -1 +1 @@ -golang 1.19 +golang 1.19.5 diff --git a/e2e/gopath/test_gopath b/e2e/gopath/test_gopath index e9940e9cc..2a9a6d440 100755 --- a/e2e/gopath/test_gopath +++ b/e2e/gopath/test_gopath @@ -1,11 +1,10 @@ #!/usr/bin/env bash - set -e -eval "$(rtx activate bash)" -_rtx_hook export RTX_EXPERIMENTAL=1 -export RTX_GO_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-go-packages" + +eval "$(rtx activate bash)" +_rtx_hook assert_gopath() { local expected="$1" @@ -15,16 +14,9 @@ assert_gopath() { fi } -cat >"$RTX_GO_DEFAULT_PACKAGES_FILE" <"$RTX_GO_DEFAULT_PACKAGES_FILE" <&1" "openjdk version \"17.0.2\"" diff --git a/src/cache.rs b/src/cache.rs index e82ac2f6b..89bada2ee 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -17,7 +17,7 @@ use serde::Serialize; #[derive(Debug, Clone)] pub struct CacheManager where - T: Clone + Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, { cache_file_path: PathBuf, fresh_duration: Option, @@ -28,7 +28,7 @@ where impl CacheManager where - T: Clone + Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, { pub fn new(cache_file_path: PathBuf) -> Self { Self { @@ -65,7 +65,7 @@ where } } let val = (fetch)()?; - if let Err(err) = self.write(val.clone()) { + if let Err(err) = self.write(&val) { warn!("failed to write cache file: {} {:#}", path.display(), err); } Ok(val) @@ -82,7 +82,7 @@ where Ok(rmp_serde::from_slice(&bytes)?) } - pub fn write(&self, val: T) -> Result<()> { + pub fn write(&self, val: &T) -> Result<()> { let path = &self.cache_file_path; trace!("writing {}", display_path(path)); if let Some(parent) = path.parent() { diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 7daa3312f..795572119 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -2,6 +2,7 @@ source: src/cli/alias/set.rs expression: output --- +java lts 17 node lts 18 node lts-argon 4 node lts-boron 6 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index 8b788f467..5d4a90e93 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -2,6 +2,7 @@ source: src/cli/alias/unset.rs expression: output --- +java lts 17 node lts 18 node lts-argon 4 node lts-boron 6 diff --git a/src/file.rs b/src/file.rs index 6d19ebbd3..cbf4fe655 100644 --- a/src/file.rs +++ b/src/file.rs @@ -10,7 +10,7 @@ use filetime::{set_file_times, FileTime}; use flate2::read::GzDecoder; use tar::Archive; -use crate::{dirs, env}; +use crate::{cmd, dirs, env}; pub fn remove_all>(path: P) -> io::Result<()> { let path = path.as_ref(); @@ -216,6 +216,7 @@ pub fn which(name: &str) -> Option { } pub fn untar(archive: &Path, dest: &Path) -> Result<()> { + debug!("tar -xzf {} -C {}", archive.display(), dest.display()); let f = File::open(archive)?; let tar = GzDecoder::new(f); let mut archive = Archive::new(tar); @@ -223,6 +224,11 @@ pub fn untar(archive: &Path, dest: &Path) -> Result<()> { Ok(()) } +pub fn unzip(archive: &Path, dest: &Path) -> Result<()> { + cmd!("unzip", archive, "-d", dest).run()?; + Ok(()) +} + #[cfg(test)] mod tests { use std::ops::Deref; diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 6059a3217..c9f906536 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -100,7 +100,7 @@ impl GoPlugin { let tarball_url = format!("https://dl.google.com/go/{}", &filename); let tarball_path = tv.download_path().join(filename); - pr.set_message(format!("downloading tarball {}", &tarball_url)); + pr.set_message(format!("downloading {}", &tarball_url)); http.download_file(&tarball_url, &tarball_path)?; self.verify_tarball_checksum(&tarball_url, &tarball_path)?; @@ -145,7 +145,6 @@ impl Plugin for GoPlugin { .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { Ok(vec![".go-version".into()]) } @@ -165,6 +164,14 @@ impl Plugin for GoPlugin { Ok(()) } + fn uninstall_version(&self, _config: &Config, tv: &ToolVersion) -> Result<()> { + let gopath = self.gopath(tv); + if gopath.exists() { + cmd!("chmod", "-R", "u+wx", gopath).run()?; + } + Ok(()) + } + fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { Ok(vec![ self.goroot(tv).join("bin"), diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs new file mode 100644 index 000000000..9406f2e36 --- /dev/null +++ b/src/plugins/core/java.rs @@ -0,0 +1,325 @@ +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::fmt::Display; +use std::fs; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::{eyre, Result}; +use itertools::Itertools; +use once_cell::sync::Lazy; +use serde_derive::{Deserialize, Serialize}; +use versions::Versioning; + +use crate::cache::CacheManager; +use crate::cli::version::{ARCH, OS}; +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::duration::DAILY; +use crate::env::RTX_EXE; +use crate::plugins::core::CorePlugin; +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; +use crate::{file, hash, http}; + +#[derive(Debug)] +pub struct JavaPlugin { + core: CorePlugin, + java_metadata_ea_cache: CacheManager>, + java_metadata_ga_cache: CacheManager>, +} + +impl JavaPlugin { + pub fn new(name: PluginName) -> Self { + let core = CorePlugin::new(name); + let java_metadata_ga_cache_filename = + format!("java_metadata_ga_{}_{}.msgpack.z", os(), arch()); + let java_metadata_ea_cache_filename = + format!("java_metadata_ea_{}_{}.msgpack.z", os(), arch()); + Self { + java_metadata_ea_cache: CacheManager::new( + core.cache_path.join(java_metadata_ea_cache_filename), + ) + .with_fresh_duration(Some(DAILY)) + .with_fresh_file(RTX_EXE.clone()), + java_metadata_ga_cache: CacheManager::new( + core.cache_path.join(java_metadata_ga_cache_filename), + ) + .with_fresh_duration(Some(DAILY)) + .with_fresh_file(RTX_EXE.clone()), + core, + } + } + + fn fetch_java_metadata(&self, release_type: &str) -> Result<&HashMap> { + let cache = if release_type == "ea" { + &self.java_metadata_ea_cache + } else { + &self.java_metadata_ga_cache + }; + let release_type = release_type.to_string(); + cache.get_or_try_init(|| { + CorePlugin::run_fetch_task_with_timeout(move || { + let mut metadata = HashMap::new(); + + for m in download_java_metadata(&release_type)?.into_iter() { + // add openjdk short versions like "java@17.0.0" which default to openjdk + if m.vendor == "openjdk" { + if m.version.contains('.') { + metadata.insert(m.version.to_string(), m.clone()); + } else { + // rtx expects full versions like ".0.0" + metadata.insert(format!("{}.0.0", m.version), m.clone()); + } + } + metadata.insert(m.to_string(), m); + } + + Ok(metadata) + }) + }) + } + fn fetch_remote_versions(&self) -> Result> { + let versions = self + .fetch_java_metadata("ga")? + .iter() + .sorted_by_cached_key(|(v, m)| { + let is_shorthand = regex!(r"^\d").is_match(v); + let vendor = &m.vendor; + let is_jdk = m.image_type == "jdk"; + let features = 10 - m.features.len(); + let version = Versioning::new(v); + (is_shorthand, vendor, is_jdk, features, version) + }) + .map(|(v, _)| v.clone()) + .unique() + .collect(); + + Ok(versions) + } + + fn java_bin(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/java") + } + + fn test_java(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + CmdLineRunner::new(&config.settings, self.java_bin(tv)) + .with_pr(pr) + .env("JAVA_HOME", tv.install_path()) + .arg("-version") + .execute() + } + + fn download(&self, tv: &ToolVersion, pr: &ProgressReport, m: &JavaMetadata) -> Result { + let http = http::Client::new()?; + let filename = m.url.split('/').last().unwrap(); + let tarball_path = tv.download_path().join(filename); + + pr.set_message(format!("downloading {}", &m.url)); + http.download_file(&m.url, &tarball_path)?; + + hash::ensure_checksum_sha256(&tarball_path, &m.sha256)?; + + Ok(tarball_path) + } + + fn install( + &self, + tv: &ToolVersion, + pr: &ProgressReport, + tarball_path: &Path, + m: &JavaMetadata, + ) -> Result<()> { + pr.set_message(format!("installing {}", tarball_path.display())); + if m.file_type == "zip" { + file::unzip(tarball_path, &tv.download_path())?; + } else { + file::untar(tarball_path, &tv.download_path())?; + } + self.move_to_install_path(tv, m) + } + fn move_to_install_path(&self, tv: &ToolVersion, m: &JavaMetadata) -> Result<()> { + let basedir = tv + .download_path() + .read_dir()? + .find(|e| e.as_ref().unwrap().file_type().unwrap().is_dir()) + .unwrap()? + .path(); + let source_dir = match m.vendor.as_str() { + "zulu" | "liberica" => basedir, + _ if os() == "macosx" => basedir.join("Contents").join("Home"), + _ => basedir, + }; + file::remove_all(tv.install_path())?; + file::create_dir_all(tv.install_path())?; + for entry in fs::read_dir(source_dir)? { + let entry = entry?; + let dest = tv.install_path().join(entry.file_name()); + trace!("moving {:?} to {:?}", entry.path(), &dest); + fs::rename(entry.path(), dest)?; + } + Ok(()) + } + + fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("verifying"); + self.test_java(config, tv, pr) + } + + fn tv_release_type(&self, tv: &ToolVersion) -> String { + tv.opts + .get("release_type") + .cloned() + .unwrap_or(String::from("ga")) + } + + fn tv_to_java_version(&self, tv: &ToolVersion) -> String { + if regex!(r"^\d").is_match(&tv.version) { + // undo openjdk shorthand + format!("openjdk-{}", tv.version) + } else { + tv.version.clone() + } + } + + fn tv_to_metadata(&self, tv: &ToolVersion) -> Result<&JavaMetadata> { + let v = self.tv_to_java_version(tv); + let release_type = self.tv_release_type(tv); + let m = self + .fetch_java_metadata(&release_type)? + .get(&v) + .ok_or_else(|| eyre!("no metadata found for version {}", tv.version))?; + Ok(m) + } +} + +impl Plugin for JavaPlugin { + fn name(&self) -> &PluginName { + &self.core.name + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.core + .remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn get_aliases(&self, _settings: &Settings) -> Result> { + let aliases = BTreeMap::from([("lts".into(), "17".into())]); + Ok(aliases) + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); + + let metadata = self.tv_to_metadata(tv)?; + let tarball_path = self.download(tv, pr, metadata)?; + self.install(tv, pr, &tarball_path, metadata)?; + self.verify(config, tv, pr)?; + + Ok(()) + } + + fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + let map = HashMap::from([( + "JAVA_HOME".into(), + tv.install_path().to_string_lossy().into(), + )]); + Ok(map) + } +} + +fn os() -> &'static str { + if cfg!(target_os = "macos") { + "macosx" + } else { + &OS + } +} + +fn arch() -> &'static str { + if cfg!(target_arch = "x86_64") || cfg!(target_arch = "amd64") { + "x86_64" + } else if cfg!(target_arch = "armv6l") || cfg!(target_arch = "armv7l") { + "arm32-vfp-hflt" + } else if cfg!(target_arch = "aarch64") || cfg!(target_arch = "arm64") { + "aarch64" + } else { + &ARCH + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[serde(default)] +struct JavaMetadata { + vendor: String, + // filename: String, + release_type: String, + version: String, + jvm_impl: String, + os: String, + architecture: String, + file_type: String, + image_type: String, + features: Vec, + url: String, + sha256: String, + // md5: String, + // md5_file: String, + // sha1: String, + // sha1_file: String, + // sha256_file: String, + // sha512: String, + // sha512_file: String, + // size: u64, +} + +impl Display for JavaMetadata { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut v = vec![self.vendor.clone()]; + if self.image_type == "jre" { + v.push(self.image_type.clone()); + } + for f in self.features.iter() { + if JAVA_FEATURES.contains(f) { + v.push(f.clone()); + } + } + if self.jvm_impl == "openj9" { + v.push(self.jvm_impl.clone()); + } + v.push(self.version.clone()); + write!(f, "{}", v.join("-")) + } +} + +// only care about these features +static JAVA_FEATURES: Lazy> = + Lazy::new(|| HashSet::from(["musl", "javafx", "lite", "large_heap"].map(|s| s.to_string()))); +static JAVA_FILE_TYPES: Lazy> = + Lazy::new(|| HashSet::from(["tar.gz", "zip"].map(|s| s.to_string()))); + +fn download_java_metadata(release_type: &str) -> Result> { + let http = http::Client::new()?; + let resp = http + .get("https://joschi.github.io/java-metadata/metadata/all.json") + .send()?; + http.ensure_success(&resp)?; + + let metadata = resp + .json::>()? + .into_iter() + .filter(|m| { + m.architecture == arch() + && m.os == os() + && JAVA_FILE_TYPES.contains(&m.file_type) + && m.release_type == release_type + }) + .collect(); + Ok(metadata) +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 6d87dcdbb..49ec86317 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -12,6 +12,7 @@ pub use python::PythonPlugin; use crate::cache::CacheManager; use crate::env::RTX_EXE; use crate::plugins::core::go::GoPlugin; +use crate::plugins::core::java::JavaPlugin; use crate::plugins::core::node::NodePlugin; use crate::plugins::core::ruby::RubyPlugin; use crate::plugins::{Plugin, PluginName}; @@ -21,6 +22,7 @@ use crate::toolset::ToolVersion; use crate::{dirs, env}; mod go; +mod java; mod node; mod python; mod ruby; @@ -37,6 +39,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ Box::new(GoPlugin::new("go".to_string())), + Box::new(JavaPlugin::new("java".to_string())), Box::new(RubyPlugin::new("ruby".to_string())), ]) }); diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 63f2d084f..eec02ff7b 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -97,7 +97,7 @@ impl ProgressReport { pub fn error>(&self, message: S) { match &self.pb { Some(pb) => { - pb.set_message(format!( + self.set_message(format!( "{} {}", style("[ERROR]").red().for_stderr(), message.as_ref() From 7144a277f323310f36f42225064718580b7f180a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 10 Jul 2023 03:31:24 -0500 Subject: [PATCH 0857/1891] chore: Release --- Cargo.lock | 42 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f0d603cb..f55360074 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,7 +266,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -436,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eed5fff0d93c7559121e9c72bf9c242295869396255071ff2cb1617147b608c5" dependencies = [ "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -680,7 +680,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1339,7 +1339,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1389,9 +1389,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] @@ -1578,7 +1578,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.33.0" +version = "1.34.0" dependencies = [ "base64", "built", @@ -1756,22 +1756,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.168" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d614f89548720367ded108b3c843be93f3a341e22d5674ca0dd5cd57f34926af" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.168" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fe589678c688e44177da4f27152ee2d190757271dc7f1d5b6b9f68d869d641" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1915,9 +1915,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -2002,7 +2002,7 @@ checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -2016,9 +2016,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" dependencies = [ "itoa", "libc", @@ -2036,9 +2036,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" dependencies = [ "time-core", ] @@ -2385,7 +2385,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", "wasm-bindgen-shared", ] @@ -2419,7 +2419,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index a4b7450b4..3dfad5194 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.33.0" +version = "1.34.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 59581f33c..7cee09cd1 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.33.0 +rtx 1.34.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -326,7 +326,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.33.0/rtx-v1.33.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.34.0/rtx-v1.34.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ca78f3b86..8e7379f0f 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.33.0"; + version = "1.34.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 33d270de2..e4ebfec78 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.33.0" +.TH rtx 1 "rtx 1.34.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.33.0 +v1.34.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 7720a8ad3..45f8c4c9f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.33.0 +Version: 1.34.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 6cc9e92d1008e88b5787526a9b08c70a17093b02 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 11 Jul 2023 10:41:05 -0500 Subject: [PATCH 0858/1891] fix filtering of files for reshims (#672) I think this logic was just wrong before and it was creating superfluous shims --- src/shims.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shims.rs b/src/shims.rs index ff05738f0..8f0869118 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -94,7 +94,10 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { } for bin in path.read_dir()? { let bin = bin?; - if !bin.file_type()?.is_file() && !bin.file_type()?.is_symlink() { + if !bin.file_type()?.is_file() + || bin.file_type()?.is_symlink() + || !file::is_executable(&bin.path()) + { continue; } let bin_name = bin.file_name().into_string().unwrap(); From e1b3ecf225dba71118d46c45bf560deadd791b52 Mon Sep 17 00:00:00 2001 From: Nikita Pedorich Date: Thu, 13 Jul 2023 23:54:26 +0900 Subject: [PATCH 0859/1891] shells: add special nix behavior (#675) --- src/shell/bash.rs | 11 +++- src/shell/fish.rs | 11 +++- src/shell/mod.rs | 6 ++ src/shell/nushell.rs | 11 +++- ...tx__shell__bash__tests__hook_init_nix.snap | 34 +++++++++++ ...tx__shell__fish__tests__hook_init_nix.snap | 47 +++++++++++++++ ..._shell__nushell__tests__hook_init_nix.snap | 59 +++++++++++++++++++ ...x__shell__xonsh__tests__hook_init_nix.snap | 12 ++++ ...rtx__shell__zsh__tests__hook_init_nix.snap | 37 ++++++++++++ src/shell/xonsh.rs | 11 +++- src/shell/zsh.rs | 11 +++- 11 files changed, 240 insertions(+), 10 deletions(-) create mode 100644 src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap create mode 100644 src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap create mode 100644 src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap create mode 100644 src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap create mode 100644 src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap diff --git a/src/shell/bash.rs b/src/shell/bash.rs index f833b17bb..3e87ec826 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -2,7 +2,7 @@ use std::path::Path; use indoc::formatdoc; -use crate::shell::{is_dir_in_path, Shell}; +use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] pub struct Bash {} @@ -12,7 +12,7 @@ impl Shell for Bash { let dir = exe.parent().unwrap(); let status = if status { " --status" } else { "" }; let mut out = String::new(); - if !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" @@ -84,6 +84,13 @@ mod tests { assert_snapshot!(bash.activate(exe, true)); } + #[test] + fn test_hook_init_nix() { + let bash = Bash::default(); + let exe = Path::new("/nix/store/rtx"); + assert_snapshot!(bash.activate(exe, true)); + } + #[test] fn test_set_env() { assert_snapshot!(Bash::default().set_env("FOO", "1")); diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 68ed58e6c..61db98f65 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -2,7 +2,7 @@ use std::path::Path; use indoc::formatdoc; -use crate::shell::{is_dir_in_path, Shell}; +use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] pub struct Fish {} @@ -14,7 +14,7 @@ impl Shell for Fish { let description = "'Update rtx environment when changing directories'"; let mut out = String::new(); - if !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { out.push_str(&format!("fish_add_path -g {dir}\n", dir = dir.display())); } @@ -103,6 +103,13 @@ mod tests { assert_snapshot!(fish.activate(exe, true)); } + #[test] + fn test_hook_init_nix() { + let fish = Fish::default(); + let exe = Path::new("/nix/store/rtx"); + assert_snapshot!(fish.activate(exe, true)); + } + #[test] fn test_set_env() { assert_snapshot!(Fish::default().set_env("FOO", "1")); diff --git a/src/shell/mod.rs b/src/shell/mod.rs index d709963e5..861a639c3 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -74,3 +74,9 @@ pub fn is_dir_in_path(dir: &Path) -> bool { .into_iter() .any(|p| p.canonicalize().unwrap_or(p) == dir) } + +pub fn is_dir_not_in_nix(dir: &Path) -> bool { + !dir.canonicalize() + .unwrap_or(dir.to_path_buf()) + .starts_with("/nix/") +} diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 5c318456f..f3d6ac234 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, path::Path}; use indoc::formatdoc; -use crate::shell::{is_dir_in_path, Shell}; +use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] pub struct Nushell {} @@ -29,7 +29,7 @@ impl Shell for Nushell { let status = if status { " --status" } else { "" }; let mut out = String::new(); - if !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { out.push_str(&format!( "let-env PATH = ($env.PATH | prepend '{}')\n", // TODO: set PATH as Path on windows dir.display() @@ -127,6 +127,13 @@ mod tests { assert_snapshot!(nushell.activate(exe, true)); } + #[test] + fn test_hook_init_nix() { + let nushell = Nushell::default(); + let exe = Path::new("/nix/store/rtx"); + assert_snapshot!(nushell.activate(exe, true)); + } + #[test] fn test_set_env() { assert_snapshot!(Nushell::default().set_env("FOO", "1")); diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap new file mode 100644 index 000000000..1bbef6267 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -0,0 +1,34 @@ +--- +source: src/shell/bash.rs +expression: "bash.activate(exe, true)" +--- +export RTX_SHELL=bash + +rtx() { + local command + command="${1:-}" + if [ "$#" = 0 ]; then + command rtx + return + fi + shift + + case "$command" in + deactivate|shell) + eval "$(command rtx "$command" "$@")" + ;; + *) + command rtx "$command" "$@" + ;; + esac +} + +_rtx_hook() { + local previous_exit_status=$?; + eval "$(rtx hook-env --status -s bash)"; + return $previous_exit_status; +}; +if ! [[ "${PROMPT_COMMAND:-}" =~ _rtx_hook ]]; then + PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" +fi + diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap new file mode 100644 index 000000000..82f674438 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap @@ -0,0 +1,47 @@ +--- +source: src/shell/fish.rs +expression: "fish.activate(exe, true)" +--- +set -gx RTX_SHELL fish + +function rtx + if test (count $argv) -eq 0 + command rtx + return + end + + set command $argv[1] + set -e argv[1] + + switch "$command" + case deactivate shell + source (command rtx "$command" $argv|psub) + case '*' + command rtx "$command" $argv + end +end + +function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; + rtx hook-env --status -s fish | source; + + if test "$rtx_fish_mode" != "disable_arrow"; + function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; + if test "$rtx_fish_mode" = "eval_after_arrow"; + set -g __rtx_env_again 0; + else; + rtx hook-env --status -s fish | source; + end; + end; + end; +end; + +function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; + if set -q __rtx_env_again; + set -e __rtx_env_again; + rtx hook-env --status -s fish | source; + echo; + end; + + functions --erase __rtx_cd_hook; +end; + diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap new file mode 100644 index 000000000..5cc7721bd --- /dev/null +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap @@ -0,0 +1,59 @@ +--- +source: src/shell/nushell.rs +assertion_line: 134 +expression: "nushell.activate(exe, true)" +--- +export-env { + let-env RTX_SHELL = "nu" + + let-env config = ($env.config | upsert hooks { + pre_prompt: [{ + condition: {|| "RTX_SHELL" in $env } + code: {|| rtx_hook } + }] + env_change: { + PWD: [{ + condition: {|| "RTX_SHELL" in $env } + code: {|| rtx_hook } + }] + } + }) +} + +def "parse vars" [] { + $in | lines | parse "{op},{name},{value}" +} + +def-env rtx [command?: string, --help, ...rest: string] { + let commands = ["shell", "deactivate"] + + if ($command == null) { + ^"/nix/store/rtx" + } else if ($command == "activate") { + let-env RTX_SHELL = "nu" + } else if ($command in $commands) { + ^"/nix/store/rtx" $command $rest + | parse vars + | update-env + } else { + ^"/nix/store/rtx" $command $rest + } +} + +def-env "update-env" [] { + for $var in $in { + if $var.op == "set" { + let-env $var.name = $"($var.value)" + } else if $var.op == "hide" { + hide-env $var.name + } + } +} + +def-env rtx_hook [] { + ^"/nix/store/rtx" hook-env --status -s nu + | parse vars + | update-env +} + + diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap new file mode 100644 index 000000000..e8daa9b3c --- /dev/null +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap @@ -0,0 +1,12 @@ +--- +source: src/shell/xonsh.rs +expression: "xonsh.activate(exe, true)" +--- +from os import environ +from xonsh.built_ins import XSH + +def listen_prompt(): # Hook Events + execx($(/nix/store/rtx hook-env --status -s xonsh)) + +XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt + diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap new file mode 100644 index 000000000..891bf6245 --- /dev/null +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -0,0 +1,37 @@ +--- +source: src/shell/zsh.rs +expression: "zsh.activate(exe, true)" +--- +export RTX_SHELL=zsh + +rtx() { + local command + command="${1:-}" + if [ "$#" = 0 ]; then + command rtx + return + fi + shift + + case "$command" in + deactivate|shell) + eval "$(command rtx "$command" "$@")" + ;; + *) + command rtx "$command" "$@" + ;; + esac +} + +_rtx_hook() { + eval "$(rtx hook-env --status -s zsh)"; +} +typeset -ag precmd_functions; +if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then + precmd_functions=( _rtx_hook ${precmd_functions[@]} ) +fi +typeset -ag chpwd_functions; +if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then + chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) +fi + diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index cc0ce7a4c..9d3bb8dae 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -2,7 +2,7 @@ use std::path::Path; use indoc::formatdoc; -use crate::shell::{is_dir_in_path, Shell}; +use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] pub struct Xonsh {} @@ -53,7 +53,7 @@ impl Shell for Xonsh { from xonsh.built_ins import XSH "#}); - if !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { let dir_str = dir.to_string_lossy(); let dir_esc = xonsh_escape_sq(&dir_str); out.push_str(&formatdoc! {r#" @@ -136,6 +136,13 @@ mod tests { insta::assert_snapshot!(xonsh.activate(exe, true)); } + #[test] + fn test_hook_init_nix() { + let xonsh = Xonsh::default(); + let exe = Path::new("/nix/store/rtx"); + insta::assert_snapshot!(xonsh.activate(exe, true)); + } + #[test] fn test_set_env() { insta::assert_snapshot!(Xonsh::default().set_env("FOO", "1")); diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 86931ea05..163558499 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -3,7 +3,7 @@ use std::path::Path; use indoc::formatdoc; use crate::shell::bash::Bash; -use crate::shell::{is_dir_in_path, Shell}; +use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] pub struct Zsh {} @@ -16,7 +16,7 @@ impl Shell for Zsh { // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_zsh.go#L10-L22 - if !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" @@ -89,6 +89,13 @@ mod tests { assert_snapshot!(zsh.activate(exe, true)); } + #[test] + fn test_hook_init_nix() { + let zsh = Zsh::default(); + let exe = Path::new("/nix/store/rtx"); + assert_snapshot!(zsh.activate(exe, true)); + } + #[test] fn test_set_env() { assert_snapshot!(Zsh::default().set_env("FOO", "1")); From 0145de95154c3e4e8bf978e3a70eba565ac8acdb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 13 Jul 2023 13:52:46 -0500 Subject: [PATCH 0860/1891] typo --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 7cee09cd1..e57b88337 100644 --- a/README.md +++ b/README.md @@ -1002,8 +1002,7 @@ ln -s ~/src/rtx-my-tool ~/.local/share/rtx/plugins/my-tool #### `~/.local/share/rtx/installs` This is where tools are installed to when running `rtx install`. For example, `rtx install -node@20.0.0` will install to `~/.local/share/rtx/installs/node/20.0.0` For example, `rtx -install 0.0` will install to `~/.local/share/rtx/installs/node/20.0.0`. +node@20.0.0` will install to `~/.local/share/rtx/installs/node/20.0.0` This will also create other symlinks to this directory for version prefixes ("20" and "20.15") and matching aliases ("lts", "latest"). From 2be8c64f32c3a6ed2eb400f427930a380f6f69b4 Mon Sep 17 00:00:00 2001 From: fang duan Date: Fri, 14 Jul 2023 23:06:36 +0800 Subject: [PATCH 0861/1891] feat: add envs for rtx go core plugin (#679) * feat: add envs for rtx go core plugin https://github.com/jdxcode/rtx/discussions/677 * fix * fix * Update src/plugins/core/go.rs Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> * Update src/plugins/core/go.rs Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> * cargo fmt --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- src/env.rs | 6 ++++++ src/plugins/core/go.rs | 12 +++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/env.rs b/src/env.rs index e229e70f7..d558ec76d 100644 --- a/src/env.rs +++ b/src/env.rs @@ -162,10 +162,16 @@ pub static RTX_RUBY_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_RUBY_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-gems")) }); +// go pub static RTX_GO_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_GO_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-go-packages")) }); pub static RTX_GO_SKIP_CHECKSUM: Lazy = Lazy::new(|| var_is_true("RTX_GO_SKIP_CHECKSUM")); +pub static RTX_GO_REPO: Lazy = + Lazy::new(|| var("RTX_GO_REPO").unwrap_or_else(|_| "https://github.com/golang/go".into())); +pub static RTX_GO_DOWNLOAD_MIRROR: Lazy = Lazy::new(|| { + var("RTX_GO_DOWNLOAD_MIRROR").unwrap_or_else(|_| "https://dl.google.com/go".into()) +}); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index c9f906536..30b38687f 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -29,14 +29,8 @@ impl GoPlugin { fn fetch_remote_versions(&self) -> Result> { CorePlugin::run_fetch_task_with_timeout(move || { - let output = cmd!( - "git", - "ls-remote", - "--tags", - "https://github.com/golang/go", - "go*" - ) - .read()?; + let repo = &*env::RTX_GO_REPO; + let output = cmd!("git", "ls-remote", "--tags", repo, "go*").read()?; let lines = output.split('\n'); let versions = lines.map(|s| s.split("/go").last().unwrap_or_default().to_string()) .filter(|s| !s.is_empty()) @@ -97,7 +91,7 @@ impl GoPlugin { fn download(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result { let http = http::Client::new()?; let filename = format!("go{}.{}-{}.tar.gz", tv.version, platform(), arch()); - let tarball_url = format!("https://dl.google.com/go/{}", &filename); + let tarball_url = format!("{}/{}", &*env::RTX_GO_DOWNLOAD_MIRROR, &filename); let tarball_path = tv.download_path().join(filename); pr.set_message(format!("downloading {}", &tarball_url)); From 57a73404c26c81cadcac3ffce233863cb6c859f5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 14 Jul 2023 10:07:45 -0500 Subject: [PATCH 0862/1891] skip parsing gemfile when not parseable (#684) Fixes #683 --- src/plugins/core/ruby.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 3c0b10827..d6a326186 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -399,9 +399,14 @@ fn parse_gemfile(body: &str) -> String { .replace_all(&v, "$1") .to_string(); let v = regex!(r#"^[^0-9]"#).replace_all(&v, "").to_string(); - regex!(r#"(.*)__ENGINE__(.*)"#) + let v = regex!(r#"(.*)__ENGINE__(.*)"#) .replace_all(&v, "$2-$1") - .to_string() + .to_string(); + // make sure it's like "ruby-3.0.0" or "3.0.0" + if !regex!(r#"^(\w+-)?([0-9])(\.[0-9])*$"#).is_match(&v) { + return "".to_string(); + } + v } #[cfg(test)] @@ -436,5 +441,12 @@ mod tests { "#}), "jruby-1.6.7" ); + assert_eq!( + parse_gemfile(indoc! {r#" + source "https://rubygems.org" + ruby File.read(File.expand_path(".ruby-version", __dir__)).strip + "#}), + "" + ); } } From 53454c8f67c6c458777b2b5b40e42bc85039168c Mon Sep 17 00:00:00 2001 From: fang duan Date: Fri, 14 Jul 2023 23:45:48 +0800 Subject: [PATCH 0863/1891] add envs for rtx ruby core plugin (#682) --- src/env.rs | 8 ++++++++ src/plugins/core/ruby.rs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/env.rs b/src/env.rs index d558ec76d..26dc353b7 100644 --- a/src/env.rs +++ b/src/env.rs @@ -149,6 +149,14 @@ pub static NVM_DIR: Lazy = pub static NODENV_ROOT: Lazy = Lazy::new(|| var_path("NODENV_ROOT").unwrap_or_else(|| HOME.join(".nodenv"))); +// ruby +pub static RTX_RUBY_BUILD_REPO: Lazy = Lazy::new(|| { + var("RTX_RUBY_BUILD_REPO").unwrap_or_else(|_| "https://github.com/rbenv/ruby-build.git".into()) +}); +pub static RTX_RUBY_INSTALL_REPO: Lazy = Lazy::new(|| { + var("RTX_RUBY_INSTALL_REPO") + .unwrap_or_else(|_| "https://github.com/postmodern/ruby-install.git".into()) +}); pub static RTX_RUBY_INSTALL: Lazy = Lazy::new(|| var_is_true("RTX_RUBY_INSTALL")); pub static RTX_RUBY_APPLY_PATCHES: Lazy> = Lazy::new(|| var("RTX_RUBY_APPLY_PATCHES").ok()); diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index d6a326186..2e6302c94 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -74,7 +74,7 @@ impl RubyPlugin { file::remove_all(&tmp)?; file::create_dir_all(tmp.parent().unwrap())?; let git = Git::new(tmp.clone()); - git.clone("https://github.com/rbenv/ruby-build.git")?; + git.clone(&env::RTX_RUBY_BUILD_REPO)?; cmd!("sh", "install.sh") .env("PREFIX", self.ruby_build_path()) @@ -108,7 +108,7 @@ impl RubyPlugin { file::remove_all(&tmp)?; file::create_dir_all(tmp.parent().unwrap())?; let git = Git::new(tmp.clone()); - git.clone("https://github.com/postmodern/ruby-install")?; + git.clone(&env::RTX_RUBY_INSTALL_REPO)?; cmd!("make", "install") .env("PREFIX", self.ruby_install_path()) From 013712869a8b9815ec8c02ccc7936565a9264cb5 Mon Sep 17 00:00:00 2001 From: fang duan Date: Fri, 14 Jul 2023 23:46:05 +0800 Subject: [PATCH 0864/1891] add envs for rtx python core plugin (#681) --- src/env.rs | 3 +++ src/plugins/core/python.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/env.rs b/src/env.rs index 26dc353b7..045d99bd1 100644 --- a/src/env.rs +++ b/src/env.rs @@ -108,6 +108,9 @@ pub static RTX_ALWAYS_KEEP_INSTALL: Lazy = pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); // python +pub static RTX_PYENV_REPO: Lazy = Lazy::new(|| { + var("RTX_PYENV_REPO").unwrap_or_else(|_| "https://github.com/pyenv/pyenv.git".into()) +}); pub static RTX_PYTHON_PATCH_URL: Lazy> = Lazy::new(|| var("RTX_PYTHON_PATCH_URL").ok()); pub static RTX_PYTHON_PATCHES_DIRECTORY: Lazy> = diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 86f67381a..9b5114233 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -50,7 +50,7 @@ impl PythonPlugin { ); create_dir_all(self.python_build_path().parent().unwrap())?; let git = Git::new(self.python_build_path()); - git.clone("https://github.com/pyenv/pyenv.git")?; + git.clone(&env::RTX_PYENV_REPO)?; Ok(()) } fn update_python_build(&self) -> Result<()> { From db5b02d50cb9469e29f23f04baf4393cdc92ed78 Mon Sep 17 00:00:00 2001 From: fang duan Date: Fri, 14 Jul 2023 23:50:59 +0800 Subject: [PATCH 0865/1891] add envs for rtx node core plugin (#680) --- docs/node.md | 1 + src/env.rs | 3 +++ src/plugins/core/node.rs | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/node.md b/docs/node.md index 63030c2b4..ad0d4f08c 100644 --- a/docs/node.md +++ b/docs/node.md @@ -23,6 +23,7 @@ Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) `node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-node` has a few extra configuration variables: +- `RTX_NODE_BUILD_REPO` [string]: the default is `https://github.com/nodenv/node-build.git` - `RTX_NODE_VERBOSE_INSTALL` [bool]: Enables verbose output for downloading and building. - `RTX_NODE_FORCE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries - `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores diff --git a/src/env.rs b/src/env.rs index 045d99bd1..8758fb08a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -123,6 +123,9 @@ pub static PYENV_ROOT: Lazy = Lazy::new(|| var_path("PYENV_ROOT").unwrap_or_else(|| HOME.join(".pyenv"))); // node +pub static RTX_NODE_BUILD_REPO: Lazy = Lazy::new(|| { + var("RTX_NODE_BUILD_REPO").unwrap_or_else(|_| "https://github.com/nodenv/node-build.git".into()) +}); pub static RTX_NODE_CONCURRENCY: Lazy = Lazy::new(|| { var("RTX_NODE_CONCURRENCY") .ok() diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 2cc67700f..fa0100125 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -63,7 +63,7 @@ impl NodePlugin { ); create_dir_all(self.node_build_path().parent().unwrap())?; let git = Git::new(self.node_build_path()); - git.clone("https://github.com/nodenv/node-build.git")?; + git.clone(&env::RTX_NODE_BUILD_REPO)?; Ok(()) } fn update_node_build(&self) -> Result<()> { From 93a3bec3be8ad0439ec3e70bdb0f26badbd9e300 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 14 Jul 2023 12:44:44 -0500 Subject: [PATCH 0866/1891] use latest versions for `rtx use` (#688) This makes it so if you run `rtx use node@20` that will use the latest version of node@20, not the latest installed version. --- src/cli/local.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli/local.rs b/src/cli/local.rs index 03cb3ee49..91c498b14 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -141,6 +141,7 @@ pub fn local( fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result<()> { let mut ts = cf.to_toolset().clone(); + ts.latest_versions = true; ts.resolve(config); if !ts.list_missing_versions(config).is_empty() { let mpr = MultiProgressReport::new(config.show_progress_bars()); From 76f8de3f51baeb3062a3bb5c6f0846278398336c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 14 Jul 2023 12:54:42 -0500 Subject: [PATCH 0867/1891] chore: Release --- Cargo.lock | 79 +++++++++++++++++++----------------------- Cargo.toml | 2 +- README.md | 4 +-- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 42 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f55360074..309d46640 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - [[package]] name = "aho-corasick" version = "1.0.2" @@ -227,9 +218,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.11" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" +checksum = "3eab9e8ceb9afdade1ab3f0fd8dbce5b1b2f468ad653baf10e771781b2b67b73" dependencies = [ "clap_builder", "clap_derive", @@ -238,9 +229,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.11" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" +checksum = "9f2763db829349bf00cfc06251268865ed4363b93a943174f638daf3ecdba2cd" dependencies = [ "anstream", "anstyle", @@ -259,9 +250,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck", "proc-macro2", @@ -431,9 +422,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed5fff0d93c7559121e9c72bf9c242295869396255071ff2cb1617147b608c5" +checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", "syn 2.0.25", @@ -539,9 +530,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" @@ -753,11 +744,11 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick", "bstr", "fnv", "log", @@ -1039,7 +1030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.3", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -1373,9 +1364,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" +checksum = "d220334a184db82b31b83f5ff093e3315280fb2b6bbc032022b2304a509aab7a" [[package]] name = "pretty_assertions" @@ -1471,7 +1462,7 @@ version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", "regex-automata", "regex-syntax", @@ -1479,20 +1470,20 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" @@ -1578,7 +1569,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.34.0" +version = "1.34.1" dependencies = [ "base64", "built", @@ -1654,9 +1645,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.3" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ "bitflags 2.3.3", "errno 0.3.1", @@ -1667,9 +1658,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.3" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19faa85ecb5197342b54f987b142fb3e30d0c90da40f80ef4fa9a726e6676ed" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" dependencies = [ "log", "ring", @@ -1776,9 +1767,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" dependencies = [ "itoa", "ryu", @@ -1926,9 +1917,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" dependencies = [ "filetime", "libc", @@ -2122,9 +2113,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.12" +version = "0.19.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +checksum = "5f8751d9c1b03c6500c387e96f81f815a4f8e72d142d2d4a9ffa6fedd51ddee7" dependencies = [ "indexmap 2.0.0", "serde", @@ -2633,9 +2624,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.9" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 3dfad5194..6d060aa1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.34.0" +version = "1.34.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e57b88337..ee94d32fd 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.34.0 +rtx 1.34.1 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -326,7 +326,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.34.0/rtx-v1.34.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.34.1/rtx-v1.34.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 8e7379f0f..d7ceaa539 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.34.0"; + version = "1.34.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index e4ebfec78..d41ac9be6 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.34.0" +.TH rtx 1 "rtx 1.34.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.34.0 +v1.34.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 45f8c4c9f..6de6fa303 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.34.0 +Version: 1.34.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 62806f3089fcbd7382b5c64b35ba418813605b45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jul 2023 22:03:22 -0500 Subject: [PATCH 0868/1891] chore(deps): bump indoc from 2.0.2 to 2.0.3 (#697) Bumps [indoc](https://github.com/dtolnay/indoc) from 2.0.2 to 2.0.3. - [Release notes](https://github.com/dtolnay/indoc/releases) - [Commits](https://github.com/dtolnay/indoc/compare/2.0.2...2.0.3) --- updated-dependencies: - dependency-name: indoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 309d46640..e977fe9cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -980,9 +980,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "761cde40c27e2a9877f8c928fd248b7eec9dd48623dd514b256858ca593fbba7" +checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4" [[package]] name = "insta" From 18996e5c88cee2f6bf81faf2ea37a5720ec36142 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jul 2023 22:03:30 -0500 Subject: [PATCH 0869/1891] chore(deps): bump toml_edit from 0.19.13 to 0.19.14 (#696) Bumps [toml_edit](https://github.com/toml-rs/toml) from 0.19.13 to 0.19.14. - [Commits](https://github.com/toml-rs/toml/compare/v0.19.13...v0.19.14) --- updated-dependencies: - dependency-name: toml_edit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e977fe9cf..e9f949186 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2113,9 +2113,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.13" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f8751d9c1b03c6500c387e96f81f815a4f8e72d142d2d4a9ffa6fedd51ddee7" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap 2.0.0", "serde", From 2991bc7789fc55caee217b528477afc2619bd014 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jul 2023 22:03:57 -0500 Subject: [PATCH 0870/1891] chore(deps): bump insta from 1.30.0 to 1.31.0 (#695) Bumps [insta](https://github.com/mitsuhiko/insta) from 1.30.0 to 1.31.0. - [Changelog](https://github.com/mitsuhiko/insta/blob/master/CHANGELOG.md) - [Commits](https://github.com/mitsuhiko/insta/compare/1.30.0...1.31.0) --- updated-dependencies: - dependency-name: insta dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9f949186..1ed4942c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -986,9 +986,9 @@ checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4" [[package]] name = "insta" -version = "1.30.0" +version = "1.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28491f7753051e5704d4d0ae7860d45fae3238d7d235bc4289dcd45c48d3cec3" +checksum = "a0770b0a3d4c70567f0d58331f3088b0e4c4f56c9b8d764efe654b4a5d46de3a" dependencies = [ "console", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 6d060aa1c..47a7776ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,7 +95,7 @@ built = { version = "0.6.1", features = ["chrono", "git2"] } [dev-dependencies] ctor = "<0.3" -insta = "1.30.0" +insta = "1.31.0" pretty_assertions = "1.3.0" [features] From 8c7c4e929ff3e209ca6b8139ad83667e509c1659 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jul 2023 22:04:05 -0500 Subject: [PATCH 0871/1891] chore(deps): bump serde_json from 1.0.102 to 1.0.103 (#694) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.102 to 1.0.103. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.102...v1.0.103) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ed4942c0..220df36f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1767,9 +1767,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 47a7776ab..ce0f20f22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,7 +73,7 @@ self_update = { version = "0.37.0", default-features = false, optional = true, f ] } serde = "1.0.164" serde_derive = "1.0.152" -serde_json = "1.0.99" +serde_json = "1.0.103" sha2 = "0.10.7" shell-escape = "0.1.4" shell-words = "1.1.0" From 72a8077f22e50ee6f34ed828c30e3f994fc10904 Mon Sep 17 00:00:00 2001 From: Alec Rust Date: Mon, 17 Jul 2023 04:23:09 +0100 Subject: [PATCH 0872/1891] Update ruby.md (#693) Change the remote version list fetching command to be for Ruby, which is more appropriate for the docs of this plugin. This list Ruby versions command actually fails (for me at least) see #692. --- docs/ruby.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ruby.md b/docs/ruby.md index 723613c67..a10aeb8af 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -67,5 +67,5 @@ update: ```bash rtx cache clean -rtx ls-remote node +rtx ls-remote ruby ``` From 833125318f90be99d17003dbf5c25b374333d813 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 18 Jul 2023 18:02:19 -0500 Subject: [PATCH 0873/1891] clippy fixes --- src/cli/args/tool.rs | 2 +- src/env.rs | 2 +- src/plugins/core/go.rs | 2 +- src/plugins/core/ruby.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index 2c8f32439..87c4a05bb 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -44,7 +44,7 @@ impl ToolArg { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let a = tools[0].clone(); let b = tools[1].clone(); - if matches!(a.tvr, None) && matches!(b.tvr, None) && re.is_match(&b.plugin) { + if a.tvr.is_none() && b.tvr.is_none() && re.is_match(&b.plugin) { tools[1].tvr = Some(ToolVersionRequest::new(a.plugin.clone(), &b.plugin)); tools[1].plugin = a.plugin; tools.remove(0); diff --git a/src/env.rs b/src/env.rs index 8758fb08a..3aa81fd9b 100644 --- a/src/env.rs +++ b/src/env.rs @@ -310,7 +310,7 @@ fn apply_patches( /// returns true if new runtime versions should not be fetched fn prefer_stale(args: &[String]) -> bool { if let Some(c) = args.get(1) { - return vec![ + return [ "env", "hook-env", "x", "exec", "direnv", "activate", "current", "ls", "where", ] .contains(&c.as_str()); diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 30b38687f..0a8f6213d 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -34,7 +34,7 @@ impl GoPlugin { let lines = output.split('\n'); let versions = lines.map(|s| s.split("/go").last().unwrap_or_default().to_string()) .filter(|s| !s.is_empty()) - .filter(|s| !regex!(r#"^1($|\.0|\.0\.[0-9]|\.1|\.1rc[0-9]|\.1\.[0-9]|.2|\.2rc[0-9]|\.2\.1|.8.5rc5)$"#).is_match(s)) + .filter(|s| !regex!(r"^1($|\.0|\.0\.[0-9]|\.1|\.1rc[0-9]|\.1\.[0-9]|.2|\.2rc[0-9]|\.2\.1|.8.5rc5)$").is_match(s)) .unique() .sorted_by_cached_key(|s| Versioning::new(s)) .collect(); diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 2e6302c94..6aecca77b 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -403,7 +403,7 @@ fn parse_gemfile(body: &str) -> String { .replace_all(&v, "$2-$1") .to_string(); // make sure it's like "ruby-3.0.0" or "3.0.0" - if !regex!(r#"^(\w+-)?([0-9])(\.[0-9])*$"#).is_match(&v) { + if !regex!(r"^(\w+-)?([0-9])(\.[0-9])*$").is_match(&v) { return "".to_string(); } v From 9d1c137a00aa90011d0dddd02dff045966b4b9d3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 18 Jul 2023 18:02:37 -0500 Subject: [PATCH 0874/1891] added python config docs --- docs/python.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/python.md b/docs/python.md index 6a1c7984b..0b4e88c2f 100644 --- a/docs/python.md +++ b/docs/python.md @@ -26,6 +26,16 @@ $ python3.11 -V 3.11.0 ``` +## Configuration + +`python-build` already has a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in +additional to that `rtx-node` has a few extra configuration variables: + +- `RTX_PYENV_REPO` [string]: the default is `https://github.com/pyenv/pyenv.git` +- `RTX_PYTHON_PATCH_URL` [string]: A url to a patch file to pass to python-build. +- `RTX_PYTHON_PATCHES_DIRECTORY` [string]: A local directory containing patch files to pass to python-build. +- `RTX_PYTHON_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-python-packages` + ## Default Python packages rtx-python can automatically install a default set of Python packages with pip right after installing a Python version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists one package per line, for example: From 62b4cd1982e61cebdd1a251859582d1c00b4f481 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 19 Jul 2023 11:49:33 -0500 Subject: [PATCH 0875/1891] save unaliased name back to .tool-versions (#699) See https://github.com/jdxcode/rtx/pull/664#issuecomment-1639576230 --- src/config/config_file/tool_versions.rs | 22 +++++++++++++++------- src/env_diff.rs | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 186cbf409..f543cdbb7 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -4,7 +4,6 @@ use std::fs; use std::fs::read_to_string; use std::path::{Path, PathBuf}; -use crate::config::AliasMap; use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; use indexmap::IndexMap; @@ -13,6 +12,7 @@ use tera::Context; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; +use crate::config::AliasMap; use crate::file::display_path; use crate::plugins::{unalias_plugin, PluginName}; use crate::tera::{get_tera, BASE_CONTEXT}; @@ -33,8 +33,9 @@ pub struct ToolVersions { is_trusted: bool, } -#[derive(Debug, Default)] +#[derive(Debug)] struct ToolVersionPlugin { + orig_name: String, versions: Vec, post: String, } @@ -79,7 +80,13 @@ impl ToolVersions { } fn get_or_create_plugin(&mut self, plugin: &str) -> &mut ToolVersionPlugin { - self.plugins.entry(plugin.to_string()).or_default() + self.plugins + .entry(plugin.to_string()) + .or_insert_with(|| ToolVersionPlugin { + orig_name: plugin.to_string(), + versions: vec![], + post: "".into(), + }) } fn parse_plugins(input: &str) -> Result> { @@ -98,9 +105,11 @@ 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 = unalias_plugin(plugin.trim_end_matches(':')); + let orig_plugin = plugin.trim_end_matches(':'); + let plugin = unalias_plugin(orig_plugin); let tvp = ToolVersionPlugin { + orig_name: orig_plugin.to_string(), versions: parts.map(|v| v.to_string()).collect(), post: match post { "" => String::from("\n"), @@ -191,8 +200,8 @@ impl ConfigFile for ToolVersions { .map(|p| measure_text_width(p)) .max() .unwrap_or_default(); - for (plugin, tv) in &self.plugins { - let plugin = pad_str(plugin, max_plugin_len, Alignment::Left, None); + for (_, tv) in &self.plugins { + let plugin = pad_str(&tv.orig_name, max_plugin_len, Alignment::Left, None); s.push_str(&format!("{} {}{}", plugin, tv.versions.join(" "), tv.post)); } @@ -218,7 +227,6 @@ impl ConfigFile for ToolVersions { #[cfg(test)] pub(crate) mod tests { - use indoc::indoc; use insta::{assert_display_snapshot, assert_snapshot}; use pretty_assertions::assert_eq; diff --git a/src/env_diff.rs b/src/env_diff.rs index a1bac7a43..9196348de 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -360,6 +360,6 @@ mod tests { let input = r#""\g\""#; let output = normalize_escape_sequences(input); // just warns - assert_str_eq!(output, r#"\g"#); + assert_str_eq!(output, r"\g"); } } From 4eca260b1ae95177996c97d5cfd6afb0e6d42bb0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 21 Jul 2023 10:12:42 -0500 Subject: [PATCH 0876/1891] clarify activate instructions a bit (#704) --- README.md | 9 +++++++++ packaging/standalone/install.envsubst | 18 ++++++++++++------ src/cli/activate.rs | 9 +++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ee94d32fd..476ea2b18 100644 --- a/README.md +++ b/README.md @@ -1525,6 +1525,15 @@ This is only intended to be used in interactive sessions, not scripts. rtx is only capable of updating PATH when the prompt is displayed to the user. For non-interactive use-cases, use shims instead. +Typically this can be added with something like the following: + + echo 'eval "$(rtx activate)"' >> ~/.zshrc + +However, this requires that "rtx" is in your PATH. If it is not, you need to +specify the full path like this: + + echo 'eval "$(/path/to/rtx activate)"' >> ~/.zshrc + Usage: activate [OPTIONS] [SHELL_TYPE] Arguments: diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index c8cde080c..fd65b0017 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -137,16 +137,22 @@ install_rtx() { after_finish_help() { case "${SHELL:-}" in */zsh) - info "rtx: run the following get started:" - info "echo -e \"\\\neval \\\"\\\$($install_path activate -s zsh)\\\"\" >> ~/.zshrc" + info "rtx: run the following to activate rtx in your shell:" + info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> ~/.zshrc\n" + info "rtx: this must be run in order to use rtx in the terminal" + info "rtx: run \`rtx doctor\` to verify this is setup correctly" ;; */bash) - info "rtx: run the following get started:" - info "echo -e \"\\\neval \\\"\\\$($install_path activate -s bash)\\\"\" >> ~/.bashrc" + info "rtx: run the following to activate rtx in your shell:" + info "echo \"eval \\\"\\\$($install_path activate bash)\\\"\" >> ~/.bashrc\n" + info "rtx: this must be run in order to use rtx in the terminal" + info "rtx: run \`rtx doctor\` to verify this is setup correctly" ;; */fish) - info "rtx: run the following get started:" - info "echo -e \"\\\n$install_path activate -s fish | source\" >> ~/.config/fish/config.fish" + info "rtx: run the following to activate rtx in your shell:" + info "echo \"$install_path activate fish | source\" >> ~/.config/fish/config.fish\n" + info "rtx: this must be run in order to use rtx in the terminal" + info "rtx: run \`rtx doctor\` to verify this is setup correctly" ;; *) info "rtx: run \`$install_path --help\` to get started" diff --git a/src/cli/activate.rs b/src/cli/activate.rs index ebf814e64..2c075d057 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -18,6 +18,15 @@ use crate::shell::{get_shell, ShellType}; /// This is only intended to be used in interactive sessions, not scripts. /// rtx is only capable of updating PATH when the prompt is displayed to the user. /// For non-interactive use-cases, use shims instead. +/// +/// Typically this can be added with something like the following: +/// +/// echo 'eval "$(rtx activate)"' >> ~/.zshrc +/// +/// However, this requires that "rtx" is in your PATH. If it is not, you need to +/// specify the full path like this: +/// +/// echo 'eval "$(/path/to/rtx activate)"' >> ~/.zshrc #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Activate { From c4f0c0483f99e4c8a1ac159af614043bd327a70f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 01:37:31 +0000 Subject: [PATCH 0877/1891] chore(deps): bump serde from 1.0.171 to 1.0.174 (#707) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.171 to 1.0.174. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.171...v1.0.174) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 220df36f4..8caca0b49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1747,18 +1747,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.171" +version = "1.0.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "3b88756493a5bd5e5395d53baa70b194b05764ab85b59e43e4b8f4e1192fa9b1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "6e5c3a298c7f978e53536f95a63bdc4c4a64550582f31a0359a9afda6aede62e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index ce0f20f22..62e5591d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ rmp-serde = "1.1.1" self_update = { version = "0.37.0", default-features = false, optional = true, features = [ "rustls", ] } -serde = "1.0.164" +serde = "1.0.174" serde_derive = "1.0.152" serde_json = "1.0.103" sha2 = "0.10.7" From cdd2f532f744fb615b38421ed5d091c8aa88bcd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 01:37:42 +0000 Subject: [PATCH 0878/1891] chore(deps): bump rmp-serde from 1.1.1 to 1.1.2 (#708) Bumps [rmp-serde](https://github.com/3Hren/msgpack-rust) from 1.1.1 to 1.1.2. - [Release notes](https://github.com/3Hren/msgpack-rust/releases) - [Commits](https://github.com/3Hren/msgpack-rust/commits) --- updated-dependencies: - dependency-name: rmp-serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8caca0b49..358556d95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1552,9 +1552,9 @@ dependencies = [ [[package]] name = "rmp-serde" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" dependencies = [ "byteorder", "rmp", diff --git a/Cargo.toml b/Cargo.toml index 62e5591d3..e52fdb387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ reqwest = { version = "0.11.17", default-features = false, features = [ "rustls-tls", "json", ] } -rmp-serde = "1.1.1" +rmp-serde = "1.1.2" self_update = { version = "0.37.0", default-features = false, optional = true, features = [ "rustls", ] } From 85505bc8c82ccc603e045d21d53b511bddd0eca4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 01:42:04 +0000 Subject: [PATCH 0879/1891] chore(deps): bump thiserror from 1.0.43 to 1.0.44 (#706) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.43 to 1.0.44. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.43...1.0.44) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 358556d95..f25ce43ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1978,18 +1978,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index e52fdb387..f7d26e3dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ simplelog = { version = "0.12.0" } tar = "0.4.38" tera = { version = "1.12.1", default-features = false } terminal_size = "0.2.1" -thiserror = "1.0.38" +thiserror = "1.0.44" toml = "<0.8" toml_edit = "<0.20" url = "2.4.0" From 3160c838c0e262fdc040dec8a81ef200252c9cdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 01:42:53 +0000 Subject: [PATCH 0880/1891] chore(deps): bump clap from 4.3.12 to 4.3.19 (#705) Bumps [clap](https://github.com/clap-rs/clap) from 4.3.12 to 4.3.19. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.3.12...v4.3.19) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f25ce43ac..92bf0a5e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.12" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eab9e8ceb9afdade1ab3f0fd8dbce5b1b2f468ad653baf10e771781b2b67b73" +checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" dependencies = [ "clap_builder", "clap_derive", @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.12" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2763db829349bf00cfc06251268865ed4363b93a943174f638daf3ecdba2cd" +checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ "anstream", "anstyle", diff --git a/Cargo.toml b/Cargo.toml index f7d26e3dc..9820e2890 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ path = "src/main.rs" [dependencies] base64 = "<0.22" chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } -clap = { version = "4.3.4", features = ["env", "derive", "string"] } +clap = { version = "4.3.19", features = ["env", "derive", "string"] } clap_complete = "4.2.3" color-eyre = "0.6.2" color-print = "0.3.4" From 51266902f345d1a72b28827f907d66f825f4935f Mon Sep 17 00:00:00 2001 From: fang duan Date: Mon, 24 Jul 2023 21:36:26 +0800 Subject: [PATCH 0881/1891] add rtx_data_dir info to rtx doctor (#709) --- src/cli/doctor.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 94d18a73e..999e3a0e9 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -28,6 +28,7 @@ impl Command for Doctor { rtxprintln!(out, "{}", rtx_version()); rtxprintln!(out, "{}", build_info()); rtxprintln!(out, "{}", shell()); + rtxprintln!(out, "{}", rtx_data_dir()); rtxprintln!(out, "{}", rtx_env_vars()); rtxprintln!( out, @@ -83,6 +84,12 @@ impl Command for Doctor { } } +fn rtx_data_dir() -> String { + let mut s = style("rtx data directory:\n").bold().to_string(); + s.push_str(&format!(" {}\n", env::RTX_DATA_DIR.to_string_lossy())); + s +} + fn rtx_env_vars() -> String { let vars = env::vars() .filter(|(k, _)| k.starts_with("RTX_")) From 0b737b68ec3562c886a13b1d9a0ffc98dc054fcb Mon Sep 17 00:00:00 2001 From: Stephen Date: Tue, 25 Jul 2023 16:06:47 +0100 Subject: [PATCH 0882/1891] bug: fix self-update Unknown Issuer (#715) This enables reqwests to load OS certificates. This ensures any extra certificates installed by the user into the OS can be used by rtx. This is important for environments that have tls decryption proxies and the resigned CA is trusted. --- Cargo.lock | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 92bf0a5e2..cd3ab1c93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -343,6 +343,16 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -1254,6 +1264,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "os_pipe" version = "1.1.4" @@ -1509,6 +1525,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", + "rustls-native-certs", "rustls-pemfile", "serde", "serde_json", @@ -1668,6 +1685,18 @@ dependencies = [ "sct", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.3" @@ -1702,6 +1731,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1718,6 +1756,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "self_update" version = "0.37.0" diff --git a/Cargo.toml b/Cargo.toml index 9820e2890..3d58d8c11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,7 @@ rayon = "1.6.1" regex = "1.8.4" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", - "rustls-tls", + "rustls-tls-native-roots", "json", ] } rmp-serde = "1.1.2" From 7b37066087766b0989489c7d21cfd4e1cea1c6a1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 25 Jul 2023 10:30:33 -0500 Subject: [PATCH 0883/1891] chore: Release --- Cargo.lock | 120 ++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 65 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd3ab1c93..2bf019e70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,7 +257,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.27", ] [[package]] @@ -437,7 +437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.25", + "syn 2.0.27", ] [[package]] @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encode_unicode" @@ -598,12 +598,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "filetime" @@ -681,7 +678,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.27", ] [[package]] @@ -1064,9 +1061,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" @@ -1112,9 +1109,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" +checksum = "24e6ab01971eb092ffe6a7d42f49f9ff42662f17604681e2843ad65077ba47dc" dependencies = [ "cc", "libc", @@ -1217,9 +1214,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -1288,9 +1285,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "paste" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "path-absolutize" @@ -1318,9 +1315,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" +checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" dependencies = [ "thiserror", "ucd-trie", @@ -1328,9 +1325,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" +checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" dependencies = [ "pest", "pest_generator", @@ -1338,22 +1335,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" +checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.27", ] [[package]] name = "pest_meta" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" +checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" dependencies = [ "once_cell", "pest", @@ -1380,9 +1377,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d220334a184db82b31b83f5ff093e3315280fb2b6bbc032022b2304a509aab7a" +checksum = "edc55135a600d700580e406b4de0d59cb9ad25e344a3a091a97ded2622ec4ec6" [[package]] name = "pretty_assertions" @@ -1396,9 +1393,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -1414,9 +1411,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -1558,9 +1555,9 @@ dependencies = [ [[package]] name = "rmp" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" dependencies = [ "byteorder", "num-traits", @@ -1586,7 +1583,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.34.1" +version = "1.34.2" dependencies = [ "base64", "built", @@ -1718,9 +1715,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" @@ -1742,9 +1739,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -1799,31 +1796,31 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.174" +version = "1.0.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b88756493a5bd5e5395d53baa70b194b05764ab85b59e43e4b8f4e1192fa9b1" +checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.174" +version = "1.0.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5c3a298c7f978e53536f95a63bdc4c4a64550582f31a0359a9afda6aede62e" +checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.27", ] [[package]] @@ -1967,9 +1964,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.25" +version = "2.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" dependencies = [ "proc-macro2", "quote", @@ -1989,15 +1986,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.23", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -2054,7 +2050,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.27", ] [[package]] @@ -2309,9 +2305,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -2353,9 +2349,9 @@ dependencies = [ [[package]] name = "urlencoding" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "utf8parse" @@ -2437,7 +2433,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.27", "wasm-bindgen-shared", ] @@ -2471,7 +2467,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.27", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2685,9 +2681,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" +checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 3d58d8c11..1d6b5e896 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.34.1" +version = "1.34.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 476ea2b18..ae9b32b24 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.34.1 +rtx 1.34.2 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -326,7 +326,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.34.1/rtx-v1.34.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.34.2/rtx-v1.34.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index d7ceaa539..8708b3bfc 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.34.1"; + version = "1.34.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index d41ac9be6..662b26112 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.34.1" +.TH rtx 1 "rtx 1.34.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.34.1 +v1.34.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6de6fa303..53141821b 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.34.1 +Version: 1.34.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 73d7ca9b720ca33d2ae096ec6d137bf95c2bf703 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 25 Jul 2023 12:54:19 -0500 Subject: [PATCH 0884/1891] refactor version installs (#689) --- e2e/ruby/test_ruby_install | 5 +- src/cli/asdf.rs | 1 + src/cli/install.rs | 125 +++------------------------------- src/cli/use.rs | 5 +- src/config/config_file/mod.rs | 10 ++- src/test.rs | 5 +- src/tool.rs | 7 ++ src/toolset/mod.rs | 119 ++++++++++++-------------------- src/toolset/tool_version.rs | 2 +- 9 files changed, 76 insertions(+), 203 deletions(-) diff --git a/e2e/ruby/test_ruby_install b/e2e/ruby/test_ruby_install index 3ab7ebab1..89905c7f7 100755 --- a/e2e/ruby/test_ruby_install +++ b/e2e/ruby/test_ruby_install @@ -9,7 +9,8 @@ export RTX_RUBY_INSTALL=1 echo "ruby-3.1.4" > .ruby-version -rtx i ruby -assert_contains "rtx x -- ruby --version" "ruby 3.1.4" +# disable this slow test for now +#rtx i ruby +#assert_contains "rtx x -- ruby --version" "ruby 3.1.4" rm .ruby-version diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 805d06761..edae43cd0 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -77,6 +77,7 @@ mod tests { #[test] fn test_fake_asdf_list() { + assert_cli!("install", "tiny@1", "tiny@2"); assert_cli!("asdf", "install", "tiny"); assert_cli_snapshot!("asdf", "list", "tiny"); } diff --git a/src/cli/install.rs b/src/cli/install.rs index 6f31b7985..9212cde57 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,10 +1,4 @@ -use std::sync::Arc; - -use color_eyre::eyre::{eyre, Result}; -use console::style; -use itertools::Itertools; -use rayon::prelude::*; -use rayon::ThreadPoolBuilder; +use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; @@ -13,14 +7,10 @@ use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::output::Output; -use crate::runtime_symlinks; -use crate::shims; -use crate::tool::Tool; use crate::toolset::{ ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, }; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::ProgressReport; /// Install a tool version /// @@ -63,27 +53,16 @@ impl Command for Install { impl Install { fn install_runtimes(&self, mut config: Config, runtimes: &[ToolArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); - let ts = ToolsetBuilder::new() + let mut ts = ToolsetBuilder::new() .with_latest_versions() .build(&mut config)?; - ThreadPoolBuilder::new() - .num_threads(config.settings.jobs) - .build()? - .install(|| -> Result<()> { - let tool_versions = - self.get_requested_tool_versions(&mut config, &ts, runtimes, &mpr)?; - if tool_versions.is_empty() { - warn!("no runtimes to install"); - warn!("specify a version with `rtx install @`"); - return Ok(()); - } - self.uninstall_existing_versions(&config, &mpr, &tool_versions)?; - self.install_requested_versions(&config, &mpr, tool_versions)?; - shims::reshim(&mut config, &ts) - .map_err(|err| eyre!("failed to reshim: {}", err))?; - runtime_symlinks::rebuild(&config)?; - Ok(()) - }) + let tool_versions = self.get_requested_tool_versions(&mut 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) } fn get_requested_tool_versions( @@ -92,7 +71,7 @@ impl Install { ts: &Toolset, runtimes: &[ToolArg], mpr: &MultiProgressReport, - ) -> Result, ToolVersion)>> { + ) -> Result> { let mut requests = vec![]; for runtime in ToolArg::double_tool_condition(runtimes) { let default_opts = ToolVersionOptions::new(); @@ -133,7 +112,7 @@ impl Install { } } let tv = tvr.resolve(config, &plugin, opts, ts.latest_versions)?; - tool_versions.push((plugin, tv)); + tool_versions.push(tv); } Ok(tool_versions) } @@ -150,88 +129,6 @@ impl Install { Ok(()) } - - fn uninstall_existing_versions( - &self, - config: &Config, - mpr: &MultiProgressReport, - tool_versions: &[(Arc, ToolVersion)], - ) -> Result<()> { - let already_installed_tool_versions = tool_versions - .iter() - .filter(|(t, tv)| t.is_version_installed(tv)) - .map(|(t, tv)| (t, tv.clone())); - if self.force { - already_installed_tool_versions - .par_bridge() - .map(|(tool, tv)| self.uninstall_version(config, tool, &tv, mpr.add())) - .collect::>>()?; - } else { - for (_, tv) in already_installed_tool_versions { - warn!("{} already installed", style(tv).cyan().for_stderr()); - } - } - Ok(()) - } - fn install_requested_versions( - &self, - config: &Config, - mpr: &MultiProgressReport, - tool_versions: Vec<(Arc, ToolVersion)>, - ) -> Result<()> { - let grouped_tool_versions: Vec<(Arc, Vec)> = tool_versions - .into_iter() - .filter(|(t, tv)| !t.is_version_installed(tv)) - .group_by(|(t, _)| t.clone()) - .into_iter() - .map(|(t, tvs)| (t, tvs.map(|(_, tv)| tv).collect())) - .collect(); - grouped_tool_versions - .into_par_iter() - .map(|(tool, versions)| { - for tv in versions { - self.install_version(config, &tool, &tv, mpr.add())?; - } - Ok(()) - }) - .collect::>>()?; - Ok(()) - } - fn uninstall_version( - &self, - config: &Config, - tool: &Tool, - tv: &ToolVersion, - mut pr: ProgressReport, - ) -> Result<()> { - tool.decorate_progress_bar(&mut pr, Some(tv)); - match tool.uninstall_version(config, tv, &pr, false) { - Ok(_) => { - pr.finish(); - Ok(()) - } - Err(err) => { - pr.error(err.to_string()); - Err(err.wrap_err(format!("failed to uninstall {}", tv))) - } - } - } - fn install_version( - &self, - config: &Config, - tool: &Tool, - tv: &ToolVersion, - mut pr: ProgressReport, - ) -> Result<()> { - tool.decorate_progress_bar(&mut pr, Some(tv)); - match tool.install_version(config, tv, &mut pr, self.force) { - Ok(_) => Ok(()), - Err(err) => { - pr.error(err.to_string()); - Err(err.wrap_err(format!("failed to install {}", tv))) - } - } - } } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/cli/use.rs b/src/cli/use.rs index cf64283c2..5cf6f157c 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -5,7 +5,7 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::cli::local::local; -use crate::config::{Config, MissingRuntimeBehavior}; +use crate::config::Config; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::output::Output; use crate::plugins::PluginName; @@ -51,8 +51,7 @@ pub struct Use { } impl Command for Use { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - config.settings.missing_runtime_behavior = MissingRuntimeBehavior::AutoInstall; + fn run(self, config: Config, out: &mut Output) -> Result<()> { let runtimes = self .tool .into_iter() diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index f9b440dc2..071939b90 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -15,7 +15,7 @@ use crate::file::{display_path, replace_path}; use crate::hash::hash_to_str; use crate::output::Output; use crate::plugins::PluginName; -use crate::toolset::{ToolVersionList, Toolset}; +use crate::toolset::{ToolVersion, ToolVersionList, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::{dirs, env}; @@ -56,8 +56,10 @@ impl dyn ConfigFile { runtimes: &[ToolArg], pin: bool, ) -> Result<()> { + // TODO: this has become a complete mess and could probably be greatly simplified let mpr = MultiProgressReport::new(config.show_progress_bars()); let mut ts = self.to_toolset().to_owned(); + ts.latest_versions = true; ts.resolve(config); let mut plugins_to_update = HashMap::new(); for runtime in runtimes { @@ -77,7 +79,11 @@ impl dyn ConfigFile { ts.versions.insert(plugin.clone(), tvl); } ts.resolve(config); - ts.install_missing(config, mpr)?; + let versions: Vec = plugins_to_update + .iter() + .flat_map(|(pn, _)| ts.versions.get(pn).unwrap().versions.clone()) + .collect(); + ts.install_versions(config, versions, &mpr, false)?; for (plugin, versions) in plugins_to_update { let versions = versions .into_iter() diff --git a/src/test.rs b/src/test.rs index 00ac89376..2d111acee 100644 --- a/src/test.rs +++ b/src/test.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use indoc::indoc; -use crate::{assert_cli, env}; +use crate::env; #[ctor::ctor] fn init() { @@ -27,9 +27,6 @@ fn init() { env::set_var("RTX_MISSING_RUNTIME_BEHAVIOR", "autoinstall"); //env::set_var("TERM", "dumb"); reset_config(); - assert_cli!("trust"); - assert_cli!("plugins", "uninstall", "tiny-link"); - assert_cli!("install", "tiny@1", "tiny@2", "tiny@3", "tiny", "dummy"); } pub fn reset_config() { diff --git a/src/tool.rs b/src/tool.rs index 53a20670a..4ef2e00e2 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -207,6 +207,13 @@ impl Tool { pr: &mut ProgressReport, force: bool, ) -> Result<()> { + if self.is_version_installed(tv) { + if force { + self.uninstall_version(config, tv, pr, false)?; + } else { + return Ok(()); + } + } self.decorate_progress_bar(pr, Some(tv)); let _lock = self.get_lock(&tv.install_path(), force)?; self.create_install_dirs(tv)?; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 862e11c60..4f192c3f7 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -1,8 +1,9 @@ -use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; +use std::thread; use color_eyre::eyre::Result; use console::style; @@ -11,7 +12,6 @@ use dialoguer::MultiSelect; use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; -use rayon::ThreadPoolBuilder; pub use builder::ToolsetBuilder; pub use tool_source::ToolSource; @@ -113,11 +113,11 @@ impl Toolset { if versions.is_empty() { warn(); } else { - self.install_missing_versions(config, versions, mpr)?; + self.install_versions(config, versions, &mpr, false)?; } } MissingRuntimeBehavior::AutoInstall => { - self.install_missing_versions(config, versions, mpr)?; + self.install_versions(config, versions, &mpr, false)?; } } Ok(()) @@ -135,85 +135,50 @@ impl Toolset { .collect() } - fn install_missing_versions( + pub fn install_versions( &mut self, config: &mut Config, - selected_versions: Vec, - mpr: MultiProgressReport, + versions: Vec, + mpr: &MultiProgressReport, + force: bool, ) -> Result<()> { - ThreadPoolBuilder::new() - .num_threads(config.settings.jobs) - .build()? - .install(|| -> Result<()> { - let plugins = selected_versions - .iter() - .map(|v| v.plugin_name.clone()) - .unique() - .collect_vec(); - let selected_versions = selected_versions - .into_iter() - .map(|v| (v.plugin_name.clone(), v.request)) - .collect::>(); - self.install_missing_plugins(config, plugins, &mpr)?; - self.versions - .iter_mut() - .par_bridge() - .filter_map(|(p, v)| match config.tools.get(p) { - Some(plugin) if plugin.is_installed() => Some((plugin, v)), - _ => None, - }) - .map(|(plugin, v)| { - let versions = v - .versions - .iter_mut() - .filter(|tv| { - !plugin.is_version_installed(tv) - && selected_versions - .contains(&(tv.plugin_name.clone(), tv.request.clone())) - }) - .collect_vec(); - (plugin, versions) - }) - .filter(|(_, versions)| !versions.is_empty()) - .map(|(plugin, versions)| { - for tv in versions { - let mut pr = mpr.add(); - // TODO: is this necessary? - // version.resolve(config, plugin.clone(), self.latest_versions)?; - plugin.install_version(config, tv, &mut pr, false)?; + self.latest_versions = true; + let queue: Vec<_> = versions + .into_iter() + .group_by(|v| v.plugin_name.clone()) + .into_iter() + .map(|(pn, v)| (config.get_or_create_tool(&pn), v.collect_vec())) + .collect(); + let queue = Arc::new(Mutex::new(queue)); + thread::scope(|s| { + (0..config.settings.jobs) + .map(|_| { + let queue = queue.clone(); + let config = &*config; + s.spawn(move || { + let next_job = || queue.lock().unwrap().pop(); + while let Some((t, versions)) = next_job() { + if !t.is_installed() { + t.install(config, &mut mpr.add(), force)?; + } + for tv in versions { + let tv = tv.request.resolve(config, &t, tv.opts.clone(), true)?; + let mut pr = mpr.add(); + t.install_version(config, &tv, &mut pr, force)?; + } } Ok(()) }) - .collect::>>()?; - shims::reshim(config, self)?; - runtime_symlinks::rebuild(config)?; - Ok(()) - }) - } - fn install_missing_plugins( - &mut self, - config: &mut Config, - missing_plugins: Vec, - mpr: &MultiProgressReport, - ) -> Result<()> { - for plugin in &missing_plugins { - config.get_or_create_tool(plugin); - } - let missing_plugins = missing_plugins - .into_par_iter() - .map(|p| config.tools.get(&p).unwrap()) - .filter(|p| !p.is_installed()) - .map(|p| { - let mut pr = mpr.add(); - p.install(config, &mut pr, false) - }) - .collect::>>()?; - if !missing_plugins.is_empty() { - self.resolve(config); - } - Ok(()) + }) + .collect_vec() + .into_iter() + .map(|t| t.join().unwrap()) + .collect::>>() + })?; + self.resolve(config); + shims::reshim(config, self)?; + runtime_symlinks::rebuild(config) } - pub fn list_missing_versions(&self, config: &Config) -> Vec<&ToolVersion> { self.versions .iter() diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 8b8faaf34..9c57922bf 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -13,7 +13,7 @@ use crate::tool::Tool; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; /// represents a single version of a tool for a particular plugin -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ToolVersion { pub request: ToolVersionRequest, pub plugin_name: PluginName, From 36e736f29b99a0b3d962f1fb64b18b939c54d61c Mon Sep 17 00:00:00 2001 From: "Justin \"J.R.\" Hill" Date: Tue, 25 Jul 2023 11:03:57 -0700 Subject: [PATCH 0885/1891] Update Nix install instructions (#642) This addresses https://github.com/jdxcode/rtx/issues/635 Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- README.md | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index ae9b32b24..59be85607 100644 --- a/README.md +++ b/README.md @@ -389,37 +389,10 @@ makepkg -si #### nix -For NixOS or those using the Nix package manager: - -```nix -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - rtx-flake = { - url = "github:jdxcode/rtx"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.flake-utils.follows = "flake-utils"; - }; - }; - - outputs = { self, nixpkgs, flake-utils, rtx-flake }: - flake-utils.lib.eachDefaultSystem(system: - let - pkgs = import nixpkgs { - inherit system; - overlays = [ rtx-flake.overlay ]; - }; - in { - devShells.default = pkgs.mkShell { - name = "my-dev-env"; - nativeBuildInputs = with pkgs; [ - rtx - ]; - }; - } - ); -} +For the Nix package manager, at release 23.05 or later: + +``` +nix-env -iA rtx ``` You can also import the package directly using From 8ef1ff3b8d6a0b4fb7071af86d6e56c07ccd4134 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:24:34 -0500 Subject: [PATCH 0886/1891] use sub-1:1.0.0 instead of 1.0.0!-1 (#556) --- .tool-versions | 2 +- README.md | 5 ++-- e2e/.e2e-tool-versions | 2 +- e2e/config/.e2e-tool-versions | 2 +- e2e/test_local | 6 ++-- src/cli/ls.rs | 22 +++++--------- src/plugins/external_plugin.rs | 27 ++++++++++++++++- src/tool.rs | 29 ++++++++++++++++++- src/toolset/builder.rs | 9 ++++++ src/toolset/tool_version.rs | 45 +++++++++++++++++++---------- src/toolset/tool_version_request.rs | 14 +++++++++ 11 files changed, 121 insertions(+), 42 deletions(-) diff --git a/.tool-versions b/.tool-versions index a1226bb30..68f92593c 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ shellcheck 0.9.0 -shfmt 3.6.0 +shfmt sub-1:3 jq latest tiny 2 1 3 diff --git a/README.md b/README.md index 59be85607..92484e87c 100644 --- a/README.md +++ b/README.md @@ -638,9 +638,8 @@ go prefix:1.19 # uses the latest 1.19.x version—needed in case "1.19 shfmt path:./shfmt # use a custom runtime node lts # use lts version of node (not supported by all plugins) -# The following syntax is experimental and subject to change -node lts!-2 # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) -python latest!-0.1 # install python-3.10 if the latest is 3.11 +node sub-2:lts # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) +python sub-0.1:latest # install python-3.10 if the latest is 3.11 ``` See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. diff --git a/e2e/.e2e-tool-versions b/e2e/.e2e-tool-versions index 0e45d0267..fbce89590 100644 --- a/e2e/.e2e-tool-versions +++ b/e2e/.e2e-tool-versions @@ -1,4 +1,4 @@ #python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 +shellcheck sub-0.1:0.10.0 shfmt 3.6.0 # test comment #node 20.0.0 diff --git a/e2e/config/.e2e-tool-versions b/e2e/config/.e2e-tool-versions index 0e45d0267..fbce89590 100644 --- a/e2e/config/.e2e-tool-versions +++ b/e2e/config/.e2e-tool-versions @@ -1,4 +1,4 @@ #python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 +shellcheck sub-0.1:0.10.0 shfmt 3.6.0 # test comment #node 20.0.0 diff --git a/e2e/test_local b/e2e/test_local index 64c654b7a..5687be159 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -101,14 +101,14 @@ assert_raises "rtx uninstall shfmt@3.6.0" rtx local --install-missing assert "rtx local" "#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 +shellcheck sub-0.1:0.10.0 shfmt 3.6.0 # test comment #node 20.0.0 " rtx local shfmt@3.5.0 assert "rtx local" "#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 +shellcheck sub-0.1:0.10.0 shfmt 3.5.0 # test comment #node 20.0.0 " @@ -120,7 +120,7 @@ fi rtx local shfmt@3.6.0 assert "rtx local" "#python 3.11.1 3.10.9 # foo -shellcheck 0.9.0 +shellcheck sub-0.1:0.10.0 shfmt 3.6.0 # test comment #node 20.0.0 " diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 995b109e8..59e4aa466 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -224,14 +224,15 @@ impl Ls { } fn get_runtime_list(&self, config: &mut Config) -> Result> { - let ts = ToolsetBuilder::new().build(config)?; + let mut tsb = ToolsetBuilder::new(); + if let Some(plugin) = &self.plugin { + tsb = tsb.with_tools(&[plugin]); + config.tools.retain(|p, _| p == plugin); + } + let ts = tsb.build(config)?; let mut versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = ts .list_installed_versions(config)? .into_iter() - .filter(|(p, _)| match &self.plugin { - Some(plugin) => &p.name == plugin, - None => true, - }) .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) .collect(); @@ -241,16 +242,7 @@ impl Ls { .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) .collect::, ToolVersion)>>(); - versions.extend( - active - .clone() - .into_iter() - .filter(|((plugin_name, _), _)| match &self.plugin { - Some(plugin) => plugin_name == plugin, - None => true, - }) - .collect::, ToolVersion))>>(), - ); + versions.extend(active.clone()); let rvs: Vec = versions .into_iter() diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 2014133d7..538bf4d99 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -1,4 +1,5 @@ use std::collections::{BTreeMap, HashMap}; +use std::fmt::{Debug, Formatter}; use std::fs; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; @@ -30,7 +31,6 @@ use crate::ui::progress_report::ProgressReport; use crate::{dirs, env, file}; /// This represents a plugin installed to ~/.local/share/rtx/plugins -#[derive(Debug)] pub struct ExternalPlugin { pub name: PluginName, pub plugin_path: PathBuf, @@ -245,6 +245,7 @@ impl ExternalPlugin { ToolVersionRequest::Version(_, _) | ToolVersionRequest::Prefix(_, _) => "version", ToolVersionRequest::Ref(_, _) => "ref", ToolVersionRequest::Path(_, _) => "path", + ToolVersionRequest::Sub { .. } => "sub", ToolVersionRequest::System(_) => { panic!("should not be called for system tool") } @@ -616,4 +617,28 @@ impl Plugin for ExternalPlugin { } } +impl Debug for ExternalPlugin { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ExternalPlugin") + .field("name", &self.name) + .field("plugin_path", &self.plugin_path) + .field("cache_path", &self.cache_path) + .field("downloads_path", &self.downloads_path) + .field("installs_path", &self.installs_path) + .field("repo_url", &self.repo_url) + .finish() + } +} + static EMPTY_HASH_MAP: Lazy> = Lazy::new(HashMap::new); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_debug() { + let plugin = ExternalPlugin::new(&PluginName::from("dummy")); + assert!(format!("{:?}", plugin).starts_with("ExternalPlugin { name: \"dummy\"")); + } +} diff --git a/src/tool.rs b/src/tool.rs index 4ef2e00e2..4c8d8342b 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,4 +1,5 @@ use std::collections::{BTreeMap, HashMap}; +use std::fmt::Debug; use std::fs; use std::fs::File; use std::path::{Path, PathBuf}; @@ -19,7 +20,6 @@ use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; use crate::{dirs, file}; -#[derive(Debug)] pub struct Tool { pub name: String, pub plugin: Box, @@ -398,6 +398,16 @@ impl PartialEq for Tool { } } +impl Debug for Tool { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Tool") + .field("name", &self.name) + .field("installs_path", &self.installs_path) + .field("plugin", &self.plugin) + .finish() + } +} + fn find_match_in_list(list: &[String], query: &str) -> Option { let v = match list.contains(&query.to_string()) { true => Some(query.to_string()), @@ -405,3 +415,20 @@ fn find_match_in_list(list: &[String], query: &str) -> Option { }; v } + +#[cfg(test)] +mod tests { + use super::*; + use crate::plugins::PluginName; + + #[test] + fn test_debug() { + let plugin = ExternalPlugin::new(&PluginName::from("dummy")); + let tool = Tool::new("dummy".to_string(), Box::new(plugin)); + let debug = format!("{:?}", tool); + assert!(debug.contains("Tool")); + assert!(debug.contains("name")); + assert!(debug.contains("installs_path")); + assert!(debug.contains("plugin")); + } +} diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index ad7a762a8..51ff60f6a 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -13,6 +13,7 @@ pub struct ToolsetBuilder { args: Vec, install_missing: bool, latest_versions: bool, + tool_filter: Option>, } impl ToolsetBuilder { @@ -35,6 +36,11 @@ impl ToolsetBuilder { self } + pub fn with_tools(mut self, tools: &[&str]) -> Self { + self.tool_filter = Some(tools.iter().map(|s| s.to_string()).collect()); + self + } + pub fn build(self, config: &mut Config) -> Result { let mut toolset = Toolset { latest_versions: self.latest_versions, @@ -44,6 +50,9 @@ impl ToolsetBuilder { load_config_files(config, &mut toolset); load_runtime_env(&mut toolset, env::vars().collect()); load_runtime_args(&mut toolset, &self.args); + if let Some(tools) = self.tool_filter { + toolset.versions.retain(|p, _| tools.contains(p)); + } toolset.resolve(config); if self.install_missing { diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 9c57922bf..f04a1976a 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -50,6 +50,17 @@ impl ToolVersion { ToolVersionRequest::Prefix(_, prefix) => { Self::resolve_prefix(config, tool, request, &prefix, opts)? } + ToolVersionRequest::Sub { + sub, orig_version, .. + } => Self::resolve_sub( + config, + tool, + request, + latest_versions, + &sub, + &orig_version, + opts, + )?, _ => { let version = request.version(); Self::new(tool, request, opts, version) @@ -83,6 +94,7 @@ impl ToolVersion { match &self.request { ToolVersionRequest::Version(_, _) => self.version.to_string(), ToolVersionRequest::Prefix(_, _) => self.version.to_string(), + ToolVersionRequest::Sub { .. } => self.version.to_string(), ToolVersionRequest::Ref(_, r) => format!("ref-{}", r), ToolVersionRequest::Path(_, p) => format!("path-{}", hash_to_str(p)), ToolVersionRequest::System(_) => "system".to_string(), @@ -108,6 +120,10 @@ impl ToolVersion { Some(("prefix", p)) => { return Self::resolve_prefix(config, tool, request, p, opts); } + Some((part, v)) if part.starts_with("sub-") => { + let sub = part.split_once('-').unwrap().1; + return Self::resolve_sub(config, tool, request, latest_versions, sub, v, opts); + } _ => (), } @@ -145,32 +161,29 @@ impl ToolVersion { if matches.contains(&v) { return build(v); } - if v.contains("!-") { - if let Some(tv) = Self::resolve_bang(config, tool, request.clone(), &v, &opts)? { - return Ok(tv); - } + // TODO: remove for calver release + if let Some((v, sub)) = v.split_once("!-") { + return Self::resolve_sub(config, tool, request.clone(), latest_versions, sub, v, opts); } Self::resolve_prefix(config, tool, request, &v, opts) } - /// resolve a version like `12.0.0!-1` which becomes `11.0.0`, `12.1.0!-0.1` becomes `12.0.0` - fn resolve_bang( + /// resolve a version like `sub-1:12.0.0` which becomes `11.0.0`, `sub-0.1:12.1.0` becomes `12.0.0` + fn resolve_sub( config: &Config, tool: &Tool, request: ToolVersionRequest, + latest_versions: bool, + sub: &str, v: &str, - opts: &ToolVersionOptions, - ) -> Result> { - let (wanted, minus) = v.split_once("!-").unwrap(); - let wanted = match wanted { + opts: ToolVersionOptions, + ) -> Result { + let v = match v { "latest" => tool.latest_version(&config.settings, None)?.unwrap(), - _ => config.resolve_alias(&tool.name, wanted)?, + _ => config.resolve_alias(&tool.name, v)?, }; - let wanted = version_sub(&wanted, minus); - let tv = tool - .latest_version(&config.settings, Some(wanted))? - .map(|v| Self::new(tool, request, opts.clone(), v)); - Ok(tv) + let v = version_sub(&v, sub); + Self::resolve_version(config, tool, request, latest_versions, &v, opts) } fn resolve_prefix( diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index f5a38831f..a21c338c3 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -14,6 +14,11 @@ pub enum ToolVersionRequest { Prefix(PluginName, String), Ref(PluginName, String), Path(PluginName, PathBuf), + Sub { + plugin_name: PluginName, + sub: String, + orig_version: String, + }, System(PluginName), } @@ -27,6 +32,11 @@ impl ToolVersionRequest { Some(("ref", r)) => Self::Ref(plugin_name, r.to_string()), Some(("prefix", p)) => Self::Prefix(plugin_name, p.to_string()), Some(("path", p)) => Self::Path(plugin_name, PathBuf::from(p)), + Some((p, v)) if p.starts_with("sub-") => Self::Sub { + plugin_name, + sub: p.split_once('-').unwrap().1.to_string(), + orig_version: v.to_string(), + }, None => { if s == "system" { Self::System(plugin_name) @@ -44,6 +54,7 @@ impl ToolVersionRequest { Self::Prefix(p, _) => p, Self::Ref(p, _) => p, Self::Path(p, _) => p, + Self::Sub { plugin_name, .. } => plugin_name, Self::System(p) => p, } } @@ -54,6 +65,9 @@ impl ToolVersionRequest { Self::Prefix(_, p) => format!("prefix:{p}"), Self::Ref(_, r) => format!("ref:{r}"), Self::Path(_, p) => format!("path:{}", p.display()), + Self::Sub { + sub, orig_version, .. + } => format!("sub-{}:{}", sub, orig_version), Self::System(_) => "system".to_string(), } } From 2e611aae5238378f2133a33111d09ca2bed6fa66 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:33:32 -0500 Subject: [PATCH 0887/1891] docs --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 92484e87c..8893303c2 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ v20.0.0 - [`.rtx.toml`](#rtxtoml) - [Legacy version files](#legacy-version-files) - [`.tool-versions`](#tool-versions) + - [Scopes](#scopes) - [Global config: `~/.config/rtx/config.toml`](#global-config-configrtxconfigtoml) - [Environment variables](#environment-variables) - [Aliases](#aliases) @@ -644,6 +645,19 @@ python sub-0.1:latest # install python-3.10 if the latest is 3.11 See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. +### Scopes + +Both `.rtx.toml` and `.tool-versions` support "scopes" which modify the behavior of the version: + +* `ref:` - compile from a vcs (usually git) ref +* `prefix:` - use the latest version that matches the prefix. Useful for Go since `1.20` + would only match `1.20` exactly but `prefix:1.20` will match `1.20.1` and `1.20.2` etc. +* `path:` - use a custom compiled version at the given path. One use-case is to re-use + Homebrew tools (e.g.: `path:/opt/homebrew/opt/node@20`). +* `sub-:` - subtracts PARTIAL_VERSION from ORIG_VERSION. This can + be used to express something like "2 versions behind lts" such as `sub-2:lts`. Or 1 minor + version behind the latest version: `sub-0.1:latest`. + ### Global config: `~/.config/rtx/config.toml` rtx can be configured in `~/.config/rtx/config.toml`. It's like local `.rtx.toml` files except that From 60b41583cbd1b97fdcd0399d28c3c47309b9b3c6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:19:10 -0500 Subject: [PATCH 0888/1891] added support for .java-version and .sdkmanrc legacy files (#720) References https://github.com/halcyon/asdf-java/issues/183 --- README.md | 4 ++-- e2e/test_java | 14 ++++++++++++-- src/plugins/core/java.rs | 20 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8893303c2..6a7b85b93 100644 --- a/README.md +++ b/README.md @@ -598,11 +598,11 @@ They support aliases, which means you can have an `.nvmrc` file with `lts/hydrog in rtx and nvm. Here are some of the supported legacy version files: | Plugin | "Legacy" (Idiomatic) Files | -|------------| -------------------------------------------------- | +|------------|----------------------------------------------------| | crystal | `.crystal-version` | | elixir | `.exenv-version` | | go | `.go-version`, `go.mod` | -| java | `.java-version` | +| java | `.java-version`, `.sdkmanrc` | | node | `.nvmrc`, `.node-version` | | python | `.python-version` | | ruby | `.ruby-version`, `Gemfile` | diff --git a/e2e/test_java b/e2e/test_java index 323cc5097..d4f7389ba 100755 --- a/e2e/test_java +++ b/e2e/test_java @@ -4,5 +4,15 @@ source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 -rtx i java@17.0.2 -assert_contains "rtx x java@17.0.2 -- java -version 2>&1" "openjdk version \"17.0.2\"" +cat <.sdkmanrc +java=17.0.2 +EOF +rtx i java +assert_contains "rtx x java -- java -version 2>&1" "openjdk version \"17.0.2\"" +rm .sdkmanrc + +cat <.java-version +17.0.2 +EOF +assert_contains "rtx x java -- java -version 2>&1" "openjdk version \"17.0.2\"" +rm .java-version diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 9406f2e36..9167b1e95 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -232,6 +232,26 @@ impl Plugin for JavaPlugin { )]); Ok(map) } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".java-version".into(), ".sdkmanrc".into()]) + } + + fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + let contents = fs::read_to_string(path)?; + if path.file_name() == Some(".sdkmanrc".as_ref()) { + let version = contents + .lines() + .find(|l| l.starts_with("java")) + .unwrap_or("java=") + .split_once('=') + .unwrap_or_default() + .1; + Ok(version.to_string()) + } else { + Ok(contents.to_string()) + } + } } fn os() -> &'static str { From d97fc52c3530469fe29ffb101978b851aa122f6d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:37:19 -0500 Subject: [PATCH 0889/1891] fix version support in default-ruby-gems (#721) --- docs/ruby.md | 4 +++- src/plugins/core/ruby.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/ruby.md b/docs/ruby.md index a10aeb8af..53864a5d7 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -44,8 +44,10 @@ To enable this feature, provide a `$HOME/.default-gems` file that lists one gem example: ``` +# supports comments pry -rubocop +bcat ~> 0.6.0 # supports version constraints +rubocop --pre # install prerelease version ``` ## `.ruby-version` and `Gemfile` support diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 6aecca77b..46d2caa28 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -178,7 +178,7 @@ impl RubyPlugin { pr.set_message(format!("installing default gem: {}", package)); let gem = self.gem_path(tv); let mut cmd = CmdLineRunner::new(settings, gem).with_pr(pr).arg("install"); - match package.split_once('-') { + match package.split_once(' ') { Some((name, "--pre")) => cmd = cmd.arg(name).arg("--pre"), Some((name, version)) => cmd = cmd.arg(name).arg("--version").arg(version), None => cmd = cmd.arg(package), From 2e7165f5b5edbb6d84a919d28fc9cacac111dd6e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:22:50 -0500 Subject: [PATCH 0890/1891] deno core plugin (#722) --- README.md | 3 +- docs/deno.md | 21 +++++ e2e/test_deno | 12 +++ src/plugins/core/deno.rs | 163 +++++++++++++++++++++++++++++++++++++++ src/plugins/core/mod.rs | 3 + 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 docs/deno.md create mode 100755 e2e/test_deno create mode 100644 src/plugins/core/deno.rs diff --git a/README.md b/README.md index 6a7b85b93..8e39efe0b 100644 --- a/README.md +++ b/README.md @@ -1093,11 +1093,12 @@ time. They can be easily overridden by installing a plugin with the same name, e You can see the core plugins with `rtx plugin ls --core`. -* [experimental] [Python](./docs/python.md) +* [Python](./docs/python.md) * [NodeJS](./docs/node.md) * [Ruby (experimental)](./docs/ruby.md) * [Go (experimental)](./docs/go.md) * [Java (experimental)](./docs/java.md) +* [Deno (experimental)](./docs/deno.md) ## FAQs diff --git a/docs/deno.md b/docs/deno.md new file mode 100644 index 000000000..d15fb80df --- /dev/null +++ b/docs/deno.md @@ -0,0 +1,21 @@ +# Deno in rtx + +The following are instructions for using the deno rtx core plugin. This is used when there isn't a +git plugin installed named "deno". + +If you want to use [asdf-deno](https://github.com/asdf-community/asdf-deno) +then run `rtx plugins install deno https://github.com/asdf-community/asdf-deno`. + +The code for this is inside the rtx repository at +[`./src/plugins/core/deno.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/deno.rs). + +## Usage + +The following installs deno and makes it the global default: + +```sh-session +$ rtx use -g deno@1 # install deno 1.x +$ rtx use -g deno@latest # install latest deno +``` + +See available versions with `rtx ls-remote deno`. diff --git a/e2e/test_deno b/e2e/test_deno new file mode 100755 index 000000000..7ac1c0f26 --- /dev/null +++ b/e2e/test_deno @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +export RTX_EXPERIMENTAL=1 + +cat <.deno-version +1.35.3 +EOF +rtx i deno +assert_contains "rtx x deno -- deno -V" "deno 1.35.3" +rm .deno-version diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs new file mode 100644 index 000000000..3cadfcfc0 --- /dev/null +++ b/src/plugins/core/deno.rs @@ -0,0 +1,163 @@ +use std::collections::HashMap; +use std::fs; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::Result; +use itertools::Itertools; +use versions::Versioning; + +use crate::cli::version::{ARCH, OS}; +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::github::GithubRelease; +use crate::plugins::core::CorePlugin; +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; +use crate::{env, file, http}; + +#[derive(Debug)] +pub struct DenoPlugin { + core: CorePlugin, +} + +impl DenoPlugin { + pub fn new(name: PluginName) -> Self { + let core = CorePlugin::new(name); + Self { core } + } + + fn fetch_remote_versions(&self) -> Result> { + let http = http::Client::new()?; + let mut req = http.get("https://api.github.com/repos/denoland/deno/releases?per_page=100"); + if let Some(token) = &*env::GITHUB_API_TOKEN { + req = req.header("authorization", format!("token {}", token)); + } + let resp = req.send()?; + http.ensure_success(&resp)?; + let releases: Vec = resp.json()?; + let versions = releases + .into_iter() + .map(|r| r.name) + .filter(|v| !v.is_empty()) + .filter(|v| v.starts_with('v')) + .map(|v| v.trim_start_matches('v').to_string()) + .unique() + .sorted_by_cached_key(|s| Versioning::new(s)) + .collect(); + Ok(versions) + } + + fn deno_bin(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/deno") + } + + fn test_deno(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + CmdLineRunner::new(&config.settings, self.deno_bin(tv)) + .with_pr(pr) + .arg("-V") + .execute() + } + + fn download(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result { + let http = http::Client::new()?; + let url = format!( + "https://github.com/denoland/deno/releases/download/v{}/deno-{}-{}.zip", + tv.version, + arch(), + os() + ); + let filename = url.split('/').last().unwrap(); + let tarball_path = tv.download_path().join(filename); + + pr.set_message(format!("downloading {}", &url)); + http.download_file(&url, &tarball_path)?; + + // TODO: hash::ensure_checksum_sha256(&tarball_path, &m.sha256)?; + + Ok(tarball_path) + } + + fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { + pr.set_message(format!("installing {}", tarball_path.display())); + fs::remove_dir_all(tv.install_path())?; + file::create_dir_all(tv.install_path().join("bin"))?; + file::unzip(tarball_path, &tv.download_path())?; + fs::rename(tv.download_path().join("deno"), self.deno_bin(tv))?; + file::make_executable(&self.deno_bin(tv))?; + Ok(()) + } + + fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("verifying"); + self.test_deno(config, tv, pr) + } +} + +impl Plugin for DenoPlugin { + fn name(&self) -> &PluginName { + &self.core.name + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.core + .remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".deno-version".into()]) + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); + + let tarball_path = self.download(tv, pr)?; + self.install(tv, pr, &tarball_path)?; + self.verify(config, tv, pr)?; + + Ok(()) + } + + fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { + let bin_paths = vec![ + tv.install_path().join("bin"), + tv.install_path().join(".deno/bin"), + ]; + Ok(bin_paths) + } + + fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + let map = HashMap::from([( + "DENO_INSTALL_ROOT".into(), + tv.install_path().join(".deno").to_string_lossy().into(), + )]); + Ok(map) + } +} + +fn os() -> &'static str { + if cfg!(target_os = "macos") { + "apple-darwin" + } else if cfg!(target_os = "linux") { + "unknown-linux-gnu" + } else { + &OS + } +} + +fn arch() -> &'static str { + if cfg!(target_arch = "x86_64") || cfg!(target_arch = "amd64") { + "x86_64" + } else if cfg!(target_arch = "aarch64") || cfg!(target_arch = "arm64") { + "aarch64" + } else { + &ARCH + } +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 49ec86317..01b163fcd 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -11,6 +11,7 @@ pub use python::PythonPlugin; use crate::cache::CacheManager; use crate::env::RTX_EXE; +use crate::plugins::core::deno::DenoPlugin; use crate::plugins::core::go::GoPlugin; use crate::plugins::core::java::JavaPlugin; use crate::plugins::core::node::NodePlugin; @@ -21,6 +22,7 @@ use crate::tool::Tool; use crate::toolset::ToolVersion; use crate::{dirs, env}; +mod deno; mod go; mod java; mod node; @@ -38,6 +40,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ + Box::new(DenoPlugin::new("deno".to_string())), Box::new(GoPlugin::new("go".to_string())), Box::new(JavaPlugin::new("java".to_string())), Box::new(RubyPlugin::new("ruby".to_string())), From 11c0813d1a128bd8861c51f3d8c4761e74eb9ef5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 11 Jul 2023 10:41:05 -0500 Subject: [PATCH 0891/1891] bun core plugin --- README.md | 1 + docs/bun.md | 18 +++++ e2e/test_bun | 12 ++++ src/plugins/core/bun.rs | 147 ++++++++++++++++++++++++++++++++++++++++ src/plugins/core/mod.rs | 3 + 5 files changed, 181 insertions(+) create mode 100644 docs/bun.md create mode 100755 e2e/test_bun create mode 100644 src/plugins/core/bun.rs diff --git a/README.md b/README.md index 8e39efe0b..628c2bba5 100644 --- a/README.md +++ b/README.md @@ -1099,6 +1099,7 @@ You can see the core plugins with `rtx plugin ls --core`. * [Go (experimental)](./docs/go.md) * [Java (experimental)](./docs/java.md) * [Deno (experimental)](./docs/deno.md) +* [Bun (experimental)](./docs/bun.md) ## FAQs diff --git a/docs/bun.md b/docs/bun.md new file mode 100644 index 000000000..436d5693f --- /dev/null +++ b/docs/bun.md @@ -0,0 +1,18 @@ +# Bun in rtx + +The following are instructions for using the bun rtx core plugin. This is used when there isn't a +git plugin installed named "bun". + +The code for this is inside the rtx repository at +[`./src/plugins/core/bun.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/bun.rs). + +## Usage + +The following installs bun and makes it the global default: + +```sh-session +$ rtx use -g bun@0.7 # install bun 0.7.x +$ rtx use -g bun@latest # install latest bun +``` + +See available versions with `rtx ls-remote bun`. diff --git a/e2e/test_bun b/e2e/test_bun new file mode 100755 index 000000000..fbf28d3ac --- /dev/null +++ b/e2e/test_bun @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +export RTX_EXPERIMENTAL=1 + +cat <.bun-version +0.7.0 +EOF +rtx i bun +assert_contains "rtx x bun -- bun -v" "0.7.0" +rm .bun-version diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs new file mode 100644 index 000000000..55b927a73 --- /dev/null +++ b/src/plugins/core/bun.rs @@ -0,0 +1,147 @@ +use std::fs; +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::Result; +use itertools::Itertools; +use versions::Versioning; + +use crate::cli::version::{ARCH, OS}; +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::github::GithubRelease; +use crate::plugins::core::CorePlugin; +use crate::plugins::{Plugin, PluginName}; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; +use crate::{env, file, http}; + +#[derive(Debug)] +pub struct BunPlugin { + core: CorePlugin, +} + +impl BunPlugin { + pub fn new(name: PluginName) -> Self { + let core = CorePlugin::new(name); + Self { core } + } + + fn fetch_remote_versions(&self) -> Result> { + let http = http::Client::new()?; + let mut req = http.get("https://api.github.com/repos/oven-sh/bun/releases?per_page=100"); + if let Some(token) = &*env::GITHUB_API_TOKEN { + req = req.header("authorization", format!("token {}", token)); + } + let resp = req.send()?; + http.ensure_success(&resp)?; + let releases: Vec = resp.json()?; + let versions = releases + .into_iter() + .map(|r| r.tag_name) + .filter_map(|v| v.strip_prefix("bun-v").map(|v| v.to_string())) + .unique() + .sorted_by_cached_key(|s| Versioning::new(s)) + .collect(); + Ok(versions) + } + + fn bun_bin(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/bun") + } + + fn test_bun(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + CmdLineRunner::new(&config.settings, self.bun_bin(tv)) + .with_pr(pr) + .arg("-v") + .execute() + } + + fn download(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result { + let http = http::Client::new()?; + let url = format!( + "https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-{}-{}.zip", + tv.version, + os(), + arch() + ); + let filename = url.split('/').last().unwrap(); + let tarball_path = tv.download_path().join(filename); + + pr.set_message(format!("downloading {}", &url)); + http.download_file(&url, &tarball_path)?; + + Ok(tarball_path) + } + + fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { + pr.set_message(format!("installing {}", tarball_path.display())); + fs::remove_dir_all(tv.install_path())?; + file::create_dir_all(tv.install_path().join("bin"))?; + file::unzip(tarball_path, &tv.download_path())?; + fs::rename( + tv.download_path() + .join(format!("bun-{}-{}", os(), arch())) + .join("bun"), + self.bun_bin(tv), + )?; + file::make_executable(&self.bun_bin(tv))?; + Ok(()) + } + + fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("verifying"); + self.test_bun(config, tv, pr) + } +} + +impl Plugin for BunPlugin { + fn name(&self) -> &PluginName { + &self.core.name + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.core + .remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".bun-version".into()]) + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); + + let tarball_path = self.download(tv, pr)?; + self.install(tv, pr, &tarball_path)?; + self.verify(config, tv, pr)?; + + Ok(()) + } +} + +fn os() -> &'static str { + if cfg!(target_os = "macos") { + "darwin" + } else if cfg!(target_os = "linux") { + "linux" + } else { + &OS + } +} + +fn arch() -> &'static str { + if cfg!(target_arch = "x86_64") || cfg!(target_arch = "amd64") { + "x64" + } else if cfg!(target_arch = "aarch64") || cfg!(target_arch = "arm64") { + "aarch64" + } else { + &ARCH + } +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 01b163fcd..650652f03 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -11,6 +11,7 @@ pub use python::PythonPlugin; use crate::cache::CacheManager; use crate::env::RTX_EXE; +use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; use crate::plugins::core::go::GoPlugin; use crate::plugins::core::java::JavaPlugin; @@ -22,6 +23,7 @@ use crate::tool::Tool; use crate::toolset::ToolVersion; use crate::{dirs, env}; +mod bun; mod deno; mod go; mod java; @@ -40,6 +42,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ + Box::new(BunPlugin::new("bun".to_string())), Box::new(DenoPlugin::new("deno".to_string())), Box::new(GoPlugin::new("go".to_string())), Box::new(JavaPlugin::new("java".to_string())), From 5acec092e4b8f12008b841a52a953ed900a155e9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:31:57 -0500 Subject: [PATCH 0892/1891] chore: Release --- .idea/vcs.xml | 1 + Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 13 ++++++++++--- 8 files changed, 29 insertions(+), 21 deletions(-) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 7fde3db4a..ceb737b78 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -18,5 +18,6 @@ + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 2bf019e70..ab282d3d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1109,9 +1109,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.10" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e6ab01971eb092ffe6a7d42f49f9ff42662f17604681e2843ad65077ba47dc" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ "cc", "libc", @@ -1583,7 +1583,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.34.2" +version = "1.35.0" dependencies = [ "base64", "built", @@ -1705,9 +1705,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.1" +version = "0.101.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e" +checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" dependencies = [ "ring", "untrusted", @@ -1805,18 +1805,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.175" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" +checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.175" +version = "1.0.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" +checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" dependencies = [ "proc-macro2", "quote", @@ -1825,9 +1825,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 1d6b5e896..6219c1cce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.34.2" +version = "1.35.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 628c2bba5..18eff7281 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.34.2 +rtx 1.35.0 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.34.2/rtx-v1.34.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.0/rtx-v1.35.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 8708b3bfc..4b3e957e4 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.34.2"; + version = "1.35.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 662b26112..85c062063 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.34.2" +.TH rtx 1 "rtx 1.35.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.34.2 +v1.35.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 53141821b..e01afe61f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.34.2 +Version: 1.35.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index b52bb8619..fe81ff0ee 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 690] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -33,6 +33,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("adr-tools", "https://gitlab.com/td7x/asdf/adr-tools.git"), ("ag", "https://github.com/koketani/asdf-ag.git"), ("age", "https://github.com/threkk/asdf-age"), + ("age-plugin-yubikey", "https://github.com/joke/asdf-age-plugin-yubikey"), ("agebox", "https://github.com/slok/asdf-agebox.git"), ("air", "https://github.com/pdemagny/asdf-air"), ("aks-engine", "https://github.com/robsonpeixoto/asdf-aks-engine.git"), @@ -116,8 +117,8 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("cilium-hubble", "https://github.com/NitriKx/asdf-cilium-hubble.git"), ("circleci-cli", "https://github.com/ucpr/asdf-circleci-cli.git"), ("clojure", "https://github.com/asdf-community/asdf-clojure.git"), + ("cloud-sql-proxy", "https://github.com/pbr0ck3r/asdf-cloud-sql-proxy.git"), ("cloudflared", "https://github.com/threkk/asdf-cloudflared"), - ("cloudsql-proxy", "https://github.com/itspngu/asdf-cloudsql-proxy.git"), ("clusterawsadm", "https://github.com/kahun/asdf-clusterawsadm.git"), ("clusterctl", "https://github.com/pfnet-research/asdf-clusterctl.git"), ("cmake", "https://github.com/asdf-community/asdf-cmake.git"), @@ -256,9 +257,10 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("go-sdk", "https://github.com/yacchi/asdf-go-sdk.git"), ("go-swagger", "https://github.com/jfreeland/asdf-go-swagger.git"), ("goconvey", "https://github.com/therounds-contrib/asdf-goconvey.git"), + ("gofumpt", "https://github.com/looztra/asdf-gofumpt.git"), ("gohugo", "https://github.com/nklmilojevic/asdf-hugo.git"), ("gojq", "https://github.com/jimmidyson/asdf-gojq.git"), - ("golang", "https://github.com/kennyp/asdf-golang.git"), + ("golang", "https://github.com/asdf-community/asdf-golang.git"), ("golangci-lint", "https://github.com/hypnoglow/asdf-golangci-lint.git"), ("gomigrate", "https://github.com/joschi/asdf-gomigrate.git"), ("gomplate", "https://github.com/sneakybeaky/asdf-gomplate.git"), @@ -346,6 +348,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("kconf", "https://github.com/particledecay/asdf-kconf.git"), ("ki", "https://github.com/comdotlinux/asdf-ki"), ("kind", "https://github.com/johnlayton/asdf-kind.git"), + ("kiota", "https://github.com/asdf-community/asdf-kiota.git"), ("kn", "https://github.com/joke/asdf-kn.git"), ("ko", "https://github.com/zasdaym/asdf-ko.git"), ("koka", "https://github.com/susurri/asdf-koka.git"), @@ -427,6 +430,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("meson", "https://github.com/asdf-community/asdf-meson.git"), ("micronaut", "https://github.com/weibemoura/asdf-micronaut.git"), ("mill", "https://github.com/asdf-community/asdf-mill.git"), + ("minify", "https://github.com/axilleas/asdf-minify"), ("minikube", "https://github.com/alvarobp/asdf-minikube.git"), ("minio", "https://github.com/aeons/asdf-minio.git"), ("minishift", "https://github.com/sqtran/asdf-minishift.git"), @@ -454,6 +458,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("nomad", "https://github.com/asdf-community/asdf-hashicorp.git"), ("nova", "https://github.com/elementalvoid/asdf-nova.git"), ("nsc", "https://github.com/dex4er/asdf-nsc.git"), + ("oapi-codegen", "https://github.com/dylanrayboss/asdf-oapi-codegen.git"), ("oc", "https://github.com/sqtran/asdf-oc.git"), ("ocaml", "https://github.com/asdf-community/asdf-ocaml.git"), ("oci", "https://github.com/yasn77/asdf-oci.git"), @@ -541,6 +546,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("scala", "https://github.com/asdf-community/asdf-scala.git"), ("scaleway-cli", "https://github.com/albarralnunez/asdf-plugin-scaleway-cli"), ("scalingo-cli", "https://github.com/brandon-welsch/asdf-scalingo-cli.git"), + ("scarb", "https://github.com/software-mansion/asdf-scarb.git"), ("sccache", "https://github.com/emersonmx/asdf-sccache.git"), ("scenery", "https://github.com/skyzyx/asdf-scenery.git"), ("schemacrawler", "https://github.com/davidecavestro/asdf-schemacrawler.git"), @@ -647,6 +653,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("ttyd", "https://github.com/ivanvc/asdf-ttyd.git"), ("tuist", "https://github.com/cprecioso/asdf-tuist.git"), ("tx", "https://github.com/ORCID/asdf-transifex.git"), + ("typos", "https://github.com/aschiavon91/asdf-typos.git"), ("uaa-cli", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("unison", "https://github.com/susurri/asdf-unison.git"), ("upt", "https://github.com/ORCID/asdf-upt.git"), From 385d08b0403897140e99e1ddad80b4f3706ebb40 Mon Sep 17 00:00:00 2001 From: fang duan Date: Thu, 27 Jul 2023 22:40:02 +0800 Subject: [PATCH 0893/1891] fix RTX-GO-SKIP-CHECKSUM (#725) --- src/plugins/core/go.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 0a8f6213d..db9fc3c0b 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -103,9 +103,9 @@ impl GoPlugin { } fn verify_tarball_checksum(&self, tarball_url: &str, tarball_path: &Path) -> Result<()> { - let checksum_url = format!("{}.sha256", tarball_url); - let checksum = http::Client::new()?.get_text(checksum_url)?; if !*env::RTX_GO_SKIP_CHECKSUM { + let checksum_url = format!("{}.sha256", tarball_url); + let checksum = http::Client::new()?.get_text(checksum_url)?; hash::ensure_checksum_sha256(tarball_path, &checksum)?; } Ok(()) From c6fc294e01631895a5b7e28e85433a13b7ebe891 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:21:26 -0500 Subject: [PATCH 0894/1891] ignore asdf-plugins repo this gets added/removed during releases but should just be ignored by the IDE --- .idea/rtx.iml | 1 + .idea/vcs.xml | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.idea/rtx.iml b/.idea/rtx.iml index 027e49820..76f92ff1b 100644 --- a/.idea/rtx.iml +++ b/.idea/rtx.iml @@ -20,6 +20,7 @@ + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index ceb737b78..617d4b9cd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -18,6 +18,5 @@ - - \ No newline at end of file + From 6ff1c175e2c22171975f1c4c1998c40fa92eb980 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:34:54 -0500 Subject: [PATCH 0895/1891] fix symlink shims (#727) Fixes #726 --- src/shims.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims.rs b/src/shims.rs index 8f0869118..2c894e633 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -94,8 +94,8 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { } for bin in path.read_dir()? { let bin = bin?; - if !bin.file_type()?.is_file() - || bin.file_type()?.is_symlink() + // skip non-files and non-symlinks or non-executable files + if (!bin.file_type()?.is_file() && !bin.file_type()?.is_symlink()) || !file::is_executable(&bin.path()) { continue; From edd531accf26476ef174b08162e2e3fd2039e6ca Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 27 Jul 2023 14:47:08 -0500 Subject: [PATCH 0896/1891] refactor reshim logic (#729) This makes it only add/remove changed shims rather than rebuilding it every time --- src/shims.rs | 80 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/src/shims.rs b/src/shims.rs index 2c894e633..30d561ea7 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; @@ -15,6 +16,7 @@ use crate::fake_asdf; use crate::file::{create_dir_all, remove_all}; use crate::lock_file::LockFile; use crate::output::Output; +use crate::tool::Tool; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; @@ -71,15 +73,15 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { }) .lock(); - // remove old shims - let _ = remove_all(&*dirs::SHIMS); - create_dir_all(&*dirs::SHIMS)?; let rtx_bin = file::which("rtx").unwrap_or(env::RTX_EXE.clone()); - let paths: Vec = ts + create_dir_all(&*dirs::SHIMS)?; + let existing_shims = list_executables_in_dir(&dirs::SHIMS)?; + + let shims: HashSet = ts .list_installed_versions(config)? .into_par_iter() - .flat_map(|(p, tv)| match p.list_bin_paths(config, &tv) { + .flat_map(|(t, tv)| match list_tool_bins(config, &t, &tv) { Ok(paths) => paths, Err(e) => { warn!("Error listing bin paths for {}: {:#}", tv, e); @@ -88,29 +90,23 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { }) .collect(); - for path in paths { - if !path.exists() { - continue; - } - for bin in path.read_dir()? { - let bin = bin?; - // skip non-files and non-symlinks or non-executable files - if (!bin.file_type()?.is_file() && !bin.file_type()?.is_symlink()) - || !file::is_executable(&bin.path()) - { - continue; - } - let bin_name = bin.file_name().into_string().unwrap(); - let symlink_path = dirs::SHIMS.join(bin_name); - file::make_symlink(&rtx_bin, &symlink_path).map_err(|err| { - eyre!( - "Failed to create symlink from {} to {}: {}", - rtx_bin.display(), - symlink_path.display(), - err - ) - })?; - } + let shims_to_add = shims.difference(&existing_shims); + let shims_to_remove = existing_shims.difference(&shims); + + for shim in shims_to_add { + let symlink_path = dirs::SHIMS.join(shim); + file::make_symlink(&rtx_bin, &symlink_path).map_err(|err| { + eyre!( + "Failed to create symlink from {} to {}: {}", + rtx_bin.display(), + symlink_path.display(), + err + ) + })?; + } + for shim in shims_to_remove { + let symlink_path = dirs::SHIMS.join(shim); + remove_all(&symlink_path)?; } for plugin in config.tools.values() { match plugin.plugin_path.join("shims").read_dir() { @@ -131,6 +127,34 @@ pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { Ok(()) } +// lists all the paths to bins in a tv that shims will be needed for +fn list_tool_bins(config: &Config, t: &Tool, tv: &ToolVersion) -> Result> { + Ok(t.list_bin_paths(config, tv)? + .into_iter() + .par_bridge() + .filter(|path| path.exists()) + .map(|dir| list_executables_in_dir(&dir)) + .collect::>>()? + .into_iter() + .flatten() + .collect()) +} + +fn list_executables_in_dir(dir: &Path) -> Result> { + let mut out = HashSet::new(); + for bin in dir.read_dir()? { + let bin = bin?; + // skip non-files and non-symlinks or non-executable files + if (!bin.file_type()?.is_file() && !bin.file_type()?.is_symlink()) + || !file::is_executable(&bin.path()) + { + continue; + } + out.insert(bin.file_name().into_string().unwrap()); + } + Ok(out) +} + fn make_shim(target: &Path, shim: &Path) -> Result<()> { if shim.exists() { fs::remove_file(shim)?; From 1b0a5663217b817da9afc3c295d86769dd4339bc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 27 Jul 2023 14:58:04 -0500 Subject: [PATCH 0897/1891] refactor symlink rebuilds (#730) This modifies the logic to only remove existing symlinks if they conflict rather than rebuild all of them every time --- src/runtime_symlinks.rs | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index ad15e660b..b18001d95 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -14,13 +14,17 @@ use crate::tool::Tool; pub fn rebuild(config: &Config) -> Result<()> { for plugin in config.tools.values() { - remove_existing_symlinks(plugin)?; let symlinks = list_symlinks(config, plugin)?; let installs_dir = dirs::INSTALLS.join(&plugin.name); for (from, to) in symlinks { let from = installs_dir.join(from); if from.exists() { - continue; + if is_runtime_symlink(&from) && from.read_link()?.as_path() != to { + trace!("Removing existing symlink: {}", from.display()); + std::fs::remove_file(&from)?; + } else { + continue; + } } make_symlink(&to, &from)?; } @@ -76,22 +80,6 @@ fn installed_versions(plugin: &Tool) -> Result> { Ok(versions) } -fn remove_existing_symlinks(plugin: &Tool) -> Result<()> { - let installs_dir = dirs::INSTALLS.join(&plugin.name); - if !installs_dir.exists() { - return Ok(()); - } - for entry in std::fs::read_dir(installs_dir)? { - let entry = entry?; - let path = entry.path(); - if is_runtime_symlink(&path) { - trace!("Removing existing symlink: {}", path.display()); - std::fs::remove_file(path)?; - } - } - Ok(()) -} - pub fn is_runtime_symlink(path: &Path) -> bool { if let Ok(link) = path.read_link() { return link.starts_with("./"); From 219717ea8d36f0f3e3db689a23aa707cc6140770 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:07:35 -0500 Subject: [PATCH 0898/1891] require trusted config for [plugins] section (#731) Fixes #728 --- src/config/config_file/rtx_toml.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 468d7e74b..436f58190 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -84,7 +84,7 @@ impl RtxToml { "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, "settings" => self.settings = self.parse_settings(k, v)?, - "plugins" => self.plugins = self.parse_hashmap(k, v)?, + "plugins" => self.plugins = self.parse_plugins(k, v)?, _ => Err(eyre!("unknown key: {}", k))?, } } @@ -207,6 +207,11 @@ impl RtxToml { } } + fn parse_plugins(&mut self, key: &str, v: &Item) -> Result> { + self.trust_check()?; + self.parse_hashmap(key, v) + } + fn parse_hashmap(&mut self, key: &str, v: &Item) -> Result> { match v.as_table_like() { Some(table) => { From 61bc54fffec2c133046be40d75aa71ca47e3c132 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:22:12 -0500 Subject: [PATCH 0899/1891] chore: Release --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab282d3d4..170f7c786 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -751,9 +751,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" +checksum = "aca8bbd8e0707c1887a8bbb7e6b40e228f251ff5d62c8220a4a7a53c73aff006" dependencies = [ "aho-corasick", "bstr", @@ -1583,7 +1583,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.0" +version = "1.35.1" dependencies = [ "base64", "built", @@ -1805,18 +1805,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 6219c1cce..97701e779 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.0" +version = "1.35.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 18eff7281..e8b6b5098 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.0 +rtx 1.35.1 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -327,7 +327,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.0/rtx-v1.35.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.1/rtx-v1.35.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 4b3e957e4..6e463f773 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.0"; + version = "1.35.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 85c062063..cbbbd5bfc 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.0" +.TH rtx 1 "rtx 1.35.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.35.0 +v1.35.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e01afe61f..9c19c84b6 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.0 +Version: 1.35.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 4430cdaca4c6dac7491bdd8a9324e156b19918e9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 28 Jul 2023 14:51:03 -0500 Subject: [PATCH 0900/1891] added logo --- README.md | 6 +++++- docs/logo-dark.png | Bin 0 -> 7525 bytes docs/logo-dark@2x.png | Bin 0 -> 22251 bytes docs/logo-light.png | Bin 0 -> 7371 bytes docs/logo-light@2x.png | Bin 0 -> 25822 bytes 5 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 docs/logo-dark.png create mode 100644 docs/logo-dark@2x.png create mode 100644 docs/logo-light.png create mode 100644 docs/logo-light@2x.png diff --git a/README.md b/README.md index e8b6b5098..bcc457222 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@
-

rtx

+ + + rtx logo + +
Crates.io GitHub GitHub Workflow Status diff --git a/docs/logo-dark.png b/docs/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a24cd0dde3a172f22f394500719801c0e28d1b54 GIT binary patch literal 7525 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 literal 0 HcmV?d00001 diff --git a/docs/logo-dark@2x.png b/docs/logo-dark@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d423105636ee90e43d31f13ee4740bdc7535ca79 GIT binary patch literal 22251 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≤$OYS(}6lbM1-`p^w5|Cr<_lK)%R&Zf5va(&|;cKg_>ON>5&?x!^ zN{eJ-PFlb}?MPOVmSn$>1{e6C6yc!Zmr)SkRlR5ATvzA=+I*Sa>~K>N0{9yst0;ZJ zr7`e5c+YYxfvFz+5bqfPm;bf2E5os*^Ky}DEHR` zSEc`rNAYqd+s{c))s{6pPn|C3&$RNx|0lrJ?CJ%gfXAjLale;cB6dvLILZ2t|K%<~ z>;m0JccxayosK=rL%_8VqqYpH#Ghjx&^~(su_mojd_@%HH$rMHzN8unRcwYo;_yL&7)E_8IgY)jaZU5AM<%%Nq+6yFCel=XQhYK4ZD=Q9zJMM&b-u938&1lEHlW>R&uy zB$@tLw9IaZR{!#7?&kPY>x|pxrr!0b%@48ha!cE+%zh13P|v-FaK7dl7o8LU!3yuc zI}a;aSjCs_p)ez8dRR~0XLp05ZEYb1$>Eub?sD+$1M0HEF?*K&dwDD1-h!zZ=?-Cg z2d*56X9#E|2G{Y#j_^DJZ66x0y*dvUZ)itd2${XrQ6tLGkt+2EtSog6)*hDkJpl&; zgV68a{{={9qyh>WB-K&LB)wBSn4jRph$3^ns34ZM!QD3Z^j24dE;J_!Rpl;)8v$Z# zQ_QBnw3Gma=`)#%Xjx0osw33N!1aebXvVV9bvpT*(&;^bj-B_qE`XCHV zXu$a;u;$O!hWyM`+|bz@`BsqGCIaja&dtG`#%T0C-pjwP`W^niwhHUfZ4R><>>yIo z`$gWt5WuFUZ^IX{b-efc_{B^Q*=rDfC=EGKI4>*or zV=Oav@8$FU`2Gv;kN14eb*}l`*E!$&I?MME2N<4;?>lZc0?~{-jK;()Ao1-~?U@sd z?ym0uJA!fzod+k$B@sHkf33%3!`PNLM-m6ZR&1*OmK6cdbYs$b`bgE7%d{c^(BI61 zX);utknNp;Capgn0l06GfvEe#kJY_M4BU|plkw5)Zl5>ce^Nm@vld@4cq3;};!ljl z1jLeWlu032dMc{bgm7JB6`Fd|W8gn%Q>0$M4%W&efWl-FAgo$HttG;#V4%JQx5@VQ8O*)lvdUGIX ztcE8+W8oDL9e6y!VaW&FQtBU&T{M@Dpd3oJ7ZmAbehv^xz&Mp=+*$;{P@D7)IdudWD?{z+Jb+8ERs>j_6y;aku|&HCIY}YX3aQ`d>F{eK#2hbo5)K< zQjjnWd*V6LgJY7+e^bbA+nJDLm!cC?9;E_ld%IYMe~r0oa4Pi9&)^H7N2tYs(9QKC|$2NC3DS2{#8ex@%5iq;IC!k#>&N1UH$V>KgUmjCWRLZk3*o?COZH(WxRzWb1gPf# z+;a*srC+YOgvh~eZjOcRBuG&?#?1bvgTuM}W(?uya!{(>#VDBQ^fiwLdKC8#Iam

E2kxdh?o`!6_0$nKpg`)MVfwBWn?K zBkqP~moJxZ?N?qjtIGBkr^b*EZ@Deje;o=R3N3u4LMWnnXxsvy@(vvO<|*%rC7URf zV~6-TcD@rj}htm>5*Inu?BUHMnC*pNRf#O3!&z08XjZlt=5{U z$%kgGe_g!+v2^p`5B$RmS%Ue&Q$cOH!osl!m@{`zQn)FLBme)>qNec6-{##LPtxek zcJNpJ)d~;BLq;bLkKn05R1xaMJ>XXsp!q=6yG@R&OukNzdfbiOv$QR__7`cbcMct} z@EAmScM&-q_iNKV8XWZXt|X7&ZluHeTjZ!ApS-iQPPqye6`ebd1?Kz|L@TE%g0wX* z|7IUIsA3DZ%n5R7m(uE0iMyYs!ME}U{kAFwvC&CU;6 z1u2c{FIe63k27Q+J$9I61?3(=wXzk*0cQEpy@AhX#jWg{<)}7QZF4N4a$rlnG4x%< zY(I3gZ3Bhm8IIlTF#`!&ySS#woo}Ud5sHpVC9>yBRaUIZN$KK$vUsGe-GkM%vuGf}By=eV13IXx_ z6}q&F0hB6lO9UHT>q~>}4a~tF#l-2MU;$#&$QVc$=?A0^-P^kL)1r zNpZ`hse9*)6!ytbNL|%gy9=dyP!l9DqN`W+&YdBNI18eKYMZ6od|KoJ-x5O-oS*!= zGW$w6v#vNi2$uLC>8NoNuG%&k7GTf|K%XHO3HPm02Aow;SWfh9p(?&7q``d0vRGJC zfT4E7!dPgO6OJo}ntGbwM>0W|*_@tr%=X_0qUT>Ho`)A13+bj#(+HFduLiM-TGL}i zj6~Mx*s3TKZ`p@gB?uw+DQp1$qZ!^VcK!a+_a_qDjP* zprl&Z+-6?cNPG1YwwDK)0rcullM6d#@(Ej7RR` zWM6=6=v>P!N37W<<8R6MYET|;3$Ac-?o708+v<_D<0f9D5=hj=`zzHyKyLiW+VOww)D%MOukjT*=)?2I$Y&t@b$8{V7woC)w-=J z!P#c-B+g_2q+6SmoPU;jl^!!stTyY0rZ%o~YB2dv`FeW%`c~gxH(ESE%GjW^hszK@ zy?Y^o_@}t#f&3Y8OH8Q!M>47^n2Em0HkuDDtzy!B&qus@b(p3FS`8ob;0%;A@6G)vBXL?%(_uEZA>esV24~zw zU}E*g`w2DT4YNqa8THlO6KVX*b@M+d)(p?L(SkJx-O`t!=LS=2Z=hzjox8c;9NVf_ zNg+G@suoaJn7E%Ghp@64*ou!I_4&|-aYc+~kKidA7KE*?v1PaG)X33Ym$jdw>})VQ zHQnFEu4=jal9k$_jHe;-cE9)B!Y0&tS|J^+t<1;Ti1|ptoza2~v7A{A0TN-1=fDbU zYe8+vu!8G5GNLmCIxmJjD^blz?njfRt0wi%4(YVsrvQ*0c?oG!MIE8{A_dV_V`b}X z9>aq@GlaE&gXH7{JszL$xedGOP*zsw2;+iz>q~TKr(M$HGCa7-MUq-}I}FgYC!OpX}vr=#0(| zX#$RZZ}W%WWcUlB$wJ9*8FA}Ofpyhtea3mIkrcT`*96rid$ZS_V>`+BQ8`ED^i zE_E8GTa+_46C;E$NjX!!teft=syq3YBLtWhnuWg8gB#VqpXI<6k*h%E-P@@}FAYvdHIVedbncqw~?Nje>oSL4|yZQF*O8TWyyJmR;`aATu&o$6op#+0s{H zF6!e4{rD$R+7OW|WUSlX^H{vE^lZ;j+1Bzd0h^(F4)X z^clug2P{~&Yk9+kk@el~KdC+&Pe`GW&_Q!aBQ;?OLUZ@oQ5Ih9N#|MEee_=DQYl@r zDrsU(H|Lpe_zXd8XO~lvyjh=MiTQ21`^7T$OQk}RY|v27O(vrE-PI4sqf#bBkptb zuSCT=gJ3A(orl3$<$W3wb`A4ZSny1x%Hy0gdUe<5isqm5<~{?PrF$(8z)avUP4Vsn zdikSr&*#S=+)sII>!zQ(#AGPnH`|%kc@Ut>{{K@C|L+*cdHTVT$p?l;nnG{fz{JiY N`UqoqskTG-{{U%m5*Ppg literal 0 HcmV?d00001 diff --git a/docs/logo-light.png b/docs/logo-light.png new file mode 100644 index 0000000000000000000000000000000000000000..8b50fdd5bdaaee6085bbbdf823e512f6f2dbcec3 GIT binary patch literal 7371 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 Z$ZvXVC2#Qy|3`*EU)xx#>4{Uq{{vRl#F792 literal 0 HcmV?d00001 diff --git a/docs/logo-light@2x.png b/docs/logo-light@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d17dd0d8996b439bbc5937d99bee8c5fba3a76cb GIT binary patch literal 25822 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 E)r5>`jz(Vl@Q`R>pl#adriWZy7GQDOr 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 Date: Sat, 29 Jul 2023 16:40:20 -0500 Subject: [PATCH 0901/1891] tweaks to runtime symlinks (#740) --- src/runtime_symlinks.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index b18001d95..7060f6a9e 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -28,6 +28,9 @@ pub fn rebuild(config: &Config) -> Result<()> { } make_symlink(&to, &from)?; } + remove_missing_symlinks(plugin)?; + // attempt to remove the installs dir (will fail if not empty) + let _ = std::fs::remove_dir(&installs_dir); } Ok(()) } @@ -80,6 +83,22 @@ fn installed_versions(plugin: &Tool) -> Result> { Ok(versions) } +fn remove_missing_symlinks(plugin: &Tool) -> Result<()> { + let installs_dir = dirs::INSTALLS.join(&plugin.name); + if !installs_dir.exists() { + return Ok(()); + } + for entry in std::fs::read_dir(installs_dir)? { + let entry = entry?; + let path = entry.path(); + if is_runtime_symlink(&path) && !path.exists() { + trace!("Removing missing symlink: {}", path.display()); + std::fs::remove_file(path)?; + } + } + Ok(()) +} + pub fn is_runtime_symlink(path: &Path) -> bool { if let Ok(link) = path.read_link() { return link.starts_with("./"); From 840e14987fd71108530b18cc0ef56a50654c3590 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:41:25 -0500 Subject: [PATCH 0902/1891] nushell (#741) * fix(nushell): fix #738 * updated snapshots --------- Co-authored-by: Lisa Scheers --- src/plugins/core/java.rs | 2 +- src/shell/nushell.rs | 8 ++++---- .../snapshots/rtx__shell__nushell__tests__hook_init.snap | 8 ++++---- .../rtx__shell__nushell__tests__hook_init_nix.snap | 7 +++---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 9167b1e95..8beb7d8f2 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -249,7 +249,7 @@ impl Plugin for JavaPlugin { .1; Ok(version.to_string()) } else { - Ok(contents.to_string()) + Ok(contents) } } } diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index f3d6ac234..9ea55c3d5 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -31,16 +31,16 @@ impl Shell for Nushell { if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { out.push_str(&format!( - "let-env PATH = ($env.PATH | prepend '{}')\n", // TODO: set PATH as Path on windows + "$env.PATH = ($env.PATH | prepend '{}')\n", // TODO: set PATH as Path on windows dir.display() )); } out.push_str(&formatdoc! {r#" export-env {{ - let-env RTX_SHELL = "nu" + $env.RTX_SHELL = "nu" - let-env config = ($env.config | upsert hooks {{ + $env.config = ($env.config | upsert hooks {{ pre_prompt: [{{ condition: {{|| "RTX_SHELL" in $env }} code: {{|| rtx_hook }} @@ -77,7 +77,7 @@ impl Shell for Nushell { def-env "update-env" [] {{ for $var in $in {{ if $var.op == "set" {{ - let-env $var.name = $"($var.value)" + load-env {{($var.name): $var.value}} }} else if $var.op == "hide" {{ hide-env $var.name }} diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap index 234916a4b..db531511a 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap @@ -2,11 +2,11 @@ source: src/shell/nushell.rs expression: "nushell.activate(exe, true)" --- -let-env PATH = ($env.PATH | prepend '/some/dir') +$env.PATH = ($env.PATH | prepend '/some/dir') export-env { - let-env RTX_SHELL = "nu" + $env.RTX_SHELL = "nu" - let-env config = ($env.config | upsert hooks { + $env.config = ($env.config | upsert hooks { pre_prompt: [{ condition: {|| "RTX_SHELL" in $env } code: {|| rtx_hook } @@ -43,7 +43,7 @@ def-env rtx [command?: string, --help, ...rest: string] { def-env "update-env" [] { for $var in $in { if $var.op == "set" { - let-env $var.name = $"($var.value)" + load-env {($var.name): $var.value} } else if $var.op == "hide" { hide-env $var.name } diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap index 5cc7721bd..f3ce71ca3 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap @@ -1,12 +1,11 @@ --- source: src/shell/nushell.rs -assertion_line: 134 expression: "nushell.activate(exe, true)" --- export-env { - let-env RTX_SHELL = "nu" + $env.RTX_SHELL = "nu" - let-env config = ($env.config | upsert hooks { + $env.config = ($env.config | upsert hooks { pre_prompt: [{ condition: {|| "RTX_SHELL" in $env } code: {|| rtx_hook } @@ -43,7 +42,7 @@ def-env rtx [command?: string, --help, ...rest: string] { def-env "update-env" [] { for $var in $in { if $var.op == "set" { - let-env $var.name = $"($var.value)" + load-env {($var.name): $var.value} } else if $var.op == "hide" { hide-env $var.name } From 70578929ee3ab8a496b9942c39071c4e8d8640bf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:45:02 -0500 Subject: [PATCH 0903/1891] make ruby, go, and java non-experimental core plugins --- README.md | 6 +++--- src/plugins/core/mod.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bcc457222..90997d8d1 100644 --- a/README.md +++ b/README.md @@ -1099,9 +1099,9 @@ You can see the core plugins with `rtx plugin ls --core`. * [Python](./docs/python.md) * [NodeJS](./docs/node.md) -* [Ruby (experimental)](./docs/ruby.md) -* [Go (experimental)](./docs/go.md) -* [Java (experimental)](./docs/java.md) +* [Ruby](./docs/ruby.md) +* [Go](./docs/go.md) +* [Java](./docs/java.md) * [Deno (experimental)](./docs/deno.md) * [Bun (experimental)](./docs/bun.md) diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 650652f03..57aedafdb 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -35,8 +35,11 @@ type ToolMap = BTreeMap>; pub static CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ + Box::new(GoPlugin::new("go".to_string())), + Box::new(JavaPlugin::new("java".to_string())), Box::new(NodePlugin::new("node".to_string())), Box::new(PythonPlugin::new("python".to_string())), + Box::new(RubyPlugin::new("ruby".to_string())), ]) }); @@ -44,9 +47,6 @@ pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ Box::new(BunPlugin::new("bun".to_string())), Box::new(DenoPlugin::new("deno".to_string())), - Box::new(GoPlugin::new("go".to_string())), - Box::new(JavaPlugin::new("java".to_string())), - Box::new(RubyPlugin::new("ruby".to_string())), ]) }); From 765d3a4716fb1dd8f3e7608df19da3bef91ee3d4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:46:44 -0500 Subject: [PATCH 0904/1891] chore: Release --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 170f7c786..bd788f713 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1377,9 +1377,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc55135a600d700580e406b4de0d59cb9ad25e344a3a091a97ded2622ec4ec6" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" [[package]] name = "pretty_assertions" @@ -1483,9 +1483,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" dependencies = [ "aho-corasick", "memchr", @@ -1583,7 +1583,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.1" +version = "1.35.2" dependencies = [ "base64", "built", @@ -1805,18 +1805,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.177" +version = "1.0.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a" +checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.177" +version = "1.0.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3" +checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 97701e779..090744238 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.1" +version = "1.35.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 90997d8d1..8e91b21b6 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.1 +rtx 1.35.2 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -331,7 +331,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.1/rtx-v1.35.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.2/rtx-v1.35.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 6e463f773..88ad7a7fd 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.1"; + version = "1.35.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index cbbbd5bfc..322678815 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.1" +.TH rtx 1 "rtx 1.35.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.35.1 +v1.35.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9c19c84b6..993d9d035 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.1 +Version: 1.35.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 808ee7ad8862a2ab0616c97bb4b83ce43056faa3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 09:24:24 -0500 Subject: [PATCH 0905/1891] default to openssl unless building for alpine (#742) Fixes #718 --- Cargo.toml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 090744238..c0afe2ef1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,13 +64,10 @@ rayon = "1.6.1" regex = "1.8.4" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", - "rustls-tls-native-roots", "json", ] } rmp-serde = "1.1.2" -self_update = { version = "0.37.0", default-features = false, optional = true, features = [ - "rustls", -] } +self_update = { version = "0.37.0", default-features = false, optional = true } serde = "1.0.174" serde_derive = "1.0.152" serde_json = "1.0.103" @@ -99,10 +96,12 @@ insta = "1.31.0" pretty_assertions = "1.3.0" [features] -alpine = [] +alpine = ["rustls-native-roots"] brew = [] deb = [] rpm = [] +rustls = ["reqwest/rustls-tls", "self_update/rustls"] +rustls-native-roots = ["reqwest/rustls-tls-native-roots", "self_update/rustls"] [package.metadata.release] allow-branch = ["main"] From 4311536e4cf2280d098dba3f3754a9cdbc36a6fc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 09:25:43 -0500 Subject: [PATCH 0906/1891] chore: Release --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd788f713..19b4fccb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -557,9 +557,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -1583,7 +1583,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.2" +version = "1.35.3" dependencies = [ "base64", "built", @@ -1650,7 +1650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", - "errno 0.3.1", + "errno 0.3.2", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", @@ -1664,7 +1664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ "bitflags 2.3.3", - "errno 0.3.1", + "errno 0.3.2", "libc", "linux-raw-sys 0.4.3", "windows-sys 0.48.0", @@ -2681,9 +2681,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" +checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index c0afe2ef1..d8b2f1662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.2" +version = "1.35.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 8e91b21b6..a8b784a55 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.2 +rtx 1.35.3 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -331,7 +331,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.2/rtx-v1.35.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.3/rtx-v1.35.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 88ad7a7fd..714ee7a86 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.2"; + version = "1.35.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 322678815..09402163d 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.2" +.TH rtx 1 "rtx 1.35.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.35.2 +v1.35.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 993d9d035..ffa451743 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.2 +Version: 1.35.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 331088ab46730687eb994b6ef229a997f5474d0e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 09:57:04 -0500 Subject: [PATCH 0907/1891] set native-tls to enable openssl --- Cargo.lock | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 8 +++-- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19b4fccb0..8aaeda482 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -630,6 +630,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -894,6 +909,19 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -1190,6 +1218,24 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nix" version = "0.26.2" @@ -1261,12 +1307,50 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.27", +] + [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-sys" +version = "0.9.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_pipe" version = "1.1.4" @@ -1514,10 +1598,12 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -1528,6 +1614,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls", "tower-service", "url", @@ -2123,6 +2210,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" diff --git a/Cargo.toml b/Cargo.toml index d8b2f1662..ddcc182e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,10 +96,12 @@ insta = "1.31.0" pretty_assertions = "1.3.0" [features] +default = ["native-tls"] alpine = ["rustls-native-roots"] -brew = [] -deb = [] -rpm = [] +brew = ["native-tls"] +deb = ["native-tls"] +rpm = ["native-tls"] +native-tls = ["reqwest/native-tls"] rustls = ["reqwest/rustls-tls", "self_update/rustls"] rustls-native-roots = ["reqwest/rustls-tls-native-roots", "self_update/rustls"] From 8d33ea2a43a98a6accf650a4a53f445d5ab2ebb0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 09:59:33 -0500 Subject: [PATCH 0908/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8aaeda482..b6510f259 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1670,7 +1670,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.3" +version = "1.35.4" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index ddcc182e8..d693ff490 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.3" +version = "1.35.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index a8b784a55..1f26ac24e 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.3 +rtx 1.35.4 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -331,7 +331,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.3/rtx-v1.35.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.4/rtx-v1.35.4-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 714ee7a86..7ed8c49e8 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.3"; + version = "1.35.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 09402163d..d5eb16571 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.3" +.TH rtx 1 "rtx 1.35.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.35.3 +v1.35.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ffa451743..c478fb09d 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.3 +Version: 1.35.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From a4b1e624f95b18f6b2a670971a4279cd598f751a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 13:29:35 -0500 Subject: [PATCH 0909/1891] vendor openssl (#745) --- Cargo.lock | 11 +++++++++++ Cargo.toml | 9 +++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6510f259..44dff561d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1339,6 +1339,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "111.26.0+1.1.1u" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.90" @@ -1347,6 +1356,7 @@ checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -1700,6 +1710,7 @@ dependencies = [ "log", "num_cpus", "once_cell", + "openssl", "path-absolutize", "pretty_assertions", "rayon", diff --git a/Cargo.toml b/Cargo.toml index d693ff490..096bdf5cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ itertools = "0.11.0" log = "0.4.19" num_cpus = "1.14.0" once_cell = "1.18.0" +openssl = { version = "0.10", optional = true } path-absolutize = "3.1.0" rayon = "1.6.1" regex = "1.8.4" @@ -98,10 +99,10 @@ pretty_assertions = "1.3.0" [features] default = ["native-tls"] alpine = ["rustls-native-roots"] -brew = ["native-tls"] -deb = ["native-tls"] -rpm = ["native-tls"] -native-tls = ["reqwest/native-tls"] +brew = [] +deb = [] +rpm = [] +native-tls = ["reqwest/native-tls", "openssl/vendored"] rustls = ["reqwest/rustls-tls", "self_update/rustls"] rustls-native-roots = ["reqwest/rustls-tls-native-roots", "self_update/rustls"] From ba4004637852afe5e77704d642689bea4be96d21 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 13:31:13 -0500 Subject: [PATCH 0910/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44dff561d..c300a9fe8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1680,7 +1680,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.4" +version = "1.35.5" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 096bdf5cc..ea5e9ebb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.4" +version = "1.35.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 1f26ac24e..e90f46711 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.4 +rtx 1.35.5 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -331,7 +331,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.4/rtx-v1.35.4-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.5/rtx-v1.35.5-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 7ed8c49e8..f2b9e9857 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.4"; + version = "1.35.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index d5eb16571..eb31de1fc 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.4" +.TH rtx 1 "rtx 1.35.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -154,6 +154,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.35.4 +v1.35.5 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c478fb09d..e61dca73c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.4 +Version: 1.35.5 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 189cd9150ce0d23967aef0f5c28ce393eb0a7254 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 15:41:55 -0500 Subject: [PATCH 0911/1891] simplify build features (#747) --- .github/workflows/rtx.yml | 10 +++- Cargo.lock | 10 ---- Cargo.toml | 5 +- justfile | 2 +- man/man1/rtx.1 | 3 -- packaging/homebrew/homebrew.rb | 8 +-- scripts/build-deb.sh | 4 +- scripts/build-linux.sh | 10 ---- scripts/build-macos.sh | 7 --- scripts/build-rpm.sh | 4 +- scripts/release.sh | 7 +-- scripts/render-homebrew.sh | 8 +-- src/cli/mod.rs | 3 ++ .../{self_update/github.rs => self_update.rs} | 0 src/cli/self_update/mod.rs | 11 ---- src/cli/self_update/other.rs | 54 ------------------- ...elf_update__other__tests__self_update.snap | 5 -- 17 files changed, 26 insertions(+), 125 deletions(-) delete mode 100755 scripts/build-linux.sh delete mode 100755 scripts/build-macos.sh rename src/cli/{self_update/github.rs => self_update.rs} (100%) delete mode 100644 src/cli/self_update/mod.rs delete mode 100644 src/cli/self_update/other.rs delete mode 100644 src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index eb136a27c..290fd0a88 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -93,7 +93,12 @@ jobs: shared-key: "build-linux-${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cross - - run: scripts/build-linux.sh ${{matrix.target}} + - run: scripts/build-tarball.sh rtx --release --features openssl/vendored,self_update --target ${{matrix.target}} + env: + CROSS: "1" + - run: scripts/build-tarball.sh rtx-nonup --release --features openssl/vendored --target ${{matrix.target}} + env: + CROSS: "1" - uses: actions/upload-artifact@v3 with: name: tarball-${{matrix.target}} @@ -120,7 +125,8 @@ jobs: with: key: "${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - - run: scripts/build-macos.sh ${{matrix.target}} + - run: scripts/build-tarball.sh rtx --release --features openssl/vendored,self_update --target ${{matrix.target}} + - run: scripts/build-tarball.sh rtx-nonup --release --features openssl/vendored --target ${{matrix.target}} - uses: actions/upload-artifact@v3 with: name: tarball-${{matrix.target}} diff --git a/Cargo.lock b/Cargo.lock index c300a9fe8..92af5c7f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1339,15 +1339,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-src" -version = "111.26.0+1.1.1u" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" version = "0.9.90" @@ -1356,7 +1347,6 @@ checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] diff --git a/Cargo.toml b/Cargo.toml index ea5e9ebb1..781378cd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,11 +98,8 @@ pretty_assertions = "1.3.0" [features] default = ["native-tls"] -alpine = ["rustls-native-roots"] brew = [] -deb = [] -rpm = [] -native-tls = ["reqwest/native-tls", "openssl/vendored"] +native-tls = ["reqwest/native-tls"] rustls = ["reqwest/rustls-tls", "self_update/rustls"] rustls-native-roots = ["reqwest/rustls-tls-native-roots", "self_update/rustls"] diff --git a/justfile b/justfile index 6c8b9d3b7..c6b860b61 100644 --- a/justfile +++ b/justfile @@ -16,7 +16,7 @@ alias lf := lint-fix # just `cargo build` build *args: - cargo build {{ args }} + cargo build --all-features {{ args }} # run all test types test *args: (test-unit args) test-e2e lint diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index eb31de1fc..2e2b736f3 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -106,9 +106,6 @@ Delete unused versions of tools rtx\-reshim(1) rebuilds the shim farm .TP -rtx\-self\-update(1) -Updates rtx itself -.TP rtx\-settings(1) Manage settings .TP diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index a20325edf..5da1ee000 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -6,22 +6,22 @@ class Rtx < Formula on_macos do if Hardware::CPU.intel? - url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-x64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-nonup-v$RTX_VERSION-macos-x64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_X86_64" end if Hardware::CPU.arm? - url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-macos-arm64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-nonup-v$RTX_VERSION-macos-arm64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_ARM64" end end on_linux do if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? - url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-arm64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-nonup-v$RTX_VERSION-linux-arm64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_ARM64" end if Hardware::CPU.intel? - url "https://rtx.pub/v$RTX_VERSION/rtx-brew-v$RTX_VERSION-linux-x64.tar.xz" + url "https://rtx.pub/v$RTX_VERSION/rtx-nonup-v$RTX_VERSION-linux-x64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_X86_64" end end diff --git a/scripts/build-deb.sh b/scripts/build-deb.sh index af9cf78d3..3dc956466 100755 --- a/scripts/build-deb.sh +++ b/scripts/build-deb.sh @@ -3,7 +3,7 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -tar -xvJf "dist/rtx-deb-$RTX_VERSION-linux-x64.tar.xz" +tar -xvJf "dist/rtx-nonup-$RTX_VERSION-linux-x64.tar.xz" fpm -s dir -t deb \ --name rtx \ --license MIT \ @@ -15,7 +15,7 @@ fpm -s dir -t deb \ rtx/bin/rtx=/usr/bin/rtx \ rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 -tar -xvJf "dist/rtx-deb-$RTX_VERSION-linux-arm64.tar.xz" +tar -xvJf "dist/rtx-nonup-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t deb \ --name rtx \ --license MIT \ diff --git a/scripts/build-linux.sh b/scripts/build-linux.sh deleted file mode 100755 index 58230e390..000000000 --- a/scripts/build-linux.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -euxo pipefail - -TARGET="$1" -export CROSS=1 - -scripts/build-tarball.sh rtx --release --features self_update --target "$TARGET" -scripts/build-tarball.sh rtx-brew --release --features brew --target "$TARGET" -scripts/build-tarball.sh rtx-deb --release --features deb --target "$TARGET" -scripts/build-tarball.sh rtx-rpm --release --features rpm --target "$TARGET" diff --git a/scripts/build-macos.sh b/scripts/build-macos.sh deleted file mode 100755 index 0cf50a2cc..000000000 --- a/scripts/build-macos.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -euxo pipefail - -TARGET="$1" - -scripts/build-tarball.sh rtx --release --features self_update --target "$TARGET" -scripts/build-tarball.sh rtx-brew --release --features brew --target "$TARGET" diff --git a/scripts/build-rpm.sh b/scripts/build-rpm.sh index 8a7b9609d..fba3a161b 100755 --- a/scripts/build-rpm.sh +++ b/scripts/build-rpm.sh @@ -3,7 +3,7 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -tar -xvJf "dist/rtx-rpm-$RTX_VERSION-linux-x64.tar.xz" +tar -xvJf "dist/rtx-nonup-$RTX_VERSION-linux-x64.tar.xz" fpm -s dir -t rpm \ --name rtx \ --license MIT \ @@ -15,7 +15,7 @@ fpm -s dir -t rpm \ rtx/bin/rtx=/usr/bin/rtx \ rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 -tar -xvJf "dist/rtx-rpm-$RTX_VERSION-linux-arm64.tar.xz" +tar -xvJf "dist/rtx-nonup-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t rpm \ --name rtx \ --license MIT \ diff --git a/scripts/release.sh b/scripts/release.sh index d833a4300..04f48997e 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -24,11 +24,6 @@ for target in "${targets[@]}"; do cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$RTX_VERSION" done -# these are already packaged into the deb/rpm -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-brew-"*.gz -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-deb-"* -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-rpm-"* - platforms=( linux-x64 linux-arm64 @@ -73,4 +68,4 @@ git add . && git commit -m "rtx ${RTX_VERSION#v}" popd # we don't want to include these in the github release, only S3 -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-brew"* +rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-nonup"* diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index c3215cf4f..a33607f8b 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -3,9 +3,9 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=${RTX_VERSION#v*} \ - RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-brew-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-brew-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-brew-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-brew-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-nonup-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-nonup-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-nonup-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-nonup-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ cmd.run(config, out), Self::Prune(cmd) => cmd.run(config, out), Self::Reshim(cmd) => cmd.run(config, out), + #[cfg(feature = "self_update")] Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Shell(cmd) => cmd.run(config, out), diff --git a/src/cli/self_update/github.rs b/src/cli/self_update.rs similarity index 100% rename from src/cli/self_update/github.rs rename to src/cli/self_update.rs diff --git a/src/cli/self_update/mod.rs b/src/cli/self_update/mod.rs deleted file mode 100644 index 104214507..000000000 --- a/src/cli/self_update/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[cfg(feature = "self_update")] -pub mod github; - -#[cfg(feature = "self_update")] -pub use github::SelfUpdate; - -#[cfg(not(feature = "self_update"))] -pub mod other; - -#[cfg(not(feature = "self_update"))] -pub use other::SelfUpdate; diff --git a/src/cli/self_update/other.rs b/src/cli/self_update/other.rs deleted file mode 100644 index db0b090db..000000000 --- a/src/cli/self_update/other.rs +++ /dev/null @@ -1,54 +0,0 @@ -use color_eyre::eyre::eyre; -use color_eyre::Result; -use console::style; - -use crate::cli::command::Command; -use crate::config::Config; -use crate::output::Output; -use crate::{cmd, env}; - -/// Updates rtx itself -/// -/// Uses whatever package manager was used to install rtx or just downloads -/// a binary from GitHub Releases if rtx was installed manually. -/// Supports: standalone, brew, deb, rpm -#[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment)] -pub struct SelfUpdate {} - -impl Command for SelfUpdate { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let cmd = if cfg!(feature = "alpine") { - "apk upgrade rtx" - } else if cfg!(feature = "brew") { - "brew upgrade rtx" - } else if cfg!(feature = "deb") { - "sudo apt update && sudo apt install rtx" - } else if cfg!(feature = "rpm") { - "sudo dnf upgrade rtx" - } else { - return Err(eyre!("Self-update is not supported")); - }; - rtxprintln!(out, "Running `{}`", style(&cmd).yellow()); - cmd!(&*env::SHELL, "-c", cmd).run()?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use insta::assert_display_snapshot; - - use crate::assert_cli_err; - - use super::*; - - #[test] - fn test_self_update() -> Result<()> { - let err = assert_cli_err!("self-update"); - assert_display_snapshot!(err); - - Ok(()) - } -} diff --git a/src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap b/src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap deleted file mode 100644 index e090928a1..000000000 --- a/src/cli/self_update/snapshots/rtx__cli__self_update__other__tests__self_update.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/self_update/other.rs -expression: err ---- -Self-update is not supported From 79085e082b695101a708c58c97b1013c968d1f0a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 15:43:05 -0500 Subject: [PATCH 0912/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92af5c7f7..70467e120 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1670,7 +1670,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.5" +version = "1.35.6" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 781378cd0..a8ebf5e44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.5" +version = "1.35.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e90f46711..39ec7e87e 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.5 +rtx 1.35.6 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -331,7 +331,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.5/rtx-v1.35.5-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.6/rtx-v1.35.6-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index f2b9e9857..e3b48f0d0 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.5"; + version = "1.35.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 2e2b736f3..1558a1c9e 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.5" +.TH rtx 1 "rtx 1.35.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -151,6 +151,6 @@ Examples: $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to node\-20.x .SH VERSION -v1.35.5 +v1.35.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e61dca73c..e93705ef3 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.5 +Version: 1.35.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 8ecf61feade91bd62ebbd79aea21d208dd2012ed Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:23:37 -0500 Subject: [PATCH 0913/1891] docs --- README.md | 2 +- man/man1/rtx.1 | 3 +-- src/cli/mod.rs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 39ec7e87e..00705a625 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ See [plugins](#plugins) below. rtx use node@latest Use latest node in current directory rtx use -g node@system Use system node as global default - rtx x node@20 -- node app.js Run `node app.js` with the PATH pointing to node-20.x + rtx x node@20 -- node app.js Run `node app.js` node-20.x on PATH ## Installation diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 1558a1c9e..c7ebc386c 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -148,8 +148,7 @@ Examples: $ rtx use \-g node@20 Use node\-20.x as default $ rtx use node@latest Use latest node in current directory $ rtx use \-g node@system Use system node everywhere unless overridden - $ rtx x node@20 \-\- node app.js Run `node app.js` with PATH pointing to - node\-20.x + $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION v1.35.6 .SH AUTHORS diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e7a0d7e33..1ee3d91d9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -252,8 +252,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ rtx use -g node@20 Use node-20.x as default $ rtx use node@latest Use latest node in current directory $ rtx use -g node@system Use system node everywhere unless overridden - $ rtx x node@20 -- node app.js Run `node app.js` with PATH pointing to - node-20.x + $ rtx x node@20 -- node app.js Run `node app.js` with node-20.x on PATH "# ); From f355cded5d0536d0a2b544bb38dbbfb4acc6b428 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 18:20:25 -0500 Subject: [PATCH 0914/1891] fixing standalone script to use the correct shasums --- scripts/render-install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/render-install.sh b/scripts/render-install.sh index 011c8a8dc..f41783063 100755 --- a/scripts/render-install.sh +++ b/scripts/render-install.sh @@ -3,9 +3,9 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=$RTX_VERSION \ - RTX_CHECKSUM_LINUX_X86_64=$(grep linux-x64.tar.gz "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ - RTX_CHECKSUM_LINUX_ARM64=$(grep linux-arm64.tar.gz "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ - RTX_CHECKSUM_MACOS_X86_64=$(grep macos-x64.tar.gz "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ - RTX_CHECKSUM_MACOS_ARM64=$(grep macos-arm64.tar.gz "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v.*linux-x64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v.*linux-arm64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v.*macos-x64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v.*macos-arm64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ Date: Sun, 30 Jul 2023 18:22:09 -0500 Subject: [PATCH 0915/1891] chore: Release --- Cargo.lock | 17 ++++++++++++----- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70467e120..4c82b8987 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,6 +450,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "deranged" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" + [[package]] name = "dialoguer" version = "0.10.4" @@ -1670,7 +1676,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.6" +version = "1.35.7" dependencies = [ "base64", "built", @@ -2152,10 +2158,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" dependencies = [ + "deranged", "itoa", "libc", "num_threads", @@ -2172,9 +2179,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] diff --git a/Cargo.toml b/Cargo.toml index a8ebf5e44..1ab3140c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.6" +version = "1.35.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 00705a625..7b930270f 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.6 +rtx 1.35.7 ``` Hook rtx into to your shell (pick the right one for your shell): @@ -331,7 +331,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.6/rtx-v1.35.6-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.7/rtx-v1.35.7-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index e3b48f0d0..6391f8b5e 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.6"; + version = "1.35.7"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index c7ebc386c..7bebfedfc 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.6" +.TH rtx 1 "rtx 1.35.7" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v1.35.6 +v1.35.7 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e93705ef3..6bf26c246 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.6 +Version: 1.35.7 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 1e42faf0c50862691700fa2e855a2dc457c90013 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 21:06:57 -0500 Subject: [PATCH 0916/1891] looser dependency versions --- Cargo.toml | 84 +++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1ab3140c4..d3d11de32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,65 +36,65 @@ path = "src/main.rs" [dependencies] base64 = "<0.22" -chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] } -clap = { version = "4.3.19", features = ["env", "derive", "string"] } -clap_complete = "4.2.3" -color-eyre = "0.6.2" -color-print = "0.3.4" -console = "0.15.7" -ctrlc = "3.4.0" -dialoguer = { version = "0.10.2", features = [] } -dirs-next = "2.0.0" -dotenvy = "0.15.6" -duct = "0.13.5" -filetime = "0.2.19" -flate2 = "1.0.26" -fslock = "0.2.1" -humantime = "2.1.0" -indenter = "0.3.3" -indexmap = { version = "2.0.0", features = ["serde"] } -indicatif = { version = "0.17.5", features = ["default", "improved_unicode"] } +chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } +clap = { version = "4.3", features = ["env", "derive", "string"] } +clap_complete = "4.2" +color-eyre = "0.6" +color-print = "0.3" +console = "0.15" +ctrlc = "3.4" +dialoguer = { version = "0.10", features = [] } +dirs-next = "2.0" +dotenvy = "0.15" +duct = "0.13" +filetime = "0.2" +flate2 = "1.0" +fslock = "0.2" +humantime = "2.1" +indenter = "0.3" +indexmap = { version = "2.0", features = ["serde"] } +indicatif = { version = "0.17", features = ["default", "improved_unicode"] } indoc = "<3" -itertools = "0.11.0" -log = "0.4.19" -num_cpus = "1.14.0" -once_cell = "1.18.0" +itertools = "0.11" +log = "0.4" +num_cpus = "1.14" +once_cell = "1.18" openssl = { version = "0.10", optional = true } -path-absolutize = "3.1.0" -rayon = "1.6.1" -regex = "1.8.4" +path-absolutize = "3.1" +rayon = "1.6" +regex = "1.8" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", "json", ] } rmp-serde = "1.1.2" self_update = { version = "0.37.0", default-features = false, optional = true } -serde = "1.0.174" -serde_derive = "1.0.152" -serde_json = "1.0.103" -sha2 = "0.10.7" -shell-escape = "0.1.4" -shell-words = "1.1.0" -simplelog = { version = "0.12.0" } -tar = "0.4.38" -tera = { version = "1.12.1", default-features = false } -terminal_size = "0.2.1" -thiserror = "1.0.44" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" +sha2 = "0.10" +shell-escape = "0.1" +shell-words = "1.1" +simplelog = { version = "0.12" } +tar = "0.4" +tera = { version = "1.12", default-features = false } +terminal_size = "0.2" +thiserror = "1.0" toml = "<0.8" toml_edit = "<0.20" -url = "2.4.0" -versions = "5.0.0" +url = "2.4" +versions = "5.0" [target.'cfg(unix)'.dependencies] -exec = "0.3.1" +exec = "0.3" [build-dependencies] -built = { version = "0.6.1", features = ["chrono", "git2"] } +built = { version = "0.6", features = ["chrono", "git2"] } [dev-dependencies] ctor = "<0.3" -insta = "1.31.0" -pretty_assertions = "1.3.0" +insta = "1.31" +pretty_assertions = "1.4" [features] default = ["native-tls"] From 283b57821d5252c23c2738aab05a9f9c1fb94e73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Jul 2023 02:19:55 +0000 Subject: [PATCH 0917/1891] chore(deps): bump serde from 1.0.178 to 1.0.179 (#748) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.178 to 1.0.179. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.178...v1.0.179) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c82b8987..3b0a16908 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1899,18 +1899,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.178" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348" +checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.178" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b" +checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c" dependencies = [ "proc-macro2", "quote", From 9eb124cce23f77a78f08c04f3977f710ea25c613 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 21:37:24 -0500 Subject: [PATCH 0918/1891] add retina tags for logo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b930270f..70035805a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

- - rtx logo + + rtx logo
Crates.io From 74f6b38bfeabd0c6bebbf1b9bdf221d88bce3ebc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 22:02:18 -0500 Subject: [PATCH 0919/1891] clarify rtx does not modify cd --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 70035805a..d14e80c62 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ _New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginn rtx is a tool for managing programming language and tool versions. For example, use this to install a particular version of node.js and ruby for a project. Using `rtx activate`, you can have your shell automatically switch to the correct node and ruby versions when you `cd` into the project's -directory. Other projects on your machine can use a different set of versions. +directory[^cd]. Other projects on your machine can use a different set of versions. rtx is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecosystem](https://github.com/asdf-vm/asdf-plugins) under the hood. However, it is _much_ faster than asdf and has a more friendly user experience. @@ -198,7 +198,7 @@ with asdf `.tool-versions` files. It can also use idiomatic version files like ` rtx hooks into your shell (with `rtx activate zsh`) and sets the `PATH` environment variable to point your shell to the correct runtime binaries. When you `cd` into a -directory containing a `.tool-versions`/`.rtx.toml` file, rtx will automatically set the +directory[^cd] containing a `.tool-versions`/`.rtx.toml` file, rtx will automatically set the appropriate tool versions in `PATH`. After activating, every time your prompt displays it will call `rtx hook-env` to fetch new @@ -214,6 +214,9 @@ You should note that rtx does not directly install these tools. Instead, it leverages plugins to install runtimes. See [plugins](#plugins) below. +[^cd]: Note that rtx does not modify "cd". It actually runs every time the prompt is _displayed_. +See the [FAQ](#what-does-rtx-activate-do). + ### Common commands rtx install node@20.0.0 Install a specific version number From 3be7ee202dfe3140b597d17f41c5bc51c7a24c8b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 22:14:50 -0500 Subject: [PATCH 0920/1891] clarify `hook-env` behavior a bit --- README.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d14e80c62..8ca628b4c 100644 --- a/README.md +++ b/README.md @@ -1137,15 +1137,31 @@ 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*. -You may think that is excessive and it should only run on `cd`, however there are many -situations where it needs to run without the directory changing, for example if the `.rtx.toml` -was modified. +It registers a shell hook to run `rtx hook-env` every time the shell prompt is displayed. +`rtx hook-env` checks the current env vars (most importantly `PATH` but there are others like +`GOROOT` or `JAVA_HOME` for some tools) and adds/removes/updates the ones that have changed. + +For example, if you `cd` into a different directory that has `java 18` instead of `java 17` +specified, just before the next prompt is displayed the shell runs: `eval "$(rtx hook-env)"` +which will execute something like this in the current shell session: + +```sh +export JAVA_HOME=~/.local/share/installs/java/18` +export PATH=~/.local/share/installs/java/18/bin:$PATH +``` + +In reality updating `PATH` is a bit more complex than that because it also needs to remove java-17, +but you get the idea. + +You may think that is excessive to run `rtx hook-env` every time the prompt is displayed +and it should only run on `cd`, however there are plenty of +situations where it needs to run without the directory changing, for example if `.tool-versions` or +`.rtx.toml` was just edited in the current shell. Note my emphasis on the word *displayed*. This means if you attempt to use `rtx activate` in a non-interactive session (like a bash script), it will never call `rtx hook-env` and in effect will never modify PATH. For this type of setup, you can either call `rtx hook-env` manually every time -you wish to update PATH, or use [shims](#shims) instead. +you wish to update PATH, or use [shims](#shims) instead (preferred). Or if you only need to use rtx for certain commands, just prefix the commands with [`rtx x --`](#rtx-exec-options-toolversion----command). @@ -1155,7 +1171,8 @@ For example, `rtx x -- npm test` or `rtx x -- ./my_script.sh`. blocking your shell every time you run a command. You can run `rtx hook-env` yourself to see what it outputs, however it is likely nothing if you're in a shell that has already been activated. -`rtx activate` also creates a shell function (in most shells) called `rtx`. This is a trick that makes it possible for `rtx shell` +`rtx activate` also creates a shell function (in most shells) called `rtx`. +This is a trick that makes it possible for `rtx shell` and `rtx deactivate` to work without wrapping them in `eval "$(rtx shell)"`. ### `rtx activate` doesn't work in `~/.profile`, `~/.bash_profile`, `~/.zprofile` From 19c60f51fc6033d04b94aa0deb04f3de43302175 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 22:15:34 -0500 Subject: [PATCH 0921/1891] typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ca628b4c..1d2f1bc18 100644 --- a/README.md +++ b/README.md @@ -1146,8 +1146,8 @@ specified, just before the next prompt is displayed the shell runs: `eval "$(rtx which will execute something like this in the current shell session: ```sh -export JAVA_HOME=~/.local/share/installs/java/18` -export PATH=~/.local/share/installs/java/18/bin:$PATH +export JAVA_HOME=$HOME/.local/share/installs/java/18` +export PATH=$HOME/.local/share/installs/java/18/bin:$PATH ``` In reality updating `PATH` is a bit more complex than that because it also needs to remove java-17, From b9c1da83733146da38b21824663a996a13745e78 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 22:16:05 -0500 Subject: [PATCH 0922/1891] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d2f1bc18..9a24ca857 100644 --- a/README.md +++ b/README.md @@ -1146,7 +1146,7 @@ specified, just before the next prompt is displayed the shell runs: `eval "$(rtx which will execute something like this in the current shell session: ```sh -export JAVA_HOME=$HOME/.local/share/installs/java/18` +export JAVA_HOME=$HOME/.local/share/installs/java/18 export PATH=$HOME/.local/share/installs/java/18/bin:$PATH ``` From dc337cb37431ec27d814fa08ad08e0ec77402f5e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 22:20:52 -0500 Subject: [PATCH 0923/1891] docs --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9a24ca857..2b2db4e74 100644 --- a/README.md +++ b/README.md @@ -1158,18 +1158,17 @@ and it should only run on `cd`, however there are plenty of situations where it needs to run without the directory changing, for example if `.tool-versions` or `.rtx.toml` was just edited in the current shell. -Note my emphasis on the word *displayed*. This means if you attempt to use `rtx activate` in a +Because it runs on prompt display, if you attempt to use `rtx activate` in a non-interactive session (like a bash script), it will never call `rtx hook-env` and in effect will -never modify PATH. For this type of setup, you can either call `rtx hook-env` manually every time -you wish to update PATH, or use [shims](#shims) instead (preferred). - +never modify PATH because it never displays a prompt. For this type of setup, you can either call +`rtx hook-env` manually every time you wish to update PATH, or use [shims](#shims) instead (preferred). Or if you only need to use rtx for certain commands, just prefix the commands with [`rtx x --`](#rtx-exec-options-toolversion----command). For example, `rtx x -- npm test` or `rtx x -- ./my_script.sh`. `rtx hook-env` will exit early in different situations if no changes have been made. This prevents -blocking your shell every time you run a command. You can run `rtx hook-env` yourself to see what it -outputs, however it is likely nothing if you're in a shell that has already been activated. +adding latency to your shell prompt every time you run a command. You can run `rtx hook-env` yourself +to see what it outputs, however it is likely nothing if you're in a shell that has already been activated. `rtx activate` also creates a shell function (in most shells) called `rtx`. This is a trick that makes it possible for `rtx shell` From 11c9bda1e75396b4fabb624d572d1ab97b289ef4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 30 Jul 2023 23:01:02 -0500 Subject: [PATCH 0924/1891] hide stdout when performing version checks (#749) This just cleans up install output a bit --- README.md | 2 +- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/go.rs | 2 +- src/plugins/core/java.rs | 2 +- src/plugins/core/node.rs | 2 ++ src/plugins/core/python.rs | 5 +++-- src/plugins/core/ruby.rs | 2 ++ src/tool.rs | 1 + 9 files changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2b2db4e74..69e146d5b 100644 --- a/README.md +++ b/README.md @@ -1154,7 +1154,7 @@ In reality updating `PATH` is a bit more complex than that because it also needs but you get the idea. You may think that is excessive to run `rtx hook-env` every time the prompt is displayed -and it should only run on `cd`, however there are plenty of +and it should only run on `cd`, however there are plenty of situations where it needs to run without the directory changing, for example if `.tool-versions` or `.rtx.toml` was just edited in the current shell. diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 55b927a73..0ce292b3b 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -50,6 +50,7 @@ impl BunPlugin { } fn test_bun(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("bun -v"); CmdLineRunner::new(&config.settings, self.bun_bin(tv)) .with_pr(pr) .arg("-v") @@ -89,7 +90,6 @@ impl BunPlugin { } fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("verifying"); self.test_bun(config, tv, pr) } } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 3cadfcfc0..9598186de 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -53,6 +53,7 @@ impl DenoPlugin { } fn test_deno(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("deno -V"); CmdLineRunner::new(&config.settings, self.deno_bin(tv)) .with_pr(pr) .arg("-V") @@ -89,7 +90,6 @@ impl DenoPlugin { } fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("verifying"); self.test_deno(config, tv, pr) } } diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index db9fc3c0b..43b502fe5 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -82,6 +82,7 @@ impl GoPlugin { } fn test_go(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("go version"); CmdLineRunner::new(&config.settings, self.go_bin(tv)) .with_pr(pr) .arg("version") @@ -122,7 +123,6 @@ impl GoPlugin { } fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("verifying"); self.test_go(config, tv, pr)?; self.install_default_packages(&config.settings, tv, pr) } diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 8beb7d8f2..f137dc5a2 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -161,7 +161,7 @@ impl JavaPlugin { } fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("verifying"); + pr.set_message("java -version"); self.test_java(config, tv, pr) } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index fa0100125..0b53ab103 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -138,6 +138,7 @@ impl NodePlugin { } fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("node -v"); CmdLineRunner::new(&config.settings, self.node_path(tv)) .with_pr(pr) .arg("-v") @@ -145,6 +146,7 @@ impl NodePlugin { } fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("npm -v"); CmdLineRunner::new(&config.settings, self.npm_path(tv)) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 9b5114233..2cfd2bebf 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -140,7 +140,8 @@ impl PythonPlugin { Ok(symlink_target == target) } - fn test_python(&self, config: &&Config, tv: &ToolVersion) -> Result<()> { + fn test_python(&self, config: &&Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("python --version"); CmdLineRunner::new(&config.settings, self.python_path(tv)) .arg("--version") .execute() @@ -200,7 +201,7 @@ impl Plugin for PythonPlugin { } } cmd.execute()?; - self.test_python(&config, tv)?; + self.test_python(&config, tv, pr)?; self.get_virtualenv(config, tv, Some(pr))?; self.install_default_packages(&config.settings, tv, pr)?; Ok(()) diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 46d2caa28..af65ae20f 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -190,6 +190,7 @@ impl RubyPlugin { } fn test_ruby(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("ruby -v"); CmdLineRunner::new(&config.settings, self.ruby_path(tv)) .with_pr(pr) .arg("-v") @@ -197,6 +198,7 @@ impl RubyPlugin { } fn test_gem(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("gem -v"); CmdLineRunner::new(&config.settings, self.gem_path(tv)) .with_pr(pr) .arg("-v") diff --git a/src/tool.rs b/src/tool.rs index 4c8d8342b..e4ae9f9f4 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -235,6 +235,7 @@ impl Tool { if let Err(err) = fs::remove_file(self.incomplete_file_path(tv)) { debug!("error removing incomplete file: {:?}", err); } + pr.set_message(""); pr.finish(); Ok(()) From 325c26b5e498664b659d95601ffb3eddc6d2b8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Mon, 31 Jul 2023 21:48:41 +0300 Subject: [PATCH 0925/1891] Spelling fixes (#752) --- deny.toml | 4 ++-- docs/node.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deny.toml b/deny.toml index a694781d8..64945b22f 100644 --- a/deny.toml +++ b/deny.toml @@ -183,11 +183,11 @@ wildcards = "allow" # * all - Both lowest-version and simplest-path are used highlight = "all" # The default lint level for `default` features for crates that are members of -# the workspace that is being checked. This can be overriden by allowing/denying +# the workspace that is being checked. This can be overridden by allowing/denying # `default` on a crate-by-crate basis if desired. workspace-default-features = "allow" # The default lint level for `default` features for external crates that are not -# members of the workspace. This can be overriden by allowing/denying `default` +# members of the workspace. This can be overridden by allowing/denying `default` # on a crate-by-crate basis if desired. external-default-features = "allow" # List of crates that are allowed. Use with care! diff --git a/docs/node.md b/docs/node.md index ad0d4f08c..87eef09e4 100644 --- a/docs/node.md +++ b/docs/node.md @@ -29,7 +29,7 @@ Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) - `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores - `RTX_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` - `NODEJS_ORG_MIRROR` [string]: (Legacy) overrides the default mirror used for downloading the - distibutions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var + distributions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var ## Default node packages From d05027a86bc59bb69af4a0e86a1a46018e877168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Mon, 31 Jul 2023 23:00:21 +0300 Subject: [PATCH 0926/1891] Promote /etc/apt/keyrings over /usr/share/keyrings (#753) Per https://manpages.debian.org/bookworm/apt/sources.list.5.en.html#THE_DEB_AND_DEB-SRC_TYPES:_OPTIONS > The recommended locations for keyrings are /usr/share/keyrings for > keyrings managed by packages, and /etc/apt/keyrings for keyrings > managed by the system operator. Some older distros may not have the dir, create it. --- CONTRIBUTING.md | 5 +++-- README.md | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2e6510e26..ca48ecdc8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,8 +107,9 @@ This is for arm64, but you can change the arch to amd64 if you want. finch run -ti --rm ubuntu apt update -y apt install gpg sudo wget curl -wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +sudo install -dm 755 /etc/apt/keyrings +wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list apt update apt install -y rtx rtx -V diff --git a/README.md b/README.md index 69e146d5b..db66ba874 100644 --- a/README.md +++ b/README.md @@ -343,8 +343,9 @@ chmod +x /usr/local/bin/rtx For installation on Ubuntu/Debian: ``` -wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +sudo install -dm 755 /etc/apt/keyrings +wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list sudo apt update sudo apt install -y rtx ``` @@ -354,7 +355,7 @@ sudo apt install -y rtx > If you're on arm64 you'll need to run the following: > > ``` -> echo "deb [signed-by=/usr/share/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` #### dnf From 80d8f77628bbc4bf60f2a003a599188e56d28984 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:14:27 -0500 Subject: [PATCH 0927/1891] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db66ba874..624a319fe 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,10 @@ $ rtx --version rtx 1.35.7 ``` -Hook rtx into to your shell (pick the right one for your shell): +Hook rtx into your shell (pick the right one for your shell): ```sh-session +# note this assumes rtx is located at ~/bin/rtx echo 'eval "$(~/bin/rtx activate bash)"' >> ~/.bashrc echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish From 24a1be1bc32238c8346767e17c25c824bb64092a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:41:29 -0500 Subject: [PATCH 0928/1891] added node lts/* alias (#751) Fixes #750 --- src/plugins/core/node.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 0b53ab103..a612a99d8 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -210,7 +210,10 @@ impl Plugin for NodePlugin { fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { let body = fs::read_to_string(path)?; // trim "v" prefix - Ok(body.trim().strip_prefix('v').unwrap_or(&body).to_string()) + let body = body.trim().strip_prefix('v').unwrap_or(&body); + // replace lts/* with lts + let body = body.replace("lts/*", "lts"); + Ok(body.to_string()) } fn external_commands(&self) -> Result> { From d1f299023335ec9f2b52623cdefc69e73ddcd77a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:10:01 -0500 Subject: [PATCH 0929/1891] hide nvm-style "lts/*" aliases (#756) --- README.md | 18 +++++++++--------- src/cli/alias/get.rs | 2 +- src/cli/alias/ls.rs | 8 +++++--- src/cli/alias/set.rs | 2 +- ...rtx__cli__alias__set__tests__alias_set.snap | 8 -------- ..._cli__alias__unset__tests__alias_unset.snap | 8 -------- src/cli/alias/unset.rs | 2 +- src/cli/doctor.rs | 1 - src/cli/plugins/ls.rs | 6 +----- src/config/mod.rs | 9 --------- 10 files changed, 18 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 624a319fe..1fd81d7c0 100644 --- a/README.md +++ b/README.md @@ -863,8 +863,8 @@ Enables experimental features. ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS -versions of runtimes. For example, you may want to specify `lts/hydrogen` as the version for node@20.x -so you can use set it with `node lts/hydrogen` in `.tool-versions`/`.rtx.toml`. +versions of runtimes. For example, you may want to specify `lts-hydrogen` as the version for node@20.x +so you can use set it with `node lts-hydrogen` in `.tool-versions`/`.rtx.toml`. User aliases can be created by adding an `alias.` section to `~/.config/rtx/config.toml`: @@ -879,9 +879,9 @@ versions: ```bash #!/usr/bin/env bash -echo "lts/hydrogen 18" -echo "lts/gallium 16" -echo "lts/fermium 14" +echo "lts-hydrogen 18" +echo "lts-gallium 16" +echo "lts-fermium 14" ``` > **Note:** @@ -1582,7 +1582,7 @@ Arguments: The alias to show Examples: - $ rtx alias get node lts/hydrogen + $ rtx alias get node lts-hydrogen 20.0.0 ``` ### `rtx alias ls [OPTIONS]` @@ -1605,7 +1605,7 @@ Options: Examples: $ rtx aliases - node lts/hydrogen 20.0.0 + node lts-hydrogen 20.0.0 ``` ### `rtx alias set ` @@ -1627,7 +1627,7 @@ Arguments: The value to set the alias to Examples: - $ rtx alias set node lts/hydrogen 18.0.0 + $ rtx alias set node lts-hydrogen 18.0.0 ``` ### `rtx alias unset ` @@ -1646,7 +1646,7 @@ Arguments: The alias to remove Examples: - $ rtx alias unset node lts/hydrogen + $ rtx alias unset node lts-hydrogen ``` ### `rtx bin-paths` diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 951c46f95..fe157093c 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -31,7 +31,7 @@ impl Command for AliasGet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias get node lts/hydrogen + $ rtx alias get node lts-hydrogen 20.0.0 "# ); diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 4b6da6d2a..cc118ca71 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -28,11 +28,13 @@ impl Command for AliasLs { if plugin_name != plugin { continue; } - } else if config.is_plugin_hidden(plugin_name) { - continue; } for (from, to) in aliases.iter() { + if plugin_name == "node" && from.starts_with("lts/") { + // hide the nvm-style aliases so only asdf-style ones display + continue; + } rtxprintln!(out, "{:20} {:20} {}", plugin_name, from, to); } } @@ -43,7 +45,7 @@ impl Command for AliasLs { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx aliases - node lts/hydrogen 20.0.0 + node lts-hydrogen 20.0.0 "# ); diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 0028a32ed..70e3baa6d 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -30,7 +30,7 @@ impl Command for AliasSet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias set node lts/hydrogen 18.0.0 + $ rtx alias set node lts-hydrogen 18.0.0 "# ); diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 795572119..a3e65eb2e 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -12,14 +12,6 @@ node lts-erbium 12 node lts-fermium 14 node lts-gallium 16 node lts-hydrogen 18 -node lts/argon 4 -node lts/boron 6 -node lts/carbon 8 -node lts/dubnium 10 -node lts/erbium 12 -node lts/fermium 14 -node lts/gallium 16 -node lts/hydrogen 18 tiny lts 3.1.0 tiny lts-prev 2.0.0 tiny my/alias 3.0 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index 5d4a90e93..2f8d56f55 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -12,14 +12,6 @@ node lts-erbium 12 node lts-fermium 14 node lts-gallium 16 node lts-hydrogen 18 -node lts/argon 4 -node lts/boron 6 -node lts/carbon 8 -node lts/dubnium 10 -node lts/erbium 12 -node lts/fermium 14 -node lts/gallium 16 -node lts/hydrogen 18 tiny lts 3.1.0 tiny lts-prev 2.0.0 diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 41d44bedb..4c4c104bc 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -26,7 +26,7 @@ impl Command for AliasUnset { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias unset node lts/hydrogen + $ rtx alias unset node lts-hydrogen "# ); diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 999e3a0e9..594feecc3 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -118,7 +118,6 @@ fn render_plugins(config: &Config) -> String { .tools .values() .filter(|p| p.is_installed()) - .filter(|p| !config.is_plugin_hidden(&p.name)) .collect::>(); let max_plugin_name_len = plugins.iter().map(|p| p.name.len()).max().unwrap_or(0) + 2; for p in plugins { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 2d207ef27..4f9a32fa8 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -43,11 +43,7 @@ impl Command for PluginsLs { .run(config, out); } - let mut plugins = config - .tools - .values() - .filter(|p| !config.is_plugin_hidden(p.plugin.name())) - .collect::>(); + let mut plugins = config.tools.values().collect::>(); if self.core { plugins.retain(|p| matches!(p.plugin.get_type(), PluginType::Core)); diff --git a/src/config/mod.rs b/src/config/mod.rs index 04367fef2..719b10d7d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -229,15 +229,6 @@ impl Config { Ok(config_files) } - pub fn is_plugin_hidden(&self, plugin_name: &PluginName) -> bool { - self.tools.get(plugin_name).map_or(false, |tool| { - if matches!(tool.plugin.get_type(), PluginType::External) { - return false; - } - plugin_name == "nodejs" || plugin_name == "golang" - }) - } - pub fn rebuild_shims_and_runtime_symlinks(&mut self) -> Result<()> { let ts = crate::toolset::ToolsetBuilder::new().build(self)?; crate::shims::reshim(self, &ts)?; From d15c813e45438ff24e254226c21b6c9c407587c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Tue, 1 Aug 2023 21:54:59 +0300 Subject: [PATCH 0930/1891] Document RTX_GO_SKIP_CHECKSUM default, and RTX_GO_DOWNLOAD_MIRROR (#757) --- docs/go.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/go.md b/docs/go.md index 15f20ada6..f53a3a1de 100644 --- a/docs/go.md +++ b/docs/go.md @@ -21,8 +21,9 @@ $ rtx use -g go@1.20 ## Configuration -- `RTX_GO_SKIP_CHECKSUM` [bool]: skips checksum verification of downloaded go tarballs +- `RTX_GO_SKIP_CHECKSUM` [bool]: skips checksum verification of downloaded go tarballs, defaults to false - `RTX_GO_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-go-packages` +- `RTX_GO_DOWNLOAD_MIRROR` [string]: location to download go from, defaults to `https://dl.google.com/go` ## Default packages From 84a593fdc31fa4bc97cb81353253e13c565d3143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Tue, 1 Aug 2023 21:55:23 +0300 Subject: [PATCH 0931/1891] Improve bash _rtx_hook PROMPT_COMMAND insertion (#755) Remove unnecessary use of a regex, match stricter. --- src/shell/bash.rs | 2 +- src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap | 2 +- src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 3e87ec826..7ff8529bd 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -42,7 +42,7 @@ impl Shell for Bash { eval "$(rtx hook-env{status} -s bash)"; return $previous_exit_status; }}; - if ! [[ "${{PROMPT_COMMAND:-}}" =~ _rtx_hook ]]; then + if [[ ";${{PROMPT_COMMAND:-}};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" fi "#}); diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 87e882e54..cdd1d50f6 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -29,7 +29,7 @@ _rtx_hook() { eval "$(rtx hook-env --status -s bash)"; return $previous_exit_status; }; -if ! [[ "${PROMPT_COMMAND:-}" =~ _rtx_hook ]]; then +if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index 1bbef6267..790a2a9cb 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -28,7 +28,7 @@ _rtx_hook() { eval "$(rtx hook-env --status -s bash)"; return $previous_exit_status; }; -if ! [[ "${PROMPT_COMMAND:-}" =~ _rtx_hook ]]; then +if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi From 3d305dc56207f07f9bb744f93b5f0c89aef0e267 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 1 Aug 2023 13:57:23 -0500 Subject: [PATCH 0932/1891] chore: Release --- Cargo.lock | 54 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b0a16908..e342aa2ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,7 +257,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -437,7 +437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -699,7 +699,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1167,9 +1167,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "log" @@ -1336,7 +1336,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1405,9 +1405,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ "thiserror", "ucd-trie", @@ -1415,9 +1415,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -1425,22 +1425,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] name = "pest_meta" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", @@ -1676,7 +1676,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.7" +version = "1.35.8" dependencies = [ "base64", "built", @@ -1760,7 +1760,7 @@ dependencies = [ "bitflags 2.3.3", "errno 0.3.2", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys 0.4.5", "windows-sys 0.48.0", ] @@ -1899,22 +1899,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.179" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0" +checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.179" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c" +checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -2058,9 +2058,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -2144,7 +2144,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -2538,7 +2538,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -2572,7 +2572,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index d3d11de32..4fc69fa4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.7" +version = "1.35.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 1fd81d7c0..aa699af44 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.7 +rtx 1.35.8 ``` Hook rtx into your shell (pick the right one for your shell): @@ -335,7 +335,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.7/rtx-v1.35.7-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v1.35.8/rtx-v1.35.8-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 6391f8b5e..63c262d9c 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.7"; + version = "1.35.8"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 7bebfedfc..a96107714 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.7" +.TH rtx 1 "rtx 1.35.8" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v1.35.7 +v1.35.8 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6bf26c246..0bcb02c65 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.7 +Version: 1.35.8 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From c12c763513e72a5ad520ab52b5c4a2d4d41e0042 Mon Sep 17 00:00:00 2001 From: ProducerMatt <58014742+ProducerMatt@users.noreply.github.com> Date: Wed, 2 Aug 2023 10:06:27 -0500 Subject: [PATCH 0933/1891] Nix: fix missing OpenSSL (#759) --- default.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/default.nix b/default.nix index 63c262d9c..529b1ad8e 100644 --- a/default.nix +++ b/default.nix @@ -1,4 +1,10 @@ { pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: +let + libssl = with pkgs; symlinkJoin { + name = "libssl-merged"; + paths = [ openssl.out openssl.dev ]; + }; +in rustPlatform.buildRustPackage { pname = "rtx"; version = "1.35.8"; @@ -9,6 +15,7 @@ rustPlatform.buildRustPackage { lockFile = ./Cargo.lock; }; + nativeBuildInputs = with pkgs; [ pkg-config ]; buildInputs = with pkgs; [ coreutils bash @@ -40,6 +47,7 @@ rustPlatform.buildRustPackage { # Need this to ensure openssl-src's build uses an available version of `perl` # https://github.com/alexcrichton/openssl-src-rs/issues/45 OPENSSL_SRC_PERL = "${perl}/bin/perl"; + OPENSSL_DIR = "${libssl}"; meta = with lib; { description = "Polyglot runtime manager (asdf rust clone)"; From 25fa4ce26fc835e9a5bbd0d9561520e73ca6c6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Thu, 3 Aug 2023 00:24:02 +0300 Subject: [PATCH 0934/1891] Add ability to not touch $GOROOT and $GOPATH (#760) Closes https://github.com/jdxcode/rtx/issues/754 --- docs/go.md | 2 ++ src/env.rs | 4 ++++ src/plugins/core/go.rs | 24 ++++++++++++++++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/go.md b/docs/go.md index f53a3a1de..4a16f2308 100644 --- a/docs/go.md +++ b/docs/go.md @@ -24,6 +24,8 @@ $ rtx use -g go@1.20 - `RTX_GO_SKIP_CHECKSUM` [bool]: skips checksum verification of downloaded go tarballs, defaults to false - `RTX_GO_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-go-packages` - `RTX_GO_DOWNLOAD_MIRROR` [string]: location to download go from, defaults to `https://dl.google.com/go` +- `RTX_GO_SET_GOROOT` [bool]: set `$GOROOT` to the rtx go installs go root dir, defaults to true +- `RTX_GO_SET_GOPATH` [bool]: set `$GOPATH` to the rtx go installs packages dir, defaults to true ## Default packages diff --git a/src/env.rs b/src/env.rs index 3aa81fd9b..718a2ad48 100644 --- a/src/env.rs +++ b/src/env.rs @@ -186,6 +186,10 @@ pub static RTX_GO_REPO: Lazy = pub static RTX_GO_DOWNLOAD_MIRROR: Lazy = Lazy::new(|| { var("RTX_GO_DOWNLOAD_MIRROR").unwrap_or_else(|_| "https://dl.google.com/go".into()) }); +pub static RTX_GO_SET_GOROOT: Lazy> = + Lazy::new(|| var_option_bool("RTX_GO_SET_GOROOT")); +pub static RTX_GO_SET_GOPATH: Lazy> = + Lazy::new(|| var_option_bool("RTX_GO_SET_GOPATH")); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Confirm { diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 43b502fe5..9d0f62e39 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -70,12 +70,18 @@ impl GoPlugin { } else { format!("{}@latest", package) }; + let mut env = HashMap::new(); + if *env::RTX_GO_SET_GOROOT != Some(false) { + env.insert("GOROOT", self.goroot(tv)); + } + if *env::RTX_GO_SET_GOPATH != Some(false) { + env.insert("GOPATH", self.gopath(tv)); + } CmdLineRunner::new(settings, self.go_bin(tv)) .with_pr(pr) .arg("install") .arg(package) - .env("GOROOT", self.goroot(tv)) - .env("GOPATH", self.gopath(tv)) + .envs(env) .execute()?; } Ok(()) @@ -167,21 +173,23 @@ impl Plugin for GoPlugin { } fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { - Ok(vec![ - self.goroot(tv).join("bin"), - self.gopath(tv).join("bin"), - ]) + // goroot/bin must always be included, irrespective of RTX_GO_SET_GOROOT + let mut paths = vec![self.goroot(tv).join("bin")]; + if *env::RTX_GO_SET_GOPATH != Some(false) { + paths.push(self.gopath(tv).join("bin")); + } + Ok(paths) } fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { let mut map = HashMap::new(); - if env::PRISTINE_ENV.get("GOROOT").is_none() { + if env::PRISTINE_ENV.get("GOROOT").is_none() && *env::RTX_GO_SET_GOROOT != Some(false) { map.insert( "GOROOT".to_string(), self.goroot(tv).to_string_lossy().to_string(), ); }; - if env::PRISTINE_ENV.get("GOPATH").is_none() { + if env::PRISTINE_ENV.get("GOPATH").is_none() && *env::RTX_GO_SET_GOPATH != Some(false) { map.insert( "GOPATH".to_string(), self.gopath(tv).to_string_lossy().to_string(), From 6f2132a40f7bd610ffc19cbb0fd95547f45fc5b7 Mon Sep 17 00:00:00 2001 From: Ben Woodward Date: Thu, 3 Aug 2023 23:29:37 +0100 Subject: [PATCH 0935/1891] fix: deploy arch zsh autocompletion corrently (#763) --- scripts/release-aur-bin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 3d734a37d..bd99f4777 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -41,7 +41,7 @@ package() { install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" install -Dm644 rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" install -Dm644 rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" - install -Dm644 _rtx "\$pkgdir/usr/share/zsh/site-functions/_zsh" + install -Dm644 _rtx "\$pkgdir/usr/share/zsh/site-functions/_rtx" } check() { From bef3f315b4b48209a4d59f004945855224f3b6c7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 3 Aug 2023 19:47:07 -0500 Subject: [PATCH 0936/1891] use "#" as delimiter for branch on plugin update (#764) --- README.md | 4 ++-- src/cli/plugins/update.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index aa699af44..a11feb1f9 100644 --- a/README.md +++ b/README.md @@ -2214,9 +2214,9 @@ Arguments: Plugin(s) to update Examples: - $ rtx plugins update # update all plugins + $ rtx plugins update # update all plugins $ rtx plugins update node # update only node - $ rtx plugins update node@beta # specify a ref + $ rtx plugins update node#beta # specify a ref ``` ### `rtx prune [OPTIONS] [PLUGINS]...` diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index e8ac9f112..dc24279d3 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -27,7 +27,7 @@ impl Command for Update { Some(plugins) => plugins .into_iter() .map(|p| { - let (p, ref_) = match p.split_once('@') { + let (p, ref_) = match p.split_once('#') { Some((p, ref_)) => (p, Some(ref_.to_string())), None => (p.as_str(), None), }; @@ -55,9 +55,9 @@ impl Command for Update { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx plugins update # update all plugins + $ rtx plugins update # update all plugins $ rtx plugins update node # update only node - $ rtx plugins update node@beta # specify a ref + $ rtx plugins update node#beta # specify a ref "# ); From d4a5fae41033f1bf3f434a8fa15fe3c98a4165ed Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 3 Aug 2023 19:47:26 -0500 Subject: [PATCH 0937/1891] reuse existing branch on plugin-update (#765) Fixes #762 --- src/git.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/git.rs b/src/git.rs index ee226672c..9c2877eb4 100644 --- a/src/git.rs +++ b/src/git.rs @@ -19,22 +19,8 @@ impl Git { self.dir.join(".git").is_dir() } - pub fn remote_default_branch(&self) -> Result { - let branch = cmd!( - "git", - "-C", - &self.dir, - "symbolic-ref", - "refs/remotes/origin/HEAD" - ) - .read()?; - - let branch = branch.rsplit_once('/').unwrap().1; - Ok(branch.to_string()) - } - pub fn update(&self, gitref: Option) -> Result<(String, String)> { - let gitref = gitref.map_or_else(|| self.remote_default_branch(), Ok)?; + let gitref = gitref.map_or_else(|| self.current_branch(), Ok)?; debug!("updating {} to {}", self.dir.display(), gitref); self.run_git_command(&[ "fetch", @@ -75,6 +61,11 @@ impl Git { Ok(()) } + pub fn current_branch(&self) -> Result { + let branch = cmd!("git", "-C", &self.dir, "branch", "--show-current").read()?; + debug!("current branch for {}: {}", self.dir.display(), &branch); + Ok(branch) + } pub fn current_sha(&self) -> Result { let sha = cmd!("git", "-C", &self.dir, "rev-parse", "HEAD").read()?; debug!("current sha for {}: {}", self.dir.display(), &sha); From c452ea25db30ce5e0a33375e7965261e690397d9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:57:19 -0500 Subject: [PATCH 0938/1891] use a different sample go package (#777) this one is failing for some reason it seems --- e2e/test_go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/test_go b/e2e/test_go index 0756fea8f..feeeb2103 100755 --- a/e2e/test_go +++ b/e2e/test_go @@ -6,7 +6,7 @@ export RTX_EXPERIMENTAL=1 export RTX_GO_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-go-packages" cat >"$RTX_GO_DEFAULT_PACKAGES_FILE" < Date: Tue, 8 Aug 2023 17:09:16 -0700 Subject: [PATCH 0939/1891] improve shim error message (#779) in the event that a not-installed tool version was selected rtx was complaining no global version selected which was not the case This fixes that by displaying all of the tools with shim names that match --- src/shims.rs | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/shims.rs b/src/shims.rs index 30d561ea7..770d3ae8e 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -6,6 +6,7 @@ use std::process::exit; use color_eyre::eyre::{eyre, Result}; use indoc::formatdoc; +use itertools::Itertools; use rayon::prelude::*; use crate::cli::command::Command; @@ -61,7 +62,7 @@ fn which_shim(config: &mut Config, bin_name: &str) -> Result { } } let tvs = ts.list_rtvs_with_bin(config, bin_name)?; - err_no_version_set(bin_name, tvs)?; + err_no_version_set(config, ts, bin_name, tvs)?; } Err(eyre!("{} is not a valid shim", bin_name)) } @@ -180,14 +181,38 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { Ok(()) } -fn err_no_version_set(bin_name: &str, tvs: Vec) -> Result<()> { +fn err_no_version_set( + config: &Config, + ts: Toolset, + bin_name: &str, + tvs: Vec, +) -> Result<()> { if tvs.is_empty() { return Ok(()); } - let mut msg = format!("No version is set for shim: {}\n", bin_name); - msg.push_str("Set a global default version with one of the following:\n"); - for tv in tvs { - msg.push_str(&format!("rtx use -g {}@{}\n", tv.plugin_name, tv.version)); + let missing_plugins = tvs.iter().map(|tv| &tv.plugin_name).collect::>(); + let mut missing_tools = ts + .list_missing_versions(config) + .into_iter() + .filter(|t| missing_plugins.contains(&t.plugin_name)) + .collect_vec(); + if missing_tools.is_empty() { + let mut msg = format!("No version is set for shim: {}\n", bin_name); + msg.push_str("Set a global default version with one of the following:\n"); + for tv in tvs { + msg.push_str(&format!("rtx use -g {}@{}\n", tv.plugin_name, tv.version)); + } + Err(eyre!(msg.trim().to_string())) + } else { + let mut msg = format!( + "Tool{} not installed for shim: {}\n", + if missing_tools.len() > 1 { "s" } else { "" }, + bin_name + ); + for t in missing_tools.drain(..) { + msg.push_str(&format!("Missing tool version: {}\n", t)); + } + msg.push_str("Install all missing tools with: rtx install\n"); + Err(eyre!(msg.trim().to_string())) } - Err(eyre!(msg.trim().to_string())) } From 42bb4b5f091d4298ea0f76da3e290dfe58214f79 Mon Sep 17 00:00:00 2001 From: fang duan Date: Wed, 9 Aug 2023 19:02:40 +0800 Subject: [PATCH 0940/1891] print setting up virtualenv when virtualenv not exists (#781) --- src/plugins/core/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 2cfd2bebf..a54ee3616 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -116,7 +116,7 @@ impl PythonPlugin { } } if !virtualenv.exists() || !self.check_venv_python(&virtualenv, tv)? { - debug!("setting up virtualenv at: {}", virtualenv.display()); + info!("setting up virtualenv at: {}", virtualenv.display()); let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)) .arg("-m") .arg("venv") From 7dc42ce42afafc97a901f4e0857b6d5920ccd16a Mon Sep 17 00:00:00 2001 From: fang duan Date: Thu, 10 Aug 2023 02:24:13 +0800 Subject: [PATCH 0941/1891] confirmation message for implode and prune (#785) * --dry-run by default * Revert "--dry-run by default" This reverts commit 769553efe0001ba23394fa5a3a5dba43ee0164d5. * add confirmation message for implode and prune close #710 --- src/cli/implode.rs | 16 +++++++++------- src/cli/prune.rs | 9 ++++++--- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 6a795f971..628634b7c 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -4,6 +4,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::file::remove_all; use crate::output::Output; +use crate::ui::prompt; use crate::{dirs, env}; /// Removes rtx CLI and all related data @@ -28,16 +29,17 @@ impl Command for Implode { files.push(&*dirs::CONFIG); } for f in files.into_iter().filter(|d| d.exists()) { - if f.is_dir() { + if self.dry_run { rtxprintln!(out, "rm -rf {}", f.display()); - if !self.dry_run { + } + + if f.is_dir() { + if !self.dry_run && prompt::confirm(&format!("remove {} ?", f.display()))? { remove_all(f)?; + return Ok(()); } - } else { - rtxprintln!(out, "rm -f {}", f.display()); - if !self.dry_run { - std::fs::remove_file(f)?; - } + } else if !self.dry_run && prompt::confirm(&format!("remove {} ?", f.display()))? { + std::fs::remove_file(f)?; } } diff --git a/src/cli/prune.rs b/src/cli/prune.rs index cdef2a64d..d4192015f 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -11,6 +11,7 @@ use crate::plugins::PluginName; use crate::tool::Tool; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::prompt; /// Delete unused versions of tools /// @@ -60,12 +61,14 @@ impl Prune { let mpr = MultiProgressReport::new(config.show_progress_bars()); for (p, tv) in to_delete { let mut pr = mpr.add(); - p.decorate_progress_bar(&mut pr, Some(&tv)); if self.dry_run { pr.set_prefix(format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); } - p.uninstall_version(config, &tv, &pr, self.dry_run)?; - pr.finish(); + if prompt::confirm(&format!("remove {} ?", &tv))? { + p.decorate_progress_bar(&mut pr, Some(&tv)); + p.uninstall_version(config, &tv, &pr, self.dry_run)?; + pr.finish(); + } } Ok(()) } From b7fd61adfa578193f0a0d355581003882a8de89a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 22:42:53 +0000 Subject: [PATCH 0942/1891] chore(deps): bump openssl from 0.10.55 to 0.10.56 (#775) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e342aa2ab..a0d7b5ebe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1315,9 +1315,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -1347,9 +1347,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" dependencies = [ "cc", "libc", From 8bafd8e89beb6a5fd70daddca7d84f0adf102f16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 23:27:41 +0000 Subject: [PATCH 0943/1891] chore(deps): bump serde from 1.0.180 to 1.0.182 (#772) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0d7b5ebe..b55b4663c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1899,18 +1899,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.180" +version = "1.0.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" +checksum = "bdb30a74471f5b7a1fa299f40b4bf1be93af61116df95465b2b5fc419331e430" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.180" +version = "1.0.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" +checksum = "6f4c2c6ea4bc09b5c419012eafcdb0fcef1d9119d626c8f3a0708a5b92d38a70" dependencies = [ "proc-macro2", "quote", From b2b87956ae6bfbebc227894548213880239ade84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 23:31:38 +0000 Subject: [PATCH 0944/1891] chore(deps): bump filetime from 0.2.21 to 0.2.22 (#773) --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b55b4663c..267db181e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,13 +610,13 @@ checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "filetime" -version = "0.2.21" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "windows-sys 0.48.0", ] From b21eb0f62b854198688d64d4014081871ac57540 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 23:32:46 +0000 Subject: [PATCH 0945/1891] chore(deps): bump regex from 1.9.1 to 1.9.3 (#774) --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 267db181e..6c88ee272 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1561,9 +1561,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" dependencies = [ "aho-corasick", "memchr", @@ -1573,9 +1573,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 4fc69fa4a..22c0d9c7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ once_cell = "1.18" openssl = { version = "0.10", optional = true } path-absolutize = "3.1" rayon = "1.6" -regex = "1.8" +regex = "1.9" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", "json", From a1c89779c850c1d53731d21d0fe016191d5f4ac5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 23:33:20 +0000 Subject: [PATCH 0946/1891] chore(deps): bump indicatif from 0.17.5 to 0.17.6 (#776) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c88ee272..22bcbade6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1007,9 +1007,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.5" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057" +checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" dependencies = [ "console", "instant", From 90a41f1ed1e96faa4c3670ff34b477907d4f7f66 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 10 Aug 2023 10:57:34 -0700 Subject: [PATCH 0947/1891] fix prefix: scope for golang (#789) Sadly, I cannot remember why I added this assertion in the first place. Fixes #787 --- .rtx.toml | 2 +- e2e/test_go | 2 +- src/plugins/core/go.rs | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.rtx.toml b/.rtx.toml index 09032c379..a411a6438 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -7,7 +7,7 @@ THIS_PROJECT = "{{config_root}}-{{env.PWD}}" [tools] #node = 'lts' tiny = { version = "1", foo = "bar" } -golang = { version = "latest", foo = "bar" } +golang = { version = "prefix:1.20", foo = "bar" } python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } ruby = "3.1" diff --git a/e2e/test_go b/e2e/test_go index feeeb2103..2889d97a9 100755 --- a/e2e/test_go +++ b/e2e/test_go @@ -9,7 +9,7 @@ cat >"$RTX_GO_DEFAULT_PACKAGES_FILE" < Result<()> { - assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); - let tarball_path = self.download(tv, pr)?; self.install(tv, pr, &tarball_path)?; self.verify(config, tv, pr)?; From f13e724dd340fea78a2561689844828b1eeb421f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Sun, 13 Aug 2023 10:42:02 +0300 Subject: [PATCH 0948/1891] refactor(python): invoke pip as `python -m pip` (#792) --- src/plugins/core/python.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index a54ee3616..1ed30b413 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -77,10 +77,6 @@ impl PythonPlugin { tv.install_path().join("bin/python") } - fn pip_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("bin/pip") - } - fn install_default_packages( &self, settings: &Settings, @@ -91,9 +87,10 @@ impl PythonPlugin { return Ok(()); } pr.set_message("installing default packages"); - let pip = self.pip_path(tv); - CmdLineRunner::new(settings, pip) + CmdLineRunner::new(settings, self.python_path(tv)) .with_pr(pr) + .arg("-m") + .arg("pip") .arg("install") .arg("--upgrade") .arg("-r") From 37ec08a43653a74338417f0dd40ece8c606f1728 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 02:10:35 +0000 Subject: [PATCH 0949/1891] chore(deps): bump log from 0.4.19 to 0.4.20 (#795) Bumps [log](https://github.com/rust-lang/log) from 0.4.19 to 0.4.20. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.19...0.4.20) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22bcbade6..d14269f7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1173,9 +1173,9 @@ checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" From 15eb415fcbcbdce14a227df2b42d1ba02f95ab53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 02:11:18 +0000 Subject: [PATCH 0950/1891] chore(deps): bump versions from 5.0.0 to 5.0.1 (#794) Bumps [versions](https://github.com/fosskers/rs-versions) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/fosskers/rs-versions/releases) - [Changelog](https://github.com/fosskers/rs-versions/blob/master/CHANGELOG.md) - [Commits](https://github.com/fosskers/rs-versions/compare/v5.0.0...v5.0.1) --- updated-dependencies: - dependency-name: versions dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d14269f7a..5e8f39d93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1075,15 +1075,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.11.0" @@ -1702,7 +1693,7 @@ dependencies = [ "indicatif", "indoc", "insta", - "itertools 0.11.0", + "itertools", "log", "num_cpus", "once_cell", @@ -2484,11 +2475,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "versions" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32feb3eb91e495efe5b6b2e3ca9d78db603043434a3a398a84b47de28abb2d02" +checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd" dependencies = [ - "itertools 0.10.5", + "itertools", "nom", ] From 5eb205ff8e8983af6710510a7e7e42146e5bf650 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 02:14:58 +0000 Subject: [PATCH 0951/1891] chore(deps): bump clap from 4.3.19 to 4.3.21 (#796) Bumps [clap](https://github.com/clap-rs/clap) from 4.3.19 to 4.3.21. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.3.19...v4.3.21) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e8f39d93..d3bcfbec6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.19" +version = "4.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" dependencies = [ "clap_builder", "clap_derive", @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" dependencies = [ "anstream", "anstyle", From 48436d1ba848ca00b46bca6f0ac32e2fd12e930e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 02:17:59 +0000 Subject: [PATCH 0952/1891] chore(deps): bump tar from 0.4.39 to 0.4.40 (#798) Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.39 to 0.4.40. - [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.39...0.4.40) --- updated-dependencies: - dependency-name: tar dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3bcfbec6..897332457 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2060,9 +2060,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" dependencies = [ "filetime", "libc", @@ -2795,9 +2795,9 @@ dependencies = [ [[package]] name = "xattr" -version = "0.2.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" dependencies = [ "libc", ] From c8e6d8a7bfb8712c8dd3ac8873418c9d60293fa5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 02:19:30 +0000 Subject: [PATCH 0953/1891] chore(deps): bump serde from 1.0.182 to 1.0.183 (#797) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.182 to 1.0.183. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.182...v1.0.183) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 897332457..6212e489c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,18 +1890,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.182" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb30a74471f5b7a1fa299f40b4bf1be93af61116df95465b2b5fc419331e430" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.182" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4c2c6ea4bc09b5c419012eafcdb0fcef1d9119d626c8f3a0708a5b92d38a70" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", From 151a433bad6edce530d89f55ac3f0de6eae4f73e Mon Sep 17 00:00:00 2001 From: Missing Link Date: Mon, 14 Aug 2023 14:55:22 +0800 Subject: [PATCH 0954/1891] Add MacPorts as a new installation method (#799) Signed-off-by: MisLink --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index a11feb1f9..c36711b99 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,12 @@ Alternatively, use the custom tap (which is updated immediately after a release) brew install jdxcode/tap/rtx ``` +#### MacPorts + +``` +sudo port install rtx +``` + #### Cargo Build from source with Cargo: From 045e7049fdae7f076267e74c68eb8adaa0a4a5e2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:22:17 -0500 Subject: [PATCH 0955/1891] read old cache for core plugins on "fast" commands (#802) --- README.md | 26 ++------------------------ e2e/test_bang | 6 +++--- src/cache.rs | 3 ++- src/config/settings.rs | 4 ++-- src/duration.rs | 2 +- src/env.rs | 18 ++++++++++-------- src/plugins/core/java.rs | 9 ++++----- src/plugins/core/mod.rs | 9 ++++----- src/plugins/core/python.rs | 6 ++---- src/plugins/external_plugin.rs | 9 ++------- src/toolset/tool_version.rs | 10 +++++----- 11 files changed, 37 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index c36711b99..d3b2ab34f 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,6 @@ v20.0.0 - [Plugins](#plugins) - [Plugin Options](#plugin-options) - [Versioning](#versioning) - - [Calver Breaking Changes](#calver-breaking-changes) - [Directories](#directories) - [`~/.config/rtx`](#configrtx) - [`~/.cache/rtx`](#cachertx) @@ -780,7 +779,7 @@ Disable legacy version file parsing for specific tools. Separate with `,`. #### `RTX_USE_TOML=0` Set to `1` to default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for -configuration. This will be default behavior once we hit the [Calver](#versioning) release. +configuration. For now this is not used by `rtx use` which will only use `.rtx.toml` unless `--path` is specified. @@ -922,12 +921,7 @@ Currently this only supports simple strings, but we can make it compatible with ## Versioning -rtx is currently a new project and is under very rapid development. Slight behavior changes may -occur between releases. -Features marked as "experimental" may change significantly or be removed entirely. - -Starting August 6, 2023\*, rtx will move to [Calver](https://calver.org/) versioning (`2023.6.1`). After the move to Calver, rtx's design will become mostly permanent and you will be able to rely on -its behavior for the long term. +rtx uses [Calver](https://calver.org/) versioning (`2023.6.1`). Breaking changes will be few but when they do happen, they will be communicated in the CLI with plenty of notice whenever possible. @@ -940,22 +934,6 @@ The numbers in Calver (YYYY.MM.RELEASE) simply represent the date of the release or how many new features were added. Each release will be small and incremental. -_\*This plan is tentative and the details may change, but the rough idea of making many changes now so we can have stability later is the goal._ - -### Calver Breaking Changes - -When we switch to Calver, we'll immediately make some notable design changes to rtx. This will -be the first and last time that such a change is made and I actually want to make sure we make -as many as we can—because we'll be stuck with these decisions. - -Here are a list of the changes that will be made: - -- `rtx local` will default to creating `.rtx.toml` instead of `.tool-versions`. (If the config - already exists the format will be preserved.) -- `rtx global` will modify `~/.config/rtx/config.toml` instead of `~/.tool-versions`. This path - can be changed with `RTX_CONFIG_FILE`. -- (more to be added) - ## Directories The following are the directories that rtx uses. diff --git a/e2e/test_bang b/e2e/test_bang index 4a463ef35..1507cef3d 100755 --- a/e2e/test_bang +++ b/e2e/test_bang @@ -10,10 +10,10 @@ assert() { fi } -rtx local tiny@latest!-1 +rtx local tiny@sub-1:latest assert "rtx current tiny" "2.1.0" -rtx local tiny@lts!-1 +rtx local tiny@sub-1:lts assert "rtx current tiny" "2.1.0" -rtx local tiny@3.1!-0.1 +rtx local tiny@sub-0.1:3.1 assert "rtx current tiny" "3.0.1" rtx local tiny@latest diff --git a/src/cache.rs b/src/cache.rs index 89bada2ee..a55bd42be 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -5,7 +5,6 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::time::Duration; -use crate::file::{display_path, modified_duration}; use color_eyre::eyre::Result; use flate2::read::ZlibDecoder; use flate2::write::ZlibEncoder; @@ -14,6 +13,8 @@ use once_cell::sync::OnceCell; use serde::de::DeserializeOwned; use serde::Serialize; +use crate::file::{display_path, modified_duration}; + #[derive(Debug, Clone)] pub struct CacheManager where diff --git a/src/config/settings.rs b/src/config/settings.rs index 6fb99a9b6..1e4310ca0 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -5,8 +5,8 @@ use std::time::Duration; use log::LevelFilter; -use crate::env; use crate::env::*; +use crate::{duration, env}; #[derive(Debug, Clone)] pub struct Settings { @@ -37,7 +37,7 @@ impl Default for Settings { always_keep_install: *RTX_ALWAYS_KEEP_INSTALL, legacy_version_file: *RTX_LEGACY_VERSION_FILE != Some(false), legacy_version_file_disable_tools: RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS.clone(), - plugin_autoupdate_last_check_duration: Duration::from_secs(60 * 60 * 24 * 7), + plugin_autoupdate_last_check_duration: duration::WEEKLY, trusted_config_paths: RTX_TRUSTED_CONFIG_PATHS.clone(), verbose: *RTX_VERBOSE, asdf_compat: *RTX_ASDF_COMPAT, diff --git a/src/duration.rs b/src/duration.rs index 0e081180c..6dcbef530 100644 --- a/src/duration.rs +++ b/src/duration.rs @@ -2,4 +2,4 @@ pub use std::time::Duration; pub(crate) const HOURLY: Duration = Duration::from_secs(60 * 60); pub(crate) const DAILY: Duration = Duration::from_secs(60 * 60 * 24); -//pub(crate) const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); +pub(crate) const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); diff --git a/src/env.rs b/src/env.rs index 718a2ad48..05f3808cf 100644 --- a/src/env.rs +++ b/src/env.rs @@ -138,7 +138,6 @@ pub static RTX_NODE_VERBOSE_INSTALL: Lazy> = pub static RTX_NODE_FORCE_COMPILE: Lazy = Lazy::new(|| var_is_true("RTX_NODE_FORCE_COMPILE")); pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { - // post-calver we can probably remove these checks let p = HOME.join(".default-nodejs-packages"); if p.exists() { return p; @@ -313,13 +312,16 @@ fn apply_patches( /// returns true if new runtime versions should not be fetched fn prefer_stale(args: &[String]) -> bool { - if let Some(c) = args.get(1) { - return [ - "env", "hook-env", "x", "exec", "direnv", "activate", "current", "ls", "where", - ] - .contains(&c.as_str()); - } - false + let binding = String::new(); + let c = args + .iter() + .filter(|a| !a.starts_with('-')) + .nth(1) + .unwrap_or(&binding); + return [ + "env", "hook-env", "x", "exec", "direnv", "activate", "current", "ls", "where", + ] + .contains(&c.as_str()); } fn log_level() -> LevelFilter { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index f137dc5a2..4746648ab 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -14,7 +14,7 @@ use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::duration::DAILY; -use crate::env::RTX_EXE; +use crate::env::PREFER_STALE; use crate::plugins::core::CorePlugin; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; @@ -31,6 +31,7 @@ pub struct JavaPlugin { impl JavaPlugin { pub fn new(name: PluginName) -> Self { let core = CorePlugin::new(name); + let fresh_duration = if *PREFER_STALE { None } else { Some(DAILY) }; let java_metadata_ga_cache_filename = format!("java_metadata_ga_{}_{}.msgpack.z", os(), arch()); let java_metadata_ea_cache_filename = @@ -39,13 +40,11 @@ impl JavaPlugin { java_metadata_ea_cache: CacheManager::new( core.cache_path.join(java_metadata_ea_cache_filename), ) - .with_fresh_duration(Some(DAILY)) - .with_fresh_file(RTX_EXE.clone()), + .with_fresh_duration(fresh_duration), java_metadata_ga_cache: CacheManager::new( core.cache_path.join(java_metadata_ga_cache_filename), ) - .with_fresh_duration(Some(DAILY)) - .with_fresh_file(RTX_EXE.clone()), + .with_fresh_duration(fresh_duration), core, } } diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 57aedafdb..df1f7a28d 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::ffi::OsString; use std::path::PathBuf; use std::sync::Arc; -use std::time::Duration; use color_eyre::eyre::Result; use once_cell::sync::Lazy; @@ -10,7 +9,8 @@ use once_cell::sync::Lazy; pub use python::PythonPlugin; use crate::cache::CacheManager; -use crate::env::RTX_EXE; +use crate::duration::DAILY; +use crate::env::PREFER_STALE; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; use crate::plugins::core::go::GoPlugin; @@ -69,11 +69,10 @@ pub struct CorePlugin { impl CorePlugin { pub fn new(name: PluginName) -> Self { let cache_path = dirs::CACHE.join(&name); - let fresh_duration = Some(Duration::from_secs(60 * 60 * 12)); // 12 hours + let fresh_duration = if *PREFER_STALE { None } else { Some(DAILY) }; Self { remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(fresh_duration) - .with_fresh_file(RTX_EXE.clone()), + .with_fresh_duration(fresh_duration), name, cache_path, } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 1ed30b413..874860a96 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -44,10 +44,8 @@ impl PythonPlugin { if self.python_build_path().exists() { return Ok(()); } - debug!( - "Installing python-build to {}", - self.python_build_path().display() - ); + let python_build_path = self.python_build_path(); + debug!("Installing python-build to {}", python_build_path.display()); create_dir_all(self.python_build_path().parent().unwrap())?; let git = Git::new(self.python_build_path()); git.clone(&env::RTX_PYENV_REPO)?; diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 538bf4d99..2b3e1e1b2 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -5,8 +5,6 @@ use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::exit; -use std::time::Duration; - use clap::Command; use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; @@ -15,6 +13,7 @@ use once_cell::sync::Lazy; use crate::cache::CacheManager; use crate::config::{Config, Settings}; +use crate::duration::DAILY; use crate::env::{PREFER_STALE, RTX_FETCH_REMOTE_VERSIONS_TIMEOUT}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; @@ -53,11 +52,7 @@ impl ExternalPlugin { let cache_path = dirs::CACHE.join(name); let toml_path = plugin_path.join("rtx.plugin.toml"); let toml = RtxPluginToml::from_file(&toml_path).unwrap(); - let fresh_duration = if *PREFER_STALE { - None - } else { - Some(Duration::from_secs(60 * 60 * 24)) - }; + let fresh_duration = if *PREFER_STALE { None } else { Some(DAILY) }; Self { name: name.into(), script_man: build_script_man(name, &plugin_path), diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index f04a1976a..b1f5f1909 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -43,6 +43,10 @@ impl ToolVersion { opts: ToolVersionOptions, latest_versions: bool, ) -> Result { + if !tool.is_installed() { + let tv = Self::new(tool, request.clone(), opts.clone(), request.version()); + return Ok(tv); + } let tv = match request.clone() { ToolVersionRequest::Version(_, v) => { Self::resolve_version(config, tool, request, latest_versions, &v, opts)? @@ -128,10 +132,10 @@ impl ToolVersion { } let build = |v| Ok(Self::new(tool, request.clone(), opts.clone(), v)); - if !tool.is_installed() { return build(v); } + let existing = build(v.clone())?; if tool.is_version_installed(&existing) { // if the version is already installed, no need to fetch all the remote versions @@ -161,10 +165,6 @@ impl ToolVersion { if matches.contains(&v) { return build(v); } - // TODO: remove for calver release - if let Some((v, sub)) = v.split_once("!-") { - return Self::resolve_sub(config, tool, request.clone(), latest_versions, sub, v, opts); - } Self::resolve_prefix(config, tool, request, &v, opts) } From c1df01e9a02a3c3bca27529c6db2a937f2d64212 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:28:52 -0500 Subject: [PATCH 0956/1891] chore: Release --- Cargo.lock | 146 ++++++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 85 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6212e489c..f52302346 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -82,9 +82,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -125,9 +125,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "block-buffer" @@ -191,11 +191,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -452,9 +453,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" [[package]] name = "dialoguer" @@ -622,9 +623,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -772,9 +773,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aca8bbd8e0707c1887a8bbb7e6b40e228f251ff5d62c8220a4a7a53c73aff006" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" dependencies = [ "aho-corasick", "bstr", @@ -867,9 +868,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -894,7 +895,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -1071,7 +1072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.4", + "rustix 0.38.8", "windows-sys 0.48.0", ] @@ -1440,9 +1441,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -1667,7 +1668,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "1.35.8" +version = "2023.8.0" dependencies = [ "base64", "built", @@ -1744,11 +1745,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno 0.3.2", "libc", "linux-raw-sys 0.4.5", @@ -1757,9 +1758,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.5" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" +checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" dependencies = [ "log", "ring", @@ -1790,9 +1791,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.2" +version = "0.101.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" +checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0" dependencies = [ "ring", "untrusted", @@ -2018,6 +2019,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -2071,14 +2082,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.7.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.38.4", + "rustix 0.38.8", "windows-sys 0.48.0", ] @@ -2120,18 +2131,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "d9207952ae1a003f42d3d5e892dac3c6ba42aa6ac0c79a6a91a2b5cb4253e75c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "f1728216d3244de4f14f14f8c15c79be1a7c67867d28d69b719690e2a19fb445" dependencies = [ "proc-macro2", "quote", @@ -2149,9 +2160,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" dependencies = [ "deranged", "itoa", @@ -2194,18 +2205,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", - "socket2", + "socket2 0.5.3", "windows-sys 0.48.0", ] @@ -2640,7 +2650,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.2", ] [[package]] @@ -2658,7 +2668,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.2", ] [[package]] @@ -2678,17 +2688,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.2", + "windows_aarch64_msvc 0.48.2", + "windows_i686_gnu 0.48.2", + "windows_i686_msvc 0.48.2", + "windows_x86_64_gnu 0.48.2", + "windows_x86_64_gnullvm 0.48.2", + "windows_x86_64_msvc 0.48.2", ] [[package]] @@ -2699,9 +2709,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" [[package]] name = "windows_aarch64_msvc" @@ -2711,9 +2721,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" [[package]] name = "windows_i686_gnu" @@ -2723,9 +2733,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" [[package]] name = "windows_i686_msvc" @@ -2735,9 +2745,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" [[package]] name = "windows_x86_64_gnu" @@ -2747,9 +2757,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" [[package]] name = "windows_x86_64_gnullvm" @@ -2759,9 +2769,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" [[package]] name = "windows_x86_64_msvc" @@ -2771,15 +2781,15 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" [[package]] name = "winnow" -version = "0.5.2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7" +checksum = "5504cc7644f4b593cbc05c4a55bf9bd4e94b867c3c0bd440934174d50482427d" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 22c0d9c7d..3027f0062 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "1.35.8" +version = "2023.8.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index d3b2ab34f..b84c3d760 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 1.35.8 +rtx 2023.8.0 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v1.35.8/rtx-v1.35.8-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.0/rtx-v2023.8.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 529b1ad8e..84f3a6e14 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "1.35.8"; + version = "2023.8.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a96107714..dd3956edb 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 1.35.8" +.TH rtx 1 "rtx 2023.8.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v1.35.8 +v2023.8.0 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 0bcb02c65..5dc93524a 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 1.35.8 +Version: 2023.8.0 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From a0a83ac52069b3f3a2a04ff8735246bb2683c803 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 15 Aug 2023 21:07:00 -0500 Subject: [PATCH 0957/1891] Update dependabot.yml --- .github/dependabot.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d062b443b..6ed70d746 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,9 +2,14 @@ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" - schedule: + schedule: &schedule interval: "weekly" + groups: &groups + dependencies: + dependency-type: "production" + dev-dependencies: + dependency-type: "development" - package-ecosystem: "cargo" directory: "/" - schedule: - interval: "weekly" + schedule: *schedule + groups: *groups From deeb6030947488b3a201aeba784a088b8b9e1864 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 02:19:46 +0000 Subject: [PATCH 0958/1891] chore(deps): bump serde_json from 1.0.104 to 1.0.105 (#804) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.104 to 1.0.105. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.104...v1.0.105) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f52302346..c3617a2d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1911,9 +1911,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", From d31ae445107b38034b9e2bb23208aab81d91a23a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:03:56 -0500 Subject: [PATCH 0959/1891] see if turning off incremental improves CI perf --- .github/workflows/rtx.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 290fd0a88..39b7d5609 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -11,6 +11,7 @@ on: env: CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 jobs: unit: From 1a0271e6f305a6dfa9b37d64be0163cde8dcd170 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:46:06 -0500 Subject: [PATCH 0960/1891] fix versioning for raku plugin (#808) Fixes #807 --- src/runtime_symlinks.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 7060f6a9e..3208f1d3f 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -5,7 +5,7 @@ use color_eyre::eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use regex::Regex; -use versions::Version; +use versions::Versioning; use crate::config::Config; use crate::dirs; @@ -39,17 +39,12 @@ fn list_symlinks(config: &Config, plugin: &Tool) -> Result 1 { - let chunks = &version.chunks.0[0..=version.chunks.0.len() - 2]; - for (i, _) in chunks.iter().enumerate() { - let partial = version.chunks.0[0..=i] - .iter() - .map(|c| c.to_string()) - .collect::>() - .join("."); - symlinks.insert(partial, rel_path(&v)); - } + let versions = Versioning::new(&v).expect("invalid version"); + let mut partial = vec![]; + while versions.nth(partial.len() + 1).is_some() { + let version = versions.nth(partial.len()).unwrap(); + partial.push(version.to_string()); + symlinks.insert(partial.join("."), rel_path(&v)); } symlinks.insert("latest".into(), rel_path(&v)); for (from, to) in config @@ -68,7 +63,7 @@ fn list_symlinks(config: &Config, plugin: &Tool) -> Result Date: Wed, 16 Aug 2023 17:08:19 -0500 Subject: [PATCH 0961/1891] improve version output (#809) this hides the git sha if one is not found --- src/cli/version.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index 92939ae0a..c3da8542b 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -30,18 +30,16 @@ pub static ARCH: Lazy = Lazy::new(|| { }); pub static VERSION: Lazy = Lazy::new(|| { - format!( - "{} {}-{} ({} {})", - if cfg!(debug_assertions) { - format!("{}-DEBUG", *RAW_VERSION) - } else { - RAW_VERSION.clone() - }, - *OS, - *ARCH, - built_info::GIT_COMMIT_HASH_SHORT.unwrap_or("unknown"), - BUILD_TIME.format("%Y-%m-%d"), - ) + let mut version = RAW_VERSION.clone(); + if cfg!(debug_assertions) { + version.push_str("-DEBUG"); + }; + let build_time = BUILD_TIME.format("%Y-%m-%d"); + let extra = match &built_info::GIT_COMMIT_HASH_SHORT { + Some(sha) => format!("({} {})", sha, build_time), + _ => format!("({})", build_time), + }; + format!("{} {}-{} {}", version, *OS, *ARCH, extra) }); pub static RAW_VERSION: Lazy = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string()); From 8a20add7a75869c479aada7631dd8150829c0869 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 16 Aug 2023 18:23:01 -0500 Subject: [PATCH 0962/1891] add --global flag to ls (#811) --- README.md | 3 + completions/_rtx | 2 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/ls.rs | 11 +++- src/config/config_file/mod.rs | 4 ++ src/config/config_file/rtx_toml.rs | 6 +- src/config/config_file/tool_versions.rs | 6 +- src/config/mod.rs | 26 ++++++--- src/toolset/builder.rs | 75 +++++++++++++++---------- 10 files changed, 92 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index b84c3d760..e2b7fa5f7 100644 --- a/README.md +++ b/README.md @@ -1950,6 +1950,9 @@ Options: -c, --current Only show tool versions currently specified in a .tool-versions/.rtx.toml + -g, --global + Only show tool versions currently specified in a the global .tool-versions/.rtx.toml + -i, --installed Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed diff --git a/completions/_rtx b/completions/_rtx index de6543b3d..fb10da70f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -817,6 +817,8 @@ default\: 4]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ '--current[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ +'-g[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ +'--global[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ '-i[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ '--installed[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ '(--json)--parseable[Output in an easily parseable format]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 920c2065d..1c0a3557e 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2413,7 +2413,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -i -m -j -r -v -h --plugin --current --installed --parseable --json --missing --prefix --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" + opts="-p -c -g -i -m -j -r -v -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index eef4abe2c..31e269f99 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -397,6 +397,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of p default: 4' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in an easily parseable format' complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 59e4aa466..83010d06b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -34,6 +34,10 @@ pub struct Ls { #[clap(long, short)] current: bool, + /// Only show tool versions currently specified in a the global .tool-versions/.rtx.toml + #[clap(long, short)] + global: bool, + /// Only show tool versions that are installed /// Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed #[clap(long, short)] @@ -66,7 +70,9 @@ impl Command for Ls { self.verify_plugin(&config)?; let mut runtimes = self.get_runtime_list(&mut config)?; - if self.current { + 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 runtimes.retain(|(_, _, source)| source.is_some()); } if self.installed { @@ -224,7 +230,8 @@ impl Ls { } fn get_runtime_list(&self, config: &mut Config) -> Result> { - let mut tsb = ToolsetBuilder::new(); + let mut tsb = ToolsetBuilder::new().with_global_only(self.global); + if let Some(plugin) = &self.plugin { tsb = tsb.with_tools(&[plugin]); config.tools.retain(|p, _| p == plugin); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 071939b90..b19cb3392 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -47,6 +47,10 @@ pub trait ConfigFile: Debug + Display + Send + Sync { fn settings(&self) -> SettingsBuilder; fn aliases(&self) -> AliasMap; fn watch_files(&self) -> Vec; + + fn is_global(&self) -> bool { + false + } } impl dyn ConfigFile { diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 436f58190..4982a08da 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -12,7 +12,7 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; -use crate::config::{config_file, AliasMap, MissingRuntimeBehavior}; +use crate::config::{config_file, global_config_files, AliasMap, MissingRuntimeBehavior}; use crate::errors::Error::UntrustedConfig; use crate::file::create_dir_all; use crate::plugins::{unalias_plugin, PluginName}; @@ -769,6 +769,10 @@ impl ConfigFile for RtxToml { None => vec![self.path.clone()], } } + + fn is_global(&self) -> bool { + global_config_files().iter().any(|p| p == &self.path) + } } #[cfg(test)] diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index f543cdbb7..db48c1247 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -12,7 +12,7 @@ use tera::Context; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; -use crate::config::AliasMap; +use crate::config::{global_config_files, AliasMap}; use crate::file::display_path; use crate::plugins::{unalias_plugin, PluginName}; use crate::tera::{get_tera, BASE_CONTEXT}; @@ -223,6 +223,10 @@ impl ConfigFile for ToolVersions { fn watch_files(&self) -> Vec { vec![self.path.clone()] } + + fn is_global(&self) -> bool { + global_config_files().iter().any(|p| p == &self.path) + } } #[cfg(test)] diff --git a/src/config/mod.rs b/src/config/mod.rs index 719b10d7d..4e45e808d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -357,6 +357,22 @@ fn load_config_filenames( let mut config_files = file::FindUp::new(&dirs::CURRENT, &filenames).collect::>(); + for cf in global_config_files() { + config_files.push(cf); + } + + config_files.into_iter().unique().collect() +} + +fn get_global_rtx_toml() -> PathBuf { + match env::RTX_CONFIG_FILE.clone() { + Some(global) => global, + None => dirs::CONFIG.join("config.toml"), + } +} + +pub fn global_config_files() -> Vec { + let mut config_files = vec![]; if env::RTX_CONFIG_FILE.is_none() && !*env::RTX_USE_TOML { // only add ~/.tool-versions if RTX_CONFIG_FILE is not set // because that's how the user overrides the default @@ -369,15 +385,7 @@ fn load_config_filenames( if global_config.is_file() { config_files.push(global_config); } - - config_files.into_iter().unique().collect() -} - -fn get_global_rtx_toml() -> PathBuf { - match env::RTX_CONFIG_FILE.clone() { - Some(global) => global, - None => dirs::CONFIG.join("config.toml"), - } + config_files } fn load_all_config_files( diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 51ff60f6a..12eefbf78 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -13,6 +13,7 @@ pub struct ToolsetBuilder { args: Vec, install_missing: bool, latest_versions: bool, + global_only: bool, tool_filter: Option>, } @@ -36,6 +37,11 @@ impl ToolsetBuilder { self } + pub fn with_global_only(mut self, global_only: bool) -> Self { + self.global_only = global_only; + self + } + pub fn with_tools(mut self, tools: &[&str]) -> Self { self.tool_filter = Some(tools.iter().map(|s| s.to_string()).collect()); self @@ -47,9 +53,9 @@ impl ToolsetBuilder { disable_tools: config.settings.disable_tools.clone(), ..Default::default() }; - load_config_files(config, &mut toolset); - load_runtime_env(&mut toolset, env::vars().collect()); - load_runtime_args(&mut toolset, &self.args); + self.load_config_files(config, &mut toolset); + self.load_runtime_env(&mut toolset, env::vars().collect()); + self.load_runtime_args(&mut toolset); if let Some(tools) = self.tool_filter { toolset.versions.retain(|p, _| tools.contains(p)); } @@ -63,41 +69,50 @@ impl ToolsetBuilder { debug!("{}", toolset); Ok(toolset) } -} -fn load_config_files(config: &Config, ts: &mut Toolset) { - for cf in config.config_files.values().rev() { - ts.merge(cf.to_toolset()); + fn load_config_files(&self, config: &Config, ts: &mut Toolset) { + for cf in config.config_files.values().rev() { + if self.global_only && !cf.is_global() { + return; + } + ts.merge(cf.to_toolset()); + } } -} -fn load_runtime_env(ts: &mut Toolset, env: BTreeMap) { - for (k, v) in env { - if k.starts_with("RTX_") && k.ends_with("_VERSION") && k != "RTX_VERSION" { - let plugin_name = k[4..k.len() - 8].to_lowercase(); - if plugin_name == "install" { - // ignore RTX_INSTALL_VERSION - continue; - } - let source = ToolSource::Environment(k, v.clone()); - let mut env_ts = Toolset::new(source); - for v in v.split_whitespace() { - let tvr = ToolVersionRequest::new(plugin_name.clone(), v); - env_ts.add_version(tvr, Default::default()); + fn load_runtime_env(&self, ts: &mut Toolset, env: BTreeMap) { + if self.global_only { + return; + } + for (k, v) in env { + if k.starts_with("RTX_") && k.ends_with("_VERSION") && k != "RTX_VERSION" { + let plugin_name = k[4..k.len() - 8].to_lowercase(); + if plugin_name == "install" { + // ignore RTX_INSTALL_VERSION + continue; + } + let source = ToolSource::Environment(k, v.clone()); + let mut env_ts = Toolset::new(source); + for v in v.split_whitespace() { + let tvr = ToolVersionRequest::new(plugin_name.clone(), v); + env_ts.add_version(tvr, Default::default()); + } + ts.merge(&env_ts); } - ts.merge(&env_ts); } } -} -fn load_runtime_args(ts: &mut Toolset, args: &[ToolArg]) { - for (_, args) in args.iter().into_group_map_by(|arg| arg.plugin.clone()) { - let mut arg_ts = Toolset::new(ToolSource::Argument); - for arg in args { - if let Some(tvr) = &arg.tvr { - arg_ts.add_version(tvr.clone(), Default::default()); + fn load_runtime_args(&self, ts: &mut Toolset) { + if self.global_only { + return; + } + for (_, args) in self.args.iter().into_group_map_by(|arg| arg.plugin.clone()) { + let mut arg_ts = Toolset::new(ToolSource::Argument); + for arg in args { + if let Some(tvr) = &arg.tvr { + arg_ts.add_version(tvr.clone(), Default::default()); + } } + ts.merge(&arg_ts); } - ts.merge(&arg_ts); } } From 3986e9f717792c5bc40339ae5addd238f9309371 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:12:05 -0500 Subject: [PATCH 0963/1891] fix race condition with cache file writing (#810) Fixes #806 --- src/cache.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index a55bd42be..bd53655ee 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -84,13 +84,14 @@ where } pub fn write(&self, val: &T) -> Result<()> { - let path = &self.cache_file_path; - trace!("writing {}", display_path(path)); - if let Some(parent) = path.parent() { + trace!("writing {}", display_path(&self.cache_file_path)); + if let Some(parent) = self.cache_file_path.parent() { fs::create_dir_all(parent)?; } - let mut zlib = ZlibEncoder::new(File::create(path)?, Compression::fast()); + let partial_path = self.cache_file_path.with_extension("part"); + let mut zlib = ZlibEncoder::new(File::create(&partial_path)?, Compression::fast()); zlib.write_all(&rmp_serde::to_vec_named(&val)?[..])?; + fs::rename(&partial_path, &self.cache_file_path)?; Ok(()) } From 136d509b3bca686caf8645592bdd757b16ce9089 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 16 Aug 2023 20:35:29 -0500 Subject: [PATCH 0964/1891] added confirmation dialog when installing plugins (#812) Fixes #790 --- README.md | 3 +- completions/_rtx | 118 ++++++++++++++++++ completions/rtx.bash | 118 +++++++++--------- completions/rtx.fish | 59 +++++++++ e2e/run_test | 1 + e2e/test_ls_remote | 3 +- man/man1/rtx.1 | 5 +- src/cli/args/mod.rs | 1 + src/cli/args/yes.rs | 14 +++ src/cli/install.rs | 26 ++-- src/cli/ls_remote.rs | 30 +---- src/cli/mod.rs | 4 + src/cli/plugins/install.rs | 47 +++---- ...cli__settings__ls__tests__settings_ls.snap | 1 + ...i__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + src/config/config_file/rtx_toml.rs | 1 + ...nfig_file__rtx_toml__tests__fixture-2.snap | 1 + src/config/settings.rs | 8 ++ src/env.rs | 1 + src/plugins/external_plugin.rs | 113 +++++++++++------ src/plugins/mod.rs | 43 ++++++- src/tool.rs | 33 ++--- src/toolset/mod.rs | 8 +- 24 files changed, 449 insertions(+), 191 deletions(-) create mode 100644 src/cli/args/yes.rs diff --git a/README.md b/README.md index e2b7fa5f7..24b8be52c 100644 --- a/README.md +++ b/README.md @@ -708,6 +708,7 @@ verbose = false # set to true to see full installation output, see `RTX_VERB asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. raw = false # set to true to directly pipe plugins to stdin/stdout/stderr +yes = false # set to true to automatically answer yes to all prompts shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` @@ -857,7 +858,7 @@ installing plugins, e.g.: `rtx plugin install node https://github.com/asdf-vm/as Disables the specified tools. Separate with `,`. Generally used for core plugins but works with all. -#### `RTX_CONFIRM=yes|no` +#### `RTX_YES=yes` This will automatically answer yes or no to prompts. This is useful for scripting. diff --git a/completions/_rtx b/completions/_rtx index fb10da70f..d825b73e0 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -26,6 +26,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -60,6 +62,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -83,6 +87,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -111,6 +117,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -135,6 +143,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -155,6 +165,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -178,6 +190,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -240,6 +254,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -261,6 +277,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -281,6 +299,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -309,6 +329,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -359,6 +381,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -380,6 +404,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -401,6 +427,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -421,6 +449,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -449,6 +479,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -469,6 +501,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -489,6 +523,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -545,6 +581,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -568,6 +606,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -591,6 +631,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -616,6 +658,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -644,6 +688,8 @@ this is the default behavior unless RTX_ASDF_COMPAT=1]' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -671,6 +717,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -693,6 +741,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -717,6 +767,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ @@ -738,6 +790,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -762,6 +816,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -794,6 +850,8 @@ e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to .tool-versions]' Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -831,6 +889,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -852,6 +912,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -875,6 +937,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -907,6 +971,8 @@ Normally these are not shown]' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -945,6 +1011,8 @@ i.e.\: they don'\''t need the full git repo url]' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ @@ -970,6 +1038,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1008,6 +1078,8 @@ e.g.\: main 1234abc]' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1031,6 +1103,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1051,6 +1125,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1074,6 +1150,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1144,6 +1222,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1165,6 +1245,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1187,6 +1269,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1207,6 +1291,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1235,6 +1321,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1256,6 +1344,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1276,6 +1366,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1298,6 +1390,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1361,6 +1455,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1382,6 +1478,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1413,6 +1511,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1434,6 +1534,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1487,6 +1589,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1508,6 +1612,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1529,6 +1635,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1562,6 +1670,8 @@ this is the default behavior unless RTX_ASDF_COMPAT=1]' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1585,6 +1695,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1605,6 +1717,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1639,6 +1753,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ @@ -1660,6 +1776,8 @@ default\: 4]: : ' \ Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 1c0a3557e..8ee484642 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -547,7 +547,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -h -V --debug --install-missing --jobs --log-level --raw --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help help" + opts="-j -r -y -v -h -V --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -573,7 +573,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -j -r -v -h --shell --status --quiet --debug --install-missing --jobs --log-level --raw --trace --verbose --help bash fish nu xonsh zsh" + opts="-s -q -j -r -y -v -h --shell --status --quiet --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -607,7 +607,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -r -v -h --plugin --debug --install-missing --jobs --log-level --raw --trace --verbose --help get ls set unset help" + opts="-p -j -r -y -v -h --plugin --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -641,7 +641,7 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -751,7 +751,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -j -r -v -h --plugin --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-p -j -r -y -v -h --plugin --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -785,7 +785,7 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -811,7 +811,7 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -837,7 +837,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ARGS]..." + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -863,7 +863,7 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -889,7 +889,7 @@ _rtx() { return 0 ;; rtx__cache) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help clear help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -915,7 +915,7 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -983,7 +983,7 @@ _rtx() { return 0 ;; rtx__completion) - opts="-s -j -r -v -h --shell --debug --install-missing --jobs --log-level --raw --trace --verbose --help bash elvish fish powershell zsh" + opts="-s -j -r -y -v -h --shell --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1017,7 +1017,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN]" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1043,7 +1043,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1069,7 +1069,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help envrc exec activate help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1095,7 +1095,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1121,7 +1121,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1147,7 +1147,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1243,7 +1243,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1269,7 +1269,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -r -v -h --shell --json --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." + opts="-s -j -r -y -v -h --shell --json --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1303,7 +1303,7 @@ _rtx() { return 0 ;; rtx__env__vars) - opts="-j -r -v -h --file --remove --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ENV_VARS]..." + opts="-j -r -y -v -h --file --remove --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1337,7 +1337,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -v -h --command --cd --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -j -r -y -v -h --command --cd --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1375,7 +1375,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -v -h --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -y -v -h --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2245,7 +2245,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -r -v -h --shell --status --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-s -j -r -y -v -h --shell --status --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2279,7 +2279,7 @@ _rtx() { return 0 ;; rtx__implode) - opts="-j -r -v -h --config --dry-run --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --config --dry-run --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2305,7 +2305,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-f -v -j -r -h --force --verbose --debug --install-missing --jobs --log-level --raw --trace --help [TOOL@VERSION]..." + opts="-f -v -j -r -y -h --force --verbose --debug --install-missing --jobs --log-level --raw --yes --trace --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2331,7 +2331,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-i -j -r -v -h --installed --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" + opts="-i -j -r -y -v -h --installed --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2357,7 +2357,7 @@ _rtx() { return 0 ;; rtx__link) - opts="-f -j -r -v -h --force --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-f -j -r -y -v -h --force --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2383,7 +2383,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." + opts="-p -j -r -y -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2413,7 +2413,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -m -j -r -v -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN_ARG]" + opts="-p -c -g -i -m -j -r -y -v -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2451,7 +2451,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PREFIX]" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2477,7 +2477,7 @@ _rtx() { return 0 ;; rtx__outdated) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2503,7 +2503,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -j -r -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --trace --verbose --help install link ls ls-remote uninstall update help" + opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2641,7 +2641,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -r -h --force --all --verbose --debug --install-missing --jobs --log-level --raw --trace --help [NAME] [GIT_URL] [REST]..." + opts="-f -a -v -j -r -y -h --force --all --verbose --debug --install-missing --jobs --log-level --raw --yes --trace --help [NAME] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2667,7 +2667,7 @@ _rtx() { return 0 ;; rtx__plugins__link) - opts="-f -j -r -v -h --force --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PATH]" + opts="-f -j -r -y -v -h --force --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2693,7 +2693,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -j -r -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2719,7 +2719,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -r -v -h --urls --only-names --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-u -j -r -y -v -h --urls --only-names --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2745,7 +2745,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help ..." + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2771,7 +2771,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -j -r -v -h --all --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN]..." + opts="-a -j -r -y -v -h --all --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2797,7 +2797,7 @@ _rtx() { return 0 ;; rtx__prune) - opts="-j -r -v -h --dry-run --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGINS]..." + opts="-j -r -y -v -h --dry-run --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGINS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2823,7 +2823,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2849,7 +2849,7 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [PLUGIN] [VERSION]" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2875,7 +2875,7 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2901,7 +2901,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help get ls set unset help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2927,7 +2927,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3037,7 +3037,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3063,7 +3063,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3089,7 +3089,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3115,7 +3115,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -r -v -h --unset --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." + opts="-u -j -r -y -v -h --unset --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3141,7 +3141,7 @@ _rtx() { return 0 ;; rtx__sync) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help node python help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3223,7 +3223,7 @@ _rtx() { return 0 ;; rtx__sync__node) - opts="-j -r -v -h --brew --nvm --nodenv --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --brew --nvm --nodenv --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3249,7 +3249,7 @@ _rtx() { return 0 ;; rtx__sync__python) - opts="-j -r -v -h --pyenv --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --pyenv --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3275,7 +3275,7 @@ _rtx() { return 0 ;; rtx__trust) - opts="-j -r -v -h --untrust --debug --install-missing --jobs --log-level --raw --trace --verbose --help [CONFIG_FILE]" + opts="-j -r -y -v -h --untrust --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3301,7 +3301,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help ..." + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3327,7 +3327,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3353,7 +3353,7 @@ _rtx() { return 0 ;; rtx__use) - opts="-g -p -j -r -v -h --pin --fuzzy --remove --global --path --debug --install-missing --jobs --log-level --raw --trace --verbose --help [TOOL@VERSION]..." + opts="-g -p -j -r -y -v -h --pin --fuzzy --remove --global --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3391,7 +3391,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3417,7 +3417,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -r -v -h --debug --install-missing --jobs --log-level --raw --trace --verbose --help [ASDF_VERSION]" + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3443,7 +3443,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-t -j -r -v -h --plugin --version --tool --debug --install-missing --jobs --log-level --raw --trace --verbose --help " + opts="-t -j -r -y -v -h --plugin --version --tool --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 31e269f99..67cc0e2b5 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -5,6 +5,7 @@ complete -c rtx -n "__fish_use_subcommand" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_use_subcommand" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_use_subcommand" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_use_subcommand" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' @@ -58,6 +59,7 @@ complete -c rtx -n "__fish_seen_subcommand_from activate" -l debug -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' @@ -69,6 +71,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' @@ -86,6 +89,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' @@ -97,6 +101,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' @@ -107,6 +112,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' @@ -117,6 +123,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' @@ -134,6 +141,7 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -l debug -d 'Sets log leve complete -c rtx -n "__fish_seen_subcommand_from asdf" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' @@ -144,6 +152,7 @@ complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l debug -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' @@ -154,6 +163,7 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' @@ -166,6 +176,7 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' @@ -179,6 +190,7 @@ complete -c rtx -n "__fish_seen_subcommand_from completion" -l debug -d 'Sets lo complete -c rtx -n "__fish_seen_subcommand_from completion" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from completion" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from completion" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from completion" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from completion" -s h -l help -d 'Print help (see more with \'--help\')' @@ -189,6 +201,7 @@ complete -c rtx -n "__fish_seen_subcommand_from current" -l debug -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from current" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from current" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from current" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' @@ -199,6 +212,7 @@ complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l debug -d 'Sets lo complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' @@ -209,6 +223,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subc complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' @@ -225,6 +240,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' @@ -235,6 +251,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' @@ -245,6 +262,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' @@ -261,6 +279,7 @@ complete -c rtx -n "__fish_seen_subcommand_from doctor" -l debug -d 'Sets log le complete -c rtx -n "__fish_seen_subcommand_from doctor" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' @@ -273,6 +292,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level complete -c rtx -n "__fish_seen_subcommand_from env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from env" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' @@ -285,6 +305,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l debug -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s h -l help -d 'Print help (see more with \'--help\')' @@ -297,6 +318,7 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -l debug -d 'Sets log leve complete -c rtx -n "__fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' @@ -314,6 +336,7 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -l debug -d 'Sets log le complete -c rtx -n "__fish_seen_subcommand_from global" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from global" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from global" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' @@ -326,6 +349,7 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l debug -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' @@ -338,6 +362,7 @@ complete -c rtx -n "__fish_seen_subcommand_from implode" -l debug -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from implode" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from implode" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' @@ -350,6 +375,7 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -l debug -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -360,6 +386,7 @@ complete -c rtx -n "__fish_seen_subcommand_from latest" -l debug -d 'Sets log le complete -c rtx -n "__fish_seen_subcommand_from latest" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from latest" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from latest" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' @@ -371,6 +398,7 @@ complete -c rtx -n "__fish_seen_subcommand_from link" -l debug -d 'Sets log leve complete -c rtx -n "__fish_seen_subcommand_from link" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' @@ -388,6 +416,7 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -l debug -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from local" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from local" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from local" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' @@ -406,6 +435,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -l debug -d 'Sets log level complete -c rtx -n "__fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' @@ -416,6 +446,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' @@ -426,6 +457,7 @@ complete -c rtx -n "__fish_seen_subcommand_from outdated" -l debug -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from outdated" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from outdated" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s h -l help -d 'Print help (see more with \'--help\')' @@ -441,6 +473,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' @@ -463,6 +496,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -473,6 +507,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' @@ -491,6 +526,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' @@ -503,6 +539,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' @@ -513,6 +550,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' @@ -524,6 +562,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' @@ -542,6 +581,7 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -l debug -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from prune" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from prune" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from prune" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from prune" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print help (see more with \'--help\')' @@ -552,6 +592,7 @@ complete -c rtx -n "__fish_seen_subcommand_from reshim" -l debug -d 'Sets log le complete -c rtx -n "__fish_seen_subcommand_from reshim" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from reshim" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' @@ -562,6 +603,7 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -l debug -d 'Sets l complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' @@ -572,6 +614,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' @@ -587,6 +630,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' @@ -597,6 +641,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' @@ -607,6 +652,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' @@ -617,6 +663,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' @@ -633,6 +680,7 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -l debug -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from shell" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from shell" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' @@ -643,6 +691,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' @@ -659,6 +708,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s h -l help -d 'Print help (see more with \'--help\')' @@ -670,6 +720,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s h -l help -d 'Print help (see more with \'--help\')' @@ -684,6 +735,7 @@ complete -c rtx -n "__fish_seen_subcommand_from trust" -l debug -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from trust" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from trust" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from trust" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from trust" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from trust" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from trust" -s h -l help -d 'Print help (see more with \'--help\')' @@ -694,6 +746,7 @@ complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l debug -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' @@ -704,6 +757,7 @@ complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l debug -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s h -l help -d 'Print help' @@ -722,6 +776,7 @@ complete -c rtx -n "__fish_seen_subcommand_from use" -l debug -d 'Sets log level complete -c rtx -n "__fish_seen_subcommand_from use" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from use" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from use" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from use" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from use" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from use" -s h -l help -d 'Print help (see more with \'--help\')' @@ -732,6 +787,7 @@ complete -c rtx -n "__fish_seen_subcommand_from version" -l debug -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from version" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from version" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from version" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' @@ -742,6 +798,7 @@ complete -c rtx -n "__fish_seen_subcommand_from where" -l debug -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from where" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from where" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from where" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' @@ -756,6 +813,7 @@ complete -c rtx -n "__fish_seen_subcommand_from which" -l debug -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from which" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from which" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from which" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' @@ -766,6 +824,7 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -l debug -d 'Sets l complete -c rtx -n "__fish_seen_subcommand_from render-help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' diff --git a/e2e/run_test b/e2e/run_test index 77f013718..ba92114d9 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -15,6 +15,7 @@ setup_env() { export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" + export RTX_YES="yes" unset GOPATH } diff --git a/e2e/test_ls_remote b/e2e/test_ls_remote index ebafa51f5..12bee3890 100755 --- a/e2e/test_ls_remote +++ b/e2e/test_ls_remote @@ -4,5 +4,4 @@ source "$(dirname "$0")/assert.sh" rtx p list-remote | grep elixir rtx p uninstall tiny -assert_fail "RTX_CONFIRM=no rtx ls-remote tiny" -assert_contains "RTX_CONFIRM=yes rtx ls-remote tiny" "1.1.0" +assert_contains "rtx ls-remote tiny" "1.1.0" diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index dd3956edb..a1cfa6c27 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -4,7 +4,7 @@ .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS -\fBrtx\fR [\fB\-\-install\-missing\fR] [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-\-log\-level\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> +\fBrtx\fR [\fB\-\-install\-missing\fR] [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-\-log\-level\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-y\fR|\fB\-\-yes\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> .SH DESCRIPTION rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx .PP @@ -30,6 +30,9 @@ Set the log output verbosity Directly pipe stdin/stdout/stderr to user. Sets \-\-jobs=1 .TP +\fB\-y\fR, \fB\-\-yes\fR +Answer yes to all prompts +.TP \fB\-v\fR, \fB\-\-verbose\fR Show installation output .TP diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index f584b96f9..cd279f31a 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -5,3 +5,4 @@ pub mod log_level; pub mod raw; pub mod tool; pub mod verbose; +pub mod yes; diff --git a/src/cli/args/yes.rs b/src/cli/args/yes.rs new file mode 100644 index 000000000..d9d55179c --- /dev/null +++ b/src/cli/args/yes.rs @@ -0,0 +1,14 @@ +use clap::{Arg, ArgAction}; + +pub struct Yes(pub bool); + +impl Yes { + pub fn arg() -> Arg { + Arg::new("yes") + .short('y') + .long("yes") + .help("Answer yes to all prompts") + .action(ArgAction::SetTrue) + .global(true) + } +} diff --git a/src/cli/install.rs b/src/cli/install.rs index 9212cde57..e1ed25290 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -3,7 +3,6 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; -use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::output::Output; @@ -38,9 +37,7 @@ pub struct Install { } impl Command for Install { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - config.settings.missing_runtime_behavior = AutoInstall; - + fn run(self, config: Config, _out: &mut Output) -> Result<()> { match &self.tool { Some(runtime) => self.install_runtimes(config, runtime)?, None => self.install_missing_runtimes(config)?, @@ -104,13 +101,7 @@ impl Install { let mut tool_versions = vec![]; for (plugin_name, tvr, opts) in requests { let plugin = config.get_or_create_tool(&plugin_name); - if !plugin.is_installed() { - let mut pr = mpr.add(); - if let Err(err) = plugin.install(config, &mut pr, false) { - pr.error(err.to_string()); - return Err(err)?; - } - } + plugin.ensure_installed(config, Some(mpr), false)?; let tv = tvr.resolve(config, &plugin, opts, ts.latest_versions)?; tool_versions.push(tv); } @@ -121,12 +112,17 @@ impl Install { let mut ts = ToolsetBuilder::new() .with_latest_versions() .build(&mut config)?; - if ts.list_missing_versions(&config).is_empty() { - warn!("no runtimes to install"); + let versions = ts + .list_missing_versions(&config) + .into_iter() + .cloned() + .collect::>(); + if versions.is_empty() { + info!("all runtimes are installed"); + return Ok(()); } let mpr = MultiProgressReport::new(config.show_progress_bars()); - ts.install_missing(&mut config, mpr)?; - + ts.install_versions(&mut config, versions, &mpr, self.force)?; Ok(()) } } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 6037836c8..5f8fd9125 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,15 +1,14 @@ -use color_eyre::eyre::Result; use std::sync::Arc; -use crate::cli::args::tool::{ToolArg, ToolArgParser}; +use color_eyre::eyre::Result; + +use crate::cli::args::tool::ToolArg; +use crate::cli::args::tool::ToolArgParser; use crate::cli::command::Command; use crate::config::Config; -use crate::errors::Error::PluginNotInstalled; use crate::output::Output; use crate::tool::Tool; use crate::toolset::ToolVersionRequest; -use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::prompt; /// List runtime versions available for install /// @@ -19,7 +18,7 @@ use crate::ui::prompt; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = ["list-all", "list-remote"])] pub struct LsRemote { /// Plugin to get versions for - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] plugin: ToolArg, /// The version prefix to use when querying the latest version @@ -58,26 +57,9 @@ impl LsRemote { fn get_plugin(&self, config: &mut Config) -> Result> { let plugin_name = self.plugin.plugin.clone(); let tool = config.get_or_create_tool(&plugin_name); - self.ensure_remote_plugin_is_installed(&tool, config)?; + tool.ensure_installed(config, None, false)?; Ok(tool) } - - fn ensure_remote_plugin_is_installed(&self, tool: &Tool, config: &mut Config) -> Result<()> { - if tool.is_installed() { - return Ok(()); - } - if prompt::confirm(&format!( - "Plugin {} is not installed, would you like to install it?", - tool.name - ))? { - let mpr = MultiProgressReport::new(config.show_progress_bars()); - let mut pr = mpr.add(); - tool.install(config, &mut pr, false)?; - return Ok(()); - } - - Err(PluginNotInstalled(tool.name.clone()))? - } } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1ee3d91d9..8bbc0b693 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -181,6 +181,7 @@ impl Cli { .arg(args::jobs::Jobs::arg()) .arg(args::log_level::LogLevel::arg()) .arg(args::raw::Raw::arg()) + .arg(args::yes::Yes::arg()) .arg(args::log_level::Trace::arg()) .arg(args::verbose::Verbose::arg()), ) @@ -208,6 +209,9 @@ impl Cli { if let Some(raw) = matches.get_one::("raw") { config.settings.raw = *raw; } + if let Some(true) = matches.get_one::("yes") { + config.settings.yes = true; + } if let Some(true) = matches.get_one::("install-missing") { config.settings.missing_runtime_behavior = AutoInstall; } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index df68f464e..eb7f25e23 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,6 +1,4 @@ use color_eyre::eyre::{eyre, Result}; -use rayon::prelude::*; -use rayon::ThreadPoolBuilder; use url::Url; use crate::cli::command::Command; @@ -53,18 +51,18 @@ impl Command for PluginsInstall { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); if self.all { - return self.install_all_missing_plugins(&mut config, mpr); + return self.install_all_missing_plugins(config, mpr); } let (name, git_url) = get_name_and_url(&self.name.clone().unwrap(), &self.git_url)?; if git_url.is_some() { - self.install_one(&config, &name, git_url, &mpr)?; + self.install_one(&mut config, &name, git_url, &mpr)?; } else { let mut plugins: Vec = vec![name]; if let Some(second) = self.git_url.clone() { plugins.push(second); }; plugins.extend(self.rest.clone()); - self.install_many(&mut config, &plugins, mpr)?; + self.install_many(config, &plugins, mpr)?; } Ok(()) @@ -74,11 +72,11 @@ impl Command for PluginsInstall { impl PluginsInstall { fn install_all_missing_plugins( &self, - config: &mut Config, + mut config: Config, mpr: MultiProgressReport, ) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; - let missing_plugins = ts.list_missing_plugins(config); + let ts = ToolsetBuilder::new().build(&mut config)?; + let missing_plugins = ts.list_missing_plugins(&mut config); if missing_plugins.is_empty() { warn!("all plugins already installed"); } @@ -88,25 +86,30 @@ impl PluginsInstall { fn install_many( &self, - config: &mut Config, + mut config: Config, plugins: &[PluginName], mpr: MultiProgressReport, ) -> Result<()> { - ThreadPoolBuilder::new() - .num_threads(config.settings.jobs) - .build()? - .install(|| -> Result<()> { - plugins - .into_par_iter() - .map(|plugin| self.install_one(config, plugin, None, &mpr)) - .collect::>>()?; - Ok(()) - }) + for plugin in plugins { + self.install_one(&mut config, plugin, None, &mpr)?; + } + Ok(()) + // TODO: run in parallel + // ThreadPoolBuilder::new() + // .num_threads(config.settings.jobs) + // .build()? + // .install(|| -> Result<()> { + // plugins + // .into_par_iter() + // .map(|plugin| self.install_one(&mut config, plugin, None, &mpr)) + // .collect::>>()?; + // Ok(()) + // }) } fn install_one( &self, - config: &Config, + config: &mut Config, name: &String, git_url: Option, mpr: &MultiProgressReport, @@ -116,10 +119,8 @@ impl PluginsInstall { if !self.force && plugin.is_installed() { mpr.warn(format!("plugin {} already installed", name)); } else { - let mut pr = mpr.add(); let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); - tool.decorate_progress_bar(&mut pr, None); - tool.install(config, &mut pr, self.force)?; + tool.ensure_installed(config, Some(mpr), true)?; } Ok(()) } diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index f4f739239..9f069c6a4 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -17,4 +17,5 @@ plugin_autoupdate_last_check_duration = 20 raw = false trusted_config_paths = [] verbose = true +yes = false diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 1e83bc48e..c9a190884 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -17,4 +17,5 @@ plugin_autoupdate_last_check_duration = 1 raw = false trusted_config_paths = [] verbose = true +yes = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index c197dad2b..7d674f3c0 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -58,6 +58,7 @@ mod tests { raw = false trusted_config_paths = [] verbose = true + yes = false "###); reset_config(); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 4982a08da..fde1cf261 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -429,6 +429,7 @@ impl RtxToml { } "log_level" => settings.log_level = Some(self.parse_log_level(&k, v)?), "raw" => settings.raw = Some(self.parse_bool(&k, v)?), + "yes" => settings.yes = Some(self.parse_bool(&k, v)?), _ => Err(eyre!("Unknown config setting: {}", k))?, }; } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 3c04f3360..ff41b3d06 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -27,4 +27,5 @@ SettingsBuilder { }, log_level: None, raw: None, + yes: None, } diff --git a/src/config/settings.rs b/src/config/settings.rs index 1e4310ca0..94655eb00 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -26,6 +26,7 @@ pub struct Settings { pub disable_tools: BTreeSet, pub log_level: LevelFilter, pub raw: bool, + pub yes: bool, } impl Default for Settings { @@ -47,6 +48,7 @@ impl Default for Settings { disable_tools: RTX_DISABLE_TOOLS.clone(), log_level: *RTX_LOG_LEVEL, raw: *RTX_RAW, + yes: *RTX_YES, } } } @@ -107,6 +109,7 @@ impl Settings { ); map.insert("log_level".into(), self.log_level.to_string()); map.insert("raw".into(), self.raw.to_string()); + map.insert("yes".into(), self.yes.to_string()); map } } @@ -129,6 +132,7 @@ pub struct SettingsBuilder { pub disable_tools: BTreeSet, pub log_level: Option, pub raw: Option, + pub yes: Option, } impl SettingsBuilder { @@ -183,6 +187,9 @@ impl SettingsBuilder { if other.raw.is_some() { self.raw = other.raw; } + if other.yes.is_some() { + self.yes = other.yes; + } self } @@ -231,6 +238,7 @@ impl SettingsBuilder { settings.disable_tools.extend(self.disable_tools.clone()); settings.log_level = self.log_level.unwrap_or(settings.log_level); settings.raw = self.raw.unwrap_or(settings.raw); + settings.yes = self.yes.unwrap_or(settings.yes); if settings.raw { settings.verbose = true; diff --git a/src/env.rs b/src/env.rs index 05f3808cf..626a94373 100644 --- a/src/env.rs +++ b/src/env.rs @@ -94,6 +94,7 @@ pub static RTX_DISABLE_TOOLS: Lazy> = Lazy::new(|| { .unwrap_or_default() }); pub static RTX_RAW: Lazy = Lazy::new(|| var_is_true("RTX_RAW")); +pub static RTX_YES: Lazy = Lazy::new(|| var_is_true("RTX_YES")); pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { var("RTX_TRUSTED_CONFIG_PATHS") .map(|v| split_paths(&v).collect()) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 2b3e1e1b2..fa5060906 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -26,7 +26,9 @@ use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; use crate::timeout::run_with_timeout; use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::ProgressReport; +use crate::ui::prompt; use crate::{dirs, env, file}; /// This represents a plugin installed to ~/.local/share/rtx/plugins @@ -80,6 +82,51 @@ impl ExternalPlugin { } } + fn get_repo_url(&self, config: &Config) -> Result { + self.repo_url + .clone() + .or_else(|| config.get_repo_url(&self.name)) + .ok_or_else(|| eyre!("No repository found for plugin {}", self.name)) + } + + fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { + let repository = self.get_repo_url(config)?; + let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); + debug!("install {} {:?}", self.name, repository); + + if self.is_installed() { + self.uninstall(pr)?; + } + + let git = Git::new(self.plugin_path.to_path_buf()); + pr.set_message(format!("cloning {repo_url}")); + git.clone(&repo_url)?; + if let Some(ref_) = &repo_ref { + pr.set_message(format!("checking out {ref_}")); + git.update(Some(ref_.to_string()))?; + } + + pr.set_message("loading plugin remote versions"); + if self.has_list_all_script() { + self.list_remote_versions(&config.settings)?; + } + if self.has_list_alias_script() { + pr.set_message("getting plugin aliases"); + self.get_aliases(&config.settings)?; + } + if self.has_list_legacy_filenames_script() { + pr.set_message("getting plugin legacy filenames"); + self.legacy_filenames(&config.settings)?; + } + + let sha = git.current_sha_short()?; + pr.finish_with_message(format!( + "{repo_url}#{}", + style(&sha).bright().yellow().for_stderr(), + )); + Ok(()) + } + fn fetch_remote_versions(&self, settings: &Settings) -> Result> { let cmd = self.script_man.cmd(settings, &Script::ListAll); let result = run_with_timeout( @@ -351,46 +398,34 @@ impl Plugin for ExternalPlugin { self.plugin_path.exists() } - fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { - let repository = self - .repo_url - .clone() - .or_else(|| config.get_repo_url(&self.name)) - .ok_or_else(|| eyre!("No repository found for plugin {}", self.name))?; - let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); - debug!("install {} {:?}", self.name, repository); - - if self.is_installed() { - self.uninstall(pr)?; - } - - let git = Git::new(self.plugin_path.to_path_buf()); - pr.set_message(format!("cloning {repo_url}")); - git.clone(&repo_url)?; - if let Some(ref_) = &repo_ref { - pr.set_message(format!("checking out {ref_}")); - git.update(Some(ref_.to_string()))?; - } - - pr.set_message("loading plugin remote versions"); - if self.has_list_all_script() { - self.list_remote_versions(&config.settings)?; - } - if self.has_list_alias_script() { - pr.set_message("getting plugin aliases"); - self.get_aliases(&config.settings)?; - } - if self.has_list_legacy_filenames_script() { - pr.set_message("getting plugin legacy filenames"); - self.legacy_filenames(&config.settings)?; + fn ensure_installed( + &self, + config: &mut Config, + mpr: Option<&MultiProgressReport>, + force: bool, + ) -> Result<()> { + if !force { + if self.is_installed() { + return Ok(()); + } + if !config.settings.yes && self.repo_url.is_none() { + let url = self.get_repo_url(config)?; + eprintln!( + "⚠️ {name} is a community-developed plugin: {url}", + name = style(&self.name).cyan(), + url = style(url.trim_end_matches(".git")).yellow(), + ); + if !prompt::confirm(&format!("Would you like to install {}?", self.name))? { + Err(PluginNotInstalled(self.name.clone()))? + } + } } - - let sha = git.current_sha_short()?; - pr.finish_with_message(format!( - "{repo_url}#{}", - style(&sha).bright().yellow().for_stderr(), - )); - Ok(()) + let _mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = mpr.unwrap_or(&_mpr); + let mut pr = mpr.add(); + self.decorate_progress_bar(&mut pr, None); + let _lock = self.get_lock(&self.plugin_path, force)?; + self.install(config, &mut pr) } fn update(&self, gitref: Option) -> Result<()> { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 2d7d09866..3e9f95893 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,17 +1,21 @@ -use clap::Command; use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; use std::path::{Path, PathBuf}; +use clap::Command; use color_eyre::eyre::Result; +use console::style; pub use external_plugin::ExternalPlugin; pub use rtx_plugin_toml::RtxPluginToml; pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; +use crate::file::display_path; +use crate::lock_file::LockFile; use crate::toolset::ToolVersion; -use crate::ui::progress_report::ProgressReport; +use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; pub mod core; mod external_plugin; @@ -42,7 +46,12 @@ pub trait Plugin: Debug + Send + Sync { fn is_installed(&self) -> bool { true } - fn install(&self, _config: &Config, _pr: &mut ProgressReport) -> Result<()> { + fn ensure_installed( + &self, + _config: &mut Config, + _mpr: Option<&MultiProgressReport>, + _force: bool, + ) -> Result<()> { Ok(()) } fn update(&self, _git_ref: Option) -> Result<()> { @@ -83,6 +92,34 @@ pub trait Plugin: Debug + Send + Sync { fn exec_env(&self, _config: &Config, _tv: &ToolVersion) -> Result> { Ok(HashMap::new()) } + + fn get_lock(&self, path: &Path, force: bool) -> Result> { + let lock = if force { + None + } else { + let lock = LockFile::new(path) + .with_callback(|l| { + debug!("waiting for lock on {}", display_path(l)); + }) + .lock()?; + Some(lock) + }; + Ok(lock) + } + + fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { + pr.set_style(PROG_TEMPLATE.clone()); + let tool = match tv { + Some(tv) => tv.to_string(), + None => self.name().to_string(), + }; + pr.set_prefix(format!( + "{} {} ", + style("rtx").dim().for_stderr(), + style(tool).cyan().for_stderr(), + )); + pr.enable_steady_tick(); + } } pub fn unalias_plugin(plugin_name: &str) -> &str { diff --git a/src/tool.rs b/src/tool.rs index e4ae9f9f4..645038150 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -13,10 +13,10 @@ use versions::Versioning; use crate::config::{Config, Settings}; use crate::file::{create_dir_all, display_path, remove_all_with_warning}; -use crate::lock_file::LockFile; -use crate::plugins::{ExternalPlugin, Plugin, PluginType}; +use crate::plugins::{ExternalPlugin, Plugin}; use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; use crate::{dirs, file}; @@ -269,13 +269,13 @@ impl Tool { Ok(()) } - pub fn install(&self, config: &Config, pr: &mut ProgressReport, force: bool) -> Result<()> { - if matches!(self.plugin.get_type(), PluginType::Core) { - return Ok(()); - } - self.decorate_progress_bar(pr, None); - let _lock = self.get_lock(&self.plugin_path, force)?; - self.plugin.install(config, pr) + pub fn ensure_installed( + &self, + config: &mut Config, + mpr: Option<&MultiProgressReport>, + force: bool, + ) -> Result<()> { + self.plugin.ensure_installed(config, mpr, force) } pub fn update(&self, git_ref: Option) -> Result<()> { self.plugin.update(git_ref) @@ -355,17 +355,7 @@ impl Tool { } fn get_lock(&self, path: &Path, force: bool) -> Result> { - let lock = if force { - None - } else { - let lock = LockFile::new(path) - .with_callback(|l| { - debug!("waiting for lock on {}", display_path(l)); - }) - .lock()?; - Some(lock) - }; - Ok(lock) + self.plugin.get_lock(path, force) } fn fuzzy_match_filter(&self, versions: Vec, query: &str) -> Vec { @@ -419,9 +409,10 @@ fn find_match_in_list(list: &[String], query: &str) -> Option { #[cfg(test)] mod tests { - use super::*; use crate::plugins::PluginName; + use super::*; + #[test] fn test_debug() { let plugin = ExternalPlugin::new(&PluginName::from("dummy")); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 4f192c3f7..c90a322fc 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -149,6 +149,11 @@ impl Toolset { .into_iter() .map(|(pn, v)| (config.get_or_create_tool(&pn), v.collect_vec())) .collect(); + for (t, _) in &queue { + if !t.is_installed() { + t.ensure_installed(config, Some(mpr), false)?; + } + } let queue = Arc::new(Mutex::new(queue)); thread::scope(|s| { (0..config.settings.jobs) @@ -158,9 +163,6 @@ impl Toolset { s.spawn(move || { let next_job = || queue.lock().unwrap().pop(); while let Some((t, versions)) = next_job() { - if !t.is_installed() { - t.install(config, &mut mpr.add(), force)?; - } for tv in versions { let tv = tv.request.resolve(config, &t, tv.opts.clone(), true)?; let mut pr = mpr.add(); From f64635c3bd75a6f019a5937be7693f3a6d83ea38 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 16 Aug 2023 20:37:15 -0500 Subject: [PATCH 0965/1891] chore: Release --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3617a2d7..ee77a21e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1668,7 +1668,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.0" +version = "2023.8.1" dependencies = [ "base64", "built", @@ -2205,9 +2205,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.31.0" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ "backtrace", "bytes", @@ -2787,9 +2787,9 @@ checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" [[package]] name = "winnow" -version = "0.5.10" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5504cc7644f4b593cbc05c4a55bf9bd4e94b867c3c0bd440934174d50482427d" +checksum = "83817bbecf72c73bad717ee86820ebf286203d2e04c3951f3cd538869c897364" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 3027f0062..88e30906b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.0" +version = "2023.8.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 24b8be52c..e422a2850 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.0 +rtx 2023.8.1 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.0/rtx-v2023.8.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.1/rtx-v2023.8.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 84f3a6e14..b876e1268 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.0"; + version = "2023.8.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a1cfa6c27..989df318c 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.0" +.TH rtx 1 "rtx 2023.8.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -153,6 +153,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.0 +v2023.8.1 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 5dc93524a..c78d2a067 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.0 +Version: 2023.8.1 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 06f2bef728fc739e8668ce6b9c14134b697e8561 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 16 Aug 2023 22:20:45 -0500 Subject: [PATCH 0966/1891] debug --- src/http.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http.rs b/src/http.rs index b18330628..4368575d0 100644 --- a/src/http.rs +++ b/src/http.rs @@ -17,10 +17,14 @@ impl Client { } pub fn get(&self, url: U) -> RequestBuilder { + let url = url.into_url().unwrap(); + debug!("GET {}", url); self.reqwest.get(url) } pub fn get_text(&self, url: U) -> Result { + let url = url.into_url().unwrap(); + debug!("GET.txt {}", url); let resp = self.get(url).send()?; self.ensure_success(&resp)?; let text = resp.text()?; From 4446bdcb7b3a0127f80e8c808364930b41c5dd4e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 17 Aug 2023 23:00:02 -0500 Subject: [PATCH 0967/1891] rtx-use: show message after setting/removing versions (#816) also changed the logic slightly to find_up the nearest .rtx.toml if one does not exist --- src/cli/global.rs | 2 +- src/cli/local.rs | 29 +++++++++++++++---- .../rtx__cli__global__tests__global-2.snap | 1 + .../rtx__cli__global__tests__global-3.snap | 1 + .../rtx__cli__global__tests__global-4.snap | 1 + .../rtx__cli__global__tests__global.snap | 1 + ...cal__tests__local_multiple_versions-2.snap | 1 + ...tx__cli__local__tests__local_remove-2.snap | 1 + ...tx__cli__local__tests__local_remove-3.snap | 1 + .../rtx__cli__local__tests__local_remove.snap | 1 + src/cli/use.rs | 17 +++++++---- 11 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/cli/global.rs b/src/cli/global.rs index 58d35e77a..938d4df30 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -27,7 +27,7 @@ pub struct Global { /// If this is a single tool with no version, the current value of the global /// .tool-versions will be displayed #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] - tool: Option>, + tool: Vec, /// Save exact version to `~/.tool-versions` /// e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions diff --git a/src/cli/local.rs b/src/cli/local.rs index 91c498b14..6f4103e70 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -1,12 +1,15 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, ContextCompat, Result}; +use console::style; +use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; +use crate::file::display_path; use crate::output::Output; use crate::plugins::PluginName; use crate::ui::multi_progress_report::MultiProgressReport; @@ -25,8 +28,8 @@ pub struct Local { /// e.g.: node@20 /// if this is a single tool with no version, /// the current value of .tool-versions/.rtx.toml will be displayed - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] - tool: Option>, + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] + tool: Vec, /// Recurse up to find a .tool-versions file rather than using the current directory only /// by default this command will only set the tool in the current directory ("$PWD/.tool-versions") @@ -96,7 +99,7 @@ pub fn local( mut config: Config, out: &mut Output, path: &Path, - runtime: Option>, + runtime: Vec, remove: Option>, pin: bool, fuzzy: bool, @@ -116,21 +119,35 @@ pub fn local( for plugin in plugins { cf.remove_plugin(plugin); } + let tools = plugins.iter().map(|r| r.to_string()).join(" "); + rtxprintln!( + out, + "{} {}", + style(display_path(path)).dim(), + style(tools).bright().strikethrough() + ); } - if let Some(runtimes) = &runtime { - let runtimes = ToolArg::double_tool_condition(&runtimes.clone()); + if !runtime.is_empty() { + let runtimes = ToolArg::double_tool_condition(&runtime.clone()); if cf.display_runtime(out, &runtimes)? { install_missing_runtimes(&mut config, cf.as_ref())?; return Ok(()); } let pin = pin || (config.settings.asdf_compat && !fuzzy); cf.add_runtimes(&mut config, &runtimes, pin)?; + let tools = runtimes.iter().map(|r| r.to_string()).join(" "); + rtxprintln!( + out, + "{} {}", + style(display_path(path)).dim(), + style(tools).bright() + ); } else { install_missing_runtimes(&mut config, cf.as_ref())?; } - if runtime.is_some() || remove.is_some() { + if !runtime.is_empty() || remove.is_some() { cf.save()?; } else { rtxprint!(out, "{}", cf.dump()); diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap index 490bfa332..528101440 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap @@ -2,4 +2,5 @@ source: src/cli/global.rs expression: output --- +~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap index 490bfa332..5d52f5b02 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap @@ -2,4 +2,5 @@ source: src/cli/global.rs expression: output --- +~/.test-tool-versions tiny diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap index 490bfa332..528101440 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap @@ -2,4 +2,5 @@ source: src/cli/global.rs expression: output --- +~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global.snap b/src/cli/snapshots/rtx__cli__global__tests__global.snap index 490bfa332..528101440 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global.snap @@ -2,4 +2,5 @@ source: src/cli/global.rs expression: output --- +~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap index 931ef3891..66669e7d2 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap @@ -2,4 +2,5 @@ source: src/cli/local.rs expression: output --- +~/cwd/.test-tool-versions tiny@2 tiny@1 tiny@3 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap index 931ef3891..a937118be 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap @@ -2,4 +2,5 @@ source: src/cli/local.rs expression: output --- +~/cwd/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap index 931ef3891..a3ac71fd8 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap @@ -2,4 +2,5 @@ source: src/cli/local.rs expression: output --- +~/cwd/.test-tool-versions tiny diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap index 931ef3891..a937118be 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap @@ -2,4 +2,5 @@ source: src/cli/local.rs expression: output --- +~/cwd/.test-tool-versions tiny@2 diff --git a/src/cli/use.rs b/src/cli/use.rs index 5cf6f157c..44ed15257 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -9,7 +9,7 @@ use crate::config::Config; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::output::Output; use crate::plugins::PluginName; -use crate::{dirs, env}; +use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. /// @@ -69,7 +69,7 @@ impl Command for Use { config, out, &path, - Some(runtimes), + runtimes, self.remove, self.pin, self.fuzzy, @@ -90,11 +90,16 @@ fn config_file_from_dir(p: &Path) -> PathBuf { } let rtx_toml = p.join(&*RTX_DEFAULT_CONFIG_FILENAME); let tool_versions = p.join(&*RTX_DEFAULT_TOOL_VERSIONS_FILENAME); - if tool_versions.exists() && !rtx_toml.exists() { - tool_versions - } else { - rtx_toml + if rtx_toml.exists() { + return rtx_toml; + } else if tool_versions.exists() { + return tool_versions; } + let filenames = vec![RTX_DEFAULT_CONFIG_FILENAME.as_str()]; + if let Some(p) = file::find_up(p, &filenames) { + return p; + } + tool_versions } static AFTER_LONG_HELP: &str = color_print::cstr!( From 90e32be035f2e70a6bc8e2412a814f8862123cc6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 17 Aug 2023 23:30:36 -0500 Subject: [PATCH 0968/1891] help tweaks (#817) --- completions/_rtx | 236 ++++++++++++++++---------------- completions/rtx.fish | 118 ++++++++-------- man/man1/rtx.1 | 7 +- src/cli/args/install_missing.rs | 1 + src/cli/args/jobs.rs | 2 +- src/cli/external.rs | 7 +- 6 files changed, 187 insertions(+), 184 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index d825b73e0..96ebba333 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -16,9 +16,9 @@ _rtx() { local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -49,9 +49,9 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate the script for]:SHELL:(bash fish nu xonsh zsh)' \ '--shell=[Shell type to generate the script for]:SHELL:(bash fish nu xonsh zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx\: @" message when changing directories]' \ '-q[noop]' \ @@ -77,9 +77,9 @@ _arguments "${_arguments_options[@]}" \ '-p+[filter aliases by plugin]:PLUGIN: ' \ '--plugin=[filter aliases by plugin]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -107,9 +107,9 @@ Sets --jobs=1]' \ (get) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -133,9 +133,9 @@ _arguments "${_arguments_options[@]}" \ '-p+[Show aliases for ]:PLUGIN: ' \ '--plugin=[Show aliases for ]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -155,9 +155,9 @@ Sets --jobs=1]' \ (set) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -180,9 +180,9 @@ Sets --jobs=1]' \ (unset) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -244,9 +244,9 @@ esac (asdf) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -267,9 +267,9 @@ Sets --jobs=1]' \ (bin-paths) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -289,9 +289,9 @@ Sets --jobs=1]' \ (cache) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -319,9 +319,9 @@ Sets --jobs=1]' \ (clear) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -371,9 +371,9 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ '--shell=[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -394,9 +394,9 @@ Sets --jobs=1]' \ (current) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -417,9 +417,9 @@ Sets --jobs=1]' \ (deactivate) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -439,9 +439,9 @@ Sets --jobs=1]' \ (direnv) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -469,9 +469,9 @@ Sets --jobs=1]' \ (envrc) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -491,9 +491,9 @@ Sets --jobs=1]' \ (exec) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -513,9 +513,9 @@ Sets --jobs=1]' \ (activate) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -571,9 +571,9 @@ esac (doctor) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -595,9 +595,9 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate environment variables for]:SHELL:(bash fish nu xonsh zsh)' \ '--shell=[Shell type to generate environment variables for]:SHELL:(bash fish nu xonsh zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--json[Output in JSON format]' \ '--debug[Sets log level to debug]' \ @@ -621,9 +621,9 @@ _arguments "${_arguments_options[@]}" \ '--file=[The TOML file to update]:FILE: ' \ '*--remove=[Remove the environment variable from config file]:ENV_VAR: ' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -648,9 +648,9 @@ _arguments "${_arguments_options[@]}" \ '()--command=[Command string to execute]:C:_cmdstring' \ '--cd=[Change to this directory before executing the command]:CD:_files -/' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -672,9 +672,9 @@ Sets --jobs=1]' \ _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to \`~/.tool-versions\` e.g.\: \`rtx global --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ @@ -706,9 +706,9 @@ _arguments "${_arguments_options[@]}" \ '-s+[Shell type to generate script for]:SHELL:(bash fish nu xonsh zsh)' \ '--shell=[Shell type to generate script for]:SHELL:(bash fish nu xonsh zsh)' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx\: @" message when changing directories]' \ '--debug[Sets log level to debug]' \ @@ -729,9 +729,9 @@ Sets --jobs=1]' \ (implode) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--config[Also remove config directory]' \ '--dry-run[List directories that would be removed without actually removing them]' \ @@ -753,9 +753,9 @@ Sets --jobs=1]' \ (install) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Force reinstall even if already installed]' \ '--force[Force reinstall even if already installed]' \ @@ -778,9 +778,9 @@ Sets --jobs=1]' \ (latest) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-i[Show latest installed instead of available version]' \ '--installed[Show latest installed instead of available version]' \ @@ -804,9 +804,9 @@ Sets --jobs=1]' \ (link) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Overwrite an existing tool version if it exists]' \ '--force[Overwrite an existing tool version if it exists]' \ @@ -832,9 +832,9 @@ e.g.\: ~/.nvm/versions/node/v20.0.0:_files -/' \ _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the plugin(s) from .tool-versions]:PLUGIN: ' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-p[Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the tool in the current directory ("\$PWD/.tool-versions")]' \ @@ -869,9 +869,9 @@ _arguments "${_arguments_options[@]}" \ '--plugin=[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ '--prefix=[Display versions matching this prefix]:PREFIX: ' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-c[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ '--current[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ @@ -902,9 +902,9 @@ Sets --jobs=1]' \ (ls-remote) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -927,9 +927,9 @@ same as the first argument after the "@":' \ (outdated) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -952,9 +952,9 @@ If not specified, all tools in global and local configs will be shown:' \ (plugins) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[list all available remote plugins]' \ '--all[list all available remote plugins]' \ @@ -991,9 +991,9 @@ Sets --jobs=1]' \ (install) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Reinstall even if plugin exists]' \ '--force[Reinstall even if plugin exists]' \ @@ -1026,9 +1026,9 @@ Can specify multiple plugins\: `rtx plugins install node ruby python`:' \ (link) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-f[Overwrite existing plugin]' \ '--force[Overwrite existing plugin]' \ @@ -1054,9 +1054,9 @@ e.g.\: ./rtx-node:_files -/' \ (ls) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-a[List all available remote plugins Same as \`rtx plugins ls-remote\`]' \ @@ -1090,9 +1090,9 @@ Sets --jobs=1]' \ (ls-remote) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--urls[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ @@ -1115,9 +1115,9 @@ Sets --jobs=1]' \ (uninstall) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1138,9 +1138,9 @@ Sets --jobs=1]' \ (update) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '()-a[Update all plugins]' \ '()--all[Update all plugins]' \ @@ -1211,9 +1211,9 @@ esac (prune) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--dry-run[Do not actually delete anything]' \ '--debug[Sets log level to debug]' \ @@ -1235,9 +1235,9 @@ Sets --jobs=1]' \ (reshim) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1259,9 +1259,9 @@ Sets --jobs=1]' \ (self-update) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1281,9 +1281,9 @@ Sets --jobs=1]' \ (settings) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1311,9 +1311,9 @@ Sets --jobs=1]' \ (get) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1334,9 +1334,9 @@ Sets --jobs=1]' \ (ls) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1356,9 +1356,9 @@ Sets --jobs=1]' \ (set) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1380,9 +1380,9 @@ Sets --jobs=1]' \ (unset) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1443,9 +1443,9 @@ esac (shell) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '-u[Removes a previously set version]' \ '--unset[Removes a previously set version]' \ @@ -1468,9 +1468,9 @@ Sets --jobs=1]' \ (sync) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1498,9 +1498,9 @@ Sets --jobs=1]' \ (node) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--brew[Get tool versions from Homebrew]' \ '--nvm[Get tool versions from nvm]' \ @@ -1523,9 +1523,9 @@ Sets --jobs=1]' \ (python) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pyenv[Get tool versions from pyenv]' \ '--debug[Sets log level to debug]' \ @@ -1578,9 +1578,9 @@ esac (trust) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--untrust[No longer trust this config]' \ '--debug[Sets log level to debug]' \ @@ -1602,9 +1602,9 @@ Sets --jobs=1]' \ (uninstall) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1625,9 +1625,9 @@ Sets --jobs=1]' \ (upgrade) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1653,9 +1653,9 @@ _arguments "${_arguments_options[@]}" \ '-p+[Specify a path to a config file or directory]:PATH:_files' \ '--path=[Specify a path to a config file or directory]:PATH:_files' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to config file e.g.\: \`rtx use --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ @@ -1685,9 +1685,9 @@ If no version is specified, it will default to @latest:' \ (version) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1707,9 +1707,9 @@ Sets --jobs=1]' \ (where) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ @@ -1741,9 +1741,9 @@ e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ '--tool=[Use a specific tool@version e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '(--version)--plugin[Show the plugin name instead of the path]' \ '(--plugin)--version[Show the version instead of the path]' \ @@ -1766,9 +1766,9 @@ Sets --jobs=1]' \ (render-help) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel -default\: 4]: : ' \ +\[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 67cc0e2b5..8b6bdd217 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,5 +1,5 @@ complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_use_subcommand" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_use_subcommand" -l install-missing -d 'Automatically install missing tools' @@ -51,7 +51,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal comm complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,nu ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' @@ -65,7 +65,7 @@ complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Sh complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' @@ -83,7 +83,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' @@ -95,7 +95,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' @@ -106,7 +106,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' @@ -117,7 +117,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' @@ -135,7 +135,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l install-missing -d 'Automatically install missing tools' @@ -146,7 +146,7 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -l trace -d 'Sets log leve complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l install-missing -d 'Automatically install missing tools' @@ -157,7 +157,7 @@ complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l trace -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' @@ -170,7 +170,7 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l install-missing -d 'Automatically install missing tools' @@ -184,7 +184,7 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from completion" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from completion" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from completion" -l install-missing -d 'Automatically install missing tools' @@ -195,7 +195,7 @@ complete -c rtx -n "__fish_seen_subcommand_from completion" -l trace -d 'Sets lo complete -c rtx -n "__fish_seen_subcommand_from completion" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from completion" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from current" -l install-missing -d 'Automatically install missing tools' @@ -206,7 +206,7 @@ complete -c rtx -n "__fish_seen_subcommand_from current" -l trace -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l install-missing -d 'Automatically install missing tools' @@ -217,7 +217,7 @@ complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l trace -d 'Sets lo complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' @@ -234,7 +234,7 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l install-missing -d 'Automatically install missing tools' @@ -245,7 +245,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' @@ -256,7 +256,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' @@ -273,7 +273,7 @@ for direnv to consume.' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l install-missing -d 'Automatically install missing tools' @@ -285,7 +285,7 @@ complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,nu ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l json -d 'Output in JSON format' complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level to debug' @@ -299,7 +299,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l file -d 'The TOML file to update' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l remove -d 'Remove the environment variable from config file' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l install-missing -d 'Automatically install missing tools' @@ -312,7 +312,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r -f -a "(__fish_complete_command)" complete -c rtx -n "__fish_seen_subcommand_from exec" -l cd -d 'Change to this directory before executing the command' -r -f -a "(__fish_complete_directories)" complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' @@ -324,7 +324,7 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show i complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions' @@ -342,7 +342,7 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,nu ,xonsh ,zsh }" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l debug -d 'Sets log level to debug' @@ -354,7 +354,7 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l trace -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' @@ -367,7 +367,7 @@ complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' @@ -379,7 +379,7 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -s y -l yes -d 'Answer complete -c rtx -n "__fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s i -l installed -d 'Show latest installed instead of available version' complete -c rtx -n "__fish_seen_subcommand_from latest" -l debug -d 'Sets log level to debug' @@ -391,7 +391,7 @@ complete -c rtx -n "__fish_seen_subcommand_from latest" -l trace -d 'Sets log le complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from link" -s f -l force -d 'Overwrite an existing tool version if it exists' complete -c rtx -n "__fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' @@ -404,7 +404,7 @@ complete -c rtx -n "__fish_seen_subcommand_from link" -s v -l verbose -d 'Show i complete -c rtx -n "__fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the tool in the current directory ("$PWD/.tool-versions")' @@ -423,7 +423,7 @@ complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print he complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show tool versions from [PLUGIN]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l prefix -d 'Display versions matching this prefix' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' @@ -440,7 +440,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -l trace -d 'Sets log level complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' @@ -451,7 +451,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from outdated" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from outdated" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from outdated" -l install-missing -d 'Automatically install missing tools' @@ -462,7 +462,7 @@ complete -c rtx -n "__fish_seen_subcommand_from outdated" -l trace -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from outdated" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s c -l core -d 'The built-in plugins only @@ -485,7 +485,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins @@ -500,7 +500,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s f -l force -d 'Overwrite existing plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' @@ -512,7 +512,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins Same as `rtx plugins ls-remote`' @@ -531,7 +531,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' @@ -544,7 +544,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' @@ -555,7 +555,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l debug -d 'Sets log level to debug' @@ -574,7 +574,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from prune" -l debug -d 'Sets log level to debug' @@ -586,7 +586,7 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -l trace -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from prune" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from reshim" -l install-missing -d 'Automatically install missing tools' @@ -597,7 +597,7 @@ complete -c rtx -n "__fish_seen_subcommand_from reshim" -l trace -d 'Sets log le complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from self-update" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing -d 'Automatically install missing tools' @@ -608,7 +608,7 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets l complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' @@ -624,7 +624,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' @@ -635,7 +635,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' @@ -646,7 +646,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' @@ -657,7 +657,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' @@ -673,7 +673,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' complete -c rtx -n "__fish_seen_subcommand_from shell" -l debug -d 'Sets log level to debug' @@ -685,7 +685,7 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' @@ -699,7 +699,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l brew -d 'Get tool versions from Homebrew' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nvm -d 'Get tool versions from nvm' @@ -713,7 +713,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l pyenv -d 'Get tool versions from pyenv' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l debug -d 'Sets log level to debug' @@ -728,7 +728,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from trust" -l untrust -d 'No longer trust this config' complete -c rtx -n "__fish_seen_subcommand_from trust" -l debug -d 'Sets log level to debug' @@ -740,7 +740,7 @@ complete -c rtx -n "__fish_seen_subcommand_from trust" -l trace -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from trust" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from trust" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' @@ -751,7 +751,7 @@ complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l trace -d 'Sets log complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l install-missing -d 'Automatically install missing tools' @@ -764,7 +764,7 @@ complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from use" -l remove -d 'Remove the tool(s) from config file' -r complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file or directory' -r -F complete -c rtx -n "__fish_seen_subcommand_from use" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from use" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from use" -l pin -d 'Save exact version to config file e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions' @@ -781,7 +781,7 @@ complete -c rtx -n "__fish_seen_subcommand_from use" -l trace -d 'Sets log level complete -c rtx -n "__fish_seen_subcommand_from use" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from use" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from version" -l install-missing -d 'Automatically install missing tools' @@ -792,7 +792,7 @@ complete -c rtx -n "__fish_seen_subcommand_from version" -l trace -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from where" -l install-missing -d 'Automatically install missing tools' @@ -805,7 +805,7 @@ complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print he complete -c rtx -n "__fish_seen_subcommand_from which" -s t -l tool -d 'Use a specific tool@version e.g.: `rtx which npm --tool=node@20`' -r complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' @@ -818,7 +818,7 @@ complete -c rtx -n "__fish_seen_subcommand_from which" -l trace -d 'Sets log lev complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -default: 4' -r +[default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l install-missing -d 'Automatically install missing tools' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 989df318c..1bb3f48e7 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -4,7 +4,7 @@ .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS -\fBrtx\fR [\fB\-\-install\-missing\fR] [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-\-log\-level\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-y\fR|\fB\-\-yes\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> +\fBrtx\fR [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-\-log\-level\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-y\fR|\fB\-\-yes\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> .SH DESCRIPTION rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx .PP @@ -16,12 +16,9 @@ It is inspired by asdf and uses asdf\*(Aqs plugin ecosystem under the hood: https://asdf\-vm.com/ .SH OPTIONS .TP -\fB\-\-install\-missing\fR -Automatically install missing tools -.TP \fB\-j\fR, \fB\-\-jobs\fR Number of plugins and runtimes to install in parallel -default: 4 +[default: 4] .TP \fB\-\-log\-level\fR=\fILEVEL\fR [default: info] Set the log output verbosity diff --git a/src/cli/args/install_missing.rs b/src/cli/args/install_missing.rs index 9373fa67f..4086fa60d 100644 --- a/src/cli/args/install_missing.rs +++ b/src/cli/args/install_missing.rs @@ -8,6 +8,7 @@ impl InstallMissing { .long("install-missing") .help("Automatically install missing tools") .action(ArgAction::SetTrue) + .hide(true) .global(true) } } diff --git a/src/cli/args/jobs.rs b/src/cli/args/jobs.rs index 0c2ff0c56..64a99fe86 100644 --- a/src/cli/args/jobs.rs +++ b/src/cli/args/jobs.rs @@ -14,7 +14,7 @@ impl Jobs { Arg::new("jobs") .short('j') .long("jobs") - .help("Number of plugins and runtimes to install in parallel\ndefault: 4") + .help("Number of plugins and runtimes to install in parallel\n[default: 4]") .value_parser(ValueParser::new(parse_jobs)) .global(true) } diff --git a/src/cli/external.rs b/src/cli/external.rs index 59f9175f3..ee76c517c 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -30,7 +30,10 @@ pub fn execute( args: &ArgMatches, external_commands: Vec, ) -> Result<()> { - if let Some(_cmd) = external_commands.iter().find(|c| c.get_name() == plugin) { + if let Some(mut cmd) = external_commands + .into_iter() + .find(|c| c.get_name() == plugin) + { if let Some((subcommand, matches)) = args.subcommand() { let plugin = config.tools.get(&plugin.to_string()).unwrap(); let args: Vec = matches @@ -39,6 +42,8 @@ pub fn execute( .map(|s| s.to_string_lossy().to_string()) .collect(); plugin.execute_external_command(config, subcommand, args)?; + } else { + cmd.print_help().unwrap(); } } From 38b8265a1368172a9a2f5de158b1b1aa523f3dba Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 18 Aug 2023 09:15:22 -0500 Subject: [PATCH 0969/1891] help tweaks (#817) (#819) --- src/plugins/core/go.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index e0fd1f104..dd397b1ae 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -181,17 +181,19 @@ impl Plugin for GoPlugin { fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { let mut map = HashMap::new(); - if env::PRISTINE_ENV.get("GOROOT").is_none() && *env::RTX_GO_SET_GOROOT != Some(false) { - map.insert( - "GOROOT".to_string(), - self.goroot(tv).to_string_lossy().to_string(), - ); + match (*env::RTX_GO_SET_GOROOT, env::PRISTINE_ENV.get("GOROOT")) { + (Some(false), _) | (None, Some(_)) => {} + (Some(true), _) | (None, None) => { + let goroot = self.goroot(tv).to_string_lossy().to_string(); + map.insert("GOROOT".to_string(), goroot); + } }; - if env::PRISTINE_ENV.get("GOPATH").is_none() && *env::RTX_GO_SET_GOPATH != Some(false) { - map.insert( - "GOPATH".to_string(), - self.gopath(tv).to_string_lossy().to_string(), - ); + match (*env::RTX_GO_SET_GOPATH, env::PRISTINE_ENV.get("GOPATH")) { + (Some(false), _) | (None, Some(_)) => {} + (Some(true), _) | (None, None) => { + let gopath = self.gopath(tv).to_string_lossy().to_string(); + map.insert("GOPATH".to_string(), gopath); + } }; Ok(map) } From c670aba007c578490479bdf499bafb3804572cdb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:29:39 -0500 Subject: [PATCH 0970/1891] set RTX_YES=true if CI=true confirmation dialogs in CI is a bad idea --- src/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env.rs b/src/env.rs index 626a94373..333b7a1b5 100644 --- a/src/env.rs +++ b/src/env.rs @@ -94,7 +94,7 @@ pub static RTX_DISABLE_TOOLS: Lazy> = Lazy::new(|| { .unwrap_or_default() }); pub static RTX_RAW: Lazy = Lazy::new(|| var_is_true("RTX_RAW")); -pub static RTX_YES: Lazy = Lazy::new(|| var_is_true("RTX_YES")); +pub static RTX_YES: Lazy = Lazy::new(|| *CI || var_is_true("RTX_YES")); pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { var("RTX_TRUSTED_CONFIG_PATHS") .map(|v| split_paths(&v).collect()) From 7bde29a1e111bac7d3fcb8d5c38dabf3938f4bdd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:35:35 -0500 Subject: [PATCH 0971/1891] set RTX_YES=1 for tests --- .../snapshots/rtx__cli__settings__ls__tests__settings_ls.snap | 2 +- .../snapshots/rtx__cli__settings__set__tests__settings_set.snap | 2 +- src/cli/settings/unset.rs | 2 +- src/test.rs | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 9f069c6a4..aed6a2056 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -17,5 +17,5 @@ plugin_autoupdate_last_check_duration = 20 raw = false trusted_config_paths = [] verbose = true -yes = false +yes = true diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index c9a190884..1f4c6bb31 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -17,5 +17,5 @@ plugin_autoupdate_last_check_duration = 1 raw = false trusted_config_paths = [] verbose = true -yes = false +yes = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 7d674f3c0..944f52575 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -58,7 +58,7 @@ mod tests { raw = false trusted_config_paths = [] verbose = true - yes = false + yes = true "###); reset_config(); diff --git a/src/test.rs b/src/test.rs index 2d111acee..29058a4b3 100644 --- a/src/test.rs +++ b/src/test.rs @@ -18,6 +18,7 @@ fn init() { ); set_current_dir(env::HOME.join("cwd")).unwrap(); env::set_var("NO_COLOR", "1"); + env::set_var("RTX_YES", "1"); env::set_var("RTX_USE_TOML", "0"); env::set_var("RTX_DATA_DIR", env::HOME.join("data")); env::set_var("RTX_CONFIG_DIR", env::HOME.join("config")); From 48df67e1a2732bbafcf3ec04c28a4a6a33345ed5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:49:57 -0500 Subject: [PATCH 0972/1891] chore: Release --- Cargo.lock | 98 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee77a21e3..064476605 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.21" +version = "4.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" +checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2" dependencies = [ "clap_builder", "clap_derive", @@ -230,9 +230,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.21" +version = "4.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" +checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4" dependencies = [ "anstream", "anstyle", @@ -258,7 +258,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -438,7 +438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -700,7 +700,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1328,7 +1328,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1425,7 +1425,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1493,9 +1493,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1668,7 +1668,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.1" +version = "2023.8.2" dependencies = [ "base64", "built", @@ -1906,7 +1906,7 @@ checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2060,9 +2060,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -2131,22 +2131,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9207952ae1a003f42d3d5e892dac3c6ba42aa6ac0c79a6a91a2b5cb4253e75c" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1728216d3244de4f14f14f8c15c79be1a7c67867d28d69b719690e2a19fb445" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2539,7 +2539,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-shared", ] @@ -2573,7 +2573,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2650,7 +2650,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.2", + "windows-targets 0.48.4", ] [[package]] @@ -2668,7 +2668,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.2", + "windows-targets 0.48.4", ] [[package]] @@ -2688,17 +2688,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" +checksum = "d92ecb8ae0317859f509f17b19adc74b0763b0fa3b085dea8ed01085c8dac222" dependencies = [ - "windows_aarch64_gnullvm 0.48.2", - "windows_aarch64_msvc 0.48.2", - "windows_i686_gnu 0.48.2", - "windows_i686_msvc 0.48.2", - "windows_x86_64_gnu 0.48.2", - "windows_x86_64_gnullvm 0.48.2", - "windows_x86_64_msvc 0.48.2", + "windows_aarch64_gnullvm 0.48.4", + "windows_aarch64_msvc 0.48.4", + "windows_i686_gnu 0.48.4", + "windows_i686_msvc 0.48.4", + "windows_x86_64_gnu 0.48.4", + "windows_x86_64_gnullvm 0.48.4", + "windows_x86_64_msvc 0.48.4", ] [[package]] @@ -2709,9 +2709,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" +checksum = "d14b0ee96970be7108701212f097ce67ca772fd84cb0ffbc86d26a94e77ba929" [[package]] name = "windows_aarch64_msvc" @@ -2721,9 +2721,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" +checksum = "1332277d49f440c8fc6014941e320ee47ededfcce10cb272728470f56cc092c9" [[package]] name = "windows_i686_gnu" @@ -2733,9 +2733,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" +checksum = "d992130ac399d56f02c20564e9975ac5ba08cb25cb832849bbc0d736a101abe5" [[package]] name = "windows_i686_msvc" @@ -2745,9 +2745,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" +checksum = "962e96d0fa4b4773c63977977ea6564f463fb10e34a6e07360428b53ae7a3f71" [[package]] name = "windows_x86_64_gnu" @@ -2757,9 +2757,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" +checksum = "30652a53018a48a9735fbc2986ff0446c37bc8bed0d3f98a0ed4d04cdb80027e" [[package]] name = "windows_x86_64_gnullvm" @@ -2769,9 +2769,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" +checksum = "b5bb3f0331abfe1a95af56067f1e64b3791b55b5373b03869560b6025de809bf" [[package]] name = "windows_x86_64_msvc" @@ -2781,15 +2781,15 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.2" +version = "0.48.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" +checksum = "bd1df36d9fd0bbe4849461de9b969f765170f4e0f90497d580a235d515722b10" [[package]] name = "winnow" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83817bbecf72c73bad717ee86820ebf286203d2e04c3951f3cd538869c897364" +checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 88e30906b..4b13452df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.1" +version = "2023.8.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e422a2850..4055be574 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.1 +rtx 2023.8.2 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.1/rtx-v2023.8.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.2/rtx-v2023.8.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index b876e1268..396bf0374 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.1"; + version = "2023.8.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 1bb3f48e7..33c81bb6b 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.1" +.TH rtx 1 "rtx 2023.8.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.1 +v2023.8.2 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c78d2a067..e2e023538 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.1 +Version: 2023.8.2 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From c5377f47f0ccf23d640b1100c89b71ff024790d4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:41:30 -0500 Subject: [PATCH 0973/1891] set fetch remove versions cache to hourly (#820) Since this does not get run often now, I think hourly is more reasonable --- src/env.rs | 15 ++++++++++++++- src/plugins/core/java.rs | 9 +++------ src/plugins/core/mod.rs | 5 +---- src/plugins/external_plugin.rs | 8 +++----- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/env.rs b/src/env.rs index 333b7a1b5..520057b95 100644 --- a/src/env.rs +++ b/src/env.rs @@ -3,6 +3,7 @@ pub use std::env::*; use std::path::PathBuf; use std::time::Duration; +use crate::duration::HOURLY; use itertools::Itertools; use log::LevelFilter; use once_cell::sync::Lazy; @@ -59,13 +60,25 @@ pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) }); +/// duration that remote version cache is kept for +/// for "fast" commands (represented by PREFER_STALE), these are always +/// cached. For "slow" commands like `rtx ls-remote` or `rtx install`: +/// - if RTX_FETCH_REMOTE_VERSIONS_CACHE is set, use that +/// - if RTX_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY +pub static RTX_FETCH_REMOTE_VERSIONS_CACHE: Lazy> = Lazy::new(|| { + if *PREFER_STALE { + None + } else { + Some(var_duration("RTX_FETCH_REMOTE_VERSIONS_CACHE").unwrap_or(HOURLY)) + } +}); + /// true if inside a script like bin/exec-env or bin/install /// used to prevent infinite loops pub static __RTX_SCRIPT: Lazy = Lazy::new(|| var_is_true("__RTX_SCRIPT")); pub static __RTX_DIFF: Lazy = Lazy::new(get_env_diff); pub static CI: Lazy = Lazy::new(|| var_is_true("CI")); pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS)); - /// essentially, this is whether we show spinners or build output on runtime install pub static PRISTINE_ENV: Lazy> = Lazy::new(|| get_pristine_env(&__RTX_DIFF, vars().collect())); diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 4746648ab..b749824ec 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -13,13 +13,11 @@ use crate::cache::CacheManager; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::duration::DAILY; -use crate::env::PREFER_STALE; use crate::plugins::core::CorePlugin; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; -use crate::{file, hash, http}; +use crate::{env, file, hash, http}; #[derive(Debug)] pub struct JavaPlugin { @@ -31,7 +29,6 @@ pub struct JavaPlugin { impl JavaPlugin { pub fn new(name: PluginName) -> Self { let core = CorePlugin::new(name); - let fresh_duration = if *PREFER_STALE { None } else { Some(DAILY) }; let java_metadata_ga_cache_filename = format!("java_metadata_ga_{}_{}.msgpack.z", os(), arch()); let java_metadata_ea_cache_filename = @@ -40,11 +37,11 @@ impl JavaPlugin { java_metadata_ea_cache: CacheManager::new( core.cache_path.join(java_metadata_ea_cache_filename), ) - .with_fresh_duration(fresh_duration), + .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), java_metadata_ga_cache: CacheManager::new( core.cache_path.join(java_metadata_ga_cache_filename), ) - .with_fresh_duration(fresh_duration), + .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), core, } } diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index df1f7a28d..c3ab10415 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -9,8 +9,6 @@ use once_cell::sync::Lazy; pub use python::PythonPlugin; use crate::cache::CacheManager; -use crate::duration::DAILY; -use crate::env::PREFER_STALE; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; use crate::plugins::core::go::GoPlugin; @@ -69,10 +67,9 @@ pub struct CorePlugin { impl CorePlugin { pub fn new(name: PluginName) -> Self { let cache_path = dirs::CACHE.join(&name); - let fresh_duration = if *PREFER_STALE { None } else { Some(DAILY) }; Self { remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(fresh_duration), + .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), name, cache_path, } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index fa5060906..3c9080252 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -13,8 +13,7 @@ use once_cell::sync::Lazy; use crate::cache::CacheManager; use crate::config::{Config, Settings}; -use crate::duration::DAILY; -use crate::env::{PREFER_STALE, RTX_FETCH_REMOTE_VERSIONS_TIMEOUT}; +use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; use crate::file::remove_all; @@ -54,7 +53,6 @@ impl ExternalPlugin { let cache_path = dirs::CACHE.join(name); let toml_path = plugin_path.join("rtx.plugin.toml"); let toml = RtxPluginToml::from_file(&toml_path).unwrap(); - let fresh_duration = if *PREFER_STALE { None } else { Some(DAILY) }; Self { name: name.into(), script_man: build_script_man(name, &plugin_path), @@ -62,11 +60,11 @@ impl ExternalPlugin { installs_path: dirs::INSTALLS.join(name), cache: ExternalPluginCache::default(), remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(fresh_duration) + .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-all")), latest_stable_cache: CacheManager::new(cache_path.join("latest_stable.msgpack.z")) - .with_fresh_duration(fresh_duration) + .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/latest-stable")), alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.z")) From 554770808bc1de531e33833ec6a397a03d86a343 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 18 Aug 2023 13:02:38 -0500 Subject: [PATCH 0974/1891] tweak output of `rtx use` status (#821) this matches installation output better --- src/cli/local.rs | 14 ++++++++------ .../rtx__cli__global__tests__global-2.snap | 2 +- .../rtx__cli__global__tests__global-3.snap | 2 +- .../rtx__cli__global__tests__global-4.snap | 2 +- .../snapshots/rtx__cli__global__tests__global.snap | 2 +- ...i__local__tests__local_multiple_versions-2.snap | 2 +- .../rtx__cli__local__tests__local_remove-2.snap | 2 +- .../rtx__cli__local__tests__local_remove-3.snap | 2 +- .../rtx__cli__local__tests__local_remove.snap | 2 +- 9 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/cli/local.rs b/src/cli/local.rs index 6f4103e70..5a0857f68 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -122,9 +122,10 @@ pub fn local( let tools = plugins.iter().map(|r| r.to_string()).join(" "); rtxprintln!( out, - "{} {}", - style(display_path(path)).dim(), - style(tools).bright().strikethrough() + "{} {} {}", + style("rtx").dim(), + display_path(path), + style(tools).cyan().strikethrough() ); } @@ -139,9 +140,10 @@ pub fn local( let tools = runtimes.iter().map(|r| r.to_string()).join(" "); rtxprintln!( out, - "{} {}", - style(display_path(path)).dim(), - style(tools).bright() + "{} {} {}", + style("rtx").dim(), + display_path(path), + style(tools).cyan() ); } else { install_missing_runtimes(&mut config, cf.as_ref())?; diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap index 528101440..faa0fcf50 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap @@ -2,5 +2,5 @@ source: src/cli/global.rs expression: output --- -~/.test-tool-versions tiny@2 +rtx ~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap index 5d52f5b02..f7307196e 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap @@ -2,5 +2,5 @@ source: src/cli/global.rs expression: output --- -~/.test-tool-versions tiny +rtx ~/.test-tool-versions tiny diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap index 528101440..faa0fcf50 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap @@ -2,5 +2,5 @@ source: src/cli/global.rs expression: output --- -~/.test-tool-versions tiny@2 +rtx ~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global.snap b/src/cli/snapshots/rtx__cli__global__tests__global.snap index 528101440..faa0fcf50 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global.snap @@ -2,5 +2,5 @@ source: src/cli/global.rs expression: output --- -~/.test-tool-versions tiny@2 +rtx ~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap index 66669e7d2..deb3edce6 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap @@ -2,5 +2,5 @@ source: src/cli/local.rs expression: output --- -~/cwd/.test-tool-versions tiny@2 tiny@1 tiny@3 +rtx ~/cwd/.test-tool-versions tiny@2 tiny@1 tiny@3 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap index a937118be..68b44c45c 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap @@ -2,5 +2,5 @@ source: src/cli/local.rs expression: output --- -~/cwd/.test-tool-versions tiny@2 +rtx ~/cwd/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap index a3ac71fd8..bdf7a29b0 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap @@ -2,5 +2,5 @@ source: src/cli/local.rs expression: output --- -~/cwd/.test-tool-versions tiny +rtx ~/cwd/.test-tool-versions tiny diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap index a937118be..68b44c45c 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap @@ -2,5 +2,5 @@ source: src/cli/local.rs expression: output --- -~/cwd/.test-tool-versions tiny@2 +rtx ~/cwd/.test-tool-versions tiny@2 From 92524429866d3432ca534f50a0da6c15b7ca173e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 02:12:14 +0000 Subject: [PATCH 0975/1891] chore(deps): bump clap from 4.3.22 to 4.3.23 (#824) Bumps [clap](https://github.com/clap-rs/clap) from 4.3.22 to 4.3.23. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.3.22...v4.3.23) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 064476605..1a695f14a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.22" +version = "4.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2" +checksum = "03aef18ddf7d879c15ce20f04826ef8418101c7e528014c3eeea13321047dca3" dependencies = [ "clap_builder", "clap_derive", @@ -230,9 +230,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.22" +version = "4.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4" +checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98" dependencies = [ "anstream", "anstyle", From d7e2de6e113fb73ef004c9390781ab51dfdad151 Mon Sep 17 00:00:00 2001 From: fang duan Date: Tue, 22 Aug 2023 00:47:47 +0800 Subject: [PATCH 0976/1891] update nodejs doc (#829) * update nodejs doc * Update docs/node.md * Update docs/node.md --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- docs/node.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/node.md b/docs/node.md index 87eef09e4..e2e52f654 100644 --- a/docs/node.md +++ b/docs/node.md @@ -19,6 +19,12 @@ $ rtx use -g node@20 Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. + +## Requirements + +rtx uses [node-build](https://github.com/nodenv/node-build) to install node runtimes, you need to ensure the [dependencies](https://github.com/nodenv/node-build/wiki#suggested-build-environment) are installed before installing node. + + ## Configuration `node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-node` has a few extra configuration variables: From 628f95743eae7f10d1286db66e98ef63a8c927d9 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 22 Aug 2023 12:23:21 +0900 Subject: [PATCH 0977/1891] stop overwriting pre_prompt and PWD in nushell.rs (#830) * stop overwriting pre_prompt and PWD in nushell.rs * update nushell hook_init.snap and hook_init_nix.snap --- src/shell/nushell.rs | 10 ++++++---- .../rtx__shell__nushell__tests__hook_init.snap | 10 ++++++---- .../rtx__shell__nushell__tests__hook_init_nix.snap | 10 ++++++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 9ea55c3d5..f43ddf3c7 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -41,15 +41,17 @@ impl Shell for Nushell { $env.RTX_SHELL = "nu" $env.config = ($env.config | upsert hooks {{ - pre_prompt: [{{ + pre_prompt: ($env.config.hooks.pre_prompt ++ + [{{ condition: {{|| "RTX_SHELL" in $env }} code: {{|| rtx_hook }} - }}] + }}]) env_change: {{ - PWD: [{{ + PWD: ($env.config.hooks.env_change.PWD ++ + [{{ condition: {{|| "RTX_SHELL" in $env }} code: {{|| rtx_hook }} - }}] + }}]) }} }}) }} diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap index db531511a..435bf2e85 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap @@ -7,15 +7,17 @@ export-env { $env.RTX_SHELL = "nu" $env.config = ($env.config | upsert hooks { - pre_prompt: [{ + pre_prompt: ($env.config.hooks.pre_prompt ++ + [{ condition: {|| "RTX_SHELL" in $env } code: {|| rtx_hook } - }] + }]) env_change: { - PWD: [{ + PWD: ($env.config.hooks.env_change.PWD ++ + [{ condition: {|| "RTX_SHELL" in $env } code: {|| rtx_hook } - }] + }]) } }) } diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap index f3ce71ca3..2e59ba9e1 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap @@ -6,15 +6,17 @@ export-env { $env.RTX_SHELL = "nu" $env.config = ($env.config | upsert hooks { - pre_prompt: [{ + pre_prompt: ($env.config.hooks.pre_prompt ++ + [{ condition: {|| "RTX_SHELL" in $env } code: {|| rtx_hook } - }] + }]) env_change: { - PWD: [{ + PWD: ($env.config.hooks.env_change.PWD ++ + [{ condition: {|| "RTX_SHELL" in $env } code: {|| rtx_hook } - }] + }]) } }) } From 5e58dfce8e0edae5b64bf50346028936f8646fe9 Mon Sep 17 00:00:00 2001 From: fang duan Date: Tue, 22 Aug 2023 23:35:39 +0800 Subject: [PATCH 0978/1891] update python doc (#828) * update python doc * Update docs/python.md --------- Co-authored-by: Jeff Dickey <216188+jdxcode@users.noreply.github.com> --- docs/python.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/python.md b/docs/python.md index 0b4e88c2f..655851f25 100644 --- a/docs/python.md +++ b/docs/python.md @@ -26,6 +26,11 @@ $ python3.11 -V 3.11.0 ``` +## Requirements + +rtx uses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/python-build) (part of pyenv) to install python runtimes, you need to ensure its [dependencies](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) are installed before installing python. + + ## Configuration `python-build` already has a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in From 1364a161ee800ab29c6ed6730f7e49f5cdd795d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:01:51 +0000 Subject: [PATCH 0979/1891] chore(deps): bump rustls-webpki from 0.101.3 to 0.101.4 (#832) Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.101.3 to 0.101.4. - [Release notes](https://github.com/rustls/webpki/releases) - [Commits](https://github.com/rustls/webpki/compare/v/0.101.3...v/0.101.4) --- updated-dependencies: - dependency-name: rustls-webpki dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 22 +++++++++++----------- deny.toml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a695f14a..126a41faf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1791,9 +1791,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.3" +version = "0.101.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ "ring", "untrusted", @@ -2693,12 +2693,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92ecb8ae0317859f509f17b19adc74b0763b0fa3b085dea8ed01085c8dac222" dependencies = [ "windows_aarch64_gnullvm 0.48.4", - "windows_aarch64_msvc 0.48.4", + "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.4", - "windows_i686_msvc 0.48.4", + "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.4", "windows_x86_64_gnullvm 0.48.4", - "windows_x86_64_msvc 0.48.4", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -2721,9 +2721,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1332277d49f440c8fc6014941e320ee47ededfcce10cb272728470f56cc092c9" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" @@ -2745,9 +2745,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962e96d0fa4b4773c63977977ea6564f463fb10e34a6e07360428b53ae7a3f71" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" @@ -2781,9 +2781,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd1df36d9fd0bbe4849461de9b969f765170f4e0f90497d580a235d515722b10" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" diff --git a/deny.toml b/deny.toml index 64945b22f..310d0c027 100644 --- a/deny.toml +++ b/deny.toml @@ -74,7 +74,7 @@ notice = "warn" # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ - #"RUSTSEC-0000-0000", + "RUSTSEC-2023-0052", # webpki ] # Threshold for security vulnerabilities, any vulnerability with a CVSS score # lower than the range specified will be ignored. Note that ignored advisories From 7372e7518314f399dab662c06af60fa38e498d3e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:55:39 -0500 Subject: [PATCH 0980/1891] turned on lto --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 4b13452df..b130fb4be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,9 @@ path = "src/main.rs" #name = "config_bench" #harness = false +[profile.release] +lto = true + [dependencies] base64 = "<0.22" chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } From 8c750cf3b1dbc8a51bdf92f90d67170aff18b58e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:36:36 -0500 Subject: [PATCH 0981/1891] increase build timeouts --- .github/workflows/rtx.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 39b7d5609..658cc1607 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -79,7 +79,7 @@ jobs: build-linux: name: build-${{matrix.target}} runs-on: ubuntu-22.04 - timeout-minutes: 20 + timeout-minutes: 30 strategy: fail-fast: false matrix: @@ -111,7 +111,7 @@ jobs: build-macos: name: build-${{matrix.target}} runs-on: macos-12 - timeout-minutes: 20 + timeout-minutes: 30 strategy: fail-fast: false matrix: From 243e5ab74274d8754cd71a41f978c758aa3db64d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:38:28 -0500 Subject: [PATCH 0982/1891] chore: Release --- Cargo.lock | 114 ++++++++++++++++++----------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 58 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 126a41faf..05c38ed0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -98,9 +98,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -191,9 +191,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", "libc", @@ -453,9 +453,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] name = "dialoguer" @@ -754,9 +754,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "git2" @@ -797,9 +797,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -1292,9 +1292,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "memchr", ] @@ -1582,9 +1582,9 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "20b9b67e2ca7dd9e9f9285b759de30ff538aab981abaaf7bc9bd90b84a0126c3" dependencies = [ "base64", "bytes", @@ -1668,7 +1668,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.2" +version = "2023.8.3" dependencies = [ "base64", "built", @@ -1891,18 +1891,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.183" +version = "1.0.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.183" +version = "1.0.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec" dependencies = [ "proc-macro2", "quote", @@ -2002,9 +2002,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -2082,9 +2082,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.7.1" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", @@ -2160,9 +2160,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" +checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" dependencies = [ "deranged", "itoa", @@ -2181,9 +2181,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" dependencies = [ "time-core", ] @@ -2594,24 +2594,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "winapi" @@ -2650,7 +2637,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.4", + "windows-targets 0.48.5", ] [[package]] @@ -2668,7 +2655,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.4", + "windows-targets 0.48.5", ] [[package]] @@ -2688,16 +2675,16 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92ecb8ae0317859f509f17b19adc74b0763b0fa3b085dea8ed01085c8dac222" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.4", + "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.4", + "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.4", - "windows_x86_64_gnullvm 0.48.4", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] @@ -2709,9 +2696,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14b0ee96970be7108701212f097ce67ca772fd84cb0ffbc86d26a94e77ba929" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" @@ -2733,9 +2720,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d992130ac399d56f02c20564e9975ac5ba08cb25cb832849bbc0d736a101abe5" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" @@ -2757,9 +2744,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30652a53018a48a9735fbc2986ff0446c37bc8bed0d3f98a0ed4d04cdb80027e" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" @@ -2769,9 +2756,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.4" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bb3f0331abfe1a95af56067f1e64b3791b55b5373b03869560b6025de809bf" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" @@ -2796,11 +2783,12 @@ dependencies = [ [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b130fb4be..2c4011e8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.2" +version = "2023.8.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 4055be574..8eba07b6b 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.2 +rtx 2023.8.3 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.2/rtx-v2023.8.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.3/rtx-v2023.8.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 396bf0374..465d60608 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.2"; + version = "2023.8.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 33c81bb6b..647860ae0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.2" +.TH rtx 1 "rtx 2023.8.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.2 +v2023.8.3 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e2e023538..4d1a112e1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.2 +Version: 2023.8.3 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 11240d0fd7b9808ac0f5b6740547f638e9ad8d67 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:52:12 -0500 Subject: [PATCH 0983/1891] increase build timeouts --- .github/workflows/rtx.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 658cc1607..1790cc096 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -79,7 +79,7 @@ jobs: build-linux: name: build-${{matrix.target}} runs-on: ubuntu-22.04 - timeout-minutes: 30 + timeout-minutes: 45 strategy: fail-fast: false matrix: @@ -111,7 +111,7 @@ jobs: build-macos: name: build-${{matrix.target}} runs-on: macos-12 - timeout-minutes: 30 + timeout-minutes: 45 strategy: fail-fast: false matrix: From 0dea4f31e17a4506169bcecb35f4a0bd0615ddd7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 22 Aug 2023 18:33:30 -0500 Subject: [PATCH 0984/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05c38ed0e..e61101d20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1668,7 +1668,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.3" +version = "2023.8.4" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 2c4011e8b..d1aec01dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.3" +version = "2023.8.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 8eba07b6b..761dc846b 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.3 +rtx 2023.8.4 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.3/rtx-v2023.8.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.4/rtx-v2023.8.4-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 465d60608..20e399c73 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.3"; + version = "2023.8.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 647860ae0..587638ace 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.3" +.TH rtx 1 "rtx 2023.8.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.3 +v2023.8.4 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 4d1a112e1..11428b466 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.3 +Version: 2023.8.4 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From c2728afbc4e99ebed1aa58d1a0cdff93117175b2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 22 Aug 2023 18:37:56 -0500 Subject: [PATCH 0985/1891] fix race condition with cache file writing (#833) --- Cargo.lock | 37 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/cache.rs | 5 ++++- src/lib.rs | 1 + src/main.rs | 1 + src/rand.rs | 10 ++++++++++ 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/rand.rs diff --git a/Cargo.lock b/Cargo.lock index e61101d20..5292a6387 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1463,6 +1463,12 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -1500,6 +1506,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" version = "1.7.0" @@ -1701,6 +1737,7 @@ dependencies = [ "openssl", "path-absolutize", "pretty_assertions", + "rand", "rayon", "regex", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index d1aec01dc..6dca1187d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,7 @@ num_cpus = "1.14" once_cell = "1.18" openssl = { version = "0.10", optional = true } path-absolutize = "3.1" +rand = "0.8" rayon = "1.6" regex = "1.9" reqwest = { version = "0.11.17", default-features = false, features = [ diff --git a/src/cache.rs b/src/cache.rs index bd53655ee..95fd75cb8 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -14,6 +14,7 @@ use serde::de::DeserializeOwned; use serde::Serialize; use crate::file::{display_path, modified_duration}; +use crate::rand::random_string; #[derive(Debug, Clone)] pub struct CacheManager @@ -88,7 +89,9 @@ where if let Some(parent) = self.cache_file_path.parent() { fs::create_dir_all(parent)?; } - let partial_path = self.cache_file_path.with_extension("part"); + let partial_path = self + .cache_file_path + .with_extension(format!("part-{}", random_string(8))); let mut zlib = ZlibEncoder::new(File::create(&partial_path)?, Compression::fast()); zlib.write_all(&rmp_serde::to_vec_named(&val)?[..])?; fs::rename(&partial_path, &self.cache_file_path)?; diff --git a/src/lib.rs b/src/lib.rs index a9a05d813..8df8f9d5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ mod hook_env; mod http; mod lock_file; mod plugins; +mod rand; mod runtime_symlinks; mod shell; mod shims; diff --git a/src/main.rs b/src/main.rs index d9b5d6388..302312d87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,7 @@ mod lock_file; mod logger; mod migrate; mod plugins; +mod rand; mod runtime_symlinks; mod shell; mod shims; diff --git a/src/rand.rs b/src/rand.rs new file mode 100644 index 000000000..b5b975ad1 --- /dev/null +++ b/src/rand.rs @@ -0,0 +1,10 @@ +use rand::distributions::Alphanumeric; +use rand::Rng; + +pub fn random_string(length: usize) -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(length) + .map(char::from) + .collect::() +} From a0f759bf28d201de2add9c4687c7a5f8a5757d48 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Tue, 22 Aug 2023 18:49:10 -0500 Subject: [PATCH 0986/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5292a6387..74d5f5c73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1704,7 +1704,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.4" +version = "2023.8.6" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 6dca1187d..72f6bc467 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.4" +version = "2023.8.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 761dc846b..e77b4a6cd 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.4 +rtx 2023.8.6 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.4/rtx-v2023.8.4-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.6/rtx-v2023.8.6-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 20e399c73..04afd2b41 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.4"; + version = "2023.8.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 587638ace..b0ebd0894 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.4" +.TH rtx 1 "rtx 2023.8.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.4 +v2023.8.6 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 11428b466..430b98a45 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.4 +Version: 2023.8.6 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From 8133fda4b6c9ded1e83a2c327eb58fe3a69e5b13 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 23 Aug 2023 09:31:31 -0500 Subject: [PATCH 0987/1891] show trace logs when performing rename/create_dir_all (#834) * show trace output when renaming * show trace output when renaming and doing create_dir_all --- src/cache.rs | 5 +++-- src/cli/link.rs | 5 ++--- src/cli/plugins/link.rs | 5 ++--- src/cli/version.rs | 4 ++-- src/config/config_file/mod.rs | 4 ++-- src/fake_asdf.rs | 4 ++-- src/file.rs | 10 ++++++++-- src/migrate.rs | 3 +-- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/java.rs | 2 +- src/plugins/external_plugin.rs | 2 +- src/tool.rs | 10 +++++----- 13 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index 95fd75cb8..77c2d56b6 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -13,6 +13,7 @@ use once_cell::sync::OnceCell; use serde::de::DeserializeOwned; use serde::Serialize; +use crate::file; use crate::file::{display_path, modified_duration}; use crate::rand::random_string; @@ -87,14 +88,14 @@ where pub fn write(&self, val: &T) -> Result<()> { trace!("writing {}", display_path(&self.cache_file_path)); if let Some(parent) = self.cache_file_path.parent() { - fs::create_dir_all(parent)?; + file::create_dir_all(parent)?; } let partial_path = self .cache_file_path .with_extension(format!("part-{}", random_string(8))); let mut zlib = ZlibEncoder::new(File::create(&partial_path)?, Compression::fast()); zlib.write_all(&rmp_serde::to_vec_named(&val)?[..])?; - fs::rename(&partial_path, &self.cache_file_path)?; + file::rename(&partial_path, &self.cache_file_path)?; Ok(()) } diff --git a/src/cli/link.rs b/src/cli/link.rs index 019dc857e..3c454725d 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -1,4 +1,3 @@ -use std::fs; use std::path::PathBuf; use clap::ValueHint; @@ -9,9 +8,9 @@ use path_absolutize::Absolutize; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; -use crate::dirs; use crate::file::{make_symlink, remove_all}; use crate::output::Output; +use crate::{dirs, file}; /// Symlinks a tool version into rtx /// @@ -64,7 +63,7 @@ impl Command for Link { )); } } - fs::create_dir_all(target.parent().unwrap())?; + file::create_dir_all(target.parent().unwrap())?; make_symlink(&path, &target)?; config.rebuild_shims_and_runtime_symlinks() diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index e13d50322..caebbc059 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -1,4 +1,3 @@ -use std::fs; use std::path::{Path, PathBuf}; use clap::ValueHint; @@ -8,10 +7,10 @@ use path_absolutize::Absolutize; use crate::cli::command::Command; use crate::config::Config; -use crate::dirs; use crate::file::{make_symlink, remove_all}; use crate::output::Output; use crate::plugins::unalias_plugin; +use crate::{dirs, file}; /// Symlinks a plugin into rtx /// @@ -57,7 +56,7 @@ impl Command for PluginsLink { )); } } - fs::create_dir_all(&*dirs::PLUGINS)?; + file::create_dir_all(&*dirs::PLUGINS)?; make_symlink(&path, &symlink)?; Ok(()) } diff --git a/src/cli/version.rs b/src/cli/version.rs index c3da8542b..bb6c39445 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -13,7 +13,7 @@ use crate::config::Config; use crate::env::CI; use crate::file::modified_duration; use crate::output::Output; -use crate::{dirs, duration}; +use crate::{dirs, duration, file}; #[derive(Debug, clap::Args)] #[clap(about = "Show rtx version", alias = "v")] @@ -98,7 +98,7 @@ fn get_latest_version(duration: Duration) -> Option { } } } - let _ = fs::create_dir_all(&*dirs::CACHE); + let _ = file::create_dir_all(&*dirs::CACHE); let version = get_latest_version_call(); let _ = fs::write(version_file_path, version.clone().unwrap_or_default()); version diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index b19cb3392..cb5945476 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -17,7 +17,7 @@ use crate::output::Output; use crate::plugins::PluginName; use crate::toolset::{ToolVersion, ToolVersionList, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::{dirs, env}; +use crate::{dirs, env, file}; pub mod legacy_version; pub mod rtx_toml; @@ -174,7 +174,7 @@ pub fn is_trusted(settings: &Settings, path: &Path) -> bool { pub fn trust(path: &Path) -> Result<()> { let hashed_path = trust_path(path.to_path_buf())?; if !hashed_path.exists() { - fs::create_dir_all(hashed_path.parent().unwrap())?; + file::create_dir_all(hashed_path.parent().unwrap())?; fs::write(hashed_path, "")?; } Ok(()) diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 349b561cc..be02b63b9 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -6,7 +6,7 @@ use std::{fs, io}; use indoc::formatdoc; use once_cell::sync::OnceCell; -use crate::env; +use crate::{env, file}; pub fn setup() -> color_eyre::Result { static SETUP: OnceCell = OnceCell::new(); @@ -14,7 +14,7 @@ pub fn setup() -> color_eyre::Result { let path = env::RTX_DATA_DIR.join(".fake-asdf"); let asdf_bin = path.join("asdf"); if !asdf_bin.exists() { - fs::create_dir_all(&path)?; + file::create_dir_all(&path)?; fs::write( &asdf_bin, // rtx="${{RTX_EXE:-rtx}}" diff --git a/src/file.rs b/src/file.rs index cbf4fe655..5d3d0789a 100644 --- a/src/file.rs +++ b/src/file.rs @@ -35,11 +35,17 @@ pub fn remove_all_with_warning>(path: P) -> io::Result<()> { }) } +pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + let from = from.as_ref(); + let to = to.as_ref(); + trace!("mv {} {}", from.display(), to.display()); + fs::rename(from, to) +} + pub fn create_dir_all>(path: P) -> io::Result<()> { let path = path.as_ref(); trace!("mkdir -p {}", path.display()); - fs::create_dir_all(path)?; - Ok(()) + fs::create_dir_all(path) } pub fn basename(path: &Path) -> Option { diff --git a/src/migrate.rs b/src/migrate.rs index 99cd54efd..e720d3642 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -1,4 +1,3 @@ -use std::fs; use std::path::Path; use color_eyre::eyre::Result; @@ -24,7 +23,7 @@ fn move_subdirs(from: &Path, to: &Path) -> Result<()> { 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::rename(from_file, to_file)?; } } file::remove_all(from)?; diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 0ce292b3b..6e16f4954 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -79,7 +79,7 @@ impl BunPlugin { fs::remove_dir_all(tv.install_path())?; file::create_dir_all(tv.install_path().join("bin"))?; file::unzip(tarball_path, &tv.download_path())?; - fs::rename( + file::rename( tv.download_path() .join(format!("bun-{}-{}", os(), arch())) .join("bun"), diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 9598186de..e06b3e632 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -84,7 +84,7 @@ impl DenoPlugin { fs::remove_dir_all(tv.install_path())?; file::create_dir_all(tv.install_path().join("bin"))?; file::unzip(tarball_path, &tv.download_path())?; - fs::rename(tv.download_path().join("deno"), self.deno_bin(tv))?; + file::rename(tv.download_path().join("deno"), self.deno_bin(tv))?; file::make_executable(&self.deno_bin(tv))?; Ok(()) } diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index b749824ec..62c5475a4 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -151,7 +151,7 @@ impl JavaPlugin { let entry = entry?; let dest = tv.install_path().join(entry.file_name()); trace!("moving {:?} to {:?}", entry.path(), &dest); - fs::rename(entry.path(), dest)?; + file::rename(entry.path(), dest)?; } Ok(()) } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 3c9080252..780dd209d 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -232,7 +232,7 @@ impl ExternalPlugin { fn write_legacy_cache(&self, legacy_file: &Path, legacy_version: &str) -> Result<()> { let fp = self.legacy_cache_file_path(legacy_file); - fs::create_dir_all(fp.parent().unwrap())?; + file::create_dir_all(fp.parent().unwrap())?; fs::write(fp, legacy_version)?; Ok(()) } diff --git a/src/tool.rs b/src/tool.rs index 645038150..c6205d7d8 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -12,7 +12,7 @@ use regex::Regex; use versions::Versioning; use crate::config::{Config, Settings}; -use crate::file::{create_dir_all, display_path, remove_all_with_warning}; +use crate::file::{display_path, remove_all_with_warning}; use crate::plugins::{ExternalPlugin, Plugin}; use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest}; @@ -196,7 +196,7 @@ impl Tool { pub fn create_symlink(&self, version: &str, target: &Path) -> Result<()> { let link = self.installs_path.join(version); - fs::create_dir_all(link.parent().unwrap())?; + file::create_dir_all(link.parent().unwrap())?; file::make_symlink(target, &link) } @@ -336,9 +336,9 @@ impl Tool { let _ = remove_all_with_warning(tv.download_path()); let _ = remove_all_with_warning(tv.cache_path()); let _ = fs::remove_file(tv.install_path()); // removes if it is a symlink - create_dir_all(tv.install_path())?; - create_dir_all(tv.download_path())?; - create_dir_all(tv.cache_path())?; + file::create_dir_all(tv.install_path())?; + file::create_dir_all(tv.download_path())?; + file::create_dir_all(tv.cache_path())?; File::create(self.incomplete_file_path(tv))?; Ok(()) } From 030dd185c4a748ab207612d4278728cdc6568761 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:35:31 -0500 Subject: [PATCH 0988/1891] improve logging on file functions (#835) --- src/cache.rs | 4 +- src/cli/direnv/envrc.rs | 5 +- src/cli/env_vars.rs | 14 +++--- src/cli/global.rs | 9 ++-- src/cli/implode.rs | 4 +- src/cli/local.rs | 10 ++-- src/cli/render_help.rs | 12 ++--- ...i__env_vars__tests__env_vars_remove-2.snap | 3 +- .../rtx__cli__r#use__tests__use_local-3.snap | 3 +- src/cli/use.rs | 27 +++++----- src/cli/version.rs | 5 +- src/config/config_file/mod.rs | 6 +-- src/config/config_file/rtx_toml.rs | 18 ++----- src/config/config_file/tool_versions.rs | 7 ++- src/config/mod.rs | 16 ++---- src/fake_asdf.rs | 7 +-- src/file.rs | 49 ++++++++++++++----- src/lock_file.rs | 3 +- src/plugins/core/bun.rs | 3 +- src/plugins/core/deno.rs | 4 +- src/plugins/core/go.rs | 4 +- src/plugins/core/java.rs | 2 +- src/plugins/core/node.rs | 12 ++--- src/plugins/core/python.rs | 2 +- src/plugins/core/ruby.rs | 14 +++--- src/plugins/external_plugin.rs | 2 +- src/plugins/mod.rs | 3 +- src/plugins/rtx_plugin_toml.rs | 5 +- src/runtime_symlinks.rs | 8 +-- src/shims.rs | 4 +- src/shorthands.rs | 6 +-- src/test.rs | 9 ++-- src/tool.rs | 6 +-- src/toolset/tool_version_list.rs | 6 +-- 34 files changed, 147 insertions(+), 145 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index 77c2d56b6..5c10ecb49 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,5 +1,5 @@ use std::cmp::min; -use std::fs; + use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; @@ -105,7 +105,7 @@ where let path = &self.cache_file_path; trace!("clearing cache {}", path.display()); if path.exists() { - fs::remove_file(path)?; + file::remove_file(path)?; } Ok(()) } diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index f92789022..38a243538 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -60,11 +60,10 @@ impl Command for Envrc { #[cfg(test)] mod tests { - use std::fs; use insta::assert_display_snapshot; - use crate::assert_cli; + use crate::{assert_cli, file}; use super::*; @@ -72,7 +71,7 @@ mod tests { fn test_direnv_envrc() { assert_cli!("install"); let stdout = assert_cli!("direnv", "envrc"); - let envrc = fs::read_to_string(stdout.trim()).unwrap(); + let envrc = file::read_to_string(stdout.trim()).unwrap(); let envrc = envrc.replace(dirs::HOME.to_string_lossy().as_ref(), "~"); let envrc = envrc .lines() diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index a566faa5a..6b1dbf221 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -70,15 +70,15 @@ fn get_rtx_toml(config: &Config, filename: &str) -> Result { #[cfg(test)] mod tests { - use std::{fs, path::PathBuf}; + use std::path::PathBuf; use insta::assert_snapshot; - use crate::{assert_cli, dirs}; + use crate::{assert_cli, dirs, file}; fn remove_config_file(filename: &str) -> PathBuf { let cf_path = dirs::CURRENT.join(filename); - let _ = fs::remove_file(&cf_path); + let _ = file::remove_file(&cf_path); cf_path } @@ -88,14 +88,14 @@ mod tests { let filename = ".test.rtx.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "FOO=bar"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); remove_config_file(filename); // Using a custom file let filename = ".test-custom.rtx.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "--file", filename, "FOO=bar"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); remove_config_file(filename); } @@ -106,7 +106,7 @@ mod tests { let cf_path = remove_config_file(filename); assert_cli!("env-vars", "BAZ=quux"); assert_cli!("env-vars", "--remove", "BAZ"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); remove_config_file(filename); // Using a custom file @@ -114,7 +114,7 @@ mod tests { let cf_path = remove_config_file(filename); assert_cli!("env-vars", "--file", filename, "BAZ=quux"); assert_cli!("env-vars", "--file", filename, "--remove", "BAZ"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); remove_config_file(filename); } } diff --git a/src/cli/global.rs b/src/cli/global.rs index 938d4df30..f78c86616 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -92,17 +92,16 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use std::fs; use pretty_assertions::assert_str_eq; - use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; + use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs, file}; #[test] fn test_global() { let cf_path = dirs::HOME.join(".test-tool-versions"); - let orig = fs::read_to_string(&cf_path).ok(); - let _ = fs::remove_file(&cf_path); + let orig = file::read_to_string(&cf_path).ok(); + let _ = file::remove_file(&cf_path); assert_cli!("install", "tiny@2"); assert_cli_snapshot!("global", "--pin", "tiny@2"); @@ -131,7 +130,7 @@ mod tests { assert_cli_snapshot!("global", "--path"); if let Some(orig) = orig { - fs::write(cf_path, orig).unwrap(); + file::write(cf_path, orig).unwrap(); } } } diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 628634b7c..4c114c393 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -5,7 +5,7 @@ use crate::config::Config; use crate::file::remove_all; use crate::output::Output; use crate::ui::prompt; -use crate::{dirs, env}; +use crate::{dirs, env, file}; /// Removes rtx CLI and all related data /// @@ -39,7 +39,7 @@ impl Command for Implode { return Ok(()); } } else if !self.dry_run && prompt::confirm(&format!("remove {} ?", f.display()))? { - std::fs::remove_file(f)?; + file::remove_file(f)?; } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 5a0857f68..c7fbf3bde 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -194,13 +194,13 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use std::{fs, panic}; + use std::panic; use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; use crate::test::reset_config; - use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; + use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs, file}; #[test] fn test_local_remove() { @@ -342,13 +342,13 @@ mod tests { where T: FnOnce() + panic::UnwindSafe, { - let _ = fs::remove_file(dirs::CURRENT.join(".test.rtx.toml")); + let _ = file::remove_file(dirs::CURRENT.join(".test.rtx.toml")); let cf_path = dirs::CURRENT.join(".test-tool-versions"); - let orig = fs::read_to_string(&cf_path).unwrap(); + let orig = file::read_to_string(&cf_path).unwrap(); let result = panic::catch_unwind(test); - fs::write(cf_path, orig).unwrap(); + file::write(cf_path, orig).unwrap(); assert!(result.is_ok()); reset_config(); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 8a004416b..0daef5235 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -2,11 +2,11 @@ use clap::builder::StyledStr; use color_eyre::eyre::Result; use console::strip_ansi_codes; use indoc::formatdoc; -use std::fs; use crate::cli::command::Command; use crate::cli::Cli; use crate::config::Config; +use crate::file; use crate::output::Output; /// internal command to generate markdown from help @@ -16,7 +16,7 @@ pub struct RenderHelp {} impl Command for RenderHelp { fn run(self, _config: Config, _out: &mut Output) -> Result<()> { - let readme = fs::read_to_string("README.md")?; + let readme = file::read_to_string("README.md")?; let mut current_readme = readme.split(""); let mut doc = String::new(); @@ -25,7 +25,7 @@ impl Command for RenderHelp { doc.push_str(render_commands().as_str()); doc.push_str(current_readme.next().unwrap()); doc = remove_trailing_spaces(&doc) + "\n"; - fs::write("README.md", &doc)?; + file::write("README.md", &doc)?; Ok(()) } } @@ -104,13 +104,13 @@ fn remove_trailing_spaces(s: &str) -> String { #[cfg(test)] mod tests { - use crate::assert_cli; + use crate::{assert_cli, file}; use indoc::indoc; use std::fs; #[test] fn test_render_help() { - fs::write( + file::write( "README.md", indoc! {r#" @@ -121,6 +121,6 @@ mod tests { assert_cli!("render-help"); let readme = fs::read_to_string("README.md").unwrap(); assert!(readme.contains("## Commands")); - fs::remove_file("README.md").unwrap(); + file::remove_file("README.md").unwrap(); } } diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap index d552ab5ef..411b4b77f 100644 --- a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap @@ -1,6 +1,5 @@ --- source: src/cli/env_vars.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(&cf_path).unwrap()" --- [env] - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap index 4a5a476a6..02d7e4645 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap @@ -1,7 +1,6 @@ --- source: src/cli/use.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(&cf_path).unwrap()" --- [tools] tiny = "2" - diff --git a/src/cli/use.rs b/src/cli/use.rs index 44ed15257..c9e301dfc 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -117,23 +117,22 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { use insta::assert_snapshot; - use std::fs; - use crate::{assert_cli, dirs}; + use crate::{assert_cli, dirs, file}; #[test] fn test_use_local() { let cf_path = dirs::CURRENT.join(".test.rtx.toml"); - fs::write(&cf_path, "").unwrap(); + file::write(&cf_path, "").unwrap(); assert_cli!("use", "tiny@2"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); assert_cli!("use", "--pin", "tiny"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); assert_cli!("use", "--fuzzy", "tiny@2"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); assert_cli!( "use", @@ -142,29 +141,29 @@ mod tests { "--path", &cf_path.to_string_lossy().to_string() ); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); - let _ = fs::remove_file(&cf_path); + let _ = file::remove_file(&cf_path); } #[test] fn test_use_local_tool_versions() { let cf_path = dirs::CURRENT.join(".test-tool-versions"); - fs::write(&cf_path, "").unwrap(); + file::write(&cf_path, "").unwrap(); assert_cli!("use", "tiny@3"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); } #[test] fn test_use_global() { let cf_path = dirs::CONFIG.join("config.toml"); - let orig = fs::read_to_string(&cf_path).unwrap(); - let _ = fs::remove_file(&cf_path); + let orig = file::read_to_string(&cf_path).unwrap(); + let _ = file::remove_file(&cf_path); assert_cli!("use", "-g", "tiny@2"); - assert_snapshot!(fs::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(&cf_path).unwrap()); - fs::write(&cf_path, orig).unwrap(); + file::write(&cf_path, orig).unwrap(); } } diff --git a/src/cli/version.rs b/src/cli/version.rs index bb6c39445..72e65842d 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,4 +1,3 @@ -use std::fs; use std::string::ToString; use std::time::Duration; @@ -93,14 +92,14 @@ fn get_latest_version(duration: Duration) -> Option { let version_file_path = dirs::CACHE.join("latest-version"); if let Ok(metadata) = modified_duration(&version_file_path) { if metadata < duration { - if let Ok(version) = fs::read_to_string(&version_file_path) { + if let Ok(version) = file::read_to_string(&version_file_path) { return Some(version); } } } let _ = file::create_dir_all(&*dirs::CACHE); let version = get_latest_version_call(); - let _ = fs::write(version_file_path, version.clone().unwrap_or_default()); + let _ = file::write(version_file_path, version.clone().unwrap_or_default()); version } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index cb5945476..21e2bb185 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::fmt::{Debug, Display}; -use std::fs; + use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; @@ -175,7 +175,7 @@ pub fn trust(path: &Path) -> Result<()> { let hashed_path = trust_path(path.to_path_buf())?; if !hashed_path.exists() { file::create_dir_all(hashed_path.parent().unwrap())?; - fs::write(hashed_path, "")?; + file::write(hashed_path, "")?; } Ok(()) } @@ -183,7 +183,7 @@ pub fn trust(path: &Path) -> Result<()> { pub fn untrust(path: &Path) -> Result<()> { let hashed_path = trust_path(path.to_path_buf())?; if hashed_path.exists() { - fs::remove_file(hashed_path)?; + file::remove_file(hashed_path)?; } Ok(()) } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index fde1cf261..9b4bf4daf 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; -use std::fs; + use std::path::{Path, PathBuf}; use std::time::Duration; @@ -21,7 +21,7 @@ use crate::toolset::{ ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, }; use crate::ui::prompt; -use crate::{dirs, env, parse_error}; +use crate::{dirs, env, file, parse_error}; #[derive(Debug, Default)] pub struct RtxToml { @@ -58,21 +58,11 @@ impl RtxToml { pub fn from_file(path: &Path, is_trusted: bool) -> Result { trace!("parsing: {}", path.display()); let mut rf = Self::init(path, is_trusted); - let body = fs::read_to_string(path).suggestion("ensure file exists and can be read")?; + let body = file::read_to_string(path).suggestion("ensure file exists and can be read")?; rf.parse(&body)?; Ok(rf) } - pub fn migrate(path: &Path, is_trusted: bool) -> Result { - // attempt to read as new .rtx.toml syntax - let mut raw = String::from("[settings]\n"); - raw.push_str(&fs::read_to_string(path)?); - let mut toml = RtxToml::init(path, is_trusted); - toml.parse(&raw)?; - toml.save()?; - Ok(toml) - } - fn parse(&mut self, s: &str) -> Result<()> { let doc: Document = s.parse().suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { @@ -745,7 +735,7 @@ impl ConfigFile for RtxToml { if let Some(parent) = self.path.parent() { create_dir_all(parent)?; } - Ok(fs::write(&self.path, contents)?) + file::write(&self.path, contents) } fn dump(&self) -> String { diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index db48c1247..ac1ae4575 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -1,7 +1,5 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; -use std::fs; -use std::fs::read_to_string; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -13,6 +11,7 @@ use tera::Context; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{global_config_files, AliasMap}; +use crate::file; use crate::file::display_path; use crate::plugins::{unalias_plugin, PluginName}; use crate::tera::{get_tera, BASE_CONTEXT}; @@ -55,7 +54,7 @@ impl ToolVersions { pub fn from_file(path: &Path, is_trusted: bool) -> Result { trace!("parsing tool-versions: {}", path.display()); - Self::parse_str(&read_to_string(path)?, path.to_path_buf(), is_trusted) + Self::parse_str(&file::read_to_string(path)?, path.to_path_buf(), is_trusted) } pub fn parse_str(s: &str, path: PathBuf, is_trusted: bool) -> Result { @@ -188,7 +187,7 @@ impl ConfigFile for ToolVersions { fn save(&self) -> Result<()> { let s = self.dump(); - Ok(fs::write(&self.path, s)?) + file::write(&self.path, s) } fn dump(&self) -> String { diff --git a/src/config/mod.rs b/src/config/mod.rs index 4e45e808d..e73348ebc 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -265,17 +265,11 @@ fn load_rtxrc() -> Result { } true => match RtxToml::from_file(&settings_path, is_trusted) { Ok(cf) => Ok(cf), - Err(err) => match RtxToml::migrate(&settings_path, is_trusted) { - Ok(cf) => Ok(cf), - Err(e) => { - trace!("Error migrating config.toml: {:#}", e); - Err(eyre!( - "Error parsing {}: {:#}", - &settings_path.display(), - err - )) - } - }, + Err(err) => Err(eyre!( + "Error parsing {}: {:#}", + &settings_path.display(), + err + )), }, } } diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index be02b63b9..5c7fba3ef 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -1,7 +1,8 @@ +use color_eyre::eyre::ErrReport; use std::env::{join_paths, split_paths}; +use std::fs; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; -use std::{fs, io}; use indoc::formatdoc; use once_cell::sync::OnceCell; @@ -15,7 +16,7 @@ pub fn setup() -> color_eyre::Result { let asdf_bin = path.join("asdf"); if !asdf_bin.exists() { file::create_dir_all(&path)?; - fs::write( + file::write( &asdf_bin, // rtx="${{RTX_EXE:-rtx}}" formatdoc! {r#" @@ -28,7 +29,7 @@ pub fn setup() -> color_eyre::Result { perms.set_mode(0o755); fs::set_permissions(&asdf_bin, perms)?; } - Ok::(path) + Ok::(path) })?; Ok(path.clone()) diff --git a/src/file.rs b/src/file.rs index 5d3d0789a..e440ef29f 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,51 +1,76 @@ +use std::fs; use std::fs::File; use std::os::unix::fs::symlink; use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::time::Duration; -use std::{fs, io}; -use color_eyre::eyre::Result; +use color_eyre::eyre::{Context, Result}; use filetime::{set_file_times, FileTime}; use flate2::read::GzDecoder; use tar::Archive; use crate::{cmd, dirs, env}; -pub fn remove_all>(path: P) -> io::Result<()> { +pub fn remove_all>(path: P) -> Result<()> { let path = path.as_ref(); match path.metadata().map(|m| m.file_type()) { Ok(x) if x.is_symlink() || x.is_file() => { - trace!("rm {}", path.display()); - fs::remove_file(path)?; + remove_file(path)?; } Ok(x) if x.is_dir() => { trace!("rm -rf {}", path.display()); - fs::remove_dir_all(path)?; + fs::remove_dir_all(path) + .with_context(|| format!("failed rm -rf: {}", path.display()))?; } _ => {} }; Ok(()) } -pub fn remove_all_with_warning>(path: P) -> io::Result<()> { +pub fn remove_file>(path: P) -> Result<()> { + let path = path.as_ref(); + trace!("rm {}", path.display()); + fs::remove_file(path).with_context(|| format!("failed rm: {}", path.display())) +} + +pub fn remove_dir>(path: P) -> Result<()> { + let path = path.as_ref(); + trace!("rmdir {}", path.display()); + fs::remove_dir(path).with_context(|| format!("failed rmdir: {}", path.display())) +} + +pub fn remove_all_with_warning>(path: P) -> Result<()> { remove_all(&path).map_err(|e| { warn!("failed to remove {}: {}", path.as_ref().display(), e); e }) } -pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { +pub fn rename, Q: AsRef>(from: P, to: Q) -> Result<()> { let from = from.as_ref(); let to = to.as_ref(); trace!("mv {} {}", from.display(), to.display()); fs::rename(from, to) + .with_context(|| format!("failed rename: {} -> {}", from.display(), to.display())) +} + +pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { + let path = path.as_ref(); + trace!("write {}", path.display()); + fs::write(path, contents).with_context(|| format!("failed write: {}", path.display())) +} + +pub fn read_to_string>(path: P) -> Result { + let path = path.as_ref(); + trace!("cat {}", path.display()); + fs::read_to_string(path).with_context(|| format!("failed read_to_string: {}", path.display())) } -pub fn create_dir_all>(path: P) -> io::Result<()> { +pub fn create_dir_all>(path: P) -> Result<()> { let path = path.as_ref(); trace!("mkdir -p {}", path.display()); - fs::create_dir_all(path) + fs::create_dir_all(path).with_context(|| format!("failed create_dir_all: {}", path.display())) } pub fn basename(path: &Path) -> Option { @@ -70,10 +95,10 @@ pub fn replace_path>(path: P) -> PathBuf { } } -pub fn touch_dir(dir: &Path) -> io::Result<()> { +pub fn touch_dir(dir: &Path) -> Result<()> { trace!("touch {}", dir.display()); let now = FileTime::now(); - set_file_times(dir, now, now) + set_file_times(dir, now, now).with_context(|| format!("failed to touch dir: {}", dir.display())) } pub fn modified_duration(path: &Path) -> Result { diff --git a/src/lock_file.rs b/src/lock_file.rs index 34cad9ed0..317f936aa 100644 --- a/src/lock_file.rs +++ b/src/lock_file.rs @@ -1,6 +1,7 @@ use crate::dirs; use crate::file::create_dir_all; use crate::hash::hash_to_str; +use color_eyre::eyre::Result; use std::path::{Path, PathBuf}; pub type OnLockedFn = Box; @@ -27,7 +28,7 @@ impl LockFile { self } - pub fn lock(self) -> Result { + pub fn lock(self) -> Result { if let Some(parent) = self.path.parent() { create_dir_all(parent)?; } diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 6e16f4954..26a6e2da8 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -1,4 +1,3 @@ -use std::fs; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -76,7 +75,7 @@ impl BunPlugin { fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { pr.set_message(format!("installing {}", tarball_path.display())); - fs::remove_dir_all(tv.install_path())?; + file::remove_all(tv.install_path())?; file::create_dir_all(tv.install_path().join("bin"))?; file::unzip(tarball_path, &tv.download_path())?; file::rename( diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index e06b3e632..4e3f43921 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs; + use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -81,7 +81,7 @@ impl DenoPlugin { fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { pr.set_message(format!("installing {}", tarball_path.display())); - fs::remove_dir_all(tv.install_path())?; + file::remove_all(tv.install_path())?; file::create_dir_all(tv.install_path().join("bin"))?; file::unzip(tarball_path, &tv.download_path())?; file::rename(tv.download_path().join("deno"), self.deno_bin(tv))?; diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index dd397b1ae..6bbd9c1aa 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs; + use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -58,7 +58,7 @@ impl GoPlugin { tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - let body = fs::read_to_string(&*env::RTX_GO_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + let body = file::read_to_string(&*env::RTX_GO_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); if package.is_empty() { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 62c5475a4..de37baf4d 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -234,7 +234,7 @@ impl Plugin for JavaPlugin { } fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { - let contents = fs::read_to_string(path)?; + let contents = file::read_to_string(path)?; if path.file_name() == Some(".sdkmanrc".as_ref()) { let version = contents .lines() diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index a612a99d8..56a73944e 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,5 +1,5 @@ use std::collections::BTreeMap; -use std::fs; + use std::path::{Path, PathBuf}; use std::process::exit; @@ -46,7 +46,7 @@ impl NodePlugin { } } - fn lock_node_build(&self) -> Result { + fn lock_node_build(&self) -> Result { LockFile::new(&self.node_build_path()) .with_callback(|l| { trace!("install_or_update_node_build {}", l.display()); @@ -111,7 +111,7 @@ impl NodePlugin { tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - let body = fs::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + let body = file::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); if package.is_empty() { @@ -131,8 +131,8 @@ impl NodePlugin { } fn install_npm_shim(&self, tv: &ToolVersion) -> Result<()> { - fs::remove_file(self.npm_path(tv)).ok(); - fs::write(self.npm_path(tv), include_str!("assets/node_npm_shim"))?; + file::remove_file(self.npm_path(tv)).ok(); + file::write(self.npm_path(tv), include_str!("assets/node_npm_shim"))?; file::make_executable(&self.npm_path(tv))?; Ok(()) } @@ -208,7 +208,7 @@ impl Plugin for NodePlugin { } fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { - let body = fs::read_to_string(path)?; + let body = file::read_to_string(path)?; // trim "v" prefix let body = body.trim().strip_prefix('v').unwrap_or(&body); // replace lts/* with lts diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 874860a96..930f2f862 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -189,7 +189,7 @@ impl Plugin for PythonPlugin { let patch_file = patches_dir.join(format!("{}.patch", tv.version)); if patch_file.exists() { pr.set_message(format!("with patch file: {}", patch_file.display())); - let contents = std::fs::read_to_string(&patch_file)?; + let contents = file::read_to_string(&patch_file)?; cmd = cmd.arg("--patch").stdin_string(contents); } else { pr.warn(format!("patch file not found: {}", patch_file.display())); diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index af65ae20f..f795eb9b0 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::env::temp_dir; -use std::fs; + use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -45,7 +45,7 @@ impl RubyPlugin { self.ruby_install_path().join("bin/ruby-install") } - fn lock_build_tool(&self) -> Result { + fn lock_build_tool(&self) -> Result { let build_tool_path = if *env::RTX_RUBY_INSTALL { self.ruby_build_bin() } else { @@ -169,7 +169,7 @@ impl RubyPlugin { tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - let body = fs::read_to_string(&*env::RTX_RUBY_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + let body = file::read_to_string(&*env::RTX_RUBY_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); if package.is_empty() { @@ -229,7 +229,7 @@ impl RubyPlugin { let d = self.rubygems_plugins_path(tv); let f = d.join("rubygems_plugin.rb"); file::create_dir_all(d)?; - fs::write(f, include_str!("assets/rubygems_plugin.rb"))?; + file::write(f, include_str!("assets/rubygems_plugin.rb"))?; Ok(()) } @@ -310,7 +310,7 @@ impl RubyPlugin { http.ensure_success(&resp)?; patches.push(resp.text()?); } else { - patches.push(fs::read_to_string(f)?); + patches.push(file::read_to_string(f)?); } } Ok(patches.join("\n")) @@ -335,10 +335,10 @@ impl Plugin for RubyPlugin { fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { let v = match path.file_name() { - Some(name) if name == "Gemfile" => parse_gemfile(&fs::read_to_string(path)?), + Some(name) if name == "Gemfile" => parse_gemfile(&file::read_to_string(path)?), _ => { // .ruby-version - let body = fs::read_to_string(path)?; + let body = file::read_to_string(path)?; body.trim() .trim_start_matches("ruby-") .trim_start_matches('v') diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 780dd209d..d0d7ea33b 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -233,7 +233,7 @@ impl ExternalPlugin { fn write_legacy_cache(&self, legacy_file: &Path, legacy_version: &str) -> Result<()> { let fp = self.legacy_cache_file_path(legacy_file); file::create_dir_all(fp.parent().unwrap())?; - fs::write(fp, legacy_version)?; + file::write(fp, legacy_version)?; Ok(()) } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 3e9f95893..2e6fa02c3 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -11,6 +11,7 @@ pub use rtx_plugin_toml::RtxPluginToml; pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; +use crate::file; use crate::file::display_path; use crate::lock_file::LockFile; use crate::toolset::ToolVersion; @@ -67,7 +68,7 @@ pub trait Plugin: Debug + Send + Sync { Ok(vec![]) } fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { - let contents = std::fs::read_to_string(path)?; + let contents = file::read_to_string(path)?; Ok(contents.trim().to_string()) } fn external_commands(&self) -> Result> { diff --git a/src/plugins/rtx_plugin_toml.rs b/src/plugins/rtx_plugin_toml.rs index b6cf8296b..da1d5d30e 100644 --- a/src/plugins/rtx_plugin_toml.rs +++ b/src/plugins/rtx_plugin_toml.rs @@ -1,11 +1,10 @@ -use std::fs; use std::path::Path; use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; use toml_edit::{Document, Item, Value}; -use crate::parse_error; +use crate::{file, parse_error}; #[derive(Debug, Default, Clone)] pub struct RtxPluginTomlScriptConfig { @@ -28,7 +27,7 @@ impl RtxPluginToml { } trace!("parsing: {}", path.display()); let mut rf = Self::init(); - let body = fs::read_to_string(path).suggestion("ensure file exists and can be read")?; + let body = file::read_to_string(path).suggestion("ensure file exists and can be read")?; rf.parse(&body)?; Ok(rf) } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 3208f1d3f..cf5ff651b 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -8,9 +8,9 @@ use regex::Regex; use versions::Versioning; use crate::config::Config; -use crate::dirs; use crate::file::make_symlink; use crate::tool::Tool; +use crate::{dirs, file}; pub fn rebuild(config: &Config) -> Result<()> { for plugin in config.tools.values() { @@ -21,7 +21,7 @@ pub fn rebuild(config: &Config) -> Result<()> { if from.exists() { if is_runtime_symlink(&from) && from.read_link()?.as_path() != to { trace!("Removing existing symlink: {}", from.display()); - std::fs::remove_file(&from)?; + file::remove_file(&from)?; } else { continue; } @@ -30,7 +30,7 @@ pub fn rebuild(config: &Config) -> Result<()> { } remove_missing_symlinks(plugin)?; // attempt to remove the installs dir (will fail if not empty) - let _ = std::fs::remove_dir(&installs_dir); + let _ = file::remove_dir(&installs_dir); } Ok(()) } @@ -88,7 +88,7 @@ fn remove_missing_symlinks(plugin: &Tool) -> Result<()> { let path = entry.path(); if is_runtime_symlink(&path) && !path.exists() { trace!("Removing missing symlink: {}", path.display()); - std::fs::remove_file(path)?; + file::remove_file(path)?; } } Ok(()) diff --git a/src/shims.rs b/src/shims.rs index 770d3ae8e..92abf7bbc 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -158,9 +158,9 @@ fn list_executables_in_dir(dir: &Path) -> Result> { fn make_shim(target: &Path, shim: &Path) -> Result<()> { if shim.exists() { - fs::remove_file(shim)?; + file::remove_file(shim)?; } - fs::write( + file::write( shim, formatdoc! {r#" #!/bin/sh diff --git a/src/shorthands.rs b/src/shorthands.rs index af310ea92..67c1caaef 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs; + use std::path::PathBuf; use color_eyre::eyre::Result; @@ -7,7 +7,7 @@ use toml::Table; use crate::config::Settings; use crate::default_shorthands::DEFAULT_SHORTHANDS; -use crate::dirs; +use crate::{dirs, file}; pub type Shorthands = HashMap; @@ -37,7 +37,7 @@ fn parse_shorthands_file(mut f: PathBuf) -> Result { if f.starts_with("~") { f = dirs::HOME.join(f.strip_prefix("~")?); } - let raw = fs::read_to_string(&f)?; + let raw = file::read_to_string(&f)?; let toml = raw.parse::()?; let mut shorthands = HashMap::new(); diff --git a/src/test.rs b/src/test.rs index 29058a4b3..129a96137 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,10 +1,9 @@ use std::env::{join_paths, set_current_dir}; -use std::fs; use std::path::PathBuf; use indoc::indoc; -use crate::env; +use crate::{env, file}; #[ctor::ctor] fn init() { @@ -31,7 +30,7 @@ fn init() { } pub fn reset_config() { - fs::write( + file::write( env::HOME.join(".test-tool-versions"), indoc! {r#" tiny 2 @@ -39,14 +38,14 @@ pub fn reset_config() { "#}, ) .unwrap(); - fs::write( + file::write( env::PWD.join(".test-tool-versions"), indoc! {r#" tiny 3 "#}, ) .unwrap(); - fs::write( + file::write( env::HOME.join("config/config.toml"), indoc! {r#" [settings] diff --git a/src/tool.rs b/src/tool.rs index c6205d7d8..01846f0ee 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,6 +1,6 @@ use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; -use std::fs; + use std::fs::File; use std::path::{Path, PathBuf}; @@ -232,7 +232,7 @@ impl Tool { debug!("error touching config file: {:?} {:?}", path, err); } } - if let Err(err) = fs::remove_file(self.incomplete_file_path(tv)) { + if let Err(err) = file::remove_file(self.incomplete_file_path(tv)) { debug!("error removing incomplete file: {:?}", err); } pr.set_message(""); @@ -335,7 +335,7 @@ impl Tool { let _ = remove_all_with_warning(tv.install_path()); let _ = remove_all_with_warning(tv.download_path()); let _ = remove_all_with_warning(tv.cache_path()); - let _ = fs::remove_file(tv.install_path()); // removes if it is a symlink + let _ = file::remove_file(tv.install_path()); // removes if it is a symlink file::create_dir_all(tv.install_path())?; file::create_dir_all(tv.download_path())?; file::create_dir_all(tv.cache_path())?; diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 8106d9918..c95e27303 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -40,8 +40,8 @@ impl ToolVersionList { #[cfg(test)] mod tests { - use crate::{dirs, env}; - use std::fs; + use crate::{dirs, env, file}; + use std::sync::Arc; use super::*; @@ -67,7 +67,7 @@ mod tests { #[test] fn test_tool_version_list_failure() { env::set_var("RTX_FAILURE", "1"); - fs::remove_dir_all(dirs::CACHE.join("dummy")).unwrap(); + file::remove_all(dirs::CACHE.join("dummy")).unwrap(); let mut config = Config::default(); let plugin_name = "dummy".to_string(); let plugin = ExternalPlugin::new(&plugin_name); From 4a171431055157bdb9e8b62ec079bf60dcaf81ab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:52:18 -0500 Subject: [PATCH 0989/1891] move trusted configs from cache to config dir (#836) also made them symlinks so you can see where they go --- e2e/run_test | 1 + src/config/config_file/mod.rs | 23 +++++++++++++---------- src/migrate.rs | 12 ++++++++++++ test/.gitignore | 1 + 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/e2e/run_test b/e2e/run_test index ba92114d9..e32cba8d2 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -12,6 +12,7 @@ setup_env() { export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="$ROOT/e2e/.rtx" export RTX_CACHE_DIR="$ROOT/e2e/.rtx/cache" + export RTX_CONFIG_DIR="$ROOT/e2e/.rtx/config" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 21e2bb185..0254c17d4 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -168,32 +168,35 @@ pub fn is_trusted(settings: &Settings, path: &Path) -> bool { { return true; } - trust_path(path.to_path_buf()).unwrap().exists() + match path.canonicalize() { + Ok(path) => trust_path(&path).exists(), + Err(_) => false, + } } pub fn trust(path: &Path) -> Result<()> { - let hashed_path = trust_path(path.to_path_buf())?; + let path = path.canonicalize()?; + let hashed_path = trust_path(&path); if !hashed_path.exists() { file::create_dir_all(hashed_path.parent().unwrap())?; - file::write(hashed_path, "")?; + file::make_symlink(&path, &hashed_path)?; } Ok(()) } pub fn untrust(path: &Path) -> Result<()> { - let hashed_path = trust_path(path.to_path_buf())?; + let path = path.canonicalize()?; + let hashed_path = trust_path(&path); if hashed_path.exists() { file::remove_file(hashed_path)?; } Ok(()) } -fn trust_path(mut path: PathBuf) -> Result { - if path.exists() { - path = path.canonicalize()?; - } - let trust_path = dirs::CACHE.join("trusted-configs").join(hash_to_str(&path)); - Ok(trust_path) +fn trust_path(path: &Path) -> PathBuf { + dirs::CONFIG + .join("trusted-configs") + .join(hash_to_str(&path)) } fn detect_config_file_type(path: &Path) -> Option { diff --git a/src/migrate.rs b/src/migrate.rs index e720d3642..e78fb4cd1 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -9,6 +9,7 @@ pub fn run() -> Result<()> { 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"))?; + move_trusted_configs()?; Ok(()) } @@ -31,3 +32,14 @@ fn move_subdirs(from: &Path, to: &Path) -> Result<()> { Ok(()) } + +fn move_trusted_configs() -> Result<()> { + let from = dirs::CACHE.join("trusted-configs"); + let to = dirs::CONFIG.join("trusted-configs"); + if from.exists() && !to.exists() { + info!("migrating {} to {}", from.display(), to.display()); + file::create_dir_all(to.parent().unwrap())?; + file::rename(from, to)?; + } + Ok(()) +} diff --git a/test/.gitignore b/test/.gitignore index c3a61e0c8..f81de271b 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,4 +1,5 @@ data/ !data/plugins cache/ +config/trusted-configs cwd/man/ From 38b446a70560be35be3e4de590c2ff38ec43658b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 24 Aug 2023 07:50:50 -0500 Subject: [PATCH 0990/1891] fix java *.0.0 versions (#839) --- src/plugins/core/java.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index de37baf4d..d8e17a236 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -171,7 +171,12 @@ impl JavaPlugin { fn tv_to_java_version(&self, tv: &ToolVersion) -> String { if regex!(r"^\d").is_match(&tv.version) { // undo openjdk shorthand - format!("openjdk-{}", tv.version) + if tv.version.ends_with(".0.0") { + // undo rtx's full "*.0.0" version + format!("openjdk-{}", &tv.version[..tv.version.len() - 4]) + } else { + format!("openjdk-{}", tv.version) + } } else { tv.version.clone() } From adc0ac5b10c6a6cffc75df4439a7119eef25899a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 24 Aug 2023 09:44:48 -0500 Subject: [PATCH 0991/1891] fixed clippy warnings (#840) --- src/cli/prune.rs | 4 ++-- src/cli/render_help.rs | 2 +- src/cli/reshim.rs | 2 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 6 +++--- src/config/mod.rs | 9 +++------ src/plugins/external_plugin.rs | 4 ++-- src/shims.rs | 2 +- 8 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index d4192015f..da97403cb 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -52,12 +52,12 @@ impl Command for Prune { } } - self.delete(&mut config, to_delete.into_values().collect()) + self.delete(&config, to_delete.into_values().collect()) } } impl Prune { - fn delete(&self, config: &mut Config, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { + fn delete(&self, config: &Config, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); for (p, tv) in to_delete { let mut pr = mpr.add(); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 0daef5235..f1774145c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -64,7 +64,7 @@ fn render_commands() -> String { doc } -fn render_command(parent: Option<&str>, c: &mut clap::Command) -> Option { +fn render_command(parent: Option<&str>, c: &clap::Command) -> Option { let mut c = c.clone().disable_help_flag(true); if c.is_hide_set() { return None; diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index a27801d30..13e14632d 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -34,7 +34,7 @@ impl Command for Reshim { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; - shims::reshim(&mut config, &ts) + shims::reshim(&config, &ts) } } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 2d9478699..68870e9f4 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -58,7 +58,7 @@ impl Command for Uninstall { } let ts = ToolsetBuilder::new().build(&mut config)?; - shims::reshim(&mut config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + shims::reshim(&config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; runtime_symlinks::rebuild(&config)?; Ok(()) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 04140ae1c..9a7e5b896 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -61,12 +61,12 @@ type GroupedToolVersions = Vec<(Arc, Vec<(ToolVersion, String)>)>; impl Upgrade { fn upgrade(&self, config: &mut Config, outdated: OutputVec) -> Result<()> { - let mut mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(config.show_progress_bars()); ThreadPoolBuilder::new() .num_threads(config.settings.jobs) .build()? .install(|| -> Result<()> { - self.install_new_versions(config, &mut mpr, outdated)?; + self.install_new_versions(config, &mpr, outdated)?; let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; shims::reshim(config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; @@ -79,7 +79,7 @@ impl Upgrade { fn install_new_versions( &self, config: &Config, - mpr: &mut MultiProgressReport, + mpr: &MultiProgressReport, outdated: OutputVec, ) -> Result<()> { let grouped_tool_versions: GroupedToolVersions = outdated diff --git a/src/config/mod.rs b/src/config/mod.rs index e73348ebc..e3dcaa328 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -191,7 +191,7 @@ impl Config { for (from, to) in plugin_aliases { aliases .entry(plugin.to_string()) - .or_insert_with(BTreeMap::new) + .or_default() .insert(from, to); } } @@ -200,7 +200,7 @@ impl Config { for (from, to) in plugin_aliases { aliases .entry(plugin.clone()) - .or_insert_with(BTreeMap::new) + .or_default() .insert(from.clone(), to.clone()); } } @@ -458,10 +458,7 @@ fn load_aliases(config_files: &ConfigMap) -> AliasMap { for config_file in config_files.values() { for (plugin, plugin_aliases) in config_file.aliases() { for (from, to) in plugin_aliases { - aliases - .entry(plugin.clone()) - .or_insert_with(BTreeMap::new) - .insert(from, to); + aliases.entry(plugin.clone()).or_default().insert(from, to); } } } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index d0d7ea33b..cc5d12b2d 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -87,7 +87,7 @@ impl ExternalPlugin { .ok_or_else(|| eyre!("No repository found for plugin {}", self.name)) } - fn install(&self, config: &Config, pr: &mut ProgressReport) -> Result<()> { + fn install(&self, config: &Config, pr: &ProgressReport) -> Result<()> { let repository = self.get_repo_url(config)?; let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); debug!("install {} {:?}", self.name, repository); @@ -423,7 +423,7 @@ impl Plugin for ExternalPlugin { let mut pr = mpr.add(); self.decorate_progress_bar(&mut pr, None); let _lock = self.get_lock(&self.plugin_path, force)?; - self.install(config, &mut pr) + self.install(config, &pr) } fn update(&self, gitref: Option) -> Result<()> { diff --git a/src/shims.rs b/src/shims.rs index 92abf7bbc..a134108a3 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -67,7 +67,7 @@ fn which_shim(config: &mut Config, bin_name: &str) -> Result { Err(eyre!("{} is not a valid shim", bin_name)) } -pub fn reshim(config: &mut Config, ts: &Toolset) -> Result<()> { +pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let _lock = LockFile::new(&dirs::SHIMS) .with_callback(|l| { trace!("reshim callback {}", l.display()); From 892c752aa56b70cd725eb5e271fc06bffa158b42 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Thu, 24 Aug 2023 09:49:37 -0500 Subject: [PATCH 0992/1891] chore: Release --- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74d5f5c73..e41e75a41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.23" +version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03aef18ddf7d879c15ce20f04826ef8418101c7e528014c3eeea13321047dca3" +checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" dependencies = [ "clap_builder", "clap_derive", @@ -230,9 +230,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.23" +version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98" +checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" dependencies = [ "anstream", "anstyle", @@ -538,9 +538,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -1618,9 +1618,9 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" -version = "0.11.19" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b9b67e2ca7dd9e9f9285b759de30ff538aab981abaaf7bc9bd90b84a0126c3" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "base64", "bytes", @@ -1704,7 +1704,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.6" +version = "2023.8.7" dependencies = [ "base64", "built", @@ -1928,18 +1928,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.185" +version = "1.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" +checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.185" +version = "1.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec" +checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" dependencies = [ "proc-macro2", "quote", @@ -2811,9 +2811,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 72f6bc467..11ac97a84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.6" +version = "2023.8.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index e77b4a6cd..3569ee07a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.6 +rtx 2023.8.7 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.6/rtx-v2023.8.6-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.7/rtx-v2023.8.7-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 04afd2b41..ed70b7070 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.6"; + version = "2023.8.7"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index b0ebd0894..92cfb489f 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.6" +.TH rtx 1 "rtx 2023.8.7" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.6 +v2023.8.7 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 430b98a45..ecdec3af0 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.6 +Version: 2023.8.7 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From e2baa7304f8e012d1b1b731f56a5a51f9c7f856d Mon Sep 17 00:00:00 2001 From: Xander Date: Fri, 25 Aug 2023 02:22:51 +0200 Subject: [PATCH 0993/1891] Fix `install.sh` output (#842) --- packaging/standalone/install.envsubst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index fd65b0017..9c7247d0f 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -138,19 +138,22 @@ after_finish_help() { case "${SHELL:-}" in */zsh) info "rtx: run the following to activate rtx in your shell:" - info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> ~/.zshrc\n" + info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> ~/.zshrc" + info "" info "rtx: this must be run in order to use rtx in the terminal" info "rtx: run \`rtx doctor\` to verify this is setup correctly" ;; */bash) info "rtx: run the following to activate rtx in your shell:" - info "echo \"eval \\\"\\\$($install_path activate bash)\\\"\" >> ~/.bashrc\n" + info "echo \"eval \\\"\\\$($install_path activate bash)\\\"\" >> ~/.bashrc" + info "" info "rtx: this must be run in order to use rtx in the terminal" info "rtx: run \`rtx doctor\` to verify this is setup correctly" ;; */fish) info "rtx: run the following to activate rtx in your shell:" - info "echo \"$install_path activate fish | source\" >> ~/.config/fish/config.fish\n" + info "echo \"$install_path activate fish | source\" >> ~/.config/fish/config.fish" + info "" info "rtx: this must be run in order to use rtx in the terminal" info "rtx: run \`rtx doctor\` to verify this is setup correctly" ;; From 68129f5c7d63d955e14528cd12f1bc621c1fa147 Mon Sep 17 00:00:00 2001 From: Scott G <479915+scottdotau@users.noreply.github.com> Date: Sat, 26 Aug 2023 04:29:43 +1000 Subject: [PATCH 0994/1891] fix node typo (#843) --- docs/python.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/python.md b/docs/python.md index 655851f25..de7797c48 100644 --- a/docs/python.md +++ b/docs/python.md @@ -34,7 +34,7 @@ rtx uses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/pytho ## Configuration `python-build` already has a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in -additional to that `rtx-node` has a few extra configuration variables: +additional to that `rtx-python` has a few extra configuration variables: - `RTX_PYENV_REPO` [string]: the default is `https://github.com/pyenv/pyenv.git` - `RTX_PYTHON_PATCH_URL` [string]: A url to a patch file to pass to python-build. From a3291d6c3d42122ff240c1df968b8f016311daae Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Fri, 25 Aug 2023 23:55:04 -0500 Subject: [PATCH 0995/1891] remove shorthands for plugins in core (#846) --- scripts/update-shorthand-repo.sh | 12 ++++++------ src/default_shorthands.rs | 9 +-------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index c79adf76a..2b4540f21 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -6,20 +6,20 @@ git clone --depth 1 https://github.com/asdf-vm/asdf-plugins rm -f src/default_shorthands.rs custom_plugins=( - '("go", "https://github.com/rtx-plugins/rtx-golang.git"),' - '("golang", "https://github.com/rtx-plugins/rtx-golang.git"),' - '("java", "https://github.com/rtx-plugins/rtx-java.git"),' '("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"),' '("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"),' - '("ruby", "https://github.com/rtx-plugins/rtx-ruby.git"),' '("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"),' ) asdf_plugins=$(find asdf-plugins/plugins -maxdepth 1 | sort | - grep -v '/plugins$' | + grep -v '/go$' | + grep -v '/golang$' | + grep -v '/java$' | grep -v '/nodejs$' | - grep -v '/python$') + grep -v '/plugins$' | + grep -v '/python$' | + grep -v '/ruby$') num_plugins=$(echo "$asdf_plugins" | wc -l | tr -d ' ') num_plugins=$((num_plugins + ${#custom_plugins[@]})) diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index fe81ff0ee..6117a2975 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 690] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -260,7 +260,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 690] = [ ("gofumpt", "https://github.com/looztra/asdf-gofumpt.git"), ("gohugo", "https://github.com/nklmilojevic/asdf-hugo.git"), ("gojq", "https://github.com/jimmidyson/asdf-gojq.git"), - ("golang", "https://github.com/asdf-community/asdf-golang.git"), ("golangci-lint", "https://github.com/hypnoglow/asdf-golangci-lint.git"), ("gomigrate", "https://github.com/joschi/asdf-gomigrate.git"), ("gomplate", "https://github.com/sneakybeaky/asdf-gomplate.git"), @@ -317,7 +316,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 690] = [ ("io", "https://github.com/mracos/asdf-io.git"), ("istioctl", "https://github.com/virtualstaticvoid/asdf-istioctl.git"), ("janet", "https://github.com/Jakski/asdf-janet.git"), - ("java", "https://github.com/halcyon/asdf-java.git"), ("jb", "https://github.com/beardix/asdf-jb.git"), ("jbang", "https://github.com/joschi/asdf-jbang.git"), ("jib", "https://github.com/joschi/asdf-jib.git"), @@ -536,7 +534,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 690] = [ ("rlwrap", "https://github.com/asdf-community/asdf-rlwrap.git"), ("rome", "https://github.com/kichiemon/asdf-rome.git"), ("rstash", "https://github.com/carlduevel/asdf-rstash.git"), - ("ruby", "https://github.com/asdf-vm/asdf-ruby.git"), ("rust", "https://github.com/code-lever/asdf-rust.git"), ("rust-analyzer", "https://github.com/Xyven1/asdf-rust-analyzer"), ("rye", "https://github.com/Azuki-bar/asdf-rye"), @@ -709,11 +706,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 690] = [ ("zoxide", "https://github.com/nyrst/asdf-zoxide"), ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), // rtx custom shorthands - ("go", "https://github.com/rtx-plugins/rtx-golang.git"), - ("golang", "https://github.com/rtx-plugins/rtx-golang.git"), - ("java", "https://github.com/rtx-plugins/rtx-java.git"), ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), - ("ruby", "https://github.com/rtx-plugins/rtx-ruby.git"), ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ]; From 98d037641fce5c9ed2d81b0cbaf7202b8f50f9f6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sat, 26 Aug 2023 00:01:24 -0500 Subject: [PATCH 0996/1891] chore: Release --- Cargo.lock | 68 +++++++++++++++++------------------------- Cargo.toml | 2 +- README.md | 4 +-- completions/rtx.bash | 2 +- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- 7 files changed, 36 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e41e75a41..552344701 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,16 +43,15 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] @@ -82,9 +81,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -219,9 +218,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.24" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" +checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d" dependencies = [ "clap_builder", "clap_derive", @@ -230,9 +229,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.24" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" +checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6" dependencies = [ "anstream", "anstyle", @@ -242,18 +241,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.3.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc443334c81a804575546c5a8a79b4913b50e28d69232903604cada1de817ce" +checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" dependencies = [ "heck", "proc-macro2", @@ -263,15 +262,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "clap_mangen" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f2e32b579dae093c2424a8b7e2bea09c89da01e1ce5065eb2f0a6f1cc15cc1f" +checksum = "cf8e5f34d85d9e0bbe2491d100a7a7c1007bb2467b518080bfe311e8947197a9" dependencies = [ "clap", "roff", @@ -1065,17 +1064,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" -[[package]] -name = "is-terminal" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" -dependencies = [ - "hermit-abi", - "rustix 0.38.8", - "windows-sys 0.48.0", -] - [[package]] name = "itertools" version = "0.11.0" @@ -1441,9 +1429,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1459,9 +1447,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" +checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" [[package]] name = "ppv-lite86" @@ -1704,7 +1692,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.7" +version = "2023.8.8" dependencies = [ "base64", "built", @@ -1782,9 +1770,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" dependencies = [ "bitflags 2.4.0", "errno 0.3.2", @@ -1928,18 +1916,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -2126,7 +2114,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.38.8", + "rustix 0.38.9", "windows-sys 0.48.0", ] diff --git a/Cargo.toml b/Cargo.toml index 11ac97a84..db9b3857e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.7" +version = "2023.8.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdxcode)"] diff --git a/README.md b/README.md index 3569ee07a..ced2f3f80 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.7 +rtx 2023.8.8 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.7/rtx-v2023.8.7-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdxcode/rtx/releases/download/v2023.8.8/rtx-v2023.8.8-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/completions/rtx.bash b/completions/rtx.bash index 8ee484642..4dd096350 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3479,5 +3479,5 @@ _rtx() { esac } -complete -F _rtx -o bashdefault -o default rtx +complete -F _rtx -o nosort -o bashdefault -o default rtx diff --git a/default.nix b/default.nix index ed70b7070..0edf77faf 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.7"; + version = "2023.8.8"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 92cfb489f..53cd70a08 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.7" +.TH rtx 1 "rtx 2023.8.8" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.7 +v2023.8.8 .SH AUTHORS Jeff Dickey <@jdxcode> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ecdec3af0..b077b39b2 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.7 +Version: 2023.8.8 Release: 1 URL: https://github.com/jdxcode/rtx/ Group: System From dcdb32a0e093b49d1db99459441ebb9514e5a595 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdxcode@users.noreply.github.com> Date: Sun, 27 Aug 2023 10:34:15 -0500 Subject: [PATCH 0997/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ced2f3f80..0104349fd 100644 --- a/README.md +++ b/README.md @@ -1083,7 +1083,7 @@ Alternatively, you may be able to get tighter integration with a direnv extensio ## Core Plugins rtx comes with some plugins built into the CLI written in Rust. These are new and will improve over -time. They can be easily overridden by installing a plugin with the same name, e.g.: `rtx plugin install python`. +time. They can be easily overridden by installing a plugin with the same name, e.g.: `rtx plugin install python https://github.com/asdf-community/asdf-python`. You can see the core plugins with `rtx plugin ls --core`. From 7660f75f36a42b5b77b9ab4654bdf6fcb1e8b38a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 27 Aug 2023 12:39:22 -0500 Subject: [PATCH 0998/1891] jdxcode -> jdx (#848) --- .github/workflows/rtx.yml | 2 +- Cargo.toml | 10 ++--- README.md | 40 +++++++++---------- SECURITY.md | 8 ++-- default.nix | 2 +- docs/bun.md | 2 +- docs/deno.md | 2 +- docs/go.md | 2 +- docs/java.md | 2 +- docs/node.md | 4 +- docs/python.md | 2 +- docs/ruby.md | 2 +- e2e/test_go | 2 +- e2e/test_plugins_install | 4 +- man/man1/rtx.1 | 4 +- packaging/deb/Dockerfile | 2 +- packaging/deb/generate-release.sh | 2 +- packaging/homebrew/homebrew.rb | 2 +- packaging/rpm/Dockerfile | 2 +- packaging/rpm/rtx.spec | 4 +- packaging/standalone/install.envsubst | 2 +- scripts/build-deb.sh | 8 ++-- scripts/build-rpm.sh | 8 ++-- scripts/release-aur-bin.sh | 6 +-- scripts/release-aur.sh | 10 ++--- scripts/release-npm.sh | 4 +- src/cli/direnv/activate.rs | 2 +- src/cli/direnv/mod.rs | 2 +- src/cli/mod.rs | 4 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/update.rs | 2 +- src/cli/self_update.rs | 2 +- ...nfig_file__rtx_toml__tests__fixture-3.snap | 2 +- ...nfig_file__rtx_toml__tests__fixture-6.snap | 2 +- src/git.rs | 2 +- test/fixtures/.rtx.toml | 2 +- 36 files changed, 80 insertions(+), 80 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 1790cc096..a799fb40e 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -229,7 +229,7 @@ jobs: path: rtx - uses: actions/checkout@v3 with: - repository: jdxcode/homebrew-tap + repository: jdx/homebrew-tap path: homebrew-tap token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - name: Install fd-find diff --git a/Cargo.toml b/Cargo.toml index db9b3857e..aee612536 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,10 +3,10 @@ name = "rtx-cli" version = "2023.8.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" -authors = ["Jeff Dickey (@jdxcode)"] -homepage = "https://github.com/jdxcode/rtx" -documentation = "https://github.com/jdxcode/rtx" -repository = "https://github.com/jdxcode/rtx" +authors = ["Jeff Dickey (@jdx)"] +homepage = "https://github.com/jdx/rtx" +documentation = "https://github.com/jdx/rtx" +repository = "https://github.com/jdx/rtx" readme = "README.md" license = "MIT" keywords = ["rtx"] @@ -114,7 +114,7 @@ sign-commit = true pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, - { file = "README.md", search = "https://github.com/jdxcode/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdxcode/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, + { file = "README.md", search = "https://github.com/jdx/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdx/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, ] diff --git a/README.md b/README.md index 0104349fd..5f5a5e31d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@
- + rtx logo
Crates.io -GitHub -GitHub Workflow Status -Codecov +GitHub +GitHub Workflow Status +Codecov Discord

Polyglot runtime manager (asdf rust clone)

@@ -279,7 +279,7 @@ Supported platforms: - `linux` If you need something else, compile it with [cargo](#cargo). -[Windows isn't currently supported.](https://github.com/jdxcode/rtx/discussions/66) +[Windows isn't currently supported.](https://github.com/jdx/rtx/discussions/66) #### Homebrew @@ -290,7 +290,7 @@ brew install rtx Alternatively, use the custom tap (which is updated immediately after a release)): ``` -brew install jdxcode/tap/rtx +brew install jdx/tap/rtx ``` #### MacPorts @@ -317,7 +317,7 @@ cargo binstall rtx-cli Build from the latest commit in main: ``` -cargo install rtx-cli --git https://github.com/jdxcode/rtx --branch main +cargo install rtx-cli --git https://github.com/jdx/rtx --branch main ``` #### npm @@ -337,10 +337,10 @@ npx rtx-cli exec python@3.11 -- python some_script.py #### GitHub Releases -Download the latest release from [GitHub](https://github.com/jdxcode/rtx/releases). +Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdxcode/rtx/releases/download/v2023.8.8/rtx-v2023.8.8-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.8.8/rtx-v2023.8.8-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` @@ -463,7 +463,7 @@ Given that `rtx` replaces both shell env `$PATH` and OS environ `PATH`, watch ou Adding a new shell is not hard at all since very little shell code is in this project. -[See here](https://github.com/jdxcode/rtx/tree/main/src/shell) for how +[See here](https://github.com/jdx/rtx/tree/main/src/shell) for how the others are implemented. If your shell isn't currently supported I'd be happy to help you get yours integrated. @@ -501,7 +501,7 @@ This can also be useful in environments where rtx isn't activated that has lot more flexibility. It supports functionality that is not possible with `.tool-versions`, such as: - setting arbitrary env vars while inside the directory -- passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdxcode/rtx-python#virtualenv-support). +- passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdx/rtx-python#virtualenv-support). - specifying custom plugin urls Here is what an `.rtx.toml` looks like: @@ -526,7 +526,7 @@ python = {version='3.10', virtualenv='.venv'} [plugins] # specify a custom repo url # note this will only be used if the plugin does not already exist -python = 'https://github.com/jdxcode/rtx-python' +python = 'https://github.com/jdx/rtx-python' [settings] # project-local settings verbose = true @@ -696,7 +696,7 @@ always_keep_install = false # deleted on failure by default # configure how frequently (in minutes) to fetch updated plugin repository changes # this is updated whenever a new runtime is installed -# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdxcode/rtx/issues/128) +# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdx/rtx/issues/128) plugin_autoupdate_last_check_duration = '1 week' # set to 0 to disable updates # config files with these prefixes will be trusted by default @@ -1202,7 +1202,7 @@ detected with your setup. If you submit a bug report, please include the output ### Windows support? -This is something we'd like to add! https://github.com/jdxcode/rtx/discussions/66 +This is something we'd like to add! https://github.com/jdx/rtx/discussions/66 It's not a near-term goal and it would require plugin modifications, but it should be feasible. @@ -1236,7 +1236,7 @@ points to: ```sh-session $ ls -l ~/.local/share/rtx/installs/node/20 -[...] /home/jdxcode/.local/share/rtx/installs/node/20 -> node-v20.0.0-linux-x64 +[...] /home/jdx/.local/share/rtx/installs/node/20 -> node-v20.0.0-linux-x64 ``` There are some exceptions to this, such as the following: @@ -1387,14 +1387,14 @@ Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. ### GitHub Actions -Use [`jdxcode/rtx-action`](https://github.com/jdxcode/rtx-action): +Use [`jdx/rtx-action`](https://github.com/jdx/rtx-action): ```yaml jobs: lint: runs-on: ubuntu-latest steps: - - uses: jdxcode/rtx-action@v1 + - uses: jdx/rtx-action@v1 - run: node -v # will be the node version from `.rtx.toml`/`.tool-versions` ``` @@ -1468,7 +1468,7 @@ If you continue to struggle, you can also try using the [shims method](#shims). While making rtx compatible with direnv is, and will always be a major goal of this project, I also want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing -env vars and [virtualenv](https://github.com/jdxcode/rtx-python#experimental-virtualenv-support) +env vars and [virtualenv](https://github.com/jdx/rtx-python#experimental-virtualenv-support) for python using `.rtx.toml`. If you find you continue to need direnv, please open an issue and let me know what it is to see if @@ -1714,7 +1714,7 @@ Examples: ``` Output direnv function to use rtx inside direnv -See https://github.com/jdxcode/rtx#direnv for more information +See https://github.com/jdx/rtx#direnv for more information Because this generates the legacy files based on currently installed plugins, you should run this command after installing new plugins. Otherwise @@ -2159,7 +2159,7 @@ Examples: ``` List all available remote plugins -The full list is here: https://github.com/jdxcode/rtx/blob/main/src/default_shorthands.rs +The full list is here: https://github.com/jdx/rtx/blob/main/src/default_shorthands.rs Examples: $ rtx plugins ls-remote diff --git a/SECURITY.md b/SECURITY.md index e34f775bb..e0b7664b8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,7 +7,7 @@ Please open a ticket or send me an email if you have thoughts on how rtx can be ## Core CLI Security -Development of the "core CLI" is done on jdxcode/rtx which only a single developer (me, @jdxcode) has access to. +Development of the "core CLI" is done on jdx/rtx which only a single developer (me, @jdx) has access to. Other contributors may only submit contributions via public Pull Requests. Reducing the number of developers with access down to 1 minimizes the chance of keys being leaked. @@ -33,10 +33,10 @@ Plugins are by far the biggest source of potential problems and where the most w There are 3 types of plugins: -* [core](https://github.com/jdxcode/rtx/issues/236) - plugins that are hardcoded into the CLI. +* [core](https://github.com/jdx/rtx/issues/236) - plugins that are hardcoded into the CLI. These are official plugins for the most common languages written in Rust. * community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. For now these will -only have @jdxcode as the sole contributor, however this may change in the future for particular plugins with +only have @jdx as the sole contributor, however this may change in the future for particular plugins with dedicated owners/collaborators. If you'd like your plugin to be moved here, ask me about it. * external - plugins owned by other parties, these include plugins in the shorthand registry. These are no more secure than installing any random tool from the internet. @@ -60,7 +60,7 @@ Send an email to security@.pub If you want, you may encrypt the message with GPG:
- @jdxcode's public key + @jdx's public key ``` -----BEGIN PGP PUBLIC KEY BLOCK----- diff --git a/default.nix b/default.nix index 0edf77faf..2b0c6f0b6 100644 --- a/default.nix +++ b/default.nix @@ -51,7 +51,7 @@ rustPlatform.buildRustPackage { meta = with lib; { description = "Polyglot runtime manager (asdf rust clone)"; - homepage = "https://github.com/jdxcode/rtx"; + homepage = "https://github.com/jdx/rtx"; license = licenses.mit; }; } diff --git a/docs/bun.md b/docs/bun.md index 436d5693f..04e855d8a 100644 --- a/docs/bun.md +++ b/docs/bun.md @@ -4,7 +4,7 @@ The following are instructions for using the bun rtx core plugin. This is used w git plugin installed named "bun". The code for this is inside the rtx repository at -[`./src/plugins/core/bun.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/bun.rs). +[`./src/plugins/core/bun.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/bun.rs). ## Usage diff --git a/docs/deno.md b/docs/deno.md index d15fb80df..2a0049fdb 100644 --- a/docs/deno.md +++ b/docs/deno.md @@ -7,7 +7,7 @@ If you want to use [asdf-deno](https://github.com/asdf-community/asdf-deno) then run `rtx plugins install deno https://github.com/asdf-community/asdf-deno`. The code for this is inside the rtx repository at -[`./src/plugins/core/deno.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/deno.rs). +[`./src/plugins/core/deno.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/deno.rs). ## Usage diff --git a/docs/go.md b/docs/go.md index 4a16f2308..6202155b8 100644 --- a/docs/go.md +++ b/docs/go.md @@ -8,7 +8,7 @@ or [rtx-golang](https://github.com/rtx-plugins/rtx-golang) then use `rtx plugins install go GIT_URL`. The code for this is inside the rtx repository at -[`./src/plugins/core/go.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/go.rs). +[`./src/plugins/core/go.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/go.rs). ## Usage diff --git a/docs/java.md b/docs/java.md index f5ac5f1fa..ba9efa130 100644 --- a/docs/java.md +++ b/docs/java.md @@ -8,7 +8,7 @@ or [rtx-java](https://github.com/rtx-plugins/rtx-java) then use `rtx plugins install java GIT_URL`. The code for this is inside the rtx repository at -[`./src/plugins/core/java.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/java.rs). +[`./src/plugins/core/java.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/java.rs). ## Usage diff --git a/docs/node.md b/docs/node.md index e2e52f654..55d3a6200 100644 --- a/docs/node.md +++ b/docs/node.md @@ -6,7 +6,7 @@ git plugin installed named "node". If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) or [rtx-node](https://github.com/rtx-plugins/rtx-nodejs) then run `rtx plugins install node GIT_URL`. -The code for this is inside the rtx repository at [`./src/plugins/core/node.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/node.rs). +The code for this is inside the rtx repository at [`./src/plugins/core/node.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/node.rs). ## Usage @@ -91,5 +91,5 @@ rtx ls-remote node ## "nodejs" -> "node" Alias You cannot install/use a plugin named "nodejs". If you attempt this, rtx will just renamed it to -"node". See the [FAQ](https://github.com/jdxcode/rtx#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) +"node". See the [FAQ](https://github.com/jdx/rtx#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) for an explanation. diff --git a/docs/python.md b/docs/python.md index de7797c48..cfecef6df 100644 --- a/docs/python.md +++ b/docs/python.md @@ -5,7 +5,7 @@ the "experimental" setting is "true" and there isn't a git plugin installed name If you want to use [asdf-python](https://github.com/asdf-community/asdf-python) or [rtx-python](https://github.com/rtx-plugins/rtx-python) then use `rtx plugins install python GIT_URL`. -The code for this is inside of the rtx repository at [`./src/plugins/core/python.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/python.rs). +The code for this is inside of the rtx repository at [`./src/plugins/core/python.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/python.rs). ## Usage diff --git a/docs/ruby.md b/docs/ruby.md index 53864a5d7..87f3f9302 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -8,7 +8,7 @@ or [rtx-ruby](https://github.com/rtx-plugins/rtx-ruby) then use `rtx plugins install ruby GIT_URL`. The code for this is inside the rtx repository at -[`./src/plugins/core/ruby.rs`](https://github.com/jdxcode/rtx/blob/main/src/plugins/core/ruby.rs). +[`./src/plugins/core/ruby.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/ruby.rs). ## Usage diff --git a/e2e/test_go b/e2e/test_go index 2889d97a9..d0c2ea755 100755 --- a/e2e/test_go +++ b/e2e/test_go @@ -6,7 +6,7 @@ export RTX_EXPERIMENTAL=1 export RTX_GO_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-go-packages" cat >"$RTX_GO_DEFAULT_PACKAGES_FILE" < .SH DESCRIPTION -rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx +rtx is a tool for managing runtime versions. https://github.com/jdx/rtx .PP It\*(Aqs a replacement for tools like nvm, nodenv, rbenv, rvm, chruby, pyenv, etc. that works for any language. It\*(Aqs also great for managing linters/tools like @@ -152,4 +152,4 @@ Examples: .SH VERSION v2023.8.8 .SH AUTHORS -Jeff Dickey <@jdxcode> +Jeff Dickey <@jdx> diff --git a/packaging/deb/Dockerfile b/packaging/deb/Dockerfile index ae817e878..cc926fa74 100644 --- a/packaging/deb/Dockerfile +++ b/packaging/deb/Dockerfile @@ -1,5 +1,5 @@ FROM ubuntu:22.04 -LABEL maintainer="jdxcode" +LABEL maintainer="jdx" RUN apt-get update \ && apt-get install -y \ diff --git a/packaging/deb/generate-release.sh b/packaging/deb/generate-release.sh index 9a9cb7941..2b949d7aa 100755 --- a/packaging/deb/generate-release.sh +++ b/packaging/deb/generate-release.sh @@ -22,7 +22,7 @@ Codename: stable Version: 1.0 Architectures: amd64 arm64 Components: main -Description: https://github.com/jdxcode/rtx +Description: https://github.com/jdx/rtx Date: $(date -Ru) EOF do_hash "MD5Sum" "md5sum" diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index 5da1ee000..5f34cb724 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -1,6 +1,6 @@ class Rtx < Formula desc "Multi-language runtime manager" - homepage "https://github.com/jdxcode/rtx" + homepage "https://github.com/jdx/rtx" license "MIT" version "$RTX_VERSION" diff --git a/packaging/rpm/Dockerfile b/packaging/rpm/Dockerfile index 79c1aa2e0..e58badc26 100644 --- a/packaging/rpm/Dockerfile +++ b/packaging/rpm/Dockerfile @@ -1,5 +1,5 @@ FROM fedora:38 -LABEL maintainer="jdxcode" +LABEL maintainer="jdx" RUN dnf install -y rpm-build rpm-sign ruby ruby-devel gcc RUN gem install fpm diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b077b39b2..d96e10e72 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -2,10 +2,10 @@ Summary: Polyglot runtime manager Name: rtx Version: 2023.8.8 Release: 1 -URL: https://github.com/jdxcode/rtx/ +URL: https://github.com/jdx/rtx/ Group: System License: MIT -Packager: @jdxcode +Packager: @jdx BuildRoot: /root/rtx %description diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index 9c7247d0f..a91a195b3 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -117,7 +117,7 @@ install_rtx() { xdg_data_home="${XDG_DATA_HOME:-$HOME/.local/share}" install_path="${RTX_INSTALL_PATH:-$xdg_data_home/rtx/bin/rtx}" install_dir="$(dirname "$install_path")" - tarball_url="https://github.com/jdxcode/rtx/releases/download/${version}/rtx-${version}-${os}-${arch}.tar.gz" + tarball_url="https://github.com/jdx/rtx/releases/download/${version}/rtx-${version}-${os}-${arch}.tar.gz" cache_file=$(download_file "$tarball_url") debug "rtx-setup: tarball=$cache_file" diff --git a/scripts/build-deb.sh b/scripts/build-deb.sh index 3dc956466..7fb960d34 100755 --- a/scripts/build-deb.sh +++ b/scripts/build-deb.sh @@ -10,8 +10,8 @@ fpm -s dir -t deb \ --version "${RTX_VERSION#v*}" \ --architecture amd64 \ --description "Polyglot runtime manager" \ - --url "https://github.com/jdxcode/rtx" \ - --maintainer "Jeff Dickey @jdxcode" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 @@ -22,8 +22,8 @@ fpm -s dir -t deb \ --version "${RTX_VERSION#v*}" \ --architecture arm64 \ --description "Polyglot runtime manager" \ - --url "https://github.com/jdxcode/rtx" \ - --maintainer "Jeff Dickey @jdxcode" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 diff --git a/scripts/build-rpm.sh b/scripts/build-rpm.sh index fba3a161b..6de5862ca 100755 --- a/scripts/build-rpm.sh +++ b/scripts/build-rpm.sh @@ -10,8 +10,8 @@ fpm -s dir -t rpm \ --version "${RTX_VERSION#v*}" \ --architecture x86_64 \ --description "Polyglot runtime manager" \ - --url "https://github.com/jdxcode/rtx" \ - --maintainer "Jeff Dickey @jdxcode" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 @@ -22,8 +22,8 @@ fpm -s dir -t rpm \ --version "${RTX_VERSION#v*}" \ --architecture aarch64 \ --description "Polyglot runtime manager" \ - --url "https://github.com/jdxcode/rtx" \ - --maintainer "Jeff Dickey @jdxcode" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index bd99f4777..ff9f4c349 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -3,7 +3,7 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -TAR_GZ_URI="https://github.com/jdxcode/rtx/releases/download/${RTX_VERSION}/rtx-${RTX_VERSION}-linux-x64.tar.gz" +TAR_GZ_URI="https://github.com/jdx/rtx/releases/download/${RTX_VERSION}/rtx-${RTX_VERSION}-linux-x64.tar.gz" SHA512=$(curl -L "$TAR_GZ_URI" | sha512sum | awk '{print $1}') @@ -20,7 +20,7 @@ pkgver=${RTX_VERSION#v*} pkgrel=1 pkgdesc='Polyglot runtime manager' arch=('x86_64') -url='https://github.com/jdxcode/rtx' +url='https://github.com/jdx/rtx' license=('MIT') provides=('rtx') conflicts=('rtx') @@ -54,7 +54,7 @@ pkgbase = rtx-bin pkgdesc = Polyglot runtime manager pkgver = ${RTX_VERSION#v*} pkgrel = 1 - url = https://github.com/jdxcode/rtx + url = https://github.com/jdx/rtx arch = x86_64 license = MIT provides = rtx diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index af0f7326d..e06916e21 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -3,7 +3,7 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -SHA512=$(curl -L "https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') +SHA512=$(curl -L "https://github.com/jdx/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') if [ ! -d aur ]; then git clone ssh://aur@aur.archlinux.org/rtx.git aur @@ -18,13 +18,13 @@ pkgver=${RTX_VERSION#v*} pkgrel=1 pkgdesc='Polyglot runtime manager' arch=('x86_64') -url='https://github.com/jdxcode/rtx' +url='https://github.com/jdx/rtx' license=('MIT') makedepends=('cargo') provides=('rtx') conflicts=('rtx-bin') options=('!lto') -source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdxcode/\$pkgname/archive/v\$pkgver.tar.gz") +source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdx/\$pkgname/archive/v\$pkgver.tar.gz") sha512sums=('$SHA512') prepare() { @@ -59,13 +59,13 @@ pkgbase = rtx pkgdesc = Polyglot runtime manager pkgver = ${RTX_VERSION#v*} pkgrel = 1 - url = https://github.com/jdxcode/rtx + url = https://github.com/jdx/rtx arch = x86_64 license = MIT makedepends = cargo provides = rtx conflicts = rtx - source = rtx-${RTX_VERSION#v*}.tar.gz::https://github.com/jdxcode/rtx/archive/$RTX_VERSION.tar.gz + source = rtx-${RTX_VERSION#v*}.tar.gz::https://github.com/jdx/rtx/archive/$RTX_VERSION.tar.gz sha512sums = $SHA512 pkgname = rtx diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index b259e142e..849629248 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -51,7 +51,7 @@ for platform in "${platforms[@]}"; do }, "repository": { "type": "git", - "url": "https://github.com/jdxcode/rtx" + "url": "https://github.com/jdx/rtx" }, "files": [ "bin", @@ -135,7 +135,7 @@ cat <"$RELEASE_DIR/npm/package.json" "version": "$RTX_VERSION", "repository": { "type": "git", - "url": "https://github.com/jdxcode/rtx" + "url": "https://github.com/jdx/rtx" }, "files": [ "installArchSpecificPackage.js", diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 1e1be26f9..c778851be 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -7,7 +7,7 @@ use crate::output::Output; /// Output direnv function to use rtx inside direnv /// -/// See https://github.com/jdxcode/rtx#direnv for more information +/// See https://github.com/jdx/rtx#direnv for more information /// /// Because this generates the legacy files based on currently installed plugins, /// you should run this command after installing new plugins. Otherwise diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index 54115c3f1..cf2215902 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -11,7 +11,7 @@ mod exec; /// Output direnv function to use rtx inside direnv /// -/// See https://github.com/jdxcode/rtx#direnv for more information +/// See https://github.com/jdx/rtx#direnv for more information /// /// Because this generates the legacy files based on currently installed plugins, /// you should run this command after installing new plugins. Otherwise diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 8bbc0b693..9f206dad2 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -171,7 +171,7 @@ impl Cli { clap::Command::new("rtx") .version(version::VERSION.to_string()) .about(env!("CARGO_PKG_DESCRIPTION")) - .author("Jeff Dickey <@jdxcode>") + .author("Jeff Dickey <@jdx>") .long_about(LONG_ABOUT) .arg_required_else_help(true) .subcommand_required(true) @@ -237,7 +237,7 @@ impl Default for Cli { } const LONG_ABOUT: &str = indoc! {" -rtx is a tool for managing runtime versions. https://github.com/jdxcode/rtx +rtx is a tool for managing runtime versions. https://github.com/jdx/rtx It's a replacement for tools like nvm, nodenv, rbenv, rvm, chruby, pyenv, etc. that works for any language. It's also great for managing linters/tools like diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index ffff4eba2..f3662e883 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -61,7 +61,7 @@ impl Command for PluginsLsRemote { const LONG_ABOUT: &str = r#" List all available remote plugins -The full list is here: https://github.com/jdxcode/rtx/blob/main/src/default_shorthands.rs +The full list is here: https://github.com/jdx/rtx/blob/main/src/default_shorthands.rs Examples: $ rtx plugins ls-remote diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index dc24279d3..07281e1cd 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -71,7 +71,7 @@ mod tests { "plugin", "install", "tiny", - "https://github.com/jdxcode/rtx-tiny.git" + "https://github.com/rtx-plugins/rtx-tiny.git" ); // assert_cli!("p", "update"); tested in e2e assert_cli!("plugins", "update", "tiny"); diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index d76f82cf8..f5751b594 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -25,7 +25,7 @@ impl Command for SelfUpdate { env::var("RTX_SELF_UPDATE_VERSION").unwrap_or(cargo_crate_version!().to_string()); let mut update = Update::configure(); update - .repo_owner("jdxcode") + .repo_owner("jdx") .repo_name("rtx") .bin_name("rtx") .show_download_progress(true) diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap index c145e1b04..0c3174970 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap @@ -3,5 +3,5 @@ source: src/config/config_file/rtx_toml.rs expression: cf.plugins() --- { - "node": "https://github.com/jdxcode/rtx-node", + "node": "https://github.com/jdx/rtx-node", } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index d3250bb61..0e7768208 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -16,7 +16,7 @@ python = [ ] [plugins] -node = 'https://github.com/jdxcode/rtx-node' +node = 'https://github.com/jdx/rtx-node' [settings] verbose = true diff --git a/src/git.rs b/src/git.rs index 9c2877eb4..a889f03af 100644 --- a/src/git.rs +++ b/src/git.rs @@ -159,7 +159,7 @@ fn get_git_version() -> Result { // fn test_clone_and_update() { // let dir = tempdir().unwrap().into_path(); // let git = Git::new(dir); -// git.clone("https://github.com/jdxcode/rtx-tiny") +// git.clone("https://github.com/rtx-plugins/rtx-tiny") // .unwrap(); // let prev_rev = "c85ab2bea15e8b785592ce1a75db341e38ac4d33".to_string(); // let latest = git.current_sha().unwrap(); diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml index b9b4aa5d2..59b15d93d 100644 --- a/test/fixtures/.rtx.toml +++ b/test/fixtures/.rtx.toml @@ -12,7 +12,7 @@ python = [ ] [plugins] -node = 'https://github.com/jdxcode/rtx-node' +node = 'https://github.com/jdx/rtx-node' [settings] verbose = true From afdbbd48da1b6f989c14644bb1be986caebbb91a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 27 Aug 2023 13:16:11 -0500 Subject: [PATCH 0999/1891] plugins-ls: show core plugins on --all (#847) --- src/cli/plugins/ls.rs | 42 ++++++++++++++++++---------------- src/git.rs | 3 +++ src/plugins/external_plugin.rs | 2 +- src/tool.rs | 15 ++++++++++++ 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 4f9a32fa8..b56ecffea 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -1,10 +1,13 @@ +use std::collections::BTreeSet; +use std::sync::Arc; + use color_eyre::eyre::Result; use crate::cli::command::Command; -use crate::cli::plugins::ls_remote::PluginsLsRemote; use crate::config::Config; use crate::output::Output; -use crate::plugins::PluginType; +use crate::plugins::{ExternalPlugin, PluginType}; +use crate::tool::Tool; /// List installed plugins /// @@ -35,43 +38,42 @@ pub struct PluginsLs { impl Command for PluginsLs { fn run(self, config: Config, out: &mut Output) -> Result<()> { + let mut tools = config.tools.values().cloned().collect::>(); + if self.all { - return PluginsLsRemote { - urls: self.urls, - only_names: false, + for (plugin, url) in config.get_shorthands() { + let mut ep = ExternalPlugin::new(plugin); + ep.repo_url = Some(url.to_string()); + let tool = Tool::new(plugin.clone(), Box::from(ep)); + tools.insert(Arc::new(tool)); } - .run(config, out); - } - - let mut plugins = config.tools.values().collect::>(); - - if self.core { - plugins.retain(|p| matches!(p.plugin.get_type(), PluginType::Core)); + } else if self.core { + tools.retain(|p| matches!(p.plugin.get_type(), PluginType::Core)); } else { - plugins.retain(|p| matches!(p.plugin.get_type(), PluginType::External)); + tools.retain(|p| matches!(p.plugin.get_type(), PluginType::External)); } if self.urls || self.refs { - for plugin in plugins { - rtxprint!(out, "{:29}", plugin.name); + for tool in tools { + rtxprint!(out, "{:29}", tool.name); if self.urls { - if let Some(url) = plugin.get_remote_url() { + if let Some(url) = tool.get_remote_url() { rtxprint!(out, " {}", url); } } if self.refs { - if let Ok(aref) = plugin.current_abbrev_ref() { + if let Ok(aref) = tool.current_abbrev_ref() { rtxprint!(out, " {}", aref); } - if let Ok(sha) = plugin.current_sha_short() { + if let Ok(sha) = tool.current_sha_short() { rtxprint!(out, " {}", sha); } } rtxprint!(out, "\n"); } } else { - for plugin in plugins { - rtxprintln!(out, "{}", plugin.name); + for tool in tools { + rtxprintln!(out, "{}", tool.name); } } Ok(()) diff --git a/src/git.rs b/src/git.rs index a889f03af..6af6e1a67 100644 --- a/src/git.rs +++ b/src/git.rs @@ -85,6 +85,9 @@ impl Git { } pub fn get_remote_url(&self) -> Option { + if !self.dir.exists() { + return None; + } let res = cmd!( "git", "-C", diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index cc5d12b2d..83a494604 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -379,7 +379,7 @@ impl Plugin for ExternalPlugin { fn get_remote_url(&self) -> Option { let git = Git::new(self.plugin_path.to_path_buf()); - git.get_remote_url() + git.get_remote_url().or_else(|| self.repo_url.clone()) } fn current_sha_short(&self) -> Result { diff --git a/src/tool.rs b/src/tool.rs index 01846f0ee..3e16e6a37 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; @@ -407,6 +408,20 @@ fn find_match_in_list(list: &[String], query: &str) -> Option { v } +impl PartialOrd for Tool { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.name.cmp(&other.name)) + } +} + +impl Ord for Tool { + fn cmp(&self, other: &Self) -> Ordering { + self.name.cmp(&other.name) + } +} + +impl Eq for Tool {} + #[cfg(test)] mod tests { use crate::plugins::PluginName; From d1da2ce3e01647e0f157224cc8782a00a20da8db Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 27 Aug 2023 13:20:41 -0500 Subject: [PATCH 1000/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 552344701..6f0fb617a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1692,7 +1692,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.8" +version = "2023.8.9" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index aee612536..554208c20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.8" +version = "2023.8.9" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 5f5a5e31d..62db2f585 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.8 +rtx 2023.8.9 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.8.8/rtx-v2023.8.8-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.8.9/rtx-v2023.8.9-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 2b0c6f0b6..0c06544ad 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.8"; + version = "2023.8.9"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index f4792d9f4..a33fa5d15 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.8" +.TH rtx 1 "rtx 2023.8.9" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.8 +v2023.8.9 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index d96e10e72..6479b903f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.8 +Version: 2023.8.9 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From d5abfa68d0ac1e0bda2309aaa85ea4a542d84c66 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:33:31 -0500 Subject: [PATCH 1001/1891] do not reshim if rtx is not on PATH (#849) also show debug output --- src/plugins/core/assets/rubygems_plugin.rb | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/plugins/core/assets/rubygems_plugin.rb b/src/plugins/core/assets/rubygems_plugin.rb index 634d12360..353835003 100644 --- a/src/plugins/core/assets/rubygems_plugin.rb +++ b/src/plugins/core/assets/rubygems_plugin.rb @@ -1,8 +1,25 @@ +def debug? + !!ENV['RTX_DEBUG'] +end + +def log_debug(msg) + $stderr.puts "[DEBUG] rtx #{msg}" if debug? +end + +def reshim + if `which ruby`.strip != '' + log_debug "reshim" + `rtx reshim` + else + log_debug "reshim skipped: ruby not found" + end +end + module ReshimInstaller def install(options) super # We don't know which gems were installed, so always reshim. - `rtx reshim` + reshim end end @@ -11,11 +28,11 @@ def install(options) else Gem.post_install do |installer| # Reshim any (potentially) new executables. - `rtx reshim` if installer.spec.executables.any? + reshim if installer.spec.executables.any? end Gem.post_uninstall do |installer| # Unfortunately, reshimming just the removed executables or # ruby version doesn't work as of 2020/04/23. - `rtx reshim` if installer.spec.executables.any? + reshim if installer.spec.executables.any? end end From 1ae7357887f3de8c352616d02f769c997f6b41d4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:56:33 -0500 Subject: [PATCH 1002/1891] set logging env vars clean up log env var logic (#850) * set log env vars if --trace is set, automatically sets RTX_DEBUG=1 in addition to RTX_TRACE=1. Also sets RTX_LOG_LEVEL when --trace/--debug is set * clean up log env var logic Main purpose is to ensure that RTX_DEBUG/RTX_TRACE are available in plugins --- src/cli/hook_env.rs | 2 +- src/env.rs | 46 ++++++++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index e8879bd66..07c344760 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -72,7 +72,7 @@ impl HookEnv { .rev() .map(|(_, v)| v.to_string()) .collect_vec(); - if !installed_versions.is_empty() && !*env::RTX_QUIET { + if !installed_versions.is_empty() { let w = match terminal_size() { Some((Width(w), _)) => w, None => 80, diff --git a/src/env.rs b/src/env.rs index 520057b95..c461de7be 100644 --- a/src/env.rs +++ b/src/env.rs @@ -45,11 +45,8 @@ pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); pub static RTX_MISSING_RUNTIME_BEHAVIOR: Lazy> = Lazy::new(|| var("RTX_MISSING_RUNTIME_BEHAVIOR").ok()); -pub static RTX_QUIET: Lazy = Lazy::new(|| var_is_true("RTX_QUIET")); -pub static RTX_DEBUG: Lazy = Lazy::new(|| var_is_true("RTX_DEBUG")); -pub static RTX_TRACE: Lazy = Lazy::new(|| var_is_true("RTX_TRACE")); pub static RTX_VERBOSE: Lazy = - Lazy::new(|| *RTX_DEBUG || *RTX_TRACE || var_is_true("RTX_VERBOSE")); + Lazy::new(|| *RTX_LOG_LEVEL > LevelFilter::Info || var_is_true("RTX_VERBOSE")); pub static RTX_JOBS: Lazy = Lazy::new(|| { var("RTX_JOBS") .ok() @@ -339,6 +336,15 @@ fn prefer_stale(args: &[String]) -> bool { } fn log_level() -> LevelFilter { + if var_is_true("RTX_QUIET") { + set_var("RTX_LOG_LEVEL", "warn"); + } + if var_is_true("RTX_DEBUG") { + set_var("RTX_LOG_LEVEL", "debug"); + } + if var_is_true("RTX_TRACE") { + set_var("RTX_LOG_LEVEL", "trace"); + } for (i, arg) in ARGS.iter().enumerate() { if arg == "--" { break; @@ -352,27 +358,29 @@ fn log_level() -> LevelFilter { } } if arg == "--debug" { - set_var("RTX_DEBUG", "1"); + set_var("RTX_LOG_LEVEL", "debug"); } if arg == "--trace" { - set_var("RTX_TRACE", "1"); + set_var("RTX_LOG_LEVEL", "trace"); } } - let log_level = var("RTX_LOG_LEVEL").unwrap_or_default(); - match log_level.parse::() { - Ok(level) => level, - _ => { - if *RTX_TRACE { - LevelFilter::Trace - } else if *RTX_DEBUG { - LevelFilter::Debug - } else if *RTX_QUIET { - LevelFilter::Warn - } else { - LevelFilter::Info - } + let log_level = var("RTX_LOG_LEVEL") + .unwrap_or_default() + .parse::() + .unwrap_or(LevelFilter::Info); + // set RTX_DEBUG/RTX_TRACE for plugins to use + match log_level { + LevelFilter::Trace => { + set_var("RTX_TRACE", "1"); + set_var("RTX_DEBUG", "1"); } + LevelFilter::Debug => { + set_var("RTX_DEBUG", "1"); + } + _ => {} } + + log_level } fn log_file_level() -> LevelFilter { From 4f2c0861fbaec522d298b2372b1612e66c95b99e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 01:39:50 +0000 Subject: [PATCH 1003/1891] chore(deps): bump openssl from 0.10.56 to 0.10.57 (#854) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.56 to 0.10.57. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.56...openssl-v0.10.57) --- updated-dependencies: - dependency-name: openssl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f0fb617a..e5efd375f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1295,11 +1295,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.56" +version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -1327,9 +1327,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.91" +version = "0.9.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" +checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" dependencies = [ "cc", "libc", From b4f74b39f798e740dd98c959868c570764953db1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 01:40:36 +0000 Subject: [PATCH 1004/1891] chore(deps): bump base64 from 0.21.2 to 0.21.3 (#853) Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.21.2 to 0.21.3. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.21.2...v0.21.3) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5efd375f..5dfedf5c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,9 +112,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "bitflags" From f0d92610ee0fa50a2e7430d6cc30ee8b7a87d99f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 01:48:34 +0000 Subject: [PATCH 1005/1891] chore(deps): bump regex from 1.9.3 to 1.9.4 (#855) Bumps [regex](https://github.com/rust-lang/regex) from 1.9.3 to 1.9.4. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.9.3...1.9.4) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5dfedf5c3..0e99a3e9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1577,9 +1577,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", @@ -1589,9 +1589,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", @@ -1600,9 +1600,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" From 10647a97d7e05867549d77eb178aedadd128caa7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 02:17:46 +0000 Subject: [PATCH 1006/1891] chore(deps): bump aws-actions/configure-aws-credentials from 2 to 3 (#856) Bumps [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials) from 2 to 3. - [Release notes](https://github.com/aws-actions/configure-aws-credentials/releases) - [Changelog](https://github.com/aws-actions/configure-aws-credentials/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws-actions/configure-aws-credentials/compare/v2...v3) --- updated-dependencies: - dependency-name: aws-actions/configure-aws-credentials dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jdx <216188+jdx@users.noreply.github.com> --- .github/workflows/rtx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index a799fb40e..8ee351576 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -244,7 +244,7 @@ jobs: node-version: "20.x" registry-url: "https://registry.npmjs.org" - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v3 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} From 21fcc4eb44f0eae7918e56a817d8247e7124900e Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Wed, 30 Aug 2023 04:18:32 +0200 Subject: [PATCH 1007/1891] add support for macos integration (#858) --- docs/java.md | 15 +++++++++++++++ src/plugins/core/java.rs | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/java.md b/docs/java.md index ba9efa130..ebb330623 100644 --- a/docs/java.md +++ b/docs/java.md @@ -21,3 +21,18 @@ $ rtx use -g java@17 # alternate shorthands for openjdk-only ``` See available versions with `rtx ls-remote java`. + +## macOS JAVA_HOME Integration + +Some applications in macOS rely on `/usr/libexec/java_home` to find installed Java runtimes. + +To integrate an installed Java runtime with macOS run the following commands for the proper version (e.g. openjdk-20). + +```sh-session +$ sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-20.jdk +$ sudo ln -s ~/.local/share/rtx/installs/java/openjdk-20/Contents /Library/Java/JavaVirtualMachines/openjdk-20.jdk/Contents +``` + +The distribution from Azul Systems does support the integration but the symlink target location will differ from the example above (e.g `~/.local/share/rtx/installs/java/zulu-11.64.190/zulu-11.jdk/Contents`). + +> Note: Not all distributions of the Java SDK support this integration (e.g liberica). diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index d8e17a236..4cf810298 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -1,9 +1,10 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt::Display; -use std::fs; +use std::fs::{self}; use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; +use indoc::formatdoc; use itertools::Itertools; use once_cell::sync::Lazy; use serde_derive::{Deserialize, Serialize}; @@ -74,6 +75,7 @@ impl JavaPlugin { }) }) } + fn fetch_remote_versions(&self) -> Result> { let versions = self .fetch_java_metadata("ga")? @@ -133,6 +135,7 @@ impl JavaPlugin { } self.move_to_install_path(tv, m) } + fn move_to_install_path(&self, tv: &ToolVersion, m: &JavaMetadata) -> Result<()> { let basedir = tv .download_path() @@ -140,6 +143,7 @@ impl JavaPlugin { .find(|e| e.as_ref().unwrap().file_type().unwrap().is_dir()) .unwrap()? .path(); + let contents_dir = basedir.join("Contents").clone(); let source_dir = match m.vendor.as_str() { "zulu" | "liberica" => basedir, _ if os() == "macosx" => basedir.join("Contents").join("Home"), @@ -153,6 +157,37 @@ impl JavaPlugin { trace!("moving {:?} to {:?}", entry.path(), &dest); file::rename(entry.path(), dest)?; } + + // move Contents dir to install path for macOS, if it exists + if os() == "macosx" && contents_dir.exists() { + file::create_dir_all(tv.install_path().join("Contents"))?; + for entry in fs::read_dir(contents_dir)? { + let entry = entry?; + // skip Home dir, so we can symlink it later + if entry.file_name() == "Home" { + continue; + } + let dest = tv.install_path().join("Contents").join(entry.file_name()); + trace!("moving {:?} to {:?}", entry.path(), &dest); + file::rename(entry.path(), dest)?; + } + file::make_symlink( + tv.install_path().as_path(), + &tv.install_path().join("Contents").join("Home"), + )?; + info!( + "{}", + formatdoc! {r#" + To enable macOS integration, run the following commands: + sudo mkdir /Library/Java/JavaVirtualMachines/{version}.jdk + sudo ln -s {path}/Contents /Library/Java/JavaVirtualMachines/{version}.jdk/Contents + "#, + version = tv.version, + path = tv.install_path().display(), + } + ); + } + Ok(()) } From 4b39b26ed36ef2b13fcbff023f3dde2dbbd5c967 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 31 Aug 2023 08:28:19 -0500 Subject: [PATCH 1008/1891] use rtx_toml by default Fixes #859 --- src/cli/use.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/use.rs b/src/cli/use.rs index c9e301dfc..10ce3b82b 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -99,7 +99,7 @@ fn config_file_from_dir(p: &Path) -> PathBuf { if let Some(p) = file::find_up(p, &filenames) { return p; } - tool_versions + rtx_toml } static AFTER_LONG_HELP: &str = color_print::cstr!( From 58b0e0e56f24fb12fae8d36cdf245dcec0808796 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 31 Aug 2023 08:30:20 -0500 Subject: [PATCH 1009/1891] chore: Release --- Cargo.lock | 86 ++++++++++++++++++++---------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 47 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e99a3e9d..ca299fd16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" dependencies = [ "memchr", "serde", @@ -206,21 +206,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "winapi", + "windows-targets 0.48.5", ] [[package]] name = "clap" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d" +checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" dependencies = [ "clap_builder", "clap_derive", @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6" +checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" dependencies = [ "anstream", "anstyle", @@ -563,9 +563,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -1159,9 +1159,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" [[package]] name = "memoffset" @@ -1224,14 +1224,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "static_assertions", ] [[package]] @@ -1385,19 +1384,20 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.2" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" dependencies = [ + "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.2" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" +checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" dependencies = [ "pest", "pest_generator", @@ -1405,9 +1405,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.2" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" +checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" dependencies = [ "pest", "pest_meta", @@ -1418,9 +1418,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.2" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" +checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" dependencies = [ "once_cell", "pest", @@ -1692,7 +1692,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.9" +version = "2023.8.10" dependencies = [ "base64", "built", @@ -1761,7 +1761,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", - "errno 0.3.2", + "errno 0.3.3", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", @@ -1770,12 +1770,12 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.9" +version = "0.38.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" dependencies = [ "bitflags 2.4.0", - "errno 0.3.2", + "errno 0.3.3", "libc", "linux-raw-sys 0.4.5", "windows-sys 0.48.0", @@ -1783,9 +1783,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.6" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring", @@ -2060,12 +2060,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.10.0" @@ -2114,7 +2108,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.38.9", + "rustix 0.38.10", "windows-sys 0.48.0", ] @@ -2185,9 +2179,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" +checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" dependencies = [ "deranged", "itoa", @@ -2206,9 +2200,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" dependencies = [ "time-core", ] @@ -2469,9 +2463,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", diff --git a/Cargo.toml b/Cargo.toml index 554208c20..30f1ae31b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.9" +version = "2023.8.10" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 62db2f585..120b72a35 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.9 +rtx 2023.8.10 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.8.9/rtx-v2023.8.9-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.8.10/rtx-v2023.8.10-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 0c06544ad..513ac3f32 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.9"; + version = "2023.8.10"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a33fa5d15..68b69f2f6 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.9" +.TH rtx 1 "rtx 2023.8.10" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.9 +v2023.8.10 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6479b903f..5d5cbe1c9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.9 +Version: 2023.8.10 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From b54ea9a867d4ce59d337273a7269fb96ec913b88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 02:04:20 +0000 Subject: [PATCH 1010/1891] chore(deps): bump ctrlc from 3.4.0 to 3.4.1 (#871) --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca299fd16..ee0dd0bb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -442,9 +442,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" +checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" dependencies = [ "nix", "windows-sys 0.48.0", @@ -1224,11 +1224,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.4" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "libc", ] From 7cf6677f4a3334be0655df569d556393699e27b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 02:04:43 +0000 Subject: [PATCH 1011/1891] chore(deps): bump clap from 4.4.1 to 4.4.2 (#870) --- Cargo.lock | 13 ++++++------- Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee0dd0bb3..253a0e4cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,20 +218,19 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" dependencies = [ "anstream", "anstyle", @@ -250,9 +249,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 30f1ae31b..777e77d66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ lto = true [dependencies] base64 = "<0.22" chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } -clap = { version = "4.3", features = ["env", "derive", "string"] } +clap = { version = "4.4", features = ["env", "derive", "string"] } clap_complete = "4.2" color-eyre = "0.6" color-print = "0.3" From 95df71f90d4db43f1f2c5e84445d0a4e7bfc3023 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 02:17:42 +0000 Subject: [PATCH 1012/1891] chore(deps): bump thiserror from 1.0.47 to 1.0.48 (#874) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 253a0e4cc..592aea880 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2149,18 +2149,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", From b35c5b2a57228df6071b75873f23cd7420b5802a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 02:18:48 +0000 Subject: [PATCH 1013/1891] chore(deps): bump tera from 1.19.0 to 1.19.1 (#873) --- Cargo.lock | 5 ++--- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 592aea880..0566c2a92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2113,9 +2113,9 @@ dependencies = [ [[package]] name = "tera" -version = "1.19.0" +version = "1.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab29bb4f3e256ae6ad5c3e2775aa1f8829f2c0c101fc407bfd3a6df15c60c5" +checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8" dependencies = [ "globwalk", "lazy_static", @@ -2124,7 +2124,6 @@ dependencies = [ "regex", "serde", "serde_json", - "thread_local", "unic-segment", ] diff --git a/Cargo.toml b/Cargo.toml index 777e77d66..7c7de03fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ shell-escape = "0.1" shell-words = "1.1" simplelog = { version = "0.12" } tar = "0.4" -tera = { version = "1.12", default-features = false } +tera = { version = "1.19", default-features = false } terminal_size = "0.2" thiserror = "1.0" toml = "<0.8" From 9e5e037f1bb2ba2b5788bee7dba797a37be13dff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 02:39:07 +0000 Subject: [PATCH 1014/1891] chore(deps): bump color-print from 0.3.4 to 0.3.5 (#872) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0566c2a92..36652219a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,18 +292,18 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" +checksum = "7a858372ff14bab9b1b30ea504f2a4bc534582aee3e42ba2d41d2a7baba63d5d" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" +checksum = "57e37866456a721d0a404439a1adae37a31be4e0055590d053dfe6981e05003f" dependencies = [ "nom", "proc-macro2", From f333ac5f8e8de399fcb3ce40576baeef0271081b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 5 Sep 2023 09:13:03 -0500 Subject: [PATCH 1015/1891] chore: Release --- Cargo.lock | 59 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +-- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 37 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36652219a..0b77451ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,7 +256,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -436,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -698,7 +698,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1158,9 +1158,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memoffset" @@ -1278,9 +1278,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -1314,7 +1314,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1325,9 +1325,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.92" +version = "0.9.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", @@ -1412,7 +1412,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1576,9 +1576,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ "aho-corasick", "memchr", @@ -1588,9 +1588,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ "aho-corasick", "memchr", @@ -1691,7 +1691,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.8.10" +version = "2023.9.0" dependencies = [ "base64", "built", @@ -1769,9 +1769,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.10" +version = "0.38.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" dependencies = [ "bitflags 2.4.0", "errno 0.3.3", @@ -1930,7 +1930,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -2078,9 +2078,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -2107,7 +2107,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.38.10", + "rustix 0.38.11", "windows-sys 0.48.0", ] @@ -2163,15 +2163,16 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -2512,9 +2513,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", @@ -2556,7 +2557,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-shared", ] @@ -2590,7 +2591,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 7c7de03fb..7a0068f5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.8.10" +version = "2023.9.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 120b72a35..1fd5f7e48 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.8.10 +rtx 2023.9.0 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.8.10/rtx-v2023.8.10-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.9.0/rtx-v2023.9.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 513ac3f32..583954f8a 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.8.10"; + version = "2023.9.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 68b69f2f6..60dfe4331 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.8.10" +.TH rtx 1 "rtx 2023.9.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.8.10 +v2023.9.0 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 5d5cbe1c9..fc4133e8f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.8.10 +Version: 2023.9.0 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 93058ca99896e14220ee91078b211d4b4716a116 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:45:36 -0500 Subject: [PATCH 1016/1891] chore(deps): bump crazy-max/ghaction-import-gpg from 5 to 6 (#886) Bumps [crazy-max/ghaction-import-gpg](https://github.com/crazy-max/ghaction-import-gpg) from 5 to 6. - [Release notes](https://github.com/crazy-max/ghaction-import-gpg/releases) - [Commits](https://github.com/crazy-max/ghaction-import-gpg/compare/v5...v6) --- updated-dependencies: - dependency-name: crazy-max/ghaction-import-gpg dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rtx.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 8ee351576..027276437 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -167,7 +167,7 @@ jobs: if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v3 - - uses: crazy-max/ghaction-import-gpg@v5 + - uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_KEY }} - uses: actions/download-artifact@v3 @@ -192,7 +192,7 @@ jobs: needs: [build-linux] steps: - uses: actions/checkout@v3 - - uses: crazy-max/ghaction-import-gpg@v5 + - uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_KEY }} - uses: actions/download-artifact@v3 @@ -253,7 +253,7 @@ jobs: with: key: ${{ secrets.RTX_SSH_KEY }} known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} - - uses: crazy-max/ghaction-import-gpg@v5 + - uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_KEY }} git_user_signingkey: true From f7e8c7db12153c4888363590c1cc1d528e82cc6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:48:33 -0500 Subject: [PATCH 1017/1891] chore(deps): bump path-absolutize from 3.1.0 to 3.1.1 (#889) Bumps [path-absolutize](https://github.com/magiclen/path-absolutize) from 3.1.0 to 3.1.1. - [Commits](https://github.com/magiclen/path-absolutize/compare/v3.1.0...v3.1.1) --- updated-dependencies: - dependency-name: path-absolutize dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b77451ad..8fadd6310 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1359,18 +1359,18 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "path-absolutize" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43eb3595c63a214e1b37b44f44b0a84900ef7ae0b4c5efce59e123d246d7a0de" +checksum = "e4af381fe79fa195b4909485d99f73a80792331df0625188e707854f0b3383f5" dependencies = [ "path-dedot", ] [[package]] name = "path-dedot" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d55e486337acb9973cdea3ec5638c1b3bcb22e573b2b7b41969e0c744d5a15e" +checksum = "07ba0ad7e047712414213ff67533e6dd477af0a4e1d14fb52343e53d30ea9397" dependencies = [ "once_cell", ] From 9299e0ff104ae7bbf58e7f8131fba340de915747 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:48:40 -0500 Subject: [PATCH 1018/1891] chore(deps): bump toml from 0.7.6 to 0.7.8 (#890) Bumps [toml](https://github.com/toml-rs/toml) from 0.7.6 to 0.7.8. - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.7.6...toml-v0.7.8) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8fadd6310..9430dd37e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2273,9 +2273,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", @@ -2294,9 +2294,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", "serde", From 5eead7032f7033ba911ed2fd556b31f80242c20e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:48:47 -0500 Subject: [PATCH 1019/1891] chore(deps): bump base64 from 0.21.3 to 0.21.4 (#891) Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.21.3 to 0.21.4. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.21.3...v0.21.4) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9430dd37e..13cc630e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,9 +112,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bitflags" From 9ee39bd7184b5fd2ed9ee1954540d8a4043f94f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:48:55 -0500 Subject: [PATCH 1020/1891] chore(deps): bump serde_json from 1.0.105 to 1.0.106 (#887) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.105 to 1.0.106. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.105...v1.0.106) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13cc630e7..4feec3d60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1935,9 +1935,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" dependencies = [ "itoa", "ryu", From c2252c93bf6208a39412dc3fb014cc89e2dd654e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 22:01:12 +0000 Subject: [PATCH 1021/1891] chore(deps): bump actions/checkout from 3 to 4 (#885) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rtx.yml | 22 +++++++++++----------- .github/workflows/test-plugins.yml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 027276437..a5346710f 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -19,7 +19,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Rust Cache uses: Swatinem/rust-cache@v2 with: @@ -46,7 +46,7 @@ jobs: tranche: [0, 1, 2, 3] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - run: rustup toolchain install nightly --component llvm-tools-preview - name: Rust Cache uses: Swatinem/rust-cache@v2 @@ -87,7 +87,7 @@ jobs: - aarch64-unknown-linux-gnu - x86_64-unknown-linux-gnu steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Rust Cache uses: Swatinem/rust-cache@v2 with: @@ -119,7 +119,7 @@ jobs: - x86_64-apple-darwin - aarch64-apple-darwin steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: rustup target add ${{matrix.target}} - name: Rust Cache uses: Swatinem/rust-cache@v2 @@ -141,7 +141,7 @@ jobs: timeout-minutes: 30 if: github.event_name != 'pull_request' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install zsh/fish/direnv run: sudo apt-get update; sudo apt-get install zsh fish direnv - uses: actions/download-artifact@v3 @@ -166,7 +166,7 @@ jobs: container: jdxcode/rtx:rpm if: github.event_name != 'pull_request' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_KEY }} @@ -191,7 +191,7 @@ jobs: if: github.event_name != 'pull_request' needs: [build-linux] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_KEY }} @@ -224,10 +224,10 @@ jobs: - rpm - deb steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: rtx - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: jdx/homebrew-tap path: homebrew-tap @@ -290,7 +290,7 @@ jobs: needs: [release] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Bump Homebrew formula uses: dawidd6/action-homebrew-bump-formula@v3 with: @@ -303,7 +303,7 @@ jobs: needs: [release] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Bump APKBUILD run: sudo -Eu packager ./scripts/release-alpine.sh env: diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index da659c7b2..f25c131a5 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -22,7 +22,7 @@ jobs: build-linux: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Rust Cache uses: Swatinem/rust-cache@v2 with: From 648297fede06515f78e46667b60dce715c2cd803 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Sep 2023 08:36:19 -0500 Subject: [PATCH 1022/1891] improve activation problem output (#895) --- src/cli/doctor.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 594feecc3..2a575e9e2 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -4,6 +4,7 @@ use std::process::exit; use color_eyre::eyre::Result; use console::{pad_str, style, Alignment}; use indenter::indented; +use indoc::formatdoc; use crate::build_time::built_info; use crate::cli::command::Command; @@ -62,9 +63,11 @@ impl Command for Doctor { } if !config.is_activated() { - let cmd = style("rtx activate").yellow().for_stderr(); - checks.push(format!( - "rtx is not activated, run `{cmd}` for setup instructions" + let cmd = style("rtx help activate").yellow().for_stderr(); + let url = style("https://rtx.pub").underlined().for_stderr(); + checks.push(formatdoc!( + r#"rtx is not activated, run {cmd} or + read documentation at {url} for activation instructions"# )); } From 1e9b87194c13f9efe90017a8ecc159eb1b30ced9 Mon Sep 17 00:00:00 2001 From: Gary Coady Date: Wed, 13 Sep 2023 15:39:01 +0200 Subject: [PATCH 1023/1891] Avoid panic if run_with_timeout hits timeout. (#866) If run_with_timeout hits the timeout, the mpsc receiver may be dropped, leading to a panic when the background thread later attempts to return its value. This change simply ignores any error. Since the timeout has already been reached, reporting on this error would just be noise. A future improvement could be to cancel the background operation, but that would require a much larger refactoring. Part of #860 Co-authored-by: jdx <216188+jdx@users.noreply.github.com> --- src/timeout.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/timeout.rs b/src/timeout.rs index 973682e67..8e6764c41 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -11,7 +11,8 @@ where let (tx, rx) = mpsc::channel(); thread::spawn(move || { let result = f(); - tx.send(result).unwrap(); + // If sending fails, the timeout has already been reached. + let _ = tx.send(result); }); rx.recv_timeout(timeout).context("timed out")? } From 9ab9816e4aadfe90dc410be0ebc94beabca737f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 08:47:57 -0500 Subject: [PATCH 1024/1891] chore(deps): bump chrono from 0.4.28 to 0.4.30 (#888) Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.28 to 0.4.30. - [Release notes](https://github.com/chronotope/chrono/releases) - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) - [Commits](https://github.com/chronotope/chrono/compare/v0.4.28...v0.4.30) --- updated-dependencies: - dependency-name: chrono dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4feec3d60..58f4dbdf2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,9 +206,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.28" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ "android-tzdata", "iana-time-zone", From c6d59d7003aad572403e9f7168b935ca7a310407 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Sep 2023 08:49:52 -0500 Subject: [PATCH 1025/1891] chore: Release --- Cargo.lock | 70 +++++++++++++++++++-------------------- Cargo.toml | 2 +- README.md | 4 +-- completions/rtx.fish | 8 ++--- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 13 +++++++- 8 files changed, 58 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58f4dbdf2..a543af4f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" [[package]] name = "anstyle-parse" @@ -172,9 +172,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cargo-lock" @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.2" +version = "4.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" +checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" dependencies = [ "clap_builder", "clap_derive", @@ -240,9 +240,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" +checksum = "4110a1e6af615a9e6d0a36f805d5c99099f8bab9b8042f5bc1fa220a4a89e36f" dependencies = [ "clap", ] @@ -256,7 +256,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -436,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -698,7 +698,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1104,9 +1104,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libgit2-sys" @@ -1146,9 +1146,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" [[package]] name = "log" @@ -1314,7 +1314,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1412,7 +1412,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1691,7 +1691,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.9.0" +version = "2023.9.1" dependencies = [ "base64", "built", @@ -1769,14 +1769,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.11" +version = "0.38.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" dependencies = [ "bitflags 2.4.0", "errno 0.3.3", "libc", - "linux-raw-sys 0.4.5", + "linux-raw-sys 0.4.7", "windows-sys 0.48.0", ] @@ -1815,9 +1815,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.4" +version = "0.101.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" +checksum = "45a27e3b59326c16e23d30aeb7a36a24cc0d29e71d68ff611cdfb4a01d013bed" dependencies = [ "ring", "untrusted", @@ -1930,7 +1930,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -2045,9 +2045,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", "windows-sys 0.48.0", @@ -2078,9 +2078,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.31" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", @@ -2107,7 +2107,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.38.11", + "rustix 0.38.13", "windows-sys 0.48.0", ] @@ -2163,7 +2163,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -2233,7 +2233,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.3", + "socket2 0.5.4", "windows-sys 0.48.0", ] @@ -2429,9 +2429,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2557,7 +2557,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", "wasm-bindgen-shared", ] @@ -2591,7 +2591,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 7a0068f5b..05ac3e32f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.9.0" +version = "2023.9.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 1fd5f7e48..c4107a06a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.9.0 +rtx 2023.9.1 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.9.0/rtx-v2023.9.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.9.1/rtx-v2023.9.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/completions/rtx.fish b/completions/rtx.fish index 8b6bdd217..2324ebc26 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -49,7 +49,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the install complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash ,fish ,nu ,xonsh ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r @@ -182,7 +182,7 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash ,elvish ,fish ,powershell ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash '',elvish '',fish '',powershell '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from completion" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r @@ -283,7 +283,7 @@ complete -c rtx -n "__fish_seen_subcommand_from doctor" -s y -l yes -d 'Answer y complete -c rtx -n "__fish_seen_subcommand_from doctor" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash ,fish ,nu ,xonsh ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r @@ -340,7 +340,7 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -s y -l yes -d 'Answer y complete -c rtx -n "__fish_seen_subcommand_from global" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash ,fish ,nu ,xonsh ,zsh }" +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r diff --git a/default.nix b/default.nix index 583954f8a..f32025d55 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.9.0"; + version = "2023.9.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 60dfe4331..5af84d9ae 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.9.0" +.TH rtx 1 "rtx 2023.9.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.9.0 +v2023.9.1 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index fc4133e8f..9d70f0759 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.9.0 +Version: 2023.9.1 Release: 1 URL: https://github.com/jdx/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 6117a2975..bca941140 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 694] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -52,6 +52,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("argocd", "https://github.com/beardix/asdf-argocd.git"), ("aria2", "https://github.com/asdf-community/asdf-aria2.git"), ("asciidoctorj", "https://github.com/gliwka/asdf-asciidoctorj.git"), + ("asdf-plugin-manager", "https://github.com/asdf-community/asdf-plugin-manager"), ("assh", "https://github.com/zekker6/asdf-assh.git"), ("aws-amplify-cli", "https://github.com/LozanoMatheus/asdf-aws-amplify-cli.git"), ("aws-copilot", "https://github.com/NeoHsu/asdf-copilot"), @@ -78,6 +79,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("bbr", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("bbr-s3-config-validator", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("benthos", "https://github.com/benthosdev/benthos-asdf.git"), + ("bfs", "https://github.com/virtualroot/asdf-bfs.git"), ("bin", "https://github.com/joe733/asdf-bin.git"), ("binnacle", "https://github.com/Traackr/asdf-binnacle.git"), ("bitwarden", "https://github.com/vixus0/asdf-bitwarden.git"), @@ -201,12 +203,14 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("embulk", "https://github.com/yuokada/asdf-embulk.git"), ("emsdk", "https://github.com/RobLoach/asdf-emsdk.git"), ("envcli", "https://github.com/zekker6/asdf-envcli.git"), + ("envsubst", "https://github.com/dex4er/asdf-envsubst.git"), ("ephemeral-postgres", "https://github.com/smashedtoatoms/asdf-ephemeral-postgres.git"), ("erlang", "https://github.com/asdf-vm/asdf-erlang.git"), ("esy", "https://github.com/asdf-community/asdf-esy.git"), ("etcd", "https://github.com/particledecay/asdf-etcd.git"), ("evans", "https://github.com/goki90210/asdf-evans.git"), ("exa", "https://github.com/nyrst/asdf-exa.git"), + ("eza", "https://github.com/lwiechec/asdf-eza.git"), ("fd", "https://gitlab.com/wt0f/asdf-fd.git"), ("ffmpeg", "https://github.com/acj/asdf-ffmpeg"), ("figma-export", "https://github.com/younke/asdf-figma-export.git"), @@ -297,6 +301,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("helmsman", "https://github.com/luisdavim/asdf-helmsman"), ("heroku-cli", "https://github.com/treilly94/asdf-heroku-cli.git"), ("hey", "https://github.com/raimon49/asdf-hey.git"), + ("hostctl", "https://github.com/svenluijten/asdf-hostctl.git"), ("httpie-go", "https://github.com/abatilo/asdf-httpie-go.git"), ("hub", "https://github.com/vixus0/asdf-hub.git"), ("hugo", "https://github.com/NeoHsu/asdf-hugo.git"), @@ -343,6 +348,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("kbld", "https://github.com/vmware-tanzu/asdf-carvel.git"), ("kcat", "https://github.com/douglasdgoulart/asdf-kcat.git"), ("kcctl", "https://github.com/joschi/asdf-kcctl.git"), + ("kcl", "https://github.com/starkers/asdf-kcl"), ("kconf", "https://github.com/particledecay/asdf-kconf.git"), ("ki", "https://github.com/comdotlinux/asdf-ki"), ("kind", "https://github.com/johnlayton/asdf-kind.git"), @@ -454,6 +460,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("nim", "https://github.com/asdf-community/asdf-nim.git"), ("ninja", "https://github.com/asdf-community/asdf-ninja.git"), ("nomad", "https://github.com/asdf-community/asdf-hashicorp.git"), + ("notation", "https://github.com/bodgit/asdf-notation.git"), ("nova", "https://github.com/elementalvoid/asdf-nova.git"), ("nsc", "https://github.com/dex4er/asdf-nsc.git"), ("oapi-codegen", "https://github.com/dylanrayboss/asdf-oapi-codegen.git"), @@ -474,6 +481,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("openshift-install", "https://github.com/hhemied/asdf-openshift-install.git"), ("operator-sdk", "https://github.com/Medium/asdf-operator-sdk.git"), ("opsgenie-lamp", "https://github.com/ORCID/asdf-opsgenie-lamp"), + ("oras", "https://github.com/bodgit/asdf-oras.git"), ("osm", "https://github.com/nlamirault/asdf-osm.git"), ("osqueryi", "https://github.com/davidecavestro/asdf-osqueryi.git"), ("pachctl", "https://github.com/abatilo/asdf-pachctl.git"), @@ -498,6 +506,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("powershell-core", "https://github.com/daveneeley/asdf-powershell-core.git"), ("pre-commit", "https://github.com/jonathanmorley/asdf-pre-commit.git"), ("protoc", "https://github.com/paxosglobal/asdf-protoc.git"), + ("protoc-gen-connect-go", "https://github.com/dylanrayboss/asdf-protoc-gen-connect-go.git"), ("protoc-gen-go", "https://github.com/pbr0ck3r/asdf-protoc-gen-go.git"), ("protoc-gen-go-grpc", "https://github.com/pbr0ck3r/asdf-protoc-gen-go-grpc.git"), ("protoc-gen-grpc-web", "https://github.com/pbr0ck3r/asdf-protoc-gen-grpc-web.git"), @@ -541,6 +550,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("sbcl", "https://github.com/smashedtoatoms/asdf-sbcl.git"), ("sbt", "https://github.com/bram2000/asdf-sbt.git"), ("scala", "https://github.com/asdf-community/asdf-scala.git"), + ("scala-cli", "https://github.com/asdf-community/asdf-scala-cli.git"), ("scaleway-cli", "https://github.com/albarralnunez/asdf-plugin-scaleway-cli"), ("scalingo-cli", "https://github.com/brandon-welsch/asdf-scalingo-cli.git"), ("scarb", "https://github.com/software-mansion/asdf-scarb.git"), @@ -567,6 +577,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 683] = [ ("snyk", "https://github.com/nirfuchs/asdf-snyk.git"), ("soft-serve", "https://github.com/chessmango/asdf-soft-serve.git"), ("solidity", "https://github.com/diegodorado/asdf-solidity.git"), + ("sonobuoy", "https://github.com/Nick-Triller/asdf-sonobuoy.git"), ("sops", "https://github.com/feniix/asdf-sops.git"), ("sopstool", "https://github.com/elementalvoid/asdf-sopstool.git"), ("soracom", "https://github.com/grimoh/asdf-soracom.git"), From 2545f4555afa5bc6fd8f7756f08008318318bf5f Mon Sep 17 00:00:00 2001 From: "Justin \"J.R.\" Hill" Date: Fri, 15 Sep 2023 06:49:09 +0900 Subject: [PATCH 1026/1891] fix: Always return a list on 'rtx ls --json' (#896) closes #882 --- src/cli/ls.rs | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 83010d06b..6b5a2a958 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -126,25 +126,23 @@ impl Ls { } fn display_json(&self, runtimes: Vec, out: &mut Output) -> Result<()> { + if let Some(plugin) = &self.plugin { + // only runtimes for 1 plugin + let runtimes: Vec = runtimes + .into_iter() + .filter(|(p, _, _)| plugin.eq(&p.name)) + .map(|row| row.into()) + .collect(); + out.stdout.writeln(serde_json::to_string_pretty(&runtimes)?); + return Ok(()); + } + let mut plugins = JSONOutput::new(); for (plugin_name, runtimes) in &runtimes .into_iter() .group_by(|(p, _, _)| p.name.to_string()) { - let runtimes = runtimes - .map(|(p, tv, source)| JSONToolVersion { - symlinked_to: p.symlink_path(&tv), - install_path: tv.install_path(), - version: tv.version, - requested_version: source.as_ref().map(|_| tv.request.version()), - source: source.map(|source| source.as_json()), - }) - .collect(); - if self.plugin.is_some() { - // only display 1 plugin - out.stdout.writeln(serde_json::to_string_pretty(&runtimes)?); - return Ok(()); - } + let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); } out.stdout.writeln(serde_json::to_string_pretty(&plugins)?); @@ -273,6 +271,19 @@ impl Ls { type RuntimeRow = (Arc, ToolVersion, Option); +impl From for JSONToolVersion { + fn from(row: RuntimeRow) -> Self { + let (p, tv, source) = row; + JSONToolVersion { + symlinked_to: p.symlink_path(&tv), + install_path: tv.install_path(), + version: tv.version, + requested_version: source.as_ref().map(|_| tv.request.version()), + source: source.map(|source| source.as_json()), + } + } +} + enum VersionStatus { Active(String, bool), Inactive(String), From f11af0254657bc625f7f69a98be20a276da435f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 21:51:59 -0500 Subject: [PATCH 1027/1891] chore(deps): bump chrono from 0.4.30 to 0.4.31 (#898) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a543af4f6..0b6e17ad1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,9 +206,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", From fa1422eec64d9fc17f0010469ec99e0c123fe186 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 21:52:15 -0500 Subject: [PATCH 1028/1891] chore(deps): bump self_update from 0.37.0 to 0.38.0 (#901) --- Cargo.lock | 27 ++++++++++++++++++++++++--- Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b6e17ad1..6a515f359 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -601,6 +601,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.0.0" @@ -1886,11 +1895,22 @@ dependencies = [ "libc", ] +[[package]] +name = "self-replace" +version = "1.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56335359191626938ef6fdeb478f9f6a7c6020254d7f4641c7d810369fa0ec1" +dependencies = [ + "fastrand 1.9.0", + "tempfile", + "windows-sys 0.48.0", +] + [[package]] name = "self_update" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a667e18055120bcc9a658d55d36f2f6bfc82e07968cc479ee7774e3bfb501e14" +checksum = "2b3c585a1ced6b97ac13bd5e56f66559e5a75f477da5913f70df98e114518446" dependencies = [ "hyper", "indicatif", @@ -1898,6 +1918,7 @@ dependencies = [ "quick-xml", "regex", "reqwest", + "self-replace", "semver", "serde_json", "tempfile", @@ -2105,7 +2126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.0.0", "redox_syscall 0.3.5", "rustix 0.38.13", "windows-sys 0.48.0", diff --git a/Cargo.toml b/Cargo.toml index 05ac3e32f..ba20fd503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,7 @@ reqwest = { version = "0.11.17", default-features = false, features = [ "json", ] } rmp-serde = "1.1.2" -self_update = { version = "0.37.0", default-features = false, optional = true } +self_update = { version = "0.38.0", default-features = false, optional = true } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" From 50574755085234db7e1481aaf63dfcfb43c0b40c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 21:52:23 -0500 Subject: [PATCH 1029/1891] chore(deps): bump serde_json from 1.0.106 to 1.0.107 (#900) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a515f359..7647bf80a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1956,9 +1956,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", From 080f22a84defd58bd170e9bfd3a3d7a57dab2080 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 21:52:35 -0500 Subject: [PATCH 1030/1891] chore(deps): bump terminal_size from 0.2.6 to 0.3.0 (#902) --- Cargo.lock | 41 +++++------------------------------------ Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7647bf80a..130fc5957 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1055,17 +1055,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipnet" version = "2.8.0" @@ -1147,12 +1136,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.7" @@ -1762,20 +1745,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustix" -version = "0.37.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags 1.3.2", - "errno 0.3.3", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - [[package]] name = "rustix" version = "0.38.13" @@ -1785,7 +1754,7 @@ dependencies = [ "bitflags 2.4.0", "errno 0.3.3", "libc", - "linux-raw-sys 0.4.7", + "linux-raw-sys", "windows-sys 0.48.0", ] @@ -2128,7 +2097,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.38.13", + "rustix", "windows-sys 0.48.0", ] @@ -2159,11 +2128,11 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.37.23", + "rustix", "windows-sys 0.48.0", ] diff --git a/Cargo.toml b/Cargo.toml index ba20fd503..7b88687fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,7 @@ shell-words = "1.1" simplelog = { version = "0.12" } tar = "0.4" tera = { version = "1.19", default-features = false } -terminal_size = "0.2" +terminal_size = "0.3" thiserror = "1.0" toml = "<0.8" toml_edit = "<0.20" From 2a23f16cffeb53e30fedf23567ba37abde568c03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 21:52:50 -0500 Subject: [PATCH 1031/1891] chore(deps): bump built from 0.6.1 to 0.7.0 (#899) --- Cargo.lock | 30 +++++++----------------------- Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 130fc5957..365aac5e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,11 +149,10 @@ dependencies = [ [[package]] name = "built" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b99c4cdc7b2c2364182331055623bdf45254fcb679fea565c40c3c11c101889a" +checksum = "1462f4ab147e1378c64dacd28f03a56d4771d93eab6c325265a35355ce47213d" dependencies = [ - "cargo-lock", "chrono", "git2", ] @@ -176,18 +175,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -[[package]] -name = "cargo-lock" -version = "9.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11c675378efb449ed3ce8de78d75d0d80542fc98487c26aba28eb3b82feac72" -dependencies = [ - "semver", - "serde", - "toml", - "url", -] - [[package]] name = "cc" version = "1.0.83" @@ -767,11 +754,11 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "git2" -version = "0.17.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044" +checksum = "12ef350ba88a33b4d524b1d1c79096c9ade5ef8c59395df0e60d1e1889414c0e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "libc", "libgit2-sys", "log", @@ -1108,9 +1095,9 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libgit2-sys" -version = "0.15.2+1.6.4" +version = "0.16.1+1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa" +checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c" dependencies = [ "cc", "libc", @@ -1899,9 +1886,6 @@ name = "semver" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" -dependencies = [ - "serde", -] [[package]] name = "serde" diff --git a/Cargo.toml b/Cargo.toml index 7b88687fc..b1e8187dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,7 +93,7 @@ versions = "5.0" exec = "0.3" [build-dependencies] -built = { version = "0.6", features = ["chrono", "git2"] } +built = { version = "0.7", features = ["chrono", "git2"] } [dev-dependencies] ctor = "<0.3" From 9b895734841dab3deb2751953036b7d999bd4dc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 21:53:03 -0500 Subject: [PATCH 1032/1891] chore(deps): bump aws-actions/configure-aws-credentials from 3 to 4 (#903) --- .github/workflows/rtx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index a5346710f..24cc08c99 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -244,7 +244,7 @@ jobs: node-version: "20.x" registry-url: "https://registry.npmjs.org" - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v3 + uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} From 90aa4277299bf67d4d830eb662e6bdcd7331233e Mon Sep 17 00:00:00 2001 From: Nico Kokonas Date: Sun, 17 Sep 2023 21:46:58 -0600 Subject: [PATCH 1033/1891] Update README.md (#904) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4107a06a..4a8ab3c13 100644 --- a/README.md +++ b/README.md @@ -1021,7 +1021,7 @@ As well as these functions: - `exec(command: &str) -> String` – execute a command and return the output -Templates are parsed with [tera](https://tera.netlify.app/docs)—which is quite powerful. For +Templates are parsed with [tera](https://keats.github.io/tera/docs/)—which is quite powerful. For example, this snippet will get the directory name of the project: ```toml From 929553e02f15805ee5ebcc8e8d959c3947d191c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 01:27:52 +0000 Subject: [PATCH 1034/1891] chore(deps): bump indicatif from 0.17.6 to 0.17.7 (#911) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 365aac5e9..489b3f758 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1002,9 +1002,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" dependencies = [ "console", "instant", From 2b47ba9648a2ebd559f5de763061820ea441700e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 01:30:55 +0000 Subject: [PATCH 1035/1891] chore(deps): bump clap_mangen from 0.2.13 to 0.2.14 (#910) --- Cargo.lock | 4 ++-- xtask/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 489b3f758..e78e0530a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -254,9 +254,9 @@ checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "clap_mangen" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8e5f34d85d9e0bbe2491d100a7a7c1007bb2467b518080bfe311e8947197a9" +checksum = "b44f35c514163027542f7147797ff930523eea288e03642727348ef1a9666f6b" dependencies = [ "clap", "roff", diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index cba1bc154..53e7b6281 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap_mangen = "0.2.10" +clap_mangen = "0.2.14" color-eyre = "0.6.2" rtx-cli = {path = ".."} From 59eb5a846f01572fe32d8c586d6d2320e7044d2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 01:40:49 +0000 Subject: [PATCH 1036/1891] chore(deps): bump rayon from 1.7.0 to 1.8.0 (#912) --- Cargo.lock | 20 ++++---------------- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e78e0530a..9a3aaa190 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -363,16 +363,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -1504,9 +1494,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -1514,14 +1504,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b1e8187dc..f60a67e50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ once_cell = "1.18" openssl = { version = "0.10", optional = true } path-absolutize = "3.1" rand = "0.8" -rayon = "1.6" +rayon = "1.8" regex = "1.9" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", From d9ebc61fa5adda1eba9f23fdb577e8fd2578fe8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 01:42:58 +0000 Subject: [PATCH 1037/1891] chore(deps): bump indoc from 2.0.3 to 2.0.4 (#913) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a3aaa190..a0107645b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1006,9 +1006,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "insta" From 962e615c622bfbea7e42d3d22f6637de858e21b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 01:45:46 +0000 Subject: [PATCH 1038/1891] chore(deps): bump toml_edit from 0.19.15 to 0.20.0 (#914) --- Cargo.lock | 15 +++++++++++++-- Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0107645b..169f32836 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1709,7 +1709,7 @@ dependencies = [ "terminal_size", "thiserror", "toml", - "toml_edit", + "toml_edit 0.20.0", "url", "versions", ] @@ -2242,7 +2242,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -2267,6 +2267,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95" +dependencies = [ + "indexmap 2.0.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index f60a67e50..b3810b850 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ tera = { version = "1.19", default-features = false } terminal_size = "0.3" thiserror = "1.0" toml = "<0.8" -toml_edit = "<0.20" +toml_edit = "<0.21" url = "2.4" versions = "5.0" From c3de328fc5d5dd91f9c2a4d01d4cd23d6e293ede Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:51:40 -0500 Subject: [PATCH 1039/1891] doctor: allow shims on PATH to hide inactive problem (#916) --- src/cli/doctor.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 2a575e9e2..f5fda8a72 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -15,7 +15,7 @@ use crate::output::Output; use crate::plugins::PluginType; use crate::shell::ShellType; use crate::toolset::ToolsetBuilder; -use crate::{cli, cmd}; +use crate::{cli, cmd, dirs}; use crate::{duration, env}; /// Check rtx installation for possible problems. @@ -62,12 +62,15 @@ impl Command for Doctor { )); } - if !config.is_activated() { + if !config.is_activated() && !shims_on_path() { let cmd = style("rtx help activate").yellow().for_stderr(); let url = style("https://rtx.pub").underlined().for_stderr(); + let shims = style(dirs::SHIMS.display()).cyan().for_stderr(); checks.push(formatdoc!( r#"rtx is not activated, run {cmd} or - read documentation at {url} for activation instructions"# + read documentation at {url} for activation instructions. + Alternatively, add the shims directory {shims} to PATH. + Using the shims directory is preferred for non-interactive setups."# )); } @@ -87,6 +90,10 @@ impl Command for Doctor { } } +fn shims_on_path() -> bool { + env::PATH.contains(&*dirs::SHIMS) +} + fn rtx_data_dir() -> String { let mut s = style("rtx data directory:\n").bold().to_string(); s.push_str(&format!(" {}\n", env::RTX_DATA_DIR.to_string_lossy())); From 155dadb0f7521c76a268a261dfad86dfbf2767a5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 25 Sep 2023 12:05:42 -0500 Subject: [PATCH 1040/1891] chore: Release --- Cargo.lock | 100 +++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 3 +- 7 files changed, 59 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 169f32836..1bc455397 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ "memchr", ] @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" @@ -205,9 +205,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.3" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" +checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" dependencies = [ "clap_builder", "clap_derive", @@ -215,9 +215,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.2" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" dependencies = [ "anstream", "anstyle", @@ -243,7 +243,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -413,7 +413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" dependencies = [ "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -684,7 +684,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -744,9 +744,9 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "git2" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ef350ba88a33b4d524b1d1c79096c9ade5ef8c59395df0e60d1e1889414c0e" +checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" dependencies = [ "bitflags 2.4.0", "libc", @@ -818,9 +818,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "http" @@ -1012,9 +1012,9 @@ checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "insta" -version = "1.31.0" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0770b0a3d4c70567f0d58331f3088b0e4c4f56c9b8d764efe654b4a5d46de3a" +checksum = "a3e02c584f4595792d09509a94cdb92a3cef7592b1eb2d9877ee6f527062d0ea" dependencies = [ "console", "lazy_static", @@ -1283,7 +1283,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -1381,7 +1381,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -1437,9 +1437,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -1658,7 +1658,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.9.1" +version = "2023.9.2" dependencies = [ "base64", "built", @@ -1722,9 +1722,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.13" +version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ "bitflags 2.4.0", "errno 0.3.3", @@ -1768,9 +1768,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.5" +version = "0.101.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a27e3b59326c16e23d30aeb7a36a24cc0d29e71d68ff611cdfb4a01d013bed" +checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" dependencies = [ "ring", "untrusted", @@ -1841,9 +1841,9 @@ dependencies = [ [[package]] name = "self-replace" -version = "1.3.6" +version = "1.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56335359191626938ef6fdeb478f9f6a7c6020254d7f4641c7d810369fa0ec1" +checksum = "525db198616b2bcd0f245daf7bfd8130222f7ee6af9ff9984c19a61bf1160c55" dependencies = [ "fastrand 1.9.0", "tempfile", @@ -1871,9 +1871,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" [[package]] name = "serde" @@ -1892,7 +1892,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -2040,9 +2040,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -2125,7 +2125,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -2140,9 +2140,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" dependencies = [ "deranged", "itoa", @@ -2155,15 +2155,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -2221,9 +2221,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -2334,9 +2334,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" @@ -2423,9 +2423,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "untrusted" @@ -2530,7 +2530,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", "wasm-bindgen-shared", ] @@ -2564,7 +2564,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2609,9 +2609,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index b3810b850..0b9f24093 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.9.1" +version = "2023.9.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 4a8ab3c13..7e00b251a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.9.1 +rtx 2023.9.2 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.9.1/rtx-v2023.9.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.9.2/rtx-v2023.9.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index f32025d55..e03a5a70c 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.9.1"; + version = "2023.9.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 5af84d9ae..e37558102 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.9.1" +.TH rtx 1 "rtx 2023.9.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.9.1 +v2023.9.2 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9d70f0759..c801e3ad4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.9.1 +Version: 2023.9.2 Release: 1 URL: https://github.com/jdx/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index bca941140..bf4a50bda 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 694] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -534,6 +534,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 694] = [ ("redskyctl", "https://github.com/sudermanjr/asdf-redskyctl.git"), ("reg", "https://github.com/looztra/asdf-reg.git"), ("regctl", "https://github.com/ORCID/asdf-regctl.git"), + ("regsync", "https://github.com/rsrchboy/asdf-regsync.git"), ("restic", "https://github.com/xataz/asdf-restic"), ("revive", "https://github.com/bjw-s/asdf-revive.git"), ("richgo", "https://github.com/paxosglobal/asdf-richgo.git"), From 153f6fe342d6527dab1f430ab367214d11de01a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:12:08 -0500 Subject: [PATCH 1041/1891] chore(deps): bump toml from 0.7.8 to 0.8.0 (#922) Bumps [toml](https://github.com/toml-rs/toml) from 0.7.8 to 0.8.0. - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.7.8...toml-v0.8.0) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 23 ++++++----------------- Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bc455397..38be7850e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1709,7 +1709,7 @@ dependencies = [ "terminal_size", "thiserror", "toml", - "toml_edit 0.20.0", + "toml_edit", "url", "versions", ] @@ -2235,14 +2235,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.8" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +checksum = "c226a7bba6d859b63c92c4b4fe69c5b6b72d0cb897dbc8e6012298e6154cb56e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.19.15", + "toml_edit", ] [[package]] @@ -2254,19 +2254,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.0.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - [[package]] name = "toml_edit" version = "0.20.0" @@ -2274,6 +2261,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95" dependencies = [ "indexmap 2.0.0", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index 0b9f24093..7fa0ee1ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ tar = "0.4" tera = { version = "1.19", default-features = false } terminal_size = "0.3" thiserror = "1.0" -toml = "<0.8" +toml = "<0.9" toml_edit = "<0.21" url = "2.4" versions = "5.0" From 404ddf721e4e09e53f1427d0f6a9681d0be0d16a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:12:46 -0500 Subject: [PATCH 1042/1891] chore(deps): bump clap from 4.4.4 to 4.4.6 (#926) Bumps [clap](https://github.com/clap-rs/clap) from 4.4.4 to 4.4.6. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.4.4...v4.4.6) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38be7850e..bfc493214 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", @@ -81,9 +81,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -205,9 +205,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.4" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" dependencies = [ "clap_builder", "clap_derive", @@ -215,9 +215,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.4" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" dependencies = [ "anstream", "anstyle", From 9df635f6ee25970557634714ca6ab934e722f03a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:12:54 -0500 Subject: [PATCH 1043/1891] chore(deps): bump ctor from 0.2.4 to 0.2.5 (#925) Bumps [ctor](https://github.com/mmastrac/rust-ctor) from 0.2.4 to 0.2.5. - [Commits](https://github.com/mmastrac/rust-ctor/commits) --- updated-dependencies: - dependency-name: ctor dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bfc493214..040afd23b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,9 +408,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" +checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" dependencies = [ "quote", "syn 2.0.37", From 403b0ed3cd9b2b0a8aa9813de74b5cf69742612c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:13:01 -0500 Subject: [PATCH 1044/1891] chore(deps): bump insta from 1.32.0 to 1.33.0 (#924) Bumps [insta](https://github.com/mitsuhiko/insta) from 1.32.0 to 1.33.0. - [Changelog](https://github.com/mitsuhiko/insta/blob/master/CHANGELOG.md) - [Commits](https://github.com/mitsuhiko/insta/compare/1.32.0...1.33.0) --- updated-dependencies: - dependency-name: insta dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 040afd23b..80637e853 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,9 +1012,9 @@ checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "insta" -version = "1.32.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e02c584f4595792d09509a94cdb92a3cef7592b1eb2d9877ee6f527062d0ea" +checksum = "1aa511b2e298cd49b1856746f6bb73e17036bcd66b25f5e92cdcdbec9bd75686" dependencies = [ "console", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 7fa0ee1ef..7ce761542 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ built = { version = "0.7", features = ["chrono", "git2"] } [dev-dependencies] ctor = "<0.3" -insta = "1.31" +insta = "1.33" pretty_assertions = "1.4" [features] From b8f142fcf1e711de2684cdce2ddebde108f0427b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:13:08 -0500 Subject: [PATCH 1045/1891] chore(deps): bump thiserror from 1.0.48 to 1.0.49 (#923) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.48 to 1.0.49. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.48...1.0.49) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80637e853..d567fe0fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2110,18 +2110,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", From 1f8b65d1394fcf3ec2273189c658b8b4b78446b7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 4 Oct 2023 09:08:13 -0500 Subject: [PATCH 1046/1891] chore: Release --- Cargo.lock | 118 ++++++++++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 77 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d567fe0fc..1ec8fdd5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,15 +57,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" dependencies = [ "utf8parse", ] @@ -227,9 +227,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.1" +version = "4.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4110a1e6af615a9e6d0a36f805d5c99099f8bab9b8042f5bc1fa220a4a89e36f" +checksum = "e3ae8ba90b9d8b007efe66e55e48fb936272f5ca00349b5b0e89877520d35ea7" dependencies = [ "clap", ] @@ -539,9 +539,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" dependencies = [ "errno-dragonfly", "libc", @@ -589,9 +589,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "filetime" @@ -806,9 +806,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" [[package]] name = "heck" @@ -981,12 +981,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", "serde", ] @@ -1115,9 +1115,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" [[package]] name = "log" @@ -1127,9 +1127,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -1352,9 +1352,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" dependencies = [ "memchr", "thiserror", @@ -1363,9 +1363,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" dependencies = [ "pest", "pest_generator", @@ -1373,9 +1373,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" dependencies = [ "pest", "pest_meta", @@ -1386,9 +1386,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" dependencies = [ "once_cell", "pest", @@ -1543,9 +1543,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.5" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" dependencies = [ "aho-corasick", "memchr", @@ -1555,9 +1555,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", @@ -1572,9 +1572,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64", "bytes", @@ -1601,6 +1601,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -1658,7 +1659,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.9.2" +version = "2023.10.0" dependencies = [ "base64", "built", @@ -1680,7 +1681,7 @@ dependencies = [ "fslock", "humantime", "indenter", - "indexmap 2.0.0", + "indexmap 2.0.2", "indicatif", "indoc", "insta", @@ -1722,12 +1723,12 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.14" +version = "0.38.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +checksum = "d2f9da0cbd88f9f09e7814e388301c8414c51c62aa6ce1e4b5c551d49d96e531" dependencies = [ "bitflags 2.4.0", - "errno 0.3.3", + "errno 0.3.4", "libc", "linux-raw-sys", "windows-sys 0.48.0", @@ -1929,9 +1930,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1940,9 +1941,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "c1b21f559e07218024e7e9f90f96f601825397de0e25420135f7f952453fed0b" dependencies = [ "lazy_static", ] @@ -2049,6 +2050,27 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tar" version = "0.4.40" @@ -2067,7 +2089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", - "fastrand 2.0.0", + "fastrand 2.0.1", "redox_syscall 0.3.5", "rustix", "windows-sys 0.48.0", @@ -2235,9 +2257,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c226a7bba6d859b63c92c4b4fe69c5b6b72d0cb897dbc8e6012298e6154cb56e" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", "serde_spanned", @@ -2256,11 +2278,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.2", "serde", "serde_spanned", "toml_datetime", diff --git a/Cargo.toml b/Cargo.toml index 7ce761542..80cf78a1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.9.2" +version = "2023.10.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 7e00b251a..a9530c7b1 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.9.2 +rtx 2023.10.0 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.9.2/rtx-v2023.9.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.10.0/rtx-v2023.10.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index e03a5a70c..83173e750 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.9.2"; + version = "2023.10.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index e37558102..794885016 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.9.2" +.TH rtx 1 "rtx 2023.10.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.9.2 +v2023.10.0 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c801e3ad4..fd0c2d912 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.9.2 +Version: 2023.10.0 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 09516f49b93d13cd097bb0bf7f70137adf3789dc Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 4 Oct 2023 19:10:00 -0500 Subject: [PATCH 1047/1891] use java.rtx.pub for java metadata (#929) --- src/plugins/core/java.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 4cf810298..2f5376710 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -362,20 +362,19 @@ static JAVA_FILE_TYPES: Lazy> = fn download_java_metadata(release_type: &str) -> Result> { let http = http::Client::new()?; - let resp = http - .get("https://joschi.github.io/java-metadata/metadata/all.json") - .send()?; + let url = format!( + "https://java.rtx.pub/metadata/{}/{}/{}.json", + release_type, + os(), + arch() + ); + let resp = http.get(url).send()?; http.ensure_success(&resp)?; let metadata = resp .json::>()? .into_iter() - .filter(|m| { - m.architecture == arch() - && m.os == os() - && JAVA_FILE_TYPES.contains(&m.file_type) - && m.release_type == release_type - }) + .filter(|m| JAVA_FILE_TYPES.contains(&m.file_type)) .collect(); Ok(metadata) } From 19220e5fd0ac78b1ddce0bc1b679d47d5dd9b11c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 4 Oct 2023 19:12:08 -0500 Subject: [PATCH 1048/1891] chore: Release --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/cli/env_vars.rs | 8 ++++---- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ec8fdd5c..7b7d5a6d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1659,7 +1659,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.10.0" +version = "2023.10.1" dependencies = [ "base64", "built", @@ -1723,9 +1723,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.15" +version = "0.38.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f9da0cbd88f9f09e7814e388301c8414c51c62aa6ce1e4b5c551d49d96e531" +checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7" dependencies = [ "bitflags 2.4.0", "errno 0.3.4", @@ -1941,9 +1941,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b21f559e07218024e7e9f90f96f601825397de0e25420135f7f952453fed0b" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] diff --git a/Cargo.toml b/Cargo.toml index 80cf78a1a..de1dc2ab0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.10.0" +version = "2023.10.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index a9530c7b1..4853c1175 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.10.0 +rtx 2023.10.1 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.10.0/rtx-v2023.10.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.10.1/rtx-v2023.10.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 83173e750..1d555b6b3 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.10.0"; + version = "2023.10.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 794885016..8ca0c7773 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.10.0" +.TH rtx 1 "rtx 2023.10.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.10.0 +v2023.10.1 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index fd0c2d912..e1f4b6593 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.10.0 +Version: 2023.10.1 Release: 1 URL: https://github.com/jdx/rtx/ Group: System diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index 6b1dbf221..c0e437df5 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -88,14 +88,14 @@ mod tests { let filename = ".test.rtx.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "FOO=bar"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); // Using a custom file let filename = ".test-custom.rtx.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "--file", filename, "FOO=bar"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); } @@ -106,7 +106,7 @@ mod tests { let cf_path = remove_config_file(filename); assert_cli!("env-vars", "BAZ=quux"); assert_cli!("env-vars", "--remove", "BAZ"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); // Using a custom file @@ -114,7 +114,7 @@ mod tests { let cf_path = remove_config_file(filename); assert_cli!("env-vars", "--file", filename, "BAZ=quux"); assert_cli!("env-vars", "--file", filename, "--remove", "BAZ"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); } } From ecc082fa777e8a48e407f441cc378a0cd1339ef1 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 4 Oct 2023 19:54:12 -0500 Subject: [PATCH 1049/1891] enable http gzip compression (#930) --- Cargo.lock | 15 +++++++++++++++ Cargo.toml | 1 + src/http.rs | 1 + 3 files changed, 17 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 7b7d5a6d4..f20516b93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,6 +89,19 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "async-compression" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb42b2197bf15ccb092b62c74515dbd8b86d0effd934795f6687c93b6e679a2c" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -1576,6 +1589,7 @@ version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ + "async-compression", "base64", "bytes", "encoding_rs", @@ -1605,6 +1619,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", + "tokio-util", "tower-service", "url", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index de1dc2ab0..67f78be1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ regex = "1.9" reqwest = { version = "0.11.17", default-features = false, features = [ "blocking", "json", + "gzip", ] } rmp-serde = "1.1.2" self_update = { version = "0.38.0", default-features = false, optional = true } diff --git a/src/http.rs b/src/http.rs index 4368575d0..c86edd098 100644 --- a/src/http.rs +++ b/src/http.rs @@ -12,6 +12,7 @@ impl Client { pub fn new() -> Result { let reqwest = reqwest::blocking::ClientBuilder::new() .user_agent(format!("rtx/{}", env!("CARGO_PKG_VERSION"))) + .gzip(true) .build()?; Ok(Self { reqwest }) } From befdb30d5eda68bf041a79be7a8ae4f7e1c00cd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 01:41:00 +0000 Subject: [PATCH 1050/1891] chore(deps): bump dialoguer from 0.10.4 to 0.11.0 Bumps [dialoguer](https://github.com/console-rs/dialoguer) from 0.10.4 to 0.11.0. - [Changelog](https://github.com/console-rs/dialoguer/blob/master/CHANGELOG.md) - [Commits](https://github.com/console-rs/dialoguer/compare/v0.10.4...v0.11.0) --- updated-dependencies: - dependency-name: dialoguer dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f20516b93..0e3476fee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -447,13 +447,14 @@ checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] name = "dialoguer" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", "shell-words", "tempfile", + "thiserror", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 67f78be1c..ee4e8a41f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ color-eyre = "0.6" color-print = "0.3" console = "0.15" ctrlc = "3.4" -dialoguer = { version = "0.10", features = [] } +dialoguer = { version = "0.11", features = [] } dirs-next = "2.0" dotenvy = "0.15" duct = "0.13" From b65984b2ec745be0a42b6d29948e8306e3c82025 Mon Sep 17 00:00:00 2001 From: Jacob Lorenzen Date: Wed, 11 Oct 2023 02:45:50 +0200 Subject: [PATCH 1051/1891] chore: map dialouger::Error to std:Error (#934) --- src/ui/prompt.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index ceac2760a..a97ca40b4 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -13,5 +13,8 @@ pub fn confirm(message: &str) -> io::Result { if !console::user_attended_stderr() { return Ok(false); } - Confirm::new().with_prompt(message).interact() + match Confirm::new().with_prompt(message).interact() { + Ok(choice) => Ok(choice), + Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), + } } From 45ff35fc1cfd968cc7305880f33bfdf17fab6044 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 15 Oct 2023 18:05:34 -0500 Subject: [PATCH 1052/1891] chore: Release --- Cargo.lock | 146 ++++++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 84 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e3476fee..eb3c3314c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -91,9 +91,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb42b2197bf15ccb092b62c74515dbd8b86d0effd934795f6687c93b6e679a2c" +checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2" dependencies = [ "flate2", "futures-core", @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" +checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" dependencies = [ "memchr", "serde", @@ -162,9 +162,9 @@ dependencies = [ [[package]] name = "built" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462f4ab147e1378c64dacd28f03a56d4771d93eab6c325265a35355ce47213d" +checksum = "38d17f4d6e4dc36d1a02fbedc2753a096848e7c1b0772f7654eab8e2c927dd53" dependencies = [ "chrono", "git2", @@ -178,9 +178,9 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -256,7 +256,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -426,7 +426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" dependencies = [ "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -441,9 +441,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] [[package]] name = "dialoguer" @@ -553,11 +556,10 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ - "errno-dragonfly", "libc", "windows-sys 0.48.0", ] @@ -621,9 +623,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", @@ -698,7 +700,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1026,9 +1028,9 @@ checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "insta" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa511b2e298cd49b1856746f6bb73e17036bcd66b25f5e92cdcdbec9bd75686" +checksum = "5d64600be34b2fcfc267740a243fa7744441bb4947a619ac4e5bb6507f35fbfc" dependencies = [ "console", "lazy_static", @@ -1069,9 +1071,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -1093,9 +1095,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libgit2-sys" @@ -1129,9 +1131,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "log" @@ -1227,9 +1229,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1297,7 +1299,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1395,7 +1397,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1433,6 +1435,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1451,9 +1459,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -1557,9 +1565,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.6" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "aaac441002f822bc9705a681810a4dd2963094b9ca0ddc41cb963a4c189189ea" dependencies = [ "aho-corasick", "memchr", @@ -1569,9 +1577,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "5011c7e263a695dc8ca064cddb722af1be54e517a280b12a5356f98366899e5d" dependencies = [ "aho-corasick", "memchr", @@ -1580,9 +1588,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" @@ -1675,7 +1683,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.10.1" +version = "2023.10.2" dependencies = [ "base64", "built", @@ -1739,12 +1747,12 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.17" +version = "0.38.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7" +checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" dependencies = [ "bitflags 2.4.0", - "errno 0.3.4", + "errno 0.3.5", "libc", "linux-raw-sys", "windows-sys 0.48.0", @@ -1888,28 +1896,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1988,9 +1996,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "similar" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597" [[package]] name = "simplelog" @@ -2057,9 +2065,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -2163,7 +2171,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2178,14 +2186,15 @@ dependencies = [ [[package]] name = "time" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", "itoa", "libc", "num_threads", + "powerfmt", "serde", "time-core", "time-macros", @@ -2223,9 +2232,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ "backtrace", "bytes", @@ -2313,20 +2322,19 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -2557,7 +2565,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -2591,7 +2599,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2792,9 +2800,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index ee4e8a41f..e98d70fda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.10.1" +version = "2023.10.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 4853c1175..867f23e68 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.10.1 +rtx 2023.10.2 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.10.1/rtx-v2023.10.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.10.2/rtx-v2023.10.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 1d555b6b3..b04977823 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.10.1"; + version = "2023.10.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 8ca0c7773..3098d0d9d 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.10.1" +.TH rtx 1 "rtx 2023.10.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.10.1 +v2023.10.2 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e1f4b6593..b88d5dea9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.10.1 +Version: 2023.10.2 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 2cebe1e37e1b8b148c38a6e5348de472ce63655b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:06:41 -0500 Subject: [PATCH 1053/1891] updated java lts to 21 (#947) --- .../alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap | 2 +- .../snapshots/rtx__cli__alias__unset__tests__alias_unset.snap | 2 +- src/plugins/core/java.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index a3e65eb2e..1d9e3ed87 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -2,7 +2,7 @@ source: src/cli/alias/set.rs expression: output --- -java lts 17 +java lts 21 node lts 18 node lts-argon 4 node lts-boron 6 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index 2f8d56f55..d9f77f628 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -2,7 +2,7 @@ source: src/cli/alias/unset.rs expression: output --- -java lts 17 +java lts 21 node lts 18 node lts-argon 4 node lts-boron 6 diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 2f5376710..91cfb1ede 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -241,7 +241,7 @@ impl Plugin for JavaPlugin { } fn get_aliases(&self, _settings: &Settings) -> Result> { - let aliases = BTreeMap::from([("lts".into(), "17".into())]); + let aliases = BTreeMap::from([("lts".into(), "21".into())]); Ok(aliases) } From 6aa2382a3e1e8d53a375d928a4a14e3d50027cac Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:16:23 -0500 Subject: [PATCH 1054/1891] Update README.md Fixes #950 --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 867f23e68..cdac82349 100644 --- a/README.md +++ b/README.md @@ -602,6 +602,24 @@ _Note: `env_file` goes at the top of the file, above `[env]`._ NODE_ENV = false # unset a previously set NODE_ENV ``` +#### `[plugins]` - Specify Custom Plugin Repo URLs + +Use `[plugins]` to add/modify plugin shortnames. Note that this will only modify +*new* plugin installations. Existing plugins can use any URL. + +```toml +[plugins] +elixir = "https://github.com/my-org/rtx-elixir.git" +node = "https://github.com/my-org/rtx-node.git#DEADBEEF" # supports specific gitref +``` + +If you simply want to install a plugin from a specific URL once, it's better to use +`rtx plugin install plugin `. Add this section to `.rtx.toml` if you want +to share the plugin location/revision with other developers in your project. + +This is similar to [`RTX_SHORTHANDS`](https://github.com/jdx/rtx#rtx_shorthands_fileconfigrtxshorthandstoml) +but doesn't require a separate file. + ### Legacy version files rtx supports "legacy version files" just like asdf. They're language-specific files like `.node-version` From a2fa00d322ddce2a143a45bf7540f61decf420b6 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:18:48 -0500 Subject: [PATCH 1055/1891] fix deactivate with existing PROMPT_COMMAND (#949) --- src/shell/bash.rs | 1 + src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap | 1 + 2 files changed, 2 insertions(+) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 7ff8529bd..977f378c0 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -52,6 +52,7 @@ impl Shell for Bash { fn deactivate(&self) -> String { formatdoc! {r#" + PROMPT_COMMAND="${{PROMPT_COMMAND//_rtx_hook;/}}" PROMPT_COMMAND="${{PROMPT_COMMAND//_rtx_hook/}}" unset _rtx_hook unset rtx diff --git a/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap index c90483684..bd78efebb 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap @@ -2,6 +2,7 @@ source: src/shell/bash.rs expression: replace_path(&deactivate) --- +PROMPT_COMMAND="${PROMPT_COMMAND//_rtx_hook;/}" PROMPT_COMMAND="${PROMPT_COMMAND//_rtx_hook/}" unset _rtx_hook unset rtx From 98d41e467ec765afae9e665a3998c92baeff1172 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 20 Oct 2023 16:51:03 -0500 Subject: [PATCH 1056/1891] remove experimental flag on upgrade/outdated (#951) --- README.md | 4 ++-- completions/_rtx | 8 ++++---- completions/rtx.fish | 8 ++++---- man/man1/rtx.1 | 4 ++-- src/cli/outdated.rs | 7 +------ src/cli/upgrade.rs | 7 +------ 6 files changed, 14 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index cdac82349..fd9202787 100644 --- a/README.md +++ b/README.md @@ -2045,7 +2045,7 @@ Examples: ### `rtx outdated [TOOL@VERSION]...` ``` -[experimental] Shows outdated tool versions +Shows outdated tool versions Usage: outdated [TOOL@VERSION]... @@ -2469,7 +2469,7 @@ Examples: ### `rtx upgrade [TOOL@VERSION]...` ``` -[experimental] Upgrades outdated tool versions +Upgrades outdated tool versions Usage: upgrade [TOOL@VERSION]... diff --git a/completions/_rtx b/completions/_rtx index 96ebba333..6f20828d5 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -2144,7 +2144,7 @@ _rtx_commands() { 'ls:List installed and/or currently selected tool versions' \ 'list:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ -'outdated:\[experimental\] Shows outdated tool versions' \ +'outdated:Shows outdated tool versions' \ 'plugins:Manage plugins' \ 'p:Manage plugins' \ 'prune:Delete unused versions of tools' \ @@ -2155,7 +2155,7 @@ _rtx_commands() { 'sync:Add tool versions from external tools to rtx' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ -'upgrade:\[experimental\] Upgrades outdated tool versions' \ +'upgrade:Upgrades outdated tool versions' \ 'use:Change the active version of a tool locally or globally.' \ 'u:Change the active version of a tool locally or globally.' \ 'version:Show rtx version' \ @@ -2512,7 +2512,7 @@ _rtx__help_commands() { 'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ 'ls:List installed and/or currently selected tool versions' \ 'ls-remote:List runtime versions available for install' \ -'outdated:\[experimental\] Shows outdated tool versions' \ +'outdated:Shows outdated tool versions' \ 'plugins:Manage plugins' \ 'prune:Delete unused versions of tools' \ 'reshim:rebuilds the shim farm' \ @@ -2522,7 +2522,7 @@ _rtx__help_commands() { 'sync:Add tool versions from external tools to rtx' \ 'trust:Marks a config file as trusted' \ 'uninstall:Removes runtime versions' \ -'upgrade:\[experimental\] Upgrades outdated tool versions' \ +'upgrade:Upgrades outdated tool versions' \ 'use:Change the active version of a tool locally or globally.' \ 'version:Show rtx version' \ 'where:Display the installation path for a runtime' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index 2324ebc26..e0876c91f 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -32,7 +32,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "link" -d 'Symlinks a tool vers complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed and/or currently selected tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_use_subcommand" -f -a "outdated" -d '[experimental] Shows outdated tool versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "outdated" -d 'Shows outdated tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d 'rebuilds the shim farm' @@ -42,7 +42,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version complete -c rtx -n "__fish_use_subcommand" -f -a "sync" -d 'Add tool versions from external tools to rtx' complete -c rtx -n "__fish_use_subcommand" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' +complete -c rtx -n "__fish_use_subcommand" -f -a "upgrade" -d 'Upgrades outdated tool versions' complete -c rtx -n "__fish_use_subcommand" -f -a "use" -d 'Change the active version of a tool locally or globally.' complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' @@ -850,7 +850,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d '[experimental] Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' @@ -860,7 +860,7 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d '[experimental] Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 3098d0d9d..0cc0c0ccb 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -95,7 +95,7 @@ rtx\-ls\-remote(1) List runtime versions available for install .TP rtx\-outdated(1) -[experimental] Shows outdated tool versions +Shows outdated tool versions .TP rtx\-plugins(1) Manage plugins @@ -122,7 +122,7 @@ rtx\-uninstall(1) Removes runtime versions .TP rtx\-upgrade(1) -[experimental] Upgrades outdated tool versions +Upgrades outdated tool versions .TP rtx\-use(1) Change the active version of a tool locally or globally. diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 78fd45b06..ebbe36b4b 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -11,7 +11,7 @@ use crate::output::Output; use crate::tool::Tool; use crate::toolset::{ToolVersion, ToolsetBuilder}; -/// [experimental] Shows outdated tool versions +/// Shows outdated tool versions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Outdated { @@ -24,11 +24,6 @@ pub struct Outdated { impl Command for Outdated { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - if !config.settings.experimental { - return Err(color_eyre::eyre::eyre!( - "This command is experimental. Enable it with `rtx settings set experimental true`" - )); - } let mut ts = ToolsetBuilder::new() .with_args(&self.tool) .build(&mut config)?; diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 9a7e5b896..802783202 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -17,7 +17,7 @@ use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::ProgressReport; -/// [experimental] Upgrades outdated tool versions +/// Upgrades outdated tool versions #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment)] pub struct Upgrade { @@ -30,11 +30,6 @@ pub struct Upgrade { impl Command for Upgrade { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - if !config.settings.experimental { - return Err(color_eyre::eyre::eyre!( - "This command is experimental. Enable it with `rtx settings set experimental true`" - )); - } let mut ts = ToolsetBuilder::new() .with_args(&self.tool) .build(&mut config)?; From 36ec52495559099d5099b0b52ba8889e8a7821ae Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 20 Oct 2023 17:03:07 -0500 Subject: [PATCH 1057/1891] chore: Release --- Cargo.lock | 72 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +-- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb3c3314c..332174b25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,9 +137,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -360,9 +360,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" dependencies = [ "libc", ] @@ -764,7 +764,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "libc", "libgit2-sys", "log", @@ -822,9 +822,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" @@ -895,7 +895,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -931,16 +931,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -1002,7 +1002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.2", "serde", ] @@ -1212,7 +1212,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "libc", ] @@ -1282,7 +1282,7 @@ version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -1565,9 +1565,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaac441002f822bc9705a681810a4dd2963094b9ca0ddc41cb963a4c189189ea" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -1577,9 +1577,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5011c7e263a695dc8ca064cddb722af1be54e517a280b12a5356f98366899e5d" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -1683,7 +1683,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.10.2" +version = "2023.10.3" dependencies = [ "base64", "built", @@ -1747,11 +1747,11 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno 0.3.5", "libc", "linux-raw-sys", @@ -2022,9 +2022,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -2032,9 +2032,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", @@ -2156,18 +2156,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", @@ -2242,7 +2242,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.4", + "socket2 0.5.5", "windows-sys 0.48.0", ] @@ -2322,9 +2322,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", @@ -2658,10 +2658,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ "windows-targets 0.48.5", ] diff --git a/Cargo.toml b/Cargo.toml index e98d70fda..c4c5f0a0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.10.2" +version = "2023.10.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index fd9202787..df1643962 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.10.2 +rtx 2023.10.3 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.10.2/rtx-v2023.10.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.10.3/rtx-v2023.10.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index b04977823..6f36e4ed7 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.10.2"; + version = "2023.10.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 0cc0c0ccb..74bb96b87 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.10.2" +.TH rtx 1 "rtx 2023.10.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.10.2 +v2023.10.3 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b88d5dea9..075981456 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.10.2 +Version: 2023.10.3 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 5162f78fe96961f467caa1dd0862af98d55bbb0d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 27 Oct 2023 22:02:47 -0500 Subject: [PATCH 1058/1891] added node 20 as lts (#946) --- .../snapshots/rtx__cli__alias__set__tests__alias_set.snap | 3 ++- .../snapshots/rtx__cli__alias__unset__tests__alias_unset.snap | 3 ++- src/plugins/core/node.rs | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 1d9e3ed87..4acb1387a 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -3,7 +3,7 @@ source: src/cli/alias/set.rs expression: output --- java lts 21 -node lts 18 +node lts 20 node lts-argon 4 node lts-boron 6 node lts-carbon 8 @@ -12,6 +12,7 @@ node lts-erbium 12 node lts-fermium 14 node lts-gallium 16 node lts-hydrogen 18 +node lts-iron 20 tiny lts 3.1.0 tiny lts-prev 2.0.0 tiny my/alias 3.0 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index d9f77f628..96a73620d 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -3,7 +3,7 @@ source: src/cli/alias/unset.rs expression: output --- java lts 21 -node lts 18 +node lts 20 node lts-argon 4 node lts-boron 6 node lts-carbon 8 @@ -12,6 +12,7 @@ node lts-erbium 12 node lts-fermium 14 node lts-gallium 16 node lts-hydrogen 18 +node lts-iron 20 tiny lts 3.1.0 tiny lts-prev 2.0.0 diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 56a73944e..be84a11bf 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -187,6 +187,7 @@ impl Plugin for NodePlugin { ("lts/fermium", "14"), ("lts/gallium", "16"), ("lts/hydrogen", "18"), + ("lts/iron", "20"), ("lts-argon", "4"), ("lts-boron", "6"), ("lts-carbon", "8"), @@ -195,7 +196,8 @@ impl Plugin for NodePlugin { ("lts-fermium", "14"), ("lts-gallium", "16"), ("lts-hydrogen", "18"), - ("lts", "18"), + ("lts-iron", "20"), + ("lts", "20"), ] .into_iter() .map(|(k, v)| (k.to_string(), v.to_string())) From 76a790246849dc56e5b1c33d97bd962450bfbdd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 01:32:24 -0500 Subject: [PATCH 1059/1891] chore(deps): bump clap_mangen from 0.2.14 to 0.2.15 (#969) Bumps [clap_mangen](https://github.com/clap-rs/clap) from 0.2.14 to 0.2.15. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.14...clap_mangen-v0.2.15) --- updated-dependencies: - dependency-name: clap_mangen dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- xtask/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 332174b25..89cc493be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -267,9 +267,9 @@ checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "clap_mangen" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b44f35c514163027542f7147797ff930523eea288e03642727348ef1a9666f6b" +checksum = "d3be86020147691e1d2ef58f75346a3d4d94807bfc473e377d52f09f0f7d77f7" dependencies = [ "clap", "roff", diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 53e7b6281..44c941e51 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap_mangen = "0.2.14" +clap_mangen = "0.2.15" color-eyre = "0.6.2" rtx-cli = {path = ".."} From cc628c83ee0d5aa1c953021468a61e96dd121a1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 01:32:39 -0500 Subject: [PATCH 1060/1891] chore(deps): bump clap from 4.4.6 to 4.4.7 (#968) Bumps [clap](https://github.com/clap-rs/clap) from 4.4.6 to 4.4.7. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.4.6...v4.4.7) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89cc493be..992c8ed68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -228,9 +228,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", @@ -249,9 +249,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -261,9 +261,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clap_mangen" From a997baa78b76c843df973e3c61a25901cf166032 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 01:32:49 -0500 Subject: [PATCH 1061/1891] chore(deps): bump serde from 1.0.189 to 1.0.190 (#967) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.189 to 1.0.190. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.189...v1.0.190) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 992c8ed68..f9fe90d3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1902,18 +1902,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", From e4df4e790576bbe65229a8a327f28fc30439acf4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 01:33:01 -0500 Subject: [PATCH 1062/1891] chore(deps): bump base64 from 0.21.4 to 0.21.5 (#966) Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.21.4 to 0.21.5. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.21.4...v0.21.5) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9fe90d3f..ef82ec759 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" From 4fe00b2aefc2e3912fda7f0c018ea89b27657500 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 01:33:13 -0500 Subject: [PATCH 1063/1891] chore(deps): bump toml from 0.8.2 to 0.8.6 (#965) Bumps [toml](https://github.com/toml-rs/toml) from 0.8.2 to 0.8.6. - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.2...toml-v0.8.6) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef82ec759..ec2119490 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1933,9 +1933,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -2282,9 +2282,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" dependencies = [ "serde", "serde_spanned", @@ -2294,18 +2294,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ "indexmap 2.0.2", "serde", From afee410627deeb10b374d9971bf3ba4abc45d614 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 01:33:23 -0500 Subject: [PATCH 1064/1891] chore(deps): bump actions/setup-node from 3 to 4 (#964) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rtx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 24cc08c99..69fc24e25 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -239,7 +239,7 @@ jobs: mkdir -p "$HOME/.local/bin" ln -s $(which fdfind) "$HOME/.local/bin/fd" echo "$HOME/.local/bin" >> $GITHUB_PATH - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: "20.x" registry-url: "https://registry.npmjs.org" From c73483213feb85e11f61c6ea958d5cec7d7c24cd Mon Sep 17 00:00:00 2001 From: Jakob Guddas Date: Fri, 3 Nov 2023 00:01:56 +0100 Subject: [PATCH 1065/1891] feat(zsh): added support for custom $ZDOTDIR (#963) --- packaging/standalone/install.envsubst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index a91a195b3..1b2e699b9 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -138,7 +138,7 @@ after_finish_help() { case "${SHELL:-}" in */zsh) info "rtx: run the following to activate rtx in your shell:" - info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> ~/.zshrc" + info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> \"${ZDOTDIR-~}/.zshrc\"" info "" info "rtx: this must be run in order to use rtx in the terminal" info "rtx: run \`rtx doctor\` to verify this is setup correctly" From 5911c7b4458417f5c5af3d68333306bcd26c4a58 Mon Sep 17 00:00:00 2001 From: Patrick Aikens Date: Thu, 2 Nov 2023 19:02:34 -0400 Subject: [PATCH 1066/1891] fix(build): Fix Darwin build (#959) --- default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.nix b/default.nix index 6f36e4ed7..0db21a124 100644 --- a/default.nix +++ b/default.nix @@ -23,7 +23,7 @@ rustPlatform.buildRustPackage { gnused git gawk - ] ++ lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.Security; + ] ++ lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.Security darwin.apple_sdk.frameworks.SystemConfiguration ]; prePatch = '' substituteInPlace ./test/data/plugins/**/bin/* \ From d966a7d50d03602e567850898bf260b00acdb948 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:23:05 -0500 Subject: [PATCH 1067/1891] added dependency instructions --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca48ecdc8..2ae2d6863 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,6 +18,9 @@ To use the container with VSCode, you'll need to install the [Remote - Container * [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that). As of this writing: 1.67.0 but GH actions will use the latest stable whenever it runs. * [just](https://github.com/casey/just) any version should do, but as of this writing I'm on 1.13.0 +* [md-magic](https://github.com/DavidWells/markdown-magic) +* [shfmt](https://github.com/mvdan/sh) +* [shellcheck](https://www.shellcheck.net/) (you'd think we'd use rtx to fetch these but frankly it's kind of a pain to dogfood rtx while testing it) @@ -73,6 +76,10 @@ You don't have to do this, but it makes things like `rtx activate` a lot easier * Run only E2E tests: `just test-e2e` * Run all tests: `just test` +## Releasing + +Run `just release -x [minor|patch]`. (minor if it is the first release in a month) + ## Linting * Lint codebase: `just lint` From 2796c45aaa9fcdc9bc1b55264bd06762a450d6c5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:24:22 -0500 Subject: [PATCH 1068/1891] chore: Release --- Cargo.lock | 186 ++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 98 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec2119490..f598a4f02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,9 +240,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.3" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ae8ba90b9d8b007efe66e55e48fb936272f5ca00349b5b0e89877520d35ea7" +checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" dependencies = [ "clap", ] @@ -360,9 +360,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -673,57 +673,45 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", "futures-io", - "futures-macro", "futures-task", "memchr", "pin-project-lite", @@ -904,9 +892,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", @@ -997,9 +985,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", @@ -1050,9 +1038,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" @@ -1080,9 +1068,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -1179,9 +1167,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi", @@ -1278,9 +1266,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "a9dfc0783362704e97ef3bd24261995a699468440099ef95d869b4d9732f829a" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1310,9 +1298,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "2f55da20b29f956fb01f0add8683eb26ee13ebe3ebd935e49898717c6b4b2830" dependencies = [ "cc", "libc", @@ -1368,9 +1356,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", @@ -1379,9 +1367,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -1389,9 +1377,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", @@ -1402,9 +1390,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -1431,9 +1419,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "1.4.3" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" +checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" [[package]] name = "powerfmt" @@ -1552,6 +1540,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -1640,17 +1637,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", + "getrandom", "libc", - "once_cell", "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1683,7 +1679,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.10.3" +version = "2023.11.0" dependencies = [ "base64", "built", @@ -1705,7 +1701,7 @@ dependencies = [ "fslock", "humantime", "indenter", - "indexmap 2.0.2", + "indexmap 2.1.0", "indicatif", "indoc", "insta", @@ -1747,9 +1743,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.20" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.1", "errno 0.3.5", @@ -1760,9 +1756,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring", @@ -1793,9 +1789,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", @@ -1833,9 +1829,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -1922,9 +1918,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -2042,9 +2038,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strsim" @@ -2108,13 +2104,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "rustix", "windows-sys 0.48.0", ] @@ -2268,9 +2264,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2307,7 +2303,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -2464,9 +2460,9 @@ checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" @@ -2546,9 +2542,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2556,9 +2552,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", @@ -2571,9 +2567,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -2583,9 +2579,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2593,9 +2589,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", @@ -2606,15 +2602,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -2800,9 +2796,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index c4c5f0a0d..485e00e82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.10.3" +version = "2023.11.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index df1643962..e9f8680eb 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.10.3 +rtx 2023.11.0 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.10.3/rtx-v2023.10.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.0/rtx-v2023.11.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 0db21a124..a8a30b641 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.10.3"; + version = "2023.11.0"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 74bb96b87..52aa824d0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.10.3" +.TH rtx 1 "rtx 2023.11.0" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.10.3 +v2023.11.0 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 075981456..05e73048f 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.10.3 +Version: 2023.11.0 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 57a7cd225dea3cd8e4dc67bdf8475f8907e7cb70 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:15:20 -0500 Subject: [PATCH 1069/1891] test: updated ruby version in e2e tests --- e2e/ruby/test_ruby | 4 ++-- e2e/ruby/test_ruby_install | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby index 368038d82..7408fbcc8 100755 --- a/e2e/ruby/test_ruby +++ b/e2e/ruby/test_ruby @@ -10,13 +10,13 @@ export RTX_RUBY_VERBOSE_INSTALL=1 cat >Gemfile < .ruby-version +echo "ruby-3.2.1" > .ruby-version # disable this slow test for now #rtx i ruby -#assert_contains "rtx x -- ruby --version" "ruby 3.1.4" +#assert_contains "rtx x -- ruby --version" "ruby 3.2.1" rm .ruby-version From 5228fcfef912f2abcde0a7acf8a63256eacdc8a6 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:17:02 -0500 Subject: [PATCH 1070/1891] plugin-uninstall: added --purge flag (#975) --- README.md | 10 +++++--- completions/_rtx | 2 ++ completions/rtx.bash | 2 +- completions/rtx.fish | 1 + e2e/test_purge | 15 ++++++++++++ src/cli/plugins/install.rs | 15 ++++++------ src/cli/plugins/ls.rs | 2 +- src/cli/plugins/uninstall.rs | 7 ++++++ src/config/mod.rs | 2 +- src/plugins/external_plugin.rs | 18 +++++++-------- src/plugins/mod.rs | 5 ++-- src/runtime_symlinks.rs | 2 +- src/tool.rs | 39 +++++++++++++++++++++++++------- src/toolset/tool_version_list.rs | 4 ++-- 14 files changed, 87 insertions(+), 37 deletions(-) create mode 100755 e2e/test_purge diff --git a/README.md b/README.md index e9f8680eb..f6ab68bcb 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ v20.0.0 - [`rtx plugins link [OPTIONS] [PATH]`](#rtx-plugins-link-options-name-path) - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) - [`rtx plugins ls-remote [OPTIONS]`](#rtx-plugins-ls-remote-options) - - [`rtx plugins uninstall ...`](#rtx-plugins-uninstall-plugin) + - [`rtx plugins uninstall [OPTIONS] ...`](#rtx-plugins-uninstall-options-plugin) - [`rtx plugins update [PLUGIN]...`](#rtx-plugins-update-plugin) - [`rtx prune [OPTIONS] [PLUGINS]...`](#rtx-prune-options-plugins) - [`rtx reshim`](#rtx-reshim) @@ -2192,17 +2192,21 @@ Options: --only-names Only show the name of each plugin by default it will show a "*" next to installed plugins ``` -### `rtx plugins uninstall ...` +### `rtx plugins uninstall [OPTIONS] ...` ``` Removes a plugin -Usage: plugins uninstall ... +Usage: plugins uninstall [OPTIONS] ... Arguments: ... Plugin(s) to remove +Options: + -p, --purge + Also remove the plugin's installs, downloads, and cache + Examples: $ rtx uninstall node ``` diff --git a/completions/_rtx b/completions/_rtx index 6f20828d5..508bc24c9 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1119,6 +1119,8 @@ _arguments "${_arguments_options[@]}" \ '--jobs=[Number of plugins and runtimes to install in parallel \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-p[Also remove the plugin'\''s installs, downloads, and cache]' \ +'--purge[Also remove the plugin'\''s installs, downloads, and cache]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index 4dd096350..f009f975c 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2745,7 +2745,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." + opts="-p -j -r -y -v -h --purge --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index e0876c91f..70302a00b 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -546,6 +546,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s p -l purge -d 'Also remove the plugin\'s installs, downloads, and cache' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/e2e/test_purge b/e2e/test_purge new file mode 100755 index 000000000..6d8ff14de --- /dev/null +++ b/e2e/test_purge @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/assert.sh" + +rtx install tiny +assert_contains "rtx ls --installed" "tiny" + +rtx plugin uninstall tiny +assert_contains "rtx ls --installed" "tiny" + +rtx plugin install tiny +assert_contains "rtx ls --installed" "tiny" + +rtx plugin uninstall tiny --purge +assert_not_contains "rtx ls --installed" "tiny" diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index eb7f25e23..61560dcb7 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -55,14 +55,14 @@ impl Command for PluginsInstall { } let (name, git_url) = get_name_and_url(&self.name.clone().unwrap(), &self.git_url)?; if git_url.is_some() { - self.install_one(&mut config, &name, git_url, &mpr)?; + self.install_one(&mut config, name, git_url, &mpr)?; } else { let mut plugins: Vec = vec![name]; if let Some(second) = self.git_url.clone() { plugins.push(second); }; plugins.extend(self.rest.clone()); - self.install_many(config, &plugins, mpr)?; + self.install_many(config, plugins, mpr)?; } Ok(()) @@ -80,14 +80,14 @@ impl PluginsInstall { if missing_plugins.is_empty() { warn!("all plugins already installed"); } - self.install_many(config, &missing_plugins, mpr)?; + self.install_many(config, missing_plugins, mpr)?; Ok(()) } fn install_many( &self, mut config: Config, - plugins: &[PluginName], + plugins: Vec, mpr: MultiProgressReport, ) -> Result<()> { for plugin in plugins { @@ -110,14 +110,15 @@ impl PluginsInstall { fn install_one( &self, config: &mut Config, - name: &String, + name: PluginName, git_url: Option, mpr: &MultiProgressReport, ) -> Result<()> { - let mut plugin = ExternalPlugin::new(name); + let mut plugin = ExternalPlugin::new(name.clone()); plugin.repo_url = git_url; if !self.force && plugin.is_installed() { - mpr.warn(format!("plugin {} already installed", name)); + mpr.warn(format!("Plugin {} already installed", name)); + mpr.warn("Use --force to install anyway".to_string()); } else { let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); tool.ensure_installed(config, Some(mpr), true)?; diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index b56ecffea..9f0c8f975 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -42,7 +42,7 @@ impl Command for PluginsLs { if self.all { for (plugin, url) in config.get_shorthands() { - let mut ep = ExternalPlugin::new(plugin); + let mut ep = ExternalPlugin::new(plugin.clone()); ep.repo_url = Some(url.to_string()); let tool = Tool::new(plugin.clone(), Box::from(ep)); tools.insert(Arc::new(tool)); diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index c82adc5cf..96e01e2f8 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -14,6 +14,10 @@ pub struct PluginsUninstall { /// Plugin(s) to remove #[clap(required = true, verbatim_doc_comment)] pub plugin: Vec, + + /// Also remove the plugin's installs, downloads, and cache + #[clap(long, short, verbatim_doc_comment)] + pub purge: bool, } impl Command for PluginsUninstall { @@ -40,6 +44,9 @@ impl PluginsUninstall { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, None); plugin.uninstall(&pr)?; + if self.purge { + plugin.purge(&pr)?; + } pr.finish_with_message("uninstalled"); } _ => mpr.suspend(|| { diff --git a/src/config/mod.rs b/src/config/mod.rs index e3dcaa328..1addb86b2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -164,7 +164,7 @@ impl Config { self.tools .entry(plugin_name.clone()) .or_insert_with(|| { - let plugin = ExternalPlugin::new(plugin_name); + let plugin = ExternalPlugin::new(plugin_name.clone()); build_tool(plugin_name.clone(), Box::new(plugin)) }) .clone() diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 83a494604..6b1b9755a 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -48,16 +48,15 @@ pub struct ExternalPlugin { } impl ExternalPlugin { - pub fn new(name: &PluginName) -> Self { - let plugin_path = dirs::PLUGINS.join(name); - let cache_path = dirs::CACHE.join(name); + pub fn new(name: PluginName) -> Self { + let plugin_path = dirs::PLUGINS.join(&name); + let cache_path = dirs::CACHE.join(&name); let toml_path = plugin_path.join("rtx.plugin.toml"); let toml = RtxPluginToml::from_file(&toml_path).unwrap(); Self { - name: name.into(), - script_man: build_script_man(name, &plugin_path), - downloads_path: dirs::DOWNLOADS.join(name), - installs_path: dirs::INSTALLS.join(name), + script_man: build_script_man(&name, &plugin_path), + downloads_path: dirs::DOWNLOADS.join(&name), + installs_path: dirs::INSTALLS.join(&name), cache: ExternalPluginCache::default(), remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE) @@ -77,6 +76,7 @@ impl ExternalPlugin { cache_path, repo_url: None, toml, + name, } } @@ -468,8 +468,6 @@ impl Plugin for ExternalPlugin { }) }; - rmdir(&self.downloads_path)?; - rmdir(&self.installs_path)?; rmdir(&self.plugin_path)?; Ok(()) @@ -666,7 +664,7 @@ mod tests { #[test] fn test_debug() { - let plugin = ExternalPlugin::new(&PluginName::from("dummy")); + let plugin = ExternalPlugin::new(PluginName::from("dummy")); assert!(format!("{:?}", plugin).starts_with("ExternalPlugin { name: \"dummy\"")); } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 2e6fa02c3..de31f9494 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -7,7 +7,6 @@ use color_eyre::eyre::Result; use console::style; pub use external_plugin::ExternalPlugin; -pub use rtx_plugin_toml::RtxPluginToml; pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; @@ -151,7 +150,7 @@ mod tests { fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); - let plugin = ExternalPlugin::new(&PluginName::from("tiny")); + let plugin = ExternalPlugin::new(PluginName::from("tiny")); let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); let version = tool .latest_version(&settings, Some("1.0.0".into())) @@ -165,7 +164,7 @@ mod tests { #[test] fn test_latest_stable() { let settings = Settings::default(); - let plugin = ExternalPlugin::new(&PluginName::from("dummy")); + let plugin = ExternalPlugin::new(PluginName::from("dummy")); let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); let version = tool.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index cf5ff651b..c2ec9ad43 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -113,7 +113,7 @@ mod tests { #[test] fn test_list_symlinks() { let config = Config::load().unwrap(); - let plugin = ExternalPlugin::new(&PluginName::from("tiny")); + let plugin = ExternalPlugin::new(PluginName::from("tiny")); let tool = Tool::new(String::from("tiny"), Box::new(plugin)); let symlinks = list_symlinks(&config, &tool).unwrap(); assert_debug_snapshot!(symlinks); diff --git a/src/tool.rs b/src/tool.rs index 3e16e6a37..a1907795c 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -6,14 +6,14 @@ use std::fs::File; use std::path::{Path, PathBuf}; use clap::Command; -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::{eyre, Context, Result}; use console::style; use itertools::Itertools; use regex::Regex; use versions::Versioning; use crate::config::{Config, Settings}; -use crate::file::{display_path, remove_all_with_warning}; +use crate::file::{display_path, remove_all, remove_all_with_warning}; use crate::plugins::{ExternalPlugin, Plugin}; use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest}; @@ -24,15 +24,19 @@ use crate::{dirs, file}; pub struct Tool { pub name: String, pub plugin: Box, - pub installs_path: PathBuf, pub plugin_path: PathBuf, + pub installs_path: PathBuf, + pub cache_path: PathBuf, + pub downloads_path: PathBuf, } impl Tool { pub fn new(name: String, plugin: Box) -> Self { Self { - installs_path: dirs::INSTALLS.join(&name), plugin_path: dirs::PLUGINS.join(&name), + installs_path: dirs::INSTALLS.join(&name), + cache_path: dirs::CACHE.join(&name), + downloads_path: dirs::DOWNLOADS.join(&name), name, plugin, } @@ -40,10 +44,10 @@ impl Tool { pub fn list() -> Result> { Ok(file::dir_subdirs(&dirs::PLUGINS)? - .iter() + .into_iter() .map(|name| { - let plugin = ExternalPlugin::new(name); - Self::new(name.to_string(), Box::new(plugin)) + let plugin = ExternalPlugin::new(name.clone()); + Self::new(name, Box::new(plugin)) }) .collect()) } @@ -284,6 +288,12 @@ impl Tool { pub fn uninstall(&self, pr: &ProgressReport) -> Result<()> { self.plugin.uninstall(pr) } + pub fn purge(&self, pr: &ProgressReport) -> Result<()> { + rmdir(&self.installs_path, pr)?; + rmdir(&self.cache_path, pr)?; + rmdir(&self.downloads_path, pr)?; + Ok(()) + } pub fn external_commands(&self) -> Result> { self.plugin.external_commands() @@ -384,6 +394,19 @@ impl Tool { } } +fn rmdir(dir: &Path, pr: &ProgressReport) -> Result<()> { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", &dir.to_string_lossy())); + remove_all(dir).wrap_err_with(|| { + format!( + "Failed to remove directory {}", + style(&dir.to_string_lossy()).cyan().for_stderr() + ) + }) +} + impl PartialEq for Tool { fn eq(&self, other: &Self) -> bool { self.plugin_path == other.plugin_path @@ -430,7 +453,7 @@ mod tests { #[test] fn test_debug() { - let plugin = ExternalPlugin::new(&PluginName::from("dummy")); + let plugin = ExternalPlugin::new(PluginName::from("dummy")); let tool = Tool::new("dummy".to_string(), Box::new(plugin)); let debug = format!("{:?}", tool); assert!(debug.contains("Tool")); diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index c95e27303..3b11dced7 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -52,7 +52,7 @@ mod tests { fn test_tool_version_list() { let mut config = Config::default(); let plugin_name = "tiny".to_string(); - let plugin = ExternalPlugin::new(&plugin_name); + let plugin = ExternalPlugin::new(plugin_name.clone()); let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); config.tools.insert(plugin_name.clone(), Arc::new(tool)); let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); @@ -70,7 +70,7 @@ mod tests { file::remove_all(dirs::CACHE.join("dummy")).unwrap(); let mut config = Config::default(); let plugin_name = "dummy".to_string(); - let plugin = ExternalPlugin::new(&plugin_name); + let plugin = ExternalPlugin::new(plugin_name.clone()); let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); config.tools.insert(plugin_name.clone(), Arc::new(tool)); let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); From 6ed81d269bc02380ab6bf4b111873b6e5c786824 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 01:16:03 +0000 Subject: [PATCH 1071/1891] chore(deps): bump openssl from 0.10.58 to 0.10.59 Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.58 to 0.10.59. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.58...openssl-v0.10.59) --- updated-dependencies: - dependency-name: openssl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f598a4f02..f2ab03a33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1266,9 +1266,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.58" +version = "0.10.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dfc0783362704e97ef3bd24261995a699468440099ef95d869b4d9732f829a" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1298,9 +1298,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.94" +version = "0.9.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f55da20b29f956fb01f0add8683eb26ee13ebe3ebd935e49898717c6b4b2830" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ "cc", "libc", From f7598e658aac82d1194da3171d78199de9bac5b4 Mon Sep 17 00:00:00 2001 From: Noah Betzen Date: Sun, 5 Nov 2023 21:12:37 -0800 Subject: [PATCH 1072/1891] fix(nushell): Use extern-wrapped instead of def-env Should fix https://github.com/jdx/rtx/issues/514 Requires nushell 0.86, which released three weeks ago: https://www.nushell.sh/blog/2023-10-17-nushell_0_86.html#unified-command-definitions --- src/shell/nushell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index f43ddf3c7..86c22629a 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -60,7 +60,7 @@ impl Shell for Nushell { $in | lines | parse "{{op}},{{name}},{{value}}" }} - def-env rtx [command?: string, --help, ...rest: string] {{ + extern-wrapped rtx [command?: string, --help, ...rest: string] {{ let commands = ["shell", "deactivate"] if ($command == null) {{ From 26e12048d40308e011182db053acc603b4adb5b9 Mon Sep 17 00:00:00 2001 From: Noah Betzen Date: Sun, 5 Nov 2023 21:16:52 -0800 Subject: [PATCH 1073/1891] Update nushell.rs --- src/shell/nushell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 86c22629a..f753bb679 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -60,7 +60,7 @@ impl Shell for Nushell { $in | lines | parse "{{op}},{{name}},{{value}}" }} - extern-wrapped rtx [command?: string, --help, ...rest: string] {{ + def --wrapped rtx [command?: string, --help, ...rest: string] {{ let commands = ["shell", "deactivate"] if ($command == null) {{ From d563fd2156481054e7c9e2b8a5f3ca2c0fc2defb Mon Sep 17 00:00:00 2001 From: Noah Betzen Date: Mon, 6 Nov 2023 10:45:24 -0800 Subject: [PATCH 1074/1891] Fix #960 `let-env` was removed in Nushell 0.83.0: https://www.nushell.sh/blog/2023-07-25-nushell_0_83.html#breaking-changes See https://github.com/jdx/rtx/issues/960 for more details --- src/shell/nushell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index f753bb679..a71243018 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -66,7 +66,7 @@ impl Shell for Nushell { if ($command == null) {{ ^"{exe}" }} else if ($command == "activate") {{ - let-env RTX_SHELL = "nu" + $env.RTX_SHELL = "nu" }} else if ($command in $commands) {{ ^"{exe}" $command $rest | parse vars From 2b385af5083eb6fc683bcf12e95ce3f04975f06e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:20:36 -0600 Subject: [PATCH 1075/1891] fixed snapshots --- .../snapshots/rtx__shell__nushell__tests__hook_init.snap | 4 ++-- .../snapshots/rtx__shell__nushell__tests__hook_init_nix.snap | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap index 435bf2e85..5f3ea9387 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap @@ -26,13 +26,13 @@ def "parse vars" [] { $in | lines | parse "{op},{name},{value}" } -def-env rtx [command?: string, --help, ...rest: string] { +def --wrapped rtx [command?: string, --help, ...rest: string] { let commands = ["shell", "deactivate"] if ($command == null) { ^"/some/dir/rtx" } else if ($command == "activate") { - let-env RTX_SHELL = "nu" + $env.RTX_SHELL = "nu" } else if ($command in $commands) { ^"/some/dir/rtx" $command $rest | parse vars diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap index 2e59ba9e1..8447c2c9b 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap @@ -25,13 +25,13 @@ def "parse vars" [] { $in | lines | parse "{op},{name},{value}" } -def-env rtx [command?: string, --help, ...rest: string] { +def --wrapped rtx [command?: string, --help, ...rest: string] { let commands = ["shell", "deactivate"] if ($command == null) { ^"/nix/store/rtx" } else if ($command == "activate") { - let-env RTX_SHELL = "nu" + $env.RTX_SHELL = "nu" } else if ($command in $commands) { ^"/nix/store/rtx" $command $rest | parse vars From 231e1d05ff7a75c8cb46b0cfe96425f80a0d0797 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:45:16 -0600 Subject: [PATCH 1076/1891] chore: Release --- Cargo.lock | 89 ++++++++++++++++++++++++------------------ Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 58 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2ab03a33..10e2dcc03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,7 +256,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -426,7 +426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" dependencies = [ "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -556,9 +556,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" dependencies = [ "libc", "windows-sys 0.48.0", @@ -1083,9 +1083,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libgit2-sys" @@ -1099,6 +1099,17 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "libz-sys" version = "1.1.12" @@ -1287,7 +1298,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1385,7 +1396,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1522,15 +1533,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -1551,12 +1553,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -1679,7 +1681,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.0" +version = "2023.11.1" dependencies = [ "base64", "built", @@ -1730,7 +1732,7 @@ dependencies = [ "terminal_size", "thiserror", "toml", - "toml_edit", + "toml_edit 0.20.7", "url", "versions", ] @@ -1748,7 +1750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.1", - "errno 0.3.5", + "errno 0.3.6", "libc", "linux-raw-sys", "windows-sys 0.48.0", @@ -1898,22 +1900,22 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.190" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2061,9 +2063,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -2167,7 +2169,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2278,14 +2280,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.21.0", ] [[package]] @@ -2302,6 +2304,17 @@ name = "toml_edit" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap 2.1.0", "serde", @@ -2561,7 +2574,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] @@ -2595,7 +2608,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2796,9 +2809,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.18" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 485e00e82..e561025d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.0" +version = "2023.11.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index f6ab68bcb..cc92d0249 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.0 +rtx 2023.11.1 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.0/rtx-v2023.11.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.1/rtx-v2023.11.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index a8a30b641..7d3fa19b7 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.0"; + version = "2023.11.1"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 52aa824d0..1f4166502 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.0" +.TH rtx 1 "rtx 2023.11.1" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.0 +v2023.11.1 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 05e73048f..3eac30d1c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.0 +Version: 2023.11.1 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 8ec558afc60c74b7fef2a3967ccbcf36b4ed0518 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:14:48 -0600 Subject: [PATCH 1077/1891] shell: fixed -h,--help flag (#976) --- src/cli/shell.rs | 2 +- src/shell/bash.rs | 12 +++++++----- src/shell/fish.rs | 16 ++++++++++++++-- .../rtx__shell__bash__tests__hook_init.snap | 12 +++++++----- .../rtx__shell__bash__tests__hook_init_nix.snap | 12 +++++++----- .../rtx__shell__fish__tests__hook_init.snap | 16 ++++++++++++++-- .../rtx__shell__fish__tests__hook_init_nix.snap | 16 ++++++++++++++-- .../rtx__shell__zsh__tests__hook_init.snap | 12 +++++++----- .../rtx__shell__zsh__tests__hook_init_nix.snap | 12 +++++++----- src/shell/zsh.rs | 12 +++++++----- 10 files changed, 85 insertions(+), 37 deletions(-) diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 763190cda..2738390ea 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -13,7 +13,7 @@ use crate::toolset::{ToolSource, ToolsetBuilder}; /// /// Only works in a session where rtx is already activated. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, alias = "s", after_long_help = AFTER_LONG_HELP)] pub struct Shell { /// Tool(s) to use #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 977f378c0..db3c5dbe2 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -28,13 +28,15 @@ impl Shell for Bash { shift case "$command" in - deactivate|shell) - eval "$(command rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" + deactivate|s|shell) + # if argv doesn't contains -h,--help + if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then + eval "$(command rtx "$command" "$@")" + return $? + fi ;; esac + command rtx "$command" "$@" }} _rtx_hook() {{ diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 61db98f65..9af41a919 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -32,9 +32,21 @@ impl Shell for Fish { set command $argv[1] set -e argv[1] + if contains -- --help $argv + command rtx "$command" $argv + return $status + end + switch "$command" - case deactivate shell - source (command rtx "$command" $argv|psub) + case deactivate s shell + # if help is requested, don't eval + if contains -- -h $argv + command rtx "$command" $argv + else if contains -- --help $argv + command rtx "$command" $argv + else + source (command rtx "$command" $argv |psub) + end case '*' command rtx "$command" $argv end diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index cdd1d50f6..cdd27d924 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -15,13 +15,15 @@ rtx() { shift case "$command" in - deactivate|shell) - eval "$(command rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" + deactivate|s|shell) + # if argv doesn't contains -h,--help + if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then + eval "$(command rtx "$command" "$@")" + return $? + fi ;; esac + command rtx "$command" "$@" } _rtx_hook() { diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index 790a2a9cb..9e555f3cd 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -14,13 +14,15 @@ rtx() { shift case "$command" in - deactivate|shell) - eval "$(command rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" + deactivate|s|shell) + # if argv doesn't contains -h,--help + if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then + eval "$(command rtx "$command" "$@")" + return $? + fi ;; esac + command rtx "$command" "$@" } _rtx_hook() { diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 206d3b33e..a9dfcd5be 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -14,9 +14,21 @@ function rtx set command $argv[1] set -e argv[1] + if contains -- --help $argv + command rtx "$command" $argv + return $status + end + switch "$command" - case deactivate shell - source (command rtx "$command" $argv|psub) + case deactivate s shell + # if help is requested, don't eval + if contains -- -h $argv + command rtx "$command" $argv + else if contains -- --help $argv + command rtx "$command" $argv + else + source (command rtx "$command" $argv |psub) + end case '*' command rtx "$command" $argv end diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap index 82f674438..4a02b4967 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap @@ -13,9 +13,21 @@ function rtx set command $argv[1] set -e argv[1] + if contains -- --help $argv + command rtx "$command" $argv + return $status + end + switch "$command" - case deactivate shell - source (command rtx "$command" $argv|psub) + case deactivate s shell + # if help is requested, don't eval + if contains -- -h $argv + command rtx "$command" $argv + else if contains -- --help $argv + command rtx "$command" $argv + else + source (command rtx "$command" $argv |psub) + end case '*' command rtx "$command" $argv end diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 7f0b514a3..c6ebdde60 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -15,13 +15,15 @@ rtx() { shift case "$command" in - deactivate|shell) - eval "$(command rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" + deactivate|s|shell) + # if argv doesn't contains -h,--help + if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then + eval "$(command rtx "$command" "$@")" + return $? + fi ;; esac + command rtx "$command" "$@" } _rtx_hook() { diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap index 891bf6245..f1218f4b4 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -14,13 +14,15 @@ rtx() { shift case "$command" in - deactivate|shell) - eval "$(command rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" + deactivate|s|shell) + # if argv doesn't contains -h,--help + if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then + eval "$(command rtx "$command" "$@")" + return $? + fi ;; esac + command rtx "$command" "$@" } _rtx_hook() { diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 163558499..d60018756 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -32,13 +32,15 @@ impl Shell for Zsh { shift case "$command" in - deactivate|shell) - eval "$(command rtx "$command" "$@")" - ;; - *) - command rtx "$command" "$@" + deactivate|s|shell) + # if argv doesn't contains -h,--help + if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then + eval "$(command rtx "$command" "$@")" + return $? + fi ;; esac + command rtx "$command" "$@" }} _rtx_hook() {{ From ff93ba283191bd42a121645fd37e54993fa8a92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Thu, 9 Nov 2023 02:22:37 +0200 Subject: [PATCH 1078/1891] docs: fix local.toml gitignore recipe (#984) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc92d0249..3b6595265 100644 --- a/README.md +++ b/README.md @@ -1063,7 +1063,7 @@ environments like `development` and `production`. To enable, set rtx will also look for "local" files like `.rtx.local.toml` and `.rtx.{RTX_ENV}.local.toml` in the current directory. These are intended to not be committed to version control. -(Add `rtx.*.local.toml` to your `.gitignore` file.) +(Add `.rtx.local.toml` and `.rtx.*.local.toml` to your `.gitignore` file.) The priority of these files goes in this order (bottom overrides top): From 9aaecba725b8607e7a903ae65eb01614d5543135 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:06:09 -0600 Subject: [PATCH 1079/1891] implode|prune: support --yes (#986) Fixes #982 --- src/cli/implode.rs | 25 +++++++++++++++++++------ src/cli/prune.rs | 2 +- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 4c114c393..c5cfe917b 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Result; +use std::path::Path; use crate::cli::command::Command; use crate::config::Config; @@ -23,7 +24,7 @@ pub struct Implode { } impl Command for Implode { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { let mut files = vec![&*dirs::ROOT, &*dirs::CACHE, &*env::RTX_EXE]; if self.config { files.push(&*dirs::CONFIG); @@ -33,13 +34,12 @@ impl Command for Implode { rtxprintln!(out, "rm -rf {}", f.display()); } - if f.is_dir() { - if !self.dry_run && prompt::confirm(&format!("remove {} ?", f.display()))? { + if self.confirm_remove(&config, f)? { + if f.is_dir() { remove_all(f)?; - return Ok(()); + } else { + file::remove_file(f)?; } - } else if !self.dry_run && prompt::confirm(&format!("remove {} ?", f.display()))? { - file::remove_file(f)?; } } @@ -47,6 +47,19 @@ impl Command for Implode { } } +impl Implode { + fn confirm_remove(&self, config: &Config, f: &Path) -> Result { + if self.dry_run { + Ok(false) + } else if config.settings.yes { + Ok(true) + } else { + let r = prompt::confirm(&format!("remove {} ?", f.display()))?; + Ok(r) + } + } +} + #[cfg(test)] #[cfg(test)] mod tests { diff --git a/src/cli/prune.rs b/src/cli/prune.rs index da97403cb..386fe6d4e 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -64,7 +64,7 @@ impl Prune { if self.dry_run { pr.set_prefix(format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); } - if prompt::confirm(&format!("remove {} ?", &tv))? { + if config.settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? { p.decorate_progress_bar(&mut pr, Some(&tv)); p.uninstall_version(config, &tv, &pr, self.dry_run)?; pr.finish(); From d3603325ff8cdeb17520fe19605a6aa7d58fcd89 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:25:38 -0600 Subject: [PATCH 1080/1891] zipsign (#985) --- .gitattributes | 1 + .github/workflows/rtx.yml | 6 ++ Cargo.lock | 149 +++++++++++++++++++++++++++++++++++++- Cargo.toml | 16 +++- deny.toml | 10 ++- scripts/build-tarball.sh | 5 ++ scripts/setup-zipsign.sh | 11 +++ src/cli/self_update.rs | 18 ++++- zipsign.pub | 1 + 9 files changed, 209 insertions(+), 8 deletions(-) create mode 100644 .gitattributes create mode 100755 scripts/setup-zipsign.sh create mode 100644 zipsign.pub diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..f7872486b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +zipsign.pub binary diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 69fc24e25..8f3d0baa4 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -94,6 +94,9 @@ jobs: shared-key: "build-linux-${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cross + - run: scripts/setup-zipsign.sh + env: + ZIPSIGN: ${{ secrets.ZIPSIGN }} - run: scripts/build-tarball.sh rtx --release --features openssl/vendored,self_update --target ${{matrix.target}} env: CROSS: "1" @@ -126,6 +129,9 @@ jobs: with: key: "${{matrix.target}}" save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + - run: scripts/setup-zipsign.sh + env: + ZIPSIGN: ${{ secrets.ZIPSIGN }} - run: scripts/build-tarball.sh rtx --release --features openssl/vendored,self_update --target ${{matrix.target}} - run: scripts/build-tarball.sh rtx-nonup --release --features openssl/vendored --target ${{matrix.target}} - uses: actions/upload-artifact@v3 diff --git a/Cargo.lock b/Cargo.lock index 10e2dcc03..9aef3b24e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,6 +129,12 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -342,6 +348,12 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "core-foundation" version = "0.9.3" @@ -439,6 +451,44 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.9" @@ -516,6 +566,30 @@ dependencies = [ "shared_child", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "signature", + "zeroize", +] + [[package]] name = "either" version = "1.9.0" @@ -609,6 +683,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fiat-crypto" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" + [[package]] name = "filetime" version = "0.2.22" @@ -1422,12 +1502,28 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + [[package]] name = "portable-atomic" version = "1.5.1" @@ -1743,6 +1839,15 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.21" @@ -1875,10 +1980,12 @@ dependencies = [ [[package]] name = "self_update" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b3c585a1ced6b97ac13bd5e56f66559e5a75f477da5913f70df98e114518446" +checksum = "1a34ad8e4a86884ab42e9b8690e9343abdcfe5fa38a0318cfe1565ba9ad437b4" dependencies = [ + "either", + "flate2", "hyper", "indicatif", "log", @@ -1888,8 +1995,10 @@ dependencies = [ "self-replace", "semver", "serde_json", + "tar", "tempfile", "urlencoding", + "zipsign-api", ] [[package]] @@ -1992,6 +2101,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "signature" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest", +] + [[package]] name = "similar" version = "2.3.0" @@ -2044,12 +2162,28 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -2864,3 +2998,14 @@ name = "zeroize" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" + +[[package]] +name = "zipsign-api" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba5aa1827d6b1a35a29b3413ec69ce5f796e4d897e3e5b38f461bef41d225ea" +dependencies = [ + "base64", + "ed25519-dalek", + "thiserror", +] diff --git a/Cargo.toml b/Cargo.toml index e561025d2..daff7ea01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,15 @@ readme = "README.md" license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] -include = ["src/**/*.rs", "src/plugins/core/assets/**", "/build.rs", "/LICENSE", "/README.md", "/Cargo.lock"] +include = [ + "src/**/*.rs", + "src/plugins/core/assets/**", + "/Cargo.lock", + "/LICENSE", + "/README.md", + "/build.rs", + "/zipsign.pub", +] rust-version = "1.65.0" build = "build.rs" @@ -73,7 +81,11 @@ reqwest = { version = "0.11.17", default-features = false, features = [ "gzip", ] } rmp-serde = "1.1.2" -self_update = { version = "0.38.0", default-features = false, optional = true } +self_update = { version = "<1", default-features = false, optional = true, features = [ + "archive-tar", + "compression-flate2", + "signatures", +] } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/deny.toml b/deny.toml index 310d0c027..2bbe8fe0f 100644 --- a/deny.toml +++ b/deny.toml @@ -101,7 +101,15 @@ unlicensed = "deny" # List of explicitly allowed licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. -allow = ["MIT", "ISC", "Apache-2.0", "Unicode-DFS-2016", "BSD-3-Clause", "OpenSSL"] +allow = [ + "MIT", + "ISC", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "Unicode-DFS-2016", + "BSD-3-Clause", + "OpenSSL", +] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index d32527688..24f96882a 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -75,4 +75,9 @@ cd dist tar -cJf "$BASENAME.tar.xz" rtx tar -czf "$BASENAME.tar.gz" rtx +if [ -f ~/.zipsign/rtx.priv ]; then + zipsign sign tar "$BASENAME.tar.gz" ~/.zipsign/rtx.priv + zipsign verify tar "$BASENAME.tar.gz" ../zipsign.pub +fi + ls -oh "$BASENAME.tar.xz" diff --git a/scripts/setup-zipsign.sh b/scripts/setup-zipsign.sh new file mode 100755 index 000000000..d73016802 --- /dev/null +++ b/scripts/setup-zipsign.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euxo pipefail + +if [ -z "$ZIPSIGN" ]; then + echo "ZIPSIGN is not defined" + exit 0 +fi + +cargo install zipsign +mkdir -p ~/.zipsign +echo "$ZIPSIGN" | base64 -d >~/.zipsign/rtx.priv diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index f5751b594..da6e13fb0 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -1,7 +1,7 @@ use color_eyre::Result; use console::style; -use self_update::backends::github::Update; +use self_update::backends::github::{ReleaseList, Update}; use self_update::cargo_crate_version; use crate::cli::command::Command; @@ -23,15 +23,27 @@ impl Command for SelfUpdate { fn run(self, _config: Config, out: &mut Output) -> Result<()> { let current_version = env::var("RTX_SELF_UPDATE_VERSION").unwrap_or(cargo_crate_version!().to_string()); + let target = format!("{}-{}", *OS, *ARCH); + let mut releases = ReleaseList::configure(); + releases.repo_owner("jdx").repo_name("rtx"); + if let Some(token) = &*env::GITHUB_API_TOKEN { + releases.auth_token(token); + } + let releases = releases.build()?.fetch()?; + let latest = &releases[0].version; + let mut update = Update::configure(); update .repo_owner("jdx") .repo_name("rtx") .bin_name("rtx") + // TODO: enable if working locally + //.verifying_keys([*include_bytes!("../../zipsign.pub")]) .show_download_progress(true) .current_version(¤t_version) - .target(&format!("{}-{}", *OS, *ARCH)) - .identifier("rtx-v"); + .target(&target) + .bin_path_in_archive("rtx/bin/rtx") + .identifier(&format!("rtx-v{latest}-{target}.tar.gz")); if let Some(token) = &*env::GITHUB_API_TOKEN { update.auth_token(token); } diff --git a/zipsign.pub b/zipsign.pub new file mode 100644 index 000000000..1a59af07a --- /dev/null +++ b/zipsign.pub @@ -0,0 +1 @@ +Ă÷©uy=îqŃŇŢôDřA¦%ÖŢR]Jł şŚ \ No newline at end of file From 5bbc727f3f8b6b902d03abe85972970cd58400ea Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:37:58 -0600 Subject: [PATCH 1081/1891] chore: Release --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 31 +++++++++++++++++++++++++------ 7 files changed, 41 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9aef3b24e..d0e2afe25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", "serde", @@ -685,9 +685,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fiat-crypto" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" +checksum = "f69037fe1b785e84986b4f2cbcf647381876a00671d25ceef715d7812dd7e1dd" [[package]] name = "filetime" @@ -811,9 +811,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -1210,9 +1210,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "log" @@ -1777,7 +1777,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.1" +version = "2023.11.2" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index daff7ea01..c3c9a2a4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.1" +version = "2023.11.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 3b6595265..963004ef8 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.1 +rtx 2023.11.2 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.1/rtx-v2023.11.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.2/rtx-v2023.11.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 7d3fa19b7..adb25a7c5 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.1"; + version = "2023.11.2"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 1f4166502..61f79d7c0 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.1" +.TH rtx 1 "rtx 2023.11.2" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.1 +v2023.11.2 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 3eac30d1c..f0b69c687 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.1 +Version: 2023.11.2 Release: 1 URL: https://github.com/jdx/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index bf4a50bda..5a9a9491a 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 714] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -54,6 +54,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("asciidoctorj", "https://github.com/gliwka/asdf-asciidoctorj.git"), ("asdf-plugin-manager", "https://github.com/asdf-community/asdf-plugin-manager"), ("assh", "https://github.com/zekker6/asdf-assh.git"), + ("atlas", "https://github.com/pbr0ck3r/asdf-atlas.git"), ("aws-amplify-cli", "https://github.com/LozanoMatheus/asdf-aws-amplify-cli.git"), ("aws-copilot", "https://github.com/NeoHsu/asdf-copilot"), ("aws-iam-authenticator", "https://github.com/zekker6/asdf-aws-iam-authenticator"), @@ -73,6 +74,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("balena-cli", "https://github.com/boatkit-io/asdf-balena-cli"), ("bashbot", "https://github.com/mathew-fleisch/asdf-bashbot.git"), ("bat", "https://gitlab.com/wt0f/asdf-bat.git"), + ("bat-extras", "https://github.com/vhdirk/asdf-bat-extras.git"), ("batect", "https://github.com/johnlayton/asdf-batect.git"), ("bats", "https://github.com/timgluz/asdf-bats.git"), ("bazel", "https://github.com/rajatvig/asdf-bazel.git"), @@ -80,9 +82,10 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("bbr-s3-config-validator", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("benthos", "https://github.com/benthosdev/benthos-asdf.git"), ("bfs", "https://github.com/virtualroot/asdf-bfs.git"), - ("bin", "https://github.com/joe733/asdf-bin.git"), + ("bin", "https://github.com/yozachar/asdf-bin.git"), ("binnacle", "https://github.com/Traackr/asdf-binnacle.git"), ("bitwarden", "https://github.com/vixus0/asdf-bitwarden.git"), + ("bitwarden-secrets-manager", "https://github.com/asdf-community/asdf-bitwarden-secrets-manager"), ("bombardier", "https://github.com/NeoHsu/asdf-bombardier.git"), ("borg", "https://github.com/lwiechec/asdf-borg"), ("bosh", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), @@ -106,6 +109,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("cf", "https://github.com/mattysweeps/asdf-cf.git"), ("cfssl", "https://github.com/mathew-fleisch/asdf-cfssl.git"), ("chamber", "https://github.com/mintel/asdf-chamber"), + ("changie", "https://github.com/pdemagny/asdf-changie"), ("cheat", "https://github.com/jmoratilla/asdf-cheat-plugin"), ("checkov", "https://github.com/bosmak/asdf-checkov.git"), ("chezmoi", "https://github.com/joke/asdf-chezmoi.git"), @@ -118,6 +122,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("cilium-cli", "https://github.com/carnei-ro/asdf-cilium-cli.git"), ("cilium-hubble", "https://github.com/NitriKx/asdf-cilium-hubble.git"), ("circleci-cli", "https://github.com/ucpr/asdf-circleci-cli.git"), + ("clarinet", "https://github.com/alexgo-io/asdf-clarinet.git"), ("clojure", "https://github.com/asdf-community/asdf-clojure.git"), ("cloud-sql-proxy", "https://github.com/pbr0ck3r/asdf-cloud-sql-proxy.git"), ("cloudflared", "https://github.com/threkk/asdf-cloudflared"), @@ -188,6 +193,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("draft", "https://github.com/kristoflemmens/asdf-draft.git"), ("driftctl", "https://github.com/nlamirault/asdf-driftctl.git"), ("drone", "https://github.com/virtualstaticvoid/asdf-drone.git"), + ("dt", "https://github.com/so-dang-cool/asdf-dt.git"), ("dtm", "https://github.com/zhenyuanlau/asdf-dtm.git"), ("duf", "https://github.com/NeoHsu/asdf-duf.git"), ("dust", "https://github.com/looztra/asdf-dust.git"), @@ -199,6 +205,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("eksctl", "https://github.com/elementalvoid/asdf-eksctl.git"), ("elasticsearch", "https://github.com/asdf-community/asdf-elasticsearch.git"), ("elixir", "https://github.com/asdf-vm/asdf-elixir.git"), + ("elixir-ls", "https://github.com/juantascon/asdf-elixir-ls"), ("elm", "https://github.com/asdf-community/asdf-elm.git"), ("embulk", "https://github.com/yuokada/asdf-embulk.git"), ("emsdk", "https://github.com/RobLoach/asdf-emsdk.git"), @@ -322,7 +329,8 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("istioctl", "https://github.com/virtualstaticvoid/asdf-istioctl.git"), ("janet", "https://github.com/Jakski/asdf-janet.git"), ("jb", "https://github.com/beardix/asdf-jb.git"), - ("jbang", "https://github.com/joschi/asdf-jbang.git"), + ("jbang", "https://github.com/jbangdev/jbang-asdf.git"), + ("jfrog-cli", "https://github.com/LozanoMatheus/asdf-jfrog-cli.git"), ("jib", "https://github.com/joschi/asdf-jib.git"), ("jiq", "https://github.com/chessmango/asdf-jiq.git"), ("jless", "https://github.com/jc00ke/asdf-jless.git"), @@ -399,6 +407,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("kuttl", "https://github.com/jimmidyson/asdf-kuttl.git"), ("kwt", "https://github.com/vmware-tanzu/asdf-carvel.git"), ("lab", "https://github.com/particledecay/asdf-lab.git"), + ("lane", "https://github.com/CodeReaper/asdf-lane.git"), ("lazygit", "https://github.com/nklmilojevic/asdf-lazygit.git"), ("lean", "https://github.com/asdf-community/asdf-lean.git"), ("lefthook", "https://github.com/jtzero/asdf-lefthook.git"), @@ -434,6 +443,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("meson", "https://github.com/asdf-community/asdf-meson.git"), ("micronaut", "https://github.com/weibemoura/asdf-micronaut.git"), ("mill", "https://github.com/asdf-community/asdf-mill.git"), + ("mimirtool", "https://github.com/asdf-community/asdf-mimirtool.git"), ("minify", "https://github.com/axilleas/asdf-minify"), ("minikube", "https://github.com/alvarobp/asdf-minikube.git"), ("minio", "https://github.com/aeons/asdf-minio.git"), @@ -443,6 +453,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("mkcert", "https://github.com/salasrod/asdf-mkcert.git"), ("mlton", "https://github.com/asdf-community/asdf-mlton.git"), ("mockery", "https://github.com/cabify/asdf-mockery.git"), + ("monarch", "https://github.com/nyuyuyu/asdf-monarch.git"), ("mongo-tools", "https://github.com/itspngu/asdf-mongo-tools.git"), ("mongodb", "https://github.com/sylph01/asdf-mongodb.git"), ("mongosh", "https://github.com/itspngu/asdf-mongosh.git"), @@ -479,6 +490,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("opensearch", "https://github.com/randikabanura/asdf-opensearch.git"), ("opensearch-cli", "https://github.com/iul1an/asdf-opensearch-cli.git"), ("openshift-install", "https://github.com/hhemied/asdf-openshift-install.git"), + ("opentofu", "https://github.com/virtualroot/asdf-opentofu.git"), ("operator-sdk", "https://github.com/Medium/asdf-operator-sdk.git"), ("opsgenie-lamp", "https://github.com/ORCID/asdf-opsgenie-lamp"), ("oras", "https://github.com/bodgit/asdf-oras.git"), @@ -493,7 +505,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("php", "https://github.com/asdf-community/asdf-php.git"), ("pint", "https://github.com/sam-burrell/asdf-pint.git"), ("pipectl", "https://github.com/pipe-cd/asdf-pipectl.git"), - ("pipx", "https://github.com/joe733/asdf-pipx.git"), + ("pipx", "https://github.com/yozachar/asdf-pipx.git"), ("pivnet", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("please", "https://github.com/asdf-community/asdf-please.git"), ("pluto", "https://github.com/FairwindsOps/asdf-pluto.git"), @@ -505,6 +517,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("powerline-go", "https://github.com/dex4er/asdf-powerline-go.git"), ("powershell-core", "https://github.com/daveneeley/asdf-powershell-core.git"), ("pre-commit", "https://github.com/jonathanmorley/asdf-pre-commit.git"), + ("promtool", "https://github.com/asdf-community/asdf-promtool"), ("protoc", "https://github.com/paxosglobal/asdf-protoc.git"), ("protoc-gen-connect-go", "https://github.com/dylanrayboss/asdf-protoc-gen-connect-go.git"), ("protoc-gen-go", "https://github.com/pbr0ck3r/asdf-protoc-gen-go.git"), @@ -516,7 +529,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("psc-package", "https://github.com/nsaunders/asdf-psc-package.git"), ("pulumi", "https://github.com/canha/asdf-pulumi.git"), ("purerl", "https://github.com/GoNZooo/asdf-purerl.git"), - ("purescript", "https://github.com/nsaunders/asdf-purescript.git"), + ("purescript", "https://github.com/jrrom/asdf-purescript.git"), ("purty", "https://github.com/nsaunders/asdf-purty.git"), ("qdns", "https://github.com/moritz-makandra/asdf-plugin-qdns.git"), ("quarkus", "https://github.com/asdf-community/asdf-quarkus.git"), @@ -584,7 +597,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("soracom", "https://github.com/grimoh/asdf-soracom.git"), ("sourcery", "https://github.com/younke/asdf-sourcery.git"), ("spacectl", "https://github.com/bodgit/asdf-spacectl.git"), - ("spago", "https://github.com/nsaunders/asdf-spago.git"), + ("spago", "https://github.com/jrrom/asdf-spago.git"), ("spark", "https://github.com/joshuaballoch/asdf-spark.git"), ("spectral", "https://github.com/vbyrd/asdf-spectral.git"), ("spin", "https://github.com/pavloos/asdf-spin.git"), @@ -595,8 +608,10 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("sshuttle", "https://github.com/xanmanning/asdf-sshuttle.git"), ("stack", "https://github.com/sestrella/asdf-ghcup.git"), ("starboard", "https://github.com/zufardhiyaulhaq/asdf-starboard.git"), + ("starknet-foundry", "https://github.com/foundry-rs/asdf-starknet-foundry.git"), ("starport", "https://github.com/nikever/asdf-starport.git"), ("starship", "https://github.com/grimoh/asdf-starship.git"), + ("staticcheck", "https://github.com/pbr0ck3r/asdf-staticcheck.git"), ("steampipe", "https://github.com/carnei-ro/asdf-steampipe.git"), ("step", "https://github.com/log2/asdf-step.git"), ("stern", "https://github.com/looztra/asdf-stern.git"), @@ -615,6 +630,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("talos", "https://github.com/particledecay/asdf-talos.git"), ("talosctl", "https://github.com/bjw-s/asdf-talosctl"), ("tanka", "https://github.com/trotttrotttrott/asdf-tanka.git"), + ("tanzu", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("task", "https://github.com/particledecay/asdf-task.git"), ("tctl", "https://github.com/eko/asdf-tctl.git"), ("tekton-cli", "https://github.com/johnhamelink/asdf-tekton-cli.git"), @@ -654,6 +670,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("tomcat", "https://github.com/mbutov/asdf-tomcat"), ("tonnage", "https://github.com/elementalvoid/asdf-tonnage.git"), ("tool-versions-to-env", "https://github.com/smartcontractkit/tool-versions-to-env-action.git"), + ("traefik", "https://github.com/Dabolus/asdf-traefik.git"), ("trdsql", "https://github.com/johnlayton/asdf-trdsql.git"), ("tree-sitter", "https://github.com/ivanvc/asdf-tree-sitter.git"), ("tridentctl", "https://github.com/asdf-community/asdf-tridentctl.git"), @@ -665,6 +682,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("typos", "https://github.com/aschiavon91/asdf-typos.git"), ("uaa-cli", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("unison", "https://github.com/susurri/asdf-unison.git"), + ("updatecli", "https://github.com/updatecli/asdf-updatecli.git"), ("upt", "https://github.com/ORCID/asdf-upt.git"), ("upx", "https://github.com/jimmidyson/asdf-upx.git"), ("usql", "https://github.com/itspngu/asdf-usql.git"), @@ -708,6 +726,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 695] = [ ("yor", "https://github.com/ordinaryexperts/asdf-yor"), ("youtube-dl", "https://github.com/iul1an/asdf-youtube-dl"), ("yq", "https://github.com/sudermanjr/asdf-yq.git"), + ("yt-dlp", "https://github.com/duhow/asdf-yt-dlp"), ("ytt", "https://github.com/vmware-tanzu/asdf-carvel.git"), ("zbctl", "https://github.com/camunda-community-hub/asdf-zbctl.git"), ("zellij", "https://github.com/chessmango/asdf-zellij.git"), From 7c2e2589b989031ebb102b72df57f712ebc79356 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:21:36 -0600 Subject: [PATCH 1082/1891] bump toml_edit (#988) --- Cargo.lock | 19 ++++--------------- Cargo.toml | 4 ++-- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0e2afe25..d707dfab9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1828,7 +1828,7 @@ dependencies = [ "terminal_size", "thiserror", "toml", - "toml_edit 0.20.7", + "toml_edit", "url", "versions", ] @@ -1887,9 +1887,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64", ] @@ -2421,7 +2421,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.0", + "toml_edit", ] [[package]] @@ -2433,17 +2433,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.1.0", - "toml_datetime", - "winnow", -] - [[package]] name = "toml_edit" version = "0.21.0" diff --git a/Cargo.toml b/Cargo.toml index c3c9a2a4b..ffa03297c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,8 +97,8 @@ tar = "0.4" tera = { version = "1.19", default-features = false } terminal_size = "0.3" thiserror = "1.0" -toml = "<0.9" -toml_edit = "<0.21" +toml = "<1" +toml_edit = "<1" url = "2.4" versions = "5.0" From 9084a6914390af40cc86a89a16e6a841c547613f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:04:11 -0600 Subject: [PATCH 1083/1891] self-update: enable zipsign signature verification (#987) Fixes #980 --- src/cli/self_update.rs | 64 ++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index da6e13fb0..0f54265d1 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -2,7 +2,8 @@ use color_eyre::Result; use console::style; use self_update::backends::github::{ReleaseList, Update}; -use self_update::cargo_crate_version; +use self_update::update::Release; +use self_update::{cargo_crate_version, Status}; use crate::cli::command::Command; use crate::cli::version::{ARCH, OS}; @@ -20,41 +21,56 @@ use crate::output::Output; pub struct SelfUpdate {} impl Command for SelfUpdate { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let current_version = - env::var("RTX_SELF_UPDATE_VERSION").unwrap_or(cargo_crate_version!().to_string()); - let target = format!("{}-{}", *OS, *ARCH); + fn run(self, config: Config, out: &mut Output) -> Result<()> { + let latest = &self.fetch_releases()?[0].version; + let status = self.do_update(&config, latest)?; + + if status.updated() { + let version = style(status.version()).bright().yellow(); + rtxprintln!(out, "Updated rtx to {version}"); + } else { + rtxprintln!(out, "rtx is already up to date"); + } + + Ok(()) + } +} + +impl SelfUpdate { + fn fetch_releases(&self) -> Result> { let mut releases = ReleaseList::configure(); - releases.repo_owner("jdx").repo_name("rtx"); if let Some(token) = &*env::GITHUB_API_TOKEN { releases.auth_token(token); } - let releases = releases.build()?.fetch()?; - let latest = &releases[0].version; + let releases = releases + .repo_owner("jdx") + .repo_name("rtx") + .build()? + .fetch()?; + Ok(releases) + } + fn do_update(&self, config: &Config, latest: &str) -> Result { + let current_version = + env::var("RTX_SELF_UPDATE_VERSION").unwrap_or(cargo_crate_version!().to_string()); + let target = format!("{}-{}", *OS, *ARCH); let mut update = Update::configure(); - update + if let Some(token) = &*env::GITHUB_API_TOKEN { + update.auth_token(token); + } + let status = update .repo_owner("jdx") .repo_name("rtx") .bin_name("rtx") - // TODO: enable if working locally - //.verifying_keys([*include_bytes!("../../zipsign.pub")]) + .verifying_keys([*include_bytes!("../../zipsign.pub")]) .show_download_progress(true) .current_version(¤t_version) .target(&target) .bin_path_in_archive("rtx/bin/rtx") - .identifier(&format!("rtx-v{latest}-{target}.tar.gz")); - if let Some(token) = &*env::GITHUB_API_TOKEN { - update.auth_token(token); - } - let status = update.build()?.update()?; - if status.updated() { - let version = style(status.version()).bright().yellow(); - rtxprintln!(out, "Updated rtx to {version}"); - } else { - rtxprintln!(out, "rtx is already up to date"); - } - - Ok(()) + .identifier(&format!("rtx-v{latest}-{target}.tar.gz")) + .no_confirm(config.settings.yes) + .build()? + .update()?; + Ok(status) } } From 7f2197d6b2cff93fb546a2890249b899672720eb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 9 Nov 2023 16:36:49 -0600 Subject: [PATCH 1084/1891] uninstall: added --all and --dry-run features (#989) --- README.md | 14 ++++++-- completions/_rtx | 4 +++ completions/rtx.bash | 2 +- completions/rtx.fish | 2 ++ e2e/test_uninstall | 17 +++++++++- src/cli/uninstall.rs | 81 ++++++++++++++++++++++++++++++++------------ 6 files changed, 94 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 963004ef8..449a21adc 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ v20.0.0 - [`rtx sync node <--brew|--nvm|--nodenv>`](#rtx-sync-node---brew--nvm--nodenv) - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - - [`rtx uninstall ...`](#rtx-uninstall-toolversion) + - [`rtx uninstall [OPTIONS] ...`](#rtx-uninstall-options-toolversion) - [`rtx upgrade [TOOL@VERSION]...`](#rtx-upgrade-toolversion) - [`rtx use [OPTIONS] [TOOL@VERSION]...`](#rtx-use-options-toolversion) - [`rtx version`](#rtx-version) @@ -2455,20 +2455,28 @@ Examples: # trusts .rtx.toml in the current or parent directory $ rtx trust ``` -### `rtx uninstall ...` +### `rtx uninstall [OPTIONS] ...` ``` Removes runtime versions -Usage: uninstall ... +Usage: uninstall [OPTIONS] ... Arguments: ... Tool(s) to remove +Options: + -a, --all + Delete all installed versions + + -n, --dry-run + Do not actually delete anything + Examples: $ rtx uninstall node@18.0.0 # will uninstall specific version $ rtx uninstall node # will uninstall current node version + $ rtx uninstall --all node@18.0.0 # will uninstall all node versions ``` ### `rtx upgrade [TOOL@VERSION]...` diff --git a/completions/_rtx b/completions/_rtx index 508bc24c9..56db671a4 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1608,6 +1608,10 @@ _arguments "${_arguments_options[@]}" \ '--jobs=[Number of plugins and runtimes to install in parallel \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-a[Delete all installed versions]' \ +'--all[Delete all installed versions]' \ +'-n[Do not actually delete anything]' \ +'--dry-run[Do not actually delete anything]' \ '--debug[Sets log level to debug]' \ '--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index f009f975c..54a70bc38 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3301,7 +3301,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." + opts="-a -n -j -r -y -v -h --all --dry-run --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 70302a00b..ea83de65b 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -743,6 +743,8 @@ complete -c rtx -n "__fish_seen_subcommand_from trust" -s h -l help -d 'Print he complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s a -l all -d 'Delete all installed versions' +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s n -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/e2e/test_uninstall b/e2e/test_uninstall index f2fbb5efe..afd803548 100755 --- a/e2e/test_uninstall +++ b/e2e/test_uninstall @@ -5,4 +5,19 @@ source "$(dirname "$0")/assert.sh" rtx i rtx uninstall tiny export CLICOLOR=0 -assert_contains "rtx ls" "3.1.0 (missing)" +assert_contains "rtx ls tiny" "3.1.0 (missing)" + +rtx i tiny@1 tiny@2.0 tiny@2.1 +assert_contains "rtx ls tiny" "1.0.1" +assert_contains "rtx ls tiny" "2.0.1" +assert_contains "rtx ls tiny" "2.1.0" + +rtx rm -a tiny@2 +assert_contains "rtx ls tiny" "1.0.1" +assert_not_contains "rtx ls tiny" "2.0.1" +assert_not_contains "rtx ls tiny" "2.1.0" + +rtx rm -a tiny +assert_not_contains "rtx ls tiny" "1.0.1" +assert_not_contains "rtx ls tiny" "2.0.1" +assert_not_contains "rtx ls tiny" "2.1.0" diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 68870e9f4..ef1fafb46 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -5,7 +5,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::toolset::ToolsetBuilder; +use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::{runtime_symlinks, shims}; @@ -16,30 +16,68 @@ pub struct Uninstall { /// Tool(s) to remove #[clap(required = true, value_name="TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, + + /// Delete all installed versions + #[clap(long, short = 'a')] + all: bool, + + /// Do not actually delete anything + #[clap(long, short = 'n')] + dry_run: bool, } impl Command for Uninstall { fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let runtimes = ToolArg::double_tool_condition(&self.tool); - let tool_versions = runtimes - .iter() - .map(|a| { - let tool = config.get_or_create_tool(&a.plugin); - let tv = match &a.tvr { - Some(tvr) => tvr.resolve(&config, &tool, Default::default(), false)?, - None => { - let ts = ToolsetBuilder::new().build(&mut config)?; - let tv = ts - .versions - .get(&a.plugin) - .and_then(|v| v.versions.first()) - .expect("no version found"); - tv.clone() - } - }; - Ok((tool, tv)) - }) - .collect::>>()?; + + let mut tool_versions = vec![]; + if self.all { + for runtime in runtimes { + let tool = config.get_or_create_tool(&runtime.plugin); + let query = runtime.tvr.map(|tvr| tvr.version()).unwrap_or_default(); + let tvs = tool + .list_installed_versions()? + .into_iter() + .filter(|v| v.starts_with(&query)) + .map(|v| { + let tvr = ToolVersionRequest::new(tool.name.clone(), &v); + let tv = ToolVersion::new(&tool, tvr, Default::default(), v); + (tool.clone(), tv) + }) + .collect::>(); + if tvs.is_empty() { + warn!( + "no versions found for {}", + style(&tool.name).cyan().for_stderr() + ); + } + tool_versions.extend(tvs); + } + } else { + tool_versions = runtimes + .into_iter() + .map(|a| { + let tool = config.get_or_create_tool(&a.plugin); + let tvs = match a.tvr { + Some(tvr) => { + vec![tvr.resolve(&config, &tool, Default::default(), false)?] + } + None => { + let ts = ToolsetBuilder::new().build(&mut config)?; + let tvl = ts.versions.get(&a.plugin).expect("no versions found"); + tvl.versions.clone() + } + }; + Ok(tvs + .into_iter() + .map(|tv| (tool.clone(), tv)) + .collect::>()) + }) + .collect::>>()? + .into_iter() + .flatten() + .collect::>(); + } let mpr = MultiProgressReport::new(config.show_progress_bars()); for (plugin, tv) in tool_versions { @@ -50,7 +88,7 @@ impl Command for Uninstall { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, Some(&tv)); - if let Err(err) = plugin.uninstall_version(&config, &tv, &pr, false) { + if let Err(err) = plugin.uninstall_version(&config, &tv, &pr, self.dry_run) { pr.error(err.to_string()); return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", &tv))); } @@ -69,5 +107,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx uninstall node@18.0.0 # will uninstall specific version $ rtx uninstall node # will uninstall current node version + $ rtx uninstall --all node@18.0.0 # will uninstall all node versions "# ); From 6ff51d8c51d0a4697f18b57c16a96cebd71ffcee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 07:26:24 -0600 Subject: [PATCH 1085/1891] chore(deps): bump clap from 4.4.7 to 4.4.8 (#991) Bumps [clap](https://github.com/clap-rs/clap) from 4.4.7 to 4.4.8. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.4.7...v4.4.8) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d707dfab9..845d52939 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,9 +224,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.7" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" +checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" dependencies = [ "clap_builder", "clap_derive", @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.7" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" +checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" dependencies = [ "anstream", "anstyle", From 05e56305dbe5249c4cc789f1c7616ec00c960dca Mon Sep 17 00:00:00 2001 From: Chris Wesseling Date: Mon, 13 Nov 2023 23:52:07 +0100 Subject: [PATCH 1086/1891] fix: xonsh hook (#994) It was raising a TypeError: ``` xonsh: For full traceback set: $XONSH_SHOW_TRACEBACK = True TypeError: 'method' object is not subscriptable Exception raised in event handler; ignored. ``` --- src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap | 4 ++-- src/shell/xonsh.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap index dc61fc800..072d1d815 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap @@ -6,6 +6,6 @@ from os import environ from xonsh.built_ins import XSH envx = XSH.env -envx.pop[ 'FOO',None] -environ.pop['FOO',None] +envx.pop( 'FOO',None) +environ.pop('FOO',None) diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 9d3bb8dae..3217ac4b1 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -115,8 +115,8 @@ impl Shell for Xonsh { from xonsh.built_ins import XSH envx = XSH.env - envx.pop[ '{k}',None] - environ.pop['{k}',None] + envx.pop( '{k}',None) + environ.pop('{k}',None) "#, k = shell_escape::unix::escape(k.into()) // todo: drop illegal chars, not escape? ) From 4f1927c6c68ac3c689fd4e531e0afb8b519e8bc5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:04:04 -0600 Subject: [PATCH 1087/1891] chore: Release --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 845d52939..165f757f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -685,9 +685,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fiat-crypto" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f69037fe1b785e84986b4f2cbcf647381876a00671d25ceef715d7812dd7e1dd" +checksum = "53a56f0780318174bad1c127063fd0c5fdfb35398e3cd79ffaab931a6c79df80" [[package]] name = "filetime" @@ -908,9 +908,9 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1777,7 +1777,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.2" +version = "2023.11.3" dependencies = [ "base64", "built", @@ -1850,9 +1850,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "ffb93593068e9babdad10e4fce47dc9b3ac25315a72a59766ffd9e9a71996a04" dependencies = [ "bitflags 2.4.1", "errno 0.3.6", @@ -2364,9 +2364,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -2484,9 +2484,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "sharded-slab", "thread_local", diff --git a/Cargo.toml b/Cargo.toml index ffa03297c..9719c47a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.2" +version = "2023.11.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 449a21adc..81768ec36 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.2 +rtx 2023.11.3 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.2/rtx-v2023.11.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.3/rtx-v2023.11.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index adb25a7c5..68f22719c 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.2"; + version = "2023.11.3"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 61f79d7c0..a2d547062 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.2" +.TH rtx 1 "rtx 2023.11.3" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.2 +v2023.11.3 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f0b69c687..ba63f7455 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.2 +Version: 2023.11.3 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 4888335568100f34dbc9a9a74d6689e579f34a86 Mon Sep 17 00:00:00 2001 From: Ben Weintraub Date: Wed, 15 Nov 2023 08:41:10 -0800 Subject: [PATCH 1088/1891] Fix quoting in zsh configuration instructions (#998) --- packaging/standalone/install.envsubst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index 1b2e699b9..971fb8a19 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -138,7 +138,7 @@ after_finish_help() { case "${SHELL:-}" in */zsh) info "rtx: run the following to activate rtx in your shell:" - info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> \"${ZDOTDIR-~}/.zshrc\"" + info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> \"${ZDOTDIR-$HOME}/.zshrc\"" info "" info "rtx: this must be run in order to use rtx in the terminal" info "rtx: run \`rtx doctor\` to verify this is setup correctly" From f6ca8004992e32f68fdfbbd7e405f82f960bce14 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:41:08 -0600 Subject: [PATCH 1089/1891] do not fail when regex version parsing fails (#1000) Fixes #999 --- src/tool.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tool.rs b/src/tool.rs index a1907795c..2c429c646 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -91,7 +91,7 @@ impl Tool { pub fn list_installed_versions_matching(&self, query: &str) -> Result> { let versions = self.list_installed_versions()?; - Ok(self.fuzzy_match_filter(versions, query)) + self.fuzzy_match_filter(versions, query) } pub fn list_remote_versions(&self, settings: &Settings) -> Result> { @@ -100,7 +100,7 @@ impl Tool { pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { let versions = self.list_remote_versions(settings)?; - Ok(self.fuzzy_match_filter(versions, query)) + self.fuzzy_match_filter(versions, query) } pub fn latest_version( @@ -369,17 +369,16 @@ impl Tool { self.plugin.get_lock(path, force) } - fn fuzzy_match_filter(&self, versions: Vec, query: &str) -> Vec { + fn fuzzy_match_filter(&self, versions: Vec, query: &str) -> Result> { let mut query = query; if query == "latest" { query = "[0-9].*"; } - let query_regex = - Regex::new(&format!("^{}([-.].+)?$", query)).expect("error parsing regex"); + let query_regex = Regex::new(&format!("^{}([-.].+)?$", query))?; let version_regex = regex!( r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" ); - versions + let versions = versions .into_iter() .filter(|v| { if query == v { @@ -390,7 +389,8 @@ impl Tool { } query_regex.is_match(v) }) - .collect() + .collect(); + Ok(versions) } } From c212385cd6a50f0ffee58d95f3c6c5783f465231 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:43:53 -0600 Subject: [PATCH 1090/1891] chore: Release --- Cargo.lock | 38 +++++++++++--------------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 18 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 165f757f0..fc2ae9bd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,9 +91,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2" +checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5" dependencies = [ "flate2", "futures-core", @@ -865,9 +865,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -875,19 +875,13 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap", "slab", "tokio", "tokio-util", "tracing", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.2" @@ -1053,16 +1047,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.1.0" @@ -1070,7 +1054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown", "serde", ] @@ -1777,7 +1761,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.3" +version = "2023.11.4" dependencies = [ "base64", "built", @@ -1799,7 +1783,7 @@ dependencies = [ "fslock", "humantime", "indenter", - "indexmap 2.1.0", + "indexmap", "indicatif", "indoc", "insta", @@ -1850,9 +1834,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.23" +version = "0.38.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb93593068e9babdad10e4fce47dc9b3ac25315a72a59766ffd9e9a71996a04" +checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234" dependencies = [ "bitflags 2.4.1", "errno 0.3.6", @@ -2439,7 +2423,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.1.0", + "indexmap", "serde", "serde_spanned", "toml_datetime", diff --git a/Cargo.toml b/Cargo.toml index 9719c47a3..c7d103d29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.3" +version = "2023.11.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 81768ec36..7f88fadb3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.3 +rtx 2023.11.4 ``` Hook rtx into your shell (pick the right one for your shell): @@ -340,7 +340,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.3/rtx-v2023.11.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.4/rtx-v2023.11.4-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 68f22719c..ab572d16b 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.3"; + version = "2023.11.4"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index a2d547062..1345216dc 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.3" +.TH rtx 1 "rtx 2023.11.4" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.3 +v2023.11.4 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ba63f7455..0901064e6 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.3 +Version: 2023.11.4 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From f9ac9b094afd59cef5730deb0604f64edfb4ed3d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 15 Nov 2023 19:01:21 -0600 Subject: [PATCH 1091/1891] set safe.directory when using git (#1002) This avoids permission failures if the user that created the git repo is not the same as the current user --- src/git.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/git.rs b/src/git.rs index 6af6e1a67..d95761b04 100644 --- a/src/git.rs +++ b/src/git.rs @@ -10,6 +10,15 @@ pub struct Git { pub dir: PathBuf, } +macro_rules! git_cmd { + ( $dir:expr $(, $arg:expr )* $(,)? ) => { + { + let safe = format!("safe.directory={}", $dir.display()); + cmd!("git", "-C", $dir, "-c", safe $(, $arg)*) + } + }; +} + impl Git { pub fn new(dir: PathBuf) -> Self { Self { dir } @@ -62,24 +71,24 @@ impl Git { } pub fn current_branch(&self) -> Result { - let branch = cmd!("git", "-C", &self.dir, "branch", "--show-current").read()?; + let branch = git_cmd!(&self.dir, "branch", "--show-current").read()?; debug!("current branch for {}: {}", self.dir.display(), &branch); Ok(branch) } pub fn current_sha(&self) -> Result { - let sha = cmd!("git", "-C", &self.dir, "rev-parse", "HEAD").read()?; + let sha = git_cmd!(&self.dir, "rev-parse", "HEAD").read()?; debug!("current sha for {}: {}", self.dir.display(), &sha); Ok(sha) } pub fn current_sha_short(&self) -> Result { - let sha = cmd!("git", "-C", &self.dir, "rev-parse", "--short", "HEAD").read()?; + let sha = git_cmd!(&self.dir, "rev-parse", "--short", "HEAD").read()?; debug!("current sha for {}: {}", self.dir.display(), &sha); Ok(sha) } pub fn current_abbrev_ref(&self) -> Result { - let aref = cmd!("git", "-C", &self.dir, "rev-parse", "--abbrev-ref", "HEAD").read()?; + let aref = git_cmd!(&self.dir, "rev-parse", "--abbrev-ref", "HEAD").read()?; debug!("current abbrev ref for {}: {}", self.dir.display(), &aref); Ok(aref) } @@ -88,15 +97,7 @@ impl Git { if !self.dir.exists() { return None; } - let res = cmd!( - "git", - "-C", - &self.dir, - "config", - "--get", - "remote.origin.url" - ) - .read(); + let res = git_cmd!(&self.dir, "config", "--get", "remote.origin.url").read(); match res { Ok(url) => { debug!("remote url for {}: {}", self.dir.display(), &url); @@ -122,7 +123,8 @@ impl Git { pub fn run_git_command(&self, args: &[&str]) -> Result<()> { let dir = self.dir.to_string_lossy(); - let mut cmd_args = vec!["-C", &dir]; + let safe = format!("safe.directory={}", dir); + let mut cmd_args = vec!["-C", &dir, "-c", &safe]; cmd_args.extend(args.iter().cloned()); match cmd::cmd("git", &cmd_args) .stderr_to_stdout() From 5372bef4879f660a467729abe94c6a7d13872d2b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 15 Nov 2023 20:56:56 -0600 Subject: [PATCH 1092/1891] refactor git.rs (#1003) --- src/git.rs | 57 +++++++++++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/src/git.rs b/src/git.rs index d95761b04..8b919a2bc 100644 --- a/src/git.rs +++ b/src/git.rs @@ -2,6 +2,7 @@ use std::fs::create_dir_all; use std::path::PathBuf; use color_eyre::eyre::{eyre, Result}; +use duct::Expression; use crate::cmd; use crate::file::touch_dir; @@ -16,7 +17,7 @@ macro_rules! git_cmd { let safe = format!("safe.directory={}", $dir.display()); cmd!("git", "-C", $dir, "-c", safe $(, $arg)*) } - }; + } } impl Git { @@ -31,23 +32,39 @@ impl Git { pub fn update(&self, gitref: Option) -> Result<(String, String)> { let gitref = gitref.map_or_else(|| self.current_branch(), Ok)?; debug!("updating {} to {}", self.dir.display(), gitref); - self.run_git_command(&[ + let exec = |cmd: Expression| match cmd.stderr_to_stdout().stdout_capture().unchecked().run() + { + Ok(res) => { + if res.status.success() { + Ok(()) + } else { + Err(eyre!( + "git failed: {cmd:?} {}", + String::from_utf8(res.stdout).unwrap() + )) + } + } + Err(err) => Err(eyre!("git failed: {cmd:?} {err:#}")), + }; + exec(git_cmd!( + &self.dir, "fetch", "--prune", "--update-head-ok", "origin", - format!("{}:{}", gitref, gitref).as_str(), - ])?; + &format!("{}:{}", gitref, gitref), + ))?; let prev_rev = self.current_sha()?; - self.run_git_command(&[ + exec(git_cmd!( + &self.dir, "-c", "advice.detachedHead=false", "-c", "advice.objectNameWarning=false", "checkout", "--force", - gitref.as_str(), - ])?; + &gitref + ))?; let post_rev = self.current_sha()?; touch_dir(&self.dir)?; @@ -120,32 +137,6 @@ impl Git { None => (url.to_string(), None), } } - - pub fn run_git_command(&self, args: &[&str]) -> Result<()> { - let dir = self.dir.to_string_lossy(); - let safe = format!("safe.directory={}", dir); - let mut cmd_args = vec!["-C", &dir, "-c", &safe]; - cmd_args.extend(args.iter().cloned()); - match cmd::cmd("git", &cmd_args) - .stderr_to_stdout() - .stdout_capture() - .unchecked() - .run() - { - Ok(res) => { - if res.status.success() { - Ok(()) - } else { - Err(eyre!( - "git failed: {:?} {}", - cmd_args, - String::from_utf8(res.stdout).unwrap() - )) - } - } - Err(err) => Err(eyre!("git failed: {:?} {:#}", cmd_args, err)), - } - } } fn get_git_version() -> Result { From 0604e91b21c78bb7108ceb176af0ca5b9d5f09cc Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 17 Nov 2023 20:09:54 -0600 Subject: [PATCH 1093/1891] prune: ignore non-symlinks in tracked config files (#1007) --- src/cli/prune.rs | 3 ++- src/config/tracking.rs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 386fe6d4e..c5b23be0a 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -64,7 +64,8 @@ impl Prune { if self.dry_run { pr.set_prefix(format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); } - if config.settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? { + if self.dry_run || config.settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? + { p.decorate_progress_bar(&mut pr, Some(&tv)); p.uninstall_version(config, &tv, &pr, self.dry_run)?; pr.finish(); diff --git a/src/config/tracking.rs b/src/config/tracking.rs index 51ecd2ef4..f708e34a5 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -40,6 +40,9 @@ impl Tracker { let mut output = vec![]; for path in read_dir(&self.tracking_dir)? { let path = path?.path(); + if !path.is_symlink() { + continue; + } let path = fs::read_link(path)?; if path.exists() { output.push(path); From e71f8a409d887d35c6173515458b53e605dca988 Mon Sep 17 00:00:00 2001 From: Jakob Guddas Date: Sat, 18 Nov 2023 03:10:53 +0100 Subject: [PATCH 1094/1891] docs: made install instructions collapsable (#1005) --- README.md | 53 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 7f88fadb3..d1d24c8c4 100644 --- a/README.md +++ b/README.md @@ -233,16 +233,17 @@ See the [FAQ](#what-does-rtx-activate-do). ## Installation Installing rtx consists of two steps. + 1. Download the binary. This depends on the device and operating system you are running rtx in. 1. Register a shell hook. This depends on the shell you are using. Read more about this step in the [FAQ](#what-does-rtx-activate-do). -### Download binary - -#### Standalone +### 1. Download binary +
+ Standalone Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate script in your rc file, rtx will automatically add itself to `PATH`. @@ -281,7 +282,9 @@ Supported platforms: If you need something else, compile it with [cargo](#cargo). [Windows isn't currently supported.](https://github.com/jdx/rtx/discussions/66) -#### Homebrew +
+
+ Homebrew ``` brew install rtx @@ -293,13 +296,17 @@ Alternatively, use the custom tap (which is updated immediately after a release) brew install jdx/tap/rtx ``` -#### MacPorts +
+
+ MacPorts ``` sudo port install rtx ``` -#### Cargo +
+
+ Cargo Build from source with Cargo: @@ -320,7 +327,9 @@ Build from the latest commit in main: cargo install rtx-cli --git https://github.com/jdx/rtx --branch main ``` -#### npm +
+
+ npm rtx is available on npm as a precompiled binary. This isn't a node.js package—just distributed via npm. This is useful for JS projects that want to setup rtx via `package.json` or `npx`. @@ -335,7 +344,9 @@ Use npx if you just want to test it out for a single command without fully insta npx rtx-cli exec python@3.11 -- python some_script.py ``` -#### GitHub Releases +
+
+ GitHub Releases Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). @@ -344,7 +355,9 @@ curl https://github.com/jdx/rtx/releases/download/v2023.11.4/rtx-v2023.11.4-linu chmod +x /usr/local/bin/rtx ``` -#### apt +
+
+ apt For installation on Ubuntu/Debian: @@ -364,7 +377,9 @@ sudo apt install -y rtx > echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` -#### dnf +
+
+ dnf For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: @@ -374,7 +389,9 @@ dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo dnf install -y rtx ``` -#### yum +
+
+ yum ``` yum install -y yum-utils @@ -382,7 +399,9 @@ yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo yum install -y rtx ``` -#### apk +
+
+ apk For Alpine Linux: @@ -392,7 +411,9 @@ apk add rtx _rtx lives in the [community repository](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/rtx/APKBUILD)._ -#### aur +
+
+ aur For Arch Linux: @@ -402,7 +423,9 @@ cd rtx makepkg -si ``` -#### nix +
+
+ nix For the Nix package manager, at release 23.05 or later: @@ -414,6 +437,8 @@ You can also import the package directly using `rtx-flake.packages.${system}.rtx`. It supports all default Nix systems. +
+ ### Register shell hook #### Bash From a79b9a51ad3f075e392a8bf0052ea9e27a52ae32 Mon Sep 17 00:00:00 2001 From: Jakob Guddas Date: Sat, 18 Nov 2023 03:11:41 +0100 Subject: [PATCH 1095/1891] docs: added zsh section to hooks install instruction (#1004) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d1d24c8c4..52d1af03f 100644 --- a/README.md +++ b/README.md @@ -447,6 +447,12 @@ systems. echo 'eval "$(rtx activate bash)"' >> ~/.bashrc ``` +#### Zsh + +``` +echo 'eval "$(rtx activate zsh)"' >> "${ZDOTDIR-$HOME}/.zshrc" +``` + #### Fish ``` From 33b762bddbb9d465de4172f7bc1a0af31f645102 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 17 Nov 2023 20:19:39 -0600 Subject: [PATCH 1096/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52d1af03f..c133ff09e 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,7 @@ Installing rtx consists of two steps. This depends on the shell you are using. Read more about this step in the [FAQ](#what-does-rtx-activate-do). -### 1. Download binary +### Download binary
Standalone From d632a1ccfd691a8ea3184292d0d77adf083f5720 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:16:01 -0600 Subject: [PATCH 1097/1891] chore(deps): bump itertools from 0.11.0 to 0.12.0 (#1010) Bumps [itertools](https://github.com/rust-itertools/itertools) from 0.11.0 to 0.12.0. - [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-itertools/itertools/compare/v0.11.0...v0.12.0) --- updated-dependencies: - dependency-name: itertools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 13 +++++++++++-- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc2ae9bd0..d7f19a5a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,6 +1115,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -1787,7 +1796,7 @@ dependencies = [ "indicatif", "indoc", "insta", - "itertools", + "itertools 0.12.0", "log", "num_cpus", "once_cell", @@ -2631,7 +2640,7 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd" dependencies = [ - "itertools", + "itertools 0.11.0", "nom", ] diff --git a/Cargo.toml b/Cargo.toml index c7d103d29..b53c171e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ indenter = "0.3" indexmap = { version = "2.0", features = ["serde"] } indicatif = { version = "0.17", features = ["default", "improved_unicode"] } indoc = "<3" -itertools = "0.11" +itertools = "0.12" log = "0.4" num_cpus = "1.14" once_cell = "1.18" From 9353c467daaf9ff08bbfb509957346a6571756af Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:34:41 -0600 Subject: [PATCH 1098/1891] cargo clippy (#1008) --- src/regex.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/regex.rs b/src/regex.rs index dcd53926b..2d9ff0e29 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,5 +1,3 @@ -pub use regex; - macro_rules! regex { ($re:literal $(,)?) => {{ static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); From 7eca4fd31b38ab693d7159c877d9a2de03d6c97a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:35:58 -0600 Subject: [PATCH 1099/1891] chore: Release --- Cargo.lock | 50 ++++++++++++++++++++++-------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 33 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7f19a5a2..43ae75b1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "color-spantrace" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" dependencies = [ "once_cell", "owo-colors", @@ -578,15 +578,16 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek", "ed25519", "serde", "sha2", "signature", + "subtle", "zeroize", ] @@ -630,9 +631,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys 0.48.0", @@ -660,9 +661,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" dependencies = [ "indenter", "once_cell", @@ -685,9 +686,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fiat-crypto" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a56f0780318174bad1c127063fd0c5fdfb35398e3cd79ffaab931a6c79df80" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" [[package]] name = "filetime" @@ -1770,7 +1771,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.4" +version = "2023.11.5" dependencies = [ "base64", "built", @@ -1843,12 +1844,12 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.24" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.4.1", - "errno 0.3.6", + "errno 0.3.7", "libc", "linux-raw-sys", "windows-sys 0.48.0", @@ -1856,9 +1857,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", "ring", @@ -2002,18 +2003,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", @@ -2096,11 +2097,12 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "signature" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", + "rand_core", ] [[package]] @@ -2977,9 +2979,9 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" [[package]] name = "zipsign-api" diff --git a/Cargo.toml b/Cargo.toml index b53c171e6..619eb4f3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.4" +version = "2023.11.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index c133ff09e..55d988cca 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.4 +rtx 2023.11.5 ``` Hook rtx into your shell (pick the right one for your shell): @@ -351,7 +351,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.4/rtx-v2023.11.4-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.5/rtx-v2023.11.5-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ab572d16b..db6d59cf6 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.4"; + version = "2023.11.5"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 1345216dc..31a233779 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.4" +.TH rtx 1 "rtx 2023.11.5" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.4 +v2023.11.5 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 0901064e6..afee3ec77 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.4 +Version: 2023.11.5 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From a69d3bbf6aa407d12bca4d761b85e43abe4ac7c4 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 25 Nov 2023 14:20:33 -0600 Subject: [PATCH 1100/1891] Update python.md --- docs/python.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/python.md b/docs/python.md index cfecef6df..d405632ab 100644 --- a/docs/python.md +++ b/docs/python.md @@ -1,7 +1,7 @@ # Python in rtx -The following are instructions for using the python rtx core plugin. This is used when -the "experimental" setting is "true" and there isn't a git plugin installed named "python" +The following are instructions for using the python rtx core plugin. The core plugin will be used so long as no plugin is manually +installed named "python" using `rtx plugins install python [GIT_URL]`. If you want to use [asdf-python](https://github.com/asdf-community/asdf-python) or [rtx-python](https://github.com/rtx-plugins/rtx-python) then use `rtx plugins install python GIT_URL`. From 9bc8d66ae9196332a85ca9f8e7db033b401e2fd5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 25 Nov 2023 14:21:25 -0600 Subject: [PATCH 1101/1891] Update python.md --- docs/python.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/python.md b/docs/python.md index d405632ab..b2bc3f65d 100644 --- a/docs/python.md +++ b/docs/python.md @@ -3,8 +3,6 @@ The following are instructions for using the python rtx core plugin. The core plugin will be used so long as no plugin is manually installed named "python" using `rtx plugins install python [GIT_URL]`. -If you want to use [asdf-python](https://github.com/asdf-community/asdf-python) or [rtx-python](https://github.com/rtx-plugins/rtx-python) then use `rtx plugins install python GIT_URL`. - The code for this is inside of the rtx repository at [`./src/plugins/core/python.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/python.rs). ## Usage From 3b5855a60e18af02254090db5e8e132395d5cffe Mon Sep 17 00:00:00 2001 From: Muescha <184316+muescha@users.noreply.github.com> Date: Sun, 26 Nov 2023 00:43:02 +0100 Subject: [PATCH 1102/1891] Update README.md: add hint for section asdf to rtx (#1013) * Update README.md: add hint for section asdf to rtx add hint for section asdf to rtx * moved the note some lines down * changed heading level * changed migration note to the features section --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 55d988cca..5eaccd02d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ## Features -- **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. +- **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. [See below for migration instructions](#how-do-i-migrate-from-asdf) - **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. - **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. - **No shims** - shims cause problems, they break `which`, and add overhead. By default, rtx @@ -498,6 +498,10 @@ in this project. the others are implemented. If your shell isn't currently supported I'd be happy to help you get yours integrated. +### Migrate from asdf + +If you're moving from asdf to rtx, please review [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) for guidance. + ## Uninstalling Use `rtx implode` to uninstall rtx. This will remove the rtx binary and all of its data. Use From 43f073a4edd6210fc7cb3d46c0216af0139221d5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:18:05 -0600 Subject: [PATCH 1103/1891] ensure cloudflare purge works --- scripts/publish-s3.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index b66e83a42..3496bc256 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -25,7 +25,7 @@ aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_d export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 export CLOUDFLARE_ZONE_ID=80d977fd09f01db52bec165778088891 -curl -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ +curl -fsS -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{ From 5d45085195b322cf80c92712b4fc175c0c918e5b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:21:40 -0600 Subject: [PATCH 1104/1891] chore: Release --- Cargo.lock | 59 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 5 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 +-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43ae75b1c..34342bd83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -735,9 +735,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -823,9 +823,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git2" @@ -842,15 +842,15 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata", + "regex-syntax", ] [[package]] @@ -885,9 +885,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -1017,9 +1017,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1027,17 +1027,16 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060" dependencies = [ + "crossbeam-deque", "globset", - "lazy_static", "log", "memchr", - "regex", + "regex-automata", "same-file", - "thread_local", "walkdir", "winapi-util", ] @@ -1351,9 +1350,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.59" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1383,9 +1382,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.95" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ "cc", "libc", @@ -1435,9 +1434,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" @@ -1548,9 +1547,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -1771,7 +1770,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.5" +version = "2023.11.6" dependencies = [ "base64", "built", @@ -2597,9 +2596,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2749,9 +2748,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index 619eb4f3d..b44b400ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.5" +version = "2023.11.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 5eaccd02d..1347c8456 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.5 +rtx 2023.11.6 ``` Hook rtx into your shell (pick the right one for your shell): @@ -79,6 +79,7 @@ v20.0.0 - [Installation](#installation) - [Download binary](#download-binary) - [Register shell hook](#register-shell-hook) + - [Migrate from asdf](#migrate-from-asdf) - [Uninstalling](#uninstalling) - [Shebang](#shebang) - [Configuration](#configuration) @@ -351,7 +352,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.5/rtx-v2023.11.5-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.6/rtx-v2023.11.6-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index db6d59cf6..dc20680c6 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.5"; + version = "2023.11.6"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 31a233779..0254d9559 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.5" +.TH rtx 1 "rtx 2023.11.6" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.5 +v2023.11.6 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index afee3ec77..1c7c566de 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.5 +Version: 2023.11.6 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 7f2485e00ba1793a78e6095e6437509227f4e385 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:00:57 -0600 Subject: [PATCH 1105/1891] fix cloudflare cache purge --- scripts/publish-s3.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 3496bc256..3cce83e14 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -25,20 +25,10 @@ aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_d export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 export CLOUDFLARE_ZONE_ID=80d977fd09f01db52bec165778088891 -curl -fsS -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ +curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ - --data '{ - "prefixes": [ - "/VERSION", - "/SHASUMS", - "/install.sh", - "/install.sh.sig", - "/rtx-latest-", - "/rpm/repodata/", - "/deb/dists/" - ] - }' + --data '{ "purge_everything": true }' #aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ # "/VERSION" \ From 818cb544b61052140361add8b8aca661c5df1c2e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:32:30 -0600 Subject: [PATCH 1106/1891] release: add shadow publishing to R2 --- .github/workflows/rtx.yml | 2 ++ scripts/publish-r2.sh | 10 ++++++++++ scripts/release.sh | 1 + 3 files changed, 13 insertions(+) create mode 100755 scripts/publish-r2.sh diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 8f3d0baa4..674f3ceaf 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -271,6 +271,8 @@ jobs: env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} + CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} - name: homebrew-tap push run: git push working-directory: homebrew-tap diff --git a/scripts/publish-r2.sh b/scripts/publish-r2.sh new file mode 100755 index 000000000..fc6ebc1e8 --- /dev/null +++ b/scripts/publish-r2.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euxo pipefail + +export AWS_DEFAULT_REGION=auto +export AWS_DEFAULT_OUTPUT=json +export AWS_ENDPOINT_URL=https://6e243906ff257b965bcae8025c2fc344.r2.cloudflarestorage.com +export AWS_ACCESS_KEY_ID=$CLOUDFLARE_ACCESS_KEY_ID +export AWS_SECRET_ACCESS_KEY=$CLOUDFLARE_SECRET_ACCESS_KEY + +./rtx/scripts/publish-s3.sh || true diff --git a/scripts/release.sh b/scripts/release.sh index 04f48997e..d0cff6877 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -61,6 +61,7 @@ gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_ NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh ./rtx/scripts/publish-s3.sh +./rtx/scripts/publish-r2.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb pushd homebrew-tap From 1450b2254bf491cb3284a0ae25cbb913959f3192 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:45:16 -0600 Subject: [PATCH 1107/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34342bd83..8bdfdb830 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1770,7 +1770,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.6" +version = "2023.11.7" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index b44b400ce..21d0d2019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.6" +version = "2023.11.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 1347c8456..4ed9baef3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.6 +rtx 2023.11.7 ``` Hook rtx into your shell (pick the right one for your shell): @@ -352,7 +352,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.6/rtx-v2023.11.6-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.7/rtx-v2023.11.7-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index dc20680c6..04a6e0355 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.6"; + version = "2023.11.7"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 0254d9559..61a705b68 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.6" +.TH rtx 1 "rtx 2023.11.7" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.6 +v2023.11.7 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 1c7c566de..b43dfb6e5 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.6 +Version: 2023.11.7 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 314f8ba49ceb44d6d9d12ba04b835b6c6e61b1b6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 21:54:34 -0600 Subject: [PATCH 1108/1891] release: use different S3 bucket name for R2 --- scripts/publish-r2.sh | 1 + scripts/publish-s3.sh | 36 ++++++++++++++---------------------- scripts/release.sh | 2 +- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/scripts/publish-r2.sh b/scripts/publish-r2.sh index fc6ebc1e8..8f97f7a46 100755 --- a/scripts/publish-r2.sh +++ b/scripts/publish-r2.sh @@ -6,5 +6,6 @@ export AWS_DEFAULT_OUTPUT=json export AWS_ENDPOINT_URL=https://6e243906ff257b965bcae8025c2fc344.r2.cloudflarestorage.com export AWS_ACCESS_KEY_ID=$CLOUDFLARE_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$CLOUDFLARE_SECRET_ACCESS_KEY +export AWS_S3_BUCKET=rtx ./rtx/scripts/publish-s3.sh || true diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 3cce83e14..f63d25893 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -5,23 +5,23 @@ set -euxo pipefail cache_day="max-age=86400,s-maxage=86400,public,immutable" cache_week="max-age=604800,s-maxage=604800,public,immutable" -aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://rtx.pub/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive +aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://$AWS_S3_BUCKET/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive -aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "rtx-latest-*" -aws s3 cp "$RELEASE_DIR" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" -aws s3 cp "$RELEASE_DIR/VERSION" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" -aws s3 cp "$RELEASE_DIR/install.sh" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress --content-type "text/plain" -aws s3 cp "$RELEASE_DIR/install.sh.sig" "s3://rtx.pub/" --cache-control "$cache_day" --no-progress -aws s3 cp "./rtx/schema/rtx.json" "s3://rtx.pub/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" -aws s3 cp "./rtx/schema/rtx.plugin.json" "s3://rtx.pub/schema/rtx.plugin.json" --cache-control "$cache_day" --no-progress --content-type "application/json" +aws s3 cp "$RELEASE_DIR" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "rtx-latest-*" +aws s3 cp "$RELEASE_DIR" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" +aws s3 cp "$RELEASE_DIR/VERSION" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR/install.sh" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --content-type "text/plain" +aws s3 cp "$RELEASE_DIR/install.sh.sig" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress +aws s3 cp "./rtx/schema/rtx.json" "s3://$AWS_S3_BUCKET/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" +aws s3 cp "./rtx/schema/rtx.plugin.json" "s3://$AWS_S3_BUCKET/schema/rtx.plugin.json" --cache-control "$cache_day" --no-progress --content-type "application/json" -aws s3 cp artifacts/rpm/rtx.repo s3://rtx.pub/rpm/ --cache-control "$cache_day" --no-progress -aws s3 cp artifacts/rpm/packages/ s3://rtx.pub/rpm/packages/ --cache-control "$cache_week" --no-progress --recursive -aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "repomd.xml*" -aws s3 cp artifacts/rpm/repodata/ s3://rtx.pub/rpm/repodata/ --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" +aws s3 cp artifacts/rpm/rtx.repo "s3://$AWS_S3_BUCKET/rpm/" --cache-control "$cache_day" --no-progress +aws s3 cp artifacts/rpm/packages/ "s3://$AWS_S3_BUCKET/rpm/packages/" --cache-control "$cache_week" --no-progress --recursive +aws s3 cp artifacts/rpm/repodata/ "s3://$AWS_S3_BUCKET/rpm/repodata/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "repomd.xml*" +aws s3 cp artifacts/rpm/repodata/ "s3://$AWS_S3_BUCKET/rpm/repodata/" --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" -aws s3 cp artifacts/deb/pool/ s3://rtx.pub/deb/pool/ --cache-control "$cache_week" --no-progress --recursive -aws s3 cp artifacts/deb/dists/ s3://rtx.pub/deb/dists/ --cache-control "$cache_day" --no-progress --no-progress --recursive +aws s3 cp artifacts/deb/pool/ "s3://$AWS_S3_BUCKET/deb/pool/" --cache-control "$cache_week" --no-progress --recursive +aws s3 cp artifacts/deb/dists/ "s3://$AWS_S3_BUCKET/deb/dists/" --cache-control "$cache_day" --no-progress --no-progress --recursive export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 export CLOUDFLARE_ZONE_ID=80d977fd09f01db52bec165778088891 @@ -29,11 +29,3 @@ curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUD -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{ "purge_everything": true }' - -#aws cloudfront create-invalidation --distribution-id E166HHA8DY7YLW --paths \ -# "/VERSION" \ -# "/SHASUMS*" \ -# "/install.sh" \ -# "/rtx-latest-*" \ -# "/rpm/repodata/*" \ -# "/deb/dists/*" diff --git a/scripts/release.sh b/scripts/release.sh index d0cff6877..4f421855f 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -60,7 +60,7 @@ gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_ NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh -./rtx/scripts/publish-s3.sh +AWS_S3_BUCKET=rtx.pub ./rtx/scripts/publish-s3.sh ./rtx/scripts/publish-r2.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb From 268f481a2c1257ab9127a7a4ac0c7026eae59175 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 21:56:22 -0600 Subject: [PATCH 1109/1891] chore: Release --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- man/man1/rtx.1 | 4 ++-- packaging/rpm/rtx.spec | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bdfdb830..2d993fd86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1770,7 +1770,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.7" +version = "2023.11.8" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 21d0d2019..3cccdcdc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.7" +version = "2023.11.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 4ed9baef3..5aa371a44 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.7 +rtx 2023.11.8 ``` Hook rtx into your shell (pick the right one for your shell): @@ -352,7 +352,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.7/rtx-v2023.11.7-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.8/rtx-v2023.11.8-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 04a6e0355..06100611f 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.7"; + version = "2023.11.8"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 61a705b68..486c382c3 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.7" +.TH rtx 1 "rtx 2023.11.8" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.7 +v2023.11.8 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b43dfb6e5..f584d1d49 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.7 +Version: 2023.11.8 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 76f9a19fe3dcf7a3f20461902a6e66cc4410e7d9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 26 Nov 2023 22:19:14 -0600 Subject: [PATCH 1110/1891] release: fix region env var --- scripts/publish-r2.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/publish-r2.sh b/scripts/publish-r2.sh index 8f97f7a46..f84c43038 100755 --- a/scripts/publish-r2.sh +++ b/scripts/publish-r2.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euxo pipefail -export AWS_DEFAULT_REGION=auto +export AWS_REGION=auto export AWS_DEFAULT_OUTPUT=json export AWS_ENDPOINT_URL=https://6e243906ff257b965bcae8025c2fc344.r2.cloudflarestorage.com export AWS_ACCESS_KEY_ID=$CLOUDFLARE_ACCESS_KEY_ID From a4f8c7b2f053423c5f1f0439ed0a491e0b6be65e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:53:28 -0600 Subject: [PATCH 1111/1891] ignore -SNAPSHOT versions (#1017) This filters out versions that should be ignored from prefix matches. Fixes #957 --- src/tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool.rs b/src/tool.rs index 2c429c646..0e3602c9f 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -376,7 +376,7 @@ impl Tool { } let query_regex = Regex::new(&format!("^{}([-.].+)?$", query))?; let version_regex = regex!( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|master)" + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|SNAPSHOT|master)" ); let versions = versions .into_iter() From ce01025cd2aa5f92fe1b8fd92d1cadeb851da46e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:07:00 -0600 Subject: [PATCH 1112/1891] logger: clean up info!() lines by removing target level (#1020) --- lefthook.yml | 5 ++++- src/logger.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lefthook.yml b/lefthook.yml index 731f3b547..b2148884e 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -1,7 +1,10 @@ pre-commit: - parallel: true + follow: true commands: pre-commit: run: just -v pre-commit lint: run: just -v lint +skip_output: + - meta + - summary diff --git a/src/logger.rs b/src/logger.rs index b89551f8e..c09cf4729 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -44,7 +44,7 @@ fn init_term_logger(level: LevelFilter) -> Box { .set_time_level(LevelFilter::Off) .set_thread_level(trace_level) .set_location_level(trace_level) - .set_target_level(LevelFilter::Error) + .set_target_level(trace_level) .build(), TerminalMode::Stderr, ColorChoice::Auto, From d7e03c30fc39e4f68e00bc9f526640411a8af7cb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:16:14 -0600 Subject: [PATCH 1113/1891] trusted-configs: move directory to data (#1021) I have had trouble deciding where to put this but I realized config is not a great place since it cannot really be shared on multiple machines --- src/config/config_file/mod.rs | 4 +--- src/migrate.rs | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 0254c17d4..3476fd820 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -194,9 +194,7 @@ pub fn untrust(path: &Path) -> Result<()> { } fn trust_path(path: &Path) -> PathBuf { - dirs::CONFIG - .join("trusted-configs") - .join(hash_to_str(&path)) + dirs::ROOT.join("trusted-configs").join(hash_to_str(&path)) } fn detect_config_file_type(path: &Path) -> Option { diff --git a/src/migrate.rs b/src/migrate.rs index e78fb4cd1..a9e099f2f 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -2,14 +2,22 @@ use std::path::Path; use color_eyre::eyre::Result; -use crate::{dirs, file}; +use crate::dirs::{CACHE, CONFIG, INSTALLS, PLUGINS, ROOT}; +use crate::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"))?; - move_trusted_configs()?; + move_subdirs(&INSTALLS.join("nodejs"), &INSTALLS.join("node"))?; + move_subdirs(&INSTALLS.join("golang"), &INSTALLS.join("go"))?; + move_subdirs(&PLUGINS.join("nodejs"), &PLUGINS.join("node"))?; + move_subdirs(&PLUGINS.join("golang"), &PLUGINS.join("go"))?; + move_dirs( + &CACHE.join("trusted-configs"), + &ROOT.join("trusted-configs"), + )?; + move_dirs( + &CONFIG.join("trusted-configs"), + &ROOT.join("trusted-configs"), + )?; Ok(()) } @@ -33,9 +41,7 @@ fn move_subdirs(from: &Path, to: &Path) -> Result<()> { Ok(()) } -fn move_trusted_configs() -> Result<()> { - let from = dirs::CACHE.join("trusted-configs"); - let to = dirs::CONFIG.join("trusted-configs"); +fn move_dirs(from: &Path, to: &Path) -> Result<()> { if from.exists() && !to.exists() { info!("migrating {} to {}", from.display(), to.display()); file::create_dir_all(to.parent().unwrap())?; From b4f4cf19bb0c6e3486a7c65bf97cf16698d3e3c4 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 15:51:58 -0600 Subject: [PATCH 1114/1891] fish: auto activate rtx with a vendor_conf.d script (#1022) * fish: auto activate rtx with a vendor_conf.d script * Update README.md --- README.md | 15 +++++++++++++++ scripts/build-tarball.sh | 14 ++++++++------ share/fish/vendor_conf.d/rtx.fish | 3 +++ 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 share/fish/vendor_conf.d/rtx.fish diff --git a/README.md b/README.md index 5aa371a44..9d750e3a1 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,13 @@ echo 'eval "$(rtx activate zsh)"' >> "${ZDOTDIR-$HOME}/.zshrc" echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` +> **Note:** +> +> For homebrew and possibly other installs rtx is automatically activated so +> this is not necessary. +> +> See [`RTX_FISH_AUTO_ACTIVATE=1`](#rtx_fish_auto_activate1) for more information. + #### Nushell ```nushell @@ -920,6 +927,14 @@ This will automatically answer yes or no to prompts. This is useful for scriptin Enables experimental features. +#### `RTX_FISH_AUTO_ACTIVATE=1` + +Configures the vendor_conf.d script for fish shell to automatically activate. +This file is automatically used in homebrew and potentially other installs to +automatically activate rtx without configuring. + +Defaults to enabled, set to "0" to disable. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index 24f96882a..32b379c39 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -64,12 +64,14 @@ if [ "${CROSS:-}" = "1" ]; then else cargo build "$@" fi -mkdir -p "dist/rtx/bin" -mkdir -p "dist/rtx/man/man1" -cp "target/$RUST_TRIPLE/release/rtx" "dist/rtx/bin/rtx" -cp README.md "dist/rtx/README.md" -cp LICENSE "dist/rtx/LICENSE" -cp man/man1/rtx.1 "dist/rtx/man/man1" +mkdir -p dist/rtx/bin +mkdir -p dist/rtx/man/man1 +mkdir -p dist/rtx/share/fish/vendor_conf.d +cp "target/$RUST_TRIPLE/release/rtx" dist/rtx/bin/rtx +cp README.md dist/rtx/README.md +cp LICENSE dist/rtx/LICENSE +cp {,dist/rtx/}man/man1/rtx.1 +cp {,dist/rtx/}share/fish/vendor_conf.d/rtx.fish cd dist tar -cJf "$BASENAME.tar.xz" rtx diff --git a/share/fish/vendor_conf.d/rtx.fish b/share/fish/vendor_conf.d/rtx.fish new file mode 100644 index 000000000..922ec25b4 --- /dev/null +++ b/share/fish/vendor_conf.d/rtx.fish @@ -0,0 +1,3 @@ +if [ "$RTX_FISH_AUTO_ACTIVATE" != "0" ] + rtx activate fish | source +end From f49873ffe2f44596745ae3cf0d99412a2ae50733 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:30:29 -0600 Subject: [PATCH 1115/1891] config: clean up error messages with config parse/trust failures (#1023) --- src/config/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 1addb86b2..c16dbed0e 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -267,7 +267,7 @@ fn load_rtxrc() -> Result { Ok(cf) => Ok(cf), Err(err) => Err(eyre!( "Error parsing {}: {:#}", - &settings_path.display(), + display_path(&settings_path), err )), }, @@ -401,7 +401,7 @@ fn load_all_config_files( // need to parse this config file None => match parse_config_file(&f, settings, legacy_filenames, tools) { Ok(cf) => Ok((f, cf)), - Err(err) => Err(eyre!("error reading config: {}\n{:#}", f.display(), err)), + Err(err) => Err(eyre!("error reading config: {}\n{err:#}", display_path(&f))), }, }) .collect::>>() From 6616e5a258194e95327b09ec2da7d087e7b96b96 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:37:17 -0600 Subject: [PATCH 1116/1891] chore: Release --- Cargo.lock | 124 +++++++++++++++++++++++++++++++---------- Cargo.toml | 2 +- README.md | 4 +- default.nix | 2 +- man/man1/rtx.1 | 4 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 102 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d993fd86..505dd26f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,9 +224,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" dependencies = [ "clap_builder", "clap_derive", @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" dependencies = [ "anstream", "anstyle", @@ -631,12 +631,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1141,9 +1141,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -1728,9 +1728,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866" dependencies = [ "cc", "getrandom", @@ -1770,7 +1770,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.8" +version = "2023.11.9" dependencies = [ "base64", "built", @@ -1848,7 +1848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.4.1", - "errno 0.3.7", + "errno 0.3.8", "libc", "linux-raw-sys", "windows-sys 0.48.0", @@ -2158,9 +2158,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -2672,9 +2672,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2682,9 +2682,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", @@ -2697,9 +2697,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -2709,9 +2709,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2719,9 +2719,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", @@ -2732,15 +2732,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -2810,6 +2810,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -2840,6 +2849,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -2852,6 +2876,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -2864,6 +2894,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -2876,6 +2912,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -2888,6 +2930,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -2900,6 +2948,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -2912,6 +2966,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -2924,6 +2984,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.19" diff --git a/Cargo.toml b/Cargo.toml index 3cccdcdc9..d74e565bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.8" +version = "2023.11.9" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 9d750e3a1..4a01bbb06 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.8 +rtx 2023.11.9 ``` Hook rtx into your shell (pick the right one for your shell): @@ -352,7 +352,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.8/rtx-v2023.11.8-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.11.9/rtx-v2023.11.9-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 06100611f..bec777b65 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.8"; + version = "2023.11.9"; src = lib.cleanSource ./.; diff --git a/man/man1/rtx.1 b/man/man1/rtx.1 index 486c382c3..d8314b33e 100644 --- a/man/man1/rtx.1 +++ b/man/man1/rtx.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.8" +.TH rtx 1 "rtx 2023.11.9" .SH NAME rtx \- Polyglot runtime manager (asdf rust clone) .SH SYNOPSIS @@ -150,6 +150,6 @@ Examples: $ rtx use \-g node@system Use system node everywhere unless overridden $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.8 +v2023.11.9 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f584d1d49..1704a51b3 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.8 +Version: 2023.11.9 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From e0fc57b47c6c81386fc95090d35fb0d9eab563e4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 18:05:00 -0600 Subject: [PATCH 1117/1891] docs: tweak to ubuntu test --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2ae2d6863..84cdcb37e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -113,7 +113,7 @@ This is for arm64, but you can change the arch to amd64 if you want. ``` finch run -ti --rm ubuntu apt update -y -apt install gpg sudo wget curl +apt install -y gpg sudo wget curl sudo install -dm 755 /etc/apt/keyrings wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list From 29df4885ae5757a9d21de41ad889e27ec47d8882 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 18:19:50 -0600 Subject: [PATCH 1118/1891] env-vars: display env vars when nothing else is passed (#1024) --- ...i__direnv__envrc__tests__direnv_envrc.snap | 2 +- src/cli/env_vars.rs | 28 +++++++++++++++---- .../rtx__cli__env__tests__env_json.snap | 3 +- ...__cli__env_vars__tests__show_env_vars.snap | 6 ++++ src/config/mod.rs | 15 +++++++--- src/test.rs | 2 ++ test/config/config.toml | 2 ++ 7 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index d5cee519e..dc6ec483a 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -7,6 +7,6 @@ watch_file ~/cwd/.test-tool-versions watch_file ~/.test-tool-versions watch_file ~/config/config.toml export JDXCODE_TINY=3.1.0 +export TEST_ENV_VAR=test-123 PATH_add ~/data/installs/dummy/ref-master/bin PATH_add ~/data/installs/tiny/3.1.0/bin - diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index c0e437df5..e27a22fba 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -6,6 +6,7 @@ use crate::config::config_file::{self, ConfigFile}; use crate::config::Config; use crate::dirs; use crate::env::RTX_DEFAULT_CONFIG_FILENAME; +use crate::file::display_path; use crate::output::Output; use super::args::env_var::{EnvVarArg, EnvVarArgParser}; @@ -31,12 +32,20 @@ pub struct EnvVars { /// Environment variable(s) to set /// e.g.: NODE_ENV=production - #[clap(value_parser = EnvVarArgParser, verbatim_doc_comment, required_unless_present = "remove")] - env_vars: Vec, + #[clap(value_parser = EnvVarArgParser, verbatim_doc_comment)] + env_vars: Option>, } impl Command for EnvVars { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { + fn run(self, config: Config, out: &mut Output) -> Result<()> { + if self.remove.is_none() && self.env_vars.is_none() { + for (key, value) in &config.env { + let source = config.env_sources.get(key).unwrap(); + rtxprintln!(out, "{key}={value} {}", display_path(source)); + } + return Ok(()); + } + let filename = self .file .unwrap_or_else(|| RTX_DEFAULT_CONFIG_FILENAME.to_string()); @@ -49,8 +58,10 @@ impl Command for EnvVars { } } - for ev in self.env_vars { - rtx_toml.update_env(&ev.key, ev.value); + if let Some(env_vars) = self.env_vars { + for ev in env_vars { + rtx_toml.update_env(&ev.key, ev.value); + } } rtx_toml.save() } @@ -74,7 +85,7 @@ mod tests { use insta::assert_snapshot; - use crate::{assert_cli, dirs, file}; + use crate::{assert_cli, assert_cli_snapshot, dirs, file}; fn remove_config_file(filename: &str) -> PathBuf { let cf_path = dirs::CURRENT.join(filename); @@ -82,6 +93,11 @@ mod tests { cf_path } + #[test] + fn test_show_env_vars() { + assert_cli_snapshot!("env-vars"); + } + #[test] fn test_env_vars() { // Using the default file diff --git a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap index 0f16d01dd..bcf8b91b8 100644 --- a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap +++ b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap @@ -4,6 +4,7 @@ expression: output --- { "JDXCODE_TINY": "3.1.0", - "PATH": "~/data/installs/tiny/3.1.0/bin:~/data/installs/dummy/ref-master/bin:$PATH" + "PATH": "~/data/installs/tiny/3.1.0/bin:~/data/installs/dummy/ref-master/bin:$PATH", + "TEST_ENV_VAR": "test-123" } diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap new file mode 100644 index 000000000..5e5bcdece --- /dev/null +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/env_vars.rs +expression: output +--- +TEST_ENV_VAR=test-123 ~/config/config.toml + diff --git a/src/config/mod.rs b/src/config/mod.rs index c16dbed0e..127c45309 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -38,6 +38,7 @@ pub struct Config { pub config_files: ConfigMap, pub tools: ToolMap, pub env: BTreeMap, + pub env_sources: HashMap, pub path_dirs: Vec, pub aliases: AliasMap, pub all_aliases: OnceCell, @@ -93,8 +94,10 @@ impl Config { } config_track.join().unwrap(); + let (env, env_sources) = load_env(&config_files); let config = Self { - env: load_env(&config_files), + env, + env_sources, path_dirs: load_path_dirs(&config_files), aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), @@ -432,16 +435,20 @@ fn parse_config_file( } } -fn load_env(config_files: &ConfigMap) -> BTreeMap { +fn load_env(config_files: &ConfigMap) -> (BTreeMap, HashMap) { let mut env = BTreeMap::new(); - for cf in config_files.values().rev() { + let mut env_sources = HashMap::new(); + for (source, cf) in config_files.iter().rev() { env.extend(cf.env()); + for k in cf.env().keys() { + env_sources.insert(k.clone(), source.clone()); + } for k in cf.env_remove() { // remove values set to "false" env.remove(&k); } } - env + (env, env_sources) } fn load_path_dirs(config_files: &ConfigMap) -> Vec { diff --git a/src/test.rs b/src/test.rs index 129a96137..030fe589d 100644 --- a/src/test.rs +++ b/src/test.rs @@ -48,6 +48,8 @@ pub fn reset_config() { file::write( env::HOME.join("config/config.toml"), indoc! {r#" + [env] + TEST_ENV_VAR = 'test-123' [settings] experimental = true verbose = true diff --git a/test/config/config.toml b/test/config/config.toml index 8006d1f52..2fd1df383 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -1,3 +1,5 @@ +[env] +TEST_ENV_VAR = 'test-123' [settings] experimental = true verbose = true From 5981e9b4193bbe65e8035baa8e47a021cbef5ae5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:26:36 -0600 Subject: [PATCH 1119/1891] fish: change vendor_conf.d script name to rtx-activate.fish (#1025) For some reason it does not work named "rtx.fish" --- scripts/build-tarball.sh | 2 +- share/fish/vendor_conf.d/{rtx.fish => rtx-activate.fish} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename share/fish/vendor_conf.d/{rtx.fish => rtx-activate.fish} (100%) diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index 32b379c39..d05b7982a 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -71,7 +71,7 @@ cp "target/$RUST_TRIPLE/release/rtx" dist/rtx/bin/rtx cp README.md dist/rtx/README.md cp LICENSE dist/rtx/LICENSE cp {,dist/rtx/}man/man1/rtx.1 -cp {,dist/rtx/}share/fish/vendor_conf.d/rtx.fish +cp {,dist/rtx/}share/fish/vendor_conf.d/rtx-activate.fish cd dist tar -cJf "$BASENAME.tar.xz" rtx diff --git a/share/fish/vendor_conf.d/rtx.fish b/share/fish/vendor_conf.d/rtx-activate.fish similarity index 100% rename from share/fish/vendor_conf.d/rtx.fish rename to share/fish/vendor_conf.d/rtx-activate.fish From 7dba0c1d0245cb8474f09ca015a3f0f208575481 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:32:56 -0600 Subject: [PATCH 1120/1891] docs: document shorthands Fixes #1001 --- README.md | 76 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 4a01bbb06..09c3244f5 100644 --- a/README.md +++ b/README.md @@ -215,8 +215,9 @@ You should note that rtx does not directly install these tools. Instead, it leverages plugins to install runtimes. See [plugins](#plugins) below. -[^cd]: Note that rtx does not modify "cd". It actually runs every time the prompt is _displayed_. -See the [FAQ](#what-does-rtx-activate-do). +[^cd]: + Note that rtx does not modify "cd". It actually runs every time the prompt is _displayed_. + See the [FAQ](#what-does-rtx-activate-do). ### Common commands @@ -648,7 +649,7 @@ NODE_ENV = false # unset a previously set NODE_ENV #### `[plugins]` - Specify Custom Plugin Repo URLs Use `[plugins]` to add/modify plugin shortnames. Note that this will only modify -*new* plugin installations. Existing plugins can use any URL. +_new_ plugin installations. Existing plugins can use any URL. ```toml [plugins] @@ -672,17 +673,17 @@ other developers to use a specific tool like rtx/asdf. They support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work in rtx and nvm. Here are some of the supported legacy version files: -| Plugin | "Legacy" (Idiomatic) Files | -|------------|----------------------------------------------------| -| crystal | `.crystal-version` | -| elixir | `.exenv-version` | -| go | `.go-version`, `go.mod` | -| java | `.java-version`, `.sdkmanrc` | -| node | `.nvmrc`, `.node-version` | -| python | `.python-version` | -| ruby | `.ruby-version`, `Gemfile` | -| terraform | `.terraform-version`, `.packer-version`, `main.tf` | -| yarn | `.yarnrc` | +| Plugin | "Legacy" (Idiomatic) Files | +| --------- | -------------------------------------------------- | +| crystal | `.crystal-version` | +| elixir | `.exenv-version` | +| go | `.go-version`, `go.mod` | +| java | `.java-version`, `.sdkmanrc` | +| node | `.nvmrc`, `.node-version` | +| python | `.python-version` | +| ruby | `.ruby-version`, `Gemfile` | +| terraform | `.terraform-version`, `.packer-version`, `main.tf` | +| yarn | `.yarnrc` | In rtx these are enabled by default. You can disable them with `rtx settings set legacy_version_file false`. There is a performance cost to having these when they're parsed as it's performed by the plugin in @@ -724,12 +725,12 @@ See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) Both `.rtx.toml` and `.tool-versions` support "scopes" which modify the behavior of the version: -* `ref:` - compile from a vcs (usually git) ref -* `prefix:` - use the latest version that matches the prefix. Useful for Go since `1.20` +- `ref:` - compile from a vcs (usually git) ref +- `prefix:` - use the latest version that matches the prefix. Useful for Go since `1.20` would only match `1.20` exactly but `prefix:1.20` will match `1.20.1` and `1.20.2` etc. -* `path:` - use a custom compiled version at the given path. One use-case is to re-use +- `path:` - use a custom compiled version at the given path. One use-case is to re-use Homebrew tools (e.g.: `path:/opt/homebrew/opt/node@20`). -* `sub-:` - subtracts PARTIAL_VERSION from ORIG_VERSION. This can +- `sub-:` - subtracts PARTIAL_VERSION from ORIG_VERSION. This can be used to express something like "2 versions behind lts" such as `sub-2:lts`. Or 1 minor version behind the latest version: `sub-0.1:latest`. @@ -902,6 +903,11 @@ Sets `RTX_JOBS=1` because only 1 plugin script can be executed at a time. Use a custom file for the shorthand aliases. This is useful if you want to share plugins within an organization. +Shorthands make it so when a user runs something like `rtx install elixir` rtx will +automatically install the [asdf-elixir](https://github.com/asdf-vm/asdf-elixir) plugin. By +default, it uses the shorthands in +[`src/default_shorthands.rs`](./src/default_shorthands.rs). + The file should be in this toml format: ```toml @@ -1118,10 +1124,10 @@ the current directory. These are intended to not be committed to version control The priority of these files goes in this order (bottom overrides top): -* `.rtx.toml` -* `.rtx.local.toml` -* `.rtx.{RTX_ENV}.toml` -* `.rtx.{RTX_ENV}.local.toml` +- `.rtx.toml` +- `.rtx.local.toml` +- `.rtx.{RTX_ENV}.toml` +- `.rtx.{RTX_ENV}.local.toml` Use `rtx doctor` to see which files are being used. @@ -1156,13 +1162,13 @@ time. They can be easily overridden by installing a plugin with the same name, e You can see the core plugins with `rtx plugin ls --core`. -* [Python](./docs/python.md) -* [NodeJS](./docs/node.md) -* [Ruby](./docs/ruby.md) -* [Go](./docs/go.md) -* [Java](./docs/java.md) -* [Deno (experimental)](./docs/deno.md) -* [Bun (experimental)](./docs/bun.md) +- [Python](./docs/python.md) +- [NodeJS](./docs/node.md) +- [Ruby](./docs/ruby.md) +- [Go](./docs/go.md) +- [Java](./docs/java.md) +- [Deno (experimental)](./docs/deno.md) +- [Bun (experimental)](./docs/bun.md) ## FAQs @@ -1310,9 +1316,9 @@ $ ls -l ~/.local/share/rtx/installs/node/20 There are some exceptions to this, such as the following: -* `rtx install node@20` -* `rtx latest node@20` -* `rtx upgrade node@20` +- `rtx install node@20` +- `rtx latest node@20` +- `rtx upgrade node@20` These will use the latest _available_ version of node-20.x. This generally makes sense because you wouldn't want to install a version that is already installed. @@ -1367,9 +1373,9 @@ For more information, see [What does `rtx activate` do?](#what-does-rtx-activate rtx uses [console.rs](https://docs.rs/console/latest/console/fn.colors_enabled.html) which honors the [clicolors spec](https://bixense.com/clicolors/): -* `CLICOLOR != 0`: ANSI colors are supported and should be used when the program isn’t piped. -* `CLICOLOR == 0`: Don’t output ANSI color escape codes. -* `CLICOLOR_FORCE != 0`: ANSI colors should be enabled no matter what. +- `CLICOLOR != 0`: ANSI colors are supported and should be used when the program isn’t piped. +- `CLICOLOR == 0`: Don’t output ANSI color escape codes. +- `CLICOLOR_FORCE != 0`: ANSI colors should be enabled no matter what. ### Is rtx secure? From 56d5df032afd9a9ac179ecb98a3d0ba299bd3d95 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:35:10 -0600 Subject: [PATCH 1121/1891] use .rtx.toml env vars on tool install (#1026) Fixes #768 --- src/plugins/core/node.rs | 10 +++++++--- src/plugins/core/python.rs | 18 +++++++++++------- src/plugins/core/ruby.rs | 23 ++++++++++++++--------- src/plugins/external_plugin.rs | 4 ++++ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index be84a11bf..5d6ef8e7e 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -107,7 +107,7 @@ impl NodePlugin { fn install_default_packages( &self, - settings: &Settings, + config: &Config, tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { @@ -119,11 +119,12 @@ impl NodePlugin { } pr.set_message(format!("installing default package: {}", package)); let npm = self.npm_path(tv); - CmdLineRunner::new(settings, npm) + CmdLineRunner::new(&config.settings, npm) .with_pr(pr) .arg("install") .arg("--global") .arg(package) + .envs(&config.env) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .execute()?; } @@ -142,6 +143,7 @@ impl NodePlugin { CmdLineRunner::new(&config.settings, self.node_path(tv)) .with_pr(pr) .arg("-v") + .envs(&config.env) .execute() } @@ -151,6 +153,7 @@ impl NodePlugin { .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) .arg("-v") + .envs(&config.env) .execute() } @@ -259,6 +262,7 @@ impl Plugin for NodePlugin { pr.set_message("running node-build"); let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()) .with_pr(pr) + .envs(&config.env) .arg(tv.version.as_str()); if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_FORCE_COMPILE { let make_opts = String::from(" -j") + &RTX_NODE_CONCURRENCY.to_string(); @@ -280,7 +284,7 @@ impl Plugin for NodePlugin { self.test_node(config, tv, pr)?; self.install_npm_shim(tv)?; self.test_npm(config, tv, pr)?; - self.install_default_packages(&config.settings, tv, pr)?; + self.install_default_packages(config, tv, pr)?; Ok(()) } } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 930f2f862..68c59928f 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -77,7 +77,7 @@ impl PythonPlugin { fn install_default_packages( &self, - settings: &Settings, + config: &Config, tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { @@ -85,7 +85,7 @@ impl PythonPlugin { return Ok(()); } pr.set_message("installing default packages"); - CmdLineRunner::new(settings, self.python_path(tv)) + CmdLineRunner::new(&config.settings, self.python_path(tv)) .with_pr(pr) .arg("-m") .arg("pip") @@ -93,6 +93,7 @@ impl PythonPlugin { .arg("--upgrade") .arg("-r") .arg(&*env::RTX_PYTHON_DEFAULT_PACKAGES_FILE) + .envs(&config.env) .execute() } @@ -116,7 +117,8 @@ impl PythonPlugin { .arg("-m") .arg("venv") .arg("--clear") - .arg(&virtualenv); + .arg(&virtualenv) + .envs(&config.env); if let Some(pr) = pr { cmd = cmd.with_pr(pr); } @@ -135,10 +137,11 @@ impl PythonPlugin { Ok(symlink_target == target) } - fn test_python(&self, config: &&Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn test_python(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("python --version"); CmdLineRunner::new(&config.settings, self.python_path(tv)) .arg("--version") + .envs(&config.env) .execute() } } @@ -173,7 +176,8 @@ impl Plugin for PythonPlugin { let mut cmd = CmdLineRunner::new(&config.settings, self.python_build_bin()) .with_pr(pr) .arg(tv.version.as_str()) - .arg(tv.install_path()); + .arg(tv.install_path()) + .envs(&config.env); if config.settings.verbose { cmd = cmd.arg("--verbose"); } @@ -196,9 +200,9 @@ impl Plugin for PythonPlugin { } } cmd.execute()?; - self.test_python(&config, tv, pr)?; + self.test_python(config, tv, pr)?; self.get_virtualenv(config, tv, Some(pr))?; - self.install_default_packages(&config.settings, tv, pr)?; + self.install_default_packages(config, tv, pr)?; Ok(()) } diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index f795eb9b0..223aceece 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -165,7 +165,7 @@ impl RubyPlugin { fn install_default_gems( &self, - settings: &Settings, + config: &Config, tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { @@ -177,7 +177,10 @@ impl RubyPlugin { } pr.set_message(format!("installing default gem: {}", package)); let gem = self.gem_path(tv); - let mut cmd = CmdLineRunner::new(settings, gem).with_pr(pr).arg("install"); + let mut cmd = CmdLineRunner::new(&config.settings, gem) + .with_pr(pr) + .arg("install") + .envs(&config.env); match package.split_once(' ') { Some((name, "--pre")) => cmd = cmd.arg(name).arg("--pre"), Some((name, version)) => cmd = cmd.arg(name).arg("--version").arg(version), @@ -194,6 +197,7 @@ impl RubyPlugin { CmdLineRunner::new(&config.settings, self.ruby_path(tv)) .with_pr(pr) .arg("-v") + .envs(&config.env) .execute() } @@ -202,6 +206,7 @@ impl RubyPlugin { CmdLineRunner::new(&config.settings, self.gem_path(tv)) .with_pr(pr) .arg("-v") + .envs(&config.env) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .execute() } @@ -239,19 +244,19 @@ impl RubyPlugin { fn install_cmd<'a>( &'a self, - settings: &'a Settings, + config: &'a Config, tv: &ToolVersion, pr: &'a ProgressReport, ) -> Result { let cmd = if *env::RTX_RUBY_INSTALL { - CmdLineRunner::new(settings, self.ruby_install_bin()) + CmdLineRunner::new(&config.settings, self.ruby_install_bin()) .args(self.install_args_ruby_install(tv)?) } else { - CmdLineRunner::new(settings, self.ruby_build_bin()) - .args(self.install_args_ruby_build(settings, tv)?) + CmdLineRunner::new(&config.settings, self.ruby_build_bin()) + .args(self.install_args_ruby_build(&config.settings, tv)?) .stdin_string(self.fetch_patches()?) }; - Ok(cmd.with_pr(pr)) + Ok(cmd.with_pr(pr).envs(&config.env)) } fn install_args_ruby_build( &self, @@ -358,12 +363,12 @@ impl Plugin for RubyPlugin { assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); pr.set_message("running ruby-build"); - self.install_cmd(&config.settings, tv, pr)?.execute()?; + self.install_cmd(config, tv, pr)?.execute()?; self.test_ruby(config, tv, pr)?; self.install_rubygems_hook(tv)?; self.test_gem(config, tv, pr)?; - self.install_default_gems(&config.settings, tv, pr)?; + self.install_default_gems(config, tv, pr)?; Ok(()) } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 6b1b9755a..c5575ba63 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -294,6 +294,10 @@ impl ExternalPlugin { ToolVersionRequest::Ref(_, v) => v, // should not have "ref:" prefix _ => &tv.version, }; + // add env vars from .rtx.toml files + for (key, value) in &config.env { + sm = sm.with_env(key, value.clone()); + } sm = sm .with_env( "RTX_INSTALL_PATH", From d773adb9591011a56658cfab44bd38b9dc6601db Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:54:47 -0600 Subject: [PATCH 1122/1891] hook-env: show env var status (#1027) Fixes #733 --- src/cli/hook_env.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 07c344760..dcc55dc4e 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -81,6 +81,11 @@ impl HookEnv { let status = installed_versions.into_iter().rev().join(" "); rtxstatusln!(out, "{}", truncate_str(&status, w - 4, "...")); } + let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env.clone()).to_patches(); + if !env_diff.is_empty() { + let env_diff = env_diff.into_iter().map(patch_to_status).join(" "); + rtxstatusln!(out, "{env_diff}"); + } } /// modifies the PATH and optionally DIRENV_DIFF env var if it exists @@ -154,6 +159,14 @@ impl HookEnv { } } +fn patch_to_status(patch: EnvDiffOperation) -> String { + match patch { + EnvDiffOperation::Add(k, _) => format!("+{}", k), + EnvDiffOperation::Change(k, _) => format!("~{}", k), + EnvDiffOperation::Remove(k) => format!("-{}", k), + } +} + #[cfg(test)] mod tests { use crate::assert_cli; From 399a75cc7e49f82f55c57a13447007f1163687d6 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:50:46 -0600 Subject: [PATCH 1123/1891] added RTX_TMP_DIR config (#1029) --- README.md | 70 ++++++++++++++++++++++++++++++++++++++---- src/cli/render_help.rs | 2 ++ src/env.rs | 3 +- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 09c3244f5..5366448ad 100644 --- a/README.md +++ b/README.md @@ -792,18 +792,30 @@ rtx can also be configured via environment variables. The following options are #### `RTX_DATA_DIR` -This is the directory where rtx stores plugins and tool installs. The default location is `~/.local/share/rtx`. +Default: `~/.local/share/rtx` or `$XDG_DATA_HOME/rtx` + +This is the directory where rtx stores plugins and tool installs. These are not supposed to be shared +across machines. #### `RTX_CACHE_DIR` -This is the directory where rtx stores internal cache. The default location is `~/.cache/rtx` on -Linux and -`~/Library/Caches/rtx` on macOS. +Default (Linux): `~/.cache/rtx` or `$XDG_CACHE_HOME/rtx` +Default (macOS): `~/Library/Caches/rtx` or `$XDG_CACHE_HOME/rtx` + +This is the directory where rtx stores internal cache. This is not supposed to be shared +across machines. It may be deleted at any time rtx is not running. + +#### `RTX_TMP_DIR` + +Default: [`std::env::temp_dir()`](https://doc.rust-lang.org/std/env/fn.temp_dir.html) implementation in rust + +This is used for temporary storage such as when installing tools. #### `RTX_CONFIG_FILE` -This is the path to the config file. The default is `~/.config/rtx/config.toml`. -(Or `$XDG_CONFIG_HOME/config.toml` if that is set) +Default: `$RTX_CONFIG_DIR/config.toml` (Usually ~/.config/rtx/config.toml) + +This is the path to the config file. #### `RTX_DEFAULT_TOOL_VERSIONS_FILENAME` @@ -1583,6 +1595,7 @@ every time rtx is initialized. Ideally, we can keep this behavior. + ## Commands ### `rtx activate [OPTIONS] [SHELL_TYPE]` @@ -1625,6 +1638,7 @@ Examples: $ rtx activate fish | source $ execx($(rtx activate xonsh)) ``` + ### `rtx alias get ` ``` @@ -1645,6 +1659,7 @@ Examples: $ rtx alias get node lts-hydrogen 20.0.0 ``` + ### `rtx alias ls [OPTIONS]` ``` @@ -1667,6 +1682,7 @@ Examples: $ rtx aliases node lts-hydrogen 20.0.0 ``` + ### `rtx alias set ` ``` @@ -1689,6 +1705,7 @@ Arguments: Examples: $ rtx alias set node lts-hydrogen 18.0.0 ``` + ### `rtx alias unset ` ``` @@ -1708,6 +1725,7 @@ Arguments: Examples: $ rtx alias unset node lts-hydrogen ``` + ### `rtx bin-paths` ``` @@ -1715,6 +1733,7 @@ List all the active runtime bin paths Usage: bin-paths ``` + ### `rtx cache clear` ``` @@ -1722,6 +1741,7 @@ Deletes all cache files in rtx Usage: cache clear ``` + ### `rtx completion [SHELL]` ``` @@ -1740,6 +1760,7 @@ Examples: $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx $ rtx completion fish > ~/.config/fish/completions/rtx.fish ``` + ### `rtx current [PLUGIN]` ``` @@ -1769,6 +1790,7 @@ Examples: $ rtx current python 3.11.0 3.10.0 ``` + ### `rtx deactivate` ``` @@ -1784,6 +1806,7 @@ Examples: $ rtx deactivate fish $ execx($(rtx deactivate xonsh)) ``` + ### `rtx direnv activate` ``` @@ -1802,6 +1825,7 @@ Examples: $ echo 'use rtx' > .envrc $ direnv allow ``` + ### `rtx doctor` ``` @@ -1813,6 +1837,7 @@ Examples: $ rtx doctor [WARN] plugin node is not installed ``` + ### `rtx env [OPTIONS] [TOOL@VERSION]...` ``` @@ -1844,6 +1869,7 @@ Examples: $ rtx env -s fish | source $ execx($(rtx env -s xonsh)) ``` + ### `rtx env-vars [OPTIONS] [ENV_VARS]...` ``` @@ -1870,6 +1896,7 @@ Options: Can be used multiple times. ``` + ### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` ``` @@ -1911,6 +1938,7 @@ Examples: # Run a command in a different directory: $ rtx x -C /path/to/project node@20 -- node ./app.js ``` + ### `rtx implode [OPTIONS]` ``` @@ -1927,6 +1955,7 @@ Options: --dry-run List directories that would be removed without actually removing them ``` + ### `rtx install [OPTIONS] [TOOL@VERSION]...` ``` @@ -1958,6 +1987,7 @@ Examples: $ rtx install node # install version specified in .tool-versions or .rtx.toml $ rtx install # installs everything specified in .tool-versions or .rtx.toml ``` + ### `rtx latest [OPTIONS] ` ``` @@ -1980,6 +2010,7 @@ Examples: $ rtx latest node # get the latest stable version of node 20.0.0 ``` + ### `rtx link [OPTIONS] ` ``` @@ -2012,6 +2043,7 @@ Examples: $ rtx link node@brew $(brew --prefix node) $ rtx use node@brew ``` + ### `rtx ls [OPTIONS]` ``` @@ -2068,6 +2100,7 @@ Examples: "python": [...] } ``` + ### `rtx ls-remote [PREFIX]` ``` @@ -2099,6 +2132,7 @@ Examples: 20.0.0 20.1.0 ``` + ### `rtx outdated [TOOL@VERSION]...` ``` @@ -2122,6 +2156,7 @@ Examples: Plugin Requested Current Latest node 20 20.0.0 20.1.0 ``` + ### `rtx plugins install [OPTIONS] [NAME] [GIT_URL]` ``` @@ -2169,6 +2204,7 @@ Examples: # install the node plugin using a specific ref $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 ``` + ### `rtx plugins link [OPTIONS] [PATH]` ``` @@ -2198,6 +2234,7 @@ Examples: # infer plugin name as "node" $ rtx plugins link ./rtx-node ``` + ### `rtx plugins ls [OPTIONS]` ``` @@ -2229,6 +2266,7 @@ Examples: node https://github.com/asdf-vm/asdf-node.git ruby https://github.com/asdf-vm/asdf-ruby.git ``` + ### `rtx plugins ls-remote [OPTIONS]` ``` @@ -2249,6 +2287,7 @@ Options: --only-names Only show the name of each plugin by default it will show a "*" next to installed plugins ``` + ### `rtx plugins uninstall [OPTIONS] ...` ``` @@ -2267,6 +2306,7 @@ Options: Examples: $ rtx uninstall node ``` + ### `rtx plugins update [PLUGIN]...` ``` @@ -2285,6 +2325,7 @@ Examples: $ rtx plugins update node # update only node $ rtx plugins update node#beta # specify a ref ``` + ### `rtx prune [OPTIONS] [PLUGINS]...` ``` @@ -2310,6 +2351,7 @@ Examples: rm -rf ~/.local/share/rtx/versions/node/20.0.0 rm -rf ~/.local/share/rtx/versions/node/20.0.1 ``` + ### `rtx reshim` ``` @@ -2336,6 +2378,7 @@ Examples: $ ~/.local/share/rtx/shims/node -v v20.0.0 ``` + ### `rtx self-update` ``` @@ -2347,6 +2390,7 @@ Supports: standalone, brew, deb, rpm Usage: self-update ``` + ### `rtx settings get ` ``` @@ -2367,6 +2411,7 @@ Examples: $ rtx settings get legacy_version_file true ``` + ### `rtx settings ls` ``` @@ -2383,6 +2428,7 @@ Examples: $ rtx settings legacy_version_file = false ``` + ### `rtx settings set ` ``` @@ -2402,6 +2448,7 @@ Arguments: Examples: $ rtx settings set legacy_version_file true ``` + ### `rtx settings unset ` ``` @@ -2418,6 +2465,7 @@ Arguments: Examples: $ rtx settings unset legacy_version_file ``` + ### `rtx shell [OPTIONS] [TOOL@VERSION]...` ``` @@ -2440,6 +2488,7 @@ Examples: $ node -v v20.0.0 ``` + ### `rtx sync node <--brew|--nvm|--nodenv>` ``` @@ -2464,6 +2513,7 @@ Examples: $ rtx sync node --brew $ rtx use -g node@18 - uses Homebrew-provided node ``` + ### `rtx sync python --pyenv` ``` @@ -2482,6 +2532,7 @@ Examples: $ rtx sync python --pyenv $ rtx use -g python@3.11.0 - uses pyenv-provided python ``` + ### `rtx trust [OPTIONS] [CONFIG_FILE]` ``` @@ -2512,6 +2563,7 @@ Examples: # trusts .rtx.toml in the current or parent directory $ rtx trust ``` + ### `rtx uninstall [OPTIONS] ...` ``` @@ -2535,6 +2587,7 @@ Examples: $ rtx uninstall node # will uninstall current node version $ rtx uninstall --all node@18.0.0 # will uninstall all node versions ``` + ### `rtx upgrade [TOOL@VERSION]...` ``` @@ -2548,6 +2601,7 @@ Arguments: e.g.: node@20 python@3.10 If not specified, all current tools will be upgraded ``` + ### `rtx use [OPTIONS] [TOOL@VERSION]...` ``` @@ -2594,6 +2648,7 @@ Examples: # will write the precise version (e.g.: 20.0.0) $ rtx use -g --pin node@20 ``` + ### `rtx version` ``` @@ -2601,6 +2656,7 @@ Show rtx version Usage: version ``` + ### `rtx where ` ``` @@ -2629,6 +2685,7 @@ Examples: $ rtx where node /home/jdx/.local/share/rtx/installs/node/20.0.0 ``` + ### `rtx which [OPTIONS] ` ``` @@ -2659,4 +2716,5 @@ Examples: $ rtx which node --version 20.0.0 ``` + diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f1774145c..9bede6bc3 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -39,6 +39,7 @@ fn render_commands() -> String { let mut doc = formatdoc!( r#" + ## Commands "# @@ -91,6 +92,7 @@ fn render_command(parent: Option<&str>, c: &clap::Command) -> Option { ``` {about} ``` + ", )) } diff --git a/src/env.rs b/src/env.rs index c461de7be..11f302d14 100644 --- a/src/env.rs +++ b/src/env.rs @@ -30,7 +30,8 @@ pub static RTX_CONFIG_DIR: Lazy = Lazy::new(|| var_path("RTX_CONFIG_DIR").unwrap_or_else(|| XDG_CONFIG_HOME.join("rtx"))); pub static RTX_DATA_DIR: Lazy = Lazy::new(|| var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx"))); -pub static RTX_TMP_DIR: Lazy = Lazy::new(|| temp_dir().join("rtx")); +pub static RTX_TMP_DIR: Lazy = + Lazy::new(|| var_path("RTX_TMP_DIR").unwrap_or_else(|| temp_dir().join("rtx"))); pub static RTX_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy = Lazy::new(|| { var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) From 066a1b07b6107644d7eda87ec94674563c5e50ff Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:59:42 -0600 Subject: [PATCH 1124/1891] node: allow node-build to set a default concurrency (#1030) --- src/env.rs | 5 ++--- src/plugins/core/node.rs | 16 +++++----------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/env.rs b/src/env.rs index 11f302d14..5a45a18c6 100644 --- a/src/env.rs +++ b/src/env.rs @@ -138,12 +138,11 @@ pub static PYENV_ROOT: Lazy = pub static RTX_NODE_BUILD_REPO: Lazy = Lazy::new(|| { var("RTX_NODE_BUILD_REPO").unwrap_or_else(|_| "https://github.com/nodenv/node-build.git".into()) }); -pub static RTX_NODE_CONCURRENCY: Lazy = Lazy::new(|| { +pub static RTX_NODE_CONCURRENCY: Lazy> = Lazy::new(|| { var("RTX_NODE_CONCURRENCY") .ok() .and_then(|v| v.parse::().ok()) - .unwrap_or(num_cpus::get() / 2) - .max(1) + .map(|v| v.max(1)) }); pub static RTX_NODE_VERBOSE_INSTALL: Lazy> = Lazy::new(|| var_option_bool("RTX_NODE_VERBOSE_INSTALL")); diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 5d6ef8e7e..84bc1985f 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -265,17 +265,11 @@ impl Plugin for NodePlugin { .envs(&config.env) .arg(tv.version.as_str()); if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_FORCE_COMPILE { - let make_opts = String::from(" -j") + &RTX_NODE_CONCURRENCY.to_string(); - cmd = cmd - .env( - "MAKE_OPTS", - env::var("MAKE_OPTS").unwrap_or_default() + &make_opts, - ) - .env( - "NODE_MAKE_OPTS", - env::var("NODE_MAKE_OPTS").unwrap_or_default() + &make_opts, - ) - .arg("--compile"); + if let Some(concurrency) = *RTX_NODE_CONCURRENCY { + let make_opts = env::var("MAKE_OPTS").unwrap_or_default(); + cmd = cmd.env("MAKE_OPTS", format!("{} -j{}", make_opts, concurrency)); + } + cmd = cmd.arg("--compile"); } if self.verbose_install(&config.settings) { cmd = cmd.arg("--verbose"); From 3938da779a0f4e9fdf979142304b98e1b17b2464 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:39:06 -0600 Subject: [PATCH 1125/1891] added RTX_ALL_FORCE_COMPILE config (#1031) Fixes https://github.com/jdx/rtx/issues/719 --- Cargo.lock | 11 +++++++++++ Cargo.toml | 6 +++++- README.md | 10 ++++++++++ docs/node.md | 15 ++++++--------- src/env.rs | 19 +++++++++++++++++-- 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 505dd26f7..777a5c109 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1816,6 +1816,7 @@ dependencies = [ "shell-escape", "shell-words", "simplelog", + "sys-info", "tar", "tera", "terminal_size", @@ -2200,6 +2201,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sys-info" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "system-configuration" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index d74e565bb..778fdad1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,10 @@ lto = true [dependencies] base64 = "<0.22" -chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } +chrono = { version = "0.4", default-features = false, features = [ + "std", + "clock", +] } clap = { version = "4.4", features = ["env", "derive", "string"] } clap_complete = "4.2" color-eyre = "0.6" @@ -93,6 +96,7 @@ sha2 = "0.10" shell-escape = "0.1" shell-words = "1.1" simplelog = { version = "0.12" } +sys-info = "0.9" tar = "0.4" tera = { version = "1.19", default-features = false } terminal_size = "0.3" diff --git a/README.md b/README.md index 5366448ad..1f516ad4d 100644 --- a/README.md +++ b/README.md @@ -945,6 +945,16 @@ This will automatically answer yes or no to prompts. This is useful for scriptin Enables experimental features. +#### `RTX_ALL_FORCE_COMPILE=1` + +Default: false unless running NixOS or Alpine (let me know if others should be added) + +Do not use precompiled binaries for all languages. Useful if running on a Linux distrobution +like Alpine that does not use glibc and therefore likely won't be able to run precompiled binaries. + +Note that this needs to be setup for each language. File a ticket if you notice a language that is not +working with this config. + #### `RTX_FISH_AUTO_ACTIVATE=1` Configures the vendor_conf.d script for fish shell to automatically activate. diff --git a/docs/node.md b/docs/node.md index 55d3a6200..e364984be 100644 --- a/docs/node.md +++ b/docs/node.md @@ -1,6 +1,6 @@ # Node in rtx -The following are instructions for using the node rtx core plugin. This is used when there isn't a +The following are instructions for using the node rtx core plugin. This is used when there isn't a git plugin installed named "node". If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) or @@ -19,22 +19,20 @@ $ rtx use -g node@20 Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. - ## Requirements rtx uses [node-build](https://github.com/nodenv/node-build) to install node runtimes, you need to ensure the [dependencies](https://github.com/nodenv/node-build/wiki#suggested-build-environment) are installed before installing node. - ## Configuration `node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-node` has a few extra configuration variables: - `RTX_NODE_BUILD_REPO` [string]: the default is `https://github.com/nodenv/node-build.git` - `RTX_NODE_VERBOSE_INSTALL` [bool]: Enables verbose output for downloading and building. -- `RTX_NODE_FORCE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries +- `RTX_NODE_FORCE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries. Can also be set across all languages with [`RTX_NODE_FORCE_COMPILE`](https://github.com/jdx/rtx#rtx_node_force_compile1) - `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores - `RTX_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` -- `NODEJS_ORG_MIRROR` [string]: (Legacy) overrides the default mirror used for downloading the +- `NODEJS_ORG_MIRROR` [string]: (Legacy) overrides the default mirror used for downloading the distributions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var ## Default node packages @@ -53,7 +51,6 @@ You can specify a non-default location of this file by setting a `RTX_NODE_DEFAU rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. To ease migration, you can have also have it read an existing `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `node` isn't defined in `.tool-versions`/`.rtx.toml`. - ## Running the wrapped node-build command We provide a command for running the installed `node-build` command: @@ -79,8 +76,8 @@ _Note that this command only lists the current `node-build` definitions. You mig ### Manually updating node-build definitions -Every new node version needs to have a definition file in the `node-build` repository. -`rtx-node` already tries to update `node-build` on every new version installation, but if you +Every new node version needs to have a definition file in the `node-build` repository. +`rtx-node` already tries to update `node-build` on every new version installation, but if you want to update `node-build` manually for some reason you can clear the cache and list the versions: ```bash @@ -90,6 +87,6 @@ rtx ls-remote node ## "nodejs" -> "node" Alias -You cannot install/use a plugin named "nodejs". If you attempt this, rtx will just renamed it to +You cannot install/use a plugin named "nodejs". If you attempt this, rtx will just renamed it to "node". See the [FAQ](https://github.com/jdx/rtx#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) for an explanation. diff --git a/src/env.rs b/src/env.rs index 5a45a18c6..867045e80 100644 --- a/src/env.rs +++ b/src/env.rs @@ -115,7 +115,14 @@ pub static RTX_ALWAYS_KEEP_DOWNLOAD: Lazy = Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_DOWNLOAD")); pub static RTX_ALWAYS_KEEP_INSTALL: Lazy = Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_INSTALL")); - +pub static RTX_ALL_FORCE_COMPILE: Lazy = + Lazy::new(|| match var_option_bool("RTX_ALL_FORCE_COMPILE") { + Some(v) => v, + None => matches!( + linux_distro().unwrap_or_default().as_str(), + "alpine" | "nixos" + ), + }); #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); @@ -146,7 +153,8 @@ pub static RTX_NODE_CONCURRENCY: Lazy> = Lazy::new(|| { }); pub static RTX_NODE_VERBOSE_INSTALL: Lazy> = Lazy::new(|| var_option_bool("RTX_NODE_VERBOSE_INSTALL")); -pub static RTX_NODE_FORCE_COMPILE: Lazy = Lazy::new(|| var_is_true("RTX_NODE_FORCE_COMPILE")); +pub static RTX_NODE_FORCE_COMPILE: Lazy = + Lazy::new(|| *RTX_ALL_FORCE_COMPILE || var_is_true("RTX_NODE_FORCE_COMPILE")); pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { let p = HOME.join(".default-nodejs-packages"); @@ -391,6 +399,13 @@ fn log_file_level() -> LevelFilter { } } +fn linux_distro() -> Option { + match sys_info::linux_os_release() { + Ok(release) => release.id, + _ => None, + } +} + #[cfg(test)] mod tests { use std::collections::HashMap; From 722c57d9c7542424c2653e3a3bf1fa66c36d7333 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 30 Nov 2023 17:26:21 -0600 Subject: [PATCH 1126/1891] simplify building rtx by removing separate xtask package (#1032) --- .cargo/config.toml | 2 - Cargo.lock | 11 +---- Cargo.toml | 49 ++++++++++------------ completions/_rtx | 38 +++++++++++++++++ completions/rtx.bash | 50 +++++++++++++++++++++- completions/rtx.fish | 91 +++++++++++++++++++++++----------------- justfile | 4 +- src/cli/mod.rs | 8 ++++ src/cli/render_mangen.rs | 54 ++++++++++++++++++++++++ src/lib.rs | 46 -------------------- xtask/Cargo.toml | 11 ----- xtask/src/main.rs | 57 ------------------------- 12 files changed, 225 insertions(+), 196 deletions(-) create mode 100644 src/cli/render_mangen.rs delete mode 100644 src/lib.rs delete mode 100644 xtask/Cargo.toml delete mode 100644 xtask/src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index cc0fa5c45..73f82bb72 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,4 +1,2 @@ [env] RUST_TEST_THREADS = '1' -[alias] -xtask = "run -p xtask --" diff --git a/Cargo.lock b/Cargo.lock index 777a5c109..71bb7da8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1777,6 +1777,7 @@ dependencies = [ "chrono", "clap", "clap_complete", + "clap_mangen", "color-eyre", "color-print", "console", @@ -1787,6 +1788,7 @@ dependencies = [ "dotenvy", "duct", "exec", + "eyre", "filetime", "flate2", "fslock", @@ -3029,15 +3031,6 @@ dependencies = [ "libc", ] -[[package]] -name = "xtask" -version = "0.1.0" -dependencies = [ - "clap_mangen", - "color-eyre", - "rtx-cli", -] - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 778fdad1d..182e6f2eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,28 +12,19 @@ license = "MIT" keywords = ["rtx"] categories = ["command-line-utilities"] include = [ - "src/**/*.rs", - "src/plugins/core/assets/**", - "/Cargo.lock", - "/LICENSE", - "/README.md", - "/build.rs", - "/zipsign.pub", + "src/**/*.rs", + "src/plugins/core/assets/**", + "/Cargo.lock", + "/LICENSE", + "/README.md", + "/build.rs", + "/zipsign.pub", ] rust-version = "1.65.0" build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[workspace] -members = ["xtask"] - -[lib] -name = "rtx" -path = "src/lib.rs" -test = false -doctest = false - [[bin]] name = "rtx" path = "src/main.rs" @@ -48,11 +39,12 @@ lto = true [dependencies] base64 = "<0.22" chrono = { version = "0.4", default-features = false, features = [ - "std", - "clock", + "std", + "clock", ] } clap = { version = "4.4", features = ["env", "derive", "string"] } clap_complete = "4.2" +clap_mangen = { version = "0.2", optional = true } color-eyre = "0.6" color-print = "0.3" console = "0.15" @@ -61,6 +53,7 @@ dialoguer = { version = "0.11", features = [] } dirs-next = "2.0" dotenvy = "0.15" duct = "0.13" +eyre = "0.6" filetime = "0.2" flate2 = "1.0" fslock = "0.2" @@ -79,15 +72,15 @@ rand = "0.8" rayon = "1.8" regex = "1.9" reqwest = { version = "0.11.17", default-features = false, features = [ - "blocking", - "json", - "gzip", + "blocking", + "json", + "gzip", ] } rmp-serde = "1.1.2" self_update = { version = "<1", default-features = false, optional = true, features = [ - "archive-tar", - "compression-flate2", - "signatures", + "archive-tar", + "compression-flate2", + "signatures", ] } serde = "1.0" serde_derive = "1.0" @@ -130,10 +123,10 @@ sign-tag = true sign-commit = true pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ - { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, - { file = "README.md", search = "https://github.com/jdx/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdx/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, - { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, - { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, + { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, + { file = "README.md", search = "https://github.com/jdx/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdx/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, + { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, + { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, ] [package.metadata.binstall] diff --git a/completions/_rtx b/completions/_rtx index 56db671a4..0ab7e929e 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1791,6 +1791,28 @@ Sets --jobs=1]' \ '--help[Print help]' \ && ret=0 ;; +(render-mangen) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +\[default\: 4\]]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +\[default\: 4\]]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; (help) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help_commands" \ @@ -2107,6 +2129,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(render-mangen) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (help) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -2168,6 +2194,7 @@ _rtx_commands() { 'where:Display the installation path for a runtime' \ 'which:Shows the path that a bin name points to' \ 'render-help:internal command to generate markdown from help' \ +'render-mangen:internal command to generate markdown from help' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx commands' commands "$@" @@ -2534,6 +2561,7 @@ _rtx__help_commands() { 'where:Display the installation path for a runtime' \ 'which:Shows the path that a bin name points to' \ 'render-help:internal command to generate markdown from help' \ +'render-mangen:internal command to generate markdown from help' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx help commands' commands "$@" @@ -2850,6 +2878,16 @@ _rtx__render-help_commands() { local commands; commands=() _describe -t commands 'rtx render-help commands' commands "$@" } +(( $+functions[_rtx__help__render-mangen_commands] )) || +_rtx__help__render-mangen_commands() { + local commands; commands=() + _describe -t commands 'rtx help render-mangen commands' commands "$@" +} +(( $+functions[_rtx__render-mangen_commands] )) || +_rtx__render-mangen_commands() { + local commands; commands=() + _describe -t commands 'rtx render-mangen commands' commands "$@" +} (( $+functions[_rtx__help__reshim_commands] )) || _rtx__help__reshim_commands() { local commands; commands=() diff --git a/completions/rtx.bash b/completions/rtx.bash index 54a70bc38..083bdb624 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -108,6 +108,9 @@ _rtx() { rtx,render-help) cmd="rtx__render__help" ;; + rtx,render-mangen) + cmd="rtx__render__mangen" + ;; rtx,reshim) cmd="rtx__reshim" ;; @@ -321,6 +324,9 @@ _rtx() { rtx__help,render-help) cmd="rtx__help__render__help" ;; + rtx__help,render-mangen) + cmd="rtx__help__render__mangen" + ;; rtx__help,reshim) cmd="rtx__help__reshim" ;; @@ -547,7 +553,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -y -v -h -V --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help help" + opts="-j -r -y -v -h -V --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1405,7 +1411,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1992,6 +1998,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__render__mangen) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__reshim) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2848,6 +2868,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__render__mangen) + opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__reshim) opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index ea83de65b..1b9f3a53e 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -48,6 +48,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_use_subcommand" -f -a "render-mangen" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -831,45 +832,57 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -s y -l yes -d 'Ans complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +[default: 4]' -r +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s y -l yes -d 'Answer yes to all prompts' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s h -l help -d 'Print help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "render-mangen" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/justfile b/justfile index c6b860b61..a279858ad 100644 --- a/justfile +++ b/justfile @@ -107,8 +107,8 @@ render-completions: build NO_COLOR=1 rtx completion fish > completions/rtx.fish # regenerate manpages -render-mangen: - NO_COLOR=1 cargo xtask mangen +render-mangen: build + NO_COLOR=1 rtx render-mangen # called by lefthook precommit hook pre-commit: render-help render-completions render-mangen diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 9f206dad2..aef62f9a5 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -38,6 +38,8 @@ mod plugins; mod prune; #[cfg(debug_assertions)] mod render_help; +#[cfg(feature = "clap_mangen")] +mod render_mangen; mod reshim; #[cfg(feature = "self_update")] mod self_update; @@ -100,6 +102,9 @@ pub enum Commands { #[cfg(debug_assertions)] RenderHelp(render_help::RenderHelp), + + #[cfg(feature = "clap_mangen")] + RenderMangen(render_mangen::RenderMangen), } impl Commands { @@ -146,6 +151,9 @@ impl Commands { #[cfg(debug_assertions)] Self::RenderHelp(cmd) => cmd.run(config, out), + + #[cfg(feature = "clap_mangen")] + Self::RenderMangen(cmd) => cmd.run(config, out), } } } diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs new file mode 100644 index 000000000..85bd2a861 --- /dev/null +++ b/src/cli/render_mangen.rs @@ -0,0 +1,54 @@ +use crate::cli::{version, Cli}; +use eyre::Result; +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; + +use crate::cli::command::Command; +use crate::config::Config; +use crate::output::Output; + +/// internal command to generate markdown from help +#[derive(Debug, clap::Args)] +#[clap(hide = true)] +pub struct RenderMangen {} + +impl Command for RenderMangen { + fn run(self, _config: Config, _out: &mut Output) -> Result<()> { + let cli = Cli::command() + .version(&*version::RAW_VERSION) + .disable_colored_help(true); + + let man = clap_mangen::Man::new(cli); + let mut buffer: Vec = Default::default(); + man.render(&mut buffer)?; + + let out_dir = project_root().join("man").join("man1"); + fs::create_dir_all(&out_dir)?; + fs::write(out_dir.join("rtx.1"), buffer)?; + + Ok(()) + } +} + +fn project_root() -> PathBuf { + Path::new(&env!("CARGO_MANIFEST_DIR")) + .ancestors() + .nth(1) + .unwrap() + .to_path_buf() +} + +#[cfg(test)] +mod tests { + use crate::env::HOME; + use crate::{assert_cli, file}; + + #[test] + fn test_render_mangen() { + let out_dir = HOME.parent().unwrap().join("man").join("man1"); + let orig = file::read_to_string(out_dir.join("rtx.1")).unwrap(); + assert_cli!("render-mangen"); + file::write(out_dir.join("rtx.1"), orig).unwrap(); + } +} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 8df8f9d5b..000000000 --- a/src/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -#[macro_use] -extern crate log; - -#[macro_use] -mod output; - -#[macro_use] -mod regex; - -#[macro_use] -pub mod cli; - -mod build_time; -mod cache; -pub mod cmd; -mod config; -mod default_shorthands; -mod direnv; -mod dirs; -mod duration; -#[allow(dead_code)] -mod env; -mod env_diff; -mod errors; -mod fake_asdf; -mod file; -mod git; -pub mod github; -mod hash; -mod hook_env; -mod http; -mod lock_file; -mod plugins; -mod rand; -mod runtime_symlinks; -mod shell; -mod shims; -mod shorthands; -mod tera; -#[cfg(test)] -mod test; -pub mod timeout; -mod toml; -mod tool; -mod toolset; -mod ui; diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml deleted file mode 100644 index 44c941e51..000000000 --- a/xtask/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "xtask" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -clap_mangen = "0.2.15" -color-eyre = "0.6.2" -rtx-cli = {path = ".."} diff --git a/xtask/src/main.rs b/xtask/src/main.rs deleted file mode 100644 index 5effd7f49..000000000 --- a/xtask/src/main.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::env; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::exit; - -use color_eyre::eyre::Result; - -use rtx::cli::{version, Cli}; - -fn main() { - if let Err(e) = try_main() { - eprintln!("{}", e); - exit(-1); - } -} - -fn try_main() -> Result<()> { - let task = env::args().nth(1); - match task.as_deref() { - Some("mangen") => mangen()?, - _ => print_help(), - } - Ok(()) -} - -fn print_help() { - eprintln!( - "Tasks: - -mangen builds man pages -" - ) -} - -fn mangen() -> Result<()> { - let cli = Cli::command() - .version(&*version::RAW_VERSION) - .disable_colored_help(true); - - let man = clap_mangen::Man::new(cli); - let mut buffer: Vec = Default::default(); - man.render(&mut buffer)?; - - let out_dir = project_root().join("man").join("man1"); - fs::create_dir_all(&out_dir)?; - fs::write(out_dir.join("rtx.1"), buffer)?; - - Ok(()) -} - -fn project_root() -> PathBuf { - Path::new(&env!("CARGO_MANIFEST_DIR")) - .ancestors() - .nth(1) - .unwrap() - .to_path_buf() -} From 1bd8b52887f310ee0514a9e3b5d36105dfaf419a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 30 Nov 2023 17:45:04 -0600 Subject: [PATCH 1127/1891] uninstall: show tool name when attempting to uninstall a nonexistant plugin (#1033) --- src/cli/uninstall.rs | 16 +++++++++------- src/tool.rs | 8 +++++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index ef1fafb46..894f1fb34 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::{bail, eyre, Result}; use console::style; use crate::cli::args::tool::{ToolArg, ToolArgParser}; @@ -46,10 +46,7 @@ impl Command for Uninstall { }) .collect::>(); if tvs.is_empty() { - warn!( - "no versions found for {}", - style(&tool.name).cyan().for_stderr() - ); + warn!("no versions found for {}", style(&tool).cyan().for_stderr()); } tool_versions.extend(tvs); } @@ -64,8 +61,13 @@ impl Command for Uninstall { } None => { let ts = ToolsetBuilder::new().build(&mut config)?; - let tvl = ts.versions.get(&a.plugin).expect("no versions found"); - tvl.versions.clone() + match ts.versions.get(&a.plugin) { + Some(tvl) => tvl.versions.clone(), + None => bail!( + "no versions found for {}", + style(&tool).cyan().for_stderr() + ), + } } }; Ok(tvs diff --git a/src/tool.rs b/src/tool.rs index 0e3602c9f..3491e3e05 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, HashMap}; -use std::fmt::Debug; +use std::fmt::{Debug, Display}; use std::fs::File; use std::path::{Path, PathBuf}; @@ -423,6 +423,12 @@ impl Debug for Tool { } } +impl Display for Tool { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", &self.name) + } +} + fn find_match_in_list(list: &[String], query: &str) -> Option { let v = match list.contains(&query.to_string()) { true => Some(query.to_string()), From 9d72a4649fef79fa869a6e39aa083862ba7d3276 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 30 Nov 2023 18:17:48 -0600 Subject: [PATCH 1128/1891] migrate: remove deprecated non-core plugins (#1034) If rtx-nodejs (or other deprecated plugins) is installed it should be removed in favor of the core plugins --- e2e/test_nodejs | 4 ++-- src/main.rs | 4 +--- src/migrate.rs | 62 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/e2e/test_nodejs b/e2e/test_nodejs index f78838b6a..aa28d8f97 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -11,8 +11,8 @@ assert_contains "rtx x node@lts/hydrogen -- node --version" "v18." assert "rtx x -- node --version" "v20.0.0" assert_contains "rtx node node-build --version" "node-build " -# test rtx-nodejs -rtx plugin i nodejs https://github.com/rtx-plugins/rtx-nodejs +# test asdf-nodejs +rtx plugin i nodejs https://github.com/asdf-vm/asdf-nodejs.git rtx use nodejs@20.1.0 assert "rtx x -- node --version" "v20.1.0" assert_contains "rtx node nodebuild --version" "node-build " diff --git a/src/main.rs b/src/main.rs index 302312d87..b83251d91 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,9 +77,7 @@ 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); - } + migrate::run(); let config = Config::load()?; let config = shims::handle_shim(config, args, out)?; diff --git a/src/migrate.rs b/src/migrate.rs index a9e099f2f..2c8c81794 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -1,25 +1,31 @@ +use std::fs; use std::path::Path; -use color_eyre::eyre::Result; +use eyre::Result; +use rayon::Scope; use crate::dirs::{CACHE, CONFIG, INSTALLS, PLUGINS, ROOT}; use crate::file; -pub fn run() -> Result<()> { - move_subdirs(&INSTALLS.join("nodejs"), &INSTALLS.join("node"))?; - move_subdirs(&INSTALLS.join("golang"), &INSTALLS.join("go"))?; - move_subdirs(&PLUGINS.join("nodejs"), &PLUGINS.join("node"))?; - move_subdirs(&PLUGINS.join("golang"), &PLUGINS.join("go"))?; - move_dirs( - &CACHE.join("trusted-configs"), - &ROOT.join("trusted-configs"), - )?; - move_dirs( - &CONFIG.join("trusted-configs"), - &ROOT.join("trusted-configs"), - )?; +pub fn run() { + rayon::scope(|s| { + task(s, || rename_plugin("nodejs", "node")); + task(s, || rename_plugin("golang", "go")); + task(s, migrate_trusted_configs); + task(s, || remove_deprecated_plugin("node", "rtx-nodejs")); + task(s, || remove_deprecated_plugin("python", "rtx-golang")); + task(s, || remove_deprecated_plugin("python", "rtx-java")); + task(s, || remove_deprecated_plugin("python", "rtx-python")); + task(s, || remove_deprecated_plugin("python", "rtx-ruby")); + }); +} - Ok(()) +fn task(s: &Scope, job: impl FnOnce() -> Result<()> + Send + 'static) { + s.spawn(|_| { + if let Err(err) = job() { + warn!("migrate: {}", err); + } + }); } fn move_subdirs(from: &Path, to: &Path) -> Result<()> { @@ -41,6 +47,20 @@ fn move_subdirs(from: &Path, to: &Path) -> Result<()> { Ok(()) } +fn rename_plugin(from: &str, to: &str) -> Result<()> { + move_subdirs(&INSTALLS.join(from), &INSTALLS.join(to))?; + move_subdirs(&PLUGINS.join(from), &PLUGINS.join(to))?; + Ok(()) +} +fn migrate_trusted_configs() -> Result<()> { + let cache_trusted_configs = CACHE.join("trusted-configs"); + let config_trusted_configs = CONFIG.join("trusted-configs"); + let root_trusted_configs = ROOT.join("trusted-configs"); + move_dirs(&cache_trusted_configs, &root_trusted_configs)?; + move_dirs(&config_trusted_configs, &root_trusted_configs)?; + Ok(()) +} + fn move_dirs(from: &Path, to: &Path) -> Result<()> { if from.exists() && !to.exists() { info!("migrating {} to {}", from.display(), to.display()); @@ -49,3 +69,15 @@ fn move_dirs(from: &Path, to: &Path) -> Result<()> { } Ok(()) } + +fn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> { + let plugin_root = PLUGINS.join(name); + let gitconfig = plugin_root.join(".git").join("config"); + let gitconfig_body = fs::read_to_string(gitconfig).unwrap_or_default(); + if !gitconfig_body.contains(&format!("github.com/rtx-plugins/{plugin_name}")) { + return Ok(()); + } + info!("removing deprecated plugin {plugin_name}, will use core {name} plugin from now on"); + file::remove_all(plugin_root)?; + Ok(()) +} From 8d24df2b942afdd0b8577732f6af0b69aa749f4f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 06:46:44 -0600 Subject: [PATCH 1129/1891] node: added ability to install node without node-build (#1035) --- Cargo.lock | 24 +++ Cargo.toml | 2 + docs/node.md | 27 ++- e2e/test_nodejs | 9 + src/cmd.rs | 28 ++- src/env.rs | 51 ++++- src/hash.rs | 13 ++ src/http.rs | 50 +++-- src/main.rs | 4 +- src/plugins/core/bun.rs | 12 +- src/plugins/core/deno.rs | 12 +- src/plugins/core/go.rs | 10 +- src/plugins/core/java.rs | 76 ++++---- src/plugins/core/mod.rs | 31 ++-- src/plugins/core/node.rs | 328 +++++++++++++++++++++------------ src/plugins/core/node_build.rs | 300 ++++++++++++++++++++++++++++++ src/plugins/core/python.rs | 12 +- src/plugins/core/ruby.rs | 14 +- src/plugins/external_plugin.rs | 2 +- src/plugins/mod.rs | 2 +- src/timeout.rs | 18 +- 21 files changed, 784 insertions(+), 241 deletions(-) create mode 100644 src/plugins/core/node_build.rs diff --git a/Cargo.lock b/Cargo.lock index 71bb7da8c..af7fd9b46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -901,6 +901,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "http" version = "0.2.11" @@ -1820,6 +1829,7 @@ dependencies = [ "simplelog", "sys-info", "tar", + "tempfile", "tera", "terminal_size", "thiserror", @@ -1827,6 +1837,7 @@ dependencies = [ "toml_edit", "url", "versions", + "which", ] [[package]] @@ -2765,6 +2776,19 @@ version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +[[package]] +name = "which" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 182e6f2eb..824c07c59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ shell-words = "1.1" simplelog = { version = "0.12" } sys-info = "0.9" tar = "0.4" +tempfile = "3.8.1" tera = { version = "1.19", default-features = false } terminal_size = "0.3" thiserror = "1.0" @@ -98,6 +99,7 @@ toml = "<1" toml_edit = "<1" url = "2.4" versions = "5.0" +which = "5" [target.'cfg(unix)'.dependencies] exec = "0.3" diff --git a/docs/node.md b/docs/node.md index e364984be..69f4567f6 100644 --- a/docs/node.md +++ b/docs/node.md @@ -17,23 +17,25 @@ default: $ rtx use -g node@20 ``` -Behind the scenes, rtx uses [`node-build`](https://github.com/nodenv/node-build) to install pre-compiled binaries and compile from source if necessary. You can check its [README](https://github.com/nodenv/node-build/blob/master/README.md) for additional settings and some troubleshooting. - ## Requirements -rtx uses [node-build](https://github.com/nodenv/node-build) to install node runtimes, you need to ensure the [dependencies](https://github.com/nodenv/node-build/wiki#suggested-build-environment) are installed before installing node. +See [BUILDING.md](https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms) in node's documentation for +required system dependencies. ## Configuration -`node-build` already has a [handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), in additional to that `rtx-node` has a few extra configuration variables: - +- `RTX_NODE_BUILD` [bool]: See [Moving away from node-build](#moving-away-from-node-build) below. - `RTX_NODE_BUILD_REPO` [string]: the default is `https://github.com/nodenv/node-build.git` -- `RTX_NODE_VERBOSE_INSTALL` [bool]: Enables verbose output for downloading and building. +- `RTX_NODE_VERIFY` [bool]: Verify the downloaded assets using GPG. Defaults to `true`. +- `RTX_NODE_NINJA` [bool]: Use ninja instead of make to compile nodel. Defaults to `true` if installed. - `RTX_NODE_FORCE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries. Can also be set across all languages with [`RTX_NODE_FORCE_COMPILE`](https://github.com/jdx/rtx#rtx_node_force_compile1) - `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores - `RTX_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` -- `NODEJS_ORG_MIRROR` [string]: (Legacy) overrides the default mirror used for downloading the - distributions, alternative to the `NODE_BUILD_MIRROR_URL` node-build env var +- `RTX_NODE_MIRROR_URL` [string]: overrides the default mirror used for downloading the distributions +- `RTX_NODE_CFLAGS` [string]: Additional CFLAGS options (e.g., to override -O3). +- `RTX_NODE_CONFIGURE_OPTS` [string]: Additional `./configure` options. +- `RTX_NODE_MAKE_OPTS` [string]: Additional `make` options. +- `RTX_NODE_MAKE_INSTALL_OPTS` [string]: Additional `make install` options. ## Default node packages @@ -90,3 +92,12 @@ rtx ls-remote node You cannot install/use a plugin named "nodejs". If you attempt this, rtx will just renamed it to "node". See the [FAQ](https://github.com/jdx/rtx#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) for an explanation. + +## Moving away from node-build + +This project is in the process of migrating away from using [node-build](https://github.com/nodenv/node-build) for fetching/compiling node. +The main reason for this is just to reduce the # of moving parts but it has some other advantages like not relying on new node-build releases to +get the latest node releases. + +Currently, you can opt into using the pure-rtx node fetching with `RTX_NODE_BUILD=0` this will be the default +behavior in a few weeks from this writing. diff --git a/e2e/test_nodejs b/e2e/test_nodejs index aa28d8f97..36cf159f1 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -3,6 +3,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 +export RTX_NODE_BUILD=1 export RTX_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-npm-packages" rtx plugin uninstall node @@ -26,3 +27,11 @@ rtx plugin uninstall nodejs # disable nodejs plugin RTX_DISABLE_TOOLS=node assert_not_contains "rtx plugins --core" "node" + +export RTX_NODE_BUILD=0 +rtx uninstall node +rtx i node +assert "rtx x -- node --version" "v20.0.0" +# rtx uninstall node +# RTX_NODE_FORCE_COMPILE=1 rtx i node +# assert "rtx x -- node --version" "v20.0.0" diff --git a/src/cmd.rs b/src/cmd.rs index 271a13729..3a24ab6e4 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -1,14 +1,18 @@ use color_eyre::Result; use std::ffi::{OsStr, OsString}; +use std::fmt::{Display, Formatter}; use std::io::{BufRead, BufReader, Write}; +use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Stdio}; use std::sync::mpsc::channel; use std::thread; use crate::config::Settings; use crate::errors::Error::ScriptFailed; +use crate::file::display_path; use crate::ui::progress_report::ProgressReport; use duct::{Expression, IntoExecutablePath}; +use eyre::Context; /// Create a command with any number of of positional arguments, which may be /// different types (anything that implements @@ -103,6 +107,11 @@ impl<'a> CmdLineRunner<'a> { } } + pub fn current_dir>(mut self, dir: P) -> Self { + self.cmd.current_dir(dir); + self + } + pub fn env_clear(mut self) -> Self { self.cmd.env_clear(); self @@ -152,11 +161,14 @@ impl<'a> CmdLineRunner<'a> { } pub fn execute(mut self) -> Result<()> { - debug!("$ {} {}", self.get_program(), self.get_args().join(" ")); + debug!("$ {}", self); if self.settings.raw { return self.execute_raw(); } - let mut cp = self.cmd.spawn()?; + let mut cp = self + .cmd + .spawn() + .with_context(|| format!("failed to execute command: {self}"))?; let stdout = BufReader::new(cp.stdout.take().unwrap()); let stderr = BufReader::new(cp.stderr.take().unwrap()); let (tx, rx) = channel(); @@ -261,12 +273,11 @@ impl<'a> CmdLineRunner<'a> { eprintln!("{}", output); } } - let program = self.cmd.get_program().to_string_lossy().to_string(); - Err(ScriptFailed(program, Some(status)))? + Err(ScriptFailed(self.get_program(), Some(status)))? } fn get_program(&self) -> String { - self.cmd.get_program().to_string_lossy().to_string() + display_path(&PathBuf::from(self.cmd.get_program())) } fn get_args(&self) -> Vec { @@ -277,6 +288,13 @@ impl<'a> CmdLineRunner<'a> { } } +impl Display for CmdLineRunner<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let args = self.get_args().join(" "); + write!(f, "{} {args}", self.get_program()) + } +} + enum ChildProcessOutput { Stdout(String), Stderr(String), diff --git a/src/env.rs b/src/env.rs index 867045e80..8fe271e62 100644 --- a/src/env.rs +++ b/src/env.rs @@ -3,11 +3,12 @@ pub use std::env::*; use std::path::PathBuf; use std::time::Duration; -use crate::duration::HOURLY; use itertools::Itertools; use log::LevelFilter; use once_cell::sync::Lazy; +use url::Url; +use crate::duration::HOURLY; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::file::replace_path; @@ -142,19 +143,59 @@ pub static PYENV_ROOT: Lazy = Lazy::new(|| var_path("PYENV_ROOT").unwrap_or_else(|| HOME.join(".pyenv"))); // node +pub static RTX_NODE_BUILD: Lazy = Lazy::new(|| match var_option_bool("RTX_NODE_BUILD") { + Some(v) => v, + _ => !*RTX_EXPERIMENTAL, +}); pub static RTX_NODE_BUILD_REPO: Lazy = Lazy::new(|| { var("RTX_NODE_BUILD_REPO").unwrap_or_else(|_| "https://github.com/nodenv/node-build.git".into()) }); +pub static RTX_NODE_MIRROR_URL: Lazy = Lazy::new(|| { + var_url("RTX_NODE_MIRROR_URL") + .or_else(|| var_url("NODE_BUILD_MIRROR_URL")) + .unwrap_or_else(|| Url::parse("https://nodejs.org/dist/").unwrap()) +}); pub static RTX_NODE_CONCURRENCY: Lazy> = Lazy::new(|| { var("RTX_NODE_CONCURRENCY") .ok() .and_then(|v| v.parse::().ok()) .map(|v| v.max(1)) + .or_else(|| { + if *RTX_NODE_NINJA { + None + } else { + Some(num_cpus::get_physical()) + } + }) }); pub static RTX_NODE_VERBOSE_INSTALL: Lazy> = Lazy::new(|| var_option_bool("RTX_NODE_VERBOSE_INSTALL")); +pub static RTX_NODE_MAKE: Lazy = + Lazy::new(|| var("RTX_NODE_MAKE").unwrap_or_else(|_| "make".into())); +pub static RTX_NODE_NINJA: Lazy = Lazy::new(|| match var_option_bool("RTX_NODE_NINJA") { + Some(v) => v, + None => is_ninja_on_path(), +}); +pub static RTX_NODE_VERIFY: Lazy = Lazy::new(|| !var_is_false("RTX_NODE_VERIFY")); pub static RTX_NODE_FORCE_COMPILE: Lazy = Lazy::new(|| *RTX_ALL_FORCE_COMPILE || var_is_true("RTX_NODE_FORCE_COMPILE")); +pub static RTX_NODE_CFLAGS: Lazy> = + Lazy::new(|| var("RTX_NODE_CFLAGS").or_else(|_| var("NODE_CFLAGS")).ok()); +pub static RTX_NODE_CONFIGURE_OPTS: Lazy> = Lazy::new(|| { + var("RTX_NODE_CONFIGURE_OPTS") + .or_else(|_| var("NODE_CONFIGURE_OPTS")) + .ok() +}); +pub static RTX_NODE_MAKE_OPTS: Lazy> = Lazy::new(|| { + var("RTX_NODE_MAKE_OPTS") + .or_else(|_| var("NODE_MAKE_OPTS")) + .ok() +}); +pub static RTX_NODE_MAKE_INSTALL_OPTS: Lazy> = Lazy::new(|| { + var("RTX_NODE_MAKE_INSTALL_OPTS") + .or_else(|_| var("NODE_MAKE_INSTALL_OPTS")) + .ok() +}); pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { var_path("RTX_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { let p = HOME.join(".default-nodejs-packages"); @@ -263,6 +304,10 @@ fn var_path(key: &str) -> Option { var_os(key).map(PathBuf::from).map(replace_path) } +fn var_url(key: &str) -> Option { + var(key).ok().map(|v| Url::parse(&v).unwrap()) +} + fn var_confirm(key: &str) -> Confirm { if var_is_true(key) { Confirm::Yes @@ -406,6 +451,10 @@ fn linux_distro() -> Option { } } +fn is_ninja_on_path() -> bool { + which::which("ninja").is_ok() +} + #[cfg(test)] mod tests { use std::collections::HashMap; diff --git a/src/hash.rs b/src/hash.rs index 32f4ffe21..7786cf328 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,9 +1,11 @@ use std::collections::hash_map::DefaultHasher; +use std::collections::HashMap; use std::fs::File; use std::hash::{Hash, Hasher}; use std::path::Path; use color_eyre::eyre::{bail, Result}; +use rayon::prelude::*; use sha2::{Digest, Sha256}; pub fn hash_to_str(t: &T) -> String { @@ -34,6 +36,17 @@ pub fn ensure_checksum_sha256(path: &Path, checksum: &str) -> Result<()> { Ok(()) } +pub fn parse_shasums(text: &str) -> HashMap { + text.par_lines() + .map(|l| { + let mut parts = l.split_whitespace(); + let hash = parts.next().unwrap(); + let name = parts.next().unwrap(); + (name.into(), hash.into()) + }) + .collect() +} + #[cfg(test)] mod tests { use insta::assert_snapshot; diff --git a/src/http.rs b/src/http.rs index c86edd098..b09f71dc1 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,20 +1,32 @@ -use color_eyre::eyre::{eyre, Result}; -use reqwest::blocking::{RequestBuilder, Response}; +use eyre::{Report, Result}; +use reqwest::blocking::{ClientBuilder, RequestBuilder}; use reqwest::IntoUrl; use std::fs::File; use std::path::Path; +use std::time::Duration; +#[derive(Debug)] pub struct Client { reqwest: reqwest::blocking::Client, } impl Client { pub fn new() -> Result { - let reqwest = reqwest::blocking::ClientBuilder::new() + Ok(Self { + reqwest: Self::_new().build()?, + }) + } + + pub fn new_with_timeout(timeout: Duration) -> Result { + Ok(Self { + reqwest: Self::_new().timeout(timeout).build()?, + }) + } + + fn _new() -> ClientBuilder { + ClientBuilder::new() .user_agent(format!("rtx/{}", env!("CARGO_PKG_VERSION"))) .gzip(true) - .build()?; - Ok(Self { reqwest }) } pub fn get(&self, url: U) -> RequestBuilder { @@ -25,28 +37,38 @@ impl Client { pub fn get_text(&self, url: U) -> Result { let url = url.into_url().unwrap(); - debug!("GET.txt {}", url); let resp = self.get(url).send()?; - self.ensure_success(&resp)?; + resp.error_for_status_ref()?; let text = resp.text()?; Ok(text) } + pub fn json(&self, url: U) -> Result + where + T: serde::de::DeserializeOwned, + { + let url = url.into_url().unwrap(); + let resp = self.get(url.clone()).send()?; + resp.error_for_status_ref()?; + let json = resp.json()?; + Ok(json) + } + pub fn download_file(&self, url: U, path: &Path) -> Result<()> { let url = url.into_url()?; debug!("Downloading {} to {}", &url, path.display()); let mut resp = self.get(url).send()?; - self.ensure_success(&resp)?; + resp.error_for_status_ref()?; let mut file = File::create(path)?; resp.copy_to(&mut file)?; Ok(()) } +} - pub fn ensure_success(&self, resp: &Response) -> Result<()> { - if resp.status().is_success() { - Ok(()) - } else { - Err(eyre!("HTTP error: {} on {}", resp.status(), resp.url())) - } +pub fn error_code(e: &Report) -> Option { + if let Some(err) = e.downcast_ref::() { + err.status().map(|s| s.as_u16()) + } else { + None } } diff --git a/src/main.rs b/src/main.rs index b83251d91..14e49b2d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,7 +99,9 @@ fn handle_ctrlc() { fn display_friendly_err(err: Report) { let dim = |s| style(s).dim().for_stderr(); let dim_red = |s| style(s).dim().red().for_stderr(); - eprintln!("{} {}", dim_red("rtx"), err); + for err in err.chain() { + eprintln!("{} {}", dim_red("rtx"), err); + } eprintln!( "{} {}", dim_red("rtx"), diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 26a6e2da8..de4762113 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -9,7 +9,7 @@ use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::github::GithubRelease; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{env, file, http}; @@ -20,8 +20,8 @@ pub struct BunPlugin { } impl BunPlugin { - pub fn new(name: PluginName) -> Self { - let core = CorePlugin::new(name); + pub fn new() -> Self { + let core = CorePlugin::new("bun"); Self { core } } @@ -32,7 +32,7 @@ impl BunPlugin { req = req.header("authorization", format!("token {}", token)); } let resp = req.send()?; - http.ensure_success(&resp)?; + resp.error_for_status_ref()?; let releases: Vec = resp.json()?; let versions = releases .into_iter() @@ -94,8 +94,8 @@ impl BunPlugin { } impl Plugin for BunPlugin { - fn name(&self) -> &PluginName { - &self.core.name + fn name(&self) -> &str { + "bun" } fn list_remote_versions(&self, _settings: &Settings) -> Result> { diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 4e3f43921..910f2fb15 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -11,7 +11,7 @@ use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::github::GithubRelease; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{env, file, http}; @@ -22,8 +22,8 @@ pub struct DenoPlugin { } impl DenoPlugin { - pub fn new(name: PluginName) -> Self { - let core = CorePlugin::new(name); + pub fn new() -> Self { + let core = CorePlugin::new("deno"); Self { core } } @@ -34,7 +34,7 @@ impl DenoPlugin { req = req.header("authorization", format!("token {}", token)); } let resp = req.send()?; - http.ensure_success(&resp)?; + resp.error_for_status_ref()?; let releases: Vec = resp.json()?; let versions = releases .into_iter() @@ -95,8 +95,8 @@ impl DenoPlugin { } impl Plugin for DenoPlugin { - fn name(&self) -> &PluginName { - &self.core.name + fn name(&self) -> &str { + "deno" } fn list_remote_versions(&self, _settings: &Settings) -> Result> { diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 6bbd9c1aa..65029f042 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -10,7 +10,7 @@ use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::ToolVersion; use crate::ui::progress_report::ProgressReport; use crate::{cmd, env, file, hash, http}; @@ -21,9 +21,9 @@ pub struct GoPlugin { } impl GoPlugin { - pub fn new(name: PluginName) -> Self { + pub fn new() -> Self { Self { - core: CorePlugin::new(name), + core: CorePlugin::new("go"), } } @@ -135,8 +135,8 @@ impl GoPlugin { } impl Plugin for GoPlugin { - fn name(&self) -> &PluginName { - &self.core.name + fn name(&self) -> &str { + "go" } fn list_remote_versions(&self, _settings: &Settings) -> Result> { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 91cfb1ede..5105b6757 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -15,7 +15,7 @@ use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{env, file, hash, http}; @@ -23,13 +23,14 @@ use crate::{env, file, hash, http}; #[derive(Debug)] pub struct JavaPlugin { core: CorePlugin, + http: http::Client, java_metadata_ea_cache: CacheManager>, java_metadata_ga_cache: CacheManager>, } impl JavaPlugin { - pub fn new(name: PluginName) -> Self { - let core = CorePlugin::new(name); + pub fn new() -> Self { + let core = CorePlugin::new("java"); let java_metadata_ga_cache_filename = format!("java_metadata_ga_{}_{}.msgpack.z", os(), arch()); let java_metadata_ea_cache_filename = @@ -44,6 +45,7 @@ impl JavaPlugin { ) .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), core, + http: http::Client::new_with_timeout(*env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap(), } } @@ -55,24 +57,22 @@ impl JavaPlugin { }; let release_type = release_type.to_string(); cache.get_or_try_init(|| { - CorePlugin::run_fetch_task_with_timeout(move || { - let mut metadata = HashMap::new(); - - for m in download_java_metadata(&release_type)?.into_iter() { - // add openjdk short versions like "java@17.0.0" which default to openjdk - if m.vendor == "openjdk" { - if m.version.contains('.') { - metadata.insert(m.version.to_string(), m.clone()); - } else { - // rtx expects full versions like ".0.0" - metadata.insert(format!("{}.0.0", m.version), m.clone()); - } + let mut metadata = HashMap::new(); + + for m in self.download_java_metadata(&release_type)?.into_iter() { + // add openjdk short versions like "java@17.0.0" which default to openjdk + if m.vendor == "openjdk" { + if m.version.contains('.') { + metadata.insert(m.version.to_string(), m.clone()); + } else { + // rtx expects full versions like ".0.0" + metadata.insert(format!("{}.0.0", m.version), m.clone()); } - metadata.insert(m.to_string(), m); } + metadata.insert(m.to_string(), m); + } - Ok(metadata) - }) + Ok(metadata) }) } @@ -226,11 +226,28 @@ impl JavaPlugin { .ok_or_else(|| eyre!("no metadata found for version {}", tv.version))?; Ok(m) } + + fn download_java_metadata(&self, release_type: &str) -> Result> { + let url = format!( + "https://java.rtx.pub/metadata/{}/{}/{}.json", + release_type, + os(), + arch() + ); + + let metadata = self + .http + .json::, _>(url)? + .into_iter() + .filter(|m| JAVA_FILE_TYPES.contains(&m.file_type)) + .collect(); + Ok(metadata) + } } impl Plugin for JavaPlugin { - fn name(&self) -> &PluginName { - &self.core.name + fn name(&self) -> &str { + "java" } fn list_remote_versions(&self, _settings: &Settings) -> Result> { @@ -359,22 +376,3 @@ static JAVA_FEATURES: Lazy> = Lazy::new(|| HashSet::from(["musl", "javafx", "lite", "large_heap"].map(|s| s.to_string()))); static JAVA_FILE_TYPES: Lazy> = Lazy::new(|| HashSet::from(["tar.gz", "zip"].map(|s| s.to_string()))); - -fn download_java_metadata(release_type: &str) -> Result> { - let http = http::Client::new()?; - let url = format!( - "https://java.rtx.pub/metadata/{}/{}/{}.json", - release_type, - os(), - arch() - ); - let resp = http.get(url).send()?; - http.ensure_success(&resp)?; - - let metadata = resp - .json::>()? - .into_iter() - .filter(|m| JAVA_FILE_TYPES.contains(&m.file_type)) - .collect(); - Ok(metadata) -} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index c3ab10415..a9de8f49a 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -9,11 +9,13 @@ use once_cell::sync::Lazy; pub use python::PythonPlugin; use crate::cache::CacheManager; +use crate::env::RTX_NODE_BUILD; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; use crate::plugins::core::go::GoPlugin; 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}; use crate::timeout::run_with_timeout; @@ -26,6 +28,7 @@ mod deno; mod go; mod java; mod node; +mod node_build; mod python; mod ruby; @@ -33,18 +36,22 @@ type ToolMap = BTreeMap>; pub static CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ - Box::new(GoPlugin::new("go".to_string())), - Box::new(JavaPlugin::new("java".to_string())), - Box::new(NodePlugin::new("node".to_string())), - Box::new(PythonPlugin::new("python".to_string())), - Box::new(RubyPlugin::new("ruby".to_string())), + Box::new(GoPlugin::new()), + Box::new(JavaPlugin::new()), + if *RTX_NODE_BUILD { + Box::new(NodeBuildPlugin::new()) + } else { + Box::new(NodePlugin::new()) + }, + Box::new(PythonPlugin::new()), + Box::new(RubyPlugin::new()), ]) }); pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ - Box::new(BunPlugin::new("bun".to_string())), - Box::new(DenoPlugin::new("deno".to_string())), + Box::new(BunPlugin::new()), + Box::new(DenoPlugin::new()), ]) }); @@ -59,18 +66,16 @@ fn build_core_plugins(tools: Vec>) -> ToolMap { #[derive(Debug)] pub struct CorePlugin { - pub name: PluginName, pub cache_path: PathBuf, pub remote_version_cache: CacheManager>, } impl CorePlugin { - pub fn new(name: PluginName) -> Self { - let cache_path = dirs::CACHE.join(&name); + pub fn new(name: &'static str) -> Self { + let cache_path = dirs::CACHE.join(name); Self { remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), - name, cache_path, } } @@ -83,8 +88,8 @@ impl CorePlugin { pub fn run_fetch_task_with_timeout(f: F) -> Result where - F: FnOnce() -> Result + Send + 'static, - T: Send + 'static, + F: FnOnce() -> Result + Send, + T: Send, { run_with_timeout(f, *env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 84bc1985f..a5ba95814 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,100 +1,178 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use std::process::exit; -use clap::Command; use color_eyre::eyre::Result; +use serde_derive::Deserialize; +use tempfile::tempdir_in; +use url::Url; +use crate::build_time::built_info; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::duration::DAILY; -use crate::env::{RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE}; -use crate::file::create_dir_all; -use crate::git::Git; -use crate::lock_file::LockFile; +use crate::env::{ + RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_CFLAGS, RTX_NODE_CONCURRENCY, + RTX_NODE_CONFIGURE_OPTS, RTX_NODE_FORCE_COMPILE, RTX_NODE_MAKE, RTX_NODE_MAKE_INSTALL_OPTS, + RTX_NODE_MAKE_OPTS, RTX_NODE_MIRROR_URL, RTX_NODE_NINJA, RTX_NODE_VERIFY, RTX_TMP_DIR, +}; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, PluginName}; -use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::plugins::Plugin; +use crate::toolset::ToolVersion; use crate::ui::progress_report::ProgressReport; -use crate::{cmd, env, file}; +use crate::{env, file, hash, http}; #[derive(Debug)] pub struct NodePlugin { core: CorePlugin, + http: http::Client, } impl NodePlugin { - pub fn new(name: PluginName) -> Self { + pub fn new() -> Self { Self { - core: CorePlugin::new(name), + core: CorePlugin::new("node"), + http: http::Client::new_with_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap(), } } - fn node_build_path(&self) -> PathBuf { - self.core.cache_path.join("node-build") - } - fn node_build_bin(&self) -> PathBuf { - self.node_build_path().join("bin/node-build") + fn fetch_remote_versions(&self) -> Result> { + let versions = self + .http + .json::, _>(RTX_NODE_MIRROR_URL.join("index.json")?)? + .into_iter() + .map(|v| { + if regex!(r"^v\d+\.").is_match(&v.version) { + v.version.strip_prefix('v').unwrap().to_string() + } else { + v.version + } + }) + .rev() + .collect(); + Ok(versions) } - fn install_or_update_node_build(&self) -> Result<()> { - let _lock = self.lock_node_build(); - if self.node_build_path().exists() { - self.update_node_build() - } else { - self.install_node_build() - } + + fn install_precompiled(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + let slug = slug(&tv.version, os(), arch()); + let tarball_name = binary_tarball_name(&tv.version); + let tmp_tarball = tv.download_path().join(&tarball_name); + let url = self.binary_tarball_url(&tv.version)?; + self.fetch_tarball(pr, url, &tmp_tarball, &tv.version)?; + pr.set_message(format!("extracting {tarball_name}")); + let tmp_extract_path = tempdir_in(tv.install_path().parent().unwrap())?; + file::untar(&tmp_tarball, tmp_extract_path.path())?; + file::remove_all(tv.install_path())?; + file::rename(tmp_extract_path.path().join(slug), tv.install_path())?; + Ok(()) } - fn lock_node_build(&self) -> Result { - LockFile::new(&self.node_build_path()) - .with_callback(|l| { - trace!("install_or_update_node_build {}", l.display()); - }) - .lock() + fn install_compiled( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + let tarball_name = source_tarball_name(&tv.version); + let tmp_tarball = tv.download_path().join(&tarball_name); + let url = self.source_tarball_url(&tv.version)?; + self.fetch_tarball(pr, url, &tmp_tarball, &tv.version)?; + pr.set_message(format!("extracting {tarball_name}")); + let build_dir = RTX_TMP_DIR.join(format!("node-v{}", tv.version)); + file::remove_all(&build_dir)?; + file::untar(&tmp_tarball, &RTX_TMP_DIR)?; + self.exec_configure(config, pr, &build_dir, &tv.install_path())?; + self.exec_make(config, pr, &build_dir)?; + self.exec_make_install(config, pr, &build_dir)?; + Ok(()) } - fn install_node_build(&self) -> Result<()> { - if self.node_build_path().exists() { - return Ok(()); + + fn fetch_tarball( + &self, + pr: &ProgressReport, + url: Url, + local: &Path, + version: &str, + ) -> Result<()> { + let tarball_name = local.file_name().unwrap().to_string_lossy().to_string(); + if local.exists() { + pr.set_message(format!("using previously downloaded {tarball_name}")); + } else { + pr.set_message(format!("downloading {tarball_name}")); + self.http.download_file(url, local)?; + } + if *RTX_NODE_VERIFY { + pr.set_message(format!("verifying {tarball_name}")); + self.verify(local, version)?; } - debug!( - "Installing node-build to {}", - self.node_build_path().display() - ); - create_dir_all(self.node_build_path().parent().unwrap())?; - let git = Git::new(self.node_build_path()); - git.clone(&env::RTX_NODE_BUILD_REPO)?; Ok(()) } - fn update_node_build(&self) -> Result<()> { - if self.node_build_recently_updated()? { - return Ok(()); + + fn sh<'a>( + &'a self, + settings: &'a Settings, + pr: &'a ProgressReport, + dir: &Path, + ) -> CmdLineRunner { + let mut cmd = CmdLineRunner::new(settings, "sh") + .with_pr(pr) + .current_dir(dir) + .arg("-c"); + if let Some(cflags) = &*RTX_NODE_CFLAGS { + cmd = cmd.env("CFLAGS", cflags); } - debug!( - "Updating node-build in {}", - self.node_build_path().display() - ); - let git = Git::new(self.node_build_path()); - let node_build_path = self.node_build_path(); - CorePlugin::run_fetch_task_with_timeout(move || { - git.update(None)?; - file::touch_dir(&node_build_path)?; - Ok(()) - }) + cmd } - fn fetch_remote_versions(&self) -> Result> { - self.install_or_update_node_build()?; - let node_build_bin = self.node_build_bin(); - CorePlugin::run_fetch_task_with_timeout(move || { - let output = cmd!(node_build_bin, "--definitions").read()?; - let versions = output - .split('\n') - .filter(|s| regex!(r"^[0-9].+$").is_match(s)) - .map(|s| s.to_string()) - .collect(); - Ok(versions) - }) + fn exec_configure( + &self, + config: &Config, + pr: &ProgressReport, + build_dir: &Path, + out: &Path, + ) -> Result<()> { + self.sh(&config.settings, pr, build_dir) + .arg(format!( + "./configure --prefix={} {} {}", + out.display(), + if *RTX_NODE_NINJA { "--ninja" } else { "" }, + RTX_NODE_CONFIGURE_OPTS.clone().unwrap_or_default() + )) + .execute() + } + fn exec_make(&self, config: &Config, pr: &ProgressReport, build_dir: &Path) -> Result<()> { + self.sh(&config.settings, pr, build_dir) + .arg(format!( + "{} {} {}", + &*RTX_NODE_MAKE, + RTX_NODE_CONCURRENCY + .map(|c| format!("-j{}", c)) + .unwrap_or_default(), + RTX_NODE_MAKE_OPTS.clone().unwrap_or_default() + )) + .execute() + } + fn exec_make_install( + &self, + config: &Config, + pr: &ProgressReport, + build_dir: &Path, + ) -> Result<()> { + self.sh(&config.settings, pr, build_dir) + .arg(format!( + "{} install {}", + &*RTX_NODE_MAKE, + RTX_NODE_MAKE_INSTALL_OPTS.clone().unwrap_or_default() + )) + .execute() + } + + fn verify(&self, tarball: &Path, version: &str) -> Result<()> { + let tarball_name = tarball.file_name().unwrap().to_string_lossy().to_string(); + // TODO: verify gpg signature + let shasums = self.http.get_text(self.shasums_url(version)?)?; + let shasums = hash::parse_shasums(&shasums); + let shasum = shasums.get(&tarball_name).unwrap(); + hash::ensure_checksum_sha256(tarball, shasum) } fn node_path(&self, tv: &ToolVersion) -> PathBuf { @@ -157,20 +235,24 @@ impl NodePlugin { .execute() } - fn node_build_recently_updated(&self) -> Result { - let updated_at = file::modified_duration(&self.node_build_path())?; - Ok(updated_at < DAILY) + fn source_tarball_url(&self, v: &str) -> Result { + let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/{}", source_tarball_name(v)))?; + Ok(url) } - - fn verbose_install(&self, settings: &Settings) -> bool { - let verbose_env = *env::RTX_NODE_VERBOSE_INSTALL; - verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) + fn binary_tarball_url(&self, v: &str) -> Result { + let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/{}", binary_tarball_name(v)))?; + Ok(url) + } + fn shasums_url(&self, v: &str) -> Result { + // let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt.asc"))?; + let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt"))?; + Ok(url) } } impl Plugin for NodePlugin { - fn name(&self) -> &PluginName { - &self.core.name + fn name(&self) -> &str { + "node" } fn list_remote_versions(&self, _settings: &Settings) -> Result> { @@ -221,60 +303,25 @@ impl Plugin for NodePlugin { Ok(body.to_string()) } - fn external_commands(&self) -> Result> { - // sort of a hack to get this not to display for nodejs - let topic = Command::new("node") - .about("Commands for the node plugin") - .subcommands(vec![Command::new("node-build") - .about("Use/manage rtx's internal node-build") - .arg( - clap::Arg::new("args") - .num_args(1..) - .allow_hyphen_values(true) - .trailing_var_arg(true), - )]); - Ok(vec![topic]) - } - - fn execute_external_command( - &self, - _config: &Config, - command: &str, - args: Vec, - ) -> Result<()> { - match command { - "node-build" => { - self.install_or_update_node_build()?; - cmd::cmd(self.node_build_bin(), args).run()?; - } - _ => unreachable!(), - } - exit(0); - } - fn install_version( &self, config: &Config, tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - self.install_node_build()?; pr.set_message("running node-build"); - let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()) - .with_pr(pr) - .envs(&config.env) - .arg(tv.version.as_str()); - if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_FORCE_COMPILE { - if let Some(concurrency) = *RTX_NODE_CONCURRENCY { - let make_opts = env::var("MAKE_OPTS").unwrap_or_default(); - cmd = cmd.env("MAKE_OPTS", format!("{} -j{}", make_opts, concurrency)); + if *RTX_NODE_FORCE_COMPILE { + self.install_compiled(config, tv, pr)?; + } else { + match self.install_precompiled(tv, pr) { + Err(e) if matches!(http::error_code(&e), Some(404)) => { + debug!("precompiled node not found"); + self.install_compiled(config, tv, pr)?; + } + Err(e) => return Err(e), + Ok(()) => {} } - cmd = cmd.arg("--compile"); - } - if self.verbose_install(&config.settings) { - cmd = cmd.arg("--verbose"); } - cmd.arg(tv.install_path()).execute()?; self.test_node(config, tv, pr)?; self.install_npm_shim(tv)?; self.test_npm(config, tv, pr)?; @@ -282,3 +329,44 @@ impl Plugin for NodePlugin { Ok(()) } } + +fn os() -> &'static str { + if cfg!(target_os = "linux") { + "linux" + } else if cfg!(target_os = "macos") { + "darwin" + } else if cfg!(target_os = "windows") { + "win" + } else { + built_info::CFG_OS + } +} + +fn arch() -> &'static str { + if cfg!(target_arch = "x86") { + "x86" + } else if cfg!(target_arch = "x86_64") { + "x64" + } else if cfg!(target_arch = "arm") { + "armv7l" + } else if cfg!(target_arch = "aarch64") { + "arm64" + } else { + built_info::CFG_TARGET_ARCH + } +} + +fn slug(v: &str, os: &str, arch: &str) -> String { + format!("node-v{v}-{os}-{arch}") +} +fn source_tarball_name(v: &str) -> String { + format!("node-v{v}.tar.gz") +} +fn binary_tarball_name(v: &str) -> String { + format!("{}.tar.gz", slug(v, os(), arch())) +} + +#[derive(Debug, Deserialize)] +struct NodeVersion { + version: String, +} diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs new file mode 100644 index 000000000..f379996ed --- /dev/null +++ b/src/plugins/core/node_build.rs @@ -0,0 +1,300 @@ +use std::collections::BTreeMap; + +use std::path::{Path, PathBuf}; +use std::process::exit; + +use clap::Command; +use color_eyre::eyre::Result; + +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::duration::DAILY; +use crate::env::{ + RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, RTX_NODE_MAKE_OPTS, RTX_NODE_MIRROR_URL, +}; +use crate::file::create_dir_all; +use crate::git::Git; +use crate::lock_file::LockFile; +use crate::plugins::core::CorePlugin; +use crate::plugins::Plugin; +use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::ui::progress_report::ProgressReport; +use crate::{cmd, env, file}; + +#[derive(Debug)] +pub struct NodeBuildPlugin { + core: CorePlugin, +} + +impl NodeBuildPlugin { + pub fn new() -> Self { + Self { + core: CorePlugin::new("node"), + } + } + + fn node_build_path(&self) -> PathBuf { + self.core.cache_path.join("node-build") + } + fn node_build_bin(&self) -> PathBuf { + self.node_build_path().join("bin/node-build") + } + fn install_or_update_node_build(&self) -> Result<()> { + let _lock = self.lock_node_build(); + if self.node_build_path().exists() { + self.update_node_build() + } else { + self.install_node_build() + } + } + + fn lock_node_build(&self) -> Result { + LockFile::new(&self.node_build_path()) + .with_callback(|l| { + trace!("install_or_update_node_build {}", l.display()); + }) + .lock() + } + fn install_node_build(&self) -> Result<()> { + if self.node_build_path().exists() { + return Ok(()); + } + debug!( + "Installing node-build to {}", + self.node_build_path().display() + ); + create_dir_all(self.node_build_path().parent().unwrap())?; + let git = Git::new(self.node_build_path()); + git.clone(&env::RTX_NODE_BUILD_REPO)?; + Ok(()) + } + fn update_node_build(&self) -> Result<()> { + if self.node_build_recently_updated()? { + return Ok(()); + } + debug!( + "Updating node-build in {}", + self.node_build_path().display() + ); + let git = Git::new(self.node_build_path()); + let node_build_path = self.node_build_path(); + CorePlugin::run_fetch_task_with_timeout(move || { + git.update(None)?; + file::touch_dir(&node_build_path)?; + Ok(()) + }) + } + + fn fetch_remote_versions(&self) -> Result> { + self.install_or_update_node_build()?; + let node_build_bin = self.node_build_bin(); + CorePlugin::run_fetch_task_with_timeout(move || { + let output = cmd!(node_build_bin, "--definitions").read()?; + let versions = output + .split('\n') + .filter(|s| regex!(r"^[0-9].+$").is_match(s)) + .map(|s| s.to_string()) + .collect(); + Ok(versions) + }) + } + + fn node_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/node") + } + + fn npm_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/npm") + } + + fn install_default_packages( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + let body = file::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + for package in body.lines() { + let package = package.split('#').next().unwrap_or_default().trim(); + if package.is_empty() { + continue; + } + pr.set_message(format!("installing default package: {}", package)); + let npm = self.npm_path(tv); + CmdLineRunner::new(&config.settings, npm) + .with_pr(pr) + .arg("install") + .arg("--global") + .arg(package) + .envs(&config.env) + .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .execute()?; + } + Ok(()) + } + + fn install_npm_shim(&self, tv: &ToolVersion) -> Result<()> { + file::remove_file(self.npm_path(tv)).ok(); + file::write(self.npm_path(tv), include_str!("assets/node_npm_shim"))?; + file::make_executable(&self.npm_path(tv))?; + Ok(()) + } + + fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("node -v"); + CmdLineRunner::new(&config.settings, self.node_path(tv)) + .with_pr(pr) + .arg("-v") + .envs(&config.env) + .execute() + } + + fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + pr.set_message("npm -v"); + CmdLineRunner::new(&config.settings, self.npm_path(tv)) + .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .with_pr(pr) + .arg("-v") + .envs(&config.env) + .execute() + } + + fn node_build_recently_updated(&self) -> Result { + let updated_at = file::modified_duration(&self.node_build_path())?; + Ok(updated_at < DAILY) + } + + fn verbose_install(&self, settings: &Settings) -> bool { + let verbose_env = *env::RTX_NODE_VERBOSE_INSTALL; + verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) + } +} + +impl Plugin for NodeBuildPlugin { + fn name(&self) -> &str { + "node" + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.core + .remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn get_aliases(&self, _settings: &Settings) -> Result> { + let aliases = [ + ("lts/argon", "4"), + ("lts/boron", "6"), + ("lts/carbon", "8"), + ("lts/dubnium", "10"), + ("lts/erbium", "12"), + ("lts/fermium", "14"), + ("lts/gallium", "16"), + ("lts/hydrogen", "18"), + ("lts/iron", "20"), + ("lts-argon", "4"), + ("lts-boron", "6"), + ("lts-carbon", "8"), + ("lts-dubnium", "10"), + ("lts-erbium", "12"), + ("lts-fermium", "14"), + ("lts-gallium", "16"), + ("lts-hydrogen", "18"), + ("lts-iron", "20"), + ("lts", "20"), + ] + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(); + Ok(aliases) + } + + fn legacy_filenames(&self, _settings: &Settings) -> Result> { + Ok(vec![".node-version".into(), ".nvmrc".into()]) + } + + fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + let body = file::read_to_string(path)?; + // trim "v" prefix + let body = body.trim().strip_prefix('v').unwrap_or(&body); + // replace lts/* with lts + let body = body.replace("lts/*", "lts"); + Ok(body.to_string()) + } + + fn external_commands(&self) -> Result> { + // sort of a hack to get this not to display for nodejs + let topic = Command::new("node") + .about("Commands for the node plugin") + .subcommands(vec![Command::new("node-build") + .about("Use/manage rtx's internal node-build") + .arg( + clap::Arg::new("args") + .num_args(1..) + .allow_hyphen_values(true) + .trailing_var_arg(true), + )]); + Ok(vec![topic]) + } + + fn execute_external_command( + &self, + _config: &Config, + command: &str, + args: Vec, + ) -> Result<()> { + match command { + "node-build" => { + self.install_or_update_node_build()?; + cmd::cmd(self.node_build_bin(), args).run()?; + } + _ => unreachable!(), + } + exit(0); + } + + fn install_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + self.install_node_build()?; + pr.set_message("running node-build"); + let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()) + .with_pr(pr) + .env("NODE_BUILD_MIRROR_URL", RTX_NODE_MIRROR_URL.to_string()) + .envs(&config.env) + .arg(tv.version.as_str()); + if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_FORCE_COMPILE { + let mut make_opts = RTX_NODE_MAKE_OPTS.clone().unwrap_or_default(); + if let Some(concurrency) = *RTX_NODE_CONCURRENCY { + make_opts = format!("{} -j{}", make_opts, concurrency); + } + if let Some(node_make_opts) = &*RTX_NODE_MAKE_OPTS { + make_opts = format!("{} {}", make_opts, node_make_opts); + } + cmd = cmd.env("NODE_MAKE_OPTS", make_opts); + if let Some(cflags) = &*env::RTX_NODE_CFLAGS { + cmd = cmd.env("NODE_CFLAGS", cflags); + } + if let Some(node_configure_opts) = &*env::RTX_NODE_CONFIGURE_OPTS { + cmd = cmd.env("NODE_CONFIGURE_OPTS", node_configure_opts); + } + if let Some(make_install_opts) = &*env::RTX_NODE_MAKE_INSTALL_OPTS { + cmd = cmd.env("NODE_MAKE_INSTALL_OPTS", make_install_opts); + } + cmd = cmd.arg("--compile"); + } + if self.verbose_install(&config.settings) { + cmd = cmd.arg("--verbose"); + } + cmd.arg(tv.install_path()).execute()?; + self.test_node(config, tv, pr)?; + self.install_npm_shim(tv)?; + self.test_npm(config, tv, pr)?; + self.install_default_packages(config, tv, pr)?; + Ok(()) + } +} diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 68c59928f..0a1e42169 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -9,7 +9,7 @@ use crate::config::{Config, Settings}; use crate::file::create_dir_all; use crate::git::Git; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{cmd, env, file, http}; @@ -20,9 +20,9 @@ pub struct PythonPlugin { } impl PythonPlugin { - pub fn new(name: PluginName) -> Self { + pub fn new() -> Self { Self { - core: CorePlugin::new(name), + core: CorePlugin::new("python"), } } @@ -147,8 +147,8 @@ impl PythonPlugin { } impl Plugin for PythonPlugin { - fn name(&self) -> &PluginName { - &self.core.name + fn name(&self) -> &str { + "python" } fn list_remote_versions(&self, _settings: &Settings) -> Result> { @@ -185,7 +185,7 @@ impl Plugin for PythonPlugin { pr.set_message(format!("with patch file from: {patch_url}")); let http = http::Client::new()?; let resp = http.get(patch_url).send()?; - http.ensure_success(&resp)?; + resp.error_for_status_ref()?; let patch = resp.text()?; cmd = cmd.arg("--patch").stdin_string(patch) } diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 223aceece..84e2d2311 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -13,7 +13,7 @@ use crate::git::Git; use crate::github::GithubRelease; use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{cmd, env, file, http}; @@ -24,9 +24,9 @@ pub struct RubyPlugin { } impl RubyPlugin { - pub fn new(name: PluginName) -> Self { + pub fn new() -> Self { Self { - core: CorePlugin::new(name), + core: CorePlugin::new("ruby"), } } @@ -225,7 +225,7 @@ impl RubyPlugin { req = req.header("authorization", format!("token {}", token)); } let resp = req.send()?; - http.ensure_success(&resp)?; + resp.error_for_status_ref()?; let release: GithubRelease = resp.json()?; Ok(release.tag_name.trim_start_matches('v').to_string()) } @@ -312,7 +312,7 @@ impl RubyPlugin { if regex!(r#"^[Hh][Tt][Tt][Pp][Ss]?://"#).is_match(f) { let http = http::Client::new()?; let resp = http.get(f).send()?; - http.ensure_success(&resp)?; + resp.error_for_status_ref()?; patches.push(resp.text()?); } else { patches.push(file::read_to_string(f)?); @@ -323,8 +323,8 @@ impl RubyPlugin { } impl Plugin for RubyPlugin { - fn name(&self) -> &PluginName { - &self.core.name + fn name(&self) -> &str { + "ruby" } fn list_remote_versions(&self, _settings: &Settings) -> Result> { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index c5575ba63..c50e6c269 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -345,7 +345,7 @@ impl Hash for ExternalPlugin { } impl Plugin for ExternalPlugin { - fn name(&self) -> &PluginName { + fn name(&self) -> &str { &self.name } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index de31f9494..be56ab3b3 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -26,7 +26,7 @@ mod script_manager; pub type PluginName = String; pub trait Plugin: Debug + Send + Sync { - fn name(&self) -> &PluginName; + fn name(&self) -> &str; fn get_type(&self) -> PluginType { PluginType::Core } diff --git a/src/timeout.rs b/src/timeout.rs index 8e6764c41..f5e6caba4 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -5,14 +5,16 @@ use std::time::Duration; pub fn run_with_timeout(f: F, timeout: Duration) -> Result where - F: FnOnce() -> Result + Send + 'static, - T: Send + 'static, + F: FnOnce() -> Result + Send, + T: Send, { let (tx, rx) = mpsc::channel(); - thread::spawn(move || { - let result = f(); - // If sending fails, the timeout has already been reached. - let _ = tx.send(result); - }); - rx.recv_timeout(timeout).context("timed out")? + thread::scope(|s| { + s.spawn(|| { + let result = f(); + // If sending fails, the timeout has already been reached. + let _ = tx.send(result); + }); + rx.recv_timeout(timeout).context("timed out") + })? } From 94a90f6afe072ef43319013321109ea7e596a5ef Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 06:51:12 -0600 Subject: [PATCH 1130/1891] alpine: create draft gitlab mr --- scripts/release-alpine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh index 3f8f87e7b..b33a1f09b 100755 --- a/scripts/release-alpine.sh +++ b/scripts/release-alpine.sh @@ -32,5 +32,5 @@ git commit -m "community/rtx: upgrade to ${RTX_VERSION#v}" git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git" git push -f jdxcode -glab mr create --fill --yes -H jdxcode/aports -R alpine/aports +glab mr create --draft --fill --yes -H jdxcode/aports -R alpine/aports #git show From 874b5d5fa33e63cfd5d38d0f62a5ed2305eadf14 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 07:01:03 -0600 Subject: [PATCH 1131/1891] migrate: rename tracked_config_files to tracked-config-files (#1036) This matches the convention used by trusted-configs --- src/config/tracking.rs | 2 +- src/migrate.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/config/tracking.rs b/src/config/tracking.rs index f708e34a5..08e16e082 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -18,7 +18,7 @@ pub struct Tracker { impl Tracker { pub fn new() -> Self { Self { - tracking_dir: dirs::ROOT.join("tracked_config_files"), + tracking_dir: dirs::ROOT.join("tracked-config-files"), ..Default::default() } } diff --git a/src/migrate.rs b/src/migrate.rs index 2c8c81794..8f85b45ad 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -12,6 +12,7 @@ pub fn run() { task(s, || rename_plugin("nodejs", "node")); task(s, || rename_plugin("golang", "go")); task(s, migrate_trusted_configs); + task(s, migrate_tracked_configs); task(s, || remove_deprecated_plugin("node", "rtx-nodejs")); task(s, || remove_deprecated_plugin("python", "rtx-golang")); task(s, || remove_deprecated_plugin("python", "rtx-java")); @@ -52,6 +53,12 @@ fn rename_plugin(from: &str, to: &str) -> Result<()> { move_subdirs(&PLUGINS.join(from), &PLUGINS.join(to))?; Ok(()) } +fn migrate_tracked_configs() -> Result<()> { + let from = ROOT.join("tracked_config_files"); + let to = ROOT.join("tracked-config-files"); + move_dirs(&from, &to)?; + Ok(()) +} fn migrate_trusted_configs() -> Result<()> { let cache_trusted_configs = CACHE.join("trusted-configs"); let config_trusted_configs = CONFIG.join("trusted-configs"); From ca6c29ac5ffa8ec52a6c8229c3c40c0f238b17bf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 07:02:54 -0600 Subject: [PATCH 1132/1891] chore: Release rtx-cli version 2023.12.0 --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af7fd9b46..5feec39bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,9 +356,9 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -366,9 +366,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" @@ -1212,9 +1212,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.11.9" +version = "2023.12.0" dependencies = [ "base64", "built", @@ -1857,15 +1857,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ "bitflags 2.4.1", "errno 0.3.8", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 824c07c59..e1aaa9ebe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.11.9" +version = "2023.12.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 1f516ad4d..520e37b07 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.11.9 +rtx 2023.12.0 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.11.9/rtx-v2023.11.9-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.0/rtx-v2023.12.0-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index bec777b65..ccd464c43 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.11.9"; + version = "2023.12.0"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 1704a51b3..d12bcc855 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.11.9 +Version: 2023.12.0 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 3c84d707208f7707cbab2728d14e60b58d1662a4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:15:20 -0600 Subject: [PATCH 1133/1891] node: removed wrong log message --- lefthook.yml | 2 ++ src/plugins/core/node.rs | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lefthook.yml b/lefthook.yml index b2148884e..52553ed23 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -3,8 +3,10 @@ pre-commit: commands: pre-commit: run: just -v pre-commit + interactive: true lint: run: just -v lint + interactive: true skip_output: - meta - summary diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index a5ba95814..be2c6b94c 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -309,7 +309,6 @@ impl Plugin for NodePlugin { tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - pr.set_message("running node-build"); if *RTX_NODE_FORCE_COMPILE { self.install_compiled(config, tv, pr)?; } else { From a53156efd648c51f19151143df70ed4128ca14b7 Mon Sep 17 00:00:00 2001 From: Yash Thakur <45539777+ysthakur@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:28:51 -0500 Subject: [PATCH 1134/1891] Use def --env instead of def-env for Nushell script (#1037) * Replace def-env with def --env * Update rtx__shell__nushell__tests__hook_init.snap * Update rtx__shell__nushell__tests__hook_init_nix.snap --- src/shell/nushell.rs | 4 ++-- .../snapshots/rtx__shell__nushell__tests__hook_init.snap | 4 ++-- .../snapshots/rtx__shell__nushell__tests__hook_init_nix.snap | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index a71243018..4487e4c81 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -76,7 +76,7 @@ impl Shell for Nushell { }} }} - def-env "update-env" [] {{ + def --env "update-env" [] {{ for $var in $in {{ if $var.op == "set" {{ load-env {{($var.name): $var.value}} @@ -86,7 +86,7 @@ impl Shell for Nushell { }} }} - def-env rtx_hook [] {{ + def --env rtx_hook [] {{ ^"{exe}" hook-env{status} -s nu | parse vars | update-env diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap index 5f3ea9387..b50f1765f 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap @@ -42,7 +42,7 @@ def --wrapped rtx [command?: string, --help, ...rest: string] { } } -def-env "update-env" [] { +def --env "update-env" [] { for $var in $in { if $var.op == "set" { load-env {($var.name): $var.value} @@ -52,7 +52,7 @@ def-env "update-env" [] { } } -def-env rtx_hook [] { +def --env rtx_hook [] { ^"/some/dir/rtx" hook-env --status -s nu | parse vars | update-env diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap index 8447c2c9b..0508392e7 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap @@ -41,7 +41,7 @@ def --wrapped rtx [command?: string, --help, ...rest: string] { } } -def-env "update-env" [] { +def --env "update-env" [] { for $var in $in { if $var.op == "set" { load-env {($var.name): $var.value} @@ -51,7 +51,7 @@ def-env "update-env" [] { } } -def-env rtx_hook [] { +def --env rtx_hook [] { ^"/nix/store/rtx" hook-env --status -s nu | parse vars | update-env From fc5ad91a923c512fb749e3b70200a454af466b74 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:35:46 -0600 Subject: [PATCH 1135/1891] formatted codebase --- src/cache.rs | 1 - src/cli/activate.rs | 1 - src/cli/args/env_var.rs | 3 ++- src/cli/args/jobs.rs | 3 ++- src/cli/args/log_level.rs | 2 ++ src/cli/asdf.rs | 1 - src/cli/current.rs | 1 - src/cli/direnv/envrc.rs | 1 - src/cli/env.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/global.rs | 3 +-- src/cli/implode.rs | 3 ++- src/cli/install.rs | 4 +--- src/cli/latest.rs | 2 +- src/cli/outdated.rs | 2 +- src/cli/render_help.rs | 6 ++++-- src/cli/render_mangen.rs | 5 +++-- src/cli/self_update.rs | 1 - src/cli/shell.rs | 2 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 2 +- src/cli/use.rs | 2 +- src/cli/where.rs | 2 +- src/cli/which.rs | 2 +- src/cmd.rs | 8 +++++--- src/config/config_file/mod.rs | 1 - src/config/config_file/rtx_toml.rs | 1 - src/config/settings.rs | 3 ++- src/default_shorthands.rs | 5 +++-- src/direnv.rs | 15 ++++++++------- src/fake_asdf.rs | 2 +- src/http.rs | 7 ++++--- src/lock_file.rs | 6 ++++-- src/migrate.rs | 2 ++ src/plugins/core/deno.rs | 1 - src/plugins/core/go.rs | 1 - src/plugins/core/node.rs | 3 ++- src/plugins/core/node_build.rs | 1 - src/plugins/core/python.rs | 1 - src/plugins/core/ruby.rs | 1 - src/plugins/external_plugin_cache.rs | 10 ++++++---- src/plugins/script_manager.rs | 2 +- src/shell/bash.rs | 6 ++++-- src/shell/fish.rs | 6 ++++-- src/shell/nushell.rs | 6 ++++-- src/shell/xonsh.rs | 9 +++++---- src/shell/zsh.rs | 6 ++++-- src/shorthands.rs | 1 - src/timeout.rs | 3 ++- src/tool.rs | 1 - src/toolset/builder.rs | 3 ++- src/toolset/tool_version_list.rs | 6 +++--- 52 files changed, 93 insertions(+), 79 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index 5c10ecb49..006d5763f 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,5 +1,4 @@ use std::cmp::min; - use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 2c075d057..b33415fa2 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -3,7 +3,6 @@ use color_eyre::eyre::Result; use crate::cli::command::Command; use crate::config::Config; use crate::dirs; - use crate::env::RTX_EXE; use crate::file::touch_dir; use crate::output::Output; diff --git a/src/cli/args/env_var.rs b/src/cli/args/env_var.rs index 2e4f27eb1..bc37cd4c0 100644 --- a/src/cli/args/env_var.rs +++ b/src/cli/args/env_var.rs @@ -1,8 +1,9 @@ +use std::ffi::OsStr; + use clap::{ error::{ContextKind, ContextValue, ErrorKind}, Arg, Command, Error, }; -use std::ffi::OsStr; #[derive(Debug, Clone, Eq, PartialEq)] pub struct EnvVarArg { diff --git a/src/cli/args/jobs.rs b/src/cli/args/jobs.rs index 64a99fe86..f22faa239 100644 --- a/src/cli/args/jobs.rs +++ b/src/cli/args/jobs.rs @@ -1,6 +1,7 @@ +use std::num::ParseIntError; + use clap::builder::ValueParser; use clap::Arg; -use std::num::ParseIntError; #[derive(Clone)] pub struct Jobs(pub usize); diff --git a/src/cli/args/log_level.rs b/src/cli/args/log_level.rs index de849b764..83ac6a519 100644 --- a/src/cli/args/log_level.rs +++ b/src/cli/args/log_level.rs @@ -28,6 +28,7 @@ pub static DEFAULT_LOG_LEVEL: Lazy = Lazy::new(|| env::RTX_LOG_LEVEL.to_string().to_lowercase()); pub struct Debug; + impl Debug { pub fn arg() -> clap::Arg { Arg::new("debug") @@ -40,6 +41,7 @@ impl Debug { } pub struct Trace; + impl Trace { pub fn arg() -> clap::Arg { Arg::new("trace") diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index edae43cd0..660b1b2f5 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -72,7 +72,6 @@ fn list_versions(mut config: Config, out: &mut Output, args: &Vec) -> Re #[cfg(test)] mod tests { - use crate::{assert_cli, assert_cli_snapshot}; #[test] diff --git a/src/cli/current.rs b/src/cli/current.rs index e40e6563a..d759fc91f 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use crate::cli::command::Command; - use crate::config::Config; use crate::output::Output; use crate::plugins::unalias_plugin; diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 38a243538..8f7e958bf 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -60,7 +60,6 @@ impl Command for Envrc { #[cfg(test)] mod tests { - use insta::assert_display_snapshot; use crate::{assert_cli, file}; diff --git a/src/cli/env.rs b/src/cli/env.rs index 73b35031c..d28bb041f 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -19,7 +19,7 @@ pub struct Env { shell: Option, /// Tool(s) to use - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, /// Output in JSON format diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 87bfa6341..5826535fd 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -30,7 +30,7 @@ use crate::toolset::ToolsetBuilder; pub struct Exec { /// Tool(s) to start /// e.g.: node@20 python@3.10 - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] pub tool: Vec, /// Command string to execute (same as --command) diff --git a/src/cli/global.rs b/src/cli/global.rs index f78c86616..d19ba6d88 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -26,7 +26,7 @@ pub struct Global { /// e.g.: node@20 /// If this is a single tool with no version, the current value of the global /// .tool-versions will be displayed - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] tool: Vec, /// Save exact version to `~/.tool-versions` @@ -92,7 +92,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs, file}; diff --git a/src/cli/implode.rs b/src/cli/implode.rs index c5cfe917b..0fc0da774 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -1,6 +1,7 @@ -use color_eyre::eyre::Result; use std::path::Path; +use color_eyre::eyre::Result; + use crate::cli::command::Command; use crate::config::Config; use crate::file::remove_all; diff --git a/src/cli/install.rs b/src/cli/install.rs index e1ed25290..f1ce2a37d 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -3,9 +3,7 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; use crate::config::Config; - use crate::output::Output; - use crate::toolset::{ ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, }; @@ -24,7 +22,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; pub struct Install { /// Tool(s) to install /// e.g.: node@20 - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: Option>, /// Force reinstall even if already installed diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 5ab5f50e9..95b47f7f4 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -12,7 +12,7 @@ use crate::toolset::ToolVersionRequest; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Latest { /// Tool to get the latest version of - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: ToolArg, /// The version prefix to use when querying the latest version diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index ebbe36b4b..dba7a352c 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -18,7 +18,7 @@ pub struct Outdated { /// Tool(s) to show outdated versions for /// e.g.: node@20 python@3.10 /// If not specified, all tools in global and local configs will be shown - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] pub tool: Vec, } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9bede6bc3..ca08e90d8 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -106,10 +106,12 @@ fn remove_trailing_spaces(s: &str) -> String { #[cfg(test)] mod tests { - use crate::{assert_cli, file}; - use indoc::indoc; use std::fs; + use indoc::indoc; + + use crate::{assert_cli, file}; + #[test] fn test_render_help() { file::write( diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 85bd2a861..8bdc664e6 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -1,10 +1,11 @@ -use crate::cli::{version, Cli}; -use eyre::Result; use std::env; use std::fs; use std::path::{Path, PathBuf}; +use eyre::Result; + use crate::cli::command::Command; +use crate::cli::{version, Cli}; use crate::config::Config; use crate::output::Output; diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 0f54265d1..347c45f70 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -1,6 +1,5 @@ use color_eyre::Result; use console::style; - use self_update::backends::github::{ReleaseList, Update}; use self_update::update::Release; use self_update::{cargo_crate_version, Status}; diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 2738390ea..0f23cb8f3 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -16,7 +16,7 @@ use crate::toolset::{ToolSource, ToolsetBuilder}; #[clap(verbatim_doc_comment, alias = "s", after_long_help = AFTER_LONG_HELP)] pub struct Shell { /// Tool(s) to use - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, /// Removes a previously set version diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 894f1fb34..ba263a688 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -14,7 +14,7 @@ use crate::{runtime_symlinks, shims}; #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct Uninstall { /// Tool(s) to remove - #[clap(required = true, value_name="TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(required = true, value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, /// Delete all installed versions diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 802783202..8b6bb4b32 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -24,7 +24,7 @@ pub struct Upgrade { /// Tool(s) to upgrade /// e.g.: node@20 python@3.10 /// If not specified, all current tools will be upgraded - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] pub tool: Vec, } diff --git a/src/cli/use.rs b/src/cli/use.rs index 10ce3b82b..525f67d58 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -23,7 +23,7 @@ pub struct Use { /// Tool(s) to add to config file /// e.g.: node@20 /// If no version is specified, it will default to @latest - #[clap(value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment, required_unless_present = "remove")] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment, required_unless_present = "remove")] tool: Vec, /// Save exact version to config file diff --git a/src/cli/where.rs b/src/cli/where.rs index abbf6744c..dfb6f8edd 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -18,7 +18,7 @@ pub struct Where { /// if "@" is specified, it will show the latest installed version /// that matches the prefix /// otherwise, it will show the current, active installed version - #[clap(required = true, value_name="TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] + #[clap(required = true, value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] tool: ToolArg, /// the version prefix to use when querying the latest version diff --git a/src/cli/which.rs b/src/cli/which.rs index debf0b25e..f39d9d9a4 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -24,7 +24,7 @@ pub struct Which { /// Use a specific tool@version /// e.g.: `rtx which npm --tool=node@20` - #[clap(short, long, value_name = "TOOL@VERSION", value_parser=ToolArgParser, verbatim_doc_comment)] + #[clap(short, long, value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] pub tool: Option, } diff --git a/src/cmd.rs b/src/cmd.rs index 3a24ab6e4..6b238f3d6 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -1,4 +1,3 @@ -use color_eyre::Result; use std::ffi::{OsStr, OsString}; use std::fmt::{Display, Formatter}; use std::io::{BufRead, BufReader, Write}; @@ -7,12 +6,14 @@ use std::process::{Command, ExitStatus, Stdio}; use std::sync::mpsc::channel; use std::thread; +use color_eyre::Result; +use duct::{Expression, IntoExecutablePath}; +use eyre::Context; + use crate::config::Settings; use crate::errors::Error::ScriptFailed; use crate::file::display_path; use crate::ui::progress_report::ProgressReport; -use duct::{Expression, IntoExecutablePath}; -use eyre::Context; /// Create a command with any number of of positional arguments, which may be /// different types (anything that implements @@ -92,6 +93,7 @@ pub struct CmdLineRunner<'a> { pr: Option<&'a ProgressReport>, stdin: Option, } + impl<'a> CmdLineRunner<'a> { pub fn new>(settings: &'a Settings, program: P) -> Self { let mut cmd = Command::new(program); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 3476fd820..37c707b40 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::fmt::{Debug, Display}; - use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 9b4bf4daf..51214b677 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; - use std::path::{Path, PathBuf}; use std::time::Duration; diff --git a/src/config/settings.rs b/src/config/settings.rs index 94655eb00..a6778cac5 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -276,9 +276,10 @@ impl Display for MissingRuntimeBehavior { #[cfg(test)] mod tests { - use super::*; use crate::config::settings::MissingRuntimeBehavior::{AutoInstall, Ignore, Prompt, Warn}; + use super::*; + #[test] fn test_settings_merge() { let mut s1 = SettingsBuilder::default(); diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 5a9a9491a..db6e28790 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -15,9 +15,10 @@ // !GENERATED FILE! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -use once_cell::sync::Lazy; use std::collections::HashMap; +use once_cell::sync::Lazy; + pub static DEFAULT_SHORTHANDS: Lazy> = Lazy::new(|| HashMap::from(DEFAULT_SHORTHAND_LIST)); @@ -739,5 +740,5 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 714] = [ // rtx custom shorthands ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), - ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), + ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ]; diff --git a/src/direnv.rs b/src/direnv.rs index 6a55f4af8..bfdb8cb14 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -1,15 +1,15 @@ +use std::collections::HashMap; +use std::env::{join_paths, split_paths}; +use std::fmt::{Display, Formatter}; +use std::io::Write; +use std::path::{Path, PathBuf}; + use base64::prelude::*; use color_eyre::eyre::Result; use flate2::write::{ZlibDecoder, ZlibEncoder}; use flate2::Compression; use itertools::Itertools; use serde_derive::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::env::{join_paths, split_paths}; -use std::fmt::{Display, Formatter}; -use std::io::Write; - -use std::path::{Path, PathBuf}; #[derive(Debug, Serialize, Deserialize)] pub struct DirenvDiff { @@ -111,9 +111,10 @@ impl Display for DirenvDiff { #[cfg(test)] mod tests { - use super::*; use insta::assert_display_snapshot; + use super::*; + #[test] fn test_parse() { let input = r#"eJys0c1yojAAwPF3ybmWaLB-zPSAGCqIQCGgeGGIELDlM2BEOr77zs7szr7AXv-H3-X_Axqw_gGabYM1qPk1A88XUP1OW93FVhBtdReswURq-FXEfSqJmEusLpKUdxLspALRJY1Yt2Bifk8aLhf5iiZIhhDCjEtE6svmteGuSJVHAV7-qppuYrAG_0WVXtNK8Ms__KgQdYc9sAapMXRj1-9XW8VX7A16UA4NPIs9xCK5WO51XnvfwWBT1R9N7zIcHvvJbZF5g8pk0V2c5CboIw8_NjOUWDK5qcxIcaFrp3anhwdr5FeKJmfd9stgqvuVZqcXsXHYJ-kSGWpoxyZLzf0a0LUcMgv17exenXXunfOTZZfybiVmb9OAhjDtHEcOk0lrRWG84OrRobW6IgGGZqwelglTq8UmJrbP9p0x9pTW5t3L21P1mZfL7_pMtIW599v-Cx_dmzEdCcZ1TAzkz7dvfO4QAefO6Y4VxYmijzgP_Oz9Hbz8uU5jDp7PXwEAAP__wB6qKg=="#; diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 5c7fba3ef..0c7f386ed 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -1,9 +1,9 @@ -use color_eyre::eyre::ErrReport; use std::env::{join_paths, split_paths}; use std::fs; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; +use color_eyre::eyre::ErrReport; use indoc::formatdoc; use once_cell::sync::OnceCell; diff --git a/src/http.rs b/src/http.rs index b09f71dc1..6f5b522be 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,10 +1,11 @@ -use eyre::{Report, Result}; -use reqwest::blocking::{ClientBuilder, RequestBuilder}; -use reqwest::IntoUrl; use std::fs::File; use std::path::Path; use std::time::Duration; +use eyre::{Report, Result}; +use reqwest::blocking::{ClientBuilder, RequestBuilder}; +use reqwest::IntoUrl; + #[derive(Debug)] pub struct Client { reqwest: reqwest::blocking::Client, diff --git a/src/lock_file.rs b/src/lock_file.rs index 317f936aa..1a02be1a5 100644 --- a/src/lock_file.rs +++ b/src/lock_file.rs @@ -1,8 +1,10 @@ +use std::path::{Path, PathBuf}; + +use color_eyre::eyre::Result; + use crate::dirs; use crate::file::create_dir_all; use crate::hash::hash_to_str; -use color_eyre::eyre::Result; -use std::path::{Path, PathBuf}; pub type OnLockedFn = Box; diff --git a/src/migrate.rs b/src/migrate.rs index 8f85b45ad..34ed6d4e2 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -53,12 +53,14 @@ fn rename_plugin(from: &str, to: &str) -> Result<()> { move_subdirs(&PLUGINS.join(from), &PLUGINS.join(to))?; Ok(()) } + fn migrate_tracked_configs() -> Result<()> { let from = ROOT.join("tracked_config_files"); let to = ROOT.join("tracked-config-files"); move_dirs(&from, &to)?; Ok(()) } + fn migrate_trusted_configs() -> Result<()> { let cache_trusted_configs = CACHE.join("trusted-configs"); let config_trusted_configs = CONFIG.join("trusted-configs"); diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 910f2fb15..6ee7ad9d8 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; - use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 65029f042..c4d6176d1 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; - use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index be2c6b94c..796a8f33d 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; - use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -358,9 +357,11 @@ fn arch() -> &'static str { fn slug(v: &str, os: &str, arch: &str) -> String { format!("node-v{v}-{os}-{arch}") } + fn source_tarball_name(v: &str) -> String { format!("node-v{v}.tar.gz") } + fn binary_tarball_name(v: &str) -> String { format!("{}.tar.gz", slug(v, os(), arch())) } diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index f379996ed..468a0a4af 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; - use std::path::{Path, PathBuf}; use std::process::exit; diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 0a1e42169..d5fcc818b 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -5,7 +5,6 @@ use color_eyre::eyre::{eyre, Result}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; - use crate::file::create_dir_all; use crate::git::Git; use crate::plugins::core::CorePlugin; diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 84e2d2311..3fe8fe32c 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::env::temp_dir; - use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index b16e24ef3..11f4d826c 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -1,3 +1,9 @@ +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::RwLock; + +use color_eyre::eyre::{eyre, Result}; + use crate::cache::CacheManager; use crate::config::Config; use crate::hash::hash_to_str; @@ -5,10 +11,6 @@ use crate::plugins::ExternalPlugin; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::{dirs, env}; -use color_eyre::eyre::{eyre, Result}; -use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::RwLock; #[derive(Debug, Default)] pub struct ExternalPluginCache { diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index d0e1504af..1b9ed755e 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -1,4 +1,3 @@ -use crate::fake_asdf::get_path_with_fake_asdf; use std::collections::HashMap; use std::ffi::OsString; use std::fmt; @@ -15,6 +14,7 @@ use crate::cmd::{cmd, CmdLineRunner}; use crate::config::Settings; use crate::errors::Error; use crate::errors::Error::ScriptFailed; +use crate::fake_asdf::get_path_with_fake_asdf; use crate::file::{basename, display_path}; use crate::ui::progress_report::ProgressReport; use crate::{dirs, env}; diff --git a/src/shell/bash.rs b/src/shell/bash.rs index db3c5dbe2..c4f489f8e 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -76,10 +76,12 @@ impl Shell for Bash { #[cfg(test)] mod tests { - use super::*; - use crate::test::replace_path; use insta::assert_snapshot; + use crate::test::replace_path; + + use super::*; + #[test] fn test_hook_init() { let bash = Bash::default(); diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 9af41a919..e9fa618a2 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -104,10 +104,12 @@ impl Shell for Fish { #[cfg(test)] mod tests { - use super::*; - use crate::test::replace_path; use insta::assert_snapshot; + use crate::test::replace_path; + + use super::*; + #[test] fn test_hook_init() { let fish = Fish::default(); diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 4487e4c81..9b26875b8 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -118,10 +118,12 @@ impl Shell for Nushell { #[cfg(test)] mod tests { - use super::*; - use crate::test::replace_path; use insta::assert_snapshot; + use crate::test::replace_path; + + use super::*; + #[test] fn test_hook_init() { let nushell = Nushell::default(); diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 3217ac4b1..38cf0dfe5 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::path::Path; use indoc::formatdoc; @@ -7,8 +8,6 @@ use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] pub struct Xonsh {} -use std::borrow::Cow; - fn xonsh_escape_sq(input: &str) -> Cow { for (i, ch) in input.chars().enumerate() { if xonsh_escape_char(ch).is_some() { @@ -125,10 +124,12 @@ impl Shell for Xonsh { #[cfg(test)] mod tests { - use super::*; - use crate::test::replace_path; use insta::assert_snapshot; + use crate::test::replace_path; + + use super::*; + #[test] fn test_hook_init() { let xonsh = Xonsh::default(); diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index d60018756..c62ad431b 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -80,10 +80,12 @@ impl Shell for Zsh { #[cfg(test)] mod tests { - use super::*; - use crate::test::replace_path; use insta::assert_snapshot; + use crate::test::replace_path; + + use super::*; + #[test] fn test_hook_init() { let zsh = Zsh::default(); diff --git a/src/shorthands.rs b/src/shorthands.rs index 67c1caaef..b792bfca0 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; - use std::path::PathBuf; use color_eyre::eyre::Result; diff --git a/src/timeout.rs b/src/timeout.rs index f5e6caba4..b09812b6f 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -1,8 +1,9 @@ -use color_eyre::eyre::{Context, Result}; use std::sync::mpsc; use std::thread; use std::time::Duration; +use color_eyre::eyre::{Context, Result}; + pub fn run_with_timeout(f: F, timeout: Duration) -> Result where F: FnOnce() -> Result + Send, diff --git a/src/tool.rs b/src/tool.rs index 3491e3e05..279699385 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,7 +1,6 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Display}; - use std::fs::File; use std::path::{Path, PathBuf}; diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 12eefbf78..0bca046e2 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,6 +1,7 @@ +use std::collections::BTreeMap; + use color_eyre::eyre::Result; use itertools::Itertools; -use std::collections::BTreeMap; use crate::cli::args::tool::ToolArg; use crate::config::Config; diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 3b11dced7..25da135f9 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -40,13 +40,13 @@ impl ToolVersionList { #[cfg(test)] mod tests { - use crate::{dirs, env, file}; - use std::sync::Arc; - use super::*; use crate::plugins::ExternalPlugin; use crate::tool::Tool; + use crate::{dirs, env, file}; + + use super::*; #[test] fn test_tool_version_list() { From 7179287b0cf4bb6ac58418363c1149af45679e83 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:45:58 -0600 Subject: [PATCH 1136/1891] node: compilation options in .rtx.toml (#1040) --- README.md | 2 +- docs/node.md | 17 +- e2e/test_nodejs | 2 +- src/cli/direnv/exec.rs | 5 +- src/cli/local.rs | 2 +- src/cli/uninstall.rs | 6 +- src/cli/upgrade.rs | 9 +- src/cmd.rs | 2 +- src/config/config_file/rtx_toml.rs | 26 +-- src/config/mod.rs | 22 +-- src/env.rs | 20 +-- src/file.rs | 38 +++-- src/hash.rs | 19 +-- src/main.rs | 2 + src/plugins/core/node.rs | 238 ++++++++++++++++----------- src/plugins/core/node_build.rs | 6 +- src/plugins/external_plugin.rs | 26 ++- src/plugins/external_plugin_cache.rs | 5 +- src/plugins/script_manager.rs | 2 +- src/shims.rs | 12 +- src/ui/prompt.rs | 5 + 21 files changed, 272 insertions(+), 194 deletions(-) diff --git a/README.md b/README.md index 520e37b07..d50e63d9c 100644 --- a/README.md +++ b/README.md @@ -945,7 +945,7 @@ This will automatically answer yes or no to prompts. This is useful for scriptin Enables experimental features. -#### `RTX_ALL_FORCE_COMPILE=1` +#### `RTX_ALL_COMPILE=1` Default: false unless running NixOS or Alpine (let me know if others should be added) diff --git a/docs/node.md b/docs/node.md index 69f4567f6..80174bf4c 100644 --- a/docs/node.md +++ b/docs/node.md @@ -28,7 +28,7 @@ required system dependencies. - `RTX_NODE_BUILD_REPO` [string]: the default is `https://github.com/nodenv/node-build.git` - `RTX_NODE_VERIFY` [bool]: Verify the downloaded assets using GPG. Defaults to `true`. - `RTX_NODE_NINJA` [bool]: Use ninja instead of make to compile nodel. Defaults to `true` if installed. -- `RTX_NODE_FORCE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries. Can also be set across all languages with [`RTX_NODE_FORCE_COMPILE`](https://github.com/jdx/rtx#rtx_node_force_compile1) +- `RTX_NODE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries. Can also be set across all languages with [`RTX_NODE__COMPILE`](https://github.com/jdx/rtx#rtx_node_compile1) - `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores - `RTX_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` - `RTX_NODE_MIRROR_URL` [string]: overrides the default mirror used for downloading the distributions @@ -37,6 +37,21 @@ required system dependencies. - `RTX_NODE_MAKE_OPTS` [string]: Additional `make` options. - `RTX_NODE_MAKE_INSTALL_OPTS` [string]: Additional `make install` options. +## Tool Options + +The following are example options that can be set in `.rtx.toml` files. +Note env vars take precedence over these. + +```toml +[tool.node] +version = "20" +compile = true # do not use pre-compiled binaries +cflags = "-O3 -march=native" # additional CFLAGS options +configure_opts = "--debug" # command line options to pass to ./configure +make_opts = "-j 4" # command line options to pass to make +make_install_opts = "-j 4" # command line options to pass to make install +``` + ## Default node packages rtx-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-npm-packages` file that lists one package per line, for example: diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 36cf159f1..21df305b1 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -33,5 +33,5 @@ rtx uninstall node rtx i node assert "rtx x -- node --version" "v20.0.0" # rtx uninstall node -# RTX_NODE_FORCE_COMPILE=1 rtx i node +# RTX_NODE_COMPILE=1 rtx i node # assert "rtx x -- node --version" "v20.0.0" diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 568bb0ca7..67d6f3fa4 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -1,5 +1,6 @@ -use color_eyre::eyre::{eyre, Result}; use duct::Expression; +use eyre::Result; +use eyre::WrapErr; use serde_derive::Deserialize; use crate::cli::command::Command; @@ -37,7 +38,7 @@ impl Command for DirenvExec { let json = cmd!("direnv", "watch", "json", ".tool-versions") .read() - .map_err(|err| eyre!("error running direnv watch: {}", err))?; + .wrap_err("error running direnv watch")?; let w: DirenvWatches = serde_json::from_str(&json)?; cmd = cmd.env("DIRENV_WATCHES", w.watches); diff --git a/src/cli/local.rs b/src/cli/local.rs index c7fbf3bde..9f09c30b0 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -91,7 +91,7 @@ pub fn get_parent_path() -> Result { filenames.push(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); } file::find_up(&dirs::CURRENT, &filenames) - .with_context(|| eyre!("no {} file found", filenames.join(" or "),)) + .wrap_err_with(|| eyre!("no {} file found", filenames.join(" or "),)) } #[allow(clippy::too_many_arguments)] diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index ba263a688..dd4e63243 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,5 +1,5 @@ -use color_eyre::eyre::{bail, eyre, Result}; use console::style; +use eyre::{Result, WrapErr}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::command::Command; @@ -92,13 +92,13 @@ impl Command for Uninstall { plugin.decorate_progress_bar(&mut pr, Some(&tv)); if let Err(err) = plugin.uninstall_version(&config, &tv, &pr, self.dry_run) { pr.error(err.to_string()); - return Err(eyre!(err).wrap_err(format!("failed to uninstall {}", &tv))); + return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); } pr.finish_with_message("uninstalled"); } let ts = ToolsetBuilder::new().build(&mut config)?; - shims::reshim(&config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + shims::reshim(&config, &ts).wrap_err("failed to reshim")?; runtime_symlinks::rebuild(&config)?; Ok(()) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 8b6bb4b32..c6549183f 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -1,7 +1,8 @@ use std::collections::HashSet; use std::sync::Arc; -use color_eyre::eyre::{eyre, Result}; +use eyre::Result; +use eyre::WrapErr; use itertools::Itertools; use rayon::prelude::*; use rayon::ThreadPoolBuilder; @@ -64,7 +65,7 @@ impl Upgrade { self.install_new_versions(config, &mpr, outdated)?; let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; - shims::reshim(config, &ts).map_err(|err| eyre!("failed to reshim: {}", err))?; + shims::reshim(config, &ts).wrap_err("failed to reshim")?; runtime_symlinks::rebuild(config)?; Ok(()) @@ -112,7 +113,7 @@ impl Upgrade { Ok(_) => Ok(()), Err(err) => { pr.error(err.to_string()); - Err(err.wrap_err(format!("failed to install {}", tv))) + Err(err.wrap_err(format!("failed to install {tv}"))) } } } @@ -132,7 +133,7 @@ impl Upgrade { } Err(err) => { pr.error(err.to_string()); - Err(err.wrap_err(format!("failed to uninstall {}", tv))) + Err(err.wrap_err(format!("failed to uninstall {tv}"))) } } } diff --git a/src/cmd.rs b/src/cmd.rs index 6b238f3d6..84abe06d2 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -170,7 +170,7 @@ impl<'a> CmdLineRunner<'a> { let mut cp = self .cmd .spawn() - .with_context(|| format!("failed to execute command: {self}"))?; + .wrap_err_with(|| format!("failed to execute command: {self}"))?; let stdout = BufReader::new(cp.stdout.take().unwrap()); let stderr = BufReader::new(cp.stderr.take().unwrap()); let (tx, rx) = channel(); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 51214b677..8c1ca47df 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -5,6 +5,8 @@ use std::time::Duration; use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; +use console::style; +use eyre::WrapErr; use log::LevelFilter; use tera::Context; use toml_edit::{table, value, Array, Document, Item, Value}; @@ -13,7 +15,7 @@ use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::config::{config_file, global_config_files, AliasMap, MissingRuntimeBehavior}; use crate::errors::Error::UntrustedConfig; -use crate::file::create_dir_all; +use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ @@ -334,13 +336,14 @@ impl RtxToml { if k == "version" || k == "path" || k == "prefix" || k == "ref" { continue; } - match v.as_str() { - Some(s) => { - let s = self.parse_template(key, s)?; - opts.insert(k.into(), s); - } - _ => parse_error!(format!("{}.{}", key, k), v, "string")?, - } + let s = if let Some(s) = v.as_str() { + self.parse_template(key, s)? + } else if let Some(b) = v.as_bool() { + b.to_string() + } else { + parse_error!(key, v, "string or bool")? + }; + opts.insert(k.into(), s); } } _ => match v { @@ -631,7 +634,7 @@ impl RtxToml { let dir = self.path.parent().unwrap(); let output = get_tera(dir) .render_str(input, &self.context) - .map_err(|err| eyre!("failed to parse template: {k}='{}': {}", input, err))?; + .wrap_err_with(|| eyre!("failed to parse template: {k}='{input}'"))?; Ok(output) } @@ -643,8 +646,9 @@ impl RtxToml { } if cmd != "hook-env" { let ans = prompt::confirm(&format!( - "Config file {} is not trusted. Would you like to trust it?", - self.path.display() + "{} {} is not trusted. Trust it?", + style("rtx").yellow().for_stderr(), + display_path(&self.path) ))?; if ans { config_file::trust(self.path.as_path())?; diff --git a/src/config/mod.rs b/src/config/mod.rs index 127c45309..3db94cb2e 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -4,7 +4,8 @@ use std::path::PathBuf; use std::sync::Arc; use std::thread; -use color_eyre::eyre::{eyre, Result}; +use eyre::Context; +use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::OnceCell; @@ -266,14 +267,8 @@ fn load_rtxrc() -> Result { trace!("settings does not exist {:?}", settings_path); Ok(RtxToml::init(&settings_path, is_trusted)) } - true => match RtxToml::from_file(&settings_path, is_trusted) { - Ok(cf) => Ok(cf), - Err(err) => Err(eyre!( - "Error parsing {}: {:#}", - display_path(&settings_path), - err - )), - }, + true => RtxToml::from_file(&settings_path, is_trusted) + .wrap_err_with(|| format!("Error parsing {}", display_path(&settings_path))), } } @@ -402,10 +397,11 @@ fn load_all_config_files( // already parsed so just return it Some(cf) => Ok((f, cf)), // need to parse this config file - None => match parse_config_file(&f, settings, legacy_filenames, tools) { - Ok(cf) => Ok((f, cf)), - Err(err) => Err(eyre!("error reading config: {}\n{err:#}", display_path(&f))), - }, + None => { + let cf = parse_config_file(&f, settings, legacy_filenames, tools) + .wrap_err_with(|| format!("error parsing config file: {}", display_path(&f)))?; + Ok((f, cf)) + } }) .collect::>>() .into_iter() diff --git a/src/env.rs b/src/env.rs index 8fe271e62..206c6f621 100644 --- a/src/env.rs +++ b/src/env.rs @@ -116,14 +116,13 @@ pub static RTX_ALWAYS_KEEP_DOWNLOAD: Lazy = Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_DOWNLOAD")); pub static RTX_ALWAYS_KEEP_INSTALL: Lazy = Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_INSTALL")); -pub static RTX_ALL_FORCE_COMPILE: Lazy = - Lazy::new(|| match var_option_bool("RTX_ALL_FORCE_COMPILE") { - Some(v) => v, - None => matches!( - linux_distro().unwrap_or_default().as_str(), - "alpine" | "nixos" - ), - }); +pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| match var_option_bool("RTX_ALL_COMPILE") { + Some(v) => v, + None => matches!( + linux_distro().unwrap_or_default().as_str(), + "alpine" | "nixos" + ), +}); #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); @@ -177,8 +176,9 @@ pub static RTX_NODE_NINJA: Lazy = Lazy::new(|| match var_option_bool("RTX_ None => is_ninja_on_path(), }); pub static RTX_NODE_VERIFY: Lazy = Lazy::new(|| !var_is_false("RTX_NODE_VERIFY")); -pub static RTX_NODE_FORCE_COMPILE: Lazy = - Lazy::new(|| *RTX_ALL_FORCE_COMPILE || var_is_true("RTX_NODE_FORCE_COMPILE")); +pub static RTX_NODE_COMPILE: Lazy = Lazy::new(|| { + *RTX_ALL_COMPILE || var_is_true("RTX_NODE_COMPILE") || var_is_true("RTX_NODE_FORCE_COMPILE") +}); pub static RTX_NODE_CFLAGS: Lazy> = Lazy::new(|| var("RTX_NODE_CFLAGS").or_else(|_| var("NODE_CFLAGS")).ok()); pub static RTX_NODE_CONFIGURE_OPTS: Lazy> = Lazy::new(|| { diff --git a/src/file.rs b/src/file.rs index e440ef29f..2a2e4e565 100644 --- a/src/file.rs +++ b/src/file.rs @@ -19,9 +19,9 @@ pub fn remove_all>(path: P) -> Result<()> { remove_file(path)?; } Ok(x) if x.is_dir() => { - trace!("rm -rf {}", path.display()); + trace!("rm -rf {}", display_path(path)); fs::remove_dir_all(path) - .with_context(|| format!("failed rm -rf: {}", path.display()))?; + .wrap_err_with(|| format!("failed rm -rf: {}", display_path(path)))?; } _ => {} }; @@ -30,14 +30,14 @@ pub fn remove_all>(path: P) -> Result<()> { pub fn remove_file>(path: P) -> Result<()> { let path = path.as_ref(); - trace!("rm {}", path.display()); - fs::remove_file(path).with_context(|| format!("failed rm: {}", path.display())) + trace!("rm {}", display_path(path)); + fs::remove_file(path).wrap_err_with(|| format!("failed rm: {}", display_path(path))) } pub fn remove_dir>(path: P) -> Result<()> { let path = path.as_ref(); - trace!("rmdir {}", path.display()); - fs::remove_dir(path).with_context(|| format!("failed rmdir: {}", path.display())) + trace!("rmdir {}", display_path(path)); + fs::remove_dir(path).wrap_err_with(|| format!("failed rmdir: {}", display_path(path))) } pub fn remove_all_with_warning>(path: P) -> Result<()> { @@ -51,26 +51,33 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> Result<()> { let from = from.as_ref(); let to = to.as_ref(); trace!("mv {} {}", from.display(), to.display()); - fs::rename(from, to) - .with_context(|| format!("failed rename: {} -> {}", from.display(), to.display())) + fs::rename(from, to).wrap_err_with(|| { + format!( + "failed rename: {} -> {}", + display_path(from), + display_path(to) + ) + }) } pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { let path = path.as_ref(); - trace!("write {}", path.display()); - fs::write(path, contents).with_context(|| format!("failed write: {}", path.display())) + trace!("write {}", display_path(path)); + fs::write(path, contents).wrap_err_with(|| format!("failed write: {}", display_path(path))) } pub fn read_to_string>(path: P) -> Result { let path = path.as_ref(); - trace!("cat {}", path.display()); - fs::read_to_string(path).with_context(|| format!("failed read_to_string: {}", path.display())) + trace!("cat {}", display_path(path)); + fs::read_to_string(path) + .wrap_err_with(|| format!("failed read_to_string: {}", display_path(path))) } pub fn create_dir_all>(path: P) -> Result<()> { let path = path.as_ref(); - trace!("mkdir -p {}", path.display()); - fs::create_dir_all(path).with_context(|| format!("failed create_dir_all: {}", path.display())) + trace!("mkdir -p {}", display_path(path)); + fs::create_dir_all(path) + .wrap_err_with(|| format!("failed create_dir_all: {}", display_path(path))) } pub fn basename(path: &Path) -> Option { @@ -98,7 +105,8 @@ pub fn replace_path>(path: P) -> PathBuf { pub fn touch_dir(dir: &Path) -> Result<()> { trace!("touch {}", dir.display()); let now = FileTime::now(); - set_file_times(dir, now, now).with_context(|| format!("failed to touch dir: {}", dir.display())) + set_file_times(dir, now, now) + .wrap_err_with(|| format!("failed to touch dir: {}", display_path(dir))) } pub fn modified_duration(path: &Path) -> Result { diff --git a/src/hash.rs b/src/hash.rs index 7786cf328..223b23c18 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -4,10 +4,12 @@ use std::fs::File; use std::hash::{Hash, Hasher}; use std::path::Path; -use color_eyre::eyre::{bail, Result}; +use eyre::Result; use rayon::prelude::*; use sha2::{Digest, Sha256}; +use crate::file::display_path; + pub fn hash_to_str(t: &T) -> String { let mut s = DefaultHasher::new(); t.hash(&mut s); @@ -20,19 +22,16 @@ pub fn file_hash_sha256(path: &Path) -> Result { let mut hasher = Sha256::new(); std::io::copy(&mut file, &mut hasher)?; let hash = hasher.finalize(); - Ok(format!("{:x}", hash)) + Ok(format!("{hash:x}")) } pub fn ensure_checksum_sha256(path: &Path, checksum: &str) -> Result<()> { let actual = file_hash_sha256(path)?; - if actual != checksum { - bail!( - "Checksum mismatch for file {:?}:\nExpected: {}\nActual: {}", - path, - checksum, - actual - ); - } + ensure!( + actual == checksum, + "Checksum mismatch for file {}:\nExpected: {checksum}\nActual: {actual}", + display_path(path), + ); Ok(()) } diff --git a/src/main.rs b/src/main.rs index 14e49b2d8..9dc22b27e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ extern crate core; #[macro_use] extern crate log; +#[macro_use] +extern crate eyre; use std::process::exit; diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 796a8f33d..9e2972b38 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -9,11 +9,7 @@ use url::Url; use crate::build_time::built_info; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::env::{ - RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_CFLAGS, RTX_NODE_CONCURRENCY, - RTX_NODE_CONFIGURE_OPTS, RTX_NODE_FORCE_COMPILE, RTX_NODE_MAKE, RTX_NODE_MAKE_INSTALL_OPTS, - RTX_NODE_MAKE_OPTS, RTX_NODE_MIRROR_URL, RTX_NODE_NINJA, RTX_NODE_VERIFY, RTX_TMP_DIR, -}; +use crate::env::{RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_MIRROR_URL}; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::ToolVersion; @@ -51,44 +47,60 @@ impl NodePlugin { Ok(versions) } - fn install_precompiled(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - let slug = slug(&tv.version, os(), arch()); - let tarball_name = binary_tarball_name(&tv.version); - let tmp_tarball = tv.download_path().join(&tarball_name); - let url = self.binary_tarball_url(&tv.version)?; - self.fetch_tarball(pr, url, &tmp_tarball, &tv.version)?; + fn install_precompiled( + &self, + config: &Config, + pr: &ProgressReport, + opts: &BuildOpts, + ) -> Result<()> { + match self.fetch_tarball( + pr, + &opts.binary_tarball_url, + &opts.binary_tarball_path, + &opts.version, + ) { + Err(e) if matches!(http::error_code(&e), Some(404)) => { + debug!("precompiled node not found"); + self.install_compiled(config, pr, opts) + } + e => e, + }?; + let tarball_name = &opts.binary_tarball_name; pr.set_message(format!("extracting {tarball_name}")); - let tmp_extract_path = tempdir_in(tv.install_path().parent().unwrap())?; - file::untar(&tmp_tarball, tmp_extract_path.path())?; - file::remove_all(tv.install_path())?; - file::rename(tmp_extract_path.path().join(slug), tv.install_path())?; + let tmp_extract_path = tempdir_in(opts.install_path.parent().unwrap())?; + file::untar(&opts.binary_tarball_path, tmp_extract_path.path())?; + file::remove_all(&opts.install_path)?; + let slug = format!("node-v{}-{}-{}", &opts.version, os(), arch()); + file::rename(tmp_extract_path.path().join(slug), &opts.install_path)?; Ok(()) } fn install_compiled( &self, config: &Config, - tv: &ToolVersion, pr: &ProgressReport, + opts: &BuildOpts, ) -> Result<()> { - let tarball_name = source_tarball_name(&tv.version); - let tmp_tarball = tv.download_path().join(&tarball_name); - let url = self.source_tarball_url(&tv.version)?; - self.fetch_tarball(pr, url, &tmp_tarball, &tv.version)?; + let tarball_name = &opts.source_tarball_name; + self.fetch_tarball( + pr, + &opts.source_tarball_url, + &opts.source_tarball_path, + &opts.version, + )?; pr.set_message(format!("extracting {tarball_name}")); - let build_dir = RTX_TMP_DIR.join(format!("node-v{}", tv.version)); - file::remove_all(&build_dir)?; - file::untar(&tmp_tarball, &RTX_TMP_DIR)?; - self.exec_configure(config, pr, &build_dir, &tv.install_path())?; - self.exec_make(config, pr, &build_dir)?; - self.exec_make_install(config, pr, &build_dir)?; + file::remove_all(&opts.build_dir)?; + file::untar(&opts.source_tarball_path, opts.build_dir.parent().unwrap())?; + self.exec_configure(config, pr, opts)?; + self.exec_make(config, pr, opts)?; + self.exec_make_install(config, pr, opts)?; Ok(()) } fn fetch_tarball( &self, pr: &ProgressReport, - url: Url, + url: &Url, local: &Path, version: &str, ) -> Result<()> { @@ -97,9 +109,9 @@ impl NodePlugin { pr.set_message(format!("using previously downloaded {tarball_name}")); } else { pr.set_message(format!("downloading {tarball_name}")); - self.http.download_file(url, local)?; + self.http.download_file(url.clone(), local)?; } - if *RTX_NODE_VERIFY { + if *env::RTX_NODE_VERIFY { pr.set_message(format!("verifying {tarball_name}")); self.verify(local, version)?; } @@ -110,58 +122,36 @@ impl NodePlugin { &'a self, settings: &'a Settings, pr: &'a ProgressReport, - dir: &Path, + opts: &BuildOpts, ) -> CmdLineRunner { let mut cmd = CmdLineRunner::new(settings, "sh") .with_pr(pr) - .current_dir(dir) + .current_dir(&opts.build_dir) .arg("-c"); - if let Some(cflags) = &*RTX_NODE_CFLAGS { + if let Some(cflags) = &opts.cflags { cmd = cmd.env("CFLAGS", cflags); } cmd } - fn exec_configure( - &self, - config: &Config, - pr: &ProgressReport, - build_dir: &Path, - out: &Path, - ) -> Result<()> { - self.sh(&config.settings, pr, build_dir) - .arg(format!( - "./configure --prefix={} {} {}", - out.display(), - if *RTX_NODE_NINJA { "--ninja" } else { "" }, - RTX_NODE_CONFIGURE_OPTS.clone().unwrap_or_default() - )) + fn exec_configure(&self, config: &Config, pr: &ProgressReport, opts: &BuildOpts) -> Result<()> { + self.sh(&config.settings, pr, opts) + .arg(&opts.configure_cmd) .execute() } - fn exec_make(&self, config: &Config, pr: &ProgressReport, build_dir: &Path) -> Result<()> { - self.sh(&config.settings, pr, build_dir) - .arg(format!( - "{} {} {}", - &*RTX_NODE_MAKE, - RTX_NODE_CONCURRENCY - .map(|c| format!("-j{}", c)) - .unwrap_or_default(), - RTX_NODE_MAKE_OPTS.clone().unwrap_or_default() - )) + fn exec_make(&self, config: &Config, pr: &ProgressReport, opts: &BuildOpts) -> Result<()> { + self.sh(&config.settings, pr, opts) + .arg(&opts.make_cmd) .execute() } fn exec_make_install( &self, config: &Config, pr: &ProgressReport, - build_dir: &Path, + opts: &BuildOpts, ) -> Result<()> { - self.sh(&config.settings, pr, build_dir) - .arg(format!( - "{} install {}", - &*RTX_NODE_MAKE, - RTX_NODE_MAKE_INSTALL_OPTS.clone().unwrap_or_default() - )) + self.sh(&config.settings, pr, opts) + .arg(&opts.make_install_cmd) .execute() } @@ -234,14 +224,6 @@ impl NodePlugin { .execute() } - fn source_tarball_url(&self, v: &str) -> Result { - let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/{}", source_tarball_name(v)))?; - Ok(url) - } - fn binary_tarball_url(&self, v: &str) -> Result { - let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/{}", binary_tarball_name(v)))?; - Ok(url) - } fn shasums_url(&self, v: &str) -> Result { // let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt.asc"))?; let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt"))?; @@ -308,17 +290,12 @@ impl Plugin for NodePlugin { tv: &ToolVersion, pr: &ProgressReport, ) -> Result<()> { - if *RTX_NODE_FORCE_COMPILE { - self.install_compiled(config, tv, pr)?; + let opts = BuildOpts::new(tv)?; + debug!("node build opts: {:#?}", opts); + if opts.compile { + self.install_compiled(config, pr, &opts)?; } else { - match self.install_precompiled(tv, pr) { - Err(e) if matches!(http::error_code(&e), Some(404)) => { - debug!("precompiled node not found"); - self.install_compiled(config, tv, pr)?; - } - Err(e) => return Err(e), - Ok(()) => {} - } + self.install_precompiled(config, pr, &opts)?; } self.test_node(config, tv, pr)?; self.install_npm_shim(tv)?; @@ -328,6 +305,93 @@ impl Plugin for NodePlugin { } } +#[derive(Debug)] +struct BuildOpts { + version: String, + compile: bool, + install_path: PathBuf, + build_dir: PathBuf, + cflags: Option, + configure_cmd: String, + make_cmd: String, + make_install_cmd: String, + source_tarball_name: String, + source_tarball_path: PathBuf, + source_tarball_url: Url, + binary_tarball_name: String, + binary_tarball_path: PathBuf, + binary_tarball_url: Url, +} + +impl BuildOpts { + fn new(tv: &ToolVersion) -> Result { + let v = &tv.version; + let install_path = tv.install_path(); + let source_tarball_name = format!("node-v{v}.tar.gz"); + let binary_tarball_name = format!("node-v{v}-{}-{}.tar.gz", os(), arch()); + + Ok(Self { + version: v.clone(), + build_dir: env::RTX_TMP_DIR.join(format!("node-v{v}")), + compile: *env::RTX_NODE_COMPILE || tv.opts.get("compile").is_some_and(|v| v == "true"), + cflags: env::RTX_NODE_CFLAGS + .clone() + .or_else(|| tv.opts.get("cflags").cloned()), + configure_cmd: configure_cmd(tv, &install_path), + make_cmd: make_cmd(tv), + make_install_cmd: make_install_cmd(tv), + source_tarball_path: tv.download_path().join(&source_tarball_name), + source_tarball_url: env::RTX_NODE_MIRROR_URL + .join(&format!("v{v}/{source_tarball_name}"))?, + source_tarball_name, + binary_tarball_path: tv.download_path().join(&binary_tarball_name), + binary_tarball_url: env::RTX_NODE_MIRROR_URL + .join(&format!("v{v}/{binary_tarball_name}"))?, + binary_tarball_name, + install_path, + }) + } +} + +fn configure_cmd(tv: &ToolVersion, install_path: &Path) -> String { + let configure_opts = env::RTX_NODE_CONFIGURE_OPTS + .clone() + .or_else(|| tv.opts.get("configure_opts").cloned()); + let mut configure_cmd = format!("./configure --prefix={}", install_path.display()); + if *env::RTX_NODE_NINJA { + configure_cmd.push_str(" --ninja"); + } + if let Some(opts) = configure_opts { + configure_cmd.push_str(&format!(" {}", opts)); + } + configure_cmd +} + +fn make_cmd(tv: &ToolVersion) -> String { + let mut make_cmd = env::RTX_NODE_MAKE.to_string(); + if let Some(concurrency) = *env::RTX_NODE_CONCURRENCY { + make_cmd.push_str(&format!(" -j{concurrency}")); + } + let make_opts = env::RTX_NODE_MAKE_OPTS + .clone() + .or_else(|| tv.opts.get("make_opts").cloned()); + if let Some(opts) = make_opts { + make_cmd.push_str(&format!(" {opts}")); + } + make_cmd +} + +fn make_install_cmd(tv: &ToolVersion) -> String { + let mut make_install_cmd = format!("{} install", &*env::RTX_NODE_MAKE); + let make_install_opts = env::RTX_NODE_MAKE_INSTALL_OPTS + .clone() + .or_else(|| tv.opts.get("make_install_opts").cloned()); + if let Some(opts) = make_install_opts { + make_install_cmd.push_str(&format!(" {opts}")); + } + make_install_cmd +} + fn os() -> &'static str { if cfg!(target_os = "linux") { "linux" @@ -354,18 +418,6 @@ fn arch() -> &'static str { } } -fn slug(v: &str, os: &str, arch: &str) -> String { - format!("node-v{v}-{os}-{arch}") -} - -fn source_tarball_name(v: &str) -> String { - format!("node-v{v}.tar.gz") -} - -fn binary_tarball_name(v: &str) -> String { - format!("{}.tar.gz", slug(v, os(), arch())) -} - #[derive(Debug, Deserialize)] struct NodeVersion { version: String, diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index 468a0a4af..6cfbd92c0 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -8,9 +8,7 @@ use color_eyre::eyre::Result; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::duration::DAILY; -use crate::env::{ - RTX_NODE_CONCURRENCY, RTX_NODE_FORCE_COMPILE, RTX_NODE_MAKE_OPTS, RTX_NODE_MIRROR_URL, -}; +use crate::env::{RTX_NODE_COMPILE, RTX_NODE_CONCURRENCY, RTX_NODE_MAKE_OPTS, RTX_NODE_MIRROR_URL}; use crate::file::create_dir_all; use crate::git::Git; use crate::lock_file::LockFile; @@ -266,7 +264,7 @@ impl Plugin for NodeBuildPlugin { .env("NODE_BUILD_MIRROR_URL", RTX_NODE_MIRROR_URL.to_string()) .envs(&config.env) .arg(tv.version.as_str()); - if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_FORCE_COMPILE { + if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_COMPILE { let mut make_opts = RTX_NODE_MAKE_OPTS.clone().unwrap_or_default(); if let Some(concurrency) = *RTX_NODE_CONCURRENCY { make_opts = format!("{} -j{}", make_opts, concurrency); diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index c50e6c269..5dc81e80d 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -16,7 +16,7 @@ use crate::config::{Config, Settings}; use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; -use crate::file::remove_all; +use crate::file::{display_path, remove_all}; use crate::git::Git; use crate::hash::hash_to_str; use crate::plugins::external_plugin_cache::ExternalPluginCache; @@ -134,9 +134,9 @@ impl ExternalPlugin { }, *RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, ) - .map_err(|err| { + .wrap_err_with(|| { let script = self.script_man.get_script_path(&Script::ListAll); - eyre!("Failed to run {}: {}", script.display(), err) + eyre!("Failed to run {}", display_path(&script)) })?; let stdout = String::from_utf8(result.stdout).unwrap(); let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); @@ -355,11 +355,10 @@ impl Plugin for ExternalPlugin { fn list_remote_versions(&self, settings: &Settings) -> Result> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions(settings)) - .map_err(|err| { + .wrap_err_with(|| { eyre!( - "Failed listing remote versions for plugin {}: {}", + "Failed listing remote versions for plugin {}", style(&self.name).cyan().for_stderr(), - err ) }) .cloned() @@ -371,11 +370,10 @@ impl Plugin for ExternalPlugin { } self.latest_stable_cache .get_or_try_init(|| self.fetch_latest_stable(settings)) - .map_err(|err| { + .wrap_err_with(|| { eyre!( - "Failed fetching latest stable version for plugin {}: {}", + "Failed fetching latest stable version for plugin {}", style(&self.name).cyan().for_stderr(), - err ) }) .cloned() @@ -487,11 +485,10 @@ impl Plugin for ExternalPlugin { let aliases = self .alias_cache .get_or_try_init(|| self.fetch_aliases(settings)) - .map_err(|err| { + .wrap_err_with(|| { eyre!( - "Failed fetching aliases for plugin {}: {}", + "Failed fetching aliases for plugin {}", style(&self.name).cyan().for_stderr(), - err ) })? .iter() @@ -509,11 +506,10 @@ impl Plugin for ExternalPlugin { } self.legacy_filename_cache .get_or_try_init(|| self.fetch_legacy_filenames(settings)) - .map_err(|err| { + .wrap_err_with(|| { eyre!( - "Failed fetching legacy filenames for plugin {}: {}", + "Failed fetching legacy filenames for plugin {}", style(&self.name).cyan().for_stderr(), - err ) }) .cloned() diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 11f4d826c..a8136f34d 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use std::path::PathBuf; use std::sync::RwLock; -use color_eyre::eyre::{eyre, Result}; +use eyre::WrapErr; +use eyre::{eyre, Result}; use crate::cache::CacheManager; use crate::config::Config; @@ -97,5 +98,5 @@ fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> Result Result<()> { for shim in shims_to_add { let symlink_path = dirs::SHIMS.join(shim); - file::make_symlink(&rtx_bin, &symlink_path).map_err(|err| { + file::make_symlink(&rtx_bin, &symlink_path).wrap_err_with(|| { eyre!( - "Failed to create symlink from {} to {}: {}", - rtx_bin.display(), - symlink_path.display(), - err + "Failed to create symlink from {} to {}", + display_path(&rtx_bin), + display_path(&symlink_path) ) })?; } diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index a97ca40b4..dd663453f 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,10 +1,15 @@ use std::io; +use std::sync::Mutex; use dialoguer::Confirm; use crate::env; +static MUTEX: Mutex<()> = Mutex::new(()); + pub fn confirm(message: &str) -> io::Result { + let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once + match *env::RTX_CONFIRM { env::Confirm::Yes => return Ok(true), env::Confirm::No => return Ok(false), From 3771d97188db81206adc4815fd99f62a8f92f76c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:47:01 -0600 Subject: [PATCH 1137/1891] chore: Release rtx-cli version 2023.12.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 5 ++--- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5feec39bc..48a3df59e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.0" +version = "2023.12.1" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index e1aaa9ebe..444b38bea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.0" +version = "2023.12.1" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index d50e63d9c..13f47df86 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.0 +rtx 2023.12.1 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.0/rtx-v2023.12.0-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.1/rtx-v2023.12.1-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ccd464c43..db94d34cb 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.0"; + version = "2023.12.1"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index d12bcc855..56f4e22d1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.0 +Version: 2023.12.1 Release: 1 URL: https://github.com/jdx/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index db6e28790..5a9a9491a 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -15,9 +15,8 @@ // !GENERATED FILE! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -use std::collections::HashMap; - use once_cell::sync::Lazy; +use std::collections::HashMap; pub static DEFAULT_SHORTHANDS: Lazy> = Lazy::new(|| HashMap::from(DEFAULT_SHORTHAND_LIST)); @@ -740,5 +739,5 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 714] = [ // rtx custom shorthands ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), - ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), + ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ]; From 3e3d84a0518fe084e08a7a065350bc5e885a5bfc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:06:40 -0600 Subject: [PATCH 1138/1891] node: fixed behavior when using RTX_EXPERIMENTAL + NODE_BUILD=1 --- src/env.rs | 5 +---- src/plugins/core/mod.rs | 11 ++++++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/env.rs b/src/env.rs index 206c6f621..e931921e6 100644 --- a/src/env.rs +++ b/src/env.rs @@ -142,10 +142,7 @@ pub static PYENV_ROOT: Lazy = Lazy::new(|| var_path("PYENV_ROOT").unwrap_or_else(|| HOME.join(".pyenv"))); // node -pub static RTX_NODE_BUILD: Lazy = Lazy::new(|| match var_option_bool("RTX_NODE_BUILD") { - Some(v) => v, - _ => !*RTX_EXPERIMENTAL, -}); +pub static RTX_NODE_BUILD: Lazy> = Lazy::new(|| var_option_bool("RTX_NODE_BUILD")); pub static RTX_NODE_BUILD_REPO: Lazy = Lazy::new(|| { var("RTX_NODE_BUILD_REPO").unwrap_or_else(|_| "https://github.com/nodenv/node-build.git".into()) }); diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index a9de8f49a..9d8a8e21f 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -38,10 +38,10 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ Box::new(GoPlugin::new()), Box::new(JavaPlugin::new()), - if *RTX_NODE_BUILD { - Box::new(NodeBuildPlugin::new()) - } else { + if *RTX_NODE_BUILD == Some(false) { Box::new(NodePlugin::new()) + } else { + Box::new(NodeBuildPlugin::new()) }, Box::new(PythonPlugin::new()), Box::new(RubyPlugin::new()), @@ -52,6 +52,11 @@ pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ Box::new(BunPlugin::new()), Box::new(DenoPlugin::new()), + if *RTX_NODE_BUILD == Some(true) { + Box::new(NodeBuildPlugin::new()) + } else { + Box::new(NodePlugin::new()) + }, ]) }); From eee2d57e5a09ee6177ce2f75fc2efb7d7894870d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 17:31:11 -0600 Subject: [PATCH 1139/1891] refactor: remove unused Command trait --- src/cli/activate.rs | 5 ++--- src/cli/alias/get.rs | 5 ++--- src/cli/alias/ls.rs | 5 ++--- src/cli/alias/mod.rs | 5 ++--- src/cli/alias/set.rs | 5 ++--- src/cli/alias/unset.rs | 5 ++--- src/cli/asdf.rs | 5 ++--- src/cli/bin_paths.rs | 5 ++--- src/cli/cache/clear.rs | 5 ++--- src/cli/cache/mod.rs | 5 ++--- src/cli/command.rs | 12 ------------ src/cli/completion.rs | 5 ++--- src/cli/current.rs | 7 ++----- src/cli/deactivate.rs | 5 ++--- src/cli/direnv/activate.rs | 5 ++--- src/cli/direnv/envrc.rs | 5 ++--- src/cli/direnv/exec.rs | 5 ++--- src/cli/direnv/mod.rs | 5 ++--- src/cli/doctor.rs | 5 ++--- src/cli/env.rs | 7 ++----- src/cli/env_vars.rs | 5 ++--- src/cli/exec.rs | 7 ++----- src/cli/global.rs | 5 ++--- src/cli/hook_env.rs | 7 ++----- src/cli/implode.rs | 7 ++----- src/cli/install.rs | 8 ++------ src/cli/latest.rs | 5 ++--- src/cli/link.rs | 5 ++--- src/cli/local.rs | 5 ++--- src/cli/ls.rs | 35 ++++++++++++++++------------------- src/cli/ls_remote.rs | 5 ++--- src/cli/mod.rs | 2 -- src/cli/outdated.rs | 11 ++++------- src/cli/plugins/install.rs | 7 ++----- src/cli/plugins/link.rs | 5 ++--- src/cli/plugins/ls.rs | 5 ++--- src/cli/plugins/ls_remote.rs | 5 ++--- src/cli/plugins/mod.rs | 5 ++--- src/cli/plugins/uninstall.rs | 7 ++----- src/cli/plugins/update.rs | 5 ++--- src/cli/prune.rs | 7 ++----- src/cli/render_help.rs | 5 ++--- src/cli/render_mangen.rs | 5 ++--- src/cli/reshim.rs | 5 ++--- src/cli/self_update.rs | 7 ++----- src/cli/settings/get.rs | 5 ++--- src/cli/settings/ls.rs | 5 ++--- src/cli/settings/mod.rs | 5 ++--- src/cli/settings/set.rs | 5 ++--- src/cli/settings/unset.rs | 5 ++--- src/cli/shell.rs | 5 ++--- src/cli/sync/mod.rs | 5 ++--- src/cli/sync/node.rs | 7 ++----- src/cli/sync/python.rs | 5 ++--- src/cli/trust.rs | 5 ++--- src/cli/uninstall.rs | 5 ++--- src/cli/upgrade.rs | 13 +++++-------- src/cli/use.rs | 5 ++--- src/cli/version.rs | 5 ++--- src/cli/where.rs | 5 ++--- src/cli/which.rs | 8 ++------ src/shims.rs | 1 - 62 files changed, 137 insertions(+), 243 deletions(-) delete mode 100644 src/cli/command.rs diff --git a/src/cli/activate.rs b/src/cli/activate.rs index b33415fa2..974861b59 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::dirs; use crate::env::RTX_EXE; @@ -46,8 +45,8 @@ pub struct Activate { quiet: bool, } -impl Command for Activate { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { +impl Activate { + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { let shell = get_shell(self.shell_type.or(self.shell)) .expect("no shell provided, use `--shell=zsh`"); diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index fe157093c..3640f4b00 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::{eyre, Result}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -17,8 +16,8 @@ pub struct AliasGet { pub alias: String, } -impl Command for AliasGet { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl AliasGet { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { match config.get_all_aliases().get(&self.plugin) { Some(plugin) => match plugin.get(&self.alias) { Some(alias) => Ok(rtxprintln!(out, "{}", alias)), diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index cc118ca71..d661a1415 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::PluginName; @@ -21,8 +20,8 @@ pub struct AliasLs { pub plugin: Option, } -impl Command for AliasLs { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl AliasLs { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { for (plugin_name, aliases) in config.get_all_aliases() { if let Some(plugin) = &self.plugin { if plugin_name != plugin { diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index d55148cd1..3a64a6771 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::PluginName; @@ -41,8 +40,8 @@ impl Commands { } } -impl Command for Alias { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Alias { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::AliasLs { plugin: self.plugin, })); diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 70e3baa6d..5ce37dbf7 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; @@ -19,8 +18,8 @@ pub struct AliasSet { pub value: String, } -impl Command for AliasSet { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl AliasSet { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { config .global_config .set_alias(&self.plugin, &self.alias, &self.value); diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 4c4c104bc..10373368e 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; @@ -17,8 +16,8 @@ pub struct AliasUnset { pub alias: String, } -impl Command for AliasUnset { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl AliasUnset { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { config.global_config.remove_alias(&self.plugin, &self.alias); config.global_config.save() } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 660b1b2f5..4a355228e 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use itertools::Itertools; -use crate::cli::command::Command; use crate::cli::Cli; use crate::config::Config; use crate::output::Output; @@ -16,8 +15,8 @@ pub struct Asdf { args: Vec, } -impl Command for Asdf { - fn run(mut self, config: Config, out: &mut Output) -> Result<()> { +impl Asdf { + pub fn run(mut self, config: Config, out: &mut Output) -> Result<()> { let mut args = vec![String::from("rtx")]; args.append(&mut self.args); diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 12a4850b4..252086c56 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::toolset::ToolsetBuilder; @@ -10,8 +9,8 @@ use crate::toolset::ToolsetBuilder; #[clap(verbatim_doc_comment)] pub struct BinPaths {} -impl Command for BinPaths { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl BinPaths { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() .build(&mut config)?; diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index b9e454966..a7f623bb9 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::env; use crate::file::remove_all; @@ -11,8 +10,8 @@ use crate::output::Output; #[clap(verbatim_doc_comment, visible_alias = "c", alias = "clean")] pub struct CacheClear {} -impl Command for CacheClear { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { +impl CacheClear { + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { let cache_dir = env::RTX_CACHE_DIR.to_path_buf(); if cache_dir.exists() { debug!("clearing cache from {}", cache_dir.display()); diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index c10512e82..06bffdea7 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::env; use crate::output::Output; @@ -31,8 +30,8 @@ impl Commands { } } -impl Command for Cache { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Cache { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { match self.command { Some(cmd) => cmd.run(config, out), None => { diff --git a/src/cli/command.rs b/src/cli/command.rs deleted file mode 100644 index b4e7741dc..000000000 --- a/src/cli/command.rs +++ /dev/null @@ -1,12 +0,0 @@ -use color_eyre::eyre::Result; - -use crate::config::Config; -use crate::output::Output; - -/// Describes a CLI command -/// -/// e.g.: `rtx plugins ls` -pub trait Command: Sized { - /// CLI command entry point - fn run(self, config: Config, output: &mut Output) -> Result<()>; -} diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 36b5afb95..aa6e9bc64 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -3,7 +3,6 @@ use std::io::Cursor; use clap_complete::generate; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::cli::Cli; use crate::config::Config; use crate::output::Output; @@ -21,8 +20,8 @@ pub struct Completion { shell_type: Option, } -impl Command for Completion { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { +impl Completion { + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { let shell = match self.shell.or(self.shell_type) { Some(shell) => shell, None => panic!("no shell provided"), diff --git a/src/cli/current.rs b/src/cli/current.rs index d759fc91f..475936c95 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::unalias_plugin; @@ -20,8 +19,8 @@ pub struct Current { plugin: Option, } -impl Command for Current { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl Current { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; match &self.plugin { Some(plugin_name) => { @@ -37,9 +36,7 @@ impl Command for Current { None => self.all(&config, ts, out), } } -} -impl Current { fn one(&self, config: &Config, ts: Toolset, out: &mut Output, tool: &Tool) -> Result<()> { if !tool.is_installed() { warn!("Plugin {} is not installed", tool.name); diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index bc04504f4..a138991ad 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -2,7 +2,6 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use indoc::formatdoc; -use crate::cli::command::Command; use crate::config::Config; use crate::hook_env; use crate::output::Output; @@ -15,8 +14,8 @@ use crate::shell::get_shell; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Deactivate {} -impl Command for Deactivate { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Deactivate { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { if !config.is_activated() { err_inactive()?; } diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index c778851be..c33d8f613 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use indoc::indoc; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -16,8 +15,8 @@ use crate::output::Output; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct DirenvActivate {} -impl Command for DirenvActivate { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { +impl DirenvActivate { + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { rtxprintln!( out, // source_env "$(rtx direnv envrc "$@")" diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 8f7e958bf..3a87c5239 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -4,7 +4,6 @@ use std::ops::Deref; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::hash::hash_to_str; @@ -18,8 +17,8 @@ use crate::{dirs, env}; #[clap(verbatim_doc_comment, hide = true)] pub struct Envrc {} -impl Command for Envrc { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl Envrc { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 67d6f3fa4..62e5384af 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -3,7 +3,6 @@ use eyre::Result; use eyre::WrapErr; use serde_derive::Deserialize; -use crate::cli::command::Command; use crate::cmd; use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; @@ -22,8 +21,8 @@ struct DirenvWatches { watches: String, } -impl Command for DirenvExec { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl DirenvExec { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index cf2215902..3911f85ab 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -40,8 +39,8 @@ impl Commands { } } -impl Command for Direnv { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Direnv { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let cmd = self .command .unwrap_or(Commands::Activate(activate::DirenvActivate {})); diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index f5fda8a72..ba34a314f 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -7,7 +7,6 @@ use indenter::indented; use indoc::formatdoc; use crate::build_time::built_info; -use crate::cli::command::Command; use crate::cli::version::VERSION; use crate::config::Config; use crate::git::Git; @@ -23,8 +22,8 @@ use crate::{duration, env}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Doctor {} -impl Command for Doctor { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl Doctor { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; rtxprintln!(out, "{}", rtx_version()); rtxprintln!(out, "{}", build_info()); diff --git a/src/cli/env.rs b/src/cli/env.rs index d28bb041f..1e9edcfcd 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shell::{get_shell, ShellType}; @@ -27,8 +26,8 @@ pub struct Env { json: bool, } -impl Command for Env { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl Env { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.tool) @@ -39,9 +38,7 @@ impl Command for Env { self.output_shell(config, out, ts) } } -} -impl Env { fn output_json(&self, config: Config, out: &mut Output, ts: Toolset) -> Result<()> { let env = ts.env_with_path(&config); rtxprintln!(out, "{}", serde_json::to_string_pretty(&env)?); diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index e27a22fba..faf36f052 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -1,6 +1,5 @@ use color_eyre::Result; -use crate::cli::command::Command; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{self, ConfigFile}; use crate::config::Config; @@ -36,8 +35,8 @@ pub struct EnvVars { env_vars: Option>, } -impl Command for EnvVars { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl EnvVars { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { if self.remove.is_none() && self.env_vars.is_none() { for (key, value) in &config.env { let source = config.env_sources.get(key).unwrap(); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 5826535fd..d8b9aaf0f 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -7,7 +7,6 @@ use color_eyre::eyre::{eyre, Result}; use duct::IntoExecutablePath; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; #[cfg(test)] use crate::cmd; use crate::config::Config; @@ -46,8 +45,8 @@ pub struct Exec { pub cd: Option, } -impl Command for Exec { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl Exec { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_args(&self.tool) .with_install_missing() @@ -61,9 +60,7 @@ impl Command for Exec { self.exec(program, args, env) } -} -impl Exec { #[cfg(not(test))] fn exec(&self, program: T, args: U, env: BTreeMap) -> Result<()> where diff --git a/src/cli/global.rs b/src/cli/global.rs index d19ba6d88..60decf3ec 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::cli::local::local; use crate::config::Config; use crate::output::Output; @@ -49,8 +48,8 @@ pub struct Global { path: bool, } -impl Command for Global { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Global { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { local( config, out, diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index dcc55dc4e..816069d70 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -8,7 +8,6 @@ use console::truncate_str; use itertools::Itertools; use terminal_size::{terminal_size, Width}; -use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::direnv::DirenvDiff; @@ -32,8 +31,8 @@ pub struct HookEnv { status: bool, } -impl Command for HookEnv { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl HookEnv { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { if config.settings.missing_runtime_behavior == Prompt { config.settings.missing_runtime_behavior = Warn; } @@ -62,9 +61,7 @@ impl Command for HookEnv { Ok(()) } -} -impl HookEnv { fn display_status(&self, config: &Config, ts: &Toolset, out: &mut Output) { let installed_versions = ts .list_current_installed_versions(config) diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 0fc0da774..aecf04a49 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -2,7 +2,6 @@ use std::path::Path; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::file::remove_all; use crate::output::Output; @@ -24,8 +23,8 @@ pub struct Implode { dry_run: bool, } -impl Command for Implode { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Implode { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let mut files = vec![&*dirs::ROOT, &*dirs::CACHE, &*env::RTX_EXE]; if self.config { files.push(&*dirs::CONFIG); @@ -46,9 +45,7 @@ impl Command for Implode { Ok(()) } -} -impl Implode { fn confirm_remove(&self, config: &Config, f: &Path) -> Result { if self.dry_run { Ok(false) diff --git a/src/cli/install.rs b/src/cli/install.rs index f1ce2a37d..490266a54 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::toolset::{ @@ -34,8 +33,8 @@ pub struct Install { verbose: u8, } -impl Command for Install { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { +impl Install { + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { match &self.tool { Some(runtime) => self.install_runtimes(config, runtime)?, None => self.install_missing_runtimes(config)?, @@ -43,9 +42,6 @@ impl Command for Install { Ok(()) } -} - -impl Install { fn install_runtimes(&self, mut config: Config, runtimes: &[ToolArg]) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); let mut ts = ToolsetBuilder::new() diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 95b47f7f4..0445cc978 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -2,7 +2,6 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::toolset::ToolVersionRequest; @@ -26,8 +25,8 @@ pub struct Latest { installed: bool, } -impl Command for Latest { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Latest { + 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), diff --git a/src/cli/link.rs b/src/cli/link.rs index 3c454725d..6e5d9e64b 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -6,7 +6,6 @@ use console::style; use path_absolutize::Absolutize; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::file::{make_symlink, remove_all}; use crate::output::Output; @@ -33,8 +32,8 @@ pub struct Link { force: bool, } -impl Command for Link { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl Link { + pub fn run(self, mut 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 9f09c30b0..5f44038e5 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -5,7 +5,6 @@ use console::style; use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; @@ -56,8 +55,8 @@ pub struct Local { path: bool, } -impl Command for Local { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Local { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let path = if self.parent { get_parent_path()? } else { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 6b5a2a958..b2ff1f373 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -11,7 +11,6 @@ use itertools::Itertools; use serde_derive::Serialize; use versions::Versioning; -use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; @@ -60,8 +59,8 @@ pub struct Ls { prefix: Option, } -impl Command for Ls { - fn run(mut self, mut config: Config, out: &mut Output) -> Result<()> { +impl Ls { + pub fn run(mut self, mut config: Config, out: &mut Output) -> Result<()> { self.plugin = self .plugin .clone() @@ -95,23 +94,7 @@ impl Command for Ls { self.display_user(&config, runtimes, out) } } -} - -type JSONOutput = IndexMap>; - -#[derive(Serialize)] -struct JSONToolVersion { - version: String, - #[serde(skip_serializing_if = "Option::is_none")] - requested_version: Option, - install_path: PathBuf, - #[serde(skip_serializing_if = "Option::is_none")] - source: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - symlinked_to: Option, -} -impl Ls { fn verify_plugin(&self, config: &Config) -> Result<()> { match &self.plugin { Some(plugin_name) => { @@ -269,6 +252,20 @@ impl Ls { } } +type JSONOutput = IndexMap>; + +#[derive(Serialize)] +struct JSONToolVersion { + version: String, + #[serde(skip_serializing_if = "Option::is_none")] + requested_version: Option, + install_path: PathBuf, + #[serde(skip_serializing_if = "Option::is_none")] + source: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + symlinked_to: Option, +} + type RuntimeRow = (Arc, ToolVersion, Option); impl From for JSONToolVersion { diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 5f8fd9125..7a05c8a86 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -4,7 +4,6 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::ToolArg; use crate::cli::args::tool::ToolArgParser; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::tool::Tool; @@ -27,8 +26,8 @@ pub struct LsRemote { prefix: Option, } -impl Command for LsRemote { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl LsRemote { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let plugin = self.get_plugin(&mut config)?; let prefix = match &self.plugin.tvr { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index aef62f9a5..6acfd17c9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -3,7 +3,6 @@ use color_eyre::Result; use indoc::indoc; use log::LevelFilter; -use crate::cli::command::Command; use crate::config::Config; use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::output::Output; @@ -14,7 +13,6 @@ pub mod args; mod asdf; mod bin_paths; mod cache; -pub mod command; mod completion; mod current; mod deactivate; diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index dba7a352c..b6bdf4779 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -5,7 +5,6 @@ use color_eyre::eyre::Result; use console::{pad_str, style, Alignment}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::tool::Tool; @@ -22,8 +21,8 @@ pub struct Outdated { pub tool: Vec, } -impl Command for Outdated { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +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)?; @@ -43,11 +42,7 @@ impl Command for Outdated { Ok(()) } -} - -type OutputVec = Vec<(Arc, ToolVersion, String)>; -impl Outdated { fn display(&self, outdated: OutputVec, out: &mut Output) { // TODO: make a generic table printer in src/ui/table let plugins = outdated @@ -117,6 +112,8 @@ impl Outdated { } } +type OutputVec = Vec<(Arc, ToolVersion, String)>; + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx outdated diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 61560dcb7..81016244f 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::{eyre, Result}; use url::Url; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin, PluginName}; @@ -47,8 +46,8 @@ pub struct PluginsInstall { rest: Vec, } -impl Command for PluginsInstall { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl PluginsInstall { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); if self.all { return self.install_all_missing_plugins(config, mpr); @@ -67,9 +66,7 @@ impl Command for PluginsInstall { Ok(()) } -} -impl PluginsInstall { fn install_all_missing_plugins( &self, mut config: Config, diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index caebbc059..5cc4ea571 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -5,7 +5,6 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use path_absolutize::Absolutize; -use crate::cli::command::Command; use crate::config::Config; use crate::file::{make_symlink, remove_all}; use crate::output::Output; @@ -33,8 +32,8 @@ pub struct PluginsLink { force: bool, } -impl Command for PluginsLink { - fn run(self, _config: Config, _out: &mut Output) -> Result<()> { +impl PluginsLink { + pub fn run(self, _config: Config, _out: &mut Output) -> Result<()> { let (name, path) = match self.path { Some(path) => (self.name, path), None => { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 9f0c8f975..836e74f1e 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::{ExternalPlugin, PluginType}; @@ -36,8 +35,8 @@ pub struct PluginsLs { pub refs: bool, } -impl Command for PluginsLs { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl PluginsLs { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let mut tools = config.tools.values().cloned().collect::>(); if self.all { diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index f3662e883..46ed1364e 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -4,7 +4,6 @@ use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; use itertools::Itertools; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -23,8 +22,8 @@ pub struct PluginsLsRemote { pub only_names: bool, } -impl Command for PluginsLsRemote { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl PluginsLsRemote { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let installed_plugins = config .tools .values() diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index cccb1d373..2ca6ec611 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -65,8 +64,8 @@ impl Commands { } } -impl Command for Plugins { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Plugins { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::PluginsLs { all: self.all, core: self.core, diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 96e01e2f8..c5740fb9a 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use console::style; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::unalias_plugin; @@ -20,8 +19,8 @@ pub struct PluginsUninstall { pub purge: bool, } -impl Command for PluginsUninstall { - fn run(self, config: Config, _out: &mut Output) -> Result<()> { +impl PluginsUninstall { + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); for plugin_name in &self.plugin { @@ -30,9 +29,7 @@ impl Command for PluginsUninstall { } Ok(()) } -} -impl PluginsUninstall { fn uninstall_one( &self, config: &Config, diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 07281e1cd..862f18c12 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::plugins::{unalias_plugin, PluginName}; @@ -21,8 +20,8 @@ pub struct Update { all: bool, } -impl Command for Update { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Update { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let plugins: Vec<_> = match self.plugin { Some(plugins) => plugins .into_iter() diff --git a/src/cli/prune.rs b/src/cli/prune.rs index c5b23be0a..84704d61c 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -4,7 +4,6 @@ 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; use crate::plugins::PluginName; @@ -31,8 +30,8 @@ pub struct Prune { pub dry_run: bool, } -impl Command for Prune { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl Prune { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; let mut to_delete = ts .list_installed_versions(&config)? @@ -54,9 +53,7 @@ impl Command for Prune { self.delete(&config, to_delete.into_values().collect()) } -} -impl Prune { fn delete(&self, config: &Config, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); for (p, tv) in to_delete { diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index ca08e90d8..9876366a9 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -3,7 +3,6 @@ use color_eyre::eyre::Result; use console::strip_ansi_codes; use indoc::formatdoc; -use crate::cli::command::Command; use crate::cli::Cli; use crate::config::Config; use crate::file; @@ -14,8 +13,8 @@ use crate::output::Output; #[clap(hide = true)] pub struct RenderHelp {} -impl Command for RenderHelp { - fn run(self, _config: Config, _out: &mut Output) -> Result<()> { +impl RenderHelp { + pub fn run(self, _config: Config, _out: &mut Output) -> Result<()> { let readme = file::read_to_string("README.md")?; let mut current_readme = readme.split(""); diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 8bdc664e6..00dba45ed 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -4,7 +4,6 @@ use std::path::{Path, PathBuf}; use eyre::Result; -use crate::cli::command::Command; use crate::cli::{version, Cli}; use crate::config::Config; use crate::output::Output; @@ -14,8 +13,8 @@ use crate::output::Output; #[clap(hide = true)] pub struct RenderMangen {} -impl Command for RenderMangen { - fn run(self, _config: Config, _out: &mut Output) -> Result<()> { +impl RenderMangen { + pub fn run(self, _config: Config, _out: &mut Output) -> Result<()> { let cli = Cli::command() .version(&*version::RAW_VERSION) .disable_colored_help(true); diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 13e14632d..efadbf474 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shims; @@ -30,8 +29,8 @@ pub struct Reshim { pub version: Option, } -impl Command for Reshim { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl Reshim { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; shims::reshim(&config, &ts) diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 347c45f70..19cb0235f 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -4,7 +4,6 @@ use self_update::backends::github::{ReleaseList, Update}; use self_update::update::Release; use self_update::{cargo_crate_version, Status}; -use crate::cli::command::Command; use crate::cli::version::{ARCH, OS}; use crate::config::Config; use crate::env; @@ -19,8 +18,8 @@ use crate::output::Output; #[clap(verbatim_doc_comment)] pub struct SelfUpdate {} -impl Command for SelfUpdate { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl SelfUpdate { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let latest = &self.fetch_releases()?[0].version; let status = self.do_update(&config, latest)?; @@ -33,9 +32,7 @@ impl Command for SelfUpdate { Ok(()) } -} -impl SelfUpdate { fn fetch_releases(&self) -> Result> { let mut releases = ReleaseList::configure(); if let Some(token) = &*env::GITHUB_API_TOKEN { diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 285780e65..da0a9097a 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::{eyre, Result}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -17,8 +16,8 @@ pub struct SettingsGet { pub key: String, } -impl Command for SettingsGet { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl SettingsGet { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { match config.settings.to_index_map().get(&self.key) { Some(value) => Ok(rtxprintln!(out, "{}", value)), None => Err(eyre!("Unknown setting: {}", self.key)), diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 3a47c1948..195200f06 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -14,8 +13,8 @@ use crate::output::Output; #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsLs {} -impl Command for SettingsLs { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl SettingsLs { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { for (key, value) in config.settings.to_index_map() { rtxprintln!(out, "{} = {}", key, value); } diff --git a/src/cli/settings/mod.rs b/src/cli/settings/mod.rs index 2b440dc7b..a7509c221 100644 --- a/src/cli/settings/mod.rs +++ b/src/cli/settings/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -36,8 +35,8 @@ impl Commands { } } -impl Command for Settings { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Settings { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::SettingsLs {})); cmd.run(config, out) diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index a8fdeebb4..311acfa8c 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::{eyre, Result}; -use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; @@ -17,8 +16,8 @@ pub struct SettingsSet { pub value: String, } -impl Command for SettingsSet { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl SettingsSet { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let value: toml_edit::Value = match self.key.as_str() { "experimental" => parse_bool(&self.value)?, "missing_runtime_behavior" => self.value.into(), diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 944f52575..f82b46108 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::output::Output; @@ -15,8 +14,8 @@ pub struct SettingsUnset { pub key: String, } -impl Command for SettingsUnset { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl SettingsUnset { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { config.global_config.remove_setting(&self.key); config.global_config.save() } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 0f23cb8f3..53a5b5817 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -3,7 +3,6 @@ use console::style; use indoc::formatdoc; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::shell::get_shell; @@ -24,8 +23,8 @@ pub struct Shell { unset: bool, } -impl Command for Shell { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl Shell { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new() .with_install_missing() .with_args(&self.tool) diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs index 1c1de0dd2..4fa53055f 100644 --- a/src/cli/sync/mod.rs +++ b/src/cli/sync/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; @@ -30,8 +29,8 @@ impl Commands { } } -impl Command for Sync { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Sync { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { self.command.run(config, out) } } diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 483e416dc..38a2e5f01 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use itertools::sorted; -use crate::cli::command::Command; use crate::config::Config; use crate::env::{NODENV_ROOT, NVM_DIR}; use crate::file; @@ -37,8 +36,8 @@ pub struct SyncNodeType { nodenv: bool, } -impl Command for SyncNode { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl SyncNode { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { if self._type.brew { self.run_brew(config, out)?; } else if self._type.nvm { @@ -48,9 +47,7 @@ impl Command for SyncNode { } Ok(()) } -} -impl SyncNode { fn run_brew(self, mut config: Config, out: &mut Output) -> Result<()> { let tool = config.get_or_create_tool(&PluginName::from("node")); diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 2f737bf0c..234609854 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use itertools::sorted; -use crate::cli::command::Command; use crate::config::Config; use crate::dirs; use crate::env::PYENV_ROOT; @@ -20,8 +19,8 @@ pub struct SyncPython { pyenv: bool, } -impl Command for SyncPython { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl SyncPython { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let python = config.get_or_create_tool(&PluginName::from("python")); let pyenv_versions_path = PYENV_ROOT.join("versions"); diff --git a/src/cli/trust.rs b/src/cli/trust.rs index 23be33289..e412ac33c 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use clap::ValueHint; use color_eyre::eyre::Result; -use crate::cli::command::Command; use crate::cli::local; use crate::config::{config_file, Config}; use crate::output::Output; @@ -29,8 +28,8 @@ pub struct Trust { pub untrust: bool, } -impl Command for Trust { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { +impl Trust { + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { let path = match &self.config_file { Some(filename) => PathBuf::from(filename), None => local::get_parent_path()?, diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index dd4e63243..a33b8714c 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -2,7 +2,6 @@ use console::style; use eyre::{Result, WrapErr}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; @@ -26,8 +25,8 @@ pub struct Uninstall { dry_run: bool, } -impl Command for Uninstall { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +impl Uninstall { + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let runtimes = ToolArg::double_tool_condition(&self.tool); let mut tool_versions = vec![]; diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index c6549183f..ae1657549 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -8,7 +8,6 @@ use rayon::prelude::*; use rayon::ThreadPoolBuilder; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::runtime_symlinks; @@ -29,8 +28,8 @@ pub struct Upgrade { pub tool: Vec, } -impl Command for Upgrade { - fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { +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)?; @@ -50,12 +49,7 @@ impl Command for Upgrade { Ok(()) } -} - -type OutputVec = Vec<(Arc, ToolVersion, String)>; -type GroupedToolVersions = Vec<(Arc, Vec<(ToolVersion, String)>)>; -impl Upgrade { fn upgrade(&self, config: &mut Config, outdated: OutputVec) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); ThreadPoolBuilder::new() @@ -138,3 +132,6 @@ impl Upgrade { } } } + +type OutputVec = Vec<(Arc, ToolVersion, String)>; +type GroupedToolVersions = Vec<(Arc, Vec<(ToolVersion, String)>)>; diff --git a/src/cli/use.rs b/src/cli/use.rs index 525f67d58..3eb01efc9 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -3,7 +3,6 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::cli::local::local; use crate::config::Config; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; @@ -50,8 +49,8 @@ pub struct Use { path: Option, } -impl Command for Use { - fn run(self, config: Config, out: &mut Output) -> Result<()> { +impl Use { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let runtimes = self .tool .into_iter() diff --git a/src/cli/version.rs b/src/cli/version.rs index 72e65842d..dc89d430e 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -7,7 +7,6 @@ use once_cell::sync::Lazy; use versions::Versioning; use crate::build_time::{built_info, BUILD_TIME}; -use crate::cli::command::Command; use crate::config::Config; use crate::env::CI; use crate::file::modified_duration; @@ -43,8 +42,8 @@ pub static VERSION: Lazy = Lazy::new(|| { pub static RAW_VERSION: Lazy = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string()); -impl Command for Version { - fn run(self, _config: Config, out: &mut Output) -> Result<()> { +impl Version { + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { show_version(out); Ok(()) } diff --git a/src/cli/where.rs b/src/cli/where.rs index dfb6f8edd..0cce6c4cc 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; use crate::output::Output; @@ -28,8 +27,8 @@ pub struct Where { asdf_version: Option, } -impl Command for Where { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl Where { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let runtime = match self.tool.tvr { None => match self.asdf_version { Some(version) => self.tool.with_version(&version), diff --git a/src/cli/which.rs b/src/cli/which.rs index f39d9d9a4..88a3b2391 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::{eyre, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -28,8 +27,8 @@ pub struct Which { pub tool: Option, } -impl Command for Which { - fn run(self, mut config: Config, out: &mut Output) -> Result<()> { +impl Which { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = self.get_toolset(&mut config)?; match ts.which(&config, &self.bin_name) { @@ -47,9 +46,6 @@ impl Command for Which { None => Err(eyre!("{} not found", self.bin_name)), } } -} - -impl Which { fn get_toolset(&self, config: &mut Config) -> Result { let mut tsb = ToolsetBuilder::new(); if let Some(tool) = &self.tool { diff --git a/src/shims.rs b/src/shims.rs index e27352c3a..fdeed58ee 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -10,7 +10,6 @@ use indoc::formatdoc; use itertools::Itertools; use rayon::prelude::*; -use crate::cli::command::Command; use crate::cli::exec::Exec; use crate::config::Config; use crate::env; From 983bfe0a17395e8d8df5c656888a30e64de81f6c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:30:47 -0600 Subject: [PATCH 1140/1891] test: move e2e directory to home directory (#1042) avoids a warning from cargo about circular symlinks --- e2e/cd/test_bash | 11 ++++++----- e2e/run_test | 6 +++--- e2e/test_link | 1 + e2e/test_tiny | 6 +++--- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 06f137762..9b085b63f 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -22,10 +22,11 @@ assert() { } assert_path() { - local expected="${1//$ROOT/\$ROOT}" + local expected="$1" local actual="${PATH/%$orig_path/}" actual="${actual/%:/}" - actual="${actual//$ROOT/\$ROOT}" + actual="${actual//$ROOT/ROOT}" + actual="${actual//$RTX_DATA_DIR\/installs/INSTALLS}" if [[ "$actual" != "$expected" ]]; then echo "Invalid PATH: $actual" echo "Expected PATH: $expected" @@ -34,17 +35,17 @@ assert_path() { } test "$(node -v)" = "v20.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/node/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "cd" cd 18 && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/node/18.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/18.0.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "18" cd .. && _rtx_hook test "$(node -v)" = "v20.0.0" -assert_path "/root:\$ROOT/e2e/cwd:\$ROOT/e2e/.rtx/installs/node/20.0.0/bin:\$ROOT/e2e/.rtx/installs/tiny/3.1.0/bin:\$ROOT/e2e/.rtx/installs/shellcheck/0.9.0/bin:\$ROOT/e2e/.rtx/installs/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" rtx shell node@18.0.0 && _rtx_hook test "$(node -v)" = "v18.0.0" diff --git a/e2e/run_test b/e2e/run_test index e32cba8d2..6a51fd0a4 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -10,9 +10,9 @@ setup_env() { export PATH="$ROOT/target/debug:$PATH" export RTX_USE_TOML="0" export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" - export RTX_DATA_DIR="$ROOT/e2e/.rtx" - export RTX_CACHE_DIR="$ROOT/e2e/.rtx/cache" - export RTX_CONFIG_DIR="$ROOT/e2e/.rtx/config" + export RTX_DATA_DIR="$HOME/.rtx/e2e" + export RTX_CACHE_DIR="$HOME/.rtx/e2e/cache" + export RTX_CONFIG_DIR="$HOME/.rtx/e2e/config" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" diff --git a/e2e/test_link b/e2e/test_link index 94f8abb79..c99f9c15c 100755 --- a/e2e/test_link +++ b/e2e/test_link @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx plugins uninstall tiny diff --git a/e2e/test_tiny b/e2e/test_tiny index cbddff57b..63e21d1c3 100755 --- a/e2e/test_tiny +++ b/e2e/test_tiny @@ -3,7 +3,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" rtx cache clean -rm -rf .rtx/installs/tiny +rm -rf "$RTX_DATA_DIR/installs/tiny" RTX_CONFIRM=y rtx ls # auto-trust # this will fail when calling bin/list-all, but it won't stop it from executing @@ -20,9 +20,9 @@ assert "rtx current tiny" "3.1.0" # test outdated/upgrade rtx settings set experimental true -rm -rf .rtx/installs/tiny +rm -rf "$RTX_DATA_DIR/installs/tiny" rtx use tiny@3 -mv .rtx/installs/tiny/{3.1.0,3.0.0} +mv "$RTX_DATA_DIR/installs/tiny/"{3.1.0,3.0.0} assert "rtx current tiny" "3.0.0" assert "rtx outdated tiny" "Tool Requested Current Latest tiny 3 3.0.0 3.1.0" From 64753851da59a0a91db1c256fa989659ba8962be Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 19:13:15 -0600 Subject: [PATCH 1141/1891] test: lint e2e test scripts (#1043) --- .shellcheckrc | 2 ++ e2e/assert.sh | 34 +++++++++++++++-------------- e2e/ruby/test_ruby | 1 + e2e/ruby/test_ruby_install | 1 + e2e/run_all_tests | 20 ++++++++--------- e2e/run_test | 44 +++++++++++++++++++------------------- e2e/test_bun | 1 + e2e/test_deno | 1 + e2e/test_doctor | 13 +++++------ e2e/test_env | 1 + e2e/test_exec | 12 +++++------ e2e/test_go | 1 + e2e/test_install | 1 + e2e/test_java | 1 + e2e/test_link | 1 + e2e/test_local | 31 +++++++++++++-------------- e2e/test_ls_remote | 1 + e2e/test_lua | 22 ------------------- e2e/test_neovim | 1 + e2e/test_nodejs | 1 + e2e/test_plugins_install | 28 ++++++++++++------------ e2e/test_purge | 1 + e2e/test_python | 1 + e2e/test_raw | 12 +++++------ e2e/test_shell | 1 + e2e/test_shims | 1 + e2e/test_system | 1 + e2e/test_tiny | 3 ++- e2e/test_tool_versions_alt | 18 ++++++++-------- e2e/test_top_runtimes | 3 ++- e2e/test_uninstall | 1 + e2e/test_zigmod | 1 + justfile | 10 +++++---- 33 files changed, 138 insertions(+), 133 deletions(-) create mode 100644 .shellcheckrc delete mode 100755 e2e/test_lua diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 000000000..cacba8e25 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,2 @@ +disable=SC2317 +disable=SC1008 diff --git a/e2e/assert.sh b/e2e/assert.sh index 729d7d5e6..246fb2571 100644 --- a/e2e/assert.sh +++ b/e2e/assert.sh @@ -1,19 +1,21 @@ +#!/usr/bin/env bash + assert() { - local actual - actual="$(bash -c "$1")" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi + local actual + actual="$(bash -c "$1")" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi } assert_contains() { - local actual - actual="$(bash -c "$1")" - if [[ "$actual" != *"$2"* ]]; then - echo "Expected '$2' to be in '$actual'" - exit 1 - fi + local actual + actual="$(bash -c "$1")" + if [[ "$actual" != *"$2"* ]]; then + echo "Expected '$2' to be in '$actual'" + exit 1 + fi } assert_not_contains() { @@ -26,8 +28,8 @@ assert_not_contains() { } assert_fail() { - if bash -c "$1" 2>&1; then - echo "Expected failure but succeeded" - exit 1 - fi + if bash -c "$1" 2>&1; then + echo "Expected failure but succeeded" + exit 1 + fi } diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby index 7408fbcc8..29ddd6eff 100755 --- a/e2e/ruby/test_ruby +++ b/e2e/ruby/test_ruby @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -e +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/../assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/ruby/test_ruby_install b/e2e/ruby/test_ruby_install index 4654e7eb5..53715cfac 100755 --- a/e2e/ruby/test_ruby_install +++ b/e2e/ruby/test_ruby_install @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -e +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/../assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/run_all_tests b/e2e/run_all_tests index f38b9ca79..f4f967168 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -6,16 +6,16 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" FILES=$(find e2e -name 'test_*' -type f -not -path "*/.rtx/*" | sort) test_count=0 for f in $FILES; do - # split tests into two tranches to reduce test time - if [ -n "${TEST_TRANCHE_COUNT:-}" ]; then - char_count=${#f} - if [[ $((char_count % "$TEST_TRANCHE_COUNT")) -ne "$TEST_TRANCHE" ]]; then - continue - fi - fi - "$ROOT/e2e/run_test" "$f" - echo - test_count=$((test_count + 1)) + # split tests into two tranches to reduce test time + if [ -n "${TEST_TRANCHE_COUNT:-}" ]; then + char_count=${#f} + if [[ $((char_count % "$TEST_TRANCHE_COUNT")) -ne "$TEST_TRANCHE" ]]; then + continue + fi + fi + "$ROOT/e2e/run_test" "$f" + echo + test_count=$((test_count + 1)) done echo "e2e: $test_count tests passed" diff --git a/e2e/run_test b/e2e/run_test index 6a51fd0a4..06d3810ea 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -6,35 +6,35 @@ ROOT="$(cd "$SCRIPT_DIR"/.. && pwd)" TEST="$1" setup_env() { - export ROOT - export PATH="$ROOT/target/debug:$PATH" - export RTX_USE_TOML="0" - export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" - export RTX_DATA_DIR="$HOME/.rtx/e2e" - export RTX_CACHE_DIR="$HOME/.rtx/e2e/cache" - export RTX_CONFIG_DIR="$HOME/.rtx/e2e/config" - export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions - export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml - export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" - export RTX_YES="yes" - unset GOPATH + export ROOT + export PATH="$ROOT/target/debug:$PATH" + export RTX_USE_TOML="0" + export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" + export RTX_DATA_DIR="$HOME/.rtx/e2e" + export RTX_CACHE_DIR="$HOME/.rtx/e2e/cache" + export RTX_CONFIG_DIR="$HOME/.rtx/e2e/config" + export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions + export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml + export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" + export RTX_YES="yes" + unset GOPATH } setup_config_files() { - mkdir -p "$ROOT/e2e/cd/18" - cp "$ROOT/e2e/config/".e2e.* "$ROOT/e2e/" - cp "$ROOT/e2e/config/"{.node-version,.alternate-tool-versions,.test-env} "$ROOT/e2e/" - cp "$ROOT/e2e/config/cd/".e2e.* "$ROOT/e2e/cd/" - cp "$ROOT/e2e/config/cd/18/".e2e.* "$ROOT/e2e/cd/18" + mkdir -p "$ROOT/e2e/cd/18" + cp "$ROOT/e2e/config/".e2e.* "$ROOT/e2e/" + cp "$ROOT/e2e/config/"{.node-version,.alternate-tool-versions,.test-env} "$ROOT/e2e/" + cp "$ROOT/e2e/config/cd/".e2e.* "$ROOT/e2e/cd/" + cp "$ROOT/e2e/config/cd/18/".e2e.* "$ROOT/e2e/cd/18" } run_test() { - echo "Running $TEST" - rm -f "$RTX_CONFIG_FILE" - rtx trust "$ROOT/e2e/.e2e.rtx.toml" >/dev/null - cd "$(dirname "$TEST")" + echo "Running $TEST" + rm -f "$RTX_CONFIG_FILE" + rtx trust "$ROOT/e2e/.e2e.rtx.toml" >/dev/null + cd "$(dirname "$TEST")" - "./$(basename "$TEST")" + "./$(basename "$TEST")" } setup_env diff --git a/e2e/test_bun b/e2e/test_bun index fbf28d3ac..383c3501e 100755 --- a/e2e/test_bun +++ b/e2e/test_bun @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_deno b/e2e/test_deno index 7ac1c0f26..653c9bd88 100755 --- a/e2e/test_deno +++ b/e2e/test_deno @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_doctor b/e2e/test_doctor index 4f4b313ab..ee050503c 100755 --- a/e2e/test_doctor +++ b/e2e/test_doctor @@ -2,12 +2,13 @@ set -euo pipefail assert() { - local actual - actual="$($*)" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi + local actual + # shellcheck disable=SC2048 + actual="$($*)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi } eval "$(rtx activate bash)" && _rtx_hook diff --git a/e2e/test_env b/e2e/test_env index 524ad9ee5..77f320441 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx i node diff --git a/e2e/test_exec b/e2e/test_exec index d52be0479..e372fd96c 100755 --- a/e2e/test_exec +++ b/e2e/test_exec @@ -2,12 +2,12 @@ set -euo pipefail assert() { - local actual - actual="$($1)" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi + local actual + actual="$($1)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi } assert "rtx x -C direnv -- pwd" "$(pwd)/direnv" diff --git a/e2e/test_go b/e2e/test_go index d0c2ea755..6a11a1456 100755 --- a/e2e/test_go +++ b/e2e/test_go @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -e +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_install b/e2e/test_install index 0ff52b8a3..9c9167687 100755 --- a/e2e/test_install +++ b/e2e/test_install @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" # installs with repo in .rtx.toml diff --git a/e2e/test_java b/e2e/test_java index d4f7389ba..7518010d9 100755 --- a/e2e/test_java +++ b/e2e/test_java @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_link b/e2e/test_link index c99f9c15c..9130bda33 100755 --- a/e2e/test_link +++ b/e2e/test_link @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -euo pipefail # shellcheck source-path=SCRIPTDIR +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx plugins uninstall tiny diff --git a/e2e/test_local b/e2e/test_local index 5687be159..8e4762be7 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -1,19 +1,19 @@ #!/usr/bin/env bash assert() { - actual="$($1)" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" != "$expected" ]]; then - echo "assertion failed, expected '$expected', got '$actual'" - exit 1 - fi + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi } assert_raises() { - if ! $1; then - echo "assertion failed: $1" - exit 1 - fi + if ! $1; then + echo "assertion failed: $1" + exit 1 + fi } export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall @@ -52,7 +52,7 @@ tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb6627394 rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then - exit 1 + exit 1 fi assert_raises "rtx uninstall shfmt@3.6.0" @@ -76,7 +76,7 @@ tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb6627394 rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then - exit 1 + exit 1 fi rtx local --rm shfmt @@ -94,7 +94,6 @@ tiny = \"latest\" tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" " - export RTX_DEFAULT_CONFIG_FILENAME=.MISSING assert_raises "rtx uninstall shfmt@3.6.0" @@ -115,7 +114,7 @@ shfmt 3.5.0 # test comment rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then - exit 1 + exit 1 fi rtx local shfmt@3.6.0 @@ -127,5 +126,5 @@ shfmt 3.6.0 # test comment rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then - exit 1 + exit 1 fi diff --git a/e2e/test_ls_remote b/e2e/test_ls_remote index 12bee3890..0c87e3037 100755 --- a/e2e/test_ls_remote +++ b/e2e/test_ls_remote @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx p list-remote | grep elixir diff --git a/e2e/test_lua b/e2e/test_lua deleted file mode 100755 index 0255708ca..000000000 --- a/e2e/test_lua +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env fish - -exit 0 # TODO: fix this test, it's flaky - -set -gx RTX_MISSING_RUNTIME_BEHAVIOR autoinstall - -rtx activate --status fish | source -rtx hook-env | source -rtx shell lua@5.4.3 - -rtx hook-env | source -set -l actual (lua -v 2>&1) -set -l expected "Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio" - -if test "$actual" = "$expected" - echo "OK" -else - echo "FAIL" - echo "Expected: $expected" - echo "Actual: $actual" - exit 1 -end diff --git a/e2e/test_neovim b/e2e/test_neovim index 58f8981ab..e7e0d3446 100755 --- a/e2e/test_neovim +++ b/e2e/test_neovim @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" # TODO: fix this in github actions CI diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 21df305b1..7699d87a0 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install index d4535071e..8e112d79f 100755 --- a/e2e/test_plugins_install +++ b/e2e/test_plugins_install @@ -2,22 +2,22 @@ set -euo pipefail assert_not_contains() { - actual="$($1)" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" == *"$expected"* ]]; then - echo "assertion failed, expected not '$expected', got '$actual'" - exit 1 - fi + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" == *"$expected"* ]]; then + echo "assertion failed, expected not '$expected', got '$actual'" + exit 1 + fi } assert_contains() { - actual="$($1)" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" != *"$expected"* ]]; then - echo "assertion failed, expected '$expected', got '$actual'" - exit 1 - fi + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != *"$expected"* ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi } # install/uninstall multiple diff --git a/e2e/test_purge b/e2e/test_purge index 6d8ff14de..562af6c1d 100755 --- a/e2e/test_purge +++ b/e2e/test_purge @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx install tiny diff --git a/e2e/test_python b/e2e/test_python index cbd07fc19..2bebaa770 100755 --- a/e2e/test_python +++ b/e2e/test_python @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_raw b/e2e/test_raw index 6f5b9d9c5..3fd783162 100755 --- a/e2e/test_raw +++ b/e2e/test_raw @@ -2,12 +2,12 @@ set -euo pipefail assert() { - local actual - actual="$($1)" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi + local actual + actual="$($1)" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi } rtx i --raw -f tiny@1 tiny@2 tiny@3 diff --git a/e2e/test_shell b/e2e/test_shell index 2fcdada94..6c732fce2 100755 --- a/e2e/test_shell +++ b/e2e/test_shell @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_shims b/e2e/test_shims index b80447b5d..56a74b0ac 100755 --- a/e2e/test_shims +++ b/e2e/test_shims @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx i node diff --git a/e2e/test_system b/e2e/test_system index 68bc81bce..be1d66b4e 100755 --- a/e2e/test_system +++ b/e2e/test_system @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 diff --git a/e2e/test_tiny b/e2e/test_tiny index 63e21d1c3..3d6b17711 100755 --- a/e2e/test_tiny +++ b/e2e/test_tiny @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx cache clean @@ -12,7 +13,7 @@ RTX_TINY_LIST_ALL_FAIL=1 RTX_TINY_VERSION=latest rtx env >/dev/null # check bin/list-legacy-files assert "rtx current tiny" "3.1.0" rtx local --remove tiny -echo "2.0" > .tiny-version +echo "2.0" >.tiny-version assert "rtx current tiny" "2.0.1" rm .tiny-version rtx local tiny@latest diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index 52b51533f..01bf7bfa8 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -10,17 +10,17 @@ git checkout .alternate-tool-versions rtx i shfmt rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then - exit 1 + exit 1 fi assert() { - actual="$($1)" - actual="${actual%$'\n'}" - expected="${2%$'\n'}" - if [[ "$actual" != "$expected" ]]; then - echo "assertion failed, expected '$expected', got '$actual'" - exit 1 - fi + actual="$($1)" + actual="${actual%$'\n'}" + expected="${2%$'\n'}" + if [[ "$actual" != "$expected" ]]; then + echo "assertion failed, expected '$expected', got '$actual'" + exit 1 + fi } assert "rtx local" "shfmt 3.5.0" @@ -30,7 +30,7 @@ assert "rtx local -p" "shfmt 3.6.0" rtx exec -- shfmt --version >&2 if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then - exit 1 + exit 1 fi rtx local -p shfmt@3.5.0 diff --git a/e2e/test_top_runtimes b/e2e/test_top_runtimes index eee1757bc..02170a418 100755 --- a/e2e/test_top_runtimes +++ b/e2e/test_top_runtimes @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC2317 set -e @@ -59,7 +60,7 @@ exit 0 # disable for now for faster releases rtx exec node -- node -v rtx exec python -- python -V rtx exec direnv -- direnv --version -rtx exec erlang -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell +rtx exec erlang -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell rtx exec elixir erlang -- elixir --version rtx exec golang -- go version rtx exec java -- java -version diff --git a/e2e/test_uninstall b/e2e/test_uninstall index afd803548..ae42f86d2 100755 --- a/e2e/test_uninstall +++ b/e2e/test_uninstall @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" rtx i diff --git a/e2e/test_zigmod b/e2e/test_zigmod index 037ab9838..a86106671 100755 --- a/e2e/test_zigmod +++ b/e2e/test_zigmod @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail +# shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" eval "$(rtx activate bash)" && eval "$(rtx hook-env)" diff --git a/justfile b/justfile index a279858ad..9ac16e036 100644 --- a/justfile +++ b/justfile @@ -78,20 +78,22 @@ clean: rm -rf *.profraw rm -rf coverage +scripts := "scripts/*.sh e2e/{test_,run_}* e2e/*.sh" + # clippy, cargo fmt --check, and just --fmt lint: cargo clippy -- -Dwarnings cargo fmt --all -- --check - shellcheck scripts/*.sh - shfmt -d scripts/*.sh + shellcheck -x {{ scripts }} + shfmt -d {{ scripts }} just --unstable --fmt --check # runs linters but makes fixes when possible lint-fix: cargo clippy --fix --allow-staged --allow-dirty -- -Dwarnings cargo fmt --all - shellcheck scripts/*.sh - shfmt -w scripts/*.sh + shellcheck -x {{ scripts }} + shfmt -w {{ scripts }} just --unstable --fmt # regenerate README.md From 40561d23363fdb6a1ed73e111be3c9c784f65d84 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 19:25:23 -0600 Subject: [PATCH 1142/1891] shims: fix bug for when rtx path changes (#1041) --- src/shims.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/shims.rs b/src/shims.rs index fdeed58ee..0e80ab603 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -77,7 +77,16 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let rtx_bin = file::which("rtx").unwrap_or(env::RTX_EXE.clone()); create_dir_all(&*dirs::SHIMS)?; - let existing_shims = list_executables_in_dir(&dirs::SHIMS)?; + + let existing_shims = list_executables_in_dir(&dirs::SHIMS)? + .into_par_iter() + .filter(|bin| { + dirs::SHIMS + .join(bin) + .read_link() + .is_ok_and(|p| p == rtx_bin) + }) + .collect::>(); let shims: HashSet = ts .list_installed_versions(config)? From f25a05873fd1fe7e3fbc5a285277aca1f94373a0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 19:50:11 -0600 Subject: [PATCH 1143/1891] node: remove compilation tool opts (#1044) This ended up not being a great idea. It is confusing that it only takes place on _new_ installs --- docs/node.md | 17 +---------------- src/plugins/core/node.rs | 37 +++++++++++-------------------------- 2 files changed, 12 insertions(+), 42 deletions(-) diff --git a/docs/node.md b/docs/node.md index 80174bf4c..9206de13b 100644 --- a/docs/node.md +++ b/docs/node.md @@ -27,7 +27,7 @@ required system dependencies. - `RTX_NODE_BUILD` [bool]: See [Moving away from node-build](#moving-away-from-node-build) below. - `RTX_NODE_BUILD_REPO` [string]: the default is `https://github.com/nodenv/node-build.git` - `RTX_NODE_VERIFY` [bool]: Verify the downloaded assets using GPG. Defaults to `true`. -- `RTX_NODE_NINJA` [bool]: Use ninja instead of make to compile nodel. Defaults to `true` if installed. +- `RTX_NODE_NINJA` [bool]: Use ninja instead of make to compile node. Defaults to `true` if installed. - `RTX_NODE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries. Can also be set across all languages with [`RTX_NODE__COMPILE`](https://github.com/jdx/rtx#rtx_node_compile1) - `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores - `RTX_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` @@ -37,21 +37,6 @@ required system dependencies. - `RTX_NODE_MAKE_OPTS` [string]: Additional `make` options. - `RTX_NODE_MAKE_INSTALL_OPTS` [string]: Additional `make install` options. -## Tool Options - -The following are example options that can be set in `.rtx.toml` files. -Note env vars take precedence over these. - -```toml -[tool.node] -version = "20" -compile = true # do not use pre-compiled binaries -cflags = "-O3 -march=native" # additional CFLAGS options -configure_opts = "--debug" # command line options to pass to ./configure -make_opts = "-j 4" # command line options to pass to make -make_install_opts = "-j 4" # command line options to pass to make install -``` - ## Default node packages rtx-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-npm-packages` file that lists one package per line, for example: diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 9e2972b38..a7c062840 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -128,7 +128,7 @@ impl NodePlugin { .with_pr(pr) .current_dir(&opts.build_dir) .arg("-c"); - if let Some(cflags) = &opts.cflags { + if let Some(cflags) = &*env::RTX_NODE_CFLAGS { cmd = cmd.env("CFLAGS", cflags); } cmd @@ -292,7 +292,7 @@ impl Plugin for NodePlugin { ) -> Result<()> { let opts = BuildOpts::new(tv)?; debug!("node build opts: {:#?}", opts); - if opts.compile { + if *env::RTX_NODE_COMPILE { self.install_compiled(config, pr, &opts)?; } else { self.install_precompiled(config, pr, &opts)?; @@ -308,10 +308,8 @@ impl Plugin for NodePlugin { #[derive(Debug)] struct BuildOpts { version: String, - compile: bool, install_path: PathBuf, build_dir: PathBuf, - cflags: Option, configure_cmd: String, make_cmd: String, make_install_cmd: String, @@ -333,13 +331,9 @@ impl BuildOpts { Ok(Self { version: v.clone(), build_dir: env::RTX_TMP_DIR.join(format!("node-v{v}")), - compile: *env::RTX_NODE_COMPILE || tv.opts.get("compile").is_some_and(|v| v == "true"), - cflags: env::RTX_NODE_CFLAGS - .clone() - .or_else(|| tv.opts.get("cflags").cloned()), - configure_cmd: configure_cmd(tv, &install_path), - make_cmd: make_cmd(tv), - make_install_cmd: make_install_cmd(tv), + configure_cmd: configure_cmd(&install_path), + make_cmd: make_cmd(), + make_install_cmd: make_install_cmd(), source_tarball_path: tv.download_path().join(&source_tarball_name), source_tarball_url: env::RTX_NODE_MIRROR_URL .join(&format!("v{v}/{source_tarball_name}"))?, @@ -353,40 +347,31 @@ impl BuildOpts { } } -fn configure_cmd(tv: &ToolVersion, install_path: &Path) -> String { - let configure_opts = env::RTX_NODE_CONFIGURE_OPTS - .clone() - .or_else(|| tv.opts.get("configure_opts").cloned()); +fn configure_cmd(install_path: &Path) -> String { let mut configure_cmd = format!("./configure --prefix={}", install_path.display()); if *env::RTX_NODE_NINJA { configure_cmd.push_str(" --ninja"); } - if let Some(opts) = configure_opts { + if let Some(opts) = &*env::RTX_NODE_CONFIGURE_OPTS { configure_cmd.push_str(&format!(" {}", opts)); } configure_cmd } -fn make_cmd(tv: &ToolVersion) -> String { +fn make_cmd() -> String { let mut make_cmd = env::RTX_NODE_MAKE.to_string(); if let Some(concurrency) = *env::RTX_NODE_CONCURRENCY { make_cmd.push_str(&format!(" -j{concurrency}")); } - let make_opts = env::RTX_NODE_MAKE_OPTS - .clone() - .or_else(|| tv.opts.get("make_opts").cloned()); - if let Some(opts) = make_opts { + if let Some(opts) = &*env::RTX_NODE_MAKE_OPTS { make_cmd.push_str(&format!(" {opts}")); } make_cmd } -fn make_install_cmd(tv: &ToolVersion) -> String { +fn make_install_cmd() -> String { let mut make_install_cmd = format!("{} install", &*env::RTX_NODE_MAKE); - let make_install_opts = env::RTX_NODE_MAKE_INSTALL_OPTS - .clone() - .or_else(|| tv.opts.get("make_install_opts").cloned()); - if let Some(opts) = make_install_opts { + if let Some(opts) = &*env::RTX_NODE_MAKE_INSTALL_OPTS { make_install_cmd.push_str(&format!(" {opts}")); } make_install_cmd From c67d82eb148ca9a489bb3ca84092855eaa163a99 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 21:11:14 -0600 Subject: [PATCH 1144/1891] upgrade: fix bug with missing versions (#1045) If a version was completely missing it would install, then uninstall it --- src/cli/upgrade.rs | 77 +++++++++++++--------------------------------- 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index ae1657549..0daba806a 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -3,9 +3,6 @@ use std::sync::Arc; use eyre::Result; use eyre::WrapErr; -use itertools::Itertools; -use rayon::prelude::*; -use rayon::ThreadPoolBuilder; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; @@ -52,64 +49,33 @@ impl Upgrade { fn upgrade(&self, config: &mut Config, outdated: OutputVec) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); - ThreadPoolBuilder::new() - .num_threads(config.settings.jobs) - .build()? - .install(|| -> Result<()> { - self.install_new_versions(config, &mpr, outdated)?; + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; - let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; - shims::reshim(config, &ts).wrap_err("failed to reshim")?; - runtime_symlinks::rebuild(config)?; - - Ok(()) + let new_versions = outdated + .iter() + .map(|(_, tv, latest)| { + let mut tv = tv.clone(); + tv.version = latest.clone(); + tv }) - } + .collect(); - fn install_new_versions( - &self, - config: &Config, - mpr: &MultiProgressReport, - outdated: OutputVec, - ) -> Result<()> { - let grouped_tool_versions: GroupedToolVersions = outdated - .into_iter() - .group_by(|(t, _, _)| t.clone()) + let to_remove = outdated .into_iter() - .map(|(t, tvs)| (t, tvs.map(|(_, tv, latest)| (tv, latest)).collect())) - .collect(); - grouped_tool_versions - .into_par_iter() - .map(|(tool, versions)| { - for (tv, latest) in versions { - let mut pr = mpr.add(); - self.install_new_version(config, &tool, &tv, latest, &mut pr)?; - self.uninstall_old_version(config, &tool, &tv, &mut pr)?; - } - Ok(()) - }) - .collect::>>()?; - Ok(()) - } + .filter(|(tool, tv, _)| tool.is_version_installed(tv)) + .map(|(tool, tv, _)| (tool, tv)) + .collect::>(); - fn install_new_version( - &self, - config: &Config, - tool: &Tool, - tv: &ToolVersion, - latest: String, - pr: &mut ProgressReport, - ) -> Result<()> { - let mut tv = tv.clone(); - tv.version = latest; - tool.decorate_progress_bar(pr, Some(&tv)); - match tool.install_version(config, &tv, pr, false) { - Ok(_) => Ok(()), - Err(err) => { - pr.error(err.to_string()); - Err(err.wrap_err(format!("failed to install {tv}"))) - } + ts.install_versions(config, new_versions, &mpr, false)?; + for (tool, tv) in to_remove { + let mut pr = mpr.add(); + self.uninstall_old_version(config, &tool, &tv, &mut pr)?; } + + let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + shims::reshim(config, &ts).wrap_err("failed to reshim")?; + runtime_symlinks::rebuild(config)?; + Ok(()) } fn uninstall_old_version( @@ -134,4 +100,3 @@ impl Upgrade { } type OutputVec = Vec<(Arc, ToolVersion, String)>; -type GroupedToolVersions = Vec<(Arc, Vec<(ToolVersion, String)>)>; From 86f0899c4f00b66e59690dbcdcf3e85745177a07 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 1 Dec 2023 21:48:36 -0600 Subject: [PATCH 1145/1891] test: added upgrade test (#1046) --- e2e/test_upgrade | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 e2e/test_upgrade diff --git a/e2e/test_upgrade b/e2e/test_upgrade new file mode 100755 index 000000000..ba12fe9bf --- /dev/null +++ b/e2e/test_upgrade @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +rtx use tiny@3 +rtx uninstall --all tiny +rtx install tiny +assert_contains "rtx ls --installed tiny" "3.1.0" + +mv "$RTX_DATA_DIR/installs/tiny/"{3.1.0,3.0.0} +assert_contains "rtx ls --installed tiny" "3.0.0" +assert_not_contains "rtx ls --installed tiny" "3.1.0" + +rtx upgrade tiny +assert_contains "rtx ls --installed tiny" "3.1.0" +assert_not_contains "rtx ls --installed tiny" "3.0.0" + +rtx use tiny@latest From 5b8407b446bffc5dacfd0244805e8a6f003c4f4a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 00:56:49 -0600 Subject: [PATCH 1146/1891] load installed/current plugins when installing plugins (#1047) Possibly a cheap workaround for #393. It should make the following possible: rtx install python rtx install poetry # poetry depends on python If you were to just run `rtx install` and try to install python and poetry at the same time it would not work, however. --- e2e/.gitignore | 2 + e2e/cd/test_bash | 6 +- e2e/config/.e2e.rtx.toml | 2 + e2e/config/pyproject.toml | 12 ++++ e2e/run_test | 2 +- e2e/test_doctor | 1 + e2e/test_local | 8 +++ e2e/test_nodejs | 2 +- e2e/test_poetry | 22 +++++++ e2e/test_python | 4 +- src/cli/which.rs | 2 +- src/cmd.rs | 18 ++++++ src/install_context.rs | 11 ++++ src/main.rs | 1 + src/plugins/core/bun.rs | 53 ++++++++--------- src/plugins/core/deno.rs | 35 ++++++----- src/plugins/core/go.rs | 30 ++++++---- src/plugins/core/java.rs | 30 +++++----- src/plugins/core/node.rs | 103 ++++++++++++--------------------- src/plugins/core/node_build.rs | 32 +++++----- src/plugins/core/python.rs | 57 ++++++++++-------- src/plugins/core/ruby.rs | 38 ++++++------ src/plugins/external_plugin.rs | 81 +++++++++++++++++--------- src/plugins/mod.rs | 20 +++++-- src/plugins/script_manager.rs | 8 +++ src/shims.rs | 13 +++-- src/tool.rs | 58 ++++++++++--------- src/toolset/mod.rs | 21 ++++--- 28 files changed, 408 insertions(+), 264 deletions(-) create mode 100644 e2e/config/pyproject.toml create mode 100755 e2e/test_poetry create mode 100644 src/install_context.rs diff --git a/e2e/.gitignore b/e2e/.gitignore index 7425c8c2a..d756e6944 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -8,3 +8,5 @@ ruby/Gemfile ruby/.ruby-version Library +/pyproject.toml +/poetry.lock diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 9b085b63f..cc879bb8a 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -35,17 +35,17 @@ assert_path() { } test "$(node -v)" = "v20.0.0" -assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "cd" cd 18 && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/18.0.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/18.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "18" cd .. && _rtx_hook test "$(node -v)" = "v20.0.0" -assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" rtx shell node@18.0.0 && _rtx_hook test "$(node -v)" = "v18.0.0" diff --git a/e2e/config/.e2e.rtx.toml b/e2e/config/.e2e.rtx.toml index 58a27e4e8..84239c98b 100644 --- a/e2e/config/.e2e.rtx.toml +++ b/e2e/config/.e2e.rtx.toml @@ -5,7 +5,9 @@ env_path = ["/root", "./cwd"] FOO = "bar" [tools] +python = "3.12.0" tiny = "latest" +poetry = {version="1.7.1", pyproject="pyproject.toml"} #golang = {version="1.19.5", foo="bar"} [plugins] diff --git a/e2e/config/pyproject.toml b/e2e/config/pyproject.toml new file mode 100644 index 000000000..58cf8e1bb --- /dev/null +++ b/e2e/config/pyproject.toml @@ -0,0 +1,12 @@ +[tool.poetry] +name = "poetry-test" +version = "0.1.0" +description = "" +authors = ["rtx"] + +[tool.poetry.dependencies] +python = "^3.12" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/e2e/run_test b/e2e/run_test index 06d3810ea..c8c9f8aeb 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -23,7 +23,7 @@ setup_env() { setup_config_files() { mkdir -p "$ROOT/e2e/cd/18" cp "$ROOT/e2e/config/".e2e.* "$ROOT/e2e/" - cp "$ROOT/e2e/config/"{.node-version,.alternate-tool-versions,.test-env} "$ROOT/e2e/" + cp "$ROOT/e2e/config/"{.node-version,.alternate-tool-versions,.test-env,pyproject.toml} "$ROOT/e2e/" cp "$ROOT/e2e/config/cd/".e2e.* "$ROOT/e2e/cd/" cp "$ROOT/e2e/config/cd/18/".e2e.* "$ROOT/e2e/cd/18" } diff --git a/e2e/test_doctor b/e2e/test_doctor index ee050503c..165dd3bea 100755 --- a/e2e/test_doctor +++ b/e2e/test_doctor @@ -11,5 +11,6 @@ assert() { fi } +rtx plugins install poetry && rtx i eval "$(rtx activate bash)" && _rtx_hook rtx doctor diff --git a/e2e/test_local b/e2e/test_local index 8e4762be7..6a12641e4 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -27,7 +27,9 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] +python = \"3.12.0\" tiny = \"latest\" +poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] @@ -42,7 +44,9 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] +python = \"3.12.0\" tiny = \"latest\" +poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} shfmt = \"3.5.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} @@ -66,7 +70,9 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] +python = \"3.12.0\" tiny = \"latest\" +poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} shfmt = \"3.6.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} @@ -87,7 +93,9 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] +python = \"3.12.0\" tiny = \"latest\" +poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 7699d87a0..cf24e7768 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -16,12 +16,12 @@ assert_contains "rtx node node-build --version" "node-build " # test asdf-nodejs rtx plugin i nodejs https://github.com/asdf-vm/asdf-nodejs.git rtx use nodejs@20.1.0 +rtx ls assert "rtx x -- node --version" "v20.1.0" 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 diff --git a/e2e/test_poetry b/e2e/test_poetry new file mode 100755 index 000000000..049cae951 --- /dev/null +++ b/e2e/test_poetry @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +rm -rf "$RTX_DATA_DIR/cache/poetry" + +export POETRY_HOME=".poetry" + +eval "$(rtx activate bash)" +rtx i python +rtx i poetry + +_rtx_hook +assert "poetry --version" "Poetry (version 1.7.1)" +python3 -V +poetry install +poetry env info +assert "$(poetry env info -e) --version" "Python 3.12.0" +assert "echo \$VIRTUAL_ENV" "$(poetry env info -p)" + +rm pyproject.toml diff --git a/e2e/test_python b/e2e/test_python index 2bebaa770..4fe31f5a9 100755 --- a/e2e/test_python +++ b/e2e/test_python @@ -6,5 +6,5 @@ source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 export RTX_PYTHON_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-python-packages" -rtx i python@3.11 -assert_contains "rtx x python@3.11 -- python --version" "Python 3.11" +rtx i python@3.12.0 +assert_contains "rtx x python@3.12.0 -- python --version" "Python 3.12" diff --git a/src/cli/which.rs b/src/cli/which.rs index 88a3b2391..0b93b984c 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -38,7 +38,7 @@ impl Which { } else if self.plugin { rtxprintln!(out, "{}", p.name); } else { - let path = p.which(&config, &tv, &self.bin_name)?; + let path = p.which(&config, &ts, &tv, &self.bin_name)?; rtxprintln!(out, "{}", path.unwrap().display()); } Ok(()) diff --git a/src/cmd.rs b/src/cmd.rs index 84abe06d2..dd8715d46 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -11,6 +11,7 @@ use duct::{Expression, IntoExecutablePath}; use eyre::Context; use crate::config::Settings; +use crate::env; use crate::errors::Error::ScriptFailed; use crate::file::display_path; use crate::ui::progress_report::ProgressReport; @@ -137,6 +138,23 @@ impl<'a> CmdLineRunner<'a> { self } + pub fn prepend_path_env(&mut self, path: PathBuf) -> &mut Self { + let k: OsString = "PATH".into(); + let mut paths = env::split_paths(self.get_env(&k).unwrap()).collect::>(); + paths.insert(0, path); + self.cmd.env("PATH", env::join_paths(paths).unwrap()); + self + } + + fn get_env(&self, key: &OsString) -> Option<&OsStr> { + for (k, v) in self.cmd.get_envs() { + if k != key { + return v; + } + } + None + } + pub fn arg>(mut self, arg: S) -> Self { self.cmd.arg(arg.as_ref()); self diff --git a/src/install_context.rs b/src/install_context.rs new file mode 100644 index 000000000..01c421d37 --- /dev/null +++ b/src/install_context.rs @@ -0,0 +1,11 @@ +use crate::config::Config; +use crate::toolset::{ToolVersion, Toolset}; +use crate::ui::progress_report::ProgressReport; + +pub struct InstallContext<'a> { + pub config: &'a Config, + pub ts: &'a Toolset, + pub tv: ToolVersion, + pub pr: ProgressReport, + pub force: bool, +} diff --git a/src/main.rs b/src/main.rs index 9dc22b27e..c18b21e55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,6 +40,7 @@ pub mod github; mod hash; mod hook_env; mod http; +mod install_context; mod lock_file; mod logger; mod migrate; diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index de4762113..312292adf 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -6,8 +6,9 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; -use crate::config::{Config, Settings}; +use crate::config::Settings; use crate::github::GithubRelease; +use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; @@ -48,10 +49,10 @@ impl BunPlugin { tv.install_path().join("bin/bun") } - fn test_bun(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("bun -v"); - CmdLineRunner::new(&config.settings, self.bun_bin(tv)) - .with_pr(pr) + fn test_bun(&self, ctx: &InstallContext) -> Result<()> { + ctx.pr.set_message("bun -v"); + CmdLineRunner::new(&ctx.config.settings, self.bun_bin(&ctx.tv)) + .with_pr(&ctx.pr) .arg("-v") .execute() } @@ -73,23 +74,25 @@ impl BunPlugin { Ok(tarball_path) } - fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { - pr.set_message(format!("installing {}", tarball_path.display())); - file::remove_all(tv.install_path())?; - file::create_dir_all(tv.install_path().join("bin"))?; - file::unzip(tarball_path, &tv.download_path())?; + fn install(&self, ctx: &InstallContext, tarball_path: &Path) -> Result<()> { + ctx.pr + .set_message(format!("installing {}", tarball_path.display())); + file::remove_all(ctx.tv.install_path())?; + file::create_dir_all(ctx.tv.install_path().join("bin"))?; + file::unzip(tarball_path, &ctx.tv.download_path())?; file::rename( - tv.download_path() + ctx.tv + .download_path() .join(format!("bun-{}-{}", os(), arch())) .join("bun"), - self.bun_bin(tv), + self.bun_bin(&ctx.tv), )?; - file::make_executable(&self.bun_bin(tv))?; + file::make_executable(&self.bun_bin(&ctx.tv))?; Ok(()) } - fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - self.test_bun(config, tv, pr) + fn verify(&self, ctx: &InstallContext) -> Result<()> { + self.test_bun(ctx) } } @@ -109,17 +112,15 @@ impl Plugin for BunPlugin { Ok(vec![".bun-version".into()]) } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { - assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); - - let tarball_path = self.download(tv, pr)?; - self.install(tv, pr, &tarball_path)?; - self.verify(config, tv, pr)?; + fn install_version(&self, ctx: &InstallContext) -> Result<()> { + assert!(matches!( + &ctx.tv.request, + ToolVersionRequest::Version { .. } + )); + + let tarball_path = self.download(&ctx.tv, &ctx.pr)?; + self.install(ctx, &tarball_path)?; + self.verify(ctx)?; Ok(()) } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 6ee7ad9d8..f1b5437ae 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -9,9 +9,10 @@ use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::github::GithubRelease; +use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; -use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::ProgressReport; use crate::{env, file, http}; @@ -109,22 +110,25 @@ impl Plugin for DenoPlugin { Ok(vec![".deno-version".into()]) } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { - assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); + fn install_version(&self, ctx: &InstallContext) -> Result<()> { + assert!(matches!( + &ctx.tv.request, + ToolVersionRequest::Version { .. } + )); - let tarball_path = self.download(tv, pr)?; - self.install(tv, pr, &tarball_path)?; - self.verify(config, tv, pr)?; + let tarball_path = self.download(&ctx.tv, &ctx.pr)?; + self.install(&ctx.tv, &ctx.pr, &tarball_path)?; + self.verify(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } - fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { + fn list_bin_paths( + &self, + _config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { let bin_paths = vec![ tv.install_path().join("bin"), tv.install_path().join(".deno/bin"), @@ -132,7 +136,12 @@ impl Plugin for DenoPlugin { Ok(bin_paths) } - fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + fn exec_env( + &self, + _config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { let map = HashMap::from([( "DENO_INSTALL_ROOT".into(), tv.install_path().join(".deno").to_string_lossy().into(), diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index c4d6176d1..6d94610fa 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -8,9 +8,10 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; +use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; -use crate::toolset::ToolVersion; +use crate::toolset::{ToolVersion, Toolset}; use crate::ui::progress_report::ProgressReport; use crate::{cmd, env, file, hash, http}; @@ -148,15 +149,10 @@ impl Plugin for GoPlugin { Ok(vec![".go-version".into()]) } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { - let tarball_path = self.download(tv, pr)?; - self.install(tv, pr, &tarball_path)?; - self.verify(config, tv, pr)?; + fn install_version(&self, ctx: &InstallContext) -> Result<()> { + let tarball_path = self.download(&ctx.tv, &ctx.pr)?; + self.install(&ctx.tv, &ctx.pr, &tarball_path)?; + self.verify(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } @@ -169,7 +165,12 @@ impl Plugin for GoPlugin { Ok(()) } - fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { + fn list_bin_paths( + &self, + _config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { // goroot/bin must always be included, irrespective of RTX_GO_SET_GOROOT let mut paths = vec![self.goroot(tv).join("bin")]; if *env::RTX_GO_SET_GOPATH != Some(false) { @@ -178,7 +179,12 @@ impl Plugin for GoPlugin { Ok(paths) } - fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + fn exec_env( + &self, + _config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { let mut map = HashMap::new(); match (*env::RTX_GO_SET_GOROOT, env::PRISTINE_ENV.get("GOROOT")) { (Some(false), _) | (None, Some(_)) => {} diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 5105b6757..292262695 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -14,9 +14,10 @@ use crate::cache::CacheManager; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; +use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; -use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::ProgressReport; use crate::{env, file, hash, http}; @@ -262,23 +263,26 @@ impl Plugin for JavaPlugin { Ok(aliases) } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { - assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); + fn install_version(&self, ctx: &InstallContext) -> Result<()> { + assert!(matches!( + &ctx.tv.request, + ToolVersionRequest::Version { .. } + )); - let metadata = self.tv_to_metadata(tv)?; - let tarball_path = self.download(tv, pr, metadata)?; - self.install(tv, pr, &tarball_path, metadata)?; - self.verify(config, tv, pr)?; + let metadata = self.tv_to_metadata(&ctx.tv)?; + let tarball_path = self.download(&ctx.tv, &ctx.pr, metadata)?; + self.install(&ctx.tv, &ctx.pr, &tarball_path, metadata)?; + self.verify(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } - fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + fn exec_env( + &self, + _config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { let map = HashMap::from([( "JAVA_HOME".into(), tv.install_path().to_string_lossy().into(), diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index a7c062840..bd2abf61c 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -10,6 +10,7 @@ use crate::build_time::built_info; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::env::{RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_MIRROR_URL}; +use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::ToolVersion; @@ -47,26 +48,21 @@ impl NodePlugin { Ok(versions) } - fn install_precompiled( - &self, - config: &Config, - pr: &ProgressReport, - opts: &BuildOpts, - ) -> Result<()> { + fn install_precompiled(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { match self.fetch_tarball( - pr, + &ctx.pr, &opts.binary_tarball_url, &opts.binary_tarball_path, &opts.version, ) { Err(e) if matches!(http::error_code(&e), Some(404)) => { debug!("precompiled node not found"); - self.install_compiled(config, pr, opts) + self.install_compiled(ctx, opts) } e => e, }?; let tarball_name = &opts.binary_tarball_name; - pr.set_message(format!("extracting {tarball_name}")); + ctx.pr.set_message(format!("extracting {tarball_name}")); let tmp_extract_path = tempdir_in(opts.install_path.parent().unwrap())?; file::untar(&opts.binary_tarball_path, tmp_extract_path.path())?; file::remove_all(&opts.install_path)?; @@ -75,25 +71,20 @@ impl NodePlugin { Ok(()) } - fn install_compiled( - &self, - config: &Config, - pr: &ProgressReport, - opts: &BuildOpts, - ) -> Result<()> { + fn install_compiled(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { let tarball_name = &opts.source_tarball_name; self.fetch_tarball( - pr, + &ctx.pr, &opts.source_tarball_url, &opts.source_tarball_path, &opts.version, )?; - pr.set_message(format!("extracting {tarball_name}")); + ctx.pr.set_message(format!("extracting {tarball_name}")); file::remove_all(&opts.build_dir)?; file::untar(&opts.source_tarball_path, opts.build_dir.parent().unwrap())?; - self.exec_configure(config, pr, opts)?; - self.exec_make(config, pr, opts)?; - self.exec_make_install(config, pr, opts)?; + self.exec_configure(ctx, opts)?; + self.exec_make(ctx, opts)?; + self.exec_make_install(ctx, opts)?; Ok(()) } @@ -118,41 +109,26 @@ impl NodePlugin { Ok(()) } - fn sh<'a>( - &'a self, - settings: &'a Settings, - pr: &'a ProgressReport, - opts: &BuildOpts, - ) -> CmdLineRunner { - let mut cmd = CmdLineRunner::new(settings, "sh") - .with_pr(pr) - .current_dir(&opts.build_dir) - .arg("-c"); + fn sh<'a>(&'a self, ctx: &'a InstallContext, opts: &BuildOpts) -> CmdLineRunner { + let mut cmd = CmdLineRunner::new(&ctx.config.settings, "sh"); + for p in &opts.path { + cmd.prepend_path_env(p.clone()); + } + cmd = cmd.with_pr(&ctx.pr).current_dir(&opts.build_dir).arg("-c"); if let Some(cflags) = &*env::RTX_NODE_CFLAGS { cmd = cmd.env("CFLAGS", cflags); } cmd } - fn exec_configure(&self, config: &Config, pr: &ProgressReport, opts: &BuildOpts) -> Result<()> { - self.sh(&config.settings, pr, opts) - .arg(&opts.configure_cmd) - .execute() + fn exec_configure(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { + self.sh(ctx, opts).arg(&opts.configure_cmd).execute() } - fn exec_make(&self, config: &Config, pr: &ProgressReport, opts: &BuildOpts) -> Result<()> { - self.sh(&config.settings, pr, opts) - .arg(&opts.make_cmd) - .execute() + fn exec_make(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { + self.sh(ctx, opts).arg(&opts.make_cmd).execute() } - fn exec_make_install( - &self, - config: &Config, - pr: &ProgressReport, - opts: &BuildOpts, - ) -> Result<()> { - self.sh(&config.settings, pr, opts) - .arg(&opts.make_install_cmd) - .execute() + fn exec_make_install(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { + self.sh(ctx, opts).arg(&opts.make_install_cmd).execute() } fn verify(&self, tarball: &Path, version: &str) -> Result<()> { @@ -284,23 +260,18 @@ impl Plugin for NodePlugin { Ok(body.to_string()) } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { - let opts = BuildOpts::new(tv)?; + fn install_version(&self, ctx: &InstallContext) -> Result<()> { + let opts = BuildOpts::new(ctx)?; debug!("node build opts: {:#?}", opts); if *env::RTX_NODE_COMPILE { - self.install_compiled(config, pr, &opts)?; + self.install_compiled(ctx, &opts)?; } else { - self.install_precompiled(config, pr, &opts)?; + self.install_precompiled(ctx, &opts)?; } - self.test_node(config, tv, pr)?; - self.install_npm_shim(tv)?; - self.test_npm(config, tv, pr)?; - self.install_default_packages(config, tv, pr)?; + self.test_node(ctx.config, &ctx.tv, &ctx.pr)?; + self.install_npm_shim(&ctx.tv)?; + self.test_npm(ctx.config, &ctx.tv, &ctx.pr)?; + self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } } @@ -308,6 +279,7 @@ impl Plugin for NodePlugin { #[derive(Debug)] struct BuildOpts { version: String, + path: Vec, install_path: PathBuf, build_dir: PathBuf, configure_cmd: String, @@ -322,23 +294,24 @@ struct BuildOpts { } impl BuildOpts { - fn new(tv: &ToolVersion) -> Result { - let v = &tv.version; - let install_path = tv.install_path(); + fn new(ctx: &InstallContext) -> Result { + let v = &ctx.tv.version; + let install_path = ctx.tv.install_path(); let source_tarball_name = format!("node-v{v}.tar.gz"); let binary_tarball_name = format!("node-v{v}-{}-{}.tar.gz", os(), arch()); Ok(Self { version: v.clone(), + path: ctx.ts.list_paths(ctx.config), build_dir: env::RTX_TMP_DIR.join(format!("node-v{v}")), configure_cmd: configure_cmd(&install_path), make_cmd: make_cmd(), make_install_cmd: make_install_cmd(), - source_tarball_path: tv.download_path().join(&source_tarball_name), + source_tarball_path: ctx.tv.download_path().join(&source_tarball_name), source_tarball_url: env::RTX_NODE_MIRROR_URL .join(&format!("v{v}/{source_tarball_name}"))?, source_tarball_name, - binary_tarball_path: tv.download_path().join(&binary_tarball_name), + binary_tarball_path: ctx.tv.download_path().join(&binary_tarball_name), binary_tarball_url: env::RTX_NODE_MIRROR_URL .join(&format!("v{v}/{binary_tarball_name}"))?, binary_tarball_name, diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index 6cfbd92c0..5e0cf2913 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -11,6 +11,7 @@ use crate::duration::DAILY; use crate::env::{RTX_NODE_COMPILE, RTX_NODE_CONCURRENCY, RTX_NODE_MAKE_OPTS, RTX_NODE_MIRROR_URL}; use crate::file::create_dir_all; use crate::git::Git; +use crate::install_context::InstallContext; use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; @@ -251,20 +252,15 @@ impl Plugin for NodeBuildPlugin { exit(0); } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { + fn install_version(&self, ctx: &InstallContext) -> Result<()> { self.install_node_build()?; - pr.set_message("running node-build"); - let mut cmd = CmdLineRunner::new(&config.settings, self.node_build_bin()) - .with_pr(pr) + ctx.pr.set_message("running node-build"); + let mut cmd = CmdLineRunner::new(&ctx.config.settings, self.node_build_bin()) + .with_pr(&ctx.pr) .env("NODE_BUILD_MIRROR_URL", RTX_NODE_MIRROR_URL.to_string()) - .envs(&config.env) - .arg(tv.version.as_str()); - if matches!(&tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_COMPILE { + .envs(&ctx.config.env) + .arg(ctx.tv.version.as_str()); + if matches!(&ctx.tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_COMPILE { let mut make_opts = RTX_NODE_MAKE_OPTS.clone().unwrap_or_default(); if let Some(concurrency) = *RTX_NODE_CONCURRENCY { make_opts = format!("{} -j{}", make_opts, concurrency); @@ -284,14 +280,14 @@ impl Plugin for NodeBuildPlugin { } cmd = cmd.arg("--compile"); } - if self.verbose_install(&config.settings) { + if self.verbose_install(&ctx.config.settings) { cmd = cmd.arg("--verbose"); } - cmd.arg(tv.install_path()).execute()?; - self.test_node(config, tv, pr)?; - self.install_npm_shim(tv)?; - self.test_npm(config, tv, pr)?; - self.install_default_packages(config, tv, pr)?; + cmd.arg(&ctx.tv.install_path()).execute()?; + self.test_node(ctx.config, &ctx.tv, &ctx.pr)?; + self.install_npm_shim(&ctx.tv)?; + self.test_npm(ctx.config, &ctx.tv, &ctx.pr)?; + self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index d5fcc818b..7aadb0c85 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -7,9 +7,10 @@ use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::file::create_dir_all; use crate::git::Git; +use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; -use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::ProgressReport; use crate::{cmd, env, file, http}; @@ -161,27 +162,23 @@ impl Plugin for PythonPlugin { Ok(vec![".python-version".to_string()]) } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { + fn install_version(&self, ctx: &InstallContext) -> Result<()> { self.install_python_build()?; - if matches!(tv.request, ToolVersionRequest::Ref(..)) { + if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); } - pr.set_message("running python-build"); - let mut cmd = CmdLineRunner::new(&config.settings, self.python_build_bin()) - .with_pr(pr) - .arg(tv.version.as_str()) - .arg(tv.install_path()) - .envs(&config.env); - if config.settings.verbose { + ctx.pr.set_message("running python-build"); + let mut cmd = CmdLineRunner::new(&ctx.config.settings, self.python_build_bin()) + .with_pr(&ctx.pr) + .arg(ctx.tv.version.as_str()) + .arg(&ctx.tv.install_path()) + .envs(&ctx.config.env); + if ctx.config.settings.verbose { cmd = cmd.arg("--verbose"); } if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { - pr.set_message(format!("with patch file from: {patch_url}")); + ctx.pr + .set_message(format!("with patch file from: {patch_url}")); let http = http::Client::new()?; let resp = http.get(patch_url).send()?; resp.error_for_status_ref()?; @@ -189,23 +186,30 @@ impl Plugin for PythonPlugin { cmd = cmd.arg("--patch").stdin_string(patch) } if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { - let patch_file = patches_dir.join(format!("{}.patch", tv.version)); + let patch_file = patches_dir.join(format!("{}.patch", &ctx.tv.version)); if patch_file.exists() { - pr.set_message(format!("with patch file: {}", patch_file.display())); + ctx.pr + .set_message(format!("with patch file: {}", patch_file.display())); let contents = file::read_to_string(&patch_file)?; cmd = cmd.arg("--patch").stdin_string(contents); } else { - pr.warn(format!("patch file not found: {}", patch_file.display())); + ctx.pr + .warn(format!("patch file not found: {}", patch_file.display())); } } cmd.execute()?; - self.test_python(config, tv, pr)?; - self.get_virtualenv(config, tv, Some(pr))?; - self.install_default_packages(config, tv, pr)?; + self.test_python(ctx.config, &ctx.tv, &ctx.pr)?; + self.get_virtualenv(ctx.config, &ctx.tv, Some(&ctx.pr))?; + self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } - fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + fn list_bin_paths( + &self, + config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { if let Some(virtualenv) = self.get_virtualenv(config, tv, None)? { Ok(vec![virtualenv.join("bin"), tv.install_path().join("bin")]) } else { @@ -213,7 +217,12 @@ impl Plugin for PythonPlugin { } } - fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + fn exec_env( + &self, + config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { if let Some(virtualenv) = self.get_virtualenv(config, tv, None)? { let hm = HashMap::from([( "VIRTUAL_ENV".to_string(), diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 3fe8fe32c..4cabc048a 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -10,10 +10,11 @@ use crate::duration::DAILY; use crate::env::GITHUB_API_TOKEN; use crate::git::Git; use crate::github::GithubRelease; +use crate::install_context::InstallContext; use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; -use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::ProgressReport; use crate::{cmd, env, file, http}; @@ -352,26 +353,29 @@ impl Plugin for RubyPlugin { Ok(v) } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { + fn install_version(&self, ctx: &InstallContext) -> Result<()> { self.update_build_tool()?; - assert!(matches!(&tv.request, ToolVersionRequest::Version { .. })); - - pr.set_message("running ruby-build"); - self.install_cmd(config, tv, pr)?.execute()?; - - self.test_ruby(config, tv, pr)?; - self.install_rubygems_hook(tv)?; - self.test_gem(config, tv, pr)?; - self.install_default_gems(config, tv, pr)?; + assert!(matches!( + &ctx.tv.request, + ToolVersionRequest::Version { .. } + )); + + ctx.pr.set_message("running ruby-build"); + self.install_cmd(ctx.config, &ctx.tv, &ctx.pr)?.execute()?; + + self.test_ruby(ctx.config, &ctx.tv, &ctx.pr)?; + self.install_rubygems_hook(&ctx.tv)?; + self.test_gem(ctx.config, &ctx.tv, &ctx.pr)?; + self.install_default_gems(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } - fn exec_env(&self, _config: &Config, tv: &ToolVersion) -> Result> { + fn exec_env( + &self, + _config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { // TODO: is there a way to avoid needing to set RUBYLIB? // is there a directory I can put rubygems_plugin.rb in that will be automatically loaded? let rubygems_plugin_path = self.rubygems_plugins_path(tv); diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 5dc81e80d..aa901de38 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -19,12 +19,13 @@ use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_all}; use crate::git::Git; use crate::hash::hash_to_str; +use crate::install_context::InstallContext; use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::rtx_plugin_toml::RtxPluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; use crate::timeout::run_with_timeout; -use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::ProgressReport; use crate::ui::prompt; @@ -237,15 +238,26 @@ impl ExternalPlugin { Ok(()) } - fn fetch_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + fn fetch_bin_paths( + &self, + config: &Config, + ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { let list_bin_paths = self.plugin_path.join("bin/list-bin-paths"); let bin_paths = if matches!(tv.request, ToolVersionRequest::System(_)) { Vec::new() } else if list_bin_paths.exists() { - let output = self - .script_man_for_tv(config, tv) - .cmd(&config.settings, &Script::ListBinPaths) - .read()?; + let mut sm = self.script_man_for_tv(config, tv); + for (t, tv) in ts.list_current_installed_versions(config) { + if t.name == self.name { + continue; + } + for p in t.list_bin_paths(config, ts, &tv)? { + sm.prepend_path(p); + } + } + let output = sm.cmd(&config.settings, &Script::ListBinPaths).read()?; output.split_whitespace().map(|f| f.to_string()).collect() } else { vec!["bin".into()] @@ -256,9 +268,18 @@ impl ExternalPlugin { .collect(); Ok(bin_paths) } - fn fetch_exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { - let script = self.script_man_for_tv(config, tv).get_script_path(&ExecEnv); - let ed = EnvDiff::from_bash_script(&script, &self.script_man_for_tv(config, tv).env)?; + fn fetch_exec_env( + &self, + config: &Config, + ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { + let mut sm = self.script_man_for_tv(config, tv); + for p in ts.list_paths(config) { + sm.prepend_path(p); + } + let script = sm.get_script_path(&ExecEnv); + let ed = EnvDiff::from_bash_script(&script, &sm.env)?; let env = ed .to_patches() .into_iter() @@ -595,22 +616,20 @@ impl Plugin for ExternalPlugin { exit(result.status.code().unwrap_or(1)); } - fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { - let run_script = |script| { - self.script_man_for_tv(config, tv) - .run_by_line(&config.settings, script, pr) - }; + fn install_version(&self, ctx: &InstallContext) -> Result<()> { + let mut sm = self.script_man_for_tv(ctx.config, &ctx.tv); + + for p in ctx.ts.list_paths(ctx.config) { + sm.prepend_path(p); + } + + let run_script = |script| sm.run_by_line(&ctx.config.settings, script, &ctx.pr); - if self.script_man_for_tv(config, tv).script_exists(&Download) { - pr.set_message("downloading"); + if sm.script_exists(&Download) { + ctx.pr.set_message("downloading"); run_script(&Download)?; } - pr.set_message("installing"); + ctx.pr.set_message("installing"); run_script(&Install)?; Ok(()) @@ -624,12 +643,22 @@ impl Plugin for ExternalPlugin { Ok(()) } - fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + fn list_bin_paths( + &self, + config: &Config, + ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { self.cache - .list_bin_paths(config, self, tv, || self.fetch_bin_paths(config, tv)) + .list_bin_paths(config, self, tv, || self.fetch_bin_paths(config, ts, tv)) } - fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + fn exec_env( + &self, + config: &Config, + ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { if matches!(tv.request, ToolVersionRequest::System(_)) { return Ok(EMPTY_HASH_MAP.clone()); } @@ -639,7 +668,7 @@ impl Plugin for ExternalPlugin { return Ok(EMPTY_HASH_MAP.clone()); } self.cache - .exec_env(config, self, tv, || self.fetch_exec_env(config, tv)) + .exec_env(config, self, tv, || self.fetch_exec_env(config, ts, tv)) } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index be56ab3b3..f66126182 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -12,8 +12,9 @@ pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; use crate::file; use crate::file::display_path; +use crate::install_context::InstallContext; use crate::lock_file::LockFile; -use crate::toolset::ToolVersion; +use crate::toolset::{ToolVersion, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; @@ -81,15 +82,24 @@ pub trait Plugin: Debug + Send + Sync { ) -> Result<()> { unimplemented!() } - fn install_version(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) - -> Result<()>; + fn install_version(&self, ctx: &InstallContext) -> Result<()>; fn uninstall_version(&self, _config: &Config, _tv: &ToolVersion) -> Result<()> { Ok(()) } - fn list_bin_paths(&self, _config: &Config, tv: &ToolVersion) -> Result> { + fn list_bin_paths( + &self, + _config: &Config, + _ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { Ok(vec![tv.install_path().join("bin")]) } - fn exec_env(&self, _config: &Config, _tv: &ToolVersion) -> Result> { + fn exec_env( + &self, + _config: &Config, + _ts: &Toolset, + _tv: &ToolVersion, + ) -> Result> { Ok(HashMap::new()) } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 8800ca2dc..9246a8421 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -114,6 +114,14 @@ impl ScriptManager { self } + pub fn prepend_path(&mut self, path: PathBuf) { + let k: OsString = "PATH".into(); + let mut paths = env::split_paths(&self.env[&k]).collect::>(); + paths.insert(0, path); + self.env + .insert("PATH".into(), env::join_paths(paths).unwrap()); + } + pub fn get_script_path(&self, script: &Script) -> PathBuf { match script { Script::RunExternalCommand(path, _) => path.clone(), diff --git a/src/shims.rs b/src/shims.rs index 0e80ab603..b348cb1ff 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -45,7 +45,7 @@ fn which_shim(config: &mut Config, bin_name: &str) -> Result { if shim.exists() { let ts = ToolsetBuilder::new().build(config)?; if let Some((p, tv)) = ts.which(config, bin_name) { - if let Some(bin) = p.which(config, &tv, bin_name)? { + if let Some(bin) = p.which(config, &ts, &tv, bin_name)? { return Ok(bin); } } @@ -91,7 +91,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let shims: HashSet = ts .list_installed_versions(config)? .into_par_iter() - .flat_map(|(t, tv)| match list_tool_bins(config, &t, &tv) { + .flat_map(|(t, tv)| match list_tool_bins(config, ts, &t, &tv) { Ok(paths) => paths, Err(e) => { warn!("Error listing bin paths for {}: {:#}", tv, e); @@ -137,8 +137,13 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { } // lists all the paths to bins in a tv that shims will be needed for -fn list_tool_bins(config: &Config, t: &Tool, tv: &ToolVersion) -> Result> { - Ok(t.list_bin_paths(config, tv)? +fn list_tool_bins( + config: &Config, + ts: &Toolset, + t: &Tool, + tv: &ToolVersion, +) -> Result> { + Ok(t.list_bin_paths(config, ts, tv)? .into_iter() .par_bridge() .filter(|path| path.exists()) diff --git a/src/tool.rs b/src/tool.rs index 279699385..6e2e8a547 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -13,9 +13,10 @@ use versions::Versioning; use crate::config::{Config, Settings}; use crate::file::{display_path, remove_all, remove_all_with_warning}; +use crate::install_context::InstallContext; use crate::plugins::{ExternalPlugin, Plugin}; use crate::runtime_symlinks::is_runtime_symlink; -use crate::toolset::{ToolVersion, ToolVersionRequest}; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; use crate::{dirs, file}; @@ -204,43 +205,37 @@ impl Tool { file::make_symlink(target, &link) } - pub fn install_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &mut ProgressReport, - force: bool, - ) -> Result<()> { - if self.is_version_installed(tv) { - if force { - self.uninstall_version(config, tv, pr, false)?; + pub fn install_version(&self, mut ctx: InstallContext) -> Result<()> { + if self.is_version_installed(&ctx.tv) { + if ctx.force { + self.uninstall_version(ctx.config, &ctx.tv, &ctx.pr, false)?; } else { return Ok(()); } } - self.decorate_progress_bar(pr, Some(tv)); - let _lock = self.get_lock(&tv.install_path(), force)?; - self.create_install_dirs(tv)?; + self.decorate_progress_bar(&mut ctx.pr, Some(&ctx.tv)); + let _lock = self.get_lock(&ctx.tv.install_path(), ctx.force)?; + self.create_install_dirs(&ctx.tv)?; - if let Err(e) = self.plugin.install_version(config, tv, pr) { - self.cleanup_install_dirs_on_error(&config.settings, tv); + if let Err(e) = self.plugin.install_version(&ctx) { + self.cleanup_install_dirs_on_error(&ctx.config.settings, &ctx.tv); return Err(e); } - self.cleanup_install_dirs(&config.settings, tv); + self.cleanup_install_dirs(&ctx.config.settings, &ctx.tv); // attempt to touch all the .tool-version files to trigger updates in hook-env let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; - touch_dirs.extend(config.config_files.keys().cloned()); + touch_dirs.extend(ctx.config.config_files.keys().cloned()); for path in touch_dirs { let err = file::touch_dir(&path); if let Err(err) = err { debug!("error touching config file: {:?} {:?}", path, err); } } - if let Err(err) = file::remove_file(self.incomplete_file_path(tv)) { + if let Err(err) = file::remove_file(self.incomplete_file_path(&ctx.tv)) { debug!("error removing incomplete file: {:?}", err); } - pr.set_message(""); - pr.finish(); + ctx.pr.set_message(""); + ctx.pr.finish(); Ok(()) } @@ -308,26 +303,37 @@ impl Tool { pub fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result { self.plugin.parse_legacy_file(path, settings) } - pub fn list_bin_paths(&self, config: &Config, tv: &ToolVersion) -> Result> { + pub fn list_bin_paths( + &self, + config: &Config, + ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { match tv.request { ToolVersionRequest::System(_) => Ok(vec![]), - _ => self.plugin.list_bin_paths(config, tv), + _ => self.plugin.list_bin_paths(config, ts, tv), } } - pub fn exec_env(&self, config: &Config, tv: &ToolVersion) -> Result> { + pub fn exec_env( + &self, + config: &Config, + ts: &Toolset, + tv: &ToolVersion, + ) -> Result> { match tv.request { ToolVersionRequest::System(_) => Ok(HashMap::new()), - _ => self.plugin.exec_env(config, tv), + _ => self.plugin.exec_env(config, ts, tv), } } pub fn which( &self, config: &Config, + ts: &Toolset, tv: &ToolVersion, bin_name: &str, ) -> Result> { - let bin_paths = self.plugin.list_bin_paths(config, tv)?; + let bin_paths = self.plugin.list_bin_paths(config, ts, tv)?; for bin_path in bin_paths { let bin_path = bin_path.join(bin_name); if bin_path.exists() { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index c90a322fc..2b48454f0 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -21,6 +21,7 @@ pub use tool_version_request::ToolVersionRequest; use crate::config::{Config, MissingRuntimeBehavior}; use crate::env; +use crate::install_context::InstallContext; use crate::plugins::PluginName; use crate::runtime_symlinks; use crate::shims; @@ -160,13 +161,19 @@ impl Toolset { .map(|_| { let queue = queue.clone(); let config = &*config; + let ts = &*self; s.spawn(move || { let next_job = || queue.lock().unwrap().pop(); while let Some((t, versions)) = next_job() { for tv in versions { - let tv = tv.request.resolve(config, &t, tv.opts.clone(), true)?; - let mut pr = mpr.add(); - t.install_version(config, &tv, &mut pr, force)?; + let ctx = InstallContext { + config, + ts, + tv: tv.request.resolve(config, &t, tv.opts.clone(), true)?, + pr: mpr.add(), + force, + }; + t.install_version(ctx)?; } } Ok(()) @@ -288,7 +295,7 @@ impl Toolset { let mut entries: BTreeMap = self .list_current_installed_versions(config) .into_par_iter() - .flat_map(|(p, tv)| match p.exec_env(config, &tv) { + .flat_map(|(p, tv)| match p.exec_env(config, self, &tv) { Ok(env) => env.into_iter().collect(), Err(e) => { warn!("Error running exec-env: {:#}", e); @@ -314,7 +321,7 @@ 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, &tv) { + .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); @@ -327,7 +334,7 @@ impl Toolset { self.list_current_installed_versions(config) .into_par_iter() .find_first(|(p, tv)| { - if let Ok(x) = p.which(config, tv, bin_name) { + if let Ok(x) = p.which(config, self, tv, bin_name) { x.is_some() } else { false @@ -339,7 +346,7 @@ impl Toolset { Ok(self .list_installed_versions(config)? .into_par_iter() - .filter(|(p, tv)| match p.which(config, tv, bin_name) { + .filter(|(p, tv)| match p.which(config, self, tv, bin_name) { Ok(x) => x.is_some(), Err(e) => { warn!("Error running which: {:#}", e); From d1987363ed4a71f9a40dd33e6973b53e2ca23e6a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 01:02:33 -0600 Subject: [PATCH 1147/1891] chore: Release rtx-cli version 2023.12.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48a3df59e..8764b59bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.1" +version = "2023.12.2" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 444b38bea..a2cefff9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.1" +version = "2023.12.2" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 13f47df86..0524b5056 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.1 +rtx 2023.12.2 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.1/rtx-v2023.12.1-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.2/rtx-v2023.12.2-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index db94d34cb..42a68d7f0 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.1"; + version = "2023.12.2"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 56f4e22d1..93384ea34 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.1 +Version: 2023.12.2 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 01734d4d6e3699760d749605cc15e957de788330 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 01:18:30 -0600 Subject: [PATCH 1148/1891] remove failing yarn test --- .github/workflows/test-plugins.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index f25c131a5..61e92e5be 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -69,8 +69,8 @@ jobs: command: rtx exec java@openjdk -- java -version - plugin: terraform command: rtx exec terraform@latest -- terraform -v - - plugin: yarn - command: rtx exec yarn@latest -- yarn --version + # - plugin: yarn + # command: rtx exec yarn@latest -- yarn --version - plugin: deno command: rtx exec deno@latest -- deno --version - plugin: bun From 1ef0fc0f4016fbb5e247ff10e25df5476f7c9c08 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 13:15:38 -0600 Subject: [PATCH 1149/1891] fix compatibility with rust 1.70.0 (#1049) also updated msrv to clap minimum --- .github/workflows/rtx.yml | 8 +++++--- Cargo.toml | 8 +++++++- src/timeout.rs | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 674f3ceaf..343445d84 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -24,17 +24,19 @@ jobs: uses: Swatinem/rust-cache@v2 with: save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + - uses: taiki-e/install-action@v2 + with: + tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete - name: Install direnv/shfmt run: sudo apt-get update; sudo apt-get install direnv shfmt - - uses: taiki-e/install-action@nextest - name: Run cargo nextest run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" - - uses: taiki-e/install-action@just - run: just lint - - uses: taiki-e/install-action@cargo-deny - run: cargo deny check + - run: cargo msrv verify + - run: cargo machete --with-metadata coverage: name: coverage-${{matrix.tranche}} diff --git a/Cargo.toml b/Cargo.toml index a2cefff9a..fc373d5ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ include = [ "/build.rs", "/zipsign.pub", ] -rust-version = "1.65.0" +rust-version = "1.70.0" build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -141,3 +141,9 @@ pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-macos-x64{ arc pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-linux-arm64{ archive-suffix }" [package.metadata.binstall.overrides.x86_64-unknown-linux-gnu] pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-linux-x64{ archive-suffix }" + +[package.metadata.cargo-machete] +ignored = [ + "built", + "openssl", +] diff --git a/src/timeout.rs b/src/timeout.rs index b09812b6f..a0f2d3c27 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -11,7 +11,7 @@ where { let (tx, rx) = mpsc::channel(); thread::scope(|s| { - s.spawn(|| { + s.spawn(move || { let result = f(); // If sending fails, the timeout has already been reached. let _ = tx.send(result); From 4e9ff1702d4779582728d003ae17a5ec6c59191c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 15:14:50 -0600 Subject: [PATCH 1150/1891] use: reuse existing versions (#1053) --- e2e/test_use | 9 +++ schema/rtx.json | 4 ++ .../rtx__cli__r#use__tests__use_local-2.snap | 4 +- src/cli/use.rs | 71 +++++++++++-------- src/config/config_file/rtx_toml.rs | 33 ++++++++- ...nfig_file__rtx_toml__tests__fixture-2.snap | 21 +----- src/config/settings.rs | 63 +++++++++++++++- 7 files changed, 153 insertions(+), 52 deletions(-) create mode 100755 e2e/test_use diff --git a/e2e/test_use b/e2e/test_use new file mode 100755 index 000000000..eb9cf9f18 --- /dev/null +++ b/e2e/test_use @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +rtx rm --all tiny +rtx i tiny@1.0.0 +rtx use tiny@1 +assert "rtx current tiny" "1.0.0" diff --git a/schema/rtx.json b/schema/rtx.json index 2d05973c0..264d08d6a 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -196,6 +196,10 @@ "verbose": { "description": "display installation output", "type": "boolean" + }, + "yes": { + "description": "assume yes for all prompts", + "type": "boolean" } } } diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap index 10ba158af..5e8a51890 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap @@ -1,7 +1,7 @@ --- source: src/cli/use.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(&cf_path).unwrap()" --- [tools] -tiny = "3.1.0" +tiny = "2.1.0" diff --git a/src/cli/use.rs b/src/cli/use.rs index 3eb01efc9..52887a401 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -3,11 +3,12 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::cli::local::local; -use crate::config::Config; +use crate::config::{config_file, Config, MissingRuntimeBehavior}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::output::Output; use crate::plugins::PluginName; +use crate::toolset::ToolsetBuilder; +use crate::ui::multi_progress_report::MultiProgressReport; use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. @@ -50,30 +51,49 @@ pub struct Use { } impl Use { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { - let runtimes = self - .tool - .into_iter() - .map(|r| match &r.tvr { - Some(_) => r, - None => ToolArg::parse(&format!("{}@latest", r.plugin)), - }) - .collect(); + pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + let mut ts = ToolsetBuilder::new() + .with_args(&self.tool) + .build(&mut config)?; + ts.versions + .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); + let mpr = MultiProgressReport::new(config.show_progress_bars()); + config.settings.missing_runtime_behavior = MissingRuntimeBehavior::AutoInstall; + ts.install_missing(&mut config, mpr)?; + let path = match (self.global, self.path) { (true, _) => global_file(), (false, Some(p)) => config_file_from_dir(&p), (false, None) => config_file_from_dir(&dirs::CURRENT), }; - local( - config, - out, - &path, - runtimes, - self.remove, - self.pin, - self.fuzzy, - false, - ) + let is_trusted = config_file::is_trusted(&config.settings, &path); + let mut cf = match path.exists() { + true => config_file::parse(&path, is_trusted)?, + false => config_file::init(&path, is_trusted), + }; + + let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); + + for (plugin_name, tvl) in ts.versions { + let versions: Vec = tvl + .versions + .into_iter() + .map(|tv| { + if pin { + tv.version + } else { + tv.request.version() + } + }) + .collect(); + cf.replace_versions(&plugin_name, &versions); + } + + for plugin_name in self.remove.unwrap_or_default() { + cf.remove_plugin(&plugin_name); + } + cf.save()?; + Ok(()) } } @@ -133,13 +153,8 @@ mod tests { assert_cli!("use", "--fuzzy", "tiny@2"); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); - assert_cli!( - "use", - "--rm", - "tiny", - "--path", - &cf_path.to_string_lossy().to_string() - ); + let p = cf_path.to_string_lossy().to_string(); + assert_cli!("use", "--rm", "tiny", "--path", &p); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); let _ = file::remove_file(&cf_path); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 8c1ca47df..841008ac0 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Display, Formatter}; use std::path::{Path, PathBuf}; use std::time::Duration; @@ -24,7 +24,7 @@ use crate::toolset::{ use crate::ui::prompt; use crate::{dirs, env, file, parse_error}; -#[derive(Debug, Default)] +#[derive(Default)] pub struct RtxToml { context: Context, path: PathBuf, @@ -769,6 +769,35 @@ impl ConfigFile for RtxToml { } } +impl Debug for RtxToml { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut d = f.debug_struct("RtxToml"); + d.field("path", &self.path) + .field("toolset", &self.toolset.to_string()) + .field("is_trusted", &self.is_trusted) + .field("settings", &self.settings); + if let Some(env_file) = &self.env_file { + d.field("env_file", env_file); + } + if !self.env.is_empty() { + d.field("env", &self.env); + } + if !self.env_remove.is_empty() { + d.field("env_remove", &self.env_remove); + } + if !self.path_dirs.is_empty() { + d.field("path_dirs", &self.path_dirs); + } + if !self.alias.is_empty() { + d.field("alias", &self.alias); + } + if !self.plugins.is_empty() { + d.field("plugins", &self.plugins); + } + d.finish() + } +} + #[cfg(test)] mod tests { use indoc::formatdoc; diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index ff41b3d06..a09a63699 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -3,29 +3,12 @@ source: src/config/config_file/rtx_toml.rs expression: cf.settings() --- SettingsBuilder { - experimental: None, - missing_runtime_behavior: Some( - Warn, - ), - always_keep_download: None, - always_keep_install: None, - legacy_version_file: None, + missing_runtime_behavior: Warn, legacy_version_file_disable_tools: { "disabled_tool_from_legacy_file", }, - plugin_autoupdate_last_check_duration: None, - trusted_config_paths: {}, - verbose: Some( - true, - ), - asdf_compat: None, - jobs: None, - shorthands_file: None, - disable_default_shorthands: None, + verbose: true, disable_tools: { "disabled_tool", }, - log_level: None, - raw: None, - yes: None, } diff --git a/src/config/settings.rs b/src/config/settings.rs index a6778cac5..d7ffb7a28 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -114,7 +114,7 @@ impl Settings { } } -#[derive(Debug, Default, Clone)] +#[derive(Default, Clone)] pub struct SettingsBuilder { pub experimental: Option, pub missing_runtime_behavior: Option, @@ -255,6 +255,67 @@ impl Display for Settings { } } +impl Debug for SettingsBuilder { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut d = f.debug_struct("SettingsBuilder"); + if let Some(experimental) = self.experimental { + d.field("experimental", &experimental); + } + if let Some(missing_runtime_behavior) = &self.missing_runtime_behavior { + d.field("missing_runtime_behavior", &missing_runtime_behavior); + } + if let Some(always_keep_download) = self.always_keep_download { + d.field("always_keep_download", &always_keep_download); + } + if let Some(always_keep_install) = self.always_keep_install { + d.field("always_keep_install", &always_keep_install); + } + if let Some(legacy_version_file) = self.legacy_version_file { + d.field("legacy_version_file", &legacy_version_file); + } + if !self.legacy_version_file_disable_tools.is_empty() { + d.field( + "legacy_version_file_disable_tools", + &self.legacy_version_file_disable_tools, + ); + } + if let Some(c) = self.plugin_autoupdate_last_check_duration { + d.field("plugin_autoupdate_last_check_duration", &c); + } + if !self.trusted_config_paths.is_empty() { + d.field("trusted_config_paths", &self.trusted_config_paths); + } + if let Some(verbose) = self.verbose { + d.field("verbose", &verbose); + } + if let Some(asdf_compat) = self.asdf_compat { + d.field("asdf_compat", &asdf_compat); + } + if let Some(jobs) = self.jobs { + d.field("jobs", &jobs); + } + if let Some(shorthands_file) = &self.shorthands_file { + d.field("shorthands_file", &shorthands_file); + } + if let Some(dds) = self.disable_default_shorthands { + d.field("disable_default_shorthands", &dds); + } + if !self.disable_tools.is_empty() { + d.field("disable_tools", &self.disable_tools); + } + if let Some(log_level) = self.log_level { + d.field("log_level", &log_level); + } + if let Some(raw) = self.raw { + d.field("raw", &raw); + } + if let Some(yes) = self.yes { + d.field("yes", &yes); + } + d.finish() + } +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum MissingRuntimeBehavior { AutoInstall, From 4a68c93045bf07337474270044652ccdfab346f5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 15:23:53 -0600 Subject: [PATCH 1151/1891] fix deadlock (#1054) This was introduced in #1047 --- src/plugins/external_plugin.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index aa901de38..a67f42ca9 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -241,22 +241,23 @@ impl ExternalPlugin { fn fetch_bin_paths( &self, config: &Config, - ts: &Toolset, + _ts: &Toolset, tv: &ToolVersion, ) -> Result> { let list_bin_paths = self.plugin_path.join("bin/list-bin-paths"); let bin_paths = if matches!(tv.request, ToolVersionRequest::System(_)) { Vec::new() } else if list_bin_paths.exists() { - let mut sm = self.script_man_for_tv(config, tv); - for (t, tv) in ts.list_current_installed_versions(config) { - if t.name == self.name { - continue; - } - for p in t.list_bin_paths(config, ts, &tv)? { - sm.prepend_path(p); - } - } + let sm = self.script_man_for_tv(config, tv); + // TODO: find a way to enable this without deadlocking + // for (t, tv) in ts.list_current_installed_versions(config) { + // if t.name == self.name { + // continue; + // } + // for p in t.list_bin_paths(config, ts, &tv)? { + // sm.prepend_path(p); + // } + // } let output = sm.cmd(&config.settings, &Script::ListBinPaths).read()?; output.split_whitespace().map(|f| f.to_string()).collect() } else { From f878a2ef70af6fd2b1e014ca78098f3ae91550b4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 15:24:23 -0600 Subject: [PATCH 1152/1891] chore: Release rtx-cli version 2023.12.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8764b59bd..662d51da7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.2" +version = "2023.12.3" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index fc373d5ca..d99b21a4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.2" +version = "2023.12.3" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 0524b5056..9a894f882 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.2 +rtx 2023.12.3 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.2/rtx-v2023.12.2-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.3/rtx-v2023.12.3-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 42a68d7f0..e61a34d6e 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.2"; + version = "2023.12.3"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 93384ea34..684eaba85 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.2 +Version: 2023.12.3 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 7232723b781c04d40be258aced3c2d0af2d78fda Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 15:52:43 -0600 Subject: [PATCH 1153/1891] test: fix warning in e2e/test_poetry (#1055) --- e2e/config/pyproject.toml | 1 + e2e/poetry_demo/__init__.py | 0 2 files changed, 1 insertion(+) create mode 100644 e2e/poetry_demo/__init__.py diff --git a/e2e/config/pyproject.toml b/e2e/config/pyproject.toml index 58cf8e1bb..dd47e64ae 100644 --- a/e2e/config/pyproject.toml +++ b/e2e/config/pyproject.toml @@ -3,6 +3,7 @@ name = "poetry-test" version = "0.1.0" description = "" authors = ["rtx"] +packages = [{include = "poetry_demo"}] [tool.poetry.dependencies] python = "^3.12" diff --git a/e2e/poetry_demo/__init__.py b/e2e/poetry_demo/__init__.py new file mode 100644 index 000000000..e69de29bb From 8e00e769406530dd48ed6e960872f84696a61d93 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:00:37 -0600 Subject: [PATCH 1154/1891] support RTX_ADD_PATH (#1056) This is an env var that poetry/pipenv use to add VIRTUAL_ENV/bin to PATH while not also creating shims for everything in there. See https://github.com/jdx/rtx/issues/897 --- src/cli/direnv/envrc.rs | 16 ++++++++++------ src/cli/hook_env.rs | 8 ++++++-- src/toolset/mod.rs | 18 +++++++++++++++--- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 3a87c5239..6bbc88905 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -41,12 +41,16 @@ impl Envrc { writeln!(file, "watch_file {}", cf.to_string_lossy())?; } for (k, v) in ts.env(&config) { - writeln!( - file, - "export {}={}", - shell_escape::unix::escape(k.into()), - shell_escape::unix::escape(v.into()), - )?; + if k == "PATH" { + writeln!(file, "PATH_add {}", v)?; + } else { + writeln!( + file, + "export {}={}", + shell_escape::unix::escape(k.into()), + shell_escape::unix::escape(v.into()), + )?; + } } for path in ts.list_paths(&config).into_iter().rev() { writeln!(file, "PATH_add {}", path.to_string_lossy())?; diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 816069d70..e42e1ebdf 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,5 +1,5 @@ use std::cmp::max; -use std::env::join_paths; +use std::env::{join_paths, split_paths}; use std::ops::Deref; use std::path::PathBuf; @@ -41,11 +41,15 @@ impl HookEnv { .build(&mut config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); out.stdout.write(hook_env::clear_old_env(&*shell)); - let env = ts.env(&config); + let mut env = ts.env(&config); + let env_path = env.remove("PATH"); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); let mut paths = config.path_dirs.clone(); + if let Some(p) = env_path { + paths.extend(split_paths(&p).collect_vec()); + } paths.extend(ts.list_paths(&config)); // load the active runtime paths diff.path = paths.clone(); // update __RTX_DIFF with the new paths for the next run diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 2b48454f0..91a7ec00a 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -287,12 +287,15 @@ impl Toolset { } pub fn env_with_path(&self, config: &Config) -> BTreeMap { let mut env = self.env(config); - let path_env = self.path_env(config); + let mut path_env = self.path_env(config); + if let Some(path) = env.get("PATH") { + path_env = format!("{}:{}", path, path_env); + } env.insert("PATH".to_string(), path_env); env } pub fn env(&self, config: &Config) -> BTreeMap { - let mut entries: BTreeMap = self + let entries = self .list_current_installed_versions(config) .into_par_iter() .flat_map(|(p, tv)| match p.exec_env(config, self, &tv) { @@ -302,12 +305,21 @@ impl Toolset { Vec::new() } }) - .collect::>() + .collect::>(); + let add_paths = entries + .iter() + .filter(|(k, _)| k == "RTX_ADD_PATH") + .map(|(_, v)| v) + .join(":"); + let mut entries: BTreeMap = entries .into_iter() .filter(|(k, _)| k != "RTX_ADD_PATH") .filter(|(k, _)| !k.starts_with("RTX_TOOL_OPTS__")) .rev() .collect(); + if !add_paths.is_empty() { + entries.insert("PATH".to_string(), add_paths); + } entries.extend(config.env.clone()); entries } From ab4fd4b720c30df5a317f023396e52e9ac2f1d6c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 18:34:41 -0600 Subject: [PATCH 1155/1891] exec: auto install missing tools if passed as arguments (#1057) Fixes #1038 --- src/cli/exec.rs | 7 +--- .../rtx__cli__r#use__tests__use_global-2.snap | 7 ++++ .../rtx__cli__r#use__tests__use_global.snap | 5 ++- .../rtx__cli__r#use__tests__use_local-2.snap | 2 +- .../rtx__cli__r#use__tests__use_local-3.snap | 6 ++-- .../rtx__cli__r#use__tests__use_local-4.snap | 4 ++- .../rtx__cli__r#use__tests__use_local-5.snap | 6 ++++ .../rtx__cli__r#use__tests__use_local-6.snap | 7 ++++ .../rtx__cli__r#use__tests__use_local-7.snap | 6 ++++ .../rtx__cli__r#use__tests__use_local-8.snap | 5 +++ .../rtx__cli__r#use__tests__use_local.snap | 5 ++- ...use__tests__use_local_tool_versions-2.snap | 6 ++++ ...r#use__tests__use_local_tool_versions.snap | 4 +-- src/cli/use.rs | 34 ++++++++++++------- src/toolset/mod.rs | 32 +++++++++++++---- 15 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap create mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap diff --git a/src/cli/exec.rs b/src/cli/exec.rs index d8b9aaf0f..4740a2bc4 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -10,7 +10,6 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; #[cfg(test)] use crate::cmd; use crate::config::Config; -use crate::config::MissingRuntimeBehavior::Ignore; use crate::env; use crate::output::Output; use crate::toolset::ToolsetBuilder; @@ -52,11 +51,7 @@ impl Exec { .with_install_missing() .build(&mut config)?; let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); - let mut env = ts.env_with_path(&config); - if config.settings.missing_runtime_behavior != Ignore { - // prevent rtx from auto-installing inside a shim - env.insert("RTX_MISSING_RUNTIME_BEHAVIOR".into(), "warn".into()); - } + let env = ts.env_with_path(&config); self.exec(program, args, env) } diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap new file mode 100644 index 000000000..bce780220 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/use.rs +expression: "file::read_to_string(&cf_path).unwrap()" +--- +[tools] +tiny = "2" + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap index 4a5a476a6..29dbda768 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap @@ -1,7 +1,6 @@ --- source: src/cli/use.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: output --- -[tools] -tiny = "2" +rtx ~/config/config.toml tiny@2 diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap index 5e8a51890..bce780220 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap @@ -3,5 +3,5 @@ source: src/cli/use.rs expression: "file::read_to_string(&cf_path).unwrap()" --- [tools] -tiny = "2.1.0" +tiny = "2" diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap index 02d7e4645..ef0385cfc 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap @@ -1,6 +1,6 @@ --- source: src/cli/use.rs -expression: "file::read_to_string(&cf_path).unwrap()" +expression: output --- -[tools] -tiny = "2" +rtx ~/cwd/.test.rtx.toml tiny + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap index 9240e541e..5e8a51890 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap @@ -1,5 +1,7 @@ --- source: src/cli/use.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(&cf_path).unwrap()" --- +[tools] +tiny = "2.1.0" diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap new file mode 100644 index 000000000..c0e3bcfff --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/use.rs +expression: output +--- +rtx ~/cwd/.test.rtx.toml tiny@2 + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap new file mode 100644 index 000000000..bce780220 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/use.rs +expression: "file::read_to_string(&cf_path).unwrap()" +--- +[tools] +tiny = "2" + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap new file mode 100644 index 000000000..29374cd5d --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/use.rs +expression: output +--- +rtx ~/cwd/.test.rtx.toml + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap new file mode 100644 index 000000000..4cdc5be05 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/use.rs +expression: "file::read_to_string(&cf_path).unwrap()" +--- + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap index 4a5a476a6..c0e3bcfff 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap @@ -1,7 +1,6 @@ --- source: src/cli/use.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: output --- -[tools] -tiny = "2" +rtx ~/cwd/.test.rtx.toml tiny@2 diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap new file mode 100644 index 000000000..ee7715e8e --- /dev/null +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/use.rs +expression: "file::read_to_string(&cf_path).unwrap()" +--- +tiny 3 + diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap index 936e0a274..b3e5c4b4d 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap @@ -1,6 +1,6 @@ --- source: src/cli/use.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: output --- -tiny 3 +rtx ~/cwd/.test-tool-versions tiny@3 diff --git a/src/cli/use.rs b/src/cli/use.rs index 52887a401..a9df19a9b 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -1,14 +1,16 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; +use console::style; +use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::config::{config_file, Config, MissingRuntimeBehavior}; +use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; +use crate::file::display_path; use crate::output::Output; use crate::plugins::PluginName; use crate::toolset::ToolsetBuilder; -use crate::ui::multi_progress_report::MultiProgressReport; use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. @@ -51,15 +53,13 @@ pub struct Use { } impl Use { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let mut ts = ToolsetBuilder::new() .with_args(&self.tool) + .with_install_missing() .build(&mut config)?; ts.versions .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); - let mpr = MultiProgressReport::new(config.show_progress_bars()); - config.settings.missing_runtime_behavior = MissingRuntimeBehavior::AutoInstall; - ts.install_missing(&mut config, mpr)?; let path = match (self.global, self.path) { (true, _) => global_file(), @@ -93,6 +93,14 @@ impl Use { cf.remove_plugin(&plugin_name); } cf.save()?; + let tools = self.tool.iter().map(|t| t.to_string()).join(" "); + rtxprintln!( + out, + "{} {} {}", + style("rtx").dim(), + display_path(&path), + style(tools).cyan() + ); Ok(()) } } @@ -137,24 +145,24 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( mod tests { use insta::assert_snapshot; - use crate::{assert_cli, dirs, file}; + use crate::{assert_cli_snapshot, dirs, file}; #[test] fn test_use_local() { let cf_path = dirs::CURRENT.join(".test.rtx.toml"); file::write(&cf_path, "").unwrap(); - assert_cli!("use", "tiny@2"); + assert_cli_snapshot!("use", "tiny@2"); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); - assert_cli!("use", "--pin", "tiny"); + assert_cli_snapshot!("use", "--pin", "tiny"); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); - assert_cli!("use", "--fuzzy", "tiny@2"); + assert_cli_snapshot!("use", "--fuzzy", "tiny@2"); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); let p = cf_path.to_string_lossy().to_string(); - assert_cli!("use", "--rm", "tiny", "--path", &p); + assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); let _ = file::remove_file(&cf_path); @@ -165,7 +173,7 @@ mod tests { let cf_path = dirs::CURRENT.join(".test-tool-versions"); file::write(&cf_path, "").unwrap(); - assert_cli!("use", "tiny@3"); + assert_cli_snapshot!("use", "tiny@3"); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); } @@ -175,7 +183,7 @@ mod tests { let orig = file::read_to_string(&cf_path).unwrap(); let _ = file::remove_file(&cf_path); - assert_cli!("use", "-g", "tiny@2"); + assert_cli_snapshot!("use", "-g", "tiny@2"); assert_snapshot!(file::read_to_string(&cf_path).unwrap()); file::write(&cf_path, orig).unwrap(); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 91a7ec00a..41153844a 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -96,18 +96,33 @@ impl Toolset { if versions.is_empty() { return Ok(()); } - let display_versions = display_versions(&versions); - let plural_versions = if versions.len() == 1 { "" } else { "s" }; + let argument_versions = versions + .iter() + .filter(|tv| matches!(self.versions[&tv.plugin_name].source, ToolSource::Argument)) + .cloned() + .collect_vec(); let warn = || { - warn!( - "Tool{} not installed: {} (install with: rtx install)", - plural_versions, display_versions - ); + let versions = versions + .iter() + .filter(|tv| !matches!(self.versions[&tv.plugin_name].source, ToolSource::Argument)) + .cloned() + .collect_vec(); + if !versions.is_empty() { + let display_versions = display_versions(&versions); + let plural_versions = if versions.len() == 1 { "" } else { "s" }; + warn!( + "Tool{} not installed: {} (install with: rtx install)", + plural_versions, display_versions + ); + } }; match config.settings.missing_runtime_behavior { - MissingRuntimeBehavior::Ignore => {} + MissingRuntimeBehavior::Ignore => { + self.install_versions(config, argument_versions, &mpr, false)?; + } MissingRuntimeBehavior::Warn => { warn(); + self.install_versions(config, argument_versions, &mpr, false)?; } MissingRuntimeBehavior::Prompt => { let versions = prompt_for_versions(&versions)?; @@ -143,6 +158,9 @@ impl Toolset { mpr: &MultiProgressReport, force: bool, ) -> Result<()> { + if versions.is_empty() { + return Ok(()); + } self.latest_versions = true; let queue: Vec<_> = versions .into_iter() From b4f2a1d40d76473c9b98ed0df74ebbd9f69658dd Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 19:52:28 -0600 Subject: [PATCH 1156/1891] python: do not forcefully create venv (#1058) --- src/plugins/core/python.rs | 61 +++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 7aadb0c85..efe56487b 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -5,7 +5,7 @@ use color_eyre::eyre::{eyre, Result}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::file::create_dir_all; +use crate::file::{create_dir_all, display_path}; use crate::git::Git; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; @@ -111,12 +111,11 @@ impl PythonPlugin { virtualenv = project_root.join(virtualenv); } } - if !virtualenv.exists() || !self.check_venv_python(&virtualenv, tv)? { + if !virtualenv.exists() { info!("setting up virtualenv at: {}", virtualenv.display()); let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)) .arg("-m") .arg("venv") - .arg("--clear") .arg(&virtualenv) .envs(&config.env); if let Some(pr) = pr { @@ -124,17 +123,25 @@ impl PythonPlugin { } cmd.execute()?; } + self.check_venv_python(&virtualenv, tv)?; Ok(Some(virtualenv)) } else { Ok(None) } } - fn check_venv_python(&self, virtualenv: &Path, tv: &ToolVersion) -> Result { + fn check_venv_python(&self, virtualenv: &Path, tv: &ToolVersion) -> Result<()> { let symlink = virtualenv.join("bin/python"); let target = tv.install_path().join("bin/python"); let symlink_target = symlink.read_link().unwrap_or_default(); - Ok(symlink_target == target) + ensure!( + symlink_target == target, + "expected venv {} to point to {}.\nTry deleting the venv at {}.", + display_path(&symlink), + display_path(&target), + display_path(virtualenv) + ); + Ok(()) } fn test_python(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { @@ -199,38 +206,36 @@ impl Plugin for PythonPlugin { } cmd.execute()?; self.test_python(ctx.config, &ctx.tv, &ctx.pr)?; - self.get_virtualenv(ctx.config, &ctx.tv, Some(&ctx.pr))?; + if let Err(e) = self.get_virtualenv(ctx.config, &ctx.tv, Some(&ctx.pr)) { + warn!("failed to get virtualenv: {e}"); + } self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; Ok(()) } - fn list_bin_paths( - &self, - config: &Config, - _ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { - if let Some(virtualenv) = self.get_virtualenv(config, tv, None)? { - Ok(vec![virtualenv.join("bin"), tv.install_path().join("bin")]) - } else { - Ok(vec![tv.install_path().join("bin")]) - } - } - fn exec_env( &self, config: &Config, _ts: &Toolset, tv: &ToolVersion, ) -> Result> { - if let Some(virtualenv) = self.get_virtualenv(config, tv, None)? { - let hm = HashMap::from([( - "VIRTUAL_ENV".to_string(), - virtualenv.to_string_lossy().to_string(), - )]); - Ok(hm) - } else { - Ok(HashMap::new()) - } + let hm = match self.get_virtualenv(config, tv, None) { + Err(e) => { + warn!("failed to get virtualenv: {e}"); + HashMap::new() + } + Ok(Some(virtualenv)) => HashMap::from([ + ( + "VIRTUAL_ENV".to_string(), + virtualenv.to_string_lossy().to_string(), + ), + ( + "RTX_ADD_PATH".to_string(), + virtualenv.join("bin").to_string_lossy().to_string(), + ), + ]), + Ok(None) => HashMap::new(), + }; + Ok(hm) } } From 59a3b965070fe9b538d56b7114044ffe64e4c126 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 20:05:01 -0600 Subject: [PATCH 1157/1891] use fuzzy versions in bin paths (#1060) Fixes #1059 Fixes #877 --- e2e/test_use | 2 ++ src/plugins/core/deno.rs | 4 ++-- src/plugins/core/python.rs | 2 +- src/plugins/mod.rs | 2 +- src/toolset/tool_version.rs | 18 ++++++++++++++++++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/e2e/test_use b/e2e/test_use index eb9cf9f18..60936026a 100755 --- a/e2e/test_use +++ b/e2e/test_use @@ -7,3 +7,5 @@ rtx rm --all tiny rtx i tiny@1.0.0 rtx use tiny@1 assert "rtx current tiny" "1.0.0" +rtx use tiny@3 +assert "rtx current tiny" "3.1.0" diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index f1b5437ae..b7e9d817d 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -130,8 +130,8 @@ impl Plugin for DenoPlugin { tv: &ToolVersion, ) -> Result> { let bin_paths = vec![ - tv.install_path().join("bin"), - tv.install_path().join(".deno/bin"), + tv.install_short_path().join("bin"), + tv.install_short_path().join(".deno/bin"), ]; Ok(bin_paths) } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index efe56487b..a0a0d13e2 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -72,7 +72,7 @@ impl PythonPlugin { } fn python_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("bin/python") + tv.install_short_path().join("bin/python") } fn install_default_packages( diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index f66126182..29d84a165 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -92,7 +92,7 @@ pub trait Plugin: Debug + Send + Sync { _ts: &Toolset, tv: &ToolVersion, ) -> Result> { - Ok(vec![tv.install_path().join("bin")]) + Ok(vec![tv.install_short_path().join("bin")]) } fn exec_env( &self, diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index b1f5f1909..05e88a888 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -80,6 +80,18 @@ impl ToolVersion { }; dirs::INSTALLS.join(&self.plugin_name).join(pathname) } + pub fn install_short_path(&self) -> PathBuf { + let pathname = match &self.request { + ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), + _ => self.tv_short_pathname(), + }; + let sp = dirs::INSTALLS.join(&self.plugin_name).join(pathname); + if sp.exists() { + sp + } else { + self.install_path() + } + } pub fn cache_path(&self) -> PathBuf { dirs::CACHE.join(&self.plugin_name).join(self.tv_pathname()) } @@ -104,6 +116,12 @@ impl ToolVersion { ToolVersionRequest::System(_) => "system".to_string(), } } + fn tv_short_pathname(&self) -> String { + match &self.request { + ToolVersionRequest::Version(_, v) => v.to_string(), + _ => self.tv_pathname(), + } + } fn resolve_version( config: &Config, From 784f6cc1361c51565c30c6bb5b7bb6bf1d884711 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 20:06:22 -0600 Subject: [PATCH 1158/1891] chore: Release rtx-cli version 2023.12.4 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 662d51da7..a951ce3ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -491,9 +491,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ "powerfmt", ] @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.3" +version = "2023.12.4" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index d99b21a4a..4fc56148c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.3" +version = "2023.12.4" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 9a894f882..70967c813 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.3 +rtx 2023.12.4 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.3/rtx-v2023.12.3-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.4/rtx-v2023.12.4-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index e61a34d6e..3502f6c73 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.3"; + version = "2023.12.4"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 684eaba85..55a5604cb 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.3 +Version: 2023.12.4 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 5b2c9ec66de97e4a01f597040bfc4ef04bd2eb72 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 20:19:44 -0600 Subject: [PATCH 1159/1891] python: fix python path in venv --- src/plugins/core/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index a0a0d13e2..a277439a4 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -132,7 +132,7 @@ impl PythonPlugin { fn check_venv_python(&self, virtualenv: &Path, tv: &ToolVersion) -> Result<()> { let symlink = virtualenv.join("bin/python"); - let target = tv.install_path().join("bin/python"); + let target = self.python_path(tv); let symlink_target = symlink.read_link().unwrap_or_default(); ensure!( symlink_target == target, From 96d3ba0f81bc4c60893c34aa196a86d88bfdf81d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 2 Dec 2023 20:20:23 -0600 Subject: [PATCH 1160/1891] chore: Release rtx-cli version 2023.12.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a951ce3ee..29662377b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.4" +version = "2023.12.5" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 4fc56148c..1eda0e2dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.4" +version = "2023.12.5" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 70967c813..3fa26242a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.4 +rtx 2023.12.5 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.4/rtx-v2023.12.4-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.5/rtx-v2023.12.5-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 3502f6c73..7d6be8d0e 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.4"; + version = "2023.12.5"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 55a5604cb..afe49bb7c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.4 +Version: 2023.12.5 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From fdb15b732f0f9b853ac6c3498960b53cde5f9dcc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 10:58:25 -0600 Subject: [PATCH 1161/1891] refactor: rename dirs::ROOT to dirs::DATA See https://github.com/jdx/rtx/issues/977 --- src/cli/activate.rs | 2 +- src/cli/env.rs | 6 +++--- src/cli/implode.rs | 4 ++-- src/cli/where.rs | 4 ++-- src/config/config_file/mod.rs | 2 +- src/config/tracking.rs | 2 +- src/dirs.rs | 2 +- src/hook_env.rs | 4 ++-- src/migrate.rs | 8 ++++---- src/plugins/external_plugin_cache.rs | 4 ++-- src/plugins/script_manager.rs | 2 +- src/shims.rs | 2 +- src/tool.rs | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 974861b59..514fd889b 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -51,7 +51,7 @@ impl Activate { .expect("no shell provided, use `--shell=zsh`"); // touch ROOT to allow hook-env to run - let _ = touch_dir(&dirs::ROOT); + let _ = touch_dir(&dirs::DATA); let output = shell.activate(&RTX_EXE, self.status); out.stdout.write(output); diff --git a/src/cli/env.rs b/src/cli/env.rs index 1e9edcfcd..75a4f9227 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -80,7 +80,7 @@ mod tests { fn test_env() { let stdout = assert_cli!("env", "-s", "bash"); assert!(stdout.contains( - dirs::ROOT + dirs::DATA .join("installs/tiny/3.1.0/bin") .to_string_lossy() .as_ref() @@ -93,7 +93,7 @@ mod tests { let stdout = assert_cli!("env", "tiny@3.0", "-s", "bash"); assert!(stdout.contains( - dirs::ROOT + dirs::DATA .join("installs/tiny/3.0.1/bin") .to_string_lossy() .as_ref() @@ -106,7 +106,7 @@ mod tests { assert_cli!("install", "tiny@my/alias"); let stdout = assert_cli!("env", "tiny@my/alias", "-s", "bash"); assert!(stdout.contains( - dirs::ROOT + dirs::DATA .join("installs/tiny/3.0.1") .to_string_lossy() .as_ref() diff --git a/src/cli/implode.rs b/src/cli/implode.rs index aecf04a49..7e9e47506 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -25,7 +25,7 @@ pub struct Implode { impl Implode { pub fn run(self, config: Config, out: &mut Output) -> Result<()> { - let mut files = vec![&*dirs::ROOT, &*dirs::CACHE, &*env::RTX_EXE]; + let mut files = vec![&*dirs::DATA, &*dirs::CACHE, &*env::RTX_EXE]; if self.config { files.push(&*dirs::CONFIG); } @@ -67,7 +67,7 @@ mod tests { #[test] fn test_implode() { let stdout = assert_cli!("implode", "--config", "--dry-run"); - assert!(stdout.contains(format!("rm -rf {}", dirs::ROOT.display()).as_str())); + assert!(stdout.contains(format!("rm -rf {}", dirs::DATA.display()).as_str())); assert!(stdout.contains(format!("rm -rf {}", dirs::CACHE.display()).as_str())); assert!(stdout.contains(format!("rm -rf {}", dirs::CONFIG.display()).as_str())); } diff --git a/src/cli/where.rs b/src/cli/where.rs index 0cce6c4cc..6f0408cf7 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -97,7 +97,7 @@ mod tests { let stdout = assert_cli!("where", "tiny"); assert_str_eq!( stdout.trim(), - dirs::ROOT.join("installs/tiny/3.1.0").to_string_lossy() + dirs::DATA.join("installs/tiny/3.1.0").to_string_lossy() ); } @@ -114,7 +114,7 @@ mod tests { let stdout = assert_cli!("where", "tiny@my/alias"); assert_str_eq!( stdout.trim(), - dirs::ROOT.join("installs/tiny/3.0.1").to_string_lossy() + dirs::DATA.join("installs/tiny/3.0.1").to_string_lossy() ); assert_cli!("uninstall", "tiny@my/alias"); } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 37c707b40..2bd93577e 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -193,7 +193,7 @@ pub fn untrust(path: &Path) -> Result<()> { } fn trust_path(path: &Path) -> PathBuf { - dirs::ROOT.join("trusted-configs").join(hash_to_str(&path)) + dirs::DATA.join("trusted-configs").join(hash_to_str(&path)) } fn detect_config_file_type(path: &Path) -> Option { diff --git a/src/config/tracking.rs b/src/config/tracking.rs index 08e16e082..d7c98218c 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -18,7 +18,7 @@ pub struct Tracker { impl Tracker { pub fn new() -> Self { Self { - tracking_dir: dirs::ROOT.join("tracked-config-files"), + tracking_dir: dirs::DATA.join("tracked-config-files"), ..Default::default() } } diff --git a/src/dirs.rs b/src/dirs.rs index 7180e40bb..345ee7be2 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -6,7 +6,7 @@ use crate::env; pub static CURRENT: Lazy = Lazy::new(|| env::PWD.clone()); pub static HOME: Lazy = Lazy::new(|| env::HOME.clone()); -pub static ROOT: Lazy = Lazy::new(|| env::RTX_DATA_DIR.clone()); +pub static DATA: Lazy = Lazy::new(|| env::RTX_DATA_DIR.clone()); pub static CACHE: Lazy = Lazy::new(|| env::RTX_CACHE_DIR.clone()); pub static CONFIG: Lazy = Lazy::new(|| env::RTX_CONFIG_DIR.clone()); pub static PLUGINS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("plugins")); diff --git a/src/hook_env.rs b/src/hook_env.rs index ccc361128..2b846eb6c 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -123,8 +123,8 @@ pub fn build_watches(watch_files: &[PathBuf]) -> Result { pub fn get_watch_files(watch_files: &[PathBuf]) -> BTreeSet { let mut watches = BTreeSet::new(); - if dirs::ROOT.exists() { - watches.insert(dirs::ROOT.clone()); + if dirs::DATA.exists() { + watches.insert(dirs::DATA.clone()); } for cf in watch_files { watches.insert(cf.clone()); diff --git a/src/migrate.rs b/src/migrate.rs index 34ed6d4e2..7f36c0ae8 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -4,7 +4,7 @@ use std::path::Path; use eyre::Result; use rayon::Scope; -use crate::dirs::{CACHE, CONFIG, INSTALLS, PLUGINS, ROOT}; +use crate::dirs::{CACHE, CONFIG, DATA, INSTALLS, PLUGINS}; use crate::file; pub fn run() { @@ -55,8 +55,8 @@ fn rename_plugin(from: &str, to: &str) -> Result<()> { } fn migrate_tracked_configs() -> Result<()> { - let from = ROOT.join("tracked_config_files"); - let to = ROOT.join("tracked-config-files"); + let from = DATA.join("tracked_config_files"); + let to = DATA.join("tracked-config-files"); move_dirs(&from, &to)?; Ok(()) } @@ -64,7 +64,7 @@ fn migrate_tracked_configs() -> Result<()> { fn migrate_trusted_configs() -> Result<()> { let cache_trusted_configs = CACHE.join("trusted-configs"); let config_trusted_configs = CONFIG.join("trusted-configs"); - let root_trusted_configs = ROOT.join("trusted-configs"); + let root_trusted_configs = DATA.join("trusted-configs"); move_dirs(&cache_trusted_configs, &root_trusted_configs)?; move_dirs(&config_trusted_configs, &root_trusted_configs)?; Ok(()) diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index a8136f34d..6652c82a0 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -41,7 +41,7 @@ impl ExternalPluginCache { None => tv.cache_path().join("list_bin_paths.msgpack.z"), }; CacheManager::new(list_bin_paths_filename) - .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(dirs::DATA.clone()) .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(tv.install_path()) }); @@ -69,7 +69,7 @@ impl ExternalPluginCache { None => tv.cache_path().join("exec_env.msgpack.z"), }; CacheManager::new(exec_env_filename) - .with_fresh_file(dirs::ROOT.clone()) + .with_fresh_file(dirs::DATA.clone()) .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(tv.install_path()) }); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 9246a8421..1585f79dd 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -82,7 +82,7 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { "PATH" => get_path_with_fake_asdf(), "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy().to_string(), "RTX_CONCURRENCY" => num_cpus::get().to_string(), - "RTX_DATA_DIR" => dirs::ROOT.to_string_lossy().to_string(), + "RTX_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), "RTX_EXE" => env::RTX_EXE.to_string_lossy().to_string(), }) .into_iter() diff --git a/src/shims.rs b/src/shims.rs index b348cb1ff..426b6ed53 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -181,7 +181,7 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { export PATH="{fake_asdf_dir}:$PATH" rtx x -- {target} "$@" "#, - data_dir = dirs::ROOT.display(), + data_dir = dirs::DATA.display(), fake_asdf_dir = fake_asdf::setup()?.display(), target = target.display()}, )?; diff --git a/src/tool.rs b/src/tool.rs index 6e2e8a547..dfed80cfc 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -223,7 +223,7 @@ impl Tool { } self.cleanup_install_dirs(&ctx.config.settings, &ctx.tv); // attempt to touch all the .tool-version files to trigger updates in hook-env - let mut touch_dirs = vec![dirs::ROOT.to_path_buf()]; + let mut touch_dirs = vec![dirs::DATA.to_path_buf()]; touch_dirs.extend(ctx.config.config_files.keys().cloned()); for path in touch_dirs { let err = file::touch_dir(&path); From 67f2045ec82a76db53db6b5fa5b1bd4581f7d24c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 12:42:04 -0600 Subject: [PATCH 1162/1891] use: added `rtx use --env` option (#1068) --- README.md | 17 +++++++++-- completions/_rtx | 10 ++++--- completions/rtx.bash | 10 ++++++- completions/rtx.fish | 7 +++-- e2e/test_use | 5 ++-- src/cli/local.rs | 6 +--- src/cli/use.rs | 54 ++++++++++++++++++++++++----------- src/config/config_file/mod.rs | 14 +++++++-- src/config/mod.rs | 20 +++++++------ src/env.rs | 3 +- 10 files changed, 98 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 3fa26242a..d7c924a50 100644 --- a/README.md +++ b/README.md @@ -2633,11 +2633,13 @@ Arguments: Options: --pin Save exact version to config file - e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions + e.g.: `rtx use --pin node@20` will save 20.0.0 as the version + + [env: RTX_ASDF_COMPAT=] --fuzzy Save fuzzy version to config file - e.g.: `rtx use --fuzzy node@20` will save `node 20` to ~/.tool-versions + e.g.: `rtx use --fuzzy node@20` will save 20 as the version this is the default behavior unless RTX_ASDF_COMPAT=1 --remove @@ -2646,8 +2648,11 @@ Options: -g, --global Use the global config file (~/.config/rtx/config.toml) instead of the local one + -e, --env + [experimental] Modify an environment-specific config file like .rtx..toml + -p, --path - Specify a path to a config file or directory + Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions Examples: # set the current version of node to 20.x in .rtx.toml of current directory @@ -2657,6 +2662,12 @@ Examples: # set the current version of node to 20.x in ~/.config/rtx/config.toml # will write the precise version (e.g.: 20.0.0) $ rtx use -g --pin node@20 + + # sets .rtx.local.toml (which is intended not to be committed to a project) + $ rtx use --env local node@20 + + # sets .rtx.staging.toml (which is used if RTX_ENV=staging) + $ rtx use --env staging node@20 ``` ### `rtx version` diff --git a/completions/_rtx b/completions/_rtx index 0ab7e929e..ca0c8e3c5 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1656,17 +1656,19 @@ If not specified, all current tools will be upgraded:' \ (use) _arguments "${_arguments_options[@]}" \ '*--remove=[Remove the tool(s) from config file]:TOOL: ' \ -'-p+[Specify a path to a config file or directory]:PATH:_files' \ -'--path=[Specify a path to a config file or directory]:PATH:_files' \ +'-e+[\[experimental\] Modify an environment-specific config file like .rtx..toml]:ENV: ' \ +'--env=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:ENV: ' \ +'-p+[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:PATH:_files' \ +'--path=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:PATH:_files' \ '-j+[Number of plugins and runtimes to install in parallel \[default\: 4\]]: : ' \ '--jobs=[Number of plugins and runtimes to install in parallel \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pin[Save exact version to config file -e.g.\: \`rtx use --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ +e.g.\: \`rtx use --pin node@20\` will save 20.0.0 as the version]' \ '--fuzzy[Save fuzzy version to config file -e.g.\: \`rtx use --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions +e.g.\: \`rtx use --fuzzy node@20\` will save 20 as the version this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '-g[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ '--global[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 083bdb624..9f162e381 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3399,7 +3399,7 @@ _rtx() { return 0 ;; rtx__use) - opts="-g -p -j -r -y -v -h --pin --fuzzy --remove --global --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-g -e -p -j -r -y -v -h --pin --fuzzy --remove --global --env --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3409,6 +3409,14 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --env) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -e) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --path) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 1b9f3a53e..ec93df1d8 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -766,14 +766,15 @@ complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log l complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from use" -l remove -d 'Remove the tool(s) from config file' -r -complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file or directory' -r -F +complete -c rtx -n "__fish_seen_subcommand_from use" -s e -l env -d '[experimental] Modify an environment-specific config file like .rtx..toml' -r +complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' -r -F complete -c rtx -n "__fish_seen_subcommand_from use" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from use" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from use" -l pin -d 'Save exact version to config file -e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions' +e.g.: `rtx use --pin node@20` will save 20.0.0 as the version' complete -c rtx -n "__fish_seen_subcommand_from use" -l fuzzy -d 'Save fuzzy version to config file -e.g.: `rtx use --fuzzy node@20` will save `node 20` to ~/.tool-versions +e.g.: `rtx use --fuzzy node@20` will save 20 as the version this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' complete -c rtx -n "__fish_seen_subcommand_from use" -l debug -d 'Sets log level to debug' diff --git a/e2e/test_use b/e2e/test_use index 60936026a..3f19e6151 100755 --- a/e2e/test_use +++ b/e2e/test_use @@ -5,7 +5,6 @@ source "$(dirname "$0")/assert.sh" rtx rm --all tiny rtx i tiny@1.0.0 -rtx use tiny@1 +rtx use --env local tiny@1 assert "rtx current tiny" "1.0.0" -rtx use tiny@3 -assert "rtx current tiny" "3.1.0" +rm .rtx.local.toml diff --git a/src/cli/local.rs b/src/cli/local.rs index 5f44038e5..afd4a7953 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -104,11 +104,7 @@ pub fn local( fuzzy: bool, show_path: bool, ) -> Result<()> { - let is_trusted = config_file::is_trusted(&config.settings, path); - let mut cf = match path.exists() { - true => config_file::parse(path, is_trusted)?, - false => config_file::init(path, is_trusted), - }; + let mut cf = config_file::parse_or_init(&config.settings, path)?; if show_path { rtxprintln!(out, "{}", path.display()); return Ok(()); diff --git a/src/cli/use.rs b/src/cli/use.rs index a9df19a9b..1a06f8c39 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -5,6 +5,7 @@ use console::style; use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; +use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; @@ -29,12 +30,17 @@ pub struct Use { tool: Vec, /// Save exact version to config file - /// e.g.: `rtx use --pin node@20` will save `node 20.0.0` to ~/.tool-versions - #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] + /// e.g.: `rtx use --pin node@20` will save 20.0.0 as the version + #[clap( + long, + env = "RTX_ASDF_COMPAT", + verbatim_doc_comment, + overrides_with = "fuzzy" + )] pin: bool, /// Save fuzzy version to config file - /// e.g.: `rtx use --fuzzy node@20` will save `node 20` to ~/.tool-versions + /// e.g.: `rtx use --fuzzy node@20` will save 20 as the version /// this is the default behavior unless RTX_ASDF_COMPAT=1 #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, @@ -44,11 +50,16 @@ pub struct Use { remove: Option>, /// Use the global config file (~/.config/rtx/config.toml) instead of the local one - #[clap(short, long, overrides_with = "path")] + #[clap(short, long, overrides_with_all = &["path", "env"])] global: bool, + /// [experimental] Modify an environment-specific config file like .rtx..toml + #[clap(long, short, overrides_with_all = &["global", "path"])] + env: Option, + /// Specify a path to a config file or directory - #[clap(short, long, overrides_with = "global", value_hint = clap::ValueHint::FilePath)] + /// If a directory is specified, it will look for .rtx.toml (default) or .tool-versions + #[clap(short, long, overrides_with_all = &["global", "env"], value_hint = clap::ValueHint::FilePath)] path: Option, } @@ -61,17 +72,7 @@ impl Use { ts.versions .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); - let path = match (self.global, self.path) { - (true, _) => global_file(), - (false, Some(p)) => config_file_from_dir(&p), - (false, None) => config_file_from_dir(&dirs::CURRENT), - }; - let is_trusted = config_file::is_trusted(&config.settings, &path); - let mut cf = match path.exists() { - true => config_file::parse(&path, is_trusted)?, - false => config_file::init(&path, is_trusted), - }; - + let mut cf = self.get_config_file(&config)?; let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); for (plugin_name, tvl) in ts.versions { @@ -98,11 +99,24 @@ impl Use { out, "{} {} {}", style("rtx").dim(), - display_path(&path), + display_path(cf.get_path()), style(tools).cyan() ); Ok(()) } + + fn get_config_file(&self, config: &Config) -> Result> { + let path = if self.global { + global_file() + } else if let Some(env) = &self.env { + config_file_from_dir(&dirs::CURRENT.join(format!(".rtx.{}.toml", env))) + } else if let Some(p) = &self.path { + config_file_from_dir(p) + } else { + config_file_from_dir(&dirs::CURRENT) + }; + config_file::parse_or_init(&config.settings, &path) + } } fn global_file() -> PathBuf { @@ -138,6 +152,12 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( # set the current version of node to 20.x in ~/.config/rtx/config.toml # will write the precise version (e.g.: 20.0.0) $ rtx use -g --pin node@20 + + # sets .rtx.local.toml (which is intended not to be committed to a project) + $ rtx use --env local node@20 + + # sets .rtx.staging.toml (which is used if RTX_ENV=staging) + $ rtx use --env staging node@20 "# ); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 2bd93577e..7c6d1b6b6 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -140,7 +140,8 @@ impl dyn ConfigFile { } } -pub fn init(path: &Path, is_trusted: bool) -> Box { +fn init(settings: &Settings, path: &Path) -> Box { + let is_trusted = is_trusted(settings, path); match detect_config_file_type(path) { Some(ConfigFileType::RtxToml) => Box::new(RtxToml::init(path, is_trusted)), Some(ConfigFileType::ToolVersions) => Box::new(ToolVersions::init(path, is_trusted)), @@ -148,7 +149,16 @@ pub fn init(path: &Path, is_trusted: bool) -> Box { } } -pub fn parse(path: &Path, is_trusted: bool) -> Result> { +pub fn parse_or_init(settings: &Settings, path: &Path) -> Result> { + let cf = match path.exists() { + true => parse(settings, path)?, + false => init(settings, path), + }; + Ok(cf) +} + +pub fn parse(settings: &Settings, path: &Path) -> Result> { + let is_trusted = is_trusted(settings, path); match detect_config_file_type(path) { Some(ConfigFileType::RtxToml) => Ok(Box::new(RtxToml::from_file(path, is_trusted)?)), Some(ConfigFileType::ToolVersions) => { diff --git a/src/config/mod.rs b/src/config/mod.rs index 3db94cb2e..8023f5dcb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -96,6 +96,11 @@ impl Config { config_track.join().unwrap(); let (env, env_sources) = load_env(&config_files); + + if !settings.experimental && env::RTX_ENV.is_some() { + warn!("RTX_ENV is set but RTX_EXPERIMENTAL is not. Ignoring RTX_ENV."); + } + let config = Self { env, env_sources, @@ -217,13 +222,11 @@ impl Config { let config_files = tracker .list_all()? .into_par_iter() - .map(|path| { - match config_file::parse(&path, config_file::is_trusted(&self.settings, &path)) { - Ok(cf) => Some((path, cf)), - Err(err) => { - error!("Error loading config file: {:#}", err); - None - } + .map(|path| match config_file::parse(&self.settings, &path) { + Ok(cf) => Some((path, cf)), + Err(err) => { + error!("Error loading config file: {:#}", err); + None } }) .collect::>() @@ -416,7 +419,6 @@ fn parse_config_file( legacy_filenames: &BTreeMap>, tools: &ToolMap, ) -> Result> { - let is_trusted = config_file::is_trusted(settings, f); match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { Some(plugin) => { let tools = tools @@ -427,7 +429,7 @@ fn parse_config_file( LegacyVersionFile::parse(settings, f.into(), &tools) .map(|f| Box::new(f) as Box) } - None => config_file::parse(f, is_trusted), + None => config_file::parse(settings, f), } } diff --git a/src/env.rs b/src/env.rs index e931921e6..38216a22a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -39,7 +39,8 @@ pub static RTX_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy = Lazy::new(|| { }); pub static RTX_DEFAULT_CONFIG_FILENAME: Lazy = Lazy::new(|| var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into())); -pub static RTX_ENV: Lazy> = Lazy::new(|| var("RTX_ENV").ok()); +pub static RTX_ENV: Lazy> = + Lazy::new(|| var("RTX_ENV").or_else(|_| var("RTX_ENVIRONMENT")).ok()); pub static RTX_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("RTX_CONFIG_FILE")); pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); pub static RTX_EXE: Lazy = Lazy::new(|| current_exe().unwrap_or_else(|_| "rtx".into())); From f25ed6df1f0e5aed2ddb236c99e53816d344c448 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 13:46:18 -0600 Subject: [PATCH 1163/1891] refactor: automatically include indoc macros --- src/cli/deactivate.rs | 1 - src/cli/direnv/activate.rs | 1 - src/cli/doctor.rs | 1 - src/cli/mod.rs | 1 - src/cli/render_help.rs | 3 --- src/cli/shell.rs | 1 - src/config/config_file/rtx_toml.rs | 1 - src/config/config_file/tool_versions.rs | 1 - src/fake_asdf.rs | 1 - src/main.rs | 2 ++ src/plugins/core/java.rs | 1 - src/plugins/core/ruby.rs | 1 - src/plugins/rtx_plugin_toml.rs | 1 - src/shell/bash.rs | 2 -- src/shell/fish.rs | 2 -- src/shell/nushell.rs | 2 -- src/shell/xonsh.rs | 2 -- src/shell/zsh.rs | 2 -- src/shims.rs | 1 - src/test.rs | 2 -- 20 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index a138991ad..b0bdc9caf 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use indoc::formatdoc; use crate::config::Config; use crate::hook_env; diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index c33d8f613..621037843 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,5 +1,4 @@ use color_eyre::eyre::Result; -use indoc::indoc; use crate::config::Config; use crate::output::Output; diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index ba34a314f..c4228f486 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -4,7 +4,6 @@ use std::process::exit; use color_eyre::eyre::Result; use console::{pad_str, style, Alignment}; use indenter::indented; -use indoc::formatdoc; use crate::build_time::built_info; use crate::cli::version::VERSION; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6acfd17c9..1efd409a0 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,6 +1,5 @@ use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; -use indoc::indoc; use log::LevelFilter; use crate::config::Config; diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9876366a9..3394eb55e 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -1,7 +1,6 @@ use clap::builder::StyledStr; use color_eyre::eyre::Result; use console::strip_ansi_codes; -use indoc::formatdoc; use crate::cli::Cli; use crate::config::Config; @@ -107,8 +106,6 @@ fn remove_trailing_spaces(s: &str) -> String { mod tests { use std::fs; - use indoc::indoc; - use crate::{assert_cli, file}; #[test] diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 53a5b5817..41486d484 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use indoc::formatdoc; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 841008ac0..7dc4f079f 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -800,7 +800,6 @@ impl Debug for RtxToml { #[cfg(test)] mod tests { - use indoc::formatdoc; use insta::{assert_debug_snapshot, assert_display_snapshot, assert_snapshot}; use crate::dirs; diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index ac1ae4575..b8a75b77a 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -230,7 +230,6 @@ impl ConfigFile for ToolVersions { #[cfg(test)] pub(crate) mod tests { - use indoc::indoc; use insta::{assert_display_snapshot, assert_snapshot}; use pretty_assertions::assert_eq; diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 0c7f386ed..cea58af14 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -4,7 +4,6 @@ use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; use color_eyre::eyre::ErrReport; -use indoc::formatdoc; use once_cell::sync::OnceCell; use crate::{env, file}; diff --git a/src/main.rs b/src/main.rs index c18b21e55..858f77896 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,8 @@ extern crate core; extern crate log; #[macro_use] extern crate eyre; +#[macro_use] +extern crate indoc; use std::process::exit; diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 292262695..e81d6d68a 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -4,7 +4,6 @@ use std::fs::{self}; use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; -use indoc::formatdoc; use itertools::Itertools; use once_cell::sync::Lazy; use serde_derive::{Deserialize, Serialize}; diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 4cabc048a..3ddea4f37 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -421,7 +421,6 @@ fn parse_gemfile(body: &str) -> String { #[cfg(test)] mod tests { - use indoc::indoc; use super::*; diff --git a/src/plugins/rtx_plugin_toml.rs b/src/plugins/rtx_plugin_toml.rs index da1d5d30e..2d13df743 100644 --- a/src/plugins/rtx_plugin_toml.rs +++ b/src/plugins/rtx_plugin_toml.rs @@ -101,7 +101,6 @@ impl RtxPluginToml { #[cfg(test)] mod tests { - use indoc::formatdoc; use insta::assert_debug_snapshot; use crate::dirs; diff --git a/src/shell/bash.rs b/src/shell/bash.rs index c4f489f8e..674ea8385 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -1,7 +1,5 @@ use std::path::Path; -use indoc::formatdoc; - use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] diff --git a/src/shell/fish.rs b/src/shell/fish.rs index e9fa618a2..9c69acbd0 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -1,7 +1,5 @@ use std::path::Path; -use indoc::formatdoc; - use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 9b26875b8..c73ffc62d 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -1,7 +1,5 @@ use std::{fmt::Display, path::Path}; -use indoc::formatdoc; - use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 38cf0dfe5..52e8f371c 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -1,8 +1,6 @@ use std::borrow::Cow; use std::path::Path; -use indoc::formatdoc; - use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index c62ad431b..cd0b50ed2 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -1,7 +1,5 @@ use std::path::Path; -use indoc::formatdoc; - use crate::shell::bash::Bash; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; diff --git a/src/shims.rs b/src/shims.rs index 426b6ed53..1f723a2c8 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -6,7 +6,6 @@ use std::process::exit; use color_eyre::eyre::{eyre, Result}; use eyre::WrapErr; -use indoc::formatdoc; use itertools::Itertools; use rayon::prelude::*; diff --git a/src/test.rs b/src/test.rs index 030fe589d..61bfe31dd 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,8 +1,6 @@ use std::env::{join_paths, set_current_dir}; use std::path::PathBuf; -use indoc::indoc; - use crate::{env, file}; #[ctor::ctor] From 8533f0da259de17371c80400b5366cc283c1464a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:44:40 -0600 Subject: [PATCH 1164/1891] self-update: do not allow if /etc/rtx/.disable-self-update exists (#1069) --- .github/workflows/rtx.yml | 8 +- Cargo.toml | 3 +- README.md | 25 ++++-- completions/_rtx | 60 +++++++------- completions/rtx.bash | 6 +- completions/rtx.fish | 106 ++++++++++++------------ e2e/cd/test_bash | 1 + justfile | 4 +- packaging/homebrew/homebrew.rb | 9 +- scripts/build-deb.sh | 9 +- scripts/build-rpm.sh | 9 +- scripts/release.sh | 3 - scripts/render-homebrew.sh | 8 +- src/cli/completion.rs | 4 +- src/cli/mod.rs | 14 ++-- src/cli/render_help.rs | 8 +- src/cli/render_mangen.rs | 2 + src/cli/self_update.rs | 70 ++++++++++++---- src/cli/version.rs | 3 +- src/config/config_file/rtx_toml.rs | 1 + src/config/config_file/tool_versions.rs | 1 + 21 files changed, 215 insertions(+), 139 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 343445d84..7f2d22483 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -99,10 +99,7 @@ jobs: - run: scripts/setup-zipsign.sh env: ZIPSIGN: ${{ secrets.ZIPSIGN }} - - run: scripts/build-tarball.sh rtx --release --features openssl/vendored,self_update --target ${{matrix.target}} - env: - CROSS: "1" - - run: scripts/build-tarball.sh rtx-nonup --release --features openssl/vendored --target ${{matrix.target}} + - run: scripts/build-tarball.sh rtx --release --features openssl/vendored --target ${{matrix.target}} env: CROSS: "1" - uses: actions/upload-artifact@v3 @@ -134,8 +131,7 @@ jobs: - run: scripts/setup-zipsign.sh env: ZIPSIGN: ${{ secrets.ZIPSIGN }} - - run: scripts/build-tarball.sh rtx --release --features openssl/vendored,self_update --target ${{matrix.target}} - - run: scripts/build-tarball.sh rtx-nonup --release --features openssl/vendored --target ${{matrix.target}} + - run: scripts/build-tarball.sh rtx --release --features openssl/vendored --target ${{matrix.target}} - uses: actions/upload-artifact@v3 with: name: tarball-${{matrix.target}} diff --git a/Cargo.toml b/Cargo.toml index 1eda0e2dd..0c6c2d5fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,7 @@ reqwest = { version = "0.11.17", default-features = false, features = [ "gzip", ] } rmp-serde = "1.1.2" -self_update = { version = "<1", default-features = false, optional = true, features = [ +self_update = { version = "<1", default-features = false, features = [ "archive-tar", "compression-flate2", "signatures", @@ -114,7 +114,6 @@ pretty_assertions = "1.4" [features] default = ["native-tls"] -brew = [] native-tls = ["reqwest/native-tls"] rustls = ["reqwest/rustls-tls", "self_update/rustls"] rustls-native-roots = ["reqwest/rustls-tls-native-roots", "self_update/rustls"] diff --git a/README.md b/README.md index d7c924a50..682e96789 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ v20.0.0 - [`rtx plugins update [PLUGIN]...`](#rtx-plugins-update-plugin) - [`rtx prune [OPTIONS] [PLUGINS]...`](#rtx-prune-options-plugins) - [`rtx reshim`](#rtx-reshim) - - [`rtx self-update`](#rtx-self-update) + - [`rtx self-update [OPTIONS] [VERSION]`](#rtx-self-update-options-version) - [`rtx settings get `](#rtx-settings-get-key) - [`rtx settings ls`](#rtx-settings-ls) - [`rtx settings set `](#rtx-settings-set-key-value) @@ -2389,16 +2389,29 @@ Examples: v20.0.0 ``` -### `rtx self-update` +### `rtx self-update [OPTIONS] [VERSION]` ``` Updates rtx itself -Uses whatever package manager was used to install rtx or just downloads -a binary from GitHub Releases if rtx was installed manually. -Supports: standalone, brew, deb, rpm +Uses the GitHub Releases API to find the latest release and binary +By default, this will also update any installed plugins -Usage: self-update +Usage: self-update [OPTIONS] [VERSION] + +Arguments: + [VERSION] + Update to a specific version + +Options: + -f, --force + Update even if already up to date + + --no-plugins + Disable auto-updating plugins + + -y, --yes + Skip confirmation prompt ``` ### `rtx settings get ` diff --git a/completions/_rtx b/completions/_rtx index ca0c8e3c5..c4924d58b 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1258,28 +1258,6 @@ Sets --jobs=1]' \ '::version:' \ && ret=0 ;; -(self-update) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; (settings) _arguments "${_arguments_options[@]}" \ '-j+[Number of plugins and runtimes to install in parallel @@ -1815,6 +1793,32 @@ Sets --jobs=1]' \ '--help[Print help]' \ && ret=0 ;; +(self-update) +_arguments "${_arguments_options[@]}" \ +'-j+[Number of plugins and runtimes to install in parallel +\[default\: 4\]]: : ' \ +'--jobs=[Number of plugins and runtimes to install in parallel +\[default\: 4\]]: : ' \ +'--log-level=[Set the log output verbosity]:LEVEL: ' \ +'-f[Update even if already up to date]' \ +'--force[Update even if already up to date]' \ +'--no-plugins[Disable auto-updating plugins]' \ +'-y[Skip confirmation prompt]' \ +'--yes[Skip confirmation prompt]' \ +'--debug[Sets log level to debug]' \ +'--install-missing[Automatically install missing tools]' \ +'-r[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--raw[Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1]' \ +'--trace[Sets log level to trace]' \ +'*-v[Show installation output]' \ +'*--verbose[Show installation output]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'::version -- Update to a specific version:' \ +&& ret=0 +;; (help) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help_commands" \ @@ -2035,10 +2039,6 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; -(self-update) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; (settings) _arguments "${_arguments_options[@]}" \ ":: :_rtx__help__settings_commands" \ @@ -2135,6 +2135,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(self-update) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (help) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -2183,7 +2187,6 @@ _rtx_commands() { 'p:Manage plugins' \ 'prune:Delete unused versions of tools' \ 'reshim:rebuilds the shim farm' \ -'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ 'sync:Add tool versions from external tools to rtx' \ @@ -2197,6 +2200,7 @@ _rtx_commands() { 'which:Shows the path that a bin name points to' \ 'render-help:internal command to generate markdown from help' \ 'render-mangen:internal command to generate markdown from help' \ +'self-update:Updates rtx itself' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx commands' commands "$@" @@ -2551,7 +2555,6 @@ _rtx__help_commands() { 'plugins:Manage plugins' \ 'prune:Delete unused versions of tools' \ 'reshim:rebuilds the shim farm' \ -'self-update:Updates rtx itself' \ 'settings:Manage settings' \ 'shell:Sets a tool version for the current shell session' \ 'sync:Add tool versions from external tools to rtx' \ @@ -2564,6 +2567,7 @@ _rtx__help_commands() { 'which:Shows the path that a bin name points to' \ 'render-help:internal command to generate markdown from help' \ 'render-mangen:internal command to generate markdown from help' \ +'self-update:Updates rtx itself' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rtx help commands' commands "$@" diff --git a/completions/rtx.bash b/completions/rtx.bash index 9f162e381..c017e124e 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -553,7 +553,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -y -v -h -V --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help render-mangen help" + opts="-j -r -y -v -h -V --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1411,7 +1411,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-help render-mangen help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2921,7 +2921,7 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-f -y -j -r -v -h --force --no-plugins --yes --debug --install-missing --jobs --log-level --raw --trace --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index ec93df1d8..e7070e502 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -36,7 +36,6 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "outdated" -d 'Shows outdated t complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' complete -c rtx -n "__fish_use_subcommand" -f -a "sync" -d 'Add tool versions from external tools to rtx' @@ -49,6 +48,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the install complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "render-mangen" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -598,17 +598,6 @@ complete -c rtx -n "__fish_seen_subcommand_from reshim" -s y -l yes -d 'Answer y complete -c rtx -n "__fish_seen_subcommand_from reshim" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing -d 'Automatically install missing tools' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r @@ -844,46 +833,59 @@ complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s y -l yes -d 'A complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "render-mangen" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +[default: 4]' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s f -l force -d 'Update even if already up to date' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l no-plugins -d 'Disable auto-updating plugins' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s y -l yes -d 'Skip confirmation prompt' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing -d 'Automatically install missing tools' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-mangen" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index cc879bb8a..493169bd7 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -34,6 +34,7 @@ assert_path() { fi } +rtx i tiny@latest test "$(node -v)" = "v20.0.0" assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "cd" diff --git a/justfile b/justfile index 9ac16e036..6e8f07706 100644 --- a/justfile +++ b/justfile @@ -63,9 +63,7 @@ test-coverage: rtx implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then rtx trust - RTX_SELF_UPDATE_VERSION=1.0.0 rtx self-update <~/.rpmmacros diff --git a/scripts/release.sh b/scripts/release.sh index 4f421855f..2cf0630e1 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -67,6 +67,3 @@ AWS_S3_BUCKET=rtx.pub ./rtx/scripts/publish-s3.sh pushd homebrew-tap git add . && git commit -m "rtx ${RTX_VERSION#v}" popd - -# we don't want to include these in the github release, only S3 -rm -rf "$RELEASE_DIR/$RTX_VERSION/rtx-nonup"* diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index a33607f8b..11788fb92 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -3,9 +3,9 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=${RTX_VERSION#v*} \ - RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-nonup-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-nonup-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-nonup-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-nonup-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ cmd.run(config, out), Self::Prune(cmd) => cmd.run(config, out), Self::Reshim(cmd) => cmd.run(config, out), - #[cfg(feature = "self_update")] - Self::SelfUpdate(cmd) => cmd.run(config, out), Self::Settings(cmd) => cmd.run(config, out), Self::Shell(cmd) => cmd.run(config, out), Self::Sync(cmd) => cmd.run(config, out), @@ -164,7 +160,10 @@ impl Cli { } pub fn new_with_external_commands(config: &Config) -> Self { - let external_commands = external::commands(config); + let mut external_commands = external::commands(config); + if SelfUpdate::is_available() { + external_commands.push(SelfUpdate::command()); + } Self { command: Self::command().subcommands(external_commands.clone()), external_commands, @@ -228,6 +227,9 @@ impl Cli { config.settings.verbose = true; } if let Some((command, sub_m)) = matches.subcommand() { + if command == "self-update" { + return SelfUpdate::from_arg_matches(sub_m)?.run(config, out); + } external::execute(&config, command, sub_m, self.external_commands)?; } let cmd = Commands::from_arg_matches(&matches)?; diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 3394eb55e..be91195a6 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -1,7 +1,9 @@ use clap::builder::StyledStr; use color_eyre::eyre::Result; use console::strip_ansi_codes; +use itertools::Itertools; +use crate::cli::self_update::SelfUpdate; use crate::cli::Cli; use crate::config::Config; use crate::file; @@ -30,6 +32,7 @@ impl RenderHelp { fn render_commands() -> String { let mut cli = Cli::command() + .subcommand(SelfUpdate::command()) .term_width(80) .max_term_width(80) .disable_help_subcommand(true) @@ -42,7 +45,10 @@ fn render_commands() -> String { "# ); - for command in cli.get_subcommands_mut() { + for command in cli + .get_subcommands_mut() + .sorted_by_cached_key(|c| c.get_name().to_string()) + { match command.has_subcommands() { true => { let name = command.get_name().to_string(); diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 00dba45ed..7e1aa987a 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use eyre::Result; +use crate::cli::self_update::SelfUpdate; use crate::cli::{version, Cli}; use crate::config::Config; use crate::output::Output; @@ -16,6 +17,7 @@ pub struct RenderMangen {} impl RenderMangen { pub fn run(self, _config: Config, _out: &mut Output) -> Result<()> { let cli = Cli::command() + .subcommand(SelfUpdate::command()) .version(&*version::RAW_VERSION) .disable_colored_help(true); diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 19cb0235f..9074cb686 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -1,3 +1,4 @@ +use clap::Args; use color_eyre::Result; use console::style; use self_update::backends::github::{ReleaseList, Update}; @@ -6,22 +7,35 @@ use self_update::{cargo_crate_version, Status}; use crate::cli::version::{ARCH, OS}; use crate::config::Config; -use crate::env; use crate::output::Output; +use crate::{cmd, env}; /// Updates rtx itself /// -/// Uses whatever package manager was used to install rtx or just downloads -/// a binary from GitHub Releases if rtx was installed manually. -/// Supports: standalone, brew, deb, rpm -#[derive(Debug, clap::Args)] +/// Uses the GitHub Releases API to find the latest release and binary +/// By default, this will also update any installed plugins +#[derive(Debug, Default, clap::Args)] #[clap(verbatim_doc_comment)] -pub struct SelfUpdate {} +pub struct SelfUpdate { + /// Update even if already up to date + #[clap(long, short)] + force: bool, + + /// Disable auto-updating plugins + #[clap(long)] + no_plugins: bool, + + /// Skip confirmation prompt + #[clap(long, short)] + yes: bool, + + /// Update to a specific version + version: Option, +} impl SelfUpdate { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { - let latest = &self.fetch_releases()?[0].version; - let status = self.do_update(&config, latest)?; + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let status = self.do_update()?; if status.updated() { let version = style(status.version()).bright().yellow(); @@ -29,6 +43,9 @@ impl SelfUpdate { } else { rtxprintln!(out, "rtx is already up to date"); } + if !self.no_plugins { + cmd!(&*env::RTX_EXE, "plugins", "update").run()?; + } Ok(()) } @@ -46,27 +63,50 @@ impl SelfUpdate { Ok(releases) } - fn do_update(&self, config: &Config, latest: &str) -> Result { - let current_version = - env::var("RTX_SELF_UPDATE_VERSION").unwrap_or(cargo_crate_version!().to_string()); + fn latest_version(&self) -> Result { + let releases = self.fetch_releases()?; + Ok(releases[0].version.clone()) + } + + fn do_update(&self) -> Result { + let v = self + .version + .clone() + .map_or_else(|| self.latest_version(), Ok) + .map(|v| format!("v{}", v))?; let target = format!("{}-{}", *OS, *ARCH); let mut update = Update::configure(); if let Some(token) = &*env::GITHUB_API_TOKEN { update.auth_token(token); } + if self.force || self.version.is_some() { + update.target_version_tag(&v); + } let status = update .repo_owner("jdx") .repo_name("rtx") .bin_name("rtx") .verifying_keys([*include_bytes!("../../zipsign.pub")]) .show_download_progress(true) - .current_version(¤t_version) + .current_version(cargo_crate_version!()) .target(&target) .bin_path_in_archive("rtx/bin/rtx") - .identifier(&format!("rtx-v{latest}-{target}.tar.gz")) - .no_confirm(config.settings.yes) + .identifier(&format!("rtx-{v}-{target}.tar.gz")) + .no_confirm(self.yes) .build()? .update()?; Ok(status) } + + pub fn is_available() -> bool { + !env::RTX_EXE + .parent() + .and_then(|p| p.parent()) + .map(|p| p.join("etc").join(".disable-self-update").exists()) + .unwrap_or_default() + } + + pub fn command() -> clap::Command { + Self::augment_args(clap::Command::new("self-update")) + } } diff --git a/src/cli/version.rs b/src/cli/version.rs index dc89d430e..25258a579 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -7,6 +7,7 @@ use once_cell::sync::Lazy; use versions::Versioning; use crate::build_time::{built_info, BUILD_TIME}; +use crate::cli::self_update::SelfUpdate; use crate::config::Config; use crate::env::CI; use crate::file::modified_duration; @@ -70,7 +71,7 @@ fn show_latest() { } if let Some(latest) = check_for_new_version(duration::DAILY) { warn!("rtx version {} available", latest); - if cfg!(feature = "self_update") { + if SelfUpdate::is_available() { let cmd = style("rtx self-update").bright().yellow().for_stderr(); warn!("To update, run {}", cmd); } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 7dc4f079f..f8fb4f57a 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -61,6 +61,7 @@ impl RtxToml { let mut rf = Self::init(path, is_trusted); let body = file::read_to_string(path).suggestion("ensure file exists and can be read")?; rf.parse(&body)?; + trace!("{rf}"); Ok(rf) } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index b8a75b77a..95556ddb2 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -75,6 +75,7 @@ impl ToolVersions { cf.plugins = Self::parse_plugins(&s)?; cf.populate_toolset(); + trace!("{cf}"); Ok(cf) } From cb5c1ad0325c5e1b1194eb96f07633499d3095fb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 16:54:29 -0600 Subject: [PATCH 1165/1891] chore: Release rtx-cli version 2023.12.6 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29662377b..f7f06e073 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.5" +version = "2023.12.6" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 0c6c2d5fe..aecefceec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.5" +version = "2023.12.6" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 682e96789..c8c5afd88 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.5 +rtx 2023.12.6 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.5/rtx-v2023.12.5-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.6/rtx-v2023.12.6-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 7d6be8d0e..a3d706633 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.5"; + version = "2023.12.6"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index afe49bb7c..98fbf830e 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.5 +Version: 2023.12.6 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From da3f6eb79c14ddf5991109bfa42d0cb1df06a109 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 17:30:48 -0600 Subject: [PATCH 1166/1891] self-update: fixed searching for .disable-self-update --- src/cli/self_update.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 9074cb686..fe5735e3a 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -99,10 +99,11 @@ impl SelfUpdate { } pub fn is_available() -> bool { - !env::RTX_EXE - .parent() - .and_then(|p| p.parent()) - .map(|p| p.join("etc").join(".disable-self-update").exists()) + !std::fs::canonicalize(&*env::RTX_EXE) + .ok() + .and_then(|p| p.parent().map(|p| p.to_path_buf())) + .and_then(|p| p.parent().map(|p| p.to_path_buf())) + .map(|p| p.join("lib").join(".disable-self-update").exists()) .unwrap_or_default() } From e25605e7bc9da68db99a2919447d7f43d859d4dd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 17:31:39 -0600 Subject: [PATCH 1167/1891] homebrew: fixed formula --- packaging/homebrew/homebrew.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index 6eb954c5b..efe995e0a 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -28,9 +28,10 @@ class Rtx < Formula def install bin.install "bin/rtx" - lib.write ".disable-self-update" man1.install "man/man1/rtx.1" generate_completions_from_executable(bin/"rtx", "completion") + lib.mkpath + touch lib/".disable-self-update" end test do From d3b226343091246ca7894794247694752b18fd7e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 17:32:20 -0600 Subject: [PATCH 1168/1891] chore: Release rtx-cli version 2023.12.7 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7f06e073..e0d6e89b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,7 +1779,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.6" +version = "2023.12.7" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index aecefceec..0caa3eacd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.6" +version = "2023.12.7" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index c8c5afd88..fcaf72337 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.6 +rtx 2023.12.7 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.6/rtx-v2023.12.6-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.7/rtx-v2023.12.7-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index a3d706633..5145784f2 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.6"; + version = "2023.12.7"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 98fbf830e..c413661a9 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.6 +Version: 2023.12.7 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 6b41fdcb490c10dbe4943be768a667a969bc2cc6 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 20:05:40 -0600 Subject: [PATCH 1169/1891] remove --install-missing (#1071) This has long since been deprecated. See #1065 for more information --- completions/_rtx | 60 ---------------- completions/rtx.bash | 120 ++++++++++++++++---------------- completions/rtx.fish | 60 ---------------- e2e/cd/test_bash | 2 +- e2e/test_local | 3 +- e2e/test_zigmod | 2 +- src/cli/args/install_missing.rs | 14 ---- src/cli/args/mod.rs | 1 - src/cli/mod.rs | 5 -- 9 files changed, 63 insertions(+), 204 deletions(-) delete mode 100644 src/cli/args/install_missing.rs diff --git a/completions/_rtx b/completions/_rtx index c4924d58b..b8f114762 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -21,7 +21,6 @@ _rtx() { \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -57,7 +56,6 @@ _arguments "${_arguments_options[@]}" \ '-q[noop]' \ '--quiet[noop]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -82,7 +80,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -112,7 +109,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -138,7 +134,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -160,7 +155,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -185,7 +179,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -249,7 +242,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -272,7 +264,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -294,7 +285,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -324,7 +314,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -376,7 +365,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -399,7 +387,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -422,7 +409,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -444,7 +430,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -474,7 +459,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -496,7 +480,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -518,7 +501,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -576,7 +558,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -601,7 +582,6 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--json[Output in JSON format]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -626,7 +606,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -653,7 +632,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -683,7 +661,6 @@ e.g.\: \`rtx global --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -712,7 +689,6 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx\: @" message when changing directories]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -736,7 +712,6 @@ _arguments "${_arguments_options[@]}" \ '--config[Also remove config directory]' \ '--dry-run[List directories that would be removed without actually removing them]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -762,7 +737,6 @@ _arguments "${_arguments_options[@]}" \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -785,7 +759,6 @@ _arguments "${_arguments_options[@]}" \ '-i[Show latest installed instead of available version]' \ '--installed[Show latest installed instead of available version]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -811,7 +784,6 @@ _arguments "${_arguments_options[@]}" \ '-f[Overwrite an existing tool version if it exists]' \ '--force[Overwrite an existing tool version if it exists]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -845,7 +817,6 @@ e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to .tool-versions]' '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the config file]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -884,7 +855,6 @@ _arguments "${_arguments_options[@]}" \ '(-i --installed)-m[Display missing tool versions]' \ '(-i --installed)--missing[Display missing tool versions]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -907,7 +877,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -932,7 +901,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -966,7 +934,6 @@ Normally these are not shown]' \ '--urls[show the git url for each plugin]' \ '--refs[show the git refs for each plugin]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1006,7 +973,6 @@ i.e.\: they don'\''t need the full git repo url]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1033,7 +999,6 @@ _arguments "${_arguments_options[@]}" \ '-f[Overwrite existing plugin]' \ '--force[Overwrite existing plugin]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1073,7 +1038,6 @@ e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ '--refs[Show the git refs for each plugin e.g.\: main 1234abc]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1098,7 +1062,6 @@ _arguments "${_arguments_options[@]}" \ '--urls[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1122,7 +1085,6 @@ _arguments "${_arguments_options[@]}" \ '-p[Also remove the plugin'\''s installs, downloads, and cache]' \ '--purge[Also remove the plugin'\''s installs, downloads, and cache]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1147,7 +1109,6 @@ _arguments "${_arguments_options[@]}" \ '()-a[Update all plugins]' \ '()--all[Update all plugins]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1219,7 +1180,6 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--dry-run[Do not actually delete anything]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1242,7 +1202,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1266,7 +1225,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1296,7 +1254,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1319,7 +1276,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1341,7 +1297,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1365,7 +1320,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1430,7 +1384,6 @@ _arguments "${_arguments_options[@]}" \ '-u[Removes a previously set version]' \ '--unset[Removes a previously set version]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1453,7 +1406,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1486,7 +1438,6 @@ _arguments "${_arguments_options[@]}" \ '--nvm[Get tool versions from nvm]' \ '--nodenv[Get tool versions from nodenv]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1509,7 +1460,6 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pyenv[Get tool versions from pyenv]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1564,7 +1514,6 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--untrust[No longer trust this config]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1591,7 +1540,6 @@ _arguments "${_arguments_options[@]}" \ '-n[Do not actually delete anything]' \ '--dry-run[Do not actually delete anything]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1614,7 +1562,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1651,7 +1598,6 @@ this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '-g[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ '--global[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1676,7 +1622,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1698,7 +1643,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1734,7 +1678,6 @@ e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ '(--version)--plugin[Show the plugin name instead of the path]' \ '(--plugin)--version[Show the version instead of the path]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1757,7 +1700,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1779,7 +1721,6 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. @@ -1806,7 +1747,6 @@ _arguments "${_arguments_options[@]}" \ '-y[Skip confirmation prompt]' \ '--yes[Skip confirmation prompt]' \ '--debug[Sets log level to debug]' \ -'--install-missing[Automatically install missing tools]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. diff --git a/completions/rtx.bash b/completions/rtx.bash index c017e124e..f1e5124e6 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -553,7 +553,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -y -v -h -V --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" + opts="-j -r -y -v -h -V --debug --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -579,7 +579,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -j -r -y -v -h --shell --status --quiet --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help bash fish nu xonsh zsh" + opts="-s -q -j -r -y -v -h --shell --status --quiet --debug --jobs --log-level --raw --yes --trace --verbose --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -613,7 +613,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -r -y -v -h --plugin --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" + opts="-p -j -r -y -v -h --plugin --debug --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -647,7 +647,7 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -757,7 +757,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -j -r -y -v -h --plugin --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-p -j -r -y -v -h --plugin --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -791,7 +791,7 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -817,7 +817,7 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -843,7 +843,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ARGS]..." + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -869,7 +869,7 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -895,7 +895,7 @@ _rtx() { return 0 ;; rtx__cache) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help clear help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -921,7 +921,7 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -989,7 +989,7 @@ _rtx() { return 0 ;; rtx__completion) - opts="-s -j -r -y -v -h --shell --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help bash elvish fish powershell zsh" + opts="-s -j -r -y -v -h --shell --debug --jobs --log-level --raw --yes --trace --verbose --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1023,7 +1023,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1049,7 +1049,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1075,7 +1075,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help envrc exec activate help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1101,7 +1101,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1127,7 +1127,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1153,7 +1153,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1249,7 +1249,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1275,7 +1275,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -r -y -v -h --shell --json --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-s -j -r -y -v -h --shell --json --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1309,7 +1309,7 @@ _rtx() { return 0 ;; rtx__env__vars) - opts="-j -r -y -v -h --file --remove --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ENV_VARS]..." + opts="-j -r -y -v -h --file --remove --debug --jobs --log-level --raw --yes --trace --verbose --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1343,7 +1343,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -y -v -h --command --cd --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -j -r -y -v -h --command --cd --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1381,7 +1381,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -y -v -h --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -y -v -h --pin --fuzzy --remove --path --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2265,7 +2265,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -r -y -v -h --shell --status --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-s -j -r -y -v -h --shell --status --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2299,7 +2299,7 @@ _rtx() { return 0 ;; rtx__implode) - opts="-j -r -y -v -h --config --dry-run --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --config --dry-run --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2325,7 +2325,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-f -v -j -r -y -h --force --verbose --debug --install-missing --jobs --log-level --raw --yes --trace --help [TOOL@VERSION]..." + opts="-f -v -j -r -y -h --force --verbose --debug --jobs --log-level --raw --yes --trace --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2351,7 +2351,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-i -j -r -y -v -h --installed --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" + opts="-i -j -r -y -v -h --installed --debug --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2377,7 +2377,7 @@ _rtx() { return 0 ;; rtx__link) - opts="-f -j -r -y -v -h --force --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-f -j -r -y -v -h --force --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2403,7 +2403,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -y -v -h --parent --pin --fuzzy --remove --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-p -j -r -y -v -h --parent --pin --fuzzy --remove --path --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2433,7 +2433,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -m -j -r -y -v -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN_ARG]" + opts="-p -c -g -i -m -j -r -y -v -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2471,7 +2471,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PREFIX]" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2497,7 +2497,7 @@ _rtx() { return 0 ;; rtx__outdated) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2523,7 +2523,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help install link ls ls-remote uninstall update help" + opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --jobs --log-level --raw --yes --trace --verbose --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2661,7 +2661,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -r -y -h --force --all --verbose --debug --install-missing --jobs --log-level --raw --yes --trace --help [NAME] [GIT_URL] [REST]..." + opts="-f -a -v -j -r -y -h --force --all --verbose --debug --jobs --log-level --raw --yes --trace --help [NAME] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2687,7 +2687,7 @@ _rtx() { return 0 ;; rtx__plugins__link) - opts="-f -j -r -y -v -h --force --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PATH]" + opts="-f -j -r -y -v -h --force --debug --jobs --log-level --raw --yes --trace --verbose --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2713,7 +2713,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2739,7 +2739,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -r -y -v -h --urls --only-names --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-u -j -r -y -v -h --urls --only-names --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2765,7 +2765,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-p -j -r -y -v -h --purge --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." + opts="-p -j -r -y -v -h --purge --debug --jobs --log-level --raw --yes --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2791,7 +2791,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -j -r -y -v -h --all --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]..." + opts="-a -j -r -y -v -h --all --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2817,7 +2817,7 @@ _rtx() { return 0 ;; rtx__prune) - opts="-j -r -y -v -h --dry-run --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGINS]..." + opts="-j -r -y -v -h --dry-run --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGINS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2843,7 +2843,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2869,7 +2869,7 @@ _rtx() { return 0 ;; rtx__render__mangen) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2895,7 +2895,7 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN] [VERSION]" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2921,7 +2921,7 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-f -y -j -r -v -h --force --no-plugins --yes --debug --install-missing --jobs --log-level --raw --trace --verbose --help [VERSION]" + opts="-f -y -j -r -v -h --force --no-plugins --yes --debug --jobs --log-level --raw --trace --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2947,7 +2947,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2973,7 +2973,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3083,7 +3083,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3109,7 +3109,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3135,7 +3135,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3161,7 +3161,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -r -y -v -h --unset --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-u -j -r -y -v -h --unset --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3187,7 +3187,7 @@ _rtx() { return 0 ;; rtx__sync) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help node python help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3269,7 +3269,7 @@ _rtx() { return 0 ;; rtx__sync__node) - opts="-j -r -y -v -h --brew --nvm --nodenv --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --brew --nvm --nodenv --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3295,7 +3295,7 @@ _rtx() { return 0 ;; rtx__sync__python) - opts="-j -r -y -v -h --pyenv --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --pyenv --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3321,7 +3321,7 @@ _rtx() { return 0 ;; rtx__trust) - opts="-j -r -y -v -h --untrust --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [CONFIG_FILE]" + opts="-j -r -y -v -h --untrust --debug --jobs --log-level --raw --yes --trace --verbose --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3347,7 +3347,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-a -n -j -r -y -v -h --all --dry-run --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help ..." + opts="-a -n -j -r -y -v -h --all --dry-run --debug --jobs --log-level --raw --yes --trace --verbose --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3373,7 +3373,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3399,7 +3399,7 @@ _rtx() { return 0 ;; rtx__use) - opts="-g -e -p -j -r -y -v -h --pin --fuzzy --remove --global --env --path --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-g -e -p -j -r -y -v -h --pin --fuzzy --remove --global --env --path --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3445,7 +3445,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3471,7 +3471,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -r -y -v -h --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" + opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3497,7 +3497,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-t -j -r -y -v -h --plugin --version --tool --debug --install-missing --jobs --log-level --raw --yes --trace --verbose --help " + opts="-t -j -r -y -v -h --plugin --version --tool --debug --jobs --log-level --raw --yes --trace --verbose --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index e7070e502..9830d1689 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -2,7 +2,6 @@ complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins an [default: 4]' -r complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_use_subcommand" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_use_subcommand" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_use_subcommand" -s y -l yes -d 'Answer yes to all prompts' @@ -57,7 +56,6 @@ complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set t complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' complete -c rtx -n "__fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' @@ -69,7 +67,6 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subco [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' @@ -87,7 +84,6 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' @@ -99,7 +95,6 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' @@ -110,7 +105,6 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' @@ -121,7 +115,6 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' @@ -139,7 +132,6 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s y -l yes -d 'Answer yes to all prompts' @@ -150,7 +142,6 @@ complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Numb [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s y -l yes -d 'Answer yes to all prompts' @@ -161,7 +152,6 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subco [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' @@ -174,7 +164,6 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcomman [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s y -l yes -d 'Answer yes to all prompts' @@ -188,7 +177,6 @@ complete -c rtx -n "__fish_seen_subcommand_from completion" -s j -l jobs -d 'Num [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from completion" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from completion" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from completion" -s y -l yes -d 'Answer yes to all prompts' @@ -199,7 +187,6 @@ complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from current" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from current" -s y -l yes -d 'Answer yes to all prompts' @@ -210,7 +197,6 @@ complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Num [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s y -l yes -d 'Answer yes to all prompts' @@ -221,7 +207,6 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subc [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' @@ -238,7 +223,6 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s y -l yes -d 'Answer yes to all prompts' @@ -249,7 +233,6 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' @@ -260,7 +243,6 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' @@ -277,7 +259,6 @@ complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s y -l yes -d 'Answer yes to all prompts' @@ -290,7 +271,6 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l json -d 'Output in JSON format' complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env" -s y -l yes -d 'Answer yes to all prompts' @@ -303,7 +283,6 @@ complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s j -l jobs -d 'Numbe [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s y -l yes -d 'Answer yes to all prompts' @@ -316,7 +295,6 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from exec" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' @@ -334,7 +312,6 @@ e.g.: `rtx global --fuzzy node@20` will save `node 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' complete -c rtx -n "__fish_seen_subcommand_from global" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from global" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from global" -s y -l yes -d 'Answer yes to all prompts' @@ -347,7 +324,6 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Numbe complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s y -l yes -d 'Answer yes to all prompts' @@ -360,7 +336,6 @@ complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set th complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' complete -c rtx -n "__fish_seen_subcommand_from implode" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from implode" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from implode" -s y -l yes -d 'Answer yes to all prompts' @@ -373,7 +348,6 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set th complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' @@ -384,7 +358,6 @@ complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s i -l installed -d 'Show latest installed instead of available version' complete -c rtx -n "__fish_seen_subcommand_from latest" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from latest" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from latest" -s y -l yes -d 'Answer yes to all prompts' @@ -396,7 +369,6 @@ complete -c rtx -n "__fish_seen_subcommand_from link" -s j -l jobs -d 'Number of complete -c rtx -n "__fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from link" -s f -l force -d 'Overwrite an existing tool version if it exists' complete -c rtx -n "__fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from link" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' @@ -414,7 +386,6 @@ e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' complete -c rtx -n "__fish_seen_subcommand_from local" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from local" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from local" -s y -l yes -d 'Answer yes to all prompts' @@ -433,7 +404,6 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in a complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' complete -c rtx -n "__fish_seen_subcommand_from ls" -s m -l missing -d 'Display missing tool versions' complete -c rtx -n "__fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' @@ -444,7 +414,6 @@ complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Numb [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' @@ -455,7 +424,6 @@ complete -c rtx -n "__fish_seen_subcommand_from outdated" -s j -l jobs -d 'Numbe [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from outdated" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from outdated" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s y -l yes -d 'Answer yes to all prompts' @@ -471,7 +439,6 @@ Normally these are not shown' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l refs -d 'show the git refs for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' @@ -494,7 +461,6 @@ This will only install plugins that have matching shorthands. i.e.: they don\'t need the full git repo url' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' @@ -505,7 +471,6 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s f -l force -d 'Overwrite existing plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' @@ -524,7 +489,6 @@ e.g.: https://github.com/asdf-vm/asdf-node.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l refs -d 'Show the git refs for each plugin e.g.: main 1234abc' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' @@ -537,7 +501,6 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' @@ -549,7 +512,6 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s p -l purge -d 'Also remove the plugin\'s installs, downloads, and cache' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' @@ -561,7 +523,6 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s y -l yes -d 'Answer yes to all prompts' @@ -580,7 +541,6 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from prune" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from prune" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from prune" -s y -l yes -d 'Answer yes to all prompts' @@ -591,7 +551,6 @@ complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s y -l yes -d 'Answer yes to all prompts' @@ -602,7 +561,6 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' @@ -618,7 +576,6 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' @@ -629,7 +586,6 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' @@ -640,7 +596,6 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' @@ -651,7 +606,6 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' @@ -668,7 +622,6 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' complete -c rtx -n "__fish_seen_subcommand_from shell" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from shell" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from shell" -s y -l yes -d 'Answer yes to all prompts' @@ -679,7 +632,6 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcom [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' @@ -696,7 +648,6 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nvm -d 'Get tool versions from nvm' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nodenv -d 'Get tool versions from nodenv' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s y -l yes -d 'Answer yes to all prompts' @@ -708,7 +659,6 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l pyenv -d 'Get tool versions from pyenv' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s y -l yes -d 'Answer yes to all prompts' @@ -723,7 +673,6 @@ complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from trust" -l untrust -d 'No longer trust this config' complete -c rtx -n "__fish_seen_subcommand_from trust" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from trust" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from trust" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from trust" -s y -l yes -d 'Answer yes to all prompts' @@ -736,7 +685,6 @@ complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s a -l all -d 'Delete all installed versions' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s n -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' @@ -747,7 +695,6 @@ complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s j -l jobs -d 'Number [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s y -l yes -d 'Answer yes to all prompts' @@ -767,7 +714,6 @@ e.g.: `rtx use --fuzzy node@20` will save 20 as the version this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' complete -c rtx -n "__fish_seen_subcommand_from use" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from use" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from use" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from use" -s y -l yes -d 'Answer yes to all prompts' @@ -778,7 +724,6 @@ complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from version" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from version" -s y -l yes -d 'Answer yes to all prompts' @@ -789,7 +734,6 @@ complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number o [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from where" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from where" -s y -l yes -d 'Answer yes to all prompts' @@ -804,7 +748,6 @@ complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from which" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from which" -s y -l yes -d 'Answer yes to all prompts' @@ -815,7 +758,6 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Nu [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s y -l yes -d 'Answer yes to all prompts' @@ -826,7 +768,6 @@ complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s j -l jobs -d ' [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s y -l yes -d 'Answer yes to all prompts' @@ -840,7 +781,6 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -s f -l force -d 'U complete -c rtx -n "__fish_seen_subcommand_from self-update" -l no-plugins -d 'Disable auto-updating plugins' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s y -l yes -d 'Skip confirmation prompt' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l install-missing -d 'Automatically install missing tools' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets log level to trace' diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 493169bd7..5713a407f 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -7,6 +7,7 @@ orig_path="$PATH" rtx trust rtx trust ../.e2e.rtx.toml rtx trust 18/.e2e.rtx.toml +rtx i tiny@latest # shellcheck disable=SC1090 eval "$(rtx activate bash --status)" && _rtx_hook @@ -34,7 +35,6 @@ assert_path() { fi } -rtx i tiny@latest test "$(node -v)" = "v20.0.0" assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "cd" diff --git a/e2e/test_local b/e2e/test_local index 6a12641e4..c2d973ac1 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -60,7 +60,6 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then fi assert_raises "rtx uninstall shfmt@3.6.0" -assert_raises "rtx local shfmt --install-missing" rtx local shfmt@3.6.0 assert "rtx local" "#:schema ../../schema/rtx.json @@ -106,7 +105,7 @@ export RTX_DEFAULT_CONFIG_FILENAME=.MISSING assert_raises "rtx uninstall shfmt@3.6.0" -rtx local --install-missing +rtx local assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck sub-0.1:0.10.0 shfmt 3.6.0 # test comment diff --git a/e2e/test_zigmod b/e2e/test_zigmod index a86106671..20cbb1a2a 100755 --- a/e2e/test_zigmod +++ b/e2e/test_zigmod @@ -5,4 +5,4 @@ source "$(dirname "$0")/assert.sh" eval "$(rtx activate bash)" && eval "$(rtx hook-env)" rtx plugin install https://github.com/kachick/asdf-zigmod -rtx x --install-missing zigmod@latest -- zigmod version +rtx x zigmod@latest -- zigmod version diff --git a/src/cli/args/install_missing.rs b/src/cli/args/install_missing.rs deleted file mode 100644 index 4086fa60d..000000000 --- a/src/cli/args/install_missing.rs +++ /dev/null @@ -1,14 +0,0 @@ -use clap::{Arg, ArgAction}; - -pub struct InstallMissing(pub bool); - -impl InstallMissing { - pub fn arg() -> Arg { - Arg::new("install-missing") - .long("install-missing") - .help("Automatically install missing tools") - .action(ArgAction::SetTrue) - .hide(true) - .global(true) - } -} diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index cd279f31a..e06319fd0 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,5 +1,4 @@ pub mod env_var; -pub mod install_missing; pub mod jobs; pub mod log_level; pub mod raw; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index f1b9adb33..7b32bc2f8 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -4,7 +4,6 @@ use color_eyre::Result; use log::LevelFilter; use crate::config::Config; -use crate::config::MissingRuntimeBehavior::AutoInstall; use crate::output::Output; mod activate; @@ -181,7 +180,6 @@ impl Cli { .subcommand_required(true) .after_long_help(AFTER_LONG_HELP) .arg(args::log_level::Debug::arg()) - .arg(args::install_missing::InstallMissing::arg()) .arg(args::jobs::Jobs::arg()) .arg(args::log_level::LogLevel::arg()) .arg(args::raw::Raw::arg()) @@ -216,9 +214,6 @@ impl Cli { if let Some(true) = matches.get_one::("yes") { config.settings.yes = true; } - if let Some(true) = matches.get_one::("install-missing") { - config.settings.missing_runtime_behavior = AutoInstall; - } if *matches.get_one::("verbose").unwrap() > 0 { config.settings.verbose = true; } From 445cdbe9abb6752963f1538db82da0d7d40b42bb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 20:17:32 -0600 Subject: [PATCH 1170/1891] remove log_level from settings (#1072) this never actually worked anyways --- completions/_rtx | 348 +++++++++--------- completions/rtx.bash | 120 +++--- completions/rtx.fish | 234 ++++++------ schema/rtx.json | 11 - src/cli/mod.rs | 18 +- ...cli__settings__ls__tests__settings_ls.snap | 1 - ...i__settings__set__tests__settings_set.snap | 1 - src/cli/settings/unset.rs | 1 - src/config/config_file/rtx_toml.rs | 7 - src/config/settings.rs | 13 - 10 files changed, 355 insertions(+), 399 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index b8f114762..0ab07766f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -21,15 +21,15 @@ _rtx() { \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '-V[Print version]' \ @@ -56,15 +56,15 @@ _arguments "${_arguments_options[@]}" \ '-q[noop]' \ '--quiet[noop]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::shell_type -- Shell type to generate the script for:(bash fish nu xonsh zsh)' \ @@ -80,15 +80,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ ":: :_rtx__alias_commands" \ @@ -109,15 +109,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':plugin -- The plugin to show the alias for:' \ @@ -134,15 +134,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -155,15 +155,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':plugin -- The plugin to set the alias for:' \ @@ -179,15 +179,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':plugin -- The plugin to remove the alias from:' \ @@ -242,15 +242,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ '*::args -- all arguments:' \ @@ -264,15 +264,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -285,15 +285,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ":: :_rtx__cache_commands" \ @@ -314,15 +314,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -365,15 +365,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::shell -- Shell type to generate completions for:(bash elvish fish powershell zsh)' \ @@ -387,15 +387,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::plugin -- Plugin to show versions of e.g.\: ruby, node:' \ @@ -409,15 +409,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -430,15 +430,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ":: :_rtx__direnv_commands" \ @@ -459,15 +459,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -480,15 +480,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -501,15 +501,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -558,15 +558,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -582,15 +582,15 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--json[Output in JSON format]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to use:' \ @@ -606,15 +606,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::env_vars -- Environment variable(s) to set @@ -632,15 +632,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to start e.g.\: node@20 python@3.10:' \ @@ -661,15 +661,15 @@ e.g.\: \`rtx global --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the global config file]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to add to .tool-versions @@ -689,15 +689,15 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--status[Show "rtx\: @" message when changing directories]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -712,15 +712,15 @@ _arguments "${_arguments_options[@]}" \ '--config[Also remove config directory]' \ '--dry-run[List directories that would be removed without actually removing them]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -737,13 +737,13 @@ _arguments "${_arguments_options[@]}" \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '-y[Answer yes to all prompts]' \ '--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to install e.g.\: node@20:' \ @@ -759,15 +759,15 @@ _arguments "${_arguments_options[@]}" \ '-i[Show latest installed instead of available version]' \ '--installed[Show latest installed instead of available version]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':tool -- Tool to get the latest version of:' \ @@ -784,15 +784,15 @@ _arguments "${_arguments_options[@]}" \ '-f[Overwrite an existing tool version if it exists]' \ '--force[Overwrite an existing tool version if it exists]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':tool -- Tool name and version to create a symlink for:' \ @@ -817,15 +817,15 @@ e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to .tool-versions]' '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '--path[Get the path of the config file]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to add to .tool-versions/.rtx.toml @@ -855,15 +855,15 @@ _arguments "${_arguments_options[@]}" \ '(-i --installed)-m[Display missing tool versions]' \ '(-i --installed)--missing[Display missing tool versions]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::plugin_arg:' \ @@ -877,15 +877,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':plugin -- Plugin to get versions for:' \ @@ -901,15 +901,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to show outdated versions for @@ -934,15 +934,15 @@ Normally these are not shown]' \ '--urls[show the git url for each plugin]' \ '--refs[show the git refs for each plugin]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ":: :_rtx__plugins_commands" \ @@ -973,13 +973,13 @@ i.e.\: they don'\''t need the full git repo url]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '-y[Answer yes to all prompts]' \ '--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::name -- The name of the plugin to install @@ -999,15 +999,15 @@ _arguments "${_arguments_options[@]}" \ '-f[Overwrite existing plugin]' \ '--force[Overwrite existing plugin]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':name -- The name of the plugin @@ -1038,15 +1038,15 @@ e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ '--refs[Show the git refs for each plugin e.g.\: main 1234abc]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -1062,15 +1062,15 @@ _arguments "${_arguments_options[@]}" \ '--urls[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -1085,15 +1085,15 @@ _arguments "${_arguments_options[@]}" \ '-p[Also remove the plugin'\''s installs, downloads, and cache]' \ '--purge[Also remove the plugin'\''s installs, downloads, and cache]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::plugin -- Plugin(s) to remove:' \ @@ -1109,15 +1109,15 @@ _arguments "${_arguments_options[@]}" \ '()-a[Update all plugins]' \ '()--all[Update all plugins]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::plugin -- Plugin(s) to update:' \ @@ -1180,15 +1180,15 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--dry-run[Do not actually delete anything]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::plugins -- Prune only versions from these plugins:' \ @@ -1202,15 +1202,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::plugin:' \ @@ -1225,15 +1225,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ ":: :_rtx__settings_commands" \ @@ -1254,15 +1254,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':key -- The setting to show:' \ @@ -1276,15 +1276,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -1297,15 +1297,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':key -- The setting to set:' \ @@ -1320,15 +1320,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':key -- The setting to remove:' \ @@ -1384,15 +1384,15 @@ _arguments "${_arguments_options[@]}" \ '-u[Removes a previously set version]' \ '--unset[Removes a previously set version]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to use:' \ @@ -1406,15 +1406,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ ":: :_rtx__sync_commands" \ @@ -1438,15 +1438,15 @@ _arguments "${_arguments_options[@]}" \ '--nvm[Get tool versions from nvm]' \ '--nodenv[Get tool versions from nodenv]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -1460,15 +1460,15 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--pyenv[Get tool versions from pyenv]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ && ret=0 @@ -1514,15 +1514,15 @@ _arguments "${_arguments_options[@]}" \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--untrust[No longer trust this config]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '::config_file -- The config file to trust:_files' \ @@ -1540,15 +1540,15 @@ _arguments "${_arguments_options[@]}" \ '-n[Do not actually delete anything]' \ '--dry-run[Do not actually delete anything]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to remove:' \ @@ -1562,15 +1562,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ '*::tool -- Tool(s) to upgrade @@ -1598,15 +1598,15 @@ this is the default behavior unless RTX_ASDF_COMPAT=1]' \ '-g[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ '--global[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ '*::tool -- Tool(s) to add to config file @@ -1622,15 +1622,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -1643,15 +1643,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':tool -- Tool(s) to look up @@ -1678,15 +1678,15 @@ e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ '(--version)--plugin[Show the plugin name instead of the path]' \ '(--plugin)--version[Show the version instead of the path]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ ':bin_name -- The bin name to look up:' \ @@ -1700,15 +1700,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -1721,15 +1721,15 @@ _arguments "${_arguments_options[@]}" \ \[default\: 4\]]: : ' \ '--log-level=[Set the log output verbosity]:LEVEL: ' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ +'-y[Answer yes to all prompts]' \ +'--yes[Answer yes to all prompts]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 @@ -1747,11 +1747,11 @@ _arguments "${_arguments_options[@]}" \ '-y[Skip confirmation prompt]' \ '--yes[Skip confirmation prompt]' \ '--debug[Sets log level to debug]' \ +'--trace[Sets log level to trace]' \ '-r[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ '--raw[Directly pipe stdin/stdout/stderr to user. Sets --jobs=1]' \ -'--trace[Sets log level to trace]' \ '*-v[Show installation output]' \ '*--verbose[Show installation output]' \ '-h[Print help (see more with '\''--help'\'')]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index f1e5124e6..6e8c7f5ab 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -553,7 +553,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -y -v -h -V --debug --jobs --log-level --raw --yes --trace --verbose --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" + opts="-j -r -v -y -h -V --jobs --debug --log-level --trace --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -579,7 +579,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -j -r -y -v -h --shell --status --quiet --debug --jobs --log-level --raw --yes --trace --verbose --help bash fish nu xonsh zsh" + opts="-s -q -j -r -v -y -h --shell --status --quiet --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -613,7 +613,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -r -y -v -h --plugin --debug --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" + opts="-p -j -r -v -y -h --plugin --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -647,7 +647,7 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -757,7 +757,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -j -r -y -v -h --plugin --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-p -j -r -v -y -h --plugin --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -791,7 +791,7 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -817,7 +817,7 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -843,7 +843,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [ARGS]..." + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -869,7 +869,7 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -895,7 +895,7 @@ _rtx() { return 0 ;; rtx__cache) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help clear help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -921,7 +921,7 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -989,7 +989,7 @@ _rtx() { return 0 ;; rtx__completion) - opts="-s -j -r -y -v -h --shell --debug --jobs --log-level --raw --yes --trace --verbose --help bash elvish fish powershell zsh" + opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1023,7 +1023,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1049,7 +1049,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1075,7 +1075,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help envrc exec activate help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1101,7 +1101,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1127,7 +1127,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1153,7 +1153,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1249,7 +1249,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1275,7 +1275,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -r -y -v -h --shell --json --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-s -j -r -v -y -h --shell --json --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1309,7 +1309,7 @@ _rtx() { return 0 ;; rtx__env__vars) - opts="-j -r -y -v -h --file --remove --debug --jobs --log-level --raw --yes --trace --verbose --help [ENV_VARS]..." + opts="-j -r -v -y -h --file --remove --jobs --debug --log-level --trace --raw --verbose --yes --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1343,7 +1343,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -y -v -h --command --cd --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -j -r -v -y -h --command --cd --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1381,7 +1381,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -y -v -h --pin --fuzzy --remove --path --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -v -y -h --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2265,7 +2265,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -r -y -v -h --shell --status --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-s -j -r -v -y -h --shell --status --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2299,7 +2299,7 @@ _rtx() { return 0 ;; rtx__implode) - opts="-j -r -y -v -h --config --dry-run --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2325,7 +2325,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-f -v -j -r -y -h --force --verbose --debug --jobs --log-level --raw --yes --trace --help [TOOL@VERSION]..." + opts="-f -v -j -r -y -h --force --verbose --jobs --debug --log-level --trace --raw --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2351,7 +2351,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-i -j -r -y -v -h --installed --debug --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" + opts="-i -j -r -v -y -h --installed --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2377,7 +2377,7 @@ _rtx() { return 0 ;; rtx__link) - opts="-f -j -r -y -v -h --force --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2403,7 +2403,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -y -v -h --parent --pin --fuzzy --remove --path --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-p -j -r -v -y -h --parent --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2433,7 +2433,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -m -j -r -y -v -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN_ARG]" + opts="-p -c -g -i -m -j -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN_ARG]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2471,7 +2471,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [PREFIX]" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2497,7 +2497,7 @@ _rtx() { return 0 ;; rtx__outdated) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2523,7 +2523,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --jobs --log-level --raw --yes --trace --verbose --help install link ls ls-remote uninstall update help" + opts="-a -c -u -j -r -v -y -h --all --core --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2661,7 +2661,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -r -y -h --force --all --verbose --debug --jobs --log-level --raw --yes --trace --help [NAME] [GIT_URL] [REST]..." + opts="-f -a -v -j -r -y -h --force --all --verbose --jobs --debug --log-level --trace --raw --yes --help [NAME] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2687,7 +2687,7 @@ _rtx() { return 0 ;; rtx__plugins__link) - opts="-f -j -r -y -v -h --force --debug --jobs --log-level --raw --yes --trace --verbose --help [PATH]" + opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2713,7 +2713,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -j -r -y -v -h --all --core --urls --refs --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-a -c -u -j -r -v -y -h --all --core --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2739,7 +2739,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -r -y -v -h --urls --only-names --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-u -j -r -v -y -h --urls --only-names --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2765,7 +2765,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-p -j -r -y -v -h --purge --debug --jobs --log-level --raw --yes --trace --verbose --help ..." + opts="-p -j -r -v -y -h --purge --jobs --debug --log-level --trace --raw --verbose --yes --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2791,7 +2791,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -j -r -y -v -h --all --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN]..." + opts="-a -j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2817,7 +2817,7 @@ _rtx() { return 0 ;; rtx__prune) - opts="-j -r -y -v -h --dry-run --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGINS]..." + opts="-j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGINS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2843,7 +2843,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2869,7 +2869,7 @@ _rtx() { return 0 ;; rtx__render__mangen) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2895,7 +2895,7 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [PLUGIN] [VERSION]" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2921,7 +2921,7 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-f -y -j -r -v -h --force --no-plugins --yes --debug --jobs --log-level --raw --trace --verbose --help [VERSION]" + opts="-f -y -j -r -v -h --force --no-plugins --yes --jobs --debug --log-level --trace --raw --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2947,7 +2947,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help get ls set unset help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2973,7 +2973,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3083,7 +3083,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3109,7 +3109,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3135,7 +3135,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3161,7 +3161,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -r -y -v -h --unset --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-u -j -r -v -y -h --unset --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3187,7 +3187,7 @@ _rtx() { return 0 ;; rtx__sync) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help node python help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3269,7 +3269,7 @@ _rtx() { return 0 ;; rtx__sync__node) - opts="-j -r -y -v -h --brew --nvm --nodenv --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --brew --nvm --nodenv --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3295,7 +3295,7 @@ _rtx() { return 0 ;; rtx__sync__python) - opts="-j -r -y -v -h --pyenv --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --pyenv --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3321,7 +3321,7 @@ _rtx() { return 0 ;; rtx__trust) - opts="-j -r -y -v -h --untrust --debug --jobs --log-level --raw --yes --trace --verbose --help [CONFIG_FILE]" + opts="-j -r -v -y -h --untrust --jobs --debug --log-level --trace --raw --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3347,7 +3347,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-a -n -j -r -y -v -h --all --dry-run --debug --jobs --log-level --raw --yes --trace --verbose --help ..." + opts="-a -n -j -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3373,7 +3373,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3399,7 +3399,7 @@ _rtx() { return 0 ;; rtx__use) - opts="-g -e -p -j -r -y -v -h --pin --fuzzy --remove --global --env --path --debug --jobs --log-level --raw --yes --trace --verbose --help [TOOL@VERSION]..." + opts="-g -e -p -j -r -v -y -h --pin --fuzzy --remove --global --env --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3445,7 +3445,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3471,7 +3471,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -r -y -v -h --debug --jobs --log-level --raw --yes --trace --verbose --help [ASDF_VERSION]" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3497,7 +3497,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-t -j -r -y -v -h --plugin --version --tool --debug --jobs --log-level --raw --yes --trace --verbose --help " + opts="-t -j -r -v -y -h --plugin --version --tool --jobs --debug --log-level --trace --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 9830d1689..36f69dc0a 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -2,11 +2,11 @@ complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins an [default: 4]' -r complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_use_subcommand" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_use_subcommand" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_use_subcommand" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_use_subcommand" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_use_subcommand" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Initializes rtx in the current shell' @@ -56,22 +56,22 @@ complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set t complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' complete -c rtx -n "__fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -84,42 +84,42 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases @@ -132,31 +132,31 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from asdf" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from asdf" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from asdf" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' @@ -164,11 +164,11 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcomman [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' @@ -177,41 +177,41 @@ complete -c rtx -n "__fish_seen_subcommand_from completion" -s j -l jobs -d 'Num [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from completion" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from completion" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from completion" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from completion" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from completion" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from completion" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from current" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from current" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from current" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from current" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from current" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file for direnv to consume.' @@ -223,31 +223,31 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file for direnv to consume.' @@ -259,11 +259,11 @@ complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from doctor" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from doctor" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from doctor" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -271,11 +271,11 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l json -d 'Output in JSON format' complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from env" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from env" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l file -d 'The TOML file to update' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l remove -d 'Remove the environment variable from config file' -r @@ -283,11 +283,11 @@ complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s j -l jobs -d 'Numbe [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r -f -a "(__fish_complete_command)" complete -c rtx -n "__fish_seen_subcommand_from exec" -l cd -d 'Change to this directory before executing the command' -r -f -a "(__fish_complete_directories)" @@ -295,11 +295,11 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -312,11 +312,11 @@ e.g.: `rtx global --fuzzy node@20` will save `node 20` to ~/.tool-versions this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' complete -c rtx -n "__fish_seen_subcommand_from global" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from global" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from global" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from global" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from global" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -324,11 +324,11 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Numbe complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -336,11 +336,11 @@ complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set th complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' complete -c rtx -n "__fish_seen_subcommand_from implode" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from implode" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -348,32 +348,32 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set th complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from latest" -s i -l installed -d 'Show latest installed instead of available version' complete -c rtx -n "__fish_seen_subcommand_from latest" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from latest" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from latest" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from latest" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from latest" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from link" -s f -l force -d 'Overwrite an existing tool version if it exists' complete -c rtx -n "__fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel @@ -386,11 +386,11 @@ e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions' complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' complete -c rtx -n "__fish_seen_subcommand_from local" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from local" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from local" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from local" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from local" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show tool versions from [PLUGIN]' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l prefix -d 'Display versions matching this prefix' -r @@ -404,31 +404,31 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in a complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' complete -c rtx -n "__fish_seen_subcommand_from ls" -s m -l missing -d 'Display missing tool versions' complete -c rtx -n "__fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from outdated" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from outdated" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from outdated" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -439,11 +439,11 @@ Normally these are not shown' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l refs -d 'show the git refs for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a plugin into rtx' @@ -461,21 +461,21 @@ This will only install plugins that have matching shorthands. i.e.: they don\'t need the full git repo url' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s f -l force -d 'Overwrite existing plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -489,11 +489,11 @@ e.g.: https://github.com/asdf-vm/asdf-node.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l refs -d 'Show the git refs for each plugin e.g.: main 1234abc' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -501,33 +501,33 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s p -l purge -d 'Also remove the plugin\'s installs, downloads, and cache' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a plugin into rtx' @@ -541,31 +541,31 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from prune" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from prune" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from prune" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from prune" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from prune" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from prune" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from reshim" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from reshim" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from reshim" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' @@ -576,41 +576,41 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' @@ -622,21 +622,21 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' complete -c rtx -n "__fish_seen_subcommand_from shell" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from shell" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from shell" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' @@ -648,22 +648,22 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nvm -d 'Get tool versions from nvm' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nodenv -d 'Get tool versions from nodenv' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l pyenv -d 'Get tool versions from pyenv' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' @@ -673,11 +673,11 @@ complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number o complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from trust" -l untrust -d 'No longer trust this config' complete -c rtx -n "__fish_seen_subcommand_from trust" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from trust" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from trust" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from trust" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from trust" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from trust" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from trust" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from trust" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -685,21 +685,21 @@ complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s a -l all -d 'Delete all installed versions' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s n -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from use" -l remove -d 'Remove the tool(s) from config file' -r complete -c rtx -n "__fish_seen_subcommand_from use" -s e -l env -d '[experimental] Modify an environment-specific config file like .rtx..toml' -r @@ -714,31 +714,31 @@ e.g.: `rtx use --fuzzy node@20` will save 20 as the version this is the default behavior unless RTX_ASDF_COMPAT=1' complete -c rtx -n "__fish_seen_subcommand_from use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' complete -c rtx -n "__fish_seen_subcommand_from use" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from use" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from use" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from use" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from use" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from use" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from use" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from use" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from version" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from version" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from version" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from version" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from version" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from where" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from where" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from where" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from where" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from where" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from which" -s t -l tool -d 'Use a specific tool@version e.g.: `rtx which npm --tool=node@20`' -r @@ -748,31 +748,31 @@ complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from which" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from which" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from which" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from which" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-help" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from render-help" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l log-level -d 'Set the log output verbosity' -r complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -781,9 +781,9 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -s f -l force -d 'U complete -c rtx -n "__fish_seen_subcommand_from self-update" -l no-plugins -d 'Disable auto-updating plugins' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s y -l yes -d 'Skip confirmation prompt' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' diff --git a/schema/rtx.json b/schema/rtx.json index 264d08d6a..39ecea351 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -182,17 +182,6 @@ "description": "enable experimental features", "type": "boolean" }, - "log_level": { - "description": "log level", - "type": "string", - "enum": [ - "error", - "warn", - "info", - "debug", - "trace" - ] - }, "verbose": { "description": "display installation output", "type": "boolean" diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 7b32bc2f8..b3a4b06f6 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,7 +1,6 @@ use crate::cli::self_update::SelfUpdate; use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; -use log::LevelFilter; use crate::config::Config; use crate::output::Output; @@ -179,13 +178,13 @@ impl Cli { .arg_required_else_help(true) .subcommand_required(true) .after_long_help(AFTER_LONG_HELP) - .arg(args::log_level::Debug::arg()) .arg(args::jobs::Jobs::arg()) + .arg(args::log_level::Debug::arg()) .arg(args::log_level::LogLevel::arg()) - .arg(args::raw::Raw::arg()) - .arg(args::yes::Yes::arg()) .arg(args::log_level::Trace::arg()) - .arg(args::verbose::Verbose::arg()), + .arg(args::raw::Raw::arg()) + .arg(args::verbose::Verbose::arg()) + .arg(args::yes::Yes::arg()), ) } @@ -196,15 +195,6 @@ impl Cli { return version::Version {}.run(config, out); } let matches = self.command.get_matches_from(args); - if let Some(log_level) = matches.get_one::("log-level") { - config.settings.log_level = *log_level; - } - if let Some(true) = matches.get_one::("debug") { - config.settings.log_level = LevelFilter::Debug; - } - if let Some(true) = matches.get_one::("trace") { - config.settings.log_level = LevelFilter::Trace; - } if let Some(jobs) = matches.get_one::("jobs") { config.settings.jobs = *jobs; } diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index aed6a2056..97eefb15c 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -11,7 +11,6 @@ experimental = true jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] -log_level = INFO missing_runtime_behavior = autoinstall plugin_autoupdate_last_check_duration = 20 raw = false diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 1f4c6bb31..b561ce783 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -11,7 +11,6 @@ experimental = true jobs = 2 legacy_version_file = false legacy_version_file_disable_tools = [] -log_level = INFO missing_runtime_behavior = autoinstall plugin_autoupdate_last_check_duration = 1 raw = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index f82b46108..9ba5cf02f 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -51,7 +51,6 @@ mod tests { jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] - log_level = INFO missing_runtime_behavior = autoinstall plugin_autoupdate_last_check_duration = 20 raw = false diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index f8fb4f57a..6258c6281 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -7,7 +7,6 @@ use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; use console::style; use eyre::WrapErr; -use log::LevelFilter; use tera::Context; use toml_edit::{table, value, Array, Document, Item, Value}; @@ -420,7 +419,6 @@ impl RtxToml { settings.disable_tools = self.parse_string_array(&k, v)?.into_iter().collect() } - "log_level" => settings.log_level = Some(self.parse_log_level(&k, v)?), "raw" => settings.raw = Some(self.parse_bool(&k, v)?), "yes" => settings.yes = Some(self.parse_bool(&k, v)?), _ => Err(eyre!("Unknown config setting: {}", k))?, @@ -555,11 +553,6 @@ impl RtxToml { } } - fn parse_log_level(&mut self, k: &str, v: &Item) -> Result { - let level = self.parse_string(k, v)?.parse()?; - Ok(level) - } - pub fn update_setting>(&mut self, key: &str, value: V) { let key = key.split('.').collect::>(); let mut settings = self diff --git a/src/config/settings.rs b/src/config/settings.rs index d7ffb7a28..c000a895e 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -3,8 +3,6 @@ use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; use std::time::Duration; -use log::LevelFilter; - use crate::env::*; use crate::{duration, env}; @@ -24,7 +22,6 @@ pub struct Settings { pub shorthands_file: Option, pub disable_default_shorthands: bool, pub disable_tools: BTreeSet, - pub log_level: LevelFilter, pub raw: bool, pub yes: bool, } @@ -46,7 +43,6 @@ impl Default for Settings { shorthands_file: RTX_SHORTHANDS_FILE.clone(), disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, disable_tools: RTX_DISABLE_TOOLS.clone(), - log_level: *RTX_LOG_LEVEL, raw: *RTX_RAW, yes: *RTX_YES, } @@ -107,7 +103,6 @@ impl Settings { "disable_tools".into(), format!("{:?}", self.disable_tools.iter().collect::>()), ); - map.insert("log_level".into(), self.log_level.to_string()); map.insert("raw".into(), self.raw.to_string()); map.insert("yes".into(), self.yes.to_string()); map @@ -130,7 +125,6 @@ pub struct SettingsBuilder { pub shorthands_file: Option, pub disable_default_shorthands: Option, pub disable_tools: BTreeSet, - pub log_level: Option, pub raw: Option, pub yes: Option, } @@ -181,9 +175,6 @@ impl SettingsBuilder { self.disable_default_shorthands = other.disable_default_shorthands; } self.disable_tools.extend(other.disable_tools); - if other.log_level.is_some() { - self.log_level = other.log_level; - } if other.raw.is_some() { self.raw = other.raw; } @@ -236,7 +227,6 @@ impl SettingsBuilder { .disable_default_shorthands .unwrap_or(settings.disable_default_shorthands); settings.disable_tools.extend(self.disable_tools.clone()); - settings.log_level = self.log_level.unwrap_or(settings.log_level); settings.raw = self.raw.unwrap_or(settings.raw); settings.yes = self.yes.unwrap_or(settings.yes); @@ -303,9 +293,6 @@ impl Debug for SettingsBuilder { if !self.disable_tools.is_empty() { d.field("disable_tools", &self.disable_tools); } - if let Some(log_level) = self.log_level { - d.field("log_level", &log_level); - } if let Some(raw) = self.raw { d.field("raw", &raw); } From 322425fcf1d3f8c67c1a00857be4b43207244ccc Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 21:03:02 -0600 Subject: [PATCH 1171/1891] deprecate missing_runtime_behavior setting (#1073) --- schema/rtx.json | 11 ----------- src/cli/direnv/envrc.rs | 4 ---- src/cli/direnv/exec.rs | 4 ---- src/cli/hook_env.rs | 5 +---- src/cli/settings/set.rs | 2 -- src/config/config_file/rtx_toml.rs | 1 + ...nfig_file__rtx_toml__tests__fixture-2.snap | 1 - ...nfig_file__rtx_toml__tests__fixture-6.snap | 1 - src/config/settings.rs | 19 ++----------------- src/test.rs | 1 - test/config/config.toml | 1 - test/fixtures/.rtx.toml | 1 - 12 files changed, 4 insertions(+), 47 deletions(-) diff --git a/schema/rtx.json b/schema/rtx.json index 39ecea351..0432658bb 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -99,17 +99,6 @@ "type": "object", "additionalProperties": false, "properties": { - "missing_runtime_behavior": { - "description": "what to do when a runtime is missing", - "type": "string", - "enum": [ - "ignore", - "prompt", - "autoinstall", - "warn", - "error" - ] - }, "legacy_version_file": { "description": "should rtx parse legacy version files (e.g. .node-version)", "type": "boolean" diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 6bbc88905..8b98946d1 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -5,7 +5,6 @@ use std::ops::Deref; use color_eyre::eyre::Result; use crate::config::Config; -use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::hash::hash_to_str; use crate::output::Output; use crate::toolset::ToolsetBuilder; @@ -19,9 +18,6 @@ pub struct Envrc {} impl Envrc { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - if config.settings.missing_runtime_behavior == Prompt { - config.settings.missing_runtime_behavior = Warn; - } let ts = ToolsetBuilder::new() .with_install_missing() .build(&mut config)?; diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 62e5384af..68eb8ff94 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -5,7 +5,6 @@ use serde_derive::Deserialize; use crate::cmd; use crate::config::Config; -use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; use crate::output::Output; use crate::toolset::ToolsetBuilder; @@ -23,9 +22,6 @@ struct DirenvWatches { impl DirenvExec { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - if config.settings.missing_runtime_behavior == Prompt { - config.settings.missing_runtime_behavior = Warn; - } let ts = ToolsetBuilder::new() .with_install_missing() .build(&mut config)?; diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index e42e1ebdf..e0baadb18 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -9,7 +9,7 @@ use itertools::Itertools; use terminal_size::{terminal_size, Width}; use crate::config::Config; -use crate::config::MissingRuntimeBehavior::{Prompt, Warn}; + use crate::direnv::DirenvDiff; use crate::env::__RTX_DIFF; use crate::env_diff::{EnvDiff, EnvDiffOperation}; @@ -33,9 +33,6 @@ pub struct HookEnv { impl HookEnv { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - if config.settings.missing_runtime_behavior == Prompt { - config.settings.missing_runtime_behavior = Warn; - } let ts = ToolsetBuilder::new() .with_install_missing() .build(&mut config)?; diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 311acfa8c..48b916b0f 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -20,7 +20,6 @@ impl SettingsSet { pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { let value: toml_edit::Value = match self.key.as_str() { "experimental" => parse_bool(&self.value)?, - "missing_runtime_behavior" => self.value.into(), "always_keep_download" => parse_bool(&self.value)?, "always_keep_install" => parse_bool(&self.value)?, "legacy_version_file" => parse_bool(&self.value)?, @@ -70,7 +69,6 @@ pub mod tests { #[test] fn test_settings_set() { reset_config(); - assert_cli!("settings", "set", "missing_runtime_behavior", "warn"); assert_cli!("settings", "set", "legacy_version_file", "false"); assert_cli!("settings", "set", "always_keep_download", "true"); assert_cli!( diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 6258c6281..d749af433 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -542,6 +542,7 @@ impl RtxToml { v: &Item, ) -> Result { let v = self.parse_string("missing_runtime_behavior", v)?; + warn!("The 'missing_runtime_behavior' setting is deprecated. Use '--yes' instead."); match v.to_lowercase().as_str() { "warn" => Ok(MissingRuntimeBehavior::Warn), "ignore" => Ok(MissingRuntimeBehavior::Ignore), diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index a09a63699..8ddeaacaf 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -3,7 +3,6 @@ source: src/config/config_file/rtx_toml.rs expression: cf.settings() --- SettingsBuilder { - missing_runtime_behavior: Warn, legacy_version_file_disable_tools: { "disabled_tool_from_legacy_file", }, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index 0e7768208..663df16c6 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -20,7 +20,6 @@ node = 'https://github.com/jdx/rtx-node' [settings] verbose = true -missing_runtime_behavior = 'warn' disable_tools = ['disabled_tool'] legacy_version_file_disable_tools = ['disabled_tool_from_legacy_file'] diff --git a/src/config/settings.rs b/src/config/settings.rs index c000a895e..73c1cb4a5 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -130,12 +130,6 @@ pub struct SettingsBuilder { } impl SettingsBuilder { - // pub fn new(missing_runtime_behavior: Option) -> Self { - // Self { - // missing_runtime_behavior: missing_runtime_behavior, - // } - // } - pub fn merge(&mut self, other: Self) -> &mut Self { if other.experimental.is_some() { self.experimental = other.experimental; @@ -324,7 +318,6 @@ impl Display for MissingRuntimeBehavior { #[cfg(test)] mod tests { - use crate::config::settings::MissingRuntimeBehavior::{AutoInstall, Ignore, Prompt, Warn}; use super::*; @@ -332,19 +325,11 @@ mod tests { fn test_settings_merge() { let mut s1 = SettingsBuilder::default(); let s2 = SettingsBuilder { - missing_runtime_behavior: Some(AutoInstall), + asdf_compat: Some(true), ..SettingsBuilder::default() }; s1.merge(s2); - assert_eq!(s1.missing_runtime_behavior, Some(AutoInstall)); - } - - #[test] - fn test_missing_runtime_behavior_display() { - assert_eq!(AutoInstall.to_string(), "autoinstall"); - assert_eq!(Prompt.to_string(), "prompt"); - assert_eq!(Warn.to_string(), "warn"); - assert_eq!(Ignore.to_string(), "ignore"); + assert_eq!(s1.asdf_compat, Some(true)); } } diff --git a/src/test.rs b/src/test.rs index 61bfe31dd..9c4315500 100644 --- a/src/test.rs +++ b/src/test.rs @@ -51,7 +51,6 @@ pub fn reset_config() { [settings] experimental = true verbose = true - missing_runtime_behavior= 'autoinstall' always_keep_download= true always_keep_install= true legacy_version_file= true diff --git a/test/config/config.toml b/test/config/config.toml index 2fd1df383..2234f4acb 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -3,7 +3,6 @@ TEST_ENV_VAR = 'test-123' [settings] experimental = true verbose = true -missing_runtime_behavior= 'autoinstall' always_keep_download= true always_keep_install= true legacy_version_file= true diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.rtx.toml index 59b15d93d..94f6660d3 100644 --- a/test/fixtures/.rtx.toml +++ b/test/fixtures/.rtx.toml @@ -16,7 +16,6 @@ node = 'https://github.com/jdx/rtx-node' [settings] verbose = true -missing_runtime_behavior = 'warn' disable_tools = ['disabled_tool'] legacy_version_file_disable_tools = ['disabled_tool_from_legacy_file'] From aabe269d5a886d859059f3f911e6d61d4f0442b8 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 3 Dec 2023 21:19:12 -0600 Subject: [PATCH 1172/1891] switch to confique for settings management (#1074) --- Cargo.lock | 34 +++++++++++++++++++++++- Cargo.toml | 1 + src/config/settings.rs | 59 ++++++++++++++++++++++++++---------------- src/env.rs | 38 +-------------------------- 4 files changed, 72 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0d6e89b6..df3c6affd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,7 +259,7 @@ version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.39", @@ -335,6 +335,28 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "confique" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7944dc1c6dec3f9b3adc127a921affd93baeea3d04c9b2d0a84380a243c9258b" +dependencies = [ + "confique-macro", + "serde", +] + +[[package]] +name = "confique-macro" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7305b4979ffd6d8b02006da5520b21c66bfab961cd688b9b6db00780f61448ce" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "console" version = "0.15.7" @@ -889,6 +911,15 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "heck" version = "0.4.1" @@ -1789,6 +1820,7 @@ dependencies = [ "clap_mangen", "color-eyre", "color-print", + "confique", "console", "ctor", "ctrlc", diff --git a/Cargo.toml b/Cargo.toml index 0caa3eacd..c181c4f32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ clap_complete = "4.2" clap_mangen = { version = "0.2", optional = true } color-eyre = "0.6" color-print = "0.3" +confique = { version = "0.2.4", default-features = false } console = "0.15" ctrlc = "3.4" dialoguer = { version = "0.11", features = [] } diff --git a/src/config/settings.rs b/src/config/settings.rs index 73c1cb4a5..0da0d0d46 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,55 +1,69 @@ +use confique::env::parse::{list_by_colon, list_by_comma}; +use confique::{Builder, Config, Partial}; +use log::LevelFilter; +use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; use std::time::Duration; -use crate::env::*; use crate::{duration, env}; -#[derive(Debug, Clone)] +#[derive(Config, Debug, Clone)] pub struct Settings { + #[config(env = "RTX_EXPERIMENTAL", default = false)] pub experimental: bool, + #[config(env = "RTX_MISSING_RUNTIME_BEHAVIOR")] pub missing_runtime_behavior: MissingRuntimeBehavior, + #[config(env = "RTX_ALWAYS_KEEP_DOWNLOAD", default = false)] pub always_keep_download: bool, + #[config(env = "RTX_ALWAYS_KEEP_INSTALL", default = false)] pub always_keep_install: bool, + #[config(env = "RTX_LEGACY_VERSION_FILE", default = true)] pub legacy_version_file: bool, + #[config(env = "RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, + #[config(env = "RTX_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION")] pub plugin_autoupdate_last_check_duration: Duration, + #[config(env = "RTX_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] pub trusted_config_paths: BTreeSet, + #[config(env = "RTX_VERBOSE", default = false)] pub verbose: bool, + #[config(env = "RTX_ASDF_COMPAT", default = false)] pub asdf_compat: bool, + #[config(env = "RTX_JOBS", default = 4)] pub jobs: usize, + #[config(env = "RTX_SHORTHANDS_FILE")] pub shorthands_file: Option, + #[config(env = "RTX_DISABLE_DEFAULT_SHORTHANDS", default = false)] pub disable_default_shorthands: bool, + #[config(env = "RTX_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub disable_tools: BTreeSet, + #[config(env = "RTX_RAW", default = false)] pub raw: bool, pub yes: bool, } +pub type SettingsPartial = ::Partial; + impl Default for Settings { fn default() -> Self { - Self { - experimental: *RTX_EXPERIMENTAL, - missing_runtime_behavior: MissingRuntimeBehavior::Warn, - always_keep_download: *RTX_ALWAYS_KEEP_DOWNLOAD, - always_keep_install: *RTX_ALWAYS_KEEP_INSTALL, - legacy_version_file: *RTX_LEGACY_VERSION_FILE != Some(false), - legacy_version_file_disable_tools: RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS.clone(), - plugin_autoupdate_last_check_duration: duration::WEEKLY, - trusted_config_paths: RTX_TRUSTED_CONFIG_PATHS.clone(), - verbose: *RTX_VERBOSE, - asdf_compat: *RTX_ASDF_COMPAT, - jobs: *RTX_JOBS, - shorthands_file: RTX_SHORTHANDS_FILE.clone(), - disable_default_shorthands: *RTX_DISABLE_DEFAULT_SHORTHANDS, - disable_tools: RTX_DISABLE_TOOLS.clone(), - raw: *RTX_RAW, - yes: *RTX_YES, - } + Settings::default_builder().load().unwrap() } } - impl Settings { + pub fn default_builder() -> Builder { + let mut partial = SettingsPartial::empty(); + partial.missing_runtime_behavior = Some(MissingRuntimeBehavior::Warn); + partial.plugin_autoupdate_last_check_duration = Some(duration::WEEKLY); + partial.yes = Some(*env::RTX_YES); + if *env::RTX_LOG_LEVEL < LevelFilter::Info { + partial.verbose = Some(true); + } + + Settings::builder().preloaded(partial).env() + } + pub fn to_index_map(&self) -> BTreeMap { let mut map = BTreeMap::new(); map.insert("experimental".to_string(), self.experimental.to_string()); @@ -297,7 +311,8 @@ impl Debug for SettingsBuilder { } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] pub enum MissingRuntimeBehavior { AutoInstall, Prompt, diff --git a/src/env.rs b/src/env.rs index 38216a22a..aeb1302be 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeSet, HashMap, HashSet}; +use std::collections::{HashMap, HashSet}; pub use std::env::*; use std::path::PathBuf; use std::time::Duration; @@ -48,14 +48,6 @@ pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); pub static RTX_MISSING_RUNTIME_BEHAVIOR: Lazy> = Lazy::new(|| var("RTX_MISSING_RUNTIME_BEHAVIOR").ok()); -pub static RTX_VERBOSE: Lazy = - Lazy::new(|| *RTX_LOG_LEVEL > LevelFilter::Info || var_is_true("RTX_VERBOSE")); -pub static RTX_JOBS: Lazy = Lazy::new(|| { - var("RTX_JOBS") - .ok() - .and_then(|v| v.parse::().ok()) - .unwrap_or(4) -}); pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) }); @@ -88,35 +80,7 @@ pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH" }); pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); pub static RTX_CONFIRM: Lazy = Lazy::new(|| var_confirm("RTX_CONFIRM")); -pub static RTX_EXPERIMENTAL: Lazy = Lazy::new(|| var_is_true("RTX_EXPERIMENTAL")); -pub static RTX_ASDF_COMPAT: Lazy = Lazy::new(|| var_is_true("RTX_ASDF_COMPAT")); -pub static RTX_SHORTHANDS_FILE: Lazy> = - Lazy::new(|| var_path("RTX_SHORTHANDS_FILE")); -pub static RTX_DISABLE_DEFAULT_SHORTHANDS: Lazy = - Lazy::new(|| var_is_true("RTX_DISABLE_DEFAULT_SHORTHANDS")); -pub static RTX_LEGACY_VERSION_FILE: Lazy> = - Lazy::new(|| var_option_bool("RTX_LEGACY_VERSION_FILE")); -pub static RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS: Lazy> = Lazy::new(|| { - var("RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS") - .map(|v| v.split(',').map(|s| s.to_string()).collect()) - .unwrap_or_default() -}); -pub static RTX_DISABLE_TOOLS: Lazy> = Lazy::new(|| { - var("RTX_DISABLE_TOOLS") - .map(|v| v.split(',').map(|s| s.to_string()).collect()) - .unwrap_or_default() -}); -pub static RTX_RAW: Lazy = Lazy::new(|| var_is_true("RTX_RAW")); pub static RTX_YES: Lazy = Lazy::new(|| *CI || var_is_true("RTX_YES")); -pub static RTX_TRUSTED_CONFIG_PATHS: Lazy> = Lazy::new(|| { - var("RTX_TRUSTED_CONFIG_PATHS") - .map(|v| split_paths(&v).collect()) - .unwrap_or_default() -}); -pub static RTX_ALWAYS_KEEP_DOWNLOAD: Lazy = - Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_DOWNLOAD")); -pub static RTX_ALWAYS_KEEP_INSTALL: Lazy = - Lazy::new(|| var_is_true("RTX_ALWAYS_KEEP_INSTALL")); pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| match var_option_bool("RTX_ALL_COMPILE") { Some(v) => v, None => matches!( From a8ba7bf033dd94e3f69001f22468aea4ab8ad058 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 4 Dec 2023 11:46:04 -0600 Subject: [PATCH 1173/1891] config: small refactors --- src/config/config_file/legacy_version.rs | 29 ++------------------- src/config/config_file/mod.rs | 32 ++++++++++++++++-------- src/config/config_file/rtx_toml.rs | 12 ++------- src/config/config_file/tool_versions.rs | 32 +----------------------- 4 files changed, 27 insertions(+), 78 deletions(-) diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index a5b48e8d4..524fdb038 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::default::Default; use std::fmt::Display; use std::path::{Path, PathBuf}; @@ -7,8 +6,8 @@ use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::settings::SettingsBuilder; -use crate::config::{AliasMap, Settings}; + +use crate::config::Settings; use crate::plugins::PluginName; use crate::tool::Tool; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -46,18 +45,6 @@ impl ConfigFile for LegacyVersionFile { self.path.as_path() } - fn plugins(&self) -> HashMap { - Default::default() - } - - fn env(&self) -> HashMap { - HashMap::new() - } - - fn path_dirs(&self) -> Vec { - vec![] - } - fn remove_plugin(&mut self, _plugin_name: &PluginName) { unimplemented!() } @@ -77,18 +64,6 @@ impl ConfigFile for LegacyVersionFile { fn to_toolset(&self) -> &Toolset { &self.toolset } - - fn settings(&self) -> SettingsBuilder { - SettingsBuilder::default() - } - - fn aliases(&self) -> AliasMap { - AliasMap::default() - } - - fn watch_files(&self) -> Vec { - vec![self.path.clone()] - } } impl Display for LegacyVersionFile { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 7c6d1b6b6..9060fac13 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -9,7 +9,7 @@ use tool_versions::ToolVersions; use crate::cli::args::tool::ToolArg; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::settings::SettingsBuilder; -use crate::config::{AliasMap, Config, Settings}; +use crate::config::{global_config_files, AliasMap, Config, Settings}; use crate::file::{display_path, replace_path}; use crate::hash::hash_to_str; use crate::output::Output; @@ -32,23 +32,35 @@ pub enum ConfigFileType { pub trait ConfigFile: Debug + Display + Send + Sync { fn get_type(&self) -> ConfigFileType; fn get_path(&self) -> &Path; - fn plugins(&self) -> HashMap; - fn env(&self) -> HashMap; + fn plugins(&self) -> HashMap { + Default::default() + } + fn env(&self) -> HashMap { + Default::default() + } fn env_remove(&self) -> Vec { - vec![] + Default::default() + } + fn path_dirs(&self) -> Vec { + Default::default() } - fn path_dirs(&self) -> Vec; - fn remove_plugin(&mut self, plugin_name: &PluginName); + fn remove_plugin(&mut self, _plugin_name: &PluginName); fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]); fn save(&self) -> Result<()>; fn dump(&self) -> String; fn to_toolset(&self) -> &Toolset; - fn settings(&self) -> SettingsBuilder; - fn aliases(&self) -> AliasMap; - fn watch_files(&self) -> Vec; + fn settings(&self) -> SettingsBuilder { + Default::default() + } + fn aliases(&self) -> AliasMap { + Default::default() + } + fn watch_files(&self) -> Vec { + vec![self.get_path().to_path_buf()] + } fn is_global(&self) -> bool { - false + global_config_files().iter().any(|p| p == self.get_path()) } } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index d749af433..e93dccb90 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -12,7 +12,7 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; -use crate::config::{config_file, global_config_files, AliasMap, MissingRuntimeBehavior}; +use crate::config::{config_file, AliasMap, MissingRuntimeBehavior}; use crate::errors::Error::UntrustedConfig; use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; @@ -83,10 +83,6 @@ impl RtxToml { Ok(()) } - pub fn settings(&self) -> SettingsBuilder { - self.settings.clone() - } - fn parse_env_file(&mut self, k: &str, v: &Item) -> Result<()> { self.trust_check()?; match v.as_str() { @@ -431,7 +427,7 @@ impl RtxToml { Ok(settings) } - pub(crate) fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { + pub fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { self.alias .entry(plugin.into()) .or_default() @@ -758,10 +754,6 @@ impl ConfigFile for RtxToml { None => vec![self.path.clone()], } } - - fn is_global(&self) -> bool { - global_config_files().iter().any(|p| p == &self.path) - } } impl Debug for RtxToml { diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 95556ddb2..bf4ef6285 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; @@ -9,8 +8,7 @@ use itertools::Itertools; use tera::Context; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::settings::SettingsBuilder; -use crate::config::{global_config_files, AliasMap}; + use crate::file; use crate::file::display_path; use crate::plugins::{unalias_plugin, PluginName}; @@ -163,18 +161,6 @@ impl ConfigFile for ToolVersions { self.path.as_path() } - fn plugins(&self) -> HashMap { - Default::default() - } - - fn env(&self) -> HashMap { - HashMap::new() - } - - fn path_dirs(&self) -> Vec { - vec![] - } - fn remove_plugin(&mut self, plugin: &PluginName) { self.plugins.remove(plugin); } @@ -211,22 +197,6 @@ impl ConfigFile for ToolVersions { fn to_toolset(&self) -> &Toolset { &self.toolset } - - fn settings(&self) -> SettingsBuilder { - SettingsBuilder::default() - } - - fn aliases(&self) -> AliasMap { - AliasMap::default() - } - - fn watch_files(&self) -> Vec { - vec![self.path.clone()] - } - - fn is_global(&self) -> bool { - global_config_files().iter().any(|p| p == &self.path) - } } #[cfg(test)] From 6fe31d8da24284292c95b0e11d26eafc84dd06e4 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:17:06 -0600 Subject: [PATCH 1174/1891] completions: custom zsh completion generator (#1070) --- .github/workflows/rtx.yml | 1 + Cargo.toml | 7 +- README.md | 2 +- completions/_rtx | 3826 +++++++------------------------ completions/rtx.bash | 182 +- completions/rtx.fish | 215 +- justfile | 9 +- src/cli/args/log_level.rs | 9 +- src/cli/completion.rs | 73 +- src/cli/mod.rs | 8 + src/cli/render_completion.rs | 315 +++ src/templates/complete_zsh.tera | 103 + 12 files changed, 1505 insertions(+), 3245 deletions(-) create mode 100644 src/cli/render_completion.rs create mode 100644 src/templates/complete_zsh.tera diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 7f2d22483..3fca4c2b0 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -58,6 +58,7 @@ jobs: - uses: taiki-e/install-action@cargo-llvm-cov - name: Install zsh/fish/direnv run: sudo apt-get update; sudo apt-get install zsh fish direnv + - run: npm i -g markdown-magic - name: Install just uses: taiki-e/install-action@just - name: Run tests with coverage diff --git a/Cargo.toml b/Cargo.toml index c181c4f32..a99bf6113 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ categories = ["command-line-utilities"] include = [ "src/**/*.rs", "src/plugins/core/assets/**", + "/completions/*", "/Cargo.lock", "/LICENSE", "/README.md", @@ -43,7 +44,7 @@ chrono = { version = "0.4", default-features = false, features = [ "clock", ] } clap = { version = "4.4", features = ["env", "derive", "string"] } -clap_complete = "4.2" +clap_complete = { version = "4", optional = true } clap_mangen = { version = "0.2", optional = true } color-eyre = "0.6" color-print = "0.3" @@ -144,6 +145,6 @@ pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-linux-x64{ arc [package.metadata.cargo-machete] ignored = [ - "built", - "openssl", + "built", + "openssl", ] diff --git a/README.md b/README.md index fcaf72337..7dc36e78d 100644 --- a/README.md +++ b/README.md @@ -1763,7 +1763,7 @@ Arguments: [SHELL] Shell type to generate completions for - [possible values: bash, elvish, fish, powershell, zsh] + [possible values: bash, fish, zsh] Examples: $ rtx completion bash > /etc/bash_completion.d/rtx diff --git a/completions/_rtx b/completions/_rtx index 0ab07766f..1565165d1 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1,3078 +1,806 @@ #compdef rtx - -autoload -U is-at-least - _rtx() { - typeset -A opt_args - typeset -a _arguments_options - local ret=1 - - if is-at-least 5.2; then - _arguments_options=(-s -S -C) - else - _arguments_options=(-s -C) - fi - - local context curcontext="$curcontext" state line - _arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'-V[Print version]' \ -'--version[Print version]' \ -":: :_rtx_commands" \ -"*::: :->rtx" \ -&& ret=0 - case $state in - (rtx) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-command-$line[1]:" - case $line[1] in - (activate) -_arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate the script for]:SHELL:(bash fish nu xonsh zsh)' \ -'--shell=[Shell type to generate the script for]:SHELL:(bash fish nu xonsh zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--status[Show "rtx\: @" message when changing directories]' \ -'-q[noop]' \ -'--quiet[noop]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::shell_type -- Shell type to generate the script for:(bash fish nu xonsh zsh)' \ -&& ret=0 -;; -(alias) -_arguments "${_arguments_options[@]}" \ -'-p+[filter aliases by plugin]:PLUGIN: ' \ -'--plugin=[filter aliases by plugin]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -":: :_rtx__alias_commands" \ -"*::: :->alias" \ -&& ret=0 - - case $state in - (alias) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-alias-command-$line[1]:" - case $line[1] in - (get) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- The plugin to show the alias for:' \ -':alias -- The alias to show:' \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -'-p+[Show aliases for ]:PLUGIN: ' \ -'--plugin=[Show aliases for ]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(set) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- The plugin to set the alias for:' \ -':alias -- The alias to set:' \ -':value -- The value to set the alias to:' \ -&& ret=0 -;; -(unset) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- The plugin to remove the alias from:' \ -':alias -- The alias to remove:' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__alias__help_commands" \ -"*::: :->help" \ -&& ret=0 - - case $state in - (help) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-alias-help-command-$line[1]:" - case $line[1] in - (get) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(set) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(unset) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; - esac - ;; -esac -;; -(asdf) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -'*::args -- all arguments:' \ -&& ret=0 -;; -(bin-paths) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(cache) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -":: :_rtx__cache_commands" \ -"*::: :->cache" \ -&& ret=0 - - case $state in - (cache) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-cache-command-$line[1]:" - case $line[1] in - (clear) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__cache__help_commands" \ -"*::: :->help" \ -&& ret=0 - - case $state in - (help) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-cache-help-command-$line[1]:" - case $line[1] in - (clear) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; - esac - ;; -esac -;; -(completion) -_arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ -'--shell=[Shell type to generate completions for]:SHELL_TYPE:(bash elvish fish powershell zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::shell -- Shell type to generate completions for:(bash elvish fish powershell zsh)' \ -&& ret=0 -;; -(current) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::plugin -- Plugin to show versions of e.g.\: ruby, node:' \ -&& ret=0 -;; -(deactivate) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(direnv) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -":: :_rtx__direnv_commands" \ -"*::: :->direnv" \ -&& ret=0 + typeset -A opt_args + local context state line curcontext=$curcontext + local ret=1 - case $state in - (direnv) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-direnv-command-$line[1]:" - case $line[1] in - (envrc) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(exec) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(activate) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__direnv__help_commands" \ -"*::: :->help" \ -&& ret=0 + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 - case $state in - (help) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-direnv-help-command-$line[1]:" - case $line[1] in - (envrc) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(exec) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(activate) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (activate) __rtx_activate_cmd && ret=0 ;; + (a|aliases|alias) __rtx_alias_cmd && ret=0 ;; + (asdf) __rtx_asdf_cmd && ret=0 ;; + (bin-paths) __rtx_bin_paths_cmd && ret=0 ;; + (cache) __rtx_cache_cmd && ret=0 ;; + (complete|completions|completion) __rtx_completion_cmd && ret=0 ;; + (current) __rtx_current_cmd && ret=0 ;; + (deactivate) __rtx_deactivate_cmd && ret=0 ;; + (direnv) __rtx_direnv_cmd && ret=0 ;; + (doctor) __rtx_doctor_cmd && ret=0 ;; + (e|env) __rtx_env_cmd && ret=0 ;; + (env-vars) __rtx_env_vars_cmd && ret=0 ;; + (x|exec) __rtx_exec_cmd && ret=0 ;; + (g|global) __rtx_global_cmd && ret=0 ;; + (hook-env) __rtx_hook_env_cmd && ret=0 ;; + (implode) __rtx_implode_cmd && ret=0 ;; + (i|install) __rtx_install_cmd && ret=0 ;; + (latest) __rtx_latest_cmd && ret=0 ;; + (link) __rtx_link_cmd && ret=0 ;; + (l|local) __rtx_local_cmd && ret=0 ;; + (list|ls) __rtx_ls_cmd && ret=0 ;; + (list-all|list-remote|ls-remote) __rtx_ls_remote_cmd && ret=0 ;; + (outdated) __rtx_outdated_cmd && ret=0 ;; + (p|plugin|plugin-list|plugins) __rtx_plugins_cmd && ret=0 ;; + (prune) __rtx_prune_cmd && ret=0 ;; + (render-completion) __rtx_render_completion_cmd && ret=0 ;; + (render-help) __rtx_render_help_cmd && ret=0 ;; + (render-mangen) __rtx_render_mangen_cmd && ret=0 ;; + (reshim) __rtx_reshim_cmd && ret=0 ;; + (self-update) __rtx_self_update_cmd && ret=0 ;; + (settings) __rtx_settings_cmd && ret=0 ;; + (s|shell) __rtx_shell_cmd && ret=0 ;; + (sync) __rtx_sync_cmd && ret=0 ;; + (trust) __rtx_trust_cmd && ret=0 ;; + (remove|rm|uninstall) __rtx_uninstall_cmd && ret=0 ;; + (upgrade) __rtx_upgrade_cmd && ret=0 ;; + (u|use) __rtx_use_cmd && ret=0 ;; + (v|version) __rtx_version_cmd && ret=0 ;; + (where) __rtx_where_cmd && ret=0 ;; + (which) __rtx_which_cmd && ret=0 ;; + esac ;; -esac -;; -(doctor) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(env) -_arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate environment variables for]:SHELL:(bash fish nu xonsh zsh)' \ -'--shell=[Shell type to generate environment variables for]:SHELL:(bash fish nu xonsh zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--json[Output in JSON format]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to use:' \ -&& ret=0 -;; -(env-vars) -_arguments "${_arguments_options[@]}" \ -'--file=[The TOML file to update]:FILE: ' \ -'*--remove=[Remove the environment variable from config file]:ENV_VAR: ' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::env_vars -- Environment variable(s) to set -e.g.\: NODE_ENV=production:' \ -&& ret=0 -;; -(exec) -_arguments "${_arguments_options[@]}" \ -'()-c+[Command string to execute]:C:_cmdstring' \ -'()--command=[Command string to execute]:C:_cmdstring' \ -'--cd=[Change to this directory before executing the command]:CD:_files -/' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to start e.g.\: node@20 python@3.10:' \ -&& ret=0 -;; -(global) -_arguments "${_arguments_options[@]}" \ -'*--remove=[Remove the plugin(s) from ~/.tool-versions]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--pin[Save exact version to \`~/.tool-versions\` -e.g.\: \`rtx global --pin node@20\` will save \`node 20.0.0\` to ~/.tool-versions]' \ -'--fuzzy[Save fuzzy version to \`~/.tool-versions\` -e.g.\: \`rtx global --fuzzy node@20\` will save \`node 20\` to ~/.tool-versions -this is the default behavior unless RTX_ASDF_COMPAT=1]' \ -'--path[Get the path of the global config file]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to add to .tool-versions -e.g.\: node@20 -If this is a single tool with no version, the current value of the global -.tool-versions will be displayed:' \ -&& ret=0 -;; -(hook-env) -_arguments "${_arguments_options[@]}" \ -'-s+[Shell type to generate script for]:SHELL:(bash fish nu xonsh zsh)' \ -'--shell=[Shell type to generate script for]:SHELL:(bash fish nu xonsh zsh)' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--status[Show "rtx\: @" message when changing directories]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(implode) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--config[Also remove config directory]' \ -'--dry-run[List directories that would be removed without actually removing them]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(install) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-f[Force reinstall even if already installed]' \ -'--force[Force reinstall even if already installed]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to install e.g.\: node@20:' \ -&& ret=0 -;; -(latest) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-i[Show latest installed instead of available version]' \ -'--installed[Show latest installed instead of available version]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':tool -- Tool to get the latest version of:' \ -'::asdf_version -- The version prefix to use when querying the latest version same as the first argument after the "@" used for asdf compatibility:' \ -&& ret=0 -;; -(link) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-f[Overwrite an existing tool version if it exists]' \ -'--force[Overwrite an existing tool version if it exists]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':tool -- Tool name and version to create a symlink for:' \ -':path -- The local path to the tool version -e.g.\: ~/.nvm/versions/node/v20.0.0:_files -/' \ -&& ret=0 -;; -(local) -_arguments "${_arguments_options[@]}" \ -'*--remove=[Remove the plugin(s) from .tool-versions]:PLUGIN: ' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-p[Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the tool in the current directory ("\$PWD/.tool-versions")]' \ -'--parent[Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the tool in the current directory ("\$PWD/.tool-versions")]' \ -'--pin[Save exact version to \`.tool-versions\` -e.g.\: \`rtx local --pin node@20\` will save \`node 20.0.0\` to .tool-versions]' \ -'--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ -'--path[Get the path of the config file]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to add to .tool-versions/.rtx.toml -e.g.\: node@20 -if this is a single tool with no version, -the current value of .tool-versions/.rtx.toml will be displayed:' \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -'-p+[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ -'--plugin=[Only show tool versions from \[PLUGIN\]]:PLUGIN: ' \ -'--prefix=[Display versions matching this prefix]:PREFIX: ' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-c[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ -'--current[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ -'-g[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ -'--global[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ -'-i[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ -'--installed[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ -'(--json)--parseable[Output in an easily parseable format]' \ -'--json[Output in json format]' \ -'(-i --installed)-m[Display missing tool versions]' \ -'(-i --installed)--missing[Display missing tool versions]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::plugin_arg:' \ -&& ret=0 -;; -(ls-remote) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':plugin -- Plugin to get versions for:' \ -'::prefix -- The version prefix to use when querying the latest version -same as the first argument after the "@":' \ -&& ret=0 -;; -(outdated) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to show outdated versions for -e.g.\: node@20 python@3.10 -If not specified, all tools in global and local configs will be shown:' \ -&& ret=0 -;; -(plugins) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-a[list all available remote plugins]' \ -'--all[list all available remote plugins]' \ -'-c[The built-in plugins only -Normally these are not shown]' \ -'--core[The built-in plugins only -Normally these are not shown]' \ -'-u[show the git url for each plugin]' \ -'--urls[show the git url for each plugin]' \ -'--refs[show the git refs for each plugin]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -":: :_rtx__plugins_commands" \ -"*::: :->plugins" \ -&& ret=0 + esac - case $state in - (plugins) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-plugins-command-$line[1]:" - case $line[1] in - (install) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-f[Reinstall even if plugin exists]' \ -'--force[Reinstall even if plugin exists]' \ -'(-f --force)-a[Install all missing plugins -This will only install plugins that have matching shorthands. -i.e.\: they don'\''t need the full git repo url]' \ -'(-f --force)--all[Install all missing plugins -This will only install plugins that have matching shorthands. -i.e.\: they don'\''t need the full git repo url]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::name -- The name of the plugin to install -e.g.\: node, ruby -Can specify multiple plugins\: `rtx plugins install node ruby python`:' \ -'::git_url -- The git url of the plugin:_urls' \ -'*::rest:' \ -&& ret=0 -;; -(link) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-f[Overwrite existing plugin]' \ -'--force[Overwrite existing plugin]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':name -- The name of the plugin -e.g.\: node, ruby:' \ -'::path -- The local path to the plugin -e.g.\: ./rtx-node:_files -/' \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-a[List all available remote plugins -Same as \`rtx plugins ls-remote\`]' \ -'--all[List all available remote plugins -Same as \`rtx plugins ls-remote\`]' \ -'-c[The built-in plugins only -Normally these are not shown]' \ -'--core[The built-in plugins only -Normally these are not shown]' \ -'-u[Show the git url for each plugin -e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ -'--urls[Show the git url for each plugin -e.g.\: https\://github.com/asdf-vm/asdf-node.git]' \ -'--refs[Show the git refs for each plugin -e.g.\: main 1234abc]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(ls-remote) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-u[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ -'--urls[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ -'--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(uninstall) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-p[Also remove the plugin'\''s installs, downloads, and cache]' \ -'--purge[Also remove the plugin'\''s installs, downloads, and cache]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::plugin -- Plugin(s) to remove:' \ -&& ret=0 -;; -(update) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'()-a[Update all plugins]' \ -'()--all[Update all plugins]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::plugin -- Plugin(s) to update:' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__plugins__help_commands" \ -"*::: :->help" \ -&& ret=0 + return ret +} +__rtx_activate_cmd() { + _arguments -s -S \ + '*::shell_type:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--status=[Show "rtx: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_alias_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 - case $state in - (help) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-plugins-help-command-$line[1]:" - case $line[1] in - (install) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(link) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls-remote) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(uninstall) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(update) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (get) __rtx_alias_get_cmd && ret=0 ;; + (list|ls) __rtx_alias_ls_cmd && ret=0 ;; + (add|create|set) __rtx_alias_set_cmd && ret=0 ;; + (del|delete|remove|rm|unset) __rtx_alias_unset_cmd && ret=0 ;; + esac ;; -esac -;; -(prune) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--dry-run[Do not actually delete anything]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::plugins -- Prune only versions from these plugins:' \ -&& ret=0 -;; -(reshim) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::plugin:' \ -'::version:' \ -&& ret=0 -;; -(settings) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -":: :_rtx__settings_commands" \ -"*::: :->settings" \ -&& ret=0 + esac - case $state in - (settings) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-settings-command-$line[1]:" - case $line[1] in - (get) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':key -- The setting to show:' \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(set) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':key -- The setting to set:' \ -':value -- The value to set:' \ -&& ret=0 -;; -(unset) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':key -- The setting to remove:' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__settings__help_commands" \ -"*::: :->help" \ -&& ret=0 + return ret +} +__rtx_alias_get_cmd() { + _arguments -s -S \ + '*::alias:' \ + '*::plugin:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_alias_ls_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-p --plugin)'{-p,--plugin}'=[Show aliases for ]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_alias_set_cmd() { + _arguments -s -S \ + '*::alias:' \ + '*::plugin:' \ + '*::value:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_alias_unset_cmd() { + _arguments -s -S \ + '*::alias:' \ + '*::plugin:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_asdf_cmd() { + _arguments -s -S \ + '*::args:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_bin_paths_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_cache_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 - case $state in - (help) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-settings-help-command-$line[1]:" - case $line[1] in - (get) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(set) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(unset) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (c|clean|clear) __rtx_cache_clear_cmd && ret=0 ;; + esac ;; -esac -;; - esac - ;; -esac -;; -(shell) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-u[Removes a previously set version]' \ -'--unset[Removes a previously set version]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to use:' \ -&& ret=0 -;; -(sync) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -":: :_rtx__sync_commands" \ -"*::: :->sync" \ -&& ret=0 + esac - case $state in - (sync) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-sync-command-$line[1]:" - case $line[1] in - (node) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--brew[Get tool versions from Homebrew]' \ -'--nvm[Get tool versions from nvm]' \ -'--nodenv[Get tool versions from nodenv]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(python) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--pyenv[Get tool versions from pyenv]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__sync__help_commands" \ -"*::: :->help" \ -&& ret=0 + return ret +} +__rtx_cache_clear_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_completion_cmd() { + _arguments -s -S \ + '*::shell:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_current_cmd() { + _arguments -s -S \ + '*::plugin:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_deactivate_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_direnv_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 - case $state in - (help) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-sync-help-command-$line[1]:" - case $line[1] in - (node) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(python) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (activate) __rtx_direnv_activate_cmd && ret=0 ;; + (envrc) __rtx_direnv_envrc_cmd && ret=0 ;; + (exec) __rtx_direnv_exec_cmd && ret=0 ;; + esac ;; -esac -;; -(trust) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--untrust[No longer trust this config]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::config_file -- The config file to trust:_files' \ -&& ret=0 -;; -(uninstall) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-a[Delete all installed versions]' \ -'--all[Delete all installed versions]' \ -'-n[Do not actually delete anything]' \ -'--dry-run[Do not actually delete anything]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to remove:' \ -&& ret=0 -;; -(upgrade) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -'*::tool -- Tool(s) to upgrade -e.g.\: node@20 python@3.10 -If not specified, all current tools will be upgraded:' \ -&& ret=0 -;; -(use) -_arguments "${_arguments_options[@]}" \ -'*--remove=[Remove the tool(s) from config file]:TOOL: ' \ -'-e+[\[experimental\] Modify an environment-specific config file like .rtx..toml]:ENV: ' \ -'--env=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:ENV: ' \ -'-p+[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:PATH:_files' \ -'--path=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:PATH:_files' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--pin[Save exact version to config file -e.g.\: \`rtx use --pin node@20\` will save 20.0.0 as the version]' \ -'--fuzzy[Save fuzzy version to config file -e.g.\: \`rtx use --fuzzy node@20\` will save 20 as the version -this is the default behavior unless RTX_ASDF_COMPAT=1]' \ -'-g[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ -'--global[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::tool -- Tool(s) to add to config file -e.g.\: node@20 -If no version is specified, it will default to @latest:' \ -&& ret=0 -;; -(version) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(where) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':tool -- Tool(s) to look up -e.g.\: ruby@3 -if "@" is specified, it will show the latest installed version -that matches the prefix -otherwise, it will show the current, active installed version:' \ -'::asdf_version -- the version prefix to use when querying the latest version -same as the first argument after the "@" -used for asdf compatibility:' \ -&& ret=0 -;; -(which) -_arguments "${_arguments_options[@]}" \ -'-t+[Use a specific tool@version -e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ -'--tool=[Use a specific tool@version -e.g.\: \`rtx which npm --tool=node@20\`]:TOOL@VERSION: ' \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'(--version)--plugin[Show the plugin name instead of the path]' \ -'(--plugin)--version[Show the version instead of the path]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -':bin_name -- The bin name to look up:' \ -&& ret=0 -;; -(render-help) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(render-mangen) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-y[Answer yes to all prompts]' \ -'--yes[Answer yes to all prompts]' \ -'-h[Print help]' \ -'--help[Print help]' \ -&& ret=0 -;; -(self-update) -_arguments "${_arguments_options[@]}" \ -'-j+[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--jobs=[Number of plugins and runtimes to install in parallel -\[default\: 4\]]: : ' \ -'--log-level=[Set the log output verbosity]:LEVEL: ' \ -'-f[Update even if already up to date]' \ -'--force[Update even if already up to date]' \ -'--no-plugins[Disable auto-updating plugins]' \ -'-y[Skip confirmation prompt]' \ -'--yes[Skip confirmation prompt]' \ -'--debug[Sets log level to debug]' \ -'--trace[Sets log level to trace]' \ -'-r[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'--raw[Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1]' \ -'*-v[Show installation output]' \ -'*--verbose[Show installation output]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'::version -- Update to a specific version:' \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__help_commands" \ -"*::: :->help" \ -&& ret=0 + esac - case $state in - (help) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-help-command-$line[1]:" - case $line[1] in - (activate) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(alias) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__help__alias_commands" \ -"*::: :->alias" \ -&& ret=0 + return ret +} +__rtx_direnv_activate_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_direnv_envrc_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_direnv_exec_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_doctor_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_env_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--json=[Output in JSON format]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]: :(bash fish nu xonsh zsh)' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_env_vars_cmd() { + _arguments -s -S \ + '*::env_vars:' \ + '--file=[The TOML file to update]:: :' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--remove=[Remove the environment variable from config file]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_exec_cmd() { + _arguments -s -S \ + '*::command:' \ + '*::tool:__rtx_tool_versions' \ + '--cd=[Change to this directory before executing the command]:: :' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-c --command)'{-c,--command}'=[Command string to execute]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_global_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--fuzzy=[Save fuzzy version to `~/.tool-versions`]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--path=[Get the path of the global config file]' \ + '--pin=[Save exact version to `~/.tool-versions`]' \ + '--remove=[Remove the plugin(s) from ~/.tool-versions]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_hook_env_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--status=[Show "rtx: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]: :(bash fish nu xonsh zsh)' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_implode_cmd() { + _arguments -s -S \ + '--config=[Also remove config directory]' \ + '--dry-run=[List directories that would be removed without actually removing them]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_install_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_latest_cmd() { + _arguments -s -S \ + '1::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_link_cmd() { + _arguments -s -S \ + '1: :_directories' \ + '1::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_local_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--fuzzy=[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--path=[Get the path of the config file]' \ + '--pin=[Save exact version to `.tool-versions`]' \ + '--remove=[Remove the plugin(s) from .tool-versions]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-p --parent)'{-p,--parent}'[Recurse up to find a .tool-versions file rather than using the current directory only]' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_ls_cmd() { + _arguments -s -S \ + '--json=[Output in json format]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--prefix=[Display versions matching this prefix]:: :' \ + '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ + '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ + '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ + '(-p --plugin)'{-p,--plugin}'=[Only show tool versions from [PLUGIN]]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_ls_remote_cmd() { + _arguments -s -S \ + '*::plugin:' \ + '*::prefix:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_outdated_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_plugins_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--refs=[show the git refs for each plugin]' \ + '(-c --core)'{-c,--core}'[The built-in plugins only]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 - case $state in - (alias) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-help-alias-command-$line[1]:" - case $line[1] in - (get) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(set) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(unset) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (a|add|i|install) __rtx_plugins_install_cmd && ret=0 ;; + (l|link) __rtx_plugins_link_cmd && ret=0 ;; + (list|ls) __rtx_plugins_ls_cmd && ret=0 ;; + (list-all|list-remote|ls-remote) __rtx_plugins_ls_remote_cmd && ret=0 ;; + (remove|rm|uninstall) __rtx_plugins_uninstall_cmd && ret=0 ;; + (upgrade|update) __rtx_plugins_update_cmd && ret=0 ;; + esac ;; -esac -;; -(asdf) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(bin-paths) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(cache) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__help__cache_commands" \ -"*::: :->cache" \ -&& ret=0 + esac - case $state in - (cache) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-help-cache-command-$line[1]:" - case $line[1] in - (clear) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; -(completion) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(current) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(deactivate) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(direnv) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__help__direnv_commands" \ -"*::: :->direnv" \ -&& ret=0 + return ret +} +__rtx_plugins_install_cmd() { + _arguments -s -S \ + '1: :_urls' \ + '*::name:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-a --all)'{-a,--all}'[Install all missing plugins]' \ + '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_plugins_link_cmd() { + _arguments -s -S \ + '*::name:' \ + '1: :_directories' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_plugins_ls_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--refs=[Show the git refs for each plugin]' \ + '(-c --core)'{-c,--core}'[The built-in plugins only]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_plugins_ls_remote_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--only-names=[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_plugins_uninstall_cmd() { + _arguments -s -S \ + '*::plugin:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_plugins_update_cmd() { + _arguments -s -S \ + '*::plugin:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_prune_cmd() { + _arguments -s -S \ + '*::plugins:' \ + '--dry-run=[Do not actually delete anything]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_render_completion_cmd() { + _arguments -s -S \ + '*::shell:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_render_help_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_render_mangen_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_reshim_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_self_update_cmd() { + _arguments -s -S \ + '*::version:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--no-plugins=[Disable auto-updating plugins]' \ + '(-f --force)'{-f,--force}'[Update even if already up to date]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_settings_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 - case $state in - (direnv) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-help-direnv-command-$line[1]:" - case $line[1] in - (envrc) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(exec) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(activate) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (get) __rtx_settings_get_cmd && ret=0 ;; + (list|ls) __rtx_settings_ls_cmd && ret=0 ;; + (add|create|set) __rtx_settings_set_cmd && ret=0 ;; + (del|delete|remove|rm|unset) __rtx_settings_unset_cmd && ret=0 ;; + esac ;; -esac -;; -(doctor) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(env) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(env-vars) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(exec) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(global) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(hook-env) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(implode) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(install) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(latest) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(link) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(local) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls-remote) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(outdated) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(plugins) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__help__plugins_commands" \ -"*::: :->plugins" \ -&& ret=0 + esac - case $state in - (plugins) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-help-plugins-command-$line[1]:" - case $line[1] in - (install) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(link) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls-remote) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(uninstall) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(update) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; -(prune) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(reshim) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(settings) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__help__settings_commands" \ -"*::: :->settings" \ -&& ret=0 + return ret +} +__rtx_settings_get_cmd() { + _arguments -s -S \ + '*::key:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_settings_ls_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_settings_set_cmd() { + _arguments -s -S \ + '*::key:' \ + '*::value:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_settings_unset_cmd() { + _arguments -s -S \ + '*::key:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_shell_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_sync_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 - case $state in - (settings) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-help-settings-command-$line[1]:" - case $line[1] in - (get) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(ls) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(set) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(unset) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (node) __rtx_sync_node_cmd && ret=0 ;; + (python) __rtx_sync_python_cmd && ret=0 ;; + esac ;; -esac -;; -(shell) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(sync) -_arguments "${_arguments_options[@]}" \ -":: :_rtx__help__sync_commands" \ -"*::: :->sync" \ -&& ret=0 + esac - case $state in - (sync) - words=($line[1] "${words[@]}") - (( CURRENT += 1 )) - curcontext="${curcontext%:*:*}:rtx-help-sync-command-$line[1]:" - case $line[1] in - (node) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(python) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; -(trust) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(uninstall) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(upgrade) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(use) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(version) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(where) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(which) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(render-help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(render-mangen) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(self-update) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; -(help) -_arguments "${_arguments_options[@]}" \ -&& ret=0 -;; - esac - ;; -esac -;; - esac - ;; -esac + return ret +} +__rtx_sync_node_cmd() { + _arguments -s -S \ + '--brew=[Get tool versions from Homebrew]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--nodenv=[Get tool versions from nodenv]' \ + '--nvm=[Get tool versions from nvm]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_sync_python_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--pyenv=[Get tool versions from pyenv]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_trust_cmd() { + _arguments -s -S \ + '1: :_files' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--untrust=[No longer trust this config]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_uninstall_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-a --all)'{-a,--all}'[Delete all installed versions]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_upgrade_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_use_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--fuzzy=[Save fuzzy version to config file]' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--pin=[Save exact version to config file]' \ + '--remove=[Remove the tool(s) from config file]:: :' \ + '(-e --env)'{-e,--env}'=[[experimental] Modify an environment-specific config file like .rtx..toml]:: :' \ + '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_version_cmd() { + _arguments -s -S \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_where_cmd() { + _arguments -s -S \ + '1::tool:__rtx_tool_versions' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +__rtx_which_cmd() { + _arguments -s -S \ + '*::bin_name:' \ + '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + '--plugin=[Show the plugin name instead of the path]' \ + '--version=[Show the version instead of the path]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:: :' \ + '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[_rtx_cmds] )) || +_rtx_cmds() { + local commands; commands=( + 'activate:Initializes rtx in the current shell' + {a,alias}':Manage aliases' + 'bin-paths:List all the active runtime bin paths' + 'cache:Manage the rtx cache' + 'completion:Generate shell completions' + 'current:Shows current active and installed runtime versions' + 'deactivate:Disable rtx for current shell session' + 'direnv:Output direnv function to use rtx inside direnv' + 'doctor:Check rtx installation for possible problems.' + {e,env}':Exports env vars to activate rtx a single time' + 'env-vars:Manage environment variables' + {x,exec}':Execute a command with tool(s) set' + 'implode:Removes rtx CLI and all related data' + {i,install}':Install a tool version' + 'latest:Gets the latest available version for a plugin' + 'link:Symlinks a tool version into rtx' + {list,ls}':List installed and/or currently selected tool versions' + 'ls-remote:List runtime versions available for install' + 'outdated:Shows outdated tool versions' + {p,plugins}':Manage plugins' + 'prune:Delete unused versions of tools' + 'reshim:rebuilds the shim farm' + 'self-update:Updates rtx itself' + 'settings:Manage settings' + 'shell:Sets a tool version for the current shell session' + 'sync:Add tool versions from external tools to rtx' + 'trust:Marks a config file as trusted' + 'uninstall:Removes runtime versions' + 'upgrade:Upgrades outdated tool versions' + {u,use}':Change the active version of a tool locally or globally.' + 'version:Show rtx version' + 'where:Display the installation path for a runtime' + 'which:Shows the path that a bin name points to' + ) + _describe -t commands 'command' commands "$@" } -(( $+functions[_rtx_commands] )) || -_rtx_commands() { - local commands; commands=( -'activate:Initializes rtx in the current shell' \ -'alias:Manage aliases' \ -'a:Manage aliases' \ -'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ -'bin-paths:List all the active runtime bin paths' \ -'cache:Manage the rtx cache' \ -'completion:Generate shell completions' \ -'current:Shows current active and installed runtime versions' \ -'deactivate:Disable rtx for current shell session' \ -'direnv:Output direnv function to use rtx inside direnv' \ -'doctor:Check rtx installation for possible problems.' \ -'env:Exports env vars to activate rtx a single time' \ -'e:Exports env vars to activate rtx a single time' \ -'env-vars:Manage environment variables' \ -'exec:Execute a command with tool(s) set' \ -'x:Execute a command with tool(s) set' \ -'global:Sets/gets the global tool version(s)' \ -'hook-env:\[internal\] called by activate hook to update env vars directory change' \ -'implode:Removes rtx CLI and all related data' \ -'install:Install a tool version' \ -'i:Install a tool version' \ -'latest:Gets the latest available version for a plugin' \ -'link:Symlinks a tool version into rtx' \ -'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ -'ls:List installed and/or currently selected tool versions' \ -'list:List installed and/or currently selected tool versions' \ -'ls-remote:List runtime versions available for install' \ -'outdated:Shows outdated tool versions' \ -'plugins:Manage plugins' \ -'p:Manage plugins' \ -'prune:Delete unused versions of tools' \ -'reshim:rebuilds the shim farm' \ -'settings:Manage settings' \ -'shell:Sets a tool version for the current shell session' \ -'sync:Add tool versions from external tools to rtx' \ -'trust:Marks a config file as trusted' \ -'uninstall:Removes runtime versions' \ -'upgrade:Upgrades outdated tool versions' \ -'use:Change the active version of a tool locally or globally.' \ -'u:Change the active version of a tool locally or globally.' \ -'version:Show rtx version' \ -'where:Display the installation path for a runtime' \ -'which:Shows the path that a bin name points to' \ -'render-help:internal command to generate markdown from help' \ -'render-mangen:internal command to generate markdown from help' \ -'self-update:Updates rtx itself' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx commands' commands "$@" -} -(( $+functions[_rtx__activate_commands] )) || -_rtx__activate_commands() { - local commands; commands=() - _describe -t commands 'rtx activate commands' commands "$@" -} -(( $+functions[_rtx__direnv__activate_commands] )) || -_rtx__direnv__activate_commands() { - local commands; commands=() - _describe -t commands 'rtx direnv activate commands' commands "$@" -} -(( $+functions[_rtx__direnv__help__activate_commands] )) || -_rtx__direnv__help__activate_commands() { - local commands; commands=() - _describe -t commands 'rtx direnv help activate commands' commands "$@" -} -(( $+functions[_rtx__help__activate_commands] )) || -_rtx__help__activate_commands() { - local commands; commands=() - _describe -t commands 'rtx help activate commands' commands "$@" -} -(( $+functions[_rtx__help__direnv__activate_commands] )) || -_rtx__help__direnv__activate_commands() { - local commands; commands=() - _describe -t commands 'rtx help direnv activate commands' commands "$@" -} -(( $+functions[_rtx__alias_commands] )) || -_rtx__alias_commands() { - local commands; commands=( -'get:Show an alias for a plugin' \ -'ls:List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in \`bin/list-aliases\`.' \ -'list:List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in \`bin/list-aliases\`.' \ -'set:Add/update an alias for a plugin' \ -'add:Add/update an alias for a plugin' \ -'create:Add/update an alias for a plugin' \ -'unset:Clears an alias for a plugin' \ -'rm:Clears an alias for a plugin' \ -'remove:Clears an alias for a plugin' \ -'delete:Clears an alias for a plugin' \ -'del:Clears an alias for a plugin' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx alias commands' commands "$@" -} -(( $+functions[_rtx__help__alias_commands] )) || -_rtx__help__alias_commands() { - local commands; commands=( -'get:Show an alias for a plugin' \ -'ls:List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in \`bin/list-aliases\`.' \ -'set:Add/update an alias for a plugin' \ -'unset:Clears an alias for a plugin' \ - ) - _describe -t commands 'rtx help alias commands' commands "$@" -} -(( $+functions[_rtx__asdf_commands] )) || -_rtx__asdf_commands() { - local commands; commands=() - _describe -t commands 'rtx asdf commands' commands "$@" -} -(( $+functions[_rtx__help__asdf_commands] )) || -_rtx__help__asdf_commands() { - local commands; commands=() - _describe -t commands 'rtx help asdf commands' commands "$@" -} -(( $+functions[_rtx__bin-paths_commands] )) || -_rtx__bin-paths_commands() { - local commands; commands=() - _describe -t commands 'rtx bin-paths commands' commands "$@" -} -(( $+functions[_rtx__help__bin-paths_commands] )) || -_rtx__help__bin-paths_commands() { - local commands; commands=() - _describe -t commands 'rtx help bin-paths commands' commands "$@" -} -(( $+functions[_rtx__cache_commands] )) || -_rtx__cache_commands() { - local commands; commands=( -'clear:Deletes all cache files in rtx' \ -'c:Deletes all cache files in rtx' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx cache commands' commands "$@" -} -(( $+functions[_rtx__help__cache_commands] )) || -_rtx__help__cache_commands() { - local commands; commands=( -'clear:Deletes all cache files in rtx' \ - ) - _describe -t commands 'rtx help cache commands' commands "$@" -} -(( $+functions[_rtx__cache__clear_commands] )) || -_rtx__cache__clear_commands() { - local commands; commands=() - _describe -t commands 'rtx cache clear commands' commands "$@" -} -(( $+functions[_rtx__cache__help__clear_commands] )) || -_rtx__cache__help__clear_commands() { - local commands; commands=() - _describe -t commands 'rtx cache help clear commands' commands "$@" -} -(( $+functions[_rtx__help__cache__clear_commands] )) || -_rtx__help__cache__clear_commands() { - local commands; commands=() - _describe -t commands 'rtx help cache clear commands' commands "$@" -} -(( $+functions[_rtx__completion_commands] )) || -_rtx__completion_commands() { - local commands; commands=() - _describe -t commands 'rtx completion commands' commands "$@" -} -(( $+functions[_rtx__help__completion_commands] )) || -_rtx__help__completion_commands() { - local commands; commands=() - _describe -t commands 'rtx help completion commands' commands "$@" -} -(( $+functions[_rtx__current_commands] )) || -_rtx__current_commands() { - local commands; commands=() - _describe -t commands 'rtx current commands' commands "$@" -} -(( $+functions[_rtx__help__current_commands] )) || -_rtx__help__current_commands() { - local commands; commands=() - _describe -t commands 'rtx help current commands' commands "$@" -} -(( $+functions[_rtx__deactivate_commands] )) || -_rtx__deactivate_commands() { - local commands; commands=() - _describe -t commands 'rtx deactivate commands' commands "$@" -} -(( $+functions[_rtx__help__deactivate_commands] )) || -_rtx__help__deactivate_commands() { - local commands; commands=() - _describe -t commands 'rtx help deactivate commands' commands "$@" -} -(( $+functions[_rtx__direnv_commands] )) || -_rtx__direnv_commands() { - local commands; commands=( -'envrc:\[internal\] This is an internal command that writes an envrc file -for direnv to consume.' \ -'exec:\[internal\] This is an internal command that writes an envrc file -for direnv to consume.' \ -'activate:Output direnv function to use rtx inside direnv' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx direnv commands' commands "$@" -} -(( $+functions[_rtx__help__direnv_commands] )) || -_rtx__help__direnv_commands() { - local commands; commands=( -'envrc:\[internal\] This is an internal command that writes an envrc file -for direnv to consume.' \ -'exec:\[internal\] This is an internal command that writes an envrc file -for direnv to consume.' \ -'activate:Output direnv function to use rtx inside direnv' \ - ) - _describe -t commands 'rtx help direnv commands' commands "$@" -} -(( $+functions[_rtx__doctor_commands] )) || -_rtx__doctor_commands() { - local commands; commands=() - _describe -t commands 'rtx doctor commands' commands "$@" -} -(( $+functions[_rtx__help__doctor_commands] )) || -_rtx__help__doctor_commands() { - local commands; commands=() - _describe -t commands 'rtx help doctor commands' commands "$@" -} -(( $+functions[_rtx__env_commands] )) || -_rtx__env_commands() { - local commands; commands=() - _describe -t commands 'rtx env commands' commands "$@" -} -(( $+functions[_rtx__help__env_commands] )) || -_rtx__help__env_commands() { - local commands; commands=() - _describe -t commands 'rtx help env commands' commands "$@" -} -(( $+functions[_rtx__env-vars_commands] )) || -_rtx__env-vars_commands() { - local commands; commands=() - _describe -t commands 'rtx env-vars commands' commands "$@" -} -(( $+functions[_rtx__help__env-vars_commands] )) || -_rtx__help__env-vars_commands() { - local commands; commands=() - _describe -t commands 'rtx help env-vars commands' commands "$@" -} -(( $+functions[_rtx__direnv__envrc_commands] )) || -_rtx__direnv__envrc_commands() { - local commands; commands=() - _describe -t commands 'rtx direnv envrc commands' commands "$@" -} -(( $+functions[_rtx__direnv__help__envrc_commands] )) || -_rtx__direnv__help__envrc_commands() { - local commands; commands=() - _describe -t commands 'rtx direnv help envrc commands' commands "$@" -} -(( $+functions[_rtx__help__direnv__envrc_commands] )) || -_rtx__help__direnv__envrc_commands() { - local commands; commands=() - _describe -t commands 'rtx help direnv envrc commands' commands "$@" -} -(( $+functions[_rtx__direnv__exec_commands] )) || -_rtx__direnv__exec_commands() { - local commands; commands=() - _describe -t commands 'rtx direnv exec commands' commands "$@" -} -(( $+functions[_rtx__direnv__help__exec_commands] )) || -_rtx__direnv__help__exec_commands() { - local commands; commands=() - _describe -t commands 'rtx direnv help exec commands' commands "$@" -} -(( $+functions[_rtx__exec_commands] )) || -_rtx__exec_commands() { - local commands; commands=() - _describe -t commands 'rtx exec commands' commands "$@" -} -(( $+functions[_rtx__help__direnv__exec_commands] )) || -_rtx__help__direnv__exec_commands() { - local commands; commands=() - _describe -t commands 'rtx help direnv exec commands' commands "$@" -} -(( $+functions[_rtx__help__exec_commands] )) || -_rtx__help__exec_commands() { - local commands; commands=() - _describe -t commands 'rtx help exec commands' commands "$@" -} -(( $+functions[_rtx__alias__get_commands] )) || -_rtx__alias__get_commands() { - local commands; commands=() - _describe -t commands 'rtx alias get commands' commands "$@" -} -(( $+functions[_rtx__alias__help__get_commands] )) || -_rtx__alias__help__get_commands() { - local commands; commands=() - _describe -t commands 'rtx alias help get commands' commands "$@" -} -(( $+functions[_rtx__help__alias__get_commands] )) || -_rtx__help__alias__get_commands() { - local commands; commands=() - _describe -t commands 'rtx help alias get commands' commands "$@" -} -(( $+functions[_rtx__help__settings__get_commands] )) || -_rtx__help__settings__get_commands() { - local commands; commands=() - _describe -t commands 'rtx help settings get commands' commands "$@" -} -(( $+functions[_rtx__settings__get_commands] )) || -_rtx__settings__get_commands() { - local commands; commands=() - _describe -t commands 'rtx settings get commands' commands "$@" -} -(( $+functions[_rtx__settings__help__get_commands] )) || -_rtx__settings__help__get_commands() { - local commands; commands=() - _describe -t commands 'rtx settings help get commands' commands "$@" -} -(( $+functions[_rtx__global_commands] )) || -_rtx__global_commands() { - local commands; commands=() - _describe -t commands 'rtx global commands' commands "$@" -} -(( $+functions[_rtx__help__global_commands] )) || -_rtx__help__global_commands() { - local commands; commands=() - _describe -t commands 'rtx help global commands' commands "$@" -} -(( $+functions[_rtx__alias__help_commands] )) || -_rtx__alias__help_commands() { - local commands; commands=( -'get:Show an alias for a plugin' \ -'ls:List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in \`bin/list-aliases\`.' \ -'set:Add/update an alias for a plugin' \ -'unset:Clears an alias for a plugin' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx alias help commands' commands "$@" -} -(( $+functions[_rtx__alias__help__help_commands] )) || -_rtx__alias__help__help_commands() { - local commands; commands=() - _describe -t commands 'rtx alias help help commands' commands "$@" -} -(( $+functions[_rtx__cache__help_commands] )) || -_rtx__cache__help_commands() { - local commands; commands=( -'clear:Deletes all cache files in rtx' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx cache help commands' commands "$@" -} -(( $+functions[_rtx__cache__help__help_commands] )) || -_rtx__cache__help__help_commands() { - local commands; commands=() - _describe -t commands 'rtx cache help help commands' commands "$@" -} -(( $+functions[_rtx__direnv__help_commands] )) || -_rtx__direnv__help_commands() { - local commands; commands=( -'envrc:\[internal\] This is an internal command that writes an envrc file -for direnv to consume.' \ -'exec:\[internal\] This is an internal command that writes an envrc file -for direnv to consume.' \ -'activate:Output direnv function to use rtx inside direnv' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx direnv help commands' commands "$@" -} -(( $+functions[_rtx__direnv__help__help_commands] )) || -_rtx__direnv__help__help_commands() { - local commands; commands=() - _describe -t commands 'rtx direnv help help commands' commands "$@" -} -(( $+functions[_rtx__help_commands] )) || -_rtx__help_commands() { - local commands; commands=( -'activate:Initializes rtx in the current shell' \ -'alias:Manage aliases' \ -'asdf:\[internal\] simulates asdf for plugins that call "asdf" internally' \ -'bin-paths:List all the active runtime bin paths' \ -'cache:Manage the rtx cache' \ -'completion:Generate shell completions' \ -'current:Shows current active and installed runtime versions' \ -'deactivate:Disable rtx for current shell session' \ -'direnv:Output direnv function to use rtx inside direnv' \ -'doctor:Check rtx installation for possible problems.' \ -'env:Exports env vars to activate rtx a single time' \ -'env-vars:Manage environment variables' \ -'exec:Execute a command with tool(s) set' \ -'global:Sets/gets the global tool version(s)' \ -'hook-env:\[internal\] called by activate hook to update env vars directory change' \ -'implode:Removes rtx CLI and all related data' \ -'install:Install a tool version' \ -'latest:Gets the latest available version for a plugin' \ -'link:Symlinks a tool version into rtx' \ -'local:Sets/gets tool version in local .tool-versions or .rtx.toml' \ -'ls:List installed and/or currently selected tool versions' \ -'ls-remote:List runtime versions available for install' \ -'outdated:Shows outdated tool versions' \ -'plugins:Manage plugins' \ -'prune:Delete unused versions of tools' \ -'reshim:rebuilds the shim farm' \ -'settings:Manage settings' \ -'shell:Sets a tool version for the current shell session' \ -'sync:Add tool versions from external tools to rtx' \ -'trust:Marks a config file as trusted' \ -'uninstall:Removes runtime versions' \ -'upgrade:Upgrades outdated tool versions' \ -'use:Change the active version of a tool locally or globally.' \ -'version:Show rtx version' \ -'where:Display the installation path for a runtime' \ -'which:Shows the path that a bin name points to' \ -'render-help:internal command to generate markdown from help' \ -'render-mangen:internal command to generate markdown from help' \ -'self-update:Updates rtx itself' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx help commands' commands "$@" -} -(( $+functions[_rtx__help__help_commands] )) || -_rtx__help__help_commands() { - local commands; commands=() - _describe -t commands 'rtx help help commands' commands "$@" -} -(( $+functions[_rtx__plugins__help_commands] )) || -_rtx__plugins__help_commands() { - local commands; commands=( -'install:Install a plugin' \ -'link:Symlinks a plugin into rtx' \ -'ls:List installed plugins' \ -'ls-remote:List all available remote plugins' \ -'uninstall:Removes a plugin' \ -'update:Updates a plugin to the latest version' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx plugins help commands' commands "$@" -} -(( $+functions[_rtx__plugins__help__help_commands] )) || -_rtx__plugins__help__help_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins help help commands' commands "$@" -} -(( $+functions[_rtx__settings__help_commands] )) || -_rtx__settings__help_commands() { - local commands; commands=( -'get:Show a current setting' \ -'ls:Show current settings' \ -'set:Add/update a setting' \ -'unset:Clears a setting' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx settings help commands' commands "$@" -} -(( $+functions[_rtx__settings__help__help_commands] )) || -_rtx__settings__help__help_commands() { - local commands; commands=() - _describe -t commands 'rtx settings help help commands' commands "$@" -} -(( $+functions[_rtx__sync__help_commands] )) || -_rtx__sync__help_commands() { - local commands; commands=( -'node:Symlinks all tool versions from an external tool into rtx' \ -'python:Symlinks all tool versions from an external tool into rtx' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx sync help commands' commands "$@" -} -(( $+functions[_rtx__sync__help__help_commands] )) || -_rtx__sync__help__help_commands() { - local commands; commands=() - _describe -t commands 'rtx sync help help commands' commands "$@" -} -(( $+functions[_rtx__help__hook-env_commands] )) || -_rtx__help__hook-env_commands() { - local commands; commands=() - _describe -t commands 'rtx help hook-env commands' commands "$@" -} -(( $+functions[_rtx__hook-env_commands] )) || -_rtx__hook-env_commands() { - local commands; commands=() - _describe -t commands 'rtx hook-env commands' commands "$@" -} -(( $+functions[_rtx__help__implode_commands] )) || -_rtx__help__implode_commands() { - local commands; commands=() - _describe -t commands 'rtx help implode commands' commands "$@" -} -(( $+functions[_rtx__implode_commands] )) || -_rtx__implode_commands() { - local commands; commands=() - _describe -t commands 'rtx implode commands' commands "$@" -} -(( $+functions[_rtx__help__install_commands] )) || -_rtx__help__install_commands() { - local commands; commands=() - _describe -t commands 'rtx help install commands' commands "$@" -} -(( $+functions[_rtx__help__plugins__install_commands] )) || -_rtx__help__plugins__install_commands() { - local commands; commands=() - _describe -t commands 'rtx help plugins install commands' commands "$@" -} -(( $+functions[_rtx__install_commands] )) || -_rtx__install_commands() { - local commands; commands=() - _describe -t commands 'rtx install commands' commands "$@" -} -(( $+functions[_rtx__plugins__help__install_commands] )) || -_rtx__plugins__help__install_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins help install commands' commands "$@" -} -(( $+functions[_rtx__plugins__install_commands] )) || -_rtx__plugins__install_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins install commands' commands "$@" -} -(( $+functions[_rtx__help__latest_commands] )) || -_rtx__help__latest_commands() { - local commands; commands=() - _describe -t commands 'rtx help latest commands' commands "$@" -} -(( $+functions[_rtx__latest_commands] )) || -_rtx__latest_commands() { - local commands; commands=() - _describe -t commands 'rtx latest commands' commands "$@" -} -(( $+functions[_rtx__help__link_commands] )) || -_rtx__help__link_commands() { - local commands; commands=() - _describe -t commands 'rtx help link commands' commands "$@" -} -(( $+functions[_rtx__help__plugins__link_commands] )) || -_rtx__help__plugins__link_commands() { - local commands; commands=() - _describe -t commands 'rtx help plugins link commands' commands "$@" -} -(( $+functions[_rtx__link_commands] )) || -_rtx__link_commands() { - local commands; commands=() - _describe -t commands 'rtx link commands' commands "$@" -} -(( $+functions[_rtx__plugins__help__link_commands] )) || -_rtx__plugins__help__link_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins help link commands' commands "$@" -} -(( $+functions[_rtx__plugins__link_commands] )) || -_rtx__plugins__link_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins link commands' commands "$@" -} -(( $+functions[_rtx__help__local_commands] )) || -_rtx__help__local_commands() { - local commands; commands=() - _describe -t commands 'rtx help local commands' commands "$@" -} -(( $+functions[_rtx__local_commands] )) || -_rtx__local_commands() { - local commands; commands=() - _describe -t commands 'rtx local commands' commands "$@" -} -(( $+functions[_rtx__alias__help__ls_commands] )) || -_rtx__alias__help__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx alias help ls commands' commands "$@" -} -(( $+functions[_rtx__alias__ls_commands] )) || -_rtx__alias__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx alias ls commands' commands "$@" -} -(( $+functions[_rtx__help__alias__ls_commands] )) || -_rtx__help__alias__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx help alias ls commands' commands "$@" -} -(( $+functions[_rtx__help__ls_commands] )) || -_rtx__help__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx help ls commands' commands "$@" -} -(( $+functions[_rtx__help__plugins__ls_commands] )) || -_rtx__help__plugins__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx help plugins ls commands' commands "$@" -} -(( $+functions[_rtx__help__settings__ls_commands] )) || -_rtx__help__settings__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx help settings ls commands' commands "$@" -} -(( $+functions[_rtx__ls_commands] )) || -_rtx__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx ls commands' commands "$@" -} -(( $+functions[_rtx__plugins__help__ls_commands] )) || -_rtx__plugins__help__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins help ls commands' commands "$@" -} -(( $+functions[_rtx__plugins__ls_commands] )) || -_rtx__plugins__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins ls commands' commands "$@" -} -(( $+functions[_rtx__settings__help__ls_commands] )) || -_rtx__settings__help__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx settings help ls commands' commands "$@" -} -(( $+functions[_rtx__settings__ls_commands] )) || -_rtx__settings__ls_commands() { - local commands; commands=() - _describe -t commands 'rtx settings ls commands' commands "$@" -} -(( $+functions[_rtx__help__ls-remote_commands] )) || -_rtx__help__ls-remote_commands() { - local commands; commands=() - _describe -t commands 'rtx help ls-remote commands' commands "$@" -} -(( $+functions[_rtx__help__plugins__ls-remote_commands] )) || -_rtx__help__plugins__ls-remote_commands() { - local commands; commands=() - _describe -t commands 'rtx help plugins ls-remote commands' commands "$@" -} -(( $+functions[_rtx__ls-remote_commands] )) || -_rtx__ls-remote_commands() { - local commands; commands=() - _describe -t commands 'rtx ls-remote commands' commands "$@" -} -(( $+functions[_rtx__plugins__help__ls-remote_commands] )) || -_rtx__plugins__help__ls-remote_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins help ls-remote commands' commands "$@" -} -(( $+functions[_rtx__plugins__ls-remote_commands] )) || -_rtx__plugins__ls-remote_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins ls-remote commands' commands "$@" -} -(( $+functions[_rtx__help__sync__node_commands] )) || -_rtx__help__sync__node_commands() { - local commands; commands=() - _describe -t commands 'rtx help sync node commands' commands "$@" -} -(( $+functions[_rtx__sync__help__node_commands] )) || -_rtx__sync__help__node_commands() { - local commands; commands=() - _describe -t commands 'rtx sync help node commands' commands "$@" -} -(( $+functions[_rtx__sync__node_commands] )) || -_rtx__sync__node_commands() { - local commands; commands=() - _describe -t commands 'rtx sync node commands' commands "$@" -} -(( $+functions[_rtx__help__outdated_commands] )) || -_rtx__help__outdated_commands() { - local commands; commands=() - _describe -t commands 'rtx help outdated commands' commands "$@" -} -(( $+functions[_rtx__outdated_commands] )) || -_rtx__outdated_commands() { - local commands; commands=() - _describe -t commands 'rtx outdated commands' commands "$@" -} -(( $+functions[_rtx__help__plugins_commands] )) || -_rtx__help__plugins_commands() { - local commands; commands=( -'install:Install a plugin' \ -'link:Symlinks a plugin into rtx' \ -'ls:List installed plugins' \ -'ls-remote:List all available remote plugins' \ -'uninstall:Removes a plugin' \ -'update:Updates a plugin to the latest version' \ - ) - _describe -t commands 'rtx help plugins commands' commands "$@" -} -(( $+functions[_rtx__plugins_commands] )) || -_rtx__plugins_commands() { - local commands; commands=( -'install:Install a plugin' \ -'i:Install a plugin' \ -'a:Install a plugin' \ -'link:Symlinks a plugin into rtx' \ -'ls:List installed plugins' \ -'list:List installed plugins' \ -'ls-remote:List all available remote plugins' \ -'list-remote:List all available remote plugins' \ -'uninstall:Removes a plugin' \ -'update:Updates a plugin to the latest version' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx plugins commands' commands "$@" -} -(( $+functions[_rtx__help__prune_commands] )) || -_rtx__help__prune_commands() { - local commands; commands=() - _describe -t commands 'rtx help prune commands' commands "$@" -} -(( $+functions[_rtx__prune_commands] )) || -_rtx__prune_commands() { - local commands; commands=() - _describe -t commands 'rtx prune commands' commands "$@" -} -(( $+functions[_rtx__help__sync__python_commands] )) || -_rtx__help__sync__python_commands() { - local commands; commands=() - _describe -t commands 'rtx help sync python commands' commands "$@" -} -(( $+functions[_rtx__sync__help__python_commands] )) || -_rtx__sync__help__python_commands() { - local commands; commands=() - _describe -t commands 'rtx sync help python commands' commands "$@" -} -(( $+functions[_rtx__sync__python_commands] )) || -_rtx__sync__python_commands() { - local commands; commands=() - _describe -t commands 'rtx sync python commands' commands "$@" -} -(( $+functions[_rtx__help__render-help_commands] )) || -_rtx__help__render-help_commands() { - local commands; commands=() - _describe -t commands 'rtx help render-help commands' commands "$@" -} -(( $+functions[_rtx__render-help_commands] )) || -_rtx__render-help_commands() { - local commands; commands=() - _describe -t commands 'rtx render-help commands' commands "$@" -} -(( $+functions[_rtx__help__render-mangen_commands] )) || -_rtx__help__render-mangen_commands() { - local commands; commands=() - _describe -t commands 'rtx help render-mangen commands' commands "$@" -} -(( $+functions[_rtx__render-mangen_commands] )) || -_rtx__render-mangen_commands() { - local commands; commands=() - _describe -t commands 'rtx render-mangen commands' commands "$@" -} -(( $+functions[_rtx__help__reshim_commands] )) || -_rtx__help__reshim_commands() { - local commands; commands=() - _describe -t commands 'rtx help reshim commands' commands "$@" -} -(( $+functions[_rtx__reshim_commands] )) || -_rtx__reshim_commands() { - local commands; commands=() - _describe -t commands 'rtx reshim commands' commands "$@" -} -(( $+functions[_rtx__help__self-update_commands] )) || -_rtx__help__self-update_commands() { - local commands; commands=() - _describe -t commands 'rtx help self-update commands' commands "$@" -} -(( $+functions[_rtx__self-update_commands] )) || -_rtx__self-update_commands() { - local commands; commands=() - _describe -t commands 'rtx self-update commands' commands "$@" -} -(( $+functions[_rtx__alias__help__set_commands] )) || -_rtx__alias__help__set_commands() { - local commands; commands=() - _describe -t commands 'rtx alias help set commands' commands "$@" -} -(( $+functions[_rtx__alias__set_commands] )) || -_rtx__alias__set_commands() { - local commands; commands=() - _describe -t commands 'rtx alias set commands' commands "$@" -} -(( $+functions[_rtx__help__alias__set_commands] )) || -_rtx__help__alias__set_commands() { - local commands; commands=() - _describe -t commands 'rtx help alias set commands' commands "$@" -} -(( $+functions[_rtx__help__settings__set_commands] )) || -_rtx__help__settings__set_commands() { - local commands; commands=() - _describe -t commands 'rtx help settings set commands' commands "$@" -} -(( $+functions[_rtx__settings__help__set_commands] )) || -_rtx__settings__help__set_commands() { - local commands; commands=() - _describe -t commands 'rtx settings help set commands' commands "$@" -} -(( $+functions[_rtx__settings__set_commands] )) || -_rtx__settings__set_commands() { - local commands; commands=() - _describe -t commands 'rtx settings set commands' commands "$@" -} -(( $+functions[_rtx__help__settings_commands] )) || -_rtx__help__settings_commands() { - local commands; commands=( -'get:Show a current setting' \ -'ls:Show current settings' \ -'set:Add/update a setting' \ -'unset:Clears a setting' \ - ) - _describe -t commands 'rtx help settings commands' commands "$@" -} -(( $+functions[_rtx__settings_commands] )) || -_rtx__settings_commands() { - local commands; commands=( -'get:Show a current setting' \ -'ls:Show current settings' \ -'list:Show current settings' \ -'set:Add/update a setting' \ -'add:Add/update a setting' \ -'create:Add/update a setting' \ -'unset:Clears a setting' \ -'rm:Clears a setting' \ -'remove:Clears a setting' \ -'delete:Clears a setting' \ -'del:Clears a setting' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx settings commands' commands "$@" -} -(( $+functions[_rtx__help__shell_commands] )) || -_rtx__help__shell_commands() { - local commands; commands=() - _describe -t commands 'rtx help shell commands' commands "$@" -} -(( $+functions[_rtx__shell_commands] )) || -_rtx__shell_commands() { - local commands; commands=() - _describe -t commands 'rtx shell commands' commands "$@" -} -(( $+functions[_rtx__help__sync_commands] )) || -_rtx__help__sync_commands() { - local commands; commands=( -'node:Symlinks all tool versions from an external tool into rtx' \ -'python:Symlinks all tool versions from an external tool into rtx' \ - ) - _describe -t commands 'rtx help sync commands' commands "$@" -} -(( $+functions[_rtx__sync_commands] )) || -_rtx__sync_commands() { - local commands; commands=( -'node:Symlinks all tool versions from an external tool into rtx' \ -'python:Symlinks all tool versions from an external tool into rtx' \ -'help:Print this message or the help of the given subcommand(s)' \ - ) - _describe -t commands 'rtx sync commands' commands "$@" -} -(( $+functions[_rtx__help__trust_commands] )) || -_rtx__help__trust_commands() { - local commands; commands=() - _describe -t commands 'rtx help trust commands' commands "$@" -} -(( $+functions[_rtx__trust_commands] )) || -_rtx__trust_commands() { - local commands; commands=() - _describe -t commands 'rtx trust commands' commands "$@" -} -(( $+functions[_rtx__help__plugins__uninstall_commands] )) || -_rtx__help__plugins__uninstall_commands() { - local commands; commands=() - _describe -t commands 'rtx help plugins uninstall commands' commands "$@" -} -(( $+functions[_rtx__help__uninstall_commands] )) || -_rtx__help__uninstall_commands() { - local commands; commands=() - _describe -t commands 'rtx help uninstall commands' commands "$@" -} -(( $+functions[_rtx__plugins__help__uninstall_commands] )) || -_rtx__plugins__help__uninstall_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins help uninstall commands' commands "$@" -} -(( $+functions[_rtx__plugins__uninstall_commands] )) || -_rtx__plugins__uninstall_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins uninstall commands' commands "$@" -} -(( $+functions[_rtx__uninstall_commands] )) || -_rtx__uninstall_commands() { - local commands; commands=() - _describe -t commands 'rtx uninstall commands' commands "$@" -} -(( $+functions[_rtx__alias__help__unset_commands] )) || -_rtx__alias__help__unset_commands() { - local commands; commands=() - _describe -t commands 'rtx alias help unset commands' commands "$@" -} -(( $+functions[_rtx__alias__unset_commands] )) || -_rtx__alias__unset_commands() { - local commands; commands=() - _describe -t commands 'rtx alias unset commands' commands "$@" -} -(( $+functions[_rtx__help__alias__unset_commands] )) || -_rtx__help__alias__unset_commands() { - local commands; commands=() - _describe -t commands 'rtx help alias unset commands' commands "$@" -} -(( $+functions[_rtx__help__settings__unset_commands] )) || -_rtx__help__settings__unset_commands() { - local commands; commands=() - _describe -t commands 'rtx help settings unset commands' commands "$@" -} -(( $+functions[_rtx__settings__help__unset_commands] )) || -_rtx__settings__help__unset_commands() { - local commands; commands=() - _describe -t commands 'rtx settings help unset commands' commands "$@" -} -(( $+functions[_rtx__settings__unset_commands] )) || -_rtx__settings__unset_commands() { - local commands; commands=() - _describe -t commands 'rtx settings unset commands' commands "$@" -} -(( $+functions[_rtx__help__plugins__update_commands] )) || -_rtx__help__plugins__update_commands() { - local commands; commands=() - _describe -t commands 'rtx help plugins update commands' commands "$@" -} -(( $+functions[_rtx__plugins__help__update_commands] )) || -_rtx__plugins__help__update_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins help update commands' commands "$@" -} -(( $+functions[_rtx__plugins__update_commands] )) || -_rtx__plugins__update_commands() { - local commands; commands=() - _describe -t commands 'rtx plugins update commands' commands "$@" -} -(( $+functions[_rtx__help__upgrade_commands] )) || -_rtx__help__upgrade_commands() { - local commands; commands=() - _describe -t commands 'rtx help upgrade commands' commands "$@" -} -(( $+functions[_rtx__upgrade_commands] )) || -_rtx__upgrade_commands() { - local commands; commands=() - _describe -t commands 'rtx upgrade commands' commands "$@" -} -(( $+functions[_rtx__help__use_commands] )) || -_rtx__help__use_commands() { - local commands; commands=() - _describe -t commands 'rtx help use commands' commands "$@" -} -(( $+functions[_rtx__use_commands] )) || -_rtx__use_commands() { - local commands; commands=() - _describe -t commands 'rtx use commands' commands "$@" -} -(( $+functions[_rtx__help__version_commands] )) || -_rtx__help__version_commands() { - local commands; commands=() - _describe -t commands 'rtx help version commands' commands "$@" -} -(( $+functions[_rtx__version_commands] )) || -_rtx__version_commands() { - local commands; commands=() - _describe -t commands 'rtx version commands' commands "$@" -} -(( $+functions[_rtx__help__where_commands] )) || -_rtx__help__where_commands() { - local commands; commands=() - _describe -t commands 'rtx help where commands' commands "$@" -} -(( $+functions[_rtx__where_commands] )) || -_rtx__where_commands() { - local commands; commands=() - _describe -t commands 'rtx where commands' commands "$@" -} -(( $+functions[_rtx__help__which_commands] )) || -_rtx__help__which_commands() { - local commands; commands=() - _describe -t commands 'rtx help which commands' commands "$@" -} -(( $+functions[_rtx__which_commands] )) || -_rtx__which_commands() { - local commands; commands=() - _describe -t commands 'rtx which commands' commands "$@" +__rtx_tool_versions() { + if compset -P '*@'; then + local -a tool_versions; tool_versions=($(rtx ls-remote ${words[CURRENT]})) + _wanted tool_version expl 'version of tool' \ + compadd -a tool_versions + else + local -a plugins; plugins=($(rtx plugins)) + _wanted plugin expl 'plugin name' \ + compadd -S '@' -a plugins + fi } -if [ "$funcstack[1]" = "_rtx" ]; then - _rtx "$@" -else - compdef _rtx rtx -fi +_rtx "$@" +# Local Variables: +# mode: Shell-Script +# sh-indentation: 2 +# indent-tabs-mode: nil +# sh-basic-offset: 2 +# End: +# vim: ft=zsh sw=2 ts=2 et diff --git a/completions/rtx.bash b/completions/rtx.bash index 6e8c7f5ab..991535e57 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -105,6 +105,9 @@ _rtx() { rtx,prune) cmd="rtx__prune" ;; + rtx,render-completion) + cmd="rtx__render__completion" + ;; rtx,render-help) cmd="rtx__render__help" ;; @@ -321,6 +324,9 @@ _rtx() { rtx__help,prune) cmd="rtx__help__prune" ;; + rtx__help,render-completion) + cmd="rtx__help__render__completion" + ;; rtx__help,render-help) cmd="rtx__help__render__help" ;; @@ -553,7 +559,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -y -h -V --jobs --debug --log-level --trace --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" + opts="-j -r -v -y -h -V --jobs --debug --log-level --trace --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -568,7 +574,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -602,7 +608,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -636,7 +642,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -662,7 +668,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -780,7 +786,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -806,7 +812,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -832,7 +838,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -858,7 +864,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -884,7 +890,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -910,7 +916,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -936,7 +942,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -989,18 +995,18 @@ _rtx() { return 0 ;; rtx__completion) - opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash elvish fish powershell zsh" + opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --shell) - COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) return 0 ;; -s) - COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) return 0 ;; --jobs) @@ -1012,7 +1018,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1038,7 +1044,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1064,7 +1070,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1090,7 +1096,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1116,7 +1122,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1142,7 +1148,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1168,7 +1174,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1264,7 +1270,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1298,7 +1304,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1332,7 +1338,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1370,7 +1376,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1400,7 +1406,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -1411,7 +1417,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-help render-mangen self-update help" + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1984,6 +1990,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__render__completion) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__render__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2288,7 +2308,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2314,7 +2334,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2340,7 +2360,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2366,7 +2386,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2392,7 +2412,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2422,7 +2442,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2460,7 +2480,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2486,7 +2506,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2512,7 +2532,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2538,7 +2558,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2676,7 +2696,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2702,7 +2722,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2728,7 +2748,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2754,7 +2774,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2780,7 +2800,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2806,7 +2826,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2832,9 +2852,43 @@ _rtx() { return 0 ;; --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__render__completion) + opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash elvish fish powershell zsh" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + return 0 + ;; + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2858,7 +2912,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2884,7 +2938,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2910,7 +2964,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2936,7 +2990,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2962,7 +3016,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -2988,7 +3042,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3098,7 +3152,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3124,7 +3178,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3150,7 +3204,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3176,7 +3230,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3202,7 +3256,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3284,7 +3338,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3310,7 +3364,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3336,7 +3390,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3362,7 +3416,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3388,7 +3442,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3434,7 +3488,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3460,7 +3514,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3486,7 +3540,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) @@ -3520,7 +3574,7 @@ _rtx() { return 0 ;; --log-level) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; *) diff --git a/completions/rtx.fish b/completions/rtx.fish index 36f69dc0a..2fad590b9 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,6 +1,6 @@ complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_use_subcommand" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_use_subcommand" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -45,6 +45,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "use" -d 'Change the active ver complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_use_subcommand" -f -a "render-completion" -d 'Generate shell completions' complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "render-mangen" -d 'internal command to generate markdown from help' complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' @@ -52,7 +53,7 @@ complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message o complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' complete -c rtx -n "__fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' @@ -65,7 +66,7 @@ complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -82,7 +83,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -93,7 +94,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -103,7 +104,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -113,7 +114,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -130,7 +131,7 @@ complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from asdf" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from asdf" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -140,7 +141,7 @@ complete -c rtx -n "__fish_seen_subcommand_from asdf" -s y -l yes -d 'Answer yes complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -150,7 +151,7 @@ complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s y -l yes -d 'Answe complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -162,7 +163,7 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subco complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -172,10 +173,10 @@ complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcomman complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash '',elvish '',fish '',powershell '',zsh ''}" +complete -c rtx -n "__fish_seen_subcommand_from completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash '',fish '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from completion" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from completion" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from completion" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -185,7 +186,7 @@ complete -c rtx -n "__fish_seen_subcommand_from completion" -s y -l yes -d 'Answ complete -c rtx -n "__fish_seen_subcommand_from completion" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from current" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from current" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -195,7 +196,7 @@ complete -c rtx -n "__fish_seen_subcommand_from current" -s y -l yes -d 'Answer complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -205,7 +206,7 @@ complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s y -l yes -d 'Answ complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -221,7 +222,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subc complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -231,7 +232,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -241,7 +242,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -257,7 +258,7 @@ complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcomma complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from doctor" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from doctor" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -268,7 +269,7 @@ complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print h complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from env" -l json -d 'Output in JSON format' complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from env" -l trace -d 'Sets log level to trace' @@ -281,7 +282,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l file -d 'The TOML f complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l remove -d 'Remove the environment variable from config file' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -293,7 +294,7 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Comman complete -c rtx -n "__fish_seen_subcommand_from exec" -l cd -d 'Change to this directory before executing the command' -r -f -a "(__fish_complete_directories)" complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -304,7 +305,7 @@ complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print hel complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions' complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` @@ -321,7 +322,7 @@ complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print h complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l trace -d 'Sets log level to trace' @@ -332,7 +333,7 @@ complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s y -l yes -d 'Answer complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' complete -c rtx -n "__fish_seen_subcommand_from implode" -l debug -d 'Sets log level to debug' @@ -344,7 +345,7 @@ complete -c rtx -n "__fish_seen_subcommand_from implode" -s y -l yes -d 'Answer complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' @@ -355,7 +356,7 @@ complete -c rtx -n "__fish_seen_subcommand_from install" -s y -l yes -d 'Answer complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from latest" -s i -l installed -d 'Show latest installed instead of available version' complete -c rtx -n "__fish_seen_subcommand_from latest" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from latest" -l trace -d 'Sets log level to trace' @@ -366,7 +367,7 @@ complete -c rtx -n "__fish_seen_subcommand_from latest" -s y -l yes -d 'Answer y complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from link" -s f -l force -d 'Overwrite an existing tool version if it exists' complete -c rtx -n "__fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' @@ -378,7 +379,7 @@ complete -c rtx -n "__fish_seen_subcommand_from link" -s h -l help -d 'Print hel complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only by default this command will only set the tool in the current directory ("$PWD/.tool-versions")' complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` @@ -396,7 +397,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show complete -c rtx -n "__fish_seen_subcommand_from ls" -l prefix -d 'Display versions matching this prefix' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' @@ -412,7 +413,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes t complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -422,7 +423,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answe complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from outdated" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from outdated" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from outdated" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from outdated" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from outdated" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -432,7 +433,7 @@ complete -c rtx -n "__fish_seen_subcommand_from outdated" -s y -l yes -d 'Answer complete -c rtx -n "__fish_seen_subcommand_from outdated" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s c -l core -d 'The built-in plugins only Normally these are not shown' @@ -454,7 +455,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins This will only install plugins that have matching shorthands. @@ -468,7 +469,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s f -l force -d 'Overwrite existing plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' @@ -479,7 +480,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins Same as `rtx plugins ls-remote`' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s c -l core -d 'The built-in plugins only @@ -497,7 +498,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' @@ -509,7 +510,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s p -l purge -d 'Also remove the plugin\'s installs, downloads, and cache' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' @@ -520,7 +521,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l trace -d 'Sets log level to trace' @@ -538,7 +539,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from prune" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from prune" -l trace -d 'Sets log level to trace' @@ -549,7 +550,7 @@ complete -c rtx -n "__fish_seen_subcommand_from prune" -s y -l yes -d 'Answer ye complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from reshim" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from reshim" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -559,7 +560,7 @@ complete -c rtx -n "__fish_seen_subcommand_from reshim" -s y -l yes -d 'Answer y complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -574,7 +575,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_su complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -584,7 +585,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -594,7 +595,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -604,7 +605,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -619,7 +620,7 @@ complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' complete -c rtx -n "__fish_seen_subcommand_from shell" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log level to trace' @@ -630,7 +631,7 @@ complete -c rtx -n "__fish_seen_subcommand_from shell" -s y -l yes -d 'Answer ye complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -643,7 +644,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcom complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l brew -d 'Get tool versions from Homebrew' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nvm -d 'Get tool versions from nvm' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nodenv -d 'Get tool versions from nodenv' @@ -656,7 +657,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l pyenv -d 'Get tool versions from pyenv' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l trace -d 'Sets log level to trace' @@ -670,7 +671,7 @@ complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from trust" -l untrust -d 'No longer trust this config' complete -c rtx -n "__fish_seen_subcommand_from trust" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from trust" -l trace -d 'Sets log level to trace' @@ -681,7 +682,7 @@ complete -c rtx -n "__fish_seen_subcommand_from trust" -s y -l yes -d 'Answer ye complete -c rtx -n "__fish_seen_subcommand_from trust" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s a -l all -d 'Delete all installed versions' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s n -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' @@ -693,7 +694,7 @@ complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answe complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -706,7 +707,7 @@ complete -c rtx -n "__fish_seen_subcommand_from use" -s e -l env -d '[experiment complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' -r -F complete -c rtx -n "__fish_seen_subcommand_from use" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from use" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from use" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from use" -l pin -d 'Save exact version to config file e.g.: `rtx use --pin node@20` will save 20.0.0 as the version' complete -c rtx -n "__fish_seen_subcommand_from use" -l fuzzy -d 'Save fuzzy version to config file @@ -722,7 +723,7 @@ complete -c rtx -n "__fish_seen_subcommand_from use" -s y -l yes -d 'Answer yes complete -c rtx -n "__fish_seen_subcommand_from use" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from version" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from version" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -732,7 +733,7 @@ complete -c rtx -n "__fish_seen_subcommand_from version" -s y -l yes -d 'Answer complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from where" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from where" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -744,7 +745,7 @@ complete -c rtx -n "__fish_seen_subcommand_from which" -s t -l tool -d 'Use a sp e.g.: `rtx which npm --tool=node@20`' -r complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' complete -c rtx -n "__fish_seen_subcommand_from which" -l debug -d 'Sets log level to debug' @@ -754,9 +755,20 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from which" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash '',elvish '',fish '',powershell '',zsh ''}" +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel +[default: 4]' -r +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -l debug -d 'Sets log level to debug' +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -l trace -d 'Sets log level to trace' +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. +Sets --jobs=1' +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s v -l verbose -d 'Show installation output' +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s y -l yes -d 'Answer yes to all prompts' +complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from render-help" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -766,7 +778,7 @@ complete -c rtx -n "__fish_seen_subcommand_from render-help" -s y -l yes -d 'Ans complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -776,7 +788,7 @@ complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s y -l yes -d 'A complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s h -l help -d 'Print help' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r +complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from self-update" -s f -l force -d 'Update even if already up to date' complete -c rtx -n "__fish_seen_subcommand_from self-update" -l no-plugins -d 'Disable auto-updating plugins' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s y -l yes -d 'Skip confirmation prompt' @@ -786,46 +798,47 @@ complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Dir Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-mangen" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-completion" -d 'Generate shell completions' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-mangen" -d 'internal command to generate markdown from help' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' +complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases Shows the aliases that can be specified. diff --git a/justfile b/justfile index 6e8f07706..4fcd43713 100644 --- a/justfile +++ b/justfile @@ -55,11 +55,12 @@ test-coverage: export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$PWD/target}" export PATH="${CARGO_TARGET_DIR}/debug:$PATH" - cargo test + cargo test --all-features cargo build --all-features ./e2e/run_all_tests if [[ "${TEST_TRANCHE:-}" == 0 ]]; then rtx trust + just pre-commit rtx implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then rtx trust @@ -102,9 +103,9 @@ render-help: build # regenerate shell completion files render-completions: build - NO_COLOR=1 rtx completion bash > completions/rtx.bash - NO_COLOR=1 rtx completion zsh > completions/_rtx - NO_COLOR=1 rtx completion fish > completions/rtx.fish + NO_COLOR=1 rtx render-completion bash > completions/rtx.bash + NO_COLOR=1 rtx render-completion zsh > completions/_rtx + NO_COLOR=1 rtx render-completion fish > completions/rtx.fish # regenerate manpages render-mangen: build diff --git a/src/cli/args/log_level.rs b/src/cli/args/log_level.rs index 83ac6a519..08351563e 100644 --- a/src/cli/args/log_level.rs +++ b/src/cli/args/log_level.rs @@ -1,6 +1,5 @@ -use clap::builder::ValueParser; use clap::{Arg, ArgAction}; -use log::{LevelFilter, ParseLevelError}; +use log::LevelFilter; use once_cell::sync::Lazy; use crate::env; @@ -8,10 +7,6 @@ use crate::env; #[derive(Clone)] pub struct LogLevel(pub LevelFilter); -fn parse_log_level(input: &str) -> core::result::Result { - input.parse::() -} - impl LogLevel { pub fn arg() -> clap::Arg { Arg::new("log-level") @@ -20,7 +15,7 @@ impl LogLevel { .help("Set the log output verbosity") .default_value(DEFAULT_LOG_LEVEL.as_str()) .global(true) - .value_parser(ValueParser::new(parse_log_level)) + .value_parser(["error", "warn", "info", "debug", "trace"]) } } diff --git a/src/cli/completion.rs b/src/cli/completion.rs index c445d22ca..a13a16dee 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -1,10 +1,8 @@ -use std::io::Cursor; - -use clap_complete::generate; +use clap::builder::PossibleValue; +use clap::ValueEnum; use color_eyre::eyre::Result; +use std::fmt::Display; -use crate::cli::self_update::SelfUpdate; -use crate::cli::Cli; use crate::config::Config; use crate::output::Output; @@ -13,25 +11,22 @@ use crate::output::Output; #[clap(aliases = ["complete", "completions"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Completion { /// Shell type to generate completions for - #[clap()] - shell: Option, + #[clap(required_unless_present = "shell_type")] + shell: Option, /// Shell type to generate completions for #[clap(long = "shell", short = 's', hide = true)] - shell_type: Option, + shell_type: Option, } impl Completion { pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let shell = match self.shell.or(self.shell_type) { - Some(shell) => shell, - None => panic!("no shell provided"), + let c = match self.shell.or(self.shell_type).unwrap() { + Shell::Bash => include_str!("../../completions/rtx.bash"), + Shell::Fish => include_str!("../../completions/rtx.fish"), + Shell::Zsh => include_str!("../../completions/_rtx"), }; - - let mut c = Cursor::new(Vec::new()); - let mut cmd = Cli::command().subcommand(SelfUpdate::command()); - generate(shell, &mut cmd, "rtx", &mut c); - rtxprintln!(out, "{}", String::from_utf8(c.into_inner()).unwrap()); + rtxprintln!(out, "{}", c.trim()); Ok(()) } @@ -44,3 +39,49 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ rtx completion fish > ~/.config/fish/completions/rtx.fish "# ); + +#[derive(Debug, Clone)] +enum Shell { + Bash, + Fish, + Zsh, +} + +impl ValueEnum for Shell { + fn value_variants<'a>() -> &'a [Self] { + &[Self::Bash, Self::Fish, Self::Zsh] + } + fn from_str(input: &str, _ignore_case: bool) -> std::result::Result { + match input { + "bash" => Ok(Self::Bash), + "fish" => Ok(Self::Fish), + "zsh" => Ok(Self::Zsh), + _ => Err(format!("unknown shell type: {}", input)), + } + } + fn to_possible_value(&self) -> Option { + Some(PossibleValue::new(self.to_string())) + } +} + +impl Display for Shell { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Bash => write!(f, "bash"), + Self::Fish => write!(f, "fish"), + Self::Zsh => write!(f, "zsh"), + } + } +} + +#[cfg(test)] +mod tests { + use crate::assert_cli; + + #[test] + fn test_completion() { + assert_cli!("completion", "zsh"); + assert_cli!("completion", "bash"); + assert_cli!("completion", "fish"); + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b3a4b06f6..4122a400b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -32,6 +32,8 @@ mod ls_remote; mod outdated; mod plugins; mod prune; +#[cfg(feature = "clap_complete")] +mod render_completion; #[cfg(debug_assertions)] mod render_help; #[cfg(feature = "clap_mangen")] @@ -93,6 +95,9 @@ pub enum Commands { Where(r#where::Where), Which(which::Which), + #[cfg(feature = "clap_complete")] + RenderCompletion(render_completion::RenderCompletion), + #[cfg(debug_assertions)] RenderHelp(render_help::RenderHelp), @@ -140,6 +145,9 @@ impl Commands { Self::Where(cmd) => cmd.run(config, out), Self::Which(cmd) => cmd.run(config, out), + #[cfg(feature = "clap_complete")] + Self::RenderCompletion(cmd) => cmd.run(config, out), + #[cfg(debug_assertions)] Self::RenderHelp(cmd) => cmd.run(config, out), diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs new file mode 100644 index 000000000..9b714c8c7 --- /dev/null +++ b/src/cli/render_completion.rs @@ -0,0 +1,315 @@ +use clap::{Arg, ArgAction, Command, ValueHint}; +use std::io::Cursor; +use std::iter::once; + +use clap_complete::generate; +use color_eyre::eyre::Result; +use itertools::Itertools; + +use crate::cli::self_update::SelfUpdate; +use crate::config::Config; +use crate::output::Output; + +/// Generate shell completions +#[derive(Debug, clap::Args)] +#[clap(hide = true, verbatim_doc_comment)] +pub struct RenderCompletion { + /// Shell type to generate completions for + #[clap(required_unless_present = "shell_type")] + shell: Option, + + /// Shell type to generate completions for + #[clap(long = "shell", short = 's', hide = true)] + shell_type: Option, +} + +impl RenderCompletion { + pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + let shell = self.shell.or(self.shell_type).unwrap(); + + let mut c = Cursor::new(Vec::new()); + let mut cmd = crate::cli::Cli::command().subcommand(SelfUpdate::command()); + + if matches!(shell, clap_complete::Shell::Zsh) { + rtxprintln!(out, "{}", ZshComplete::new(cmd).render()?.trim()); + } else { + generate(shell, &mut cmd, "rtx", &mut c); + rtxprintln!(out, "{}", String::from_utf8(c.into_inner()).unwrap()); + } + + Ok(()) + } +} + +struct ZshComplete { + cmd: clap::Command, +} + +impl ZshComplete { + fn new(cmd: clap::Command) -> Self { + Self { cmd } + } + + fn render(&self) -> Result { + let command_funcs = self.render_command_funcs(&[&self.cmd]); + let command_descriptions = self.render_command_descriptions(); + + Ok(formatdoc! {r#" + #compdef rtx + _rtx() {{ + typeset -A opt_args + local context state line curcontext=$curcontext + local ret=1 + + {args} + }} + {command_funcs} + {command_descriptions} + + __rtx_tool_versions() {{ + if compset -P '*@'; then + local -a tool_versions; tool_versions=($(rtx ls-remote ${{words[CURRENT]}})) + _wanted tool_version expl 'version of tool' \ + compadd -a tool_versions + else + local -a plugins; plugins=($(rtx plugins)) + _wanted plugin expl 'plugin name' \ + compadd -S '@' -a plugins + fi + }} + + _rtx "$@" + + # Local Variables: + # mode: Shell-Script + # sh-indentation: 2 + # indent-tabs-mode: nil + # sh-basic-offset: 2 + # End: + # vim: ft=zsh sw=2 ts=2 et + "#, args = self.render_args(&[&self.cmd])}) + } + + fn render_args(&self, cmds: &[&Command]) -> String { + let args = cmds + .iter() + .flat_map(|cmd| cmd.get_arguments()) + .filter(|arg| arg.is_global_set()); + let cmd = cmds.last().unwrap(); + let args = args + .chain(cmd.get_arguments()) + .filter(|arg| !arg.is_hide_set()) + .unique_by(|arg| arg.get_id()) + .sorted_by_key(|arg| (arg.get_short(), arg.get_long(), arg.get_id())) + .map(|arg| self.render_arg(arg)) + .collect::>() + .join(" \\\n "); + if cmd.has_subcommands() { + let subcommands = self.render_subcommands(cmds); + formatdoc! {r#" + _arguments -s -S \ + {args} \ + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 + + {subcommands} + + return ret"# + } + } else { + formatdoc! {r#" + _arguments -s -S \ + {args}"# + } + } + } + + fn render_subcommands(&self, cmds: &[&Command]) -> String { + let cmd = cmds.last().unwrap(); + let cases = cmd + .get_subcommands() + .sorted_by_cached_key(|c| c.get_name()) + .map(|cmd| { + let name = cmd.get_name(); + let mut names = cmd.get_all_aliases().sorted().collect_vec(); + names.push(name); + let names = names.join("|"); + let func = cmds + .iter() + .chain(once(&cmd)) + .map(|c| c.get_name()) + .join("_") + .replace('-', "_"); + format!(" ({names}) __{func}_cmd && ret=0 ;;",) + }) + .collect::>() + .join("\n"); + formatdoc! {r#" + case "$state" in + (args) + curcontext="${{curcontext%:*:*}}:rtx-cmd-$words[1]:" + case $words[1] in + {cases} + esac + ;; + esac"# + } + } + + fn render_arg(&self, arg: &clap::Arg) -> String { + if arg.get_action().takes_values() { + self.render_option(arg) + } else { + self.render_flag(arg) + } + } + + fn render_flag(&self, arg: &clap::Arg) -> String { + // print this: '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + let help = match arg.get_help() { + Some(help) => escape_single_quote(first_line(&help.to_string())).to_string(), + None => return String::new(), + }; + match (arg.get_short(), arg.get_long()) { + (Some(short), Some(long)) => { + format!("'(-{short} --{long})'{{-{short},--{long}}}'[{help}]'",) + } + (Some(short), None) => { + format!("'-{short}[{help}]'",) + } + (None, Some(long)) => format!("'--{long}=[{help}]'"), + (None, None) => self.render_positional(arg), + } + } + + fn render_option(&self, arg: &clap::Arg) -> String { + // print this: '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + let help = match arg.get_help() { + Some(help) => escape_single_quote(first_line(&help.to_string())).to_string(), + None => return String::new(), + }; + let completions = match arg.get_possible_values() { + values if values.is_empty() => ":: :".to_string(), + values => format!( + ": :({})", + values + .iter() + .map(|v| v.get_name()) + .collect::>() + .join(" ") + ), + }; + match (arg.get_short(), arg.get_long()) { + (Some(short), Some(long)) => { + format!("'(-{short} --{long})'{{-{short},--{long}}}'=[{help}]{completions}'",) + } + (Some(short), None) => { + format!("'-{short}[{help}]{completions}'") + } + (None, Some(long)) => format!("'--{long}=[{help}]{completions}'"), + (None, None) => self.render_positional(arg), + } + } + + fn render_positional(&self, arg: &Arg) -> String { + let name = arg.get_id(); + let plural = if matches!(arg.get_action(), ArgAction::Append) { + "*" + } else { + "1" + }; + match arg.get_value_hint() { + ValueHint::DirPath => format!("'{plural}: :_directories'"), + ValueHint::FilePath => format!("'{plural}: :_files'"), + ValueHint::AnyPath => format!("'{plural}: :_files'"), + ValueHint::CommandString => format!("'{plural}: :_command_string -c'"), + ValueHint::ExecutablePath => format!("'{plural}: :_command_names -e'"), + ValueHint::Username => format!("'{plural}: :_users'"), + ValueHint::Hostname => format!("'{plural}: :_hosts'"), + ValueHint::Url => format!("'{plural}: :_urls'"), + ValueHint::EmailAddress => format!("'{plural}: :_email_addresses'"), + _ if name == "tool" => format!("'{plural}::{name}:__rtx_tool_versions'"), + _ => format!("'*::{name}:'"), + } + } + + fn render_command_funcs(&self, cmds: &[&Command]) -> String { + let cmd = cmds.last().unwrap(); + cmd.get_subcommands() + .sorted_by_key(|c| c.get_name()) + .map(|cmd| { + let func = cmds + .iter() + .chain(once(&cmd)) + .map(|c| c.get_name()) + .join("_") + .replace('-', "_"); + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + let args = self.render_args(&cmds); + let subcommand_funcs = self.render_command_funcs(&cmds); + (formatdoc! {r#" + __{func}_cmd() {{ + {args} + }} + {subcommand_funcs}"#, + }) + .trim() + .to_string() + }) + .collect::>() + .join("\n") + } + + fn render_command_descriptions(&self) -> String { + let commands = self + .cmd + .get_subcommands() + .filter(|c| !c.is_hide_set()) + .sorted_by_key(|c| c.get_name()) + .map(|cmd| { + let name = cmd.get_name(); + let about = match cmd.get_about() { + Some(about) => escape_single_quote(first_line(&about.to_string())).to_string(), + None => String::new(), + }; + let aliases = cmd.get_visible_aliases().sorted().collect_vec(); + if aliases.is_empty() { + format!(" '{}:{}'", name, about) + } else { + let aliases = aliases.join(","); + format!(" {{{aliases},{name}}}':{about}'") + } + }) + .collect::>() + .join("\n"); + formatdoc! {r#" + (( $+functions[_rtx_cmds] )) || + _rtx_cmds() {{ + local commands; commands=( + {commands} + ) + _describe -t commands 'command' commands "$@" + }}"#} + } +} + +fn first_line(s: &str) -> &str { + s.lines().next().unwrap_or_default() +} + +fn escape_single_quote(s: &str) -> String { + s.replace('\'', r"'\''") +} + +#[cfg(test)] +mod tests { + use crate::assert_cli; + + #[test] + fn test_completion() { + assert_cli!("render-completion", "bash"); + assert_cli!("render-completion", "fish"); + assert_cli!("render-completion", "zsh"); + } +} diff --git a/src/templates/complete_zsh.tera b/src/templates/complete_zsh.tera new file mode 100644 index 000000000..84221167b --- /dev/null +++ b/src/templates/complete_zsh.tera @@ -0,0 +1,103 @@ +{%- macro escape_help(s) -%} +{{s|replace(from="[", to="\[")|replace(from="]",to="\]")}} +{%- endmacro -%} + +{%- macro arg(arg) -%} +{%- if arg.long and arg.has_value %}'{{ self::option(arg=arg) -}}' +{%- elif arg.long %}'{{ self::flag(arg=arg) -}}' +{%- else %}'{{ self::positional(arg=arg) -}}' +{%- endif -%} +{%- endmacro arg -%} + +{% macro option(arg) -%} +{% if arg.short -%} +(-{{ arg.short }} --{{ arg.long }})'{-{{ arg.short }},--{{ arg.long }}}' +{%- else -%} +--{{ arg.long }} +{%- endif -%} +=[{{self::escape_help(s=arg.help)}}] +{%- if arg.choices | length == 0 -%} +:: : +{%- else -%} +: :({%- for choice in arg.choices -%} +{%- if choice.Single %}{{ choice.Single }} {% else -%}{{ choice |json_encode}} {%- endif -%} +{%- endfor -%}) +{%- endif -%} +{% endmacro option -%} + +{% macro flag(arg) -%} +{% if arg.short -%} +(-{{ arg.short }} --{{ arg.long }})'{-{{ arg.short }},--{{ arg.long }}}' +{%- else -%} +--{{ arg.long }} +{%- endif -%} +[{{self::escape_help(s=arg.help)}}] +{%- endmacro flag -%} + +{% macro positional(arg) -%} +:{{arg.id}}: : +{%- endmacro positional -%} + +#compdef rtx +_rtx() { + typeset -A opt_args + local context state line curcontext=$curcontext + local ret=1 + + _arguments -s -S \ + '(-h --help)'{-h,--help}'[Print help (see more with '--help')]' \ + {% for arg in visible_args -%} + {% if not arg.hide -%} + {{ self::arg(arg=arg) }} \ + {% endif -%} + {% endfor -%} + '1: :_rtx_cmds' \ + '*::arg:->args' && ret=0 + + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + {%- for cmd in commands %} + ({% for a in cmd.visible_aliases %}{{a}}|{% endfor %}{{cmd.name}}) + __rtx_cmd_{{cmd.name|replace(from="-", to="_")}}_arguments && ret=0 + ;; + {%- endfor %} + esac + ;; + esac + + return ret +} + +{%- for cmd in commands %} +__rtx_cmd_{{cmd.name|replace(from="-", to="_")}}_arguments() { + _arguments{% if cmd.visible_args | length > 0 %} \{% endif %} +{% for arg in cmd.visible_args -%} +{% if not arg.hide %} {{ self::arg(arg=arg) }}{% if not loop.last %} \{% endif %} +{% endif -%} +{% endfor -%} +}{%- endfor %} + +(( $+functions[_rtx_cmds] )) || +_rtx_cmds() { + local commands; commands=( + {%- for cmd in commands %} + '{{cmd.name}}:{{cmd.about}}' + {%- for a in cmd.visible_aliases %} + '{{a}}:{{cmd.about}}' + {%- endfor %} + {%- endfor %} + ) + _describe -t commands 'command' commands "$@" +} + +_rtx "$@" + +# Local Variables: +# mode: Shell-Script +# sh-indentation: 2 +# indent-tabs-mode: nil +# sh-basic-offset: 2 +# End: +# vim: ft=zsh sw=2 ts=2 et From 95c78edadfd25dc32e8c4bd002ae596207484d28 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:19:55 -0600 Subject: [PATCH 1175/1891] chore: Release rtx-cli version 2023.12.8 --- Cargo.lock | 38 +++++++++++++++++++------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df3c6affd..2dca6a6e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,30 +63,30 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -224,9 +224,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.10" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.9" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -1390,9 +1390,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.60" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1422,9 +1422,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.96" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -1810,7 +1810,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.7" +version = "2023.12.8" dependencies = [ "base64", "built", @@ -3061,9 +3061,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.19" +version = "0.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +checksum = "0383266b19108dfc6314a56047aa545a1b4d1be60e799b4dbdd407b56402704b" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index a99bf6113..4355c104c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.7" +version = "2023.12.8" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 7dc36e78d..e4d22a38e 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.7 +rtx 2023.12.8 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.7/rtx-v2023.12.7-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.8/rtx-v2023.12.8-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 5145784f2..b5f551934 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.7"; + version = "2023.12.8"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c413661a9..663bab368 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.7 +Version: 2023.12.8 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 7b91d99fbdf8e90aa6e7f38078b5c9a557596fa0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 14:40:45 -0600 Subject: [PATCH 1176/1891] completions: fix zsh completions when sourced directly (#1080) This makes `eval "$(rtx completion zsh)"` work again. Fixes #1079 --- .github/workflows/rtx.yml | 2 +- README.md | 70 ++-- completions/_rtx | 696 ++++++++++++++++++++--------------- completions/rtx.bash | 32 +- completions/rtx.fish | 18 +- justfile | 2 +- lefthook.yml | 3 - src/cli/alias/ls.rs | 8 +- src/cli/asdf.rs | 3 +- src/cli/env.rs | 2 +- src/cli/env_vars.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/implode.rs | 2 +- src/cli/ls.rs | 19 +- src/cli/plugins/install.rs | 6 +- src/cli/plugins/ls.rs | 10 +- src/cli/plugins/mod.rs | 12 +- src/cli/plugins/uninstall.rs | 19 +- src/cli/prune.rs | 6 +- src/cli/render_completion.rs | 281 +++++++++----- src/cli/settings/set.rs | 1 + 21 files changed, 707 insertions(+), 489 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 3fca4c2b0..0f22f02a1 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -57,7 +57,7 @@ jobs: save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cargo-llvm-cov - name: Install zsh/fish/direnv - run: sudo apt-get update; sudo apt-get install zsh fish direnv + run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - run: npm i -g markdown-magic - name: Install just uses: taiki-e/install-action@just diff --git a/README.md b/README.md index e4d22a38e..ef9d75440 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ v20.0.0 - [Commands](#commands) - [`rtx activate [OPTIONS] [SHELL_TYPE]`](#rtx-activate-options-shell_type) - [`rtx alias get `](#rtx-alias-get-plugin-alias) - - [`rtx alias ls [OPTIONS]`](#rtx-alias-ls-options) + - [`rtx alias ls [PLUGIN]`](#rtx-alias-ls-plugin) - [`rtx alias set `](#rtx-alias-set-plugin-alias-value) - [`rtx alias unset `](#rtx-alias-unset-plugin-alias) - [`rtx bin-paths`](#rtx-bin-paths) @@ -148,16 +148,16 @@ v20.0.0 - [`rtx install [OPTIONS] [TOOL@VERSION]...`](#rtx-install-options-toolversion) - [`rtx latest [OPTIONS] `](#rtx-latest-options-toolversion) - [`rtx link [OPTIONS] `](#rtx-link-options-toolversion-path) - - [`rtx ls [OPTIONS]`](#rtx-ls-options) + - [`rtx ls [OPTIONS] [PLUGIN]`](#rtx-ls-options-plugin) - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-toolversion-prefix) - [`rtx outdated [TOOL@VERSION]...`](#rtx-outdated-toolversion) - - [`rtx plugins install [OPTIONS] [NAME] [GIT_URL]`](#rtx-plugins-install-options-name-git_url) + - [`rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]`](#rtx-plugins-install-options-new_plugin-git_url) - [`rtx plugins link [OPTIONS] [PATH]`](#rtx-plugins-link-options-name-path) - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) - [`rtx plugins ls-remote [OPTIONS]`](#rtx-plugins-ls-remote-options) - - [`rtx plugins uninstall [OPTIONS] ...`](#rtx-plugins-uninstall-options-plugin) + - [`rtx plugins uninstall [OPTIONS] [PLUGIN]...`](#rtx-plugins-uninstall-options-plugin) - [`rtx plugins update [PLUGIN]...`](#rtx-plugins-update-plugin) - - [`rtx prune [OPTIONS] [PLUGINS]...`](#rtx-prune-options-plugins) + - [`rtx prune [OPTIONS] [PLUGIN]...`](#rtx-prune-options-plugin) - [`rtx reshim`](#rtx-reshim) - [`rtx self-update [OPTIONS] [VERSION]`](#rtx-self-update-options-version) - [`rtx settings get `](#rtx-settings-get-key) @@ -1670,7 +1670,7 @@ Examples: 20.0.0 ``` -### `rtx alias ls [OPTIONS]` +### `rtx alias ls [PLUGIN]` ``` List aliases @@ -1682,10 +1682,10 @@ For user config, aliases are defined like the following in `~/.config/rtx/config [alias.node] lts = "20.0.0" -Usage: alias ls [OPTIONS] +Usage: alias ls [PLUGIN] -Options: - -p, --plugin +Arguments: + [PLUGIN] Show aliases for Examples: @@ -1868,11 +1868,9 @@ Options: [possible values: bash, fish, nu, xonsh, zsh] - --json + -J, --json Output in JSON format - [short aliases: J] - Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" @@ -1933,11 +1931,9 @@ Options: -c, --command Command string to execute - --cd + -C, --cd Change to this directory before executing the command - [short aliases: C] - Examples: $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x $ rtx x node@20 -- node ./app.js # shorter alias @@ -1962,7 +1958,7 @@ Options: --config Also remove config directory - --dry-run + -n, --dry-run List directories that would be removed without actually removing them ``` @@ -2054,17 +2050,18 @@ Examples: $ rtx use node@brew ``` -### `rtx ls [OPTIONS]` +### `rtx ls [OPTIONS] [PLUGIN]` ``` List installed and/or currently selected tool versions -Usage: ls [OPTIONS] +Usage: ls [OPTIONS] [PLUGIN] -Options: - -p, --plugin +Arguments: + [PLUGIN] Only show tool versions from [PLUGIN] +Options: -c, --current Only show tool versions currently specified in a .tool-versions/.rtx.toml @@ -2074,11 +2071,9 @@ Options: -i, --installed Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed - --json + -J, --json Output in json format - [short aliases: J] - -m, --missing Display missing tool versions @@ -2167,7 +2162,7 @@ Examples: node 20 20.0.0 20.1.0 ``` -### `rtx plugins install [OPTIONS] [NAME] [GIT_URL]` +### `rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` ``` Install a plugin @@ -2177,10 +2172,10 @@ e.g.: `rtx install node@20` will autoinstall the node plugin This behavior can be modified in ~/.config/rtx/config.toml -Usage: plugins install [OPTIONS] [NAME] [GIT_URL] +Usage: plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL] Arguments: - [NAME] + [NEW_PLUGIN] The name of the plugin to install e.g.: node, ruby Can specify multiple plugins: `rtx plugins install node ruby python` @@ -2259,6 +2254,12 @@ Options: The built-in plugins only Normally these are not shown + --user + List installed plugins + + This is the default behavior but can be used with --core + to show core and user plugins + -u, --urls Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-node.git @@ -2298,21 +2299,24 @@ Options: Only show the name of each plugin by default it will show a "*" next to installed plugins ``` -### `rtx plugins uninstall [OPTIONS] ...` +### `rtx plugins uninstall [OPTIONS] [PLUGIN]...` ``` Removes a plugin -Usage: plugins uninstall [OPTIONS] ... +Usage: plugins uninstall [OPTIONS] [PLUGIN]... Arguments: - ... + [PLUGIN]... Plugin(s) to remove Options: -p, --purge Also remove the plugin's installs, downloads, and cache + -a, --all + Remove all plugins + Examples: $ rtx uninstall node ``` @@ -2336,7 +2340,7 @@ Examples: $ rtx plugins update node#beta # specify a ref ``` -### `rtx prune [OPTIONS] [PLUGINS]...` +### `rtx prune [OPTIONS] [PLUGIN]...` ``` Delete unused versions of tools @@ -2346,14 +2350,14 @@ Versions which are no longer the latest specified in any of those configs are de Versions installed only with environment variables (`RTX__VERSION`) will be deleted, as will versions only referenced on the command line (`rtx exec @`). -Usage: prune [OPTIONS] [PLUGINS]... +Usage: prune [OPTIONS] [PLUGIN]... Arguments: - [PLUGINS]... + [PLUGIN]... Prune only versions from these plugins Options: - --dry-run + -n, --dry-run Do not actually delete anything Examples: diff --git a/completions/_rtx b/completions/_rtx index 1565165d1..5540180a5 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -5,12 +5,12 @@ _rtx() { local ret=1 _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :_rtx_cmds' \ + '1: :__rtx_cmds' \ '*::arg:->args' && ret=0 case "$state" in @@ -42,9 +42,6 @@ _rtx() { (outdated) __rtx_outdated_cmd && ret=0 ;; (p|plugin|plugin-list|plugins) __rtx_plugins_cmd && ret=0 ;; (prune) __rtx_prune_cmd && ret=0 ;; - (render-completion) __rtx_render_completion_cmd && ret=0 ;; - (render-help) __rtx_render_help_cmd && ret=0 ;; - (render-mangen) __rtx_render_mangen_cmd && ret=0 ;; (reshim) __rtx_reshim_cmd && ret=0 ;; (self-update) __rtx_self_update_cmd && ret=0 ;; (settings) __rtx_settings_cmd && ret=0 ;; @@ -63,25 +60,27 @@ _rtx() { return ret } +(( $+functions[__rtx_activate_cmd] )) || __rtx_activate_cmd() { _arguments -s -S \ - '*::shell_type:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--status=[Show "rtx: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '::shell_type:(bash fish nu xonsh zsh)' \ + '--status[Show "rtx\: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_alias_cmd] )) || __rtx_alias_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:: :' \ + '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :_rtx_cmds' \ + '1: :__rtx_alias_cmds' \ '*::arg:->args' && ret=0 case "$state" in @@ -98,71 +97,78 @@ __rtx_alias_cmd() { return ret } +(( $+functions[__rtx_alias_get_cmd] )) || __rtx_alias_get_cmd() { _arguments -s -S \ - '*::alias:' \ - '*::plugin:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_alias_ls_cmd] )) || __rtx_alias_ls_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-p --plugin)'{-p,--plugin}'=[Show aliases for ]:: :' \ + '::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_alias_set_cmd] )) || __rtx_alias_set_cmd() { _arguments -s -S \ - '*::alias:' \ - '*::plugin:' \ - '*::value:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + ':value:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_alias_unset_cmd] )) || __rtx_alias_unset_cmd() { _arguments -s -S \ - '*::alias:' \ - '*::plugin:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_asdf_cmd] )) || __rtx_asdf_cmd() { _arguments -s -S \ - '*::args:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '*::args:_cmdambivalent' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_bin_paths_cmd] )) || __rtx_bin_paths_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_cache_cmd] )) || __rtx_cache_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :_rtx_cmds' \ + '1: :__rtx_cache_cmds' \ '*::arg:->args' && ret=0 case "$state" in @@ -176,48 +182,53 @@ __rtx_cache_cmd() { return ret } +(( $+functions[__rtx_cache_clear_cmd] )) || __rtx_cache_clear_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_completion_cmd] )) || __rtx_completion_cmd() { _arguments -s -S \ - '*::shell:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '::shell:(bash fish zsh)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_current_cmd] )) || __rtx_current_cmd() { _arguments -s -S \ - '*::plugin:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_deactivate_cmd] )) || __rtx_deactivate_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_direnv_cmd] )) || __rtx_direnv_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :_rtx_cmds' \ + '1: :__rtx_direnv_cmds' \ '*::arg:->args' && ret=0 case "$state" in @@ -233,195 +244,213 @@ __rtx_direnv_cmd() { return ret } +(( $+functions[__rtx_direnv_activate_cmd] )) || __rtx_direnv_activate_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_direnv_envrc_cmd] )) || __rtx_direnv_envrc_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_direnv_exec_cmd] )) || __rtx_direnv_exec_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_doctor_cmd] )) || __rtx_doctor_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_env_cmd] )) || __rtx_env_cmd() { _arguments -s -S \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ '*::tool:__rtx_tool_versions' \ - '--json=[Output in JSON format]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-J --json)'{-J,--json}'[Output in JSON format]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]: :(bash fish nu xonsh zsh)' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_env_vars_cmd] )) || __rtx_env_vars_cmd() { _arguments -s -S \ + '--file=[The TOML file to update]:file:_files' \ + '*--remove=[Remove the environment variable from config file]:remove:' \ '*::env_vars:' \ - '--file=[The TOML file to update]:: :' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--remove=[Remove the environment variable from config file]:: :' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_exec_cmd] )) || __rtx_exec_cmd() { _arguments -s -S \ - '*::command:' \ '*::tool:__rtx_tool_versions' \ - '--cd=[Change to this directory before executing the command]:: :' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-c --command)'{-c,--command}'=[Command string to execute]:: :' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ + '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_global_cmd] )) || __rtx_global_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--fuzzy=[Save fuzzy version to `~/.tool-versions`]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--path=[Get the path of the global config file]' \ - '--pin=[Save exact version to `~/.tool-versions`]' \ - '--remove=[Remove the plugin(s) from ~/.tool-versions]:: :' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '--pin[Save exact version to \`~/.tool-versions\`]' \ + '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ + '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ + '--path[Get the path of the global config file]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_hook_env_cmd] )) || __rtx_hook_env_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--status=[Show "rtx: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ + '--status[Show "rtx\: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]: :(bash fish nu xonsh zsh)' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_implode_cmd] )) || __rtx_implode_cmd() { _arguments -s -S \ - '--config=[Also remove config directory]' \ - '--dry-run=[List directories that would be removed without actually removing them]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '--config[Also remove config directory]' \ + '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_install_cmd] )) || __rtx_install_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_latest_cmd] )) || __rtx_latest_cmd() { _arguments -s -S \ - '1::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + ':tool:__rtx_tool_versions' \ '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_link_cmd] )) || __rtx_link_cmd() { _arguments -s -S \ - '1: :_directories' \ - '1::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + ':tool:__rtx_tool_versions' \ + ':path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_local_cmd] )) || __rtx_local_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--fuzzy=[Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--path=[Get the path of the config file]' \ - '--pin=[Save exact version to `.tool-versions`]' \ - '--remove=[Remove the plugin(s) from .tool-versions]:: :' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ '(-p --parent)'{-p,--parent}'[Recurse up to find a .tool-versions file rather than using the current directory only]' \ + '--pin[Save exact version to \`.tool-versions\`]' \ + '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ + '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ + '--path[Get the path of the config file]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_ls_cmd] )) || __rtx_ls_cmd() { _arguments -s -S \ - '--json=[Output in json format]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--prefix=[Display versions matching this prefix]:: :' \ + '::plugin:__rtx_plugins' \ '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-J --json)'{-J,--json}'[Output in json format]' \ '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ - '(-p --plugin)'{-p,--plugin}'=[Only show tool versions from [PLUGIN]]:: :' \ + '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_ls_remote_cmd] )) || __rtx_ls_remote_cmd() { _arguments -s -S \ - '*::plugin:' \ - '*::prefix:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':plugin:__rtx_plugins' \ + '::prefix:__rtx_prefixes' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_outdated_cmd] )) || __rtx_outdated_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_plugins_cmd] )) || __rtx_plugins_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--refs=[show the git refs for each plugin]' \ '(-c --core)'{-c,--core}'[The built-in plugins only]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '--refs[show the git refs for each plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :_rtx_cmds' \ + '1: :__rtx_plugins_cmds' \ '*::arg:->args' && ret=0 case "$state" in @@ -440,131 +469,118 @@ __rtx_plugins_cmd() { return ret } +(( $+functions[__rtx_plugins_install_cmd] )) || __rtx_plugins_install_cmd() { _arguments -s -S \ - '1: :_urls' \ - '*::name:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-a --all)'{-a,--all}'[Install all missing plugins]' \ + ':new_plugin:__rtx_all_plugins' \ + '::git_url:_urls' \ '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-a --all)'{-a,--all}'[Install all missing plugins]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_plugins_link_cmd] )) || __rtx_plugins_link_cmd() { _arguments -s -S \ - '*::name:' \ - '1: :_directories' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ + ':name:' \ + '::path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_plugins_ls_cmd] )) || __rtx_plugins_ls_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--refs=[Show the git refs for each plugin]' \ '(-c --core)'{-c,--core}'[The built-in plugins only]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '--refs[Show the git refs for each plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_plugins_ls_remote_cmd] )) || __rtx_plugins_ls_remote_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--only-names=[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ + '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_plugins_uninstall_cmd] )) || __rtx_plugins_uninstall_cmd() { _arguments -s -S \ - '*::plugin:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '*::plugin:__rtx_plugins' \ '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ + '(-a --all)'{-a,--all}'[Remove all plugins]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_plugins_update_cmd] )) || __rtx_plugins_update_cmd() { _arguments -s -S \ - '*::plugin:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '*::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_prune_cmd] )) || __rtx_prune_cmd() { _arguments -s -S \ - '*::plugins:' \ - '--dry-run=[Do not actually delete anything]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -__rtx_render_completion_cmd() { - _arguments -s -S \ - '*::shell:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -__rtx_render_help_cmd() { - _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -__rtx_render_mangen_cmd() { - _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '*::plugin:__rtx_plugins' \ + '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_reshim_cmd] )) || __rtx_reshim_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_self_update_cmd] )) || __rtx_self_update_cmd() { _arguments -s -S \ - '*::version:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--no-plugins=[Disable auto-updating plugins]' \ '(-f --force)'{-f,--force}'[Update even if already up to date]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '--no-plugins[Disable auto-updating plugins]' \ + '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ + '::version:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '*'{-v,--verbose}'[Show installation output]' } +(( $+functions[__rtx_settings_cmd] )) || __rtx_settings_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :_rtx_cmds' \ + '1: :__rtx_settings_cmds' \ '*::arg:->args' && ret=0 case "$state" in @@ -581,60 +597,66 @@ __rtx_settings_cmd() { return ret } +(( $+functions[__rtx_settings_get_cmd] )) || __rtx_settings_get_cmd() { _arguments -s -S \ - '*::key:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':key:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_settings_ls_cmd] )) || __rtx_settings_ls_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_settings_set_cmd] )) || __rtx_settings_set_cmd() { _arguments -s -S \ - '*::key:' \ - '*::value:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':key:' \ + ':value:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_settings_unset_cmd] )) || __rtx_settings_unset_cmd() { _arguments -s -S \ - '*::key:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':key:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_shell_cmd] )) || __rtx_shell_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_sync_cmd] )) || __rtx_sync_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :_rtx_cmds' \ + '1: :__rtx_sync_cmds' \ '*::arg:->args' && ret=0 case "$state" in @@ -649,102 +671,111 @@ __rtx_sync_cmd() { return ret } +(( $+functions[__rtx_sync_node_cmd] )) || __rtx_sync_node_cmd() { _arguments -s -S \ - '--brew=[Get tool versions from Homebrew]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--nodenv=[Get tool versions from nodenv]' \ - '--nvm=[Get tool versions from nvm]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '--brew[Get tool versions from Homebrew]' \ + '--nvm[Get tool versions from nvm]' \ + '--nodenv[Get tool versions from nodenv]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_sync_python_cmd] )) || __rtx_sync_python_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--pyenv=[Get tool versions from pyenv]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '--pyenv[Get tool versions from pyenv]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_trust_cmd] )) || __rtx_trust_cmd() { _arguments -s -S \ - '1: :_files' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--untrust=[No longer trust this config]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '::config_file:_files' \ + '--untrust[No longer trust this config]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_uninstall_cmd] )) || __rtx_uninstall_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ '(-a --all)'{-a,--all}'[Delete all installed versions]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_upgrade_cmd] )) || __rtx_upgrade_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_use_cmd] )) || __rtx_use_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--fuzzy=[Save fuzzy version to config file]' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--pin=[Save exact version to config file]' \ - '--remove=[Remove the tool(s) from config file]:: :' \ - '(-e --env)'{-e,--env}'=[[experimental] Modify an environment-specific config file like .rtx..toml]:: :' \ + '--pin[Save exact version to config file]' \ + '--fuzzy[Save fuzzy version to config file]' \ + '*--remove=[Remove the tool(s) from config file]:remove:' \ '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:: :' \ + '(-e --env)'{-e,--env}'=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:env:' \ + '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_version_cmd] )) || __rtx_version_cmd() { _arguments -s -S \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_where_cmd] )) || __rtx_where_cmd() { _arguments -s -S \ - '1::tool:__rtx_tool_versions' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_which_cmd] )) || __rtx_which_cmd() { _arguments -s -S \ - '*::bin_name:' \ - '--log-level=[Set the log output verbosity]: :(error warn info debug trace)' \ - '--plugin=[Show the plugin name instead of the path]' \ - '--version=[Show the version instead of the path]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ + ':bin_name:' \ + '--plugin[Show the plugin name instead of the path]' \ + '--version[Show the version instead of the path]' \ + '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:: :' \ - '(-v --verbose)'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show installation output]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } -(( $+functions[_rtx_cmds] )) || -_rtx_cmds() { +(( $+functions[__rtx_cmds] )) || +__rtx_cmds() { local commands; commands=( 'activate:Initializes rtx in the current shell' {a,alias}':Manage aliases' @@ -782,20 +813,99 @@ _rtx_cmds() { ) _describe -t commands 'command' commands "$@" } +(( $+functions[__rtx_alias_cmds] )) || +__rtx_alias_cmds() { + local commands; commands=( + 'get:Show an alias for a plugin' + {list,ls}':List aliases' + {add,create,set}':Add/update an alias for a plugin' + {del,delete,remove,rm,unset}':Clears an alias for a plugin' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_cache_cmds] )) || +__rtx_cache_cmds() { + local commands; commands=( + {c,clear}':Deletes all cache files in rtx' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_direnv_cmds] )) || +__rtx_direnv_cmds() { + local commands; commands=( + 'activate:Output direnv function to use rtx inside direnv' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_plugins_cmds] )) || +__rtx_plugins_cmds() { + local commands; commands=( + {a,i,install}':Install a plugin' + 'link:Symlinks a plugin into rtx' + {list,ls}':List installed plugins' + {list-remote,ls-remote}':List all available remote plugins' + 'uninstall:Removes a plugin' + 'update:Updates a plugin to the latest version' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_settings_cmds] )) || +__rtx_settings_cmds() { + local commands; commands=( + 'get:Show a current setting' + {list,ls}':Show current settings' + {add,create,set}':Add/update a setting' + {del,delete,remove,rm,unset}':Clears a setting' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_sync_cmds] )) || +__rtx_sync_cmds() { + local commands; commands=( + 'node:Symlinks all tool versions from an external tool into rtx' + 'python:Symlinks all tool versions from an external tool into rtx' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_tool_versions] )) || __rtx_tool_versions() { if compset -P '*@'; then local -a tool_versions; tool_versions=($(rtx ls-remote ${words[CURRENT]})) _wanted tool_version expl 'version of tool' \ compadd -a tool_versions else - local -a plugins; plugins=($(rtx plugins)) + local -a plugins; plugins=($(rtx plugins --core --user)) _wanted plugin expl 'plugin name' \ compadd -S '@' -a plugins fi } +(( $+functions[__rtx_plugins] )) || +__rtx_plugins() { + local -a plugins; plugins=($(rtx plugins --core --user)) + _describe -t plugins 'plugin' plugins "$@" +} +(( $+functions[__rtx_all_plugins] )) || +__rtx_all_plugins() { + local -a all_plugins; all_plugins=($(rtx plugins --all)) + _describe -t all_plugins 'all_plugins' all_plugins "$@" +} +(( $+functions[__rtx_aliases] )) || +__rtx_aliases() { + local -a aliases; aliases=($(rtx aliases ls ${words[CURRENT-1]} | awk '{print $2}')) + _describe -t aliases 'alias' aliases "$@" +} +(( $+functions[__rtx_prefixes] )) || +__rtx_prefixes() { + local -a prefixes; prefixes=($(rtx ls-remote ${words[CURRENT-1]})) + _describe -t prefixes 'prefix' prefixes "$@" +} -_rtx "$@" +if [ "$funcstack[1]" = "_rtx" ]; then + _rtx "$@" +else + compdef _rtx rtx +fi # Local Variables: # mode: Shell-Script diff --git a/completions/rtx.bash b/completions/rtx.bash index 991535e57..7227365de 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -763,20 +763,12 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-p -j -r -v -y -h --plugin --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --plugin) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -p) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1281,7 +1273,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -r -v -y -h --shell --json --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-s -J -j -r -v -y -h --shell --json --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1349,7 +1341,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -j -r -v -y -h --command --cd --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -C -j -r -v -y -h --command --cd --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1367,6 +1359,10 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2319,7 +2315,7 @@ _rtx() { return 0 ;; rtx__implode) - opts="-j -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-n -j -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2453,7 +2449,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -m -j -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN_ARG]" + opts="-p -c -g -i -J -m -j -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2543,7 +2539,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -j -r -v -y -h --all --core --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help install link ls ls-remote uninstall update help" + opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2681,7 +2677,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -r -y -h --force --all --verbose --jobs --debug --log-level --trace --raw --yes --help [NAME] [GIT_URL] [REST]..." + opts="-f -a -v -j -r -y -h --force --all --verbose --jobs --debug --log-level --trace --raw --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2733,7 +2729,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -j -r -v -y -h --all --core --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2785,7 +2781,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-p -j -r -v -y -h --purge --jobs --debug --log-level --trace --raw --verbose --yes --help ..." + opts="-p -a -j -r -v -y -h --purge --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2837,7 +2833,7 @@ _rtx() { return 0 ;; rtx__prune) - opts="-j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGINS]..." + opts="-n -j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 2fad590b9..09c484423 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -91,7 +91,6 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s p -l plugin -d 'Show aliases for ' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" @@ -270,7 +269,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell typ complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from env" -l json -d 'Output in JSON format' +complete -c rtx -n "__fish_seen_subcommand_from env" -s J -l json -d 'Output in JSON format' complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from env" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -278,7 +277,7 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from env" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l file -d 'The TOML file to update' -r +complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l file -d 'The TOML file to update' -r -F complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l remove -d 'Remove the environment variable from config file' -r complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -291,7 +290,7 @@ complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s v -l verbose -d 'Sh complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s h -l help -d 'Print help (see more with \'--help\')' complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r -f -a "(__fish_complete_command)" -complete -c rtx -n "__fish_seen_subcommand_from exec" -l cd -d 'Change to this directory before executing the command' -r -f -a "(__fish_complete_directories)" +complete -c rtx -n "__fish_seen_subcommand_from exec" -s C -l cd -d 'Change to this directory before executing the command' -r -f -a "(__fish_complete_directories)" complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" @@ -335,7 +334,7 @@ complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' -complete -c rtx -n "__fish_seen_subcommand_from implode" -l dry-run -d 'List directories that would be removed without actually removing them' +complete -c rtx -n "__fish_seen_subcommand_from implode" -s n -l dry-run -d 'List directories that would be removed without actually removing them' complete -c rtx -n "__fish_seen_subcommand_from implode" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -393,7 +392,7 @@ Sets --jobs=1' complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' complete -c rtx -n "__fish_seen_subcommand_from local" -s y -l yes -d 'Answer yes to all prompts' complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -d 'Only show tool versions from [PLUGIN]' -r +complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -r complete -c rtx -n "__fish_seen_subcommand_from ls" -l prefix -d 'Display versions matching this prefix' -r complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r @@ -402,7 +401,7 @@ complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only sho complete -c rtx -n "__fish_seen_subcommand_from ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' complete -c rtx -n "__fish_seen_subcommand_from ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in an easily parseable format' -complete -c rtx -n "__fish_seen_subcommand_from ls" -l json -d 'Output in json format' +complete -c rtx -n "__fish_seen_subcommand_from ls" -s J -l json -d 'Output in json format' complete -c rtx -n "__fish_seen_subcommand_from ls" -s m -l missing -d 'Display missing tool versions' complete -c rtx -n "__fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' @@ -437,6 +436,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_sub complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s c -l core -d 'The built-in plugins only Normally these are not shown' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l user -d 'List installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l refs -d 'show the git refs for each plugin' complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' @@ -485,6 +485,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm Same as `rtx plugins ls-remote`' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s c -l core -d 'The built-in plugins only Normally these are not shown' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l user -d 'List installed plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-node.git' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l refs -d 'Show the git refs for each plugin @@ -512,6 +513,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s p -l purge -d 'Also remove the plugin\'s installs, downloads, and cache' +complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s a -l all -d 'Remove all plugins' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. @@ -540,7 +542,7 @@ complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcomm complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel [default: 4]' -r complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from prune" -l dry-run -d 'Do not actually delete anything' +complete -c rtx -n "__fish_seen_subcommand_from prune" -s n -l dry-run -d 'Do not actually delete anything' complete -c rtx -n "__fish_seen_subcommand_from prune" -l debug -d 'Sets log level to debug' complete -c rtx -n "__fish_seen_subcommand_from prune" -l trace -d 'Sets log level to trace' complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. diff --git a/justfile b/justfile index 4fcd43713..ff82bd530 100644 --- a/justfile +++ b/justfile @@ -112,7 +112,7 @@ render-mangen: build NO_COLOR=1 rtx render-mangen # called by lefthook precommit hook -pre-commit: render-help render-completions render-mangen +pre-commit: render-help render-completions render-mangen lint git add README.md git add completions git add man diff --git a/lefthook.yml b/lefthook.yml index 52553ed23..da19c9b66 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -4,9 +4,6 @@ pre-commit: pre-commit: run: just -v pre-commit interactive: true - lint: - run: just -v lint - interactive: true skip_output: - meta - summary diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index d661a1415..88e0589f5 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -16,7 +16,7 @@ use crate::plugins::PluginName; #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasLs { /// Show aliases for - #[clap(short, long)] + #[clap()] pub plugin: Option, } @@ -34,7 +34,11 @@ impl AliasLs { // hide the nvm-style aliases so only asdf-style ones display continue; } - rtxprintln!(out, "{:20} {:20} {}", plugin_name, from, to); + if self.plugin.is_some() { + rtxprintln!(out, "{:20} {}", from, to); + } else { + rtxprintln!(out, "{:20} {:20} {}", plugin_name, from, to); + } } } Ok(()) diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 4a355228e..feb073e3b 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -1,3 +1,4 @@ +use clap::ValueHint::CommandWithArguments; use color_eyre::eyre::Result; use itertools::Itertools; @@ -11,7 +12,7 @@ use crate::toolset::ToolsetBuilder; #[clap(hide = true, verbatim_doc_comment)] pub struct Asdf { /// all arguments - #[clap(allow_hyphen_values = true)] + #[clap(allow_hyphen_values = true, value_hint = CommandWithArguments, trailing_var_arg = true)] args: Vec, } diff --git a/src/cli/env.rs b/src/cli/env.rs index 75a4f9227..1bb1279f2 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -22,7 +22,7 @@ pub struct Env { tool: Vec, /// Output in JSON format - #[clap(long, visible_short_alias = 'J', overrides_with = "shell")] + #[clap(long, short = 'J', overrides_with = "shell")] json: bool, } diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index faf36f052..8a216b6e5 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -20,7 +20,7 @@ pub struct EnvVars { /// The TOML file to update /// /// Defaults to RTX_DEFAULT_CONFIG_FILENAME environment variable, or ".rtx.toml". - #[clap(long, verbatim_doc_comment, required = false)] + #[clap(long, verbatim_doc_comment, required = false, value_hint = clap::ValueHint::FilePath)] file: Option, /// Remove the environment variable from config file diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 4740a2bc4..ebefbb96e 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -40,7 +40,7 @@ pub struct Exec { pub c: Option, /// Change to this directory before executing the command - #[clap(visible_short_alias = 'C', value_hint = ValueHint::DirPath, long)] + #[clap(short = 'C', value_hint = ValueHint::DirPath, long)] pub cd: Option, } diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 7e9e47506..a52af9d6b 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -19,7 +19,7 @@ pub struct Implode { config: bool, /// List directories that would be removed without actually removing them - #[clap(long, verbatim_doc_comment)] + #[clap(long, short = 'n', verbatim_doc_comment)] dry_run: bool, } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index b2ff1f373..09f10bac9 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -23,11 +23,11 @@ use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; #[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Ls { /// Only show tool versions from [PLUGIN] - #[clap(long, short)] + #[clap(conflicts_with = "plugin_flag")] plugin: Option, - #[clap(hide = true)] - plugin_arg: Option, + #[clap(long = "plugin", short, hide = true)] + plugin_flag: Option, /// Only show tool versions currently specified in a .tool-versions/.rtx.toml #[clap(long, short)] @@ -43,11 +43,11 @@ pub struct Ls { installed: bool, /// Output in an easily parseable format - #[clap(long, hide = true, visible_short_alias = 'x', conflicts_with = "json")] + #[clap(long, hide = true, conflicts_with = "json")] parseable: bool, /// Output in json format - #[clap(long, visible_short_alias = 'J', overrides_with = "parseable")] + #[clap(long, short = 'J', overrides_with = "parseable")] json: bool, /// Display missing tool versions @@ -55,7 +55,7 @@ pub struct Ls { missing: bool, /// Display versions matching this prefix - #[clap(long)] + #[clap(long, requires = "plugin")] prefix: Option, } @@ -64,7 +64,7 @@ impl Ls { self.plugin = self .plugin .clone() - .or(self.plugin_arg.clone()) + .or(self.plugin_flag.clone()) .map(|p| PluginName::from(unalias_plugin(&p))); self.verify_plugin(&config)?; @@ -81,9 +81,6 @@ impl Ls { runtimes.retain(|(p, tv, _)| !p.is_version_installed(tv)); } if let Some(prefix) = &self.prefix { - if self.plugin.is_none() { - panic!("--prefix requires --plugin"); - } runtimes.retain(|(_, tv, _)| tv.version.starts_with(prefix)); } if self.json { @@ -418,7 +415,7 @@ mod tests { fn test_ls_parseable() { let _ = remove_all(dirs::INSTALLS.as_path()); assert_cli!("install"); - assert_cli_snapshot!("ls", "-x"); + assert_cli_snapshot!("ls", "--parseable"); assert_cli_snapshot!("ls", "--parseable", "tiny"); } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 81016244f..2c15c7af3 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -21,7 +21,7 @@ pub struct PluginsInstall { /// e.g.: node, ruby /// Can specify multiple plugins: `rtx plugins install node ruby python` #[clap(required_unless_present = "all", verbatim_doc_comment)] - name: Option, + new_plugin: Option, /// The git url of the plugin /// e.g.: https://github.com/asdf-vm/asdf-node.git @@ -35,7 +35,7 @@ pub struct PluginsInstall { /// Install all missing plugins /// This will only install plugins that have matching shorthands. /// i.e.: they don't need the full git repo url - #[clap(short, long, conflicts_with_all = ["name", "force"], verbatim_doc_comment)] + #[clap(short, long, conflicts_with_all = ["new_plugin", "force"], verbatim_doc_comment)] all: bool, /// Show installation output @@ -52,7 +52,7 @@ impl PluginsInstall { if self.all { return self.install_all_missing_plugins(config, mpr); } - let (name, git_url) = get_name_and_url(&self.name.clone().unwrap(), &self.git_url)?; + 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)?; } else { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 836e74f1e..3f2791b86 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -21,9 +21,16 @@ pub struct PluginsLs { /// The built-in plugins only /// Normally these are not shown - #[clap(short, long, verbatim_doc_comment)] + #[clap(short, long, verbatim_doc_comment, conflicts_with = "all")] pub core: bool, + /// List installed plugins + /// + /// This is the default behavior but can be used with --core + /// to show core and user plugins + #[clap(long, verbatim_doc_comment, conflicts_with = "all")] + pub user: bool, + /// Show the git url for each plugin /// e.g.: https://github.com/asdf-vm/asdf-node.git #[clap(short, long, verbatim_doc_comment)] @@ -46,6 +53,7 @@ impl PluginsLs { let tool = Tool::new(plugin.clone(), Box::from(ep)); tools.insert(Arc::new(tool)); } + } else if self.user && self.core { } else if self.core { tools.retain(|p| matches!(p.plugin.get_type(), PluginType::Core)); } else { diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 2ca6ec611..dde5e2f4d 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -25,9 +25,16 @@ pub struct Plugins { /// The built-in plugins only /// Normally these are not shown - #[clap(short, long, verbatim_doc_comment)] + #[clap(short, long, verbatim_doc_comment, conflicts_with = "all")] pub core: bool, + /// List installed plugins + /// + /// This is the default behavior but can be used with --core + /// to show core and user plugins + #[clap(long, verbatim_doc_comment, conflicts_with = "all")] + pub user: bool, + /// show the git url for each plugin /// /// e.g.: https://github.com/asdf-vm/asdf-node.git @@ -69,8 +76,9 @@ impl Plugins { let cmd = self.command.unwrap_or(Commands::Ls(ls::PluginsLs { all: self.all, core: self.core, - urls: self.urls, refs: self.refs, + urls: self.urls, + user: self.user, })); cmd.run(config, out) diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index c5740fb9a..9ea6f1bae 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -11,20 +11,29 @@ use crate::ui::multi_progress_report::MultiProgressReport; #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct PluginsUninstall { /// Plugin(s) to remove - #[clap(required = true, verbatim_doc_comment)] - pub plugin: Vec, + #[clap(verbatim_doc_comment)] + plugin: Vec, /// Also remove the plugin's installs, downloads, and cache #[clap(long, short, verbatim_doc_comment)] - pub purge: bool, + purge: bool, + + /// Remove all plugins + #[clap(long, short, verbatim_doc_comment, conflicts_with = "plugin")] + all: bool, } impl PluginsUninstall { pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); - for plugin_name in &self.plugin { - let plugin_name = unalias_plugin(plugin_name); + let plugins = match self.all { + true => config.tools.keys().cloned().collect(), + false => self.plugin.clone(), + }; + + for plugin_name in plugins { + let plugin_name = unalias_plugin(&plugin_name); self.uninstall_one(&config, plugin_name, &mpr)?; } Ok(()) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 84704d61c..9b5ca1f54 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -23,10 +23,10 @@ use crate::ui::prompt; pub struct Prune { /// Prune only versions from these plugins #[clap()] - pub plugins: Option>, + pub plugin: Option>, /// Do not actually delete anything - #[clap(long, short_alias = 'n')] + #[clap(long, short = 'n')] pub dry_run: bool, } @@ -39,7 +39,7 @@ impl Prune { .map(|(p, tv)| (tv.to_string(), (p, tv))) .collect::, ToolVersion)>>(); - if let Some(plugins) = &self.plugins { + if let Some(plugins) = &self.plugin { to_delete.retain(|_, (_, tv)| plugins.contains(&tv.plugin_name)); } diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 9b714c8c7..5a40510f1 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -1,17 +1,18 @@ -use clap::{Arg, ArgAction, Command, ValueHint}; +use clap::{Arg, ArgAction, Args, Command, ValueHint}; +use std::collections::HashSet; use std::io::Cursor; -use std::iter::once; use clap_complete::generate; use color_eyre::eyre::Result; use itertools::Itertools; +use once_cell::sync::Lazy; use crate::cli::self_update::SelfUpdate; use crate::config::Config; use crate::output::Output; /// Generate shell completions -#[derive(Debug, clap::Args)] +#[derive(Debug, Args)] #[clap(hide = true, verbatim_doc_comment)] pub struct RenderCompletion { /// Shell type to generate completions for @@ -30,7 +31,7 @@ impl RenderCompletion { let mut c = Cursor::new(Vec::new()); let mut cmd = crate::cli::Cli::command().subcommand(SelfUpdate::command()); - if matches!(shell, clap_complete::Shell::Zsh) { + if let clap_complete::Shell::Zsh = shell { rtxprintln!(out, "{}", ZshComplete::new(cmd).render()?.trim()); } else { generate(shell, &mut cmd, "rtx", &mut c); @@ -42,7 +43,7 @@ impl RenderCompletion { } struct ZshComplete { - cmd: clap::Command, + cmd: Command, } impl ZshComplete { @@ -52,7 +53,7 @@ impl ZshComplete { fn render(&self) -> Result { let command_funcs = self.render_command_funcs(&[&self.cmd]); - let command_descriptions = self.render_command_descriptions(); + let command_descriptions = self.render_command_descriptions(&[&self.cmd]); Ok(formatdoc! {r#" #compdef rtx @@ -66,19 +67,44 @@ impl ZshComplete { {command_funcs} {command_descriptions} + (( $+functions[__rtx_tool_versions] )) || __rtx_tool_versions() {{ if compset -P '*@'; then local -a tool_versions; tool_versions=($(rtx ls-remote ${{words[CURRENT]}})) _wanted tool_version expl 'version of tool' \ compadd -a tool_versions else - local -a plugins; plugins=($(rtx plugins)) + local -a plugins; plugins=($(rtx plugins --core --user)) _wanted plugin expl 'plugin name' \ compadd -S '@' -a plugins fi }} + (( $+functions[__rtx_plugins] )) || + __rtx_plugins() {{ + local -a plugins; plugins=($(rtx plugins --core --user)) + _describe -t plugins 'plugin' plugins "$@" + }} + (( $+functions[__rtx_all_plugins] )) || + __rtx_all_plugins() {{ + local -a all_plugins; all_plugins=($(rtx plugins --all)) + _describe -t all_plugins 'all_plugins' all_plugins "$@" + }} + (( $+functions[__rtx_aliases] )) || + __rtx_aliases() {{ + local -a aliases; aliases=($(rtx aliases ls ${{words[CURRENT-1]}} | awk '{{print $2}}')) + _describe -t aliases 'alias' aliases "$@" + }} + (( $+functions[__rtx_prefixes] )) || + __rtx_prefixes() {{ + local -a prefixes; prefixes=($(rtx ls-remote ${{words[CURRENT-1]}})) + _describe -t prefixes 'prefix' prefixes "$@" + }} - _rtx "$@" + if [ "$funcstack[1]" = "_rtx" ]; then + _rtx "$@" + else + compdef _rtx rtx + fi # Local Variables: # mode: Shell-Script @@ -91,25 +117,26 @@ impl ZshComplete { } fn render_args(&self, cmds: &[&Command]) -> String { - let args = cmds + let global_args = cmds .iter() .flat_map(|cmd| cmd.get_arguments()) .filter(|arg| arg.is_global_set()); let cmd = cmds.last().unwrap(); - let args = args - .chain(cmd.get_arguments()) - .filter(|arg| !arg.is_hide_set()) + let args = cmd + .get_arguments() + .chain(global_args) + .filter(|arg| !arg.is_hide_set() && !arg.is_last_set()) .unique_by(|arg| arg.get_id()) - .sorted_by_key(|arg| (arg.get_short(), arg.get_long(), arg.get_id())) .map(|arg| self.render_arg(arg)) .collect::>() .join(" \\\n "); if cmd.has_subcommands() { let subcommands = self.render_subcommands(cmds); + let func = format!("__{}_cmds", func_name(cmds)); formatdoc! {r#" _arguments -s -S \ {args} \ - '1: :_rtx_cmds' \ + '1: :{func}' \ '*::arg:->args' && ret=0 {subcommands} @@ -128,18 +155,15 @@ impl ZshComplete { let cmd = cmds.last().unwrap(); let cases = cmd .get_subcommands() + .filter(|c| !banned(c)) .sorted_by_cached_key(|c| c.get_name()) .map(|cmd| { - let name = cmd.get_name(); let mut names = cmd.get_all_aliases().sorted().collect_vec(); - names.push(name); + names.push(cmd.get_name()); let names = names.join("|"); - let func = cmds - .iter() - .chain(once(&cmd)) - .map(|c| c.get_name()) - .join("_") - .replace('-', "_"); + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + let func = func_name(&cmds); format!(" ({names}) __{func}_cmd && ret=0 ;;",) }) .collect::>() @@ -157,98 +181,109 @@ impl ZshComplete { } fn render_arg(&self, arg: &clap::Arg) -> String { - if arg.get_action().takes_values() { - self.render_option(arg) - } else { - self.render_flag(arg) - } - } - - fn render_flag(&self, arg: &clap::Arg) -> String { - // print this: '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ let help = match arg.get_help() { - Some(help) => escape_single_quote(first_line(&help.to_string())).to_string(), + Some(help) => format!("[{}]", help_escape(first_line(&help.to_string()))), None => return String::new(), }; - match (arg.get_short(), arg.get_long()) { - (Some(short), Some(long)) => { - format!("'(-{short} --{long})'{{-{short},--{long}}}'[{help}]'",) - } - (Some(short), None) => { - format!("'-{short}[{help}]'",) - } - (None, Some(long)) => format!("'--{long}=[{help}]'"), - (None, None) => self.render_positional(arg), - } - } - fn render_option(&self, arg: &clap::Arg) -> String { - // print this: '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:: :' \ - let help = match arg.get_help() { - Some(help) => escape_single_quote(first_line(&help.to_string())).to_string(), - None => return String::new(), + let multiple = if let ArgAction::Count | ArgAction::Append = arg.get_action() { + "*" + } else { + "" }; - let completions = match arg.get_possible_values() { - values if values.is_empty() => ":: :".to_string(), - values => format!( - ": :({})", - values - .iter() - .map(|v| v.get_name()) - .collect::>() - .join(" ") - ), + let all = self.get_short_and_longs(arg); + let conflicts = if all.len() < 2 || multiple == "*" { + "".to_string() + } else { + format!("({})", all.join(" ")) }; - match (arg.get_short(), arg.get_long()) { - (Some(short), Some(long)) => { - format!("'(-{short} --{long})'{{-{short},--{long}}}'=[{help}]{completions}'",) - } - (Some(short), None) => { - format!("'-{short}[{help}]{completions}'") + let all = if all.len() < 2 { + all.join(" ") + } else { + format!("'{{{}}}'", all.join(",")) + }; + let name = arg.get_id(); + let completions = format!("{name}:{}", self.render_completion(arg)); + if arg.is_positional() { + if let ArgAction::Count | ArgAction::Append = arg.get_action() { + format!("'*::{completions}'") + } else if arg.is_required_set() || name == "new_plugin" { + format!("':{completions}'") + } else { + format!("'::{completions}'") } - (None, Some(long)) => format!("'--{long}=[{help}]{completions}'"), - (None, None) => self.render_positional(arg), + } else if arg.get_action().takes_values() { + format!("'{conflicts}{multiple}{all}={help}:{completions}'") + } else { + format!("'{conflicts}{multiple}{all}{help}'") } } - fn render_positional(&self, arg: &Arg) -> String { - let name = arg.get_id(); - let plural = if matches!(arg.get_action(), ArgAction::Append) { - "*" - } else { - "1" + fn get_short_and_longs(&self, arg: &Arg) -> Vec { + let short = arg + .get_short_and_visible_aliases() + .unwrap_or_default() + .into_iter() + .map(|s| format!("-{s}")) + .sorted(); + let long = arg + .get_long_and_visible_aliases() + .unwrap_or_default() + .into_iter() + .map(|s| format!("--{s}")) + .sorted(); + short.chain(long).collect() + } + + fn render_completion(&self, arg: &Arg) -> String { + let possible_values = arg.get_possible_values(); + if !possible_values.is_empty() { + return format!( + "({})", + possible_values + .iter() + .map(|v| escape_value(v.get_name())) + .collect::>() + .join(" ") + ); }; match arg.get_value_hint() { - ValueHint::DirPath => format!("'{plural}: :_directories'"), - ValueHint::FilePath => format!("'{plural}: :_files'"), - ValueHint::AnyPath => format!("'{plural}: :_files'"), - ValueHint::CommandString => format!("'{plural}: :_command_string -c'"), - ValueHint::ExecutablePath => format!("'{plural}: :_command_names -e'"), - ValueHint::Username => format!("'{plural}: :_users'"), - ValueHint::Hostname => format!("'{plural}: :_hosts'"), - ValueHint::Url => format!("'{plural}: :_urls'"), - ValueHint::EmailAddress => format!("'{plural}: :_email_addresses'"), - _ if name == "tool" => format!("'{plural}::{name}:__rtx_tool_versions'"), - _ => format!("'*::{name}:'"), + ValueHint::DirPath => format!("_directories"), + ValueHint::FilePath => format!("_files"), + ValueHint::AnyPath => format!("_files"), + ValueHint::CommandName => format!("_command_names -e"), + ValueHint::CommandString => format!("_cmdstring"), + ValueHint::CommandWithArguments => format!("_cmdambivalent"), + ValueHint::ExecutablePath => format!("_absolute_command_paths"), + ValueHint::Username => format!("_users"), + ValueHint::Hostname => format!("_hosts"), + ValueHint::Url => format!("_urls"), + ValueHint::EmailAddress => format!("_email_addresses"), + ValueHint::Other => format!("( )"), + _ => match arg.get_id().as_str() { + "tool" => format!("__rtx_tool_versions"), + "plugin" => format!("__rtx_plugins"), + "new_plugin" => format!("__rtx_all_plugins"), + "alias" => format!("__rtx_aliases"), + "prefix" => format!("__rtx_prefixes"), + _ => format!(""), + }, } } fn render_command_funcs(&self, cmds: &[&Command]) -> String { let cmd = cmds.last().unwrap(); cmd.get_subcommands() + .filter(|c| !banned(c)) .sorted_by_key(|c| c.get_name()) .map(|cmd| { - let func = cmds - .iter() - .chain(once(&cmd)) - .map(|c| c.get_name()) - .join("_") - .replace('-', "_"); let mut cmds = cmds.iter().copied().collect_vec(); cmds.push(cmd); + let func = func_name(&cmds); let args = self.render_args(&cmds); let subcommand_funcs = self.render_command_funcs(&cmds); (formatdoc! {r#" + (( $+functions[__{func}_cmd] )) || __{func}_cmd() {{ {args} }} @@ -261,16 +296,16 @@ impl ZshComplete { .join("\n") } - fn render_command_descriptions(&self) -> String { - let commands = self - .cmd + fn render_command_descriptions(&self, cmds: &[&Command]) -> String { + let cmd = cmds.last().unwrap(); + let commands = cmd .get_subcommands() - .filter(|c| !c.is_hide_set()) + .filter(|c| !c.is_hide_set() && !banned(c)) .sorted_by_key(|c| c.get_name()) .map(|cmd| { let name = cmd.get_name(); let about = match cmd.get_about() { - Some(about) => escape_single_quote(first_line(&about.to_string())).to_string(), + Some(about) => help_escape(first_line(&about.to_string())).to_string(), None => String::new(), }; let aliases = cmd.get_visible_aliases().sorted().collect_vec(); @@ -283,23 +318,69 @@ impl ZshComplete { }) .collect::>() .join("\n"); - formatdoc! {r#" - (( $+functions[_rtx_cmds] )) || - _rtx_cmds() {{ + let func = format!("__{}_cmds", func_name(cmds)); + let mut out = vec![formatdoc! {r#" + (( $+functions[{func}] )) || + {func}() {{ local commands; commands=( {commands} ) _describe -t commands 'command' commands "$@" - }}"#} + }}"#}]; + + for cmd in cmd + .get_subcommands() + .filter(|c| c.has_subcommands() && !banned(c)) + { + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + out.push(self.render_command_descriptions(&cmds)); + } + out.join("\n") } } +fn func_name(cmds: &[&Command]) -> String { + cmds.iter() + .map(|c| c.get_name()) + .join("_") + .replace('-', "_") +} + fn first_line(s: &str) -> &str { s.lines().next().unwrap_or_default() } -fn escape_single_quote(s: &str) -> String { - s.replace('\'', r"'\''") +fn help_escape(s: &str) -> String { + s.replace('\\', "\\\\") + .replace('\'', "'\\''") + .replace('[', "\\[") + .replace(']', "\\]") + .replace(':', "\\:") + .replace('$', "\\$") + .replace('`', "\\`") +} + +/// Escape value string inside single quotes and parentheses +fn escape_value(string: &str) -> String { + string + .replace('\\', "\\\\") + .replace('\'', "'\\''") + .replace('[', "\\[") + .replace(']', "\\]") + .replace(':', "\\:") + .replace('$', "\\$") + .replace('`', "\\`") + .replace('(', "\\(") + .replace(')', "\\)") + .replace(' ', "\\ ") +} + +static BANNED_COMMANDS: Lazy> = + Lazy::new(|| ["render-mangen", "render-help", "render-completion"].into()); + +fn banned(cmd: &Command) -> bool { + BANNED_COMMANDS.contains(&cmd.get_name()) } #[cfg(test)] diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 48b916b0f..a155b3283 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -11,6 +11,7 @@ use crate::output::Output; #[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsSet { /// The setting to set + #[clap()] pub key: String, /// The value to set pub value: String, From f688de27a1b9eacb75ef5b873a0878f624b915e0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:54:13 -0600 Subject: [PATCH 1177/1891] remove deprecated missing_runtime_behavior flag (#1081) --- .github/workflows/test-plugins.yml | 1 - e2e/cd/test_bash | 7 +- e2e/cd/test_zsh | 4 - e2e/run_test | 4 +- e2e/test_local | 2 - e2e/test_poetry | 5 +- e2e/test_tiny | 2 +- e2e/test_tool_versions_alt | 1 - justfile | 1 - lefthook.yml | 1 - src/cli/bin_paths.rs | 7 +- src/cli/direnv/envrc.rs | 5 +- src/cli/direnv/exec.rs | 5 +- src/cli/env.rs | 5 +- src/cli/exec.rs | 5 +- src/cli/hook_env.rs | 4 +- src/cli/local.rs | 17 ----- ...cli__settings__ls__tests__settings_ls.snap | 2 - ...i__settings__set__tests__settings_set.snap | 2 - src/cli/settings/unset.rs | 1 - src/cli/shell.rs | 10 ++- src/cli/use.rs | 3 +- src/config/config_file/rtx_toml.rs | 34 +-------- src/config/mod.rs | 2 +- src/config/settings.rs | 28 ------- src/env.rs | 34 --------- src/fake_asdf.rs | 1 - src/test.rs | 1 - src/toolset/builder.rs | 12 --- src/toolset/mod.rs | 75 ++----------------- src/ui/prompt.rs | 7 -- 31 files changed, 35 insertions(+), 253 deletions(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 61e92e5be..fab160ec9 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -40,7 +40,6 @@ jobs: runs-on: ubuntu-22.04 needs: [build-linux] env: - RTX_MISSING_RUNTIME_BEHAVIOR: autoinstall GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} strategy: fail-fast: false diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 5713a407f..afc70ca4d 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -4,11 +4,6 @@ set -euo pipefail orig_path="$PATH" -rtx trust -rtx trust ../.e2e.rtx.toml -rtx trust 18/.e2e.rtx.toml -rtx i tiny@latest - # shellcheck disable=SC1090 eval "$(rtx activate bash --status)" && _rtx_hook @@ -39,7 +34,7 @@ test "$(node -v)" = "v20.0.0" assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "cd" -cd 18 && _rtx_hook +cd 18 && rtx i && _rtx_hook test "$(node -v)" = "v18.0.0" assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/18.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "18" diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index f992f0c66..bc459a7b6 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -2,10 +2,6 @@ set -euo pipefail orig_path="$PATH" -rtx trust -rtx trust ../.e2e.rtx.toml -rtx trust 18/.e2e.rtx.toml - assert_path() { local expected="${1//$HOME/\~}" local actual="${PATH/%$orig_path/}" diff --git a/e2e/run_test b/e2e/run_test index c8c9f8aeb..70885ce1f 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -9,13 +9,13 @@ setup_env() { export ROOT export PATH="$ROOT/target/debug:$PATH" export RTX_USE_TOML="0" - export RTX_MISSING_RUNTIME_BEHAVIOR="autoinstall" export RTX_DATA_DIR="$HOME/.rtx/e2e" export RTX_CACHE_DIR="$HOME/.rtx/e2e/cache" export RTX_CONFIG_DIR="$HOME/.rtx/e2e/config" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" + export RTX_TRUSTED_CONFIG_PATHS="$ROOT/e2e" export RTX_YES="yes" unset GOPATH } @@ -31,8 +31,8 @@ setup_config_files() { run_test() { echo "Running $TEST" rm -f "$RTX_CONFIG_FILE" - rtx trust "$ROOT/e2e/.e2e.rtx.toml" >/dev/null cd "$(dirname "$TEST")" + rtx i "./$(basename "$TEST")" } diff --git a/e2e/test_local b/e2e/test_local index c2d973ac1..8670e1ac5 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -16,8 +16,6 @@ assert_raises() { fi } -export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall - assert_raises "rtx uninstall shfmt@3.6.0" assert "rtx local" "#:schema ../../schema/rtx.json diff --git a/e2e/test_poetry b/e2e/test_poetry index 049cae951..a8f59f74c 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -9,12 +9,11 @@ export POETRY_HOME=".poetry" eval "$(rtx activate bash)" rtx i python -rtx i poetry +rtx i poetry && _rtx_hook -_rtx_hook assert "poetry --version" "Poetry (version 1.7.1)" python3 -V -poetry install +poetry install && _rtx_hook poetry env info assert "$(poetry env info -e) --version" "Python 3.12.0" assert "echo \$VIRTUAL_ENV" "$(poetry env info -p)" diff --git a/e2e/test_tiny b/e2e/test_tiny index 3d6b17711..81c524681 100755 --- a/e2e/test_tiny +++ b/e2e/test_tiny @@ -5,7 +5,7 @@ source "$(dirname "$0")/assert.sh" rtx cache clean rm -rf "$RTX_DATA_DIR/installs/tiny" -RTX_CONFIRM=y rtx ls # auto-trust +rtx ls # this will fail when calling bin/list-all, but it won't stop it from executing RTX_TINY_LIST_ALL_FAIL=1 RTX_TINY_VERSION=latest rtx env >/dev/null diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index 01bf7bfa8..8e9d0e796 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -euo pipefail -export RTX_MISSING_RUNTIME_BEHAVIOR=autoinstall export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.MISSING diff --git a/justfile b/justfile index ff82bd530..ca7ffc715 100644 --- a/justfile +++ b/justfile @@ -2,7 +2,6 @@ set shell := ["bash", "-uc"] export RTX_DATA_DIR := "/tmp/rtx" export PATH := env_var_or_default("CARGO_TARGET_DIR", justfile_directory() / "target") / "debug:" + env_var("PATH") -export RTX_MISSING_RUNTIME_BEHAVIOR := "autoinstall" export RUST_TEST_THREADS := "1" # defaults to `just test` diff --git a/lefthook.yml b/lefthook.yml index da19c9b66..4a6ea8bad 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -3,7 +3,6 @@ pre-commit: commands: pre-commit: run: just -v pre-commit - interactive: true skip_output: - meta - summary diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 252086c56..0edcfc6b3 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -11,9 +11,7 @@ pub struct BinPaths {} impl BinPaths { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new() - .with_install_missing() - .build(&mut config)?; + let ts = ToolsetBuilder::new().build(&mut config)?; for p in ts.list_paths(&config) { rtxprintln!(out, "{}", p.display()); } @@ -23,10 +21,11 @@ impl BinPaths { #[cfg(test)] mod tests { - use crate::assert_cli_snapshot; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_bin_paths() { + assert_cli!("i"); assert_cli_snapshot!("bin-paths"); } } diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 8b98946d1..1d3af25a9 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -18,9 +18,8 @@ pub struct Envrc {} impl Envrc { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new() - .with_install_missing() - .build(&mut config)?; + let ts = ToolsetBuilder::new().build(&mut config)?; + let envrc_path = env::RTX_TMP_DIR .join("direnv") .join(hash_to_str(dirs::CURRENT.deref()) + ".envrc"); diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 68eb8ff94..361b74c56 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -22,9 +22,8 @@ struct DirenvWatches { impl DirenvExec { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new() - .with_install_missing() - .build(&mut config)?; + let ts = ToolsetBuilder::new().build(&mut config)?; + let mut cmd = env_cmd(); for (k, v) in ts.env_with_path(&config) { diff --git a/src/cli/env.rs b/src/cli/env.rs index 1bb1279f2..985cc7100 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -28,10 +28,11 @@ pub struct Env { impl Env { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new() - .with_install_missing() + let mut ts = ToolsetBuilder::new() .with_args(&self.tool) .build(&mut config)?; + ts.install_arg_versions(&mut config)?; + if self.json { self.output_json(config, out, ts) } else { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index ebefbb96e..49c8c2599 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -46,10 +46,11 @@ pub struct Exec { impl Exec { pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new() + let mut ts = ToolsetBuilder::new() .with_args(&self.tool) - .with_install_missing() .build(&mut config)?; + ts.install_arg_versions(&mut config)?; + let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); let env = ts.env_with_path(&config); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index e0baadb18..767dc37a9 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -33,9 +33,7 @@ pub struct HookEnv { impl HookEnv { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new() - .with_install_missing() - .build(&mut config)?; + let ts = ToolsetBuilder::new().build(&mut 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/local.rs b/src/cli/local.rs index afd4a7953..0c09713ec 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -5,13 +5,11 @@ use console::style; use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; use crate::output::Output; use crate::plugins::PluginName; -use crate::ui::multi_progress_report::MultiProgressReport; use crate::{dirs, env, file}; /// Sets/gets tool version in local .tool-versions or .rtx.toml @@ -127,7 +125,6 @@ pub fn local( if !runtime.is_empty() { let runtimes = ToolArg::double_tool_condition(&runtime.clone()); if cf.display_runtime(out, &runtimes)? { - install_missing_runtimes(&mut config, cf.as_ref())?; return Ok(()); } let pin = pin || (config.settings.asdf_compat && !fuzzy); @@ -140,8 +137,6 @@ pub fn local( display_path(path), style(tools).cyan() ); - } else { - install_missing_runtimes(&mut config, cf.as_ref())?; } if !runtime.is_empty() || remove.is_some() { @@ -153,18 +148,6 @@ pub fn local( Ok(()) } -fn install_missing_runtimes(config: &mut Config, cf: &dyn ConfigFile) -> Result<()> { - let mut ts = cf.to_toolset().clone(); - ts.latest_versions = true; - ts.resolve(config); - if !ts.list_missing_versions(config).is_empty() { - let mpr = MultiProgressReport::new(config.show_progress_bars()); - ts.install_missing(config, mpr)?; - } - - Ok(()) -} - static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # set the current version of node to 20.x for the current directory diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 97eefb15c..178a161b4 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -11,10 +11,8 @@ experimental = true jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] -missing_runtime_behavior = autoinstall plugin_autoupdate_last_check_duration = 20 raw = false trusted_config_paths = [] verbose = true yes = true - diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index b561ce783..17a79df6f 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -11,10 +11,8 @@ experimental = true jobs = 2 legacy_version_file = false legacy_version_file_disable_tools = [] -missing_runtime_behavior = autoinstall plugin_autoupdate_last_check_duration = 1 raw = false trusted_config_paths = [] verbose = true yes = true - diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 9ba5cf02f..180922701 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -51,7 +51,6 @@ mod tests { jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] - missing_runtime_behavior = autoinstall plugin_autoupdate_last_check_duration = 20 raw = false trusted_config_paths = [] diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 41486d484..00776bbca 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -24,13 +24,15 @@ pub struct Shell { impl Shell { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new() - .with_install_missing() - .with_args(&self.tool) - .build(&mut config)?; 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 shell = get_shell(None).expect("no shell detected"); for (p, tv) in ts.list_current_installed_versions(&config) { diff --git a/src/cli/use.rs b/src/cli/use.rs index 1a06f8c39..b63deac43 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -67,8 +67,9 @@ impl Use { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let mut ts = ToolsetBuilder::new() .with_args(&self.tool) - .with_install_missing() .build(&mut config)?; + ts.install_arg_versions(&mut config)?; + ts.versions .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index e93dccb90..90a9875d7 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -12,7 +12,7 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; -use crate::config::{config_file, AliasMap, MissingRuntimeBehavior}; +use crate::config::{config_file, AliasMap}; use crate::errors::Error::UntrustedConfig; use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; @@ -377,10 +377,6 @@ impl RtxToml { let k = format!("{}.{}", key, config_key); match config_key.to_lowercase().as_str() { "experimental" => settings.experimental = Some(self.parse_bool(&k, v)?), - "missing_runtime_behavior" => { - settings.missing_runtime_behavior = - Some(self.parse_missing_runtime_behavior(&k, v)?) - } "legacy_version_file" => { settings.legacy_version_file = Some(self.parse_bool(&k, v)?) } @@ -512,16 +508,6 @@ impl RtxToml { } } - fn parse_string(&mut self, k: &str, v: &Item) -> Result { - match v.as_value().map(|v| v.as_str()) { - Some(Some(v)) => { - let v = self.parse_template(k, v)?; - Ok(v) - } - _ => parse_error!(k, v, "string")?, - } - } - fn parse_string_array(&self, k: &String, v: &Item) -> Result> { match v .as_array() @@ -532,24 +518,6 @@ impl RtxToml { } } - fn parse_missing_runtime_behavior( - &mut self, - k: &str, - v: &Item, - ) -> Result { - let v = self.parse_string("missing_runtime_behavior", v)?; - warn!("The 'missing_runtime_behavior' setting is deprecated. Use '--yes' instead."); - match v.to_lowercase().as_str() { - "warn" => Ok(MissingRuntimeBehavior::Warn), - "ignore" => Ok(MissingRuntimeBehavior::Ignore), - "prompt" => Ok(MissingRuntimeBehavior::Prompt), - "autoinstall" => Ok(MissingRuntimeBehavior::AutoInstall), - _ => Err(eyre!( - "expected {k} to be one of: 'warn', 'ignore', 'prompt', 'autoinstall'. Got: {v}" - )), - } - } - pub fn update_setting>(&mut self, key: &str, value: V) { let key = key.split('.').collect::>(); let mut settings = self diff --git a/src/config/mod.rs b/src/config/mod.rs index 8023f5dcb..bc7729af7 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -11,7 +11,7 @@ use itertools::Itertools; use once_cell::sync::OnceCell; use rayon::prelude::*; -pub use settings::{MissingRuntimeBehavior, Settings}; +pub use settings::Settings; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; diff --git a/src/config/settings.rs b/src/config/settings.rs index 0da0d0d46..bbb215d5d 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -13,8 +13,6 @@ use crate::{duration, env}; pub struct Settings { #[config(env = "RTX_EXPERIMENTAL", default = false)] pub experimental: bool, - #[config(env = "RTX_MISSING_RUNTIME_BEHAVIOR")] - pub missing_runtime_behavior: MissingRuntimeBehavior, #[config(env = "RTX_ALWAYS_KEEP_DOWNLOAD", default = false)] pub always_keep_download: bool, #[config(env = "RTX_ALWAYS_KEEP_INSTALL", default = false)] @@ -54,7 +52,6 @@ impl Default for Settings { impl Settings { pub fn default_builder() -> Builder { let mut partial = SettingsPartial::empty(); - partial.missing_runtime_behavior = Some(MissingRuntimeBehavior::Warn); partial.plugin_autoupdate_last_check_duration = Some(duration::WEEKLY); partial.yes = Some(*env::RTX_YES); if *env::RTX_LOG_LEVEL < LevelFilter::Info { @@ -67,10 +64,6 @@ impl Settings { pub fn to_index_map(&self) -> BTreeMap { let mut map = BTreeMap::new(); map.insert("experimental".to_string(), self.experimental.to_string()); - map.insert( - "missing_runtime_behavior".to_string(), - self.missing_runtime_behavior.to_string(), - ); map.insert( "always_keep_download".to_string(), self.always_keep_download.to_string(), @@ -126,7 +119,6 @@ impl Settings { #[derive(Default, Clone)] pub struct SettingsBuilder { pub experimental: Option, - pub missing_runtime_behavior: Option, pub always_keep_download: Option, pub always_keep_install: Option, pub legacy_version_file: Option, @@ -148,9 +140,6 @@ impl SettingsBuilder { if other.experimental.is_some() { self.experimental = other.experimental; } - if other.missing_runtime_behavior.is_some() { - self.missing_runtime_behavior = other.missing_runtime_behavior; - } if other.always_keep_download.is_some() { self.always_keep_download = other.always_keep_download; } @@ -195,20 +184,6 @@ impl SettingsBuilder { pub fn build(&self) -> Settings { let mut settings = Settings::default(); settings.experimental = self.experimental.unwrap_or(settings.experimental); - settings.missing_runtime_behavior = match env::RTX_MISSING_RUNTIME_BEHAVIOR - .to_owned() - .unwrap_or_default() - .as_ref() - { - "autoinstall" => MissingRuntimeBehavior::AutoInstall, - "warn" => MissingRuntimeBehavior::Warn, - "ignore" => MissingRuntimeBehavior::Ignore, - "prompt" => MissingRuntimeBehavior::Prompt, - _ => self - .missing_runtime_behavior - .clone() - .unwrap_or(settings.missing_runtime_behavior), - }; settings.always_keep_download = self .always_keep_download .unwrap_or(settings.always_keep_download); @@ -259,9 +234,6 @@ impl Debug for SettingsBuilder { if let Some(experimental) = self.experimental { d.field("experimental", &experimental); } - if let Some(missing_runtime_behavior) = &self.missing_runtime_behavior { - d.field("missing_runtime_behavior", &missing_runtime_behavior); - } if let Some(always_keep_download) = self.always_keep_download { d.field("always_keep_download", &always_keep_download); } diff --git a/src/env.rs b/src/env.rs index aeb1302be..10d121756 100644 --- a/src/env.rs +++ b/src/env.rs @@ -46,8 +46,6 @@ pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); pub static RTX_EXE: Lazy = Lazy::new(|| current_exe().unwrap_or_else(|_| "rtx".into())); pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); -pub static RTX_MISSING_RUNTIME_BEHAVIOR: Lazy> = - Lazy::new(|| var("RTX_MISSING_RUNTIME_BEHAVIOR").ok()); pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) }); @@ -79,7 +77,6 @@ pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH" None => vec![], }); pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); -pub static RTX_CONFIRM: Lazy = Lazy::new(|| var_confirm("RTX_CONFIRM")); pub static RTX_YES: Lazy = Lazy::new(|| *CI || var_is_true("RTX_YES")); pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| match var_option_bool("RTX_ALL_COMPILE") { Some(v) => v, @@ -212,13 +209,6 @@ pub static RTX_GO_SET_GOROOT: Lazy> = pub static RTX_GO_SET_GOPATH: Lazy> = Lazy::new(|| var_option_bool("RTX_GO_SET_GOPATH")); -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Confirm { - Yes, - No, - Prompt, -} - fn get_env_diff() -> EnvDiff { let env = vars().collect::>(); match env.get("__RTX_DIFF") { @@ -270,16 +260,6 @@ fn var_url(key: &str) -> Option { var(key).ok().map(|v| Url::parse(&v).unwrap()) } -fn var_confirm(key: &str) -> Confirm { - if var_is_true(key) { - Confirm::Yes - } else if var_is_false(key) { - Confirm::No - } else { - Confirm::Prompt - } -} - fn var_duration(key: &str) -> Option { var(key) .ok() @@ -451,18 +431,4 @@ mod tests { ); remove_var("RTX_TEST_PATH"); } - - #[test] - fn test_var_confirm() { - set_var("RTX_TEST_CONFIRM", "true"); - assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::Yes); - remove_var("RTX_TEST_CONFIRM"); - set_var("RTX_TEST_CONFIRM", "false"); - assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::No); - remove_var("RTX_TEST_CONFIRM"); - set_var("RTX_TEST_CONFIRM", "prompt"); - assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::Prompt); - remove_var("RTX_TEST_CONFIRM"); - assert_eq!(var_confirm("RTX_TEST_CONFIRM"), Confirm::Prompt); - } } diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index cea58af14..3434e359b 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -20,7 +20,6 @@ pub fn setup() -> color_eyre::Result { // rtx="${{RTX_EXE:-rtx}}" formatdoc! {r#" #!/bin/sh - export RTX_MISSING_RUNTIME_BEHAVIOR=ignore rtx asdf "$@" "#}, )?; diff --git a/src/test.rs b/src/test.rs index 9c4315500..dd9597b5f 100644 --- a/src/test.rs +++ b/src/test.rs @@ -22,7 +22,6 @@ fn init() { env::set_var("RTX_CACHE_DIR", env::HOME.join("data/cache")); env::set_var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME", ".test-tool-versions"); env::set_var("RTX_DEFAULT_CONFIG_FILENAME", ".test.rtx.toml"); - env::set_var("RTX_MISSING_RUNTIME_BEHAVIOR", "autoinstall"); //env::set_var("TERM", "dumb"); reset_config(); } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 0bca046e2..fb129cc1e 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -7,12 +7,10 @@ use crate::cli::args::tool::ToolArg; use crate::config::Config; use crate::env; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; -use crate::ui::multi_progress_report::MultiProgressReport; #[derive(Debug, Default)] pub struct ToolsetBuilder { args: Vec, - install_missing: bool, latest_versions: bool, global_only: bool, tool_filter: Option>, @@ -28,11 +26,6 @@ impl ToolsetBuilder { self } - pub fn with_install_missing(mut self) -> Self { - self.install_missing = true; - self - } - pub fn with_latest_versions(mut self) -> Self { self.latest_versions = true; self @@ -62,11 +55,6 @@ impl ToolsetBuilder { } toolset.resolve(config); - if self.install_missing { - let mpr = MultiProgressReport::new(config.show_progress_bars()); - toolset.install_missing(config, mpr)?; - } - debug!("{}", toolset); Ok(toolset) } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 41153844a..ee4bd84c0 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -6,9 +6,7 @@ use std::sync::{Arc, Mutex}; use std::thread; use color_eyre::eyre::Result; -use console::style; -use dialoguer::theme::ColorfulTheme; -use dialoguer::MultiSelect; + use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; @@ -19,7 +17,7 @@ pub use tool_version::ToolVersion; pub use tool_version_list::ToolVersionList; pub use tool_version_request::ToolVersionRequest; -use crate::config::{Config, MissingRuntimeBehavior}; +use crate::config::Config; use crate::env; use crate::install_context::InstallContext; use crate::plugins::PluginName; @@ -87,56 +85,15 @@ impl Toolset { .par_iter_mut() .for_each(|(_, v)| v.resolve(config, self.latest_versions)); } - pub fn install_missing(&mut self, config: &mut Config, mpr: MultiProgressReport) -> Result<()> { + pub fn install_arg_versions(&mut self, config: &mut Config) -> Result<()> { + let mpr = MultiProgressReport::new(config.show_progress_bars()); let versions = self .list_missing_versions(config) .into_iter() - .cloned() - .collect_vec(); - if versions.is_empty() { - return Ok(()); - } - let argument_versions = versions - .iter() .filter(|tv| matches!(self.versions[&tv.plugin_name].source, ToolSource::Argument)) .cloned() .collect_vec(); - let warn = || { - let versions = versions - .iter() - .filter(|tv| !matches!(self.versions[&tv.plugin_name].source, ToolSource::Argument)) - .cloned() - .collect_vec(); - if !versions.is_empty() { - let display_versions = display_versions(&versions); - let plural_versions = if versions.len() == 1 { "" } else { "s" }; - warn!( - "Tool{} not installed: {} (install with: rtx install)", - plural_versions, display_versions - ); - } - }; - match config.settings.missing_runtime_behavior { - MissingRuntimeBehavior::Ignore => { - self.install_versions(config, argument_versions, &mpr, false)?; - } - MissingRuntimeBehavior::Warn => { - warn(); - self.install_versions(config, argument_versions, &mpr, false)?; - } - MissingRuntimeBehavior::Prompt => { - let versions = prompt_for_versions(&versions)?; - if versions.is_empty() { - warn(); - } else { - self.install_versions(config, versions, &mpr, false)?; - } - } - MissingRuntimeBehavior::AutoInstall => { - self.install_versions(config, versions, &mpr, false)?; - } - } - Ok(()) + self.install_versions(config, versions, &mpr, false) } pub fn list_missing_plugins(&self, config: &mut Config) -> Vec { @@ -398,25 +355,3 @@ impl Display for Toolset { write!(f, "{}", plugins.join(", ")) } } - -fn display_versions(versions: &[ToolVersion]) -> String { - let display_versions = versions - .iter() - .map(|v| style(&v.to_string()).cyan().for_stderr().to_string()) - .join(", "); - display_versions -} - -fn prompt_for_versions(versions: &[ToolVersion]) -> Result> { - if !console::user_attended_stderr() { - return Ok(vec![]); - } - Ok(MultiSelect::with_theme(&ColorfulTheme::default()) - .with_prompt("Select versions to install") - .items(versions) - .defaults(&versions.iter().map(|_| true).collect_vec()) - .interact()? - .into_iter() - .map(|i| versions[i].clone()) - .collect()) -} diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index dd663453f..0a0ea19ba 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -3,18 +3,11 @@ use std::sync::Mutex; use dialoguer::Confirm; -use crate::env; - static MUTEX: Mutex<()> = Mutex::new(()); pub fn confirm(message: &str) -> io::Result { let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once - match *env::RTX_CONFIRM { - env::Confirm::Yes => return Ok(true), - env::Confirm::No => return Ok(false), - env::Confirm::Prompt => (), - } if !console::user_attended_stderr() { return Ok(false); } From 8920713ec71779ceffb4fe75eec6f5c0fb535fda Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:05:30 -0600 Subject: [PATCH 1178/1891] shims: insert rtx PATH entries just before the shim directory (#1082) * remove deprecated missing_runtime_behavior flag * shims: insert rtx PATH entries just before the shim directory Before, rtx would put the PATH entries at the front of PATH but that is too aggressive in some scenarios Fixes #1061 --- e2e/assert.sh | 9 ++++ e2e/test_shims | 7 ++- src/main.rs | 1 + src/path_env.rs | 122 +++++++++++++++++++++++++++++++++++++++++++++ src/toolset/mod.rs | 21 ++++---- 5 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 src/path_env.rs diff --git a/e2e/assert.sh b/e2e/assert.sh index 246fb2571..1b3dfa93c 100644 --- a/e2e/assert.sh +++ b/e2e/assert.sh @@ -33,3 +33,12 @@ assert_fail() { exit 1 fi } + +assert_matches() { + local actual + actual="$(bash -c "$1")" + if [[ ! "$actual" =~ $2 ]]; then + echo "Expected '$2' to match '$actual'" + exit 1 + fi +} diff --git a/e2e/test_shims b/e2e/test_shims index 56a74b0ac..ba0a9919c 100755 --- a/e2e/test_shims +++ b/e2e/test_shims @@ -3,6 +3,11 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" +export PATH="/XSTARTX:$RTX_DATA_DIR/shims:/XENDX$PATH" rtx i node rtx reshim -assert "$RTX_DATA_DIR/shims/node -v" "v20.0.0" +assert "node -v" "v20.0.0" + +# should still have this prefix since rtx should only modify PATH +# starting at the shim directory +assert_matches "node -p 'process.env.PATH'" "^/XSTARTX:" diff --git a/src/main.rs b/src/main.rs index 858f77896..338c942da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,6 +46,7 @@ mod install_context; mod lock_file; mod logger; mod migrate; +mod path_env; mod plugins; mod rand; mod runtime_symlinks; diff --git a/src/path_env.rs b/src/path_env.rs new file mode 100644 index 000000000..3d9edb9ca --- /dev/null +++ b/src/path_env.rs @@ -0,0 +1,122 @@ +use crate::dirs; +use itertools::Itertools; +use std::env::join_paths; +use std::ffi::OsString; +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::path::PathBuf; + +pub struct PathEnv { + pre: Vec, + rtx: Vec, + post: Vec, + seen_shims: bool, +} + +impl PathEnv { + pub fn new() -> Self { + Self { + pre: Vec::new(), + rtx: Vec::new(), + post: Vec::new(), + seen_shims: false, + } + } + + pub fn add(&mut self, path: PathBuf) { + self.rtx.push(path); + } + + pub fn to_vec(&self) -> Vec { + let mut paths = self.pre.iter().chain(self.rtx.iter()).collect_vec(); + if self.seen_shims { + paths.push(&dirs::SHIMS); + } + paths.into_iter().chain(self.post.iter()).cloned().collect() + } + + pub fn join(&self) -> OsString { + join_paths(self.to_vec()).unwrap() + } +} + +impl Display for PathEnv { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.join().to_string_lossy()) + } +} + +impl FromIterator for PathEnv { + fn from_iter>(paths: T) -> Self { + let mut path_env = Self::new(); + + for path in paths { + if path_env.seen_shims { + path_env.post.push(path); + } else if path == *dirs::SHIMS { + path_env.seen_shims = true; + } else { + path_env.pre.push(path); + } + } + if !path_env.seen_shims { + path_env.post = path_env.pre; + path_env.pre = Vec::new(); + } + + path_env + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_path_env() { + let mut path_env = PathEnv::from_iter( + [ + "/before-1", + "/before-2", + "/before-3", + dirs::SHIMS.to_str().unwrap(), + "/after-1", + "/after-2", + "/after-3", + ] + .map(PathBuf::from), + ); + path_env.add("/1".into()); + path_env.add("/2".into()); + path_env.add("/3".into()); + assert_eq!( + path_env.to_string(), + format!( + "/before-1:/before-2:/before-3:/1:/2:/3:{}:/after-1:/after-2:/after-3", + dirs::SHIMS.to_str().unwrap() + ) + ); + } + + #[test] + fn test_path_env_no_rtx() { + let mut path_env = PathEnv::from_iter( + [ + "/before-1", + "/before-2", + "/before-3", + "/after-1", + "/after-2", + "/after-3", + ] + .map(PathBuf::from), + ); + path_env.add("/1".into()); + path_env.add("/2".into()); + path_env.add("/3".into()); + assert_eq!( + path_env.to_string(), + format!("/1:/2:/3:/before-1:/before-2:/before-3:/after-1:/after-2:/after-3") + ); + } +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index ee4bd84c0..5047e1f56 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -1,5 +1,4 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::env::join_paths; use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; @@ -20,6 +19,7 @@ pub use tool_version_request::ToolVersionRequest; use crate::config::Config; use crate::env; use crate::install_context::InstallContext; +use crate::path_env::PathEnv; use crate::plugins::PluginName; use crate::runtime_symlinks; use crate::shims; @@ -261,12 +261,18 @@ impl Toolset { .collect() } pub fn env_with_path(&self, config: &Config) -> BTreeMap { + let mut path_env = PathEnv::from_iter(env::PATH.clone()); + for p in config.path_dirs.clone() { + path_env.add(p); + } + for p in self.list_paths(config) { + path_env.add(p); + } let mut env = self.env(config); - let mut path_env = self.path_env(config); if let Some(path) = env.get("PATH") { - path_env = format!("{}:{}", path, path_env); + path_env.add(PathBuf::from(path)); } - env.insert("PATH".to_string(), path_env); + env.insert("PATH".to_string(), path_env.to_string()); env } pub fn env(&self, config: &Config) -> BTreeMap { @@ -298,13 +304,6 @@ impl Toolset { entries.extend(config.env.clone()); entries } - pub fn path_env(&self, config: &Config) -> String { - let installs = self.list_paths(config); - join_paths([config.path_dirs.clone(), installs, env::PATH.clone()].concat()) - .unwrap() - .to_string_lossy() - .into() - } pub fn list_paths(&self, config: &Config) -> Vec { self.list_current_installed_versions(config) .into_par_iter() From e5ce65d4b5886ff17494eb717514e74966eb9975 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:31:44 -0600 Subject: [PATCH 1179/1891] completions: reformat zsh with shfmt (#1083) --- completions/_rtx | 1785 +++++++++++++------------ e2e/ruby/test_ruby | 1 + justfile | 2 +- src/cli/direnv/exec.rs | 1 - src/cli/render_completion.rs | 349 +---- src/main.rs | 4 +- src/shell/completions/mod.rs | 9 + src/shell/completions/zsh_complete.rs | 337 +++++ src/shell/mod.rs | 3 + 9 files changed, 1256 insertions(+), 1235 deletions(-) create mode 100644 src/shell/completions/mod.rs create mode 100644 src/shell/completions/zsh_complete.rs diff --git a/completions/_rtx b/completions/_rtx index 5540180a5..c28f5e641 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1,910 +1,923 @@ #compdef rtx _rtx() { - typeset -A opt_args - local context state line curcontext=$curcontext - local ret=1 + typeset -A opt_args + local context state line curcontext=$curcontext + local ret=1 - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_cmds' \ - '*::arg:->args' && ret=0 + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - (activate) __rtx_activate_cmd && ret=0 ;; - (a|aliases|alias) __rtx_alias_cmd && ret=0 ;; - (asdf) __rtx_asdf_cmd && ret=0 ;; - (bin-paths) __rtx_bin_paths_cmd && ret=0 ;; - (cache) __rtx_cache_cmd && ret=0 ;; - (complete|completions|completion) __rtx_completion_cmd && ret=0 ;; - (current) __rtx_current_cmd && ret=0 ;; - (deactivate) __rtx_deactivate_cmd && ret=0 ;; - (direnv) __rtx_direnv_cmd && ret=0 ;; - (doctor) __rtx_doctor_cmd && ret=0 ;; - (e|env) __rtx_env_cmd && ret=0 ;; - (env-vars) __rtx_env_vars_cmd && ret=0 ;; - (x|exec) __rtx_exec_cmd && ret=0 ;; - (g|global) __rtx_global_cmd && ret=0 ;; - (hook-env) __rtx_hook_env_cmd && ret=0 ;; - (implode) __rtx_implode_cmd && ret=0 ;; - (i|install) __rtx_install_cmd && ret=0 ;; - (latest) __rtx_latest_cmd && ret=0 ;; - (link) __rtx_link_cmd && ret=0 ;; - (l|local) __rtx_local_cmd && ret=0 ;; - (list|ls) __rtx_ls_cmd && ret=0 ;; - (list-all|list-remote|ls-remote) __rtx_ls_remote_cmd && ret=0 ;; - (outdated) __rtx_outdated_cmd && ret=0 ;; - (p|plugin|plugin-list|plugins) __rtx_plugins_cmd && ret=0 ;; - (prune) __rtx_prune_cmd && ret=0 ;; - (reshim) __rtx_reshim_cmd && ret=0 ;; - (self-update) __rtx_self_update_cmd && ret=0 ;; - (settings) __rtx_settings_cmd && ret=0 ;; - (s|shell) __rtx_shell_cmd && ret=0 ;; - (sync) __rtx_sync_cmd && ret=0 ;; - (trust) __rtx_trust_cmd && ret=0 ;; - (remove|rm|uninstall) __rtx_uninstall_cmd && ret=0 ;; - (upgrade) __rtx_upgrade_cmd && ret=0 ;; - (u|use) __rtx_use_cmd && ret=0 ;; - (v|version) __rtx_version_cmd && ret=0 ;; - (where) __rtx_where_cmd && ret=0 ;; - (which) __rtx_which_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + activate) __rtx_activate_cmd && ret=0 ;; + a | aliases | alias) __rtx_alias_cmd && ret=0 ;; + asdf) __rtx_asdf_cmd && ret=0 ;; + bin-paths) __rtx_bin_paths_cmd && ret=0 ;; + cache) __rtx_cache_cmd && ret=0 ;; + complete | completions | completion) __rtx_completion_cmd && ret=0 ;; + current) __rtx_current_cmd && ret=0 ;; + deactivate) __rtx_deactivate_cmd && ret=0 ;; + direnv) __rtx_direnv_cmd && ret=0 ;; + doctor) __rtx_doctor_cmd && ret=0 ;; + e | env) __rtx_env_cmd && ret=0 ;; + env-vars) __rtx_env_vars_cmd && ret=0 ;; + x | exec) __rtx_exec_cmd && ret=0 ;; + g | global) __rtx_global_cmd && ret=0 ;; + hook-env) __rtx_hook_env_cmd && ret=0 ;; + implode) __rtx_implode_cmd && ret=0 ;; + i | install) __rtx_install_cmd && ret=0 ;; + latest) __rtx_latest_cmd && ret=0 ;; + link) __rtx_link_cmd && ret=0 ;; + l | local) __rtx_local_cmd && ret=0 ;; + list | ls) __rtx_ls_cmd && ret=0 ;; + list-all | list-remote | ls-remote) __rtx_ls_remote_cmd && ret=0 ;; + outdated) __rtx_outdated_cmd && ret=0 ;; + p | plugin | plugin-list | plugins) __rtx_plugins_cmd && ret=0 ;; + prune) __rtx_prune_cmd && ret=0 ;; + reshim) __rtx_reshim_cmd && ret=0 ;; + self-update) __rtx_self_update_cmd && ret=0 ;; + settings) __rtx_settings_cmd && ret=0 ;; + s | shell) __rtx_shell_cmd && ret=0 ;; + sync) __rtx_sync_cmd && ret=0 ;; + trust) __rtx_trust_cmd && ret=0 ;; + remove | rm | uninstall) __rtx_uninstall_cmd && ret=0 ;; + upgrade) __rtx_upgrade_cmd && ret=0 ;; + u | use) __rtx_use_cmd && ret=0 ;; + v | version) __rtx_version_cmd && ret=0 ;; + where) __rtx_where_cmd && ret=0 ;; + which) __rtx_which_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(( $+functions[__rtx_activate_cmd] )) || -__rtx_activate_cmd() { - _arguments -s -S \ - '::shell_type:(bash fish nu xonsh zsh)' \ - '--status[Show "rtx\: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_alias_cmd] )) || -__rtx_alias_cmd() { - _arguments -s -S \ - '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_alias_cmds' \ - '*::arg:->args' && ret=0 + return ret +} +(($ + functions[__rtx_activate_cmd])) || + __rtx_activate_cmd() { + _arguments -s -S \ + '::shell_type:(bash fish nu xonsh zsh)' \ + '--status[Show "rtx\: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_alias_cmd])) || + __rtx_alias_cmd() { + _arguments -s -S \ + '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_alias_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - (get) __rtx_alias_get_cmd && ret=0 ;; - (list|ls) __rtx_alias_ls_cmd && ret=0 ;; - (add|create|set) __rtx_alias_set_cmd && ret=0 ;; - (del|delete|remove|rm|unset) __rtx_alias_unset_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + get) __rtx_alias_get_cmd && ret=0 ;; + list | ls) __rtx_alias_ls_cmd && ret=0 ;; + add | create | set) __rtx_alias_set_cmd && ret=0 ;; + del | delete | remove | rm | unset) __rtx_alias_unset_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(( $+functions[__rtx_alias_get_cmd] )) || -__rtx_alias_get_cmd() { - _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_alias_ls_cmd] )) || -__rtx_alias_ls_cmd() { - _arguments -s -S \ - '::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_alias_set_cmd] )) || -__rtx_alias_set_cmd() { - _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ - ':value:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_alias_unset_cmd] )) || -__rtx_alias_unset_cmd() { - _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_asdf_cmd] )) || -__rtx_asdf_cmd() { - _arguments -s -S \ - '*::args:_cmdambivalent' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_bin_paths_cmd] )) || -__rtx_bin_paths_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_cache_cmd] )) || -__rtx_cache_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_cache_cmds' \ - '*::arg:->args' && ret=0 + return ret + } +(($ + functions[__rtx_alias_get_cmd])) || + __rtx_alias_get_cmd() { + _arguments -s -S \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_alias_ls_cmd])) || + __rtx_alias_ls_cmd() { + _arguments -s -S \ + '::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_alias_set_cmd])) || + __rtx_alias_set_cmd() { + _arguments -s -S \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + ':value:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_alias_unset_cmd])) || + __rtx_alias_unset_cmd() { + _arguments -s -S \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_asdf_cmd])) || + __rtx_asdf_cmd() { + _arguments -s -S \ + '*::args:_cmdambivalent' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_bin_paths_cmd])) || + __rtx_bin_paths_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_cache_cmd])) || + __rtx_cache_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_cache_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - (c|clean|clear) __rtx_cache_clear_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + c | clean | clear) __rtx_cache_clear_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(( $+functions[__rtx_cache_clear_cmd] )) || -__rtx_cache_clear_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_completion_cmd] )) || -__rtx_completion_cmd() { - _arguments -s -S \ - '::shell:(bash fish zsh)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_current_cmd] )) || -__rtx_current_cmd() { - _arguments -s -S \ - '::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_deactivate_cmd] )) || -__rtx_deactivate_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_direnv_cmd] )) || -__rtx_direnv_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_direnv_cmds' \ - '*::arg:->args' && ret=0 + return ret + } +(($ + functions[__rtx_cache_clear_cmd])) || + __rtx_cache_clear_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_completion_cmd])) || + __rtx_completion_cmd() { + _arguments -s -S \ + '::shell:(bash fish zsh)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_current_cmd])) || + __rtx_current_cmd() { + _arguments -s -S \ + '::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_deactivate_cmd])) || + __rtx_deactivate_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_direnv_cmd])) || + __rtx_direnv_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_direnv_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - (activate) __rtx_direnv_activate_cmd && ret=0 ;; - (envrc) __rtx_direnv_envrc_cmd && ret=0 ;; - (exec) __rtx_direnv_exec_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + activate) __rtx_direnv_activate_cmd && ret=0 ;; + envrc) __rtx_direnv_envrc_cmd && ret=0 ;; + exec) __rtx_direnv_exec_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(( $+functions[__rtx_direnv_activate_cmd] )) || -__rtx_direnv_activate_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_direnv_envrc_cmd] )) || -__rtx_direnv_envrc_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_direnv_exec_cmd] )) || -__rtx_direnv_exec_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_doctor_cmd] )) || -__rtx_doctor_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_env_cmd] )) || -__rtx_env_cmd() { - _arguments -s -S \ - '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ - '*::tool:__rtx_tool_versions' \ - '(-J --json)'{-J,--json}'[Output in JSON format]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_env_vars_cmd] )) || -__rtx_env_vars_cmd() { - _arguments -s -S \ - '--file=[The TOML file to update]:file:_files' \ - '*--remove=[Remove the environment variable from config file]:remove:' \ - '*::env_vars:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_exec_cmd] )) || -__rtx_exec_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ - '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_global_cmd] )) || -__rtx_global_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '--pin[Save exact version to \`~/.tool-versions\`]' \ - '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ - '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ - '--path[Get the path of the global config file]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_hook_env_cmd] )) || -__rtx_hook_env_cmd() { - _arguments -s -S \ - '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ - '--status[Show "rtx\: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_implode_cmd] )) || -__rtx_implode_cmd() { - _arguments -s -S \ - '--config[Also remove config directory]' \ - '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_install_cmd] )) || -__rtx_install_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_latest_cmd] )) || -__rtx_latest_cmd() { - _arguments -s -S \ - ':tool:__rtx_tool_versions' \ - '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_link_cmd] )) || -__rtx_link_cmd() { - _arguments -s -S \ - ':tool:__rtx_tool_versions' \ - ':path:_directories' \ - '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_local_cmd] )) || -__rtx_local_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-p --parent)'{-p,--parent}'[Recurse up to find a .tool-versions file rather than using the current directory only]' \ - '--pin[Save exact version to \`.tool-versions\`]' \ - '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ - '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ - '--path[Get the path of the config file]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_ls_cmd] )) || -__rtx_ls_cmd() { - _arguments -s -S \ - '::plugin:__rtx_plugins' \ - '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ - '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ - '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ - '(-J --json)'{-J,--json}'[Output in json format]' \ - '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ - '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_ls_remote_cmd] )) || -__rtx_ls_remote_cmd() { - _arguments -s -S \ - ':plugin:__rtx_plugins' \ - '::prefix:__rtx_prefixes' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_outdated_cmd] )) || -__rtx_outdated_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_plugins_cmd] )) || -__rtx_plugins_cmd() { - _arguments -s -S \ - '(-c --core)'{-c,--core}'[The built-in plugins only]' \ - '--user[List installed plugins]' \ - '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ - '--refs[show the git refs for each plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_plugins_cmds' \ - '*::arg:->args' && ret=0 + return ret + } +(($ + functions[__rtx_direnv_activate_cmd])) || + __rtx_direnv_activate_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_direnv_envrc_cmd])) || + __rtx_direnv_envrc_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_direnv_exec_cmd])) || + __rtx_direnv_exec_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_doctor_cmd])) || + __rtx_doctor_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_env_cmd])) || + __rtx_env_cmd() { + _arguments -s -S \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ + '*::tool:__rtx_tool_versions' \ + '(-J --json)'{-J,--json}'[Output in JSON format]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_env_vars_cmd])) || + __rtx_env_vars_cmd() { + _arguments -s -S \ + '--file=[The TOML file to update]:file:_files' \ + '*--remove=[Remove the environment variable from config file]:remove:' \ + '*::env_vars:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_exec_cmd])) || + __rtx_exec_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ + '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_global_cmd])) || + __rtx_global_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--pin[Save exact version to \`~/.tool-versions\`]' \ + '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ + '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ + '--path[Get the path of the global config file]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_hook_env_cmd])) || + __rtx_hook_env_cmd() { + _arguments -s -S \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ + '--status[Show "rtx\: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_implode_cmd])) || + __rtx_implode_cmd() { + _arguments -s -S \ + '--config[Also remove config directory]' \ + '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_install_cmd])) || + __rtx_install_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_latest_cmd])) || + __rtx_latest_cmd() { + _arguments -s -S \ + ':tool:__rtx_tool_versions' \ + '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_link_cmd])) || + __rtx_link_cmd() { + _arguments -s -S \ + ':tool:__rtx_tool_versions' \ + ':path:_directories' \ + '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_local_cmd])) || + __rtx_local_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-p --parent)'{-p,--parent}'[Recurse up to find a .tool-versions file rather than using the current directory only]' \ + '--pin[Save exact version to \`.tool-versions\`]' \ + '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ + '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ + '--path[Get the path of the config file]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_ls_cmd])) || + __rtx_ls_cmd() { + _arguments -s -S \ + '::plugin:__rtx_plugins' \ + '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ + '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ + '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ + '(-J --json)'{-J,--json}'[Output in json format]' \ + '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ + '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_ls_remote_cmd])) || + __rtx_ls_remote_cmd() { + _arguments -s -S \ + ':plugin:__rtx_plugins' \ + '::prefix:__rtx_prefixes' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_outdated_cmd])) || + __rtx_outdated_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_plugins_cmd])) || + __rtx_plugins_cmd() { + _arguments -s -S \ + '(-c --core)'{-c,--core}'[The built-in plugins only]' \ + '--user[List installed plugins]' \ + '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ + '--refs[show the git refs for each plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_plugins_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - (a|add|i|install) __rtx_plugins_install_cmd && ret=0 ;; - (l|link) __rtx_plugins_link_cmd && ret=0 ;; - (list|ls) __rtx_plugins_ls_cmd && ret=0 ;; - (list-all|list-remote|ls-remote) __rtx_plugins_ls_remote_cmd && ret=0 ;; - (remove|rm|uninstall) __rtx_plugins_uninstall_cmd && ret=0 ;; - (upgrade|update) __rtx_plugins_update_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + a | add | i | install) __rtx_plugins_install_cmd && ret=0 ;; + l | link) __rtx_plugins_link_cmd && ret=0 ;; + list | ls) __rtx_plugins_ls_cmd && ret=0 ;; + list-all | list-remote | ls-remote) __rtx_plugins_ls_remote_cmd && ret=0 ;; + remove | rm | uninstall) __rtx_plugins_uninstall_cmd && ret=0 ;; + upgrade | update) __rtx_plugins_update_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(( $+functions[__rtx_plugins_install_cmd] )) || -__rtx_plugins_install_cmd() { - _arguments -s -S \ - ':new_plugin:__rtx_all_plugins' \ - '::git_url:_urls' \ - '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ - '(-a --all)'{-a,--all}'[Install all missing plugins]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_plugins_link_cmd] )) || -__rtx_plugins_link_cmd() { - _arguments -s -S \ - ':name:' \ - '::path:_directories' \ - '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_plugins_ls_cmd] )) || -__rtx_plugins_ls_cmd() { - _arguments -s -S \ - '(-c --core)'{-c,--core}'[The built-in plugins only]' \ - '--user[List installed plugins]' \ - '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '--refs[Show the git refs for each plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_plugins_ls_remote_cmd] )) || -__rtx_plugins_ls_remote_cmd() { - _arguments -s -S \ - '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ - '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_plugins_uninstall_cmd] )) || -__rtx_plugins_uninstall_cmd() { - _arguments -s -S \ - '*::plugin:__rtx_plugins' \ - '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ - '(-a --all)'{-a,--all}'[Remove all plugins]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_plugins_update_cmd] )) || -__rtx_plugins_update_cmd() { - _arguments -s -S \ - '*::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_prune_cmd] )) || -__rtx_prune_cmd() { - _arguments -s -S \ - '*::plugin:__rtx_plugins' \ - '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_reshim_cmd] )) || -__rtx_reshim_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_self_update_cmd] )) || -__rtx_self_update_cmd() { - _arguments -s -S \ - '(-f --force)'{-f,--force}'[Update even if already up to date]' \ - '--no-plugins[Disable auto-updating plugins]' \ - '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ - '::version:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' -} -(( $+functions[__rtx_settings_cmd] )) || -__rtx_settings_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_settings_cmds' \ - '*::arg:->args' && ret=0 + return ret + } +(($ + functions[__rtx_plugins_install_cmd])) || + __rtx_plugins_install_cmd() { + _arguments -s -S \ + ':new_plugin:__rtx_all_plugins' \ + '::git_url:_urls' \ + '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ + '(-a --all)'{-a,--all}'[Install all missing plugins]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_plugins_link_cmd])) || + __rtx_plugins_link_cmd() { + _arguments -s -S \ + ':name:' \ + '::path:_directories' \ + '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_plugins_ls_cmd])) || + __rtx_plugins_ls_cmd() { + _arguments -s -S \ + '(-c --core)'{-c,--core}'[The built-in plugins only]' \ + '--user[List installed plugins]' \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ + '--refs[Show the git refs for each plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_plugins_ls_remote_cmd])) || + __rtx_plugins_ls_remote_cmd() { + _arguments -s -S \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ + '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_plugins_uninstall_cmd])) || + __rtx_plugins_uninstall_cmd() { + _arguments -s -S \ + '*::plugin:__rtx_plugins' \ + '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ + '(-a --all)'{-a,--all}'[Remove all plugins]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_plugins_update_cmd])) || + __rtx_plugins_update_cmd() { + _arguments -s -S \ + '*::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_prune_cmd])) || + __rtx_prune_cmd() { + _arguments -s -S \ + '*::plugin:__rtx_plugins' \ + '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_reshim_cmd])) || + __rtx_reshim_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_self_update_cmd])) || + __rtx_self_update_cmd() { + _arguments -s -S \ + '(-f --force)'{-f,--force}'[Update even if already up to date]' \ + '--no-plugins[Disable auto-updating plugins]' \ + '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ + '::version:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' + } +(($ + functions[__rtx_settings_cmd])) || + __rtx_settings_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_settings_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - (get) __rtx_settings_get_cmd && ret=0 ;; - (list|ls) __rtx_settings_ls_cmd && ret=0 ;; - (add|create|set) __rtx_settings_set_cmd && ret=0 ;; - (del|delete|remove|rm|unset) __rtx_settings_unset_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + get) __rtx_settings_get_cmd && ret=0 ;; + list | ls) __rtx_settings_ls_cmd && ret=0 ;; + add | create | set) __rtx_settings_set_cmd && ret=0 ;; + del | delete | remove | rm | unset) __rtx_settings_unset_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(( $+functions[__rtx_settings_get_cmd] )) || -__rtx_settings_get_cmd() { - _arguments -s -S \ - ':key:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_settings_ls_cmd] )) || -__rtx_settings_ls_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_settings_set_cmd] )) || -__rtx_settings_set_cmd() { - _arguments -s -S \ - ':key:' \ - ':value:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_settings_unset_cmd] )) || -__rtx_settings_unset_cmd() { - _arguments -s -S \ - ':key:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_shell_cmd] )) || -__rtx_shell_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_sync_cmd] )) || -__rtx_sync_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_sync_cmds' \ - '*::arg:->args' && ret=0 + return ret + } +(($ + functions[__rtx_settings_get_cmd])) || + __rtx_settings_get_cmd() { + _arguments -s -S \ + ':key:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_settings_ls_cmd])) || + __rtx_settings_ls_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_settings_set_cmd])) || + __rtx_settings_set_cmd() { + _arguments -s -S \ + ':key:' \ + ':value:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_settings_unset_cmd])) || + __rtx_settings_unset_cmd() { + _arguments -s -S \ + ':key:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_shell_cmd])) || + __rtx_shell_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_sync_cmd])) || + __rtx_sync_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_sync_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - (node) __rtx_sync_node_cmd && ret=0 ;; - (python) __rtx_sync_python_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + node) __rtx_sync_node_cmd && ret=0 ;; + python) __rtx_sync_python_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(( $+functions[__rtx_sync_node_cmd] )) || -__rtx_sync_node_cmd() { - _arguments -s -S \ - '--brew[Get tool versions from Homebrew]' \ - '--nvm[Get tool versions from nvm]' \ - '--nodenv[Get tool versions from nodenv]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_sync_python_cmd] )) || -__rtx_sync_python_cmd() { - _arguments -s -S \ - '--pyenv[Get tool versions from pyenv]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_trust_cmd] )) || -__rtx_trust_cmd() { - _arguments -s -S \ - '::config_file:_files' \ - '--untrust[No longer trust this config]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_uninstall_cmd] )) || -__rtx_uninstall_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-a --all)'{-a,--all}'[Delete all installed versions]' \ - '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_upgrade_cmd] )) || -__rtx_upgrade_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_use_cmd] )) || -__rtx_use_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '--pin[Save exact version to config file]' \ - '--fuzzy[Save fuzzy version to config file]' \ - '*--remove=[Remove the tool(s) from config file]:remove:' \ - '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ - '(-e --env)'{-e,--env}'=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:env:' \ - '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_version_cmd] )) || -__rtx_version_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_where_cmd] )) || -__rtx_where_cmd() { - _arguments -s -S \ - ':tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_which_cmd] )) || -__rtx_which_cmd() { - _arguments -s -S \ - ':bin_name:' \ - '--plugin[Show the plugin name instead of the path]' \ - '--version[Show the version instead of the path]' \ - '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' -} -(( $+functions[__rtx_cmds] )) || -__rtx_cmds() { - local commands; commands=( - 'activate:Initializes rtx in the current shell' - {a,alias}':Manage aliases' - 'bin-paths:List all the active runtime bin paths' - 'cache:Manage the rtx cache' - 'completion:Generate shell completions' - 'current:Shows current active and installed runtime versions' - 'deactivate:Disable rtx for current shell session' - 'direnv:Output direnv function to use rtx inside direnv' - 'doctor:Check rtx installation for possible problems.' - {e,env}':Exports env vars to activate rtx a single time' - 'env-vars:Manage environment variables' - {x,exec}':Execute a command with tool(s) set' - 'implode:Removes rtx CLI and all related data' - {i,install}':Install a tool version' - 'latest:Gets the latest available version for a plugin' - 'link:Symlinks a tool version into rtx' - {list,ls}':List installed and/or currently selected tool versions' - 'ls-remote:List runtime versions available for install' - 'outdated:Shows outdated tool versions' - {p,plugins}':Manage plugins' - 'prune:Delete unused versions of tools' - 'reshim:rebuilds the shim farm' - 'self-update:Updates rtx itself' - 'settings:Manage settings' - 'shell:Sets a tool version for the current shell session' - 'sync:Add tool versions from external tools to rtx' - 'trust:Marks a config file as trusted' - 'uninstall:Removes runtime versions' - 'upgrade:Upgrades outdated tool versions' - {u,use}':Change the active version of a tool locally or globally.' - 'version:Show rtx version' - 'where:Display the installation path for a runtime' - 'which:Shows the path that a bin name points to' - ) - _describe -t commands 'command' commands "$@" -} -(( $+functions[__rtx_alias_cmds] )) || -__rtx_alias_cmds() { - local commands; commands=( - 'get:Show an alias for a plugin' - {list,ls}':List aliases' - {add,create,set}':Add/update an alias for a plugin' - {del,delete,remove,rm,unset}':Clears an alias for a plugin' - ) - _describe -t commands 'command' commands "$@" -} -(( $+functions[__rtx_cache_cmds] )) || -__rtx_cache_cmds() { - local commands; commands=( - {c,clear}':Deletes all cache files in rtx' - ) - _describe -t commands 'command' commands "$@" -} -(( $+functions[__rtx_direnv_cmds] )) || -__rtx_direnv_cmds() { - local commands; commands=( - 'activate:Output direnv function to use rtx inside direnv' - ) - _describe -t commands 'command' commands "$@" -} -(( $+functions[__rtx_plugins_cmds] )) || -__rtx_plugins_cmds() { - local commands; commands=( - {a,i,install}':Install a plugin' - 'link:Symlinks a plugin into rtx' - {list,ls}':List installed plugins' - {list-remote,ls-remote}':List all available remote plugins' - 'uninstall:Removes a plugin' - 'update:Updates a plugin to the latest version' - ) - _describe -t commands 'command' commands "$@" -} -(( $+functions[__rtx_settings_cmds] )) || -__rtx_settings_cmds() { - local commands; commands=( - 'get:Show a current setting' - {list,ls}':Show current settings' - {add,create,set}':Add/update a setting' - {del,delete,remove,rm,unset}':Clears a setting' - ) - _describe -t commands 'command' commands "$@" -} -(( $+functions[__rtx_sync_cmds] )) || -__rtx_sync_cmds() { - local commands; commands=( - 'node:Symlinks all tool versions from an external tool into rtx' - 'python:Symlinks all tool versions from an external tool into rtx' - ) - _describe -t commands 'command' commands "$@" -} + return ret + } +(($ + functions[__rtx_sync_node_cmd])) || + __rtx_sync_node_cmd() { + _arguments -s -S \ + '--brew[Get tool versions from Homebrew]' \ + '--nvm[Get tool versions from nvm]' \ + '--nodenv[Get tool versions from nodenv]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_sync_python_cmd])) || + __rtx_sync_python_cmd() { + _arguments -s -S \ + '--pyenv[Get tool versions from pyenv]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_trust_cmd])) || + __rtx_trust_cmd() { + _arguments -s -S \ + '::config_file:_files' \ + '--untrust[No longer trust this config]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_uninstall_cmd])) || + __rtx_uninstall_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-a --all)'{-a,--all}'[Delete all installed versions]' \ + '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_upgrade_cmd])) || + __rtx_upgrade_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_use_cmd])) || + __rtx_use_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--pin[Save exact version to config file]' \ + '--fuzzy[Save fuzzy version to config file]' \ + '*--remove=[Remove the tool(s) from config file]:remove:' \ + '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ + '(-e --env)'{-e,--env}'=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:env:' \ + '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_version_cmd])) || + __rtx_version_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_where_cmd])) || + __rtx_where_cmd() { + _arguments -s -S \ + ':tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_which_cmd])) || + __rtx_which_cmd() { + _arguments -s -S \ + ':bin_name:' \ + '--plugin[Show the plugin name instead of the path]' \ + '--version[Show the version instead of the path]' \ + '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + } +(($ + functions[__rtx_cmds])) || + __rtx_cmds() { + local commands + commands=( + 'activate:Initializes rtx in the current shell' + {a,alias}':Manage aliases' + 'bin-paths:List all the active runtime bin paths' + 'cache:Manage the rtx cache' + 'completion:Generate shell completions' + 'current:Shows current active and installed runtime versions' + 'deactivate:Disable rtx for current shell session' + 'direnv:Output direnv function to use rtx inside direnv' + 'doctor:Check rtx installation for possible problems.' + {e,env}':Exports env vars to activate rtx a single time' + 'env-vars:Manage environment variables' + {x,exec}':Execute a command with tool(s) set' + 'implode:Removes rtx CLI and all related data' + {i,install}':Install a tool version' + 'latest:Gets the latest available version for a plugin' + 'link:Symlinks a tool version into rtx' + {list,ls}':List installed and/or currently selected tool versions' + 'ls-remote:List runtime versions available for install' + 'outdated:Shows outdated tool versions' + {p,plugins}':Manage plugins' + 'prune:Delete unused versions of tools' + 'reshim:rebuilds the shim farm' + 'self-update:Updates rtx itself' + 'settings:Manage settings' + 'shell:Sets a tool version for the current shell session' + 'sync:Add tool versions from external tools to rtx' + 'trust:Marks a config file as trusted' + 'uninstall:Removes runtime versions' + 'upgrade:Upgrades outdated tool versions' + {u,use}':Change the active version of a tool locally or globally.' + 'version:Show rtx version' + 'where:Display the installation path for a runtime' + 'which:Shows the path that a bin name points to' + ) + _describe -t commands 'command' commands "$@" + } +(($ + functions[__rtx_alias_cmds])) || + __rtx_alias_cmds() { + local commands + commands=( + 'get:Show an alias for a plugin' + {list,ls}':List aliases' + {add,create,set}':Add/update an alias for a plugin' + {del,delete,remove,rm,unset}':Clears an alias for a plugin' + ) + _describe -t commands 'command' commands "$@" + } +(($ + functions[__rtx_cache_cmds])) || + __rtx_cache_cmds() { + local commands + commands=( + {c,clear}':Deletes all cache files in rtx' + ) + _describe -t commands 'command' commands "$@" + } +(($ + functions[__rtx_direnv_cmds])) || + __rtx_direnv_cmds() { + local commands + commands=( + 'activate:Output direnv function to use rtx inside direnv' + ) + _describe -t commands 'command' commands "$@" + } +(($ + functions[__rtx_plugins_cmds])) || + __rtx_plugins_cmds() { + local commands + commands=( + {a,i,install}':Install a plugin' + 'link:Symlinks a plugin into rtx' + {list,ls}':List installed plugins' + {list-remote,ls-remote}':List all available remote plugins' + 'uninstall:Removes a plugin' + 'update:Updates a plugin to the latest version' + ) + _describe -t commands 'command' commands "$@" + } +(($ + functions[__rtx_settings_cmds])) || + __rtx_settings_cmds() { + local commands + commands=( + 'get:Show a current setting' + {list,ls}':Show current settings' + {add,create,set}':Add/update a setting' + {del,delete,remove,rm,unset}':Clears a setting' + ) + _describe -t commands 'command' commands "$@" + } +(($ + functions[__rtx_sync_cmds])) || + __rtx_sync_cmds() { + local commands + commands=( + 'node:Symlinks all tool versions from an external tool into rtx' + 'python:Symlinks all tool versions from an external tool into rtx' + ) + _describe -t commands 'command' commands "$@" + } -(( $+functions[__rtx_tool_versions] )) || -__rtx_tool_versions() { - if compset -P '*@'; then - local -a tool_versions; tool_versions=($(rtx ls-remote ${words[CURRENT]})) - _wanted tool_version expl 'version of tool' \ - compadd -a tool_versions - else - local -a plugins; plugins=($(rtx plugins --core --user)) - _wanted plugin expl 'plugin name' \ - compadd -S '@' -a plugins - fi -} -(( $+functions[__rtx_plugins] )) || -__rtx_plugins() { - local -a plugins; plugins=($(rtx plugins --core --user)) - _describe -t plugins 'plugin' plugins "$@" -} -(( $+functions[__rtx_all_plugins] )) || -__rtx_all_plugins() { - local -a all_plugins; all_plugins=($(rtx plugins --all)) - _describe -t all_plugins 'all_plugins' all_plugins "$@" -} -(( $+functions[__rtx_aliases] )) || -__rtx_aliases() { - local -a aliases; aliases=($(rtx aliases ls ${words[CURRENT-1]} | awk '{print $2}')) - _describe -t aliases 'alias' aliases "$@" -} -(( $+functions[__rtx_prefixes] )) || -__rtx_prefixes() { - local -a prefixes; prefixes=($(rtx ls-remote ${words[CURRENT-1]})) - _describe -t prefixes 'prefix' prefixes "$@" -} +(($ + functions[__rtx_tool_versions])) || + __rtx_tool_versions() { + if compset -P '*@'; then + local -a tool_versions + tool_versions=($(rtx ls-remote ${words[CURRENT]})) + _wanted tool_version expl 'version of tool' \ + compadd -a tool_versions + else + local -a plugins + plugins=($(rtx plugins --core --user)) + _wanted plugin expl 'plugin name' \ + compadd -S '@' -a plugins + fi + } +(($ + functions[__rtx_plugins])) || + __rtx_plugins() { + local -a plugins + plugins=($(rtx plugins --core --user)) + _describe -t plugins 'plugin' plugins "$@" + } +(($ + functions[__rtx_all_plugins])) || + __rtx_all_plugins() { + local -a all_plugins + all_plugins=($(rtx plugins --all)) + _describe -t all_plugins 'all_plugins' all_plugins "$@" + } +(($ + functions[__rtx_aliases])) || + __rtx_aliases() { + local -a aliases + aliases=($(rtx aliases ls ${words[CURRENT - 1]} | awk '{print $2}')) + _describe -t aliases 'alias' aliases "$@" + } +(($ + functions[__rtx_prefixes])) || + __rtx_prefixes() { + local -a prefixes + prefixes=($(rtx ls-remote ${words[CURRENT - 1]})) + _describe -t prefixes 'prefix' prefixes "$@" + } if [ "$funcstack[1]" = "_rtx" ]; then - _rtx "$@" + _rtx "$@" else - compdef _rtx rtx + compdef _rtx rtx fi # Local Variables: diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby index 29ddd6eff..a515b11fe 100755 --- a/e2e/ruby/test_ruby +++ b/e2e/ruby/test_ruby @@ -7,6 +7,7 @@ source "$(dirname "$0")/../assert.sh" export RTX_EXPERIMENTAL=1 export RTX_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" export RTX_RUBY_VERBOSE_INSTALL=1 +export RTX_RAW=1 cat >Gemfile < Self { - Self { cmd } - } - - fn render(&self) -> Result { - let command_funcs = self.render_command_funcs(&[&self.cmd]); - let command_descriptions = self.render_command_descriptions(&[&self.cmd]); - - Ok(formatdoc! {r#" - #compdef rtx - _rtx() {{ - typeset -A opt_args - local context state line curcontext=$curcontext - local ret=1 - - {args} - }} - {command_funcs} - {command_descriptions} - - (( $+functions[__rtx_tool_versions] )) || - __rtx_tool_versions() {{ - if compset -P '*@'; then - local -a tool_versions; tool_versions=($(rtx ls-remote ${{words[CURRENT]}})) - _wanted tool_version expl 'version of tool' \ - compadd -a tool_versions - else - local -a plugins; plugins=($(rtx plugins --core --user)) - _wanted plugin expl 'plugin name' \ - compadd -S '@' -a plugins - fi - }} - (( $+functions[__rtx_plugins] )) || - __rtx_plugins() {{ - local -a plugins; plugins=($(rtx plugins --core --user)) - _describe -t plugins 'plugin' plugins "$@" - }} - (( $+functions[__rtx_all_plugins] )) || - __rtx_all_plugins() {{ - local -a all_plugins; all_plugins=($(rtx plugins --all)) - _describe -t all_plugins 'all_plugins' all_plugins "$@" - }} - (( $+functions[__rtx_aliases] )) || - __rtx_aliases() {{ - local -a aliases; aliases=($(rtx aliases ls ${{words[CURRENT-1]}} | awk '{{print $2}}')) - _describe -t aliases 'alias' aliases "$@" - }} - (( $+functions[__rtx_prefixes] )) || - __rtx_prefixes() {{ - local -a prefixes; prefixes=($(rtx ls-remote ${{words[CURRENT-1]}})) - _describe -t prefixes 'prefix' prefixes "$@" - }} - - if [ "$funcstack[1]" = "_rtx" ]; then - _rtx "$@" - else - compdef _rtx rtx - fi - - # Local Variables: - # mode: Shell-Script - # sh-indentation: 2 - # indent-tabs-mode: nil - # sh-basic-offset: 2 - # End: - # vim: ft=zsh sw=2 ts=2 et - "#, args = self.render_args(&[&self.cmd])}) - } - - fn render_args(&self, cmds: &[&Command]) -> String { - let global_args = cmds - .iter() - .flat_map(|cmd| cmd.get_arguments()) - .filter(|arg| arg.is_global_set()); - let cmd = cmds.last().unwrap(); - let args = cmd - .get_arguments() - .chain(global_args) - .filter(|arg| !arg.is_hide_set() && !arg.is_last_set()) - .unique_by(|arg| arg.get_id()) - .map(|arg| self.render_arg(arg)) - .collect::>() - .join(" \\\n "); - if cmd.has_subcommands() { - let subcommands = self.render_subcommands(cmds); - let func = format!("__{}_cmds", func_name(cmds)); - formatdoc! {r#" - _arguments -s -S \ - {args} \ - '1: :{func}' \ - '*::arg:->args' && ret=0 - - {subcommands} - - return ret"# - } - } else { - formatdoc! {r#" - _arguments -s -S \ - {args}"# - } - } - } - - fn render_subcommands(&self, cmds: &[&Command]) -> String { - let cmd = cmds.last().unwrap(); - let cases = cmd - .get_subcommands() - .filter(|c| !banned(c)) - .sorted_by_cached_key(|c| c.get_name()) - .map(|cmd| { - let mut names = cmd.get_all_aliases().sorted().collect_vec(); - names.push(cmd.get_name()); - let names = names.join("|"); - let mut cmds = cmds.iter().copied().collect_vec(); - cmds.push(cmd); - let func = func_name(&cmds); - format!(" ({names}) __{func}_cmd && ret=0 ;;",) - }) - .collect::>() - .join("\n"); - formatdoc! {r#" - case "$state" in - (args) - curcontext="${{curcontext%:*:*}}:rtx-cmd-$words[1]:" - case $words[1] in - {cases} - esac - ;; - esac"# - } - } - - fn render_arg(&self, arg: &clap::Arg) -> String { - let help = match arg.get_help() { - Some(help) => format!("[{}]", help_escape(first_line(&help.to_string()))), - None => return String::new(), - }; - - let multiple = if let ArgAction::Count | ArgAction::Append = arg.get_action() { - "*" - } else { - "" - }; - let all = self.get_short_and_longs(arg); - let conflicts = if all.len() < 2 || multiple == "*" { - "".to_string() - } else { - format!("({})", all.join(" ")) - }; - let all = if all.len() < 2 { - all.join(" ") - } else { - format!("'{{{}}}'", all.join(",")) - }; - let name = arg.get_id(); - let completions = format!("{name}:{}", self.render_completion(arg)); - if arg.is_positional() { - if let ArgAction::Count | ArgAction::Append = arg.get_action() { - format!("'*::{completions}'") - } else if arg.is_required_set() || name == "new_plugin" { - format!("':{completions}'") - } else { - format!("'::{completions}'") - } - } else if arg.get_action().takes_values() { - format!("'{conflicts}{multiple}{all}={help}:{completions}'") - } else { - format!("'{conflicts}{multiple}{all}{help}'") - } - } - - fn get_short_and_longs(&self, arg: &Arg) -> Vec { - let short = arg - .get_short_and_visible_aliases() - .unwrap_or_default() - .into_iter() - .map(|s| format!("-{s}")) - .sorted(); - let long = arg - .get_long_and_visible_aliases() - .unwrap_or_default() - .into_iter() - .map(|s| format!("--{s}")) - .sorted(); - short.chain(long).collect() - } - - fn render_completion(&self, arg: &Arg) -> String { - let possible_values = arg.get_possible_values(); - if !possible_values.is_empty() { - return format!( - "({})", - possible_values - .iter() - .map(|v| escape_value(v.get_name())) - .collect::>() - .join(" ") - ); - }; - match arg.get_value_hint() { - ValueHint::DirPath => format!("_directories"), - ValueHint::FilePath => format!("_files"), - ValueHint::AnyPath => format!("_files"), - ValueHint::CommandName => format!("_command_names -e"), - ValueHint::CommandString => format!("_cmdstring"), - ValueHint::CommandWithArguments => format!("_cmdambivalent"), - ValueHint::ExecutablePath => format!("_absolute_command_paths"), - ValueHint::Username => format!("_users"), - ValueHint::Hostname => format!("_hosts"), - ValueHint::Url => format!("_urls"), - ValueHint::EmailAddress => format!("_email_addresses"), - ValueHint::Other => format!("( )"), - _ => match arg.get_id().as_str() { - "tool" => format!("__rtx_tool_versions"), - "plugin" => format!("__rtx_plugins"), - "new_plugin" => format!("__rtx_all_plugins"), - "alias" => format!("__rtx_aliases"), - "prefix" => format!("__rtx_prefixes"), - _ => format!(""), - }, - } - } - - fn render_command_funcs(&self, cmds: &[&Command]) -> String { - let cmd = cmds.last().unwrap(); - cmd.get_subcommands() - .filter(|c| !banned(c)) - .sorted_by_key(|c| c.get_name()) - .map(|cmd| { - let mut cmds = cmds.iter().copied().collect_vec(); - cmds.push(cmd); - let func = func_name(&cmds); - let args = self.render_args(&cmds); - let subcommand_funcs = self.render_command_funcs(&cmds); - (formatdoc! {r#" - (( $+functions[__{func}_cmd] )) || - __{func}_cmd() {{ - {args} - }} - {subcommand_funcs}"#, - }) - .trim() - .to_string() - }) - .collect::>() - .join("\n") - } - - fn render_command_descriptions(&self, cmds: &[&Command]) -> String { - let cmd = cmds.last().unwrap(); - let commands = cmd - .get_subcommands() - .filter(|c| !c.is_hide_set() && !banned(c)) - .sorted_by_key(|c| c.get_name()) - .map(|cmd| { - let name = cmd.get_name(); - let about = match cmd.get_about() { - Some(about) => help_escape(first_line(&about.to_string())).to_string(), - None => String::new(), - }; - let aliases = cmd.get_visible_aliases().sorted().collect_vec(); - if aliases.is_empty() { - format!(" '{}:{}'", name, about) - } else { - let aliases = aliases.join(","); - format!(" {{{aliases},{name}}}':{about}'") - } - }) - .collect::>() - .join("\n"); - let func = format!("__{}_cmds", func_name(cmds)); - let mut out = vec![formatdoc! {r#" - (( $+functions[{func}] )) || - {func}() {{ - local commands; commands=( - {commands} - ) - _describe -t commands 'command' commands "$@" - }}"#}]; - - for cmd in cmd - .get_subcommands() - .filter(|c| c.has_subcommands() && !banned(c)) - { - let mut cmds = cmds.iter().copied().collect_vec(); - cmds.push(cmd); - out.push(self.render_command_descriptions(&cmds)); - } - out.join("\n") - } -} - -fn func_name(cmds: &[&Command]) -> String { - cmds.iter() - .map(|c| c.get_name()) - .join("_") - .replace('-', "_") -} - -fn first_line(s: &str) -> &str { - s.lines().next().unwrap_or_default() -} - -fn help_escape(s: &str) -> String { - s.replace('\\', "\\\\") - .replace('\'', "'\\''") - .replace('[', "\\[") - .replace(']', "\\]") - .replace(':', "\\:") - .replace('$', "\\$") - .replace('`', "\\`") -} - -/// Escape value string inside single quotes and parentheses -fn escape_value(string: &str) -> String { - string - .replace('\\', "\\\\") - .replace('\'', "'\\''") - .replace('[', "\\[") - .replace(']', "\\]") - .replace(':', "\\:") - .replace('$', "\\$") - .replace('`', "\\`") - .replace('(', "\\(") - .replace(')', "\\)") - .replace(' ', "\\ ") -} - -static BANNED_COMMANDS: Lazy> = - Lazy::new(|| ["render-mangen", "render-help", "render-completion"].into()); - -fn banned(cmd: &Command) -> bool { - BANNED_COMMANDS.contains(&cmd.get_name()) -} - #[cfg(test)] mod tests { use crate::assert_cli; diff --git a/src/main.rs b/src/main.rs index 338c942da..503cfa763 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,10 +23,12 @@ mod output; #[macro_use] mod regex; +#[macro_use] +mod cmd; + pub mod build_time; mod cache; mod cli; -mod cmd; mod config; mod default_shorthands; mod direnv; diff --git a/src/shell/completions/mod.rs b/src/shell/completions/mod.rs new file mode 100644 index 000000000..e552c0a80 --- /dev/null +++ b/src/shell/completions/mod.rs @@ -0,0 +1,9 @@ +use clap::Command; + +mod zsh_complete; + +pub fn zsh_complete(cmd: &Command) -> eyre::Result { + let output = zsh_complete::render(cmd); + let result = cmd!("shfmt", "-s").stdin_bytes(output.trim()).read()?; + Ok(result) +} diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs new file mode 100644 index 000000000..413561f0d --- /dev/null +++ b/src/shell/completions/zsh_complete.rs @@ -0,0 +1,337 @@ +use clap::{Arg, ArgAction, Command, ValueHint}; +use itertools::Itertools; +use once_cell::sync::Lazy; +use std::collections::HashSet; + +pub fn render(cmd: &Command) -> String { + let cmds = vec![cmd]; + let command_funcs = render_command_funcs(&cmds); + let command_descriptions = render_command_descriptions(&cmds); + let args = render_args(&cmds); + + formatdoc! {r#" + #compdef rtx + _rtx() {{ + typeset -A opt_args + local context state line curcontext=$curcontext + local ret=1 + + {args} + }} + {command_funcs} + {command_descriptions} + + (( $+functions[__rtx_tool_versions] )) || + __rtx_tool_versions() {{ + if compset -P '*@'; then + local -a tool_versions; tool_versions=($(rtx ls-remote ${{words[CURRENT]}})) + _wanted tool_version expl 'version of tool' \ + compadd -a tool_versions + else + local -a plugins; plugins=($(rtx plugins --core --user)) + _wanted plugin expl 'plugin name' \ + compadd -S '@' -a plugins + fi + }} + (( $+functions[__rtx_plugins] )) || + __rtx_plugins() {{ + local -a plugins; plugins=($(rtx plugins --core --user)) + _describe -t plugins 'plugin' plugins "$@" + }} + (( $+functions[__rtx_all_plugins] )) || + __rtx_all_plugins() {{ + local -a all_plugins; all_plugins=($(rtx plugins --all)) + _describe -t all_plugins 'all_plugins' all_plugins "$@" + }} + (( $+functions[__rtx_aliases] )) || + __rtx_aliases() {{ + local -a aliases; aliases=($(rtx aliases ls ${{words[CURRENT-1]}} | awk '{{print $2}}')) + _describe -t aliases 'alias' aliases "$@" + }} + (( $+functions[__rtx_prefixes] )) || + __rtx_prefixes() {{ + local -a prefixes; prefixes=($(rtx ls-remote ${{words[CURRENT-1]}})) + _describe -t prefixes 'prefix' prefixes "$@" + }} + + if [ "$funcstack[1]" = "_rtx" ]; then + _rtx "$@" + else + compdef _rtx rtx + fi + + # Local Variables: + # mode: Shell-Script + # sh-indentation: 2 + # indent-tabs-mode: nil + # sh-basic-offset: 2 + # End: + # vim: ft=zsh sw=2 ts=2 et + "#} +} + +fn render_args(cmds: &[&Command]) -> String { + let global_args = cmds + .iter() + .flat_map(|cmd| cmd.get_arguments()) + .filter(|arg| arg.is_global_set()); + let cmd = cmds.last().unwrap(); + let args = cmd + .get_arguments() + .chain(global_args) + .filter(|arg| !arg.is_hide_set() && !arg.is_last_set()) + .unique_by(|arg| arg.get_id()) + .map(render_arg) + .collect::>() + .join(" \\\n "); + if cmd.has_subcommands() { + let subcommands = render_subcommands(cmds); + let func = format!("__{}_cmds", func_name(cmds)); + formatdoc! {r#" + _arguments -s -S \ + {args} \ + '1: :{func}' \ + '*::arg:->args' && ret=0 + + {subcommands} + + return ret"# + } + } else { + formatdoc! {r#" + _arguments -s -S \ + {args}"# + } + } +} + +fn render_subcommands(cmds: &[&Command]) -> String { + let cmd = cmds.last().unwrap(); + let cases = cmd + .get_subcommands() + .filter(|c| !banned(c)) + .sorted_by_cached_key(|c| c.get_name()) + .map(|cmd| { + let mut names = cmd.get_all_aliases().sorted().collect_vec(); + names.push(cmd.get_name()); + let names = names.join("|"); + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + let func = func_name(&cmds); + format!(" ({names}) __{func}_cmd && ret=0 ;;",) + }) + .collect::>() + .join("\n"); + formatdoc! {r#" + case "$state" in + (args) + curcontext="${{curcontext%:*:*}}:rtx-cmd-$words[1]:" + case $words[1] in + {cases} + esac + ;; + esac"# + } +} + +fn render_arg(arg: &Arg) -> String { + let help = match arg.get_help() { + Some(help) => format!("[{}]", help_escape(first_line(&help.to_string()))), + None => return String::new(), + }; + + let multiple = if let ArgAction::Count | ArgAction::Append = arg.get_action() { + "*" + } else { + "" + }; + let all = get_short_and_longs(arg); + let conflicts = if all.len() < 2 || multiple == "*" { + "".to_string() + } else { + format!("({})", all.join(" ")) + }; + let all = if all.len() < 2 { + all.join(" ") + } else { + format!("'{{{}}}'", all.join(",")) + }; + let name = arg.get_id(); + let completions = format!("{name}:{}", render_completion(arg)); + if arg.is_positional() { + if let ArgAction::Count | ArgAction::Append = arg.get_action() { + format!("'*::{completions}'") + } else if arg.is_required_set() || name == "new_plugin" { + format!("':{completions}'") + } else { + format!("'::{completions}'") + } + } else if arg.get_action().takes_values() { + format!("'{conflicts}{multiple}{all}={help}:{completions}'") + } else { + format!("'{conflicts}{multiple}{all}{help}'") + } +} + +fn get_short_and_longs(arg: &Arg) -> Vec { + let short = arg + .get_short_and_visible_aliases() + .unwrap_or_default() + .into_iter() + .map(|s| format!("-{s}")) + .sorted(); + let long = arg + .get_long_and_visible_aliases() + .unwrap_or_default() + .into_iter() + .map(|s| format!("--{s}")) + .sorted(); + short.chain(long).collect() +} + +fn render_completion(arg: &Arg) -> String { + let possible_values = arg.get_possible_values(); + if !possible_values.is_empty() { + return format!( + "({})", + possible_values + .iter() + .map(|v| escape_value(v.get_name())) + .collect::>() + .join(" ") + ); + }; + match arg.get_value_hint() { + ValueHint::DirPath => "_directories".to_string(), + ValueHint::FilePath => "_files".to_string(), + ValueHint::AnyPath => "_files".to_string(), + ValueHint::CommandName => "_command_names -e".to_string(), + ValueHint::CommandString => "_cmdstring".to_string(), + ValueHint::CommandWithArguments => "_cmdambivalent".to_string(), + ValueHint::ExecutablePath => "_absolute_command_paths".to_string(), + ValueHint::Username => "_users".to_string(), + ValueHint::Hostname => "_hosts".to_string(), + ValueHint::Url => "_urls".to_string(), + ValueHint::EmailAddress => "_email_addresses".to_string(), + ValueHint::Other => "( )".to_string(), + _ => match arg.get_id().as_str() { + "tool" => "__rtx_tool_versions".to_string(), + "plugin" => "__rtx_plugins".to_string(), + "new_plugin" => "__rtx_all_plugins".to_string(), + "alias" => "__rtx_aliases".to_string(), + "prefix" => "__rtx_prefixes".to_string(), + _ => String::new(), + }, + } +} + +fn render_command_funcs(cmds: &[&Command]) -> String { + let cmd = cmds.last().unwrap(); + cmd.get_subcommands() + .filter(|c| !banned(c)) + .sorted_by_key(|c| c.get_name()) + .map(|cmd| { + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + let func = func_name(&cmds); + let args = render_args(&cmds); + let subcommand_funcs = render_command_funcs(&cmds); + formatdoc! {r#" + (( $+functions[__{func}_cmd] )) || + __{func}_cmd() {{ + {args} + }} + {subcommand_funcs}"#, + } + .trim() + .to_string() + }) + .collect::>() + .join("\n") +} + +fn render_command_descriptions(cmds: &[&Command]) -> String { + let cmd = cmds.last().unwrap(); + let commands = cmd + .get_subcommands() + .filter(|c| !c.is_hide_set() && !banned(c)) + .sorted_by_key(|c| c.get_name()) + .map(|cmd| { + let name = cmd.get_name(); + let about = match cmd.get_about() { + Some(about) => help_escape(first_line(&about.to_string())).to_string(), + None => String::new(), + }; + let aliases = cmd.get_visible_aliases().sorted().collect_vec(); + if aliases.is_empty() { + format!(" '{}:{}'", name, about) + } else { + let aliases = aliases.join(","); + format!(" {{{aliases},{name}}}':{about}'") + } + }) + .collect::>() + .join("\n"); + let func = format!("__{}_cmds", func_name(cmds)); + let mut out = vec![formatdoc! {r#" + (( $+functions[{func}] )) || + {func}() {{ + local commands; commands=( + {commands} + ) + _describe -t commands 'command' commands "$@" + }}"#}]; + + for cmd in cmd + .get_subcommands() + .filter(|c| c.has_subcommands() && !banned(c)) + { + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + out.push(render_command_descriptions(&cmds)); + } + out.join("\n") +} + +fn func_name(cmds: &[&Command]) -> String { + cmds.iter() + .map(|c| c.get_name()) + .join("_") + .replace('-', "_") +} + +fn first_line(s: &str) -> &str { + s.lines().next().unwrap_or_default() +} + +fn help_escape(s: &str) -> String { + s.replace('\\', "\\\\") + .replace('\'', "'\\''") + .replace('[', "\\[") + .replace(']', "\\]") + .replace(':', "\\:") + .replace('$', "\\$") + .replace('`', "\\`") +} + +/// Escape value string inside single quotes and parentheses +fn escape_value(string: &str) -> String { + string + .replace('\\', "\\\\") + .replace('\'', "'\\''") + .replace('[', "\\[") + .replace(']', "\\]") + .replace(':', "\\:") + .replace('$', "\\$") + .replace('`', "\\`") + .replace('(', "\\(") + .replace(')', "\\)") + .replace(' ', "\\ ") +} + +static BANNED_COMMANDS: Lazy> = + Lazy::new(|| ["render-mangen", "render-help", "render-completion"].into()); + +fn banned(cmd: &Command) -> bool { + BANNED_COMMANDS.contains(&cmd.get_name()) +} diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 861a639c3..a561ad631 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -9,6 +9,9 @@ mod nushell; mod xonsh; mod zsh; +#[cfg(feature = "clap_complete")] +pub mod completions; + #[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)] pub enum ShellType { Bash, From 41ae216ecb59b7b00e1640285a5e98cf05a7736d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:51:07 -0600 Subject: [PATCH 1180/1891] completions: small tweaks --- completions/rtx.bash | 1 - completions/rtx.fish | 1 - lefthook.yml | 20 +++++++++++++++++--- src/cli/render_completion.rs | 16 +++++++++------- src/shell/completions/mod.rs | 2 +- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/completions/rtx.bash b/completions/rtx.bash index 7227365de..67ad72fa4 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3584,4 +3584,3 @@ _rtx() { } complete -F _rtx -o nosort -o bashdefault -o default rtx - diff --git a/completions/rtx.fish b/completions/rtx.fish index 09c484423..40e4f6ec2 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -865,4 +865,3 @@ complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "unset" -d 'Clears a setting' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' - diff --git a/lefthook.yml b/lefthook.yml index 4a6ea8bad..c998f357d 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -1,8 +1,22 @@ pre-commit: - follow: true + parallel: true commands: - pre-commit: - run: just -v pre-commit + cargo_fmt: + run: cargo fmt --all -- --check + glob: "src/**/*.rs" + clippy: + run: cargo clippy -- -Dwarnings + glob: "src/**/*.rs" + render: + run: just render-help render-completions render-mangen + glob: "src/**/*.rs" + shellcheck: + run: shellcheck -x {all_files} && shfmt -d {all_files} + glob: "{scripts/*.sh,e2e/test_*,e2e/run_*}" + just_fmt: + run: just --unstable --fmt --check + glob: "justfile" + skip_output: - meta - summary diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 5bff1f354..52804b164 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -26,15 +26,17 @@ impl RenderCompletion { pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { let shell = self.shell.or(self.shell_type).unwrap(); - let mut c = Cursor::new(Vec::new()); let mut cmd = crate::cli::Cli::command().subcommand(SelfUpdate::command()); - if let clap_complete::Shell::Zsh = shell { - rtxprintln!(out, "{}", zsh_complete(&cmd)?); - } else { - generate(shell, &mut cmd, "rtx", &mut c); - rtxprintln!(out, "{}", String::from_utf8(c.into_inner()).unwrap()); - } + let script = match shell { + clap_complete::Shell::Zsh => zsh_complete(&cmd)?, + _ => { + let mut c = Cursor::new(Vec::new()); + generate(shell, &mut cmd, "rtx", &mut c); + String::from_utf8(c.into_inner()).unwrap() + } + }; + rtxprintln!(out, "{}", script.trim()); Ok(()) } diff --git a/src/shell/completions/mod.rs b/src/shell/completions/mod.rs index e552c0a80..e9c056221 100644 --- a/src/shell/completions/mod.rs +++ b/src/shell/completions/mod.rs @@ -4,6 +4,6 @@ mod zsh_complete; pub fn zsh_complete(cmd: &Command) -> eyre::Result { let output = zsh_complete::render(cmd); - let result = cmd!("shfmt", "-s").stdin_bytes(output.trim()).read()?; + let result = cmd!("shfmt", "-s").stdin_bytes(output).read()?; Ok(result) } From 8aa02f1e279c2d26b0b82804423b0d74ea5f3f99 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:06:22 -0600 Subject: [PATCH 1181/1891] completions: new fish completer (#1084) --- completions/_rtx | 8 +- completions/rtx.fish | 1174 +++++++----------------- src/cli/render_completion.rs | 5 +- src/shell/completions/fish_complete.rs | 183 ++++ src/shell/completions/mod.rs | 17 + src/shell/completions/zsh_complete.rs | 26 +- 6 files changed, 517 insertions(+), 896 deletions(-) create mode 100644 src/shell/completions/fish_complete.rs diff --git a/completions/_rtx b/completions/_rtx index c28f5e641..121f20f22 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -920,10 +920,4 @@ else compdef _rtx rtx fi -# Local Variables: -# mode: Shell-Script -# sh-indentation: 2 -# indent-tabs-mode: nil -# sh-basic-offset: 2 -# End: -# vim: ft=zsh sw=2 ts=2 et +# vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/completions/rtx.fish b/completions/rtx.fish index 40e4f6ec2..de42177be 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,867 +1,307 @@ -complete -c rtx -n "__fish_use_subcommand" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_use_subcommand" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_use_subcommand" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_use_subcommand" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_use_subcommand" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_use_subcommand" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_use_subcommand" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_use_subcommand" -s V -l version -d 'Print version' -complete -c rtx -n "__fish_use_subcommand" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_use_subcommand" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_use_subcommand" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_use_subcommand" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_use_subcommand" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_use_subcommand" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_use_subcommand" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_use_subcommand" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_use_subcommand" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_use_subcommand" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_use_subcommand" -f -a "env-vars" -d 'Manage environment variables' -complete -c rtx -n "__fish_use_subcommand" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_use_subcommand" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_use_subcommand" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_use_subcommand" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_use_subcommand" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_use_subcommand" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_use_subcommand" -f -a "link" -d 'Symlinks a tool version into rtx' -complete -c rtx -n "__fish_use_subcommand" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_use_subcommand" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_use_subcommand" -f -a "outdated" -d 'Shows outdated tool versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_use_subcommand" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_use_subcommand" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_use_subcommand" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_use_subcommand" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_use_subcommand" -f -a "sync" -d 'Add tool versions from external tools to rtx' -complete -c rtx -n "__fish_use_subcommand" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_use_subcommand" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "upgrade" -d 'Upgrades outdated tool versions' -complete -c rtx -n "__fish_use_subcommand" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_use_subcommand" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_use_subcommand" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_use_subcommand" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_use_subcommand" -f -a "render-completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_use_subcommand" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_use_subcommand" -f -a "render-mangen" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_use_subcommand" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s s -l shell -d 'Shell type to generate the script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" -complete -c rtx -n "__fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from activate" -l status -d 'Show "rtx: @" message when changing directories' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s q -l quiet -d 'noop' -complete -c rtx -n "__fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s p -l plugin -d 'filter aliases by plugin' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`.' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`.' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from alias; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from asdf" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from asdf" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from asdf" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from bin-paths" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' -complete -c rtx -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from clear" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "clear" -d 'Deletes all cache files in rtx' -complete -c rtx -n "__fish_seen_subcommand_from cache; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from clear; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash '',fish '',zsh ''}" -complete -c rtx -n "__fish_seen_subcommand_from completion" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from completion" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from completion" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from completion" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from completion" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from current" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from current" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from current" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from current" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from current" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from current" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from current" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from current" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from deactivate" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file -for direnv to consume.' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file -for direnv to consume.' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from envrc" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from exec" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from activate" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file -for direnv to consume.' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file -for direnv to consume.' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from direnv; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from doctor" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from doctor" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from doctor" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from env" -s s -l shell -d 'Shell type to generate environment variables for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" -complete -c rtx -n "__fish_seen_subcommand_from env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from env" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from env" -s J -l json -d 'Output in JSON format' -complete -c rtx -n "__fish_seen_subcommand_from env" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from env" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from env" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from env" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from env" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l file -d 'The TOML file to update' -r -F -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l remove -d 'Remove the environment variable from config file' -r -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from env-vars" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from exec" -s c -l command -d 'Command string to execute' -r -f -a "(__fish_complete_command)" -complete -c rtx -n "__fish_seen_subcommand_from exec" -s C -l cd -d 'Change to this directory before executing the command' -r -f -a "(__fish_complete_directories)" -complete -c rtx -n "__fish_seen_subcommand_from exec" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from exec" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from exec" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from exec" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from exec" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from exec" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from exec" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from exec" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from global" -l remove -d 'Remove the plugin(s) from ~/.tool-versions' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from global" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from global" -l pin -d 'Save exact version to `~/.tool-versions` -e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions' -complete -c rtx -n "__fish_seen_subcommand_from global" -l fuzzy -d 'Save fuzzy version to `~/.tool-versions` -e.g.: `rtx global --fuzzy node@20` will save `node 20` to ~/.tool-versions -this is the default behavior unless RTX_ASDF_COMPAT=1' -complete -c rtx -n "__fish_seen_subcommand_from global" -l path -d 'Get the path of the global config file' -complete -c rtx -n "__fish_seen_subcommand_from global" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from global" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from global" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from global" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from global" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from global" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s s -l shell -d 'Shell type to generate script for' -r -f -a "{bash '',fish '',nu '',xonsh '',zsh ''}" -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l status -d 'Show "rtx: @" message when changing directories' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from hook-env" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from implode" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from implode" -l config -d 'Also remove config directory' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s n -l dry-run -d 'List directories that would be removed without actually removing them' -complete -c rtx -n "__fish_seen_subcommand_from implode" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from implode" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from implode" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from install" -s f -l force -d 'Force reinstall even if already installed' -complete -c rtx -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from latest" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from latest" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from latest" -s i -l installed -d 'Show latest installed instead of available version' -complete -c rtx -n "__fish_seen_subcommand_from latest" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from latest" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from latest" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from latest" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from latest" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from latest" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from link" -s f -l force -d 'Overwrite an existing tool version if it exists' -complete -c rtx -n "__fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from local" -l remove -d 'Remove the plugin(s) from .tool-versions' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from local" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from local" -s p -l parent -d 'Recurse up to find a .tool-versions file rather than using the current directory only -by default this command will only set the tool in the current directory ("$PWD/.tool-versions")' -complete -c rtx -n "__fish_seen_subcommand_from local" -l pin -d 'Save exact version to `.tool-versions` -e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions' -complete -c rtx -n "__fish_seen_subcommand_from local" -l fuzzy -d 'Save fuzzy version to `.tool-versions` e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1' -complete -c rtx -n "__fish_seen_subcommand_from local" -l path -d 'Get the path of the config file' -complete -c rtx -n "__fish_seen_subcommand_from local" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from local" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from local" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from local" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from local" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from local" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s p -l plugin -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -l prefix -d 'Display versions matching this prefix' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' -complete -c rtx -n "__fish_seen_subcommand_from ls" -l parseable -d 'Output in an easily parseable format' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s J -l json -d 'Output in json format' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s m -l missing -d 'Display missing tool versions' -complete -c rtx -n "__fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from outdated" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from outdated" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from outdated" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s a -l all -d 'list all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s c -l core -d 'The built-in plugins only -Normally these are not shown' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l user -d 'List installed plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s u -l urls -d 'show the git url for each plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l refs -d 'show the git refs for each plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a plugin into rtx' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s f -l force -d 'Reinstall even if plugin exists' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s a -l all -d 'Install all missing plugins -This will only install plugins that have matching shorthands. -i.e.: they don\'t need the full git repo url' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from install" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s f -l force -d 'Overwrite existing plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from link" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s a -l all -d 'List all available remote plugins -Same as `rtx plugins ls-remote`' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s c -l core -d 'The built-in plugins only -Normally these are not shown' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l user -d 'List installed plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s u -l urls -d 'Show the git url for each plugin -e.g.: https://github.com/asdf-vm/asdf-node.git' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l refs -d 'Show the git refs for each plugin -e.g.: main 1234abc' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from ls-remote" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s p -l purge -d 'Also remove the plugin\'s installs, downloads, and cache' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s a -l all -d 'Remove all plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s a -l all -d 'Update all plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from update" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a plugin into rtx' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes a plugin' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "update" -d 'Updates a plugin to the latest version' -complete -c rtx -n "__fish_seen_subcommand_from plugins; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from prune" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from prune" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from prune" -s n -l dry-run -d 'Do not actually delete anything' -complete -c rtx -n "__fish_seen_subcommand_from prune" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from prune" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from prune" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from prune" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from prune" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from prune" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from reshim" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from reshim" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from reshim" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' -complete -c rtx -n "__fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from ls" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "get" -d 'Show a current setting' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'Show current settings' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "set" -d 'Add/update a setting' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "unset" -d 'Clears a setting' -complete -c rtx -n "__fish_seen_subcommand_from settings; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from shell" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from shell" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from shell" -s u -l unset -d 'Removes a previously set version' -complete -c rtx -n "__fish_seen_subcommand_from shell" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from shell" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from shell" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from shell" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from shell" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from shell" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' -complete -c rtx -n "__fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l brew -d 'Get tool versions from Homebrew' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nvm -d 'Get tool versions from nvm' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l nodenv -d 'Get tool versions from nodenv' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from node" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l pyenv -d 'Get tool versions from pyenv' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from python" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' -complete -c rtx -n "__fish_seen_subcommand_from sync; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from trust" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from trust" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from trust" -l untrust -d 'No longer trust this config' -complete -c rtx -n "__fish_seen_subcommand_from trust" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from trust" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from trust" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from trust" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from trust" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from trust" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s a -l all -d 'Delete all installed versions' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s n -l dry-run -d 'Do not actually delete anything' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from uninstall" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from upgrade" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from use" -l remove -d 'Remove the tool(s) from config file' -r -complete -c rtx -n "__fish_seen_subcommand_from use" -s e -l env -d '[experimental] Modify an environment-specific config file like .rtx..toml' -r -complete -c rtx -n "__fish_seen_subcommand_from use" -s p -l path -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' -r -F -complete -c rtx -n "__fish_seen_subcommand_from use" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from use" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from use" -l pin -d 'Save exact version to config file -e.g.: `rtx use --pin node@20` will save 20.0.0 as the version' -complete -c rtx -n "__fish_seen_subcommand_from use" -l fuzzy -d 'Save fuzzy version to config file -e.g.: `rtx use --fuzzy node@20` will save 20 as the version -this is the default behavior unless RTX_ASDF_COMPAT=1' -complete -c rtx -n "__fish_seen_subcommand_from use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' -complete -c rtx -n "__fish_seen_subcommand_from use" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from use" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from use" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from use" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from use" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from use" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from version" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from version" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from version" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from version" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from version" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from version" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from version" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from version" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from where" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from where" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from where" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from where" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from where" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from where" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from where" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from where" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from which" -s t -l tool -d 'Use a specific tool@version -e.g.: `rtx which npm --tool=node@20`' -r -complete -c rtx -n "__fish_seen_subcommand_from which" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from which" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from which" -l plugin -d 'Show the plugin name instead of the path' -complete -c rtx -n "__fish_seen_subcommand_from which" -l version -d 'Show the version instead of the path' -complete -c rtx -n "__fish_seen_subcommand_from which" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from which" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from which" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from which" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from which" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from which" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s s -l shell -d 'Shell type to generate completions for' -r -f -a "{bash '',elvish '',fish '',powershell '',zsh ''}" -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from render-completion" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from render-help" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from render-help" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from render-help" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s y -l yes -d 'Answer yes to all prompts' -complete -c rtx -n "__fish_seen_subcommand_from render-mangen" -s h -l help -d 'Print help' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s j -l jobs -d 'Number of plugins and runtimes to install in parallel -[default: 4]' -r -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l log-level -d 'Set the log output verbosity' -r -f -a "{error '',warn '',info '',debug '',trace ''}" -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s f -l force -d 'Update even if already up to date' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l no-plugins -d 'Disable auto-updating plugins' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s y -l yes -d 'Skip confirmation prompt' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l debug -d 'Sets log level to debug' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -l trace -d 'Sets log level to trace' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user. -Sets --jobs=1' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s v -l verbose -d 'Show installation output' -complete -c rtx -n "__fish_seen_subcommand_from self-update" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "activate" -d 'Initializes rtx in the current shell' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "alias" -d 'Manage aliases' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "asdf" -d '[internal] simulates asdf for plugins that call "asdf" internally' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "bin-paths" -d 'List all the active runtime bin paths' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "cache" -d 'Manage the rtx cache' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "current" -d 'Shows current active and installed runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "deactivate" -d 'Disable rtx for current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "direnv" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "doctor" -d 'Check rtx installation for possible problems.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env" -d 'Exports env vars to activate rtx a single time' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "env-vars" -d 'Manage environment variables' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "exec" -d 'Execute a command with tool(s) set' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "global" -d 'Sets/gets the global tool version(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "hook-env" -d '[internal] called by activate hook to update env vars directory change' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "implode" -d 'Removes rtx CLI and all related data' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "install" -d 'Install a tool version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "latest" -d 'Gets the latest available version for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "link" -d 'Symlinks a tool version into rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "local" -d 'Sets/gets tool version in local .tool-versions or .rtx.toml' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls" -d 'List installed and/or currently selected tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "ls-remote" -d 'List runtime versions available for install' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "outdated" -d 'Shows outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "plugins" -d 'Manage plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "prune" -d 'Delete unused versions of tools' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "reshim" -d 'rebuilds the shim farm' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "settings" -d 'Manage settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "shell" -d 'Sets a tool version for the current shell session' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "sync" -d 'Add tool versions from external tools to rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "trust" -d 'Marks a config file as trusted' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "uninstall" -d 'Removes runtime versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "upgrade" -d 'Upgrades outdated tool versions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "use" -d 'Change the active version of a tool locally or globally.' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "version" -d 'Show rtx version' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "where" -d 'Display the installation path for a runtime' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "which" -d 'Shows the path that a bin name points to' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-completion" -d 'Generate shell completions' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-help" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "render-mangen" -d 'internal command to generate markdown from help' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "self-update" -d 'Updates rtx itself' -complete -c rtx -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from activate; and not __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from asdf; and not __fish_seen_subcommand_from bin-paths; and not __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from current; and not __fish_seen_subcommand_from deactivate; and not __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from doctor; and not __fish_seen_subcommand_from env; and not __fish_seen_subcommand_from env-vars; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from global; and not __fish_seen_subcommand_from hook-env; and not __fish_seen_subcommand_from implode; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from latest; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from local; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from outdated; and not __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from prune; and not __fish_seen_subcommand_from reshim; and not __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from shell; and not __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from trust; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from upgrade; and not __fish_seen_subcommand_from use; and not __fish_seen_subcommand_from version; and not __fish_seen_subcommand_from where; and not __fish_seen_subcommand_from which; and not __fish_seen_subcommand_from render-completion; and not __fish_seen_subcommand_from render-help; and not __fish_seen_subcommand_from render-mangen; and not __fish_seen_subcommand_from self-update; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`.' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "set" -d 'Add/update an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from alias; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "unset" -d 'Clears an alias for a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from clear" -f -a "clear" -d 'Deletes all cache files in rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "envrc" -d '[internal] This is an internal command that writes an envrc file -for direnv to consume.' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "exec" -d '[internal] This is an internal command that writes an envrc file -for direnv to consume.' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from direnv; and not __fish_seen_subcommand_from envrc; and not __fish_seen_subcommand_from exec; and not __fish_seen_subcommand_from activate" -f -a "activate" -d 'Output direnv function to use rtx inside direnv' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "install" -d 'Install a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "link" -d 'Symlinks a plugin into rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "ls" -d 'List installed plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "ls-remote" -d 'List all available remote plugins' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "uninstall" -d 'Removes a plugin' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from plugins; and not __fish_seen_subcommand_from install; and not __fish_seen_subcommand_from link; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from ls-remote; and not __fish_seen_subcommand_from uninstall; and not __fish_seen_subcommand_from update" -f -a "update" -d 'Updates a plugin to the latest version' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "get" -d 'Show a current setting' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "ls" -d 'Show current settings' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "set" -d 'Add/update a setting' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from settings; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from ls; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from unset" -f -a "unset" -d 'Clears a setting' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python" -f -a "node" -d 'Symlinks all tool versions from an external tool into rtx' -complete -c rtx -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from sync; and not __fish_seen_subcommand_from node; and not __fish_seen_subcommand_from python" -f -a "python" -d 'Symlinks all tool versions from an external tool into rtx' +set -l fssf "__fish_seen_subcommand_from" + +# rtx +complete -xc rtx -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' +complete -xc rtx -l log-level -a "error warn info debug trace" -d 'Set the log output verbosity' +complete -xc rtx -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user.' +complete -xc rtx -s v -l verbose -d 'Show installation output' +complete -xc rtx -s y -l yes -d 'Answer yes to all prompts' +set -l others activate alias bin-paths cache completion current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which +complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell' +complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' +complete -xc rtx -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' +complete -xc rtx -n "not $fssf $others" -a cache -d 'Manage the rtx cache' +complete -xc rtx -n "not $fssf $others" -a completion -d 'Generate shell completions' +complete -xc rtx -n "not $fssf $others" -a current -d 'Shows current active and installed runtime versions' +complete -xc rtx -n "not $fssf $others" -a deactivate -d 'Disable rtx for current shell session' +complete -xc rtx -n "not $fssf $others" -a direnv -d 'Output direnv function to use rtx inside direnv' +complete -xc rtx -n "not $fssf $others" -a doctor -d 'Check rtx installation for possible problems.' +complete -xc rtx -n "not $fssf $others" -a env -d 'Exports env vars to activate rtx a single time' +complete -xc rtx -n "not $fssf $others" -a env-vars -d 'Manage environment variables' +complete -xc rtx -n "not $fssf $others" -a exec -d 'Execute a command with tool(s) set' +complete -xc rtx -n "not $fssf $others" -a implode -d 'Removes rtx CLI and all related data' +complete -xc rtx -n "not $fssf $others" -a install -d 'Install a tool version' +complete -xc rtx -n "not $fssf $others" -a latest -d 'Gets the latest available version for a plugin' +complete -xc rtx -n "not $fssf $others" -a link -d 'Symlinks a tool version into rtx' +complete -xc rtx -n "not $fssf $others" -a ls -d 'List installed and/or currently selected tool versions' +complete -xc rtx -n "not $fssf $others" -a ls-remote -d 'List runtime versions available for install' +complete -xc rtx -n "not $fssf $others" -a outdated -d 'Shows outdated tool versions' +complete -xc rtx -n "not $fssf $others" -a plugins -d 'Manage plugins' +complete -xc rtx -n "not $fssf $others" -a prune -d 'Delete unused versions of tools' +complete -xc rtx -n "not $fssf $others" -a reshim -d 'rebuilds the shim farm' +complete -xc rtx -n "not $fssf $others" -a self-update -d 'Updates rtx itself' +complete -xc rtx -n "not $fssf $others" -a settings -d 'Manage settings' +complete -xc rtx -n "not $fssf $others" -a shell -d 'Sets a tool version for the current shell session' +complete -xc rtx -n "not $fssf $others" -a sync -d 'Add tool versions from external tools to rtx' +complete -xc rtx -n "not $fssf $others" -a trust -d 'Marks a config file as trusted' +complete -xc rtx -n "not $fssf $others" -a uninstall -d 'Removes runtime versions' +complete -xc rtx -n "not $fssf $others" -a upgrade -d 'Upgrades outdated tool versions' +complete -xc rtx -n "not $fssf $others" -a use -d 'Change the active version of a tool locally or globally.' +complete -xc rtx -n "not $fssf $others" -a version -d 'Show rtx version' +complete -xc rtx -n "not $fssf $others" -a where -d 'Display the installation path for a runtime' +complete -xc rtx -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' + +# activate +complete -xc rtx -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' +complete -xc rtx -n "$fssf activate" -l status -d 'Show "rtx: @" message when changing directories' + +# alias +complete -xc rtx -n "$fssf alias" -s p -l plugin -a "(__rtx_plugins)" -d 'filter aliases by plugin' +set -l others get ls set unset +complete -xc rtx -n "$fssf alias; and not $fssf $others" -a get -d 'Show an alias for a plugin' +complete -xc rtx -n "$fssf alias; and not $fssf $others" -a ls -d 'List aliases' +complete -xc rtx -n "$fssf alias; and not $fssf $others" -a set -d 'Add/update an alias for a plugin' +complete -xc rtx -n "$fssf alias; and not $fssf $others" -a unset -d 'Clears an alias for a plugin' + +# alias get +complete -xc rtx -n "$fssf alias; and $fssf get" -d 'The alias to show' +complete -xc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_plugins)" -d 'The plugin to show the alias for' + +# alias ls +complete -xc rtx -n "$fssf alias; and $fssf ls" -a "(__rtx_plugins)" -d 'Show aliases for ' + +# alias set +complete -xc rtx -n "$fssf alias; and $fssf set" -d 'The alias to set' +complete -xc rtx -n "$fssf alias; and $fssf set" -a "(__rtx_plugins)" -d 'The plugin to set the alias for' +complete -xc rtx -n "$fssf alias; and $fssf set" -d 'The value to set the alias to' + +# alias unset +complete -xc rtx -n "$fssf alias; and $fssf unset" -d 'The alias to remove' +complete -xc rtx -n "$fssf alias; and $fssf unset" -a "(__rtx_plugins)" -d 'The plugin to remove the alias from' + + +# bin-paths + +# cache +set -l others clear +complete -xc rtx -n "$fssf cache; and not $fssf $others" -a clear -d 'Deletes all cache files in rtx' + +# cache clear + + +# completion +complete -xc rtx -n "$fssf completion" -a "bash fish zsh" -d 'Shell type to generate completions for' + +# current +complete -xc rtx -n "$fssf current" -a "(__rtx_plugins)" -d 'Plugin to show versions of e.g.: ruby, node' + +# deactivate + +# direnv +set -l others activate +complete -xc rtx -n "$fssf direnv; and not $fssf $others" -a activate -d 'Output direnv function to use rtx inside direnv' + +# direnv activate + + +# doctor + +# env +complete -xc rtx -n "$fssf env" -s J -l json -d 'Output in JSON format' +complete -xc rtx -n "$fssf env" -s s -l shell -a "bash fish nu xonsh zsh" -d 'Shell type to generate environment variables for' +complete -xc rtx -n "$fssf env" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' + +# env-vars +complete -xc rtx -n "$fssf env-vars" -d 'Environment variable(s) to set' +complete -xc rtx -n "$fssf env-vars" -l file -a "(__fish_complete_path)" -d 'The TOML file to update' +complete -xc rtx -n "$fssf env-vars" -l remove -d 'Remove the environment variable from config file' + +# exec +complete -xc rtx -n "$fssf exec" -s c -l command -d 'Command string to execute' +complete -xc rtx -n "$fssf exec" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' +complete -xc rtx -n "$fssf exec" -d 'Command string to execute (same as --command)' +complete -xc rtx -n "$fssf exec" -a "(__rtx_tool_versions)" -d 'Tool(s) to start e.g.: node@20 python@3.10' + +# implode +complete -xc rtx -n "$fssf implode" -l config -d 'Also remove config directory' +complete -xc rtx -n "$fssf implode" -s n -l dry-run -d 'List directories that would be removed without actually removing them' + +# install +complete -xc rtx -n "$fssf install" -s f -l force -d 'Force reinstall even if already installed' +complete -xc rtx -n "$fssf install" -a "(__rtx_tool_versions)" -d 'Tool(s) to install e.g.: node@20' +complete -xc rtx -n "$fssf install" -s v -l verbose -d 'Show installation output' + +# latest +complete -xc rtx -n "$fssf latest" -s i -l installed -d 'Show latest installed instead of available version' +complete -xc rtx -n "$fssf latest" -a "(__rtx_tool_versions)" -d 'Tool to get the latest version of' + +# link +complete -xc rtx -n "$fssf link" -s f -l force -d 'Overwrite an existing tool version if it exists' +complete -xc rtx -n "$fssf link" -a "(__fish_complete_directories)" -d 'The local path to the tool version' +complete -xc rtx -n "$fssf link" -a "(__rtx_tool_versions)" -d 'Tool name and version to create a symlink for' + +# ls +complete -xc rtx -n "$fssf ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' +complete -xc rtx -n "$fssf ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' +complete -xc rtx -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' +complete -xc rtx -n "$fssf ls" -s J -l json -d 'Output in json format' +complete -xc rtx -n "$fssf ls" -s m -l missing -d 'Display missing tool versions' +complete -xc rtx -n "$fssf ls" -a "(__rtx_plugins)" -d 'Only show tool versions from [PLUGIN]' +complete -xc rtx -n "$fssf ls" -l prefix -d 'Display versions matching this prefix' + +# ls-remote +complete -xc rtx -n "$fssf ls-remote" -a "(__rtx_plugins)" -d 'Plugin to get versions for' +complete -xc rtx -n "$fssf ls-remote" -d 'The version prefix to use when querying the latest version' + +# outdated +complete -xc rtx -n "$fssf outdated" -a "(__rtx_tool_versions)" -d 'Tool(s) to show outdated versions for' + +# plugins +complete -xc rtx -n "$fssf plugins" -s c -l core -d 'The built-in plugins only' +complete -xc rtx -n "$fssf plugins" -l refs -d 'show the git refs for each plugin' +complete -xc rtx -n "$fssf plugins" -s u -l urls -d 'show the git url for each plugin' +complete -xc rtx -n "$fssf plugins" -l user -d 'List installed plugins' +set -l others install link ls ls-remote uninstall update +complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a install -d 'Install a plugin' +complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a link -d 'Symlinks a plugin into rtx' +complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a ls -d 'List installed plugins' +complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a ls-remote -d 'List all available remote plugins' +complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a uninstall -d 'Removes a plugin' +complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a update -d 'Updates a plugin to the latest version' + +# plugins install +complete -xc rtx -n "$fssf plugins; and $fssf install" -s a -l all -d 'Install all missing plugins' +complete -xc rtx -n "$fssf plugins; and $fssf install" -s f -l force -d 'Reinstall even if plugin exists' +complete -xc rtx -n "$fssf plugins; and $fssf install" -d 'The git url of the plugin' +complete -xc rtx -n "$fssf plugins; and $fssf install" -a "(__rtx_all_plugins)" -d 'The name of the plugin to install' +complete -xc rtx -n "$fssf plugins; and $fssf install" -s v -l verbose -d 'Show installation output' + +# plugins link +complete -xc rtx -n "$fssf plugins; and $fssf link" -s f -l force -d 'Overwrite existing plugin' +complete -xc rtx -n "$fssf plugins; and $fssf link" -d 'The name of the plugin' +complete -xc rtx -n "$fssf plugins; and $fssf link" -a "(__fish_complete_directories)" -d 'The local path to the plugin' + +# plugins ls +complete -xc rtx -n "$fssf plugins; and $fssf ls" -s c -l core -d 'The built-in plugins only' +complete -xc rtx -n "$fssf plugins; and $fssf ls" -l refs -d 'Show the git refs for each plugin' +complete -xc rtx -n "$fssf plugins; and $fssf ls" -s u -l urls -d 'Show the git url for each plugin' +complete -xc rtx -n "$fssf plugins; and $fssf ls" -l user -d 'List installed plugins' + +# plugins ls-remote +complete -xc rtx -n "$fssf plugins; and $fssf ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' +complete -xc rtx -n "$fssf plugins; and $fssf ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' + +# plugins uninstall +complete -xc rtx -n "$fssf plugins; and $fssf uninstall" -s a -l all -d 'Remove all plugins' +complete -xc rtx -n "$fssf plugins; and $fssf uninstall" -a "(__rtx_plugins)" -d 'Plugin(s) to remove' +complete -xc rtx -n "$fssf plugins; and $fssf uninstall" -s p -l purge -d 'Also remove the plugin'\''s installs, downloads, and cache' + +# plugins update +complete -xc rtx -n "$fssf plugins; and $fssf update" -a "(__rtx_plugins)" -d 'Plugin(s) to update' + + +# prune +complete -xc rtx -n "$fssf prune" -s n -l dry-run -d 'Do not actually delete anything' +complete -xc rtx -n "$fssf prune" -a "(__rtx_plugins)" -d 'Prune only versions from these plugins' + +# reshim + +# self-update +complete -xc rtx -n "$fssf self-update" -s f -l force -d 'Update even if already up to date' +complete -xc rtx -n "$fssf self-update" -l no-plugins -d 'Disable auto-updating plugins' +complete -xc rtx -n "$fssf self-update" -d 'Update to a specific version' +complete -xc rtx -n "$fssf self-update" -s y -l yes -d 'Skip confirmation prompt' + +# settings +set -l others get ls set unset +complete -xc rtx -n "$fssf settings; and not $fssf $others" -a get -d 'Show a current setting' +complete -xc rtx -n "$fssf settings; and not $fssf $others" -a ls -d 'Show current settings' +complete -xc rtx -n "$fssf settings; and not $fssf $others" -a set -d 'Add/update a setting' +complete -xc rtx -n "$fssf settings; and not $fssf $others" -a unset -d 'Clears a setting' + +# settings get +complete -xc rtx -n "$fssf settings; and $fssf get" -d 'The setting to show' + +# settings ls + +# settings set +complete -xc rtx -n "$fssf settings; and $fssf set" -d 'The setting to set' +complete -xc rtx -n "$fssf settings; and $fssf set" -d 'The value to set' + +# settings unset +complete -xc rtx -n "$fssf settings; and $fssf unset" -d 'The setting to remove' + + +# shell +complete -xc rtx -n "$fssf shell" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' +complete -xc rtx -n "$fssf shell" -s u -l unset -d 'Removes a previously set version' + +# sync +set -l others node python +complete -xc rtx -n "$fssf sync; and not $fssf $others" -a node -d 'Symlinks all tool versions from an external tool into rtx' +complete -xc rtx -n "$fssf sync; and not $fssf $others" -a python -d 'Symlinks all tool versions from an external tool into rtx' + +# sync node +complete -xc rtx -n "$fssf sync; and $fssf node" -l brew -d 'Get tool versions from Homebrew' +complete -xc rtx -n "$fssf sync; and $fssf node" -l nodenv -d 'Get tool versions from nodenv' +complete -xc rtx -n "$fssf sync; and $fssf node" -l nvm -d 'Get tool versions from nvm' + +# sync python +complete -xc rtx -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versions from pyenv' + + +# trust +complete -xc rtx -n "$fssf trust" -a "(__fish_complete_path)" -d 'The config file to trust' +complete -xc rtx -n "$fssf trust" -l untrust -d 'No longer trust this config' + +# uninstall +complete -xc rtx -n "$fssf uninstall" -s a -l all -d 'Delete all installed versions' +complete -xc rtx -n "$fssf uninstall" -s n -l dry-run -d 'Do not actually delete anything' +complete -xc rtx -n "$fssf uninstall" -a "(__rtx_tool_versions)" -d 'Tool(s) to remove' + +# upgrade +complete -xc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' + +# use +complete -xc rtx -n "$fssf use" -s e -l env -d '[experimental] Modify an environment-specific config file like .rtx..toml' +complete -xc rtx -n "$fssf use" -l fuzzy -d 'Save fuzzy version to config file' +complete -xc rtx -n "$fssf use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' +complete -xc rtx -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' +complete -xc rtx -n "$fssf use" -l pin -d 'Save exact version to config file' +complete -xc rtx -n "$fssf use" -l remove -d 'Remove the tool(s) from config file' +complete -xc rtx -n "$fssf use" -a "(__rtx_tool_versions)" -d 'Tool(s) to add to config file' + +# version + +# where +complete -xc rtx -n "$fssf where" -a "(__rtx_tool_versions)" -d 'Tool(s) to look up' + +# which +complete -xc rtx -n "$fssf which" -d 'The bin name to look up' +complete -xc rtx -n "$fssf which" -l plugin -a "(__rtx_plugins)" -d 'Show the plugin name instead of the path' +complete -xc rtx -n "$fssf which" -s t -l tool -a "(__rtx_tool_versions)" -d 'Use a specific tool@version' +complete -xc rtx -n "$fssf which" -l version -d 'Show the version instead of the path' + + + +function __rtx_all_plugins + if test -z "$__rtx_all_plugins_cache" + set -g __rtx_all_plugins_cache (rtx plugins ls --all) + end + for p in $__rtx_all_plugins_cache + echo $p + end +end +function __rtx_plugins + if test -z "$__rtx_plugins_cache" + set -g __rtx_plugins_cache (rtx plugins ls --core --user) + end + for p in $__rtx_plugins_cache + echo $p + end +end +function __rtx_tool_versions + if test -z "$__rtx_tool_versions_cache" + set -g __rtx_tool_versions_cache + for plugin in (__rtx_plugins) + for v in (rtx ls-remote $plugin) + set -a __rtx_tool_versions_cache "$plugin@$v" + end + end + end + for tv in $__rtx_tool_versions_cache + echo $tv + end +end + +# vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 52804b164..65a221bed 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -7,7 +7,7 @@ use color_eyre::eyre::Result; use crate::cli::self_update::SelfUpdate; use crate::config::Config; use crate::output::Output; -use crate::shell::completions::zsh_complete; +use crate::shell::completions; /// Generate shell completions #[derive(Debug, Args)] @@ -29,7 +29,8 @@ impl RenderCompletion { let mut cmd = crate::cli::Cli::command().subcommand(SelfUpdate::command()); let script = match shell { - clap_complete::Shell::Zsh => zsh_complete(&cmd)?, + clap_complete::Shell::Zsh => completions::zsh_complete(&cmd)?, + clap_complete::Shell::Fish => completions::fish_complete(&cmd)?, _ => { let mut c = Cursor::new(Vec::new()); generate(shell, &mut cmd, "rtx", &mut c); diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs new file mode 100644 index 000000000..a2a5b7b1b --- /dev/null +++ b/src/shell/completions/fish_complete.rs @@ -0,0 +1,183 @@ +use clap::builder::StyledStr; +use clap::{Arg, Command, ValueHint}; +use itertools::Itertools; + +use crate::shell::completions::is_banned; + +pub fn render(cmd: &Command) -> String { + let cmds = vec![cmd]; + let subcommands = render_subcommands(&cmds).join("\n"); + + format! {r#" +set -l fssf "__fish_seen_subcommand_from" + +{subcommands} + +function __rtx_all_plugins + if test -z "$__rtx_all_plugins_cache" + set -g __rtx_all_plugins_cache (rtx plugins ls --all) + end + for p in $__rtx_all_plugins_cache + echo $p + end +end +function __rtx_plugins + if test -z "$__rtx_plugins_cache" + set -g __rtx_plugins_cache (rtx plugins ls --core --user) + end + for p in $__rtx_plugins_cache + echo $p + end +end +function __rtx_tool_versions + if test -z "$__rtx_tool_versions_cache" + set -g __rtx_tool_versions_cache + for plugin in (__rtx_plugins) + for v in (rtx ls-remote $plugin) + set -a __rtx_tool_versions_cache "$plugin@$v" + end + end + end + for tv in $__rtx_tool_versions_cache + echo $tv + end +end + +# vim: noet ci pi sts=0 sw=4 ts=4 +"#} +} + +fn render_args(cmds: &[&Command]) -> Vec { + let cmd = cmds[cmds.len() - 1]; + cmd.get_arguments() + .filter(|a| !a.is_hide_set()) + .sorted_by_cached_key(|a| a.get_id()) + .map(|a| render_arg(cmds, a)) + .collect() +} + +fn render_arg(cmds: &[&Command], a: &Arg) -> String { + let mut complete_cmd = r#"complete -xc rtx"#.to_string(); + let parents = cmds.iter().skip(1).map(|c| c.get_name()).collect_vec(); + if cmds.len() > 1 { + let mut p = format!("$fssf {}", &parents[0]); + for parent in &parents[1..] { + p.push_str(&format!("; and $fssf {}", parent)); + } + complete_cmd.push_str(&format!(r#" -n "{p}""#)); + } + if let Some(short) = a.get_short() { + complete_cmd.push_str(&format!(" -s {}", short)); + } + if let Some(long) = a.get_long() { + complete_cmd.push_str(&format!(" -l {}", long)); + } + if let Some(c) = render_completer(a) { + complete_cmd.push_str(&format!(r#" -a "{c}""#)); + } + let help = about_to_help(a.get_help()); + complete_cmd.push_str(&format!(" -d '{help}'")); + complete_cmd +} + +fn render_completer(a: &Arg) -> Option { + let possible_values = a.get_possible_values(); + if !possible_values.is_empty() { + return Some( + possible_values + .iter() + .map(|v| escape_value(v.get_name())) + .collect::>() + .join(" "), + ); + } + match a.get_value_hint() { + ValueHint::DirPath => Some("(__fish_complete_directories)".to_string()), + ValueHint::FilePath => Some("(__fish_complete_path)".to_string()), + ValueHint::AnyPath => Some("(__fish_complete_path)".to_string()), + _ => match a.get_id().as_str() { + "tool" => Some("(__rtx_tool_versions)".to_string()), + "plugin" => Some("(__rtx_plugins)".to_string()), + "new_plugin" => Some("(__rtx_all_plugins)".to_string()), + //"alias" => Some("(__rtx_aliases)".to_string()), + //"prefix" => Some("(__rtx_prefixes)".to_string()), + _ => None, + }, + } +} + +fn render_subcommands(cmds: &[&Command]) -> Vec { + let cmd = cmds[cmds.len() - 1]; + let full_name = cmds.iter().skip(1).map(|c| c.get_name()).join(" "); + let parents = cmds.iter().skip(1).map(|c| c.get_name()).collect_vec(); + + let args = render_args(cmds); + let subcommands = cmd + .get_subcommands() + .filter(|c| !is_banned(c) && !c.is_hide_set()) + .sorted_by_cached_key(|c| c.get_name()) + .collect_vec(); + let command_names = subcommands.iter().map(|c| c.get_name()).join(" "); + + let subcommand_defs = subcommands.iter().map(|cmd| { + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + let name = cmd.get_name(); + let help = about_to_help(cmd.get_about()); + if parents.is_empty() { + format!(r#"complete -xc rtx -n "not $fssf $others" -a {name} -d '{help}'"#) + } else { + let mut p = format!("$fssf {}", &parents[0]); + for parent in &parents[1..] { + p.push_str(&format!("; and $fssf {}", parent)); + } + format!(r#"complete -xc rtx -n "{p}; and not $fssf $others" -a {name} -d '{help}'"#) + } + }); + + let rendered_subcommands = subcommands.iter().flat_map(|cmd| { + let mut cmds = cmds.iter().copied().collect_vec(); + cmds.push(cmd); + render_subcommands(&cmds) + }); + + let mut out = vec![format! {"# {}", if full_name.is_empty() { "rtx" } else { &full_name }}]; + out.extend(args); + if !subcommands.is_empty() { + out.push(format! {"set -l others {command_names}"}); + out.extend(subcommand_defs); + out.push(String::new()); + out.extend(rendered_subcommands); + } + out.push(String::new()); + out +} + +fn first_line(s: &str) -> &str { + s.lines().next().unwrap_or_default() +} + +fn help_escape(s: &str) -> String { + s.replace('\\', "\\\\").replace('\'', "'\\''") +} + +fn about_to_help(ss: Option<&StyledStr>) -> String { + match ss { + Some(ss) => help_escape(first_line(&ss.to_string())), + None => String::new(), + } +} + +fn escape_value(string: &str) -> String { + string + .replace('\\', "\\\\") + .replace('\'', "'\\''") + .replace('[', "\\[") + .replace(']', "\\]") + .replace(':', "\\:") + .replace('$', "\\$") + .replace('`', "\\`") + .replace('(', "\\(") + .replace(')', "\\)") + .replace(' ', "\\ ") +} diff --git a/src/shell/completions/mod.rs b/src/shell/completions/mod.rs index e9c056221..64969159b 100644 --- a/src/shell/completions/mod.rs +++ b/src/shell/completions/mod.rs @@ -1,5 +1,8 @@ use clap::Command; +use once_cell::sync::Lazy; +use std::collections::HashSet; +mod fish_complete; mod zsh_complete; pub fn zsh_complete(cmd: &Command) -> eyre::Result { @@ -7,3 +10,17 @@ pub fn zsh_complete(cmd: &Command) -> eyre::Result { let result = cmd!("shfmt", "-s").stdin_bytes(output).read()?; Ok(result) } + +pub fn fish_complete(cmd: &Command) -> eyre::Result { + let output = fish_complete::render(cmd); + // eprintln!("{}", output); + // let result = cmd!("shfmt", "-s").stdin_bytes(output).read()?; + Ok(output) +} + +static BANNED_COMMANDS: Lazy> = + Lazy::new(|| ["render-mangen", "render-help", "render-completion"].into()); + +pub fn is_banned(cmd: &Command) -> bool { + BANNED_COMMANDS.contains(&cmd.get_name()) +} diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index 413561f0d..38c0100a0 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -1,7 +1,6 @@ +use crate::shell::completions::is_banned; use clap::{Arg, ArgAction, Command, ValueHint}; use itertools::Itertools; -use once_cell::sync::Lazy; -use std::collections::HashSet; pub fn render(cmd: &Command) -> String { let cmds = vec![cmd]; @@ -60,13 +59,7 @@ pub fn render(cmd: &Command) -> String { compdef _rtx rtx fi - # Local Variables: - # mode: Shell-Script - # sh-indentation: 2 - # indent-tabs-mode: nil - # sh-basic-offset: 2 - # End: - # vim: ft=zsh sw=2 ts=2 et + # vim: noet ci pi sts=0 sw=4 ts=4 "#} } @@ -109,7 +102,7 @@ fn render_subcommands(cmds: &[&Command]) -> String { let cmd = cmds.last().unwrap(); let cases = cmd .get_subcommands() - .filter(|c| !banned(c)) + .filter(|c| !is_banned(c)) .sorted_by_cached_key(|c| c.get_name()) .map(|cmd| { let mut names = cmd.get_all_aliases().sorted().collect_vec(); @@ -228,7 +221,7 @@ fn render_completion(arg: &Arg) -> String { fn render_command_funcs(cmds: &[&Command]) -> String { let cmd = cmds.last().unwrap(); cmd.get_subcommands() - .filter(|c| !banned(c)) + .filter(|c| !is_banned(c)) .sorted_by_key(|c| c.get_name()) .map(|cmd| { let mut cmds = cmds.iter().copied().collect_vec(); @@ -254,7 +247,7 @@ fn render_command_descriptions(cmds: &[&Command]) -> String { let cmd = cmds.last().unwrap(); let commands = cmd .get_subcommands() - .filter(|c| !c.is_hide_set() && !banned(c)) + .filter(|c| !c.is_hide_set() && !is_banned(c)) .sorted_by_key(|c| c.get_name()) .map(|cmd| { let name = cmd.get_name(); @@ -284,7 +277,7 @@ fn render_command_descriptions(cmds: &[&Command]) -> String { for cmd in cmd .get_subcommands() - .filter(|c| c.has_subcommands() && !banned(c)) + .filter(|c| c.has_subcommands() && !is_banned(c)) { let mut cmds = cmds.iter().copied().collect_vec(); cmds.push(cmd); @@ -328,10 +321,3 @@ fn escape_value(string: &str) -> String { .replace(')', "\\)") .replace(' ', "\\ ") } - -static BANNED_COMMANDS: Lazy> = - Lazy::new(|| ["render-mangen", "render-help", "render-completion"].into()); - -fn banned(cmd: &Command) -> bool { - BANNED_COMMANDS.contains(&cmd.get_name()) -} From 4dc445832898135f2dd5afc1edda1b983c279304 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:23:55 -0600 Subject: [PATCH 1182/1891] completions: new fish completer (#1085) --- README.md | 12 ++++-- completions/_rtx | 3 +- completions/rtx.bash | 2 +- completions/rtx.fish | 8 +--- src/cli/ls_remote.rs | 53 +++++++++++++++++++------- src/shell/completions/fish_complete.rs | 7 +--- 6 files changed, 53 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index ef9d75440..956798bf8 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ v20.0.0 - [`rtx latest [OPTIONS] `](#rtx-latest-options-toolversion) - [`rtx link [OPTIONS] `](#rtx-link-options-toolversion-path) - [`rtx ls [OPTIONS] [PLUGIN]`](#rtx-ls-options-plugin) - - [`rtx ls-remote [PREFIX]`](#rtx-ls-remote-toolversion-prefix) + - [`rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]`](#rtx-ls-remote-options-toolversion-prefix) - [`rtx outdated [TOOL@VERSION]...`](#rtx-outdated-toolversion) - [`rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]`](#rtx-plugins-install-options-new_plugin-git_url) - [`rtx plugins link [OPTIONS] [PATH]`](#rtx-plugins-link-options-name-path) @@ -2106,7 +2106,7 @@ Examples: } ``` -### `rtx ls-remote [PREFIX]` +### `rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` ``` List runtime versions available for install @@ -2114,16 +2114,20 @@ List runtime versions available for install note that the results are cached for 24 hours run `rtx cache clean` to clear the cache and get fresh results -Usage: ls-remote [PREFIX] +Usage: ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX] Arguments: - + [TOOL@VERSION] Plugin to get versions for [PREFIX] The version prefix to use when querying the latest version same as the first argument after the "@" +Options: + --all + Show all installed plugins and versions + Examples: $ rtx ls-remote node 18.0.0 diff --git a/completions/_rtx b/completions/_rtx index 121f20f22..bb6d18671 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -420,7 +420,8 @@ _rtx() { (($ + functions[__rtx_ls_remote_cmd])) || __rtx_ls_remote_cmd() { _arguments -s -S \ - ':plugin:__rtx_plugins' \ + '::plugin:__rtx_plugins' \ + '--all[Show all installed plugins and versions]' \ '::prefix:__rtx_prefixes' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 67ad72fa4..a6f428945 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2487,7 +2487,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PREFIX]" + opts="-j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION] [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index de42177be..0f840c0a6 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -140,6 +140,7 @@ complete -xc rtx -n "$fssf ls" -a "(__rtx_plugins)" -d 'Only show tool versions complete -xc rtx -n "$fssf ls" -l prefix -d 'Display versions matching this prefix' # ls-remote +complete -xc rtx -n "$fssf ls-remote" -l all -d 'Show all installed plugins and versions' complete -xc rtx -n "$fssf ls-remote" -a "(__rtx_plugins)" -d 'Plugin to get versions for' complete -xc rtx -n "$fssf ls-remote" -d 'The version prefix to use when querying the latest version' @@ -292,12 +293,7 @@ function __rtx_plugins end function __rtx_tool_versions if test -z "$__rtx_tool_versions_cache" - set -g __rtx_tool_versions_cache - for plugin in (__rtx_plugins) - for v in (rtx ls-remote $plugin) - set -a __rtx_tool_versions_cache "$plugin@$v" - end - end + set -g __rtx_tool_versions_cache (rtx ls-remote --all) end for tv in $__rtx_tool_versions_cache echo $tv diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 7a05c8a86..de5674277 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -17,8 +17,12 @@ use crate::toolset::ToolVersionRequest; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = ["list-all", "list-remote"])] pub struct LsRemote { /// Plugin to get versions for - #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] - plugin: ToolArg, + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, required_unless_present = "all")] + plugin: Option, + + /// Show all installed plugins and versions + #[clap(long, verbatim_doc_comment, conflicts_with_all = ["plugin", "prefix"])] + all: bool, /// The version prefix to use when querying the latest version /// same as the first argument after the "@" @@ -28,18 +32,27 @@ pub struct LsRemote { impl LsRemote { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let plugin = self.get_plugin(&mut config)?; + if let Some(plugin) = self.get_plugin(&mut config)? { + self.run_single(config, out, plugin) + } else { + self.run_all(config, out) + } + } - let prefix = match &self.plugin.tvr { - Some(ToolVersionRequest::Version(_, v)) => Some(v), - _ => self.prefix.as_ref(), + fn run_single(self, config: Config, out: &mut Output, plugin: Arc) -> Result<()> { + let prefix = match &self.plugin { + Some(tool_arg) => match &tool_arg.tvr { + Some(ToolVersionRequest::Version(_, v)) => Some(v.clone()), + _ => self.prefix.clone(), + }, + _ => self.prefix.clone(), }; let versions = plugin.list_remote_versions(&config.settings)?; let versions = match prefix { Some(prefix) => versions .into_iter() - .filter(|v| v.starts_with(prefix)) + .filter(|v| v.starts_with(&prefix)) .collect(), None => versions, }; @@ -50,14 +63,26 @@ impl LsRemote { Ok(()) } -} -impl LsRemote { - fn get_plugin(&self, config: &mut Config) -> Result> { - let plugin_name = self.plugin.plugin.clone(); - let tool = config.get_or_create_tool(&plugin_name); - tool.ensure_installed(config, None, false)?; - Ok(tool) + fn run_all(self, config: Config, out: &mut Output) -> Result<()> { + for plugin in config.tools.values() { + let versions = plugin.list_remote_versions(&config.settings)?; + for version in versions { + rtxprintln!(out, "{}@{}", plugin.name, version); + } + } + Ok(()) + } + + fn get_plugin(&self, config: &mut Config) -> Result>> { + match &self.plugin { + Some(tool_arg) => { + let tool = config.get_or_create_tool(&tool_arg.plugin); + tool.ensure_installed(config, None, false)?; + Ok(Some(tool)) + } + None => Ok(None), + } } } diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index a2a5b7b1b..f9a06f2a8 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -31,12 +31,7 @@ function __rtx_plugins end function __rtx_tool_versions if test -z "$__rtx_tool_versions_cache" - set -g __rtx_tool_versions_cache - for plugin in (__rtx_plugins) - for v in (rtx ls-remote $plugin) - set -a __rtx_tool_versions_cache "$plugin@$v" - end - end + set -g __rtx_tool_versions_cache (rtx ls-remote --all) end for tv in $__rtx_tool_versions_cache echo $tv From d2bb3fdf13f2f31704fbf88493bc452cc8a4c000 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:32:38 -0600 Subject: [PATCH 1183/1891] node: use non-node-build plugin by default (#1086) See #1028 --- src/plugins/core/mod.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 9d8a8e21f..d82574eb3 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -38,10 +38,10 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ Box::new(GoPlugin::new()), Box::new(JavaPlugin::new()), - if *RTX_NODE_BUILD == Some(false) { - Box::new(NodePlugin::new()) - } else { + if *RTX_NODE_BUILD == Some(true) { Box::new(NodeBuildPlugin::new()) + } else { + Box::new(NodePlugin::new()) }, Box::new(PythonPlugin::new()), Box::new(RubyPlugin::new()), @@ -52,11 +52,6 @@ pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ Box::new(BunPlugin::new()), Box::new(DenoPlugin::new()), - if *RTX_NODE_BUILD == Some(true) { - Box::new(NodeBuildPlugin::new()) - } else { - Box::new(NodePlugin::new()) - }, ]) }); From 989f50571bfd3c637c59e7404d490a1f4123d4de Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:33:29 -0600 Subject: [PATCH 1184/1891] chore: Release rtx-cli version 2023.12.9 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 +- completions/rtx.bash | 3586 ---------------------------------------- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 6 files changed, 6 insertions(+), 3592 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2dca6a6e0..a88fb5989 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1810,7 +1810,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.8" +version = "2023.12.9" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 4355c104c..f9e62330c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.8" +version = "2023.12.9" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 956798bf8..eee64913f 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.8 +rtx 2023.12.9 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.8/rtx-v2023.12.8-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.9/rtx-v2023.12.9-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/completions/rtx.bash b/completions/rtx.bash index a6f428945..e69de29bb 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1,3586 +0,0 @@ -_rtx() { - local i cur prev opts cmd - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - cmd="" - opts="" - - for i in ${COMP_WORDS[@]} - do - case "${cmd},${i}" in - ",$1") - cmd="rtx" - ;; - rtx,a) - cmd="rtx__alias" - ;; - rtx,activate) - cmd="rtx__activate" - ;; - rtx,alias) - cmd="rtx__alias" - ;; - rtx,asdf) - cmd="rtx__asdf" - ;; - rtx,bin-paths) - cmd="rtx__bin__paths" - ;; - rtx,cache) - cmd="rtx__cache" - ;; - rtx,completion) - cmd="rtx__completion" - ;; - rtx,current) - cmd="rtx__current" - ;; - rtx,deactivate) - cmd="rtx__deactivate" - ;; - rtx,direnv) - cmd="rtx__direnv" - ;; - rtx,doctor) - cmd="rtx__doctor" - ;; - rtx,e) - cmd="rtx__env" - ;; - rtx,env) - cmd="rtx__env" - ;; - rtx,env-vars) - cmd="rtx__env__vars" - ;; - rtx,exec) - cmd="rtx__exec" - ;; - rtx,global) - cmd="rtx__global" - ;; - rtx,help) - cmd="rtx__help" - ;; - rtx,hook-env) - cmd="rtx__hook__env" - ;; - rtx,i) - cmd="rtx__install" - ;; - rtx,implode) - cmd="rtx__implode" - ;; - rtx,install) - cmd="rtx__install" - ;; - rtx,latest) - cmd="rtx__latest" - ;; - rtx,link) - cmd="rtx__link" - ;; - rtx,list) - cmd="rtx__ls" - ;; - rtx,local) - cmd="rtx__local" - ;; - rtx,ls) - cmd="rtx__ls" - ;; - rtx,ls-remote) - cmd="rtx__ls__remote" - ;; - rtx,outdated) - cmd="rtx__outdated" - ;; - rtx,p) - cmd="rtx__plugins" - ;; - rtx,plugins) - cmd="rtx__plugins" - ;; - rtx,prune) - cmd="rtx__prune" - ;; - rtx,render-completion) - cmd="rtx__render__completion" - ;; - rtx,render-help) - cmd="rtx__render__help" - ;; - rtx,render-mangen) - cmd="rtx__render__mangen" - ;; - rtx,reshim) - cmd="rtx__reshim" - ;; - rtx,self-update) - cmd="rtx__self__update" - ;; - rtx,settings) - cmd="rtx__settings" - ;; - rtx,shell) - cmd="rtx__shell" - ;; - rtx,sync) - cmd="rtx__sync" - ;; - rtx,trust) - cmd="rtx__trust" - ;; - rtx,u) - cmd="rtx__use" - ;; - rtx,uninstall) - cmd="rtx__uninstall" - ;; - rtx,upgrade) - cmd="rtx__upgrade" - ;; - rtx,use) - cmd="rtx__use" - ;; - rtx,version) - cmd="rtx__version" - ;; - rtx,where) - cmd="rtx__where" - ;; - rtx,which) - cmd="rtx__which" - ;; - rtx,x) - cmd="rtx__exec" - ;; - rtx__alias,add) - cmd="rtx__alias__set" - ;; - rtx__alias,create) - cmd="rtx__alias__set" - ;; - rtx__alias,del) - cmd="rtx__alias__unset" - ;; - rtx__alias,delete) - cmd="rtx__alias__unset" - ;; - rtx__alias,get) - cmd="rtx__alias__get" - ;; - rtx__alias,help) - cmd="rtx__alias__help" - ;; - rtx__alias,list) - cmd="rtx__alias__ls" - ;; - rtx__alias,ls) - cmd="rtx__alias__ls" - ;; - rtx__alias,remove) - cmd="rtx__alias__unset" - ;; - rtx__alias,rm) - cmd="rtx__alias__unset" - ;; - rtx__alias,set) - cmd="rtx__alias__set" - ;; - rtx__alias,unset) - cmd="rtx__alias__unset" - ;; - rtx__alias__help,get) - cmd="rtx__alias__help__get" - ;; - rtx__alias__help,help) - cmd="rtx__alias__help__help" - ;; - rtx__alias__help,ls) - cmd="rtx__alias__help__ls" - ;; - rtx__alias__help,set) - cmd="rtx__alias__help__set" - ;; - rtx__alias__help,unset) - cmd="rtx__alias__help__unset" - ;; - rtx__cache,c) - cmd="rtx__cache__clear" - ;; - rtx__cache,clear) - cmd="rtx__cache__clear" - ;; - rtx__cache,help) - cmd="rtx__cache__help" - ;; - rtx__cache__help,clear) - cmd="rtx__cache__help__clear" - ;; - rtx__cache__help,help) - cmd="rtx__cache__help__help" - ;; - rtx__direnv,activate) - cmd="rtx__direnv__activate" - ;; - rtx__direnv,envrc) - cmd="rtx__direnv__envrc" - ;; - rtx__direnv,exec) - cmd="rtx__direnv__exec" - ;; - rtx__direnv,help) - cmd="rtx__direnv__help" - ;; - rtx__direnv__help,activate) - cmd="rtx__direnv__help__activate" - ;; - rtx__direnv__help,envrc) - cmd="rtx__direnv__help__envrc" - ;; - rtx__direnv__help,exec) - cmd="rtx__direnv__help__exec" - ;; - rtx__direnv__help,help) - cmd="rtx__direnv__help__help" - ;; - rtx__help,activate) - cmd="rtx__help__activate" - ;; - rtx__help,alias) - cmd="rtx__help__alias" - ;; - rtx__help,asdf) - cmd="rtx__help__asdf" - ;; - rtx__help,bin-paths) - cmd="rtx__help__bin__paths" - ;; - rtx__help,cache) - cmd="rtx__help__cache" - ;; - rtx__help,completion) - cmd="rtx__help__completion" - ;; - rtx__help,current) - cmd="rtx__help__current" - ;; - rtx__help,deactivate) - cmd="rtx__help__deactivate" - ;; - rtx__help,direnv) - cmd="rtx__help__direnv" - ;; - rtx__help,doctor) - cmd="rtx__help__doctor" - ;; - rtx__help,env) - cmd="rtx__help__env" - ;; - rtx__help,env-vars) - cmd="rtx__help__env__vars" - ;; - rtx__help,exec) - cmd="rtx__help__exec" - ;; - rtx__help,global) - cmd="rtx__help__global" - ;; - rtx__help,help) - cmd="rtx__help__help" - ;; - rtx__help,hook-env) - cmd="rtx__help__hook__env" - ;; - rtx__help,implode) - cmd="rtx__help__implode" - ;; - rtx__help,install) - cmd="rtx__help__install" - ;; - rtx__help,latest) - cmd="rtx__help__latest" - ;; - rtx__help,link) - cmd="rtx__help__link" - ;; - rtx__help,local) - cmd="rtx__help__local" - ;; - rtx__help,ls) - cmd="rtx__help__ls" - ;; - rtx__help,ls-remote) - cmd="rtx__help__ls__remote" - ;; - rtx__help,outdated) - cmd="rtx__help__outdated" - ;; - rtx__help,plugins) - cmd="rtx__help__plugins" - ;; - rtx__help,prune) - cmd="rtx__help__prune" - ;; - rtx__help,render-completion) - cmd="rtx__help__render__completion" - ;; - rtx__help,render-help) - cmd="rtx__help__render__help" - ;; - rtx__help,render-mangen) - cmd="rtx__help__render__mangen" - ;; - rtx__help,reshim) - cmd="rtx__help__reshim" - ;; - rtx__help,self-update) - cmd="rtx__help__self__update" - ;; - rtx__help,settings) - cmd="rtx__help__settings" - ;; - rtx__help,shell) - cmd="rtx__help__shell" - ;; - rtx__help,sync) - cmd="rtx__help__sync" - ;; - rtx__help,trust) - cmd="rtx__help__trust" - ;; - rtx__help,uninstall) - cmd="rtx__help__uninstall" - ;; - rtx__help,upgrade) - cmd="rtx__help__upgrade" - ;; - rtx__help,use) - cmd="rtx__help__use" - ;; - rtx__help,version) - cmd="rtx__help__version" - ;; - rtx__help,where) - cmd="rtx__help__where" - ;; - rtx__help,which) - cmd="rtx__help__which" - ;; - rtx__help__alias,get) - cmd="rtx__help__alias__get" - ;; - rtx__help__alias,ls) - cmd="rtx__help__alias__ls" - ;; - rtx__help__alias,set) - cmd="rtx__help__alias__set" - ;; - rtx__help__alias,unset) - cmd="rtx__help__alias__unset" - ;; - rtx__help__cache,clear) - cmd="rtx__help__cache__clear" - ;; - rtx__help__direnv,activate) - cmd="rtx__help__direnv__activate" - ;; - rtx__help__direnv,envrc) - cmd="rtx__help__direnv__envrc" - ;; - rtx__help__direnv,exec) - cmd="rtx__help__direnv__exec" - ;; - rtx__help__plugins,install) - cmd="rtx__help__plugins__install" - ;; - rtx__help__plugins,link) - cmd="rtx__help__plugins__link" - ;; - rtx__help__plugins,ls) - cmd="rtx__help__plugins__ls" - ;; - rtx__help__plugins,ls-remote) - cmd="rtx__help__plugins__ls__remote" - ;; - rtx__help__plugins,uninstall) - cmd="rtx__help__plugins__uninstall" - ;; - rtx__help__plugins,update) - cmd="rtx__help__plugins__update" - ;; - rtx__help__settings,get) - cmd="rtx__help__settings__get" - ;; - rtx__help__settings,ls) - cmd="rtx__help__settings__ls" - ;; - rtx__help__settings,set) - cmd="rtx__help__settings__set" - ;; - rtx__help__settings,unset) - cmd="rtx__help__settings__unset" - ;; - rtx__help__sync,node) - cmd="rtx__help__sync__node" - ;; - rtx__help__sync,python) - cmd="rtx__help__sync__python" - ;; - rtx__plugins,a) - cmd="rtx__plugins__install" - ;; - rtx__plugins,help) - cmd="rtx__plugins__help" - ;; - rtx__plugins,i) - cmd="rtx__plugins__install" - ;; - rtx__plugins,install) - cmd="rtx__plugins__install" - ;; - rtx__plugins,link) - cmd="rtx__plugins__link" - ;; - rtx__plugins,list) - cmd="rtx__plugins__ls" - ;; - rtx__plugins,list-remote) - cmd="rtx__plugins__ls__remote" - ;; - rtx__plugins,ls) - cmd="rtx__plugins__ls" - ;; - rtx__plugins,ls-remote) - cmd="rtx__plugins__ls__remote" - ;; - rtx__plugins,uninstall) - cmd="rtx__plugins__uninstall" - ;; - rtx__plugins,update) - cmd="rtx__plugins__update" - ;; - rtx__plugins__help,help) - cmd="rtx__plugins__help__help" - ;; - rtx__plugins__help,install) - cmd="rtx__plugins__help__install" - ;; - rtx__plugins__help,link) - cmd="rtx__plugins__help__link" - ;; - rtx__plugins__help,ls) - cmd="rtx__plugins__help__ls" - ;; - rtx__plugins__help,ls-remote) - cmd="rtx__plugins__help__ls__remote" - ;; - rtx__plugins__help,uninstall) - cmd="rtx__plugins__help__uninstall" - ;; - rtx__plugins__help,update) - cmd="rtx__plugins__help__update" - ;; - rtx__settings,add) - cmd="rtx__settings__set" - ;; - rtx__settings,create) - cmd="rtx__settings__set" - ;; - rtx__settings,del) - cmd="rtx__settings__unset" - ;; - rtx__settings,delete) - cmd="rtx__settings__unset" - ;; - rtx__settings,get) - cmd="rtx__settings__get" - ;; - rtx__settings,help) - cmd="rtx__settings__help" - ;; - rtx__settings,list) - cmd="rtx__settings__ls" - ;; - rtx__settings,ls) - cmd="rtx__settings__ls" - ;; - rtx__settings,remove) - cmd="rtx__settings__unset" - ;; - rtx__settings,rm) - cmd="rtx__settings__unset" - ;; - rtx__settings,set) - cmd="rtx__settings__set" - ;; - rtx__settings,unset) - cmd="rtx__settings__unset" - ;; - rtx__settings__help,get) - cmd="rtx__settings__help__get" - ;; - rtx__settings__help,help) - cmd="rtx__settings__help__help" - ;; - rtx__settings__help,ls) - cmd="rtx__settings__help__ls" - ;; - rtx__settings__help,set) - cmd="rtx__settings__help__set" - ;; - rtx__settings__help,unset) - cmd="rtx__settings__help__unset" - ;; - rtx__sync,help) - cmd="rtx__sync__help" - ;; - rtx__sync,node) - cmd="rtx__sync__node" - ;; - rtx__sync,python) - cmd="rtx__sync__python" - ;; - rtx__sync__help,help) - cmd="rtx__sync__help__help" - ;; - rtx__sync__help,node) - cmd="rtx__sync__help__node" - ;; - rtx__sync__help,python) - cmd="rtx__sync__help__python" - ;; - *) - ;; - esac - done - - case "${cmd}" in - rtx) - opts="-j -r -v -y -h -V --jobs --debug --log-level --trace --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__activate) - opts="-s -q -j -r -v -y -h --shell --status --quiet --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish nu xonsh zsh" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --shell) - COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias) - opts="-p -j -r -v -y -h --plugin --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --plugin) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -p) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__get) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__help) - opts="get ls set unset help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__help__get) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__help__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__help__ls) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__help__set) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__help__unset) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__ls) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__set) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__alias__unset) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__asdf) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ARGS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__bin__paths) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__cache) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help clear help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__cache__clear) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__cache__help) - opts="clear help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__cache__help__clear) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__cache__help__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__completion) - opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish zsh" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --shell) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__current) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__deactivate) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help envrc exec activate help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__activate) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__envrc) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__exec) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__help) - opts="envrc exec activate help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__help__activate) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__help__envrc) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__help__exec) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__direnv__help__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__doctor) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__env) - opts="-s -J -j -r -v -y -h --shell --json --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --shell) - COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__env__vars) - opts="-j -r -v -y -h --file --remove --jobs --debug --log-level --trace --raw --verbose --yes --help [ENV_VARS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --file) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --remove) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__exec) - opts="-c -C -j -r -v -y -h --command --cd --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --command) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -c) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --cd) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -C) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__global) - opts="-j -r -v -y -h --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --remove) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__activate) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__alias) - opts="get ls set unset" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__alias__get) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__alias__ls) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__alias__set) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__alias__unset) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__asdf) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__bin__paths) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__cache) - opts="clear" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__cache__clear) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__completion) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__current) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__deactivate) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__direnv) - opts="envrc exec activate" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__direnv__activate) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__direnv__envrc) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__direnv__exec) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__doctor) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__env) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__env__vars) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__exec) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__global) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__hook__env) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__implode) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__install) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__latest) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__link) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__local) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__ls) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__ls__remote) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__outdated) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__plugins) - opts="install link ls ls-remote uninstall update" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__plugins__install) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__plugins__link) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__plugins__ls) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__plugins__ls__remote) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__plugins__uninstall) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__plugins__update) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__prune) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__render__completion) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__render__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__render__mangen) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__reshim) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__self__update) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__settings) - opts="get ls set unset" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__settings__get) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__settings__ls) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__settings__set) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__settings__unset) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__shell) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__sync) - opts="node python" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__sync__node) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__sync__python) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__trust) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__uninstall) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__upgrade) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__use) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__version) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__where) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__help__which) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__hook__env) - opts="-s -j -r -v -y -h --shell --status --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --shell) - COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__implode) - opts="-n -j -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__install) - opts="-f -v -j -r -y -h --force --verbose --jobs --debug --log-level --trace --raw --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__latest) - opts="-i -j -r -v -y -h --installed --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__link) - opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__local) - opts="-p -j -r -v -y -h --parent --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --remove) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__ls) - opts="-p -c -g -i -J -m -j -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --plugin) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -p) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --prefix) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__ls__remote) - opts="-j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION] [PREFIX]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__outdated) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins) - opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help install link ls ls-remote uninstall update help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help) - opts="install link ls ls-remote uninstall update help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help__install) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help__link) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help__ls) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help__ls__remote) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help__uninstall) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__help__update) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__install) - opts="-f -a -v -j -r -y -h --force --all --verbose --jobs --debug --log-level --trace --raw --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__link) - opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help [PATH]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__ls) - opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__ls__remote) - opts="-u -j -r -v -y -h --urls --only-names --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__uninstall) - opts="-p -a -j -r -v -y -h --purge --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__plugins__update) - opts="-a -j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__prune) - opts="-n -j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__render__completion) - opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash elvish fish powershell zsh" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --shell) - COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__render__help) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__render__mangen) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__reshim) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN] [VERSION]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__self__update) - opts="-f -y -j -r -v -h --force --no-plugins --yes --jobs --debug --log-level --trace --raw --verbose --help [VERSION]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__get) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__help) - opts="get ls set unset help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__help__get) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__help__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__help__ls) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__help__set) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__help__unset) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__ls) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__set) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__settings__unset) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__shell) - opts="-u -j -r -v -y -h --unset --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__sync) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help node python help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__sync__help) - opts="node python help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__sync__help__help) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__sync__help__node) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__sync__help__python) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__sync__node) - opts="-j -r -v -y -h --brew --nvm --nodenv --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__sync__python) - opts="-j -r -v -y -h --pyenv --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__trust) - opts="-j -r -v -y -h --untrust --jobs --debug --log-level --trace --raw --verbose --yes --help [CONFIG_FILE]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__uninstall) - opts="-a -n -j -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help ..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__upgrade) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__use) - opts="-g -e -p -j -r -v -y -h --pin --fuzzy --remove --global --env --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --remove) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --env) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -e) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --path) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -p) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__version) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__where) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - rtx__which) - opts="-t -j -r -v -y -h --plugin --version --tool --jobs --debug --log-level --trace --raw --verbose --yes --help " - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --tool) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -t) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; - esac -} - -complete -F _rtx -o nosort -o bashdefault -o default rtx diff --git a/default.nix b/default.nix index b5f551934..5797f4c83 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.8"; + version = "2023.12.9"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 663bab368..78f22a944 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.8 +Version: 2023.12.9 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 8a615d31780d5edf83f3f95fa6f96da8f1eaf129 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 5 Dec 2023 23:15:52 -0600 Subject: [PATCH 1185/1891] config: small refactor to remove usage of mut --- src/config/config_file/rtx_toml.rs | 46 +++++++++++++++++------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 90a9875d7..e8862669f 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -1,6 +1,8 @@ +use std::cell::RefCell; use std::collections::HashMap; use std::fmt::{Debug, Display, Formatter}; use std::path::{Path, PathBuf}; +use std::sync::Mutex; use std::time::Duration; use color_eyre::eyre::eyre; @@ -36,7 +38,7 @@ pub struct RtxToml { alias: AliasMap, doc: Document, plugins: HashMap, - is_trusted: bool, + is_trusted: Mutex>, } impl RtxToml { @@ -46,7 +48,7 @@ impl RtxToml { Self { path: path.to_path_buf(), context, - is_trusted, + is_trusted: Mutex::new(RefCell::new(is_trusted)), toolset: Toolset { source: Some(ToolSource::RtxToml(path.to_path_buf())), ..Default::default() @@ -137,7 +139,7 @@ impl RtxToml { Ok(()) } - fn parse_path_env(&mut self, k: &str, v: &Item) -> Result> { + fn parse_path_env(&self, k: &str, v: &Item) -> Result> { self.trust_check()?; match v.as_array() { Some(array) => { @@ -165,7 +167,7 @@ impl RtxToml { } } - fn parse_alias(&mut self, k: &str, v: &Item) -> Result { + fn parse_alias(&self, k: &str, v: &Item) -> Result { match v.as_table_like() { Some(table) => { let mut aliases = AliasMap::new(); @@ -194,12 +196,12 @@ impl RtxToml { } } - fn parse_plugins(&mut self, key: &str, v: &Item) -> Result> { + fn parse_plugins(&self, key: &str, v: &Item) -> Result> { self.trust_check()?; self.parse_hashmap(key, v) } - fn parse_hashmap(&mut self, key: &str, v: &Item) -> Result> { + fn parse_hashmap(&self, key: &str, v: &Item) -> Result> { match v.as_table_like() { Some(table) => { let mut env = HashMap::new(); @@ -219,7 +221,7 @@ impl RtxToml { } } - fn parse_toolset(&mut self, key: &str, v: &Item) -> Result { + fn parse_toolset(&self, key: &str, v: &Item) -> Result { let mut toolset = Toolset::new(self.toolset.source.clone().unwrap()); match v.as_table_like() { @@ -237,7 +239,7 @@ impl RtxToml { } fn parse_tool_version_list( - &mut self, + &self, key: &str, v: &Item, plugin_name: &PluginName, @@ -284,7 +286,7 @@ impl RtxToml { } fn parse_tool_version( - &mut self, + &self, key: &str, v: &Item, plugin_name: &PluginName, @@ -354,7 +356,7 @@ impl RtxToml { } fn parse_tool_version_request( - &mut self, + &self, key: &str, v: &Value, plugin_name: &PluginName, @@ -368,7 +370,7 @@ impl RtxToml { } } - fn parse_settings(&mut self, key: &str, v: &Item) -> Result { + fn parse_settings(&self, key: &str, v: &Item) -> Result { let mut settings = SettingsBuilder::default(); match v.as_table_like() { @@ -456,7 +458,7 @@ impl RtxToml { } } - fn parse_duration_minutes(&mut self, k: &str, v: &Item) -> Result { + fn parse_duration_minutes(&self, k: &str, v: &Item) -> Result { match v.as_value() { Some(Value::String(s)) => Ok(humantime::parse_duration(s.value())?), Some(Value::Integer(i)) => Ok(Duration::from_secs(*i.value() as u64 * 60)), @@ -464,21 +466,21 @@ impl RtxToml { } } - fn parse_bool(&mut self, k: &str, v: &Item) -> Result { + fn parse_bool(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_bool()) { Some(Some(v)) => Ok(v), _ => parse_error!(k, v, "boolean")?, } } - fn parse_usize(&mut self, k: &str, v: &Item) -> Result { + fn parse_usize(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_integer()) { Some(Some(v)) => Ok(v as usize), _ => parse_error!(k, v, "usize")?, } } - fn parse_path(&mut self, k: &str, v: &Item) -> Result { + fn parse_path(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => { let v = self.parse_template(k, v)?; @@ -488,7 +490,7 @@ impl RtxToml { } } - fn parse_paths(&mut self, k: &str, v: &Item) -> Result> { + fn parse_paths(&self, k: &str, v: &Item) -> Result> { match v.as_value().map(|v| v.as_array()) { Some(Some(v)) => { let mut paths = vec![]; @@ -585,7 +587,7 @@ impl RtxToml { env_tbl.remove(key); } - fn parse_template(&mut self, k: &str, input: &str) -> Result { + fn parse_template(&self, k: &str, input: &str) -> Result { if !input.contains("{{") && !input.contains("{%") && !input.contains("{#") { return Ok(input.to_string()); } @@ -597,10 +599,10 @@ impl RtxToml { Ok(output) } - fn trust_check(&mut self) -> Result<()> { + fn trust_check(&self) -> Result<()> { let default_cmd = String::new(); let cmd = env::ARGS.get(1).unwrap_or(&default_cmd).as_str(); - if self.is_trusted || cmd == "trust" || cmd == "completion" || cfg!(test) { + if self.get_is_trusted() || cmd == "trust" || cmd == "completion" || cfg!(test) { return Ok(()); } if cmd != "hook-env" { @@ -611,12 +613,16 @@ impl RtxToml { ))?; if ans { config_file::trust(self.path.as_path())?; - self.is_trusted = true; + self.is_trusted.lock().unwrap().replace(true); return Ok(()); } } Err(UntrustedConfig())? } + + fn get_is_trusted(&self) -> bool { + *self.is_trusted.lock().unwrap().borrow() + } } impl Display for RtxToml { From 060d53c6eee89ef7aba2f7ba27257c8e1d1429da Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 00:43:37 -0600 Subject: [PATCH 1186/1891] completions: fixed bash --- completions/rtx.bash | 3586 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3586 insertions(+) diff --git a/completions/rtx.bash b/completions/rtx.bash index e69de29bb..a6f428945 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -0,0 +1,3586 @@ +_rtx() { + local i cur prev opts cmd + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="" + opts="" + + for i in ${COMP_WORDS[@]} + do + case "${cmd},${i}" in + ",$1") + cmd="rtx" + ;; + rtx,a) + cmd="rtx__alias" + ;; + rtx,activate) + cmd="rtx__activate" + ;; + rtx,alias) + cmd="rtx__alias" + ;; + rtx,asdf) + cmd="rtx__asdf" + ;; + rtx,bin-paths) + cmd="rtx__bin__paths" + ;; + rtx,cache) + cmd="rtx__cache" + ;; + rtx,completion) + cmd="rtx__completion" + ;; + rtx,current) + cmd="rtx__current" + ;; + rtx,deactivate) + cmd="rtx__deactivate" + ;; + rtx,direnv) + cmd="rtx__direnv" + ;; + rtx,doctor) + cmd="rtx__doctor" + ;; + rtx,e) + cmd="rtx__env" + ;; + rtx,env) + cmd="rtx__env" + ;; + rtx,env-vars) + cmd="rtx__env__vars" + ;; + rtx,exec) + cmd="rtx__exec" + ;; + rtx,global) + cmd="rtx__global" + ;; + rtx,help) + cmd="rtx__help" + ;; + rtx,hook-env) + cmd="rtx__hook__env" + ;; + rtx,i) + cmd="rtx__install" + ;; + rtx,implode) + cmd="rtx__implode" + ;; + rtx,install) + cmd="rtx__install" + ;; + rtx,latest) + cmd="rtx__latest" + ;; + rtx,link) + cmd="rtx__link" + ;; + rtx,list) + cmd="rtx__ls" + ;; + rtx,local) + cmd="rtx__local" + ;; + rtx,ls) + cmd="rtx__ls" + ;; + rtx,ls-remote) + cmd="rtx__ls__remote" + ;; + rtx,outdated) + cmd="rtx__outdated" + ;; + rtx,p) + cmd="rtx__plugins" + ;; + rtx,plugins) + cmd="rtx__plugins" + ;; + rtx,prune) + cmd="rtx__prune" + ;; + rtx,render-completion) + cmd="rtx__render__completion" + ;; + rtx,render-help) + cmd="rtx__render__help" + ;; + rtx,render-mangen) + cmd="rtx__render__mangen" + ;; + rtx,reshim) + cmd="rtx__reshim" + ;; + rtx,self-update) + cmd="rtx__self__update" + ;; + rtx,settings) + cmd="rtx__settings" + ;; + rtx,shell) + cmd="rtx__shell" + ;; + rtx,sync) + cmd="rtx__sync" + ;; + rtx,trust) + cmd="rtx__trust" + ;; + rtx,u) + cmd="rtx__use" + ;; + rtx,uninstall) + cmd="rtx__uninstall" + ;; + rtx,upgrade) + cmd="rtx__upgrade" + ;; + rtx,use) + cmd="rtx__use" + ;; + rtx,version) + cmd="rtx__version" + ;; + rtx,where) + cmd="rtx__where" + ;; + rtx,which) + cmd="rtx__which" + ;; + rtx,x) + cmd="rtx__exec" + ;; + rtx__alias,add) + cmd="rtx__alias__set" + ;; + rtx__alias,create) + cmd="rtx__alias__set" + ;; + rtx__alias,del) + cmd="rtx__alias__unset" + ;; + rtx__alias,delete) + cmd="rtx__alias__unset" + ;; + rtx__alias,get) + cmd="rtx__alias__get" + ;; + rtx__alias,help) + cmd="rtx__alias__help" + ;; + rtx__alias,list) + cmd="rtx__alias__ls" + ;; + rtx__alias,ls) + cmd="rtx__alias__ls" + ;; + rtx__alias,remove) + cmd="rtx__alias__unset" + ;; + rtx__alias,rm) + cmd="rtx__alias__unset" + ;; + rtx__alias,set) + cmd="rtx__alias__set" + ;; + rtx__alias,unset) + cmd="rtx__alias__unset" + ;; + rtx__alias__help,get) + cmd="rtx__alias__help__get" + ;; + rtx__alias__help,help) + cmd="rtx__alias__help__help" + ;; + rtx__alias__help,ls) + cmd="rtx__alias__help__ls" + ;; + rtx__alias__help,set) + cmd="rtx__alias__help__set" + ;; + rtx__alias__help,unset) + cmd="rtx__alias__help__unset" + ;; + rtx__cache,c) + cmd="rtx__cache__clear" + ;; + rtx__cache,clear) + cmd="rtx__cache__clear" + ;; + rtx__cache,help) + cmd="rtx__cache__help" + ;; + rtx__cache__help,clear) + cmd="rtx__cache__help__clear" + ;; + rtx__cache__help,help) + cmd="rtx__cache__help__help" + ;; + rtx__direnv,activate) + cmd="rtx__direnv__activate" + ;; + rtx__direnv,envrc) + cmd="rtx__direnv__envrc" + ;; + rtx__direnv,exec) + cmd="rtx__direnv__exec" + ;; + rtx__direnv,help) + cmd="rtx__direnv__help" + ;; + rtx__direnv__help,activate) + cmd="rtx__direnv__help__activate" + ;; + rtx__direnv__help,envrc) + cmd="rtx__direnv__help__envrc" + ;; + rtx__direnv__help,exec) + cmd="rtx__direnv__help__exec" + ;; + rtx__direnv__help,help) + cmd="rtx__direnv__help__help" + ;; + rtx__help,activate) + cmd="rtx__help__activate" + ;; + rtx__help,alias) + cmd="rtx__help__alias" + ;; + rtx__help,asdf) + cmd="rtx__help__asdf" + ;; + rtx__help,bin-paths) + cmd="rtx__help__bin__paths" + ;; + rtx__help,cache) + cmd="rtx__help__cache" + ;; + rtx__help,completion) + cmd="rtx__help__completion" + ;; + rtx__help,current) + cmd="rtx__help__current" + ;; + rtx__help,deactivate) + cmd="rtx__help__deactivate" + ;; + rtx__help,direnv) + cmd="rtx__help__direnv" + ;; + rtx__help,doctor) + cmd="rtx__help__doctor" + ;; + rtx__help,env) + cmd="rtx__help__env" + ;; + rtx__help,env-vars) + cmd="rtx__help__env__vars" + ;; + rtx__help,exec) + cmd="rtx__help__exec" + ;; + rtx__help,global) + cmd="rtx__help__global" + ;; + rtx__help,help) + cmd="rtx__help__help" + ;; + rtx__help,hook-env) + cmd="rtx__help__hook__env" + ;; + rtx__help,implode) + cmd="rtx__help__implode" + ;; + rtx__help,install) + cmd="rtx__help__install" + ;; + rtx__help,latest) + cmd="rtx__help__latest" + ;; + rtx__help,link) + cmd="rtx__help__link" + ;; + rtx__help,local) + cmd="rtx__help__local" + ;; + rtx__help,ls) + cmd="rtx__help__ls" + ;; + rtx__help,ls-remote) + cmd="rtx__help__ls__remote" + ;; + rtx__help,outdated) + cmd="rtx__help__outdated" + ;; + rtx__help,plugins) + cmd="rtx__help__plugins" + ;; + rtx__help,prune) + cmd="rtx__help__prune" + ;; + rtx__help,render-completion) + cmd="rtx__help__render__completion" + ;; + rtx__help,render-help) + cmd="rtx__help__render__help" + ;; + rtx__help,render-mangen) + cmd="rtx__help__render__mangen" + ;; + rtx__help,reshim) + cmd="rtx__help__reshim" + ;; + rtx__help,self-update) + cmd="rtx__help__self__update" + ;; + rtx__help,settings) + cmd="rtx__help__settings" + ;; + rtx__help,shell) + cmd="rtx__help__shell" + ;; + rtx__help,sync) + cmd="rtx__help__sync" + ;; + rtx__help,trust) + cmd="rtx__help__trust" + ;; + rtx__help,uninstall) + cmd="rtx__help__uninstall" + ;; + rtx__help,upgrade) + cmd="rtx__help__upgrade" + ;; + rtx__help,use) + cmd="rtx__help__use" + ;; + rtx__help,version) + cmd="rtx__help__version" + ;; + rtx__help,where) + cmd="rtx__help__where" + ;; + rtx__help,which) + cmd="rtx__help__which" + ;; + rtx__help__alias,get) + cmd="rtx__help__alias__get" + ;; + rtx__help__alias,ls) + cmd="rtx__help__alias__ls" + ;; + rtx__help__alias,set) + cmd="rtx__help__alias__set" + ;; + rtx__help__alias,unset) + cmd="rtx__help__alias__unset" + ;; + rtx__help__cache,clear) + cmd="rtx__help__cache__clear" + ;; + rtx__help__direnv,activate) + cmd="rtx__help__direnv__activate" + ;; + rtx__help__direnv,envrc) + cmd="rtx__help__direnv__envrc" + ;; + rtx__help__direnv,exec) + cmd="rtx__help__direnv__exec" + ;; + rtx__help__plugins,install) + cmd="rtx__help__plugins__install" + ;; + rtx__help__plugins,link) + cmd="rtx__help__plugins__link" + ;; + rtx__help__plugins,ls) + cmd="rtx__help__plugins__ls" + ;; + rtx__help__plugins,ls-remote) + cmd="rtx__help__plugins__ls__remote" + ;; + rtx__help__plugins,uninstall) + cmd="rtx__help__plugins__uninstall" + ;; + rtx__help__plugins,update) + cmd="rtx__help__plugins__update" + ;; + rtx__help__settings,get) + cmd="rtx__help__settings__get" + ;; + rtx__help__settings,ls) + cmd="rtx__help__settings__ls" + ;; + rtx__help__settings,set) + cmd="rtx__help__settings__set" + ;; + rtx__help__settings,unset) + cmd="rtx__help__settings__unset" + ;; + rtx__help__sync,node) + cmd="rtx__help__sync__node" + ;; + rtx__help__sync,python) + cmd="rtx__help__sync__python" + ;; + rtx__plugins,a) + cmd="rtx__plugins__install" + ;; + rtx__plugins,help) + cmd="rtx__plugins__help" + ;; + rtx__plugins,i) + cmd="rtx__plugins__install" + ;; + rtx__plugins,install) + cmd="rtx__plugins__install" + ;; + rtx__plugins,link) + cmd="rtx__plugins__link" + ;; + rtx__plugins,list) + cmd="rtx__plugins__ls" + ;; + rtx__plugins,list-remote) + cmd="rtx__plugins__ls__remote" + ;; + rtx__plugins,ls) + cmd="rtx__plugins__ls" + ;; + rtx__plugins,ls-remote) + cmd="rtx__plugins__ls__remote" + ;; + rtx__plugins,uninstall) + cmd="rtx__plugins__uninstall" + ;; + rtx__plugins,update) + cmd="rtx__plugins__update" + ;; + rtx__plugins__help,help) + cmd="rtx__plugins__help__help" + ;; + rtx__plugins__help,install) + cmd="rtx__plugins__help__install" + ;; + rtx__plugins__help,link) + cmd="rtx__plugins__help__link" + ;; + rtx__plugins__help,ls) + cmd="rtx__plugins__help__ls" + ;; + rtx__plugins__help,ls-remote) + cmd="rtx__plugins__help__ls__remote" + ;; + rtx__plugins__help,uninstall) + cmd="rtx__plugins__help__uninstall" + ;; + rtx__plugins__help,update) + cmd="rtx__plugins__help__update" + ;; + rtx__settings,add) + cmd="rtx__settings__set" + ;; + rtx__settings,create) + cmd="rtx__settings__set" + ;; + rtx__settings,del) + cmd="rtx__settings__unset" + ;; + rtx__settings,delete) + cmd="rtx__settings__unset" + ;; + rtx__settings,get) + cmd="rtx__settings__get" + ;; + rtx__settings,help) + cmd="rtx__settings__help" + ;; + rtx__settings,list) + cmd="rtx__settings__ls" + ;; + rtx__settings,ls) + cmd="rtx__settings__ls" + ;; + rtx__settings,remove) + cmd="rtx__settings__unset" + ;; + rtx__settings,rm) + cmd="rtx__settings__unset" + ;; + rtx__settings,set) + cmd="rtx__settings__set" + ;; + rtx__settings,unset) + cmd="rtx__settings__unset" + ;; + rtx__settings__help,get) + cmd="rtx__settings__help__get" + ;; + rtx__settings__help,help) + cmd="rtx__settings__help__help" + ;; + rtx__settings__help,ls) + cmd="rtx__settings__help__ls" + ;; + rtx__settings__help,set) + cmd="rtx__settings__help__set" + ;; + rtx__settings__help,unset) + cmd="rtx__settings__help__unset" + ;; + rtx__sync,help) + cmd="rtx__sync__help" + ;; + rtx__sync,node) + cmd="rtx__sync__node" + ;; + rtx__sync,python) + cmd="rtx__sync__python" + ;; + rtx__sync__help,help) + cmd="rtx__sync__help__help" + ;; + rtx__sync__help,node) + cmd="rtx__sync__help__node" + ;; + rtx__sync__help,python) + cmd="rtx__sync__help__python" + ;; + *) + ;; + esac + done + + case "${cmd}" in + rtx) + opts="-j -r -v -y -h -V --jobs --debug --log-level --trace --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__activate) + opts="-s -q -j -r -v -y -h --shell --status --quiet --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish nu xonsh zsh" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias) + opts="-p -j -r -v -y -h --plugin --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --plugin) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__get) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help) + opts="get ls set unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__help__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__ls) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__set) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__alias__unset) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__asdf) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__bin__paths) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help clear help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__clear) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__help) + opts="clear help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__help__clear) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__cache__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__completion) + opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish zsh" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__current) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__deactivate) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help envrc exec activate help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__activate) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__envrc) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__exec) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help) + opts="envrc exec activate help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__activate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__envrc) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__exec) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__direnv__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__doctor) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__env) + opts="-s -J -j -r -v -y -h --shell --json --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__env__vars) + opts="-j -r -v -y -h --file --remove --jobs --debug --log-level --trace --raw --verbose --yes --help [ENV_VARS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --file) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__exec) + opts="-c -C -j -r -v -y -h --command --cd --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --command) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -c) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__global) + opts="-j -r -v -y -h --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help) + opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__activate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias) + opts="get ls set unset" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__alias__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__asdf) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__bin__paths) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__cache) + opts="clear" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__cache__clear) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__completion) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__current) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__deactivate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv) + opts="envrc exec activate" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv__activate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv__envrc) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__direnv__exec) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__doctor) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__env) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__env__vars) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__exec) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__global) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__hook__env) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__implode) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__install) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__latest) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__link) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__local) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__ls__remote) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__outdated) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins) + opts="install link ls ls-remote uninstall update" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__install) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__link) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__ls__remote) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__uninstall) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__plugins__update) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__prune) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__render__completion) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__render__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__render__mangen) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__reshim) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__self__update) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings) + opts="get ls set unset" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__settings__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__shell) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__sync) + opts="node python" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__sync__node) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__sync__python) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__trust) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__uninstall) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__upgrade) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__use) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__version) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__where) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__which) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__hook__env) + opts="-s -j -r -v -y -h --shell --status --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__implode) + opts="-n -j -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__install) + opts="-f -v -j -r -y -h --force --verbose --jobs --debug --log-level --trace --raw --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__latest) + opts="-i -j -r -v -y -h --installed --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__link) + opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__local) + opts="-p -j -r -v -y -h --parent --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__ls) + opts="-p -c -g -i -J -m -j -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --plugin) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --prefix) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__ls__remote) + opts="-j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION] [PREFIX]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__outdated) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins) + opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help install link ls ls-remote uninstall update help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help) + opts="install link ls ls-remote uninstall update help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__install) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__link) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__ls__remote) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__uninstall) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__help__update) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__install) + opts="-f -a -v -j -r -y -h --force --all --verbose --jobs --debug --log-level --trace --raw --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__link) + opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help [PATH]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__ls) + opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__ls__remote) + opts="-u -j -r -v -y -h --urls --only-names --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__uninstall) + opts="-p -a -j -r -v -y -h --purge --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__plugins__update) + opts="-a -j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__prune) + opts="-n -j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__render__completion) + opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash elvish fish powershell zsh" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__render__help) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__render__mangen) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__reshim) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN] [VERSION]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__self__update) + opts="-f -y -j -r -v -h --force --no-plugins --yes --jobs --debug --log-level --trace --raw --verbose --help [VERSION]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__get) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help) + opts="get ls set unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__help__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__ls) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__set) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__settings__unset) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__shell) + opts="-u -j -r -v -y -h --unset --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help node python help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__help) + opts="node python help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__help__node) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__help__python) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__node) + opts="-j -r -v -y -h --brew --nvm --nodenv --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__sync__python) + opts="-j -r -v -y -h --pyenv --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__trust) + opts="-j -r -v -y -h --untrust --jobs --debug --log-level --trace --raw --verbose --yes --help [CONFIG_FILE]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__uninstall) + opts="-a -n -j -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help ..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__upgrade) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__use) + opts="-g -e -p -j -r -v -y -h --pin --fuzzy --remove --global --env --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --remove) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --env) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -e) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -p) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__version) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__where) + opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__which) + opts="-t -j -r -v -y -h --plugin --version --tool --jobs --debug --log-level --trace --raw --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --tool) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +complete -F _rtx -o nosort -o bashdefault -o default rtx From 3c960364c2e46303292f6d4bfc9103e1d427a564 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 01:16:31 -0600 Subject: [PATCH 1187/1891] confique: switch .rtx.toml to use SettingsPartial (#1075) --- README.md | 2 +- e2e/run_test | 2 +- justfile | 3 + src/cli/latest.rs | 2 +- src/cli/local.rs | 2 +- src/cli/mod.rs | 4 +- ...cli__settings__ls__tests__settings_ls.snap | 3 +- ...i__settings__set__tests__settings_set.snap | 3 +- src/cli/settings/unset.rs | 2 +- src/cli/version.rs | 2 +- src/config/config_file/legacy_version.rs | 1 - src/config/config_file/mod.rs | 8 +- src/config/config_file/rtx_toml.rs | 137 ++++++------ ...nfig_file__rtx_toml__tests__fixture-2.snap | 16 +- src/config/mod.rs | 13 +- src/config/settings.rs | 202 ++---------------- src/duration.rs | 6 +- src/env.rs | 1 - 18 files changed, 123 insertions(+), 286 deletions(-) diff --git a/README.md b/README.md index eee64913f..763b09292 100644 --- a/README.md +++ b/README.md @@ -937,7 +937,7 @@ installing plugins, e.g.: `rtx plugin install node https://github.com/asdf-vm/as Disables the specified tools. Separate with `,`. Generally used for core plugins but works with all. -#### `RTX_YES=yes` +#### `RTX_YES=1` This will automatically answer yes or no to prompts. This is useful for scripting. diff --git a/e2e/run_test b/e2e/run_test index 70885ce1f..79aec09ae 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -16,7 +16,7 @@ setup_env() { export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" export RTX_TRUSTED_CONFIG_PATHS="$ROOT/e2e" - export RTX_YES="yes" + export RTX_YES="1" unset GOPATH } diff --git a/justfile b/justfile index 25fc069e6..686d088d7 100644 --- a/justfile +++ b/justfile @@ -17,6 +17,9 @@ alias lf := lint-fix build *args: cargo build --all-features {{ args }} +watch: + watchexec -w src -- just build + # run all test types test *args: (test-unit args) test-e2e lint diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 0445cc978..5cde6fbd7 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -107,6 +107,6 @@ mod tests { #[test] fn test_latest_alias() { let stdout = assert_cli!("latest", "tiny@lts"); - assert_str_eq!(stdout, "3.1.0\n"); + assert_str_eq!(stdout, "3.1.0"); } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 0c09713ec..9b15f0821 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -248,7 +248,7 @@ mod tests { run_test(|| { assert_cli!("local", "tiny", "2"); let stdout = assert_cli!("local", "tiny"); - assert_str_eq!(stdout, "2\n"); + assert_str_eq!(stdout, "2"); }); } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 4122a400b..a826672ce 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -283,7 +283,7 @@ pub mod tests { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; - console::strip_ansi_codes(&output).to_string() + console::strip_ansi_codes(output.trim()).to_string() }}; } @@ -292,7 +292,7 @@ pub mod tests { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; - let output = console::strip_ansi_codes(&output).to_string(); + let output = console::strip_ansi_codes(&output.trim()).to_string(); let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); let output = $crate::test::replace_path(&output); insta::assert_snapshot!(output); diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 178a161b4..1f7669196 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -11,8 +11,9 @@ experimental = true jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] -plugin_autoupdate_last_check_duration = 20 +plugin_autoupdate_last_check_duration = 20m raw = false trusted_config_paths = [] verbose = true yes = true + diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 17a79df6f..f838f0a4a 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -11,8 +11,9 @@ experimental = true jobs = 2 legacy_version_file = false legacy_version_file_disable_tools = [] -plugin_autoupdate_last_check_duration = 1 +plugin_autoupdate_last_check_duration = 1m raw = false trusted_config_paths = [] verbose = true yes = true + diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 180922701..99e50c227 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -51,7 +51,7 @@ mod tests { jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] - plugin_autoupdate_last_check_duration = 20 + plugin_autoupdate_last_check_duration = 20m raw = false trusted_config_paths = [] verbose = true diff --git a/src/cli/version.rs b/src/cli/version.rs index 25258a579..a007fa3d4 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -142,6 +142,6 @@ mod tests { #[test] fn test_version() { let stdout = assert_cli!("version"); - assert_str_eq!(stdout, VERSION.to_string() + "\n"); + assert_str_eq!(stdout, VERSION.to_string()); } } diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 524fdb038..758a3e551 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; - use crate::config::Settings; use crate::plugins::PluginName; use crate::tool::Tool; diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 9060fac13..8b1445ca1 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -3,12 +3,13 @@ use std::fmt::{Debug, Display}; use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; +use confique::Partial; use tool_versions::ToolVersions; use crate::cli::args::tool::ToolArg; use crate::config::config_file::rtx_toml::RtxToml; -use crate::config::settings::SettingsBuilder; +use crate::config::settings::SettingsPartial; use crate::config::{global_config_files, AliasMap, Config, Settings}; use crate::file::{display_path, replace_path}; use crate::hash::hash_to_str; @@ -49,8 +50,8 @@ pub trait ConfigFile: Debug + Display + Send + Sync { fn save(&self) -> Result<()>; fn dump(&self) -> String; fn to_toolset(&self) -> &Toolset; - fn settings(&self) -> SettingsBuilder { - Default::default() + fn settings(&self) -> Result { + Ok(SettingsPartial::empty()) } fn aliases(&self) -> AliasMap { Default::default() @@ -58,7 +59,6 @@ pub trait ConfigFile: Debug + Display + Send + Sync { fn watch_files(&self) -> Vec { vec![self.get_path().to_path_buf()] } - fn is_global(&self) -> bool { global_config_files().iter().any(|p| p == self.get_path()) } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index e8862669f..5816707cd 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -3,18 +3,18 @@ use std::collections::HashMap; use std::fmt::{Debug, Display, Formatter}; use std::path::{Path, PathBuf}; use std::sync::Mutex; -use std::time::Duration; use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; +use confique::Partial; use console::style; use eyre::WrapErr; use tera::Context; -use toml_edit::{table, value, Array, Document, Item, Value}; +use toml_edit::{table, value, Array, Document, Item, Table, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::settings::SettingsBuilder; -use crate::config::{config_file, AliasMap}; +use crate::config::settings::SettingsPartial; +use crate::config::{config_file, AliasMap, Settings}; use crate::errors::Error::UntrustedConfig; use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; @@ -34,7 +34,7 @@ pub struct RtxToml { env: HashMap, env_remove: Vec, path_dirs: Vec, - settings: SettingsBuilder, + settings: Table, alias: AliasMap, doc: Document, plugins: HashMap, @@ -370,59 +370,11 @@ impl RtxToml { } } - fn parse_settings(&self, key: &str, v: &Item) -> Result { - let mut settings = SettingsBuilder::default(); - - match v.as_table_like() { - Some(table) => { - for (config_key, v) in table.iter() { - let k = format!("{}.{}", key, config_key); - match config_key.to_lowercase().as_str() { - "experimental" => settings.experimental = Some(self.parse_bool(&k, v)?), - "legacy_version_file" => { - settings.legacy_version_file = Some(self.parse_bool(&k, v)?) - } - "legacy_version_file_disable_tools" => { - settings.legacy_version_file_disable_tools = - self.parse_string_array(&k, v)?.into_iter().collect() - } - "always_keep_download" => { - settings.always_keep_download = Some(self.parse_bool(&k, v)?) - } - "always_keep_install" => { - settings.always_keep_install = Some(self.parse_bool(&k, v)?) - } - "plugin_autoupdate_last_check_duration" => { - settings.plugin_autoupdate_last_check_duration = - Some(self.parse_duration_minutes(&k, v)?) - } - "trusted_config_paths" => { - settings.trusted_config_paths = - self.parse_paths(&k, v)?.into_iter().collect(); - } - "verbose" => settings.verbose = Some(self.parse_bool(&k, v)?), - "asdf_compat" => settings.asdf_compat = Some(self.parse_bool(&k, v)?), - "jobs" => settings.jobs = Some(self.parse_usize(&k, v)?), - "shorthands_file" => { - settings.shorthands_file = Some(self.parse_path(&k, v)?) - } - "disable_default_shorthands" => { - settings.disable_default_shorthands = Some(self.parse_bool(&k, v)?) - } - "disable_tools" => { - settings.disable_tools = - self.parse_string_array(&k, v)?.into_iter().collect() - } - "raw" => settings.raw = Some(self.parse_bool(&k, v)?), - "yes" => settings.yes = Some(self.parse_bool(&k, v)?), - _ => Err(eyre!("Unknown config setting: {}", k))?, - }; - } - } - None => parse_error!("settings", v, "table")?, + fn parse_settings(&self, _k: &str, v: &Item) -> Result
{ + match v.as_table() { + Some(table) => Ok(table.clone()), + None => parse_error!("settings", v, "table"), } - - Ok(settings) } pub fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { @@ -458,14 +410,6 @@ impl RtxToml { } } - fn parse_duration_minutes(&self, k: &str, v: &Item) -> Result { - match v.as_value() { - Some(Value::String(s)) => Ok(humantime::parse_duration(s.value())?), - Some(Value::Integer(i)) => Ok(Duration::from_secs(*i.value() as u64 * 60)), - _ => parse_error!(k, v, "duration")?, - } - } - fn parse_bool(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_bool()) { Some(Some(v)) => Ok(v), @@ -473,6 +417,13 @@ impl RtxToml { } } + fn parse_string(&self, k: &str, v: &Item) -> Result { + match v.as_value().map(|v| v.as_str()) { + Some(Some(v)) => Ok(v.to_string()), + _ => parse_error!(k, v, "string")?, + } + } + fn parse_usize(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_integer()) { Some(Some(v)) => Ok(v as usize), @@ -714,8 +665,46 @@ impl ConfigFile for RtxToml { &self.toolset } - fn settings(&self) -> SettingsBuilder { - self.settings.clone() + fn settings(&self) -> Result { + let mut s = SettingsPartial::empty(); + + for (config_key, v) in self.settings.iter() { + let k = format!("settings.{config_key}"); + match config_key.to_lowercase().as_str() { + "experimental" => s.experimental = Some(self.parse_bool(&k, v)?), + "legacy_version_file" => s.legacy_version_file = Some(self.parse_bool(&k, v)?), + "legacy_version_file_disable_tools" => { + s.legacy_version_file_disable_tools = + Some(self.parse_string_array(&k, v)?.into_iter().collect()) + } + "always_keep_download" => s.always_keep_download = Some(self.parse_bool(&k, v)?), + "always_keep_install" => s.always_keep_install = Some(self.parse_bool(&k, v)?), + "plugin_autoupdate_last_check_duration" => { + s.plugin_autoupdate_last_check_duration = match v.as_integer() { + Some(i) => Some(format!("{}m", i)), + None => Some(self.parse_string(&k, v)?), + } + } + "trusted_config_paths" => { + s.trusted_config_paths = Some(self.parse_paths(&k, v)?.into_iter().collect()); + } + "verbose" => s.verbose = Some(self.parse_bool(&k, v)?), + "asdf_compat" => s.asdf_compat = Some(self.parse_bool(&k, v)?), + "jobs" => s.jobs = Some(self.parse_usize(&k, v)?), + "shorthands_file" => s.shorthands_file = Some(self.parse_path(&k, v)?), + "disable_default_shorthands" => { + s.disable_default_shorthands = Some(self.parse_bool(&k, v)?) + } + "disable_tools" => { + s.disable_tools = Some(self.parse_string_array(&k, v)?.into_iter().collect()); + } + "raw" => s.raw = Some(self.parse_bool(&k, v)?), + "yes" => s.yes = Some(self.parse_bool(&k, v)?), + _ => Err(eyre!("Unknown config setting: {}", k))?, + }; + } + + Ok(s) } fn aliases(&self) -> AliasMap { @@ -735,8 +724,12 @@ impl Debug for RtxToml { let mut d = f.debug_struct("RtxToml"); d.field("path", &self.path) .field("toolset", &self.toolset.to_string()) - .field("is_trusted", &self.is_trusted) - .field("settings", &self.settings); + .field("is_trusted", &self.is_trusted); + if let Ok(partial) = self.settings() { + if let Ok(settings) = Settings::default_builder().preloaded(partial).load() { + d.field("settings", &settings); + } + } if let Some(env_file) = &self.env_file { d.field("env_file", env_file); } @@ -771,9 +764,13 @@ mod tests { #[test] fn test_fixture() { let cf = RtxToml::from_file(&dirs::HOME.join("fixtures/.rtx.toml"), true).unwrap(); + let settings = Settings::default_builder() + .preloaded(cf.settings().unwrap()) + .load() + .unwrap(); assert_debug_snapshot!(cf.env()); - assert_debug_snapshot!(cf.settings()); + assert_debug_snapshot!(settings); assert_debug_snapshot!(cf.plugins()); assert_snapshot!(replace_path(&format!("{:#?}", cf.toolset))); assert_debug_snapshot!(cf.alias); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 8ddeaacaf..475b9c3d1 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -1,13 +1,25 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf.settings() +expression: settings --- -SettingsBuilder { +Settings { + experimental: false, + always_keep_download: false, + always_keep_install: false, + legacy_version_file: true, legacy_version_file_disable_tools: { "disabled_tool_from_legacy_file", }, + plugin_autoupdate_last_check_duration: "7d", + trusted_config_paths: {}, verbose: true, + asdf_compat: false, + jobs: 4, + shorthands_file: None, + disable_default_shorthands: false, disable_tools: { "disabled_tool", }, + raw: false, + yes: true, } diff --git a/src/config/mod.rs b/src/config/mod.rs index bc7729af7..871e52dab 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -16,6 +16,7 @@ pub use settings::Settings; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; + use crate::config::tracking::Tracker; use crate::file::display_path; use crate::plugins::core::{CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; @@ -52,21 +53,23 @@ pub struct Config { impl Config { pub fn load() -> Result { let global_config = load_rtxrc()?; - let mut settings_b = global_config.settings(); - let settings = settings_b.build(); + let settings = Settings::default_builder() + .preloaded(global_config.settings()?) + .load()?; let config_filenames = load_config_filenames(&settings, &BTreeMap::new()); let tools = load_tools(&settings)?; let config_files = load_all_config_files( - &settings_b.build(), + &settings, &config_filenames, &tools, &BTreeMap::new(), ConfigMap::new(), )?; + let mut settings = Settings::default_builder(); for cf in config_files.values() { - settings_b.merge(cf.settings()); + settings = settings.preloaded(cf.settings()?); } - let settings = settings_b.build(); + let settings = settings.load()?; trace!("Settings: {:#?}", settings); let legacy_files = load_legacy_files(&settings, &tools); diff --git a/src/config/settings.rs b/src/config/settings.rs index bbb215d5d..7e61883a0 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,13 +1,13 @@ use confique::env::parse::{list_by_colon, list_by_comma}; use confique::{Builder, Config, Partial}; + use log::LevelFilter; use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; -use std::time::Duration; -use crate::{duration, env}; +use crate::env; #[derive(Config, Debug, Clone)] pub struct Settings { @@ -21,8 +21,8 @@ pub struct Settings { pub legacy_version_file: bool, #[config(env = "RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, - #[config(env = "RTX_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION")] - pub plugin_autoupdate_last_check_duration: Duration, + #[config(env = "RTX_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION", default = "7d")] + pub plugin_autoupdate_last_check_duration: String, #[config(env = "RTX_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] pub trusted_config_paths: BTreeSet, #[config(env = "RTX_VERBOSE", default = false)] @@ -39,6 +39,7 @@ pub struct Settings { pub disable_tools: BTreeSet, #[config(env = "RTX_RAW", default = false)] pub raw: bool, + #[config(env = "RTX_YES", default = false)] pub yes: bool, } @@ -51,14 +52,14 @@ impl Default for Settings { } impl Settings { pub fn default_builder() -> Builder { - let mut partial = SettingsPartial::empty(); - partial.plugin_autoupdate_last_check_duration = Some(duration::WEEKLY); - partial.yes = Some(*env::RTX_YES); + let mut p = SettingsPartial::empty(); + if *env::CI { + p.yes = Some(true); + } if *env::RTX_LOG_LEVEL < LevelFilter::Info { - partial.verbose = Some(true); + p.verbose = Some(true); } - - Settings::builder().preloaded(partial).env() + Self::builder().preloaded(p).env() } pub fn to_index_map(&self) -> BTreeMap { @@ -87,7 +88,7 @@ impl Settings { ); map.insert( "plugin_autoupdate_last_check_duration".to_string(), - (self.plugin_autoupdate_last_check_duration.as_secs() / 60).to_string(), + self.plugin_autoupdate_last_check_duration.to_string(), ); map.insert( "trusted_config_paths".to_string(), @@ -116,173 +117,12 @@ impl Settings { } } -#[derive(Default, Clone)] -pub struct SettingsBuilder { - pub experimental: Option, - pub always_keep_download: Option, - pub always_keep_install: Option, - pub legacy_version_file: Option, - pub legacy_version_file_disable_tools: BTreeSet, - pub plugin_autoupdate_last_check_duration: Option, - pub trusted_config_paths: BTreeSet, - pub verbose: Option, - pub asdf_compat: Option, - pub jobs: Option, - pub shorthands_file: Option, - pub disable_default_shorthands: Option, - pub disable_tools: BTreeSet, - pub raw: Option, - pub yes: Option, -} - -impl SettingsBuilder { - pub fn merge(&mut self, other: Self) -> &mut Self { - if other.experimental.is_some() { - self.experimental = other.experimental; - } - if other.always_keep_download.is_some() { - self.always_keep_download = other.always_keep_download; - } - if other.always_keep_install.is_some() { - self.always_keep_install = other.always_keep_install; - } - if other.legacy_version_file.is_some() { - self.legacy_version_file = other.legacy_version_file; - } - self.legacy_version_file_disable_tools - .extend(other.legacy_version_file_disable_tools); - if other.plugin_autoupdate_last_check_duration.is_some() { - self.plugin_autoupdate_last_check_duration = - other.plugin_autoupdate_last_check_duration; - } - self.trusted_config_paths.extend(other.trusted_config_paths); - if other.verbose.is_some() { - self.verbose = other.verbose; - } - if other.asdf_compat.is_some() { - self.asdf_compat = other.asdf_compat; - } - if other.jobs.is_some() { - self.jobs = other.jobs; - } - if other.shorthands_file.is_some() { - self.shorthands_file = other.shorthands_file; - } - if other.disable_default_shorthands.is_some() { - self.disable_default_shorthands = other.disable_default_shorthands; - } - self.disable_tools.extend(other.disable_tools); - if other.raw.is_some() { - self.raw = other.raw; - } - if other.yes.is_some() { - self.yes = other.yes; - } - self - } - - pub fn build(&self) -> Settings { - let mut settings = Settings::default(); - settings.experimental = self.experimental.unwrap_or(settings.experimental); - settings.always_keep_download = self - .always_keep_download - .unwrap_or(settings.always_keep_download); - settings.always_keep_install = self - .always_keep_install - .unwrap_or(settings.always_keep_install); - settings.legacy_version_file = self - .legacy_version_file - .unwrap_or(settings.legacy_version_file); - settings - .legacy_version_file_disable_tools - .extend(self.legacy_version_file_disable_tools.clone()); - settings.plugin_autoupdate_last_check_duration = self - .plugin_autoupdate_last_check_duration - .unwrap_or(settings.plugin_autoupdate_last_check_duration); - settings - .trusted_config_paths - .extend(self.trusted_config_paths.clone()); - settings.verbose = self.verbose.unwrap_or(settings.verbose); - settings.asdf_compat = self.asdf_compat.unwrap_or(settings.asdf_compat); - settings.jobs = self.jobs.unwrap_or(settings.jobs); - settings.shorthands_file = self.shorthands_file.clone().or(settings.shorthands_file); - settings.disable_default_shorthands = self - .disable_default_shorthands - .unwrap_or(settings.disable_default_shorthands); - settings.disable_tools.extend(self.disable_tools.clone()); - settings.raw = self.raw.unwrap_or(settings.raw); - settings.yes = self.yes.unwrap_or(settings.yes); - - if settings.raw { - settings.verbose = true; - settings.jobs = 1; - } - - settings - } -} - impl Display for Settings { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.to_index_map().fmt(f) } } -impl Debug for SettingsBuilder { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut d = f.debug_struct("SettingsBuilder"); - if let Some(experimental) = self.experimental { - d.field("experimental", &experimental); - } - if let Some(always_keep_download) = self.always_keep_download { - d.field("always_keep_download", &always_keep_download); - } - if let Some(always_keep_install) = self.always_keep_install { - d.field("always_keep_install", &always_keep_install); - } - if let Some(legacy_version_file) = self.legacy_version_file { - d.field("legacy_version_file", &legacy_version_file); - } - if !self.legacy_version_file_disable_tools.is_empty() { - d.field( - "legacy_version_file_disable_tools", - &self.legacy_version_file_disable_tools, - ); - } - if let Some(c) = self.plugin_autoupdate_last_check_duration { - d.field("plugin_autoupdate_last_check_duration", &c); - } - if !self.trusted_config_paths.is_empty() { - d.field("trusted_config_paths", &self.trusted_config_paths); - } - if let Some(verbose) = self.verbose { - d.field("verbose", &verbose); - } - if let Some(asdf_compat) = self.asdf_compat { - d.field("asdf_compat", &asdf_compat); - } - if let Some(jobs) = self.jobs { - d.field("jobs", &jobs); - } - if let Some(shorthands_file) = &self.shorthands_file { - d.field("shorthands_file", &shorthands_file); - } - if let Some(dds) = self.disable_default_shorthands { - d.field("disable_default_shorthands", &dds); - } - if !self.disable_tools.is_empty() { - d.field("disable_tools", &self.disable_tools); - } - if let Some(raw) = self.raw { - d.field("raw", &raw); - } - if let Some(yes) = self.yes { - d.field("yes", &yes); - } - d.finish() - } -} - #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum MissingRuntimeBehavior { @@ -302,21 +142,3 @@ impl Display for MissingRuntimeBehavior { } } } - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_settings_merge() { - let mut s1 = SettingsBuilder::default(); - let s2 = SettingsBuilder { - asdf_compat: Some(true), - ..SettingsBuilder::default() - }; - s1.merge(s2); - - assert_eq!(s1.asdf_compat, Some(true)); - } -} diff --git a/src/duration.rs b/src/duration.rs index 6dcbef530..f80fa902c 100644 --- a/src/duration.rs +++ b/src/duration.rs @@ -1,5 +1,5 @@ pub use std::time::Duration; -pub(crate) const HOURLY: Duration = Duration::from_secs(60 * 60); -pub(crate) const DAILY: Duration = Duration::from_secs(60 * 60 * 24); -pub(crate) const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); +pub const HOURLY: Duration = Duration::from_secs(60 * 60); +pub const DAILY: Duration = Duration::from_secs(60 * 60 * 24); +//pub const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); diff --git a/src/env.rs b/src/env.rs index 10d121756..95880ac2f 100644 --- a/src/env.rs +++ b/src/env.rs @@ -77,7 +77,6 @@ pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH" None => vec![], }); pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); -pub static RTX_YES: Lazy = Lazy::new(|| *CI || var_is_true("RTX_YES")); pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| match var_option_bool("RTX_ALL_COMPILE") { Some(v) => v, None => matches!( From 5af7847cee1f9c9cec09405b3dff8a0c3c798b2d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 01:17:15 -0600 Subject: [PATCH 1188/1891] test: make snapshots use consistent whitespace --- .../snapshots/rtx__cli__alias__set__tests__alias_set.snap | 1 - .../rtx__cli__alias__unset__tests__alias_unset.snap | 1 - src/cli/latest.rs | 2 +- src/cli/local.rs | 2 +- src/cli/mod.rs | 2 +- .../rtx__cli__plugins__link__tests__plugin_link.snap | 1 - .../rtx__cli__plugins__ls__tests__plugin_list.snap | 1 - src/cli/settings/ls.rs | 7 ++----- src/cli/settings/set.rs | 7 ++----- .../rtx__cli__settings__ls__tests__settings_ls.snap | 3 +-- .../rtx__cli__settings__set__tests__settings_set.snap | 3 +-- .../snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap | 1 - .../snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap | 1 - .../snapshots/rtx__cli__bin_paths__tests__bin_paths.snap | 1 - src/cli/snapshots/rtx__cli__current__tests__current.snap | 1 - .../rtx__cli__current__tests__current_missing.snap | 1 - .../rtx__cli__current__tests__current_with_runtimes.snap | 1 - .../rtx__cli__deactivate__tests__deactivate-2.snap | 1 - src/cli/snapshots/rtx__cli__env__tests__env_json.snap | 1 - .../snapshots/rtx__cli__env_vars__tests__env_vars-2.snap | 2 +- src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap | 2 +- .../rtx__cli__env_vars__tests__env_vars_remove-2.snap | 3 ++- .../rtx__cli__env_vars__tests__env_vars_remove.snap | 2 +- .../rtx__cli__env_vars__tests__show_env_vars.snap | 1 - src/cli/snapshots/rtx__cli__global__tests__global-2.snap | 1 - src/cli/snapshots/rtx__cli__global__tests__global-3.snap | 1 - src/cli/snapshots/rtx__cli__global__tests__global-4.snap | 1 - src/cli/snapshots/rtx__cli__global__tests__global-5.snap | 1 - src/cli/snapshots/rtx__cli__global__tests__global-6.snap | 1 - src/cli/snapshots/rtx__cli__global__tests__global.snap | 1 - .../rtx__cli__install__tests__install_with_alias.snap | 1 - src/cli/snapshots/rtx__cli__latest__tests__latest.snap | 1 - .../rtx__cli__latest__tests__latest_asdf_format.snap | 1 - .../rtx__cli__latest__tests__latest_installed.snap | 1 - src/cli/snapshots/rtx__cli__link__tests__link.snap | 1 - .../rtx__cli__local__tests__local_alias_prefix.snap | 1 - .../snapshots/rtx__cli__local__tests__local_alias_ref.snap | 1 - .../rtx__cli__local__tests__local_alias_system.snap | 1 - .../rtx__cli__local__tests__local_multiple_versions-2.snap | 1 - .../rtx__cli__local__tests__local_multiple_versions-3.snap | 1 - .../rtx__cli__local__tests__local_multiple_versions.snap | 1 - .../snapshots/rtx__cli__local__tests__local_remove-2.snap | 1 - .../snapshots/rtx__cli__local__tests__local_remove-3.snap | 1 - .../snapshots/rtx__cli__local__tests__local_remove.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap | 1 - src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap | 1 - .../snapshots/rtx__cli__ls_remote__tests__list_remote.snap | 1 - .../rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap | 1 - .../rtx__cli__ls_remote__tests__ls_remote_prefix.snap | 1 - src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap | 1 - src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap | 1 - src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap | 1 - src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap | 3 +-- src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap | 1 - .../rtx__cli__r#use__tests__use_local_tool_versions.snap | 1 - .../rtx__cli__r#where__tests__where_asdf_style-2.snap | 1 - .../rtx__cli__r#where__tests__where_asdf_style.snap | 1 - src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap | 2 -- src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap | 1 - src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap | 1 - src/cli/snapshots/rtx__cli__trust__tests__trust.snap | 1 - src/cli/snapshots/rtx__cli__which__tests__which.snap | 1 - .../snapshots/rtx__cli__which__tests__which_plugin.snap | 1 - src/cli/snapshots/rtx__cli__which__tests__which_tool.snap | 1 - .../snapshots/rtx__cli__which__tests__which_version.snap | 1 - src/cli/version.rs | 2 +- ...nfig__config_file__rtx_toml__tests__remove_alias-2.snap | 1 + ...__config_file__rtx_toml__tests__replace_versions-2.snap | 1 + ..._config__config_file__rtx_toml__tests__set_alias-2.snap | 1 + 78 files changed, 19 insertions(+), 87 deletions(-) diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap index 4acb1387a..cc52c9de7 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap @@ -16,4 +16,3 @@ node lts-iron 20 tiny lts 3.1.0 tiny lts-prev 2.0.0 tiny my/alias 3.0 - diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap index 96a73620d..042be8bcc 100644 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap @@ -15,4 +15,3 @@ node lts-hydrogen 18 node lts-iron 20 tiny lts 3.1.0 tiny lts-prev 2.0.0 - diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 5cde6fbd7..0445cc978 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -107,6 +107,6 @@ mod tests { #[test] fn test_latest_alias() { let stdout = assert_cli!("latest", "tiny@lts"); - assert_str_eq!(stdout, "3.1.0"); + assert_str_eq!(stdout, "3.1.0\n"); } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 9b15f0821..0c09713ec 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -248,7 +248,7 @@ mod tests { run_test(|| { assert_cli!("local", "tiny", "2"); let stdout = assert_cli!("local", "tiny"); - assert_str_eq!(stdout, "2"); + assert_str_eq!(stdout, "2\n"); }); } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index a826672ce..22b991c74 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -283,7 +283,7 @@ pub mod tests { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; - console::strip_ansi_codes(output.trim()).to_string() + console::strip_ansi_codes(&output).to_string() }}; } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap index 5d2904f71..6b2857c95 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap @@ -5,4 +5,3 @@ expression: output dummy tiny tiny-link - diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap index 388fca08c..751d679e5 100644 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap @@ -4,4 +4,3 @@ expression: output --- dummy tiny - diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 195200f06..5526797f7 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -31,15 +31,12 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::assert_snapshot; - - use crate::assert_cli; + use crate::assert_cli_snapshot; use crate::test::reset_config; #[test] fn test_settings_ls() { reset_config(); - let stdout = assert_cli!("settings"); - assert_snapshot!(stdout); + assert_cli_snapshot!("settings"); } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index a155b3283..b567db0b5 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -62,10 +62,8 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] pub mod tests { - use insta::assert_snapshot; - - use crate::assert_cli; use crate::test::reset_config; + use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_settings_set() { @@ -79,8 +77,7 @@ pub mod tests { "1" ); - let stdout = assert_cli!("settings"); - assert_snapshot!(stdout); + assert_cli_snapshot!("settings"); reset_config(); } } diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 1f7669196..962bc8838 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -1,6 +1,6 @@ --- source: src/cli/settings/ls.rs -expression: stdout +expression: output --- always_keep_download = true always_keep_install = true @@ -16,4 +16,3 @@ raw = false trusted_config_paths = [] verbose = true yes = true - diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index f838f0a4a..e963eca42 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -1,6 +1,6 @@ --- source: src/cli/settings/set.rs -expression: stdout +expression: output --- always_keep_download = true always_keep_install = true @@ -16,4 +16,3 @@ raw = false trusted_config_paths = [] verbose = true yes = true - diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap index 75e9cc723..1ed9713ad 100644 --- a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap @@ -5,4 +5,3 @@ expression: output 1.0.1 2.1.0 3.1.0 - diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap index 3985be099..b324caf70 100644 --- a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap @@ -3,4 +3,3 @@ source: src/cli/asdf.rs expression: output --- 3.1.0 - diff --git a/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap b/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap index 13b480c7c..f823b231b 100644 --- a/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap +++ b/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap @@ -4,4 +4,3 @@ expression: output --- ~/data/installs/tiny/3.1.0/bin ~/data/installs/dummy/ref-master/bin - diff --git a/src/cli/snapshots/rtx__cli__current__tests__current.snap b/src/cli/snapshots/rtx__cli__current__tests__current.snap index 69c3025d5..a43a96d94 100644 --- a/src/cli/snapshots/rtx__cli__current__tests__current.snap +++ b/src/cli/snapshots/rtx__cli__current__tests__current.snap @@ -4,4 +4,3 @@ expression: output --- tiny 3.1.0 dummy ref:master - diff --git a/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap b/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap index 80d44c39f..00adbfcec 100644 --- a/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap +++ b/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap @@ -4,4 +4,3 @@ expression: output --- dummy 1.1.0 tiny 3.1.0 - diff --git a/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap b/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap index af8af8fe4..c26b4a741 100644 --- a/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap +++ b/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap @@ -3,4 +3,3 @@ source: src/cli/current.rs expression: output --- 3.1.0 - diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap index 7739ccdb1..040c3aa10 100644 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap +++ b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap @@ -8,4 +8,3 @@ chpwd_functions=( ${chpwd_functions:#_rtx_hook} ) unset -f _rtx_hook unset -f rtx unset RTX_SHELL - diff --git a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap index bcf8b91b8..f3114eada 100644 --- a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap +++ b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap @@ -7,4 +7,3 @@ expression: output "PATH": "~/data/installs/tiny/3.1.0/bin:~/data/installs/dummy/ref-master/bin:$PATH", "TEST_ENV_VAR": "test-123" } - diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap index 507049870..e712390a1 100644 --- a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap @@ -1,6 +1,6 @@ --- source: src/cli/env_vars.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(cf_path).unwrap()" --- [env] FOO = "bar" diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap index 507049870..e712390a1 100644 --- a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap @@ -1,6 +1,6 @@ --- source: src/cli/env_vars.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(cf_path).unwrap()" --- [env] FOO = "bar" diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap index 411b4b77f..a76beff3f 100644 --- a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap @@ -1,5 +1,6 @@ --- source: src/cli/env_vars.rs -expression: "file::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(cf_path).unwrap()" --- [env] + diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap index d552ab5ef..a76beff3f 100644 --- a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap @@ -1,6 +1,6 @@ --- source: src/cli/env_vars.rs -expression: "fs::read_to_string(&cf_path).unwrap()" +expression: "file::read_to_string(cf_path).unwrap()" --- [env] diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap b/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap index 5e5bcdece..a067a978b 100644 --- a/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap +++ b/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap @@ -3,4 +3,3 @@ source: src/cli/env_vars.rs expression: output --- TEST_ENV_VAR=test-123 ~/config/config.toml - diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap index faa0fcf50..bbe62066a 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-2.snap @@ -3,4 +3,3 @@ source: src/cli/global.rs expression: output --- rtx ~/.test-tool-versions tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap index f7307196e..131ca2e88 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-3.snap @@ -3,4 +3,3 @@ source: src/cli/global.rs expression: output --- rtx ~/.test-tool-versions tiny - diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap index faa0fcf50..bbe62066a 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-4.snap @@ -3,4 +3,3 @@ source: src/cli/global.rs expression: output --- rtx ~/.test-tool-versions tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-5.snap b/src/cli/snapshots/rtx__cli__global__tests__global-5.snap index f498cb9e4..878f100f1 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-5.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-5.snap @@ -3,4 +3,3 @@ source: src/cli/global.rs expression: output --- 2.1.0 - diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-6.snap b/src/cli/snapshots/rtx__cli__global__tests__global-6.snap index f91f9f636..7feec566a 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-6.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global-6.snap @@ -3,4 +3,3 @@ source: src/cli/global.rs expression: output --- ~/.test-tool-versions - diff --git a/src/cli/snapshots/rtx__cli__global__tests__global.snap b/src/cli/snapshots/rtx__cli__global__tests__global.snap index faa0fcf50..bbe62066a 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global.snap +++ b/src/cli/snapshots/rtx__cli__global__tests__global.snap @@ -3,4 +3,3 @@ source: src/cli/global.rs expression: output --- rtx ~/.test-tool-versions tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap b/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap index 86a2ad859..3e1412c8f 100644 --- a/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap +++ b/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap @@ -3,4 +3,3 @@ source: src/cli/install.rs expression: output --- ~/data/installs/tiny/3.0.1 - diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest.snap index b1916b4dd..02f19f164 100644 --- a/src/cli/snapshots/rtx__cli__latest__tests__latest.snap +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest.snap @@ -3,4 +3,3 @@ source: src/cli/latest.rs expression: output --- 1.1.0 - diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap index b1916b4dd..02f19f164 100644 --- a/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap @@ -3,4 +3,3 @@ source: src/cli/latest.rs expression: output --- 1.1.0 - diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap index 30ec5fef9..e97632de7 100644 --- a/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap @@ -3,4 +3,3 @@ source: src/cli/latest.rs expression: output --- 2.0.0 - diff --git a/src/cli/snapshots/rtx__cli__link__tests__link.snap b/src/cli/snapshots/rtx__cli__link__tests__link.snap index 709ba7b0b..ff4c9d311 100644 --- a/src/cli/snapshots/rtx__cli__link__tests__link.snap +++ b/src/cli/snapshots/rtx__cli__link__tests__link.snap @@ -7,4 +7,3 @@ tiny 2.1.0 tiny 3.0.1 tiny 3.1.0 ~/cwd/.test-tool-versions 3 tiny 9.8.7 (symlink) - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap b/src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap index b6210172a..4bb053e50 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- 1.1.0 - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap b/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap index ceae61a97..3a0504c83 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- ref:master - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap b/src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap index fdc036a38..3c068e77a 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- system - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap index deb3edce6..906895a96 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- rtx ~/cwd/.test-tool-versions tiny@2 tiny@1 tiny@3 - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap index e2d22c7ee..64e20d63e 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap @@ -6,4 +6,3 @@ expression: output ~/data/installs/tiny/1.0.1/bin ~/data/installs/tiny/3.1.0/bin ~/data/installs/dummy/ref-master/bin - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap index 3107c39d8..361a4602b 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- ~/cwd/.test-tool-versions - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap index 68b44c45c..6ba0e3d6e 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- rtx ~/cwd/.test-tool-versions tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap index bdf7a29b0..d14062203 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- rtx ~/cwd/.test-tool-versions tiny - diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap index 68b44c45c..6ba0e3d6e 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap @@ -3,4 +3,3 @@ source: src/cli/local.rs expression: output --- rtx ~/cwd/.test-tool-versions tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap index d37d8cb22..1cb3e88d6 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap @@ -5,4 +5,3 @@ expression: output dummy ref:master ~/.test-tool-versions ref:master tiny 2.0.0 tiny 3.1.0 ~/cwd/.test-tool-versions 3 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap index e94646e29..f94499c4e 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap @@ -5,4 +5,3 @@ expression: output dummy ref:master ~/.test-tool-versions ref:master tiny 2.0.0 tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap index 66c0cb095..770850e1b 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap @@ -4,4 +4,3 @@ expression: output --- dummy ref:master ~/.test-tool-versions ref:master tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap index 625cf85e6..b5f49eb5d 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap @@ -4,4 +4,3 @@ expression: output --- dummy ref:master ~/.test-tool-versions ref:master tiny 3.1.0 ~/cwd/.test-tool-versions 3 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap index 625cf85e6..b5f49eb5d 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap @@ -4,4 +4,3 @@ expression: output --- dummy ref:master ~/.test-tool-versions ref:master tiny 3.1.0 ~/cwd/.test-tool-versions 3 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap index 625cf85e6..b5f49eb5d 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap @@ -4,4 +4,3 @@ expression: output --- dummy ref:master ~/.test-tool-versions ref:master tiny 3.1.0 ~/cwd/.test-tool-versions 3 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap index 9370d9faf..ee12692da 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap @@ -13,4 +13,3 @@ expression: output } } ] - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap index 1f463fe1d..52c77f0ad 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap @@ -26,4 +26,3 @@ expression: output } ] } - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap index 014ad6e9e..e748bd94c 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap @@ -3,4 +3,3 @@ source: src/cli/ls.rs expression: output --- 3.1.0 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap index 65e52d29f..60395ba27 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap @@ -4,4 +4,3 @@ expression: output --- dummy ref:master tiny 3.1.0 - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap index b7e229332..7adc26e3b 100644 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap +++ b/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap @@ -3,4 +3,3 @@ source: src/cli/ls.rs expression: output --- tiny 3.1.0 ~/cwd/.test-tool-versions 3 - diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap b/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap index bc50965d1..86bbd390d 100644 --- a/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap +++ b/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap @@ -5,4 +5,3 @@ expression: output 1.0.0 1.1.0 2.0.0 - diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap index 3dfc8868a..620292a24 100644 --- a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap +++ b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap @@ -3,4 +3,3 @@ source: src/cli/ls_remote.rs expression: output --- 2.0.0 - diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap index 1e1f6c111..4275d8fd6 100644 --- a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap +++ b/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap @@ -4,4 +4,3 @@ expression: output --- 1.0.0 1.1.0 - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap index 29dbda768..7d2e376ee 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap @@ -3,4 +3,3 @@ source: src/cli/use.rs expression: output --- rtx ~/config/config.toml tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap index ef0385cfc..852372f08 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap @@ -3,4 +3,3 @@ source: src/cli/use.rs expression: output --- rtx ~/cwd/.test.rtx.toml tiny - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap index c0e3bcfff..fb50bf992 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap @@ -3,4 +3,3 @@ source: src/cli/use.rs expression: output --- rtx ~/cwd/.test.rtx.toml tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap index 29374cd5d..6d0d8c5b9 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap @@ -2,5 +2,4 @@ source: src/cli/use.rs expression: output --- -rtx ~/cwd/.test.rtx.toml - +rtx ~/cwd/.test.rtx.toml diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap index c0e3bcfff..fb50bf992 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap @@ -3,4 +3,3 @@ source: src/cli/use.rs expression: output --- rtx ~/cwd/.test.rtx.toml tiny@2 - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap index b3e5c4b4d..e91afc5c9 100644 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap +++ b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap @@ -3,4 +3,3 @@ source: src/cli/use.rs expression: output --- rtx ~/cwd/.test-tool-versions tiny@3 - diff --git a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap index 2e61ed71a..79cad1e90 100644 --- a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap +++ b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap @@ -3,4 +3,3 @@ source: src/cli/where.rs expression: output --- ~/data/installs/tiny/3.1.0 - diff --git a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap index 6ed345ef8..4ff9ac632 100644 --- a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap +++ b/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap @@ -3,4 +3,3 @@ source: src/cli/where.rs expression: output --- ~/data/installs/tiny/2.1.0 - diff --git a/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap b/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap index 07cec3054..debb0be97 100644 --- a/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap +++ b/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap @@ -3,5 +3,3 @@ source: src/cli/shell.rs expression: output --- export RTX_TINY_VERSION=1.0.1 - - diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap index 25005a3a1..f5ac8a47f 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap @@ -3,4 +3,3 @@ source: src/cli/trust.rs expression: output --- untrusted ~/cwd/.test-tool-versions - diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap index d9c3be1c9..bef9d4076 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap @@ -3,4 +3,3 @@ source: src/cli/trust.rs expression: output --- trusted ~/cwd/.test-tool-versions - diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust.snap index d9c3be1c9..bef9d4076 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust.snap +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust.snap @@ -3,4 +3,3 @@ source: src/cli/trust.rs expression: output --- trusted ~/cwd/.test-tool-versions - diff --git a/src/cli/snapshots/rtx__cli__which__tests__which.snap b/src/cli/snapshots/rtx__cli__which__tests__which.snap index a92a17033..8bcebb8d2 100644 --- a/src/cli/snapshots/rtx__cli__which__tests__which.snap +++ b/src/cli/snapshots/rtx__cli__which__tests__which.snap @@ -3,4 +3,3 @@ source: src/cli/which.rs expression: output --- ~/data/installs/dummy/1.0.0/bin/dummy - diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap b/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap index 6c335017f..cfde89d60 100644 --- a/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap +++ b/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap @@ -3,4 +3,3 @@ source: src/cli/which.rs expression: output --- dummy - diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap b/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap index 9d5e4e14e..b21e95fdd 100644 --- a/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap +++ b/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap @@ -3,4 +3,3 @@ source: src/cli/which.rs expression: output --- ~/data/installs/dummy/1.0.1/bin/dummy - diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_version.snap b/src/cli/snapshots/rtx__cli__which__tests__which_version.snap index 7915230b0..0a896d11f 100644 --- a/src/cli/snapshots/rtx__cli__which__tests__which_version.snap +++ b/src/cli/snapshots/rtx__cli__which__tests__which_version.snap @@ -3,4 +3,3 @@ source: src/cli/which.rs expression: output --- 1.0.0 - diff --git a/src/cli/version.rs b/src/cli/version.rs index a007fa3d4..25258a579 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -142,6 +142,6 @@ mod tests { #[test] fn test_version() { let stdout = assert_cli!("version"); - assert_str_eq!(stdout, VERSION.to_string()); + assert_str_eq!(stdout, VERSION.to_string() + "\n"); } } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap index cb58ec131..abcf56e9b 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap @@ -4,3 +4,4 @@ expression: cf --- [alias.node] 18 = "18.0.0" + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap index 4fbd85b70..c4451e3e5 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap @@ -4,3 +4,4 @@ expression: cf --- [tools] node = ["16.0.1", "18.0.1"] + diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap index ac48a5daa..1489c70df 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap @@ -9,3 +9,4 @@ expression: cf [alias.python] "3.10" = "3.10.0" + From ea40d17c9a906fd3120d7e76790f01ebd36df850 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 01:45:14 -0600 Subject: [PATCH 1189/1891] upgrade: added --dry-run (#1088) --- README.md | 10 +++-- completions/_rtx | 1 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + lefthook.yml | 2 +- .../rtx__cli__upgrade__tests__upgrade-2.snap | 5 +++ .../rtx__cli__upgrade__tests__upgrade.snap | 6 +++ src/cli/upgrade.rs | 42 ++++++++++++++++--- 8 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__upgrade__tests__upgrade-2.snap create mode 100644 src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap diff --git a/README.md b/README.md index 763b09292..7ed1fbe3f 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ v20.0.0 - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall [OPTIONS] ...`](#rtx-uninstall-options-toolversion) - - [`rtx upgrade [TOOL@VERSION]...`](#rtx-upgrade-toolversion) + - [`rtx upgrade [OPTIONS] [TOOL@VERSION]...`](#rtx-upgrade-options-toolversion) - [`rtx use [OPTIONS] [TOOL@VERSION]...`](#rtx-use-options-toolversion) - [`rtx version`](#rtx-version) - [`rtx where `](#rtx-where-toolversion) @@ -2619,18 +2619,22 @@ Examples: $ rtx uninstall --all node@18.0.0 # will uninstall all node versions ``` -### `rtx upgrade [TOOL@VERSION]...` +### `rtx upgrade [OPTIONS] [TOOL@VERSION]...` ``` Upgrades outdated tool versions -Usage: upgrade [TOOL@VERSION]... +Usage: upgrade [OPTIONS] [TOOL@VERSION]... Arguments: [TOOL@VERSION]... Tool(s) to upgrade e.g.: node@20 python@3.10 If not specified, all current tools will be upgraded + +Options: + -n, --dry-run + Just print what would be done, don't actually do it ``` ### `rtx use [OPTIONS] [TOOL@VERSION]...` diff --git a/completions/_rtx b/completions/_rtx index bb6d18671..4a8f0a2ce 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -721,6 +721,7 @@ _rtx() { __rtx_upgrade_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ + '(-n --dry-run)'{-n,--dry-run}'[Just print what would be done, don'\''t actually do it]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index a6f428945..d7b6b53c0 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3423,7 +3423,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-n -j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 0f840c0a6..8152d235e 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -251,6 +251,7 @@ complete -xc rtx -n "$fssf uninstall" -s n -l dry-run -d 'Do not actually delete complete -xc rtx -n "$fssf uninstall" -a "(__rtx_tool_versions)" -d 'Tool(s) to remove' # upgrade +complete -xc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' complete -xc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' # use diff --git a/lefthook.yml b/lefthook.yml index c998f357d..f4a1b4969 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -8,7 +8,7 @@ pre-commit: run: cargo clippy -- -Dwarnings glob: "src/**/*.rs" render: - run: just render-help render-completions render-mangen + run: just render-help render-completions render-mangen && git add README.md completions man glob: "src/**/*.rs" shellcheck: run: shellcheck -x {all_files} && shfmt -d {all_files} diff --git a/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade-2.snap b/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade-2.snap new file mode 100644 index 000000000..23c1cf15c --- /dev/null +++ b/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade-2.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/upgrade.rs +expression: output +--- + diff --git a/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap b/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap new file mode 100644 index 000000000..06099fdf3 --- /dev/null +++ b/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/upgrade.rs +expression: output +--- +Would uninstall tiny tiny@3.0.0 +Would install tiny@3.1.0 diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 0daba806a..bb75342c8 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -22,11 +22,15 @@ pub struct Upgrade { /// e.g.: node@20 python@3.10 /// If not specified, all current tools will be upgraded #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] - pub tool: Vec, + tool: Vec, + + /// Just print what would be done, don't actually do it + #[clap(long, short = 'n', verbatim_doc_comment)] + dry_run: bool, } impl Upgrade { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let mut ts = ToolsetBuilder::new() .with_args(&self.tool) .build(&mut config)?; @@ -41,13 +45,13 @@ impl Upgrade { if outdated.is_empty() { info!("All tools are up to date"); } else { - self.upgrade(&mut config, outdated)?; + self.upgrade(&mut config, outdated, out)?; } Ok(()) } - fn upgrade(&self, config: &mut Config, outdated: OutputVec) -> Result<()> { + fn upgrade(&self, config: &mut Config, outdated: OutputVec, out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; @@ -66,6 +70,15 @@ impl Upgrade { .map(|(tool, tv, _)| (tool, tv)) .collect::>(); + if self.dry_run { + for (tool, tv) in &to_remove { + rtxprintln!(out, "Would uninstall {} {}", tool, tv); + } + for tv in &new_versions { + rtxprintln!(out, "Would install {}", tv); + } + return Ok(()); + } ts.install_versions(config, new_versions, &mpr, false)?; for (tool, tv) in to_remove { let mut pr = mpr.add(); @@ -86,7 +99,7 @@ impl Upgrade { pr: &mut ProgressReport, ) -> Result<()> { tool.decorate_progress_bar(pr, Some(tv)); - match tool.uninstall_version(config, tv, pr, false) { + match tool.uninstall_version(config, tv, pr, self.dry_run) { Ok(_) => { pr.finish(); Ok(()) @@ -100,3 +113,22 @@ impl Upgrade { } type OutputVec = Vec<(Arc, ToolVersion, String)>; + +#[cfg(test)] +pub mod tests { + use crate::test::reset_config; + use crate::{assert_cli_snapshot, dirs, file}; + + #[test] + fn test_upgrade() { + reset_config(); + file::rename( + dirs::INSTALLS.join("tiny").join("3.1.0"), + dirs::INSTALLS.join("tiny").join("3.0.0"), + ) + .unwrap(); + assert_cli_snapshot!("upgrade", "--dry-run"); + assert_cli_snapshot!("upgrade"); + assert!(dirs::INSTALLS.join("tiny").join("3.1.0").exists()); + } +} From 98e504af2672dd4a2dd1ff7e6e257a6da34c9bf4 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:51:23 -0600 Subject: [PATCH 1190/1891] added building docker images for CI (#1089) --- .github/workflows/docker.yml | 63 ++++++++++++++++++++++++ .github/workflows/rtx.yml | 22 ++++++--- packaging/github-actions/Dockerfile | 75 +++++++++++++++++++++++++++++ scripts/build-tarball.sh | 6 +++ scripts/release-npm.sh | 2 + scripts/release.sh | 9 ++-- scripts/render-homebrew.sh | 2 + scripts/render-install.sh | 2 + src/cli/version.rs | 19 +++----- src/file.rs | 7 ++- src/http.rs | 30 ++++++++---- src/plugins/core/bun.rs | 11 ++--- src/plugins/core/deno.rs | 11 ++--- src/plugins/core/python.rs | 4 +- src/plugins/core/ruby.rs | 15 ++---- 15 files changed, 212 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/docker.yml create mode 100644 packaging/github-actions/Dockerfile diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 000000000..7ae2b38fc --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,63 @@ +name: docker + +on: + push: + tags: ["v*"] + branches: ['docker-release'] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + docker: + name: docker-${{ matrix.flavor }} + strategy: + fail-fast: false + matrix: + flavor: + - alpine + - deb + - github-actions + - rpm + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ghcr.io/jdx/rtx:${{ matrix.flavor }} + labels: ${{ steps.meta.outputs.labels }} + file: packaging/${{ matrix.flavor }}/Dockerfile + test: + runs-on: ubuntu-22.04 + container: ghcr.io/jdx/rtx:github-actions + timeout-minutes: 10 + steps: + - run: node -v + - run: cargo -V + - name: Checkout + uses: actions/checkout@v4 + - name: Run cargo nextest + run: cargo nextest run --all-features + env: + RUST_BACKTRACE: "1" diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 0f22f02a1..7da836665 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -16,6 +16,7 @@ env: jobs: unit: runs-on: ubuntu-22.04 + container: ghcr.io/jdx/rtx:github-actions timeout-minutes: 10 steps: - name: Checkout @@ -24,11 +25,11 @@ jobs: uses: Swatinem/rust-cache@v2 with: save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - - uses: taiki-e/install-action@v2 - with: - tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete - - name: Install direnv/shfmt - run: sudo apt-get update; sudo apt-get install direnv shfmt + # - uses: taiki-e/install-action@v2 + # with: + # tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete + # - name: Install direnv/shfmt + # run: sudo apt-get update; sudo apt-get install direnv shfmt - name: Run cargo nextest run: cargo nextest run --all-features env: @@ -40,6 +41,7 @@ jobs: coverage: name: coverage-${{matrix.tranche}} + #container: ghcr.io/jdx/rtx:github-actions runs-on: ubuntu-latest timeout-minutes: 30 strategy: @@ -89,6 +91,8 @@ jobs: target: - aarch64-unknown-linux-gnu - x86_64-unknown-linux-gnu + - arm-unknown-linux-musleabihf + - armv7-unknown-linux-gnueabihf steps: - uses: actions/checkout@v4 - name: Rust Cache @@ -142,6 +146,7 @@ jobs: if-no-files-found: error e2e-linux: runs-on: ubuntu-22.04 + #container: ghcr.io/jdx/rtx:github-actions needs: [build-linux] timeout-minutes: 30 if: github.event_name != 'pull_request' @@ -168,7 +173,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-linux] timeout-minutes: 10 - container: jdxcode/rtx:rpm + container: ghcr.io/jdx/rtx:rpm if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v4 @@ -191,7 +196,7 @@ jobs: if-no-files-found: error deb: runs-on: ubuntu-22.04 - container: jdxcode/rtx:deb + container: ghcr.io/jdx/rtx:deb timeout-minutes: 10 if: github.event_name != 'pull_request' needs: [build-linux] @@ -217,6 +222,7 @@ jobs: release: runs-on: ubuntu-22.04 if: startsWith(github.event.ref, 'refs/tags/v') + #container: ghcr.io/jdx/rtx:github-actions timeout-minutes: 10 permissions: contents: write @@ -305,7 +311,7 @@ jobs: formula: rtx bump-alpine: runs-on: ubuntu-22.04 - container: jdxcode/rtx:alpine + container: ghcr.io/jdx/rtx:alpine timeout-minutes: 30 needs: [release] steps: diff --git a/packaging/github-actions/Dockerfile b/packaging/github-actions/Dockerfile new file mode 100644 index 000000000..acd21c9b6 --- /dev/null +++ b/packaging/github-actions/Dockerfile @@ -0,0 +1,75 @@ +FROM ubuntu +LABEL maintainer="jdx" + +ENV PATH="/root/.cargo/bin:${PATH}" +ENV CARGO_HOME="/root/.cargo" +ENV RUSTUP_HOME="/root/.rustup" +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=Etc/UTC + +RUN apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y \ + autoconf \ + bash \ + build-essential \ + ca-certificates \ + curl \ + direnv \ + fd-find \ + fish \ + git \ + gnupg \ + libbz2-dev \ + libdb-dev \ + libffi-dev \ + libgdbm-dev \ + libgdbm6 \ + libgmp-dev \ + liblzma-dev \ + libncurses5-dev \ + libncursesw5-dev \ + libreadline-dev \ + libreadline6-dev \ + libsqlite3-dev \ + libssl-dev \ + libxml2-dev \ + libxmlsec1-dev \ + libyaml-dev \ + patch \ + pkg-config \ + shellcheck \ + shfmt \ + sudo \ + tk-dev \ + uuid-dev \ + xz-utils \ + zlib1g-dev \ + zsh \ + && ln -s /usr/bin/{fdfind,fd} \ + && mkdir -p /etc/apt/keyrings \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list \ + && apt-get update && apt-get install -y nodejs \ + && node -v \ + && npm i -g markdown-magic \ + && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ + && curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash \ + && rustup install stable && rustup default stable \ + && rustup toolchain install nightly --component llvm-tools-preview \ + && cargo install \ + cargo-msrv \ + && cargo binstall -y \ + cargo-deny \ + cargo-llvm-cov \ + cargo-machete \ + cargo-nextest \ + cross \ + just \ + zipsign \ + && apt-get clean \ + && rustc -vV \ + && cargo -V \ + && node -v \ + && npm -v \ + && just --version diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index d05b7982a..ef7c5d0ab 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -45,6 +45,12 @@ get_arch() { aarch64-*) echo "arm64" ;; + arm-*) + echo "armv6" + ;; + armv7-*) + echo "armv7" + ;; x86_64-*) echo "x64" ;; diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index 849629248..01152814f 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -23,6 +23,8 @@ dist_tag="$(dist_tag_from_version "$RTX_VERSION")" platforms=( linux-x64 linux-arm64 + linux-armv6 + linux-armv7 macos-x64 macos-arm64 ) diff --git a/scripts/release.sh b/scripts/release.sh index 2cf0630e1..c9bbdaa33 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -10,12 +10,11 @@ export RTX_VERSION RELEASE_DIR rm -rf "${RELEASE_DIR:?}/$RTX_VERSION" mkdir -p "$RELEASE_DIR/$RTX_VERSION" -#cp artifacts/tarball-x86_64-pc-windows-gnu/*.zip "$RELEASE_DIR/$RTX_VERSION" -#cp artifacts/tarball-x86_64-pc-windows-gnu/*.zip "$RELEASE_DIR/rtx-latest-windows.zip" - targets=( x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu + arm-unknown-linux-gnueabihf + armv7-unknown-linux-gnueabihf x86_64-apple-darwin aarch64-apple-darwin ) @@ -27,6 +26,8 @@ done platforms=( linux-x64 linux-arm64 + linux-armv6 + linux-armv7 macos-x64 macos-arm64 ) @@ -60,7 +61,7 @@ gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_ NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh -AWS_S3_BUCKET=rtx.pub ./rtx/scripts/publish-s3.sh +#AWS_S3_BUCKET=rtx.pub ./rtx/scripts/publish-s3.sh ./rtx/scripts/publish-r2.sh ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index 11788fb92..c906a41f3 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -5,6 +5,8 @@ set -euxo pipefail RTX_VERSION=${RTX_VERSION#v*} \ RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARMV6=$(grep "rtx-v$RTX_VERSION-linux-armv6.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARMV7=$(grep "rtx-v$RTX_VERSION-linux-armv7.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ diff --git a/scripts/render-install.sh b/scripts/render-install.sh index f41783063..fa3d37564 100755 --- a/scripts/render-install.sh +++ b/scripts/render-install.sh @@ -5,6 +5,8 @@ set -euxo pipefail RTX_VERSION=$RTX_VERSION \ RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v.*linux-x64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v.*linux-arm64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_ARMV6=$(grep "rtx-v.*linux-armv6.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_ARMV7=$(grep "rtx-v.*linux-armv7.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v.*macos-x64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v.*macos-arm64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ diff --git a/src/cli/version.rs b/src/cli/version.rs index 25258a579..d2fcc0414 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -113,22 +113,17 @@ fn get_latest_version_call() -> Option { let timeout = Duration::from_secs(3); const URL: &str = "http://rtx.pub/VERSION"; debug!("checking rtx version from {}", URL); - let client = crate::http::Client::new().ok()?; - match client.get(URL).timeout(timeout).send() { - Ok(res) => { - if res.status().is_success() { - return res.text().ok().map(|text| { - debug!("got version {text}"); - text.trim().to_string() - }); - } - debug!("failed to check for version: {:#?}", res); + let client = crate::http::Client::new_with_timeout(timeout).ok()?; + match client.get_text(URL) { + Ok(text) => { + debug!("got version {text}"); + Some(text.trim().to_string()) } Err(err) => { debug!("failed to check for version: {:#?}", err); + None } - }; - None + } } #[cfg(test)] diff --git a/src/file.rs b/src/file.rs index 2a2e4e565..fa114ebe3 100644 --- a/src/file.rs +++ b/src/file.rs @@ -202,7 +202,8 @@ pub fn is_executable(path: &Path) -> bool { pub fn make_executable(path: &Path) -> Result<()> { let mut perms = path.metadata()?.permissions(); perms.set_mode(perms.mode() | 0o111); - fs::set_permissions(path, perms)?; + fs::set_permissions(path, perms) + .wrap_err_with(|| format!("failed to chmod +x: {}", display_path(path)))?; Ok(()) } @@ -264,7 +265,9 @@ pub fn untar(archive: &Path, dest: &Path) -> Result<()> { } pub fn unzip(archive: &Path, dest: &Path) -> Result<()> { - cmd!("unzip", archive, "-d", dest).run()?; + cmd!("unzip", archive, "-d", dest) + .run() + .wrap_err_with(|| eyre!("unzip {} -d {}", display_path(archive), display_path(dest)))?; Ok(()) } diff --git a/src/http.rs b/src/http.rs index 6f5b522be..4777fd458 100644 --- a/src/http.rs +++ b/src/http.rs @@ -2,8 +2,10 @@ use std::fs::File; use std::path::Path; use std::time::Duration; +use crate::file::display_path; +use crate::{env, file}; use eyre::{Report, Result}; -use reqwest::blocking::{ClientBuilder, RequestBuilder}; +use reqwest::blocking::{ClientBuilder, Response}; use reqwest::IntoUrl; #[derive(Debug)] @@ -30,16 +32,24 @@ impl Client { .gzip(true) } - pub fn get(&self, url: U) -> RequestBuilder { + pub fn get(&self, url: U) -> Result { let url = url.into_url().unwrap(); debug!("GET {}", url); - self.reqwest.get(url) + let mut req = self.reqwest.get(url.clone()); + if url.host_str() == Some("api.github.com") { + if let Some(token) = &*env::GITHUB_API_TOKEN { + req = req.header("authorization", format!("token {}", token)); + } + } + let resp = req.send()?; + debug!("GET {url} {}", resp.status()); + resp.error_for_status_ref()?; + Ok(resp) } pub fn get_text(&self, url: U) -> Result { let url = url.into_url().unwrap(); - let resp = self.get(url).send()?; - resp.error_for_status_ref()?; + let resp = self.get(url)?; let text = resp.text()?; Ok(text) } @@ -49,17 +59,17 @@ impl Client { T: serde::de::DeserializeOwned, { let url = url.into_url().unwrap(); - let resp = self.get(url.clone()).send()?; - resp.error_for_status_ref()?; + let resp = self.get(url.clone())?; let json = resp.json()?; Ok(json) } pub fn download_file(&self, url: U, path: &Path) -> Result<()> { let url = url.into_url()?; - debug!("Downloading {} to {}", &url, path.display()); - let mut resp = self.get(url).send()?; - resp.error_for_status_ref()?; + debug!("GET Downloading {} to {}", &url, display_path(path)); + let mut resp = self.get(url.clone())?; + + file::create_dir_all(path.parent().unwrap())?; let mut file = File::create(path)?; resp.copy_to(&mut file)?; Ok(()) diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 312292adf..08e722999 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -13,7 +13,7 @@ use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; -use crate::{env, file, http}; +use crate::{file, http}; #[derive(Debug)] pub struct BunPlugin { @@ -28,13 +28,8 @@ impl BunPlugin { fn fetch_remote_versions(&self) -> Result> { let http = http::Client::new()?; - let mut req = http.get("https://api.github.com/repos/oven-sh/bun/releases?per_page=100"); - if let Some(token) = &*env::GITHUB_API_TOKEN { - req = req.header("authorization", format!("token {}", token)); - } - let resp = req.send()?; - resp.error_for_status_ref()?; - let releases: Vec = resp.json()?; + let releases: Vec = + http.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?; let versions = releases .into_iter() .map(|r| r.tag_name) diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index b7e9d817d..3abd7679c 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -14,7 +14,7 @@ use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::ProgressReport; -use crate::{env, file, http}; +use crate::{file, http}; #[derive(Debug)] pub struct DenoPlugin { @@ -29,13 +29,8 @@ impl DenoPlugin { fn fetch_remote_versions(&self) -> Result> { let http = http::Client::new()?; - let mut req = http.get("https://api.github.com/repos/denoland/deno/releases?per_page=100"); - if let Some(token) = &*env::GITHUB_API_TOKEN { - req = req.header("authorization", format!("token {}", token)); - } - let resp = req.send()?; - resp.error_for_status_ref()?; - let releases: Vec = resp.json()?; + let releases: Vec = + http.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; let versions = releases .into_iter() .map(|r| r.name) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index a277439a4..9092e393d 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -187,9 +187,7 @@ impl Plugin for PythonPlugin { ctx.pr .set_message(format!("with patch file from: {patch_url}")); let http = http::Client::new()?; - let resp = http.get(patch_url).send()?; - resp.error_for_status_ref()?; - let patch = resp.text()?; + let patch = http.get_text(patch_url)?; cmd = cmd.arg("--patch").stdin_string(patch) } if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 3ddea4f37..d68d6aa39 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -7,7 +7,7 @@ use color_eyre::eyre::Result; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::duration::DAILY; -use crate::env::GITHUB_API_TOKEN; + use crate::git::Git; use crate::github::GithubRelease; use crate::install_context::InstallContext; @@ -220,13 +220,8 @@ impl RubyPlugin { fn latest_ruby_build_version(&self) -> Result { let http = http::Client::new()?; - let mut req = http.get("https://api.github.com/repos/rbenv/ruby-build/releases/latest"); - if let Some(token) = &*GITHUB_API_TOKEN { - req = req.header("authorization", format!("token {}", token)); - } - let resp = req.send()?; - resp.error_for_status_ref()?; - let release: GithubRelease = resp.json()?; + let release: GithubRelease = + http.json("https://api.github.com/repos/rbenv/ruby-build/releases/latest")?; Ok(release.tag_name.trim_start_matches('v').to_string()) } @@ -311,9 +306,7 @@ impl RubyPlugin { for f in &self.fetch_patch_sources() { if regex!(r#"^[Hh][Tt][Tt][Pp][Ss]?://"#).is_match(f) { let http = http::Client::new()?; - let resp = http.get(f).send()?; - resp.error_for_status_ref()?; - patches.push(resp.text()?); + patches.push(http.get_text(f)?); } else { patches.push(file::read_to_string(f)?); } From 5319d25c2a5f5a8e26b058aa26237f3fa6852788 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:43:02 -0600 Subject: [PATCH 1191/1891] refactor: started the work to merge tool and plugin struct/traits (#1091) --- src/config/mod.rs | 9 +- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/go.rs | 4 +- src/plugins/core/java.rs | 2 +- src/plugins/core/node.rs | 2 +- src/plugins/core/node_build.rs | 2 +- src/plugins/core/python.rs | 2 +- src/plugins/core/ruby.rs | 2 +- src/plugins/external_plugin.rs | 13 +- src/plugins/mod.rs | 271 +++++++++++++++++++++++++++- src/tool.rs | 316 +++------------------------------ 12 files changed, 314 insertions(+), 313 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 871e52dab..ec13b8bd9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -283,9 +283,14 @@ fn load_tools(settings: &Settings) -> Result { if settings.experimental { tools.extend(EXPERIMENTAL_CORE_PLUGINS.clone()); } - let plugins = Tool::list()? + let plugins = ExternalPlugin::list()? .into_par_iter() - .map(|p| (p.name.clone(), Arc::new(p))) + .map(|p| { + ( + p.name.clone(), + Arc::new(Tool::new(p.name.clone(), Box::new(p))), + ) + }) .collect::>(); tools.extend(plugins); for tool in &settings.disable_tools { diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 08e722999..0d42f5e24 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -107,7 +107,7 @@ impl Plugin for BunPlugin { Ok(vec![".bun-version".into()]) } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { assert!(matches!( &ctx.tv.request, ToolVersionRequest::Version { .. } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 3abd7679c..c5dec07d8 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -105,7 +105,7 @@ impl Plugin for DenoPlugin { Ok(vec![".deno-version".into()]) } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { assert!(matches!( &ctx.tv.request, ToolVersionRequest::Version { .. } diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 6d94610fa..60d34f270 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -149,7 +149,7 @@ impl Plugin for GoPlugin { Ok(vec![".go-version".into()]) } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let tarball_path = self.download(&ctx.tv, &ctx.pr)?; self.install(&ctx.tv, &ctx.pr, &tarball_path)?; self.verify(ctx.config, &ctx.tv, &ctx.pr)?; @@ -157,7 +157,7 @@ impl Plugin for GoPlugin { Ok(()) } - fn uninstall_version(&self, _config: &Config, tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, _config: &Config, tv: &ToolVersion) -> Result<()> { let gopath = self.gopath(tv); if gopath.exists() { cmd!("chmod", "-R", "u+wx", gopath).run()?; diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index e81d6d68a..457ee90e8 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -262,7 +262,7 @@ impl Plugin for JavaPlugin { Ok(aliases) } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { assert!(matches!( &ctx.tv.request, ToolVersionRequest::Version { .. } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index bd2abf61c..9027f76d9 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -260,7 +260,7 @@ impl Plugin for NodePlugin { Ok(body.to_string()) } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let opts = BuildOpts::new(ctx)?; debug!("node build opts: {:#?}", opts); if *env::RTX_NODE_COMPILE { diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index 5e0cf2913..2290529b2 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -252,7 +252,7 @@ impl Plugin for NodeBuildPlugin { exit(0); } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { self.install_node_build()?; ctx.pr.set_message("running node-build"); let mut cmd = CmdLineRunner::new(&ctx.config.settings, self.node_build_bin()) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 9092e393d..9519d60d2 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -169,7 +169,7 @@ impl Plugin for PythonPlugin { Ok(vec![".python-version".to_string()]) } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { self.install_python_build()?; if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index d68d6aa39..e184a67d5 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -346,7 +346,7 @@ impl Plugin for RubyPlugin { Ok(v) } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { self.update_build_tool()?; assert!(matches!( &ctx.tv.request, diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index a67f42ca9..b772e4343 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -81,6 +81,13 @@ impl ExternalPlugin { } } + pub fn list() -> Result> { + Ok(file::dir_subdirs(&dirs::PLUGINS)? + .into_iter() + .map(Self::new) + .collect()) + } + fn get_repo_url(&self, config: &Config) -> Result { self.repo_url .clone() @@ -388,7 +395,7 @@ impl Plugin for ExternalPlugin { fn latest_stable_version(&self, settings: &Settings) -> Result> { if !self.has_latest_stable_script() { - return Ok(None); + return self.latest_version(settings, Some("latest".into())); } self.latest_stable_cache .get_or_try_init(|| self.fetch_latest_stable(settings)) @@ -617,7 +624,7 @@ impl Plugin for ExternalPlugin { exit(result.status.code().unwrap_or(1)); } - fn install_version(&self, ctx: &InstallContext) -> Result<()> { + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let mut sm = self.script_man_for_tv(ctx.config, &ctx.tv); for p in ctx.ts.list_paths(ctx.config) { @@ -636,7 +643,7 @@ impl Plugin for ExternalPlugin { Ok(()) } - fn uninstall_version(&self, config: &Config, tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, config: &Config, tv: &ToolVersion) -> Result<()> { if self.plugin_path.join("bin/uninstall").exists() { self.script_man_for_tv(config, tv) .run(&config.settings, &Script::Uninstall)?; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 29d84a165..e52d6db11 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,22 +1,29 @@ use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; +use std::fs::File; use std::path::{Path, PathBuf}; use clap::Command; use color_eyre::eyre::Result; use console::style; +use eyre::WrapErr; +use itertools::Itertools; +use regex::Regex; +use versions::Versioning; pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; -use crate::file; -use crate::file::display_path; +use crate::file::{display_path, remove_all, remove_all_with_warning}; use crate::install_context::InstallContext; use crate::lock_file::LockFile; -use crate::toolset::{ToolVersion, Toolset}; +use crate::runtime_symlinks::is_runtime_symlink; +use crate::tool::Tool; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; +use crate::{dirs, file}; pub mod core; mod external_plugin; @@ -31,10 +38,102 @@ pub trait Plugin: Debug + Send + Sync { fn get_type(&self) -> PluginType { PluginType::Core } + fn installs_path(&self) -> PathBuf { + dirs::INSTALLS.join(self.name()) + } + fn cache_path(&self) -> PathBuf { + dirs::CACHE.join(self.name()) + } + fn downloads_path(&self) -> PathBuf { + dirs::DOWNLOADS.join(self.name()) + } fn list_remote_versions(&self, settings: &Settings) -> Result>; - fn latest_stable_version(&self, _settings: &Settings) -> Result> { - Ok(None) + fn latest_stable_version(&self, settings: &Settings) -> Result> { + self.latest_version(settings, Some("latest".into())) + } + fn list_installed_versions(&self) -> Result> { + Ok(match self.installs_path().exists() { + true => file::dir_subdirs(&self.installs_path())? + .iter() + .filter(|v| !is_runtime_symlink(&self.installs_path().join(v))) + .filter(|v| !self.installs_path().join(v).join("incomplete").exists()) + .cloned() + .sorted_by_cached_key(|v| Versioning::new(v).unwrap_or_default()) + .collect(), + false => vec![], + }) + } + fn is_version_installed(&self, tv: &ToolVersion) -> bool { + match tv.request { + ToolVersionRequest::System(_) => true, + _ => { + tv.install_path().exists() + && !self.incomplete_file_path(tv).exists() + && !is_runtime_symlink(&tv.install_path()) + } + } + } + fn is_version_outdated(&self, tool: &Tool, config: &Config, tv: &ToolVersion) -> bool { + let latest = match tv.latest_version(config, tool) { + Ok(latest) => latest, + Err(e) => { + debug!("Error getting latest version for {}: {:#}", self.name(), e); + return false; + } + }; + !self.is_version_installed(tv) || tv.version != latest + } + fn symlink_path(&self, tv: &ToolVersion) -> Option { + match tv.install_path() { + path if path.is_symlink() => Some(path), + _ => None, + } + } + fn create_symlink(&self, version: &str, target: &Path) -> Result<()> { + let link = self.installs_path().join(version); + file::create_dir_all(link.parent().unwrap())?; + file::make_symlink(target, &link) + } + fn list_installed_versions_matching(&self, query: &str) -> Result> { + let versions = self.list_installed_versions()?; + fuzzy_match_filter(versions, query) + } + fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { + let versions = self.list_remote_versions(settings)?; + fuzzy_match_filter(versions, query) } + fn latest_version(&self, settings: &Settings, query: Option) -> Result> { + match query { + Some(query) => { + let matches = self.list_versions_matching(settings, &query)?; + Ok(find_match_in_list(&matches, &query)) + } + None => self.latest_stable_version(settings), + } + } + fn latest_installed_version(&self, query: Option) -> Result> { + match query { + Some(query) => { + let matches = self.list_installed_versions_matching(&query)?; + Ok(find_match_in_list(&matches, &query)) + } + None => { + let installed_symlink = self.installs_path().join("latest"); + if installed_symlink.exists() { + let target = installed_symlink.read_link()?; + let version = target + .file_name() + .ok_or_else(|| eyre!("Invalid symlink target"))? + .to_string_lossy() + .to_string(); + Ok(Some(version)) + } else { + Ok(None) + } + } + } + } + fn get_remote_url(&self) -> Option { None } @@ -61,6 +160,12 @@ pub trait Plugin: Debug + Send + Sync { fn uninstall(&self, _pr: &ProgressReport) -> Result<()> { Ok(()) } + fn purge(&self, pr: &ProgressReport) -> Result<()> { + rmdir(&self.installs_path(), pr)?; + rmdir(&self.cache_path(), pr)?; + rmdir(&self.downloads_path(), pr)?; + Ok(()) + } fn get_aliases(&self, _settings: &Settings) -> Result> { Ok(BTreeMap::new()) } @@ -82,8 +187,69 @@ pub trait Plugin: Debug + Send + Sync { ) -> Result<()> { unimplemented!() } - fn install_version(&self, ctx: &InstallContext) -> Result<()>; - fn uninstall_version(&self, _config: &Config, _tv: &ToolVersion) -> Result<()> { + fn install_version(&self, mut ctx: InstallContext) -> Result<()> { + if self.is_version_installed(&ctx.tv) { + if ctx.force { + self.uninstall_version(ctx.config, &ctx.tv, &ctx.pr, false)?; + } else { + return Ok(()); + } + } + self.decorate_progress_bar(&mut ctx.pr, Some(&ctx.tv)); + let _lock = self.get_lock(&ctx.tv.install_path(), ctx.force)?; + self.create_install_dirs(&ctx.tv)?; + + if let Err(e) = self.install_version_impl(&ctx) { + self.cleanup_install_dirs_on_error(&ctx.config.settings, &ctx.tv); + return Err(e); + } + self.cleanup_install_dirs(&ctx.config.settings, &ctx.tv); + // attempt to touch all the .tool-version files to trigger updates in hook-env + let mut touch_dirs = vec![dirs::DATA.to_path_buf()]; + touch_dirs.extend(ctx.config.config_files.keys().cloned()); + for path in touch_dirs { + let err = file::touch_dir(&path); + if let Err(err) = err { + debug!("error touching config file: {:?} {:?}", path, err); + } + } + if let Err(err) = file::remove_file(self.incomplete_file_path(&ctx.tv)) { + debug!("error removing incomplete file: {:?}", err); + } + ctx.pr.set_message(""); + ctx.pr.finish(); + + Ok(()) + } + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()>; + fn uninstall_version( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + dryrun: bool, + ) -> Result<()> { + pr.set_message(format!("uninstall {tv}")); + + if !dryrun { + self.uninstall_version_impl(config, tv)?; + } + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", display_path(dir))); + if dryrun { + return Ok(()); + } + remove_all_with_warning(dir) + }; + rmdir(&tv.install_path())?; + rmdir(&tv.download_path())?; + rmdir(&tv.cache_path())?; + Ok(()) + } + fn uninstall_version_impl(&self, _config: &Config, _tv: &ToolVersion) -> Result<()> { Ok(()) } fn list_bin_paths( @@ -92,7 +258,10 @@ pub trait Plugin: Debug + Send + Sync { _ts: &Toolset, tv: &ToolVersion, ) -> Result> { - Ok(vec![tv.install_short_path().join("bin")]) + match tv.request { + ToolVersionRequest::System(_) => Ok(vec![]), + _ => Ok(vec![tv.install_short_path().join("bin")]), + } } fn exec_env( &self, @@ -102,6 +271,22 @@ pub trait Plugin: Debug + Send + Sync { ) -> Result> { Ok(HashMap::new()) } + fn which( + &self, + config: &Config, + ts: &Toolset, + tv: &ToolVersion, + bin_name: &str, + ) -> Result> { + let bin_paths = self.list_bin_paths(config, ts, tv)?; + for bin_path in bin_paths { + let bin_path = bin_path.join(bin_name); + if bin_path.exists() { + return Ok(Some(bin_path)); + } + } + Ok(None) + } fn get_lock(&self, path: &Path, force: bool) -> Result> { let lock = if force { @@ -116,7 +301,28 @@ pub trait Plugin: Debug + Send + Sync { }; Ok(lock) } - + fn create_install_dirs(&self, tv: &ToolVersion) -> Result<()> { + let _ = remove_all_with_warning(tv.install_path()); + let _ = remove_all_with_warning(tv.download_path()); + let _ = remove_all_with_warning(tv.cache_path()); + let _ = file::remove_file(tv.install_path()); // removes if it is a symlink + file::create_dir_all(tv.install_path())?; + file::create_dir_all(tv.download_path())?; + file::create_dir_all(tv.cache_path())?; + File::create(self.incomplete_file_path(tv))?; + Ok(()) + } + fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { + if !settings.always_keep_install { + let _ = remove_all_with_warning(tv.install_path()); + self.cleanup_install_dirs(settings, tv); + } + } + fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { + if !settings.always_keep_download && !settings.always_keep_install { + let _ = remove_all_with_warning(tv.download_path()); + } + } fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { pr.set_style(PROG_TEMPLATE.clone()); let tool = match tv { @@ -130,6 +336,10 @@ pub trait Plugin: Debug + Send + Sync { )); pr.enable_steady_tick(); } + + fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("incomplete") + } } pub fn unalias_plugin(plugin_name: &str) -> &str { @@ -140,6 +350,49 @@ pub fn unalias_plugin(plugin_name: &str) -> &str { } } +fn fuzzy_match_filter(versions: Vec, query: &str) -> Result> { + let mut query = query; + if query == "latest" { + query = "[0-9].*"; + } + let query_regex = Regex::new(&format!("^{}([-.].+)?$", query))?; + let version_regex = regex!( + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|SNAPSHOT|master)" + ); + let versions = versions + .into_iter() + .filter(|v| { + if query == v { + return true; + } + if version_regex.is_match(v) { + return false; + } + query_regex.is_match(v) + }) + .collect(); + Ok(versions) +} +fn find_match_in_list(list: &[String], query: &str) -> Option { + let v = match list.contains(&query.to_string()) { + true => Some(query.to_string()), + false => list.last().map(|s| s.to_string()), + }; + v +} +fn rmdir(dir: &Path, pr: &ProgressReport) -> Result<()> { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", &dir.to_string_lossy())); + remove_all(dir).wrap_err_with(|| { + format!( + "Failed to remove directory {}", + style(&dir.to_string_lossy()).cyan().for_stderr() + ) + }) +} + pub enum PluginType { #[allow(dead_code)] Core, diff --git a/src/tool.rs b/src/tool.rs index dfed80cfc..476ddab8a 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,26 +1,22 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Display}; -use std::fs::File; + use std::path::{Path, PathBuf}; use clap::Command; -use color_eyre::eyre::{eyre, Context, Result}; -use console::style; -use itertools::Itertools; -use regex::Regex; -use versions::Versioning; +use color_eyre::eyre::Result; use crate::config::{Config, Settings}; -use crate::file::{display_path, remove_all, remove_all_with_warning}; + +use crate::dirs; use crate::install_context::InstallContext; -use crate::plugins::{ExternalPlugin, Plugin}; -use crate::runtime_symlinks::is_runtime_symlink; -use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; +use crate::plugins::Plugin; +use crate::toolset::{ToolVersion, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; -use crate::{dirs, file}; +use crate::ui::progress_report::ProgressReport; +#[derive(Debug)] pub struct Tool { pub name: String, pub plugin: Box, @@ -42,16 +38,6 @@ impl Tool { } } - pub fn list() -> Result> { - Ok(file::dir_subdirs(&dirs::PLUGINS)? - .into_iter() - .map(|name| { - let plugin = ExternalPlugin::new(name.clone()); - Self::new(name, Box::new(plugin)) - }) - .collect()) - } - pub fn is_installed(&self) -> bool { self.plugin.is_installed() } @@ -69,29 +55,11 @@ impl Tool { } pub fn list_installed_versions(&self) -> Result> { - Ok(match self.installs_path.exists() { - true => file::dir_subdirs(&self.installs_path)? - .iter() - .filter(|v| !is_runtime_symlink(&self.installs_path.join(v))) - // TODO: share logic with incomplete_file_path - .filter(|v| { - !dirs::CACHE - .join(&self.name) - .join(v) - .join("incomplete") - .exists() - }) - .map(|v| Versioning::new(v).unwrap_or_default()) - .sorted() - .map(|v| v.to_string()) - .collect(), - false => vec![], - }) + self.plugin.list_installed_versions() } pub fn list_installed_versions_matching(&self, query: &str) -> Result> { - let versions = self.list_installed_versions()?; - self.fuzzy_match_filter(versions, query) + self.plugin.list_installed_versions_matching(query) } pub fn list_remote_versions(&self, settings: &Settings) -> Result> { @@ -99,8 +67,7 @@ impl Tool { } pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - let versions = self.list_remote_versions(settings)?; - self.fuzzy_match_filter(versions, query) + self.plugin.list_versions_matching(settings, query) } pub fn latest_version( @@ -108,36 +75,11 @@ impl Tool { settings: &Settings, query: Option, ) -> Result> { - match query { - Some(query) => { - let matches = self.list_versions_matching(settings, &query)?; - Ok(find_match_in_list(&matches, &query)) - } - None => self.latest_stable_version(settings), - } + self.plugin.latest_version(settings, query) } pub fn latest_installed_version(&self, query: Option) -> Result> { - match query { - Some(query) => { - let matches = self.list_installed_versions_matching(&query)?; - Ok(find_match_in_list(&matches, &query)) - } - None => { - let installed_symlink = self.installs_path.join("latest"); - if installed_symlink.exists() { - let target = installed_symlink.read_link()?; - let version = target - .file_name() - .ok_or_else(|| eyre!("Invalid symlink target"))? - .to_string_lossy() - .to_string(); - Ok(Some(version)) - } else { - Ok(None) - } - } - } + self.plugin.latest_installed_version(query) } pub fn get_aliases(&self, settings: &Settings) -> Result> { @@ -148,96 +90,28 @@ impl Tool { self.plugin.legacy_filenames(settings) } - fn latest_stable_version(&self, settings: &Settings) -> Result> { - if let Some(latest) = self.plugin.latest_stable_version(settings)? { - Ok(Some(latest)) - } else { - self.latest_version(settings, Some("latest".into())) - } - } - pub fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { - pr.set_style(PROG_TEMPLATE.clone()); - let tool = match tv { - Some(tv) => tv.to_string(), - None => self.name.to_string(), - }; - pr.set_prefix(format!( - "{} {} ", - style("rtx").dim().for_stderr(), - style(tool).cyan().for_stderr(), - )); - pr.enable_steady_tick(); + self.plugin.decorate_progress_bar(pr, tv); } pub fn is_version_installed(&self, tv: &ToolVersion) -> bool { - match tv.request { - ToolVersionRequest::System(_) => true, - _ => { - tv.install_path().exists() - && !self.incomplete_file_path(tv).exists() - && !is_runtime_symlink(&tv.install_path()) - } - } + self.plugin.is_version_installed(tv) } pub fn is_version_outdated(&self, config: &Config, tv: &ToolVersion) -> bool { - let latest = match tv.latest_version(config, self) { - Ok(latest) => latest, - Err(e) => { - debug!("Error getting latest version for {}: {:#}", self.name, e); - return false; - } - }; - !self.is_version_installed(tv) || tv.version != latest + self.plugin.is_version_outdated(self, config, tv) } pub fn symlink_path(&self, tv: &ToolVersion) -> Option { - match tv.install_path() { - path if path.is_symlink() => Some(path), - _ => None, - } + self.plugin.symlink_path(tv) } pub fn create_symlink(&self, version: &str, target: &Path) -> Result<()> { - let link = self.installs_path.join(version); - file::create_dir_all(link.parent().unwrap())?; - file::make_symlink(target, &link) - } - - pub fn install_version(&self, mut ctx: InstallContext) -> Result<()> { - if self.is_version_installed(&ctx.tv) { - if ctx.force { - self.uninstall_version(ctx.config, &ctx.tv, &ctx.pr, false)?; - } else { - return Ok(()); - } - } - self.decorate_progress_bar(&mut ctx.pr, Some(&ctx.tv)); - let _lock = self.get_lock(&ctx.tv.install_path(), ctx.force)?; - self.create_install_dirs(&ctx.tv)?; - - if let Err(e) = self.plugin.install_version(&ctx) { - self.cleanup_install_dirs_on_error(&ctx.config.settings, &ctx.tv); - return Err(e); - } - self.cleanup_install_dirs(&ctx.config.settings, &ctx.tv); - // attempt to touch all the .tool-version files to trigger updates in hook-env - let mut touch_dirs = vec![dirs::DATA.to_path_buf()]; - touch_dirs.extend(ctx.config.config_files.keys().cloned()); - for path in touch_dirs { - let err = file::touch_dir(&path); - if let Err(err) = err { - debug!("error touching config file: {:?} {:?}", path, err); - } - } - if let Err(err) = file::remove_file(self.incomplete_file_path(&ctx.tv)) { - debug!("error removing incomplete file: {:?}", err); - } - ctx.pr.set_message(""); - ctx.pr.finish(); + self.plugin.create_symlink(version, target) + } - Ok(()) + pub fn install_version(&self, ctx: InstallContext) -> Result<()> { + self.plugin.install_version(ctx) } pub fn uninstall_version( @@ -247,25 +121,7 @@ impl Tool { pr: &ProgressReport, dryrun: bool, ) -> Result<()> { - pr.set_message(format!("uninstall {tv}")); - - if !dryrun { - self.plugin.uninstall_version(config, tv)?; - } - let rmdir = |dir: &Path| { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", display_path(dir))); - if dryrun { - return Ok(()); - } - remove_all_with_warning(dir) - }; - rmdir(&tv.install_path())?; - rmdir(&tv.download_path())?; - rmdir(&tv.cache_path())?; - Ok(()) + self.plugin.uninstall_version(config, tv, pr, dryrun) } pub fn ensure_installed( @@ -283,10 +139,7 @@ impl Tool { self.plugin.uninstall(pr) } pub fn purge(&self, pr: &ProgressReport) -> Result<()> { - rmdir(&self.installs_path, pr)?; - rmdir(&self.cache_path, pr)?; - rmdir(&self.downloads_path, pr)?; - Ok(()) + self.plugin.purge(pr) } pub fn external_commands(&self) -> Result> { @@ -309,10 +162,7 @@ impl Tool { ts: &Toolset, tv: &ToolVersion, ) -> Result> { - match tv.request { - ToolVersionRequest::System(_) => Ok(vec![]), - _ => self.plugin.list_bin_paths(config, ts, tv), - } + self.plugin.list_bin_paths(config, ts, tv) } pub fn exec_env( &self, @@ -320,10 +170,7 @@ impl Tool { ts: &Toolset, tv: &ToolVersion, ) -> Result> { - match tv.request { - ToolVersionRequest::System(_) => Ok(HashMap::new()), - _ => self.plugin.exec_env(config, ts, tv), - } + self.plugin.exec_env(config, ts, tv) } pub fn which( @@ -333,83 +180,8 @@ impl Tool { tv: &ToolVersion, bin_name: &str, ) -> Result> { - let bin_paths = self.plugin.list_bin_paths(config, ts, tv)?; - for bin_path in bin_paths { - let bin_path = bin_path.join(bin_name); - if bin_path.exists() { - return Ok(Some(bin_path)); - } - } - Ok(None) - } - - fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { - tv.cache_path().join("incomplete") + self.plugin.which(config, ts, tv, bin_name) } - - fn create_install_dirs(&self, tv: &ToolVersion) -> Result<()> { - let _ = remove_all_with_warning(tv.install_path()); - let _ = remove_all_with_warning(tv.download_path()); - let _ = remove_all_with_warning(tv.cache_path()); - let _ = file::remove_file(tv.install_path()); // removes if it is a symlink - file::create_dir_all(tv.install_path())?; - file::create_dir_all(tv.download_path())?; - file::create_dir_all(tv.cache_path())?; - File::create(self.incomplete_file_path(tv))?; - Ok(()) - } - fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { - if !settings.always_keep_install { - let _ = remove_all_with_warning(tv.install_path()); - self.cleanup_install_dirs(settings, tv); - } - } - fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { - if !settings.always_keep_download && !settings.always_keep_install { - let _ = remove_all_with_warning(tv.download_path()); - } - } - - fn get_lock(&self, path: &Path, force: bool) -> Result> { - self.plugin.get_lock(path, force) - } - - fn fuzzy_match_filter(&self, versions: Vec, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9].*"; - } - let query_regex = Regex::new(&format!("^{}([-.].+)?$", query))?; - let version_regex = regex!( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|SNAPSHOT|master)" - ); - let versions = versions - .into_iter() - .filter(|v| { - if query == v { - return true; - } - if version_regex.is_match(v) { - return false; - } - query_regex.is_match(v) - }) - .collect(); - Ok(versions) - } -} - -fn rmdir(dir: &Path, pr: &ProgressReport) -> Result<()> { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", &dir.to_string_lossy())); - remove_all(dir).wrap_err_with(|| { - format!( - "Failed to remove directory {}", - style(&dir.to_string_lossy()).cyan().for_stderr() - ) - }) } impl PartialEq for Tool { @@ -418,30 +190,12 @@ impl PartialEq for Tool { } } -impl Debug for Tool { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Tool") - .field("name", &self.name) - .field("installs_path", &self.installs_path) - .field("plugin", &self.plugin) - .finish() - } -} - impl Display for Tool { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", &self.name) } } -fn find_match_in_list(list: &[String], query: &str) -> Option { - let v = match list.contains(&query.to_string()) { - true => Some(query.to_string()), - false => list.last().map(|s| s.to_string()), - }; - v -} - impl PartialOrd for Tool { fn partial_cmp(&self, other: &Self) -> Option { Some(self.name.cmp(&other.name)) @@ -455,21 +209,3 @@ impl Ord for Tool { } impl Eq for Tool {} - -#[cfg(test)] -mod tests { - use crate::plugins::PluginName; - - use super::*; - - #[test] - fn test_debug() { - let plugin = ExternalPlugin::new(PluginName::from("dummy")); - let tool = Tool::new("dummy".to_string(), Box::new(plugin)); - let debug = format!("{:?}", tool); - assert!(debug.contains("Tool")); - assert!(debug.contains("name")); - assert!(debug.contains("installs_path")); - assert!(debug.contains("plugin")); - } -} From f36b1257711027dda13b026874c166f6bd995138 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:48:38 -0600 Subject: [PATCH 1192/1891] chore: Release rtx-cli version 2023.12.10 --- Cargo.lock | 39 +++++++++++++++------------------------ Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a88fb5989..c00ab3825 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -714,14 +714,14 @@ checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall", + "windows-sys 0.52.0", ] [[package]] @@ -1220,7 +1220,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ "bitflags 2.4.1", "libc", - "redox_syscall 0.4.1", + "redox_syscall", ] [[package]] @@ -1291,9 +1291,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", @@ -1559,9 +1559,9 @@ checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "portable-atomic" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "powerfmt" @@ -1662,15 +1662,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1768,9 +1759,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", @@ -1810,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.9" +version = "2023.12.10" dependencies = [ "base64", "built", @@ -2296,7 +2287,7 @@ checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.4.1", + "redox_syscall", "rustix", "windows-sys 0.48.0", ] @@ -3061,9 +3052,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.24" +version = "0.5.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0383266b19108dfc6314a56047aa545a1b4d1be60e799b4dbdd407b56402704b" +checksum = "b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index f9e62330c..43b014a68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.9" +version = "2023.12.10" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 7ed1fbe3f..0d7beeceb 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.9 +rtx 2023.12.10 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.9/rtx-v2023.12.9-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.10/rtx-v2023.12.10-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 5797f4c83..0e7260d91 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.9"; + version = "2023.12.10"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 78f22a944..108290468 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.9 +Version: 2023.12.10 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 0edc2e78897317c16224da7c947878ef60bbed99 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 11:10:18 -0600 Subject: [PATCH 1193/1891] refactor: get rid of Tools struct (#1093) --- src/cli/current.rs | 24 ++- src/cli/doctor.rs | 14 +- src/cli/external.rs | 7 +- src/cli/install.rs | 4 +- src/cli/latest.rs | 4 +- src/cli/ls.rs | 28 +-- src/cli/ls_remote.rs | 16 +- src/cli/outdated.rs | 8 +- src/cli/plugins/install.rs | 4 +- src/cli/plugins/ls.rs | 14 +- src/cli/plugins/ls_remote.rs | 6 +- src/cli/plugins/uninstall.rs | 4 +- src/cli/plugins/update.rs | 4 +- src/cli/prune.rs | 11 +- src/cli/shell.rs | 4 +- src/cli/sync/node.rs | 6 +- src/cli/sync/python.rs | 2 +- src/cli/uninstall.rs | 10 +- src/cli/upgrade.rs | 8 +- src/cli/where.rs | 4 +- src/cli/which.rs | 2 +- src/config/config_file/legacy_version.rs | 7 +- src/config/config_file/mod.rs | 10 +- src/config/mod.rs | 73 ++++---- src/main.rs | 1 - src/plugins/core/mod.rs | 47 +++-- src/plugins/external_plugin.rs | 8 +- src/plugins/mod.rs | 42 +++-- src/runtime_symlinks.rs | 28 +-- src/shims.rs | 11 +- src/tool.rs | 211 ----------------------- src/toolset/mod.rs | 58 ++++--- src/toolset/tool_version.rs | 36 ++-- src/toolset/tool_version_list.rs | 17 +- src/toolset/tool_version_request.rs | 22 +-- 35 files changed, 284 insertions(+), 471 deletions(-) delete mode 100644 src/tool.rs diff --git a/src/cli/current.rs b/src/cli/current.rs index 475936c95..27816afd8 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,9 +1,9 @@ use color_eyre::eyre::Result; +use std::sync::Arc; use crate::config::Config; use crate::output::Output; -use crate::plugins::unalias_plugin; -use crate::tool::Tool; +use crate::plugins::{unalias_plugin, Plugin}; use crate::toolset::{Toolset, ToolsetBuilder}; /// Shows current active and installed runtime versions @@ -25,8 +25,8 @@ impl Current { match &self.plugin { Some(plugin_name) => { let plugin_name = unalias_plugin(plugin_name); - match config.tools.get(plugin_name) { - Some(plugin) => self.one(&config, ts, out, plugin), + match config.plugins.get(plugin_name) { + Some(plugin) => self.one(&config, ts, out, plugin.clone()), None => { warn!("Plugin {} is not installed", plugin_name); Ok(()) @@ -37,15 +37,21 @@ impl Current { } } - fn one(&self, config: &Config, ts: Toolset, out: &mut Output, tool: &Tool) -> Result<()> { + fn one( + &self, + config: &Config, + ts: Toolset, + out: &mut Output, + tool: Arc, + ) -> Result<()> { if !tool.is_installed() { - warn!("Plugin {} is not installed", tool.name); + warn!("Plugin {} is not installed", tool.name()); return Ok(()); } match ts .list_versions_by_plugin(config) .into_iter() - .find(|(p, _)| p.name == tool.name) + .find(|(p, _)| p.name() == tool.name()) { Some((_, versions)) => { rtxprintln!( @@ -59,7 +65,7 @@ impl Current { ); } None => { - warn!("Plugin {} does not have a version set", tool.name); + warn!("Plugin {} does not have a version set", tool.name()); } }; Ok(()) @@ -82,7 +88,7 @@ impl Current { rtxprintln!( out, "{} {}", - &plugin.name, + &plugin.name(), versions .iter() .map(|v| v.version.to_string()) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index c4228f486..e12a4e1f6 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -45,9 +45,9 @@ impl Doctor { ); let mut checks = Vec::new(); - for plugin in config.tools.values() { + for plugin in config.plugins.values() { if !plugin.is_installed() { - checks.push(format!("plugin {} is not installed", &plugin.name)); + checks.push(format!("plugin {} is not installed", &plugin.name())); continue; } } @@ -123,16 +123,16 @@ 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 - .tools + .plugins .values() .filter(|p| p.is_installed()) .collect::>(); - let max_plugin_name_len = plugins.iter().map(|p| p.name.len()).max().unwrap_or(0) + 2; + let max_plugin_name_len = plugins.iter().map(|p| p.name().len()).max().unwrap_or(0) + 2; for p in plugins { - let padded_name = pad_str(&p.name, max_plugin_name_len, Alignment::Left, None); - let si = match p.plugin.get_type() { + let padded_name = pad_str(p.name(), max_plugin_name_len, Alignment::Left, None); + let si = match p.get_type() { PluginType::External => { - let git = Git::new(p.plugin_path.clone()); + let git = Git::new(dirs::PLUGINS.join(p.name())); match git.get_remote_url() { Some(url) => { let sha = git diff --git a/src/cli/external.rs b/src/cli/external.rs index ee76c517c..9c4bc2cc1 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -7,7 +7,7 @@ use crate::config::Config; pub fn commands(config: &Config) -> Vec { config - .tools + .plugins .values() .collect_vec() .into_par_iter() @@ -16,7 +16,8 @@ pub fn commands(config: &Config) -> Vec { Err(e) => { warn!( "failed to load external commands for plugin {}: {:#}", - p.name, e + p.name(), + e ); vec![] } @@ -35,7 +36,7 @@ pub fn execute( .find(|c| c.get_name() == plugin) { if let Some((subcommand, matches)) = args.subcommand() { - let plugin = config.tools.get(&plugin.to_string()).unwrap(); + let plugin = config.plugins.get(&plugin.to_string()).unwrap(); let args: Vec = matches .get_raw("args") .unwrap_or_default() diff --git a/src/cli/install.rs b/src/cli/install.rs index 490266a54..df400fa47 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -94,9 +94,9 @@ impl Install { } let mut tool_versions = vec![]; for (plugin_name, tvr, opts) in requests { - let plugin = config.get_or_create_tool(&plugin_name); + let plugin = config.get_or_create_plugin(&plugin_name); plugin.ensure_installed(config, Some(mpr), false)?; - let tv = tvr.resolve(config, &plugin, opts, ts.latest_versions)?; + let tv = tvr.resolve(config, plugin, opts, ts.latest_versions)?; tool_versions.push(tv); } Ok(tool_versions) diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 0445cc978..11462bde2 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -35,7 +35,7 @@ impl Latest { style(&self.tool).cyan().for_stderr() ))?, }; - let plugin = config.tools.get(&self.tool.plugin).ok_or_else(|| { + let plugin = config.plugins.get(&self.tool.plugin).ok_or_else(|| { eyre!( "plugin {} not found. run {} to install it", style(self.tool.plugin.to_string()).cyan().for_stderr(), @@ -45,7 +45,7 @@ impl Latest { ) })?; if let Some(v) = prefix { - prefix = Some(config.resolve_alias(&plugin.name, &v)?); + prefix = Some(config.resolve_alias(plugin.name(), &v)?); } let latest_version = if self.installed { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 09f10bac9..cc2c4b7a8 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -14,8 +14,7 @@ use versions::Versioning; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::{unalias_plugin, PluginName}; -use crate::tool::Tool; +use crate::plugins::{unalias_plugin, Plugin, PluginName}; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; /// List installed and/or currently selected tool versions @@ -95,7 +94,7 @@ impl Ls { fn verify_plugin(&self, config: &Config) -> Result<()> { match &self.plugin { Some(plugin_name) => { - let plugin = config.tools.get(plugin_name); + let plugin = config.plugins.get(plugin_name); if plugin.is_none() || !plugin.unwrap().is_installed() { return Err(PluginNotInstalled(plugin_name.clone()))?; } @@ -110,7 +109,7 @@ impl Ls { // only runtimes for 1 plugin let runtimes: Vec = runtimes .into_iter() - .filter(|(p, _, _)| plugin.eq(&p.name)) + .filter(|(p, _, _)| plugin.eq(&p.name())) .map(|row| row.into()) .collect(); out.stdout.writeln(serde_json::to_string_pretty(&runtimes)?); @@ -120,7 +119,7 @@ impl Ls { let mut plugins = JSONOutput::new(); for (plugin_name, runtimes) in &runtimes .into_iter() - .group_by(|(p, _, _)| p.name.to_string()) + .group_by(|(p, _, _)| p.name().to_string()) { let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); @@ -156,13 +155,16 @@ impl Ls { let output = runtimes .into_iter() .map(|(p, tv, source)| { - let plugin = p.name.to_string(); + let plugin = p.name().to_string(); let version = if let Some(symlink_path) = p.symlink_path(&tv) { VersionStatus::Symlink(tv.version, symlink_path, source.is_some()) } else if !p.is_version_installed(&tv) { VersionStatus::Missing(tv.version) } else if source.is_some() { - VersionStatus::Active(tv.version.clone(), p.is_version_outdated(config, &tv)) + VersionStatus::Active( + tv.version.clone(), + p.is_version_outdated(config, &tv, p.clone()), + ) } else { VersionStatus::Inactive(tv.version) }; @@ -212,20 +214,20 @@ impl Ls { if let Some(plugin) = &self.plugin { tsb = tsb.with_tools(&[plugin]); - config.tools.retain(|p, _| p == plugin); + config.plugins.retain(|p, _| p == plugin); } let ts = tsb.build(config)?; - let mut versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = ts + let mut versions: HashMap<(String, String), (Arc, ToolVersion)> = ts .list_installed_versions(config)? .into_iter() - .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) + .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) .collect(); let active = ts .list_current_versions(config) .into_iter() - .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p, tv))) - .collect::, ToolVersion)>>(); + .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) + .collect::, ToolVersion)>>(); versions.extend(active.clone()); @@ -263,7 +265,7 @@ struct JSONToolVersion { symlinked_to: Option, } -type RuntimeRow = (Arc, ToolVersion, Option); +type RuntimeRow = (Arc, ToolVersion, Option); impl From for JSONToolVersion { fn from(row: RuntimeRow) -> Self { diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index de5674277..aac7fe306 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -6,7 +6,7 @@ use crate::cli::args::tool::ToolArg; use crate::cli::args::tool::ToolArgParser; use crate::config::Config; use crate::output::Output; -use crate::tool::Tool; +use crate::plugins::Plugin; use crate::toolset::ToolVersionRequest; /// List runtime versions available for install @@ -39,7 +39,7 @@ impl LsRemote { } } - fn run_single(self, config: Config, out: &mut Output, plugin: Arc) -> Result<()> { + fn run_single(self, config: Config, out: &mut Output, plugin: Arc) -> Result<()> { let prefix = match &self.plugin { Some(tool_arg) => match &tool_arg.tvr { Some(ToolVersionRequest::Version(_, v)) => Some(v.clone()), @@ -65,21 +65,21 @@ impl LsRemote { } fn run_all(self, config: Config, out: &mut Output) -> Result<()> { - for plugin in config.tools.values() { + for plugin in config.plugins.values() { let versions = plugin.list_remote_versions(&config.settings)?; for version in versions { - rtxprintln!(out, "{}@{}", plugin.name, version); + rtxprintln!(out, "{}@{}", plugin.name(), version); } } Ok(()) } - fn get_plugin(&self, config: &mut Config) -> Result>> { + fn get_plugin(&self, config: &mut Config) -> Result>> { match &self.plugin { Some(tool_arg) => { - let tool = config.get_or_create_tool(&tool_arg.plugin); - tool.ensure_installed(config, None, false)?; - Ok(Some(tool)) + let plugin = config.get_or_create_plugin(&tool_arg.plugin); + plugin.ensure_installed(config, None, false)?; + Ok(Some(plugin)) } None => Ok(None), } diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index b6bdf4779..ca78237cd 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -7,7 +7,7 @@ use console::{pad_str, style, Alignment}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::output::Output; -use crate::tool::Tool; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolsetBuilder}; /// Shows outdated tool versions @@ -47,7 +47,7 @@ impl Outdated { // TODO: make a generic table printer in src/ui/table let plugins = outdated .iter() - .map(|(t, _, _)| t.name.clone()) + .map(|(t, _, _)| t.name()) .collect::>(); let requests = outdated .iter() @@ -103,7 +103,7 @@ impl Outdated { rtxprintln!( out, "{} {} {} {}", - pad_plugin(&plugins[i]), + pad_plugin(plugins[i]), pad_requested(&requests[i]), pad_current(¤ts[i]), latests[i] @@ -112,7 +112,7 @@ impl Outdated { } } -type OutputVec = Vec<(Arc, ToolVersion, String)>; +type OutputVec = Vec<(Arc, ToolVersion, String)>; static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 2c15c7af3..ae4cf6aeb 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -4,7 +4,6 @@ use url::Url; use crate::config::Config; use crate::output::Output; use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin, PluginName}; -use crate::tool::Tool; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; @@ -117,8 +116,7 @@ impl PluginsInstall { mpr.warn(format!("Plugin {} already installed", name)); mpr.warn("Use --force to install anyway".to_string()); } else { - let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); - tool.ensure_installed(config, Some(mpr), true)?; + plugin.ensure_installed(config, Some(mpr), true)?; } Ok(()) } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 3f2791b86..20e57129e 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -6,7 +6,6 @@ use color_eyre::eyre::Result; use crate::config::Config; use crate::output::Output; use crate::plugins::{ExternalPlugin, PluginType}; -use crate::tool::Tool; /// List installed plugins /// @@ -44,25 +43,24 @@ pub struct PluginsLs { impl PluginsLs { pub fn run(self, config: Config, out: &mut Output) -> Result<()> { - let mut tools = config.tools.values().cloned().collect::>(); + let mut tools = config.plugins.values().cloned().collect::>(); if self.all { for (plugin, url) in config.get_shorthands() { let mut ep = ExternalPlugin::new(plugin.clone()); ep.repo_url = Some(url.to_string()); - let tool = Tool::new(plugin.clone(), Box::from(ep)); - tools.insert(Arc::new(tool)); + tools.insert(Arc::new(ep)); } } else if self.user && self.core { } else if self.core { - tools.retain(|p| matches!(p.plugin.get_type(), PluginType::Core)); + tools.retain(|p| matches!(p.get_type(), PluginType::Core)); } else { - tools.retain(|p| matches!(p.plugin.get_type(), PluginType::External)); + tools.retain(|p| matches!(p.get_type(), PluginType::External)); } if self.urls || self.refs { for tool in tools { - rtxprint!(out, "{:29}", tool.name); + rtxprint!(out, "{:29}", tool.name()); if self.urls { if let Some(url) = tool.get_remote_url() { rtxprint!(out, " {}", url); @@ -80,7 +78,7 @@ impl PluginsLs { } } else { for tool in tools { - rtxprintln!(out, "{}", tool.name); + rtxprintln!(out, "{tool}"); } } Ok(()) diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 46ed1364e..4ed8337c1 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 - .tools + .plugins .values() .filter(|p| p.is_installed()) - .map(|p| p.name.clone()) + .map(|p| p.name()) .collect::>(); let shorthands = config.get_shorthands().iter().sorted().collect_vec(); @@ -43,7 +43,7 @@ impl PluginsLsRemote { } for (plugin, repo) in shorthands { - let installed = if !self.only_names && installed_plugins.contains(plugin) { + let installed = if !self.only_names && installed_plugins.contains(plugin.as_str()) { "*" } else { " " diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 9ea6f1bae..b1064312d 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -28,7 +28,7 @@ impl PluginsUninstall { let mpr = MultiProgressReport::new(config.show_progress_bars()); let plugins = match self.all { - true => config.tools.keys().cloned().collect(), + true => config.plugins.keys().cloned().collect(), false => self.plugin.clone(), }; @@ -45,7 +45,7 @@ impl PluginsUninstall { plugin_name: &str, mpr: &MultiProgressReport, ) -> Result<()> { - match config.tools.get(plugin_name) { + match config.plugins.get(plugin_name) { Some(plugin) if plugin.is_installed() => { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, None); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 862f18c12..fce3ea0d2 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -31,7 +31,7 @@ impl Update { None => (p.as_str(), None), }; let p = unalias_plugin(p); - let plugin = config.tools.get(p).ok_or_else(|| { + let plugin = config.plugins.get(p).ok_or_else(|| { eyre!("plugin {} not found", style(p).cyan().for_stderr()) })?; Ok((plugin.clone(), ref_)) @@ -45,7 +45,7 @@ impl Update { }; for (plugin, ref_) in plugins { - rtxprintln!(out, "updating plugin {}", plugin.name); + rtxprintln!(out, "updating plugin {plugin}"); plugin.update(ref_)?; } Ok(()) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 9b5ca1f54..983e40ff4 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -6,8 +6,7 @@ use console::style; use crate::config::Config; use crate::output::Output; -use crate::plugins::PluginName; -use crate::tool::Tool; +use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; @@ -37,7 +36,7 @@ impl Prune { .list_installed_versions(&config)? .into_iter() .map(|(p, tv)| (tv.to_string(), (p, tv))) - .collect::, ToolVersion)>>(); + .collect::, ToolVersion)>>(); if let Some(plugins) = &self.plugin { to_delete.retain(|_, (_, tv)| plugins.contains(&tv.plugin_name)); @@ -54,7 +53,11 @@ impl Prune { self.delete(&config, to_delete.into_values().collect()) } - fn delete(&self, config: &Config, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { + fn delete( + &self, + config: &Config, + to_delete: Vec<(Arc, ToolVersion)>, + ) -> Result<()> { let mpr = MultiProgressReport::new(config.show_progress_bars()); for (p, tv) in to_delete { let mut pr = mpr.add(); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 00776bbca..4d8412758 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -36,9 +36,9 @@ impl Shell { let shell = get_shell(None).expect("no shell detected"); for (p, tv) in ts.list_current_installed_versions(&config) { - let source = &ts.versions.get(&p.name).unwrap().source; + let source = &ts.versions.get(p.name()).unwrap().source; if matches!(source, ToolSource::Argument) { - let k = format!("RTX_{}_VERSION", p.name.to_uppercase()); + let k = format!("RTX_{}_VERSION", p.name().to_uppercase()); let op = if self.unset { shell.unset_env(&k) } else { diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 38a2e5f01..6609ac3e5 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -49,7 +49,7 @@ impl SyncNode { } fn run_brew(self, mut config: Config, out: &mut Output) -> Result<()> { - let tool = config.get_or_create_tool(&PluginName::from("node")); + let tool = config.get_or_create_plugin(&PluginName::from("node")); let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); let installed_versions_path = dirs::INSTALLS.join("node"); @@ -70,7 +70,7 @@ impl SyncNode { } fn run_nvm(self, mut config: Config, out: &mut Output) -> Result<()> { - let tool = config.get_or_create_tool(&PluginName::from("node")); + let tool = config.get_or_create_plugin(&PluginName::from("node")); let nvm_versions_path = NVM_DIR.join("versions").join("node"); let installed_versions_path = dirs::INSTALLS.join("node"); @@ -88,7 +88,7 @@ impl SyncNode { } fn run_nodenv(self, mut config: Config, out: &mut Output) -> Result<()> { - let tool = config.get_or_create_tool(&PluginName::from("node")); + let tool = config.get_or_create_plugin(&PluginName::from("node")); let nodenv_versions_path = NODENV_ROOT.join("versions"); let installed_versions_path = dirs::INSTALLS.join("node"); diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 234609854..2f2be6e90 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -21,7 +21,7 @@ pub struct SyncPython { impl SyncPython { pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let python = config.get_or_create_tool(&PluginName::from("python")); + let python = config.get_or_create_plugin(&PluginName::from("python")); let pyenv_versions_path = PYENV_ROOT.join("versions"); let installed_python_versions_path = dirs::INSTALLS.join("python"); diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index a33b8714c..b17f99b97 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -32,15 +32,15 @@ impl Uninstall { let mut tool_versions = vec![]; if self.all { for runtime in runtimes { - let tool = config.get_or_create_tool(&runtime.plugin); + let tool = config.get_or_create_plugin(&runtime.plugin); let query = runtime.tvr.map(|tvr| tvr.version()).unwrap_or_default(); let tvs = tool .list_installed_versions()? .into_iter() .filter(|v| v.starts_with(&query)) .map(|v| { - let tvr = ToolVersionRequest::new(tool.name.clone(), &v); - let tv = ToolVersion::new(&tool, tvr, Default::default(), v); + let tvr = ToolVersionRequest::new(tool.name().into(), &v); + let tv = ToolVersion::new(tool.clone(), tvr, Default::default(), v); (tool.clone(), tv) }) .collect::>(); @@ -53,10 +53,10 @@ impl Uninstall { tool_versions = runtimes .into_iter() .map(|a| { - let tool = config.get_or_create_tool(&a.plugin); + let tool = config.get_or_create_plugin(&a.plugin); let tvs = match a.tvr { Some(tvr) => { - vec![tvr.resolve(&config, &tool, Default::default(), false)?] + vec![tvr.resolve(&config, tool.clone(), Default::default(), false)?] } None => { let ts = ToolsetBuilder::new().build(&mut config)?; diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index bb75342c8..65816ebfb 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -7,9 +7,9 @@ use eyre::WrapErr; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; use crate::runtime_symlinks; use crate::shims; -use crate::tool::Tool; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::ProgressReport; @@ -82,7 +82,7 @@ impl Upgrade { ts.install_versions(config, new_versions, &mpr, false)?; for (tool, tv) in to_remove { let mut pr = mpr.add(); - self.uninstall_old_version(config, &tool, &tv, &mut pr)?; + self.uninstall_old_version(config, tool.clone(), &tv, &mut pr)?; } let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; @@ -94,7 +94,7 @@ impl Upgrade { fn uninstall_old_version( &self, config: &Config, - tool: &Tool, + tool: Arc, tv: &ToolVersion, pr: &mut ProgressReport, ) -> Result<()> { @@ -112,7 +112,7 @@ impl Upgrade { } } -type OutputVec = Vec<(Arc, ToolVersion, String)>; +type OutputVec = Vec<(Arc, ToolVersion, String)>; #[cfg(test)] pub mod tests { diff --git a/src/cli/where.rs b/src/cli/where.rs index 6f0408cf7..8b0368fe5 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -47,7 +47,7 @@ impl Where { _ => self.tool, }; - let plugin = match config.tools.get(&runtime.plugin) { + let plugin = match config.plugins.get(&runtime.plugin) { Some(plugin) => plugin, None => Err(PluginNotInstalled(runtime.plugin.clone()))?, }; @@ -55,7 +55,7 @@ impl Where { match runtime .tvr .as_ref() - .map(|tvr| tvr.resolve(&config, plugin, Default::default(), false)) + .map(|tvr| tvr.resolve(&config, plugin.clone(), Default::default(), false)) { Some(Ok(tv)) if plugin.is_version_installed(&tv) => { rtxprintln!(out, "{}", tv.install_path().to_string_lossy()); diff --git a/src/cli/which.rs b/src/cli/which.rs index 0b93b984c..034d6826f 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -36,7 +36,7 @@ impl Which { if self.version { rtxprintln!(out, "{}", tv.version); } else if self.plugin { - rtxprintln!(out, "{}", p.name); + rtxprintln!(out, "{p}"); } else { let path = p.which(&config, &ts, &tv, &self.bin_name)?; rtxprintln!(out, "{}", path.unwrap().display()); diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 758a3e551..cd9d83699 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -7,8 +7,7 @@ use color_eyre::eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::Settings; -use crate::plugins::PluginName; -use crate::tool::Tool; +use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; #[derive(Debug)] @@ -18,14 +17,14 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(settings: &Settings, path: PathBuf, plugins: &[&Arc]) -> Result { + pub fn parse(settings: &Settings, path: PathBuf, plugins: &[&Arc]) -> Result { let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.clone())); for plugin in plugins { let version = plugin.parse_legacy_file(&path, settings)?; for version in version.split_whitespace() { toolset.add_version( - ToolVersionRequest::new(plugin.name.to_string(), version), + ToolVersionRequest::new(plugin.name().to_string(), version), Default::default(), ); } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 8b1445ca1..a36ae3fc4 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -104,9 +104,13 @@ impl dyn ConfigFile { .into_iter() .map(|tvr| { if pin { - let plugin = config.tools.get(&plugin).unwrap(); - let tv = - tvr.resolve(config, plugin, Default::default(), ts.latest_versions)?; + let plugin = config.plugins.get(&plugin).unwrap(); + let tv = tvr.resolve( + config, + plugin.clone(), + Default::default(), + ts.latest_versions, + )?; Ok(tv.version) } else { Ok(tvr.version()) diff --git a/src/config/mod.rs b/src/config/mod.rs index ec13b8bd9..52045096f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -19,10 +19,9 @@ use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::tracking::Tracker; use crate::file::display_path; -use crate::plugins::core::{CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; +use crate::plugins::core::{PluginMap, CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; -use crate::tool::Tool; use crate::{dirs, env, file, hook_env}; pub mod config_file; @@ -31,14 +30,14 @@ mod tracking; type AliasMap = BTreeMap>; type ConfigMap = IndexMap>; -type ToolMap = BTreeMap>; +type ToolMap = BTreeMap>; #[derive(Debug, Default)] pub struct Config { pub settings: Settings, pub global_config: RtxToml, pub config_files: ConfigMap, - pub tools: ToolMap, + pub plugins: PluginMap, pub env: BTreeMap, pub env_sources: HashMap, pub path_dirs: Vec, @@ -57,11 +56,11 @@ impl Config { .preloaded(global_config.settings()?) .load()?; let config_filenames = load_config_filenames(&settings, &BTreeMap::new()); - let tools = load_tools(&settings)?; + let plugins = load_plugins(&settings)?; let config_files = load_all_config_files( &settings, &config_filenames, - &tools, + &plugins, &BTreeMap::new(), ConfigMap::new(), )?; @@ -72,14 +71,14 @@ impl Config { let settings = settings.load()?; trace!("Settings: {:#?}", settings); - let legacy_files = load_legacy_files(&settings, &tools); + let legacy_files = load_legacy_files(&settings, &plugins); let config_filenames = load_config_filenames(&settings, &legacy_files); let config_track = track_config_files(&config_filenames); let config_files = load_all_config_files( &settings, &config_filenames, - &tools, + &plugins, &legacy_files, config_files, ); @@ -115,7 +114,7 @@ impl Config { config_files, settings, global_config, - tools, + plugins, should_exit_early, repo_urls, }; @@ -150,13 +149,13 @@ impl Config { self.settings.verbose || !console::user_attended_stderr() } - pub fn resolve_alias(&self, plugin_name: &PluginName, v: &str) -> Result { + pub fn resolve_alias(&self, plugin_name: &str, v: &str) -> Result { if let Some(plugin_aliases) = self.aliases.get(plugin_name) { if let Some(alias) = plugin_aliases.get(v) { return Ok(alias.clone()); } } - if let Some(plugin) = self.tools.get(plugin_name) { + if let Some(plugin) = self.plugins.get(plugin_name) { if let Some(alias) = plugin.get_aliases(&self.settings)?.get(v) { return Ok(alias.clone()); } @@ -164,28 +163,25 @@ impl Config { Ok(v.to_string()) } - pub fn external_plugins(&self) -> Vec<(&PluginName, Arc)> { - self.tools + pub fn external_plugins(&self) -> Vec<(&PluginName, Arc)> { + self.plugins .iter() - .filter(|(_, tool)| matches!(tool.plugin.get_type(), PluginType::External)) + .filter(|(_, tool)| matches!(tool.get_type(), PluginType::External)) .map(|(name, tool)| (name, tool.clone())) .collect() } - pub fn get_or_create_tool(&mut self, plugin_name: &PluginName) -> Arc { - self.tools + pub fn get_or_create_plugin(&mut self, plugin_name: &PluginName) -> Arc { + self.plugins .entry(plugin_name.clone()) - .or_insert_with(|| { - let plugin = ExternalPlugin::new(plugin_name.clone()); - build_tool(plugin_name.clone(), Box::new(plugin)) - }) + .or_insert_with(|| ExternalPlugin::newa(plugin_name.clone())) .clone() } fn load_all_aliases(&self) -> AliasMap { let mut aliases: AliasMap = self.aliases.clone(); let plugin_aliases: Vec<_> = self - .tools + .plugins .values() .par_bridge() .map(|plugin| { @@ -196,7 +192,7 @@ impl Config { BTreeMap::new() } }; - (plugin.name.clone(), aliases) + (plugin.name(), aliases) }) .collect(); for (plugin, plugin_aliases) in plugin_aliases { @@ -278,32 +274,23 @@ fn load_rtxrc() -> Result { } } -fn load_tools(settings: &Settings) -> Result { +fn load_plugins(settings: &Settings) -> Result { let mut tools = CORE_PLUGINS.clone(); if settings.experimental { tools.extend(EXPERIMENTAL_CORE_PLUGINS.clone()); } - let plugins = ExternalPlugin::list()? - .into_par_iter() - .map(|p| { - ( - p.name.clone(), - Arc::new(Tool::new(p.name.clone(), Box::new(p))), - ) - }) - .collect::>(); - tools.extend(plugins); + let external = ExternalPlugin::list()? + .into_iter() + .map(|e| (e.name().into(), e)) + .collect::)>>(); + tools.extend(external); for tool in &settings.disable_tools { tools.remove(tool); } Ok(tools) } -fn build_tool(name: PluginName, plugin: Box) -> Arc { - Arc::new(Tool::new(name, plugin)) -} - -fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap> { +fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap> { if !settings.legacy_version_file { return BTreeMap::new(); } @@ -314,13 +301,13 @@ fn load_legacy_files(settings: &Settings, tools: &ToolMap) -> BTreeMap Some( filenames .iter() - .map(|f| (f.to_string(), tool.name.to_string())) + .map(|f| (f.to_string(), tool.name().to_string())) .collect_vec(), ), Err(err) => { @@ -394,7 +381,7 @@ pub fn global_config_files() -> Vec { fn load_all_config_files( settings: &Settings, config_filenames: &[PathBuf], - tools: &ToolMap, + tools: &PluginMap, legacy_filenames: &BTreeMap>, mut existing: ConfigMap, ) -> Result { @@ -498,9 +485,9 @@ 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 - .tools + .plugins .iter() - .filter(|(_, t)| matches!(t.plugin.get_type(), PluginType::External)) + .filter(|(_, t)| matches!(t.get_type(), PluginType::External)) .map(|(p, _)| p.to_string()) .collect::>(); let config_files = self diff --git a/src/main.rs b/src/main.rs index 503cfa763..228a00195 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,7 +60,6 @@ pub mod tera; mod test; pub mod timeout; mod toml; -mod tool; mod toolset; mod ui; diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index d82574eb3..0cdae088d 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::ffi::OsString; +use std::iter::Iterator; use std::path::PathBuf; use std::sync::Arc; @@ -19,7 +20,6 @@ use crate::plugins::core::node_build::NodeBuildPlugin; use crate::plugins::core::ruby::RubyPlugin; use crate::plugins::{Plugin, PluginName}; use crate::timeout::run_with_timeout; -use crate::tool::Tool; use crate::toolset::ToolVersion; use crate::{dirs, env}; @@ -32,38 +32,35 @@ mod node_build; mod python; mod ruby; -type ToolMap = BTreeMap>; +pub type PluginMap = BTreeMap>; -pub static CORE_PLUGINS: Lazy = Lazy::new(|| { - build_core_plugins(vec![ - Box::new(GoPlugin::new()), - Box::new(JavaPlugin::new()), +pub static CORE_PLUGINS: Lazy = Lazy::new(|| { + let plugins: Vec> = vec![ + Arc::new(GoPlugin::new()), + Arc::new(JavaPlugin::new()), if *RTX_NODE_BUILD == Some(true) { - Box::new(NodeBuildPlugin::new()) + Arc::new(NodeBuildPlugin::new()) } else { - Box::new(NodePlugin::new()) + Arc::new(NodePlugin::new()) }, - Box::new(PythonPlugin::new()), - Box::new(RubyPlugin::new()), - ]) + Arc::new(PythonPlugin::new()), + Arc::new(RubyPlugin::new()), + ]; + plugins + .into_iter() + .map(|plugin| (plugin.name().to_string(), plugin)) + .collect() }); -pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { - build_core_plugins(vec![ - Box::new(BunPlugin::new()), - Box::new(DenoPlugin::new()), - ]) +pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { + let plugins: Vec> = + vec![Arc::new(BunPlugin::new()), Arc::new(DenoPlugin::new())]; + plugins + .into_iter() + .map(|plugin| (plugin.name().to_string(), plugin)) + .collect() }); -fn build_core_plugins(tools: Vec>) -> ToolMap { - ToolMap::from_iter(tools.into_iter().map(|plugin| { - ( - plugin.name().to_string(), - Arc::new(Tool::new(plugin.name().to_string(), plugin)), - ) - })) -} - #[derive(Debug)] pub struct CorePlugin { pub cache_path: PathBuf, diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index b772e4343..48f133354 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -4,6 +4,7 @@ use std::fs; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::exit; +use std::sync::Arc; use clap::Command; use color_eyre::eyre::{eyre, Result, WrapErr}; @@ -80,11 +81,14 @@ impl ExternalPlugin { name, } } + pub fn newa(name: PluginName) -> Arc { + Arc::new(Self::new(name)) + } - pub fn list() -> Result> { + pub fn list() -> Result>> { Ok(file::dir_subdirs(&dirs::PLUGINS)? .into_iter() - .map(Self::new) + .map(Self::newa) .collect()) } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index e52d6db11..1f3352d60 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,7 +1,8 @@ use std::collections::{BTreeMap, HashMap}; -use std::fmt::Debug; +use std::fmt::{Debug, Display}; use std::fs::File; use std::path::{Path, PathBuf}; +use std::sync::Arc; use clap::Command; use color_eyre::eyre::Result; @@ -19,7 +20,6 @@ use crate::file::{display_path, remove_all, remove_all_with_warning}; use crate::install_context::InstallContext; use crate::lock_file::LockFile; use crate::runtime_symlinks::is_runtime_symlink; -use crate::tool::Tool; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; @@ -73,8 +73,8 @@ pub trait Plugin: Debug + Send + Sync { } } } - fn is_version_outdated(&self, tool: &Tool, config: &Config, tv: &ToolVersion) -> bool { - let latest = match tv.latest_version(config, tool) { + fn is_version_outdated(&self, config: &Config, tv: &ToolVersion, p: Arc) -> bool { + let latest = match tv.latest_version(config, p) { Ok(latest) => latest, Err(e) => { debug!("Error getting latest version for {}: {:#}", self.name(), e); @@ -393,6 +393,29 @@ fn rmdir(dir: &Path, pr: &ProgressReport) -> Result<()> { }) } +impl Display for dyn Plugin { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name()) + } +} +impl Eq for dyn Plugin {} +impl PartialEq for dyn Plugin { + fn eq(&self, other: &Self) -> bool { + self.get_type() == other.get_type() && self.name() == other.name() + } +} +impl PartialOrd for dyn Plugin { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for dyn Plugin { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.name().cmp(other.name()) + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] pub enum PluginType { #[allow(dead_code)] Core, @@ -405,7 +428,6 @@ mod tests { use crate::assert_cli; use crate::config::Settings; - use crate::tool::Tool; use super::*; @@ -413,14 +435,13 @@ mod tests { fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); let settings = Settings::default(); - let plugin = ExternalPlugin::new(PluginName::from("tiny")); - let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); - let version = tool + let plugin = ExternalPlugin::newa(PluginName::from("tiny")); + let version = plugin .latest_version(&settings, Some("1.0.0".into())) .unwrap() .unwrap(); assert_str_eq!(version, "1.0.0"); - let version = tool.latest_version(&settings, None).unwrap().unwrap(); + let version = plugin.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "3.1.0"); } @@ -428,8 +449,7 @@ mod tests { fn test_latest_stable() { let settings = Settings::default(); let plugin = ExternalPlugin::new(PluginName::from("dummy")); - let tool = Tool::new(plugin.name.clone(), Box::new(plugin)); - let version = tool.latest_version(&settings, None).unwrap().unwrap(); + let version = plugin.latest_version(&settings, None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); } } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index c2ec9ad43..659ec4e32 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; +use std::sync::Arc; use color_eyre::eyre::Result; use indexmap::IndexMap; @@ -9,13 +10,13 @@ use versions::Versioning; use crate::config::Config; use crate::file::make_symlink; -use crate::tool::Tool; +use crate::plugins::Plugin; use crate::{dirs, file}; pub fn rebuild(config: &Config) -> Result<()> { - for plugin in config.tools.values() { - let symlinks = list_symlinks(config, plugin)?; - let installs_dir = dirs::INSTALLS.join(&plugin.name); + for plugin in config.plugins.values() { + let symlinks = list_symlinks(config, plugin.clone())?; + let installs_dir = dirs::INSTALLS.join(plugin.name()); for (from, to) in symlinks { let from = installs_dir.join(from); if from.exists() { @@ -28,17 +29,17 @@ pub fn rebuild(config: &Config) -> Result<()> { } make_symlink(&to, &from)?; } - remove_missing_symlinks(plugin)?; + remove_missing_symlinks(plugin.clone())?; // attempt to remove the installs dir (will fail if not empty) let _ = file::remove_dir(&installs_dir); } Ok(()) } -fn list_symlinks(config: &Config, plugin: &Tool) -> Result> { +fn list_symlinks(config: &Config, plugin: Arc) -> Result> { let mut symlinks = IndexMap::new(); let rel_path = |x: &String| PathBuf::from(".").join(x.clone()); - for v in installed_versions(plugin)? { + for v in installed_versions(&plugin)? { let versions = Versioning::new(&v).expect("invalid version"); let mut partial = vec![]; while versions.nth(partial.len() + 1).is_some() { @@ -49,7 +50,7 @@ fn list_symlinks(config: &Config, plugin: &Tool) -> Result Result Result> { +fn installed_versions(plugin: &Arc) -> Result> { let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let versions = plugin .list_installed_versions()? @@ -78,8 +79,8 @@ fn installed_versions(plugin: &Tool) -> Result> { Ok(versions) } -fn remove_missing_symlinks(plugin: &Tool) -> Result<()> { - let installs_dir = dirs::INSTALLS.join(&plugin.name); +fn remove_missing_symlinks(plugin: Arc) -> Result<()> { + let installs_dir = dirs::INSTALLS.join(plugin.name()); if !installs_dir.exists() { return Ok(()); } @@ -113,9 +114,8 @@ mod tests { #[test] fn test_list_symlinks() { let config = Config::load().unwrap(); - let plugin = ExternalPlugin::new(PluginName::from("tiny")); - let tool = Tool::new(String::from("tiny"), Box::new(plugin)); - let symlinks = list_symlinks(&config, &tool).unwrap(); + let plugin = ExternalPlugin::newa(PluginName::from("tiny")); + let symlinks = list_symlinks(&config, plugin).unwrap(); assert_debug_snapshot!(symlinks); } } diff --git a/src/shims.rs b/src/shims.rs index 1f723a2c8..a94888997 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -3,6 +3,7 @@ use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; use std::process::exit; +use std::sync::Arc; use color_eyre::eyre::{eyre, Result}; use eyre::WrapErr; @@ -16,7 +17,7 @@ use crate::fake_asdf; use crate::file::{create_dir_all, display_path, remove_all}; use crate::lock_file::LockFile; use crate::output::Output; -use crate::tool::Tool; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; @@ -90,7 +91,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let shims: HashSet = ts .list_installed_versions(config)? .into_par_iter() - .flat_map(|(t, tv)| match list_tool_bins(config, ts, &t, &tv) { + .flat_map(|(t, tv)| match list_tool_bins(config, ts, t.clone(), &tv) { Ok(paths) => paths, Err(e) => { warn!("Error listing bin paths for {}: {:#}", tv, e); @@ -116,8 +117,8 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let symlink_path = dirs::SHIMS.join(shim); remove_all(&symlink_path)?; } - for plugin in config.tools.values() { - match plugin.plugin_path.join("shims").read_dir() { + for plugin in config.plugins.values() { + match dirs::PLUGINS.join(plugin.name()).join("shims").read_dir() { Ok(files) => { for bin in files { let bin = bin?; @@ -139,7 +140,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { fn list_tool_bins( config: &Config, ts: &Toolset, - t: &Tool, + t: Arc, tv: &ToolVersion, ) -> Result> { Ok(t.list_bin_paths(config, ts, tv)? diff --git a/src/tool.rs b/src/tool.rs deleted file mode 100644 index 476ddab8a..000000000 --- a/src/tool.rs +++ /dev/null @@ -1,211 +0,0 @@ -use std::cmp::Ordering; -use std::collections::{BTreeMap, HashMap}; -use std::fmt::{Debug, Display}; - -use std::path::{Path, PathBuf}; - -use clap::Command; -use color_eyre::eyre::Result; - -use crate::config::{Config, Settings}; - -use crate::dirs; -use crate::install_context::InstallContext; -use crate::plugins::Plugin; -use crate::toolset::{ToolVersion, Toolset}; -use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::ProgressReport; - -#[derive(Debug)] -pub struct Tool { - pub name: String, - pub plugin: Box, - pub plugin_path: PathBuf, - pub installs_path: PathBuf, - pub cache_path: PathBuf, - pub downloads_path: PathBuf, -} - -impl Tool { - pub fn new(name: String, plugin: Box) -> Self { - Self { - plugin_path: dirs::PLUGINS.join(&name), - installs_path: dirs::INSTALLS.join(&name), - cache_path: dirs::CACHE.join(&name), - downloads_path: dirs::DOWNLOADS.join(&name), - name, - plugin, - } - } - - pub fn is_installed(&self) -> bool { - self.plugin.is_installed() - } - - pub fn get_remote_url(&self) -> Option { - self.plugin.get_remote_url() - } - - pub fn current_sha_short(&self) -> Result { - self.plugin.current_sha_short() - } - - pub fn current_abbrev_ref(&self) -> Result { - self.plugin.current_abbrev_ref() - } - - pub fn list_installed_versions(&self) -> Result> { - self.plugin.list_installed_versions() - } - - pub fn list_installed_versions_matching(&self, query: &str) -> Result> { - self.plugin.list_installed_versions_matching(query) - } - - pub fn list_remote_versions(&self, settings: &Settings) -> Result> { - self.plugin.list_remote_versions(settings) - } - - pub fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - self.plugin.list_versions_matching(settings, query) - } - - pub fn latest_version( - &self, - settings: &Settings, - query: Option, - ) -> Result> { - self.plugin.latest_version(settings, query) - } - - pub fn latest_installed_version(&self, query: Option) -> Result> { - self.plugin.latest_installed_version(query) - } - - pub fn get_aliases(&self, settings: &Settings) -> Result> { - self.plugin.get_aliases(settings) - } - - pub fn legacy_filenames(&self, settings: &Settings) -> Result> { - self.plugin.legacy_filenames(settings) - } - - pub fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { - self.plugin.decorate_progress_bar(pr, tv); - } - - pub fn is_version_installed(&self, tv: &ToolVersion) -> bool { - self.plugin.is_version_installed(tv) - } - - pub fn is_version_outdated(&self, config: &Config, tv: &ToolVersion) -> bool { - self.plugin.is_version_outdated(self, config, tv) - } - - pub fn symlink_path(&self, tv: &ToolVersion) -> Option { - self.plugin.symlink_path(tv) - } - - pub fn create_symlink(&self, version: &str, target: &Path) -> Result<()> { - self.plugin.create_symlink(version, target) - } - - pub fn install_version(&self, ctx: InstallContext) -> Result<()> { - self.plugin.install_version(ctx) - } - - pub fn uninstall_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - dryrun: bool, - ) -> Result<()> { - self.plugin.uninstall_version(config, tv, pr, dryrun) - } - - pub fn ensure_installed( - &self, - config: &mut Config, - mpr: Option<&MultiProgressReport>, - force: bool, - ) -> Result<()> { - self.plugin.ensure_installed(config, mpr, force) - } - pub fn update(&self, git_ref: Option) -> Result<()> { - self.plugin.update(git_ref) - } - pub fn uninstall(&self, pr: &ProgressReport) -> Result<()> { - self.plugin.uninstall(pr) - } - pub fn purge(&self, pr: &ProgressReport) -> Result<()> { - self.plugin.purge(pr) - } - - pub fn external_commands(&self) -> Result> { - self.plugin.external_commands() - } - pub fn execute_external_command( - &self, - config: &Config, - command: &str, - args: Vec, - ) -> Result<()> { - self.plugin.execute_external_command(config, command, args) - } - pub fn parse_legacy_file(&self, path: &Path, settings: &Settings) -> Result { - self.plugin.parse_legacy_file(path, settings) - } - pub fn list_bin_paths( - &self, - config: &Config, - ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { - self.plugin.list_bin_paths(config, ts, tv) - } - pub fn exec_env( - &self, - config: &Config, - ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { - self.plugin.exec_env(config, ts, tv) - } - - pub fn which( - &self, - config: &Config, - ts: &Toolset, - tv: &ToolVersion, - bin_name: &str, - ) -> Result> { - self.plugin.which(config, ts, tv, bin_name) - } -} - -impl PartialEq for Tool { - fn eq(&self, other: &Self) -> bool { - self.plugin_path == other.plugin_path - } -} - -impl Display for Tool { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", &self.name) - } -} - -impl PartialOrd for Tool { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.name.cmp(&other.name)) - } -} - -impl Ord for Tool { - fn cmp(&self, other: &Self) -> Ordering { - self.name.cmp(&other.name) - } -} - -impl Eq for Tool {} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 5047e1f56..466f947b4 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -5,7 +5,6 @@ use std::sync::{Arc, Mutex}; use std::thread; use color_eyre::eyre::Result; - use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; @@ -20,10 +19,9 @@ use crate::config::Config; use crate::env; use crate::install_context::InstallContext; use crate::path_env::PathEnv; -use crate::plugins::PluginName; +use crate::plugins::{Plugin, PluginName}; use crate::runtime_symlinks; use crate::shims; -use crate::tool::Tool; use crate::ui::multi_progress_report::MultiProgressReport; mod builder; @@ -97,14 +95,11 @@ impl Toolset { } pub fn list_missing_plugins(&self, config: &mut Config) -> Vec { - for plugin in self.versions.keys() { - config.get_or_create_tool(plugin); - } self.versions .keys() - .map(|p| config.tools.get(p).unwrap()) + .map(|p| config.get_or_create_plugin(p)) .filter(|p| !p.is_installed()) - .map(|p| p.name.clone()) + .map(|p| p.name().into()) .collect() } @@ -123,7 +118,7 @@ impl Toolset { .into_iter() .group_by(|v| v.plugin_name.clone()) .into_iter() - .map(|(pn, v)| (config.get_or_create_tool(&pn), v.collect_vec())) + .map(|(pn, v)| (config.get_or_create_plugin(&pn), v.collect_vec())) .collect(); for (t, _) in &queue { if !t.is_installed() { @@ -144,7 +139,12 @@ impl Toolset { let ctx = InstallContext { config, ts, - tv: tv.request.resolve(config, &t, tv.opts.clone(), true)?, + tv: tv.request.resolve( + config, + t.clone(), + tv.opts.clone(), + true, + )?, pr: mpr.add(), force, }; @@ -167,7 +167,7 @@ impl Toolset { self.versions .iter() .map(|(p, tvl)| { - let p = config.tools.get(p).unwrap(); + let p = config.plugins.get(p).unwrap(); (p, tvl) }) .flat_map(|(p, tvl)| { @@ -181,25 +181,25 @@ impl Toolset { pub fn list_installed_versions( &self, config: &Config, - ) -> Result, ToolVersion)>> { - let current_versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = self + ) -> Result, ToolVersion)>> { + let current_versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = self .list_current_versions(config) .into_iter() - .map(|(p, tv)| ((p.name.clone(), tv.version.clone()), (p.clone(), tv))) + .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p.clone(), tv))) .collect(); let versions = config - .tools + .plugins .values() .collect_vec() .into_par_iter() .map(|p| { let versions = p.list_installed_versions()?; Ok(versions.into_iter().map(|v| { - match current_versions.get(&(p.name.clone(), v.clone())) { + match current_versions.get(&(p.name().into(), v.clone())) { Some((p, tv)) => (p.clone(), tv.clone()), None => { - let tv = ToolVersionRequest::new(p.name.clone(), &v) - .resolve(config, p, Default::default(), false) + let tv = ToolVersionRequest::new(p.name().into(), &v) + .resolve(config, p.clone(), Default::default(), false) .unwrap(); (p.clone(), tv) } @@ -213,16 +213,19 @@ impl Toolset { Ok(versions) } - pub fn list_versions_by_plugin(&self, config: &Config) -> Vec<(Arc, &Vec)> { + pub fn list_versions_by_plugin( + &self, + config: &Config, + ) -> Vec<(Arc, &Vec)> { self.versions .iter() .map(|(p, v)| { - let p = config.tools.get(p).unwrap(); + let p = config.plugins.get(p).unwrap(); (p.clone(), &v.versions) }) .collect() } - pub fn list_current_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion)> { + pub fn list_current_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion)> { self.list_versions_by_plugin(config) .iter() .flat_map(|(p, v)| v.iter().map(|v| (p.clone(), v.clone()))) @@ -231,13 +234,16 @@ impl Toolset { pub fn list_current_installed_versions( &self, config: &Config, - ) -> Vec<(Arc, ToolVersion)> { + ) -> Vec<(Arc, ToolVersion)> { self.list_current_versions(config) .into_iter() .filter(|(p, v)| p.is_version_installed(v)) .collect() } - pub fn list_outdated_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion, String)> { + pub fn list_outdated_versions( + &self, + config: &Config, + ) -> Vec<(Arc, ToolVersion, String)> { self.list_current_versions(config) .into_iter() .filter_map(|(t, tv)| { @@ -245,10 +251,10 @@ impl Toolset { // do not consider symlinked versions to be outdated return None; } - let latest = match tv.latest_version(config, &t) { + let latest = match tv.latest_version(config, t.clone()) { Ok(latest) => latest, Err(e) => { - warn!("Error getting latest version for {}: {:#}", t.name, e); + warn!("Error getting latest version for {t}: {e:#}"); return None; } }; @@ -316,7 +322,7 @@ impl Toolset { }) .collect() } - pub fn which(&self, config: &Config, bin_name: &str) -> Option<(Arc, ToolVersion)> { + pub fn which(&self, config: &Config, bin_name: &str) -> Option<(Arc, ToolVersion)> { self.list_current_installed_versions(config) .into_par_iter() .find_first(|(p, tv)| { diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 05e88a888..f9b07ad01 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -1,6 +1,7 @@ use std::fmt::{Display, Formatter}; use std::fs; use std::path::PathBuf; +use std::sync::Arc; use color_eyre::eyre::Result; use versions::{Chunk, Version}; @@ -8,8 +9,7 @@ use versions::{Chunk, Version}; use crate::config::Config; use crate::dirs; use crate::hash::hash_to_str; -use crate::plugins::PluginName; -use crate::tool::Tool; +use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; /// represents a single version of a tool for a particular plugin @@ -23,13 +23,13 @@ pub struct ToolVersion { impl ToolVersion { pub fn new( - tool: &Tool, + tool: Arc, request: ToolVersionRequest, opts: ToolVersionOptions, version: String, ) -> Self { ToolVersion { - plugin_name: tool.name.to_string(), + plugin_name: tool.name().to_string(), version, request, opts, @@ -38,7 +38,7 @@ impl ToolVersion { pub fn resolve( config: &Config, - tool: &Tool, + tool: Arc, request: ToolVersionRequest, opts: ToolVersionOptions, latest_versions: bool, @@ -100,7 +100,7 @@ impl ToolVersion { .join(&self.plugin_name) .join(self.tv_pathname()) } - pub fn latest_version(&self, config: &Config, tool: &Tool) -> Result { + pub fn latest_version(&self, config: &Config, tool: Arc) -> Result { let tv = self .request .resolve(config, tool, self.opts.clone(), true)?; @@ -125,13 +125,13 @@ impl ToolVersion { fn resolve_version( config: &Config, - tool: &Tool, + tool: Arc, request: ToolVersionRequest, latest_versions: bool, v: &str, opts: ToolVersionOptions, ) -> Result { - let v = config.resolve_alias(&tool.name, v)?; + let v = config.resolve_alias(tool.name(), v)?; match v.split_once(':') { Some(("ref", r)) => { return Ok(Self::resolve_ref(tool, r.to_string(), opts)); @@ -149,7 +149,7 @@ impl ToolVersion { _ => (), } - let build = |v| Ok(Self::new(tool, request.clone(), opts.clone(), v)); + let build = |v| Ok(Self::new(tool.clone(), request.clone(), opts.clone(), v)); if !tool.is_installed() { return build(v); } @@ -189,7 +189,7 @@ impl ToolVersion { /// resolve a version like `sub-1:12.0.0` which becomes `11.0.0`, `sub-0.1:12.1.0` becomes `12.0.0` fn resolve_sub( config: &Config, - tool: &Tool, + tool: Arc, request: ToolVersionRequest, latest_versions: bool, sub: &str, @@ -198,7 +198,7 @@ impl ToolVersion { ) -> Result { let v = match v { "latest" => tool.latest_version(&config.settings, None)?.unwrap(), - _ => config.resolve_alias(&tool.name, v)?, + _ => config.resolve_alias(tool.name(), v)?, }; let v = version_sub(&v, sub); Self::resolve_version(config, tool, request, latest_versions, &v, opts) @@ -206,7 +206,7 @@ impl ToolVersion { fn resolve_prefix( config: &Config, - tool: &Tool, + tool: Arc, request: ToolVersionRequest, prefix: &str, opts: ToolVersionOptions, @@ -220,15 +220,19 @@ impl ToolVersion { Ok(Self::new(tool, request, opts, v.to_string())) } - fn resolve_ref(tool: &Tool, r: String, opts: ToolVersionOptions) -> Self { - let request = ToolVersionRequest::Ref(tool.name.clone(), r); + fn resolve_ref(tool: Arc, r: String, opts: ToolVersionOptions) -> Self { + let request = ToolVersionRequest::Ref(tool.name().into(), r); let version = request.version(); Self::new(tool, request, opts, version) } - fn resolve_path(tool: &Tool, path: PathBuf, opts: ToolVersionOptions) -> Result { + fn resolve_path( + tool: Arc, + path: PathBuf, + opts: ToolVersionOptions, + ) -> Result { let path = fs::canonicalize(path)?; - let request = ToolVersionRequest::Path(tool.name.clone(), path); + let request = ToolVersionRequest::Path(tool.name().into(), path); let version = request.version(); Ok(Self::new(tool, request, opts, version)) } diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 25da135f9..88894056d 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -22,7 +22,7 @@ impl ToolVersionList { } pub fn resolve(&mut self, config: &Config, latest_versions: bool) { self.versions.clear(); - let plugin = match config.tools.get(&self.plugin_name) { + let plugin = match config.plugins.get(&self.plugin_name) { Some(p) => p, _ => { debug!("Plugin {} is not installed", self.plugin_name); @@ -30,7 +30,7 @@ impl ToolVersionList { } }; for (tvr, opts) in &mut self.requests { - match tvr.resolve(config, plugin, opts.clone(), latest_versions) { + match tvr.resolve(config, plugin.clone(), opts.clone(), latest_versions) { Ok(v) => self.versions.push(v), Err(err) => warn!("failed to resolve tool version: {:#}", err), } @@ -40,10 +40,7 @@ impl ToolVersionList { #[cfg(test)] mod tests { - use std::sync::Arc; - use crate::plugins::ExternalPlugin; - use crate::tool::Tool; use crate::{dirs, env, file}; use super::*; @@ -52,9 +49,8 @@ mod tests { fn test_tool_version_list() { let mut config = Config::default(); let plugin_name = "tiny".to_string(); - let plugin = ExternalPlugin::new(plugin_name.clone()); - let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); - config.tools.insert(plugin_name.clone(), Arc::new(tool)); + let plugin = ExternalPlugin::newa(plugin_name.clone()); + config.plugins.insert(plugin_name.clone(), plugin); let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); tvl.requests.push(( ToolVersionRequest::new(plugin_name, "latest"), @@ -70,9 +66,8 @@ mod tests { file::remove_all(dirs::CACHE.join("dummy")).unwrap(); let mut config = Config::default(); let plugin_name = "dummy".to_string(); - let plugin = ExternalPlugin::new(plugin_name.clone()); - let tool = Tool::new(plugin_name.clone(), Box::new(plugin)); - config.tools.insert(plugin_name.clone(), Arc::new(tool)); + let plugin = ExternalPlugin::newa(plugin_name.clone()); + config.plugins.insert(plugin_name.clone(), plugin); let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); tvl.requests.push(( ToolVersionRequest::new(plugin_name, "latest"), diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index a21c338c3..4ceeb491b 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -1,29 +1,29 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; +use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::Config; -use crate::plugins::PluginName; -use crate::tool::Tool; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionOptions}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum ToolVersionRequest { - Version(PluginName, String), - Prefix(PluginName, String), - Ref(PluginName, String), - Path(PluginName, PathBuf), + Version(String, String), + Prefix(String, String), + Ref(String, String), + Path(String, PathBuf), Sub { - plugin_name: PluginName, + plugin_name: String, sub: String, orig_version: String, }, - System(PluginName), + System(String), } impl ToolVersionRequest { - pub fn new(plugin_name: PluginName, s: &str) -> Self { + pub fn new(plugin_name: String, s: &str) -> Self { let s = match s.split_once('-') { Some(("ref", r)) => format!("ref:{}", r), _ => s.to_string(), @@ -48,7 +48,7 @@ impl ToolVersionRequest { } } - pub fn plugin_name(&self) -> &PluginName { + pub fn plugin_name(&self) -> &String { match self { Self::Version(p, _) => p, Self::Prefix(p, _) => p, @@ -75,7 +75,7 @@ impl ToolVersionRequest { pub fn resolve( &self, config: &Config, - plugin: &Tool, + plugin: Arc, opts: ToolVersionOptions, latest_versions: bool, ) -> Result { From d6ee86e0477c763bc31f3c2b9330a4eded876275 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 11:13:17 -0600 Subject: [PATCH 1194/1891] completions: fix zsh completion (#1094) shfmt actually broke it. Fixes #1092 --- completions/_rtx | 1789 +++++++++++++++---------------- src/shell/completions/mod.rs | 4 +- src/templates/complete_zsh.tera | 103 -- 3 files changed, 890 insertions(+), 1006 deletions(-) delete mode 100644 src/templates/complete_zsh.tera diff --git a/completions/_rtx b/completions/_rtx index 4a8f0a2ce..5c29aa6b9 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -1,925 +1,912 @@ #compdef rtx _rtx() { - typeset -A opt_args - local context state line curcontext=$curcontext - local ret=1 + typeset -A opt_args + local context state line curcontext=$curcontext + local ret=1 - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_cmds' \ - '*::arg:->args' && ret=0 + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - activate) __rtx_activate_cmd && ret=0 ;; - a | aliases | alias) __rtx_alias_cmd && ret=0 ;; - asdf) __rtx_asdf_cmd && ret=0 ;; - bin-paths) __rtx_bin_paths_cmd && ret=0 ;; - cache) __rtx_cache_cmd && ret=0 ;; - complete | completions | completion) __rtx_completion_cmd && ret=0 ;; - current) __rtx_current_cmd && ret=0 ;; - deactivate) __rtx_deactivate_cmd && ret=0 ;; - direnv) __rtx_direnv_cmd && ret=0 ;; - doctor) __rtx_doctor_cmd && ret=0 ;; - e | env) __rtx_env_cmd && ret=0 ;; - env-vars) __rtx_env_vars_cmd && ret=0 ;; - x | exec) __rtx_exec_cmd && ret=0 ;; - g | global) __rtx_global_cmd && ret=0 ;; - hook-env) __rtx_hook_env_cmd && ret=0 ;; - implode) __rtx_implode_cmd && ret=0 ;; - i | install) __rtx_install_cmd && ret=0 ;; - latest) __rtx_latest_cmd && ret=0 ;; - link) __rtx_link_cmd && ret=0 ;; - l | local) __rtx_local_cmd && ret=0 ;; - list | ls) __rtx_ls_cmd && ret=0 ;; - list-all | list-remote | ls-remote) __rtx_ls_remote_cmd && ret=0 ;; - outdated) __rtx_outdated_cmd && ret=0 ;; - p | plugin | plugin-list | plugins) __rtx_plugins_cmd && ret=0 ;; - prune) __rtx_prune_cmd && ret=0 ;; - reshim) __rtx_reshim_cmd && ret=0 ;; - self-update) __rtx_self_update_cmd && ret=0 ;; - settings) __rtx_settings_cmd && ret=0 ;; - s | shell) __rtx_shell_cmd && ret=0 ;; - sync) __rtx_sync_cmd && ret=0 ;; - trust) __rtx_trust_cmd && ret=0 ;; - remove | rm | uninstall) __rtx_uninstall_cmd && ret=0 ;; - upgrade) __rtx_upgrade_cmd && ret=0 ;; - u | use) __rtx_use_cmd && ret=0 ;; - v | version) __rtx_version_cmd && ret=0 ;; - where) __rtx_where_cmd && ret=0 ;; - which) __rtx_which_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (activate) __rtx_activate_cmd && ret=0 ;; + (a|aliases|alias) __rtx_alias_cmd && ret=0 ;; + (asdf) __rtx_asdf_cmd && ret=0 ;; + (bin-paths) __rtx_bin_paths_cmd && ret=0 ;; + (cache) __rtx_cache_cmd && ret=0 ;; + (complete|completions|completion) __rtx_completion_cmd && ret=0 ;; + (current) __rtx_current_cmd && ret=0 ;; + (deactivate) __rtx_deactivate_cmd && ret=0 ;; + (direnv) __rtx_direnv_cmd && ret=0 ;; + (doctor) __rtx_doctor_cmd && ret=0 ;; + (e|env) __rtx_env_cmd && ret=0 ;; + (env-vars) __rtx_env_vars_cmd && ret=0 ;; + (x|exec) __rtx_exec_cmd && ret=0 ;; + (g|global) __rtx_global_cmd && ret=0 ;; + (hook-env) __rtx_hook_env_cmd && ret=0 ;; + (implode) __rtx_implode_cmd && ret=0 ;; + (i|install) __rtx_install_cmd && ret=0 ;; + (latest) __rtx_latest_cmd && ret=0 ;; + (link) __rtx_link_cmd && ret=0 ;; + (l|local) __rtx_local_cmd && ret=0 ;; + (list|ls) __rtx_ls_cmd && ret=0 ;; + (list-all|list-remote|ls-remote) __rtx_ls_remote_cmd && ret=0 ;; + (outdated) __rtx_outdated_cmd && ret=0 ;; + (p|plugin|plugin-list|plugins) __rtx_plugins_cmd && ret=0 ;; + (prune) __rtx_prune_cmd && ret=0 ;; + (reshim) __rtx_reshim_cmd && ret=0 ;; + (self-update) __rtx_self_update_cmd && ret=0 ;; + (settings) __rtx_settings_cmd && ret=0 ;; + (s|shell) __rtx_shell_cmd && ret=0 ;; + (sync) __rtx_sync_cmd && ret=0 ;; + (trust) __rtx_trust_cmd && ret=0 ;; + (remove|rm|uninstall) __rtx_uninstall_cmd && ret=0 ;; + (upgrade) __rtx_upgrade_cmd && ret=0 ;; + (u|use) __rtx_use_cmd && ret=0 ;; + (v|version) __rtx_version_cmd && ret=0 ;; + (where) __rtx_where_cmd && ret=0 ;; + (which) __rtx_which_cmd && ret=0 ;; + esac + ;; + esac - return ret -} -(($ + functions[__rtx_activate_cmd])) || - __rtx_activate_cmd() { - _arguments -s -S \ - '::shell_type:(bash fish nu xonsh zsh)' \ - '--status[Show "rtx\: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_alias_cmd])) || - __rtx_alias_cmd() { - _arguments -s -S \ - '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_alias_cmds' \ - '*::arg:->args' && ret=0 +return ret +} +(( $+functions[__rtx_activate_cmd] )) || +__rtx_activate_cmd() { + _arguments -s -S \ + '::shell_type:(bash fish nu xonsh zsh)' \ + '--status[Show "rtx\: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_alias_cmd] )) || +__rtx_alias_cmd() { + _arguments -s -S \ + '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_alias_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - get) __rtx_alias_get_cmd && ret=0 ;; - list | ls) __rtx_alias_ls_cmd && ret=0 ;; - add | create | set) __rtx_alias_set_cmd && ret=0 ;; - del | delete | remove | rm | unset) __rtx_alias_unset_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (get) __rtx_alias_get_cmd && ret=0 ;; + (list|ls) __rtx_alias_ls_cmd && ret=0 ;; + (add|create|set) __rtx_alias_set_cmd && ret=0 ;; + (del|delete|remove|rm|unset) __rtx_alias_unset_cmd && ret=0 ;; + esac + ;; + esac - return ret - } -(($ + functions[__rtx_alias_get_cmd])) || - __rtx_alias_get_cmd() { - _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_alias_ls_cmd])) || - __rtx_alias_ls_cmd() { - _arguments -s -S \ - '::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_alias_set_cmd])) || - __rtx_alias_set_cmd() { - _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ - ':value:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_alias_unset_cmd])) || - __rtx_alias_unset_cmd() { - _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_asdf_cmd])) || - __rtx_asdf_cmd() { - _arguments -s -S \ - '*::args:_cmdambivalent' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_bin_paths_cmd])) || - __rtx_bin_paths_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_cache_cmd])) || - __rtx_cache_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_cache_cmds' \ - '*::arg:->args' && ret=0 +return ret +} +(( $+functions[__rtx_alias_get_cmd] )) || +__rtx_alias_get_cmd() { + _arguments -s -S \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_alias_ls_cmd] )) || +__rtx_alias_ls_cmd() { + _arguments -s -S \ + '::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_alias_set_cmd] )) || +__rtx_alias_set_cmd() { + _arguments -s -S \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + ':value:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_alias_unset_cmd] )) || +__rtx_alias_unset_cmd() { + _arguments -s -S \ + ':plugin:__rtx_plugins' \ + ':alias:__rtx_aliases' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_asdf_cmd] )) || +__rtx_asdf_cmd() { + _arguments -s -S \ + '*::args:_cmdambivalent' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_bin_paths_cmd] )) || +__rtx_bin_paths_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_cache_cmd] )) || +__rtx_cache_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_cache_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - c | clean | clear) __rtx_cache_clear_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (c|clean|clear) __rtx_cache_clear_cmd && ret=0 ;; + esac + ;; + esac - return ret - } -(($ + functions[__rtx_cache_clear_cmd])) || - __rtx_cache_clear_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_completion_cmd])) || - __rtx_completion_cmd() { - _arguments -s -S \ - '::shell:(bash fish zsh)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_current_cmd])) || - __rtx_current_cmd() { - _arguments -s -S \ - '::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_deactivate_cmd])) || - __rtx_deactivate_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_direnv_cmd])) || - __rtx_direnv_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_direnv_cmds' \ - '*::arg:->args' && ret=0 +return ret +} +(( $+functions[__rtx_cache_clear_cmd] )) || +__rtx_cache_clear_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_completion_cmd] )) || +__rtx_completion_cmd() { + _arguments -s -S \ + '::shell:(bash fish zsh)' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_current_cmd] )) || +__rtx_current_cmd() { + _arguments -s -S \ + '::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_deactivate_cmd] )) || +__rtx_deactivate_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_direnv_cmd] )) || +__rtx_direnv_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_direnv_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - activate) __rtx_direnv_activate_cmd && ret=0 ;; - envrc) __rtx_direnv_envrc_cmd && ret=0 ;; - exec) __rtx_direnv_exec_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (activate) __rtx_direnv_activate_cmd && ret=0 ;; + (envrc) __rtx_direnv_envrc_cmd && ret=0 ;; + (exec) __rtx_direnv_exec_cmd && ret=0 ;; + esac + ;; + esac - return ret - } -(($ + functions[__rtx_direnv_activate_cmd])) || - __rtx_direnv_activate_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_direnv_envrc_cmd])) || - __rtx_direnv_envrc_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_direnv_exec_cmd])) || - __rtx_direnv_exec_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_doctor_cmd])) || - __rtx_doctor_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_env_cmd])) || - __rtx_env_cmd() { - _arguments -s -S \ - '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ - '*::tool:__rtx_tool_versions' \ - '(-J --json)'{-J,--json}'[Output in JSON format]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_env_vars_cmd])) || - __rtx_env_vars_cmd() { - _arguments -s -S \ - '--file=[The TOML file to update]:file:_files' \ - '*--remove=[Remove the environment variable from config file]:remove:' \ - '*::env_vars:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_exec_cmd])) || - __rtx_exec_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ - '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_global_cmd])) || - __rtx_global_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '--pin[Save exact version to \`~/.tool-versions\`]' \ - '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ - '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ - '--path[Get the path of the global config file]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_hook_env_cmd])) || - __rtx_hook_env_cmd() { - _arguments -s -S \ - '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ - '--status[Show "rtx\: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_implode_cmd])) || - __rtx_implode_cmd() { - _arguments -s -S \ - '--config[Also remove config directory]' \ - '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_install_cmd])) || - __rtx_install_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_latest_cmd])) || - __rtx_latest_cmd() { - _arguments -s -S \ - ':tool:__rtx_tool_versions' \ - '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_link_cmd])) || - __rtx_link_cmd() { - _arguments -s -S \ - ':tool:__rtx_tool_versions' \ - ':path:_directories' \ - '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_local_cmd])) || - __rtx_local_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-p --parent)'{-p,--parent}'[Recurse up to find a .tool-versions file rather than using the current directory only]' \ - '--pin[Save exact version to \`.tool-versions\`]' \ - '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ - '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ - '--path[Get the path of the config file]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_ls_cmd])) || - __rtx_ls_cmd() { - _arguments -s -S \ - '::plugin:__rtx_plugins' \ - '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ - '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ - '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ - '(-J --json)'{-J,--json}'[Output in json format]' \ - '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ - '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_ls_remote_cmd])) || - __rtx_ls_remote_cmd() { - _arguments -s -S \ - '::plugin:__rtx_plugins' \ - '--all[Show all installed plugins and versions]' \ - '::prefix:__rtx_prefixes' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_outdated_cmd])) || - __rtx_outdated_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_plugins_cmd])) || - __rtx_plugins_cmd() { - _arguments -s -S \ - '(-c --core)'{-c,--core}'[The built-in plugins only]' \ - '--user[List installed plugins]' \ - '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ - '--refs[show the git refs for each plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_plugins_cmds' \ - '*::arg:->args' && ret=0 +return ret +} +(( $+functions[__rtx_direnv_activate_cmd] )) || +__rtx_direnv_activate_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_direnv_envrc_cmd] )) || +__rtx_direnv_envrc_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_direnv_exec_cmd] )) || +__rtx_direnv_exec_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_doctor_cmd] )) || +__rtx_doctor_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_env_cmd] )) || +__rtx_env_cmd() { + _arguments -s -S \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ + '*::tool:__rtx_tool_versions' \ + '(-J --json)'{-J,--json}'[Output in JSON format]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_env_vars_cmd] )) || +__rtx_env_vars_cmd() { + _arguments -s -S \ + '--file=[The TOML file to update]:file:_files' \ + '*--remove=[Remove the environment variable from config file]:remove:' \ + '*::env_vars:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_exec_cmd] )) || +__rtx_exec_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ + '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_global_cmd] )) || +__rtx_global_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--pin[Save exact version to \`~/.tool-versions\`]' \ + '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ + '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ + '--path[Get the path of the global config file]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_hook_env_cmd] )) || +__rtx_hook_env_cmd() { + _arguments -s -S \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ + '--status[Show "rtx\: @" message when changing directories]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_implode_cmd] )) || +__rtx_implode_cmd() { + _arguments -s -S \ + '--config[Also remove config directory]' \ + '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_install_cmd] )) || +__rtx_install_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_latest_cmd] )) || +__rtx_latest_cmd() { + _arguments -s -S \ + ':tool:__rtx_tool_versions' \ + '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_link_cmd] )) || +__rtx_link_cmd() { + _arguments -s -S \ + ':tool:__rtx_tool_versions' \ + ':path:_directories' \ + '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_local_cmd] )) || +__rtx_local_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-p --parent)'{-p,--parent}'[Recurse up to find a .tool-versions file rather than using the current directory only]' \ + '--pin[Save exact version to \`.tool-versions\`]' \ + '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ + '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ + '--path[Get the path of the config file]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_ls_cmd] )) || +__rtx_ls_cmd() { + _arguments -s -S \ + '::plugin:__rtx_plugins' \ + '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ + '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ + '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ + '(-J --json)'{-J,--json}'[Output in json format]' \ + '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ + '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_ls_remote_cmd] )) || +__rtx_ls_remote_cmd() { + _arguments -s -S \ + '::plugin:__rtx_plugins' \ + '--all[Show all installed plugins and versions]' \ + '::prefix:__rtx_prefixes' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_outdated_cmd] )) || +__rtx_outdated_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_plugins_cmd] )) || +__rtx_plugins_cmd() { + _arguments -s -S \ + '(-c --core)'{-c,--core}'[The built-in plugins only]' \ + '--user[List installed plugins]' \ + '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ + '--refs[show the git refs for each plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_plugins_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - a | add | i | install) __rtx_plugins_install_cmd && ret=0 ;; - l | link) __rtx_plugins_link_cmd && ret=0 ;; - list | ls) __rtx_plugins_ls_cmd && ret=0 ;; - list-all | list-remote | ls-remote) __rtx_plugins_ls_remote_cmd && ret=0 ;; - remove | rm | uninstall) __rtx_plugins_uninstall_cmd && ret=0 ;; - upgrade | update) __rtx_plugins_update_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (a|add|i|install) __rtx_plugins_install_cmd && ret=0 ;; + (l|link) __rtx_plugins_link_cmd && ret=0 ;; + (list|ls) __rtx_plugins_ls_cmd && ret=0 ;; + (list-all|list-remote|ls-remote) __rtx_plugins_ls_remote_cmd && ret=0 ;; + (remove|rm|uninstall) __rtx_plugins_uninstall_cmd && ret=0 ;; + (upgrade|update) __rtx_plugins_update_cmd && ret=0 ;; + esac + ;; + esac - return ret - } -(($ + functions[__rtx_plugins_install_cmd])) || - __rtx_plugins_install_cmd() { - _arguments -s -S \ - ':new_plugin:__rtx_all_plugins' \ - '::git_url:_urls' \ - '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ - '(-a --all)'{-a,--all}'[Install all missing plugins]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_plugins_link_cmd])) || - __rtx_plugins_link_cmd() { - _arguments -s -S \ - ':name:' \ - '::path:_directories' \ - '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_plugins_ls_cmd])) || - __rtx_plugins_ls_cmd() { - _arguments -s -S \ - '(-c --core)'{-c,--core}'[The built-in plugins only]' \ - '--user[List installed plugins]' \ - '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '--refs[Show the git refs for each plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_plugins_ls_remote_cmd])) || - __rtx_plugins_ls_remote_cmd() { - _arguments -s -S \ - '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ - '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_plugins_uninstall_cmd])) || - __rtx_plugins_uninstall_cmd() { - _arguments -s -S \ - '*::plugin:__rtx_plugins' \ - '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ - '(-a --all)'{-a,--all}'[Remove all plugins]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_plugins_update_cmd])) || - __rtx_plugins_update_cmd() { - _arguments -s -S \ - '*::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_prune_cmd])) || - __rtx_prune_cmd() { - _arguments -s -S \ - '*::plugin:__rtx_plugins' \ - '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_reshim_cmd])) || - __rtx_reshim_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_self_update_cmd])) || - __rtx_self_update_cmd() { - _arguments -s -S \ - '(-f --force)'{-f,--force}'[Update even if already up to date]' \ - '--no-plugins[Disable auto-updating plugins]' \ - '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ - '::version:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' - } -(($ + functions[__rtx_settings_cmd])) || - __rtx_settings_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_settings_cmds' \ - '*::arg:->args' && ret=0 +return ret +} +(( $+functions[__rtx_plugins_install_cmd] )) || +__rtx_plugins_install_cmd() { + _arguments -s -S \ + ':new_plugin:__rtx_all_plugins' \ + '::git_url:_urls' \ + '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ + '(-a --all)'{-a,--all}'[Install all missing plugins]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_plugins_link_cmd] )) || +__rtx_plugins_link_cmd() { + _arguments -s -S \ + ':name:' \ + '::path:_directories' \ + '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_plugins_ls_cmd] )) || +__rtx_plugins_ls_cmd() { + _arguments -s -S \ + '(-c --core)'{-c,--core}'[The built-in plugins only]' \ + '--user[List installed plugins]' \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ + '--refs[Show the git refs for each plugin]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_plugins_ls_remote_cmd] )) || +__rtx_plugins_ls_remote_cmd() { + _arguments -s -S \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ + '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_plugins_uninstall_cmd] )) || +__rtx_plugins_uninstall_cmd() { + _arguments -s -S \ + '*::plugin:__rtx_plugins' \ + '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ + '(-a --all)'{-a,--all}'[Remove all plugins]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_plugins_update_cmd] )) || +__rtx_plugins_update_cmd() { + _arguments -s -S \ + '*::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_prune_cmd] )) || +__rtx_prune_cmd() { + _arguments -s -S \ + '*::plugin:__rtx_plugins' \ + '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_reshim_cmd] )) || +__rtx_reshim_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_self_update_cmd] )) || +__rtx_self_update_cmd() { + _arguments -s -S \ + '(-f --force)'{-f,--force}'[Update even if already up to date]' \ + '--no-plugins[Disable auto-updating plugins]' \ + '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ + '::version:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' +} +(( $+functions[__rtx_settings_cmd] )) || +__rtx_settings_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_settings_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - get) __rtx_settings_get_cmd && ret=0 ;; - list | ls) __rtx_settings_ls_cmd && ret=0 ;; - add | create | set) __rtx_settings_set_cmd && ret=0 ;; - del | delete | remove | rm | unset) __rtx_settings_unset_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (get) __rtx_settings_get_cmd && ret=0 ;; + (list|ls) __rtx_settings_ls_cmd && ret=0 ;; + (add|create|set) __rtx_settings_set_cmd && ret=0 ;; + (del|delete|remove|rm|unset) __rtx_settings_unset_cmd && ret=0 ;; + esac + ;; + esac - return ret - } -(($ + functions[__rtx_settings_get_cmd])) || - __rtx_settings_get_cmd() { - _arguments -s -S \ - ':key:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_settings_ls_cmd])) || - __rtx_settings_ls_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_settings_set_cmd])) || - __rtx_settings_set_cmd() { - _arguments -s -S \ - ':key:' \ - ':value:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_settings_unset_cmd])) || - __rtx_settings_unset_cmd() { - _arguments -s -S \ - ':key:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_shell_cmd])) || - __rtx_shell_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_sync_cmd])) || - __rtx_sync_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ - '1: :__rtx_sync_cmds' \ - '*::arg:->args' && ret=0 +return ret +} +(( $+functions[__rtx_settings_get_cmd] )) || +__rtx_settings_get_cmd() { + _arguments -s -S \ + ':key:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_settings_ls_cmd] )) || +__rtx_settings_ls_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_settings_set_cmd] )) || +__rtx_settings_set_cmd() { + _arguments -s -S \ + ':key:' \ + ':value:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_settings_unset_cmd] )) || +__rtx_settings_unset_cmd() { + _arguments -s -S \ + ':key:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_shell_cmd] )) || +__rtx_shell_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_sync_cmd] )) || +__rtx_sync_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_sync_cmds' \ + '*::arg:->args' && ret=0 - case "$state" in - args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - node) __rtx_sync_node_cmd && ret=0 ;; - python) __rtx_sync_python_cmd && ret=0 ;; - esac - ;; - esac + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (node) __rtx_sync_node_cmd && ret=0 ;; + (python) __rtx_sync_python_cmd && ret=0 ;; + esac + ;; + esac - return ret - } -(($ + functions[__rtx_sync_node_cmd])) || - __rtx_sync_node_cmd() { - _arguments -s -S \ - '--brew[Get tool versions from Homebrew]' \ - '--nvm[Get tool versions from nvm]' \ - '--nodenv[Get tool versions from nodenv]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_sync_python_cmd])) || - __rtx_sync_python_cmd() { - _arguments -s -S \ - '--pyenv[Get tool versions from pyenv]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_trust_cmd])) || - __rtx_trust_cmd() { - _arguments -s -S \ - '::config_file:_files' \ - '--untrust[No longer trust this config]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_uninstall_cmd])) || - __rtx_uninstall_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-a --all)'{-a,--all}'[Delete all installed versions]' \ - '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_upgrade_cmd])) || - __rtx_upgrade_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '(-n --dry-run)'{-n,--dry-run}'[Just print what would be done, don'\''t actually do it]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_use_cmd])) || - __rtx_use_cmd() { - _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ - '--pin[Save exact version to config file]' \ - '--fuzzy[Save fuzzy version to config file]' \ - '*--remove=[Remove the tool(s) from config file]:remove:' \ - '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ - '(-e --env)'{-e,--env}'=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:env:' \ - '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_version_cmd])) || - __rtx_version_cmd() { - _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_where_cmd])) || - __rtx_where_cmd() { - _arguments -s -S \ - ':tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_which_cmd])) || - __rtx_which_cmd() { - _arguments -s -S \ - ':bin_name:' \ - '--plugin[Show the plugin name instead of the path]' \ - '--version[Show the version instead of the path]' \ - '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' - } -(($ + functions[__rtx_cmds])) || - __rtx_cmds() { - local commands - commands=( - 'activate:Initializes rtx in the current shell' - {a,alias}':Manage aliases' - 'bin-paths:List all the active runtime bin paths' - 'cache:Manage the rtx cache' - 'completion:Generate shell completions' - 'current:Shows current active and installed runtime versions' - 'deactivate:Disable rtx for current shell session' - 'direnv:Output direnv function to use rtx inside direnv' - 'doctor:Check rtx installation for possible problems.' - {e,env}':Exports env vars to activate rtx a single time' - 'env-vars:Manage environment variables' - {x,exec}':Execute a command with tool(s) set' - 'implode:Removes rtx CLI and all related data' - {i,install}':Install a tool version' - 'latest:Gets the latest available version for a plugin' - 'link:Symlinks a tool version into rtx' - {list,ls}':List installed and/or currently selected tool versions' - 'ls-remote:List runtime versions available for install' - 'outdated:Shows outdated tool versions' - {p,plugins}':Manage plugins' - 'prune:Delete unused versions of tools' - 'reshim:rebuilds the shim farm' - 'self-update:Updates rtx itself' - 'settings:Manage settings' - 'shell:Sets a tool version for the current shell session' - 'sync:Add tool versions from external tools to rtx' - 'trust:Marks a config file as trusted' - 'uninstall:Removes runtime versions' - 'upgrade:Upgrades outdated tool versions' - {u,use}':Change the active version of a tool locally or globally.' - 'version:Show rtx version' - 'where:Display the installation path for a runtime' - 'which:Shows the path that a bin name points to' - ) - _describe -t commands 'command' commands "$@" - } -(($ + functions[__rtx_alias_cmds])) || - __rtx_alias_cmds() { - local commands - commands=( - 'get:Show an alias for a plugin' - {list,ls}':List aliases' - {add,create,set}':Add/update an alias for a plugin' - {del,delete,remove,rm,unset}':Clears an alias for a plugin' - ) - _describe -t commands 'command' commands "$@" - } -(($ + functions[__rtx_cache_cmds])) || - __rtx_cache_cmds() { - local commands - commands=( - {c,clear}':Deletes all cache files in rtx' - ) - _describe -t commands 'command' commands "$@" - } -(($ + functions[__rtx_direnv_cmds])) || - __rtx_direnv_cmds() { - local commands - commands=( - 'activate:Output direnv function to use rtx inside direnv' - ) - _describe -t commands 'command' commands "$@" - } -(($ + functions[__rtx_plugins_cmds])) || - __rtx_plugins_cmds() { - local commands - commands=( - {a,i,install}':Install a plugin' - 'link:Symlinks a plugin into rtx' - {list,ls}':List installed plugins' - {list-remote,ls-remote}':List all available remote plugins' - 'uninstall:Removes a plugin' - 'update:Updates a plugin to the latest version' - ) - _describe -t commands 'command' commands "$@" - } -(($ + functions[__rtx_settings_cmds])) || - __rtx_settings_cmds() { - local commands - commands=( - 'get:Show a current setting' - {list,ls}':Show current settings' - {add,create,set}':Add/update a setting' - {del,delete,remove,rm,unset}':Clears a setting' - ) - _describe -t commands 'command' commands "$@" - } -(($ + functions[__rtx_sync_cmds])) || - __rtx_sync_cmds() { - local commands - commands=( - 'node:Symlinks all tool versions from an external tool into rtx' - 'python:Symlinks all tool versions from an external tool into rtx' - ) - _describe -t commands 'command' commands "$@" - } +return ret +} +(( $+functions[__rtx_sync_node_cmd] )) || +__rtx_sync_node_cmd() { + _arguments -s -S \ + '--brew[Get tool versions from Homebrew]' \ + '--nvm[Get tool versions from nvm]' \ + '--nodenv[Get tool versions from nodenv]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_sync_python_cmd] )) || +__rtx_sync_python_cmd() { + _arguments -s -S \ + '--pyenv[Get tool versions from pyenv]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_trust_cmd] )) || +__rtx_trust_cmd() { + _arguments -s -S \ + '::config_file:_files' \ + '--untrust[No longer trust this config]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_uninstall_cmd] )) || +__rtx_uninstall_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-a --all)'{-a,--all}'[Delete all installed versions]' \ + '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_upgrade_cmd] )) || +__rtx_upgrade_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '(-n --dry-run)'{-n,--dry-run}'[Just print what would be done, don'\''t actually do it]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_use_cmd] )) || +__rtx_use_cmd() { + _arguments -s -S \ + '*::tool:__rtx_tool_versions' \ + '--pin[Save exact version to config file]' \ + '--fuzzy[Save fuzzy version to config file]' \ + '*--remove=[Remove the tool(s) from config file]:remove:' \ + '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ + '(-e --env)'{-e,--env}'=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:env:' \ + '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_version_cmd] )) || +__rtx_version_cmd() { + _arguments -s -S \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_where_cmd] )) || +__rtx_where_cmd() { + _arguments -s -S \ + ':tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_which_cmd] )) || +__rtx_which_cmd() { + _arguments -s -S \ + ':bin_name:' \ + '--plugin[Show the plugin name instead of the path]' \ + '--version[Show the version instead of the path]' \ + '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ + '*'{-v,--verbose}'[Show installation output]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_cmds] )) || +__rtx_cmds() { + local commands; commands=( + 'activate:Initializes rtx in the current shell' + {a,alias}':Manage aliases' + 'bin-paths:List all the active runtime bin paths' + 'cache:Manage the rtx cache' + 'completion:Generate shell completions' + 'current:Shows current active and installed runtime versions' + 'deactivate:Disable rtx for current shell session' + 'direnv:Output direnv function to use rtx inside direnv' + 'doctor:Check rtx installation for possible problems.' + {e,env}':Exports env vars to activate rtx a single time' + 'env-vars:Manage environment variables' + {x,exec}':Execute a command with tool(s) set' + 'implode:Removes rtx CLI and all related data' + {i,install}':Install a tool version' + 'latest:Gets the latest available version for a plugin' + 'link:Symlinks a tool version into rtx' + {list,ls}':List installed and/or currently selected tool versions' + 'ls-remote:List runtime versions available for install' + 'outdated:Shows outdated tool versions' + {p,plugins}':Manage plugins' + 'prune:Delete unused versions of tools' + 'reshim:rebuilds the shim farm' + 'self-update:Updates rtx itself' + 'settings:Manage settings' + 'shell:Sets a tool version for the current shell session' + 'sync:Add tool versions from external tools to rtx' + 'trust:Marks a config file as trusted' + 'uninstall:Removes runtime versions' + 'upgrade:Upgrades outdated tool versions' + {u,use}':Change the active version of a tool locally or globally.' + 'version:Show rtx version' + 'where:Display the installation path for a runtime' + 'which:Shows the path that a bin name points to' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_alias_cmds] )) || +__rtx_alias_cmds() { + local commands; commands=( + 'get:Show an alias for a plugin' + {list,ls}':List aliases' + {add,create,set}':Add/update an alias for a plugin' + {del,delete,remove,rm,unset}':Clears an alias for a plugin' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_cache_cmds] )) || +__rtx_cache_cmds() { + local commands; commands=( + {c,clear}':Deletes all cache files in rtx' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_direnv_cmds] )) || +__rtx_direnv_cmds() { + local commands; commands=( + 'activate:Output direnv function to use rtx inside direnv' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_plugins_cmds] )) || +__rtx_plugins_cmds() { + local commands; commands=( + {a,i,install}':Install a plugin' + 'link:Symlinks a plugin into rtx' + {list,ls}':List installed plugins' + {list-remote,ls-remote}':List all available remote plugins' + 'uninstall:Removes a plugin' + 'update:Updates a plugin to the latest version' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_settings_cmds] )) || +__rtx_settings_cmds() { + local commands; commands=( + 'get:Show a current setting' + {list,ls}':Show current settings' + {add,create,set}':Add/update a setting' + {del,delete,remove,rm,unset}':Clears a setting' + ) + _describe -t commands 'command' commands "$@" +} +(( $+functions[__rtx_sync_cmds] )) || +__rtx_sync_cmds() { + local commands; commands=( + 'node:Symlinks all tool versions from an external tool into rtx' + 'python:Symlinks all tool versions from an external tool into rtx' + ) + _describe -t commands 'command' commands "$@" +} -(($ + functions[__rtx_tool_versions])) || - __rtx_tool_versions() { - if compset -P '*@'; then - local -a tool_versions - tool_versions=($(rtx ls-remote ${words[CURRENT]})) - _wanted tool_version expl 'version of tool' \ - compadd -a tool_versions - else - local -a plugins - plugins=($(rtx plugins --core --user)) - _wanted plugin expl 'plugin name' \ - compadd -S '@' -a plugins - fi - } -(($ + functions[__rtx_plugins])) || - __rtx_plugins() { - local -a plugins - plugins=($(rtx plugins --core --user)) - _describe -t plugins 'plugin' plugins "$@" - } -(($ + functions[__rtx_all_plugins])) || - __rtx_all_plugins() { - local -a all_plugins - all_plugins=($(rtx plugins --all)) - _describe -t all_plugins 'all_plugins' all_plugins "$@" - } -(($ + functions[__rtx_aliases])) || - __rtx_aliases() { - local -a aliases - aliases=($(rtx aliases ls ${words[CURRENT - 1]} | awk '{print $2}')) - _describe -t aliases 'alias' aliases "$@" - } -(($ + functions[__rtx_prefixes])) || - __rtx_prefixes() { - local -a prefixes - prefixes=($(rtx ls-remote ${words[CURRENT - 1]})) - _describe -t prefixes 'prefix' prefixes "$@" - } +(( $+functions[__rtx_tool_versions] )) || +__rtx_tool_versions() { + if compset -P '*@'; then + local -a tool_versions; tool_versions=($(rtx ls-remote ${words[CURRENT]})) + _wanted tool_version expl 'version of tool' \ + compadd -a tool_versions + else + local -a plugins; plugins=($(rtx plugins --core --user)) + _wanted plugin expl 'plugin name' \ + compadd -S '@' -a plugins + fi +} +(( $+functions[__rtx_plugins] )) || +__rtx_plugins() { + local -a plugins; plugins=($(rtx plugins --core --user)) + _describe -t plugins 'plugin' plugins "$@" +} +(( $+functions[__rtx_all_plugins] )) || +__rtx_all_plugins() { + local -a all_plugins; all_plugins=($(rtx plugins --all)) + _describe -t all_plugins 'all_plugins' all_plugins "$@" +} +(( $+functions[__rtx_aliases] )) || +__rtx_aliases() { + local -a aliases; aliases=($(rtx aliases ls ${words[CURRENT-1]} | awk '{print $2}')) + _describe -t aliases 'alias' aliases "$@" +} +(( $+functions[__rtx_prefixes] )) || +__rtx_prefixes() { + local -a prefixes; prefixes=($(rtx ls-remote ${words[CURRENT-1]})) + _describe -t prefixes 'prefix' prefixes "$@" +} if [ "$funcstack[1]" = "_rtx" ]; then - _rtx "$@" + _rtx "$@" else - compdef _rtx rtx + compdef _rtx rtx fi # vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/src/shell/completions/mod.rs b/src/shell/completions/mod.rs index 64969159b..46247b48d 100644 --- a/src/shell/completions/mod.rs +++ b/src/shell/completions/mod.rs @@ -7,8 +7,8 @@ mod zsh_complete; pub fn zsh_complete(cmd: &Command) -> eyre::Result { let output = zsh_complete::render(cmd); - let result = cmd!("shfmt", "-s").stdin_bytes(output).read()?; - Ok(result) + // let result = cmd!("shfmt", "-s").stdin_bytes(output).read()?; + Ok(output) } pub fn fish_complete(cmd: &Command) -> eyre::Result { diff --git a/src/templates/complete_zsh.tera b/src/templates/complete_zsh.tera deleted file mode 100644 index 84221167b..000000000 --- a/src/templates/complete_zsh.tera +++ /dev/null @@ -1,103 +0,0 @@ -{%- macro escape_help(s) -%} -{{s|replace(from="[", to="\[")|replace(from="]",to="\]")}} -{%- endmacro -%} - -{%- macro arg(arg) -%} -{%- if arg.long and arg.has_value %}'{{ self::option(arg=arg) -}}' -{%- elif arg.long %}'{{ self::flag(arg=arg) -}}' -{%- else %}'{{ self::positional(arg=arg) -}}' -{%- endif -%} -{%- endmacro arg -%} - -{% macro option(arg) -%} -{% if arg.short -%} -(-{{ arg.short }} --{{ arg.long }})'{-{{ arg.short }},--{{ arg.long }}}' -{%- else -%} ---{{ arg.long }} -{%- endif -%} -=[{{self::escape_help(s=arg.help)}}] -{%- if arg.choices | length == 0 -%} -:: : -{%- else -%} -: :({%- for choice in arg.choices -%} -{%- if choice.Single %}{{ choice.Single }} {% else -%}{{ choice |json_encode}} {%- endif -%} -{%- endfor -%}) -{%- endif -%} -{% endmacro option -%} - -{% macro flag(arg) -%} -{% if arg.short -%} -(-{{ arg.short }} --{{ arg.long }})'{-{{ arg.short }},--{{ arg.long }}}' -{%- else -%} ---{{ arg.long }} -{%- endif -%} -[{{self::escape_help(s=arg.help)}}] -{%- endmacro flag -%} - -{% macro positional(arg) -%} -:{{arg.id}}: : -{%- endmacro positional -%} - -#compdef rtx -_rtx() { - typeset -A opt_args - local context state line curcontext=$curcontext - local ret=1 - - _arguments -s -S \ - '(-h --help)'{-h,--help}'[Print help (see more with '--help')]' \ - {% for arg in visible_args -%} - {% if not arg.hide -%} - {{ self::arg(arg=arg) }} \ - {% endif -%} - {% endfor -%} - '1: :_rtx_cmds' \ - '*::arg:->args' && ret=0 - - case "$state" in - (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" - case $words[1] in - {%- for cmd in commands %} - ({% for a in cmd.visible_aliases %}{{a}}|{% endfor %}{{cmd.name}}) - __rtx_cmd_{{cmd.name|replace(from="-", to="_")}}_arguments && ret=0 - ;; - {%- endfor %} - esac - ;; - esac - - return ret -} - -{%- for cmd in commands %} -__rtx_cmd_{{cmd.name|replace(from="-", to="_")}}_arguments() { - _arguments{% if cmd.visible_args | length > 0 %} \{% endif %} -{% for arg in cmd.visible_args -%} -{% if not arg.hide %} {{ self::arg(arg=arg) }}{% if not loop.last %} \{% endif %} -{% endif -%} -{% endfor -%} -}{%- endfor %} - -(( $+functions[_rtx_cmds] )) || -_rtx_cmds() { - local commands; commands=( - {%- for cmd in commands %} - '{{cmd.name}}:{{cmd.about}}' - {%- for a in cmd.visible_aliases %} - '{{a}}:{{cmd.about}}' - {%- endfor %} - {%- endfor %} - ) - _describe -t commands 'command' commands "$@" -} - -_rtx "$@" - -# Local Variables: -# mode: Shell-Script -# sh-indentation: 2 -# indent-tabs-mode: nil -# sh-basic-offset: 2 -# End: -# vim: ft=zsh sw=2 ts=2 et From f3b3f06a92670109597cdacfca556e1e586bcec4 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 12:53:29 -0600 Subject: [PATCH 1195/1891] release: support more arm architectures (#1095) * release: support more arm architectures * release: support more arm architectures --- .github/workflows/rtx.yml | 94 ++++++++++++++++++-------------------- scripts/build-tarball.sh | 14 +++++- scripts/release-npm.sh | 4 ++ scripts/release.sh | 13 ++---- scripts/render-homebrew.sh | 4 ++ scripts/render-install.sh | 4 ++ 6 files changed, 74 insertions(+), 59 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 7da836665..16d375e54 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -3,10 +3,9 @@ name: rtx on: push: tags: ["v*"] - branches: ["main"] + branches: ["main", "release/*"] pull_request: branches: ["main"] - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: env: @@ -81,58 +80,56 @@ jobs: fail_ci_if_error: false files: lcov.info - build-linux: - name: build-${{matrix.target}} - runs-on: ubuntu-22.04 - timeout-minutes: 45 - strategy: - fail-fast: false - matrix: - target: - - aarch64-unknown-linux-gnu - - x86_64-unknown-linux-gnu - - arm-unknown-linux-musleabihf - - armv7-unknown-linux-gnueabihf - steps: - - uses: actions/checkout@v4 - - name: Rust Cache - uses: Swatinem/rust-cache@v2 - with: - shared-key: "build-linux-${{matrix.target}}" - save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - - uses: taiki-e/install-action@cross - - run: scripts/setup-zipsign.sh - env: - ZIPSIGN: ${{ secrets.ZIPSIGN }} - - run: scripts/build-tarball.sh rtx --release --features openssl/vendored --target ${{matrix.target}} - env: - CROSS: "1" - - uses: actions/upload-artifact@v3 - with: - name: tarball-${{matrix.target}} - path: | - dist/rtx-*.tar.xz - dist/rtx-*.tar.gz - if-no-files-found: error - - build-macos: - name: build-${{matrix.target}} - runs-on: macos-12 + build-tarball: + if: startsWith(github.event.ref, 'refs/tags/v') || startsWith(github.event.ref, 'refs/heads/release/') || (github.event_name == 'push' && github.ref_name == 'main') + name: build-tarball-${{matrix.name}} + runs-on: ${{matrix.os}} timeout-minutes: 45 strategy: fail-fast: false matrix: - target: - - x86_64-apple-darwin - - aarch64-apple-darwin + include: + - os: ubuntu-22.04 + name: linux-x64 + target: x86_64-unknown-linux-gnu + - os: ubuntu-22.04 + name: linux-x64-musl + target: aarch64-unknown-linux-musl + - os: ubuntu-22.04 + name: linux-arm64 + target: aarch64-unknown-linux-gnu + - os: ubuntu-22.04 + name: linux-arm64-musl + target: aarch64-unknown-linux-musl + - os: ubuntu-22.04 + name: linux-armv7 + target: armv7-unknown-linux-gnueabi + - os: ubuntu-22.04 + name: linux-armv7-musl + target: armv7-unknown-linux-musleabi + - os: ubuntu-22.04 + name: linux-armv6 + target: arm-unknown-linux-gnueabi + - os: ubuntu-22.04 + name: linux-armv6-musl + target: arm-unknown-linux-musleabi + - os: macos-12 + name: macos-x64 + target: x86_64-apple-darwin + - os: macos-12 + name: macos-arm64 + target: aarch64-apple-darwin steps: - uses: actions/checkout@v4 - - run: rustup target add ${{matrix.target}} + - if: matrix.os == 'macos-12' + run: rustup target add ${{matrix.target}} - name: Rust Cache uses: Swatinem/rust-cache@v2 with: - key: "${{matrix.target}}" + shared-key: "build-tarball-${{matrix.name}}" save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + - if: matrix.os == 'ubuntu-22.04' + uses: taiki-e/install-action@cross - run: scripts/setup-zipsign.sh env: ZIPSIGN: ${{ secrets.ZIPSIGN }} @@ -147,7 +144,7 @@ jobs: e2e-linux: runs-on: ubuntu-22.04 #container: ghcr.io/jdx/rtx:github-actions - needs: [build-linux] + needs: [build-tarball] timeout-minutes: 30 if: github.event_name != 'pull_request' steps: @@ -171,7 +168,7 @@ jobs: command: ./e2e/run_all_tests rpm: runs-on: ubuntu-22.04 - needs: [build-linux] + needs: [build-tarball] timeout-minutes: 10 container: ghcr.io/jdx/rtx:rpm if: github.event_name != 'pull_request' @@ -199,7 +196,7 @@ jobs: container: ghcr.io/jdx/rtx:deb timeout-minutes: 10 if: github.event_name != 'pull_request' - needs: [build-linux] + needs: [build-tarball] steps: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 @@ -230,8 +227,7 @@ jobs: - unit - coverage - e2e-linux - - build-linux - - build-macos + - build-tarball - rpm - deb steps: diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index ef7c5d0ab..c641fdafa 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -59,13 +59,23 @@ get_arch() { ;; esac } +get_suffix() { + case "$RUST_TRIPLE" in + *-musl | *-musleabi | *-musleabihf) + echo "-musl" + ;; + *) + echo "" + ;; + esac +} #endregion set -x VERSION=$(./scripts/get-version.sh) -BASENAME=$NAME-$VERSION-$(get_os)-$(get_arch) +BASENAME=$NAME-$VERSION-$(get_os)-$(get_arch)$(get_suffix) -if [ "${CROSS:-}" = "1" ]; then +if command -v cross >/dev/null; then cross build "$@" else cargo build "$@" diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index 01152814f..dc5890241 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -22,9 +22,13 @@ dist_tag="$(dist_tag_from_version "$RTX_VERSION")" platforms=( linux-x64 + linux-x64-musl linux-arm64 + linux-arm64-musl linux-armv6 + linux-armv6-musl linux-armv7 + linux-armv7-musl macos-x64 macos-arm64 ) diff --git a/scripts/release.sh b/scripts/release.sh index c9bbdaa33..5c569605f 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -10,14 +10,7 @@ export RTX_VERSION RELEASE_DIR rm -rf "${RELEASE_DIR:?}/$RTX_VERSION" mkdir -p "$RELEASE_DIR/$RTX_VERSION" -targets=( - x86_64-unknown-linux-gnu - aarch64-unknown-linux-gnu - arm-unknown-linux-gnueabihf - armv7-unknown-linux-gnueabihf - x86_64-apple-darwin - aarch64-apple-darwin -) +targets=$(find artifacts -name 'tarball-*' -exec basename {} \; | sed 's/^tarball-//') for target in "${targets[@]}"; do cp "artifacts/tarball-$target/"*.tar.gz "$RELEASE_DIR/$RTX_VERSION" cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$RTX_VERSION" @@ -25,9 +18,13 @@ done platforms=( linux-x64 + linux-x64-musl linux-arm64 + linux-arm64-musl linux-armv6 + linux-armv6-musl linux-armv7 + linux-armv7-musl macos-x64 macos-arm64 ) diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index c906a41f3..3e297ac65 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -4,9 +4,13 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=${RTX_VERSION#v*} \ RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_X86_64_MUSL=$(grep "rtx-v$RTX_VERSION-linux-x64-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARM64_MUSL=$(grep "rtx-v$RTX_VERSION-linux-arm64-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_LINUX_ARMV6=$(grep "rtx-v$RTX_VERSION-linux-armv6.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARMV6_MUSL=$(grep "rtx-v$RTX_VERSION-linux-armv6-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_LINUX_ARMV7=$(grep "rtx-v$RTX_VERSION-linux-armv7.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ + RTX_CHECKSUM_LINUX_ARMV7_MUSL=$(grep "rtx-v$RTX_VERSION-linux-armv7-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ diff --git a/scripts/render-install.sh b/scripts/render-install.sh index fa3d37564..f5cf4a98b 100755 --- a/scripts/render-install.sh +++ b/scripts/render-install.sh @@ -4,9 +4,13 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=$RTX_VERSION \ RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v.*linux-x64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_X86_64_MUSL=$(grep "rtx-v.*linux-x64-musl.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v.*linux-arm64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_ARM64_MUSL=$(grep "rtx-v.*linux-arm64-musl.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_LINUX_ARMV6=$(grep "rtx-v.*linux-armv6.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_ARMV6_MUSL=$(grep "rtx-v.*linux-armv6-musl.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_LINUX_ARMV7=$(grep "rtx-v.*linux-armv7.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ + RTX_CHECKSUM_LINUX_ARMV7_MUSL=$(grep "rtx-v.*linux-armv7-musl.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v.*macos-x64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v.*macos-arm64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ From 6d41c07699fe1e0a9fcca851f2cb1b705b39666e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 13:01:00 -0600 Subject: [PATCH 1196/1891] chore: Release rtx-cli version 2023.12.11 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c00ab3825..8c5a69533 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.10" +version = "2023.12.11" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 43b014a68..4f82c8d2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.10" +version = "2023.12.11" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 0d7beeceb..570a02233 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.10 +rtx 2023.12.11 ``` Hook rtx into your shell (pick the right one for your shell): @@ -353,7 +353,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.10/rtx-v2023.12.10-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.11/rtx-v2023.12.11-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 0e7260d91..ce8de6271 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.10"; + version = "2023.12.11"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 108290468..cc5b3f4a4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.10 +Version: 2023.12.11 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 100bd24716eed8fc7f23ac78f16b79692c45898c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 13:06:04 -0600 Subject: [PATCH 1197/1891] ci: added super-linter --- .github/workflows/linter.yml | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/linter.yml diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 000000000..3589bbf5e --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,38 @@ +--- +name: Lint Code Base + +# +# Documentation: +# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions +# + +on: + push: + branches-ignore: [main] + pull_request: + branches: [main] + +jobs: + build: + name: Lint Code Base + runs-on: ubuntu-latest + + permissions: + contents: read + packages: read + statuses: write + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + # Full git history is needed to get a proper + # list of changed files within `super-linter` + fetch-depth: 0 + + - name: Lint Code Base + uses: super-linter/super-linter@v5 + env: + VALIDATE_ALL_CODEBASE: false + DEFAULT_BRANCH: main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 6840d02c511838e7d2b6705538d90d6cf8ecb48c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 15:24:20 -0600 Subject: [PATCH 1198/1891] ci: added super-linter (#1096) * ci: added super-linter * ci: split testing/release into separate workflows * fewer jobs * restyled * auto-linting * auto-linting * auto-linting * mega linter * mega linter * mega linter * mega linter * mega linter * mega linter * mega linter * mega linter * Restyle ci: added super-linter (#1097) * Restyled by jq * Restyled by prettier-json * Restyled by prettier-markdown * Restyled by shellharden * Restyled by shfmt * Restyled by standardrb * Restyled by whitespace --------- Co-authored-by: Restyled.io --------- Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com> Co-authored-by: Restyled.io --- .cspell.json | 16 ++ .devcontainer/devcontainer.json | 48 ++-- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/restyled.yml | 1 + .github/workflows/docker.yml | 2 +- .github/workflows/linter.yml | 38 --- .github/workflows/mega-linter.yml | 183 +++++++++++++ .github/workflows/release.yml | 245 +++++++++++++++++ .github/workflows/rtx.yml | 304 ++++----------------- .github/workflows/test-plugins.yml | 4 +- .gitignore | 2 + .jscpd.json | 15 + .mega-linter.yml | 28 ++ .yamllint.yml | 1 + CONTRIBUTING.md | 34 +-- README.md | 39 ++- SECURITY.md | 18 +- docs/bun.md | 6 +- docs/demo.sh | 2 +- docs/deno.md | 6 +- docs/go.md | 10 +- docs/java.md | 14 +- docs/node.md | 40 +-- docs/python.md | 7 +- docs/ruby.md | 12 +- packaging/alpine/Dockerfile | 2 + packaging/deb/generate-release.sh | 25 +- packaging/github-actions/Dockerfile | 2 +- schema/rtx.json | 8 +- schema/rtx.plugin.json | 8 +- src/cli/render_help.rs | 2 +- src/plugins/core/assets/rubygems_plugin.rb | 6 +- 32 files changed, 673 insertions(+), 457 deletions(-) create mode 100644 .cspell.json create mode 100644 .github/restyled.yml delete mode 100644 .github/workflows/linter.yml create mode 100644 .github/workflows/mega-linter.yml create mode 100644 .github/workflows/release.yml create mode 100644 .jscpd.json create mode 100644 .mega-linter.yml create mode 100644 .yamllint.yml diff --git a/.cspell.json b/.cspell.json new file mode 100644 index 000000000..b798d2932 --- /dev/null +++ b/.cspell.json @@ -0,0 +1,16 @@ +{ + "ignorePaths": [ + "**/node_modules/**", + "**/vscode-extension/**", + "**/.git/**", + "**/.pnpm-lock.json", + ".vscode", + "megalinter", + "package-lock.json", + "report" + ], + "language": "en", + "noConfigSearch": true, + "words": ["megalinter", "oxsecurity"], + "version": "0.2" +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 83b2b7c61..cfb16e6c7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,36 +1,36 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/rust { - "name": "Rust", + "name": "Rust", - // "image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye", + // "image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "build": { - "dockerfile": "Dockerfile" - }, + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "build": { + "dockerfile": "Dockerfile" + }, - // Use 'mounts' to make the cargo cache persistent in a Docker Volume. - // "mounts": [ - // { - // "source": "devcontainer-cargo-cache-${devcontainerId}", - // "target": "/usr/local/cargo", - // "type": "volume" - // } - // ] + // Use 'mounts' to make the cargo cache persistent in a Docker Volume. + // "mounts": [ + // { + // "source": "devcontainer-cargo-cache-${devcontainerId}", + // "target": "/usr/local/cargo", + // "type": "volume" + // } + // ] - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "rustc --version", + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "rustc --version", - // Configure tool-specific properties. - // "customizations": {}, + // Configure tool-specific properties. + // "customizations": {}, - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - "remoteUser": "root" + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + "remoteUser": "root" } diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 18f56b985..546fd35dd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -18,7 +18,7 @@ A clear and concise description of what you expected to happen. **`rtx doctor` output** -``` +```text REPLACE WITH OUTPUT OF `rtx doctor` ``` diff --git a/.github/restyled.yml b/.github/restyled.yml new file mode 100644 index 000000000..d4ca94189 --- /dev/null +++ b/.github/restyled.yml @@ -0,0 +1 @@ +enabled: true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7ae2b38fc..a205f4dab 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -3,7 +3,7 @@ name: docker on: push: tags: ["v*"] - branches: ['docker-release'] + branches: ["docker-release"] workflow_dispatch: env: diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml deleted file mode 100644 index 3589bbf5e..000000000 --- a/.github/workflows/linter.yml +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Lint Code Base - -# -# Documentation: -# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions -# - -on: - push: - branches-ignore: [main] - pull_request: - branches: [main] - -jobs: - build: - name: Lint Code Base - runs-on: ubuntu-latest - - permissions: - contents: read - packages: read - statuses: write - - steps: - - name: Checkout Code - uses: actions/checkout@v3 - with: - # Full git history is needed to get a proper - # list of changed files within `super-linter` - fetch-depth: 0 - - - name: Lint Code Base - uses: super-linter/super-linter@v5 - env: - VALIDATE_ALL_CODEBASE: false - DEFAULT_BRANCH: main - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml new file mode 100644 index 000000000..41dd24565 --- /dev/null +++ b/.github/workflows/mega-linter.yml @@ -0,0 +1,183 @@ +# MegaLinter GitHub Action configuration file +# More info at https://megalinter.io +--- +name: MegaLinter + +# Trigger mega-linter at every push. Action will also be visible from +# Pull Requests to main +on: + # Comment this line to trigger action only on pull-requests + # (not recommended if you don't pay for GH Actions) + # push: + + pull_request: + branches: + - main + +# Comment env block if you do not want to apply fixes +env: + # Apply linter fixes configuration + # + # When active, APPLY_FIXES must also be defined as environment variable + # (in github/workflows/mega-linter.yml or other CI tool) + APPLY_FIXES: all + + # Decide which event triggers application of fixes in a commit or a PR + # (pull_request, push, all) + APPLY_FIXES_EVENT: pull_request + + # If APPLY_FIXES is used, defines if the fixes are directly committed (commit) + # or posted in a PR (pull_request) + APPLY_FIXES_MODE: commit + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + megalinter: + name: MegaLinter + runs-on: ubuntu-latest + + # Give the default GITHUB_TOKEN write permission to commit and push, comment + # issues, and post new Pull Requests; remove the ones you do not need + permissions: + contents: write + issues: write + pull-requests: write + + steps: + # Git Checkout + - name: Checkout Code + uses: actions/checkout@v3 + with: + token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} + + # If you use VALIDATE_ALL_CODEBASE = true, you can remove this line to + # improve performance + fetch-depth: 0 + + # MegaLinter + - name: MegaLinter + + # You can override MegaLinter flavor used to have faster performances + # More info at https://megalinter.io/latest/flavors/ + uses: oxsecurity/megalinter@v7 + + id: ml + + # All available variables are described in documentation + # https://megalinter.io/latest/config-file/ + env: + # Validates all source when push on main, else just the git diff with + # main. Override with true if you always want to lint all sources + # + # To validate the entire codebase, set to: + # VALIDATE_ALL_CODEBASE: true + # + # To validate only diff with main, set to: + # VALIDATE_ALL_CODEBASE: >- + # ${{ + # github.event_name == 'push' && + # github.ref == 'refs/heads/main' + # }} + VALIDATE_ALL_CODEBASE: true + + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # ADD YOUR CUSTOM ENV VARIABLES HERE TO OVERRIDE VALUES OF + # .mega-linter.yml AT THE ROOT OF YOUR REPOSITORY + + # Upload MegaLinter artifacts + - name: Archive production artifacts + uses: actions/upload-artifact@v3 + if: success() || failure() + with: + name: MegaLinter reports + path: | + megalinter-reports + mega-linter.log + + # Create pull request if applicable + # (for now works only on PR from same repository, not from forks) + - name: Create Pull Request with applied fixes + uses: peter-evans/create-pull-request@v5 + id: cpr + if: >- + steps.ml.outputs.has_updated_sources == 1 && + ( + env.APPLY_FIXES_EVENT == 'all' || + env.APPLY_FIXES_EVENT == github.event_name + ) && + env.APPLY_FIXES_MODE == 'pull_request' && + ( + github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository + ) && + !contains(github.event.head_commit.message, 'skip fix') + with: + token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} + commit-message: "[MegaLinter] Apply linters automatic fixes" + title: "[MegaLinter] Apply linters automatic fixes" + labels: bot + + - name: Create PR output + if: >- + steps.ml.outputs.has_updated_sources == 1 && + ( + env.APPLY_FIXES_EVENT == 'all' || + env.APPLY_FIXES_EVENT == github.event_name + ) && + env.APPLY_FIXES_MODE == 'pull_request' && + ( + github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository + ) && + !contains(github.event.head_commit.message, 'skip fix') + run: | + echo "PR Number - ${{ steps.cpr.outputs.pull-request-number }}" + echo "PR URL - ${{ steps.cpr.outputs.pull-request-url }}" + + # Push new commit if applicable + # (for now works only on PR from same repository, not from forks) + - name: Prepare commit + if: >- + steps.ml.outputs.has_updated_sources == 1 && + ( + env.APPLY_FIXES_EVENT == 'all' || + env.APPLY_FIXES_EVENT == github.event_name + ) && + env.APPLY_FIXES_MODE == 'commit' && + github.ref != 'refs/heads/main' && + ( + github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository + ) && + !contains(github.event.head_commit.message, 'skip fix') + run: sudo chown -Rc $UID .git/ + + - name: Commit and push applied linter fixes + uses: stefanzweifel/git-auto-commit-action@v4 + if: >- + steps.ml.outputs.has_updated_sources == 1 && + ( + env.APPLY_FIXES_EVENT == 'all' || + env.APPLY_FIXES_EVENT == github.event_name + ) && + env.APPLY_FIXES_MODE == 'commit' && + github.ref != 'refs/heads/main' && + ( + github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository + ) && + !contains(github.event.head_commit.message, 'skip fix') + with: + branch: >- + ${{ + github.event.pull_request.head.ref || + github.head_ref || + github.ref + }} + commit_message: "[MegaLinter] Apply linters fixes" + commit_user_name: megalinter-bot + commit_user_email: nicolas.vuillamy@ox.security diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..d9ecb35ea --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,245 @@ +name: release + +on: + push: + tags: ["v*"] + branches: ["main", "release/*"] + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + +jobs: + build-tarball: + name: build-tarball-${{matrix.name}} + runs-on: ${{matrix.os}} + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-22.04 + name: linux-x64 + target: x86_64-unknown-linux-gnu + - os: ubuntu-22.04 + name: linux-x64-musl + target: aarch64-unknown-linux-musl + - os: ubuntu-22.04 + name: linux-arm64 + target: aarch64-unknown-linux-gnu + - os: ubuntu-22.04 + name: linux-arm64-musl + target: aarch64-unknown-linux-musl + - os: ubuntu-22.04 + name: linux-armv7 + target: armv7-unknown-linux-gnueabi + - os: ubuntu-22.04 + name: linux-armv7-musl + target: armv7-unknown-linux-musleabi + - os: ubuntu-22.04 + name: linux-armv6 + target: arm-unknown-linux-gnueabi + - os: ubuntu-22.04 + name: linux-armv6-musl + target: arm-unknown-linux-musleabi + - os: macos-12 + name: macos-x64 + target: x86_64-apple-darwin + - os: macos-12 + name: macos-arm64 + target: aarch64-apple-darwin + steps: + - uses: actions/checkout@v4 + - if: matrix.os == 'macos-12' + run: rustup target add ${{matrix.target}} + - name: Rust Cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "build-tarball-${{matrix.name}}" + - if: matrix.os == 'ubuntu-22.04' + uses: taiki-e/install-action@cross + - run: scripts/setup-zipsign.sh + env: + ZIPSIGN: ${{ secrets.ZIPSIGN }} + - run: scripts/build-tarball.sh rtx --release --features openssl/vendored --target ${{matrix.target}} + - uses: actions/upload-artifact@v3 + with: + name: tarball-${{matrix.target}} + path: | + dist/rtx-*.tar.xz + dist/rtx-*.tar.gz + if-no-files-found: error + e2e-linux: + runs-on: ubuntu-22.04 + #container: ghcr.io/jdx/rtx:github-actions + needs: [build-tarball] + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - name: Install zsh/fish/direnv + run: sudo apt-get update; sudo apt-get install zsh fish direnv + - uses: actions/download-artifact@v3 + with: + name: tarball-x86_64-unknown-linux-gnu + path: dist + - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz + - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH + - run: rtx -v + - name: Run e2e tests + uses: nick-fields/retry@v2 + env: + RUST_BACKTRACE: "1" + with: + timeout_minutes: 20 + max_attempts: 3 + command: ./e2e/run_all_tests + rpm: + runs-on: ubuntu-22.04 + needs: [build-tarball] + timeout-minutes: 10 + container: ghcr.io/jdx/rtx:rpm + steps: + - uses: actions/checkout@v4 + - uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_KEY }} + - uses: actions/download-artifact@v3 + with: + name: tarball-x86_64-unknown-linux-gnu + path: dist + - uses: actions/download-artifact@v3 + with: + name: tarball-aarch64-unknown-linux-gnu + path: dist + - run: scripts/build-rpm.sh + - uses: actions/upload-artifact@v3 + with: + name: rpm + path: dist/rpmrepo + if-no-files-found: error + deb: + runs-on: ubuntu-22.04 + container: ghcr.io/jdx/rtx:deb + timeout-minutes: 10 + needs: [build-tarball] + steps: + - uses: actions/checkout@v4 + - uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_KEY }} + - uses: actions/download-artifact@v3 + with: + name: tarball-x86_64-unknown-linux-gnu + path: dist + - uses: actions/download-artifact@v3 + with: + name: tarball-aarch64-unknown-linux-gnu + path: dist + - run: scripts/build-deb.sh + - uses: actions/upload-artifact@v3 + with: + name: deb + path: dist/deb + if-no-files-found: error + release: + runs-on: ubuntu-22.04 + if: startsWith(github.event.ref, 'refs/tags/v') + #container: ghcr.io/jdx/rtx:github-actions + timeout-minutes: 10 + permissions: + contents: write + needs: + - e2e-linux + - build-tarball + - rpm + - deb + steps: + - uses: actions/checkout@v4 + with: + path: rtx + - uses: actions/checkout@v4 + with: + repository: jdx/homebrew-tap + path: homebrew-tap + token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + - name: Install fd-find + run: | + sudo apt-get update + sudo apt-get install fd-find + mkdir -p "$HOME/.local/bin" + ln -s $(which fdfind) "$HOME/.local/bin/fd" + echo "$HOME/.local/bin" >> $GITHUB_PATH + - uses: actions/setup-node@v4 + with: + node-version: "20.x" + registry-url: "https://registry.npmjs.org" + - name: Set AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-2 + - uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.RTX_SSH_KEY }} + known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} + - uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_KEY }} + git_user_signingkey: true + git_commit_gpgsign: true + workdir: homebrew-tap + - uses: actions/download-artifact@v3 + with: { path: artifacts } + - run: rtx/scripts/release.sh + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} + CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} + - name: homebrew-tap push + run: git push + working-directory: homebrew-tap + - name: GitHub Release Assets + uses: softprops/action-gh-release@v1 + if: startsWith(github.event.ref, 'refs/tags/v') + with: + fail_on_unmatched_files: true + draft: false + files: releases/${{github.ref_name}}/* + generate_release_notes: true + token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + - name: Release to aur + run: scripts/release-aur.sh + working-directory: rtx + - name: Release aur-bin + run: scripts/release-aur-bin.sh + working-directory: rtx + bump-homebrew-formula: + runs-on: macos-latest + if: startsWith(github.event.ref, 'refs/tags/v') + timeout-minutes: 10 + needs: [release] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Bump Homebrew formula + uses: dawidd6/action-homebrew-bump-formula@v3 + with: + token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + formula: rtx + bump-alpine: + runs-on: ubuntu-22.04 + container: ghcr.io/jdx/rtx:alpine + timeout-minutes: 30 + needs: [release] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Bump APKBUILD + run: sudo -Eu packager ./scripts/release-alpine.sh + env: + ALPINE_PUB_KEY: ${{ secrets.ALPINE_PUB_KEY }} + ALPINE_PRIV_KEY: ${{ secrets.ALPINE_PRIV_KEY }} + GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 16d375e54..e7f3b3701 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -18,19 +18,16 @@ jobs: container: ghcr.io/jdx/rtx:github-actions timeout-minutes: 10 steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Rust Cache - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 with: - save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + save-if: false # - uses: taiki-e/install-action@v2 # with: # tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete # - name: Install direnv/shfmt # run: sudo apt-get update; sudo apt-get install direnv shfmt - - name: Run cargo nextest - run: cargo nextest run --all-features + - run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" - run: just lint @@ -38,6 +35,23 @@ jobs: - run: cargo msrv verify - run: cargo machete --with-metadata + lint-fix: + runs-on: ubuntu-22.04 + timeout-minutes: 10 + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + with: + shared-key: test + save-if: false + - run: sudo apt-get update; sudo apt-get install shfmt shellcheck + - uses: taiki-e/install-action@just + - run: just lint-fix + - uses: EndBug/add-and-commit@v9 + with: + push: true + coverage: name: coverage-${{matrix.tranche}} #container: ghcr.io/jdx/rtx:github-actions @@ -48,22 +62,17 @@ jobs: matrix: tranche: [0, 1, 2, 3] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - run: rustup toolchain install nightly --component llvm-tools-preview - - name: Rust Cache - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@v2 with: - shared-key: coverage + shared-key: test save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - uses: taiki-e/install-action@cargo-llvm-cov - - name: Install zsh/fish/direnv - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt + - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - run: npm i -g markdown-magic - - name: Install just - uses: taiki-e/install-action@just - - name: Run tests with coverage - uses: nick-fields/retry@v2 + - uses: taiki-e/install-action@just + - uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" @@ -80,242 +89,23 @@ jobs: fail_ci_if_error: false files: lcov.info - build-tarball: - if: startsWith(github.event.ref, 'refs/tags/v') || startsWith(github.event.ref, 'refs/heads/release/') || (github.event_name == 'push' && github.ref_name == 'main') - name: build-tarball-${{matrix.name}} - runs-on: ${{matrix.os}} - timeout-minutes: 45 - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-22.04 - name: linux-x64 - target: x86_64-unknown-linux-gnu - - os: ubuntu-22.04 - name: linux-x64-musl - target: aarch64-unknown-linux-musl - - os: ubuntu-22.04 - name: linux-arm64 - target: aarch64-unknown-linux-gnu - - os: ubuntu-22.04 - name: linux-arm64-musl - target: aarch64-unknown-linux-musl - - os: ubuntu-22.04 - name: linux-armv7 - target: armv7-unknown-linux-gnueabi - - os: ubuntu-22.04 - name: linux-armv7-musl - target: armv7-unknown-linux-musleabi - - os: ubuntu-22.04 - name: linux-armv6 - target: arm-unknown-linux-gnueabi - - os: ubuntu-22.04 - name: linux-armv6-musl - target: arm-unknown-linux-musleabi - - os: macos-12 - name: macos-x64 - target: x86_64-apple-darwin - - os: macos-12 - name: macos-arm64 - target: aarch64-apple-darwin - steps: - - uses: actions/checkout@v4 - - if: matrix.os == 'macos-12' - run: rustup target add ${{matrix.target}} - - name: Rust Cache - uses: Swatinem/rust-cache@v2 - with: - shared-key: "build-tarball-${{matrix.name}}" - save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - - if: matrix.os == 'ubuntu-22.04' - uses: taiki-e/install-action@cross - - run: scripts/setup-zipsign.sh - env: - ZIPSIGN: ${{ secrets.ZIPSIGN }} - - run: scripts/build-tarball.sh rtx --release --features openssl/vendored --target ${{matrix.target}} - - uses: actions/upload-artifact@v3 - with: - name: tarball-${{matrix.target}} - path: | - dist/rtx-*.tar.xz - dist/rtx-*.tar.gz - if-no-files-found: error - e2e-linux: - runs-on: ubuntu-22.04 - #container: ghcr.io/jdx/rtx:github-actions - needs: [build-tarball] - timeout-minutes: 30 - if: github.event_name != 'pull_request' - steps: - - uses: actions/checkout@v4 - - name: Install zsh/fish/direnv - run: sudo apt-get update; sudo apt-get install zsh fish direnv - - uses: actions/download-artifact@v3 - with: - name: tarball-x86_64-unknown-linux-gnu - path: dist - - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz - - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH - - run: rtx -v - - name: Run e2e tests - uses: nick-fields/retry@v2 - env: - RUST_BACKTRACE: "1" - with: - timeout_minutes: 20 - max_attempts: 3 - command: ./e2e/run_all_tests - rpm: - runs-on: ubuntu-22.04 - needs: [build-tarball] - timeout-minutes: 10 - container: ghcr.io/jdx/rtx:rpm - if: github.event_name != 'pull_request' - steps: - - uses: actions/checkout@v4 - - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_KEY }} - - uses: actions/download-artifact@v3 - with: - name: tarball-x86_64-unknown-linux-gnu - path: dist - - uses: actions/download-artifact@v3 - with: - name: tarball-aarch64-unknown-linux-gnu - path: dist - - run: scripts/build-rpm.sh - - uses: actions/upload-artifact@v3 - with: - name: rpm - path: dist/rpmrepo - if-no-files-found: error - deb: - runs-on: ubuntu-22.04 - container: ghcr.io/jdx/rtx:deb - timeout-minutes: 10 - if: github.event_name != 'pull_request' - needs: [build-tarball] - steps: - - uses: actions/checkout@v4 - - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_KEY }} - - uses: actions/download-artifact@v3 - with: - name: tarball-x86_64-unknown-linux-gnu - path: dist - - uses: actions/download-artifact@v3 - with: - name: tarball-aarch64-unknown-linux-gnu - path: dist - - run: scripts/build-deb.sh - - uses: actions/upload-artifact@v3 - with: - name: deb - path: dist/deb - if-no-files-found: error - release: - runs-on: ubuntu-22.04 - if: startsWith(github.event.ref, 'refs/tags/v') - #container: ghcr.io/jdx/rtx:github-actions - timeout-minutes: 10 - permissions: - contents: write - needs: - - unit - - coverage - - e2e-linux - - build-tarball - - rpm - - deb - steps: - - uses: actions/checkout@v4 - with: - path: rtx - - uses: actions/checkout@v4 - with: - repository: jdx/homebrew-tap - path: homebrew-tap - token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - - name: Install fd-find - run: | - sudo apt-get update - sudo apt-get install fd-find - mkdir -p "$HOME/.local/bin" - ln -s $(which fdfind) "$HOME/.local/bin/fd" - echo "$HOME/.local/bin" >> $GITHUB_PATH - - uses: actions/setup-node@v4 - with: - node-version: "20.x" - registry-url: "https://registry.npmjs.org" - - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-west-2 - - uses: shimataro/ssh-key-action@v2 - with: - key: ${{ secrets.RTX_SSH_KEY }} - known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} - - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_KEY }} - git_user_signingkey: true - git_commit_gpgsign: true - workdir: homebrew-tap - - uses: actions/download-artifact@v3 - with: { path: artifacts } - - run: rtx/scripts/release.sh - env: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} - CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} - - name: homebrew-tap push - run: git push - working-directory: homebrew-tap - - name: GitHub Release Assets - uses: softprops/action-gh-release@v1 - if: startsWith(github.event.ref, 'refs/tags/v') - with: - fail_on_unmatched_files: true - draft: false - files: releases/${{github.ref_name}}/* - generate_release_notes: true - token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - - name: Release to aur - run: scripts/release-aur.sh - working-directory: rtx - - name: Release aur-bin - run: scripts/release-aur-bin.sh - working-directory: rtx - bump-homebrew-formula: - runs-on: macos-latest - if: startsWith(github.event.ref, 'refs/tags/v') - timeout-minutes: 10 - needs: [release] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Bump Homebrew formula - uses: dawidd6/action-homebrew-bump-formula@v3 - with: - token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - formula: rtx - bump-alpine: - runs-on: ubuntu-22.04 - container: ghcr.io/jdx/rtx:alpine - timeout-minutes: 30 - needs: [release] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Bump APKBUILD - run: sudo -Eu packager ./scripts/release-alpine.sh - env: - ALPINE_PUB_KEY: ${{ secrets.ALPINE_PUB_KEY }} - ALPINE_PRIV_KEY: ${{ secrets.ALPINE_PRIV_KEY }} - GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} + # super-linter: + # runs-on: ubuntu-latest + # permissions: + # contents: read + # packages: read + # statuses: write + # steps: + # - name: Checkout Code + # uses: actions/checkout@v3 + # with: + # # Full git history is needed to get a proper + # # list of changed files within `super-linter` + # fetch-depth: 0 + # + # - name: Lint Code Base + # uses: super-linter/super-linter@v5 + # env: + # VALIDATE_ALL_CODEBASE: false + # DEFAULT_BRANCH: main + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index fab160ec9..f0cba324f 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -10,8 +10,8 @@ on: schedule: # run at midnight on sunday (utc?) - cron: 0 0 * * 0 -# pull_request: -# branches: ["main"] + # pull_request: + # branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/.gitignore b/.gitignore index deeb5cc06..9afa6f690 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ lcov.info .abuild /aports /aur + +megalinter-reports/ diff --git a/.jscpd.json b/.jscpd.json new file mode 100644 index 000000000..2cee5f5d5 --- /dev/null +++ b/.jscpd.json @@ -0,0 +1,15 @@ +{ + "threshold": 0, + "reporters": ["html", "markdown"], + "ignore": [ + "**/node_modules/**", + "**/.git/**", + "**/.rbenv/**", + "**/.venv/**", + "**/*cache*/**", + "**/.github/**", + "**/.idea/**", + "**/report/**", + "**/*.svg" + ] +} diff --git a/.mega-linter.yml b/.mega-linter.yml new file mode 100644 index 000000000..7eda535bd --- /dev/null +++ b/.mega-linter.yml @@ -0,0 +1,28 @@ +# Configuration file for MegaLinter +# +# See all available variables at https://megalinter.io/latest/config-file/ and in +# linters documentation + +# all, none, or list of linter keys +APPLY_FIXES: all + +# If you use ENABLE variable, all other languages/formats/tooling-formats will +# be disabled by default +# ENABLE: +# - RUST + +DISABLE: + - SPELL + +DISABLE_LINTERS: + - REPOSITORY_CHECKOV + +PRE_COMMANDS: + - command: apk add --no-cache zlib-dev zlib-static openssl-dev libffi-dev + +SHOW_ELAPSED_TIME: true + +#FILEIO_REPORTER: false + +FILTER_REGEX_EXCLUDE: "(completions/|target/)" +JSON_JSONLINT_FILTER_REGEX_EXCLUDE: '(\.vscode/)' diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 000000000..cd310bfaf --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1 @@ +document-start: disable diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 84cdcb37e..8609713b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,11 +16,11 @@ To use the container with VSCode, you'll need to install the [Remote - Container ## Dependencies -* [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that). As of this writing: 1.67.0 but GH actions will use the latest stable whenever it runs. -* [just](https://github.com/casey/just) any version should do, but as of this writing I'm on 1.13.0 -* [md-magic](https://github.com/DavidWells/markdown-magic) -* [shfmt](https://github.com/mvdan/sh) -* [shellcheck](https://www.shellcheck.net/) +- [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that). As of this writing: 1.67.0 but GH actions will use the latest stable whenever it runs. +- [just](https://github.com/casey/just) any version should do, but as of this writing I'm on 1.13.0 +- [md-magic](https://github.com/DavidWells/markdown-magic) +- [shfmt](https://github.com/mvdan/sh) +- [shellcheck](https://www.shellcheck.net/) (you'd think we'd use rtx to fetch these but frankly it's kind of a pain to dogfood rtx while testing it) @@ -29,7 +29,7 @@ To use the container with VSCode, you'll need to install the [Remote - Container Just should be used for just about every task. Here is a full list of its tasks: -``` +```shell ~/src/rtx ❯ just --list Available recipes: build *args # just `cargo build` @@ -61,7 +61,7 @@ Shouldn't require anything special I'm aware of, but `just build` is a good sani I put a shim for `cargo run` that makes it easy to run build + run rtx in dev mode. It's at `.bin/rtx`. What I do is add this to PATH with direnv. Here is my `.envrc`: -``` +```shell source_up_if_exists PATH_add "$(expand_path .bin)" ``` @@ -72,9 +72,9 @@ You don't have to do this, but it makes things like `rtx activate` a lot easier ## Running Tests -* Run only unit tests: `just test-unit` -* Run only E2E tests: `just test-e2e` -* Run all tests: `just test` +- Run only unit tests: `just test-unit` +- Run only E2E tests: `just test-e2e` +- Run all tests: `just test` ## Releasing @@ -82,12 +82,12 @@ Run `just release -x [minor|patch]`. (minor if it is the first release in a mont ## Linting -* Lint codebase: `just lint` -* Lint and fix codebase: `just lint-fix` +- Lint codebase: `just lint` +- Lint and fix codebase: `just lint-fix` ## Generating readme and shell completion files -``` +```shell just pre-commit ``` @@ -95,7 +95,7 @@ just pre-commit This project uses lefthook which will automatically install a pre-commit hook: -``` +```shell brew install lefthook # or install via some other means lefthook install git commit @@ -110,7 +110,7 @@ if actually changing the packaging setup. This is for arm64, but you can change the arch to amd64 if you want. -``` +```shell finch run -ti --rm ubuntu apt update -y apt install -y gpg sudo wget curl @@ -124,7 +124,7 @@ rtx -V ### Amazon Linux 2 (yum) -``` +```shell finch run -ti --rm amazonlinux yum install -y yum-utils yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo @@ -134,7 +134,7 @@ rtx -v ### Fedora (dnf) -``` +```shell finch run -ti --rm fedora dnf install -y dnf-plugins-core dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo diff --git a/README.md b/README.md index 570a02233..f4d647761 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ v20.0.0 _New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction._ rtx is a tool for managing programming language and tool versions. For example, use this to install -a particular version of node.js and ruby for a project. Using `rtx activate`, you can have your +a particular version of Node.js and ruby for a project. Using `rtx activate`, you can have your shell automatically switch to the correct node and ruby versions when you `cd` into the project's directory[^cd]. Other projects on your machine can use a different set of versions. @@ -281,7 +281,7 @@ Supported platforms: - `macos` - `linux` -If you need something else, compile it with [cargo](#cargo). +If you need something else, compile it with `cargo install rtx-cli` (see below). [Windows isn't currently supported.](https://github.com/jdx/rtx/discussions/66) @@ -333,7 +333,7 @@ cargo install rtx-cli --git https://github.com/jdx/rtx --branch main
npm -rtx is available on npm as a precompiled binary. This isn't a node.js package—just distributed +rtx is available on npm as a precompiled binary. This isn't a Node.js package—just distributed via npm. This is useful for JS projects that want to setup rtx via `package.json` or `npx`. ``` @@ -483,8 +483,8 @@ do { Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a bit off startup time by using a pure Python import: add the code below to, for example, `~/.config/xonsh/rtx.py` config file and `import rtx` it in `~/.config/xonsh/rc.xsh`: ```xsh -from pathlib import Path -from xonsh.built_ins import XSH +from pathlib import Path +from xonsh.built_ins import XSH ctx = XSH.ctx rtx_init = subprocess.run([Path('~/bin/rtx').expanduser(),'activate','xonsh'],capture_output=True,encoding="UTF-8").stdout @@ -546,7 +546,7 @@ that has lot more flexibility. It supports functionality that is not possible wi - setting arbitrary env vars while inside the directory - passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdx/rtx-python#virtualenv-support). -- specifying custom plugin urls +- specifying custom plugin URLs Here is what an `.rtx.toml` looks like: @@ -606,7 +606,7 @@ You can also have environment specific config files like `.rtx.production.toml`, #### `[env]` - Arbitrary Environment Variables The `[env]` section of .rtx.toml allows setting arbitrary environment variables. -These can be simple key/value entries like this: +These can be simple key-value entries like this: ```toml [env] @@ -646,7 +646,7 @@ _Note: `env_file` goes at the top of the file, above `[env]`._ NODE_ENV = false # unset a previously set NODE_ENV ``` -#### `[plugins]` - Specify Custom Plugin Repo URLs +#### `[plugins]` - Specify Custom Plugin Repository URLs Use `[plugins]` to add/modify plugin shortnames. Note that this will only modify _new_ plugin installations. Existing plugins can use any URL. @@ -836,7 +836,7 @@ to use this feature. #### `RTX_${PLUGIN}_VERSION` -Set the version for a runtime. For example, `RTX_NODE_VERSION=20` will use node@20.x regardless +Set the version for a runtime. For example, `RTX_NODE_VERSION=20` will use regardless of what is set in `.tool-versions`/`.rtx.toml`. #### `RTX_LEGACY_VERSION_FILE=1` @@ -929,7 +929,7 @@ node = "https://github.com/my-org/rtx-node.git" #### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` -Disables the shorthand aliases for installing plugins. You will have to specify full urls when +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,node` @@ -966,7 +966,7 @@ Defaults to enabled, set to "0" to disable. ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS -versions of runtimes. For example, you may want to specify `lts-hydrogen` as the version for node@20.x +versions of runtimes. For example, you may want to specify `lts-hydrogen` as the version for so you can use set it with `node lts-hydrogen` in `.tool-versions`/`.rtx.toml`. User aliases can be created by adding an `alias.` section to `~/.config/rtx/config.toml`: @@ -997,7 +997,7 @@ echo "lts-fermium 14" rtx uses asdf's plugin ecosystem under the hood. These plugins contain shell scripts like `bin/install` (for installing) and `bin/list-all` (for listing all of the available versions). -See https://github.com/asdf-vm/asdf-plugins for the list of built-in plugins shorthands. See asdf's +See for the list of built-in plugins shorthands. See asdf's [Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn more about how they work. @@ -1023,7 +1023,7 @@ rtx uses [Calver](https://calver.org/) versioning (`2023.6.1`). Breaking changes will be few but when they do happen, they will be communicated in the CLI with plenty of notice whenever possible. -Rather than have semver major releases to communicate change in large releases, +Rather than have SemVer major releases to communicate change in large releases, new functionality and changes can be opted-into with settings like `experimental = true`. This way plugin authors and users can test out new functionality immediately without waiting for a major release. @@ -1194,7 +1194,7 @@ You can see the core plugins with `rtx plugin ls --core`. ## FAQs -### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file. +### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file You can make git ignore these files in 3 different ways: @@ -1299,7 +1299,7 @@ detected with your setup. If you submit a bug report, please include the output ### Windows support? -This is something we'd like to add! https://github.com/jdx/rtx/discussions/66 +This is something we'd like to add! It's not a near-term goal and it would require plugin modifications, but it should be feasible. @@ -1312,12 +1312,11 @@ and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves files with `curl` or `wget`. However this is really up to the plugin. If you're having a proxy-related issue installing something -you should post an issue on the plugin's repo. +you should post an issue on the plugin's repository. ### How do the shorthand plugin names map to repositories? -e.g.: how does `rtx plugin install node` know to fetch [https://github.com/rtx-plugins/rtx-nodejs] -(https://github.com/rtx-plugins/rtx-nodejs)? +e.g.: how does `rtx plugin install elixir` know to fetch ? asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. This is regularly updated every time that rtx has a release. This repository is stored directly into @@ -1415,7 +1414,7 @@ and the runtime itself. e.g.: when you call `node` it will call an asdf shim fil which then calls `asdf exec`, which then calls the correct version of node. These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead -updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo gif at the top of this README +updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo GIF at the top of this README that `rtx` isn't actually used when calling `node -v` for this reason. The performance is identical to running node without using rtx. @@ -1565,7 +1564,7 @@ If you continue to struggle, you can also try using the [shims method](#shims). While making rtx compatible with direnv is, and will always be a major goal of this project, I also want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing -env vars and [virtualenv](https://github.com/jdx/rtx-python#experimental-virtualenv-support) +env vars and [virtualenv](https://github.com/jdx/rtx/blob/main/docs/python.md#experimental-automatic-virtualenv-creationactivation) for python using `.rtx.toml`. If you find you continue to need direnv, please open an issue and let me know what it is to see if diff --git a/SECURITY.md b/SECURITY.md index e0b7664b8..e1cdc802c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -33,13 +33,13 @@ Plugins are by far the biggest source of potential problems and where the most w There are 3 types of plugins: -* [core](https://github.com/jdx/rtx/issues/236) - plugins that are hardcoded into the CLI. +- [core](https://github.com/jdx/rtx/issues/236) - plugins that are hardcoded into the CLI. These are official plugins for the most common languages written in Rust. -* community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. For now these will -only have @jdx as the sole contributor, however this may change in the future for particular plugins with -dedicated owners/collaborators. If you'd like your plugin to be moved here, ask me about it. -* external - plugins owned by other parties, these include plugins in the shorthand registry. These are no more -secure than installing any random tool from the internet. +- community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. For now these will + only have @jdx as the sole contributor, however this may change in the future for particular plugins with + dedicated owners/collaborators. If you'd like your plugin to be moved here, ask me about it. +- external - plugins owned by other parties, these include plugins in the shorthand registry. These are no more + secure than installing any random tool from the internet. Just because a plugin is inside of the shorthand registry (so you can run `rtx install foo@`, does not mean I vouch for it. I have no idea who almost anyone that builds those plugins are. If it's coming from the rtx-plugins @@ -61,7 +61,7 @@ If you want, you may encrypt the message with GPG:
@jdx's public key - + ``` -----BEGIN PGP PUBLIC KEY BLOCK----- @@ -115,5 +115,7 @@ MFPobhR7zlCShd7TdY1a41uxTGB+Wmn4DO0s/wzSgdgxIzG+TM1X47owe7l5RiI1 1wxfuzN2+ao= =/CHf -----END PGP PUBLIC KEY BLOCK----- - ``` + +```
+``` diff --git a/docs/bun.md b/docs/bun.md index 04e855d8a..b67b42799 100644 --- a/docs/bun.md +++ b/docs/bun.md @@ -1,6 +1,6 @@ # Bun in rtx -The following are instructions for using the bun rtx core plugin. This is used when there isn't a +The following are instructions for using the bun rtx core plugin. This is used when there isn't a git plugin installed named "bun". The code for this is inside the rtx repository at @@ -11,8 +11,8 @@ The code for this is inside the rtx repository at The following installs bun and makes it the global default: ```sh-session -$ rtx use -g bun@0.7 # install bun 0.7.x -$ rtx use -g bun@latest # install latest bun +rtx use -g bun@0.7 # install bun 0.7.x +rtx use -g bun@latest # install latest bun ``` See available versions with `rtx ls-remote bun`. diff --git a/docs/demo.sh b/docs/demo.sh index eebbd856a..be85e9dc2 100755 --- a/docs/demo.sh +++ b/docs/demo.sh @@ -3,4 +3,4 @@ set -e cd rm -rf ~/myproj/.* ~/.rtx/installs ~/.config/rtx -PATH="$HOME/.cargo/bin:$PATH" vhs < ~/src/rtx/docs/demo.tape +PATH="$HOME/.cargo/bin:$PATH" vhs <~/src/rtx/docs/demo.tape diff --git a/docs/deno.md b/docs/deno.md index 2a0049fdb..fc6b2bf4f 100644 --- a/docs/deno.md +++ b/docs/deno.md @@ -1,6 +1,6 @@ # Deno in rtx -The following are instructions for using the deno rtx core plugin. This is used when there isn't a +The following are instructions for using the deno rtx core plugin. This is used when there isn't a git plugin installed named "deno". If you want to use [asdf-deno](https://github.com/asdf-community/asdf-deno) @@ -14,8 +14,8 @@ The code for this is inside the rtx repository at The following installs deno and makes it the global default: ```sh-session -$ rtx use -g deno@1 # install deno 1.x -$ rtx use -g deno@latest # install latest deno +rtx use -g deno@1 # install deno 1.x +rtx use -g deno@latest # install latest deno ``` See available versions with `rtx ls-remote deno`. diff --git a/docs/go.md b/docs/go.md index 6202155b8..53081cbe8 100644 --- a/docs/go.md +++ b/docs/go.md @@ -1,6 +1,6 @@ # Go in rtx -The following are instructions for using the go rtx core plugin. This is used when there isn't a +The following are instructions for using the go rtx core plugin. This is used when there isn't a git plugin installed named "go". If you want to use [asdf-golang](https://github.com/kennyp/asdf-golang) @@ -16,7 +16,7 @@ The following installs the latest version of go-1.20.x (if some version of 1.20. installed) and makes it the global default: ```sh-session -$ rtx use -g go@1.20 +rtx use -g go@1.20 ``` ## Configuration @@ -29,11 +29,11 @@ $ rtx use -g go@1.20 ## Default packages -rtx can automatically install a default set of packages right after installing a new go version. -To enable this feature, provide a `$HOME/.default-go-packages` file that lists one packages per +rtx can automatically install a default set of packages right after installing a new go version. +To enable this feature, provide a `$HOME/.default-go-packages` file that lists one packages per line, for example: -``` +```text github.com/Dreamacro/clash # allows comments github.com/jesseduffield/lazygit ``` diff --git a/docs/java.md b/docs/java.md index ebb330623..7edb6a6c6 100644 --- a/docs/java.md +++ b/docs/java.md @@ -1,6 +1,6 @@ # Java in rtx -The following are instructions for using the java rtx core plugin. This is used when there isn't a +The following are instructions for using the java rtx core plugin. This is used when there isn't a git plugin installed named "java". If you want to use [asdf-java](https://github.com/halcyon/asdf-java) @@ -12,12 +12,12 @@ The code for this is inside the rtx repository at ## Usage -The following installs the latest version of java-openjdk-17.x (if some version of openjdk-17.x is +The following installs the latest version of java-openjdk-17.x (if some version of openjdk-17.x is not already installed) and makes it the global default: ```sh-session -$ rtx use -g java@openjdk-17 -$ rtx use -g java@17 # alternate shorthands for openjdk-only +rtx use -g java@openjdk-17 +rtx use -g java@17 # alternate shorthands for openjdk-only ``` See available versions with `rtx ls-remote java`. @@ -29,10 +29,10 @@ Some applications in macOS rely on `/usr/libexec/java_home` to find installed Ja To integrate an installed Java runtime with macOS run the following commands for the proper version (e.g. openjdk-20). ```sh-session -$ sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-20.jdk -$ sudo ln -s ~/.local/share/rtx/installs/java/openjdk-20/Contents /Library/Java/JavaVirtualMachines/openjdk-20.jdk/Contents +sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-20.jdk +sudo ln -s ~/.local/share/rtx/installs/java/openjdk-20/Contents /Library/Java/JavaVirtualMachines/openjdk-20.jdk/Contents ``` -The distribution from Azul Systems does support the integration but the symlink target location will differ from the example above (e.g `~/.local/share/rtx/installs/java/zulu-11.64.190/zulu-11.jdk/Contents`). +The distribution from Azul Systems does support the integration but the symlink target location will differ from the example above (e.g `~/.local/share/rtx/installs/java/zulu-11.64.190/zulu-11.jdk/Contents`). > Note: Not all distributions of the Java SDK support this integration (e.g liberica). diff --git a/docs/node.md b/docs/node.md index 9206de13b..56658f9db 100644 --- a/docs/node.md +++ b/docs/node.md @@ -14,12 +14,12 @@ The following installs the latest version of node-20.x and makes it the global default: ```sh-session -$ rtx use -g node@20 +rtx use -g node@20 ``` ## Requirements -See [BUILDING.md](https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms) in node's documentation for +See [BUILDING.md](https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms) in node's documentation for required system dependencies. ## Configuration @@ -41,7 +41,7 @@ required system dependencies. rtx-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-npm-packages` file that lists one package per line, for example: -``` +```text lodash request express @@ -53,40 +53,6 @@ You can specify a non-default location of this file by setting a `RTX_NODE_DEFAU rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. To ease migration, you can have also have it read an existing `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `node` isn't defined in `.tool-versions`/`.rtx.toml`. -## Running the wrapped node-build command - -We provide a command for running the installed `node-build` command: - -```bash -rtx node node-build --version -``` - -### node-build advanced variations - -`node-build` has some additional variations aside from the versions listed in `rtx ls-remote -node` (chakracore/graalvm branches and some others). As of now, we weakly support these variations. In the sense that they are available for install and can be used in a `.tool-versions` file, but we don't list them as installation candidates nor give them full attention. - -Some of them will work out of the box, and some will need a bit of investigation to get them built. We are planning in providing better support for these variations in the future. - -To list all the available variations run: - -```bash -rtx node node-build --definitions -``` - -_Note that this command only lists the current `node-build` definitions. You might want to [update the local `node-build` repository](#updating-node-build-definitions) before listing them._ - -### Manually updating node-build definitions - -Every new node version needs to have a definition file in the `node-build` repository. -`rtx-node` already tries to update `node-build` on every new version installation, but if you -want to update `node-build` manually for some reason you can clear the cache and list the versions: - -```bash -rtx cache clean -rtx ls-remote node -``` - ## "nodejs" -> "node" Alias You cannot install/use a plugin named "nodejs". If you attempt this, rtx will just renamed it to diff --git a/docs/python.md b/docs/python.md index b2bc3f65d..d992232e3 100644 --- a/docs/python.md +++ b/docs/python.md @@ -11,7 +11,7 @@ The following installs the latest version of python-3.11.x and makes it the glob default: ```sh-session -$ rtx use -g python@3.11 +rtx use -g python@3.11 ``` You can also use multiple versions of python at the same time: @@ -28,7 +28,6 @@ $ python3.11 -V rtx uses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/python-build) (part of pyenv) to install python runtimes, you need to ensure its [dependencies](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) are installed before installing python. - ## Configuration `python-build` already has a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in @@ -43,7 +42,7 @@ additional to that `rtx-python` has a few extra configuration variables: rtx-python can automatically install a default set of Python packages with pip right after installing a Python version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists one package per line, for example: -``` +```text ansible pipenv ``` @@ -53,7 +52,7 @@ You can specify a non-default location of this file by setting a `RTX_PYTHON_DEF ## [experimental] Automatic virtualenv creation/activation Python comes with virtualenv support built in, use it with `.rtx.toml` configuration like -the following: +one of the following: ```toml [tools] diff --git a/docs/ruby.md b/docs/ruby.md index 87f3f9302..1c4b6e2e6 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -1,6 +1,6 @@ # Ruby in rtx -The following are instructions for using the ruby rtx core plugin. This is used when there isn't a +The following are instructions for using the ruby rtx core plugin. This is used when there isn't a git plugin installed named "ruby". If you want to use [asdf-ruby](https://github.com/asdf-vm/asdf-ruby) @@ -16,7 +16,7 @@ The following installs the latest version of ruby-3.2.x (if some version of 3.2. installed) and makes it the global default: ```sh-session -$ rtx use -g ruby@3.2 +rtx use -g ruby@3.2 ``` Behind the scenes, rtx uses [`ruby-build`](https://github.com/rbenv/ruby-build) to compile ruby @@ -39,8 +39,8 @@ in additional to that rtx has a few extra configuration variables: ## Default gems -rtx can automatically install a default set of gems right after installing a new ruby version. -To enable this feature, provide a `$HOME/.default-gems` file that lists one gem per line, for +rtx can automatically install a default set of gems right after installing a new ruby version. +To enable this feature, provide a `$HOME/.default-gems` file that lists one gem per line, for example: ``` @@ -59,12 +59,12 @@ However it can also read ruby-specific version files `.ruby-version` or `Gemfile Create a `.ruby-version` file for the current version of ruby: ```sh-session -$ ruby -v > .ruby-version +ruby -v > .ruby-version ``` ### Manually updating ruby-build -ruby-build should update daily, however if you find versions do not yet exist you can force an +ruby-build should update daily, however if you find versions do not yet exist you can force an update: ```bash diff --git a/packaging/alpine/Dockerfile b/packaging/alpine/Dockerfile index b239b692b..caac20b7c 100644 --- a/packaging/alpine/Dockerfile +++ b/packaging/alpine/Dockerfile @@ -7,3 +7,5 @@ RUN echo "packager ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers RUN mkdir -p /__w && chown packager:packager /__w && chmod 777 /__w #USER packager #WORKDIR /home/packager + +HEALTHCHECK CMD abuild -v diff --git a/packaging/deb/generate-release.sh b/packaging/deb/generate-release.sh index 2b949d7aa..22ed368b4 100755 --- a/packaging/deb/generate-release.sh +++ b/packaging/deb/generate-release.sh @@ -1,20 +1,23 @@ #!/bin/sh set -e +# shellcheck disable=SC2185 +# shellcheck disable=SC2086 +# shellcheck disable=SC2044 do_hash() { - HASH_NAME=$1 - HASH_CMD=$2 - echo "${HASH_NAME}:" - for f in $(find -type f); do - f=$(echo $f | cut -c3-) # remove ./ prefix - if [ "$f" = "Release" ]; then - continue - fi - echo " $(${HASH_CMD} ${f} | cut -d" " -f1) $(wc -c $f)" - done + HASH_NAME=$1 + HASH_CMD=$2 + echo "$HASH_NAME:" + for f in "$(find -type f)"; do + f=$(echo "$f" | cut -c3-) # remove ./ prefix + if [ "$f" = "Release" ]; then + continue + fi + echo " $("$HASH_CMD" "$f" | cut -d" " -f1) $(wc -c "$f")" + done } -cat << EOF +cat <, c: &clap::Command) -> Option { " ### `rtx {usage}` - ``` + ```text {about} ``` diff --git a/src/plugins/core/assets/rubygems_plugin.rb b/src/plugins/core/assets/rubygems_plugin.rb index 353835003..2f2dbbc9a 100644 --- a/src/plugins/core/assets/rubygems_plugin.rb +++ b/src/plugins/core/assets/rubygems_plugin.rb @@ -1,13 +1,13 @@ def debug? - !!ENV['RTX_DEBUG'] + !!ENV["RTX_DEBUG"] end def log_debug(msg) - $stderr.puts "[DEBUG] rtx #{msg}" if debug? + warn "[DEBUG] rtx #{msg}" if debug? end def reshim - if `which ruby`.strip != '' + if `which ruby`.strip != "" log_debug "reshim" `rtx reshim` else From d572c5cd543a0315df7cf99cc640ca6354c762d5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 20:41:43 -0600 Subject: [PATCH 1199/1891] added ability to do dry runs of releases (#1098) --- .devcontainer/Dockerfile | 16 +-- .editorconfig | 11 +- .github/ISSUE_TEMPLATE/blank.md | 9 +- .github/ISSUE_TEMPLATE/bug_report.md | 5 +- .github/ISSUE_TEMPLATE/feature_request.md | 7 +- .github/actionlint.yaml | 18 ++++ .github/restyled.yml | 4 + .github/workflows/release.yml | 84 +++++++++------ .github/workflows/rtx.yml | 62 ++++++----- .github/workflows/test-plugins.yml | 4 +- .hadolint.yaml | 5 + .idea/rtx.iml | 1 + .markdown-link-check.json | 7 ++ .markdownlint.json | 6 ++ .markdownlintignore | 1 + .mega-linter.yml | 7 +- README.md | 116 +++++++++++---------- SECURITY.md | 3 +- docs/python.md | 4 +- e2e/assert.sh | 56 +++++----- e2e/test_poetry | 3 +- justfile | 10 +- packaging/alpine/Dockerfile | 13 +-- packaging/deb/Dockerfile | 5 +- packaging/deb/generate-release.sh | 5 +- packaging/github-actions/Dockerfile | 18 ++-- packaging/homebrew/homebrew.rb | 6 +- packaging/rpm/Dockerfile | 7 +- scripts/build-deb.sh | 40 +++---- scripts/build-rpm.sh | 40 +++---- scripts/build-tarball.sh | 111 ++++++++++---------- scripts/build-windows.ps1 | 5 - scripts/pre-release-hook.sh | 4 +- scripts/publish-s3.sh | 6 +- scripts/release-aur-bin.sh | 48 +++++---- scripts/release-aur.sh | 56 +++++----- scripts/release-npm.sh | 72 ++++++------- scripts/release.sh | 50 ++++----- scripts/render-homebrew.sh | 24 ++--- scripts/render-install.sh | 24 ++--- scripts/setup-zipsign.sh | 4 +- scripts/update-shorthand-repo.sh | 32 +++--- src/cli/local.rs | 2 +- src/http.rs | 4 +- src/plugins/core/assets/rubygems_plugin.rb | 2 + src/plugins/core/java.rs | 2 +- src/plugins/core/node.rs | 2 +- src/plugins/core/node_build.rs | 2 +- src/test.rs | 1 + src/toolset/tool_version.rs | 2 +- 50 files changed, 565 insertions(+), 461 deletions(-) create mode 100644 .github/actionlint.yaml create mode 100644 .hadolint.yaml create mode 100644 .markdown-link-check.json create mode 100644 .markdownlint.json create mode 100644 .markdownlintignore mode change 100644 => 100755 e2e/assert.sh delete mode 100644 scripts/build-windows.ps1 diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3b87849a6..a441e57b0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,23 +1,23 @@ FROM mcr.microsoft.com/devcontainers/rust:0-1-bullseye +SHELL ["/bin/bash", "-o", "pipefail", "-c"] WORKDIR /workspaces/cached # Use another target directory to avoid conflicts with the host target directory -RUN mkdir /workspaces/target ENV CARGO_TARGET_DIR=/workspaces/target - -# Install rust tools -RUN rustup component add clippy llvm-tools rustfmt -RUN cargo install cargo-insta cargo-llvm-cov - -# Install dependencies -RUN export DEBIAN_FRONTEND=noninteractive \ +RUN mkdir /workspaces/target \ + # Install rust tools + && rustup component add clippy llvm-tools rustfmt \ + && cargo install cargo-insta cargo-llvm-cov \ + # Install dependencies + && export DEBIAN_FRONTEND=noninteractive \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get update \ && apt-get -y install --no-install-recommends \ # shells, direnv, shellcheck bash fish zsh direnv nodejs shellcheck \ && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ # shfmt && curl -sS https://webi.sh/shfmt | sh \ # just diff --git a/.editorconfig b/.editorconfig index 7ff8aed42..ac106646c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,11 @@ -[*.sh] -indent_style = tab +[*.toml] +indent_style = space +indent_size = 2 -[Cargo.toml] +[*.sh] indent_style = space indent_size = 2 + +# shfmt +switch_case_indent = true +simplify = true diff --git a/.github/ISSUE_TEMPLATE/blank.md b/.github/ISSUE_TEMPLATE/blank.md index 50fac4f02..612a93fb0 100644 --- a/.github/ISSUE_TEMPLATE/blank.md +++ b/.github/ISSUE_TEMPLATE/blank.md @@ -1,10 +1,7 @@ --- name: Blank about: Blank issue template -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 546fd35dd..5ad2c8038 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: Something not working right? -title: '' +title: "" labels: bug -assignees: '' - +assignees: "" --- **Describe the bug** diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 809b7b057..60f49e9f5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,10 +1,7 @@ --- name: Feature request about: Suggest an idea for this project -title: '' +title: "" labels: enhancement -assignees: '' - +assignees: "" --- - - diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 000000000..012d6a74c --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,18 @@ +self-hosted-runner: + # Labels of self-hosted runner in array of strings. + labels: + - buildjet-32vcpu-ubuntu-2204-arm + - buildjet-16vcpu-ubuntu-2204-arm + - buildjet-8vcpu-ubuntu-2204-arm + - buildjet-4vcpu-ubuntu-2204-arm + - buildjet-2vcpu-ubuntu-2204-arm + - buildjet-32vcpu-ubuntu-2204 + - buildjet-16vcpu-ubuntu-2204 + - buildjet-8vcpu-ubuntu-2204 + - buildjet-4vcpu-ubuntu-2204 + - buildjet-2vcpu-ubuntu-2204 + +# Configuration variables in array of strings defined in your repository or +# organization. `null` means disabling configuration variables check. +# Empty array means no configuration variable is allowed. +config-variables: null diff --git a/.github/restyled.yml b/.github/restyled.yml index d4ca94189..ca41f213f 100644 --- a/.github/restyled.yml +++ b/.github/restyled.yml @@ -1 +1,5 @@ enabled: true +restylers: + - "!shellharden" + - "!prettier-markdown" + - "*" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d9ecb35ea..ffb11da30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,10 @@ on: branches: ["main", "release/*"] workflow_dispatch: +concurrency: + group: release + cancel-in-progress: true + env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 @@ -13,51 +17,72 @@ env: jobs: build-tarball: name: build-tarball-${{matrix.name}} - runs-on: ${{matrix.os}} + runs-on: ${{matrix.runs-on}} timeout-minutes: 45 strategy: fail-fast: false matrix: include: - - os: ubuntu-22.04 + - os: ubuntu name: linux-x64 target: x86_64-unknown-linux-gnu - - os: ubuntu-22.04 + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: ubuntu name: linux-x64-musl - target: aarch64-unknown-linux-musl - - os: ubuntu-22.04 + target: x86_64-unknown-linux-musl + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: ubuntu name: linux-arm64 target: aarch64-unknown-linux-gnu - - os: ubuntu-22.04 + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: ubuntu name: linux-arm64-musl target: aarch64-unknown-linux-musl - - os: ubuntu-22.04 + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: ubuntu name: linux-armv7 target: armv7-unknown-linux-gnueabi - - os: ubuntu-22.04 + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: ubuntu name: linux-armv7-musl target: armv7-unknown-linux-musleabi - - os: ubuntu-22.04 + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: ubuntu name: linux-armv6 target: arm-unknown-linux-gnueabi - - os: ubuntu-22.04 + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: ubuntu name: linux-armv6-musl target: arm-unknown-linux-musleabi - - os: macos-12 + runs-on: buildjet-4vcpu-ubuntu-2204 + - os: macos name: macos-x64 target: x86_64-apple-darwin - - os: macos-12 + runs-on: macos-12 + - os: macos name: macos-arm64 target: aarch64-apple-darwin + runs-on: macos-12 + # - os: macos + # name: macos + # target: universal2-apple-darwin + # runs-on: macos-12 steps: - uses: actions/checkout@v4 - - if: matrix.os == 'macos-12' - run: rustup target add ${{matrix.target}} - - name: Rust Cache - uses: Swatinem/rust-cache@v2 + - if: matrix.target == 'universal2-apple-darwin' + run: | + brew install zig + rustup target add x86_64-apple-darwin + rustup target add aarch64-apple-darwin + cargo install cargo-zigbuild + - run: rustup target add ${{matrix.target}} + if: matrix.target != 'universal2-apple-darwin' + - run: rustup toolchain install stable --profile minimal + - uses: Swatinem/rust-cache@v2 with: - shared-key: "build-tarball-${{matrix.name}}" - - if: matrix.os == 'ubuntu-22.04' + shared-key: build-tarball-${{matrix.name}} + cache-provider: buildjet + - if: matrix.os == 'ubuntu' uses: taiki-e/install-action@cross - run: scripts/setup-zipsign.sh env: @@ -71,7 +96,7 @@ jobs: dist/rtx-*.tar.gz if-no-files-found: error e2e-linux: - runs-on: ubuntu-22.04 + runs-on: buildjet-16vcpu-ubuntu-2204 #container: ghcr.io/jdx/rtx:github-actions needs: [build-tarball] timeout-minutes: 30 @@ -83,8 +108,8 @@ jobs: with: name: tarball-x86_64-unknown-linux-gnu path: dist - - run: tar -C "$HOME" -xvJf dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz - - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH + - run: tar -C "$HOME" -xvJf "dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz" + - run: echo "$HOME/rtx/bin" >> "$GITHUB_PATH" - run: rtx -v - name: Run e2e tests uses: nick-fields/retry@v2 @@ -143,8 +168,7 @@ jobs: path: dist/deb if-no-files-found: error release: - runs-on: ubuntu-22.04 - if: startsWith(github.event.ref, 'refs/tags/v') + runs-on: buildjet-4vcpu-ubuntu-2204 #container: ghcr.io/jdx/rtx:github-actions timeout-minutes: 10 permissions: @@ -154,6 +178,8 @@ jobs: - build-tarball - rpm - deb + env: + DRY_RUN: ${{ startsWith(github.event.ref, 'refs/tags/v') && '0' || '1' }} steps: - uses: actions/checkout@v4 with: @@ -168,18 +194,12 @@ jobs: sudo apt-get update sudo apt-get install fd-find mkdir -p "$HOME/.local/bin" - ln -s $(which fdfind) "$HOME/.local/bin/fd" - echo "$HOME/.local/bin" >> $GITHUB_PATH + ln -s "$(which fdfind)" "$HOME/.local/bin/fd" + echo "$HOME/.local/bin" >> "$GITHUB_PATH" - uses: actions/setup-node@v4 with: node-version: "20.x" registry-url: "https://registry.npmjs.org" - - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-west-2 - uses: shimataro/ssh-key-action@v2 with: key: ${{ secrets.RTX_SSH_KEY }} @@ -199,6 +219,7 @@ jobs: CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} - name: homebrew-tap push + if: startsWith(github.event.ref, 'refs/tags/v') run: git push working-directory: homebrew-tap - name: GitHub Release Assets @@ -231,6 +252,7 @@ jobs: formula: rtx bump-alpine: runs-on: ubuntu-22.04 + if: startsWith(github.event.ref, 'refs/tags/v') container: ghcr.io/jdx/rtx:alpine timeout-minutes: 30 needs: [release] diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index e7f3b3701..0e95ef392 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -3,59 +3,60 @@ name: rtx on: push: tags: ["v*"] - branches: ["main", "release/*"] + branches: ["main"] pull_request: branches: ["main"] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 + RTX_TRUSTED_CONFIG_PATHS: ${{ github.workspace }} jobs: unit: - runs-on: ubuntu-22.04 - container: ghcr.io/jdx/rtx:github-actions + runs-on: buildjet-8vcpu-ubuntu-2204 + #container: ghcr.io/jdx/rtx:github-actions timeout-minutes: 10 steps: - uses: actions/checkout@v4 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} - uses: Swatinem/rust-cache@v2 with: - save-if: false - # - uses: taiki-e/install-action@v2 - # with: - # tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete - # - name: Install direnv/shfmt - # run: sudo apt-get update; sudo apt-get install direnv shfmt + shared-key: unit + save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + cache-provider: buildjet + - uses: taiki-e/install-action@v2 + with: + tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete + - name: Install direnv/shfmt + run: sudo apt-get update; sudo apt-get install direnv shfmt + - run: pnpm i -g markdown-magic prettier markdownlint-cli - run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" - - run: just lint - run: cargo deny check - run: cargo msrv verify - run: cargo machete --with-metadata - - lint-fix: - runs-on: ubuntu-22.04 - timeout-minutes: 10 - if: github.event_name == 'pull_request' - steps: - - uses: actions/checkout@v4 - - uses: Swatinem/rust-cache@v2 - with: - shared-key: test - save-if: false - - run: sudo apt-get update; sudo apt-get install shfmt shellcheck - - uses: taiki-e/install-action@just - - run: just lint-fix - - uses: EndBug/add-and-commit@v9 + - run: just render-all lint-fix + - if: github.event_name == 'pull_request' + uses: EndBug/add-and-commit@v9 with: push: true + author_name: rtx[bot] + author_email: 123107610+rtx-vm@users.noreply.github.com + - run: just lint coverage: name: coverage-${{matrix.tranche}} #container: ghcr.io/jdx/rtx:github-actions - runs-on: ubuntu-latest + runs-on: buildjet-4vcpu-ubuntu-2204 timeout-minutes: 30 strategy: fail-fast: false @@ -63,14 +64,19 @@ jobs: tranche: [0, 1, 2, 3] steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: rustup toolchain install nightly --component llvm-tools-preview - uses: Swatinem/rust-cache@v2 with: - shared-key: test + shared-key: coverage + cache-provider: buildjet save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + cache-all-crates: true - uses: taiki-e/install-action@cargo-llvm-cov - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - - run: npm i -g markdown-magic + - run: pnpm i -g markdown-magic - uses: taiki-e/install-action@just - uses: nick-fields/retry@v2 env: diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index f0cba324f..2b100a217 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -100,7 +100,7 @@ jobs: # dist/rtx-v1.16.0-linux-x64.tar.xz # x86_64-unknown-linux-gnu-v1.16.0-linux-x64.tar.xz - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH + - run: echo "$HOME/rtx/bin" >> "$GITHUB_PATH" - run: rtx -v - name: ${{matrix.command}} uses: nick-fields/retry@v2 @@ -178,7 +178,7 @@ jobs: name: tarball-x86_64-unknown-linux-gnu path: dist - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - - run: echo "$HOME/rtx/bin" >> $GITHUB_PATH + - run: echo "$HOME/rtx/bin" >> "$GITHUB_PATH" - name: rtx install ${{matrix.plugins}}@latest uses: nick-fields/retry@v2 with: diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 000000000..0303e48ae --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1,5 @@ +ignored: + - DL3008 + - DL3018 + - DL3028 + - DL3041 diff --git a/.idea/rtx.iml b/.idea/rtx.iml index 76f92ff1b..1646cdc59 100644 --- a/.idea/rtx.iml +++ b/.idea/rtx.iml @@ -21,6 +21,7 @@ + diff --git a/.markdown-link-check.json b/.markdown-link-check.json new file mode 100644 index 000000000..60967aea0 --- /dev/null +++ b/.markdown-link-check.json @@ -0,0 +1,7 @@ +{ + "ignorePatterns": [ + { + "pattern": "^https://crates.io" + } + ] +} diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 000000000..213af9b63 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,6 @@ +{ + "MD013": false, + "MD033": false, + "MD040": false, + "MD041": false +} diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1 @@ +target/ diff --git a/.mega-linter.yml b/.mega-linter.yml index 7eda535bd..afa427ebb 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -15,7 +15,12 @@ DISABLE: - SPELL DISABLE_LINTERS: + - COPYPASTE_JSCPD + - REPOSITORY_GRYPE - REPOSITORY_CHECKOV + - REPOSITORY_DEVSKIM + - REPOSITORY_KICS + - REPOSITORY_TRIVY PRE_COMMANDS: - command: apk add --no-cache zlib-dev zlib-static openssl-dev libffi-dev @@ -25,4 +30,4 @@ SHOW_ELAPSED_TIME: true #FILEIO_REPORTER: false FILTER_REGEX_EXCLUDE: "(completions/|target/)" -JSON_JSONLINT_FILTER_REGEX_EXCLUDE: '(\.vscode/)' +JSON_JSONLINT_FILTER_REGEX_EXCLUDE: '(\.devcontainer/)' diff --git a/README.md b/README.md index f4d647761..10105a92a 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ v20.0.0 - [IDE Integration](#ide-integration) - [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) + - [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) @@ -221,16 +221,18 @@ See [plugins](#plugins) below. ### Common commands - rtx install node@20.0.0 Install a specific version number - rtx install node@20 Install a fuzzy version number - rtx use node@20 Use node-20.x in current project - rtx use -g node@20 Use node-20.x as global default +```text +rtx install node@20.0.0 Install a specific version number +rtx install node@20 Install a fuzzy version number +rtx use node@20 Use node-20.x in current project +rtx use -g node@20 Use node-20.x as global default - rtx install node Install the current version specified in .tool-versions/.rtx.toml - rtx use node@latest Use latest node in current directory - rtx use -g node@system Use system node as global default +rtx install node Install the current version specified in .tool-versions/.rtx.toml +rtx use node@latest Use latest node in current directory +rtx use -g node@system Use system node as global default - rtx x node@20 -- node app.js Run `node app.js` node-20.x on PATH +rtx x node@20 -- node app.js Run `node app.js` node-20.x on PATH +``` ## Installation @@ -545,7 +547,7 @@ This can also be useful in environments where rtx isn't activated that has lot more flexibility. It supports functionality that is not possible with `.tool-versions`, such as: - setting arbitrary env vars while inside the directory -- passing options to plugins like `virtualenv='.venv'` for [rtx-python](https://github.com/jdx/rtx-python#virtualenv-support). +- passing options to plugins like `virtualenv='.venv'` for [python](https://github.com/jdx/rtx/blob/main/docs/python.md#experimental-automatic-virtualenv-creationactivation). - specifying custom plugin URLs Here is what an `.rtx.toml` looks like: @@ -570,7 +572,7 @@ python = {version='3.10', virtualenv='.venv'} [plugins] # specify a custom repo url # note this will only be used if the plugin does not already exist -python = 'https://github.com/jdx/rtx-python' +python = 'https://github.com/asdf-community/asdf-python' [settings] # project-local settings verbose = true @@ -674,7 +676,7 @@ They support aliases, which means you can have an `.nvmrc` file with `lts/hydrog in rtx and nvm. Here are some of the supported legacy version files: | Plugin | "Legacy" (Idiomatic) Files | -| --------- | -------------------------------------------------- | +|-----------|----------------------------------------------------| | crystal | `.crystal-version` | | elixir | `.exenv-version` | | go | `.go-version`, `go.mod` | @@ -1609,7 +1611,7 @@ behavior. ### `rtx activate [OPTIONS] [SHELL_TYPE]` -``` +```text Initializes rtx in the current shell This should go into your shell's rc file. @@ -1650,7 +1652,7 @@ Examples: ### `rtx alias get ` -``` +```text Show an alias for a plugin This is the contents of an alias. entry in ~/.config/rtx/config.toml @@ -1671,7 +1673,7 @@ Examples: ### `rtx alias ls [PLUGIN]` -``` +```text List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`. @@ -1694,7 +1696,7 @@ Examples: ### `rtx alias set ` -``` +```text Add/update an alias for a plugin This modifies the contents of ~/.config/rtx/config.toml @@ -1717,7 +1719,7 @@ Examples: ### `rtx alias unset ` -``` +```text Clears an alias for a plugin This modifies the contents of ~/.config/rtx/config.toml @@ -1737,7 +1739,7 @@ Examples: ### `rtx bin-paths` -``` +```text List all the active runtime bin paths Usage: bin-paths @@ -1745,7 +1747,7 @@ Usage: bin-paths ### `rtx cache clear` -``` +```text Deletes all cache files in rtx Usage: cache clear @@ -1753,7 +1755,7 @@ Usage: cache clear ### `rtx completion [SHELL]` -``` +```text Generate shell completions Usage: completion [SHELL] @@ -1772,7 +1774,7 @@ Examples: ### `rtx current [PLUGIN]` -``` +```text Shows current active and installed runtime versions This is similar to `rtx ls --current`, but this only shows the runtime @@ -1802,7 +1804,7 @@ Examples: ### `rtx deactivate` -``` +```text Disable rtx for current shell session This can be used to temporarily disable rtx in a shell session. @@ -1818,7 +1820,7 @@ Examples: ### `rtx direnv activate` -``` +```text Output direnv function to use rtx inside direnv See https://github.com/jdx/rtx#direnv for more information @@ -1837,7 +1839,7 @@ Examples: ### `rtx doctor` -``` +```text Check rtx installation for possible problems. Usage: doctor @@ -1849,7 +1851,7 @@ Examples: ### `rtx env [OPTIONS] [TOOL@VERSION]...` -``` +```text Exports env vars to activate rtx a single time Use this if you don't want to permanently install rtx. It's not necessary to @@ -1879,7 +1881,7 @@ Examples: ### `rtx env-vars [OPTIONS] [ENV_VARS]...` -``` +```text Manage environment variables By default this command modifies ".rtx.toml" in the current directory. @@ -1906,7 +1908,7 @@ Options: ### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` -``` +```text Execute a command with tool(s) set use this to avoid modifying the shell session or running ad-hoc commands with rtx tools set. @@ -1946,7 +1948,7 @@ Examples: ### `rtx implode [OPTIONS]` -``` +```text Removes rtx CLI and all related data Skips config directory by default. @@ -1963,7 +1965,7 @@ Options: ### `rtx install [OPTIONS] [TOOL@VERSION]...` -``` +```text Install a tool version This will install a tool version to `~/.local/share/rtx/installs//` @@ -1995,7 +1997,7 @@ Examples: ### `rtx latest [OPTIONS] ` -``` +```text Gets the latest available version for a plugin Usage: latest [OPTIONS] @@ -2018,7 +2020,7 @@ Examples: ### `rtx link [OPTIONS] ` -``` +```text Symlinks a tool version into rtx Use this for adding installs either custom compiled outside @@ -2051,7 +2053,7 @@ Examples: ### `rtx ls [OPTIONS] [PLUGIN]` -``` +```text List installed and/or currently selected tool versions Usage: ls [OPTIONS] [PLUGIN] @@ -2107,7 +2109,7 @@ Examples: ### `rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` -``` +```text List runtime versions available for install note that the results are cached for 24 hours @@ -2143,7 +2145,7 @@ Examples: ### `rtx outdated [TOOL@VERSION]...` -``` +```text Shows outdated tool versions Usage: outdated [TOOL@VERSION]... @@ -2167,7 +2169,7 @@ Examples: ### `rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` -``` +```text Install a plugin note that rtx automatically can install plugins when you install a tool @@ -2215,7 +2217,7 @@ Examples: ### `rtx plugins link [OPTIONS] [PATH]` -``` +```text Symlinks a plugin into rtx This is used for developing a plugin. @@ -2245,7 +2247,7 @@ Examples: ### `rtx plugins ls [OPTIONS]` -``` +```text List installed plugins Can also show remotely available plugins to install. @@ -2283,7 +2285,7 @@ Examples: ### `rtx plugins ls-remote [OPTIONS]` -``` +```text List all available remote plugins The full list is here: https://github.com/jdx/rtx/blob/main/src/default_shorthands.rs @@ -2304,7 +2306,7 @@ Options: ### `rtx plugins uninstall [OPTIONS] [PLUGIN]...` -``` +```text Removes a plugin Usage: plugins uninstall [OPTIONS] [PLUGIN]... @@ -2326,7 +2328,7 @@ Examples: ### `rtx plugins update [PLUGIN]...` -``` +```text Updates a plugin to the latest version note: this updates the plugin itself, not the runtime versions @@ -2345,7 +2347,7 @@ Examples: ### `rtx prune [OPTIONS] [PLUGIN]...` -``` +```text Delete unused versions of tools rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files @@ -2371,7 +2373,7 @@ Examples: ### `rtx reshim` -``` +```text rebuilds the shim farm This creates new shims in ~/.local/share/rtx/shims for CLIs that have been added. @@ -2398,7 +2400,7 @@ Examples: ### `rtx self-update [OPTIONS] [VERSION]` -``` +```text Updates rtx itself Uses the GitHub Releases API to find the latest release and binary @@ -2423,7 +2425,7 @@ Options: ### `rtx settings get ` -``` +```text Show a current setting This is the contents of a single entry in ~/.config/rtx/config.toml @@ -2444,7 +2446,7 @@ Examples: ### `rtx settings ls` -``` +```text Show current settings This is the contents of ~/.config/rtx/config.toml @@ -2461,7 +2463,7 @@ Examples: ### `rtx settings set ` -``` +```text Add/update a setting This modifies the contents of ~/.config/rtx/config.toml @@ -2481,7 +2483,7 @@ Examples: ### `rtx settings unset ` -``` +```text Clears a setting This modifies the contents of ~/.config/rtx/config.toml @@ -2498,7 +2500,7 @@ Examples: ### `rtx shell [OPTIONS] [TOOL@VERSION]...` -``` +```text Sets a tool version for the current shell session Only works in a session where rtx is already activated. @@ -2521,7 +2523,7 @@ Examples: ### `rtx sync node <--brew|--nvm|--nodenv>` -``` +```text Symlinks all tool versions from an external tool into rtx For example, use this to import all Homebrew node installs into rtx @@ -2546,7 +2548,7 @@ Examples: ### `rtx sync python --pyenv` -``` +```text Symlinks all tool versions from an external tool into rtx For example, use this to import all pyenv installs into rtx @@ -2565,7 +2567,7 @@ Examples: ### `rtx trust [OPTIONS] [CONFIG_FILE]` -``` +```text Marks a config file as trusted This means rtx will parse the file with potentially dangerous @@ -2596,7 +2598,7 @@ Examples: ### `rtx uninstall [OPTIONS] ...` -``` +```text Removes runtime versions Usage: uninstall [OPTIONS] ... @@ -2620,7 +2622,7 @@ Examples: ### `rtx upgrade [OPTIONS] [TOOL@VERSION]...` -``` +```text Upgrades outdated tool versions Usage: upgrade [OPTIONS] [TOOL@VERSION]... @@ -2638,7 +2640,7 @@ Options: ### `rtx use [OPTIONS] [TOOL@VERSION]...` -``` +```text Change the active version of a tool locally or globally. This will install the tool if it is not already installed. @@ -2696,7 +2698,7 @@ Examples: ### `rtx version` -``` +```text Show rtx version Usage: version @@ -2704,7 +2706,7 @@ Usage: version ### `rtx where ` -``` +```text Display the installation path for a runtime Must be installed. @@ -2733,7 +2735,7 @@ Examples: ### `rtx which [OPTIONS] ` -``` +```text Shows the path that a bin name points to Usage: which [OPTIONS] diff --git a/SECURITY.md b/SECURITY.md index e1cdc802c..a5fd3b798 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -62,7 +62,7 @@ If you want, you may encrypt the message with GPG:
@jdx's public key - ``` +``` -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBGQfPjUBEADAtjLxcoJlHYNwvN8xYEai/waWZpnKvNWP86kYuX5xqb/GR1wZ @@ -117,5 +117,6 @@ MFPobhR7zlCShd7TdY1a41uxTGB+Wmn4DO0s/wzSgdgxIzG+TM1X47owe7l5RiI1 -----END PGP PUBLIC KEY BLOCK----- ``` +
``` diff --git a/docs/python.md b/docs/python.md index d992232e3..992483407 100644 --- a/docs/python.md +++ b/docs/python.md @@ -31,7 +31,7 @@ rtx uses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/pytho ## Configuration `python-build` already has a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in -additional to that `rtx-python` has a few extra configuration variables: +additional to that python in rtx has a few extra configuration variables: - `RTX_PYENV_REPO` [string]: the default is `https://github.com/pyenv/pyenv.git` - `RTX_PYTHON_PATCH_URL` [string]: A url to a patch file to pass to python-build. @@ -40,7 +40,7 @@ additional to that `rtx-python` has a few extra configuration variables: ## Default Python packages -rtx-python can automatically install a default set of Python packages with pip right after installing a Python version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists one package per line, for example: +rtx can automatically install a default set of Python packages with pip right after installing a Python version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists one package per line, for example: ```text ansible diff --git a/e2e/assert.sh b/e2e/assert.sh old mode 100644 new mode 100755 index 1b3dfa93c..5651ae6b2 --- a/e2e/assert.sh +++ b/e2e/assert.sh @@ -1,44 +1,44 @@ #!/usr/bin/env bash assert() { - local actual - actual="$(bash -c "$1")" - if [[ "$actual" != "$2" ]]; then - echo "Expected '$2' but got '$actual'" - exit 1 - fi + local actual + actual="$(bash -c "$1")" + if [[ "$actual" != "$2" ]]; then + echo "Expected '$2' but got '$actual'" + exit 1 + fi } assert_contains() { - local actual - actual="$(bash -c "$1")" - if [[ "$actual" != *"$2"* ]]; then - echo "Expected '$2' to be in '$actual'" - exit 1 - fi + local actual + actual="$(bash -c "$1")" + if [[ "$actual" != *"$2"* ]]; then + echo "Expected '$2' to be in '$actual'" + exit 1 + fi } assert_not_contains() { - local actual - actual="$(bash -c "$1")" - if [[ "$actual" == *"$2"* ]]; then - echo "Expected '$2' to not be in '$actual'" - exit 1 - fi + local actual + actual="$(bash -c "$1")" + if [[ "$actual" == *"$2"* ]]; then + echo "Expected '$2' to not be in '$actual'" + exit 1 + fi } assert_fail() { - if bash -c "$1" 2>&1; then - echo "Expected failure but succeeded" - exit 1 - fi + if bash -c "$1" 2>&1; then + echo "Expected failure but succeeded" + exit 1 + fi } assert_matches() { - local actual - actual="$(bash -c "$1")" - if [[ ! "$actual" =~ $2 ]]; then - echo "Expected '$2' to match '$actual'" - exit 1 - fi + local actual + actual="$(bash -c "$1")" + if [[ ! "$actual" =~ $2 ]]; then + echo "Expected '$2' to match '$actual'" + exit 1 + fi } diff --git a/e2e/test_poetry b/e2e/test_poetry index a8f59f74c..c669db4d2 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -8,12 +8,13 @@ rm -rf "$RTX_DATA_DIR/cache/poetry" export POETRY_HOME=".poetry" eval "$(rtx activate bash)" -rtx i python +rtx i python && _rtx_hook rtx i poetry && _rtx_hook assert "poetry --version" "Poetry (version 1.7.1)" python3 -V poetry install && _rtx_hook +rtx i poetry -f && _rtx_hook poetry env info assert "$(poetry env info -e) --version" "Python 3.12.0" assert "echo \$VIRTUAL_ENV" "$(poetry env info -p)" diff --git a/justfile b/justfile index 686d088d7..cd00b47c1 100644 --- a/justfile +++ b/justfile @@ -62,7 +62,7 @@ test-coverage: ./e2e/run_all_tests if [[ "${TEST_TRANCHE:-}" == 0 ]]; then rtx trust - just pre-commit + just render-help render-completions render-mangen rtx implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then rtx trust @@ -88,6 +88,8 @@ lint: shellcheck -x {{ scripts }} shfmt -d {{ scripts }} just --unstable --fmt --check + prettier -c $(git ls-files '*.yml' '*.yaml') + markdownlint . # runs linters but makes fixes when possible lint-fix: @@ -96,6 +98,10 @@ lint-fix: shellcheck -x {{ scripts }} shfmt -w {{ scripts }} just --unstable --fmt + prettier -w $(git ls-files '*.yml' '*.yaml') + markdownlint --fix . + +render-all: render-help render-completions render-mangen # regenerate README.md render-help: build @@ -114,7 +120,7 @@ render-mangen: build NO_COLOR=1 rtx render-mangen # called by lefthook precommit hook -pre-commit: render-help render-completions render-mangen lint +pre-commit: render-all lint git add README.md git add completions git add man diff --git a/packaging/alpine/Dockerfile b/packaging/alpine/Dockerfile index caac20b7c..fe36cd91d 100644 --- a/packaging/alpine/Dockerfile +++ b/packaging/alpine/Dockerfile @@ -1,10 +1,11 @@ FROM alpine:edge -RUN apk add --no-cache sudo build-base alpine-sdk bash direnv glab atools -RUN apk fix -RUN adduser -D packager -RUN addgroup packager abuild -RUN echo "packager ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -RUN mkdir -p /__w && chown packager:packager /__w && chmod 777 /__w + +RUN apk add --no-cache sudo build-base alpine-sdk bash direnv glab atools \ + && apk fix \ + && adduser -D packager \ + && addgroup packager abuild \ + && echo "packager ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \ + && mkdir -p /__w && chown packager:packager /__w && chmod 777 /__w #USER packager #WORKDIR /home/packager diff --git a/packaging/deb/Dockerfile b/packaging/deb/Dockerfile index cc926fa74..81a6ce715 100644 --- a/packaging/deb/Dockerfile +++ b/packaging/deb/Dockerfile @@ -2,9 +2,10 @@ FROM ubuntu:22.04 LABEL maintainer="jdx" RUN apt-get update \ - && apt-get install -y \ + && apt-get install --no-install-recommends -y \ build-essential \ ruby \ - && apt-get clean + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* RUN gem install fpm diff --git a/packaging/deb/generate-release.sh b/packaging/deb/generate-release.sh index 22ed368b4..c9ba48e67 100755 --- a/packaging/deb/generate-release.sh +++ b/packaging/deb/generate-release.sh @@ -1,8 +1,9 @@ #!/bin/sh set -e -# shellcheck disable=SC2185 -# shellcheck disable=SC2086 # shellcheck disable=SC2044 +# shellcheck disable=SC2066 +# shellcheck disable=SC2086 +# shellcheck disable=SC2185 do_hash() { HASH_NAME=$1 diff --git a/packaging/github-actions/Dockerfile b/packaging/github-actions/Dockerfile index 5b9a6dcc8..5920b646d 100644 --- a/packaging/github-actions/Dockerfile +++ b/packaging/github-actions/Dockerfile @@ -7,9 +7,11 @@ ENV RUSTUP_HOME="/root/.rustup" ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Etc/UTC -RUN apt-get update \ +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN apt-get update \ && apt-get upgrade -y \ - && apt-get install -y \ + && apt-get install -y --no-install-recommends \ autoconf \ bash \ build-essential \ @@ -48,11 +50,14 @@ RUN apt-get update \ zsh \ && ln -s /usr/bin/{fdfind,fd} \ && mkdir -p /etc/apt/keyrings \ - && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ - && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list \ - && apt-get update && apt-get install -y nodejs \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ + && apt-get update && apt-get install -y --no-install-recommends nodejs \ && node -v \ - && npm i -g markdown-magic \ + && npm i -g \ + markdown-magic \ + markdownlint-cli \ + prettier \ && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ && curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash \ && rustup install stable && rustup default stable \ @@ -68,6 +73,7 @@ RUN apt-get update \ just \ zipsign \ && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ && rustc -vV \ && cargo -V \ && node -v \ diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index efe995e0a..ea50bb15a 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Rtx < Formula desc "Multi-language runtime manager" homepage "https://github.com/jdx/rtx" @@ -29,9 +31,9 @@ class Rtx < Formula def install bin.install "bin/rtx" man1.install "man/man1/rtx.1" - generate_completions_from_executable(bin/"rtx", "completion") + generate_completions_from_executable(bin / "rtx", "completion") lib.mkpath - touch lib/".disable-self-update" + touch lib / ".disable-self-update" end test do diff --git a/packaging/rpm/Dockerfile b/packaging/rpm/Dockerfile index e58badc26..15d63e8f4 100644 --- a/packaging/rpm/Dockerfile +++ b/packaging/rpm/Dockerfile @@ -1,6 +1,7 @@ FROM fedora:38 LABEL maintainer="jdx" -RUN dnf install -y rpm-build rpm-sign ruby ruby-devel gcc -RUN gem install fpm -RUN dnf install -y createrepo +RUN dnf install -y rpm-build rpm-sign ruby ruby-devel gcc \ + && gem install fpm \ + && dnf install -y createrepo \ + && dnf clean all diff --git a/scripts/build-deb.sh b/scripts/build-deb.sh index 9182978fa..dca75d3c7 100755 --- a/scripts/build-deb.sh +++ b/scripts/build-deb.sh @@ -8,29 +8,29 @@ touch rtx/lib/.disable-self-update tar -xvJf "dist/rtx-$RTX_VERSION-linux-x64.tar.xz" fpm -s dir -t deb \ - --name rtx \ - --license MIT \ - --version "${RTX_VERSION#v*}" \ - --architecture amd64 \ - --description "Polyglot runtime manager" \ - --url "https://github.com/jdx/rtx" \ - --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + --name rtx \ + --license MIT \ + --version "${RTX_VERSION#v*}" \ + --architecture amd64 \ + --description "Polyglot runtime manager" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ + rtx/bin/rtx=/usr/bin/rtx \ + rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 tar -xvJf "dist/rtx-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t deb \ - --name rtx \ - --license MIT \ - --version "${RTX_VERSION#v*}" \ - --architecture arm64 \ - --description "Polyglot runtime manager" \ - --url "https://github.com/jdx/rtx" \ - --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + --name rtx \ + --license MIT \ + --version "${RTX_VERSION#v*}" \ + --architecture arm64 \ + --description "Polyglot runtime manager" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ + rtx/bin/rtx=/usr/bin/rtx \ + rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 mkdir -p dist/deb/pool/main cp -v ./*.deb dist/deb/pool/main diff --git a/scripts/build-rpm.sh b/scripts/build-rpm.sh index e2ae06555..5ae865985 100755 --- a/scripts/build-rpm.sh +++ b/scripts/build-rpm.sh @@ -8,29 +8,29 @@ touch rtx/lib/.disable-self-update tar -xvJf "dist/rtx-$RTX_VERSION-linux-x64.tar.xz" fpm -s dir -t rpm \ - --name rtx \ - --license MIT \ - --version "${RTX_VERSION#v*}" \ - --architecture x86_64 \ - --description "Polyglot runtime manager" \ - --url "https://github.com/jdx/rtx" \ - --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + --name rtx \ + --license MIT \ + --version "${RTX_VERSION#v*}" \ + --architecture x86_64 \ + --description "Polyglot runtime manager" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ + rtx/bin/rtx=/usr/bin/rtx \ + rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 tar -xvJf "dist/rtx-$RTX_VERSION-linux-arm64.tar.xz" fpm -s dir -t rpm \ - --name rtx \ - --license MIT \ - --version "${RTX_VERSION#v*}" \ - --architecture aarch64 \ - --description "Polyglot runtime manager" \ - --url "https://github.com/jdx/rtx" \ - --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + --name rtx \ + --license MIT \ + --version "${RTX_VERSION#v*}" \ + --architecture aarch64 \ + --description "Polyglot runtime manager" \ + --url "https://github.com/jdx/rtx" \ + --maintainer "Jeff Dickey @jdx" \ + rtx/bin/rtx=/usr/bin/rtx \ + rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ + rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 cat <~/.rpmmacros %_signature gpg diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index c641fdafa..39715a5da 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -2,72 +2,75 @@ set -euo pipefail error() { - echo "$@" >&2 - exit 1 + echo "$@" >&2 + exit 1 } NAME="$1" shift for arg in "$@"; do - if [ "${next_target:-}" = 1 ]; then - next_target= - TARGET="$arg" - continue - fi - case "$arg" in - --target) - next_target=1 - ;; - *) ;; + if [ "${next_target:-}" = 1 ]; then + next_target= + TARGET="$arg" + continue + fi + case "$arg" in + --target) + next_target=1 + ;; + *) ;; - esac + esac done RUST_TRIPLE=${TARGET:-$(rustc -vV | grep ^host: | cut -d ' ' -f2)} #region os/arch get_os() { - case "$RUST_TRIPLE" in - *-apple-darwin*) - echo "macos" - ;; - *-linux-*) - echo "linux" - ;; - *) - error "unsupported OS: $RUST_TRIPLE" - ;; - esac + case "$RUST_TRIPLE" in + *-apple-darwin*) + echo "macos" + ;; + *-linux-*) + echo "linux" + ;; + *) + error "unsupported OS: $RUST_TRIPLE" + ;; + esac } get_arch() { - case "$RUST_TRIPLE" in - aarch64-*) - echo "arm64" - ;; - arm-*) - echo "armv6" - ;; - armv7-*) - echo "armv7" - ;; - x86_64-*) - echo "x64" - ;; - *) - error "unsupported arch: $RUST_TRIPLE" - ;; - esac + case "$RUST_TRIPLE" in + aarch64-*) + echo "arm64" + ;; + arm-*) + echo "armv6" + ;; + armv7-*) + echo "armv7" + ;; + x86_64-*) + echo "x64" + ;; + universal2-*) + echo "universal" + ;; + *) + error "unsupported arch: $RUST_TRIPLE" + ;; + esac } get_suffix() { - case "$RUST_TRIPLE" in - *-musl | *-musleabi | *-musleabihf) - echo "-musl" - ;; - *) - echo "" - ;; - esac + case "$RUST_TRIPLE" in + *-musl | *-musleabi | *-musleabihf) + echo "-musl" + ;; + *) + echo "" + ;; + esac } #endregion @@ -76,9 +79,11 @@ VERSION=$(./scripts/get-version.sh) BASENAME=$NAME-$VERSION-$(get_os)-$(get_arch)$(get_suffix) if command -v cross >/dev/null; then - cross build "$@" + cross build "$@" +elif command -v zig >/dev/null; then + cargo zigbuild "$@" else - cargo build "$@" + cargo build "$@" fi mkdir -p dist/rtx/bin mkdir -p dist/rtx/man/man1 @@ -94,8 +99,8 @@ tar -cJf "$BASENAME.tar.xz" rtx tar -czf "$BASENAME.tar.gz" rtx if [ -f ~/.zipsign/rtx.priv ]; then - zipsign sign tar "$BASENAME.tar.gz" ~/.zipsign/rtx.priv - zipsign verify tar "$BASENAME.tar.gz" ../zipsign.pub + zipsign sign tar "$BASENAME.tar.gz" ~/.zipsign/rtx.priv + zipsign verify tar "$BASENAME.tar.gz" ../zipsign.pub fi ls -oh "$BASENAME.tar.xz" diff --git a/scripts/build-windows.ps1 b/scripts/build-windows.ps1 deleted file mode 100644 index e846320e1..000000000 --- a/scripts/build-windows.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -Get-ChildItem target\release -New-Item dist\rtx\bin -ItemType Directory -ea 0 -Copy-Item target\release\rtx.exe dist\rtx\bin\rtx.exe -$Env:RTX_VERSION = (cargo get version --pretty) -Compress-Archive -Path dist\rtx -DestinationPath dist\rtx-$env:RTX_VERSION-windows-x64.zip diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index e1fd6adf6..4e051d9ad 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -2,9 +2,9 @@ set -euxo pipefail if [[ "${NO_UPDATE:-}" == "1" ]]; then - echo "NO_UPDATE is set, skipping update" + echo "NO_UPDATE is set, skipping update" else - cargo update && git add Cargo.lock + cargo update && git add Cargo.lock fi just render-mangen render-help diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index f63d25893..4852411ee 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -26,6 +26,6 @@ aws s3 cp artifacts/deb/dists/ "s3://$AWS_S3_BUCKET/deb/dists/" --cache-control export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 export CLOUDFLARE_ZONE_ID=80d977fd09f01db52bec165778088891 curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ - -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ - -H "Content-Type: application/json" \ - --data '{ "purge_everything": true }' + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data '{ "purge_everything": true }' diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index ff9f4c349..74eba3c4f 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -3,12 +3,12 @@ set -euxo pipefail RTX_VERSION=$(./scripts/get-version.sh) -TAR_GZ_URI="https://github.com/jdx/rtx/releases/download/${RTX_VERSION}/rtx-${RTX_VERSION}-linux-x64.tar.gz" +TAR_GZ_URI="https://github.com/jdx/rtx/releases/download/$RTX_VERSION/rtx-$RTX_VERSION-linux-x64.tar.gz" SHA512=$(curl -L "$TAR_GZ_URI" | sha512sum | awk '{print $1}') if [ ! -d aur-bin ]; then - git clone ssh://aur@aur.archlinux.org/rtx-bin.git aur-bin + git clone ssh://aur@aur.archlinux.org/rtx-bin.git aur-bin fi git -C aur-bin pull @@ -29,19 +29,19 @@ source=("rtx-\$pkgver.tar.gz::${TAR_GZ_URI}") sha512sums=('$SHA512') build() { - cd "\$srcdir/" - rtx/bin/rtx completions bash > rtx.bash - rtx/bin/rtx completions fish > rtx.fish - rtx/bin/rtx completions zsh > _rtx + cd "\$srcdir/" + rtx/bin/rtx completions bash > rtx.bash + rtx/bin/rtx completions fish > rtx.fish + rtx/bin/rtx completions zsh > _rtx } package() { - cd "\$srcdir/" - install -Dm755 rtx/bin/rtx "\$pkgdir/usr/bin/rtx" - install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" - install -Dm644 rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" - install -Dm644 rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" - install -Dm644 _rtx "\$pkgdir/usr/share/zsh/site-functions/_rtx" + cd "\$srcdir/" + install -Dm755 rtx/bin/rtx "\$pkgdir/usr/bin/rtx" + install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" + install -Dm644 rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" + install -Dm644 rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" + install -Dm644 _rtx "\$pkgdir/usr/share/zsh/site-functions/_rtx" } check() { @@ -51,16 +51,16 @@ EOF cat >aur-bin/.SRCINFO <aur/.SRCINFO <&2 - exit 1 + echo "$@" >&2 + exit 1 } if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then - echo "NODE_AUTH_TOKEN must be set" >&2 - exit 0 + echo "NODE_AUTH_TOKEN must be set" >&2 + exit 0 fi mkdir -p "$RELEASE_DIR/npm" dist_tag_from_version() { - IFS="-" read -r -a version_split <<<"$1" - IFS="." read -r -a version_split <<<"${version_split[1]:-latest}" - echo "${version_split[0]}" + IFS="-" read -r -a version_split <<<"$1" + IFS="." read -r -a version_split <<<"${version_split[1]:-latest}" + echo "${version_split[0]}" } dist_tag="$(dist_tag_from_version "$RTX_VERSION")" platforms=( - linux-x64 - linux-x64-musl - linux-arm64 - linux-arm64-musl - linux-armv6 - linux-armv6-musl - linux-armv7 - linux-armv7-musl - macos-x64 - macos-arm64 + linux-x64 + linux-x64-musl + linux-arm64 + linux-arm64-musl + linux-armv6 + linux-armv6-musl + linux-armv7 + linux-armv7-musl + macos-x64 + macos-arm64 ) for platform in "${platforms[@]}"; do - # shellcheck disable=SC2206 - platform_split=(${platform//-/ }) - os="${platform_split[0]}" - arch="${platform_split[1]}" - - if [[ "$os" == "macos" ]]; then - os="darwin" - fi - - cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" - cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" - tar -xzvf "$RELEASE_DIR/rtx-latest-$platform.tar.gz" -C "$RELEASE_DIR" - rm -rf "$RELEASE_DIR/npm" - mv "$RELEASE_DIR/rtx" "$RELEASE_DIR/npm" - cat <"$RELEASE_DIR/npm/package.json" + # shellcheck disable=SC2206 + platform_split=(${platform//-/ }) + os="${platform_split[0]}" + arch="${platform_split[1]}" + + if [[ "$os" == "macos" ]]; then + os="darwin" + fi + + cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" + cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" + tar -xzvf "$RELEASE_DIR/rtx-latest-$platform.tar.gz" -C "$RELEASE_DIR" + rm -rf "$RELEASE_DIR/npm" + mv "$RELEASE_DIR/rtx" "$RELEASE_DIR/npm" + cat <"$RELEASE_DIR/npm/package.json" { "name": "$NPM_PREFIX-$os-$arch", "version": "$RTX_VERSION", @@ -68,10 +68,10 @@ for platform in "${platforms[@]}"; do "cpu": "$arch" } EOF - pushd "$RELEASE_DIR/npm" - tree || true - npm publish --access public --tag "$dist_tag" - popd + pushd "$RELEASE_DIR/npm" + tree || true + npm publish --access public --tag "$dist_tag" + popd done cat <"$RELEASE_DIR/npm/installArchSpecificPackage.js" diff --git a/scripts/release.sh b/scripts/release.sh index 5c569605f..577c770d8 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -10,30 +10,30 @@ export RTX_VERSION RELEASE_DIR rm -rf "${RELEASE_DIR:?}/$RTX_VERSION" mkdir -p "$RELEASE_DIR/$RTX_VERSION" -targets=$(find artifacts -name 'tarball-*' -exec basename {} \; | sed 's/^tarball-//') -for target in "${targets[@]}"; do - cp "artifacts/tarball-$target/"*.tar.gz "$RELEASE_DIR/$RTX_VERSION" - cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$RTX_VERSION" -done +find artifacts -name 'tarball-*' -exec sh -c ' + target=${1#artifacts/tarball-} + cp "artifacts/tarball-$target/"*.tar.gz "$RELEASE_DIR/$RTX_VERSION" + cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$RTX_VERSION" + ' sh {} \; platforms=( - linux-x64 - linux-x64-musl - linux-arm64 - linux-arm64-musl - linux-armv6 - linux-armv6-musl - linux-armv7 - linux-armv7-musl - macos-x64 - macos-arm64 + linux-x64 + linux-x64-musl + linux-arm64 + linux-arm64-musl + linux-armv6 + linux-armv6-musl + linux-armv7 + linux-armv7-musl + macos-x64 + macos-arm64 ) for platform in "${platforms[@]}"; do - cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" - cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" - tar -xvzf "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" - cp -v rtx/bin/rtx "$RELEASE_DIR/rtx-latest-$platform" - cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" + cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" + cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" + tar -xvzf "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" + cp -v rtx/bin/rtx "$RELEASE_DIR/rtx-latest-$platform" + cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" done pushd "$RELEASE_DIR" @@ -56,10 +56,12 @@ popd ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh -NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh -NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh -#AWS_S3_BUCKET=rtx.pub ./rtx/scripts/publish-s3.sh -./rtx/scripts/publish-r2.sh +if [[ "$DRY_RUN" != 1 ]]; then + NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh + NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh + #AWS_S3_BUCKET=rtx.pub ./rtx/scripts/publish-s3.sh + ./rtx/scripts/publish-r2.sh +fi ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb pushd homebrew-tap diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index 3e297ac65..51c1e85aa 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -3,15 +3,15 @@ set -euxo pipefail # shellcheck disable=SC2016 RTX_VERSION=${RTX_VERSION#v*} \ - RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_X86_64_MUSL=$(grep "rtx-v$RTX_VERSION-linux-x64-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64_MUSL=$(grep "rtx-v$RTX_VERSION-linux-arm64-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV6=$(grep "rtx-v$RTX_VERSION-linux-armv6.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV6_MUSL=$(grep "rtx-v$RTX_VERSION-linux-armv6-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV7=$(grep "rtx-v$RTX_VERSION-linux-armv7.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV7_MUSL=$(grep "rtx-v$RTX_VERSION-linux-armv7-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ - >src/default_shorthands.rs + plugin=$(basename "$file") + repository=$(cat "$file") + repository="${repository/#repository = /}" + echo " (\"$plugin\", \"$repository\")," >>src/default_shorthands.rs done echo " // rtx custom shorthands" >>src/default_shorthands.rs for plugin in "${custom_plugins[@]}"; do - echo " $plugin" >>src/default_shorthands.rs + echo " $plugin" >>src/default_shorthands.rs done echo "];" >>src/default_shorthands.rs rm -rf asdf-plugins diff --git a/src/cli/local.rs b/src/cli/local.rs index 0c09713ec..e57838cc6 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -123,7 +123,7 @@ pub fn local( } if !runtime.is_empty() { - let runtimes = ToolArg::double_tool_condition(&runtime.clone()); + let runtimes = ToolArg::double_tool_condition(&runtime); if cf.display_runtime(out, &runtimes)? { return Ok(()); } diff --git a/src/http.rs b/src/http.rs index 4777fd458..48cd5859c 100644 --- a/src/http.rs +++ b/src/http.rs @@ -59,7 +59,7 @@ impl Client { T: serde::de::DeserializeOwned, { let url = url.into_url().unwrap(); - let resp = self.get(url.clone())?; + let resp = self.get(url)?; let json = resp.json()?; Ok(json) } @@ -67,7 +67,7 @@ impl Client { pub fn download_file(&self, url: U, path: &Path) -> Result<()> { let url = url.into_url()?; debug!("GET Downloading {} to {}", &url, display_path(path)); - let mut resp = self.get(url.clone())?; + let mut resp = self.get(url)?; file::create_dir_all(path.parent().unwrap())?; let mut file = File::create(path)?; diff --git a/src/plugins/core/assets/rubygems_plugin.rb b/src/plugins/core/assets/rubygems_plugin.rb index 2f2dbbc9a..bd88173f6 100644 --- a/src/plugins/core/assets/rubygems_plugin.rb +++ b/src/plugins/core/assets/rubygems_plugin.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + def debug? !!ENV["RTX_DEBUG"] end diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 457ee90e8..a184e3277 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -143,7 +143,7 @@ impl JavaPlugin { .find(|e| e.as_ref().unwrap().file_type().unwrap().is_dir()) .unwrap()? .path(); - let contents_dir = basedir.join("Contents").clone(); + let contents_dir = basedir.join("Contents"); let source_dir = match m.vendor.as_str() { "zulu" | "liberica" => basedir, _ if os() == "macosx" => basedir.join("Contents").join("Home"), diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 9027f76d9..ce7e0390d 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -257,7 +257,7 @@ impl Plugin for NodePlugin { let body = body.trim().strip_prefix('v').unwrap_or(&body); // replace lts/* with lts let body = body.replace("lts/*", "lts"); - Ok(body.to_string()) + Ok(body) } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index 2290529b2..be83e4265 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -218,7 +218,7 @@ impl Plugin for NodeBuildPlugin { let body = body.trim().strip_prefix('v').unwrap_or(&body); // replace lts/* with lts let body = body.replace("lts/*", "lts"); - Ok(body.to_string()) + Ok(body) } fn external_commands(&self) -> Result> { diff --git a/src/test.rs b/src/test.rs index dd9597b5f..66ae0be0c 100644 --- a/src/test.rs +++ b/src/test.rs @@ -14,6 +14,7 @@ fn init() { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test"), ); set_current_dir(env::HOME.join("cwd")).unwrap(); + env::remove_var("RTX_TRUSTED_CONFIG_PATHS"); env::set_var("NO_COLOR", "1"); env::set_var("RTX_YES", "1"); env::set_var("RTX_USE_TOML", "0"); diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index f9b07ad01..ee51a7bfc 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -44,7 +44,7 @@ impl ToolVersion { latest_versions: bool, ) -> Result { if !tool.is_installed() { - let tv = Self::new(tool, request.clone(), opts.clone(), request.version()); + let tv = Self::new(tool, request.clone(), opts, request.version()); return Ok(tv); } let tv = match request.clone() { From aa4df560968c63844e03a4645fbc8d92721c7747 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 20:45:01 -0600 Subject: [PATCH 1200/1891] CI: pnpm -> npm --- .github/workflows/rtx.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 0e95ef392..611f9aa56 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -37,7 +37,7 @@ jobs: tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete - name: Install direnv/shfmt run: sudo apt-get update; sudo apt-get install direnv shfmt - - run: pnpm i -g markdown-magic prettier markdownlint-cli + - run: npm i -g markdown-magic prettier markdownlint-cli - run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" @@ -76,7 +76,7 @@ jobs: cache-all-crates: true - uses: taiki-e/install-action@cargo-llvm-cov - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - - run: pnpm i -g markdown-magic + - run: npm i -g markdown-magic - uses: taiki-e/install-action@just - uses: nick-fields/retry@v2 env: From 6b31c6142ab2fe52a7564721134a08b75adeb2bd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:05:17 -0600 Subject: [PATCH 1201/1891] cache zipsign binary --- .github/workflows/release.yml | 11 ++++------- scripts/setup-zipsign.sh | 5 ++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ffb11da30..ef0bcd0e7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,14 +69,11 @@ jobs: # runs-on: macos-12 steps: - uses: actions/checkout@v4 - - if: matrix.target == 'universal2-apple-darwin' - run: | - brew install zig - rustup target add x86_64-apple-darwin - rustup target add aarch64-apple-darwin - cargo install cargo-zigbuild + - uses: buildjet/cache@v3 + with: + path: ~/.cargo/bin/zipsign + key: ${{ runner.os }}-cargo-zipsign - run: rustup target add ${{matrix.target}} - if: matrix.target != 'universal2-apple-darwin' - run: rustup toolchain install stable --profile minimal - uses: Swatinem/rust-cache@v2 with: diff --git a/scripts/setup-zipsign.sh b/scripts/setup-zipsign.sh index 3d9fe6c06..8597444e0 100755 --- a/scripts/setup-zipsign.sh +++ b/scripts/setup-zipsign.sh @@ -6,6 +6,9 @@ if [ -z "$ZIPSIGN" ]; then exit 0 fi -cargo install zipsign +if ! command -v zipsign >/dev/null 2>&1; then + cargo install zipsign +fi + mkdir -p ~/.zipsign echo "$ZIPSIGN" | base64 -d >~/.zipsign/rtx.priv From d45297e7bff76570980ee37ee4de52d855805207 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:11:25 -0600 Subject: [PATCH 1202/1891] CI: use buildjet/github cache --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ef0bcd0e7..7599e40d4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,7 +69,7 @@ jobs: # runs-on: macos-12 steps: - uses: actions/checkout@v4 - - uses: buildjet/cache@v3 + - uses: ${{ matrix.os == 'macos' ?? 'actions/cache@v3' || 'buildjet/cache@v3' }} with: path: ~/.cargo/bin/zipsign key: ${{ runner.os }}-cargo-zipsign @@ -78,7 +78,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: shared-key: build-tarball-${{matrix.name}} - cache-provider: buildjet + cache-provider: ${{ matrix.os == 'macos' ?? 'github' || 'buildjet' }} - if: matrix.os == 'ubuntu' uses: taiki-e/install-action@cross - run: scripts/setup-zipsign.sh From d519409658f1e27702b32a1aa5f4b160c5fc5dac Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:14:18 -0600 Subject: [PATCH 1203/1891] CI: fixed actions syntax --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7599e40d4..6cf5db996 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,7 +69,7 @@ jobs: # runs-on: macos-12 steps: - uses: actions/checkout@v4 - - uses: ${{ matrix.os == 'macos' ?? 'actions/cache@v3' || 'buildjet/cache@v3' }} + - uses: ${{ matrix.os == 'macos' && 'actions/cache@v3' || 'buildjet/cache@v3' }} with: path: ~/.cargo/bin/zipsign key: ${{ runner.os }}-cargo-zipsign @@ -78,7 +78,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: shared-key: build-tarball-${{matrix.name}} - cache-provider: ${{ matrix.os == 'macos' ?? 'github' || 'buildjet' }} + cache-provider: ${{ matrix.os == 'macos' && 'github' || 'buildjet' }} - if: matrix.os == 'ubuntu' uses: taiki-e/install-action@cross - run: scripts/setup-zipsign.sh From 6370ba2d002acfbd1f840d9b09d365463e71c296 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:16:03 -0600 Subject: [PATCH 1204/1891] CI: fixed actions syntax --- .github/workflows/release.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6cf5db996..cf810471d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,7 +69,13 @@ jobs: # runs-on: macos-12 steps: - uses: actions/checkout@v4 - - uses: ${{ matrix.os == 'macos' && 'actions/cache@v3' || 'buildjet/cache@v3' }} + - if: matrix.os == 'macos' + uses: actions/cache@v3 + with: + path: ~/.cargo/bin/zipsign + key: ${{ runner.os }}-cargo-zipsign + - if: matrix.os == 'ubuntu' + uses: buildjet/cache@v3 with: path: ~/.cargo/bin/zipsign key: ${{ runner.os }}-cargo-zipsign From b9fb155ce95be4433d27159d78896293a9ae0d8c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:32:38 -0600 Subject: [PATCH 1205/1891] chore: Release rtx-cli version 2023.12.12 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c5a69533..0e733d24b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.11" +version = "2023.12.12" dependencies = [ "base64", "built", @@ -2604,9 +2604,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" diff --git a/Cargo.toml b/Cargo.toml index 4f82c8d2a..700fea47d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.11" +version = "2023.12.12" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 10105a92a..ad7d70b6a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.11 +rtx 2023.12.12 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.11/rtx-v2023.12.11-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.12/rtx-v2023.12.12-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ce8de6271..7286945ba 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.11"; + version = "2023.12.12"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index cc5b3f4a4..2bc37b5ec 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.11 +Version: 2023.12.12 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 6bce08700e92904505e0deedbc8428954b8fba2b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:34:58 -0600 Subject: [PATCH 1206/1891] CI: allow tag + branch to run the release workflow at the same time --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf810471d..65f60267e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: workflow_dispatch: concurrency: - group: release + group: release-${{ github.ref_name }} cancel-in-progress: true env: From 232f10c8ad60eb660719bd2bf37265f775008bb9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:43:39 -0600 Subject: [PATCH 1207/1891] chore: Release rtx-cli version 2023.12.13 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e733d24b..261a83f62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.12" +version = "2023.12.13" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 700fea47d..9026d7873 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.12" +version = "2023.12.13" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index ad7d70b6a..1a29839e9 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.12 +rtx 2023.12.13 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.12/rtx-v2023.12.12-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.13/rtx-v2023.12.13-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 7286945ba..321d0b989 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.12"; + version = "2023.12.13"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 2bc37b5ec..312ed098a 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.12 +Version: 2023.12.13 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From f63a229abf95027d69cca45a6e633f82b046b96a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:54:15 -0600 Subject: [PATCH 1208/1891] CI: stop using custom container since it is missing gpg and it broke the most recent release --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65f60267e..2b17e9e9e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,7 +126,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-tarball] timeout-minutes: 10 - container: ghcr.io/jdx/rtx:rpm + # container: ghcr.io/jdx/rtx:rpm steps: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 @@ -148,7 +148,7 @@ jobs: if-no-files-found: error deb: runs-on: ubuntu-22.04 - container: ghcr.io/jdx/rtx:deb + # container: ghcr.io/jdx/rtx:deb timeout-minutes: 10 needs: [build-tarball] steps: From 84b5aac41b296646bfd73cebbb765d043d0550c0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:54:44 -0600 Subject: [PATCH 1209/1891] chore: Release rtx-cli version 2023.12.14 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 261a83f62..1e0494eaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.13" +version = "2023.12.14" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 9026d7873..0bd18bd9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.13" +version = "2023.12.14" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 1a29839e9..359cb3660 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.13 +rtx 2023.12.14 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.13/rtx-v2023.12.13-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.14/rtx-v2023.12.14-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 321d0b989..ea0d08936 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.13"; + version = "2023.12.14"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 312ed098a..b98466321 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.13 +Version: 2023.12.14 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From b3d229b02c61fa2c579cf08a6c7f0b5c1f7d545f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:07:58 -0600 Subject: [PATCH 1210/1891] CI: use correct release containers --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2b17e9e9e..8ec585cbc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,7 +126,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-tarball] timeout-minutes: 10 - # container: ghcr.io/jdx/rtx:rpm + container: jdxcode/rtx:rpm steps: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 @@ -148,7 +148,7 @@ jobs: if-no-files-found: error deb: runs-on: ubuntu-22.04 - # container: ghcr.io/jdx/rtx:deb + container: jdxcode/rtx:deb timeout-minutes: 10 needs: [build-tarball] steps: From 0986a797ff3519ac090a34bb391c6dd516bc83fc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:09:34 -0600 Subject: [PATCH 1211/1891] chore: Release rtx-cli version 2023.12.15 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e0494eaa..bba290cab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.14" +version = "2023.12.15" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 0bd18bd9f..a302b4dc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.14" +version = "2023.12.15" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 359cb3660..a96b8a076 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.14 +rtx 2023.12.15 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.14/rtx-v2023.12.14-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.15/rtx-v2023.12.15-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index ea0d08936..6762f3087 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.14"; + version = "2023.12.15"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b98466321..dd1a886d1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.14 +Version: 2023.12.15 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From a7bfb04864b2e6d1e33d5961f977b938e7f0506d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:29:56 -0600 Subject: [PATCH 1212/1891] CI: do not publish npm packages during dry runs --- scripts/release-npm.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index 773a92d1d..44536c83b 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -70,7 +70,13 @@ for platform in "${platforms[@]}"; do EOF pushd "$RELEASE_DIR/npm" tree || true - npm publish --access public --tag "$dist_tag" + if [ "$DRY_RUN" != "0" ]; then + echo DRY_RUN + echo npm publish --access public --tag "$dist_tag" + echo DRY_RUN + else + npm publish --access public --tag "$dist_tag" + fi popd done @@ -161,5 +167,11 @@ cat <"$RELEASE_DIR/npm/package.json" } EOF pushd "$RELEASE_DIR/npm" -npm publish --access public --tag "$dist_tag" +if [ "$DRY_RUN" != "0" ]; then + echo DRY_RUN + echo npm publish --access public --tag "$dist_tag" + echo DRY_RUN +else + npm publish --access public --tag "$dist_tag" +fi popd From 1a0a612410dbd5e6c9ac3469da231e6772478f30 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:30:39 -0600 Subject: [PATCH 1213/1891] chore: Release rtx-cli version 2023.12.16 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bba290cab..1d41aa147 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.15" +version = "2023.12.16" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index a302b4dc0..fc0a6d450 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.15" +version = "2023.12.16" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index a96b8a076..8d317123c 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.15 +rtx 2023.12.16 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.15/rtx-v2023.12.15-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.16/rtx-v2023.12.16-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 6762f3087..06beb8bdc 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.15"; + version = "2023.12.16"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index dd1a886d1..f8fbf6793 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.15 +Version: 2023.12.16 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 1bed0fc40e5df0230278382c398ce4e55e4c88ec Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 23:19:06 -0600 Subject: [PATCH 1214/1891] CI: do not fail the build if npm publish fails --- scripts/release-npm.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release-npm.sh b/scripts/release-npm.sh index 44536c83b..a732192fd 100755 --- a/scripts/release-npm.sh +++ b/scripts/release-npm.sh @@ -75,7 +75,7 @@ EOF echo npm publish --access public --tag "$dist_tag" echo DRY_RUN else - npm publish --access public --tag "$dist_tag" + npm publish --access public --tag "$dist_tag" || true fi popd done @@ -172,6 +172,6 @@ if [ "$DRY_RUN" != "0" ]; then echo npm publish --access public --tag "$dist_tag" echo DRY_RUN else - npm publish --access public --tag "$dist_tag" + npm publish --access public --tag "$dist_tag" || true fi popd From f13c6bf682e410355fdf1bd065c0e849d0c435a6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 6 Dec 2023 23:19:37 -0600 Subject: [PATCH 1215/1891] chore: Release rtx-cli version 2023.12.17 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d41aa147..5dda66aa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.16" +version = "2023.12.17" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index fc0a6d450..0df5e5755 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.16" +version = "2023.12.17" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 8d317123c..642b591b5 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.16 +rtx 2023.12.17 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.16/rtx-v2023.12.16-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.17/rtx-v2023.12.17-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 06beb8bdc..c6d95d4a8 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.16"; + version = "2023.12.17"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f8fbf6793..e804c2010 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.16 +Version: 2023.12.17 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From a3676e4c61f9c5c6b86be2e901b8320c2adc2707 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 00:19:57 -0600 Subject: [PATCH 1216/1891] node: default PATH to current PATH when compiling (#1107) * node: default PATH to current PATH when compiling Fixes #1106 * Restyled by rustfmt (#1108) Co-authored-by: Restyled.io --------- Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com> Co-authored-by: Restyled.io --- src/cmd.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd.rs b/src/cmd.rs index dd8715d46..826897f54 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -140,7 +140,11 @@ impl<'a> CmdLineRunner<'a> { pub fn prepend_path_env(&mut self, path: PathBuf) -> &mut Self { let k: OsString = "PATH".into(); - let mut paths = env::split_paths(self.get_env(&k).unwrap()).collect::>(); + let existing = self + .get_env(&k) + .map(|c| c.to_owned()) + .unwrap_or_else(|| env::var_os("PATH").unwrap()); + let mut paths = env::split_paths(&existing).collect::>(); paths.insert(0, path); self.cmd.env("PATH", env::join_paths(paths).unwrap()); self From 3eebf1e0b79f6545ba685ec07927c4cc66ce65ae Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 00:21:19 -0600 Subject: [PATCH 1217/1891] chore: Release rtx-cli version 2023.12.18 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5dda66aa9..38f808e9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.17" +version = "2023.12.18" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 0df5e5755..d98fd187b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.17" +version = "2023.12.18" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 642b591b5..2d6c165c1 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.17 +rtx 2023.12.18 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.17/rtx-v2023.12.17-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.18/rtx-v2023.12.18-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index c6d95d4a8..109172837 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.17"; + version = "2023.12.18"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e804c2010..ac43082bf 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.17 +Version: 2023.12.18 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From eead151e4dfaa82d05a137392663edc67d9c2c6f Mon Sep 17 00:00:00 2001 From: Koosha Date: Thu, 7 Dec 2023 19:30:01 +0100 Subject: [PATCH 1218/1891] [ISSUE-1110] handle null in java plugin (#1111) --- src/plugins/core/java.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index a184e3277..c5cb8a2ba 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -83,7 +83,10 @@ impl JavaPlugin { .sorted_by_cached_key(|(v, m)| { let is_shorthand = regex!(r"^\d").is_match(v); let vendor = &m.vendor; - let is_jdk = m.image_type == "jdk"; + let is_jdk = m + .image_type + .as_ref() + .is_some_and(|image_type| image_type == "jdk"); let features = 10 - m.features.len(); let version = Versioning::new(v); (is_shorthand, vendor, is_jdk, features, version) @@ -128,7 +131,7 @@ impl JavaPlugin { m: &JavaMetadata, ) -> Result<()> { pr.set_message(format!("installing {}", tarball_path.display())); - if m.file_type == "zip" { + if m.file_type == Some("zip".to_string()) { file::unzip(tarball_path, &tv.download_path())?; } else { file::untar(tarball_path, &tv.download_path())?; @@ -239,7 +242,11 @@ impl JavaPlugin { .http .json::, _>(url)? .into_iter() - .filter(|m| JAVA_FILE_TYPES.contains(&m.file_type)) + .filter(|m| { + m.file_type + .as_ref() + .is_some_and(|file_type| JAVA_FILE_TYPES.contains(file_type)) + }) .collect(); Ok(metadata) } @@ -340,8 +347,8 @@ struct JavaMetadata { jvm_impl: String, os: String, architecture: String, - file_type: String, - image_type: String, + file_type: Option, + image_type: Option, features: Vec, url: String, sha256: String, @@ -358,8 +365,14 @@ struct JavaMetadata { impl Display for JavaMetadata { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut v = vec![self.vendor.clone()]; - if self.image_type == "jre" { - v.push(self.image_type.clone()); + if self + .image_type + .as_ref() + .is_some_and(|image_type| image_type == "jre") + { + v.push(self.image_type.clone().unwrap()); + } else if self.image_type.is_none() { + v.push("unknown".to_string()); } for f in self.features.iter() { if JAVA_FEATURES.contains(f) { From 4aa89aeaf4ebea4798911d53e71ea74fb67de000 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:30:15 -0600 Subject: [PATCH 1219/1891] deb: fix script issues introduced from linter (#1112) * deb: fix script issues introduced from linter * [MegaLinter] Apply linters fixes --------- Co-authored-by: jdx --- packaging/deb/generate-release.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packaging/deb/generate-release.sh b/packaging/deb/generate-release.sh index c9ba48e67..4978ed754 100755 --- a/packaging/deb/generate-release.sh +++ b/packaging/deb/generate-release.sh @@ -1,5 +1,5 @@ -#!/bin/sh -set -e +#!/bin/bash +set -euo pipefail # shellcheck disable=SC2044 # shellcheck disable=SC2066 # shellcheck disable=SC2086 @@ -8,13 +8,13 @@ set -e do_hash() { HASH_NAME=$1 HASH_CMD=$2 - echo "$HASH_NAME:" - for f in "$(find -type f)"; do - f=$(echo "$f" | cut -c3-) # remove ./ prefix + echo "${HASH_NAME}:" + for f in $(find -type f); do + f=$(echo $f | cut -c3-) # remove ./ prefix if [ "$f" = "Release" ]; then continue fi - echo " $("$HASH_CMD" "$f" | cut -d" " -f1) $(wc -c "$f")" + echo " $(${HASH_CMD} ${f} | cut -d" " -f1) $(wc -c $f)" done } From 85f6e9076382323359dc20cea4a26e67b9500345 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:31:32 -0600 Subject: [PATCH 1220/1891] chore: Release rtx-cli version 2023.12.19 --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38f808e9c..0b2ee00c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1384,9 +1384,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.18" +version = "2023.12.19" dependencies = [ "base64", "built", @@ -2536,9 +2536,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -3052,9 +3052,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.25" +version = "0.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94" +checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index d98fd187b..bd33cd2d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.18" +version = "2023.12.19" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 2d6c165c1..74abcc600 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.18 +rtx 2023.12.19 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.18/rtx-v2023.12.18-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.19/rtx-v2023.12.19-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 109172837..5f197a4e5 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.18"; + version = "2023.12.19"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ac43082bf..143161441 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.18 +Version: 2023.12.19 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 37f6dc257421dad0985a83429732cb5134030751 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 13:02:36 -0600 Subject: [PATCH 1221/1891] CI: skip autocreating alpine MRs I plan to enable this again if I can get it to reuse open draft MRs --- scripts/release-alpine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh index b33a1f09b..b814069bf 100755 --- a/scripts/release-alpine.sh +++ b/scripts/release-alpine.sh @@ -32,5 +32,5 @@ git commit -m "community/rtx: upgrade to ${RTX_VERSION#v}" git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git" git push -f jdxcode -glab mr create --draft --fill --yes -H jdxcode/aports -R alpine/aports +#glab mr create --draft --fill --yes -H jdxcode/aports -R alpine/aports #git show From c40029d1362364cee5afde5353b656a6e9b2ae1f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 13:36:57 -0600 Subject: [PATCH 1222/1891] CI: do not fail release if homebrew fails --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8ec585cbc..91d1a32c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -245,6 +245,7 @@ jobs: if: startsWith(github.event.ref, 'refs/tags/v') timeout-minutes: 10 needs: [release] + continue-on-error: true steps: - name: Checkout repository uses: actions/checkout@v4 From e54dbe6814543195241f80ad1b5afad91b73b6ac Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:45:30 -0600 Subject: [PATCH 1223/1891] Update README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 74abcc600..535da22db 100644 --- a/README.md +++ b/README.md @@ -1485,7 +1485,16 @@ Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. ### GitHub Actions -Use [`jdx/rtx-action`](https://github.com/jdx/rtx-action): +rtx is pretty easy to use without an action: + +```yaml +jobs: + build: + steps: + - run: curl https://rtx.pub/install.sh | sh && echo "$HOME/.local/share/rtx/bin/rtx" >> $GITHUB_PATH +``` + +Or you can use the custom action [`jdx/rtx-action`](https://github.com/jdx/rtx-action): ```yaml jobs: From 90600f7f54cd25e6083bc33d46f15fb59a7628ee Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:49:09 -0600 Subject: [PATCH 1224/1891] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 535da22db..7329d2c1f 100644 --- a/README.md +++ b/README.md @@ -1491,7 +1491,10 @@ rtx is pretty easy to use without an action: jobs: build: steps: - - run: curl https://rtx.pub/install.sh | sh && echo "$HOME/.local/share/rtx/bin/rtx" >> $GITHUB_PATH + - run: | + curl https://rtx.pub/install.sh | sh + echo "$HOME/.local/share/rtx/bin" >> $GITHUB_PATH + echo "$HOME/.local/share/rtx/shims" >> $GITHUB_PATH ``` Or you can use the custom action [`jdx/rtx-action`](https://github.com/jdx/rtx-action): From 712d317f256e0cd6a2fa8249c12b75a87e8724a7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 18:18:06 -0600 Subject: [PATCH 1225/1891] CI: make alpine releases reuse open draft MRs (#1113) * CI: make alpine releases reuse open draft MRs * reuse open branch * CI: separate aur scripts * reuse existing alpine aports branch * reuse existing alpine aports branch * automerge * fix * fix --- .github/workflows/release.yml | 41 +++++++++++++++++++++++++---------- scripts/release-alpine.sh | 16 ++++++++++---- scripts/release-aur-bin.sh | 6 ++++- scripts/release-aur.sh | 6 ++++- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 91d1a32c5..f79ff7e6d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,7 @@ concurrency: env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 + DRY_RUN: ${{ startsWith(github.event.ref, 'refs/tags/v') && '0' || '1' }} jobs: build-tarball: @@ -181,8 +182,6 @@ jobs: - build-tarball - rpm - deb - env: - DRY_RUN: ${{ startsWith(github.event.ref, 'refs/tags/v') && '0' || '1' }} steps: - uses: actions/checkout@v4 with: @@ -234,17 +233,10 @@ jobs: files: releases/${{github.ref_name}}/* generate_release_notes: true token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - - name: Release to aur - run: scripts/release-aur.sh - working-directory: rtx - - name: Release aur-bin - run: scripts/release-aur-bin.sh - working-directory: rtx bump-homebrew-formula: runs-on: macos-latest - if: startsWith(github.event.ref, 'refs/tags/v') timeout-minutes: 10 - needs: [release] + needs: [e2e-linux] continue-on-error: true steps: - name: Checkout repository @@ -254,12 +246,37 @@ jobs: with: token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} formula: rtx + bump-aur: + runs-on: ubuntu-22.04 + timeout-minutes: 30 + needs: [e2e-linux] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.RTX_SSH_KEY }} + known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} + - name: Bump aur + run: ./scripts/release-aur.sh + bump-aur-bin: + runs-on: ubuntu-22.04 + timeout-minutes: 30 + needs: [e2e-linux] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.RTX_SSH_KEY }} + known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} + - name: Bump aur-bin + run: ./scripts/release-aur-bin.sh bump-alpine: runs-on: ubuntu-22.04 - if: startsWith(github.event.ref, 'refs/tags/v') container: ghcr.io/jdx/rtx:alpine timeout-minutes: 30 - needs: [release] + needs: [e2e-linux] steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh index b814069bf..9c9be69a4 100755 --- a/scripts/release-alpine.sh +++ b/scripts/release-alpine.sh @@ -17,6 +17,8 @@ git config --global user.email 6271-jdxcode@users.gitlab.alpinelinux.org git clone https://gitlab.alpinelinux.org/alpine/aports /home/packager/aports cd /home/packager/aports git config --local core.hooksPath .githooks +git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git" +git checkout -mb rtx cd community/rtx sed -i "s/pkgver=.*/pkgver=${RTX_VERSION#v}/" APKBUILD @@ -27,10 +29,16 @@ abuild -r apkbuild-lint APKBUILD git add APKBUILD -git checkout -B "rtx/${RTX_VERSION#v}" git commit -m "community/rtx: upgrade to ${RTX_VERSION#v}" -git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git" -git push -f jdxcode -#glab mr create --draft --fill --yes -H jdxcode/aports -R alpine/aports +if [ "$DRY_RUN" == 0 ]; then + git push jdxcode +fi + +open_mr="$(glab mr list -R alpine/aports --author=@me)" +if [[ "$open_mr" != "Showing"* ]]; then + if [ "$DRY_RUN" == 0 ]; then + glab mr create --draft --fill --yes -H jdxcode/aports -R alpine/aports + fi +fi #git show diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 74eba3c4f..421f01274 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -67,7 +67,11 @@ EOF cd aur-bin git add .SRCINFO PKGBUILD +if git diff-index --quiet HEAD --; then + echo "No changes to PKGBUILD or .SRCINFO" + exit 0 +fi git commit -m "rtx ${RTX_VERSION#v}" -if [[ "$DRY_RUN" != 1 ]]; then +if [[ "$DRY_RUN" == 0 ]]; then git push fi diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 39f52e653..49c02cd76 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -73,7 +73,11 @@ EOF cd aur git add .SRCINFO PKGBUILD +if git diff-index --quiet HEAD --; then + echo "No changes to PKGBUILD or .SRCINFO" + exit 0 +fi git commit -m "rtx ${RTX_VERSION#v}" -if [ "$DRY_RUN" != 1 ]; then +if [ "$DRY_RUN" == 0 ]; then git push fi From b9a189478f467db4fd7e52354e7e1d320016f5f2 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 19:23:48 -0600 Subject: [PATCH 1226/1891] docker: added jdxcode/rtx image (#1117) * docker: added jdxcode/rtx image * fix * fix * fix --- .github/workflows/docker.yml | 25 +++++++++++++++++++++++++ .github/workflows/release.yml | 4 ++-- Dockerfile | 1 + README.md | 8 ++++++++ packaging/rtx/Dockerfile | 24 ++++++++++++++++++++++++ packaging/standalone/install.envsubst | 3 ++- 6 files changed, 62 insertions(+), 3 deletions(-) create mode 120000 Dockerfile create mode 100644 packaging/rtx/Dockerfile diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a205f4dab..86333a70d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -21,6 +21,7 @@ jobs: - deb - github-actions - rpm + - rtx runs-on: ubuntu-latest permissions: contents: read @@ -61,3 +62,27 @@ jobs: run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" + dockerhub: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: jdxcode/rtx + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: jdxcode/rtx:latest + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f79ff7e6d..5ea20c80a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -127,7 +127,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-tarball] timeout-minutes: 10 - container: jdxcode/rtx:rpm + container: ghcr.io/jdxcode/rtx:rpm steps: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 @@ -149,7 +149,7 @@ jobs: if-no-files-found: error deb: runs-on: ubuntu-22.04 - container: jdxcode/rtx:deb + container: ghcr.io/jdxcode/rtx:deb timeout-minutes: 10 needs: [build-tarball] steps: diff --git a/Dockerfile b/Dockerfile new file mode 120000 index 000000000..6451905bb --- /dev/null +++ b/Dockerfile @@ -0,0 +1 @@ +packaging/rtx/Dockerfile \ No newline at end of file diff --git a/README.md b/README.md index 7329d2c1f..248b7329c 100644 --- a/README.md +++ b/README.md @@ -441,6 +441,14 @@ You can also import the package directly using `rtx-flake.packages.${system}.rtx`. It supports all default Nix systems. +
+
+ Docker + +``` +docker run jdxcode/rtx x node@20 -- node -v +``` +
### Register shell hook diff --git a/packaging/rtx/Dockerfile b/packaging/rtx/Dockerfile new file mode 100644 index 000000000..c433c027b --- /dev/null +++ b/packaging/rtx/Dockerfile @@ -0,0 +1,24 @@ +FROM ubuntu:22.04 +LABEL maintainer="jdx" + +ENV RTX_DATA_DIR="/rtx" +ENV RTX_CONFIG_DIR="/rtx" +ENV RTX_CACHE_DIR="/rtx/cache" +ENV PATH="/rtx/shims:/rtx/bin:$PATH" + +ENV RTX_INSTALL_PATH="/rtx/bin/rtx" + +RUN apt-get update && apt-get install -y \ + build-essential \ + curl \ + bash \ + git \ + wget \ + && apt-get clean && rm -rf /var/lib/apt/lists/* \ + # TODO: build from this source + && curl -fsSL https://rtx.pub/install.sh | sh \ + && rtx --version + +WORKDIR /rtx +ENTRYPOINT ["rtx"] +CMD ["--help"] diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index 971fb8a19..d668e617a 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -115,7 +115,8 @@ install_rtx() { os="$(get_os)" arch="$(get_arch)" xdg_data_home="${XDG_DATA_HOME:-$HOME/.local/share}" - install_path="${RTX_INSTALL_PATH:-$xdg_data_home/rtx/bin/rtx}" + rtx_data_dir="${RTX_DATA_DIR:-$xdg_data_home/rtx}" + install_path="${RTX_INSTALL_PATH:-${rtx_data_dir:}/bin/rtx}" install_dir="$(dirname "$install_path")" tarball_url="https://github.com/jdx/rtx/releases/download/${version}/rtx-${version}-${os}-${arch}.tar.gz" From 1ee26cf70eef60f1ba1336c75e3b58d1669f21d1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 19:50:31 -0600 Subject: [PATCH 1227/1891] CI: tweak concurrency --- .github/workflows/docker.yml | 4 ++++ .github/workflows/release.yml | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 86333a70d..6d1b9a8c4 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -6,6 +6,10 @@ on: branches: ["docker-release"] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ea20c80a..3aac754c6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,6 @@ on: concurrency: group: release-${{ github.ref_name }} - cancel-in-progress: true env: CARGO_TERM_COLOR: always From e1d2ff9643e67d80e56b587daf4f5b4d2cd54ab9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 19:51:48 -0600 Subject: [PATCH 1228/1891] CI: fix ghcr urls --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3aac754c6..88e0f5539 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,7 +126,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-tarball] timeout-minutes: 10 - container: ghcr.io/jdxcode/rtx:rpm + container: ghcr.io/jdx/rtx:rpm steps: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 @@ -148,7 +148,7 @@ jobs: if-no-files-found: error deb: runs-on: ubuntu-22.04 - container: ghcr.io/jdxcode/rtx:deb + container: ghcr.io/jdx/rtx:deb timeout-minutes: 10 needs: [build-tarball] steps: From ac8b4906b01996d385e5ab9db51eddb8d824d68c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:50:46 -0600 Subject: [PATCH 1229/1891] ls-remote: fetch versions in parallel (#1119) * ls-remote: fetch versions in parallel * lint dockerfile --- packaging/rtx/Dockerfile | 1 + src/cli/ls_remote.rs | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packaging/rtx/Dockerfile b/packaging/rtx/Dockerfile index c433c027b..2c77adc00 100644 --- a/packaging/rtx/Dockerfile +++ b/packaging/rtx/Dockerfile @@ -1,5 +1,6 @@ FROM ubuntu:22.04 LABEL maintainer="jdx" +SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV RTX_DATA_DIR="/rtx" ENV RTX_CONFIG_DIR="/rtx" diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index aac7fe306..20e98bb5a 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; +use rayon::prelude::*; use crate::cli::args::tool::ToolArg; use crate::cli::args::tool::ToolArgParser; @@ -65,10 +66,18 @@ impl LsRemote { } fn run_all(self, config: Config, out: &mut Output) -> Result<()> { - for plugin in config.plugins.values() { - let versions = plugin.list_remote_versions(&config.settings)?; - for version in versions { - rtxprintln!(out, "{}@{}", plugin.name(), version); + let versions = config + .plugins + .values() + .par_bridge() + .map(|p| { + let versions = p.list_remote_versions(&config.settings)?; + Ok((p, versions)) + }) + .collect::>>()?; + for (plugin, versions) in versions { + for v in versions { + rtxprintln!(out, "{}@{v}", plugin); } } Ok(()) From d3732e6d5026a74da54317a693730ebf1b97931c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:54:14 -0600 Subject: [PATCH 1230/1891] lint: hadolint --- .hadolint.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.hadolint.yaml b/.hadolint.yaml index 0303e48ae..82b1d6c0d 100644 --- a/.hadolint.yaml +++ b/.hadolint.yaml @@ -1,5 +1,6 @@ ignored: - DL3008 + - DL3015 - DL3018 - DL3028 - DL3041 From 8c53b6d85ab510637c0d96e492795963b691a647 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 21:27:05 -0600 Subject: [PATCH 1231/1891] node: use metadata.rtx.pub for version fetching (#1120) --- src/plugins/core/node.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index ce7e0390d..c2b85ab1a 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -32,9 +32,22 @@ impl NodePlugin { } fn fetch_remote_versions(&self) -> Result> { + let node_url_overridden = env::var("RTX_NODE_MIRROR_URL") + .or(env::var("NODE_BUILD_MIRROR_URL")) + .is_ok(); + if node_url_overridden { + self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) + } else { + self.fetch_remote_versions_from_rtx().or_else(|e| { + warn!("failed to fetch remote versions from rtx: {}", e); + self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) + }) + } + } + fn fetch_remote_versions_from_node(&self, base: &Url) -> Result> { let versions = self .http - .json::, _>(RTX_NODE_MIRROR_URL.join("index.json")?)? + .json::, _>(base.join("index.json")?)? .into_iter() .map(|v| { if regex!(r"^v\d+\.").is_match(&v.version) { @@ -47,6 +60,16 @@ impl NodePlugin { .collect(); Ok(versions) } + fn fetch_remote_versions_from_rtx(&self) -> Result> { + let versions = self + .http + .get_text("http://metadata.rtx.pub/versions/node")? + .lines() + .map(|v| v.trim().to_string()) + .filter(|v| !v.is_empty()) + .collect(); + Ok(versions) + } fn install_precompiled(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { match self.fetch_tarball( From 7ba301d11856fce5c6e6bf53038b169074040577 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 21:27:45 -0600 Subject: [PATCH 1232/1891] chore: Release rtx-cli version 2023.12.20 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b2ee00c7..cbe86f907 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.19" +version = "2023.12.20" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index bd33cd2d2..c168d5d05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.19" +version = "2023.12.20" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 248b7329c..cc495a53f 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.19 +rtx 2023.12.20 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.19/rtx-v2023.12.19-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.20/rtx-v2023.12.20-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 5f197a4e5..101f82d58 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.19"; + version = "2023.12.20"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 143161441..94164b6f8 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.19 +Version: 2023.12.20 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 1c9c01a57d87d28b89a61a15ecbc333dca4c0a64 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 21:30:52 -0600 Subject: [PATCH 1233/1891] CI: fix deb build docker --- packaging/deb/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/deb/Dockerfile b/packaging/deb/Dockerfile index 81a6ce715..b10492e93 100644 --- a/packaging/deb/Dockerfile +++ b/packaging/deb/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:22.04 LABEL maintainer="jdx" RUN apt-get update \ - && apt-get install --no-install-recommends -y \ + && apt-get install -y \ build-essential \ ruby \ && apt-get clean \ From 66b4799040b8aa838d1296de0f6ec5d0b2690694 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 22:10:44 -0600 Subject: [PATCH 1234/1891] CI: set git user/email for aur release (#1121) --- scripts/release-aur-bin.sh | 3 +++ scripts/release-aur.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 421f01274..b470c8e6a 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash set -euxo pipefail +git config --global user.name rtx-vm +git config --global user.email 123107610+rtx-vm@users.noreply.github.com + RTX_VERSION=$(./scripts/get-version.sh) TAR_GZ_URI="https://github.com/jdx/rtx/releases/download/$RTX_VERSION/rtx-$RTX_VERSION-linux-x64.tar.gz" diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 49c02cd76..7917de26a 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash set -euxo pipefail +git config --global user.name rtx-vm +git config --global user.email 123107610+rtx-vm@users.noreply.github.com + RTX_VERSION=$(./scripts/get-version.sh) SHA512=$(curl -L "https://github.com/jdx/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') From 88ee4057a1b40964e29524c73494691ee170989d Mon Sep 17 00:00:00 2001 From: Jean-Charles Sisk Date: Thu, 7 Dec 2023 23:39:28 -0500 Subject: [PATCH 1235/1891] devcontainer: minor fixes for nodesource and npm packages (#1124) * chore(devcontainer): replace deprecated nodesource script * chore(devcontainer): add npm packages required by `just` commands --- .devcontainer/Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a441e57b0..9218d4a55 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -11,7 +11,7 @@ RUN mkdir /workspaces/target \ && cargo install cargo-insta cargo-llvm-cov \ # Install dependencies && export DEBIAN_FRONTEND=noninteractive \ - && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ + && curl -fsSL https://deb.nodesource.com/nsolid_setup_deb.sh | bash -s -- 20 \ && apt-get update \ && apt-get -y install --no-install-recommends \ # shells, direnv, shellcheck @@ -21,6 +21,8 @@ RUN mkdir /workspaces/target \ # shfmt && curl -sS https://webi.sh/shfmt | sh \ # just - && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/bin + && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/bin \ + # npm packages + && npm install -g prettier@3.1.0 markdownlint-cli@0.37.0 markdown-magic@2.6.1 ENTRYPOINT [ "/bin/bash" ] From 40c7e82fd3babd2a732f127722cb70f942d949bb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 22:42:56 -0600 Subject: [PATCH 1236/1891] alpine: do not create as draft --- scripts/release-alpine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh index 9c9be69a4..92bb382b8 100755 --- a/scripts/release-alpine.sh +++ b/scripts/release-alpine.sh @@ -38,7 +38,7 @@ fi open_mr="$(glab mr list -R alpine/aports --author=@me)" if [[ "$open_mr" != "Showing"* ]]; then if [ "$DRY_RUN" == 0 ]; then - glab mr create --draft --fill --yes -H jdxcode/aports -R alpine/aports + glab mr create --fill --yes -H jdxcode/aports -R alpine/aports fi fi #git show From 203b650eb645c22b13b9838473f4f41f06797dda Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 7 Dec 2023 23:08:22 -0600 Subject: [PATCH 1237/1891] versions: make stable by sorting alphanumerically after sorting with semver (#1123) * versions: make stable by sorting alphanumerically after sorting with semver * Commit from GitHub Actions (rtx) --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- src/cli/ls.rs | 6 +++++- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/go.rs | 2 +- src/plugins/core/java.rs | 9 ++++++++- src/plugins/mod.rs | 2 +- src/runtime_symlinks.rs | 2 +- 7 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index cc2c4b7a8..035691e46 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -234,7 +234,11 @@ impl Ls { let rvs: Vec = versions .into_iter() .sorted_by_cached_key(|((plugin_name, version), _)| { - (plugin_name.clone(), Versioning::new(version)) + ( + plugin_name.clone(), + Versioning::new(version), + version.clone(), + ) }) .map(|(k, (p, tv))| { let source = match &active.get(&k) { diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 0d42f5e24..f544be47f 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -35,7 +35,7 @@ impl BunPlugin { .map(|r| r.tag_name) .filter_map(|v| v.strip_prefix("bun-v").map(|v| v.to_string())) .unique() - .sorted_by_cached_key(|s| Versioning::new(s)) + .sorted_by_cached_key(|s| (Versioning::new(s), s.to_string())) .collect(); Ok(versions) } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index c5dec07d8..c4129a92b 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -38,7 +38,7 @@ impl DenoPlugin { .filter(|v| v.starts_with('v')) .map(|v| v.trim_start_matches('v').to_string()) .unique() - .sorted_by_cached_key(|s| Versioning::new(s)) + .sorted_by_cached_key(|s| (Versioning::new(s), s.to_string())) .collect(); Ok(versions) } diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 60d34f270..c81dad64e 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -36,7 +36,7 @@ impl GoPlugin { .filter(|s| !s.is_empty()) .filter(|s| !regex!(r"^1($|\.0|\.0\.[0-9]|\.1|\.1rc[0-9]|\.1\.[0-9]|.2|\.2rc[0-9]|\.2\.1|.8.5rc5)$").is_match(s)) .unique() - .sorted_by_cached_key(|s| Versioning::new(s)) + .sorted_by_cached_key(|s| (Versioning::new(s), s.to_string())) .collect(); Ok(versions) }) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index c5cb8a2ba..c9f46b390 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -89,7 +89,14 @@ impl JavaPlugin { .is_some_and(|image_type| image_type == "jdk"); let features = 10 - m.features.len(); let version = Versioning::new(v); - (is_shorthand, vendor, is_jdk, features, version) + ( + is_shorthand, + vendor, + is_jdk, + features, + version, + v.to_string(), + ) }) .map(|(v, _)| v.clone()) .unique() diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 1f3352d60..29b8c0177 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -58,7 +58,7 @@ pub trait Plugin: Debug + Send + Sync { .filter(|v| !is_runtime_symlink(&self.installs_path().join(v))) .filter(|v| !self.installs_path().join(v).join("incomplete").exists()) .cloned() - .sorted_by_cached_key(|v| Versioning::new(v).unwrap_or_default()) + .sorted_by_cached_key(|v| (Versioning::new(v), v.to_string())) .collect(), false => vec![], }) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 659ec4e32..af4957dd1 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -64,7 +64,7 @@ fn list_symlinks(config: &Config, plugin: Arc) -> Result Date: Thu, 7 Dec 2023 23:28:46 -0600 Subject: [PATCH 1238/1891] docker: build source from repo (#1122) * docker: build source from repo * docker lint --- .dockerignore | 1 + .hadolint.yaml | 1 + packaging/rtx/Dockerfile | 22 +++++++++------------- 3 files changed, 11 insertions(+), 13 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +target/ diff --git a/.hadolint.yaml b/.hadolint.yaml index 82b1d6c0d..246210584 100644 --- a/.hadolint.yaml +++ b/.hadolint.yaml @@ -1,4 +1,5 @@ ignored: + - DL3006 - DL3008 - DL3015 - DL3018 diff --git a/packaging/rtx/Dockerfile b/packaging/rtx/Dockerfile index 2c77adc00..a38db51d7 100644 --- a/packaging/rtx/Dockerfile +++ b/packaging/rtx/Dockerfile @@ -1,24 +1,20 @@ -FROM ubuntu:22.04 +FROM rust as builder LABEL maintainer="jdx" SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV RTX_DATA_DIR="/rtx" ENV RTX_CONFIG_DIR="/rtx" ENV RTX_CACHE_DIR="/rtx/cache" -ENV PATH="/rtx/shims:/rtx/bin:$PATH" +ENV PATH="/rtx/shims:$PATH" +WORKDIR /usr/src/rtx -ENV RTX_INSTALL_PATH="/rtx/bin/rtx" +COPY . /usr/src/rtx/ -RUN apt-get update && apt-get install -y \ - build-essential \ - curl \ - bash \ - git \ - wget \ - && apt-get clean && rm -rf /var/lib/apt/lists/* \ - # TODO: build from this source - && curl -fsSL https://rtx.pub/install.sh | sh \ - && rtx --version +RUN cargo build --release + +FROM rust as runtime + +COPY --from=builder /usr/src/rtx/target/release/rtx /usr/local/bin/rtx WORKDIR /rtx ENTRYPOINT ["rtx"] From 74d12b3ae098e427f42c565644d41ecc2fc90810 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 8 Dec 2023 00:17:42 -0600 Subject: [PATCH 1239/1891] test: fix tiny versions --- e2e/test_uninstall | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/test_uninstall b/e2e/test_uninstall index ae42f86d2..c2b144b57 100755 --- a/e2e/test_uninstall +++ b/e2e/test_uninstall @@ -9,16 +9,16 @@ export CLICOLOR=0 assert_contains "rtx ls tiny" "3.1.0 (missing)" rtx i tiny@1 tiny@2.0 tiny@2.1 -assert_contains "rtx ls tiny" "1.0.1" +assert_contains "rtx ls tiny" "1.1.0" assert_contains "rtx ls tiny" "2.0.1" assert_contains "rtx ls tiny" "2.1.0" rtx rm -a tiny@2 -assert_contains "rtx ls tiny" "1.0.1" +assert_contains "rtx ls tiny" "1.1.0" assert_not_contains "rtx ls tiny" "2.0.1" assert_not_contains "rtx ls tiny" "2.1.0" rtx rm -a tiny -assert_not_contains "rtx ls tiny" "1.0.1" +assert_not_contains "rtx ls tiny" "1.1.0" assert_not_contains "rtx ls tiny" "2.0.1" assert_not_contains "rtx ls tiny" "2.1.0" From 31531badf741618a7157eac2b7578289d6bc12f0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:16:38 -0600 Subject: [PATCH 1240/1891] CI: only bump homebrew on git tag --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88e0f5539..37958ebf8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -235,8 +235,8 @@ jobs: bump-homebrew-formula: runs-on: macos-latest timeout-minutes: 10 - needs: [e2e-linux] continue-on-error: true + if: startsWith(github.event.ref, 'refs/tags/v') steps: - name: Checkout repository uses: actions/checkout@v4 From 0479e6ee151af27e26b25277a1b44ce9a2593449 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 8 Dec 2023 11:17:27 -0600 Subject: [PATCH 1241/1891] show better error if terminated by signal (#1126) --- src/cli/exec.rs | 7 ++++--- src/plugins/external_plugin.rs | 13 ++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 49c8c2599..74b52c794 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -93,9 +93,10 @@ impl Exec { cmd = cmd.env(k, v); } let res = cmd.unchecked().run()?; - match res.status.code().unwrap_or(1) { - 0 => Ok(()), - code => Err(eyre!("command failed with exit code {}", code)), + match res.status.code() { + Some(0) => Ok(()), + Some(code) => Err(eyre!("command failed: exit code {}", code)), + None => Err(eyre!("command failed: terminated by signal")), } } } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 48f133354..001c35c7d 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -159,12 +159,11 @@ impl ExternalPlugin { } }; if !result.status.success() { - return Err(eyre!( - "error running {}: exited with code {}\n{}", - Script::ListAll, - result.status.code().unwrap_or_default(), - stderr - ))?; + let s = Script::ListAll; + match result.status.code() { + Some(code) => bail!("error running {}: exited with code {}\n{}", s, code, stderr), + None => bail!("error running {}: terminated by signal\n{}", s, stderr), + }; } else if settings.verbose { display_stderr(); } @@ -625,7 +624,7 @@ impl Plugin for ExternalPlugin { .cmd(&config.settings, &script) .unchecked() .run()?; - exit(result.status.code().unwrap_or(1)); + exit(result.status.code().unwrap_or(-1)); } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { From 1c6adf845525ae2f4615e6680dddbe4eb77d6624 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 8 Dec 2023 11:17:38 -0600 Subject: [PATCH 1242/1891] standalone: bug fix (#1130) * standalone: bug fix * release fixes * release fixes * release fixes --- .github/workflows/release.yml | 8 ++++++++ packaging/standalone/install.envsubst | 2 +- scripts/release.sh | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37958ebf8..ea1b94709 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -99,10 +99,15 @@ jobs: dist/rtx-*.tar.gz if-no-files-found: error e2e-linux: + name: e2e-linux-${{matrix.tranche}} runs-on: buildjet-16vcpu-ubuntu-2204 #container: ghcr.io/jdx/rtx:github-actions needs: [build-tarball] timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + tranche: [0, 1, 2, 3] steps: - uses: actions/checkout@v4 - name: Install zsh/fish/direnv @@ -117,7 +122,10 @@ jobs: - name: Run e2e tests uses: nick-fields/retry@v2 env: + GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" + TEST_TRANCHE: ${{matrix.tranche}} + TEST_TRANCHE_COUNT: 4 with: timeout_minutes: 20 max_attempts: 3 diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index d668e617a..637319ec8 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -116,7 +116,7 @@ install_rtx() { arch="$(get_arch)" xdg_data_home="${XDG_DATA_HOME:-$HOME/.local/share}" rtx_data_dir="${RTX_DATA_DIR:-$xdg_data_home/rtx}" - install_path="${RTX_INSTALL_PATH:-${rtx_data_dir:}/bin/rtx}" + install_path="${RTX_INSTALL_PATH:-${rtx_data_dir}/bin/rtx}" install_dir="$(dirname "$install_path")" tarball_url="https://github.com/jdx/rtx/releases/download/${version}/rtx-${version}-${os}-${arch}.tar.gz" diff --git a/scripts/release.sh b/scripts/release.sh index 577c770d8..b685bb6da 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -54,6 +54,11 @@ gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh +chmod +x "$RELEASE_DIR"/install.sh +shellcheck "$RELEASE_DIR"/install.sh +# TODO: figure out how to test this +# "$RELEASE_DIR"/install.sh +#~/.local/share/rtx/bin/rtx -v gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh if [[ "$DRY_RUN" != 1 ]]; then From f0c1b8f932352c7b60278fdfb5cbc5b4d9ee8664 Mon Sep 17 00:00:00 2001 From: Jean-Charles Sisk Date: Fri, 8 Dec 2023 12:18:19 -0500 Subject: [PATCH 1243/1891] (nodejs plugin) add support for automatically shimming package managers with `corepack enable` (#1118) * feat: support RTX_NODE_COREPACK_ENABLE * chore: lint e2e/test_nodejs * refactor(node): RTX_NODE_COREPACK_ENABLE -> RTX_NODE_COREPACK * refactor(node): remove unnecessary `test_corepack` --------- Co-authored-by: jdx <216188+jdx@users.noreply.github.com> --- docs/node.md | 1 + e2e/test_nodejs | 5 +++++ src/env.rs | 1 + src/plugins/core/node.rs | 24 ++++++++++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/docs/node.md b/docs/node.md index 56658f9db..3101f5861 100644 --- a/docs/node.md +++ b/docs/node.md @@ -36,6 +36,7 @@ required system dependencies. - `RTX_NODE_CONFIGURE_OPTS` [string]: Additional `./configure` options. - `RTX_NODE_MAKE_OPTS` [string]: Additional `make` options. - `RTX_NODE_MAKE_INSTALL_OPTS` [string]: Additional `make install` options. +- `RTX_NODE_COREPACK` [bool]: Installs the default corepack shims after installing any node version that ships with [corepack](https://github.com/nodejs/corepack). ## Default node packages diff --git a/e2e/test_nodejs b/e2e/test_nodejs index cf24e7768..bca296c08 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -36,3 +36,8 @@ assert "rtx x -- node --version" "v20.0.0" # rtx uninstall node # RTX_NODE_COMPILE=1 rtx i node # assert "rtx x -- node --version" "v20.0.0" + +export RTX_NODE_COREPACK=1 +rtx uninstall node +rtx i node +assert_contains "rtx x node -- which yarn" "yarn" diff --git a/src/env.rs b/src/env.rs index 95880ac2f..4632e3f86 100644 --- a/src/env.rs +++ b/src/env.rs @@ -167,6 +167,7 @@ pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { HOME.join(".default-npm-packages") }) }); +pub static RTX_NODE_COREPACK: Lazy = Lazy::new(|| var_is_true("RTX_NODE_COREPACK")); pub static NVM_DIR: Lazy = Lazy::new(|| var_path("NVM_DIR").unwrap_or_else(|| HOME.join(".nvm"))); pub static NODENV_ROOT: Lazy = diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index c2b85ab1a..15d75ea7b 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -171,6 +171,10 @@ impl NodePlugin { tv.install_path().join("bin/npm") } + fn corepack_path(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin/corepack") + } + fn install_default_packages( &self, config: &Config, @@ -204,6 +208,22 @@ impl NodePlugin { Ok(()) } + fn enable_default_corepack_shims( + &self, + config: &Config, + tv: &ToolVersion, + pr: &ProgressReport, + ) -> Result<()> { + pr.set_message("enabling corepack shims"); + let corepack = self.corepack_path(tv); + CmdLineRunner::new(&config.settings, corepack) + .with_pr(pr) + .arg("enable") + .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) + .execute()?; + Ok(()) + } + fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("node -v"); CmdLineRunner::new(&config.settings, self.node_path(tv)) @@ -295,6 +315,10 @@ impl Plugin for NodePlugin { self.install_npm_shim(&ctx.tv)?; self.test_npm(ctx.config, &ctx.tv, &ctx.pr)?; self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; + if *env::RTX_NODE_COREPACK && self.corepack_path(&ctx.tv).exists() { + self.enable_default_corepack_shims(ctx.config, &ctx.tv, &ctx.pr)?; + } + Ok(()) } } From d574ac78d46a0eaed94d5f1232010f88ec89dcd6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 8 Dec 2023 11:19:15 -0600 Subject: [PATCH 1244/1891] chore: Release rtx-cli version 2023.12.21 --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbe86f907..0c83dc0dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,9 +72,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ "windows-sys 0.52.0", ] @@ -683,9 +683,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.9" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +checksum = "8bbb8258be8305fb0237d7b295f47bb24ff1b136a535f473baf40e70468515aa" dependencies = [ "indenter", "once_cell", @@ -1801,7 +1801,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.20" +version = "2023.12.21" dependencies = [ "base64", "built", @@ -1880,9 +1880,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.26" +version = "0.38.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +checksum = "bfeae074e687625746172d639330f1de242a178bf3189b51e35a7a21573513ac" dependencies = [ "bitflags 2.4.1", "errno 0.3.8", @@ -1893,9 +1893,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring", diff --git a/Cargo.toml b/Cargo.toml index c168d5d05..063647144 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.20" +version = "2023.12.21" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index cc495a53f..2bfb15461 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.20 +rtx 2023.12.21 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.20/rtx-v2023.12.20-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.21/rtx-v2023.12.21-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 101f82d58..8cc914d41 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.20"; + version = "2023.12.21"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 94164b6f8..a27ae7e21 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.20 +Version: 2023.12.21 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 7cbd37ec94fcd39fceadbccc383301036d2b4630 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 8 Dec 2023 11:40:16 -0600 Subject: [PATCH 1245/1891] CI: switch back to non-buildjet runners --- .github/workflows/release.yml | 29 +++++++++++------------------ .github/workflows/rtx.yml | 6 ++---- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ea1b94709..654493000 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,35 +26,35 @@ jobs: - os: ubuntu name: linux-x64 target: x86_64-unknown-linux-gnu - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: ubuntu name: linux-x64-musl target: x86_64-unknown-linux-musl - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: ubuntu name: linux-arm64 target: aarch64-unknown-linux-gnu - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: ubuntu name: linux-arm64-musl target: aarch64-unknown-linux-musl - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: ubuntu name: linux-armv7 target: armv7-unknown-linux-gnueabi - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: ubuntu name: linux-armv7-musl target: armv7-unknown-linux-musleabi - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: ubuntu name: linux-armv6 target: arm-unknown-linux-gnueabi - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: ubuntu name: linux-armv6-musl target: arm-unknown-linux-musleabi - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest - os: macos name: macos-x64 target: x86_64-apple-darwin @@ -69,13 +69,7 @@ jobs: # runs-on: macos-12 steps: - uses: actions/checkout@v4 - - if: matrix.os == 'macos' - uses: actions/cache@v3 - with: - path: ~/.cargo/bin/zipsign - key: ${{ runner.os }}-cargo-zipsign - - if: matrix.os == 'ubuntu' - uses: buildjet/cache@v3 + - uses: actions/cache@v3 with: path: ~/.cargo/bin/zipsign key: ${{ runner.os }}-cargo-zipsign @@ -84,7 +78,6 @@ jobs: - uses: Swatinem/rust-cache@v2 with: shared-key: build-tarball-${{matrix.name}} - cache-provider: ${{ matrix.os == 'macos' && 'github' || 'buildjet' }} - if: matrix.os == 'ubuntu' uses: taiki-e/install-action@cross - run: scripts/setup-zipsign.sh @@ -100,7 +93,7 @@ jobs: if-no-files-found: error e2e-linux: name: e2e-linux-${{matrix.tranche}} - runs-on: buildjet-16vcpu-ubuntu-2204 + runs-on: ubuntu-latest #container: ghcr.io/jdx/rtx:github-actions needs: [build-tarball] timeout-minutes: 30 @@ -179,7 +172,7 @@ jobs: path: dist/deb if-no-files-found: error release: - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest #container: ghcr.io/jdx/rtx:github-actions timeout-minutes: 10 permissions: diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 611f9aa56..9f618ea29 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -19,7 +19,7 @@ env: jobs: unit: - runs-on: buildjet-8vcpu-ubuntu-2204 + runs-on: ubuntu-latest #container: ghcr.io/jdx/rtx:github-actions timeout-minutes: 10 steps: @@ -31,7 +31,6 @@ jobs: with: shared-key: unit save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - cache-provider: buildjet - uses: taiki-e/install-action@v2 with: tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete @@ -56,7 +55,7 @@ jobs: coverage: name: coverage-${{matrix.tranche}} #container: ghcr.io/jdx/rtx:github-actions - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest timeout-minutes: 30 strategy: fail-fast: false @@ -71,7 +70,6 @@ jobs: - uses: Swatinem/rust-cache@v2 with: shared-key: coverage - cache-provider: buildjet save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} cache-all-crates: true - uses: taiki-e/install-action@cargo-llvm-cov From 90a08421ee4c339f214de186d9788122ecd64361 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 9 Dec 2023 19:16:51 -0600 Subject: [PATCH 1246/1891] latest: prompt for plugin install (#1133) --- src/cli/latest.rs | 14 ++++---------- ..._cli__latest__tests__latest_missing_plugin.snap | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 11462bde2..76a73336f 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -26,7 +26,7 @@ pub struct Latest { } impl Latest { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let mut prefix = match self.tool.tvr { None => self.asdf_version, Some(ToolVersionRequest::Version(_, version)) => Some(version), @@ -35,15 +35,9 @@ impl Latest { style(&self.tool).cyan().for_stderr() ))?, }; - let plugin = config.plugins.get(&self.tool.plugin).ok_or_else(|| { - eyre!( - "plugin {} not found. run {} to install it", - style(self.tool.plugin.to_string()).cyan().for_stderr(), - style(format!("rtx plugin install {}", self.tool.plugin)) - .yellow() - .for_stderr() - ) - })?; + + let plugin = config.get_or_create_plugin(&self.tool.plugin); + plugin.ensure_installed(&mut config, None, false)?; if let Some(v) = prefix { prefix = Some(config.resolve_alias(plugin.name(), &v)?); } diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap b/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap index d9e64789c..e7aaee4d5 100644 --- a/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap +++ b/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap @@ -2,4 +2,4 @@ source: src/cli/latest.rs expression: stdout --- -plugin invalid_plugin not found. run rtx plugin install invalid_plugin to install it +No repository found for plugin invalid_plugin From 5aaf866fb0b51d8ce7ecc3f22f1623d19ca0e46e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 9 Dec 2023 20:52:22 -0600 Subject: [PATCH 1247/1891] rm bin script --- .bin/rtx | 5 ----- 1 file changed, 5 deletions(-) delete mode 100755 .bin/rtx diff --git a/.bin/rtx b/.bin/rtx deleted file mode 100755 index e87624ee8..000000000 --- a/.bin/rtx +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -e - -SCRIPT_DIR="$( cd "$( dirname "$(readlink -f "${BASH_SOURCE[0]}")")" >/dev/null 2>&1 && pwd )" -cargo run -q --all-features --manifest-path "$SCRIPT_DIR/../Cargo.toml" -- "$@" From 14dcfa4d7e6bf5443683e834936557956970788f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 10 Dec 2023 18:28:49 -0600 Subject: [PATCH 1248/1891] CI: exit alpine release script if no changes --- scripts/release-alpine.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh index 92bb382b8..c3d51a7d1 100755 --- a/scripts/release-alpine.sh +++ b/scripts/release-alpine.sh @@ -29,6 +29,11 @@ abuild -r apkbuild-lint APKBUILD git add APKBUILD + +if git diff --cached --exit-code; then + echo "No changes to commit" + exit 0 +fi git commit -m "community/rtx: upgrade to ${RTX_VERSION#v}" if [ "$DRY_RUN" == 0 ]; then From 7a38020a7bf4919d1d8ec704c568b9288fd9d1cb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 10 Dec 2023 20:02:56 -0600 Subject: [PATCH 1249/1891] settings: add Debug trait (#1131) --- Cargo.lock | 25 +++------- Cargo.toml | 4 +- src/config/config_file/rtx_toml.rs | 14 ++---- ...nfig_file__rtx_toml__tests__fixture-2.snap | 50 +++++++++++-------- src/config/settings.rs | 1 + 5 files changed, 44 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c83dc0dd..7d7ab84bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,9 +337,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "confique" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944dc1c6dec3f9b3adc127a921affd93baeea3d04c9b2d0a84380a243c9258b" +checksum = "c37945ed2efccb10339a12eea282a5af9ebac77720d088723b2bbbdc44eca964" dependencies = [ "confique-macro", "serde", @@ -347,9 +347,9 @@ dependencies = [ [[package]] name = "confique-macro" -version = "0.0.8" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7305b4979ffd6d8b02006da5520b21c66bfab961cd688b9b6db00780f61448ce" +checksum = "3821efdaaab3c5297054a90201cc3afa2061fc6ba2bc5d2fa558b850a7dabefe" dependencies = [ "heck 0.3.3", "proc-macro2", @@ -1146,15 +1146,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.0" @@ -1830,7 +1821,7 @@ dependencies = [ "indicatif", "indoc", "insta", - "itertools 0.12.0", + "itertools", "log", "num_cpus", "once_cell", @@ -2684,11 +2675,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "versions" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd" +checksum = "d7c271c81503258e3850c9d0f0d279d4ce9458d3388ef9eaa081b10d542182c3" dependencies = [ - "itertools 0.11.0", + "itertools", "nom", ] diff --git a/Cargo.toml b/Cargo.toml index 063647144..78380cf80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ clap_complete = { version = "4", optional = true } clap_mangen = { version = "0.2", optional = true } color-eyre = "0.6" color-print = "0.3" -confique = { version = "0.2.4", default-features = false } +confique = { version = "0.2", default-features = false } console = "0.15" ctrlc = "3.4" dialoguer = { version = "0.11", features = [] } @@ -100,7 +100,7 @@ thiserror = "1.0" toml = "<1" toml_edit = "<1" url = "2.4" -versions = "5.0" +versions = "6" which = "5" [target.'cfg(unix)'.dependencies] diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 5816707cd..ae6576d51 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -14,7 +14,7 @@ use toml_edit::{table, value, Array, Document, Item, Table, Value}; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsPartial; -use crate::config::{config_file, AliasMap, Settings}; +use crate::config::{config_file, AliasMap}; use crate::errors::Error::UntrustedConfig; use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; @@ -725,10 +725,8 @@ impl Debug for RtxToml { d.field("path", &self.path) .field("toolset", &self.toolset.to_string()) .field("is_trusted", &self.is_trusted); - if let Ok(partial) = self.settings() { - if let Ok(settings) = Settings::default_builder().preloaded(partial).load() { - d.field("settings", &settings); - } + if let Ok(settings) = self.settings() { + d.field("settings", &settings); } if let Some(env_file) = &self.env_file { d.field("env_file", env_file); @@ -764,13 +762,9 @@ mod tests { #[test] fn test_fixture() { let cf = RtxToml::from_file(&dirs::HOME.join("fixtures/.rtx.toml"), true).unwrap(); - let settings = Settings::default_builder() - .preloaded(cf.settings().unwrap()) - .load() - .unwrap(); assert_debug_snapshot!(cf.env()); - assert_debug_snapshot!(settings); + assert_debug_snapshot!(cf.settings()); assert_debug_snapshot!(cf.plugins()); assert_snapshot!(replace_path(&format!("{:#?}", cf.toolset))); assert_debug_snapshot!(cf.alias); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 475b9c3d1..908104eb1 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -1,25 +1,33 @@ --- source: src/config/config_file/rtx_toml.rs -expression: settings +expression: cf.settings() --- -Settings { - experimental: false, - always_keep_download: false, - always_keep_install: false, - legacy_version_file: true, - legacy_version_file_disable_tools: { - "disabled_tool_from_legacy_file", +Ok( + PartialSettings { + experimental: None, + always_keep_download: None, + always_keep_install: None, + legacy_version_file: None, + legacy_version_file_disable_tools: Some( + { + "disabled_tool_from_legacy_file", + }, + ), + plugin_autoupdate_last_check_duration: None, + trusted_config_paths: None, + verbose: Some( + true, + ), + asdf_compat: None, + jobs: None, + shorthands_file: None, + disable_default_shorthands: None, + disable_tools: Some( + { + "disabled_tool", + }, + ), + raw: None, + yes: None, }, - plugin_autoupdate_last_check_duration: "7d", - trusted_config_paths: {}, - verbose: true, - asdf_compat: false, - jobs: 4, - shorthands_file: None, - disable_default_shorthands: false, - disable_tools: { - "disabled_tool", - }, - raw: false, - yes: true, -} +) diff --git a/src/config/settings.rs b/src/config/settings.rs index 7e61883a0..13a555a60 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -10,6 +10,7 @@ use std::path::PathBuf; use crate::env; #[derive(Config, Debug, Clone)] +#[config(partial_attr(derive(Debug)))] pub struct Settings { #[config(env = "RTX_EXPERIMENTAL", default = false)] pub experimental: bool, From 02f69ff1480af0e599ead4ddaca8245d12f7ada4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:35:26 -0600 Subject: [PATCH 1250/1891] consolidate asset hosts --- CONTRIBUTING.md | 8 ++++---- README.md | 20 ++++++++++---------- SECURITY.md | 9 ++++----- docs/demo.tape | 2 +- packaging/homebrew/homebrew.rb | 8 ++++---- packaging/rpm/rtx.repo | 4 ++-- schema/rtx.json | 2 +- schema/rtx.plugin.json | 2 +- scripts/release.sh | 2 +- src/cli/doctor.rs | 2 +- src/cli/version.rs | 2 +- src/plugins/core/java.rs | 2 +- src/plugins/core/node.rs | 2 +- 13 files changed, 32 insertions(+), 33 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8609713b3..0a885cbef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,8 +115,8 @@ finch run -ti --rm ubuntu apt update -y apt install -y gpg sudo wget curl sudo install -dm 755 /etc/apt/keyrings -wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +wget -qO - https://rtx.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list apt update apt install -y rtx rtx -V @@ -127,7 +127,7 @@ rtx -V ```shell finch run -ti --rm amazonlinux yum install -y yum-utils -yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo +yum-config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo yum install -y rtx rtx -v ``` @@ -137,7 +137,7 @@ rtx -v ```shell finch run -ti --rm fedora dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo +dnf config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo dnf install -y rtx rtx -v ``` diff --git a/README.md b/README.md index 2bfb15461..68b60aa4b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Note that calling `which node` gives us a real path to node, not a shim. Install rtx on macOS (other methods [here](#installation)): ```sh-session -$ curl https://rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx +$ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version rtx 2023.12.21 @@ -252,14 +252,14 @@ Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate file, rtx will automatically add itself to `PATH`. ``` -curl https://rtx.pub/install.sh | sh +curl https://rtx.jdx.dev/install.sh | sh ``` If you want to verify the install script hasn't been tampered with: ``` gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 0x29DDE9E0 -curl https://rtx.pub/install.sh.sig | gpg --decrypt > install.sh +curl https://rtx.jdx.dev/install.sh.sig | gpg --decrypt > install.sh # ensure the above is signed with the rtx release key sh ./install.sh ``` @@ -267,7 +267,7 @@ sh ./install.sh or if you're allergic to `| sh`: ``` -curl https://rtx.pub/rtx-latest-macos-arm64 > /usr/local/bin/rtx +curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > /usr/local/bin/rtx ``` It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` @@ -367,8 +367,8 @@ For installation on Ubuntu/Debian: ``` sudo install -dm 755 /etc/apt/keyrings -wget -qO - https://rtx.pub/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +wget -qO - https://rtx.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list sudo apt update sudo apt install -y rtx ``` @@ -378,7 +378,7 @@ sudo apt install -y rtx > If you're on arm64 you'll need to run the following: > > ``` -> echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.pub/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +> echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list > ``` @@ -389,7 +389,7 @@ For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: ``` dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://rtx.pub/rpm/rtx.repo +dnf config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo dnf install -y rtx ``` @@ -399,7 +399,7 @@ dnf install -y rtx ``` yum install -y yum-utils -yum-config-manager --add-repo https://rtx.pub/rpm/rtx.repo +yum-config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo yum install -y rtx ``` @@ -1500,7 +1500,7 @@ jobs: build: steps: - run: | - curl https://rtx.pub/install.sh | sh + curl https://rtx.jdx.dev/install.sh | sh echo "$HOME/.local/share/rtx/bin" >> $GITHUB_PATH echo "$HOME/.local/share/rtx/shims" >> $GITHUB_PATH ``` diff --git a/SECURITY.md b/SECURITY.md index a5fd3b798..0cb07aad8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -20,12 +20,11 @@ the project. I only select dependencies with broad usage across the Rust communi I'm open to PRs or suggestions on reducing dependency count even at the cost of functionality because it will make rtx more secure. -## rtx.pub +## rtx.jdx.dev -rtx.pub is the asset host for rtx. It's used to host precompiled rtx CLI binaries, and hosts a "[VERSION](https://rtx.pub/VERSION)" -which rtx uses to occasionally check for a new version being released. Currently this is hosted with a mix -of 3 different vendors for CDN, assets, and domain registration. This will be brought down to a single vendor -to reduce the surface area for security reasons. +rtx.jdx.dev is the asset host for rtx. It's used to host precompiled rtx CLI binaries, and hosts a "[VERSION](https://rtx.jdx.dev/VERSION)" +which rtx uses to occasionally check for a new version being released. Everything hosted there uses a single +vendor to reduce surface area. ## rtx plugins diff --git a/docs/demo.tape b/docs/demo.tape index 29b4e9527..3a82d7e2d 100644 --- a/docs/demo.tape +++ b/docs/demo.tape @@ -58,7 +58,7 @@ Set Width 1200 Set Height 600 Set Padding 10 -Type "http rtx.pub/rtx-latest-macos-arm64 > ~/bin/rtx" Enter Sleep 2s +Type "http rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx" Enter Sleep 2s Type "chmod +x ~/bin/rtx" Sleep 1s Enter Sleep 1s Type "rtx -v" Sleep 1s Enter Sleep 1s Type 'eval "$(rtx activate bash)"' Sleep 1s Enter Sleep 2s diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index ea50bb15a..3161ee195 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -8,22 +8,22 @@ class Rtx < Formula on_macos do if Hardware::CPU.intel? - url "https://rtx.pub/v$RTX_VERSION/rtx-v$RTX_VERSION-macos-x64.tar.xz" + url "https://rtx.jdx.dev/v$RTX_VERSION/rtx-v$RTX_VERSION-macos-x64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_X86_64" end if Hardware::CPU.arm? - url "https://rtx.pub/v$RTX_VERSION/rtx-v$RTX_VERSION-macos-arm64.tar.xz" + url "https://rtx.jdx.dev/v$RTX_VERSION/rtx-v$RTX_VERSION-macos-arm64.tar.xz" sha256 "$RTX_CHECKSUM_MACOS_ARM64" end end on_linux do if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? - url "https://rtx.pub/v$RTX_VERSION/rtx-v$RTX_VERSION-linux-arm64.tar.xz" + url "https://rtx.jdx.dev/v$RTX_VERSION/rtx-v$RTX_VERSION-linux-arm64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_ARM64" end if Hardware::CPU.intel? - url "https://rtx.pub/v$RTX_VERSION/rtx-v$RTX_VERSION-linux-x64.tar.xz" + url "https://rtx.jdx.dev/v$RTX_VERSION/rtx-v$RTX_VERSION-linux-x64.tar.xz" sha256 "$RTX_CHECKSUM_LINUX_X86_64" end end diff --git a/packaging/rpm/rtx.repo b/packaging/rpm/rtx.repo index 94053a357..b017080b2 100644 --- a/packaging/rpm/rtx.repo +++ b/packaging/rpm/rtx.repo @@ -1,6 +1,6 @@ [rtx-repo] name=RTX Repo -baseurl=https://rtx.pub/rpm +baseurl=https://rtx.jdx.dev/rpm enabled=1 gpgcheck=1 -gpgkey=http://rtx.pub/gpg-key.pub +gpgkey=http://rtx.jdx.dev/gpg-key.pub diff --git a/schema/rtx.json b/schema/rtx.json index f9c09ec98..1f11a6e79 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://rtx.pub/schema/rtx.json", + "$id": "https://rtx.jdx.dev/schema/rtx.json", "title": "rtx", "description": "config file for rtx version manager (.rtx.toml)", "type": "object", diff --git a/schema/rtx.plugin.json b/schema/rtx.plugin.json index 5e4ec6c51..838cc763e 100644 --- a/schema/rtx.plugin.json +++ b/schema/rtx.plugin.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://rtx.pub/schema/rtx.plugin.json", + "$id": "https://rtx.jdx.dev/schema/rtx.plugin.json", "title": "rtx-plugin", "description": "config file for an rtx plugin", "type": "object", diff --git a/scripts/release.sh b/scripts/release.sh index b685bb6da..eb99227ee 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -64,7 +64,7 @@ gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_ if [[ "$DRY_RUN" != 1 ]]; then NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh - #AWS_S3_BUCKET=rtx.pub ./rtx/scripts/publish-s3.sh + #AWS_S3_BUCKET=rtx.jdx.dev ./rtx/scripts/publish-s3.sh ./rtx/scripts/publish-r2.sh fi diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index e12a4e1f6..f5904926b 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -62,7 +62,7 @@ impl Doctor { if !config.is_activated() && !shims_on_path() { let cmd = style("rtx help activate").yellow().for_stderr(); - let url = style("https://rtx.pub").underlined().for_stderr(); + let url = style("https://rtx.jdx.dev").underlined().for_stderr(); let shims = style(dirs::SHIMS.display()).cyan().for_stderr(); checks.push(formatdoc!( r#"rtx is not activated, run {cmd} or diff --git a/src/cli/version.rs b/src/cli/version.rs index d2fcc0414..388c9e154 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -111,7 +111,7 @@ fn get_latest_version_call() -> Option { #[cfg(not(test))] fn get_latest_version_call() -> Option { let timeout = Duration::from_secs(3); - const URL: &str = "http://rtx.pub/VERSION"; + const URL: &str = "http://rtx.jdx.dev/VERSION"; debug!("checking rtx version from {}", URL); let client = crate::http::Client::new_with_timeout(timeout).ok()?; match client.get_text(URL) { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index c9f46b390..756a4ae50 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -239,7 +239,7 @@ impl JavaPlugin { fn download_java_metadata(&self, release_type: &str) -> Result> { let url = format!( - "https://java.rtx.pub/metadata/{}/{}/{}.json", + "https://rtx-java-metadata.jdx.dev/metadata/{}/{}/{}.json", release_type, os(), arch() diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 15d75ea7b..bad0d7ab5 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -63,7 +63,7 @@ impl NodePlugin { fn fetch_remote_versions_from_rtx(&self) -> Result> { let versions = self .http - .get_text("http://metadata.rtx.pub/versions/node")? + .get_text("http://rtx-versions.jdx.dev/node")? .lines() .map(|v| v.trim().to_string()) .filter(|v| !v.is_empty()) From e45cfa9e02f5c06bd51a885f1d358d51e0af1481 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:44:36 -0600 Subject: [PATCH 1251/1891] Create CNAME --- docs/CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/CNAME diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 000000000..5a9541bc3 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +rtx-versions.jdx.dev \ No newline at end of file From f3080ae34e22fc666f0b6268cee5dc3757dbf82f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:45:50 -0600 Subject: [PATCH 1252/1891] Delete CNAME --- docs/CNAME | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/CNAME diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index 5a9541bc3..000000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -rtx-versions.jdx.dev \ No newline at end of file From bcf7dec24b0549ba6167d48a1a8a3a29140448fd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:52:18 -0600 Subject: [PATCH 1253/1891] chore: Release rtx-cli version 2023.12.22 --- Cargo.lock | 62 ++++++++++++++++++++++-------------------- Cargo.toml | 2 +- README.md | 4 +-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d7ab84bf..804fe926f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" dependencies = [ "anstyle", "anstyle-parse", @@ -262,7 +262,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -460,7 +460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -498,7 +498,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -954,9 +954,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1157,9 +1157,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" @@ -1187,9 +1187,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libgit2-sys" @@ -1402,7 +1402,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1500,7 +1500,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1792,7 +1792,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.21" +version = "2023.12.22" dependencies = [ "base64", "built", @@ -1871,9 +1871,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.27" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfeae074e687625746172d639330f1de242a178bf3189b51e35a7a21573513ac" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno 0.3.8", @@ -1927,9 +1927,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -2045,7 +2045,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2219,9 +2219,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" dependencies = [ "proc-macro2", "quote", @@ -2335,7 +2335,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2396,9 +2396,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ "backtrace", "bytes", @@ -2729,7 +2729,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-shared", ] @@ -2763,7 +2763,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3043,9 +3043,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.26" +version = "0.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" +checksum = "cb877ca3232bec99a6472ed63f7241de2a250165260908b2d24c09d867907a85" dependencies = [ "memchr", ] @@ -3062,11 +3062,13 @@ dependencies = [ [[package]] name = "xattr" -version = "1.0.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +checksum = "d367426ae76bdfce3d8eaea6e94422afd6def7d46f9c89e2980309115b3c2c41" dependencies = [ "libc", + "linux-raw-sys", + "rustix", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 78380cf80..8b9015912 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.21" +version = "2023.12.22" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 68b60aa4b..e60fd32e5 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.21 +rtx 2023.12.22 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.21/rtx-v2023.12.21-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.22/rtx-v2023.12.22-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 8cc914d41..c6ecab0de 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.21"; + version = "2023.12.22"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index a27ae7e21..7b08f8631 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.21 +Version: 2023.12.22 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From bac0036134daaccb60bce99d44973c948b9cd827 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:08:59 -0600 Subject: [PATCH 1254/1891] brew: autoactivate rtx in fish --- packaging/homebrew/homebrew.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/homebrew/homebrew.rb b/packaging/homebrew/homebrew.rb index 3161ee195..c72f1a847 100644 --- a/packaging/homebrew/homebrew.rb +++ b/packaging/homebrew/homebrew.rb @@ -31,6 +31,7 @@ class Rtx < Formula def install bin.install "bin/rtx" man1.install "man/man1/rtx.1" + share.install "share/fish" generate_completions_from_executable(bin / "rtx", "completion") lib.mkpath touch lib / ".disable-self-update" From b62fed7e5152becb743ae9c598a6f91301df0c85 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:54:19 -0600 Subject: [PATCH 1255/1891] use rtx-versions.jdx.dev to fetch remote versions (#1136) This should improve performance a tad and will also make rtx work better in cases where it does not have GITHUB_API_TOKEN set and is rate-limited on GitHub --- .idea/inspectionProfiles/Project_Default.xml | 31 ++++++++++++++++ src/plugins/core/bun.rs | 9 +++-- src/plugins/core/deno.rs | 9 +++-- src/plugins/core/go.rs | 4 ++ src/plugins/core/java.rs | 4 ++ src/plugins/core/mod.rs | 14 ++++++- src/plugins/core/python.rs | 4 ++ src/plugins/core/ruby.rs | 4 ++ src/plugins/external_plugin.rs | 39 +++++++++++++++++++- src/plugins/mod.rs | 7 +++- 10 files changed, 115 insertions(+), 10 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 64d6d1127..7a8cf6a2c 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -6,5 +6,36 @@ + + + \ No newline at end of file diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index f544be47f..e1b0b8f7c 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -10,7 +10,7 @@ use crate::config::Settings; use crate::github::GithubRelease; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; +use crate::plugins::{Plugin, HTTP}; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::ProgressReport; use crate::{file, http}; @@ -27,9 +27,12 @@ impl BunPlugin { } fn fetch_remote_versions(&self) -> Result> { - let http = http::Client::new()?; + match self.core.fetch_remote_versions_from_rtx() { + Ok(versions) => return Ok(versions), + Err(e) => warn!("failed to fetch remote versions: {}", e), + } let releases: Vec = - http.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?; + HTTP.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?; let versions = releases .into_iter() .map(|r| r.tag_name) diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index c4129a92b..59ce2e62a 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -11,7 +11,7 @@ use crate::config::{Config, Settings}; use crate::github::GithubRelease; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; +use crate::plugins::{Plugin, HTTP}; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::ProgressReport; use crate::{file, http}; @@ -28,9 +28,12 @@ impl DenoPlugin { } fn fetch_remote_versions(&self) -> Result> { - let http = http::Client::new()?; + match self.core.fetch_remote_versions_from_rtx() { + Ok(versions) => return Ok(versions), + Err(e) => warn!("failed to fetch remote versions: {}", e), + } let releases: Vec = - http.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; + HTTP.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; let versions = releases .into_iter() .map(|r| r.name) diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index c81dad64e..c6d3d6b97 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -28,6 +28,10 @@ impl GoPlugin { } fn fetch_remote_versions(&self) -> Result> { + match self.core.fetch_remote_versions_from_rtx() { + Ok(versions) => return Ok(versions), + Err(e) => warn!("failed to fetch remote versions: {}", e), + } CorePlugin::run_fetch_task_with_timeout(move || { let repo = &*env::RTX_GO_REPO; let output = cmd!("git", "ls-remote", "--tags", repo, "go*").read()?; diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 756a4ae50..72913286b 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -77,6 +77,10 @@ impl JavaPlugin { } fn fetch_remote_versions(&self) -> Result> { + match self.core.fetch_remote_versions_from_rtx() { + Ok(versions) => return Ok(versions), + Err(e) => warn!("failed to fetch remote versions: {}", e), + } let versions = self .fetch_java_metadata("ga")? .iter() diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 0cdae088d..65600ac8a 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -18,7 +18,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}; +use crate::plugins::{Plugin, PluginName, HTTP}; use crate::timeout::run_with_timeout; use crate::toolset::ToolVersion; use crate::{dirs, env}; @@ -63,6 +63,7 @@ pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { #[derive(Debug)] pub struct CorePlugin { + pub name: &'static str, pub cache_path: PathBuf, pub remote_version_cache: CacheManager>, } @@ -71,6 +72,7 @@ impl CorePlugin { pub fn new(name: &'static str) -> Self { let cache_path = dirs::CACHE.join(name); Self { + name, remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), cache_path, @@ -90,4 +92,14 @@ impl CorePlugin { { run_with_timeout(f, *env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) } + + pub fn fetch_remote_versions_from_rtx(&self) -> Result> { + let versions = HTTP + .get_text(format!("http://rtx-versions.jdx.dev/{}", &self.name))? + .lines() + .map(|v| v.trim().to_string()) + .filter(|v| !v.is_empty()) + .collect(); + Ok(versions) + } } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 9519d60d2..5aad85aea 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -63,6 +63,10 @@ impl PythonPlugin { } fn fetch_remote_versions(&self) -> Result> { + match self.core.fetch_remote_versions_from_rtx() { + Ok(versions) => return Ok(versions), + Err(e) => warn!("failed to fetch remote versions: {}", e), + } self.install_or_update_python_build()?; let python_build_bin = self.python_build_bin(); CorePlugin::run_fetch_task_with_timeout(move || { diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index e184a67d5..9a5cc645a 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -141,6 +141,10 @@ impl RubyPlugin { } fn fetch_remote_versions(&self) -> Result> { + match self.core.fetch_remote_versions_from_rtx() { + Ok(versions) => return Ok(versions), + Err(e) => warn!("failed to fetch remote versions: {}", e), + } self.update_build_tool()?; let ruby_build_bin = self.ruby_build_bin(); let versions = CorePlugin::run_fetch_task_with_timeout(move || { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 001c35c7d..5cc1f4bba 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -14,6 +14,7 @@ use once_cell::sync::Lazy; use crate::cache::CacheManager; use crate::config::{Config, Settings}; +use crate::default_shorthands::DEFAULT_SHORTHANDS; use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; @@ -24,13 +25,13 @@ use crate::install_context::InstallContext; use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::rtx_plugin_toml::RtxPluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; -use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; +use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager, HTTP}; use crate::timeout::run_with_timeout; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::ProgressReport; use crate::ui::prompt; -use crate::{dirs, env, file}; +use crate::{dirs, env, file, http}; /// This represents a plugin installed to ~/.local/share/rtx/plugins pub struct ExternalPlugin { @@ -137,7 +138,41 @@ impl ExternalPlugin { Ok(()) } + fn fetch_versions(&self) -> Result>> { + // ensure that we're using a default shorthand plugin + let git = Git::new(self.plugin_path.to_path_buf()); + if git.get_remote_url() + != DEFAULT_SHORTHANDS + .get(self.name.as_str()) + .map(|s| s.to_string()) + { + return Ok(None); + } + let versions = match HTTP.get_text(format!("http://rtx-versions.jdx.dev/{}", self.name)) { + Err(err) if http::error_code(&err) == Some(404) => return Ok(None), + res => res?, + }; + let versions = versions + .lines() + .map(|v| v.trim().to_string()) + .filter(|v| !v.is_empty()) + .collect_vec(); + match versions.is_empty() { + true => Ok(None), + false => Ok(Some(versions)), + } + } + fn fetch_remote_versions(&self, settings: &Settings) -> Result> { + match self.fetch_versions() { + Ok(Some(versions)) => return Ok(versions), + Err(err) => warn!( + "Failed to fetch remote versions for plugin {}: {}", + style(&self.name).cyan().for_stderr(), + err + ), + _ => {} + }; let cmd = self.script_man.cmd(settings, &Script::ListAll); let result = run_with_timeout( move || { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 29b8c0177..4873e4e37 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -9,6 +9,7 @@ use color_eyre::eyre::Result; use console::style; use eyre::WrapErr; use itertools::Itertools; +use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; @@ -16,6 +17,7 @@ pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; +use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::{display_path, remove_all, remove_all_with_warning}; use crate::install_context::InstallContext; use crate::lock_file::LockFile; @@ -23,7 +25,7 @@ use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; -use crate::{dirs, file}; +use crate::{dirs, file, http}; pub mod core; mod external_plugin; @@ -33,6 +35,9 @@ mod script_manager; pub type PluginName = String; +pub static HTTP: Lazy = + Lazy::new(|| http::Client::new_with_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); + pub trait Plugin: Debug + Send + Sync { fn name(&self) -> &str; fn get_type(&self) -> PluginType { From efe4be50e2865cd8a5ef97c449df180a871b0ff6 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:02:35 -0600 Subject: [PATCH 1256/1891] add jq and python bin to dockerfile (#1137) --- packaging/rtx/Dockerfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packaging/rtx/Dockerfile b/packaging/rtx/Dockerfile index a38db51d7..7fe3833cd 100644 --- a/packaging/rtx/Dockerfile +++ b/packaging/rtx/Dockerfile @@ -10,7 +10,12 @@ WORKDIR /usr/src/rtx COPY . /usr/src/rtx/ -RUN cargo build --release +RUN cargo build --release \ + && ln -s /usr/bin/{python3,python} \ + && python -V \ + && apt-get update && apt-get install -y \ + jq \ + && rm -rf /var/lib/apt/lists/* && apt-get clean FROM rust as runtime From 42ba8b91c3cffbfd81e40786eb967a988ed9f83f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:02:49 -0600 Subject: [PATCH 1257/1891] added RTX_USE_VERSION_HOST (#1138) can be used to bypass it --- src/env.rs | 2 ++ src/plugins/core/bun.rs | 3 ++- src/plugins/core/deno.rs | 3 ++- src/plugins/core/go.rs | 3 ++- src/plugins/core/java.rs | 3 ++- src/plugins/core/mod.rs | 10 +++++++--- src/plugins/core/node.rs | 24 +++++++----------------- src/plugins/core/node_build.rs | 5 +++++ src/plugins/core/python.rs | 3 ++- src/plugins/core/ruby.rs | 3 ++- src/plugins/external_plugin.rs | 3 +++ 11 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/env.rs b/src/env.rs index 4632e3f86..859057f95 100644 --- a/src/env.rs +++ b/src/env.rs @@ -87,6 +87,8 @@ pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| match var_option_bool("RTX #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); +pub static RTX_USE_VERSIONS_HOST: Lazy = Lazy::new(|| !var_is_false("RTX_USE_VERSIONS_HOST")); + // python pub static RTX_PYENV_REPO: Lazy = Lazy::new(|| { var("RTX_PYENV_REPO").unwrap_or_else(|_| "https://github.com/pyenv/pyenv.git".into()) diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index e1b0b8f7c..2d6310e6a 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -28,7 +28,8 @@ impl BunPlugin { fn fetch_remote_versions(&self) -> Result> { match self.core.fetch_remote_versions_from_rtx() { - Ok(versions) => return Ok(versions), + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } let releases: Vec = diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 59ce2e62a..f2298eba7 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -29,7 +29,8 @@ impl DenoPlugin { fn fetch_remote_versions(&self) -> Result> { match self.core.fetch_remote_versions_from_rtx() { - Ok(versions) => return Ok(versions), + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } let releases: Vec = diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index c6d3d6b97..097d352f5 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -29,7 +29,8 @@ impl GoPlugin { fn fetch_remote_versions(&self) -> Result> { match self.core.fetch_remote_versions_from_rtx() { - Ok(versions) => return Ok(versions), + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } CorePlugin::run_fetch_task_with_timeout(move || { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 72913286b..0d014e7cc 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -78,7 +78,8 @@ impl JavaPlugin { fn fetch_remote_versions(&self) -> Result> { match self.core.fetch_remote_versions_from_rtx() { - Ok(versions) => return Ok(versions), + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } let versions = self diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 65600ac8a..ad9ccf09b 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use std::sync::Arc; use color_eyre::eyre::Result; +use itertools::Itertools; use once_cell::sync::Lazy; pub use python::PythonPlugin; @@ -93,13 +94,16 @@ impl CorePlugin { run_with_timeout(f, *env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) } - pub fn fetch_remote_versions_from_rtx(&self) -> Result> { + pub fn fetch_remote_versions_from_rtx(&self) -> Result>> { + if !*env::RTX_USE_VERSIONS_HOST { + return Ok(None); + } let versions = HTTP .get_text(format!("http://rtx-versions.jdx.dev/{}", &self.name))? .lines() .map(|v| v.trim().to_string()) .filter(|v| !v.is_empty()) - .collect(); - Ok(versions) + .collect_vec(); + Ok(Some(versions)) } } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index bad0d7ab5..20c5314ad 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -35,14 +35,14 @@ impl NodePlugin { let node_url_overridden = env::var("RTX_NODE_MIRROR_URL") .or(env::var("NODE_BUILD_MIRROR_URL")) .is_ok(); - if node_url_overridden { - self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) - } else { - self.fetch_remote_versions_from_rtx().or_else(|e| { - warn!("failed to fetch remote versions from rtx: {}", e); - self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) - }) + if !node_url_overridden { + match self.core.fetch_remote_versions_from_rtx() { + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} + Err(e) => warn!("failed to fetch remote versions: {}", e), + } } + self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) } fn fetch_remote_versions_from_node(&self, base: &Url) -> Result> { let versions = self @@ -60,16 +60,6 @@ impl NodePlugin { .collect(); Ok(versions) } - fn fetch_remote_versions_from_rtx(&self) -> Result> { - let versions = self - .http - .get_text("http://rtx-versions.jdx.dev/node")? - .lines() - .map(|v| v.trim().to_string()) - .filter(|v| !v.is_empty()) - .collect(); - Ok(versions) - } fn install_precompiled(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { match self.fetch_tarball( diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index be83e4265..d0b737469 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -84,6 +84,11 @@ impl NodeBuildPlugin { } fn fetch_remote_versions(&self) -> Result> { + match self.core.fetch_remote_versions_from_rtx() { + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} + Err(e) => warn!("failed to fetch remote versions: {}", e), + } self.install_or_update_node_build()?; let node_build_bin = self.node_build_bin(); CorePlugin::run_fetch_task_with_timeout(move || { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 5aad85aea..04d337735 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -64,7 +64,8 @@ impl PythonPlugin { fn fetch_remote_versions(&self) -> Result> { match self.core.fetch_remote_versions_from_rtx() { - Ok(versions) => return Ok(versions), + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } self.install_or_update_python_build()?; diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 9a5cc645a..d3404395d 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -142,7 +142,8 @@ impl RubyPlugin { fn fetch_remote_versions(&self) -> Result> { match self.core.fetch_remote_versions_from_rtx() { - Ok(versions) => return Ok(versions), + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } self.update_build_tool()?; diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 5cc1f4bba..bed5e4a74 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -139,6 +139,9 @@ impl ExternalPlugin { } fn fetch_versions(&self) -> Result>> { + if !*env::RTX_USE_VERSIONS_HOST { + return Ok(None); + } // ensure that we're using a default shorthand plugin let git = Git::new(self.plugin_path.to_path_buf()); if git.get_remote_url() From 1f0ea9ddf0f8d0b0c9a4d1050dc0a8c842889d04 Mon Sep 17 00:00:00 2001 From: Tomoyuki Harada Date: Tue, 12 Dec 2023 08:17:52 +0900 Subject: [PATCH 1258/1891] (python plugin): fixes #1134 (#1135) * (python plugin): fixes #1134 * (python plugin): fixes #1134 --- src/plugins/core/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 04d337735..beffc66b8 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -90,7 +90,7 @@ impl PythonPlugin { return Ok(()); } pr.set_message("installing default packages"); - CmdLineRunner::new(&config.settings, self.python_path(tv)) + CmdLineRunner::new(&config.settings, tv.install_path().join("bin/python")) .with_pr(pr) .arg("-m") .arg("pip") From 49929c4ccffa0c40660b88a1e9aabfd2c5e16bf1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:33:53 -0600 Subject: [PATCH 1259/1891] chore: Release rtx-cli version 2023.12.23 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 804fe926f..8e7a4984f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1792,7 +1792,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.22" +version = "2023.12.23" dependencies = [ "base64", "built", @@ -3043,9 +3043,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.27" +version = "0.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb877ca3232bec99a6472ed63f7241de2a250165260908b2d24c09d867907a85" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 8b9015912..90a3c9c4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.22" +version = "2023.12.23" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index e60fd32e5..a6b321a14 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.22 +rtx 2023.12.23 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.22/rtx-v2023.12.22-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.23/rtx-v2023.12.23-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index c6ecab0de..a7417cad1 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.22"; + version = "2023.12.23"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 7b08f8631..9c52602d8 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.22 +Version: 2023.12.23 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From ef8b1ad0f9cbc248a4835553d32bee2c99375b4d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:49:04 -0600 Subject: [PATCH 1260/1891] update CLOUDFLARE_ZONE_ID --- .github/workflows/release.yml | 1 + scripts/publish-s3.sh | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 654493000..0ebe36e93 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -220,6 +220,7 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} + CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} - name: homebrew-tap push if: startsWith(github.event.ref, 'refs/tags/v') run: git push diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 4852411ee..2e64d55fe 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -24,7 +24,6 @@ aws s3 cp artifacts/deb/pool/ "s3://$AWS_S3_BUCKET/deb/pool/" --cache-control "$ aws s3 cp artifacts/deb/dists/ "s3://$AWS_S3_BUCKET/deb/dists/" --cache-control "$cache_day" --no-progress --no-progress --recursive export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 -export CLOUDFLARE_ZONE_ID=80d977fd09f01db52bec165778088891 curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ From 7b79bbb4fd0bd8d3098a0158ff70a47f97a73980 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 18:29:48 -0600 Subject: [PATCH 1261/1891] bump docker/setup-buildx-action (#1139) --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 6d1b9a8c4..358da4c0f 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -71,7 +71,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Log in to Docker Hub uses: docker/login-action@v3 with: From 6dd0c554031ca1d3f44f90c11c456b666d595c21 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 19:52:19 -0600 Subject: [PATCH 1262/1891] docker: fix jq/python/pip installs (#1141) --- packaging/rtx/Dockerfile | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/packaging/rtx/Dockerfile b/packaging/rtx/Dockerfile index 7fe3833cd..b2285479d 100644 --- a/packaging/rtx/Dockerfile +++ b/packaging/rtx/Dockerfile @@ -1,25 +1,33 @@ +# syntax=docker/dockerfile:1 FROM rust as builder LABEL maintainer="jdx" -SHELL ["/bin/bash", "-o", "pipefail", "-c"] +WORKDIR /usr/src/rtx +COPY . /usr/src/rtx/ +RUN cargo build --release + +FROM rust as runtime + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV RTX_DATA_DIR="/rtx" ENV RTX_CONFIG_DIR="/rtx" ENV RTX_CACHE_DIR="/rtx/cache" ENV PATH="/rtx/shims:$PATH" -WORKDIR /usr/src/rtx -COPY . /usr/src/rtx/ +COPY --from=builder /usr/src/rtx/target/release/rtx /usr/local/bin/rtx -RUN cargo build --release \ - && ln -s /usr/bin/{python3,python} \ - && python -V \ - && apt-get update && apt-get install -y \ +RUN < Date: Mon, 11 Dec 2023 20:23:29 -0600 Subject: [PATCH 1263/1891] logging: added --quiet flag (#1140) * logging: added --quiet flag * Commit from GitHub Actions (rtx) --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- completions/_rtx | 228 +++++++++--------- completions/rtx.bash | 120 ++++----- completions/rtx.fish | 4 +- src/cli/args/log_level.rs | 1 + src/cli/args/mod.rs | 1 + src/cli/args/quiet.rs | 16 ++ src/cli/args/verbose.rs | 3 +- src/cli/install.rs | 4 +- src/cli/mod.rs | 4 + src/cli/plugins/install.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/prune.rs | 2 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 2 +- src/config/config_file/mod.rs | 2 +- ...nfig_file__rtx_toml__tests__fixture-2.snap | 1 + src/config/mod.rs | 4 - src/config/settings.rs | 2 + src/env.rs | 7 +- src/plugins/external_plugin.rs | 2 +- src/toolset/mod.rs | 2 +- src/ui/multi_progress_report.rs | 26 +- src/ui/progress_report.rs | 20 +- 23 files changed, 247 insertions(+), 210 deletions(-) create mode 100644 src/cli/args/quiet.rs diff --git a/completions/_rtx b/completions/_rtx index 5c29aa6b9..64dbc6294 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -6,9 +6,9 @@ _rtx() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cmds' \ '*::arg:->args' && ret=0 @@ -66,9 +66,9 @@ __rtx_activate_cmd() { '::shell_type:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_alias_cmd] )) || @@ -76,9 +76,9 @@ __rtx_alias_cmd() { _arguments -s -S \ '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_alias_cmds' \ '*::arg:->args' && ret=0 @@ -103,9 +103,9 @@ __rtx_alias_get_cmd() { ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_alias_ls_cmd] )) || @@ -113,9 +113,9 @@ __rtx_alias_ls_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_alias_set_cmd] )) || @@ -125,9 +125,9 @@ __rtx_alias_set_cmd() { ':alias:__rtx_aliases' \ ':value:' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_alias_unset_cmd] )) || @@ -136,9 +136,9 @@ __rtx_alias_unset_cmd() { ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_asdf_cmd] )) || @@ -146,27 +146,27 @@ __rtx_asdf_cmd() { _arguments -s -S \ '*::args:_cmdambivalent' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_bin_paths_cmd] )) || __rtx_bin_paths_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_cache_cmd] )) || __rtx_cache_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cache_cmds' \ '*::arg:->args' && ret=0 @@ -186,9 +186,9 @@ return ret __rtx_cache_clear_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_completion_cmd] )) || @@ -196,9 +196,9 @@ __rtx_completion_cmd() { _arguments -s -S \ '::shell:(bash fish zsh)' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_current_cmd] )) || @@ -206,27 +206,27 @@ __rtx_current_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_deactivate_cmd] )) || __rtx_deactivate_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_cmd] )) || __rtx_direnv_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_direnv_cmds' \ '*::arg:->args' && ret=0 @@ -248,36 +248,36 @@ return ret __rtx_direnv_activate_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_envrc_cmd] )) || __rtx_direnv_envrc_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_exec_cmd] )) || __rtx_direnv_exec_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_doctor_cmd] )) || __rtx_doctor_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_env_cmd] )) || @@ -287,9 +287,9 @@ __rtx_env_cmd() { '*::tool:__rtx_tool_versions' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_env_vars_cmd] )) || @@ -299,9 +299,9 @@ __rtx_env_vars_cmd() { '*--remove=[Remove the environment variable from config file]:remove:' \ '*::env_vars:' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_exec_cmd] )) || @@ -311,9 +311,9 @@ __rtx_exec_cmd() { '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_global_cmd] )) || @@ -325,9 +325,9 @@ __rtx_global_cmd() { '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ '--path[Get the path of the global config file]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_hook_env_cmd] )) || @@ -336,9 +336,9 @@ __rtx_hook_env_cmd() { '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_implode_cmd] )) || @@ -347,9 +347,9 @@ __rtx_implode_cmd() { '--config[Also remove config directory]' \ '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_install_cmd] )) || @@ -359,7 +359,7 @@ __rtx_install_cmd() { '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ '*'{-v,--verbose}'[Show installation output]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -369,9 +369,9 @@ __rtx_latest_cmd() { ':tool:__rtx_tool_versions' \ '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_link_cmd] )) || @@ -381,9 +381,9 @@ __rtx_link_cmd() { ':path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_local_cmd] )) || @@ -396,9 +396,9 @@ __rtx_local_cmd() { '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ '--path[Get the path of the config file]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_ls_cmd] )) || @@ -412,9 +412,9 @@ __rtx_ls_cmd() { '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_ls_remote_cmd] )) || @@ -424,9 +424,9 @@ __rtx_ls_remote_cmd() { '--all[Show all installed plugins and versions]' \ '::prefix:__rtx_prefixes' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_outdated_cmd] )) || @@ -434,9 +434,9 @@ __rtx_outdated_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_cmd] )) || @@ -447,9 +447,9 @@ __rtx_plugins_cmd() { '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ '--refs[show the git refs for each plugin]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_plugins_cmds' \ '*::arg:->args' && ret=0 @@ -479,7 +479,7 @@ __rtx_plugins_install_cmd() { '(-a --all)'{-a,--all}'[Install all missing plugins]' \ '*'{-v,--verbose}'[Show installation output]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -490,9 +490,9 @@ __rtx_plugins_link_cmd() { '::path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_ls_cmd] )) || @@ -503,9 +503,9 @@ __rtx_plugins_ls_cmd() { '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ '--refs[Show the git refs for each plugin]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_ls_remote_cmd] )) || @@ -514,9 +514,9 @@ __rtx_plugins_ls_remote_cmd() { '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_uninstall_cmd] )) || @@ -526,9 +526,9 @@ __rtx_plugins_uninstall_cmd() { '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ '(-a --all)'{-a,--all}'[Remove all plugins]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_update_cmd] )) || @@ -536,9 +536,9 @@ __rtx_plugins_update_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_prune_cmd] )) || @@ -547,18 +547,18 @@ __rtx_prune_cmd() { '*::plugin:__rtx_plugins' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_reshim_cmd] )) || __rtx_reshim_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_self_update_cmd] )) || @@ -569,17 +569,17 @@ __rtx_self_update_cmd() { '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ '::version:' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' } (( $+functions[__rtx_settings_cmd] )) || __rtx_settings_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_settings_cmds' \ '*::arg:->args' && ret=0 @@ -603,18 +603,18 @@ __rtx_settings_get_cmd() { _arguments -s -S \ ':key:' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_settings_ls_cmd] )) || __rtx_settings_ls_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_settings_set_cmd] )) || @@ -623,9 +623,9 @@ __rtx_settings_set_cmd() { ':key:' \ ':value:' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_settings_unset_cmd] )) || @@ -633,9 +633,9 @@ __rtx_settings_unset_cmd() { _arguments -s -S \ ':key:' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_shell_cmd] )) || @@ -644,18 +644,18 @@ __rtx_shell_cmd() { '*::tool:__rtx_tool_versions' \ '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_sync_cmd] )) || __rtx_sync_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_sync_cmds' \ '*::arg:->args' && ret=0 @@ -679,9 +679,9 @@ __rtx_sync_node_cmd() { '--nvm[Get tool versions from nvm]' \ '--nodenv[Get tool versions from nodenv]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_sync_python_cmd] )) || @@ -689,9 +689,9 @@ __rtx_sync_python_cmd() { _arguments -s -S \ '--pyenv[Get tool versions from pyenv]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_trust_cmd] )) || @@ -700,9 +700,9 @@ __rtx_trust_cmd() { '::config_file:_files' \ '--untrust[No longer trust this config]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_uninstall_cmd] )) || @@ -712,9 +712,9 @@ __rtx_uninstall_cmd() { '(-a --all)'{-a,--all}'[Delete all installed versions]' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_upgrade_cmd] )) || @@ -723,9 +723,9 @@ __rtx_upgrade_cmd() { '*::tool:__rtx_tool_versions' \ '(-n --dry-run)'{-n,--dry-run}'[Just print what would be done, don'\''t actually do it]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_use_cmd] )) || @@ -739,18 +739,18 @@ __rtx_use_cmd() { '(-e --env)'{-e,--env}'=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:env:' \ '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_version_cmd] )) || __rtx_version_cmd() { _arguments -s -S \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_where_cmd] )) || @@ -758,9 +758,9 @@ __rtx_where_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_which_cmd] )) || @@ -771,9 +771,9 @@ __rtx_which_cmd() { '--version[Show the version instead of the path]' \ '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ - '--log-level=[Set the log output verbosity]:log-level:(error warn info debug trace)' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ - '*'{-v,--verbose}'[Show installation output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_cmds] )) || diff --git a/completions/rtx.bash b/completions/rtx.bash index d7b6b53c0..c275b26a1 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -559,7 +559,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -r -v -y -h -V --jobs --debug --log-level --trace --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + opts="-j -q -r -v -y -h -V --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -619,7 +619,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -r -v -y -h --plugin --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" + opts="-p -j -q -r -v -y -h --plugin --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -653,7 +653,7 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -763,7 +763,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -789,7 +789,7 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -815,7 +815,7 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -841,7 +841,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ARGS]..." + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -867,7 +867,7 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -893,7 +893,7 @@ _rtx() { return 0 ;; rtx__cache) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help clear help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -919,7 +919,7 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -987,7 +987,7 @@ _rtx() { return 0 ;; rtx__completion) - opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish zsh" + opts="-s -j -q -r -v -y -h --shell --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1021,7 +1021,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1047,7 +1047,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1073,7 +1073,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help envrc exec activate help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1099,7 +1099,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1125,7 +1125,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1151,7 +1151,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1247,7 +1247,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1273,7 +1273,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -J -j -r -v -y -h --shell --json --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-s -J -j -q -r -v -y -h --shell --json --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1307,7 +1307,7 @@ _rtx() { return 0 ;; rtx__env__vars) - opts="-j -r -v -y -h --file --remove --jobs --debug --log-level --trace --raw --verbose --yes --help [ENV_VARS]..." + opts="-j -q -r -v -y -h --file --remove --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1341,7 +1341,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -C -j -r -v -y -h --command --cd --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -C -j -q -r -v -y -h --command --cd --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1383,7 +1383,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -r -v -y -h --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-j -q -r -v -y -h --pin --fuzzy --remove --path --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2281,7 +2281,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -r -v -y -h --shell --status --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-s -j -q -r -v -y -h --shell --status --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2315,7 +2315,7 @@ _rtx() { return 0 ;; rtx__implode) - opts="-n -j -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-n -j -q -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2341,7 +2341,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-f -v -j -r -y -h --force --verbose --jobs --debug --log-level --trace --raw --yes --help [TOOL@VERSION]..." + opts="-f -v -j -q -r -y -h --force --verbose --jobs --debug --log-level --trace --quiet --raw --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2367,7 +2367,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-i -j -r -v -y -h --installed --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" + opts="-i -j -q -r -v -y -h --installed --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2393,7 +2393,7 @@ _rtx() { return 0 ;; rtx__link) - opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-f -j -q -r -v -y -h --force --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2419,7 +2419,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -r -v -y -h --parent --pin --fuzzy --remove --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-p -j -q -r -v -y -h --parent --pin --fuzzy --remove --path --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2449,7 +2449,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -J -m -j -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]" + opts="-p -c -g -i -J -m -j -q -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2487,7 +2487,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION] [PREFIX]" + opts="-j -q -r -v -y -h --all --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION] [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2513,7 +2513,7 @@ _rtx() { return 0 ;; rtx__outdated) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2539,7 +2539,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help install link ls ls-remote uninstall update help" + opts="-a -c -u -j -q -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2677,7 +2677,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -r -y -h --force --all --verbose --jobs --debug --log-level --trace --raw --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." + opts="-f -a -v -j -q -r -y -h --force --all --verbose --jobs --debug --log-level --trace --quiet --raw --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2703,7 +2703,7 @@ _rtx() { return 0 ;; rtx__plugins__link) - opts="-f -j -r -v -y -h --force --jobs --debug --log-level --trace --raw --verbose --yes --help [PATH]" + opts="-f -j -q -r -v -y -h --force --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2729,7 +2729,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -j -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-a -c -u -j -q -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2755,7 +2755,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -r -v -y -h --urls --only-names --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-u -j -q -r -v -y -h --urls --only-names --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2781,7 +2781,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-p -a -j -r -v -y -h --purge --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." + opts="-p -a -j -q -r -v -y -h --purge --all --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2807,7 +2807,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -j -r -v -y -h --all --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." + opts="-a -j -q -r -v -y -h --all --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2833,7 +2833,7 @@ _rtx() { return 0 ;; rtx__prune) - opts="-n -j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN]..." + opts="-n -j -q -r -v -y -h --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2859,7 +2859,7 @@ _rtx() { return 0 ;; rtx__render__completion) - opts="-s -j -r -v -y -h --shell --jobs --debug --log-level --trace --raw --verbose --yes --help bash elvish fish powershell zsh" + opts="-s -j -q -r -v -y -h --shell --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2893,7 +2893,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2919,7 +2919,7 @@ _rtx() { return 0 ;; rtx__render__mangen) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2945,7 +2945,7 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [PLUGIN] [VERSION]" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2971,7 +2971,7 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-f -y -j -r -v -h --force --no-plugins --yes --jobs --debug --log-level --trace --raw --verbose --help [VERSION]" + opts="-f -y -j -q -r -v -h --force --no-plugins --yes --jobs --debug --log-level --trace --quiet --raw --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2997,7 +2997,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help get ls set unset help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3023,7 +3023,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3133,7 +3133,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3159,7 +3159,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3185,7 +3185,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3211,7 +3211,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -r -v -y -h --unset --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-u -j -q -r -v -y -h --unset --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3237,7 +3237,7 @@ _rtx() { return 0 ;; rtx__sync) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help node python help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3319,7 +3319,7 @@ _rtx() { return 0 ;; rtx__sync__node) - opts="-j -r -v -y -h --brew --nvm --nodenv --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --brew --nvm --nodenv --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3345,7 +3345,7 @@ _rtx() { return 0 ;; rtx__sync__python) - opts="-j -r -v -y -h --pyenv --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --pyenv --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3371,7 +3371,7 @@ _rtx() { return 0 ;; rtx__trust) - opts="-j -r -v -y -h --untrust --jobs --debug --log-level --trace --raw --verbose --yes --help [CONFIG_FILE]" + opts="-j -q -r -v -y -h --untrust --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3397,7 +3397,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-a -n -j -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help ..." + opts="-a -n -j -q -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3423,7 +3423,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-n -j -r -v -y -h --dry-run --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-n -j -q -r -v -y -h --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3449,7 +3449,7 @@ _rtx() { return 0 ;; rtx__use) - opts="-g -e -p -j -r -v -y -h --pin --fuzzy --remove --global --env --path --jobs --debug --log-level --trace --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-g -e -p -j -q -r -v -y -h --pin --fuzzy --remove --global --env --path --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3495,7 +3495,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3521,7 +3521,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -r -v -y -h --jobs --debug --log-level --trace --raw --verbose --yes --help [ASDF_VERSION]" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3547,7 +3547,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-t -j -r -v -y -h --plugin --version --tool --jobs --debug --log-level --trace --raw --verbose --yes --help " + opts="-t -j -q -r -v -y -h --plugin --version --tool --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 8152d235e..ac6a6f3d1 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -2,9 +2,9 @@ set -l fssf "__fish_seen_subcommand_from" # rtx complete -xc rtx -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -complete -xc rtx -l log-level -a "error warn info debug trace" -d 'Set the log output verbosity' +complete -xc rtx -s q -l quiet -d 'Suppress output' complete -xc rtx -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user.' -complete -xc rtx -s v -l verbose -d 'Show installation output' +complete -xc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -xc rtx -s y -l yes -d 'Answer yes to all prompts' set -l others activate alias bin-paths cache completion current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell' diff --git a/src/cli/args/log_level.rs b/src/cli/args/log_level.rs index 08351563e..c49abceb5 100644 --- a/src/cli/args/log_level.rs +++ b/src/cli/args/log_level.rs @@ -15,6 +15,7 @@ impl LogLevel { .help("Set the log output verbosity") .default_value(DEFAULT_LOG_LEVEL.as_str()) .global(true) + .hide(true) .value_parser(["error", "warn", "info", "debug", "trace"]) } } diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index e06319fd0..248528581 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,6 +1,7 @@ pub mod env_var; pub mod jobs; pub mod log_level; +pub mod quiet; pub mod raw; pub mod tool; pub mod verbose; diff --git a/src/cli/args/quiet.rs b/src/cli/args/quiet.rs new file mode 100644 index 000000000..dc967f221 --- /dev/null +++ b/src/cli/args/quiet.rs @@ -0,0 +1,16 @@ +use clap::{Arg, ArgAction}; + +#[derive(Clone)] +pub struct Quiet; + +impl Quiet { + pub fn arg() -> Arg { + Arg::new("quiet") + .short('q') + .long("quiet") + .help("Suppress output") + .global(true) + .overrides_with("verbose") + .action(ArgAction::SetTrue) + } +} diff --git a/src/cli/args/verbose.rs b/src/cli/args/verbose.rs index 8ca0defc0..78c0cc839 100644 --- a/src/cli/args/verbose.rs +++ b/src/cli/args/verbose.rs @@ -8,8 +8,9 @@ impl Verbose { Arg::new("verbose") .short('v') .long("verbose") - .help("Show installation output") + .help("Show extra output (use -vv for even more)") .global(true) + .overrides_with("quiet") .action(ArgAction::Count) } } diff --git a/src/cli/install.rs b/src/cli/install.rs index df400fa47..a8bfc989d 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -43,7 +43,7 @@ impl Install { Ok(()) } fn install_runtimes(&self, mut config: Config, runtimes: &[ToolArg]) -> Result<()> { - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); let mut ts = ToolsetBuilder::new() .with_latest_versions() .build(&mut config)?; @@ -115,7 +115,7 @@ impl Install { info!("all runtimes are installed"); return Ok(()); } - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); ts.install_versions(&mut config, versions, &mpr, self.force)?; Ok(()) } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 22b991c74..fe57ab85d 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -190,6 +190,7 @@ impl Cli { .arg(args::log_level::Debug::arg()) .arg(args::log_level::LogLevel::arg()) .arg(args::log_level::Trace::arg()) + .arg(args::quiet::Quiet::arg()) .arg(args::raw::Raw::arg()) .arg(args::verbose::Verbose::arg()) .arg(args::yes::Yes::arg()), @@ -212,6 +213,9 @@ impl Cli { if let Some(true) = matches.get_one::("yes") { config.settings.yes = true; } + if let Some(true) = matches.get_one::("quiet") { + config.settings.quiet = true; + } if *matches.get_one::("verbose").unwrap() > 0 { config.settings.verbose = true; } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index ae4cf6aeb..1b79066e6 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -47,7 +47,7 @@ pub struct PluginsInstall { impl PluginsInstall { pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); if self.all { return self.install_all_missing_plugins(config, mpr); } diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index b1064312d..377a9be16 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -25,7 +25,7 @@ pub struct PluginsUninstall { impl PluginsUninstall { pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); let plugins = match self.all { true => config.plugins.keys().cloned().collect(), diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 983e40ff4..e86c89ccf 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -58,7 +58,7 @@ impl Prune { config: &Config, to_delete: Vec<(Arc, ToolVersion)>, ) -> Result<()> { - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); for (p, tv) in to_delete { let mut pr = mpr.add(); if self.dry_run { diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index b17f99b97..9f1ebc33e 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -80,7 +80,7 @@ impl Uninstall { .collect::>(); } - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); for (plugin, tv) in tool_versions { if !plugin.is_version_installed(&tv) { warn!("{} is not installed", style(&tv).cyan().for_stderr()); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 65816ebfb..9ba3aa6bb 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -52,7 +52,7 @@ impl Upgrade { } fn upgrade(&self, config: &mut Config, outdated: OutputVec, out: &mut Output) -> Result<()> { - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let new_versions = outdated diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index a36ae3fc4..f94053b3a 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -72,7 +72,7 @@ impl dyn ConfigFile { pin: bool, ) -> Result<()> { // TODO: this has become a complete mess and could probably be greatly simplified - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); let mut ts = self.to_toolset().to_owned(); ts.latest_versions = true; ts.resolve(config); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 908104eb1..f05f3ecb0 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -18,6 +18,7 @@ Ok( verbose: Some( true, ), + quiet: None, asdf_compat: None, jobs: None, shorthands_file: None, diff --git a/src/config/mod.rs b/src/config/mod.rs index 52045096f..8e72966d9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -145,10 +145,6 @@ impl Config { env::var("__RTX_DIFF").is_ok() } - pub fn show_progress_bars(&self) -> bool { - self.settings.verbose || !console::user_attended_stderr() - } - pub fn resolve_alias(&self, plugin_name: &str, v: &str) -> Result { if let Some(plugin_aliases) = self.aliases.get(plugin_name) { if let Some(alias) = plugin_aliases.get(v) { diff --git a/src/config/settings.rs b/src/config/settings.rs index 13a555a60..af157aba5 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -28,6 +28,8 @@ pub struct Settings { pub trusted_config_paths: BTreeSet, #[config(env = "RTX_VERBOSE", default = false)] pub verbose: bool, + #[config(env = "RTX_QUIET", default = false)] + pub quiet: bool, #[config(env = "RTX_ASDF_COMPAT", default = false)] pub asdf_compat: bool, #[config(env = "RTX_JOBS", default = 4)] diff --git a/src/env.rs b/src/env.rs index 859057f95..da2eb2c3e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -354,12 +354,15 @@ fn log_level() -> LevelFilter { set_var("RTX_LOG_LEVEL", level); } } - if arg == "--debug" { + if arg == "--debug" || arg == "--verbose" || (arg == "-v" && ARGS.len() > 1) { set_var("RTX_LOG_LEVEL", "debug"); } - if arg == "--trace" { + if arg == "--trace" || arg == "-vv" { set_var("RTX_LOG_LEVEL", "trace"); } + if arg == "--quiet" || arg == "-q" { + set_var("RTX_LOG_LEVEL", "warn"); + } } let log_level = var("RTX_LOG_LEVEL") .unwrap_or_default() diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index bed5e4a74..a50998d9a 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -490,7 +490,7 @@ impl Plugin for ExternalPlugin { } } } - let _mpr = MultiProgressReport::new(config.show_progress_bars()); + let _mpr = MultiProgressReport::new(&config.settings); let mpr = mpr.unwrap_or(&_mpr); let mut pr = mpr.add(); self.decorate_progress_bar(&mut pr, None); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 466f947b4..a31f4daea 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -84,7 +84,7 @@ impl Toolset { .for_each(|(_, v)| v.resolve(config, self.latest_versions)); } pub fn install_arg_versions(&mut self, config: &mut Config) -> Result<()> { - let mpr = MultiProgressReport::new(config.show_progress_bars()); + let mpr = MultiProgressReport::new(&config.settings); let versions = self .list_missing_versions(config) .into_iter() diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 0714c925c..a2790a25c 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,3 +1,4 @@ +use crate::config::Settings; use console::style; use indicatif::MultiProgress; @@ -6,25 +7,28 @@ use crate::ui::progress_report::ProgressReport; #[derive(Debug)] pub struct MultiProgressReport { mp: Option, + quiet: bool, } impl MultiProgressReport { - pub fn new(verbose: bool) -> Self { - match verbose { - true => Self { mp: None }, - false => Self { - mp: Some(MultiProgress::new()), - }, + pub fn new(settings: &Settings) -> Self { + let mp = match settings.quiet || settings.verbose || !console::user_attended_stderr() { + true => None, + false => Some(MultiProgress::new()), + }; + MultiProgressReport { + mp, + quiet: settings.quiet, } } pub fn add(&self) -> ProgressReport { match &self.mp { Some(mp) => { - let mut pr = ProgressReport::new(false); + let mut pr = ProgressReport::new(false, self.quiet); pr.pb = Some(mp.add(pr.pb.unwrap())); pr } - None => ProgressReport::new(true), + None => ProgressReport::new(true, self.quiet), } } pub fn suspend R, R>(&self, f: F) -> R { @@ -42,7 +46,8 @@ impl MultiProgressReport { message )); } - None => warn!("{}", message), + None if !self.quiet => warn!("{}", message), + _ => (), } } // pub fn clear(&self) { @@ -61,7 +66,8 @@ mod tests { #[test] fn test_multi_progress_report() { - let mpr = MultiProgressReport::new(false); + let settings = Settings::default(); + let mpr = MultiProgressReport::new(&settings); let pr = mpr.add(); pr.set_style(indicatif::ProgressStyle::with_template("").unwrap()); pr.enable_steady_tick(); diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index eec02ff7b..db1d05168 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -9,6 +9,7 @@ use once_cell::sync::Lazy; pub struct ProgressReport { pub pb: Option, prefix: String, + quiet: bool, } pub static PROG_TEMPLATE: Lazy = Lazy::new(|| { @@ -33,7 +34,7 @@ pub static ERROR_TEMPLATE: Lazy = Lazy::new(|| { }); impl ProgressReport { - pub fn new(verbose: bool) -> ProgressReport { + pub fn new(verbose: bool, quiet: bool) -> ProgressReport { let pb = match verbose { true => None, false => Some(ProgressBar::new(0)), @@ -41,6 +42,7 @@ impl ProgressReport { ProgressReport { pb, prefix: String::new(), + quiet, } } @@ -79,19 +81,22 @@ impl ProgressReport { pub fn set_message>(&self, message: S) { match &self.pb { Some(pb) => pb.set_message(message.as_ref().replace('\r', "")), - None => eprintln!("{}", message.as_ref()), + None if !self.quiet => eprintln!("{}", message.as_ref()), + _ => (), } } pub fn println>(&self, message: S) { match &self.pb { Some(pb) => pb.println(message), - None => eprintln!("{}", message.as_ref()), + None if !self.quiet => eprintln!("{}", message.as_ref()), + _ => (), } } pub fn warn>(&self, message: S) { match &self.pb { Some(pb) => pb.println(format!("{} {}", style("[WARN]").yellow(), message.as_ref())), - None => eprintln!("{}", message.as_ref()), + None if !self.quiet => eprintln!("{}", message.as_ref()), + _ => (), } } pub fn error>(&self, message: S) { @@ -123,7 +128,8 @@ impl ProgressReport { pb.set_style(SUCCESS_TEMPLATE.clone()); pb.finish_with_message(message); } - None => eprintln!("{}", message.into()), + None if !self.quiet => eprintln!("{}", message.into()), + _ => (), } } // pub fn clear(&self) { @@ -140,7 +146,7 @@ mod tests { #[test] fn test_progress_report() { - let mut pr = ProgressReport::new(false); + let mut pr = ProgressReport::new(false, false); pr.set_prefix("prefix"); assert_eq!(pr.prefix(), "prefix"); pr.set_message("message"); @@ -149,7 +155,7 @@ mod tests { #[test] fn test_progress_report_verbose() { - let mut pr = ProgressReport::new(true); + let mut pr = ProgressReport::new(true, false); pr.set_prefix("prefix"); assert_eq!(pr.prefix(), "prefix"); pr.set_message("message"); From 22c27ee6f504c84e87b1df4927dca8d294aae273 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 20:43:35 -0600 Subject: [PATCH 1264/1891] ls-remote: sort by plugin name (#1142) --- src/cli/ls_remote.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 20e98bb5a..ea2f90b41 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; +use itertools::Itertools; use rayon::prelude::*; use crate::cli::args::tool::ToolArg; @@ -74,7 +75,10 @@ impl LsRemote { let versions = p.list_remote_versions(&config.settings)?; Ok((p, versions)) }) - .collect::>>()?; + .collect::>>()? + .into_iter() + .sorted_by_cached_key(|(p, _)| p.name().to_string()) + .collect::>(); for (plugin, versions) in versions { for v in versions { rtxprintln!(out, "{}@{v}", plugin); From 0f7315924d9a69c0041f2c5517e357df639fcac3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 20:43:36 -0600 Subject: [PATCH 1265/1891] docker: added python3-full --- packaging/rtx/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packaging/rtx/Dockerfile b/packaging/rtx/Dockerfile index b2285479d..26f955917 100644 --- a/packaging/rtx/Dockerfile +++ b/packaging/rtx/Dockerfile @@ -20,7 +20,8 @@ RUN < Date: Mon, 11 Dec 2023 21:10:19 -0600 Subject: [PATCH 1266/1891] docs --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a6b321a14..4ca3cb990 100644 --- a/README.md +++ b/README.md @@ -787,7 +787,6 @@ disable_default_shorthands = false # disable the default shorthands, see `RTX_DI disable_tools = ['node'] # disable specific tools, generally used to turn off core tools experimental = false # enable experimental features -log_level = 'debug' # log verbosity, see `RTX_LOG_LEVEL` [alias.node] my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20.x @@ -844,6 +843,15 @@ development/staging/production environments. See [Config Environments](#experimental-config-environments) for more on how to use this feature. +#### `RTX_USE_VERSIONS_HOST` + +Default: `true` + +Set to "false" to disable using [rtx-versions](https://rtx-versions.jdx.dev) as +a quick way for rtx to query for new versions. This host regularly grabs all the +latest versions of core and community plugins. It's faster than running a plugin's +`list-all` command and gets around GitHub rate limiting problems when using it. + #### `RTX_${PLUGIN}_VERSION` Set the version for a runtime. For example, `RTX_NODE_VERSION=20` will use regardless @@ -903,6 +911,12 @@ This shows the installation output during `rtx install` and `rtx plugin install` This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have 2 configuration for the same thing, but for now it is its own config. +Equivalent to `RTX_LOG_LEVEL=debug`. + +#### `RTX_QUIET=1` + +Equivalent to `RTX_LOG_LEVEL=warn`. + #### `RTX_ASDF_COMPAT=1` Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. From afacb21c4d2fd217026f597dc50ad641b7666b75 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 21:22:59 -0600 Subject: [PATCH 1267/1891] test: fix erlang in test-plugins.yml --- .github/workflows/test-plugins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 2b100a217..aa39c5efd 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -92,7 +92,7 @@ jobs: command: rtx exec postgres@latest -- psql -V steps: - name: apt-get - run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl4-openssl-dev libgd-dev libonig-dev autoconf bison build-essential curl gettext git libgd-dev libcurl4-openssl-dev libedit-dev libicu-dev libjpeg-dev libmysqlclient-dev libonig-dev libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libxml2-dev libzip-dev openssl pkg-config re2c zlib1g-dev + run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl4-openssl-dev libgd-dev libonig-dev autoconf bison build-essential curl gettext git libgd-dev libcurl4-openssl-dev libedit-dev libicu-dev libjpeg-dev libmysqlclient-dev libonig-dev libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libxml2-dev libzip-dev openssl pkg-config re2c zlib1g-dev libwxgtk-webview3.0-gtk3-dev - uses: actions/download-artifact@v3 with: name: tarball-x86_64-unknown-linux-gnu From 904e4583c55ee02196673df44e0c293296c5309a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 21:46:03 -0600 Subject: [PATCH 1268/1891] docker: use rtx-provided python instead of ubuntu --- packaging/rtx/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rtx/Dockerfile b/packaging/rtx/Dockerfile index 26f955917..bdd12708a 100644 --- a/packaging/rtx/Dockerfile +++ b/packaging/rtx/Dockerfile @@ -25,7 +25,7 @@ apt-get update && apt-get install -y \ python3-pip rm -rf /var/lib/apt/lists/* && apt-get clean -ln -s ./python3 /usr/bin/python +rtx use -g python@latest rtx -v EOT From b0e668fa4f818151b1348d8df2f48b3251d1a5f7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 11 Dec 2023 21:46:15 -0600 Subject: [PATCH 1269/1891] python: logging --- src/plugins/core/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index beffc66b8..48d8f9724 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -179,7 +179,7 @@ impl Plugin for PythonPlugin { if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); } - ctx.pr.set_message("running python-build"); + ctx.pr.set_message("Running python-build"); let mut cmd = CmdLineRunner::new(&ctx.config.settings, self.python_build_bin()) .with_pr(&ctx.pr) .arg(ctx.tv.version.as_str()) 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 1270/1891] 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"), From ab3acf5830c423d666a5916c407f0604ad5909a5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:54:04 -0600 Subject: [PATCH 1271/1891] uninstall: tweak behavior (#1144) Fixes #1115 --- README.md | 8 +-- completions/rtx.bash | 2 +- e2e/test_nodejs | 2 +- src/cli/uninstall.rs | 124 +++++++++++++++++++++--------------- src/file.rs | 16 ++++- src/plugins/mod.rs | 6 ++ src/runtime_symlinks.rs | 4 +- src/toolset/tool_version.rs | 30 ++++++++- 8 files changed, 128 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 4ca3cb990..07561c16c 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ v20.0.0 - [`rtx sync node <--brew|--nvm|--nodenv>`](#rtx-sync-node---brew--nvm--nodenv) - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - - [`rtx uninstall [OPTIONS] ...`](#rtx-uninstall-options-toolversion) + - [`rtx uninstall [OPTIONS] [TOOL@VERSION]...`](#rtx-uninstall-options-toolversion) - [`rtx upgrade [OPTIONS] [TOOL@VERSION]...`](#rtx-upgrade-options-toolversion) - [`rtx use [OPTIONS] [TOOL@VERSION]...`](#rtx-use-options-toolversion) - [`rtx version`](#rtx-version) @@ -2630,15 +2630,15 @@ Examples: $ rtx trust ``` -### `rtx uninstall [OPTIONS] ...` +### `rtx uninstall [OPTIONS] [TOOL@VERSION]...` ```text Removes runtime versions -Usage: uninstall [OPTIONS] ... +Usage: uninstall [OPTIONS] [TOOL@VERSION]... Arguments: - ... + [TOOL@VERSION]... Tool(s) to remove Options: diff --git a/completions/rtx.bash b/completions/rtx.bash index c275b26a1..89744e55e 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3397,7 +3397,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-a -n -j -q -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help ..." + opts="-a -n -j -q -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/e2e/test_nodejs b/e2e/test_nodejs index bca296c08..e861976aa 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -30,7 +30,7 @@ rtx plugin uninstall nodejs RTX_DISABLE_TOOLS=node assert_not_contains "rtx plugins --core" "node" export RTX_NODE_BUILD=0 -rtx uninstall node +rtx uninstall -a node rtx i node assert "rtx x -- node --version" "v20.0.0" # rtx uninstall node diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index b20ab9a04..387ebbc65 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,9 +1,13 @@ use console::style; use eyre::{Result, WrapErr}; +use itertools::Itertools; +use rayon::prelude::*; +use std::sync::Arc; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::output::Output; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::{runtime_symlinks, shims}; @@ -13,11 +17,11 @@ use crate::{runtime_symlinks, shims}; #[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] pub struct Uninstall { /// Tool(s) to remove - #[clap(required = true, value_name = "TOOL@VERSION", value_parser = ToolArgParser)] + #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, required_unless_present = "all")] tool: Vec, /// Delete all installed versions - #[clap(long, short = 'a')] + #[clap(long, short)] all: bool, /// Do not actually delete anything @@ -27,57 +31,18 @@ pub struct Uninstall { impl Uninstall { pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { - let runtimes = ToolArg::double_tool_condition(&self.tool); - - let mut tool_versions = vec![]; - if self.all { - for runtime in runtimes { - let tool = config.get_or_create_plugin(&runtime.plugin); - let query = runtime.tvr.map(|tvr| tvr.version()).unwrap_or_default(); - let tvs = tool - .list_installed_versions()? - .into_iter() - .filter(|v| v.starts_with(&query)) - .map(|v| { - let tvr = ToolVersionRequest::new(tool.name().into(), &v); - let tv = ToolVersion::new(tool.clone(), tvr, Default::default(), v); - (tool.clone(), tv) - }) - .collect::>(); - if tvs.is_empty() { - warn!("no versions found for {}", style(&tool).cyan().for_stderr()); - } - tool_versions.extend(tvs); - } + let tool_versions = if self.tool.is_empty() && self.all { + self.get_all_tool_versions(&config)? } else { - tool_versions = runtimes - .into_iter() - .map(|a| { - let tool = config.get_or_create_plugin(&a.plugin); - let tvs = match a.tvr { - Some(tvr) => { - vec![tvr.resolve(&config, tool.clone(), Default::default(), false)?] - } - None => { - let ts = ToolsetBuilder::new().build(&config)?; - match ts.versions.get(&a.plugin) { - Some(tvl) => tvl.versions.clone(), - None => bail!( - "no versions found for {}", - style(&tool).cyan().for_stderr() - ), - } - } - }; - Ok(tvs - .into_iter() - .map(|tv| (tool.clone(), tv)) - .collect::>()) - }) - .collect::>>()? - .into_iter() - .flatten() - .collect::>(); + self.get_requested_tool_versions(&config)? + }; + let tool_versions = tool_versions + .into_iter() + .unique() + .sorted() + .collect::>(); + if !self.all && tool_versions.len() > 1 { + bail!("multiple tools specified, use --all to uninstall all versions"); } let mpr = MultiProgressReport::new(&config.settings); @@ -93,7 +58,11 @@ impl Uninstall { pr.error(err.to_string()); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); } - pr.finish_with_message("uninstalled"); + if self.dry_run { + pr.finish_with_message("uninstalled (dry-run)"); + } else { + pr.finish_with_message("uninstalled"); + } } let ts = ToolsetBuilder::new().build(&config)?; @@ -102,6 +71,55 @@ impl Uninstall { Ok(()) } + + fn get_all_tool_versions( + &self, + config: &Config, + ) -> Result, ToolVersion)>> { + let ts = ToolsetBuilder::new().build(config)?; + let tool_versions = ts + .list_installed_versions(config)? + .into_iter() + .collect::>(); + Ok(tool_versions) + } + fn get_requested_tool_versions( + &self, + config: &Config, + ) -> Result, ToolVersion)>> { + let runtimes = ToolArg::double_tool_condition(&self.tool); + let tool_versions = runtimes + .into_par_iter() + .map(|a| { + let tool = config.get_or_create_plugin(&a.plugin); + let query = a.tvr.as_ref().map(|tvr| tvr.version()).unwrap_or_default(); + let mut tvs = tool + .list_installed_versions()? + .into_iter() + .filter(|v| v.starts_with(&query)) + .map(|v| { + let tvr = ToolVersionRequest::new(tool.name().into(), &v); + let tv = ToolVersion::new(tool.clone(), tvr, Default::default(), v); + (tool.clone(), tv) + }) + .collect::>(); + if let Some(tvr) = &a.tvr { + tvs.push(( + tool.clone(), + tvr.resolve(config, tool.clone(), Default::default(), false)?, + )); + } + if tvs.is_empty() { + warn!("no versions found for {}", style(&tool).cyan().for_stderr()); + } + Ok(tvs) + }) + .collect::>>()? + .into_iter() + .flatten() + .collect::>(); + Ok(tool_versions) + } } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/file.rs b/src/file.rs index fa114ebe3..cb76ea442 100644 --- a/src/file.rs +++ b/src/file.rs @@ -36,8 +36,14 @@ pub fn remove_file>(path: P) -> Result<()> { pub fn remove_dir>(path: P) -> Result<()> { let path = path.as_ref(); - trace!("rmdir {}", display_path(path)); - fs::remove_dir(path).wrap_err_with(|| format!("failed rmdir: {}", display_path(path))) + (|| -> Result<()> { + if path.exists() && is_empty_dir(path)? { + trace!("rmdir {}", display_path(path)); + fs::remove_dir(path)?; + } + Ok(()) + })() + .wrap_err_with(|| format!("failed to remove_dir: {}", display_path(path))) } pub fn remove_all_with_warning>(path: P) -> Result<()> { @@ -207,6 +213,12 @@ pub fn make_executable(path: &Path) -> Result<()> { Ok(()) } +fn is_empty_dir(path: &Path) -> Result { + path.read_dir() + .map(|mut i| i.next().is_none()) + .wrap_err_with(|| format!("failed to read_dir: {}", display_path(path))) +} + pub struct FindUp { current_dir: PathBuf, current_dir_filenames: Vec, diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 2b5c3cb4c..19218e6bd 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Display}; use std::fs::File; +use std::hash::Hash; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -409,6 +410,11 @@ impl PartialEq for dyn Plugin { self.get_type() == other.get_type() && self.name() == other.name() } } +impl Hash for dyn Plugin { + fn hash(&self, state: &mut H) { + self.name().hash(state) + } +} impl PartialOrd for dyn Plugin { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 19e108c12..b52f946d3 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -30,8 +30,8 @@ pub fn rebuild(config: &Config) -> Result<()> { make_symlink(&to, &from)?; } remove_missing_symlinks(plugin.clone())?; - // attempt to remove the installs dir (will fail if not empty) - let _ = file::remove_dir(&installs_dir); + // remove install dir if empty + file::remove_dir(&installs_dir)?; } Ok(()) } diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index ee51a7bfc..b54521136 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -1,5 +1,7 @@ +use std::cmp::Ordering; use std::fmt::{Display, Formatter}; use std::fs; +use std::hash::{Hash, Hasher}; use std::path::PathBuf; use std::sync::Arc; @@ -13,7 +15,7 @@ use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; /// represents a single version of a tool for a particular plugin -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone)] pub struct ToolVersion { pub request: ToolVersionRequest, pub plugin_name: PluginName, @@ -244,6 +246,32 @@ impl Display for ToolVersion { } } +impl PartialEq for ToolVersion { + fn eq(&self, other: &Self) -> bool { + self.plugin_name == other.plugin_name && self.version == other.version + } +} +impl Eq for ToolVersion {} +impl PartialOrd for ToolVersion { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for ToolVersion { + fn cmp(&self, other: &Self) -> Ordering { + match self.plugin_name.cmp(&other.plugin_name) { + Ordering::Equal => self.version.cmp(&other.version), + o => o, + } + } +} +impl Hash for ToolVersion { + fn hash(&self, state: &mut H) { + self.plugin_name.hash(state); + self.version.hash(state); + } +} + /// subtracts sub from orig and removes suffix /// e.g. version_sub("18.2.3", "2") -> "16" /// e.g. version_sub("18.2.3", "0.1") -> "18.1" From 1449e7c114896a35cd9fc88d9d2397dd314b8ef2 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 15:07:14 -0600 Subject: [PATCH 1272/1891] CI: remove nightly toolchain (#1145) --- .github/workflows/rtx.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 9f618ea29..4d3f20bb4 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -66,17 +66,19 @@ jobs: with: fetch-depth: 0 - - run: rustup toolchain install nightly --component llvm-tools-preview + #- run: rustup toolchain install nightly --component llvm-tools-preview --profile minimal - uses: Swatinem/rust-cache@v2 with: shared-key: coverage save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} cache-all-crates: true - - uses: taiki-e/install-action@cargo-llvm-cov - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - run: npm i -g markdown-magic - - uses: taiki-e/install-action@just - - uses: nick-fields/retry@v2 + - uses: taiki-e/install-action@v2 + with: + tool: cargo-llvm-cov,just + - name: Test w/ coverage + uses: nick-fields/retry@v2 env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" From ea402cd563f2bb6f9c69156ae23355089d169c71 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 15:08:34 -0600 Subject: [PATCH 1273/1891] chore: Release rtx-cli version 2023.12.24 --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e7a4984f..8917ea6e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -455,9 +455,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" +checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", "syn 2.0.40", @@ -683,9 +683,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.10" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbb8258be8305fb0237d7b295f47bb24ff1b136a535f473baf40e70468515aa" +checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" dependencies = [ "indenter", "once_cell", @@ -1792,7 +1792,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.23" +version = "2023.12.24" dependencies = [ "base64", "built", @@ -3062,9 +3062,9 @@ dependencies = [ [[package]] name = "xattr" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d367426ae76bdfce3d8eaea6e94422afd6def7d46f9c89e2980309115b3c2c41" +checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995" dependencies = [ "libc", "linux-raw-sys", diff --git a/Cargo.toml b/Cargo.toml index 90a3c9c4a..ab0103ee1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.23" +version = "2023.12.24" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 07561c16c..025cfe8bd 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.23 +rtx 2023.12.24 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.23/rtx-v2023.12.23-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.24/rtx-v2023.12.24-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index a7417cad1..9d4739340 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.23"; + version = "2023.12.24"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9c52602d8..82a06ec4c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.23 +Version: 2023.12.24 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 4f23c852ed77738815e8653fe938618a7476640c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 15:09:31 -0600 Subject: [PATCH 1274/1891] plugin: skip eager loading of plugin data when installing (#1146) --- src/plugins/external_plugin.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 5440cc8ea..71fcf3326 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -117,19 +117,6 @@ impl ExternalPlugin { git.update(Some(ref_.to_string()))?; } - pr.set_message("loading plugin remote versions"); - if self.has_list_all_script() { - self.list_remote_versions(&config.settings)?; - } - if self.has_list_alias_script() { - pr.set_message("getting plugin aliases"); - self.get_aliases(&config.settings)?; - } - if self.has_list_legacy_filenames_script() { - pr.set_message("getting plugin legacy filenames"); - self.legacy_filenames(&config.settings)?; - } - let sha = git.current_sha_short()?; pr.finish_with_message(format!( "{repo_url}#{}", @@ -231,9 +218,6 @@ impl ExternalPlugin { }) } - fn has_list_all_script(&self) -> bool { - self.script_man.script_exists(&Script::ListAll) - } fn has_list_alias_script(&self) -> bool { self.script_man.script_exists(&Script::ListAliases) } From ebd675f08f20ebf086ef7fa54462ffaceb719bed Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:16:52 -0600 Subject: [PATCH 1275/1891] CI: wait for release before bumping homebrew --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ebe36e93..fcab0a7da 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -237,6 +237,7 @@ jobs: bump-homebrew-formula: runs-on: macos-latest timeout-minutes: 10 + needs: [release] continue-on-error: true if: startsWith(github.event.ref, 'refs/tags/v') steps: From b88674161a574cc1865ada7743a96b9d3e927330 Mon Sep 17 00:00:00 2001 From: rtx-vm <123107610+rtx-vm@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:36:55 -0600 Subject: [PATCH 1276/1891] arch: error if not able to get sha --- scripts/release-aur-bin.sh | 3 ++- scripts/release-aur.sh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index b470c8e6a..e2b1bfe5f 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -8,7 +8,7 @@ RTX_VERSION=$(./scripts/get-version.sh) TAR_GZ_URI="https://github.com/jdx/rtx/releases/download/$RTX_VERSION/rtx-$RTX_VERSION-linux-x64.tar.gz" -SHA512=$(curl -L "$TAR_GZ_URI" | sha512sum | awk '{print $1}') +SHA512=$(curl -fsSL "$TAR_GZ_URI" | sha512sum | awk '{print $1}') if [ ! -d aur-bin ]; then git clone ssh://aur@aur.archlinux.org/rtx-bin.git aur-bin @@ -74,6 +74,7 @@ if git diff-index --quiet HEAD --; then echo "No changes to PKGBUILD or .SRCINFO" exit 0 fi +git diff --cached git commit -m "rtx ${RTX_VERSION#v}" if [[ "$DRY_RUN" == 0 ]]; then git push diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 7917de26a..82ed3d7ac 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -6,7 +6,7 @@ git config --global user.email 123107610+rtx-vm@users.noreply.github.com RTX_VERSION=$(./scripts/get-version.sh) -SHA512=$(curl -L "https://github.com/jdx/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') +SHA512=$(curl -fsSL "https://github.com/jdx/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') if [ ! -d aur ]; then git clone ssh://aur@aur.archlinux.org/rtx.git aur @@ -80,6 +80,7 @@ if git diff-index --quiet HEAD --; then echo "No changes to PKGBUILD or .SRCINFO" exit 0 fi +git diff --cached git commit -m "rtx ${RTX_VERSION#v}" if [ "$DRY_RUN" == 0 ]; then git push From 784d1530cf30231afa75610fcd557e04c0f7db7b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:39:46 -0600 Subject: [PATCH 1277/1891] arch: set local gitconfig --- scripts/release-aur-bin.sh | 5 ++--- scripts/release-aur.sh | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index e2b1bfe5f..c5edf9999 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -1,9 +1,6 @@ #!/usr/bin/env bash set -euxo pipefail -git config --global user.name rtx-vm -git config --global user.email 123107610+rtx-vm@users.noreply.github.com - RTX_VERSION=$(./scripts/get-version.sh) TAR_GZ_URI="https://github.com/jdx/rtx/releases/download/$RTX_VERSION/rtx-$RTX_VERSION-linux-x64.tar.gz" @@ -69,6 +66,8 @@ pkgname = rtx-bin EOF cd aur-bin +git config user.name rtx-vm +git config user.email 123107610+rtx-vm@users.noreply.github.com git add .SRCINFO PKGBUILD if git diff-index --quiet HEAD --; then echo "No changes to PKGBUILD or .SRCINFO" diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 82ed3d7ac..46ec76c2c 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -1,9 +1,6 @@ #!/usr/bin/env bash set -euxo pipefail -git config --global user.name rtx-vm -git config --global user.email 123107610+rtx-vm@users.noreply.github.com - RTX_VERSION=$(./scripts/get-version.sh) SHA512=$(curl -fsSL "https://github.com/jdx/rtx/archive/$RTX_VERSION.tar.gz" | sha512sum | awk '{print $1}') @@ -75,6 +72,8 @@ pkgname = rtx EOF cd aur +git config user.name rtx-vm +git config user.email 123107610+rtx-vm@users.noreply.github.com git add .SRCINFO PKGBUILD if git diff-index --quiet HEAD --; then echo "No changes to PKGBUILD or .SRCINFO" From 9160c4facffafd26bee4e94fe726316d07c1e4e5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 18:45:53 -0600 Subject: [PATCH 1278/1891] hook-env: keep prepended PATH entries in front (#1150) With this change, if you manually run PATH="/foo:$PATH" in your shell after activating rtx, rtx will keep "/foo" in front of its own PATH entries. Fixes #863 --- e2e/cd/test_bash | 7 ++++++- src/cli/hook_env.rs | 16 +++++++++++++--- src/env.rs | 1 + src/shell/bash.rs | 1 + src/shell/fish.rs | 1 + .../rtx__shell__bash__tests__hook_init.snap | 1 + .../rtx__shell__bash__tests__hook_init_nix.snap | 1 + .../rtx__shell__fish__tests__hook_init.snap | 1 + .../rtx__shell__fish__tests__hook_init_nix.snap | 1 + .../rtx__shell__zsh__tests__hook_init.snap | 1 + .../rtx__shell__zsh__tests__hook_init_nix.snap | 1 + src/shell/zsh.rs | 1 + 12 files changed, 29 insertions(+), 4 deletions(-) diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index afc70ca4d..60b827f76 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -43,8 +43,13 @@ cd .. && _rtx_hook test "$(node -v)" = "v20.0.0" assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +export PATH="PRE:$PATH" +cd 18 && _rtx_hook +test "$(node -v)" = "v18.0.0" +assert_path "PRE:/root:ROOT/e2e/cwd:INSTALLS/node/18.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" + rtx shell node@18.0.0 && _rtx_hook test "$(node -v)" = "v18.0.0" rtx deactivate -assert_path "" +assert_path "PRE" diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 817c8689e..defd7bc36 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -90,9 +90,19 @@ impl HookEnv { installs: &Vec, to_remove: &Vec, ) -> Result> { - let new_path = join_paths([installs.clone(), env::PATH.clone()].concat())? - .to_string_lossy() - .to_string(); + let full = join_paths(&*env::PATH)?.to_string_lossy().to_string(); + let (pre, post) = match &*env::__RTX_ORIG_PATH { + Some(orig_path) => match full.split_once(&format!(":{orig_path}")) { + Some((pre, post)) => (pre.to_string(), (orig_path.to_string() + post)), + None => (String::new(), full), + }, + None => (String::new(), full), + }; + let install_path = join_paths(installs)?.to_string_lossy().to_string(); + let new_path = vec![pre, install_path, post] + .into_iter() + .filter(|p| !p.is_empty()) + .join(":"); let mut ops = vec![EnvDiffOperation::Add("PATH".into(), new_path)]; if let Some(input) = env::DIRENV_DIFF.deref() { diff --git a/src/env.rs b/src/env.rs index da2eb2c3e..fa8e3c8f1 100644 --- a/src/env.rs +++ b/src/env.rs @@ -67,6 +67,7 @@ pub static RTX_FETCH_REMOTE_VERSIONS_CACHE: Lazy> = Lazy::new(| /// used to prevent infinite loops pub static __RTX_SCRIPT: Lazy = Lazy::new(|| var_is_true("__RTX_SCRIPT")); pub static __RTX_DIFF: Lazy = Lazy::new(get_env_diff); +pub static __RTX_ORIG_PATH: Lazy> = Lazy::new(|| var("__RTX_ORIG_PATH").ok()); pub static CI: Lazy = Lazy::new(|| var_is_true("CI")); pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS)); /// essentially, this is whether we show spinners or build output on runtime install diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 674ea8385..6b116be8d 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -15,6 +15,7 @@ impl Shell for Bash { } out.push_str(&formatdoc! {r#" export RTX_SHELL=bash + export __RTX_ORIG_PATH="$PATH" rtx() {{ local command diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 9c69acbd0..a1e616acc 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -20,6 +20,7 @@ impl Shell for Fish { // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_fish.go#L14-L36 out.push_str(&formatdoc! {r#" set -gx RTX_SHELL fish + set -gx __RTX_ORIG_PATH $PATH function rtx if test (count $argv) -eq 0 diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index cdd27d924..fab0399f5 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -4,6 +4,7 @@ expression: "bash.activate(exe, true)" --- export PATH="/some/dir:$PATH" export RTX_SHELL=bash +export __RTX_ORIG_PATH="$PATH" rtx() { local command diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index 9e555f3cd..81c47d461 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -3,6 +3,7 @@ source: src/shell/bash.rs expression: "bash.activate(exe, true)" --- export RTX_SHELL=bash +export __RTX_ORIG_PATH="$PATH" rtx() { local command diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index a9dfcd5be..85c54a5a9 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -4,6 +4,7 @@ expression: "fish.activate(exe, true)" --- fish_add_path -g /some/dir set -gx RTX_SHELL fish +set -gx __RTX_ORIG_PATH $PATH function rtx if test (count $argv) -eq 0 diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap index 4a02b4967..662c282c3 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap @@ -3,6 +3,7 @@ source: src/shell/fish.rs expression: "fish.activate(exe, true)" --- set -gx RTX_SHELL fish +set -gx __RTX_ORIG_PATH $PATH function rtx if test (count $argv) -eq 0 diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index c6ebdde60..b01fd8338 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -4,6 +4,7 @@ expression: "zsh.activate(exe, true)" --- export PATH="/some/dir:$PATH" export RTX_SHELL=zsh +export __RTX_ORIG_PATH="$PATH" rtx() { local command diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap index f1218f4b4..21055d9dc 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -3,6 +3,7 @@ source: src/shell/zsh.rs expression: "zsh.activate(exe, true)" --- export RTX_SHELL=zsh +export __RTX_ORIG_PATH="$PATH" rtx() { local command diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index cd0b50ed2..4dbff4ff4 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -19,6 +19,7 @@ impl Shell for Zsh { } out.push_str(&formatdoc! {r#" export RTX_SHELL=zsh + export __RTX_ORIG_PATH="$PATH" rtx() {{ local command From 6c80436d3caa577f634e853a4ebe07847a39a57d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 22:30:29 -0600 Subject: [PATCH 1279/1891] erlang core plugin (#1151) --- .github/workflows/test-plugins.yml | 8 +- e2e/test_erlang | 8 ++ src/plugins/core/erlang.rs | 121 +++++++++++++++++++++++++++++ src/plugins/core/mod.rs | 9 ++- 4 files changed, 141 insertions(+), 5 deletions(-) create mode 100755 e2e/test_erlang create mode 100644 src/plugins/core/erlang.rs diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index aa39c5efd..155dd7964 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -54,12 +54,12 @@ jobs: - plugin: direnv command: rtx exec direnv@latest -- direnv --version - plugin: erlang - command: rtx exec erlang@latest -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell + command: rtx exec erlang@24.3.4.9 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell - plugin: elixir command: | - rtx use --global erlang@latest + rtx use --global erlang@24.3.4.9 eval "$(rtx env bash)" - rtx use --global elixir@latest + rtx use --global elixir@main-otp-24 eval "$(rtx env bash)" rtx exec -- elixir --version - plugin: golang @@ -109,6 +109,8 @@ jobs: max_attempts: 3 retry_wait_seconds: 30 command: ${{matrix.command}} + env: + RTX_EXPERIMENTAL: "1" test-install: # Tests installing the top 50 plugins not already tested in `test-install-and-run`. # installing is a better-than-nothing smoke test that the plugin is correctly implemented diff --git a/e2e/test_erlang b/e2e/test_erlang new file mode 100755 index 000000000..345ef35ab --- /dev/null +++ b/e2e/test_erlang @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +export RTX_EXPERIMENTAL=1 + +assert_contains "rtx x erlang@24.3.4.9 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell" "24" diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs new file mode 100644 index 000000000..4cdd54769 --- /dev/null +++ b/src/plugins/core/erlang.rs @@ -0,0 +1,121 @@ +use std::path::PathBuf; + +use color_eyre::eyre::Result; + +use crate::config::Settings; + +use crate::file::display_path; +use crate::install_context::InstallContext; +use crate::lock_file::LockFile; +use crate::plugins::core::CorePlugin; +use crate::plugins::{Plugin, HTTP}; +use crate::toolset::ToolVersionRequest; +use crate::{cmd, file}; + +#[derive(Debug)] +pub struct ErlangPlugin { + core: CorePlugin, +} + +const KERL_VERSION: &str = "4.0.0"; + +impl ErlangPlugin { + pub fn new() -> Self { + Self { + core: CorePlugin::new("erlang"), + } + } + + fn kerl_path(&self) -> PathBuf { + self.core.cache_path.join(format!("kerl-{}", KERL_VERSION)) + } + + fn lock_build_tool(&self) -> Result { + LockFile::new(&self.kerl_path()) + .with_callback(|l| { + trace!("install_or_update_kerl {}", l.display()); + }) + .lock() + } + + fn update_kerl(&self) -> Result<()> { + let _lock = self.lock_build_tool(); + if self.kerl_path().exists() { + return Ok(()); + } + self.install_kerl()?; + cmd!(self.kerl_path(), "update", "releases") + .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) + .run()?; + Ok(()) + } + + fn install_kerl(&self) -> Result<()> { + debug!("Installing kerl to {}", display_path(&self.kerl_path())); + HTTP.download_file( + format!("https://raw.githubusercontent.com/kerl/kerl/{KERL_VERSION}/kerl"), + &self.kerl_path(), + )?; + file::make_executable(&self.kerl_path())?; + Ok(()) + } + + fn fetch_remote_versions(&self) -> Result> { + match self.core.fetch_remote_versions_from_rtx() { + Ok(Some(versions)) => return Ok(versions), + Ok(None) => {} + Err(e) => warn!("failed to fetch remote versions: {}", e), + } + self.update_kerl()?; + let versions = CorePlugin::run_fetch_task_with_timeout(move || { + let output = cmd!(self.kerl_path(), "list", "releases", "all") + .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) + .read()?; + let versions = output + .split('\n') + .filter(|s| regex!(r"^[0-9].+$").is_match(s)) + .map(|s| s.to_string()) + .collect(); + Ok(versions) + })?; + Ok(versions) + } +} + +impl Plugin for ErlangPlugin { + fn name(&self) -> &str { + self.core.name + } + + fn list_remote_versions(&self, _settings: &Settings) -> Result> { + self.core + .remote_version_cache + .get_or_try_init(|| self.fetch_remote_versions()) + .cloned() + } + + fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { + self.update_kerl()?; + + file::remove_all(ctx.tv.install_path())?; + match &ctx.tv.request { + ToolVersionRequest::Ref(..) => { + unimplemented!("erlang does not yet support refs"); + } + ToolVersionRequest::Version(..) => { + cmd!( + self.kerl_path(), + "build-install", + &ctx.tv.version, + &ctx.tv.version, + ctx.tv.install_path() + ) + .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) + .run()?; + } + _ => unimplemented!(), + } + + Ok(()) + } +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 8d7a79d4b..f0d890bc1 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -14,6 +14,7 @@ use crate::cache::CacheManager; use crate::env::RTX_NODE_BUILD; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; +use crate::plugins::core::erlang::ErlangPlugin; use crate::plugins::core::go::GoPlugin; use crate::plugins::core::java::JavaPlugin; use crate::plugins::core::node::NodePlugin; @@ -26,6 +27,7 @@ use crate::{dirs, env}; mod bun; mod deno; +mod erlang; mod go; mod java; mod node; @@ -54,8 +56,11 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { }); pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { - let plugins: Vec> = - vec![Arc::new(BunPlugin::new()), Arc::new(DenoPlugin::new())]; + let plugins: Vec> = vec![ + Arc::new(BunPlugin::new()), + Arc::new(DenoPlugin::new()), + Arc::new(ErlangPlugin::new()), + ]; plugins .into_iter() .map(|plugin| (plugin.name().to_string(), plugin)) From c2623f7c7e78cd8fe60267dea17024d78ebce426 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 22:46:45 -0600 Subject: [PATCH 1280/1891] deno|bun: make non-experimental (#1152) --- README.md | 4 ++-- src/plugins/core/mod.rs | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 025cfe8bd..a3f6f48d3 100644 --- a/README.md +++ b/README.md @@ -1213,8 +1213,8 @@ You can see the core plugins with `rtx plugin ls --core`. - [Ruby](./docs/ruby.md) - [Go](./docs/go.md) - [Java](./docs/java.md) -- [Deno (experimental)](./docs/deno.md) -- [Bun (experimental)](./docs/bun.md) +- [Deno](./docs/deno.md) +- [Bun](./docs/bun.md) ## FAQs diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index f0d890bc1..74c0dbdd3 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -39,6 +39,8 @@ pub type PluginMap = BTreeMap>; pub static CORE_PLUGINS: Lazy = Lazy::new(|| { let plugins: Vec> = vec![ + Arc::new(BunPlugin::new()), + Arc::new(DenoPlugin::new()), Arc::new(GoPlugin::new()), Arc::new(JavaPlugin::new()), if *RTX_NODE_BUILD == Some(true) { @@ -56,11 +58,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { }); pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { - let plugins: Vec> = vec![ - Arc::new(BunPlugin::new()), - Arc::new(DenoPlugin::new()), - Arc::new(ErlangPlugin::new()), - ]; + let plugins: Vec> = vec![Arc::new(ErlangPlugin::new())]; plugins .into_iter() .map(|plugin| (plugin.name().to_string(), plugin)) From 8019ce13b3381ff0c2b1f71920f631f1c7528be5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 23:06:14 -0600 Subject: [PATCH 1281/1891] config-environments: make non-experimental (#1153) * config-environments: make non-experimental * config-environments: make non-experimental --- README.md | 19 +++++++------------ completions/_rtx | 2 +- completions/rtx.fish | 2 +- src/cli/use.rs | 2 +- src/config/mod.rs | 15 ++++----------- 5 files changed, 14 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index a3f6f48d3..74e86281c 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ v20.0.0 - [`~/.cache/rtx`](#cachertx) - [`~/.local/share/rtx`](#localsharertx) - [Templates](#templates) -- [[experimental] Config Environments](#experimental-config-environments) +- [Config Environments](#config-environments) - [IDE Integration](#ide-integration) - [Core Plugins](#core-plugins) - [FAQs](#faqs) @@ -611,7 +611,7 @@ Then when inside of `~/src/myproj/backend`, `node` will be `18`, `python` will b will be `3.1`. You can check the active versions with `rtx ls --current`. You can also have environment specific config files like `.rtx.production.toml`, see -[Config Environments](#experimental-config-environments) for more details. +[Config Environments](#config-environments) for more details. #### `[env]` - Arbitrary Environment Variables @@ -835,12 +835,12 @@ a different name. Set to something other than `.rtx.toml` to have rtx look for `.rtx.toml` config files with a different name. -#### [experimental] `RTX_ENV` +#### `RTX_ENV` Enables environment-specific config files such as `.rtx.development.toml`. Use this for different env vars or different tool versions in development/staging/production environments. See -[Config Environments](#experimental-config-environments) for more on how +[Config Environments](#config-environments) for more on how to use this feature. #### `RTX_USE_VERSIONS_HOST` @@ -1123,10 +1123,6 @@ does not work for some reason. ## Templates -> **Warning** -> -> This functionality is experimental and may change in the future. - Templates are used in the following locations: - `.tool-versions` files @@ -1157,11 +1153,10 @@ Here's another using `exec()`: current = "{{exec(command='node --version')}}" ``` -## [experimental] Config Environments +## Config Environments It's possible to have separate `.rtx.toml` files in the same directory for different -environments like `development` and `production`. To enable, set -`experimental = true` in `~/.config/rtx/config.toml`, then set `RTX_ENV` to an environment like +environments like `development` and `production`. To enable, set `RTX_ENV` to an environment like `development` or `production`. rtx will then look for a `.rtx.{RTX_ENV}.toml` file in the current directory. rtx will also look for "local" files like `.rtx.local.toml` and `.rtx.{RTX_ENV}.local.toml` in @@ -2709,7 +2704,7 @@ Options: Use the global config file (~/.config/rtx/config.toml) instead of the local one -e, --env - [experimental] Modify an environment-specific config file like .rtx..toml + Modify an environment-specific config file like .rtx..toml -p, --path Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions diff --git a/completions/_rtx b/completions/_rtx index 64dbc6294..13940684a 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -736,7 +736,7 @@ __rtx_use_cmd() { '--fuzzy[Save fuzzy version to config file]' \ '*--remove=[Remove the tool(s) from config file]:remove:' \ '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ - '(-e --env)'{-e,--env}'=[\[experimental\] Modify an environment-specific config file like .rtx..toml]:env:' \ + '(-e --env)'{-e,--env}'=[Modify an environment-specific config file like .rtx..toml]:env:' \ '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ diff --git a/completions/rtx.fish b/completions/rtx.fish index ac6a6f3d1..fb17426ad 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -255,7 +255,7 @@ complete -xc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be complete -xc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' # use -complete -xc rtx -n "$fssf use" -s e -l env -d '[experimental] Modify an environment-specific config file like .rtx..toml' +complete -xc rtx -n "$fssf use" -s e -l env -d 'Modify an environment-specific config file like .rtx..toml' complete -xc rtx -n "$fssf use" -l fuzzy -d 'Save fuzzy version to config file' complete -xc rtx -n "$fssf use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' complete -xc rtx -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' diff --git a/src/cli/use.rs b/src/cli/use.rs index 96fee8f1b..22b6f357c 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -53,7 +53,7 @@ pub struct Use { #[clap(short, long, overrides_with_all = &["path", "env"])] global: bool, - /// [experimental] Modify an environment-specific config file like .rtx..toml + /// Modify an environment-specific config file like .rtx..toml #[clap(long, short, overrides_with_all = &["global", "path"])] env: Option, diff --git a/src/config/mod.rs b/src/config/mod.rs index 720e058fb..db7ee6eb7 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -52,10 +52,10 @@ pub struct Config { impl Config { pub fn load() -> Result { let global_config = load_rtxrc()?; + let config_filenames = load_config_filenames(&BTreeMap::new()); let settings = Settings::default_builder() .preloaded(global_config.settings()?) .load()?; - let config_filenames = load_config_filenames(&settings, &BTreeMap::new()); let plugins = load_plugins(&settings)?; let config_files = load_all_config_files( &settings, @@ -72,7 +72,7 @@ impl Config { trace!("Settings: {:#?}", settings); let legacy_files = load_legacy_files(&settings, &plugins); - let config_filenames = load_config_filenames(&settings, &legacy_files); + let config_filenames = load_config_filenames(&legacy_files); let config_track = track_config_files(&config_filenames); let config_files = load_all_config_files( @@ -99,10 +99,6 @@ impl Config { let (env, env_sources) = load_env(&config_files); - if !settings.experimental && env::RTX_ENV.is_some() { - warn!("RTX_ENV is set but RTX_EXPERIMENTAL is not. Ignoring RTX_ENV."); - } - let config = Self { env, env_sources, @@ -330,14 +326,11 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap>, -) -> Vec { +fn load_config_filenames(legacy_filenames: &BTreeMap>) -> Vec { let mut filenames = legacy_filenames.keys().cloned().collect_vec(); filenames.push(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone()); filenames.push(env::RTX_DEFAULT_CONFIG_FILENAME.clone()); - if settings.experimental && *env::RTX_DEFAULT_CONFIG_FILENAME == ".rtx.toml" { + if *env::RTX_DEFAULT_CONFIG_FILENAME == ".rtx.toml" { filenames.push(".rtx.local.toml".to_string()); if let Some(env) = &*env::RTX_ENV { filenames.push(format!(".rtx.{}.toml", env)); From 743321d7a7062ab1e4f5627d85ac6347fcc2a764 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 23:18:33 -0600 Subject: [PATCH 1282/1891] python: update python-build if needed (#1154) --- src/plugins/core/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 48d8f9724..f41a8037b 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -175,7 +175,7 @@ impl Plugin for PythonPlugin { } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { - self.install_python_build()?; + self.install_or_update_python_build()?; if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); } From 52306a5baa6093a7f7fed76704e3ad220751f11d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 00:52:34 -0600 Subject: [PATCH 1283/1891] hook-env: use new non-aggressive PATH logic only in experimental mode (#1155) --- e2e/cd/test_bash | 1 + src/cli/hook_env.rs | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 60b827f76..131c2ab28 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -2,6 +2,7 @@ # shellcheck disable=SC2088 set -euo pipefail +export RTX_EXPERIMENTAL=1 orig_path="$PATH" # shellcheck disable=SC1090 diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index defd7bc36..7df80c107 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -10,6 +10,7 @@ use terminal_size::{terminal_size, Width}; use crate::config::Config; +use crate::config::Settings; use crate::direnv::DirenvDiff; use crate::env::__RTX_DIFF; use crate::env_diff::{EnvDiff, EnvDiffOperation}; @@ -48,7 +49,7 @@ impl HookEnv { paths.extend(ts.list_paths(&config)); // load the active runtime paths diff.path = paths.clone(); // update __RTX_DIFF with the new paths for the next run - patches.extend(self.build_path_operations(&paths, &__RTX_DIFF.path)?); + patches.extend(self.build_path_operations(&config.settings, &paths, &__RTX_DIFF.path)?); patches.push(self.build_diff_operation(&diff)?); patches.push(self.build_watch_operation(&config)?); @@ -87,14 +88,17 @@ impl HookEnv { /// modifies the PATH and optionally DIRENV_DIFF env var if it exists fn build_path_operations( &self, + settings: &Settings, installs: &Vec, to_remove: &Vec, ) -> Result> { let full = join_paths(&*env::PATH)?.to_string_lossy().to_string(); let (pre, post) = match &*env::__RTX_ORIG_PATH { Some(orig_path) => match full.split_once(&format!(":{orig_path}")) { - Some((pre, post)) => (pre.to_string(), (orig_path.to_string() + post)), - None => (String::new(), full), + Some((pre, post)) if settings.experimental => { + (pre.to_string(), (orig_path.to_string() + post)) + } + _ => (String::new(), full), }, None => (String::new(), full), }; From e1f4173174fd27c15888592ee520a52657d72a54 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 00:54:05 -0600 Subject: [PATCH 1284/1891] chore: Release rtx-cli version 2023.12.25 --- Cargo.lock | 24 ++++++++++++------------ Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8917ea6e9..bda0a9390 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,7 +262,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", ] [[package]] @@ -460,7 +460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.40", + "syn 2.0.41", ] [[package]] @@ -498,7 +498,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", ] [[package]] @@ -1402,7 +1402,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", ] [[package]] @@ -1500,7 +1500,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", ] [[package]] @@ -1792,7 +1792,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.24" +version = "2023.12.25" dependencies = [ "base64", "built", @@ -2045,7 +2045,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", ] [[package]] @@ -2219,9 +2219,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.40" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -2335,7 +2335,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", ] [[package]] @@ -2729,7 +2729,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", "wasm-bindgen-shared", ] @@ -2763,7 +2763,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.40", + "syn 2.0.41", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index ab0103ee1..654562b05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.24" +version = "2023.12.25" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 74e86281c..07257d76d 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.24 +rtx 2023.12.25 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.24/rtx-v2023.12.24-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.25/rtx-v2023.12.25-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 9d4739340..48dc3429a 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.24"; + version = "2023.12.25"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 82a06ec4c..c3f4ab580 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.24 +Version: 2023.12.25 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From d2b8404708a76226ba8eeedaa2b716e5d58e7f55 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 01:17:33 -0600 Subject: [PATCH 1285/1891] CI: set aur-bin to depend on release --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcab0a7da..c0929f6f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -264,7 +264,7 @@ jobs: bump-aur-bin: runs-on: ubuntu-22.04 timeout-minutes: 30 - needs: [e2e-linux] + needs: [release] steps: - name: Checkout repository uses: actions/checkout@v4 From 907f17d48e618b91b845bfdc3722297a5cef1684 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:26:08 -0600 Subject: [PATCH 1286/1891] use cache directory for incomplete marker this was here originally but was mistakenly moved during a refactor Fixes #1156 --- src/plugins/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 19218e6bd..a86c31f8d 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -344,7 +344,7 @@ pub trait Plugin: Debug + Send + Sync { } fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("incomplete") + tv.cache_path().join("incomplete") } } From 476ad2c7183eb370cd0b06181dd80fefeb5ae700 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:33:29 -0600 Subject: [PATCH 1287/1891] disable idea spellchecking --- .idea/inspectionProfiles/Project_Default.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 7a8cf6a2c..780774c70 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -37,5 +37,10 @@ + + \ No newline at end of file From cb874c666326be67b679a002a79bce35d7531bd7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:45:07 -0600 Subject: [PATCH 1288/1891] erlang: allow non-version prefixes (#1160) Fixes #1157 --- src/plugins/core/erlang.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 4cdd54769..02aa0dddb 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -102,7 +102,7 @@ impl Plugin for ErlangPlugin { ToolVersionRequest::Ref(..) => { unimplemented!("erlang does not yet support refs"); } - ToolVersionRequest::Version(..) => { + _ => { cmd!( self.kerl_path(), "build-install", @@ -113,7 +113,6 @@ impl Plugin for ErlangPlugin { .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) .run()?; } - _ => unimplemented!(), } Ok(()) From 09dfd034142836e1648a875fdee64bf9b96c966b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 14:03:55 -0600 Subject: [PATCH 1289/1891] python: show regular cpython versions last (#1162) Fits convention in other plugins and makes it so they are what you see and not hard to find towards the start --- src/plugins/core/python.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index f41a8037b..e210a224d 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; +use itertools::Itertools; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; @@ -72,7 +73,12 @@ impl PythonPlugin { let python_build_bin = self.python_build_bin(); CorePlugin::run_fetch_task_with_timeout(move || { let output = cmd!(python_build_bin, "--definitions").read()?; - Ok(output.split('\n').map(|s| s.to_string()).collect()) + let versions = output + .split('\n') + .map(|s| s.to_string()) + .sorted_by_cached_key(|v| regex!(r"^\d+").is_match(v)) + .collect(); + Ok(versions) }) } From 13255b1e8bfa683561bd5851a52b99c0a310b82f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 14:51:13 -0600 Subject: [PATCH 1290/1891] cache-clear: add optional plugin argument (#1161) * cache-clear: add optional plugin argument * Commit from GitHub Actions (rtx) --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- README.md | 10 +++-- completions/_rtx | 1 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/cache/clear.rs | 37 ++++++++++++++----- ...cli__cache__clear__tests__cache_clear.snap | 5 +++ ...che__clear__tests__cache_clear_plugin.snap | 5 +++ src/cli/mod.rs | 12 ++++++ 8 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap create mode 100644 src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap diff --git a/README.md b/README.md index 07257d76d..5bad41ed6 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ v20.0.0 - [`rtx alias set `](#rtx-alias-set-plugin-alias-value) - [`rtx alias unset `](#rtx-alias-unset-plugin-alias) - [`rtx bin-paths`](#rtx-bin-paths) - - [`rtx cache clear`](#rtx-cache-clear) + - [`rtx cache clear [PLUGIN]...`](#rtx-cache-clear-plugin) - [`rtx completion [SHELL]`](#rtx-completion-shell) - [`rtx current [PLUGIN]`](#rtx-current-plugin) - [`rtx deactivate`](#rtx-deactivate) @@ -1774,12 +1774,16 @@ List all the active runtime bin paths Usage: bin-paths ``` -### `rtx cache clear` +### `rtx cache clear [PLUGIN]...` ```text Deletes all cache files in rtx -Usage: cache clear +Usage: cache clear [PLUGIN]... + +Arguments: + [PLUGIN]... + Plugin(s) to clear cache for e.g.: node, python ``` ### `rtx completion [SHELL]` diff --git a/completions/_rtx b/completions/_rtx index 13940684a..fb60bac41 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -185,6 +185,7 @@ return ret (( $+functions[__rtx_cache_clear_cmd] )) || __rtx_cache_clear_cmd() { _arguments -s -S \ + '*::plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 89744e55e..3cf07db92 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -919,7 +919,7 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index fb17426ad..a840a74e9 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -77,6 +77,7 @@ set -l others clear complete -xc rtx -n "$fssf cache; and not $fssf $others" -a clear -d 'Deletes all cache files in rtx' # cache clear +complete -xc rtx -n "$fssf cache; and $fssf clear" -a "(__rtx_plugins)" -d 'Plugin(s) to clear cache for e.g.: node, python' # completion diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index a7f623bb9..5906d6b7d 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -1,33 +1,50 @@ use color_eyre::eyre::Result; use crate::config::Config; -use crate::env; -use crate::file::remove_all; +use crate::dirs::CACHE; +use crate::file::{display_path, remove_all}; use crate::output::Output; /// Deletes all cache files in rtx #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "c", alias = "clean")] -pub struct CacheClear {} +pub struct CacheClear { + /// Plugin(s) to clear cache for + /// e.g.: node, python + plugin: Option>, +} impl CacheClear { pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { - let cache_dir = env::RTX_CACHE_DIR.to_path_buf(); - if cache_dir.exists() { - debug!("clearing cache from {}", cache_dir.display()); - remove_all(cache_dir)?; + let cache_dirs = match &self.plugin { + Some(plugins) => plugins.iter().map(|p| CACHE.join(p)).collect(), + None => vec![CACHE.to_path_buf()], + }; + for p in cache_dirs { + if p.exists() { + debug!("clearing cache from {}", display_path(&p)); + remove_all(p)?; + } + } + match &self.plugin { + Some(plugins) => rtxstatusln!(out, "cache cleared for {}", plugins.join(", ")), + None => rtxstatusln!(out, "cache cleared"), } - rtxstatusln!(out, "cache cleared"); Ok(()) } } #[cfg(test)] mod tests { - use crate::assert_cli; + use crate::assert_cli_snapshot_stderr; #[test] fn test_cache_clear() { - assert_cli!("cache", "clear"); + assert_cli_snapshot_stderr!("cache", "clear"); + } + + #[test] + fn test_cache_clear_plugin() { + assert_cli_snapshot_stderr!("cache", "clear", "tiny"); } } diff --git a/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap b/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap new file mode 100644 index 000000000..de6ce6cee --- /dev/null +++ b/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/cache/clear.rs +expression: output +--- +rtx cache cleared diff --git a/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap b/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap new file mode 100644 index 000000000..805c0c5c4 --- /dev/null +++ b/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/cache/clear.rs +expression: output +--- +rtx cache cleared for tiny diff --git a/src/cli/mod.rs b/src/cli/mod.rs index fe57ab85d..c44d12c6f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -303,6 +303,18 @@ pub mod tests { }}; } + #[macro_export] + macro_rules! assert_cli_snapshot_stderr { + ($($args:expr),+) => {{ + let args = &vec!["rtx".into(), $($args.into()),+]; + let output = $crate::cli::tests::cli_run(args).unwrap().stderr.content; + let output = console::strip_ansi_codes(&output.trim()).to_string(); + let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); + let output = $crate::test::replace_path(&output); + insta::assert_snapshot!(output); + }}; + } + #[macro_export] macro_rules! assert_cli_err { ($($args:expr),+) => {{ From f83a556078f453e33619b52148a30575c1aa273a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:22:43 -0600 Subject: [PATCH 1291/1891] refactor: simplified stdout/stderr mocking in tests (#1163) --- .markdown-link-check.json | 6 +- src/cli/activate.rs | 5 +- src/cli/alias/get.rs | 5 +- src/cli/alias/ls.rs | 8 +-- src/cli/alias/mod.rs | 15 ++-- src/cli/alias/set.rs | 3 +- src/cli/alias/unset.rs | 3 +- src/cli/asdf.rs | 22 +++--- src/cli/bin_paths.rs | 6 +- src/cli/cache/clear.rs | 7 +- src/cli/cache/mod.rs | 11 ++- src/cli/completion.rs | 5 +- src/cli/current.rs | 20 ++---- src/cli/deactivate.rs | 8 +-- src/cli/direnv/activate.rs | 4 +- src/cli/direnv/envrc.rs | 6 +- src/cli/direnv/exec.rs | 6 +- src/cli/direnv/mod.rs | 13 ++-- src/cli/doctor.rs | 32 ++++----- src/cli/env.rs | 16 ++--- src/cli/env_vars.rs | 5 +- src/cli/exec.rs | 4 +- src/cli/global.rs | 4 +- src/cli/hook_env.rs | 16 ++--- src/cli/implode.rs | 6 +- src/cli/install.rs | 4 +- src/cli/latest.rs | 8 +-- src/cli/link.rs | 4 +- src/cli/local.rs | 16 ++--- src/cli/ls.rs | 30 ++++---- src/cli/ls_remote.rs | 16 ++--- src/cli/mod.rs | 110 +++++++++++++++--------------- src/cli/outdated.rs | 9 +-- src/cli/plugins/install.rs | 4 +- src/cli/plugins/link.rs | 4 +- src/cli/plugins/ls.rs | 16 ++--- src/cli/plugins/ls_remote.rs | 5 +- src/cli/plugins/mod.rs | 19 +++--- src/cli/plugins/uninstall.rs | 4 +- src/cli/plugins/update.rs | 6 +- src/cli/prune.rs | 4 +- src/cli/render_completion.rs | 5 +- src/cli/render_help.rs | 3 +- src/cli/render_mangen.rs | 3 +- src/cli/reshim.rs | 4 +- src/cli/self_update.rs | 8 +-- src/cli/settings/get.rs | 5 +- src/cli/settings/ls.rs | 5 +- src/cli/settings/mod.rs | 15 ++-- src/cli/settings/set.rs | 3 +- src/cli/settings/unset.rs | 3 +- src/cli/shell.rs | 5 +- src/cli/sync/mod.rs | 11 ++- src/cli/sync/node.rs | 21 +++--- src/cli/sync/python.rs | 6 +- src/cli/trust.rs | 7 +- src/cli/uninstall.rs | 4 +- src/cli/upgrade.rs | 12 ++-- src/cli/use.rs | 5 +- src/cli/version.rs | 16 ++--- src/cli/where.rs | 6 +- src/cli/which.rs | 10 +-- src/config/config_file/mod.rs | 6 +- src/main.rs | 9 +-- src/output.rs | 124 +++++++++++++--------------------- src/shims.rs | 6 +- 66 files changed, 354 insertions(+), 443 deletions(-) diff --git a/.markdown-link-check.json b/.markdown-link-check.json index 60967aea0..2fc2c67da 100644 --- a/.markdown-link-check.json +++ b/.markdown-link-check.json @@ -1,7 +1,3 @@ { - "ignorePatterns": [ - { - "pattern": "^https://crates.io" - } - ] + "ignorePatterns": [{ "pattern": "^https://crates.io" }] } diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 514fd889b..2dd46b511 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -4,7 +4,6 @@ use crate::config::Config; use crate::dirs; use crate::env::RTX_EXE; use crate::file::touch_dir; -use crate::output::Output; use crate::shell::{get_shell, ShellType}; /// Initializes rtx in the current shell @@ -46,7 +45,7 @@ pub struct Activate { } impl Activate { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let shell = get_shell(self.shell_type.or(self.shell)) .expect("no shell provided, use `--shell=zsh`"); @@ -54,7 +53,7 @@ impl Activate { let _ = touch_dir(&dirs::DATA); let output = shell.activate(&RTX_EXE, self.status); - out.stdout.write(output); + rtxprint!("{output}"); Ok(()) } diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 3640f4b00..ee505da5e 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::{eyre, Result}; use crate::config::Config; -use crate::output::Output; /// Show an alias for a plugin /// @@ -17,10 +16,10 @@ pub struct AliasGet { } impl AliasGet { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match config.get_all_aliases().get(&self.plugin) { Some(plugin) => match plugin.get(&self.alias) { - Some(alias) => Ok(rtxprintln!(out, "{}", alias)), + Some(alias) => Ok(rtxprintln!("{}", alias)), None => Err(eyre!("Unknown alias: {}", &self.alias)), }, None => Err(eyre!("Unknown plugin: {}", &self.plugin)), diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 88e0589f5..fae6e7349 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; + use crate::plugins::PluginName; /// List aliases @@ -21,7 +21,7 @@ pub struct AliasLs { } impl AliasLs { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { for (plugin_name, aliases) in config.get_all_aliases() { if let Some(plugin) = &self.plugin { if plugin_name != plugin { @@ -35,9 +35,9 @@ impl AliasLs { continue; } if self.plugin.is_some() { - rtxprintln!(out, "{:20} {}", from, to); + rtxprintln!("{:20} {}", from, to); } else { - rtxprintln!(out, "{:20} {:20} {}", plugin_name, from, to); + rtxprintln!("{:20} {:20} {}", plugin_name, from, to); } } } diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index 3a64a6771..2d07861d8 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -2,7 +2,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; use crate::plugins::PluginName; mod get; @@ -30,22 +29,22 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self { - Self::Get(cmd) => cmd.run(config, out), - Self::Ls(cmd) => cmd.run(config, out), - Self::Set(cmd) => cmd.run(config, out), - Self::Unset(cmd) => cmd.run(config, out), + Self::Get(cmd) => cmd.run(config), + Self::Ls(cmd) => cmd.run(config), + Self::Set(cmd) => cmd.run(config), + Self::Unset(cmd) => cmd.run(config), } } } impl Alias { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::AliasLs { plugin: self.plugin, })); - cmd.run(config, out) + cmd.run(config) } } diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 5ce37dbf7..c24e43044 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -2,7 +2,6 @@ use color_eyre::eyre::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; -use crate::output::Output; /// Add/update an alias for a plugin /// @@ -19,7 +18,7 @@ pub struct AliasSet { } impl AliasSet { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { config .global_config .set_alias(&self.plugin, &self.alias, &self.value); diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 10373368e..777b3b221 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -2,7 +2,6 @@ use color_eyre::eyre::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; -use crate::output::Output; /// Clears an alias for a plugin /// @@ -17,7 +16,7 @@ pub struct AliasUnset { } impl AliasUnset { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { config.global_config.remove_alias(&self.plugin, &self.alias); config.global_config.save() } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 06ec017dd..a7a650764 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::cli::Cli; use crate::config::Config; -use crate::output::Output; + use crate::toolset::ToolsetBuilder; /// [internal] simulates asdf for plugins that call "asdf" internally @@ -17,32 +17,32 @@ pub struct Asdf { } impl Asdf { - pub fn run(mut self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(mut self, config: Config) -> Result<()> { let mut args = vec![String::from("rtx")]; args.append(&mut self.args); match args.get(1).map(|s| s.as_str()) { - Some("reshim") => Cli::new().run(config, &args, out), - Some("list") => list_versions(config, out, &args), + Some("reshim") => Cli::new().run(config, &args), + Some("list") => list_versions(config, &args), Some("install") => { if args.len() == 4 { let version = args.pop().unwrap(); args[2] = format!("{}@{}", args[2], version); } - Cli::new().run(config, &args, out) + Cli::new().run(config, &args) } - _ => Cli::new().run(config, &args, out), + _ => Cli::new().run(config, &args), } } } -fn list_versions(config: Config, out: &mut Output, args: &Vec) -> Result<()> { +fn list_versions(config: Config, args: &Vec) -> Result<()> { if args[2] == "all" { let mut new_args: Vec = vec!["rtx".into(), "ls-remote".into()]; if args.len() >= 3 { new_args.push(args[3].clone()); } - return Cli::new().run(config, &new_args, out); + return Cli::new().run(config, &new_args); } let ts = ToolsetBuilder::new().build(&config)?; let mut versions = ts.list_installed_versions(&config)?; @@ -53,16 +53,16 @@ fn list_versions(config: Config, out: &mut Output, args: &Vec) -> Result if let Some(plugin) = plugin { versions.retain(|(_, v)| v.plugin_name.as_str() == plugin); for (_, version) in versions { - rtxprintln!(out, "{}", version.version); + rtxprintln!("{}", version.version); } } else { for (plugin, versions) in &versions .into_iter() .group_by(|(_, v)| v.plugin_name.to_string()) { - rtxprintln!(out, "{}", plugin); + rtxprintln!("{}", plugin); for (_, tv) in versions { - rtxprintln!(out, " {}", tv.version); + rtxprintln!(" {}", tv.version); } } } diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index c05327f05..2d124c8e7 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; + use crate::toolset::ToolsetBuilder; /// List all the active runtime bin paths @@ -10,10 +10,10 @@ use crate::toolset::ToolsetBuilder; pub struct BinPaths {} impl BinPaths { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = ToolsetBuilder::new().build(&config)?; for p in ts.list_paths(&config) { - rtxprintln!(out, "{}", p.display()); + rtxprintln!("{}", p.display()); } Ok(()) } diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index 5906d6b7d..06d414683 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -3,7 +3,6 @@ use color_eyre::eyre::Result; use crate::config::Config; use crate::dirs::CACHE; use crate::file::{display_path, remove_all}; -use crate::output::Output; /// Deletes all cache files in rtx #[derive(Debug, clap::Args)] @@ -15,7 +14,7 @@ pub struct CacheClear { } impl CacheClear { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let cache_dirs = match &self.plugin { Some(plugins) => plugins.iter().map(|p| CACHE.join(p)).collect(), None => vec![CACHE.to_path_buf()], @@ -27,8 +26,8 @@ impl CacheClear { } } match &self.plugin { - Some(plugins) => rtxstatusln!(out, "cache cleared for {}", plugins.join(", ")), - None => rtxstatusln!(out, "cache cleared"), + Some(plugins) => rtxstatusln!("cache cleared for {}", plugins.join(", ")), + None => rtxstatusln!("cache cleared"), } Ok(()) } diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 06bffdea7..10339f440 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -3,7 +3,6 @@ use color_eyre::eyre::Result; use crate::config::Config; use crate::env; -use crate::output::Output; mod clear; @@ -23,20 +22,20 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self { - Self::Clear(cmd) => cmd.run(config, out), + Self::Clear(cmd) => cmd.run(config), } } } impl Cache { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self.command { - Some(cmd) => cmd.run(config, out), + Some(cmd) => cmd.run(config), None => { // just show the cache dir - rtxprintln!(out, "{}", env::RTX_CACHE_DIR.display()); + rtxprintln!("{}", env::RTX_CACHE_DIR.display()); Ok(()) } } diff --git a/src/cli/completion.rs b/src/cli/completion.rs index a13a16dee..3d449a121 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -4,7 +4,6 @@ use color_eyre::eyre::Result; use std::fmt::Display; use crate::config::Config; -use crate::output::Output; /// Generate shell completions #[derive(Debug, clap::Args)] @@ -20,13 +19,13 @@ pub struct Completion { } impl Completion { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let c = match self.shell.or(self.shell_type).unwrap() { Shell::Bash => include_str!("../../completions/rtx.bash"), Shell::Fish => include_str!("../../completions/rtx.fish"), Shell::Zsh => include_str!("../../completions/_rtx"), }; - rtxprintln!(out, "{}", c.trim()); + rtxprintln!("{}", c.trim()); Ok(()) } diff --git a/src/cli/current.rs b/src/cli/current.rs index 92fc67b4c..2b95c2433 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::Result; use std::sync::Arc; use crate::config::Config; -use crate::output::Output; + use crate::plugins::{unalias_plugin, Plugin}; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -20,7 +20,7 @@ pub struct Current { } impl Current { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = ToolsetBuilder::new().build(&config)?; match &self.plugin { Some(plugin_name) => { @@ -29,19 +29,13 @@ impl Current { if !plugin.is_installed() { bail!("Plugin {} is not installed", plugin_name); } - self.one(&config, ts, out, plugin.clone()) + self.one(&config, ts, plugin.clone()) } - None => self.all(&config, ts, out), + None => self.all(&config, ts), } } - fn one( - &self, - config: &Config, - ts: Toolset, - out: &mut Output, - tool: Arc, - ) -> Result<()> { + fn one(&self, config: &Config, ts: Toolset, tool: Arc) -> Result<()> { if !tool.is_installed() { warn!("Plugin {} is not installed", tool.name()); return Ok(()); @@ -53,7 +47,6 @@ impl Current { { Some((_, versions)) => { rtxprintln!( - out, "{}", versions .iter() @@ -69,7 +62,7 @@ impl Current { Ok(()) } - fn all(&self, config: &Config, ts: Toolset, out: &mut Output) -> Result<()> { + fn all(&self, config: &Config, ts: Toolset) -> Result<()> { for (plugin, versions) in ts.list_versions_by_plugin(config) { if versions.is_empty() { continue; @@ -84,7 +77,6 @@ impl Current { } } rtxprintln!( - out, "{} {}", &plugin.name(), versions diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index b0bdc9caf..d9eb45c61 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -3,7 +3,7 @@ use console::style; use crate::config::Config; use crate::hook_env; -use crate::output::Output; + use crate::shell::get_shell; /// Disable rtx for current shell session @@ -14,16 +14,16 @@ use crate::shell::get_shell; pub struct Deactivate {} impl Deactivate { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { if !config.is_activated() { err_inactive()?; } let shell = get_shell(None).expect("no shell detected"); - out.stdout.write(hook_env::clear_old_env(&*shell)); + rtxprint!("{}", hook_env::clear_old_env(&*shell)); let output = shell.deactivate(); - out.stdout.write(output); + rtxprint!("{output}"); Ok(()) } diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 621037843..4b0ccecde 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; /// Output direnv function to use rtx inside direnv /// @@ -15,9 +14,8 @@ use crate::output::Output; pub struct DirenvActivate {} impl DirenvActivate { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { rtxprintln!( - out, // source_env "$(rtx direnv envrc "$@")" indoc! {r#" ### Do not edit. This was autogenerated by 'rtx direnv' ### diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 651cbf5ae..48a512a88 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -6,7 +6,7 @@ use color_eyre::eyre::Result; use crate::config::Config; use crate::hash::hash_to_str; -use crate::output::Output; + use crate::toolset::ToolsetBuilder; use crate::{dirs, env}; @@ -17,7 +17,7 @@ use crate::{dirs, env}; pub struct Envrc {} impl Envrc { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = ToolsetBuilder::new().build(&config)?; let envrc_path = env::RTX_TMP_DIR @@ -51,7 +51,7 @@ impl Envrc { writeln!(file, "PATH_add {}", path.to_string_lossy())?; } - rtxprintln!(out, "{}", envrc_path.to_string_lossy()); + rtxprintln!("{}", envrc_path.to_string_lossy()); Ok(()) } } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 70d3e4cfe..e7b9f5d03 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -4,7 +4,7 @@ use eyre::WrapErr; use serde_derive::Deserialize; use crate::config::Config; -use crate::output::Output; + use crate::toolset::ToolsetBuilder; /// [internal] This is an internal command that writes an envrc file @@ -20,7 +20,7 @@ struct DirenvWatches { } impl DirenvExec { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = ToolsetBuilder::new().build(&config)?; let mut cmd = env_cmd(); @@ -35,7 +35,7 @@ impl DirenvExec { let w: DirenvWatches = serde_json::from_str(&json)?; cmd = cmd.env("DIRENV_WATCHES", w.watches); - rtxprint!(out, "{}", cmd.read()?); + rtxprint!("{}", cmd.read()?); Ok(()) } } diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index 3911f85ab..681fe3f33 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -2,7 +2,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; mod activate; mod envrc; @@ -30,20 +29,20 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self { - Self::Activate(cmd) => cmd.run(config, out), - Self::Envrc(cmd) => cmd.run(config, out), - Self::Exec(cmd) => cmd.run(config, out), + Self::Activate(cmd) => cmd.run(config), + Self::Envrc(cmd) => cmd.run(config), + Self::Exec(cmd) => cmd.run(config), } } } impl Direnv { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let cmd = self .command .unwrap_or(Commands::Activate(activate::DirenvActivate {})); - cmd.run(config, out) + cmd.run(config) } } diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index a1bfbee51..aed61ac0e 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -9,7 +9,7 @@ use crate::build_time::built_info; use crate::cli::version::VERSION; use crate::config::Config; use crate::git::Git; -use crate::output::Output; + use crate::plugins::PluginType; use crate::shell::ShellType; use crate::toolset::ToolsetBuilder; @@ -22,27 +22,21 @@ use crate::{duration, env}; pub struct Doctor {} impl Doctor { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = ToolsetBuilder::new().build(&config)?; - rtxprintln!(out, "{}", rtx_version()); - rtxprintln!(out, "{}", build_info()); - rtxprintln!(out, "{}", shell()); - rtxprintln!(out, "{}", rtx_data_dir()); - rtxprintln!(out, "{}", rtx_env_vars()); + rtxprintln!("{}", rtx_version()); + rtxprintln!("{}", build_info()); + rtxprintln!("{}", shell()); + rtxprintln!("{}", rtx_data_dir()); + rtxprintln!("{}", rtx_env_vars()); rtxprintln!( - out, "{}\n{}\n", style("settings:").bold(), indent(config.settings.to_string()) ); - rtxprintln!(out, "{}", render_config_files(&config)); - rtxprintln!(out, "{}", render_plugins(&config)); - rtxprintln!( - out, - "{}\n{}\n", - style("toolset:").bold(), - indent(ts.to_string()) - ); + rtxprintln!("{}", render_config_files(&config)); + rtxprintln!("{}", render_plugins(&config)); + rtxprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())); let mut checks = Vec::new(); for plugin in config.list_plugins() { @@ -73,13 +67,13 @@ impl Doctor { } if checks.is_empty() { - rtxprintln!(out, "No problems found"); + rtxprintln!("No problems found"); } else { let checks_plural = if checks.len() == 1 { "" } else { "s" }; let summary = format!("{} problem{checks_plural} found:", checks.len()); - rtxprintln!(out, "{}", style(summary).red().bold()); + rtxprintln!("{}", style(summary).red().bold()); for check in &checks { - rtxprintln!(out, "{}\n", check); + rtxprintln!("{}\n", check); } exit(1); } diff --git a/src/cli/env.rs b/src/cli/env.rs index 2d3f7b235..b48deb182 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; + use crate::shell::{get_shell, ShellType}; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -27,30 +27,30 @@ pub struct Env { } impl Env { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> 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) + self.output_json(config, ts) } else { - self.output_shell(config, out, ts) + self.output_shell(config, ts) } } - fn output_json(&self, config: Config, out: &mut Output, ts: Toolset) -> Result<()> { + fn output_json(&self, config: Config, ts: Toolset) -> Result<()> { let env = ts.env_with_path(&config); - rtxprintln!(out, "{}", serde_json::to_string_pretty(&env)?); + rtxprintln!("{}", serde_json::to_string_pretty(&env)?); Ok(()) } - fn output_shell(&self, config: Config, out: &mut Output, ts: Toolset) -> Result<()> { + fn output_shell(&self, config: Config, ts: Toolset) -> Result<()> { let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); for (k, v) in ts.env_with_path(&config) { let k = k.to_string(); let v = v.to_string(); - rtxprint!(out, "{}", shell.set_env(&k, &v)); + rtxprint!("{}", shell.set_env(&k, &v)); } Ok(()) } diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index 8a216b6e5..e1c5372e1 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -6,7 +6,6 @@ use crate::config::Config; use crate::dirs; use crate::env::RTX_DEFAULT_CONFIG_FILENAME; use crate::file::display_path; -use crate::output::Output; use super::args::env_var::{EnvVarArg, EnvVarArgParser}; @@ -36,11 +35,11 @@ pub struct EnvVars { } impl EnvVars { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { if self.remove.is_none() && self.env_vars.is_none() { for (key, value) in &config.env { let source = config.env_sources.get(key).unwrap(); - rtxprintln!(out, "{key}={value} {}", display_path(source)); + rtxprintln!("{key}={value} {}", display_path(source)); } return Ok(()); } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index ba9cb3583..6dfbed2ab 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -11,7 +11,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cmd; use crate::config::Config; use crate::env; -use crate::output::Output; + use crate::toolset::ToolsetBuilder; /// Execute a command with tool(s) set @@ -45,7 +45,7 @@ pub struct Exec { } impl Exec { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; ts.install_arg_versions(&config)?; diff --git a/src/cli/global.rs b/src/cli/global.rs index 60decf3ec..87042e439 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -5,7 +5,6 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::local::local; use crate::config::Config; -use crate::output::Output; use crate::plugins::PluginName; use crate::{dirs, env}; @@ -49,10 +48,9 @@ pub struct Global { } impl Global { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { local( config, - out, &global_file(), self.tool, self.remove, diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 7df80c107..fdd023107 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -14,7 +14,7 @@ use crate::config::Settings; use crate::direnv::DirenvDiff; use crate::env::__RTX_DIFF; use crate::env_diff::{EnvDiff, EnvDiffOperation}; -use crate::output::Output; + use crate::shell::{get_shell, ShellType}; use crate::toolset::{Toolset, ToolsetBuilder}; use crate::{env, hook_env}; @@ -33,10 +33,10 @@ pub struct HookEnv { } impl HookEnv { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> 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)); + rtxprint!("{}", hook_env::clear_old_env(&*shell)); let mut env = ts.env(&config); let env_path = env.remove("PATH"); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); @@ -54,15 +54,15 @@ impl HookEnv { patches.push(self.build_watch_operation(&config)?); let output = hook_env::build_env_commands(&*shell, &patches); - out.stdout.write(output); + rtxprint!("{output}"); if self.status { - self.display_status(&config, &ts, out); + self.display_status(&config, &ts); } Ok(()) } - fn display_status(&self, config: &Config, ts: &Toolset, out: &mut Output) { + fn display_status(&self, config: &Config, ts: &Toolset) { let installed_versions = ts .list_current_installed_versions(config) .into_iter() @@ -76,12 +76,12 @@ impl HookEnv { } as usize; let w = max(w, 40); let status = installed_versions.into_iter().rev().join(" "); - rtxstatusln!(out, "{}", truncate_str(&status, w - 4, "...")); + rtxstatusln!("{}", truncate_str(&status, w - 4, "...")); } let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env.clone()).to_patches(); if !env_diff.is_empty() { let env_diff = env_diff.into_iter().map(patch_to_status).join(" "); - rtxstatusln!(out, "{env_diff}"); + rtxstatusln!("{env_diff}"); } } diff --git a/src/cli/implode.rs b/src/cli/implode.rs index a52af9d6b..6a62a35e8 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -4,7 +4,7 @@ use color_eyre::eyre::Result; use crate::config::Config; use crate::file::remove_all; -use crate::output::Output; + use crate::ui::prompt; use crate::{dirs, env, file}; @@ -24,14 +24,14 @@ pub struct Implode { } impl Implode { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mut files = vec![&*dirs::DATA, &*dirs::CACHE, &*env::RTX_EXE]; if self.config { files.push(&*dirs::CONFIG); } for f in files.into_iter().filter(|d| d.exists()) { if self.dry_run { - rtxprintln!(out, "rm -rf {}", f.display()); + rtxprintln!("rm -rf {}", f.display()); } if self.confirm_remove(&config, f)? { diff --git a/src/cli/install.rs b/src/cli/install.rs index a6bb7ebc1..b77419041 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; + use crate::toolset::{ ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, }; @@ -34,7 +34,7 @@ pub struct Install { } impl Install { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match &self.tool { Some(runtime) => self.install_runtimes(config, runtime)?, None => self.install_missing_runtimes(config)?, diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 1f8d01ff7..edeaeb548 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -3,7 +3,7 @@ use console::style; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; + use crate::toolset::ToolVersionRequest; /// Gets the latest available version for a plugin @@ -26,7 +26,7 @@ pub struct Latest { } impl Latest { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mut prefix = match self.tool.tvr { None => self.asdf_version, Some(ToolVersionRequest::Version(_, version)) => Some(version), @@ -48,7 +48,7 @@ impl Latest { plugin.latest_version(&config.settings, prefix)? }; if let Some(version) = latest_version { - rtxprintln!(out, "{}", version); + rtxprintln!("{}", version); } Ok(()) } @@ -101,6 +101,6 @@ mod tests { #[test] fn test_latest_alias() { let stdout = assert_cli!("latest", "tiny@lts"); - assert_str_eq!(stdout, "3.1.0\n"); + assert_str_eq!(stdout, "3.1.0"); } } diff --git a/src/cli/link.rs b/src/cli/link.rs index e95721196..31468931b 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -8,7 +8,7 @@ use path_absolutize::Absolutize; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::file::{make_symlink, remove_all}; -use crate::output::Output; + use crate::{dirs, file}; /// Symlinks a tool version into rtx @@ -33,7 +33,7 @@ pub struct Link { } impl Link { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> 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 89f2e3456..d2162affd 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -8,7 +8,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; -use crate::output::Output; + use crate::plugins::PluginName; use crate::{dirs, env, file}; @@ -54,7 +54,7 @@ pub struct Local { } impl Local { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let path = if self.parent { get_parent_path()? } else { @@ -62,7 +62,6 @@ impl Local { }; local( config, - out, &path, self.tool, self.remove, @@ -94,7 +93,6 @@ pub fn get_parent_path() -> Result { #[allow(clippy::too_many_arguments)] pub fn local( config: Config, - out: &mut Output, path: &Path, runtime: Vec, remove: Option>, @@ -104,7 +102,7 @@ pub fn local( ) -> Result<()> { let mut cf = config_file::parse_or_init(&config.settings, path)?; if show_path { - rtxprintln!(out, "{}", path.display()); + rtxprintln!("{}", path.display()); return Ok(()); } @@ -114,7 +112,6 @@ pub fn local( } let tools = plugins.iter().map(|r| r.to_string()).join(" "); rtxprintln!( - out, "{} {} {}", style("rtx").dim(), display_path(path), @@ -124,14 +121,13 @@ pub fn local( if !runtime.is_empty() { let runtimes = ToolArg::double_tool_condition(&runtime); - if cf.display_runtime(out, &runtimes)? { + if cf.display_runtime(&runtimes)? { return Ok(()); } let pin = pin || (config.settings.asdf_compat && !fuzzy); cf.add_runtimes(&config, &runtimes, pin)?; let tools = runtimes.iter().map(|r| r.to_string()).join(" "); rtxprintln!( - out, "{} {} {}", style("rtx").dim(), display_path(path), @@ -142,7 +138,7 @@ pub fn local( if !runtime.is_empty() || remove.is_some() { cf.save()?; } else { - rtxprint!(out, "{}", cf.dump()); + rtxprint!("{}", cf.dump()); } Ok(()) @@ -248,7 +244,7 @@ mod tests { run_test(|| { assert_cli!("local", "tiny", "2"); let stdout = assert_cli!("local", "tiny"); - assert_str_eq!(stdout, "2\n"); + assert_str_eq!(stdout, "2"); }); } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index e18a8d2d4..7a27e2fa7 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -13,7 +13,6 @@ use versions::Versioning; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; -use crate::output::Output; use crate::plugins::{unalias_plugin, Plugin, PluginName}; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; @@ -59,7 +58,7 @@ pub struct Ls { } impl Ls { - pub fn run(mut self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(mut self, config: Config) -> Result<()> { self.plugin = self .plugin .clone() @@ -83,11 +82,11 @@ impl Ls { runtimes.retain(|(_, tv, _)| tv.version.starts_with(prefix)); } if self.json { - self.display_json(runtimes, out) + self.display_json(runtimes) } else if self.parseable { - self.display_parseable(runtimes, out) + self.display_parseable(runtimes) } else { - self.display_user(&config, runtimes, out) + self.display_user(&config, runtimes) } } @@ -104,7 +103,7 @@ impl Ls { Ok(()) } - fn display_json(&self, runtimes: Vec, out: &mut Output) -> Result<()> { + fn display_json(&self, runtimes: Vec) -> Result<()> { if let Some(plugin) = &self.plugin { // only runtimes for 1 plugin let runtimes: Vec = runtimes @@ -112,7 +111,7 @@ impl Ls { .filter(|(p, _, _)| plugin.eq(&p.name())) .map(|row| row.into()) .collect(); - out.stdout.writeln(serde_json::to_string_pretty(&runtimes)?); + rtxprintln!("{}", serde_json::to_string_pretty(&runtimes)?); return Ok(()); } @@ -124,11 +123,11 @@ impl Ls { let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); } - out.stdout.writeln(serde_json::to_string_pretty(&plugins)?); + rtxprintln!("{}", serde_json::to_string_pretty(&plugins)?); Ok(()) } - fn display_parseable(&self, runtimes: Vec, out: &mut Output) -> Result<()> { + fn display_parseable(&self, runtimes: Vec) -> Result<()> { warn!("The parseable output format is deprecated and will be removed in a future release."); warn!("Please use the regular output format instead which has been modified to be more easily parseable."); runtimes @@ -138,20 +137,15 @@ impl Ls { .for_each(|(_, tv)| { if self.plugin.is_some() { // only displaying 1 plugin so only show the version - rtxprintln!(out, "{}", tv.version); + rtxprintln!("{}", tv.version); } else { - rtxprintln!(out, "{} {}", tv.plugin_name, tv.version); + rtxprintln!("{} {}", tv.plugin_name, tv.version); } }); Ok(()) } - fn display_user( - &self, - config: &Config, - runtimes: Vec, - out: &mut Output, - ) -> Result<()> { + fn display_user(&self, config: &Config, runtimes: Vec) -> Result<()> { let output = runtimes .into_iter() .map(|(p, tv, source)| { @@ -204,7 +198,7 @@ impl Ls { format!("{} {}", plugin, version) } }; - rtxprintln!(out, "{}", line.trim_end()); + rtxprintln!("{}", line.trim_end()); } Ok(()) } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index f49afb8fa..89eba68da 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -7,7 +7,7 @@ use rayon::prelude::*; use crate::cli::args::tool::ToolArg; use crate::cli::args::tool::ToolArgParser; use crate::config::Config; -use crate::output::Output; + use crate::plugins::Plugin; use crate::toolset::ToolVersionRequest; @@ -33,15 +33,15 @@ pub struct LsRemote { } impl LsRemote { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { if let Some(plugin) = self.get_plugin(&config)? { - self.run_single(config, out, plugin) + self.run_single(config, plugin) } else { - self.run_all(config, out) + self.run_all(config) } } - fn run_single(self, config: Config, out: &mut Output, plugin: Arc) -> Result<()> { + fn run_single(self, config: Config, plugin: Arc) -> Result<()> { let prefix = match &self.plugin { Some(tool_arg) => match &tool_arg.tvr { Some(ToolVersionRequest::Version(_, v)) => Some(v.clone()), @@ -60,13 +60,13 @@ impl LsRemote { }; for version in versions { - rtxprintln!(out, "{}", version); + rtxprintln!("{}", version); } Ok(()) } - fn run_all(self, config: Config, out: &mut Output) -> Result<()> { + fn run_all(self, config: Config) -> Result<()> { let versions = config .list_plugins() .into_par_iter() @@ -80,7 +80,7 @@ impl LsRemote { .collect::>(); for (plugin, versions) in versions { for v in versions { - rtxprintln!(out, "{}@{v}", plugin); + rtxprintln!("{}@{v}", plugin); } } Ok(()) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index c44d12c6f..22f6eb69f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -3,7 +3,6 @@ use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; use crate::config::Config; -use crate::output::Output; mod activate; mod alias; @@ -106,53 +105,53 @@ pub enum Commands { } impl Commands { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self { - Self::Activate(cmd) => cmd.run(config, out), - Self::Alias(cmd) => cmd.run(config, out), - Self::Asdf(cmd) => cmd.run(config, out), - Self::BinPaths(cmd) => cmd.run(config, out), - Self::Cache(cmd) => cmd.run(config, out), - Self::Completion(cmd) => cmd.run(config, out), - Self::Current(cmd) => cmd.run(config, out), - Self::Deactivate(cmd) => cmd.run(config, out), - Self::Direnv(cmd) => cmd.run(config, out), - Self::Doctor(cmd) => cmd.run(config, out), - Self::Env(cmd) => cmd.run(config, out), - Self::EnvVars(cmd) => cmd.run(config, out), - Self::Exec(cmd) => cmd.run(config, out), - Self::Global(cmd) => cmd.run(config, out), - Self::HookEnv(cmd) => cmd.run(config, out), - Self::Implode(cmd) => cmd.run(config, out), - Self::Install(cmd) => cmd.run(config, out), - Self::Latest(cmd) => cmd.run(config, out), - Self::Link(cmd) => cmd.run(config, out), - Self::Local(cmd) => cmd.run(config, out), - Self::Ls(cmd) => cmd.run(config, out), - Self::LsRemote(cmd) => cmd.run(config, out), - Self::Outdated(cmd) => cmd.run(config, out), - Self::Plugins(cmd) => cmd.run(config, out), - Self::Prune(cmd) => cmd.run(config, out), - Self::Reshim(cmd) => cmd.run(config, out), - Self::Settings(cmd) => cmd.run(config, out), - Self::Shell(cmd) => cmd.run(config, out), - Self::Sync(cmd) => cmd.run(config, out), - Self::Trust(cmd) => cmd.run(config, out), - Self::Uninstall(cmd) => cmd.run(config, out), - Self::Upgrade(cmd) => cmd.run(config, out), - Self::Use(cmd) => cmd.run(config, out), - Self::Version(cmd) => cmd.run(config, out), - Self::Where(cmd) => cmd.run(config, out), - Self::Which(cmd) => cmd.run(config, out), + Self::Activate(cmd) => cmd.run(config), + Self::Alias(cmd) => cmd.run(config), + Self::Asdf(cmd) => cmd.run(config), + Self::BinPaths(cmd) => cmd.run(config), + Self::Cache(cmd) => cmd.run(config), + Self::Completion(cmd) => cmd.run(config), + Self::Current(cmd) => cmd.run(config), + Self::Deactivate(cmd) => cmd.run(config), + Self::Direnv(cmd) => cmd.run(config), + Self::Doctor(cmd) => cmd.run(config), + Self::Env(cmd) => cmd.run(config), + Self::EnvVars(cmd) => cmd.run(config), + Self::Exec(cmd) => cmd.run(config), + Self::Global(cmd) => cmd.run(config), + Self::HookEnv(cmd) => cmd.run(config), + Self::Implode(cmd) => cmd.run(config), + Self::Install(cmd) => cmd.run(config), + Self::Latest(cmd) => cmd.run(config), + Self::Link(cmd) => cmd.run(config), + Self::Local(cmd) => cmd.run(config), + Self::Ls(cmd) => cmd.run(config), + Self::LsRemote(cmd) => cmd.run(config), + Self::Outdated(cmd) => cmd.run(config), + Self::Plugins(cmd) => cmd.run(config), + Self::Prune(cmd) => cmd.run(config), + Self::Reshim(cmd) => cmd.run(config), + Self::Settings(cmd) => cmd.run(config), + Self::Shell(cmd) => cmd.run(config), + Self::Sync(cmd) => cmd.run(config), + Self::Trust(cmd) => cmd.run(config), + Self::Uninstall(cmd) => cmd.run(config), + Self::Upgrade(cmd) => cmd.run(config), + Self::Use(cmd) => cmd.run(config), + Self::Version(cmd) => cmd.run(config), + Self::Where(cmd) => cmd.run(config), + Self::Which(cmd) => cmd.run(config), #[cfg(feature = "clap_complete")] - Self::RenderCompletion(cmd) => cmd.run(config, out), + Self::RenderCompletion(cmd) => cmd.run(config), #[cfg(debug_assertions)] - Self::RenderHelp(cmd) => cmd.run(config, out), + Self::RenderHelp(cmd) => cmd.run(config), #[cfg(feature = "clap_mangen")] - Self::RenderMangen(cmd) => cmd.run(config, out), + Self::RenderMangen(cmd) => cmd.run(config), } } } @@ -197,11 +196,11 @@ impl Cli { ) } - pub fn run(self, mut config: Config, args: &Vec, out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config, args: &Vec) -> Result<()> { debug!("{}", &args.join(" ")); if args[1..] == ["-v"] { // normally this would be considered --verbose - return version::Version {}.run(config, out); + return version::Version {}.run(config); } let matches = self.command.get_matches_from(args); if let Some(jobs) = matches.get_one::("jobs") { @@ -225,12 +224,12 @@ impl Cli { } if let Some((command, sub_m)) = matches.subcommand() { if command == "self-update" { - return SelfUpdate::from_arg_matches(sub_m)?.run(config, out); + return SelfUpdate::from_arg_matches(sub_m)?.run(config); } external::execute(&config, command, sub_m, self.external_commands)?; } let cmd = Commands::from_arg_matches(&matches)?; - cmd.run(config, out) + cmd.run(config) } } @@ -269,25 +268,28 @@ pub mod tests { use color_eyre::{Section, SectionExt}; use crate::dirs; + use crate::output::tests::{STDERR, STDOUT}; use super::*; - pub fn cli_run(args: &Vec) -> Result { + pub fn cli_run(args: &Vec) -> Result<()> { + STDOUT.lock().unwrap().clear(); + STDERR.lock().unwrap().clear(); let config = Config::load()?; - let mut out = Output::tracked(); Cli::new_with_external_commands(&config) - .run(config, args, &mut out) + .run(config, args) .with_section(|| format!("{}", args.join(" ").header("Command:")))?; - Ok(out) + Ok(()) } #[macro_export] macro_rules! assert_cli { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; - let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; - console::strip_ansi_codes(&output).to_string() + $crate::cli::tests::cli_run(args).unwrap(); + let output = $crate::output::tests::STDOUT.lock().unwrap().join("\n"); + console::strip_ansi_codes(&output).trim().to_string() }}; } @@ -295,7 +297,8 @@ pub mod tests { macro_rules! assert_cli_snapshot { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; - let output = $crate::cli::tests::cli_run(args).unwrap().stdout.content; + $crate::cli::tests::cli_run(args).unwrap(); + let output = $crate::output::tests::STDOUT.lock().unwrap().join("\n"); let output = console::strip_ansi_codes(&output.trim()).to_string(); let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); let output = $crate::test::replace_path(&output); @@ -307,7 +310,8 @@ pub mod tests { macro_rules! assert_cli_snapshot_stderr { ($($args:expr),+) => {{ let args = &vec!["rtx".into(), $($args.into()),+]; - let output = $crate::cli::tests::cli_run(args).unwrap().stderr.content; + $crate::cli::tests::cli_run(args).unwrap(); + let output = $crate::output::tests::STDERR.lock().unwrap().join("\n"); let output = console::strip_ansi_codes(&output.trim()).to_string(); let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); let output = $crate::test::replace_path(&output); diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index d2da32457..c5a673c80 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -6,7 +6,6 @@ use console::{pad_str, style, Alignment}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolsetBuilder}; @@ -22,7 +21,7 @@ pub struct Outdated { } impl Outdated { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let tool_set = self .tool @@ -35,13 +34,13 @@ impl Outdated { if outdated.is_empty() { info!("All tools are up to date"); } else { - self.display(outdated, out); + self.display(outdated); } Ok(()) } - fn display(&self, outdated: OutputVec, out: &mut Output) { + fn display(&self, outdated: OutputVec) { // TODO: make a generic table printer in src/ui/table let plugins = outdated .iter() @@ -90,7 +89,6 @@ impl Outdated { let pad_requested = |s| pad_str(s, requested_width, Alignment::Left, None); let pad_current = |s| pad_str(s, current_width, Alignment::Left, None); rtxprintln!( - out, "{} {} {} {}", style(pad_plugin("Tool")).dim(), style(pad_requested("Requested")).dim(), @@ -99,7 +97,6 @@ impl Outdated { ); for i in 0..outdated.len() { rtxprintln!( - out, "{} {} {} {}", pad_plugin(plugins[i]), pad_requested(&requests[i]), diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index b3c72ba06..6f837f51c 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::{eyre, Result}; use url::Url; use crate::config::Config; -use crate::output::Output; + use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin, PluginName}; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; @@ -46,7 +46,7 @@ pub struct PluginsInstall { } impl PluginsInstall { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); if self.all { return self.install_all_missing_plugins(config, mpr); diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index 5cc4ea571..ffe6400ef 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -7,7 +7,7 @@ use path_absolutize::Absolutize; use crate::config::Config; use crate::file::{make_symlink, remove_all}; -use crate::output::Output; + use crate::plugins::unalias_plugin; use crate::{dirs, file}; @@ -33,7 +33,7 @@ pub struct PluginsLink { } impl PluginsLink { - pub fn run(self, _config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let (name, path) = match self.path { Some(path) => (self.name, path), None => { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index bdba3e470..18bb1c1b4 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; + use crate::plugins::{ExternalPlugin, PluginType}; /// List installed plugins @@ -42,7 +42,7 @@ pub struct PluginsLs { } impl PluginsLs { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mut tools = config.list_plugins().into_iter().collect::>(); if self.all { @@ -60,25 +60,25 @@ impl PluginsLs { if self.urls || self.refs { for tool in tools { - rtxprint!(out, "{:29}", tool.name()); + rtxprint!("{:29}", tool.name()); if self.urls { if let Some(url) = tool.get_remote_url() { - rtxprint!(out, " {}", url); + rtxprint!(" {}", url); } } if self.refs { if let Ok(aref) = tool.current_abbrev_ref() { - rtxprint!(out, " {}", aref); + rtxprint!(" {}", aref); } if let Ok(sha) = tool.current_sha_short() { - rtxprint!(out, " {}", sha); + rtxprint!(" {}", sha); } } - rtxprint!(out, "\n"); + rtxprint!("\n"); } } else { for tool in tools { - rtxprintln!(out, "{tool}"); + rtxprintln!("{tool}"); } } Ok(()) diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 944ee6b1b..539ab1686 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -5,7 +5,6 @@ use console::{measure_text_width, pad_str, Alignment}; use itertools::Itertools; use crate::config::Config; -use crate::output::Output; /// List all available remote plugins #[derive(Debug, clap::Args)] @@ -23,7 +22,7 @@ pub struct PluginsLsRemote { } impl PluginsLsRemote { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let installed_plugins = config .list_plugins() .into_iter() @@ -50,7 +49,7 @@ impl PluginsLsRemote { }; let url = if self.urls { repo } else { "" }; let plugin = pad_str(plugin, max_plugin_len, Alignment::Left, None); - rtxprintln!(out, "{} {}{}", plugin, installed, url); + rtxprintln!("{} {}{}", plugin, installed, url); } Ok(()) diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index dde5e2f4d..91a82efec 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -2,7 +2,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; mod install; mod link; @@ -59,20 +58,20 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self { - Self::Install(cmd) => cmd.run(config, out), - Self::Link(cmd) => cmd.run(config, out), - Self::Ls(cmd) => cmd.run(config, out), - Self::LsRemote(cmd) => cmd.run(config, out), - Self::Uninstall(cmd) => cmd.run(config, out), - Self::Update(cmd) => cmd.run(config, out), + Self::Install(cmd) => cmd.run(config), + Self::Link(cmd) => cmd.run(config), + Self::Ls(cmd) => cmd.run(config), + Self::LsRemote(cmd) => cmd.run(config), + Self::Uninstall(cmd) => cmd.run(config), + Self::Update(cmd) => cmd.run(config), } } } impl Plugins { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::PluginsLs { all: self.all, core: self.core, @@ -81,6 +80,6 @@ impl Plugins { user: self.user, })); - cmd.run(config, out) + cmd.run(config) } } diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 92bd26228..46cbe74d6 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::Result; use console::style; use crate::config::Config; -use crate::output::Output; + use crate::plugins::unalias_plugin; use crate::ui::multi_progress_report::MultiProgressReport; @@ -24,7 +24,7 @@ pub struct PluginsUninstall { } impl PluginsUninstall { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); let plugins = match self.all { diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 75d43eeae..200d853ca 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; + use crate::plugins::{unalias_plugin, PluginName}; /// Updates a plugin to the latest version @@ -20,7 +20,7 @@ pub struct Update { } impl Update { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let plugins: Vec<_> = match self.plugin { Some(plugins) => plugins .into_iter() @@ -42,7 +42,7 @@ impl Update { }; for (plugin, ref_) in plugins { - rtxprintln!(out, "updating plugin {plugin}"); + rtxprintln!("updating plugin {plugin}"); plugin.update(ref_)?; } Ok(()) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 420cdf35e..675f508a6 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -5,7 +5,7 @@ use color_eyre::eyre::Result; use console::style; use crate::config::Config; -use crate::output::Output; + use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -30,7 +30,7 @@ pub struct Prune { } impl Prune { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = ToolsetBuilder::new().build(&config)?; let mut to_delete = ts .list_installed_versions(&config)? diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 65a221bed..73591ee8c 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -6,7 +6,6 @@ use color_eyre::eyre::Result; use crate::cli::self_update::SelfUpdate; use crate::config::Config; -use crate::output::Output; use crate::shell::completions; /// Generate shell completions @@ -23,7 +22,7 @@ pub struct RenderCompletion { } impl RenderCompletion { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let shell = self.shell.or(self.shell_type).unwrap(); let mut cmd = crate::cli::Cli::command().subcommand(SelfUpdate::command()); @@ -37,7 +36,7 @@ impl RenderCompletion { String::from_utf8(c.into_inner()).unwrap() } }; - rtxprintln!(out, "{}", script.trim()); + rtxprintln!("{}", script.trim()); Ok(()) } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 7df6cdad4..b10bad218 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -7,7 +7,6 @@ use crate::cli::self_update::SelfUpdate; use crate::cli::Cli; use crate::config::Config; use crate::file; -use crate::output::Output; /// internal command to generate markdown from help #[derive(Debug, clap::Args)] @@ -15,7 +14,7 @@ use crate::output::Output; pub struct RenderHelp {} impl RenderHelp { - pub fn run(self, _config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let readme = file::read_to_string("README.md")?; let mut current_readme = readme.split(""); diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 7e1aa987a..9a9678724 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -7,7 +7,6 @@ use eyre::Result; use crate::cli::self_update::SelfUpdate; use crate::cli::{version, Cli}; use crate::config::Config; -use crate::output::Output; /// internal command to generate markdown from help #[derive(Debug, clap::Args)] @@ -15,7 +14,7 @@ use crate::output::Output; pub struct RenderMangen {} impl RenderMangen { - pub fn run(self, _config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let cli = Cli::command() .subcommand(SelfUpdate::command()) .version(&*version::RAW_VERSION) diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index bb565aa41..9c8e50e01 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; + use crate::shims; use crate::toolset::ToolsetBuilder; @@ -30,7 +30,7 @@ pub struct Reshim { } impl Reshim { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = ToolsetBuilder::new().build(&config)?; shims::reshim(&config, &ts) diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index fe5735e3a..8b85ef041 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -7,7 +7,7 @@ use self_update::{cargo_crate_version, Status}; use crate::cli::version::{ARCH, OS}; use crate::config::Config; -use crate::output::Output; + use crate::{cmd, env}; /// Updates rtx itself @@ -34,14 +34,14 @@ pub struct SelfUpdate { } impl SelfUpdate { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let status = self.do_update()?; if status.updated() { let version = style(status.version()).bright().yellow(); - rtxprintln!(out, "Updated rtx to {version}"); + rtxprintln!("Updated rtx to {version}"); } else { - rtxprintln!(out, "rtx is already up to date"); + rtxprintln!("rtx is already up to date"); } if !self.no_plugins { cmd!(&*env::RTX_EXE, "plugins", "update").run()?; diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index da0a9097a..2547c4b73 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::{eyre, Result}; use crate::config::Config; -use crate::output::Output; /// Show a current setting /// @@ -17,9 +16,9 @@ pub struct SettingsGet { } impl SettingsGet { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match config.settings.to_index_map().get(&self.key) { - Some(value) => Ok(rtxprintln!(out, "{}", value)), + Some(value) => Ok(rtxprintln!("{}", value)), None => Err(eyre!("Unknown setting: {}", self.key)), } } diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 5526797f7..eb3a6391c 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,7 +1,6 @@ use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; /// Show current settings /// @@ -14,9 +13,9 @@ use crate::output::Output; pub struct SettingsLs {} impl SettingsLs { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { for (key, value) in config.settings.to_index_map() { - rtxprintln!(out, "{} = {}", key, value); + rtxprintln!("{} = {}", key, value); } Ok(()) } diff --git a/src/cli/settings/mod.rs b/src/cli/settings/mod.rs index a7509c221..5dfb50289 100644 --- a/src/cli/settings/mod.rs +++ b/src/cli/settings/mod.rs @@ -2,7 +2,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; mod get; mod ls; @@ -25,20 +24,20 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self { - Self::Get(cmd) => cmd.run(config, out), - Self::Ls(cmd) => cmd.run(config, out), - Self::Set(cmd) => cmd.run(config, out), - Self::Unset(cmd) => cmd.run(config, out), + Self::Get(cmd) => cmd.run(config), + Self::Ls(cmd) => cmd.run(config), + Self::Set(cmd) => cmd.run(config), + Self::Unset(cmd) => cmd.run(config), } } } impl Settings { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::SettingsLs {})); - cmd.run(config, out) + cmd.run(config) } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index b567db0b5..e78089bc9 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -2,7 +2,6 @@ use color_eyre::eyre::{eyre, Result}; use crate::config::config_file::ConfigFile; use crate::config::Config; -use crate::output::Output; /// Add/update a setting /// @@ -18,7 +17,7 @@ pub struct SettingsSet { } impl SettingsSet { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { let value: toml_edit::Value = match self.key.as_str() { "experimental" => parse_bool(&self.value)?, "always_keep_download" => parse_bool(&self.value)?, diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 99e50c227..f71b756ed 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -2,7 +2,6 @@ use color_eyre::eyre::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; -use crate::output::Output; /// Clears a setting /// @@ -15,7 +14,7 @@ pub struct SettingsUnset { } impl SettingsUnset { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { config.global_config.remove_setting(&self.key); config.global_config.save() } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index a1f1d4dc7..cddea016a 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -3,7 +3,6 @@ use console::style; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; use crate::shell::get_shell; use crate::toolset::{ToolSource, ToolsetBuilder}; @@ -23,7 +22,7 @@ pub struct Shell { } impl Shell { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { if !config.is_activated() { err_inactive()?; } @@ -42,7 +41,7 @@ impl Shell { } else { shell.set_env(&k, &tv.version) }; - out.stdout.writeln(op); + rtxprintln!("{op}"); } } diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs index 4fa53055f..2db3317fe 100644 --- a/src/cli/sync/mod.rs +++ b/src/cli/sync/mod.rs @@ -2,7 +2,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; use crate::config::Config; -use crate::output::Output; mod node; mod python; @@ -21,16 +20,16 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { match self { - Self::Node(cmd) => cmd.run(config, out), - Self::Python(cmd) => cmd.run(config, out), + Self::Node(cmd) => cmd.run(config), + Self::Python(cmd) => cmd.run(config), } } } impl Sync { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { - self.command.run(config, out) + pub fn run(self, config: Config) -> Result<()> { + self.command.run(config) } } diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 1c9279c8a..ee7957d4e 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -6,7 +6,6 @@ use itertools::sorted; use crate::config::Config; use crate::env::{NODENV_ROOT, NVM_DIR}; use crate::file; -use crate::output::Output; use crate::plugins::PluginName; use crate::{cmd, dirs}; @@ -37,18 +36,18 @@ pub struct SyncNodeType { } impl SyncNode { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { if self._type.brew { - self.run_brew(config, out)?; + self.run_brew(config)?; } else if self._type.nvm { - self.run_nvm(config, out)?; + self.run_nvm(config)?; } else if self._type.nodenv { - self.run_nodenv(config, out)?; + self.run_nodenv(config)?; } Ok(()) } - fn run_brew(self, config: Config, out: &mut Output) -> Result<()> { + fn run_brew(self, config: Config) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); @@ -63,13 +62,13 @@ impl SyncNode { } let v = entry.trim_start_matches("node@"); tool.create_symlink(v, &brew_prefix.join(&entry))?; - rtxprintln!(out, "Synced node@{} from Homebrew", v); + rtxprintln!("Synced node@{} from Homebrew", v); } config.rebuild_shims_and_runtime_symlinks() } - fn run_nvm(self, config: Config, out: &mut Output) -> Result<()> { + fn run_nvm(self, config: Config) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let nvm_versions_path = NVM_DIR.join("versions").join("node"); @@ -81,13 +80,13 @@ impl SyncNode { for entry in sorted(subdirs) { let v = entry.trim_start_matches('v'); tool.create_symlink(v, &nvm_versions_path.join(&entry))?; - rtxprintln!(out, "Synced node@{} from nvm", v); + rtxprintln!("Synced node@{} from nvm", v); } config.rebuild_shims_and_runtime_symlinks() } - fn run_nodenv(self, config: Config, out: &mut Output) -> Result<()> { + fn run_nodenv(self, config: Config) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let nodenv_versions_path = NODENV_ROOT.join("versions"); @@ -98,7 +97,7 @@ impl SyncNode { let subdirs = file::dir_subdirs(&nodenv_versions_path)?; for v in sorted(subdirs) { tool.create_symlink(&v, &nodenv_versions_path.join(&v))?; - rtxprintln!(out, "Synced node@{} from nodenv", v); + rtxprintln!("Synced node@{} from nodenv", v); } config.rebuild_shims_and_runtime_symlinks() diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index ae28e2faf..9e0e38de7 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -5,7 +5,7 @@ use crate::config::Config; use crate::dirs; use crate::env::PYENV_ROOT; use crate::file; -use crate::output::Output; + use crate::plugins::PluginName; /// Symlinks all tool versions from an external tool into rtx @@ -20,7 +20,7 @@ pub struct SyncPython { } impl SyncPython { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let python = config.get_or_create_plugin(&PluginName::from("python")); let pyenv_versions_path = PYENV_ROOT.join("versions"); @@ -34,7 +34,7 @@ impl SyncPython { let subdirs = file::dir_subdirs(&pyenv_versions_path)?; for v in sorted(subdirs) { python.create_symlink(&v, &pyenv_versions_path.join(&v))?; - rtxprintln!(out, "Synced python@{} from pyenv", v); + rtxprintln!("Synced python@{} from pyenv", v); } config.rebuild_shims_and_runtime_symlinks() diff --git a/src/cli/trust.rs b/src/cli/trust.rs index e412ac33c..c679eb3c1 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -5,7 +5,6 @@ use color_eyre::eyre::Result; use crate::cli::local; use crate::config::{config_file, Config}; -use crate::output::Output; /// Marks a config file as trusted /// @@ -29,17 +28,17 @@ pub struct Trust { } impl Trust { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, _config: Config) -> Result<()> { let path = match &self.config_file { Some(filename) => PathBuf::from(filename), None => local::get_parent_path()?, }; if self.untrust { config_file::untrust(&path)?; - rtxprintln!(out, "untrusted {}", &path.canonicalize()?.display()); + rtxprintln!("untrusted {}", &path.canonicalize()?.display()); } else { config_file::trust(&path)?; - rtxprintln!(out, "trusted {}", &path.canonicalize()?.display()); + rtxprintln!("trusted {}", &path.canonicalize()?.display()); } Ok(()) } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 387ebbc65..f4861fca5 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; + use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -30,7 +30,7 @@ pub struct Uninstall { } impl Uninstall { - pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let tool_versions = if self.tool.is_empty() && self.all { self.get_all_tool_versions(&config)? } else { diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index aaa49eed4..60c536b23 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -6,7 +6,7 @@ use eyre::WrapErr; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; + use crate::plugins::Plugin; use crate::runtime_symlinks; use crate::shims; @@ -30,7 +30,7 @@ pub struct Upgrade { } impl Upgrade { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let tool_set = self .tool @@ -43,13 +43,13 @@ impl Upgrade { if outdated.is_empty() { info!("All tools are up to date"); } else { - self.upgrade(&config, outdated, out)?; + self.upgrade(&config, outdated)?; } Ok(()) } - fn upgrade(&self, config: &Config, outdated: OutputVec, out: &mut Output) -> Result<()> { + fn upgrade(&self, config: &Config, outdated: OutputVec) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; @@ -70,10 +70,10 @@ impl Upgrade { if self.dry_run { for (tool, tv) in &to_remove { - rtxprintln!(out, "Would uninstall {} {}", tool, tv); + rtxprintln!("Would uninstall {} {}", tool, tv); } for tv in &new_versions { - rtxprintln!(out, "Would install {}", tv); + rtxprintln!("Would install {}", tv); } return Ok(()); } diff --git a/src/cli/use.rs b/src/cli/use.rs index 22b6f357c..78666f05a 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -9,7 +9,7 @@ use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; -use crate::output::Output; + use crate::plugins::PluginName; use crate::toolset::ToolsetBuilder; use crate::{dirs, env, file}; @@ -64,7 +64,7 @@ pub struct Use { } impl Use { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; ts.install_arg_versions(&config)?; @@ -95,7 +95,6 @@ impl Use { cf.save()?; let tools = self.tool.iter().map(|t| t.to_string()).join(" "); rtxprintln!( - out, "{} {} {}", style("rtx").dim(), display_path(cf.get_path()), diff --git a/src/cli/version.rs b/src/cli/version.rs index 388c9e154..b155ea3b5 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -11,7 +11,7 @@ use crate::cli::self_update::SelfUpdate; use crate::config::Config; use crate::env::CI; use crate::file::modified_duration; -use crate::output::Output; + use crate::{dirs, duration, file}; #[derive(Debug, clap::Args)] @@ -44,24 +44,24 @@ pub static VERSION: Lazy = Lazy::new(|| { pub static RAW_VERSION: Lazy = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string()); impl Version { - pub fn run(self, _config: Config, out: &mut Output) -> Result<()> { - show_version(out); + pub fn run(self, _config: Config) -> Result<()> { + show_version(); Ok(()) } } -pub fn print_version_if_requested(args: &[String], out: &mut Output) { +pub fn print_version_if_requested(args: &[String]) { if args.len() == 2 && (args[0] == "rtx" || args[0].ends_with("/rtx")) { let cmd = &args[1].to_lowercase(); if cmd == "version" || cmd == "-v" || cmd == "--version" { - show_version(out); + show_version(); std::process::exit(0); } } } -fn show_version(out: &mut Output) { - rtxprintln!(out, "{}", *VERSION); +fn show_version() { + rtxprintln!("{}", *VERSION); show_latest(); } @@ -137,6 +137,6 @@ mod tests { #[test] fn test_version() { let stdout = assert_cli!("version"); - assert_str_eq!(stdout, VERSION.to_string() + "\n"); + assert_str_eq!(stdout, VERSION.to_string()); } } diff --git a/src/cli/where.rs b/src/cli/where.rs index ee81e5e7b..8be4c1471 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -3,7 +3,7 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; -use crate::output::Output; + use crate::toolset::ToolsetBuilder; /// Display the installation path for a runtime @@ -28,7 +28,7 @@ pub struct Where { } impl Where { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let runtime = match self.tool.tvr { None => match self.asdf_version { Some(version) => self.tool.with_version(&version), @@ -55,7 +55,7 @@ impl Where { .map(|tvr| tvr.resolve(&config, plugin.clone(), Default::default(), false)) { Some(Ok(tv)) if plugin.is_version_installed(&tv) => { - rtxprintln!(out, "{}", tv.install_path().to_string_lossy()); + rtxprintln!("{}", tv.install_path().to_string_lossy()); Ok(()) } _ => Err(VersionNotInstalled( diff --git a/src/cli/which.rs b/src/cli/which.rs index f580a3501..c0aa7f4d4 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::{eyre, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::output::Output; + use crate::toolset::{Toolset, ToolsetBuilder}; /// Shows the path that a bin name points to @@ -28,18 +28,18 @@ pub struct Which { } impl Which { - pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config) -> Result<()> { let ts = self.get_toolset(&config)?; match ts.which(&config, &self.bin_name) { Some((p, tv)) => { if self.version { - rtxprintln!(out, "{}", tv.version); + rtxprintln!("{}", tv.version); } else if self.plugin { - rtxprintln!(out, "{p}"); + rtxprintln!("{p}"); } else { let path = p.which(&config, &ts, &tv, &self.bin_name)?; - rtxprintln!(out, "{}", path.unwrap().display()); + rtxprintln!("{}", path.unwrap().display()); } Ok(()) } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 97c7a08b4..3d1532572 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -13,7 +13,7 @@ use crate::config::settings::SettingsPartial; use crate::config::{global_config_files, AliasMap, Config, Settings}; use crate::file::{display_path, replace_path}; use crate::hash::hash_to_str; -use crate::output::Output; + use crate::plugins::PluginName; use crate::toolset::{ToolVersion, ToolVersionList, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -121,7 +121,7 @@ impl dyn ConfigFile { /// this is for `rtx local|global TOOL` which will display the version instead of setting it /// it's only valid to use a single tool in this case /// returns "true" if the tool was displayed which means the CLI should exit - pub fn display_runtime(&self, out: &mut Output, runtimes: &[ToolArg]) -> Result { + pub fn display_runtime(&self, runtimes: &[ToolArg]) -> Result { // in this situation we just print the current version in the config file if runtimes.len() == 1 && runtimes[0].tvr.is_none() { let plugin = &runtimes[0].plugin; @@ -140,7 +140,7 @@ impl dyn ConfigFile { .iter() .map(|(tvr, _)| tvr.version()) .collect::>(); - rtxprintln!(out, "{}", tvl.join(" ")); + rtxprintln!("{}", tvl.join(" ")); return Ok(true); } // check for something like `rtx local node python@latest` which is invalid diff --git a/src/main.rs b/src/main.rs index 228a00195..8dd232f7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,6 @@ use console::{style, Term}; use crate::cli::version::VERSION; use crate::cli::Cli; use crate::config::Config; -use crate::output::Output; #[macro_use] mod output; @@ -80,19 +79,17 @@ fn main() -> Result<()> { } fn run(args: &Vec) -> Result<()> { - let out = &mut Output::new(); - // show version before loading config in case of error - cli::version::print_version_if_requested(&env::ARGS, out); + cli::version::print_version_if_requested(&env::ARGS); migrate::run(); let config = Config::load()?; - let config = shims::handle_shim(config, args, out)?; + let config = shims::handle_shim(config, args)?; if config.should_exit_early { return Ok(()); } let cli = Cli::new_with_external_commands(&config); - cli.run(config, args, out) + cli.run(config, args) } fn handle_ctrlc() { diff --git a/src/output.rs b/src/output.rs index 87f1a1c11..59567a1f9 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,97 +1,67 @@ -use std::io; -use std::io::Write; -use std::process::ExitCode; - -#[derive(Debug)] -pub enum OutputType { - Stdout, - Stderr, -} - -#[derive(Debug)] -pub struct Output { - pub stdout: OutputStream, - pub stderr: OutputStream, - pub status: ExitCode, -} - -impl Output { - pub fn new() -> Self { - Self { - stdout: OutputStream::new(OutputType::Stdout), - stderr: OutputStream::new(OutputType::Stderr), - status: ExitCode::from(0), - } - } - - #[cfg(test)] - pub fn tracked() -> Self { - let mut output = Self::new(); - output.stdout.track = true; - output.stderr.track = true; - - output - } -} - -impl Default for Output { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug)] -pub struct OutputStream { - pub content: String, - pub output_type: OutputType, - pub track: bool, -} - -impl OutputStream { - pub fn new(output_type: OutputType) -> Self { - Self { - content: Default::default(), - track: false, - output_type, - } - } - pub fn write(&mut self, content: String) { - if self.track { - self.content.push_str(&content); - } else { - let _ = match self.output_type { - OutputType::Stdout => io::stdout().write(content.as_bytes()), - OutputType::Stderr => io::stderr().write(content.as_bytes()), - }; - } - } - - pub fn writeln(&mut self, content: String) { - self.write(format!("{content}\n")); - } +#[cfg(test)] +#[macro_export] +macro_rules! rtxprintln { + () => { + rtxprint!("\n") + }; + ($($arg:tt)*) => {{ + let mut stdout = $crate::output::tests::STDOUT.lock().unwrap(); + stdout.push(format!($($arg)*)); + }}; } +#[cfg(not(test))] #[macro_export] macro_rules! rtxprintln { () => { rtxprint!("\n") }; - ($out:ident, $($arg:tt)*) => {{ - $out.stdout.writeln(format!($($arg)*)); + ($($arg:tt)*) => {{ + println!($($arg)*); }}; } +#[cfg(test)] #[macro_export] macro_rules! rtxprint { - ($out:ident, $($arg:tt)*) => {{ - $out.stdout.write(format!($($arg)*)); + ($($arg:tt)*) => {{ + let mut stdout = $crate::output::tests::STDOUT.lock().unwrap(); + let cur = stdout.pop().unwrap_or_default(); + stdout.push(cur + &format!($($arg)*)); }}; } +#[cfg(not(test))] +#[macro_export] +macro_rules! rtxprint { + ($($arg:tt)*) => {{ + print!($($arg)*); + }}; +} + +#[cfg(test)] #[macro_export] macro_rules! rtxstatusln { - ($out:ident, $($arg:tt)*) => {{ + ($($arg:tt)*) => {{ + let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); + let rtx = console::style("rtx ").dim().for_stderr(); + stderr.push(format!("{}{}", rtx, format!($($arg)*))); + }}; + } + +#[cfg(not(test))] +#[macro_export] +macro_rules! rtxstatusln { + ($($arg:tt)*) => {{ let rtx = console::style("rtx ").dim().for_stderr(); - $out.stderr.writeln(format!("{}{}", rtx, format!($($arg)*))); + eprintln!("{}{}", rtx, format!($($arg)*)); }}; } + +#[cfg(test)] +pub mod tests { + use std::sync::Mutex; + + pub static STDOUT: Mutex> = Mutex::new(Vec::new()); + pub static STDERR: Mutex> = Mutex::new(Vec::new()); +} diff --git a/src/shims.rs b/src/shims.rs index fc2f644dd..212ffc620 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -16,14 +16,14 @@ use crate::env; use crate::fake_asdf; use crate::file::{create_dir_all, display_path, remove_all}; use crate::lock_file::LockFile; -use crate::output::Output; + use crate::plugins::Plugin; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; 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(config: Config, args: &[String], out: &mut Output) -> Result { +pub fn handle_shim(config: Config, args: &[String]) -> Result { let (_, bin_name) = args[0].rsplit_once('/').unwrap_or(("", &args[0])); if bin_name == "rtx" { return Ok(config); @@ -36,7 +36,7 @@ pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result< command: Some(args), cd: None, }; - exec.run(config, out)?; + exec.run(config)?; exit(0); } From 11ec133f2cb7d503e51ffe36de963a43c593214e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:54:38 -0600 Subject: [PATCH 1292/1891] ls: allow passing multiple plugins to filter (#1164) --- README.md | 8 ++++---- completions/_rtx | 2 +- completions/rtx.bash | 2 +- src/cli/ls.rs | 30 ++++++++++++++++-------------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 5bad41ed6..0f997f743 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ v20.0.0 - [`rtx install [OPTIONS] [TOOL@VERSION]...`](#rtx-install-options-toolversion) - [`rtx latest [OPTIONS] `](#rtx-latest-options-toolversion) - [`rtx link [OPTIONS] `](#rtx-link-options-toolversion-path) - - [`rtx ls [OPTIONS] [PLUGIN]`](#rtx-ls-options-plugin) + - [`rtx ls [OPTIONS] [PLUGIN]...`](#rtx-ls-options-plugin) - [`rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]`](#rtx-ls-remote-options-toolversion-prefix) - [`rtx outdated [TOOL@VERSION]...`](#rtx-outdated-toolversion) - [`rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]`](#rtx-plugins-install-options-new_plugin-git_url) @@ -2084,15 +2084,15 @@ Examples: $ rtx use node@brew ``` -### `rtx ls [OPTIONS] [PLUGIN]` +### `rtx ls [OPTIONS] [PLUGIN]...` ```text List installed and/or currently selected tool versions -Usage: ls [OPTIONS] [PLUGIN] +Usage: ls [OPTIONS] [PLUGIN]... Arguments: - [PLUGIN] + [PLUGIN]... Only show tool versions from [PLUGIN] Options: diff --git a/completions/_rtx b/completions/_rtx index fb60bac41..9cddd3dd3 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -405,7 +405,7 @@ __rtx_local_cmd() { (( $+functions[__rtx_ls_cmd] )) || __rtx_ls_cmd() { _arguments -s -S \ - '::plugin:__rtx_plugins' \ + '*::plugin:__rtx_plugins' \ '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 3cf07db92..964e1d0d4 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2449,7 +2449,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -J -m -j -q -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]" + opts="-p -c -g -i -J -m -j -q -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 7a27e2fa7..79287c6bd 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -22,10 +22,10 @@ use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; pub struct Ls { /// Only show tool versions from [PLUGIN] #[clap(conflicts_with = "plugin_flag")] - plugin: Option, + plugin: Option>, #[clap(long = "plugin", short, hide = true)] - plugin_flag: Option, + plugin_flag: Option, /// Only show tool versions currently specified in a .tool-versions/.rtx.toml #[clap(long, short)] @@ -61,9 +61,8 @@ impl Ls { pub fn run(mut self, config: Config) -> Result<()> { self.plugin = self .plugin - .clone() - .or(self.plugin_flag.clone()) - .map(|p| PluginName::from(unalias_plugin(&p))); + .or_else(|| self.plugin_flag.clone().map(|p| vec![p])) + .map(|p| p.into_iter().map(|p| unalias_plugin(&p).into()).collect()); self.verify_plugin(&config)?; let mut runtimes = self.get_runtime_list(&config)?; @@ -92,10 +91,12 @@ impl Ls { fn verify_plugin(&self, config: &Config) -> Result<()> { match &self.plugin { - Some(plugin_name) => { - let plugin = config.get_or_create_plugin(plugin_name); - if !plugin.is_installed() { - return Err(PluginNotInstalled(plugin_name.clone()))?; + Some(plugins) => { + for plugin_name in plugins { + let plugin = config.get_or_create_plugin(plugin_name); + if !plugin.is_installed() { + return Err(PluginNotInstalled(plugin_name.clone()))?; + } } } None => {} @@ -104,11 +105,11 @@ impl Ls { } fn display_json(&self, runtimes: Vec) -> Result<()> { - if let Some(plugin) = &self.plugin { + if let Some(plugins) = &self.plugin { // only runtimes for 1 plugin let runtimes: Vec = runtimes .into_iter() - .filter(|(p, _, _)| plugin.eq(&p.name())) + .filter(|(p, _, _)| plugins.contains(&p.name().to_string())) .map(|row| row.into()) .collect(); rtxprintln!("{}", serde_json::to_string_pretty(&runtimes)?); @@ -206,8 +207,9 @@ impl Ls { 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]); + if let Some(plugins) = &self.plugin { + let plugins = plugins.iter().map(|p| p.as_str()).collect_vec(); + tsb = tsb.with_tools(&plugins); } let ts = tsb.build(config)?; let mut versions: HashMap<(String, String), (Arc, ToolVersion)> = ts @@ -227,7 +229,7 @@ impl Ls { let rvs: Vec = versions .into_iter() .filter(|((plugin_name, _), _)| match &self.plugin { - Some(p) => p.eq(plugin_name), + Some(p) => p.contains(plugin_name), None => true, }) .sorted_by_cached_key(|((plugin_name, version), _)| { From e1cd1fc1d9a8159bb3b13fcb9bbf633406e54cdc Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:56:39 -0600 Subject: [PATCH 1293/1891] completions: improve completions for ls-remote and uninstall (#1165) --- completions/_rtx | 23 +++++++++++++++++++---- completions/rtx.fish | 10 +++++++++- src/cli/uninstall.rs | 6 +++--- src/shell/completions/fish_complete.rs | 9 +++++++++ src/shell/completions/zsh_complete.rs | 22 +++++++++++++++++++--- 5 files changed, 59 insertions(+), 11 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index 9cddd3dd3..0b79f829f 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -709,7 +709,7 @@ __rtx_trust_cmd() { (( $+functions[__rtx_uninstall_cmd] )) || __rtx_uninstall_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::installed_tool:__rtx_installed_tool_versions' \ '(-a --all)'{-a,--all}'[Delete all installed versions]' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ @@ -876,7 +876,20 @@ __rtx_tool_versions() { if compset -P '*@'; then local -a tool_versions; tool_versions=($(rtx ls-remote ${words[CURRENT]})) _wanted tool_version expl 'version of tool' \ - compadd -a tool_versions + compadd -a tool_versions -o nosort + else + local -a plugins; plugins=($(rtx plugins --core --user)) + _wanted plugin expl 'plugin name' \ + compadd -S '@' -a plugins + fi +} +(( $+functions[__rtx_installed_tool_versions] )) || +__rtx_installed_tool_versions() { + if compset -P '*@'; then + local plugin; plugin=${words[CURRENT]%%@*} + local -a installed_tool_versions; installed_tool_versions=($(rtx ls --installed $plugin | awk '{print $2}')) + _wanted installed_tool_version expl 'version of tool' \ + compadd -a installed_tool_versions -o nosort else local -a plugins; plugins=($(rtx plugins --core --user)) _wanted plugin expl 'plugin name' \ @@ -900,8 +913,10 @@ __rtx_aliases() { } (( $+functions[__rtx_prefixes] )) || __rtx_prefixes() { - local -a prefixes; prefixes=($(rtx ls-remote ${words[CURRENT-1]})) - _describe -t prefixes 'prefix' prefixes "$@" + if [[ CURRENT -gt 2 ]]; then + local -a prefixes; prefixes=($(rtx ls-remote ${words[CURRENT-1]})) + _describe -t prefixes 'prefix' prefixes "$@" + fi } if [ "$funcstack[1]" = "_rtx" ]; then diff --git a/completions/rtx.fish b/completions/rtx.fish index a840a74e9..e8edcaf0c 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -249,7 +249,7 @@ complete -xc rtx -n "$fssf trust" -l untrust -d 'No longer trust this config' # uninstall complete -xc rtx -n "$fssf uninstall" -s a -l all -d 'Delete all installed versions' complete -xc rtx -n "$fssf uninstall" -s n -l dry-run -d 'Do not actually delete anything' -complete -xc rtx -n "$fssf uninstall" -a "(__rtx_tool_versions)" -d 'Tool(s) to remove' +complete -xc rtx -n "$fssf uninstall" -a "(__rtx_installed_tool_versions)" -d 'Tool(s) to remove' # upgrade complete -xc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' @@ -301,5 +301,13 @@ function __rtx_tool_versions echo $tv end end +function __rtx_installed_tool_versions + if test -z "$__rtx_installed_tool_versions_cache" + set -g __rtx_installed_tool_versions_cache (rtx ls --installed | awk '{print $1 "@" $2}') + end + for tv in $__rtx_installed_tool_versions_cache + echo $tv + end +end # vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index f4861fca5..b23ce6ff7 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -18,7 +18,7 @@ use crate::{runtime_symlinks, shims}; pub struct Uninstall { /// Tool(s) to remove #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, required_unless_present = "all")] - tool: Vec, + installed_tool: Vec, /// Delete all installed versions #[clap(long, short)] @@ -31,7 +31,7 @@ pub struct Uninstall { impl Uninstall { pub fn run(self, config: Config) -> Result<()> { - let tool_versions = if self.tool.is_empty() && self.all { + let tool_versions = if self.installed_tool.is_empty() && self.all { self.get_all_tool_versions(&config)? } else { self.get_requested_tool_versions(&config)? @@ -87,7 +87,7 @@ impl Uninstall { &self, config: &Config, ) -> Result, ToolVersion)>> { - let runtimes = ToolArg::double_tool_condition(&self.tool); + let runtimes = ToolArg::double_tool_condition(&self.installed_tool); let tool_versions = runtimes .into_par_iter() .map(|a| { diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index f9a06f2a8..28cc7c9ff 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -37,6 +37,14 @@ function __rtx_tool_versions echo $tv end end +function __rtx_installed_tool_versions + if test -z "$__rtx_installed_tool_versions_cache" + set -g __rtx_installed_tool_versions_cache (rtx ls --installed | awk '{{print $1 "@" $2}}') + end + for tv in $__rtx_installed_tool_versions_cache + echo $tv + end +end # vim: noet ci pi sts=0 sw=4 ts=4 "#} @@ -92,6 +100,7 @@ fn render_completer(a: &Arg) -> Option { ValueHint::AnyPath => Some("(__fish_complete_path)".to_string()), _ => match a.get_id().as_str() { "tool" => Some("(__rtx_tool_versions)".to_string()), + "installed_tool" => Some("(__rtx_installed_tool_versions)".to_string()), "plugin" => Some("(__rtx_plugins)".to_string()), "new_plugin" => Some("(__rtx_all_plugins)".to_string()), //"alias" => Some("(__rtx_aliases)".to_string()), diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index 38c0100a0..1ba43cb45 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -25,7 +25,20 @@ pub fn render(cmd: &Command) -> String { if compset -P '*@'; then local -a tool_versions; tool_versions=($(rtx ls-remote ${{words[CURRENT]}})) _wanted tool_version expl 'version of tool' \ - compadd -a tool_versions + compadd -a tool_versions -o nosort + else + local -a plugins; plugins=($(rtx plugins --core --user)) + _wanted plugin expl 'plugin name' \ + compadd -S '@' -a plugins + fi + }} + (( $+functions[__rtx_installed_tool_versions] )) || + __rtx_installed_tool_versions() {{ + if compset -P '*@'; then + local plugin; plugin=${{words[CURRENT]%%@*}} + local -a installed_tool_versions; installed_tool_versions=($(rtx ls --installed $plugin | awk '{{print $2}}')) + _wanted installed_tool_version expl 'version of tool' \ + compadd -a installed_tool_versions -o nosort else local -a plugins; plugins=($(rtx plugins --core --user)) _wanted plugin expl 'plugin name' \ @@ -49,8 +62,10 @@ pub fn render(cmd: &Command) -> String { }} (( $+functions[__rtx_prefixes] )) || __rtx_prefixes() {{ - local -a prefixes; prefixes=($(rtx ls-remote ${{words[CURRENT-1]}})) - _describe -t prefixes 'prefix' prefixes "$@" + if [[ CURRENT -gt 2 ]]; then + local -a prefixes; prefixes=($(rtx ls-remote ${{words[CURRENT-1]}})) + _describe -t prefixes 'prefix' prefixes "$@" + fi }} if [ "$funcstack[1]" = "_rtx" ]; then @@ -209,6 +224,7 @@ fn render_completion(arg: &Arg) -> String { ValueHint::Other => "( )".to_string(), _ => match arg.get_id().as_str() { "tool" => "__rtx_tool_versions".to_string(), + "installed_tool" => "__rtx_installed_tool_versions".to_string(), "plugin" => "__rtx_plugins".to_string(), "new_plugin" => "__rtx_all_plugins".to_string(), "alias" => "__rtx_aliases".to_string(), From 631c53d3d219869285ef49e6ec7a7055135ce482 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:06:27 -0600 Subject: [PATCH 1294/1891] completions: improve fish tool completions (#1167) #97 --- completions/rtx.fish | 216 ++++++++++++------------- src/shell/completions/fish_complete.rs | 4 +- 2 files changed, 110 insertions(+), 110 deletions(-) diff --git a/completions/rtx.fish b/completions/rtx.fish index e8edcaf0c..f00d50013 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,11 +1,11 @@ set -l fssf "__fish_seen_subcommand_from" # rtx -complete -xc rtx -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' -complete -xc rtx -s q -l quiet -d 'Suppress output' -complete -xc rtx -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user.' -complete -xc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' -complete -xc rtx -s y -l yes -d 'Answer yes to all prompts' +complete -kxc rtx -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' +complete -kxc rtx -s q -l quiet -d 'Suppress output' +complete -kxc rtx -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user.' +complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' +complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' set -l others activate alias bin-paths cache completion current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell' complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' @@ -42,11 +42,11 @@ complete -xc rtx -n "not $fssf $others" -a where -d 'Display the installation pa complete -xc rtx -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' # activate -complete -xc rtx -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' -complete -xc rtx -n "$fssf activate" -l status -d 'Show "rtx: @" message when changing directories' +complete -kxc rtx -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' +complete -kxc rtx -n "$fssf activate" -l status -d 'Show "rtx: @" message when changing directories' # alias -complete -xc rtx -n "$fssf alias" -s p -l plugin -a "(__rtx_plugins)" -d 'filter aliases by plugin' +complete -kxc rtx -n "$fssf alias" -s p -l plugin -a "(__rtx_plugins)" -d 'filter aliases by plugin' set -l others get ls set unset complete -xc rtx -n "$fssf alias; and not $fssf $others" -a get -d 'Show an alias for a plugin' complete -xc rtx -n "$fssf alias; and not $fssf $others" -a ls -d 'List aliases' @@ -54,20 +54,20 @@ complete -xc rtx -n "$fssf alias; and not $fssf $others" -a set -d 'Add/update a complete -xc rtx -n "$fssf alias; and not $fssf $others" -a unset -d 'Clears an alias for a plugin' # alias get -complete -xc rtx -n "$fssf alias; and $fssf get" -d 'The alias to show' -complete -xc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_plugins)" -d 'The plugin to show the alias for' +complete -kxc rtx -n "$fssf alias; and $fssf get" -d 'The alias to show' +complete -kxc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_plugins)" -d 'The plugin to show the alias for' # alias ls -complete -xc rtx -n "$fssf alias; and $fssf ls" -a "(__rtx_plugins)" -d 'Show aliases for ' +complete -kxc rtx -n "$fssf alias; and $fssf ls" -a "(__rtx_plugins)" -d 'Show aliases for ' # alias set -complete -xc rtx -n "$fssf alias; and $fssf set" -d 'The alias to set' -complete -xc rtx -n "$fssf alias; and $fssf set" -a "(__rtx_plugins)" -d 'The plugin to set the alias for' -complete -xc rtx -n "$fssf alias; and $fssf set" -d 'The value to set the alias to' +complete -kxc rtx -n "$fssf alias; and $fssf set" -d 'The alias to set' +complete -kxc rtx -n "$fssf alias; and $fssf set" -a "(__rtx_plugins)" -d 'The plugin to set the alias for' +complete -kxc rtx -n "$fssf alias; and $fssf set" -d 'The value to set the alias to' # alias unset -complete -xc rtx -n "$fssf alias; and $fssf unset" -d 'The alias to remove' -complete -xc rtx -n "$fssf alias; and $fssf unset" -a "(__rtx_plugins)" -d 'The plugin to remove the alias from' +complete -kxc rtx -n "$fssf alias; and $fssf unset" -d 'The alias to remove' +complete -kxc rtx -n "$fssf alias; and $fssf unset" -a "(__rtx_plugins)" -d 'The plugin to remove the alias from' # bin-paths @@ -77,14 +77,14 @@ set -l others clear complete -xc rtx -n "$fssf cache; and not $fssf $others" -a clear -d 'Deletes all cache files in rtx' # cache clear -complete -xc rtx -n "$fssf cache; and $fssf clear" -a "(__rtx_plugins)" -d 'Plugin(s) to clear cache for e.g.: node, python' +complete -kxc rtx -n "$fssf cache; and $fssf clear" -a "(__rtx_plugins)" -d 'Plugin(s) to clear cache for e.g.: node, python' # completion -complete -xc rtx -n "$fssf completion" -a "bash fish zsh" -d 'Shell type to generate completions for' +complete -kxc rtx -n "$fssf completion" -a "bash fish zsh" -d 'Shell type to generate completions for' # current -complete -xc rtx -n "$fssf current" -a "(__rtx_plugins)" -d 'Plugin to show versions of e.g.: ruby, node' +complete -kxc rtx -n "$fssf current" -a "(__rtx_plugins)" -d 'Plugin to show versions of e.g.: ruby, node' # deactivate @@ -98,61 +98,61 @@ complete -xc rtx -n "$fssf direnv; and not $fssf $others" -a activate -d 'Output # doctor # env -complete -xc rtx -n "$fssf env" -s J -l json -d 'Output in JSON format' -complete -xc rtx -n "$fssf env" -s s -l shell -a "bash fish nu xonsh zsh" -d 'Shell type to generate environment variables for' -complete -xc rtx -n "$fssf env" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' +complete -kxc rtx -n "$fssf env" -s J -l json -d 'Output in JSON format' +complete -kxc rtx -n "$fssf env" -s s -l shell -a "bash fish nu xonsh zsh" -d 'Shell type to generate environment variables for' +complete -kxc rtx -n "$fssf env" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' # env-vars -complete -xc rtx -n "$fssf env-vars" -d 'Environment variable(s) to set' -complete -xc rtx -n "$fssf env-vars" -l file -a "(__fish_complete_path)" -d 'The TOML file to update' -complete -xc rtx -n "$fssf env-vars" -l remove -d 'Remove the environment variable from config file' +complete -kxc rtx -n "$fssf env-vars" -d 'Environment variable(s) to set' +complete -kxc rtx -n "$fssf env-vars" -l file -a "(__fish_complete_path)" -d 'The TOML file to update' +complete -kxc rtx -n "$fssf env-vars" -l remove -d 'Remove the environment variable from config file' # exec -complete -xc rtx -n "$fssf exec" -s c -l command -d 'Command string to execute' -complete -xc rtx -n "$fssf exec" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' -complete -xc rtx -n "$fssf exec" -d 'Command string to execute (same as --command)' -complete -xc rtx -n "$fssf exec" -a "(__rtx_tool_versions)" -d 'Tool(s) to start e.g.: node@20 python@3.10' +complete -kxc rtx -n "$fssf exec" -s c -l command -d 'Command string to execute' +complete -kxc rtx -n "$fssf exec" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' +complete -kxc rtx -n "$fssf exec" -d 'Command string to execute (same as --command)' +complete -kxc rtx -n "$fssf exec" -a "(__rtx_tool_versions)" -d 'Tool(s) to start e.g.: node@20 python@3.10' # implode -complete -xc rtx -n "$fssf implode" -l config -d 'Also remove config directory' -complete -xc rtx -n "$fssf implode" -s n -l dry-run -d 'List directories that would be removed without actually removing them' +complete -kxc rtx -n "$fssf implode" -l config -d 'Also remove config directory' +complete -kxc rtx -n "$fssf implode" -s n -l dry-run -d 'List directories that would be removed without actually removing them' # install -complete -xc rtx -n "$fssf install" -s f -l force -d 'Force reinstall even if already installed' -complete -xc rtx -n "$fssf install" -a "(__rtx_tool_versions)" -d 'Tool(s) to install e.g.: node@20' -complete -xc rtx -n "$fssf install" -s v -l verbose -d 'Show installation output' +complete -kxc rtx -n "$fssf install" -s f -l force -d 'Force reinstall even if already installed' +complete -kxc rtx -n "$fssf install" -a "(__rtx_tool_versions)" -d 'Tool(s) to install e.g.: node@20' +complete -kxc rtx -n "$fssf install" -s v -l verbose -d 'Show installation output' # latest -complete -xc rtx -n "$fssf latest" -s i -l installed -d 'Show latest installed instead of available version' -complete -xc rtx -n "$fssf latest" -a "(__rtx_tool_versions)" -d 'Tool to get the latest version of' +complete -kxc rtx -n "$fssf latest" -s i -l installed -d 'Show latest installed instead of available version' +complete -kxc rtx -n "$fssf latest" -a "(__rtx_tool_versions)" -d 'Tool to get the latest version of' # link -complete -xc rtx -n "$fssf link" -s f -l force -d 'Overwrite an existing tool version if it exists' -complete -xc rtx -n "$fssf link" -a "(__fish_complete_directories)" -d 'The local path to the tool version' -complete -xc rtx -n "$fssf link" -a "(__rtx_tool_versions)" -d 'Tool name and version to create a symlink for' +complete -kxc rtx -n "$fssf link" -s f -l force -d 'Overwrite an existing tool version if it exists' +complete -kxc rtx -n "$fssf link" -a "(__fish_complete_directories)" -d 'The local path to the tool version' +complete -kxc rtx -n "$fssf link" -a "(__rtx_tool_versions)" -d 'Tool name and version to create a symlink for' # ls -complete -xc rtx -n "$fssf ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' -complete -xc rtx -n "$fssf ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' -complete -xc rtx -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' -complete -xc rtx -n "$fssf ls" -s J -l json -d 'Output in json format' -complete -xc rtx -n "$fssf ls" -s m -l missing -d 'Display missing tool versions' -complete -xc rtx -n "$fssf ls" -a "(__rtx_plugins)" -d 'Only show tool versions from [PLUGIN]' -complete -xc rtx -n "$fssf ls" -l prefix -d 'Display versions matching this prefix' +complete -kxc rtx -n "$fssf ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' +complete -kxc rtx -n "$fssf ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' +complete -kxc rtx -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' +complete -kxc rtx -n "$fssf ls" -s J -l json -d 'Output in json format' +complete -kxc rtx -n "$fssf ls" -s m -l missing -d 'Display missing tool versions' +complete -kxc rtx -n "$fssf ls" -a "(__rtx_plugins)" -d 'Only show tool versions from [PLUGIN]' +complete -kxc rtx -n "$fssf ls" -l prefix -d 'Display versions matching this prefix' # ls-remote -complete -xc rtx -n "$fssf ls-remote" -l all -d 'Show all installed plugins and versions' -complete -xc rtx -n "$fssf ls-remote" -a "(__rtx_plugins)" -d 'Plugin to get versions for' -complete -xc rtx -n "$fssf ls-remote" -d 'The version prefix to use when querying the latest version' +complete -kxc rtx -n "$fssf ls-remote" -l all -d 'Show all installed plugins and versions' +complete -kxc rtx -n "$fssf ls-remote" -a "(__rtx_plugins)" -d 'Plugin to get versions for' +complete -kxc rtx -n "$fssf ls-remote" -d 'The version prefix to use when querying the latest version' # outdated -complete -xc rtx -n "$fssf outdated" -a "(__rtx_tool_versions)" -d 'Tool(s) to show outdated versions for' +complete -kxc rtx -n "$fssf outdated" -a "(__rtx_tool_versions)" -d 'Tool(s) to show outdated versions for' # plugins -complete -xc rtx -n "$fssf plugins" -s c -l core -d 'The built-in plugins only' -complete -xc rtx -n "$fssf plugins" -l refs -d 'show the git refs for each plugin' -complete -xc rtx -n "$fssf plugins" -s u -l urls -d 'show the git url for each plugin' -complete -xc rtx -n "$fssf plugins" -l user -d 'List installed plugins' +complete -kxc rtx -n "$fssf plugins" -s c -l core -d 'The built-in plugins only' +complete -kxc rtx -n "$fssf plugins" -l refs -d 'show the git refs for each plugin' +complete -kxc rtx -n "$fssf plugins" -s u -l urls -d 'show the git url for each plugin' +complete -kxc rtx -n "$fssf plugins" -l user -d 'List installed plugins' set -l others install link ls ls-remote uninstall update complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a install -d 'Install a plugin' complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a link -d 'Symlinks a plugin into rtx' @@ -162,47 +162,47 @@ complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a uninstall -d 'Remo complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a update -d 'Updates a plugin to the latest version' # plugins install -complete -xc rtx -n "$fssf plugins; and $fssf install" -s a -l all -d 'Install all missing plugins' -complete -xc rtx -n "$fssf plugins; and $fssf install" -s f -l force -d 'Reinstall even if plugin exists' -complete -xc rtx -n "$fssf plugins; and $fssf install" -d 'The git url of the plugin' -complete -xc rtx -n "$fssf plugins; and $fssf install" -a "(__rtx_all_plugins)" -d 'The name of the plugin to install' -complete -xc rtx -n "$fssf plugins; and $fssf install" -s v -l verbose -d 'Show installation output' +complete -kxc rtx -n "$fssf plugins; and $fssf install" -s a -l all -d 'Install all missing plugins' +complete -kxc rtx -n "$fssf plugins; and $fssf install" -s f -l force -d 'Reinstall even if plugin exists' +complete -kxc rtx -n "$fssf plugins; and $fssf install" -d 'The git url of the plugin' +complete -kxc rtx -n "$fssf plugins; and $fssf install" -a "(__rtx_all_plugins)" -d 'The name of the plugin to install' +complete -kxc rtx -n "$fssf plugins; and $fssf install" -s v -l verbose -d 'Show installation output' # plugins link -complete -xc rtx -n "$fssf plugins; and $fssf link" -s f -l force -d 'Overwrite existing plugin' -complete -xc rtx -n "$fssf plugins; and $fssf link" -d 'The name of the plugin' -complete -xc rtx -n "$fssf plugins; and $fssf link" -a "(__fish_complete_directories)" -d 'The local path to the plugin' +complete -kxc rtx -n "$fssf plugins; and $fssf link" -s f -l force -d 'Overwrite existing plugin' +complete -kxc rtx -n "$fssf plugins; and $fssf link" -d 'The name of the plugin' +complete -kxc rtx -n "$fssf plugins; and $fssf link" -a "(__fish_complete_directories)" -d 'The local path to the plugin' # plugins ls -complete -xc rtx -n "$fssf plugins; and $fssf ls" -s c -l core -d 'The built-in plugins only' -complete -xc rtx -n "$fssf plugins; and $fssf ls" -l refs -d 'Show the git refs for each plugin' -complete -xc rtx -n "$fssf plugins; and $fssf ls" -s u -l urls -d 'Show the git url for each plugin' -complete -xc rtx -n "$fssf plugins; and $fssf ls" -l user -d 'List installed plugins' +complete -kxc rtx -n "$fssf plugins; and $fssf ls" -s c -l core -d 'The built-in plugins only' +complete -kxc rtx -n "$fssf plugins; and $fssf ls" -l refs -d 'Show the git refs for each plugin' +complete -kxc rtx -n "$fssf plugins; and $fssf ls" -s u -l urls -d 'Show the git url for each plugin' +complete -kxc rtx -n "$fssf plugins; and $fssf ls" -l user -d 'List installed plugins' # plugins ls-remote -complete -xc rtx -n "$fssf plugins; and $fssf ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' -complete -xc rtx -n "$fssf plugins; and $fssf ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' +complete -kxc rtx -n "$fssf plugins; and $fssf ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' +complete -kxc rtx -n "$fssf plugins; and $fssf ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' # plugins uninstall -complete -xc rtx -n "$fssf plugins; and $fssf uninstall" -s a -l all -d 'Remove all plugins' -complete -xc rtx -n "$fssf plugins; and $fssf uninstall" -a "(__rtx_plugins)" -d 'Plugin(s) to remove' -complete -xc rtx -n "$fssf plugins; and $fssf uninstall" -s p -l purge -d 'Also remove the plugin'\''s installs, downloads, and cache' +complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -s a -l all -d 'Remove all plugins' +complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -a "(__rtx_plugins)" -d 'Plugin(s) to remove' +complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -s p -l purge -d 'Also remove the plugin'\''s installs, downloads, and cache' # plugins update -complete -xc rtx -n "$fssf plugins; and $fssf update" -a "(__rtx_plugins)" -d 'Plugin(s) to update' +complete -kxc rtx -n "$fssf plugins; and $fssf update" -a "(__rtx_plugins)" -d 'Plugin(s) to update' # prune -complete -xc rtx -n "$fssf prune" -s n -l dry-run -d 'Do not actually delete anything' -complete -xc rtx -n "$fssf prune" -a "(__rtx_plugins)" -d 'Prune only versions from these plugins' +complete -kxc rtx -n "$fssf prune" -s n -l dry-run -d 'Do not actually delete anything' +complete -kxc rtx -n "$fssf prune" -a "(__rtx_plugins)" -d 'Prune only versions from these plugins' # reshim # self-update -complete -xc rtx -n "$fssf self-update" -s f -l force -d 'Update even if already up to date' -complete -xc rtx -n "$fssf self-update" -l no-plugins -d 'Disable auto-updating plugins' -complete -xc rtx -n "$fssf self-update" -d 'Update to a specific version' -complete -xc rtx -n "$fssf self-update" -s y -l yes -d 'Skip confirmation prompt' +complete -kxc rtx -n "$fssf self-update" -s f -l force -d 'Update even if already up to date' +complete -kxc rtx -n "$fssf self-update" -l no-plugins -d 'Disable auto-updating plugins' +complete -kxc rtx -n "$fssf self-update" -d 'Update to a specific version' +complete -kxc rtx -n "$fssf self-update" -s y -l yes -d 'Skip confirmation prompt' # settings set -l others get ls set unset @@ -212,21 +212,21 @@ complete -xc rtx -n "$fssf settings; and not $fssf $others" -a set -d 'Add/updat complete -xc rtx -n "$fssf settings; and not $fssf $others" -a unset -d 'Clears a setting' # settings get -complete -xc rtx -n "$fssf settings; and $fssf get" -d 'The setting to show' +complete -kxc rtx -n "$fssf settings; and $fssf get" -d 'The setting to show' # settings ls # settings set -complete -xc rtx -n "$fssf settings; and $fssf set" -d 'The setting to set' -complete -xc rtx -n "$fssf settings; and $fssf set" -d 'The value to set' +complete -kxc rtx -n "$fssf settings; and $fssf set" -d 'The setting to set' +complete -kxc rtx -n "$fssf settings; and $fssf set" -d 'The value to set' # settings unset -complete -xc rtx -n "$fssf settings; and $fssf unset" -d 'The setting to remove' +complete -kxc rtx -n "$fssf settings; and $fssf unset" -d 'The setting to remove' # shell -complete -xc rtx -n "$fssf shell" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' -complete -xc rtx -n "$fssf shell" -s u -l unset -d 'Removes a previously set version' +complete -kxc rtx -n "$fssf shell" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' +complete -kxc rtx -n "$fssf shell" -s u -l unset -d 'Removes a previously set version' # sync set -l others node python @@ -234,46 +234,46 @@ complete -xc rtx -n "$fssf sync; and not $fssf $others" -a node -d 'Symlinks all complete -xc rtx -n "$fssf sync; and not $fssf $others" -a python -d 'Symlinks all tool versions from an external tool into rtx' # sync node -complete -xc rtx -n "$fssf sync; and $fssf node" -l brew -d 'Get tool versions from Homebrew' -complete -xc rtx -n "$fssf sync; and $fssf node" -l nodenv -d 'Get tool versions from nodenv' -complete -xc rtx -n "$fssf sync; and $fssf node" -l nvm -d 'Get tool versions from nvm' +complete -kxc rtx -n "$fssf sync; and $fssf node" -l brew -d 'Get tool versions from Homebrew' +complete -kxc rtx -n "$fssf sync; and $fssf node" -l nodenv -d 'Get tool versions from nodenv' +complete -kxc rtx -n "$fssf sync; and $fssf node" -l nvm -d 'Get tool versions from nvm' # sync python -complete -xc rtx -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versions from pyenv' +complete -kxc rtx -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versions from pyenv' # trust -complete -xc rtx -n "$fssf trust" -a "(__fish_complete_path)" -d 'The config file to trust' -complete -xc rtx -n "$fssf trust" -l untrust -d 'No longer trust this config' +complete -kxc rtx -n "$fssf trust" -a "(__fish_complete_path)" -d 'The config file to trust' +complete -kxc rtx -n "$fssf trust" -l untrust -d 'No longer trust this config' # uninstall -complete -xc rtx -n "$fssf uninstall" -s a -l all -d 'Delete all installed versions' -complete -xc rtx -n "$fssf uninstall" -s n -l dry-run -d 'Do not actually delete anything' -complete -xc rtx -n "$fssf uninstall" -a "(__rtx_installed_tool_versions)" -d 'Tool(s) to remove' +complete -kxc rtx -n "$fssf uninstall" -s a -l all -d 'Delete all installed versions' +complete -kxc rtx -n "$fssf uninstall" -s n -l dry-run -d 'Do not actually delete anything' +complete -kxc rtx -n "$fssf uninstall" -a "(__rtx_installed_tool_versions)" -d 'Tool(s) to remove' # upgrade -complete -xc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' -complete -xc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' +complete -kxc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' +complete -kxc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' # use -complete -xc rtx -n "$fssf use" -s e -l env -d 'Modify an environment-specific config file like .rtx..toml' -complete -xc rtx -n "$fssf use" -l fuzzy -d 'Save fuzzy version to config file' -complete -xc rtx -n "$fssf use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' -complete -xc rtx -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' -complete -xc rtx -n "$fssf use" -l pin -d 'Save exact version to config file' -complete -xc rtx -n "$fssf use" -l remove -d 'Remove the tool(s) from config file' -complete -xc rtx -n "$fssf use" -a "(__rtx_tool_versions)" -d 'Tool(s) to add to config file' +complete -kxc rtx -n "$fssf use" -s e -l env -d 'Modify an environment-specific config file like .rtx..toml' +complete -kxc rtx -n "$fssf use" -l fuzzy -d 'Save fuzzy version to config file' +complete -kxc rtx -n "$fssf use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' +complete -kxc rtx -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' +complete -kxc rtx -n "$fssf use" -l pin -d 'Save exact version to config file' +complete -kxc rtx -n "$fssf use" -l remove -d 'Remove the tool(s) from config file' +complete -kxc rtx -n "$fssf use" -a "(__rtx_tool_versions)" -d 'Tool(s) to add to config file' # version # where -complete -xc rtx -n "$fssf where" -a "(__rtx_tool_versions)" -d 'Tool(s) to look up' +complete -kxc rtx -n "$fssf where" -a "(__rtx_tool_versions)" -d 'Tool(s) to look up' # which -complete -xc rtx -n "$fssf which" -d 'The bin name to look up' -complete -xc rtx -n "$fssf which" -l plugin -a "(__rtx_plugins)" -d 'Show the plugin name instead of the path' -complete -xc rtx -n "$fssf which" -s t -l tool -a "(__rtx_tool_versions)" -d 'Use a specific tool@version' -complete -xc rtx -n "$fssf which" -l version -d 'Show the version instead of the path' +complete -kxc rtx -n "$fssf which" -d 'The bin name to look up' +complete -kxc rtx -n "$fssf which" -l plugin -a "(__rtx_plugins)" -d 'Show the plugin name instead of the path' +complete -kxc rtx -n "$fssf which" -s t -l tool -a "(__rtx_tool_versions)" -d 'Use a specific tool@version' +complete -kxc rtx -n "$fssf which" -l version -d 'Show the version instead of the path' @@ -295,7 +295,7 @@ function __rtx_plugins end function __rtx_tool_versions if test -z "$__rtx_tool_versions_cache" - set -g __rtx_tool_versions_cache (rtx ls-remote --all) + set -g __rtx_tool_versions_cache (rtx plugins --core --user) (rtx ls-remote --all | tac) end for tv in $__rtx_tool_versions_cache echo $tv diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index 28cc7c9ff..3de9bf94c 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -31,7 +31,7 @@ function __rtx_plugins end function __rtx_tool_versions if test -z "$__rtx_tool_versions_cache" - set -g __rtx_tool_versions_cache (rtx ls-remote --all) + set -g __rtx_tool_versions_cache (rtx plugins --core --user) (rtx ls-remote --all | tac) end for tv in $__rtx_tool_versions_cache echo $tv @@ -60,7 +60,7 @@ fn render_args(cmds: &[&Command]) -> Vec { } fn render_arg(cmds: &[&Command], a: &Arg) -> String { - let mut complete_cmd = r#"complete -xc rtx"#.to_string(); + let mut complete_cmd = r#"complete -kxc rtx"#.to_string(); let parents = cmds.iter().skip(1).map(|c| c.get_name()).collect_vec(); if cmds.len() > 1 { let mut p = format!("$fssf {}", &parents[0]); From fff00efbb4760be739241087ec2a6f1dd74680b2 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:31:11 -0600 Subject: [PATCH 1295/1891] completions: complete setting names (#1166) --- README.md | 24 +++++++++++----------- completions/_rtx | 11 +++++++--- completions/rtx.bash | 6 +++--- completions/rtx.fish | 28 ++++++++++++++++++++------ src/cli/settings/get.rs | 6 +++--- src/cli/settings/set.rs | 8 ++++---- src/cli/settings/unset.rs | 4 ++-- src/shell/completions/fish_complete.rs | 19 ++++++++++++++++- src/shell/completions/zsh_complete.rs | 6 ++++++ 9 files changed, 78 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 0f997f743..a1fcab8f0 100644 --- a/README.md +++ b/README.md @@ -160,10 +160,10 @@ v20.0.0 - [`rtx prune [OPTIONS] [PLUGIN]...`](#rtx-prune-options-plugin) - [`rtx reshim`](#rtx-reshim) - [`rtx self-update [OPTIONS] [VERSION]`](#rtx-self-update-options-version) - - [`rtx settings get `](#rtx-settings-get-key) + - [`rtx settings get `](#rtx-settings-get-setting) - [`rtx settings ls`](#rtx-settings-ls) - - [`rtx settings set `](#rtx-settings-set-key-value) - - [`rtx settings unset `](#rtx-settings-unset-key) + - [`rtx settings set `](#rtx-settings-set-setting-value) + - [`rtx settings unset `](#rtx-settings-unset-setting) - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) - [`rtx sync node <--brew|--nvm|--nodenv>`](#rtx-sync-node---brew--nvm--nodenv) - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) @@ -2456,7 +2456,7 @@ Options: Skip confirmation prompt ``` -### `rtx settings get ` +### `rtx settings get ` ```text Show a current setting @@ -2466,10 +2466,10 @@ This is the contents of a single entry in ~/.config/rtx/config.toml Note that aliases are also stored in this file but managed separately with `rtx aliases get` -Usage: settings get +Usage: settings get Arguments: - + The setting to show Examples: @@ -2494,17 +2494,17 @@ Examples: legacy_version_file = false ``` -### `rtx settings set ` +### `rtx settings set ` ```text Add/update a setting This modifies the contents of ~/.config/rtx/config.toml -Usage: settings set +Usage: settings set Arguments: - + The setting to set @@ -2514,17 +2514,17 @@ Examples: $ rtx settings set legacy_version_file true ``` -### `rtx settings unset ` +### `rtx settings unset ` ```text Clears a setting This modifies the contents of ~/.config/rtx/config.toml -Usage: settings unset +Usage: settings unset Arguments: - + The setting to remove Examples: diff --git a/completions/_rtx b/completions/_rtx index 0b79f829f..e10ef3693 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -602,7 +602,7 @@ return ret (( $+functions[__rtx_settings_get_cmd] )) || __rtx_settings_get_cmd() { _arguments -s -S \ - ':key:' \ + ':setting:__rtx_settings' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ @@ -621,7 +621,7 @@ __rtx_settings_ls_cmd() { (( $+functions[__rtx_settings_set_cmd] )) || __rtx_settings_set_cmd() { _arguments -s -S \ - ':key:' \ + ':setting:__rtx_settings' \ ':value:' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ @@ -632,7 +632,7 @@ __rtx_settings_set_cmd() { (( $+functions[__rtx_settings_unset_cmd] )) || __rtx_settings_unset_cmd() { _arguments -s -S \ - ':key:' \ + ':setting:__rtx_settings' \ '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ @@ -911,6 +911,11 @@ __rtx_aliases() { local -a aliases; aliases=($(rtx aliases ls ${words[CURRENT-1]} | awk '{print $2}')) _describe -t aliases 'alias' aliases "$@" } +(( $+functions[__rtx_settings] )) || +__rtx_settings() { + local -a settings; settings=($(rtx settings ls | awk '{print $1}')) + _describe -t settings 'setting' settings "$@" +} (( $+functions[__rtx_prefixes] )) || __rtx_prefixes() { if [[ CURRENT -gt 2 ]]; then diff --git a/completions/rtx.bash b/completions/rtx.bash index 964e1d0d4..94e321304 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3023,7 +3023,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3159,7 +3159,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3185,7 +3185,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index f00d50013..bd0221f60 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -54,19 +54,19 @@ complete -xc rtx -n "$fssf alias; and not $fssf $others" -a set -d 'Add/update a complete -xc rtx -n "$fssf alias; and not $fssf $others" -a unset -d 'Clears an alias for a plugin' # alias get -complete -kxc rtx -n "$fssf alias; and $fssf get" -d 'The alias to show' +complete -kxc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_aliases)" -d 'The alias to show' complete -kxc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_plugins)" -d 'The plugin to show the alias for' # alias ls complete -kxc rtx -n "$fssf alias; and $fssf ls" -a "(__rtx_plugins)" -d 'Show aliases for ' # alias set -complete -kxc rtx -n "$fssf alias; and $fssf set" -d 'The alias to set' +complete -kxc rtx -n "$fssf alias; and $fssf set" -a "(__rtx_aliases)" -d 'The alias to set' complete -kxc rtx -n "$fssf alias; and $fssf set" -a "(__rtx_plugins)" -d 'The plugin to set the alias for' complete -kxc rtx -n "$fssf alias; and $fssf set" -d 'The value to set the alias to' # alias unset -complete -kxc rtx -n "$fssf alias; and $fssf unset" -d 'The alias to remove' +complete -kxc rtx -n "$fssf alias; and $fssf unset" -a "(__rtx_aliases)" -d 'The alias to remove' complete -kxc rtx -n "$fssf alias; and $fssf unset" -a "(__rtx_plugins)" -d 'The plugin to remove the alias from' @@ -212,16 +212,16 @@ complete -xc rtx -n "$fssf settings; and not $fssf $others" -a set -d 'Add/updat complete -xc rtx -n "$fssf settings; and not $fssf $others" -a unset -d 'Clears a setting' # settings get -complete -kxc rtx -n "$fssf settings; and $fssf get" -d 'The setting to show' +complete -kxc rtx -n "$fssf settings; and $fssf get" -a "(__rtx_settings)" -d 'The setting to show' # settings ls # settings set -complete -kxc rtx -n "$fssf settings; and $fssf set" -d 'The setting to set' +complete -kxc rtx -n "$fssf settings; and $fssf set" -a "(__rtx_settings)" -d 'The setting to set' complete -kxc rtx -n "$fssf settings; and $fssf set" -d 'The value to set' # settings unset -complete -kxc rtx -n "$fssf settings; and $fssf unset" -d 'The setting to remove' +complete -kxc rtx -n "$fssf settings; and $fssf unset" -a "(__rtx_settings)" -d 'The setting to remove' # shell @@ -309,5 +309,21 @@ function __rtx_installed_tool_versions echo $tv end end +function __rtx_aliases + if test -z "$__rtx_aliases_cache" + set -g __rtx_aliases_cache (rtx alias ls | awk '{print $2}') + end + for a in $__rtx_aliases_cache + echo $a + end +end +function __rtx_settings + if test -z "$__rtx_settings_cache" + set -g __rtx_settings_cache (rtx settings ls | awk '{print $1}') + end + for s in $__rtx_settings_cache + echo $s + end +end # vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 2547c4b73..c28d57c92 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -12,14 +12,14 @@ use crate::config::Config; #[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsGet { /// The setting to show - pub key: String, + pub setting: String, } impl SettingsGet { pub fn run(self, config: Config) -> Result<()> { - match config.settings.to_index_map().get(&self.key) { + match config.settings.to_index_map().get(&self.setting) { Some(value) => Ok(rtxprintln!("{}", value)), - None => Err(eyre!("Unknown setting: {}", self.key)), + None => Err(eyre!("Unknown setting: {}", self.setting)), } } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index e78089bc9..160e436a2 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -11,14 +11,14 @@ use crate::config::Config; pub struct SettingsSet { /// The setting to set #[clap()] - pub key: String, + pub setting: String, /// The value to set pub value: String, } impl SettingsSet { pub fn run(self, mut config: Config) -> Result<()> { - let value: toml_edit::Value = match self.key.as_str() { + let value: toml_edit::Value = match self.setting.as_str() { "experimental" => parse_bool(&self.value)?, "always_keep_download" => parse_bool(&self.value)?, "always_keep_install" => parse_bool(&self.value)?, @@ -30,10 +30,10 @@ impl SettingsSet { "shorthands_file" => self.value.into(), "disable_default_shorthands" => parse_bool(&self.value)?, "raw" => parse_bool(&self.value)?, - _ => return Err(eyre!("Unknown setting: {}", self.key)), + _ => return Err(eyre!("Unknown setting: {}", self.setting)), }; - config.global_config.update_setting(&self.key, value); + config.global_config.update_setting(&self.setting, value); config.global_config.save() } } diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index f71b756ed..d7e609194 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -10,12 +10,12 @@ use crate::config::Config; #[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsUnset { /// The setting to remove - pub key: String, + pub setting: String, } impl SettingsUnset { pub fn run(self, mut config: Config) -> Result<()> { - config.global_config.remove_setting(&self.key); + config.global_config.remove_setting(&self.setting); config.global_config.save() } } diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index 3de9bf94c..d3681fb69 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -45,6 +45,22 @@ function __rtx_installed_tool_versions echo $tv end end +function __rtx_aliases + if test -z "$__rtx_aliases_cache" + set -g __rtx_aliases_cache (rtx alias ls | awk '{{print $2}}') + end + for a in $__rtx_aliases_cache + echo $a + end +end +function __rtx_settings + if test -z "$__rtx_settings_cache" + set -g __rtx_settings_cache (rtx settings ls | awk '{{print $1}}') + end + for s in $__rtx_settings_cache + echo $s + end +end # vim: noet ci pi sts=0 sw=4 ts=4 "#} @@ -103,7 +119,8 @@ fn render_completer(a: &Arg) -> Option { "installed_tool" => Some("(__rtx_installed_tool_versions)".to_string()), "plugin" => Some("(__rtx_plugins)".to_string()), "new_plugin" => Some("(__rtx_all_plugins)".to_string()), - //"alias" => Some("(__rtx_aliases)".to_string()), + "alias" => Some("(__rtx_aliases)".to_string()), + "setting" => Some("(__rtx_settings)".to_string()), //"prefix" => Some("(__rtx_prefixes)".to_string()), _ => None, }, diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index 1ba43cb45..eef6b79a9 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -60,6 +60,11 @@ pub fn render(cmd: &Command) -> String { local -a aliases; aliases=($(rtx aliases ls ${{words[CURRENT-1]}} | awk '{{print $2}}')) _describe -t aliases 'alias' aliases "$@" }} + (( $+functions[__rtx_settings] )) || + __rtx_settings() {{ + local -a settings; settings=($(rtx settings ls | awk '{{print $1}}')) + _describe -t settings 'setting' settings "$@" + }} (( $+functions[__rtx_prefixes] )) || __rtx_prefixes() {{ if [[ CURRENT -gt 2 ]]; then @@ -228,6 +233,7 @@ fn render_completion(arg: &Arg) -> String { "plugin" => "__rtx_plugins".to_string(), "new_plugin" => "__rtx_all_plugins".to_string(), "alias" => "__rtx_aliases".to_string(), + "setting" => "__rtx_settings".to_string(), "prefix" => "__rtx_prefixes".to_string(), _ => String::new(), }, From 253918b67336c920e7954eafb8a7289294c73537 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:30:09 -0600 Subject: [PATCH 1296/1891] flags: move raw+jobs flags to only commands that install (#1168) --- README.md | 73 ++++- completions/_rtx | 133 +------- completions/rtx.bash | 576 ++++------------------------------ completions/rtx.fish | 15 +- e2e/test_local | 6 +- src/cli/args/jobs.rs | 22 -- src/cli/args/mod.rs | 2 - src/cli/args/raw.rs | 14 - src/cli/env.rs | 24 +- src/cli/exec.rs | 24 +- src/cli/install.rs | 29 +- src/cli/mod.rs | 8 - src/cli/shell.rs | 24 +- src/cli/upgrade.rs | 24 +- src/cli/use.rs | 55 +++- src/cli/which.rs | 15 +- src/config/config_file/mod.rs | 9 +- src/install_context.rs | 1 + src/shims.rs | 2 + src/toolset/mod.rs | 19 +- 20 files changed, 337 insertions(+), 738 deletions(-) delete mode 100644 src/cli/args/jobs.rs delete mode 100644 src/cli/args/raw.rs diff --git a/README.md b/README.md index a1fcab8f0..a7107fbdc 100644 --- a/README.md +++ b/README.md @@ -1902,9 +1902,18 @@ Options: [possible values: bash, fish, nu, xonsh, zsh] + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + -J, --json Output in JSON format + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" @@ -1968,6 +1977,15 @@ Options: -C, --cd Change to this directory before executing the command + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + Examples: $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x $ rtx x node@20 -- node ./app.js # shorter alias @@ -2018,6 +2036,15 @@ Options: -f, --force Force reinstall even if already installed + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + -v, --verbose... Show installation output @@ -2545,6 +2572,15 @@ Arguments: Tool(s) to use Options: + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + -u, --unset Removes a previously set version @@ -2669,6 +2705,15 @@ Arguments: Options: -n, --dry-run Just print what would be done, don't actually do it + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 ``` ### `rtx use [OPTIONS] [TOOL@VERSION]...` @@ -2690,29 +2735,41 @@ Arguments: If no version is specified, it will default to @latest Options: - --pin - Save exact version to config file - e.g.: `rtx use --pin node@20` will save 20.0.0 as the version - - [env: RTX_ASDF_COMPAT=] + -f, --force + Force reinstall even if already installed --fuzzy Save fuzzy version to config file e.g.: `rtx use --fuzzy node@20` will save 20 as the version this is the default behavior unless RTX_ASDF_COMPAT=1 - --remove - Remove the tool(s) from config file - -g, --global Use the global config file (~/.config/rtx/config.toml) instead of the local one -e, --env Modify an environment-specific config file like .rtx..toml + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + --remove + Remove the tool(s) from config file + -p, --path Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions + --pin + Save exact version to config file + e.g.: `rtx use --pin node@20` will save 20.0.0 as the version + + [env: RTX_ASDF_COMPAT=] + Examples: # set the current version of node to 20.x in .rtx.toml of current directory # will write the fuzzy version (e.g.: 20) diff --git a/completions/_rtx b/completions/_rtx index e10ef3693..438230c74 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -5,9 +5,7 @@ _rtx() { local ret=1 _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cmds' \ @@ -65,9 +63,7 @@ __rtx_activate_cmd() { _arguments -s -S \ '::shell_type:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -75,9 +71,7 @@ __rtx_activate_cmd() { __rtx_alias_cmd() { _arguments -s -S \ '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_alias_cmds' \ @@ -102,9 +96,7 @@ __rtx_alias_get_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -112,9 +104,7 @@ __rtx_alias_get_cmd() { __rtx_alias_ls_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -124,9 +114,7 @@ __rtx_alias_set_cmd() { ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ ':value:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -135,9 +123,7 @@ __rtx_alias_unset_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -145,27 +131,21 @@ __rtx_alias_unset_cmd() { __rtx_asdf_cmd() { _arguments -s -S \ '*::args:_cmdambivalent' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_bin_paths_cmd] )) || __rtx_bin_paths_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_cache_cmd] )) || __rtx_cache_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cache_cmds' \ @@ -186,9 +166,7 @@ return ret __rtx_cache_clear_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -196,9 +174,7 @@ __rtx_cache_clear_cmd() { __rtx_completion_cmd() { _arguments -s -S \ '::shell:(bash fish zsh)' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -206,27 +182,21 @@ __rtx_completion_cmd() { __rtx_current_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_deactivate_cmd] )) || __rtx_deactivate_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_cmd] )) || __rtx_direnv_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_direnv_cmds' \ @@ -248,36 +218,28 @@ return ret (( $+functions[__rtx_direnv_activate_cmd] )) || __rtx_direnv_activate_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_envrc_cmd] )) || __rtx_direnv_envrc_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_exec_cmd] )) || __rtx_direnv_exec_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_doctor_cmd] )) || __rtx_doctor_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -286,10 +248,10 @@ __rtx_env_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ '*::tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -299,9 +261,7 @@ __rtx_env_vars_cmd() { '--file=[The TOML file to update]:file:_files' \ '*--remove=[Remove the environment variable from config file]:remove:' \ '*::env_vars:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -311,9 +271,9 @@ __rtx_exec_cmd() { '*::tool:__rtx_tool_versions' \ '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ + '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -325,9 +285,7 @@ __rtx_global_cmd() { '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ '--path[Get the path of the global config file]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -336,9 +294,7 @@ __rtx_hook_env_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -347,9 +303,7 @@ __rtx_implode_cmd() { _arguments -s -S \ '--config[Also remove config directory]' \ '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -358,10 +312,10 @@ __rtx_install_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ + '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ + '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '*'{-v,--verbose}'[Show installation output]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_latest_cmd] )) || @@ -369,9 +323,7 @@ __rtx_latest_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -381,9 +333,7 @@ __rtx_link_cmd() { ':tool:__rtx_tool_versions' \ ':path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -396,9 +346,7 @@ __rtx_local_cmd() { '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ '--path[Get the path of the config file]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -412,9 +360,7 @@ __rtx_ls_cmd() { '(-J --json)'{-J,--json}'[Output in json format]' \ '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -424,9 +370,7 @@ __rtx_ls_remote_cmd() { '::plugin:__rtx_plugins' \ '--all[Show all installed plugins and versions]' \ '::prefix:__rtx_prefixes' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -434,9 +378,7 @@ __rtx_ls_remote_cmd() { __rtx_outdated_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -447,9 +389,7 @@ __rtx_plugins_cmd() { '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ '--refs[show the git refs for each plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_plugins_cmds' \ @@ -479,9 +419,7 @@ __rtx_plugins_install_cmd() { '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ '(-a --all)'{-a,--all}'[Install all missing plugins]' \ '*'{-v,--verbose}'[Show installation output]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_link_cmd] )) || @@ -490,9 +428,7 @@ __rtx_plugins_link_cmd() { ':name:' \ '::path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -503,9 +439,7 @@ __rtx_plugins_ls_cmd() { '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ '--refs[Show the git refs for each plugin]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -514,9 +448,7 @@ __rtx_plugins_ls_remote_cmd() { _arguments -s -S \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -526,9 +458,7 @@ __rtx_plugins_uninstall_cmd() { '*::plugin:__rtx_plugins' \ '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ '(-a --all)'{-a,--all}'[Remove all plugins]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -536,9 +466,7 @@ __rtx_plugins_uninstall_cmd() { __rtx_plugins_update_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -547,18 +475,14 @@ __rtx_prune_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_reshim_cmd] )) || __rtx_reshim_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -569,17 +493,13 @@ __rtx_self_update_cmd() { '--no-plugins[Disable auto-updating plugins]' \ '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ '::version:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' } (( $+functions[__rtx_settings_cmd] )) || __rtx_settings_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_settings_cmds' \ @@ -603,18 +523,14 @@ return ret __rtx_settings_get_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_settings_ls_cmd] )) || __rtx_settings_ls_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -623,9 +539,7 @@ __rtx_settings_set_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ ':value:' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -633,9 +547,7 @@ __rtx_settings_set_cmd() { __rtx_settings_unset_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -643,19 +555,17 @@ __rtx_settings_unset_cmd() { __rtx_shell_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ + '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_sync_cmd] )) || __rtx_sync_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_sync_cmds' \ @@ -679,9 +589,7 @@ __rtx_sync_node_cmd() { '--brew[Get tool versions from Homebrew]' \ '--nvm[Get tool versions from nvm]' \ '--nodenv[Get tool versions from nodenv]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -689,9 +597,7 @@ __rtx_sync_node_cmd() { __rtx_sync_python_cmd() { _arguments -s -S \ '--pyenv[Get tool versions from pyenv]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -700,9 +606,7 @@ __rtx_trust_cmd() { _arguments -s -S \ '::config_file:_files' \ '--untrust[No longer trust this config]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -712,9 +616,7 @@ __rtx_uninstall_cmd() { '*::installed_tool:__rtx_installed_tool_versions' \ '(-a --all)'{-a,--all}'[Delete all installed versions]' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -723,9 +625,9 @@ __rtx_upgrade_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ '(-n --dry-run)'{-n,--dry-run}'[Just print what would be done, don'\''t actually do it]' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ + '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -733,24 +635,23 @@ __rtx_upgrade_cmd() { __rtx_use_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '--pin[Save exact version to config file]' \ + '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ '--fuzzy[Save fuzzy version to config file]' \ - '*--remove=[Remove the tool(s) from config file]:remove:' \ '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ '(-e --env)'{-e,--env}'=[Modify an environment-specific config file like .rtx..toml]:env:' \ + '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ + '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ + '*--remove=[Remove the tool(s) from config file]:remove:' \ '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ + '--pin[Save exact version to config file]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_version_cmd] )) || __rtx_version_cmd() { _arguments -s -S \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -758,9 +659,7 @@ __rtx_version_cmd() { __rtx_where_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -771,9 +670,7 @@ __rtx_which_cmd() { '--plugin[Show the plugin name instead of the path]' \ '--version[Show the version instead of the path]' \ '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of plugins and runtimes to install in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ - '(-r --raw)'{-r,--raw}'[Directly pipe stdin/stdout/stderr to user.]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } diff --git a/completions/rtx.bash b/completions/rtx.bash index 94e321304..bfb1a55bf 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -559,20 +559,12 @@ _rtx() { case "${cmd}" in rtx) - opts="-j -q -r -v -y -h -V --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -585,7 +577,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -j -r -v -y -h --shell --status --quiet --jobs --debug --log-level --trace --raw --verbose --yes --help bash fish nu xonsh zsh" + opts="-s -q -v -y -h --shell --status --quiet --debug --log-level --trace --verbose --yes --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -599,14 +591,6 @@ _rtx() { COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -619,7 +603,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -j -q -r -v -y -h --plugin --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help get ls set unset help" + opts="-p -q -v -y -h --plugin --debug --log-level --trace --quiet --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -633,14 +617,6 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -653,20 +629,12 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -763,20 +731,12 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -789,20 +749,12 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -815,20 +767,12 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -841,20 +785,12 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ARGS]..." + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -867,20 +803,12 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -893,20 +821,12 @@ _rtx() { return 0 ;; rtx__cache) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help clear help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -919,20 +839,12 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -987,7 +899,7 @@ _rtx() { return 0 ;; rtx__completion) - opts="-s -j -q -r -v -y -h --shell --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help bash fish zsh" + opts="-s -q -v -y -h --shell --debug --log-level --trace --quiet --verbose --yes --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1001,14 +913,6 @@ _rtx() { COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1021,20 +925,12 @@ _rtx() { return 0 ;; rtx__current) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1047,20 +943,12 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1073,20 +961,12 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help envrc exec activate help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1099,20 +979,12 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1125,20 +997,12 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1151,20 +1015,12 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1247,20 +1103,12 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1273,7 +1121,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -J -j -q -r -v -y -h --shell --json --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-s -j -J -q -v -y -h --shell --jobs --json --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1307,7 +1155,7 @@ _rtx() { return 0 ;; rtx__env__vars) - opts="-j -q -r -v -y -h --file --remove --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ENV_VARS]..." + opts="-q -v -y -h --file --remove --debug --log-level --trace --quiet --verbose --yes --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1321,14 +1169,6 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -1341,7 +1181,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -C -j -q -r -v -y -h --command --cd --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -C -j -q -v -y -h --command --cd --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1383,7 +1223,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-j -q -r -v -y -h --pin --fuzzy --remove --path --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-q -v -y -h --pin --fuzzy --remove --path --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1393,14 +1233,6 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2281,7 +2113,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -j -q -r -v -y -h --shell --status --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-s -q -v -y -h --shell --status --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2295,14 +2127,6 @@ _rtx() { COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2315,20 +2139,12 @@ _rtx() { return 0 ;; rtx__implode) - opts="-n -j -q -r -v -y -h --config --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-n -q -v -y -h --config --dry-run --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2341,7 +2157,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-f -v -j -q -r -y -h --force --verbose --jobs --debug --log-level --trace --quiet --raw --yes --help [TOOL@VERSION]..." + opts="-f -j -v -q -y -h --force --jobs --raw --verbose --debug --log-level --trace --quiet --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2367,20 +2183,12 @@ _rtx() { return 0 ;; rtx__latest) - opts="-i -j -q -r -v -y -h --installed --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ASDF_VERSION]" + opts="-i -q -v -y -h --installed --debug --log-level --trace --quiet --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2393,20 +2201,12 @@ _rtx() { return 0 ;; rtx__link) - opts="-f -j -q -r -v -y -h --force --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-f -q -v -y -h --force --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2419,7 +2219,7 @@ _rtx() { return 0 ;; rtx__local) - opts="-p -j -q -r -v -y -h --parent --pin --fuzzy --remove --path --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-p -q -v -y -h --parent --pin --fuzzy --remove --path --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2429,14 +2229,6 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2449,7 +2241,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -J -m -j -q -r -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." + opts="-p -c -g -i -J -m -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2467,14 +2259,6 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2487,20 +2271,12 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-j -q -r -v -y -h --all --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION] [PREFIX]" + opts="-q -v -y -h --all --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION] [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2513,20 +2289,12 @@ _rtx() { return 0 ;; rtx__outdated) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2539,20 +2307,12 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -j -q -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help install link ls ls-remote uninstall update help" + opts="-a -c -u -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --quiet --verbose --yes --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2677,20 +2437,12 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -j -q -r -y -h --force --all --verbose --jobs --debug --log-level --trace --quiet --raw --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." + opts="-f -a -v -q -y -h --force --all --verbose --debug --log-level --trace --quiet --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2703,20 +2455,12 @@ _rtx() { return 0 ;; rtx__plugins__link) - opts="-f -j -q -r -v -y -h --force --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PATH]" + opts="-f -q -v -y -h --force --debug --log-level --trace --quiet --verbose --yes --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2729,20 +2473,12 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -j -q -r -v -y -h --all --core --user --urls --refs --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-a -c -u -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2755,20 +2491,12 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -j -q -r -v -y -h --urls --only-names --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-u -q -v -y -h --urls --only-names --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2781,20 +2509,12 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-p -a -j -q -r -v -y -h --purge --all --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." + opts="-p -a -q -v -y -h --purge --all --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2807,20 +2527,12 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -j -q -r -v -y -h --all --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." + opts="-a -q -v -y -h --all --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2833,20 +2545,12 @@ _rtx() { return 0 ;; rtx__prune) - opts="-n -j -q -r -v -y -h --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN]..." + opts="-n -q -v -y -h --dry-run --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2859,7 +2563,7 @@ _rtx() { return 0 ;; rtx__render__completion) - opts="-s -j -q -r -v -y -h --shell --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help bash elvish fish powershell zsh" + opts="-s -q -v -y -h --shell --debug --log-level --trace --quiet --verbose --yes --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2873,14 +2577,6 @@ _rtx() { COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2893,20 +2589,12 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2919,20 +2607,12 @@ _rtx() { return 0 ;; rtx__render__mangen) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2945,20 +2625,12 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [PLUGIN] [VERSION]" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2971,20 +2643,12 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-f -y -j -q -r -v -h --force --no-plugins --yes --jobs --debug --log-level --trace --quiet --raw --verbose --help [VERSION]" + opts="-f -y -q -v -h --force --no-plugins --yes --debug --log-level --trace --quiet --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -2997,20 +2661,12 @@ _rtx() { return 0 ;; rtx__settings) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help get ls set unset help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3023,20 +2679,12 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3133,20 +2781,12 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3159,20 +2799,12 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3185,20 +2817,12 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3211,7 +2835,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-u -j -q -r -v -y -h --unset --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-j -u -q -v -y -h --jobs --raw --unset --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3237,20 +2861,12 @@ _rtx() { return 0 ;; rtx__sync) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help node python help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3319,20 +2935,12 @@ _rtx() { return 0 ;; rtx__sync__node) - opts="-j -q -r -v -y -h --brew --nvm --nodenv --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --brew --nvm --nodenv --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3345,20 +2953,12 @@ _rtx() { return 0 ;; rtx__sync__python) - opts="-j -q -r -v -y -h --pyenv --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --pyenv --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3371,20 +2971,12 @@ _rtx() { return 0 ;; rtx__trust) - opts="-j -q -r -v -y -h --untrust --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [CONFIG_FILE]" + opts="-q -v -y -h --untrust --debug --log-level --trace --quiet --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3397,20 +2989,12 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-a -n -j -q -r -v -y -h --all --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-a -n -q -v -y -h --all --dry-run --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3423,7 +3007,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-n -j -q -r -v -y -h --dry-run --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-n -j -q -v -y -h --dry-run --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3449,37 +3033,37 @@ _rtx() { return 0 ;; rtx__use) - opts="-g -e -p -j -q -r -v -y -h --pin --fuzzy --remove --global --env --path --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [TOOL@VERSION]..." + opts="-f -g -e -j -p -q -v -y -h --force --fuzzy --global --env --jobs --raw --remove --path --pin --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --remove) + --env) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --env) + -e) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -e) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --path) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -p) + --remove) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) + --path) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -j) + -p) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -3495,20 +3079,12 @@ _rtx() { return 0 ;; rtx__version) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3521,20 +3097,12 @@ _rtx() { return 0 ;; rtx__where) - opts="-j -q -r -v -y -h --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help [ASDF_VERSION]" + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 @@ -3547,7 +3115,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-t -j -q -r -v -y -h --plugin --version --tool --jobs --debug --log-level --trace --quiet --raw --verbose --yes --help " + opts="-t -q -v -y -h --plugin --version --tool --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3561,14 +3129,6 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index bd0221f60..7c515a3fa 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,9 +1,7 @@ set -l fssf "__fish_seen_subcommand_from" # rtx -complete -kxc rtx -s j -l jobs -d 'Number of plugins and runtimes to install in parallel' complete -kxc rtx -s q -l quiet -d 'Suppress output' -complete -kxc rtx -s r -l raw -d 'Directly pipe stdin/stdout/stderr to user.' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' set -l others activate alias bin-paths cache completion current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which @@ -98,7 +96,9 @@ complete -xc rtx -n "$fssf direnv; and not $fssf $others" -a activate -d 'Output # doctor # env +complete -kxc rtx -n "$fssf env" -s j -l jobs -d 'Number of jobs to run in parallel' complete -kxc rtx -n "$fssf env" -s J -l json -d 'Output in JSON format' +complete -kxc rtx -n "$fssf env" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf env" -s s -l shell -a "bash fish nu xonsh zsh" -d 'Shell type to generate environment variables for' complete -kxc rtx -n "$fssf env" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' @@ -111,6 +111,8 @@ complete -kxc rtx -n "$fssf env-vars" -l remove -d 'Remove the environment varia complete -kxc rtx -n "$fssf exec" -s c -l command -d 'Command string to execute' complete -kxc rtx -n "$fssf exec" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' complete -kxc rtx -n "$fssf exec" -d 'Command string to execute (same as --command)' +complete -kxc rtx -n "$fssf exec" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc rtx -n "$fssf exec" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf exec" -a "(__rtx_tool_versions)" -d 'Tool(s) to start e.g.: node@20 python@3.10' # implode @@ -119,6 +121,8 @@ complete -kxc rtx -n "$fssf implode" -s n -l dry-run -d 'List directories that w # install complete -kxc rtx -n "$fssf install" -s f -l force -d 'Force reinstall even if already installed' +complete -kxc rtx -n "$fssf install" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc rtx -n "$fssf install" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf install" -a "(__rtx_tool_versions)" -d 'Tool(s) to install e.g.: node@20' complete -kxc rtx -n "$fssf install" -s v -l verbose -d 'Show installation output' @@ -225,6 +229,8 @@ complete -kxc rtx -n "$fssf settings; and $fssf unset" -a "(__rtx_settings)" -d # shell +complete -kxc rtx -n "$fssf shell" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc rtx -n "$fssf shell" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf shell" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' complete -kxc rtx -n "$fssf shell" -s u -l unset -d 'Removes a previously set version' @@ -253,14 +259,19 @@ complete -kxc rtx -n "$fssf uninstall" -a "(__rtx_installed_tool_versions)" -d ' # upgrade complete -kxc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' +complete -kxc rtx -n "$fssf upgrade" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc rtx -n "$fssf upgrade" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' # use complete -kxc rtx -n "$fssf use" -s e -l env -d 'Modify an environment-specific config file like .rtx..toml' +complete -kxc rtx -n "$fssf use" -s f -l force -d 'Force reinstall even if already installed' complete -kxc rtx -n "$fssf use" -l fuzzy -d 'Save fuzzy version to config file' complete -kxc rtx -n "$fssf use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' +complete -kxc rtx -n "$fssf use" -s j -l jobs -d 'Number of jobs to run in parallel' complete -kxc rtx -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' complete -kxc rtx -n "$fssf use" -l pin -d 'Save exact version to config file' +complete -kxc rtx -n "$fssf use" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf use" -l remove -d 'Remove the tool(s) from config file' complete -kxc rtx -n "$fssf use" -a "(__rtx_tool_versions)" -d 'Tool(s) to add to config file' diff --git a/e2e/test_local b/e2e/test_local index 8670e1ac5..d0e720cfa 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -16,7 +16,7 @@ assert_raises() { fi } -assert_raises "rtx uninstall shfmt@3.6.0" +rtx i shfmt@3.6.0 shfmt@3.5.0 assert "rtx local" "#:schema ../../schema/rtx.json env_file = '.test-env' @@ -57,8 +57,6 @@ if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi -assert_raises "rtx uninstall shfmt@3.6.0" - rtx local shfmt@3.6.0 assert "rtx local" "#:schema ../../schema/rtx.json env_file = '.test-env' @@ -101,8 +99,6 @@ tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb6627394 export RTX_DEFAULT_CONFIG_FILENAME=.MISSING -assert_raises "rtx uninstall shfmt@3.6.0" - rtx local assert "rtx local" "#python 3.11.1 3.10.9 # foo shellcheck sub-0.1:0.10.0 diff --git a/src/cli/args/jobs.rs b/src/cli/args/jobs.rs deleted file mode 100644 index f22faa239..000000000 --- a/src/cli/args/jobs.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::num::ParseIntError; - -use clap::builder::ValueParser; -use clap::Arg; - -#[derive(Clone)] -pub struct Jobs(pub usize); - -fn parse_jobs(input: &str) -> Result { - input.parse::() -} - -impl Jobs { - pub fn arg() -> clap::Arg { - Arg::new("jobs") - .short('j') - .long("jobs") - .help("Number of plugins and runtimes to install in parallel\n[default: 4]") - .value_parser(ValueParser::new(parse_jobs)) - .global(true) - } -} diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index 248528581..30ecb9d08 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,8 +1,6 @@ pub mod env_var; -pub mod jobs; pub mod log_level; pub mod quiet; -pub mod raw; pub mod tool; pub mod verbose; pub mod yes; diff --git a/src/cli/args/raw.rs b/src/cli/args/raw.rs deleted file mode 100644 index 60670c50a..000000000 --- a/src/cli/args/raw.rs +++ /dev/null @@ -1,14 +0,0 @@ -use clap::{Arg, ArgAction}; - -pub struct Raw(pub bool); - -impl Raw { - pub fn arg() -> Arg { - Arg::new("raw") - .short('r') - .long("raw") - .help("Directly pipe stdin/stdout/stderr to user.\nSets --jobs=1") - .action(ArgAction::SetTrue) - .global(true) - } -} diff --git a/src/cli/env.rs b/src/cli/env.rs index b48deb182..36ee4ce1b 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -4,7 +4,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::shell::{get_shell, ShellType}; -use crate::toolset::{Toolset, ToolsetBuilder}; +use crate::toolset::{InstallOptions, Toolset, ToolsetBuilder}; /// Exports env vars to activate rtx a single time /// @@ -21,15 +21,33 @@ pub struct Env { #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, + /// Number of jobs to run in parallel + /// [default: 4] + #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + jobs: Option, + /// Output in JSON format #[clap(long, short = 'J', overrides_with = "shell")] json: bool, + + /// Directly pipe stdin/stdout/stderr from plugin to user + /// Sets --jobs=1 + #[clap(long, overrides_with = "jobs")] + raw: bool, } impl Env { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { + if self.raw { + config.settings.raw = true; + } let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; - ts.install_arg_versions(&config)?; + let opts = InstallOptions { + force: false, + jobs: self.jobs, + raw: self.raw, + }; + ts.install_arg_versions(&config, &opts)?; if self.json { self.output_json(config, ts) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 6dfbed2ab..15fb18288 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -12,7 +12,7 @@ use crate::cmd; use crate::config::Config; use crate::env; -use crate::toolset::ToolsetBuilder; +use crate::toolset::{InstallOptions, ToolsetBuilder}; /// Execute a command with tool(s) set /// @@ -42,12 +42,30 @@ pub struct Exec { /// Change to this directory before executing the command #[clap(short = 'C', value_hint = ValueHint::DirPath, long)] pub cd: Option, + + /// Number of jobs to run in parallel + /// [default: 4] + #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + pub jobs: Option, + + /// Directly pipe stdin/stdout/stderr from plugin to user + /// Sets --jobs=1 + #[clap(long, overrides_with = "jobs")] + pub raw: bool, } impl Exec { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { + if self.raw { + config.settings.raw = true; + } let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; - ts.install_arg_versions(&config)?; + let opts = InstallOptions { + force: false, + jobs: self.jobs, + raw: self.raw, + }; + ts.install_arg_versions(&config, &opts)?; let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); let env = ts.env_with_path(&config); diff --git a/src/cli/install.rs b/src/cli/install.rs index b77419041..3c98a9746 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -4,7 +4,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::toolset::{ - ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, + InstallOptions, ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, }; use crate::ui::multi_progress_report::MultiProgressReport; @@ -28,13 +28,26 @@ pub struct Install { #[clap(long, short, requires = "tool")] force: bool, + /// Number of jobs to run in parallel + /// [default: 4] + #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + jobs: Option, + + /// Directly pipe stdin/stdout/stderr from plugin to user + /// Sets --jobs=1 + #[clap(long, overrides_with = "jobs")] + raw: bool, + /// Show installation output #[clap(long, short, action = clap::ArgAction::Count)] verbose: u8, } impl Install { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { + if self.raw { + config.settings.raw = true; + } match &self.tool { Some(runtime) => self.install_runtimes(config, runtime)?, None => self.install_missing_runtimes(config)?, @@ -53,7 +66,15 @@ impl Install { warn!("specify a version with `rtx install @`"); return Ok(()); } - ts.install_versions(&config, tool_versions, &mpr, self.force) + ts.install_versions(&config, tool_versions, &mpr, &self.install_opts()) + } + + fn install_opts(&self) -> InstallOptions { + InstallOptions { + force: self.force, + jobs: self.jobs, + raw: self.raw, + } } fn get_requested_tool_versions( @@ -116,7 +137,7 @@ impl Install { return Ok(()); } let mpr = MultiProgressReport::new(&config.settings); - ts.install_versions(&config, versions, &mpr, self.force)?; + ts.install_versions(&config, versions, &mpr, &self.install_opts())?; Ok(()) } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 22f6eb69f..831ea4f7c 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -185,12 +185,10 @@ impl Cli { .arg_required_else_help(true) .subcommand_required(true) .after_long_help(AFTER_LONG_HELP) - .arg(args::jobs::Jobs::arg()) .arg(args::log_level::Debug::arg()) .arg(args::log_level::LogLevel::arg()) .arg(args::log_level::Trace::arg()) .arg(args::quiet::Quiet::arg()) - .arg(args::raw::Raw::arg()) .arg(args::verbose::Verbose::arg()) .arg(args::yes::Yes::arg()), ) @@ -203,12 +201,6 @@ impl Cli { return version::Version {}.run(config); } let matches = self.command.get_matches_from(args); - if let Some(jobs) = matches.get_one::("jobs") { - config.settings.jobs = *jobs; - } - if let Some(raw) = matches.get_one::("raw") { - config.settings.raw = *raw; - } if let Some(true) = matches.get_one::("yes") { config.settings.yes = true; } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index cddea016a..02062e05d 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -4,7 +4,7 @@ use console::style; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::shell::get_shell; -use crate::toolset::{ToolSource, ToolsetBuilder}; +use crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder}; /// Sets a tool version for the current shell session /// @@ -16,19 +16,37 @@ pub struct Shell { #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, + /// Number of jobs to run in parallel + /// [default: 4] + #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + jobs: Option, + + /// Directly pipe stdin/stdout/stderr from plugin to user + /// Sets --jobs=1 + #[clap(long, overrides_with = "jobs")] + raw: bool, + /// Removes a previously set version #[clap(long, short)] unset: bool, } impl Shell { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { + if self.raw { + config.settings.raw = true; + } if !config.is_activated() { err_inactive()?; } let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; - ts.install_arg_versions(&config)?; + let opts = InstallOptions { + force: false, + jobs: self.jobs, + raw: self.raw, + }; + ts.install_arg_versions(&config, &opts)?; let shell = get_shell(None).expect("no shell detected"); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 60c536b23..435534adb 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -10,7 +10,7 @@ use crate::config::Config; use crate::plugins::Plugin; use crate::runtime_symlinks; use crate::shims; -use crate::toolset::{ToolVersion, ToolsetBuilder}; +use crate::toolset::{InstallOptions, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::ProgressReport; @@ -27,10 +27,23 @@ pub struct Upgrade { /// Just print what would be done, don't actually do it #[clap(long, short = 'n', verbatim_doc_comment)] dry_run: bool, + + /// Number of jobs to run in parallel + /// [default: 4] + #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + jobs: Option, + + /// Directly pipe stdin/stdout/stderr from plugin to user + /// Sets --jobs=1 + #[clap(long, overrides_with = "jobs")] + raw: bool, } impl Upgrade { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { + if self.raw { + config.settings.raw = true; + } let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let tool_set = self .tool @@ -77,7 +90,12 @@ impl Upgrade { } return Ok(()); } - ts.install_versions(config, new_versions, &mpr, false)?; + let opts = InstallOptions { + force: false, + jobs: self.jobs, + raw: self.raw, + }; + ts.install_versions(config, new_versions, &mpr, &opts)?; for (tool, tv) in to_remove { let mut pr = mpr.add(); self.uninstall_old_version(config, tool.clone(), &tv, &mut pr)?; diff --git a/src/cli/use.rs b/src/cli/use.rs index 78666f05a..f99a4ec33 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -11,7 +11,7 @@ use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME use crate::file::display_path; use crate::plugins::PluginName; -use crate::toolset::ToolsetBuilder; +use crate::toolset::{InstallOptions, ToolsetBuilder}; use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. @@ -29,15 +29,9 @@ pub struct Use { #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment, required_unless_present = "remove")] tool: Vec, - /// Save exact version to config file - /// e.g.: `rtx use --pin node@20` will save 20.0.0 as the version - #[clap( - long, - env = "RTX_ASDF_COMPAT", - verbatim_doc_comment, - overrides_with = "fuzzy" - )] - pin: bool, + /// Force reinstall even if already installed + #[clap(long, short, requires = "tool")] + force: bool, /// Save fuzzy version to config file /// e.g.: `rtx use --fuzzy node@20` will save 20 as the version @@ -45,10 +39,6 @@ pub struct Use { #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, - /// Remove the tool(s) from config file - #[clap(long, value_name = "TOOL", aliases = ["rm", "unset"])] - remove: Option>, - /// Use the global config file (~/.config/rtx/config.toml) instead of the local one #[clap(short, long, overrides_with_all = &["path", "env"])] global: bool, @@ -57,16 +47,49 @@ pub struct Use { #[clap(long, short, overrides_with_all = &["global", "path"])] env: Option, + /// Number of jobs to run in parallel + /// [default: 4] + #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + jobs: Option, + + /// Directly pipe stdin/stdout/stderr from plugin to user + /// Sets --jobs=1 + #[clap(long, overrides_with = "jobs")] + raw: bool, + + /// Remove the tool(s) from config file + #[clap(long, value_name = "TOOL", aliases = ["rm", "unset"])] + remove: Option>, + /// Specify a path to a config file or directory /// If a directory is specified, it will look for .rtx.toml (default) or .tool-versions #[clap(short, long, overrides_with_all = &["global", "env"], value_hint = clap::ValueHint::FilePath)] path: Option, + + /// Save exact version to config file + /// e.g.: `rtx use --pin node@20` will save 20.0.0 as the version + #[clap( + long, + env = "RTX_ASDF_COMPAT", + verbatim_doc_comment, + overrides_with = "fuzzy" + )] + pin: bool, } impl Use { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, mut config: Config) -> Result<()> { + if self.raw { + config.settings.raw = true; + } let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; - ts.install_arg_versions(&config)?; + + let opts = InstallOptions { + force: self.force, + jobs: self.jobs, + raw: self.raw, + }; + ts.install_arg_versions(&config, &opts)?; ts.versions .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); diff --git a/src/cli/which.rs b/src/cli/which.rs index c0aa7f4d4..cfcfd9f0c 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -73,26 +73,29 @@ mod tests { #[test] fn test_which() { - assert_cli!("global", "dummy@1.0.0"); + assert_cli!("use", "dummy@1.0.0"); assert_cli_snapshot!("which", "dummy"); - assert_cli!("global", "dummy@ref:master"); + assert_cli!("use", "dummy@ref:master"); assert_cli!("uninstall", "dummy@1.0.0"); + assert_cli!("use", "--rm", "dummy"); } #[test] fn test_which_plugin() { - assert_cli!("global", "dummy@1.0.0"); + assert_cli!("use", "dummy@1.0.0"); assert_cli_snapshot!("which", "--plugin", "dummy"); - assert_cli!("global", "dummy@ref:master"); + assert_cli!("use", "dummy@ref:master"); assert_cli!("uninstall", "dummy@1.0.0"); + assert_cli!("use", "--rm", "dummy"); } #[test] fn test_which_version() { - assert_cli!("global", "dummy@1.0.0"); + assert_cli!("use", "dummy@1.0.0"); assert_cli_snapshot!("which", "--version", "dummy"); - assert_cli!("global", "dummy@ref:master"); + assert_cli!("use", "dummy@ref:master"); assert_cli!("uninstall", "dummy@1.0.0"); + assert_cli!("use", "--rm", "dummy"); } #[test] diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 3d1532572..620298d45 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -15,8 +15,7 @@ use crate::file::{display_path, replace_path}; use crate::hash::hash_to_str; use crate::plugins::PluginName; -use crate::toolset::{ToolVersion, ToolVersionList, Toolset}; -use crate::ui::multi_progress_report::MultiProgressReport; +use crate::toolset::{ToolVersionList, Toolset}; use crate::{dirs, env, file}; pub mod legacy_version; @@ -67,7 +66,6 @@ pub trait ConfigFile: Debug + Display + Send + Sync { impl dyn ConfigFile { 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(); ts.latest_versions = true; ts.resolve(config); @@ -89,11 +87,6 @@ impl dyn ConfigFile { ts.versions.insert(plugin.clone(), tvl); } ts.resolve(config); - let versions: Vec = plugins_to_update - .iter() - .flat_map(|(pn, _)| ts.versions.get(pn).unwrap().versions.clone()) - .collect(); - ts.install_versions(config, versions, &mpr, false)?; for (plugin, versions) in plugins_to_update { let versions = versions .into_iter() diff --git a/src/install_context.rs b/src/install_context.rs index 01c421d37..a3c150130 100644 --- a/src/install_context.rs +++ b/src/install_context.rs @@ -7,5 +7,6 @@ pub struct InstallContext<'a> { pub ts: &'a Toolset, pub tv: ToolVersion, pub pr: ProgressReport, + pub raw: bool, pub force: bool, } diff --git a/src/shims.rs b/src/shims.rs index 212ffc620..f66d58816 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -35,6 +35,8 @@ pub fn handle_shim(config: Config, args: &[String]) -> Result { c: None, command: Some(args), cd: None, + jobs: None, + raw: false, }; exec.run(config)?; exit(0); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index f982ae9f3..9df025311 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -32,6 +32,13 @@ mod tool_version_request; pub type ToolVersionOptions = BTreeMap; +#[derive(Debug, Default)] +pub struct InstallOptions { + pub force: bool, + pub jobs: Option, + pub raw: bool, +} + /// a toolset is a collection of tools for various plugins /// /// one example is a .tool-versions file @@ -83,7 +90,7 @@ impl Toolset { .par_iter_mut() .for_each(|(_, v)| v.resolve(config, self.latest_versions)); } - pub fn install_arg_versions(&mut self, config: &Config) -> Result<()> { + pub fn install_arg_versions(&mut self, config: &Config, opts: &InstallOptions) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); let versions = self .list_missing_versions(config) @@ -91,7 +98,7 @@ impl Toolset { .filter(|tv| matches!(self.versions[&tv.plugin_name].source, ToolSource::Argument)) .cloned() .collect_vec(); - self.install_versions(config, versions, &mpr, false) + self.install_versions(config, versions, &mpr, opts) } pub fn list_missing_plugins(&self, config: &Config) -> Vec { @@ -108,7 +115,7 @@ impl Toolset { config: &Config, versions: Vec, mpr: &MultiProgressReport, - force: bool, + opts: &InstallOptions, ) -> Result<()> { if versions.is_empty() { return Ok(()); @@ -126,8 +133,9 @@ impl Toolset { } } let queue = Arc::new(Mutex::new(queue)); + let jobs = opts.jobs.unwrap_or(config.settings.jobs); thread::scope(|s| { - (0..config.settings.jobs) + (0..jobs) .map(|_| { let queue = queue.clone(); let ts = &*self; @@ -145,7 +153,8 @@ impl Toolset { true, )?, pr: mpr.add(), - force, + raw: opts.raw, + force: opts.force, }; t.install_version(ctx)?; } From dd71d09c6345d5fb9821109035acf811193fb357 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:17:07 -0600 Subject: [PATCH 1297/1891] test: skip slow e2e tests unless releasing (#1169) * test: skip slow e2e tests unless releasing * Commit from GitHub Actions (rtx) * test: skip slow e2e tests unless releasing --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- .github/workflows/release.yml | 1 + e2e/ruby/test_ruby | 4 ++++ e2e/run_test | 1 + e2e/test_erlang | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c0929f6f7..d76660a05 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -119,6 +119,7 @@ jobs: RUST_BACKTRACE: "1" TEST_TRANCHE: ${{matrix.tranche}} TEST_TRANCHE_COUNT: 4 + TEST_ALL: 1 with: timeout_minutes: 20 max_attempts: 3 diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby index a515b11fe..588e46933 100755 --- a/e2e/ruby/test_ruby +++ b/e2e/ruby/test_ruby @@ -9,6 +9,10 @@ export RTX_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" export RTX_RUBY_VERBOSE_INSTALL=1 export RTX_RAW=1 +if [ "${TEST_ALL:-}" != 1 ]; then + exit +fi + cat >Gemfile < Date: Wed, 13 Dec 2023 18:35:30 -0600 Subject: [PATCH 1298/1891] added RTX_RAW env var to --raw flags --- README.md | 12 ++++++++++++ src/cli/env.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/install.rs | 2 +- src/cli/shell.rs | 2 +- src/cli/upgrade.rs | 2 +- src/cli/use.rs | 2 +- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a7107fbdc..99280d926 100644 --- a/README.md +++ b/README.md @@ -1914,6 +1914,8 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + [env: RTX_RAW=] + Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" @@ -1986,6 +1988,8 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + [env: RTX_RAW=] + Examples: $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x $ rtx x node@20 -- node ./app.js # shorter alias @@ -2045,6 +2049,8 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + [env: RTX_RAW=] + -v, --verbose... Show installation output @@ -2581,6 +2587,8 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + [env: RTX_RAW=] + -u, --unset Removes a previously set version @@ -2714,6 +2722,8 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + [env: RTX_RAW=] ``` ### `rtx use [OPTIONS] [TOOL@VERSION]...` @@ -2758,6 +2768,8 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + [env: RTX_RAW=] + --remove Remove the tool(s) from config file diff --git a/src/cli/env.rs b/src/cli/env.rs index 36ee4ce1b..79467cae8 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -32,7 +32,7 @@ pub struct Env { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, overrides_with = "jobs")] + #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] raw: bool, } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 15fb18288..c58c99ed5 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -50,7 +50,7 @@ pub struct Exec { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, overrides_with = "jobs")] + #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] pub raw: bool, } diff --git a/src/cli/install.rs b/src/cli/install.rs index 3c98a9746..0af09e6c0 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -35,7 +35,7 @@ pub struct Install { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, overrides_with = "jobs")] + #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] raw: bool, /// Show installation output diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 02062e05d..a136b632f 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -23,7 +23,7 @@ pub struct Shell { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, overrides_with = "jobs")] + #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] raw: bool, /// Removes a previously set version diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 435534adb..d0cac324d 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -35,7 +35,7 @@ pub struct Upgrade { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, overrides_with = "jobs")] + #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] raw: bool, } diff --git a/src/cli/use.rs b/src/cli/use.rs index f99a4ec33..d7ab75519 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -54,7 +54,7 @@ pub struct Use { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, overrides_with = "jobs")] + #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] raw: bool, /// Remove the tool(s) from config file From e8ccf67ee3ac88662cfac7d9ec6be70b0abe45a1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:46:46 -0600 Subject: [PATCH 1299/1891] Revert "added RTX_RAW env var to --raw flags" This reverts commit 70937d2a26447d89a20abffe658f8ee51b673d98. --- README.md | 12 ------------ src/cli/env.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/install.rs | 2 +- src/cli/shell.rs | 2 +- src/cli/upgrade.rs | 2 +- src/cli/use.rs | 2 +- 7 files changed, 6 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 99280d926..a7107fbdc 100644 --- a/README.md +++ b/README.md @@ -1914,8 +1914,6 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - [env: RTX_RAW=] - Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" @@ -1988,8 +1986,6 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - [env: RTX_RAW=] - Examples: $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x $ rtx x node@20 -- node ./app.js # shorter alias @@ -2049,8 +2045,6 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - [env: RTX_RAW=] - -v, --verbose... Show installation output @@ -2587,8 +2581,6 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - [env: RTX_RAW=] - -u, --unset Removes a previously set version @@ -2722,8 +2714,6 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - - [env: RTX_RAW=] ``` ### `rtx use [OPTIONS] [TOOL@VERSION]...` @@ -2768,8 +2758,6 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - [env: RTX_RAW=] - --remove Remove the tool(s) from config file diff --git a/src/cli/env.rs b/src/cli/env.rs index 79467cae8..36ee4ce1b 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -32,7 +32,7 @@ pub struct Env { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] + #[clap(long, overrides_with = "jobs")] raw: bool, } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index c58c99ed5..15fb18288 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -50,7 +50,7 @@ pub struct Exec { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] + #[clap(long, overrides_with = "jobs")] pub raw: bool, } diff --git a/src/cli/install.rs b/src/cli/install.rs index 0af09e6c0..3c98a9746 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -35,7 +35,7 @@ pub struct Install { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] + #[clap(long, overrides_with = "jobs")] raw: bool, /// Show installation output diff --git a/src/cli/shell.rs b/src/cli/shell.rs index a136b632f..02062e05d 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -23,7 +23,7 @@ pub struct Shell { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] + #[clap(long, overrides_with = "jobs")] raw: bool, /// Removes a previously set version diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index d0cac324d..435534adb 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -35,7 +35,7 @@ pub struct Upgrade { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] + #[clap(long, overrides_with = "jobs")] raw: bool, } diff --git a/src/cli/use.rs b/src/cli/use.rs index d7ab75519..f99a4ec33 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -54,7 +54,7 @@ pub struct Use { /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 - #[clap(long, env = "RTX_RAW", overrides_with = "jobs")] + #[clap(long, overrides_with = "jobs")] raw: bool, /// Remove the tool(s) from config file From ac2d364dac77f7fc8ad4c89e2913949b01c572a0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:57:46 -0600 Subject: [PATCH 1300/1891] activate: use full path to rtx (#1170) See https://github.com/Homebrew/homebrew-core/pull/157141 --- src/shell/bash.rs | 7 ++++--- src/shell/fish.rs | 19 ++++++++++--------- .../rtx__shell__bash__tests__hook_init.snap | 6 +++--- ...tx__shell__bash__tests__hook_init_nix.snap | 6 +++--- .../rtx__shell__fish__tests__hook_init.snap | 18 +++++++++--------- ...tx__shell__fish__tests__hook_init_nix.snap | 18 +++++++++--------- .../rtx__shell__zsh__tests__hook_init.snap | 8 ++++---- ...rtx__shell__zsh__tests__hook_init_nix.snap | 8 ++++---- src/shell/zsh.rs | 9 +++++---- 9 files changed, 51 insertions(+), 48 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 6b116be8d..24b8ba076 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -8,6 +8,7 @@ pub struct Bash {} impl Shell for Bash { fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); + let exe = exe.to_string_lossy(); let status = if status { " --status" } else { "" }; let mut out = String::new(); if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { @@ -21,7 +22,7 @@ impl Shell for Bash { local command command="${{1:-}}" if [ "$#" = 0 ]; then - command rtx + command {exe} return fi shift @@ -30,12 +31,12 @@ impl Shell for Bash { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command rtx "$command" "$@")" + eval "$(command {exe} "$command" "$@")" return $? fi ;; esac - command rtx "$command" "$@" + command {exe} "$command" "$@" }} _rtx_hook() {{ diff --git a/src/shell/fish.rs b/src/shell/fish.rs index a1e616acc..725ae1f0e 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -8,6 +8,7 @@ pub struct Fish {} impl Shell for Fish { fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); + let exe = exe.to_string_lossy(); let status = if status { " --status" } else { "" }; let description = "'Update rtx environment when changing directories'"; let mut out = String::new(); @@ -24,7 +25,7 @@ impl Shell for Fish { function rtx if test (count $argv) -eq 0 - command rtx + command {exe} return end @@ -32,7 +33,7 @@ impl Shell for Fish { set -e argv[1] if contains -- --help $argv - command rtx "$command" $argv + command {exe} "$command" $argv return $status end @@ -40,26 +41,26 @@ impl Shell for Fish { case deactivate s shell # if help is requested, don't eval if contains -- -h $argv - command rtx "$command" $argv + command {exe} "$command" $argv else if contains -- --help $argv - command rtx "$command" $argv + command {exe} "$command" $argv else - source (command rtx "$command" $argv |psub) + source (command {exe} "$command" $argv |psub) end case '*' - command rtx "$command" $argv + command {exe} "$command" $argv end end function __rtx_env_eval --on-event fish_prompt --description {description}; - rtx hook-env{status} -s fish | source; + {exe} hook-env{status} -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description {description}; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - rtx hook-env{status} -s fish | source; + {exe} hook-env{status} -s fish | source; end; end; end; @@ -68,7 +69,7 @@ impl Shell for Fish { function __rtx_env_eval_2 --on-event fish_preexec --description {description}; if set -q __rtx_env_again; set -e __rtx_env_again; - rtx hook-env{status} -s fish | source; + {exe} hook-env{status} -s fish | source; echo; end; diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index fab0399f5..ab6c773b6 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -10,7 +10,7 @@ rtx() { local command command="${1:-}" if [ "$#" = 0 ]; then - command rtx + command /some/dir/rtx return fi shift @@ -19,12 +19,12 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command rtx "$command" "$@")" + eval "$(command /some/dir/rtx "$command" "$@")" return $? fi ;; esac - command rtx "$command" "$@" + command /some/dir/rtx "$command" "$@" } _rtx_hook() { diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index 81c47d461..abb13f678 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -9,7 +9,7 @@ rtx() { local command command="${1:-}" if [ "$#" = 0 ]; then - command rtx + command /nix/store/rtx return fi shift @@ -18,12 +18,12 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command rtx "$command" "$@")" + eval "$(command /nix/store/rtx "$command" "$@")" return $? fi ;; esac - command rtx "$command" "$@" + command /nix/store/rtx "$command" "$@" } _rtx_hook() { diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 85c54a5a9..b22d47187 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -8,7 +8,7 @@ set -gx __RTX_ORIG_PATH $PATH function rtx if test (count $argv) -eq 0 - command rtx + command /some/dir/rtx return end @@ -16,7 +16,7 @@ function rtx set -e argv[1] if contains -- --help $argv - command rtx "$command" $argv + command /some/dir/rtx "$command" $argv return $status end @@ -24,26 +24,26 @@ function rtx case deactivate s shell # if help is requested, don't eval if contains -- -h $argv - command rtx "$command" $argv + command /some/dir/rtx "$command" $argv else if contains -- --help $argv - command rtx "$command" $argv + command /some/dir/rtx "$command" $argv else - source (command rtx "$command" $argv |psub) + source (command /some/dir/rtx "$command" $argv |psub) end case '*' - command rtx "$command" $argv + command /some/dir/rtx "$command" $argv end end function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; - rtx hook-env --status -s fish | source; + /some/dir/rtx hook-env --status -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - rtx hook-env --status -s fish | source; + /some/dir/rtx hook-env --status -s fish | source; end; end; end; @@ -52,7 +52,7 @@ end; function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; if set -q __rtx_env_again; set -e __rtx_env_again; - rtx hook-env --status -s fish | source; + /some/dir/rtx hook-env --status -s fish | source; echo; end; diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap index 662c282c3..e657c0177 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap @@ -7,7 +7,7 @@ set -gx __RTX_ORIG_PATH $PATH function rtx if test (count $argv) -eq 0 - command rtx + command /nix/store/rtx return end @@ -15,7 +15,7 @@ function rtx set -e argv[1] if contains -- --help $argv - command rtx "$command" $argv + command /nix/store/rtx "$command" $argv return $status end @@ -23,26 +23,26 @@ function rtx case deactivate s shell # if help is requested, don't eval if contains -- -h $argv - command rtx "$command" $argv + command /nix/store/rtx "$command" $argv else if contains -- --help $argv - command rtx "$command" $argv + command /nix/store/rtx "$command" $argv else - source (command rtx "$command" $argv |psub) + source (command /nix/store/rtx "$command" $argv |psub) end case '*' - command rtx "$command" $argv + command /nix/store/rtx "$command" $argv end end function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; - rtx hook-env --status -s fish | source; + /nix/store/rtx hook-env --status -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - rtx hook-env --status -s fish | source; + /nix/store/rtx hook-env --status -s fish | source; end; end; end; @@ -51,7 +51,7 @@ end; function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; if set -q __rtx_env_again; set -e __rtx_env_again; - rtx hook-env --status -s fish | source; + /nix/store/rtx hook-env --status -s fish | source; echo; end; diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index b01fd8338..ca7f5e7c7 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -10,7 +10,7 @@ rtx() { local command command="${1:-}" if [ "$#" = 0 ]; then - command rtx + command /some/dir/rtx return fi shift @@ -19,16 +19,16 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command rtx "$command" "$@")" + eval "$(command /some/dir/rtx "$command" "$@")" return $? fi ;; esac - command rtx "$command" "$@" + command /some/dir/rtx "$command" "$@" } _rtx_hook() { - eval "$(rtx hook-env --status -s zsh)"; + eval "$(/some/dir/rtx hook-env --status -s zsh)"; } typeset -ag precmd_functions; if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap index 21055d9dc..4373a8d67 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -9,7 +9,7 @@ rtx() { local command command="${1:-}" if [ "$#" = 0 ]; then - command rtx + command /nix/store/rtx return fi shift @@ -18,16 +18,16 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command rtx "$command" "$@")" + eval "$(command /nix/store/rtx "$command" "$@")" return $? fi ;; esac - command rtx "$command" "$@" + command /nix/store/rtx "$command" "$@" } _rtx_hook() { - eval "$(rtx hook-env --status -s zsh)"; + eval "$(/nix/store/rtx hook-env --status -s zsh)"; } typeset -ag precmd_functions; if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 4dbff4ff4..6011db5dc 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -9,6 +9,7 @@ pub struct Zsh {} impl Shell for Zsh { fn activate(&self, exe: &Path, status: bool) -> String { let dir = exe.parent().unwrap(); + let exe = exe.to_string_lossy(); let status = if status { " --status" } else { "" }; let mut out = String::new(); @@ -25,7 +26,7 @@ impl Shell for Zsh { local command command="${{1:-}}" if [ "$#" = 0 ]; then - command rtx + command {exe} return fi shift @@ -34,16 +35,16 @@ impl Shell for Zsh { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command rtx "$command" "$@")" + eval "$(command {exe} "$command" "$@")" return $? fi ;; esac - command rtx "$command" "$@" + command {exe} "$command" "$@" }} _rtx_hook() {{ - eval "$(rtx hook-env{status} -s zsh)"; + eval "$({exe} hook-env{status} -s zsh)"; }} typeset -ag precmd_functions; if [[ -z "${{precmd_functions[(r)_rtx_hook]+1}}" ]]; then From bf4994aa282c76c74063ebf2e14a6e4501f73185 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:55:43 -0600 Subject: [PATCH 1301/1891] e2e: disable verbose mode --- e2e/run_test | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e/run_test b/e2e/run_test index f08f5f10b..79aec09ae 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -17,7 +17,6 @@ setup_env() { export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" export RTX_TRUSTED_CONFIG_PATHS="$ROOT/e2e" export RTX_YES="1" - export RTX_VERBOSE="1" unset GOPATH } From 571b9b955a1f6590d786eb93f0dff06b07eba500 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:57:28 -0600 Subject: [PATCH 1302/1891] e2e: disable npm fund message --- e2e/run_test | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e/run_test b/e2e/run_test index 79aec09ae..2e5d76edb 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -17,6 +17,7 @@ setup_env() { export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" export RTX_TRUSTED_CONFIG_PATHS="$ROOT/e2e" export RTX_YES="1" + export NPM_CONFIG_FUND="false" unset GOPATH } From 02c8ba00ef8c3e0f526ed4d4cbce5d1dad4607bb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:09:45 -0600 Subject: [PATCH 1303/1891] install: set jobs=1 if --raw --- src/toolset/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 9df025311..19ab621e3 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -133,7 +133,10 @@ impl Toolset { } } let queue = Arc::new(Mutex::new(queue)); - let jobs = opts.jobs.unwrap_or(config.settings.jobs); + let jobs = match opts.raw { + true => 1, + false => opts.jobs.unwrap_or(config.settings.jobs), + }; thread::scope(|s| { (0..jobs) .map(|_| { From 41025c5a489e1d627d87c85f01163255a257b8e0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:22:23 -0600 Subject: [PATCH 1304/1891] activate: allow overriding rtx binary path with RTX_EXE env var --- src/env.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/env.rs b/src/env.rs index fa8e3c8f1..0278894bd 100644 --- a/src/env.rs +++ b/src/env.rs @@ -43,7 +43,11 @@ pub static RTX_ENV: Lazy> = Lazy::new(|| var("RTX_ENV").or_else(|_| var("RTX_ENVIRONMENT")).ok()); pub static RTX_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("RTX_CONFIG_FILE")); pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); -pub static RTX_EXE: Lazy = Lazy::new(|| current_exe().unwrap_or_else(|_| "rtx".into())); +pub static RTX_EXE: Lazy = Lazy::new(|| { + var_path("RTX_EXE") + .or_else(|| current_exe().ok()) + .unwrap_or_else(|| "rtx".into()) +}); pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { From 072d297e1ca9d007a2fc059fcae027582dcaae02 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:25:19 -0600 Subject: [PATCH 1305/1891] refactor: minor tweaks to env.rs --- src/env.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/env.rs b/src/env.rs index 0278894bd..d57973c30 100644 --- a/src/env.rs +++ b/src/env.rs @@ -82,12 +82,13 @@ pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH" None => vec![], }); pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); -pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| match var_option_bool("RTX_ALL_COMPILE") { - Some(v) => v, - None => matches!( - linux_distro().unwrap_or_default().as_str(), - "alpine" | "nixos" - ), +pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| { + var_option_bool("RTX_ALL_COMPILE").unwrap_or_else(|| { + matches!( + linux_distro().unwrap_or_default().as_str(), + "alpine" | "nixos" + ) + }) }); #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); @@ -136,10 +137,8 @@ pub static RTX_NODE_VERBOSE_INSTALL: Lazy> = Lazy::new(|| var_option_bool("RTX_NODE_VERBOSE_INSTALL")); pub static RTX_NODE_MAKE: Lazy = Lazy::new(|| var("RTX_NODE_MAKE").unwrap_or_else(|_| "make".into())); -pub static RTX_NODE_NINJA: Lazy = Lazy::new(|| match var_option_bool("RTX_NODE_NINJA") { - Some(v) => v, - None => is_ninja_on_path(), -}); +pub static RTX_NODE_NINJA: Lazy = + Lazy::new(|| var_option_bool("RTX_NODE_NINJA").unwrap_or_else(is_ninja_on_path)); pub static RTX_NODE_VERIFY: Lazy = Lazy::new(|| !var_is_false("RTX_NODE_VERIFY")); pub static RTX_NODE_COMPILE: Lazy = Lazy::new(|| { *RTX_ALL_COMPILE || var_is_true("RTX_NODE_COMPILE") || var_is_true("RTX_NODE_FORCE_COMPILE") From 695470005c80dfc90cee4aae2564a9c1e1db38fc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:26:23 -0600 Subject: [PATCH 1306/1891] help --- src/cli/activate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 2dd46b511..719c33f73 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -6,7 +6,7 @@ use crate::env::RTX_EXE; use crate::file::touch_dir; use crate::shell::{get_shell, ShellType}; -/// Initializes rtx in the current shell +/// Initializes rtx in the current shell session /// /// This should go into your shell's rc file. /// Otherwise, it will only take effect in the current session. From f3c32cb7e9329a335f3bfdfc9fb44fcab7560e05 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:26:40 -0600 Subject: [PATCH 1307/1891] help --- README.md | 2 +- completions/_rtx | 2 +- completions/rtx.fish | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a7107fbdc..88bb7bcb3 100644 --- a/README.md +++ b/README.md @@ -1641,7 +1641,7 @@ behavior. ### `rtx activate [OPTIONS] [SHELL_TYPE]` ```text -Initializes rtx in the current shell +Initializes rtx in the current shell session This should go into your shell's rc file. Otherwise, it will only take effect in the current session. diff --git a/completions/_rtx b/completions/_rtx index 438230c74..331302757 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -677,7 +677,7 @@ __rtx_which_cmd() { (( $+functions[__rtx_cmds] )) || __rtx_cmds() { local commands; commands=( - 'activate:Initializes rtx in the current shell' + 'activate:Initializes rtx in the current shell session' {a,alias}':Manage aliases' 'bin-paths:List all the active runtime bin paths' 'cache:Manage the rtx cache' diff --git a/completions/rtx.fish b/completions/rtx.fish index 7c515a3fa..3687ef0f4 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -5,7 +5,7 @@ complete -kxc rtx -s q -l quiet -d 'Suppress output' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' set -l others activate alias bin-paths cache completion current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which -complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell' +complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell session' complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' complete -xc rtx -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' complete -xc rtx -n "not $fssf $others" -a cache -d 'Manage the rtx cache' From 2131936bf88e0e642b0e49c78de21cc991b3e219 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 20:23:28 -0600 Subject: [PATCH 1308/1891] use: show warning if setting a version that will not be used (#1171) e.g.: `rtx use -g node@18` if there is a local .rtx.toml with node already defined --- .github/workflows/rtx.yml | 1 + e2e/cd/test_bash | 1 + e2e/ruby/test_ruby | 3 +-- e2e/run_test | 1 - e2e/test_bang | 1 + src/cli/use.rs | 25 +++++++++++++++++++++++-- src/toolset/mod.rs | 5 +++-- 7 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 4d3f20bb4..0a215acda 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -85,6 +85,7 @@ jobs: RTX_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} TEST_TRANCHE: ${{matrix.tranche}} TEST_TRANCHE_COUNT: 4 + TEST_FULL: ${{github.ref_name == 'main' && '1' || '0'}} with: timeout_minutes: 30 max_attempts: 2 diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 131c2ab28..836a4e6f0 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -31,6 +31,7 @@ assert_path() { fi } +rtx i && _rtx_hook test "$(node -v)" = "v20.0.0" assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" assert "$FOO" "cd" diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby index 588e46933..bfa1b481c 100755 --- a/e2e/ruby/test_ruby +++ b/e2e/ruby/test_ruby @@ -7,7 +7,6 @@ source "$(dirname "$0")/../assert.sh" export RTX_EXPERIMENTAL=1 export RTX_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" export RTX_RUBY_VERBOSE_INSTALL=1 -export RTX_RAW=1 if [ "${TEST_ALL:-}" != 1 ]; then exit @@ -22,7 +21,7 @@ source "https://rubygems.org" git_source(:github) { |repo| "https://github.com/#{repo}.git" } EOF -rtx i ruby +rtx i ruby -v assert_contains "rtx x -- ruby --version" "ruby 3.2.2" rm Gemfile diff --git a/e2e/run_test b/e2e/run_test index 2e5d76edb..3700f64e8 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -33,7 +33,6 @@ run_test() { echo "Running $TEST" rm -f "$RTX_CONFIG_FILE" cd "$(dirname "$TEST")" - rtx i "./$(basename "$TEST")" } diff --git a/e2e/test_bang b/e2e/test_bang index 1507cef3d..432b6bcaf 100755 --- a/e2e/test_bang +++ b/e2e/test_bang @@ -10,6 +10,7 @@ assert() { fi } +rtx i tiny rtx local tiny@sub-1:latest assert "rtx current tiny" "2.1.0" rtx local tiny@sub-1:lts diff --git a/src/cli/use.rs b/src/cli/use.rs index f99a4ec33..7b4d36ed1 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -9,9 +9,8 @@ use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; - use crate::plugins::PluginName; -use crate::toolset::{InstallOptions, ToolsetBuilder}; +use crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder}; use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. @@ -112,6 +111,9 @@ impl Use { cf.replace_versions(&plugin_name, &versions); } + if self.global { + self.warn_if_hidden(&config, cf.get_path()); + } for plugin_name in self.remove.unwrap_or_default() { cf.remove_plugin(&plugin_name); } @@ -138,6 +140,25 @@ impl Use { }; config_file::parse_or_init(&config.settings, &path) } + + fn warn_if_hidden(&self, config: &Config, global: &Path) { + let ts = ToolsetBuilder::new().build(config).unwrap_or_default(); + let warn = |targ: &ToolArg, p| { + let plugin = &targ.plugin; + let p = display_path(p); + let global = display_path(global); + warn!("{plugin} is is defined in {p} which overrides the global config ({global})"); + }; + for targ in &self.tool { + if let Some(tv) = ts.versions.get(&targ.plugin) { + if let ToolSource::RtxToml(p) | ToolSource::ToolVersions(p) = &tv.source { + if p != global { + warn(targ, p); + } + } + } + } + } } fn global_file() -> PathBuf { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 19ab621e3..ea7fddccd 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -133,7 +133,8 @@ impl Toolset { } } let queue = Arc::new(Mutex::new(queue)); - let jobs = match opts.raw { + let raw = opts.raw || config.settings.raw; + let jobs = match raw { true => 1, false => opts.jobs.unwrap_or(config.settings.jobs), }; @@ -156,7 +157,7 @@ impl Toolset { true, )?, pr: mpr.add(), - raw: opts.raw, + raw, force: opts.force, }; t.install_version(ctx)?; From 7d40fd0ea4e507ab767b717c5d299a1f02b9f5c5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 20:24:24 -0600 Subject: [PATCH 1309/1891] refactor: --raw parsing --- src/cli/env.rs | 5 +---- src/cli/exec.rs | 5 +---- src/cli/install.rs | 5 +---- src/cli/shell.rs | 5 +---- src/cli/upgrade.rs | 5 +---- src/cli/use.rs | 5 +---- src/config/settings.rs | 8 ++++++++ 7 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/cli/env.rs b/src/cli/env.rs index 36ee4ce1b..3812c871e 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -37,10 +37,7 @@ pub struct Env { } impl Env { - pub fn run(self, mut config: Config) -> Result<()> { - if self.raw { - config.settings.raw = true; - } + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let opts = InstallOptions { force: false, diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 15fb18288..24686cd72 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -55,10 +55,7 @@ pub struct Exec { } impl Exec { - pub fn run(self, mut config: Config) -> Result<()> { - if self.raw { - config.settings.raw = true; - } + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let opts = InstallOptions { force: false, diff --git a/src/cli/install.rs b/src/cli/install.rs index 3c98a9746..e727400a6 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -44,10 +44,7 @@ pub struct Install { } impl Install { - pub fn run(self, mut config: Config) -> Result<()> { - if self.raw { - config.settings.raw = true; - } + pub fn run(self, config: Config) -> Result<()> { match &self.tool { Some(runtime) => self.install_runtimes(config, runtime)?, None => self.install_missing_runtimes(config)?, diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 02062e05d..ebc8e21f8 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -32,10 +32,7 @@ pub struct Shell { } impl Shell { - pub fn run(self, mut config: Config) -> Result<()> { - if self.raw { - config.settings.raw = true; - } + pub fn run(self, config: Config) -> Result<()> { if !config.is_activated() { err_inactive()?; } diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 435534adb..adbd6cd3d 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -40,10 +40,7 @@ pub struct Upgrade { } impl Upgrade { - pub fn run(self, mut config: Config) -> Result<()> { - if self.raw { - config.settings.raw = true; - } + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let tool_set = self .tool diff --git a/src/cli/use.rs b/src/cli/use.rs index 7b4d36ed1..554ed5ea6 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -77,10 +77,7 @@ pub struct Use { } impl Use { - pub fn run(self, mut config: Config) -> Result<()> { - if self.raw { - config.settings.raw = true; - } + pub fn run(self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let opts = InstallOptions { diff --git a/src/config/settings.rs b/src/config/settings.rs index af157aba5..f53a94e5b 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -62,6 +62,14 @@ impl Settings { if *env::RTX_LOG_LEVEL < LevelFilter::Info { p.verbose = Some(true); } + for arg in &*env::ARGS { + if arg == "--" { + break; + } + if arg == "--raw" { + p.raw = Some(true); + } + } Self::builder().preloaded(p).env() } From 08cb30d60812d1b2b05f30682e372169ebd4e5ca Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 20:46:31 -0600 Subject: [PATCH 1310/1891] chore: Release rtx-cli version 2023.12.26 --- Cargo.lock | 25 +++++++++---------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bda0a9390..0e8cd965a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,9 +412,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -423,22 +423,21 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -683,9 +682,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" dependencies = [ "indenter", "once_cell", @@ -1792,7 +1791,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.25" +version = "2023.12.26" dependencies = [ "base64", "built", @@ -1949,12 +1948,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "sct" version = "0.7.1" diff --git a/Cargo.toml b/Cargo.toml index 654562b05..d99e176d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.25" +version = "2023.12.26" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 88bb7bcb3..731854112 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.25 +rtx 2023.12.26 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.25/rtx-v2023.12.25-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.26/rtx-v2023.12.26-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 48dc3429a..e7be01434 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.25"; + version = "2023.12.26"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index c3f4ab580..9effc2b93 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.25 +Version: 2023.12.26 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From a1a72d004837f97bd623aa10c1c2619006e76d21 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:42:24 -0600 Subject: [PATCH 1311/1891] refactor: make env::ARGS a singleton (#1172) --- src/cli/exec.rs | 13 ++++--------- src/cli/mod.rs | 2 ++ src/cli/plugins/install.rs | 6 ++---- .../snapshots/rtx__cli__exec__tests__exec_fail.snap | 5 +++++ src/config/config_file/rtx_toml.rs | 3 ++- src/config/settings.rs | 2 +- src/env.rs | 12 +++++++----- src/hook_env.rs | 3 ++- src/main.rs | 12 +++++++----- 9 files changed, 32 insertions(+), 26 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__exec__tests__exec_fail.snap diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 24686cd72..ad932946d 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -144,8 +144,8 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli; - use crate::cli::tests::cli_run; + use crate::{assert_cli, assert_cli_err}; + use insta::assert_display_snapshot; #[test] fn test_exec_ok() { @@ -154,13 +154,8 @@ mod tests { #[test] fn test_exec_fail() { - let _ = cli_run( - &vec!["rtx", "exec", "--", "exit", "1"] - .into_iter() - .map(String::from) - .collect::>(), - ) - .unwrap_err(); + let err = assert_cli_err!("exec", "--", "exit", "1"); + assert_display_snapshot!(err); } #[test] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 831ea4f7c..4878f8a18 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -260,11 +260,13 @@ pub mod tests { use color_eyre::{Section, SectionExt}; use crate::dirs; + use crate::env; use crate::output::tests::{STDERR, STDOUT}; use super::*; pub fn cli_run(args: &Vec) -> Result<()> { + *env::ARGS.write().unwrap() = args.clone(); STDOUT.lock().unwrap().clear(); STDERR.lock().unwrap().clear(); let config = Config::load()?; diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 6f837f51c..78f506ae1 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -164,14 +164,12 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { + use crate::assert_cli_err; use insta::assert_display_snapshot; - use crate::cli::tests::cli_run; - #[test] fn test_plugin_install_invalid_url() { - let args = ["rtx", "plugin", "add", "tiny:"].map(String::from).into(); - let err = cli_run(&args).unwrap_err(); + let err = assert_cli_err!("plugin", "add", "tiny:"); assert_display_snapshot!(err); } } diff --git a/src/cli/snapshots/rtx__cli__exec__tests__exec_fail.snap b/src/cli/snapshots/rtx__cli__exec__tests__exec_fail.snap new file mode 100644 index 000000000..e343554fb --- /dev/null +++ b/src/cli/snapshots/rtx__cli__exec__tests__exec_fail.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/exec.rs +expression: err +--- +No such file or directory (os error 2) diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index ae6576d51..0c0ca4854 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -552,7 +552,8 @@ impl RtxToml { fn trust_check(&self) -> Result<()> { let default_cmd = String::new(); - let cmd = env::ARGS.get(1).unwrap_or(&default_cmd).as_str(); + let args = env::ARGS.read().unwrap(); + let cmd = args.get(1).unwrap_or(&default_cmd).as_str(); if self.get_is_trusted() || cmd == "trust" || cmd == "completion" || cfg!(test) { return Ok(()); } diff --git a/src/config/settings.rs b/src/config/settings.rs index f53a94e5b..ce1e629dc 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -62,7 +62,7 @@ impl Settings { if *env::RTX_LOG_LEVEL < LevelFilter::Info { p.verbose = Some(true); } - for arg in &*env::ARGS { + for arg in &*env::ARGS.read().unwrap() { if arg == "--" { break; } diff --git a/src/env.rs b/src/env.rs index d57973c30..ce1767bbf 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,6 +1,7 @@ use std::collections::{HashMap, HashSet}; pub use std::env::*; use std::path::PathBuf; +use std::sync::RwLock; use std::time::Duration; use itertools::Itertools; @@ -12,7 +13,7 @@ use crate::duration::HOURLY; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::file::replace_path; -pub static ARGS: Lazy> = Lazy::new(|| args().collect()); +pub static ARGS: RwLock> = RwLock::new(vec![]); pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "sh".into())); // paths and directories @@ -73,7 +74,7 @@ pub static __RTX_SCRIPT: Lazy = Lazy::new(|| var_is_true("__RTX_SCRIPT")); pub static __RTX_DIFF: Lazy = Lazy::new(get_env_diff); pub static __RTX_ORIG_PATH: Lazy> = Lazy::new(|| var("__RTX_ORIG_PATH").ok()); pub static CI: Lazy = Lazy::new(|| var_is_true("CI")); -pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS)); +pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS.read().unwrap())); /// essentially, this is whether we show spinners or build output on runtime install pub static PRISTINE_ENV: Lazy> = Lazy::new(|| get_pristine_env(&__RTX_DIFF, vars().collect())); @@ -346,7 +347,8 @@ fn log_level() -> LevelFilter { if var_is_true("RTX_TRACE") { set_var("RTX_LOG_LEVEL", "trace"); } - for (i, arg) in ARGS.iter().enumerate() { + let args = ARGS.read().unwrap(); + for (i, arg) in args.iter().enumerate() { if arg == "--" { break; } @@ -354,11 +356,11 @@ fn log_level() -> LevelFilter { set_var("RTX_LOG_LEVEL", level); } if arg == "--log-level" { - if let Some(level) = ARGS.get(i + 1) { + if let Some(level) = args.get(i + 1) { set_var("RTX_LOG_LEVEL", level); } } - if arg == "--debug" || arg == "--verbose" || (arg == "-v" && ARGS.len() > 1) { + if arg == "--debug" || arg == "--verbose" || (arg == "-v" && args.len() > 1) { set_var("RTX_LOG_LEVEL", "debug"); } if arg == "--trace" || arg == "-vv" { diff --git a/src/hook_env.rs b/src/hook_env.rs index 2b846eb6c..af7577b9b 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -20,7 +20,8 @@ use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being /// called and it does not need to be pub fn should_exit_early(watch_files: &[PathBuf]) -> bool { - if env::ARGS.len() < 2 || env::ARGS[1] != "hook-env" { + let args = env::ARGS.read().unwrap(); + if args.len() < 2 || args[1] != "hook-env" { return false; } let watch_files = get_watch_files(watch_files); diff --git a/src/main.rs b/src/main.rs index 8dd232f7c..681bf214e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,12 +63,13 @@ mod toolset; mod ui; fn main() -> Result<()> { + *env::ARGS.write().unwrap() = env::args().collect(); color_eyre::install()?; let log_level = *env::RTX_LOG_LEVEL; logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); handle_ctrlc(); - match run(&env::ARGS).with_section(|| VERSION.to_string().header("Version:")) { + match run().with_section(|| VERSION.to_string().header("Version:")) { Ok(()) => Ok(()), Err(err) if log_level < log::LevelFilter::Debug => { display_friendly_err(err); @@ -78,18 +79,19 @@ fn main() -> Result<()> { } } -fn run(args: &Vec) -> Result<()> { +fn run() -> Result<()> { + let args = env::ARGS.read().unwrap(); // show version before loading config in case of error - cli::version::print_version_if_requested(&env::ARGS); + cli::version::print_version_if_requested(&args); migrate::run(); let config = Config::load()?; - let config = shims::handle_shim(config, args)?; + let config = shims::handle_shim(config, &args)?; if config.should_exit_early { return Ok(()); } let cli = Cli::new_with_external_commands(&config); - cli.run(config, args) + cli.run(config, &args) } fn handle_ctrlc() { From 2e7463833aea4b774f496dc712d00877c3705a7b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:57:56 -0600 Subject: [PATCH 1312/1891] refactor: parse CLI into settings partial (#1173) --- src/cli/mod.rs | 39 ++++++++++++++++++------------ src/config/config_file/rtx_toml.rs | 11 +++------ src/config/mod.rs | 8 ++++-- src/config/settings.rs | 7 ++++-- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 4878f8a18..c4585158a 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,8 +1,9 @@ use crate::cli::self_update::SelfUpdate; use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; +use confique::Partial; -use crate::config::Config; +use crate::config::{Config, SettingsPartial}; mod activate; mod alias; @@ -194,26 +195,13 @@ impl Cli { ) } - pub fn run(self, mut config: Config, args: &Vec) -> Result<()> { + pub fn run(self, config: Config, args: &Vec) -> Result<()> { debug!("{}", &args.join(" ")); if args[1..] == ["-v"] { // normally this would be considered --verbose return version::Version {}.run(config); } let matches = self.command.get_matches_from(args); - if let Some(true) = matches.get_one::("yes") { - config.settings.yes = true; - } - if let Some(true) = matches.get_one::("quiet") { - config.settings.quiet = true; - } - if *matches.get_one::("verbose").unwrap() > 0 { - config.settings.verbose = true; - } - if config.settings.raw { - config.settings.jobs = 1; - config.settings.verbose = true; - } if let Some((command, sub_m)) = matches.subcommand() { if command == "self-update" { return SelfUpdate::from_arg_matches(sub_m)?.run(config); @@ -223,6 +211,27 @@ impl Cli { let cmd = Commands::from_arg_matches(&matches)?; cmd.run(config) } + + pub fn settings(self, args: &Vec) -> SettingsPartial { + let mut s = SettingsPartial::empty(); + if let Ok(m) = self.command.try_get_matches_from(args) { + if let Some(true) = m.get_one::("yes") { + s.yes = Some(true); + } + if let Some(true) = m.get_one::("quiet") { + s.quiet = Some(true); + } + if *m.get_one::("verbose").unwrap() > 0 { + s.verbose = Some(true); + } + } + // if let Some(true) = m.get_one::("trace") { + // s.log_level = Some(true); + // } + // TODO: log_level/debug/trace + + s + } } impl Default for Cli { diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 0c0ca4854..08c859605 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -90,14 +90,9 @@ impl RtxToml { match v.as_str() { Some(filename) => { let path = self.path.parent().unwrap().join(filename); - let dotenv = match dotenvy::from_path_iter(&path) { - Ok(dotenv) => dotenv, - Err(e) => Err(eyre!( - "failed to parse dotenv file: {}\n{:#}", - path.display(), - e - ))?, - }; + let dotenv = dotenvy::from_path_iter(&path).wrap_err_with(|| { + eyre!("failed to parse dotenv file: {}", display_path(&path)) + })?; for item in dotenv { let (k, v) = item?; self.env.insert(k, v); diff --git a/src/config/mod.rs b/src/config/mod.rs index db7ee6eb7..bb39581f8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -11,7 +11,7 @@ use itertools::Itertools; use once_cell::sync::OnceCell; use rayon::prelude::*; -pub use settings::Settings; +pub use settings::{Settings, SettingsPartial}; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; @@ -68,7 +68,11 @@ impl Config { for cf in config_files.values() { settings = settings.preloaded(cf.settings()?); } - let settings = settings.load()?; + let mut settings = settings.load()?; + if settings.raw { + settings.verbose = true; + settings.jobs = 1; + } trace!("Settings: {:#?}", settings); let legacy_files = load_legacy_files(&settings, &plugins); diff --git a/src/config/settings.rs b/src/config/settings.rs index ce1e629dc..86d02fdc7 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,6 +1,7 @@ use confique::env::parse::{list_by_colon, list_by_comma}; use confique::{Builder, Config, Partial}; +use crate::cli::Cli; use log::LevelFilter; use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; @@ -56,13 +57,14 @@ impl Default for Settings { impl Settings { pub fn default_builder() -> Builder { let mut p = SettingsPartial::empty(); + let args = env::ARGS.read().unwrap(); if *env::CI { p.yes = Some(true); } if *env::RTX_LOG_LEVEL < LevelFilter::Info { p.verbose = Some(true); } - for arg in &*env::ARGS.read().unwrap() { + for arg in &*args { if arg == "--" { break; } @@ -70,7 +72,8 @@ impl Settings { p.raw = Some(true); } } - Self::builder().preloaded(p).env() + let cli = Cli::new().settings(&args); + Self::builder().preloaded(cli).preloaded(p).env() } pub fn to_index_map(&self) -> BTreeMap { From 6a6441e750cff184e9d9fbe6ab16be5267e34930 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 00:51:16 -0600 Subject: [PATCH 1313/1891] settings refactor (#1174) * refactor: parse CLI into settings partial * whitespace * refactor: memoize partial settings * readme --- src/cli/mod.rs | 1 + src/config/mod.rs | 20 ++++++++------ src/config/settings.rs | 60 +++++++++++++++++++++++++++--------------- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index c4585158a..f8bc3397c 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -275,6 +275,7 @@ pub mod tests { use super::*; pub fn cli_run(args: &Vec) -> Result<()> { + Config::reset(); *env::ARGS.write().unwrap() = args.clone(); STDOUT.lock().unwrap().clear(); STDERR.lock().unwrap().clear(); diff --git a/src/config/mod.rs b/src/config/mod.rs index bb39581f8..a59190ba4 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -13,10 +13,10 @@ use rayon::prelude::*; pub use settings::{Settings, SettingsPartial}; +use crate::cli::Cli; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; - use crate::config::tracking::Tracker; use crate::file::display_path; use crate::plugins::core::{PluginMap, CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; @@ -51,11 +51,12 @@ pub struct Config { impl Config { pub fn load() -> Result { + let cli_settings = Cli::new().settings(&env::ARGS.read().unwrap()); + Settings::add_partial(cli_settings); let global_config = load_rtxrc()?; + Settings::add_partial(global_config.settings()?); let config_filenames = load_config_filenames(&BTreeMap::new()); - let settings = Settings::default_builder() - .preloaded(global_config.settings()?) - .load()?; + let settings = Settings::default_builder().load()?; let plugins = load_plugins(&settings)?; let config_files = load_all_config_files( &settings, @@ -64,11 +65,10 @@ impl Config { &BTreeMap::new(), ConfigMap::new(), )?; - let mut settings = Settings::default_builder(); for cf in config_files.values() { - settings = settings.preloaded(cf.settings()?); + Settings::add_partial(cf.settings()?); } - let mut settings = settings.load()?; + let mut settings = Settings::default_builder().load()?; if settings.raw { settings.verbose = true; settings.jobs = 1; @@ -123,7 +123,6 @@ impl Config { Ok(config) } - pub fn get_shorthands(&self) -> &Shorthands { self.shorthands .get_or_init(|| get_shorthands(&self.settings)) @@ -241,6 +240,11 @@ impl Config { crate::runtime_symlinks::rebuild(self)?; Ok(()) } + + #[cfg(test)] + pub fn reset() { + Settings::reset(); + } } fn get_project_root(config_files: &ConfigMap) -> Option { diff --git a/src/config/settings.rs b/src/config/settings.rs index 86d02fdc7..f2999044d 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,17 +1,18 @@ use confique::env::parse::{list_by_colon, list_by_comma}; -use confique::{Builder, Config, Partial}; -use crate::cli::Cli; -use log::LevelFilter; -use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; +use std::sync::{Once, RwLock}; + +use confique::{Builder, Config, Partial}; +use log::LevelFilter; +use serde_derive::{Deserialize, Serialize}; use crate::env; #[derive(Config, Debug, Clone)] -#[config(partial_attr(derive(Debug)))] +#[config(partial_attr(derive(Debug, Clone)))] pub struct Settings { #[config(env = "RTX_EXPERIMENTAL", default = false)] pub experimental: bool, @@ -54,26 +55,38 @@ impl Default for Settings { Settings::default_builder().load().unwrap() } } + +static PARTIALS: RwLock> = RwLock::new(Vec::new()); + impl Settings { - pub fn default_builder() -> Builder { - let mut p = SettingsPartial::empty(); - let args = env::ARGS.read().unwrap(); - if *env::CI { - p.yes = Some(true); - } - if *env::RTX_LOG_LEVEL < LevelFilter::Info { - p.verbose = Some(true); - } - for arg in &*args { - if arg == "--" { - break; + pub fn add_partial(partial: SettingsPartial) { + static ONCE: Once = Once::new(); + ONCE.call_once(|| { + let mut p = SettingsPartial::empty(); + if *env::CI { + p.yes = Some(true); + } + if *env::RTX_LOG_LEVEL < LevelFilter::Info { + p.verbose = Some(true); } - if arg == "--raw" { - p.raw = Some(true); + for arg in &*env::ARGS.read().unwrap() { + if arg == "--" { + break; + } + if arg == "--raw" { + p.raw = Some(true); + } } + PARTIALS.write().unwrap().push(p); + }); + PARTIALS.write().unwrap().push(partial); + } + pub fn default_builder() -> Builder { + let mut b = Self::builder(); + for partial in PARTIALS.read().unwrap().iter() { + b = b.preloaded(partial.clone()); } - let cli = Cli::new().settings(&args); - Self::builder().preloaded(cli).preloaded(p).env() + b.env() } pub fn to_index_map(&self) -> BTreeMap { @@ -129,6 +142,11 @@ impl Settings { map.insert("yes".into(), self.yes.to_string()); map } + + #[cfg(test)] + pub fn reset() { + PARTIALS.write().unwrap().clear(); + } } impl Display for Settings { From 28761536315504a91a563de5a7be06d34be82221 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 00:57:58 -0600 Subject: [PATCH 1314/1891] settings refactor (#1175) * refactor: parse CLI into settings partial * whitespace * refactor: memoize partial settings * readme * refactor: use memoized config/settings --- src/cli/activate.rs | 3 +- src/cli/alias/get.rs | 3 +- src/cli/alias/ls.rs | 3 +- src/cli/alias/mod.rs | 15 ++- src/cli/alias/set.rs | 9 +- src/cli/alias/unset.rs | 7 +- src/cli/asdf.rs | 16 +-- src/cli/bin_paths.rs | 6 +- src/cli/cache/clear.rs | 3 +- src/cli/cache/mod.rs | 9 +- src/cli/completion.rs | 4 +- src/cli/current.rs | 16 +-- src/cli/deactivate.rs | 2 +- src/cli/direnv/activate.rs | 4 +- src/cli/direnv/envrc.rs | 8 +- src/cli/direnv/exec.rs | 6 +- src/cli/direnv/mod.rs | 6 +- src/cli/doctor.rs | 13 +-- src/cli/env.rs | 14 +-- src/cli/env_vars.rs | 8 +- src/cli/exec.rs | 8 +- src/cli/external.rs | 2 +- src/cli/global.rs | 2 +- src/cli/hook_env.rs | 17 ++-- src/cli/implode.rs | 11 +- src/cli/install.rs | 30 +++--- src/cli/latest.rs | 6 +- src/cli/link.rs | 2 +- src/cli/local.rs | 13 +-- src/cli/ls.rs | 17 ++-- src/cli/ls_remote.rs | 16 +-- src/cli/mod.rs | 43 ++++---- src/cli/outdated.rs | 6 +- src/cli/plugins/install.rs | 28 ++---- src/cli/plugins/link.rs | 3 +- src/cli/plugins/ls.rs | 2 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/mod.rs | 6 +- src/cli/plugins/uninstall.rs | 6 +- src/cli/plugins/update.rs | 2 +- src/cli/prune.rs | 28 +++--- src/cli/render_completion.rs | 3 +- src/cli/render_help.rs | 4 +- src/cli/render_mangen.rs | 3 +- src/cli/reshim.rs | 6 +- src/cli/self_update.rs | 3 +- src/cli/settings/get.rs | 7 +- src/cli/settings/ls.rs | 7 +- src/cli/settings/mod.rs | 16 ++- src/cli/settings/set.rs | 7 +- src/cli/settings/unset.rs | 7 +- src/cli/shell.rs | 5 +- src/cli/sync/mod.rs | 12 +-- src/cli/sync/node.rs | 15 +-- src/cli/sync/python.rs | 3 +- src/cli/trust.rs | 4 +- src/cli/uninstall.rs | 18 ++-- src/cli/upgrade.rs | 15 ++- src/cli/use.rs | 19 ++-- src/cli/version.rs | 4 +- src/cli/where.rs | 6 +- src/cli/which.rs | 13 +-- src/cmd.rs | 12 +-- src/config/config_file/legacy_version.rs | 5 +- src/config/config_file/mod.rs | 25 ++--- src/config/config_file/rtx_toml.rs | 19 ++++ src/config/mod.rs | 56 +++++------ src/config/settings.rs | 22 +++- src/install_context.rs | 2 - src/main.rs | 6 +- src/plugins/core/bun.rs | 7 +- src/plugins/core/deno.rs | 23 ++--- src/plugins/core/erlang.rs | 4 +- src/plugins/core/go.rs | 36 +++---- src/plugins/core/java.rs | 20 ++-- src/plugins/core/node.rs | 38 ++++--- src/plugins/core/node_build.rs | 37 ++++--- src/plugins/core/python.rs | 24 +++-- src/plugins/core/ruby.rs | 39 ++++--- src/plugins/external_plugin.rs | 123 +++++++++-------------- src/plugins/external_plugin_cache.rs | 4 +- src/plugins/mod.rs | 88 ++++++---------- src/plugins/script_manager.rs | 21 ++-- src/shims.rs | 26 ++--- src/shorthands.rs | 25 +++-- src/toolset/builder.rs | 5 +- src/toolset/mod.rs | 67 +++++------- src/toolset/tool_version.rs | 43 +++----- src/toolset/tool_version_list.rs | 2 +- src/toolset/tool_version_request.rs | 4 +- src/ui/multi_progress_report.rs | 6 +- 91 files changed, 635 insertions(+), 736 deletions(-) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 719c33f73..763da6bbb 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::config::Config; use crate::dirs; use crate::env::RTX_EXE; use crate::file::touch_dir; @@ -45,7 +44,7 @@ pub struct Activate { } impl Activate { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let shell = get_shell(self.shell_type.or(self.shell)) .expect("no shell provided, use `--shell=zsh`"); diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index ee505da5e..14a463fe0 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -16,7 +16,8 @@ pub struct AliasGet { } impl AliasGet { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; match config.get_all_aliases().get(&self.plugin) { Some(plugin) => match plugin.get(&self.alias) { Some(alias) => Ok(rtxprintln!("{}", alias)), diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index fae6e7349..5d3bc1e74 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -21,7 +21,8 @@ pub struct AliasLs { } impl AliasLs { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::get(); for (plugin_name, aliases) in config.get_all_aliases() { if let Some(plugin) = &self.plugin { if plugin_name != plugin { diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index 2d07861d8..30cf763b3 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::config::Config; use crate::plugins::PluginName; mod get; @@ -29,22 +28,22 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { match self { - Self::Get(cmd) => cmd.run(config), - Self::Ls(cmd) => cmd.run(config), - Self::Set(cmd) => cmd.run(config), - Self::Unset(cmd) => cmd.run(config), + Self::Get(cmd) => cmd.run(), + Self::Ls(cmd) => cmd.run(), + Self::Set(cmd) => cmd.run(), + Self::Unset(cmd) => cmd.run(), } } } impl Alias { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::AliasLs { plugin: self.plugin, })); - cmd.run(config) + cmd.run() } } diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index c24e43044..c35985bb3 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -18,11 +18,10 @@ pub struct AliasSet { } impl AliasSet { - pub fn run(self, mut config: Config) -> Result<()> { - config - .global_config - .set_alias(&self.plugin, &self.alias, &self.value); - config.global_config.save() + pub fn run(self) -> Result<()> { + let mut global_config = Config::get().global_config.clone(); + global_config.set_alias(&self.plugin, &self.alias, &self.value); + global_config.save() } } diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 777b3b221..932313330 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -16,9 +16,10 @@ pub struct AliasUnset { } impl AliasUnset { - pub fn run(self, mut config: Config) -> Result<()> { - config.global_config.remove_alias(&self.plugin, &self.alias); - config.global_config.save() + pub fn run(self) -> Result<()> { + let mut global_config = Config::get().global_config.clone(); + global_config.remove_alias(&self.plugin, &self.alias); + global_config.save() } } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index a7a650764..4cba00113 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -17,35 +17,35 @@ pub struct Asdf { } impl Asdf { - pub fn run(mut self, config: Config) -> Result<()> { + pub fn run(mut self, config: &Config) -> Result<()> { let mut args = vec![String::from("rtx")]; args.append(&mut self.args); match args.get(1).map(|s| s.as_str()) { - Some("reshim") => Cli::new().run(config, &args), + Some("reshim") => Cli::new().run(&args), Some("list") => list_versions(config, &args), Some("install") => { if args.len() == 4 { let version = args.pop().unwrap(); args[2] = format!("{}@{}", args[2], version); } - Cli::new().run(config, &args) + Cli::new().run(&args) } - _ => Cli::new().run(config, &args), + _ => Cli::new().run(&args), } } } -fn list_versions(config: Config, args: &Vec) -> Result<()> { +fn list_versions(config: &Config, args: &Vec) -> Result<()> { if args[2] == "all" { let mut new_args: Vec = vec!["rtx".into(), "ls-remote".into()]; if args.len() >= 3 { new_args.push(args[3].clone()); } - return Cli::new().run(config, &new_args); + return Cli::new().run(&new_args); } - let ts = ToolsetBuilder::new().build(&config)?; - let mut versions = ts.list_installed_versions(&config)?; + let ts = ToolsetBuilder::new().build(config)?; + let mut versions = ts.list_installed_versions(config)?; let plugin = match args.len() { 3 => Some(&args[2]), _ => None, diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 2d124c8e7..7d3cb3e98 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -10,9 +10,9 @@ use crate::toolset::ToolsetBuilder; pub struct BinPaths {} impl BinPaths { - pub fn run(self, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; - for p in ts.list_paths(&config) { + pub fn run(self, config: &Config) -> Result<()> { + let ts = ToolsetBuilder::new().build(config)?; + for p in ts.list_paths() { rtxprintln!("{}", p.display()); } Ok(()) diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index 06d414683..dc8cca32a 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -1,6 +1,5 @@ use color_eyre::eyre::Result; -use crate::config::Config; use crate::dirs::CACHE; use crate::file::{display_path, remove_all}; @@ -14,7 +13,7 @@ pub struct CacheClear { } impl CacheClear { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let cache_dirs = match &self.plugin { Some(plugins) => plugins.iter().map(|p| CACHE.join(p)).collect(), None => vec![CACHE.to_path_buf()], diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 10339f440..c262fcadb 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::config::Config; use crate::env; mod clear; @@ -22,17 +21,17 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { match self { - Self::Clear(cmd) => cmd.run(config), + Self::Clear(cmd) => cmd.run(), } } } impl Cache { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { match self.command { - Some(cmd) => cmd.run(config), + Some(cmd) => cmd.run(), None => { // just show the cache dir rtxprintln!("{}", env::RTX_CACHE_DIR.display()); diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 3d449a121..5b5b58b66 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -3,8 +3,6 @@ use clap::ValueEnum; use color_eyre::eyre::Result; use std::fmt::Display; -use crate::config::Config; - /// Generate shell completions #[derive(Debug, clap::Args)] #[clap(aliases = ["complete", "completions"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] @@ -19,7 +17,7 @@ pub struct Completion { } impl Completion { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let c = match self.shell.or(self.shell_type).unwrap() { Shell::Bash => include_str!("../../completions/rtx.bash"), Shell::Fish => include_str!("../../completions/rtx.fish"), diff --git a/src/cli/current.rs b/src/cli/current.rs index 2b95c2433..1718f796c 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -20,8 +20,8 @@ pub struct Current { } impl Current { - pub fn run(self, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let ts = ToolsetBuilder::new().build(config)?; match &self.plugin { Some(plugin_name) => { let plugin_name = unalias_plugin(plugin_name); @@ -29,19 +29,19 @@ impl Current { if !plugin.is_installed() { bail!("Plugin {} is not installed", plugin_name); } - self.one(&config, ts, plugin.clone()) + self.one(ts, plugin.clone()) } - None => self.all(&config, ts), + None => self.all(ts), } } - fn one(&self, config: &Config, ts: Toolset, tool: Arc) -> Result<()> { + fn one(&self, ts: Toolset, tool: Arc) -> Result<()> { if !tool.is_installed() { warn!("Plugin {} is not installed", tool.name()); return Ok(()); } match ts - .list_versions_by_plugin(config) + .list_versions_by_plugin() .into_iter() .find(|(p, _)| p.name() == tool.name()) { @@ -62,8 +62,8 @@ impl Current { Ok(()) } - fn all(&self, config: &Config, ts: Toolset) -> Result<()> { - for (plugin, versions) in ts.list_versions_by_plugin(config) { + fn all(&self, ts: Toolset) -> Result<()> { + for (plugin, versions) in ts.list_versions_by_plugin() { if versions.is_empty() { continue; } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index d9eb45c61..b291d3854 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -14,7 +14,7 @@ use crate::shell::get_shell; pub struct Deactivate {} impl Deactivate { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { if !config.is_activated() { err_inactive()?; } diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 4b0ccecde..96163b943 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,7 +1,5 @@ use color_eyre::eyre::Result; -use crate::config::Config; - /// Output direnv function to use rtx inside direnv /// /// See https://github.com/jdx/rtx#direnv for more information @@ -14,7 +12,7 @@ use crate::config::Config; pub struct DirenvActivate {} impl DirenvActivate { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { rtxprintln!( // source_env "$(rtx direnv envrc "$@")" indoc! {r#" diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 48a512a88..fab6715b2 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, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let ts = ToolsetBuilder::new().build(config)?; let envrc_path = env::RTX_TMP_DIR .join("direnv") @@ -35,7 +35,7 @@ impl Envrc { for cf in config.config_files.keys() { writeln!(file, "watch_file {}", cf.to_string_lossy())?; } - for (k, v) in ts.env(&config) { + for (k, v) in ts.env(config) { if k == "PATH" { writeln!(file, "PATH_add {}", v)?; } else { @@ -47,7 +47,7 @@ impl Envrc { )?; } } - for path in ts.list_paths(&config).into_iter().rev() { + for path in ts.list_paths().into_iter().rev() { writeln!(file, "PATH_add {}", path.to_string_lossy())?; } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index e7b9f5d03..a627beccd 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -20,12 +20,12 @@ struct DirenvWatches { } impl DirenvExec { - pub fn run(self, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let ts = ToolsetBuilder::new().build(config)?; let mut cmd = env_cmd(); - for (k, v) in ts.env_with_path(&config) { + for (k, v) in ts.env_with_path(config) { cmd = cmd.env(k, v); } diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index 681fe3f33..da3c2fe25 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -29,9 +29,9 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { match self { - Self::Activate(cmd) => cmd.run(config), + Self::Activate(cmd) => cmd.run(), Self::Envrc(cmd) => cmd.run(config), Self::Exec(cmd) => cmd.run(config), } @@ -39,7 +39,7 @@ impl Commands { } impl Direnv { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { let cmd = self .command .unwrap_or(Commands::Activate(activate::DirenvActivate {})); diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index aed61ac0e..95db1318a 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -7,7 +7,7 @@ use indenter::indented; use crate::build_time::built_info; use crate::cli::version::VERSION; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::git::Git; use crate::plugins::PluginType; @@ -22,8 +22,9 @@ use crate::{duration, env}; pub struct Doctor {} impl Doctor { - pub fn run(self, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let settings = Settings::try_get()?; + let ts = ToolsetBuilder::new().build(config)?; rtxprintln!("{}", rtx_version()); rtxprintln!("{}", build_info()); rtxprintln!("{}", shell()); @@ -32,10 +33,10 @@ impl Doctor { rtxprintln!( "{}\n{}\n", style("settings:").bold(), - indent(config.settings.to_string()) + indent(settings.to_string()) ); - rtxprintln!("{}", render_config_files(&config)); - rtxprintln!("{}", render_plugins(&config)); + rtxprintln!("{}", render_config_files(config)); + rtxprintln!("{}", render_plugins(config)); rtxprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())); let mut checks = Vec::new(); diff --git a/src/cli/env.rs b/src/cli/env.rs index 3812c871e..2ce817764 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -37,14 +37,14 @@ pub struct Env { } impl Env { - pub fn run(self, config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let opts = InstallOptions { force: false, jobs: self.jobs, raw: self.raw, }; - ts.install_arg_versions(&config, &opts)?; + ts.install_arg_versions(config, &opts)?; if self.json { self.output_json(config, ts) @@ -53,16 +53,16 @@ impl Env { } } - fn output_json(&self, config: Config, ts: Toolset) -> Result<()> { - let env = ts.env_with_path(&config); + fn output_json(&self, config: &Config, ts: Toolset) -> Result<()> { + let env = ts.env_with_path(config); rtxprintln!("{}", serde_json::to_string_pretty(&env)?); Ok(()) } - fn output_shell(&self, config: Config, ts: Toolset) -> Result<()> { + fn output_shell(&self, config: &Config, ts: Toolset) -> Result<()> { let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); - for (k, v) in ts.env_with_path(&config) { + for (k, v) in ts.env_with_path(config) { let k = k.to_string(); let v = v.to_string(); rtxprint!("{}", shell.set_env(&k, &v)); diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index e1c5372e1..aaded7705 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -35,7 +35,7 @@ pub struct EnvVars { } impl EnvVars { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { if self.remove.is_none() && self.env_vars.is_none() { for (key, value) in &config.env { let source = config.env_sources.get(key).unwrap(); @@ -48,7 +48,7 @@ impl EnvVars { .file .unwrap_or_else(|| RTX_DEFAULT_CONFIG_FILENAME.to_string()); - let mut rtx_toml = get_rtx_toml(&config, filename.as_str())?; + let mut rtx_toml = get_rtx_toml(filename.as_str())?; if let Some(env_names) = &self.remove { for name in env_names { @@ -65,9 +65,9 @@ impl EnvVars { } } -fn get_rtx_toml(config: &Config, filename: &str) -> Result { +fn get_rtx_toml(filename: &str) -> Result { let path = dirs::CURRENT.join(filename); - let is_trusted = config_file::is_trusted(&config.settings, &path); + let is_trusted = config_file::is_trusted(&path); let rtx_toml = if path.exists() { RtxToml::from_file(&path, is_trusted)? } else { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index ad932946d..f32c3aeab 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -55,17 +55,17 @@ pub struct Exec { } impl Exec { - pub fn run(self, config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let opts = InstallOptions { force: false, jobs: self.jobs, raw: self.raw, }; - ts.install_arg_versions(&config, &opts)?; + ts.install_arg_versions(config, &opts)?; let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); - let env = ts.env_with_path(&config); + let env = ts.env_with_path(config); self.exec(program, args, env) } diff --git a/src/cli/external.rs b/src/cli/external.rs index 51f507a27..97fa2b300 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -35,7 +35,7 @@ pub fn execute( .unwrap_or_default() .map(|s| s.to_string_lossy().to_string()) .collect(); - plugin.execute_external_command(config, subcommand, args)?; + plugin.execute_external_command(subcommand, args)?; } else { cmd.print_help().unwrap(); } diff --git a/src/cli/global.rs b/src/cli/global.rs index 87042e439..46e82fcbb 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -48,7 +48,7 @@ pub struct Global { } impl Global { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { local( config, &global_file(), diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index fdd023107..cc3df1e45 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -33,11 +33,11 @@ pub struct HookEnv { } impl HookEnv { - pub fn run(self, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let ts = ToolsetBuilder::new().build(config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); rtxprint!("{}", hook_env::clear_old_env(&*shell)); - let mut env = ts.env(&config); + let mut env = ts.env(config); let env_path = env.remove("PATH"); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); @@ -46,17 +46,18 @@ impl HookEnv { if let Some(p) = env_path { paths.extend(split_paths(&p).collect_vec()); } - paths.extend(ts.list_paths(&config)); // load the active runtime paths + paths.extend(ts.list_paths()); // load the active runtime paths diff.path = paths.clone(); // update __RTX_DIFF with the new paths for the next run - patches.extend(self.build_path_operations(&config.settings, &paths, &__RTX_DIFF.path)?); + let settings = Settings::try_get()?; + patches.extend(self.build_path_operations(&settings, &paths, &__RTX_DIFF.path)?); patches.push(self.build_diff_operation(&diff)?); - patches.push(self.build_watch_operation(&config)?); + patches.push(self.build_watch_operation(config)?); let output = hook_env::build_env_commands(&*shell, &patches); rtxprint!("{output}"); if self.status { - self.display_status(&config, &ts); + self.display_status(config, &ts); } Ok(()) @@ -64,7 +65,7 @@ impl HookEnv { fn display_status(&self, config: &Config, ts: &Toolset) { let installed_versions = ts - .list_current_installed_versions(config) + .list_current_installed_versions() .into_iter() .rev() .map(|(_, v)| v.to_string()) diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 6a62a35e8..167f5d129 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -2,7 +2,7 @@ use std::path::Path; use color_eyre::eyre::Result; -use crate::config::Config; +use crate::config::Settings; use crate::file::remove_all; use crate::ui::prompt; @@ -24,7 +24,7 @@ pub struct Implode { } impl Implode { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let mut files = vec![&*dirs::DATA, &*dirs::CACHE, &*env::RTX_EXE]; if self.config { files.push(&*dirs::CONFIG); @@ -34,7 +34,7 @@ impl Implode { rtxprintln!("rm -rf {}", f.display()); } - if self.confirm_remove(&config, f)? { + if self.confirm_remove(f)? { if f.is_dir() { remove_all(f)?; } else { @@ -46,10 +46,11 @@ impl Implode { Ok(()) } - fn confirm_remove(&self, config: &Config, f: &Path) -> Result { + fn confirm_remove(&self, f: &Path) -> Result { + let settings = Settings::try_get()?; if self.dry_run { Ok(false) - } else if config.settings.yes { + } else if settings.yes { Ok(true) } else { let r = prompt::confirm(&format!("remove {} ?", f.display()))?; diff --git a/src/cli/install.rs b/src/cli/install.rs index e727400a6..e5db33a7e 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -44,7 +44,7 @@ pub struct Install { } impl Install { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { match &self.tool { Some(runtime) => self.install_runtimes(config, runtime)?, None => self.install_missing_runtimes(config)?, @@ -52,18 +52,16 @@ impl Install { Ok(()) } - fn install_runtimes(&self, config: Config, runtimes: &[ToolArg]) -> Result<()> { - let mpr = MultiProgressReport::new(&config.settings); - let mut ts = ToolsetBuilder::new() - .with_latest_versions() - .build(&config)?; - let tool_versions = self.get_requested_tool_versions(&config, &ts, runtimes, &mpr)?; + fn install_runtimes(&self, config: &Config, runtimes: &[ToolArg]) -> Result<()> { + let mpr = MultiProgressReport::new(); + let mut ts = ToolsetBuilder::new().with_latest_versions().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(&config, tool_versions, &mpr, &self.install_opts()) + ts.install_versions(config, tool_versions, &mpr, &self.install_opts()) } fn install_opts(&self) -> InstallOptions { @@ -113,19 +111,17 @@ impl Install { let mut tool_versions = vec![]; for (plugin_name, tvr, opts) in requests { let plugin = config.get_or_create_plugin(&plugin_name); - plugin.ensure_installed(config, Some(mpr), false)?; - let tv = tvr.resolve(config, plugin, opts, ts.latest_versions)?; + plugin.ensure_installed(Some(mpr), false)?; + let tv = tvr.resolve(plugin, opts, ts.latest_versions)?; tool_versions.push(tv); } Ok(tool_versions) } - fn install_missing_runtimes(&self, config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new() - .with_latest_versions() - .build(&config)?; + fn install_missing_runtimes(&self, config: &Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_latest_versions().build(config)?; let versions = ts - .list_missing_versions(&config) + .list_missing_versions(config) .into_iter() .cloned() .collect::>(); @@ -133,8 +129,8 @@ impl Install { info!("all runtimes are installed"); return Ok(()); } - let mpr = MultiProgressReport::new(&config.settings); - ts.install_versions(&config, versions, &mpr, &self.install_opts())?; + let mpr = MultiProgressReport::new(); + ts.install_versions(config, versions, &mpr, &self.install_opts())?; Ok(()) } } diff --git a/src/cli/latest.rs b/src/cli/latest.rs index edeaeb548..4b37e8914 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -26,7 +26,7 @@ pub struct Latest { } impl Latest { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> 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(&config, None, false)?; + plugin.ensure_installed(None, false)?; if let Some(v) = prefix { prefix = Some(config.resolve_alias(plugin.name(), &v)?); } @@ -45,7 +45,7 @@ impl Latest { let latest_version = if self.installed { plugin.latest_installed_version(prefix)? } else { - plugin.latest_version(&config.settings, prefix)? + plugin.latest_version(prefix)? }; if let Some(version) = latest_version { rtxprintln!("{}", version); diff --git a/src/cli/link.rs b/src/cli/link.rs index 31468931b..9a9b10b2b 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -33,7 +33,7 @@ pub struct Link { } impl Link { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> 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 d2162affd..90fa1ab2a 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -5,7 +5,7 @@ use console::style; use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; -use crate::config::{config_file, Config}; +use crate::config::{config_file, Config, Settings}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; @@ -54,7 +54,7 @@ pub struct Local { } impl Local { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { let path = if self.parent { get_parent_path()? } else { @@ -92,7 +92,7 @@ pub fn get_parent_path() -> Result { #[allow(clippy::too_many_arguments)] pub fn local( - config: Config, + config: &Config, path: &Path, runtime: Vec, remove: Option>, @@ -100,7 +100,8 @@ pub fn local( fuzzy: bool, show_path: bool, ) -> Result<()> { - let mut cf = config_file::parse_or_init(&config.settings, path)?; + let settings = Settings::try_get()?; + let mut cf = config_file::parse_or_init(path)?; if show_path { rtxprintln!("{}", path.display()); return Ok(()); @@ -124,8 +125,8 @@ pub fn local( if cf.display_runtime(&runtimes)? { return Ok(()); } - let pin = pin || (config.settings.asdf_compat && !fuzzy); - cf.add_runtimes(&config, &runtimes, pin)?; + let pin = pin || (settings.asdf_compat && !fuzzy); + cf.add_runtimes(config, &runtimes, pin)?; let tools = runtimes.iter().map(|r| r.to_string()).join(" "); rtxprintln!( "{} {} {}", diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 79287c6bd..54c7a2d89 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -58,14 +58,14 @@ pub struct Ls { } impl Ls { - pub fn run(mut self, config: Config) -> Result<()> { + pub fn run(mut self, config: &Config) -> Result<()> { self.plugin = self .plugin .or_else(|| self.plugin_flag.clone().map(|p| vec![p])) .map(|p| p.into_iter().map(|p| unalias_plugin(&p).into()).collect()); - self.verify_plugin(&config)?; + self.verify_plugin(config)?; - let mut runtimes = self.get_runtime_list(&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 @@ -85,7 +85,7 @@ impl Ls { } else if self.parseable { self.display_parseable(runtimes) } else { - self.display_user(&config, runtimes) + self.display_user(runtimes) } } @@ -146,7 +146,7 @@ impl Ls { Ok(()) } - fn display_user(&self, config: &Config, runtimes: Vec) -> Result<()> { + fn display_user(&self, runtimes: Vec) -> Result<()> { let output = runtimes .into_iter() .map(|(p, tv, source)| { @@ -156,10 +156,7 @@ impl Ls { } else if !p.is_version_installed(&tv) { VersionStatus::Missing(tv.version) } else if source.is_some() { - VersionStatus::Active( - tv.version.clone(), - p.is_version_outdated(config, &tv, p.clone()), - ) + VersionStatus::Active(tv.version.clone(), p.is_version_outdated(&tv, p.clone())) } else { VersionStatus::Inactive(tv.version) }; @@ -219,7 +216,7 @@ impl Ls { .collect(); let active = ts - .list_current_versions(config) + .list_current_versions() .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) .collect::, ToolVersion)>>(); diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 89eba68da..2bbd1f454 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -33,15 +33,15 @@ pub struct LsRemote { } impl LsRemote { - pub fn run(self, config: Config) -> Result<()> { - if let Some(plugin) = self.get_plugin(&config)? { - self.run_single(config, plugin) + pub fn run(self, config: &Config) -> Result<()> { + if let Some(plugin) = self.get_plugin(config)? { + self.run_single(plugin) } else { self.run_all(config) } } - fn run_single(self, config: Config, plugin: Arc) -> Result<()> { + fn run_single(self, plugin: Arc) -> Result<()> { let prefix = match &self.plugin { Some(tool_arg) => match &tool_arg.tvr { Some(ToolVersionRequest::Version(_, v)) => Some(v.clone()), @@ -50,7 +50,7 @@ impl LsRemote { _ => self.prefix.clone(), }; - let versions = plugin.list_remote_versions(&config.settings)?; + let versions = plugin.list_remote_versions()?; let versions = match prefix { Some(prefix) => versions .into_iter() @@ -66,12 +66,12 @@ impl LsRemote { Ok(()) } - fn run_all(self, config: Config) -> Result<()> { + fn run_all(self, config: &Config) -> Result<()> { let versions = config .list_plugins() .into_par_iter() .map(|p| { - let versions = p.list_remote_versions(&config.settings)?; + let versions = p.list_remote_versions()?; Ok((p, versions)) }) .collect::>>()? @@ -90,7 +90,7 @@ impl LsRemote { match &self.plugin { Some(tool_arg) => { let plugin = config.get_or_create_plugin(&tool_arg.plugin); - plugin.ensure_installed(config, None, false)?; + plugin.ensure_installed(None, false)?; Ok(Some(plugin)) } None => Ok(None), diff --git a/src/cli/mod.rs b/src/cli/mod.rs index f8bc3397c..508886a17 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -106,14 +106,14 @@ pub enum Commands { } impl Commands { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { match self { - Self::Activate(cmd) => cmd.run(config), - Self::Alias(cmd) => cmd.run(config), + Self::Activate(cmd) => cmd.run(), + Self::Alias(cmd) => cmd.run(), Self::Asdf(cmd) => cmd.run(config), Self::BinPaths(cmd) => cmd.run(config), - Self::Cache(cmd) => cmd.run(config), - Self::Completion(cmd) => cmd.run(config), + Self::Cache(cmd) => cmd.run(), + Self::Completion(cmd) => cmd.run(), Self::Current(cmd) => cmd.run(config), Self::Deactivate(cmd) => cmd.run(config), Self::Direnv(cmd) => cmd.run(config), @@ -123,7 +123,7 @@ impl Commands { Self::Exec(cmd) => cmd.run(config), Self::Global(cmd) => cmd.run(config), Self::HookEnv(cmd) => cmd.run(config), - Self::Implode(cmd) => cmd.run(config), + Self::Implode(cmd) => cmd.run(), Self::Install(cmd) => cmd.run(config), Self::Latest(cmd) => cmd.run(config), Self::Link(cmd) => cmd.run(config), @@ -134,25 +134,25 @@ impl Commands { Self::Plugins(cmd) => cmd.run(config), Self::Prune(cmd) => cmd.run(config), Self::Reshim(cmd) => cmd.run(config), - Self::Settings(cmd) => cmd.run(config), - Self::Shell(cmd) => cmd.run(config), - Self::Sync(cmd) => cmd.run(config), - Self::Trust(cmd) => cmd.run(config), + Self::Settings(cmd) => cmd.run(), + Self::Shell(cmd) => cmd.run(), + Self::Sync(cmd) => cmd.run(), + Self::Trust(cmd) => cmd.run(), Self::Uninstall(cmd) => cmd.run(config), Self::Upgrade(cmd) => cmd.run(config), Self::Use(cmd) => cmd.run(config), - Self::Version(cmd) => cmd.run(config), + Self::Version(cmd) => cmd.run(), Self::Where(cmd) => cmd.run(config), - Self::Which(cmd) => cmd.run(config), + Self::Which(cmd) => cmd.run(), #[cfg(feature = "clap_complete")] - Self::RenderCompletion(cmd) => cmd.run(config), + Self::RenderCompletion(cmd) => cmd.run(), #[cfg(debug_assertions)] - Self::RenderHelp(cmd) => cmd.run(config), + Self::RenderHelp(cmd) => cmd.run(), #[cfg(feature = "clap_mangen")] - Self::RenderMangen(cmd) => cmd.run(config), + Self::RenderMangen(cmd) => cmd.run(), } } } @@ -195,21 +195,22 @@ impl Cli { ) } - pub fn run(self, config: Config, args: &Vec) -> Result<()> { + pub fn run(self, args: &Vec) -> Result<()> { debug!("{}", &args.join(" ")); + let config = Config::try_get()?; if args[1..] == ["-v"] { // normally this would be considered --verbose - return version::Version {}.run(config); + return version::Version {}.run(); } let matches = self.command.get_matches_from(args); if let Some((command, sub_m)) = matches.subcommand() { if command == "self-update" { - return SelfUpdate::from_arg_matches(sub_m)?.run(config); + return SelfUpdate::from_arg_matches(sub_m)?.run(); } external::execute(&config, command, sub_m, self.external_commands)?; } let cmd = Commands::from_arg_matches(&matches)?; - cmd.run(config) + cmd.run(&config) } pub fn settings(self, args: &Vec) -> SettingsPartial { @@ -279,9 +280,9 @@ pub mod tests { *env::ARGS.write().unwrap() = args.clone(); STDOUT.lock().unwrap().clear(); STDERR.lock().unwrap().clear(); - let config = Config::load()?; + let config = Config::try_get()?; Cli::new_with_external_commands(&config) - .run(config, args) + .run(args) .with_section(|| format!("{}", args.join(" ").header("Command:")))?; Ok(()) diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index c5a673c80..46c84736d 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -21,8 +21,8 @@ pub struct Outdated { } impl Outdated { - pub fn run(self, config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let tool_set = self .tool .iter() @@ -30,7 +30,7 @@ impl Outdated { .collect::>(); ts.versions .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); - let outdated = ts.list_outdated_versions(&config); + let outdated = ts.list_outdated_versions(); if outdated.is_empty() { info!("All tools are up to date"); } else { diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 78f506ae1..b7f8d32c2 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -46,44 +46,39 @@ pub struct PluginsInstall { } impl PluginsInstall { - pub fn run(self, config: Config) -> Result<()> { - let mpr = MultiProgressReport::new(&config.settings); + pub fn run(self, config: &Config) -> Result<()> { + let mpr = MultiProgressReport::new(); 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(&config, name, git_url, &mpr)?; + self.install_one(name, git_url, &mpr)?; } else { let mut plugins: Vec = vec![name]; if let Some(second) = self.git_url.clone() { plugins.push(second); }; plugins.extend(self.rest.clone()); - self.install_many(config, plugins, mpr)?; + self.install_many(plugins, mpr)?; } Ok(()) } - 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); + 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"); } - self.install_many(config, missing_plugins, mpr)?; + self.install_many(missing_plugins, mpr)?; Ok(()) } - fn install_many( - &self, - config: Config, - plugins: Vec, - mpr: MultiProgressReport, - ) -> Result<()> { + fn install_many(&self, plugins: Vec, mpr: MultiProgressReport) -> Result<()> { for plugin in plugins { - self.install_one(&config, plugin, None, &mpr)?; + self.install_one(plugin, None, &mpr)?; } Ok(()) // TODO: run in parallel @@ -101,7 +96,6 @@ impl PluginsInstall { fn install_one( &self, - config: &Config, name: PluginName, git_url: Option, mpr: &MultiProgressReport, @@ -112,7 +106,7 @@ impl PluginsInstall { mpr.warn(format!("Plugin {} already installed", name)); mpr.warn("Use --force to install anyway".to_string()); } else { - plugin.ensure_installed(config, Some(mpr), true)?; + plugin.ensure_installed(Some(mpr), true)?; } Ok(()) } diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index ffe6400ef..21b1fc4f9 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -5,7 +5,6 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use path_absolutize::Absolutize; -use crate::config::Config; use crate::file::{make_symlink, remove_all}; use crate::plugins::unalias_plugin; @@ -33,7 +32,7 @@ pub struct PluginsLink { } impl PluginsLink { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let (name, path) = match self.path { Some(path) => (self.name, path), None => { diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 18bb1c1b4..0118f55de 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -42,7 +42,7 @@ pub struct PluginsLs { } impl PluginsLs { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { let mut tools = config.list_plugins().into_iter().collect::>(); if self.all { diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 539ab1686..90ffb1d51 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -22,7 +22,7 @@ pub struct PluginsLsRemote { } impl PluginsLsRemote { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { let installed_plugins = config .list_plugins() .into_iter() diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 91a82efec..1a5b29c13 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -58,10 +58,10 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { match self { Self::Install(cmd) => cmd.run(config), - Self::Link(cmd) => cmd.run(config), + Self::Link(cmd) => cmd.run(), Self::Ls(cmd) => cmd.run(config), Self::LsRemote(cmd) => cmd.run(config), Self::Uninstall(cmd) => cmd.run(config), @@ -71,7 +71,7 @@ impl Commands { } impl Plugins { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::PluginsLs { all: self.all, core: self.core, diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 46cbe74d6..af5c7a58a 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -24,8 +24,8 @@ pub struct PluginsUninstall { } impl PluginsUninstall { - pub fn run(self, config: Config) -> Result<()> { - let mpr = MultiProgressReport::new(&config.settings); + pub fn run(self, config: &Config) -> Result<()> { + let mpr = MultiProgressReport::new(); let plugins = match self.all { true => config @@ -38,7 +38,7 @@ impl PluginsUninstall { for plugin_name in plugins { let plugin_name = unalias_plugin(&plugin_name); - self.uninstall_one(&config, plugin_name, &mpr)?; + self.uninstall_one(config, plugin_name, &mpr)?; } Ok(()) } diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 200d853ca..6ef8f56a9 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -20,7 +20,7 @@ pub struct Update { } impl Update { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { let plugins: Vec<_> = match self.plugin { Some(plugins) => plugins .into_iter() diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 675f508a6..218dbc479 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use color_eyre::eyre::Result; use console::style; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolsetBuilder}; @@ -30,10 +30,10 @@ pub struct Prune { } impl Prune { - pub fn run(self, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let ts = ToolsetBuilder::new().build(config)?; let mut to_delete = ts - .list_installed_versions(&config)? + .list_installed_versions(config)? .into_iter() .map(|(p, tv)| (tv.to_string(), (p, tv))) .collect::, ToolVersion)>>(); @@ -44,30 +44,26 @@ impl Prune { for cf in config.get_tracked_config_files()?.values() { let mut ts = cf.to_toolset().clone(); - ts.resolve(&config); - for (_, tv) in ts.list_current_versions(&config) { + ts.resolve(config); + for (_, tv) in ts.list_current_versions() { to_delete.remove(&tv.to_string()); } } - self.delete(&config, to_delete.into_values().collect()) + self.delete(to_delete.into_values().collect()) } - fn delete( - &self, - config: &Config, - to_delete: Vec<(Arc, ToolVersion)>, - ) -> Result<()> { - let mpr = MultiProgressReport::new(&config.settings); + fn delete(&self, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { + let settings = Settings::try_get()?; + let mpr = MultiProgressReport::new(); for (p, tv) in to_delete { let mut pr = mpr.add(); if self.dry_run { pr.set_prefix(format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); } - if self.dry_run || config.settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? - { + if self.dry_run || settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? { p.decorate_progress_bar(&mut pr, Some(&tv)); - p.uninstall_version(config, &tv, &pr, self.dry_run)?; + p.uninstall_version(&tv, &pr, self.dry_run)?; pr.finish(); } } diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 73591ee8c..b81866a84 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -5,7 +5,6 @@ use clap_complete::generate; use color_eyre::eyre::Result; use crate::cli::self_update::SelfUpdate; -use crate::config::Config; use crate::shell::completions; /// Generate shell completions @@ -22,7 +21,7 @@ pub struct RenderCompletion { } impl RenderCompletion { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let shell = self.shell.or(self.shell_type).unwrap(); let mut cmd = crate::cli::Cli::command().subcommand(SelfUpdate::command()); diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index b10bad218..bac24c20b 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use crate::cli::self_update::SelfUpdate; use crate::cli::Cli; -use crate::config::Config; + use crate::file; /// internal command to generate markdown from help @@ -14,7 +14,7 @@ use crate::file; pub struct RenderHelp {} impl RenderHelp { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let readme = file::read_to_string("README.md")?; let mut current_readme = readme.split(""); diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 9a9678724..296331acf 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -6,7 +6,6 @@ use eyre::Result; use crate::cli::self_update::SelfUpdate; use crate::cli::{version, Cli}; -use crate::config::Config; /// internal command to generate markdown from help #[derive(Debug, clap::Args)] @@ -14,7 +13,7 @@ use crate::config::Config; pub struct RenderMangen {} impl RenderMangen { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let cli = Cli::command() .subcommand(SelfUpdate::command()) .version(&*version::RAW_VERSION) diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 9c8e50e01..05b422143 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -30,10 +30,10 @@ pub struct Reshim { } impl Reshim { - pub fn run(self, config: Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let ts = ToolsetBuilder::new().build(config)?; - shims::reshim(&config, &ts) + shims::reshim(config, &ts) } } diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 8b85ef041..55fb4f6b0 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -6,7 +6,6 @@ use self_update::update::Release; use self_update::{cargo_crate_version, Status}; use crate::cli::version::{ARCH, OS}; -use crate::config::Config; use crate::{cmd, env}; @@ -34,7 +33,7 @@ pub struct SelfUpdate { } impl SelfUpdate { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let status = self.do_update()?; if status.updated() { diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index c28d57c92..35acd7414 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::{eyre, Result}; -use crate::config::Config; +use crate::config::Settings; /// Show a current setting /// @@ -16,8 +16,9 @@ pub struct SettingsGet { } impl SettingsGet { - pub fn run(self, config: Config) -> Result<()> { - match config.settings.to_index_map().get(&self.setting) { + pub fn run(self) -> Result<()> { + let settings = Settings::try_get()?; + match settings.to_index_map().get(&self.setting) { Some(value) => Ok(rtxprintln!("{}", value)), None => Err(eyre!("Unknown setting: {}", self.setting)), } diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index eb3a6391c..bab77ced0 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Result; -use crate::config::Config; +use crate::config::Settings; /// Show current settings /// @@ -13,8 +13,9 @@ use crate::config::Config; pub struct SettingsLs {} impl SettingsLs { - pub fn run(self, config: Config) -> Result<()> { - for (key, value) in config.settings.to_index_map() { + pub fn run(self) -> Result<()> { + let settings = Settings::try_get()?; + for (key, value) in settings.to_index_map() { rtxprintln!("{} = {}", key, value); } Ok(()) diff --git a/src/cli/settings/mod.rs b/src/cli/settings/mod.rs index 5dfb50289..c42c55058 100644 --- a/src/cli/settings/mod.rs +++ b/src/cli/settings/mod.rs @@ -1,8 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::config::Config; - mod get; mod ls; mod set; @@ -24,20 +22,20 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { match self { - Self::Get(cmd) => cmd.run(config), - Self::Ls(cmd) => cmd.run(config), - Self::Set(cmd) => cmd.run(config), - Self::Unset(cmd) => cmd.run(config), + Self::Get(cmd) => cmd.run(), + Self::Ls(cmd) => cmd.run(), + Self::Set(cmd) => cmd.run(), + Self::Unset(cmd) => cmd.run(), } } } impl Settings { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::SettingsLs {})); - cmd.run(config) + cmd.run() } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 160e436a2..81bf55d93 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -17,7 +17,7 @@ pub struct SettingsSet { } impl SettingsSet { - pub fn run(self, mut config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let value: toml_edit::Value = match self.setting.as_str() { "experimental" => parse_bool(&self.value)?, "always_keep_download" => parse_bool(&self.value)?, @@ -33,8 +33,9 @@ impl SettingsSet { _ => return Err(eyre!("Unknown setting: {}", self.setting)), }; - config.global_config.update_setting(&self.setting, value); - config.global_config.save() + let mut global_config = Config::try_get()?.global_config.clone(); + global_config.update_setting(&self.setting, value); + global_config.save() } } diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index d7e609194..c0b5310de 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -14,9 +14,10 @@ pub struct SettingsUnset { } impl SettingsUnset { - pub fn run(self, mut config: Config) -> Result<()> { - config.global_config.remove_setting(&self.setting); - config.global_config.save() + pub fn run(self) -> Result<()> { + let mut global_config = Config::try_get()?.global_config.clone(); + global_config.remove_setting(&self.setting); + global_config.save() } } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index ebc8e21f8..edbbe40f3 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -32,7 +32,8 @@ pub struct Shell { } impl Shell { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; if !config.is_activated() { err_inactive()?; } @@ -47,7 +48,7 @@ impl Shell { let shell = get_shell(None).expect("no shell detected"); - for (p, tv) in ts.list_current_installed_versions(&config) { + for (p, tv) in ts.list_current_installed_versions() { let source = &ts.versions.get(p.name()).unwrap().source; if matches!(source, ToolSource::Argument) { let k = format!("RTX_{}_VERSION", p.name().to_uppercase()); diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs index 2db3317fe..ae0ac7658 100644 --- a/src/cli/sync/mod.rs +++ b/src/cli/sync/mod.rs @@ -1,8 +1,6 @@ use clap::Subcommand; use color_eyre::eyre::Result; -use crate::config::Config; - mod node; mod python; @@ -20,16 +18,16 @@ enum Commands { } impl Commands { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { match self { - Self::Node(cmd) => cmd.run(config), - Self::Python(cmd) => cmd.run(config), + Self::Node(cmd) => cmd.run(), + Self::Python(cmd) => cmd.run(), } } } impl Sync { - pub fn run(self, config: Config) -> Result<()> { - self.command.run(config) + pub fn run(self) -> Result<()> { + self.command.run() } } diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index ee7957d4e..29eb0a5f6 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -36,18 +36,19 @@ pub struct SyncNodeType { } impl SyncNode { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; if self._type.brew { - self.run_brew(config)?; + self.run_brew(&config)?; } else if self._type.nvm { - self.run_nvm(config)?; + self.run_nvm(&config)?; } else if self._type.nodenv { - self.run_nodenv(config)?; + self.run_nodenv(&config)?; } Ok(()) } - fn run_brew(self, config: Config) -> Result<()> { + fn run_brew(self, config: &Config) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); @@ -68,7 +69,7 @@ impl SyncNode { config.rebuild_shims_and_runtime_symlinks() } - fn run_nvm(self, config: Config) -> Result<()> { + fn run_nvm(self, config: &Config) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let nvm_versions_path = NVM_DIR.join("versions").join("node"); @@ -86,7 +87,7 @@ impl SyncNode { config.rebuild_shims_and_runtime_symlinks() } - fn run_nodenv(self, config: Config) -> Result<()> { + fn run_nodenv(self, config: &Config) -> 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 9e0e38de7..148933e35 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -20,7 +20,8 @@ pub struct SyncPython { } impl SyncPython { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let python = config.get_or_create_plugin(&PluginName::from("python")); let pyenv_versions_path = PYENV_ROOT.join("versions"); diff --git a/src/cli/trust.rs b/src/cli/trust.rs index c679eb3c1..177b5612f 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -4,7 +4,7 @@ use clap::ValueHint; use color_eyre::eyre::Result; use crate::cli::local; -use crate::config::{config_file, Config}; +use crate::config::config_file; /// Marks a config file as trusted /// @@ -28,7 +28,7 @@ pub struct Trust { } impl Trust { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { let path = match &self.config_file { Some(filename) => PathBuf::from(filename), None => local::get_parent_path()?, diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index b23ce6ff7..5f09581e5 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -30,11 +30,11 @@ pub struct Uninstall { } impl Uninstall { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> Result<()> { let tool_versions = if self.installed_tool.is_empty() && self.all { - self.get_all_tool_versions(&config)? + self.get_all_tool_versions(config)? } else { - self.get_requested_tool_versions(&config)? + self.get_requested_tool_versions(config)? }; let tool_versions = tool_versions .into_iter() @@ -45,7 +45,7 @@ impl Uninstall { bail!("multiple tools specified, use --all to uninstall all versions"); } - let mpr = MultiProgressReport::new(&config.settings); + let mpr = MultiProgressReport::new(); for (plugin, tv) in tool_versions { if !plugin.is_version_installed(&tv) { warn!("{} is not installed", style(&tv).cyan().for_stderr()); @@ -54,7 +54,7 @@ impl Uninstall { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, Some(&tv)); - if let Err(err) = plugin.uninstall_version(&config, &tv, &pr, self.dry_run) { + if let Err(err) = plugin.uninstall_version(&tv, &pr, self.dry_run) { pr.error(err.to_string()); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); } @@ -65,9 +65,9 @@ impl Uninstall { } } - let ts = ToolsetBuilder::new().build(&config)?; - shims::reshim(&config, &ts).wrap_err("failed to reshim")?; - runtime_symlinks::rebuild(&config)?; + let ts = ToolsetBuilder::new().build(config)?; + shims::reshim(config, &ts).wrap_err("failed to reshim")?; + runtime_symlinks::rebuild(config)?; Ok(()) } @@ -106,7 +106,7 @@ impl Uninstall { if let Some(tvr) = &a.tvr { tvs.push(( tool.clone(), - tvr.resolve(config, tool.clone(), Default::default(), false)?, + tvr.resolve(tool.clone(), Default::default(), false)?, )); } if tvs.is_empty() { diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index adbd6cd3d..f2634421e 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -40,8 +40,8 @@ pub struct Upgrade { } impl Upgrade { - pub fn run(self, config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let tool_set = self .tool .iter() @@ -49,18 +49,18 @@ impl Upgrade { .collect::>(); ts.versions .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); - let outdated = ts.list_outdated_versions(&config); + let outdated = ts.list_outdated_versions(); if outdated.is_empty() { info!("All tools are up to date"); } else { - self.upgrade(&config, outdated)?; + self.upgrade(config, outdated)?; } Ok(()) } fn upgrade(&self, config: &Config, outdated: OutputVec) -> Result<()> { - let mpr = MultiProgressReport::new(&config.settings); + let mpr = MultiProgressReport::new(); let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let new_versions = outdated @@ -95,7 +95,7 @@ impl Upgrade { ts.install_versions(config, new_versions, &mpr, &opts)?; for (tool, tv) in to_remove { let mut pr = mpr.add(); - self.uninstall_old_version(config, tool.clone(), &tv, &mut pr)?; + self.uninstall_old_version(tool.clone(), &tv, &mut pr)?; } let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; @@ -106,13 +106,12 @@ impl Upgrade { fn uninstall_old_version( &self, - config: &Config, tool: Arc, tv: &ToolVersion, pr: &mut ProgressReport, ) -> Result<()> { tool.decorate_progress_bar(pr, Some(tv)); - match tool.uninstall_version(config, tv, pr, self.dry_run) { + match tool.uninstall_version(tv, pr, self.dry_run) { Ok(_) => { pr.finish(); Ok(()) diff --git a/src/cli/use.rs b/src/cli/use.rs index 554ed5ea6..371f00e44 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::config_file::ConfigFile; -use crate::config::{config_file, Config}; +use crate::config::{config_file, Config, Settings}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; use crate::plugins::PluginName; @@ -77,21 +77,22 @@ pub struct Use { } impl Use { - pub fn run(self, config: Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + pub fn run(self, config: &Config) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let opts = InstallOptions { force: self.force, jobs: self.jobs, raw: self.raw, }; - ts.install_arg_versions(&config, &opts)?; + ts.install_arg_versions(config, &opts)?; ts.versions .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); - let mut cf = self.get_config_file(&config)?; - let pin = self.pin || (config.settings.asdf_compat && !self.fuzzy); + let mut cf = self.get_config_file()?; + let settings = Settings::try_get()?; + let pin = self.pin || (settings.asdf_compat && !self.fuzzy); for (plugin_name, tvl) in ts.versions { let versions: Vec = tvl @@ -109,7 +110,7 @@ impl Use { } if self.global { - self.warn_if_hidden(&config, cf.get_path()); + self.warn_if_hidden(config, cf.get_path()); } for plugin_name in self.remove.unwrap_or_default() { cf.remove_plugin(&plugin_name); @@ -125,7 +126,7 @@ impl Use { Ok(()) } - fn get_config_file(&self, config: &Config) -> Result> { + fn get_config_file(&self) -> Result> { let path = if self.global { global_file() } else if let Some(env) = &self.env { @@ -135,7 +136,7 @@ impl Use { } else { config_file_from_dir(&dirs::CURRENT) }; - config_file::parse_or_init(&config.settings, &path) + config_file::parse_or_init(&path) } fn warn_if_hidden(&self, config: &Config, global: &Path) { diff --git a/src/cli/version.rs b/src/cli/version.rs index b155ea3b5..babb777ee 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -8,7 +8,7 @@ use versions::Versioning; use crate::build_time::{built_info, BUILD_TIME}; use crate::cli::self_update::SelfUpdate; -use crate::config::Config; + use crate::env::CI; use crate::file::modified_duration; @@ -44,7 +44,7 @@ pub static VERSION: Lazy = Lazy::new(|| { pub static RAW_VERSION: Lazy = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string()); impl Version { - pub fn run(self, _config: Config) -> Result<()> { + pub fn run(self) -> Result<()> { show_version(); Ok(()) } diff --git a/src/cli/where.rs b/src/cli/where.rs index 8be4c1471..95455245f 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -28,14 +28,14 @@ pub struct Where { } impl Where { - pub fn run(self, config: Config) -> Result<()> { + pub fn run(self, config: &Config) -> 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(&config)?; + .build(config)?; let v = ts .versions .get(&self.tool.plugin) @@ -52,7 +52,7 @@ impl Where { match runtime .tvr .as_ref() - .map(|tvr| tvr.resolve(&config, plugin.clone(), Default::default(), false)) + .map(|tvr| tvr.resolve(plugin.clone(), Default::default(), false)) { Some(Ok(tv)) if plugin.is_version_installed(&tv) => { rtxprintln!("{}", tv.install_path().to_string_lossy()); diff --git a/src/cli/which.rs b/src/cli/which.rs index cfcfd9f0c..e0c1592cb 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -28,17 +28,17 @@ pub struct Which { } impl Which { - pub fn run(self, config: Config) -> Result<()> { - let ts = self.get_toolset(&config)?; + pub fn run(self) -> Result<()> { + let ts = self.get_toolset()?; - match ts.which(&config, &self.bin_name) { + match ts.which(&self.bin_name) { Some((p, tv)) => { if self.version { rtxprintln!("{}", tv.version); } else if self.plugin { rtxprintln!("{p}"); } else { - let path = p.which(&config, &ts, &tv, &self.bin_name)?; + let path = p.which(&tv, &self.bin_name)?; rtxprintln!("{}", path.unwrap().display()); } Ok(()) @@ -46,12 +46,13 @@ impl Which { None => Err(eyre!("{} not found", self.bin_name)), } } - fn get_toolset(&self, config: &Config) -> Result { + fn get_toolset(&self) -> Result { + let config = Config::try_get()?; let mut tsb = ToolsetBuilder::new(); if let Some(tool) = &self.tool { tsb = tsb.with_args(&[tool.clone()]); } - let ts = tsb.build(config)?; + let ts = tsb.build(&config)?; Ok(ts) } } diff --git a/src/cmd.rs b/src/cmd.rs index 826897f54..42e58e38a 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -6,11 +6,11 @@ use std::process::{Command, ExitStatus, Stdio}; use std::sync::mpsc::channel; use std::thread; +use crate::config::Settings; use color_eyre::Result; use duct::{Expression, IntoExecutablePath}; use eyre::Context; -use crate::config::Settings; use crate::env; use crate::errors::Error::ScriptFailed; use crate::file::display_path; @@ -90,13 +90,12 @@ where pub struct CmdLineRunner<'a> { cmd: Command, - settings: &'a Settings, pr: Option<&'a ProgressReport>, stdin: Option, } impl<'a> CmdLineRunner<'a> { - pub fn new>(settings: &'a Settings, program: P) -> Self { + pub fn new>(program: P) -> Self { let mut cmd = Command::new(program); cmd.stdin(Stdio::null()); cmd.stdout(Stdio::piped()); @@ -104,7 +103,6 @@ impl<'a> CmdLineRunner<'a> { Self { cmd, - settings, pr: None, stdin: None, } @@ -185,8 +183,9 @@ impl<'a> CmdLineRunner<'a> { } pub fn execute(mut self) -> Result<()> { + let settings = &Settings::try_get()?; debug!("$ {}", self); - if self.settings.raw { + if settings.raw { return self.execute_raw(); } let mut cp = self @@ -286,10 +285,11 @@ impl<'a> CmdLineRunner<'a> { } fn on_error(&self, output: String, status: ExitStatus) -> Result<()> { + let settings = Settings::try_get()?; match self.pr { Some(pr) => { pr.error(format!("{} failed", self.get_program())); - if !self.settings.verbose && !output.trim().is_empty() { + if !settings.verbose && !output.trim().is_empty() { pr.println(output); } } diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index cd9d83699..c77ea4a78 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use color_eyre::eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::config::Settings; use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -17,11 +16,11 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(settings: &Settings, path: PathBuf, plugins: &[&Arc]) -> Result { + pub fn parse(path: PathBuf, plugins: &[&Arc]) -> Result { let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.clone())); for plugin in plugins { - let version = plugin.parse_legacy_file(&path, settings)?; + let version = plugin.parse_legacy_file(&path)?; for version in version.split_whitespace() { toolset.add_version( ToolVersionRequest::new(plugin.name().to_string(), version), diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 620298d45..e0e998b71 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -93,12 +93,8 @@ impl dyn ConfigFile { .map(|tvr| { if pin { let plugin = config.get_or_create_plugin(&plugin); - let tv = tvr.resolve( - config, - plugin.clone(), - Default::default(), - ts.latest_versions, - )?; + let tv = + tvr.resolve(plugin.clone(), Default::default(), ts.latest_versions)?; Ok(tv.version) } else { Ok(tvr.version()) @@ -144,8 +140,8 @@ impl dyn ConfigFile { } } -fn init(settings: &Settings, path: &Path) -> Box { - let is_trusted = is_trusted(settings, path); +fn init(path: &Path) -> Box { + let is_trusted = is_trusted(path); match detect_config_file_type(path) { Some(ConfigFileType::RtxToml) => Box::new(RtxToml::init(path, is_trusted)), Some(ConfigFileType::ToolVersions) => Box::new(ToolVersions::init(path, is_trusted)), @@ -153,16 +149,16 @@ fn init(settings: &Settings, path: &Path) -> Box { } } -pub fn parse_or_init(settings: &Settings, path: &Path) -> Result> { +pub fn parse_or_init(path: &Path) -> Result> { let cf = match path.exists() { - true => parse(settings, path)?, - false => init(settings, path), + true => parse(path)?, + false => init(path), }; Ok(cf) } -pub fn parse(settings: &Settings, path: &Path) -> Result> { - let is_trusted = is_trusted(settings, path); +pub fn parse(path: &Path) -> Result> { + let is_trusted = is_trusted(path); match detect_config_file_type(path) { Some(ConfigFileType::RtxToml) => Ok(Box::new(RtxToml::from_file(path, is_trusted)?)), Some(ConfigFileType::ToolVersions) => { @@ -173,7 +169,8 @@ pub fn parse(settings: &Settings, path: &Path) -> Result> { } } -pub fn is_trusted(settings: &Settings, path: &Path) -> bool { +pub fn is_trusted(path: &Path) -> bool { + let settings = Settings::get(); if settings .trusted_config_paths .iter() diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 08c859605..e7808fd85 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -746,6 +746,25 @@ impl Debug for RtxToml { } } +impl Clone for RtxToml { + fn clone(&self) -> Self { + Self { + context: self.context.clone(), + path: self.path.clone(), + toolset: self.toolset.clone(), + env_file: self.env_file.clone(), + env: self.env.clone(), + env_remove: self.env_remove.clone(), + path_dirs: self.path_dirs.clone(), + settings: self.settings.clone(), + alias: self.alias.clone(), + doc: self.doc.clone(), + plugins: self.plugins.clone(), + is_trusted: Mutex::new(RefCell::new(*self.is_trusted.lock().unwrap().borrow())), + } + } +} + #[cfg(test)] mod tests { use insta::{assert_debug_snapshot, assert_display_snapshot, assert_snapshot}; diff --git a/src/config/mod.rs b/src/config/mod.rs index a59190ba4..a492c3ae8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -34,7 +34,6 @@ type ToolMap = BTreeMap>; #[derive(Debug, Default)] pub struct Config { - pub settings: Settings, pub global_config: RtxToml, pub config_files: ConfigMap, pub env: BTreeMap, @@ -49,17 +48,29 @@ pub struct Config { repo_urls: HashMap, } +static CONFIG: RwLock>> = RwLock::new(None); + impl Config { + pub fn get() -> Arc { + Self::try_get().unwrap() + } + pub fn try_get() -> Result> { + if let Some(config) = &*CONFIG.read().unwrap() { + return Ok(config.clone()); + } + let config = Arc::new(Self::load()?); + *CONFIG.write().unwrap() = Some(config.clone()); + Ok(config) + } pub fn load() -> Result { let cli_settings = Cli::new().settings(&env::ARGS.read().unwrap()); Settings::add_partial(cli_settings); let global_config = load_rtxrc()?; Settings::add_partial(global_config.settings()?); let config_filenames = load_config_filenames(&BTreeMap::new()); - let settings = Settings::default_builder().load()?; + let settings = Settings::try_get()?; let plugins = load_plugins(&settings)?; let config_files = load_all_config_files( - &settings, &config_filenames, &plugins, &BTreeMap::new(), @@ -68,24 +79,15 @@ impl Config { for cf in config_files.values() { Settings::add_partial(cf.settings()?); } - let mut settings = Settings::default_builder().load()?; - if settings.raw { - settings.verbose = true; - settings.jobs = 1; - } + let settings = Settings::try_get()?; trace!("Settings: {:#?}", settings); let legacy_files = load_legacy_files(&settings, &plugins); let config_filenames = load_config_filenames(&legacy_files); let config_track = track_config_files(&config_filenames); - let config_files = load_all_config_files( - &settings, - &config_filenames, - &plugins, - &legacy_files, - config_files, - ); + let config_files = + load_all_config_files(&config_filenames, &plugins, &legacy_files, config_files); let config_files = config_files?; let watch_files = config_files .values() @@ -112,7 +114,6 @@ impl Config { shorthands: OnceCell::new(), project_root: get_project_root(&config_files), config_files, - settings, global_config, plugins: RwLock::new(plugins), should_exit_early, @@ -124,8 +125,7 @@ impl Config { Ok(config) } pub fn get_shorthands(&self) -> &Shorthands { - self.shorthands - .get_or_init(|| get_shorthands(&self.settings)) + self.shorthands.get_or_init(get_shorthands) } pub fn get_repo_url(&self, plugin_name: &PluginName) -> Option { @@ -151,7 +151,7 @@ impl Config { } } if let Some(plugin) = self.plugins.read().unwrap().get(plugin_name) { - if let Some(alias) = plugin.get_aliases(&self.settings)?.get(v) { + if let Some(alias) = plugin.get_aliases()?.get(v) { return Ok(alias.clone()); } } @@ -187,7 +187,7 @@ impl Config { .list_plugins() .into_par_iter() .map(|plugin| { - let aliases = plugin.get_aliases(&self.settings).unwrap_or_else(|err| { + let aliases = plugin.get_aliases().unwrap_or_else(|err| { warn!("get_aliases: {err}"); BTreeMap::new() }); @@ -220,7 +220,7 @@ impl Config { let config_files = tracker .list_all()? .into_par_iter() - .map(|path| match config_file::parse(&self.settings, &path) { + .map(|path| match config_file::parse(&path) { Ok(cf) => Some((path, cf)), Err(err) => { error!("Error loading config file: {:#}", err); @@ -244,6 +244,7 @@ impl Config { #[cfg(test)] pub fn reset() { Settings::reset(); + CONFIG.write().unwrap().take(); } } @@ -267,7 +268,7 @@ fn load_rtxrc() -> Result { let settings_path = env::RTX_CONFIG_FILE .clone() .unwrap_or(dirs::CONFIG.join("config.toml")); - let is_trusted = config_file::is_trusted(&Settings::default(), &settings_path); + let is_trusted = config_file::is_trusted(&settings_path); match settings_path.exists() { false => { trace!("settings does not exist {:?}", settings_path); @@ -307,7 +308,7 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap Some( filenames .iter() @@ -379,7 +380,6 @@ pub fn global_config_files() -> Vec { } fn load_all_config_files( - settings: &Settings, config_filenames: &[PathBuf], tools: &PluginMap, legacy_filenames: &BTreeMap>, @@ -396,7 +396,7 @@ fn load_all_config_files( Some(cf) => Ok((f, cf)), // need to parse this config file None => { - let cf = parse_config_file(&f, settings, legacy_filenames, tools) + let cf = parse_config_file(&f, legacy_filenames, tools) .wrap_err_with(|| format!("error parsing config file: {}", display_path(&f)))?; Ok((f, cf)) } @@ -410,7 +410,6 @@ fn load_all_config_files( fn parse_config_file( f: &PathBuf, - settings: &Settings, legacy_filenames: &BTreeMap>, tools: &ToolMap, ) -> Result> { @@ -421,10 +420,9 @@ fn parse_config_file( .filter(|(k, _)| plugin.contains(k)) .map(|(_, t)| t) .collect::>(); - LegacyVersionFile::parse(settings, f.into(), &tools) - .map(|f| Box::new(f) as Box) + LegacyVersionFile::parse(f.into(), &tools).map(|f| Box::new(f) as Box) } - None => config_file::parse(settings, f), + None => config_file::parse(f), } } diff --git a/src/config/settings.rs b/src/config/settings.rs index f2999044d..6cb4b483c 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,9 +1,10 @@ use confique::env::parse::{list_by_colon, list_by_comma}; +use eyre::Result; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; -use std::sync::{Once, RwLock}; +use std::sync::{Arc, Once, RwLock}; use confique::{Builder, Config, Partial}; use log::LevelFilter; @@ -57,8 +58,25 @@ impl Default for Settings { } static PARTIALS: RwLock> = RwLock::new(Vec::new()); +static SETTINGS: RwLock>> = RwLock::new(None); impl Settings { + pub fn get() -> Arc { + Self::try_get().unwrap() + } + pub fn try_get() -> Result> { + if let Some(settings) = SETTINGS.read().unwrap().as_ref() { + return Ok(settings.clone()); + } + let mut settings = Self::default_builder().load()?; + if settings.raw { + settings.verbose = true; + settings.jobs = 1; + } + let settings = Arc::new(Self::default_builder().load()?); + *SETTINGS.write().unwrap() = Some(settings.clone()); + Ok(settings) + } pub fn add_partial(partial: SettingsPartial) { static ONCE: Once = Once::new(); ONCE.call_once(|| { @@ -80,6 +98,7 @@ impl Settings { PARTIALS.write().unwrap().push(p); }); PARTIALS.write().unwrap().push(partial); + *SETTINGS.write().unwrap() = None; } pub fn default_builder() -> Builder { let mut b = Self::builder(); @@ -146,6 +165,7 @@ impl Settings { #[cfg(test)] pub fn reset() { PARTIALS.write().unwrap().clear(); + *SETTINGS.write().unwrap() = None; } } diff --git a/src/install_context.rs b/src/install_context.rs index a3c150130..daa1baefa 100644 --- a/src/install_context.rs +++ b/src/install_context.rs @@ -1,9 +1,7 @@ -use crate::config::Config; use crate::toolset::{ToolVersion, Toolset}; use crate::ui::progress_report::ProgressReport; pub struct InstallContext<'a> { - pub config: &'a Config, pub ts: &'a Toolset, pub tv: ToolVersion, pub pr: ProgressReport, diff --git a/src/main.rs b/src/main.rs index 681bf214e..6d766d7af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,13 +85,13 @@ fn run() -> Result<()> { cli::version::print_version_if_requested(&args); migrate::run(); - let config = Config::load()?; - let config = shims::handle_shim(config, &args)?; + let config = Config::try_get()?; + shims::handle_shim(&config, &args)?; if config.should_exit_early { return Ok(()); } let cli = Cli::new_with_external_commands(&config); - cli.run(config, &args) + cli.run(&args) } fn handle_ctrlc() { diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 2d6310e6a..85dc6c125 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -6,7 +6,6 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; -use crate::config::Settings; use crate::github::GithubRelease; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; @@ -50,7 +49,7 @@ impl BunPlugin { fn test_bun(&self, ctx: &InstallContext) -> Result<()> { ctx.pr.set_message("bun -v"); - CmdLineRunner::new(&ctx.config.settings, self.bun_bin(&ctx.tv)) + CmdLineRunner::new(self.bun_bin(&ctx.tv)) .with_pr(&ctx.pr) .arg("-v") .execute() @@ -100,14 +99,14 @@ impl Plugin for BunPlugin { "bun" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".bun-version".into()]) } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index f2298eba7..5368c1902 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -7,7 +7,7 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; -use crate::config::{Config, Settings}; +use crate::config::Config; use crate::github::GithubRelease; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; @@ -51,9 +51,9 @@ impl DenoPlugin { tv.install_path().join("bin/deno") } - fn test_deno(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn test_deno(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("deno -V"); - CmdLineRunner::new(&config.settings, self.deno_bin(tv)) + CmdLineRunner::new(self.deno_bin(tv)) .with_pr(pr) .arg("-V") .execute() @@ -88,8 +88,8 @@ impl DenoPlugin { Ok(()) } - fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - self.test_deno(config, tv, pr) + fn verify(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + self.test_deno(tv, pr) } } @@ -98,14 +98,14 @@ impl Plugin for DenoPlugin { "deno" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".deno-version".into()]) } @@ -117,17 +117,12 @@ impl Plugin for DenoPlugin { let tarball_path = self.download(&ctx.tv, &ctx.pr)?; self.install(&ctx.tv, &ctx.pr, &tarball_path)?; - self.verify(ctx.config, &ctx.tv, &ctx.pr)?; + self.verify(&ctx.tv, &ctx.pr)?; Ok(()) } - fn list_bin_paths( - &self, - _config: &Config, - _ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { + fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { let bin_paths = vec![ tv.install_short_path().join("bin"), tv.install_short_path().join(".deno/bin"), diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 02aa0dddb..500c6d08b 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -2,8 +2,6 @@ use std::path::PathBuf; use color_eyre::eyre::Result; -use crate::config::Settings; - use crate::file::display_path; use crate::install_context::InstallContext; use crate::lock_file::LockFile; @@ -87,7 +85,7 @@ impl Plugin for ErlangPlugin { self.core.name } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 097d352f5..a29a19c7c 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -7,7 +7,7 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; -use crate::config::{Config, Settings}; +use crate::config::Config; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; @@ -57,12 +57,7 @@ impl GoPlugin { tv.install_path().join("packages") } - fn install_default_packages( - &self, - settings: &Settings, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { + fn install_default_packages(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { let body = file::read_to_string(&*env::RTX_GO_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); @@ -82,7 +77,7 @@ impl GoPlugin { if *env::RTX_GO_SET_GOPATH != Some(false) { env.insert("GOPATH", self.gopath(tv)); } - CmdLineRunner::new(settings, self.go_bin(tv)) + CmdLineRunner::new(self.go_bin(tv)) .with_pr(pr) .arg("install") .arg(package) @@ -92,9 +87,9 @@ impl GoPlugin { Ok(()) } - fn test_go(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn test_go(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("go version"); - CmdLineRunner::new(&config.settings, self.go_bin(tv)) + CmdLineRunner::new(self.go_bin(tv)) .with_pr(pr) .arg("version") .execute() @@ -133,9 +128,9 @@ impl GoPlugin { Ok(()) } - fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - self.test_go(config, tv, pr)?; - self.install_default_packages(&config.settings, tv, pr) + fn verify(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + self.test_go(tv, pr)?; + self.install_default_packages(tv, pr) } } @@ -144,25 +139,25 @@ impl Plugin for GoPlugin { "go" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".go-version".into()]) } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let tarball_path = self.download(&ctx.tv, &ctx.pr)?; self.install(&ctx.tv, &ctx.pr, &tarball_path)?; - self.verify(ctx.config, &ctx.tv, &ctx.pr)?; + self.verify(&ctx.tv, &ctx.pr)?; Ok(()) } - fn uninstall_version_impl(&self, _config: &Config, tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, tv: &ToolVersion) -> Result<()> { let gopath = self.gopath(tv); if gopath.exists() { cmd!("chmod", "-R", "u+wx", gopath).run()?; @@ -170,12 +165,7 @@ impl Plugin for GoPlugin { Ok(()) } - fn list_bin_paths( - &self, - _config: &Config, - _ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { + fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { // goroot/bin must always be included, irrespective of RTX_GO_SET_GOROOT let mut paths = vec![self.goroot(tv).join("bin")]; if *env::RTX_GO_SET_GOPATH != Some(false) { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 0d014e7cc..3c983adb6 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -12,7 +12,7 @@ use versions::Versioning; use crate::cache::CacheManager; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; -use crate::config::{Config, Settings}; +use crate::config::Config; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; @@ -114,8 +114,8 @@ impl JavaPlugin { tv.install_path().join("bin/java") } - fn test_java(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - CmdLineRunner::new(&config.settings, self.java_bin(tv)) + fn test_java(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + CmdLineRunner::new(self.java_bin(tv)) .with_pr(pr) .env("JAVA_HOME", tv.install_path()) .arg("-version") @@ -206,9 +206,9 @@ impl JavaPlugin { Ok(()) } - fn verify(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn verify(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("java -version"); - self.test_java(config, tv, pr) + self.test_java(tv, pr) } fn tv_release_type(&self, tv: &ToolVersion) -> String { @@ -269,14 +269,14 @@ impl Plugin for JavaPlugin { "java" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn get_aliases(&self, _settings: &Settings) -> Result> { + fn get_aliases(&self) -> Result> { let aliases = BTreeMap::from([("lts".into(), "21".into())]); Ok(aliases) } @@ -290,7 +290,7 @@ impl Plugin for JavaPlugin { let metadata = self.tv_to_metadata(&ctx.tv)?; let tarball_path = self.download(&ctx.tv, &ctx.pr, metadata)?; self.install(&ctx.tv, &ctx.pr, &tarball_path, metadata)?; - self.verify(ctx.config, &ctx.tv, &ctx.pr)?; + self.verify(&ctx.tv, &ctx.pr)?; Ok(()) } @@ -308,11 +308,11 @@ impl Plugin for JavaPlugin { Ok(map) } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".java-version".into(), ".sdkmanrc".into()]) } - fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + fn parse_legacy_file(&self, path: &Path) -> Result { let contents = file::read_to_string(path)?; if path.file_name() == Some(".sdkmanrc".as_ref()) { let version = contents diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 20c5314ad..057a73e1e 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -8,7 +8,7 @@ use url::Url; use crate::build_time::built_info; use crate::cmd::CmdLineRunner; -use crate::config::{Config, Settings}; +use crate::config::Config; use crate::env::{RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_MIRROR_URL}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; @@ -123,7 +123,7 @@ impl NodePlugin { } fn sh<'a>(&'a self, ctx: &'a InstallContext, opts: &BuildOpts) -> CmdLineRunner { - let mut cmd = CmdLineRunner::new(&ctx.config.settings, "sh"); + let mut cmd = CmdLineRunner::new("sh"); for p in &opts.path { cmd.prepend_path_env(p.clone()); } @@ -179,7 +179,7 @@ impl NodePlugin { } pr.set_message(format!("installing default package: {}", package)); let npm = self.npm_path(tv); - CmdLineRunner::new(&config.settings, npm) + CmdLineRunner::new(npm) .with_pr(pr) .arg("install") .arg("--global") @@ -198,15 +198,10 @@ impl NodePlugin { Ok(()) } - fn enable_default_corepack_shims( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - ) -> Result<()> { + fn enable_default_corepack_shims(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("enabling corepack shims"); let corepack = self.corepack_path(tv); - CmdLineRunner::new(&config.settings, corepack) + CmdLineRunner::new(corepack) .with_pr(pr) .arg("enable") .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) @@ -216,7 +211,7 @@ impl NodePlugin { fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("node -v"); - CmdLineRunner::new(&config.settings, self.node_path(tv)) + CmdLineRunner::new(self.node_path(tv)) .with_pr(pr) .arg("-v") .envs(&config.env) @@ -225,7 +220,7 @@ impl NodePlugin { fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("npm -v"); - CmdLineRunner::new(&config.settings, self.npm_path(tv)) + CmdLineRunner::new(self.npm_path(tv)) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) .arg("-v") @@ -245,14 +240,14 @@ impl Plugin for NodePlugin { "node" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn get_aliases(&self, _settings: &Settings) -> Result> { + fn get_aliases(&self) -> Result> { let aliases = [ ("lts/argon", "4"), ("lts/boron", "6"), @@ -280,11 +275,11 @@ impl Plugin for NodePlugin { Ok(aliases) } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".node-version".into(), ".nvmrc".into()]) } - fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + fn parse_legacy_file(&self, path: &Path) -> Result { let body = file::read_to_string(path)?; // trim "v" prefix let body = body.trim().strip_prefix('v').unwrap_or(&body); @@ -294,6 +289,7 @@ impl Plugin for NodePlugin { } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { + let config = Config::get(); let opts = BuildOpts::new(ctx)?; debug!("node build opts: {:#?}", opts); if *env::RTX_NODE_COMPILE { @@ -301,12 +297,12 @@ impl Plugin for NodePlugin { } else { self.install_precompiled(ctx, &opts)?; } - self.test_node(ctx.config, &ctx.tv, &ctx.pr)?; + self.test_node(&config, &ctx.tv, &ctx.pr)?; self.install_npm_shim(&ctx.tv)?; - self.test_npm(ctx.config, &ctx.tv, &ctx.pr)?; - self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; + self.test_npm(&config, &ctx.tv, &ctx.pr)?; + self.install_default_packages(&config, &ctx.tv, &ctx.pr)?; if *env::RTX_NODE_COREPACK && self.corepack_path(&ctx.tv).exists() { - self.enable_default_corepack_shims(ctx.config, &ctx.tv, &ctx.pr)?; + self.enable_default_corepack_shims(&ctx.tv, &ctx.pr)?; } Ok(()) @@ -339,7 +335,7 @@ impl BuildOpts { Ok(Self { version: v.clone(), - path: ctx.ts.list_paths(ctx.config), + path: ctx.ts.list_paths(), build_dir: env::RTX_TMP_DIR.join(format!("node-v{v}")), configure_cmd: configure_cmd(&install_path), make_cmd: make_cmd(), diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index d0b737469..48303945e 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -124,7 +124,7 @@ impl NodeBuildPlugin { } pr.set_message(format!("installing default package: {}", package)); let npm = self.npm_path(tv); - CmdLineRunner::new(&config.settings, npm) + CmdLineRunner::new(npm) .with_pr(pr) .arg("install") .arg("--global") @@ -145,7 +145,7 @@ impl NodeBuildPlugin { fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("node -v"); - CmdLineRunner::new(&config.settings, self.node_path(tv)) + CmdLineRunner::new(self.node_path(tv)) .with_pr(pr) .arg("-v") .envs(&config.env) @@ -154,7 +154,7 @@ impl NodeBuildPlugin { fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("npm -v"); - CmdLineRunner::new(&config.settings, self.npm_path(tv)) + CmdLineRunner::new(self.npm_path(tv)) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) .arg("-v") @@ -167,7 +167,8 @@ impl NodeBuildPlugin { Ok(updated_at < DAILY) } - fn verbose_install(&self, settings: &Settings) -> bool { + fn verbose_install(&self) -> bool { + let settings = Settings::get(); let verbose_env = *env::RTX_NODE_VERBOSE_INSTALL; verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) } @@ -178,14 +179,14 @@ impl Plugin for NodeBuildPlugin { "node" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn get_aliases(&self, _settings: &Settings) -> Result> { + fn get_aliases(&self) -> Result> { let aliases = [ ("lts/argon", "4"), ("lts/boron", "6"), @@ -213,11 +214,11 @@ impl Plugin for NodeBuildPlugin { Ok(aliases) } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".node-version".into(), ".nvmrc".into()]) } - fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + fn parse_legacy_file(&self, path: &Path) -> Result { let body = file::read_to_string(path)?; // trim "v" prefix let body = body.trim().strip_prefix('v').unwrap_or(&body); @@ -241,12 +242,7 @@ impl Plugin for NodeBuildPlugin { Ok(vec![topic]) } - fn execute_external_command( - &self, - _config: &Config, - command: &str, - args: Vec, - ) -> Result<()> { + fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { match command { "node-build" => { self.install_or_update_node_build()?; @@ -258,12 +254,13 @@ impl Plugin for NodeBuildPlugin { } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { + let config = Config::get(); self.install_node_build()?; ctx.pr.set_message("running node-build"); - let mut cmd = CmdLineRunner::new(&ctx.config.settings, self.node_build_bin()) + let mut cmd = CmdLineRunner::new(self.node_build_bin()) .with_pr(&ctx.pr) .env("NODE_BUILD_MIRROR_URL", RTX_NODE_MIRROR_URL.to_string()) - .envs(&ctx.config.env) + .envs(&config.env) .arg(ctx.tv.version.as_str()); if matches!(&ctx.tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_COMPILE { let mut make_opts = RTX_NODE_MAKE_OPTS.clone().unwrap_or_default(); @@ -285,14 +282,14 @@ impl Plugin for NodeBuildPlugin { } cmd = cmd.arg("--compile"); } - if self.verbose_install(&ctx.config.settings) { + if self.verbose_install() { cmd = cmd.arg("--verbose"); } cmd.arg(&ctx.tv.install_path()).execute()?; - self.test_node(ctx.config, &ctx.tv, &ctx.pr)?; + self.test_node(&config, &ctx.tv, &ctx.pr)?; self.install_npm_shim(&ctx.tv)?; - self.test_npm(ctx.config, &ctx.tv, &ctx.pr)?; - self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; + self.test_npm(&config, &ctx.tv, &ctx.pr)?; + self.install_default_packages(&config, &ctx.tv, &ctx.pr)?; Ok(()) } } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index e210a224d..655a6f6f5 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -96,7 +96,7 @@ impl PythonPlugin { return Ok(()); } pr.set_message("installing default packages"); - CmdLineRunner::new(&config.settings, tv.install_path().join("bin/python")) + CmdLineRunner::new(tv.install_path().join("bin/python")) .with_pr(pr) .arg("-m") .arg("pip") @@ -124,7 +124,7 @@ impl PythonPlugin { } if !virtualenv.exists() { info!("setting up virtualenv at: {}", virtualenv.display()); - let mut cmd = CmdLineRunner::new(&config.settings, self.python_path(tv)) + let mut cmd = CmdLineRunner::new(self.python_path(tv)) .arg("-m") .arg("venv") .arg(&virtualenv) @@ -157,7 +157,7 @@ impl PythonPlugin { fn test_python(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("python --version"); - CmdLineRunner::new(&config.settings, self.python_path(tv)) + CmdLineRunner::new(self.python_path(tv)) .arg("--version") .envs(&config.env) .execute() @@ -169,29 +169,31 @@ impl Plugin for PythonPlugin { "python" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".python-version".to_string()]) } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { + let config = Config::get(); + let settings = Settings::try_get()?; self.install_or_update_python_build()?; if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); } ctx.pr.set_message("Running python-build"); - let mut cmd = CmdLineRunner::new(&ctx.config.settings, self.python_build_bin()) + let mut cmd = CmdLineRunner::new(self.python_build_bin()) .with_pr(&ctx.pr) .arg(ctx.tv.version.as_str()) .arg(&ctx.tv.install_path()) - .envs(&ctx.config.env); - if ctx.config.settings.verbose { + .envs(&config.env); + if settings.verbose { cmd = cmd.arg("--verbose"); } if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { @@ -214,11 +216,11 @@ impl Plugin for PythonPlugin { } } cmd.execute()?; - self.test_python(ctx.config, &ctx.tv, &ctx.pr)?; - if let Err(e) = self.get_virtualenv(ctx.config, &ctx.tv, Some(&ctx.pr)) { + self.test_python(&config, &ctx.tv, &ctx.pr)?; + if let Err(e) = self.get_virtualenv(&config, &ctx.tv, Some(&ctx.pr)) { warn!("failed to get virtualenv: {e}"); } - self.install_default_packages(ctx.config, &ctx.tv, &ctx.pr)?; + self.install_default_packages(&config, &ctx.tv, &ctx.pr)?; Ok(()) } diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index d3404395d..916877180 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -182,7 +182,7 @@ impl RubyPlugin { } pr.set_message(format!("installing default gem: {}", package)); let gem = self.gem_path(tv); - let mut cmd = CmdLineRunner::new(&config.settings, gem) + let mut cmd = CmdLineRunner::new(gem) .with_pr(pr) .arg("install") .envs(&config.env); @@ -199,7 +199,7 @@ impl RubyPlugin { fn test_ruby(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("ruby -v"); - CmdLineRunner::new(&config.settings, self.ruby_path(tv)) + CmdLineRunner::new(self.ruby_path(tv)) .with_pr(pr) .arg("-v") .envs(&config.env) @@ -208,7 +208,7 @@ impl RubyPlugin { fn test_gem(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { pr.set_message("gem -v"); - CmdLineRunner::new(&config.settings, self.gem_path(tv)) + CmdLineRunner::new(self.gem_path(tv)) .with_pr(pr) .arg("-v") .envs(&config.env) @@ -249,22 +249,17 @@ impl RubyPlugin { pr: &'a ProgressReport, ) -> Result { let cmd = if *env::RTX_RUBY_INSTALL { - CmdLineRunner::new(&config.settings, self.ruby_install_bin()) - .args(self.install_args_ruby_install(tv)?) + CmdLineRunner::new(self.ruby_install_bin()).args(self.install_args_ruby_install(tv)?) } else { - CmdLineRunner::new(&config.settings, self.ruby_build_bin()) - .args(self.install_args_ruby_build(&config.settings, tv)?) + CmdLineRunner::new(self.ruby_build_bin()) + .args(self.install_args_ruby_build(tv)?) .stdin_string(self.fetch_patches()?) }; Ok(cmd.with_pr(pr).envs(&config.env)) } - fn install_args_ruby_build( - &self, - settings: &Settings, - tv: &ToolVersion, - ) -> Result> { + fn install_args_ruby_build(&self, tv: &ToolVersion) -> Result> { let mut args = env::RTX_RUBY_BUILD_OPTS.clone()?; - if self.verbose_install(settings) { + if self.verbose_install() { args.push("--verbose".into()); } if env::RTX_RUBY_APPLY_PATCHES.is_some() { @@ -292,7 +287,8 @@ impl RubyPlugin { Ok(args) } - fn verbose_install(&self, settings: &Settings) -> bool { + fn verbose_install(&self) -> bool { + let settings = Settings::get(); let verbose_env = *env::RTX_RUBY_VERBOSE_INSTALL; verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) } @@ -325,18 +321,18 @@ impl Plugin for RubyPlugin { "ruby" } - fn list_remote_versions(&self, _settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .cloned() } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![".ruby-version".into(), "Gemfile".into()]) } - fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + fn parse_legacy_file(&self, path: &Path) -> Result { let v = match path.file_name() { Some(name) if name == "Gemfile" => parse_gemfile(&file::read_to_string(path)?), _ => { @@ -359,12 +355,13 @@ impl Plugin for RubyPlugin { )); ctx.pr.set_message("running ruby-build"); - self.install_cmd(ctx.config, &ctx.tv, &ctx.pr)?.execute()?; + let config = Config::get(); + self.install_cmd(&config, &ctx.tv, &ctx.pr)?.execute()?; - self.test_ruby(ctx.config, &ctx.tv, &ctx.pr)?; + self.test_ruby(&config, &ctx.tv, &ctx.pr)?; self.install_rubygems_hook(&ctx.tv)?; - self.test_gem(ctx.config, &ctx.tv, &ctx.pr)?; - self.install_default_gems(ctx.config, &ctx.tv, &ctx.pr)?; + self.test_gem(&config, &ctx.tv, &ctx.pr)?; + self.install_default_gems(&config, &ctx.tv, &ctx.pr)?; Ok(()) } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 71fcf3326..bf16c670b 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -100,8 +100,9 @@ impl ExternalPlugin { .ok_or_else(|| eyre!("No repository found for plugin {}", self.name)) } - fn install(&self, config: &Config, pr: &ProgressReport) -> Result<()> { - let repository = self.get_repo_url(config)?; + fn install(&self, pr: &ProgressReport) -> Result<()> { + let config = Config::get(); + let repository = self.get_repo_url(&config)?; let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); debug!("install {} {:?}", self.name, repository); @@ -153,7 +154,8 @@ impl ExternalPlugin { } } - fn fetch_remote_versions(&self, settings: &Settings) -> Result> { + fn fetch_remote_versions(&self) -> Result> { + let settings = Settings::try_get()?; match self.fetch_versions() { Ok(Some(versions)) => return Ok(versions), Err(err) => warn!( @@ -163,7 +165,7 @@ impl ExternalPlugin { ), _ => {} }; - let cmd = self.script_man.cmd(settings, &Script::ListAll); + let cmd = self.script_man.cmd(&Script::ListAll); let result = run_with_timeout( move || { let result = cmd.stdout_capture().stderr_capture().unchecked().run()?; @@ -196,19 +198,17 @@ impl ExternalPlugin { Ok(stdout.split_whitespace().map(|v| v.into()).collect()) } - fn fetch_legacy_filenames(&self, settings: &Settings) -> Result> { - let stdout = self - .script_man - .read(settings, &Script::ListLegacyFilenames)?; + fn fetch_legacy_filenames(&self) -> Result> { + let stdout = self.script_man.read(&Script::ListLegacyFilenames)?; Ok(self.parse_legacy_filenames(&stdout)) } fn parse_legacy_filenames(&self, data: &str) -> Vec { data.split_whitespace().map(|v| v.into()).collect() } - fn fetch_latest_stable(&self, settings: &Settings) -> Result> { + fn fetch_latest_stable(&self) -> Result> { let latest_stable = self .script_man - .read(settings, &Script::LatestStable)? + .read(&Script::LatestStable)? .trim() .to_string(); Ok(if latest_stable.is_empty() { @@ -227,8 +227,8 @@ impl ExternalPlugin { fn has_latest_stable_script(&self) -> bool { self.script_man.script_exists(&Script::LatestStable) } - fn fetch_aliases(&self, settings: &Settings) -> Result> { - let stdout = self.script_man.read(settings, &Script::ListAliases)?; + fn fetch_aliases(&self) -> Result> { + let stdout = self.script_man.read(&Script::ListAliases)?; Ok(self.parse_aliases(&stdout)) } fn parse_aliases(&self, data: &str) -> Vec<(String, String)> { @@ -270,17 +270,12 @@ impl ExternalPlugin { Ok(()) } - fn fetch_bin_paths( - &self, - config: &Config, - _ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { + fn fetch_bin_paths(&self, tv: &ToolVersion) -> Result> { let list_bin_paths = self.plugin_path.join("bin/list-bin-paths"); let bin_paths = if matches!(tv.request, ToolVersionRequest::System(_)) { Vec::new() } else if list_bin_paths.exists() { - let sm = self.script_man_for_tv(config, tv); + let sm = self.script_man_for_tv(tv); // TODO: find a way to enable this without deadlocking // for (t, tv) in ts.list_current_installed_versions(config) { // if t.name == self.name { @@ -290,7 +285,7 @@ impl ExternalPlugin { // sm.prepend_path(p); // } // } - let output = sm.cmd(&config.settings, &Script::ListBinPaths).read()?; + let output = sm.cmd(&Script::ListBinPaths).read()?; output.split_whitespace().map(|f| f.to_string()).collect() } else { vec!["bin".into()] @@ -301,14 +296,9 @@ impl ExternalPlugin { .collect(); Ok(bin_paths) } - fn fetch_exec_env( - &self, - config: &Config, - ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { - let mut sm = self.script_man_for_tv(config, tv); - for p in ts.list_paths(config) { + fn fetch_exec_env(&self, ts: &Toolset, tv: &ToolVersion) -> Result> { + let mut sm = self.script_man_for_tv(tv); + for p in ts.list_paths() { sm.prepend_path(p); } let script = sm.get_script_path(&ExecEnv); @@ -325,7 +315,8 @@ impl ExternalPlugin { Ok(env) } - fn script_man_for_tv(&self, config: &Config, tv: &ToolVersion) -> ScriptManager { + fn script_man_for_tv(&self, tv: &ToolVersion) -> ScriptManager { + let config = Config::get(); let mut sm = self.script_man.clone(); for (key, value) in &tv.opts { let k = format!("RTX_TOOL_OPTS__{}", key.to_uppercase()); @@ -406,9 +397,9 @@ impl Plugin for ExternalPlugin { fn get_type(&self) -> PluginType { PluginType::External } - fn list_remote_versions(&self, settings: &Settings) -> Result> { + fn list_remote_versions(&self) -> Result> { self.remote_version_cache - .get_or_try_init(|| self.fetch_remote_versions(settings)) + .get_or_try_init(|| self.fetch_remote_versions()) .wrap_err_with(|| { eyre!( "Failed listing remote versions for plugin {}", @@ -418,12 +409,12 @@ impl Plugin for ExternalPlugin { .cloned() } - fn latest_stable_version(&self, settings: &Settings) -> Result> { + fn latest_stable_version(&self) -> Result> { if !self.has_latest_stable_script() { - return self.latest_version(settings, Some("latest".into())); + return self.latest_version(Some("latest".into())); } self.latest_stable_cache - .get_or_try_init(|| self.fetch_latest_stable(settings)) + .get_or_try_init(|| self.fetch_latest_stable()) .wrap_err_with(|| { eyre!( "Failed fetching latest stable version for plugin {}", @@ -452,18 +443,15 @@ impl Plugin for ExternalPlugin { self.plugin_path.exists() } - fn ensure_installed( - &self, - config: &Config, - mpr: Option<&MultiProgressReport>, - force: bool, - ) -> Result<()> { + fn ensure_installed(&self, mpr: Option<&MultiProgressReport>, force: bool) -> Result<()> { + let config = Config::get(); + let settings = Settings::try_get()?; if !force { if self.is_installed() { return Ok(()); } - if !config.settings.yes && self.repo_url.is_none() { - let url = self.get_repo_url(config)?; + if !settings.yes && self.repo_url.is_none() { + let url = self.get_repo_url(&config)?; eprintln!( "⚠️ {name} is a community-developed plugin: {url}", name = style(&self.name).cyan(), @@ -474,12 +462,12 @@ impl Plugin for ExternalPlugin { } } } - let _mpr = MultiProgressReport::new(&config.settings); + let _mpr = MultiProgressReport::new(); let mpr = mpr.unwrap_or(&_mpr); let mut pr = mpr.add(); self.decorate_progress_bar(&mut pr, None); let _lock = self.get_lock(&self.plugin_path, force)?; - self.install(config, &pr) + self.install(&pr) } fn update(&self, gitref: Option) -> Result<()> { @@ -529,7 +517,7 @@ impl Plugin for ExternalPlugin { Ok(()) } - fn get_aliases(&self, settings: &Settings) -> Result> { + fn get_aliases(&self) -> Result> { if let Some(data) = &self.toml.list_aliases.data { return Ok(self.parse_aliases(data).into_iter().collect()); } @@ -538,7 +526,7 @@ impl Plugin for ExternalPlugin { } let aliases = self .alias_cache - .get_or_try_init(|| self.fetch_aliases(settings)) + .get_or_try_init(|| self.fetch_aliases()) .wrap_err_with(|| { eyre!( "Failed fetching aliases for plugin {}", @@ -551,7 +539,7 @@ impl Plugin for ExternalPlugin { Ok(aliases) } - fn legacy_filenames(&self, settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { if let Some(data) = &self.toml.list_legacy_filenames.data { return Ok(self.parse_legacy_filenames(data)); } @@ -559,7 +547,7 @@ impl Plugin for ExternalPlugin { return Ok(vec![]); } self.legacy_filename_cache - .get_or_try_init(|| self.fetch_legacy_filenames(settings)) + .get_or_try_init(|| self.fetch_legacy_filenames()) .wrap_err_with(|| { eyre!( "Failed fetching legacy filenames for plugin {}", @@ -569,14 +557,14 @@ impl Plugin for ExternalPlugin { .cloned() } - fn parse_legacy_file(&self, legacy_file: &Path, settings: &Settings) -> Result { + fn parse_legacy_file(&self, legacy_file: &Path) -> Result { if let Some(cached) = self.fetch_cached_legacy_file(legacy_file)? { return Ok(cached); } trace!("parsing legacy file: {}", legacy_file.to_string_lossy()); let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); let legacy_version = match self.script_man.script_exists(&script) { - true => self.script_man.read(settings, &script)?, + true => self.script_man.read(&script)?, false => fs::read_to_string(legacy_file)?, } .trim() @@ -626,12 +614,7 @@ impl Plugin for ExternalPlugin { Ok(vec![topic]) } - fn execute_external_command( - &self, - config: &Config, - command: &str, - args: Vec, - ) -> Result<()> { + fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { if !self.is_installed() { return Err(PluginNotInstalled(self.name.clone()).into()); } @@ -641,22 +624,18 @@ impl Plugin for ExternalPlugin { .join(format!("command-{command}.bash")), args, ); - let result = self - .script_man - .cmd(&config.settings, &script) - .unchecked() - .run()?; + let result = self.script_man.cmd(&script).unchecked().run()?; exit(result.status.code().unwrap_or(-1)); } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { - let mut sm = self.script_man_for_tv(ctx.config, &ctx.tv); + let mut sm = self.script_man_for_tv(&ctx.tv); - for p in ctx.ts.list_paths(ctx.config) { + for p in ctx.ts.list_paths() { sm.prepend_path(p); } - let run_script = |script| sm.run_by_line(&ctx.config.settings, script, &ctx.pr); + let run_script = |script| sm.run_by_line(script, &ctx.pr); if sm.script_exists(&Download) { ctx.pr.set_message("downloading"); @@ -668,22 +647,16 @@ impl Plugin for ExternalPlugin { Ok(()) } - fn uninstall_version_impl(&self, config: &Config, tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, tv: &ToolVersion) -> Result<()> { if self.plugin_path.join("bin/uninstall").exists() { - self.script_man_for_tv(config, tv) - .run(&config.settings, &Script::Uninstall)?; + self.script_man_for_tv(tv).run(&Script::Uninstall)?; } Ok(()) } - fn list_bin_paths( - &self, - config: &Config, - ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { + fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { self.cache - .list_bin_paths(config, self, tv, || self.fetch_bin_paths(config, ts, tv)) + .list_bin_paths(self, tv, || self.fetch_bin_paths(tv)) } fn exec_env( @@ -701,7 +674,7 @@ impl Plugin for ExternalPlugin { return Ok(EMPTY_HASH_MAP.clone()); } self.cache - .exec_env(config, self, tv, || self.fetch_exec_env(config, ts, tv)) + .exec_env(config, self, tv, || self.fetch_exec_env(ts, tv)) } } diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 6652c82a0..39a3e7fc7 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -22,7 +22,6 @@ pub struct ExternalPluginCache { impl ExternalPluginCache { pub fn list_bin_paths( &self, - config: &Config, plugin: &ExternalPlugin, tv: &ToolVersion, fetch: F, @@ -34,7 +33,8 @@ impl ExternalPluginCache { let cm = w.entry(tv.request.clone()).or_insert_with(|| { let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key { Some(key) => { - let key = render_cache_key(config, tv, key); + let config = Config::get(); + let key = render_cache_key(&config, tv, key); let filename = format!("{}.msgpack.z", key); tv.cache_path().join("list_bin_paths").join(filename) } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index a86c31f8d..02e11df4c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -53,9 +53,9 @@ pub trait Plugin: Debug + Send + Sync { fn downloads_path(&self) -> PathBuf { dirs::DOWNLOADS.join(self.name()) } - fn list_remote_versions(&self, settings: &Settings) -> Result>; - fn latest_stable_version(&self, settings: &Settings) -> Result> { - self.latest_version(settings, Some("latest".into())) + fn list_remote_versions(&self) -> Result>; + fn latest_stable_version(&self) -> Result> { + self.latest_version(Some("latest".into())) } fn list_installed_versions(&self) -> Result> { Ok(match self.installs_path().exists() { @@ -79,8 +79,8 @@ pub trait Plugin: Debug + Send + Sync { } } } - fn is_version_outdated(&self, config: &Config, tv: &ToolVersion, p: Arc) -> bool { - let latest = match tv.latest_version(config, p) { + fn is_version_outdated(&self, tv: &ToolVersion, p: Arc) -> bool { + let latest = match tv.latest_version(p) { Ok(latest) => latest, Err(e) => { debug!("Error getting latest version for {}: {:#}", self.name(), e); @@ -104,17 +104,17 @@ pub trait Plugin: Debug + Send + Sync { let versions = self.list_installed_versions()?; fuzzy_match_filter(versions, query) } - fn list_versions_matching(&self, settings: &Settings, query: &str) -> Result> { - let versions = self.list_remote_versions(settings)?; + fn list_versions_matching(&self, query: &str) -> Result> { + let versions = self.list_remote_versions()?; fuzzy_match_filter(versions, query) } - fn latest_version(&self, settings: &Settings, query: Option) -> Result> { + fn latest_version(&self, query: Option) -> Result> { match query { Some(query) => { - let matches = self.list_versions_matching(settings, &query)?; + let matches = self.list_versions_matching(&query)?; Ok(find_match_in_list(&matches, &query)) } - None => self.latest_stable_version(settings), + None => self.latest_stable_version(), } } fn latest_installed_version(&self, query: Option) -> Result> { @@ -152,12 +152,7 @@ pub trait Plugin: Debug + Send + Sync { fn is_installed(&self) -> bool { true } - fn ensure_installed( - &self, - _config: &Config, - _mpr: Option<&MultiProgressReport>, - _force: bool, - ) -> Result<()> { + fn ensure_installed(&self, _mpr: Option<&MultiProgressReport>, _force: bool) -> Result<()> { Ok(()) } fn update(&self, _git_ref: Option) -> Result<()> { @@ -172,31 +167,28 @@ pub trait Plugin: Debug + Send + Sync { rmdir(&self.downloads_path(), pr)?; Ok(()) } - fn get_aliases(&self, _settings: &Settings) -> Result> { + fn get_aliases(&self) -> Result> { Ok(BTreeMap::new()) } - fn legacy_filenames(&self, _settings: &Settings) -> Result> { + fn legacy_filenames(&self) -> Result> { Ok(vec![]) } - fn parse_legacy_file(&self, path: &Path, _settings: &Settings) -> Result { + fn parse_legacy_file(&self, path: &Path) -> Result { let contents = file::read_to_string(path)?; Ok(contents.trim().to_string()) } fn external_commands(&self) -> Result> { Ok(vec![]) } - fn execute_external_command( - &self, - _config: &Config, - _command: &str, - _args: Vec, - ) -> Result<()> { + fn execute_external_command(&self, _command: &str, _args: Vec) -> Result<()> { unimplemented!() } fn install_version(&self, mut ctx: InstallContext) -> Result<()> { + let config = Config::get(); + let settings = Settings::try_get()?; if self.is_version_installed(&ctx.tv) { if ctx.force { - self.uninstall_version(ctx.config, &ctx.tv, &ctx.pr, false)?; + self.uninstall_version(&ctx.tv, &ctx.pr, false)?; } else { return Ok(()); } @@ -206,13 +198,13 @@ pub trait Plugin: Debug + Send + Sync { self.create_install_dirs(&ctx.tv)?; if let Err(e) = self.install_version_impl(&ctx) { - self.cleanup_install_dirs_on_error(&ctx.config.settings, &ctx.tv); + self.cleanup_install_dirs_on_error(&settings, &ctx.tv); return Err(e); } - self.cleanup_install_dirs(&ctx.config.settings, &ctx.tv); + self.cleanup_install_dirs(&settings, &ctx.tv); // attempt to touch all the .tool-version files to trigger updates in hook-env let mut touch_dirs = vec![dirs::DATA.to_path_buf()]; - touch_dirs.extend(ctx.config.config_files.keys().cloned()); + touch_dirs.extend(config.config_files.keys().cloned()); for path in touch_dirs { let err = file::touch_dir(&path); if let Err(err) = err { @@ -228,17 +220,11 @@ pub trait Plugin: Debug + Send + Sync { Ok(()) } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()>; - fn uninstall_version( - &self, - config: &Config, - tv: &ToolVersion, - pr: &ProgressReport, - dryrun: bool, - ) -> Result<()> { + fn uninstall_version(&self, tv: &ToolVersion, pr: &ProgressReport, dryrun: bool) -> Result<()> { pr.set_message(format!("uninstall {tv}")); if !dryrun { - self.uninstall_version_impl(config, tv)?; + self.uninstall_version_impl(tv)?; } let rmdir = |dir: &Path| { if !dir.exists() { @@ -255,15 +241,10 @@ pub trait Plugin: Debug + Send + Sync { rmdir(&tv.cache_path())?; Ok(()) } - fn uninstall_version_impl(&self, _config: &Config, _tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, _tv: &ToolVersion) -> Result<()> { Ok(()) } - fn list_bin_paths( - &self, - _config: &Config, - _ts: &Toolset, - tv: &ToolVersion, - ) -> Result> { + fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { match tv.request { ToolVersionRequest::System(_) => Ok(vec![]), _ => Ok(vec![tv.install_short_path().join("bin")]), @@ -277,14 +258,8 @@ pub trait Plugin: Debug + Send + Sync { ) -> Result> { Ok(HashMap::new()) } - fn which( - &self, - config: &Config, - ts: &Toolset, - tv: &ToolVersion, - bin_name: &str, - ) -> Result> { - let bin_paths = self.list_bin_paths(config, ts, tv)?; + fn which(&self, tv: &ToolVersion, bin_name: &str) -> Result> { + let bin_paths = self.list_bin_paths(tv)?; for bin_path in bin_paths { let bin_path = bin_path.join(bin_name); if bin_path.exists() { @@ -438,29 +413,26 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::assert_cli; - use crate::config::Settings; use super::*; #[test] fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); - let settings = Settings::default(); let plugin = ExternalPlugin::newa(PluginName::from("tiny")); let version = plugin - .latest_version(&settings, Some("1.0.0".into())) + .latest_version(Some("1.0.0".into())) .unwrap() .unwrap(); assert_str_eq!(version, "1.0.0"); - let version = plugin.latest_version(&settings, None).unwrap().unwrap(); + let version = plugin.latest_version(None).unwrap().unwrap(); assert_str_eq!(version, "3.1.0"); } #[test] fn test_latest_stable() { - let settings = Settings::default(); let plugin = ExternalPlugin::new(PluginName::from("dummy")); - let version = plugin.latest_version(&settings, None).unwrap().unwrap(); + let version = plugin.latest_version(None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); } } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 1585f79dd..e156a2fe0 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -133,7 +133,7 @@ impl ScriptManager { self.get_script_path(script).is_file() } - pub fn cmd(&self, settings: &Settings, script: &Script) -> Expression { + pub fn cmd(&self, script: &Script) -> Expression { let args = match script { Script::ParseLegacyFile(filename) => vec![filename.clone()], Script::RunExternalCommand(_, args) => args.clone(), @@ -144,6 +144,7 @@ impl ScriptManager { // return Err(PluginNotInstalled(self.plugin_name.clone()).into()); // } let mut cmd = cmd(script_path, args).full_env(&self.env); + let settings = &Settings::get(); if !settings.raw { // ignore stdin, otherwise a prompt may show up where the user won't see it cmd = cmd.stdin_null(); @@ -151,8 +152,8 @@ impl ScriptManager { cmd } - pub fn run(&self, settings: &Settings, script: &Script) -> Result<()> { - let cmd = self.cmd(settings, script); + pub fn run(&self, script: &Script) -> Result<()> { + let cmd = self.cmd(script); let Output { status, .. } = cmd.unchecked().run()?; match status.success() { @@ -163,8 +164,9 @@ impl ScriptManager { } } - pub fn read(&self, settings: &Settings, script: &Script) -> Result { - let mut cmd = self.cmd(settings, script); + pub fn read(&self, script: &Script) -> Result { + let mut cmd = self.cmd(script); + let settings = &Settings::try_get()?; if !settings.verbose { cmd = cmd.stderr_null(); } @@ -172,13 +174,8 @@ impl ScriptManager { .wrap_err_with(|| ScriptFailed(display_path(&self.get_script_path(script)), None)) } - pub fn run_by_line( - &self, - settings: &Settings, - script: &Script, - pr: &ProgressReport, - ) -> Result<()> { - let cmd = CmdLineRunner::new(settings, self.get_script_path(script)) + pub fn run_by_line(&self, script: &Script, pr: &ProgressReport) -> Result<()> { + let cmd = CmdLineRunner::new(self.get_script_path(script)) .with_pr(pr) .env_clear() .envs(&self.env); diff --git a/src/shims.rs b/src/shims.rs index f66d58816..ab98a55fe 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(config: Config, args: &[String]) -> Result { +pub fn handle_shim(config: &Config, args: &[String]) -> Result<()> { let (_, bin_name) = args[0].rsplit_once('/').unwrap_or(("", &args[0])); if bin_name == "rtx" { - return Ok(config); + return Ok(()); } let mut args: Vec = args.iter().map(OsString::from).collect(); - args[0] = which_shim(&config, bin_name)?.into(); + args[0] = which_shim(config, bin_name)?.into(); let exec = Exec { tool: vec![], c: None, @@ -46,8 +46,8 @@ 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)?; - if let Some((p, tv)) = ts.which(config, bin_name) { - if let Some(bin) = p.which(config, &ts, &tv, bin_name)? { + if let Some((p, tv)) = ts.which(bin_name) { + if let Some(bin) = p.which(&tv, bin_name)? { return Ok(bin); } } @@ -93,12 +93,11 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let shims: HashSet = ts .list_installed_versions(config)? .into_par_iter() - .flat_map(|(t, tv)| match list_tool_bins(config, ts, t.clone(), &tv) { - Ok(paths) => paths, - Err(e) => { + .flat_map(|(t, tv)| { + list_tool_bins(t.clone(), &tv).unwrap_or_else(|e| { warn!("Error listing bin paths for {}: {:#}", tv, e); Vec::new() - } + }) }) .collect(); @@ -139,13 +138,8 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { } // lists all the paths to bins in a tv that shims will be needed for -fn list_tool_bins( - config: &Config, - ts: &Toolset, - t: Arc, - tv: &ToolVersion, -) -> Result> { - Ok(t.list_bin_paths(config, ts, tv)? +fn list_tool_bins(t: Arc, tv: &ToolVersion) -> Result> { + Ok(t.list_bin_paths(tv)? .into_iter() .par_bridge() .filter(|path| path.exists()) diff --git a/src/shorthands.rs b/src/shorthands.rs index b792bfca0..77c672251 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -10,8 +10,9 @@ use crate::{dirs, file}; pub type Shorthands = HashMap; -pub fn get_shorthands(settings: &Settings) -> Shorthands { +pub fn get_shorthands() -> Shorthands { let mut shorthands = HashMap::new(); + let settings = Settings::get(); if !settings.disable_default_shorthands { shorthands.extend( DEFAULT_SHORTHANDS @@ -50,17 +51,19 @@ fn parse_shorthands_file(mut f: PathBuf) -> Result { #[cfg(test)] mod tests { + use crate::config::SettingsPartial; + use confique::Partial; use pretty_assertions::assert_str_eq; use super::*; #[test] fn test_get_shorthands() { - let settings = Settings { - shorthands_file: Some("../fixtures/shorthands.toml".into()), - ..Settings::default() - }; - let shorthands = get_shorthands(&settings); + Settings::reset(); + let mut partial = SettingsPartial::empty(); + partial.shorthands_file = Some("../fixtures/shorthands.toml".into()); + Settings::add_partial(partial); + let shorthands = get_shorthands(); assert_str_eq!( shorthands["elixir"], "https://github.com/asdf-vm/asdf-elixir.git" @@ -71,11 +74,11 @@ mod tests { #[test] fn test_get_shorthands_missing_file() { - let settings = Settings { - shorthands_file: Some("test/fixtures/missing.toml".into()), - ..Settings::default() - }; - let shorthands = get_shorthands(&settings); + Settings::reset(); + let mut partial = SettingsPartial::empty(); + partial.shorthands_file = Some("test/fixtures/missing.toml".into()); + Settings::add_partial(partial); + let shorthands = get_shorthands(); assert!(!shorthands.is_empty()); } } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index d42f33bbb..b30094005 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -4,7 +4,7 @@ use color_eyre::eyre::Result; use itertools::Itertools; use crate::cli::args::tool::ToolArg; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::env; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -42,9 +42,10 @@ impl ToolsetBuilder { } pub fn build(self, config: &Config) -> Result { + let settings = Settings::try_get()?; let mut toolset = Toolset { latest_versions: self.latest_versions, - disable_tools: config.settings.disable_tools.clone(), + disable_tools: settings.disable_tools.clone(), ..Default::default() }; self.load_config_files(config, &mut toolset); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index ea7fddccd..c90c5566a 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -15,7 +15,7 @@ pub use tool_version::ToolVersion; pub use tool_version_list::ToolVersionList; pub use tool_version_request::ToolVersionRequest; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::env; use crate::install_context::InstallContext; use crate::path_env::PathEnv; @@ -91,7 +91,7 @@ impl Toolset { .for_each(|(_, v)| v.resolve(config, self.latest_versions)); } pub fn install_arg_versions(&mut self, config: &Config, opts: &InstallOptions) -> Result<()> { - let mpr = MultiProgressReport::new(&config.settings); + let mpr = MultiProgressReport::new(); let versions = self .list_missing_versions(config) .into_iter() @@ -120,6 +120,7 @@ impl Toolset { if versions.is_empty() { return Ok(()); } + let settings = Settings::try_get()?; self.latest_versions = true; let queue: Vec<_> = versions .into_iter() @@ -129,14 +130,14 @@ impl Toolset { .collect(); for (t, _) in &queue { if !t.is_installed() { - t.ensure_installed(config, Some(mpr), false)?; + t.ensure_installed(Some(mpr), false)?; } } let queue = Arc::new(Mutex::new(queue)); - let raw = opts.raw || config.settings.raw; + let raw = opts.raw || settings.raw; let jobs = match raw { true => 1, - false => opts.jobs.unwrap_or(config.settings.jobs), + false => opts.jobs.unwrap_or(settings.jobs), }; thread::scope(|s| { (0..jobs) @@ -148,14 +149,8 @@ impl Toolset { while let Some((t, versions)) = next_job() { for tv in versions { let ctx = InstallContext { - config, ts, - tv: tv.request.resolve( - config, - t.clone(), - tv.opts.clone(), - true, - )?, + tv: tv.request.resolve(t.clone(), tv.opts.clone(), true)?, pr: mpr.add(), raw, force: opts.force, @@ -195,7 +190,7 @@ impl Toolset { config: &Config, ) -> Result, ToolVersion)>> { let current_versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = self - .list_current_versions(config) + .list_current_versions() .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p.clone(), tv))) .collect(); @@ -211,7 +206,7 @@ impl Toolset { Some((p, tv)) => (p.clone(), tv.clone()), None => { let tv = ToolVersionRequest::new(p.name().into(), &v) - .resolve(config, p.clone(), Default::default(), false) + .resolve(p.clone(), Default::default(), false) .unwrap(); (p.clone(), tv) } @@ -226,42 +221,34 @@ impl Toolset { Ok(versions) } - pub fn list_versions_by_plugin( - &self, - config: &Config, - ) -> Vec<(Arc, &Vec)> { + pub fn list_versions_by_plugin(&self) -> Vec<(Arc, &Vec)> { + let config = Config::get(); self.versions .iter() .map(|(p, v)| (config.get_or_create_plugin(p), &v.versions)) .collect() } - pub fn list_current_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion)> { - self.list_versions_by_plugin(config) + pub fn list_current_versions(&self) -> Vec<(Arc, ToolVersion)> { + self.list_versions_by_plugin() .iter() .flat_map(|(p, v)| v.iter().map(|v| (p.clone(), v.clone()))) .collect() } - pub fn list_current_installed_versions( - &self, - config: &Config, - ) -> Vec<(Arc, ToolVersion)> { - self.list_current_versions(config) + pub fn list_current_installed_versions(&self) -> Vec<(Arc, ToolVersion)> { + self.list_current_versions() .into_iter() .filter(|(p, v)| p.is_version_installed(v)) .collect() } - pub fn list_outdated_versions( - &self, - config: &Config, - ) -> Vec<(Arc, ToolVersion, String)> { - self.list_current_versions(config) + pub fn list_outdated_versions(&self) -> Vec<(Arc, ToolVersion, String)> { + self.list_current_versions() .into_iter() .filter_map(|(t, tv)| { if t.symlink_path(&tv).is_some() { // do not consider symlinked versions to be outdated return None; } - let latest = match tv.latest_version(config, t.clone()) { + let latest = match tv.latest_version(t.clone()) { Ok(latest) => latest, Err(e) => { warn!("Error getting latest version for {t}: {e:#}"); @@ -281,7 +268,7 @@ impl Toolset { for p in config.path_dirs.clone() { path_env.add(p); } - for p in self.list_paths(config) { + for p in self.list_paths() { path_env.add(p); } let mut env = self.env(config); @@ -293,7 +280,7 @@ impl Toolset { } pub fn env(&self, config: &Config) -> BTreeMap { let entries = self - .list_current_installed_versions(config) + .list_current_installed_versions() .into_par_iter() .flat_map(|(p, tv)| match p.exec_env(config, self, &tv) { Ok(env) => env.into_iter().collect(), @@ -320,22 +307,22 @@ impl Toolset { entries.extend(config.env.clone()); entries } - pub fn list_paths(&self, config: &Config) -> Vec { - self.list_current_installed_versions(config) + pub fn list_paths(&self) -> Vec { + self.list_current_installed_versions() .into_par_iter() .flat_map(|(p, tv)| { - p.list_bin_paths(config, self, &tv).unwrap_or_else(|e| { + p.list_bin_paths(&tv).unwrap_or_else(|e| { warn!("Error listing bin paths for {tv}: {e:#}"); Vec::new() }) }) .collect() } - pub fn which(&self, config: &Config, bin_name: &str) -> Option<(Arc, ToolVersion)> { - self.list_current_installed_versions(config) + pub fn which(&self, bin_name: &str) -> Option<(Arc, ToolVersion)> { + self.list_current_installed_versions() .into_par_iter() .find_first(|(p, tv)| { - if let Ok(x) = p.which(config, self, tv, bin_name) { + if let Ok(x) = p.which(tv, bin_name) { x.is_some() } else { false @@ -347,7 +334,7 @@ impl Toolset { Ok(self .list_installed_versions(config)? .into_par_iter() - .filter(|(p, tv)| match p.which(config, self, tv, bin_name) { + .filter(|(p, tv)| match p.which(tv, bin_name) { Ok(x) => x.is_some(), Err(e) => { warn!("Error running which: {:#}", e); diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index b54521136..8aa5e306d 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -39,7 +39,6 @@ impl ToolVersion { } pub fn resolve( - config: &Config, tool: Arc, request: ToolVersionRequest, opts: ToolVersionOptions, @@ -51,22 +50,14 @@ impl ToolVersion { } let tv = match request.clone() { ToolVersionRequest::Version(_, v) => { - Self::resolve_version(config, tool, request, latest_versions, &v, opts)? + Self::resolve_version(tool, request, latest_versions, &v, opts)? } ToolVersionRequest::Prefix(_, prefix) => { - Self::resolve_prefix(config, tool, request, &prefix, opts)? + Self::resolve_prefix(tool, request, &prefix, opts)? } ToolVersionRequest::Sub { sub, orig_version, .. - } => Self::resolve_sub( - config, - tool, - request, - latest_versions, - &sub, - &orig_version, - opts, - )?, + } => Self::resolve_sub(tool, request, latest_versions, &sub, &orig_version, opts)?, _ => { let version = request.version(); Self::new(tool, request, opts, version) @@ -102,10 +93,8 @@ impl ToolVersion { .join(&self.plugin_name) .join(self.tv_pathname()) } - pub fn latest_version(&self, config: &Config, tool: Arc) -> Result { - let tv = self - .request - .resolve(config, tool, self.opts.clone(), true)?; + pub fn latest_version(&self, tool: Arc) -> Result { + let tv = self.request.resolve(tool, self.opts.clone(), true)?; Ok(tv.version) } fn tv_pathname(&self) -> String { @@ -126,13 +115,13 @@ impl ToolVersion { } fn resolve_version( - config: &Config, tool: Arc, request: ToolVersionRequest, latest_versions: bool, v: &str, opts: ToolVersionOptions, ) -> Result { + let config = Config::get(); let v = config.resolve_alias(tool.name(), v)?; match v.split_once(':') { Some(("ref", r)) => { @@ -142,11 +131,11 @@ impl ToolVersion { return Self::resolve_path(tool, PathBuf::from(p), opts); } Some(("prefix", p)) => { - return Self::resolve_prefix(config, tool, request, p, opts); + return Self::resolve_prefix(tool, request, p, opts); } Some((part, v)) if part.starts_with("sub-") => { let sub = part.split_once('-').unwrap().1; - return Self::resolve_sub(config, tool, request, latest_versions, sub, v, opts); + return Self::resolve_sub(tool, request, latest_versions, sub, v, opts); } _ => (), } @@ -168,7 +157,7 @@ impl ToolVersion { return build(v); } } - if let Some(v) = tool.latest_version(&config.settings, None)? { + if let Some(v) = tool.latest_version(None)? { return build(v); } } @@ -181,16 +170,15 @@ impl ToolVersion { return build(v.clone()); } } - let matches = tool.list_versions_matching(&config.settings, &v)?; + let matches = tool.list_versions_matching(&v)?; if matches.contains(&v) { return build(v); } - Self::resolve_prefix(config, tool, request, &v, opts) + Self::resolve_prefix(tool, request, &v, opts) } /// resolve a version like `sub-1:12.0.0` which becomes `11.0.0`, `sub-0.1:12.1.0` becomes `12.0.0` fn resolve_sub( - config: &Config, tool: Arc, request: ToolVersionRequest, latest_versions: bool, @@ -199,21 +187,20 @@ impl ToolVersion { opts: ToolVersionOptions, ) -> Result { let v = match v { - "latest" => tool.latest_version(&config.settings, None)?.unwrap(), - _ => config.resolve_alias(tool.name(), v)?, + "latest" => tool.latest_version(None)?.unwrap(), + _ => Config::get().resolve_alias(tool.name(), v)?, }; let v = version_sub(&v, sub); - Self::resolve_version(config, tool, request, latest_versions, &v, opts) + Self::resolve_version(tool, request, latest_versions, &v, opts) } fn resolve_prefix( - config: &Config, tool: Arc, request: ToolVersionRequest, prefix: &str, opts: ToolVersionOptions, ) -> Result { - let matches = tool.list_versions_matching(&config.settings, prefix)?; + let matches = tool.list_versions_matching(prefix)?; let v = match matches.last() { Some(v) => v, None => prefix, diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 6fdf34007..b6cb2a1d8 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -24,7 +24,7 @@ impl ToolVersionList { self.versions.clear(); 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) { + match tvr.resolve(plugin.clone(), opts.clone(), latest_versions) { Ok(v) => self.versions.push(v), Err(err) => warn!("failed to resolve tool version: {:#}", err), } diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 4ceeb491b..748f0e8c8 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -4,7 +4,6 @@ use std::sync::Arc; use color_eyre::eyre::Result; -use crate::config::Config; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionOptions}; @@ -74,12 +73,11 @@ impl ToolVersionRequest { pub fn resolve( &self, - config: &Config, plugin: Arc, opts: ToolVersionOptions, latest_versions: bool, ) -> Result { - ToolVersion::resolve(config, plugin, self.clone(), opts, latest_versions) + ToolVersion::resolve(plugin, self.clone(), opts, latest_versions) } } diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index a2790a25c..702a558b7 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -11,7 +11,8 @@ pub struct MultiProgressReport { } impl MultiProgressReport { - pub fn new(settings: &Settings) -> Self { + pub fn new() -> Self { + let settings = Settings::get(); let mp = match settings.quiet || settings.verbose || !console::user_attended_stderr() { true => None, false => Some(MultiProgress::new()), @@ -66,8 +67,7 @@ mod tests { #[test] fn test_multi_progress_report() { - let settings = Settings::default(); - let mpr = MultiProgressReport::new(&settings); + let mpr = MultiProgressReport::new(); let pr = mpr.add(); pr.set_style(indicatif::ProgressStyle::with_template("").unwrap()); pr.enable_steady_tick(); From 0b3ce876350d7b4386967649908afe2bc0b1ed88 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 01:14:13 -0600 Subject: [PATCH 1315/1891] refactor --- src/shell/completions/zsh_complete.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index eef6b79a9..eab3416e8 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -251,15 +251,14 @@ fn render_command_funcs(cmds: &[&Command]) -> String { let func = func_name(&cmds); let args = render_args(&cmds); let subcommand_funcs = render_command_funcs(&cmds); - formatdoc! {r#" + let s = formatdoc! {r#" (( $+functions[__{func}_cmd] )) || __{func}_cmd() {{ {args} }} {subcommand_funcs}"#, - } - .trim() - .to_string() + }; + s.trim().to_string() }) .collect::>() .join("\n") From cf92bb36b55947dcd5731811bb5181c6abcb425d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 01:15:56 -0600 Subject: [PATCH 1316/1891] CI: skip bump-alpine unless it is a real release --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d76660a05..e07ce307e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -280,6 +280,7 @@ jobs: container: ghcr.io/jdx/rtx:alpine timeout-minutes: 30 needs: [e2e-linux] + if: startsWith(github.event.ref, 'refs/tags/v') steps: - name: Checkout repository uses: actions/checkout@v4 From 834373cdd5f6cf510f1e0496daf694335b07f3c8 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 01:57:27 -0600 Subject: [PATCH 1317/1891] zip: do not require "unzip" utility to unzip archives (#1178) Fixes #1177 --- Cargo.lock | 13 +++++++++++++ Cargo.toml | 1 + src/file.rs | 11 ++++++----- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e8cd965a..973ff1f97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1851,6 +1851,7 @@ dependencies = [ "url", "versions", "which", + "zip", ] [[package]] @@ -3085,6 +3086,18 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "byteorder", + "crc32fast", + "crossbeam-utils", + "flate2", +] + [[package]] name = "zipsign-api" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index d99e176d3..7a93369bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,6 +102,7 @@ toml_edit = "<1" url = "2.4" versions = "6" which = "5" +zip = { version = "0.6", default-features = false, features = ["deflate"] } [target.'cfg(unix)'.dependencies] exec = "0.3" diff --git a/src/file.rs b/src/file.rs index cb76ea442..edf30db53 100644 --- a/src/file.rs +++ b/src/file.rs @@ -9,8 +9,9 @@ use color_eyre::eyre::{Context, Result}; use filetime::{set_file_times, FileTime}; use flate2::read::GzDecoder; use tar::Archive; +use zip::ZipArchive; -use crate::{cmd, dirs, env}; +use crate::{dirs, env}; pub fn remove_all>(path: P) -> Result<()> { let path = path.as_ref(); @@ -277,10 +278,10 @@ pub fn untar(archive: &Path, dest: &Path) -> Result<()> { } pub fn unzip(archive: &Path, dest: &Path) -> Result<()> { - cmd!("unzip", archive, "-d", dest) - .run() - .wrap_err_with(|| eyre!("unzip {} -d {}", display_path(archive), display_path(dest)))?; - Ok(()) + ZipArchive::new(File::open(archive)?) + .wrap_err_with(|| format!("failed to open zip archive: {}", display_path(archive)))? + .extract(dest) + .wrap_err_with(|| format!("failed to extract zip archive: {}", display_path(archive))) } #[cfg(test)] From 5dd20e4522b73699a7778a039f875855fe384a25 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 01:59:27 -0600 Subject: [PATCH 1318/1891] CI: added e2e test for install.sh (#1176) Fixes #1132 --- .github/workflows/rtx.yml | 1 + packaging/standalone/install.envsubst | 14 +++++++------- scripts/release.sh | 6 ++---- scripts/render-install.sh | 2 +- scripts/test-standalone.sh | 20 ++++++++++++++++++++ 5 files changed, 31 insertions(+), 12 deletions(-) create mode 100755 scripts/test-standalone.sh diff --git a/.github/workflows/rtx.yml b/.github/workflows/rtx.yml index 0a215acda..ad0858f94 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/rtx.yml @@ -43,6 +43,7 @@ jobs: - run: cargo deny check - run: cargo msrv verify - run: cargo machete --with-metadata + - run: ./scripts/test-standalone.sh - run: just render-all lint-fix - if: github.event_name == 'pull_request' uses: EndBug/add-and-commit@v9 diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index 637319ec8..46d5d9dc5 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -52,13 +52,13 @@ get_arch() { } shasum_bin() { - if command -v shasum >/dev/null 2>&1; then - echo "shasum" - elif command -v sha256sum >/dev/null 2>&1; then - echo "sha256sum" - else - error "rtx install requires shasum or sha256sum but neither is installed. Aborting." - fi + if command -v shasum >/dev/null 2>&1; then + echo "shasum" + elif command -v sha256sum >/dev/null 2>&1; then + echo "sha256sum" + else + error "rtx install requires shasum or sha256sum but neither is installed. Aborting." + fi } get_checksum() { diff --git a/scripts/release.sh b/scripts/release.sh index eb99227ee..2c9cda0b3 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -4,9 +4,10 @@ set -euxo pipefail git config --global user.name rtx-vm git config --global user.email 123107610+rtx-vm@users.noreply.github.com +BASE_DIR="$(cd rtx && pwd)" RTX_VERSION=$(cd rtx && ./scripts/get-version.sh) RELEASE_DIR=releases -export RTX_VERSION RELEASE_DIR +export BASE_DIR RTX_VERSION RELEASE_DIR rm -rf "${RELEASE_DIR:?}/$RTX_VERSION" mkdir -p "$RELEASE_DIR/$RTX_VERSION" @@ -56,9 +57,6 @@ popd ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh chmod +x "$RELEASE_DIR"/install.sh shellcheck "$RELEASE_DIR"/install.sh -# TODO: figure out how to test this -# "$RELEASE_DIR"/install.sh -#~/.local/share/rtx/bin/rtx -v gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh if [[ "$DRY_RUN" != 1 ]]; then diff --git a/scripts/render-install.sh b/scripts/render-install.sh index 1f66c7357..7b2b4c786 100755 --- a/scripts/render-install.sh +++ b/scripts/render-install.sh @@ -14,4 +14,4 @@ RTX_VERSION=$RTX_VERSION \ RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v.*macos-x64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v.*macos-arm64.tar.gz" "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt") \ envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ - "$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" +./scripts/render-install.sh >tmp/install.sh +chmod +x tmp/install.sh +shellcheck tmp/install.sh + +RTX_DATA_DIR="$RELEASE_DIR" ./tmp/install.sh +if [[ ! "$("$RELEASE_DIR/bin/rtx" -v)" =~ ^${RTX_VERSION//v/} ]]; then + echo "rtx version mismatch" + exit 1 +fi +rm -rf "$RELEASE_DIR" From 78c9f50839858bc9e4f7e675bfce39c1e2238a28 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 02:18:01 -0600 Subject: [PATCH 1319/1891] refactor: clean up is_trusted logic (#1179) --- src/cli/env_vars.rs | 7 ++--- src/config/config_file/mod.rs | 12 +++----- src/config/config_file/rtx_toml.rs | 40 ++++++++++++++----------- src/config/config_file/tool_versions.rs | 28 ++++++++--------- src/config/mod.rs | 7 ++--- 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index aaded7705..dd4f2c979 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -1,7 +1,7 @@ use color_eyre::Result; use crate::config::config_file::rtx_toml::RtxToml; -use crate::config::config_file::{self, ConfigFile}; +use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::dirs; use crate::env::RTX_DEFAULT_CONFIG_FILENAME; @@ -67,11 +67,10 @@ impl EnvVars { fn get_rtx_toml(filename: &str) -> Result { let path = dirs::CURRENT.join(filename); - let is_trusted = config_file::is_trusted(&path); let rtx_toml = if path.exists() { - RtxToml::from_file(&path, is_trusted)? + RtxToml::from_file(&path)? } else { - RtxToml::init(&path, is_trusted) + RtxToml::init(&path) }; Ok(rtx_toml) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index e0e998b71..6f3c79722 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -141,10 +141,9 @@ impl dyn ConfigFile { } fn init(path: &Path) -> Box { - let is_trusted = is_trusted(path); match detect_config_file_type(path) { - Some(ConfigFileType::RtxToml) => Box::new(RtxToml::init(path, is_trusted)), - Some(ConfigFileType::ToolVersions) => Box::new(ToolVersions::init(path, is_trusted)), + Some(ConfigFileType::RtxToml) => Box::new(RtxToml::init(path)), + Some(ConfigFileType::ToolVersions) => Box::new(ToolVersions::init(path)), _ => panic!("Unknown config file type: {}", path.display()), } } @@ -158,12 +157,9 @@ pub fn parse_or_init(path: &Path) -> Result> { } pub fn parse(path: &Path) -> Result> { - let is_trusted = is_trusted(path); match detect_config_file_type(path) { - Some(ConfigFileType::RtxToml) => Ok(Box::new(RtxToml::from_file(path, is_trusted)?)), - Some(ConfigFileType::ToolVersions) => { - Ok(Box::new(ToolVersions::from_file(path, is_trusted)?)) - } + Some(ConfigFileType::RtxToml) => Ok(Box::new(RtxToml::from_file(path)?)), + Some(ConfigFileType::ToolVersions) => Ok(Box::new(ToolVersions::from_file(path)?)), #[allow(clippy::box_default)] _ => Ok(Box::new(RtxToml::default())), } diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index e7808fd85..756db85bc 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::collections::HashMap; use std::fmt::{Debug, Display, Formatter}; use std::path::{Path, PathBuf}; @@ -38,17 +37,17 @@ pub struct RtxToml { alias: AliasMap, doc: Document, plugins: HashMap, - is_trusted: Mutex>, + is_trusted: Mutex>, } impl RtxToml { - pub fn init(path: &Path, is_trusted: bool) -> Self { + pub fn init(path: &Path) -> Self { let mut context = BASE_CONTEXT.clone(); context.insert("config_root", path.parent().unwrap().to_str().unwrap()); Self { path: path.to_path_buf(), context, - is_trusted: Mutex::new(RefCell::new(is_trusted)), + is_trusted: Mutex::new(None), toolset: Toolset { source: Some(ToolSource::RtxToml(path.to_path_buf())), ..Default::default() @@ -57,9 +56,9 @@ impl RtxToml { } } - pub fn from_file(path: &Path, is_trusted: bool) -> Result { + pub fn from_file(path: &Path) -> Result { trace!("parsing: {}", path.display()); - let mut rf = Self::init(path, is_trusted); + let mut rf = Self::init(path); let body = file::read_to_string(path).suggestion("ensure file exists and can be read")?; rf.parse(&body)?; trace!("{rf}"); @@ -568,7 +567,12 @@ impl RtxToml { } fn get_is_trusted(&self) -> bool { - *self.is_trusted.lock().unwrap().borrow() + let mut is_trusted = self.is_trusted.lock().unwrap(); + is_trusted.unwrap_or_else(|| { + let b = config_file::is_trusted(self.path.as_path()); + *is_trusted = Some(b); + b + }) } } @@ -760,7 +764,7 @@ impl Clone for RtxToml { alias: self.alias.clone(), doc: self.doc.clone(), plugins: self.plugins.clone(), - is_trusted: Mutex::new(RefCell::new(*self.is_trusted.lock().unwrap().borrow())), + is_trusted: Mutex::new(*self.is_trusted.lock().unwrap()), } } } @@ -776,7 +780,7 @@ mod tests { #[test] fn test_fixture() { - let cf = RtxToml::from_file(&dirs::HOME.join("fixtures/.rtx.toml"), true).unwrap(); + let cf = RtxToml::from_file(&dirs::HOME.join("fixtures/.rtx.toml")).unwrap(); assert_debug_snapshot!(cf.env()); assert_debug_snapshot!(cf.settings()); @@ -789,7 +793,7 @@ mod tests { #[test] fn test_env() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [env] foo="bar" @@ -808,7 +812,7 @@ mod tests { #[test] fn test_path_dirs() { let p = dirs::HOME.join("fixtures/.rtx.toml"); - let mut cf = RtxToml::init(&p, true); + let mut cf = RtxToml::init(&p); cf.parse(&formatdoc! {r#" env_path=["/foo", "./bar"] [env] @@ -827,7 +831,7 @@ mod tests { #[test] fn test_set_alias() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [alias.node] 16 = "16.0.0" @@ -845,7 +849,7 @@ mod tests { #[test] fn test_remove_alias() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [alias.node] 16 = "16.0.0" @@ -864,7 +868,7 @@ mod tests { #[test] fn test_replace_versions() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [tools] node = ["16.0.0", "18.0.0"] @@ -881,7 +885,7 @@ mod tests { #[test] fn test_remove_plugin() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [tools] node = ["16.0.0", "18.0.0"] @@ -895,7 +899,7 @@ mod tests { #[test] fn test_update_setting() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true @@ -914,7 +918,7 @@ mod tests { #[test] fn test_remove_setting() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true @@ -927,7 +931,7 @@ mod tests { #[test] fn test_fail_with_unknown_key() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path(), true); + let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); let err = cf .parse(&formatdoc! {r#" invalid_key = true diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index bf4ef6285..818bd8e8c 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -7,7 +7,7 @@ use indexmap::IndexMap; use itertools::Itertools; use tera::Context; -use crate::config::config_file::{ConfigFile, ConfigFileType}; +use crate::config::config_file::{is_trusted, ConfigFile, ConfigFileType}; use crate::file; use crate::file::display_path; @@ -27,7 +27,6 @@ pub struct ToolVersions { pre: String, plugins: IndexMap, toolset: Toolset, - is_trusted: bool, } #[derive(Debug)] @@ -38,27 +37,26 @@ struct ToolVersionPlugin { } impl ToolVersions { - pub fn init(filename: &Path, is_trusted: bool) -> ToolVersions { + pub fn init(filename: &Path) -> ToolVersions { let mut context = BASE_CONTEXT.clone(); context.insert("config_root", filename.parent().unwrap().to_str().unwrap()); ToolVersions { context, toolset: Toolset::new(ToolSource::ToolVersions(filename.to_path_buf())), path: filename.to_path_buf(), - is_trusted, ..Default::default() } } - pub fn from_file(path: &Path, is_trusted: bool) -> Result { + pub fn from_file(path: &Path) -> Result { trace!("parsing tool-versions: {}", path.display()); - Self::parse_str(&file::read_to_string(path)?, path.to_path_buf(), is_trusted) + Self::parse_str(&file::read_to_string(path)?, path.to_path_buf()) } - pub fn parse_str(s: &str, path: PathBuf, is_trusted: bool) -> Result { - let mut cf = Self::init(&path, is_trusted); + pub fn parse_str(s: &str, path: PathBuf) -> Result { + let mut cf = Self::init(&path); let dir = path.parent().unwrap(); - let s = if cf.is_trusted { + let s = if is_trusted(&path) { get_tera(dir).render_str(s, &cf.context)? } else { s.to_string() @@ -210,8 +208,8 @@ pub(crate) mod tests { #[test] fn test_parse() { - let tv = ToolVersions::from_file(dirs::CURRENT.join(".test-tool-versions").as_path(), true) - .unwrap(); + let tv = + ToolVersions::from_file(dirs::CURRENT.join(".test-tool-versions").as_path()).unwrap(); assert_eq!(tv.path, dirs::CURRENT.join(".test-tool-versions")); assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.test-tool-versions): tiny@3"); } @@ -226,7 +224,7 @@ pub(crate) mod tests { # tail comment "}; let path = dirs::CURRENT.join(".test-tool-versions"); - let tv = ToolVersions::parse_str(orig, path, false).unwrap(); + let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_eq!(tv.dump(), orig); } @@ -236,7 +234,7 @@ pub(crate) mod tests { ruby: 3.0.5 "}; let path = dirs::CURRENT.join(".test-tool-versions"); - let tv = ToolVersions::parse_str(orig, path, false).unwrap(); + let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_snapshot!(tv.dump(), @r###" ruby 3.0.5 "###); @@ -249,7 +247,7 @@ pub(crate) mod tests { python {{exec(command='echo 3.11.0')}} "}; let path = dirs::CURRENT.join(".test-tool-versions"); - let tv = ToolVersions::parse_str(orig, path, true).unwrap(); + let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_snapshot!(tv.dump(), @r###" ruby 3.0.5 python 3.11.0 @@ -262,7 +260,7 @@ pub(crate) mod tests { ruby: 3.0.5 3.1 "}; let path = dirs::CURRENT.join(".test-tool-versions"); - let tv = ToolVersions::parse_str(orig, path, true).unwrap(); + let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_display_snapshot!(tv.to_toolset(), @"ruby@3.0.5 ruby@3.1"); } } diff --git a/src/config/mod.rs b/src/config/mod.rs index a492c3ae8..d4c471e3a 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -268,14 +268,13 @@ fn load_rtxrc() -> Result { let settings_path = env::RTX_CONFIG_FILE .clone() .unwrap_or(dirs::CONFIG.join("config.toml")); - let is_trusted = config_file::is_trusted(&settings_path); match settings_path.exists() { false => { trace!("settings does not exist {:?}", settings_path); - Ok(RtxToml::init(&settings_path, is_trusted)) + Ok(RtxToml::init(&settings_path)) } - true => RtxToml::from_file(&settings_path, is_trusted) - .wrap_err_with(|| format!("Error parsing {}", display_path(&settings_path))), + true => RtxToml::from_file(&settings_path) + .wrap_err_with(|| eyre!("Error parsing {}", display_path(&settings_path))), } } From c0b38da2c7ade68b58591fda85a90e570f1c531e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 02:19:55 -0600 Subject: [PATCH 1320/1891] test: show time for each e2e test --- e2e/run_test | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/e2e/run_test b/e2e/run_test index 3700f64e8..c1e46487a 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -34,7 +34,11 @@ run_test() { rm -f "$RTX_CONFIG_FILE" cd "$(dirname "$TEST")" + START=$(date +%s) "./$(basename "$TEST")" + END=$(date +%s) + + echo "$TEST: $((END - START))s" } setup_env From 8cbe2b1e2da817bdba288d7446c57c73830d6047 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 02:22:07 -0600 Subject: [PATCH 1321/1891] bun|deno: remove shorthand repo since these are core plugins now (#1180) --- scripts/update-shorthand-repo.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index 3d9e62a13..d32025321 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -13,6 +13,8 @@ custom_plugins=( asdf_plugins=$(find asdf-plugins/plugins -maxdepth 1 | sort | + grep -v '/bun$' | + grep -v '/deno$' | grep -v '/go$' | grep -v '/golang$' | grep -v '/java$' | From 29d301d6a79fa616dda5e0b1214efefc9f54e5fb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 04:34:35 -0600 Subject: [PATCH 1322/1891] CI: consolidate GH action cache (#1181) * CI: consolidate GH action cache * CI: consolidate GH action cache * Commit from GitHub Actions (test) * CI: test run formatting * e2e * ci * ci * poetry * e2e * poetry * e2e * poetry * e2e * make more e2e tests slow --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- .github/workflows/{rtx.yml => test.yml} | 13 ++++++------- e2e/cd/test_bash | 15 +++++++++++---- e2e/config/.e2e.rtx.toml | 4 +--- e2e/run_all_tests | 6 ++++++ e2e/run_test | 16 ++++++++++++++-- e2e/test_bun | 4 ++-- e2e/test_local | 16 ++++------------ e2e/test_nodejs | 19 ++++--------------- e2e/test_plugins_install | 1 + e2e/test_poetry | 9 +++++++++ e2e/test_python | 4 ++++ justfile | 15 ++++++++++++--- scripts/release.sh | 9 ++++++++- src/cli/install.rs | 6 +----- src/shims.rs | 11 +++-------- src/toolset/mod.rs | 23 ++++++++--------------- 16 files changed, 94 insertions(+), 77 deletions(-) rename .github/workflows/{rtx.yml => test.yml} (93%) diff --git a/.github/workflows/rtx.yml b/.github/workflows/test.yml similarity index 93% rename from .github/workflows/rtx.yml rename to .github/workflows/test.yml index ad0858f94..f8d3c434f 100644 --- a/.github/workflows/rtx.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,4 @@ -name: rtx - +name: test on: push: tags: ["v*"] @@ -29,8 +28,9 @@ jobs: ref: ${{ github.event.pull_request.head.ref }} - uses: Swatinem/rust-cache@v2 with: - shared-key: unit - save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + shared-key: test + save-if: ${{ github.ref_name == 'main' }} + cache-all-crates: true - uses: taiki-e/install-action@v2 with: tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete @@ -70,9 +70,8 @@ jobs: #- run: rustup toolchain install nightly --component llvm-tools-preview --profile minimal - uses: Swatinem/rust-cache@v2 with: - shared-key: coverage - save-if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - cache-all-crates: true + shared-key: test + save-if: false - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - run: npm i -g markdown-magic - uses: taiki-e/install-action@v2 diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 836a4e6f0..af7d4aabf 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -31,24 +31,31 @@ assert_path() { fi } +NODE_18="INSTALLS/node/18.0.0/bin" +NODE_20="INSTALLS/node/20.0.0/bin" +TINY="INSTALLS/tiny/3.1.0/bin" +SHELLCHECK="INSTALLS/shellcheck/0.9.0/bin" +SHFMT="INSTALLS/shfmt/3.6.0/bin" + +rtx ls rtx i && _rtx_hook test "$(node -v)" = "v20.0.0" -assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:$NODE_20:$TINY:$SHELLCHECK:$SHFMT" assert "$FOO" "cd" cd 18 && rtx i && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/18.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:$NODE_18:$TINY:$SHELLCHECK:$SHFMT" assert "$FOO" "18" cd .. && _rtx_hook test "$(node -v)" = "v20.0.0" -assert_path "/root:ROOT/e2e/cwd:INSTALLS/node/20.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +assert_path "/root:ROOT/e2e/cwd:$NODE_20:$TINY:$SHELLCHECK:$SHFMT" export PATH="PRE:$PATH" cd 18 && _rtx_hook test "$(node -v)" = "v18.0.0" -assert_path "PRE:/root:ROOT/e2e/cwd:INSTALLS/node/18.0.0/bin:INSTALLS/python/3.12.0/bin:INSTALLS/tiny/3.1.0/bin:INSTALLS/poetry/1.7.1/bin:INSTALLS/shellcheck/0.9.0/bin:INSTALLS/shfmt/3.6.0/bin" +assert_path "PRE:/root:ROOT/e2e/cwd:$NODE_18:$TINY:$SHELLCHECK:$SHFMT" rtx shell node@18.0.0 && _rtx_hook test "$(node -v)" = "v18.0.0" diff --git a/e2e/config/.e2e.rtx.toml b/e2e/config/.e2e.rtx.toml index 84239c98b..6a2d5fe45 100644 --- a/e2e/config/.e2e.rtx.toml +++ b/e2e/config/.e2e.rtx.toml @@ -5,10 +5,8 @@ env_path = ["/root", "./cwd"] FOO = "bar" [tools] -python = "3.12.0" tiny = "latest" -poetry = {version="1.7.1", pyproject="pyproject.toml"} #golang = {version="1.19.5", foo="bar"} [plugins] -tiny-ref = "https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4" +tiny-ref = "https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c" diff --git a/e2e/run_all_tests b/e2e/run_all_tests index f4f967168..9bcd26c90 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -5,6 +5,12 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" FILES=$(find e2e -name 'test_*' -type f -not -path "*/.rtx/*" | sort) test_count=0 +if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then + { + echo "| Test | Duration | Result |" + echo "| ---- | -------- | ------ |" + } >>"$GITHUB_STEP_SUMMARY" +fi for f in $FILES; do # split tests into two tranches to reduce test time if [ -n "${TEST_TRANCHE_COUNT:-}" ]; then diff --git a/e2e/run_test b/e2e/run_test index c1e46487a..9a930311d 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -15,6 +15,7 @@ setup_env() { export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" + export RTX_ALWAYS_KEEP_DOWNLOAD="1" export RTX_TRUSTED_CONFIG_PATHS="$ROOT/e2e" export RTX_YES="1" export NPM_CONFIG_FUND="false" @@ -30,15 +31,26 @@ setup_config_files() { } run_test() { - echo "Running $TEST" + echo "::group::E2E $TEST" rm -f "$RTX_CONFIG_FILE" cd "$(dirname "$TEST")" START=$(date +%s) - "./$(basename "$TEST")" + local status=0 + "./$(basename "$TEST")" || status=$? END=$(date +%s) + if [[ "$status" == 0 ]]; then + STATUS_MSG=":white_check_mark:" + else + echo "::error file=$TEST::E2E Test Failed (code: $status)" + STATUS_MSG=":x:" + fi echo "$TEST: $((END - START))s" + if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then + echo "| $TEST | $((END - START))s | $STATUS_MSG" >>"$GITHUB_STEP_SUMMARY" + fi + return "$status" } setup_env diff --git a/e2e/test_bun b/e2e/test_bun index 383c3501e..a4241e98b 100755 --- a/e2e/test_bun +++ b/e2e/test_bun @@ -6,8 +6,8 @@ source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 cat <.bun-version -0.7.0 +1.0.17 EOF rtx i bun -assert_contains "rtx x bun -- bun -v" "0.7.0" +assert_contains "rtx x bun -- bun -v" "1.0.17" rm .bun-version diff --git a/e2e/test_local b/e2e/test_local index d0e720cfa..b32dbf51e 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -25,13 +25,11 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] -python = \"3.12.0\" tiny = \"latest\" -poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" " rtx local shfmt@3.5.0 @@ -42,14 +40,12 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] -python = \"3.12.0\" tiny = \"latest\" -poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} shfmt = \"3.5.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" " rtx exec -- shfmt --version >&2 @@ -65,14 +61,12 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] -python = \"3.12.0\" tiny = \"latest\" -poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} shfmt = \"3.6.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" " rtx exec -- shfmt --version >&2 @@ -88,13 +82,11 @@ env_path = [\"/root\", \"./cwd\"] FOO = \"bar\" [tools] -python = \"3.12.0\" tiny = \"latest\" -poetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"} #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#df03b6719dd465d565bb66273942c8495673eaa4\" +tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" " export RTX_DEFAULT_CONFIG_FILENAME=.MISSING diff --git a/e2e/test_nodejs b/e2e/test_nodejs index e861976aa..e19e06d4f 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -4,20 +4,21 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" export RTX_EXPERIMENTAL=1 -export RTX_NODE_BUILD=1 +export RTX_NODE_COREPACK=1 export RTX_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-npm-packages" rtx plugin uninstall node rtx i node node@lts/hydrogen assert_contains "rtx x node@lts/hydrogen -- node --version" "v18." assert "rtx x -- node --version" "v20.0.0" -assert_contains "rtx node node-build --version" "node-build " +assert_contains "rtx x -- which yarn" "yarn" # test asdf-nodejs rtx plugin i nodejs https://github.com/asdf-vm/asdf-nodejs.git rtx use nodejs@20.1.0 rtx ls assert "rtx x -- node --version" "v20.1.0" +assert_contains "rtx ls-remote nodejs" "20.1.0" assert_contains "rtx node nodebuild --version" "node-build " rtx use --rm node @@ -25,19 +26,7 @@ rtx use --rm node 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 +assert_not_contains "rtx plugins --user" "node" # disable nodejs plugin RTX_DISABLE_TOOLS=node assert_not_contains "rtx plugins --core" "node" - -export RTX_NODE_BUILD=0 -rtx uninstall -a node -rtx i node -assert "rtx x -- node --version" "v20.0.0" -# rtx uninstall node -# RTX_NODE_COMPILE=1 rtx i node -# assert "rtx x -- node --version" "v20.0.0" - -export RTX_NODE_COREPACK=1 -rtx uninstall node -rtx i node -assert_contains "rtx x node -- which yarn" "yarn" diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install index 8e112d79f..c18662080 100755 --- a/e2e/test_plugins_install +++ b/e2e/test_plugins_install @@ -47,3 +47,4 @@ rtx plugin uninstall tiny rtx plugin update rtx plugin update shfmt +rtx i diff --git a/e2e/test_poetry b/e2e/test_poetry index c669db4d2..bd9620041 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -3,11 +3,20 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" +if [ "${TEST_ALL:-}" != 1 ]; then + exit +fi + rm -rf "$RTX_DATA_DIR/cache/poetry" export POETRY_HOME=".poetry" eval "$(rtx activate bash)" +cat >.e2e.rtx.toml <VERSION cp rtx-latest-linux-x64 rtx-latest-linux-amd64 @@ -54,18 +57,22 @@ gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc popd +echo "::group::install.sh" ./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh chmod +x "$RELEASE_DIR"/install.sh shellcheck "$RELEASE_DIR"/install.sh gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh if [[ "$DRY_RUN" != 1 ]]; then + echo "::group::Publish npm @jdxcode/rtx" NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh + echo "::group::Publish npm rtx-cli" NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh - #AWS_S3_BUCKET=rtx.jdx.dev ./rtx/scripts/publish-s3.sh + echo "::group::Publish r2" ./rtx/scripts/publish-r2.sh fi +echo "::group::Publish homebrew" ./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb pushd homebrew-tap git add . && git commit -m "rtx ${RTX_VERSION#v}" diff --git a/src/cli/install.rs b/src/cli/install.rs index e5db33a7e..4b9f3b0d1 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -120,11 +120,7 @@ impl Install { fn install_missing_runtimes(&self, config: &Config) -> Result<()> { let mut ts = ToolsetBuilder::new().with_latest_versions().build(config)?; - let versions = ts - .list_missing_versions(config) - .into_iter() - .cloned() - .collect::>(); + let versions = ts.list_missing_versions(); if versions.is_empty() { info!("all runtimes are installed"); return Ok(()); diff --git a/src/shims.rs b/src/shims.rs index ab98a55fe..c5fc75be5 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -64,7 +64,7 @@ fn which_shim(config: &Config, bin_name: &str) -> Result { } } let tvs = ts.list_rtvs_with_bin(config, bin_name)?; - err_no_version_set(config, ts, bin_name, tvs)?; + err_no_version_set(ts, bin_name, tvs)?; } Err(eyre!("{} is not a valid shim", bin_name)) } @@ -190,18 +190,13 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { Ok(()) } -fn err_no_version_set( - config: &Config, - ts: Toolset, - bin_name: &str, - tvs: Vec, -) -> Result<()> { +fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Result<()> { if tvs.is_empty() { return Ok(()); } let missing_plugins = tvs.iter().map(|tv| &tv.plugin_name).collect::>(); let mut missing_tools = ts - .list_missing_versions(config) + .list_missing_versions() .into_iter() .filter(|t| missing_plugins.contains(&t.plugin_name)) .collect_vec(); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index c90c5566a..a44abf030 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -93,10 +93,11 @@ impl Toolset { pub fn install_arg_versions(&mut self, config: &Config, opts: &InstallOptions) -> Result<()> { let mpr = MultiProgressReport::new(); let versions = self - .list_missing_versions(config) + .list_current_versions() .into_iter() + .filter(|(p, tv)| opts.force || !p.is_version_installed(tv)) + .map(|(_, tv)| tv) .filter(|tv| matches!(self.versions[&tv.plugin_name].source, ToolSource::Argument)) - .cloned() .collect_vec(); self.install_versions(config, versions, &mpr, opts) } @@ -170,19 +171,11 @@ impl Toolset { shims::reshim(config, self)?; runtime_symlinks::rebuild(config) } - pub fn list_missing_versions(&self, config: &Config) -> Vec<&ToolVersion> { - self.versions - .iter() - .map(|(p, tvl)| { - let p = config.get_or_create_plugin(p); - (p, tvl) - }) - .flat_map(|(p, tvl)| { - tvl.versions - .iter() - .filter(|tv| !p.is_version_installed(tv)) - .collect_vec() - }) + pub fn list_missing_versions(&self) -> Vec { + self.list_current_versions() + .into_iter() + .filter(|(p, tv)| !p.is_version_installed(tv)) + .map(|(_, tv)| tv) .collect() } pub fn list_installed_versions( From 05968b8730cd37bc2ae724ab228fbaa10b1298b9 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 05:45:39 -0600 Subject: [PATCH 1323/1891] refactor: use trait object for progress bar wrappers (#1182) --- .github/workflows/test.yml | 8 +- e2e/test_poetry | 2 +- e2e/test_python | 2 +- src/cli/plugins/uninstall.rs | 8 +- src/cli/prune.rs | 6 +- src/cli/uninstall.rs | 8 +- src/cli/upgrade.rs | 6 +- src/cmd.rs | 10 +- src/install_context.rs | 4 +- src/plugins/core/bun.rs | 10 +- src/plugins/core/deno.rs | 18 +-- src/plugins/core/go.rs | 20 +-- src/plugins/core/java.rs | 23 ++-- src/plugins/core/node.rs | 35 +++--- src/plugins/core/node_build.rs | 22 ++-- src/plugins/core/python.rs | 22 ++-- src/plugins/core/ruby.rs | 25 ++-- src/plugins/external_plugin.rs | 18 +-- src/plugins/mod.rs | 25 ++-- src/plugins/script_manager.rs | 4 +- src/ui/multi_progress_report.rs | 29 ++--- src/ui/progress_report.rs | 216 +++++++++++++++++--------------- 22 files changed, 268 insertions(+), 253 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f8d3c434f..9bf896582 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,9 +28,8 @@ jobs: ref: ${{ github.event.pull_request.head.ref }} - uses: Swatinem/rust-cache@v2 with: - shared-key: test + shared-key: unit save-if: ${{ github.ref_name == 'main' }} - cache-all-crates: true - uses: taiki-e/install-action@v2 with: tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete @@ -66,12 +65,11 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - #- run: rustup toolchain install nightly --component llvm-tools-preview --profile minimal - uses: Swatinem/rust-cache@v2 with: - shared-key: test - save-if: false + shared-key: coverage + save-if: ${{ github.ref_name == 'main' }} - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - run: npm i -g markdown-magic - uses: taiki-e/install-action@v2 diff --git a/e2e/test_poetry b/e2e/test_poetry index bd9620041..9a013b093 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -4,7 +4,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" if [ "${TEST_ALL:-}" != 1 ]; then - exit + exit fi rm -rf "$RTX_DATA_DIR/cache/poetry" diff --git a/e2e/test_python b/e2e/test_python index 6c87599df..b1b1e678c 100755 --- a/e2e/test_python +++ b/e2e/test_python @@ -4,7 +4,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" if [ "${TEST_ALL:-}" != 1 ]; then - exit + exit fi export RTX_EXPERIMENTAL=1 diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index af5c7a58a..b3c3e1454 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -52,12 +52,12 @@ impl PluginsUninstall { 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)?; + plugin.decorate_progress_bar(pr.as_mut(), None); + plugin.uninstall(pr.as_ref())?; if self.purge { - plugin.purge(&pr)?; + plugin.purge(pr.as_ref())?; } - pr.finish_with_message("uninstalled"); + pr.finish_with_message("uninstalled".into()); } _ => mpr.suspend(|| { warn!( diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 218dbc479..a1b63840e 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -59,11 +59,11 @@ impl Prune { for (p, tv) in to_delete { let mut pr = mpr.add(); if self.dry_run { - pr.set_prefix(format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); + pr.set_prefix(&format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); } if self.dry_run || settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? { - p.decorate_progress_bar(&mut pr, Some(&tv)); - p.uninstall_version(&tv, &pr, self.dry_run)?; + p.decorate_progress_bar(pr.as_mut(), Some(&tv)); + p.uninstall_version(&tv, pr.as_ref(), self.dry_run)?; pr.finish(); } } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 5f09581e5..2581c2ae0 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -53,15 +53,15 @@ impl Uninstall { } let mut pr = mpr.add(); - plugin.decorate_progress_bar(&mut pr, Some(&tv)); - if let Err(err) = plugin.uninstall_version(&tv, &pr, self.dry_run) { + plugin.decorate_progress_bar(pr.as_mut(), Some(&tv)); + if let Err(err) = plugin.uninstall_version(&tv, pr.as_ref(), self.dry_run) { pr.error(err.to_string()); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); } if self.dry_run { - pr.finish_with_message("uninstalled (dry-run)"); + pr.finish_with_message("uninstalled (dry-run)".into()); } else { - pr.finish_with_message("uninstalled"); + pr.finish_with_message("uninstalled".into()); } } diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index f2634421e..c3611b1d7 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -12,7 +12,7 @@ use crate::runtime_symlinks; use crate::shims; use crate::toolset::{InstallOptions, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; /// Upgrades outdated tool versions #[derive(Debug, clap::Args)] @@ -95,7 +95,7 @@ impl Upgrade { ts.install_versions(config, new_versions, &mpr, &opts)?; for (tool, tv) in to_remove { let mut pr = mpr.add(); - self.uninstall_old_version(tool.clone(), &tv, &mut pr)?; + self.uninstall_old_version(tool.clone(), &tv, pr.as_mut())?; } let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; @@ -108,7 +108,7 @@ impl Upgrade { &self, tool: Arc, tv: &ToolVersion, - pr: &mut ProgressReport, + pr: &mut dyn SingleReport, ) -> Result<()> { tool.decorate_progress_bar(pr, Some(tv)); match tool.uninstall_version(tv, pr, self.dry_run) { diff --git a/src/cmd.rs b/src/cmd.rs index 42e58e38a..3fe46fc18 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -14,7 +14,7 @@ use eyre::Context; use crate::env; use crate::errors::Error::ScriptFailed; use crate::file::display_path; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; /// Create a command with any number of of positional arguments, which may be /// different types (anything that implements @@ -90,7 +90,7 @@ where pub struct CmdLineRunner<'a> { cmd: Command, - pr: Option<&'a ProgressReport>, + pr: Option<&'a dyn SingleReport>, stdin: Option, } @@ -171,7 +171,7 @@ impl<'a> CmdLineRunner<'a> { self } - pub fn with_pr(mut self, pr: &'a ProgressReport) -> Self { + pub fn with_pr(mut self, pr: &'a dyn SingleReport) -> Self { self.pr = Some(pr); self } @@ -270,7 +270,7 @@ impl<'a> CmdLineRunner<'a> { fn on_stdout(&self, line: &str) { if !line.trim().is_empty() { if let Some(pr) = self.pr { - pr.set_message(line) + pr.set_message(line.into()) } } } @@ -278,7 +278,7 @@ impl<'a> CmdLineRunner<'a> { fn on_stderr(&self, line: &str) { if !line.trim().is_empty() { match self.pr { - Some(pr) => pr.println(line), + Some(pr) => pr.println(line.into()), None => eprintln!("{}", line), } } diff --git a/src/install_context.rs b/src/install_context.rs index daa1baefa..b4e39436e 100644 --- a/src/install_context.rs +++ b/src/install_context.rs @@ -1,10 +1,10 @@ use crate::toolset::{ToolVersion, Toolset}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; pub struct InstallContext<'a> { pub ts: &'a Toolset, pub tv: ToolVersion, - pub pr: ProgressReport, + pub pr: Box, pub raw: bool, pub force: bool, } diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 85dc6c125..693ec3c60 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -11,7 +11,7 @@ use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::{Plugin, HTTP}; use crate::toolset::{ToolVersion, ToolVersionRequest}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{file, http}; #[derive(Debug)] @@ -48,14 +48,14 @@ impl BunPlugin { } fn test_bun(&self, ctx: &InstallContext) -> Result<()> { - ctx.pr.set_message("bun -v"); + ctx.pr.set_message("bun -v".into()); CmdLineRunner::new(self.bun_bin(&ctx.tv)) - .with_pr(&ctx.pr) + .with_pr(ctx.pr.as_ref()) .arg("-v") .execute() } - fn download(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result { + fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { let http = http::Client::new()?; let url = format!( "https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-{}-{}.zip", @@ -116,7 +116,7 @@ impl Plugin for BunPlugin { ToolVersionRequest::Version { .. } )); - let tarball_path = self.download(&ctx.tv, &ctx.pr)?; + let tarball_path = self.download(&ctx.tv, ctx.pr.as_ref())?; self.install(ctx, &tarball_path)?; self.verify(ctx)?; diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 5368c1902..b8eddf375 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -13,7 +13,7 @@ use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::{Plugin, HTTP}; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{file, http}; #[derive(Debug)] @@ -51,15 +51,15 @@ impl DenoPlugin { tv.install_path().join("bin/deno") } - fn test_deno(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("deno -V"); + fn test_deno(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("deno -V".into()); CmdLineRunner::new(self.deno_bin(tv)) .with_pr(pr) .arg("-V") .execute() } - fn download(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result { + fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { let http = http::Client::new()?; let url = format!( "https://github.com/denoland/deno/releases/download/v{}/deno-{}-{}.zip", @@ -78,7 +78,7 @@ impl DenoPlugin { Ok(tarball_path) } - fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { + fn install(&self, tv: &ToolVersion, pr: &dyn SingleReport, tarball_path: &Path) -> Result<()> { pr.set_message(format!("installing {}", tarball_path.display())); file::remove_all(tv.install_path())?; file::create_dir_all(tv.install_path().join("bin"))?; @@ -88,7 +88,7 @@ impl DenoPlugin { Ok(()) } - fn verify(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn verify(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { self.test_deno(tv, pr) } } @@ -115,9 +115,9 @@ impl Plugin for DenoPlugin { ToolVersionRequest::Version { .. } )); - let tarball_path = self.download(&ctx.tv, &ctx.pr)?; - self.install(&ctx.tv, &ctx.pr, &tarball_path)?; - self.verify(&ctx.tv, &ctx.pr)?; + let tarball_path = self.download(&ctx.tv, ctx.pr.as_ref())?; + self.install(&ctx.tv, ctx.pr.as_ref(), &tarball_path)?; + self.verify(&ctx.tv, ctx.pr.as_ref())?; Ok(()) } diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index a29a19c7c..569df5d40 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -12,7 +12,7 @@ use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, Toolset}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file, hash, http}; #[derive(Debug)] @@ -57,7 +57,7 @@ impl GoPlugin { tv.install_path().join("packages") } - fn install_default_packages(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn install_default_packages(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { let body = file::read_to_string(&*env::RTX_GO_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); @@ -87,15 +87,15 @@ impl GoPlugin { Ok(()) } - fn test_go(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("go version"); + fn test_go(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("go version".into()); CmdLineRunner::new(self.go_bin(tv)) .with_pr(pr) .arg("version") .execute() } - fn download(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result { + fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { let http = http::Client::new()?; let filename = format!("go{}.{}-{}.tar.gz", tv.version, platform(), arch()); let tarball_url = format!("{}/{}", &*env::RTX_GO_DOWNLOAD_MIRROR, &filename); @@ -118,7 +118,7 @@ impl GoPlugin { Ok(()) } - fn install(&self, tv: &ToolVersion, pr: &ProgressReport, tarball_path: &Path) -> Result<()> { + fn install(&self, tv: &ToolVersion, pr: &dyn SingleReport, tarball_path: &Path) -> Result<()> { let tarball = tarball_path .file_name() .unwrap_or_default() @@ -128,7 +128,7 @@ impl GoPlugin { Ok(()) } - fn verify(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn verify(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { self.test_go(tv, pr)?; self.install_default_packages(tv, pr) } @@ -150,9 +150,9 @@ impl Plugin for GoPlugin { } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { - let tarball_path = self.download(&ctx.tv, &ctx.pr)?; - self.install(&ctx.tv, &ctx.pr, &tarball_path)?; - self.verify(&ctx.tv, &ctx.pr)?; + let tarball_path = self.download(&ctx.tv, ctx.pr.as_ref())?; + self.install(&ctx.tv, ctx.pr.as_ref(), &tarball_path)?; + self.verify(&ctx.tv, ctx.pr.as_ref())?; Ok(()) } diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 3c983adb6..50ecccf7c 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -17,7 +17,7 @@ use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{env, file, hash, http}; #[derive(Debug)] @@ -114,7 +114,7 @@ impl JavaPlugin { tv.install_path().join("bin/java") } - fn test_java(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { + fn test_java(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { CmdLineRunner::new(self.java_bin(tv)) .with_pr(pr) .env("JAVA_HOME", tv.install_path()) @@ -122,7 +122,12 @@ impl JavaPlugin { .execute() } - fn download(&self, tv: &ToolVersion, pr: &ProgressReport, m: &JavaMetadata) -> Result { + fn download( + &self, + tv: &ToolVersion, + pr: &dyn SingleReport, + m: &JavaMetadata, + ) -> Result { let http = http::Client::new()?; let filename = m.url.split('/').last().unwrap(); let tarball_path = tv.download_path().join(filename); @@ -138,7 +143,7 @@ impl JavaPlugin { fn install( &self, tv: &ToolVersion, - pr: &ProgressReport, + pr: &dyn SingleReport, tarball_path: &Path, m: &JavaMetadata, ) -> Result<()> { @@ -206,8 +211,8 @@ impl JavaPlugin { Ok(()) } - fn verify(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("java -version"); + fn verify(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("java -version".into()); self.test_java(tv, pr) } @@ -288,9 +293,9 @@ impl Plugin for JavaPlugin { )); let metadata = self.tv_to_metadata(&ctx.tv)?; - let tarball_path = self.download(&ctx.tv, &ctx.pr, metadata)?; - self.install(&ctx.tv, &ctx.pr, &tarball_path, metadata)?; - self.verify(&ctx.tv, &ctx.pr)?; + let tarball_path = self.download(&ctx.tv, ctx.pr.as_ref(), metadata)?; + self.install(&ctx.tv, ctx.pr.as_ref(), &tarball_path, metadata)?; + self.verify(&ctx.tv, ctx.pr.as_ref())?; Ok(()) } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 057a73e1e..6e258ad81 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -14,7 +14,7 @@ use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::ToolVersion; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{env, file, hash, http}; #[derive(Debug)] @@ -63,7 +63,7 @@ impl NodePlugin { fn install_precompiled(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { match self.fetch_tarball( - &ctx.pr, + ctx.pr.as_ref(), &opts.binary_tarball_url, &opts.binary_tarball_path, &opts.version, @@ -87,7 +87,7 @@ impl NodePlugin { fn install_compiled(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { let tarball_name = &opts.source_tarball_name; self.fetch_tarball( - &ctx.pr, + ctx.pr.as_ref(), &opts.source_tarball_url, &opts.source_tarball_path, &opts.version, @@ -103,7 +103,7 @@ impl NodePlugin { fn fetch_tarball( &self, - pr: &ProgressReport, + pr: &dyn SingleReport, url: &Url, local: &Path, version: &str, @@ -127,7 +127,10 @@ impl NodePlugin { for p in &opts.path { cmd.prepend_path_env(p.clone()); } - cmd = cmd.with_pr(&ctx.pr).current_dir(&opts.build_dir).arg("-c"); + cmd = cmd + .with_pr(ctx.pr.as_ref()) + .current_dir(&opts.build_dir) + .arg("-c"); if let Some(cflags) = &*env::RTX_NODE_CFLAGS { cmd = cmd.env("CFLAGS", cflags); } @@ -169,7 +172,7 @@ impl NodePlugin { &self, config: &Config, tv: &ToolVersion, - pr: &ProgressReport, + pr: &dyn SingleReport, ) -> Result<()> { let body = file::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { @@ -198,8 +201,8 @@ impl NodePlugin { Ok(()) } - fn enable_default_corepack_shims(&self, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("enabling corepack shims"); + fn enable_default_corepack_shims(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("enabling corepack shims".into()); let corepack = self.corepack_path(tv); CmdLineRunner::new(corepack) .with_pr(pr) @@ -209,8 +212,8 @@ impl NodePlugin { Ok(()) } - fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("node -v"); + fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("node -v".into()); CmdLineRunner::new(self.node_path(tv)) .with_pr(pr) .arg("-v") @@ -218,8 +221,8 @@ impl NodePlugin { .execute() } - fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("npm -v"); + fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("npm -v".into()); CmdLineRunner::new(self.npm_path(tv)) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) @@ -297,12 +300,12 @@ impl Plugin for NodePlugin { } else { self.install_precompiled(ctx, &opts)?; } - self.test_node(&config, &ctx.tv, &ctx.pr)?; + self.test_node(&config, &ctx.tv, ctx.pr.as_ref())?; self.install_npm_shim(&ctx.tv)?; - self.test_npm(&config, &ctx.tv, &ctx.pr)?; - self.install_default_packages(&config, &ctx.tv, &ctx.pr)?; + self.test_npm(&config, &ctx.tv, ctx.pr.as_ref())?; + self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; if *env::RTX_NODE_COREPACK && self.corepack_path(&ctx.tv).exists() { - self.enable_default_corepack_shims(&ctx.tv, &ctx.pr)?; + self.enable_default_corepack_shims(&ctx.tv, ctx.pr.as_ref())?; } Ok(()) diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index 48303945e..41bd55c22 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -16,7 +16,7 @@ use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file}; #[derive(Debug)] @@ -114,7 +114,7 @@ impl NodeBuildPlugin { &self, config: &Config, tv: &ToolVersion, - pr: &ProgressReport, + pr: &dyn SingleReport, ) -> Result<()> { let body = file::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { @@ -143,8 +143,8 @@ impl NodeBuildPlugin { Ok(()) } - fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("node -v"); + fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("node -v".into()); CmdLineRunner::new(self.node_path(tv)) .with_pr(pr) .arg("-v") @@ -152,8 +152,8 @@ impl NodeBuildPlugin { .execute() } - fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("npm -v"); + fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("npm -v".into()); CmdLineRunner::new(self.npm_path(tv)) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) @@ -256,9 +256,9 @@ impl Plugin for NodeBuildPlugin { fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let config = Config::get(); self.install_node_build()?; - ctx.pr.set_message("running node-build"); + ctx.pr.set_message("running node-build".into()); let mut cmd = CmdLineRunner::new(self.node_build_bin()) - .with_pr(&ctx.pr) + .with_pr(ctx.pr.as_ref()) .env("NODE_BUILD_MIRROR_URL", RTX_NODE_MIRROR_URL.to_string()) .envs(&config.env) .arg(ctx.tv.version.as_str()); @@ -286,10 +286,10 @@ impl Plugin for NodeBuildPlugin { cmd = cmd.arg("--verbose"); } cmd.arg(&ctx.tv.install_path()).execute()?; - self.test_node(&config, &ctx.tv, &ctx.pr)?; + self.test_node(&config, &ctx.tv, ctx.pr.as_ref())?; self.install_npm_shim(&ctx.tv)?; - self.test_npm(&config, &ctx.tv, &ctx.pr)?; - self.install_default_packages(&config, &ctx.tv, &ctx.pr)?; + self.test_npm(&config, &ctx.tv, ctx.pr.as_ref())?; + self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; Ok(()) } } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 655a6f6f5..d4b980da8 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -12,7 +12,7 @@ use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file, http}; #[derive(Debug)] @@ -90,12 +90,12 @@ impl PythonPlugin { &self, config: &Config, tv: &ToolVersion, - pr: &ProgressReport, + pr: &dyn SingleReport, ) -> Result<()> { if !env::RTX_PYTHON_DEFAULT_PACKAGES_FILE.exists() { return Ok(()); } - pr.set_message("installing default packages"); + pr.set_message("installing default packages".into()); CmdLineRunner::new(tv.install_path().join("bin/python")) .with_pr(pr) .arg("-m") @@ -112,7 +112,7 @@ impl PythonPlugin { &self, config: &Config, tv: &ToolVersion, - pr: Option<&ProgressReport>, + pr: Option<&dyn SingleReport>, ) -> Result> { if let Some(virtualenv) = tv.opts.get("virtualenv") { let mut virtualenv: PathBuf = file::replace_path(Path::new(virtualenv)); @@ -155,8 +155,8 @@ impl PythonPlugin { Ok(()) } - fn test_python(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("python --version"); + fn test_python(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("python --version".into()); CmdLineRunner::new(self.python_path(tv)) .arg("--version") .envs(&config.env) @@ -187,9 +187,9 @@ impl Plugin for PythonPlugin { if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { return Err(eyre!("Ref versions not supported for python")); } - ctx.pr.set_message("Running python-build"); + ctx.pr.set_message("Running python-build".into()); let mut cmd = CmdLineRunner::new(self.python_build_bin()) - .with_pr(&ctx.pr) + .with_pr(ctx.pr.as_ref()) .arg(ctx.tv.version.as_str()) .arg(&ctx.tv.install_path()) .envs(&config.env); @@ -216,11 +216,11 @@ impl Plugin for PythonPlugin { } } cmd.execute()?; - self.test_python(&config, &ctx.tv, &ctx.pr)?; - if let Err(e) = self.get_virtualenv(&config, &ctx.tv, Some(&ctx.pr)) { + self.test_python(&config, &ctx.tv, ctx.pr.as_ref())?; + if let Err(e) = self.get_virtualenv(&config, &ctx.tv, Some(ctx.pr.as_ref())) { warn!("failed to get virtualenv: {e}"); } - self.install_default_packages(&config, &ctx.tv, &ctx.pr)?; + self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; Ok(()) } diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 916877180..4dad31a10 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -15,7 +15,7 @@ use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file, http}; #[derive(Debug)] @@ -172,7 +172,7 @@ impl RubyPlugin { &self, config: &Config, tv: &ToolVersion, - pr: &ProgressReport, + pr: &dyn SingleReport, ) -> Result<()> { let body = file::read_to_string(&*env::RTX_RUBY_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { @@ -197,8 +197,8 @@ impl RubyPlugin { Ok(()) } - fn test_ruby(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("ruby -v"); + fn test_ruby(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("ruby -v".into()); CmdLineRunner::new(self.ruby_path(tv)) .with_pr(pr) .arg("-v") @@ -206,8 +206,8 @@ impl RubyPlugin { .execute() } - fn test_gem(&self, config: &Config, tv: &ToolVersion, pr: &ProgressReport) -> Result<()> { - pr.set_message("gem -v"); + fn test_gem(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { + pr.set_message("gem -v".into()); CmdLineRunner::new(self.gem_path(tv)) .with_pr(pr) .arg("-v") @@ -246,7 +246,7 @@ impl RubyPlugin { &'a self, config: &'a Config, tv: &ToolVersion, - pr: &'a ProgressReport, + pr: &'a dyn SingleReport, ) -> Result { let cmd = if *env::RTX_RUBY_INSTALL { CmdLineRunner::new(self.ruby_install_bin()).args(self.install_args_ruby_install(tv)?) @@ -354,14 +354,15 @@ impl Plugin for RubyPlugin { ToolVersionRequest::Version { .. } )); - ctx.pr.set_message("running ruby-build"); + ctx.pr.set_message("running ruby-build".into()); let config = Config::get(); - self.install_cmd(&config, &ctx.tv, &ctx.pr)?.execute()?; + self.install_cmd(&config, &ctx.tv, ctx.pr.as_ref())? + .execute()?; - self.test_ruby(&config, &ctx.tv, &ctx.pr)?; + self.test_ruby(&config, &ctx.tv, ctx.pr.as_ref())?; self.install_rubygems_hook(&ctx.tv)?; - self.test_gem(&config, &ctx.tv, &ctx.pr)?; - self.install_default_gems(&config, &ctx.tv, &ctx.pr)?; + self.test_gem(&config, &ctx.tv, ctx.pr.as_ref())?; + self.install_default_gems(&config, &ctx.tv, ctx.pr.as_ref())?; Ok(()) } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index bf16c670b..cc6fe6b13 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -29,7 +29,7 @@ use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager, HTTP use crate::timeout::run_with_timeout; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::ui::prompt; use crate::{dirs, env, file, http}; @@ -100,7 +100,7 @@ impl ExternalPlugin { .ok_or_else(|| eyre!("No repository found for plugin {}", self.name)) } - fn install(&self, pr: &ProgressReport) -> Result<()> { + fn install(&self, pr: &dyn SingleReport) -> Result<()> { let config = Config::get(); let repository = self.get_repo_url(&config)?; let (repo_url, repo_ref) = Git::split_url_and_ref(&repository); @@ -465,9 +465,9 @@ impl Plugin for ExternalPlugin { let _mpr = MultiProgressReport::new(); let mpr = mpr.unwrap_or(&_mpr); let mut pr = mpr.add(); - self.decorate_progress_bar(&mut pr, None); + self.decorate_progress_bar(pr.as_mut(), None); let _lock = self.get_lock(&self.plugin_path, force)?; - self.install(&pr) + self.install(pr.as_ref()) } fn update(&self, gitref: Option) -> Result<()> { @@ -493,11 +493,11 @@ impl Plugin for ExternalPlugin { Ok(()) } - fn uninstall(&self, pr: &ProgressReport) -> Result<()> { + fn uninstall(&self, pr: &dyn SingleReport) -> Result<()> { if !self.is_installed() { return Ok(()); } - pr.set_message("uninstalling"); + pr.set_message("uninstalling".into()); let rmdir = |dir: &Path| { if !dir.exists() { @@ -635,13 +635,13 @@ impl Plugin for ExternalPlugin { sm.prepend_path(p); } - let run_script = |script| sm.run_by_line(script, &ctx.pr); + let run_script = |script| sm.run_by_line(script, ctx.pr.as_ref()); if sm.script_exists(&Download) { - ctx.pr.set_message("downloading"); + ctx.pr.set_message("downloading".into()); run_script(&Download)?; } - ctx.pr.set_message("installing"); + ctx.pr.set_message("installing".into()); run_script(&Install)?; Ok(()) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 02e11df4c..71549dc39 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -25,7 +25,7 @@ use crate::lock_file::LockFile; use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::{ProgressReport, PROG_TEMPLATE}; +use crate::ui::progress_report::{SingleReport, PROG_TEMPLATE}; use crate::{dirs, file, http}; pub mod core; @@ -158,10 +158,10 @@ pub trait Plugin: Debug + Send + Sync { fn update(&self, _git_ref: Option) -> Result<()> { Ok(()) } - fn uninstall(&self, _pr: &ProgressReport) -> Result<()> { + fn uninstall(&self, _pr: &dyn SingleReport) -> Result<()> { Ok(()) } - fn purge(&self, pr: &ProgressReport) -> Result<()> { + fn purge(&self, pr: &dyn SingleReport) -> Result<()> { rmdir(&self.installs_path(), pr)?; rmdir(&self.cache_path(), pr)?; rmdir(&self.downloads_path(), pr)?; @@ -188,12 +188,12 @@ pub trait Plugin: Debug + Send + Sync { let settings = Settings::try_get()?; if self.is_version_installed(&ctx.tv) { if ctx.force { - self.uninstall_version(&ctx.tv, &ctx.pr, false)?; + self.uninstall_version(&ctx.tv, ctx.pr.as_ref(), false)?; } else { return Ok(()); } } - self.decorate_progress_bar(&mut ctx.pr, Some(&ctx.tv)); + self.decorate_progress_bar(ctx.pr.as_mut(), Some(&ctx.tv)); let _lock = self.get_lock(&ctx.tv.install_path(), ctx.force)?; self.create_install_dirs(&ctx.tv)?; @@ -214,13 +214,18 @@ pub trait Plugin: Debug + Send + Sync { if let Err(err) = file::remove_file(self.incomplete_file_path(&ctx.tv)) { debug!("error removing incomplete file: {:?}", err); } - ctx.pr.set_message(""); + ctx.pr.set_message("".into()); ctx.pr.finish(); Ok(()) } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()>; - fn uninstall_version(&self, tv: &ToolVersion, pr: &ProgressReport, dryrun: bool) -> Result<()> { + fn uninstall_version( + &self, + tv: &ToolVersion, + pr: &dyn SingleReport, + dryrun: bool, + ) -> Result<()> { pr.set_message(format!("uninstall {tv}")); if !dryrun { @@ -304,13 +309,13 @@ pub trait Plugin: Debug + Send + Sync { let _ = remove_all_with_warning(tv.download_path()); } } - fn decorate_progress_bar(&self, pr: &mut ProgressReport, tv: Option<&ToolVersion>) { + fn decorate_progress_bar(&self, pr: &mut dyn SingleReport, tv: Option<&ToolVersion>) { pr.set_style(PROG_TEMPLATE.clone()); let tool = match tv { Some(tv) => tv.to_string(), None => self.name().to_string(), }; - pr.set_prefix(format!( + pr.set_prefix(&format!( "{} {} ", style("rtx").dim().for_stderr(), style(tool).cyan().for_stderr(), @@ -361,7 +366,7 @@ fn find_match_in_list(list: &[String], query: &str) -> Option { }; v } -fn rmdir(dir: &Path, pr: &ProgressReport) -> Result<()> { +fn rmdir(dir: &Path, pr: &dyn SingleReport) -> Result<()> { if !dir.exists() { return Ok(()); } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index e156a2fe0..0e6aed2c2 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -16,7 +16,7 @@ use crate::errors::Error; use crate::errors::Error::ScriptFailed; use crate::fake_asdf::get_path_with_fake_asdf; use crate::file::{basename, display_path}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::SingleReport; use crate::{dirs, env}; #[derive(Debug, Clone)] @@ -174,7 +174,7 @@ impl ScriptManager { .wrap_err_with(|| ScriptFailed(display_path(&self.get_script_path(script)), None)) } - pub fn run_by_line(&self, script: &Script, pr: &ProgressReport) -> Result<()> { + pub fn run_by_line(&self, script: &Script, pr: &dyn SingleReport) -> Result<()> { let cmd = CmdLineRunner::new(self.get_script_path(script)) .with_pr(pr) .env_clear() diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 702a558b7..0bfdd774b 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,8 +1,8 @@ use crate::config::Settings; use console::style; -use indicatif::MultiProgress; +use indicatif::{MultiProgress, ProgressBar}; -use crate::ui::progress_report::ProgressReport; +use crate::ui::progress_report::{ProgressReport, QuietReport, SingleReport, VerboseReport}; #[derive(Debug)] pub struct MultiProgressReport { @@ -22,14 +22,11 @@ impl MultiProgressReport { quiet: settings.quiet, } } - pub fn add(&self) -> ProgressReport { + pub fn add(&self) -> Box { match &self.mp { - Some(mp) => { - let mut pr = ProgressReport::new(false, self.quiet); - pr.pb = Some(mp.add(pr.pb.unwrap())); - pr - } - None => ProgressReport::new(true, self.quiet), + _ if self.quiet => Box::new(QuietReport::new()), + Some(mp) => Box::new(ProgressReport::new(mp.add(ProgressBar::new(0)))), + None => Box::new(VerboseReport::new()), } } pub fn suspend R, R>(&self, f: F) -> R { @@ -51,14 +48,6 @@ impl MultiProgressReport { _ => (), } } - // pub fn clear(&self) { - // match &self.mp { - // Some(mp) => { - // let _ = mp.clear(); - // }, - // None => () - // } - // } } #[cfg(test)] @@ -71,8 +60,8 @@ mod tests { let pr = mpr.add(); pr.set_style(indicatif::ProgressStyle::with_template("").unwrap()); pr.enable_steady_tick(); - pr.finish_with_message("test"); - pr.println(""); - pr.set_message("test"); + pr.finish_with_message("test".into()); + pr.println("".into()); + pr.set_message("test".into()); } } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index db1d05168..8389fe683 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,15 +1,20 @@ -use std::borrow::Cow; use std::time::Duration; use console::style; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; -#[derive(Debug)] -pub struct ProgressReport { - pub pb: Option, - prefix: String, - quiet: bool, +pub trait SingleReport: Send + Sync { + fn enable_steady_tick(&self) {} + fn set_prefix(&mut self, prefix: &str); + fn prefix(&self) -> String; + fn set_style(&self, _style: ProgressStyle) {} + fn set_message(&self, _message: String) {} + fn println(&self, _message: String) {} + fn warn(&self, _message: String) {} + fn error(&self, _message: String) {} + fn finish(&self) {} + fn finish_with_message(&self, _message: String) {} } pub static PROG_TEMPLATE: Lazy = Lazy::new(|| { @@ -17,7 +22,7 @@ pub static PROG_TEMPLATE: Lazy = Lazy::new(|| { .unwrap() }); -pub static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { +static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { let tmpl = format!( "{{prefix}}{{wide_msg}} {} {{elapsed:3.dim.italic}}", style("✓").bright().green().for_stderr() @@ -25,7 +30,7 @@ pub static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { ProgressStyle::with_template(tmpl.as_str()).unwrap() }); -pub static ERROR_TEMPLATE: Lazy = Lazy::new(|| { +static ERROR_TEMPLATE: Lazy = Lazy::new(|| { let tmpl = format!( "{{prefix:.red}}{{wide_msg}} {} {{elapsed:3.dim.italic}}", style("✗").red().for_stderr() @@ -33,111 +38,111 @@ pub static ERROR_TEMPLATE: Lazy = Lazy::new(|| { ProgressStyle::with_template(tmpl.as_str()).unwrap() }); +#[derive(Debug)] +pub struct ProgressReport { + pub pb: ProgressBar, +} + impl ProgressReport { - pub fn new(verbose: bool, quiet: bool) -> ProgressReport { - let pb = match verbose { - true => None, - false => Some(ProgressBar::new(0)), - }; - ProgressReport { - pb, - prefix: String::new(), - quiet, - } + pub fn new(pb: ProgressBar) -> ProgressReport { + ProgressReport { pb } } +} - pub fn enable_steady_tick(&self) { - match &self.pb { - Some(pb) => pb.enable_steady_tick(Duration::from_millis(250)), - None => (), - } +impl SingleReport for ProgressReport { + fn enable_steady_tick(&self) { + self.pb.enable_steady_tick(Duration::from_millis(250)); } - pub fn set_prefix(&mut self, prefix: impl Into>) { - match &self.pb { - Some(pb) => pb.set_prefix(prefix), - None => { - self.prefix = prefix.into().to_string(); - } - } + fn set_prefix(&mut self, prefix: &str) { + self.pb.set_prefix(prefix.to_string()); } - pub fn prefix(&self) -> String { - match &self.pb { - Some(pb) => pb.prefix(), - None => self.prefix.clone(), - } + fn prefix(&self) -> String { + self.pb.prefix() } - pub fn set_style(&self, style: ProgressStyle) { - match &self.pb { - Some(pb) => { - pb.set_style(style); - pb.set_prefix(console::style("rtx").dim().for_stderr().to_string()); - } - None => (), - } + fn set_style(&self, style: ProgressStyle) { + self.pb.set_style(style); + self.pb + .set_prefix(console::style("rtx").dim().for_stderr().to_string()); } - pub fn set_message>(&self, message: S) { - match &self.pb { - Some(pb) => pb.set_message(message.as_ref().replace('\r', "")), - None if !self.quiet => eprintln!("{}", message.as_ref()), - _ => (), - } + fn set_message(&self, message: String) { + self.pb.set_message(message.replace('\r', "")); } - pub fn println>(&self, message: S) { - match &self.pb { - Some(pb) => pb.println(message), - None if !self.quiet => eprintln!("{}", message.as_ref()), - _ => (), - } + fn println(&self, message: String) { + self.pb.println(message); } - pub fn warn>(&self, message: S) { - match &self.pb { - Some(pb) => pb.println(format!("{} {}", style("[WARN]").yellow(), message.as_ref())), - None if !self.quiet => eprintln!("{}", message.as_ref()), - _ => (), - } + fn warn(&self, message: String) { + self.pb + .println(format!("{} {}", style("[WARN]").yellow(), message)); } - pub fn error>(&self, message: S) { - match &self.pb { - Some(pb) => { - self.set_message(format!( - "{} {}", - style("[ERROR]").red().for_stderr(), - message.as_ref() - )); - pb.set_style(ERROR_TEMPLATE.clone()); - pb.finish() - } - None => (), - } + fn error(&self, message: String) { + self.set_message(format!( + "{} {}", + style("[ERROR]").red().for_stderr(), + message + )); + self.pb.set_style(ERROR_TEMPLATE.clone()); + self.pb.finish(); } - pub fn finish(&self) { - match &self.pb { - Some(pb) => { - pb.set_style(SUCCESS_TEMPLATE.clone()); - pb.finish() - } - None => (), + fn finish(&self) { + self.pb.set_style(SUCCESS_TEMPLATE.clone()); + self.pb.finish() + } + fn finish_with_message(&self, message: String) { + self.pb.set_style(SUCCESS_TEMPLATE.clone()); + self.pb.finish_with_message(message); + } +} + +pub struct QuietReport { + prefix: String, +} +impl QuietReport { + pub fn new() -> QuietReport { + QuietReport { + prefix: String::new(), } } - pub fn finish_with_message(&self, message: impl Into>) { - match &self.pb { - Some(pb) => { - pb.set_style(SUCCESS_TEMPLATE.clone()); - pb.finish_with_message(message); - } - None if !self.quiet => eprintln!("{}", message.into()), - _ => (), +} +impl SingleReport for QuietReport { + fn set_prefix(&mut self, prefix: &str) { + self.prefix = prefix.to_string(); + } + + fn prefix(&self) -> String { + self.prefix.clone() + } +} +pub struct VerboseReport { + prefix: String, +} +impl VerboseReport { + pub fn new() -> VerboseReport { + VerboseReport { + prefix: String::new(), } } - // pub fn clear(&self) { - // match &self.pb { - // Some(pb) => pb.finish_and_clear(), - // None => (), - // } - // } +} +impl SingleReport for VerboseReport { + fn set_prefix(&mut self, prefix: &str) { + self.prefix = prefix.to_string(); + } + + fn prefix(&self) -> String { + self.prefix.clone() + } + + fn set_message(&self, message: String) { + eprintln!("{}", message); + } + fn println(&self, message: String) { + eprintln!("{}", message); + } + fn warn(&self, message: String) { + eprintln!("{}", message); + } } #[cfg(test)] @@ -146,19 +151,28 @@ mod tests { #[test] fn test_progress_report() { - let mut pr = ProgressReport::new(false, false); + let mut pr = ProgressReport::new(ProgressBar::new(0)); pr.set_prefix("prefix"); assert_eq!(pr.prefix(), "prefix"); - pr.set_message("message"); - pr.finish_with_message("message"); + pr.set_message("message".into()); + pr.finish_with_message("message".into()); } #[test] fn test_progress_report_verbose() { - let mut pr = ProgressReport::new(true, false); + let mut pr = VerboseReport::new(); + pr.set_prefix("prefix"); + assert_eq!(pr.prefix(), "prefix"); + pr.set_message("message".into()); + pr.finish_with_message("message".into()); + } + + #[test] + fn test_progress_report_quiet() { + let mut pr = QuietReport::new(); pr.set_prefix("prefix"); assert_eq!(pr.prefix(), "prefix"); - pr.set_message("message"); - pr.finish_with_message("message"); + pr.set_message("message".into()); + pr.finish_with_message("message".into()); } } From 16921e3245849abc531b5783386128b31c1dc400 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 05:46:26 -0600 Subject: [PATCH 1324/1891] chore: Release rtx-cli version 2023.12.27 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 4 +--- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 973ff1f97..962bd02c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1791,7 +1791,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.26" +version = "2023.12.27" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 7a93369bb..158316ff5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.26" +version = "2023.12.27" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 731854112..52c5aba70 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.26 +rtx 2023.12.27 ``` Hook rtx into your shell (pick the right one for your shell): @@ -355,7 +355,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.26/rtx-v2023.12.26-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.27/rtx-v2023.12.27-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index e7be01434..78bb5a5f8 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.26"; + version = "2023.12.27"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9effc2b93..456f904ca 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.26 +Version: 2023.12.27 Release: 1 URL: https://github.com/jdx/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 5a9a9491a..7cecda06a 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,7 +23,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 714] = [ +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 712] = [ // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), @@ -96,7 +96,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 714] = [ ("btrace", "https://github.com/joschi/asdf-btrace.git"), ("buf", "https://github.com/truepay/asdf-buf.git"), ("buildpack", "https://github.com/johnlayton/asdf-buildpack.git"), - ("bun", "https://github.com/cometkim/asdf-bun.git"), ("bundler", "https://github.com/jonathanmorley/asdf-bundler.git"), ("caddy", "https://github.com/salasrod/asdf-caddy.git"), ("calicoctl", "https://github.com/TheCubicleJockey/asdf-calicoctl.git"), @@ -165,7 +164,6 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 714] = [ ("dbmate", "https://github.com/juusujanar/asdf-dbmate.git"), ("deck", "https://github.com/nutellinoit/asdf-deck.git"), ("delta", "https://github.com/andweeb/asdf-delta.git"), - ("deno", "https://github.com/asdf-community/asdf-deno.git"), ("dep", "https://github.com/paxosglobal/asdf-dep.git"), ("depot", "https://github.com/depot/asdf-depot.git"), ("desk", "https://github.com/endorama/asdf-desk.git"), From 5a314a62de324fb8a78d6e004a9868e12eb49630 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 06:38:01 -0600 Subject: [PATCH 1325/1891] trust: find .rtx.local.toml files (#1183) Fixes #1050 --- justfile | 4 -- .../rtx__cli__trust__tests__trust-4.snap | 5 ++ src/cli/trust.rs | 48 +++++++++++++++---- src/config/config_file/tool_versions.rs | 11 +++-- src/config/mod.rs | 2 +- 5 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap diff --git a/justfile b/justfile index 5ae0dbac6..f6dd4ece7 100644 --- a/justfile +++ b/justfile @@ -64,15 +64,11 @@ test-coverage: if [[ "${TEST_TRANCHE:-}" == 0 ]]; then echo "::group::Unit tests" cargo test --all-features - echo "::group::Trust" - rtx trust echo "::group::render-help render-completions render-mangen" just render-help render-completions render-mangen echo "::group::Implode" rtx implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then - echo "::group::Trust" - rtx trust echo "::group::Self update" rtx self-update -fy fi diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap new file mode 100644 index 000000000..f5ac8a47f --- /dev/null +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/trust.rs +expression: output +--- +untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/trust.rs b/src/cli/trust.rs index 177b5612f..0c25b8e50 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -1,9 +1,10 @@ +use std::collections::BTreeMap; use std::path::PathBuf; use clap::ValueHint; use color_eyre::eyre::Result; -use crate::cli::local; +use crate::config; use crate::config::config_file; /// Marks a config file as trusted @@ -29,19 +30,47 @@ pub struct Trust { impl Trust { pub fn run(self) -> Result<()> { - let path = match &self.config_file { - Some(filename) => PathBuf::from(filename), - None => local::get_parent_path()?, - }; if self.untrust { - config_file::untrust(&path)?; - rtxprintln!("untrusted {}", &path.canonicalize()?.display()); + self.untrust() } else { - config_file::trust(&path)?; - rtxprintln!("trusted {}", &path.canonicalize()?.display()); + self.trust() } + } + fn untrust(&self) -> Result<()> { + let path = match &self.config_file { + Some(filename) => PathBuf::from(filename), + None => match self.get_next_trusted() { + Some(path) => path, + None => bail!("No trusted config files found."), + }, + }; + config_file::untrust(&path)?; + rtxprintln!("untrusted {}", &path.canonicalize()?.display()); Ok(()) } + fn trust(&self) -> Result<()> { + let path = match &self.config_file { + Some(filename) => PathBuf::from(filename), + None => match self.get_next_untrusted() { + Some(path) => path, + None => bail!("No untrusted config files found."), + }, + }; + config_file::trust(&path)?; + rtxprintln!("trusted {}", &path.canonicalize()?.display()); + Ok(()) + } + + fn get_next_trusted(&self) -> Option { + config::load_config_filenames(&BTreeMap::new()) + .into_iter() + .find(|p| config_file::is_trusted(p)) + } + fn get_next_untrusted(&self) -> Option { + config::load_config_filenames(&BTreeMap::new()) + .into_iter() + .find(|p| !config_file::is_trusted(p)) + } } static AFTER_LONG_HELP: &str = color_print::cstr!( @@ -63,5 +92,6 @@ mod tests { assert_cli_snapshot!("trust"); assert_cli_snapshot!("trust", "--untrust"); assert_cli_snapshot!("trust", ".test-tool-versions"); + assert_cli_snapshot!("trust", "--untrust", ".test-tool-versions"); } } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 818bd8e8c..48b7ae445 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -1,13 +1,14 @@ use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; +use crate::config::config_file; use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; use indexmap::IndexMap; use itertools::Itertools; use tera::Context; -use crate::config::config_file::{is_trusted, ConfigFile, ConfigFileType}; +use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::file; use crate::file::display_path; @@ -56,7 +57,7 @@ impl ToolVersions { pub fn parse_str(s: &str, path: PathBuf) -> Result { let mut cf = Self::init(&path); let dir = path.parent().unwrap(); - let s = if is_trusted(&path) { + let s = if config_file::is_trusted(&path) { get_tera(dir).render_str(s, &cf.context)? } else { s.to_string() @@ -202,7 +203,7 @@ pub(crate) mod tests { use insta::{assert_display_snapshot, assert_snapshot}; use pretty_assertions::assert_eq; - use crate::dirs; + use crate::{assert_cli, dirs}; use super::*; @@ -247,7 +248,9 @@ pub(crate) mod tests { python {{exec(command='echo 3.11.0')}} "}; let path = dirs::CURRENT.join(".test-tool-versions"); - let tv = ToolVersions::parse_str(orig, path).unwrap(); + assert_cli!("trust", path.to_string_lossy()); + let tv = ToolVersions::parse_str(orig, path.clone()).unwrap(); + assert_cli!("trust", "--untrust", path.to_string_lossy()); assert_snapshot!(tv.dump(), @r###" ruby 3.0.5 python 3.11.0 diff --git a/src/config/mod.rs b/src/config/mod.rs index d4c471e3a..917674713 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -334,7 +334,7 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap>) -> Vec { +pub fn load_config_filenames(legacy_filenames: &BTreeMap>) -> Vec { let mut filenames = legacy_filenames.keys().cloned().collect_vec(); filenames.push(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone()); filenames.push(env::RTX_DEFAULT_CONFIG_FILENAME.clone()); From f4b8c347af6251e0e94949f75fac3426185315cb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 07:59:35 -0600 Subject: [PATCH 1326/1891] shims: fix bug that displayed debug info if `-v` or `-vv` was passed (#1184) * shims: fix bug that displayed debug info if `-v` or `-vv` was passed * lint * lint * lint --- src/cli/version.rs | 7 ++++--- src/env.rs | 7 ++++++- src/main.rs | 7 +++---- src/shims.rs | 8 ++++---- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index babb777ee..e1bf552e9 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -9,7 +9,7 @@ use versions::Versioning; use crate::build_time::{built_info, BUILD_TIME}; use crate::cli::self_update::SelfUpdate; -use crate::env::CI; +use crate::env; use crate::file::modified_duration; use crate::{dirs, duration, file}; @@ -50,7 +50,8 @@ impl Version { } } -pub fn print_version_if_requested(args: &[String]) { +pub fn print_version_if_requested() { + let args = env::ARGS.read().unwrap(); if args.len() == 2 && (args[0] == "rtx" || args[0].ends_with("/rtx")) { let cmd = &args[1].to_lowercase(); if cmd == "version" || cmd == "-v" || cmd == "--version" { @@ -66,7 +67,7 @@ fn show_version() { } fn show_latest() { - if *CI { + if *env::CI { return; } if let Some(latest) = check_for_new_version(duration::DAILY) { diff --git a/src/env.rs b/src/env.rs index ce1767bbf..71e0528bc 100644 --- a/src/env.rs +++ b/src/env.rs @@ -49,6 +49,10 @@ pub static RTX_EXE: Lazy = Lazy::new(|| { .or_else(|| current_exe().ok()) .unwrap_or_else(|| "rtx".into()) }); +pub static RTX_BIN_NAME: Lazy = Lazy::new(|| { + let arg0 = &ARGS.read().unwrap()[0]; + arg0.rsplit_once('/').unwrap_or(("", &arg0)).1.to_string() +}); pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { @@ -349,7 +353,8 @@ fn log_level() -> LevelFilter { } let args = ARGS.read().unwrap(); for (i, arg) in args.iter().enumerate() { - if arg == "--" { + // stop parsing after "--" or if we're executing as a shim + if arg == "--" || &*RTX_BIN_NAME != "rtx" { break; } if let Some(("--log-level", level)) = arg.split_once('=') { diff --git a/src/main.rs b/src/main.rs index 6d766d7af..059ba9964 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,18 +80,17 @@ fn main() -> Result<()> { } fn run() -> Result<()> { - let args = env::ARGS.read().unwrap(); // show version before loading config in case of error - cli::version::print_version_if_requested(&args); + cli::version::print_version_if_requested(); migrate::run(); let config = Config::try_get()?; - shims::handle_shim(&config, &args)?; + shims::handle_shim(&config)?; if config.should_exit_early { return Ok(()); } let cli = Cli::new_with_external_commands(&config); - cli.run(&args) + cli.run(&env::ARGS.read().unwrap()) } fn handle_ctrlc() { diff --git a/src/shims.rs b/src/shims.rs index c5fc75be5..5aa47db0b 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(config: &Config, args: &[String]) -> Result<()> { - let (_, bin_name) = args[0].rsplit_once('/').unwrap_or(("", &args[0])); - if bin_name == "rtx" { +pub fn handle_shim(config: &Config) -> Result<()> { + if *env::RTX_BIN_NAME == "rtx" { return Ok(()); } + let args = env::ARGS.read().unwrap(); let mut args: Vec = args.iter().map(OsString::from).collect(); - args[0] = which_shim(config, bin_name)?.into(); + args[0] = which_shim(config, &env::RTX_BIN_NAME)?.into(); let exec = Exec { tool: vec![], c: None, From c778555db3a02cd83fec79c2e6fc4c302037376c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 11:06:21 -0600 Subject: [PATCH 1327/1891] plugin-update: update in parallel (#1186) * plugin-update: update in parallel * lint * Commit from GitHub Actions (test) * lint --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- README.md | 11 +++-- completions/_rtx | 1 + completions/rtx.bash | 10 +++- completions/rtx.fish | 1 + src/cli/plugins/uninstall.rs | 3 +- src/cli/plugins/update.rs | 31 ++++++++---- src/cli/prune.rs | 6 +-- src/cli/uninstall.rs | 4 +- src/cli/upgrade.rs | 9 ++-- src/config/settings.rs | 2 +- src/plugins/core/go.rs | 2 +- src/plugins/external_plugin.rs | 40 ++++++++++----- src/plugins/mod.rs | 25 ++-------- src/plugins/script_manager.rs | 19 +------ src/toolset/mod.rs | 4 +- src/ui/multi_progress_report.rs | 25 +++++++--- src/ui/progress_report.rs | 87 +++++++-------------------------- 17 files changed, 129 insertions(+), 151 deletions(-) diff --git a/README.md b/README.md index 52c5aba70..557626e0f 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ v20.0.0 - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) - [`rtx plugins ls-remote [OPTIONS]`](#rtx-plugins-ls-remote-options) - [`rtx plugins uninstall [OPTIONS] [PLUGIN]...`](#rtx-plugins-uninstall-options-plugin) - - [`rtx plugins update [PLUGIN]...`](#rtx-plugins-update-plugin) + - [`rtx plugins update [OPTIONS] [PLUGIN]...`](#rtx-plugins-update-options-plugin) - [`rtx prune [OPTIONS] [PLUGIN]...`](#rtx-prune-options-plugin) - [`rtx reshim`](#rtx-reshim) - [`rtx self-update [OPTIONS] [VERSION]`](#rtx-self-update-options-version) @@ -2386,19 +2386,24 @@ Examples: $ rtx uninstall node ``` -### `rtx plugins update [PLUGIN]...` +### `rtx plugins update [OPTIONS] [PLUGIN]...` ```text Updates a plugin to the latest version note: this updates the plugin itself, not the runtime versions -Usage: plugins update [PLUGIN]... +Usage: plugins update [OPTIONS] [PLUGIN]... Arguments: [PLUGIN]... Plugin(s) to update +Options: + -j, --jobs + Number of jobs to run in parallel + Default: 4 + Examples: $ rtx plugins update # update all plugins $ rtx plugins update node # update only node diff --git a/completions/_rtx b/completions/_rtx index 331302757..a680c9b46 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -466,6 +466,7 @@ __rtx_plugins_uninstall_cmd() { __rtx_plugins_update_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ + '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' diff --git a/completions/rtx.bash b/completions/rtx.bash index bfb1a55bf..9774d21cd 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2527,12 +2527,20 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-a -q -v -y -h --all --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." + opts="-j -q -v -y -h --jobs --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 3687ef0f4..43aa39bb4 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -193,6 +193,7 @@ complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -a "(__rtx_plugins)" - complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -s p -l purge -d 'Also remove the plugin'\''s installs, downloads, and cache' # plugins update +complete -kxc rtx -n "$fssf plugins; and $fssf update" -s j -l jobs -d 'Number of jobs to run in parallel' complete -kxc rtx -n "$fssf plugins; and $fssf update" -a "(__rtx_plugins)" -d 'Plugin(s) to update' diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index b3c3e1454..f676bdd70 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -51,8 +51,7 @@ impl PluginsUninstall { ) -> Result<()> { match config.get_or_create_plugin(plugin_name) { plugin if plugin.is_installed() => { - let mut pr = mpr.add(); - plugin.decorate_progress_bar(pr.as_mut(), None); + let pr = mpr.add(&style(plugin.name()).blue().for_stderr().to_string()); plugin.uninstall(pr.as_ref())?; if self.purge { plugin.purge(pr.as_ref())?; diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 6ef8f56a9..6108ab26a 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,8 +1,11 @@ use color_eyre::eyre::Result; +use console::style; +use rayon::prelude::*; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::plugins::{unalias_plugin, PluginName}; +use crate::ui::multi_progress_report::MultiProgressReport; /// Updates a plugin to the latest version /// @@ -14,9 +17,10 @@ pub struct Update { #[clap()] plugin: Option>, - /// Update all plugins - #[clap(long, short = 'a', conflicts_with = "plugin", hide = true)] - all: bool, + /// Number of jobs to run in parallel + /// Default: 4 + #[clap(long, short, verbatim_doc_comment)] + jobs: Option, } impl Update { @@ -41,11 +45,20 @@ impl Update { .collect::>(), }; - for (plugin, ref_) in plugins { - rtxprintln!("updating plugin {plugin}"); - plugin.update(ref_)?; - } - Ok(()) + // let queue = Mutex::new(plugins); + let settings = Settings::try_get()?; + let mpr = MultiProgressReport::new(); + rayon::ThreadPoolBuilder::new() + .num_threads(self.jobs.unwrap_or(settings.jobs)) + .build()? + .install(|| { + plugins.into_par_iter().for_each(|(plugin, ref_)| { + let prefix = format!("plugin:{}", style(plugin.name()).blue().for_stderr()); + let pr = mpr.add(&prefix); + plugin.update(pr.as_ref(), ref_).unwrap(); + }); + Ok(()) + }) } } diff --git a/src/cli/prune.rs b/src/cli/prune.rs index a1b63840e..4eec46c3d 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -57,12 +57,12 @@ impl Prune { let settings = Settings::try_get()?; let mpr = MultiProgressReport::new(); for (p, tv) in to_delete { - let mut pr = mpr.add(); + let mut prefix = format!("{}", style(&tv).cyan().for_stderr()); if self.dry_run { - pr.set_prefix(&format!("{} {} ", pr.prefix(), style("[dryrun]").bold())); + prefix = format!("{} {} ", prefix, style("[dryrun]").bold()); } + let pr = mpr.add(&prefix); if self.dry_run || settings.yes || prompt::confirm(&format!("remove {} ?", &tv))? { - p.decorate_progress_bar(pr.as_mut(), Some(&tv)); p.uninstall_version(&tv, pr.as_ref(), self.dry_run)?; pr.finish(); } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 2581c2ae0..804326c2f 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -52,8 +52,8 @@ impl Uninstall { continue; } - let mut pr = mpr.add(); - plugin.decorate_progress_bar(pr.as_mut(), Some(&tv)); + let prefix = format!("{}", style(&tv).cyan().for_stderr()); + let pr = mpr.add(&prefix); if let Err(err) = plugin.uninstall_version(&tv, pr.as_ref(), self.dry_run) { pr.error(err.to_string()); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index c3611b1d7..b197756fe 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -1,3 +1,4 @@ +use console::style; use std::collections::HashSet; use std::sync::Arc; @@ -94,8 +95,9 @@ impl Upgrade { }; ts.install_versions(config, new_versions, &mpr, &opts)?; for (tool, tv) in to_remove { - let mut pr = mpr.add(); - self.uninstall_old_version(tool.clone(), &tv, pr.as_mut())?; + let prefix = format!("{}", style(&tv).cyan().for_stderr()); + let pr = mpr.add(&prefix); + self.uninstall_old_version(tool.clone(), &tv, pr.as_ref())?; } let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; @@ -108,9 +110,8 @@ impl Upgrade { &self, tool: Arc, tv: &ToolVersion, - pr: &mut dyn SingleReport, + pr: &dyn SingleReport, ) -> Result<()> { - tool.decorate_progress_bar(pr, Some(tv)); match tool.uninstall_version(tv, pr, self.dry_run) { Ok(_) => { pr.finish(); diff --git a/src/config/settings.rs b/src/config/settings.rs index 6cb4b483c..6cd3dd983 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -84,7 +84,7 @@ impl Settings { if *env::CI { p.yes = Some(true); } - if *env::RTX_LOG_LEVEL < LevelFilter::Info { + if *env::RTX_LOG_LEVEL > LevelFilter::Info { p.verbose = Some(true); } for arg in &*env::ARGS.read().unwrap() { diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 569df5d40..155f7f17e 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -157,7 +157,7 @@ impl Plugin for GoPlugin { Ok(()) } - fn uninstall_version_impl(&self, tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, _pr: &dyn SingleReport, tv: &ToolVersion) -> Result<()> { let gopath = self.gopath(tv); if gopath.exists() { cmd!("chmod", "-R", "u+wx", gopath).run()?; diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index cc6fe6b13..44722b885 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -117,6 +117,7 @@ impl ExternalPlugin { pr.set_message(format!("checking out {ref_}")); git.update(Some(ref_.to_string()))?; } + self.exec_hook(pr, "post-plugin-add")?; let sha = git.current_sha_short()?; pr.finish_with_message(format!( @@ -366,6 +367,15 @@ impl ExternalPlugin { .with_env("ASDF_INSTALL_VERSION", install_version); sm } + + fn exec_hook(&self, pr: &dyn SingleReport, hook: &str) -> Result<()> { + let script = Script::Hook(hook.to_string()); + if self.script_man.script_exists(&script) { + pr.set_message(format!("executing {hook} hook")); + self.script_man.run_by_line(&script, pr)?; + } + Ok(()) + } } fn build_script_man(name: &str, plugin_path: &Path) -> ScriptManager { @@ -464,32 +474,38 @@ impl Plugin for ExternalPlugin { } let _mpr = MultiProgressReport::new(); let mpr = mpr.unwrap_or(&_mpr); - let mut pr = mpr.add(); - self.decorate_progress_bar(pr.as_mut(), None); + let pr = mpr.add(&style(&self.name).blue().for_stderr().to_string()); let _lock = self.get_lock(&self.plugin_path, force)?; self.install(pr.as_ref()) } - fn update(&self, gitref: Option) -> Result<()> { + fn update(&self, pr: &dyn SingleReport, gitref: Option) -> Result<()> { + let config = Config::get(); let plugin_path = self.plugin_path.to_path_buf(); if plugin_path.is_symlink() { - warn!( + pr.warn(format!( "Plugin: {} is a symlink, not updating", style(&self.name).cyan().for_stderr() - ); + )); return Ok(()); } let git = Git::new(plugin_path); if !git.is_repo() { - warn!( + pr.warn(format!( "Plugin {} is not a git repository, not updating", style(&self.name).cyan().for_stderr() - ); + )); return Ok(()); } - // TODO: asdf_run_hook "pre_plugin_update" + pr.set_message("updating git repo".into()); let (_pre, _post) = git.update(gitref)?; - // TODO: asdf_run_hook "post_plugin_update" + let sha = git.current_sha_short()?; + let repo_url = self.get_repo_url(&config)?; + self.exec_hook(pr, "post-plugin-update")?; + pr.finish_with_message(format!( + "{repo_url}#{}", + style(&sha).bright().yellow().for_stderr(), + )); Ok(()) } @@ -497,6 +513,7 @@ impl Plugin for ExternalPlugin { if !self.is_installed() { return Ok(()); } + self.exec_hook(pr, "pre-plugin-remove")?; pr.set_message("uninstalling".into()); let rmdir = |dir: &Path| { @@ -647,9 +664,10 @@ impl Plugin for ExternalPlugin { Ok(()) } - fn uninstall_version_impl(&self, tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, pr: &dyn SingleReport, tv: &ToolVersion) -> Result<()> { if self.plugin_path.join("bin/uninstall").exists() { - self.script_man_for_tv(tv).run(&Script::Uninstall)?; + self.script_man_for_tv(tv) + .run_by_line(&Script::Uninstall, pr)?; } Ok(()) } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 71549dc39..ba18c71b5 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -25,7 +25,7 @@ use crate::lock_file::LockFile; use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::{SingleReport, PROG_TEMPLATE}; +use crate::ui::progress_report::SingleReport; use crate::{dirs, file, http}; pub mod core; @@ -155,7 +155,7 @@ pub trait Plugin: Debug + Send + Sync { fn ensure_installed(&self, _mpr: Option<&MultiProgressReport>, _force: bool) -> Result<()> { Ok(()) } - fn update(&self, _git_ref: Option) -> Result<()> { + fn update(&self, _pr: &dyn SingleReport, _git_ref: Option) -> Result<()> { Ok(()) } fn uninstall(&self, _pr: &dyn SingleReport) -> Result<()> { @@ -183,7 +183,7 @@ pub trait Plugin: Debug + Send + Sync { fn execute_external_command(&self, _command: &str, _args: Vec) -> Result<()> { unimplemented!() } - fn install_version(&self, mut ctx: InstallContext) -> Result<()> { + fn install_version(&self, ctx: InstallContext) -> Result<()> { let config = Config::get(); let settings = Settings::try_get()?; if self.is_version_installed(&ctx.tv) { @@ -193,7 +193,6 @@ pub trait Plugin: Debug + Send + Sync { return Ok(()); } } - self.decorate_progress_bar(ctx.pr.as_mut(), Some(&ctx.tv)); let _lock = self.get_lock(&ctx.tv.install_path(), ctx.force)?; self.create_install_dirs(&ctx.tv)?; @@ -229,7 +228,7 @@ pub trait Plugin: Debug + Send + Sync { pr.set_message(format!("uninstall {tv}")); if !dryrun { - self.uninstall_version_impl(tv)?; + self.uninstall_version_impl(pr, tv)?; } let rmdir = |dir: &Path| { if !dir.exists() { @@ -246,7 +245,7 @@ pub trait Plugin: Debug + Send + Sync { rmdir(&tv.cache_path())?; Ok(()) } - fn uninstall_version_impl(&self, _tv: &ToolVersion) -> Result<()> { + fn uninstall_version_impl(&self, _pr: &dyn SingleReport, _tv: &ToolVersion) -> Result<()> { Ok(()) } fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { @@ -309,20 +308,6 @@ pub trait Plugin: Debug + Send + Sync { let _ = remove_all_with_warning(tv.download_path()); } } - fn decorate_progress_bar(&self, pr: &mut dyn SingleReport, tv: Option<&ToolVersion>) { - pr.set_style(PROG_TEMPLATE.clone()); - let tool = match tv { - Some(tv) => tv.to_string(), - None => self.name().to_string(), - }; - pr.set_prefix(&format!( - "{} {} ", - style("rtx").dim().for_stderr(), - style(tool).cyan().for_stderr(), - )); - pr.enable_steady_tick(); - } - fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { tv.cache_path().join("incomplete") } diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 0e6aed2c2..0e299061b 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -3,7 +3,6 @@ use std::ffi::OsString; use std::fmt; use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use std::process::Output; use color_eyre::eyre::{Context, Result}; use duct::Expression; @@ -28,10 +27,7 @@ pub struct ScriptManager { #[derive(Debug, Clone)] pub enum Script { - // PreInstall, - // PostInstall, - // PreUninstall, - // PostUninstall, + Hook(String), // Plugin LatestStable, @@ -58,6 +54,7 @@ impl Display for Script { Script::ListLegacyFilenames => write!(f, "list-legacy-filenames"), Script::ListAliases => write!(f, "list-aliases"), Script::ParseLegacyFile(_) => write!(f, "parse-legacy-file"), + Script::Hook(script) => write!(f, "{script}"), // RuntimeVersion Script::Install => write!(f, "install"), @@ -152,18 +149,6 @@ impl ScriptManager { cmd } - pub fn run(&self, script: &Script) -> Result<()> { - let cmd = self.cmd(script); - let Output { status, .. } = cmd.unchecked().run()?; - - match status.success() { - true => Ok(()), - false => { - Err(ScriptFailed(display_path(&self.get_script_path(script)), Some(status)).into()) - } - } - } - pub fn read(&self, script: &Script) -> Result { let mut cmd = self.cmd(script); let settings = &Settings::try_get()?; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index a44abf030..47111246b 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -5,6 +5,7 @@ use std::sync::{Arc, Mutex}; use std::thread; use color_eyre::eyre::Result; +use console::style; use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; @@ -149,10 +150,11 @@ impl Toolset { let next_job = || queue.lock().unwrap().pop(); while let Some((t, versions)) = next_job() { for tv in versions { + let prefix = format!("{}", style(&tv).cyan().for_stderr()); let ctx = InstallContext { ts, tv: tv.request.resolve(t.clone(), tv.opts.clone(), true)?, - pr: mpr.add(), + pr: mpr.add(&prefix), raw, force: opts.force, }; diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 0bfdd774b..b156121b0 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,6 +1,8 @@ use crate::config::Settings; use console::style; -use indicatif::{MultiProgress, ProgressBar}; +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use once_cell::sync::Lazy; +use std::time::Duration; use crate::ui::progress_report::{ProgressReport, QuietReport, SingleReport, VerboseReport}; @@ -10,6 +12,11 @@ pub struct MultiProgressReport { quiet: bool, } +static PROG_TEMPLATE: Lazy = Lazy::new(|| { + ProgressStyle::with_template("{prefix} {wide_msg} {spinner:.blue} {elapsed:3.dim.italic}") + .unwrap() +}); + impl MultiProgressReport { pub fn new() -> Self { let settings = Settings::get(); @@ -22,11 +29,17 @@ impl MultiProgressReport { quiet: settings.quiet, } } - pub fn add(&self) -> Box { + pub fn add(&self, prefix: &str) -> Box { match &self.mp { _ if self.quiet => Box::new(QuietReport::new()), - Some(mp) => Box::new(ProgressReport::new(mp.add(ProgressBar::new(0)))), - None => Box::new(VerboseReport::new()), + Some(mp) => { + let pb = ProgressBar::new(1) + .with_style(PROG_TEMPLATE.clone()) + .with_prefix(format!("{} {}", style("rtx").dim().for_stderr(), prefix)); + pb.enable_steady_tick(Duration::from_millis(250)); + Box::new(ProgressReport::new(mp.add(pb))) + } + None => Box::new(VerboseReport::new(prefix.to_string())), } } pub fn suspend R, R>(&self, f: F) -> R { @@ -57,9 +70,7 @@ mod tests { #[test] fn test_multi_progress_report() { let mpr = MultiProgressReport::new(); - let pr = mpr.add(); - pr.set_style(indicatif::ProgressStyle::with_template("").unwrap()); - pr.enable_steady_tick(); + let pr = mpr.add("PREFIX"); pr.finish_with_message("test".into()); pr.println("".into()); pr.set_message("test".into()); diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 8389fe683..0d3a7be6e 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,14 +1,8 @@ -use std::time::Duration; - use console::style; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; pub trait SingleReport: Send + Sync { - fn enable_steady_tick(&self) {} - fn set_prefix(&mut self, prefix: &str); - fn prefix(&self) -> String; - fn set_style(&self, _style: ProgressStyle) {} fn set_message(&self, _message: String) {} fn println(&self, _message: String) {} fn warn(&self, _message: String) {} @@ -17,14 +11,9 @@ pub trait SingleReport: Send + Sync { fn finish_with_message(&self, _message: String) {} } -pub static PROG_TEMPLATE: Lazy = Lazy::new(|| { - ProgressStyle::with_template("{prefix}{wide_msg} {spinner:.blue} {elapsed:3.dim.italic}") - .unwrap() -}); - static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { let tmpl = format!( - "{{prefix}}{{wide_msg}} {} {{elapsed:3.dim.italic}}", + "{{prefix}} {{wide_msg}} {} {{elapsed:3.dim.italic}}", style("✓").bright().green().for_stderr() ); ProgressStyle::with_template(tmpl.as_str()).unwrap() @@ -32,7 +21,7 @@ static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { static ERROR_TEMPLATE: Lazy = Lazy::new(|| { let tmpl = format!( - "{{prefix:.red}}{{wide_msg}} {} {{elapsed:3.dim.italic}}", + "{{prefix:.red}} {{wide_msg}} {} {{elapsed:3.dim.italic}}", style("✗").red().for_stderr() ); ProgressStyle::with_template(tmpl.as_str()).unwrap() @@ -40,7 +29,7 @@ static ERROR_TEMPLATE: Lazy = Lazy::new(|| { #[derive(Debug)] pub struct ProgressReport { - pub pb: ProgressBar, + pb: ProgressBar, } impl ProgressReport { @@ -50,23 +39,6 @@ impl ProgressReport { } impl SingleReport for ProgressReport { - fn enable_steady_tick(&self) { - self.pb.enable_steady_tick(Duration::from_millis(250)); - } - - fn set_prefix(&mut self, prefix: &str) { - self.pb.set_prefix(prefix.to_string()); - } - - fn prefix(&self) -> String { - self.pb.prefix() - } - - fn set_style(&self, style: ProgressStyle) { - self.pb.set_style(style); - self.pb - .set_prefix(console::style("rtx").dim().for_stderr().to_string()); - } fn set_message(&self, message: String) { self.pb.set_message(message.replace('\r', "")); } @@ -96,52 +68,35 @@ impl SingleReport for ProgressReport { } } -pub struct QuietReport { - prefix: String, -} +pub struct QuietReport {} + impl QuietReport { pub fn new() -> QuietReport { - QuietReport { - prefix: String::new(), - } + QuietReport {} } } -impl SingleReport for QuietReport { - fn set_prefix(&mut self, prefix: &str) { - self.prefix = prefix.to_string(); - } - fn prefix(&self) -> String { - self.prefix.clone() - } -} +impl SingleReport for QuietReport {} + pub struct VerboseReport { prefix: String, } + impl VerboseReport { - pub fn new() -> VerboseReport { - VerboseReport { - prefix: String::new(), - } + pub fn new(prefix: String) -> VerboseReport { + VerboseReport { prefix } } } -impl SingleReport for VerboseReport { - fn set_prefix(&mut self, prefix: &str) { - self.prefix = prefix.to_string(); - } - - fn prefix(&self) -> String { - self.prefix.clone() - } +impl SingleReport for VerboseReport { fn set_message(&self, message: String) { - eprintln!("{}", message); + eprintln!("{} {}", self.prefix, message); } fn println(&self, message: String) { - eprintln!("{}", message); + eprintln!("{} {}", self.prefix, message); } fn warn(&self, message: String) { - eprintln!("{}", message); + eprintln!("{} {}", self.prefix, message); } } @@ -151,27 +106,21 @@ mod tests { #[test] fn test_progress_report() { - let mut pr = ProgressReport::new(ProgressBar::new(0)); - pr.set_prefix("prefix"); - assert_eq!(pr.prefix(), "prefix"); + let pr = ProgressReport::new(ProgressBar::new(0)); pr.set_message("message".into()); pr.finish_with_message("message".into()); } #[test] fn test_progress_report_verbose() { - let mut pr = VerboseReport::new(); - pr.set_prefix("prefix"); - assert_eq!(pr.prefix(), "prefix"); + let pr = VerboseReport::new("PREFIX".to_string()); pr.set_message("message".into()); pr.finish_with_message("message".into()); } #[test] fn test_progress_report_quiet() { - let mut pr = QuietReport::new(); - pr.set_prefix("prefix"); - assert_eq!(pr.prefix(), "prefix"); + let pr = QuietReport::new(); pr.set_message("message".into()); pr.finish_with_message("message".into()); } From a29324ea38f131b14c18de744795d21e611876a0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 11:46:18 -0600 Subject: [PATCH 1328/1891] verbose: improve verbose progress bar output (#1187) --- src/cache.rs | 2 +- src/cli/plugins/uninstall.rs | 3 +- src/errors.rs | 3 -- src/plugins/external_plugin.rs | 19 +++++++------ src/plugins/mod.rs | 1 - src/shims.rs | 1 - src/ui/multi_progress_report.rs | 2 +- src/ui/progress_report.rs | 50 ++++++++++++++++++++++----------- 8 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index 006d5763f..a262b3609 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -99,7 +99,7 @@ where Ok(()) } - #[allow(dead_code)] + #[cfg(test)] pub fn clear(&self) -> Result<()> { let path = &self.cache_file_path; trace!("clearing cache {}", path.display()); diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index f676bdd70..4ad0b32ad 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -51,7 +51,8 @@ impl PluginsUninstall { ) -> Result<()> { match config.get_or_create_plugin(plugin_name) { plugin if plugin.is_installed() => { - let pr = mpr.add(&style(plugin.name()).blue().for_stderr().to_string()); + let prefix = format!("plugin:{}", style(&plugin.name()).blue().for_stderr()); + let pr = mpr.add(&prefix); plugin.uninstall(pr.as_ref())?; if self.purge { plugin.purge(pr.as_ref())?; diff --git a/src/errors.rs b/src/errors.rs index a37ff2495..255149b4c 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -10,9 +10,6 @@ pub enum Error { PluginNotInstalled(PluginName), #[error("{0}@{1} not installed")] VersionNotInstalled(PluginName, String), - #[error("{0}@{1} not found")] - #[allow(dead_code)] - VersionNotFound(PluginName, String), #[error("{} exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(String, Option), #[error("Config file is not trusted.\nTrust it with `rtx trust`.")] diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 44722b885..3c568ad00 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -462,19 +462,22 @@ impl Plugin for ExternalPlugin { } if !settings.yes && self.repo_url.is_none() { let url = self.get_repo_url(&config)?; - eprintln!( - "⚠️ {name} is a community-developed plugin: {url}", - name = style(&self.name).cyan(), - url = style(url.trim_end_matches(".git")).yellow(), - ); - if !prompt::confirm(&format!("Would you like to install {}?", self.name))? { - Err(PluginNotInstalled(self.name.clone()))? + if !url.starts_with("https://github.com/rtx-plugins/") { + eprintln!( + "⚠️ {name} is a community-developed plugin: {url}", + name = style(&self.name).cyan(), + url = style(url.trim_end_matches(".git")).yellow(), + ); + if !prompt::confirm(&format!("Would you like to install {}?", self.name))? { + Err(PluginNotInstalled(self.name.clone()))? + } } } } let _mpr = MultiProgressReport::new(); let mpr = mpr.unwrap_or(&_mpr); - let pr = mpr.add(&style(&self.name).blue().for_stderr().to_string()); + let prefix = format!("plugin:{}", style(&self.name).blue().for_stderr()); + let pr = mpr.add(&prefix); let _lock = self.get_lock(&self.plugin_path, force)?; self.install(pr.as_ref()) } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index ba18c71b5..26b0ff327 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -393,7 +393,6 @@ impl Ord for dyn Plugin { #[derive(Debug, Clone, Copy, PartialEq)] pub enum PluginType { - #[allow(dead_code)] Core, External, } diff --git a/src/shims.rs b/src/shims.rs index 5aa47db0b..9e66b3fc6 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -22,7 +22,6 @@ use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; 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(config: &Config) -> Result<()> { if *env::RTX_BIN_NAME == "rtx" { return Ok(()); diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index b156121b0..253d8081a 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -31,7 +31,7 @@ impl MultiProgressReport { } pub fn add(&self, prefix: &str) -> Box { match &self.mp { - _ if self.quiet => Box::new(QuietReport::new()), + _ if self.quiet => Box::new(QuietReport::new(prefix.to_string())), Some(mp) => { let pb = ProgressBar::new(1) .with_style(PROG_TEMPLATE.clone()) diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 0d3a7be6e..fa19e5a83 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -3,10 +3,10 @@ use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; pub trait SingleReport: Send + Sync { - fn set_message(&self, _message: String) {} fn println(&self, _message: String) {} - fn warn(&self, _message: String) {} - fn error(&self, _message: String) {} + fn warn(&self, _message: String); + fn error(&self, _message: String); + fn set_message(&self, _message: String) {} fn finish(&self) {} fn finish_with_message(&self, _message: String) {} } @@ -39,9 +39,6 @@ impl ProgressReport { } impl SingleReport for ProgressReport { - fn set_message(&self, message: String) { - self.pb.set_message(message.replace('\r', "")); - } fn println(&self, message: String) { self.pb.println(message); } @@ -58,6 +55,9 @@ impl SingleReport for ProgressReport { self.pb.set_style(ERROR_TEMPLATE.clone()); self.pb.finish(); } + fn set_message(&self, message: String) { + self.pb.set_message(message.replace('\r', "")); + } fn finish(&self) { self.pb.set_style(SUCCESS_TEMPLATE.clone()); self.pb.finish() @@ -68,15 +68,24 @@ impl SingleReport for ProgressReport { } } -pub struct QuietReport {} +pub struct QuietReport { + prefix: String, +} impl QuietReport { - pub fn new() -> QuietReport { - QuietReport {} + pub fn new(prefix: String) -> QuietReport { + QuietReport { prefix } } } -impl SingleReport for QuietReport {} +impl SingleReport for QuietReport { + fn warn(&self, message: String) { + warn!("{} {}", self.prefix, message); + } + fn error(&self, message: String) { + error!("{} {}", self.prefix, message); + } +} pub struct VerboseReport { prefix: String, @@ -89,14 +98,23 @@ impl VerboseReport { } impl SingleReport for VerboseReport { - fn set_message(&self, message: String) { - eprintln!("{} {}", self.prefix, message); - } fn println(&self, message: String) { - eprintln!("{} {}", self.prefix, message); + eprintln!("{message}"); } fn warn(&self, message: String) { - eprintln!("{} {}", self.prefix, message); + warn!("{} {}", self.prefix, message); + } + fn error(&self, message: String) { + error!("{} {}", self.prefix, message); + } + fn set_message(&self, message: String) { + eprintln!("{} {message}", self.prefix); + } + fn finish(&self) { + self.finish_with_message(style("done").green().to_string()); + } + fn finish_with_message(&self, message: String) { + self.set_message(message); } } @@ -120,7 +138,7 @@ mod tests { #[test] fn test_progress_report_quiet() { - let pr = QuietReport::new(); + let pr = QuietReport::new("PREFIX".to_string()); pr.set_message("message".into()); pr.finish_with_message("message".into()); } From 474534a062480f25cc81ea8ef0600282b86a9131 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 22:10:38 -0600 Subject: [PATCH 1329/1891] config-files: added new CLI topic (#1189) * config-files: added new CLI topic * wip * wip * wip * wip * wip --- .config/insta.yaml | 4 + Cargo.lock | 118 ++++++++++ Cargo.toml | 7 +- README.md | 36 ++++ completions/_rtx | 49 +++++ completions/rtx.bash | 202 +++++++++++++++++- completions/rtx.fish | 17 +- src/cli/alias/get.rs | 4 +- src/cli/alias/ls.rs | 1 - src/cli/alias/set.rs | 1 - src/cli/alias/unset.rs | 1 - src/cli/asdf.rs | 11 +- src/cli/bin_paths.rs | 6 +- src/cli/cache/clear.rs | 9 +- src/cli/cache/mod.rs | 1 - ...cli__cache__clear__tests__cache_clear.snap | 5 - ...che__clear__tests__cache_clear_plugin.snap | 5 - src/cli/completion.rs | 1 - src/cli/config/generate.rs | 114 ++++++++++ src/cli/config/ls.rs | 85 ++++++++ src/cli/config/mod.rs | 42 ++++ ...li__config__generate__tests__generate.snap | 60 ++++++ src/cli/current.rs | 19 +- src/cli/deactivate.rs | 4 +- src/cli/direnv/envrc.rs | 5 +- src/cli/direnv/exec.rs | 1 - src/cli/env.rs | 1 - src/cli/env_vars.rs | 5 +- src/cli/exec.rs | 2 - src/cli/global.rs | 3 +- src/cli/hook_env.rs | 12 +- src/cli/implode.rs | 2 +- src/cli/install.rs | 7 +- src/cli/latest.rs | 8 +- src/cli/link.rs | 9 +- src/cli/local.rs | 7 +- src/cli/ls.rs | 177 ++++++++------- src/cli/ls_remote.rs | 5 +- src/cli/mod.rs | 68 +----- src/cli/outdated.rs | 2 - src/cli/plugins/install.rs | 4 +- src/cli/plugins/link.rs | 11 +- src/cli/plugins/ls.rs | 1 - src/cli/plugins/ls_remote.rs | 1 - ...li__plugins__link__tests__plugin_link.snap | 7 - src/cli/plugins/update.rs | 1 - src/cli/prune.rs | 1 - src/cli/render_completion.rs | 1 - src/cli/render_help.rs | 3 +- src/cli/render_mangen.rs | 2 +- src/cli/settings/get.rs | 8 +- src/cli/settings/ls.rs | 8 +- src/cli/settings/set.rs | 1 - ...cli__settings__ls__tests__settings_ls.snap | 5 +- ...i__settings__set__tests__settings_set.snap | 5 +- src/cli/settings/unset.rs | 7 +- src/cli/shell.rs | 4 - ...rtx__cli__asdf__tests__fake_asdf_list.snap | 7 - ...tx__cli__asdf__tests__fake_asdf_other.snap | 5 - ...rtx__cli__bin_paths__tests__bin_paths.snap | 6 - .../rtx__cli__current__tests__current.snap | 6 - ..._cli__current__tests__current_missing.snap | 6 - ...current__tests__current_with_runtimes.snap | 5 - .../rtx__cli__link__tests__link.snap | 9 - .../snapshots/rtx__cli__ls__tests__ls-2.snap | 7 - .../snapshots/rtx__cli__ls__tests__ls-3.snap | 7 - .../snapshots/rtx__cli__ls__tests__ls-4.snap | 6 - .../snapshots/rtx__cli__ls__tests__ls-5.snap | 6 - .../snapshots/rtx__cli__ls__tests__ls.snap | 6 - .../rtx__cli__ls__tests__ls_current.snap | 6 - .../rtx__cli__ls__tests__ls_missing.snap | 5 - .../rtx__cli__ls__tests__ls_parseable-2.snap | 5 - .../rtx__cli__ls__tests__ls_parseable.snap | 6 - .../rtx__cli__ls__tests__ls_prefix.snap | 5 - .../rtx__cli__r#use__tests__use_global-2.snap | 7 - .../rtx__cli__r#use__tests__use_global.snap | 5 - .../rtx__cli__r#use__tests__use_local-2.snap | 7 - .../rtx__cli__r#use__tests__use_local-3.snap | 5 - .../rtx__cli__r#use__tests__use_local-4.snap | 7 - .../rtx__cli__r#use__tests__use_local-5.snap | 5 - .../rtx__cli__r#use__tests__use_local-6.snap | 7 - .../rtx__cli__r#use__tests__use_local-7.snap | 5 - .../rtx__cli__r#use__tests__use_local-8.snap | 5 - .../rtx__cli__r#use__tests__use_local.snap | 5 - ...use__tests__use_local_tool_versions-2.snap | 6 - ...r#use__tests__use_local_tool_versions.snap | 5 - src/cli/sync/python.rs | 1 - src/cli/trust.rs | 1 - src/cli/uninstall.rs | 4 +- src/cli/upgrade.rs | 2 +- src/cli/use.rs | 69 +++--- src/cli/version.rs | 2 - src/cli/where.rs | 8 +- src/cli/which.rs | 1 - src/config/config_file/legacy_version.rs | 7 - src/config/config_file/mod.rs | 11 +- src/config/config_file/rtx_toml.rs | 83 ++++--- ...__config_file__rtx_toml__tests__env-3.snap | 2 +- ..._config_file__rtx_toml__tests__env-4.snap} | 4 +- ...__config_file__rtx_toml__tests__env-5.snap | 28 +++ ...nfig_file__rtx_toml__tests__fixture-2.snap | 55 +++-- ...nfig_file__rtx_toml__tests__fixture-6.snap | 62 +++--- ...ig_file__rtx_toml__tests__path_dirs-3.snap | 2 +- ...g_file__rtx_toml__tests__path_dirs-4.snap} | 5 +- ...ig_file__rtx_toml__tests__path_dirs-5.snap | 32 +++ ...file__rtx_toml__tests__remove_alias-2.snap | 2 +- ...file__rtx_toml__tests__remove_alias-3.snap | 5 + ...file__rtx_toml__tests__remove_alias-4.snap | 30 +++ ...ile__rtx_toml__tests__remove_plugin-2.snap | 2 +- ...ile__rtx_toml__tests__remove_plugin-3.snap | 5 + ...ile__rtx_toml__tests__remove_plugin-4.snap | 25 +++ ...__rtx_toml__tests__replace_versions-2.snap | 2 +- ...__rtx_toml__tests__replace_versions-3.snap | 5 + ...__rtx_toml__tests__replace_versions-4.snap | 25 +++ ...ig_file__rtx_toml__tests__set_alias-2.snap | 9 +- src/config/config_file/tool_versions.rs | 5 +- src/config/mod.rs | 1 - src/config/settings.rs | 100 ++------- src/direnv.rs | 1 - src/env.rs | 11 + src/env_diff.rs | 2 +- src/hash.rs | 1 - src/main.rs | 8 +- src/plugins/core/python.rs | 30 +-- src/plugins/external_plugin.rs | 31 +-- src/plugins/mod.rs | 12 +- src/plugins/rtx_plugin_toml.rs | 1 - src/plugins/script_manager.rs | 7 +- src/runtime_symlinks.rs | 2 - src/shell/bash.rs | 1 - src/shell/fish.rs | 1 - src/shell/nushell.rs | 1 - src/shell/xonsh.rs | 1 - src/shell/zsh.rs | 1 - ..._time__tests__render_outdated_message.snap | 7 - src/test.rs | 75 ++++++- src/toolset/mod.rs | 14 +- src/toolset/tool_version.rs | 19 +- src/toolset/tool_version_list.rs | 2 +- src/toolset/tool_version_request.rs | 3 +- src/ui/mod.rs | 2 + src/ui/multi_progress_report.rs | 23 +- src/ui/progress_report.rs | 114 +++++++--- src/ui/table.rs | 37 ++++ src/ui/truncate.rs | 6 + 145 files changed, 1562 insertions(+), 804 deletions(-) create mode 100644 .config/insta.yaml delete mode 100644 src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap delete mode 100644 src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap create mode 100644 src/cli/config/generate.rs create mode 100644 src/cli/config/ls.rs create mode 100644 src/cli/config/mod.rs create mode 100644 src/cli/config/snapshots/rtx__cli__config__generate__tests__generate.snap delete mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap delete mode 100644 src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap delete mode 100644 src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap delete mode 100644 src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap delete mode 100644 src/cli/snapshots/rtx__cli__current__tests__current.snap delete mode 100644 src/cli/snapshots/rtx__cli__current__tests__current_missing.snap delete mode 100644 src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap delete mode 100644 src/cli/snapshots/rtx__cli__link__tests__link.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap delete mode 100644 src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap delete mode 100644 src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__env-2.snap => rtx__config__config_file__rtx_toml__tests__env-4.snap} (79%) create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap => rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap} (57%) create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap create mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap delete mode 100644 src/snapshots/rtx__build_time__tests__render_outdated_message.snap create mode 100644 src/ui/table.rs create mode 100644 src/ui/truncate.rs diff --git a/.config/insta.yaml b/.config/insta.yaml new file mode 100644 index 000000000..68e8c03a3 --- /dev/null +++ b/.config/insta.yaml @@ -0,0 +1,4 @@ +test: + auto_review: true +review: + warn_undiscovered: true diff --git a/Cargo.lock b/Cargo.lock index 962bd02c2..5f701d961 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,25 @@ dependencies = [ "libc", ] +[[package]] +name = "ansi-str" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cf4578926a981ab0ca955dc023541d19de37112bc24c1a197bd806d3d86ad1d" +dependencies = [ + "ansitok", +] + +[[package]] +name = "ansitok" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220044e6a1bb31ddee4e3db724d29767f352de47445a6cd75e1a173142136c83" +dependencies = [ + "nom", + "vte", +] + [[package]] name = "anstream" version = "0.6.5" @@ -89,6 +108,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "async-compression" version = "0.4.5" @@ -182,6 +207,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + [[package]] name = "byteorder" version = "1.5.0" @@ -1126,6 +1157,8 @@ dependencies = [ "console", "lazy_static", "linked-hash-map", + "regex", + "serde", "similar", "yaml-rust", ] @@ -1438,6 +1471,19 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "papergrid" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8" +dependencies = [ + "ansi-str", + "ansitok", + "bytecount", + "fnv", + "unicode-width", +] + [[package]] name = "paste" version = "1.0.14" @@ -1575,6 +1621,30 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.70" @@ -1841,6 +1911,7 @@ dependencies = [ "shell-words", "simplelog", "sys-info", + "tabled", "tar", "tempfile", "tera", @@ -2253,6 +2324,32 @@ dependencies = [ "libc", ] +[[package]] +name = "tabled" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfe9c3632da101aba5131ed63f9eed38665f8b3c68703a6bb18124835c1a5d22" +dependencies = [ + "ansi-str", + "ansitok", + "papergrid", + "tabled_derive", + "unicode-width", +] + +[[package]] +name = "tabled_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "tar" version = "0.4.40" @@ -2677,6 +2774,27 @@ dependencies = [ "nom", ] +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "walkdir" version = "2.4.0" diff --git a/Cargo.toml b/Cargo.toml index 158316ff5..d339de016 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,12 +86,13 @@ self_update = { version = "<1", default-features = false, features = [ ] } serde = "1.0" serde_derive = "1.0" -serde_json = "1.0" +serde_json = { version = "1.0", features = [] } sha2 = "0.10" shell-escape = "0.1" shell-words = "1.1" simplelog = { version = "0.12" } sys-info = "0.9" +tabled = { version = "0.14", features = ["color"] } tar = "0.4" tempfile = "3.8.1" tera = { version = "1.19", default-features = false } @@ -112,8 +113,8 @@ built = { version = "0.7", features = ["chrono", "git2"] } [dev-dependencies] ctor = "<0.3" -insta = "1.33" -pretty_assertions = "1.4" +insta = { version = "1", features = ["filters", "json"] } +pretty_assertions = "1" [features] default = ["native-tls"] diff --git a/README.md b/README.md index 557626e0f..cff1d6004 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,8 @@ v20.0.0 - [`rtx bin-paths`](#rtx-bin-paths) - [`rtx cache clear [PLUGIN]...`](#rtx-cache-clear-plugin) - [`rtx completion [SHELL]`](#rtx-completion-shell) + - [`rtx config ls [OPTIONS]`](#rtx-config-ls-options) + - [`rtx config generate [OPTIONS]`](#rtx-config-generate-options) - [`rtx current [PLUGIN]`](#rtx-current-plugin) - [`rtx deactivate`](#rtx-deactivate) - [`rtx direnv activate`](#rtx-direnv-activate) @@ -1805,6 +1807,37 @@ Examples: $ rtx completion fish > ~/.config/fish/completions/rtx.fish ``` +### `rtx config ls [OPTIONS]` + +```text +[experimental] List config files currently in use + +Usage: config ls [OPTIONS] + +Options: + --no-header + Do not print table header + +Examples: + $ rtx config ls +``` + +### `rtx config generate [OPTIONS]` + +```text +[experimental] Generate an .rtx.toml file + +Usage: config generate [OPTIONS] + +Options: + -o, --output + Output to file instead of stdout + +Examples: + $ rtx cf generate > .rtx.toml + $ rtx cf generate --output=.rtx.toml +``` + ### `rtx current [PLUGIN]` ```text @@ -2141,6 +2174,9 @@ Options: --prefix Display versions matching this prefix + --no-header + Don't display headers + Examples: $ rtx ls node 20.0.0 ~/src/myapp/.tool-versions latest diff --git a/completions/_rtx b/completions/_rtx index a680c9b46..4157fa092 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -21,6 +21,7 @@ _rtx() { (bin-paths) __rtx_bin_paths_cmd && ret=0 ;; (cache) __rtx_cache_cmd && ret=0 ;; (complete|completions|completion) __rtx_completion_cmd && ret=0 ;; + (cfg|config) __rtx_config_cmd && ret=0 ;; (current) __rtx_current_cmd && ret=0 ;; (deactivate) __rtx_deactivate_cmd && ret=0 ;; (direnv) __rtx_direnv_cmd && ret=0 ;; @@ -178,6 +179,44 @@ __rtx_completion_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_config_cmd] )) || +__rtx_config_cmd() { + _arguments -s -S \ + '--no-header[Do not print table header]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_config_cmds' \ + '*::arg:->args' && ret=0 + + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (g|generate) __rtx_config_generate_cmd && ret=0 ;; + (ls) __rtx_config_ls_cmd && ret=0 ;; + esac + ;; + esac + +return ret +} +(( $+functions[__rtx_config_generate_cmd] )) || +__rtx_config_generate_cmd() { + _arguments -s -S \ + '(-o --output)'{-o,--output}'=[Output to file instead of stdout]:output:_files' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_config_ls_cmd] )) || +__rtx_config_ls_cmd() { + _arguments -s -S \ + '--no-header[Do not print table header]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} (( $+functions[__rtx_current_cmd] )) || __rtx_current_cmd() { _arguments -s -S \ @@ -360,6 +399,7 @@ __rtx_ls_cmd() { '(-J --json)'{-J,--json}'[Output in json format]' \ '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ + '--no-header[Don'\''t display headers]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' @@ -683,6 +723,7 @@ __rtx_cmds() { 'bin-paths:List all the active runtime bin paths' 'cache:Manage the rtx cache' 'completion:Generate shell completions' + {cfg,config}':\[experimental\] Manage config files' 'current:Shows current active and installed runtime versions' 'deactivate:Disable rtx for current shell session' 'direnv:Output direnv function to use rtx inside direnv' @@ -731,6 +772,14 @@ __rtx_cache_cmds() { ) _describe -t commands 'command' commands "$@" } +(( $+functions[__rtx_config_cmds] )) || +__rtx_config_cmds() { + local commands; commands=( + {g,generate}':\[experimental\] Generate an .rtx.toml file' + 'ls:\[experimental\] List config files currently in use' + ) + _describe -t commands 'command' commands "$@" +} (( $+functions[__rtx_direnv_cmds] )) || __rtx_direnv_cmds() { local commands; commands=( diff --git a/completions/rtx.bash b/completions/rtx.bash index 9774d21cd..b332c8f7f 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -30,9 +30,15 @@ _rtx() { rtx,cache) cmd="rtx__cache" ;; + rtx,cfg) + cmd="rtx__config" + ;; rtx,completion) cmd="rtx__completion" ;; + rtx,config) + cmd="rtx__config" + ;; rtx,current) cmd="rtx__current" ;; @@ -222,6 +228,27 @@ _rtx() { rtx__cache__help,help) cmd="rtx__cache__help__help" ;; + rtx__config,g) + cmd="rtx__config__generate" + ;; + rtx__config,generate) + cmd="rtx__config__generate" + ;; + rtx__config,help) + cmd="rtx__config__help" + ;; + rtx__config,ls) + cmd="rtx__config__ls" + ;; + rtx__config__help,generate) + cmd="rtx__config__help__generate" + ;; + rtx__config__help,help) + cmd="rtx__config__help__help" + ;; + rtx__config__help,ls) + cmd="rtx__config__help__ls" + ;; rtx__direnv,activate) cmd="rtx__direnv__activate" ;; @@ -264,6 +291,9 @@ _rtx() { rtx__help,completion) cmd="rtx__help__completion" ;; + rtx__help,config) + cmd="rtx__help__config" + ;; rtx__help,current) cmd="rtx__help__current" ;; @@ -384,6 +414,12 @@ _rtx() { rtx__help__cache,clear) cmd="rtx__help__cache__clear" ;; + rtx__help__config,generate) + cmd="rtx__help__config__generate" + ;; + rtx__help__config,ls) + cmd="rtx__help__config__ls" + ;; rtx__help__direnv,activate) cmd="rtx__help__direnv__activate" ;; @@ -559,7 +595,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -924,6 +960,124 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__config) + opts="-q -v -y -h --no-header --debug --log-level --trace --quiet --verbose --yes --help ls generate help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__config__generate) + opts="-o -q -v -y -h --output --debug --log-level --trace --quiet --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --output) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__config__help) + opts="ls generate help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__config__help__generate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__config__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__config__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__config__ls) + opts="-q -v -y -h --no-header --debug --log-level --trace --quiet --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__current) opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -1245,7 +1399,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1412,6 +1566,48 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__config) + opts="ls generate" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__config__generate) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__config__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__current) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2241,7 +2437,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -J -m -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." + opts="-p -c -g -i -J -m -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --no-header --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 43aa39bb4..3420999a2 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -4,12 +4,13 @@ set -l fssf "__fish_seen_subcommand_from" complete -kxc rtx -s q -l quiet -d 'Suppress output' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' -set -l others activate alias bin-paths cache completion current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which +set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell session' complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' complete -xc rtx -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' complete -xc rtx -n "not $fssf $others" -a cache -d 'Manage the rtx cache' complete -xc rtx -n "not $fssf $others" -a completion -d 'Generate shell completions' +complete -xc rtx -n "not $fssf $others" -a config -d '[experimental] Manage config files' complete -xc rtx -n "not $fssf $others" -a current -d 'Shows current active and installed runtime versions' complete -xc rtx -n "not $fssf $others" -a deactivate -d 'Disable rtx for current shell session' complete -xc rtx -n "not $fssf $others" -a direnv -d 'Output direnv function to use rtx inside direnv' @@ -81,6 +82,19 @@ complete -kxc rtx -n "$fssf cache; and $fssf clear" -a "(__rtx_plugins)" -d 'Plu # completion complete -kxc rtx -n "$fssf completion" -a "bash fish zsh" -d 'Shell type to generate completions for' +# config +complete -kxc rtx -n "$fssf config" -l no-header -d 'Do not print table header' +set -l others generate ls +complete -xc rtx -n "$fssf config; and not $fssf $others" -a generate -d '[experimental] Generate an .rtx.toml file' +complete -xc rtx -n "$fssf config; and not $fssf $others" -a ls -d '[experimental] List config files currently in use' + +# config generate +complete -kxc rtx -n "$fssf config; and $fssf generate" -s o -l output -a "(__fish_complete_path)" -d 'Output to file instead of stdout' + +# config ls +complete -kxc rtx -n "$fssf config; and $fssf ls" -l no-header -d 'Do not print table header' + + # current complete -kxc rtx -n "$fssf current" -a "(__rtx_plugins)" -d 'Plugin to show versions of e.g.: ruby, node' @@ -141,6 +155,7 @@ complete -kxc rtx -n "$fssf ls" -s g -l global -d 'Only show tool versions curre complete -kxc rtx -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' complete -kxc rtx -n "$fssf ls" -s J -l json -d 'Output in json format' complete -kxc rtx -n "$fssf ls" -s m -l missing -d 'Display missing tool versions' +complete -kxc rtx -n "$fssf ls" -l no-header -d 'Don'\''t display headers' complete -kxc rtx -n "$fssf ls" -a "(__rtx_plugins)" -d 'Only show tool versions from [PLUGIN]' complete -kxc rtx -n "$fssf ls" -l prefix -d 'Display versions matching this prefix' diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 14a463fe0..7f54d0f45 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -37,9 +37,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::{assert_display_snapshot, assert_snapshot}; - - use crate::{assert_cli, assert_cli_err, test::reset_config}; + use crate::test::reset_config; #[test] fn test_alias_get() { diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 5d3bc1e74..ebfaf106b 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -55,7 +55,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_alias_ls() { diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index c35985bb3..199f8c8d4 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -34,7 +34,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] pub mod tests { use crate::test::reset_config; - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_alias_set() { diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 932313330..19c87befe 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -32,7 +32,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { use crate::test::reset_config; - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_alias_unset() { diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 4cba00113..45d4a4b72 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -72,18 +72,23 @@ fn list_versions(config: &Config, args: &Vec) -> Result<()> { #[cfg(test)] mod tests { - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_fake_asdf_list() { assert_cli!("install", "tiny@1", "tiny@2"); assert_cli!("asdf", "install", "tiny"); - assert_cli_snapshot!("asdf", "list", "tiny"); + assert_cli_snapshot!("asdf", "list", "tiny", @r###" + 1.0.1 + 2.1.0 + 3.1.0 + "###); } #[test] fn test_fake_asdf_other() { - assert_cli_snapshot!("asdf", "current", "tiny"); + assert_cli_snapshot!("asdf", "current", "tiny", @r###" + 3.1.0 + "###); } #[test] diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 7d3cb3e98..59a3f808c 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -21,11 +21,13 @@ impl BinPaths { #[cfg(test)] mod tests { - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_bin_paths() { assert_cli!("i"); - assert_cli_snapshot!("bin-paths"); + assert_cli_snapshot!("bin-paths", @r###" + ~/data/installs/tiny/3.1.0/bin + ~/data/installs/dummy/ref-master/bin + "###); } } diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index dc8cca32a..41b7d6d01 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -34,15 +34,18 @@ impl CacheClear { #[cfg(test)] mod tests { - use crate::assert_cli_snapshot_stderr; #[test] fn test_cache_clear() { - assert_cli_snapshot_stderr!("cache", "clear"); + assert_cli_snapshot!("cache", "clear", @r###" + rtx cache cleared + "###); } #[test] fn test_cache_clear_plugin() { - assert_cli_snapshot_stderr!("cache", "clear", "tiny"); + assert_cli_snapshot!("cache", "clear", "tiny", @r###" + rtx cache cleared for tiny + "###); } } diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index c262fcadb..0994b4695 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -45,7 +45,6 @@ impl Cache { mod tests { use pretty_assertions::assert_str_eq; - use crate::assert_cli; use crate::env; #[test] diff --git a/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap b/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap deleted file mode 100644 index de6ce6cee..000000000 --- a/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/cache/clear.rs -expression: output ---- -rtx cache cleared diff --git a/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap b/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap deleted file mode 100644 index 805c0c5c4..000000000 --- a/src/cli/cache/snapshots/rtx__cli__cache__clear__tests__cache_clear_plugin.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/cache/clear.rs -expression: output ---- -rtx cache cleared for tiny diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 5b5b58b66..89a8be007 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -73,7 +73,6 @@ impl Display for Shell { #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_completion() { diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs new file mode 100644 index 000000000..754788641 --- /dev/null +++ b/src/cli/config/generate.rs @@ -0,0 +1,114 @@ +use std::path::PathBuf; + +use crate::config::Settings; +use crate::file; +use crate::file::display_path; +use clap::ValueHint; +use color_eyre::eyre::Result; + +/// [experimental] Generate an .rtx.toml file +#[derive(Debug, clap::Args)] +#[clap(visible_alias = "g", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct ConfigGenerate { + /// Output to file instead of stdout + #[clap(long, short, verbatim_doc_comment, value_hint = ValueHint::FilePath)] + output: Option, +} + +impl ConfigGenerate { + pub fn run(self) -> Result<()> { + let settings = Settings::try_get()?; + settings.ensure_experimental()?; + let doc = r#" +# # rtx config files are hierarchical. rtx will find all of the config files +# # in all parent directories and merge them together. +# # You might have a structure like: +# +# * ~/work/project/.rtx.toml # a config file for a specific work project +# * ~/work/.rtx.toml # a config file for projects related to work +# * ~/.config/rtx/config.toml # the global config file +# * /etc/rtx/config.toml # the system config file +# +# # This setup allows you to define default versions and configuration across +# # all projects but override them for specific projects. +# +# # add extra directories to PATH +# env_path = [ +# "~/bin", # absolute path +# "./node_modules/.bin", # relative path to this file, not $PWD +# ] +# +# # set arbitrary env vars to be used whenever in this project or subprojects +# [env] +# NODE_ENV = "development" +# NPM_CONFIG_PREFIX = "~/.npm-global" +# EDITOR = "code --wait" +# +# [env_remove] +# load a dotenv file +# env_file = ".env" +# +# [tools] +# terraform = '1.0.0' # specify a single version +# erlang = '26' # specify a major version only +# node = 'ref:master' # build from a git ref +# node = 'path:~/.nodes/14' # BYO – specify a non-rtx managed installation +# +# # newest with this prefix (typically exact matches don't use the prefix) +# go = 'prefix:1.16' +# +# # multiple versions will all go into PATH in the order specified +# # this is helpful for making `python311` and `python310` available +# # even when `python` and `python3` point to a different version +# python = ['3.12', '3.11', '3.10'] +# +# # some plugins can take options like python's virtualenv activation +# # with these, rtx will automatically setup and activate vevs when entering +# # the project directory +# python = {version='3.12', virtualenv='.venv'} +# poetry = {version='1.7.1', pyproject='pyproject.toml'} +# +# [plugins] +# # specify a custom repo url so you can install with `rtx plugin add ` +# # note this will only be used if the plugin is not already installed +# python = 'https://github.com/asdf-community/asdf-python' +# +# [alias.node] +# # setup a custom alias so you can run `rtx use -g node@work` for node-16.x +# work = '16' +"# + .trim(); + if let Some(output) = &self.output { + rtxstatusln!("writing to {}", display_path(output)); + file::write(output, doc)?; + } else { + rtxprintln!("{doc}"); + } + + Ok(()) + } +} + +// TODO: fill this out +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx cf generate > .rtx.toml + $ rtx cf generate --output=.rtx.toml +"# +); + +#[cfg(test)] +mod tests { + use std::env; + + #[test] + fn test_generate() { + with_settings!({ + let out = assert_cli!("config", "generate"); + for line in out.lines() { + assert!(line.len() < 80); + } + assert_cli_snapshot!("cfg", "generate"); + }); + } +} diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs new file mode 100644 index 000000000..ec9a8da7c --- /dev/null +++ b/src/cli/config/ls.rs @@ -0,0 +1,85 @@ +use color_eyre::eyre::Result; +use console::style; +use itertools::Itertools; +use tabled::settings::object::Columns; + +use tabled::settings::{Modify, Width}; +use tabled::Tabled; + +use crate::config::config_file::ConfigFile; +use crate::config::{Config, Settings}; +use crate::file::display_path; +use crate::ui::table; + +/// [experimental] List config files currently in use +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct ConfigLs { + /// Do not print table header + #[clap(long, alias = "no-headers", verbatim_doc_comment)] + pub no_header: bool, +} + +impl ConfigLs { + pub fn run(self) -> Result<()> { + let settings = Settings::try_get()?; + settings.ensure_experimental()?; + let config = Config::try_get()?; + let rows = config + .config_files + .values() + .map(|cf| cf.as_ref().into()) + .collect::>(); + let mut table = tabled::Table::new(rows); + table::default_style(&mut table, self.no_header); + table.with(Modify::new(Columns::last()).with(Width::truncate(40).suffix("…"))); + rtxprintln!("{table}"); + + Ok(()) + } +} + +fn format_plugin_cell(s: String) -> String { + match s.is_empty() { + true => style("(none)").italic().dim().to_string(), + false => style(s).dim().to_string(), + } +} + +#[derive(Tabled)] +#[tabled(rename_all = "PascalCase")] +struct Row { + path: String, + plugins: String, +} + +impl From<&dyn ConfigFile> for Row { + fn from(cf: &dyn ConfigFile) -> Self { + let path = display_path(cf.get_path()); + let ts = cf.to_toolset(); + let plugins = ts.list_plugins().into_iter().join(", "); + let plugins = format_plugin_cell(plugins); + Self { path, plugins } + } +} + +// TODO: fill this out +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx config ls +"# +); + +#[cfg(test)] +mod tests { + use std::env; + + #[test] + fn test_config_ls() { + assert_cli_snapshot!("cfg", "--no-headers", @r###" + ~/cwd/.test-tool-versions tiny + ~/.test-tool-versions tiny, dummy + ~/config/config.toml (none) + "###); + } +} diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs new file mode 100644 index 000000000..7640026c1 --- /dev/null +++ b/src/cli/config/mod.rs @@ -0,0 +1,42 @@ +use clap::Subcommand; +use eyre::Result; + +mod generate; +mod ls; + +/// [experimental] Manage config files +#[derive(Debug, clap::Args)] +#[clap(visible_alias = "cfg")] +pub struct Config { + #[clap(subcommand)] + command: Option, + + /// Do not print table header + #[clap(long, alias = "no-headers", verbatim_doc_comment)] + no_header: bool, +} + +#[derive(Debug, Subcommand)] +enum Commands { + Ls(ls::ConfigLs), + Generate(generate::ConfigGenerate), +} + +impl Commands { + pub fn run(self) -> Result<()> { + match self { + Self::Ls(cmd) => cmd.run(), + Self::Generate(cmd) => cmd.run(), + } + } +} + +impl Config { + pub fn run(self) -> Result<()> { + let cmd = self.command.unwrap_or(Commands::Ls(ls::ConfigLs { + no_header: self.no_header, + })); + + cmd.run() + } +} diff --git a/src/cli/config/snapshots/rtx__cli__config__generate__tests__generate.snap b/src/cli/config/snapshots/rtx__cli__config__generate__tests__generate.snap new file mode 100644 index 000000000..c3811157c --- /dev/null +++ b/src/cli/config/snapshots/rtx__cli__config__generate__tests__generate.snap @@ -0,0 +1,60 @@ +--- +source: src/cli/config/generate.rs +expression: output +--- +# # rtx config files are hierarchical. rtx will find all of the config files +# # in all parent directories and merge them together. +# # You might have a structure like: +# +# * ~/work/project/.rtx.toml # a config file for a specific work project +# * ~/work/.rtx.toml # a config file for projects related to work +# * ~/.config/rtx/config.toml # the global config file +# * /etc/rtx/config.toml # the system config file +# +# # This setup allows you to define default versions and configuration across +# # all projects but override them for specific projects. +# +# # add extra directories to PATH +# env_path = [ +# "~/bin", # absolute path +# "./node_modules/.bin", # relative path to this file, not $PWD +# ] +# +# # set arbitrary env vars to be used whenever in this project or subprojects +# [env] +# NODE_ENV = "development" +# NPM_CONFIG_PREFIX = "~/.npm-global" +# EDITOR = "code --wait" +# +# [env_remove] +# load a dotenv file +# env_file = ".env" +# +# [tools] +# terraform = '1.0.0' # specify a single version +# erlang = '26' # specify a major version only +# node = 'ref:master' # build from a git ref +# node = 'path:~/.nodes/14' # BYO – specify a non-rtx managed installation +# +# # newest with this prefix (typically exact matches don't use the prefix) +# go = 'prefix:1.16' +# +# # multiple versions will all go into PATH in the order specified +# # this is helpful for making `python311` and `python310` available +# # even when `python` and `python3` point to a different version +# python = ['3.12', '3.11', '3.10'] +# +# # some plugins can take options like python's virtualenv activation +# # with these, rtx will automatically setup and activate vevs when entering +# # the project directory +# python = {version='3.12', virtualenv='.venv'} +# poetry = {version='1.7.1', pyproject='pyproject.toml'} +# +# [plugins] +# # specify a custom repo url so you can install with `rtx plugin add ` +# # note this will only be used if the plugin is not already installed +# python = 'https://github.com/asdf-community/asdf-python' +# +# [alias.node] +# # setup a custom alias so you can run `rtx use -g node@work` for node-16.x +# work = '16' diff --git a/src/cli/current.rs b/src/cli/current.rs index 1718f796c..f9a54865f 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,5 +1,4 @@ use color_eyre::eyre::Result; -use std::sync::Arc; use crate::config::Config; @@ -29,13 +28,13 @@ impl Current { if !plugin.is_installed() { bail!("Plugin {} is not installed", plugin_name); } - self.one(ts, plugin.clone()) + self.one(ts, plugin.as_ref()) } None => self.all(ts), } } - fn one(&self, ts: Toolset, tool: Arc) -> Result<()> { + fn one(&self, ts: Toolset, tool: &dyn Plugin) -> Result<()> { if !tool.is_installed() { warn!("Plugin {} is not installed", tool.name()); return Ok(()); @@ -112,16 +111,17 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( mod tests { use std::env; - use crate::{assert_cli, assert_cli_snapshot}; - #[test] fn test_current() { - assert_cli_snapshot!("current"); + assert_cli_snapshot!("current", @r###" + tiny 3.1.0 + dummy ref:master + "###); } #[test] fn test_current_with_runtimes() { - assert_cli_snapshot!("current", "tiny"); + assert_cli_snapshot!("current", "tiny", @"3.1.0"); } #[test] @@ -129,7 +129,10 @@ mod tests { assert_cli!("uninstall", "dummy@1.0.1"); env::set_var("RTX_DUMMY_VERSION", "1.1.0"); - assert_cli_snapshot!("current"); + assert_cli_snapshot!("current", @r###" + dummy 1.1.0 + tiny 3.1.0 + "###); env::remove_var("RTX_DUMMY_VERSION"); } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index b291d3854..2be6dc635 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -50,9 +50,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::assert_display_snapshot; - - use crate::{assert_cli_err, assert_cli_snapshot, env}; + use crate::env; #[test] fn test_deactivate() { diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index fab6715b2..d10faf3c5 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -58,11 +58,8 @@ impl Envrc { #[cfg(test)] mod tests { - use insta::assert_display_snapshot; - - use crate::{assert_cli, file}; - use super::*; + use crate::file; #[test] fn test_direnv_envrc() { diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index a627beccd..cba06b80c 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -54,7 +54,6 @@ fn env_cmd() -> Expression { mod tests { use pretty_assertions::assert_str_eq; - use crate::assert_cli; use crate::cli::tests::grep; #[test] diff --git a/src/cli/env.rs b/src/cli/env.rs index 2ce817764..790c6f378 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -88,7 +88,6 @@ mod tests { use crate::cli::tests::grep; use crate::dirs; - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_env() { diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index dd4f2c979..d70f655b1 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -78,12 +78,9 @@ fn get_rtx_toml(filename: &str) -> Result { #[cfg(test)] mod tests { + use crate::{dirs, file}; use std::path::PathBuf; - use insta::assert_snapshot; - - use crate::{assert_cli, assert_cli_snapshot, dirs, file}; - fn remove_config_file(filename: &str) -> PathBuf { let cf_path = dirs::CURRENT.join(filename); let _ = file::remove_file(&cf_path); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index f32c3aeab..7bb71f112 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -144,8 +144,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::{assert_cli, assert_cli_err}; - use insta::assert_display_snapshot; #[test] fn test_exec_ok() { diff --git a/src/cli/global.rs b/src/cli/global.rs index 46e82fcbb..f9f3a320f 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -89,10 +89,9 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { + use crate::{dirs, file}; use pretty_assertions::assert_str_eq; - use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs, file}; - #[test] fn test_global() { let cf_path = dirs::HOME.join(".test-tool-versions"); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index cc3df1e45..c8048b23a 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,12 +1,9 @@ -use std::cmp::max; use std::env::{join_paths, split_paths}; use std::ops::Deref; use std::path::PathBuf; use color_eyre::eyre::Result; -use console::truncate_str; use itertools::Itertools; -use terminal_size::{terminal_size, Width}; use crate::config::Config; @@ -17,6 +14,7 @@ use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::shell::{get_shell, ShellType}; use crate::toolset::{Toolset, ToolsetBuilder}; +use crate::ui::truncate::screen_trunc; use crate::{env, hook_env}; /// [internal] called by activate hook to update env vars directory change @@ -71,13 +69,8 @@ impl HookEnv { .map(|(_, v)| v.to_string()) .collect_vec(); if !installed_versions.is_empty() { - let w = match terminal_size() { - Some((Width(w), _)) => w, - None => 80, - } as usize; - let w = max(w, 40); let status = installed_versions.into_iter().rev().join(" "); - rtxstatusln!("{}", truncate_str(&status, w - 4, "...")); + rtxstatusln!("{}", screen_trunc(&status)); } let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env.clone()).to_patches(); if !env_diff.is_empty() { @@ -180,7 +173,6 @@ fn patch_to_status(patch: EnvDiffOperation) -> String { #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_hook_env() { diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 167f5d129..cb3883b58 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -62,7 +62,7 @@ impl Implode { #[cfg(test)] #[cfg(test)] mod tests { - use crate::assert_cli; + use crate::dirs; #[test] diff --git a/src/cli/install.rs b/src/cli/install.rs index 4b9f3b0d1..edc01f434 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -111,8 +111,8 @@ impl Install { let mut tool_versions = vec![]; for (plugin_name, tvr, opts) in requests { let plugin = config.get_or_create_plugin(&plugin_name); - plugin.ensure_installed(Some(mpr), false)?; - let tv = tvr.resolve(plugin, opts, ts.latest_versions)?; + plugin.ensure_installed(mpr, false)?; + let tv = tvr.resolve(plugin.as_ref(), opts, ts.latest_versions)?; tool_versions.push(tv); } Ok(tool_versions) @@ -142,10 +142,9 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { + use crate::dirs; use pretty_assertions::assert_str_eq; - use crate::{assert_cli, assert_cli_snapshot, dirs}; - #[test] fn test_install_force() { assert_cli!("install", "-f", "tiny"); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 4b37e8914..95a453b25 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -5,6 +5,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::toolset::ToolVersionRequest; +use crate::ui::multi_progress_report::MultiProgressReport; /// Gets the latest available version for a plugin #[derive(Debug, clap::Args)] @@ -37,7 +38,8 @@ impl Latest { }; let plugin = config.get_or_create_plugin(&self.tool.plugin); - plugin.ensure_installed(None, false)?; + let mpr = MultiProgressReport::new(); + plugin.ensure_installed(&mpr, false)?; if let Some(v) = prefix { prefix = Some(config.resolve_alias(plugin.name(), &v)?); } @@ -66,10 +68,8 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::assert_display_snapshot; - use pretty_assertions::assert_str_eq; - use crate::{assert_cli, assert_cli_err, assert_cli_snapshot}; + use pretty_assertions::assert_str_eq; #[test] fn test_latest() { diff --git a/src/cli/link.rs b/src/cli/link.rs index 9a9b10b2b..d35b8d9d1 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -85,13 +85,18 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { use crate::file::create_dir_all; - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_link() { create_dir_all("../data/tmp/tiny").unwrap(); assert_cli!("link", "tiny@9.8.7", "../data/tmp/tiny"); - assert_cli_snapshot!("ls", "tiny"); + assert_cli_snapshot!("ls", "tiny", @r###" + tiny 1.0.1 + tiny 2.1.0 + tiny 3.0.1 + tiny 3.1.0 ~/cwd/.test-tool-versions 3 + tiny 9.8.7 (symlink) + "###); assert_cli!("uninstall", "tiny@9.8.7"); } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 90fa1ab2a..92f27ab6b 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -169,13 +169,14 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { + use std::panic; use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; use crate::test::reset_config; - use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs, file}; + use crate::{dirs, file}; #[test] fn test_local_remove() { @@ -185,9 +186,9 @@ mod tests { assert_cli_snapshot!("local", "tiny@2"); assert_cli_snapshot!("local", "--remove", "tiny"); let stdout = assert_cli!("ls", "--current"); - assert_str_eq!( + assert_snapshot!( grep(stdout, "tiny"), - "tiny 2.1.0 ~/.test-tool-versions 2" + @"tiny 2.1.0 ~/.test-tool-versions 2" ); }); } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 54c7a2d89..09924ba0b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -5,16 +5,18 @@ use std::sync::Arc; use color_eyre::eyre::Result; use console::style; -use console::Alignment::Left; use indexmap::IndexMap; use itertools::Itertools; use serde_derive::Serialize; + +use tabled::{Table, Tabled}; use versions::Versioning; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::plugins::{unalias_plugin, Plugin, PluginName}; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; +use crate::ui::table; /// List installed and/or currently selected tool versions #[derive(Debug, clap::Args)] @@ -55,6 +57,10 @@ pub struct Ls { /// Display versions matching this prefix #[clap(long, requires = "plugin")] prefix: Option, + + /// Don't display headers + #[clap(long, alias="no-headers", verbatim_doc_comment, conflicts_with_all = &["json", "parseable"])] + no_header: bool, } impl Ls { @@ -147,57 +153,22 @@ impl Ls { } fn display_user(&self, runtimes: Vec) -> Result<()> { - let output = runtimes - .into_iter() - .map(|(p, tv, source)| { - let plugin = p.name().to_string(); - let version = if let Some(symlink_path) = p.symlink_path(&tv) { - VersionStatus::Symlink(tv.version, symlink_path, source.is_some()) - } else if !p.is_version_installed(&tv) { - VersionStatus::Missing(tv.version) - } else if source.is_some() { - VersionStatus::Active(tv.version.clone(), p.is_version_outdated(&tv, p.clone())) - } else { - VersionStatus::Inactive(tv.version) - }; - let request = source.map(|source| (source.to_string(), tv.request.version())); - (plugin, version, request) - }) - .collect::>(); - let (max_plugin_len, max_version_len, max_source_len) = output.iter().fold( - (0, 0, 0), - |(max_plugin, max_version, max_source), (plugin, version, request)| { - let plugin = max_plugin.max(plugin.len()); - let version = max_version.max(version.to_plain_string().len()); - let source = match request { - Some((source, _)) => max_source.max(source.len()), - None => max_source, - }; - (plugin.min(10), version.min(15), source.min(30)) + // let data = runtimes + // .into_iter() + // .map(|(plugin, tv, source)| (plugin.to_string(), tv.to_string())) + // .collect_vec(); + let rows = runtimes.into_iter().map(|(p, tv, source)| Row { + plugin: p.clone(), + version: (p.as_ref(), &tv, &source).into(), + requested: match source.is_some() { + true => Some(tv.request.version()), + false => None, }, - ); - for (plugin, version, request) in output { - let pad = |s, len| console::pad_str(s, len, Left, None); - let plugin_extra = - ((plugin.len() as i8 - max_plugin_len as i8).max(0) as usize).min(max_version_len); - let plugin = pad(&plugin, max_plugin_len); - let plugin = style(plugin).cyan(); - let version_extra = (version.to_plain_string().len() as i8 - max_version_len as i8 - + plugin_extra as i8) - .max(0) as usize; - let version = version.to_string(); - let version = pad(&version, max_version_len - plugin_extra); - let line = match &request { - Some((source, requested)) => { - let source = pad(source, max_source_len - version_extra); - format!("{} {} {} {}", plugin, version, source, requested) - } - None => { - format!("{} {}", plugin, version) - } - }; - rtxprintln!("{}", line.trim_end()); - } + source, + }); + let mut table = Table::new(rows); + table::default_style(&mut table, self.no_header); + rtxprintln!("{}", table.to_string()); Ok(()) } @@ -267,6 +238,36 @@ struct JSONToolVersion { type RuntimeRow = (Arc, ToolVersion, Option); +#[derive(Tabled)] +#[tabled(rename_all = "PascalCase")] +struct Row { + #[tabled(display_with = "Self::display_plugin")] + plugin: Arc, + version: VersionStatus, + #[tabled(rename = "Config Source", display_with = "Self::display_source")] + source: Option, + #[tabled(display_with = "Self::display_option")] + requested: Option, +} + +impl Row { + fn display_option(arg: &Option) -> String { + match arg { + Some(s) => s.clone(), + None => String::new(), + } + } + fn display_plugin(plugin: &Arc) -> String { + style(plugin).blue().to_string() + } + fn display_source(source: &Option) -> String { + match source { + Some(source) => source.to_string(), + None => String::new(), + } + } +} + impl From for JSONToolVersion { fn from(row: RuntimeRow) -> Self { let (p, tv, source) = row; @@ -287,19 +288,16 @@ enum VersionStatus { Symlink(String, PathBuf, bool), } -impl VersionStatus { - fn to_plain_string(&self) -> String { - match self { - VersionStatus::Active(version, outdated) => { - if *outdated { - format!("{} (outdated)", version) - } else { - version.to_string() - } - } - VersionStatus::Inactive(version) => version.to_string(), - VersionStatus::Missing(version) => format!("{} (missing)", version), - VersionStatus::Symlink(version, _, _) => format!("{} (symlink)", version), +impl From<(&dyn Plugin, &ToolVersion, &Option)> for VersionStatus { + fn from((p, tv, source): (&dyn Plugin, &ToolVersion, &Option)) -> Self { + if let Some(symlink_path) = p.symlink_path(tv) { + VersionStatus::Symlink(tv.version.clone(), symlink_path, source.is_some()) + } else if !p.is_version_installed(tv) { + VersionStatus::Missing(tv.version.clone()) + } else if source.is_some() { + VersionStatus::Active(tv.version.clone(), p.is_version_outdated(tv, p)) + } else { + VersionStatus::Inactive(tv.version.clone()) } } } @@ -323,11 +321,7 @@ impl Display for VersionStatus { VersionStatus::Missing(version) => write!( f, "{} {}", - if console::colors_enabled() { - style(version).strikethrough().red().to_string() - } else { - version.to_string() - }, + style(version).strikethrough().red(), style("(missing)").red() ), VersionStatus::Symlink(version, _, active) => { @@ -378,31 +372,51 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( mod tests { use pretty_assertions::assert_str_eq; + use crate::dirs; use crate::file::remove_all; - use crate::{assert_cli, assert_cli_err, assert_cli_snapshot, dirs}; #[test] fn test_ls() { let _ = remove_all(dirs::INSTALLS.as_path()); assert_cli!("install"); - assert_cli_snapshot!("list"); + assert_cli_snapshot!("list", @r###" + dummy ref:master ~/.test-tool-versions ref:master + tiny 3.1.0 ~/cwd/.test-tool-versions 3 + "###); assert_cli!("install", "tiny@2.0.0"); - assert_cli_snapshot!("list"); + assert_cli_snapshot!("list", @r###" + dummy ref:master ~/.test-tool-versions ref:master + tiny 2.0.0 + tiny 3.1.0 ~/cwd/.test-tool-versions 3 + "###); assert_cli!("uninstall", "tiny@3.1.0"); - assert_cli_snapshot!("list"); + assert_cli_snapshot!("list", @r###" + dummy ref:master ~/.test-tool-versions ref:master + tiny 2.0.0 + tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 + "###); assert_cli!("uninstall", "tiny@2.0.0"); - assert_cli_snapshot!("list"); + assert_cli_snapshot!("list", @r###" + dummy ref:master ~/.test-tool-versions ref:master + tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 + "###); assert_cli!("install"); - assert_cli_snapshot!("list"); + assert_cli_snapshot!("list", @r###" + dummy ref:master ~/.test-tool-versions ref:master + tiny 3.1.0 ~/cwd/.test-tool-versions 3 + "###); } #[test] fn test_ls_current() { - assert_cli_snapshot!("ls", "-c"); + assert_cli_snapshot!("ls", "-c", @r###" + dummy ref:master ~/.test-tool-versions ref:master + tiny 3.1.0 ~/cwd/.test-tool-versions 3 + "###); } #[test] @@ -417,14 +431,17 @@ mod tests { fn test_ls_parseable() { let _ = remove_all(dirs::INSTALLS.as_path()); assert_cli!("install"); - assert_cli_snapshot!("ls", "--parseable"); - assert_cli_snapshot!("ls", "--parseable", "tiny"); + assert_cli_snapshot!("ls", "--parseable", @r###" + dummy ref:master + tiny 3.1.0 + "###); + assert_cli_snapshot!("ls", "--parseable", "tiny", @"3.1.0"); } #[test] fn test_ls_missing() { assert_cli!("install"); - assert_cli_snapshot!("ls", "--missing"); + assert_cli_snapshot!("ls", "--missing", @""); } #[test] @@ -436,6 +453,6 @@ mod tests { #[test] fn test_ls_prefix() { assert_cli!("install"); - assert_cli_snapshot!("ls", "--plugin=tiny", "--prefix=3"); + assert_cli_snapshot!("ls", "--plugin=tiny", "--prefix=3", @"tiny 3.1.0 ~/cwd/.test-tool-versions 3"); } } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 2bbd1f454..6734fbfd7 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -10,6 +10,7 @@ use crate::config::Config; use crate::plugins::Plugin; use crate::toolset::ToolVersionRequest; +use crate::ui::multi_progress_report::MultiProgressReport; /// List runtime versions available for install /// @@ -90,7 +91,8 @@ impl LsRemote { match &self.plugin { Some(tool_arg) => { let plugin = config.get_or_create_plugin(&tool_arg.plugin); - plugin.ensure_installed(None, false)?; + let mpr = MultiProgressReport::new(); + plugin.ensure_installed(&mpr, false)?; Ok(Some(plugin)) } None => Ok(None), @@ -116,7 +118,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli_snapshot; #[test] fn test_list_remote() { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 508886a17..af3e1967e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,8 +1,8 @@ -use crate::cli::self_update::SelfUpdate; use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; use confique::Partial; +use crate::cli::self_update::SelfUpdate; use crate::config::{Config, SettingsPartial}; mod activate; @@ -12,6 +12,7 @@ mod asdf; mod bin_paths; mod cache; mod completion; +mod config; mod current; mod deactivate; mod direnv; @@ -64,6 +65,7 @@ pub enum Commands { BinPaths(bin_paths::BinPaths), Cache(cache::Cache), Completion(completion::Completion), + Config(config::Config), Current(current::Current), Deactivate(deactivate::Deactivate), Direnv(direnv::Direnv), @@ -114,6 +116,7 @@ impl Commands { Self::BinPaths(cmd) => cmd.run(config), Self::Cache(cmd) => cmd.run(), Self::Completion(cmd) => cmd.run(), + Self::Config(cmd) => cmd.run(), Self::Current(cmd) => cmd.run(config), Self::Deactivate(cmd) => cmd.run(config), Self::Direnv(cmd) => cmd.run(config), @@ -267,70 +270,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] pub mod tests { - use color_eyre::{Section, SectionExt}; - use crate::dirs; - use crate::env; - use crate::output::tests::{STDERR, STDOUT}; - - use super::*; - - pub fn cli_run(args: &Vec) -> Result<()> { - Config::reset(); - *env::ARGS.write().unwrap() = args.clone(); - STDOUT.lock().unwrap().clear(); - STDERR.lock().unwrap().clear(); - let config = Config::try_get()?; - Cli::new_with_external_commands(&config) - .run(args) - .with_section(|| format!("{}", args.join(" ").header("Command:")))?; - - Ok(()) - } - - #[macro_export] - macro_rules! assert_cli { - ($($args:expr),+) => {{ - let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::tests::cli_run(args).unwrap(); - let output = $crate::output::tests::STDOUT.lock().unwrap().join("\n"); - console::strip_ansi_codes(&output).trim().to_string() - }}; - } - - #[macro_export] - macro_rules! assert_cli_snapshot { - ($($args:expr),+) => {{ - let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::tests::cli_run(args).unwrap(); - let output = $crate::output::tests::STDOUT.lock().unwrap().join("\n"); - let output = console::strip_ansi_codes(&output.trim()).to_string(); - let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); - let output = $crate::test::replace_path(&output); - insta::assert_snapshot!(output); - }}; - } - - #[macro_export] - macro_rules! assert_cli_snapshot_stderr { - ($($args:expr),+) => {{ - let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::tests::cli_run(args).unwrap(); - let output = $crate::output::tests::STDERR.lock().unwrap().join("\n"); - let output = console::strip_ansi_codes(&output.trim()).to_string(); - let output = output.replace($crate::dirs::HOME.to_string_lossy().as_ref(), "~"); - let output = $crate::test::replace_path(&output); - insta::assert_snapshot!(output); - }}; - } - - #[macro_export] - macro_rules! assert_cli_err { - ($($args:expr),+) => {{ - let args = &vec!["rtx".into(), $($args.into()),+]; - $crate::cli::tests::cli_run(args).unwrap_err() - }}; - } pub fn grep(output: String, pattern: &str) -> String { output diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 46c84736d..89ad74d09 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -126,8 +126,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( mod tests { use std::env; - use crate::assert_cli_snapshot; - #[test] fn test_current() { assert_cli_snapshot!("outdated"); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index b7f8d32c2..d847ebb20 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -106,7 +106,7 @@ impl PluginsInstall { mpr.warn(format!("Plugin {} already installed", name)); mpr.warn("Use --force to install anyway".to_string()); } else { - plugin.ensure_installed(Some(mpr), true)?; + plugin.ensure_installed(mpr, true)?; } Ok(()) } @@ -158,8 +158,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli_err; - use insta::assert_display_snapshot; #[test] fn test_plugin_install_invalid_url() { diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index 21b1fc4f9..e85ce6a66 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -79,12 +79,15 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_plugin_link() { - assert_cli!("plugin", "link", "tiny-link", "../data/plugins/tiny"); - assert_cli_snapshot!("plugins", "ls"); - assert_cli!("plugin", "uninstall", "tiny-link"); + assert_cli_snapshot!("plugin", "link", "-f", "tiny-link", "../data/plugins/tiny", @""); + assert_cli_snapshot!("plugins", "ls", @r###" + dummy + tiny + tiny-link + "###); + assert_cli_snapshot!("plugin", "uninstall", "tiny-link", @""); } } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 0118f55de..b5a0abab7 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -102,7 +102,6 @@ mod tests { use pretty_assertions::assert_str_eq; use crate::cli::tests::grep; - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_plugin_list() { diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 90ffb1d51..4548f10db 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -67,7 +67,6 @@ Examples: #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_plugin_list_remote() { diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap deleted file mode 100644 index 6b2857c95..000000000 --- a/src/cli/plugins/snapshots/rtx__cli__plugins__link__tests__plugin_link.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/plugins/link.rs -expression: output ---- -dummy -tiny -tiny-link diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 6108ab26a..84d219a5d 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -72,7 +72,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_plugin_update() { diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 4eec46c3d..8f88a2b3c 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -81,7 +81,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_prune() { diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index b81866a84..6149e4507 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -43,7 +43,6 @@ impl RenderCompletion { #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_completion() { diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index bac24c20b..aeda18d0f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -109,10 +109,9 @@ fn remove_trailing_spaces(s: &str) -> String { #[cfg(test)] mod tests { + use crate::file; use std::fs; - use crate::{assert_cli, file}; - #[test] fn test_render_help() { file::write( diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 296331acf..3434e31f7 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -42,7 +42,7 @@ fn project_root() -> PathBuf { #[cfg(test)] mod tests { use crate::env::HOME; - use crate::{assert_cli, file}; + use crate::file; #[test] fn test_render_mangen() { diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 35acd7414..2bfe5bc32 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,4 +1,6 @@ use color_eyre::eyre::{eyre, Result}; +use serde_json::Value; +use std::collections::BTreeMap; use crate::config::Settings; @@ -18,7 +20,9 @@ pub struct SettingsGet { impl SettingsGet { pub fn run(self) -> Result<()> { let settings = Settings::try_get()?; - match settings.to_index_map().get(&self.setting) { + let json = settings.to_string(); + let doc: BTreeMap = serde_json::from_str(&json)?; + match doc.get(&self.setting) { Some(value) => Ok(rtxprintln!("{}", value)), None => Err(eyre!("Unknown setting: {}", self.setting)), } @@ -34,10 +38,8 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::{assert_display_snapshot, assert_snapshot}; use crate::test::reset_config; - use crate::{assert_cli, assert_cli_err}; #[test] fn test_settings_get() { diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index bab77ced0..a4c708f94 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,4 +1,6 @@ use color_eyre::eyre::Result; +use serde_json::Value; +use std::collections::BTreeMap; use crate::config::Settings; @@ -15,7 +17,9 @@ pub struct SettingsLs {} impl SettingsLs { pub fn run(self) -> Result<()> { let settings = Settings::try_get()?; - for (key, value) in settings.to_index_map() { + let json = settings.to_string(); + let doc: BTreeMap = serde_json::from_str(&json)?; + for (key, value) in doc { rtxprintln!("{} = {}", key, value); } Ok(()) @@ -31,7 +35,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli_snapshot; + use crate::test::reset_config; #[test] diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 81bf55d93..e379b3871 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -63,7 +63,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] pub mod tests { use crate::test::reset_config; - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_settings_set() { diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 962bc8838..28f158eb9 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -5,14 +5,17 @@ expression: output always_keep_download = true always_keep_install = true asdf_compat = false +color = true disable_default_shorthands = false disable_tools = [] experimental = true jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] -plugin_autoupdate_last_check_duration = 20m +plugin_autoupdate_last_check_duration = "20m" +quiet = false raw = false +shorthands_file = null trusted_config_paths = [] verbose = true yes = true diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index e963eca42..cc490dd07 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -5,14 +5,17 @@ expression: output always_keep_download = true always_keep_install = true asdf_compat = false +color = true disable_default_shorthands = false disable_tools = [] experimental = true jobs = 2 legacy_version_file = false legacy_version_file_disable_tools = [] -plugin_autoupdate_last_check_duration = 1m +plugin_autoupdate_last_check_duration = "1m" +quiet = false raw = false +shorthands_file = null trusted_config_paths = [] verbose = true yes = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index c0b5310de..a03d49070 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -29,9 +29,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::assert_snapshot; - use crate::assert_cli; use crate::test::reset_config; #[test] @@ -45,14 +43,17 @@ mod tests { always_keep_download = true always_keep_install = true asdf_compat = false + color = true disable_default_shorthands = false disable_tools = [] experimental = true jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] - plugin_autoupdate_last_check_duration = 20m + plugin_autoupdate_last_check_duration = "20m" + quiet = false raw = false + shorthands_file = null trusted_config_paths = [] verbose = true yes = true diff --git a/src/cli/shell.rs b/src/cli/shell.rs index edbbe40f3..0ec12268c 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -87,10 +87,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( mod tests { use std::env; - use insta::assert_display_snapshot; - - use crate::{assert_cli_err, assert_cli_snapshot}; - #[test] fn test_shell() { let err = assert_cli_err!("shell", "tiny@1.0.1"); diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap deleted file mode 100644 index 1ed9713ad..000000000 --- a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_list.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/asdf.rs -expression: output ---- -1.0.1 -2.1.0 -3.1.0 diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap deleted file mode 100644 index b324caf70..000000000 --- a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_other.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/asdf.rs -expression: output ---- -3.1.0 diff --git a/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap b/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap deleted file mode 100644 index f823b231b..000000000 --- a/src/cli/snapshots/rtx__cli__bin_paths__tests__bin_paths.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/bin_paths.rs -expression: output ---- -~/data/installs/tiny/3.1.0/bin -~/data/installs/dummy/ref-master/bin diff --git a/src/cli/snapshots/rtx__cli__current__tests__current.snap b/src/cli/snapshots/rtx__cli__current__tests__current.snap deleted file mode 100644 index a43a96d94..000000000 --- a/src/cli/snapshots/rtx__cli__current__tests__current.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/current.rs -expression: output ---- -tiny 3.1.0 -dummy ref:master diff --git a/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap b/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap deleted file mode 100644 index 00adbfcec..000000000 --- a/src/cli/snapshots/rtx__cli__current__tests__current_missing.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/current.rs -expression: output ---- -dummy 1.1.0 -tiny 3.1.0 diff --git a/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap b/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap deleted file mode 100644 index c26b4a741..000000000 --- a/src/cli/snapshots/rtx__cli__current__tests__current_with_runtimes.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/current.rs -expression: output ---- -3.1.0 diff --git a/src/cli/snapshots/rtx__cli__link__tests__link.snap b/src/cli/snapshots/rtx__cli__link__tests__link.snap deleted file mode 100644 index ff4c9d311..000000000 --- a/src/cli/snapshots/rtx__cli__link__tests__link.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: src/cli/link.rs -expression: output ---- -tiny 1.0.1 -tiny 2.1.0 -tiny 3.0.1 -tiny 3.1.0 ~/cwd/.test-tool-versions 3 -tiny 9.8.7 (symlink) diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap deleted file mode 100644 index 1cb3e88d6..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-2.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -dummy ref:master ~/.test-tool-versions ref:master -tiny 2.0.0 -tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap deleted file mode 100644 index f94499c4e..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-3.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -dummy ref:master ~/.test-tool-versions ref:master -tiny 2.0.0 -tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap deleted file mode 100644 index 770850e1b..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-4.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -dummy ref:master ~/.test-tool-versions ref:master -tiny 3.1.0 (missing) ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap deleted file mode 100644 index b5f49eb5d..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls-5.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -dummy ref:master ~/.test-tool-versions ref:master -tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls.snap deleted file mode 100644 index b5f49eb5d..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -dummy ref:master ~/.test-tool-versions ref:master -tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap deleted file mode 100644 index b5f49eb5d..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_current.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -dummy ref:master ~/.test-tool-versions ref:master -tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap deleted file mode 100644 index dc9a10412..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_missing.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- - diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap deleted file mode 100644 index e748bd94c..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable-2.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -3.1.0 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap deleted file mode 100644 index 60395ba27..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_parseable.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -dummy ref:master -tiny 3.1.0 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap b/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap deleted file mode 100644 index 7adc26e3b..000000000 --- a/src/cli/snapshots/rtx__cli__ls__tests__ls_prefix.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/ls.rs -expression: output ---- -tiny 3.1.0 ~/cwd/.test-tool-versions 3 diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap deleted file mode 100644 index bce780220..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_global-2.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/use.rs -expression: "file::read_to_string(&cf_path).unwrap()" ---- -[tools] -tiny = "2" - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap deleted file mode 100644 index 7d2e376ee..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_global.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/use.rs -expression: output ---- -rtx ~/config/config.toml tiny@2 diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap deleted file mode 100644 index bce780220..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-2.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/use.rs -expression: "file::read_to_string(&cf_path).unwrap()" ---- -[tools] -tiny = "2" - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap deleted file mode 100644 index 852372f08..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-3.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/use.rs -expression: output ---- -rtx ~/cwd/.test.rtx.toml tiny diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap deleted file mode 100644 index 5e8a51890..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-4.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/use.rs -expression: "file::read_to_string(&cf_path).unwrap()" ---- -[tools] -tiny = "2.1.0" - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap deleted file mode 100644 index fb50bf992..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-5.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/use.rs -expression: output ---- -rtx ~/cwd/.test.rtx.toml tiny@2 diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap deleted file mode 100644 index bce780220..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-6.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/use.rs -expression: "file::read_to_string(&cf_path).unwrap()" ---- -[tools] -tiny = "2" - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap deleted file mode 100644 index 6d0d8c5b9..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-7.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/use.rs -expression: output ---- -rtx ~/cwd/.test.rtx.toml diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap deleted file mode 100644 index 4cdc5be05..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local-8.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/use.rs -expression: "file::read_to_string(&cf_path).unwrap()" ---- - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap deleted file mode 100644 index fb50bf992..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/use.rs -expression: output ---- -rtx ~/cwd/.test.rtx.toml tiny@2 diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap deleted file mode 100644 index ee7715e8e..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions-2.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/use.rs -expression: "file::read_to_string(&cf_path).unwrap()" ---- -tiny 3 - diff --git a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap b/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap deleted file mode 100644 index e91afc5c9..000000000 --- a/src/cli/snapshots/rtx__cli__r#use__tests__use_local_tool_versions.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/use.rs -expression: output ---- -rtx ~/cwd/.test-tool-versions tiny@3 diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 148933e35..57d866445 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -52,7 +52,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli; #[test] fn test_pyenv() { diff --git a/src/cli/trust.rs b/src/cli/trust.rs index 0c25b8e50..9a59d6cc1 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -85,7 +85,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::assert_cli_snapshot; #[test] fn test_trust() { diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 804326c2f..a15d25f1c 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -99,14 +99,14 @@ impl Uninstall { .filter(|v| v.starts_with(&query)) .map(|v| { let tvr = ToolVersionRequest::new(tool.name().into(), &v); - let tv = ToolVersion::new(tool.clone(), tvr, Default::default(), v); + let tv = ToolVersion::new(tool.as_ref(), tvr, Default::default(), v); (tool.clone(), tv) }) .collect::>(); if let Some(tvr) = &a.tvr { tvs.push(( tool.clone(), - tvr.resolve(tool.clone(), Default::default(), false)?, + tvr.resolve(tool.as_ref(), Default::default(), false)?, )); } if tvs.is_empty() { diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index b197756fe..b9e32f74b 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -130,7 +130,7 @@ type OutputVec = Vec<(Arc, ToolVersion, String)>; #[cfg(test)] pub mod tests { use crate::test::reset_config; - use crate::{assert_cli_snapshot, dirs, file}; + use crate::{dirs, file}; #[test] fn test_upgrade() { diff --git a/src/cli/use.rs b/src/cli/use.rs index 371f00e44..fa69653c3 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -58,7 +58,7 @@ pub struct Use { /// Remove the tool(s) from config file #[clap(long, value_name = "TOOL", aliases = ["rm", "unset"])] - remove: Option>, + remove: Vec, /// Specify a path to a config file or directory /// If a directory is specified, it will look for .rtx.toml (default) or .tool-versions @@ -112,17 +112,11 @@ impl Use { if self.global { self.warn_if_hidden(config, cf.get_path()); } - for plugin_name in self.remove.unwrap_or_default() { - cf.remove_plugin(&plugin_name); + for plugin_name in &self.remove { + cf.remove_plugin(plugin_name); } cf.save()?; - let tools = self.tool.iter().map(|t| t.to_string()).join(" "); - rtxprintln!( - "{} {} {}", - style("rtx").dim(), - display_path(cf.get_path()), - style(tools).cyan() - ); + self.render_success_message(cf.as_ref()); Ok(()) } @@ -157,6 +151,19 @@ impl Use { } } } + + fn render_success_message(&self, cf: &dyn ConfigFile) { + let path = display_path(cf.get_path()); + let (dir, file) = path.rsplit_once('/').unwrap_or(("", &path)); + let tools = self.tool.iter().map(|t| t.to_string()).join(" "); + rtxprintln!( + "\n{} {}{} updated with tools: {}\n", + style("rtx").green(), + style(dir.to_owned() + "/").dim(), + file, + style(tools).cyan() + ); + } } fn global_file() -> PathBuf { @@ -203,27 +210,34 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::assert_snapshot; - - use crate::{assert_cli_snapshot, dirs, file}; + use crate::{dirs, file}; #[test] fn test_use_local() { let cf_path = dirs::CURRENT.join(".test.rtx.toml"); file::write(&cf_path, "").unwrap(); - assert_cli_snapshot!("use", "tiny@2"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_cli_snapshot!("use", "tiny@2", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny@2"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = "2" + "###); - assert_cli_snapshot!("use", "--pin", "tiny"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_cli_snapshot!("use", "--pin", "tiny", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = "2.1.0" + "###); - assert_cli_snapshot!("use", "--fuzzy", "tiny@2"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_cli_snapshot!("use", "--fuzzy", "tiny@2", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny@2"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = "2" + "###); let p = cf_path.to_string_lossy().to_string(); - assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p, @"rtx ~/cwd/.test.rtx.toml updated with tools:"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @""); let _ = file::remove_file(&cf_path); } @@ -233,8 +247,10 @@ mod tests { let cf_path = dirs::CURRENT.join(".test-tool-versions"); file::write(&cf_path, "").unwrap(); - assert_cli_snapshot!("use", "tiny@3"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_cli_snapshot!("use", "tiny@3", @"rtx ~/cwd/.test-tool-versions updated with tools: tiny@3"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + tiny 3 + "###); } #[test] @@ -243,8 +259,11 @@ mod tests { let orig = file::read_to_string(&cf_path).unwrap(); let _ = file::remove_file(&cf_path); - assert_cli_snapshot!("use", "-g", "tiny@2"); - assert_snapshot!(file::read_to_string(&cf_path).unwrap()); + assert_cli_snapshot!("use", "-g", "tiny@2", @"rtx ~/config/config.toml updated with tools: tiny@2"); + assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [tools] + tiny = "2" + "###); file::write(&cf_path, orig).unwrap(); } diff --git a/src/cli/version.rs b/src/cli/version.rs index e1bf552e9..db8cda817 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -131,8 +131,6 @@ fn get_latest_version_call() -> Option { mod tests { use pretty_assertions::assert_str_eq; - use crate::assert_cli; - use super::*; #[test] diff --git a/src/cli/where.rs b/src/cli/where.rs index 95455245f..9e00ad0ed 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -52,7 +52,7 @@ impl Where { match runtime .tvr .as_ref() - .map(|tvr| tvr.resolve(plugin.clone(), Default::default(), false)) + .map(|tvr| tvr.resolve(plugin.as_ref(), Default::default(), false)) { Some(Ok(tv)) if plugin.is_version_installed(&tv) => { rtxprintln!("{}", tv.install_path().to_string_lossy()); @@ -82,11 +82,9 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use insta::assert_display_snapshot; - use pretty_assertions::assert_str_eq; - use crate::{assert_cli, assert_cli_err}; - use crate::{assert_cli_snapshot, dirs}; + use crate::dirs; + use pretty_assertions::assert_str_eq; #[test] fn test_where() { diff --git a/src/cli/which.rs b/src/cli/which.rs index e0c1592cb..0bc2c70fb 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -70,7 +70,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::{assert_cli, assert_cli_snapshot}; #[test] fn test_which() { diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index c77ea4a78..e3b2888b6 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -1,5 +1,4 @@ use std::default::Default; -use std::fmt::Display; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -62,9 +61,3 @@ impl ConfigFile for LegacyVersionFile { &self.toolset } } - -impl Display for LegacyVersionFile { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "LegacyVersionFile({})", self.path.display()) - } -} diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 6f3c79722..938bed10c 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -29,7 +29,7 @@ pub enum ConfigFileType { LegacyVersion, } -pub trait ConfigFile: Debug + Display + Send + Sync { +pub trait ConfigFile: Debug + Send + Sync { fn get_type(&self) -> ConfigFileType; fn get_path(&self) -> &Path; fn plugins(&self) -> HashMap { @@ -94,7 +94,7 @@ impl dyn ConfigFile { if pin { let plugin = config.get_or_create_plugin(&plugin); let tv = - tvr.resolve(plugin.clone(), Default::default(), ts.latest_versions)?; + tvr.resolve(plugin.as_ref(), Default::default(), ts.latest_versions)?; Ok(tv.version) } else { Ok(tvr.version()) @@ -214,6 +214,13 @@ fn detect_config_file_type(path: &Path) -> Option { } } +impl Display for dyn ConfigFile { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let toolset = self.to_toolset().to_string(); + write!(f, "{}: {toolset}", &display_path(self.get_path())) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 756db85bc..4b4b5c00b 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fmt::{Debug, Display, Formatter}; +use std::fmt::{Debug, Formatter}; use std::path::{Path, PathBuf}; use std::sync::Mutex; @@ -57,11 +57,11 @@ impl RtxToml { } pub fn from_file(path: &Path) -> Result { - trace!("parsing: {}", path.display()); + trace!("parsing: {}", display_path(path)); let mut rf = Self::init(path); let body = file::read_to_string(path).suggestion("ensure file exists and can be read")?; rf.parse(&body)?; - trace!("{rf}"); + trace!("{}", rf.dump()); Ok(rf) } @@ -576,12 +576,6 @@ impl RtxToml { } } -impl Display for RtxToml { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.dump()) - } -} - impl ConfigFile for RtxToml { fn get_type(&self) -> ConfigFileType { ConfigFileType::RtxToml @@ -721,12 +715,13 @@ impl ConfigFile for RtxToml { impl Debug for RtxToml { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut d = f.debug_struct("RtxToml"); - d.field("path", &self.path) - .field("toolset", &self.toolset.to_string()) - .field("is_trusted", &self.is_trusted); + let tools = self.toolset.to_string(); + let title = format!("RtxToml({}): {tools}", &display_path(&self.path)); + let mut d = f.debug_struct(&title); + // d.field("is_trusted", &self.is_trusted); if let Ok(settings) = self.settings() { - d.field("settings", &settings); + let json = serde_json::to_value(settings).unwrap_or_default(); + d.field("settings", &json); } if let Some(env_file) = &self.env_file { d.field("env_file", env_file); @@ -771,8 +766,6 @@ impl Clone for RtxToml { #[cfg(test)] mod tests { - use insta::{assert_debug_snapshot, assert_display_snapshot, assert_snapshot}; - use crate::dirs; use crate::test::replace_path; @@ -783,12 +776,12 @@ mod tests { let cf = RtxToml::from_file(&dirs::HOME.join("fixtures/.rtx.toml")).unwrap(); assert_debug_snapshot!(cf.env()); - assert_debug_snapshot!(cf.settings()); + assert_json_snapshot!(cf.settings().unwrap()); assert_debug_snapshot!(cf.plugins()); assert_snapshot!(replace_path(&format!("{:#?}", cf.toolset))); assert_debug_snapshot!(cf.alias); - assert_snapshot!(replace_path(&cf.to_string())); + assert_snapshot!(replace_path(&format!("{:#?}", &cf))); } #[test] @@ -806,27 +799,37 @@ mod tests { } "###); assert_debug_snapshot!(cf.path_dirs(), @"[]"); - assert_display_snapshot!(cf); + let cf: Box = Box::new(cf); + with_settings!({ + assert_snapshot!(cf.dump()); + assert_display_snapshot!(cf); + assert_debug_snapshot!(cf); + }); } #[test] fn test_path_dirs() { - let p = dirs::HOME.join("fixtures/.rtx.toml"); - let mut cf = RtxToml::init(&p); - cf.parse(&formatdoc! {r#" - env_path=["/foo", "./bar"] - [env] - foo="bar" - "#}) - .unwrap(); - - assert_debug_snapshot!(cf.env(), @r###" - { - "foo": "bar", - } - "###); - assert_snapshot!(replace_path(&format!("{:?}", cf.path_dirs())), @r###"["/foo", "~/fixtures/bar"]"###); - assert_display_snapshot!(cf); + with_settings!({ + let p = dirs::HOME.join("fixtures/.rtx.toml"); + let mut cf = RtxToml::init(&p); + cf.parse(&formatdoc! {r#" + env_path=["/foo", "./bar"] + [env] + foo="bar" + "#}) + .unwrap(); + + assert_debug_snapshot!(cf.env(), @r###" + { + "foo": "bar", + } + "###); + assert_snapshot!(replace_path(&format!("{:?}", cf.path_dirs())), @r###"["/foo", "~/fixtures/bar"]"###); + let cf: Box = Box::new(cf); + assert_snapshot!(cf.dump()); + assert_display_snapshot!(cf); + assert_debug_snapshot!(cf); + }); } #[test] @@ -844,6 +847,7 @@ mod tests { cf.set_alias("python", "3.10", "3.10.0"); assert_debug_snapshot!(cf.alias); + let cf: Box = Box::new(cf); assert_display_snapshot!(cf); } @@ -863,7 +867,10 @@ mod tests { cf.remove_alias("python", "3.10"); assert_debug_snapshot!(cf.alias); + let cf: Box = Box::new(cf); + assert_snapshot!(cf.dump()); assert_display_snapshot!(cf); + assert_debug_snapshot!(cf); } #[test] @@ -880,7 +887,10 @@ mod tests { ); assert_debug_snapshot!(cf.toolset); + let cf: Box = Box::new(cf); + assert_snapshot!(cf.dump()); assert_display_snapshot!(cf); + assert_debug_snapshot!(cf); } #[test] @@ -894,7 +904,10 @@ mod tests { cf.remove_plugin(&PluginName::from("node")); assert_debug_snapshot!(cf.toolset); + let cf: Box = Box::new(cf); + assert_snapshot!(cf.dump()); assert_display_snapshot!(cf); + assert_debug_snapshot!(cf); } #[test] diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap index 8913bebf1..4b149823d 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf +expression: cf.dump() --- [env] foo="bar" diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-4.snap similarity index 79% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-2.snap rename to src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-4.snap index 8913bebf1..8a3782775 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-4.snap @@ -2,6 +2,4 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- -[env] -foo="bar" - +/tmp/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap new file mode 100644 index 000000000..669b186d2 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap @@ -0,0 +1,28 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +RtxToml(/tmp/.rtx.toml): { + settings: Object { + "always_keep_download": Null, + "always_keep_install": Null, + "asdf_compat": Null, + "color": Null, + "disable_default_shorthands": Null, + "disable_tools": Null, + "experimental": Null, + "jobs": Null, + "legacy_version_file": Null, + "legacy_version_file_disable_tools": Null, + "plugin_autoupdate_last_check_duration": Null, + "quiet": Null, + "raw": Null, + "shorthands_file": Null, + "trusted_config_paths": Null, + "verbose": Null, + "yes": Null, + }, + env: { + "foo": "bar", + }, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index f05f3ecb0..189db46c9 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -1,34 +1,27 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf.settings() +expression: cf.settings().unwrap() --- -Ok( - PartialSettings { - experimental: None, - always_keep_download: None, - always_keep_install: None, - legacy_version_file: None, - legacy_version_file_disable_tools: Some( - { - "disabled_tool_from_legacy_file", - }, - ), - plugin_autoupdate_last_check_duration: None, - trusted_config_paths: None, - verbose: Some( - true, - ), - quiet: None, - asdf_compat: None, - jobs: None, - shorthands_file: None, - disable_default_shorthands: None, - disable_tools: Some( - { - "disabled_tool", - }, - ), - raw: None, - yes: None, - }, -) +{ + "experimental": null, + "color": null, + "always_keep_download": null, + "always_keep_install": null, + "legacy_version_file": null, + "legacy_version_file_disable_tools": [ + "disabled_tool_from_legacy_file" + ], + "plugin_autoupdate_last_check_duration": null, + "trusted_config_paths": null, + "verbose": true, + "quiet": null, + "asdf_compat": null, + "jobs": null, + "shorthands_file": null, + "disable_default_shorthands": null, + "disable_tools": [ + "disabled_tool" + ], + "raw": null, + "yes": null +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index 663df16c6..f429e0d9f 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -1,28 +1,40 @@ --- source: src/config/config_file/rtx_toml.rs -expression: replace_path(&cf.to_string()) +expression: "replace_path(&format!(\"{:#?}\", & cf))" --- -[env] -NODE_ENV = 'production' - -[tools] -terraform = '1.0.0' -node = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18'] -jq = { prefix = '1.6' } -shellcheck = { version = '0.9.0' } -python = [ - { version = '3.10.0', venv = '.venv' }, - { version = '3.9.0' }, -] - -[plugins] -node = 'https://github.com/jdx/rtx-node' - -[settings] -verbose = true -disable_tools = ['disabled_tool'] -legacy_version_file_disable_tools = ['disabled_tool_from_legacy_file'] - -[alias.node] -my_custom_node = '18' - +RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { + settings: Object { + "always_keep_download": Null, + "always_keep_install": Null, + "asdf_compat": Null, + "color": Null, + "disable_default_shorthands": Null, + "disable_tools": Array [ + String("disabled_tool"), + ], + "experimental": Null, + "jobs": Null, + "legacy_version_file": Null, + "legacy_version_file_disable_tools": Array [ + String("disabled_tool_from_legacy_file"), + ], + "plugin_autoupdate_last_check_duration": Null, + "quiet": Null, + "raw": Null, + "shorthands_file": Null, + "trusted_config_paths": Null, + "verbose": Bool(true), + "yes": Null, + }, + env: { + "NODE_ENV": "production", + }, + alias: { + "node": { + "my_custom_node": "18", + }, + }, + plugins: { + "node": "https://github.com/jdx/rtx-node", + }, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap index c890b0931..769507ed1 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf +expression: cf.dump() --- env_path=["/foo", "./bar"] [env] diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap similarity index 57% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap rename to src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap index a62bbc53c..74cc3c1ca 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap @@ -2,7 +2,4 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- -[env] -foo="bar" -PATH=["/foo", "./bar", "$PATH"] - +~/fixtures/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap new file mode 100644 index 000000000..e98f35fb6 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap @@ -0,0 +1,32 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +RtxToml(~/fixtures/.rtx.toml): { + settings: Object { + "always_keep_download": Null, + "always_keep_install": Null, + "asdf_compat": Null, + "color": Null, + "disable_default_shorthands": Null, + "disable_tools": Null, + "experimental": Null, + "jobs": Null, + "legacy_version_file": Null, + "legacy_version_file_disable_tools": Null, + "plugin_autoupdate_last_check_duration": Null, + "quiet": Null, + "raw": Null, + "shorthands_file": Null, + "trusted_config_paths": Null, + "verbose": Null, + "yes": Null, + }, + env: { + "foo": "bar", + }, + path_dirs: [ + "/foo", + "~/fixtures/bar", + ], +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap index abcf56e9b..e34c0b3bd 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf +expression: cf.dump() --- [alias.node] 18 = "18.0.0" diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap new file mode 100644 index 000000000..8a3782775 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +/tmp/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap new file mode 100644 index 000000000..a57323b23 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap @@ -0,0 +1,30 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +RtxToml(/tmp/.rtx.toml): { + settings: Object { + "always_keep_download": Null, + "always_keep_install": Null, + "asdf_compat": Null, + "color": Null, + "disable_default_shorthands": Null, + "disable_tools": Null, + "experimental": Null, + "jobs": Null, + "legacy_version_file": Null, + "legacy_version_file_disable_tools": Null, + "plugin_autoupdate_last_check_duration": Null, + "quiet": Null, + "raw": Null, + "shorthands_file": Null, + "trusted_config_paths": Null, + "verbose": Null, + "yes": Null, + }, + alias: { + "node": { + "18": "18.0.0", + }, + }, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap index def19a35d..54880bbc6 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap @@ -1,5 +1,5 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf +expression: cf.dump() --- diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap new file mode 100644 index 000000000..8a3782775 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +/tmp/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap new file mode 100644 index 000000000..f151f9cca --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap @@ -0,0 +1,25 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +RtxToml(/tmp/.rtx.toml): { + settings: Object { + "always_keep_download": Null, + "always_keep_install": Null, + "asdf_compat": Null, + "color": Null, + "disable_default_shorthands": Null, + "disable_tools": Null, + "experimental": Null, + "jobs": Null, + "legacy_version_file": Null, + "legacy_version_file_disable_tools": Null, + "plugin_autoupdate_last_check_duration": Null, + "quiet": Null, + "raw": Null, + "shorthands_file": Null, + "trusted_config_paths": Null, + "verbose": Null, + "yes": Null, + }, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap index c4451e3e5..d09f9ef21 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/rtx_toml.rs -expression: cf +expression: cf.dump() --- [tools] node = ["16.0.1", "18.0.1"] diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap new file mode 100644 index 000000000..4b1488a04 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +/tmp/.rtx.toml: node@16.0.1 node@18.0.1 diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap new file mode 100644 index 000000000..84363c803 --- /dev/null +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap @@ -0,0 +1,25 @@ +--- +source: src/config/config_file/rtx_toml.rs +expression: cf +--- +RtxToml(/tmp/.rtx.toml): node@16.0.1 node@18.0.1 { + settings: Object { + "always_keep_download": Null, + "always_keep_install": Null, + "asdf_compat": Null, + "color": Null, + "disable_default_shorthands": Null, + "disable_tools": Null, + "experimental": Null, + "jobs": Null, + "legacy_version_file": Null, + "legacy_version_file_disable_tools": Null, + "plugin_autoupdate_last_check_duration": Null, + "quiet": Null, + "raw": Null, + "shorthands_file": Null, + "trusted_config_paths": Null, + "verbose": Null, + "yes": Null, + }, +} diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap index 1489c70df..8a3782775 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap @@ -2,11 +2,4 @@ source: src/config/config_file/rtx_toml.rs expression: cf --- -[alias.node] -16 = "16.0.0" -18 = "18.0.1" -20 = "20.0.0" - -[alias.python] -"3.10" = "3.10.0" - +/tmp/.rtx.toml: diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 48b7ae445..1b1621744 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -200,10 +200,9 @@ impl ConfigFile for ToolVersions { #[cfg(test)] pub(crate) mod tests { - use insta::{assert_display_snapshot, assert_snapshot}; - use pretty_assertions::assert_eq; - use crate::{assert_cli, dirs}; + use crate::dirs; + use pretty_assertions::assert_eq; use super::*; diff --git a/src/config/mod.rs b/src/config/mod.rs index 917674713..cbe8e5732 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -499,7 +499,6 @@ impl Display for Config { #[cfg(test)] mod tests { - use insta::assert_display_snapshot; use super::*; diff --git a/src/config/settings.rs b/src/config/settings.rs index 6cd3dd983..5c49dc1bb 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,22 +1,25 @@ use confique::env::parse::{list_by_colon, list_by_comma}; use eyre::Result; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeSet; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; use std::sync::{Arc, Once, RwLock}; use confique::{Builder, Config, Partial}; use log::LevelFilter; -use serde_derive::{Deserialize, Serialize}; +use serde::ser::Error; +use serde_derive::Serialize; use crate::env; -#[derive(Config, Debug, Clone)] -#[config(partial_attr(derive(Debug, Clone)))] +#[derive(Config, Debug, Clone, Serialize)] +#[config(partial_attr(derive(Clone, Serialize)))] pub struct Settings { #[config(env = "RTX_EXPERIMENTAL", default = false)] pub experimental: bool, + #[config(env = "RTX_COLOR", default = true)] + pub color: bool, #[config(env = "RTX_ALWAYS_KEEP_DOWNLOAD", default = false)] pub always_keep_download: bool, #[config(env = "RTX_ALWAYS_KEEP_INSTALL", default = false)] @@ -73,6 +76,10 @@ impl Settings { settings.verbose = true; settings.jobs = 1; } + if !settings.color { + console::set_colors_enabled(false); + console::set_colors_enabled_stderr(false); + } let settings = Arc::new(Self::default_builder().load()?); *SETTINGS.write().unwrap() = Some(settings.clone()); Ok(settings) @@ -101,65 +108,11 @@ impl Settings { *SETTINGS.write().unwrap() = None; } pub fn default_builder() -> Builder { - let mut b = Self::builder(); + let mut b = Self::builder().env(); for partial in PARTIALS.read().unwrap().iter() { b = b.preloaded(partial.clone()); } - b.env() - } - - pub fn to_index_map(&self) -> BTreeMap { - let mut map = BTreeMap::new(); - map.insert("experimental".to_string(), self.experimental.to_string()); - map.insert( - "always_keep_download".to_string(), - self.always_keep_download.to_string(), - ); - map.insert( - "always_keep_install".to_string(), - self.always_keep_install.to_string(), - ); - map.insert( - "legacy_version_file".to_string(), - self.legacy_version_file.to_string(), - ); - map.insert( - "legacy_version_file_disable_tools".to_string(), - format!( - "{:?}", - self.legacy_version_file_disable_tools - .iter() - .collect::>() - ), - ); - map.insert( - "plugin_autoupdate_last_check_duration".to_string(), - self.plugin_autoupdate_last_check_duration.to_string(), - ); - map.insert( - "trusted_config_paths".to_string(), - format!("{:?}", self.trusted_config_paths.iter().collect::>()), - ); - map.insert("verbose".into(), self.verbose.to_string()); - map.insert("asdf_compat".into(), self.asdf_compat.to_string()); - map.insert("jobs".into(), self.jobs.to_string()); - if let Some(shorthands_file) = &self.shorthands_file { - map.insert( - "shorthands_file".into(), - shorthands_file.to_string_lossy().to_string(), - ); - } - map.insert( - "disable_default_shorthands".into(), - self.disable_default_shorthands.to_string(), - ); - map.insert( - "disable_tools".into(), - format!("{:?}", self.disable_tools.iter().collect::>()), - ); - map.insert("raw".into(), self.raw.to_string()); - map.insert("yes".into(), self.yes.to_string()); - map + b } #[cfg(test)] @@ -167,30 +120,19 @@ impl Settings { PARTIALS.write().unwrap().clear(); *SETTINGS.write().unwrap() = None; } -} -impl Display for Settings { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.to_index_map().fmt(f) + pub fn ensure_experimental(&self) -> Result<()> { + let msg = "This command is experimental. Enable it with `rtx config set experimental 1`"; + ensure!(self.experimental, msg); + Ok(()) } } -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum MissingRuntimeBehavior { - AutoInstall, - Prompt, - Warn, - Ignore, -} - -impl Display for MissingRuntimeBehavior { +impl Display for Settings { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - MissingRuntimeBehavior::AutoInstall => write!(f, "autoinstall"), - MissingRuntimeBehavior::Prompt => write!(f, "prompt"), - MissingRuntimeBehavior::Warn => write!(f, "warn"), - MissingRuntimeBehavior::Ignore => write!(f, "ignore"), + match serde_json::to_string_pretty(self) { + Ok(s) => write!(f, "{}", s), + Err(e) => std::fmt::Result::Err(std::fmt::Error::custom(e)), } } } diff --git a/src/direnv.rs b/src/direnv.rs index bfdb8cb14..825b19494 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -111,7 +111,6 @@ impl Display for DirenvDiff { #[cfg(test)] mod tests { - use insta::assert_display_snapshot; use super::*; diff --git a/src/env.rs b/src/env.rs index 71e0528bc..73fc3f53c 100644 --- a/src/env.rs +++ b/src/env.rs @@ -7,6 +7,7 @@ use std::time::Duration; use itertools::Itertools; use log::LevelFilter; use once_cell::sync::Lazy; + use url::Url; use crate::duration::HOURLY; @@ -59,6 +60,16 @@ pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) }); +#[cfg(test)] +pub static TERM_WIDTH: Lazy = Lazy::new(|| 80); + +#[cfg(not(test))] +pub static TERM_WIDTH: Lazy = Lazy::new(|| { + terminal_size::terminal_size() + .map(|(w, _)| w.0 as usize) + .unwrap_or(80) +}); + /// duration that remote version cache is kept for /// for "fast" commands (represented by PREFER_STALE), these are always /// cached. For "slow" commands like `rtx ls-remote` or `rtx install`: diff --git a/src/env_diff.rs b/src/env_diff.rs index 9196348de..52f1a7c7d 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -252,7 +252,7 @@ fn normalize_escape_sequences(input: &str) -> String { #[cfg(test)] mod tests { use indexmap::indexmap; - use insta::assert_debug_snapshot; + use pretty_assertions::assert_str_eq; use crate::dirs; diff --git a/src/hash.rs b/src/hash.rs index 223b23c18..e4d005f59 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -48,7 +48,6 @@ pub fn parse_shasums(text: &str) -> HashMap { #[cfg(test)] mod tests { - use insta::assert_snapshot; use super::*; diff --git a/src/main.rs b/src/main.rs index 059ba9964..64aeee7b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,12 @@ extern crate log; extern crate eyre; #[macro_use] extern crate indoc; +#[cfg(test)] +#[macro_use] +extern crate insta; +#[cfg(test)] +#[macro_use] +mod test; use std::process::exit; @@ -55,8 +61,6 @@ mod shell; mod shims; mod shorthands; pub mod tera; -#[cfg(test)] -mod test; pub mod timeout; mod toml; mod toolset; diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index d4b980da8..18543bcd0 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -115,6 +115,13 @@ impl PythonPlugin { pr: Option<&dyn SingleReport>, ) -> Result> { if let Some(virtualenv) = tv.opts.get("virtualenv") { + let settings = Settings::try_get()?; + if !settings.experimental { + warn!( + "please enable experimental mode with `rtx config set experimental true` \ + to use python virtualenv activation" + ); + } let mut virtualenv: PathBuf = file::replace_path(Path::new(virtualenv)); if !virtualenv.is_absolute() { // TODO: use the path of the config file that specified python, not the top one like this @@ -230,22 +237,15 @@ impl Plugin for PythonPlugin { _ts: &Toolset, tv: &ToolVersion, ) -> Result> { - let hm = match self.get_virtualenv(config, tv, None) { - Err(e) => { - warn!("failed to get virtualenv: {e}"); - HashMap::new() + let mut hm = HashMap::new(); + match self.get_virtualenv(config, tv, None) { + Err(e) => warn!("failed to get virtualenv: {e}"), + Ok(Some(virtualenv)) => { + let bin = virtualenv.join("bin"); + hm.insert("VIRTUAL_ENV".into(), virtualenv.to_string_lossy().into()); + hm.insert("RTX_ADD_PATH".into(), bin.to_string_lossy().into()); } - Ok(Some(virtualenv)) => HashMap::from([ - ( - "VIRTUAL_ENV".to_string(), - virtualenv.to_string_lossy().to_string(), - ), - ( - "RTX_ADD_PATH".to_string(), - virtualenv.join("bin").to_string_lossy().to_string(), - ), - ]), - Ok(None) => HashMap::new(), + Ok(None) => {} }; Ok(hm) } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 3c568ad00..8e7275245 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -344,23 +344,13 @@ impl ExternalPlugin { for (key, value) in &config.env { sm = sm.with_env(key, value.clone()); } + let install = tv.install_path().to_string_lossy().to_string(); + let download = tv.download_path().to_string_lossy().to_string(); sm = sm - .with_env( - "RTX_INSTALL_PATH", - tv.install_path().to_string_lossy().to_string(), - ) - .with_env( - "ASDF_INSTALL_PATH", - tv.install_path().to_string_lossy().to_string(), - ) - .with_env( - "RTX_DOWNLOAD_PATH", - tv.download_path().to_string_lossy().to_string(), - ) - .with_env( - "ASDF_DOWNLOAD_PATH", - tv.download_path().to_string_lossy().to_string(), - ) + .with_env("RTX_INSTALL_PATH", &install) + .with_env("ASDF_INSTALL_PATH", install) + .with_env("RTX_DOWNLOAD_PATH", &download) + .with_env("ASDF_DOWNLOAD_PATH", download) .with_env("RTX_INSTALL_TYPE", install_type) .with_env("ASDF_INSTALL_TYPE", install_type) .with_env("RTX_INSTALL_VERSION", install_version) @@ -453,7 +443,7 @@ impl Plugin for ExternalPlugin { self.plugin_path.exists() } - fn ensure_installed(&self, mpr: Option<&MultiProgressReport>, force: bool) -> Result<()> { + fn ensure_installed(&self, mpr: &MultiProgressReport, force: bool) -> Result<()> { let config = Config::get(); let settings = Settings::try_get()?; if !force { @@ -474,8 +464,6 @@ impl Plugin for ExternalPlugin { } } } - let _mpr = MultiProgressReport::new(); - let mpr = mpr.unwrap_or(&_mpr); let prefix = format!("plugin:{}", style(&self.name).blue().for_stderr()); let pr = mpr.add(&prefix); let _lock = self.get_lock(&self.plugin_path, force)?; @@ -523,11 +511,11 @@ impl Plugin for ExternalPlugin { if !dir.exists() { return Ok(()); } - pr.set_message(format!("removing {}", &dir.to_string_lossy())); + pr.set_message(format!("removing {}", display_path(dir))); remove_all(dir).wrap_err_with(|| { format!( "Failed to remove directory {}", - style(&dir.to_string_lossy()).cyan().for_stderr() + style(display_path(dir)).cyan().for_stderr() ) }) }; @@ -663,6 +651,7 @@ impl Plugin for ExternalPlugin { } ctx.pr.set_message("installing".into()); run_script(&Install)?; + file::remove_dir(&self.downloads_path)?; Ok(()) } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 26b0ff327..b330c8cec 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -3,7 +3,6 @@ use std::fmt::{Debug, Display}; use std::fs::File; use std::hash::Hash; use std::path::{Path, PathBuf}; -use std::sync::Arc; use clap::Command; use color_eyre::eyre::Result; @@ -79,7 +78,7 @@ pub trait Plugin: Debug + Send + Sync { } } } - fn is_version_outdated(&self, tv: &ToolVersion, p: Arc) -> bool { + fn is_version_outdated(&self, tv: &ToolVersion, p: &dyn Plugin) -> bool { let latest = match tv.latest_version(p) { Ok(latest) => latest, Err(e) => { @@ -152,7 +151,7 @@ pub trait Plugin: Debug + Send + Sync { fn is_installed(&self) -> bool { true } - fn ensure_installed(&self, _mpr: Option<&MultiProgressReport>, _force: bool) -> Result<()> { + fn ensure_installed(&self, _mpr: &MultiProgressReport, _force: bool) -> Result<()> { Ok(()) } fn update(&self, _pr: &dyn SingleReport, _git_ref: Option) -> Result<()> { @@ -213,8 +212,7 @@ pub trait Plugin: Debug + Send + Sync { if let Err(err) = file::remove_file(self.incomplete_file_path(&ctx.tv)) { debug!("error removing incomplete file: {:?}", err); } - ctx.pr.set_message("".into()); - ctx.pr.finish(); + ctx.pr.finish_with_message("installed".to_string()); Ok(()) } @@ -225,7 +223,7 @@ pub trait Plugin: Debug + Send + Sync { pr: &dyn SingleReport, dryrun: bool, ) -> Result<()> { - pr.set_message(format!("uninstall {tv}")); + pr.set_message("uninstall".into()); if !dryrun { self.uninstall_version_impl(pr, tv)?; @@ -401,8 +399,6 @@ pub enum PluginType { mod tests { use pretty_assertions::assert_str_eq; - use crate::assert_cli; - use super::*; #[test] diff --git a/src/plugins/rtx_plugin_toml.rs b/src/plugins/rtx_plugin_toml.rs index 2d13df743..116c40f91 100644 --- a/src/plugins/rtx_plugin_toml.rs +++ b/src/plugins/rtx_plugin_toml.rs @@ -101,7 +101,6 @@ impl RtxPluginToml { #[cfg(test)] mod tests { - use insta::assert_debug_snapshot; use crate::dirs; diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 0e299061b..5063b236b 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -160,7 +160,9 @@ impl ScriptManager { } pub fn run_by_line(&self, script: &Script, pr: &dyn SingleReport) -> Result<()> { - let cmd = CmdLineRunner::new(self.get_script_path(script)) + let path = self.get_script_path(script); + pr.set_message(display_path(&path)); + let cmd = CmdLineRunner::new(path.clone()) .with_pr(pr) .env_clear() .envs(&self.env); @@ -169,8 +171,7 @@ impl ScriptManager { Some(ScriptFailed(_, status)) => *status, _ => None, }; - let path = display_path(&self.get_script_path(script)); - return Err(ScriptFailed(path, status).into()); + return Err(ScriptFailed(display_path(&path), status).into()); } Ok(()) } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index b52f946d3..3140cbbbb 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -104,8 +104,6 @@ pub fn is_runtime_symlink(path: &Path) -> bool { #[cfg(test)] mod tests { - use insta::assert_debug_snapshot; - use crate::config::Config; use crate::plugins::{ExternalPlugin, PluginName}; diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 24b8ba076..01cbc68ee 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -76,7 +76,6 @@ impl Shell for Bash { #[cfg(test)] mod tests { - use insta::assert_snapshot; use crate::test::replace_path; diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 725ae1f0e..7d39e4a38 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -104,7 +104,6 @@ impl Shell for Fish { #[cfg(test)] mod tests { - use insta::assert_snapshot; use crate::test::replace_path; diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index c73ffc62d..814584ee8 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -116,7 +116,6 @@ impl Shell for Nushell { #[cfg(test)] mod tests { - use insta::assert_snapshot; use crate::test::replace_path; diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 52e8f371c..921b5b331 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -122,7 +122,6 @@ impl Shell for Xonsh { #[cfg(test)] mod tests { - use insta::assert_snapshot; use crate::test::replace_path; diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 6011db5dc..767a0fa76 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -80,7 +80,6 @@ impl Shell for Zsh { #[cfg(test)] mod tests { - use insta::assert_snapshot; use crate::test::replace_path; diff --git a/src/snapshots/rtx__build_time__tests__render_outdated_message.snap b/src/snapshots/rtx__build_time__tests__render_outdated_message.snap deleted file mode 100644 index d03ed834f..000000000 --- a/src/snapshots/rtx__build_time__tests__render_outdated_message.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/build_time.rs -expression: "console::strip_ansi_codes(&msg)" ---- -rtx rtx has not been updated in over a year. Please update to the latest version. -rtx update with: `rtx self-update` -rtx To hide this warning, set RTX_HIDE_OUTDATED_BUILD=1. diff --git a/src/test.rs b/src/test.rs index 66ae0be0c..a6125ebf4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,10 +1,16 @@ +use color_eyre::{Help, SectionExt}; use std::env::{join_paths, set_current_dir}; use std::path::PathBuf; -use crate::{env, file}; +use crate::cli::Cli; +use crate::config::Config; +use crate::output::tests::{STDERR, STDOUT}; +use crate::{dirs, env, file}; #[ctor::ctor] fn init() { + console::set_colors_enabled(false); + console::set_colors_enabled_stderr(false); if env::var("__RTX_DIFF").is_ok() { // TODO: fix this panic!("cannot run tests when rtx is activated"); @@ -75,3 +81,70 @@ pub fn replace_path(input: &str) -> String { .replace(&home, "~") .replace(&*env::RTX_EXE.to_string_lossy(), "rtx") } + +pub fn cli_run(args: &Vec) -> eyre::Result<(String, String)> { + Config::reset(); + *env::ARGS.write().unwrap() = args.clone(); + STDOUT.lock().unwrap().clear(); + STDERR.lock().unwrap().clear(); + let config = Config::try_get()?; + Cli::new_with_external_commands(&config) + .run(args) + .with_section(|| format!("{}", args.join(" ").header("Command:")))?; + let stdout = clean_output(STDOUT.lock().unwrap().join("\n")); + let stderr = clean_output(STDERR.lock().unwrap().join("\n")); + + Ok((stdout, stderr)) +} + +fn clean_output(output: String) -> String { + let output = output.trim().to_string(); + let output = console::strip_ansi_codes(&output).to_string(); + let output = output.replace(dirs::HOME.to_string_lossy().as_ref(), "~"); + let output = replace_path(&output); + output.trim().to_string() +} + +#[macro_export] +macro_rules! with_settings { + ($body:block) => {{ + let home = $crate::env::HOME.to_string_lossy().to_string(); + insta::with_settings!({sort_maps => true, filters => vec![ + (home.as_str(), "~"), + ]}, {$body}) + }} +} + +#[macro_export] +macro_rules! assert_cli_snapshot { + ($($args:expr),+, @$snapshot:literal) => { + let args = &vec!["rtx".into(), $($args.into()),+]; + let (stdout, stderr) = $crate::test::cli_run(args).unwrap(); + let output = [stdout, stderr].join("\n").trim().to_string(); + insta::assert_snapshot!(output, @$snapshot); + }; + ($($args:expr),+) => { + let args = &vec!["rtx".into(), $($args.into()),+]; + let (stdout, stderr) = $crate::test::cli_run(args).unwrap(); + let output = [stdout, stderr].join("\n").trim().to_string(); + insta::assert_snapshot!(output); + }; +} + +#[macro_export] +macro_rules! assert_cli { + ($($args:expr),+) => {{ + let args = &vec!["rtx".into(), $($args.into()),+]; + $crate::test::cli_run(args).unwrap(); + let output = $crate::output::tests::STDOUT.lock().unwrap().join("\n"); + console::strip_ansi_codes(&output).trim().to_string() + }}; +} + +#[macro_export] +macro_rules! assert_cli_err { + ($($args:expr),+) => {{ + let args = &vec!["rtx".into(), $($args.into()),+]; + $crate::test::cli_run(args).unwrap_err() + }}; +} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 47111246b..d7ca7b5b4 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -132,7 +132,7 @@ impl Toolset { .collect(); for (t, _) in &queue { if !t.is_installed() { - t.ensure_installed(Some(mpr), false)?; + t.ensure_installed(mpr, false)?; } } let queue = Arc::new(Mutex::new(queue)); @@ -153,7 +153,7 @@ impl Toolset { let prefix = format!("{}", style(&tv).cyan().for_stderr()); let ctx = InstallContext { ts, - tv: tv.request.resolve(t.clone(), tv.opts.clone(), true)?, + tv: tv.request.resolve(t.as_ref(), tv.opts.clone(), true)?, pr: mpr.add(&prefix), raw, force: opts.force, @@ -201,7 +201,7 @@ impl Toolset { Some((p, tv)) => (p.clone(), tv.clone()), None => { let tv = ToolVersionRequest::new(p.name().into(), &v) - .resolve(p.clone(), Default::default(), false) + .resolve(p.as_ref(), Default::default(), false) .unwrap(); (p.clone(), tv) } @@ -216,6 +216,12 @@ impl Toolset { Ok(versions) } + pub fn list_plugins(&self) -> Vec> { + self.list_versions_by_plugin() + .into_iter() + .map(|(p, _)| p) + .collect() + } pub fn list_versions_by_plugin(&self) -> Vec<(Arc, &Vec)> { let config = Config::get(); self.versions @@ -243,7 +249,7 @@ impl Toolset { // do not consider symlinked versions to be outdated return None; } - let latest = match tv.latest_version(t.clone()) { + let latest = match tv.latest_version(t.as_ref()) { Ok(latest) => latest, Err(e) => { warn!("Error getting latest version for {t}: {e:#}"); diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 8aa5e306d..e65fc9105 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -3,7 +3,6 @@ use std::fmt::{Display, Formatter}; use std::fs; use std::hash::{Hash, Hasher}; use std::path::PathBuf; -use std::sync::Arc; use color_eyre::eyre::Result; use versions::{Chunk, Version}; @@ -25,7 +24,7 @@ pub struct ToolVersion { impl ToolVersion { pub fn new( - tool: Arc, + tool: &dyn Plugin, request: ToolVersionRequest, opts: ToolVersionOptions, version: String, @@ -39,7 +38,7 @@ impl ToolVersion { } pub fn resolve( - tool: Arc, + tool: &dyn Plugin, request: ToolVersionRequest, opts: ToolVersionOptions, latest_versions: bool, @@ -93,7 +92,7 @@ impl ToolVersion { .join(&self.plugin_name) .join(self.tv_pathname()) } - pub fn latest_version(&self, tool: Arc) -> Result { + pub fn latest_version(&self, tool: &dyn Plugin) -> Result { let tv = self.request.resolve(tool, self.opts.clone(), true)?; Ok(tv.version) } @@ -115,7 +114,7 @@ impl ToolVersion { } fn resolve_version( - tool: Arc, + tool: &dyn Plugin, request: ToolVersionRequest, latest_versions: bool, v: &str, @@ -140,7 +139,7 @@ impl ToolVersion { _ => (), } - let build = |v| Ok(Self::new(tool.clone(), request.clone(), opts.clone(), v)); + let build = |v| Ok(Self::new(tool, request.clone(), opts.clone(), v)); if !tool.is_installed() { return build(v); } @@ -179,7 +178,7 @@ impl ToolVersion { /// resolve a version like `sub-1:12.0.0` which becomes `11.0.0`, `sub-0.1:12.1.0` becomes `12.0.0` fn resolve_sub( - tool: Arc, + tool: &dyn Plugin, request: ToolVersionRequest, latest_versions: bool, sub: &str, @@ -195,7 +194,7 @@ impl ToolVersion { } fn resolve_prefix( - tool: Arc, + tool: &dyn Plugin, request: ToolVersionRequest, prefix: &str, opts: ToolVersionOptions, @@ -209,14 +208,14 @@ impl ToolVersion { Ok(Self::new(tool, request, opts, v.to_string())) } - fn resolve_ref(tool: Arc, r: String, opts: ToolVersionOptions) -> Self { + fn resolve_ref(tool: &dyn Plugin, r: String, opts: ToolVersionOptions) -> Self { let request = ToolVersionRequest::Ref(tool.name().into(), r); let version = request.version(); Self::new(tool, request, opts, version) } fn resolve_path( - tool: Arc, + tool: &dyn Plugin, path: PathBuf, opts: ToolVersionOptions, ) -> Result { diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index b6cb2a1d8..beb2a2dfa 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -24,7 +24,7 @@ impl ToolVersionList { self.versions.clear(); let plugin = config.get_or_create_plugin(&self.plugin_name); for (tvr, opts) in &mut self.requests { - match tvr.resolve(plugin.clone(), opts.clone(), latest_versions) { + match tvr.resolve(plugin.as_ref(), opts.clone(), latest_versions) { Ok(v) => self.versions.push(v), Err(err) => warn!("failed to resolve tool version: {:#}", err), } diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 748f0e8c8..6c6909b45 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -1,6 +1,5 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use std::sync::Arc; use color_eyre::eyre::Result; @@ -73,7 +72,7 @@ impl ToolVersionRequest { pub fn resolve( &self, - plugin: Arc, + plugin: &dyn Plugin, opts: ToolVersionOptions, latest_versions: bool, ) -> Result { diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 60fe8b916..78e081de0 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,3 +1,5 @@ pub mod multi_progress_report; pub mod progress_report; pub mod prompt; +pub mod table; +pub mod truncate; diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 253d8081a..7287d2676 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,8 +1,6 @@ use crate::config::Settings; use console::style; -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use once_cell::sync::Lazy; -use std::time::Duration; +use indicatif::MultiProgress; use crate::ui::progress_report::{ProgressReport, QuietReport, SingleReport, VerboseReport}; @@ -12,15 +10,14 @@ pub struct MultiProgressReport { quiet: bool, } -static PROG_TEMPLATE: Lazy = Lazy::new(|| { - ProgressStyle::with_template("{prefix} {wide_msg} {spinner:.blue} {elapsed:3.dim.italic}") - .unwrap() -}); - impl MultiProgressReport { pub fn new() -> Self { let settings = Settings::get(); - let mp = match settings.quiet || settings.verbose || !console::user_attended_stderr() { + let mp = match settings.raw + || settings.quiet + || settings.verbose + || !console::user_attended_stderr() + { true => None, false => Some(MultiProgress::new()), }; @@ -33,11 +30,9 @@ impl MultiProgressReport { match &self.mp { _ if self.quiet => Box::new(QuietReport::new(prefix.to_string())), Some(mp) => { - let pb = ProgressBar::new(1) - .with_style(PROG_TEMPLATE.clone()) - .with_prefix(format!("{} {}", style("rtx").dim().for_stderr(), prefix)); - pb.enable_steady_tick(Duration::from_millis(250)); - Box::new(ProgressReport::new(mp.add(pb))) + let mut pr = ProgressReport::new(prefix.into()); + pr.pb = mp.add(pr.pb); + Box::new(pr) } None => Box::new(VerboseReport::new(prefix.to_string())), } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index fa19e5a83..be8925210 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,6 +1,8 @@ +use crate::config::Config; use console::style; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; +use std::time::Duration; pub trait SingleReport: Send + Sync { fn println(&self, _message: String) {} @@ -11,30 +13,70 @@ pub trait SingleReport: Send + Sync { fn finish_with_message(&self, _message: String) {} } +static PROG_TEMPLATE: Lazy = Lazy::new(|| { + ProgressStyle::with_template("{prefix} {wide_msg} {spinner:.blue} {elapsed:3.dim.italic}") + .unwrap() +}); + static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { let tmpl = format!( - "{{prefix}} {{wide_msg}} {} {{elapsed:3.dim.italic}}", + "{{prefix}} {} {{wide_msg}}", style("✓").bright().green().for_stderr() ); ProgressStyle::with_template(tmpl.as_str()).unwrap() }); static ERROR_TEMPLATE: Lazy = Lazy::new(|| { - let tmpl = format!( - "{{prefix:.red}} {{wide_msg}} {} {{elapsed:3.dim.italic}}", - style("✗").red().for_stderr() - ); + let tmpl = format!("{{prefix}} {} {{wide_msg}}", style("✗").red().for_stderr()); ProgressStyle::with_template(tmpl.as_str()).unwrap() }); #[derive(Debug)] pub struct ProgressReport { - pb: ProgressBar, + pub pb: ProgressBar, + prefix: String, + pad: usize, +} + +static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { + Config::get() + .list_plugins() + .into_iter() + .map(|p| p.name().len() + 12) + .max() + .unwrap_or_default() + .max(20) + .min(40) +}); + +fn pad_prefix(w: usize, s: &str) -> String { + console::pad_str(s, w, console::Alignment::Left, None).to_string() +} +fn normal_prefix(pad: usize, prefix: &str) -> String { + let prefix = format!("{} {prefix}", style("rtx").dim().for_stderr()); + pad_prefix(pad, &prefix) +} +fn error_prefix(pad: usize, prefix: &str) -> String { + let prefix = format!("{} {prefix}", style("rtx").red().for_stderr()); + pad_prefix(pad, &prefix) +} +fn warn_prefix(pad: usize, prefix: &str) -> String { + let prefix = format!("{} {prefix}", style("rtx").yellow().for_stderr()); + pad_prefix(pad, &prefix) +} +fn success_prefix(pad: usize, prefix: &str) -> String { + let prefix = format!("{} {prefix}", style("rtx").green().for_stderr()); + pad_prefix(pad, &prefix) } impl ProgressReport { - pub fn new(pb: ProgressBar) -> ProgressReport { - ProgressReport { pb } + pub fn new(prefix: String) -> ProgressReport { + let pad = *LONGEST_PLUGIN_NAME + 2; + let pb = ProgressBar::new(100) + .with_style(PROG_TEMPLATE.clone()) + .with_prefix(normal_prefix(pad, &prefix)); + pb.enable_steady_tick(Duration::from_millis(250)); + ProgressReport { prefix, pb, pad } } } @@ -43,16 +85,15 @@ impl SingleReport for ProgressReport { self.pb.println(message); } fn warn(&self, message: String) { - self.pb - .println(format!("{} {}", style("[WARN]").yellow(), message)); + let msg = format!("{} {message}", style("[WARN]").yellow().for_stderr()); + self.pb.set_prefix(warn_prefix(self.pad, &self.prefix)); + self.pb.println(msg); } fn error(&self, message: String) { - self.set_message(format!( - "{} {}", - style("[ERROR]").red().for_stderr(), - message - )); + let msg = format!("{} {message}", style("[ERROR]").red().for_stderr()); + self.set_message(msg); self.pb.set_style(ERROR_TEMPLATE.clone()); + self.pb.set_prefix(error_prefix(self.pad - 2, &self.prefix)); self.pb.finish(); } fn set_message(&self, message: String) { @@ -60,40 +101,56 @@ impl SingleReport for ProgressReport { } fn finish(&self) { self.pb.set_style(SUCCESS_TEMPLATE.clone()); + self.pb + .set_prefix(success_prefix(self.pad - 2, &self.prefix)); self.pb.finish() } fn finish_with_message(&self, message: String) { self.pb.set_style(SUCCESS_TEMPLATE.clone()); + self.pb + .set_prefix(success_prefix(self.pad - 2, &self.prefix)); self.pb.finish_with_message(message); } } pub struct QuietReport { prefix: String, + pad: usize, } impl QuietReport { pub fn new(prefix: String) -> QuietReport { - QuietReport { prefix } + QuietReport { + prefix, + pad: *LONGEST_PLUGIN_NAME + 2, + } } } impl SingleReport for QuietReport { fn warn(&self, message: String) { - warn!("{} {}", self.prefix, message); + let prefix = warn_prefix(self.pad - 2, &self.prefix); + let x = style("⚠").yellow().for_stderr(); + warn!("{prefix} {x} {message}"); } fn error(&self, message: String) { - error!("{} {}", self.prefix, message); + let prefix = error_prefix(self.pad - 2, &self.prefix); + let x = style("✗").red().for_stderr(); + error!("{prefix} {x} {message}"); } } pub struct VerboseReport { prefix: String, + pad: usize, } impl VerboseReport { pub fn new(prefix: String) -> VerboseReport { - VerboseReport { prefix } + VerboseReport { + prefix, + pad: *LONGEST_PLUGIN_NAME + 2, + } } } @@ -102,19 +159,26 @@ impl SingleReport for VerboseReport { eprintln!("{message}"); } fn warn(&self, message: String) { - warn!("{} {}", self.prefix, message); + let prefix = warn_prefix(self.pad - 2, &self.prefix); + let x = style("⚠").yellow().for_stderr(); + warn!("{prefix} {x} {message}"); } fn error(&self, message: String) { - error!("{} {}", self.prefix, message); + let prefix = error_prefix(self.pad - 2, &self.prefix); + let x = style("✗").red().for_stderr(); + error!("{prefix} {x} {message}"); } fn set_message(&self, message: String) { - eprintln!("{} {message}", self.prefix); + let prefix = normal_prefix(self.pad, &self.prefix); + eprintln!("{prefix} {message}"); } fn finish(&self) { - self.finish_with_message(style("done").green().to_string()); + self.finish_with_message(style("done").green().for_stderr().to_string()); } fn finish_with_message(&self, message: String) { - self.set_message(message); + let prefix = success_prefix(self.pad - 2, &self.prefix); + let ico = style("✓").bright().green().for_stderr(); + eprintln!("{prefix} {ico} {message}"); } } @@ -124,7 +188,7 @@ mod tests { #[test] fn test_progress_report() { - let pr = ProgressReport::new(ProgressBar::new(0)); + let pr = ProgressReport::new("foo".into()); pr.set_message("message".into()); pr.finish_with_message("message".into()); } diff --git a/src/ui/table.rs b/src/ui/table.rs new file mode 100644 index 000000000..05fe35f34 --- /dev/null +++ b/src/ui/table.rs @@ -0,0 +1,37 @@ +use console::style; +use tabled::settings::object::{Columns, Rows}; +use tabled::settings::peaker::PriorityMax; +use tabled::settings::width::{MinWidth, Wrap}; +use tabled::settings::{Disable, Format, Margin, Modify, Padding, Settings, Style, Width}; +use tabled::Table; + +use crate::env::TERM_WIDTH; + +type SettingPriority = Settings>; +type SettingMinWidth = Settings; +// type SettingCellHeightLimit = Settings; +// type SettingCellHeightIncrease = Settings; + +pub fn term_size_settings() -> SettingMinWidth { + Settings::default() + .with(Width::wrap(*TERM_WIDTH).priority::()) + .with(Width::increase(*TERM_WIDTH)) + // .with(Height::limit(*TERM_HEIGHT)) + // .with(Height::increase(*TERM_HEIGHT)) +} + +pub fn default_style(table: &mut Table, no_headers: bool) { + let header = |h: &_| style(h).italic().magenta().to_string(); + + if no_headers || !console::user_attended() || cfg!(test) { + table.with(Disable::row(Rows::first())); + } else { + table.with(Modify::new(Rows::first()).with(Format::content(header))); + } + table + .with(Style::empty()) + .with(term_size_settings()) + .with(Margin::new(0, 0, 0, 0)) + .with(Modify::new(Columns::first()).with(Padding::new(0, 1, 0, 0))) + .with(Modify::new(Columns::last()).with(Padding::zero())); +} diff --git a/src/ui/truncate.rs b/src/ui/truncate.rs new file mode 100644 index 000000000..bc6b61b54 --- /dev/null +++ b/src/ui/truncate.rs @@ -0,0 +1,6 @@ +use crate::env::TERM_WIDTH; +use std::borrow::Cow; + +pub fn screen_trunc(s: &str) -> Cow { + console::truncate_str(s, *TERM_WIDTH, "…") +} From 151218a7fbd607be15e08350117300621f5f8ae7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 22:51:17 -0600 Subject: [PATCH 1330/1891] various CLI improvements (#1190) * various CLI improvements * various CLI improvements * e2e test fixes --- .config/insta.yaml | 2 - README.md | 10 ++- completions/_rtx | 24 ++++--- completions/rtx.bash | 34 ++++++++- completions/rtx.fish | 2 + e2e/test_go | 1 + e2e/test_link | 2 +- e2e/test_nodejs | 3 +- src/cli/alias/ls.rs | 70 +++++++++++++------ src/cli/alias/mod.rs | 5 ++ src/cli/alias/set.rs | 17 ++++- ...tx__cli__alias__set__tests__alias_set.snap | 18 ----- ...cli__alias__unset__tests__alias_unset.snap | 17 ----- src/cli/alias/unset.rs | 16 ++++- src/cli/link.rs | 2 +- src/cli/plugins/install.rs | 2 +- src/cli/plugins/link.rs | 2 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/plugins/update.rs | 2 +- src/cli/shell.rs | 2 +- src/cli/uninstall.rs | 2 +- 22 files changed, 149 insertions(+), 88 deletions(-) delete mode 100644 src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap delete mode 100644 src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap diff --git a/.config/insta.yaml b/.config/insta.yaml index 68e8c03a3..e3d6a23b5 100644 --- a/.config/insta.yaml +++ b/.config/insta.yaml @@ -1,4 +1,2 @@ test: auto_review: true -review: - warn_undiscovered: true diff --git a/README.md b/README.md index cff1d6004..3cc4cecb8 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ v20.0.0 - [Commands](#commands) - [`rtx activate [OPTIONS] [SHELL_TYPE]`](#rtx-activate-options-shell_type) - [`rtx alias get `](#rtx-alias-get-plugin-alias) - - [`rtx alias ls [PLUGIN]`](#rtx-alias-ls-plugin) + - [`rtx alias ls [OPTIONS] [PLUGIN]`](#rtx-alias-ls-options-plugin) - [`rtx alias set `](#rtx-alias-set-plugin-alias-value) - [`rtx alias unset `](#rtx-alias-unset-plugin-alias) - [`rtx bin-paths`](#rtx-bin-paths) @@ -1702,7 +1702,7 @@ Examples: 20.0.0 ``` -### `rtx alias ls [PLUGIN]` +### `rtx alias ls [OPTIONS] [PLUGIN]` ```text List aliases @@ -1714,12 +1714,16 @@ For user config, aliases are defined like the following in `~/.config/rtx/config [alias.node] lts = "20.0.0" -Usage: alias ls [PLUGIN] +Usage: alias ls [OPTIONS] [PLUGIN] Arguments: [PLUGIN] Show aliases for +Options: + --no-header + Don't show table header + Examples: $ rtx aliases node lts-hydrogen 20.0.0 diff --git a/completions/_rtx b/completions/_rtx index 4157fa092..991c85e9d 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -34,7 +34,7 @@ _rtx() { (implode) __rtx_implode_cmd && ret=0 ;; (i|install) __rtx_install_cmd && ret=0 ;; (latest) __rtx_latest_cmd && ret=0 ;; - (link) __rtx_link_cmd && ret=0 ;; + (ln|link) __rtx_link_cmd && ret=0 ;; (l|local) __rtx_local_cmd && ret=0 ;; (list|ls) __rtx_ls_cmd && ret=0 ;; (list-all|list-remote|ls-remote) __rtx_ls_remote_cmd && ret=0 ;; @@ -44,7 +44,7 @@ _rtx() { (reshim) __rtx_reshim_cmd && ret=0 ;; (self-update) __rtx_self_update_cmd && ret=0 ;; (settings) __rtx_settings_cmd && ret=0 ;; - (s|shell) __rtx_shell_cmd && ret=0 ;; + (sh|shell) __rtx_shell_cmd && ret=0 ;; (sync) __rtx_sync_cmd && ret=0 ;; (trust) __rtx_trust_cmd && ret=0 ;; (remove|rm|uninstall) __rtx_uninstall_cmd && ret=0 ;; @@ -72,6 +72,7 @@ __rtx_activate_cmd() { __rtx_alias_cmd() { _arguments -s -S \ '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ + '--no-header[Don'\''t show table header]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ @@ -105,6 +106,7 @@ __rtx_alias_get_cmd() { __rtx_alias_ls_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ + '--no-header[Don'\''t show table header]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' @@ -440,7 +442,7 @@ __rtx_plugins_cmd() { curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" case $words[1] in (a|add|i|install) __rtx_plugins_install_cmd && ret=0 ;; - (l|link) __rtx_plugins_link_cmd && ret=0 ;; + (ln|link) __rtx_plugins_link_cmd && ret=0 ;; (list|ls) __rtx_plugins_ls_cmd && ret=0 ;; (list-all|list-remote|ls-remote) __rtx_plugins_ls_remote_cmd && ret=0 ;; (remove|rm|uninstall) __rtx_plugins_uninstall_cmd && ret=0 ;; @@ -734,7 +736,7 @@ __rtx_cmds() { 'implode:Removes rtx CLI and all related data' {i,install}':Install a tool version' 'latest:Gets the latest available version for a plugin' - 'link:Symlinks a tool version into rtx' + {ln,link}':Symlinks a tool version into rtx' {list,ls}':List installed and/or currently selected tool versions' 'ls-remote:List runtime versions available for install' 'outdated:Shows outdated tool versions' @@ -743,10 +745,10 @@ __rtx_cmds() { 'reshim:rebuilds the shim farm' 'self-update:Updates rtx itself' 'settings:Manage settings' - 'shell:Sets a tool version for the current shell session' + {sh,shell}':Sets a tool version for the current shell session' 'sync:Add tool versions from external tools to rtx' 'trust:Marks a config file as trusted' - 'uninstall:Removes runtime versions' + {remove,rm,uninstall}':Removes runtime versions' 'upgrade:Upgrades outdated tool versions' {u,use}':Change the active version of a tool locally or globally.' 'version:Show rtx version' @@ -790,12 +792,12 @@ __rtx_direnv_cmds() { (( $+functions[__rtx_plugins_cmds] )) || __rtx_plugins_cmds() { local commands; commands=( - {a,i,install}':Install a plugin' - 'link:Symlinks a plugin into rtx' + {a,add,i,install}':Install a plugin' + {ln,link}':Symlinks a plugin into rtx' {list,ls}':List installed plugins' - {list-remote,ls-remote}':List all available remote plugins' - 'uninstall:Removes a plugin' - 'update:Updates a plugin to the latest version' + {list-all,list-remote,ls-remote}':List all available remote plugins' + {remove,rm,uninstall}':Removes a plugin' + {upgrade,update}':Updates a plugin to the latest version' ) _describe -t commands 'command' commands "$@" } diff --git a/completions/rtx.bash b/completions/rtx.bash index b332c8f7f..f7e602f2b 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -90,6 +90,9 @@ _rtx() { rtx,list) cmd="rtx__ls" ;; + rtx,ln) + cmd="rtx__link" + ;; rtx,local) cmd="rtx__local" ;; @@ -111,6 +114,9 @@ _rtx() { rtx,prune) cmd="rtx__prune" ;; + rtx,remove) + cmd="rtx__uninstall" + ;; rtx,render-completion) cmd="rtx__render__completion" ;; @@ -123,12 +129,18 @@ _rtx() { rtx,reshim) cmd="rtx__reshim" ;; + rtx,rm) + cmd="rtx__uninstall" + ;; rtx,self-update) cmd="rtx__self__update" ;; rtx,settings) cmd="rtx__settings" ;; + rtx,sh) + cmd="rtx__shell" + ;; rtx,shell) cmd="rtx__shell" ;; @@ -468,6 +480,9 @@ _rtx() { rtx__plugins,a) cmd="rtx__plugins__install" ;; + rtx__plugins,add) + cmd="rtx__plugins__install" + ;; rtx__plugins,help) cmd="rtx__plugins__help" ;; @@ -483,21 +498,36 @@ _rtx() { rtx__plugins,list) cmd="rtx__plugins__ls" ;; + rtx__plugins,list-all) + cmd="rtx__plugins__ls__remote" + ;; rtx__plugins,list-remote) cmd="rtx__plugins__ls__remote" ;; + rtx__plugins,ln) + cmd="rtx__plugins__link" + ;; rtx__plugins,ls) cmd="rtx__plugins__ls" ;; rtx__plugins,ls-remote) cmd="rtx__plugins__ls__remote" ;; + rtx__plugins,remove) + cmd="rtx__plugins__uninstall" + ;; + rtx__plugins,rm) + cmd="rtx__plugins__uninstall" + ;; rtx__plugins,uninstall) cmd="rtx__plugins__uninstall" ;; rtx__plugins,update) cmd="rtx__plugins__update" ;; + rtx__plugins,upgrade) + cmd="rtx__plugins__update" + ;; rtx__plugins__help,help) cmd="rtx__plugins__help__help" ;; @@ -639,7 +669,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -q -v -y -h --plugin --debug --log-level --trace --quiet --verbose --yes --help get ls set unset help" + opts="-p -q -v -y -h --plugin --no-header --debug --log-level --trace --quiet --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -767,7 +797,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]" + opts="-q -v -y -h --no-header --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 3420999a2..1bcb72c0c 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -45,6 +45,7 @@ complete -kxc rtx -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type complete -kxc rtx -n "$fssf activate" -l status -d 'Show "rtx: @" message when changing directories' # alias +complete -kxc rtx -n "$fssf alias" -l no-header -d 'Don'\''t show table header' complete -kxc rtx -n "$fssf alias" -s p -l plugin -a "(__rtx_plugins)" -d 'filter aliases by plugin' set -l others get ls set unset complete -xc rtx -n "$fssf alias; and not $fssf $others" -a get -d 'Show an alias for a plugin' @@ -57,6 +58,7 @@ complete -kxc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_aliases)" -d 'The a complete -kxc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_plugins)" -d 'The plugin to show the alias for' # alias ls +complete -kxc rtx -n "$fssf alias; and $fssf ls" -l no-header -d 'Don'\''t show table header' complete -kxc rtx -n "$fssf alias; and $fssf ls" -a "(__rtx_plugins)" -d 'Show aliases for ' # alias set diff --git a/e2e/test_go b/e2e/test_go index 6a11a1456..14d0b9cf1 100755 --- a/e2e/test_go +++ b/e2e/test_go @@ -14,3 +14,4 @@ rtx use golang@prefix:1.20 assert_contains "rtx x -- go version" "go version go1.20" rm "$RTX_GO_DEFAULT_PACKAGES_FILE" +chmod -R u+w "$RTX_DATA_DIR/installs/go" diff --git a/e2e/test_link b/e2e/test_link index 9130bda33..6217c609c 100755 --- a/e2e/test_link +++ b/e2e/test_link @@ -5,7 +5,7 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" rtx plugins uninstall tiny -rtx p l "$ROOT/test/data/plugins/tiny" +rtx p ln "$ROOT/test/data/plugins/tiny" assert_contains "rtx p" "tiny" assert_fail "rtx p link $ROOT/test/data/plugins/tiny" rtx plugins link -f "$ROOT/test/data/plugins/tiny" diff --git a/e2e/test_nodejs b/e2e/test_nodejs index e19e06d4f..da74d15b2 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -8,7 +8,8 @@ export RTX_NODE_COREPACK=1 export RTX_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-npm-packages" rtx plugin uninstall node -rtx i node node@lts/hydrogen +rtx i node@lts/hydrogen +rtx i -f node assert_contains "rtx x node@lts/hydrogen -- node --version" "v18." assert "rtx x -- node --version" "v20.0.0" assert_contains "rtx x -- which yarn" "yarn" diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index ebfaf106b..e71c2f20c 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,8 +1,9 @@ use color_eyre::eyre::Result; +use tabled::Tabled; use crate::config::Config; - use crate::plugins::PluginName; +use crate::ui::table; /// List aliases /// Shows the aliases that can be specified. @@ -18,34 +19,44 @@ pub struct AliasLs { /// Show aliases for #[clap()] pub plugin: Option, + + /// Don't show table header + #[clap(long)] + pub no_header: bool, } impl AliasLs { pub fn run(self) -> Result<()> { let config = Config::get(); - for (plugin_name, aliases) in config.get_all_aliases() { - if let Some(plugin) = &self.plugin { - if plugin_name != plugin { - continue; - } - } - - for (from, to) in aliases.iter() { - if plugin_name == "node" && from.starts_with("lts/") { - // hide the nvm-style aliases so only asdf-style ones display - continue; - } - if self.plugin.is_some() { - rtxprintln!("{:20} {}", from, to); - } else { - rtxprintln!("{:20} {:20} {}", plugin_name, from, to); - } - } - } + let rows = config + .get_all_aliases() + .iter() + .flat_map(|(plugin, aliases)| { + aliases + .iter() + .filter(|(from, _to)| plugin != "node" || !from.starts_with("lts/")) + .map(|(from, to)| Row { + plugin: plugin.clone(), + alias: from.clone(), + version: to.clone(), + }) + .collect::>() + }) + .collect::>(); + let mut table = tabled::Table::new(rows); + table::default_style(&mut table, self.no_header); + rtxprintln!("{table}"); Ok(()) } } +#[derive(Tabled)] +struct Row { + plugin: String, + alias: String, + version: String, +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx aliases @@ -55,10 +66,23 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - #[test] fn test_alias_ls() { - let stdout = assert_cli!("aliases"); - assert!(stdout.contains("my/alias")); + assert_cli_snapshot!("aliases", @r###" + java lts 21 + node lts 20 + node lts-argon 4 + node lts-boron 6 + node lts-carbon 8 + node lts-dubnium 10 + node lts-erbium 12 + node lts-fermium 14 + node lts-gallium 16 + node lts-hydrogen 18 + node lts-iron 20 + tiny lts 3.1.0 + tiny lts-prev 2.0.0 + tiny my/alias 3.0 + "###); } } diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index 30cf763b3..6bd69ac8f 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -17,6 +17,10 @@ pub struct Alias { /// filter aliases by plugin #[clap(short, long)] pub plugin: Option, + + /// Don't show table header + #[clap(long)] + pub no_header: bool, } #[derive(Debug, Subcommand)] @@ -42,6 +46,7 @@ impl Alias { pub fn run(self) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(ls::AliasLs { plugin: self.plugin, + no_header: self.no_header, })); cmd.run() diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 199f8c8d4..dae2dfea6 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -40,7 +40,22 @@ pub mod tests { reset_config(); assert_cli!("alias", "set", "tiny", "my/alias", "3.0"); - assert_cli_snapshot!("aliases"); + assert_cli_snapshot!("aliases", @r###" + java lts 21 + node lts 20 + node lts-argon 4 + node lts-boron 6 + node lts-carbon 8 + node lts-dubnium 10 + node lts-erbium 12 + node lts-fermium 14 + node lts-gallium 16 + node lts-hydrogen 18 + node lts-iron 20 + tiny lts 3.1.0 + tiny lts-prev 2.0.0 + tiny my/alias 3.0 + "###); reset_config(); } } diff --git a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap b/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap deleted file mode 100644 index cc52c9de7..000000000 --- a/src/cli/alias/snapshots/rtx__cli__alias__set__tests__alias_set.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: src/cli/alias/set.rs -expression: output ---- -java lts 21 -node lts 20 -node lts-argon 4 -node lts-boron 6 -node lts-carbon 8 -node lts-dubnium 10 -node lts-erbium 12 -node lts-fermium 14 -node lts-gallium 16 -node lts-hydrogen 18 -node lts-iron 20 -tiny lts 3.1.0 -tiny lts-prev 2.0.0 -tiny my/alias 3.0 diff --git a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap b/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap deleted file mode 100644 index 042be8bcc..000000000 --- a/src/cli/alias/snapshots/rtx__cli__alias__unset__tests__alias_unset.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: src/cli/alias/unset.rs -expression: output ---- -java lts 21 -node lts 20 -node lts-argon 4 -node lts-boron 6 -node lts-carbon 8 -node lts-dubnium 10 -node lts-erbium 12 -node lts-fermium 14 -node lts-gallium 16 -node lts-hydrogen 18 -node lts-iron 20 -tiny lts 3.1.0 -tiny lts-prev 2.0.0 diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 19c87befe..d64843d6c 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -38,7 +38,21 @@ mod tests { reset_config(); assert_cli!("alias", "unset", "tiny", "my/alias"); - assert_cli_snapshot!("aliases"); + assert_cli_snapshot!("aliases", @r###" + java lts 21 + node lts 20 + node lts-argon 4 + node lts-boron 6 + node lts-carbon 8 + node lts-dubnium 10 + node lts-erbium 12 + node lts-fermium 14 + node lts-gallium 16 + node lts-hydrogen 18 + node lts-iron 20 + tiny lts 3.1.0 + tiny lts-prev 2.0.0 + "###); reset_config(); } diff --git a/src/cli/link.rs b/src/cli/link.rs index d35b8d9d1..9b675518c 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -16,7 +16,7 @@ use crate::{dirs, file}; /// Use this for adding installs either custom compiled outside /// rtx or built with a different tool. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "ln", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Link { /// Tool name and version to create a symlink for #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index d847ebb20..cccfd134c 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -14,7 +14,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// /// This behavior can be modified in ~/.config/rtx/config.toml #[derive(Debug, clap::Args)] -#[clap(visible_aliases = ["i", "a"], alias = "add", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_aliases = ["i", "a", "add"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct PluginsInstall { /// The name of the plugin to install /// e.g.: node, ruby diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index e85ce6a66..da85d6fcc 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -14,7 +14,7 @@ use crate::{dirs, file}; /// /// This is used for developing a plugin. #[derive(Debug, clap::Args)] -#[clap(alias = "l", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "ln", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct PluginsLink { /// The name of the plugin /// e.g.: node, ruby diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 4548f10db..c24df3294 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -8,7 +8,7 @@ use crate::config::Config; /// List all available remote plugins #[derive(Debug, clap::Args)] -#[clap(visible_alias = "list-remote", long_about = LONG_ABOUT, verbatim_doc_comment, alias = "list-all")] +#[clap(visible_aliases = ["list-remote", "list-all"], long_about = LONG_ABOUT, verbatim_doc_comment)] pub struct PluginsLsRemote { /// Show the git url for each plugin /// e.g.: https://github.com/rtx-plugins/rtx-nodejs.git diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 4ad0b32ad..493d832bf 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -8,7 +8,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Removes a plugin #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, visible_aliases = ["remove", "rm"], after_long_help = AFTER_LONG_HELP)] pub struct PluginsUninstall { /// Plugin(s) to remove #[clap(verbatim_doc_comment)] diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 84d219a5d..2b80403b8 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -11,7 +11,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// /// note: this updates the plugin itself, not the runtime versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "upgrade", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, visible_alias = "upgrade", after_long_help = AFTER_LONG_HELP)] pub struct Update { /// Plugin(s) to update #[clap()] diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 0ec12268c..874809ecd 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -10,7 +10,7 @@ use crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder}; /// /// Only works in a session where rtx is already activated. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "s", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, visible_alias = "sh", after_long_help = AFTER_LONG_HELP)] pub struct Shell { /// Tool(s) to use #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index a15d25f1c..225d798a5 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -14,7 +14,7 @@ use crate::{runtime_symlinks, shims}; /// Removes runtime versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, alias = "remove", alias = "rm", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, visible_aliases = ["remove", "rm"], after_long_help = AFTER_LONG_HELP)] pub struct Uninstall { /// Tool(s) to remove #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, required_unless_present = "all")] From 362bfcdb630f2e249d69ffa85867137e86fe7c11 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 14 Dec 2023 22:51:51 -0600 Subject: [PATCH 1331/1891] chore: Release rtx-cli version 2023.12.28 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f701d961..cbd079d06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation" @@ -1861,7 +1861,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.27" +version = "2023.12.28" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index d339de016..cdf102716 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.27" +version = "2023.12.28" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 3cc4cecb8..fb790ff74 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.27 +rtx 2023.12.28 ``` Hook rtx into your shell (pick the right one for your shell): @@ -357,7 +357,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.27/rtx-v2023.12.27-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.28/rtx-v2023.12.28-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 78bb5a5f8..b119163ee 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.27"; + version = "2023.12.28"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 456f904ca..b9bb274a8 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.27 +Version: 2023.12.28 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 07d9a0494872953846d27a6cc94b41d540f58ee1 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 15 Dec 2023 00:01:24 -0600 Subject: [PATCH 1332/1891] tweak output layout (#1191) --- src/ui/progress_report.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index be8925210..e1aa2adf0 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -42,11 +42,11 @@ static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { Config::get() .list_plugins() .into_iter() - .map(|p| p.name().len() + 12) + .map(|p| p.name().len() + 15) .max() .unwrap_or_default() - .max(20) - .min(40) + .max(15) + .min(35) }); fn pad_prefix(w: usize, s: &str) -> String { @@ -71,7 +71,7 @@ fn success_prefix(pad: usize, prefix: &str) -> String { impl ProgressReport { pub fn new(prefix: String) -> ProgressReport { - let pad = *LONGEST_PLUGIN_NAME + 2; + let pad = *LONGEST_PLUGIN_NAME; let pb = ProgressBar::new(100) .with_style(PROG_TEMPLATE.clone()) .with_prefix(normal_prefix(pad, &prefix)); @@ -122,7 +122,7 @@ impl QuietReport { pub fn new(prefix: String) -> QuietReport { QuietReport { prefix, - pad: *LONGEST_PLUGIN_NAME + 2, + pad: *LONGEST_PLUGIN_NAME, } } } @@ -149,7 +149,7 @@ impl VerboseReport { pub fn new(prefix: String) -> VerboseReport { VerboseReport { prefix, - pad: *LONGEST_PLUGIN_NAME + 2, + pad: *LONGEST_PLUGIN_NAME, } } } From 31890a874a976a6f9e8134294d31226c38f0c018 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 15 Dec 2023 01:03:52 -0600 Subject: [PATCH 1333/1891] system (#1193) * added ability to see config filenames * small refactor on config to break out fetching config filenames --- src/cli/trust.rs | 7 +++---- src/config/mod.rs | 33 +++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/cli/trust.rs b/src/cli/trust.rs index 9a59d6cc1..ef9ba81b0 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -1,11 +1,10 @@ -use std::collections::BTreeMap; use std::path::PathBuf; use clap::ValueHint; use color_eyre::eyre::Result; use crate::config; -use crate::config::config_file; +use crate::config::{config_file, DEFAULT_CONFIG_FILENAMES}; /// Marks a config file as trusted /// @@ -62,12 +61,12 @@ impl Trust { } fn get_next_trusted(&self) -> Option { - config::load_config_filenames(&BTreeMap::new()) + config::load_config_paths(&DEFAULT_CONFIG_FILENAMES) .into_iter() .find(|p| config_file::is_trusted(p)) } fn get_next_untrusted(&self) -> Option { - config::load_config_filenames(&BTreeMap::new()) + config::load_config_paths(&DEFAULT_CONFIG_FILENAMES) .into_iter() .find(|p| !config_file::is_trusted(p)) } diff --git a/src/config/mod.rs b/src/config/mod.rs index cbe8e5732..d31fd7586 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -8,7 +8,7 @@ use eyre::Context; use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; -use once_cell::sync::OnceCell; +use once_cell::sync::{Lazy, OnceCell}; use rayon::prelude::*; pub use settings::{Settings, SettingsPartial}; @@ -67,15 +67,12 @@ impl Config { Settings::add_partial(cli_settings); let global_config = load_rtxrc()?; Settings::add_partial(global_config.settings()?); - let config_filenames = load_config_filenames(&BTreeMap::new()); + + let config_paths = load_config_paths(&DEFAULT_CONFIG_FILENAMES); let settings = Settings::try_get()?; let plugins = load_plugins(&settings)?; - let config_files = load_all_config_files( - &config_filenames, - &plugins, - &BTreeMap::new(), - ConfigMap::new(), - )?; + let config_files = + load_all_config_files(&config_paths, &plugins, &BTreeMap::new(), ConfigMap::new())?; for cf in config_files.values() { Settings::add_partial(cf.settings()?); } @@ -83,11 +80,16 @@ impl Config { trace!("Settings: {:#?}", settings); let legacy_files = load_legacy_files(&settings, &plugins); - let config_filenames = load_config_filenames(&legacy_files); - let config_track = track_config_files(&config_filenames); + let config_filenames = legacy_files + .keys() + .chain(DEFAULT_CONFIG_FILENAMES.iter()) + .cloned() + .collect_vec(); + let config_paths = load_config_paths(&config_filenames); + let config_track = track_config_files(&config_paths); let config_files = - load_all_config_files(&config_filenames, &plugins, &legacy_files, config_files); + load_all_config_files(&config_paths, &plugins, &legacy_files, config_files); let config_files = config_files?; let watch_files = config_files .values() @@ -334,8 +336,8 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap>) -> Vec { - let mut filenames = legacy_filenames.keys().cloned().collect_vec(); +pub static DEFAULT_CONFIG_FILENAMES: Lazy> = Lazy::new(|| { + let mut filenames = vec![]; filenames.push(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone()); filenames.push(env::RTX_DEFAULT_CONFIG_FILENAME.clone()); if *env::RTX_DEFAULT_CONFIG_FILENAME == ".rtx.toml" { @@ -345,8 +347,11 @@ pub fn load_config_filenames(legacy_filenames: &BTreeMap filenames.push(format!(".rtx.{}.local.toml", env)); } } + filenames +}); - let mut config_files = file::FindUp::new(&dirs::CURRENT, &filenames).collect::>(); +pub fn load_config_paths(config_filenames: &[String]) -> Vec { + let mut config_files = file::FindUp::new(&dirs::CURRENT, config_filenames).collect::>(); for cf in global_config_files() { config_files.push(cf); From f3e59d0e29b2459a641e3933d6a8994b0406fcf9 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 15 Dec 2023 01:48:51 -0600 Subject: [PATCH 1334/1891] fix indicatif progress bars in dev mode (#1195) Fixes #881 --- src/ui/progress_report.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index e1aa2adf0..8b3c02edf 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -82,7 +82,9 @@ impl ProgressReport { impl SingleReport for ProgressReport { fn println(&self, message: String) { - self.pb.println(message); + self.pb.suspend(|| { + eprintln!("{message}"); + }); } fn warn(&self, message: String) { let msg = format!("{} {message}", style("[WARN]").yellow().for_stderr()); @@ -169,8 +171,9 @@ impl SingleReport for VerboseReport { error!("{prefix} {x} {message}"); } fn set_message(&self, message: String) { - let prefix = normal_prefix(self.pad, &self.prefix); - eprintln!("{prefix} {message}"); + // let prefix = normal_prefix(self.pad, &self.prefix); + // eprintln!("{prefix} {message}"); + eprintln!("{message}"); } fn finish(&self) { self.finish_with_message(style("done").green().for_stderr().to_string()); From 29b86ef713dd98d48929edf9ea01f20f9891a723 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 15 Dec 2023 01:49:45 -0600 Subject: [PATCH 1335/1891] added system config lookup (/etc/rtx/config.toml) (#1194) * added ability to see config filenames * small refactor on config to break out fetching config filenames * added system config lookup (/etc/rtx/config.toml) --- README.md | 6 ++++++ src/config/config_file/mod.rs | 7 +++++-- src/config/mod.rs | 12 ++++++++++++ src/dirs.rs | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fb790ff74..23be8b69b 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ v20.0.0 - [`.tool-versions`](#tool-versions) - [Scopes](#scopes) - [Global config: `~/.config/rtx/config.toml`](#global-config-configrtxconfigtoml) + - [System config: `/etc/rtx/config.toml`](#system-config-etcrtxconfigtoml) - [Environment variables](#environment-variables) - [Aliases](#aliases) - [Plugins](#plugins) @@ -797,6 +798,11 @@ my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20 These settings can also be managed with `rtx settings ls|get|set|unset`. +### System config: `/etc/rtx/config.toml` + +Similar to `~/.config/rtx/config.toml` but for all users on the system. This is useful for +setting defaults for all users. + ### Environment variables rtx can also be configured via environment variables. The following options are available: diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 938bed10c..4bda2bdd1 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -10,7 +10,7 @@ use tool_versions::ToolVersions; use crate::cli::args::tool::ToolArg; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::settings::SettingsPartial; -use crate::config::{global_config_files, AliasMap, Config, Settings}; +use crate::config::{global_config_files, system_config_files, AliasMap, Config, Settings}; use crate::file::{display_path, replace_path}; use crate::hash::hash_to_str; @@ -59,7 +59,10 @@ pub trait ConfigFile: Debug + Send + Sync { vec![self.get_path().to_path_buf()] } fn is_global(&self) -> bool { - global_config_files().iter().any(|p| p == self.get_path()) + global_config_files() + .iter() + .chain(system_config_files().iter()) + .any(|p| p == self.get_path()) } } diff --git a/src/config/mod.rs b/src/config/mod.rs index d31fd7586..99b4c6dcb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -356,6 +356,9 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { for cf in global_config_files() { config_files.push(cf); } + for cf in system_config_files() { + config_files.push(cf); + } config_files.into_iter().unique().collect() } @@ -383,6 +386,15 @@ pub fn global_config_files() -> Vec { config_files } +pub fn system_config_files() -> Vec { + let mut config_files = vec![]; + let system = dirs::SYSTEM.join("config.toml"); + if system.is_file() { + config_files.push(system); + } + config_files +} + fn load_all_config_files( config_filenames: &[PathBuf], tools: &PluginMap, diff --git a/src/dirs.rs b/src/dirs.rs index 345ee7be2..02900d49d 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -13,3 +13,4 @@ pub static PLUGINS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("plugins pub static DOWNLOADS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("downloads")); pub static INSTALLS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("installs")); pub static SHIMS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("shims")); +pub static SYSTEM: Lazy = Lazy::new(|| PathBuf::from("/etc/rtx")); From 71a83d13a7439e72a06f53c5211bb5e27f9dcc9d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:01:11 -0600 Subject: [PATCH 1336/1891] release: purge both rtx.pub and jdx.rtx.dev asset hosts on releases See #974 --- .github/workflows/release.yml | 1 - scripts/publish-s3.sh | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e07ce307e..ff7643445 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -221,7 +221,6 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} - CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} - name: homebrew-tap push if: startsWith(github.event.ref, 'refs/tags/v') run: git push diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 2e64d55fe..96c5d8984 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -24,7 +24,11 @@ aws s3 cp artifacts/deb/pool/ "s3://$AWS_S3_BUCKET/deb/pool/" --cache-control "$ aws s3 cp artifacts/deb/dists/ "s3://$AWS_S3_BUCKET/deb/dists/" --cache-control "$cache_day" --no-progress --no-progress --recursive export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 -curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ +curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/90dfd7997bdcfa8579c52d8ee8dd4cd1/purge_cache" \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data '{ "purge_everything": true }' +curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/80d977fd09f01db52bec165778088891/purge_cache" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{ "purge_everything": true }' From 9fc59f057a8d7f711f57707f0780bcda18a57434 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 15 Dec 2023 12:53:44 -0600 Subject: [PATCH 1337/1891] java: disable rtx-versions (#1197) Fixes #1196 --- src/plugins/core/java.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 50ecccf7c..ea5d7369b 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -77,11 +77,13 @@ impl JavaPlugin { } fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { - Ok(Some(versions)) => return Ok(versions), - Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), - } + // TODO: find out how to get this to work for different os/arch + // See https://github.com/jdx/rtx/issues/1196 + // match self.core.fetch_remote_versions_from_rtx() { + // Ok(Some(versions)) => return Ok(versions), + // Ok(None) => {} + // Err(e) => warn!("failed to fetch remote versions: {}", e), + // } let versions = self .fetch_java_metadata("ga")? .iter() From 59cdbb58543de0582b1aa43c8a634b492ad11837 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 15 Dec 2023 13:19:20 -0600 Subject: [PATCH 1338/1891] chore: Release rtx-cli version 2023.12.29 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbd079d06..cd9916f27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1861,7 +1861,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.28" +version = "2023.12.29" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index cdf102716..00058ffda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.28" +version = "2023.12.29" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 23be8b69b..893a85e03 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.28 +rtx 2023.12.29 ``` Hook rtx into your shell (pick the right one for your shell): @@ -358,7 +358,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.28/rtx-v2023.12.28-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.29/rtx-v2023.12.29-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index b119163ee..72ad636a9 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.28"; + version = "2023.12.29"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index b9bb274a8..f948def01 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.28 +Version: 2023.12.29 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 3087e6fca96baacdfec7b3fe66efa6fa9036bd4e Mon Sep 17 00:00:00 2001 From: Josh Taylor Date: Sun, 17 Dec 2023 02:49:37 +0800 Subject: [PATCH 1339/1891] Change warning for rtx config set experimental (#1200) --- src/config/settings.rs | 2 +- src/plugins/core/python.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/settings.rs b/src/config/settings.rs index 5c49dc1bb..ce08fc679 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -122,7 +122,7 @@ impl Settings { } pub fn ensure_experimental(&self) -> Result<()> { - let msg = "This command is experimental. Enable it with `rtx config set experimental 1`"; + let msg = "This command is experimental. Enable it with `rtx settings set experimental true`"; ensure!(self.experimental, msg); Ok(()) } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 18543bcd0..788608cb7 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -118,7 +118,7 @@ impl PythonPlugin { let settings = Settings::try_get()?; if !settings.experimental { warn!( - "please enable experimental mode with `rtx config set experimental true` \ + "please enable experimental mode with `rtx settings set experimental true` \ to use python virtualenv activation" ); } From 4e7a4127800a88af7854e8bbc1789c72da64ab20 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 16 Dec 2023 13:02:57 -0600 Subject: [PATCH 1340/1891] CI: show git diff on unit (#1203) --- .github/workflows/test.yml | 1 + src/config/settings.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9bf896582..bea407b36 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,6 +44,7 @@ jobs: - run: cargo machete --with-metadata - run: ./scripts/test-standalone.sh - run: just render-all lint-fix + - run: git diff HEAD - if: github.event_name == 'pull_request' uses: EndBug/add-and-commit@v9 with: diff --git a/src/config/settings.rs b/src/config/settings.rs index ce08fc679..2f73b7260 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -122,7 +122,8 @@ impl Settings { } pub fn ensure_experimental(&self) -> Result<()> { - let msg = "This command is experimental. Enable it with `rtx settings set experimental true`"; + let msg = + "This command is experimental. Enable it with `rtx settings set experimental true`"; ensure!(self.experimental, msg); Ok(()) } From 80ab14dda15f77bccff4c8da4561ebe903b06eaf Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 16 Dec 2023 13:14:15 -0600 Subject: [PATCH 1341/1891] lazy-load http client (#1202) On my machine this is a a mild performance increase, 5.4ms to 3ms. It may have something to do with regressions seen in https://github.com/jdx/rtx/discussions/1201 --- src/cli/version.rs | 4 +--- src/http.rs | 25 +++++++++++++++++-------- src/plugins/core/bun.rs | 10 +++++----- src/plugins/core/deno.rs | 10 +++++----- src/plugins/core/erlang.rs | 5 +++-- src/plugins/core/go.rs | 8 ++++---- src/plugins/core/java.rs | 11 ++++------- src/plugins/core/mod.rs | 5 +++-- src/plugins/core/node.rs | 12 +++++------- src/plugins/core/python.rs | 6 +++--- src/plugins/core/ruby.rs | 9 ++++----- src/plugins/external_plugin.rs | 12 +++++++----- src/plugins/mod.rs | 7 +------ 13 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index db8cda817..a1d534933 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -111,11 +111,9 @@ fn get_latest_version_call() -> Option { #[cfg(not(test))] fn get_latest_version_call() -> Option { - let timeout = Duration::from_secs(3); const URL: &str = "http://rtx.jdx.dev/VERSION"; debug!("checking rtx version from {}", URL); - let client = crate::http::Client::new_with_timeout(timeout).ok()?; - match client.get_text(URL) { + match crate::http::HTTP_VERSION_CHECK.get_text(URL) { Ok(text) => { debug!("got version {text}"); Some(text.trim().to_string()) diff --git a/src/http.rs b/src/http.rs index 48cd5859c..e00471824 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,10 +1,22 @@ use std::fs::File; + +#[cfg(not(test))] +pub static HTTP_VERSION_CHECK: Lazy = + Lazy::new(|| Client::new(Duration::from_secs(3)).unwrap()); + +pub static HTTP: Lazy = Lazy::new(|| Client::new(Duration::from_secs(30)).unwrap()); + +pub static HTTP_FETCH: Lazy = + Lazy::new(|| Client::new(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); + use std::path::Path; use std::time::Duration; +use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::display_path; use crate::{env, file}; use eyre::{Report, Result}; +use once_cell::sync::Lazy; use reqwest::blocking::{ClientBuilder, Response}; use reqwest::IntoUrl; @@ -14,15 +26,12 @@ pub struct Client { } impl Client { - pub fn new() -> Result { - Ok(Self { - reqwest: Self::_new().build()?, - }) - } - - pub fn new_with_timeout(timeout: Duration) -> Result { + fn new(timeout: Duration) -> Result { Ok(Self { - reqwest: Self::_new().timeout(timeout).build()?, + reqwest: Self::_new() + .timeout(timeout) + .connect_timeout(timeout) + .build()?, }) } diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 693ec3c60..63bea0840 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -6,13 +6,14 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; +use crate::file; use crate::github::GithubRelease; +use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, HTTP}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::SingleReport; -use crate::{file, http}; #[derive(Debug)] pub struct BunPlugin { @@ -32,7 +33,7 @@ impl BunPlugin { Err(e) => warn!("failed to fetch remote versions: {}", e), } let releases: Vec = - HTTP.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?; + HTTP_FETCH.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?; let versions = releases .into_iter() .map(|r| r.tag_name) @@ -56,7 +57,6 @@ impl BunPlugin { } fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { - let http = http::Client::new()?; let url = format!( "https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-{}-{}.zip", tv.version, @@ -67,7 +67,7 @@ impl BunPlugin { let tarball_path = tv.download_path().join(filename); pr.set_message(format!("downloading {}", &url)); - http.download_file(&url, &tarball_path)?; + HTTP.download_file(&url, &tarball_path)?; Ok(tarball_path) } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index b8eddf375..ef158620d 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -8,13 +8,14 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; +use crate::file; use crate::github::GithubRelease; +use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, HTTP}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; -use crate::{file, http}; #[derive(Debug)] pub struct DenoPlugin { @@ -34,7 +35,7 @@ impl DenoPlugin { Err(e) => warn!("failed to fetch remote versions: {}", e), } let releases: Vec = - HTTP.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; + HTTP_FETCH.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; let versions = releases .into_iter() .map(|r| r.name) @@ -60,7 +61,6 @@ impl DenoPlugin { } fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { - let http = http::Client::new()?; let url = format!( "https://github.com/denoland/deno/releases/download/v{}/deno-{}-{}.zip", tv.version, @@ -71,7 +71,7 @@ impl DenoPlugin { let tarball_path = tv.download_path().join(filename); pr.set_message(format!("downloading {}", &url)); - http.download_file(&url, &tarball_path)?; + HTTP.download_file(&url, &tarball_path)?; // TODO: hash::ensure_checksum_sha256(&tarball_path, &m.sha256)?; diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 500c6d08b..216c9fac6 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -3,10 +3,11 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use crate::file::display_path; +use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; -use crate::plugins::{Plugin, HTTP}; +use crate::plugins::Plugin; use crate::toolset::ToolVersionRequest; use crate::{cmd, file}; @@ -50,7 +51,7 @@ impl ErlangPlugin { fn install_kerl(&self) -> Result<()> { debug!("Installing kerl to {}", display_path(&self.kerl_path())); - HTTP.download_file( + HTTP_FETCH.download_file( format!("https://raw.githubusercontent.com/kerl/kerl/{KERL_VERSION}/kerl"), &self.kerl_path(), )?; diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 155f7f17e..1e7f96827 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -8,12 +8,13 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; +use crate::http::HTTP; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, Toolset}; use crate::ui::progress_report::SingleReport; -use crate::{cmd, env, file, hash, http}; +use crate::{cmd, env, file, hash}; #[derive(Debug)] pub struct GoPlugin { @@ -96,13 +97,12 @@ impl GoPlugin { } fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { - let http = http::Client::new()?; let filename = format!("go{}.{}-{}.tar.gz", tv.version, platform(), arch()); let tarball_url = format!("{}/{}", &*env::RTX_GO_DOWNLOAD_MIRROR, &filename); let tarball_path = tv.download_path().join(filename); pr.set_message(format!("downloading {}", &tarball_url)); - http.download_file(&tarball_url, &tarball_path)?; + HTTP.download_file(&tarball_url, &tarball_path)?; self.verify_tarball_checksum(&tarball_url, &tarball_path)?; @@ -112,7 +112,7 @@ impl GoPlugin { fn verify_tarball_checksum(&self, tarball_url: &str, tarball_path: &Path) -> Result<()> { if !*env::RTX_GO_SKIP_CHECKSUM { let checksum_url = format!("{}.sha256", tarball_url); - let checksum = http::Client::new()?.get_text(checksum_url)?; + let checksum = HTTP.get_text(checksum_url)?; hash::ensure_checksum_sha256(tarball_path, &checksum)?; } Ok(()) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index ea5d7369b..65d8e5d49 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -13,17 +13,17 @@ use crate::cache::CacheManager; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; +use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; -use crate::{env, file, hash, http}; +use crate::{env, file, hash}; #[derive(Debug)] pub struct JavaPlugin { core: CorePlugin, - http: http::Client, java_metadata_ea_cache: CacheManager>, java_metadata_ga_cache: CacheManager>, } @@ -45,7 +45,6 @@ impl JavaPlugin { ) .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), core, - http: http::Client::new_with_timeout(*env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap(), } } @@ -130,12 +129,11 @@ impl JavaPlugin { pr: &dyn SingleReport, m: &JavaMetadata, ) -> Result { - let http = http::Client::new()?; let filename = m.url.split('/').last().unwrap(); let tarball_path = tv.download_path().join(filename); pr.set_message(format!("downloading {}", &m.url)); - http.download_file(&m.url, &tarball_path)?; + HTTP.download_file(&m.url, &tarball_path)?; hash::ensure_checksum_sha256(&tarball_path, &m.sha256)?; @@ -257,8 +255,7 @@ impl JavaPlugin { arch() ); - let metadata = self - .http + let metadata = HTTP_FETCH .json::, _>(url)? .into_iter() .filter(|m| { diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 74c0dbdd3..8ebd9e8ef 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -12,6 +12,7 @@ pub use python::PythonPlugin; use crate::cache::CacheManager; use crate::env::RTX_NODE_BUILD; +use crate::http::HTTP_FETCH; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; use crate::plugins::core::erlang::ErlangPlugin; @@ -20,7 +21,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, HTTP}; +use crate::plugins::Plugin; use crate::timeout::run_with_timeout; use crate::toolset::ToolVersion; use crate::{dirs, env}; @@ -101,7 +102,7 @@ impl CorePlugin { if !*env::RTX_USE_VERSIONS_HOST { return Ok(None); } - let versions = HTTP + let versions = HTTP_FETCH .get_text(format!("http://rtx-versions.jdx.dev/{}", &self.name))? .lines() .map(|v| v.trim().to_string()) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 6e258ad81..17bcfb232 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -9,7 +9,8 @@ use url::Url; use crate::build_time::built_info; use crate::cmd::CmdLineRunner; use crate::config::Config; -use crate::env::{RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, RTX_NODE_MIRROR_URL}; +use crate::env::RTX_NODE_MIRROR_URL; +use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; @@ -20,14 +21,12 @@ use crate::{env, file, hash, http}; #[derive(Debug)] pub struct NodePlugin { core: CorePlugin, - http: http::Client, } impl NodePlugin { pub fn new() -> Self { Self { core: CorePlugin::new("node"), - http: http::Client::new_with_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap(), } } @@ -45,8 +44,7 @@ impl NodePlugin { self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) } fn fetch_remote_versions_from_node(&self, base: &Url) -> Result> { - let versions = self - .http + let versions = HTTP_FETCH .json::, _>(base.join("index.json")?)? .into_iter() .map(|v| { @@ -113,7 +111,7 @@ impl NodePlugin { pr.set_message(format!("using previously downloaded {tarball_name}")); } else { pr.set_message(format!("downloading {tarball_name}")); - self.http.download_file(url.clone(), local)?; + HTTP.download_file(url.clone(), local)?; } if *env::RTX_NODE_VERIFY { pr.set_message(format!("verifying {tarball_name}")); @@ -150,7 +148,7 @@ impl NodePlugin { fn verify(&self, tarball: &Path, version: &str) -> Result<()> { let tarball_name = tarball.file_name().unwrap().to_string_lossy().to_string(); // TODO: verify gpg signature - let shasums = self.http.get_text(self.shasums_url(version)?)?; + let shasums = HTTP.get_text(self.shasums_url(version)?)?; let shasums = hash::parse_shasums(&shasums); let shasum = shasums.get(&tarball_name).unwrap(); hash::ensure_checksum_sha256(tarball, shasum) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 788608cb7..346d6c59f 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -8,12 +8,13 @@ use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::file::{create_dir_all, display_path}; use crate::git::Git; +use crate::http::HTTP; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; -use crate::{cmd, env, file, http}; +use crate::{cmd, env, file}; #[derive(Debug)] pub struct PythonPlugin { @@ -206,8 +207,7 @@ impl Plugin for PythonPlugin { if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { ctx.pr .set_message(format!("with patch file from: {patch_url}")); - let http = http::Client::new()?; - let patch = http.get_text(patch_url)?; + let patch = HTTP.get_text(patch_url)?; cmd = cmd.arg("--patch").stdin_string(patch) } if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 4dad31a10..d1d2eb33c 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -10,13 +10,14 @@ use crate::duration::DAILY; use crate::git::Git; use crate::github::GithubRelease; +use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; -use crate::{cmd, env, file, http}; +use crate::{cmd, env, file}; #[derive(Debug)] pub struct RubyPlugin { @@ -224,9 +225,8 @@ impl RubyPlugin { } fn latest_ruby_build_version(&self) -> Result { - let http = http::Client::new()?; let release: GithubRelease = - http.json("https://api.github.com/repos/rbenv/ruby-build/releases/latest")?; + HTTP_FETCH.json("https://api.github.com/repos/rbenv/ruby-build/releases/latest")?; Ok(release.tag_name.trim_start_matches('v').to_string()) } @@ -306,8 +306,7 @@ impl RubyPlugin { let mut patches = vec![]; for f in &self.fetch_patch_sources() { if regex!(r#"^[Hh][Tt][Tt][Pp][Ss]?://"#).is_match(f) { - let http = http::Client::new()?; - patches.push(http.get_text(f)?); + patches.push(HTTP.get_text(f)?); } else { patches.push(file::read_to_string(f)?); } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 8e7275245..ff04d700b 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -21,11 +21,12 @@ use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_all}; use crate::git::Git; use crate::hash::hash_to_str; +use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::rtx_plugin_toml::RtxPluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; -use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager, HTTP}; +use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; use crate::timeout::run_with_timeout; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -140,10 +141,11 @@ impl ExternalPlugin { { return Ok(None); } - let versions = match HTTP.get_text(format!("http://rtx-versions.jdx.dev/{}", self.name)) { - Err(err) if http::error_code(&err) == Some(404) => return Ok(None), - res => res?, - }; + let versions = + match HTTP_FETCH.get_text(format!("http://rtx-versions.jdx.dev/{}", self.name)) { + Err(err) if http::error_code(&err) == Some(404) => return Ok(None), + res => res?, + }; let versions = versions .lines() .map(|v| v.trim().to_string()) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index b330c8cec..48f40443d 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -9,7 +9,6 @@ use color_eyre::eyre::Result; use console::style; use eyre::WrapErr; use itertools::Itertools; -use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; @@ -17,7 +16,6 @@ pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; use crate::config::{Config, Settings}; -use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::{display_path, remove_all, remove_all_with_warning}; use crate::install_context::InstallContext; use crate::lock_file::LockFile; @@ -25,7 +23,7 @@ use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::SingleReport; -use crate::{dirs, file, http}; +use crate::{dirs, file}; pub mod core; mod external_plugin; @@ -35,9 +33,6 @@ mod script_manager; pub type PluginName = String; -pub static HTTP: Lazy = - Lazy::new(|| http::Client::new_with_timeout(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); - pub trait Plugin: Debug + Send + Sync { fn name(&self) -> &str; fn get_type(&self) -> PluginType { From 6a8e379a8c3d622ed6f25febd96ee1f88b636e00 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 16 Dec 2023 13:55:49 -0600 Subject: [PATCH 1342/1891] chore: Release rtx-cli version 2023.12.30 --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd9916f27..8df79adf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -964,11 +964,11 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1861,7 +1861,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.29" +version = "2023.12.30" dependencies = [ "base64", "built", @@ -2411,18 +2411,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 00058ffda..5ad2ec170 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.29" +version = "2023.12.30" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 893a85e03..a5ee18c4a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.29 +rtx 2023.12.30 ``` Hook rtx into your shell (pick the right one for your shell): @@ -358,7 +358,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.29/rtx-v2023.12.29-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.30/rtx-v2023.12.30-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 72ad636a9..4fe3cdbbd 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.29"; + version = "2023.12.30"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index f948def01..e50cb67cd 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.29 +Version: 2023.12.30 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 7dc6c9292b566a8336e8dea99c4322d11210a9c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:37:47 -0600 Subject: [PATCH 1343/1891] ui tweaks --- src/plugins/mod.rs | 1 + src/ui/progress_report.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 48f40443d..ba05669fd 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -183,6 +183,7 @@ pub trait Plugin: Debug + Send + Sync { if self.is_version_installed(&ctx.tv) { if ctx.force { self.uninstall_version(&ctx.tv, ctx.pr.as_ref(), false)?; + ctx.pr.set_message("installing".into()); } else { return Ok(()); } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 8b3c02edf..dcbe57618 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -42,7 +42,7 @@ static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { Config::get() .list_plugins() .into_iter() - .map(|p| p.name().len() + 15) + .map(|p| p.name().len() + 10) .max() .unwrap_or_default() .max(15) From eb69c35d340a6350ef6fd3468fadf7982afaae64 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 13:38:47 -0600 Subject: [PATCH 1344/1891] ruby: only warn if build tool cannot update (#1212) Fixes #1211 --- src/plugins/core/ruby.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index d1d2eb33c..38a6b1b5a 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -3,6 +3,7 @@ use std::env::temp_dir; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; +use eyre::WrapErr; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; @@ -61,9 +62,11 @@ impl RubyPlugin { fn update_build_tool(&self) -> Result<()> { if *env::RTX_RUBY_INSTALL { - self.update_ruby_install()?; + self.update_ruby_install() + .wrap_err("failed to update ruby-install")?; } self.update_ruby_build() + .wrap_err("failed to update ruby-build") } fn install_ruby_build(&self) -> Result<()> { @@ -147,7 +150,9 @@ impl RubyPlugin { Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } - self.update_build_tool()?; + if let Err(err) = self.update_build_tool() { + warn!("{err}"); + } let ruby_build_bin = self.ruby_build_bin(); let versions = CorePlugin::run_fetch_task_with_timeout(move || { let output = cmd!(ruby_build_bin, "--definitions").read()?; @@ -347,7 +352,9 @@ impl Plugin for RubyPlugin { } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { - self.update_build_tool()?; + if let Err(err) = self.update_build_tool() { + warn!("{err}"); + } assert!(matches!( &ctx.tv.request, ToolVersionRequest::Version { .. } From f1539b4635c4d6b7cdad1d6417093a47b5e1fe16 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 13:51:23 -0600 Subject: [PATCH 1345/1891] refactor: color_eyre::eyre::Result -> eyre::Result --- src/cache.rs | 2 +- src/cli/activate.rs | 2 +- src/cli/alias/ls.rs | 2 +- src/cli/alias/mod.rs | 2 +- src/cli/alias/set.rs | 2 +- src/cli/alias/unset.rs | 2 +- src/cli/args/tool.rs | 2 +- src/cli/asdf.rs | 2 +- src/cli/bin_paths.rs | 2 +- src/cli/cache/clear.rs | 2 +- src/cli/cache/mod.rs | 2 +- src/cli/completion.rs | 2 +- src/cli/config/generate.rs | 2 +- src/cli/config/ls.rs | 2 +- src/cli/current.rs | 2 +- src/cli/direnv/activate.rs | 2 +- src/cli/direnv/envrc.rs | 2 +- src/cli/direnv/mod.rs | 2 +- src/cli/doctor.rs | 2 +- src/cli/env.rs | 2 +- src/cli/external.rs | 2 +- src/cli/global.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/implode.rs | 2 +- src/cli/install.rs | 2 +- src/cli/ls.rs | 2 +- src/cli/ls_remote.rs | 2 +- src/cli/outdated.rs | 2 +- src/cli/plugins/ls.rs | 2 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/mod.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/plugins/update.rs | 2 +- src/cli/prune.rs | 2 +- src/cli/render_completion.rs | 2 +- src/cli/render_help.rs | 2 +- src/cli/reshim.rs | 2 +- src/cli/settings/ls.rs | 2 +- src/cli/settings/mod.rs | 2 +- src/cli/settings/unset.rs | 2 +- src/cli/sync/mod.rs | 2 +- src/cli/sync/node.rs | 2 +- src/cli/sync/python.rs | 2 +- src/cli/trust.rs | 2 +- src/cli/use.rs | 2 +- src/cli/version.rs | 2 +- src/cli/where.rs | 2 +- src/config/config_file/legacy_version.rs | 2 +- src/config/config_file/tool_versions.rs | 2 +- src/config/tracking.rs | 2 +- src/direnv.rs | 2 +- src/env_diff.rs | 2 +- src/hook_env.rs | 2 +- src/lock_file.rs | 2 +- src/logger.rs | 2 +- src/main.rs | 2 +- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/erlang.rs | 2 +- src/plugins/core/go.rs | 2 +- src/plugins/core/mod.rs | 2 +- src/plugins/core/node.rs | 2 +- src/plugins/core/node_build.rs | 2 +- src/plugins/core/ruby.rs | 2 +- src/plugins/mod.rs | 2 +- src/runtime_symlinks.rs | 2 +- src/shorthands.rs | 2 +- src/toolset/builder.rs | 2 +- src/toolset/mod.rs | 2 +- src/toolset/tool_version.rs | 2 +- src/toolset/tool_version_request.rs | 2 +- 71 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index a262b3609..67e3d3d24 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -4,7 +4,7 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::time::Duration; -use color_eyre::eyre::Result; +use eyre::Result; use flate2::read::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 763da6bbb..6f6c9e21c 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::dirs; use crate::env::RTX_EXE; diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index e71c2f20c..9367896d5 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use tabled::Tabled; use crate::config::Config; diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index 6bd69ac8f..c34a2c475 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use color_eyre::eyre::Result; +use eyre::Result; use crate::plugins::PluginName; diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index dae2dfea6..bd73ac665 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index d64843d6c..6e124d22b 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index 87c4a05bb..0590d76bd 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -2,7 +2,7 @@ use std::ffi::{OsStr, OsString}; use std::fmt::Display; use clap::{Arg, Command, Error}; -use color_eyre::eyre::Result; +use eyre::Result; use regex::Regex; use crate::plugins::{unalias_plugin, PluginName}; diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 45d4a4b72..4a1f991cb 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -1,5 +1,5 @@ use clap::ValueHint::CommandWithArguments; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use crate::cli::Cli; diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 59a3f808c..9d31765c1 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Config; diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index 41b7d6d01..b3da775ba 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::dirs::CACHE; use crate::file::{display_path, remove_all}; diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 0994b4695..07d9b810c 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use color_eyre::eyre::Result; +use eyre::Result; use crate::env; diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 89a8be007..6cfc1fc49 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -1,6 +1,6 @@ use clap::builder::PossibleValue; use clap::ValueEnum; -use color_eyre::eyre::Result; +use eyre::Result; use std::fmt::Display; /// Generate shell completions diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index 754788641..a875c4d87 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -4,7 +4,7 @@ use crate::config::Settings; use crate::file; use crate::file::display_path; use clap::ValueHint; -use color_eyre::eyre::Result; +use eyre::Result; /// [experimental] Generate an .rtx.toml file #[derive(Debug, clap::Args)] diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index ec9a8da7c..f20c2c579 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -1,5 +1,5 @@ -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use itertools::Itertools; use tabled::settings::object::Columns; diff --git a/src/cli/current.rs b/src/cli/current.rs index f9a54865f..a33416812 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Config; diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 96163b943..8f6d4d42b 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; /// Output direnv function to use rtx inside direnv /// diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index d10faf3c5..e3066175f 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -2,7 +2,7 @@ use std::fs::{create_dir_all, File}; use std::io::Write; use std::ops::Deref; -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Config; use crate::hash::hash_to_str; diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index da3c2fe25..8e3667297 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Config; diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 95db1318a..64e786b41 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -1,8 +1,8 @@ use std::fmt::Write; use std::process::exit; -use color_eyre::eyre::Result; use console::{pad_str, style, Alignment}; +use eyre::Result; use indenter::indented; use crate::build_time::built_info; diff --git a/src/cli/env.rs b/src/cli/env.rs index 790c6f378..6f46e4fbc 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/cli/external.rs b/src/cli/external.rs index 97fa2b300..58ef6e65d 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -1,5 +1,5 @@ use clap::{ArgMatches, Command}; -use color_eyre::eyre::Result; +use eyre::Result; use rayon::prelude::*; use crate::config::Config; diff --git a/src/cli/global.rs b/src/cli/global.rs index f9f3a320f..d75a23d3b 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::local::local; diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index c8048b23a..f5995201f 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -2,7 +2,7 @@ use std::env::{join_paths, split_paths}; use std::ops::Deref; use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use crate::config::Config; diff --git a/src/cli/implode.rs b/src/cli/implode.rs index cb3883b58..4c15ad5e2 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -1,6 +1,6 @@ use std::path::Path; -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Settings; use crate::file::remove_all; diff --git a/src/cli/install.rs b/src/cli/install.rs index edc01f434..048361018 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 09924ba0b..d29be5f1b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -3,8 +3,8 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::Arc; -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use serde_derive::Serialize; diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 6734fbfd7..42226b03c 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use rayon::prelude::*; diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 89ad74d09..6e004e8be 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -1,8 +1,8 @@ use std::collections::HashSet; use std::sync::Arc; -use color_eyre::eyre::Result; use console::{pad_str, style, Alignment}; +use eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index b5a0abab7..b4facee6c 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -1,7 +1,7 @@ use std::collections::BTreeSet; use std::sync::Arc; -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Config; diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index c24df3294..6540c11ec 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; -use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; +use eyre::Result; use itertools::Itertools; use crate::config::Config; diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 1a5b29c13..bb0271313 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Config; diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 493d832bf..134c50037 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,5 +1,5 @@ -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use crate::config::Config; diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 2b80403b8..085641a7d 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,5 +1,5 @@ -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use rayon::prelude::*; use crate::config::{Config, Settings}; diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 8f88a2b3c..47583dbff 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; use std::sync::Arc; -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use crate::config::{Config, Settings}; diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 6149e4507..37eb176d3 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -2,7 +2,7 @@ use clap::Args; use std::io::Cursor; use clap_complete::generate; -use color_eyre::eyre::Result; +use eyre::Result; use crate::cli::self_update::SelfUpdate; use crate::shell::completions; diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index aeda18d0f..26d53e9db 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -1,6 +1,6 @@ use clap::builder::StyledStr; -use color_eyre::eyre::Result; use console::strip_ansi_codes; +use eyre::Result; use itertools::Itertools; use crate::cli::self_update::SelfUpdate; diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 05b422143..48a39e1e1 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::Config; diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index a4c708f94..8fe7824aa 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use serde_json::Value; use std::collections::BTreeMap; diff --git a/src/cli/settings/mod.rs b/src/cli/settings/mod.rs index c42c55058..129fbc6cf 100644 --- a/src/cli/settings/mod.rs +++ b/src/cli/settings/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use color_eyre::eyre::Result; +use eyre::Result; mod get; mod ls; diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index a03d49070..aa00a7ce1 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs index ae0ac7658..8d125ce30 100644 --- a/src/cli/sync/mod.rs +++ b/src/cli/sync/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use color_eyre::eyre::Result; +use eyre::Result; mod node; mod python; diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 29eb0a5f6..37d5832a7 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::sorted; use crate::config::Config; diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 57d866445..9783c0abe 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use itertools::sorted; use crate::config::Config; diff --git a/src/cli/trust.rs b/src/cli/trust.rs index ef9ba81b0..aa2a86c72 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use clap::ValueHint; -use color_eyre::eyre::Result; +use eyre::Result; use crate::config; use crate::config::{config_file, DEFAULT_CONFIG_FILENAMES}; diff --git a/src/cli/use.rs b/src/cli/use.rs index fa69653c3..1a94433c9 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; diff --git a/src/cli/version.rs b/src/cli/version.rs index a1d534933..99acd17f8 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -1,8 +1,8 @@ use std::string::ToString; use std::time::Duration; -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use once_cell::sync::Lazy; use versions::Versioning; diff --git a/src/cli/where.rs b/src/cli/where.rs index 9e00ad0ed..bd4f217ae 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index e3b2888b6..89e046eee 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -2,7 +2,7 @@ use std::default::Default; use std::path::{Path, PathBuf}; use std::sync::Arc; -use color_eyre::eyre::Result; +use eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::plugins::{Plugin, PluginName}; diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 1b1621744..64a7df293 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -2,8 +2,8 @@ use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; use crate::config::config_file; -use color_eyre::eyre::Result; use console::{measure_text_width, pad_str, Alignment}; +use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use tera::Context; diff --git a/src/config/tracking.rs b/src/config/tracking.rs index d7c98218c..27b1deabb 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -3,7 +3,7 @@ use std::fs; use std::fs::{read_dir, remove_file}; use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; +use eyre::Result; use crate::dirs; use crate::file::{create_dir_all, make_symlink}; diff --git a/src/direnv.rs b/src/direnv.rs index 825b19494..92b035055 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -5,7 +5,7 @@ use std::io::Write; use std::path::{Path, PathBuf}; use base64::prelude::*; -use color_eyre::eyre::Result; +use eyre::Result; use flate2::write::{ZlibDecoder, ZlibEncoder}; use flate2::Compression; use itertools::Itertools; diff --git a/src/env_diff.rs b/src/env_diff.rs index 52f1a7c7d..1aea04bf0 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -5,7 +5,7 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use base64::prelude::*; -use color_eyre::eyre::Result; +use eyre::Result; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; diff --git a/src/hook_env.rs b/src/hook_env.rs index af7577b9b..402efcc19 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use std::time::SystemTime; use base64::prelude::*; -use color_eyre::eyre::Result; +use eyre::Result; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; diff --git a/src/lock_file.rs b/src/lock_file.rs index 1a02be1a5..0acc31bdb 100644 --- a/src/lock_file.rs +++ b/src/lock_file.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; +use eyre::Result; use crate::dirs; use crate::file::create_dir_all; diff --git a/src/logger.rs b/src/logger.rs index c09cf4729..071523007 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -4,7 +4,7 @@ use std::env; use std::fs::{create_dir_all, File, OpenOptions}; use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use simplelog::*; pub fn init(log_level: LevelFilter, log_file_level: LevelFilter) { diff --git a/src/main.rs b/src/main.rs index 64aeee7b0..b15aa0f08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,9 +14,9 @@ mod test; use std::process::exit; -use color_eyre::eyre::Result; use color_eyre::{Help, Report, SectionExt}; use console::{style, Term}; +use eyre::Result; use crate::cli::version::VERSION; use crate::cli::Cli; diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 63bea0840..bcb928ad9 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use versions::Versioning; diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index ef158620d..a7c44598a 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use versions::Versioning; diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 216c9fac6..cb0fcedf4 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use crate::file::display_path; use crate::http::HTTP_FETCH; diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 1e7f96827..f9ba54a75 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use versions::Versioning; diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 8ebd9e8ef..8018f66fa 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -4,7 +4,7 @@ use std::iter::Iterator; use std::path::PathBuf; use std::sync::Arc; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use once_cell::sync::Lazy; diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 17bcfb232..183c9b04e 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; +use eyre::Result; use serde_derive::Deserialize; use tempfile::tempdir_in; use url::Url; diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index 41bd55c22..da2a26fa0 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use std::process::exit; use clap::Command; -use color_eyre::eyre::Result; +use eyre::Result; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 38a6b1b5a..ced09d8d1 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::env::temp_dir; use std::path::{Path, PathBuf}; -use color_eyre::eyre::Result; +use eyre::Result; use eyre::WrapErr; use crate::cmd::CmdLineRunner; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index ba05669fd..725ffd20c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -5,8 +5,8 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; use clap::Command; -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use eyre::WrapErr; use itertools::Itertools; use regex::Regex; diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 3140cbbbb..9c82536f6 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::sync::Arc; -use color_eyre::eyre::Result; +use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use regex::Regex; diff --git a/src/shorthands.rs b/src/shorthands.rs index 77c672251..c15609492 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use toml::Table; use crate::config::Settings; diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index b30094005..b011e56f9 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use color_eyre::eyre::Result; +use eyre::Result; use itertools::Itertools; use crate::cli::args::tool::ToolArg; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index d7ca7b5b4..008325b1d 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::thread; -use color_eyre::eyre::Result; use console::style; +use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use rayon::prelude::*; diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index e65fc9105..421c60010 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -4,7 +4,7 @@ use std::fs; use std::hash::{Hash, Hasher}; use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use versions::{Chunk, Version}; use crate::config::Config; diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 6c6909b45..208ceb6d2 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -1,7 +1,7 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use color_eyre::eyre::Result; +use eyre::Result; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionOptions}; From 6dcd810febfc82be6742461e59ce118919e45c72 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 14:16:56 -0600 Subject: [PATCH 1346/1891] node: fix installing older versions --- src/plugins/core/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 183c9b04e..af56798e6 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -68,7 +68,7 @@ impl NodePlugin { ) { Err(e) if matches!(http::error_code(&e), Some(404)) => { debug!("precompiled node not found"); - self.install_compiled(ctx, opts) + return self.install_compiled(ctx, opts); } e => e, }?; From 31c876bcd2649bfe25a64782314b409023bb7e91 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:19:49 -0600 Subject: [PATCH 1347/1891] better error on tar failures --- src/file.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/file.rs b/src/file.rs index edf30db53..989109155 100644 --- a/src/file.rs +++ b/src/file.rs @@ -272,9 +272,11 @@ pub fn untar(archive: &Path, dest: &Path) -> Result<()> { debug!("tar -xzf {} -C {}", archive.display(), dest.display()); let f = File::open(archive)?; let tar = GzDecoder::new(f); - let mut archive = Archive::new(tar); - archive.unpack(dest)?; - Ok(()) + Archive::new(tar).unpack(dest).wrap_err_with(|| { + let archive = display_path(archive); + let dest = display_path(dest); + format!("failed to extract tar: {archive} to {dest}") + }) } pub fn unzip(archive: &Path, dest: &Path) -> Result<()> { From 9c3043356247f078cf26c3837910fa9315c4a851 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:38:32 -0600 Subject: [PATCH 1348/1891] export short paths (#1214) Fixes #1213 --- e2e/cd/test_bash | 2 +- src/cli/bin_paths.rs | 2 +- ...x__cli__direnv__envrc__tests__direnv_envrc.snap | 2 +- src/cli/env.rs | 4 ++-- .../snapshots/rtx__cli__env__tests__env_json.snap | 2 +- ...i__local__tests__local_multiple_versions-3.snap | 6 +++--- src/plugins/external_plugin.rs | 14 +++++++------- src/plugins/external_plugin_cache.rs | 7 +++---- 8 files changed, 19 insertions(+), 20 deletions(-) diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index af7d4aabf..2362ea93f 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -33,7 +33,7 @@ assert_path() { NODE_18="INSTALLS/node/18.0.0/bin" NODE_20="INSTALLS/node/20.0.0/bin" -TINY="INSTALLS/tiny/3.1.0/bin" +TINY="INSTALLS/tiny/latest/bin" SHELLCHECK="INSTALLS/shellcheck/0.9.0/bin" SHFMT="INSTALLS/shfmt/3.6.0/bin" diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 9d31765c1..fa29d4cdb 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -26,7 +26,7 @@ mod tests { fn test_bin_paths() { assert_cli!("i"); assert_cli_snapshot!("bin-paths", @r###" - ~/data/installs/tiny/3.1.0/bin + ~/data/installs/tiny/3/bin ~/data/installs/dummy/ref-master/bin "###); } diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap index dc6ec483a..28ae6d539 100644 --- a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap +++ b/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap @@ -9,4 +9,4 @@ watch_file ~/config/config.toml export JDXCODE_TINY=3.1.0 export TEST_ENV_VAR=test-123 PATH_add ~/data/installs/dummy/ref-master/bin -PATH_add ~/data/installs/tiny/3.1.0/bin +PATH_add ~/data/installs/tiny/3/bin diff --git a/src/cli/env.rs b/src/cli/env.rs index 6f46e4fbc..348e6be30 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -94,7 +94,7 @@ mod tests { let stdout = assert_cli!("env", "-s", "bash"); assert!(stdout.contains( dirs::DATA - .join("installs/tiny/3.1.0/bin") + .join("installs/tiny/3/bin") .to_string_lossy() .as_ref() )); @@ -107,7 +107,7 @@ mod tests { assert!(stdout.contains( dirs::DATA - .join("installs/tiny/3.0.1/bin") + .join("installs/tiny/3.0/bin") .to_string_lossy() .as_ref() )); diff --git a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap index f3114eada..cdf9b5494 100644 --- a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap +++ b/src/cli/snapshots/rtx__cli__env__tests__env_json.snap @@ -4,6 +4,6 @@ expression: output --- { "JDXCODE_TINY": "3.1.0", - "PATH": "~/data/installs/tiny/3.1.0/bin:~/data/installs/dummy/ref-master/bin:$PATH", + "PATH": "~/data/installs/tiny/3/bin:~/data/installs/dummy/ref-master/bin:$PATH", "TEST_ENV_VAR": "test-123" } diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap index 64e20d63e..ded8a39e7 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap +++ b/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap @@ -2,7 +2,7 @@ source: src/cli/local.rs expression: output --- -~/data/installs/tiny/2.1.0/bin -~/data/installs/tiny/1.0.1/bin -~/data/installs/tiny/3.1.0/bin +~/data/installs/tiny/2/bin +~/data/installs/tiny/1/bin +~/data/installs/tiny/3/bin ~/data/installs/dummy/ref-master/bin diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ff04d700b..28883e0e6 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -273,7 +273,7 @@ impl ExternalPlugin { Ok(()) } - fn fetch_bin_paths(&self, tv: &ToolVersion) -> Result> { + fn fetch_bin_paths(&self, tv: &ToolVersion) -> Result> { let list_bin_paths = self.plugin_path.join("bin/list-bin-paths"); let bin_paths = if matches!(tv.request, ToolVersionRequest::System(_)) { Vec::new() @@ -293,10 +293,6 @@ impl ExternalPlugin { } else { vec!["bin".into()] }; - let bin_paths = bin_paths - .into_iter() - .map(|path| tv.install_path().join(path)) - .collect(); Ok(bin_paths) } fn fetch_exec_env(&self, ts: &Toolset, tv: &ToolVersion) -> Result> { @@ -667,8 +663,12 @@ impl Plugin for ExternalPlugin { } fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { - self.cache - .list_bin_paths(self, tv, || self.fetch_bin_paths(tv)) + Ok(self + .cache + .list_bin_paths(self, tv, || self.fetch_bin_paths(tv))? + .into_iter() + .map(|path| tv.install_short_path().join(path)) + .collect()) } fn exec_env( diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 39a3e7fc7..2189439d9 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::path::PathBuf; use std::sync::RwLock; use eyre::WrapErr; @@ -15,7 +14,7 @@ use crate::{dirs, env}; #[derive(Debug, Default)] pub struct ExternalPluginCache { - list_bin_paths: RwLock>>>, + list_bin_paths: RwLock>>>, exec_env: RwLock>>>, } @@ -25,9 +24,9 @@ impl ExternalPluginCache { plugin: &ExternalPlugin, tv: &ToolVersion, fetch: F, - ) -> Result> + ) -> Result> where - F: FnOnce() -> Result>, + F: FnOnce() -> Result>, { let mut w = self.list_bin_paths.write().unwrap(); let cm = w.entry(tv.request.clone()).or_insert_with(|| { From f112e07ccffda1955ff2e64c3bb5a1c1dfe238fb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:43:33 -0600 Subject: [PATCH 1349/1891] erlang: fix caching problems (#1215) --- src/plugins/core/erlang.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index cb0fcedf4..f217d54c9 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -29,6 +29,10 @@ impl ErlangPlugin { self.core.cache_path.join(format!("kerl-{}", KERL_VERSION)) } + fn kerl_base_dir(&self) -> PathBuf { + self.core.cache_path.join("kerl") + } + fn lock_build_tool(&self) -> Result { LockFile::new(&self.kerl_path()) .with_callback(|l| { @@ -40,11 +44,13 @@ impl ErlangPlugin { fn update_kerl(&self) -> Result<()> { let _lock = self.lock_build_tool(); if self.kerl_path().exists() { + // TODO: find a way to not have to do this #1209 + file::remove_all(self.kerl_path())?; return Ok(()); } self.install_kerl()?; cmd!(self.kerl_path(), "update", "releases") - .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) + .env("KERL_BASE_DIR", self.kerl_base_dir()) .run()?; Ok(()) } From ec4a05e8f0549eac74d424f59080fbe7edd876f8 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:33:24 -0600 Subject: [PATCH 1350/1891] uninstall: only uninstall 1 version if exact match (#1217) Fixes #1206 --- src/cli/uninstall.rs | 17 ++++++++++++----- src/plugins/core/erlang.rs | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 225d798a5..686057aad 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -93,13 +93,20 @@ impl Uninstall { .map(|a| { let tool = config.get_or_create_plugin(&a.plugin); let query = a.tvr.as_ref().map(|tvr| tvr.version()).unwrap_or_default(); - let mut tvs = tool - .list_installed_versions()? + let installed_versions = tool.list_installed_versions()?; + let exact_match = installed_versions.iter().find(|v| v == &&query); + let matches = match exact_match { + Some(m) => vec![m], + None => installed_versions + .iter() + .filter(|v| v.starts_with(&query)) + .collect_vec(), + }; + let mut tvs = matches .into_iter() - .filter(|v| v.starts_with(&query)) .map(|v| { - let tvr = ToolVersionRequest::new(tool.name().into(), &v); - let tv = ToolVersion::new(tool.as_ref(), tvr, Default::default(), v); + let tvr = ToolVersionRequest::new(tool.name().into(), v); + let tv = ToolVersion::new(tool.as_ref(), tvr, Default::default(), v.into()); (tool.clone(), tv) }) .collect::>(); diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index f217d54c9..7f9c662c1 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -45,7 +45,7 @@ impl ErlangPlugin { let _lock = self.lock_build_tool(); if self.kerl_path().exists() { // TODO: find a way to not have to do this #1209 - file::remove_all(self.kerl_path())?; + file::remove_all(self.kerl_base_dir())?; return Ok(()); } self.install_kerl()?; From 8658f3132f4febdbfc2bdd7976977a54d7cda0d0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:35:21 -0600 Subject: [PATCH 1351/1891] chore: Release rtx-cli version 2023.12.31 --- Cargo.lock | 44 ++++++++++++++++-------------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 22 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8df79adf7..a7ffd5b11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1013,9 +1013,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1028,7 +1028,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2", "tokio", "tower-service", "tracing", @@ -1773,9 +1773,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "async-compression", "base64", @@ -1861,7 +1861,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.30" +version = "2023.12.31" dependencies = [ "base64", "built", @@ -2126,9 +2126,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -2223,16 +2223,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.5" @@ -2441,9 +2431,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -2463,9 +2453,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -2487,9 +2477,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -2497,7 +2487,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.5", + "socket2", "windows-sys 0.48.0", ] @@ -3155,9 +3145,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.28" +version = "0.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 5ad2ec170..8f22b1439 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.30" +version = "2023.12.31" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index a5ee18c4a..a8e05ef9a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.30 +rtx 2023.12.31 ``` Hook rtx into your shell (pick the right one for your shell): @@ -358,7 +358,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.30/rtx-v2023.12.30-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.31/rtx-v2023.12.31-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 4fe3cdbbd..fcbedb2a4 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.30"; + version = "2023.12.31"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e50cb67cd..6d2aea5a1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.30 +Version: 2023.12.31 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From dc8d95a776ff7fb8fa80f2645b5d29a2e11c3514 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 11:32:00 -0600 Subject: [PATCH 1352/1891] readme --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index a8e05ef9a..8500ca7f8 100644 --- a/README.md +++ b/README.md @@ -860,6 +860,8 @@ a quick way for rtx to query for new versions. This host regularly grabs all the latest versions of core and community plugins. It's faster than running a plugin's `list-all` command and gets around GitHub rate limiting problems when using it. +See [FAQ](#new-version-of-a-tool-is-not-available) for more information. + #### `RTX_${PLUGIN}_VERSION` Set the version for a runtime. For example, `RTX_NODE_VERSION=20` will use regardless @@ -1324,6 +1326,17 @@ doesn't work, try running `asdf install python latest` to see if it's an issue w Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. +### New version of a tool is not available + +There are 2 places that versions are cached so a brand new release might not appear right away. + +The first is that the rtx CLI caches versions for 24 hours. This can be cleared with `rtx cache clear`. + +The second uses the [rtx-versions](https://github.com/jdx/rtx-versions) repo as a centralized +place to list all of the versions of most plugins. This is intended to speed up rtx and also +get around GitHub rate limits when querying for new versions. Check that repo for your plugin to +see if it has an updated version. This service can be disabled by setting `RTX_USE_VERSIONS_HOST=0`. + ### Windows support? This is something we'd like to add! From 9fb493e7b0d0772eb9adc231df799e7181339810 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 11:55:26 -0600 Subject: [PATCH 1353/1891] readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8500ca7f8..19e2150f5 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ v20.0.0 - [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) + - [New version of a tool is not available](#new-version-of-a-tool-is-not-available) - [Windows support?](#windows-support) - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) From 987e33805dc02af8f53f77e893ff73690d2ebce3 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 12:10:19 -0600 Subject: [PATCH 1354/1891] trim "v" prefix on versions (#1219) * trim "v" prefix on versions * Commit from GitHub Actions (test) --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- src/plugins/external_plugin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 28883e0e6..01e165085 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -198,7 +198,10 @@ impl ExternalPlugin { display_stderr(); } - Ok(stdout.split_whitespace().map(|v| v.into()).collect()) + Ok(stdout + .split_whitespace() + .map(|v| regex!(r"^v(\d+)").replace(v, "$1").to_string()) + .collect()) } fn fetch_legacy_filenames(&self) -> Result> { From d8e86ec7479930be101d48167f7e253c8bb03e3c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 12:40:24 -0600 Subject: [PATCH 1355/1891] use table to output plugins list (#1220) --- README.md | 8 +-- completions/_rtx | 4 +- completions/rtx.fish | 4 +- e2e/test_bang | 1 + src/cli/mod.rs | 1 + src/cli/plugins/ls.rs | 67 +++++++++++-------- src/cli/plugins/mod.rs | 10 ++- ...__plugins__ls__tests__plugin_list_all.snap | 5 ++ 8 files changed, 55 insertions(+), 45 deletions(-) create mode 100644 src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_all.snap diff --git a/README.md b/README.md index 19e2150f5..79d412664 100644 --- a/README.md +++ b/README.md @@ -2389,18 +2389,14 @@ Options: Show the git url for each plugin e.g.: https://github.com/asdf-vm/asdf-node.git - --refs - Show the git refs for each plugin - e.g.: main 1234abc - Examples: $ rtx plugins ls node ruby $ rtx plugins ls --urls - node https://github.com/asdf-vm/asdf-node.git - ruby https://github.com/asdf-vm/asdf-ruby.git + node https://github.com/asdf-vm/asdf-node.git + ruby https://github.com/asdf-vm/asdf-ruby.git ``` ### `rtx plugins ls-remote [OPTIONS]` diff --git a/completions/_rtx b/completions/_rtx index 991c85e9d..dfe0190c5 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -429,8 +429,7 @@ __rtx_plugins_cmd() { _arguments -s -S \ '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ - '(-u --urls)'{-u,--urls}'[show the git url for each plugin]' \ - '--refs[show the git refs for each plugin]' \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ @@ -480,7 +479,6 @@ __rtx_plugins_ls_cmd() { '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '--refs[Show the git refs for each plugin]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' diff --git a/completions/rtx.fish b/completions/rtx.fish index 1bcb72c0c..bf47cfec2 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -171,8 +171,7 @@ complete -kxc rtx -n "$fssf outdated" -a "(__rtx_tool_versions)" -d 'Tool(s) to # plugins complete -kxc rtx -n "$fssf plugins" -s c -l core -d 'The built-in plugins only' -complete -kxc rtx -n "$fssf plugins" -l refs -d 'show the git refs for each plugin' -complete -kxc rtx -n "$fssf plugins" -s u -l urls -d 'show the git url for each plugin' +complete -kxc rtx -n "$fssf plugins" -s u -l urls -d 'Show the git url for each plugin' complete -kxc rtx -n "$fssf plugins" -l user -d 'List installed plugins' set -l others install link ls ls-remote uninstall update complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a install -d 'Install a plugin' @@ -196,7 +195,6 @@ complete -kxc rtx -n "$fssf plugins; and $fssf link" -a "(__fish_complete_direct # plugins ls complete -kxc rtx -n "$fssf plugins; and $fssf ls" -s c -l core -d 'The built-in plugins only' -complete -kxc rtx -n "$fssf plugins; and $fssf ls" -l refs -d 'Show the git refs for each plugin' complete -kxc rtx -n "$fssf plugins; and $fssf ls" -s u -l urls -d 'Show the git url for each plugin' complete -kxc rtx -n "$fssf plugins; and $fssf ls" -l user -d 'List installed plugins' diff --git a/e2e/test_bang b/e2e/test_bang index 432b6bcaf..2341f3816 100755 --- a/e2e/test_bang +++ b/e2e/test_bang @@ -10,6 +10,7 @@ assert() { fi } +rtx uninstall --all tiny rtx i tiny rtx local tiny@sub-1:latest assert "rtx current tiny" "2.1.0" diff --git a/src/cli/mod.rs b/src/cli/mod.rs index af3e1967e..b752d8257 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -278,6 +278,7 @@ pub mod tests { .find(|line| line.contains(pattern)) .map(|line| line.to_string()) .unwrap() + .trim() .replace(dirs::HOME.to_string_lossy().as_ref(), "~") } } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index b4facee6c..91cab0c5a 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -2,9 +2,12 @@ use std::collections::BTreeSet; use std::sync::Arc; use eyre::Result; +use rayon::prelude::*; +use tabled::settings::object::Columns; +use tabled::settings::{Margin, Modify, Padding, Style}; +use tabled::Tabled; use crate::config::Config; - use crate::plugins::{ExternalPlugin, PluginType}; /// List installed plugins @@ -32,12 +35,12 @@ pub struct PluginsLs { /// Show the git url for each plugin /// e.g.: https://github.com/asdf-vm/asdf-node.git - #[clap(short, long, verbatim_doc_comment)] + #[clap(short, long, alias = "url", verbatim_doc_comment)] pub urls: bool, /// Show the git refs for each plugin /// e.g.: main 1234abc - #[clap(long, verbatim_doc_comment)] + #[clap(long, hide = true, verbatim_doc_comment)] pub refs: bool, } @@ -59,23 +62,29 @@ impl PluginsLs { } if self.urls || self.refs { - for tool in tools { - rtxprint!("{:29}", tool.name()); - if self.urls { - if let Some(url) = tool.get_remote_url() { - rtxprint!(" {}", url); - } - } - if self.refs { - if let Ok(aref) = tool.current_abbrev_ref() { - rtxprint!(" {}", aref); - } - if let Ok(sha) = tool.current_sha_short() { - rtxprint!(" {}", sha); + let data = tools + .into_par_iter() + .map(|p| { + let mut row = Row { + plugin: p.name().to_string(), + url: p.get_remote_url().unwrap_or_default(), + ref_: String::new(), + sha: String::new(), + }; + if p.is_installed() { + row.ref_ = p.current_abbrev_ref().unwrap_or_default(); + row.sha = p.current_sha_short().unwrap_or_default(); } - } - rtxprint!("\n"); - } + row + }) + .collect::>(); + let mut table = tabled::Table::new(data); + table + .with(Style::empty()) + .with(Margin::new(0, 0, 0, 0)) + .with(Modify::new(Columns::first()).with(Padding::new(0, 1, 0, 0))) + .with(Modify::new(Columns::last()).with(Padding::zero())); + rtxprintln!("{table}"); } else { for tool in tools { rtxprintln!("{tool}"); @@ -85,6 +94,15 @@ impl PluginsLs { } } +#[derive(Tabled)] +#[tabled(rename_all = "PascalCase")] +struct Row { + plugin: String, + url: String, + ref_: String, + sha: String, +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ rtx plugins ls @@ -92,15 +110,13 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( ruby $ rtx plugins ls --urls - node https://github.com/asdf-vm/asdf-node.git - ruby https://github.com/asdf-vm/asdf-ruby.git + node https://github.com/asdf-vm/asdf-node.git + ruby https://github.com/asdf-vm/asdf-ruby.git "# ); #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::cli::tests::grep; #[test] @@ -117,10 +133,7 @@ mod tests { #[test] fn test_plugin_list_all() { let stdout = assert_cli!("plugin", "list", "--all", "--urls"); - assert_str_eq!( - grep(stdout, "zephyr"), - "zephyr https://github.com/nsaunders/asdf-zephyr.git" - ); + assert_snapshot!(grep(stdout, "zephyr")); } #[test] diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index bb0271313..fde8db3e6 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -34,16 +34,14 @@ pub struct Plugins { #[clap(long, verbatim_doc_comment, conflicts_with = "all")] pub user: bool, - /// show the git url for each plugin - /// + /// Show the git url for each plugin /// e.g.: https://github.com/asdf-vm/asdf-node.git - #[clap(short, long)] + #[clap(short, long, alias = "url", verbatim_doc_comment)] pub urls: bool, - /// show the git refs for each plugin - /// + /// Show the git refs for each plugin /// e.g.: main 1234abc - #[clap(long)] + #[clap(long, hide = true, verbatim_doc_comment)] pub refs: bool, } diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_all.snap b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_all.snap new file mode 100644 index 000000000..077116270 --- /dev/null +++ b/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_all.snap @@ -0,0 +1,5 @@ +--- +source: src/cli/plugins/ls.rs +expression: "grep(stdout, \"zephyr\")" +--- +zephyr https://github.com/nsaunders/asdf-zephyr.git From 342f6dc657c1c92a76e690ee95b4b7488b395f60 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:48:13 -0600 Subject: [PATCH 1356/1891] use: fix calling with no version set (#1216) * use: fix when no version set * wip * move latest_versions check --- e2e/test_use | 10 +++++ src/cli/env.rs | 1 + src/cli/exec.rs | 1 + src/cli/install.rs | 7 +-- src/cli/shell.rs | 1 + src/cli/upgrade.rs | 1 + src/cli/use.rs | 44 ++++++++++++------- src/config/config_file/mod.rs | 4 +- ...nfig_file__rtx_toml__tests__fixture-4.snap | 1 - ..._file__rtx_toml__tests__remove_plugin.snap | 1 - ...le__rtx_toml__tests__replace_versions.snap | 1 - src/toolset/builder.rs | 7 --- src/toolset/mod.rs | 11 +++-- 13 files changed, 55 insertions(+), 35 deletions(-) diff --git a/e2e/test_use b/e2e/test_use index 3f19e6151..a24042fd8 100755 --- a/e2e/test_use +++ b/e2e/test_use @@ -5,6 +5,16 @@ source "$(dirname "$0")/assert.sh" rtx rm --all tiny rtx i tiny@1.0.0 +rtx use tiny@1 +assert "rtx current tiny" "1.0.0" + rtx use --env local tiny@1 assert "rtx current tiny" "1.0.0" +assert "cat .rtx.local.toml" '[tools] +tiny = "1"' rm .rtx.local.toml + +rtx use --rm tiny +assert "rtx current tiny" "" +rtx use tiny +assert_contains "rtx current tiny" "1.0.0" diff --git a/src/cli/env.rs b/src/cli/env.rs index 348e6be30..7bc9faadd 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -43,6 +43,7 @@ impl Env { force: false, jobs: self.jobs, raw: self.raw, + latest_versions: false, }; ts.install_arg_versions(config, &opts)?; diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 7bb71f112..7fe61d68e 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -61,6 +61,7 @@ impl Exec { force: false, jobs: self.jobs, raw: self.raw, + latest_versions: false, }; ts.install_arg_versions(config, &opts)?; diff --git a/src/cli/install.rs b/src/cli/install.rs index 048361018..6d019b000 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -54,7 +54,7 @@ impl Install { } fn install_runtimes(&self, config: &Config, runtimes: &[ToolArg]) -> Result<()> { let mpr = MultiProgressReport::new(); - let mut ts = ToolsetBuilder::new().with_latest_versions().build(config)?; + let mut ts = ToolsetBuilder::new().build(config)?; let tool_versions = self.get_requested_tool_versions(config, &ts, runtimes, &mpr)?; if tool_versions.is_empty() { warn!("no runtimes to install"); @@ -69,6 +69,7 @@ impl Install { force: self.force, jobs: self.jobs, raw: self.raw, + latest_versions: true, } } @@ -112,14 +113,14 @@ impl Install { for (plugin_name, tvr, opts) in requests { let plugin = config.get_or_create_plugin(&plugin_name); plugin.ensure_installed(mpr, false)?; - let tv = tvr.resolve(plugin.as_ref(), opts, ts.latest_versions)?; + let tv = tvr.resolve(plugin.as_ref(), opts, true)?; tool_versions.push(tv); } Ok(tool_versions) } fn install_missing_runtimes(&self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_latest_versions().build(config)?; + let mut ts = ToolsetBuilder::new().build(config)?; let versions = ts.list_missing_versions(); if versions.is_empty() { info!("all runtimes are installed"); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 874809ecd..1a52e4e5c 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -43,6 +43,7 @@ impl Shell { force: false, jobs: self.jobs, raw: self.raw, + latest_versions: false, }; ts.install_arg_versions(&config, &opts)?; diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index b9e32f74b..0e3b59604 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -92,6 +92,7 @@ impl Upgrade { force: false, jobs: self.jobs, raw: self.raw, + latest_versions: true, }; ts.install_versions(config, new_versions, &mpr, &opts)?; for (tool, tv) in to_remove { diff --git a/src/cli/use.rs b/src/cli/use.rs index 1a94433c9..a8fe41598 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -10,7 +10,8 @@ use crate::config::{config_file, Config, Settings}; use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; use crate::plugins::PluginName; -use crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder}; +use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest, ToolsetBuilder}; +use crate::ui::multi_progress_report::MultiProgressReport; use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. @@ -78,25 +79,38 @@ pub struct Use { impl Use { pub fn run(self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; - - let opts = InstallOptions { - force: self.force, - jobs: self.jobs, - raw: self.raw, - }; - ts.install_arg_versions(config, &opts)?; - - ts.versions - .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); + let mut ts = ToolsetBuilder::new().build(config)?; + let mpr = MultiProgressReport::new(); + let versions = self + .tool + .iter() + .map(|t| { + let tvr = match &t.tvr { + Some(ref tvr) => tvr.clone(), + None => ToolVersionRequest::new(t.plugin.to_string(), "latest"), + }; + let plugin = config.get_or_create_plugin(&t.plugin); + ToolVersion::resolve(plugin.as_ref(), tvr, Default::default(), false) + }) + .collect::>>()?; + ts.install_versions( + config, + versions.clone(), + &mpr, + &InstallOptions { + force: self.force, + jobs: self.jobs, + raw: self.raw, + latest_versions: false, + }, + )?; let mut cf = self.get_config_file()?; let settings = Settings::try_get()?; let pin = self.pin || (settings.asdf_compat && !self.fuzzy); - for (plugin_name, tvl) in ts.versions { + for (plugin_name, tvl) in &versions.into_iter().group_by(|tv| tv.plugin_name.clone()) { let versions: Vec = tvl - .versions .into_iter() .map(|tv| { if pin { @@ -226,7 +240,7 @@ mod tests { assert_cli_snapshot!("use", "--pin", "tiny", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] - tiny = "2.1.0" + tiny = "3.1.0" "###); assert_cli_snapshot!("use", "--fuzzy", "tiny@2", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny@2"); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 4bda2bdd1..1a802bf0d 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -70,7 +70,6 @@ impl dyn ConfigFile { 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 mut ts = self.to_toolset().to_owned(); - ts.latest_versions = true; ts.resolve(config); let mut plugins_to_update = HashMap::new(); for runtime in runtimes { @@ -96,8 +95,7 @@ impl dyn ConfigFile { .map(|tvr| { if pin { let plugin = config.get_or_create_plugin(&plugin); - let tv = - tvr.resolve(plugin.as_ref(), Default::default(), ts.latest_versions)?; + let tv = tvr.resolve(plugin.as_ref(), Default::default(), false)?; Ok(tv.version) } else { Ok(tvr.version()) diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap index b7634f241..ab5e9775b 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap @@ -120,6 +120,5 @@ Toolset { "~/fixtures/.rtx.toml", ), ), - latest_versions: false, disable_tools: {}, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap index 1cbf09703..81b912b3a 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap @@ -9,6 +9,5 @@ Toolset { "/tmp/.rtx.toml", ), ), - latest_versions: false, disable_tools: {}, } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap index 52eb02332..05bd9410b 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap @@ -33,6 +33,5 @@ Toolset { "/tmp/.rtx.toml", ), ), - latest_versions: false, disable_tools: {}, } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index b011e56f9..d10d46829 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -11,7 +11,6 @@ use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; #[derive(Debug, Default)] pub struct ToolsetBuilder { args: Vec, - latest_versions: bool, global_only: bool, tool_filter: Option>, } @@ -26,11 +25,6 @@ impl ToolsetBuilder { self } - pub fn with_latest_versions(mut self) -> Self { - self.latest_versions = true; - self - } - pub fn with_global_only(mut self, global_only: bool) -> Self { self.global_only = global_only; self @@ -44,7 +38,6 @@ impl ToolsetBuilder { pub fn build(self, config: &Config) -> Result { let settings = Settings::try_get()?; let mut toolset = Toolset { - latest_versions: self.latest_versions, disable_tools: settings.disable_tools.clone(), ..Default::default() }; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 008325b1d..88d714316 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -38,6 +38,7 @@ pub struct InstallOptions { pub force: bool, pub jobs: Option, pub raw: bool, + pub latest_versions: bool, } /// a toolset is a collection of tools for various plugins @@ -49,7 +50,6 @@ pub struct InstallOptions { pub struct Toolset { pub versions: IndexMap, pub source: Option, - pub latest_versions: bool, pub disable_tools: BTreeSet, } @@ -89,7 +89,7 @@ impl Toolset { .iter_mut() .collect::>() .par_iter_mut() - .for_each(|(_, v)| v.resolve(config, self.latest_versions)); + .for_each(|(_, v)| v.resolve(config, false)); } pub fn install_arg_versions(&mut self, config: &Config, opts: &InstallOptions) -> Result<()> { let mpr = MultiProgressReport::new(); @@ -123,7 +123,6 @@ impl Toolset { return Ok(()); } let settings = Settings::try_get()?; - self.latest_versions = true; let queue: Vec<_> = versions .into_iter() .group_by(|v| v.plugin_name.clone()) @@ -153,7 +152,11 @@ impl Toolset { let prefix = format!("{}", style(&tv).cyan().for_stderr()); let ctx = InstallContext { ts, - tv: tv.request.resolve(t.as_ref(), tv.opts.clone(), true)?, + tv: tv.request.resolve( + t.as_ref(), + tv.opts.clone(), + opts.latest_versions, + )?, pr: mpr.add(&prefix), raw, force: opts.force, From 4a09c5a92d944f955b706fec16b3f7e90c5b1934 Mon Sep 17 00:00:00 2001 From: Jared Allard Date: Wed, 20 Dec 2023 16:44:58 -0800 Subject: [PATCH 1357/1891] docs(README): extra ) (#1221) Super minor change... but there was an extra `)`. This removes it. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79d412664..89735456d 100644 --- a/README.md +++ b/README.md @@ -298,7 +298,7 @@ If you need something else, compile it with `cargo install rtx-cli` (see below). brew install rtx ``` -Alternatively, use the custom tap (which is updated immediately after a release)): +Alternatively, use the custom tap (which is updated immediately after a release): ``` brew install jdx/tap/rtx From 576b4096ba28da537fd99b5f0ba88e33fd83cd5d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:00:17 -0600 Subject: [PATCH 1358/1891] linux: use argv0 to find rtx bin (#1222) Direct paths cause failures when updating the CLI if the real path to the binary changes such as with homebrew that puts the version in the path. --- e2e/cd/test_bash | 3 ++- src/cli/activate.rs | 15 +++++++++++---- src/cli/implode.rs | 2 +- src/cli/self_update.rs | 4 ++-- src/env.rs | 14 ++++++++------ src/fake_asdf.rs | 1 - src/plugins/script_manager.rs | 2 +- src/shims.rs | 2 +- src/test.rs | 2 +- 9 files changed, 27 insertions(+), 18 deletions(-) diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 2362ea93f..9a04219ba 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -21,7 +21,8 @@ assert() { assert_path() { local expected="$1" local actual="${PATH/%$orig_path/}" - actual="${actual/%:/}" + actual="${actual%:}" + actual="${actual%:}" actual="${actual//$ROOT/ROOT}" actual="${actual//$RTX_DATA_DIR\/installs/INSTALLS}" if [[ "$actual" != "$expected" ]]; then diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 6f6c9e21c..bbe5fbb6c 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,9 +1,10 @@ +use std::path::PathBuf; + use eyre::Result; -use crate::dirs; -use crate::env::RTX_EXE; use crate::file::touch_dir; use crate::shell::{get_shell, ShellType}; +use crate::{dirs, env}; /// Initializes rtx in the current shell session /// @@ -46,12 +47,18 @@ pub struct Activate { impl Activate { pub fn run(self) -> Result<()> { let shell = get_shell(self.shell_type.or(self.shell)) - .expect("no shell provided, use `--shell=zsh`"); + .expect("no shell provided. Run `rtx activate zsh` or similar"); // touch ROOT to allow hook-env to run let _ = touch_dir(&dirs::DATA); - let output = shell.activate(&RTX_EXE, self.status); + let rtx_bin = if cfg!(target_os = "linux") { + // linux dereferences symlinks, so use argv0 instead + PathBuf::from(&*env::ARGV0) + } else { + env::RTX_BIN.clone() + }; + let output = shell.activate(&rtx_bin, self.status); rtxprint!("{output}"); Ok(()) diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 4c15ad5e2..7243820ff 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -25,7 +25,7 @@ pub struct Implode { impl Implode { pub fn run(self) -> Result<()> { - let mut files = vec![&*dirs::DATA, &*dirs::CACHE, &*env::RTX_EXE]; + let mut files = vec![&*dirs::DATA, &*dirs::CACHE, &*env::RTX_BIN]; if self.config { files.push(&*dirs::CONFIG); } diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 55fb4f6b0..85e4e32ae 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -43,7 +43,7 @@ impl SelfUpdate { rtxprintln!("rtx is already up to date"); } if !self.no_plugins { - cmd!(&*env::RTX_EXE, "plugins", "update").run()?; + cmd!(&*env::RTX_BIN, "plugins", "update").run()?; } Ok(()) @@ -98,7 +98,7 @@ impl SelfUpdate { } pub fn is_available() -> bool { - !std::fs::canonicalize(&*env::RTX_EXE) + !std::fs::canonicalize(&*env::RTX_BIN) .ok() .and_then(|p| p.parent().map(|p| p.to_path_buf())) .and_then(|p| p.parent().map(|p| p.to_path_buf())) diff --git a/src/env.rs b/src/env.rs index 73fc3f53c..e7140f171 100644 --- a/src/env.rs +++ b/src/env.rs @@ -45,15 +45,13 @@ pub static RTX_ENV: Lazy> = Lazy::new(|| var("RTX_ENV").or_else(|_| var("RTX_ENVIRONMENT")).ok()); pub static RTX_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("RTX_CONFIG_FILE")); pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); -pub static RTX_EXE: Lazy = Lazy::new(|| { +pub static RTX_BIN: Lazy = Lazy::new(|| { var_path("RTX_EXE") .or_else(|| current_exe().ok()) .unwrap_or_else(|| "rtx".into()) }); -pub static RTX_BIN_NAME: Lazy = Lazy::new(|| { - let arg0 = &ARGS.read().unwrap()[0]; - arg0.rsplit_once('/').unwrap_or(("", &arg0)).1.to_string() -}); +pub static ARGV0: Lazy = Lazy::new(|| ARGS.read().unwrap()[0].to_string()); +pub static RTX_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0)); pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { @@ -365,7 +363,7 @@ fn log_level() -> LevelFilter { let args = ARGS.read().unwrap(); for (i, arg) in args.iter().enumerate() { // stop parsing after "--" or if we're executing as a shim - if arg == "--" || &*RTX_BIN_NAME != "rtx" { + if arg == "--" || *RTX_BIN_NAME != "rtx" { break; } if let Some(("--log-level", level)) = arg.split_once('=') { @@ -420,6 +418,10 @@ fn linux_distro() -> Option { } } +fn filename(path: &str) -> &str { + path.rsplit_once('/').map(|(_, file)| file).unwrap_or(path) +} + fn is_ninja_on_path() -> bool { which::which("ninja").is_ok() } diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 3434e359b..f37a056e7 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -17,7 +17,6 @@ pub fn setup() -> color_eyre::Result { file::create_dir_all(&path)?; file::write( &asdf_bin, - // rtx="${{RTX_EXE:-rtx}}" formatdoc! {r#" #!/bin/sh rtx asdf "$@" diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 5063b236b..82c541c94 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -80,7 +80,7 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy().to_string(), "RTX_CONCURRENCY" => num_cpus::get().to_string(), "RTX_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), - "RTX_EXE" => env::RTX_EXE.to_string_lossy().to_string(), + "RTX_EXE" => env::RTX_BIN.to_string_lossy().to_string(), }) .into_iter() .map(|(k, v)| (k.into(), v.into())), diff --git a/src/shims.rs b/src/shims.rs index 9e66b3fc6..4b32d43ab 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -75,7 +75,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { }) .lock(); - let rtx_bin = file::which("rtx").unwrap_or(env::RTX_EXE.clone()); + let rtx_bin = file::which("rtx").unwrap_or(env::RTX_BIN.clone()); create_dir_all(&*dirs::SHIMS)?; diff --git a/src/test.rs b/src/test.rs index a6125ebf4..a00788100 100644 --- a/src/test.rs +++ b/src/test.rs @@ -79,7 +79,7 @@ pub fn replace_path(input: &str) -> String { input .replace(&path, "$PATH") .replace(&home, "~") - .replace(&*env::RTX_EXE.to_string_lossy(), "rtx") + .replace(&*env::RTX_BIN.to_string_lossy(), "rtx") } pub fn cli_run(args: &Vec) -> eyre::Result<(String, String)> { From 2f9c0f1741abe650e28162e2c110fc5d5e3b8d3b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:20:07 -0600 Subject: [PATCH 1359/1891] use XDG_STATE_HOME (#1223) Used for tracked configs and trusted configs.: Fixes #1218 --- e2e/run_test | 1 + src/cli/implode.rs | 4 ++-- src/cli/version.rs | 2 +- src/config/config_file/mod.rs | 2 +- src/config/tracking.rs | 12 +++++------- src/dirs.rs | 25 +++++++++++++++---------- src/env.rs | 10 ++++++++-- src/file.rs | 4 ++-- src/hook_env.rs | 2 +- src/migrate.rs | 15 ++++++--------- src/plugins/external_plugin_cache.rs | 4 ++-- src/test.rs | 1 + test/.gitignore | 2 +- 13 files changed, 46 insertions(+), 38 deletions(-) diff --git a/e2e/run_test b/e2e/run_test index 9a930311d..a645bbb6d 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -10,6 +10,7 @@ setup_env() { export PATH="$ROOT/target/debug:$PATH" export RTX_USE_TOML="0" export RTX_DATA_DIR="$HOME/.rtx/e2e" + export RTX_STATE_DIR="$HOME/.rtx/e2e" export RTX_CACHE_DIR="$HOME/.rtx/e2e/cache" export RTX_CONFIG_DIR="$HOME/.rtx/e2e/config" export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 7243820ff..bd1f00774 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -25,9 +25,9 @@ pub struct Implode { impl Implode { pub fn run(self) -> Result<()> { - let mut files = vec![&*dirs::DATA, &*dirs::CACHE, &*env::RTX_BIN]; + let mut files = vec![*dirs::DATA, *dirs::CACHE, &*env::RTX_BIN]; if self.config { - files.push(&*dirs::CONFIG); + files.push(&dirs::CONFIG); } for f in files.into_iter().filter(|d| d.exists()) { if self.dry_run { diff --git a/src/cli/version.rs b/src/cli/version.rs index 99acd17f8..03dc35a92 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -98,7 +98,7 @@ fn get_latest_version(duration: Duration) -> Option { } } } - let _ = file::create_dir_all(&*dirs::CACHE); + let _ = file::create_dir_all(*dirs::CACHE); let version = get_latest_version_call(); let _ = file::write(version_file_path, version.clone().unwrap_or_default()); version diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 1a802bf0d..3e1bed2cd 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -201,7 +201,7 @@ pub fn untrust(path: &Path) -> Result<()> { } fn trust_path(path: &Path) -> PathBuf { - dirs::DATA.join("trusted-configs").join(hash_to_str(&path)) + dirs::TRUSTED_CONFIGS.join(hash_to_str(&path)) } fn detect_config_file_type(path: &Path) -> Option { diff --git a/src/config/tracking.rs b/src/config/tracking.rs index 27b1deabb..371213c3a 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -5,29 +5,27 @@ use std::path::{Path, PathBuf}; use eyre::Result; -use crate::dirs; +use crate::dirs::TRACKED_CONFIGS; use crate::file::{create_dir_all, make_symlink}; use crate::hash::hash_to_str; #[derive(Debug, Default)] pub struct Tracker { - tracking_dir: PathBuf, config_files: HashSet, } impl Tracker { pub fn new() -> Self { Self { - tracking_dir: dirs::DATA.join("tracked-config-files"), ..Default::default() } } pub fn track(&mut self, path: &Path) -> Result<()> { if !self.config_files.contains(path) { - let tracking_path = self.tracking_dir.join(hash_to_str(&path)); + let tracking_path = TRACKED_CONFIGS.join(hash_to_str(&path)); if !tracking_path.exists() { - create_dir_all(&self.tracking_dir)?; + create_dir_all(&*TRACKED_CONFIGS)?; make_symlink(path, &tracking_path)?; } self.config_files.insert(path.to_path_buf()); @@ -38,7 +36,7 @@ impl Tracker { pub fn list_all(&self) -> Result> { self.clean()?; let mut output = vec![]; - for path in read_dir(&self.tracking_dir)? { + for path in read_dir(&*TRACKED_CONFIGS)? { let path = path?.path(); if !path.is_symlink() { continue; @@ -52,7 +50,7 @@ impl Tracker { } pub fn clean(&self) -> Result<()> { - for path in read_dir(&self.tracking_dir)? { + for path in read_dir(&*TRACKED_CONFIGS)? { let path = path?.path(); if !path.exists() { remove_file(&path)?; diff --git a/src/dirs.rs b/src/dirs.rs index 02900d49d..9d9ae2f72 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -1,16 +1,21 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use once_cell::sync::Lazy; use crate::env; -pub static CURRENT: Lazy = Lazy::new(|| env::PWD.clone()); -pub static HOME: Lazy = Lazy::new(|| env::HOME.clone()); -pub static DATA: Lazy = Lazy::new(|| env::RTX_DATA_DIR.clone()); -pub static CACHE: Lazy = Lazy::new(|| env::RTX_CACHE_DIR.clone()); -pub static CONFIG: Lazy = Lazy::new(|| env::RTX_CONFIG_DIR.clone()); -pub static PLUGINS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("plugins")); -pub static DOWNLOADS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("downloads")); -pub static INSTALLS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("installs")); -pub static SHIMS: Lazy = Lazy::new(|| env::RTX_DATA_DIR.join("shims")); +pub static CURRENT: Lazy<&Path> = Lazy::new(|| &env::PWD); +pub static HOME: Lazy<&Path> = Lazy::new(|| &env::HOME); +pub static DATA: Lazy<&Path> = Lazy::new(|| &env::RTX_DATA_DIR); +pub static CACHE: Lazy<&Path> = Lazy::new(|| &env::RTX_CACHE_DIR); +pub static CONFIG: Lazy<&Path> = Lazy::new(|| &env::RTX_CONFIG_DIR); +pub static STATE: Lazy<&Path> = Lazy::new(|| &env::RTX_STATE_DIR); pub static SYSTEM: Lazy = Lazy::new(|| PathBuf::from("/etc/rtx")); + +pub static PLUGINS: Lazy = Lazy::new(|| DATA.join("plugins")); +pub static DOWNLOADS: Lazy = Lazy::new(|| DATA.join("downloads")); +pub static INSTALLS: Lazy = Lazy::new(|| DATA.join("installs")); +pub static SHIMS: Lazy = Lazy::new(|| DATA.join("shims")); + +pub static TRACKED_CONFIGS: Lazy = Lazy::new(|| STATE.join("tracked-configs")); +pub static TRUSTED_CONFIGS: Lazy = Lazy::new(|| STATE.join("trusted-configs")); diff --git a/src/env.rs b/src/env.rs index e7140f171..7c3d03ecb 100644 --- a/src/env.rs +++ b/src/env.rs @@ -21,18 +21,24 @@ pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "s pub static HOME: Lazy = Lazy::new(|| dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/"))); pub static PWD: Lazy = Lazy::new(|| current_dir().unwrap_or_else(|_| PathBuf::new())); + pub static XDG_CACHE_HOME: Lazy = Lazy::new(|| dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache"))); -pub static XDG_DATA_HOME: Lazy = - Lazy::new(|| var_path("XDG_DATA_HOME").unwrap_or_else(|| HOME.join(".local/share"))); pub static XDG_CONFIG_HOME: Lazy = Lazy::new(|| var_path("XDG_CONFIG_HOME").unwrap_or_else(|| HOME.join(".config"))); +pub static XDG_DATA_HOME: Lazy = + Lazy::new(|| var_path("XDG_DATA_HOME").unwrap_or_else(|| HOME.join(".local/share"))); +pub static XDG_STATE_HOME: Lazy = + Lazy::new(|| var_path("XDG_STATE_HOME").unwrap_or_else(|| HOME.join(".local/state"))); + pub static RTX_CACHE_DIR: Lazy = Lazy::new(|| var_path("RTX_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("rtx"))); pub static RTX_CONFIG_DIR: Lazy = Lazy::new(|| var_path("RTX_CONFIG_DIR").unwrap_or_else(|| XDG_CONFIG_HOME.join("rtx"))); pub static RTX_DATA_DIR: Lazy = Lazy::new(|| var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx"))); +pub static RTX_STATE_DIR: Lazy = + Lazy::new(|| var_path("RTX_STATE_DIR").unwrap_or_else(|| XDG_STATE_HOME.join("rtx"))); pub static RTX_TMP_DIR: Lazy = Lazy::new(|| var_path("RTX_TMP_DIR").unwrap_or_else(|| temp_dir().join("rtx"))); diff --git a/src/file.rs b/src/file.rs index 989109155..5883b7f51 100644 --- a/src/file.rs +++ b/src/file.rs @@ -248,7 +248,7 @@ impl Iterator for FindUp { } } self.current_dir_filenames = self.filenames.clone(); - if cfg!(test) && self.current_dir == dirs::HOME.as_path() { + if cfg!(test) && self.current_dir == *dirs::HOME { return None; // in tests, do not recurse further than ./test } if !self.current_dir.pop() { @@ -323,7 +323,7 @@ mod tests { #[test] fn test_dir_subdirs() { - let subdirs = dir_subdirs(dirs::HOME.as_path()).unwrap(); + let subdirs = dir_subdirs(&dirs::HOME).unwrap(); assert!(subdirs.contains(&"cwd".to_string())); } diff --git a/src/hook_env.rs b/src/hook_env.rs index 402efcc19..50cd3dd5a 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -125,7 +125,7 @@ pub fn build_watches(watch_files: &[PathBuf]) -> Result { pub fn get_watch_files(watch_files: &[PathBuf]) -> BTreeSet { let mut watches = BTreeSet::new(); if dirs::DATA.exists() { - watches.insert(dirs::DATA.clone()); + watches.insert(dirs::DATA.to_path_buf()); } for cf in watch_files { watches.insert(cf.clone()); diff --git a/src/migrate.rs b/src/migrate.rs index 7f36c0ae8..547aa0745 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -4,7 +4,7 @@ use std::path::Path; use eyre::Result; use rayon::Scope; -use crate::dirs::{CACHE, CONFIG, DATA, INSTALLS, PLUGINS}; +use crate::dirs::*; use crate::file; pub fn run() { @@ -55,18 +55,15 @@ fn rename_plugin(from: &str, to: &str) -> Result<()> { } fn migrate_tracked_configs() -> Result<()> { - let from = DATA.join("tracked_config_files"); - let to = DATA.join("tracked-config-files"); - move_dirs(&from, &to)?; + move_dirs(&DATA.join("tracked_config_files"), &TRACKED_CONFIGS)?; + move_dirs(&DATA.join("tracked-config-files"), &TRACKED_CONFIGS)?; Ok(()) } fn migrate_trusted_configs() -> Result<()> { - let cache_trusted_configs = CACHE.join("trusted-configs"); - let config_trusted_configs = CONFIG.join("trusted-configs"); - let root_trusted_configs = DATA.join("trusted-configs"); - move_dirs(&cache_trusted_configs, &root_trusted_configs)?; - move_dirs(&config_trusted_configs, &root_trusted_configs)?; + move_dirs(&CACHE.join("trusted-configs"), &TRUSTED_CONFIGS)?; + move_dirs(&CONFIG.join("trusted-configs"), &TRUSTED_CONFIGS)?; + move_dirs(&DATA.join("trusted-configs"), &TRUSTED_CONFIGS)?; Ok(()) } diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 2189439d9..8584fc338 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -40,7 +40,7 @@ impl ExternalPluginCache { None => tv.cache_path().join("list_bin_paths.msgpack.z"), }; CacheManager::new(list_bin_paths_filename) - .with_fresh_file(dirs::DATA.clone()) + .with_fresh_file(dirs::DATA.to_path_buf()) .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(tv.install_path()) }); @@ -68,7 +68,7 @@ impl ExternalPluginCache { None => tv.cache_path().join("exec_env.msgpack.z"), }; CacheManager::new(exec_env_filename) - .with_fresh_file(dirs::DATA.clone()) + .with_fresh_file(dirs::DATA.to_path_buf()) .with_fresh_file(plugin.plugin_path.clone()) .with_fresh_file(tv.install_path()) }); diff --git a/src/test.rs b/src/test.rs index a00788100..c0e4a2c3c 100644 --- a/src/test.rs +++ b/src/test.rs @@ -25,6 +25,7 @@ fn init() { env::set_var("RTX_YES", "1"); env::set_var("RTX_USE_TOML", "0"); env::set_var("RTX_DATA_DIR", env::HOME.join("data")); + env::set_var("RTX_STATE_DIR", env::HOME.join("state")); env::set_var("RTX_CONFIG_DIR", env::HOME.join("config")); env::set_var("RTX_CACHE_DIR", env::HOME.join("data/cache")); env::set_var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME", ".test-tool-versions"); diff --git a/test/.gitignore b/test/.gitignore index f81de271b..7061e564e 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,5 +1,5 @@ data/ !data/plugins cache/ -config/trusted-configs +state/ cwd/man/ From 848f3fdeabc8de975771dfa3581ec91d2067208b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:33:35 -0600 Subject: [PATCH 1360/1891] verbose: recommend --verbose over setting log level (#1224) * verbose: recommend --verbose over setting log level I am trying to simplify things and take out the concept of "log level". Instead it is just verbose/quiet. * test --- src/cli/asdf.rs | 1 + src/env.rs | 7 +++---- src/main.rs | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 4a1f991cb..fe179fcf3 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -75,6 +75,7 @@ mod tests { #[test] fn test_fake_asdf_list() { + assert_cli!("uninstall", "--all", "tiny"); assert_cli!("install", "tiny@1", "tiny@2"); assert_cli!("asdf", "install", "tiny"); assert_cli_snapshot!("asdf", "list", "tiny", @r###" diff --git a/src/env.rs b/src/env.rs index 7c3d03ecb..40689f6b4 100644 --- a/src/env.rs +++ b/src/env.rs @@ -7,7 +7,6 @@ use std::time::Duration; use itertools::Itertools; use log::LevelFilter; use once_cell::sync::Lazy; - use url::Url; use crate::duration::HOURLY; @@ -360,10 +359,10 @@ fn log_level() -> LevelFilter { if var_is_true("RTX_QUIET") { set_var("RTX_LOG_LEVEL", "warn"); } - if var_is_true("RTX_DEBUG") { + if var_is_true("RTX_DEBUG") || var_is_true("RTX_VERBOSE") { set_var("RTX_LOG_LEVEL", "debug"); } - if var_is_true("RTX_TRACE") { + if var_is_true("RTX_TRACE") || var("RTX_VERBOSE").is_ok_and(|v| v == "2") { set_var("RTX_LOG_LEVEL", "trace"); } let args = ARGS.read().unwrap(); @@ -380,7 +379,7 @@ fn log_level() -> LevelFilter { set_var("RTX_LOG_LEVEL", level); } } - if arg == "--debug" || arg == "--verbose" || (arg == "-v" && args.len() > 1) { + if arg == "--debug" || arg == "--verbose" || (arg == "-v" && args.len() > 2) { set_var("RTX_LOG_LEVEL", "debug"); } if arg == "--trace" || arg == "-vv" { diff --git a/src/main.rs b/src/main.rs index b15aa0f08..ccd660c8c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -79,7 +79,9 @@ fn main() -> Result<()> { display_friendly_err(err); exit(1); } - Err(err) => Err(err).suggestion("Run with RTX_DEBUG=1 for more information."), + Err(err) => { + Err(err).suggestion("Run with --verbose or RTX_VERBOSE=1 for more information.") + } } } From 13e285226e2991eb35b57d4567af6bc14d5ca11c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:43:11 -0600 Subject: [PATCH 1361/1891] config: minor loading tweaks --- src/config/mod.rs | 20 +++++++++----------- src/plugins/external_plugin.rs | 4 ++-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 99b4c6dcb..52c6074ab 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -68,9 +68,11 @@ impl Config { let global_config = load_rtxrc()?; Settings::add_partial(global_config.settings()?); - let config_paths = load_config_paths(&DEFAULT_CONFIG_FILENAMES); - let settings = Settings::try_get()?; - let plugins = load_plugins(&settings)?; + let (config_paths, plugins) = rayon::join( + || load_config_paths(&DEFAULT_CONFIG_FILENAMES), + load_plugins, + ); + let plugins = plugins?; let config_files = load_all_config_files(&config_paths, &plugins, &BTreeMap::new(), ConfigMap::new())?; for cf in config_files.values() { @@ -89,8 +91,7 @@ impl Config { let config_track = track_config_files(&config_paths); let config_files = - load_all_config_files(&config_paths, &plugins, &legacy_files, config_files); - let config_files = config_files?; + load_all_config_files(&config_paths, &plugins, &legacy_files, config_files)?; let watch_files = config_files .values() .flat_map(|cf| cf.watch_files()) @@ -280,16 +281,13 @@ fn load_rtxrc() -> Result { } } -fn load_plugins(settings: &Settings) -> Result { +fn load_plugins() -> Result { let mut tools = CORE_PLUGINS.clone(); + let settings = Settings::try_get()?; if settings.experimental { tools.extend(EXPERIMENTAL_CORE_PLUGINS.clone()); } - let external = ExternalPlugin::list()? - .into_iter() - .map(|e| (e.name().into(), e)) - .collect::)>>(); - tools.extend(external); + tools.extend(ExternalPlugin::list()?); for tool in &settings.disable_tools { tools.remove(tool); } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 01e165085..b161c8ab4 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -87,10 +87,10 @@ impl ExternalPlugin { Arc::new(Self::new(name)) } - pub fn list() -> Result>> { + pub fn list() -> Result)>> { Ok(file::dir_subdirs(&dirs::PLUGINS)? .into_iter() - .map(Self::newa) + .map(|name| (name.clone(), Self::newa(name))) .collect()) } From 9dfa8b3aecd0f3ae77a4d56d6a812351ecb9d3c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 20:23:12 -0600 Subject: [PATCH 1362/1891] chore: Release rtx-cli version 2023.12.32 --- Cargo.lock | 28 ++++++++++++++-------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7ffd5b11..bf68cc8b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,7 +293,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -490,7 +490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -528,7 +528,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1434,7 +1434,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1545,7 +1545,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1583,9 +1583,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "platforms" @@ -1861,7 +1861,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.31" +version = "2023.12.32" dependencies = [ "base64", "built", @@ -2110,7 +2110,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2274,9 +2274,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" dependencies = [ "proc-macro2", "quote", @@ -2416,7 +2416,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2831,7 +2831,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", "wasm-bindgen-shared", ] @@ -2865,7 +2865,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 8f22b1439..e9552d9a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.31" +version = "2023.12.32" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 89735456d..fa763ec9c 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.31 +rtx 2023.12.32 ``` Hook rtx into your shell (pick the right one for your shell): @@ -359,7 +359,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.31/rtx-v2023.12.31-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.32/rtx-v2023.12.32-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index fcbedb2a4..5d67a452b 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.31"; + version = "2023.12.32"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6d2aea5a1..6e3a126b1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.31 +Version: 2023.12.32 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 9ab9646920b5dd724c0f97db7d6f26d7568f46bd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 21:31:25 -0600 Subject: [PATCH 1363/1891] perf --- src/cli/mod.rs | 36 ++++++++++++++++++++---------------- src/config/mod.rs | 7 +------ src/main.rs | 3 +++ 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b752d8257..14383edc8 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,6 +1,7 @@ use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; use confique::Partial; +use once_cell::sync::Lazy; use crate::cli::self_update::SelfUpdate; use crate::config::{Config, SettingsPartial}; @@ -180,22 +181,25 @@ impl Cli { } pub fn command() -> clap::Command { - Commands::augment_subcommands( - clap::Command::new("rtx") - .version(version::VERSION.to_string()) - .about(env!("CARGO_PKG_DESCRIPTION")) - .author("Jeff Dickey <@jdx>") - .long_about(LONG_ABOUT) - .arg_required_else_help(true) - .subcommand_required(true) - .after_long_help(AFTER_LONG_HELP) - .arg(args::log_level::Debug::arg()) - .arg(args::log_level::LogLevel::arg()) - .arg(args::log_level::Trace::arg()) - .arg(args::quiet::Quiet::arg()) - .arg(args::verbose::Verbose::arg()) - .arg(args::yes::Yes::arg()), - ) + static COMMAND: Lazy = Lazy::new(|| { + Commands::augment_subcommands( + clap::Command::new("rtx") + .version(version::VERSION.to_string()) + .about(env!("CARGO_PKG_DESCRIPTION")) + .author("Jeff Dickey <@jdx>") + .long_about(LONG_ABOUT) + .arg_required_else_help(true) + .subcommand_required(true) + .after_long_help(AFTER_LONG_HELP) + .arg(args::log_level::Debug::arg()) + .arg(args::log_level::LogLevel::arg()) + .arg(args::log_level::Trace::arg()) + .arg(args::quiet::Quiet::arg()) + .arg(args::verbose::Verbose::arg()) + .arg(args::yes::Yes::arg()), + ) + }); + COMMAND.clone() } pub fn run(self, args: &Vec) -> Result<()> { diff --git a/src/config/mod.rs b/src/config/mod.rs index 52c6074ab..695e270d6 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -98,12 +98,7 @@ impl Config { .collect_vec(); let should_exit_early = hook_env::should_exit_early(&watch_files); - let mut repo_urls = HashMap::new(); - for cf in config_files.values() { - for (plugin_name, repo_url) in cf.plugins() { - repo_urls.insert(plugin_name, repo_url); - } - } + let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); config_track.join().unwrap(); let (env, env_sources) = load_env(&config_files); diff --git a/src/main.rs b/src/main.rs index ccd660c8c..01d708259 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,6 +67,9 @@ mod toolset; mod ui; fn main() -> Result<()> { + rayon::spawn(|| { + Cli::new(); // this is slow so we memoize it in the background + }); *env::ARGS.write().unwrap() = env::args().collect(); color_eyre::install()?; let log_level = *env::RTX_LOG_LEVEL; From a3074723cfcadf4e9f536feb871ddc5a20559870 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 21:39:04 -0600 Subject: [PATCH 1364/1891] perf --- src/config/mod.rs | 50 ++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 695e270d6..65c7cbfaa 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,7 +2,6 @@ use std::collections::{BTreeMap, HashMap}; use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::{Arc, RwLock}; -use std::thread; use eyre::Context; use eyre::Result; @@ -88,24 +87,37 @@ impl Config { .cloned() .collect_vec(); let config_paths = load_config_paths(&config_filenames); - let config_track = track_config_files(&config_paths); - let config_files = load_all_config_files(&config_paths, &plugins, &legacy_files, config_files)?; - let watch_files = config_files - .values() - .flat_map(|cf| cf.watch_files()) - .collect_vec(); - let should_exit_early = hook_env::should_exit_early(&watch_files); - - let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); - config_track.join().unwrap(); - let (env, env_sources) = load_env(&config_files); + let mut env: Option<_> = None; + let mut env_sources: Option<_> = None; + let mut should_exit_early = false; + let mut repo_urls = HashMap::new(); + rayon::scope(|s| { + s.spawn(|_| { + track_config_files(&config_paths); + }); + s.spawn(|_| { + let (a, b) = load_env(&config_files); + env = Some(a); + env_sources = Some(b); + }); + s.spawn(|_| { + let watch_files = config_files + .values() + .flat_map(|cf| cf.watch_files()) + .collect_vec(); + should_exit_early = hook_env::should_exit_early(&watch_files); + }); + s.spawn(|_| { + repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); + }) + }); let config = Self { - env, - env_sources, + env: env.unwrap(), + env_sources: env_sources.unwrap(), path_dirs: load_path_dirs(&config_files), aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), @@ -473,7 +485,7 @@ fn load_aliases(config_files: &ConfigMap) -> AliasMap { aliases } -fn track_config_files(config_filenames: &[PathBuf]) -> thread::JoinHandle<()> { +fn track_config_files(config_filenames: &[PathBuf]) { let config_filenames = config_filenames.to_vec(); let track = move || -> Result<()> { let mut tracker = Tracker::new(); @@ -482,11 +494,9 @@ fn track_config_files(config_filenames: &[PathBuf]) -> thread::JoinHandle<()> { } Ok(()) }; - thread::spawn(move || { - if let Err(err) = track() { - warn!("tracking config files: {:#}", err); - } - }) + if let Err(err) = track() { + warn!("tracking config files: {:#}", err); + } } impl Display for Config { From 9a87ebff7daafc59abc858513b2314f7f0de377c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 22:21:43 -0600 Subject: [PATCH 1365/1891] plugins-install: install in parallel (#1226) --- src/cli/plugins/install.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index cccfd134c..039e30e43 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,7 +1,9 @@ use color_eyre::eyre::{eyre, Result}; +use rayon::prelude::*; +use rayon::ThreadPoolBuilder; use url::Url; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin, PluginName}; use crate::toolset::ToolsetBuilder; @@ -77,21 +79,16 @@ impl PluginsInstall { } fn install_many(&self, plugins: Vec, mpr: MultiProgressReport) -> Result<()> { - for plugin in plugins { - self.install_one(plugin, None, &mpr)?; - } - Ok(()) - // TODO: run in parallel - // ThreadPoolBuilder::new() - // .num_threads(config.settings.jobs) - // .build()? - // .install(|| -> Result<()> { - // plugins - // .into_par_iter() - // .map(|plugin| self.install_one(&config, plugin, None, &mpr)) - // .collect::>>()?; - // Ok(()) - // }) + ThreadPoolBuilder::new() + .num_threads(Settings::get().jobs) + .build()? + .install(|| -> Result<()> { + plugins + .into_par_iter() + .map(|plugin| self.install_one(plugin, None, &mpr)) + .collect::>>()?; + Ok(()) + }) } fn install_one( From 8dd311f9d5dd493ab28e04dc39a202394f0d73ee Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 20 Dec 2023 22:30:53 -0600 Subject: [PATCH 1366/1891] make system directory configurable (#1227) Fixes #1064 --- README.md | 6 ++++++ src/dirs.rs | 2 +- src/env.rs | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fa763ec9c..7b3e007ac 100644 --- a/README.md +++ b/README.md @@ -829,6 +829,12 @@ Default: [`std::env::temp_dir()`](https://doc.rust-lang.org/std/env/fn.temp_dir. This is used for temporary storage such as when installing tools. +#### `RTX_SYSTEM_DIR` + +Default: `/etc/rtx` + +This is the directory where rtx stores system-wide configuration. + #### `RTX_CONFIG_FILE` Default: `$RTX_CONFIG_DIR/config.toml` (Usually ~/.config/rtx/config.toml) diff --git a/src/dirs.rs b/src/dirs.rs index 9d9ae2f72..d4a22b1d5 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -10,7 +10,7 @@ pub static DATA: Lazy<&Path> = Lazy::new(|| &env::RTX_DATA_DIR); pub static CACHE: Lazy<&Path> = Lazy::new(|| &env::RTX_CACHE_DIR); pub static CONFIG: Lazy<&Path> = Lazy::new(|| &env::RTX_CONFIG_DIR); pub static STATE: Lazy<&Path> = Lazy::new(|| &env::RTX_STATE_DIR); -pub static SYSTEM: Lazy = Lazy::new(|| PathBuf::from("/etc/rtx")); +pub static SYSTEM: Lazy<&Path> = Lazy::new(|| &env::RTX_SYSTEM_DIR); pub static PLUGINS: Lazy = Lazy::new(|| DATA.join("plugins")); pub static DOWNLOADS: Lazy = Lazy::new(|| DATA.join("downloads")); diff --git a/src/env.rs b/src/env.rs index 40689f6b4..9f4d987ad 100644 --- a/src/env.rs +++ b/src/env.rs @@ -40,6 +40,8 @@ pub static RTX_STATE_DIR: Lazy = Lazy::new(|| var_path("RTX_STATE_DIR").unwrap_or_else(|| XDG_STATE_HOME.join("rtx"))); pub static RTX_TMP_DIR: Lazy = Lazy::new(|| var_path("RTX_TMP_DIR").unwrap_or_else(|| temp_dir().join("rtx"))); +pub static RTX_SYSTEM_DIR: Lazy = + Lazy::new(|| var_path("RTX_SYSTEM_DIR").unwrap_or_else(|| PathBuf::from("/etc/rtx"))); pub static RTX_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy = Lazy::new(|| { var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) From b412f614b7ad680e8382cbbbef876f56a8b07897 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 05:40:13 -0600 Subject: [PATCH 1367/1891] upgrade: added --interactive (#1228) Fixes #479 --- Cargo.lock | 23 +++++++++++++++++------ Cargo.toml | 3 ++- README.md | 3 +++ completions/_rtx | 1 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + src/cli/upgrade.rs | 39 ++++++++++++++++++++++++++++++--------- 7 files changed, 55 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf68cc8b4..c7f06da32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -531,6 +531,16 @@ dependencies = [ "syn 2.0.42", ] +[[package]] +name = "demand" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76b3984ede3301048a4b6d4693a59cf22700ab6636e62776602f2065e52973e" +dependencies = [ + "console", + "termcolor", +] + [[package]] name = "der" version = "0.7.8" @@ -1473,9 +1483,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "papergrid" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8" +checksum = "9ad43c07024ef767f9160710b3a6773976194758c7919b17e63b863db0bdf7fb" dependencies = [ "ansi-str", "ansitok", @@ -1875,6 +1885,7 @@ dependencies = [ "console", "ctor", "ctrlc", + "demand", "dialoguer", "dirs-next", "dotenvy", @@ -2316,9 +2327,9 @@ dependencies = [ [[package]] name = "tabled" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfe9c3632da101aba5131ed63f9eed38665f8b3c68703a6bb18124835c1a5d22" +checksum = "4c998b0c8b921495196a48aabaf1901ff28be0760136e31604f7967b0792050e" dependencies = [ "ansi-str", "ansitok", @@ -2329,9 +2340,9 @@ dependencies = [ [[package]] name = "tabled_derive" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4" +checksum = "4c138f99377e5d653a371cdad263615634cfc8467685dfe8e73e2b8e98f44b17" dependencies = [ "heck 0.4.1", "proc-macro-error", diff --git a/Cargo.toml b/Cargo.toml index e9552d9a6..9711e560f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ color-print = "0.3" confique = { version = "0.2", default-features = false } console = "0.15" ctrlc = "3.4" +demand = "0.1" dialoguer = { version = "0.11", features = [] } dirs-next = "2.0" dotenvy = "0.15" @@ -92,7 +93,7 @@ shell-escape = "0.1" shell-words = "1.1" simplelog = { version = "0.12" } sys-info = "0.9" -tabled = { version = "0.14", features = ["color"] } +tabled = { version = "0.15", features = ["ansi"] } tar = "0.4" tempfile = "3.8.1" tera = { version = "1.19", default-features = false } diff --git a/README.md b/README.md index 7b3e007ac..40825383f 100644 --- a/README.md +++ b/README.md @@ -2779,6 +2779,9 @@ Options: [env: RTX_JOBS=] + -i, --interactive + Display multiselect menu to choose which tools to upgrade + --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 ``` diff --git a/completions/_rtx b/completions/_rtx index dfe0190c5..8b5e70ed8 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -667,6 +667,7 @@ __rtx_upgrade_cmd() { '*::tool:__rtx_tool_versions' \ '(-n --dry-run)'{-n,--dry-run}'[Just print what would be done, don'\''t actually do it]' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ + '(-i --interactive)'{-i,--interactive}'[Display multiselect menu to choose which tools to upgrade]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index f7e602f2b..4e2316611 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3241,7 +3241,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-n -j -q -v -y -h --dry-run --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-n -j -i -q -v -y -h --dry-run --jobs --interactive --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index bf47cfec2..4c26bb695 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -275,6 +275,7 @@ complete -kxc rtx -n "$fssf uninstall" -a "(__rtx_installed_tool_versions)" -d ' # upgrade complete -kxc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' +complete -kxc rtx -n "$fssf upgrade" -s i -l interactive -d 'Display multiselect menu to choose which tools to upgrade' complete -kxc rtx -n "$fssf upgrade" -s j -l jobs -d 'Number of jobs to run in parallel' complete -kxc rtx -n "$fssf upgrade" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 0e3b59604..b019f7fd3 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -1,4 +1,5 @@ use console::style; +use demand::DemandOption; use std::collections::HashSet; use std::sync::Arc; @@ -34,6 +35,10 @@ pub struct Upgrade { #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] jobs: Option, + /// Display multiselect menu to choose which tools to upgrade + #[clap(long, short, verbatim_doc_comment, conflicts_with = "tool")] + interactive: bool, + /// Directly pipe stdin/stdout/stderr from plugin to user /// Sets --jobs=1 #[clap(long, overrides_with = "jobs")] @@ -42,15 +47,19 @@ pub struct Upgrade { impl Upgrade { pub fn run(self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; - let tool_set = self - .tool - .iter() - .map(|t| t.plugin.clone()) - .collect::>(); - ts.versions - .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); - let outdated = ts.list_outdated_versions(); + let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + let mut outdated = ts.list_outdated_versions(); + if self.interactive { + let tvs = self.get_interactive_tool_set(&outdated)?; + outdated.retain(|(_, tv, _)| tvs.contains(tv)); + } else { + let tool_set = self + .tool + .iter() + .map(|t| t.plugin.clone()) + .collect::>(); + outdated.retain(|(p, _, _)| tool_set.is_empty() || tool_set.contains(p.name())); + } if outdated.is_empty() { info!("All tools are up to date"); } else { @@ -124,6 +133,18 @@ impl Upgrade { } } } + + fn get_interactive_tool_set(&self, outdated: &OutputVec) -> Result> { + let mut ms = demand::MultiSelect::new("rtx upgrade") + .description("Select tools to upgrade") + .filterable(true) + .min(1); + for (_, tv, latest) in outdated { + let label = format!("{tv} -> {latest}"); + ms = ms.option(DemandOption::new(tv).label(&label)); + } + Ok(ms.run()?.into_iter().cloned().collect()) + } } type OutputVec = Vec<(Arc, ToolVersion, String)>; From 90420812e68df471b79a1ced9813aeb7b4b878c4 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 06:20:34 -0600 Subject: [PATCH 1368/1891] confirm: switch to demand from dialogeur (#1229) --- Cargo.lock | 18 ++---------------- Cargo.toml | 3 +-- src/ui/prompt.rs | 8 ++------ 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7f06da32..0a73e1066 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -533,9 +533,9 @@ dependencies = [ [[package]] name = "demand" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76b3984ede3301048a4b6d4693a59cf22700ab6636e62776602f2065e52973e" +checksum = "a5c77b6a21b2b5964fb382eeeb9941000ef6f08b32684d5cef0fddb67c644931" dependencies = [ "console", "termcolor", @@ -560,19 +560,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "dialoguer" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" -dependencies = [ - "console", - "shell-words", - "tempfile", - "thiserror", - "zeroize", -] - [[package]] name = "diff" version = "0.1.13" @@ -1886,7 +1873,6 @@ dependencies = [ "ctor", "ctrlc", "demand", - "dialoguer", "dirs-next", "dotenvy", "duct", diff --git a/Cargo.toml b/Cargo.toml index 9711e560f..fc545c4c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,8 +51,7 @@ color-print = "0.3" confique = { version = "0.2", default-features = false } console = "0.15" ctrlc = "3.4" -demand = "0.1" -dialoguer = { version = "0.11", features = [] } +demand = "0.2" dirs-next = "2.0" dotenvy = "0.15" duct = "0.13" diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 0a0ea19ba..74bf6c750 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,8 +1,7 @@ +use demand::Confirm; use std::io; use std::sync::Mutex; -use dialoguer::Confirm; - static MUTEX: Mutex<()> = Mutex::new(()); pub fn confirm(message: &str) -> io::Result { @@ -11,8 +10,5 @@ pub fn confirm(message: &str) -> io::Result { if !console::user_attended_stderr() { return Ok(false); } - match Confirm::new().with_prompt(message).interact() { - Ok(choice) => Ok(choice), - Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), - } + Confirm::new(message).run() } From 30b772266f569e1d9aa9e8d52bf0e0720655a235 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 05:27:44 -0600 Subject: [PATCH 1369/1891] updated demand crate --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a73e1066..752e492be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -533,9 +533,9 @@ dependencies = [ [[package]] name = "demand" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5c77b6a21b2b5964fb382eeeb9941000ef6f08b32684d5cef0fddb67c644931" +checksum = "d848199107fe9efba52867f0050bf80d1dc9ba1e032ba804dbdabea18ddd7f0d" dependencies = [ "console", "termcolor", diff --git a/Cargo.toml b/Cargo.toml index fc545c4c3..5e3152a20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ color-print = "0.3" confique = { version = "0.2", default-features = false } console = "0.15" ctrlc = "3.4" -demand = "0.2" +demand = "0.3" dirs-next = "2.0" dotenvy = "0.15" duct = "0.13" From ca745b77bc47237472037a1a4951fb9296b1c5d0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 06:32:50 -0600 Subject: [PATCH 1370/1891] chore: Release rtx-cli version 2023.12.33 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 752e492be..63535a8b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1858,7 +1858,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.32" +version = "2023.12.33" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 5e3152a20..81160d5a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.32" +version = "2023.12.33" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 40825383f..34d1c9004 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.32 +rtx 2023.12.33 ``` Hook rtx into your shell (pick the right one for your shell): @@ -359,7 +359,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.32/rtx-v2023.12.32-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.33/rtx-v2023.12.33-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 5d67a452b..7e216227e 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.32"; + version = "2023.12.33"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6e3a126b1..4a7bf8d38 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.32 +Version: 2023.12.33 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 2fd606818e7fd8e0ef66d20ccdc8bfd4928ab556 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:10:22 -0600 Subject: [PATCH 1371/1891] hook-env: added warning back for missing installs (#1230) * hook-env: added warning back for missing installs Can be disabled with `rtx activate --quiet` * wip * wip * wip * wip --- README.md | 3 ++ completions/_rtx | 122 +++++++++++++++++++++--------------------- completions/rtx.bash | 2 +- completions/rtx.fish | 3 +- src/cli/activate.rs | 13 +++-- src/cli/args/quiet.rs | 2 +- src/cli/hook_env.rs | 29 ++++++++-- src/env.rs | 11 +++- src/hook_env.rs | 27 ++++------ src/output.rs | 21 ++++++++ src/shell/bash.rs | 9 ++-- src/shell/fish.rs | 13 +++-- src/shell/mod.rs | 2 +- src/shell/nushell.rs | 9 ++-- src/shell/xonsh.rs | 9 ++-- src/shell/zsh.rs | 9 ++-- src/ui/mod.rs | 1 - src/ui/truncate.rs | 6 --- 18 files changed, 165 insertions(+), 126 deletions(-) delete mode 100644 src/ui/truncate.rs diff --git a/README.md b/README.md index 34d1c9004..4795d203a 100644 --- a/README.md +++ b/README.md @@ -1700,6 +1700,9 @@ Options: --status Show "rtx: @" message when changing directories + -q, --quiet + Hide warnings such as when a tool is not installed + Examples: $ eval "$(rtx activate bash)" $ eval "$(rtx activate zsh)" diff --git a/completions/_rtx b/completions/_rtx index 8b5e70ed8..e0c1fef29 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -5,7 +5,7 @@ _rtx() { local ret=1 _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cmds' \ @@ -64,7 +64,7 @@ __rtx_activate_cmd() { _arguments -s -S \ '::shell_type:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Hide warnings such as when a tool is not installed]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -73,7 +73,7 @@ __rtx_alias_cmd() { _arguments -s -S \ '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ '--no-header[Don'\''t show table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_alias_cmds' \ @@ -98,7 +98,7 @@ __rtx_alias_get_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -107,7 +107,7 @@ __rtx_alias_ls_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ '--no-header[Don'\''t show table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -117,7 +117,7 @@ __rtx_alias_set_cmd() { ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ ':value:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -126,7 +126,7 @@ __rtx_alias_unset_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -134,21 +134,21 @@ __rtx_alias_unset_cmd() { __rtx_asdf_cmd() { _arguments -s -S \ '*::args:_cmdambivalent' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_bin_paths_cmd] )) || __rtx_bin_paths_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_cache_cmd] )) || __rtx_cache_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cache_cmds' \ @@ -169,7 +169,7 @@ return ret __rtx_cache_clear_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -177,7 +177,7 @@ __rtx_cache_clear_cmd() { __rtx_completion_cmd() { _arguments -s -S \ '::shell:(bash fish zsh)' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -185,7 +185,7 @@ __rtx_completion_cmd() { __rtx_config_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_config_cmds' \ @@ -207,7 +207,7 @@ return ret __rtx_config_generate_cmd() { _arguments -s -S \ '(-o --output)'{-o,--output}'=[Output to file instead of stdout]:output:_files' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -215,7 +215,7 @@ __rtx_config_generate_cmd() { __rtx_config_ls_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -223,21 +223,21 @@ __rtx_config_ls_cmd() { __rtx_current_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_deactivate_cmd] )) || __rtx_deactivate_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_cmd] )) || __rtx_direnv_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_direnv_cmds' \ @@ -259,28 +259,28 @@ return ret (( $+functions[__rtx_direnv_activate_cmd] )) || __rtx_direnv_activate_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_envrc_cmd] )) || __rtx_direnv_envrc_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_exec_cmd] )) || __rtx_direnv_exec_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_doctor_cmd] )) || __rtx_doctor_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -292,7 +292,7 @@ __rtx_env_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -302,7 +302,7 @@ __rtx_env_vars_cmd() { '--file=[The TOML file to update]:file:_files' \ '*--remove=[Remove the environment variable from config file]:remove:' \ '*::env_vars:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -314,7 +314,7 @@ __rtx_exec_cmd() { '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -326,7 +326,7 @@ __rtx_global_cmd() { '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ '--path[Get the path of the global config file]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -335,7 +335,7 @@ __rtx_hook_env_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Hide warnings such as when a tool is not installed]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -344,7 +344,7 @@ __rtx_implode_cmd() { _arguments -s -S \ '--config[Also remove config directory]' \ '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -356,7 +356,7 @@ __rtx_install_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '*'{-v,--verbose}'[Show installation output]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_latest_cmd] )) || @@ -364,7 +364,7 @@ __rtx_latest_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -374,7 +374,7 @@ __rtx_link_cmd() { ':tool:__rtx_tool_versions' \ ':path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -387,7 +387,7 @@ __rtx_local_cmd() { '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ '--path[Get the path of the config file]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -402,7 +402,7 @@ __rtx_ls_cmd() { '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ '--no-header[Don'\''t display headers]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -412,7 +412,7 @@ __rtx_ls_remote_cmd() { '::plugin:__rtx_plugins' \ '--all[Show all installed plugins and versions]' \ '::prefix:__rtx_prefixes' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -420,7 +420,7 @@ __rtx_ls_remote_cmd() { __rtx_outdated_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -430,7 +430,7 @@ __rtx_plugins_cmd() { '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_plugins_cmds' \ @@ -460,7 +460,7 @@ __rtx_plugins_install_cmd() { '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ '(-a --all)'{-a,--all}'[Install all missing plugins]' \ '*'{-v,--verbose}'[Show installation output]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_link_cmd] )) || @@ -469,7 +469,7 @@ __rtx_plugins_link_cmd() { ':name:' \ '::path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -479,7 +479,7 @@ __rtx_plugins_ls_cmd() { '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -488,7 +488,7 @@ __rtx_plugins_ls_remote_cmd() { _arguments -s -S \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -498,7 +498,7 @@ __rtx_plugins_uninstall_cmd() { '*::plugin:__rtx_plugins' \ '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ '(-a --all)'{-a,--all}'[Remove all plugins]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -507,7 +507,7 @@ __rtx_plugins_update_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -516,14 +516,14 @@ __rtx_prune_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_reshim_cmd] )) || __rtx_reshim_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -534,13 +534,13 @@ __rtx_self_update_cmd() { '--no-plugins[Disable auto-updating plugins]' \ '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ '::version:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' } (( $+functions[__rtx_settings_cmd] )) || __rtx_settings_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_settings_cmds' \ @@ -564,14 +564,14 @@ return ret __rtx_settings_get_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_settings_ls_cmd] )) || __rtx_settings_ls_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -580,7 +580,7 @@ __rtx_settings_set_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ ':value:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -588,7 +588,7 @@ __rtx_settings_set_cmd() { __rtx_settings_unset_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -599,14 +599,14 @@ __rtx_shell_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_sync_cmd] )) || __rtx_sync_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_sync_cmds' \ @@ -630,7 +630,7 @@ __rtx_sync_node_cmd() { '--brew[Get tool versions from Homebrew]' \ '--nvm[Get tool versions from nvm]' \ '--nodenv[Get tool versions from nodenv]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -638,7 +638,7 @@ __rtx_sync_node_cmd() { __rtx_sync_python_cmd() { _arguments -s -S \ '--pyenv[Get tool versions from pyenv]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -647,7 +647,7 @@ __rtx_trust_cmd() { _arguments -s -S \ '::config_file:_files' \ '--untrust[No longer trust this config]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -657,7 +657,7 @@ __rtx_uninstall_cmd() { '*::installed_tool:__rtx_installed_tool_versions' \ '(-a --all)'{-a,--all}'[Delete all installed versions]' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -669,7 +669,7 @@ __rtx_upgrade_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-i --interactive)'{-i,--interactive}'[Display multiselect menu to choose which tools to upgrade]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -686,14 +686,14 @@ __rtx_use_cmd() { '*--remove=[Remove the tool(s) from config file]:remove:' \ '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ '--pin[Save exact version to config file]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_version_cmd] )) || __rtx_version_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -701,7 +701,7 @@ __rtx_version_cmd() { __rtx_where_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -712,7 +712,7 @@ __rtx_which_cmd() { '--plugin[Show the plugin name instead of the path]' \ '--version[Show the version instead of the path]' \ '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ - '(-q --quiet)'{-q,--quiet}'[Suppress output]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } diff --git a/completions/rtx.bash b/completions/rtx.bash index 4e2316611..e306ed689 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -2339,7 +2339,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -q -v -y -h --shell --status --debug --log-level --trace --quiet --verbose --yes --help" + opts="-s -q -v -y -h --shell --status --quiet --debug --log-level --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 4c26bb695..31672563a 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,7 +1,7 @@ set -l fssf "__fish_seen_subcommand_from" # rtx -complete -kxc rtx -s q -l quiet -d 'Suppress output' +complete -kxc rtx -s q -l quiet -d 'Suppress warnings and other non-error messages' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which @@ -41,6 +41,7 @@ complete -xc rtx -n "not $fssf $others" -a where -d 'Display the installation pa complete -xc rtx -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' # activate +complete -kxc rtx -n "$fssf activate" -s q -l quiet -d 'Hide warnings such as when a tool is not installed' complete -kxc rtx -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' complete -kxc rtx -n "$fssf activate" -l status -d 'Show "rtx: @" message when changing directories' diff --git a/src/cli/activate.rs b/src/cli/activate.rs index bbe5fbb6c..a4caaf7b9 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -39,8 +39,8 @@ pub struct Activate { #[clap(long)] status: bool, - /// noop - #[clap(long, short, hide = true)] + /// Hide warnings such as when a tool is not installed + #[clap(long, short)] quiet: bool, } @@ -58,7 +58,14 @@ impl Activate { } else { env::RTX_BIN.clone() }; - let output = shell.activate(&rtx_bin, self.status); + let mut flags = vec![]; + if self.quiet { + flags.push(" --quiet"); + } + if self.status { + flags.push(" --status"); + } + let output = shell.activate(&rtx_bin, flags.join("")); rtxprint!("{output}"); Ok(()) diff --git a/src/cli/args/quiet.rs b/src/cli/args/quiet.rs index dc967f221..a5773c772 100644 --- a/src/cli/args/quiet.rs +++ b/src/cli/args/quiet.rs @@ -8,7 +8,7 @@ impl Quiet { Arg::new("quiet") .short('q') .long("quiet") - .help("Suppress output") + .help("Suppress warnings and other non-error messages") .global(true) .overrides_with("verbose") .action(ArgAction::SetTrue) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index f5995201f..7f2bb2596 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,3 +1,4 @@ +use console::{style, truncate_str}; use std::env::{join_paths, split_paths}; use std::ops::Deref; use std::path::PathBuf; @@ -9,12 +10,11 @@ use crate::config::Config; use crate::config::Settings; use crate::direnv::DirenvDiff; -use crate::env::__RTX_DIFF; +use crate::env::{TERM_WIDTH, __RTX_DIFF}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::shell::{get_shell, ShellType}; use crate::toolset::{Toolset, ToolsetBuilder}; -use crate::ui::truncate::screen_trunc; use crate::{env, hook_env}; /// [internal] called by activate hook to update env vars directory change @@ -28,6 +28,10 @@ pub struct HookEnv { /// Show "rtx: @" message when changing directories #[clap(long)] status: bool, + + /// Hide warnings such as when a tool is not installed + #[clap(long, short)] + quiet: bool, } impl HookEnv { @@ -57,6 +61,7 @@ impl HookEnv { if self.status { self.display_status(config, &ts); } + self.missing_versions_warning(&ts); Ok(()) } @@ -70,12 +75,12 @@ impl HookEnv { .collect_vec(); if !installed_versions.is_empty() { let status = installed_versions.into_iter().rev().join(" "); - rtxstatusln!("{}", screen_trunc(&status)); + rtxstatusln!("{}", truncate_str(&status, TERM_WIDTH.max(60) - 5, "…")); } let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env.clone()).to_patches(); if !env_diff.is_empty() { let env_diff = env_diff.into_iter().map(patch_to_status).join(" "); - rtxstatusln!("{env_diff}"); + rtxstatusln!("{}", truncate_str(&env_diff, TERM_WIDTH.max(60) - 5, "…")); } } @@ -161,6 +166,22 @@ impl HookEnv { hook_env::serialize_watches(&watches)?, )) } + fn missing_versions_warning(&self, ts: &Toolset) { + let missing = ts.list_missing_versions(); + if missing.is_empty() { + return; + } + let versions = missing + .iter() + .map(|tv| tv.to_string()) + .collect::>() + .join(", "); + rtxwarn!( + "missing: {}. Install with {}", + truncate_str(&versions, TERM_WIDTH.max(60) - 39, "…"), + style("rtx install").yellow().for_stderr(), + ); + } } fn patch_to_status(patch: EnvDiffOperation) -> String { diff --git a/src/env.rs b/src/env.rs index 9f4d987ad..578b23c9c 100644 --- a/src/env.rs +++ b/src/env.rs @@ -12,6 +12,7 @@ use url::Url; use crate::duration::HOURLY; use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches}; use crate::file::replace_path; +use crate::hook_env::{deserialize_watches, HookEnvWatches}; pub static ARGS: RwLock> = RwLock::new(vec![]); pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "sh".into())); @@ -93,6 +94,12 @@ pub static RTX_FETCH_REMOTE_VERSIONS_CACHE: Lazy> = Lazy::new(| pub static __RTX_SCRIPT: Lazy = Lazy::new(|| var_is_true("__RTX_SCRIPT")); pub static __RTX_DIFF: Lazy = Lazy::new(get_env_diff); pub static __RTX_ORIG_PATH: Lazy> = Lazy::new(|| var("__RTX_ORIG_PATH").ok()); +pub static __RTX_WATCH: Lazy> = Lazy::new(|| match var("__RTX_WATCH") { + Ok(raw) => deserialize_watches(raw) + .map_err(|e| rtxwarn!("Failed to deserialize __RTX_WATCH {e}")) + .ok(), + _ => None, +}); pub static CI: Lazy = Lazy::new(|| var_is_true("CI")); pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS.read().unwrap())); /// essentially, this is whether we show spinners or build output on runtime install @@ -359,7 +366,7 @@ fn prefer_stale(args: &[String]) -> bool { fn log_level() -> LevelFilter { if var_is_true("RTX_QUIET") { - set_var("RTX_LOG_LEVEL", "warn"); + set_var("RTX_LOG_LEVEL", "error"); } if var_is_true("RTX_DEBUG") || var_is_true("RTX_VERBOSE") { set_var("RTX_LOG_LEVEL", "debug"); @@ -388,7 +395,7 @@ fn log_level() -> LevelFilter { set_var("RTX_LOG_LEVEL", "trace"); } if arg == "--quiet" || arg == "-q" { - set_var("RTX_LOG_LEVEL", "warn"); + set_var("RTX_LOG_LEVEL", "error"); } } let log_level = var("RTX_LOG_LEVEL") diff --git a/src/hook_env.rs b/src/hook_env.rs index 50cd3dd5a..31fa85dbd 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -25,25 +25,16 @@ pub fn should_exit_early(watch_files: &[PathBuf]) -> bool { return false; } let watch_files = get_watch_files(watch_files); - match env::var("__RTX_WATCH") { - Ok(raw) => { - match deserialize_watches(raw) { - Ok(watches) => { - if have_config_files_been_modified(&watches, watch_files) { - return false; - } - if have_rtx_env_vars_been_modified(&watches) { - return false; - } - } - Err(e) => { - debug!("error deserializing watches: {:?}", e); - return false; - } - }; + match &*env::__RTX_WATCH { + Some(watches) => { + if have_config_files_been_modified(watches, watch_files) { + return false; + } + if have_rtx_env_vars_been_modified(watches) { + return false; + } } - Err(_) => { - // __RTX_WATCH is not set + None => { return false; } }; diff --git a/src/output.rs b/src/output.rs index 59567a1f9..a16978703 100644 --- a/src/output.rs +++ b/src/output.rs @@ -49,6 +49,16 @@ macro_rules! rtxstatusln { }}; } +#[cfg(test)] +#[macro_export] +macro_rules! rtxwarn { + ($($arg:tt)*) => {{ + let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); + let rtx = console::style("rtx ").yellow().for_stderr(); + stderr.push(format!("{}{}", rtx, format!($($arg)*))); + }}; + } + #[cfg(not(test))] #[macro_export] macro_rules! rtxstatusln { @@ -58,6 +68,17 @@ macro_rules! rtxstatusln { }}; } +#[cfg(not(test))] +#[macro_export] +macro_rules! rtxwarn { + ($($arg:tt)*) => {{ + if log_enabled!(log::Level::Warn) { + let rtx = console::style("rtx ").yellow().for_stderr(); + eprintln!("{}{}", rtx, format!($($arg)*)); + } + }}; +} + #[cfg(test)] pub mod tests { use std::sync::Mutex; diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 01cbc68ee..2492824f9 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -6,10 +6,9 @@ use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; pub struct Bash {} impl Shell for Bash { - fn activate(&self, exe: &Path, status: bool) -> String { + fn activate(&self, exe: &Path, flags: String) -> String { let dir = exe.parent().unwrap(); let exe = exe.to_string_lossy(); - let status = if status { " --status" } else { "" }; let mut out = String::new(); if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); @@ -41,7 +40,7 @@ impl Shell for Bash { _rtx_hook() {{ local previous_exit_status=$?; - eval "$(rtx hook-env{status} -s bash)"; + eval "$(rtx hook-env{flags} -s bash)"; return $previous_exit_status; }}; if [[ ";${{PROMPT_COMMAND:-}};" != *";_rtx_hook;"* ]]; then @@ -85,14 +84,14 @@ mod tests { fn test_hook_init() { let bash = Bash::default(); let exe = Path::new("/some/dir/rtx"); - assert_snapshot!(bash.activate(exe, true)); + assert_snapshot!(bash.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let bash = Bash::default(); let exe = Path::new("/nix/store/rtx"); - assert_snapshot!(bash.activate(exe, true)); + assert_snapshot!(bash.activate(exe, " --status".into())); } #[test] diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 7d39e4a38..936e0c678 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -6,10 +6,9 @@ use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; pub struct Fish {} impl Shell for Fish { - fn activate(&self, exe: &Path, status: bool) -> String { + fn activate(&self, exe: &Path, flags: String) -> String { let dir = exe.parent().unwrap(); let exe = exe.to_string_lossy(); - let status = if status { " --status" } else { "" }; let description = "'Update rtx environment when changing directories'"; let mut out = String::new(); @@ -53,14 +52,14 @@ impl Shell for Fish { end function __rtx_env_eval --on-event fish_prompt --description {description}; - {exe} hook-env{status} -s fish | source; + {exe} hook-env{flags} -s fish | source; if test "$rtx_fish_mode" != "disable_arrow"; function __rtx_cd_hook --on-variable PWD --description {description}; if test "$rtx_fish_mode" = "eval_after_arrow"; set -g __rtx_env_again 0; else; - {exe} hook-env{status} -s fish | source; + {exe} hook-env{flags} -s fish | source; end; end; end; @@ -69,7 +68,7 @@ impl Shell for Fish { function __rtx_env_eval_2 --on-event fish_preexec --description {description}; if set -q __rtx_env_again; set -e __rtx_env_again; - {exe} hook-env{status} -s fish | source; + {exe} hook-env{flags} -s fish | source; echo; end; @@ -113,14 +112,14 @@ mod tests { fn test_hook_init() { let fish = Fish::default(); let exe = Path::new("/some/dir/rtx"); - assert_snapshot!(fish.activate(exe, true)); + assert_snapshot!(fish.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let fish = Fish::default(); let exe = Path::new("/nix/store/rtx"); - assert_snapshot!(fish.activate(exe, true)); + assert_snapshot!(fish.activate(exe, " --status".into())); } #[test] diff --git a/src/shell/mod.rs b/src/shell/mod.rs index a561ad631..6742efb7e 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -53,7 +53,7 @@ impl Display for ShellType { } pub trait Shell { - fn activate(&self, exe: &Path, status: bool) -> String; + fn activate(&self, exe: &Path, flags: String) -> String; fn deactivate(&self) -> String; fn set_env(&self, k: &str, v: &str) -> String; fn unset_env(&self, k: &str) -> String; diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 814584ee8..77833563c 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -21,10 +21,9 @@ impl<'a> Display for EnvOp<'a> { } impl Shell for Nushell { - fn activate(&self, exe: &Path, status: bool) -> String { + fn activate(&self, exe: &Path, flags: String) -> String { let dir = exe.parent().unwrap(); let exe = exe.display(); - let status = if status { " --status" } else { "" }; let mut out = String::new(); if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { @@ -85,7 +84,7 @@ impl Shell for Nushell { }} def --env rtx_hook [] {{ - ^"{exe}" hook-env{status} -s nu + ^"{exe}" hook-env{flags} -s nu | parse vars | update-env }} @@ -125,14 +124,14 @@ mod tests { fn test_hook_init() { let nushell = Nushell::default(); let exe = Path::new("/some/dir/rtx"); - assert_snapshot!(nushell.activate(exe, true)); + assert_snapshot!(nushell.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let nushell = Nushell::default(); let exe = Path::new("/nix/store/rtx"); - assert_snapshot!(nushell.activate(exe, true)); + assert_snapshot!(nushell.activate(exe, " --status".into())); } #[test] diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 921b5b331..d09a5f356 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -35,10 +35,9 @@ fn xonsh_escape_char(ch: char) -> Option<&'static str> { } impl Shell for Xonsh { - fn activate(&self, exe: &Path, status: bool) -> String { + fn activate(&self, exe: &Path, flags: String) -> String { let dir = exe.parent().unwrap(); let exe = exe.display(); - let status = if status { " --status" } else { "" }; let mut out = String::new(); // todo: xonsh doesn't update the environment that rtx relies on with $PATH.add even with $UPDATE_OS_ENVIRON (github.com/xonsh/xonsh/issues/3207) @@ -63,7 +62,7 @@ impl Shell for Xonsh { // todo: subprocess instead of $() is a bit faster, but lose auto-color detection (use $FORCE_COLOR) out.push_str(&formatdoc! {r#" def listen_prompt(): # Hook Events - execx($({exe} hook-env{status} -s xonsh)) + execx($({exe} hook-env{flags} -s xonsh)) XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt "#}); @@ -131,14 +130,14 @@ mod tests { fn test_hook_init() { let xonsh = Xonsh::default(); let exe = Path::new("/some/dir/rtx"); - insta::assert_snapshot!(xonsh.activate(exe, true)); + insta::assert_snapshot!(xonsh.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let xonsh = Xonsh::default(); let exe = Path::new("/nix/store/rtx"); - insta::assert_snapshot!(xonsh.activate(exe, true)); + insta::assert_snapshot!(xonsh.activate(exe, " --status".into())); } #[test] diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 767a0fa76..5423bb80b 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -7,10 +7,9 @@ use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; pub struct Zsh {} impl Shell for Zsh { - fn activate(&self, exe: &Path, status: bool) -> String { + fn activate(&self, exe: &Path, flags: String) -> String { let dir = exe.parent().unwrap(); let exe = exe.to_string_lossy(); - let status = if status { " --status" } else { "" }; let mut out = String::new(); // much of this is from direnv @@ -44,7 +43,7 @@ impl Shell for Zsh { }} _rtx_hook() {{ - eval "$({exe} hook-env{status} -s zsh)"; + eval "$({exe} hook-env{flags} -s zsh)"; }} typeset -ag precmd_functions; if [[ -z "${{precmd_functions[(r)_rtx_hook]+1}}" ]]; then @@ -89,14 +88,14 @@ mod tests { fn test_hook_init() { let zsh = Zsh::default(); let exe = Path::new("/some/dir/rtx"); - assert_snapshot!(zsh.activate(exe, true)); + assert_snapshot!(zsh.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let zsh = Zsh::default(); let exe = Path::new("/nix/store/rtx"); - assert_snapshot!(zsh.activate(exe, true)); + assert_snapshot!(zsh.activate(exe, " --status".into())); } #[test] diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 78e081de0..768fe4f7c 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -2,4 +2,3 @@ pub mod multi_progress_report; pub mod progress_report; pub mod prompt; pub mod table; -pub mod truncate; diff --git a/src/ui/truncate.rs b/src/ui/truncate.rs deleted file mode 100644 index bc6b61b54..000000000 --- a/src/ui/truncate.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::env::TERM_WIDTH; -use std::borrow::Cow; - -pub fn screen_trunc(s: &str) -> Cow { - console::truncate_str(s, *TERM_WIDTH, "…") -} From dc262de30324bf40a3d363778082490461ea6ac0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:24:37 -0600 Subject: [PATCH 1372/1891] use rtxwarn for warnings (#1231) * use rtxwarn for warnings this should correctly suspend the progress bar when printing warnings * wip * wip * precommit * wip * wip --- src/cache.rs | 4 +- src/cli/current.rs | 11 ++-- src/cli/external.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/install.rs | 10 ++-- src/cli/latest.rs | 2 +- src/cli/link.rs | 2 +- src/cli/ls.rs | 14 ++++- src/cli/ls_remote.rs | 2 +- src/cli/outdated.rs | 2 +- src/cli/plugins/install.rs | 22 ++++--- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/uninstall.rs | 12 ++-- src/cli/plugins/update.rs | 2 +- src/cli/prune.rs | 2 +- .../rtx__cli__outdated__tests__current.snap | 2 +- ...utdated__tests__current_with_runtimes.snap | 2 +- src/cli/uninstall.rs | 6 +- src/cli/upgrade.rs | 4 +- src/cli/use.rs | 9 ++- src/cli/version.rs | 4 +- src/config/mod.rs | 4 +- src/env.rs | 4 +- src/env_diff.rs | 2 +- src/fake_asdf.rs | 2 +- src/file.rs | 2 +- src/git.rs | 4 +- src/migrate.rs | 10 ++-- src/output.rs | 26 +++++--- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/erlang.rs | 2 +- src/plugins/core/go.rs | 2 +- src/plugins/core/java.rs | 4 +- src/plugins/core/node.rs | 2 +- src/plugins/core/node_build.rs | 2 +- src/plugins/core/python.rs | 13 ++-- src/plugins/core/ruby.rs | 6 +- src/plugins/external_plugin.rs | 10 ++-- src/shims.rs | 2 +- src/shorthands.rs | 2 +- src/toolset/mod.rs | 10 ++-- src/toolset/tool_version_list.rs | 2 +- src/ui/multi_progress_report.rs | 60 ++++++++++--------- src/ui/progress_report.rs | 20 ------- 45 files changed, 161 insertions(+), 152 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index 67e3d3d24..cd52df8dd 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -62,13 +62,13 @@ where match self.parse() { Ok(val) => return Ok::<_, color_eyre::Report>(val), Err(err) => { - warn!("failed to parse cache file: {} {:#}", path.display(), err); + rtxwarn!("failed to parse cache file: {} {:#}", path.display(), err); } } } let val = (fetch)()?; if let Err(err) = self.write(&val) { - warn!("failed to write cache file: {} {:#}", path.display(), err); + rtxwarn!("failed to write cache file: {} {:#}", path.display(), err); } Ok(val) })?; diff --git a/src/cli/current.rs b/src/cli/current.rs index a33416812..3d875d830 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -36,7 +36,7 @@ impl Current { fn one(&self, ts: Toolset, tool: &dyn Plugin) -> Result<()> { if !tool.is_installed() { - warn!("Plugin {} is not installed", tool.name()); + rtxwarn!("Plugin {} is not installed", tool.name()); return Ok(()); } match ts @@ -55,7 +55,7 @@ impl Current { ); } None => { - warn!("Plugin {} does not have a version set", tool.name()); + rtxwarn!("Plugin {} does not have a version set", tool.name()); } }; Ok(()) @@ -69,9 +69,11 @@ impl Current { for tv in versions { if !plugin.is_version_installed(tv) { let source = ts.versions.get(&tv.plugin_name).unwrap().source.clone(); - warn!( + rtxwarn!( "{}@{} is specified in {}, but not installed", - tv.plugin_name, &tv.version, &source + tv.plugin_name, + &tv.version, + &source ); } } @@ -132,6 +134,7 @@ mod tests { assert_cli_snapshot!("current", @r###" dummy 1.1.0 tiny 3.1.0 + rtx dummy@1.1.0 is specified in RTX_DUMMY_VERSION=1.1.0, but not installed "###); env::remove_var("RTX_DUMMY_VERSION"); diff --git a/src/cli/external.rs b/src/cli/external.rs index 58ef6e65d..c269bf23f 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -11,7 +11,7 @@ pub fn commands(config: &Config) -> Vec { .flat_map(|p| { p.external_commands().unwrap_or_else(|e| { let p = p.name(); - warn!("failed to load external commands for plugin {p}: {e:#}"); + rtxwarn!("failed to load external commands for plugin {p}: {e:#}"); vec![] }) }) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 7f2bb2596..b5653d3c4 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -113,7 +113,7 @@ impl HookEnv { Ok(Some(op)) => { ops.push(op); } - Err(err) => warn!("failed to update DIRENV_DIFF: {:#}", err), + Err(err) => rtxwarn!("failed to update DIRENV_DIFF: {:#}", err), _ => {} } } diff --git a/src/cli/install.rs b/src/cli/install.rs index 6d019b000..2566de02b 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -53,12 +53,12 @@ impl Install { Ok(()) } fn install_runtimes(&self, config: &Config, runtimes: &[ToolArg]) -> Result<()> { - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); let mut ts = ToolsetBuilder::new().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 @`"); + rtxwarn!("no runtimes to install"); + rtxwarn!("specify a version with `rtx install @`"); return Ok(()); } ts.install_versions(config, tool_versions, &mpr, &self.install_opts()) @@ -123,10 +123,10 @@ impl Install { let mut ts = ToolsetBuilder::new().build(config)?; let versions = ts.list_missing_versions(); if versions.is_empty() { - info!("all runtimes are installed"); + rtxstatusln!("all runtimes are installed"); return Ok(()); } - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); ts.install_versions(config, versions, &mpr, &self.install_opts())?; Ok(()) } diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 95a453b25..6926aab6d 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -38,7 +38,7 @@ impl Latest { }; let plugin = config.get_or_create_plugin(&self.tool.plugin); - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); plugin.ensure_installed(&mpr, 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 9b675518c..5d4e1995a 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -45,7 +45,7 @@ impl Link { }; let path = self.path.absolutize()?; if !path.exists() { - warn!( + rtxwarn!( "Target path {} does not exist", style(path.to_string_lossy()).cyan().for_stderr() ); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index d29be5f1b..9086e2655 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -135,8 +135,10 @@ impl Ls { } fn display_parseable(&self, runtimes: Vec) -> Result<()> { - warn!("The parseable output format is deprecated and will be removed in a future release."); - warn!("Please use the regular output format instead which has been modified to be more easily parseable."); + rtxwarn!( + "The parseable output format is deprecated and will be removed in a future release." + ); + rtxwarn!("Please use the regular output format instead which has been modified to be more easily parseable."); runtimes .into_iter() .map(|(p, tv, _)| (p, tv)) @@ -434,8 +436,14 @@ mod tests { assert_cli_snapshot!("ls", "--parseable", @r###" dummy ref:master tiny 3.1.0 + rtx The parseable output format is deprecated and will be removed in a future release. + rtx Please use the regular output format instead which has been modified to be more easily parseable. + "###); + assert_cli_snapshot!("ls", "--parseable", "tiny", @r###" + 3.1.0 + rtx The parseable output format is deprecated and will be removed in a future release. + rtx Please use the regular output format instead which has been modified to be more easily parseable. "###); - assert_cli_snapshot!("ls", "--parseable", "tiny", @"3.1.0"); } #[test] diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 42226b03c..1fced6fff 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -91,7 +91,7 @@ impl LsRemote { match &self.plugin { Some(tool_arg) => { let plugin = config.get_or_create_plugin(&tool_arg.plugin); - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); plugin.ensure_installed(&mpr, false)?; Ok(Some(plugin)) } diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 6e004e8be..35e986425 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -32,7 +32,7 @@ impl Outdated { .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); let outdated = ts.list_outdated_versions(); if outdated.is_empty() { - info!("All tools are up to date"); + rtxstatusln!("All tools are up to date"); } else { self.display(outdated); } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 039e30e43..b7cee5eb1 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -49,9 +49,9 @@ pub struct PluginsInstall { impl PluginsInstall { pub fn run(self, config: &Config) -> Result<()> { - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); if self.all { - return self.install_all_missing_plugins(config, mpr); + 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() { @@ -62,30 +62,34 @@ impl PluginsInstall { plugins.push(second); }; plugins.extend(self.rest.clone()); - self.install_many(plugins, mpr)?; + self.install_many(plugins, &mpr)?; } Ok(()) } - fn install_all_missing_plugins(&self, config: &Config, mpr: MultiProgressReport) -> Result<()> { + 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"); + rtxwarn!("all plugins already installed"); } self.install_many(missing_plugins, mpr)?; Ok(()) } - fn install_many(&self, plugins: Vec, mpr: MultiProgressReport) -> Result<()> { + fn install_many(&self, plugins: Vec, mpr: &MultiProgressReport) -> Result<()> { ThreadPoolBuilder::new() .num_threads(Settings::get().jobs) .build()? .install(|| -> Result<()> { plugins .into_par_iter() - .map(|plugin| self.install_one(plugin, None, &mpr)) + .map(|plugin| self.install_one(plugin, None, mpr)) .collect::>>()?; Ok(()) }) @@ -100,8 +104,8 @@ impl PluginsInstall { let mut plugin = ExternalPlugin::new(name.clone()); plugin.repo_url = git_url; if !self.force && plugin.is_installed() { - mpr.warn(format!("Plugin {} already installed", name)); - mpr.warn("Use --force to install anyway".to_string()); + rtxwarn!("Plugin {name} already installed"); + rtxwarn!("Use --force to install anyway"); } else { plugin.ensure_installed(mpr, true)?; } diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 6540c11ec..63abc10d8 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -38,7 +38,7 @@ impl PluginsLsRemote { .unwrap_or(0); if shorthands.is_empty() { - warn!("default shorthands are disabled"); + rtxwarn!("default shorthands are disabled"); } for (plugin, repo) in shorthands { diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 134c50037..dd54bf5dc 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -25,7 +25,7 @@ pub struct PluginsUninstall { impl PluginsUninstall { pub fn run(self, config: &Config) -> Result<()> { - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); let plugins = match self.all { true => config @@ -59,12 +59,10 @@ impl PluginsUninstall { } pr.finish_with_message("uninstalled".into()); } - _ => mpr.suspend(|| { - warn!( - "{} is not installed", - style(plugin_name).cyan().for_stderr() - ); - }), + _ => rtxwarn!( + "{} is not installed", + style(plugin_name).cyan().for_stderr() + ), } Ok(()) } diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 085641a7d..d2758b688 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -47,7 +47,7 @@ impl Update { // let queue = Mutex::new(plugins); let settings = Settings::try_get()?; - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); rayon::ThreadPoolBuilder::new() .num_threads(self.jobs.unwrap_or(settings.jobs)) .build()? diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 47583dbff..1d4f2aa93 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -55,7 +55,7 @@ impl Prune { fn delete(&self, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { let settings = Settings::try_get()?; - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); for (p, tv) in to_delete { let mut prefix = format!("{}", style(&tv).cyan().for_stderr()); if self.dry_run { diff --git a/src/cli/snapshots/rtx__cli__outdated__tests__current.snap b/src/cli/snapshots/rtx__cli__outdated__tests__current.snap index ea8cca771..e033a0b06 100644 --- a/src/cli/snapshots/rtx__cli__outdated__tests__current.snap +++ b/src/cli/snapshots/rtx__cli__outdated__tests__current.snap @@ -2,4 +2,4 @@ source: src/cli/outdated.rs expression: output --- - +rtx All tools are up to date diff --git a/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap b/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap index ea8cca771..e033a0b06 100644 --- a/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap +++ b/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap @@ -2,4 +2,4 @@ source: src/cli/outdated.rs expression: output --- - +rtx All tools are up to date diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 686057aad..1130de3c4 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -45,10 +45,10 @@ impl Uninstall { bail!("multiple tools specified, use --all to uninstall all versions"); } - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); for (plugin, tv) in tool_versions { if !plugin.is_version_installed(&tv) { - warn!("{} is not installed", style(&tv).cyan().for_stderr()); + rtxwarn!("{} is not installed", style(&tv).cyan().for_stderr()); continue; } @@ -117,7 +117,7 @@ impl Uninstall { )); } if tvs.is_empty() { - warn!("no versions found for {}", style(&tool).cyan().for_stderr()); + rtxwarn!("no versions found for {}", style(&tool).cyan().for_stderr()); } Ok(tvs) }) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index b019f7fd3..afac9d347 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -61,7 +61,7 @@ impl Upgrade { outdated.retain(|(p, _, _)| tool_set.is_empty() || tool_set.contains(p.name())); } if outdated.is_empty() { - info!("All tools are up to date"); + rtxstatusln!("All tools are up to date"); } else { self.upgrade(config, outdated)?; } @@ -70,7 +70,7 @@ impl Upgrade { } fn upgrade(&self, config: &Config, outdated: OutputVec) -> Result<()> { - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let new_versions = outdated diff --git a/src/cli/use.rs b/src/cli/use.rs index a8fe41598..e687fb355 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -80,7 +80,7 @@ pub struct Use { impl Use { pub fn run(self, config: &Config) -> Result<()> { let mut ts = ToolsetBuilder::new().build(config)?; - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); let versions = self .tool .iter() @@ -153,7 +153,7 @@ impl Use { let plugin = &targ.plugin; let p = display_path(p); let global = display_path(global); - warn!("{plugin} is is defined in {p} which overrides the global config ({global})"); + rtxwarn!("{plugin} is is defined in {p} which overrides the global config ({global})"); }; for targ in &self.tool { if let Some(tv) = ts.versions.get(&targ.plugin) { @@ -273,7 +273,10 @@ mod tests { let orig = file::read_to_string(&cf_path).unwrap(); let _ = file::remove_file(&cf_path); - assert_cli_snapshot!("use", "-g", "tiny@2", @"rtx ~/config/config.toml updated with tools: tiny@2"); + assert_cli_snapshot!("use", "-g", "tiny@2", @r###" + rtx ~/config/config.toml updated with tools: tiny@2 + rtx tiny is is defined in ~/cwd/.test-tool-versions which overrides the global config (~/config/config.toml) + "###); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] tiny = "2" diff --git a/src/cli/version.rs b/src/cli/version.rs index 03dc35a92..3f721bcdb 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -71,10 +71,10 @@ fn show_latest() { return; } if let Some(latest) = check_for_new_version(duration::DAILY) { - warn!("rtx version {} available", latest); + rtxwarn!("rtx version {} available", latest); if SelfUpdate::is_available() { let cmd = style("rtx self-update").bright().yellow().for_stderr(); - warn!("To update, run {}", cmd); + rtxwarn!("To update, run {}", cmd); } } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 65c7cbfaa..cf07c09ae 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -198,7 +198,7 @@ impl Config { .into_par_iter() .map(|plugin| { let aliases = plugin.get_aliases().unwrap_or_else(|err| { - warn!("get_aliases: {err}"); + rtxwarn!("get_aliases: {err}"); BTreeMap::new() }); (plugin.name().to_string(), aliases) @@ -495,7 +495,7 @@ fn track_config_files(config_filenames: &[PathBuf]) { Ok(()) }; if let Err(err) = track() { - warn!("tracking config files: {:#}", err); + rtxwarn!("tracking config files: {:#}", err); } } diff --git a/src/env.rs b/src/env.rs index 578b23c9c..fa0f06ee5 100644 --- a/src/env.rs +++ b/src/env.rs @@ -247,7 +247,7 @@ fn get_env_diff() -> EnvDiff { let env = vars().collect::>(); match env.get("__RTX_DIFF") { Some(raw) => EnvDiff::deserialize(raw).unwrap_or_else(|err| { - warn!("Failed to deserialize __RTX_DIFF: {:#}", err); + rtxwarn!("Failed to deserialize __RTX_DIFF: {:#}", err); EnvDiff::default() }), None => EnvDiff::default(), @@ -279,7 +279,7 @@ fn var_option_bool(key: &str) -> Option { Ok(_) if var_is_true(key) => Some(true), Ok(_) if var_is_false(key) => Some(false), Ok(v) => { - warn!("Invalid value for env var {}={}", key, v); + rtxwarn!("Invalid value for env var {}={}", key, v); None } _ => None, diff --git a/src/env_diff.rs b/src/env_diff.rs index 1aea04bf0..9d894b1e1 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -238,7 +238,7 @@ fn normalize_escape_sequences(input: &str) -> String { } }, None => { - warn!("Invalid escape sequence: {}", input); + rtxwarn!("Invalid escape sequence: {}", input); } } } else { diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index f37a056e7..3ea10306b 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -39,7 +39,7 @@ pub fn get_path_with_fake_asdf() -> String { path.insert(0, fake_asdf_path); } Err(e) => { - warn!("Failed to setup fake asdf: {:#}", e); + rtxwarn!("Failed to setup fake asdf: {:#}", e); } }; join_paths(path).unwrap().to_string_lossy().to_string() diff --git a/src/file.rs b/src/file.rs index 5883b7f51..62cb11926 100644 --- a/src/file.rs +++ b/src/file.rs @@ -49,7 +49,7 @@ pub fn remove_dir>(path: P) -> Result<()> { pub fn remove_all_with_warning>(path: P) -> Result<()> { remove_all(&path).map_err(|e| { - warn!("failed to remove {}: {}", path.as_ref().display(), e); + rtxwarn!("failed to remove {}: {}", path.as_ref().display(), e); e }) } diff --git a/src/git.rs b/src/git.rs index 8b919a2bc..2103ce672 100644 --- a/src/git.rs +++ b/src/git.rs @@ -78,7 +78,7 @@ impl Git { } match get_git_version() { Ok(version) => trace!("git version: {}", version), - Err(err) => warn!( + Err(err) => rtxwarn!( "failed to get git version: {:#}\n Git is required to use rtx.", err ), @@ -121,7 +121,7 @@ impl Git { Some(url) } Err(err) => { - warn!( + rtxwarn!( "failed to get remote url for {}: {:#}", self.dir.display(), err diff --git a/src/migrate.rs b/src/migrate.rs index 547aa0745..2277153ab 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -24,14 +24,14 @@ pub fn run() { fn task(s: &Scope, job: impl FnOnce() -> Result<()> + Send + 'static) { s.spawn(|_| { if let Err(err) = job() { - warn!("migrate: {}", err); + rtxwarn!("migrate: {}", err); } }); } fn move_subdirs(from: &Path, to: &Path) -> Result<()> { if from.exists() { - info!("migrating {} to {}", from.display(), to.display()); + rtxstatusln!("migrating {} to {}", from.display(), to.display()); file::create_dir_all(to)?; for f in from.read_dir()? { let f = f?.file_name(); @@ -69,7 +69,7 @@ fn migrate_trusted_configs() -> Result<()> { fn move_dirs(from: &Path, to: &Path) -> Result<()> { if from.exists() && !to.exists() { - info!("migrating {} to {}", from.display(), to.display()); + rtxstatusln!("migrating {} to {}", from.display(), to.display()); file::create_dir_all(to.parent().unwrap())?; file::rename(from, to)?; } @@ -83,7 +83,9 @@ fn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> { if !gitconfig_body.contains(&format!("github.com/rtx-plugins/{plugin_name}")) { return Ok(()); } - info!("removing deprecated plugin {plugin_name}, will use core {name} plugin from now on"); + rtxstatusln!( + "removing deprecated plugin {plugin_name}, will use core {name} plugin from now on" + ); file::remove_all(plugin_root)?; Ok(()) } diff --git a/src/output.rs b/src/output.rs index a16978703..b75098e8a 100644 --- a/src/output.rs +++ b/src/output.rs @@ -52,19 +52,25 @@ macro_rules! rtxstatusln { #[cfg(test)] #[macro_export] macro_rules! rtxwarn { - ($($arg:tt)*) => {{ - let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); - let rtx = console::style("rtx ").yellow().for_stderr(); - stderr.push(format!("{}{}", rtx, format!($($arg)*))); - }}; + ($($arg:tt)*) => { + $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { + let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); + let rtx = console::style("rtx ").yellow().for_stderr(); + stderr.push(format!("{}{}", rtx, format!($($arg)*))); + }) + } } #[cfg(not(test))] #[macro_export] macro_rules! rtxstatusln { ($($arg:tt)*) => {{ - let rtx = console::style("rtx ").dim().for_stderr(); - eprintln!("{}{}", rtx, format!($($arg)*)); + if log_enabled!(log::Level::Info) { + $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { + let rtx = console::style("rtx ").dim().for_stderr(); + eprintln!("{}{}", rtx, format!($($arg)*)); + }); + } }}; } @@ -73,8 +79,10 @@ macro_rules! rtxstatusln { macro_rules! rtxwarn { ($($arg:tt)*) => {{ if log_enabled!(log::Level::Warn) { - let rtx = console::style("rtx ").yellow().for_stderr(); - eprintln!("{}{}", rtx, format!($($arg)*)); + $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { + let rtx = console::style("rtx ").yellow().for_stderr(); + eprintln!("{}{}", rtx, format!($($arg)*)); + }); } }}; } diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index bcb928ad9..b07cdf6b1 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -30,7 +30,7 @@ impl BunPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } let releases: Vec = HTTP_FETCH.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?; diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index a7c44598a..3823be365 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -32,7 +32,7 @@ impl DenoPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } let releases: Vec = HTTP_FETCH.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 7f9c662c1..9be58cb5f 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -69,7 +69,7 @@ impl ErlangPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } self.update_kerl()?; let versions = CorePlugin::run_fetch_task_with_timeout(move || { diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index f9ba54a75..48ba9a8a3 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -32,7 +32,7 @@ impl GoPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } CorePlugin::run_fetch_task_with_timeout(move || { let repo = &*env::RTX_GO_REPO; diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 65d8e5d49..1290d3e42 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -81,7 +81,7 @@ impl JavaPlugin { // match self.core.fetch_remote_versions_from_rtx() { // Ok(Some(versions)) => return Ok(versions), // Ok(None) => {} - // Err(e) => warn!("failed to fetch remote versions: {}", e), + // Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), // } let versions = self .fetch_java_metadata("ga")? @@ -195,7 +195,7 @@ impl JavaPlugin { tv.install_path().as_path(), &tv.install_path().join("Contents").join("Home"), )?; - info!( + rtxstatusln!( "{}", formatdoc! {r#" To enable macOS integration, run the following commands: diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index af56798e6..41441a3f3 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -38,7 +38,7 @@ impl NodePlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } } self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index da2a26fa0..5c6f4f581 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -87,7 +87,7 @@ impl NodeBuildPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } self.install_or_update_node_build()?; let node_build_bin = self.node_build_bin(); diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 346d6c59f..13d22422b 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -68,7 +68,7 @@ impl PythonPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } self.install_or_update_python_build()?; let python_build_bin = self.python_build_bin(); @@ -118,7 +118,7 @@ impl PythonPlugin { if let Some(virtualenv) = tv.opts.get("virtualenv") { let settings = Settings::try_get()?; if !settings.experimental { - warn!( + rtxwarn!( "please enable experimental mode with `rtx settings set experimental true` \ to use python virtualenv activation" ); @@ -131,7 +131,7 @@ impl PythonPlugin { } } if !virtualenv.exists() { - info!("setting up virtualenv at: {}", virtualenv.display()); + rtxstatusln!("setting up virtualenv at: {}", virtualenv.display()); let mut cmd = CmdLineRunner::new(self.python_path(tv)) .arg("-m") .arg("venv") @@ -218,14 +218,13 @@ impl Plugin for PythonPlugin { let contents = file::read_to_string(&patch_file)?; cmd = cmd.arg("--patch").stdin_string(contents); } else { - ctx.pr - .warn(format!("patch file not found: {}", patch_file.display())); + rtxwarn!("patch file not found: {}", patch_file.display()); } } cmd.execute()?; self.test_python(&config, &ctx.tv, ctx.pr.as_ref())?; if let Err(e) = self.get_virtualenv(&config, &ctx.tv, Some(ctx.pr.as_ref())) { - warn!("failed to get virtualenv: {e}"); + rtxwarn!("failed to get virtualenv: {e}"); } self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; Ok(()) @@ -239,7 +238,7 @@ impl Plugin for PythonPlugin { ) -> Result> { let mut hm = HashMap::new(); match self.get_virtualenv(config, tv, None) { - Err(e) => warn!("failed to get virtualenv: {e}"), + Err(e) => rtxwarn!("failed to get virtualenv: {e}"), Ok(Some(virtualenv)) => { let bin = virtualenv.join("bin"); hm.insert("VIRTUAL_ENV".into(), virtualenv.to_string_lossy().into()); diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index ced09d8d1..af6f33ee1 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -148,10 +148,10 @@ impl RubyPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), + Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), } if let Err(err) = self.update_build_tool() { - warn!("{err}"); + rtxwarn!("{err}"); } let ruby_build_bin = self.ruby_build_bin(); let versions = CorePlugin::run_fetch_task_with_timeout(move || { @@ -353,7 +353,7 @@ impl Plugin for RubyPlugin { fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { if let Err(err) = self.update_build_tool() { - warn!("{err}"); + rtxwarn!("{err}"); } assert!(matches!( &ctx.tv.request, diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index b161c8ab4..b1c790eed 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -161,7 +161,7 @@ impl ExternalPlugin { let settings = Settings::try_get()?; match self.fetch_versions() { Ok(Some(versions)) => return Ok(versions), - Err(err) => warn!( + Err(err) => rtxwarn!( "Failed to fetch remote versions for plugin {}: {}", style(&self.name).cyan().for_stderr(), err @@ -475,18 +475,18 @@ impl Plugin for ExternalPlugin { let config = Config::get(); let plugin_path = self.plugin_path.to_path_buf(); if plugin_path.is_symlink() { - pr.warn(format!( + rtxwarn!( "Plugin: {} is a symlink, not updating", style(&self.name).cyan().for_stderr() - )); + ); return Ok(()); } let git = Git::new(plugin_path); if !git.is_repo() { - pr.warn(format!( + rtxwarn!( "Plugin {} is not a git repository, not updating", style(&self.name).cyan().for_stderr() - )); + ); return Ok(()); } pr.set_message("updating git repo".into()); diff --git a/src/shims.rs b/src/shims.rs index 4b32d43ab..72553c446 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -94,7 +94,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { .into_par_iter() .flat_map(|(t, tv)| { list_tool_bins(t.clone(), &tv).unwrap_or_else(|e| { - warn!("Error listing bin paths for {}: {:#}", tv, e); + rtxwarn!("Error listing bin paths for {}: {:#}", tv, e); Vec::new() }) }) diff --git a/src/shorthands.rs b/src/shorthands.rs index c15609492..d68d530ae 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -26,7 +26,7 @@ pub fn get_shorthands() -> Shorthands { shorthands.extend(custom); } Err(err) => { - warn!("Failed to read shorthands file: {} {:#}", &f.display(), err); + rtxwarn!("Failed to read shorthands file: {} {:#}", &f.display(), err); } } } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 88d714316..ee2a361de 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -92,7 +92,7 @@ impl Toolset { .for_each(|(_, v)| v.resolve(config, false)); } pub fn install_arg_versions(&mut self, config: &Config, opts: &InstallOptions) -> Result<()> { - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); let versions = self .list_current_versions() .into_iter() @@ -255,7 +255,7 @@ impl Toolset { let latest = match tv.latest_version(t.as_ref()) { Ok(latest) => latest, Err(e) => { - warn!("Error getting latest version for {t}: {e:#}"); + rtxwarn!("Error getting latest version for {t}: {e:#}"); return None; } }; @@ -289,7 +289,7 @@ impl Toolset { .flat_map(|(p, tv)| match p.exec_env(config, self, &tv) { Ok(env) => env.into_iter().collect(), Err(e) => { - warn!("Error running exec-env: {:#}", e); + rtxwarn!("Error running exec-env: {:#}", e); Vec::new() } }) @@ -316,7 +316,7 @@ impl Toolset { .into_par_iter() .flat_map(|(p, tv)| { p.list_bin_paths(&tv).unwrap_or_else(|e| { - warn!("Error listing bin paths for {tv}: {e:#}"); + rtxwarn!("Error listing bin paths for {tv}: {e:#}"); Vec::new() }) }) @@ -341,7 +341,7 @@ impl Toolset { .filter(|(p, tv)| match p.which(tv, bin_name) { Ok(x) => x.is_some(), Err(e) => { - warn!("Error running which: {:#}", e); + rtxwarn!("Error running which: {:#}", e); false } }) diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index beb2a2dfa..b86aa8933 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -26,7 +26,7 @@ impl ToolVersionList { for (tvr, opts) in &mut self.requests { match tvr.resolve(plugin.as_ref(), opts.clone(), latest_versions) { Ok(v) => self.versions.push(v), - Err(err) => warn!("failed to resolve tool version: {:#}", err), + Err(err) => rtxwarn!("failed to resolve tool version: {:#}", err), } } } diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 7287d2676..207ef7d6a 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,6 +1,6 @@ use crate::config::Settings; -use console::style; use indicatif::MultiProgress; +use std::sync::{Arc, Mutex, Weak}; use crate::ui::progress_report::{ProgressReport, QuietReport, SingleReport, VerboseReport}; @@ -9,23 +9,34 @@ pub struct MultiProgressReport { mp: Option, quiet: bool, } +static INSTANCE: Mutex>> = Mutex::new(None); impl MultiProgressReport { - pub fn new() -> Self { - let settings = Settings::get(); - let mp = match settings.raw - || settings.quiet - || settings.verbose - || !console::user_attended_stderr() - { - true => None, - false => Some(MultiProgress::new()), - }; - MultiProgressReport { - mp, - quiet: settings.quiet, + pub fn try_get() -> Option> { + match &*INSTANCE.lock().unwrap() { + Some(w) => w.upgrade(), + None => None, } } + pub fn get() -> Arc { + Self::try_get().unwrap_or_else(|| { + let settings = Settings::get(); + let mp = match settings.raw + || settings.quiet + || settings.verbose + || !console::user_attended_stderr() + { + true => None, + false => Some(MultiProgress::new()), + }; + let mpr = Arc::new(MultiProgressReport { + mp, + quiet: settings.quiet, + }); + *INSTANCE.lock().unwrap() = Some(Arc::downgrade(&mpr)); + mpr + }) + } pub fn add(&self, prefix: &str) -> Box { match &self.mp { _ if self.quiet => Box::new(QuietReport::new(prefix.to_string())), @@ -37,23 +48,16 @@ impl MultiProgressReport { None => Box::new(VerboseReport::new(prefix.to_string())), } } - pub fn suspend R, R>(&self, f: F) -> R { - match &self.mp { - Some(mp) => mp.suspend(f), + pub fn suspend_if_active R, R>(f: F) -> R { + match Self::try_get() { + Some(mpr) => mpr.suspend(f), None => f(), } } - pub fn warn(&self, message: String) { + pub fn suspend R, R>(&self, f: F) -> R { match &self.mp { - Some(pb) => { - let _ = pb.println(format!( - "{} {}", - style("[WARN]").yellow().for_stderr(), - message - )); - } - None if !self.quiet => warn!("{}", message), - _ => (), + Some(mp) => mp.suspend(f), + None => f(), } } } @@ -64,7 +68,7 @@ mod tests { #[test] fn test_multi_progress_report() { - let mpr = MultiProgressReport::new(); + let mpr = MultiProgressReport::get(); let pr = mpr.add("PREFIX"); pr.finish_with_message("test".into()); pr.println("".into()); diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index dcbe57618..53556bb8e 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -6,7 +6,6 @@ use std::time::Duration; pub trait SingleReport: Send + Sync { fn println(&self, _message: String) {} - fn warn(&self, _message: String); fn error(&self, _message: String); fn set_message(&self, _message: String) {} fn finish(&self) {} @@ -60,10 +59,6 @@ fn error_prefix(pad: usize, prefix: &str) -> String { let prefix = format!("{} {prefix}", style("rtx").red().for_stderr()); pad_prefix(pad, &prefix) } -fn warn_prefix(pad: usize, prefix: &str) -> String { - let prefix = format!("{} {prefix}", style("rtx").yellow().for_stderr()); - pad_prefix(pad, &prefix) -} fn success_prefix(pad: usize, prefix: &str) -> String { let prefix = format!("{} {prefix}", style("rtx").green().for_stderr()); pad_prefix(pad, &prefix) @@ -86,11 +81,6 @@ impl SingleReport for ProgressReport { eprintln!("{message}"); }); } - fn warn(&self, message: String) { - let msg = format!("{} {message}", style("[WARN]").yellow().for_stderr()); - self.pb.set_prefix(warn_prefix(self.pad, &self.prefix)); - self.pb.println(msg); - } fn error(&self, message: String) { let msg = format!("{} {message}", style("[ERROR]").red().for_stderr()); self.set_message(msg); @@ -130,11 +120,6 @@ impl QuietReport { } impl SingleReport for QuietReport { - fn warn(&self, message: String) { - let prefix = warn_prefix(self.pad - 2, &self.prefix); - let x = style("⚠").yellow().for_stderr(); - warn!("{prefix} {x} {message}"); - } fn error(&self, message: String) { let prefix = error_prefix(self.pad - 2, &self.prefix); let x = style("✗").red().for_stderr(); @@ -160,11 +145,6 @@ impl SingleReport for VerboseReport { fn println(&self, message: String) { eprintln!("{message}"); } - fn warn(&self, message: String) { - let prefix = warn_prefix(self.pad - 2, &self.prefix); - let x = style("⚠").yellow().for_stderr(); - warn!("{prefix} {x} {message}"); - } fn error(&self, message: String) { let prefix = error_prefix(self.pad - 2, &self.prefix); let x = style("✗").red().for_stderr(); From d36c3a488cd3a99854d49cf930ad299b74429a6d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:31:07 -0600 Subject: [PATCH 1373/1891] plugin-update: fix git repo url fetching (#1232) --- src/plugins/external_plugin.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index b1c790eed..e7fdc9e3d 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -452,7 +452,7 @@ impl Plugin for ExternalPlugin { return Ok(()); } if !settings.yes && self.repo_url.is_none() { - let url = self.get_repo_url(&config)?; + let url = self.get_repo_url(&config).unwrap_or_default(); if !url.starts_with("https://github.com/rtx-plugins/") { eprintln!( "⚠️ {name} is a community-developed plugin: {url}", @@ -472,7 +472,6 @@ impl Plugin for ExternalPlugin { } fn update(&self, pr: &dyn SingleReport, gitref: Option) -> Result<()> { - let config = Config::get(); let plugin_path = self.plugin_path.to_path_buf(); if plugin_path.is_symlink() { rtxwarn!( @@ -492,7 +491,7 @@ impl Plugin for ExternalPlugin { pr.set_message("updating git repo".into()); let (_pre, _post) = git.update(gitref)?; let sha = git.current_sha_short()?; - let repo_url = self.get_repo_url(&config)?; + let repo_url = self.get_remote_url().unwrap_or_default(); self.exec_hook(pr, "post-plugin-update")?; pr.finish_with_message(format!( "{repo_url}#{}", From b420e6b556aefb547cd868d5768bcfa72fa212ea Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:30:32 -0600 Subject: [PATCH 1374/1891] version: show version in debug mode --- src/cli/version.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli/version.rs b/src/cli/version.rs index 3f721bcdb..9e4530591 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -59,6 +59,7 @@ pub fn print_version_if_requested() { std::process::exit(0); } } + debug!("{}", *VERSION); } fn show_version() { From f42fdd22cb89affe8dbb5950d7d890aa02126232 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:56:11 -0600 Subject: [PATCH 1375/1891] show missing version message on more commands (#1233) Disable by setting RTX_DISABLE_PLUGINS or running with --quiet --- src/cli/bin_paths.rs | 1 + src/cli/env.rs | 1 + src/cli/exec.rs | 1 + src/cli/hook_env.rs | 20 ++------------------ src/cli/shell.rs | 1 + src/cli/upgrade.rs | 6 +++++- src/toolset/mod.rs | 20 +++++++++++++++++++- 7 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index fa29d4cdb..25fd5091d 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -12,6 +12,7 @@ pub struct BinPaths {} impl BinPaths { pub fn run(self, config: &Config) -> Result<()> { let ts = ToolsetBuilder::new().build(config)?; + ts.warn_if_versions_missing(); for p in ts.list_paths() { rtxprintln!("{}", p.display()); } diff --git a/src/cli/env.rs b/src/cli/env.rs index 7bc9faadd..0415e0d3d 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -46,6 +46,7 @@ impl Env { latest_versions: false, }; ts.install_arg_versions(config, &opts)?; + ts.warn_if_versions_missing(); if self.json { self.output_json(config, ts) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 7fe61d68e..e210e0f9f 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -64,6 +64,7 @@ impl Exec { latest_versions: false, }; ts.install_arg_versions(config, &opts)?; + ts.warn_if_versions_missing(); let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); let env = ts.env_with_path(config); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index b5653d3c4..ccbf9de98 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,4 +1,4 @@ -use console::{style, truncate_str}; +use console::truncate_str; use std::env::{join_paths, split_paths}; use std::ops::Deref; use std::path::PathBuf; @@ -61,7 +61,7 @@ impl HookEnv { if self.status { self.display_status(config, &ts); } - self.missing_versions_warning(&ts); + ts.warn_if_versions_missing(); Ok(()) } @@ -166,22 +166,6 @@ impl HookEnv { hook_env::serialize_watches(&watches)?, )) } - fn missing_versions_warning(&self, ts: &Toolset) { - let missing = ts.list_missing_versions(); - if missing.is_empty() { - return; - } - let versions = missing - .iter() - .map(|tv| tv.to_string()) - .collect::>() - .join(", "); - rtxwarn!( - "missing: {}. Install with {}", - truncate_str(&versions, TERM_WIDTH.max(60) - 39, "…"), - style("rtx install").yellow().for_stderr(), - ); - } } fn patch_to_status(patch: EnvDiffOperation) -> String { diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 1a52e4e5c..dfe02c0c6 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -46,6 +46,7 @@ impl Shell { latest_versions: false, }; ts.install_arg_versions(&config, &opts)?; + ts.warn_if_versions_missing(); let shell = get_shell(None).expect("no shell detected"); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index afac9d347..22c845c8c 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -140,7 +140,11 @@ impl Upgrade { .filterable(true) .min(1); for (_, tv, latest) in outdated { - let label = format!("{tv} -> {latest}"); + let label = if &tv.version == latest { + tv.to_string() + } else { + format!("{tv} -> {latest}") + }; ms = ms.option(DemandOption::new(tv).label(&label)); } Ok(ms.run()?.into_iter().cloned().collect()) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index ee2a361de..400a90890 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::thread; -use console::style; +use console::{style, truncate_str}; use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; @@ -18,6 +18,7 @@ pub use tool_version_request::ToolVersionRequest; use crate::config::{Config, Settings}; use crate::env; +use crate::env::TERM_WIDTH; use crate::install_context::InstallContext; use crate::path_env::PathEnv; use crate::plugins::{Plugin, PluginName}; @@ -348,6 +349,23 @@ impl Toolset { .map(|(_, tv)| tv) .collect()) } + + pub fn warn_if_versions_missing(&self) { + let missing = self.list_missing_versions(); + if missing.is_empty() { + return; + } + let versions = missing + .iter() + .map(|tv| tv.to_string()) + .collect::>() + .join(", "); + rtxwarn!( + "missing: {}. Install with {}", + truncate_str(&versions, TERM_WIDTH.max(60) - 39, "…"), + style("rtx install").yellow().for_stderr(), + ); + } } impl Display for Toolset { From 7ef7870696f94ee1ed00309a61dacb3933c0453a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:08:55 -0600 Subject: [PATCH 1376/1891] logger: clean up warn/error logging (#1235) --- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 14 +++-------- src/cmd.rs | 2 +- src/config/mod.rs | 2 +- src/output.rs | 25 +++++++++++++++++++ src/ui/multi_progress_report.rs | 2 +- src/ui/progress_report.rs | 44 ++++----------------------------- 7 files changed, 38 insertions(+), 53 deletions(-) diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 1130de3c4..e95928970 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -55,7 +55,7 @@ impl Uninstall { let prefix = format!("{}", style(&tv).cyan().for_stderr()); let pr = mpr.add(&prefix); if let Err(err) = plugin.uninstall_version(&tv, pr.as_ref(), self.dry_run) { - pr.error(err.to_string()); + rtxerror!("{err}"); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); } if self.dry_run { diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 22c845c8c..8cdf9b818 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -122,16 +122,10 @@ impl Upgrade { tv: &ToolVersion, pr: &dyn SingleReport, ) -> Result<()> { - match tool.uninstall_version(tv, pr, self.dry_run) { - Ok(_) => { - pr.finish(); - Ok(()) - } - Err(err) => { - pr.error(err.to_string()); - Err(err.wrap_err(format!("failed to uninstall {tv}"))) - } - } + tool.uninstall_version(tv, pr, self.dry_run) + .wrap_err_with(|| format!("failed to uninstall {tv}"))?; + pr.finish(); + Ok(()) } fn get_interactive_tool_set(&self, outdated: &OutputVec) -> Result> { diff --git a/src/cmd.rs b/src/cmd.rs index 3fe46fc18..8e9cfaf7e 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -288,7 +288,7 @@ impl<'a> CmdLineRunner<'a> { let settings = Settings::try_get()?; match self.pr { Some(pr) => { - pr.error(format!("{} failed", self.get_program())); + rtxerror!("{} failed", self.get_program()); if !settings.verbose && !output.trim().is_empty() { pr.println(output); } diff --git a/src/config/mod.rs b/src/config/mod.rs index cf07c09ae..9c7ff7fff 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -233,7 +233,7 @@ impl Config { .map(|path| match config_file::parse(&path) { Ok(cf) => Some((path, cf)), Err(err) => { - error!("Error loading config file: {:#}", err); + rtxerror!("Error loading config file: {:#}", err); None } }) diff --git a/src/output.rs b/src/output.rs index b75098e8a..3d074c760 100644 --- a/src/output.rs +++ b/src/output.rs @@ -61,6 +61,18 @@ macro_rules! rtxwarn { } } +#[cfg(test)] +#[macro_export] +macro_rules! rtxerror { + ($($arg:tt)*) => { + $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { + let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); + let rtx = console::style("rtx ").red().for_stderr(); + stderr.push(format!("{}{}", rtx, format!($($arg)*))); + }) + } + } + #[cfg(not(test))] #[macro_export] macro_rules! rtxstatusln { @@ -87,6 +99,19 @@ macro_rules! rtxwarn { }}; } +#[cfg(not(test))] +#[macro_export] +macro_rules! rtxerror { + ($($arg:tt)*) => {{ + if log_enabled!(log::Level::Error) { + $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { + let rtx = console::style("rtx ").red().for_stderr(); + eprintln!("{}{}", rtx, format!($($arg)*)); + }); + } + }}; +} + #[cfg(test)] pub mod tests { use std::sync::Mutex; diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 207ef7d6a..9f7a78cff 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -39,7 +39,7 @@ impl MultiProgressReport { } pub fn add(&self, prefix: &str) -> Box { match &self.mp { - _ if self.quiet => Box::new(QuietReport::new(prefix.to_string())), + _ if self.quiet => Box::new(QuietReport::new()), Some(mp) => { let mut pr = ProgressReport::new(prefix.into()); pr.pb = mp.add(pr.pb); diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 53556bb8e..084bdc597 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -6,7 +6,6 @@ use std::time::Duration; pub trait SingleReport: Send + Sync { fn println(&self, _message: String) {} - fn error(&self, _message: String); fn set_message(&self, _message: String) {} fn finish(&self) {} fn finish_with_message(&self, _message: String) {} @@ -25,11 +24,6 @@ static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { ProgressStyle::with_template(tmpl.as_str()).unwrap() }); -static ERROR_TEMPLATE: Lazy = Lazy::new(|| { - let tmpl = format!("{{prefix}} {} {{wide_msg}}", style("✗").red().for_stderr()); - ProgressStyle::with_template(tmpl.as_str()).unwrap() -}); - #[derive(Debug)] pub struct ProgressReport { pub pb: ProgressBar, @@ -55,10 +49,6 @@ fn normal_prefix(pad: usize, prefix: &str) -> String { let prefix = format!("{} {prefix}", style("rtx").dim().for_stderr()); pad_prefix(pad, &prefix) } -fn error_prefix(pad: usize, prefix: &str) -> String { - let prefix = format!("{} {prefix}", style("rtx").red().for_stderr()); - pad_prefix(pad, &prefix) -} fn success_prefix(pad: usize, prefix: &str) -> String { let prefix = format!("{} {prefix}", style("rtx").green().for_stderr()); pad_prefix(pad, &prefix) @@ -81,13 +71,6 @@ impl SingleReport for ProgressReport { eprintln!("{message}"); }); } - fn error(&self, message: String) { - let msg = format!("{} {message}", style("[ERROR]").red().for_stderr()); - self.set_message(msg); - self.pb.set_style(ERROR_TEMPLATE.clone()); - self.pb.set_prefix(error_prefix(self.pad - 2, &self.prefix)); - self.pb.finish(); - } fn set_message(&self, message: String) { self.pb.set_message(message.replace('\r', "")); } @@ -105,27 +88,15 @@ impl SingleReport for ProgressReport { } } -pub struct QuietReport { - prefix: String, - pad: usize, -} +pub struct QuietReport {} impl QuietReport { - pub fn new(prefix: String) -> QuietReport { - QuietReport { - prefix, - pad: *LONGEST_PLUGIN_NAME, - } + pub fn new() -> QuietReport { + QuietReport {} } } -impl SingleReport for QuietReport { - fn error(&self, message: String) { - let prefix = error_prefix(self.pad - 2, &self.prefix); - let x = style("✗").red().for_stderr(); - error!("{prefix} {x} {message}"); - } -} +impl SingleReport for QuietReport {} pub struct VerboseReport { prefix: String, @@ -145,11 +116,6 @@ impl SingleReport for VerboseReport { fn println(&self, message: String) { eprintln!("{message}"); } - fn error(&self, message: String) { - let prefix = error_prefix(self.pad - 2, &self.prefix); - let x = style("✗").red().for_stderr(); - error!("{prefix} {x} {message}"); - } fn set_message(&self, message: String) { // let prefix = normal_prefix(self.pad, &self.prefix); // eprintln!("{prefix} {message}"); @@ -185,7 +151,7 @@ mod tests { #[test] fn test_progress_report_quiet() { - let pr = QuietReport::new("PREFIX".to_string()); + let pr = QuietReport::new(); pr.set_message("message".into()); pr.finish_with_message("message".into()); } From 03525afda3c1a7f6a5709713a1b877297bc57686 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:28:31 -0600 Subject: [PATCH 1377/1891] progress: fixed race condition --- src/ui/multi_progress_report.rs | 42 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 9f7a78cff..fc21fa2f9 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -19,23 +19,31 @@ impl MultiProgressReport { } } pub fn get() -> Arc { - Self::try_get().unwrap_or_else(|| { - let settings = Settings::get(); - let mp = match settings.raw - || settings.quiet - || settings.verbose - || !console::user_attended_stderr() - { - true => None, - false => Some(MultiProgress::new()), - }; - let mpr = Arc::new(MultiProgressReport { - mp, - quiet: settings.quiet, - }); - *INSTANCE.lock().unwrap() = Some(Arc::downgrade(&mpr)); - mpr - }) + let mut mutex = INSTANCE.lock().unwrap(); + if let Some(w) = &*mutex { + if let Some(mpr) = w.upgrade() { + return mpr; + } + } + + let mpr = Arc::new(Self::new()); + *mutex = Some(Arc::downgrade(&mpr)); + mpr + } + fn new() -> Self { + let settings = Settings::get(); + let mp = match settings.raw + || settings.quiet + || settings.verbose + || !console::user_attended_stderr() + { + true => None, + false => Some(MultiProgress::new()), + }; + MultiProgressReport { + mp, + quiet: settings.quiet, + } } pub fn add(&self, prefix: &str) -> Box { match &self.mp { From 189221c4c28b87da43920b5b192a48cc2b110d06 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:22:33 -0600 Subject: [PATCH 1378/1891] logger: clean up warn/error logging (#1236) --- src/cache.rs | 4 ++-- src/cli/cache/clear.rs | 4 ++-- src/cli/config/generate.rs | 2 +- src/cli/current.rs | 10 ++++----- src/cli/external.rs | 2 +- src/cli/hook_env.rs | 6 ++--- src/cli/install.rs | 6 ++--- src/cli/link.rs | 2 +- src/cli/ls.rs | 6 ++--- src/cli/outdated.rs | 2 +- src/cli/plugins/install.rs | 6 ++--- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/uninstall.rs | 6 ++--- src/cli/upgrade.rs | 2 +- src/cli/use.rs | 2 +- src/cli/version.rs | 4 ++-- src/cmd.rs | 2 +- src/config/mod.rs | 6 ++--- src/env.rs | 6 ++--- src/env_diff.rs | 2 +- src/fake_asdf.rs | 2 +- src/file.rs | 2 +- src/git.rs | 4 ++-- src/main.rs | 2 -- src/migrate.rs | 10 ++++----- src/output.rs | 38 ++++++++++++++++++++++++-------- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/erlang.rs | 2 +- src/plugins/core/go.rs | 2 +- src/plugins/core/java.rs | 4 ++-- src/plugins/core/node.rs | 2 +- src/plugins/core/node_build.rs | 2 +- src/plugins/core/python.rs | 12 +++++----- src/plugins/core/ruby.rs | 6 ++--- src/plugins/external_plugin.rs | 6 ++--- src/shims.rs | 2 +- src/shorthands.rs | 2 +- src/toolset/mod.rs | 10 ++++----- src/toolset/tool_version_list.rs | 2 +- 41 files changed, 105 insertions(+), 93 deletions(-) diff --git a/src/cache.rs b/src/cache.rs index cd52df8dd..67e3d3d24 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -62,13 +62,13 @@ where match self.parse() { Ok(val) => return Ok::<_, color_eyre::Report>(val), Err(err) => { - rtxwarn!("failed to parse cache file: {} {:#}", path.display(), err); + warn!("failed to parse cache file: {} {:#}", path.display(), err); } } } let val = (fetch)()?; if let Err(err) = self.write(&val) { - rtxwarn!("failed to write cache file: {} {:#}", path.display(), err); + warn!("failed to write cache file: {} {:#}", path.display(), err); } Ok(val) })?; diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index b3da775ba..107a004e9 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -25,8 +25,8 @@ impl CacheClear { } } match &self.plugin { - Some(plugins) => rtxstatusln!("cache cleared for {}", plugins.join(", ")), - None => rtxstatusln!("cache cleared"), + Some(plugins) => info!("cache cleared for {}", plugins.join(", ")), + None => info!("cache cleared"), } Ok(()) } diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index a875c4d87..a94e3e9b1 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -79,7 +79,7 @@ impl ConfigGenerate { "# .trim(); if let Some(output) = &self.output { - rtxstatusln!("writing to {}", display_path(output)); + info!("writing to {}", display_path(output)); file::write(output, doc)?; } else { rtxprintln!("{doc}"); diff --git a/src/cli/current.rs b/src/cli/current.rs index 3d875d830..937cb9719 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -36,7 +36,7 @@ impl Current { fn one(&self, ts: Toolset, tool: &dyn Plugin) -> Result<()> { if !tool.is_installed() { - rtxwarn!("Plugin {} is not installed", tool.name()); + warn!("Plugin {} is not installed", tool.name()); return Ok(()); } match ts @@ -55,7 +55,7 @@ impl Current { ); } None => { - rtxwarn!("Plugin {} does not have a version set", tool.name()); + warn!("Plugin {} does not have a version set", tool.name()); } }; Ok(()) @@ -69,11 +69,9 @@ impl Current { for tv in versions { if !plugin.is_version_installed(tv) { let source = ts.versions.get(&tv.plugin_name).unwrap().source.clone(); - rtxwarn!( + warn!( "{}@{} is specified in {}, but not installed", - tv.plugin_name, - &tv.version, - &source + tv.plugin_name, &tv.version, &source ); } } diff --git a/src/cli/external.rs b/src/cli/external.rs index c269bf23f..58ef6e65d 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -11,7 +11,7 @@ pub fn commands(config: &Config) -> Vec { .flat_map(|p| { p.external_commands().unwrap_or_else(|e| { let p = p.name(); - rtxwarn!("failed to load external commands for plugin {p}: {e:#}"); + warn!("failed to load external commands for plugin {p}: {e:#}"); vec![] }) }) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index ccbf9de98..11e77eea4 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -75,12 +75,12 @@ impl HookEnv { .collect_vec(); if !installed_versions.is_empty() { let status = installed_versions.into_iter().rev().join(" "); - rtxstatusln!("{}", truncate_str(&status, TERM_WIDTH.max(60) - 5, "…")); + info!("{}", truncate_str(&status, TERM_WIDTH.max(60) - 5, "…")); } let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env.clone()).to_patches(); if !env_diff.is_empty() { let env_diff = env_diff.into_iter().map(patch_to_status).join(" "); - rtxstatusln!("{}", truncate_str(&env_diff, TERM_WIDTH.max(60) - 5, "…")); + info!("{}", truncate_str(&env_diff, TERM_WIDTH.max(60) - 5, "…")); } } @@ -113,7 +113,7 @@ impl HookEnv { Ok(Some(op)) => { ops.push(op); } - Err(err) => rtxwarn!("failed to update DIRENV_DIFF: {:#}", err), + Err(err) => warn!("failed to update DIRENV_DIFF: {:#}", err), _ => {} } } diff --git a/src/cli/install.rs b/src/cli/install.rs index 2566de02b..761144934 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -57,8 +57,8 @@ impl Install { let mut ts = ToolsetBuilder::new().build(config)?; let tool_versions = self.get_requested_tool_versions(config, &ts, runtimes, &mpr)?; if tool_versions.is_empty() { - rtxwarn!("no runtimes to install"); - rtxwarn!("specify a version with `rtx install @`"); + warn!("no runtimes to install"); + warn!("specify a version with `rtx install @`"); return Ok(()); } ts.install_versions(config, tool_versions, &mpr, &self.install_opts()) @@ -123,7 +123,7 @@ impl Install { let mut ts = ToolsetBuilder::new().build(config)?; let versions = ts.list_missing_versions(); if versions.is_empty() { - rtxstatusln!("all runtimes are installed"); + info!("all runtimes are installed"); return Ok(()); } let mpr = MultiProgressReport::get(); diff --git a/src/cli/link.rs b/src/cli/link.rs index 5d4e1995a..9b675518c 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -45,7 +45,7 @@ impl Link { }; let path = self.path.absolutize()?; if !path.exists() { - rtxwarn!( + warn!( "Target path {} does not exist", style(path.to_string_lossy()).cyan().for_stderr() ); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 9086e2655..8cd412218 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -135,10 +135,8 @@ impl Ls { } fn display_parseable(&self, runtimes: Vec) -> Result<()> { - rtxwarn!( - "The parseable output format is deprecated and will be removed in a future release." - ); - rtxwarn!("Please use the regular output format instead which has been modified to be more easily parseable."); + warn!("The parseable output format is deprecated and will be removed in a future release."); + warn!("Please use the regular output format instead which has been modified to be more easily parseable."); runtimes .into_iter() .map(|(p, tv, _)| (p, tv)) diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 35e986425..6e004e8be 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -32,7 +32,7 @@ impl Outdated { .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); let outdated = ts.list_outdated_versions(); if outdated.is_empty() { - rtxstatusln!("All tools are up to date"); + info!("All tools are up to date"); } else { self.display(outdated); } diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index b7cee5eb1..a916627a3 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -76,7 +76,7 @@ impl PluginsInstall { let ts = ToolsetBuilder::new().build(config)?; let missing_plugins = ts.list_missing_plugins(config); if missing_plugins.is_empty() { - rtxwarn!("all plugins already installed"); + warn!("all plugins already installed"); } self.install_many(missing_plugins, mpr)?; Ok(()) @@ -104,8 +104,8 @@ impl PluginsInstall { let mut plugin = ExternalPlugin::new(name.clone()); plugin.repo_url = git_url; if !self.force && plugin.is_installed() { - rtxwarn!("Plugin {name} already installed"); - rtxwarn!("Use --force to install anyway"); + warn!("Plugin {name} already installed"); + warn!("Use --force to install anyway"); } else { plugin.ensure_installed(mpr, true)?; } diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 63abc10d8..6540c11ec 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -38,7 +38,7 @@ impl PluginsLsRemote { .unwrap_or(0); if shorthands.is_empty() { - rtxwarn!("default shorthands are disabled"); + warn!("default shorthands are disabled"); } for (plugin, repo) in shorthands { diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index dd54bf5dc..0f5ccddce 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -59,7 +59,7 @@ impl PluginsUninstall { } pr.finish_with_message("uninstalled".into()); } - _ => rtxwarn!( + _ => warn!( "{} is not installed", style(plugin_name).cyan().for_stderr() ), diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index e95928970..50297cbf9 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -48,14 +48,14 @@ impl Uninstall { let mpr = MultiProgressReport::get(); for (plugin, tv) in tool_versions { if !plugin.is_version_installed(&tv) { - rtxwarn!("{} is not installed", style(&tv).cyan().for_stderr()); + warn!("{} is not installed", style(&tv).cyan().for_stderr()); continue; } let prefix = format!("{}", style(&tv).cyan().for_stderr()); let pr = mpr.add(&prefix); if let Err(err) = plugin.uninstall_version(&tv, pr.as_ref(), self.dry_run) { - rtxerror!("{err}"); + error!("{err}"); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); } if self.dry_run { @@ -117,7 +117,7 @@ impl Uninstall { )); } if tvs.is_empty() { - rtxwarn!("no versions found for {}", style(&tool).cyan().for_stderr()); + warn!("no versions found for {}", style(&tool).cyan().for_stderr()); } Ok(tvs) }) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 8cdf9b818..9b1d9844d 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -61,7 +61,7 @@ impl Upgrade { outdated.retain(|(p, _, _)| tool_set.is_empty() || tool_set.contains(p.name())); } if outdated.is_empty() { - rtxstatusln!("All tools are up to date"); + info!("All tools are up to date"); } else { self.upgrade(config, outdated)?; } diff --git a/src/cli/use.rs b/src/cli/use.rs index e687fb355..85b84a593 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -153,7 +153,7 @@ impl Use { let plugin = &targ.plugin; let p = display_path(p); let global = display_path(global); - rtxwarn!("{plugin} is is defined in {p} which overrides the global config ({global})"); + warn!("{plugin} is is defined in {p} which overrides the global config ({global})"); }; for targ in &self.tool { if let Some(tv) = ts.versions.get(&targ.plugin) { diff --git a/src/cli/version.rs b/src/cli/version.rs index 9e4530591..2c0a298e9 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -72,10 +72,10 @@ fn show_latest() { return; } if let Some(latest) = check_for_new_version(duration::DAILY) { - rtxwarn!("rtx version {} available", latest); + warn!("rtx version {} available", latest); if SelfUpdate::is_available() { let cmd = style("rtx self-update").bright().yellow().for_stderr(); - rtxwarn!("To update, run {}", cmd); + warn!("To update, run {}", cmd); } } } diff --git a/src/cmd.rs b/src/cmd.rs index 8e9cfaf7e..cefc3d6d6 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -288,7 +288,7 @@ impl<'a> CmdLineRunner<'a> { let settings = Settings::try_get()?; match self.pr { Some(pr) => { - rtxerror!("{} failed", self.get_program()); + error!("{} failed", self.get_program()); if !settings.verbose && !output.trim().is_empty() { pr.println(output); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 9c7ff7fff..65c7cbfaa 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -198,7 +198,7 @@ impl Config { .into_par_iter() .map(|plugin| { let aliases = plugin.get_aliases().unwrap_or_else(|err| { - rtxwarn!("get_aliases: {err}"); + warn!("get_aliases: {err}"); BTreeMap::new() }); (plugin.name().to_string(), aliases) @@ -233,7 +233,7 @@ impl Config { .map(|path| match config_file::parse(&path) { Ok(cf) => Some((path, cf)), Err(err) => { - rtxerror!("Error loading config file: {:#}", err); + error!("Error loading config file: {:#}", err); None } }) @@ -495,7 +495,7 @@ fn track_config_files(config_filenames: &[PathBuf]) { Ok(()) }; if let Err(err) = track() { - rtxwarn!("tracking config files: {:#}", err); + warn!("tracking config files: {:#}", err); } } diff --git a/src/env.rs b/src/env.rs index fa0f06ee5..4b5fefbd6 100644 --- a/src/env.rs +++ b/src/env.rs @@ -96,7 +96,7 @@ pub static __RTX_DIFF: Lazy = Lazy::new(get_env_diff); pub static __RTX_ORIG_PATH: Lazy> = Lazy::new(|| var("__RTX_ORIG_PATH").ok()); pub static __RTX_WATCH: Lazy> = Lazy::new(|| match var("__RTX_WATCH") { Ok(raw) => deserialize_watches(raw) - .map_err(|e| rtxwarn!("Failed to deserialize __RTX_WATCH {e}")) + .map_err(|e| warn!("Failed to deserialize __RTX_WATCH {e}")) .ok(), _ => None, }); @@ -247,7 +247,7 @@ fn get_env_diff() -> EnvDiff { let env = vars().collect::>(); match env.get("__RTX_DIFF") { Some(raw) => EnvDiff::deserialize(raw).unwrap_or_else(|err| { - rtxwarn!("Failed to deserialize __RTX_DIFF: {:#}", err); + warn!("Failed to deserialize __RTX_DIFF: {:#}", err); EnvDiff::default() }), None => EnvDiff::default(), @@ -279,7 +279,7 @@ fn var_option_bool(key: &str) -> Option { Ok(_) if var_is_true(key) => Some(true), Ok(_) if var_is_false(key) => Some(false), Ok(v) => { - rtxwarn!("Invalid value for env var {}={}", key, v); + warn!("Invalid value for env var {}={}", key, v); None } _ => None, diff --git a/src/env_diff.rs b/src/env_diff.rs index 9d894b1e1..1aea04bf0 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -238,7 +238,7 @@ fn normalize_escape_sequences(input: &str) -> String { } }, None => { - rtxwarn!("Invalid escape sequence: {}", input); + warn!("Invalid escape sequence: {}", input); } } } else { diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 3ea10306b..f37a056e7 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -39,7 +39,7 @@ pub fn get_path_with_fake_asdf() -> String { path.insert(0, fake_asdf_path); } Err(e) => { - rtxwarn!("Failed to setup fake asdf: {:#}", e); + warn!("Failed to setup fake asdf: {:#}", e); } }; join_paths(path).unwrap().to_string_lossy().to_string() diff --git a/src/file.rs b/src/file.rs index 62cb11926..5883b7f51 100644 --- a/src/file.rs +++ b/src/file.rs @@ -49,7 +49,7 @@ pub fn remove_dir>(path: P) -> Result<()> { pub fn remove_all_with_warning>(path: P) -> Result<()> { remove_all(&path).map_err(|e| { - rtxwarn!("failed to remove {}: {}", path.as_ref().display(), e); + warn!("failed to remove {}: {}", path.as_ref().display(), e); e }) } diff --git a/src/git.rs b/src/git.rs index 2103ce672..8b919a2bc 100644 --- a/src/git.rs +++ b/src/git.rs @@ -78,7 +78,7 @@ impl Git { } match get_git_version() { Ok(version) => trace!("git version: {}", version), - Err(err) => rtxwarn!( + Err(err) => warn!( "failed to get git version: {:#}\n Git is required to use rtx.", err ), @@ -121,7 +121,7 @@ impl Git { Some(url) } Err(err) => { - rtxwarn!( + warn!( "failed to get remote url for {}: {:#}", self.dir.display(), err diff --git a/src/main.rs b/src/main.rs index 01d708259..c884faf56 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,5 @@ extern crate core; #[macro_use] -extern crate log; -#[macro_use] extern crate eyre; #[macro_use] extern crate indoc; diff --git a/src/migrate.rs b/src/migrate.rs index 2277153ab..547aa0745 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -24,14 +24,14 @@ pub fn run() { fn task(s: &Scope, job: impl FnOnce() -> Result<()> + Send + 'static) { s.spawn(|_| { if let Err(err) = job() { - rtxwarn!("migrate: {}", err); + warn!("migrate: {}", err); } }); } fn move_subdirs(from: &Path, to: &Path) -> Result<()> { if from.exists() { - rtxstatusln!("migrating {} to {}", from.display(), to.display()); + info!("migrating {} to {}", from.display(), to.display()); file::create_dir_all(to)?; for f in from.read_dir()? { let f = f?.file_name(); @@ -69,7 +69,7 @@ fn migrate_trusted_configs() -> Result<()> { fn move_dirs(from: &Path, to: &Path) -> Result<()> { if from.exists() && !to.exists() { - rtxstatusln!("migrating {} to {}", from.display(), to.display()); + info!("migrating {} to {}", from.display(), to.display()); file::create_dir_all(to.parent().unwrap())?; file::rename(from, to)?; } @@ -83,9 +83,7 @@ fn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> { if !gitconfig_body.contains(&format!("github.com/rtx-plugins/{plugin_name}")) { return Ok(()); } - rtxstatusln!( - "removing deprecated plugin {plugin_name}, will use core {name} plugin from now on" - ); + info!("removing deprecated plugin {plugin_name}, will use core {name} plugin from now on"); file::remove_all(plugin_root)?; Ok(()) } diff --git a/src/output.rs b/src/output.rs index 3d074c760..e6749bf87 100644 --- a/src/output.rs +++ b/src/output.rs @@ -41,7 +41,7 @@ macro_rules! rtxprint { #[cfg(test)] #[macro_export] -macro_rules! rtxstatusln { +macro_rules! info { ($($arg:tt)*) => {{ let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); let rtx = console::style("rtx ").dim().for_stderr(); @@ -51,7 +51,7 @@ macro_rules! rtxstatusln { #[cfg(test)] #[macro_export] -macro_rules! rtxwarn { +macro_rules! warn { ($($arg:tt)*) => { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); @@ -63,7 +63,7 @@ macro_rules! rtxwarn { #[cfg(test)] #[macro_export] -macro_rules! rtxerror { +macro_rules! error { ($($arg:tt)*) => { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); @@ -73,11 +73,27 @@ macro_rules! rtxerror { } } +#[macro_export] +macro_rules! trace { + ($($arg:tt)*) => {{ + log::trace!($($arg)*); + }}; +} + +#[macro_export] +macro_rules! debug { + ($($arg:tt)*) => {{ + log::debug!($($arg)*); + }}; +} + #[cfg(not(test))] #[macro_export] -macro_rules! rtxstatusln { +macro_rules! info { ($($arg:tt)*) => {{ - if log_enabled!(log::Level::Info) { + if log::log_enabled!(log::Level::Debug) { + log::info!($($arg)*); + } else if log::log_enabled!(log::Level::Info) { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let rtx = console::style("rtx ").dim().for_stderr(); eprintln!("{}{}", rtx, format!($($arg)*)); @@ -88,9 +104,11 @@ macro_rules! rtxstatusln { #[cfg(not(test))] #[macro_export] -macro_rules! rtxwarn { +macro_rules! warn { ($($arg:tt)*) => {{ - if log_enabled!(log::Level::Warn) { + if log::log_enabled!(log::Level::Debug) { + log::warn!($($arg)*); + } else if log::log_enabled!(log::Level::Warn) { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let rtx = console::style("rtx ").yellow().for_stderr(); eprintln!("{}{}", rtx, format!($($arg)*)); @@ -101,9 +119,11 @@ macro_rules! rtxwarn { #[cfg(not(test))] #[macro_export] -macro_rules! rtxerror { +macro_rules! error { ($($arg:tt)*) => {{ - if log_enabled!(log::Level::Error) { + if log::log_enabled!(log::Level::Debug) { + log::error!($($arg)*); + } else if log::log_enabled!(log::Level::Error) { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let rtx = console::style("rtx ").red().for_stderr(); eprintln!("{}{}", rtx, format!($($arg)*)); diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index b07cdf6b1..bcb928ad9 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -30,7 +30,7 @@ impl BunPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } let releases: Vec = HTTP_FETCH.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?; diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 3823be365..a7c44598a 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -32,7 +32,7 @@ impl DenoPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } let releases: Vec = HTTP_FETCH.json("https://api.github.com/repos/denoland/deno/releases?per_page=100")?; diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 9be58cb5f..7f9c662c1 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -69,7 +69,7 @@ impl ErlangPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } self.update_kerl()?; let versions = CorePlugin::run_fetch_task_with_timeout(move || { diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 48ba9a8a3..f9ba54a75 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -32,7 +32,7 @@ impl GoPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } CorePlugin::run_fetch_task_with_timeout(move || { let repo = &*env::RTX_GO_REPO; diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 1290d3e42..65d8e5d49 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -81,7 +81,7 @@ impl JavaPlugin { // match self.core.fetch_remote_versions_from_rtx() { // Ok(Some(versions)) => return Ok(versions), // Ok(None) => {} - // Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + // Err(e) => warn!("failed to fetch remote versions: {}", e), // } let versions = self .fetch_java_metadata("ga")? @@ -195,7 +195,7 @@ impl JavaPlugin { tv.install_path().as_path(), &tv.install_path().join("Contents").join("Home"), )?; - rtxstatusln!( + info!( "{}", formatdoc! {r#" To enable macOS integration, run the following commands: diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 41441a3f3..af56798e6 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -38,7 +38,7 @@ impl NodePlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } } self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs index 5c6f4f581..da2a26fa0 100644 --- a/src/plugins/core/node_build.rs +++ b/src/plugins/core/node_build.rs @@ -87,7 +87,7 @@ impl NodeBuildPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } self.install_or_update_node_build()?; let node_build_bin = self.node_build_bin(); diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 13d22422b..2b9044c44 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -68,7 +68,7 @@ impl PythonPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } self.install_or_update_python_build()?; let python_build_bin = self.python_build_bin(); @@ -118,7 +118,7 @@ impl PythonPlugin { if let Some(virtualenv) = tv.opts.get("virtualenv") { let settings = Settings::try_get()?; if !settings.experimental { - rtxwarn!( + warn!( "please enable experimental mode with `rtx settings set experimental true` \ to use python virtualenv activation" ); @@ -131,7 +131,7 @@ impl PythonPlugin { } } if !virtualenv.exists() { - rtxstatusln!("setting up virtualenv at: {}", virtualenv.display()); + info!("setting up virtualenv at: {}", virtualenv.display()); let mut cmd = CmdLineRunner::new(self.python_path(tv)) .arg("-m") .arg("venv") @@ -218,13 +218,13 @@ impl Plugin for PythonPlugin { let contents = file::read_to_string(&patch_file)?; cmd = cmd.arg("--patch").stdin_string(contents); } else { - rtxwarn!("patch file not found: {}", patch_file.display()); + warn!("patch file not found: {}", patch_file.display()); } } cmd.execute()?; self.test_python(&config, &ctx.tv, ctx.pr.as_ref())?; if let Err(e) = self.get_virtualenv(&config, &ctx.tv, Some(ctx.pr.as_ref())) { - rtxwarn!("failed to get virtualenv: {e}"); + warn!("failed to get virtualenv: {e}"); } self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; Ok(()) @@ -238,7 +238,7 @@ impl Plugin for PythonPlugin { ) -> Result> { let mut hm = HashMap::new(); match self.get_virtualenv(config, tv, None) { - Err(e) => rtxwarn!("failed to get virtualenv: {e}"), + Err(e) => warn!("failed to get virtualenv: {e}"), Ok(Some(virtualenv)) => { let bin = virtualenv.join("bin"); hm.insert("VIRTUAL_ENV".into(), virtualenv.to_string_lossy().into()); diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index af6f33ee1..ced09d8d1 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -148,10 +148,10 @@ impl RubyPlugin { match self.core.fetch_remote_versions_from_rtx() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} - Err(e) => rtxwarn!("failed to fetch remote versions: {}", e), + Err(e) => warn!("failed to fetch remote versions: {}", e), } if let Err(err) = self.update_build_tool() { - rtxwarn!("{err}"); + warn!("{err}"); } let ruby_build_bin = self.ruby_build_bin(); let versions = CorePlugin::run_fetch_task_with_timeout(move || { @@ -353,7 +353,7 @@ impl Plugin for RubyPlugin { fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { if let Err(err) = self.update_build_tool() { - rtxwarn!("{err}"); + warn!("{err}"); } assert!(matches!( &ctx.tv.request, diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index e7fdc9e3d..99ad6b93a 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -161,7 +161,7 @@ impl ExternalPlugin { let settings = Settings::try_get()?; match self.fetch_versions() { Ok(Some(versions)) => return Ok(versions), - Err(err) => rtxwarn!( + Err(err) => warn!( "Failed to fetch remote versions for plugin {}: {}", style(&self.name).cyan().for_stderr(), err @@ -474,7 +474,7 @@ impl Plugin for ExternalPlugin { fn update(&self, pr: &dyn SingleReport, gitref: Option) -> Result<()> { let plugin_path = self.plugin_path.to_path_buf(); if plugin_path.is_symlink() { - rtxwarn!( + warn!( "Plugin: {} is a symlink, not updating", style(&self.name).cyan().for_stderr() ); @@ -482,7 +482,7 @@ impl Plugin for ExternalPlugin { } let git = Git::new(plugin_path); if !git.is_repo() { - rtxwarn!( + warn!( "Plugin {} is not a git repository, not updating", style(&self.name).cyan().for_stderr() ); diff --git a/src/shims.rs b/src/shims.rs index 72553c446..4b32d43ab 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -94,7 +94,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { .into_par_iter() .flat_map(|(t, tv)| { list_tool_bins(t.clone(), &tv).unwrap_or_else(|e| { - rtxwarn!("Error listing bin paths for {}: {:#}", tv, e); + warn!("Error listing bin paths for {}: {:#}", tv, e); Vec::new() }) }) diff --git a/src/shorthands.rs b/src/shorthands.rs index d68d530ae..c15609492 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -26,7 +26,7 @@ pub fn get_shorthands() -> Shorthands { shorthands.extend(custom); } Err(err) => { - rtxwarn!("Failed to read shorthands file: {} {:#}", &f.display(), err); + warn!("Failed to read shorthands file: {} {:#}", &f.display(), err); } } } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 400a90890..0d4de2cee 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -256,7 +256,7 @@ impl Toolset { let latest = match tv.latest_version(t.as_ref()) { Ok(latest) => latest, Err(e) => { - rtxwarn!("Error getting latest version for {t}: {e:#}"); + warn!("Error getting latest version for {t}: {e:#}"); return None; } }; @@ -290,7 +290,7 @@ impl Toolset { .flat_map(|(p, tv)| match p.exec_env(config, self, &tv) { Ok(env) => env.into_iter().collect(), Err(e) => { - rtxwarn!("Error running exec-env: {:#}", e); + warn!("Error running exec-env: {:#}", e); Vec::new() } }) @@ -317,7 +317,7 @@ impl Toolset { .into_par_iter() .flat_map(|(p, tv)| { p.list_bin_paths(&tv).unwrap_or_else(|e| { - rtxwarn!("Error listing bin paths for {tv}: {e:#}"); + warn!("Error listing bin paths for {tv}: {e:#}"); Vec::new() }) }) @@ -342,7 +342,7 @@ impl Toolset { .filter(|(p, tv)| match p.which(tv, bin_name) { Ok(x) => x.is_some(), Err(e) => { - rtxwarn!("Error running which: {:#}", e); + warn!("Error running which: {:#}", e); false } }) @@ -360,7 +360,7 @@ impl Toolset { .map(|tv| tv.to_string()) .collect::>() .join(", "); - rtxwarn!( + warn!( "missing: {}. Install with {}", truncate_str(&versions, TERM_WIDTH.max(60) - 39, "…"), style("rtx install").yellow().for_stderr(), diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index b86aa8933..beb2a2dfa 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -26,7 +26,7 @@ impl ToolVersionList { for (tvr, opts) in &mut self.requests { match tvr.resolve(plugin.as_ref(), opts.clone(), latest_versions) { Ok(v) => self.versions.push(v), - Err(err) => rtxwarn!("failed to resolve tool version: {:#}", err), + Err(err) => warn!("failed to resolve tool version: {:#}", err), } } } From 8893991bb3ecfadb2ffa60590d2a3c511557e59c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:31:54 -0600 Subject: [PATCH 1379/1891] cli-parser: consolidate CLI parsing logic (#1237) No more custom parsing so now things like `rtx i -fvv` works correctly --- src/cli/args/log_level.rs | 7 --- src/cli/mod.rs | 16 +++-- src/cli/settings/ls.rs | 3 + ...__config_file__rtx_toml__tests__env-5.snap | 4 ++ ...nfig_file__rtx_toml__tests__fixture-2.snap | 6 +- ...nfig_file__rtx_toml__tests__fixture-6.snap | 4 ++ ...ig_file__rtx_toml__tests__path_dirs-5.snap | 4 ++ ...file__rtx_toml__tests__remove_alias-4.snap | 4 ++ ...ile__rtx_toml__tests__remove_plugin-4.snap | 4 ++ ...__rtx_toml__tests__replace_versions-4.snap | 4 ++ src/config/mod.rs | 3 - src/config/settings.rs | 51 +++++++++++---- src/env.rs | 63 +------------------ src/logger.rs | 16 +++-- src/main.rs | 7 ++- 15 files changed, 102 insertions(+), 94 deletions(-) diff --git a/src/cli/args/log_level.rs b/src/cli/args/log_level.rs index c49abceb5..b650884e8 100644 --- a/src/cli/args/log_level.rs +++ b/src/cli/args/log_level.rs @@ -1,8 +1,5 @@ use clap::{Arg, ArgAction}; use log::LevelFilter; -use once_cell::sync::Lazy; - -use crate::env; #[derive(Clone)] pub struct LogLevel(pub LevelFilter); @@ -13,16 +10,12 @@ impl LogLevel { .long("log-level") .value_name("LEVEL") .help("Set the log output verbosity") - .default_value(DEFAULT_LOG_LEVEL.as_str()) .global(true) .hide(true) .value_parser(["error", "warn", "info", "debug", "trace"]) } } -pub static DEFAULT_LOG_LEVEL: Lazy = - Lazy::new(|| env::RTX_LOG_LEVEL.to_string().to_lowercase()); - pub struct Debug; impl Debug { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 14383edc8..208b7e4cd 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -229,14 +229,22 @@ impl Cli { if let Some(true) = m.get_one::("quiet") { s.quiet = Some(true); } + if let Some(true) = m.get_one::("trace") { + s.log_level = Some("trace".to_string()); + } + if let Some(true) = m.get_one::("debug") { + s.log_level = Some("debug".to_string()); + } + if let Some(log_level) = m.get_one::("log-level") { + s.log_level = Some(log_level.to_string()); + } if *m.get_one::("verbose").unwrap() > 0 { s.verbose = Some(true); } + if *m.get_one::("verbose").unwrap() > 1 { + s.log_level = Some("trace".to_string()); + } } - // if let Some(true) = m.get_one::("trace") { - // s.log_level = Some(true); - // } - // TODO: log_level/debug/trace s } diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 8fe7824aa..d2c0e2e4a 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -20,6 +20,9 @@ impl SettingsLs { let json = settings.to_string(); let doc: BTreeMap = serde_json::from_str(&json)?; for (key, value) in doc { + if Settings::hidden_configs().contains(key.as_str()) { + continue; + } rtxprintln!("{} = {}", key, value); } Ok(()) diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap index 669b186d2..7dfa1bb61 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap @@ -7,17 +7,21 @@ RtxToml(/tmp/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "ci": Null, "color": Null, + "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, + "log_level": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, "shorthands_file": Null, + "trace": Null, "trusted_config_paths": Null, "verbose": Null, "yes": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 189db46c9..d93b2aab0 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -13,6 +13,9 @@ expression: cf.settings().unwrap() ], "plugin_autoupdate_last_check_duration": null, "trusted_config_paths": null, + "log_level": null, + "trace": null, + "debug": null, "verbose": true, "quiet": null, "asdf_compat": null, @@ -23,5 +26,6 @@ expression: cf.settings().unwrap() "disabled_tool" ], "raw": null, - "yes": null + "yes": null, + "ci": null } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index f429e0d9f..4dbbe879b 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -7,7 +7,9 @@ RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref: "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "ci": Null, "color": Null, + "debug": Null, "disable_default_shorthands": Null, "disable_tools": Array [ String("disabled_tool"), @@ -18,10 +20,12 @@ RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref: "legacy_version_file_disable_tools": Array [ String("disabled_tool_from_legacy_file"), ], + "log_level": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, "shorthands_file": Null, + "trace": Null, "trusted_config_paths": Null, "verbose": Bool(true), "yes": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap index e98f35fb6..3cf6222b8 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap @@ -7,17 +7,21 @@ RtxToml(~/fixtures/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "ci": Null, "color": Null, + "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, + "log_level": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, "shorthands_file": Null, + "trace": Null, "trusted_config_paths": Null, "verbose": Null, "yes": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap index a57323b23..1ef19af55 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap @@ -7,17 +7,21 @@ RtxToml(/tmp/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "ci": Null, "color": Null, + "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, + "log_level": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, "shorthands_file": Null, + "trace": Null, "trusted_config_paths": Null, "verbose": Null, "yes": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap index f151f9cca..b72846d1f 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap @@ -7,17 +7,21 @@ RtxToml(/tmp/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "ci": Null, "color": Null, + "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, + "log_level": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, "shorthands_file": Null, + "trace": Null, "trusted_config_paths": Null, "verbose": Null, "yes": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap index 84363c803..88bac99d2 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap @@ -7,17 +7,21 @@ RtxToml(/tmp/.rtx.toml): node@16.0.1 node@18.0.1 { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "ci": Null, "color": Null, + "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, + "log_level": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, "shorthands_file": Null, + "trace": Null, "trusted_config_paths": Null, "verbose": Null, "yes": Null, diff --git a/src/config/mod.rs b/src/config/mod.rs index 65c7cbfaa..05e120d2c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -12,7 +12,6 @@ use rayon::prelude::*; pub use settings::{Settings, SettingsPartial}; -use crate::cli::Cli; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::{ConfigFile, ConfigFileType}; @@ -62,8 +61,6 @@ impl Config { Ok(config) } pub fn load() -> Result { - let cli_settings = Cli::new().settings(&env::ARGS.read().unwrap()); - Settings::add_partial(cli_settings); let global_config = load_rtxrc()?; Settings::add_partial(global_config.settings()?); diff --git a/src/config/settings.rs b/src/config/settings.rs index 2f73b7260..219ba71f4 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,17 +1,17 @@ use confique::env::parse::{list_by_colon, list_by_comma}; use eyre::Result; -use std::collections::BTreeSet; +use std::collections::{BTreeSet, HashSet}; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; use std::sync::{Arc, Once, RwLock}; use confique::{Builder, Config, Partial}; -use log::LevelFilter; -use serde::ser::Error; -use serde_derive::Serialize; +use once_cell::sync::Lazy; use crate::env; +use serde::ser::Error; +use serde_derive::Serialize; #[derive(Config, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize)))] @@ -32,6 +32,12 @@ pub struct Settings { pub plugin_autoupdate_last_check_duration: String, #[config(env = "RTX_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] pub trusted_config_paths: BTreeSet, + #[config(env = "RTX_LOG_LEVEL", default = "info")] + pub log_level: String, + #[config(env = "RTX_TRACE", default = false)] + pub trace: bool, + #[config(env = "RTX_DEBUG", default = false)] + pub debug: bool, #[config(env = "RTX_VERBOSE", default = false)] pub verbose: bool, #[config(env = "RTX_QUIET", default = false)] @@ -50,6 +56,8 @@ pub struct Settings { pub raw: bool, #[config(env = "RTX_YES", default = false)] pub yes: bool, + #[config(env = "CI", default = false)] + pub ci: bool, } pub type SettingsPartial = ::Partial; @@ -76,11 +84,33 @@ impl Settings { settings.verbose = true; settings.jobs = 1; } + if settings.debug { + settings.log_level = "debug".to_string(); + } + if settings.trace { + settings.log_level = "trace".to_string(); + } + if settings.log_level == "trace" || settings.log_level == "debug" { + settings.verbose = true; + settings.debug = true; + if settings.log_level == "trace" { + settings.trace = true; + } + } + if settings.verbose { + settings.quiet = false; + if settings.log_level != "trace" { + settings.log_level = "debug".to_string(); + } + } if !settings.color { console::set_colors_enabled(false); console::set_colors_enabled_stderr(false); } - let settings = Arc::new(Self::default_builder().load()?); + if settings.ci { + settings.yes = true; + } + let settings = Arc::new(settings); *SETTINGS.write().unwrap() = Some(settings.clone()); Ok(settings) } @@ -88,12 +118,6 @@ impl Settings { static ONCE: Once = Once::new(); ONCE.call_once(|| { let mut p = SettingsPartial::empty(); - if *env::CI { - p.yes = Some(true); - } - if *env::RTX_LOG_LEVEL > LevelFilter::Info { - p.verbose = Some(true); - } for arg in &*env::ARGS.read().unwrap() { if arg == "--" { break; @@ -114,6 +138,11 @@ impl Settings { } b } + pub fn hidden_configs() -> HashSet<&'static str> { + static HIDDEN_CONFIGS: Lazy> = + Lazy::new(|| ["ci", "debug", "trace", "log_level"].into()); + HIDDEN_CONFIGS.clone() + } #[cfg(test)] pub fn reset() { diff --git a/src/env.rs b/src/env.rs index 4b5fefbd6..e35e93c61 100644 --- a/src/env.rs +++ b/src/env.rs @@ -60,8 +60,7 @@ pub static RTX_BIN: Lazy = Lazy::new(|| { }); pub static ARGV0: Lazy = Lazy::new(|| ARGS.read().unwrap()[0].to_string()); pub static RTX_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0)); -pub static RTX_LOG_LEVEL: Lazy = Lazy::new(log_level); -pub static RTX_LOG_FILE_LEVEL: Lazy = Lazy::new(log_file_level); +pub static RTX_LOG_FILE_LEVEL: Lazy> = Lazy::new(log_file_level); pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) }); @@ -364,65 +363,9 @@ fn prefer_stale(args: &[String]) -> bool { .contains(&c.as_str()); } -fn log_level() -> LevelFilter { - if var_is_true("RTX_QUIET") { - set_var("RTX_LOG_LEVEL", "error"); - } - if var_is_true("RTX_DEBUG") || var_is_true("RTX_VERBOSE") { - set_var("RTX_LOG_LEVEL", "debug"); - } - if var_is_true("RTX_TRACE") || var("RTX_VERBOSE").is_ok_and(|v| v == "2") { - set_var("RTX_LOG_LEVEL", "trace"); - } - let args = ARGS.read().unwrap(); - for (i, arg) in args.iter().enumerate() { - // stop parsing after "--" or if we're executing as a shim - if arg == "--" || *RTX_BIN_NAME != "rtx" { - break; - } - if let Some(("--log-level", level)) = arg.split_once('=') { - set_var("RTX_LOG_LEVEL", level); - } - if arg == "--log-level" { - if let Some(level) = args.get(i + 1) { - set_var("RTX_LOG_LEVEL", level); - } - } - if arg == "--debug" || arg == "--verbose" || (arg == "-v" && args.len() > 2) { - set_var("RTX_LOG_LEVEL", "debug"); - } - if arg == "--trace" || arg == "-vv" { - set_var("RTX_LOG_LEVEL", "trace"); - } - if arg == "--quiet" || arg == "-q" { - set_var("RTX_LOG_LEVEL", "error"); - } - } - let log_level = var("RTX_LOG_LEVEL") - .unwrap_or_default() - .parse::() - .unwrap_or(LevelFilter::Info); - // set RTX_DEBUG/RTX_TRACE for plugins to use - match log_level { - LevelFilter::Trace => { - set_var("RTX_TRACE", "1"); - set_var("RTX_DEBUG", "1"); - } - LevelFilter::Debug => { - set_var("RTX_DEBUG", "1"); - } - _ => {} - } - - log_level -} - -fn log_file_level() -> LevelFilter { +fn log_file_level() -> Option { let log_level = var("RTX_LOG_FILE_LEVEL").unwrap_or_default(); - match log_level.parse::() { - Ok(level) => level, - _ => *RTX_LOG_LEVEL, - } + log_level.parse::().ok() } fn linux_distro() -> Option { diff --git a/src/logger.rs b/src/logger.rs index 071523007..60c7f9ca3 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,25 +1,31 @@ extern crate simplelog; -use std::env; use std::fs::{create_dir_all, File, OpenOptions}; use std::path::PathBuf; +use crate::config::Settings; +use crate::env; use eyre::Result; use simplelog::*; -pub fn init(log_level: LevelFilter, log_file_level: LevelFilter) { +pub fn init() -> LevelFilter { + let settings = Settings::get(); let mut loggers: Vec> = vec![]; - loggers.push(init_term_logger(log_level)); + let level = settings.log_level.parse().unwrap(); + loggers.push(init_term_logger(level)); if let Ok(log) = env::var("RTX_LOG_FILE") { let log_file = PathBuf::from(log); - if let Some(logger) = init_write_logger(log_file_level, log_file) { + let file_level = env::RTX_LOG_FILE_LEVEL.unwrap_or(level); + if let Some(logger) = init_write_logger(file_level, log_file) { loggers.push(logger) } } CombinedLogger::init(loggers).unwrap_or_else(|err| { eprintln!("rtx: could not initialize logger: {err}"); }); + + level } fn init_log_file(log_file: PathBuf) -> Result { @@ -74,6 +80,6 @@ mod tests { #[test] fn test_init() { - init(LevelFilter::Debug, LevelFilter::Debug); + init(); } } diff --git a/src/main.rs b/src/main.rs index c884faf56..94fd14a68 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ use eyre::Result; use crate::cli::version::VERSION; use crate::cli::Cli; -use crate::config::Config; +use crate::config::{Config, Settings}; #[macro_use] mod output; @@ -70,8 +70,9 @@ fn main() -> Result<()> { }); *env::ARGS.write().unwrap() = env::args().collect(); color_eyre::install()?; - let log_level = *env::RTX_LOG_LEVEL; - logger::init(log_level, *env::RTX_LOG_FILE_LEVEL); + let cli_settings = Cli::new().settings(&env::ARGS.read().unwrap()); + Settings::add_partial(cli_settings); + let log_level = logger::init(); handle_ctrlc(); match run().with_section(|| VERSION.to_string().header("Version:")) { From 8faa2536f19538cfd293f0a7f8de6ece4ec13a3c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:39:37 -0600 Subject: [PATCH 1380/1891] logging: pipe log level settings to plugins (#1238) --- src/env.rs | 2 +- src/plugins/script_manager.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/env.rs b/src/env.rs index e35e93c61..fbca29878 100644 --- a/src/env.rs +++ b/src/env.rs @@ -54,7 +54,7 @@ pub static RTX_ENV: Lazy> = pub static RTX_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("RTX_CONFIG_FILE")); pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); pub static RTX_BIN: Lazy = Lazy::new(|| { - var_path("RTX_EXE") + var_path("RTX_BIN") .or_else(|| current_exe().ok()) .unwrap_or_else(|| "rtx".into()) }); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 82c541c94..9e1e123f3 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -68,10 +68,18 @@ impl Display for Script { } static INITIAL_ENV: Lazy> = Lazy::new(|| { + let settings = Settings::get(); let mut env: HashMap = env::PRISTINE_ENV .iter() .map(|(k, v)| (k.into(), v.into())) .collect(); + if settings.trace { + env.insert("RTX_TRACE".into(), "1".into()); + } + if settings.debug { + env.insert("RTX_DEBUG".into(), "1".into()); + env.insert("RTX_VERBOSE".into(), "1".into()); + } env.extend( (indexmap! { "__RTX_SCRIPT" => "1".to_string(), @@ -80,7 +88,8 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy().to_string(), "RTX_CONCURRENCY" => num_cpus::get().to_string(), "RTX_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), - "RTX_EXE" => env::RTX_BIN.to_string_lossy().to_string(), + "RTX_BIN" => env::RTX_BIN.to_string_lossy().to_string(), + "RTX_LOG_LEVEL" => settings.log_level.to_string(), }) .into_iter() .map(|(k, v)| (k.into(), v.into())), From ad233f6d3413759eba136dad3f537df5a6128be9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:40:32 -0600 Subject: [PATCH 1381/1891] CI: push aur-bin after E2E tests --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff7643445..cf1f76599 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -264,7 +264,7 @@ jobs: bump-aur-bin: runs-on: ubuntu-22.04 timeout-minutes: 30 - needs: [release] + needs: [e2e-linux] steps: - name: Checkout repository uses: actions/checkout@v4 From 7abe91ab62cd221ba8c0dcf70286833eb908e85c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:43:03 -0600 Subject: [PATCH 1382/1891] chore: Release rtx-cli version 2023.12.34 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63535a8b8..9f20acc6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1858,7 +1858,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.33" +version = "2023.12.34" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 81160d5a1..9df91170c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.33" +version = "2023.12.34" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 4795d203a..a2342f6ed 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.33 +rtx 2023.12.34 ``` Hook rtx into your shell (pick the right one for your shell): @@ -359,7 +359,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.33/rtx-v2023.12.33-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.34/rtx-v2023.12.34-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 7e216227e..f076db131 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.33"; + version = "2023.12.34"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 4a7bf8d38..e2f5da3bb 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.33 +Version: 2023.12.34 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 88ba90e6f7cd8f35d3a9b028b676ee9e588d44c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 12:46:23 -0600 Subject: [PATCH 1383/1891] Revert "CI: push aur-bin after E2E tests" This reverts commit ad233f6d3413759eba136dad3f537df5a6128be9. --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf1f76599..ff7643445 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -264,7 +264,7 @@ jobs: bump-aur-bin: runs-on: ubuntu-22.04 timeout-minutes: 30 - needs: [e2e-linux] + needs: [release] steps: - name: Checkout repository uses: actions/checkout@v4 From 6b30014a2981b9a63107bf501b39ec4e4c17028c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:07:21 -0600 Subject: [PATCH 1384/1891] config: improve debug output --- src/config/mod.rs | 26 ++++++++++++++----- .../snapshots/rtx__config__tests__load.snap | 24 +++++++++++++++-- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 05e120d2c..ffc757ed9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,5 @@ use std::collections::{BTreeMap, HashMap}; -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Formatter}; use std::path::PathBuf; use std::sync::{Arc, RwLock}; @@ -30,7 +30,7 @@ type AliasMap = BTreeMap>; type ConfigMap = IndexMap>; type ToolMap = BTreeMap>; -#[derive(Debug, Default)] +#[derive(Default)] pub struct Config { pub global_config: RtxToml, pub config_files: ConfigMap, @@ -127,7 +127,7 @@ impl Config { repo_urls, }; - debug!("{}", &config); + debug!("{config:#?}"); Ok(config) } @@ -496,7 +496,7 @@ fn track_config_files(config_filenames: &[PathBuf]) { } } -impl Display for Config { +impl Debug for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let plugins = self .list_plugins() @@ -509,8 +509,20 @@ impl Display for Config { .iter() .map(|(p, _)| display_path(p)) .collect::>(); - writeln!(f, "Files: {}", config_files.join(", "))?; - write!(f, "Installed Plugins: {}", plugins.join(", ")) + let mut s = f.debug_struct("Config"); + s.field("Config Files", &config_files); + s.field("Installed Plugins", &plugins); + if !self.env.is_empty() { + s.field("Env", &self.env); + s.field("Env Sources", &self.env_sources); + } + if !self.path_dirs.is_empty() { + s.field("Path Dirs", &self.path_dirs); + } + if !self.aliases.is_empty() { + s.field("Aliases", &self.aliases); + } + s.finish() } } @@ -522,6 +534,6 @@ mod tests { #[test] fn test_load() { let config = Config::load().unwrap(); - assert_display_snapshot!(config); + assert_debug_snapshot!(config); } } diff --git a/src/config/snapshots/rtx__config__tests__load.snap b/src/config/snapshots/rtx__config__tests__load.snap index deb69ec87..de5409b8f 100644 --- a/src/config/snapshots/rtx__config__tests__load.snap +++ b/src/config/snapshots/rtx__config__tests__load.snap @@ -2,5 +2,25 @@ source: src/config/mod.rs expression: config --- -Files: ~/cwd/.test-tool-versions, ~/.test-tool-versions, ~/config/config.toml -Installed Plugins: dummy, tiny +Config { + Config Files: [ + "~/cwd/.test-tool-versions", + "~/.test-tool-versions", + "~/config/config.toml", + ], + Installed Plugins: [ + "dummy", + "tiny", + ], + Env: { + "TEST_ENV_VAR": "test-123", + }, + Env Sources: { + "TEST_ENV_VAR": "/Users/jdx/src/rtx/test/config/config.toml", + }, + Aliases: { + "tiny": { + "my/alias": "3.0", + }, + }, +} From cb933d4f03e7e7095c0a522506ab7310349275cb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:12:38 -0600 Subject: [PATCH 1385/1891] logger: label debug logs --- src/cli/mod.rs | 2 +- src/cli/version.rs | 2 +- src/config/mod.rs | 2 +- src/config/snapshots/rtx__config__tests__load.snap | 3 --- src/toolset/builder.rs | 2 +- 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 208b7e4cd..bdbd6328b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -203,7 +203,7 @@ impl Cli { } pub fn run(self, args: &Vec) -> Result<()> { - debug!("{}", &args.join(" ")); + debug!("ARGS: {}", &args.join(" ")); let config = Config::try_get()?; if args[1..] == ["-v"] { // normally this would be considered --verbose diff --git a/src/cli/version.rs b/src/cli/version.rs index 2c0a298e9..fe60b57f3 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -59,7 +59,7 @@ pub fn print_version_if_requested() { std::process::exit(0); } } - debug!("{}", *VERSION); + debug!("Version: {}", *VERSION); } fn show_version() { diff --git a/src/config/mod.rs b/src/config/mod.rs index ffc757ed9..342bd3046 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -514,7 +514,7 @@ impl Debug for Config { s.field("Installed Plugins", &plugins); if !self.env.is_empty() { s.field("Env", &self.env); - s.field("Env Sources", &self.env_sources); + // s.field("Env Sources", &self.env_sources); } if !self.path_dirs.is_empty() { s.field("Path Dirs", &self.path_dirs); diff --git a/src/config/snapshots/rtx__config__tests__load.snap b/src/config/snapshots/rtx__config__tests__load.snap index de5409b8f..c98a8075a 100644 --- a/src/config/snapshots/rtx__config__tests__load.snap +++ b/src/config/snapshots/rtx__config__tests__load.snap @@ -15,9 +15,6 @@ Config { Env: { "TEST_ENV_VAR": "test-123", }, - Env Sources: { - "TEST_ENV_VAR": "/Users/jdx/src/rtx/test/config/config.toml", - }, Aliases: { "tiny": { "my/alias": "3.0", diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index d10d46829..8f1115fc0 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -49,7 +49,7 @@ impl ToolsetBuilder { } toolset.resolve(config); - debug!("{}", toolset); + debug!("Toolset: {}", toolset); Ok(toolset) } From 97eb1f440c2e59dfabe1809779b035586dabc750 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:29:04 -0600 Subject: [PATCH 1386/1891] test: fix alpine builds (#1239) --- src/cli/asdf.rs | 3 ++- .../snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap | 2 +- src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap | 2 +- .../snapshots/rtx__shell__bash__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap | 2 +- .../snapshots/rtx__shell__fish__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap | 2 +- .../snapshots/rtx__shell__nushell__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap | 2 +- .../snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap | 2 +- src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap | 2 +- 12 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index fe179fcf3..5548dae08 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -99,6 +99,7 @@ mod tests { #[test] fn test_fake_asdf_install() { - assert_cli_snapshot!("asdf", "install", "tiny"); + // on alpine this shows a warning, use assert_cli! to just get stdout + assert_snapshot!(assert_cli!("asdf", "install", "tiny")); } } diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap index 7e33daa9d..0d5fbf77d 100644 --- a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap +++ b/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap @@ -1,5 +1,5 @@ --- source: src/cli/asdf.rs -expression: output +expression: "assert_cli!(\"asdf\", \"install\", \"tiny\")" --- diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index ab6c773b6..6b39184b3 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -1,6 +1,6 @@ --- source: src/shell/bash.rs -expression: "bash.activate(exe, true)" +expression: "bash.activate(exe, \" --status\".into())" --- export PATH="/some/dir:$PATH" export RTX_SHELL=bash diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index abb13f678..f202bf9fe 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -1,6 +1,6 @@ --- source: src/shell/bash.rs -expression: "bash.activate(exe, true)" +expression: "bash.activate(exe, \" --status\".into())" --- export RTX_SHELL=bash export __RTX_ORIG_PATH="$PATH" diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index b22d47187..7bd36e638 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -1,6 +1,6 @@ --- source: src/shell/fish.rs -expression: "fish.activate(exe, true)" +expression: "fish.activate(exe, \" --status\".into())" --- fish_add_path -g /some/dir set -gx RTX_SHELL fish diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap index e657c0177..9a512e991 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap @@ -1,6 +1,6 @@ --- source: src/shell/fish.rs -expression: "fish.activate(exe, true)" +expression: "fish.activate(exe, \" --status\".into())" --- set -gx RTX_SHELL fish set -gx __RTX_ORIG_PATH $PATH diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap index b50f1765f..ad3b38e14 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap @@ -1,6 +1,6 @@ --- source: src/shell/nushell.rs -expression: "nushell.activate(exe, true)" +expression: "nushell.activate(exe, \" --status\".into())" --- $env.PATH = ($env.PATH | prepend '/some/dir') export-env { diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap index 0508392e7..b6fc7f4f1 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap @@ -1,6 +1,6 @@ --- source: src/shell/nushell.rs -expression: "nushell.activate(exe, true)" +expression: "nushell.activate(exe, \" --status\".into())" --- export-env { $env.RTX_SHELL = "nu" diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap index d2d7c7a14..5fda84d35 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap @@ -1,6 +1,6 @@ --- source: src/shell/xonsh.rs -expression: "xonsh.activate(exe, true)" +expression: "xonsh.activate(exe, \" --status\".into())" --- from os import environ from xonsh.built_ins import XSH diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap index e8daa9b3c..803db0e6a 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap @@ -1,6 +1,6 @@ --- source: src/shell/xonsh.rs -expression: "xonsh.activate(exe, true)" +expression: "xonsh.activate(exe, \" --status\".into())" --- from os import environ from xonsh.built_ins import XSH diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index ca7f5e7c7..f5bd0c33a 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -1,6 +1,6 @@ --- source: src/shell/zsh.rs -expression: "zsh.activate(exe, true)" +expression: "zsh.activate(exe, \" --status\".into())" --- export PATH="/some/dir:$PATH" export RTX_SHELL=zsh diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap index 4373a8d67..d74ba184f 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -1,6 +1,6 @@ --- source: src/shell/zsh.rs -expression: "zsh.activate(exe, true)" +expression: "zsh.activate(exe, \" --status\".into())" --- export RTX_SHELL=zsh export __RTX_ORIG_PATH="$PATH" From 6764909e985a73f46bf89c2353c18df0bbb82434 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:20:08 -0600 Subject: [PATCH 1387/1891] upgrade: minor tweaks --- src/cli/upgrade.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 9b1d9844d..ed0e4551c 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -49,7 +49,7 @@ impl Upgrade { pub fn run(self, config: &Config) -> Result<()> { let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; let mut outdated = ts.list_outdated_versions(); - if self.interactive { + if self.interactive && !outdated.is_empty() { let tvs = self.get_interactive_tool_set(&outdated)?; outdated.retain(|(_, tv, _)| tvs.contains(tv)); } else { @@ -89,11 +89,11 @@ impl Upgrade { .collect::>(); if self.dry_run { - for (tool, tv) in &to_remove { - rtxprintln!("Would uninstall {} {}", tool, tv); + for (_, tv) in &to_remove { + info!("Would uninstall {tv}"); } for tv in &new_versions { - rtxprintln!("Would install {}", tv); + info!("Would install {tv}"); } return Ok(()); } From bc035aeaf31e82dc254e4fed3696aad3dbebda1b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:20:36 -0600 Subject: [PATCH 1388/1891] upgrade: minor tweaks --- src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap b/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap index 06099fdf3..26fcbfe2b 100644 --- a/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap +++ b/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap @@ -2,5 +2,5 @@ source: src/cli/upgrade.rs expression: output --- -Would uninstall tiny tiny@3.0.0 -Would install tiny@3.1.0 +rtx Would uninstall tiny@3.0.0 +rtx Would install tiny@3.1.0 From eabee1626690768b85aa3d579000ef2a9e366875 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:43:08 -0600 Subject: [PATCH 1389/1891] plugins: hide hidden files as versions (#1240) --- src/cli/current.rs | 6 +++++- src/plugins/mod.rs | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cli/current.rs b/src/cli/current.rs index 937cb9719..10c0635c8 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,3 +1,4 @@ +use console::style; use eyre::Result; use crate::config::Config; @@ -55,7 +56,10 @@ impl Current { ); } None => { - warn!("Plugin {} does not have a version set", tool.name()); + warn!( + "Plugin {} does not have a version set", + style(tool.name()).blue().for_stderr() + ); } }; Ok(()) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 725ffd20c..2dfc3dddc 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -54,10 +54,10 @@ pub trait Plugin: Debug + Send + Sync { fn list_installed_versions(&self) -> Result> { Ok(match self.installs_path().exists() { true => file::dir_subdirs(&self.installs_path())? - .iter() + .into_iter() + .filter(|v| !v.starts_with('.')) .filter(|v| !is_runtime_symlink(&self.installs_path().join(v))) .filter(|v| !self.installs_path().join(v).join("incomplete").exists()) - .cloned() .sorted_by_cached_key(|v| (Versioning::new(v), v.to_string())) .collect(), false => vec![], From 554d50c039848a263ffdc4cd1023c0141027d045 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:49:05 -0600 Subject: [PATCH 1390/1891] upgrade: added "up" alias (#1241) --- completions/_rtx | 4 ++-- completions/rtx.bash | 3 +++ src/cli/upgrade.rs | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index e0c1fef29..cc1679dfc 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -48,7 +48,7 @@ _rtx() { (sync) __rtx_sync_cmd && ret=0 ;; (trust) __rtx_trust_cmd && ret=0 ;; (remove|rm|uninstall) __rtx_uninstall_cmd && ret=0 ;; - (upgrade) __rtx_upgrade_cmd && ret=0 ;; + (up|upgrade) __rtx_upgrade_cmd && ret=0 ;; (u|use) __rtx_use_cmd && ret=0 ;; (v|version) __rtx_version_cmd && ret=0 ;; (where) __rtx_where_cmd && ret=0 ;; @@ -748,7 +748,7 @@ __rtx_cmds() { 'sync:Add tool versions from external tools to rtx' 'trust:Marks a config file as trusted' {remove,rm,uninstall}':Removes runtime versions' - 'upgrade:Upgrades outdated tool versions' + {up,upgrade}':Upgrades outdated tool versions' {u,use}':Change the active version of a tool locally or globally.' 'version:Show rtx version' 'where:Display the installation path for a runtime' diff --git a/completions/rtx.bash b/completions/rtx.bash index e306ed689..6660ee4fc 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -156,6 +156,9 @@ _rtx() { rtx,uninstall) cmd="rtx__uninstall" ;; + rtx,up) + cmd="rtx__upgrade" + ;; rtx,upgrade) cmd="rtx__upgrade" ;; diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index ed0e4551c..a05e38369 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -18,7 +18,7 @@ use crate::ui::progress_report::SingleReport; /// Upgrades outdated tool versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment)] +#[clap(visible_alias = "up", verbatim_doc_comment)] pub struct Upgrade { /// Tool(s) to upgrade /// e.g.: node@20 python@3.10 From d4be34d709f12e53ea63637e45a604b438a0d904 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:56:24 -0600 Subject: [PATCH 1391/1891] readme: added aliases (#1242) --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++ src/cli/render_help.rs | 9 ++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a2342f6ed..be93e47b0 100644 --- a/README.md +++ b/README.md @@ -1733,6 +1733,8 @@ Examples: ### `rtx alias ls [OPTIONS] [PLUGIN]` +**Aliases:** `list` + ```text List aliases Shows the aliases that can be specified. @@ -1760,6 +1762,8 @@ Examples: ### `rtx alias set ` +**Aliases:** `add, create` + ```text Add/update an alias for a plugin @@ -1783,6 +1787,8 @@ Examples: ### `rtx alias unset ` +**Aliases:** `del, delete, remove, rm` + ```text Clears an alias for a plugin @@ -1811,6 +1817,8 @@ Usage: bin-paths ### `rtx cache clear [PLUGIN]...` +**Aliases:** `c` + ```text Deletes all cache files in rtx @@ -1857,6 +1865,8 @@ Examples: ### `rtx config generate [OPTIONS]` +**Aliases:** `g` + ```text [experimental] Generate an .rtx.toml file @@ -1950,6 +1960,8 @@ Examples: ### `rtx env [OPTIONS] [TOOL@VERSION]...` +**Aliases:** `e` + ```text Exports env vars to activate rtx a single time @@ -2016,6 +2028,8 @@ Options: ### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` +**Aliases:** `x` + ```text Execute a command with tool(s) set @@ -2082,6 +2096,8 @@ Options: ### `rtx install [OPTIONS] [TOOL@VERSION]...` +**Aliases:** `i` + ```text Install a tool version @@ -2146,6 +2162,8 @@ Examples: ### `rtx link [OPTIONS] ` +**Aliases:** `ln` + ```text Symlinks a tool version into rtx @@ -2179,6 +2197,8 @@ Examples: ### `rtx ls [OPTIONS] [PLUGIN]...` +**Aliases:** `list` + ```text List installed and/or currently selected tool versions @@ -2298,6 +2318,8 @@ Examples: ### `rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` +**Aliases:** `a, add, i` + ```text Install a plugin @@ -2346,6 +2368,8 @@ Examples: ### `rtx plugins link [OPTIONS] [PATH]` +**Aliases:** `ln` + ```text Symlinks a plugin into rtx @@ -2376,6 +2400,8 @@ Examples: ### `rtx plugins ls [OPTIONS]` +**Aliases:** `list` + ```text List installed plugins @@ -2410,6 +2436,8 @@ Examples: ### `rtx plugins ls-remote [OPTIONS]` +**Aliases:** `list-all, list-remote` + ```text List all available remote plugins @@ -2431,6 +2459,8 @@ Options: ### `rtx plugins uninstall [OPTIONS] [PLUGIN]...` +**Aliases:** `remove, rm` + ```text Removes a plugin @@ -2453,6 +2483,8 @@ Examples: ### `rtx plugins update [OPTIONS] [PLUGIN]...` +**Aliases:** `upgrade` + ```text Updates a plugin to the latest version @@ -2576,6 +2608,8 @@ Examples: ### `rtx settings ls` +**Aliases:** `list` + ```text Show current settings @@ -2593,6 +2627,8 @@ Examples: ### `rtx settings set ` +**Aliases:** `add, create` + ```text Add/update a setting @@ -2613,6 +2649,8 @@ Examples: ### `rtx settings unset ` +**Aliases:** `del, delete, remove, rm` + ```text Clears a setting @@ -2630,6 +2668,8 @@ Examples: ### `rtx shell [OPTIONS] [TOOL@VERSION]...` +**Aliases:** `sh` + ```text Sets a tool version for the current shell session @@ -2737,6 +2777,8 @@ Examples: ### `rtx uninstall [OPTIONS] [TOOL@VERSION]...` +**Aliases:** `remove, rm` + ```text Removes runtime versions @@ -2761,6 +2803,8 @@ Examples: ### `rtx upgrade [OPTIONS] [TOOL@VERSION]...` +**Aliases:** `up` + ```text Upgrades outdated tool versions @@ -2791,6 +2835,8 @@ Options: ### `rtx use [OPTIONS] [TOOL@VERSION]...` +**Aliases:** `u` + ```text Change the active version of a tool locally or globally. diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 26d53e9db..f406813f1 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -85,13 +85,20 @@ fn render_command(parent: Option<&str>, c: &clap::Command) -> Option { }; let mut c = c.override_usage(&usage); + let aliases = c.get_visible_aliases().sorted().collect_vec(); + let aliases = if !aliases.is_empty() { + format!("\n**Aliases:** `{}`\n", aliases.join(", ")) + } else { + String::new() + }; + let about = strip_ansi_codes(&c.render_long_help().to_string()) .trim() .to_string(); Some(formatdoc!( " ### `rtx {usage}` - + {aliases} ```text {about} ``` From d2d36a7dd88b8f0f4a51a3bc2db48e034870d774 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:06:57 -0600 Subject: [PATCH 1392/1891] CI: disable codecov + mega linter comments on PRs (too noisy) (#1243) --- .github/workflows/test.yml | 10 +++++----- .mega-linter.yml | 2 ++ README.md | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bea407b36..0d91ba24c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -89,11 +89,11 @@ jobs: timeout_minutes: 30 max_attempts: 2 command: just test-coverage - - name: Upload to codecov.io - uses: codecov/codecov-action@v3 - with: - fail_ci_if_error: false - files: lcov.info + # - name: Upload to codecov.io + # uses: codecov/codecov-action@v3 + # with: + # fail_ci_if_error: false + # files: lcov.info # super-linter: # runs-on: ubuntu-latest diff --git a/.mega-linter.yml b/.mega-linter.yml index afa427ebb..1404fe113 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -6,6 +6,8 @@ # all, none, or list of linter keys APPLY_FIXES: all +GITHUB_COMMENT_REPORTER: false + # If you use ENABLE variable, all other languages/formats/tooling-formats will # be disabled by default # ENABLE: diff --git a/README.md b/README.md index be93e47b0..821c685a3 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Crates.io GitHub GitHub Workflow Status -Codecov + Discord

Polyglot runtime manager (asdf rust clone)

From 9fbd2a75223208e764d90fac4e03a50354e72820 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:07:54 -0600 Subject: [PATCH 1393/1891] readme: fixed badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 821c685a3..bcdbbfcc3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@
Crates.io GitHub -GitHub Workflow Status +GitHub Workflow Status Discord

Polyglot runtime manager (asdf rust clone)

From 9728e90e3ff21fef5c82f2260b4a8adfc0146ff5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:18:13 -0600 Subject: [PATCH 1394/1891] CI: codacy (#1244) --- .github/workflows/test.yml | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d91ba24c..c84d671f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -89,29 +89,13 @@ jobs: timeout_minutes: 30 max_attempts: 2 command: just test-coverage + - name: Run codacy-coverage-reporter + uses: codacy/codacy-coverage-reporter-action@v1 + with: + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + coverage-reports: lcov.info # - name: Upload to codecov.io # uses: codecov/codecov-action@v3 # with: # fail_ci_if_error: false # files: lcov.info - - # super-linter: - # runs-on: ubuntu-latest - # permissions: - # contents: read - # packages: read - # statuses: write - # steps: - # - name: Checkout Code - # uses: actions/checkout@v3 - # with: - # # Full git history is needed to get a proper - # # list of changed files within `super-linter` - # fetch-depth: 0 - # - # - name: Lint Code Base - # uses: super-linter/super-linter@v5 - # env: - # VALIDATE_ALL_CODEBASE: false - # DEFAULT_BRANCH: main - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 5513f86aea9d08dc4165005fa963c46c896cbc6d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:23:19 -0600 Subject: [PATCH 1395/1891] docker: remote apt-get upgrade makes hadolint happy --- packaging/github-actions/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/packaging/github-actions/Dockerfile b/packaging/github-actions/Dockerfile index 5920b646d..070372154 100644 --- a/packaging/github-actions/Dockerfile +++ b/packaging/github-actions/Dockerfile @@ -10,7 +10,6 @@ ENV TZ=Etc/UTC SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN apt-get update \ - && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ autoconf \ bash \ From 48d82a0df66f30ea7673193cf53e23f30d470fdf Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:09:37 -0600 Subject: [PATCH 1396/1891] style: use consistent colors for tools/plugins (#1245) * style: use consistent colors for tools/plugins * fix tests * style --- src/cli/latest.rs | 7 ++----- src/cli/link.rs | 5 +++-- src/cli/local.rs | 22 ++++++++-------------- src/cli/plugins/link.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/prune.rs | 3 ++- src/cli/uninstall.rs | 8 ++++---- src/cli/upgrade.rs | 5 ++--- src/cli/use.rs | 30 ++++++++++++++---------------- src/plugins/external_plugin.rs | 16 ++++++++-------- src/plugins/script_manager.rs | 4 ++-- src/toolset/mod.rs | 15 ++++++++------- src/ui/mod.rs | 1 + src/ui/style.rs | 23 +++++++++++++++++++++++ 14 files changed, 79 insertions(+), 64 deletions(-) create mode 100644 src/ui/style.rs diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 6926aab6d..7e7356e6b 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,11 +1,11 @@ use color_eyre::eyre::{eyre, Result}; -use console::style; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::toolset::ToolVersionRequest; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::style::style_tool; /// Gets the latest available version for a plugin #[derive(Debug, clap::Args)] @@ -31,10 +31,7 @@ impl Latest { let mut prefix = match self.tool.tvr { None => self.asdf_version, Some(ToolVersionRequest::Version(_, version)) => Some(version), - _ => Err(eyre!( - "invalid version: {}", - style(&self.tool).cyan().for_stderr() - ))?, + _ => Err(eyre!("invalid version: {}", style_tool(&self.tool)))?, }; let plugin = config.get_or_create_plugin(&self.tool.plugin); diff --git a/src/cli/link.rs b/src/cli/link.rs index 9b675518c..a29c26987 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -9,6 +9,7 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::file::{make_symlink, remove_all}; +use crate::ui::style::style_tool; use crate::{dirs, file}; /// Symlinks a tool version into rtx @@ -39,7 +40,7 @@ impl Link { None => { return Err(eyre!( "must provide a version for {}", - style(&self.tool).cyan().for_stderr() + style_tool(&self.tool) )); } }; @@ -57,7 +58,7 @@ impl Link { } else { return Err(eyre!( "Tool version {} already exists, use {} to overwrite", - style(&self.tool).cyan().for_stderr(), + style_tool(&self.tool), style("--force").yellow().for_stderr() )); } diff --git a/src/cli/local.rs b/src/cli/local.rs index 92f27ab6b..35c3b9d16 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -10,6 +10,7 @@ use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME use crate::file::display_path; use crate::plugins::PluginName; +use crate::ui::style::style_tool; use crate::{dirs, env, file}; /// Sets/gets tool version in local .tool-versions or .rtx.toml @@ -111,13 +112,11 @@ pub fn local( for plugin in plugins { cf.remove_plugin(plugin); } - let tools = plugins.iter().map(|r| r.to_string()).join(" "); - rtxprintln!( - "{} {} {}", - style("rtx").dim(), - display_path(path), - style(tools).cyan().strikethrough() - ); + let tools = plugins + .iter() + .map(|r| style(r).blue().for_stderr().to_string()) + .join(" "); + rtxprintln!("{} {} {tools}", style("rtx").dim(), display_path(path)); } if !runtime.is_empty() { @@ -127,13 +126,8 @@ pub fn local( } let pin = pin || (settings.asdf_compat && !fuzzy); cf.add_runtimes(config, &runtimes, pin)?; - let tools = runtimes.iter().map(|r| r.to_string()).join(" "); - rtxprintln!( - "{} {} {}", - style("rtx").dim(), - display_path(path), - style(tools).cyan() - ); + let tools = runtimes.iter().map(style_tool).join(" "); + rtxprintln!("{} {} {tools}", style("rtx").dim(), display_path(path)); } if !runtime.is_empty() || remove.is_some() { diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index da85d6fcc..10b11c78a 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -50,7 +50,7 @@ impl PluginsLink { } else { return Err(eyre!( "plugin {} already exists, use --force to overwrite", - style(&name).cyan().for_stderr() + style(&name).blue().for_stderr() )); } } diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 0f5ccddce..bbf7a8d92 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -61,7 +61,7 @@ impl PluginsUninstall { } _ => warn!( "{} is not installed", - style(plugin_name).cyan().for_stderr() + style(plugin_name).blue().for_stderr() ), } Ok(()) diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 1d4f2aa93..3e46d7699 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -10,6 +10,7 @@ use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; +use crate::ui::style::style_tv; /// Delete unused versions of tools /// @@ -57,7 +58,7 @@ impl Prune { let settings = Settings::try_get()?; let mpr = MultiProgressReport::get(); for (p, tv) in to_delete { - let mut prefix = format!("{}", style(&tv).cyan().for_stderr()); + let mut prefix = style_tv(&tv); if self.dry_run { prefix = format!("{} {} ", prefix, style("[dryrun]").bold()); } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 50297cbf9..a6710a1c4 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -10,6 +10,7 @@ use crate::config::Config; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::style::style_tv; use crate::{runtime_symlinks, shims}; /// Removes runtime versions @@ -48,12 +49,11 @@ impl Uninstall { let mpr = MultiProgressReport::get(); for (plugin, tv) in tool_versions { if !plugin.is_version_installed(&tv) { - warn!("{} is not installed", style(&tv).cyan().for_stderr()); + warn!("{} is not installed", style_tv(&tv)); continue; } - let prefix = format!("{}", style(&tv).cyan().for_stderr()); - let pr = mpr.add(&prefix); + let pr = mpr.add(&style_tv(&tv)); if let Err(err) = plugin.uninstall_version(&tv, pr.as_ref(), self.dry_run) { error!("{err}"); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); @@ -117,7 +117,7 @@ impl Uninstall { )); } if tvs.is_empty() { - warn!("no versions found for {}", style(&tool).cyan().for_stderr()); + warn!("no versions found for {}", style(&tool).blue().for_stderr()); } Ok(tvs) }) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index a05e38369..8b89cc076 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -1,4 +1,3 @@ -use console::style; use demand::DemandOption; use std::collections::HashSet; use std::sync::Arc; @@ -15,6 +14,7 @@ use crate::shims; use crate::toolset::{InstallOptions, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::SingleReport; +use crate::ui::style::style_tv; /// Upgrades outdated tool versions #[derive(Debug, clap::Args)] @@ -105,8 +105,7 @@ impl Upgrade { }; ts.install_versions(config, new_versions, &mpr, &opts)?; for (tool, tv) in to_remove { - let prefix = format!("{}", style(&tv).cyan().for_stderr()); - let pr = mpr.add(&prefix); + let pr = mpr.add(&style_tv(&tv)); self.uninstall_old_version(tool.clone(), &tv, pr.as_ref())?; } diff --git a/src/cli/use.rs b/src/cli/use.rs index 85b84a593..24a9a7c5b 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -12,6 +12,7 @@ use crate::file::display_path; use crate::plugins::PluginName; use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::style::style_tv; use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. @@ -109,12 +110,12 @@ impl Use { let settings = Settings::try_get()?; let pin = self.pin || (settings.asdf_compat && !self.fuzzy); - for (plugin_name, tvl) in &versions.into_iter().group_by(|tv| tv.plugin_name.clone()) { + for (plugin_name, tvl) in &versions.iter().group_by(|tv| tv.plugin_name.clone()) { let versions: Vec = tvl .into_iter() .map(|tv| { if pin { - tv.version + tv.version.clone() } else { tv.request.version() } @@ -130,7 +131,7 @@ impl Use { cf.remove_plugin(plugin_name); } cf.save()?; - self.render_success_message(cf.as_ref()); + self.render_success_message(cf.as_ref(), &versions); Ok(()) } @@ -166,16 +167,13 @@ impl Use { } } - fn render_success_message(&self, cf: &dyn ConfigFile) { + fn render_success_message(&self, cf: &dyn ConfigFile, versions: &[ToolVersion]) { let path = display_path(cf.get_path()); - let (dir, file) = path.rsplit_once('/').unwrap_or(("", &path)); - let tools = self.tool.iter().map(|t| t.to_string()).join(" "); + let tools = versions.iter().map(style_tv).join(", "); rtxprintln!( - "\n{} {}{} updated with tools: {}\n", + "{} {} tools: {tools}", style("rtx").green(), - style(dir.to_owned() + "/").dim(), - file, - style(tools).cyan() + style(path).cyan().for_stderr(), ); } } @@ -231,26 +229,26 @@ mod tests { let cf_path = dirs::CURRENT.join(".test.rtx.toml"); file::write(&cf_path, "").unwrap(); - assert_cli_snapshot!("use", "tiny@2", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny@2"); + assert_cli_snapshot!("use", "tiny@2", @"rtx ~/cwd/.test.rtx.toml tools: tiny@2.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] tiny = "2" "###); - assert_cli_snapshot!("use", "--pin", "tiny", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny"); + assert_cli_snapshot!("use", "--pin", "tiny", @"rtx ~/cwd/.test.rtx.toml tools: tiny@3.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] tiny = "3.1.0" "###); - assert_cli_snapshot!("use", "--fuzzy", "tiny@2", @"rtx ~/cwd/.test.rtx.toml updated with tools: tiny@2"); + assert_cli_snapshot!("use", "--fuzzy", "tiny@2", @"rtx ~/cwd/.test.rtx.toml tools: tiny@2.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] tiny = "2" "###); let p = cf_path.to_string_lossy().to_string(); - assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p, @"rtx ~/cwd/.test.rtx.toml updated with tools:"); + assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p, @"rtx ~/cwd/.test.rtx.toml tools:"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @""); let _ = file::remove_file(&cf_path); @@ -261,7 +259,7 @@ mod tests { let cf_path = dirs::CURRENT.join(".test-tool-versions"); file::write(&cf_path, "").unwrap(); - assert_cli_snapshot!("use", "tiny@3", @"rtx ~/cwd/.test-tool-versions updated with tools: tiny@3"); + assert_cli_snapshot!("use", "tiny@3", @"rtx ~/cwd/.test-tool-versions tools: tiny@3.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" tiny 3 "###); @@ -274,7 +272,7 @@ mod tests { let _ = file::remove_file(&cf_path); assert_cli_snapshot!("use", "-g", "tiny@2", @r###" - rtx ~/config/config.toml updated with tools: tiny@2 + rtx ~/config/config.toml tools: tiny@2.1.0 rtx tiny is is defined in ~/cwd/.test-tool-versions which overrides the global config (~/config/config.toml) "###); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 99ad6b93a..644b7a872 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -163,7 +163,7 @@ impl ExternalPlugin { Ok(Some(versions)) => return Ok(versions), Err(err) => warn!( "Failed to fetch remote versions for plugin {}: {}", - style(&self.name).cyan().for_stderr(), + style(&self.name).blue().for_stderr(), err ), _ => {} @@ -404,7 +404,7 @@ impl Plugin for ExternalPlugin { .wrap_err_with(|| { eyre!( "Failed listing remote versions for plugin {}", - style(&self.name).cyan().for_stderr(), + style(&self.name).blue().for_stderr(), ) }) .cloned() @@ -419,7 +419,7 @@ impl Plugin for ExternalPlugin { .wrap_err_with(|| { eyre!( "Failed fetching latest stable version for plugin {}", - style(&self.name).cyan().for_stderr(), + style(&self.name).blue().for_stderr(), ) }) .cloned() @@ -456,7 +456,7 @@ impl Plugin for ExternalPlugin { if !url.starts_with("https://github.com/rtx-plugins/") { eprintln!( "⚠️ {name} is a community-developed plugin: {url}", - name = style(&self.name).cyan(), + name = style(&self.name).blue(), url = style(url.trim_end_matches(".git")).yellow(), ); if !prompt::confirm(&format!("Would you like to install {}?", self.name))? { @@ -476,7 +476,7 @@ impl Plugin for ExternalPlugin { if plugin_path.is_symlink() { warn!( "Plugin: {} is a symlink, not updating", - style(&self.name).cyan().for_stderr() + style(&self.name).blue().for_stderr() ); return Ok(()); } @@ -484,7 +484,7 @@ impl Plugin for ExternalPlugin { if !git.is_repo() { warn!( "Plugin {} is not a git repository, not updating", - style(&self.name).cyan().for_stderr() + style(&self.name).blue().for_stderr() ); return Ok(()); } @@ -538,7 +538,7 @@ impl Plugin for ExternalPlugin { .wrap_err_with(|| { eyre!( "Failed fetching aliases for plugin {}", - style(&self.name).cyan().for_stderr(), + style(&self.name).blue().for_stderr(), ) })? .iter() @@ -559,7 +559,7 @@ impl Plugin for ExternalPlugin { .wrap_err_with(|| { eyre!( "Failed fetching legacy filenames for plugin {}", - style(&self.name).cyan().for_stderr(), + style(&self.name).blue().for_stderr(), ) }) .cloned() diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 9e1e123f3..9e4259feb 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -82,14 +82,14 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { } env.extend( (indexmap! { - "__RTX_SCRIPT" => "1".to_string(), "ASDF_CONCURRENCY" => num_cpus::get().to_string(), "PATH" => get_path_with_fake_asdf(), + "RTX_BIN" => env::RTX_BIN.to_string_lossy().to_string(), "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy().to_string(), "RTX_CONCURRENCY" => num_cpus::get().to_string(), "RTX_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), - "RTX_BIN" => env::RTX_BIN.to_string_lossy().to_string(), "RTX_LOG_LEVEL" => settings.log_level.to_string(), + "__RTX_SCRIPT" => "1".to_string(), }) .into_iter() .map(|(k, v)| (k.into(), v.into())), diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 0d4de2cee..0c7ff6b33 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -25,6 +25,7 @@ use crate::plugins::{Plugin, PluginName}; use crate::runtime_symlinks; use crate::shims; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::style::style_tv; mod builder; mod tool_source; @@ -150,15 +151,15 @@ impl Toolset { let next_job = || queue.lock().unwrap().pop(); while let Some((t, versions)) = next_job() { for tv in versions { - let prefix = format!("{}", style(&tv).cyan().for_stderr()); + let tv = tv.request.resolve( + t.as_ref(), + tv.opts.clone(), + opts.latest_versions, + )?; let ctx = InstallContext { ts, - tv: tv.request.resolve( - t.as_ref(), - tv.opts.clone(), - opts.latest_versions, - )?, - pr: mpr.add(&prefix), + pr: mpr.add(&style_tv(&tv)), + tv, raw, force: opts.force, }; diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 768fe4f7c..d0ce5ed88 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,4 +1,5 @@ pub mod multi_progress_report; pub mod progress_report; pub mod prompt; +pub mod style; pub mod table; diff --git a/src/ui/style.rs b/src/ui/style.rs new file mode 100644 index 000000000..79097f247 --- /dev/null +++ b/src/ui/style.rs @@ -0,0 +1,23 @@ +use crate::cli::args::tool::ToolArg; +use crate::toolset::ToolVersion; +use console::style; + +pub fn style_tv(tv: &ToolVersion) -> String { + format!( + "{}{}", + style(&tv.plugin_name).bright().for_stderr(), + style(&format!("@{}", &tv.version)).dim().for_stderr() + ) +} +pub fn style_tool(tool: &ToolArg) -> String { + let version = tool + .tvr + .as_ref() + .map(|t| t.version()) + .unwrap_or(String::from("latest")); + format!( + "{}{}", + style(&tool.plugin).bright().for_stderr(), + style(&format!("@{version}",)).dim().for_stderr() + ) +} From 62818f474954e1de91237923d1c97d5d308b81fb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:48:55 -0600 Subject: [PATCH 1397/1891] style --- src/cli/args/tool.rs | 14 ++++++++++++++ src/cli/latest.rs | 5 ++--- src/cli/link.rs | 10 ++-------- src/cli/local.rs | 3 +-- src/cli/prune.rs | 3 +-- src/cli/uninstall.rs | 5 ++--- src/cli/upgrade.rs | 3 +-- src/cli/use.rs | 3 +-- src/toolset/mod.rs | 3 +-- src/toolset/tool_version.rs | 8 ++++++++ src/ui/mod.rs | 1 - src/ui/style.rs | 23 ----------------------- 12 files changed, 33 insertions(+), 48 deletions(-) delete mode 100644 src/ui/style.rs diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index 0590d76bd..db3d1460b 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -2,6 +2,7 @@ use std::ffi::{OsStr, OsString}; use std::fmt::Display; use clap::{Arg, Command, Error}; +use console::style; use eyre::Result; use regex::Regex; @@ -59,6 +60,19 @@ impl ToolArg { ..self } } + + pub fn style(&self) -> String { + let version = self + .tvr + .as_ref() + .map(|t| t.version()) + .unwrap_or(String::from("latest")); + format!( + "{}{}", + style(&self.plugin).blue().for_stderr(), + style(&format!("@{version}",)).dim().for_stderr() + ) + } } impl Display for ToolArg { diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 7e7356e6b..8a66e51ac 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,11 +1,10 @@ -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::toolset::ToolVersionRequest; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::style::style_tool; /// Gets the latest available version for a plugin #[derive(Debug, clap::Args)] @@ -31,7 +30,7 @@ impl Latest { let mut prefix = match self.tool.tvr { None => self.asdf_version, Some(ToolVersionRequest::Version(_, version)) => Some(version), - _ => Err(eyre!("invalid version: {}", style_tool(&self.tool)))?, + _ => bail!("invalid version: {}", self.tool.style()), }; let plugin = config.get_or_create_plugin(&self.tool.plugin); diff --git a/src/cli/link.rs b/src/cli/link.rs index a29c26987..b3b849178 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -9,7 +9,6 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::file::{make_symlink, remove_all}; -use crate::ui::style::style_tool; use crate::{dirs, file}; /// Symlinks a tool version into rtx @@ -37,12 +36,7 @@ impl Link { pub fn run(self, config: &Config) -> Result<()> { let version = match self.tool.tvr { Some(ref tvr) => tvr.version(), - None => { - return Err(eyre!( - "must provide a version for {}", - style_tool(&self.tool) - )); - } + None => bail!("must provide a version for {}", self.tool.style()), }; let path = self.path.absolutize()?; if !path.exists() { @@ -58,7 +52,7 @@ impl Link { } else { return Err(eyre!( "Tool version {} already exists, use {} to overwrite", - style_tool(&self.tool), + self.tool.style(), style("--force").yellow().for_stderr() )); } diff --git a/src/cli/local.rs b/src/cli/local.rs index 35c3b9d16..431a5ae18 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -10,7 +10,6 @@ use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME use crate::file::display_path; use crate::plugins::PluginName; -use crate::ui::style::style_tool; use crate::{dirs, env, file}; /// Sets/gets tool version in local .tool-versions or .rtx.toml @@ -126,7 +125,7 @@ pub fn local( } let pin = pin || (settings.asdf_compat && !fuzzy); cf.add_runtimes(config, &runtimes, pin)?; - let tools = runtimes.iter().map(style_tool).join(" "); + let tools = runtimes.iter().map(|t| t.style()).join(" "); rtxprintln!("{} {} {tools}", style("rtx").dim(), display_path(path)); } diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 3e46d7699..3a67b8ba4 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -10,7 +10,6 @@ use crate::plugins::{Plugin, PluginName}; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; -use crate::ui::style::style_tv; /// Delete unused versions of tools /// @@ -58,7 +57,7 @@ impl Prune { let settings = Settings::try_get()?; let mpr = MultiProgressReport::get(); for (p, tv) in to_delete { - let mut prefix = style_tv(&tv); + let mut prefix = tv.style(); if self.dry_run { prefix = format!("{} {} ", prefix, style("[dryrun]").bold()); } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index a6710a1c4..dde987123 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -10,7 +10,6 @@ use crate::config::Config; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::style::style_tv; use crate::{runtime_symlinks, shims}; /// Removes runtime versions @@ -49,11 +48,11 @@ impl Uninstall { let mpr = MultiProgressReport::get(); for (plugin, tv) in tool_versions { if !plugin.is_version_installed(&tv) { - warn!("{} is not installed", style_tv(&tv)); + warn!("{} is not installed", tv.style()); continue; } - let pr = mpr.add(&style_tv(&tv)); + let pr = mpr.add(&tv.style()); if let Err(err) = plugin.uninstall_version(&tv, pr.as_ref(), self.dry_run) { error!("{err}"); return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 8b89cc076..90aa2bf27 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -14,7 +14,6 @@ use crate::shims; use crate::toolset::{InstallOptions, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::SingleReport; -use crate::ui::style::style_tv; /// Upgrades outdated tool versions #[derive(Debug, clap::Args)] @@ -105,7 +104,7 @@ impl Upgrade { }; ts.install_versions(config, new_versions, &mpr, &opts)?; for (tool, tv) in to_remove { - let pr = mpr.add(&style_tv(&tv)); + let pr = mpr.add(&tv.style()); self.uninstall_old_version(tool.clone(), &tv, pr.as_ref())?; } diff --git a/src/cli/use.rs b/src/cli/use.rs index 24a9a7c5b..35adf6bfc 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -12,7 +12,6 @@ use crate::file::display_path; use crate::plugins::PluginName; use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::style::style_tv; use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. @@ -169,7 +168,7 @@ impl Use { fn render_success_message(&self, cf: &dyn ConfigFile, versions: &[ToolVersion]) { let path = display_path(cf.get_path()); - let tools = versions.iter().map(style_tv).join(", "); + let tools = versions.iter().map(|t| t.style()).join(", "); rtxprintln!( "{} {} tools: {tools}", style("rtx").green(), diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 0c7ff6b33..54d78e922 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -25,7 +25,6 @@ use crate::plugins::{Plugin, PluginName}; use crate::runtime_symlinks; use crate::shims; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::style::style_tv; mod builder; mod tool_source; @@ -158,7 +157,7 @@ impl Toolset { )?; let ctx = InstallContext { ts, - pr: mpr.add(&style_tv(&tv)), + pr: mpr.add(&tv.style()), tv, raw, force: opts.force, diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 421c60010..ae5451019 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -1,3 +1,4 @@ +use console::style; use std::cmp::Ordering; use std::fmt::{Display, Formatter}; use std::fs; @@ -96,6 +97,13 @@ impl ToolVersion { let tv = self.request.resolve(tool, self.opts.clone(), true)?; Ok(tv.version) } + pub fn style(&self) -> String { + format!( + "{}{}", + style(&self.plugin_name).blue().for_stderr(), + style(&format!("@{}", &self.version)).dim().for_stderr() + ) + } fn tv_pathname(&self) -> String { match &self.request { ToolVersionRequest::Version(_, _) => self.version.to_string(), diff --git a/src/ui/mod.rs b/src/ui/mod.rs index d0ce5ed88..768fe4f7c 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,5 +1,4 @@ pub mod multi_progress_report; pub mod progress_report; pub mod prompt; -pub mod style; pub mod table; diff --git a/src/ui/style.rs b/src/ui/style.rs deleted file mode 100644 index 79097f247..000000000 --- a/src/ui/style.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::cli::args::tool::ToolArg; -use crate::toolset::ToolVersion; -use console::style; - -pub fn style_tv(tv: &ToolVersion) -> String { - format!( - "{}{}", - style(&tv.plugin_name).bright().for_stderr(), - style(&format!("@{}", &tv.version)).dim().for_stderr() - ) -} -pub fn style_tool(tool: &ToolArg) -> String { - let version = tool - .tvr - .as_ref() - .map(|t| t.version()) - .unwrap_or(String::from("latest")); - format!( - "{}{}", - style(&tool.plugin).bright().for_stderr(), - style(&format!("@{version}",)).dim().for_stderr() - ) -} From ff8d73c0d19defe98ee616df743ec6320ef7c92d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:52:48 -0600 Subject: [PATCH 1398/1891] style --- src/cli/args/tool.rs | 2 +- src/toolset/tool_version.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index db3d1460b..43202833d 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -70,7 +70,7 @@ impl ToolArg { format!( "{}{}", style(&self.plugin).blue().for_stderr(), - style(&format!("@{version}",)).dim().for_stderr() + style(&format!("@{version}",)).for_stderr() ) } } diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index ae5451019..35afe8f6f 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -101,7 +101,7 @@ impl ToolVersion { format!( "{}{}", style(&self.plugin_name).blue().for_stderr(), - style(&format!("@{}", &self.version)).dim().for_stderr() + style(&format!("@{}", &self.version)).for_stderr() ) } fn tv_pathname(&self) -> String { From 2d18c0b454ed5a57fabb58997e0c447eb97e0636 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:57:55 -0600 Subject: [PATCH 1399/1891] recommend --verbose over RTX_DEBUG --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 94fd14a68..2edd34e03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -118,6 +118,6 @@ fn display_friendly_err(err: Report) { eprintln!( "{} {}", dim_red("rtx"), - dim("Run with RTX_DEBUG=1 for more information") + dim("Run with --verbose or RTX_VERBOSE=1 for more information") ); } From 69bfebe958ff3ab32d24577b09ad2e0cfb3b3e11 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 17:16:02 -0600 Subject: [PATCH 1400/1891] which: improved error message --- src/cli/which.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/cli/which.rs b/src/cli/which.rs index 0bc2c70fb..3b832bf17 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -1,7 +1,8 @@ -use color_eyre::eyre::{eyre, Result}; +use eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; +use crate::dirs::SHIMS; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -43,7 +44,16 @@ impl Which { } Ok(()) } - None => Err(eyre!("{} not found", self.bin_name)), + None => { + if self.has_shim(&self.bin_name) { + bail!("{} is an rtx bin however it is not currently active. Use `rtx use` to activate it in this directory.", self.bin_name) + } else { + bail!( + "{} is not an rtx bin. Perhaps you need to install it first.", + self.bin_name + ) + } + } } } fn get_toolset(&self) -> Result { @@ -55,6 +65,9 @@ impl Which { let ts = tsb.build(&config)?; Ok(ts) } + fn has_shim(&self, shim: &str) -> bool { + SHIMS.join(shim).exists() + } } static AFTER_LONG_HELP: &str = color_print::cstr!( From c34467f31a14675a12df1c1d413080b068b539a8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 17:18:20 -0600 Subject: [PATCH 1401/1891] remove state dir when uninstalling/imploding --- README.md | 1 + src/cli/implode.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bcdbbfcc3..689094d55 100644 --- a/README.md +++ b/README.md @@ -533,6 +533,7 @@ Use `rtx implode` to uninstall rtx. This will remove the rtx binary and all of i Alternatively, manually remove the following directories to fully clean up: - `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) +- `~/.local/state/rtx` (can also be `RTX_STATE_DIR` or `XDG_STATE_HOME/rtx`) - `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) - on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) - on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) diff --git a/src/cli/implode.rs b/src/cli/implode.rs index bd1f00774..d768e7bfa 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -25,7 +25,7 @@ pub struct Implode { impl Implode { pub fn run(self) -> Result<()> { - let mut files = vec![*dirs::DATA, *dirs::CACHE, &*env::RTX_BIN]; + let mut files = vec![*dirs::STATE, *dirs::DATA, *dirs::CACHE, &*env::RTX_BIN]; if self.config { files.push(&dirs::CONFIG); } @@ -68,6 +68,7 @@ mod tests { #[test] fn test_implode() { let stdout = assert_cli!("implode", "--config", "--dry-run"); + assert!(stdout.contains(format!("rm -rf {}", dirs::STATE.display()).as_str())); assert!(stdout.contains(format!("rm -rf {}", dirs::DATA.display()).as_str())); assert!(stdout.contains(format!("rm -rf {}", dirs::CACHE.display()).as_str())); assert!(stdout.contains(format!("rm -rf {}", dirs::CONFIG.display()).as_str())); From 9191686db4f2cd5a90b042612bd3e1ec525ac432 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 21 Dec 2023 17:24:31 -0600 Subject: [PATCH 1402/1891] trust: added --all flag (#1246) --- README.md | 3 +++ completions/_rtx | 1 + completions/rtx.bash | 2 +- completions/rtx.fish | 1 + .../rtx__cli__trust__tests__trust-2.snap | 2 +- .../rtx__cli__trust__tests__trust-3.snap | 2 +- .../rtx__cli__trust__tests__trust-4.snap | 2 +- .../rtx__cli__trust__tests__trust.snap | 2 +- src/cli/trust.rs | 19 +++++++++++++++---- 9 files changed, 25 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 689094d55..6511720d6 100644 --- a/README.md +++ b/README.md @@ -2765,6 +2765,9 @@ Arguments: The config file to trust Options: + -a, --all + Trust all config files in the current directory and its parents + --untrust No longer trust this config diff --git a/completions/_rtx b/completions/_rtx index cc1679dfc..8f7ce320a 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -646,6 +646,7 @@ __rtx_sync_python_cmd() { __rtx_trust_cmd() { _arguments -s -S \ '::config_file:_files' \ + '(-a --all)'{-a,--all}'[Trust all config files in the current directory and its parents]' \ '--untrust[No longer trust this config]' \ '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ diff --git a/completions/rtx.bash b/completions/rtx.bash index 6660ee4fc..2fcf4949b 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -3208,7 +3208,7 @@ _rtx() { return 0 ;; rtx__trust) - opts="-q -v -y -h --untrust --debug --log-level --trace --quiet --verbose --yes --help [CONFIG_FILE]" + opts="-a -q -v -y -h --all --untrust --debug --log-level --trace --quiet --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index 31672563a..dc0a43d30 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -266,6 +266,7 @@ complete -kxc rtx -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versio # trust +complete -kxc rtx -n "$fssf trust" -s a -l all -d 'Trust all config files in the current directory and its parents' complete -kxc rtx -n "$fssf trust" -a "(__fish_complete_path)" -d 'The config file to trust' complete -kxc rtx -n "$fssf trust" -l untrust -d 'No longer trust this config' diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap index f5ac8a47f..ab87a1ba2 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -untrusted ~/cwd/.test-tool-versions +rtx untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap index bef9d4076..efb7aabf7 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -trusted ~/cwd/.test-tool-versions +rtx trusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap index f5ac8a47f..ab87a1ba2 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -untrusted ~/cwd/.test-tool-versions +rtx untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust.snap b/src/cli/snapshots/rtx__cli__trust__tests__trust.snap index bef9d4076..efb7aabf7 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust.snap +++ b/src/cli/snapshots/rtx__cli__trust__tests__trust.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -trusted ~/cwd/.test-tool-versions +rtx trusted ~/cwd/.test-tool-versions diff --git a/src/cli/trust.rs b/src/cli/trust.rs index aa2a86c72..b37f12d12 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -20,17 +20,26 @@ use crate::config::{config_file, DEFAULT_CONFIG_FILENAMES}; pub struct Trust { /// The config file to trust #[clap(value_hint = ValueHint::FilePath, verbatim_doc_comment)] - pub config_file: Option, + config_file: Option, + + /// Trust all config files in the current directory and its parents + #[clap(long, short, verbatim_doc_comment)] + all: bool, /// No longer trust this config #[clap(long)] - pub untrust: bool, + untrust: bool, } impl Trust { pub fn run(self) -> Result<()> { if self.untrust { self.untrust() + } else if self.all { + while self.get_next_untrusted().is_some() { + self.trust()?; + } + Ok(()) } else { self.trust() } @@ -44,7 +53,8 @@ impl Trust { }, }; config_file::untrust(&path)?; - rtxprintln!("untrusted {}", &path.canonicalize()?.display()); + let path = path.canonicalize()?; + info!("untrusted {}", path.display()); Ok(()) } fn trust(&self) -> Result<()> { @@ -56,7 +66,8 @@ impl Trust { }, }; config_file::trust(&path)?; - rtxprintln!("trusted {}", &path.canonicalize()?.display()); + let path = path.canonicalize()?; + info!("trusted {}", path.display()); Ok(()) } From 2c4ec06e8a80354e7880ee2b2ae30590da293aab Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:31:05 -0600 Subject: [PATCH 1403/1891] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 6511720d6..3f6c7b838 100644 --- a/README.md +++ b/README.md @@ -1043,6 +1043,14 @@ See for the list of built-in plugins s [Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn more about how they work. +### Plugin Authors + +https://github.com/rtx-plugins is a GitHub organization for community-developed plugins. +See [SECURITY.md](./SECURITY.md) for more details on how plugins here are treated differently. + +If you'd like your plugin to be hosted here please let me know (GH discussion or discord is fine) +and I'd be happy to host it for you. + ### Plugin Options rtx has support for "plugin options" which is configuration specified in `.rtx.toml` to change behavior From 7801c41273de64fdf8ed437c07d76ae636bd00cb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:37:06 -0600 Subject: [PATCH 1404/1891] Update SECURITY.md --- SECURITY.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 0cb07aad8..b6d594069 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -34,11 +34,9 @@ There are 3 types of plugins: - [core](https://github.com/jdx/rtx/issues/236) - plugins that are hardcoded into the CLI. These are official plugins for the most common languages written in Rust. -- community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. For now these will - only have @jdx as the sole contributor, however this may change in the future for particular plugins with - dedicated owners/collaborators. If you'd like your plugin to be moved here, ask me about it. +- community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. [See below](#rtx-plugins-github-org) for details. - external - plugins owned by other parties, these include plugins in the shorthand registry. These are no more - secure than installing any random tool from the internet. + secure than installing any random tool from the internet. These receive a warning dialog when installed in rtx. Just because a plugin is inside of the shorthand registry (so you can run `rtx install foo@`, does not mean I vouch for it. I have no idea who almost anyone that builds those plugins are. If it's coming from the rtx-plugins @@ -46,7 +44,18 @@ GitHub org, you can have more trust in it. (See the owners with `rtx plugins ls- Over time we should be able to move more plugins into being fully maintained by rtx. I plan to add an `RTX_PARANOID=1` env var that, when set, will make changes to make rtx behave as securely as possible -(e.g.: only using core plugins, only allowing plugins that use GPG verification of assets). +(e.g.: only using core/rtx-plugins plugins, only allowing plugins that use GPG verification of assets). + +## rtx-plugins GitHub org + +This is similar to https://github.com/asdf-community but with the advantage of being a bit more secure by keeping the +contributor count minimal—currently only @jdx will be allowed to merge PRs. For this reason, plugins using this +organization will not receive a confirmation warning dialog when installed with rtx as they've been vetted by a +trusted source. + +If you're a plugin maintainer that would like to move your repo to this org please let me know. Plugins can either +retain compatibility with asdf or use rtx specific functionality—that's up to you. asdf-compatible plugins should +use "asdf-" as the prefix and "rtx-" prefixed-plugins denote rtx-only compatibility. ## Supported Versions @@ -54,7 +63,7 @@ The only supported version is the most recent one. ## Reporting a Vulnerability -Send an email to security@.pub +Send an email to security@ If you want, you may encrypt the message with GPG: @@ -118,4 +127,3 @@ MFPobhR7zlCShd7TdY1a41uxTGB+Wmn4DO0s/wzSgdgxIzG+TM1X47owe7l5RiI1 ``` -``` From 421a3dcc0da158b12d890f32c8933c931a6c042f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:37:29 -0600 Subject: [PATCH 1405/1891] Update SECURITY.md --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index b6d594069..7acdb9e39 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -48,7 +48,7 @@ Over time we should be able to move more plugins into being fully maintained by ## rtx-plugins GitHub org -This is similar to https://github.com/asdf-community but with the advantage of being a bit more secure by keeping the +This is similar to https://github.com/asdf-community but with the advantage of being more secure by keeping the contributor count minimal—currently only @jdx will be allowed to merge PRs. For this reason, plugins using this organization will not receive a confirmation warning dialog when installed with rtx as they've been vetted by a trusted source. From 6ae3fe647716f382c6ac638a8f5896883a10d23c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:43:10 -0600 Subject: [PATCH 1406/1891] Update SECURITY.md --- SECURITY.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 7acdb9e39..7b6e7d955 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -53,9 +53,8 @@ contributor count minimal—currently only @jdx will be allowed to merge PRs. Fo organization will not receive a confirmation warning dialog when installed with rtx as they've been vetted by a trusted source. -If you're a plugin maintainer that would like to move your repo to this org please let me know. Plugins can either -retain compatibility with asdf or use rtx specific functionality—that's up to you. asdf-compatible plugins should -use "asdf-" as the prefix and "rtx-" prefixed-plugins denote rtx-only compatibility. +If you're a plugin maintainer that would like to move your repo to this org [please let me know](https://github.com/orgs/rtx-plugins/discussions). +Plugins can either retain compatibility with asdf or use rtx specific functionality—that's up to you. asdf-compatible plugins should use "asdf-" as the prefix and "rtx-" prefixed-plugins denote rtx-only compatibility. ## Supported Versions From 97b00b0489e278fa382b6dd245e729090ca01b88 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 10:45:35 -0600 Subject: [PATCH 1407/1891] Update SECURITY.md --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 7b6e7d955..a353ae5d3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -46,7 +46,7 @@ Over time we should be able to move more plugins into being fully maintained by `RTX_PARANOID=1` env var that, when set, will make changes to make rtx behave as securely as possible (e.g.: only using core/rtx-plugins plugins, only allowing plugins that use GPG verification of assets). -## rtx-plugins GitHub org +## [rtx-plugins](https://github.com/rtx-plugins) GitHub org This is similar to https://github.com/asdf-community but with the advantage of being more secure by keeping the contributor count minimal—currently only @jdx will be allowed to merge PRs. For this reason, plugins using this From fb06a7757a7d9670f7978dade7f091e314a5c163 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 15:37:17 -0600 Subject: [PATCH 1408/1891] readme lint --- README.md | 3 ++- SECURITY.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f6c7b838..c3eb77fe8 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ v20.0.0 - [Environment variables](#environment-variables) - [Aliases](#aliases) - [Plugins](#plugins) + - [Plugin Authors](#plugin-authors) - [Plugin Options](#plugin-options) - [Versioning](#versioning) - [Directories](#directories) @@ -1045,7 +1046,7 @@ more about how they work. ### Plugin Authors -https://github.com/rtx-plugins is a GitHub organization for community-developed plugins. + is a GitHub organization for community-developed plugins. See [SECURITY.md](./SECURITY.md) for more details on how plugins here are treated differently. If you'd like your plugin to be hosted here please let me know (GH discussion or discord is fine) diff --git a/SECURITY.md b/SECURITY.md index a353ae5d3..55d6fe98d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -48,7 +48,7 @@ Over time we should be able to move more plugins into being fully maintained by ## [rtx-plugins](https://github.com/rtx-plugins) GitHub org -This is similar to https://github.com/asdf-community but with the advantage of being more secure by keeping the +This is similar to but with the advantage of being more secure by keeping the contributor count minimal—currently only @jdx will be allowed to merge PRs. For this reason, plugins using this organization will not receive a confirmation warning dialog when installed with rtx as they've been vetted by a trusted source. From ec091c7fa6e77fb39b1635ee08bbb8e4e5b1dcac Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 15:37:33 -0600 Subject: [PATCH 1409/1891] exec: added --cd alias --- src/cli/exec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index e210e0f9f..9f8b0ddf2 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -3,8 +3,8 @@ use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use clap::ValueHint; -use color_eyre::eyre::{eyre, Result}; use duct::IntoExecutablePath; +use eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; #[cfg(test)] @@ -40,7 +40,7 @@ pub struct Exec { pub c: Option, /// Change to this directory before executing the command - #[clap(short = 'C', value_hint = ValueHint::DirPath, long)] + #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)] pub cd: Option, /// Number of jobs to run in parallel @@ -89,7 +89,7 @@ impl Exec { env::set_current_dir(cd)?; } let err = exec::Command::new(program.clone()).args(&args).exec(); - Err(eyre!("{:?} {}", program.to_string_lossy(), err.to_string())) + bail!("{:?} {err}", program.to_string_lossy()) } #[cfg(test)] From 0514fe14fb69aa63653b00642b0661384990f78f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 19:04:18 -0600 Subject: [PATCH 1410/1891] perf: skip loading config object before launching command (#1251) Fixes #412 --- completions/rtx.bash | 4 +- src/cli/asdf.rs | 24 +++-- src/cli/bin_paths.rs | 5 +- src/cli/config/generate.rs | 3 +- src/cli/config/ls.rs | 2 +- src/cli/current.rs | 5 +- src/cli/deactivate.rs | 3 +- src/cli/direnv/mod.rs | 5 +- src/cli/doctor.rs | 70 +++++++------ src/cli/env.rs | 11 +- src/cli/env_vars.rs | 3 +- src/cli/exec.rs | 9 +- src/cli/external.rs | 10 +- src/cli/global.rs | 5 +- src/cli/hook_env.rs | 14 ++- src/cli/install.rs | 7 +- src/cli/latest.rs | 3 +- src/cli/link.rs | 3 +- src/cli/local.rs | 5 +- src/cli/ls.rs | 7 +- src/cli/ls_remote.rs | 13 +-- src/cli/mod.rs | 189 +++++++++++++---------------------- src/cli/outdated.rs | 5 +- src/cli/plugins/mod.rs | 5 +- src/cli/prune.rs | 9 +- src/cli/render_completion.rs | 3 +- src/cli/render_help.rs | 2 - src/cli/render_mangen.rs | 2 - src/cli/reshim.rs | 7 +- src/cli/self_update.rs | 8 +- src/cli/settings/get.rs | 3 +- src/cli/settings/ls.rs | 3 +- src/cli/uninstall.rs | 13 +-- src/cli/upgrade.rs | 7 +- src/cli/use.rs | 9 +- src/cli/where.rs | 5 +- src/config/mod.rs | 4 +- src/config/settings.rs | 26 +++++ src/env.rs | 1 + src/logger.rs | 19 ++-- src/main.rs | 30 ++---- src/shims.rs | 18 ++-- src/shorthands.rs | 2 +- src/test.rs | 5 +- 44 files changed, 288 insertions(+), 298 deletions(-) diff --git a/completions/rtx.bash b/completions/rtx.bash index 2fcf4949b..ec9b49839 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -628,7 +628,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1432,7 +1432,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen self-update help" + opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 5548dae08..1a90d7902 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -1,7 +1,9 @@ +use crate::cli::args::tool::ToolArg; use clap::ValueHint::CommandWithArguments; use eyre::Result; use itertools::Itertools; +use crate::cli::ls_remote::LsRemote; use crate::cli::Cli; use crate::config::Config; @@ -17,32 +19,34 @@ pub struct Asdf { } impl Asdf { - pub fn run(mut self, config: &Config) -> Result<()> { + pub fn run(mut self) -> Result<()> { + let config = Config::try_get()?; let mut args = vec![String::from("rtx")]; args.append(&mut self.args); match args.get(1).map(|s| s.as_str()) { - Some("reshim") => Cli::new().run(&args), - Some("list") => list_versions(config, &args), + Some("reshim") => Cli::run(&args), + Some("list") => list_versions(&config, &args), Some("install") => { if args.len() == 4 { let version = args.pop().unwrap(); args[2] = format!("{}@{}", args[2], version); } - Cli::new().run(&args) + Cli::run(&args) } - _ => Cli::new().run(&args), + _ => Cli::run(&args), } } } -fn list_versions(config: &Config, args: &Vec) -> Result<()> { +fn list_versions(config: &Config, args: &[String]) -> Result<()> { if args[2] == "all" { - let mut new_args: Vec = vec!["rtx".into(), "ls-remote".into()]; - if args.len() >= 3 { - new_args.push(args[3].clone()); + return LsRemote { + prefix: None, + all: false, + plugin: args.get(3).map(|s| ToolArg::parse(s)), } - return Cli::new().run(&new_args); + .run(); } let ts = ToolsetBuilder::new().build(config)?; let mut versions = ts.list_installed_versions(config)?; diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 25fd5091d..e8a38d602 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -10,8 +10,9 @@ use crate::toolset::ToolsetBuilder; pub struct BinPaths {} impl BinPaths { - pub fn run(self, config: &Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let ts = ToolsetBuilder::new().build(&config)?; ts.warn_if_versions_missing(); for p in ts.list_paths() { rtxprintln!("{}", p.display()); diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index a94e3e9b1..9fdcd55d9 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use crate::config::Settings; +use crate::config::{Config, Settings}; use crate::file; use crate::file::display_path; use clap::ValueHint; @@ -17,6 +17,7 @@ pub struct ConfigGenerate { impl ConfigGenerate { pub fn run(self) -> Result<()> { + let _ = Config::try_get()?; let settings = Settings::try_get()?; settings.ensure_experimental()?; let doc = r#" diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index f20c2c579..fdadaa3a8 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -22,9 +22,9 @@ pub struct ConfigLs { impl ConfigLs { pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let settings = Settings::try_get()?; settings.ensure_experimental()?; - let config = Config::try_get()?; let rows = config .config_files .values() diff --git a/src/cli/current.rs b/src/cli/current.rs index 10c0635c8..65a2b1978 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -20,8 +20,9 @@ pub struct Current { } impl Current { - pub fn run(self, config: &Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let ts = ToolsetBuilder::new().build(&config)?; match &self.plugin { Some(plugin_name) => { let plugin_name = unalias_plugin(plugin_name); diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 2be6dc635..478d4d2b1 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -14,7 +14,8 @@ use crate::shell::get_shell; pub struct Deactivate {} impl Deactivate { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; if !config.is_activated() { err_inactive()?; } diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index 8e3667297..9ab2eaf4e 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -39,10 +39,11 @@ impl Commands { } impl Direnv { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let cmd = self .command .unwrap_or(Commands::Activate(activate::DirenvActivate {})); - cmd.run(config) + cmd.run(&config) } } diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 64e786b41..b54fa5f3d 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -22,29 +22,53 @@ use crate::{duration, env}; pub struct Doctor {} impl Doctor { - pub fn run(self, config: &Config) -> Result<()> { - let settings = Settings::try_get()?; - let ts = ToolsetBuilder::new().build(config)?; + pub fn run(self) -> Result<()> { + let mut checks = Vec::new(); + rtxprintln!("{}", rtx_version()); rtxprintln!("{}", build_info()); rtxprintln!("{}", shell()); rtxprintln!("{}", rtx_data_dir()); rtxprintln!("{}", rtx_env_vars()); - rtxprintln!( - "{}\n{}\n", - style("settings:").bold(), - indent(settings.to_string()) - ); - rtxprintln!("{}", render_config_files(config)); - rtxprintln!("{}", render_plugins(config)); - rtxprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())); - - let mut checks = Vec::new(); - for plugin in config.list_plugins() { - if !plugin.is_installed() { - checks.push(format!("plugin {} is not installed", &plugin.name())); - continue; + match Settings::try_get() { + Ok(settings) => { + rtxprintln!( + "{}\n{}\n", + style("settings:").bold(), + indent(settings.to_string()) + ); + } + Err(err) => warn!("failed to load settings: {}", err), + } + match Config::try_get() { + Ok(config) => { + rtxprintln!("{}", render_config_files(&config)); + rtxprintln!("{}", render_plugins(&config)); + for plugin in config.list_plugins() { + if !plugin.is_installed() { + checks.push(format!("plugin {} is not installed", &plugin.name())); + continue; + } + } + if !config.is_activated() && !shims_on_path() { + let cmd = style("rtx help activate").yellow().for_stderr(); + let url = style("https://rtx.jdx.dev").underlined().for_stderr(); + let shims = style(dirs::SHIMS.display()).cyan().for_stderr(); + checks.push(formatdoc!( + r#"rtx is not activated, run {cmd} or + read documentation at {url} for activation instructions. + Alternatively, add the shims directory {shims} to PATH. + Using the shims directory is preferred for non-interactive setups."# + )); + } + match ToolsetBuilder::new().build(&config) { + Ok(ts) => { + rtxprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())) + } + Err(err) => warn!("failed to load toolset: {}", err), + } } + Err(err) => warn!("failed to load config: {}", err), } if let Some(latest) = cli::version::check_for_new_version(duration::HOURLY) { @@ -55,18 +79,6 @@ impl Doctor { )); } - if !config.is_activated() && !shims_on_path() { - let cmd = style("rtx help activate").yellow().for_stderr(); - let url = style("https://rtx.jdx.dev").underlined().for_stderr(); - let shims = style(dirs::SHIMS.display()).cyan().for_stderr(); - checks.push(formatdoc!( - r#"rtx is not activated, run {cmd} or - read documentation at {url} for activation instructions. - Alternatively, add the shims directory {shims} to PATH. - Using the shims directory is preferred for non-interactive setups."# - )); - } - if checks.is_empty() { rtxprintln!("No problems found"); } else { diff --git a/src/cli/env.rs b/src/cli/env.rs index 0415e0d3d..4637341ad 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -37,21 +37,22 @@ pub struct Env { } impl Env { - pub fn run(self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let opts = InstallOptions { force: false, jobs: self.jobs, raw: self.raw, latest_versions: false, }; - ts.install_arg_versions(config, &opts)?; + ts.install_arg_versions(&config, &opts)?; ts.warn_if_versions_missing(); if self.json { - self.output_json(config, ts) + self.output_json(&config, ts) } else { - self.output_shell(config, ts) + self.output_shell(&config, ts) } } diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index d70f655b1..c0d8e6bbd 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -35,7 +35,8 @@ pub struct EnvVars { } impl EnvVars { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; if self.remove.is_none() && self.env_vars.is_none() { for (key, value) in &config.env { let source = config.env_sources.get(key).unwrap(); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 9f8b0ddf2..636c80dc2 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -55,19 +55,20 @@ pub struct Exec { } impl Exec { - pub fn run(self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let opts = InstallOptions { force: false, jobs: self.jobs, raw: self.raw, latest_versions: false, }; - ts.install_arg_versions(config, &opts)?; + ts.install_arg_versions(&config, &opts)?; ts.warn_if_versions_missing(); let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); - let env = ts.env_with_path(config); + let env = ts.env_with_path(&config); self.exec(program, args, env) } diff --git a/src/cli/external.rs b/src/cli/external.rs index 58ef6e65d..411e01bcb 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -18,13 +18,9 @@ pub fn commands(config: &Config) -> Vec { .collect() } -pub fn execute( - config: &Config, - plugin: &str, - args: &ArgMatches, - external_commands: Vec, -) -> Result<()> { - if let Some(mut cmd) = external_commands +pub fn execute(plugin: &str, args: &ArgMatches) -> Result<()> { + let config = Config::try_get()?; + if let Some(mut cmd) = commands(&config) .into_iter() .find(|c| c.get_name() == plugin) { diff --git a/src/cli/global.rs b/src/cli/global.rs index d75a23d3b..6ee2316c5 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -48,9 +48,10 @@ pub struct Global { } impl Global { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; local( - config, + &config, &global_file(), self.tool, self.remove, diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 11e77eea4..46fab34ca 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -35,11 +35,15 @@ pub struct HookEnv { } impl HookEnv { - pub fn run(self, config: &Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + if config.should_exit_early { + return Ok(()); + } + let ts = ToolsetBuilder::new().build(&config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); rtxprint!("{}", hook_env::clear_old_env(&*shell)); - let mut env = ts.env(config); + let mut env = ts.env(&config); let env_path = env.remove("PATH"); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); @@ -54,12 +58,12 @@ impl HookEnv { let settings = Settings::try_get()?; patches.extend(self.build_path_operations(&settings, &paths, &__RTX_DIFF.path)?); patches.push(self.build_diff_operation(&diff)?); - patches.push(self.build_watch_operation(config)?); + patches.push(self.build_watch_operation(&config)?); let output = hook_env::build_env_commands(&*shell, &patches); rtxprint!("{output}"); if self.status { - self.display_status(config, &ts); + self.display_status(&config, &ts); } ts.warn_if_versions_missing(); diff --git a/src/cli/install.rs b/src/cli/install.rs index 761144934..a3d6a8ddc 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -44,10 +44,11 @@ pub struct Install { } impl Install { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; match &self.tool { - Some(runtime) => self.install_runtimes(config, runtime)?, - None => self.install_missing_runtimes(config)?, + Some(runtime) => self.install_runtimes(&config, runtime)?, + None => self.install_missing_runtimes(&config)?, } Ok(()) diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 8a66e51ac..838ffea4e 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -26,7 +26,8 @@ pub struct Latest { } impl Latest { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let mut prefix = match self.tool.tvr { None => self.asdf_version, Some(ToolVersionRequest::Version(_, version)) => Some(version), diff --git a/src/cli/link.rs b/src/cli/link.rs index b3b849178..8fcfeadf8 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -33,7 +33,8 @@ pub struct Link { } impl Link { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let version = match self.tool.tvr { Some(ref tvr) => tvr.version(), None => bail!("must provide a version for {}", self.tool.style()), diff --git a/src/cli/local.rs b/src/cli/local.rs index 431a5ae18..3c3f5d4a9 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -54,14 +54,15 @@ pub struct Local { } impl Local { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let path = if self.parent { get_parent_path()? } else { get_path() }; local( - config, + &config, &path, self.tool, self.remove, diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 8cd412218..756b8fe95 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -64,14 +64,15 @@ pub struct Ls { } impl Ls { - pub fn run(mut self, config: &Config) -> Result<()> { + pub fn run(mut self) -> Result<()> { + let config = Config::try_get()?; self.plugin = self .plugin .or_else(|| self.plugin_flag.clone().map(|p| vec![p])) .map(|p| p.into_iter().map(|p| unalias_plugin(&p).into()).collect()); - self.verify_plugin(config)?; + self.verify_plugin(&config)?; - let mut runtimes = self.get_runtime_list(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 diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 1fced6fff..e558666d8 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -21,24 +21,25 @@ use crate::ui::multi_progress_report::MultiProgressReport; pub struct LsRemote { /// Plugin to get versions for #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, required_unless_present = "all")] - plugin: Option, + pub(crate) plugin: Option, /// Show all installed plugins and versions #[clap(long, verbatim_doc_comment, conflicts_with_all = ["plugin", "prefix"])] - all: bool, + pub(crate) all: bool, /// The version prefix to use when querying the latest version /// same as the first argument after the "@" #[clap(verbatim_doc_comment)] - prefix: Option, + pub(crate) prefix: Option, } impl LsRemote { - pub fn run(self, config: &Config) -> Result<()> { - if let Some(plugin) = self.get_plugin(config)? { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + if let Some(plugin) = self.get_plugin(&config)? { self.run_single(plugin) } else { - self.run_all(config) + self.run_all(&config) } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index bdbd6328b..e1ac04e11 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,10 +1,8 @@ use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; -use confique::Partial; -use once_cell::sync::Lazy; -use crate::cli::self_update::SelfUpdate; -use crate::config::{Config, SettingsPartial}; +use crate::config::{Config, Settings}; +use crate::{logger, shims}; mod activate; mod alias; @@ -53,10 +51,7 @@ pub mod version; mod r#where; mod r#which; -pub struct Cli { - command: clap::Command, - external_commands: Vec, -} +pub struct Cli {} #[derive(Debug, Subcommand)] pub enum Commands { @@ -87,6 +82,7 @@ pub enum Commands { Plugins(plugins::Plugins), Prune(prune::Prune), Reshim(reshim::Reshim), + SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Shell(shell::Shell), Sync(sync::Sync), @@ -109,44 +105,45 @@ pub enum Commands { } impl Commands { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { match self { Self::Activate(cmd) => cmd.run(), Self::Alias(cmd) => cmd.run(), - Self::Asdf(cmd) => cmd.run(config), - Self::BinPaths(cmd) => cmd.run(config), + Self::Asdf(cmd) => cmd.run(), + Self::BinPaths(cmd) => cmd.run(), Self::Cache(cmd) => cmd.run(), Self::Completion(cmd) => cmd.run(), Self::Config(cmd) => cmd.run(), - Self::Current(cmd) => cmd.run(config), - Self::Deactivate(cmd) => cmd.run(config), - Self::Direnv(cmd) => cmd.run(config), - Self::Doctor(cmd) => cmd.run(config), - Self::Env(cmd) => cmd.run(config), - Self::EnvVars(cmd) => cmd.run(config), - Self::Exec(cmd) => cmd.run(config), - Self::Global(cmd) => cmd.run(config), - Self::HookEnv(cmd) => cmd.run(config), + Self::Current(cmd) => cmd.run(), + Self::Deactivate(cmd) => cmd.run(), + Self::Direnv(cmd) => cmd.run(), + Self::Doctor(cmd) => cmd.run(), + Self::Env(cmd) => cmd.run(), + Self::EnvVars(cmd) => cmd.run(), + Self::Exec(cmd) => cmd.run(), + Self::Global(cmd) => cmd.run(), + Self::HookEnv(cmd) => cmd.run(), Self::Implode(cmd) => cmd.run(), - Self::Install(cmd) => cmd.run(config), - Self::Latest(cmd) => cmd.run(config), - Self::Link(cmd) => cmd.run(config), - Self::Local(cmd) => cmd.run(config), - Self::Ls(cmd) => cmd.run(config), - Self::LsRemote(cmd) => cmd.run(config), - Self::Outdated(cmd) => cmd.run(config), - Self::Plugins(cmd) => cmd.run(config), - Self::Prune(cmd) => cmd.run(config), - Self::Reshim(cmd) => cmd.run(config), + Self::Install(cmd) => cmd.run(), + Self::Latest(cmd) => cmd.run(), + Self::Link(cmd) => cmd.run(), + Self::Local(cmd) => cmd.run(), + Self::Ls(cmd) => cmd.run(), + Self::LsRemote(cmd) => cmd.run(), + Self::Outdated(cmd) => cmd.run(), + Self::Plugins(cmd) => cmd.run(), + Self::Prune(cmd) => cmd.run(), + Self::Reshim(cmd) => cmd.run(), + Self::SelfUpdate(cmd) => cmd.run(), Self::Settings(cmd) => cmd.run(), Self::Shell(cmd) => cmd.run(), Self::Sync(cmd) => cmd.run(), Self::Trust(cmd) => cmd.run(), - Self::Uninstall(cmd) => cmd.run(config), - Self::Upgrade(cmd) => cmd.run(config), - Self::Use(cmd) => cmd.run(config), + Self::Uninstall(cmd) => cmd.run(), + Self::Upgrade(cmd) => cmd.run(), + Self::Use(cmd) => cmd.run(), Self::Version(cmd) => cmd.run(), - Self::Where(cmd) => cmd.run(config), + Self::Where(cmd) => cmd.run(), Self::Which(cmd) => cmd.run(), #[cfg(feature = "clap_complete")] @@ -162,97 +159,49 @@ impl Commands { } impl Cli { - pub fn new() -> Self { - Self { - command: Self::command(), - external_commands: vec![], - } - } - - pub fn new_with_external_commands(config: &Config) -> Self { - let mut external_commands = external::commands(config); - if SelfUpdate::is_available() { - external_commands.push(SelfUpdate::command()); - } - Self { - command: Self::command().subcommands(external_commands.clone()), - external_commands, - } - } - pub fn command() -> clap::Command { - static COMMAND: Lazy = Lazy::new(|| { - Commands::augment_subcommands( - clap::Command::new("rtx") - .version(version::VERSION.to_string()) - .about(env!("CARGO_PKG_DESCRIPTION")) - .author("Jeff Dickey <@jdx>") - .long_about(LONG_ABOUT) - .arg_required_else_help(true) - .subcommand_required(true) - .after_long_help(AFTER_LONG_HELP) - .arg(args::log_level::Debug::arg()) - .arg(args::log_level::LogLevel::arg()) - .arg(args::log_level::Trace::arg()) - .arg(args::quiet::Quiet::arg()) - .arg(args::verbose::Verbose::arg()) - .arg(args::yes::Yes::arg()), - ) - }); - COMMAND.clone() + Commands::augment_subcommands( + clap::Command::new("rtx") + .version(version::VERSION.to_string()) + .about(env!("CARGO_PKG_DESCRIPTION")) + .author("Jeff Dickey <@jdx>") + .long_about(LONG_ABOUT) + .arg_required_else_help(true) + .subcommand_required(true) + .after_long_help(AFTER_LONG_HELP) + .arg(args::log_level::Debug::arg()) + .arg(args::log_level::LogLevel::arg()) + .arg(args::log_level::Trace::arg()) + .arg(args::quiet::Quiet::arg()) + .arg(args::verbose::Verbose::arg()) + .arg(args::yes::Yes::arg()), + ) } - pub fn run(self, args: &Vec) -> Result<()> { - debug!("ARGS: {}", &args.join(" ")); - let config = Config::try_get()?; - if args[1..] == ["-v"] { - // normally this would be considered --verbose - return version::Version {}.run(); + pub fn run(args: &Vec) -> Result<()> { + *crate::env::ARGS.write().unwrap() = crate::env::args().collect(); + shims::handle_shim()?; + version::print_version_if_requested(); + + let matches = Self::command() + .try_get_matches_from(args) + .unwrap_or_else(|_| { + Self::command() + .subcommands(external::commands(Config::get().as_ref())) + .get_matches_from(args) + }); + Settings::add_cli_matches(&matches); + if let Ok(settings) = Settings::try_get() { + logger::init(&settings); } - let matches = self.command.get_matches_from(args); - if let Some((command, sub_m)) = matches.subcommand() { - if command == "self-update" { - return SelfUpdate::from_arg_matches(sub_m)?.run(); - } - external::execute(&config, command, sub_m, self.external_commands)?; - } - let cmd = Commands::from_arg_matches(&matches)?; - cmd.run(&config) - } - - pub fn settings(self, args: &Vec) -> SettingsPartial { - let mut s = SettingsPartial::empty(); - if let Ok(m) = self.command.try_get_matches_from(args) { - if let Some(true) = m.get_one::("yes") { - s.yes = Some(true); - } - if let Some(true) = m.get_one::("quiet") { - s.quiet = Some(true); - } - if let Some(true) = m.get_one::("trace") { - s.log_level = Some("trace".to_string()); - } - if let Some(true) = m.get_one::("debug") { - s.log_level = Some("debug".to_string()); - } - if let Some(log_level) = m.get_one::("log-level") { - s.log_level = Some(log_level.to_string()); - } - if *m.get_one::("verbose").unwrap() > 0 { - s.verbose = Some(true); - } - if *m.get_one::("verbose").unwrap() > 1 { - s.log_level = Some("trace".to_string()); - } + debug!("ARGS: {}", &args.join(" ")); + match Commands::from_arg_matches(&matches) { + Ok(cmd) => cmd.run(), + Err(err) => matches + .subcommand() + .ok_or(err) + .map(|(command, sub_m)| external::execute(command, sub_m))?, } - - s - } -} - -impl Default for Cli { - fn default() -> Self { - Self::new() } } diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 6e004e8be..31f7766b0 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -21,8 +21,9 @@ pub struct Outdated { } impl Outdated { - pub fn run(self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let tool_set = self .tool .iter() diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index fde8db3e6..457c77f32 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -69,7 +69,8 @@ impl Commands { } impl Plugins { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let cmd = self.command.unwrap_or(Commands::Ls(ls::PluginsLs { all: self.all, core: self.core, @@ -78,6 +79,6 @@ impl Plugins { user: self.user, })); - cmd.run(config) + cmd.run(&config) } } diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 3a67b8ba4..a6e0d7e2a 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -30,10 +30,11 @@ pub struct Prune { } impl Prune { - pub fn run(self, config: &Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let ts = ToolsetBuilder::new().build(&config)?; let mut to_delete = ts - .list_installed_versions(config)? + .list_installed_versions(&config)? .into_iter() .map(|(p, tv)| (tv.to_string(), (p, tv))) .collect::, ToolVersion)>>(); @@ -44,7 +45,7 @@ impl Prune { for cf in config.get_tracked_config_files()?.values() { let mut ts = cf.to_toolset().clone(); - ts.resolve(config); + ts.resolve(&config); for (_, tv) in ts.list_current_versions() { to_delete.remove(&tv.to_string()); } diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 37eb176d3..9e9be5b9b 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -4,7 +4,6 @@ use std::io::Cursor; use clap_complete::generate; use eyre::Result; -use crate::cli::self_update::SelfUpdate; use crate::shell::completions; /// Generate shell completions @@ -24,7 +23,7 @@ impl RenderCompletion { pub fn run(self) -> Result<()> { let shell = self.shell.or(self.shell_type).unwrap(); - let mut cmd = crate::cli::Cli::command().subcommand(SelfUpdate::command()); + let mut cmd = crate::cli::Cli::command(); let script = match shell { clap_complete::Shell::Zsh => completions::zsh_complete(&cmd)?, diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index f406813f1..60dda6b7f 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -3,7 +3,6 @@ use console::strip_ansi_codes; use eyre::Result; use itertools::Itertools; -use crate::cli::self_update::SelfUpdate; use crate::cli::Cli; use crate::file; @@ -31,7 +30,6 @@ impl RenderHelp { fn render_commands() -> String { let mut cli = Cli::command() - .subcommand(SelfUpdate::command()) .term_width(80) .max_term_width(80) .disable_help_subcommand(true) diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 3434e31f7..547df68a8 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -4,7 +4,6 @@ use std::path::{Path, PathBuf}; use eyre::Result; -use crate::cli::self_update::SelfUpdate; use crate::cli::{version, Cli}; /// internal command to generate markdown from help @@ -15,7 +14,6 @@ pub struct RenderMangen {} impl RenderMangen { pub fn run(self) -> Result<()> { let cli = Cli::command() - .subcommand(SelfUpdate::command()) .version(&*version::RAW_VERSION) .disable_colored_help(true); diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 48a39e1e1..3be229bcc 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -30,10 +30,11 @@ pub struct Reshim { } impl Reshim { - pub fn run(self, config: &Config) -> Result<()> { - let ts = ToolsetBuilder::new().build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let ts = ToolsetBuilder::new().build(&config)?; - shims::reshim(config, &ts) + shims::reshim(&config, &ts) } } diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 85e4e32ae..4e63c3e55 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -1,4 +1,3 @@ -use clap::Args; use color_eyre::Result; use console::style; use self_update::backends::github::{ReleaseList, Update}; @@ -34,6 +33,9 @@ pub struct SelfUpdate { impl SelfUpdate { pub fn run(self) -> Result<()> { + if !Self::is_available() && !self.force { + bail!("rtx is installed via a package manager, cannot update"); + } let status = self.do_update()?; if status.updated() { @@ -105,8 +107,4 @@ impl SelfUpdate { .map(|p| p.join("lib").join(".disable-self-update").exists()) .unwrap_or_default() } - - pub fn command() -> clap::Command { - Self::augment_args(clap::Command::new("self-update")) - } } diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 2bfe5bc32..708b19624 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::{eyre, Result}; use serde_json::Value; use std::collections::BTreeMap; -use crate::config::Settings; +use crate::config::{Config, Settings}; /// Show a current setting /// @@ -19,6 +19,7 @@ pub struct SettingsGet { impl SettingsGet { pub fn run(self) -> Result<()> { + Config::try_get()?; let settings = Settings::try_get()?; let json = settings.to_string(); let doc: BTreeMap = serde_json::from_str(&json)?; diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index d2c0e2e4a..f712c8051 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -2,7 +2,7 @@ use eyre::Result; use serde_json::Value; use std::collections::BTreeMap; -use crate::config::Settings; +use crate::config::{Config, Settings}; /// Show current settings /// @@ -16,6 +16,7 @@ pub struct SettingsLs {} impl SettingsLs { pub fn run(self) -> Result<()> { + Config::try_get()?; let settings = Settings::try_get()?; let json = settings.to_string(); let doc: BTreeMap = serde_json::from_str(&json)?; diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index dde987123..178e1de9f 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -30,11 +30,12 @@ pub struct Uninstall { } impl Uninstall { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; let tool_versions = if self.installed_tool.is_empty() && self.all { - self.get_all_tool_versions(config)? + self.get_all_tool_versions(&config)? } else { - self.get_requested_tool_versions(config)? + self.get_requested_tool_versions(&config)? }; let tool_versions = tool_versions .into_iter() @@ -64,9 +65,9 @@ impl Uninstall { } } - let ts = ToolsetBuilder::new().build(config)?; - shims::reshim(config, &ts).wrap_err("failed to reshim")?; - runtime_symlinks::rebuild(config)?; + let ts = ToolsetBuilder::new().build(&config)?; + shims::reshim(&config, &ts).wrap_err("failed to reshim")?; + runtime_symlinks::rebuild(&config)?; Ok(()) } diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 90aa2bf27..1a2172dfa 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -45,8 +45,9 @@ pub struct Upgrade { } impl Upgrade { - pub fn run(self, config: &Config) -> Result<()> { - let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let mut outdated = ts.list_outdated_versions(); if self.interactive && !outdated.is_empty() { let tvs = self.get_interactive_tool_set(&outdated)?; @@ -62,7 +63,7 @@ impl Upgrade { if outdated.is_empty() { info!("All tools are up to date"); } else { - self.upgrade(config, outdated)?; + self.upgrade(&config, outdated)?; } Ok(()) diff --git a/src/cli/use.rs b/src/cli/use.rs index 35adf6bfc..3852508f8 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -78,8 +78,9 @@ pub struct Use { } impl Use { - pub fn run(self, config: &Config) -> Result<()> { - let mut ts = ToolsetBuilder::new().build(config)?; + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let mut ts = ToolsetBuilder::new().build(&config)?; let mpr = MultiProgressReport::get(); let versions = self .tool @@ -94,7 +95,7 @@ impl Use { }) .collect::>>()?; ts.install_versions( - config, + &config, versions.clone(), &mpr, &InstallOptions { @@ -124,7 +125,7 @@ impl Use { } if self.global { - self.warn_if_hidden(config, cf.get_path()); + self.warn_if_hidden(&config, cf.get_path()); } for plugin_name in &self.remove { cf.remove_plugin(plugin_name); diff --git a/src/cli/where.rs b/src/cli/where.rs index bd4f217ae..e28bb3395 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -28,14 +28,15 @@ pub struct Where { } impl Where { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; 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(config)?; + .build(&config)?; let v = ts .versions .get(&self.tool.plugin) diff --git a/src/config/mod.rs b/src/config/mod.rs index 342bd3046..11cb6cb74 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use once_cell::sync::{Lazy, OnceCell}; use rayon::prelude::*; -pub use settings::{Settings, SettingsPartial}; +pub use settings::Settings; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; @@ -23,7 +23,7 @@ use crate::shorthands::{get_shorthands, Shorthands}; use crate::{dirs, env, file, hook_env}; pub mod config_file; -mod settings; +pub mod settings; mod tracking; type AliasMap = BTreeMap>; diff --git a/src/config/settings.rs b/src/config/settings.rs index 219ba71f4..c8db0d4cb 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -131,6 +131,32 @@ impl Settings { PARTIALS.write().unwrap().push(partial); *SETTINGS.write().unwrap() = None; } + pub fn add_cli_matches(m: &clap::ArgMatches) { + let mut s = SettingsPartial::empty(); + if let Some(true) = m.get_one::("yes") { + s.yes = Some(true); + } + if let Some(true) = m.get_one::("quiet") { + s.quiet = Some(true); + } + if let Some(true) = m.get_one::("trace") { + s.log_level = Some("trace".to_string()); + } + if let Some(true) = m.get_one::("debug") { + s.log_level = Some("debug".to_string()); + } + if let Some(log_level) = m.get_one::("log-level") { + s.log_level = Some(log_level.to_string()); + } + if *m.get_one::("verbose").unwrap() > 0 { + s.verbose = Some(true); + } + if *m.get_one::("verbose").unwrap() > 1 { + s.log_level = Some("trace".to_string()); + } + Self::add_partial(s); + } + pub fn default_builder() -> Builder { let mut b = Self::builder().env(); for partial in PARTIALS.read().unwrap().iter() { diff --git a/src/env.rs b/src/env.rs index fbca29878..cd026c803 100644 --- a/src/env.rs +++ b/src/env.rs @@ -60,6 +60,7 @@ pub static RTX_BIN: Lazy = Lazy::new(|| { }); pub static ARGV0: Lazy = Lazy::new(|| ARGS.read().unwrap()[0].to_string()); pub static RTX_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0)); +pub static RTX_LOG_FILE: Lazy> = Lazy::new(|| var_path("RTX_LOG_FILE")); pub static RTX_LOG_FILE_LEVEL: Lazy> = Lazy::new(log_file_level); pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) diff --git a/src/logger.rs b/src/logger.rs index 60c7f9ca3..eea3e98a0 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,21 +1,22 @@ extern crate simplelog; use std::fs::{create_dir_all, File, OpenOptions}; -use std::path::PathBuf; +use std::path::Path; use crate::config::Settings; use crate::env; use eyre::Result; use simplelog::*; -pub fn init() -> LevelFilter { - let settings = Settings::get(); +pub fn init(settings: &Settings) { + if cfg!(test) { + return; + } let mut loggers: Vec> = vec![]; let level = settings.log_level.parse().unwrap(); loggers.push(init_term_logger(level)); - if let Ok(log) = env::var("RTX_LOG_FILE") { - let log_file = PathBuf::from(log); + if let Some(log_file) = &*env::RTX_LOG_FILE { let file_level = env::RTX_LOG_FILE_LEVEL.unwrap_or(level); if let Some(logger) = init_write_logger(file_level, log_file) { loggers.push(logger) @@ -24,11 +25,9 @@ pub fn init() -> LevelFilter { CombinedLogger::init(loggers).unwrap_or_else(|err| { eprintln!("rtx: could not initialize logger: {err}"); }); - - level } -fn init_log_file(log_file: PathBuf) -> Result { +fn init_log_file(log_file: &Path) -> Result { if let Some(log_dir) = log_file.parent() { create_dir_all(log_dir)?; } @@ -57,7 +56,7 @@ fn init_term_logger(level: LevelFilter) -> Box { ) } -fn init_write_logger(level: LevelFilter, log_path: PathBuf) -> Option> { +fn init_write_logger(level: LevelFilter, log_path: &Path) -> Option> { match init_log_file(log_path) { Ok(log_file) => Some(WriteLogger::new( level, @@ -80,6 +79,6 @@ mod tests { #[test] fn test_init() { - init(); + init(&Settings::get()); } } diff --git a/src/main.rs b/src/main.rs index 2edd34e03..8c6f1df30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,10 +15,10 @@ use std::process::exit; use color_eyre::{Help, Report, SectionExt}; use console::{style, Term}; use eyre::Result; +use itertools::Itertools; use crate::cli::version::VERSION; use crate::cli::Cli; -use crate::config::{Config, Settings}; #[macro_use] mod output; @@ -65,19 +65,15 @@ mod toolset; mod ui; fn main() -> Result<()> { - rayon::spawn(|| { - Cli::new(); // this is slow so we memoize it in the background - }); - *env::ARGS.write().unwrap() = env::args().collect(); + let args = env::args().collect_vec(); + *env::ARGS.write().unwrap() = args.clone(); color_eyre::install()?; - let cli_settings = Cli::new().settings(&env::ARGS.read().unwrap()); - Settings::add_partial(cli_settings); - let log_level = logger::init(); handle_ctrlc(); + migrate::run(); - match run().with_section(|| VERSION.to_string().header("Version:")) { + match Cli::run(&args).with_section(|| VERSION.to_string().header("Version:")) { Ok(()) => Ok(()), - Err(err) if log_level < log::LevelFilter::Debug => { + Err(err) if log::max_level() < log::LevelFilter::Debug => { display_friendly_err(err); exit(1); } @@ -87,20 +83,6 @@ fn main() -> Result<()> { } } -fn run() -> Result<()> { - // show version before loading config in case of error - cli::version::print_version_if_requested(); - migrate::run(); - - let config = Config::try_get()?; - shims::handle_shim(&config)?; - if config.should_exit_early { - return Ok(()); - } - let cli = Cli::new_with_external_commands(&config); - cli.run(&env::ARGS.read().unwrap()) -} - fn handle_ctrlc() { let _ = ctrlc::set_handler(move || { let _ = Term::stderr().show_cursor(); diff --git a/src/shims.rs b/src/shims.rs index 4b32d43ab..710811fdb 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -22,13 +22,14 @@ use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; // executes as if it was a shim if the command is not "rtx", e.g.: "node" -pub fn handle_shim(config: &Config) -> Result<()> { - if *env::RTX_BIN_NAME == "rtx" { +pub fn handle_shim() -> Result<()> { + // TODO: instead, check if bin is in shims dir + if *env::RTX_BIN_NAME == "rtx" || cfg!(test) { return Ok(()); } let args = env::ARGS.read().unwrap(); let mut args: Vec = args.iter().map(OsString::from).collect(); - args[0] = which_shim(config, &env::RTX_BIN_NAME)?.into(); + args[0] = which_shim(&env::RTX_BIN_NAME)?.into(); let exec = Exec { tool: vec![], c: None, @@ -37,14 +38,15 @@ pub fn handle_shim(config: &Config) -> Result<()> { jobs: None, raw: false, }; - exec.run(config)?; + exec.run()?; exit(0); } -fn which_shim(config: &Config, bin_name: &str) -> Result { +fn which_shim(bin_name: &str) -> Result { let shim = dirs::SHIMS.join(bin_name); if shim.exists() { - let ts = ToolsetBuilder::new().build(config)?; + let config = Config::try_get()?; + let ts = ToolsetBuilder::new().build(&config)?; if let Some((p, tv)) = ts.which(bin_name) { if let Some(bin) = p.which(&tv, bin_name)? { return Ok(bin); @@ -62,10 +64,10 @@ fn which_shim(config: &Config, bin_name: &str) -> Result { return Ok(bin); } } - let tvs = ts.list_rtvs_with_bin(config, bin_name)?; + let tvs = ts.list_rtvs_with_bin(&config, bin_name)?; err_no_version_set(ts, bin_name, tvs)?; } - Err(eyre!("{} is not a valid shim", bin_name)) + bail!("{} is not a valid shim", bin_name) } pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { diff --git a/src/shorthands.rs b/src/shorthands.rs index c15609492..bab235b89 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -51,7 +51,7 @@ fn parse_shorthands_file(mut f: PathBuf) -> Result { #[cfg(test)] mod tests { - use crate::config::SettingsPartial; + use crate::config::settings::SettingsPartial; use confique::Partial; use pretty_assertions::assert_str_eq; diff --git a/src/test.rs b/src/test.rs index c0e4a2c3c..de8d2d485 100644 --- a/src/test.rs +++ b/src/test.rs @@ -88,10 +88,7 @@ pub fn cli_run(args: &Vec) -> eyre::Result<(String, String)> { *env::ARGS.write().unwrap() = args.clone(); STDOUT.lock().unwrap().clear(); STDERR.lock().unwrap().clear(); - let config = Config::try_get()?; - Cli::new_with_external_commands(&config) - .run(args) - .with_section(|| format!("{}", args.join(" ").header("Command:")))?; + Cli::run(args).with_section(|| format!("{}", args.join(" ").header("Command:")))?; let stdout = clean_output(STDOUT.lock().unwrap().join("\n")); let stderr = clean_output(STDERR.lock().unwrap().join("\n")); From ac63f88956f4e92ea4ba411592952901699d811e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 19:40:17 -0600 Subject: [PATCH 1411/1891] shims: do not assume something is a shim (#1252) Fixes #921 --- src/cli/mod.rs | 4 ++-- src/cli/version.rs | 5 ++--- src/main.rs | 11 ++++------ src/output.rs | 12 +++++------ src/shims.rs | 52 ++++++++++++++++++++++------------------------ 5 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e1ac04e11..0659ec2c3 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -179,9 +179,9 @@ impl Cli { } pub fn run(args: &Vec) -> Result<()> { - *crate::env::ARGS.write().unwrap() = crate::env::args().collect(); + *crate::env::ARGS.write().unwrap() = args.clone(); shims::handle_shim()?; - version::print_version_if_requested(); + version::print_version_if_requested(args); let matches = Self::command() .try_get_matches_from(args) diff --git a/src/cli/version.rs b/src/cli/version.rs index fe60b57f3..4515c7c14 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -50,9 +50,8 @@ impl Version { } } -pub fn print_version_if_requested() { - let args = env::ARGS.read().unwrap(); - if args.len() == 2 && (args[0] == "rtx" || args[0].ends_with("/rtx")) { +pub fn print_version_if_requested(args: &[String]) { + if args.len() == 2 && *env::RTX_BIN_NAME == "rtx" { let cmd = &args[1].to_lowercase(); if cmd == "version" || cmd == "-v" || cmd == "--version" { show_version(); diff --git a/src/main.rs b/src/main.rs index 8c6f1df30..3e92cdf7f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,7 +66,6 @@ mod ui; fn main() -> Result<()> { let args = env::args().collect_vec(); - *env::ARGS.write().unwrap() = args.clone(); color_eyre::install()?; handle_ctrlc(); migrate::run(); @@ -92,14 +91,12 @@ fn handle_ctrlc() { } fn display_friendly_err(err: Report) { - let dim = |s| style(s).dim().for_stderr(); - let dim_red = |s| style(s).dim().red().for_stderr(); for err in err.chain() { - eprintln!("{} {}", dim_red("rtx"), err); + error!("{err}"); } - eprintln!( - "{} {}", - dim_red("rtx"), + let dim = |s| style(s).dim().for_stderr(); + error!( + "{}", dim("Run with --verbose or RTX_VERBOSE=1 for more information") ); } diff --git a/src/output.rs b/src/output.rs index e6749bf87..e589797cc 100644 --- a/src/output.rs +++ b/src/output.rs @@ -44,8 +44,8 @@ macro_rules! rtxprint { macro_rules! info { ($($arg:tt)*) => {{ let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); - let rtx = console::style("rtx ").dim().for_stderr(); - stderr.push(format!("{}{}", rtx, format!($($arg)*))); + let rtx = console::style("rtx").dim().for_stderr(); + stderr.push(format!("{} {}", rtx, format!($($arg)*))); }}; } @@ -55,8 +55,8 @@ macro_rules! warn { ($($arg:tt)*) => { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); - let rtx = console::style("rtx ").yellow().for_stderr(); - stderr.push(format!("{}{}", rtx, format!($($arg)*))); + let rtx = console::style("rtx").yellow().for_stderr(); + stderr.push(format!("{} {}", rtx, format!($($arg)*))); }) } } @@ -67,8 +67,8 @@ macro_rules! error { ($($arg:tt)*) => { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); - let rtx = console::style("rtx ").red().for_stderr(); - stderr.push(format!("{}{}", rtx, format!($($arg)*))); + let rtx = console::style("rtx").red().for_stderr(); + stderr.push(format!("{} {}", rtx, format!($($arg)*))); }) } } diff --git a/src/shims.rs b/src/shims.rs index 710811fdb..dbadc1f92 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -11,11 +11,11 @@ use itertools::Itertools; use rayon::prelude::*; use crate::cli::exec::Exec; -use crate::config::Config; -use crate::env; +use crate::config::{Config, Settings}; use crate::fake_asdf; use crate::file::{create_dir_all, display_path, remove_all}; use crate::lock_file::LockFile; +use crate::{env, logger}; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; @@ -24,9 +24,11 @@ use crate::{dirs, file}; // executes as if it was a shim if the command is not "rtx", e.g.: "node" pub fn handle_shim() -> Result<()> { // TODO: instead, check if bin is in shims dir - if *env::RTX_BIN_NAME == "rtx" || cfg!(test) { + let bin_name = *env::RTX_BIN_NAME; + if bin_name == "rtx" || !dirs::SHIMS.join(bin_name).exists() || cfg!(test) { return Ok(()); } + logger::init(&Settings::get()); let args = env::ARGS.read().unwrap(); let mut args: Vec = args.iter().map(OsString::from).collect(); args[0] = which_shim(&env::RTX_BIN_NAME)?.into(); @@ -43,31 +45,27 @@ pub fn handle_shim() -> Result<()> { } fn which_shim(bin_name: &str) -> Result { - let shim = dirs::SHIMS.join(bin_name); - if shim.exists() { - let config = Config::try_get()?; - let ts = ToolsetBuilder::new().build(&config)?; - if let Some((p, tv)) = ts.which(bin_name) { - if let Some(bin) = p.which(&tv, bin_name)? { - return Ok(bin); - } + let config = Config::try_get()?; + let ts = ToolsetBuilder::new().build(&config)?; + if let Some((p, tv)) = ts.which(bin_name) { + if let Some(bin) = p.which(&tv, bin_name)? { + return Ok(bin); } - // fallback for "system" - for path in &*env::PATH { - if fs::canonicalize(path).unwrap_or_default() - == fs::canonicalize(&*dirs::SHIMS).unwrap_or_default() - { - continue; - } - let bin = path.join(bin_name); - if bin.exists() { - return Ok(bin); - } + } + // fallback for "system" + for path in &*env::PATH { + if fs::canonicalize(path).unwrap_or_default() + == fs::canonicalize(&*dirs::SHIMS).unwrap_or_default() + { + continue; + } + let bin = path.join(bin_name); + if bin.exists() { + return Ok(bin); } - let tvs = ts.list_rtvs_with_bin(&config, bin_name)?; - err_no_version_set(ts, bin_name, tvs)?; } - bail!("{} is not a valid shim", bin_name) + let tvs = ts.list_rtvs_with_bin(&config, bin_name)?; + err_no_version_set(ts, bin_name, tvs) } pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { @@ -191,9 +189,9 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { Ok(()) } -fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Result<()> { +fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Result { if tvs.is_empty() { - return Ok(()); + bail!("{} is not a valid shim", bin_name); } let missing_plugins = tvs.iter().map(|tv| &tv.plugin_name).collect::>(); let mut missing_tools = ts From 5063ef0432468af68e0985bd8d06853429d056dc Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 19:52:13 -0600 Subject: [PATCH 1412/1891] hook-env: move exit-early logic into function (#1253) This is no longer needed in the config object --- src/cli/hook_env.rs | 18 +++++++++--------- src/config/mod.rs | 35 ++++++----------------------------- 2 files changed, 15 insertions(+), 38 deletions(-) diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 46fab34ca..d5fe3f287 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -37,7 +37,12 @@ pub struct HookEnv { impl HookEnv { pub fn run(self) -> Result<()> { let config = Config::try_get()?; - if config.should_exit_early { + let watch_files: Vec<_> = config + .config_files + .values() + .flat_map(|p| p.watch_files()) + .collect(); + if hook_env::should_exit_early(&watch_files) { return Ok(()); } let ts = ToolsetBuilder::new().build(&config)?; @@ -58,7 +63,7 @@ impl HookEnv { let settings = Settings::try_get()?; patches.extend(self.build_path_operations(&settings, &paths, &__RTX_DIFF.path)?); patches.push(self.build_diff_operation(&diff)?); - patches.push(self.build_watch_operation(&config)?); + patches.push(self.build_watch_operation(&watch_files)?); let output = hook_env::build_env_commands(&*shell, &patches); rtxprint!("{output}"); @@ -158,13 +163,8 @@ impl HookEnv { )) } - fn build_watch_operation(&self, config: &Config) -> Result { - let watch_files: Vec<_> = config - .config_files - .values() - .flat_map(|p| p.watch_files()) - .collect(); - let watches = hook_env::build_watches(&watch_files)?; + fn build_watch_operation(&self, watch_files: &[PathBuf]) -> Result { + let watches = hook_env::build_watches(watch_files)?; Ok(EnvDiffOperation::Add( "__RTX_WATCH".into(), hook_env::serialize_watches(&watches)?, diff --git a/src/config/mod.rs b/src/config/mod.rs index 11cb6cb74..06296d02f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -20,7 +20,7 @@ use crate::file::display_path; use crate::plugins::core::{PluginMap, CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; -use crate::{dirs, env, file, hook_env}; +use crate::{dirs, env, file}; pub mod config_file; pub mod settings; @@ -39,7 +39,6 @@ pub struct Config { pub path_dirs: Vec, pub aliases: AliasMap, pub all_aliases: OnceCell, - pub should_exit_early: bool, pub project_root: Option, plugins: RwLock, shorthands: OnceCell>, @@ -84,37 +83,16 @@ impl Config { .cloned() .collect_vec(); let config_paths = load_config_paths(&config_filenames); + track_config_files(&config_paths); let config_files = load_all_config_files(&config_paths, &plugins, &legacy_files, config_files)?; - let mut env: Option<_> = None; - let mut env_sources: Option<_> = None; - let mut should_exit_early = false; - let mut repo_urls = HashMap::new(); - rayon::scope(|s| { - s.spawn(|_| { - track_config_files(&config_paths); - }); - s.spawn(|_| { - let (a, b) = load_env(&config_files); - env = Some(a); - env_sources = Some(b); - }); - s.spawn(|_| { - let watch_files = config_files - .values() - .flat_map(|cf| cf.watch_files()) - .collect_vec(); - should_exit_early = hook_env::should_exit_early(&watch_files); - }); - s.spawn(|_| { - repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); - }) - }); + let (env, env_sources) = load_env(&config_files); + let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); let config = Self { - env: env.unwrap(), - env_sources: env_sources.unwrap(), + env, + env_sources, path_dirs: load_path_dirs(&config_files), aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), @@ -123,7 +101,6 @@ impl Config { config_files, global_config, plugins: RwLock::new(plugins), - should_exit_early, repo_urls, }; From cb5ff63d26a589c139f62217d754e3556b95c045 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 20:05:44 -0600 Subject: [PATCH 1413/1891] config: simplify tracking (#1254) --- src/config/mod.rs | 22 ++++------------------ src/config/tracking.rs | 31 +++++++++---------------------- 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 06296d02f..478eee069 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -83,7 +83,6 @@ impl Config { .cloned() .collect_vec(); let config_paths = load_config_paths(&config_filenames); - track_config_files(&config_paths); let config_files = load_all_config_files(&config_paths, &plugins, &legacy_files, config_files)?; @@ -200,9 +199,7 @@ impl Config { } pub fn get_tracked_config_files(&self) -> Result { - let tracker = Tracker::new(); - let config_files = tracker - .list_all()? + let config_files = Tracker::list_all()? .into_par_iter() .map(|path| match config_file::parse(&path) { Ok(cf) => Some((path, cf)), @@ -393,6 +390,9 @@ fn load_all_config_files( None => { let cf = parse_config_file(&f, legacy_filenames, tools) .wrap_err_with(|| format!("error parsing config file: {}", display_path(&f)))?; + if let Err(err) = Tracker::track(&f) { + warn!("tracking config: {err:#}"); + } Ok((f, cf)) } }) @@ -459,20 +459,6 @@ fn load_aliases(config_files: &ConfigMap) -> AliasMap { aliases } -fn track_config_files(config_filenames: &[PathBuf]) { - let config_filenames = config_filenames.to_vec(); - let track = move || -> Result<()> { - let mut tracker = Tracker::new(); - for config_file in &config_filenames { - tracker.track(config_file)?; - } - Ok(()) - }; - if let Err(err) = track() { - warn!("tracking config files: {:#}", err); - } -} - impl Debug for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let plugins = self diff --git a/src/config/tracking.rs b/src/config/tracking.rs index 371213c3a..32f70b1fe 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -1,4 +1,3 @@ -use std::collections::HashSet; use std::fs; use std::fs::{read_dir, remove_file}; use std::path::{Path, PathBuf}; @@ -9,32 +8,20 @@ use crate::dirs::TRACKED_CONFIGS; use crate::file::{create_dir_all, make_symlink}; use crate::hash::hash_to_str; -#[derive(Debug, Default)] -pub struct Tracker { - config_files: HashSet, -} +pub struct Tracker {} impl Tracker { - pub fn new() -> Self { - Self { - ..Default::default() - } - } - - pub fn track(&mut self, path: &Path) -> Result<()> { - if !self.config_files.contains(path) { - let tracking_path = TRACKED_CONFIGS.join(hash_to_str(&path)); - if !tracking_path.exists() { - create_dir_all(&*TRACKED_CONFIGS)?; - make_symlink(path, &tracking_path)?; - } - self.config_files.insert(path.to_path_buf()); + pub fn track(path: &Path) -> Result<()> { + let tracking_path = TRACKED_CONFIGS.join(hash_to_str(&path)); + if !tracking_path.exists() { + create_dir_all(&*TRACKED_CONFIGS)?; + make_symlink(path, &tracking_path)?; } Ok(()) } - pub fn list_all(&self) -> Result> { - self.clean()?; + pub fn list_all() -> Result> { + Self::clean()?; let mut output = vec![]; for path in read_dir(&*TRACKED_CONFIGS)? { let path = path?.path(); @@ -49,7 +36,7 @@ impl Tracker { Ok(output) } - pub fn clean(&self) -> Result<()> { + pub fn clean() -> Result<()> { for path in read_dir(&*TRACKED_CONFIGS)? { let path = path?.path(); if !path.exists() { From 388168c046a607f235dff909de3dd0296307ebf6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 20:11:07 -0600 Subject: [PATCH 1414/1891] chore: Release rtx-cli version 2023.12.35 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f20acc6e..9c4aa2464 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1858,7 +1858,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.34" +version = "2023.12.35" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 9df91170c..139f9a94d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.34" +version = "2023.12.35" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index c3eb77fe8..964f15bd5 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.34 +rtx 2023.12.35 ``` Hook rtx into your shell (pick the right one for your shell): @@ -360,7 +360,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.34/rtx-v2023.12.34-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.35/rtx-v2023.12.35-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index f076db131..b43bb0e26 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.34"; + version = "2023.12.35"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e2f5da3bb..86714fd98 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.34 +Version: 2023.12.35 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From db99330e2cdf225e9fe6f8ef3ef6c2ef8c3c6a27 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 20:56:37 -0600 Subject: [PATCH 1415/1891] config: simplify loading (#1255) Moved the logic around to simplify the config loading process. For now this removes the ability to have project local settings. Fixes #735 --- README.md | 3 --- src/config/mod.rs | 38 +++++++++------------------------- src/plugins/external_plugin.rs | 3 ++- 3 files changed, 12 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 964f15bd5..2c8eaeb33 100644 --- a/README.md +++ b/README.md @@ -588,9 +588,6 @@ python = {version='3.10', virtualenv='.venv'} # note this will only be used if the plugin does not already exist python = 'https://github.com/asdf-community/asdf-python' -[settings] # project-local settings -verbose = true - [alias.node] # project-local aliases my_custom_node = '20' ``` diff --git a/src/config/mod.rs b/src/config/mod.rs index 478eee069..6b09a79ff 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -61,21 +61,12 @@ impl Config { } pub fn load() -> Result { let global_config = load_rtxrc()?; + // TODO: read system config settings Settings::add_partial(global_config.settings()?); - - let (config_paths, plugins) = rayon::join( - || load_config_paths(&DEFAULT_CONFIG_FILENAMES), - load_plugins, - ); - let plugins = plugins?; - let config_files = - load_all_config_files(&config_paths, &plugins, &BTreeMap::new(), ConfigMap::new())?; - for cf in config_files.values() { - Settings::add_partial(cf.settings()?); - } let settings = Settings::try_get()?; trace!("Settings: {:#?}", settings); + let plugins = load_plugins(&settings)?; let legacy_files = load_legacy_files(&settings, &plugins); let config_filenames = legacy_files .keys() @@ -83,8 +74,7 @@ impl Config { .cloned() .collect_vec(); let config_paths = load_config_paths(&config_filenames); - let config_files = - load_all_config_files(&config_paths, &plugins, &legacy_files, config_files)?; + let config_files = load_all_config_files(&config_paths, &plugins, &legacy_files)?; let (env, env_sources) = load_env(&config_files); let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); @@ -259,9 +249,8 @@ fn load_rtxrc() -> Result { } } -fn load_plugins() -> Result { +fn load_plugins(settings: &Settings) -> Result { let mut tools = CORE_PLUGINS.clone(); - let settings = Settings::try_get()?; if settings.experimental { tools.extend(EXPERIMENTAL_CORE_PLUGINS.clone()); } @@ -375,26 +364,19 @@ fn load_all_config_files( config_filenames: &[PathBuf], tools: &PluginMap, legacy_filenames: &BTreeMap>, - mut existing: ConfigMap, ) -> Result { Ok(config_filenames .iter() .unique() - .map(|f| (f.clone(), existing.shift_remove(f))) .collect_vec() .into_par_iter() - .map(|(f, existing)| match existing { - // already parsed so just return it - Some(cf) => Ok((f, cf)), - // need to parse this config file - None => { - let cf = parse_config_file(&f, legacy_filenames, tools) - .wrap_err_with(|| format!("error parsing config file: {}", display_path(&f)))?; - if let Err(err) = Tracker::track(&f) { - warn!("tracking config: {err:#}"); - } - Ok((f, cf)) + .map(|f| { + let cf = parse_config_file(f, legacy_filenames, tools) + .wrap_err_with(|| format!("error parsing config file: {}", display_path(f)))?; + if let Err(err) = Tracker::track(f) { + warn!("tracking config: {err:#}"); } + Ok((f.clone(), cf)) }) .collect::>>() .into_iter() diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 644b7a872..20aca0f9f 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -11,6 +11,7 @@ use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; use itertools::Itertools; use once_cell::sync::Lazy; +use rayon::prelude::*; use crate::cache::CacheManager; use crate::config::{Config, Settings}; @@ -89,7 +90,7 @@ impl ExternalPlugin { pub fn list() -> Result)>> { Ok(file::dir_subdirs(&dirs::PLUGINS)? - .into_iter() + .into_par_iter() .map(|name| (name.clone(), Self::newa(name))) .collect()) } From bfed4f294b09378adeb4715a9e2377ff7e7834fe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:51:24 -0600 Subject: [PATCH 1416/1891] removed test that exited code 0 --- src/cli/version.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/cli/version.rs b/src/cli/version.rs index 4515c7c14..09bcd44a0 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -124,16 +124,3 @@ fn get_latest_version_call() -> Option { } } } - -#[cfg(test)] -mod tests { - use pretty_assertions::assert_str_eq; - - use super::*; - - #[test] - fn test_version() { - let stdout = assert_cli!("version"); - assert_str_eq!(stdout, VERSION.to_string()); - } -} From ff8de2093c4fc20121c60964ccaa35a7cd40d3e5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 23:48:19 -0600 Subject: [PATCH 1417/1891] init: only use ctrl-c handler if needed --- src/cli/mod.rs | 3 ++- src/cli/upgrade.rs | 3 ++- src/main.rs | 12 +----------- src/ui/mod.rs | 17 +++++++++++++++++ src/ui/multi_progress_report.rs | 1 + src/ui/progress_report.rs | 2 ++ src/ui/prompt.rs | 2 ++ 7 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 0659ec2c3..46bd9b98b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -2,7 +2,7 @@ use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; use crate::config::{Config, Settings}; -use crate::{logger, shims}; +use crate::{logger, migrate, shims}; mod activate; mod alias; @@ -194,6 +194,7 @@ impl Cli { if let Ok(settings) = Settings::try_get() { logger::init(&settings); } + migrate::run(); debug!("ARGS: {}", &args.join(" ")); match Commands::from_arg_matches(&matches) { Ok(cmd) => cmd.run(), diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 1a2172dfa..c4c9cc9f6 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -9,11 +9,11 @@ use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; use crate::plugins::Plugin; -use crate::runtime_symlinks; use crate::shims; use crate::toolset::{InstallOptions, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::SingleReport; +use crate::{runtime_symlinks, ui}; /// Upgrades outdated tool versions #[derive(Debug, clap::Args)] @@ -128,6 +128,7 @@ impl Upgrade { } fn get_interactive_tool_set(&self, outdated: &OutputVec) -> Result> { + ui::handle_ctrlc(); let mut ms = demand::MultiSelect::new("rtx upgrade") .description("Select tools to upgrade") .filterable(true) diff --git a/src/main.rs b/src/main.rs index 3e92cdf7f..8bd65810c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ mod test; use std::process::exit; use color_eyre::{Help, Report, SectionExt}; -use console::{style, Term}; +use console::style; use eyre::Result; use itertools::Itertools; @@ -67,8 +67,6 @@ mod ui; fn main() -> Result<()> { let args = env::args().collect_vec(); color_eyre::install()?; - handle_ctrlc(); - migrate::run(); match Cli::run(&args).with_section(|| VERSION.to_string().header("Version:")) { Ok(()) => Ok(()), @@ -82,14 +80,6 @@ fn main() -> Result<()> { } } -fn handle_ctrlc() { - let _ = ctrlc::set_handler(move || { - let _ = Term::stderr().show_cursor(); - debug!("Ctrl-C pressed, exiting..."); - exit(1); - }); -} - fn display_friendly_err(err: Report) { for err in err.chain() { error!("{err}"); diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 768fe4f7c..92a5b36ff 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,4 +1,21 @@ +use console::{user_attended_stderr, Term}; +use std::process::exit; +use std::sync::Once; + pub mod multi_progress_report; pub mod progress_report; pub mod prompt; pub mod table; + +pub fn handle_ctrlc() { + static ONCE: Once = Once::new(); + ONCE.call_once(|| { + if user_attended_stderr() { + let _ = ctrlc::set_handler(move || { + let _ = Term::stderr().show_cursor(); + debug!("Ctrl-C pressed, exiting..."); + exit(1); + }); + } + }); +} diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index fc21fa2f9..374dc091a 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,4 +1,5 @@ use crate::config::Settings; + use indicatif::MultiProgress; use std::sync::{Arc, Mutex, Weak}; diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 084bdc597..44e6dd429 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,4 +1,5 @@ use crate::config::Config; +use crate::ui; use console::style; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; @@ -56,6 +57,7 @@ fn success_prefix(pad: usize, prefix: &str) -> String { impl ProgressReport { pub fn new(prefix: String) -> ProgressReport { + ui::handle_ctrlc(); let pad = *LONGEST_PLUGIN_NAME; let pb = ProgressBar::new(100) .with_style(PROG_TEMPLATE.clone()) diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 74bf6c750..a6527f905 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,3 +1,4 @@ +use crate::ui; use demand::Confirm; use std::io; use std::sync::Mutex; @@ -6,6 +7,7 @@ static MUTEX: Mutex<()> = Mutex::new(()); pub fn confirm(message: &str) -> io::Result { let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once + ui::handle_ctrlc(); if !console::user_attended_stderr() { return Ok(false); From d7722cc092507f252a163d9f0e9ad8841eea6f27 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 22 Dec 2023 23:54:36 -0600 Subject: [PATCH 1418/1891] simplify InstallOptions --- README.md | 9 ---- completions/_rtx | 2 - completions/rtx.bash | 10 +--- completions/rtx.fish | 2 - src/cli/env.rs | 18 +------ src/cli/exec.rs | 2 +- src/config/config_file/rtx_toml.rs | 76 ++++++++++++++---------------- src/config/mod.rs | 8 ++-- src/config/settings.rs | 3 ++ src/plugins/rtx_plugin_toml.rs | 10 ++-- src/toml.rs | 4 +- src/toolset/mod.rs | 11 +++++ src/ui/table.rs | 6 ++- 13 files changed, 68 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 2c8eaeb33..dd9c1a7a4 100644 --- a/README.md +++ b/README.md @@ -1987,18 +1987,9 @@ Options: [possible values: bash, fish, nu, xonsh, zsh] - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: RTX_JOBS=] - -J, --json Output in JSON format - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - Examples: $ eval "$(rtx env -s bash)" $ eval "$(rtx env -s zsh)" diff --git a/completions/_rtx b/completions/_rtx index 8f7ce320a..f4c0a4bcc 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -289,9 +289,7 @@ __rtx_env_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ '*::tool:__rtx_tool_versions' \ - '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ - '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' diff --git a/completions/rtx.bash b/completions/rtx.bash index ec9b49839..bcb3560e0 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -1308,7 +1308,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -j -J -q -v -y -h --shell --jobs --json --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-s -J -q -v -y -h --shell --json --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1322,14 +1322,6 @@ _rtx() { COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -j) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; --log-level) COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 diff --git a/completions/rtx.fish b/completions/rtx.fish index dc0a43d30..4ff51e951 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -113,9 +113,7 @@ complete -xc rtx -n "$fssf direnv; and not $fssf $others" -a activate -d 'Output # doctor # env -complete -kxc rtx -n "$fssf env" -s j -l jobs -d 'Number of jobs to run in parallel' complete -kxc rtx -n "$fssf env" -s J -l json -d 'Output in JSON format' -complete -kxc rtx -n "$fssf env" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' complete -kxc rtx -n "$fssf env" -s s -l shell -a "bash fish nu xonsh zsh" -d 'Shell type to generate environment variables for' complete -kxc rtx -n "$fssf env" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' diff --git a/src/cli/env.rs b/src/cli/env.rs index 4637341ad..f057731e0 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -21,32 +21,16 @@ pub struct Env { #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser)] tool: Vec, - /// Number of jobs to run in parallel - /// [default: 4] - #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] - jobs: Option, - /// Output in JSON format #[clap(long, short = 'J', overrides_with = "shell")] json: bool, - - /// Directly pipe stdin/stdout/stderr from plugin to user - /// Sets --jobs=1 - #[clap(long, overrides_with = "jobs")] - raw: bool, } impl Env { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; - let opts = InstallOptions { - force: false, - jobs: self.jobs, - raw: self.raw, - latest_versions: false, - }; - ts.install_arg_versions(&config, &opts)?; + ts.install_arg_versions(&config, &InstallOptions::new())?; ts.warn_if_versions_missing(); if self.json { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 636c80dc2..ffbf569b5 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -40,7 +40,7 @@ pub struct Exec { pub c: Option, /// Change to this directory before executing the command - #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)] + #[clap(short = 'C', long, value_hint = ValueHint::DirPath)] pub cd: Option, /// Number of jobs to run in parallel diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 4b4b5c00b..70b8386bb 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -77,7 +77,7 @@ impl RtxToml { "tools" => self.toolset = self.parse_toolset(k, v)?, "settings" => self.settings = self.parse_settings(k, v)?, "plugins" => self.plugins = self.parse_plugins(k, v)?, - _ => Err(eyre!("unknown key: {}", k))?, + _ => bail!("unknown key: {}", style(k).red().for_stderr()), } } self.doc = doc; @@ -98,7 +98,7 @@ impl RtxToml { } self.env_file = Some(path); } - _ => parse_error!(k, v, "string")?, + _ => parse_error!(k, v, "string"), } Ok(()) } @@ -124,11 +124,11 @@ impl RtxToml { self.env_remove.push(k); } } else { - parse_error!(key, v, "string or bool")?; + parse_error!(key, v, "string or bool") } } } - _ => parse_error!(key, v, "table")?, + _ => parse_error!(key, v, "table"), } Ok(()) } @@ -152,12 +152,12 @@ impl RtxToml { }; path.push(s); } - _ => parse_error!(k, v, "string")?, + _ => parse_error!(k, v, "string"), } } Ok(path) } - _ => parse_error!(k, v, "array")?, + _ => parse_error!(k, v, "array"), } } @@ -177,16 +177,16 @@ impl RtxToml { let s = self.parse_template(&k, s)?; plugin_aliases.insert(from, s); } - _ => parse_error!(format!("{}.{}", k, from), to, "string")?, + _ => parse_error!(format!("{}.{}", k, from), to, "string"), } } } - _ => parse_error!(k, v, "table")?, + _ => parse_error!(k, v, "table"), } } Ok(aliases) } - _ => parse_error!(k, v, "table")?, + _ => parse_error!(k, v, "table"), } } @@ -206,7 +206,7 @@ impl RtxToml { let s = self.parse_template(key, s)?; env.insert(k, s); } - _ => parse_error!(key, v, "string")?, + _ => parse_error!(key, v, "string"), } } Ok(env) @@ -228,7 +228,7 @@ impl RtxToml { } Ok(toolset) } - _ => parse_error!(key, v, "table")?, + _ => parse_error!(key, v, "table"), } } @@ -285,45 +285,41 @@ impl RtxToml { v: &Item, plugin_name: &PluginName, ) -> Result<(ToolVersionRequest, ToolVersionOptions)> { - let mut tv = ToolVersionRequest::new(plugin_name.clone(), "system"); - let mut opts = ToolVersionOptions::default(); - match v.as_table_like() { Some(table) => { - if let Some(v) = table.get("version") { + let tv = if let Some(v) = table.get("version") { match v { - Item::Value(v) => { - tv = self.parse_tool_version_request(key, v, plugin_name)?; - } - _ => parse_error!(format!("{}.version", key), v, "string")?, + Item::Value(v) => self.parse_tool_version_request(key, v, plugin_name)?, + _ => parse_error!(format!("{}.version", key), v, "string"), } } else if let Some(path) = table.get("path") { match path.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - tv = ToolVersionRequest::Path(plugin_name.clone(), s.into()); + ToolVersionRequest::Path(plugin_name.clone(), s.into()) } - _ => parse_error!(format!("{}.path", key), v, "string")?, + _ => parse_error!(format!("{}.path", key), v, "string"), } } else if let Some(prefix) = table.get("prefix") { match prefix.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - tv = ToolVersionRequest::Prefix(plugin_name.clone(), s); + ToolVersionRequest::Prefix(plugin_name.clone(), s) } - _ => parse_error!(format!("{}.prefix", key), v, "string")?, + _ => parse_error!(format!("{}.prefix", key), v, "string"), } } else if let Some(r) = table.get("ref") { match r.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - tv = ToolVersionRequest::Ref(plugin_name.clone(), s); + ToolVersionRequest::Ref(plugin_name.clone(), s) } - _ => parse_error!(format!("{}.ref", key), v, "string")?, + _ => parse_error!(format!("{}.ref", key), v, "string"), } } else { - parse_error!(key, v, "version, path, or prefix")? - } + parse_error!(key, v, "version, path, or prefix"); + }; + let mut opts = ToolVersionOptions::default(); for (k, v) in table.iter() { if k == "version" || k == "path" || k == "prefix" || k == "ref" { continue; @@ -333,20 +329,20 @@ impl RtxToml { } else if let Some(b) = v.as_bool() { b.to_string() } else { - parse_error!(key, v, "string or bool")? + parse_error!(key, v, "string or bool"); }; opts.insert(k.into(), s); } + Ok((tv, opts)) } _ => match v { Item::Value(v) => { - tv = self.parse_tool_version_request(key, v, plugin_name)?; + let tv = self.parse_tool_version_request(key, v, plugin_name)?; + Ok((tv, Default::default())) } - _ => parse_error!(key, v, "value")?, + _ => parse_error!(key, v, "value"), }, } - - Ok((tv, opts)) } fn parse_tool_version_request( @@ -360,7 +356,7 @@ impl RtxToml { let s = self.parse_template(key, s)?; Ok(ToolVersionRequest::new(plugin_name.clone(), &s)) } - _ => parse_error!(key, v, "string")?, + _ => parse_error!(key, v, "string"), } } @@ -407,21 +403,21 @@ impl RtxToml { fn parse_bool(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_bool()) { Some(Some(v)) => Ok(v), - _ => parse_error!(k, v, "boolean")?, + _ => parse_error!(k, v, "boolean"), } } fn parse_string(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => Ok(v.to_string()), - _ => parse_error!(k, v, "string")?, + _ => parse_error!(k, v, "string"), } } fn parse_usize(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_integer()) { Some(Some(v)) => Ok(v as usize), - _ => parse_error!(k, v, "usize")?, + _ => parse_error!(k, v, "usize"), } } @@ -431,7 +427,7 @@ impl RtxToml { let v = self.parse_template(k, v)?; Ok(v.into()) } - _ => parse_error!(k, v, "path")?, + _ => parse_error!(k, v, "path"), } } @@ -446,12 +442,12 @@ impl RtxToml { let v = self.parse_template(&k, v)?; paths.push(v.into()); } - _ => parse_error!(k, v, "path")?, + _ => parse_error!(k, v, "path"), } } Ok(paths) } - _ => parse_error!(k, v, "array of paths")?, + _ => parse_error!(k, v, "array of paths"), } } @@ -461,7 +457,7 @@ impl RtxToml { .map(|v| v.iter().map(|v| v.as_str().unwrap().to_string()).collect()) { Some(v) => Ok(v), - _ => parse_error!(k, v, "array of strings")?, + _ => parse_error!(k, v, "array of strings"), } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 6b09a79ff..6288e2896 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -32,17 +32,17 @@ type ToolMap = BTreeMap>; #[derive(Default)] pub struct Config { - pub global_config: RtxToml, + pub aliases: AliasMap, pub config_files: ConfigMap, pub env: BTreeMap, pub env_sources: HashMap, + pub global_config: RtxToml, pub path_dirs: Vec, - pub aliases: AliasMap, - pub all_aliases: OnceCell, pub project_root: Option, + all_aliases: OnceCell, plugins: RwLock, - shorthands: OnceCell>, repo_urls: HashMap, + shorthands: OnceCell>, } static CONFIG: RwLock>> = RwLock::new(None); diff --git a/src/config/settings.rs b/src/config/settings.rs index c8db0d4cb..9fe3f60a4 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -90,6 +90,9 @@ impl Settings { if settings.trace { settings.log_level = "trace".to_string(); } + if settings.quiet { + settings.log_level = "error".to_string(); + } if settings.log_level == "trace" || settings.log_level == "debug" { settings.verbose = true; settings.debug = true; diff --git a/src/plugins/rtx_plugin_toml.rs b/src/plugins/rtx_plugin_toml.rs index 116c40f91..9c85f7c82 100644 --- a/src/plugins/rtx_plugin_toml.rs +++ b/src/plugins/rtx_plugin_toml.rs @@ -67,14 +67,14 @@ impl RtxPluginToml { "cache-key" => config.cache_key = Some(self.parse_string_array(k, v)?), "data" => match v.as_value() { Some(v) => config.data = Some(self.parse_string(k, v)?), - _ => parse_error!(key, v, "string")?, + _ => parse_error!(key, v, "string"), }, - _ => parse_error!(key, v, "one of: cache-key")?, + _ => parse_error!(key, v, "one of: cache-key"), } } Ok(config) } - _ => parse_error!(key, v, "table")?, + _ => parse_error!(key, v, "table"), } } @@ -87,14 +87,14 @@ impl RtxPluginToml { } Ok(out) } - _ => parse_error!(k, v, "array")?, + _ => parse_error!(k, v, "array"), } } fn parse_string(&mut self, k: &str, v: &Value) -> Result { match v.as_str() { Some(v) => Ok(v.to_string()), - _ => parse_error!(k, v, "string")?, + _ => parse_error!(k, v, "string"), } } } diff --git a/src/toml.rs b/src/toml.rs index 858d3f892..1c28d5002 100644 --- a/src/toml.rs +++ b/src/toml.rs @@ -1,11 +1,11 @@ #[macro_export] macro_rules! parse_error { ($key:expr, $val:expr, $t:expr) => {{ - Err(eyre!( + bail!( r#"expected value of "{}" to be a {}, got: {}"#, $key, $t, $val - )) + ) }}; } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 54d78e922..6420cb41f 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -42,6 +42,17 @@ pub struct InstallOptions { pub latest_versions: bool, } +impl InstallOptions { + pub fn new() -> Self { + let settings = Settings::get(); + InstallOptions { + jobs: Some(settings.jobs), + raw: settings.raw, + ..Default::default() + } + } +} + /// a toolset is a collection of tools for various plugins /// /// one example is a .tool-versions file diff --git a/src/ui/table.rs b/src/ui/table.rs index 05fe35f34..84c2cb5c7 100644 --- a/src/ui/table.rs +++ b/src/ui/table.rs @@ -28,9 +28,11 @@ pub fn default_style(table: &mut Table, no_headers: bool) { } else { table.with(Modify::new(Rows::first()).with(Format::content(header))); } + table.with(Style::empty()); + if console::user_attended() { + table.with(term_size_settings()); + } table - .with(Style::empty()) - .with(term_size_settings()) .with(Margin::new(0, 0, 0, 0)) .with(Modify::new(Columns::first()).with(Padding::new(0, 1, 0, 0))) .with(Modify::new(Columns::last()).with(Padding::zero())); From 15d6dc2631d860bd3c424c978dacaa2e2bdfd1f1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:37:59 -0600 Subject: [PATCH 1419/1891] change --quiet to display warnings but not errors --- README.md | 2 +- completions/_rtx | 120 ++++++++++++++++++++--------------------- completions/rtx.fish | 4 +- src/cli/activate.rs | 2 +- src/cli/args/quiet.rs | 2 +- src/cli/bin_paths.rs | 2 +- src/cli/env.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/hook_env.rs | 2 +- src/cli/shell.rs | 2 +- src/config/settings.rs | 2 +- src/env.rs | 1 + src/toolset/mod.rs | 15 +++--- 13 files changed, 79 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index dd9c1a7a4..c4c02b53d 100644 --- a/README.md +++ b/README.md @@ -1708,7 +1708,7 @@ Options: Show "rtx: @" message when changing directories -q, --quiet - Hide warnings such as when a tool is not installed + Suppress non-error messages Examples: $ eval "$(rtx activate bash)" diff --git a/completions/_rtx b/completions/_rtx index f4c0a4bcc..43fcdf348 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -5,7 +5,7 @@ _rtx() { local ret=1 _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cmds' \ @@ -64,7 +64,7 @@ __rtx_activate_cmd() { _arguments -s -S \ '::shell_type:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ - '(-q --quiet)'{-q,--quiet}'[Hide warnings such as when a tool is not installed]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -73,7 +73,7 @@ __rtx_alias_cmd() { _arguments -s -S \ '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ '--no-header[Don'\''t show table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_alias_cmds' \ @@ -98,7 +98,7 @@ __rtx_alias_get_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -107,7 +107,7 @@ __rtx_alias_ls_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ '--no-header[Don'\''t show table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -117,7 +117,7 @@ __rtx_alias_set_cmd() { ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ ':value:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -126,7 +126,7 @@ __rtx_alias_unset_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -134,21 +134,21 @@ __rtx_alias_unset_cmd() { __rtx_asdf_cmd() { _arguments -s -S \ '*::args:_cmdambivalent' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_bin_paths_cmd] )) || __rtx_bin_paths_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_cache_cmd] )) || __rtx_cache_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_cache_cmds' \ @@ -169,7 +169,7 @@ return ret __rtx_cache_clear_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -177,7 +177,7 @@ __rtx_cache_clear_cmd() { __rtx_completion_cmd() { _arguments -s -S \ '::shell:(bash fish zsh)' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -185,7 +185,7 @@ __rtx_completion_cmd() { __rtx_config_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_config_cmds' \ @@ -207,7 +207,7 @@ return ret __rtx_config_generate_cmd() { _arguments -s -S \ '(-o --output)'{-o,--output}'=[Output to file instead of stdout]:output:_files' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -215,7 +215,7 @@ __rtx_config_generate_cmd() { __rtx_config_ls_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -223,21 +223,21 @@ __rtx_config_ls_cmd() { __rtx_current_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_deactivate_cmd] )) || __rtx_deactivate_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_cmd] )) || __rtx_direnv_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_direnv_cmds' \ @@ -259,28 +259,28 @@ return ret (( $+functions[__rtx_direnv_activate_cmd] )) || __rtx_direnv_activate_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_envrc_cmd] )) || __rtx_direnv_envrc_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_direnv_exec_cmd] )) || __rtx_direnv_exec_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_doctor_cmd] )) || __rtx_doctor_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -290,7 +290,7 @@ __rtx_env_cmd() { '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ '*::tool:__rtx_tool_versions' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -300,7 +300,7 @@ __rtx_env_vars_cmd() { '--file=[The TOML file to update]:file:_files' \ '*--remove=[Remove the environment variable from config file]:remove:' \ '*::env_vars:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -312,7 +312,7 @@ __rtx_exec_cmd() { '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -324,7 +324,7 @@ __rtx_global_cmd() { '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ '--path[Get the path of the global config file]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -342,7 +342,7 @@ __rtx_implode_cmd() { _arguments -s -S \ '--config[Also remove config directory]' \ '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -354,7 +354,7 @@ __rtx_install_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '*'{-v,--verbose}'[Show installation output]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_latest_cmd] )) || @@ -362,7 +362,7 @@ __rtx_latest_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -372,7 +372,7 @@ __rtx_link_cmd() { ':tool:__rtx_tool_versions' \ ':path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -385,7 +385,7 @@ __rtx_local_cmd() { '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ '--path[Get the path of the config file]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -400,7 +400,7 @@ __rtx_ls_cmd() { '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ '--no-header[Don'\''t display headers]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -410,7 +410,7 @@ __rtx_ls_remote_cmd() { '::plugin:__rtx_plugins' \ '--all[Show all installed plugins and versions]' \ '::prefix:__rtx_prefixes' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -418,7 +418,7 @@ __rtx_ls_remote_cmd() { __rtx_outdated_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -428,7 +428,7 @@ __rtx_plugins_cmd() { '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_plugins_cmds' \ @@ -458,7 +458,7 @@ __rtx_plugins_install_cmd() { '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ '(-a --all)'{-a,--all}'[Install all missing plugins]' \ '*'{-v,--verbose}'[Show installation output]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_plugins_link_cmd] )) || @@ -467,7 +467,7 @@ __rtx_plugins_link_cmd() { ':name:' \ '::path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -477,7 +477,7 @@ __rtx_plugins_ls_cmd() { '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -486,7 +486,7 @@ __rtx_plugins_ls_remote_cmd() { _arguments -s -S \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -496,7 +496,7 @@ __rtx_plugins_uninstall_cmd() { '*::plugin:__rtx_plugins' \ '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ '(-a --all)'{-a,--all}'[Remove all plugins]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -505,7 +505,7 @@ __rtx_plugins_update_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -514,14 +514,14 @@ __rtx_prune_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_reshim_cmd] )) || __rtx_reshim_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -532,13 +532,13 @@ __rtx_self_update_cmd() { '--no-plugins[Disable auto-updating plugins]' \ '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ '::version:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' } (( $+functions[__rtx_settings_cmd] )) || __rtx_settings_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_settings_cmds' \ @@ -562,14 +562,14 @@ return ret __rtx_settings_get_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_settings_ls_cmd] )) || __rtx_settings_ls_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -578,7 +578,7 @@ __rtx_settings_set_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ ':value:' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -586,7 +586,7 @@ __rtx_settings_set_cmd() { __rtx_settings_unset_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -597,14 +597,14 @@ __rtx_shell_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_sync_cmd] )) || __rtx_sync_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ '1: :__rtx_sync_cmds' \ @@ -628,7 +628,7 @@ __rtx_sync_node_cmd() { '--brew[Get tool versions from Homebrew]' \ '--nvm[Get tool versions from nvm]' \ '--nodenv[Get tool versions from nodenv]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -636,7 +636,7 @@ __rtx_sync_node_cmd() { __rtx_sync_python_cmd() { _arguments -s -S \ '--pyenv[Get tool versions from pyenv]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -646,7 +646,7 @@ __rtx_trust_cmd() { '::config_file:_files' \ '(-a --all)'{-a,--all}'[Trust all config files in the current directory and its parents]' \ '--untrust[No longer trust this config]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -656,7 +656,7 @@ __rtx_uninstall_cmd() { '*::installed_tool:__rtx_installed_tool_versions' \ '(-a --all)'{-a,--all}'[Delete all installed versions]' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -668,7 +668,7 @@ __rtx_upgrade_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-i --interactive)'{-i,--interactive}'[Display multiselect menu to choose which tools to upgrade]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -685,14 +685,14 @@ __rtx_use_cmd() { '*--remove=[Remove the tool(s) from config file]:remove:' \ '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ '--pin[Save exact version to config file]' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } (( $+functions[__rtx_version_cmd] )) || __rtx_version_cmd() { _arguments -s -S \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -700,7 +700,7 @@ __rtx_version_cmd() { __rtx_where_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } @@ -711,7 +711,7 @@ __rtx_which_cmd() { '--plugin[Show the plugin name instead of the path]' \ '--version[Show the version instead of the path]' \ '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ - '(-q --quiet)'{-q,--quiet}'[Suppress warnings and other non-error messages]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } diff --git a/completions/rtx.fish b/completions/rtx.fish index 4ff51e951..970d89548 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,7 +1,7 @@ set -l fssf "__fish_seen_subcommand_from" # rtx -complete -kxc rtx -s q -l quiet -d 'Suppress warnings and other non-error messages' +complete -kxc rtx -s q -l quiet -d 'Suppress non-error messages' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which @@ -41,7 +41,7 @@ complete -xc rtx -n "not $fssf $others" -a where -d 'Display the installation pa complete -xc rtx -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' # activate -complete -kxc rtx -n "$fssf activate" -s q -l quiet -d 'Hide warnings such as when a tool is not installed' +complete -kxc rtx -n "$fssf activate" -s q -l quiet -d 'Suppress non-error messages' complete -kxc rtx -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' complete -kxc rtx -n "$fssf activate" -l status -d 'Show "rtx: @" message when changing directories' diff --git a/src/cli/activate.rs b/src/cli/activate.rs index a4caaf7b9..cc3c43b64 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -39,7 +39,7 @@ pub struct Activate { #[clap(long)] status: bool, - /// Hide warnings such as when a tool is not installed + /// Suppress non-error messages #[clap(long, short)] quiet: bool, } diff --git a/src/cli/args/quiet.rs b/src/cli/args/quiet.rs index a5773c772..cb4ef8dd8 100644 --- a/src/cli/args/quiet.rs +++ b/src/cli/args/quiet.rs @@ -8,7 +8,7 @@ impl Quiet { Arg::new("quiet") .short('q') .long("quiet") - .help("Suppress warnings and other non-error messages") + .help("Suppress non-error messages") .global(true) .overrides_with("verbose") .action(ArgAction::SetTrue) diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index e8a38d602..fc2b4aaca 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -13,7 +13,7 @@ impl BinPaths { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let ts = ToolsetBuilder::new().build(&config)?; - ts.warn_if_versions_missing(); + ts.notify_if_versions_missing(); for p in ts.list_paths() { rtxprintln!("{}", p.display()); } diff --git a/src/cli/env.rs b/src/cli/env.rs index f057731e0..6637c645b 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -31,7 +31,7 @@ impl Env { let config = Config::try_get()?; let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; ts.install_arg_versions(&config, &InstallOptions::new())?; - ts.warn_if_versions_missing(); + ts.notify_if_versions_missing(); if self.json { self.output_json(&config, ts) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index ffbf569b5..c72539bbf 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -65,7 +65,7 @@ impl Exec { latest_versions: false, }; ts.install_arg_versions(&config, &opts)?; - ts.warn_if_versions_missing(); + ts.notify_if_versions_missing(); let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); let env = ts.env_with_path(&config); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index d5fe3f287..161da5acf 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -70,7 +70,7 @@ impl HookEnv { if self.status { self.display_status(&config, &ts); } - ts.warn_if_versions_missing(); + ts.notify_if_versions_missing(); Ok(()) } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index dfe02c0c6..bab4f8290 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -46,7 +46,7 @@ impl Shell { latest_versions: false, }; ts.install_arg_versions(&config, &opts)?; - ts.warn_if_versions_missing(); + ts.notify_if_versions_missing(); let shell = get_shell(None).expect("no shell detected"); diff --git a/src/config/settings.rs b/src/config/settings.rs index 9fe3f60a4..660fd889f 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -91,7 +91,7 @@ impl Settings { settings.log_level = "trace".to_string(); } if settings.quiet { - settings.log_level = "error".to_string(); + settings.log_level = "warn".to_string(); } if settings.log_level == "trace" || settings.log_level == "debug" { settings.verbose = true; diff --git a/src/env.rs b/src/env.rs index cd026c803..26328b92a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -74,6 +74,7 @@ pub static TERM_WIDTH: Lazy = Lazy::new(|| { terminal_size::terminal_size() .map(|(w, _)| w.0 as usize) .unwrap_or(80) + .max(60) }); /// duration that remote version cache is kept for diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 6420cb41f..148ed192f 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::thread; -use console::{style, truncate_str}; +use console::truncate_str; use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; @@ -361,20 +361,19 @@ impl Toolset { .collect()) } - pub fn warn_if_versions_missing(&self) { + pub fn notify_if_versions_missing(&self) { let missing = self.list_missing_versions(); if missing.is_empty() { return; } let versions = missing .iter() - .map(|tv| tv.to_string()) + .map(|tv| tv.style()) .collect::>() - .join(", "); - warn!( - "missing: {}. Install with {}", - truncate_str(&versions, TERM_WIDTH.max(60) - 39, "…"), - style("rtx install").yellow().for_stderr(), + .join(" "); + info!( + "missing: {}", + truncate_str(&versions, *TERM_WIDTH - 13, "…"), ); } } From 2b4388833081d9cb7433c614d529b7c62716bc22 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 05:05:22 -0600 Subject: [PATCH 1420/1891] task (#1260) --- .rtx.local.toml | 7 + .rtx.toml | 64 ++- .rtx/config.toml | 1 + .rtx/tasks/filetask | 12 + Cargo.lock | 61 ++- Cargo.toml | 20 +- README.md | 387 +++++++++++-- completions/_rtx | 93 ++++ completions/rtx.bash | 336 +++++++++++- completions/rtx.fish | 54 +- justfile | 3 +- schema/rtx.json | 111 ++++ src/cli/deactivate.rs | 7 +- src/cli/implode.rs | 2 +- src/cli/mod.rs | 6 + src/cli/plugins/uninstall.rs | 10 +- src/cli/run.rs | 510 ++++++++++++++++++ ...cli__settings__ls__tests__settings_ls.snap | 1 + ...i__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + src/cli/task/edit.rs | 44 ++ src/cli/task/ls.rs | 96 ++++ src/cli/task/mod.rs | 42 ++ src/cmd.rs | 94 +++- src/config/config_file/mod.rs | 39 +- src/config/config_file/rtx_toml.rs | 106 +++- ...__config_file__rtx_toml__tests__env-5.snap | 1 + ...nfig_file__rtx_toml__tests__fixture-2.snap | 1 + ...nfig_file__rtx_toml__tests__fixture-6.snap | 3 +- ...ig_file__rtx_toml__tests__path_dirs-5.snap | 1 + ...file__rtx_toml__tests__remove_alias-4.snap | 1 + ...ile__rtx_toml__tests__remove_plugin-4.snap | 1 + ...__rtx_toml__tests__replace_versions-4.snap | 1 + src/config/config_file/toml.rs | 53 ++ src/config/mod.rs | 114 +++- src/config/settings.rs | 2 + src/env.rs | 4 +- src/file.rs | 21 +- src/main.rs | 3 + src/output.rs | 21 +- src/plugins/core/assets/node_npm_shim | 2 +- src/plugins/external_plugin.rs | 5 +- src/shell/completions/fish_complete.rs | 11 +- src/shell/completions/zsh_complete.rs | 6 + src/task.rs | 182 +++++++ src/tera.rs | 1 + src/test.rs | 7 + src/toml.rs | 8 +- src/ui/mod.rs | 2 + src/ui/progress_report.rs | 15 +- src/ui/prompt.rs | 2 +- src/ui/style.rs | 41 ++ src/ui/table.rs | 2 +- test/.gitignore | 1 + test/config/config.toml | 7 + test/cwd/.rtx/tasks/filetask | 11 + 56 files changed, 2478 insertions(+), 160 deletions(-) create mode 100644 .rtx/config.toml create mode 100755 .rtx/tasks/filetask create mode 100644 src/cli/run.rs create mode 100644 src/cli/task/edit.rs create mode 100644 src/cli/task/ls.rs create mode 100644 src/cli/task/mod.rs create mode 100644 src/config/config_file/toml.rs create mode 100644 src/task.rs create mode 100644 src/ui/style.rs create mode 100755 test/cwd/.rtx/tasks/filetask diff --git a/.rtx.local.toml b/.rtx.local.toml index 7e0caf504..d7b0609af 100644 --- a/.rtx.local.toml +++ b/.rtx.local.toml @@ -1,3 +1,10 @@ #:schema ./schema/rtx.json + +tasks.a1 = { run = "echo a1 1>&2 && sleep 1.5" } +tasks.a2 = { run = "echo a2 && sleep 1.0" } +tasks.b1 = { run = "echo b1 && sleep 1.0", depends = ["a1", "a2"] } +tasks.c1 = { run = "echo c1 && sleep 0.5 && echo", depends = ["b1"] } +#tasks.filetask = "echo local" + [env] FOO=".rtx.local.toml" diff --git a/.rtx.toml b/.rtx.toml index a411a6438..3a0744291 100644 --- a/.rtx.toml +++ b/.rtx.toml @@ -1,8 +1,9 @@ #:schema ./schema/rtx.json + env_file = '.env' [env] FOO = "bar" -THIS_PROJECT = "{{config_root}}-{{env.PWD}}" +THIS_PROJECT = "{{config_root}}-{{cwd}}" [tools] #node = 'lts' @@ -16,3 +17,64 @@ nnnn = 'https://github.com/rtx-plugins/rtx-nodejs#main' [alias.tiny] abc = '1' + +[tasks.format] +run = "cargo fmt -- --emit=files" + +[tasks.clean] +run = "cargo clean" + +[tasks.build] +alias = "b" +run = "cargo build --color always --all-features" +sources = ["src/**/*.rs"] +outputs = ["target/debug/rtx"] + +[tasks.test] +run = "cargo test" +depends = ["clean"] +env = { CARGO_TERM_COLOR = "always" } + +[tasks.ci] +depends = [ + "format", + "build", + "test" +] + +[tasks.render-completions] +depends = ["build"] +env = { NO_COLOR = "1" } +sources = ["target/debug/rtx"] +outputs = [ + "completions/rtx.bash", + "completions/_rtx", + "completions/rtx.fish", +] +run = """ +#!/usr/bin/env bash +set -xeuo pipefail +target/debug/rtx render-completion bash > completions/rtx.bash +target/debug/rtx render-completion zsh > completions/_rtx +target/debug/rtx render-completion fish > completions/rtx.fish +""" + +[tasks.render-mangen] +depends = ["build"] +env = { NO_COLOR = "1" } +run = "target/debug/rtx render-mangen" +sources = ["target/debug/rtx"] +outputs = ["man/man1/rtx.1"] + +[tasks.render-help] +depends = ["build"] +env = { NO_COLOR = "1" } +run = [ + "target/debug/rtx render-help", + "md-magic", +] +sources = ["target/debug/rtx"] +outputs = ["README.md"] + +[tasks.render-all] +depends = ["render-*"] diff --git a/.rtx/config.toml b/.rtx/config.toml new file mode 100644 index 000000000..a14805611 --- /dev/null +++ b/.rtx/config.toml @@ -0,0 +1 @@ +tasks.lint = "echo LINT!" diff --git a/.rtx/tasks/filetask b/.rtx/tasks/filetask new file mode 100755 index 000000000..037960417 --- /dev/null +++ b/.rtx/tasks/filetask @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# rtx description="This is a test build script" +# rtx depends=["lint", "build"] +# rtx sources=[".test-tool-versions"] +# rtx outputs=["$RTX_PROJECT_ROOT/test/test-build-output.txt"] +# rtx env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} + +set -euxo pipefail +cd "$RTX_PROJECT_ROOT" || exit 1 +echo "running test-build script" +echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test/test-build-output.txt +echo "ARGS:" "$@" diff --git a/Cargo.lock b/Cargo.lock index 9c4aa2464..23a8ff559 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -751,6 +751,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -913,6 +919,17 @@ dependencies = [ "walkdir", ] +[[package]] +name = "globwalk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baba373693f105316dff9ebdae694118df59cf8fb3fc21b2acf1e294a3893794" +dependencies = [ + "bitflags 2.4.1", + "ignore", + "walkdir", +] + [[package]] name = "h2" version = "0.3.22" @@ -1556,6 +1573,16 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -1876,11 +1903,13 @@ dependencies = [ "dirs-next", "dotenvy", "duct", + "either", "exec", "eyre", "filetime", "flate2", "fslock", + "globwalk 0.9.0", "humantime", "indenter", "indexmap", @@ -1893,6 +1922,7 @@ dependencies = [ "once_cell", "openssl", "path-absolutize", + "petgraph", "pretty_assertions", "rand", "rayon", @@ -1907,6 +1937,7 @@ dependencies = [ "shell-escape", "shell-words", "simplelog", + "strum", "sys-info", "tabled", "tar", @@ -1993,6 +2024,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.16" @@ -2252,6 +2289,28 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.42", +] + [[package]] name = "subtle" version = "2.5.0" @@ -2367,7 +2426,7 @@ version = "1.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8" dependencies = [ - "globwalk", + "globwalk 0.8.1", "lazy_static", "pest", "pest_derive", diff --git a/Cargo.toml b/Cargo.toml index 139f9a94d..72ea4c394 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,10 +39,7 @@ lto = true [dependencies] base64 = "<0.22" -chrono = { version = "0.4", default-features = false, features = [ - "std", - "clock", -] } +chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } clap = { version = "4.4", features = ["env", "derive", "string"] } clap_complete = { version = "4", optional = true } clap_mangen = { version = "0.2", optional = true } @@ -55,10 +52,12 @@ demand = "0.3" dirs-next = "2.0" dotenvy = "0.15" duct = "0.13" +either = "1.9.0" eyre = "0.6" filetime = "0.2" flate2 = "1.0" fslock = "0.2" +globwalk = "0.9.0" humantime = "2.1" indenter = "0.3" indexmap = { version = "2.0", features = ["serde"] } @@ -73,12 +72,9 @@ path-absolutize = "3.1" rand = "0.8" rayon = "1.8" regex = "1.9" -reqwest = { version = "0.11.17", default-features = false, features = [ - "blocking", - "json", - "gzip", -] } +reqwest = { version = "0.11.17", default-features = false, features = ["blocking", "json", "gzip"] } rmp-serde = "1.1.2" +petgraph = "0.6.4" self_update = { version = "<1", default-features = false, features = [ "archive-tar", "compression-flate2", @@ -91,6 +87,7 @@ sha2 = "0.10" shell-escape = "0.1" shell-words = "1.1" simplelog = { version = "0.12" } +strum = { version = "0.25.0", features = ["derive"] } sys-info = "0.9" tabled = { version = "0.15", features = ["ansi"] } tar = "0.4" @@ -146,7 +143,4 @@ pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-linux-arm64{ a pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-linux-x64{ archive-suffix }" [package.metadata.cargo-machete] -ignored = [ - "built", - "openssl", -] +ignored = ["built", "openssl"] diff --git a/README.md b/README.md index c4c02b53d..eb681c1bb 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ - **Fuzzy matching and aliases** - It's enough to just say you want "v20" of node, or the "lts" version. rtx will figure out the right version without you needing to specify an exact version. - **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. +- **Task runner** - Define project-specific tasks like `test` or `lint`. Supports parallel execution and file watching. ## 30 Second Demo @@ -81,7 +82,6 @@ v20.0.0 - [Register shell hook](#register-shell-hook) - [Migrate from asdf](#migrate-from-asdf) - [Uninstalling](#uninstalling) -- [Shebang](#shebang) - [Configuration](#configuration) - [`.rtx.toml`](#rtxtoml) - [Legacy version files](#legacy-version-files) @@ -90,8 +90,17 @@ v20.0.0 - [Global config: `~/.config/rtx/config.toml`](#global-config-configrtxconfigtoml) - [System config: `/etc/rtx/config.toml`](#system-config-etcrtxconfigtoml) - [Environment variables](#environment-variables) +- [Shebang](#shebang) +- [[experimental] Task Runner](#experimental-task-runner) + - [Script-based Tasks](#script-based-tasks) + - [Config-based Tasks](#config-based-tasks) + - [Task Environment Variables](#task-environment-variables) + - [Running Tasks](#running-tasks) + - [Running on file changes](#running-on-file-changes) + - [Watching files (coming soon)](#watching-files-coming-soon) - [Aliases](#aliases) - [Plugins](#plugins) + - [Core Plugins](#core-plugins) - [Plugin Authors](#plugin-authors) - [Plugin Options](#plugin-options) - [Versioning](#versioning) @@ -102,7 +111,6 @@ v20.0.0 - [Templates](#templates) - [Config Environments](#config-environments) - [IDE Integration](#ide-integration) -- [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) @@ -164,6 +172,7 @@ v20.0.0 - [`rtx plugins update [OPTIONS] [PLUGIN]...`](#rtx-plugins-update-options-plugin) - [`rtx prune [OPTIONS] [PLUGIN]...`](#rtx-prune-options-plugin) - [`rtx reshim`](#rtx-reshim) + - [`rtx run [OPTIONS] [ARGS]...`](#rtx-run-options-task-args) - [`rtx self-update [OPTIONS] [VERSION]`](#rtx-self-update-options-version) - [`rtx settings get `](#rtx-settings-get-setting) - [`rtx settings ls`](#rtx-settings-ls) @@ -172,6 +181,9 @@ v20.0.0 - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) - [`rtx sync node <--brew|--nvm|--nodenv>`](#rtx-sync-node---brew--nvm--nodenv) - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) + - [`rtx task edit `](#rtx-task-edit-task) + - [`rtx task ls [OPTIONS]`](#rtx-task-ls-options) + - [`rtx task run [OPTIONS] [ARGS]...`](#rtx-task-run-options-task-args) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall [OPTIONS] [TOOL@VERSION]...`](#rtx-uninstall-options-toolversion) - [`rtx upgrade [OPTIONS] [TOOL@VERSION]...`](#rtx-upgrade-options-toolversion) @@ -539,20 +551,6 @@ Alternatively, manually remove the following directories to fully clean up: - on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) - on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) -## Shebang - -You can specify a tool and its version in a shebang without needing to first -setup `.tool-versions`/`.rtx.toml` config: - -```typescript -#!/usr/bin/env -S rtx x node@20 -- node -// "env -S" allows multiple arguments in a shebang -console.log(`Running node: ${process.version}`); -``` - -This can also be useful in environments where rtx isn't activated -(such as a non-interactive session). - ## Configuration ### `.rtx.toml` @@ -564,6 +562,17 @@ that has lot more flexibility. It supports functionality that is not possible wi - passing options to plugins like `virtualenv='.venv'` for [python](https://github.com/jdx/rtx/blob/main/docs/python.md#experimental-automatic-virtualenv-creationactivation). - specifying custom plugin URLs +They can use any of the following project locations (in order of precedence, top is highest): + +- `.rtx.toml` +- `.rtx/config.toml` +- `.config/rtx.toml` +- `.config/rtx/rtx.toml` + +They can also be named `.rtx.local.toml` and environment-specific files like `.rtx.production.toml`. +Can also be opted-in. See [Config Environments](#config-environments) for more details. +Run `rtx config` to see the order of precedence on your system. + Here is what an `.rtx.toml` looks like: ```toml @@ -785,6 +794,8 @@ jobs = 4 # number of plugins or runtimes to install in parallel. The raw = false # set to true to directly pipe plugins to stdin/stdout/stderr yes = false # set to true to automatically answer yes to all prompts +task_output = "prefix" # see Task Runner for more information + shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` disable_tools = ['node'] # disable specific tools, generally used to turn off core tools @@ -981,6 +992,13 @@ all. This will automatically answer yes or no to prompts. This is useful for scripting. +#### `RTX_TASK_OUTPUT=prefix` + +This controls the output of `rtx run`. It can be one of: + +- `prefix` - (default if jobs > 1) print by line with the prefix of the task name +- `interleave` - (default if jobs == 1) display stdout/stderr as it comes in + #### `RTX_EXPERIMENTAL=1` Enables experimental features. @@ -989,7 +1007,7 @@ Enables experimental features. Default: false unless running NixOS or Alpine (let me know if others should be added) -Do not use precompiled binaries for all languages. Useful if running on a Linux distrobution +Do not use precompiled binaries for all languages. Useful if running on a Linux distribution like Alpine that does not use glibc and therefore likely won't be able to run precompiled binaries. Note that this needs to be setup for each language. File a ticket if you notice a language that is not @@ -1003,6 +1021,163 @@ automatically activate rtx without configuring. Defaults to enabled, set to "0" to disable. +## Shebang + +You can specify a tool and its version in a shebang without needing to first +setup `.tool-versions`/`.rtx.toml` config: + +```typescript +#!/usr/bin/env -S rtx x node@20 -- node +// "env -S" allows multiple arguments in a shebang +console.log(`Running node: ${process.version}`); +``` + +This can also be useful in environments where rtx isn't activated +(such as a non-interactive session). + +## [experimental] Task Runner + +You can define tasks in `.rtx.toml` files or as standalone files. These are useful for things like +running linters, tests, builders, servers, and other tasks that are specific to a project. Of course, +tasks launched with rtx will include the tool environment (tools and env vars) even if rtx has not been otherwise +activated. + +> **Warning** +> +> This is an experimental feature. It is not yet stable and will likely change. Some of the docs +> may not be implemented, may be implemented incorrectly, or the docs may need to be updated. +> Please give feedback early since while it's experimental it's much easier to change. + +### Script-based Tasks + +Tasks can be defined in 2 ways, either as standalone script files in `.rtx/tasks` such as the following build script +for cargo: + +```bash +#!/usr/bin/env bash +# rtx:description "Build the CLI" +cargo build +``` + +> **Note:** +> +> The `rtx:description` comment is optional but recommended. It will be used in the output of `rtx tasks`. +> The other configuration for "script" tasks is supported in this format so you can specify things like the +> following-note that this is parsed a TOML table: +> +> ```bash +> # rtx alias="b" +> # rtx sources=["Cargo.toml", "src/**/*.rs"] +> # rtx outputs=["target/debug/mycli"] +> # rtx env={RUST_BACKTRACE = "1"} +> # rtx depends=["lint", "test"] +> ``` + +Assuming that file was located in `.rtx/tasks/build`, it could be run with `rtx run build`. +This script can also be edited with $EDITOR by running `rtx task edit build`, if it doesn't exist it will be created. +These are convenient for quickly making new scripts. Having the code in a bash file and not TOML helps make it work +better in editors since they can do syntax highlighting and linting more easily. + +### Config-based Tasks + +Tasks can also be defined in `.rtx.toml` files in different ways: + +```toml +task.clean = 'cargo clean && rm -rf .cache' # runs as a shell command + +[task.build] +description = 'Build the CLI' +run = "cargo build" +alias = 'b' # `rtx run b` + +[task.test] +description = 'Run automated tests' +run = [ # multiple commands are run in series + 'cargo test', + './scripts/test-e2e.sh', +] +dir = "{{cwd}}" # run in user's cwd, default is the project's base directory + +[task.lint] +description = 'Lint with clippy' +env = {RUST_BACKTRACE = '1'} # env vars for the script +# you can specify a multiline script instead of individual commands +run = """ +#!/usr/bin/env bash +cargo clippy +""" + +[task.ci] # only dependencies to be run +description = 'Run CI tasks' +depends = ['build', 'lint', 'test'] + +[task.release] +description = 'Cut a new release' +file = 'scripts/release.sh' # execute an external script +``` + +### Task Environment Variables + +- `RTX_PROJECT_ROOT` - the root of the project, defaults to the directory of the `.rtx.toml` file + +### Running Tasks + +See available tasks with `rtx tasks`. Run a task with `rtx task run`, `rtx run`, or just `rtx r`. +You might even want to make a shell alias like `alias r='rtx r'` since this is likely a common command. + +By default, tasks will execute with a maximum of 4 parallel jobs. Customize this with the `--jobs` option, +`jobs` setting or `RTX_JOBS` environment variable. The output normally will be by line, prefixed with the task +label. By printing line-by-line we avoid interleaving output from parallel executions. However, if +--jobs == 1, the output will be set to `interleave`. + +To just print stdout/stderr directly, use `--interleave`, the `task_output` setting, or `RTX_TASK_OUTPUT=interleave`. + +Stdin is not read by default. To enable this, set `raw = true` on the task that needs it. This will prevent +it running in parallel with any other task-a RWMutex will get a write lock in this case. + +Extra arguments will be passed to the task, for example, if we want to run in release mode: + +```bash +rtx r build --release +``` + +If there are multiple commands, the args are only passed to the last command. + +Multiple tasks/arguments can be separated with this `:::` delimiter: + +```bash +rtx r build arg1 arg2 ::: test arg3 arg4 +``` + +### Running on file changes + +It's often handy to only execute a task if the files it uses changes. For example, we might only want +to run `cargo build` if a ".rs" file changes. This can be done with the following task config: + +```toml +[task.build] +description = 'Build the CLI' +run = "cargo build" +sources = ['Cargo.toml', 'src/**/*.rs'] # skip running if these files haven't changed +outputs = ['target/debug/mycli'] +``` + +Now if `target/debug/mycli` is newer than `Cargo.toml` or any ".rs" file, the task will be skipped. + +### Watching files (coming soon) + +Run a task when the source changes with `rtx watch`: + +```bash +rtx watch -t build +``` + +Define specific files to watch with `--glob`: + +```bash +rtx watch -t build --glob '*.rs' +``` + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS @@ -1041,6 +1216,21 @@ See for the list of built-in plugins s [Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn more about how they work. +### Core Plugins + +rtx comes with some plugins built into the CLI written in Rust. These are new and will improve over +time. They can be easily overridden by installing a plugin with the same name, e.g.: `rtx plugin install python https://github.com/asdf-community/asdf-python`. + +You can see the core plugins with `rtx plugin ls --core`. + +- [Python](./docs/python.md) +- [NodeJS](./docs/node.md) +- [Ruby](./docs/ruby.md) +- [Go](./docs/go.md) +- [Java](./docs/java.md) +- [Deno](./docs/deno.md) +- [Bun](./docs/bun.md) + ### Plugin Authors is a GitHub organization for community-developed plugins. @@ -1189,9 +1379,17 @@ the current directory. These are intended to not be committed to version control The priority of these files goes in this order (bottom overrides top): +- `.config/rtx/config.toml` +- `.rtx/config.toml` - `.rtx.toml` +- `.config/rtx/config.local.toml` +- `.rtx/config.local.toml` - `.rtx.local.toml` +- `.config/rtx/config.{RTX_ENV}.toml` +- `.rtx/config.{RTX_ENV}.toml` - `.rtx.{RTX_ENV}.toml` +- `.config/rtx/config.{RTX_ENV}.local.toml` +- `.rtx/config.{RTX_ENV}.local.toml` - `.rtx.{RTX_ENV}.local.toml` Use `rtx doctor` to see which files are being used. @@ -1220,21 +1418,6 @@ Direnv and rtx work similarly and there should be a direnv extension that can be Alternatively, you may be able to get tighter integration with a direnv extension and using the [`use_rtx`](#direnv) direnv function. -## Core Plugins - -rtx comes with some plugins built into the CLI written in Rust. These are new and will improve over -time. They can be easily overridden by installing a plugin with the same name, e.g.: `rtx plugin install python https://github.com/asdf-community/asdf-python`. - -You can see the core plugins with `rtx plugin ls --core`. - -- [Python](./docs/python.md) -- [NodeJS](./docs/node.md) -- [Ruby](./docs/ruby.md) -- [Go](./docs/go.md) -- [Java](./docs/java.md) -- [Deno](./docs/deno.md) -- [Bun](./docs/bun.md) - ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file @@ -2558,6 +2741,61 @@ Examples: v20.0.0 ``` +### `rtx run [OPTIONS] [ARGS]...` + +**Aliases:** `r` + +```text +[experimental] Run a task + +Usage: run [OPTIONS] [ARGS]... + +Arguments: + + Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2 + + [ARGS]... + Arguments to pass to the task + +Options: + -C, --cd + Change to this directory before executing the command + + -n, --dry-run + Don't actually run the task(s), just print them in order of execution + + -f, --force + Force the task to run even if outputs are up to date + + -p, --prefix + Print stdout/stderr by line, prefixed with the task's label + Defaults to true if --jobs > 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -i, --interleave + Print directly to stdout/stderr instead of by line + Defaults to true if --jobs == 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -t, --tool + Tool(s) to also add e.g.: node@20 python@3.10 + + -j, --jobs + Number of tasks to run in parallel + [default: 4] + Configure with `jobs` config or `RTX_JOBS` env var + + [env: RTX_JOBS=] + + -r, --raw + Read/write directly to stdin/stdout/stderr instead of by line + Configure with `raw` config or `RTX_RAW` env var + +Examples: + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + TODO +``` + ### `rtx self-update [OPTIONS] [VERSION]` ```text @@ -2742,6 +2980,91 @@ Examples: $ rtx use -g python@3.11.0 - uses pyenv-provided python ``` +### `rtx task edit ` + +```text +[experimental] Edit a task with $EDITOR + +Usage: task edit + +Arguments: + + Task to edit +``` + +### `rtx task ls [OPTIONS]` + +```text +[experimental] List config files currently in use + +Usage: task ls [OPTIONS] + +Options: + --no-header + Do not print table header + + --hidden + Show hidden tasks + +Examples: + $ rtx task ls +``` + +### `rtx task run [OPTIONS] [ARGS]...` + +**Aliases:** `r` + +```text +[experimental] Run a task + +Usage: task run [OPTIONS] [ARGS]... + +Arguments: + + Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2 + + [ARGS]... + Arguments to pass to the task + +Options: + -C, --cd + Change to this directory before executing the command + + -n, --dry-run + Don't actually run the task(s), just print them in order of execution + + -f, --force + Force the task to run even if outputs are up to date + + -p, --prefix + Print stdout/stderr by line, prefixed with the task's label + Defaults to true if --jobs > 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -i, --interleave + Print directly to stdout/stderr instead of by line + Defaults to true if --jobs == 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -t, --tool + Tool(s) to also add e.g.: node@20 python@3.10 + + -j, --jobs + Number of tasks to run in parallel + [default: 4] + Configure with `jobs` config or `RTX_JOBS` env var + + [env: RTX_JOBS=] + + -r, --raw + Read/write directly to stdin/stdout/stderr instead of by line + Configure with `raw` config or `RTX_RAW` env var + +Examples: + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + TODO +``` + ### `rtx trust [OPTIONS] [CONFIG_FILE]` ```text diff --git a/completions/_rtx b/completions/_rtx index 43fcdf348..be6324a37 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -42,10 +42,12 @@ _rtx() { (p|plugin|plugin-list|plugins) __rtx_plugins_cmd && ret=0 ;; (prune) __rtx_prune_cmd && ret=0 ;; (reshim) __rtx_reshim_cmd && ret=0 ;; + (r|run) __rtx_run_cmd && ret=0 ;; (self-update) __rtx_self_update_cmd && ret=0 ;; (settings) __rtx_settings_cmd && ret=0 ;; (sh|shell) __rtx_shell_cmd && ret=0 ;; (sync) __rtx_sync_cmd && ret=0 ;; + (t|tasks|task) __rtx_task_cmd && ret=0 ;; (trust) __rtx_trust_cmd && ret=0 ;; (remove|rm|uninstall) __rtx_uninstall_cmd && ret=0 ;; (up|upgrade) __rtx_upgrade_cmd && ret=0 ;; @@ -525,6 +527,23 @@ __rtx_reshim_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_run_cmd] )) || +__rtx_run_cmd() { + _arguments -s -S \ + ':task:__rtx_tasks' \ + '*::args:' \ + '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ + '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ + '(-f --force)'{-f,--force}'[Force the task to run even if outputs are up to date]' \ + '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the task'\''s label]' \ + '(-i --interleave)'{-i,--interleave}'[Print directly to stdout/stderr instead of by line]' \ + '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ + '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} (( $+functions[__rtx_self_update_cmd] )) || __rtx_self_update_cmd() { _arguments -s -S \ @@ -640,6 +659,64 @@ __rtx_sync_python_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_task_cmd] )) || +__rtx_task_cmd() { + _arguments -s -S \ + '--no-header[Do not print table header]' \ + '--hidden[Show hidden tasks]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '1: :__rtx_task_cmds' \ + '*::arg:->args' && ret=0 + + case "$state" in + (args) + curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + case $words[1] in + (edit) __rtx_task_edit_cmd && ret=0 ;; + (ls) __rtx_task_ls_cmd && ret=0 ;; + (r|run) __rtx_task_run_cmd && ret=0 ;; + esac + ;; + esac + +return ret +} +(( $+functions[__rtx_task_edit_cmd] )) || +__rtx_task_edit_cmd() { + _arguments -s -S \ + ':task:__rtx_tasks' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_task_ls_cmd] )) || +__rtx_task_ls_cmd() { + _arguments -s -S \ + '--no-header[Do not print table header]' \ + '--hidden[Show hidden tasks]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} +(( $+functions[__rtx_task_run_cmd] )) || +__rtx_task_run_cmd() { + _arguments -s -S \ + ':task:__rtx_tasks' \ + '*::args:' \ + '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ + '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ + '(-f --force)'{-f,--force}'[Force the task to run even if outputs are up to date]' \ + '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the task'\''s label]' \ + '(-i --interleave)'{-i,--interleave}'[Print directly to stdout/stderr instead of by line]' \ + '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__rtx_tool_versions' \ + '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ + '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} (( $+functions[__rtx_trust_cmd] )) || __rtx_trust_cmd() { _arguments -s -S \ @@ -741,10 +818,12 @@ __rtx_cmds() { {p,plugins}':Manage plugins' 'prune:Delete unused versions of tools' 'reshim:rebuilds the shim farm' + {r,run}':\[experimental\] Run a task' 'self-update:Updates rtx itself' 'settings:Manage settings' {sh,shell}':Sets a tool version for the current shell session' 'sync:Add tool versions from external tools to rtx' + {t,task}':\[experimental\] Manage tasks' 'trust:Marks a config file as trusted' {remove,rm,uninstall}':Removes runtime versions' {up,upgrade}':Upgrades outdated tool versions' @@ -817,6 +896,15 @@ __rtx_sync_cmds() { ) _describe -t commands 'command' commands "$@" } +(( $+functions[__rtx_task_cmds] )) || +__rtx_task_cmds() { + local commands; commands=( + 'edit:\[experimental\] Edit a task with \$EDITOR' + 'ls:\[experimental\] List config files currently in use' + {r,run}':\[experimental\] Run a task' + ) + _describe -t commands 'command' commands "$@" +} (( $+functions[__rtx_tool_versions] )) || __rtx_tool_versions() { @@ -863,6 +951,11 @@ __rtx_settings() { local -a settings; settings=($(rtx settings ls | awk '{print $1}')) _describe -t settings 'setting' settings "$@" } +(( $+functions[__rtx_tasks] )) || +__rtx_tasks() { + local -a tasks; tasks=($(rtx tasks ls --no-header | awk '{print $1}')) + _describe -t tasks 'task' tasks "$@" +} (( $+functions[__rtx_prefixes] )) || __rtx_prefixes() { if [[ CURRENT -gt 2 ]]; then diff --git a/completions/rtx.bash b/completions/rtx.bash index bcb3560e0..f01ab7ad6 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -114,6 +114,9 @@ _rtx() { rtx,prune) cmd="rtx__prune" ;; + rtx,r) + cmd="rtx__run" + ;; rtx,remove) cmd="rtx__uninstall" ;; @@ -132,6 +135,9 @@ _rtx() { rtx,rm) cmd="rtx__uninstall" ;; + rtx,run) + cmd="rtx__run" + ;; rtx,self-update) cmd="rtx__self__update" ;; @@ -147,6 +153,12 @@ _rtx() { rtx,sync) cmd="rtx__sync" ;; + rtx,t) + cmd="rtx__task" + ;; + rtx,task) + cmd="rtx__task" + ;; rtx,trust) cmd="rtx__trust" ;; @@ -381,6 +393,9 @@ _rtx() { rtx__help,reshim) cmd="rtx__help__reshim" ;; + rtx__help,run) + cmd="rtx__help__run" + ;; rtx__help,self-update) cmd="rtx__help__self__update" ;; @@ -393,6 +408,9 @@ _rtx() { rtx__help,sync) cmd="rtx__help__sync" ;; + rtx__help,task) + cmd="rtx__help__task" + ;; rtx__help,trust) cmd="rtx__help__trust" ;; @@ -480,6 +498,15 @@ _rtx() { rtx__help__sync,python) cmd="rtx__help__sync__python" ;; + rtx__help__task,edit) + cmd="rtx__help__task__edit" + ;; + rtx__help__task,ls) + cmd="rtx__help__task__ls" + ;; + rtx__help__task,run) + cmd="rtx__help__task__run" + ;; rtx__plugins,a) cmd="rtx__plugins__install" ;; @@ -621,6 +648,33 @@ _rtx() { rtx__sync__help,python) cmd="rtx__sync__help__python" ;; + rtx__task,edit) + cmd="rtx__task__edit" + ;; + rtx__task,help) + cmd="rtx__task__help" + ;; + rtx__task,ls) + cmd="rtx__task__ls" + ;; + rtx__task,r) + cmd="rtx__task__run" + ;; + rtx__task,run) + cmd="rtx__task__run" + ;; + rtx__task__help,edit) + cmd="rtx__task__help__edit" + ;; + rtx__task__help,help) + cmd="rtx__task__help__help" + ;; + rtx__task__help,ls) + cmd="rtx__task__help__ls" + ;; + rtx__task__help,run) + cmd="rtx__task__help__run" + ;; *) ;; esac @@ -628,7 +682,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen help" + opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1424,7 +1478,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which render-completion render-help render-mangen help" + opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2095,6 +2149,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__run) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__self__update) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2235,6 +2303,62 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__task) + opts="edit ls run" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__task__edit) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__task__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__help__task__run) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__trust) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2871,6 +2995,48 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__run) + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --tool) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__self__update) opts="-f -y -q -v -h --force --no-plugins --yes --debug --log-level --trace --quiet --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then @@ -3199,6 +3365,172 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__task) + opts="-q -v -y -h --no-header --hidden --debug --log-level --trace --quiet --verbose --yes --help edit ls run help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__edit) + opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__help) + opts="edit ls run help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__help__edit) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__help__ls) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__help__run) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__ls) + opts="-q -v -y -h --no-header --hidden --debug --log-level --trace --quiet --verbose --yes --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rtx__task__run) + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --tool) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -j) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__trust) opts="-a -q -v -y -h --all --untrust --debug --log-level --trace --quiet --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 970d89548..79665743b 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -4,7 +4,7 @@ set -l fssf "__fish_seen_subcommand_from" complete -kxc rtx -s q -l quiet -d 'Suppress non-error messages' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' -set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim self-update settings shell sync trust uninstall upgrade use version where which +set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version where which complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell session' complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' complete -xc rtx -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' @@ -28,10 +28,12 @@ complete -xc rtx -n "not $fssf $others" -a outdated -d 'Shows outdated tool vers complete -xc rtx -n "not $fssf $others" -a plugins -d 'Manage plugins' complete -xc rtx -n "not $fssf $others" -a prune -d 'Delete unused versions of tools' complete -xc rtx -n "not $fssf $others" -a reshim -d 'rebuilds the shim farm' +complete -xc rtx -n "not $fssf $others" -a run -d '[experimental] Run a task' complete -xc rtx -n "not $fssf $others" -a self-update -d 'Updates rtx itself' complete -xc rtx -n "not $fssf $others" -a settings -d 'Manage settings' complete -xc rtx -n "not $fssf $others" -a shell -d 'Sets a tool version for the current shell session' complete -xc rtx -n "not $fssf $others" -a sync -d 'Add tool versions from external tools to rtx' +complete -xc rtx -n "not $fssf $others" -a task -d '[experimental] Manage tasks' complete -xc rtx -n "not $fssf $others" -a trust -d 'Marks a config file as trusted' complete -xc rtx -n "not $fssf $others" -a uninstall -d 'Removes runtime versions' complete -xc rtx -n "not $fssf $others" -a upgrade -d 'Upgrades outdated tool versions' @@ -217,6 +219,18 @@ complete -kxc rtx -n "$fssf prune" -a "(__rtx_plugins)" -d 'Prune only versions # reshim +# run +complete -kxc rtx -n "$fssf run" -d 'Arguments to pass to the task' +complete -kxc rtx -n "$fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' +complete -kxc rtx -n "$fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' +complete -kxc rtx -n "$fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' +complete -kxc rtx -n "$fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' +complete -kxc rtx -n "$fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' +complete -kxc rtx -n "$fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' +complete -kxc rtx -n "$fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' +complete -kxc rtx -n "$fssf run" -a "(__rtx_tasks)" -d 'Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2' +complete -kxc rtx -n "$fssf run" -s t -l tool -a "(__rtx_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' + # self-update complete -kxc rtx -n "$fssf self-update" -s f -l force -d 'Update even if already up to date' complete -kxc rtx -n "$fssf self-update" -l no-plugins -d 'Disable auto-updating plugins' @@ -263,6 +277,34 @@ complete -kxc rtx -n "$fssf sync; and $fssf node" -l nvm -d 'Get tool versions f complete -kxc rtx -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versions from pyenv' +# task +complete -kxc rtx -n "$fssf task" -l hidden -d 'Show hidden tasks' +complete -kxc rtx -n "$fssf task" -l no-header -d 'Do not print table header' +set -l others edit ls run +complete -xc rtx -n "$fssf task; and not $fssf $others" -a edit -d '[experimental] Edit a task with $EDITOR' +complete -xc rtx -n "$fssf task; and not $fssf $others" -a ls -d '[experimental] List config files currently in use' +complete -xc rtx -n "$fssf task; and not $fssf $others" -a run -d '[experimental] Run a task' + +# task edit +complete -kxc rtx -n "$fssf task; and $fssf edit" -a "(__rtx_tasks)" -d 'Task to edit' + +# task ls +complete -kxc rtx -n "$fssf task; and $fssf ls" -l hidden -d 'Show hidden tasks' +complete -kxc rtx -n "$fssf task; and $fssf ls" -l no-header -d 'Do not print table header' + +# task run +complete -kxc rtx -n "$fssf task; and $fssf run" -d 'Arguments to pass to the task' +complete -kxc rtx -n "$fssf task; and $fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' +complete -kxc rtx -n "$fssf task; and $fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' +complete -kxc rtx -n "$fssf task; and $fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' +complete -kxc rtx -n "$fssf task; and $fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' +complete -kxc rtx -n "$fssf task; and $fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' +complete -kxc rtx -n "$fssf task; and $fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' +complete -kxc rtx -n "$fssf task; and $fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' +complete -kxc rtx -n "$fssf task; and $fssf run" -a "(__rtx_tasks)" -d 'Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2' +complete -kxc rtx -n "$fssf task; and $fssf run" -s t -l tool -a "(__rtx_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' + + # trust complete -kxc rtx -n "$fssf trust" -s a -l all -d 'Trust all config files in the current directory and its parents' complete -kxc rtx -n "$fssf trust" -a "(__fish_complete_path)" -d 'The config file to trust' @@ -330,10 +372,7 @@ function __rtx_tool_versions end end function __rtx_installed_tool_versions - if test -z "$__rtx_installed_tool_versions_cache" - set -g __rtx_installed_tool_versions_cache (rtx ls --installed | awk '{print $1 "@" $2}') - end - for tv in $__rtx_installed_tool_versions_cache + for tv in (rtx ls --installed | awk '{print $1 "@" $2}') echo $tv end end @@ -345,6 +384,11 @@ function __rtx_aliases echo $a end end +function __rtx_tasks + for tv in (rtx task ls --no-header | awk '{print $1}') + echo $tv + end +end function __rtx_settings if test -z "$__rtx_settings_cache" set -g __rtx_settings_cache (rtx settings ls | awk '{print $1}') diff --git a/justfile b/justfile index f6dd4ece7..13a13855c 100644 --- a/justfile +++ b/justfile @@ -70,7 +70,8 @@ test-coverage: rtx implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then echo "::group::Self update" - rtx self-update -fy + # TODO: remove this once the task runnner is shipped + rtx self-update -fy || true fi echo "::group::Render lcov report" cargo llvm-cov report --lcov --output-path lcov.info diff --git a/schema/rtx.json b/schema/rtx.json index 1f11a6e79..8bcad0e49 100644 --- a/schema/rtx.json +++ b/schema/rtx.json @@ -6,6 +6,11 @@ "type": "object", "additionalProperties": false, "properties": { + "min_version": { + "description": "minimum version of rtx required to use this config", + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$" + }, "env_file": { "description": "path to .env file", "type": "string" @@ -49,6 +54,11 @@ ] } }, + "tasks": { + "description": "task runner tasks", + "type": "object", + "additionalProperties": { "$ref": "#/$defs/task" } + }, "plugins": { "description": "plugins to use", "type": "object", @@ -92,6 +102,101 @@ } ] }, + "task": { + "oneOf": [ + { + "type": "string", + "description": "script to run" + }, + { + "description": "script to run", + "type": "array", + "items": { + "description": "script to run", + "type": "string" + } + }, + { + "type": "object", + "properties": { + "run": { + "oneOf": [ + { + "description": "script to run", + "type": "string" + }, + { + "description": "script to run", + "type": "array", + "items": { + "description": "script to run", + "type": "string" + } + } + ] + }, + "depends": { + "description": "other tasks to run before this task", + "type": "array", + "items": { + "description": "task to run before this task", + "type": "string" + } + }, + "alias": { + "oneOf": [ + { + "description": "alias for this task", + "type": "string" + }, + { + "description": "alias for this task", + "type": "array", + "items": { + "description": "alias for this task", + "type": "string" + } + } + ] + }, + "dir": { + "description": "directory to run script in, default is current working directory", + "type": "string" + }, + "env": { + "description": "environment variables", + "type": "object", + "additionalProperties": { "type": "string" } + }, + "quiet": { + "description": "do not display rtx information for this task", + "type": "boolean" + }, + "raw": { + "description": "directly connect task to stdin/stdout/stderr", + "type": "boolean" + }, + "sources": { + "description": "files that this task depends on", + "type": "array", + "items": { + "description": "glob pattern for files that this task depends on", + "type": "string" + } + }, + "outputs": { + "description": "files created by this task", + "type": "array", + "items": { + "description": "glob pattern for files created by this task", + "type": "string" + } + } + }, + "additionalProperties": false + } + ] + }, "settings": { "description": "settings for rtx", "type": "object", @@ -176,6 +281,12 @@ "yes": { "description": "assume yes for all prompts", "type": "boolean" + }, + "task_output": { + "description": "how to display task output", + "type": "string", + "default": "prefix", + "enum": ["prefix", "interleave"] } } } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 478d4d2b1..a5cbc621a 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -1,10 +1,9 @@ -use color_eyre::eyre::{eyre, Result}; -use console::style; +use eyre::Result; use crate::config::Config; use crate::hook_env; - use crate::shell::get_shell; +use crate::ui::style; /// Disable rtx for current shell session /// @@ -36,7 +35,7 @@ fn err_inactive() -> Result<()> { rtx is not activated in this shell session. Please run `{}` first in your shell rc file. "#, - style("rtx activate").yellow() + style::eyellow("rtx activate") ))) } diff --git a/src/cli/implode.rs b/src/cli/implode.rs index d768e7bfa..0f5b60064 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -53,7 +53,7 @@ impl Implode { } else if settings.yes { Ok(true) } else { - let r = prompt::confirm(&format!("remove {} ?", f.display()))?; + let r = prompt::confirm(format!("remove {} ?", f.display()))?; Ok(r) } } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 46bd9b98b..211d3e3df 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -39,10 +39,12 @@ mod render_help; #[cfg(feature = "clap_mangen")] mod render_mangen; mod reshim; +mod run; mod self_update; mod settings; mod shell; mod sync; +mod task; mod trust; mod uninstall; mod upgrade; @@ -82,10 +84,12 @@ pub enum Commands { Plugins(plugins::Plugins), Prune(prune::Prune), Reshim(reshim::Reshim), + Run(run::Run), SelfUpdate(self_update::SelfUpdate), Settings(settings::Settings), Shell(shell::Shell), Sync(sync::Sync), + Task(task::Task), Trust(trust::Trust), Uninstall(uninstall::Uninstall), Upgrade(upgrade::Upgrade), @@ -134,10 +138,12 @@ impl Commands { Self::Plugins(cmd) => cmd.run(), Self::Prune(cmd) => cmd.run(), Self::Reshim(cmd) => cmd.run(), + Self::Run(cmd) => cmd.run(), Self::SelfUpdate(cmd) => cmd.run(), Self::Settings(cmd) => cmd.run(), Self::Shell(cmd) => cmd.run(), Self::Sync(cmd) => cmd.run(), + Self::Task(cmd) => cmd.run(), Self::Trust(cmd) => cmd.run(), Self::Uninstall(cmd) => cmd.run(), Self::Upgrade(cmd) => cmd.run(), diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index bbf7a8d92..8360eb147 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,10 +1,9 @@ -use console::style; use eyre::Result; use crate::config::Config; - use crate::plugins::unalias_plugin; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::style; /// Removes a plugin #[derive(Debug, clap::Args)] @@ -51,7 +50,7 @@ impl PluginsUninstall { ) -> Result<()> { match config.get_or_create_plugin(plugin_name) { plugin if plugin.is_installed() => { - let prefix = format!("plugin:{}", style(&plugin.name()).blue().for_stderr()); + let prefix = format!("plugin:{}", style::eblue(&plugin.name())); let pr = mpr.add(&prefix); plugin.uninstall(pr.as_ref())?; if self.purge { @@ -59,10 +58,7 @@ impl PluginsUninstall { } pr.finish_with_message("uninstalled".into()); } - _ => warn!( - "{} is not installed", - style(plugin_name).blue().for_stderr() - ), + _ => warn!("{} is not installed", style::eblue(plugin_name)), } Ok(()) } diff --git a/src/cli/run.rs b/src/cli/run.rs new file mode 100644 index 000000000..bfeeabd07 --- /dev/null +++ b/src/cli/run.rs @@ -0,0 +1,510 @@ +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::io::Write; +use std::iter::once; +use std::os::unix::prelude::ExitStatusExt; +use std::path::{Path, PathBuf}; +use std::process::{exit, Stdio}; +use std::str::FromStr; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{mpsc, Mutex}; +use std::time::SystemTime; + +use clap::ValueHint; +use console::{style, Color}; +use duct::IntoExecutablePath; +use eyre::Result; +use globwalk::GlobWalkerBuilder; +use itertools::Itertools; +use once_cell::sync::Lazy; +use petgraph::graph::DiGraph; +use petgraph::Direction; + +use crate::cli::args::tool::{ToolArg, ToolArgParser}; +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; +use crate::errors::Error; +use crate::errors::Error::ScriptFailed; +use crate::file::display_path; +use crate::task::Task; +use crate::toolset::{InstallOptions, ToolsetBuilder}; +use crate::ui::style; +use crate::{env, file, ui}; + +/// [experimental] Run a task +#[derive(Debug, clap::Args)] +#[clap(visible_alias = "r", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct Run { + /// Task to run + /// Can specify multiple tasks by separating with `:::` + /// e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2 + pub task: String, + + /// Arguments to pass to the task + #[clap()] + pub args: Vec, + + /// Change to this directory before executing the command + #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)] + pub cd: Option, + + /// Don't actually run the task(s), just print them in order of execution + #[clap(long, short = 'n', verbatim_doc_comment)] + pub dry_run: bool, + + /// Force the task to run even if outputs are up to date + #[clap(long, short, verbatim_doc_comment)] + pub force: bool, + + /// Print stdout/stderr by line, prefixed with the task's label + /// Defaults to true if --jobs > 1 + /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + #[clap(long, short, verbatim_doc_comment, overrides_with = "interleave")] + pub prefix: bool, + + /// Print directly to stdout/stderr instead of by line + /// Defaults to true if --jobs == 1 + /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + #[clap(long, short, verbatim_doc_comment, overrides_with = "prefix")] + pub interleave: bool, + + /// Tool(s) to also add + /// e.g.: node@20 python@3.10 + #[clap(short, long, value_name = "TOOL@VERSION", value_parser = ToolArgParser)] + pub tool: Vec, + + /// Number of tasks to run in parallel + /// [default: 4] + /// Configure with `jobs` config or `RTX_JOBS` env var + #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + pub jobs: Option, + + /// Read/write directly to stdin/stdout/stderr instead of by line + /// Configure with `raw` config or `RTX_RAW` env var + #[clap(long, short, verbatim_doc_comment)] + pub raw: bool, +} + +impl Run { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let settings = Settings::try_get()?; + settings.ensure_experimental()?; + let task_list = self.get_task_lists(&config)?; + self.parallelize_tasks(&config, task_list) + } + + fn get_task_lists(&self, config: &Config) -> Result> { + once(&self.task) + .chain(self.args.iter()) + .map(|s| vec![s.to_string()]) + .coalesce(|a, b| { + if b == vec![":::".to_string()] { + Err((a, b)) + } else if a == vec![":::".to_string()] { + Ok(b) + } else { + Ok(a.into_iter().chain(b).collect_vec()) + } + }) + .flat_map(|args| args.split_first().map(|(t, a)| (t.clone(), a.to_vec()))) + .map(|(t, args)| match config.tasks().get(&t) { + Some(task) => Ok(task.clone().with_args(args.to_vec())), + None => Err(self.err_no_task(config, &t)), + }) + .collect() + } + + fn parallelize_tasks(self, config: &Config, tasks: Vec) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; + + ts.install_arg_versions(config, &InstallOptions::new())?; + ts.notify_if_versions_missing(); + let mut env = ts.env_with_path(config); + if let Some(root) = &config.project_root { + env.insert("RTX_PROJECT_ROOT".into(), root.display().to_string()); + } + + let tasks = Mutex::new(Deps::new(config, tasks)?); + + for task in tasks.lock().unwrap().all() { + self.validate_task(task)?; + } + + let pool = rayon::ThreadPoolBuilder::new() + .num_threads(self.jobs() + 1) + .build()?; + pool.scope(|s| { + let run = |task: &Task| { + let t = task.clone(); + s.spawn(|_| { + let task = t; + trace!("running task: {task}"); + if let Err(err) = self.run_task(config, &env, &task) { + error!("{err}"); + exit(1); + } + let mut tasks = tasks.lock().unwrap(); + tasks.remove(&task); + }); + }; + let rx = tasks.lock().unwrap().subscribe(); + while let Some(task) = rx.recv().unwrap() { + run(&task); + } + }); + Ok(()) + } + + fn run_task(&self, config: &Config, env: &BTreeMap, task: &Task) -> Result<()> { + if self.dry_run { + return Ok(()); + } + let prefix = style::estyle(task.prefix()).fg(get_color()).to_string(); + if !self.force && self.sources_are_fresh(config, task) { + info_unprefix_trunc!("{prefix} sources up-to-date, skipping"); + return Ok(()); + } + + let env: BTreeMap = env + .iter() + .chain(task.env.iter()) + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + + if let Some(file) = &task.file { + self.exec_file(file, task, &env, &prefix)?; + } else { + for (i, cmd) in task.run.iter().enumerate() { + let args = match i == task.run.len() - 1 { + true => task.args.iter().cloned().collect_vec(), + false => vec![], + }; + self.exec_script(cmd, &args, task, &env, &prefix)?; + } + } + + self.save_checksum(task)?; + + Ok(()) + } + + fn exec_script( + &self, + script: &str, + args: &[String], + task: &Task, + env: &BTreeMap, + prefix: &str, + ) -> Result<()> { + let script = format!("{} {}", script, shell_words::join(args)); + let cmd = style::ebold(format!("$ {script}")).bright().to_string(); + info_unprefix_trunc!("{prefix} {cmd}"); + + if env::var("RTX_TASK_SCRIPT_FILE").is_ok() { + let mut tmp = tempfile::NamedTempFile::new()?; + let args = once(tmp.path().display().to_string()) + .chain(args.iter().cloned()) + .collect_vec(); + writeln!(tmp, "{}", script.trim())?; + self.exec("sh", &args, task, env, prefix) + } else { + let args = vec!["-c".to_string(), script.trim().to_string()]; + self.exec("sh", &args, task, env, prefix) + } + } + + fn exec_file( + &self, + file: &Path, + task: &Task, + env: &BTreeMap, + prefix: &str, + ) -> Result<()> { + let command = file.to_string_lossy().to_string(); + let args = task.args.iter().cloned().collect_vec(); + + let cmd = format!("{} {}", display_path(file), args.join(" ")); + let cmd = style::ebold(format!("$ {cmd}")).bright().to_string(); + info_unprefix_trunc!("{prefix} {cmd}"); + + self.exec(&command, &args, task, env, prefix) + } + + fn exec( + &self, + program: &str, + args: &[String], + task: &Task, + env: &BTreeMap, + prefix: &str, + ) -> Result<()> { + let program = program.to_executable(); + let mut cmd = CmdLineRunner::new(program.clone()).args(args).envs(env); + match &self.output(task) { + TaskOutput::Prefix => cmd = cmd.prefix(format!("{prefix} ")), + TaskOutput::Interleave => cmd = cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit()), + } + if self.raw(task) { + cmd.with_raw(); + } + if let Some(cd) = &self.cd.as_ref().or(task.dir.as_ref()) { + cmd = cmd.current_dir(cd); + } + if let Err(err) = cmd.execute() { + if let Some(ScriptFailed(_, Some(status))) = err.downcast_ref::() { + if let Some(code) = status.code() { + error!("{prefix} exited with code {code}"); + exit(code); + } else if let Some(signal) = status.signal() { + error!("{prefix} killed by signal {signal}"); + exit(1); + } + } + error!("{err}"); + exit(1); + } + trace!("{prefix} exited successfully"); + Ok(()) + } + + fn output(&self, task: &Task) -> TaskOutput { + let settings = Settings::get(); + if self.prefix { + TaskOutput::Prefix + } else if self.interleave { + TaskOutput::Interleave + } else if let Some(output) = &settings.task_output { + TaskOutput::from_str(output).unwrap() + } else if self.raw(task) || self.jobs() == 1 { + TaskOutput::Interleave + } else { + TaskOutput::Prefix + } + } + + fn raw(&self, task: &Task) -> bool { + self.raw || task.raw || Settings::get().raw + } + + fn jobs(&self) -> usize { + if self.raw { + 1 + } else { + self.jobs.unwrap_or(Settings::get().jobs) + } + } + + fn err_no_task(&self, config: &Config, t: &str) -> eyre::Report { + let tasks = config.tasks(); + let task_names = tasks.keys().sorted().map(style::ecyan).join(", "); + let t = style(&t).yellow().for_stderr(); + eyre!("no task named `{t}` found. Available tasks: {task_names}") + } + fn validate_task(&self, task: &Task) -> Result<()> { + if let Some(path) = &task.file { + if !file::is_executable(path) { + let dp = display_path(path); + let msg = format!("Script `{dp}` is not executable. Make it executable?"); + if ui::confirm(msg)? { + file::make_executable(path)?; + } else { + bail!("`{dp}` is not executable") + } + } + } + Ok(()) + } + + fn sources_are_fresh(&self, config: &Config, task: &Task) -> bool { + let run = || -> Result { + let sources = self.get_last_modified(&self.cwd(config, task), &task.sources)?; + let outputs = self.get_last_modified(&self.cwd(config, task), &task.outputs)?; + trace!("sources: {sources:?}, outputs: {outputs:?}",); + match (sources, outputs) { + (Some(sources), Some(outputs)) => Ok(sources < outputs), + _ => Ok(false), + } + }; + run().unwrap_or_else(|err| { + warn!("sources_are_fresh: {err}"); + false + }) + } + + fn get_last_modified(&self, root: &Path, globs: &[String]) -> Result> { + let last_mod = GlobWalkerBuilder::from_patterns(root, globs) + .follow_links(true) + .build()? + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_file()) + .map(|e| e.path().to_owned()) + .unique() + .map(|p| p.metadata().map_err(|err| eyre!(err))) + .collect::>>()? + .into_iter() + .map(|m| m.modified().map_err(|err| eyre!(err))) + .collect::>>()? + .into_iter() + .max(); + trace!("last_modified of {}: {last_mod:?}", globs.join(" ")); + Ok(last_mod) + } + + fn cwd(&self, config: &Config, task: &Task) -> PathBuf { + self.cd + .as_ref() + .or(task.dir.as_ref()) + .cloned() + .or_else(|| config.project_root.clone()) + .unwrap_or_else(|| env::PWD.clone()) + } + + fn save_checksum(&self, task: &Task) -> Result<()> { + if task.sources.is_empty() { + return Ok(()); + } + // TODO + Ok(()) + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + TODO +"# +); + +#[derive(Debug)] +struct Deps { + graph: DiGraph, + sent: HashSet, + tx: mpsc::Sender>, +} + +impl Deps { + fn new(config: &Config, tasks: Vec) -> Result { + let mut graph = DiGraph::new(); + let mut indexes = HashMap::new(); + let mut stack = vec![]; + for t in tasks { + stack.push(t.clone()); + indexes + .entry(t.name.clone()) + .or_insert_with(|| graph.add_node(t)); + } + while let Some(a) = stack.pop() { + let a_idx = *indexes + .entry(a.name.clone()) + .or_insert_with(|| graph.add_node(a.clone())); + for b in a.resolve_depends(config)? { + let b_idx = *indexes + .entry(b.name.clone()) + .or_insert_with(|| graph.add_node(b.clone())); + graph.add_edge(a_idx, b_idx, ()); + stack.push(b.clone()); + } + } + let (tx, _) = mpsc::channel(); + let sent = HashSet::new(); + Ok(Self { graph, tx, sent }) + } + + fn leaves(&self) -> Vec { + self.graph + .externals(Direction::Outgoing) + .map(|idx| self.graph[idx].clone()) + .collect() + } + + fn emit_leaves(&mut self) { + let leaves = self.leaves().into_iter().collect_vec(); + for task in leaves { + if self.sent.contains(&task.name) { + continue; + } + self.sent.insert(task.name.clone()); + self.tx.send(Some(task)).unwrap(); + } + if self.graph.node_count() == 0 { + self.tx.send(None).unwrap(); + } + } + + fn subscribe(&mut self) -> mpsc::Receiver> { + let (tx, rx) = mpsc::channel(); + self.tx = tx; + self.emit_leaves(); + rx + } + + // #[requires(self.graph.node_count() > 0)] + // #[ensures(self.graph.node_count() == old(self.graph.node_count()) - 1)] + fn remove(&mut self, task: &Task) { + if let Some(idx) = self + .graph + .node_indices() + .find(|&idx| &self.graph[idx] == task) + { + self.graph.remove_node(idx); + self.emit_leaves(); + } + } + + fn all(&self) -> impl Iterator { + self.graph.node_indices().map(|idx| &self.graph[idx]) + } + + // fn pop(&'a mut self) -> Option<&'a Task> { + // if let Some(leaf) = self.leaves().first() { + // self.remove(&leaf.clone()) + // } else { + // None + // } + // } +} + +#[derive(Debug, PartialEq, EnumString)] +enum TaskOutput { + Prefix, + Interleave, +} + +fn get_color() -> Color { + static COLORS: Lazy> = Lazy::new(|| { + vec![ + Color::Blue, + Color::Magenta, + Color::Cyan, + Color::Green, + Color::Yellow, + Color::Red, + ] + }); + static COLOR_IDX: AtomicUsize = AtomicUsize::new(0); + COLORS[COLOR_IDX.fetch_add(1, Ordering::Relaxed) % COLORS.len()] +} + +#[cfg(test)] +mod tests { + use crate::file; + + #[test] + fn test_task_run() { + file::remove_all("test-build-output.txt").unwrap(); + assert_cli_snapshot!( + "r", + "filetask", + "arg1", + "arg2", + ":::", + "configtask", + "arg3", + "arg4" + , @""); + let body = file::read_to_string("test-build-output.txt").unwrap(); + assert_snapshot!(body, @r###" + TEST_BUILDSCRIPT_ENV_VAR: VALID + "###); + } +} diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 28f158eb9..d286b64ea 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -16,6 +16,7 @@ plugin_autoupdate_last_check_duration = "20m" quiet = false raw = false shorthands_file = null +task_output = null trusted_config_paths = [] verbose = true yes = true diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index cc490dd07..c3c33295e 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -16,6 +16,7 @@ plugin_autoupdate_last_check_duration = "1m" quiet = false raw = false shorthands_file = null +task_output = null trusted_config_paths = [] verbose = true yes = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index aa00a7ce1..787750cc4 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -54,6 +54,7 @@ mod tests { quiet = false raw = false shorthands_file = null + task_output = null trusted_config_paths = [] verbose = true yes = true diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs new file mode 100644 index 000000000..94d82269c --- /dev/null +++ b/src/cli/task/edit.rs @@ -0,0 +1,44 @@ +use eyre::Result; + +use crate::config::{Config, Settings}; +use crate::task::Task; +use crate::{env, file}; + +/// [experimental] Edit a task with $EDITOR +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment)] +pub struct TaskEdit { + /// Task to edit + #[clap()] + task: String, +} + +impl TaskEdit { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let settings = Settings::try_get()?; + settings.ensure_experimental()?; + + let task = config.tasks().get(&self.task).cloned().map_or_else( + || { + let path = config + .project_root + .as_ref() + .unwrap_or(&env::PWD) + .join(".rtx") + .join("tasks") + .join(&self.task); + Task::from_path(path) + }, + Ok, + )?; + let file = &task.config_source; + if !file.exists() { + file::create(file)?; + file::make_executable(file)?; + } + cmd!(&*env::EDITOR, &file).run()?; + + Ok(()) + } +} diff --git a/src/cli/task/ls.rs b/src/cli/task/ls.rs new file mode 100644 index 000000000..fa2df8728 --- /dev/null +++ b/src/cli/task/ls.rs @@ -0,0 +1,96 @@ +use crate::task::Task; +use console::truncate_str; +use eyre::Result; +use itertools::Itertools; + +use tabled::Tabled; + +use crate::config::{Config, Settings}; +use crate::file::display_path; +use crate::ui::{style, table}; + +/// [experimental] List config files currently in use +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct TaskLs { + /// Do not print table header + #[clap(long, alias = "no-headers", verbatim_doc_comment)] + pub no_header: bool, + + /// Show hidden tasks + #[clap(long, verbatim_doc_comment)] + pub hidden: bool, +} + +impl TaskLs { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let settings = Settings::try_get()?; + settings.ensure_experimental()?; + let rows = config + .tasks() + .iter() + .filter(|(n, t)| *n == &t.name) // filter out aliases + .map(|(_, t)| t) + .sorted() + .filter(|t| self.hidden || !t.hide) + .map(|t| t.into()) + .collect::>(); + let mut table = tabled::Table::new(rows); + table::default_style(&mut table, self.no_header); + rtxprintln!("{table}"); + + Ok(()) + } +} + +#[derive(Tabled)] +#[tabled(rename_all = "PascalCase")] +struct Row { + name: String, + description: String, + // command: String, + source: String, +} + +impl From<&Task> for Row { + fn from(task: &Task) -> Self { + // let cmd = task.command_string().unwrap_or_default(); + Self { + name: style::nbold(&task.name).bright().to_string(), + description: style::nblue(truncate(&task.description, 40)).to_string(), + // command: style::ndim(truncate(&cmd, 20)).dim().to_string(), + source: display_path(&task.config_source), + } + } +} + +fn first_line(s: &str) -> &str { + s.lines().next().unwrap_or_default() +} + +fn truncate(s: &str, len: usize) -> String { + first_line(&truncate_str(s, len, "…")).to_string() +} + +// TODO: fill this out +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx task ls +"# +); + +#[cfg(test)] +mod tests { + use std::env; + + #[test] + fn test_task_ls() { + assert_cli_snapshot!("t", "--no-headers", @r###" + configtask ~/config/config.toml + filetask This is a test build script ~/cwd/.rtx/tasks/filetask + lint ~/config/config.toml + test ~/config/config.toml + "###); + } +} diff --git a/src/cli/task/mod.rs b/src/cli/task/mod.rs new file mode 100644 index 000000000..81903df55 --- /dev/null +++ b/src/cli/task/mod.rs @@ -0,0 +1,42 @@ +use crate::cli::run; +use clap::Subcommand; +use eyre::Result; + +mod edit; +mod ls; + +/// [experimental] Manage tasks +#[derive(Debug, clap::Args)] +#[clap(visible_alias = "t", alias = "tasks", verbatim_doc_comment)] +pub struct Task { + #[clap(subcommand)] + command: Option, + + #[clap(flatten)] + ls: ls::TaskLs, +} + +#[derive(Debug, Subcommand)] +enum Commands { + Edit(edit::TaskEdit), + Ls(ls::TaskLs), + Run(run::Run), +} + +impl Commands { + pub fn run(self) -> Result<()> { + match self { + Self::Edit(cmd) => cmd.run(), + Self::Ls(cmd) => cmd.run(), + Self::Run(cmd) => cmd.run(), + } + } +} + +impl Task { + pub fn run(self) -> Result<()> { + let cmd = self.command.unwrap_or(Commands::Ls(self.ls)); + + cmd.run() + } +} diff --git a/src/cmd.rs b/src/cmd.rs index cefc3d6d6..3a36d6e76 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -4,6 +4,7 @@ use std::io::{BufRead, BufReader, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Stdio}; use std::sync::mpsc::channel; +use std::sync::{Mutex, RwLock}; use std::thread; use crate::config::Settings; @@ -92,8 +93,12 @@ pub struct CmdLineRunner<'a> { cmd: Command, pr: Option<&'a dyn SingleReport>, stdin: Option, + prefix: String, + raw: bool, } +static OUTPUT_LOCK: Mutex<()> = Mutex::new(()); + impl<'a> CmdLineRunner<'a> { pub fn new>(program: P) -> Self { let mut cmd = Command::new(program); @@ -105,9 +110,26 @@ impl<'a> CmdLineRunner<'a> { cmd, pr: None, stdin: None, + prefix: String::new(), + raw: false, } } + pub fn stdout>(mut self, cfg: T) -> Self { + self.cmd.stdout(cfg); + self + } + + pub fn stderr>(mut self, cfg: T) -> Self { + self.cmd.stderr(cfg); + self + } + + pub fn prefix(mut self, prefix: impl Into) -> Self { + self.prefix = prefix.into(); + self + } + pub fn current_dir>(mut self, dir: P) -> Self { self.cmd.current_dir(dir); self @@ -175,6 +197,10 @@ impl<'a> CmdLineRunner<'a> { self.pr = Some(pr); self } + pub fn with_raw(&mut self) -> &mut Self { + self.raw = true; + self + } pub fn stdin_string(mut self, input: impl Into) -> Self { self.cmd.stdin(Stdio::piped()); @@ -183,38 +209,44 @@ impl<'a> CmdLineRunner<'a> { } pub fn execute(mut self) -> Result<()> { + static RAW_LOCK: RwLock<()> = RwLock::new(()); + let read_lock = RAW_LOCK.read().unwrap(); let settings = &Settings::try_get()?; debug!("$ {}", self); - if settings.raw { + if settings.raw || self.raw { + drop(read_lock); + let _write_lock = RAW_LOCK.write().unwrap(); return self.execute_raw(); } let mut cp = self .cmd .spawn() .wrap_err_with(|| format!("failed to execute command: {self}"))?; - let stdout = BufReader::new(cp.stdout.take().unwrap()); - let stderr = BufReader::new(cp.stderr.take().unwrap()); let (tx, rx) = channel(); - thread::spawn({ - let tx = tx.clone(); - move || { - for line in stdout.lines() { - let line = line.unwrap(); - tx.send(ChildProcessOutput::Stdout(line)).unwrap(); + if let Some(stdout) = cp.stdout.take() { + thread::spawn({ + let tx = tx.clone(); + move || { + for line in BufReader::new(stdout).lines() { + let line = line.unwrap(); + tx.send(ChildProcessOutput::Stdout(line)).unwrap(); + } + tx.send(ChildProcessOutput::Done).unwrap(); } - tx.send(ChildProcessOutput::Done).unwrap(); - } - }); - thread::spawn({ - let tx = tx.clone(); - move || { - for line in stderr.lines() { - let line = line.unwrap(); - tx.send(ChildProcessOutput::Stderr(line)).unwrap(); + }); + } + if let Some(stderr) = cp.stderr.take() { + thread::spawn({ + let tx = tx.clone(); + move || { + for line in BufReader::new(stderr).lines() { + let line = line.unwrap(); + tx.send(ChildProcessOutput::Stderr(line)).unwrap(); + } + tx.send(ChildProcessOutput::Done).unwrap(); } - tx.send(ChildProcessOutput::Done).unwrap(); - } - }); + }); + } if let Some(text) = self.stdin.take() { let mut stdin = cp.stdin.take().unwrap(); thread::spawn(move || { @@ -268,19 +300,25 @@ impl<'a> CmdLineRunner<'a> { } fn on_stdout(&self, line: &str) { - if !line.trim().is_empty() { - if let Some(pr) = self.pr { + let _lock = OUTPUT_LOCK.lock().unwrap(); + if let Some(pr) = self.pr { + if !line.trim().is_empty() { pr.set_message(line.into()) } + } else { + println!("{}{}", self.prefix, line); } } fn on_stderr(&self, line: &str) { - if !line.trim().is_empty() { - match self.pr { - Some(pr) => pr.println(line.into()), - None => eprintln!("{}", line), + let _lock = OUTPUT_LOCK.lock().unwrap(); + match self.pr { + Some(pr) => { + if !line.trim().is_empty() { + pr.println(line.into()) + } } + None => eprintln!("{}{}", self.prefix, line), } } @@ -294,7 +332,7 @@ impl<'a> CmdLineRunner<'a> { } } None => { - eprintln!("{}", output); + // eprintln!("{}", output); } } Err(ScriptFailed(self.get_program(), Some(status)))? diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 3e1bed2cd..e81121d46 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::fmt::{Debug, Display}; +use std::hash::Hash; use std::path::{Path, PathBuf}; use color_eyre::eyre::{eyre, Result}; @@ -15,11 +16,13 @@ use crate::file::{display_path, replace_path}; use crate::hash::hash_to_str; use crate::plugins::PluginName; +use crate::task::Task; use crate::toolset::{ToolVersionList, Toolset}; use crate::{dirs, env, file}; pub mod legacy_version; pub mod rtx_toml; +pub mod toml; pub mod tool_versions; #[derive(Debug, PartialEq)] @@ -32,6 +35,25 @@ pub enum ConfigFileType { pub trait ConfigFile: Debug + Send + Sync { fn get_type(&self) -> ConfigFileType; fn get_path(&self) -> &Path; + /// gets the project directory for the config + /// if it's a global/system config, returns None + /// files like ~/src/foo/.rtx/config.toml will return ~/src/foo + /// and ~/src/foo/.rtx.config.toml will return None + fn project_root(&self) -> Option<&Path> { + let p = self.get_path(); + if env::RTX_CONFIG_FILE.as_ref().is_some_and(|f| f == p) { + return None; + } + match p.parent() { + Some(dir) => match dir { + dir if dir.starts_with(*dirs::CONFIG) => None, + dir if dir.starts_with(*dirs::SYSTEM) => None, + dir if dir == *dirs::HOME => None, + dir => Some(dir), + }, + None => None, + } + } fn plugins(&self) -> HashMap { Default::default() } @@ -41,7 +63,10 @@ pub trait ConfigFile: Debug + Send + Sync { fn env_remove(&self) -> Vec { Default::default() } - fn path_dirs(&self) -> Vec { + fn env_path(&self) -> Vec { + Default::default() + } + fn tasks(&self) -> Vec<&Task> { Default::default() } fn remove_plugin(&mut self, _plugin_name: &PluginName); @@ -222,6 +247,18 @@ impl Display for dyn ConfigFile { } } +impl PartialEq for dyn ConfigFile { + fn eq(&self, other: &Self) -> bool { + self.get_path() == other.get_path() + } +} +impl Eq for dyn ConfigFile {} +impl Hash for dyn ConfigFile { + fn hash(&self, state: &mut H) { + self.get_path().hash(state); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 70b8386bb..4ea7b8cd5 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -6,7 +6,6 @@ use std::sync::Mutex; use color_eyre::eyre::eyre; use color_eyre::{Result, Section}; use confique::Partial; -use console::style; use eyre::WrapErr; use tera::Context; use toml_edit::{table, value, Array, Document, Item, Table, Value}; @@ -17,11 +16,12 @@ use crate::config::{config_file, AliasMap}; use crate::errors::Error::UntrustedConfig; use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; +use crate::task::Task; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, }; -use crate::ui::prompt; +use crate::ui::{prompt, style}; use crate::{dirs, env, file, parse_error}; #[derive(Default)] @@ -37,6 +37,7 @@ pub struct RtxToml { alias: AliasMap, doc: Document, plugins: HashMap, + tasks: Vec, is_trusted: Mutex>, } @@ -77,7 +78,8 @@ impl RtxToml { "tools" => self.toolset = self.parse_toolset(k, v)?, "settings" => self.settings = self.parse_settings(k, v)?, "plugins" => self.plugins = self.parse_plugins(k, v)?, - _ => bail!("unknown key: {}", style(k).red().for_stderr()), + "tasks" => self.tasks = self.parse_tasks(k, v)?, + _ => bail!("unknown key: {}", style::ered(k)), } } self.doc = doc; @@ -195,6 +197,57 @@ impl RtxToml { self.parse_hashmap(key, v) } + fn parse_tasks(&self, key: &str, v: &Item) -> Result> { + match v.as_table_like() { + Some(table) => { + let mut tasks = Vec::new(); + for (name, v) in table.iter() { + let k = format!("{}.{}", key, name); + let name = self.parse_template(&k, name)?; + let task = self.parse_task(&k, v, &name)?; + tasks.push(task); + } + Ok(tasks) + } + _ => parse_error!(key, v, "table"), + } + } + + fn parse_task(&self, key: &str, v: &Item, name: &str) -> Result { + let mut task = Task::new(name.into(), self.path.clone()); + if v.as_str().is_some() { + task.run = self.parse_string_or_array(key, v)?; + return Ok(task); + } + match v.as_table_like() { + Some(table) => { + let mut task = Task::new(name.into(), self.path.clone()); + for (k, v) in table.iter() { + let key = format!("{key}.{k}"); + match k { + "alias" => task.aliases = self.parse_string_or_array(&key, v)?, + // "args" => task.args = self.parse_string_array(&key, v)?, + "run" => task.run = self.parse_string_or_array(&key, v)?, + // "command" => task.command = Some(self.parse_string_tmpl(&key, v)?), + "depends" => task.depends = self.parse_string_array(&key, v)?, + "description" => task.description = self.parse_string(&key, v)?, + "env" => task.env = self.parse_hashmap(&key, v)?, + "file" => task.file = Some(self.parse_path(&key, v)?), + "hide" => task.hide = self.parse_bool(&key, v)?, + "dir" => task.dir = Some(self.parse_path(&key, v)?), + "outputs" => task.outputs = self.parse_string_array(&key, v)?, + "raw" => task.raw = self.parse_bool(&key, v)?, + // "script" => task.script = Some(self.parse_string_tmpl(&key, v)?), + "sources" => task.sources = self.parse_string_array(&key, v)?, + _ => parse_error!(key, v, "task property"), + } + } + Ok(task) + } + _ => parse_error!(key, v, "table"), + } + } + fn parse_hashmap(&self, key: &str, v: &Item) -> Result> { match v.as_table_like() { Some(table) => { @@ -451,7 +504,17 @@ impl RtxToml { } } - fn parse_string_array(&self, k: &String, v: &Item) -> Result> { + fn parse_string_or_array(&self, k: &str, v: &Item) -> Result> { + match v.as_value().map(|v| v.as_str()) { + Some(Some(v)) => { + let v = self.parse_template(k, v)?; + Ok(vec![v]) + } + _ => self.parse_string_array(k, v), + } + } + + fn parse_string_array(&self, k: &str, v: &Item) -> Result> { match v .as_array() .map(|v| v.iter().map(|v| v.as_str().unwrap().to_string()).collect()) @@ -548,10 +611,10 @@ impl RtxToml { return Ok(()); } if cmd != "hook-env" { - let ans = prompt::confirm(&format!( + let ans = prompt::confirm(format!( "{} {} is not trusted. Trust it?", - style("rtx").yellow().for_stderr(), - display_path(&self.path) + style::eyellow("rtx"), + style::epath(&self.path) ))?; if ans { config_file::trust(self.path.as_path())?; @@ -581,6 +644,24 @@ impl ConfigFile for RtxToml { self.path.as_path() } + fn project_root(&self) -> Option<&Path> { + let fp = self.get_path(); + let filename = fp.file_name().unwrap_or_default().to_string_lossy(); + match fp.parent() { + Some(dir) => match dir { + dir if dir.starts_with(*dirs::CONFIG) => None, + dir if dir.starts_with(*dirs::SYSTEM) => None, + dir if dir == *dirs::HOME => None, + dir if !filename.starts_with('.') && dir.ends_with("/.rtx") => dir.parent(), + dir if !filename.starts_with('.') && dir.ends_with("/.config/rtx") => { + dir.parent().unwrap().parent() + } + dir => Some(dir), + }, + None => None, + } + } + fn plugins(&self) -> HashMap { self.plugins.clone() } @@ -593,10 +674,14 @@ impl ConfigFile for RtxToml { self.env_remove.clone() } - fn path_dirs(&self) -> Vec { + fn env_path(&self) -> Vec { self.path_dirs.clone() } + fn tasks(&self) -> Vec<&Task> { + self.tasks.iter().collect() + } + fn remove_plugin(&mut self, plugin: &PluginName) { self.toolset.versions.remove(plugin); if let Some(tools) = self.doc.get_mut("tools") { @@ -755,6 +840,7 @@ impl Clone for RtxToml { alias: self.alias.clone(), doc: self.doc.clone(), plugins: self.plugins.clone(), + tasks: self.tasks.clone(), is_trusted: Mutex::new(*self.is_trusted.lock().unwrap()), } } @@ -794,7 +880,7 @@ mod tests { "foo": "bar", } "###); - assert_debug_snapshot!(cf.path_dirs(), @"[]"); + assert_debug_snapshot!(cf.env_path(), @"[]"); let cf: Box = Box::new(cf); with_settings!({ assert_snapshot!(cf.dump()); @@ -820,7 +906,7 @@ mod tests { "foo": "bar", } "###); - assert_snapshot!(replace_path(&format!("{:?}", cf.path_dirs())), @r###"["/foo", "~/fixtures/bar"]"###); + assert_snapshot!(replace_path(&format!("{:?}", cf.env_path())), @r###"["/foo", "~/fixtures/bar"]"###); let cf: Box = Box::new(cf); assert_snapshot!(cf.dump()); assert_display_snapshot!(cf); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap index 7dfa1bb61..36e4c96f5 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap @@ -21,6 +21,7 @@ RtxToml(/tmp/.rtx.toml): { "quiet": Null, "raw": Null, "shorthands_file": Null, + "task_output": Null, "trace": Null, "trusted_config_paths": Null, "verbose": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index d93b2aab0..d31bba6f0 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -27,5 +27,6 @@ expression: cf.settings().unwrap() ], "raw": null, "yes": null, + "task_output": null, "ci": null } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index 4dbbe879b..afface3d4 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/rtx_toml.rs -expression: "replace_path(&format!(\"{:#?}\", & cf))" +expression: "replace_path(&format!(\"{:#?}\", &cf))" --- RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { settings: Object { @@ -25,6 +25,7 @@ RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref: "quiet": Null, "raw": Null, "shorthands_file": Null, + "task_output": Null, "trace": Null, "trusted_config_paths": Null, "verbose": Bool(true), diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap index 3cf6222b8..ab2146ca5 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap @@ -21,6 +21,7 @@ RtxToml(~/fixtures/.rtx.toml): { "quiet": Null, "raw": Null, "shorthands_file": Null, + "task_output": Null, "trace": Null, "trusted_config_paths": Null, "verbose": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap index 1ef19af55..965323699 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap @@ -21,6 +21,7 @@ RtxToml(/tmp/.rtx.toml): { "quiet": Null, "raw": Null, "shorthands_file": Null, + "task_output": Null, "trace": Null, "trusted_config_paths": Null, "verbose": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap index b72846d1f..0e6aba27b 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap @@ -21,6 +21,7 @@ RtxToml(/tmp/.rtx.toml): { "quiet": Null, "raw": Null, "shorthands_file": Null, + "task_output": Null, "trace": Null, "trusted_config_paths": Null, "verbose": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap index 88bac99d2..806c4f308 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap @@ -21,6 +21,7 @@ RtxToml(/tmp/.rtx.toml): node@16.0.1 node@18.0.1 { "quiet": Null, "raw": Null, "shorthands_file": Null, + "task_output": Null, "trace": Null, "trusted_config_paths": Null, "verbose": Null, diff --git a/src/config/config_file/toml.rs b/src/config/config_file/toml.rs new file mode 100644 index 000000000..2cd344661 --- /dev/null +++ b/src/config/config_file/toml.rs @@ -0,0 +1,53 @@ +use std::collections::HashMap; + +pub struct TomlParser<'a> { + pub table: &'a toml::Value, +} + +impl<'a> TomlParser<'a> { + pub fn new(table: &'a toml::Value) -> Self { + Self { table } + } + + pub fn parse_str(&self, key: &str) -> Option { + self.table + .get(key) + .and_then(|value| value.as_str()) + .map(|value| value.to_string()) + } + pub fn parse_bool(&self, key: &str) -> Option { + self.table.get(key).and_then(|value| value.as_bool()) + } + pub fn parse_array(&self, key: &str) -> Option> + where + T: Default + From, + { + self.table + .get(key) + .and_then(|value| value.as_array()) + .map(|array| { + array + .iter() + .filter_map(|value| value.as_str().map(|v| v.to_string().into())) + .collect::>() + }) + } + pub fn parse_hashmap(&self, key: &str) -> Option> + where + T: From, + { + self.table + .get(key) + .and_then(|value| value.as_table()) + .map(|table| { + table + .iter() + .filter_map(|(key, value)| { + value + .as_str() + .map(|v| (key.to_string(), v.to_string().into())) + }) + .collect::>() + }) + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 6288e2896..b5b0b2695 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,7 @@ +use either::Either; use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Formatter}; +use std::iter::once; use std::path::PathBuf; use std::sync::{Arc, RwLock}; @@ -14,12 +16,14 @@ pub use settings::Settings; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::rtx_toml::RtxToml; -use crate::config::config_file::{ConfigFile, ConfigFileType}; +use crate::config::config_file::ConfigFile; use crate::config::tracking::Tracker; use crate::file::display_path; use crate::plugins::core::{PluginMap, CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; +use crate::task::Task; +use crate::ui::style; use crate::{dirs, env, file}; pub mod config_file; @@ -43,6 +47,7 @@ pub struct Config { plugins: RwLock, repo_urls: HashMap, shorthands: OnceCell>, + tasks: OnceCell>, } static CONFIG: RwLock>> = RwLock::new(None); @@ -86,6 +91,7 @@ impl Config { aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), shorthands: OnceCell::new(), + tasks: OnceCell::new(), project_root: get_project_root(&config_files), config_files, global_config, @@ -113,6 +119,10 @@ impl Config { self.all_aliases.get_or_init(|| self.load_all_aliases()) } + pub fn tasks(&self) -> &HashMap { + self.tasks.get_or_init(|| self.load_all_tasks()) + } + pub fn is_activated(&self) -> bool { env::var("__RTX_DIFF").is_ok() } @@ -188,6 +198,50 @@ impl Config { aliases } + pub fn load_all_tasks(&self) -> HashMap { + self.config_files + .values() + .collect_vec() + .into_par_iter() + .flat_map(|cf| { + match cf.project_root() { + Some(pr) => vec![ + pr.join(".rtx").join("tasks"), + pr.join(".config").join("rtx").join("tasks"), + ], + None => vec![], + } + .into_par_iter() + .flat_map(|dir| file::ls(&dir).map_err(|err| warn!("load_all_tasks: {err}"))) + .flatten() + .map(Either::Right) + .chain(rayon::iter::once(Either::Left(cf))) + }) + .collect::, PathBuf>>>() + .into_iter() + .unique() + .collect_vec() + .into_par_iter() + .flat_map(|either| match either { + Either::Left(cf) => cf.tasks().into_iter().cloned().collect(), + Either::Right(path) => match Task::from_path(path) { + Ok(task) => vec![task], + Err(err) => { + warn!("Error loading task: {:#}", err); + vec![] + } + }, + }) + .flat_map(|t| { + t.aliases + .iter() + .map(|a| (a.to_string(), t.clone())) + .chain(once((t.name.clone(), t.clone()))) + .collect::>() + }) + .collect() + } + pub fn get_tracked_config_files(&self) -> Result { let config_files = Tracker::list_all()? .into_par_iter() @@ -220,19 +274,10 @@ impl Config { } fn get_project_root(config_files: &ConfigMap) -> Option { - for (p, cf) in config_files.into_iter() { - if p == &get_global_rtx_toml() { - // ~/.config/rtx/config.toml is not a project config file - continue; - } - match cf.get_type() { - ConfigFileType::RtxToml | ConfigFileType::ToolVersions => { - return Some(p.parent()?.to_path_buf()); - } - _ => {} - } - } - None + config_files + .values() + .find_map(|cf| cf.project_root()) + .map(|pr| pr.to_path_buf()) } fn load_rtxrc() -> Result { @@ -302,14 +347,27 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap> = Lazy::new(|| { - let mut filenames = vec![]; - filenames.push(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone()); - filenames.push(env::RTX_DEFAULT_CONFIG_FILENAME.clone()); + let mut filenames = vec![ + env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone(), + env::RTX_DEFAULT_CONFIG_FILENAME.clone(), + ]; if *env::RTX_DEFAULT_CONFIG_FILENAME == ".rtx.toml" { - filenames.push(".rtx.local.toml".to_string()); + filenames.insert(0, ".rtx/config.toml".into()); + filenames.insert(0, ".config/rtx.toml".into()); + filenames.insert(0, ".config/rtx/config.toml".into()); + filenames.push(".config/rtx/config.local.toml".into()); + filenames.push(".config/rtx.local.toml".into()); + filenames.push(".rtx/config.local.toml".into()); + filenames.push(".rtx.local.toml".into()); if let Some(env) = &*env::RTX_ENV { - filenames.push(format!(".rtx.{}.toml", env)); - filenames.push(format!(".rtx.{}.local.toml", env)); + filenames.push(format!(".config/rtx/config.{env}.toml")); + filenames.push(format!(".config/rtx.{env}.toml")); + filenames.push(format!(".rtx/config.{env}.local.toml")); + filenames.push(format!(".rtx.{env}.toml")); + filenames.push(format!(".config/rtx/config.{env}.local.toml")); + filenames.push(format!(".config/rtx.{env}.local.toml")); + filenames.push(format!(".rtx/config.{env}.local.toml")); + filenames.push(format!(".rtx.{env}.local.toml")); } } filenames @@ -371,8 +429,12 @@ fn load_all_config_files( .collect_vec() .into_par_iter() .map(|f| { - let cf = parse_config_file(f, legacy_filenames, tools) - .wrap_err_with(|| format!("error parsing config file: {}", display_path(f)))?; + let cf = parse_config_file(f, legacy_filenames, tools).wrap_err_with(|| { + format!( + "error parsing config file: {}", + style::ebold(display_path(f)) + ) + })?; if let Err(err) = Tracker::track(f) { warn!("tracking config: {err:#}"); } @@ -422,7 +484,7 @@ fn load_env(config_files: &ConfigMap) -> (BTreeMap, HashMap Vec { let mut path_dirs = vec![]; for cf in config_files.values().rev() { - path_dirs.extend(cf.path_dirs()); + path_dirs.extend(cf.env_path()); } path_dirs } @@ -457,6 +519,12 @@ impl Debug for Config { let mut s = f.debug_struct("Config"); s.field("Config Files", &config_files); s.field("Installed Plugins", &plugins); + if let Some(tasks) = self.tasks.get() { + s.field( + "Tasks", + &tasks.values().map(|t| t.to_string()).collect_vec(), + ); + } if !self.env.is_empty() { s.field("Env", &self.env); // s.field("Env Sources", &self.env_sources); diff --git a/src/config/settings.rs b/src/config/settings.rs index 660fd889f..708aa8919 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -56,6 +56,8 @@ pub struct Settings { pub raw: bool, #[config(env = "RTX_YES", default = false)] pub yes: bool, + #[config(env = "RTX_TASK_OUTPUT")] + pub task_output: Option, #[config(env = "CI", default = false)] pub ci: bool, } diff --git a/src/env.rs b/src/env.rs index 26328b92a..8c6160873 100644 --- a/src/env.rs +++ b/src/env.rs @@ -21,6 +21,8 @@ pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "s pub static HOME: Lazy = Lazy::new(|| dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/"))); pub static PWD: Lazy = Lazy::new(|| current_dir().unwrap_or_else(|_| PathBuf::new())); +pub static EDITOR: Lazy = + Lazy::new(|| var("VISUAL").unwrap_or_else(|_| var("EDITOR").unwrap_or_else(|_| "nano".into()))); pub static XDG_CACHE_HOME: Lazy = Lazy::new(|| dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache"))); @@ -74,7 +76,7 @@ pub static TERM_WIDTH: Lazy = Lazy::new(|| { terminal_size::terminal_size() .map(|(w, _)| w.0 as usize) .unwrap_or(80) - .max(60) + .max(80) }); /// duration that remote version cache is kept for diff --git a/src/file.rs b/src/file.rs index 5883b7f51..ef23b2661 100644 --- a/src/file.rs +++ b/src/file.rs @@ -80,11 +80,22 @@ pub fn read_to_string>(path: P) -> Result { .wrap_err_with(|| format!("failed read_to_string: {}", display_path(path))) } +pub fn create(path: &Path) -> Result { + if let Some(parent) = path.parent() { + create_dir_all(parent)?; + } + trace!("touch {}", display_path(path)); + File::create(path).wrap_err_with(|| format!("failed create: {}", display_path(path))) +} + pub fn create_dir_all>(path: P) -> Result<()> { let path = path.as_ref(); - trace!("mkdir -p {}", display_path(path)); - fs::create_dir_all(path) - .wrap_err_with(|| format!("failed create_dir_all: {}", display_path(path))) + if !path.exists() { + trace!("mkdir -p {}", display_path(path)); + fs::create_dir_all(path) + .wrap_err_with(|| format!("failed create_dir_all: {}", display_path(path)))?; + } + Ok(()) } pub fn basename(path: &Path) -> Option { @@ -156,7 +167,7 @@ pub fn dir_subdirs(dir: &Path) -> Result> { Ok(output) } -pub fn dir_files(dir: &Path) -> Result> { +pub fn ls(dir: &Path) -> Result> { let mut output = vec![]; if !dir.is_dir() { @@ -166,7 +177,7 @@ pub fn dir_files(dir: &Path) -> Result> { for entry in dir.read_dir()? { let entry = entry?; if entry.file_type()?.is_file() { - output.push(entry.file_name().into_string().unwrap()); + output.push(entry.path()); } } diff --git a/src/main.rs b/src/main.rs index 8bd65810c..17d96014a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,8 @@ extern crate core; extern crate eyre; #[macro_use] extern crate indoc; +#[macro_use] +extern crate strum; #[cfg(test)] #[macro_use] extern crate insta; @@ -58,6 +60,7 @@ mod runtime_symlinks; mod shell; mod shims; mod shorthands; +mod task; pub mod tera; pub mod timeout; mod toml; diff --git a/src/output.rs b/src/output.rs index e589797cc..328cc313b 100644 --- a/src/output.rs +++ b/src/output.rs @@ -90,18 +90,35 @@ macro_rules! debug { #[cfg(not(test))] #[macro_export] macro_rules! info { + ($($arg:tt)*) => {{ + let rtx = console::style("rtx").dim().for_stderr(); + info_unprefix!("{} {}", rtx, format!($($arg)*)); + }}; +} + +#[macro_export] +macro_rules! info_unprefix { ($($arg:tt)*) => {{ if log::log_enabled!(log::Level::Debug) { log::info!($($arg)*); } else if log::log_enabled!(log::Level::Info) { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { - let rtx = console::style("rtx ").dim().for_stderr(); - eprintln!("{}{}", rtx, format!($($arg)*)); + eprintln!("{}", format!($($arg)*)); }); } }}; } +#[macro_export] +macro_rules! info_unprefix_trunc { + ($($arg:tt)*) => {{ + let msg = format!($($arg)*); + let msg = msg.lines().next().unwrap_or_default(); + let msg = console::truncate_str(&msg, *$crate::env::TERM_WIDTH, "…"); + info_unprefix!("{msg}"); + }}; +} + #[cfg(not(test))] #[macro_export] macro_rules! warn { diff --git a/src/plugins/core/assets/node_npm_shim b/src/plugins/core/assets/node_npm_shim index e3a0f1af2..74d6bfae7 100755 --- a/src/plugins/core/assets/node_npm_shim +++ b/src/plugins/core/assets/node_npm_shim @@ -16,7 +16,7 @@ should_reshim() { return 1 fi - local is_global= cmd= cmd_needs_reshim= + local is_global='' cmd='' cmd_needs_reshim='' local additional_bare_cmds=() for arg; do diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 20aca0f9f..71db78e5b 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -460,7 +460,7 @@ impl Plugin for ExternalPlugin { name = style(&self.name).blue(), url = style(url.trim_end_matches(".git")).yellow(), ); - if !prompt::confirm(&format!("Would you like to install {}?", self.name))? { + if !prompt::confirm(format!("Would you like to install {}?", self.name))? { Err(PluginNotInstalled(self.name.clone()))? } } @@ -590,7 +590,8 @@ impl Plugin for ExternalPlugin { return Ok(vec![]); } let mut commands = vec![]; - for command in file::dir_files(&command_path)? { + for p in file::ls(&command_path)? { + let command = p.file_name().unwrap().to_string_lossy().to_string(); if !command.starts_with("command-") || !command.ends_with(".bash") { continue; } diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index d3681fb69..22fa1ceed 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -38,10 +38,7 @@ function __rtx_tool_versions end end function __rtx_installed_tool_versions - if test -z "$__rtx_installed_tool_versions_cache" - set -g __rtx_installed_tool_versions_cache (rtx ls --installed | awk '{{print $1 "@" $2}}') - end - for tv in $__rtx_installed_tool_versions_cache + for tv in (rtx ls --installed | awk '{{print $1 "@" $2}}') echo $tv end end @@ -53,6 +50,11 @@ function __rtx_aliases echo $a end end +function __rtx_tasks + for tv in (rtx task ls --no-header | awk '{{print $1}}') + echo $tv + end +end function __rtx_settings if test -z "$__rtx_settings_cache" set -g __rtx_settings_cache (rtx settings ls | awk '{{print $1}}') @@ -121,6 +123,7 @@ fn render_completer(a: &Arg) -> Option { "new_plugin" => Some("(__rtx_all_plugins)".to_string()), "alias" => Some("(__rtx_aliases)".to_string()), "setting" => Some("(__rtx_settings)".to_string()), + "task" => Some("(__rtx_tasks)".to_string()), //"prefix" => Some("(__rtx_prefixes)".to_string()), _ => None, }, diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index eab3416e8..904361b7f 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -65,6 +65,11 @@ pub fn render(cmd: &Command) -> String { local -a settings; settings=($(rtx settings ls | awk '{{print $1}}')) _describe -t settings 'setting' settings "$@" }} + (( $+functions[__rtx_tasks] )) || + __rtx_tasks() {{ + local -a tasks; tasks=($(rtx tasks ls --no-header | awk '{{print $1}}')) + _describe -t tasks 'task' tasks "$@" + }} (( $+functions[__rtx_prefixes] )) || __rtx_prefixes() {{ if [[ CURRENT -gt 2 ]]; then @@ -234,6 +239,7 @@ fn render_completion(arg: &Arg) -> String { "new_plugin" => "__rtx_all_plugins".to_string(), "alias" => "__rtx_aliases".to_string(), "setting" => "__rtx_settings".to_string(), + "task" => "__rtx_tasks".to_string(), "prefix" => "__rtx_prefixes".to_string(), _ => String::new(), }, diff --git a/src/task.rs b/src/task.rs new file mode 100644 index 000000000..63b4a82ab --- /dev/null +++ b/src/task.rs @@ -0,0 +1,182 @@ +use console::truncate_str; +use std::cmp::Ordering; +use std::collections::HashMap; +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::hash::{Hash, Hasher}; +use std::path::PathBuf; + +use eyre::Result; +use itertools::Itertools; + +use crate::config::config_file::toml::TomlParser; +use crate::config::Config; +use crate::file; + +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct Task { + pub name: String, + pub description: String, + pub aliases: Vec, + pub config_source: PathBuf, + pub depends: Vec, + pub env: HashMap, + pub dir: Option, + pub hide: bool, + pub raw: bool, + pub sources: Vec, + pub outputs: Vec, + + // normal type + pub run: Vec, + + // command type + // pub command: Option, + pub args: Vec, + + // script type + // pub script: Option, + + // file type + pub file: Option, +} + +impl Task { + pub fn new(name: String, config_source: PathBuf) -> Task { + Task { + name: name.clone(), + config_source, + ..Default::default() + } + } + pub fn from_path(path: PathBuf) -> Result { + let info = file::read_to_string(&path)? + .lines() + .filter_map(|line| regex!(r"^# rtx ([a-z]+=.+)$").captures(line)) + .map(|captures| captures.extract()) + .flat_map(|(_, [toml])| { + toml.parse::() + .map_err(|e| debug!("failed to parse toml: {e}")) + }) + .filter_map(|toml| toml.as_table().cloned()) + .flatten() + .fold(toml::Table::new(), |mut map, (key, value)| { + map.insert(key, value); + map + }); + let info = toml::Value::Table(info); + let p = TomlParser::new(&info); + // trace!("task info: {:#?}", info); + + let name = path.file_name().unwrap().to_str().unwrap().to_string(); + let task = Task { + hide: !file::is_executable(&path) || p.parse_bool("hide").unwrap_or_default(), + description: p.parse_str("description").unwrap_or_default(), + sources: p.parse_array("sources").unwrap_or_default(), + outputs: p.parse_array("outputs").unwrap_or_default(), + depends: p.parse_array("depends").unwrap_or_default(), + dir: p.parse_str("dir").map(PathBuf::from), + env: p.parse_hashmap("env").unwrap_or_default(), + file: Some(path.clone()), + ..Task::new(name, path) + }; + Ok(task) + } + + pub fn command_string(&self) -> Option { + if let Some(command) = self.run.first() { + Some(command.to_string()) + // } else if let Some(script) = &self.script { + // Some(script.to_string()) + } else { + self.file + .as_ref() + .map(|file| file.to_str().unwrap().to_string()) + } + } + + // pub fn args(&self) -> impl Iterator { + // if let Some(script) = &self.script { + // // TODO: cli_args + // vec!["-c".to_string(), script.to_string()].into_iter() + // } else { + // self.args + // .iter() + // .chain(self.cli_args.iter()) + // .cloned() + // .collect_vec() + // .into_iter() + // } + // } + pub fn with_args(mut self, args: Vec) -> Self { + self.args = args; + self + } + + pub fn prefix(&self) -> String { + format!("[{}]", self.name) + } + + pub fn resolve_depends<'a>(&self, config: &'a Config) -> Result> { + let tasks = config.tasks(); + let depends = self + .depends + .iter() + .map(|name| match name.strip_suffix('*') { + Some(prefix) => Ok(tasks + .values() + .unique() + .filter(|t| *t != self && t.name.starts_with(prefix)) + .collect::>()), + None => tasks + .get(name) + .map(|task| vec![task]) + .ok_or_else(|| eyre!("task not found: {name}")), + }) + .collect::>>()? + .into_iter() + .flatten() + .collect(); + Ok(depends) + } + + // pub fn project_root(&self) -> &Path { + // match self + // .config_source + // .parent() + // .expect("task source has no parent") + // { + // dir if dir.ends_with(".rtx/tasks") => dir.parent().unwrap(), + // dir if dir.ends_with(".config/rtx/tasks") => dir.parent().unwrap().parent().unwrap(), + // dir => dir, + // } + // } +} + +impl Display for Task { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Some(cmd) = self.command_string() { + write!(f, "{} {}", self.prefix(), truncate_str(&cmd, 60, "…")) + } else { + write!(f, "{}", self.prefix()) + } + } +} + +impl PartialOrd for Task { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Task { + fn cmp(&self, other: &Self) -> Ordering { + self.name.cmp(&other.name) + } +} + +impl Hash for Task { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} diff --git a/src/tera.rs b/src/tera.rs index 98a6b9bfb..7425214d6 100644 --- a/src/tera.rs +++ b/src/tera.rs @@ -11,6 +11,7 @@ use crate::hash::hash_to_str; pub static BASE_CONTEXT: Lazy = Lazy::new(|| { let mut context = Context::new(); context.insert("env", &*env::PRISTINE_ENV); + context.insert("cwd", &*env::PWD); context }); diff --git a/src/test.rs b/src/test.rs index de8d2d485..a89caf4ad 100644 --- a/src/test.rs +++ b/src/test.rs @@ -66,6 +66,13 @@ pub fn reset_config() { [alias.tiny] "my/alias" = '3.0' + + [tasks.configtask] + run = 'echo "configtask:"' + [tasks.lint] + run = 'echo "linting!"' + [tasks.test] + run = 'echo "testing!"' "#}, ) .unwrap(); diff --git a/src/toml.rs b/src/toml.rs index 1c28d5002..4aeb4ccf2 100644 --- a/src/toml.rs +++ b/src/toml.rs @@ -2,10 +2,10 @@ macro_rules! parse_error { ($key:expr, $val:expr, $t:expr) => {{ bail!( - r#"expected value of "{}" to be a {}, got: {}"#, - $key, - $t, - $val + r#"expected value of {} to be a {}, got: {}"#, + $crate::ui::style::eyellow($key), + $crate::ui::style::ecyan($t), + $crate::ui::style::eblue($val.to_string().trim()), ) }}; } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 92a5b36ff..10cb9ce6a 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,10 +1,12 @@ use console::{user_attended_stderr, Term}; +pub use prompt::confirm; use std::process::exit; use std::sync::Once; pub mod multi_progress_report; pub mod progress_report; pub mod prompt; +pub mod style; pub mod table; pub fn handle_ctrlc() { diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 44e6dd429..26f015c34 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,6 +1,6 @@ use crate::config::Config; use crate::ui; -use console::style; +use crate::ui::style; use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; use std::time::Duration; @@ -18,10 +18,7 @@ static PROG_TEMPLATE: Lazy = Lazy::new(|| { }); static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { - let tmpl = format!( - "{{prefix}} {} {{wide_msg}}", - style("✓").bright().green().for_stderr() - ); + let tmpl = format!("{{prefix}} {} {{wide_msg}}", style::egreen("✓").bright()); ProgressStyle::with_template(tmpl.as_str()).unwrap() }); @@ -47,11 +44,11 @@ fn pad_prefix(w: usize, s: &str) -> String { console::pad_str(s, w, console::Alignment::Left, None).to_string() } fn normal_prefix(pad: usize, prefix: &str) -> String { - let prefix = format!("{} {prefix}", style("rtx").dim().for_stderr()); + let prefix = format!("{} {prefix}", style::edim("rtx")); pad_prefix(pad, &prefix) } fn success_prefix(pad: usize, prefix: &str) -> String { - let prefix = format!("{} {prefix}", style("rtx").green().for_stderr()); + let prefix = format!("{} {prefix}", style::egreen("rtx")); pad_prefix(pad, &prefix) } @@ -124,11 +121,11 @@ impl SingleReport for VerboseReport { eprintln!("{message}"); } fn finish(&self) { - self.finish_with_message(style("done").green().for_stderr().to_string()); + self.finish_with_message(style::egreen("done").to_string()); } fn finish_with_message(&self, message: String) { let prefix = success_prefix(self.pad - 2, &self.prefix); - let ico = style("✓").bright().green().for_stderr(); + let ico = style::egreen("✓").bright(); eprintln!("{prefix} {ico} {message}"); } } diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index a6527f905..76da1a9ee 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -5,7 +5,7 @@ use std::sync::Mutex; static MUTEX: Mutex<()> = Mutex::new(()); -pub fn confirm(message: &str) -> io::Result { +pub fn confirm>(message: S) -> io::Result { let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once ui::handle_ctrlc(); diff --git a/src/ui/style.rs b/src/ui/style.rs new file mode 100644 index 000000000..f98876553 --- /dev/null +++ b/src/ui/style.rs @@ -0,0 +1,41 @@ +use crate::file::display_path; +use console::{style, StyledObject}; +use std::path::Path; + +pub fn estyle(val: D) -> StyledObject { + style(val).for_stderr() +} +pub fn ecyan(val: D) -> StyledObject { + estyle(val).cyan() +} +pub fn eblue(val: D) -> StyledObject { + estyle(val).blue() +} +pub fn egreen(val: D) -> StyledObject { + estyle(val).green() +} +pub fn eyellow(val: D) -> StyledObject { + estyle(val).yellow() +} +pub fn ered(val: D) -> StyledObject { + estyle(val).red() +} +pub fn edim(val: D) -> StyledObject { + estyle(val).dim() +} +pub fn ebold(val: D) -> StyledObject { + estyle(val).bold() +} +pub fn epath(path: &Path) -> StyledObject { + estyle(display_path(path)) +} + +pub fn nstyle(val: D) -> StyledObject { + style(val).for_stdout() +} +pub fn nblue(val: D) -> StyledObject { + nstyle(val).cyan() +} +pub fn nbold(val: D) -> StyledObject { + nstyle(val).bold() +} diff --git a/src/ui/table.rs b/src/ui/table.rs index 84c2cb5c7..d15d63531 100644 --- a/src/ui/table.rs +++ b/src/ui/table.rs @@ -29,7 +29,7 @@ pub fn default_style(table: &mut Table, no_headers: bool) { table.with(Modify::new(Rows::first()).with(Format::content(header))); } table.with(Style::empty()); - if console::user_attended() { + if console::user_attended() || cfg!(test) { table.with(term_size_settings()); } table diff --git a/test/.gitignore b/test/.gitignore index 7061e564e..b8f5b586f 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -3,3 +3,4 @@ data/ cache/ state/ cwd/man/ +test-build-output.txt diff --git a/test/config/config.toml b/test/config/config.toml index 2234f4acb..69a229f91 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -11,3 +11,10 @@ jobs = 2 [alias.tiny] "my/alias" = '3.0' + +[tasks.configtask] +run = 'echo "configtask:"' +[tasks.lint] +run = 'echo "linting!"' +[tasks.test] +run = 'echo "testing!"' diff --git a/test/cwd/.rtx/tasks/filetask b/test/cwd/.rtx/tasks/filetask new file mode 100755 index 000000000..f466b183f --- /dev/null +++ b/test/cwd/.rtx/tasks/filetask @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# rtx description="This is a test build script" +# rtx depends=["lint", "test"] +# rtx sources=[".test-tool-versions"] +# rtx outputs=["$RTX_PROJECT_ROOT/test/test-build-output.txt"] +# rtx env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} + +set -euxo pipefail +cd "$RTX_PROJECT_ROOT" || exit 1 +echo "running test-build script" +echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test-build-output.txt From b59ec1b85ccaebd70873724e99f69c1763cb5f50 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 05:11:46 -0600 Subject: [PATCH 1421/1891] docs --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb681c1bb..6d65aed06 100644 --- a/README.md +++ b/README.md @@ -1282,16 +1282,23 @@ These are the default directories, see ### `~/.config/rtx` -This directory stores the global configuration file `~/.config/rtx/config.toml`. +This directory stores the global configuration file `~/.config/rtx/config.toml`. This is intended to go into your +dotfiles repo to share across machines. ### `~/.cache/rtx` _On macOS this is `~/Library/Caches/rtx`._ Stores internal cache that rtx uses for things like the list of all available versions of a -plugin. +plugin. Do not share this across machines. You may delete this directory any time rtx isn't actively installing something. +Do this with `rtx cache clear`. See [Cache Behavior](#cache-behavior) for more information. +### `~/.local/state/rtx` + +Used for storing state local to the machine such as which config files are trusted. These should not be shared across +machines. + ### `~/.local/share/rtx` This is the main directory that rtx uses and is where plugins and tools are installed into. @@ -1299,6 +1306,9 @@ It is nearly identical to `~/.asdf` in asdf, so much so that you may be able to symlinking these together and using asdf and rtx simultaneously. (Supporting this isn't a project goal, however). +This directory _could_ be shared across machines but only if they run the same OS/arch. In general I wouldn't advise +doing so. + #### `~/.local/share/rtx/downloads` This is where plugins may optionally cache downloaded assets such as tarballs. Use the From 5bef38660691afd66dbc76825892aad551ab3baa Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 05:12:12 -0600 Subject: [PATCH 1422/1891] docs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6d65aed06..35589ce59 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ v20.0.0 - [Directories](#directories) - [`~/.config/rtx`](#configrtx) - [`~/.cache/rtx`](#cachertx) + - [`~/.local/state/rtx`](#localstatertx) - [`~/.local/share/rtx`](#localsharertx) - [Templates](#templates) - [Config Environments](#config-environments) From af4e744526b56e5dadc3eded7643bcda7fc395b5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 05:33:44 -0600 Subject: [PATCH 1423/1891] task runner e2e test --- .idea/rtx.iml | 2 -- e2e/.gitignore | 2 +- e2e/.rtx/tasks/build | 4 ++++ e2e/.rtx/tasks/filetask | 13 +++++++++++++ e2e/config/.e2e.rtx.toml | 7 +++++++ e2e/test_run | 9 +++++++++ src/config/mod.rs | 1 + 7 files changed, 35 insertions(+), 3 deletions(-) create mode 100755 e2e/.rtx/tasks/build create mode 100755 e2e/.rtx/tasks/filetask create mode 100755 e2e/test_run diff --git a/.idea/rtx.iml b/.idea/rtx.iml index 1646cdc59..8e4258be6 100644 --- a/.idea/rtx.iml +++ b/.idea/rtx.iml @@ -12,10 +12,8 @@ - - diff --git a/e2e/.gitignore b/e2e/.gitignore index d756e6944..8dd64b3e5 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,6 +1,5 @@ .e2e.rtx.toml .local -.rtx .cache .config .asdf @@ -10,3 +9,4 @@ ruby/.ruby-version Library /pyproject.toml /poetry.lock +/test-e2e/ diff --git a/e2e/.rtx/tasks/build b/e2e/.rtx/tasks/build new file mode 100755 index 000000000..d1bebb0fd --- /dev/null +++ b/e2e/.rtx/tasks/build @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -xeuo pipefail + +echo "BUILD" diff --git a/e2e/.rtx/tasks/filetask b/e2e/.rtx/tasks/filetask new file mode 100755 index 000000000..3e7d92e19 --- /dev/null +++ b/e2e/.rtx/tasks/filetask @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# rtx description="This is a test build script" +# rtx depends=["lint", "test"] +# rtx sources=[".test-tool-versions"] +# rtx outputs=["$RTX_PROJECT_ROOT/test-e2e/test-build-output.txt"] +# rtx env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} + +set -euxo pipefail +cd "$RTX_PROJECT_ROOT" || exit 1 +echo "running test-build script" +mkdir -p test-e2e +echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test-e2e/test-build-output.txt +echo "ARGS: $*" >> test-e2e/test-build-output.txt diff --git a/e2e/config/.e2e.rtx.toml b/e2e/config/.e2e.rtx.toml index 6a2d5fe45..630efb393 100644 --- a/e2e/config/.e2e.rtx.toml +++ b/e2e/config/.e2e.rtx.toml @@ -10,3 +10,10 @@ tiny = "latest" [plugins] tiny-ref = "https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c" + +[tasks.configtask] +run = 'echo "configtask:"' +[tasks.lint] +run = 'echo "linting!"' +[tasks.test] +run = 'echo "testing!"' diff --git a/e2e/test_run b/e2e/test_run new file mode 100755 index 000000000..ffe5b63db --- /dev/null +++ b/e2e/test_run @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +rtx settings set experimental true +rtx r configtask arg1 arg2 ::: filetask arg1 arg2 +assert "cat test-e2e/test-build-output.txt" "TEST_BUILDSCRIPT_ENV_VAR: VALID +ARGS: arg1 arg2" diff --git a/src/config/mod.rs b/src/config/mod.rs index b5b0b2695..16ebd97f2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -219,6 +219,7 @@ impl Config { }) .collect::, PathBuf>>>() .into_iter() + .rev() .unique() .collect_vec() .into_par_iter() From b18c3042e4d528deff977ec8e812fb67496958d2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 05:39:34 -0600 Subject: [PATCH 1424/1891] fix e2e test --- e2e/test_local | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/e2e/test_local b/e2e/test_local index b32dbf51e..df97dc935 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -30,6 +30,13 @@ tiny = \"latest\" [plugins] tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" + +[tasks.configtask] +run = 'echo \"configtask:\"' +[tasks.lint] +run = 'echo \"linting!\"' +[tasks.test] +run = 'echo \"testing!\"' " rtx local shfmt@3.5.0 @@ -46,6 +53,13 @@ shfmt = \"3.5.0\" [plugins] tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" + +[tasks.configtask] +run = 'echo \"configtask:\"' +[tasks.lint] +run = 'echo \"linting!\"' +[tasks.test] +run = 'echo \"testing!\"' " rtx exec -- shfmt --version >&2 @@ -67,6 +81,13 @@ shfmt = \"3.6.0\" [plugins] tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" + +[tasks.configtask] +run = 'echo \"configtask:\"' +[tasks.lint] +run = 'echo \"linting!\"' +[tasks.test] +run = 'echo \"testing!\"' " rtx exec -- shfmt --version >&2 @@ -87,6 +108,13 @@ tiny = \"latest\" [plugins] tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" + +[tasks.configtask] +run = 'echo \"configtask:\"' +[tasks.lint] +run = 'echo \"linting!\"' +[tasks.test] +run = 'echo \"testing!\"' " export RTX_DEFAULT_CONFIG_FILENAME=.MISSING From ec05748cb3da2d31f01a0d82182f41e32090098f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 05:43:40 -0600 Subject: [PATCH 1425/1891] chore: Release rtx-cli version 2023.12.36 --- Cargo.lock | 46 +++++++++++++++++------------------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 23 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23a8ff559..ad5059ae8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -454,21 +454,20 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.16" +version = "0.9.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" +checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", ] [[package]] name = "crossbeam-utils" -version = "0.8.17" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" dependencies = [ "cfg-if", ] @@ -495,12 +494,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" dependencies = [ "nix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -605,9 +604,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "duct" -version = "0.13.6" +version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ae3fc31835f74c2a7ceda3aeede378b0ae2e74c8f1c36559fcc9ae2a4e7d3e" +checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" dependencies = [ "libc", "once_cell", @@ -1296,15 +1295,6 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -1412,9 +1402,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -1427,9 +1417,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.61" +version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1459,9 +1449,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.97" +version = "0.9.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" dependencies = [ "cc", "libc", @@ -1671,9 +1661,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -1885,7 +1875,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.35" +version = "2023.12.36" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 72ea4c394..ff6654317 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.35" +version = "2023.12.36" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 35589ce59..7a5466efc 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.35 +rtx 2023.12.36 ``` Hook rtx into your shell (pick the right one for your shell): @@ -373,7 +373,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.35/rtx-v2023.12.35-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.36/rtx-v2023.12.36-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index b43bb0e26..9690f67a2 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.35"; + version = "2023.12.36"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 86714fd98..9ac9b5a25 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.35 +Version: 2023.12.36 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From e7fa521e516fde35fdcd7b3384bfc28789fb9829 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 08:21:37 -0600 Subject: [PATCH 1426/1891] watch: added new command (#1263) * watch: added new command * Commit from GitHub Actions (test) --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- README.md | 195 ++++++++++++++++++++++++++++++++++++----- completions/_rtx | 19 +++- completions/rtx.bash | 67 ++++++++++++-- completions/rtx.fish | 19 ++-- src/cli/mod.rs | 3 + src/cli/run.rs | 48 ++++++++-- src/cli/task/edit.rs | 21 ++++- src/cli/task/ls.rs | 8 +- src/cli/watch.rs | 138 +++++++++++++++++++++++++++++ src/config/settings.rs | 1 - 10 files changed, 472 insertions(+), 47 deletions(-) create mode 100644 src/cli/watch.rs diff --git a/README.md b/README.md index 7a5466efc..a83188b1d 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ v20.0.0 - [Task Environment Variables](#task-environment-variables) - [Running Tasks](#running-tasks) - [Running on file changes](#running-on-file-changes) - - [Watching files (coming soon)](#watching-files-coming-soon) + - [Watching files](#watching-files) - [Aliases](#aliases) - [Plugins](#plugins) - [Core Plugins](#core-plugins) @@ -173,7 +173,7 @@ v20.0.0 - [`rtx plugins update [OPTIONS] [PLUGIN]...`](#rtx-plugins-update-options-plugin) - [`rtx prune [OPTIONS] [PLUGIN]...`](#rtx-prune-options-plugin) - [`rtx reshim`](#rtx-reshim) - - [`rtx run [OPTIONS] [ARGS]...`](#rtx-run-options-task-args) + - [`rtx run [OPTIONS] [TASK] [ARGS]...`](#rtx-run-options-task-args) - [`rtx self-update [OPTIONS] [VERSION]`](#rtx-self-update-options-version) - [`rtx settings get `](#rtx-settings-get-setting) - [`rtx settings ls`](#rtx-settings-ls) @@ -182,14 +182,15 @@ v20.0.0 - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) - [`rtx sync node <--brew|--nvm|--nodenv>`](#rtx-sync-node---brew--nvm--nodenv) - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - - [`rtx task edit `](#rtx-task-edit-task) + - [`rtx task edit [OPTIONS] `](#rtx-task-edit-options-task) - [`rtx task ls [OPTIONS]`](#rtx-task-ls-options) - - [`rtx task run [OPTIONS] [ARGS]...`](#rtx-task-run-options-task-args) + - [`rtx task run [OPTIONS] [TASK] [ARGS]...`](#rtx-task-run-options-task-args) - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - [`rtx uninstall [OPTIONS] [TOOL@VERSION]...`](#rtx-uninstall-options-toolversion) - [`rtx upgrade [OPTIONS] [TOOL@VERSION]...`](#rtx-upgrade-options-toolversion) - [`rtx use [OPTIONS] [TOOL@VERSION]...`](#rtx-use-options-toolversion) - [`rtx version`](#rtx-version) + - [`rtx watch [OPTIONS] [ARGS]...`](#rtx-watch-options-args) - [`rtx where `](#rtx-where-toolversion) - [`rtx which [OPTIONS] `](#rtx-which-options-bin_name) @@ -1139,7 +1140,7 @@ it running in parallel with any other task-a RWMutex will get a write lock in th Extra arguments will be passed to the task, for example, if we want to run in release mode: ```bash -rtx r build --release +rtx run build --release ``` If there are multiple commands, the args are only passed to the last command. @@ -1147,7 +1148,13 @@ If there are multiple commands, the args are only passed to the last command. Multiple tasks/arguments can be separated with this `:::` delimiter: ```bash -rtx r build arg1 arg2 ::: test arg3 arg4 +rtx run build arg1 arg2 ::: test arg3 arg4 +``` + +rtx will run the "default" task if no task is specified. + +```bash +rtx run ``` ### Running on file changes @@ -1165,7 +1172,7 @@ outputs = ['target/debug/mycli'] Now if `target/debug/mycli` is newer than `Cargo.toml` or any ".rs" file, the task will be skipped. -### Watching files (coming soon) +### Watching files Run a task when the source changes with `rtx watch`: @@ -1173,12 +1180,18 @@ Run a task when the source changes with `rtx watch`: rtx watch -t build ``` -Define specific files to watch with `--glob`: +Currently this just shells out to watchexec-which you can install however you want including with rtx: `rtx use -g watchexec@latest`. +This may change in the future. + +Arguments to `rtx watch` will be forwarded onto watchexec. For example, to print diagnostic info: ```bash -rtx watch -t build --glob '*.rs' +rtx watch -t build -- --print-events --verbose ``` +See watchexec's help with `watchexec --help` or `rtx watch -- --help` to see +all of the options. + ## Aliases rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS @@ -2752,21 +2765,48 @@ Examples: v20.0.0 ``` -### `rtx run [OPTIONS] [ARGS]...` +### `rtx run [OPTIONS] [TASK] [ARGS]...` **Aliases:** `r` ```text [experimental] Run a task -Usage: run [OPTIONS] [ARGS]... +This command will run a task, or multiple tasks in parallel. +Tasks may have dependencies on other tasks or on source files. +If source is configured on a task, it will only run if the source +files have changed. + +Tasks can be defined in .rtx.toml or as standalone scripts. +In .rtx.toml, tasks take this form: + + [tasks.build] + run = "npm run build" + sources = ["src/**/*.ts"] + outputs = ["dist/**/*.js"] + +Alternatively, tasks can be defined as standalone scripts. +These must be located in the `.rtx/tasks` directory. +The name of the script will be the name of the task. + + $ cat .rtx/tasks/build< - Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2 + [TASK] + Task to run + Can specify multiple tasks by separating with `:::` + e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2 + + [default: default] [ARGS]... - Arguments to pass to the task + Arguments to pass to the task. Use ":::" to separate tasks Options: -C, --cd @@ -2803,8 +2843,22 @@ Options: Configure with `raw` config or `RTX_RAW` env var Examples: + $ rtx run lint + Runs the "lint" task. This needs to either be defined in .rtx.toml + or as a standalone script. See the project README for more information. + + $ rtx run build --force + Forces the "build" task to run even if its sources are up-to-date. + + $ rtx run test --raw + Runs "test" with stdin/stdout/stderr all connected to the current terminal. + This forces `--jobs=1` to prevent interleaving of output. + + $ rtx run lint ::: test ::: check + Runs the "lint", "test", and "check" tasks in parallel. + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 - TODO + Execute multiple tasks each with their own arguments. ``` ### `rtx self-update [OPTIONS] [VERSION]` @@ -2991,22 +3045,38 @@ Examples: $ rtx use -g python@3.11.0 - uses pyenv-provided python ``` -### `rtx task edit ` +### `rtx task edit [OPTIONS] ` ```text [experimental] Edit a task with $EDITOR -Usage: task edit +The task will be created as a standalone script if it does not already exist. + +Usage: task edit [OPTIONS] Arguments: Task to edit + +Options: + -p, --path + Display the path to the task instead of editing it + +Examples: + $ rtx task edit build + $ rtx task edit test ``` ### `rtx task ls [OPTIONS]` ```text -[experimental] List config files currently in use +[experimental] List available tasks to execute +These may be included from the config file or from the project's .rtx/tasks directory +rtx will merge all tasks from all parent directories into this list. + +So if you have global tasks in ~/.config/rtx/tasks/* and project-specific tasks in +~/myproject/.rtx/tasks/*, then they'll both be available but the project-specific +tasks will override the global ones if they have the same name. Usage: task ls [OPTIONS] @@ -3021,21 +3091,48 @@ Examples: $ rtx task ls ``` -### `rtx task run [OPTIONS] [ARGS]...` +### `rtx task run [OPTIONS] [TASK] [ARGS]...` **Aliases:** `r` ```text [experimental] Run a task -Usage: task run [OPTIONS] [ARGS]... +This command will run a task, or multiple tasks in parallel. +Tasks may have dependencies on other tasks or on source files. +If source is configured on a task, it will only run if the source +files have changed. + +Tasks can be defined in .rtx.toml or as standalone scripts. +In .rtx.toml, tasks take this form: + + [tasks.build] + run = "npm run build" + sources = ["src/**/*.ts"] + outputs = ["dist/**/*.js"] + +Alternatively, tasks can be defined as standalone scripts. +These must be located in the `.rtx/tasks` directory. +The name of the script will be the name of the task. + + $ cat .rtx/tasks/build< - Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2 + [TASK] + Task to run + Can specify multiple tasks by separating with `:::` + e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2 + + [default: default] [ARGS]... - Arguments to pass to the task + Arguments to pass to the task. Use ":::" to separate tasks Options: -C, --cd @@ -3072,8 +3169,22 @@ Options: Configure with `raw` config or `RTX_RAW` env var Examples: + $ rtx run lint + Runs the "lint" task. This needs to either be defined in .rtx.toml + or as a standalone script. See the project README for more information. + + $ rtx run build --force + Forces the "build" task to run even if its sources are up-to-date. + + $ rtx run test --raw + Runs "test" with stdin/stdout/stderr all connected to the current terminal. + This forces `--jobs=1` to prevent interleaving of output. + + $ rtx run lint ::: test ::: check + Runs the "lint", "test", and "check" tasks in parallel. + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 - TODO + Execute multiple tasks each with their own arguments. ``` ### `rtx trust [OPTIONS] [CONFIG_FILE]` @@ -3248,6 +3359,42 @@ Show rtx version Usage: version ``` +### `rtx watch [OPTIONS] [ARGS]...` + +**Aliases:** `w` + +```text +[experimental] Run a task watching for changes + +Usage: watch [OPTIONS] [ARGS]... + +Arguments: + [ARGS]... + Extra arguments + +Options: + -t, --task + Task to run + + [default: default] + + -g, --glob + Files to watch + Defaults to sources from the task(s) + +Examples: + $ rtx watch -t build + Runs the "build" task. Will re-run the task when any of its sources change. + Uses "sources" from the task definition to determine which files to watch. + + $ rtx watch -t build --glob src/**/*.rs + Runs the "build" task but specify the files to watch with a glob pattern. + This overrides the "sources" from the task definition. + + $ rtx run -t build --clear + Extra arguments are passed to watchexec. See `watchexec --help` for details. +``` + ### `rtx where ` ```text diff --git a/completions/_rtx b/completions/_rtx index be6324a37..c13bd2acc 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -53,6 +53,7 @@ _rtx() { (up|upgrade) __rtx_upgrade_cmd && ret=0 ;; (u|use) __rtx_use_cmd && ret=0 ;; (v|version) __rtx_version_cmd && ret=0 ;; + (w|watch) __rtx_watch_cmd && ret=0 ;; (where) __rtx_where_cmd && ret=0 ;; (which) __rtx_which_cmd && ret=0 ;; esac @@ -530,7 +531,7 @@ __rtx_reshim_cmd() { (( $+functions[__rtx_run_cmd] )) || __rtx_run_cmd() { _arguments -s -S \ - ':task:__rtx_tasks' \ + '::task:__rtx_tasks' \ '*::args:' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ @@ -687,6 +688,7 @@ return ret __rtx_task_edit_cmd() { _arguments -s -S \ ':task:__rtx_tasks' \ + '(-p --path)'{-p,--path}'[Display the path to the task instead of editing it]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' @@ -703,7 +705,7 @@ __rtx_task_ls_cmd() { (( $+functions[__rtx_task_run_cmd] )) || __rtx_task_run_cmd() { _arguments -s -S \ - ':task:__rtx_tasks' \ + '::task:__rtx_tasks' \ '*::args:' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ @@ -773,6 +775,16 @@ __rtx_version_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_watch_cmd] )) || +__rtx_watch_cmd() { + _arguments -s -S \ + '*'{-t,--task}'=[Task to run]:task:__rtx_tasks' \ + '*::args:' \ + '*'{-g,--glob}'=[Files to watch]:glob:' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} (( $+functions[__rtx_where_cmd] )) || __rtx_where_cmd() { _arguments -s -S \ @@ -829,6 +841,7 @@ __rtx_cmds() { {up,upgrade}':Upgrades outdated tool versions' {u,use}':Change the active version of a tool locally or globally.' 'version:Show rtx version' + {w,watch}':\[experimental\] Run a task watching for changes' 'where:Display the installation path for a runtime' 'which:Shows the path that a bin name points to' ) @@ -900,7 +913,7 @@ __rtx_sync_cmds() { __rtx_task_cmds() { local commands; commands=( 'edit:\[experimental\] Edit a task with \$EDITOR' - 'ls:\[experimental\] List config files currently in use' + 'ls:\[experimental\] List available tasks to execute' {r,run}':\[experimental\] Run a task' ) _describe -t commands 'command' commands "$@" diff --git a/completions/rtx.bash b/completions/rtx.bash index f01ab7ad6..fceb30e7e 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -180,6 +180,12 @@ _rtx() { rtx,version) cmd="rtx__version" ;; + rtx,w) + cmd="rtx__watch" + ;; + rtx,watch) + cmd="rtx__watch" + ;; rtx,where) cmd="rtx__where" ;; @@ -426,6 +432,9 @@ _rtx() { rtx__help,version) cmd="rtx__help__version" ;; + rtx__help,watch) + cmd="rtx__help__watch" + ;; rtx__help,where) cmd="rtx__help__where" ;; @@ -682,7 +691,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version where which render-completion render-help render-mangen help" + opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1478,7 +1487,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version where which render-completion render-help render-mangen help" + opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2429,6 +2438,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__watch) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__where) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2996,7 +3019,7 @@ _rtx() { return 0 ;; rtx__run) - opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3384,7 +3407,7 @@ _rtx() { return 0 ;; rtx__task__edit) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + opts="-p -q -v -y -h --path --debug --log-level --trace --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3490,7 +3513,7 @@ _rtx() { return 0 ;; rtx__task__run) - opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3657,6 +3680,40 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__watch) + opts="-t -g -q -v -y -h --task --glob --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --task) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --glob) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -g) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__where) opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completions/rtx.fish b/completions/rtx.fish index 79665743b..a13b2d04c 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -4,7 +4,7 @@ set -l fssf "__fish_seen_subcommand_from" complete -kxc rtx -s q -l quiet -d 'Suppress non-error messages' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' -set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version where which +set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell session' complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' complete -xc rtx -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' @@ -39,6 +39,7 @@ complete -xc rtx -n "not $fssf $others" -a uninstall -d 'Removes runtime version complete -xc rtx -n "not $fssf $others" -a upgrade -d 'Upgrades outdated tool versions' complete -xc rtx -n "not $fssf $others" -a use -d 'Change the active version of a tool locally or globally.' complete -xc rtx -n "not $fssf $others" -a version -d 'Show rtx version' +complete -xc rtx -n "not $fssf $others" -a watch -d '[experimental] Run a task watching for changes' complete -xc rtx -n "not $fssf $others" -a where -d 'Display the installation path for a runtime' complete -xc rtx -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' @@ -220,7 +221,7 @@ complete -kxc rtx -n "$fssf prune" -a "(__rtx_plugins)" -d 'Prune only versions # reshim # run -complete -kxc rtx -n "$fssf run" -d 'Arguments to pass to the task' +complete -kxc rtx -n "$fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' complete -kxc rtx -n "$fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' complete -kxc rtx -n "$fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' complete -kxc rtx -n "$fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' @@ -228,7 +229,7 @@ complete -kxc rtx -n "$fssf run" -s i -l interleave -d 'Print directly to stdout complete -kxc rtx -n "$fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' complete -kxc rtx -n "$fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' complete -kxc rtx -n "$fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' -complete -kxc rtx -n "$fssf run" -a "(__rtx_tasks)" -d 'Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2' +complete -kxc rtx -n "$fssf run" -a "(__rtx_tasks)" -d 'Task to run' complete -kxc rtx -n "$fssf run" -s t -l tool -a "(__rtx_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' # self-update @@ -282,10 +283,11 @@ complete -kxc rtx -n "$fssf task" -l hidden -d 'Show hidden tasks' complete -kxc rtx -n "$fssf task" -l no-header -d 'Do not print table header' set -l others edit ls run complete -xc rtx -n "$fssf task; and not $fssf $others" -a edit -d '[experimental] Edit a task with $EDITOR' -complete -xc rtx -n "$fssf task; and not $fssf $others" -a ls -d '[experimental] List config files currently in use' +complete -xc rtx -n "$fssf task; and not $fssf $others" -a ls -d '[experimental] List available tasks to execute' complete -xc rtx -n "$fssf task; and not $fssf $others" -a run -d '[experimental] Run a task' # task edit +complete -kxc rtx -n "$fssf task; and $fssf edit" -s p -l path -d 'Display the path to the task instead of editing it' complete -kxc rtx -n "$fssf task; and $fssf edit" -a "(__rtx_tasks)" -d 'Task to edit' # task ls @@ -293,7 +295,7 @@ complete -kxc rtx -n "$fssf task; and $fssf ls" -l hidden -d 'Show hidden tasks' complete -kxc rtx -n "$fssf task; and $fssf ls" -l no-header -d 'Do not print table header' # task run -complete -kxc rtx -n "$fssf task; and $fssf run" -d 'Arguments to pass to the task' +complete -kxc rtx -n "$fssf task; and $fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' complete -kxc rtx -n "$fssf task; and $fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' complete -kxc rtx -n "$fssf task; and $fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' complete -kxc rtx -n "$fssf task; and $fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' @@ -301,7 +303,7 @@ complete -kxc rtx -n "$fssf task; and $fssf run" -s i -l interleave -d 'Print di complete -kxc rtx -n "$fssf task; and $fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' complete -kxc rtx -n "$fssf task; and $fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' complete -kxc rtx -n "$fssf task; and $fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' -complete -kxc rtx -n "$fssf task; and $fssf run" -a "(__rtx_tasks)" -d 'Task to run Can specify multiple tasks by separating with `:::` e.g.: rtx run task1 arg1 arg2 ::: task2 arg1 arg2' +complete -kxc rtx -n "$fssf task; and $fssf run" -a "(__rtx_tasks)" -d 'Task to run' complete -kxc rtx -n "$fssf task; and $fssf run" -s t -l tool -a "(__rtx_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' @@ -336,6 +338,11 @@ complete -kxc rtx -n "$fssf use" -a "(__rtx_tool_versions)" -d 'Tool(s) to add t # version +# watch +complete -kxc rtx -n "$fssf watch" -d 'Extra arguments' +complete -kxc rtx -n "$fssf watch" -s g -l glob -d 'Files to watch' +complete -kxc rtx -n "$fssf watch" -s t -l task -a "(__rtx_tasks)" -d 'Task to run' + # where complete -kxc rtx -n "$fssf where" -a "(__rtx_tool_versions)" -d 'Tool(s) to look up' diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 211d3e3df..b86181736 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -50,6 +50,7 @@ mod uninstall; mod upgrade; mod r#use; pub mod version; +mod watch; mod r#where; mod r#which; @@ -95,6 +96,7 @@ pub enum Commands { Upgrade(upgrade::Upgrade), Use(r#use::Use), Version(version::Version), + Watch(watch::Watch), Where(r#where::Where), Which(which::Which), @@ -149,6 +151,7 @@ impl Commands { Self::Upgrade(cmd) => cmd.run(), Self::Use(cmd) => cmd.run(), Self::Version(cmd) => cmd.run(), + Self::Watch(cmd) => cmd.run(), Self::Where(cmd) => cmd.run(), Self::Which(cmd) => cmd.run(), diff --git a/src/cli/run.rs b/src/cli/run.rs index bfeeabd07..4380312c2 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -31,15 +31,39 @@ use crate::ui::style; use crate::{env, file, ui}; /// [experimental] Run a task +/// +/// This command will run a task, or multiple tasks in parallel. +/// Tasks may have dependencies on other tasks or on source files. +/// If source is configured on a task, it will only run if the source +/// files have changed. +/// +/// Tasks can be defined in .rtx.toml or as standalone scripts. +/// In .rtx.toml, tasks take this form: +/// +/// [tasks.build] +/// run = "npm run build" +/// sources = ["src/**/*.ts"] +/// outputs = ["dist/**/*.js"] +/// +/// Alternatively, tasks can be defined as standalone scripts. +/// These must be located in the `.rtx/tasks` directory. +/// The name of the script will be the name of the task. +/// +/// $ cat .rtx/tasks/build<, @@ -156,9 +180,6 @@ impl Run { } fn run_task(&self, config: &Config, env: &BTreeMap, task: &Task) -> Result<()> { - if self.dry_run { - return Ok(()); - } let prefix = style::estyle(task.prefix()).fg(get_color()).to_string(); if !self.force && self.sources_are_fresh(config, task) { info_unprefix_trunc!("{prefix} sources up-to-date, skipping"); @@ -250,6 +271,9 @@ impl Run { if let Some(cd) = &self.cd.as_ref().or(task.dir.as_ref()) { cmd = cmd.current_dir(cd); } + if self.dry_run { + return Ok(()); + } if let Err(err) = cmd.execute() { if let Some(ScriptFailed(_, Some(status))) = err.downcast_ref::() { if let Some(code) = status.code() { @@ -370,8 +394,22 @@ impl Run { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: + $ rtx run lint + Runs the "lint" task. This needs to either be defined in .rtx.toml + or as a standalone script. See the project README for more information. + + $ rtx run build --force + Forces the "build" task to run even if its sources are up-to-date. + + $ rtx run test --raw + Runs "test" with stdin/stdout/stderr all connected to the current terminal. + This forces `--jobs=1` to prevent interleaving of output. + + $ rtx run lint ::: test ::: check + Runs the "lint", "test", and "check" tasks in parallel. + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 - TODO + Execute multiple tasks each with their own arguments. "# ); diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs index 94d82269c..d13f4b8e2 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/task/edit.rs @@ -5,12 +5,18 @@ use crate::task::Task; use crate::{env, file}; /// [experimental] Edit a task with $EDITOR +/// +/// The task will be created as a standalone script if it does not already exist. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct TaskEdit { /// Task to edit #[clap()] task: String, + + /// Display the path to the task instead of editing it + #[clap(long, short, verbatim_doc_comment)] + path: bool, } impl TaskEdit { @@ -37,8 +43,19 @@ impl TaskEdit { file::create(file)?; file::make_executable(file)?; } - cmd!(&*env::EDITOR, &file).run()?; + if self.path { + rtxprintln!("{}", file.display()); + } else { + cmd!(&*env::EDITOR, &file).run()?; + } Ok(()) } } + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx task edit build + $ rtx task edit test +"# +); diff --git a/src/cli/task/ls.rs b/src/cli/task/ls.rs index fa2df8728..a62b37491 100644 --- a/src/cli/task/ls.rs +++ b/src/cli/task/ls.rs @@ -9,7 +9,13 @@ use crate::config::{Config, Settings}; use crate::file::display_path; use crate::ui::{style, table}; -/// [experimental] List config files currently in use +/// [experimental] List available tasks to execute +/// These may be included from the config file or from the project's .rtx/tasks directory +/// rtx will merge all tasks from all parent directories into this list. +/// +/// So if you have global tasks in ~/.config/rtx/tasks/* and project-specific tasks in +/// ~/myproject/.rtx/tasks/*, then they'll both be available but the project-specific +/// tasks will override the global ones if they have the same name. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct TaskLs { diff --git a/src/cli/watch.rs b/src/cli/watch.rs new file mode 100644 index 000000000..f10aee472 --- /dev/null +++ b/src/cli/watch.rs @@ -0,0 +1,138 @@ +use std::process::exit; + +use console::style; + +use eyre::Result; + +use crate::config::{Config, Settings}; + +use crate::cmd; +use crate::toolset::ToolsetBuilder; + +/// [experimental] Run a task watching for changes +#[derive(Debug, clap::Args)] +#[clap(visible_alias = "w", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct Watch { + /// Task to run + #[clap(short, long, verbatim_doc_comment, default_value = "default")] + task: Vec, + + /// Extra arguments + #[clap(allow_hyphen_values = true)] + args: Vec, + + /// Files to watch + /// Defaults to sources from the task(s) + #[clap(short, long, verbatim_doc_comment)] + glob: Vec, + // /// Change to this directory before executing the command + // #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)] + // pub cd: Option, + // + // /// Don't actually run the task(s), just print them in order of execution + // #[clap(long, short = 'n', verbatim_doc_comment)] + // pub dry_run: bool, + // + // /// Force the task to run even if outputs are up to date + // #[clap(long, short, verbatim_doc_comment)] + // pub force: bool, + // + // /// Print stdout/stderr by line, prefixed with the task's label + // /// Defaults to true if --jobs > 1 + // /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + // #[clap(long, short, verbatim_doc_comment, overrides_with = "interleave")] + // pub prefix: bool, + // + // /// Print directly to stdout/stderr instead of by line + // /// Defaults to true if --jobs == 1 + // /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + // #[clap(long, short, verbatim_doc_comment, overrides_with = "prefix")] + // pub interleave: bool, + // + // /// Tool(s) to also add + // /// e.g.: node@20 python@3.10 + // #[clap(short, long, value_name = "TOOL@VERSION", value_parser = ToolArgParser)] + // pub tool: Vec, + // + // /// Number of tasks to run in parallel + // /// [default: 4] + // /// Configure with `jobs` config or `RTX_JOBS` env var + // #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + // pub jobs: Option, + // + // /// Read/write directly to stdin/stdout/stderr instead of by line + // /// Configure with `raw` config or `RTX_RAW` env var + // #[clap(long, short, verbatim_doc_comment)] + // pub raw: bool, +} + +impl Watch { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let settings = Settings::try_get()?; + let ts = ToolsetBuilder::new().build(&config)?; + settings.ensure_experimental()?; + if let Err(err) = which::which("watchexec") { + if !ts.versions.contains_key("watchexec") { + eprintln!("{}: {}", style("Error").red().bold(), err); + eprintln!("{}: Install watchexec with:", style("Hint").bold()); + eprintln!(" rtx use -g watchexec@latest"); + exit(1); + } + } + let tasks = self + .task + .iter() + .map(|t| { + config + .tasks() + .get(t) + .cloned() + .ok_or_else(|| eyre!("Task not found: {t}")) + }) + .collect::>>()?; + let mut args = vec![]; + let globs = if self.glob.is_empty() { + tasks + .iter() + .flat_map(|t| t.sources.clone()) + .collect::>() + } else { + self.glob.clone() + }; + if !globs.is_empty() { + args.push("-f".to_string()); + args.extend(itertools::intersperse(globs, "-f".to_string()).collect::>()); + } + args.extend(self.args.clone()); + args.extend(["--".to_string(), "rtx".to_string(), "run".to_string()]); + for arg in itertools::intersperse(tasks.iter().map(|t| t.name.as_str()), ":::") { + args.push(arg.to_string()); + } + info!("$ watchexec {}", args.join(" ")); + let mut cmd = cmd::cmd("watchexec", &args); + for (k, v) in ts.env_with_path(&config) { + cmd = cmd.env(k, v); + } + if let Some(root) = &config.project_root { + cmd = cmd.dir(root); + } + cmd.run()?; + Ok(()) + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ rtx watch -t build + Runs the "build" task. Will re-run the task when any of its sources change. + Uses "sources" from the task definition to determine which files to watch. + + $ rtx watch -t build --glob src/**/*.rs + Runs the "build" task but specify the files to watch with a glob pattern. + This overrides the "sources" from the task definition. + + $ rtx run -t build --clear + Extra arguments are passed to watchexec. See `watchexec --help` for details. +"# +); diff --git a/src/config/settings.rs b/src/config/settings.rs index 708aa8919..352fa6e68 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -83,7 +83,6 @@ impl Settings { } let mut settings = Self::default_builder().load()?; if settings.raw { - settings.verbose = true; settings.jobs = 1; } if settings.debug { From c3c7a62577b9b1937d9fbd02257680d0a6a194d4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 08:22:22 -0600 Subject: [PATCH 1427/1891] chore: Release rtx-cli version 2023.12.37 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad5059ae8..9c5c67b07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1875,7 +1875,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.36" +version = "2023.12.37" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index ff6654317..f54030949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.36" +version = "2023.12.37" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index a83188b1d..9e420dd7f 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.36 +rtx 2023.12.37 ``` Hook rtx into your shell (pick the right one for your shell): @@ -374,7 +374,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.36/rtx-v2023.12.36-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.37/rtx-v2023.12.37-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 9690f67a2..af056b38a 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.36"; + version = "2023.12.37"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 9ac9b5a25..e0d0b29b2 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.36 +Version: 2023.12.37 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From bcba6e21d1c63c24ffa9c78203f3ce1cc00f08a9 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 09:09:59 -0600 Subject: [PATCH 1428/1891] Update README.md --- README.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9e420dd7f..dd0521d1a 100644 --- a/README.md +++ b/README.md @@ -1044,6 +1044,13 @@ running linters, tests, builders, servers, and other tasks that are specific to tasks launched with rtx will include the tool environment (tools and env vars) even if rtx has not been otherwise activated. +Here's my favorite features about rtx's task runner: + +* building dependencies in parallel—by default with no configuration required +* last-modified checking to avoid rebuilding when there are no changes—requires minimal config +* `rtx watch` to automatically rebuild on changes—no configuration required, but it helps +* ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack syntax highlighting and linting/checking support + > **Warning** > > This is an experimental feature. It is not yet stable and will likely change. Some of the docs @@ -1052,7 +1059,7 @@ activated. ### Script-based Tasks -Tasks can be defined in 2 ways, either as standalone script files in `.rtx/tasks` such as the following build script +Tasks can be defined in 2 ways, either as standalone script files in `.rtx/tasks/:task_name` such as the following build script for cargo: ```bash @@ -1075,14 +1082,15 @@ cargo build > # rtx depends=["lint", "test"] > ``` -Assuming that file was located in `.rtx/tasks/build`, it could be run with `rtx run build`. -This script can also be edited with $EDITOR by running `rtx task edit build`, if it doesn't exist it will be created. +Assuming that file was located in `.rtx/tasks/build`, it can then be run with `rtx run build` (or with its alias: `rtx run b`). +This script can be edited with by running `rtx task edit build` (using $EDITOR). If it doesn't exist it will be created. These are convenient for quickly making new scripts. Having the code in a bash file and not TOML helps make it work -better in editors since they can do syntax highlighting and linting more easily. +better in editors since they can do syntax highlighting and linting more easily. They also still work great for non-rtx users—though +of course they'll need to find a different way to install their dev tools the tasks might use. ### Config-based Tasks -Tasks can also be defined in `.rtx.toml` files in different ways: +Tasks can also be defined in `.rtx.toml` files in different ways. This is a more "traditional" method of defining tasks: ```toml task.clean = 'cargo clean && rm -rf .cache' # runs as a shell command @@ -1151,7 +1159,7 @@ Multiple tasks/arguments can be separated with this `:::` delimiter: rtx run build arg1 arg2 ::: test arg3 arg4 ``` -rtx will run the "default" task if no task is specified. +rtx will run the task named "default" if no task is specified—and you've created one named "default". You can also alias a different task to "default". ```bash rtx run @@ -1160,7 +1168,7 @@ rtx run ### Running on file changes It's often handy to only execute a task if the files it uses changes. For example, we might only want -to run `cargo build` if a ".rs" file changes. This can be done with the following task config: +to run `cargo build` if an ".rs" file changes. This can be done with the following config: ```toml [task.build] @@ -1170,7 +1178,8 @@ sources = ['Cargo.toml', 'src/**/*.rs'] # skip running if these files haven't ch outputs = ['target/debug/mycli'] ``` -Now if `target/debug/mycli` is newer than `Cargo.toml` or any ".rs" file, the task will be skipped. +Now if `target/debug/mycli` is newer than `Cargo.toml` or any ".rs" file, the task will be skipped. This uses last modified timestamps. +It wouldn't be hard to add checksum support. ### Watching files From aba4495270920a68964e18e16e23e650b3d7eb19 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 09:14:36 -0600 Subject: [PATCH 1429/1891] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dd0521d1a..66c8cf2e8 100644 --- a/README.md +++ b/README.md @@ -14,15 +14,15 @@ ## Features -- **asdf-compatible** - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. [See below for migration instructions](#how-do-i-migrate-from-asdf) - **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. - **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. - **No shims** - shims cause problems, they break `which`, and add overhead. By default, rtx does not use them—however you can if you want to. -- **Fuzzy matching and aliases** - It's enough to just say you want "v20" of node, or the "lts" +- [**Arbitrary env vars**](#env---arbitrary-environment-variables) - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. +- [**Task runner**](#experimental-task-runner) - Define project-specific tasks like `test` or `lint`. Supports parallel execution and file watching. +- [**asdf-compatible**](#how-do-i-migrate-from-asdf) - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. +- [**Fuzzy matching and aliases**](#plugins) - It's enough to just say you want "v20" of node, or the "lts" version. rtx will figure out the right version without you needing to specify an exact version. -- **Arbitrary env vars** - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. -- **Task runner** - Define project-specific tasks like `test` or `lint`. Supports parallel execution and file watching. ## 30 Second Demo From fdb2a69ad815d7b4cf10f51aeed0989bcf974c0e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 09:15:59 -0600 Subject: [PATCH 1430/1891] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 66c8cf2e8..25e48921c 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ ## Features -- **Polyglot** - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. -- **Fast** - rtx is written in Rust and is very fast. 20x-200x faster than asdf. -- **No shims** - shims cause problems, they break `which`, and add overhead. By default, rtx +- [**Polyglot**](#plugins) - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. +- [**Fast**](#performance) - rtx is written in Rust and is very fast. 20x-200x faster than asdf. +- [**No shims**](#shims) - shims cause problems, they break `which`, and add overhead. By default, rtx does not use them—however you can if you want to. - [**Arbitrary env vars**](#env---arbitrary-environment-variables) - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. - [**Task runner**](#experimental-task-runner) - Define project-specific tasks like `test` or `lint`. Supports parallel execution and file watching. - [**asdf-compatible**](#how-do-i-migrate-from-asdf) - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. -- [**Fuzzy matching and aliases**](#plugins) - It's enough to just say you want "v20" of node, or the "lts" +- [**Fuzzy matching and aliases**](#aliases) - It's enough to just say you want "v20" of node, or the "lts" version. rtx will figure out the right version without you needing to specify an exact version. ## 30 Second Demo From 3d55aef6233565846d931b851806fa3b10c90e96 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 09:19:58 -0600 Subject: [PATCH 1431/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 25e48921c..2a9fd1e45 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ - [**No shims**](#shims) - shims cause problems, they break `which`, and add overhead. By default, rtx does not use them—however you can if you want to. - [**Arbitrary env vars**](#env---arbitrary-environment-variables) - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. -- [**Task runner**](#experimental-task-runner) - Define project-specific tasks like `test` or `lint`. Supports parallel execution and file watching. +- [**Task runner**](#experimental-task-runner) - Define project-specific tasks like `test` or `lint`. Supports parallel execution and "watch" support to rerun on source changes. - [**asdf-compatible**](#how-do-i-migrate-from-asdf) - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. - [**Fuzzy matching and aliases**](#aliases) - It's enough to just say you want "v20" of node, or the "lts" version. rtx will figure out the right version without you needing to specify an exact version. From a8f384ec6e130802d0278bc798c397c96b556987 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 09:25:51 -0600 Subject: [PATCH 1432/1891] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2a9fd1e45..2cac7ac14 100644 --- a/README.md +++ b/README.md @@ -1039,10 +1039,9 @@ This can also be useful in environments where rtx isn't activated ## [experimental] Task Runner -You can define tasks in `.rtx.toml` files or as standalone files. These are useful for things like +You can define tasks in `.rtx.toml` files or as standalone shell scripts. These are useful for things like running linters, tests, builders, servers, and other tasks that are specific to a project. Of course, -tasks launched with rtx will include the tool environment (tools and env vars) even if rtx has not been otherwise -activated. +tasks launched with rtx will include the rtx environment—your tools and env vars defined in `.rtx.toml`. Here's my favorite features about rtx's task runner: @@ -1057,7 +1056,7 @@ Here's my favorite features about rtx's task runner: > may not be implemented, may be implemented incorrectly, or the docs may need to be updated. > Please give feedback early since while it's experimental it's much easier to change. -### Script-based Tasks +### Script Tasks Tasks can be defined in 2 ways, either as standalone script files in `.rtx/tasks/:task_name` such as the following build script for cargo: @@ -1088,7 +1087,7 @@ These are convenient for quickly making new scripts. Having the code in a bash f better in editors since they can do syntax highlighting and linting more easily. They also still work great for non-rtx users—though of course they'll need to find a different way to install their dev tools the tasks might use. -### Config-based Tasks +### TOML-based Tasks Tasks can also be defined in `.rtx.toml` files in different ways. This is a more "traditional" method of defining tasks: From 5cb9e2536dbbb036df964483d9bd0cccc9c2c2bb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 11:14:00 -0600 Subject: [PATCH 1433/1891] not-found handler (#1267) * not-found handler * Commit from GitHub Actions (test) * docs * zsh --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- README.md | 17 ++++--- completions/_rtx | 10 ++++ completions/rtx.bash | 50 ++++++++++++++++++- src/cli/hook_env.rs | 2 +- src/cli/hook_not_found.rs | 35 +++++++++++++ src/cli/mod.rs | 3 ++ ...cli__settings__ls__tests__settings_ls.snap | 1 + ...i__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + ...__config_file__rtx_toml__tests__env-5.snap | 1 + ...nfig_file__rtx_toml__tests__fixture-2.snap | 1 + ...nfig_file__rtx_toml__tests__fixture-6.snap | 1 + ...ig_file__rtx_toml__tests__path_dirs-5.snap | 1 + ...file__rtx_toml__tests__remove_alias-4.snap | 1 + ...ile__rtx_toml__tests__remove_plugin-4.snap | 1 + ...__rtx_toml__tests__replace_versions-4.snap | 1 + src/config/settings.rs | 2 + src/shell/bash.rs | 17 +++++++ src/shell/fish.rs | 12 +++++ .../rtx__shell__bash__tests__hook_init.snap | 12 +++++ ...tx__shell__bash__tests__hook_init_nix.snap | 12 +++++ .../rtx__shell__fish__tests__hook_init.snap | 7 +++ ...tx__shell__fish__tests__hook_init_nix.snap | 7 +++ .../rtx__shell__zsh__tests__hook_init.snap | 9 ++++ ...rtx__shell__zsh__tests__hook_init_nix.snap | 9 ++++ src/shell/zsh.rs | 14 ++++++ src/shims.rs | 11 +++- src/toolset/mod.rs | 27 ++++++++++ 28 files changed, 256 insertions(+), 10 deletions(-) create mode 100644 src/cli/hook_not_found.rs diff --git a/README.md b/README.md index 2cac7ac14..1d36692d5 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,8 @@ v20.0.0 - [Environment variables](#environment-variables) - [Shebang](#shebang) - [[experimental] Task Runner](#experimental-task-runner) - - [Script-based Tasks](#script-based-tasks) - - [Config-based Tasks](#config-based-tasks) + - [Script Tasks](#script-tasks) + - [TOML-based Tasks](#toml-based-tasks) - [Task Environment Variables](#task-environment-variables) - [Running Tasks](#running-tasks) - [Running on file changes](#running-on-file-changes) @@ -796,6 +796,7 @@ jobs = 4 # number of plugins or runtimes to install in parallel. The raw = false # set to true to directly pipe plugins to stdin/stdout/stderr yes = false # set to true to automatically answer yes to all prompts +not_found_auto_install = true task_output = "prefix" # see Task Runner for more information shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` @@ -994,6 +995,10 @@ all. This will automatically answer yes or no to prompts. This is useful for scripting. +#### `RTX_NOT_FOUND_AUTO_INSTALL=true` + +Set to false to disable the "command not found" handler to autoinstall missing tool versions. + #### `RTX_TASK_OUTPUT=prefix` This controls the output of `rtx run`. It can be one of: @@ -1045,10 +1050,10 @@ tasks launched with rtx will include the rtx environment—your tools and env va Here's my favorite features about rtx's task runner: -* building dependencies in parallel—by default with no configuration required -* last-modified checking to avoid rebuilding when there are no changes—requires minimal config -* `rtx watch` to automatically rebuild on changes—no configuration required, but it helps -* ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack syntax highlighting and linting/checking support +- building dependencies in parallel—by default with no configuration required +- last-modified checking to avoid rebuilding when there are no changes—requires minimal config +- `rtx watch` to automatically rebuild on changes—no configuration required, but it helps +- ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack syntax highlighting and linting/checking support > **Warning** > diff --git a/completions/_rtx b/completions/_rtx index c13bd2acc..f87c05ba2 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -31,6 +31,7 @@ _rtx() { (x|exec) __rtx_exec_cmd && ret=0 ;; (g|global) __rtx_global_cmd && ret=0 ;; (hook-env) __rtx_hook_env_cmd && ret=0 ;; + (hook-not-found) __rtx_hook_not_found_cmd && ret=0 ;; (implode) __rtx_implode_cmd && ret=0 ;; (i|install) __rtx_install_cmd && ret=0 ;; (latest) __rtx_latest_cmd && ret=0 ;; @@ -340,6 +341,15 @@ __rtx_hook_env_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' } +(( $+functions[__rtx_hook_not_found_cmd] )) || +__rtx_hook_not_found_cmd() { + _arguments -s -S \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ + ':bin:' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' +} (( $+functions[__rtx_implode_cmd] )) || __rtx_implode_cmd() { _arguments -s -S \ diff --git a/completions/rtx.bash b/completions/rtx.bash index fceb30e7e..f768eebd5 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -72,6 +72,9 @@ _rtx() { rtx,hook-env) cmd="rtx__hook__env" ;; + rtx,hook-not-found) + cmd="rtx__hook__not__found" + ;; rtx,i) cmd="rtx__install" ;; @@ -357,6 +360,9 @@ _rtx() { rtx__help,hook-env) cmd="rtx__help__hook__env" ;; + rtx__help,hook-not-found) + cmd="rtx__help__hook__not__found" + ;; rtx__help,implode) cmd="rtx__help__implode" ;; @@ -691,7 +697,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" + opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1487,7 +1493,7 @@ _rtx() { return 0 ;; rtx__help) - opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" + opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1878,6 +1884,20 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__help__hook__not__found) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__help__implode) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -2506,6 +2526,32 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + rtx__hook__not__found) + opts="-s -q -v -y -h --shell --debug --log-level --trace --quiet --verbose --yes --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; rtx__implode) opts="-n -q -v -y -h --config --dry-run --debug --log-level --trace --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 161da5acf..0fd84e332 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -69,8 +69,8 @@ impl HookEnv { rtxprint!("{output}"); if self.status { self.display_status(&config, &ts); + ts.notify_if_versions_missing(); } - ts.notify_if_versions_missing(); Ok(()) } diff --git a/src/cli/hook_not_found.rs b/src/cli/hook_not_found.rs new file mode 100644 index 000000000..1b51765a4 --- /dev/null +++ b/src/cli/hook_not_found.rs @@ -0,0 +1,35 @@ +use std::process::exit; + +use eyre::Result; + +use crate::config::{Config, Settings}; + +use crate::shell::ShellType; +use crate::toolset::ToolsetBuilder; + +/// [internal] called by shell when a command is not found +#[derive(Debug, clap::Args)] +#[clap(hide = true)] +pub struct HookNotFound { + /// Shell type to generate script for + #[clap(long, short)] + shell: Option, + + /// Attempted bin to run + #[clap()] + bin: String, +} + +impl HookNotFound { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let settings = Settings::try_get()?; + if settings.not_found_auto_install { + let mut ts = ToolsetBuilder::new().build(&config)?; + if ts.install_missing_bin(&self.bin)?.is_some() { + return Ok(()); + } + } + exit(127); + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b86181736..0683e4cab 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -22,6 +22,7 @@ pub mod exec; mod external; mod global; mod hook_env; +mod hook_not_found; mod implode; mod install; mod latest; @@ -74,6 +75,7 @@ pub enum Commands { Exec(exec::Exec), Global(global::Global), HookEnv(hook_env::HookEnv), + HookNotFound(hook_not_found::HookNotFound), Implode(implode::Implode), Install(install::Install), Latest(latest::Latest), @@ -129,6 +131,7 @@ impl Commands { Self::Exec(cmd) => cmd.run(), Self::Global(cmd) => cmd.run(), Self::HookEnv(cmd) => cmd.run(), + Self::HookNotFound(cmd) => cmd.run(), Self::Implode(cmd) => cmd.run(), Self::Install(cmd) => cmd.run(), Self::Latest(cmd) => cmd.run(), diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index d286b64ea..00d01cd1a 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -12,6 +12,7 @@ experimental = true jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] +not_found_auto_install = true plugin_autoupdate_last_check_duration = "20m" quiet = false raw = false diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index c3c33295e..1b8a3ef78 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -12,6 +12,7 @@ experimental = true jobs = 2 legacy_version_file = false legacy_version_file_disable_tools = [] +not_found_auto_install = true plugin_autoupdate_last_check_duration = "1m" quiet = false raw = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 787750cc4..b84a44f26 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -50,6 +50,7 @@ mod tests { jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] + not_found_auto_install = true plugin_autoupdate_last_check_duration = "20m" quiet = false raw = false diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap index 36e4c96f5..a0050ed78 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap @@ -17,6 +17,7 @@ RtxToml(/tmp/.rtx.toml): { "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, "log_level": Null, + "not_found_auto_install": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index d31bba6f0..865dfd784 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -28,5 +28,6 @@ expression: cf.settings().unwrap() "raw": null, "yes": null, "task_output": null, + "not_found_auto_install": null, "ci": null } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index afface3d4..a1465bae9 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -21,6 +21,7 @@ RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref: String("disabled_tool_from_legacy_file"), ], "log_level": Null, + "not_found_auto_install": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap index ab2146ca5..ac7cfbeca 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap @@ -17,6 +17,7 @@ RtxToml(~/fixtures/.rtx.toml): { "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, "log_level": Null, + "not_found_auto_install": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap index 965323699..008bdff73 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap @@ -17,6 +17,7 @@ RtxToml(/tmp/.rtx.toml): { "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, "log_level": Null, + "not_found_auto_install": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap index 0e6aba27b..b8fbed129 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap @@ -17,6 +17,7 @@ RtxToml(/tmp/.rtx.toml): { "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, "log_level": Null, + "not_found_auto_install": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap index 806c4f308..e631174c1 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap @@ -17,6 +17,7 @@ RtxToml(/tmp/.rtx.toml): node@16.0.1 node@18.0.1 { "legacy_version_file": Null, "legacy_version_file_disable_tools": Null, "log_level": Null, + "not_found_auto_install": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/settings.rs b/src/config/settings.rs index 352fa6e68..2a58433e7 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -58,6 +58,8 @@ pub struct Settings { pub yes: bool, #[config(env = "RTX_TASK_OUTPUT")] pub task_output: Option, + #[config(env = "RTX_NOT_FOUND_AUTO_INSTALL", default = true)] + pub not_found_auto_install: bool, #[config(env = "CI", default = false)] pub ci: bool, } diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 2492824f9..c2ef39488 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -1,3 +1,4 @@ +use crate::config::Settings; use std::path::Path; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; @@ -47,6 +48,22 @@ impl Shell for Bash { PROMPT_COMMAND="_rtx_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" fi "#}); + if Settings::get().not_found_auto_install { + out.push_str(&formatdoc! {r#" + eval 'command_not_found_handle() {{ + local ret + if (( ! IN_CNFH++)) && {exe} hook-not-found -s bash "$1"; then + _rtx_hook + "$@" + ret=$? + (( IN_CNFH-- )) + return "$ret" + fi + (( IN_CNFH-- )) + '"$(typeset -f command_not_found_handle | tail -n +2)"' + }}' + "#}); + } out } diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 936e0c678..6fa97df91 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -1,3 +1,4 @@ +use crate::config::Settings; use std::path::Path; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; @@ -75,6 +76,17 @@ impl Shell for Fish { functions --erase __rtx_cd_hook; end; "#}); + if Settings::get().not_found_auto_install { + out.push_str(&formatdoc! {r#" + function fish_command_not_found + if {exe} hook-not-found -s fish $argv[1] + {exe} hook-env{flags} -s fish | source + else + __fish_default_command_not_found_handler $argv + end + end + "#}); + } out } diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 6b39184b3..70e6030b3 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -35,4 +35,16 @@ _rtx_hook() { if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi +eval 'command_not_found_handle() { +local ret + if (( ! IN_CNFH++)) && /some/dir/rtx hook-not-found -s bash "$1"; then + _rtx_hook + "$@" + ret=$? + (( IN_CNFH-- )) + return "$ret" + fi + (( IN_CNFH-- )) + '"$(typeset -f command_not_found_handle | tail -n +2)"' +}' diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index f202bf9fe..b11bcddbe 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -34,4 +34,16 @@ _rtx_hook() { if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi +eval 'command_not_found_handle() { +local ret + if (( ! IN_CNFH++)) && /nix/store/rtx hook-not-found -s bash "$1"; then + _rtx_hook + "$@" + ret=$? + (( IN_CNFH-- )) + return "$ret" + fi + (( IN_CNFH-- )) + '"$(typeset -f command_not_found_handle | tail -n +2)"' +}' diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap index 7bd36e638..e79cca36d 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap @@ -58,4 +58,11 @@ function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx envi functions --erase __rtx_cd_hook; end; +function fish_command_not_found + if /some/dir/rtx hook-not-found -s fish $argv[1] + /some/dir/rtx hook-env --status -s fish | source + else + __fish_default_command_not_found_handler $argv + end +end diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap index 9a512e991..1a9296e35 100644 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap @@ -57,4 +57,11 @@ function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx envi functions --erase __rtx_cd_hook; end; +function fish_command_not_found + if /nix/store/rtx hook-not-found -s fish $argv[1] + /nix/store/rtx hook-env --status -s fish | source + else + __fish_default_command_not_found_handler $argv + end +end diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index f5bd0c33a..d1f12a3d2 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -39,3 +39,12 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi +function command_not_found_handler() { + /some/dir/rtx hook-not-found -s zsh "$1" + if (( $? == 0 )); then + _rtx_hook + "$@" + return $? + fi +} + diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap index d74ba184f..eb400370c 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -38,3 +38,12 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi +function command_not_found_handler() { + /nix/store/rtx hook-not-found -s zsh "$1" + if (( $? == 0 )); then + _rtx_hook + "$@" + return $? + fi +} + diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 5423bb80b..c09edd771 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -1,3 +1,4 @@ +use crate::config::Settings; use std::path::Path; use crate::shell::bash::Bash; @@ -53,7 +54,20 @@ impl Shell for Zsh { if [[ -z "${{chpwd_functions[(r)_rtx_hook]+1}}" ]]; then chpwd_functions=( _rtx_hook ${{chpwd_functions[@]}} ) fi + + "#}); + if Settings::get().not_found_auto_install { + out.push_str(&formatdoc! {r#" + function command_not_found_handler() {{ + {exe} hook-not-found -s zsh "$1" + if (( $? == 0 )); then + _rtx_hook + "$@" + return $? + fi + }} "#}); + } out } diff --git a/src/shims.rs b/src/shims.rs index dbadc1f92..c8c202935 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -46,12 +46,21 @@ pub fn handle_shim() -> Result<()> { fn which_shim(bin_name: &str) -> Result { let config = Config::try_get()?; - let ts = ToolsetBuilder::new().build(&config)?; + let mut ts = ToolsetBuilder::new().build(&config)?; if let Some((p, tv)) = ts.which(bin_name) { if let Some(bin) = p.which(&tv, bin_name)? { return Ok(bin); } } + let settings = Settings::try_get()?; + if settings.not_found_auto_install { + for tv in ts.install_missing_bin(bin_name)?.unwrap_or_default() { + let p = config.get_or_create_plugin(&tv.plugin_name); + if let Some(bin) = p.which(&tv, bin_name)? { + return Ok(bin); + } + } + } // fallback for "system" for path in &*env::PATH { if fs::canonicalize(path).unwrap_or_default() diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 148ed192f..d9f823915 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -345,6 +345,33 @@ impl Toolset { } }) } + pub fn install_missing_bin(&mut self, bin_name: &str) -> Result>> { + let config = Config::try_get()?; + let plugins = self + .list_installed_versions(&config)? + .into_iter() + .filter(|(p, tv)| { + if let Ok(x) = p.which(tv, bin_name) { + x.is_some() + } else { + false + } + }) + .collect_vec(); + for (plugin, _) in plugins { + let versions = self + .list_missing_versions() + .into_iter() + .filter(|tv| tv.plugin_name == plugin.name()) + .collect_vec(); + if !versions.is_empty() { + let mpr = MultiProgressReport::get(); + self.install_versions(&config, versions.clone(), &mpr, &InstallOptions::new())?; + return Ok(Some(versions)); + } + } + Ok(None) + } pub fn list_rtvs_with_bin(&self, config: &Config, bin_name: &str) -> Result> { Ok(self From 68b0da21f87a2486f8cacfb1350a5557dcbccb8d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 11:14:57 -0600 Subject: [PATCH 1434/1891] chore: Release rtx-cli version 2023.12.38 --- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c5c67b07..302c887fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -808,42 +808,42 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", @@ -1875,7 +1875,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.37" +version = "2023.12.38" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index f54030949..8b6ec0782 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.37" +version = "2023.12.38" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 1d36692d5..15d992bb3 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.37 +rtx 2023.12.38 ``` Hook rtx into your shell (pick the right one for your shell): @@ -374,7 +374,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.37/rtx-v2023.12.37-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.38/rtx-v2023.12.38-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index af056b38a..364fe3a17 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.37"; + version = "2023.12.38"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index e0d0b29b2..6f8c2dc5c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.37 +Version: 2023.12.38 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 7732045592cd7159738ec87b60e4e30db44fe95a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 12:12:58 -0600 Subject: [PATCH 1435/1891] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 15d992bb3..f6ee5cce9 100644 --- a/README.md +++ b/README.md @@ -1097,14 +1097,14 @@ of course they'll need to find a different way to install their dev tools the ta Tasks can also be defined in `.rtx.toml` files in different ways. This is a more "traditional" method of defining tasks: ```toml -task.clean = 'cargo clean && rm -rf .cache' # runs as a shell command +tasks.clean = 'cargo clean && rm -rf .cache' # runs as a shell command -[task.build] +[tasks.build] description = 'Build the CLI' run = "cargo build" alias = 'b' # `rtx run b` -[task.test] +[tasks.test] description = 'Run automated tests' run = [ # multiple commands are run in series 'cargo test', @@ -1112,7 +1112,7 @@ run = [ # multiple commands are run in series ] dir = "{{cwd}}" # run in user's cwd, default is the project's base directory -[task.lint] +[tasks.lint] description = 'Lint with clippy' env = {RUST_BACKTRACE = '1'} # env vars for the script # you can specify a multiline script instead of individual commands @@ -1125,7 +1125,7 @@ cargo clippy description = 'Run CI tasks' depends = ['build', 'lint', 'test'] -[task.release] +[tasks.release] description = 'Cut a new release' file = 'scripts/release.sh' # execute an external script ``` @@ -1175,7 +1175,7 @@ It's often handy to only execute a task if the files it uses changes. For exampl to run `cargo build` if an ".rs" file changes. This can be done with the following config: ```toml -[task.build] +[tasks.build] description = 'Build the CLI' run = "cargo build" sources = ['Cargo.toml', 'src/**/*.rs'] # skip running if these files haven't changed From 751bf570f6dcd9651b934f014b3d2975e6fe76e7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 13:31:36 -0600 Subject: [PATCH 1436/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6ee5cce9..13812afd2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ GitHub Workflow Status Discord -

Polyglot runtime manager (asdf rust clone)

+

Install dev tools, manage your local environment, run tasks on your projects.

## Features From b5bcdc8770526d6a9c1418db6d444eee0bd08de6 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 13:43:19 -0600 Subject: [PATCH 1437/1891] Update README.md --- README.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 13812afd2..568ada8fe 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` -> **Warning** +> ![TIP] > > If you use direnv with `layout python` or other logic that needs to reference rtx runtimes inside > of an `.envrc`, see the [direnv section](#direnv) below. @@ -199,7 +199,9 @@ v20.0.0 ## About -_New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction._ +> ![TIP] +> +> New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction. rtx is a tool for managing programming language and tool versions. For example, use this to install a particular version of Node.js and ruby for a project. Using `rtx activate`, you can have your @@ -392,7 +394,7 @@ sudo apt update sudo apt install -y rtx ``` -> **Warning** +> ![IMPORTANT] > > If you're on arm64 you'll need to run the following: > @@ -714,7 +716,7 @@ There is a performance cost to having these when they're parsed as it's performe `bin/parse-version-file`. However these are [cached](#cache-behavior) so it's not a huge deal. You may not even notice. -> **Note** +> ![NOTE] > > asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies > that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" @@ -810,7 +812,9 @@ my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20 # this can also be specified in a plugin (see below in "Aliases") ``` -These settings can also be managed with `rtx settings ls|get|set|unset`. +> ![TIP] +> +> These settings can also be managed with `rtx settings ls|get|set|unset`. ### System config: `/etc/rtx/config.toml` @@ -1055,7 +1059,7 @@ Here's my favorite features about rtx's task runner: - `rtx watch` to automatically rebuild on changes—no configuration required, but it helps - ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack syntax highlighting and linting/checking support -> **Warning** +> ![WARNING] > > This is an experimental feature. It is not yet stable and will likely change. Some of the docs > may not be implemented, may be implemented incorrectly, or the docs may need to be updated. @@ -1229,7 +1233,7 @@ echo "lts-gallium 16" echo "lts-fermium 14" ``` -> **Note:** +> ![NOTE] > > Because this is rtx-specific functionality not currently used by asdf it isn't likely to be in any > plugin currently, but plugin authors can add this script without impacting asdf users. @@ -1431,9 +1435,11 @@ The priority of these files goes in this order (bottom overrides top): Use `rtx doctor` to see which files are being used. -_Note that currently modifying `RTX_DEFAULT_CONFIG_FILENAME` to something other than `.rtx.toml` -will not work with this feature. For now, it will disable it entirely. This may change in the -future._ +> ![IMPORTANT] +> +> Note that currently modifying `RTX_DEFAULT_CONFIG_FILENAME` to something other than `.rtx.toml` +> will not work with this feature. For now, it will disable it entirely. This may change in the +> future. ## IDE Integration From d8ebacfcf7733b5f669643f752ae9d49a24f0501 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 13:44:25 -0600 Subject: [PATCH 1438/1891] Update README.md --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 568ada8fe..eb1d892c8 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` -> ![TIP] +> [!TIP] > > If you use direnv with `layout python` or other logic that needs to reference rtx runtimes inside > of an `.envrc`, see the [direnv section](#direnv) below. @@ -199,7 +199,7 @@ v20.0.0 ## About -> ![TIP] +> [!TIP] > > New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction. @@ -394,7 +394,7 @@ sudo apt update sudo apt install -y rtx ``` -> ![IMPORTANT] +> [!IMPORTANT] > > If you're on arm64 you'll need to run the following: > @@ -716,7 +716,7 @@ There is a performance cost to having these when they're parsed as it's performe `bin/parse-version-file`. However these are [cached](#cache-behavior) so it's not a huge deal. You may not even notice. -> ![NOTE] +> [!NOTE] > > asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies > that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" @@ -812,7 +812,7 @@ my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20 # this can also be specified in a plugin (see below in "Aliases") ``` -> ![TIP] +> [!TIP] > > These settings can also be managed with `rtx settings ls|get|set|unset`. @@ -1059,7 +1059,7 @@ Here's my favorite features about rtx's task runner: - `rtx watch` to automatically rebuild on changes—no configuration required, but it helps - ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack syntax highlighting and linting/checking support -> ![WARNING] +> [!WARNING] > > This is an experimental feature. It is not yet stable and will likely change. Some of the docs > may not be implemented, may be implemented incorrectly, or the docs may need to be updated. @@ -1233,7 +1233,7 @@ echo "lts-gallium 16" echo "lts-fermium 14" ``` -> ![NOTE] +> [!NOTE] > > Because this is rtx-specific functionality not currently used by asdf it isn't likely to be in any > plugin currently, but plugin authors can add this script without impacting asdf users. @@ -1435,7 +1435,7 @@ The priority of these files goes in this order (bottom overrides top): Use `rtx doctor` to see which files are being used. -> ![IMPORTANT] +> [!IMPORTANT] > > Note that currently modifying `RTX_DEFAULT_CONFIG_FILENAME` to something other than `.rtx.toml` > will not work with this feature. For now, it will disable it entirely. This may change in the From 6decd6b6d79dac80f69901f1b2355c4430222fe6 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 17:03:56 -0600 Subject: [PATCH 1439/1891] Update README.md --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb1d892c8..007d219fa 100644 --- a/README.md +++ b/README.md @@ -492,7 +492,7 @@ echo 'eval "$(rtx activate zsh)"' >> "${ZDOTDIR-$HOME}/.zshrc" echo 'rtx activate fish | source' >> ~/.config/fish/config.fish ``` -> **Note:** +> [!TIP] > > For homebrew and possibly other installs rtx is automatically activated so > this is not necessary. @@ -1076,7 +1076,7 @@ for cargo: cargo build ``` -> **Note:** +> [!IMPORTANT] > > The `rtx:description` comment is optional but recommended. It will be used in the output of `rtx tasks`. > The other configuration for "script" tasks is supported in this format so you can specify things like the @@ -1153,6 +1153,21 @@ To just print stdout/stderr directly, use `--interleave`, the `task_output` sett Stdin is not read by default. To enable this, set `raw = true` on the task that needs it. This will prevent it running in parallel with any other task-a RWMutex will get a write lock in this case. +There is partial support for wildcards, for example, this makes a "lint" task that runs everything that begins with "lint:". + +``` +[tasks."lint:eslint"] # using a ":" means we need to add quotes +run = "eslint ." +[tasks."lint:prettier"] +run = "prettier --check ." +[tasks.lint] +depends = ["lint:*"] +``` + +> [!NOTE] +> As of this writing these wildcards only function at the right side and only work for dependencies. +> It should be possible to also run `rtx run lint:*` but that is not yet implemented. + Extra arguments will be passed to the task, for example, if we want to run in release mode: ```bash From 336494c5a742eabdba56bdb44f67d9a1fbd17e11 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 17:45:00 -0600 Subject: [PATCH 1440/1891] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 007d219fa..8e236c993 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,12 @@ ## Features -- [**Polyglot**](#plugins) - compatible with any language, so no more figuring out how nvm, nodenv, pyenv, etc work individually—just use 1 tool. -- [**Fast**](#performance) - rtx is written in Rust and is very fast. 20x-200x faster than asdf. -- [**No shims**](#shims) - shims cause problems, they break `which`, and add overhead. By default, rtx - does not use them—however you can if you want to. +rtx is 3 tools in one. Like [asdf](https://asdf-vm.com) it manages dev tools like node, python, cmake, terraform, and hundreds more. Like [direnv](https://github.com/direnv/direnv) it manages environment variables in different directories. Like [make](https://www.gnu.org/software/make/manual/make.html) it manages tasks used to build and test projects. You can use it for one of these use-cases or all 3. + +- [**Polyglot**](#plugins) - Manage toolchains for any language. Have specific versions for specific projects. No more figuring out how nvm, nodenv, pyenv, etc work individually—just use this 1 tool. +- [**Fast**](#performance) - rtx is written in Rust and is very fast. 20x-200x faster than asdf which is what it originally set out to replace. +- [**No shims**](#shims) - most dev tool managers like rtx use shims, but they cause problems, they break `which`, and add overhead. By default, rtx + does not use them—however they are available for some use-cases. - [**Arbitrary env vars**](#env---arbitrary-environment-variables) - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. - [**Task runner**](#experimental-task-runner) - Define project-specific tasks like `test` or `lint`. Supports parallel execution and "watch" support to rerun on source changes. - [**asdf-compatible**](#how-do-i-migrate-from-asdf) - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. From 64f78d48afcf0c75d3c495dccd8bba141ec39180 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 17:58:09 -0600 Subject: [PATCH 1441/1891] Update README.md --- README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8e236c993..41a3590b8 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,15 @@

Install dev tools, manage your local environment, run tasks on your projects.

-## Features +## What is it? + +rtx solves 3 related use-cases: -rtx is 3 tools in one. Like [asdf](https://asdf-vm.com) it manages dev tools like node, python, cmake, terraform, and hundreds more. Like [direnv](https://github.com/direnv/direnv) it manages environment variables in different directories. Like [make](https://www.gnu.org/software/make/manual/make.html) it manages tasks used to build and test projects. You can use it for one of these use-cases or all 3. +* Like [asdf](https://asdf-vm.com) it manages dev tools like node, python, cmake, terraform, and hundreds more. +* Like [direnv](https://github.com/direnv/direnv) it manages environment variables in different directories. +* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages tasks used to build and test projects. + +## Features - [**Polyglot**](#plugins) - Manage toolchains for any language. Have specific versions for specific projects. No more figuring out how nvm, nodenv, pyenv, etc work individually—just use this 1 tool. - [**Fast**](#performance) - rtx is written in Rust and is very fast. 20x-200x faster than asdf which is what it originally set out to replace. @@ -1478,6 +1484,17 @@ Direnv and rtx work similarly and there should be a direnv extension that can be Alternatively, you may be able to get tighter integration with a direnv extension and using the [`use_rtx`](#direnv) direnv function. +## Project Roadmap + +Issues marked ["enhancements"](https://github.com/jdx/rtx/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) are the best way to read about ideas for future +functionality. As far as general scope however, these are likely going to be focuses for 2024: + +* Tasks - this is the newest headline feature of rtx and needs to be refined, tested, and iterated on before it can come out of experimental +* Documentation website - we've outgrown what is mostly a single README +* Supply chain hardening - securing rtx is very important and this topic has had a lot of interest from the community. We plan to make several improvements on this front +* Improved python development - better virtualenv integration, precompiled python binaries, and other areas are topics that frequently come up to improve +* Improved plugin development - it's unclear what we'll do exactly but in general we want to make the experience of vending tools for asdf/rtx to be better and safer. + ## FAQs ### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file From 0a0a80c3e35256a48052d7d139f0848776856b72 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 17:58:29 -0600 Subject: [PATCH 1442/1891] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 41a3590b8..8deff43d2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ GitHub Workflow Status Discord -

Install dev tools, manage your local environment, run tasks on your projects.

## What is it? From be86313b923bace7e3a9266b347304c4c5e2c7d0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 17:59:38 -0600 Subject: [PATCH 1443/1891] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8deff43d2..9131c06e2 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ rtx solves 3 related use-cases: -* Like [asdf](https://asdf-vm.com) it manages dev tools like node, python, cmake, terraform, and hundreds more. -* Like [direnv](https://github.com/direnv/direnv) it manages environment variables in different directories. +* Like [asdf](https://asdf-vm.com) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://github.com/asdf-vm/asdf-plugins). +* Like [direnv](https://github.com/direnv/direnv) it manages environment variables for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages tasks used to build and test projects. ## Features From b22a2237a4a90bd384e9705187125c329bd5dc8f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 18:21:19 -0600 Subject: [PATCH 1444/1891] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 9131c06e2..8f81272a9 100644 --- a/README.md +++ b/README.md @@ -1493,6 +1493,14 @@ functionality. As far as general scope however, these are likely going to be foc * Supply chain hardening - securing rtx is very important and this topic has had a lot of interest from the community. We plan to make several improvements on this front * Improved python development - better virtualenv integration, precompiled python binaries, and other areas are topics that frequently come up to improve * Improved plugin development - it's unclear what we'll do exactly but in general we want to make the experience of vending tools for asdf/rtx to be better and safer. +* GUI/TUI - While we're all big CLI fans, it still would be great to better visualize what tools are available, what your configuration is, and other things via some kind of UI. + +### Anti-goals + +* Dependency management - rtx expects you to have system dependencies (like openssl or readline) already setup and configured. This makes it different than tools like nix which manage all dependencies for you. While this seems like an obvious downside, it actually ends up making rtx far easier to use than nix. That said, we would like to make managing system dependencies easier where we can but this is likely going to be simply via better docs and error messages. +* DevOps tooling - rtx is designed with local development in mind. While there are certainly many devs using it for production/server roles which we support and encourage, that will never be the our focus on the roadmap. Building a better ansible/terraform/kubernetes just isn't the goal. +* Remote task caching - turbopack, moonrepo, and many others are trying to solve this (major) problem. rtx's task runner will likely always just be a simple convenience around executing scripts. +* Windows support - I don't have a Windows machine and I think asdf/rtx's focus on Unix tools will make supporting (non-WSL) Windows challenging if not impossible. Unless someone else wants to take on the challenge of building a Windows port I would not expect to see it happen. ## FAQs From 65797b613324a59753f953d2413f8c0c1827dd9f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 24 Dec 2023 18:21:45 -0600 Subject: [PATCH 1445/1891] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 8f81272a9..5ab774dcc 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ ## What is it? -rtx solves 3 related use-cases: - * Like [asdf](https://asdf-vm.com) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://github.com/asdf-vm/asdf-plugins). * Like [direnv](https://github.com/direnv/direnv) it manages environment variables for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages tasks used to build and test projects. From 8d22a016738ae1ead2e244e502746e6115bbc245 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 25 Dec 2023 15:26:57 -0600 Subject: [PATCH 1446/1891] Update README.md --- README.md | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5ab774dcc..1775300f5 100644 --- a/README.md +++ b/README.md @@ -13,21 +13,9 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://github.com/asdf-vm/asdf-plugins). -* Like [direnv](https://github.com/direnv/direnv) it manages environment variables for different project directories. -* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages tasks used to build and test projects. - -## Features - -- [**Polyglot**](#plugins) - Manage toolchains for any language. Have specific versions for specific projects. No more figuring out how nvm, nodenv, pyenv, etc work individually—just use this 1 tool. -- [**Fast**](#performance) - rtx is written in Rust and is very fast. 20x-200x faster than asdf which is what it originally set out to replace. -- [**No shims**](#shims) - most dev tool managers like rtx use shims, but they cause problems, they break `which`, and add overhead. By default, rtx - does not use them—however they are available for some use-cases. -- [**Arbitrary env vars**](#env---arbitrary-environment-variables) - Set custom env vars when in a project directory like `NODE_ENV=production` or `AWS_PROFILE=staging`. -- [**Task runner**](#experimental-task-runner) - Define project-specific tasks like `test` or `lint`. Supports parallel execution and "watch" support to rerun on source changes. -- [**asdf-compatible**](#how-do-i-migrate-from-asdf) - rtx is compatible with asdf plugins and `.tool-versions` files. It can be used as a drop-in replacement. -- [**Fuzzy matching and aliases**](#aliases) - It's enough to just say you want "v20" of node, or the "lts" - version. rtx will figure out the right version without you needing to specify an exact version. +* Like [asdf](https://asdf-vm.com) (or [nvm]([https://nvm.sh](https://github.com/nvm-sh/nvm)) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). +* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](env---arbitrary-environment-variables) for different project directories. +* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](#experimental-task-runner) used to build and test projects. ## 30 Second Demo @@ -1732,7 +1720,7 @@ asdf made (what I consider) a poor design decision to use shims that go between and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, which then calls `asdf exec`, which then calls the correct version of node. -These shims have terrible performance, adding ~120ms to every runtime call. rtx does not use shims and instead +These shims have terrible performance, adding ~120ms to every runtime call. `rtx activate` does not use shims and instead updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo GIF at the top of this README that `rtx` isn't actually used when calling `node -v` for this reason. The performance is identical to running node without using rtx. @@ -1746,7 +1734,7 @@ rtx does call an internal command `rtx hook-env` every time the directory has ch it's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's a full reload. -tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~10ms) +tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~5ms) when the prompt loads. ### Environment variables in rtx From 5688f60d693b453f1d46201fe24e653551c24263 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 25 Dec 2023 15:27:24 -0600 Subject: [PATCH 1447/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1775300f5..488c1d128 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm]([https://nvm.sh](https://github.com/nvm-sh/nvm)) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). +* Like [asdf](https://asdf-vm.com) (or [nvm]([https://nvm.sh](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). * Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](env---arbitrary-environment-variables) for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](#experimental-task-runner) used to build and test projects. From e06f8ad6b5b316021b57a8ab1ec4b5915bdbb53e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 25 Dec 2023 15:27:35 -0600 Subject: [PATCH 1448/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 488c1d128..bac66f31d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm]([https://nvm.sh](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). +* Like [asdf](https://asdf-vm.com) (or [nvm](https://nvm.sh](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). * Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](env---arbitrary-environment-variables) for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](#experimental-task-runner) used to build and test projects. From 3758ae20ee7aea94c62ada573f6b5b392eb8d7fe Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 25 Dec 2023 15:27:50 -0600 Subject: [PATCH 1449/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bac66f31d..6ffa3ac7d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm](https://nvm.sh](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). +* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). * Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](env---arbitrary-environment-variables) for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](#experimental-task-runner) used to build and test projects. From a2c87405fdf9ca38aaba06036a0a775b4f609dc1 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 25 Dec 2023 15:28:07 -0600 Subject: [PATCH 1450/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ffa3ac7d..edca8894a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). +* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). * Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](env---arbitrary-environment-variables) for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](#experimental-task-runner) used to build and test projects. From 5a570749ae72164072c358eaca09259bfd07f512 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:19:15 -0600 Subject: [PATCH 1451/1891] bash/zsh: fixed command_not_found fallback --- src/shell/bash.rs | 28 ++++++++++++++++------------ src/shell/zsh.rs | 24 ++++++++++++++++-------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index c2ef39488..ea16f81d6 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -50,18 +50,22 @@ impl Shell for Bash { "#}); if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" - eval 'command_not_found_handle() {{ - local ret - if (( ! IN_CNFH++)) && {exe} hook-not-found -s bash "$1"; then - _rtx_hook - "$@" - ret=$? - (( IN_CNFH-- )) - return "$ret" - fi - (( IN_CNFH-- )) - '"$(typeset -f command_not_found_handle | tail -n +2)"' - }}' + if [ -z "$_rtx_cmd_not_found" ]; then + _rtx_cmd_not_found=1 + test -n "$(declare -f command_not_found_handle)" && eval "${{_/command_not_found_handle/_command_not_found_handle}}" + + command_not_found_handle() {{ + if {exe} hook-not-found -s bash "$1"; then + _rtx_hook + "$@" + elif [ -n "$(declare -f _command_not_found_handle)" ]; then + _command_not_found_handle "$@" + else + echo "zsh: command not found: $1" >&2 + return 127 + fi + }} + fi "#}); } diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index c09edd771..aeaf1333d 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -58,14 +58,22 @@ impl Shell for Zsh { "#}); if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" - function command_not_found_handler() {{ - {exe} hook-not-found -s zsh "$1" - if (( $? == 0 )); then - _rtx_hook - "$@" - return $? - fi - }} + if [ -z "$_rtx_cmd_not_found" ]; then + _rtx_cmd_not_found=1 + test -n "$(declare -f command_not_found_handler)" && eval "${{_/command_not_found_handler/_command_not_found_handler}}" + + function command_not_found_handler() {{ + if {exe} hook-not-found -s zsh "$1"; then + _rtx_hook + "$@" + elif [ -n "$(declare -f _command_not_found_handler)" ]; then + _command_not_found_handler "$@" + else + echo "zsh: command not found: $1" >&2 + return 127 + fi + }} + fi "#}); } From c5aeabedff98b13cb63762749401debd603de58d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:23:12 -0600 Subject: [PATCH 1452/1891] docs --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index edca8894a..c8735c9c8 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ v20.0.0
Click to expand -- [Features](#features) +- [What is it?](#what-is-it) - [30 Second Demo](#30-second-demo) - [Quickstart](#quickstart) - [About](#about) @@ -105,6 +105,8 @@ v20.0.0 - [Templates](#templates) - [Config Environments](#config-environments) - [IDE Integration](#ide-integration) +- [Project Roadmap](#project-roadmap) + - [Anti-goals](#anti-goals) - [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) @@ -193,7 +195,7 @@ v20.0.0 ## About > [!TIP] -> +> > New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction. rtx is a tool for managing programming language and tool versions. For example, use this to install @@ -806,7 +808,7 @@ my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20 ``` > [!TIP] -> +> > These settings can also be managed with `rtx settings ls|get|set|unset`. ### System config: `/etc/rtx/config.toml` From 0866394a15f74dd2bd0193e02895cce5f4af1072 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:25:02 -0600 Subject: [PATCH 1453/1891] typo --- src/shell/bash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index ea16f81d6..d45d7f753 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -61,7 +61,7 @@ impl Shell for Bash { elif [ -n "$(declare -f _command_not_found_handle)" ]; then _command_not_found_handle "$@" else - echo "zsh: command not found: $1" >&2 + echo "bash: command not found: $1" >&2 return 127 fi }} From fb3aac868a72c30c3501f1bdcce7e10942ae5b44 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:25:29 -0600 Subject: [PATCH 1454/1891] test snapshots --- .../rtx__shell__bash__tests__hook_init.snap | 28 +++++++++++-------- ...tx__shell__bash__tests__hook_init_nix.snap | 28 +++++++++++-------- .../rtx__shell__zsh__tests__hook_init.snap | 24 ++++++++++------ ...rtx__shell__zsh__tests__hook_init_nix.snap | 24 ++++++++++------ 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 70e6030b3..128f18176 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -35,16 +35,20 @@ _rtx_hook() { if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi -eval 'command_not_found_handle() { -local ret - if (( ! IN_CNFH++)) && /some/dir/rtx hook-not-found -s bash "$1"; then - _rtx_hook - "$@" - ret=$? - (( IN_CNFH-- )) - return "$ret" - fi - (( IN_CNFH-- )) - '"$(typeset -f command_not_found_handle | tail -n +2)"' -}' +if [ -z "$_rtx_cmd_not_found" ]; then + _rtx_cmd_not_found=1 + test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" + + command_not_found_handle() { + if /some/dir/rtx hook-not-found -s bash "$1"; then + _rtx_hook + "$@" + elif [ -n "$(declare -f _command_not_found_handle)" ]; then + _command_not_found_handle "$@" + else + echo "bash: command not found: $1" >&2 + return 127 + fi + } +fi diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index b11bcddbe..86609888a 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -34,16 +34,20 @@ _rtx_hook() { if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi -eval 'command_not_found_handle() { -local ret - if (( ! IN_CNFH++)) && /nix/store/rtx hook-not-found -s bash "$1"; then - _rtx_hook - "$@" - ret=$? - (( IN_CNFH-- )) - return "$ret" - fi - (( IN_CNFH-- )) - '"$(typeset -f command_not_found_handle | tail -n +2)"' -}' +if [ -z "$_rtx_cmd_not_found" ]; then + _rtx_cmd_not_found=1 + test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" + + command_not_found_handle() { + if /nix/store/rtx hook-not-found -s bash "$1"; then + _rtx_hook + "$@" + elif [ -n "$(declare -f _command_not_found_handle)" ]; then + _command_not_found_handle "$@" + else + echo "bash: command not found: $1" >&2 + return 127 + fi + } +fi diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index d1f12a3d2..6cc6a8cb1 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -39,12 +39,20 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi -function command_not_found_handler() { - /some/dir/rtx hook-not-found -s zsh "$1" - if (( $? == 0 )); then - _rtx_hook - "$@" - return $? - fi -} +if [ -z "$_rtx_cmd_not_found" ]; then + _rtx_cmd_not_found=1 + test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" + + function command_not_found_handler() { + if /some/dir/rtx hook-not-found -s zsh "$1"; then + _rtx_hook + "$@" + elif [ -n "$(declare -f _command_not_found_handler)" ]; then + _command_not_found_handler "$@" + else + echo "zsh: command not found: $1" >&2 + return 127 + fi + } +fi diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap index eb400370c..6013e6da9 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -38,12 +38,20 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi -function command_not_found_handler() { - /nix/store/rtx hook-not-found -s zsh "$1" - if (( $? == 0 )); then - _rtx_hook - "$@" - return $? - fi -} +if [ -z "$_rtx_cmd_not_found" ]; then + _rtx_cmd_not_found=1 + test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" + + function command_not_found_handler() { + if /nix/store/rtx hook-not-found -s zsh "$1"; then + _rtx_hook + "$@" + elif [ -n "$(declare -f _command_not_found_handler)" ]; then + _command_not_found_handler "$@" + else + echo "zsh: command not found: $1" >&2 + return 127 + fi + } +fi From 01fa605da5d3b0942dfeae92156c1d0d9cb14f42 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:43:07 -0600 Subject: [PATCH 1455/1891] fixed e2e tests --- src/shell/bash.rs | 2 +- src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap | 2 +- src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap | 2 +- src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap | 2 +- src/shell/zsh.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index d45d7f753..e6e691bd9 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -50,7 +50,7 @@ impl Shell for Bash { "#}); if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" - if [ -z "$_rtx_cmd_not_found" ]; then + if [ -z "${{_rtx_cmd_not_found:-}}" ]; then _rtx_cmd_not_found=1 test -n "$(declare -f command_not_found_handle)" && eval "${{_/command_not_found_handle/_command_not_found_handle}}" diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap index 128f18176..5c1dcacf8 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap @@ -35,7 +35,7 @@ _rtx_hook() { if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi -if [ -z "$_rtx_cmd_not_found" ]; then +if [ -z "${_rtx_cmd_not_found:-}" ]; then _rtx_cmd_not_found=1 test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap index 86609888a..b8df24524 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap @@ -34,7 +34,7 @@ _rtx_hook() { if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi -if [ -z "$_rtx_cmd_not_found" ]; then +if [ -z "${_rtx_cmd_not_found:-}" ]; then _rtx_cmd_not_found=1 test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap index 6cc6a8cb1..2bffea535 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap @@ -39,7 +39,7 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi -if [ -z "$_rtx_cmd_not_found" ]; then +if [ -z "${_rtx_cmd_not_found:-}" ]; then _rtx_cmd_not_found=1 test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap index 6013e6da9..ef746b2b1 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap @@ -38,7 +38,7 @@ if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) fi -if [ -z "$_rtx_cmd_not_found" ]; then +if [ -z "${_rtx_cmd_not_found:-}" ]; then _rtx_cmd_not_found=1 test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index aeaf1333d..311f19fb2 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -58,7 +58,7 @@ impl Shell for Zsh { "#}); if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" - if [ -z "$_rtx_cmd_not_found" ]; then + if [ -z "${{_rtx_cmd_not_found:-}}" ]; then _rtx_cmd_not_found=1 test -n "$(declare -f command_not_found_handler)" && eval "${{_/command_not_found_handler/_command_not_found_handler}}" From 4a2241fb9fd95a45c4045a5af7f532674a8029af Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:43:58 -0600 Subject: [PATCH 1456/1891] markdownlint --- .markdownlint.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.markdownlint.json b/.markdownlint.json index 213af9b63..a36edfc88 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,4 +1,5 @@ { + "MD004": false, "MD013": false, "MD033": false, "MD040": false, From 2fbe4b9566ca7ca63353d7cb75327ec80abc0a41 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:48:26 -0600 Subject: [PATCH 1457/1891] chore: Release rtx-cli version 2023.12.39 --- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 302c887fa..3f2a37a49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,7 +293,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -489,7 +489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -527,7 +527,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -1438,7 +1438,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -1549,7 +1549,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -1875,7 +1875,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.38" +version = "2023.12.39" dependencies = [ "base64", "built", @@ -2134,7 +2134,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -2298,7 +2298,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -2320,9 +2320,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.42" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", @@ -2447,22 +2447,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", ] [[package]] @@ -2877,7 +2877,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", "wasm-bindgen-shared", ] @@ -2911,7 +2911,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.43", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 8b6ec0782..fd437036b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.38" +version = "2023.12.39" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index c8735c9c8..13dbc63b4 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.38 +rtx 2023.12.39 ``` Hook rtx into your shell (pick the right one for your shell): @@ -371,7 +371,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.38/rtx-v2023.12.38-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.39/rtx-v2023.12.39-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 364fe3a17..3345c1e5d 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.38"; + version = "2023.12.39"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 6f8c2dc5c..13c37dc3c 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.38 +Version: 2023.12.39 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From fc84c2335cbaed32529f94c062fa73c127cbf3f2 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 27 Dec 2023 11:35:55 -0600 Subject: [PATCH 1458/1891] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13dbc63b4..31871cae0 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ GitHub Workflow Status Discord +The front-end to your dev env. ## What is it? From 4ea1cfb77948ba4df262a7cf30428968eda21572 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 27 Dec 2023 11:36:14 -0600 Subject: [PATCH 1459/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31871cae0..656b56358 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ GitHub Workflow Status Discord -The front-end to your dev env. +

The front-end to your dev env.

## What is it? From 19963710b0be0ba3f70500829fe939deb55a5208 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 27 Dec 2023 12:00:13 -0600 Subject: [PATCH 1460/1891] CI: continue on codacy error --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c84d671f1..d091d7833 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -91,6 +91,7 @@ jobs: command: just test-coverage - name: Run codacy-coverage-reporter uses: codacy/codacy-coverage-reporter-action@v1 + continue-on-error: true with: project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} coverage-reports: lcov.info From e57d99da748bd18acb18d32bfc621db90d8f8915 Mon Sep 17 00:00:00 2001 From: "Justin \"J.R.\" Hill" Date: Wed, 27 Dec 2023 10:05:53 -0800 Subject: [PATCH 1461/1891] docs: fix typo in README link (#1278) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 656b56358..c485a3786 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ## What is it? * Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). -* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](env---arbitrary-environment-variables) for different project directories. +* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](#env---arbitrary-environment-variables) for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](#experimental-task-runner) used to build and test projects. ## 30 Second Demo From 1531209f2e3f59ec1caef2722eb1d1a355c16f2a Mon Sep 17 00:00:00 2001 From: Andrew Chen Wang <60190294+Andrew-Chen-Wang@users.noreply.github.com> Date: Wed, 27 Dec 2023 13:56:18 -0500 Subject: [PATCH 1462/1891] Fix typo of where plugin is defined (#1279) * Fix typo of where plugin is defined * Update test in use.rs --- src/cli/use.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/use.rs b/src/cli/use.rs index 3852508f8..6220005a0 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -154,7 +154,7 @@ impl Use { let plugin = &targ.plugin; let p = display_path(p); let global = display_path(global); - warn!("{plugin} is is defined in {p} which overrides the global config ({global})"); + warn!("{plugin} is defined in {p} which overrides the global config ({global})"); }; for targ in &self.tool { if let Some(tv) = ts.versions.get(&targ.plugin) { @@ -273,7 +273,7 @@ mod tests { assert_cli_snapshot!("use", "-g", "tiny@2", @r###" rtx ~/config/config.toml tools: tiny@2.1.0 - rtx tiny is is defined in ~/cwd/.test-tool-versions which overrides the global config (~/config/config.toml) + rtx tiny is defined in ~/cwd/.test-tool-versions which overrides the global config (~/config/config.toml) "###); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] From 7d0e293ea18bcf37dfae66d7f6b59c167bfff9f2 Mon Sep 17 00:00:00 2001 From: Zahid Date: Wed, 27 Dec 2023 22:49:06 +0100 Subject: [PATCH 1463/1891] docs: correct env variable RTX_EXPERIMENTAL in README (#1281) RTX_EXPERIMENTAL=1 setting this in .rtx.toml fails with: ```bash rtx expected value of env.RTX_EXPERIMENTAL to be a string or bool, got: 1 rtx Run with --verbose or RTX_VERBOSE=1 for more information ``` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c485a3786..aa38344f7 100644 --- a/README.md +++ b/README.md @@ -1006,7 +1006,7 @@ This controls the output of `rtx run`. It can be one of: - `prefix` - (default if jobs > 1) print by line with the prefix of the task name - `interleave` - (default if jobs == 1) display stdout/stderr as it comes in -#### `RTX_EXPERIMENTAL=1` +#### `RTX_EXPERIMENTAL=true` Enables experimental features. From 794df59a12d4bec522e74a584395087585d9274f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 27 Dec 2023 17:09:34 -0600 Subject: [PATCH 1464/1891] use rtx-plugins as shortname repo (#1282) --- README.md | 9 ++++----- scripts/query-top-plugins.fish | 2 +- scripts/update-shorthand-repo.sh | 7 +++---- src/default_shorthands.rs | 7 +++---- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index aa38344f7..93acc2cb8 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ a particular version of Node.js and ruby for a project. Using `rtx activate`, yo shell automatically switch to the correct node and ruby versions when you `cd` into the project's directory[^cd]. Other projects on your machine can use a different set of versions. -rtx is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecosystem](https://github.com/asdf-vm/asdf-plugins) +rtx is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecosystem](https://github.com/rtx-plugins/registry) under the hood. However, it is _much_ faster than asdf and has a more friendly user experience. For more on how rtx compares to asdf, [see below](#comparison-to-asdf). @@ -1254,7 +1254,7 @@ echo "lts-fermium 14" rtx uses asdf's plugin ecosystem under the hood. These plugins contain shell scripts like `bin/install` (for installing) and `bin/list-all` (for listing all of the available versions). -See for the list of built-in plugins shorthands. See asdf's +See for the list of built-in plugins shorthands. See asdf's [Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn more about how they work. @@ -1628,10 +1628,9 @@ you should post an issue on the plugin's repository. e.g.: how does `rtx plugin install elixir` know to fetch ? -asdf maintains [an index](https://github.com/asdf-vm/asdf-plugins) of shorthands that rtx uses as a base. +We maintain [an index](https://github.com/rtx-plugins/registry) of shorthands that rtx uses as a base. This is regularly updated every time that rtx has a release. This repository is stored directly into -the codebase [here](./src/default_shorthands.rs). The bottom of that file contains modifications that -rtx makes on top of asdf. +the codebase [here](./src/default_shorthands.rs). ### Does "node@20" mean the newest available version of node? diff --git a/scripts/query-top-plugins.fish b/scripts/query-top-plugins.fish index 1f63e7a20..f81c1bb4e 100755 --- a/scripts/query-top-plugins.fish +++ b/scripts/query-top-plugins.fish @@ -16,7 +16,7 @@ if test -d /tmp/asdf-plugins git pull /tmp/asdf-plugins cd $current_dir else - git clone --depth=1 git@github.com:asdf-vm/asdf-plugins.git /tmp/asdf-plugins + git clone --depth=1 git@github.com:rtx-plugins/registry.git /tmp/asdf-plugins end if test -e stargazer_count.txt diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index d32025321..c22e8369a 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -2,12 +2,11 @@ set -euo pipefail rm -rf asdf-plugins -git clone --depth 1 https://github.com/asdf-vm/asdf-plugins +git clone --depth 1 https://github.com/rtx-plugins/registry asdf-plugins rm -f src/default_shorthands.rs custom_plugins=( '("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"),' - '("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"),' '("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"),' ) @@ -53,11 +52,11 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] const DEFAULT_SHORTHAND_LIST: [(&str, &str); $num_plugins] = [ - // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins + // shorthands from https://github.com/rtx-plugins/registry EOF for file in $asdf_plugins; do plugin=$(basename "$file") - repository=$(cat "$file") + repository=$(grep -e '^repository = ' "$file") repository="${repository/#repository = /}" echo " (\"$plugin\", \"$repository\")," >>src/default_shorthands.rs done diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 7cecda06a..d03c35e8d 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -23,8 +23,8 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] #[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 712] = [ - // asdf original shorthands from https://github.com/asdf-vm/asdf-plugins +const DEFAULT_SHORTHAND_LIST: [(&str, &str); 711] = [ + // shorthands from https://github.com/rtx-plugins/registry ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), ("act", "https://github.com/grimoh/asdf-act.git"), @@ -508,7 +508,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 712] = [ ("please", "https://github.com/asdf-community/asdf-please.git"), ("pluto", "https://github.com/FairwindsOps/asdf-pluto.git"), ("pnpm", "https://github.com/jonathanmorley/asdf-pnpm.git"), - ("poetry", "https://github.com/asdf-community/asdf-poetry.git"), + ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), ("polaris", "https://github.com/particledecay/asdf-polaris.git"), ("popeye", "https://github.com/nlamirault/asdf-popeye.git"), ("postgres", "https://github.com/smashedtoatoms/asdf-postgres.git"), @@ -736,6 +736,5 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 712] = [ ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), // rtx custom shorthands ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), - ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ]; From 10a4248c3e8d654a325b2982443ba0222b39f50a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 28 Dec 2023 09:25:50 -0600 Subject: [PATCH 1465/1891] plugins: add support for "trusted" plugins (#1284) --- scripts/update-shorthand-repo.sh | 76 +++++++++++++++++++------------- src/cli/plugins/install.rs | 2 +- src/default_shorthands.rs | 26 ++++++----- src/plugins/external_plugin.rs | 8 +++- 4 files changed, 67 insertions(+), 45 deletions(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index c22e8369a..f7147eabf 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -5,25 +5,9 @@ rm -rf asdf-plugins git clone --depth 1 https://github.com/rtx-plugins/registry asdf-plugins rm -f src/default_shorthands.rs -custom_plugins=( - '("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"),' - '("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"),' -) - -asdf_plugins=$(find asdf-plugins/plugins -maxdepth 1 | - sort | - grep -v '/bun$' | - grep -v '/deno$' | - grep -v '/go$' | - grep -v '/golang$' | - grep -v '/java$' | - grep -v '/nodejs$' | - grep -v '/plugins$' | - grep -v '/python$' | - grep -v '/ruby$') - +asdf_plugins=$(ls asdf-plugins/plugins) num_plugins=$(echo "$asdf_plugins" | wc -l | tr -d ' ') -num_plugins=$((num_plugins + ${#custom_plugins[@]})) +trusted=() cat >src/default_shorthands.rs <src/default_shorthands.rs <> = - Lazy::new(|| HashMap::from(DEFAULT_SHORTHAND_LIST)); +use std::collections::{HashSet, HashMap}; #[rustfmt::skip] -#[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); $num_plugins] = [ - // shorthands from https://github.com/rtx-plugins/registry +pub static DEFAULT_SHORTHANDS: Lazy> = + Lazy::new(|| HashMap::from([ EOF -for file in $asdf_plugins; do - plugin=$(basename "$file") +count=0 +for plugin in $asdf_plugins; do + file="asdf-plugins/plugins/$plugin" repository=$(grep -e '^repository = ' "$file") repository="${repository/#repository = /}" + printf "[%03d/%d] %s\n" $((++count)) "$num_plugins" "$repository" + if [[ $repository == "https://github.com/rtx-plugins/"* ]]; then + trusted+=("$plugin") + elif grep -qe '^first-party = true' "$file"; then + trusted+=("$plugin") + fi + # if [[ $repository == "https://github.com/"* ]]; then + # owner=${repository#*github.com/} + # owner=${owner%/*} + # repo=${repository#*github.com/*/} + # repo=${repo%.git} + # stars["$owner/$repo"]="$plugin" + # fi echo " (\"$plugin\", \"$repository\")," >>src/default_shorthands.rs done -echo " // rtx custom shorthands" >>src/default_shorthands.rs -for plugin in "${custom_plugins[@]}"; do - echo " $plugin" >>src/default_shorthands.rs +echo "]));" >>src/default_shorthands.rs + +cat <>src/default_shorthands.rs + +#[rustfmt::skip] +pub static TRUSTED_SHORTHANDS: Lazy> = + Lazy::new(|| HashSet::from([ +EOF +for plugin in "${trusted[@]}"; do + echo " \"$plugin\"," >>src/default_shorthands.rs done -echo "];" >>src/default_shorthands.rs +echo "]));" >>src/default_shorthands.rs + +#cat <>src/default_shorthands.rs +##[rustfmt::skip] +#pub static GITHUB_STARS: Lazy> = +# Lazy::new(|| HashMap::from([ +#EOF +#for plugin in "${!stars[@]}"; do +# echo " (\"$plugin\", ${stars[$plugin]})," >>src/default_shorthands.rs +#done +#echo "]));" >>src/default_shorthands.rs + +rustfmt src/default_shorthands.rs + rm -rf asdf-plugins diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index a916627a3..e7ef2f864 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -107,7 +107,7 @@ impl PluginsInstall { warn!("Plugin {name} already installed"); warn!("Use --force to install anyway"); } else { - plugin.ensure_installed(mpr, true)?; + plugin.ensure_installed(mpr, self.force)?; } Ok(()) } diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index d03c35e8d..8ebb88632 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -16,15 +16,11 @@ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! use once_cell::sync::Lazy; -use std::collections::HashMap; - -pub static DEFAULT_SHORTHANDS: Lazy> = - Lazy::new(|| HashMap::from(DEFAULT_SHORTHAND_LIST)); +use std::collections::{HashMap, HashSet}; #[rustfmt::skip] -#[cfg_attr(coverage_nightly, no_coverage)] -const DEFAULT_SHORTHAND_LIST: [(&str, &str); 711] = [ - // shorthands from https://github.com/rtx-plugins/registry +pub static DEFAULT_SHORTHANDS: Lazy> = + Lazy::new(|| HashMap::from([ ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), ("R", "https://github.com/asdf-community/asdf-r.git"), ("act", "https://github.com/grimoh/asdf-act.git"), @@ -503,6 +499,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 711] = [ ("php", "https://github.com/asdf-community/asdf-php.git"), ("pint", "https://github.com/sam-burrell/asdf-pint.git"), ("pipectl", "https://github.com/pipe-cd/asdf-pipectl.git"), + ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), ("pipx", "https://github.com/yozachar/asdf-pipx.git"), ("pivnet", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("please", "https://github.com/asdf-community/asdf-please.git"), @@ -661,6 +658,7 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 711] = [ ("thrift", "https://github.com/alisaifee/asdf-thrift.git"), ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), ("timoni", "https://github.com/Smana/asdf-timoni.git"), + ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ("titan", "https://github.com/gabitchov/asdf-titan.git"), ("tlsg-cli", "https://github.com/0ghny/asdf-tlsgcli.git"), ("tmux", "https://github.com/aphecetche/asdf-tmux.git"), @@ -734,7 +732,13 @@ const DEFAULT_SHORTHAND_LIST: [(&str, &str); 711] = [ ("zola", "https://github.com/salasrod/asdf-zola.git"), ("zoxide", "https://github.com/nyrst/asdf-zoxide"), ("zprint", "https://github.com/carlduevel/asdf-zprint.git"), - // rtx custom shorthands - ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), - ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), -]; +])); + +#[rustfmt::skip] +pub static TRUSTED_SHORTHANDS: Lazy> = + Lazy::new(|| HashSet::from([ + "dt", + "pipenv", + "poetry", + "tiny", +])); diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 71db78e5b..676abfbfa 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -15,7 +15,7 @@ use rayon::prelude::*; use crate::cache::CacheManager; use crate::config::{Config, Settings}; -use crate::default_shorthands::DEFAULT_SHORTHANDS; +use crate::default_shorthands::{DEFAULT_SHORTHANDS, TRUSTED_SHORTHANDS}; use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; @@ -454,7 +454,11 @@ impl Plugin for ExternalPlugin { } if !settings.yes && self.repo_url.is_none() { let url = self.get_repo_url(&config).unwrap_or_default(); - if !url.starts_with("https://github.com/rtx-plugins/") { + let is_shorthand = DEFAULT_SHORTHANDS + .get(self.name.as_str()) + .is_some_and(|s| s == &url); + let is_trusted = !is_shorthand || TRUSTED_SHORTHANDS.contains(&self.name.as_str()); + if !is_trusted { eprintln!( "⚠️ {name} is a community-developed plugin: {url}", name = style(&self.name).blue(), From 460e54772b2eda6bf75358c50ac6a694394c051d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 28 Dec 2023 09:28:43 -0600 Subject: [PATCH 1466/1891] chore: Release rtx-cli version 2023.12.40 --- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 2 +- README.md | 4 ++-- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- src/default_shorthands.rs | 3 ++- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f2a37a49..e3dbfb497 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,9 +277,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.4" +version = "4.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" +checksum = "a51919c5608a32e34ea1d6be321ad070065e17613e168c5b6977024290f2630b" dependencies = [ "clap", ] @@ -1875,7 +1875,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.39" +version = "2023.12.40" dependencies = [ "base64", "built", @@ -2037,11 +2037,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2399,15 +2399,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3191,9 +3191,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.30" +version = "0.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" +checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" dependencies = [ "memchr", ] @@ -3210,9 +3210,9 @@ dependencies = [ [[package]] name = "xattr" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995" +checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1" dependencies = [ "libc", "linux-raw-sys", diff --git a/Cargo.toml b/Cargo.toml index fd437036b..b160d33e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.39" +version = "2023.12.40" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 93acc2cb8..3192cd4e1 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install rtx on macOS (other methods [here](#installation)): $ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx $ chmod +x ~/bin/rtx $ rtx --version -rtx 2023.12.39 +rtx 2023.12.40 ``` Hook rtx into your shell (pick the right one for your shell): @@ -372,7 +372,7 @@ npx rtx-cli exec python@3.11 -- python some_script.py Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). ``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.39/rtx-v2023.12.39-linux-x64 > /usr/local/bin/rtx +curl https://github.com/jdx/rtx/releases/download/v2023.12.40/rtx-v2023.12.40-linux-x64 > /usr/local/bin/rtx chmod +x /usr/local/bin/rtx ``` diff --git a/default.nix b/default.nix index 3345c1e5d..3b2e4c2cc 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.39"; + version = "2023.12.40"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 13c37dc3c..ca36b33f3 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.39 +Version: 2023.12.40 Release: 1 URL: https://github.com/jdx/rtx/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 8ebb88632..15a74276e 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -304,7 +304,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("hey", "https://github.com/raimon49/asdf-hey.git"), ("hostctl", "https://github.com/svenluijten/asdf-hostctl.git"), ("httpie-go", "https://github.com/abatilo/asdf-httpie-go.git"), - ("hub", "https://github.com/vixus0/asdf-hub.git"), + ("hub", "https://github.com/rtx-plugins/asdf-hub.git"), ("hugo", "https://github.com/NeoHsu/asdf-hugo.git"), ("hurl", "https://github.com/raimon49/asdf-hurl.git"), ("hwatch", "https://github.com/chessmango/asdf-hwatch.git"), @@ -738,6 +738,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = pub static TRUSTED_SHORTHANDS: Lazy> = Lazy::new(|| HashSet::from([ "dt", + "hub", "pipenv", "poetry", "tiny", From 1186a6bc430483bc55b4b904c298b8c462e0cceb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:16:03 -0600 Subject: [PATCH 1467/1891] task: read RTX_TASK_OUTPUT as lowercase (#1288) Fixes #1287 --- src/cli/run.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 4380312c2..2615c80e4 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -4,7 +4,7 @@ use std::iter::once; use std::os::unix::prelude::ExitStatusExt; use std::path::{Path, PathBuf}; use std::process::{exit, Stdio}; -use std::str::FromStr; + use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{mpsc, Mutex}; use std::time::SystemTime; @@ -261,7 +261,7 @@ impl Run { ) -> Result<()> { let program = program.to_executable(); let mut cmd = CmdLineRunner::new(program.clone()).args(args).envs(env); - match &self.output(task) { + match &self.output(task)? { TaskOutput::Prefix => cmd = cmd.prefix(format!("{prefix} ")), TaskOutput::Interleave => cmd = cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit()), } @@ -291,18 +291,18 @@ impl Run { Ok(()) } - fn output(&self, task: &Task) -> TaskOutput { + fn output(&self, task: &Task) -> Result { let settings = Settings::get(); if self.prefix { - TaskOutput::Prefix + Ok(TaskOutput::Prefix) } else if self.interleave { - TaskOutput::Interleave + Ok(TaskOutput::Interleave) } else if let Some(output) = &settings.task_output { - TaskOutput::from_str(output).unwrap() + Ok(output.parse()?) } else if self.raw(task) || self.jobs() == 1 { - TaskOutput::Interleave + Ok(TaskOutput::Interleave) } else { - TaskOutput::Prefix + Ok(TaskOutput::Prefix) } } @@ -503,6 +503,7 @@ impl Deps { } #[derive(Debug, PartialEq, EnumString)] +#[strum(serialize_all = "snake_case")] enum TaskOutput { Prefix, Interleave, From c5fa2f10b8ae1dbb6b2965b73b2d2fb349461af7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 30 Dec 2023 12:15:32 -0600 Subject: [PATCH 1468/1891] make --cd a global flag (#1299) Fixes #977 --- README.md | 3 - completions/_rtx | 201 +++-- completions/rtx.bash | 700 ++++++++++++++++-- completions/rtx.fish | 4 +- e2e/test_exec | 2 + src/cli/args/cd.rs | 17 + src/cli/args/mod.rs | 1 + src/cli/args/yes.rs | 2 +- src/cli/direnv/envrc.rs | 9 +- src/cli/env_vars.rs | 8 +- src/cli/exec.rs | 14 +- src/cli/local.rs | 20 +- src/cli/mod.rs | 1 + src/cli/run.rs | 2 +- src/cli/task/edit.rs | 2 +- src/cli/use.rs | 10 +- ...__config_file__rtx_toml__tests__env-5.snap | 1 + ...nfig_file__rtx_toml__tests__fixture-2.snap | 3 +- ...nfig_file__rtx_toml__tests__fixture-6.snap | 1 + ...ig_file__rtx_toml__tests__path_dirs-5.snap | 1 + ...file__rtx_toml__tests__remove_alias-4.snap | 1 + ...ile__rtx_toml__tests__remove_plugin-4.snap | 1 + ...__rtx_toml__tests__replace_versions-4.snap | 1 + src/config/config_file/tool_versions.rs | 24 +- src/config/mod.rs | 3 +- src/config/settings.rs | 14 +- src/dirs.rs | 1 - src/env.rs | 1 - src/file.rs | 2 +- src/hook_env.rs | 4 +- src/plugins/external_plugin_cache.rs | 11 +- src/shims.rs | 1 - src/tera.rs | 2 +- src/test.rs | 2 +- 34 files changed, 858 insertions(+), 212 deletions(-) create mode 100644 src/cli/args/cd.rs diff --git a/README.md b/README.md index 3192cd4e1..23ba9c3e9 100644 --- a/README.md +++ b/README.md @@ -2307,9 +2307,6 @@ Options: -c, --command Command string to execute - -C, --cd - Change to this directory before executing the command - -j, --jobs Number of jobs to run in parallel [default: 4] diff --git a/completions/_rtx b/completions/_rtx index f87c05ba2..379a11dfa 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -5,9 +5,10 @@ _rtx() { local ret=1 _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_cmds' \ '*::arg:->args' && ret=0 @@ -69,17 +70,19 @@ __rtx_activate_cmd() { '::shell_type:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_alias_cmd] )) || __rtx_alias_cmd() { _arguments -s -S \ '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ '--no-header[Don'\''t show table header]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_alias_cmds' \ '*::arg:->args' && ret=0 @@ -102,18 +105,20 @@ __rtx_alias_get_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_alias_ls_cmd] )) || __rtx_alias_ls_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ '--no-header[Don'\''t show table header]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_alias_set_cmd] )) || __rtx_alias_set_cmd() { @@ -121,40 +126,45 @@ __rtx_alias_set_cmd() { ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ ':value:' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_alias_unset_cmd] )) || __rtx_alias_unset_cmd() { _arguments -s -S \ ':plugin:__rtx_plugins' \ ':alias:__rtx_aliases' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_asdf_cmd] )) || __rtx_asdf_cmd() { _arguments -s -S \ '*::args:_cmdambivalent' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_bin_paths_cmd] )) || __rtx_bin_paths_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_cache_cmd] )) || __rtx_cache_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_cache_cmds' \ '*::arg:->args' && ret=0 @@ -173,25 +183,28 @@ return ret __rtx_cache_clear_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_completion_cmd] )) || __rtx_completion_cmd() { _arguments -s -S \ '::shell:(bash fish zsh)' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_config_cmd] )) || __rtx_config_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_config_cmds' \ '*::arg:->args' && ret=0 @@ -211,39 +224,44 @@ return ret __rtx_config_generate_cmd() { _arguments -s -S \ '(-o --output)'{-o,--output}'=[Output to file instead of stdout]:output:_files' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_config_ls_cmd] )) || __rtx_config_ls_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_current_cmd] )) || __rtx_current_cmd() { _arguments -s -S \ '::plugin:__rtx_plugins' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_deactivate_cmd] )) || __rtx_deactivate_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_direnv_cmd] )) || __rtx_direnv_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_direnv_cmds' \ '*::arg:->args' && ret=0 @@ -263,30 +281,34 @@ return ret (( $+functions[__rtx_direnv_activate_cmd] )) || __rtx_direnv_activate_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_direnv_envrc_cmd] )) || __rtx_direnv_envrc_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_direnv_exec_cmd] )) || __rtx_direnv_exec_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_doctor_cmd] )) || __rtx_doctor_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_env_cmd] )) || __rtx_env_cmd() { @@ -294,9 +316,10 @@ __rtx_env_cmd() { '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ '*::tool:__rtx_tool_versions' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_env_vars_cmd] )) || __rtx_env_vars_cmd() { @@ -304,21 +327,22 @@ __rtx_env_vars_cmd() { '--file=[The TOML file to update]:file:_files' \ '*--remove=[Remove the environment variable from config file]:remove:' \ '*::env_vars:' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_exec_cmd] )) || __rtx_exec_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ - '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_global_cmd] )) || __rtx_global_cmd() { @@ -328,9 +352,10 @@ __rtx_global_cmd() { '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ '--path[Get the path of the global config file]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_hook_env_cmd] )) || __rtx_hook_env_cmd() { @@ -338,26 +363,29 @@ __rtx_hook_env_cmd() { '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ '--status[Show "rtx\: @" message when changing directories]' \ '(-q --quiet)'{-q,--quiet}'[Hide warnings such as when a tool is not installed]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_hook_not_found_cmd] )) || __rtx_hook_not_found_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ ':bin:' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_implode_cmd] )) || __rtx_implode_cmd() { _arguments -s -S \ '--config[Also remove config directory]' \ '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_install_cmd] )) || __rtx_install_cmd() { @@ -367,17 +395,19 @@ __rtx_install_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '*'{-v,--verbose}'[Show installation output]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_latest_cmd] )) || __rtx_latest_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_link_cmd] )) || __rtx_link_cmd() { @@ -385,9 +415,10 @@ __rtx_link_cmd() { ':tool:__rtx_tool_versions' \ ':path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_local_cmd] )) || __rtx_local_cmd() { @@ -398,9 +429,10 @@ __rtx_local_cmd() { '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ '--path[Get the path of the config file]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_ls_cmd] )) || __rtx_ls_cmd() { @@ -413,9 +445,10 @@ __rtx_ls_cmd() { '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ '--no-header[Don'\''t display headers]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_ls_remote_cmd] )) || __rtx_ls_remote_cmd() { @@ -423,17 +456,19 @@ __rtx_ls_remote_cmd() { '::plugin:__rtx_plugins' \ '--all[Show all installed plugins and versions]' \ '::prefix:__rtx_prefixes' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_outdated_cmd] )) || __rtx_outdated_cmd() { _arguments -s -S \ '*::tool:__rtx_tool_versions' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_plugins_cmd] )) || __rtx_plugins_cmd() { @@ -441,9 +476,10 @@ __rtx_plugins_cmd() { '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_plugins_cmds' \ '*::arg:->args' && ret=0 @@ -471,8 +507,9 @@ __rtx_plugins_install_cmd() { '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ '(-a --all)'{-a,--all}'[Install all missing plugins]' \ '*'{-v,--verbose}'[Show installation output]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_plugins_link_cmd] )) || __rtx_plugins_link_cmd() { @@ -480,9 +517,10 @@ __rtx_plugins_link_cmd() { ':name:' \ '::path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite existing plugin]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_plugins_ls_cmd] )) || __rtx_plugins_ls_cmd() { @@ -490,18 +528,20 @@ __rtx_plugins_ls_cmd() { '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_plugins_ls_remote_cmd] )) || __rtx_plugins_ls_remote_cmd() { _arguments -s -S \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_plugins_uninstall_cmd] )) || __rtx_plugins_uninstall_cmd() { @@ -509,34 +549,38 @@ __rtx_plugins_uninstall_cmd() { '*::plugin:__rtx_plugins' \ '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ '(-a --all)'{-a,--all}'[Remove all plugins]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_plugins_update_cmd] )) || __rtx_plugins_update_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_prune_cmd] )) || __rtx_prune_cmd() { _arguments -s -S \ '*::plugin:__rtx_plugins' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_reshim_cmd] )) || __rtx_reshim_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_run_cmd] )) || __rtx_run_cmd() { @@ -553,7 +597,7 @@ __rtx_run_cmd() { '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_self_update_cmd] )) || __rtx_self_update_cmd() { @@ -562,15 +606,17 @@ __rtx_self_update_cmd() { '--no-plugins[Disable auto-updating plugins]' \ '(-y --yes)'{-y,--yes}'[Skip confirmation prompt]' \ '::version:' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' } (( $+functions[__rtx_settings_cmd] )) || __rtx_settings_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_settings_cmds' \ '*::arg:->args' && ret=0 @@ -592,33 +638,37 @@ return ret __rtx_settings_get_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_settings_ls_cmd] )) || __rtx_settings_ls_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_settings_set_cmd] )) || __rtx_settings_set_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ ':value:' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_settings_unset_cmd] )) || __rtx_settings_unset_cmd() { _arguments -s -S \ ':setting:__rtx_settings' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_shell_cmd] )) || __rtx_shell_cmd() { @@ -627,16 +677,18 @@ __rtx_shell_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_sync_cmd] )) || __rtx_sync_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_sync_cmds' \ '*::arg:->args' && ret=0 @@ -658,26 +710,29 @@ __rtx_sync_node_cmd() { '--brew[Get tool versions from Homebrew]' \ '--nvm[Get tool versions from nvm]' \ '--nodenv[Get tool versions from nodenv]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_sync_python_cmd] )) || __rtx_sync_python_cmd() { _arguments -s -S \ '--pyenv[Get tool versions from pyenv]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_task_cmd] )) || __rtx_task_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '--hidden[Show hidden tasks]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ '1: :__rtx_task_cmds' \ '*::arg:->args' && ret=0 @@ -699,18 +754,20 @@ __rtx_task_edit_cmd() { _arguments -s -S \ ':task:__rtx_tasks' \ '(-p --path)'{-p,--path}'[Display the path to the task instead of editing it]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_task_ls_cmd] )) || __rtx_task_ls_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '--hidden[Show hidden tasks]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_task_run_cmd] )) || __rtx_task_run_cmd() { @@ -727,7 +784,7 @@ __rtx_task_run_cmd() { '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_trust_cmd] )) || __rtx_trust_cmd() { @@ -735,9 +792,10 @@ __rtx_trust_cmd() { '::config_file:_files' \ '(-a --all)'{-a,--all}'[Trust all config files in the current directory and its parents]' \ '--untrust[No longer trust this config]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_uninstall_cmd] )) || __rtx_uninstall_cmd() { @@ -745,9 +803,10 @@ __rtx_uninstall_cmd() { '*::installed_tool:__rtx_installed_tool_versions' \ '(-a --all)'{-a,--all}'[Delete all installed versions]' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_upgrade_cmd] )) || __rtx_upgrade_cmd() { @@ -757,9 +816,10 @@ __rtx_upgrade_cmd() { '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-i --interactive)'{-i,--interactive}'[Display multiselect menu to choose which tools to upgrade]' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_use_cmd] )) || __rtx_use_cmd() { @@ -774,16 +834,18 @@ __rtx_use_cmd() { '*--remove=[Remove the tool(s) from config file]:remove:' \ '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ '--pin[Save exact version to config file]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_version_cmd] )) || __rtx_version_cmd() { _arguments -s -S \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_watch_cmd] )) || __rtx_watch_cmd() { @@ -791,17 +853,19 @@ __rtx_watch_cmd() { '*'{-t,--task}'=[Task to run]:task:__rtx_tasks' \ '*::args:' \ '*'{-g,--glob}'=[Files to watch]:glob:' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_where_cmd] )) || __rtx_where_cmd() { _arguments -s -S \ ':tool:__rtx_tool_versions' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_which_cmd] )) || __rtx_which_cmd() { @@ -810,9 +874,10 @@ __rtx_which_cmd() { '--plugin[Show the plugin name instead of the path]' \ '--version[Show the version instead of the path]' \ '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ - '(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } (( $+functions[__rtx_cmds] )) || __rtx_cmds() { diff --git a/completions/rtx.bash b/completions/rtx.bash index f768eebd5..cb65510d5 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -697,7 +697,7 @@ _rtx() { case "${cmd}" in rtx) - opts="-q -v -y -h -V --debug --log-level --trace --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" + opts="-C -q -v -y -h -V --debug --log-level --trace --cd --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -707,6 +707,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -715,7 +723,7 @@ _rtx() { return 0 ;; rtx__activate) - opts="-s -q -v -y -h --shell --status --quiet --debug --log-level --trace --verbose --yes --help bash fish nu xonsh zsh" + opts="-s -q -C -v -y -h --shell --status --quiet --debug --log-level --trace --cd --verbose --yes --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -733,6 +741,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -741,7 +757,7 @@ _rtx() { return 0 ;; rtx__alias) - opts="-p -q -v -y -h --plugin --no-header --debug --log-level --trace --quiet --verbose --yes --help get ls set unset help" + opts="-p -C -q -v -y -h --plugin --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -759,6 +775,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -767,7 +791,7 @@ _rtx() { return 0 ;; rtx__alias__get) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -777,6 +801,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -869,7 +901,7 @@ _rtx() { return 0 ;; rtx__alias__ls) - opts="-q -v -y -h --no-header --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]" + opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -879,6 +911,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -887,7 +927,7 @@ _rtx() { return 0 ;; rtx__alias__set) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -897,6 +937,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -905,7 +953,7 @@ _rtx() { return 0 ;; rtx__alias__unset) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -915,6 +963,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -923,7 +979,7 @@ _rtx() { return 0 ;; rtx__asdf) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -933,6 +989,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -941,7 +1005,7 @@ _rtx() { return 0 ;; rtx__bin__paths) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -951,6 +1015,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -959,7 +1031,7 @@ _rtx() { return 0 ;; rtx__cache) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help clear help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -969,6 +1041,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -977,7 +1057,7 @@ _rtx() { return 0 ;; rtx__cache__clear) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -987,6 +1067,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1037,7 +1125,7 @@ _rtx() { return 0 ;; rtx__completion) - opts="-s -q -v -y -h --shell --debug --log-level --trace --quiet --verbose --yes --help bash fish zsh" + opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1055,6 +1143,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1063,7 +1159,7 @@ _rtx() { return 0 ;; rtx__config) - opts="-q -v -y -h --no-header --debug --log-level --trace --quiet --verbose --yes --help ls generate help" + opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help ls generate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1073,6 +1169,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1081,7 +1185,7 @@ _rtx() { return 0 ;; rtx__config__generate) - opts="-o -q -v -y -h --output --debug --log-level --trace --quiet --verbose --yes --help" + opts="-o -C -q -v -y -h --output --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1099,6 +1203,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1163,7 +1275,7 @@ _rtx() { return 0 ;; rtx__config__ls) - opts="-q -v -y -h --no-header --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1173,6 +1285,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1181,7 +1301,7 @@ _rtx() { return 0 ;; rtx__current) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1191,6 +1311,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1199,7 +1327,7 @@ _rtx() { return 0 ;; rtx__deactivate) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1209,6 +1337,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1217,7 +1353,7 @@ _rtx() { return 0 ;; rtx__direnv) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help envrc exec activate help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1227,6 +1363,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1235,7 +1379,7 @@ _rtx() { return 0 ;; rtx__direnv__activate) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1245,6 +1389,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1253,7 +1405,7 @@ _rtx() { return 0 ;; rtx__direnv__envrc) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1263,6 +1415,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1271,7 +1431,7 @@ _rtx() { return 0 ;; rtx__direnv__exec) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1281,6 +1441,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1359,7 +1527,7 @@ _rtx() { return 0 ;; rtx__doctor) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1369,6 +1537,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1377,7 +1553,7 @@ _rtx() { return 0 ;; rtx__env) - opts="-s -J -q -v -y -h --shell --json --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-s -J -C -q -v -y -h --shell --json --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1395,6 +1571,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1403,7 +1587,7 @@ _rtx() { return 0 ;; rtx__env__vars) - opts="-q -v -y -h --file --remove --debug --log-level --trace --quiet --verbose --yes --help [ENV_VARS]..." + opts="-C -q -v -y -h --file --remove --debug --log-level --trace --cd --quiet --verbose --yes --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1421,6 +1605,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1429,7 +1621,7 @@ _rtx() { return 0 ;; rtx__exec) - opts="-c -C -j -q -v -y -h --command --cd --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -j -C -q -v -y -h --command --jobs --raw --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1443,24 +1635,24 @@ _rtx() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --cd) + --jobs) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -C) + -j) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --jobs) - COMPREPLY=($(compgen -f "${cur}")) + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; - -j) + --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + -C) + COMPREPLY=($(compgen -f "${cur}")) return 0 ;; *) @@ -1471,7 +1663,7 @@ _rtx() { return 0 ;; rtx__global) - opts="-q -v -y -h --pin --fuzzy --remove --path --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-C -q -v -y -h --pin --fuzzy --remove --path --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1485,6 +1677,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2501,7 +2701,7 @@ _rtx() { return 0 ;; rtx__hook__env) - opts="-s -q -v -y -h --shell --status --quiet --debug --log-level --trace --verbose --yes --help" + opts="-s -q -C -v -y -h --shell --status --quiet --debug --log-level --trace --cd --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2519,6 +2719,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2527,7 +2735,7 @@ _rtx() { return 0 ;; rtx__hook__not__found) - opts="-s -q -v -y -h --shell --debug --log-level --trace --quiet --verbose --yes --help " + opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2545,6 +2753,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2553,7 +2769,7 @@ _rtx() { return 0 ;; rtx__implode) - opts="-n -q -v -y -h --config --dry-run --debug --log-level --trace --quiet --verbose --yes --help" + opts="-n -C -q -v -y -h --config --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2563,6 +2779,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2571,7 +2795,7 @@ _rtx() { return 0 ;; rtx__install) - opts="-f -j -v -q -y -h --force --jobs --raw --verbose --debug --log-level --trace --quiet --yes --help [TOOL@VERSION]..." + opts="-f -j -v -C -q -y -h --force --jobs --raw --verbose --debug --log-level --trace --cd --quiet --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2589,6 +2813,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2597,7 +2829,7 @@ _rtx() { return 0 ;; rtx__latest) - opts="-i -q -v -y -h --installed --debug --log-level --trace --quiet --verbose --yes --help [ASDF_VERSION]" + opts="-i -C -q -v -y -h --installed --debug --log-level --trace --cd --quiet --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2607,6 +2839,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2615,7 +2855,7 @@ _rtx() { return 0 ;; rtx__link) - opts="-f -q -v -y -h --force --debug --log-level --trace --quiet --verbose --yes --help " + opts="-f -C -q -v -y -h --force --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2625,15 +2865,23 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; - *) - COMPREPLY=() + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; rtx__local) - opts="-p -q -v -y -h --parent --pin --fuzzy --remove --path --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-p -C -q -v -y -h --parent --pin --fuzzy --remove --path --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2647,6 +2895,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2655,7 +2911,7 @@ _rtx() { return 0 ;; rtx__ls) - opts="-p -c -g -i -J -m -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --no-header --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." + opts="-p -c -g -i -J -m -C -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2677,6 +2933,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2685,7 +2949,7 @@ _rtx() { return 0 ;; rtx__ls__remote) - opts="-q -v -y -h --all --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION] [PREFIX]" + opts="-C -q -v -y -h --all --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION] [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2695,6 +2959,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2703,7 +2975,7 @@ _rtx() { return 0 ;; rtx__outdated) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2713,6 +2985,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2721,7 +3001,7 @@ _rtx() { return 0 ;; rtx__plugins) - opts="-a -c -u -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --quiet --verbose --yes --help install link ls ls-remote uninstall update help" + opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --cd --quiet --verbose --yes --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2731,6 +3011,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2851,7 +3139,7 @@ _rtx() { return 0 ;; rtx__plugins__install) - opts="-f -a -v -q -y -h --force --all --verbose --debug --log-level --trace --quiet --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." + opts="-f -a -v -C -q -y -h --force --all --verbose --debug --log-level --trace --cd --quiet --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2861,6 +3149,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2869,7 +3165,7 @@ _rtx() { return 0 ;; rtx__plugins__link) - opts="-f -q -v -y -h --force --debug --log-level --trace --quiet --verbose --yes --help [PATH]" + opts="-f -C -q -v -y -h --force --debug --log-level --trace --cd --quiet --verbose --yes --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2879,6 +3175,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2887,7 +3191,7 @@ _rtx() { return 0 ;; rtx__plugins__ls) - opts="-a -c -u -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --quiet --verbose --yes --help" + opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2897,6 +3201,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2905,7 +3217,7 @@ _rtx() { return 0 ;; rtx__plugins__ls__remote) - opts="-u -q -v -y -h --urls --only-names --debug --log-level --trace --quiet --verbose --yes --help" + opts="-u -C -q -v -y -h --urls --only-names --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2915,6 +3227,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2923,7 +3243,7 @@ _rtx() { return 0 ;; rtx__plugins__uninstall) - opts="-p -a -q -v -y -h --purge --all --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." + opts="-p -a -C -q -v -y -h --purge --all --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2933,6 +3253,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2941,7 +3269,7 @@ _rtx() { return 0 ;; rtx__plugins__update) - opts="-j -q -v -y -h --jobs --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." + opts="-j -C -q -v -y -h --jobs --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2959,6 +3287,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2967,7 +3303,7 @@ _rtx() { return 0 ;; rtx__prune) - opts="-n -q -v -y -h --dry-run --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN]..." + opts="-n -C -q -v -y -h --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2977,6 +3313,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2985,7 +3329,7 @@ _rtx() { return 0 ;; rtx__render__completion) - opts="-s -q -v -y -h --shell --debug --log-level --trace --quiet --verbose --yes --help bash elvish fish powershell zsh" + opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3003,6 +3347,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3011,7 +3363,7 @@ _rtx() { return 0 ;; rtx__render__help) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3021,6 +3373,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3029,7 +3389,7 @@ _rtx() { return 0 ;; rtx__render__mangen) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3039,6 +3399,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3047,7 +3415,7 @@ _rtx() { return 0 ;; rtx__reshim) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [PLUGIN] [VERSION]" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3057,6 +3425,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3107,7 +3483,7 @@ _rtx() { return 0 ;; rtx__self__update) - opts="-f -y -q -v -h --force --no-plugins --yes --debug --log-level --trace --quiet --verbose --help [VERSION]" + opts="-f -y -C -q -v -h --force --no-plugins --yes --debug --log-level --trace --cd --quiet --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3117,6 +3493,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3125,7 +3509,7 @@ _rtx() { return 0 ;; rtx__settings) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help get ls set unset help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3135,6 +3519,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3143,7 +3535,7 @@ _rtx() { return 0 ;; rtx__settings__get) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3153,6 +3545,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3245,7 +3645,7 @@ _rtx() { return 0 ;; rtx__settings__ls) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3255,6 +3655,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3263,7 +3671,7 @@ _rtx() { return 0 ;; rtx__settings__set) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3273,6 +3681,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3281,7 +3697,7 @@ _rtx() { return 0 ;; rtx__settings__unset) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help " + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3291,6 +3707,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3299,7 +3723,7 @@ _rtx() { return 0 ;; rtx__shell) - opts="-j -u -q -v -y -h --jobs --raw --unset --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-j -u -C -q -v -y -h --jobs --raw --unset --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3317,6 +3741,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3325,7 +3757,7 @@ _rtx() { return 0 ;; rtx__sync) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help node python help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3335,6 +3767,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3399,7 +3839,7 @@ _rtx() { return 0 ;; rtx__sync__node) - opts="-q -v -y -h --brew --nvm --nodenv --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --brew --nvm --nodenv --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3409,6 +3849,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3417,7 +3865,7 @@ _rtx() { return 0 ;; rtx__sync__python) - opts="-q -v -y -h --pyenv --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --pyenv --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3427,6 +3875,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3435,7 +3891,7 @@ _rtx() { return 0 ;; rtx__task) - opts="-q -v -y -h --no-header --hidden --debug --log-level --trace --quiet --verbose --yes --help edit ls run help" + opts="-C -q -v -y -h --no-header --hidden --debug --log-level --trace --cd --quiet --verbose --yes --help edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3445,6 +3901,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3453,7 +3917,7 @@ _rtx() { return 0 ;; rtx__task__edit) - opts="-p -q -v -y -h --path --debug --log-level --trace --quiet --verbose --yes --help " + opts="-p -C -q -v -y -h --path --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3463,6 +3927,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3541,7 +4013,7 @@ _rtx() { return 0 ;; rtx__task__ls) - opts="-q -v -y -h --no-header --hidden --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --no-header --hidden --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3551,6 +4023,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3601,7 +4081,7 @@ _rtx() { return 0 ;; rtx__trust) - opts="-a -q -v -y -h --all --untrust --debug --log-level --trace --quiet --verbose --yes --help [CONFIG_FILE]" + opts="-a -C -q -v -y -h --all --untrust --debug --log-level --trace --cd --quiet --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3611,6 +4091,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3619,7 +4107,7 @@ _rtx() { return 0 ;; rtx__uninstall) - opts="-a -n -q -v -y -h --all --dry-run --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-a -n -C -q -v -y -h --all --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3629,6 +4117,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3637,7 +4133,7 @@ _rtx() { return 0 ;; rtx__upgrade) - opts="-n -j -i -q -v -y -h --dry-run --jobs --interactive --raw --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-n -j -i -C -q -v -y -h --dry-run --jobs --interactive --raw --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3655,6 +4151,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3663,7 +4167,7 @@ _rtx() { return 0 ;; rtx__use) - opts="-f -g -e -j -p -q -v -y -h --force --fuzzy --global --env --jobs --raw --remove --path --pin --debug --log-level --trace --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-f -g -e -j -p -C -q -v -y -h --force --fuzzy --global --env --jobs --raw --remove --path --pin --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3701,6 +4205,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3709,7 +4221,7 @@ _rtx() { return 0 ;; rtx__version) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3719,6 +4231,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3727,7 +4247,7 @@ _rtx() { return 0 ;; rtx__watch) - opts="-t -g -q -v -y -h --task --glob --debug --log-level --trace --quiet --verbose --yes --help [ARGS]..." + opts="-t -g -C -q -v -y -h --task --glob --debug --log-level --trace --cd --quiet --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3753,6 +4273,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3761,7 +4289,7 @@ _rtx() { return 0 ;; rtx__where) - opts="-q -v -y -h --debug --log-level --trace --quiet --verbose --yes --help [ASDF_VERSION]" + opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3771,6 +4299,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3779,7 +4315,7 @@ _rtx() { return 0 ;; rtx__which) - opts="-t -q -v -y -h --plugin --version --tool --debug --log-level --trace --quiet --verbose --yes --help " + opts="-t -C -q -v -y -h --plugin --version --tool --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3797,6 +4333,14 @@ _rtx() { COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) return 0 ;; + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; diff --git a/completions/rtx.fish b/completions/rtx.fish index a13b2d04c..923f07a93 100644 --- a/completions/rtx.fish +++ b/completions/rtx.fish @@ -1,9 +1,10 @@ set -l fssf "__fish_seen_subcommand_from" # rtx +complete -kxc rtx -s C -l cd -a "(__fish_complete_directories)" -d 'Change directory before running command' complete -kxc rtx -s q -l quiet -d 'Suppress non-error messages' complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' -complete -kxc rtx -s y -l yes -d 'Answer yes to all prompts' +complete -kxc rtx -s y -l yes -d 'Answer yes to all confirmation prompts' set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell session' complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' @@ -127,7 +128,6 @@ complete -kxc rtx -n "$fssf env-vars" -l remove -d 'Remove the environment varia # exec complete -kxc rtx -n "$fssf exec" -s c -l command -d 'Command string to execute' -complete -kxc rtx -n "$fssf exec" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' complete -kxc rtx -n "$fssf exec" -d 'Command string to execute (same as --command)' complete -kxc rtx -n "$fssf exec" -s j -l jobs -d 'Number of jobs to run in parallel' complete -kxc rtx -n "$fssf exec" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' diff --git a/e2e/test_exec b/e2e/test_exec index e372fd96c..5f30b243b 100755 --- a/e2e/test_exec +++ b/e2e/test_exec @@ -10,4 +10,6 @@ assert() { fi } +assert "rtx x -C $PWD/direnv -- pwd" "$(pwd)/direnv" +assert "rtx x -C ./direnv -- pwd" "$(pwd)/direnv" assert "rtx x -C direnv -- pwd" "$(pwd)/direnv" diff --git a/src/cli/args/cd.rs b/src/cli/args/cd.rs new file mode 100644 index 000000000..2eebe08b1 --- /dev/null +++ b/src/cli/args/cd.rs @@ -0,0 +1,17 @@ +use clap::{Arg, ArgAction}; + +#[derive(Clone)] +pub struct Cd; + +impl Cd { + pub fn arg() -> Arg { + Arg::new("cd") + .short('C') + .long("cd") + .help("Change directory before running command") + .global(true) + .action(ArgAction::Set) + .value_hint(clap::ValueHint::DirPath) + .value_name("DIR") + } +} diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index 30ecb9d08..e3c7dafad 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,3 +1,4 @@ +pub mod cd; pub mod env_var; pub mod log_level; pub mod quiet; diff --git a/src/cli/args/yes.rs b/src/cli/args/yes.rs index d9d55179c..2abbb0d80 100644 --- a/src/cli/args/yes.rs +++ b/src/cli/args/yes.rs @@ -7,7 +7,7 @@ impl Yes { Arg::new("yes") .short('y') .long("yes") - .help("Answer yes to all prompts") + .help("Answer yes to all confirmation prompts") .action(ArgAction::SetTrue) .global(true) } diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index e3066175f..fafa3c85f 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -1,14 +1,13 @@ use std::fs::{create_dir_all, File}; use std::io::Write; -use std::ops::Deref; use eyre::Result; use crate::config::Config; use crate::hash::hash_to_str; +use crate::env; use crate::toolset::ToolsetBuilder; -use crate::{dirs, env}; /// [internal] This is an internal command that writes an envrc file /// for direnv to consume. @@ -22,7 +21,7 @@ impl Envrc { let envrc_path = env::RTX_TMP_DIR .join("direnv") - .join(hash_to_str(dirs::CURRENT.deref()) + ".envrc"); + .join(hash_to_str(&env::current_dir()?) + ".envrc"); // TODO: exit early if envrc_path exists and is up to date create_dir_all(envrc_path.parent().unwrap())?; @@ -58,8 +57,8 @@ impl Envrc { #[cfg(test)] mod tests { - use super::*; - use crate::file; + + use crate::{dirs, file}; #[test] fn test_direnv_envrc() { diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index c0d8e6bbd..15b93f984 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -3,7 +3,7 @@ use color_eyre::Result; use crate::config::config_file::rtx_toml::RtxToml; use crate::config::config_file::ConfigFile; use crate::config::Config; -use crate::dirs; +use crate::env; use crate::env::RTX_DEFAULT_CONFIG_FILENAME; use crate::file::display_path; @@ -67,7 +67,7 @@ impl EnvVars { } fn get_rtx_toml(filename: &str) -> Result { - let path = dirs::CURRENT.join(filename); + let path = env::current_dir()?.join(filename); let rtx_toml = if path.exists() { RtxToml::from_file(&path)? } else { @@ -79,11 +79,11 @@ fn get_rtx_toml(filename: &str) -> Result { #[cfg(test)] mod tests { - use crate::{dirs, file}; + use crate::{env, file}; use std::path::PathBuf; fn remove_config_file(filename: &str) -> PathBuf { - let cf_path = dirs::CURRENT.join(filename); + let cf_path = env::current_dir().unwrap().join(filename); let _ = file::remove_file(&cf_path); cf_path } diff --git a/src/cli/exec.rs b/src/cli/exec.rs index c72539bbf..8b1ece6e9 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -1,6 +1,5 @@ use std::collections::BTreeMap; use std::ffi::{OsStr, OsString}; -use std::path::PathBuf; use clap::ValueHint; use duct::IntoExecutablePath; @@ -39,10 +38,6 @@ pub struct Exec { #[clap(short, long = "command", value_hint = ValueHint::CommandString, conflicts_with = "command")] pub c: Option, - /// Change to this directory before executing the command - #[clap(short = 'C', long, value_hint = ValueHint::DirPath)] - pub cd: Option, - /// Number of jobs to run in parallel /// [default: 4] #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] @@ -86,9 +81,6 @@ impl Exec { } let args = args.into_iter().map(Into::into).collect::>(); let program = program.to_executable(); - if let Some(cd) = &self.cd { - env::set_current_dir(cd)?; - } let err = exec::Command::new(program.clone()).args(&args).exec(); bail!("{:?} {err}", program.to_string_lossy()) } @@ -102,9 +94,6 @@ impl Exec { E: AsRef, { let mut cmd = cmd::cmd(program, args); - if let Some(cd) = &self.cd { - cmd = cmd.dir(cd); - } for (k, v) in env.iter() { cmd = cmd.env(k, v); } @@ -147,6 +136,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { + use std::env; #[test] fn test_exec_ok() { @@ -161,6 +151,8 @@ mod tests { #[test] fn test_exec_cd() { + let cwd = env::current_dir().unwrap(); assert_cli!("exec", "-C", "/tmp", "--", "pwd"); + env::set_current_dir(cwd).unwrap(); } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 3c3f5d4a9..92a2e3f02 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -10,7 +10,7 @@ use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME use crate::file::display_path; use crate::plugins::PluginName; -use crate::{dirs, env, file}; +use crate::{env, file}; /// Sets/gets tool version in local .tool-versions or .rtx.toml /// @@ -59,7 +59,7 @@ impl Local { let path = if self.parent { get_parent_path()? } else { - get_path() + get_path()? }; local( &config, @@ -73,12 +73,12 @@ impl Local { } } -fn get_path() -> PathBuf { - let rtx_toml = dirs::CURRENT.join(RTX_DEFAULT_CONFIG_FILENAME.as_str()); +fn get_path() -> Result { + let rtx_toml = env::current_dir()?.join(RTX_DEFAULT_CONFIG_FILENAME.as_str()); if *env::RTX_USE_TOML || rtx_toml.exists() { - rtx_toml + Ok(rtx_toml) } else { - dirs::CURRENT.join(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) + Ok(env::current_dir()?.join(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str())) } } @@ -87,7 +87,7 @@ pub fn get_parent_path() -> Result { if !*env::RTX_USE_TOML { filenames.push(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); } - file::find_up(&dirs::CURRENT, &filenames) + file::find_up(&env::current_dir()?, &filenames) .wrap_err_with(|| eyre!("no {} file found", filenames.join(" or "),)) } @@ -170,7 +170,7 @@ mod tests { use crate::cli::tests::grep; use crate::test::reset_config; - use crate::{dirs, file}; + use crate::{dirs, env, file}; #[test] fn test_local_remove() { @@ -312,8 +312,8 @@ mod tests { where T: FnOnce() + panic::UnwindSafe, { - let _ = file::remove_file(dirs::CURRENT.join(".test.rtx.toml")); - let cf_path = dirs::CURRENT.join(".test-tool-versions"); + let _ = file::remove_file(env::current_dir().unwrap().join(".test.rtx.toml")); + let cf_path = env::current_dir().unwrap().join(".test-tool-versions"); let orig = file::read_to_string(&cf_path).unwrap(); let result = panic::catch_unwind(test); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 0683e4cab..f1a9aafc7 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -184,6 +184,7 @@ impl Cli { .arg(args::log_level::Debug::arg()) .arg(args::log_level::LogLevel::arg()) .arg(args::log_level::Trace::arg()) + .arg(args::cd::Cd::arg()) .arg(args::quiet::Quiet::arg()) .arg(args::verbose::Verbose::arg()) .arg(args::yes::Yes::arg()), diff --git a/src/cli/run.rs b/src/cli/run.rs index 2615c80e4..a1e0d4bcc 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -380,7 +380,7 @@ impl Run { .or(task.dir.as_ref()) .cloned() .or_else(|| config.project_root.clone()) - .unwrap_or_else(|| env::PWD.clone()) + .unwrap_or_else(|| env::current_dir().unwrap().clone()) } fn save_checksum(&self, task: &Task) -> Result<()> { diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs index d13f4b8e2..e9debe25c 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/task/edit.rs @@ -30,7 +30,7 @@ impl TaskEdit { let path = config .project_root .as_ref() - .unwrap_or(&env::PWD) + .unwrap_or(&env::current_dir()?) .join(".rtx") .join("tasks") .join(&self.task); diff --git a/src/cli/use.rs b/src/cli/use.rs index 6220005a0..9faa8c563 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -139,11 +139,11 @@ impl Use { let path = if self.global { global_file() } else if let Some(env) = &self.env { - config_file_from_dir(&dirs::CURRENT.join(format!(".rtx.{}.toml", env))) + config_file_from_dir(&env::current_dir()?.join(format!(".rtx.{}.toml", env))) } else if let Some(p) = &self.path { config_file_from_dir(p) } else { - config_file_from_dir(&dirs::CURRENT) + config_file_from_dir(&env::current_dir()?) }; config_file::parse_or_init(&path) } @@ -222,11 +222,11 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::{dirs, file}; + use crate::{dirs, env, file}; #[test] fn test_use_local() { - let cf_path = dirs::CURRENT.join(".test.rtx.toml"); + let cf_path = env::current_dir().unwrap().join(".test.rtx.toml"); file::write(&cf_path, "").unwrap(); assert_cli_snapshot!("use", "tiny@2", @"rtx ~/cwd/.test.rtx.toml tools: tiny@2.1.0"); @@ -256,7 +256,7 @@ mod tests { #[test] fn test_use_local_tool_versions() { - let cf_path = dirs::CURRENT.join(".test-tool-versions"); + let cf_path = env::current_dir().unwrap().join(".test-tool-versions"); file::write(&cf_path, "").unwrap(); assert_cli_snapshot!("use", "tiny@3", @"rtx ~/cwd/.test-tool-versions tools: tiny@3.1.0"); diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap index a0050ed78..2737c4128 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap @@ -7,6 +7,7 @@ RtxToml(/tmp/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "cd": Null, "ci": Null, "color": Null, "debug": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index 865dfd784..e65f4a962 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -29,5 +29,6 @@ expression: cf.settings().unwrap() "yes": null, "task_output": null, "not_found_auto_install": null, - "ci": null + "ci": null, + "cd": null } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index a1465bae9..b4c0c2c97 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -7,6 +7,7 @@ RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref: "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "cd": Null, "ci": Null, "color": Null, "debug": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap index ac7cfbeca..7b26e59d7 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap @@ -7,6 +7,7 @@ RtxToml(~/fixtures/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "cd": Null, "ci": Null, "color": Null, "debug": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap index 008bdff73..77cd0f6ac 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap @@ -7,6 +7,7 @@ RtxToml(/tmp/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "cd": Null, "ci": Null, "color": Null, "debug": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap index b8fbed129..506ca353f 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap @@ -7,6 +7,7 @@ RtxToml(/tmp/.rtx.toml): { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "cd": Null, "ci": Null, "color": Null, "debug": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap index e631174c1..6a95fc58b 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap @@ -7,6 +7,7 @@ RtxToml(/tmp/.rtx.toml): node@16.0.1 node@18.0.1 { "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, + "cd": Null, "ci": Null, "color": Null, "debug": Null, diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 64a7df293..c23fac069 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -201,16 +201,24 @@ impl ConfigFile for ToolVersions { #[cfg(test)] pub(crate) mod tests { - use crate::dirs; + use crate::env; use pretty_assertions::assert_eq; use super::*; #[test] fn test_parse() { - let tv = - ToolVersions::from_file(dirs::CURRENT.join(".test-tool-versions").as_path()).unwrap(); - assert_eq!(tv.path, dirs::CURRENT.join(".test-tool-versions")); + let tv = ToolVersions::from_file( + env::current_dir() + .unwrap() + .join(".test-tool-versions") + .as_path(), + ) + .unwrap(); + assert_eq!( + tv.path, + env::current_dir().unwrap().join(".test-tool-versions") + ); assert_display_snapshot!(tv, @"ToolVersions(~/cwd/.test-tool-versions): tiny@3"); } @@ -223,7 +231,7 @@ pub(crate) mod tests { shfmt 3.6.0 # tail comment "}; - let path = dirs::CURRENT.join(".test-tool-versions"); + let path = env::current_dir().unwrap().join(".test-tool-versions"); let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_eq!(tv.dump(), orig); } @@ -233,7 +241,7 @@ pub(crate) mod tests { let orig = indoc! {" ruby: 3.0.5 "}; - let path = dirs::CURRENT.join(".test-tool-versions"); + let path = env::current_dir().unwrap().join(".test-tool-versions"); let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_snapshot!(tv.dump(), @r###" ruby 3.0.5 @@ -246,7 +254,7 @@ pub(crate) mod tests { ruby {{'3.0.5'}} python {{exec(command='echo 3.11.0')}} "}; - let path = dirs::CURRENT.join(".test-tool-versions"); + let path = env::current_dir().unwrap().join(".test-tool-versions"); assert_cli!("trust", path.to_string_lossy()); let tv = ToolVersions::parse_str(orig, path.clone()).unwrap(); assert_cli!("trust", "--untrust", path.to_string_lossy()); @@ -261,7 +269,7 @@ pub(crate) mod tests { let orig = indoc! {" ruby: 3.0.5 3.1 "}; - let path = dirs::CURRENT.join(".test-tool-versions"); + let path = env::current_dir().unwrap().join(".test-tool-versions"); let tv = ToolVersions::parse_str(orig, path).unwrap(); assert_display_snapshot!(tv.to_toolset(), @"ruby@3.0.5 ruby@3.1"); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 16ebd97f2..419b9d122 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -375,7 +375,8 @@ pub static DEFAULT_CONFIG_FILENAMES: Lazy> = Lazy::new(|| { }); pub fn load_config_paths(config_filenames: &[String]) -> Vec { - let mut config_files = file::FindUp::new(&dirs::CURRENT, config_filenames).collect::>(); + let mut config_files = + file::FindUp::new(&env::current_dir().unwrap(), config_filenames).collect::>(); for cf in global_config_files() { config_files.push(cf); diff --git a/src/config/settings.rs b/src/config/settings.rs index 2a58433e7..d2bcbe141 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -62,6 +62,7 @@ pub struct Settings { pub not_found_auto_install: bool, #[config(env = "CI", default = false)] pub ci: bool, + pub cd: Option, } pub type SettingsPartial = ::Partial; @@ -84,6 +85,14 @@ impl Settings { return Ok(settings.clone()); } let mut settings = Self::default_builder().load()?; + if let Some(cd) = &settings.cd { + static ORIG_PATH: Lazy> = Lazy::new(env::current_dir); + let mut cd = PathBuf::from(cd); + if cd.is_relative() { + cd = ORIG_PATH.as_ref()?.join(cd); + } + env::set_current_dir(cd)?; + } if settings.raw { settings.jobs = 1; } @@ -139,6 +148,9 @@ impl Settings { } pub fn add_cli_matches(m: &clap::ArgMatches) { let mut s = SettingsPartial::empty(); + if let Some(cd) = m.get_one::("cd") { + s.cd = Some(cd.to_string()); + } if let Some(true) = m.get_one::("yes") { s.yes = Some(true); } @@ -172,7 +184,7 @@ impl Settings { } pub fn hidden_configs() -> HashSet<&'static str> { static HIDDEN_CONFIGS: Lazy> = - Lazy::new(|| ["ci", "debug", "trace", "log_level"].into()); + Lazy::new(|| ["ci", "cd", "debug", "trace", "log_level"].into()); HIDDEN_CONFIGS.clone() } diff --git a/src/dirs.rs b/src/dirs.rs index d4a22b1d5..7815232f4 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -4,7 +4,6 @@ use once_cell::sync::Lazy; use crate::env; -pub static CURRENT: Lazy<&Path> = Lazy::new(|| &env::PWD); pub static HOME: Lazy<&Path> = Lazy::new(|| &env::HOME); pub static DATA: Lazy<&Path> = Lazy::new(|| &env::RTX_DATA_DIR); pub static CACHE: Lazy<&Path> = Lazy::new(|| &env::RTX_CACHE_DIR); diff --git a/src/env.rs b/src/env.rs index 8c6160873..d63e5c1f0 100644 --- a/src/env.rs +++ b/src/env.rs @@ -20,7 +20,6 @@ pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "s // paths and directories pub static HOME: Lazy = Lazy::new(|| dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/"))); -pub static PWD: Lazy = Lazy::new(|| current_dir().unwrap_or_else(|_| PathBuf::new())); pub static EDITOR: Lazy = Lazy::new(|| var("VISUAL").unwrap_or_else(|_| var("EDITOR").unwrap_or_else(|_| "nano".into()))); diff --git a/src/file.rs b/src/file.rs index ef23b2661..3f65b03a1 100644 --- a/src/file.rs +++ b/src/file.rs @@ -309,7 +309,7 @@ mod tests { #[test] fn test_find_up() { - let path = &dirs::CURRENT; + let path = &env::current_dir().unwrap(); let filenames = vec![".rtxrc", ".rtxrc.toml", ".test-tool-versions"] .into_iter() .map(|s| s.to_string()) diff --git a/src/hook_env.rs b/src/hook_env.rs index 31fa85dbd..f10c43713 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -167,8 +167,6 @@ mod tests { use pretty_assertions::assert_str_eq; - use crate::dirs; - use super::*; #[test] @@ -180,7 +178,7 @@ mod tests { }; assert!(!have_config_files_been_modified(&watches, files)); - let fp = dirs::CURRENT.join(".test-tool-versions"); + let fp = env::current_dir().unwrap().join(".test-tool-versions"); let watches = HookEnvWatches { files: BTreeMap::from([(fp.clone(), UNIX_EPOCH)]), env_var_hash: "".into(), diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 8584fc338..87cea79c7 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -95,7 +95,12 @@ fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> Result Result<()> { tool: vec![], c: None, command: Some(args), - cd: None, jobs: None, raw: false, }; diff --git a/src/tera.rs b/src/tera.rs index 7425214d6..374e97514 100644 --- a/src/tera.rs +++ b/src/tera.rs @@ -11,7 +11,7 @@ use crate::hash::hash_to_str; pub static BASE_CONTEXT: Lazy = Lazy::new(|| { let mut context = Context::new(); context.insert("env", &*env::PRISTINE_ENV); - context.insert("cwd", &*env::PWD); + context.insert("cwd", &*env::current_dir().unwrap()); context }); diff --git a/src/test.rs b/src/test.rs index a89caf4ad..abb088fa8 100644 --- a/src/test.rs +++ b/src/test.rs @@ -44,7 +44,7 @@ pub fn reset_config() { ) .unwrap(); file::write( - env::PWD.join(".test-tool-versions"), + env::current_dir().unwrap().join(".test-tool-versions"), indoc! {r#" tiny 3 "#}, From 89469057362fce47916e148d99efcb9a804b8a1a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 30 Dec 2023 15:37:25 -0600 Subject: [PATCH 1469/1891] new doc site --- README.md | 3466 +----------------------------------------------- docs/deno.md | 22 +- docs/go.md | 45 +- docs/java.md | 39 +- docs/node.md | 71 +- docs/python.md | 63 +- docs/ruby.md | 74 +- 7 files changed, 17 insertions(+), 3763 deletions(-) diff --git a/README.md b/README.md index 23ba9c3e9..5c9caf6e3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- + rtx logo @@ -28,29 +28,24 @@ Note that calling `which node` gives us a real path to node, not a shim. ## Quickstart -Install rtx on macOS (other methods [here](#installation)): +Install rtx on macOS (other methods [here](https://rtx.jdx.dev/installation)): ```sh-session -$ curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx -$ chmod +x ~/bin/rtx -$ rtx --version +$ curl https://rtx.jdx.dev/install.sh | sh +$ ~/.local/share/rtx/bin/rtx --version rtx 2023.12.40 ``` Hook rtx into your shell (pick the right one for your shell): ```sh-session -# note this assumes rtx is located at ~/bin/rtx -echo 'eval "$(~/bin/rtx activate bash)"' >> ~/.bashrc -echo 'eval "$(~/bin/rtx activate zsh)"' >> ~/.zshrc -echo '~/bin/rtx activate fish | source' >> ~/.config/fish/config.fish +# note this assumes rtx is located at ~/.local/share/rtx/bin/rtx +# which is what install.sh does by default +echo 'eval "$(~/.local/share/rtx/bin/rtx activate bash)"' >> ~/.bashrc +echo 'eval "$(~/.local/share/rtx/bin/rtx activate zsh)"' >> ~/.zshrc +echo '~/.local/share/rtx/bin/rtx activate fish | source' >> ~/.config/fish/config.fish ``` -> [!TIP] -> -> If you use direnv with `layout python` or other logic that needs to reference rtx runtimes inside -> of an `.envrc`, see the [direnv section](#direnv) below. - Install a runtime and set it as the global default: ```sh-session @@ -59,3445 +54,6 @@ $ node -v v20.0.0 ``` -## Table of Contents - - -
-Click to expand - -- [What is it?](#what-is-it) -- [30 Second Demo](#30-second-demo) -- [Quickstart](#quickstart) -- [About](#about) - - [How it works](#how-it-works) - - [Common commands](#common-commands) -- [Installation](#installation) - - [Download binary](#download-binary) - - [Register shell hook](#register-shell-hook) - - [Migrate from asdf](#migrate-from-asdf) -- [Uninstalling](#uninstalling) -- [Configuration](#configuration) - - [`.rtx.toml`](#rtxtoml) - - [Legacy version files](#legacy-version-files) - - [`.tool-versions`](#tool-versions) - - [Scopes](#scopes) - - [Global config: `~/.config/rtx/config.toml`](#global-config-configrtxconfigtoml) - - [System config: `/etc/rtx/config.toml`](#system-config-etcrtxconfigtoml) - - [Environment variables](#environment-variables) -- [Shebang](#shebang) -- [[experimental] Task Runner](#experimental-task-runner) - - [Script Tasks](#script-tasks) - - [TOML-based Tasks](#toml-based-tasks) - - [Task Environment Variables](#task-environment-variables) - - [Running Tasks](#running-tasks) - - [Running on file changes](#running-on-file-changes) - - [Watching files](#watching-files) -- [Aliases](#aliases) -- [Plugins](#plugins) - - [Core Plugins](#core-plugins) - - [Plugin Authors](#plugin-authors) - - [Plugin Options](#plugin-options) -- [Versioning](#versioning) -- [Directories](#directories) - - [`~/.config/rtx`](#configrtx) - - [`~/.cache/rtx`](#cachertx) - - [`~/.local/state/rtx`](#localstatertx) - - [`~/.local/share/rtx`](#localsharertx) -- [Templates](#templates) -- [Config Environments](#config-environments) -- [IDE Integration](#ide-integration) -- [Project Roadmap](#project-roadmap) - - [Anti-goals](#anti-goals) -- [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) - - [New version of a tool is not available](#new-version-of-a-tool-is-not-available) - - [Windows support?](#windows-support) - - [How do I use rtx with http proxies?](#how-do-i-use-rtx-with-http-proxies) - - [How do the shorthand plugin names map to repositories?](#how-do-the-shorthand-plugin-names-map-to-repositories) - - [Does "node@20" mean the newest available version of node?](#does-node20-mean-the-newest-available-version-of-node) - - [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) - - [How compatible is rtx with asdf?](#how-compatible-is-rtx-with-asdf) - - [rtx isn't working when calling from tmux or another shell initialization script](#rtx-isnt-working-when-calling-from-tmux-or-another-shell-initialization-script) - - [How do I disable/force CLI color output?](#how-do-i-disableforce-cli-color-output) - - [Is rtx secure?](#is-rtx-secure) -- [Comparison to asdf](#comparison-to-asdf) - - [Performance](#performance) - - [Environment variables in rtx](#environment-variables-in-rtx) - - [UX](#ux) - - [CI/CD](#cicd) - - [GitHub Actions](#github-actions) -- [Shims](#shims) -- [direnv](#direnv) - - [rtx inside of direnv (`use rtx` in `.envrc`)](#rtx-inside-of-direnv-use-rtx-in-envrc) - - [Do you need direnv?](#do-you-need-direnv) -- [Cache Behavior](#cache-behavior) - - [Plugin/Runtime Cache](#pluginruntime-cache) -- [Commands](#commands) - - [`rtx activate [OPTIONS] [SHELL_TYPE]`](#rtx-activate-options-shell_type) - - [`rtx alias get `](#rtx-alias-get-plugin-alias) - - [`rtx alias ls [OPTIONS] [PLUGIN]`](#rtx-alias-ls-options-plugin) - - [`rtx alias set `](#rtx-alias-set-plugin-alias-value) - - [`rtx alias unset `](#rtx-alias-unset-plugin-alias) - - [`rtx bin-paths`](#rtx-bin-paths) - - [`rtx cache clear [PLUGIN]...`](#rtx-cache-clear-plugin) - - [`rtx completion [SHELL]`](#rtx-completion-shell) - - [`rtx config ls [OPTIONS]`](#rtx-config-ls-options) - - [`rtx config generate [OPTIONS]`](#rtx-config-generate-options) - - [`rtx current [PLUGIN]`](#rtx-current-plugin) - - [`rtx deactivate`](#rtx-deactivate) - - [`rtx direnv activate`](#rtx-direnv-activate) - - [`rtx doctor`](#rtx-doctor) - - [`rtx env [OPTIONS] [TOOL@VERSION]...`](#rtx-env-options-toolversion) - - [`rtx env-vars [OPTIONS] [ENV_VARS]...`](#rtx-env-vars-options-env_vars) - - [`rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]`](#rtx-exec-options-toolversion----command) - - [`rtx implode [OPTIONS]`](#rtx-implode-options) - - [`rtx install [OPTIONS] [TOOL@VERSION]...`](#rtx-install-options-toolversion) - - [`rtx latest [OPTIONS] `](#rtx-latest-options-toolversion) - - [`rtx link [OPTIONS] `](#rtx-link-options-toolversion-path) - - [`rtx ls [OPTIONS] [PLUGIN]...`](#rtx-ls-options-plugin) - - [`rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]`](#rtx-ls-remote-options-toolversion-prefix) - - [`rtx outdated [TOOL@VERSION]...`](#rtx-outdated-toolversion) - - [`rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]`](#rtx-plugins-install-options-new_plugin-git_url) - - [`rtx plugins link [OPTIONS] [PATH]`](#rtx-plugins-link-options-name-path) - - [`rtx plugins ls [OPTIONS]`](#rtx-plugins-ls-options) - - [`rtx plugins ls-remote [OPTIONS]`](#rtx-plugins-ls-remote-options) - - [`rtx plugins uninstall [OPTIONS] [PLUGIN]...`](#rtx-plugins-uninstall-options-plugin) - - [`rtx plugins update [OPTIONS] [PLUGIN]...`](#rtx-plugins-update-options-plugin) - - [`rtx prune [OPTIONS] [PLUGIN]...`](#rtx-prune-options-plugin) - - [`rtx reshim`](#rtx-reshim) - - [`rtx run [OPTIONS] [TASK] [ARGS]...`](#rtx-run-options-task-args) - - [`rtx self-update [OPTIONS] [VERSION]`](#rtx-self-update-options-version) - - [`rtx settings get `](#rtx-settings-get-setting) - - [`rtx settings ls`](#rtx-settings-ls) - - [`rtx settings set `](#rtx-settings-set-setting-value) - - [`rtx settings unset `](#rtx-settings-unset-setting) - - [`rtx shell [OPTIONS] [TOOL@VERSION]...`](#rtx-shell-options-toolversion) - - [`rtx sync node <--brew|--nvm|--nodenv>`](#rtx-sync-node---brew--nvm--nodenv) - - [`rtx sync python --pyenv`](#rtx-sync-python---pyenv) - - [`rtx task edit [OPTIONS] `](#rtx-task-edit-options-task) - - [`rtx task ls [OPTIONS]`](#rtx-task-ls-options) - - [`rtx task run [OPTIONS] [TASK] [ARGS]...`](#rtx-task-run-options-task-args) - - [`rtx trust [OPTIONS] [CONFIG_FILE]`](#rtx-trust-options-config_file) - - [`rtx uninstall [OPTIONS] [TOOL@VERSION]...`](#rtx-uninstall-options-toolversion) - - [`rtx upgrade [OPTIONS] [TOOL@VERSION]...`](#rtx-upgrade-options-toolversion) - - [`rtx use [OPTIONS] [TOOL@VERSION]...`](#rtx-use-options-toolversion) - - [`rtx version`](#rtx-version) - - [`rtx watch [OPTIONS] [ARGS]...`](#rtx-watch-options-args) - - [`rtx where `](#rtx-where-toolversion) - - [`rtx which [OPTIONS] `](#rtx-which-options-bin_name) - -
- - -## About - -> [!TIP] -> -> New developer? Try reading the [Beginner's Guide](https://dev.to/jdxcode/beginners-guide-to-rtx-ac4) for a gentler introduction. - -rtx is a tool for managing programming language and tool versions. For example, use this to install -a particular version of Node.js and ruby for a project. Using `rtx activate`, you can have your -shell automatically switch to the correct node and ruby versions when you `cd` into the project's -directory[^cd]. Other projects on your machine can use a different set of versions. - -rtx is inspired by [asdf](https://asdf-vm.com) and uses asdf's vast [plugin ecosystem](https://github.com/rtx-plugins/registry) -under the hood. However, it is _much_ faster than asdf and has a more friendly user experience. -For more on how rtx compares to asdf, [see below](#comparison-to-asdf). - -rtx can be configured in many ways. The most typical is by `.rtx.toml`, but it's also compatible -with asdf `.tool-versions` files. It can also use idiomatic version files like `.node-version` and -`.ruby-version`. See [Configuration](#configuration) for more. - -### How it works - -rtx hooks into your shell (with `rtx activate zsh`) and sets the `PATH` -environment variable to point your shell to the correct runtime binaries. When you `cd` into a -directory[^cd] containing a `.tool-versions`/`.rtx.toml` file, rtx will automatically set the -appropriate tool versions in `PATH`. - -After activating, every time your prompt displays it will call `rtx hook-env` to fetch new -environment variables. -This should be very fast. It exits early if the directory wasn't changed or `.tool-versions`/`.rtx.toml` files haven't been modified. - -Unlike asdf which uses shim files to dynamically locate runtimes when they're called, rtx modifies -`PATH` ahead of time so the runtimes are called directly. This is not only faster since it avoids -any overhead, but it also makes it so commands like `which node` work as expected. This also -means there isn't any need to run `asdf reshim` after installing new runtime binaries. - -You should note that rtx does not directly install these tools. -Instead, it leverages plugins to install runtimes. -See [plugins](#plugins) below. - -[^cd]: - Note that rtx does not modify "cd". It actually runs every time the prompt is _displayed_. - See the [FAQ](#what-does-rtx-activate-do). - -### Common commands - -```text -rtx install node@20.0.0 Install a specific version number -rtx install node@20 Install a fuzzy version number -rtx use node@20 Use node-20.x in current project -rtx use -g node@20 Use node-20.x as global default - -rtx install node Install the current version specified in .tool-versions/.rtx.toml -rtx use node@latest Use latest node in current directory -rtx use -g node@system Use system node as global default - -rtx x node@20 -- node app.js Run `node app.js` node-20.x on PATH -``` - -## Installation - -Installing rtx consists of two steps. - -1. Download the binary. - This depends on the device and operating system you are running rtx in. -1. Register a shell hook. - This depends on the shell you are using. - Read more about this step in the [FAQ](#what-does-rtx-activate-do). - -### Download binary - -
- Standalone -Note that it isn't necessary for `rtx` to be on `PATH`. If you run the activate script in your rc -file, rtx will automatically add itself to `PATH`. - -``` -curl https://rtx.jdx.dev/install.sh | sh -``` - -If you want to verify the install script hasn't been tampered with: - -``` -gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 0x29DDE9E0 -curl https://rtx.jdx.dev/install.sh.sig | gpg --decrypt > install.sh -# ensure the above is signed with the rtx release key -sh ./install.sh -``` - -or if you're allergic to `| sh`: - -``` -curl https://rtx.jdx.dev/rtx-latest-macos-arm64 > /usr/local/bin/rtx -``` - -It doesn't matter where you put it. So use `~/bin`, `/usr/local/bin`, `~/.local/share/rtx/bin/rtx` -or whatever. - -Supported architectures: - -- `x64` -- `arm64` - -Supported platforms: - -- `macos` -- `linux` - -If you need something else, compile it with `cargo install rtx-cli` (see below). -[Windows isn't currently supported.](https://github.com/jdx/rtx/discussions/66) - -
-
- Homebrew - -``` -brew install rtx -``` - -Alternatively, use the custom tap (which is updated immediately after a release): - -``` -brew install jdx/tap/rtx -``` - -
-
- MacPorts - -``` -sudo port install rtx -``` - -
-
- Cargo - -Build from source with Cargo: - -``` -cargo install rtx-cli -``` - -Do it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall): - -``` -cargo install cargo-binstall -cargo binstall rtx-cli -``` - -Build from the latest commit in main: - -``` -cargo install rtx-cli --git https://github.com/jdx/rtx --branch main -``` - -
-
- npm - -rtx is available on npm as a precompiled binary. This isn't a Node.js package—just distributed -via npm. This is useful for JS projects that want to setup rtx via `package.json` or `npx`. - -``` -npm install -g rtx-cli -``` - -Use npx if you just want to test it out for a single command without fully installing: - -``` -npx rtx-cli exec python@3.11 -- python some_script.py -``` - -
-
- GitHub Releases - -Download the latest release from [GitHub](https://github.com/jdx/rtx/releases). - -``` -curl https://github.com/jdx/rtx/releases/download/v2023.12.40/rtx-v2023.12.40-linux-x64 > /usr/local/bin/rtx -chmod +x /usr/local/bin/rtx -``` - -
-
- apt - -For installation on Ubuntu/Debian: - -``` -sudo install -dm 755 /etc/apt/keyrings -wget -qO - https://rtx.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=amd64] https://rtx.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list -sudo apt update -sudo apt install -y rtx -``` - -> [!IMPORTANT] -> -> If you're on arm64 you'll need to run the following: -> -> ``` -> echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list -> ``` - -
-
- dnf - -For Fedora, CentOS, Amazon Linux, RHEL and other dnf-based distributions: - -``` -dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo -dnf install -y rtx -``` - -
-
- yum - -``` -yum install -y yum-utils -yum-config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo -yum install -y rtx -``` - -
-
- apk - -For Alpine Linux: - -``` -apk add rtx -``` - -_rtx lives in the [community repository](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/rtx/APKBUILD)._ - -
-
- aur - -For Arch Linux: - -``` -git clone https://aur.archlinux.org/rtx.git -cd rtx -makepkg -si -``` - -
-
- nix - -For the Nix package manager, at release 23.05 or later: - -``` -nix-env -iA rtx -``` - -You can also import the package directly using -`rtx-flake.packages.${system}.rtx`. It supports all default Nix -systems. - -
-
- Docker - -``` -docker run jdxcode/rtx x node@20 -- node -v -``` - -
- -### Register shell hook - -#### Bash - -``` -echo 'eval "$(rtx activate bash)"' >> ~/.bashrc -``` - -#### Zsh - -``` -echo 'eval "$(rtx activate zsh)"' >> "${ZDOTDIR-$HOME}/.zshrc" -``` - -#### Fish - -``` -echo 'rtx activate fish | source' >> ~/.config/fish/config.fish -``` - -> [!TIP] -> -> For homebrew and possibly other installs rtx is automatically activated so -> this is not necessary. -> -> See [`RTX_FISH_AUTO_ACTIVATE=1`](#rtx_fish_auto_activate1) for more information. - -#### Nushell - -```nushell -do { - let rtxpath = ($nu.config-path | path dirname | path join "rtx.nu") - run-external rtx activate nu --redirect-stdout | save $rtxpath -f - $"\nsource "($rtxpath)"" | save $nu.config-path --append -} -``` - -#### Xonsh - -Since `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a bit off startup time by using a pure Python import: add the code below to, for example, `~/.config/xonsh/rtx.py` config file and `import rtx` it in `~/.config/xonsh/rc.xsh`: - -```xsh -from pathlib import Path -from xonsh.built_ins import XSH - -ctx = XSH.ctx -rtx_init = subprocess.run([Path('~/bin/rtx').expanduser(),'activate','xonsh'],capture_output=True,encoding="UTF-8").stdout -XSH.builtins.execx(rtx_init,'exec',ctx,filename='rtx') -``` - -Or continue to use `rc.xsh`/`.xonshrc`: - -```xsh -echo 'execx($(~/bin/rtx activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xonshrc -``` - -Given that `rtx` replaces both shell env `$PATH` and OS environ `PATH`, watch out that your configs don't have these two set differently (might throw `os.environ['PATH'] = xonsh.built_ins.XSH.env.get_detyped('PATH')` at the end of a config to make sure they match) - -#### Something else? - -Adding a new shell is not hard at all since very little shell code is -in this project. -[See here](https://github.com/jdx/rtx/tree/main/src/shell) for how -the others are implemented. If your shell isn't currently supported -I'd be happy to help you get yours integrated. - -### Migrate from asdf - -If you're moving from asdf to rtx, please review [How do I migrate from asdf?](#how-do-i-migrate-from-asdf) for guidance. - -## Uninstalling - -Use `rtx implode` to uninstall rtx. This will remove the rtx binary and all of its data. Use -`rtx implode --help` for more information. - -Alternatively, manually remove the following directories to fully clean up: - -- `~/.local/share/rtx` (can also be `RTX_DATA_DIR` or `XDG_DATA_HOME/rtx`) -- `~/.local/state/rtx` (can also be `RTX_STATE_DIR` or `XDG_STATE_HOME/rtx`) -- `~/.config/rtx` (can also be `RTX_CONFIG_DIR` or `XDG_CONFIG_HOME/rtx`) -- on Linux: `~/.cache/rtx` (can also be `RTX_CACHE_DIR` or `XDG_CACHE_HOME/rtx`) -- on macOS: `~/Library/Caches/rtx` (can also be `RTX_CACHE_DIR`) - -## Configuration - -### `.rtx.toml` - -`.rtx.toml` is a new config file that replaces asdf-style `.tool-versions` files with a file -that has lot more flexibility. It supports functionality that is not possible with `.tool-versions`, such as: - -- setting arbitrary env vars while inside the directory -- passing options to plugins like `virtualenv='.venv'` for [python](https://github.com/jdx/rtx/blob/main/docs/python.md#experimental-automatic-virtualenv-creationactivation). -- specifying custom plugin URLs - -They can use any of the following project locations (in order of precedence, top is highest): - -- `.rtx.toml` -- `.rtx/config.toml` -- `.config/rtx.toml` -- `.config/rtx/rtx.toml` - -They can also be named `.rtx.local.toml` and environment-specific files like `.rtx.production.toml`. -Can also be opted-in. See [Config Environments](#config-environments) for more details. -Run `rtx config` to see the order of precedence on your system. - -Here is what an `.rtx.toml` looks like: - -```toml -[env] -# supports arbitrary env vars so rtx can be used like direnv/dotenv -NODE_ENV = 'production' - -[tools] -# specify single or multiple versions -terraform = '1.0.0' -erlang = ['23.3', '24.0'] - -# supports everything you can do with .tool-versions currently -node = ['16', 'prefix:20', 'ref:master', 'path:~/.nodes/14'] - -# send arbitrary options to the plugin, passed as: -# RTX_TOOL_OPTS__VENV=.venv -python = {version='3.10', virtualenv='.venv'} - -[plugins] -# specify a custom repo url -# note this will only be used if the plugin does not already exist -python = 'https://github.com/asdf-community/asdf-python' - -[alias.node] # project-local aliases -my_custom_node = '20' -``` - -`.rtx.toml` files are hierarchical. The configuration in a file in the current directory will -override conflicting configuration in parent directories. For example, if `~/src/myproj/.rtx.toml` -defines the following: - -```toml -[tools] -node = '20' -python = '3.10' -``` - -And `~/src/myproj/backend/.rtx.toml` defines: - -```toml -[tools] -node = '18' -ruby = '3.1' -``` - -Then when inside of `~/src/myproj/backend`, `node` will be `18`, `python` will be `3.10`, and `ruby` -will be `3.1`. You can check the active versions with `rtx ls --current`. - -You can also have environment specific config files like `.rtx.production.toml`, see -[Config Environments](#config-environments) for more details. - -#### `[env]` - Arbitrary Environment Variables - -The `[env]` section of .rtx.toml allows setting arbitrary environment variables. -These can be simple key-value entries like this: - -```toml -[env] -NODE_ENV = 'production' -``` - -`PATH` is treated specially, it needs to be defined as an array in `env_path`: - -```toml -env_path = [ - # adds an absolute path - "~/.local/share/bin", - # adds a path relative to the .rtx.toml, not PWD - "./node_modules/.bin", -] -``` - -_Note: `env_path` is a top-level key, it does not go inside of `[env]`._ - -Environment variable values can be templates, see [Templates](#templates) for details. - -```toml -[env] -LD_LIBRARY_PATH = "/some/path:{{env.LD_LIBRARY_PATH}}" -``` - -`env_file` can be used to specify a [dotenv](https://dotenv.org) file to load: - -```toml -env_file = '.env' -``` - -_Note: `env_file` goes at the top of the file, above `[env]`._ - -```toml -[env] -NODE_ENV = false # unset a previously set NODE_ENV -``` - -#### `[plugins]` - Specify Custom Plugin Repository URLs - -Use `[plugins]` to add/modify plugin shortnames. Note that this will only modify -_new_ plugin installations. Existing plugins can use any URL. - -```toml -[plugins] -elixir = "https://github.com/my-org/rtx-elixir.git" -node = "https://github.com/my-org/rtx-node.git#DEADBEEF" # supports specific gitref -``` - -If you simply want to install a plugin from a specific URL once, it's better to use -`rtx plugin install plugin `. Add this section to `.rtx.toml` if you want -to share the plugin location/revision with other developers in your project. - -This is similar to [`RTX_SHORTHANDS`](https://github.com/jdx/rtx#rtx_shorthands_fileconfigrtxshorthandstoml) -but doesn't require a separate file. - -### Legacy version files - -rtx supports "legacy version files" just like asdf. They're language-specific files like `.node-version` -and `.python-version`. These are ideal for setting the runtime version of a project without forcing -other developers to use a specific tool like rtx/asdf. - -They support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work -in rtx and nvm. Here are some of the supported legacy version files: - -| Plugin | "Legacy" (Idiomatic) Files | -|-----------|----------------------------------------------------| -| crystal | `.crystal-version` | -| elixir | `.exenv-version` | -| go | `.go-version`, `go.mod` | -| java | `.java-version`, `.sdkmanrc` | -| node | `.nvmrc`, `.node-version` | -| python | `.python-version` | -| ruby | `.ruby-version`, `Gemfile` | -| terraform | `.terraform-version`, `.packer-version`, `main.tf` | -| yarn | `.yarnrc` | - -In rtx these are enabled by default. You can disable them with `rtx settings set legacy_version_file false`. -There is a performance cost to having these when they're parsed as it's performed by the plugin in -`bin/parse-version-file`. However these are [cached](#cache-behavior) so it's not a huge deal. -You may not even notice. - -> [!NOTE] -> -> asdf calls these "legacy version files" so we do too. I think this is a bad name since it implies -> that they shouldn't be used—which is definitely not the case IMO. I prefer the term "idiomatic" -> version files since they're version files not specific to asdf/rtx and can be used by other tools. -> (`.nvmrc` being a notable exception, which is tied to a specific tool.) - -### `.tool-versions` - -The `.tool-versions` file is asdf's config file and it can be used in rtx just like `.rtx.toml`. -It isn't as flexible so it's recommended to use `.rtx.toml` instead. It can be useful if you -already have a lot of `.tool-versions` files or work on a team that uses asdf. - -Here is an example with all the supported syntax: - -``` -node 20.0.0 # comments are allowed -ruby 3 # can be fuzzy version -shellcheck latest # also supports "latest" -jq 1.6 -erlang ref:master # compile from vcs ref -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) - -node sub-2:lts # install 2 versions behind the latest lts (e.g.: 18 if lts is 20) -python sub-0.1:latest # install python-3.10 if the latest is 3.11 -``` - -See [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on this file format. - -### Scopes - -Both `.rtx.toml` and `.tool-versions` support "scopes" which modify the behavior of the version: - -- `ref:` - compile from a vcs (usually git) ref -- `prefix:` - use the latest version that matches the prefix. Useful for Go since `1.20` - would only match `1.20` exactly but `prefix:1.20` will match `1.20.1` and `1.20.2` etc. -- `path:` - use a custom compiled version at the given path. One use-case is to re-use - Homebrew tools (e.g.: `path:/opt/homebrew/opt/node@20`). -- `sub-:` - subtracts PARTIAL_VERSION from ORIG_VERSION. This can - be used to express something like "2 versions behind lts" such as `sub-2:lts`. Or 1 minor - version behind the latest version: `sub-0.1:latest`. - -### Global config: `~/.config/rtx/config.toml` - -rtx can be configured in `~/.config/rtx/config.toml`. It's like local `.rtx.toml` files except that -it is used for all directories. - -```toml -[tools] -# global tool versions go here -# you can set these with `rtx use -g` -node = 'lts' -python = ['3.10', '3.11'] - -[settings] -# plugins can read the versions files used by other version managers (if enabled by the plugin) -# for example, .nvmrc in the case of node's nvm -legacy_version_file = true # enabled by default (unlike asdf) -legacy_version_file_disable_tools = ['python'] # disable for specific tools - -# configure `rtx install` to always keep the downloaded archive -always_keep_download = false # deleted after install by default -always_keep_install = false # deleted on failure by default - -# configure how frequently (in minutes) to fetch updated plugin repository changes -# this is updated whenever a new runtime is installed -# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdx/rtx/issues/128) -plugin_autoupdate_last_check_duration = '1 week' # set to 0 to disable updates - -# config files with these prefixes will be trusted by default -trusted_config_paths = [ - '~/work/my-trusted-projects', -] - -verbose = false # set to true to see full installation output, see `RTX_VERBOSE` -asdf_compat = false # set to true to ensure .tool-versions will be compatible with asdf, see `RTX_ASDF_COMPAT` -jobs = 4 # number of plugins or runtimes to install in parallel. The default is `4`. -raw = false # set to true to directly pipe plugins to stdin/stdout/stderr -yes = false # set to true to automatically answer yes to all prompts - -not_found_auto_install = true -task_output = "prefix" # see Task Runner for more information - -shorthands_file = '~/.config/rtx/shorthands.toml' # path to the shorthands file, see `RTX_SHORTHANDS_FILE` -disable_default_shorthands = false # disable the default shorthands, see `RTX_DISABLE_DEFAULT_SHORTHANDS` -disable_tools = ['node'] # disable specific tools, generally used to turn off core tools - -experimental = false # enable experimental features - -[alias.node] -my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20.x - # this can also be specified in a plugin (see below in "Aliases") -``` - -> [!TIP] -> -> These settings can also be managed with `rtx settings ls|get|set|unset`. - -### System config: `/etc/rtx/config.toml` - -Similar to `~/.config/rtx/config.toml` but for all users on the system. This is useful for -setting defaults for all users. - -### Environment variables - -rtx can also be configured via environment variables. The following options are available: - -#### `RTX_DATA_DIR` - -Default: `~/.local/share/rtx` or `$XDG_DATA_HOME/rtx` - -This is the directory where rtx stores plugins and tool installs. These are not supposed to be shared -across machines. - -#### `RTX_CACHE_DIR` - -Default (Linux): `~/.cache/rtx` or `$XDG_CACHE_HOME/rtx` -Default (macOS): `~/Library/Caches/rtx` or `$XDG_CACHE_HOME/rtx` - -This is the directory where rtx stores internal cache. This is not supposed to be shared -across machines. It may be deleted at any time rtx is not running. - -#### `RTX_TMP_DIR` - -Default: [`std::env::temp_dir()`](https://doc.rust-lang.org/std/env/fn.temp_dir.html) implementation in rust - -This is used for temporary storage such as when installing tools. - -#### `RTX_SYSTEM_DIR` - -Default: `/etc/rtx` - -This is the directory where rtx stores system-wide configuration. - -#### `RTX_CONFIG_FILE` - -Default: `$RTX_CONFIG_DIR/config.toml` (Usually ~/.config/rtx/config.toml) - -This is the path to the config file. - -#### `RTX_DEFAULT_TOOL_VERSIONS_FILENAME` - -Set to something other than ".tool-versions" to have rtx look for `.tool-versions` files but with -a different name. - -#### `RTX_DEFAULT_CONFIG_FILENAME` - -Set to something other than `.rtx.toml` to have rtx look for `.rtx.toml` config files with a different name. - -#### `RTX_ENV` - -Enables environment-specific config files such as `.rtx.development.toml`. -Use this for different env vars or different tool versions in -development/staging/production environments. See -[Config Environments](#config-environments) for more on how -to use this feature. - -#### `RTX_USE_VERSIONS_HOST` - -Default: `true` - -Set to "false" to disable using [rtx-versions](https://rtx-versions.jdx.dev) as -a quick way for rtx to query for new versions. This host regularly grabs all the -latest versions of core and community plugins. It's faster than running a plugin's -`list-all` command and gets around GitHub rate limiting problems when using it. - -See [FAQ](#new-version-of-a-tool-is-not-available) for more information. - -#### `RTX_${PLUGIN}_VERSION` - -Set the version for a runtime. For example, `RTX_NODE_VERSION=20` will use regardless -of what is set in `.tool-versions`/`.rtx.toml`. - -#### `RTX_LEGACY_VERSION_FILE=1` - -Plugins can read the versions files used by other version managers (if enabled by the plugin) -for example, `.nvmrc` in the case of node's nvm. See [legacy version files](#legacy-version-files) for more -information. - -Set to "0" to disable legacy version file parsing. - -#### `RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS=node,python` - -Disable legacy version file parsing for specific tools. Separate with `,`. - -#### `RTX_USE_TOML=0` - -Set to `1` to default to using `.rtx.toml` in `rtx local` instead of `.tool-versions` for -configuration. - -For now this is not used by `rtx use` which will only use `.rtx.toml` unless `--path` is specified. - -#### `RTX_TRUSTED_CONFIG_PATHS` - -This is a list of paths that rtx will automatically mark as -trusted. They can be separated with `:`. - -#### `RTX_LOG_LEVEL=trace|debug|info|warn|error` - -These change the verbosity of rtx. - -You can also use `RTX_DEBUG=1`, `RTX_TRACE=1`, and `RTX_QUIET=1` as well as -`--log-level=trace|debug|info|warn|error`. - -#### `RTX_LOG_FILE=~/rtx.log` - -Output logs to a file. - -#### `RTX_LOG_FILE_LEVEL=trace|debug|info|warn|error` - -Same as `RTX_LOG_LEVEL` but for the log _file_ output level. This is useful if you want -to store the logs but not have them litter your display. - -#### `RTX_ALWAYS_KEEP_DOWNLOAD=1` - -Set to "1" to always keep the downloaded archive. By default it is deleted after install. - -#### `RTX_ALWAYS_KEEP_INSTALL=1` - -Set to "1" to always keep the install directory. By default it is deleted on failure. - -#### `RTX_VERBOSE=1` - -This shows the installation output during `rtx install` and `rtx plugin install`. -This should likely be merged so it behaves the same as `RTX_DEBUG=1` and we don't have -2 configuration for the same thing, but for now it is its own config. - -Equivalent to `RTX_LOG_LEVEL=debug`. - -#### `RTX_QUIET=1` - -Equivalent to `RTX_LOG_LEVEL=warn`. - -#### `RTX_ASDF_COMPAT=1` - -Only output `.tool-versions` files in `rtx local|global` which will be usable by asdf. -This disables rtx functionality that would otherwise make these files incompatible with asdf. - -#### `RTX_JOBS=1` - -Set the number plugins or runtimes to install in parallel. The default is `4`. - -#### `RTX_RAW=1` - -Set to "1" to directly pipe plugin scripts to stdin/stdout/stderr. By default stdin is disabled -because when installing a bunch of plugins in parallel you won't see the prompt. Use this if a -plugin accepts input or otherwise does not seem to be installing correctly. - -Sets `RTX_JOBS=1` because only 1 plugin script can be executed at a time. - -#### `RTX_SHORTHANDS_FILE=~/.config/rtx/shorthands.toml` - -Use a custom file for the shorthand aliases. This is useful if you want to share plugins within -an organization. - -Shorthands make it so when a user runs something like `rtx install elixir` rtx will -automatically install the [asdf-elixir](https://github.com/asdf-vm/asdf-elixir) plugin. By -default, it uses the shorthands in -[`src/default_shorthands.rs`](./src/default_shorthands.rs). - -The file should be in this toml format: - -```toml -elixir = "https://github.com/my-org/rtx-elixir.git" -node = "https://github.com/my-org/rtx-node.git" -``` - -#### `RTX_DISABLE_DEFAULT_SHORTHANDS=1` - -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,node` - -Disables the specified tools. Separate with `,`. Generally used for core plugins but works with -all. - -#### `RTX_YES=1` - -This will automatically answer yes or no to prompts. This is useful for scripting. - -#### `RTX_NOT_FOUND_AUTO_INSTALL=true` - -Set to false to disable the "command not found" handler to autoinstall missing tool versions. - -#### `RTX_TASK_OUTPUT=prefix` - -This controls the output of `rtx run`. It can be one of: - -- `prefix` - (default if jobs > 1) print by line with the prefix of the task name -- `interleave` - (default if jobs == 1) display stdout/stderr as it comes in - -#### `RTX_EXPERIMENTAL=true` - -Enables experimental features. - -#### `RTX_ALL_COMPILE=1` - -Default: false unless running NixOS or Alpine (let me know if others should be added) - -Do not use precompiled binaries for all languages. Useful if running on a Linux distribution -like Alpine that does not use glibc and therefore likely won't be able to run precompiled binaries. - -Note that this needs to be setup for each language. File a ticket if you notice a language that is not -working with this config. - -#### `RTX_FISH_AUTO_ACTIVATE=1` - -Configures the vendor_conf.d script for fish shell to automatically activate. -This file is automatically used in homebrew and potentially other installs to -automatically activate rtx without configuring. - -Defaults to enabled, set to "0" to disable. - -## Shebang - -You can specify a tool and its version in a shebang without needing to first -setup `.tool-versions`/`.rtx.toml` config: - -```typescript -#!/usr/bin/env -S rtx x node@20 -- node -// "env -S" allows multiple arguments in a shebang -console.log(`Running node: ${process.version}`); -``` - -This can also be useful in environments where rtx isn't activated -(such as a non-interactive session). - -## [experimental] Task Runner - -You can define tasks in `.rtx.toml` files or as standalone shell scripts. These are useful for things like -running linters, tests, builders, servers, and other tasks that are specific to a project. Of course, -tasks launched with rtx will include the rtx environment—your tools and env vars defined in `.rtx.toml`. - -Here's my favorite features about rtx's task runner: - -- building dependencies in parallel—by default with no configuration required -- last-modified checking to avoid rebuilding when there are no changes—requires minimal config -- `rtx watch` to automatically rebuild on changes—no configuration required, but it helps -- ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack syntax highlighting and linting/checking support - -> [!WARNING] -> -> This is an experimental feature. It is not yet stable and will likely change. Some of the docs -> may not be implemented, may be implemented incorrectly, or the docs may need to be updated. -> Please give feedback early since while it's experimental it's much easier to change. - -### Script Tasks - -Tasks can be defined in 2 ways, either as standalone script files in `.rtx/tasks/:task_name` such as the following build script -for cargo: - -```bash -#!/usr/bin/env bash -# rtx:description "Build the CLI" -cargo build -``` - -> [!IMPORTANT] -> -> The `rtx:description` comment is optional but recommended. It will be used in the output of `rtx tasks`. -> The other configuration for "script" tasks is supported in this format so you can specify things like the -> following-note that this is parsed a TOML table: -> -> ```bash -> # rtx alias="b" -> # rtx sources=["Cargo.toml", "src/**/*.rs"] -> # rtx outputs=["target/debug/mycli"] -> # rtx env={RUST_BACKTRACE = "1"} -> # rtx depends=["lint", "test"] -> ``` - -Assuming that file was located in `.rtx/tasks/build`, it can then be run with `rtx run build` (or with its alias: `rtx run b`). -This script can be edited with by running `rtx task edit build` (using $EDITOR). If it doesn't exist it will be created. -These are convenient for quickly making new scripts. Having the code in a bash file and not TOML helps make it work -better in editors since they can do syntax highlighting and linting more easily. They also still work great for non-rtx users—though -of course they'll need to find a different way to install their dev tools the tasks might use. - -### TOML-based Tasks - -Tasks can also be defined in `.rtx.toml` files in different ways. This is a more "traditional" method of defining tasks: - -```toml -tasks.clean = 'cargo clean && rm -rf .cache' # runs as a shell command - -[tasks.build] -description = 'Build the CLI' -run = "cargo build" -alias = 'b' # `rtx run b` - -[tasks.test] -description = 'Run automated tests' -run = [ # multiple commands are run in series - 'cargo test', - './scripts/test-e2e.sh', -] -dir = "{{cwd}}" # run in user's cwd, default is the project's base directory - -[tasks.lint] -description = 'Lint with clippy' -env = {RUST_BACKTRACE = '1'} # env vars for the script -# you can specify a multiline script instead of individual commands -run = """ -#!/usr/bin/env bash -cargo clippy -""" - -[task.ci] # only dependencies to be run -description = 'Run CI tasks' -depends = ['build', 'lint', 'test'] - -[tasks.release] -description = 'Cut a new release' -file = 'scripts/release.sh' # execute an external script -``` - -### Task Environment Variables - -- `RTX_PROJECT_ROOT` - the root of the project, defaults to the directory of the `.rtx.toml` file - -### Running Tasks - -See available tasks with `rtx tasks`. Run a task with `rtx task run`, `rtx run`, or just `rtx r`. -You might even want to make a shell alias like `alias r='rtx r'` since this is likely a common command. - -By default, tasks will execute with a maximum of 4 parallel jobs. Customize this with the `--jobs` option, -`jobs` setting or `RTX_JOBS` environment variable. The output normally will be by line, prefixed with the task -label. By printing line-by-line we avoid interleaving output from parallel executions. However, if ---jobs == 1, the output will be set to `interleave`. - -To just print stdout/stderr directly, use `--interleave`, the `task_output` setting, or `RTX_TASK_OUTPUT=interleave`. - -Stdin is not read by default. To enable this, set `raw = true` on the task that needs it. This will prevent -it running in parallel with any other task-a RWMutex will get a write lock in this case. - -There is partial support for wildcards, for example, this makes a "lint" task that runs everything that begins with "lint:". - -``` -[tasks."lint:eslint"] # using a ":" means we need to add quotes -run = "eslint ." -[tasks."lint:prettier"] -run = "prettier --check ." -[tasks.lint] -depends = ["lint:*"] -``` - -> [!NOTE] -> As of this writing these wildcards only function at the right side and only work for dependencies. -> It should be possible to also run `rtx run lint:*` but that is not yet implemented. - -Extra arguments will be passed to the task, for example, if we want to run in release mode: - -```bash -rtx run build --release -``` - -If there are multiple commands, the args are only passed to the last command. - -Multiple tasks/arguments can be separated with this `:::` delimiter: - -```bash -rtx run build arg1 arg2 ::: test arg3 arg4 -``` - -rtx will run the task named "default" if no task is specified—and you've created one named "default". You can also alias a different task to "default". - -```bash -rtx run -``` - -### Running on file changes - -It's often handy to only execute a task if the files it uses changes. For example, we might only want -to run `cargo build` if an ".rs" file changes. This can be done with the following config: - -```toml -[tasks.build] -description = 'Build the CLI' -run = "cargo build" -sources = ['Cargo.toml', 'src/**/*.rs'] # skip running if these files haven't changed -outputs = ['target/debug/mycli'] -``` - -Now if `target/debug/mycli` is newer than `Cargo.toml` or any ".rs" file, the task will be skipped. This uses last modified timestamps. -It wouldn't be hard to add checksum support. - -### Watching files - -Run a task when the source changes with `rtx watch`: - -```bash -rtx watch -t build -``` - -Currently this just shells out to watchexec-which you can install however you want including with rtx: `rtx use -g watchexec@latest`. -This may change in the future. - -Arguments to `rtx watch` will be forwarded onto watchexec. For example, to print diagnostic info: - -```bash -rtx watch -t build -- --print-events --verbose -``` - -See watchexec's help with `watchexec --help` or `rtx watch -- --help` to see -all of the options. - -## Aliases - -rtx supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS -versions of runtimes. For example, you may want to specify `lts-hydrogen` as the version for -so you can use set it with `node lts-hydrogen` in `.tool-versions`/`.rtx.toml`. - -User aliases can be created by adding an `alias.` section to `~/.config/rtx/config.toml`: - -```toml -[alias.node] -my_custom_20 = '20' -``` - -Plugins can also provide aliases via a `bin/list-aliases` script. Here is an example showing node.js -versions: - -```bash -#!/usr/bin/env bash - -echo "lts-hydrogen 18" -echo "lts-gallium 16" -echo "lts-fermium 14" -``` - -> [!NOTE] -> -> Because this is rtx-specific functionality not currently used by asdf it isn't likely to be in any -> plugin currently, but plugin authors can add this script without impacting asdf users. - -## Plugins - -rtx uses asdf's plugin ecosystem under the hood. These plugins contain shell scripts like -`bin/install` (for installing) and `bin/list-all` (for listing all of the available versions). - -See for the list of built-in plugins shorthands. See asdf's -[Create a Plugin](https://asdf-vm.com/plugins/create.html) for how to create your own or just learn -more about how they work. - -### Core Plugins - -rtx comes with some plugins built into the CLI written in Rust. These are new and will improve over -time. They can be easily overridden by installing a plugin with the same name, e.g.: `rtx plugin install python https://github.com/asdf-community/asdf-python`. - -You can see the core plugins with `rtx plugin ls --core`. - -- [Python](./docs/python.md) -- [NodeJS](./docs/node.md) -- [Ruby](./docs/ruby.md) -- [Go](./docs/go.md) -- [Java](./docs/java.md) -- [Deno](./docs/deno.md) -- [Bun](./docs/bun.md) - -### Plugin Authors - - is a GitHub organization for community-developed plugins. -See [SECURITY.md](./SECURITY.md) for more details on how plugins here are treated differently. - -If you'd like your plugin to be hosted here please let me know (GH discussion or discord is fine) -and I'd be happy to host it for you. - -### Plugin Options - -rtx has support for "plugin options" which is configuration specified in `.rtx.toml` to change behavior -of plugins. One example of this is virtualenv on python runtimes: - -```toml -[tools] -python = {version='3.11', virtualenv='.venv'} -``` - -This will be passed to all plugin scripts as `RTX_TOOL_OPTS__VIRTUALENV=.venv`. The user can specify -any option and it will be passed to the plugin in that format. - -Currently this only supports simple strings, but we can make it compatible with more complex types -(arrays, tables) fairly easily if there is a need for it. - -## Versioning - -rtx uses [Calver](https://calver.org/) versioning (`2023.6.1`). -Breaking changes will be few but when they do happen, -they will be communicated in the CLI with plenty of notice whenever possible. - -Rather than have SemVer major releases to communicate change in large releases, -new functionality and changes can be opted-into with settings like `experimental = true`. -This way plugin authors and users can -test out new functionality immediately without waiting for a major release. - -The numbers in Calver (YYYY.MM.RELEASE) simply represent the date of the release—not compatibility -or how many new features were added. -Each release will be small and incremental. - -## Directories - -The following are the directories that rtx uses. -These are the default directories, see -[Configuration](#configuration) for information on changing the locations. - -> **Tip** -> -> If you often find yourself using these directories (as I do), I suggest setting all of them to `~/.rtx` for easy access. - -### `~/.config/rtx` - -This directory stores the global configuration file `~/.config/rtx/config.toml`. This is intended to go into your -dotfiles repo to share across machines. - -### `~/.cache/rtx` - -_On macOS this is `~/Library/Caches/rtx`._ - -Stores internal cache that rtx uses for things like the list of all available versions of a -plugin. Do not share this across machines. You may delete this directory any time rtx isn't actively installing something. -Do this with `rtx cache clear`. -See [Cache Behavior](#cache-behavior) for more information. - -### `~/.local/state/rtx` - -Used for storing state local to the machine such as which config files are trusted. These should not be shared across -machines. - -### `~/.local/share/rtx` - -This is the main directory that rtx uses and is where plugins and tools are installed into. -It is nearly identical to `~/.asdf` in asdf, so much so that you may be able to get by -symlinking these together and using asdf and rtx simultaneously. (Supporting this isn't a -project goal, however). - -This directory _could_ be shared across machines but only if they run the same OS/arch. In general I wouldn't advise -doing so. - -#### `~/.local/share/rtx/downloads` - -This is where plugins may optionally cache downloaded assets such as tarballs. Use the -`always_keep_downloads` setting to prevent rtx from removing files from here. - -#### `~/.local/share/rtx/plugins` - -rtx installs plugins to this directory when running `rtx plugins install`. If you are working on a -plugin, I suggest -symlinking it manually by running: - -``` -ln -s ~/src/rtx-my-tool ~/.local/share/rtx/plugins/my-tool -``` - -#### `~/.local/share/rtx/installs` - -This is where tools are installed to when running `rtx install`. For example, `rtx install -node@20.0.0` will install to `~/.local/share/rtx/installs/node/20.0.0` - -This will also create other symlinks to this directory for version prefixes ("20" and "20.15") -and matching aliases ("lts", "latest"). -For example: - -``` -20 -> ./20.15.0 -20.15 -> ./20.15.0 -latest -> ./20.15.0 -lts -> ./20.15.0 -``` - -#### `~/.local/share/rtx/shims` - -This is where rtx places shims. Generally these are used for IDE integration or if `rtx activate` -does not work for some reason. - -## Templates - -Templates are used in the following locations: - -- `.tool-versions` files -- `.rtx.toml` files for most configuration -- _(Submit a ticket if you want to see it used elsewhere!)_ - -The following context objects are available inside templates: - -- `env: HashMap` – current environment variables -- `config_root: PathBuf` – directory containing the `.rtx.toml` file - -As well as these functions: - -- `exec(command: &str) -> String` – execute a command and return the output - -Templates are parsed with [tera](https://keats.github.io/tera/docs/)—which is quite powerful. For -example, this snippet will get the directory name of the project: - -```toml -[env] -PROJECT_NAME = "{{config_root | split(pat='/') | last}}" -``` - -Here's another using `exec()`: - -```toml -[aliases] -current = "{{exec(command='node --version')}}" -``` - -## Config Environments - -It's possible to have separate `.rtx.toml` files in the same directory for different -environments like `development` and `production`. To enable, set `RTX_ENV` to an environment like -`development` or `production`. rtx will then look for a `.rtx.{RTX_ENV}.toml` file in the current directory. - -rtx will also look for "local" files like `.rtx.local.toml` and `.rtx.{RTX_ENV}.local.toml` in -the current directory. These are intended to not be committed to version control. -(Add `.rtx.local.toml` and `.rtx.*.local.toml` to your `.gitignore` file.) - -The priority of these files goes in this order (bottom overrides top): - -- `.config/rtx/config.toml` -- `.rtx/config.toml` -- `.rtx.toml` -- `.config/rtx/config.local.toml` -- `.rtx/config.local.toml` -- `.rtx.local.toml` -- `.config/rtx/config.{RTX_ENV}.toml` -- `.rtx/config.{RTX_ENV}.toml` -- `.rtx.{RTX_ENV}.toml` -- `.config/rtx/config.{RTX_ENV}.local.toml` -- `.rtx/config.{RTX_ENV}.local.toml` -- `.rtx.{RTX_ENV}.local.toml` - -Use `rtx doctor` to see which files are being used. - -> [!IMPORTANT] -> -> Note that currently modifying `RTX_DEFAULT_CONFIG_FILENAME` to something other than `.rtx.toml` -> will not work with this feature. For now, it will disable it entirely. This may change in the -> future. - -## IDE Integration - -IDEs work better with shims than they do environment variable modifications. The simplest way is -to add the rtx shim directory to PATH. - -For IntelliJ and VSCode—and likely others, you can modify `~/.zprofile` -with the following: - -``` -export PATH="$HOME/.local/share/rtx/shims:$PATH" -``` - -This won't work for all of rtx's functionality. For example, arbitrary env vars in `[env]` will only be set -if a shim is executed. For this we need tighter integration with the IDE and a custom plugin. If you feel -ambitious, take a look at existing direnv extensions for your IDE and see if you can modify it to work for rtx. -Direnv and rtx work similarly and there should be a direnv extension that can be used as a starting point. - -Alternatively, you may be able to get tighter integration with a direnv extension and using the -[`use_rtx`](#direnv) direnv function. - -## Project Roadmap - -Issues marked ["enhancements"](https://github.com/jdx/rtx/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) are the best way to read about ideas for future -functionality. As far as general scope however, these are likely going to be focuses for 2024: - -* Tasks - this is the newest headline feature of rtx and needs to be refined, tested, and iterated on before it can come out of experimental -* Documentation website - we've outgrown what is mostly a single README -* Supply chain hardening - securing rtx is very important and this topic has had a lot of interest from the community. We plan to make several improvements on this front -* Improved python development - better virtualenv integration, precompiled python binaries, and other areas are topics that frequently come up to improve -* Improved plugin development - it's unclear what we'll do exactly but in general we want to make the experience of vending tools for asdf/rtx to be better and safer. -* GUI/TUI - While we're all big CLI fans, it still would be great to better visualize what tools are available, what your configuration is, and other things via some kind of UI. - -### Anti-goals - -* Dependency management - rtx expects you to have system dependencies (like openssl or readline) already setup and configured. This makes it different than tools like nix which manage all dependencies for you. While this seems like an obvious downside, it actually ends up making rtx far easier to use than nix. That said, we would like to make managing system dependencies easier where we can but this is likely going to be simply via better docs and error messages. -* DevOps tooling - rtx is designed with local development in mind. While there are certainly many devs using it for production/server roles which we support and encourage, that will never be the our focus on the roadmap. Building a better ansible/terraform/kubernetes just isn't the goal. -* Remote task caching - turbopack, moonrepo, and many others are trying to solve this (major) problem. rtx's task runner will likely always just be a simple convenience around executing scripts. -* Windows support - I don't have a Windows machine and I think asdf/rtx's focus on Unix tools will make supporting (non-WSL) Windows challenging if not impossible. Unless someone else wants to take on the challenge of building a Windows port I would not expect to see it happen. - -## FAQs - -### I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file - -You can make git ignore these files in 3 different ways: - -- Adding `.tool-versions` to project's `.gitignore` file. This has the downside that you need to commit the change to the ignore file. -- 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. -`rtx hook-env` checks the current env vars (most importantly `PATH` but there are others like -`GOROOT` or `JAVA_HOME` for some tools) and adds/removes/updates the ones that have changed. - -For example, if you `cd` into a different directory that has `java 18` instead of `java 17` -specified, just before the next prompt is displayed the shell runs: `eval "$(rtx hook-env)"` -which will execute something like this in the current shell session: - -```sh -export JAVA_HOME=$HOME/.local/share/installs/java/18 -export PATH=$HOME/.local/share/installs/java/18/bin:$PATH -``` - -In reality updating `PATH` is a bit more complex than that because it also needs to remove java-17, -but you get the idea. - -You may think that is excessive to run `rtx hook-env` every time the prompt is displayed -and it should only run on `cd`, however there are plenty of -situations where it needs to run without the directory changing, for example if `.tool-versions` or -`.rtx.toml` was just edited in the current shell. - -Because it runs on prompt display, if you attempt to use `rtx activate` in a -non-interactive session (like a bash script), it will never call `rtx hook-env` and in effect will -never modify PATH because it never displays a prompt. For this type of setup, you can either call -`rtx hook-env` manually every time you wish to update PATH, or use [shims](#shims) instead (preferred). -Or if you only need to use rtx for certain commands, just prefix the commands with -[`rtx x --`](#rtx-exec-options-toolversion----command). -For example, `rtx x -- npm test` or `rtx x -- ./my_script.sh`. - -`rtx hook-env` will exit early in different situations if no changes have been made. This prevents -adding latency to your shell prompt every time you run a command. You can run `rtx hook-env` yourself -to see what it outputs, however it is likely nothing if you're in a shell that has already been activated. - -`rtx activate` also creates a shell function (in most shells) called `rtx`. -This is a trick that makes it possible for `rtx shell` -and `rtx deactivate` to work without wrapping them in `eval "$(rtx shell)"`. - -### `rtx activate` doesn't work in `~/.profile`, `~/.bash_profile`, `~/.zprofile` - -`rtx activate` should only be used in `rc` files. These are the interactive ones used when -a real user is using the terminal. (As opposed to being executed by an IDE or something). The prompt -isn't displayed in non-interactive environments so PATH won't be modified. - -For non-interactive setups, consider using shims instead which will route calls to the correct -directory by looking at `PWD` every time they're executed. You can also call `rtx exec` instead of -expecting things to be directly on PATH. You can also run `rtx env` in a non-interactive shell, however that -will only setup the global tools. It won't modify the environment variables when entering into a -different project. - -Also see the [shebang](#shebang) example for a way to make scripts call rtx to get the runtime. -That is another way to use rtx without activation. - -### rtx is failing or not working right - -First try setting `RTX_DEBUG=1` or `RTX_TRACE=1` and see if that gives you more information. -You can also set `RTX_LOG_FILE_LEVEL=debug RTX_LOG_FILE=/path/to/logfile` to write logs to a file. - -If something is happening with the activate hook, you can try disabling it and calling `eval "$(rtx hook-env)"` manually. -It can also be helpful to use `rtx env` which will just output environment variables that would be set. -Also consider using [shims](#shims) which can be more compatible. - -If runtime installation isn't working right, try using the `--raw` flag which will install things in -series and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact -with you for some reason this will make it work. - -Of course check the version of rtx with `rtx --version` and make sure it is the latest. Use `rtx self-update` -to update it. `rtx cache clean` can be used to wipe the internal cache and `rtx implode` can be used -to remove everything except config. - -Before submitting a ticket, it's a good idea to test what you were doing with asdf. That way we can rule -out if the issue is with rtx or if it's with a particular plugin. For example, if `rtx install python@latest` -doesn't work, try running `asdf install python latest` to see if it's an issue with asdf-python. - -Lastly, there is `rtx doctor` which will show diagnostic information and any warnings about issues -detected with your setup. If you submit a bug report, please include the output of `rtx doctor`. - -### New version of a tool is not available - -There are 2 places that versions are cached so a brand new release might not appear right away. - -The first is that the rtx CLI caches versions for 24 hours. This can be cleared with `rtx cache clear`. - -The second uses the [rtx-versions](https://github.com/jdx/rtx-versions) repo as a centralized -place to list all of the versions of most plugins. This is intended to speed up rtx and also -get around GitHub rate limits when querying for new versions. Check that repo for your plugin to -see if it has an updated version. This service can be disabled by setting `RTX_USE_VERSIONS_HOST=0`. - -### Windows support? - -This is something we'd like to add! - -It's not a near-term goal and it would require plugin modifications, but it should be feasible. - -### How do I use rtx with http proxies? - -Short answer: just set `http_proxy` and `https_proxy` environment variables. These should be lowercase. - -rtx doesn't really do anything with http itself. The only exception to that is checking for new versions -and `rtx self-update`. It uses `git` to clone plugins and the plugins themselves generally will download -files with `curl` or `wget`. - -However this is really up to the plugin. If you're having a proxy-related issue installing something -you should post an issue on the plugin's repository. - -### How do the shorthand plugin names map to repositories? - -e.g.: how does `rtx plugin install elixir` know to fetch ? - -We maintain [an index](https://github.com/rtx-plugins/registry) of shorthands that rtx uses as a base. -This is regularly updated every time that rtx has a release. This repository is stored directly into -the codebase [here](./src/default_shorthands.rs). - -### Does "node@20" mean the newest available version of node? - -It depends on the command. Normally, for most commands and inside of config files, "node@20" will -point to the latest _installed_ version of node-20.x. You can find this version by running -`rtx latest --installed node@20` or by seeing what the `~/.local/share/rtx/installs/node/20` symlink -points to: - -```sh-session -$ ls -l ~/.local/share/rtx/installs/node/20 -[...] /home/jdx/.local/share/rtx/installs/node/20 -> node-v20.0.0-linux-x64 -``` - -There are some exceptions to this, such as the following: - -- `rtx install node@20` -- `rtx latest node@20` -- `rtx upgrade node@20` - -These will use the latest _available_ version of node-20.x. This generally makes sense because you -wouldn't want to install a version that is already installed. - -### How do I migrate from asdf? - -First, just install rtx with `rtx activate` like in the getting started guide and remove asdf from your -shell rc file. - -Then you can just run `rtx install` in a directory with an asdf `.tool-versions` file and it will -install the runtimes. You could attempt to avoid this by copying the internal directory from asdf over -to rtx with `cp -r ~/.asdf ~/.local/share/rtx`. That _should_ work because they use the same structure, -however this isn't officially supported or regularly tested. Alternatively you can set `RTX_DATA_DIR=~/.asdf` -and see what happens. - -### How compatible is rtx with asdf? - -rtx should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin -should be usable in rtx. The commands in rtx are slightly -different, such as `rtx install node@20.0.0` vs `asdf install node 20.0.0`—this is done so -multiple tools can be specified at once. However, asdf-style syntax is still supported: (`rtx -install node 20.0.0`). This is the case for most commands, though the help for the command may -say that asdf-style syntax is supported. - -When in doubt, just try asdf syntax and see if it works. If it doesn't open a ticket. It may -not be possible to support every command identically, but -we should attempt to make things as consistent as possible. - -This isn't important for usability reasons so much as making it so plugins continue to work that -call asdf commands. - -If you need to switch to/from asdf or work in a project with asdf users, you can set -[`RTX_ASDF_COMPAT=1`](#rtx_asdf_compat1). That prevents -rtx from writing `.tool-versions` files that will not be -compatible with asdf. Also consider using `.rtx.toml` instead which won't conflict with asdf setups. - -### rtx isn't working when calling from tmux or another shell initialization script - -`rtx activate` will not update PATH until the shell prompt is displayed. So if you need to access a -tool provided by rtx before the prompt is displayed you must manually call `hook-env`: - -```bash -eval "$(rtx activate bash)" -eval "$(rtx hook-env)" -python --version # will work only after calling hook-env explicitly -``` - -For more information, see [What does `rtx activate` do?](#what-does-rtx-activate-do) - -### How do I disable/force CLI color output? - -rtx uses [console.rs](https://docs.rs/console/latest/console/fn.colors_enabled.html) which -honors the [clicolors spec](https://bixense.com/clicolors/): - -- `CLICOLOR != 0`: ANSI colors are supported and should be used when the program isn’t piped. -- `CLICOLOR == 0`: Don’t output ANSI color escape codes. -- `CLICOLOR_FORCE != 0`: ANSI colors should be enabled no matter what. - -### Is rtx secure? - -Not as much as it should be, though currently a bit more secure than asdf. Work will happen in this area as secure -supply chains are incredibly important. See [SECURITY.md](./SECURITY.md) for more information. - -## Comparison to asdf - -rtx is mostly a clone of asdf, but there are notable areas where improvements have been made. - -### Performance - -asdf made (what I consider) a poor design decision to use shims that go between a call to a runtime -and the runtime itself. e.g.: when you call `node` it will call an asdf shim file `~/.asdf/shims/node`, -which then calls `asdf exec`, which then calls the correct version of node. - -These shims have terrible performance, adding ~120ms to every runtime call. `rtx activate` does not use shims and instead -updates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are the main reason that I wrote this. Note that in the demo GIF at the top of this README -that `rtx` isn't actually used when calling `node -v` for this reason. The performance is -identical to running node without using rtx. - -I don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup -of [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written -in bash which certainly makes it challenging to be performant, however I think the real problem is the -shim design. I don't think it's possible to fix that without a complete rewrite. - -rtx does call an internal command `rtx hook-env` every time the directory has changed, but because -it's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes, 14ms if it's -a full reload. - -tl;dr: asdf adds overhead (~120ms) when calling a runtime, rtx adds a small amount of overhead (~5ms) -when the prompt loads. - -### Environment variables in rtx - -asdf only helps manage runtime executables. However, some tools are managed via environment variables -(notably Java which switches via `JAVA_HOME`). This isn't supported very well in asdf and requires -a separate shell extension just to manage. - -However asdf _plugins_ have a `bin/exec-env` script that is used for exporting environment variables -like [`JAVA_HOME`](https://github.com/halcyon/asdf-java/blob/master/bin/exec-env). rtx simply exports -the environment variables from the `bin/exec-env` script in the plugin but places them in the shell -for _all_ commands. In asdf it only exports those commands when the shim is called. This means if you -call `java` it will set `JAVA_HOME`, but not if you call some Java tool like `mvn`. - -This means we're just using the existing plugin script but because rtx doesn't use shims it can be -used for more things. It would be trivial to make a plugin that exports arbitrary environment -variables like [dotenv](https://github.com/motdotla/dotenv) or [direnv](https://github.com/direnv/direnv). - -### UX - -Some commands are the same in asdf but others have been changed. Everything that's possible -in asdf should be possible in rtx but may use slightly different syntax. rtx has more forgiving commands, -such as using fuzzy-matching, e.g.: `rtx install node@20`. While in asdf you _can_ run -`asdf install node latest:20`, you can't use `latest:20` in a `.tool-versions` file or many other places. -In `rtx` you can use fuzzy-matching everywhere. - -asdf requires several steps to install a new runtime if the plugin isn't installed, e.g.: - -```sh-session -asdf plugin add node -asdf install node latest:20 -asdf local node latest:20 -``` - -In `rtx` this can all be done in a single step to set the local runtime version. If the plugin -and/or runtime needs to be installed it will prompt: - -[![asciicast](https://asciinema.org/a/564031.svg)](https://asciinema.org/a/564031) - -I've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like -having `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?). -`rtx` makes heavy use of aliases so you don't need to remember if it's `rtx plugin add node` or -`rtx plugin install node`. If I can guess what you meant, then I'll try to get rtx to respond -in the right way. - -That said, there are a lot of great things about asdf. It's the best multi-runtime manager out there -and I've really been impressed with the plugin system. Most of the design decisions the authors made -were very good. I really just have 2 complaints: the shims and the fact it's written in Bash. - -### CI/CD - -Using rtx in CI/CD is a great way to synchronize tool versions for dev/build. - -### GitHub Actions - -rtx is pretty easy to use without an action: - -```yaml -jobs: - build: - steps: - - run: | - curl https://rtx.jdx.dev/install.sh | sh - echo "$HOME/.local/share/rtx/bin" >> $GITHUB_PATH - echo "$HOME/.local/share/rtx/shims" >> $GITHUB_PATH -``` - -Or you can use the custom action [`jdx/rtx-action`](https://github.com/jdx/rtx-action): - -```yaml -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: jdx/rtx-action@v1 - - run: node -v # will be the node version from `.rtx.toml`/`.tool-versions` -``` - -## Shims - -While the PATH design of rtx works great in most cases, there are some situations where shims are -preferable. One example is when calling rtx binaries from an IDE. - -To support this, rtx does have a shim dir that can be used. It's located at `~/.local/share/rtx/shims`. - -```sh-session -$ rtx i node@20.0.0 -$ rtx reshim # may be required if new shims need to be created -$ ~/.local/share/rtx/shims/node -v -v20.0.0 -``` - -## direnv - -[direnv](https://direnv.net) and rtx both manage environment variables based on directory. Because they both analyze -the current environment variables before and after their respective "hook" commands are run, they can sometimes conflict with each other. - -If you have an issue, it's likely to do with the ordering of PATH. This means it would -really only be a problem if you were trying to manage the same tool with direnv and rtx. For example, -you may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with python -in it as well. - -A more typical usage of direnv would be to set some arbitrary environment variables, or add unrelated -binaries to PATH. In these cases, rtx will not interfere with direnv. - -### rtx inside of direnv (`use rtx` in `.envrc`) - -If you do encounter issues with `rtx activate`, or just want to use direnv in an alternate way, -this is a simpler setup that's less likely to cause issues—at the cost of functionality. - -This may be required if you want to use direnv's `layout python` with rtx. Otherwise there are -situations where rtx will override direnv's PATH. `use rtx` ensures that direnv always has control. - -To do this, first use `rtx` to build a `use_rtx` function that you can use in `.envrc` files: - -``` -rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh -``` - -Now in your `.envrc` file add the following: - -```sh-session -use rtx -``` - -direnv will now call rtx to export its environment variables. You'll need to make sure to add `use_rtx` -to all projects that use rtx (or use direnv's `source_up` to load it from a subdirectory). You can also add `use rtx` to `~/.config/direnv/direnvrc`. - -Note that in this method direnv typically won't know to refresh `.tool-versions` files -unless they're at the same level as a `.envrc` file. You'll likely always want to have -a `.envrc` file next to your `.tool-versions` for this reason. To make this a little -easier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead -setting environment variables entirely in `.envrc`: - -``` -export RTX_NODE_VERSION=20.0.0 -export RTX_PYTHON_VERSION=3.11 -``` - -Of course if you use `rtx activate`, then these steps won't have been necessary and you can use rtx -as if direnv was not used. - -If you continue to struggle, you can also try using the [shims method](#shims). - -### Do you need direnv? - -While making rtx compatible with direnv is, and will always be a major goal of this project, I also -want rtx to be capable of replacing direnv if needed. This is why rtx includes support for managing -env vars and [virtualenv](https://github.com/jdx/rtx/blob/main/docs/python.md#experimental-automatic-virtualenv-creationactivation) -for python using `.rtx.toml`. - -If you find you continue to need direnv, please open an issue and let me know what it is to see if -it's something rtx could support. rtx will never be as capable as direnv with a DSL like `.envrc`, -but I think we can handle enough common use cases to make that unnecessary for most people. - -## Cache Behavior - -rtx makes use of caching in many places in order to be efficient. The details about how long to keep -cache for should eventually all be configurable. There may be gaps in the current behavior where -things are hardcoded, but I'm happy to add more settings to cover whatever config is needed. - -Below I explain the behavior it uses around caching. If you're seeing behavior where things don't appear -to be updating, this is a good place to start. - -### Plugin/Runtime Cache - -Each plugin has a cache that's stored in `~/$RTX_CACHE_DIR/`. It stores -the list of versions available for that plugin (`rtx ls-remote `), the legacy filenames (see below), -the list of aliases, the bin directories within each runtime installation, and the result of -running `exec-env` after the runtime was installed. - -Remote versions are updated daily by default. The file is zlib messagepack, if you want to view it you can -run the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)). - -```sh-session -cat ~/$RTX_CACHE_DIR/node/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode -``` - -Note that the caching of `exec-env` may be problematic if the script isn't simply exporting -static values. The vast majority of `exec-env` scripts only export static values, but if you're -working with a plugin that has a dynamic `exec-env` submit -a ticket and we can try to figure out what to do. - -Caching `exec-env` massively improved the performance of rtx since it requires calling bash -every time rtx is initialized. Ideally, we can keep this -behavior. - - - -## Commands - -### `rtx activate [OPTIONS] [SHELL_TYPE]` - -```text -Initializes rtx in the current shell session - -This should go into your shell's rc file. -Otherwise, it will only take effect in the current session. -(e.g. ~/.zshrc, ~/.bashrc) - -This is only intended to be used in interactive sessions, not scripts. -rtx is only capable of updating PATH when the prompt is displayed to the user. -For non-interactive use-cases, use shims instead. - -Typically this can be added with something like the following: - - echo 'eval "$(rtx activate)"' >> ~/.zshrc - -However, this requires that "rtx" is in your PATH. If it is not, you need to -specify the full path like this: - - echo 'eval "$(/path/to/rtx activate)"' >> ~/.zshrc - -Usage: activate [OPTIONS] [SHELL_TYPE] - -Arguments: - [SHELL_TYPE] - Shell type to generate the script for - - [possible values: bash, fish, nu, xonsh, zsh] - -Options: - --status - Show "rtx: @" message when changing directories - - -q, --quiet - Suppress non-error messages - -Examples: - $ eval "$(rtx activate bash)" - $ eval "$(rtx activate zsh)" - $ rtx activate fish | source - $ execx($(rtx activate xonsh)) -``` - -### `rtx alias get ` - -```text -Show an alias for a plugin - -This is the contents of an alias. entry in ~/.config/rtx/config.toml - -Usage: alias get - -Arguments: - - The plugin to show the alias for - - - The alias to show - -Examples: - $ rtx alias get node lts-hydrogen - 20.0.0 -``` - -### `rtx alias ls [OPTIONS] [PLUGIN]` - -**Aliases:** `list` - -```text -List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`. - -For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: - - [alias.node] - lts = "20.0.0" - -Usage: alias ls [OPTIONS] [PLUGIN] - -Arguments: - [PLUGIN] - Show aliases for - -Options: - --no-header - Don't show table header - -Examples: - $ rtx aliases - node lts-hydrogen 20.0.0 -``` - -### `rtx alias set ` - -**Aliases:** `add, create` - -```text -Add/update an alias for a plugin - -This modifies the contents of ~/.config/rtx/config.toml - -Usage: alias set - -Arguments: - - The plugin to set the alias for - - - The alias to set - - - The value to set the alias to - -Examples: - $ rtx alias set node lts-hydrogen 18.0.0 -``` - -### `rtx alias unset ` - -**Aliases:** `del, delete, remove, rm` - -```text -Clears an alias for a plugin - -This modifies the contents of ~/.config/rtx/config.toml - -Usage: alias unset - -Arguments: - - The plugin to remove the alias from - - - The alias to remove - -Examples: - $ rtx alias unset node lts-hydrogen -``` - -### `rtx bin-paths` - -```text -List all the active runtime bin paths - -Usage: bin-paths -``` - -### `rtx cache clear [PLUGIN]...` - -**Aliases:** `c` - -```text -Deletes all cache files in rtx - -Usage: cache clear [PLUGIN]... - -Arguments: - [PLUGIN]... - Plugin(s) to clear cache for e.g.: node, python -``` - -### `rtx completion [SHELL]` - -```text -Generate shell completions - -Usage: completion [SHELL] - -Arguments: - [SHELL] - Shell type to generate completions for - - [possible values: bash, fish, zsh] - -Examples: - $ rtx completion bash > /etc/bash_completion.d/rtx - $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx - $ rtx completion fish > ~/.config/fish/completions/rtx.fish -``` - -### `rtx config ls [OPTIONS]` - -```text -[experimental] List config files currently in use - -Usage: config ls [OPTIONS] - -Options: - --no-header - Do not print table header - -Examples: - $ rtx config ls -``` - -### `rtx config generate [OPTIONS]` - -**Aliases:** `g` - -```text -[experimental] Generate an .rtx.toml file - -Usage: config generate [OPTIONS] - -Options: - -o, --output - Output to file instead of stdout - -Examples: - $ rtx cf generate > .rtx.toml - $ rtx cf generate --output=.rtx.toml -``` - -### `rtx current [PLUGIN]` - -```text -Shows current active and installed runtime versions - -This is similar to `rtx ls --current`, but this only shows the runtime -and/or version. It's designed to fit into scripts more easily. - -Usage: current [PLUGIN] - -Arguments: - [PLUGIN] - Plugin to show versions of e.g.: ruby, node - -Examples: - # outputs `.tool-versions` compatible format - $ rtx current - python 3.11.0 3.10.0 - shfmt 3.6.0 - shellcheck 0.9.0 - node 20.0.0 - - $ rtx current node - 20.0.0 - - # can output multiple versions - $ rtx current python - 3.11.0 3.10.0 -``` - -### `rtx deactivate` - -```text -Disable rtx for current shell session - -This can be used to temporarily disable rtx in a shell session. - -Usage: deactivate - -Examples: - $ rtx deactivate bash - $ rtx deactivate zsh - $ rtx deactivate fish - $ execx($(rtx deactivate xonsh)) -``` - -### `rtx direnv activate` - -```text -Output direnv function to use rtx inside direnv - -See https://github.com/jdx/rtx#direnv for more information - -Because this generates the legacy files based on currently installed plugins, -you should run this command after installing new plugins. Otherwise -direnv may not know to update environment variables when legacy file versions change. - -Usage: direnv activate - -Examples: - $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh - $ echo 'use rtx' > .envrc - $ direnv allow -``` - -### `rtx doctor` - -```text -Check rtx installation for possible problems. - -Usage: doctor - -Examples: - $ rtx doctor - [WARN] plugin node is not installed -``` - -### `rtx env [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `e` - -```text -Exports env vars to activate rtx a single time - -Use this if you don't want to permanently install rtx. It's not necessary to -use this if you have `rtx activate` in your shell rc file. - -Usage: env [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to use - -Options: - -s, --shell - Shell type to generate environment variables for - - [possible values: bash, fish, nu, xonsh, zsh] - - -J, --json - Output in JSON format - -Examples: - $ eval "$(rtx env -s bash)" - $ eval "$(rtx env -s zsh)" - $ rtx env -s fish | source - $ execx($(rtx env -s xonsh)) -``` - -### `rtx env-vars [OPTIONS] [ENV_VARS]...` - -```text -Manage environment variables - -By default this command modifies ".rtx.toml" in the current directory. -You can specify the file name by either setting the RTX_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. - -Usage: env-vars [OPTIONS] [ENV_VARS]... - -Arguments: - [ENV_VARS]... - Environment variable(s) to set - e.g.: NODE_ENV=production - -Options: - --file - The TOML file to update - - Defaults to RTX_DEFAULT_CONFIG_FILENAME environment variable, or ".rtx.toml". - - --remove - Remove the environment variable from config file - - Can be used multiple times. -``` - -### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` - -**Aliases:** `x` - -```text -Execute a command with tool(s) set - -use this to avoid modifying the shell session or running ad-hoc commands with rtx tools set. - -Tools will be loaded from .rtx.toml/.tool-versions, though they can be overridden with args -Note that only the plugin specified will be overridden, so if a `.tool-versions` file -includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. - -The "--" separates runtimes from the commands to pass along to the subprocess. - -Usage: exec [OPTIONS] [TOOL@VERSION]... [-- ...] - -Arguments: - [TOOL@VERSION]... - Tool(s) to start e.g.: node@20 python@3.10 - - [COMMAND]... - Command string to execute (same as --command) - -Options: - -c, --command - Command string to execute - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: RTX_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - -Examples: - $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x - $ rtx x node@20 -- node ./app.js # shorter alias - - # Specify command as a string: - $ rtx exec node@20 python@3.11 --command "node -v && python -V" - - # Run a command in a different directory: - $ rtx x -C /path/to/project node@20 -- node ./app.js -``` - -### `rtx implode [OPTIONS]` - -```text -Removes rtx CLI and all related data - -Skips config directory by default. - -Usage: implode [OPTIONS] - -Options: - --config - Also remove config directory - - -n, --dry-run - List directories that would be removed without actually removing them -``` - -### `rtx install [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `i` - -```text -Install a tool version - -This will install a tool version to `~/.local/share/rtx/installs//` -It won't be used simply by being installed, however. -For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. -Or you can call a tool version explicitly with `rtx exec @ -- `. - -Tools will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` - -Usage: install [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to install e.g.: node@20 - -Options: - -f, --force - Force reinstall even if already installed - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: RTX_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - - -v, --verbose... - Show installation output - -Examples: - $ rtx install node@20.0.0 # install specific node version - $ rtx install node@20 # install fuzzy node version - $ rtx install node # install version specified in .tool-versions or .rtx.toml - $ rtx install # installs everything specified in .tool-versions or .rtx.toml -``` - -### `rtx latest [OPTIONS] ` - -```text -Gets the latest available version for a plugin - -Usage: latest [OPTIONS] - -Arguments: - - Tool to get the latest version of - -Options: - -i, --installed - Show latest installed instead of available version - -Examples: - $ rtx latest node@20 # get the latest version of node 20 - 20.0.0 - - $ rtx latest node # get the latest stable version of node - 20.0.0 -``` - -### `rtx link [OPTIONS] ` - -**Aliases:** `ln` - -```text -Symlinks a tool version into rtx - -Use this for adding installs either custom compiled outside -rtx or built with a different tool. - -Usage: link [OPTIONS] - -Arguments: - - Tool name and version to create a symlink for - - - The local path to the tool version - e.g.: ~/.nvm/versions/node/v20.0.0 - -Options: - -f, --force - Overwrite an existing tool version if it exists - -Examples: - # build node-20.0.0 with node-build and link it into rtx - $ node-build 20.0.0 ~/.nodes/20.0.0 - $ rtx link node@20.0.0 ~/.nodes/20.0.0 - - # have rtx use the python version provided by Homebrew - $ brew install node - $ rtx link node@brew $(brew --prefix node) - $ rtx use node@brew -``` - -### `rtx ls [OPTIONS] [PLUGIN]...` - -**Aliases:** `list` - -```text -List installed and/or currently selected tool versions - -Usage: ls [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Only show tool versions from [PLUGIN] - -Options: - -c, --current - Only show tool versions currently specified in a .tool-versions/.rtx.toml - - -g, --global - Only show tool versions currently specified in a the global .tool-versions/.rtx.toml - - -i, --installed - Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed - - -J, --json - Output in json format - - -m, --missing - Display missing tool versions - - --prefix - Display versions matching this prefix - - --no-header - Don't display headers - -Examples: - $ rtx ls - node 20.0.0 ~/src/myapp/.tool-versions latest - python 3.11.0 ~/.tool-versions 3.10 - python 3.10.0 - - $ rtx ls --current - node 20.0.0 ~/src/myapp/.tool-versions 20 - python 3.11.0 ~/.tool-versions 3.11.0 - - $ rtx ls --json - { - "node": [ - { - "version": "20.0.0", - "install_path": "/Users/jdx/.rtx/installs/node/20.0.0", - "source": { - "type": ".rtx.toml", - "path": "/Users/jdx/.rtx.toml" - } - } - ], - "python": [...] - } -``` - -### `rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` - -```text -List runtime versions available for install - -note that the results are cached for 24 hours -run `rtx cache clean` to clear the cache and get fresh results - -Usage: ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX] - -Arguments: - [TOOL@VERSION] - Plugin to get versions for - - [PREFIX] - The version prefix to use when querying the latest version - same as the first argument after the "@" - -Options: - --all - Show all installed plugins and versions - -Examples: - $ rtx ls-remote node - 18.0.0 - 20.0.0 - - $ rtx ls-remote node@20 - 20.0.0 - 20.1.0 - - $ rtx ls-remote node 20 - 20.0.0 - 20.1.0 -``` - -### `rtx outdated [TOOL@VERSION]...` - -```text -Shows outdated tool versions - -Usage: outdated [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to show outdated versions for - e.g.: node@20 python@3.10 - If not specified, all tools in global and local configs will be shown - -Examples: - $ rtx outdated - Plugin Requested Current Latest - python 3.11 3.11.0 3.11.1 - node 20 20.0.0 20.1.0 - - $ rtx outdated node - Plugin Requested Current Latest - node 20 20.0.0 20.1.0 -``` - -### `rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` - -**Aliases:** `a, add, i` - -```text -Install a plugin - -note that rtx automatically can install plugins when you install a tool -e.g.: `rtx install node@20` will autoinstall the node plugin - -This behavior can be modified in ~/.config/rtx/config.toml - -Usage: plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL] - -Arguments: - [NEW_PLUGIN] - The name of the plugin to install - e.g.: node, ruby - Can specify multiple plugins: `rtx plugins install node ruby python` - - [GIT_URL] - The git url of the plugin - -Options: - -f, --force - Reinstall even if plugin exists - - -a, --all - Install all missing plugins - This will only install plugins that have matching shorthands. - i.e.: they don't need the full git repo url - - -v, --verbose... - Show installation output - -Examples: - # install the node via shorthand - $ rtx plugins install node - - # install the node plugin using a specific git url - $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git - - # install the node plugin using the git url only - # (node is inferred from the url) - $ rtx plugins install https://github.com/rtx-plugins/rtx-nodejs.git - - # install the node plugin using a specific ref - $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 -``` - -### `rtx plugins link [OPTIONS] [PATH]` - -**Aliases:** `ln` - -```text -Symlinks a plugin into rtx - -This is used for developing a plugin. - -Usage: plugins link [OPTIONS] [PATH] - -Arguments: - - The name of the plugin - e.g.: node, ruby - - [PATH] - The local path to the plugin - e.g.: ./rtx-node - -Options: - -f, --force - Overwrite existing plugin - -Examples: - # essentially just `ln -s ./rtx-node ~/.local/share/rtx/plugins/node` - $ rtx plugins link node ./rtx-node - - # infer plugin name as "node" - $ rtx plugins link ./rtx-node -``` - -### `rtx plugins ls [OPTIONS]` - -**Aliases:** `list` - -```text -List installed plugins - -Can also show remotely available plugins to install. - -Usage: plugins ls [OPTIONS] - -Options: - -c, --core - The built-in plugins only - Normally these are not shown - - --user - List installed plugins - - This is the default behavior but can be used with --core - to show core and user plugins - - -u, --urls - Show the git url for each plugin - e.g.: https://github.com/asdf-vm/asdf-node.git - -Examples: - $ rtx plugins ls - node - ruby - - $ rtx plugins ls --urls - node https://github.com/asdf-vm/asdf-node.git - ruby https://github.com/asdf-vm/asdf-ruby.git -``` - -### `rtx plugins ls-remote [OPTIONS]` - -**Aliases:** `list-all, list-remote` - -```text -List all available remote plugins - -The full list is here: https://github.com/jdx/rtx/blob/main/src/default_shorthands.rs - -Examples: - $ rtx plugins ls-remote - - -Usage: plugins ls-remote [OPTIONS] - -Options: - -u, --urls - Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git - - --only-names - Only show the name of each plugin by default it will show a "*" next to installed plugins -``` - -### `rtx plugins uninstall [OPTIONS] [PLUGIN]...` - -**Aliases:** `remove, rm` - -```text -Removes a plugin - -Usage: plugins uninstall [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Plugin(s) to remove - -Options: - -p, --purge - Also remove the plugin's installs, downloads, and cache - - -a, --all - Remove all plugins - -Examples: - $ rtx uninstall node -``` - -### `rtx plugins update [OPTIONS] [PLUGIN]...` - -**Aliases:** `upgrade` - -```text -Updates a plugin to the latest version - -note: this updates the plugin itself, not the runtime versions - -Usage: plugins update [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Plugin(s) to update - -Options: - -j, --jobs - Number of jobs to run in parallel - Default: 4 - -Examples: - $ rtx plugins update # update all plugins - $ rtx plugins update node # update only node - $ rtx plugins update node#beta # specify a ref -``` - -### `rtx prune [OPTIONS] [PLUGIN]...` - -```text -Delete unused versions of tools - -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`). - -Usage: prune [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Prune only versions from these plugins - -Options: - -n, --dry-run - Do not actually delete anything - -Examples: - $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/node/20.0.0 - rm -rf ~/.local/share/rtx/versions/node/20.0.1 -``` - -### `rtx reshim` - -```text -rebuilds the shim farm - -This creates new shims in ~/.local/share/rtx/shims for CLIs that have been added. -rtx will try to do this automatically for commands like `npm i -g` but there are -other ways to install things (like using yarn or pnpm for node) that rtx does -not know about and so it will be necessary to call this explicitly. - -If you think rtx should automatically call this for a particular command, please -open an issue on the rtx repo. You can also setup a shell function to reshim -automatically (it's really fast so you don't need to worry about overhead): - -npm() { - command npm "$@" - rtx reshim -} - -Usage: reshim - -Examples: - $ rtx reshim - $ ~/.local/share/rtx/shims/node -v - v20.0.0 -``` - -### `rtx run [OPTIONS] [TASK] [ARGS]...` - -**Aliases:** `r` - -```text -[experimental] Run a task - -This command will run a task, or multiple tasks in parallel. -Tasks may have dependencies on other tasks or on source files. -If source is configured on a task, it will only run if the source -files have changed. - -Tasks can be defined in .rtx.toml or as standalone scripts. -In .rtx.toml, tasks take this form: - - [tasks.build] - run = "npm run build" - sources = ["src/**/*.ts"] - outputs = ["dist/**/*.js"] - -Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.rtx/tasks` directory. -The name of the script will be the name of the task. - - $ cat .rtx/tasks/build< - Change to this directory before executing the command - - -n, --dry-run - Don't actually run the task(s), just print them in order of execution - - -f, --force - Force the task to run even if outputs are up to date - - -p, --prefix - Print stdout/stderr by line, prefixed with the task's label - Defaults to true if --jobs > 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var - - -i, --interleave - Print directly to stdout/stderr instead of by line - Defaults to true if --jobs == 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var - - -t, --tool - Tool(s) to also add e.g.: node@20 python@3.10 - - -j, --jobs - Number of tasks to run in parallel - [default: 4] - Configure with `jobs` config or `RTX_JOBS` env var - - [env: RTX_JOBS=] - - -r, --raw - Read/write directly to stdin/stdout/stderr instead of by line - Configure with `raw` config or `RTX_RAW` env var - -Examples: - $ rtx run lint - Runs the "lint" task. This needs to either be defined in .rtx.toml - or as a standalone script. See the project README for more information. - - $ rtx run build --force - Forces the "build" task to run even if its sources are up-to-date. - - $ rtx run test --raw - Runs "test" with stdin/stdout/stderr all connected to the current terminal. - This forces `--jobs=1` to prevent interleaving of output. - - $ rtx run lint ::: test ::: check - Runs the "lint", "test", and "check" tasks in parallel. - - $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 - Execute multiple tasks each with their own arguments. -``` - -### `rtx self-update [OPTIONS] [VERSION]` - -```text -Updates rtx itself - -Uses the GitHub Releases API to find the latest release and binary -By default, this will also update any installed plugins - -Usage: self-update [OPTIONS] [VERSION] - -Arguments: - [VERSION] - Update to a specific version - -Options: - -f, --force - Update even if already up to date - - --no-plugins - Disable auto-updating plugins - - -y, --yes - Skip confirmation prompt -``` - -### `rtx settings get ` - -```text -Show a current setting - -This is the contents of a single entry in ~/.config/rtx/config.toml - -Note that aliases are also stored in this file -but managed separately with `rtx aliases get` - -Usage: settings get - -Arguments: - - The setting to show - -Examples: - $ rtx settings get legacy_version_file - true -``` - -### `rtx settings ls` - -**Aliases:** `list` - -```text -Show current settings - -This is the contents of ~/.config/rtx/config.toml - -Note that aliases are also stored in this file -but managed separately with `rtx aliases` - -Usage: settings ls - -Examples: - $ rtx settings - legacy_version_file = false -``` - -### `rtx settings set ` - -**Aliases:** `add, create` - -```text -Add/update a setting - -This modifies the contents of ~/.config/rtx/config.toml - -Usage: settings set - -Arguments: - - The setting to set - - - The value to set - -Examples: - $ rtx settings set legacy_version_file true -``` - -### `rtx settings unset ` - -**Aliases:** `del, delete, remove, rm` - -```text -Clears a setting - -This modifies the contents of ~/.config/rtx/config.toml - -Usage: settings unset - -Arguments: - - The setting to remove - -Examples: - $ rtx settings unset legacy_version_file -``` - -### `rtx shell [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `sh` - -```text -Sets a tool version for the current shell session - -Only works in a session where rtx is already activated. - -Usage: shell [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to use - -Options: - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: RTX_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - - -u, --unset - Removes a previously set version - -Examples: - $ rtx shell node@20 - $ node -v - v20.0.0 -``` - -### `rtx sync node <--brew|--nvm|--nodenv>` - -```text -Symlinks all tool versions from an external tool into rtx - -For example, use this to import all Homebrew node installs into rtx - -Usage: sync node <--brew|--nvm|--nodenv> - -Options: - --brew - Get tool versions from Homebrew - - --nvm - Get tool versions from nvm - - --nodenv - Get tool versions from nodenv - -Examples: - $ brew install node@18 node@20 - $ rtx sync node --brew - $ rtx use -g node@18 - uses Homebrew-provided node -``` - -### `rtx sync python --pyenv` - -```text -Symlinks all tool versions from an external tool into rtx - -For example, use this to import all pyenv installs into rtx - -Usage: sync python --pyenv - -Options: - --pyenv - Get tool versions from pyenv - -Examples: - $ pyenv install 3.11.0 - $ rtx sync python --pyenv - $ rtx use -g python@3.11.0 - uses pyenv-provided python -``` - -### `rtx task edit [OPTIONS] ` - -```text -[experimental] Edit a task with $EDITOR - -The task will be created as a standalone script if it does not already exist. - -Usage: task edit [OPTIONS] - -Arguments: - - Task to edit - -Options: - -p, --path - Display the path to the task instead of editing it - -Examples: - $ rtx task edit build - $ rtx task edit test -``` - -### `rtx task ls [OPTIONS]` - -```text -[experimental] List available tasks to execute -These may be included from the config file or from the project's .rtx/tasks directory -rtx will merge all tasks from all parent directories into this list. - -So if you have global tasks in ~/.config/rtx/tasks/* and project-specific tasks in -~/myproject/.rtx/tasks/*, then they'll both be available but the project-specific -tasks will override the global ones if they have the same name. - -Usage: task ls [OPTIONS] - -Options: - --no-header - Do not print table header - - --hidden - Show hidden tasks - -Examples: - $ rtx task ls -``` - -### `rtx task run [OPTIONS] [TASK] [ARGS]...` - -**Aliases:** `r` - -```text -[experimental] Run a task - -This command will run a task, or multiple tasks in parallel. -Tasks may have dependencies on other tasks or on source files. -If source is configured on a task, it will only run if the source -files have changed. - -Tasks can be defined in .rtx.toml or as standalone scripts. -In .rtx.toml, tasks take this form: - - [tasks.build] - run = "npm run build" - sources = ["src/**/*.ts"] - outputs = ["dist/**/*.js"] - -Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.rtx/tasks` directory. -The name of the script will be the name of the task. - - $ cat .rtx/tasks/build< - Change to this directory before executing the command - - -n, --dry-run - Don't actually run the task(s), just print them in order of execution - - -f, --force - Force the task to run even if outputs are up to date - - -p, --prefix - Print stdout/stderr by line, prefixed with the task's label - Defaults to true if --jobs > 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var - - -i, --interleave - Print directly to stdout/stderr instead of by line - Defaults to true if --jobs == 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var - - -t, --tool - Tool(s) to also add e.g.: node@20 python@3.10 - - -j, --jobs - Number of tasks to run in parallel - [default: 4] - Configure with `jobs` config or `RTX_JOBS` env var - - [env: RTX_JOBS=] - - -r, --raw - Read/write directly to stdin/stdout/stderr instead of by line - Configure with `raw` config or `RTX_RAW` env var - -Examples: - $ rtx run lint - Runs the "lint" task. This needs to either be defined in .rtx.toml - or as a standalone script. See the project README for more information. - - $ rtx run build --force - Forces the "build" task to run even if its sources are up-to-date. - - $ rtx run test --raw - Runs "test" with stdin/stdout/stderr all connected to the current terminal. - This forces `--jobs=1` to prevent interleaving of output. - - $ rtx run lint ::: test ::: check - Runs the "lint", "test", and "check" tasks in parallel. - - $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 - Execute multiple tasks each with their own arguments. -``` - -### `rtx trust [OPTIONS] [CONFIG_FILE]` - -```text -Marks a config file as trusted - -This means rtx will parse the file with potentially dangerous -features enabled. - -This includes: -- environment variables -- templates -- `path:` plugin versions - -Usage: trust [OPTIONS] [CONFIG_FILE] - -Arguments: - [CONFIG_FILE] - The config file to trust - -Options: - -a, --all - Trust all config files in the current directory and its parents - - --untrust - No longer trust this config - -Examples: - # trusts ~/some_dir/.rtx.toml - $ rtx trust ~/some_dir/.rtx.toml - - # trusts .rtx.toml in the current or parent directory - $ rtx trust -``` - -### `rtx uninstall [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `remove, rm` - -```text -Removes runtime versions - -Usage: uninstall [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to remove - -Options: - -a, --all - Delete all installed versions - - -n, --dry-run - Do not actually delete anything - -Examples: - $ rtx uninstall node@18.0.0 # will uninstall specific version - $ rtx uninstall node # will uninstall current node version - $ rtx uninstall --all node@18.0.0 # will uninstall all node versions -``` - -### `rtx upgrade [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `up` - -```text -Upgrades outdated tool versions - -Usage: upgrade [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to upgrade - e.g.: node@20 python@3.10 - If not specified, all current tools will be upgraded - -Options: - -n, --dry-run - Just print what would be done, don't actually do it - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: RTX_JOBS=] - - -i, --interactive - Display multiselect menu to choose which tools to upgrade - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 -``` - -### `rtx use [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `u` - -```text -Change the active version of a tool locally or globally. - -This will install the tool if it is not already installed. -By default, this will use an `.rtx.toml` file in the current directory. -Use the --global flag to use the global config file instead. -This replaces asdf's `local` and `global` commands, however those are still available in rtx. - -Usage: use [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to add to config file - e.g.: node@20 - If no version is specified, it will default to @latest - -Options: - -f, --force - Force reinstall even if already installed - - --fuzzy - Save fuzzy version to config file - e.g.: `rtx use --fuzzy node@20` will save 20 as the version - this is the default behavior unless RTX_ASDF_COMPAT=1 - - -g, --global - Use the global config file (~/.config/rtx/config.toml) instead of the local one - - -e, --env - Modify an environment-specific config file like .rtx..toml - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: RTX_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - - --remove - Remove the tool(s) from config file - - -p, --path - Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions - - --pin - Save exact version to config file - e.g.: `rtx use --pin node@20` will save 20.0.0 as the version - - [env: RTX_ASDF_COMPAT=] - -Examples: - # set the current version of node to 20.x in .rtx.toml of current directory - # will write the fuzzy version (e.g.: 20) - $ rtx use node@20 - - # set the current version of node to 20.x in ~/.config/rtx/config.toml - # will write the precise version (e.g.: 20.0.0) - $ rtx use -g --pin node@20 - - # sets .rtx.local.toml (which is intended not to be committed to a project) - $ rtx use --env local node@20 - - # sets .rtx.staging.toml (which is used if RTX_ENV=staging) - $ rtx use --env staging node@20 -``` - -### `rtx version` - -```text -Show rtx version - -Usage: version -``` - -### `rtx watch [OPTIONS] [ARGS]...` - -**Aliases:** `w` - -```text -[experimental] Run a task watching for changes - -Usage: watch [OPTIONS] [ARGS]... - -Arguments: - [ARGS]... - Extra arguments - -Options: - -t, --task - Task to run - - [default: default] - - -g, --glob - Files to watch - Defaults to sources from the task(s) - -Examples: - $ rtx watch -t build - Runs the "build" task. Will re-run the task when any of its sources change. - Uses "sources" from the task definition to determine which files to watch. - - $ rtx watch -t build --glob src/**/*.rs - Runs the "build" task but specify the files to watch with a glob pattern. - This overrides the "sources" from the task definition. - - $ rtx run -t build --clear - Extra arguments are passed to watchexec. See `watchexec --help` for details. -``` - -### `rtx where ` - -```text -Display the installation path for a runtime - -Must be installed. - -Usage: where - -Arguments: - - Tool(s) to look up - e.g.: ruby@3 - if "@" is specified, it will show the latest installed version - that matches the prefix - otherwise, it will show the current, active installed version - -Examples: - # Show the latest installed version of node - # If it is is not installed, errors - $ rtx where node@20 - /home/jdx/.local/share/rtx/installs/node/20.0.0 - - # Show the current, active install directory of node - # Errors if node is not referenced in any .tool-version file - $ rtx where node - /home/jdx/.local/share/rtx/installs/node/20.0.0 -``` - -### `rtx which [OPTIONS] ` - -```text -Shows the path that a bin name points to - -Usage: which [OPTIONS] - -Arguments: - - The bin name to look up - -Options: - --plugin - Show the plugin name instead of the path - - --version - Show the version instead of the path - - -t, --tool - Use a specific tool@version - e.g.: `rtx which npm --tool=node@20` - -Examples: - $ rtx which node - /home/username/.local/share/rtx/installs/node/20.0.0/bin/node - $ rtx which node --plugin - node - $ rtx which node --version - 20.0.0 -``` +## Full Documentation - +See [rtx.jdx.dev](https://rtx.jdx.dev). diff --git a/docs/deno.md b/docs/deno.md index fc6b2bf4f..318811d82 100644 --- a/docs/deno.md +++ b/docs/deno.md @@ -1,21 +1 @@ -# Deno in rtx - -The following are instructions for using the deno rtx core plugin. This is used when there isn't a -git plugin installed named "deno". - -If you want to use [asdf-deno](https://github.com/asdf-community/asdf-deno) -then run `rtx plugins install deno https://github.com/asdf-community/asdf-deno`. - -The code for this is inside the rtx repository at -[`./src/plugins/core/deno.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/deno.rs). - -## Usage - -The following installs deno and makes it the global default: - -```sh-session -rtx use -g deno@1 # install deno 1.x -rtx use -g deno@latest # install latest deno -``` - -See available versions with `rtx ls-remote deno`. +Moved to [rtx.jdx.dev/lang/deno](https://rtx.jdx.dev/lang/deno). diff --git a/docs/go.md b/docs/go.md index 53081cbe8..d4f85bfd1 100644 --- a/docs/go.md +++ b/docs/go.md @@ -1,44 +1 @@ -# Go in rtx - -The following are instructions for using the go rtx core plugin. This is used when there isn't a -git plugin installed named "go". - -If you want to use [asdf-golang](https://github.com/kennyp/asdf-golang) -or [rtx-golang](https://github.com/rtx-plugins/rtx-golang) -then use `rtx plugins install go GIT_URL`. - -The code for this is inside the rtx repository at -[`./src/plugins/core/go.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/go.rs). - -## Usage - -The following installs the latest version of go-1.20.x (if some version of 1.20.x is not already -installed) and makes it the global default: - -```sh-session -rtx use -g go@1.20 -``` - -## Configuration - -- `RTX_GO_SKIP_CHECKSUM` [bool]: skips checksum verification of downloaded go tarballs, defaults to false -- `RTX_GO_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-go-packages` -- `RTX_GO_DOWNLOAD_MIRROR` [string]: location to download go from, defaults to `https://dl.google.com/go` -- `RTX_GO_SET_GOROOT` [bool]: set `$GOROOT` to the rtx go installs go root dir, defaults to true -- `RTX_GO_SET_GOPATH` [bool]: set `$GOPATH` to the rtx go installs packages dir, defaults to true - -## Default packages - -rtx can automatically install a default set of packages right after installing a new go version. -To enable this feature, provide a `$HOME/.default-go-packages` file that lists one packages per -line, for example: - -```text -github.com/Dreamacro/clash # allows comments -github.com/jesseduffield/lazygit -``` - -## `.go-version` file support - -rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. -However it can also read go-specific version files named `.go-version`. +Moved to [rtx.jdx.dev/lang/go](https://rtx.jdx.dev/lang/go). diff --git a/docs/java.md b/docs/java.md index 7edb6a6c6..654b01708 100644 --- a/docs/java.md +++ b/docs/java.md @@ -1,38 +1 @@ -# Java in rtx - -The following are instructions for using the java rtx core plugin. This is used when there isn't a -git plugin installed named "java". - -If you want to use [asdf-java](https://github.com/halcyon/asdf-java) -or [rtx-java](https://github.com/rtx-plugins/rtx-java) -then use `rtx plugins install java GIT_URL`. - -The code for this is inside the rtx repository at -[`./src/plugins/core/java.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/java.rs). - -## Usage - -The following installs the latest version of java-openjdk-17.x (if some version of openjdk-17.x is -not already installed) and makes it the global default: - -```sh-session -rtx use -g java@openjdk-17 -rtx use -g java@17 # alternate shorthands for openjdk-only -``` - -See available versions with `rtx ls-remote java`. - -## macOS JAVA_HOME Integration - -Some applications in macOS rely on `/usr/libexec/java_home` to find installed Java runtimes. - -To integrate an installed Java runtime with macOS run the following commands for the proper version (e.g. openjdk-20). - -```sh-session -sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-20.jdk -sudo ln -s ~/.local/share/rtx/installs/java/openjdk-20/Contents /Library/Java/JavaVirtualMachines/openjdk-20.jdk/Contents -``` - -The distribution from Azul Systems does support the integration but the symlink target location will differ from the example above (e.g `~/.local/share/rtx/installs/java/zulu-11.64.190/zulu-11.jdk/Contents`). - -> Note: Not all distributions of the Java SDK support this integration (e.g liberica). +Moved to [rtx.jdx.dev/lang/java](https://rtx.jdx.dev/lang/java). diff --git a/docs/node.md b/docs/node.md index 3101f5861..53798e178 100644 --- a/docs/node.md +++ b/docs/node.md @@ -1,70 +1 @@ -# Node in rtx - -The following are instructions for using the node rtx core plugin. This is used when there isn't a -git plugin installed named "node". - -If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) or -[rtx-node](https://github.com/rtx-plugins/rtx-nodejs) then run `rtx plugins install node GIT_URL`. - -The code for this is inside the rtx repository at [`./src/plugins/core/node.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/node.rs). - -## Usage - -The following installs the latest version of node-20.x and makes it the global -default: - -```sh-session -rtx use -g node@20 -``` - -## Requirements - -See [BUILDING.md](https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms) in node's documentation for -required system dependencies. - -## Configuration - -- `RTX_NODE_BUILD` [bool]: See [Moving away from node-build](#moving-away-from-node-build) below. -- `RTX_NODE_BUILD_REPO` [string]: the default is `https://github.com/nodenv/node-build.git` -- `RTX_NODE_VERIFY` [bool]: Verify the downloaded assets using GPG. Defaults to `true`. -- `RTX_NODE_NINJA` [bool]: Use ninja instead of make to compile node. Defaults to `true` if installed. -- `RTX_NODE_COMPILE` [bool]: Forces compilation from source instead of preferring pre-compiled binaries. Can also be set across all languages with [`RTX_NODE__COMPILE`](https://github.com/jdx/rtx#rtx_node_compile1) -- `RTX_NODE_CONCURRENCY` [uint]: How many jobs should be used in compilation. Defaults to half the computer cores -- `RTX_NODE_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-npm-packages` -- `RTX_NODE_MIRROR_URL` [string]: overrides the default mirror used for downloading the distributions -- `RTX_NODE_CFLAGS` [string]: Additional CFLAGS options (e.g., to override -O3). -- `RTX_NODE_CONFIGURE_OPTS` [string]: Additional `./configure` options. -- `RTX_NODE_MAKE_OPTS` [string]: Additional `make` options. -- `RTX_NODE_MAKE_INSTALL_OPTS` [string]: Additional `make install` options. -- `RTX_NODE_COREPACK` [bool]: Installs the default corepack shims after installing any node version that ships with [corepack](https://github.com/nodejs/corepack). - -## Default node packages - -rtx-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-npm-packages` file that lists one package per line, for example: - -```text -lodash -request -express -``` - -You can specify a non-default location of this file by setting a `RTX_NODE_DEFAULT_PACKAGES_FILE` variable. - -## `.nvmrc` and `.node-version` support - -rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. To ease migration, you can have also have it read an existing `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `node` isn't defined in `.tool-versions`/`.rtx.toml`. - -## "nodejs" -> "node" Alias - -You cannot install/use a plugin named "nodejs". If you attempt this, rtx will just renamed it to -"node". See the [FAQ](https://github.com/jdx/rtx#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) -for an explanation. - -## Moving away from node-build - -This project is in the process of migrating away from using [node-build](https://github.com/nodenv/node-build) for fetching/compiling node. -The main reason for this is just to reduce the # of moving parts but it has some other advantages like not relying on new node-build releases to -get the latest node releases. - -Currently, you can opt into using the pure-rtx node fetching with `RTX_NODE_BUILD=0` this will be the default -behavior in a few weeks from this writing. +Moved to [rtx.jdx.dev/lang/node](https://rtx.jdx.dev/lang/node). diff --git a/docs/python.md b/docs/python.md index 992483407..74ac71494 100644 --- a/docs/python.md +++ b/docs/python.md @@ -1,62 +1 @@ -# Python in rtx - -The following are instructions for using the python rtx core plugin. The core plugin will be used so long as no plugin is manually -installed named "python" using `rtx plugins install python [GIT_URL]`. - -The code for this is inside of the rtx repository at [`./src/plugins/core/python.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/python.rs). - -## Usage - -The following installs the latest version of python-3.11.x and makes it the global -default: - -```sh-session -rtx use -g python@3.11 -``` - -You can also use multiple versions of python at the same time: - -```sh-session -$ rtx use -g python@3.10 python@3.11 -$ python -V -3.10.0 -$ python3.11 -V -3.11.0 -``` - -## Requirements - -rtx uses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/python-build) (part of pyenv) to install python runtimes, you need to ensure its [dependencies](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) are installed before installing python. - -## Configuration - -`python-build` already has a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in -additional to that python in rtx has a few extra configuration variables: - -- `RTX_PYENV_REPO` [string]: the default is `https://github.com/pyenv/pyenv.git` -- `RTX_PYTHON_PATCH_URL` [string]: A url to a patch file to pass to python-build. -- `RTX_PYTHON_PATCHES_DIRECTORY` [string]: A local directory containing patch files to pass to python-build. -- `RTX_PYTHON_DEFAULT_PACKAGES_FILE` [string]: location of default packages file, defaults to `$HOME/.default-python-packages` - -## Default Python packages - -rtx can automatically install a default set of Python packages with pip right after installing a Python version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists one package per line, for example: - -```text -ansible -pipenv -``` - -You can specify a non-default location of this file by setting a `RTX_PYTHON_DEFAULT_PACKAGES_FILE` variable. - -## [experimental] Automatic virtualenv creation/activation - -Python comes with virtualenv support built in, use it with `.rtx.toml` configuration like -one of the following: - -```toml -[tools] -python = {version="3.11", virtualenv=".venv"} # relative to this file's directory -python = {version="3.11", virtualenv="/root/.venv"} # can be absolute -python = {version="3.11", virtualenv="{{env.HOME}}/.cache/venv/myproj"} # can use templates -``` +Moved to [rtx.jdx.dev/lang/python](https://rtx.jdx.dev/lang/python) diff --git a/docs/ruby.md b/docs/ruby.md index 1c4b6e2e6..3c3459196 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -1,73 +1 @@ -# Ruby in rtx - -The following are instructions for using the ruby rtx core plugin. This is used when there isn't a -git plugin installed named "ruby". - -If you want to use [asdf-ruby](https://github.com/asdf-vm/asdf-ruby) -or [rtx-ruby](https://github.com/rtx-plugins/rtx-ruby) -then use `rtx plugins install ruby GIT_URL`. - -The code for this is inside the rtx repository at -[`./src/plugins/core/ruby.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/ruby.rs). - -## Usage - -The following installs the latest version of ruby-3.2.x (if some version of 3.2.x is not already -installed) and makes it the global default: - -```sh-session -rtx use -g ruby@3.2 -``` - -Behind the scenes, rtx uses [`ruby-build`](https://github.com/rbenv/ruby-build) to compile ruby -from source. You can check its -[README](https://github.com/rbenv/ruby-build/blob/master/README.md) -for additional settings and some troubleshooting. - -## Configuration - -`ruby-build` already has a -[handful of settings](https://github.com/nodenv/node-build#custom-build-configuration), -in additional to that rtx has a few extra configuration variables: - -- `RTX_RUBY_INSTALL` [bool]: Build with ruby-install instead of ruby-build -- `RTX_RUBY_APPLY_PATCHES` [string]: A list of patches (files or URLs) to apply to the ruby source code -- `RTX_RUBY_VERBOSE_INSTALL` [bool]: Show verbose output during installation (passes --verbose to ruby-build) -- `RTX_RUBY_BUILD_OPTS` [string]: Command line options to pass to ruby-build when installing -- `RTX_RUBY_INSTALL_OPTS` [string]: Command line options to pass to ruby-install when installing (if RTX_RUBY_INSTALL=1) -- `RTX_RUBY_DEFAULT_PACKAGES_FILE` [string]: location of default gems file, defaults to `$HOME/.default-gems` - -## Default gems - -rtx can automatically install a default set of gems right after installing a new ruby version. -To enable this feature, provide a `$HOME/.default-gems` file that lists one gem per line, for -example: - -``` -# supports comments -pry -bcat ~> 0.6.0 # supports version constraints -rubocop --pre # install prerelease version -``` - -## `.ruby-version` and `Gemfile` support - -rtx uses a `.tool-versions` or `.rtx.toml` file for auto-switching between software versions. -However it can also read ruby-specific version files `.ruby-version` or `Gemfile` -(if it specifies a ruby version). - -Create a `.ruby-version` file for the current version of ruby: - -```sh-session -ruby -v > .ruby-version -``` - -### Manually updating ruby-build - -ruby-build should update daily, however if you find versions do not yet exist you can force an -update: - -```bash -rtx cache clean -rtx ls-remote ruby -``` +Moved to [rtx.jdx.dev/lang/ruby](https://rtx.jdx.dev/lang/ruby). From 0ab06acc6a98f00ac023d55beaf7e023ceb6e240 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 30 Dec 2023 16:16:28 -0600 Subject: [PATCH 1470/1891] added cli_reference.md --- docs/cli-reference.md | 1577 ++++++++++++++++++++++++++++++++++++++++ justfile | 3 +- src/cli/render_help.rs | 10 +- 3 files changed, 1584 insertions(+), 6 deletions(-) create mode 100644 docs/cli-reference.md diff --git a/docs/cli-reference.md b/docs/cli-reference.md new file mode 100644 index 000000000..a55d232d0 --- /dev/null +++ b/docs/cli-reference.md @@ -0,0 +1,1577 @@ + + +## Commands + +### `rtx activate [OPTIONS] [SHELL_TYPE]` + +```text +Initializes rtx in the current shell session + +This should go into your shell's rc file. +Otherwise, it will only take effect in the current session. +(e.g. ~/.zshrc, ~/.bashrc) + +This is only intended to be used in interactive sessions, not scripts. +rtx is only capable of updating PATH when the prompt is displayed to the user. +For non-interactive use-cases, use shims instead. + +Typically this can be added with something like the following: + + echo 'eval "$(rtx activate)"' >> ~/.zshrc + +However, this requires that "rtx" is in your PATH. If it is not, you need to +specify the full path like this: + + echo 'eval "$(/path/to/rtx activate)"' >> ~/.zshrc + +Usage: activate [OPTIONS] [SHELL_TYPE] + +Arguments: + [SHELL_TYPE] + Shell type to generate the script for + + [possible values: bash, fish, nu, xonsh, zsh] + +Options: + --status + Show "rtx: @" message when changing directories + + -q, --quiet + Suppress non-error messages + +Examples: + $ eval "$(rtx activate bash)" + $ eval "$(rtx activate zsh)" + $ rtx activate fish | source + $ execx($(rtx activate xonsh)) +``` + +### `rtx alias get ` + +```text +Show an alias for a plugin + +This is the contents of an alias. entry in ~/.config/rtx/config.toml + +Usage: alias get + +Arguments: + + The plugin to show the alias for + + + The alias to show + +Examples: + $ rtx alias get node lts-hydrogen + 20.0.0 +``` + +### `rtx alias ls [OPTIONS] [PLUGIN]` + +**Aliases:** `list` + +```text +List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`. + +For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: + + [alias.node] + lts = "20.0.0" + +Usage: alias ls [OPTIONS] [PLUGIN] + +Arguments: + [PLUGIN] + Show aliases for + +Options: + --no-header + Don't show table header + +Examples: + $ rtx aliases + node lts-hydrogen 20.0.0 +``` + +### `rtx alias set ` + +**Aliases:** `add, create` + +```text +Add/update an alias for a plugin + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: alias set + +Arguments: + + The plugin to set the alias for + + + The alias to set + + + The value to set the alias to + +Examples: + $ rtx alias set node lts-hydrogen 18.0.0 +``` + +### `rtx alias unset ` + +**Aliases:** `del, delete, remove, rm` + +```text +Clears an alias for a plugin + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: alias unset + +Arguments: + + The plugin to remove the alias from + + + The alias to remove + +Examples: + $ rtx alias unset node lts-hydrogen +``` + +### `rtx bin-paths` + +```text +List all the active runtime bin paths + +Usage: bin-paths +``` + +### `rtx cache clear [PLUGIN]...` + +**Aliases:** `c` + +```text +Deletes all cache files in rtx + +Usage: cache clear [PLUGIN]... + +Arguments: + [PLUGIN]... + Plugin(s) to clear cache for e.g.: node, python +``` + +### `rtx completion [SHELL]` + +```text +Generate shell completions + +Usage: completion [SHELL] + +Arguments: + [SHELL] + Shell type to generate completions for + + [possible values: bash, fish, zsh] + +Examples: + $ rtx completion bash > /etc/bash_completion.d/rtx + $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx + $ rtx completion fish > ~/.config/fish/completions/rtx.fish +``` + +### `rtx config ls [OPTIONS]` + +```text +[experimental] List config files currently in use + +Usage: config ls [OPTIONS] + +Options: + --no-header + Do not print table header + +Examples: + $ rtx config ls +``` + +### `rtx config generate [OPTIONS]` + +**Aliases:** `g` + +```text +[experimental] Generate an .rtx.toml file + +Usage: config generate [OPTIONS] + +Options: + -o, --output + Output to file instead of stdout + +Examples: + $ rtx cf generate > .rtx.toml + $ rtx cf generate --output=.rtx.toml +``` + +### `rtx current [PLUGIN]` + +```text +Shows current active and installed runtime versions + +This is similar to `rtx ls --current`, but this only shows the runtime +and/or version. It's designed to fit into scripts more easily. + +Usage: current [PLUGIN] + +Arguments: + [PLUGIN] + Plugin to show versions of e.g.: ruby, node + +Examples: + # outputs `.tool-versions` compatible format + $ rtx current + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + node 20.0.0 + + $ rtx current node + 20.0.0 + + # can output multiple versions + $ rtx current python + 3.11.0 3.10.0 +``` + +### `rtx deactivate` + +```text +Disable rtx for current shell session + +This can be used to temporarily disable rtx in a shell session. + +Usage: deactivate + +Examples: + $ rtx deactivate bash + $ rtx deactivate zsh + $ rtx deactivate fish + $ execx($(rtx deactivate xonsh)) +``` + +### `rtx direnv activate` + +```text +Output direnv function to use rtx inside direnv + +See https://github.com/jdx/rtx#direnv for more information + +Because this generates the legacy files based on currently installed plugins, +you should run this command after installing new plugins. Otherwise +direnv may not know to update environment variables when legacy file versions change. + +Usage: direnv activate + +Examples: + $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh + $ echo 'use rtx' > .envrc + $ direnv allow +``` + +### `rtx doctor` + +```text +Check rtx installation for possible problems. + +Usage: doctor + +Examples: + $ rtx doctor + [WARN] plugin node is not installed +``` + +### `rtx env [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `e` + +```text +Exports env vars to activate rtx a single time + +Use this if you don't want to permanently install rtx. It's not necessary to +use this if you have `rtx activate` in your shell rc file. + +Usage: env [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to use + +Options: + -s, --shell + Shell type to generate environment variables for + + [possible values: bash, fish, nu, xonsh, zsh] + + -J, --json + Output in JSON format + +Examples: + $ eval "$(rtx env -s bash)" + $ eval "$(rtx env -s zsh)" + $ rtx env -s fish | source + $ execx($(rtx env -s xonsh)) +``` + +### `rtx env-vars [OPTIONS] [ENV_VARS]...` + +```text +Manage environment variables + +By default this command modifies ".rtx.toml" in the current directory. +You can specify the file name by either setting the RTX_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. + +Usage: env-vars [OPTIONS] [ENV_VARS]... + +Arguments: + [ENV_VARS]... + Environment variable(s) to set + e.g.: NODE_ENV=production + +Options: + --file + The TOML file to update + + Defaults to RTX_DEFAULT_CONFIG_FILENAME environment variable, or ".rtx.toml". + + --remove + Remove the environment variable from config file + + Can be used multiple times. +``` + +### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` + +**Aliases:** `x` + +```text +Execute a command with tool(s) set + +use this to avoid modifying the shell session or running ad-hoc commands with rtx tools set. + +Tools will be loaded from .rtx.toml/.tool-versions, though they can be overridden with args +Note that only the plugin specified will be overridden, so if a `.tool-versions` file +includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. + +The "--" separates runtimes from the commands to pass along to the subprocess. + +Usage: exec [OPTIONS] [TOOL@VERSION]... [-- ...] + +Arguments: + [TOOL@VERSION]... + Tool(s) to start e.g.: node@20 python@3.10 + + [COMMAND]... + Command string to execute (same as --command) + +Options: + -c, --command + Command string to execute + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + +Examples: + $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x + $ rtx x node@20 -- node ./app.js # shorter alias + + # Specify command as a string: + $ rtx exec node@20 python@3.11 --command "node -v && python -V" + + # Run a command in a different directory: + $ rtx x -C /path/to/project node@20 -- node ./app.js +``` + +### `rtx implode [OPTIONS]` + +```text +Removes rtx CLI and all related data + +Skips config directory by default. + +Usage: implode [OPTIONS] + +Options: + --config + Also remove config directory + + -n, --dry-run + List directories that would be removed without actually removing them +``` + +### `rtx install [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `i` + +```text +Install a tool version + +This will install a tool version to `~/.local/share/rtx/installs//` +It won't be used simply by being installed, however. +For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. +Or you can call a tool version explicitly with `rtx exec @ -- `. + +Tools will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` + +Usage: install [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to install e.g.: node@20 + +Options: + -f, --force + Force reinstall even if already installed + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + -v, --verbose... + Show installation output + +Examples: + $ rtx install node@20.0.0 # install specific node version + $ rtx install node@20 # install fuzzy node version + $ rtx install node # install version specified in .tool-versions or .rtx.toml + $ rtx install # installs everything specified in .tool-versions or .rtx.toml +``` + +### `rtx latest [OPTIONS] ` + +```text +Gets the latest available version for a plugin + +Usage: latest [OPTIONS] + +Arguments: + + Tool to get the latest version of + +Options: + -i, --installed + Show latest installed instead of available version + +Examples: + $ rtx latest node@20 # get the latest version of node 20 + 20.0.0 + + $ rtx latest node # get the latest stable version of node + 20.0.0 +``` + +### `rtx link [OPTIONS] ` + +**Aliases:** `ln` + +```text +Symlinks a tool version into rtx + +Use this for adding installs either custom compiled outside +rtx or built with a different tool. + +Usage: link [OPTIONS] + +Arguments: + + Tool name and version to create a symlink for + + + The local path to the tool version + e.g.: ~/.nvm/versions/node/v20.0.0 + +Options: + -f, --force + Overwrite an existing tool version if it exists + +Examples: + # build node-20.0.0 with node-build and link it into rtx + $ node-build 20.0.0 ~/.nodes/20.0.0 + $ rtx link node@20.0.0 ~/.nodes/20.0.0 + + # have rtx use the python version provided by Homebrew + $ brew install node + $ rtx link node@brew $(brew --prefix node) + $ rtx use node@brew +``` + +### `rtx ls [OPTIONS] [PLUGIN]...` + +**Aliases:** `list` + +```text +List installed and/or currently selected tool versions + +Usage: ls [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Only show tool versions from [PLUGIN] + +Options: + -c, --current + Only show tool versions currently specified in a .tool-versions/.rtx.toml + + -g, --global + Only show tool versions currently specified in a the global .tool-versions/.rtx.toml + + -i, --installed + Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed + + -J, --json + Output in json format + + -m, --missing + Display missing tool versions + + --prefix + Display versions matching this prefix + + --no-header + Don't display headers + +Examples: + $ rtx ls + node 20.0.0 ~/src/myapp/.tool-versions latest + python 3.11.0 ~/.tool-versions 3.10 + python 3.10.0 + + $ rtx ls --current + node 20.0.0 ~/src/myapp/.tool-versions 20 + python 3.11.0 ~/.tool-versions 3.11.0 + + $ rtx ls --json + { + "node": [ + { + "version": "20.0.0", + "install_path": "/Users/jdx/.rtx/installs/node/20.0.0", + "source": { + "type": ".rtx.toml", + "path": "/Users/jdx/.rtx.toml" + } + } + ], + "python": [...] + } +``` + +### `rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` + +```text +List runtime versions available for install + +note that the results are cached for 24 hours +run `rtx cache clean` to clear the cache and get fresh results + +Usage: ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX] + +Arguments: + [TOOL@VERSION] + Plugin to get versions for + + [PREFIX] + The version prefix to use when querying the latest version + same as the first argument after the "@" + +Options: + --all + Show all installed plugins and versions + +Examples: + $ rtx ls-remote node + 18.0.0 + 20.0.0 + + $ rtx ls-remote node@20 + 20.0.0 + 20.1.0 + + $ rtx ls-remote node 20 + 20.0.0 + 20.1.0 +``` + +### `rtx outdated [TOOL@VERSION]...` + +```text +Shows outdated tool versions + +Usage: outdated [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to show outdated versions for + e.g.: node@20 python@3.10 + If not specified, all tools in global and local configs will be shown + +Examples: + $ rtx outdated + Plugin Requested Current Latest + python 3.11 3.11.0 3.11.1 + node 20 20.0.0 20.1.0 + + $ rtx outdated node + Plugin Requested Current Latest + node 20 20.0.0 20.1.0 +``` + +### `rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` + +**Aliases:** `a, add, i` + +```text +Install a plugin + +note that rtx automatically can install plugins when you install a tool +e.g.: `rtx install node@20` will autoinstall the node plugin + +This behavior can be modified in ~/.config/rtx/config.toml + +Usage: plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL] + +Arguments: + [NEW_PLUGIN] + The name of the plugin to install + e.g.: node, ruby + Can specify multiple plugins: `rtx plugins install node ruby python` + + [GIT_URL] + The git url of the plugin + +Options: + -f, --force + Reinstall even if plugin exists + + -a, --all + Install all missing plugins + This will only install plugins that have matching shorthands. + i.e.: they don't need the full git repo url + + -v, --verbose... + Show installation output + +Examples: + # install the node via shorthand + $ rtx plugins install node + + # install the node plugin using a specific git url + $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git + + # install the node plugin using the git url only + # (node is inferred from the url) + $ rtx plugins install https://github.com/rtx-plugins/rtx-nodejs.git + + # install the node plugin using a specific ref + $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 +``` + +### `rtx plugins link [OPTIONS] [PATH]` + +**Aliases:** `ln` + +```text +Symlinks a plugin into rtx + +This is used for developing a plugin. + +Usage: plugins link [OPTIONS] [PATH] + +Arguments: + + The name of the plugin + e.g.: node, ruby + + [PATH] + The local path to the plugin + e.g.: ./rtx-node + +Options: + -f, --force + Overwrite existing plugin + +Examples: + # essentially just `ln -s ./rtx-node ~/.local/share/rtx/plugins/node` + $ rtx plugins link node ./rtx-node + + # infer plugin name as "node" + $ rtx plugins link ./rtx-node +``` + +### `rtx plugins ls [OPTIONS]` + +**Aliases:** `list` + +```text +List installed plugins + +Can also show remotely available plugins to install. + +Usage: plugins ls [OPTIONS] + +Options: + -c, --core + The built-in plugins only + Normally these are not shown + + --user + List installed plugins + + This is the default behavior but can be used with --core + to show core and user plugins + + -u, --urls + Show the git url for each plugin + e.g.: https://github.com/asdf-vm/asdf-node.git + +Examples: + $ rtx plugins ls + node + ruby + + $ rtx plugins ls --urls + node https://github.com/asdf-vm/asdf-node.git + ruby https://github.com/asdf-vm/asdf-ruby.git +``` + +### `rtx plugins ls-remote [OPTIONS]` + +**Aliases:** `list-all, list-remote` + +```text +List all available remote plugins + +The full list is here: https://github.com/jdx/rtx/blob/main/src/default_shorthands.rs + +Examples: + $ rtx plugins ls-remote + + +Usage: plugins ls-remote [OPTIONS] + +Options: + -u, --urls + Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git + + --only-names + Only show the name of each plugin by default it will show a "*" next to installed plugins +``` + +### `rtx plugins uninstall [OPTIONS] [PLUGIN]...` + +**Aliases:** `remove, rm` + +```text +Removes a plugin + +Usage: plugins uninstall [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Plugin(s) to remove + +Options: + -p, --purge + Also remove the plugin's installs, downloads, and cache + + -a, --all + Remove all plugins + +Examples: + $ rtx uninstall node +``` + +### `rtx plugins update [OPTIONS] [PLUGIN]...` + +**Aliases:** `upgrade` + +```text +Updates a plugin to the latest version + +note: this updates the plugin itself, not the runtime versions + +Usage: plugins update [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Plugin(s) to update + +Options: + -j, --jobs + Number of jobs to run in parallel + Default: 4 + +Examples: + $ rtx plugins update # update all plugins + $ rtx plugins update node # update only node + $ rtx plugins update node#beta # specify a ref +``` + +### `rtx prune [OPTIONS] [PLUGIN]...` + +```text +Delete unused versions of tools + +rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`RTX__VERSION`) will be deleted, +as will versions only referenced on the command line (`rtx exec @`). + +Usage: prune [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Prune only versions from these plugins + +Options: + -n, --dry-run + Do not actually delete anything + +Examples: + $ rtx prune --dry-run + rm -rf ~/.local/share/rtx/versions/node/20.0.0 + rm -rf ~/.local/share/rtx/versions/node/20.0.1 +``` + +### `rtx reshim` + +```text +rebuilds the shim farm + +This creates new shims in ~/.local/share/rtx/shims for CLIs that have been added. +rtx will try to do this automatically for commands like `npm i -g` but there are +other ways to install things (like using yarn or pnpm for node) that rtx does +not know about and so it will be necessary to call this explicitly. + +If you think rtx should automatically call this for a particular command, please +open an issue on the rtx repo. You can also setup a shell function to reshim +automatically (it's really fast so you don't need to worry about overhead): + +npm() { + command npm "$@" + rtx reshim +} + +Usage: reshim + +Examples: + $ rtx reshim + $ ~/.local/share/rtx/shims/node -v + v20.0.0 +``` + +### `rtx run [OPTIONS] [TASK] [ARGS]...` + +**Aliases:** `r` + +```text +[experimental] Run a task + +This command will run a task, or multiple tasks in parallel. +Tasks may have dependencies on other tasks or on source files. +If source is configured on a task, it will only run if the source +files have changed. + +Tasks can be defined in .rtx.toml or as standalone scripts. +In .rtx.toml, tasks take this form: + + [tasks.build] + run = "npm run build" + sources = ["src/**/*.ts"] + outputs = ["dist/**/*.js"] + +Alternatively, tasks can be defined as standalone scripts. +These must be located in the `.rtx/tasks` directory. +The name of the script will be the name of the task. + + $ cat .rtx/tasks/build< + Change to this directory before executing the command + + -n, --dry-run + Don't actually run the task(s), just print them in order of execution + + -f, --force + Force the task to run even if outputs are up to date + + -p, --prefix + Print stdout/stderr by line, prefixed with the task's label + Defaults to true if --jobs > 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -i, --interleave + Print directly to stdout/stderr instead of by line + Defaults to true if --jobs == 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -t, --tool + Tool(s) to also add e.g.: node@20 python@3.10 + + -j, --jobs + Number of tasks to run in parallel + [default: 4] + Configure with `jobs` config or `RTX_JOBS` env var + + [env: RTX_JOBS=] + + -r, --raw + Read/write directly to stdin/stdout/stderr instead of by line + Configure with `raw` config or `RTX_RAW` env var + +Examples: + $ rtx run lint + Runs the "lint" task. This needs to either be defined in .rtx.toml + or as a standalone script. See the project README for more information. + + $ rtx run build --force + Forces the "build" task to run even if its sources are up-to-date. + + $ rtx run test --raw + Runs "test" with stdin/stdout/stderr all connected to the current terminal. + This forces `--jobs=1` to prevent interleaving of output. + + $ rtx run lint ::: test ::: check + Runs the "lint", "test", and "check" tasks in parallel. + + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + Execute multiple tasks each with their own arguments. +``` + +### `rtx self-update [OPTIONS] [VERSION]` + +```text +Updates rtx itself + +Uses the GitHub Releases API to find the latest release and binary +By default, this will also update any installed plugins + +Usage: self-update [OPTIONS] [VERSION] + +Arguments: + [VERSION] + Update to a specific version + +Options: + -f, --force + Update even if already up to date + + --no-plugins + Disable auto-updating plugins + + -y, --yes + Skip confirmation prompt +``` + +### `rtx settings get ` + +```text +Show a current setting + +This is the contents of a single entry in ~/.config/rtx/config.toml + +Note that aliases are also stored in this file +but managed separately with `rtx aliases get` + +Usage: settings get + +Arguments: + + The setting to show + +Examples: + $ rtx settings get legacy_version_file + true +``` + +### `rtx settings ls` + +**Aliases:** `list` + +```text +Show current settings + +This is the contents of ~/.config/rtx/config.toml + +Note that aliases are also stored in this file +but managed separately with `rtx aliases` + +Usage: settings ls + +Examples: + $ rtx settings + legacy_version_file = false +``` + +### `rtx settings set ` + +**Aliases:** `add, create` + +```text +Add/update a setting + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: settings set + +Arguments: + + The setting to set + + + The value to set + +Examples: + $ rtx settings set legacy_version_file true +``` + +### `rtx settings unset ` + +**Aliases:** `del, delete, remove, rm` + +```text +Clears a setting + +This modifies the contents of ~/.config/rtx/config.toml + +Usage: settings unset + +Arguments: + + The setting to remove + +Examples: + $ rtx settings unset legacy_version_file +``` + +### `rtx shell [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `sh` + +```text +Sets a tool version for the current shell session + +Only works in a session where rtx is already activated. + +Usage: shell [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to use + +Options: + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + -u, --unset + Removes a previously set version + +Examples: + $ rtx shell node@20 + $ node -v + v20.0.0 +``` + +### `rtx sync node <--brew|--nvm|--nodenv>` + +```text +Symlinks all tool versions from an external tool into rtx + +For example, use this to import all Homebrew node installs into rtx + +Usage: sync node <--brew|--nvm|--nodenv> + +Options: + --brew + Get tool versions from Homebrew + + --nvm + Get tool versions from nvm + + --nodenv + Get tool versions from nodenv + +Examples: + $ brew install node@18 node@20 + $ rtx sync node --brew + $ rtx use -g node@18 - uses Homebrew-provided node +``` + +### `rtx sync python --pyenv` + +```text +Symlinks all tool versions from an external tool into rtx + +For example, use this to import all pyenv installs into rtx + +Usage: sync python --pyenv + +Options: + --pyenv + Get tool versions from pyenv + +Examples: + $ pyenv install 3.11.0 + $ rtx sync python --pyenv + $ rtx use -g python@3.11.0 - uses pyenv-provided python +``` + +### `rtx task edit [OPTIONS] ` + +```text +[experimental] Edit a task with $EDITOR + +The task will be created as a standalone script if it does not already exist. + +Usage: task edit [OPTIONS] + +Arguments: + + Task to edit + +Options: + -p, --path + Display the path to the task instead of editing it + +Examples: + $ rtx task edit build + $ rtx task edit test +``` + +### `rtx task ls [OPTIONS]` + +```text +[experimental] List available tasks to execute +These may be included from the config file or from the project's .rtx/tasks directory +rtx will merge all tasks from all parent directories into this list. + +So if you have global tasks in ~/.config/rtx/tasks/* and project-specific tasks in +~/myproject/.rtx/tasks/*, then they'll both be available but the project-specific +tasks will override the global ones if they have the same name. + +Usage: task ls [OPTIONS] + +Options: + --no-header + Do not print table header + + --hidden + Show hidden tasks + +Examples: + $ rtx task ls +``` + +### `rtx task run [OPTIONS] [TASK] [ARGS]...` + +**Aliases:** `r` + +```text +[experimental] Run a task + +This command will run a task, or multiple tasks in parallel. +Tasks may have dependencies on other tasks or on source files. +If source is configured on a task, it will only run if the source +files have changed. + +Tasks can be defined in .rtx.toml or as standalone scripts. +In .rtx.toml, tasks take this form: + + [tasks.build] + run = "npm run build" + sources = ["src/**/*.ts"] + outputs = ["dist/**/*.js"] + +Alternatively, tasks can be defined as standalone scripts. +These must be located in the `.rtx/tasks` directory. +The name of the script will be the name of the task. + + $ cat .rtx/tasks/build< + Change to this directory before executing the command + + -n, --dry-run + Don't actually run the task(s), just print them in order of execution + + -f, --force + Force the task to run even if outputs are up to date + + -p, --prefix + Print stdout/stderr by line, prefixed with the task's label + Defaults to true if --jobs > 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -i, --interleave + Print directly to stdout/stderr instead of by line + Defaults to true if --jobs == 1 + Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + + -t, --tool + Tool(s) to also add e.g.: node@20 python@3.10 + + -j, --jobs + Number of tasks to run in parallel + [default: 4] + Configure with `jobs` config or `RTX_JOBS` env var + + [env: RTX_JOBS=] + + -r, --raw + Read/write directly to stdin/stdout/stderr instead of by line + Configure with `raw` config or `RTX_RAW` env var + +Examples: + $ rtx run lint + Runs the "lint" task. This needs to either be defined in .rtx.toml + or as a standalone script. See the project README for more information. + + $ rtx run build --force + Forces the "build" task to run even if its sources are up-to-date. + + $ rtx run test --raw + Runs "test" with stdin/stdout/stderr all connected to the current terminal. + This forces `--jobs=1` to prevent interleaving of output. + + $ rtx run lint ::: test ::: check + Runs the "lint", "test", and "check" tasks in parallel. + + $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + Execute multiple tasks each with their own arguments. +``` + +### `rtx trust [OPTIONS] [CONFIG_FILE]` + +```text +Marks a config file as trusted + +This means rtx will parse the file with potentially dangerous +features enabled. + +This includes: +- environment variables +- templates +- `path:` plugin versions + +Usage: trust [OPTIONS] [CONFIG_FILE] + +Arguments: + [CONFIG_FILE] + The config file to trust + +Options: + -a, --all + Trust all config files in the current directory and its parents + + --untrust + No longer trust this config + +Examples: + # trusts ~/some_dir/.rtx.toml + $ rtx trust ~/some_dir/.rtx.toml + + # trusts .rtx.toml in the current or parent directory + $ rtx trust +``` + +### `rtx uninstall [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `remove, rm` + +```text +Removes runtime versions + +Usage: uninstall [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to remove + +Options: + -a, --all + Delete all installed versions + + -n, --dry-run + Do not actually delete anything + +Examples: + $ rtx uninstall node@18.0.0 # will uninstall specific version + $ rtx uninstall node # will uninstall current node version + $ rtx uninstall --all node@18.0.0 # will uninstall all node versions +``` + +### `rtx upgrade [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `up` + +```text +Upgrades outdated tool versions + +Usage: upgrade [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to upgrade + e.g.: node@20 python@3.10 + If not specified, all current tools will be upgraded + +Options: + -n, --dry-run + Just print what would be done, don't actually do it + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + -i, --interactive + Display multiselect menu to choose which tools to upgrade + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 +``` + +### `rtx use [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `u` + +```text +Change the active version of a tool locally or globally. + +This will install the tool if it is not already installed. +By default, this will use an `.rtx.toml` file in the current directory. +Use the --global flag to use the global config file instead. +This replaces asdf's `local` and `global` commands, however those are still available in rtx. + +Usage: use [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to add to config file + e.g.: node@20 + If no version is specified, it will default to @latest + +Options: + -f, --force + Force reinstall even if already installed + + --fuzzy + Save fuzzy version to config file + e.g.: `rtx use --fuzzy node@20` will save 20 as the version + this is the default behavior unless RTX_ASDF_COMPAT=1 + + -g, --global + Use the global config file (~/.config/rtx/config.toml) instead of the local one + + -e, --env + Modify an environment-specific config file like .rtx..toml + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: RTX_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + --remove + Remove the tool(s) from config file + + -p, --path + Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions + + --pin + Save exact version to config file + e.g.: `rtx use --pin node@20` will save 20.0.0 as the version + + [env: RTX_ASDF_COMPAT=] + +Examples: + # set the current version of node to 20.x in .rtx.toml of current directory + # will write the fuzzy version (e.g.: 20) + $ rtx use node@20 + + # set the current version of node to 20.x in ~/.config/rtx/config.toml + # will write the precise version (e.g.: 20.0.0) + $ rtx use -g --pin node@20 + + # sets .rtx.local.toml (which is intended not to be committed to a project) + $ rtx use --env local node@20 + + # sets .rtx.staging.toml (which is used if RTX_ENV=staging) + $ rtx use --env staging node@20 +``` + +### `rtx version` + +```text +Show rtx version + +Usage: version +``` + +### `rtx watch [OPTIONS] [ARGS]...` + +**Aliases:** `w` + +```text +[experimental] Run a task watching for changes + +Usage: watch [OPTIONS] [ARGS]... + +Arguments: + [ARGS]... + Extra arguments + +Options: + -t, --task + Task to run + + [default: default] + + -g, --glob + Files to watch + Defaults to sources from the task(s) + +Examples: + $ rtx watch -t build + Runs the "build" task. Will re-run the task when any of its sources change. + Uses "sources" from the task definition to determine which files to watch. + + $ rtx watch -t build --glob src/**/*.rs + Runs the "build" task but specify the files to watch with a glob pattern. + This overrides the "sources" from the task definition. + + $ rtx run -t build --clear + Extra arguments are passed to watchexec. See `watchexec --help` for details. +``` + +### `rtx where ` + +```text +Display the installation path for a runtime + +Must be installed. + +Usage: where + +Arguments: + + Tool(s) to look up + e.g.: ruby@3 + if "@" is specified, it will show the latest installed version + that matches the prefix + otherwise, it will show the current, active installed version + +Examples: + # Show the latest installed version of node + # If it is is not installed, errors + $ rtx where node@20 + /home/jdx/.local/share/rtx/installs/node/20.0.0 + + # Show the current, active install directory of node + # Errors if node is not referenced in any .tool-version file + $ rtx where node + /home/jdx/.local/share/rtx/installs/node/20.0.0 +``` + +### `rtx which [OPTIONS] ` + +```text +Shows the path that a bin name points to + +Usage: which [OPTIONS] + +Arguments: + + The bin name to look up + +Options: + --plugin + Show the plugin name instead of the path + + --version + Show the version instead of the path + + -t, --tool + Use a specific tool@version + e.g.: `rtx which npm --tool=node@20` + +Examples: + $ rtx which node + /home/username/.local/share/rtx/installs/node/20.0.0/bin/node + $ rtx which node --plugin + node + $ rtx which node --version + 20.0.0 +``` + + diff --git a/justfile b/justfile index 13a13855c..07e013a27 100644 --- a/justfile +++ b/justfile @@ -109,7 +109,7 @@ lint-fix: render-all: render-help render-completions render-mangen -# regenerate README.md +# regenerate docs/cli-reference.md render-help: build NO_COLOR=1 rtx render-help #npx markdown-magic @@ -128,6 +128,7 @@ render-mangen: build # called by lefthook precommit hook pre-commit: render-all lint git add README.md + git add docs/cli-reference.md git add completions git add man diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 60dda6b7f..9d76b6af0 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -14,7 +14,7 @@ pub struct RenderHelp {} impl RenderHelp { pub fn run(self) -> Result<()> { - let readme = file::read_to_string("README.md")?; + let readme = file::read_to_string("docs/cli-reference.md")?; let mut current_readme = readme.split(""); let mut doc = String::new(); @@ -23,7 +23,7 @@ impl RenderHelp { doc.push_str(render_commands().as_str()); doc.push_str(current_readme.next().unwrap()); doc = remove_trailing_spaces(&doc) + "\n"; - file::write("README.md", &doc)?; + file::write("docs/cli-reference.md", &doc)?; Ok(()) } } @@ -120,7 +120,7 @@ mod tests { #[test] fn test_render_help() { file::write( - "README.md", + "docs/cli-reference.md", indoc! {r#" @@ -128,8 +128,8 @@ mod tests { ) .unwrap(); assert_cli!("render-help"); - let readme = fs::read_to_string("README.md").unwrap(); + let readme = fs::read_to_string("docs/cli-reference.md").unwrap(); assert!(readme.contains("## Commands")); - file::remove_file("README.md").unwrap(); + file::remove_file("docs/cli-reference.md").unwrap(); } } From d6ce49b17ae33bd0516944a17644297c19874c3d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 30 Dec 2023 16:20:31 -0600 Subject: [PATCH 1471/1891] added cli_reference.md --- README.md | 6 +++--- src/cli/render_help.rs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5c9caf6e3..1d6810cdb 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](#plugins). -* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](#env---arbitrary-environment-variables) for different project directories. -* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](#experimental-task-runner) used to build and test projects. +* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://rtx.jdx.dev/plugins). +* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://rtx.jdx.dev/environments) for different project directories. +* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://rtx.jdx.dev/tasks) used to build and test projects. ## 30 Second Demo diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 9d76b6af0..e262f9061 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -119,6 +119,7 @@ mod tests { #[test] fn test_render_help() { + file::create_dir_all("docs").unwrap(); file::write( "docs/cli-reference.md", indoc! {r#" From eab717794b3b172114e4262757b9c040b710cc97 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 30 Dec 2023 16:25:36 -0600 Subject: [PATCH 1472/1891] fixed links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1d6810cdb..10c034b19 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://rtx.jdx.dev/plugins). -* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://rtx.jdx.dev/environments) for different project directories. -* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://rtx.jdx.dev/tasks) used to build and test projects. +* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://rtx.jdx.dev/plugins.html). +* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://rtx.jdx.dev/environments.html) for different project directories. +* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://rtx.jdx.dev/tasks.html) used to build and test projects. ## 30 Second Demo From d74213c67da0d7f58279dea2123a6ea136b9e7ae Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 30 Dec 2023 16:51:29 -0600 Subject: [PATCH 1473/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 10c034b19..8cec0057d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Note that calling `which node` gives us a real path to node, not a shim. ## Quickstart -Install rtx on macOS (other methods [here](https://rtx.jdx.dev/installation)): +Install rtx on macOS (other methods [here](https://rtx.jdx.dev/getting-started.html)): ```sh-session $ curl https://rtx.jdx.dev/install.sh | sh From 5532b2a1c2824537e6e03928f5dafd559bd46455 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:14:21 -0600 Subject: [PATCH 1474/1891] docs: reference new docs url --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b160d33e4..4c5127ae4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ version = "2023.12.40" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] -homepage = "https://github.com/jdx/rtx" -documentation = "https://github.com/jdx/rtx" +homepage = "https://rtx.jdx.dev" +documentation = "https://rtx.jdx.dev" repository = "https://github.com/jdx/rtx" readme = "README.md" license = "MIT" From be5226fb7eed5c0d2e5fa34c88021d11e9702448 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 31 Dec 2023 15:34:14 -0600 Subject: [PATCH 1475/1891] node: remove node-build support (#1304) See #1028 Use asdf-nodejs if you want to continue using node-build (but please lmk why you need it) --- README.md | 2 +- docs/bun.md | 19 +-- docs/deno.md | 2 +- docs/go.md | 2 +- docs/java.md | 2 +- docs/node.md | 2 +- docs/python.md | 2 +- docs/ruby.md | 2 +- src/env.rs | 6 - src/plugins/core/mod.rs | 9 +- src/plugins/core/node_build.rs | 295 --------------------------------- 11 files changed, 9 insertions(+), 334 deletions(-) delete mode 100644 src/plugins/core/node_build.rs diff --git a/README.md b/README.md index 8cec0057d..af09e04ce 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ * Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://rtx.jdx.dev/plugins.html). * Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://rtx.jdx.dev/environments.html) for different project directories. -* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://rtx.jdx.dev/tasks.html) used to build and test projects. +* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://rtx.jdx.dev/tasks/) used to build and test projects. ## 30 Second Demo diff --git a/docs/bun.md b/docs/bun.md index b67b42799..ea7fa4aad 100644 --- a/docs/bun.md +++ b/docs/bun.md @@ -1,18 +1 @@ -# Bun in rtx - -The following are instructions for using the bun rtx core plugin. This is used when there isn't a -git plugin installed named "bun". - -The code for this is inside the rtx repository at -[`./src/plugins/core/bun.rs`](https://github.com/jdx/rtx/blob/main/src/plugins/core/bun.rs). - -## Usage - -The following installs bun and makes it the global default: - -```sh-session -rtx use -g bun@0.7 # install bun 0.7.x -rtx use -g bun@latest # install latest bun -``` - -See available versions with `rtx ls-remote bun`. +See [rtx.jdx.dev](https://rtx.jdx.dev/lang/bun.html) for more information. diff --git a/docs/deno.md b/docs/deno.md index 318811d82..66ff02b78 100644 --- a/docs/deno.md +++ b/docs/deno.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/deno](https://rtx.jdx.dev/lang/deno). +Moved to [rtx.jdx.dev/lang/deno.html](https://rtx.jdx.dev/lang/deno.html). diff --git a/docs/go.md b/docs/go.md index d4f85bfd1..a4addfcf3 100644 --- a/docs/go.md +++ b/docs/go.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/go](https://rtx.jdx.dev/lang/go). +Moved to [rtx.jdx.dev/lang/go.html](https://rtx.jdx.dev/lang/go.html). diff --git a/docs/java.md b/docs/java.md index 654b01708..db5e03536 100644 --- a/docs/java.md +++ b/docs/java.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/java](https://rtx.jdx.dev/lang/java). +Moved to [rtx.jdx.dev/lang/java.html](https://rtx.jdx.dev/lang/java.html). diff --git a/docs/node.md b/docs/node.md index 53798e178..8ec788e9d 100644 --- a/docs/node.md +++ b/docs/node.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/node](https://rtx.jdx.dev/lang/node). +Moved to [rtx.jdx.dev/lang/node.html](https://rtx.jdx.dev/lang/node.html). diff --git a/docs/python.md b/docs/python.md index 74ac71494..ec7694f0f 100644 --- a/docs/python.md +++ b/docs/python.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/python](https://rtx.jdx.dev/lang/python) +Moved to [rtx.jdx.dev/lang/python.html](https://rtx.jdx.dev/lang/python.html) diff --git a/docs/ruby.md b/docs/ruby.md index 3c3459196..3a0fcbd66 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/ruby](https://rtx.jdx.dev/lang/ruby). +Moved to [rtx.jdx.dev/lang/ruby.html](https://rtx.jdx.dev/lang/ruby.html). diff --git a/src/env.rs b/src/env.rs index d63e5c1f0..106665321 100644 --- a/src/env.rs +++ b/src/env.rs @@ -141,10 +141,6 @@ pub static PYENV_ROOT: Lazy = Lazy::new(|| var_path("PYENV_ROOT").unwrap_or_else(|| HOME.join(".pyenv"))); // node -pub static RTX_NODE_BUILD: Lazy> = Lazy::new(|| var_option_bool("RTX_NODE_BUILD")); -pub static RTX_NODE_BUILD_REPO: Lazy = Lazy::new(|| { - var("RTX_NODE_BUILD_REPO").unwrap_or_else(|_| "https://github.com/nodenv/node-build.git".into()) -}); pub static RTX_NODE_MIRROR_URL: Lazy = Lazy::new(|| { var_url("RTX_NODE_MIRROR_URL") .or_else(|| var_url("NODE_BUILD_MIRROR_URL")) @@ -163,8 +159,6 @@ pub static RTX_NODE_CONCURRENCY: Lazy> = Lazy::new(|| { } }) }); -pub static RTX_NODE_VERBOSE_INSTALL: Lazy> = - Lazy::new(|| var_option_bool("RTX_NODE_VERBOSE_INSTALL")); pub static RTX_NODE_MAKE: Lazy = Lazy::new(|| var("RTX_NODE_MAKE").unwrap_or_else(|_| "make".into())); pub static RTX_NODE_NINJA: Lazy = diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 8018f66fa..8ba73761f 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -11,7 +11,6 @@ use once_cell::sync::Lazy; pub use python::PythonPlugin; use crate::cache::CacheManager; -use crate::env::RTX_NODE_BUILD; use crate::http::HTTP_FETCH; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; @@ -19,7 +18,6 @@ use crate::plugins::core::erlang::ErlangPlugin; use crate::plugins::core::go::GoPlugin; 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; use crate::timeout::run_with_timeout; @@ -32,7 +30,6 @@ mod erlang; mod go; mod java; mod node; -mod node_build; mod python; mod ruby; @@ -44,11 +41,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { Arc::new(DenoPlugin::new()), Arc::new(GoPlugin::new()), Arc::new(JavaPlugin::new()), - if *RTX_NODE_BUILD == Some(true) { - Arc::new(NodeBuildPlugin::new()) - } else { - Arc::new(NodePlugin::new()) - }, + Arc::new(NodePlugin::new()), Arc::new(PythonPlugin::new()), Arc::new(RubyPlugin::new()), ]; diff --git a/src/plugins/core/node_build.rs b/src/plugins/core/node_build.rs deleted file mode 100644 index da2a26fa0..000000000 --- a/src/plugins/core/node_build.rs +++ /dev/null @@ -1,295 +0,0 @@ -use std::collections::BTreeMap; -use std::path::{Path, PathBuf}; -use std::process::exit; - -use clap::Command; -use eyre::Result; - -use crate::cmd::CmdLineRunner; -use crate::config::{Config, Settings}; -use crate::duration::DAILY; -use crate::env::{RTX_NODE_COMPILE, RTX_NODE_CONCURRENCY, RTX_NODE_MAKE_OPTS, RTX_NODE_MIRROR_URL}; -use crate::file::create_dir_all; -use crate::git::Git; -use crate::install_context::InstallContext; -use crate::lock_file::LockFile; -use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; -use crate::toolset::{ToolVersion, ToolVersionRequest}; -use crate::ui::progress_report::SingleReport; -use crate::{cmd, env, file}; - -#[derive(Debug)] -pub struct NodeBuildPlugin { - core: CorePlugin, -} - -impl NodeBuildPlugin { - pub fn new() -> Self { - Self { - core: CorePlugin::new("node"), - } - } - - fn node_build_path(&self) -> PathBuf { - self.core.cache_path.join("node-build") - } - fn node_build_bin(&self) -> PathBuf { - self.node_build_path().join("bin/node-build") - } - fn install_or_update_node_build(&self) -> Result<()> { - let _lock = self.lock_node_build(); - if self.node_build_path().exists() { - self.update_node_build() - } else { - self.install_node_build() - } - } - - fn lock_node_build(&self) -> Result { - LockFile::new(&self.node_build_path()) - .with_callback(|l| { - trace!("install_or_update_node_build {}", l.display()); - }) - .lock() - } - fn install_node_build(&self) -> Result<()> { - if self.node_build_path().exists() { - return Ok(()); - } - debug!( - "Installing node-build to {}", - self.node_build_path().display() - ); - create_dir_all(self.node_build_path().parent().unwrap())?; - let git = Git::new(self.node_build_path()); - git.clone(&env::RTX_NODE_BUILD_REPO)?; - Ok(()) - } - fn update_node_build(&self) -> Result<()> { - if self.node_build_recently_updated()? { - return Ok(()); - } - debug!( - "Updating node-build in {}", - self.node_build_path().display() - ); - let git = Git::new(self.node_build_path()); - let node_build_path = self.node_build_path(); - CorePlugin::run_fetch_task_with_timeout(move || { - git.update(None)?; - file::touch_dir(&node_build_path)?; - Ok(()) - }) - } - - fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { - Ok(Some(versions)) => return Ok(versions), - Ok(None) => {} - Err(e) => warn!("failed to fetch remote versions: {}", e), - } - self.install_or_update_node_build()?; - let node_build_bin = self.node_build_bin(); - CorePlugin::run_fetch_task_with_timeout(move || { - let output = cmd!(node_build_bin, "--definitions").read()?; - let versions = output - .split('\n') - .filter(|s| regex!(r"^[0-9].+$").is_match(s)) - .map(|s| s.to_string()) - .collect(); - Ok(versions) - }) - } - - fn node_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("bin/node") - } - - fn npm_path(&self, tv: &ToolVersion) -> PathBuf { - tv.install_path().join("bin/npm") - } - - fn install_default_packages( - &self, - config: &Config, - tv: &ToolVersion, - pr: &dyn SingleReport, - ) -> Result<()> { - let body = file::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); - for package in body.lines() { - let package = package.split('#').next().unwrap_or_default().trim(); - if package.is_empty() { - continue; - } - pr.set_message(format!("installing default package: {}", package)); - let npm = self.npm_path(tv); - CmdLineRunner::new(npm) - .with_pr(pr) - .arg("install") - .arg("--global") - .arg(package) - .envs(&config.env) - .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) - .execute()?; - } - Ok(()) - } - - fn install_npm_shim(&self, tv: &ToolVersion) -> Result<()> { - file::remove_file(self.npm_path(tv)).ok(); - file::write(self.npm_path(tv), include_str!("assets/node_npm_shim"))?; - file::make_executable(&self.npm_path(tv))?; - Ok(()) - } - - fn test_node(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { - pr.set_message("node -v".into()); - CmdLineRunner::new(self.node_path(tv)) - .with_pr(pr) - .arg("-v") - .envs(&config.env) - .execute() - } - - fn test_npm(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { - pr.set_message("npm -v".into()); - CmdLineRunner::new(self.npm_path(tv)) - .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) - .with_pr(pr) - .arg("-v") - .envs(&config.env) - .execute() - } - - fn node_build_recently_updated(&self) -> Result { - let updated_at = file::modified_duration(&self.node_build_path())?; - Ok(updated_at < DAILY) - } - - fn verbose_install(&self) -> bool { - let settings = Settings::get(); - let verbose_env = *env::RTX_NODE_VERBOSE_INSTALL; - verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) - } -} - -impl Plugin for NodeBuildPlugin { - fn name(&self) -> &str { - "node" - } - - fn list_remote_versions(&self) -> Result> { - self.core - .remote_version_cache - .get_or_try_init(|| self.fetch_remote_versions()) - .cloned() - } - - fn get_aliases(&self) -> Result> { - let aliases = [ - ("lts/argon", "4"), - ("lts/boron", "6"), - ("lts/carbon", "8"), - ("lts/dubnium", "10"), - ("lts/erbium", "12"), - ("lts/fermium", "14"), - ("lts/gallium", "16"), - ("lts/hydrogen", "18"), - ("lts/iron", "20"), - ("lts-argon", "4"), - ("lts-boron", "6"), - ("lts-carbon", "8"), - ("lts-dubnium", "10"), - ("lts-erbium", "12"), - ("lts-fermium", "14"), - ("lts-gallium", "16"), - ("lts-hydrogen", "18"), - ("lts-iron", "20"), - ("lts", "20"), - ] - .into_iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect(); - Ok(aliases) - } - - fn legacy_filenames(&self) -> Result> { - Ok(vec![".node-version".into(), ".nvmrc".into()]) - } - - fn parse_legacy_file(&self, path: &Path) -> Result { - let body = file::read_to_string(path)?; - // trim "v" prefix - let body = body.trim().strip_prefix('v').unwrap_or(&body); - // replace lts/* with lts - let body = body.replace("lts/*", "lts"); - Ok(body) - } - - fn external_commands(&self) -> Result> { - // sort of a hack to get this not to display for nodejs - let topic = Command::new("node") - .about("Commands for the node plugin") - .subcommands(vec![Command::new("node-build") - .about("Use/manage rtx's internal node-build") - .arg( - clap::Arg::new("args") - .num_args(1..) - .allow_hyphen_values(true) - .trailing_var_arg(true), - )]); - Ok(vec![topic]) - } - - fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { - match command { - "node-build" => { - self.install_or_update_node_build()?; - cmd::cmd(self.node_build_bin(), args).run()?; - } - _ => unreachable!(), - } - exit(0); - } - - fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { - let config = Config::get(); - self.install_node_build()?; - ctx.pr.set_message("running node-build".into()); - let mut cmd = CmdLineRunner::new(self.node_build_bin()) - .with_pr(ctx.pr.as_ref()) - .env("NODE_BUILD_MIRROR_URL", RTX_NODE_MIRROR_URL.to_string()) - .envs(&config.env) - .arg(ctx.tv.version.as_str()); - if matches!(&ctx.tv.request, ToolVersionRequest::Ref { .. }) || *RTX_NODE_COMPILE { - let mut make_opts = RTX_NODE_MAKE_OPTS.clone().unwrap_or_default(); - if let Some(concurrency) = *RTX_NODE_CONCURRENCY { - make_opts = format!("{} -j{}", make_opts, concurrency); - } - if let Some(node_make_opts) = &*RTX_NODE_MAKE_OPTS { - make_opts = format!("{} {}", make_opts, node_make_opts); - } - cmd = cmd.env("NODE_MAKE_OPTS", make_opts); - if let Some(cflags) = &*env::RTX_NODE_CFLAGS { - cmd = cmd.env("NODE_CFLAGS", cflags); - } - if let Some(node_configure_opts) = &*env::RTX_NODE_CONFIGURE_OPTS { - cmd = cmd.env("NODE_CONFIGURE_OPTS", node_configure_opts); - } - if let Some(make_install_opts) = &*env::RTX_NODE_MAKE_INSTALL_OPTS { - cmd = cmd.env("NODE_MAKE_INSTALL_OPTS", make_install_opts); - } - cmd = cmd.arg("--compile"); - } - if self.verbose_install() { - cmd = cmd.arg("--verbose"); - } - cmd.arg(&ctx.tv.install_path()).execute()?; - self.test_node(&config, &ctx.tv, ctx.pr.as_ref())?; - self.install_npm_shim(&ctx.tv)?; - self.test_npm(&config, &ctx.tv, ctx.pr.as_ref())?; - self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; - Ok(()) - } -} From c1effa330f4803567262af1ad86130537012acab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 31 Dec 2023 15:36:12 -0600 Subject: [PATCH 1476/1891] fixed just release --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4c5127ae4..bd566de5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,7 +126,6 @@ sign-commit = true pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, - { file = "README.md", search = "https://github.com/jdx/rtx/releases/download/v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?/rtx-v[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?", replace = "https://github.com/jdx/rtx/releases/download/v{{version}}/rtx-v{{version}}", exactly = 1 }, { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, ] From adc8160213e55c10b0842a4e68fc223daad27d41 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 31 Dec 2023 15:37:17 -0600 Subject: [PATCH 1477/1891] chore: Release rtx-cli version 2024.0.0 --- Cargo.lock | 66 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3dbfb497..16d27a9b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,9 +183,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" dependencies = [ "memchr", "serde", @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.11" +version = "4.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" dependencies = [ "clap_builder", "clap_derive", @@ -265,9 +265,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.11" +version = "4.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" dependencies = [ "anstream", "anstyle", @@ -304,9 +304,9 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clap_mangen" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3be86020147691e1d2ef58f75346a3d4d94807bfc473e377d52f09f0f7d77f7" +checksum = "10b5db60b3310cdb376fbeb8826e875a38080d0c61bdec0a91a3da8338948736" dependencies = [ "clap", "roff", @@ -552,9 +552,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -1077,9 +1077,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1291,9 +1291,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -1461,12 +1461,12 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177" +checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1603,9 +1603,9 @@ checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "platforms" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" +checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" [[package]] name = "portable-atomic" @@ -1661,9 +1661,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "a293318316cf6478ec1ad2a21c49390a8d5b5eae9fab736467d93fbc0edc29c5" dependencies = [ "unicode-ident", ] @@ -1679,9 +1679,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" dependencies = [ "proc-macro2", ] @@ -1875,7 +1875,7 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rtx-cli" -version = "2023.12.40" +version = "2024.0.0" dependencies = [ "base64", "built", @@ -2223,9 +2223,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597" +checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" [[package]] name = "simplelog" @@ -2447,18 +2447,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" +checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" +checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" dependencies = [ "proc-macro2", "quote", @@ -2984,11 +2984,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bd566de5e..35e2e8a3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rtx-cli" -version = "2023.12.40" +version = "2024.0.0" edition = "2021" description = "Polyglot runtime manager (asdf rust clone)" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index af09e04ce..c0f486c87 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Install rtx on macOS (other methods [here](https://rtx.jdx.dev/getting-started.h ```sh-session $ curl https://rtx.jdx.dev/install.sh | sh $ ~/.local/share/rtx/bin/rtx --version -rtx 2023.12.40 +rtx 2024.0.0 ``` Hook rtx into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 3b2e4c2cc..a1bf26534 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "rtx"; - version = "2023.12.40"; + version = "2024.0.0"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index ca36b33f3..73e42a7c4 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,6 +1,6 @@ Summary: Polyglot runtime manager Name: rtx -Version: 2023.12.40 +Version: 2024.0.0 Release: 1 URL: https://github.com/jdx/rtx/ Group: System From 8d98b9158b6dc4d6c36332a5f52061e81cc87d91 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 31 Dec 2023 15:57:57 -0600 Subject: [PATCH 1478/1891] env-vars: added "ev" alias --- src/cli/env_vars.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index 15b93f984..b326d7e0f 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -14,7 +14,7 @@ use super::args::env_var::{EnvVarArg, EnvVarArgParser}; /// By default this command modifies ".rtx.toml" in the current directory. /// You can specify the file name by either setting the RTX_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment)] +#[clap(visible_alias = "ev", verbatim_doc_comment)] pub struct EnvVars { /// The TOML file to update /// From 4bfe580eef8a8192f621ea729c8013ef141dacf3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 31 Dec 2023 15:58:12 -0600 Subject: [PATCH 1479/1891] env-vars: added "ev" alias --- completions/_rtx | 4 ++-- completions/rtx.bash | 3 +++ docs/cli-reference.md | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/completions/_rtx b/completions/_rtx index 379a11dfa..34f6aebd0 100644 --- a/completions/_rtx +++ b/completions/_rtx @@ -28,7 +28,7 @@ _rtx() { (direnv) __rtx_direnv_cmd && ret=0 ;; (doctor) __rtx_doctor_cmd && ret=0 ;; (e|env) __rtx_env_cmd && ret=0 ;; - (env-vars) __rtx_env_vars_cmd && ret=0 ;; + (ev|env-vars) __rtx_env_vars_cmd && ret=0 ;; (x|exec) __rtx_exec_cmd && ret=0 ;; (g|global) __rtx_global_cmd && ret=0 ;; (hook-env) __rtx_hook_env_cmd && ret=0 ;; @@ -893,7 +893,7 @@ __rtx_cmds() { 'direnv:Output direnv function to use rtx inside direnv' 'doctor:Check rtx installation for possible problems.' {e,env}':Exports env vars to activate rtx a single time' - 'env-vars:Manage environment variables' + {ev,env-vars}':Manage environment variables' {x,exec}':Execute a command with tool(s) set' 'implode:Removes rtx CLI and all related data' {i,install}':Install a tool version' diff --git a/completions/rtx.bash b/completions/rtx.bash index cb65510d5..00ae8d630 100644 --- a/completions/rtx.bash +++ b/completions/rtx.bash @@ -60,6 +60,9 @@ _rtx() { rtx,env-vars) cmd="rtx__env__vars" ;; + rtx,ev) + cmd="rtx__env__vars" + ;; rtx,exec) cmd="rtx__exec" ;; diff --git a/docs/cli-reference.md b/docs/cli-reference.md index a55d232d0..ffe9720e1 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -328,6 +328,8 @@ Examples: ### `rtx env-vars [OPTIONS] [ENV_VARS]...` +**Aliases:** `ev` + ```text Manage environment variables From 484806fd980d6c39aaa76e4066b18f54edd35137 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 1 Jan 2024 11:53:46 -0600 Subject: [PATCH 1480/1891] env: added RTX_ENV_FILE config (#1305) This lets you set RTX_ENV_FILE=.env in order to always import a local env file if one exists. --- e2e/.test-env2 | 1 + e2e/test_env | 1 + ...cli__settings__ls__tests__settings_ls.snap | 1 + ...i__settings__set__tests__settings_set.snap | 1 + src/cli/settings/unset.rs | 1 + ...__config_file__rtx_toml__tests__env-5.snap | 1 + ...nfig_file__rtx_toml__tests__fixture-2.snap | 1 + ...nfig_file__rtx_toml__tests__fixture-6.snap | 1 + ...ig_file__rtx_toml__tests__path_dirs-5.snap | 1 + ...file__rtx_toml__tests__remove_alias-4.snap | 1 + ...ile__rtx_toml__tests__remove_plugin-4.snap | 1 + ...__rtx_toml__tests__replace_versions-4.snap | 1 + src/config/mod.rs | 22 +++++++++++++++++-- src/config/settings.rs | 2 ++ 14 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 e2e/.test-env2 diff --git a/e2e/.test-env2 b/e2e/.test-env2 new file mode 100644 index 000000000..ffc50a82a --- /dev/null +++ b/e2e/.test-env2 @@ -0,0 +1 @@ +TEST_ENV2=foo diff --git a/e2e/test_env b/e2e/test_env index 77f320441..4d9dd3629 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -10,3 +10,4 @@ rtx i node@18.0.0 eval "$(rtx env -s bash node@18.0.0)" assert "node -v" "v18.0.0" assert "rtx x -- env | grep FOO_FROM_FILE" "FOO_FROM_FILE=foo_from_file" +RTX_ENV_FILE=.test-env2 assert "rtx x -- env | grep TEST_ENV2" "TEST_ENV2=foo" diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap index 00d01cd1a..0f5f06aa7 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap @@ -8,6 +8,7 @@ asdf_compat = false color = true disable_default_shorthands = false disable_tools = [] +env_file = null experimental = true jobs = 2 legacy_version_file = true diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap index 1b8a3ef78..4a5b53cc0 100644 --- a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap +++ b/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap @@ -8,6 +8,7 @@ asdf_compat = false color = true disable_default_shorthands = false disable_tools = [] +env_file = null experimental = true jobs = 2 legacy_version_file = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index b84a44f26..4561b50b5 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -46,6 +46,7 @@ mod tests { color = true disable_default_shorthands = false disable_tools = [] + env_file = null experimental = true jobs = 2 legacy_version_file = true diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap index 2737c4128..f7b8a0c72 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap @@ -13,6 +13,7 @@ RtxToml(/tmp/.rtx.toml): { "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, + "env_file": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap index e65f4a962..aed7a5ce4 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap @@ -30,5 +30,6 @@ expression: cf.settings().unwrap() "task_output": null, "not_found_auto_install": null, "ci": null, + "env_file": null, "cd": null } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap index b4c0c2c97..73fa61186 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap @@ -15,6 +15,7 @@ RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref: "disable_tools": Array [ String("disabled_tool"), ], + "env_file": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap index 7b26e59d7..2af5c6c37 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap @@ -13,6 +13,7 @@ RtxToml(~/fixtures/.rtx.toml): { "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, + "env_file": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap index 77cd0f6ac..985c19094 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap @@ -13,6 +13,7 @@ RtxToml(/tmp/.rtx.toml): { "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, + "env_file": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap index 506ca353f..efa54ab41 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap @@ -13,6 +13,7 @@ RtxToml(/tmp/.rtx.toml): { "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, + "env_file": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap index 6a95fc58b..44f34f4ae 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap @@ -13,6 +13,7 @@ RtxToml(/tmp/.rtx.toml): node@16.0.1 node@18.0.1 { "debug": Null, "disable_default_shorthands": Null, "disable_tools": Null, + "env_file": Null, "experimental": Null, "jobs": Null, "legacy_version_file": Null, diff --git a/src/config/mod.rs b/src/config/mod.rs index 419b9d122..d2e02a862 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -81,7 +81,7 @@ impl Config { let config_paths = load_config_paths(&config_filenames); let config_files = load_all_config_files(&config_paths, &plugins, &legacy_files)?; - let (env, env_sources) = load_env(&config_files); + let (env, env_sources) = load_env(&settings, &config_files); let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); let config = Self { @@ -467,7 +467,10 @@ fn parse_config_file( } } -fn load_env(config_files: &ConfigMap) -> (BTreeMap, HashMap) { +fn load_env( + settings: &Settings, + config_files: &ConfigMap, +) -> (BTreeMap, HashMap) { let mut env = BTreeMap::new(); let mut env_sources = HashMap::new(); for (source, cf) in config_files.iter().rev() { @@ -480,6 +483,21 @@ fn load_env(config_files: &ConfigMap) -> (BTreeMap, HashMap { + for item in iter { + let (k, v) = item.unwrap_or_else(|err| { + warn!("env_file: {err}"); + Default::default() + }); + env.insert(k.clone(), v); + env_sources.insert(k, env_file.clone()); + } + } + Err(err) => trace!("env_file: {err}"), + } + } (env, env_sources) } diff --git a/src/config/settings.rs b/src/config/settings.rs index d2bcbe141..0bb3f907a 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -62,6 +62,8 @@ pub struct Settings { pub not_found_auto_install: bool, #[config(env = "CI", default = false)] pub ci: bool, + #[config(env = "RTX_ENV_FILE")] + pub env_file: Option, pub cd: Option, } From 0737393b7b167fd57d168dfbf886405bb0a8cecb Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 1 Jan 2024 19:15:10 -0600 Subject: [PATCH 1481/1891] Update CONTRIBUTING.md --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a885cbef..f664e34f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,8 @@ # Contributing +Before submitting a PR, unless it's something obvious, consider filing an issue or simply mention what you plan to do in the [Discord](https://discord.gg/UBa7pJUN7Z). +PRs are often either rejected or need to change significantly after submission so make sure before you start working on something it won't be a wasted effort. + ## Development Container The directory `.devcontainer` contains a Dockerfile that can be used to build a container for local development. This is useful if you want to use a [GitHub Codespace](https://docs.github.com/codespaces), VSCode's remote container feature or a standalone container to develop rtx. To use it, you'll need to have Docker Desktop installed and running. From 0f980b22382b4da002336f6b456d5181416bf75b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 20:40:53 -0600 Subject: [PATCH 1482/1891] chore: Configure Renovate (#1307) * Add renovate.json * [MegaLinter] Apply linters fixes --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: renovate[bot] --- renovate.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 000000000..22a994324 --- /dev/null +++ b/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"] +} From 83f208852f67504727e57187aa5c16d6a4f2e883 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 02:47:05 +0000 Subject: [PATCH 1483/1891] fix(deps): update rust crate indexmap to 2.1 (#1308) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 35e2e8a3a..ce1810217 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ fslock = "0.2" globwalk = "0.9.0" humantime = "2.1" indenter = "0.3" -indexmap = { version = "2.0", features = ["serde"] } +indexmap = { version = "2.1", features = ["serde"] } indicatif = { version = "0.17", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.12" From 92b664e9d70803243c2ed70882052b113196abf8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 02:47:25 +0000 Subject: [PATCH 1484/1891] fix(deps): update rust crate num_cpus to 1.16 (#1309) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ce1810217..7b6b69686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ indicatif = { version = "0.17", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.12" log = "0.4" -num_cpus = "1.14" +num_cpus = "1.16" once_cell = "1.18" openssl = { version = "0.10", optional = true } path-absolutize = "3.1" From 4fbb420ca159030fcee17d0a6890d0b532042e49 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 02:56:02 +0000 Subject: [PATCH 1485/1891] fix(deps): update rust crate once_cell to 1.19 (#1311) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7b6b69686..c25a6968e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ indoc = "<3" itertools = "0.12" log = "0.4" num_cpus = "1.16" -once_cell = "1.18" +once_cell = "1.19" openssl = { version = "0.10", optional = true } path-absolutize = "3.1" rand = "0.8" From d2458e7f34ed1c899e950b18458cf437ffcd7c49 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 02:56:21 +0000 Subject: [PATCH 1486/1891] fix(deps): update rust crate regex to 1.10 (#1312) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c25a6968e..fb394023d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ openssl = { version = "0.10", optional = true } path-absolutize = "3.1" rand = "0.8" rayon = "1.8" -regex = "1.9" +regex = "1.10" reqwest = { version = "0.11.17", default-features = false, features = ["blocking", "json", "gzip"] } rmp-serde = "1.1.2" petgraph = "0.6.4" From 4884e233c623c5ffa489373282dceac93e4f3f89 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 02:56:42 +0000 Subject: [PATCH 1487/1891] fix(deps): update rust crate url to 2.5 (#1315) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fb394023d..f16e1815e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ terminal_size = "0.3" thiserror = "1.0" toml = "<1" toml_edit = "<1" -url = "2.4" +url = "2.5" versions = "6" which = "5" zip = { version = "0.6", default-features = false, features = ["deflate"] } From 43b37bc2296460e8b222ab0cbb815ac457717074 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 1 Jan 2024 20:57:12 -0600 Subject: [PATCH 1488/1891] consistent dependency versions --- Cargo.toml | 60 +++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f16e1815e..ea88e65e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,66 +38,66 @@ path = "src/main.rs" lto = true [dependencies] -base64 = "<0.22" +base64 = "0.21" chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } -clap = { version = "4.4", features = ["env", "derive", "string"] } +clap = { version = "4", features = ["env", "derive", "string"] } clap_complete = { version = "4", optional = true } clap_mangen = { version = "0.2", optional = true } color-eyre = "0.6" color-print = "0.3" confique = { version = "0.2", default-features = false } console = "0.15" -ctrlc = "3.4" +ctrlc = "3" demand = "0.3" -dirs-next = "2.0" +dirs-next = "2" dotenvy = "0.15" duct = "0.13" -either = "1.9.0" +either = "1" eyre = "0.6" filetime = "0.2" -flate2 = "1.0" +flate2 = "1" fslock = "0.2" -globwalk = "0.9.0" -humantime = "2.1" +globwalk = "0.9" +humantime = "2" indenter = "0.3" -indexmap = { version = "2.1", features = ["serde"] } +indexmap = { version = "2", features = ["serde"] } indicatif = { version = "0.17", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.12" log = "0.4" -num_cpus = "1.16" -once_cell = "1.19" +num_cpus = "1" +once_cell = "1" openssl = { version = "0.10", optional = true } -path-absolutize = "3.1" +path-absolutize = "3" rand = "0.8" -rayon = "1.8" -regex = "1.10" -reqwest = { version = "0.11.17", default-features = false, features = ["blocking", "json", "gzip"] } -rmp-serde = "1.1.2" -petgraph = "0.6.4" -self_update = { version = "<1", default-features = false, features = [ +rayon = "1" +regex = "1" +reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "gzip"] } +rmp-serde = "1" +petgraph = "0.6" +self_update = { version = "0.39", default-features = false, features = [ "archive-tar", "compression-flate2", "signatures", ] } -serde = "1.0" -serde_derive = "1.0" -serde_json = { version = "1.0", features = [] } +serde = "1" +serde_derive = "1" +serde_json = { version = "1", features = [] } sha2 = "0.10" shell-escape = "0.1" -shell-words = "1.1" +shell-words = "1" simplelog = { version = "0.12" } -strum = { version = "0.25.0", features = ["derive"] } +strum = { version = "0.25", features = ["derive"] } sys-info = "0.9" tabled = { version = "0.15", features = ["ansi"] } tar = "0.4" -tempfile = "3.8.1" -tera = { version = "1.19", default-features = false } +tempfile = "3" +tera = { version = "1", default-features = false } terminal_size = "0.3" -thiserror = "1.0" -toml = "<1" -toml_edit = "<1" -url = "2.5" +thiserror = "1" +toml = "0.8" +toml_edit = "0.21" +url = "2" versions = "6" which = "5" zip = { version = "0.6", default-features = false, features = ["deflate"] } @@ -109,7 +109,7 @@ exec = "0.3" built = { version = "0.7", features = ["chrono", "git2"] } [dev-dependencies] -ctor = "<0.3" +ctor = "0.2" insta = { version = "1", features = ["filters", "json"] } pretty_assertions = "1" From b2fe4802289fc42f8339922541b683d7365cc6b8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 02:59:27 +0000 Subject: [PATCH 1489/1891] chore(deps): update actions/upload-artifact action to v4 (#1320) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/mega-linter.yml | 2 +- .github/workflows/release.yml | 6 +++--- .github/workflows/test-plugins.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index 41dd24565..a1f214b2d 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -90,7 +90,7 @@ jobs: # Upload MegaLinter artifacts - name: Archive production artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: success() || failure() with: name: MegaLinter reports diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff7643445..3f8d5b0d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -84,7 +84,7 @@ jobs: env: ZIPSIGN: ${{ secrets.ZIPSIGN }} - run: scripts/build-tarball.sh rtx --release --features openssl/vendored --target ${{matrix.target}} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: tarball-${{matrix.target}} path: | @@ -143,7 +143,7 @@ jobs: name: tarball-aarch64-unknown-linux-gnu path: dist - run: scripts/build-rpm.sh - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: rpm path: dist/rpmrepo @@ -167,7 +167,7 @@ jobs: name: tarball-aarch64-unknown-linux-gnu path: dist - run: scripts/build-deb.sh - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: deb path: dist/deb diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 155dd7964..31a152934 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -29,7 +29,7 @@ jobs: shared-key: "build-linux-x86_64-unknown-linux-gnu" save-if: false - run: scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu path: | From 1d0bd4840f85897b2af5eacb703723073802834c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 20:59:45 -0600 Subject: [PATCH 1490/1891] chore(deps): update actions/download-artifact action to v4 (#1319) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 12 ++++++------ .github/workflows/test-plugins.yml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f8d5b0d2..11e133613 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,7 +105,7 @@ jobs: - uses: actions/checkout@v4 - name: Install zsh/fish/direnv run: sudo apt-get update; sudo apt-get install zsh fish direnv - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu path: dist @@ -134,11 +134,11 @@ jobs: - uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_KEY }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: tarball-aarch64-unknown-linux-gnu path: dist @@ -158,11 +158,11 @@ jobs: - uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_KEY }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: tarball-aarch64-unknown-linux-gnu path: dist @@ -213,7 +213,7 @@ jobs: git_user_signingkey: true git_commit_gpgsign: true workdir: homebrew-tap - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: { path: artifacts } - run: rtx/scripts/release.sh env: diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 31a152934..310a480dc 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -93,7 +93,7 @@ jobs: steps: - name: apt-get run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl4-openssl-dev libgd-dev libonig-dev autoconf bison build-essential curl gettext git libgd-dev libcurl4-openssl-dev libedit-dev libicu-dev libjpeg-dev libmysqlclient-dev libonig-dev libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libxml2-dev libzip-dev openssl pkg-config re2c zlib1g-dev libwxgtk-webview3.0-gtk3-dev - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu path: dist @@ -175,7 +175,7 @@ jobs: steps: - name: Install zsh/fish/direnv run: sudo apt-get update; sudo apt-get install zsh fish direnv - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu path: dist From 88f8c838668a99bba12145dc25973fdcdaf2c4e0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 03:00:00 +0000 Subject: [PATCH 1491/1891] chore(deps): update fedora docker tag to v40 (#1322) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packaging/rpm/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpm/Dockerfile b/packaging/rpm/Dockerfile index 15d63e8f4..30feefff1 100644 --- a/packaging/rpm/Dockerfile +++ b/packaging/rpm/Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:38 +FROM fedora:40 LABEL maintainer="jdx" RUN dnf install -y rpm-build rpm-sign ruby ruby-devel gcc \ From 22efd8dffbf126c25e70cc0a953b916cb21beb26 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 03:00:35 +0000 Subject: [PATCH 1492/1891] chore(deps): update mcr.microsoft.com/devcontainers/rust docker tag to v1 (#1323) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 9218d4a55..443372343 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/rust:0-1-bullseye +FROM mcr.microsoft.com/devcontainers/rust:1-1-bullseye SHELL ["/bin/bash", "-o", "pipefail", "-c"] WORKDIR /workspaces/cached From 7078db0243189a4325f2cdcd1910290dc9048ff4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 03:01:32 +0000 Subject: [PATCH 1493/1891] chore(deps): update stefanzweifel/git-auto-commit-action action to v5 (#1324) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/mega-linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index a1f214b2d..f891d1676 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -157,7 +157,7 @@ jobs: run: sudo chown -Rc $UID .git/ - name: Commit and push applied linter fixes - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 if: >- steps.ml.outputs.has_updated_sources == 1 && ( From acc9a6803d6d3087a847529baa7d7e341ef46cc2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:01:54 -0600 Subject: [PATCH 1494/1891] renovate: ignore asdf/nodejs --- renovate.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 22a994324..31fc1be15 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,10 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["config:recommended"] + "extends": ["config:recommended"], + "asdf": { + "enabled": false + }, + "nodejs": { + "enabled": false + } } From b04ae5ca195e5ff0dbc47becb5da0a5958a85ac7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:02:12 -0600 Subject: [PATCH 1495/1891] chore(deps): update actions/checkout action to v4 (#1318) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/mega-linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index f891d1676..7c8d96456 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -49,7 +49,7 @@ jobs: steps: # Git Checkout - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} From 4d921c7608e4807ae765383253e100763d04bd75 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:06:40 -0600 Subject: [PATCH 1496/1891] renovate: ignore nodenv --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 31fc1be15..e6136dad4 100644 --- a/renovate.json +++ b/renovate.json @@ -4,7 +4,7 @@ "asdf": { "enabled": false }, - "nodejs": { + "nodenv": { "enabled": false } } From 4361f0385a82da470cfe47a5044a00ca783c9ddc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:26:48 -0600 Subject: [PATCH 1497/1891] renovate: tuck away --- renovate.json => .github/renovate.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename renovate.json => .github/renovate.json (100%) diff --git a/renovate.json b/.github/renovate.json similarity index 100% rename from renovate.json rename to .github/renovate.json From 2c569fc01a77987e6823dc749eb917f1fe5a0cf0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:39:17 -0600 Subject: [PATCH 1498/1891] renovate: disable dashboard --- .github/renovate.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json b/.github/renovate.json index e6136dad4..d624c7512 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,6 +1,7 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:recommended"], + "dependabotCompatibility": false, "asdf": { "enabled": false }, From e00fb1fde649ecc85aa40ac8846f71316d679e54 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:44:43 -0600 Subject: [PATCH 1499/1891] ci: disable auto package updates --- scripts/pre-release-hook.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 4e051d9ad..e922bc9c8 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -3,8 +3,8 @@ set -euxo pipefail if [[ "${NO_UPDATE:-}" == "1" ]]; then echo "NO_UPDATE is set, skipping update" -else - cargo update && git add Cargo.lock +# else +# cargo update && git add Cargo.lock fi just render-mangen render-help From 400ac0a0ff64cf5a6846f662df5dc432237e87b2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:54:36 -0600 Subject: [PATCH 1500/1891] renovate: disable dashboard --- .github/renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json b/.github/renovate.json index d624c7512..9eb15d45a 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,7 +1,7 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:recommended"], - "dependabotCompatibility": false, + "dependencyDashboard": false, "asdf": { "enabled": false }, From 83c0ffcf210c51228f82e9eb586d09a5ea7933f4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 09:54:43 -0600 Subject: [PATCH 1501/1891] updated description --- Cargo.toml | 2 +- default.nix | 2 +- packaging/rpm/rtx.spec | 2 +- scripts/build-deb.sh | 4 ++-- scripts/build-rpm.sh | 4 ++-- scripts/release-aur-bin.sh | 4 ++-- scripts/release-aur.sh | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ea88e65e0..b2bf7d2f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rtx-cli" version = "2024.0.0" edition = "2021" -description = "Polyglot runtime manager (asdf rust clone)" +description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] homepage = "https://rtx.jdx.dev" documentation = "https://rtx.jdx.dev" diff --git a/default.nix b/default.nix index a1bf26534..15b0bdaa3 100644 --- a/default.nix +++ b/default.nix @@ -50,7 +50,7 @@ rustPlatform.buildRustPackage { OPENSSL_DIR = "${libssl}"; meta = with lib; { - description = "Polyglot runtime manager (asdf rust clone)"; + description = "The front-end to your dev env"; homepage = "https://github.com/jdx/rtx"; license = licenses.mit; }; diff --git a/packaging/rpm/rtx.spec b/packaging/rpm/rtx.spec index 73e42a7c4..d4b9326d1 100644 --- a/packaging/rpm/rtx.spec +++ b/packaging/rpm/rtx.spec @@ -1,4 +1,4 @@ -Summary: Polyglot runtime manager +Summary: The front-end to your dev env Name: rtx Version: 2024.0.0 Release: 1 diff --git a/scripts/build-deb.sh b/scripts/build-deb.sh index dca75d3c7..9f79783a0 100755 --- a/scripts/build-deb.sh +++ b/scripts/build-deb.sh @@ -12,7 +12,7 @@ fpm -s dir -t deb \ --license MIT \ --version "${RTX_VERSION#v*}" \ --architecture amd64 \ - --description "Polyglot runtime manager" \ + --description "The front-end to your dev env" \ --url "https://github.com/jdx/rtx" \ --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ @@ -25,7 +25,7 @@ fpm -s dir -t deb \ --license MIT \ --version "${RTX_VERSION#v*}" \ --architecture arm64 \ - --description "Polyglot runtime manager" \ + --description "The front-end to your dev env" \ --url "https://github.com/jdx/rtx" \ --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ diff --git a/scripts/build-rpm.sh b/scripts/build-rpm.sh index 5ae865985..55ff70e83 100755 --- a/scripts/build-rpm.sh +++ b/scripts/build-rpm.sh @@ -12,7 +12,7 @@ fpm -s dir -t rpm \ --license MIT \ --version "${RTX_VERSION#v*}" \ --architecture x86_64 \ - --description "Polyglot runtime manager" \ + --description "The front-end to your dev env" \ --url "https://github.com/jdx/rtx" \ --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ @@ -25,7 +25,7 @@ fpm -s dir -t rpm \ --license MIT \ --version "${RTX_VERSION#v*}" \ --architecture aarch64 \ - --description "Polyglot runtime manager" \ + --description "The front-end to your dev env" \ --url "https://github.com/jdx/rtx" \ --maintainer "Jeff Dickey @jdx" \ rtx/bin/rtx=/usr/bin/rtx \ diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index c5edf9999..44fe56bfa 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -18,7 +18,7 @@ cat >aur-bin/PKGBUILD <aur-bin/.SRCINFO <aur/PKGBUILD <aur/.SRCINFO < Date: Tue, 2 Jan 2024 09:53:50 -0600 Subject: [PATCH 1502/1891] rtx -> mise --- .github/ISSUE_TEMPLATE/bug_report.md | 4 +- .github/workflows/docker.yml | 10 +- .github/workflows/mega-linter.yml | 4 + .github/workflows/release.yml | 30 +- .github/workflows/test-plugins.yml | 72 +- .github/workflows/test.yml | 13 +- .mise.dev.toml | 2 + .rtx.local.toml => .mise.local.toml | 4 +- .rtx.toml => .mise.toml | 28 +- {.rtx => .mise}/config.toml | 0 .mise/tasks/filetask | 12 + .rtx.dev.toml | 2 - .rtx/tasks/filetask | 12 - CONTRIBUTING.md | 40 +- Cargo.lock | 140 +- Cargo.toml | 28 +- Dockerfile | 2 +- README.md | 48 +- SECURITY.md | 36 +- completions/{_rtx => _mise} | 670 ++++----- completions/{rtx.bash => mise.bash} | 1282 ++++++++--------- completions/mise.fish | 408 ++++++ completions/rtx.fish | 408 ------ default.nix | 4 +- docs/bun.md | 2 +- docs/cli-reference.md | 572 ++++---- docs/demo.sh | 4 +- docs/demo.tape | 16 +- docs/deno.md | 2 +- docs/go.md | 2 +- docs/java.md | 2 +- docs/node.md | 2 +- docs/python.md | 2 +- docs/ruby.md | 2 +- e2e/.gitignore | 2 +- e2e/{.rtx => .mise}/tasks/build | 0 e2e/.mise/tasks/filetask | 13 + e2e/.rtx/tasks/filetask | 13 - e2e/cd/test_bash | 20 +- e2e/cd/test_bash_legacy_activate | 14 +- e2e/cd/test_fish | 14 +- e2e/cd/test_zsh | 16 +- e2e/config/{.e2e.rtx.toml => .e2e.mise.toml} | 2 +- .../cd/.e2e.mise.toml} | 0 e2e/config/cd/.e2e.rtx.toml | 2 - .../cd/18/.e2e.mise.toml} | 0 e2e/config/cd/18/.e2e.rtx.toml | 2 - e2e/config/pyproject.toml | 2 +- e2e/direnv/no_tool_versions/test_direnv | 20 +- .../load-first/.e2e-tool-versions | 0 .../load-first/.envrc | 0 .../system_version/test_direnv_system_version | 34 +- e2e/gopath/test_gopath | 18 +- e2e/ruby/test_ruby | 10 +- e2e/ruby/test_ruby_install | 10 +- e2e/run_all_tests | 2 +- e2e/run_test | 24 +- e2e/test_bang | 18 +- e2e/test_bun | 6 +- e2e/test_deno | 6 +- e2e/test_doctor | 6 +- e2e/test_env | 12 +- e2e/test_erlang | 4 +- e2e/test_exec | 6 +- e2e/test_go | 14 +- e2e/test_install | 6 +- e2e/test_java | 8 +- e2e/test_link | 10 +- e2e/test_local | 46 +- e2e/test_log_level | 8 +- e2e/test_ls_remote | 6 +- e2e/test_neovim | 4 +- e2e/test_nodejs | 44 +- e2e/test_plugins_install | 44 +- e2e/test_poetry | 14 +- e2e/test_purge | 16 +- e2e/test_python | 8 +- e2e/test_raw | 4 +- e2e/test_run | 4 +- e2e/test_shell | 8 +- e2e/test_shims | 8 +- e2e/test_system | 8 +- e2e/test_tiny | 36 +- e2e/test_tool_versions_alt | 24 +- e2e/test_top_runtimes | 38 +- e2e/test_uninstall | 30 +- e2e/test_upgrade | 22 +- e2e/test_use | 24 +- e2e/test_zigmod | 6 +- flake.nix | 12 +- justfile | 24 +- man/man1/{rtx.1 => mise.1} | 14 +- packaging/deb/generate-release.sh | 6 +- packaging/homebrew/homebrew.rb | 45 - packaging/{rtx => mise}/Dockerfile | 22 +- packaging/rpm/mise.repo | 6 + packaging/rpm/mise.spec | 21 + packaging/rpm/rpmmacros | 2 +- packaging/rpm/rtx.repo | 6 - packaging/rpm/rtx.spec | 21 - packaging/standalone/install.envsubst | 56 +- schema/{rtx.json => mise.json} | 18 +- schema/{rtx.plugin.json => mise.plugin.json} | 6 +- scripts/build-deb.sh | 38 +- scripts/build-rpm.sh | 38 +- scripts/build-tarball.sh | 24 +- scripts/publish-r2.sh | 4 +- scripts/publish-s3.sh | 10 +- scripts/release-alpine.sh | 10 +- scripts/release-aur-bin.sh | 54 +- scripts/release-aur.sh | 46 +- scripts/release-npm.sh | 28 +- scripts/release.sh | 68 +- scripts/render-homebrew.sh | 26 +- scripts/render-install.sh | 24 +- scripts/setup-zipsign.sh | 2 +- scripts/test-standalone.sh | 14 +- share/fish/vendor_conf.d/mise-activate.fish | 3 + share/fish/vendor_conf.d/rtx-activate.fish | 3 - src/cli/activate.rs | 30 +- src/cli/alias/get.rs | 6 +- src/cli/alias/ls.rs | 6 +- src/cli/alias/set.rs | 4 +- src/cli/alias/unset.rs | 4 +- src/cli/args/tool.rs | 4 +- src/cli/asdf.rs | 8 +- src/cli/bin_paths.rs | 2 +- src/cli/cache/clear.rs | 6 +- src/cli/cache/mod.rs | 8 +- src/cli/completion.rs | 14 +- src/cli/config/generate.rs | 26 +- src/cli/config/ls.rs | 4 +- ...i__config__generate__tests__generate.snap} | 18 +- src/cli/current.rs | 18 +- src/cli/deactivate.rs | 28 +- src/cli/direnv/activate.rs | 18 +- src/cli/direnv/envrc.rs | 4 +- src/cli/direnv/exec.rs | 2 +- src/cli/direnv/mod.rs | 4 +- ...__direnv__envrc__tests__direnv_envrc.snap} | 0 src/cli/doctor.rs | 52 +- src/cli/env.rs | 18 +- src/cli/env_vars.rs | 40 +- src/cli/exec.rs | 16 +- src/cli/global.rs | 26 +- src/cli/hook_env.rs | 18 +- src/cli/implode.rs | 6 +- src/cli/install.rs | 20 +- src/cli/latest.rs | 6 +- src/cli/link.rs | 14 +- src/cli/local.rs | 54 +- src/cli/ls.rs | 36 +- src/cli/ls_remote.rs | 12 +- src/cli/mod.rs | 22 +- src/cli/outdated.rs | 8 +- src/cli/plugins/install.rs | 17 +- src/cli/plugins/link.rs | 11 +- src/cli/plugins/ls.rs | 10 +- src/cli/plugins/ls_remote.rs | 6 +- src/cli/plugins/mod.rs | 2 +- ...l__tests__plugin_install_invalid_url.snap} | 0 ...cli__plugins__ls__tests__plugin_list.snap} | 0 ..._plugins__ls__tests__plugin_list_all.snap} | 0 src/cli/plugins/uninstall.rs | 2 +- src/cli/plugins/update.rs | 6 +- src/cli/prune.rs | 12 +- src/cli/render_completion.rs | 4 +- src/cli/render_help.rs | 12 +- src/cli/render_mangen.rs | 6 +- src/cli/reshim.rs | 16 +- src/cli/run.rs | 38 +- src/cli/self_update.rs | 22 +- src/cli/settings/get.rs | 8 +- src/cli/settings/ls.rs | 8 +- src/cli/settings/set.rs | 4 +- ...li__settings__ls__tests__settings_ls.snap} | 0 ...__settings__set__tests__settings_set.snap} | 0 src/cli/settings/unset.rs | 4 +- src/cli/shell.rs | 22 +- ..._cli__asdf__tests__fake_asdf_install.snap} | 0 ...__cli__asdf__tests__fake_asdf_reshim.snap} | 0 ..._cli__deactivate__tests__deactivate-2.snap | 10 + ...e__cli__deactivate__tests__deactivate.snap | 7 + ...p => mise__cli__env__tests__env_json.snap} | 0 ...se__cli__env_vars__tests__env_vars-2.snap} | 0 ...mise__cli__env_vars__tests__env_vars.snap} | 0 ...__env_vars__tests__env_vars_remove-2.snap} | 0 ...li__env_vars__tests__env_vars_remove.snap} | 0 ..._cli__env_vars__tests__show_env_vars.snap} | 0 ...=> mise__cli__exec__tests__exec_fail.snap} | 0 ...> mise__cli__global__tests__global-2.snap} | 2 +- ...> mise__cli__global__tests__global-3.snap} | 2 +- ...> mise__cli__global__tests__global-4.snap} | 2 +- ...> mise__cli__global__tests__global-5.snap} | 0 ...> mise__cli__global__tests__global-6.snap} | 0 ... => mise__cli__global__tests__global.snap} | 2 +- ...cli__install__tests__install_nothing.snap} | 0 ...__install__tests__install_with_alias.snap} | 0 ... => mise__cli__latest__tests__latest.snap} | 0 ...i__latest__tests__latest_asdf_format.snap} | 0 ...cli__latest__tests__latest_installed.snap} | 0 ...latest__tests__latest_missing_plugin.snap} | 0 ...e__cli__latest__tests__latest_system.snap} | 0 ...li__local__tests__local_alias_prefix.snap} | 0 ...__cli__local__tests__local_alias_ref.snap} | 0 ...li__local__tests__local_alias_system.snap} | 0 ...al__tests__local_multiple_versions-2.snap} | 2 +- ...al__tests__local_multiple_versions-3.snap} | 0 ...ocal__tests__local_multiple_versions.snap} | 0 ...e__cli__local__tests__local_remove-2.snap} | 2 +- ...e__cli__local__tests__local_remove-3.snap} | 2 +- ...ise__cli__local__tests__local_remove.snap} | 2 +- ...p => mise__cli__ls__tests__ls_json-2.snap} | 0 ...nap => mise__cli__ls__tests__ls_json.snap} | 0 ...__cli__ls_remote__tests__list_remote.snap} | 0 ...ls_remote__tests__ls_remote_prefix-2.snap} | 0 ...__ls_remote__tests__ls_remote_prefix.snap} | 0 ... mise__cli__outdated__tests__current.snap} | 2 +- ...tdated__tests__current_with_runtimes.snap} | 2 +- ...__r#where__tests__where_asdf_style-2.snap} | 0 ...li__r#where__tests__where_asdf_style.snap} | 0 ... => mise__cli__shell__tests__shell-2.snap} | 2 +- .../mise__cli__shell__tests__shell.snap | 7 + ... => mise__cli__trust__tests__trust-2.snap} | 2 +- ... => mise__cli__trust__tests__trust-3.snap} | 2 +- ... => mise__cli__trust__tests__trust-4.snap} | 2 +- ...ap => mise__cli__trust__tests__trust.snap} | 2 +- ...mise__cli__upgrade__tests__upgrade-2.snap} | 0 .../mise__cli__upgrade__tests__upgrade.snap | 6 + ...ap => mise__cli__which__tests__which.snap} | 0 ...ise__cli__which__tests__which_plugin.snap} | 0 ... mise__cli__which__tests__which_tool.snap} | 0 ...se__cli__which__tests__which_version.snap} | 0 ..._cli__deactivate__tests__deactivate-2.snap | 10 - ...x__cli__deactivate__tests__deactivate.snap | 7 - .../rtx__cli__shell__tests__shell.snap | 7 - .../rtx__cli__upgrade__tests__upgrade.snap | 6 - src/cli/sync/mod.rs | 2 +- src/cli/sync/node.rs | 14 +- src/cli/sync/python.rs | 10 +- src/cli/task/edit.rs | 8 +- src/cli/task/ls.rs | 18 +- src/cli/trust.rs | 10 +- src/cli/uninstall.rs | 6 +- src/cli/upgrade.rs | 4 +- src/cli/use.rs | 76 +- src/cli/version.rs | 14 +- src/cli/watch.rs | 20 +- src/cli/where.rs | 10 +- src/cli/which.rs | 20 +- src/cmd.rs | 4 +- .../config_file/{rtx_toml.rs => mise_toml.rs} | 46 +- src/config/config_file/mod.rs | 32 +- ...config_file__mise_toml__tests__env-3.snap} | 2 +- ..._config_file__mise_toml__tests__env-4.snap | 5 + ...config_file__mise_toml__tests__env-5.snap} | 4 +- ...ig_file__mise_toml__tests__fixture-2.snap} | 2 +- ...ig_file__mise_toml__tests__fixture-3.snap} | 2 +- ...ig_file__mise_toml__tests__fixture-4.snap} | 26 +- ...ig_file__mise_toml__tests__fixture-5.snap} | 2 +- ...ig_file__mise_toml__tests__fixture-6.snap} | 4 +- ...nfig_file__mise_toml__tests__fixture.snap} | 2 +- ..._file__mise_toml__tests__path_dirs-3.snap} | 2 +- ...g_file__mise_toml__tests__path_dirs-4.snap | 5 + ..._file__mise_toml__tests__path_dirs-5.snap} | 4 +- ...le__mise_toml__tests__remove_alias-2.snap} | 2 +- ...ile__mise_toml__tests__remove_alias-3.snap | 5 + ...le__mise_toml__tests__remove_alias-4.snap} | 4 +- ...file__mise_toml__tests__remove_alias.snap} | 2 +- ...le__mise_toml__tests__remove_plugin-2.snap | 5 + ...le__mise_toml__tests__remove_plugin-3.snap | 5 + ...e__mise_toml__tests__remove_plugin-4.snap} | 4 +- ...ile__mise_toml__tests__remove_plugin.snap} | 6 +- ...mise_toml__tests__replace_versions-2.snap} | 2 +- ..._mise_toml__tests__replace_versions-3.snap | 5 + ...mise_toml__tests__replace_versions-4.snap} | 4 +- ...__mise_toml__tests__replace_versions.snap} | 10 +- ...g_file__mise_toml__tests__set_alias-2.snap | 5 + ...ig_file__mise_toml__tests__set_alias.snap} | 2 +- ...__config_file__rtx_toml__tests__env-4.snap | 5 - ...ig_file__rtx_toml__tests__path_dirs-4.snap | 5 - ...file__rtx_toml__tests__remove_alias-3.snap | 5 - ...ile__rtx_toml__tests__remove_plugin-2.snap | 5 - ...ile__rtx_toml__tests__remove_plugin-3.snap | 5 - ...__rtx_toml__tests__replace_versions-3.snap | 5 - ...ig_file__rtx_toml__tests__set_alias-2.snap | 5 - src/config/mod.rs | 78 +- src/config/settings.rs | 48 +- ...ad.snap => mise__config__tests__load.snap} | 0 src/dirs.rs | 10 +- src/env.rs | 225 +-- src/errors.rs | 2 +- src/fake_asdf.rs | 4 +- src/file.rs | 2 +- src/git.rs | 2 +- src/hook_env.rs | 18 +- src/http.rs | 6 +- src/logger.rs | 8 +- src/main.rs | 4 +- src/migrate.rs | 11 + src/output.rs | 36 +- src/path_env.rs | 10 +- src/plugins/core/assets/node_npm_shim | 8 +- src/plugins/core/assets/rubygems_plugin.rb | 6 +- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/erlang.rs | 2 +- src/plugins/core/go.rs | 22 +- src/plugins/core/java.rs | 12 +- src/plugins/core/mod.rs | 8 +- src/plugins/core/node.rs | 42 +- src/plugins/core/python.rs | 16 +- src/plugins/core/ruby.rs | 28 +- src/plugins/external_plugin.rs | 51 +- ...rtx_plugin_toml.rs => mise_plugin_toml.rs} | 26 +- src/plugins/mod.rs | 2 +- src/plugins/script_manager.rs | 22 +- ...ns__mise_plugin_toml__tests__fixture.snap} | 4 +- src/shell/bash.rs | 34 +- src/shell/completions/fish_complete.rs | 72 +- src/shell/completions/zsh_complete.rs | 80 +- src/shell/fish.rs | 40 +- src/shell/mod.rs | 2 +- src/shell/nushell.rs | 22 +- .../mise__shell__bash__tests__deactivate.snap | 10 + ... mise__shell__bash__tests__hook_init.snap} | 28 +- ...e__shell__bash__tests__hook_init_nix.snap} | 28 +- ...=> mise__shell__bash__tests__set_env.snap} | 0 ... mise__shell__bash__tests__unset_env.snap} | 0 .../mise__shell__fish__tests__deactivate.snap | 10 + .../mise__shell__fish__tests__hook_init.snap | 68 + ...se__shell__fish__tests__hook_init_nix.snap | 67 + ...=> mise__shell__fish__tests__set_env.snap} | 0 ... mise__shell__fish__tests__unset_env.snap} | 0 ...e__shell__nushell__tests__deactivate.snap} | 2 +- ...se__shell__nushell__tests__hook_init.snap} | 24 +- ...shell__nushell__tests__hook_init_nix.snap} | 24 +- ...mise__shell__nushell__tests__set_env.snap} | 0 ...se__shell__nushell__tests__unset_env.snap} | 0 ...mise__shell__xonsh__tests__hook_init.snap} | 2 +- ...__shell__xonsh__tests__hook_init_nix.snap} | 2 +- ...> mise__shell__xonsh__tests__set_env.snap} | 0 ...mise__shell__xonsh__tests__unset_env.snap} | 0 ...hell__xonsh__tests__xonsh_deactivate.snap} | 0 .../mise__shell__zsh__tests__deactivate.snap | 10 + ...> mise__shell__zsh__tests__hook_init.snap} | 32 +- ...se__shell__zsh__tests__hook_init_nix.snap} | 32 +- ... => mise__shell__zsh__tests__set_env.snap} | 0 ...> mise__shell__zsh__tests__unset_env.snap} | 0 .../rtx__shell__bash__tests__deactivate.snap | 10 - .../rtx__shell__fish__tests__deactivate.snap | 10 - .../rtx__shell__fish__tests__hook_init.snap | 68 - ...tx__shell__fish__tests__hook_init_nix.snap | 67 - .../rtx__shell__zsh__tests__deactivate.snap | 10 - src/shell/xonsh.rs | 6 +- src/shell/zsh.rs | 36 +- src/shims.rs | 22 +- ...nv__tests__add_path_to_old_and_new-2.snap} | 0 ...renv__tests__add_path_to_old_and_new.snap} | 0 ....snap => mise__direnv__tests__dump-2.snap} | 0 ...mp.snap => mise__direnv__tests__dump.snap} | 0 ... => mise__direnv__tests__null_path-2.snap} | 0 ...ap => mise__direnv__tests__null_path.snap} | 0 ...e.snap => mise__direnv__tests__parse.snap} | 0 ....snap => mise__env_diff__tests__diff.snap} | 0 ...e__env_diff__tests__from_bash_script.snap} | 0 ... => mise__env_diff__tests__serialize.snap} | 0 ...ap => mise__hash__tests__hash_sha256.snap} | 0 ...ntime_symlinks__tests__list_symlinks.snap} | 0 src/task.rs | 6 +- src/test.rs | 32 +- src/toolset/builder.rs | 9 +- src/toolset/mod.rs | 3 + src/toolset/tool_source.rs | 26 +- src/toolset/tool_version_list.rs | 4 +- src/ui/progress_report.rs | 4 +- test/cwd/.mise/tasks/filetask | 11 + test/cwd/.rtx/tasks/filetask | 11 - .../{.rtx-tiny-version => .mise-tiny-version} | 0 test/data/plugins/dummy/bin/latest-stable | 4 +- test/fixtures/{.rtx.toml => .mise.toml} | 0 .../{rtx.plugin.toml => mise.plugin.toml} | 2 +- 382 files changed, 4090 insertions(+), 4101 deletions(-) create mode 100644 .mise.dev.toml rename .rtx.local.toml => .mise.local.toml (84%) rename .rtx.toml => .mise.toml (67%) rename {.rtx => .mise}/config.toml (100%) create mode 100755 .mise/tasks/filetask delete mode 100644 .rtx.dev.toml delete mode 100755 .rtx/tasks/filetask rename completions/{_rtx => _mise} (71%) rename completions/{rtx.bash => mise.bash} (85%) create mode 100644 completions/mise.fish delete mode 100644 completions/rtx.fish rename e2e/{.rtx => .mise}/tasks/build (100%) create mode 100755 e2e/.mise/tasks/filetask delete mode 100755 e2e/.rtx/tasks/filetask rename e2e/config/{.e2e.rtx.toml => .e2e.mise.toml} (91%) rename e2e/{cd/.e2e.rtx.toml => config/cd/.e2e.mise.toml} (100%) delete mode 100644 e2e/config/cd/.e2e.rtx.toml rename e2e/{cd/18/.e2e.rtx.toml => config/cd/18/.e2e.mise.toml} (100%) delete mode 100644 e2e/config/cd/18/.e2e.rtx.toml rename e2e/direnv/system_version/{rtx-direnv-system-version-reset => mise-direnv-system-version-reset}/load-first/.e2e-tool-versions (100%) rename e2e/direnv/system_version/{rtx-direnv-system-version-reset => mise-direnv-system-version-reset}/load-first/.envrc (100%) rename man/man1/{rtx.1 => mise.1} (88%) delete mode 100644 packaging/homebrew/homebrew.rb rename packaging/{rtx => mise}/Dockerfile (56%) create mode 100644 packaging/rpm/mise.repo create mode 100644 packaging/rpm/mise.spec delete mode 100644 packaging/rpm/rtx.repo delete mode 100644 packaging/rpm/rtx.spec rename schema/{rtx.json => mise.json} (92%) rename schema/{rtx.plugin.json => mise.plugin.json} (91%) create mode 100644 share/fish/vendor_conf.d/mise-activate.fish delete mode 100644 share/fish/vendor_conf.d/rtx-activate.fish rename src/cli/config/snapshots/{rtx__cli__config__generate__tests__generate.snap => mise__cli__config__generate__tests__generate.snap} (70%) rename src/cli/direnv/snapshots/{rtx__cli__direnv__envrc__tests__direnv_envrc.snap => mise__cli__direnv__envrc__tests__direnv_envrc.snap} (100%) rename src/cli/plugins/snapshots/{rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap => mise__cli__plugins__install__tests__plugin_install_invalid_url.snap} (100%) rename src/cli/plugins/snapshots/{rtx__cli__plugins__ls__tests__plugin_list.snap => mise__cli__plugins__ls__tests__plugin_list.snap} (100%) rename src/cli/plugins/snapshots/{rtx__cli__plugins__ls__tests__plugin_list_all.snap => mise__cli__plugins__ls__tests__plugin_list_all.snap} (100%) rename src/cli/settings/snapshots/{rtx__cli__settings__ls__tests__settings_ls.snap => mise__cli__settings__ls__tests__settings_ls.snap} (100%) rename src/cli/settings/snapshots/{rtx__cli__settings__set__tests__settings_set.snap => mise__cli__settings__set__tests__settings_set.snap} (100%) rename src/cli/snapshots/{rtx__cli__asdf__tests__fake_asdf_install.snap => mise__cli__asdf__tests__fake_asdf_install.snap} (100%) rename src/cli/snapshots/{rtx__cli__asdf__tests__fake_asdf_reshim.snap => mise__cli__asdf__tests__fake_asdf_reshim.snap} (100%) create mode 100644 src/cli/snapshots/mise__cli__deactivate__tests__deactivate-2.snap create mode 100644 src/cli/snapshots/mise__cli__deactivate__tests__deactivate.snap rename src/cli/snapshots/{rtx__cli__env__tests__env_json.snap => mise__cli__env__tests__env_json.snap} (100%) rename src/cli/snapshots/{rtx__cli__env_vars__tests__env_vars-2.snap => mise__cli__env_vars__tests__env_vars-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__env_vars__tests__env_vars.snap => mise__cli__env_vars__tests__env_vars.snap} (100%) rename src/cli/snapshots/{rtx__cli__env_vars__tests__env_vars_remove-2.snap => mise__cli__env_vars__tests__env_vars_remove-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__env_vars__tests__env_vars_remove.snap => mise__cli__env_vars__tests__env_vars_remove.snap} (100%) rename src/cli/snapshots/{rtx__cli__env_vars__tests__show_env_vars.snap => mise__cli__env_vars__tests__show_env_vars.snap} (100%) rename src/cli/snapshots/{rtx__cli__exec__tests__exec_fail.snap => mise__cli__exec__tests__exec_fail.snap} (100%) rename src/cli/snapshots/{rtx__cli__global__tests__global.snap => mise__cli__global__tests__global-2.snap} (60%) rename src/cli/snapshots/{rtx__cli__global__tests__global-3.snap => mise__cli__global__tests__global-3.snap} (62%) rename src/cli/snapshots/{rtx__cli__global__tests__global-2.snap => mise__cli__global__tests__global-4.snap} (60%) rename src/cli/snapshots/{rtx__cli__global__tests__global-5.snap => mise__cli__global__tests__global-5.snap} (100%) rename src/cli/snapshots/{rtx__cli__global__tests__global-6.snap => mise__cli__global__tests__global-6.snap} (100%) rename src/cli/snapshots/{rtx__cli__global__tests__global-4.snap => mise__cli__global__tests__global.snap} (60%) rename src/cli/snapshots/{rtx__cli__install__tests__install_nothing.snap => mise__cli__install__tests__install_nothing.snap} (100%) rename src/cli/snapshots/{rtx__cli__install__tests__install_with_alias.snap => mise__cli__install__tests__install_with_alias.snap} (100%) rename src/cli/snapshots/{rtx__cli__latest__tests__latest.snap => mise__cli__latest__tests__latest.snap} (100%) rename src/cli/snapshots/{rtx__cli__latest__tests__latest_asdf_format.snap => mise__cli__latest__tests__latest_asdf_format.snap} (100%) rename src/cli/snapshots/{rtx__cli__latest__tests__latest_installed.snap => mise__cli__latest__tests__latest_installed.snap} (100%) rename src/cli/snapshots/{rtx__cli__latest__tests__latest_missing_plugin.snap => mise__cli__latest__tests__latest_missing_plugin.snap} (100%) rename src/cli/snapshots/{rtx__cli__latest__tests__latest_system.snap => mise__cli__latest__tests__latest_system.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local_alias_prefix.snap => mise__cli__local__tests__local_alias_prefix.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local_alias_ref.snap => mise__cli__local__tests__local_alias_ref.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local_alias_system.snap => mise__cli__local__tests__local_alias_system.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local_multiple_versions-2.snap => mise__cli__local__tests__local_multiple_versions-2.snap} (50%) rename src/cli/snapshots/{rtx__cli__local__tests__local_multiple_versions-3.snap => mise__cli__local__tests__local_multiple_versions-3.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local_multiple_versions.snap => mise__cli__local__tests__local_multiple_versions.snap} (100%) rename src/cli/snapshots/{rtx__cli__local__tests__local_remove-2.snap => mise__cli__local__tests__local_remove-2.snap} (57%) rename src/cli/snapshots/{rtx__cli__local__tests__local_remove-3.snap => mise__cli__local__tests__local_remove-3.snap} (59%) rename src/cli/snapshots/{rtx__cli__local__tests__local_remove.snap => mise__cli__local__tests__local_remove.snap} (57%) rename src/cli/snapshots/{rtx__cli__ls__tests__ls_json-2.snap => mise__cli__ls__tests__ls_json-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__ls__tests__ls_json.snap => mise__cli__ls__tests__ls_json.snap} (100%) rename src/cli/snapshots/{rtx__cli__ls_remote__tests__list_remote.snap => mise__cli__ls_remote__tests__list_remote.snap} (100%) rename src/cli/snapshots/{rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap => mise__cli__ls_remote__tests__ls_remote_prefix-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__ls_remote__tests__ls_remote_prefix.snap => mise__cli__ls_remote__tests__ls_remote_prefix.snap} (100%) rename src/cli/snapshots/{rtx__cli__outdated__tests__current.snap => mise__cli__outdated__tests__current.snap} (64%) rename src/cli/snapshots/{rtx__cli__outdated__tests__current_with_runtimes.snap => mise__cli__outdated__tests__current_with_runtimes.snap} (64%) rename src/cli/snapshots/{rtx__cli__r#where__tests__where_asdf_style-2.snap => mise__cli__r#where__tests__where_asdf_style-2.snap} (100%) rename src/cli/snapshots/{rtx__cli__r#where__tests__where_asdf_style.snap => mise__cli__r#where__tests__where_asdf_style.snap} (100%) rename src/cli/snapshots/{rtx__cli__shell__tests__shell-2.snap => mise__cli__shell__tests__shell-2.snap} (62%) create mode 100644 src/cli/snapshots/mise__cli__shell__tests__shell.snap rename src/cli/snapshots/{rtx__cli__trust__tests__trust-2.snap => mise__cli__trust__tests__trust-2.snap} (55%) rename src/cli/snapshots/{rtx__cli__trust__tests__trust-3.snap => mise__cli__trust__tests__trust-3.snap} (57%) rename src/cli/snapshots/{rtx__cli__trust__tests__trust-4.snap => mise__cli__trust__tests__trust-4.snap} (55%) rename src/cli/snapshots/{rtx__cli__trust__tests__trust.snap => mise__cli__trust__tests__trust.snap} (57%) rename src/cli/snapshots/{rtx__cli__upgrade__tests__upgrade-2.snap => mise__cli__upgrade__tests__upgrade-2.snap} (100%) create mode 100644 src/cli/snapshots/mise__cli__upgrade__tests__upgrade.snap rename src/cli/snapshots/{rtx__cli__which__tests__which.snap => mise__cli__which__tests__which.snap} (100%) rename src/cli/snapshots/{rtx__cli__which__tests__which_plugin.snap => mise__cli__which__tests__which_plugin.snap} (100%) rename src/cli/snapshots/{rtx__cli__which__tests__which_tool.snap => mise__cli__which__tests__which_tool.snap} (100%) rename src/cli/snapshots/{rtx__cli__which__tests__which_version.snap => mise__cli__which__tests__which_version.snap} (100%) delete mode 100644 src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap delete mode 100644 src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap delete mode 100644 src/cli/snapshots/rtx__cli__shell__tests__shell.snap delete mode 100644 src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap rename src/config/config_file/{rtx_toml.rs => mise_toml.rs} (96%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__env-3.snap => mise__config__config_file__mise_toml__tests__env-3.snap} (51%) create mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__env-5.snap => mise__config__config_file__mise_toml__tests__env-5.snap} (92%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__fixture-2.snap => mise__config__config_file__mise_toml__tests__fixture-2.snap} (94%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__fixture-3.snap => mise__config__config_file__mise_toml__tests__fixture-3.snap} (65%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__fixture-4.snap => mise__config__config_file__mise_toml__tests__fixture-4.snap} (85%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__fixture-5.snap => mise__config__config_file__mise_toml__tests__fixture-5.snap} (66%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__fixture-6.snap => mise__config__config_file__mise_toml__tests__fixture-6.snap} (84%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__fixture.snap => mise__config__config_file__mise_toml__tests__fixture.snap} (58%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap => mise__config__config_file__mise_toml__tests__path_dirs-3.snap} (62%) create mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap => mise__config__config_file__mise_toml__tests__path_dirs-5.snap} (92%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap => mise__config__config_file__mise_toml__tests__remove_alias-2.snap} (56%) create mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap => mise__config__config_file__mise_toml__tests__remove_alias-4.snap} (92%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__remove_alias.snap => mise__config__config_file__mise_toml__tests__remove_alias.snap} (63%) create mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-2.snap create mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-3.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap => mise__config__config_file__mise_toml__tests__remove_plugin-4.snap} (91%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__remove_plugin.snap => mise__config__config_file__mise_toml__tests__remove_plugin.snap} (56%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap => mise__config__config_file__mise_toml__tests__replace_versions-2.snap} (60%) create mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-3.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap => mise__config__config_file__mise_toml__tests__replace_versions-4.snap} (89%) rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__replace_versions.snap => mise__config__config_file__mise_toml__tests__replace_versions.snap} (80%) create mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap rename src/config/config_file/snapshots/{rtx__config__config_file__rtx_toml__tests__set_alias.snap => mise__config__config_file__mise_toml__tests__set_alias.snap} (79%) delete mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-4.snap delete mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap delete mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap delete mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap delete mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap delete mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap delete mode 100644 src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap rename src/config/snapshots/{rtx__config__tests__load.snap => mise__config__tests__load.snap} (100%) rename src/plugins/{rtx_plugin_toml.rs => mise_plugin_toml.rs} (85%) rename src/plugins/snapshots/{rtx__plugins__rtx_plugin_toml__tests__fixture.snap => mise__plugins__mise_plugin_toml__tests__fixture.snap} (64%) create mode 100644 src/shell/snapshots/mise__shell__bash__tests__deactivate.snap rename src/shell/snapshots/{rtx__shell__bash__tests__hook_init.snap => mise__shell__bash__tests__hook_init.snap} (62%) rename src/shell/snapshots/{rtx__shell__bash__tests__hook_init_nix.snap => mise__shell__bash__tests__hook_init_nix.snap} (61%) rename src/shell/snapshots/{rtx__shell__bash__tests__set_env.snap => mise__shell__bash__tests__set_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__bash__tests__unset_env.snap => mise__shell__bash__tests__unset_env.snap} (100%) create mode 100644 src/shell/snapshots/mise__shell__fish__tests__deactivate.snap create mode 100644 src/shell/snapshots/mise__shell__fish__tests__hook_init.snap create mode 100644 src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap rename src/shell/snapshots/{rtx__shell__fish__tests__set_env.snap => mise__shell__fish__tests__set_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__fish__tests__unset_env.snap => mise__shell__fish__tests__unset_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__nushell__tests__deactivate.snap => mise__shell__nushell__tests__deactivate.snap} (81%) rename src/shell/snapshots/{rtx__shell__nushell__tests__hook_init.snap => mise__shell__nushell__tests__hook_init.snap} (67%) rename src/shell/snapshots/{rtx__shell__nushell__tests__hook_init_nix.snap => mise__shell__nushell__tests__hook_init_nix.snap} (65%) rename src/shell/snapshots/{rtx__shell__nushell__tests__set_env.snap => mise__shell__nushell__tests__set_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__nushell__tests__unset_env.snap => mise__shell__nushell__tests__unset_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__xonsh__tests__hook_init.snap => mise__shell__xonsh__tests__hook_init.snap} (87%) rename src/shell/snapshots/{rtx__shell__xonsh__tests__hook_init_nix.snap => mise__shell__xonsh__tests__hook_init_nix.snap} (84%) rename src/shell/snapshots/{rtx__shell__xonsh__tests__set_env.snap => mise__shell__xonsh__tests__set_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__xonsh__tests__unset_env.snap => mise__shell__xonsh__tests__unset_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__xonsh__tests__xonsh_deactivate.snap => mise__shell__xonsh__tests__xonsh_deactivate.snap} (100%) create mode 100644 src/shell/snapshots/mise__shell__zsh__tests__deactivate.snap rename src/shell/snapshots/{rtx__shell__zsh__tests__hook_init.snap => mise__shell__zsh__tests__hook_init.snap} (57%) rename src/shell/snapshots/{rtx__shell__zsh__tests__hook_init_nix.snap => mise__shell__zsh__tests__hook_init_nix.snap} (56%) rename src/shell/snapshots/{rtx__shell__zsh__tests__set_env.snap => mise__shell__zsh__tests__set_env.snap} (100%) rename src/shell/snapshots/{rtx__shell__zsh__tests__unset_env.snap => mise__shell__zsh__tests__unset_env.snap} (100%) delete mode 100644 src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap delete mode 100644 src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap delete mode 100644 src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap delete mode 100644 src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap delete mode 100644 src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap rename src/snapshots/{rtx__direnv__tests__add_path_to_old_and_new-2.snap => mise__direnv__tests__add_path_to_old_and_new-2.snap} (100%) rename src/snapshots/{rtx__direnv__tests__add_path_to_old_and_new.snap => mise__direnv__tests__add_path_to_old_and_new.snap} (100%) rename src/snapshots/{rtx__direnv__tests__dump-2.snap => mise__direnv__tests__dump-2.snap} (100%) rename src/snapshots/{rtx__direnv__tests__dump.snap => mise__direnv__tests__dump.snap} (100%) rename src/snapshots/{rtx__direnv__tests__null_path-2.snap => mise__direnv__tests__null_path-2.snap} (100%) rename src/snapshots/{rtx__direnv__tests__null_path.snap => mise__direnv__tests__null_path.snap} (100%) rename src/snapshots/{rtx__direnv__tests__parse.snap => mise__direnv__tests__parse.snap} (100%) rename src/snapshots/{rtx__env_diff__tests__diff.snap => mise__env_diff__tests__diff.snap} (100%) rename src/snapshots/{rtx__env_diff__tests__from_bash_script.snap => mise__env_diff__tests__from_bash_script.snap} (100%) rename src/snapshots/{rtx__env_diff__tests__serialize.snap => mise__env_diff__tests__serialize.snap} (100%) rename src/snapshots/{rtx__hash__tests__hash_sha256.snap => mise__hash__tests__hash_sha256.snap} (100%) rename src/snapshots/{rtx__runtime_symlinks__tests__list_symlinks.snap => mise__runtime_symlinks__tests__list_symlinks.snap} (100%) create mode 100755 test/cwd/.mise/tasks/filetask delete mode 100755 test/cwd/.rtx/tasks/filetask rename test/cwd/tiny-legacy/{.rtx-tiny-version => .mise-tiny-version} (100%) rename test/fixtures/{.rtx.toml => .mise.toml} (100%) rename test/fixtures/{rtx.plugin.toml => mise.plugin.toml} (50%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5ad2c8038..2d7275627 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -15,10 +15,10 @@ Steps to reproduce the behavior. **Expected behavior** A clear and concise description of what you expected to happen. -**`rtx doctor` output** +**`mise doctor` output** ```text -REPLACE WITH OUTPUT OF `rtx doctor` +REPLACE WITH OUTPUT OF `mise doctor` ``` **Additional context** diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 358da4c0f..f4b1f7946 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: - deb - github-actions - rpm - - rtx + - mise runs-on: ubuntu-latest permissions: contents: read @@ -50,12 +50,12 @@ jobs: with: context: . push: true - tags: ghcr.io/jdx/rtx:${{ matrix.flavor }} + tags: ghcr.io/jdx/mise:${{ matrix.flavor }} labels: ${{ steps.meta.outputs.labels }} file: packaging/${{ matrix.flavor }}/Dockerfile test: runs-on: ubuntu-22.04 - container: ghcr.io/jdx/rtx:github-actions + container: ghcr.io/jdx/mise:github-actions timeout-minutes: 10 steps: - run: node -v @@ -81,12 +81,12 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: jdxcode/rtx + images: jdxcode/mise - name: Build and push Docker image uses: docker/build-push-action@v5 with: file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true - tags: jdxcode/rtx:latest + tags: jdxcode/mise:latest labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index 7c8d96456..96ea77b5d 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -13,6 +13,10 @@ on: pull_request: branches: - main + push: + branches: + - main + - mise # Comment env block if you do not want to apply fixes env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11e133613..04598cd08 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: release on: push: tags: ["v*"] - branches: ["main", "release/*"] + branches: ["main", "mise", "release/*"] workflow_dispatch: concurrency: @@ -83,18 +83,18 @@ jobs: - run: scripts/setup-zipsign.sh env: ZIPSIGN: ${{ secrets.ZIPSIGN }} - - run: scripts/build-tarball.sh rtx --release --features openssl/vendored --target ${{matrix.target}} + - run: scripts/build-tarball.sh mise --release --features openssl/vendored --target ${{matrix.target}} - uses: actions/upload-artifact@v4 with: name: tarball-${{matrix.target}} path: | - dist/rtx-*.tar.xz - dist/rtx-*.tar.gz + dist/mise-*.tar.xz + dist/mise-*.tar.gz if-no-files-found: error e2e-linux: name: e2e-linux-${{matrix.tranche}} runs-on: ubuntu-latest - #container: ghcr.io/jdx/rtx:github-actions + #container: ghcr.io/jdx/mise:github-actions needs: [build-tarball] timeout-minutes: 30 strategy: @@ -109,9 +109,9 @@ jobs: with: name: tarball-x86_64-unknown-linux-gnu path: dist - - run: tar -C "$HOME" -xvJf "dist/rtx-$(./scripts/get-version.sh)-linux-x64.tar.xz" - - run: echo "$HOME/rtx/bin" >> "$GITHUB_PATH" - - run: rtx -v + - run: tar -C "$HOME" -xvJf "dist/mise-$(./scripts/get-version.sh)-linux-x64.tar.xz" + - run: echo "$HOME/mise/bin" >> "$GITHUB_PATH" + - run: mise -v - name: Run e2e tests uses: nick-fields/retry@v2 env: @@ -133,7 +133,7 @@ jobs: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 with: - gpg_private_key: ${{ secrets.GPG_KEY }} + gpg_private_key: ${{ secrets.MISE_GPG_KEY }} - uses: actions/download-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu @@ -157,7 +157,7 @@ jobs: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 with: - gpg_private_key: ${{ secrets.GPG_KEY }} + gpg_private_key: ${{ secrets.MISE_GPG_KEY }} - uses: actions/download-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu @@ -174,7 +174,7 @@ jobs: if-no-files-found: error release: runs-on: ubuntu-latest - #container: ghcr.io/jdx/rtx:github-actions + #container: ghcr.io/jdx/mise:github-actions timeout-minutes: 10 permissions: contents: write @@ -186,7 +186,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - path: rtx + path: mise - uses: actions/checkout@v4 with: repository: jdx/homebrew-tap @@ -209,13 +209,13 @@ jobs: known_hosts: ${{ secrets.RTX_KNOWN_HOSTS_AUR }} - uses: crazy-max/ghaction-import-gpg@v6 with: - gpg_private_key: ${{ secrets.GPG_KEY }} + gpg_private_key: ${{ secrets.MISE_GPG_KEY }} git_user_signingkey: true git_commit_gpgsign: true workdir: homebrew-tap - uses: actions/download-artifact@v4 with: { path: artifacts } - - run: rtx/scripts/release.sh + - run: mise/scripts/release.sh env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -247,7 +247,7 @@ jobs: uses: dawidd6/action-homebrew-bump-formula@v3 with: token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - formula: rtx + formula: mise bump-aur: runs-on: ubuntu-22.04 timeout-minutes: 30 diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index 310a480dc..c0e07deb0 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -28,7 +28,7 @@ jobs: with: shared-key: "build-linux-x86_64-unknown-linux-gnu" save-if: false - - run: scripts/build-tarball.sh rtx --release --target x86_64-unknown-linux-gnu + - run: scripts/build-tarball.sh mise --release --target x86_64-unknown-linux-gnu - uses: actions/upload-artifact@v4 with: name: tarball-x86_64-unknown-linux-gnu @@ -46,50 +46,50 @@ jobs: matrix: include: - plugin: node - command: rtx exec node@latest -- node -v + command: mise exec node@latest -- node -v - plugin: ruby - command: rtx exec ruby@latest -- ruby --version + command: mise exec ruby@latest -- ruby --version - plugin: python - command: rtx exec python@latest -- python -V + command: mise exec python@latest -- python -V - plugin: direnv - command: rtx exec direnv@latest -- direnv --version + command: mise exec direnv@latest -- direnv --version - plugin: erlang - command: rtx exec erlang@24.3.4.9 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell + command: mise exec erlang@24.3.4.9 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell - plugin: elixir command: | - rtx use --global erlang@24.3.4.9 - eval "$(rtx env bash)" - rtx use --global elixir@main-otp-24 - eval "$(rtx env bash)" - rtx exec -- elixir --version + mise use --global erlang@24.3.4.9 + eval "$(mise env bash)" + mise use --global elixir@main-otp-24 + eval "$(mise env bash)" + mise exec -- elixir --version - plugin: golang - command: rtx exec golang@latest -- go version + command: mise exec golang@latest -- go version - plugin: java - command: rtx exec java@openjdk -- java -version + command: mise exec java@openjdk -- java -version - plugin: terraform - command: rtx exec terraform@latest -- terraform -v + command: mise exec terraform@latest -- terraform -v # - plugin: yarn - # command: rtx exec yarn@latest -- yarn --version + # command: mise exec yarn@latest -- yarn --version - plugin: deno - command: rtx exec deno@latest -- deno --version + command: mise exec deno@latest -- deno --version - plugin: bun - command: rtx exec bun@latest -- bun --version + command: mise exec bun@latest -- bun --version - plugin: kubectl - command: rtx exec kubectl@latest -- kubectl version --client + command: mise exec kubectl@latest -- kubectl version --client - plugin: dotnet - command: rtx exec dotnet@latest -- dotnet --list-sdks + command: mise exec dotnet@latest -- dotnet --list-sdks - plugin: flutter - command: rtx exec flutter@latest -- flutter --version + command: mise exec flutter@latest -- flutter --version - plugin: crystal - command: rtx exec crystal@latest -- crystal -v + command: mise exec crystal@latest -- crystal -v - plugin: neovim - command: rtx exec neovim@latest -- nvim --version + command: mise exec neovim@latest -- nvim --version - plugin: php - command: rtx exec php@latest -- php -v php + command: mise exec php@latest -- php -v php - plugin: rust - command: rtx exec rust@nightly -- rustc -V + command: mise exec rust@nightly -- rustc -V - plugin: postgres - command: rtx exec postgres@latest -- psql -V + command: mise exec postgres@latest -- psql -V steps: - name: apt-get run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl4-openssl-dev libgd-dev libonig-dev autoconf bison build-essential curl gettext git libgd-dev libcurl4-openssl-dev libedit-dev libicu-dev libjpeg-dev libmysqlclient-dev libonig-dev libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libxml2-dev libzip-dev openssl pkg-config re2c zlib1g-dev libwxgtk-webview3.0-gtk3-dev @@ -97,11 +97,11 @@ jobs: with: name: tarball-x86_64-unknown-linux-gnu path: dist - # dist/rtx-v1.16.0-linux-x64.tar.xz + # dist/mise-v1.16.0-linux-x64.tar.xz # x86_64-unknown-linux-gnu-v1.16.0-linux-x64.tar.xz - - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - - run: echo "$HOME/rtx/bin" >> "$GITHUB_PATH" - - run: rtx -v + - run: tar -C "$HOME" -xvJf dist/mise-*-linux-x64.tar.xz + - run: echo "$HOME/mise/bin" >> "$GITHUB_PATH" + - run: mise -v - name: ${{matrix.command}} uses: nick-fields/retry@v2 with: @@ -110,11 +110,11 @@ jobs: retry_wait_seconds: 30 command: ${{matrix.command}} env: - RTX_EXPERIMENTAL: "1" + MISE_EXPERIMENTAL: "1" test-install: # Tests installing the top 50 plugins not already tested in `test-install-and-run`. # installing is a better-than-nothing smoke test that the plugin is correctly implemented - # and behaves as expected with rtx. + # and behaves as expected with mise. runs-on: ubuntu-22.04 needs: [build-linux] env: @@ -150,7 +150,7 @@ jobs: - awscli - dart - conan - # TODO: - awsebcli fails in asdf and rtx the same way + # TODO: - awsebcli fails in asdf and mise the same way - aws-sam-cli - ansible-base - kotlin @@ -179,12 +179,12 @@ jobs: with: name: tarball-x86_64-unknown-linux-gnu path: dist - - run: tar -C "$HOME" -xvJf dist/rtx-*-linux-x64.tar.xz - - run: echo "$HOME/rtx/bin" >> "$GITHUB_PATH" - - name: rtx install ${{matrix.plugins}}@latest + - run: tar -C "$HOME" -xvJf dist/mise-*-linux-x64.tar.xz + - run: echo "$HOME/mise/bin" >> "$GITHUB_PATH" + - name: mise install ${{matrix.plugins}}@latest uses: nick-fields/retry@v2 with: timeout_minutes: 20 max_attempts: 3 retry_wait_seconds: 30 - command: rtx install ${{matrix.plugins}}@latest + command: mise install ${{matrix.plugins}}@latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d091d7833..7b12fa46e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,7 @@ name: test on: push: tags: ["v*"] - branches: ["main"] + branches: ["main", "mise"] pull_request: branches: ["main"] workflow_dispatch: @@ -14,12 +14,12 @@ concurrency: env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 - RTX_TRUSTED_CONFIG_PATHS: ${{ github.workspace }} + MISE_TRUSTED_CONFIG_PATHS: ${{ github.workspace }} jobs: unit: runs-on: ubuntu-latest - #container: ghcr.io/jdx/rtx:github-actions + #container: ghcr.io/jdx/mise:github-actions timeout-minutes: 10 steps: - uses: actions/checkout@v4 @@ -43,19 +43,20 @@ jobs: - run: cargo msrv verify - run: cargo machete --with-metadata - run: ./scripts/test-standalone.sh + if: github.ref_name != 'mise' - run: just render-all lint-fix - run: git diff HEAD - if: github.event_name == 'pull_request' uses: EndBug/add-and-commit@v9 with: push: true - author_name: rtx[bot] + author_name: mise[bot] author_email: 123107610+rtx-vm@users.noreply.github.com - run: just lint coverage: name: coverage-${{matrix.tranche}} - #container: ghcr.io/jdx/rtx:github-actions + #container: ghcr.io/jdx/mise:github-actions runs-on: ubuntu-latest timeout-minutes: 30 strategy: @@ -81,7 +82,7 @@ jobs: env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" - RTX_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} + MISE_GITHUB_BOT_TOKEN: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} TEST_TRANCHE: ${{matrix.tranche}} TEST_TRANCHE_COUNT: 4 TEST_FULL: ${{github.ref_name == 'main' && '1' || '0'}} diff --git a/.mise.dev.toml b/.mise.dev.toml new file mode 100644 index 000000000..4dae1552f --- /dev/null +++ b/.mise.dev.toml @@ -0,0 +1,2 @@ +[env] +FOO=".mise.dev.toml" diff --git a/.rtx.local.toml b/.mise.local.toml similarity index 84% rename from .rtx.local.toml rename to .mise.local.toml index d7b0609af..3b62ceb2a 100644 --- a/.rtx.local.toml +++ b/.mise.local.toml @@ -1,4 +1,4 @@ -#:schema ./schema/rtx.json +#:schema ./schema/mise.json tasks.a1 = { run = "echo a1 1>&2 && sleep 1.5" } tasks.a2 = { run = "echo a2 && sleep 1.0" } @@ -7,4 +7,4 @@ tasks.c1 = { run = "echo c1 && sleep 0.5 && echo", depends = ["b1"] } #tasks.filetask = "echo local" [env] -FOO=".rtx.local.toml" +FOO=".mise.local.toml" diff --git a/.rtx.toml b/.mise.toml similarity index 67% rename from .rtx.toml rename to .mise.toml index 3a0744291..44a617dcd 100644 --- a/.rtx.toml +++ b/.mise.toml @@ -1,4 +1,4 @@ -#:schema ./schema/rtx.json +#:schema ./schema/mise.json env_file = '.env' [env] @@ -28,7 +28,7 @@ run = "cargo clean" alias = "b" run = "cargo build --color always --all-features" sources = ["src/**/*.rs"] -outputs = ["target/debug/rtx"] +outputs = ["target/debug/mise"] [tasks.test] run = "cargo test" @@ -45,35 +45,35 @@ depends = [ [tasks.render-completions] depends = ["build"] env = { NO_COLOR = "1" } -sources = ["target/debug/rtx"] +sources = ["target/debug/mise"] outputs = [ - "completions/rtx.bash", - "completions/_rtx", - "completions/rtx.fish", + "completions/mise.bash", + "completions/_mise", + "completions/mise.fish", ] run = """ #!/usr/bin/env bash set -xeuo pipefail -target/debug/rtx render-completion bash > completions/rtx.bash -target/debug/rtx render-completion zsh > completions/_rtx -target/debug/rtx render-completion fish > completions/rtx.fish +target/debug/mise render-completion bash > completions/mise.bash +target/debug/mise render-completion zsh > completions/_mise +target/debug/mise render-completion fish > completions/mise.fish """ [tasks.render-mangen] depends = ["build"] env = { NO_COLOR = "1" } -run = "target/debug/rtx render-mangen" -sources = ["target/debug/rtx"] -outputs = ["man/man1/rtx.1"] +run = "target/debug/mise render-mangen" +sources = ["target/debug/mise"] +outputs = ["man/man1/mise.1"] [tasks.render-help] depends = ["build"] env = { NO_COLOR = "1" } run = [ - "target/debug/rtx render-help", + "target/debug/mise render-help", "md-magic", ] -sources = ["target/debug/rtx"] +sources = ["target/debug/mise"] outputs = ["README.md"] [tasks.render-all] diff --git a/.rtx/config.toml b/.mise/config.toml similarity index 100% rename from .rtx/config.toml rename to .mise/config.toml diff --git a/.mise/tasks/filetask b/.mise/tasks/filetask new file mode 100755 index 000000000..ee264c008 --- /dev/null +++ b/.mise/tasks/filetask @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# mise description="This is a test build script" +# mise depends=["lint", "build"] +# mise sources=[".test-tool-versions"] +# mise outputs=["$MISE_PROJECT_ROOT/test/test-build-output.txt"] +# mise env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} + +set -euxo pipefail +cd "$MISE_PROJECT_ROOT" || exit 1 +echo "running test-build script" +echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test/test-build-output.txt +echo "ARGS:" "$@" diff --git a/.rtx.dev.toml b/.rtx.dev.toml deleted file mode 100644 index d8f9ce960..000000000 --- a/.rtx.dev.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -FOO=".rtx.dev.toml" diff --git a/.rtx/tasks/filetask b/.rtx/tasks/filetask deleted file mode 100755 index 037960417..000000000 --- a/.rtx/tasks/filetask +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -# rtx description="This is a test build script" -# rtx depends=["lint", "build"] -# rtx sources=[".test-tool-versions"] -# rtx outputs=["$RTX_PROJECT_ROOT/test/test-build-output.txt"] -# rtx env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} - -set -euxo pipefail -cd "$RTX_PROJECT_ROOT" || exit 1 -echo "running test-build script" -echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test/test-build-output.txt -echo "ARGS:" "$@" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f664e34f4..dffb221e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,17 +5,17 @@ PRs are often either rejected or need to change significantly after submission s ## Development Container -The directory `.devcontainer` contains a Dockerfile that can be used to build a container for local development. This is useful if you want to use a [GitHub Codespace](https://docs.github.com/codespaces), VSCode's remote container feature or a standalone container to develop rtx. To use it, you'll need to have Docker Desktop installed and running. +The directory `.devcontainer` contains a Dockerfile that can be used to build a container for local development. This is useful if you want to use a [GitHub Codespace](https://docs.github.com/codespaces), VSCode's remote container feature or a standalone container to develop mise. To use it, you'll need to have Docker Desktop installed and running. Build and run the container with the following commands: ```shell cd .devcontainer -docker build -t local/rtxdevcontainer . -docker run --rm -it -v "$(pwd)"/../:/workspaces/cached local/rtxdevcontainer +docker build -t local/misedevcontainer . +docker run --rm -it -v "$(pwd)"/../:/workspaces/cached local/misedevcontainer ``` -To use the container with VSCode, you'll need to install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. Once installed, you can open the project in a container by opening the Command Palette (F1) and selecting "Remote-Containers: Open Folder in Container...". Select the root of the rtx project and the container will be built and started. +To use the container with VSCode, you'll need to install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. Once installed, you can open the project in a container by opening the Command Palette (F1) and selecting "Remote-Containers: Open Folder in Container...". Select the root of the mise project and the container will be built and started. ## Dependencies @@ -25,7 +25,7 @@ To use the container with VSCode, you'll need to install the [Remote - Container - [shfmt](https://github.com/mvdan/sh) - [shellcheck](https://www.shellcheck.net/) -(you'd think we'd use rtx to fetch these but frankly it's kind of a pain to dogfood rtx while testing it) +(you'd think we'd use mise to fetch these but frankly it's kind of a pain to dogfood mise while testing it) ## Just @@ -33,7 +33,7 @@ Just should be used for just about every task. Here is a full list of its tasks: ```shell -~/src/rtx ❯ just --list +~/src/mise ❯ just --list Available recipes: build *args # just `cargo build` b *args # alias for `build` @@ -42,7 +42,7 @@ Available recipes: lint # clippy, cargo fmt --check, and just --fmt lint-fix # runs linters but makes fixes when possible pre-commit # called by lefthook precommit hook - release *args # create/publish a new version of rtx + release *args # create/publish a new version of mise render-completions # regenerate shell completion files render-help # regenerate README.md render-mangen # regenerate manpages @@ -61,7 +61,7 @@ Shouldn't require anything special I'm aware of, but `just build` is a good sani ## Running the CLI -I put a shim for `cargo run` that makes it easy to run build + run rtx in dev mode. It's at `.bin/rtx`. What I do is add this to PATH +I put a shim for `cargo run` that makes it easy to run build + run mise in dev mode. It's at `.bin/mise`. What I do is add this to PATH with direnv. Here is my `.envrc`: ```shell @@ -69,9 +69,9 @@ source_up_if_exists PATH_add "$(expand_path .bin)" ``` -Now I can just run `rtx` as if I was using an installed version and it will build it from source every time there are changes. +Now I can just run `mise` as if I was using an installed version and it will build it from source every time there are changes. -You don't have to do this, but it makes things like `rtx activate` a lot easier to setup. +You don't have to do this, but it makes things like `mise activate` a lot easier to setup. ## Running Tests @@ -118,11 +118,11 @@ finch run -ti --rm ubuntu apt update -y apt install -y gpg sudo wget curl sudo install -dm 755 /etc/apt/keyrings -wget -qO - https://rtx.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/rtx-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/etc/apt/keyrings/rtx-archive-keyring.gpg arch=arm64] https://rtx.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/rtx.list +wget -qO - https://mise.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/mise-archive-keyring.gpg 1> /dev/null +echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=arm64] https://mise.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/mise.list apt update -apt install -y rtx -rtx -V +apt install -y mise +mise -V ``` ### Amazon Linux 2 (yum) @@ -130,9 +130,9 @@ rtx -V ```shell finch run -ti --rm amazonlinux yum install -y yum-utils -yum-config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo -yum install -y rtx -rtx -v +yum-config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo +yum install -y mise +mise -v ``` ### Fedora (dnf) @@ -140,7 +140,7 @@ rtx -v ```shell finch run -ti --rm fedora dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://rtx.jdx.dev/rpm/rtx.repo -dnf install -y rtx -rtx -v +dnf config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo +dnf install -y mise +mise -v ``` diff --git a/Cargo.lock b/Cargo.lock index 16d27a9b4..7263db869 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1327,6 +1327,76 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mise" +version = "2024.0.0" +dependencies = [ + "base64", + "built", + "chrono", + "clap", + "clap_complete", + "clap_mangen", + "color-eyre", + "color-print", + "confique", + "console", + "ctor", + "ctrlc", + "demand", + "dirs-next", + "dotenvy", + "duct", + "either", + "exec", + "eyre", + "filetime", + "flate2", + "fslock", + "globwalk 0.9.0", + "humantime", + "indenter", + "indexmap", + "indicatif", + "indoc", + "insta", + "itertools", + "log", + "num_cpus", + "once_cell", + "openssl", + "path-absolutize", + "petgraph", + "pretty_assertions", + "rand", + "rayon", + "regex", + "reqwest", + "rmp-serde", + "self_update", + "serde", + "serde_derive", + "serde_json", + "sha2", + "shell-escape", + "shell-words", + "simplelog", + "strum", + "sys-info", + "tabled", + "tar", + "tempfile", + "tera", + "terminal_size", + "thiserror", + "toml", + "toml_edit", + "url", + "versions", + "which", + "zip", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -1873,76 +1943,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" -[[package]] -name = "rtx-cli" -version = "2024.0.0" -dependencies = [ - "base64", - "built", - "chrono", - "clap", - "clap_complete", - "clap_mangen", - "color-eyre", - "color-print", - "confique", - "console", - "ctor", - "ctrlc", - "demand", - "dirs-next", - "dotenvy", - "duct", - "either", - "exec", - "eyre", - "filetime", - "flate2", - "fslock", - "globwalk 0.9.0", - "humantime", - "indenter", - "indexmap", - "indicatif", - "indoc", - "insta", - "itertools", - "log", - "num_cpus", - "once_cell", - "openssl", - "path-absolutize", - "petgraph", - "pretty_assertions", - "rand", - "rayon", - "regex", - "reqwest", - "rmp-serde", - "self_update", - "serde", - "serde_derive", - "serde_json", - "sha2", - "shell-escape", - "shell-words", - "simplelog", - "strum", - "sys-info", - "tabled", - "tar", - "tempfile", - "tera", - "terminal_size", - "thiserror", - "toml", - "toml_edit", - "url", - "versions", - "which", - "zip", -] - [[package]] name = "rustc-demangle" version = "0.1.23" diff --git a/Cargo.toml b/Cargo.toml index b2bf7d2f7..694db0b26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,15 @@ [package] -name = "rtx-cli" +name = "mise" version = "2024.0.0" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] -homepage = "https://rtx.jdx.dev" -documentation = "https://rtx.jdx.dev" -repository = "https://github.com/jdx/rtx" +homepage = "https://mise.jdx.dev" +documentation = "https://mise.jdx.dev" +repository = "https://github.com/jdx/mise" readme = "README.md" license = "MIT" -keywords = ["rtx"] +keywords = ["mise"] categories = ["command-line-utilities"] include = [ "src/**/*.rs", @@ -27,7 +27,7 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] -name = "rtx" +name = "mise" path = "src/main.rs" #[[bench]] @@ -125,21 +125,21 @@ sign-tag = true sign-commit = true pre-release-hook = "./scripts/pre-release-hook.sh" pre-release-replacements = [ - { file = "README.md", search = "^rtx [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "rtx {{version}}", exactly = 1 }, - { file = "packaging/rpm/rtx.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, - { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, + { file = "README.md", search = "^mise [0-9]+.[0-9]+.[0-9]+(-rc.[0-9]+)?$", replace = "mise {{version}}", exactly = 1 }, + { file = "packaging/rpm/mise.spec", search = "^Version: [0-9]+.[0-9]+.[0-9]+(-rc.[0-9]+)?$", replace = "Version: {{version}}", exactly = 1 }, + { file = "default.nix", search = "version = \"[0-9]+.[0-9]+.[0-9]+(-rc.[0-9]+)?\";$", replace = "version = \"{{version}}\";", exactly = 1 }, ] [package.metadata.binstall] -bin-dir = "rtx/bin/rtx" +bin-dir = "mise/bin/mise" [package.metadata.binstall.overrides.aarch64-apple-darwin] -pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-macos-arm64{ archive-suffix }" +pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-macos-arm64{ archive-suffix }" [package.metadata.binstall.overrides.x86_64-apple-darwin] -pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-macos-x64{ archive-suffix }" +pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-macos-x64{ archive-suffix }" [package.metadata.binstall.overrides.aarch64-unknown-linux-gnu] -pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-linux-arm64{ archive-suffix }" +pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-arm64{ archive-suffix }" [package.metadata.binstall.overrides.x86_64-unknown-linux-gnu] -pkg-url = "{ repo }/releases/download/v{ version }/rtx-v{version}-linux-x64{ archive-suffix }" +pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-x64{ archive-suffix }" [package.metadata.cargo-machete] ignored = ["built", "openssl"] diff --git a/Dockerfile b/Dockerfile index 6451905bb..42899face 120000 --- a/Dockerfile +++ b/Dockerfile @@ -1 +1 @@ -packaging/rtx/Dockerfile \ No newline at end of file +./packaging/mise/Dockerfile \ No newline at end of file diff --git a/README.md b/README.md index c0f486c87..94a142458 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,26 @@
- - - rtx logo - + + + +
-Crates.io -GitHub -GitHub Workflow Status - +Crates.io +GitHub +GitHub Workflow Status + Discord -

The front-end to your dev env.

+

The front-end to your dev env. (formerly called "rtx")

## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://rtx.jdx.dev/plugins.html). -* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://rtx.jdx.dev/environments.html) for different project directories. -* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://rtx.jdx.dev/tasks/) used to build and test projects. +* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://mise.jdx.dev/plugins.html). +* Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://mise.jdx.dev/environments.html) for different project directories. +* Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://mise.jdx.dev/tasks/) used to build and test projects. ## 30 Second Demo -The following shows using rtx to install different versions +The following shows using mise to install different versions of [node](https://nodejs.org). Note that calling `which node` gives us a real path to node, not a shim. @@ -28,32 +28,32 @@ Note that calling `which node` gives us a real path to node, not a shim. ## Quickstart -Install rtx on macOS (other methods [here](https://rtx.jdx.dev/getting-started.html)): +Install mise on macOS (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session -$ curl https://rtx.jdx.dev/install.sh | sh -$ ~/.local/share/rtx/bin/rtx --version -rtx 2024.0.0 +$ curl https://mise.jdx.dev/install.sh | sh +$ ~/.local/share/mise/bin/mise --version +mise 2024.0.0 ``` -Hook rtx into your shell (pick the right one for your shell): +Hook mise into your shell (pick the right one for your shell): ```sh-session -# note this assumes rtx is located at ~/.local/share/rtx/bin/rtx +# note this assumes mise is located at ~/.local/share/mise/bin/mise # which is what install.sh does by default -echo 'eval "$(~/.local/share/rtx/bin/rtx activate bash)"' >> ~/.bashrc -echo 'eval "$(~/.local/share/rtx/bin/rtx activate zsh)"' >> ~/.zshrc -echo '~/.local/share/rtx/bin/rtx activate fish | source' >> ~/.config/fish/config.fish +echo 'eval "$(~/.local/share/mise/bin/mise activate bash)"' >> ~/.bashrc +echo 'eval "$(~/.local/share/mise/bin/mise activate zsh)"' >> ~/.zshrc +echo '~/.local/share/mise/bin/mise activate fish | source' >> ~/.config/fish/config.fish ``` Install a runtime and set it as the global default: ```sh-session -$ rtx use --global node@20 +$ mise use --global node@20 $ node -v v20.0.0 ``` ## Full Documentation -See [rtx.jdx.dev](https://rtx.jdx.dev). +See [mise.jdx.dev](https://mise.jdx.dev). diff --git a/SECURITY.md b/SECURITY.md index 55d6fe98d..a63533357 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,13 +1,13 @@ # Security Policy -rtx is a convenient tool to manage developer tools, however its model is also open to potential risks. The following -are major areas of rtx and the security considerations currently being made and what needs to be made in the future. +mise is a convenient tool to manage developer tools, however its model is also open to potential risks. The following +are major areas of mise and the security considerations currently being made and what needs to be made in the future. -Please open a ticket or send me an email if you have thoughts on how rtx can be made more secure. +Please open a ticket or send me an email if you have thoughts on how mise can be made more secure. ## Core CLI Security -Development of the "core CLI" is done on jdx/rtx which only a single developer (me, @jdx) has access to. +Development of the "core CLI" is done on jdx/mise which only a single developer (me, @jdx) has access to. Other contributors may only submit contributions via public Pull Requests. Reducing the number of developers with access down to 1 minimizes the chance of keys being leaked. @@ -18,43 +18,43 @@ that can take over my account if need be. The dependencies in the core CLI are a security vector. I've tried to be judicious about what dependencies make it into the project. I only select dependencies with broad usage across the Rust community where possible. I'm open to PRs or suggestions on reducing dependency count even at the cost of functionality because it will make -rtx more secure. +mise more secure. -## rtx.jdx.dev +## mise.jdx.dev -rtx.jdx.dev is the asset host for rtx. It's used to host precompiled rtx CLI binaries, and hosts a "[VERSION](https://rtx.jdx.dev/VERSION)" -which rtx uses to occasionally check for a new version being released. Everything hosted there uses a single +mise.jdx.dev is the asset host for mise. It's used to host precompiled mise CLI binaries, and hosts a "[VERSION](https://mise.jdx.dev/VERSION)" +which mise uses to occasionally check for a new version being released. Everything hosted there uses a single vendor to reduce surface area. -## rtx plugins +## mise plugins Plugins are by far the biggest source of potential problems and where the most work still needs to be made. There are 3 types of plugins: -- [core](https://github.com/jdx/rtx/issues/236) - plugins that are hardcoded into the CLI. +- [core](https://github.com/jdx/mise/issues/236) - plugins that are hardcoded into the CLI. These are official plugins for the most common languages written in Rust. - community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. [See below](#rtx-plugins-github-org) for details. - external - plugins owned by other parties, these include plugins in the shorthand registry. These are no more - secure than installing any random tool from the internet. These receive a warning dialog when installed in rtx. + secure than installing any random tool from the internet. These receive a warning dialog when installed in mise. -Just because a plugin is inside of the shorthand registry (so you can run `rtx install foo@`, does not mean +Just because a plugin is inside of the shorthand registry (so you can run `mise install foo@`, does not mean I vouch for it. I have no idea who almost anyone that builds those plugins are. If it's coming from the rtx-plugins -GitHub org, you can have more trust in it. (See the owners with `rtx plugins ls-remote --urls`). +GitHub org, you can have more trust in it. (See the owners with `mise plugins ls-remote --urls`). -Over time we should be able to move more plugins into being fully maintained by rtx. I plan to add an -`RTX_PARANOID=1` env var that, when set, will make changes to make rtx behave as securely as possible +Over time we should be able to move more plugins into being fully maintained by mise. I plan to add an +`MISE_PARANOID=1` env var that, when set, will make changes to make mise behave as securely as possible (e.g.: only using core/rtx-plugins plugins, only allowing plugins that use GPG verification of assets). ## [rtx-plugins](https://github.com/rtx-plugins) GitHub org This is similar to but with the advantage of being more secure by keeping the contributor count minimal—currently only @jdx will be allowed to merge PRs. For this reason, plugins using this -organization will not receive a confirmation warning dialog when installed with rtx as they've been vetted by a +organization will not receive a confirmation warning dialog when installed with mise as they've been vetted by a trusted source. If you're a plugin maintainer that would like to move your repo to this org [please let me know](https://github.com/orgs/rtx-plugins/discussions). -Plugins can either retain compatibility with asdf or use rtx specific functionality—that's up to you. asdf-compatible plugins should use "asdf-" as the prefix and "rtx-" prefixed-plugins denote rtx-only compatibility. +Plugins can either retain compatibility with asdf or use mise specific functionality—that's up to you. asdf-compatible plugins should use "asdf-" as the prefix and "mise-" prefixed-plugins denote mise-only compatibility. ## Supported Versions @@ -62,7 +62,7 @@ The only supported version is the most recent one. ## Reporting a Vulnerability -Send an email to security@ +Send an email to security@ If you want, you may encrypt the message with GPG: diff --git a/completions/_rtx b/completions/_mise similarity index 71% rename from completions/_rtx rename to completions/_mise index 34f6aebd0..4d89f2a89 100644 --- a/completions/_rtx +++ b/completions/_mise @@ -1,5 +1,5 @@ -#compdef rtx -_rtx() { +#compdef mise +_mise() { typeset -A opt_args local context state line curcontext=$curcontext local ret=1 @@ -9,140 +9,140 @@ _rtx() { '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_cmds' \ + '1: :__mise_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (activate) __rtx_activate_cmd && ret=0 ;; - (a|aliases|alias) __rtx_alias_cmd && ret=0 ;; - (asdf) __rtx_asdf_cmd && ret=0 ;; - (bin-paths) __rtx_bin_paths_cmd && ret=0 ;; - (cache) __rtx_cache_cmd && ret=0 ;; - (complete|completions|completion) __rtx_completion_cmd && ret=0 ;; - (cfg|config) __rtx_config_cmd && ret=0 ;; - (current) __rtx_current_cmd && ret=0 ;; - (deactivate) __rtx_deactivate_cmd && ret=0 ;; - (direnv) __rtx_direnv_cmd && ret=0 ;; - (doctor) __rtx_doctor_cmd && ret=0 ;; - (e|env) __rtx_env_cmd && ret=0 ;; - (ev|env-vars) __rtx_env_vars_cmd && ret=0 ;; - (x|exec) __rtx_exec_cmd && ret=0 ;; - (g|global) __rtx_global_cmd && ret=0 ;; - (hook-env) __rtx_hook_env_cmd && ret=0 ;; - (hook-not-found) __rtx_hook_not_found_cmd && ret=0 ;; - (implode) __rtx_implode_cmd && ret=0 ;; - (i|install) __rtx_install_cmd && ret=0 ;; - (latest) __rtx_latest_cmd && ret=0 ;; - (ln|link) __rtx_link_cmd && ret=0 ;; - (l|local) __rtx_local_cmd && ret=0 ;; - (list|ls) __rtx_ls_cmd && ret=0 ;; - (list-all|list-remote|ls-remote) __rtx_ls_remote_cmd && ret=0 ;; - (outdated) __rtx_outdated_cmd && ret=0 ;; - (p|plugin|plugin-list|plugins) __rtx_plugins_cmd && ret=0 ;; - (prune) __rtx_prune_cmd && ret=0 ;; - (reshim) __rtx_reshim_cmd && ret=0 ;; - (r|run) __rtx_run_cmd && ret=0 ;; - (self-update) __rtx_self_update_cmd && ret=0 ;; - (settings) __rtx_settings_cmd && ret=0 ;; - (sh|shell) __rtx_shell_cmd && ret=0 ;; - (sync) __rtx_sync_cmd && ret=0 ;; - (t|tasks|task) __rtx_task_cmd && ret=0 ;; - (trust) __rtx_trust_cmd && ret=0 ;; - (remove|rm|uninstall) __rtx_uninstall_cmd && ret=0 ;; - (up|upgrade) __rtx_upgrade_cmd && ret=0 ;; - (u|use) __rtx_use_cmd && ret=0 ;; - (v|version) __rtx_version_cmd && ret=0 ;; - (w|watch) __rtx_watch_cmd && ret=0 ;; - (where) __rtx_where_cmd && ret=0 ;; - (which) __rtx_which_cmd && ret=0 ;; + (activate) __mise_activate_cmd && ret=0 ;; + (a|aliases|alias) __mise_alias_cmd && ret=0 ;; + (asdf) __mise_asdf_cmd && ret=0 ;; + (bin-paths) __mise_bin_paths_cmd && ret=0 ;; + (cache) __mise_cache_cmd && ret=0 ;; + (complete|completions|completion) __mise_completion_cmd && ret=0 ;; + (cfg|config) __mise_config_cmd && ret=0 ;; + (current) __mise_current_cmd && ret=0 ;; + (deactivate) __mise_deactivate_cmd && ret=0 ;; + (direnv) __mise_direnv_cmd && ret=0 ;; + (doctor) __mise_doctor_cmd && ret=0 ;; + (e|env) __mise_env_cmd && ret=0 ;; + (ev|env-vars) __mise_env_vars_cmd && ret=0 ;; + (x|exec) __mise_exec_cmd && ret=0 ;; + (g|global) __mise_global_cmd && ret=0 ;; + (hook-env) __mise_hook_env_cmd && ret=0 ;; + (hook-not-found) __mise_hook_not_found_cmd && ret=0 ;; + (implode) __mise_implode_cmd && ret=0 ;; + (i|install) __mise_install_cmd && ret=0 ;; + (latest) __mise_latest_cmd && ret=0 ;; + (ln|link) __mise_link_cmd && ret=0 ;; + (l|local) __mise_local_cmd && ret=0 ;; + (list|ls) __mise_ls_cmd && ret=0 ;; + (list-all|list-remote|ls-remote) __mise_ls_remote_cmd && ret=0 ;; + (outdated) __mise_outdated_cmd && ret=0 ;; + (p|plugin|plugin-list|plugins) __mise_plugins_cmd && ret=0 ;; + (prune) __mise_prune_cmd && ret=0 ;; + (reshim) __mise_reshim_cmd && ret=0 ;; + (r|run) __mise_run_cmd && ret=0 ;; + (self-update) __mise_self_update_cmd && ret=0 ;; + (settings) __mise_settings_cmd && ret=0 ;; + (sh|shell) __mise_shell_cmd && ret=0 ;; + (sync) __mise_sync_cmd && ret=0 ;; + (t|tasks|task) __mise_task_cmd && ret=0 ;; + (trust) __mise_trust_cmd && ret=0 ;; + (remove|rm|uninstall) __mise_uninstall_cmd && ret=0 ;; + (up|upgrade) __mise_upgrade_cmd && ret=0 ;; + (u|use) __mise_use_cmd && ret=0 ;; + (v|version) __mise_version_cmd && ret=0 ;; + (w|watch) __mise_watch_cmd && ret=0 ;; + (where) __mise_where_cmd && ret=0 ;; + (which) __mise_which_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_activate_cmd] )) || -__rtx_activate_cmd() { +(( $+functions[__mise_activate_cmd] )) || +__mise_activate_cmd() { _arguments -s -S \ '::shell_type:(bash fish nu xonsh zsh)' \ - '--status[Show "rtx\: @" message when changing directories]' \ + '--status[Show "mise\: @" message when changing directories]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_alias_cmd] )) || -__rtx_alias_cmd() { +(( $+functions[__mise_alias_cmd] )) || +__mise_alias_cmd() { _arguments -s -S \ - '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__rtx_plugins' \ + '(-p --plugin)'{-p,--plugin}'=[filter aliases by plugin]:plugin:__mise_plugins' \ '--no-header[Don'\''t show table header]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_alias_cmds' \ + '1: :__mise_alias_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (get) __rtx_alias_get_cmd && ret=0 ;; - (list|ls) __rtx_alias_ls_cmd && ret=0 ;; - (add|create|set) __rtx_alias_set_cmd && ret=0 ;; - (del|delete|remove|rm|unset) __rtx_alias_unset_cmd && ret=0 ;; + (get) __mise_alias_get_cmd && ret=0 ;; + (list|ls) __mise_alias_ls_cmd && ret=0 ;; + (add|create|set) __mise_alias_set_cmd && ret=0 ;; + (del|delete|remove|rm|unset) __mise_alias_unset_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_alias_get_cmd] )) || -__rtx_alias_get_cmd() { +(( $+functions[__mise_alias_get_cmd] )) || +__mise_alias_get_cmd() { _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ + ':plugin:__mise_plugins' \ + ':alias:__mise_aliases' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_alias_ls_cmd] )) || -__rtx_alias_ls_cmd() { +(( $+functions[__mise_alias_ls_cmd] )) || +__mise_alias_ls_cmd() { _arguments -s -S \ - '::plugin:__rtx_plugins' \ + '::plugin:__mise_plugins' \ '--no-header[Don'\''t show table header]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_alias_set_cmd] )) || -__rtx_alias_set_cmd() { +(( $+functions[__mise_alias_set_cmd] )) || +__mise_alias_set_cmd() { _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ + ':plugin:__mise_plugins' \ + ':alias:__mise_aliases' \ ':value:' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_alias_unset_cmd] )) || -__rtx_alias_unset_cmd() { +(( $+functions[__mise_alias_unset_cmd] )) || +__mise_alias_unset_cmd() { _arguments -s -S \ - ':plugin:__rtx_plugins' \ - ':alias:__rtx_aliases' \ + ':plugin:__mise_plugins' \ + ':alias:__mise_aliases' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_asdf_cmd] )) || -__rtx_asdf_cmd() { +(( $+functions[__mise_asdf_cmd] )) || +__mise_asdf_cmd() { _arguments -s -S \ '*::args:_cmdambivalent' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -150,46 +150,46 @@ __rtx_asdf_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_bin_paths_cmd] )) || -__rtx_bin_paths_cmd() { +(( $+functions[__mise_bin_paths_cmd] )) || +__mise_bin_paths_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_cache_cmd] )) || -__rtx_cache_cmd() { +(( $+functions[__mise_cache_cmd] )) || +__mise_cache_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_cache_cmds' \ + '1: :__mise_cache_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (c|clean|clear) __rtx_cache_clear_cmd && ret=0 ;; + (c|clean|clear) __mise_cache_clear_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_cache_clear_cmd] )) || -__rtx_cache_clear_cmd() { +(( $+functions[__mise_cache_clear_cmd] )) || +__mise_cache_clear_cmd() { _arguments -s -S \ - '*::plugin:__rtx_plugins' \ + '*::plugin:__mise_plugins' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_completion_cmd] )) || -__rtx_completion_cmd() { +(( $+functions[__mise_completion_cmd] )) || +__mise_completion_cmd() { _arguments -s -S \ '::shell:(bash fish zsh)' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -197,31 +197,31 @@ __rtx_completion_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_config_cmd] )) || -__rtx_config_cmd() { +(( $+functions[__mise_config_cmd] )) || +__mise_config_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_config_cmds' \ + '1: :__mise_config_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (g|generate) __rtx_config_generate_cmd && ret=0 ;; - (ls) __rtx_config_ls_cmd && ret=0 ;; + (g|generate) __mise_config_generate_cmd && ret=0 ;; + (ls) __mise_config_ls_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_config_generate_cmd] )) || -__rtx_config_generate_cmd() { +(( $+functions[__mise_config_generate_cmd] )) || +__mise_config_generate_cmd() { _arguments -s -S \ '(-o --output)'{-o,--output}'=[Output to file instead of stdout]:output:_files' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -229,8 +229,8 @@ __rtx_config_generate_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_config_ls_cmd] )) || -__rtx_config_ls_cmd() { +(( $+functions[__mise_config_ls_cmd] )) || +__mise_config_ls_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -238,91 +238,91 @@ __rtx_config_ls_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_current_cmd] )) || -__rtx_current_cmd() { +(( $+functions[__mise_current_cmd] )) || +__mise_current_cmd() { _arguments -s -S \ - '::plugin:__rtx_plugins' \ + '::plugin:__mise_plugins' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_deactivate_cmd] )) || -__rtx_deactivate_cmd() { +(( $+functions[__mise_deactivate_cmd] )) || +__mise_deactivate_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_direnv_cmd] )) || -__rtx_direnv_cmd() { +(( $+functions[__mise_direnv_cmd] )) || +__mise_direnv_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_direnv_cmds' \ + '1: :__mise_direnv_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (activate) __rtx_direnv_activate_cmd && ret=0 ;; - (envrc) __rtx_direnv_envrc_cmd && ret=0 ;; - (exec) __rtx_direnv_exec_cmd && ret=0 ;; + (activate) __mise_direnv_activate_cmd && ret=0 ;; + (envrc) __mise_direnv_envrc_cmd && ret=0 ;; + (exec) __mise_direnv_exec_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_direnv_activate_cmd] )) || -__rtx_direnv_activate_cmd() { +(( $+functions[__mise_direnv_activate_cmd] )) || +__mise_direnv_activate_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_direnv_envrc_cmd] )) || -__rtx_direnv_envrc_cmd() { +(( $+functions[__mise_direnv_envrc_cmd] )) || +__mise_direnv_envrc_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_direnv_exec_cmd] )) || -__rtx_direnv_exec_cmd() { +(( $+functions[__mise_direnv_exec_cmd] )) || +__mise_direnv_exec_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_doctor_cmd] )) || -__rtx_doctor_cmd() { +(( $+functions[__mise_doctor_cmd] )) || +__mise_doctor_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_env_cmd] )) || -__rtx_env_cmd() { +(( $+functions[__mise_env_cmd] )) || +__mise_env_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_env_vars_cmd] )) || -__rtx_env_vars_cmd() { +(( $+functions[__mise_env_vars_cmd] )) || +__mise_env_vars_cmd() { _arguments -s -S \ '--file=[The TOML file to update]:file:_files' \ '*--remove=[Remove the environment variable from config file]:remove:' \ @@ -332,10 +332,10 @@ __rtx_env_vars_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_exec_cmd] )) || -__rtx_exec_cmd() { +(( $+functions[__mise_exec_cmd] )) || +__mise_exec_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-c --command)'{-c,--command}'=[Command string to execute]:c:_cmdstring' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ @@ -344,10 +344,10 @@ __rtx_exec_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_global_cmd] )) || -__rtx_global_cmd() { +(( $+functions[__mise_global_cmd] )) || +__mise_global_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '--pin[Save exact version to \`~/.tool-versions\`]' \ '--fuzzy[Save fuzzy version to \`~/.tool-versions\`]' \ '*--remove=[Remove the plugin(s) from ~/.tool-versions]:remove:' \ @@ -357,18 +357,18 @@ __rtx_global_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_hook_env_cmd] )) || -__rtx_hook_env_cmd() { +(( $+functions[__mise_hook_env_cmd] )) || +__mise_hook_env_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ - '--status[Show "rtx\: @" message when changing directories]' \ + '--status[Show "mise\: @" message when changing directories]' \ '(-q --quiet)'{-q,--quiet}'[Hide warnings such as when a tool is not installed]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_hook_not_found_cmd] )) || -__rtx_hook_not_found_cmd() { +(( $+functions[__mise_hook_not_found_cmd] )) || +__mise_hook_not_found_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ ':bin:' \ @@ -377,8 +377,8 @@ __rtx_hook_not_found_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_implode_cmd] )) || -__rtx_implode_cmd() { +(( $+functions[__mise_implode_cmd] )) || +__mise_implode_cmd() { _arguments -s -S \ '--config[Also remove config directory]' \ '(-n --dry-run)'{-n,--dry-run}'[List directories that would be removed without actually removing them]' \ @@ -387,10 +387,10 @@ __rtx_implode_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_install_cmd] )) || -__rtx_install_cmd() { +(( $+functions[__mise_install_cmd] )) || +__mise_install_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ @@ -399,20 +399,20 @@ __rtx_install_cmd() { '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_latest_cmd] )) || -__rtx_latest_cmd() { +(( $+functions[__mise_latest_cmd] )) || +__mise_latest_cmd() { _arguments -s -S \ - ':tool:__rtx_tool_versions' \ + ':tool:__mise_tool_versions' \ '(-i --installed)'{-i,--installed}'[Show latest installed instead of available version]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_link_cmd] )) || -__rtx_link_cmd() { +(( $+functions[__mise_link_cmd] )) || +__mise_link_cmd() { _arguments -s -S \ - ':tool:__rtx_tool_versions' \ + ':tool:__mise_tool_versions' \ ':path:_directories' \ '(-f --force)'{-f,--force}'[Overwrite an existing tool version if it exists]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -420,13 +420,13 @@ __rtx_link_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_local_cmd] )) || -__rtx_local_cmd() { +(( $+functions[__mise_local_cmd] )) || +__mise_local_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-p --parent)'{-p,--parent}'[Recurse up to find a .tool-versions file rather than using the current directory only]' \ '--pin[Save exact version to \`.tool-versions\`]' \ - '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`rtx local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless RTX_ASDF_COMPAT=1]' \ + '--fuzzy[Save fuzzy version to \`.tool-versions\` e.g.\: \`mise local --fuzzy node@20\` will save \`node 20\` to .tool-versions This is the default behavior unless MISE_ASDF_COMPAT=1]' \ '*--remove=[Remove the plugin(s) from .tool-versions]:remove:' \ '--path[Get the path of the config file]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -434,44 +434,44 @@ __rtx_local_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_ls_cmd] )) || -__rtx_ls_cmd() { +(( $+functions[__mise_ls_cmd] )) || +__mise_ls_cmd() { _arguments -s -S \ - '*::plugin:__rtx_plugins' \ - '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.rtx.toml]' \ - '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.rtx.toml]' \ - '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed]' \ + '*::plugin:__mise_plugins' \ + '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.mise.toml]' \ + '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.mise.toml]' \ + '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed]' \ '(-J --json)'{-J,--json}'[Output in json format]' \ '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ - '--prefix=[Display versions matching this prefix]:prefix:__rtx_prefixes' \ + '--prefix=[Display versions matching this prefix]:prefix:__mise_prefixes' \ '--no-header[Don'\''t display headers]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_ls_remote_cmd] )) || -__rtx_ls_remote_cmd() { +(( $+functions[__mise_ls_remote_cmd] )) || +__mise_ls_remote_cmd() { _arguments -s -S \ - '::plugin:__rtx_plugins' \ + '::plugin:__mise_plugins' \ '--all[Show all installed plugins and versions]' \ - '::prefix:__rtx_prefixes' \ + '::prefix:__mise_prefixes' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_outdated_cmd] )) || -__rtx_outdated_cmd() { +(( $+functions[__mise_outdated_cmd] )) || +__mise_outdated_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_plugins_cmd] )) || -__rtx_plugins_cmd() { +(( $+functions[__mise_plugins_cmd] )) || +__mise_plugins_cmd() { _arguments -s -S \ '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ @@ -480,29 +480,29 @@ __rtx_plugins_cmd() { '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_plugins_cmds' \ + '1: :__mise_plugins_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (a|add|i|install) __rtx_plugins_install_cmd && ret=0 ;; - (ln|link) __rtx_plugins_link_cmd && ret=0 ;; - (list|ls) __rtx_plugins_ls_cmd && ret=0 ;; - (list-all|list-remote|ls-remote) __rtx_plugins_ls_remote_cmd && ret=0 ;; - (remove|rm|uninstall) __rtx_plugins_uninstall_cmd && ret=0 ;; - (upgrade|update) __rtx_plugins_update_cmd && ret=0 ;; + (a|add|i|install) __mise_plugins_install_cmd && ret=0 ;; + (ln|link) __mise_plugins_link_cmd && ret=0 ;; + (list|ls) __mise_plugins_ls_cmd && ret=0 ;; + (list-all|list-remote|ls-remote) __mise_plugins_ls_remote_cmd && ret=0 ;; + (remove|rm|uninstall) __mise_plugins_uninstall_cmd && ret=0 ;; + (upgrade|update) __mise_plugins_update_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_plugins_install_cmd] )) || -__rtx_plugins_install_cmd() { +(( $+functions[__mise_plugins_install_cmd] )) || +__mise_plugins_install_cmd() { _arguments -s -S \ - ':new_plugin:__rtx_all_plugins' \ + ':new_plugin:__mise_all_plugins' \ '::git_url:_urls' \ '(-f --force)'{-f,--force}'[Reinstall even if plugin exists]' \ '(-a --all)'{-a,--all}'[Install all missing plugins]' \ @@ -511,8 +511,8 @@ __rtx_plugins_install_cmd() { '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_plugins_link_cmd] )) || -__rtx_plugins_link_cmd() { +(( $+functions[__mise_plugins_link_cmd] )) || +__mise_plugins_link_cmd() { _arguments -s -S \ ':name:' \ '::path:_directories' \ @@ -522,8 +522,8 @@ __rtx_plugins_link_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_plugins_ls_cmd] )) || -__rtx_plugins_ls_cmd() { +(( $+functions[__mise_plugins_ls_cmd] )) || +__mise_plugins_ls_cmd() { _arguments -s -S \ '(-c --core)'{-c,--core}'[The built-in plugins only]' \ '--user[List installed plugins]' \ @@ -533,8 +533,8 @@ __rtx_plugins_ls_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_plugins_ls_remote_cmd] )) || -__rtx_plugins_ls_remote_cmd() { +(( $+functions[__mise_plugins_ls_remote_cmd] )) || +__mise_plugins_ls_remote_cmd() { _arguments -s -S \ '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ @@ -543,10 +543,10 @@ __rtx_plugins_ls_remote_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_plugins_uninstall_cmd] )) || -__rtx_plugins_uninstall_cmd() { +(( $+functions[__mise_plugins_uninstall_cmd] )) || +__mise_plugins_uninstall_cmd() { _arguments -s -S \ - '*::plugin:__rtx_plugins' \ + '*::plugin:__mise_plugins' \ '(-p --purge)'{-p,--purge}'[Also remove the plugin'\''s installs, downloads, and cache]' \ '(-a --all)'{-a,--all}'[Remove all plugins]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -554,53 +554,53 @@ __rtx_plugins_uninstall_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_plugins_update_cmd] )) || -__rtx_plugins_update_cmd() { +(( $+functions[__mise_plugins_update_cmd] )) || +__mise_plugins_update_cmd() { _arguments -s -S \ - '*::plugin:__rtx_plugins' \ + '*::plugin:__mise_plugins' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_prune_cmd] )) || -__rtx_prune_cmd() { +(( $+functions[__mise_prune_cmd] )) || +__mise_prune_cmd() { _arguments -s -S \ - '*::plugin:__rtx_plugins' \ + '*::plugin:__mise_plugins' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_reshim_cmd] )) || -__rtx_reshim_cmd() { +(( $+functions[__mise_reshim_cmd] )) || +__mise_reshim_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_run_cmd] )) || -__rtx_run_cmd() { +(( $+functions[__mise_run_cmd] )) || +__mise_run_cmd() { _arguments -s -S \ - '::task:__rtx_tasks' \ + '::task:__mise_tasks' \ '*::args:' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ '(-f --force)'{-f,--force}'[Force the task to run even if outputs are up to date]' \ '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the task'\''s label]' \ '(-i --interleave)'{-i,--interleave}'[Print directly to stdout/stderr instead of by line]' \ - '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__rtx_tool_versions' \ + '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__mise_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_self_update_cmd] )) || -__rtx_self_update_cmd() { +(( $+functions[__mise_self_update_cmd] )) || +__mise_self_update_cmd() { _arguments -s -S \ '(-f --force)'{-f,--force}'[Update even if already up to date]' \ '--no-plugins[Disable auto-updating plugins]' \ @@ -610,70 +610,70 @@ __rtx_self_update_cmd() { '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' } -(( $+functions[__rtx_settings_cmd] )) || -__rtx_settings_cmd() { +(( $+functions[__mise_settings_cmd] )) || +__mise_settings_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_settings_cmds' \ + '1: :__mise_settings_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (get) __rtx_settings_get_cmd && ret=0 ;; - (list|ls) __rtx_settings_ls_cmd && ret=0 ;; - (add|create|set) __rtx_settings_set_cmd && ret=0 ;; - (del|delete|remove|rm|unset) __rtx_settings_unset_cmd && ret=0 ;; + (get) __mise_settings_get_cmd && ret=0 ;; + (list|ls) __mise_settings_ls_cmd && ret=0 ;; + (add|create|set) __mise_settings_set_cmd && ret=0 ;; + (del|delete|remove|rm|unset) __mise_settings_unset_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_settings_get_cmd] )) || -__rtx_settings_get_cmd() { +(( $+functions[__mise_settings_get_cmd] )) || +__mise_settings_get_cmd() { _arguments -s -S \ - ':setting:__rtx_settings' \ + ':setting:__mise_settings' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_settings_ls_cmd] )) || -__rtx_settings_ls_cmd() { +(( $+functions[__mise_settings_ls_cmd] )) || +__mise_settings_ls_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_settings_set_cmd] )) || -__rtx_settings_set_cmd() { +(( $+functions[__mise_settings_set_cmd] )) || +__mise_settings_set_cmd() { _arguments -s -S \ - ':setting:__rtx_settings' \ + ':setting:__mise_settings' \ ':value:' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_settings_unset_cmd] )) || -__rtx_settings_unset_cmd() { +(( $+functions[__mise_settings_unset_cmd] )) || +__mise_settings_unset_cmd() { _arguments -s -S \ - ':setting:__rtx_settings' \ + ':setting:__mise_settings' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_shell_cmd] )) || -__rtx_shell_cmd() { +(( $+functions[__mise_shell_cmd] )) || +__mise_shell_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '(-u --unset)'{-u,--unset}'[Removes a previously set version]' \ @@ -682,30 +682,30 @@ __rtx_shell_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_sync_cmd] )) || -__rtx_sync_cmd() { +(( $+functions[__mise_sync_cmd] )) || +__mise_sync_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_sync_cmds' \ + '1: :__mise_sync_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (node) __rtx_sync_node_cmd && ret=0 ;; - (python) __rtx_sync_python_cmd && ret=0 ;; + (node) __mise_sync_node_cmd && ret=0 ;; + (python) __mise_sync_python_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_sync_node_cmd] )) || -__rtx_sync_node_cmd() { +(( $+functions[__mise_sync_node_cmd] )) || +__mise_sync_node_cmd() { _arguments -s -S \ '--brew[Get tool versions from Homebrew]' \ '--nvm[Get tool versions from nvm]' \ @@ -715,8 +715,8 @@ __rtx_sync_node_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_sync_python_cmd] )) || -__rtx_sync_python_cmd() { +(( $+functions[__mise_sync_python_cmd] )) || +__mise_sync_python_cmd() { _arguments -s -S \ '--pyenv[Get tool versions from pyenv]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -724,8 +724,8 @@ __rtx_sync_python_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_task_cmd] )) || -__rtx_task_cmd() { +(( $+functions[__mise_task_cmd] )) || +__mise_task_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '--hidden[Show hidden tasks]' \ @@ -733,34 +733,34 @@ __rtx_task_cmd() { '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__rtx_task_cmds' \ + '1: :__mise_task_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) - curcontext="${curcontext%:*:*}:rtx-cmd-$words[1]:" + curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (edit) __rtx_task_edit_cmd && ret=0 ;; - (ls) __rtx_task_ls_cmd && ret=0 ;; - (r|run) __rtx_task_run_cmd && ret=0 ;; + (edit) __mise_task_edit_cmd && ret=0 ;; + (ls) __mise_task_ls_cmd && ret=0 ;; + (r|run) __mise_task_run_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__rtx_task_edit_cmd] )) || -__rtx_task_edit_cmd() { +(( $+functions[__mise_task_edit_cmd] )) || +__mise_task_edit_cmd() { _arguments -s -S \ - ':task:__rtx_tasks' \ + ':task:__mise_tasks' \ '(-p --path)'{-p,--path}'[Display the path to the task instead of editing it]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_task_ls_cmd] )) || -__rtx_task_ls_cmd() { +(( $+functions[__mise_task_ls_cmd] )) || +__mise_task_ls_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '--hidden[Show hidden tasks]' \ @@ -769,25 +769,25 @@ __rtx_task_ls_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_task_run_cmd] )) || -__rtx_task_run_cmd() { +(( $+functions[__mise_task_run_cmd] )) || +__mise_task_run_cmd() { _arguments -s -S \ - '::task:__rtx_tasks' \ + '::task:__mise_tasks' \ '*::args:' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ '(-f --force)'{-f,--force}'[Force the task to run even if outputs are up to date]' \ '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the task'\''s label]' \ '(-i --interleave)'{-i,--interleave}'[Print directly to stdout/stderr instead of by line]' \ - '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__rtx_tool_versions' \ + '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__mise_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_trust_cmd] )) || -__rtx_trust_cmd() { +(( $+functions[__mise_trust_cmd] )) || +__mise_trust_cmd() { _arguments -s -S \ '::config_file:_files' \ '(-a --all)'{-a,--all}'[Trust all config files in the current directory and its parents]' \ @@ -797,10 +797,10 @@ __rtx_trust_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_uninstall_cmd] )) || -__rtx_uninstall_cmd() { +(( $+functions[__mise_uninstall_cmd] )) || +__mise_uninstall_cmd() { _arguments -s -S \ - '*::installed_tool:__rtx_installed_tool_versions' \ + '*::installed_tool:__mise_installed_tool_versions' \ '(-a --all)'{-a,--all}'[Delete all installed versions]' \ '(-n --dry-run)'{-n,--dry-run}'[Do not actually delete anything]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -808,10 +808,10 @@ __rtx_uninstall_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_upgrade_cmd] )) || -__rtx_upgrade_cmd() { +(( $+functions[__mise_upgrade_cmd] )) || +__mise_upgrade_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-n --dry-run)'{-n,--dry-run}'[Just print what would be done, don'\''t actually do it]' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '(-i --interactive)'{-i,--interactive}'[Display multiselect menu to choose which tools to upgrade]' \ @@ -821,36 +821,36 @@ __rtx_upgrade_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_use_cmd] )) || -__rtx_use_cmd() { +(( $+functions[__mise_use_cmd] )) || +__mise_use_cmd() { _arguments -s -S \ - '*::tool:__rtx_tool_versions' \ + '*::tool:__mise_tool_versions' \ '(-f --force)'{-f,--force}'[Force reinstall even if already installed]' \ '--fuzzy[Save fuzzy version to config file]' \ - '(-g --global)'{-g,--global}'[Use the global config file (~/.config/rtx/config.toml) instead of the local one]' \ - '(-e --env)'{-e,--env}'=[Modify an environment-specific config file like .rtx..toml]:env:' \ + '(-g --global)'{-g,--global}'[Use the global config file (~/.config/mise/config.toml) instead of the local one]' \ + '(-e --env)'{-e,--env}'=[Modify an environment-specific config file like .mise..toml]:env:' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ '*--remove=[Remove the tool(s) from config file]:remove:' \ - '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions]:path:_files' \ + '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions]:path:_files' \ '--pin[Save exact version to config file]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_version_cmd] )) || -__rtx_version_cmd() { +(( $+functions[__mise_version_cmd] )) || +__mise_version_cmd() { _arguments -s -S \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_watch_cmd] )) || -__rtx_watch_cmd() { +(( $+functions[__mise_watch_cmd] )) || +__mise_watch_cmd() { _arguments -s -S \ - '*'{-t,--task}'=[Task to run]:task:__rtx_tasks' \ + '*'{-t,--task}'=[Task to run]:task:__mise_tasks' \ '*::args:' \ '*'{-g,--glob}'=[Files to watch]:glob:' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -858,47 +858,47 @@ __rtx_watch_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_where_cmd] )) || -__rtx_where_cmd() { +(( $+functions[__mise_where_cmd] )) || +__mise_where_cmd() { _arguments -s -S \ - ':tool:__rtx_tool_versions' \ + ':tool:__mise_tool_versions' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_which_cmd] )) || -__rtx_which_cmd() { +(( $+functions[__mise_which_cmd] )) || +__mise_which_cmd() { _arguments -s -S \ ':bin_name:' \ '--plugin[Show the plugin name instead of the path]' \ '--version[Show the version instead of the path]' \ - '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__rtx_tool_versions' \ + '(-t --tool)'{-t,--tool}'=[Use a specific tool@version]:tool:__mise_tool_versions' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__rtx_cmds] )) || -__rtx_cmds() { +(( $+functions[__mise_cmds] )) || +__mise_cmds() { local commands; commands=( - 'activate:Initializes rtx in the current shell session' + 'activate:Initializes mise in the current shell session' {a,alias}':Manage aliases' 'bin-paths:List all the active runtime bin paths' - 'cache:Manage the rtx cache' + 'cache:Manage the mise cache' 'completion:Generate shell completions' {cfg,config}':\[experimental\] Manage config files' 'current:Shows current active and installed runtime versions' - 'deactivate:Disable rtx for current shell session' - 'direnv:Output direnv function to use rtx inside direnv' - 'doctor:Check rtx installation for possible problems.' - {e,env}':Exports env vars to activate rtx a single time' + 'deactivate:Disable mise for current shell session' + 'direnv:Output direnv function to use mise inside direnv' + 'doctor:Check mise installation for possible problems.' + {e,env}':Exports env vars to activate mise a single time' {ev,env-vars}':Manage environment variables' {x,exec}':Execute a command with tool(s) set' - 'implode:Removes rtx CLI and all related data' + 'implode:Removes mise CLI and all related data' {i,install}':Install a tool version' 'latest:Gets the latest available version for a plugin' - {ln,link}':Symlinks a tool version into rtx' + {ln,link}':Symlinks a tool version into mise' {list,ls}':List installed and/or currently selected tool versions' 'ls-remote:List runtime versions available for install' 'outdated:Shows outdated tool versions' @@ -906,24 +906,24 @@ __rtx_cmds() { 'prune:Delete unused versions of tools' 'reshim:rebuilds the shim farm' {r,run}':\[experimental\] Run a task' - 'self-update:Updates rtx itself' + 'self-update:Updates mise itself' 'settings:Manage settings' {sh,shell}':Sets a tool version for the current shell session' - 'sync:Add tool versions from external tools to rtx' + 'sync:Add tool versions from external tools to mise' {t,task}':\[experimental\] Manage tasks' 'trust:Marks a config file as trusted' {remove,rm,uninstall}':Removes runtime versions' {up,upgrade}':Upgrades outdated tool versions' {u,use}':Change the active version of a tool locally or globally.' - 'version:Show rtx version' + 'version:Show mise version' {w,watch}':\[experimental\] Run a task watching for changes' 'where:Display the installation path for a runtime' 'which:Shows the path that a bin name points to' ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_alias_cmds] )) || -__rtx_alias_cmds() { +(( $+functions[__mise_alias_cmds] )) || +__mise_alias_cmds() { local commands; commands=( 'get:Show an alias for a plugin' {list,ls}':List aliases' @@ -932,33 +932,33 @@ __rtx_alias_cmds() { ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_cache_cmds] )) || -__rtx_cache_cmds() { +(( $+functions[__mise_cache_cmds] )) || +__mise_cache_cmds() { local commands; commands=( - {c,clear}':Deletes all cache files in rtx' + {c,clear}':Deletes all cache files in mise' ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_config_cmds] )) || -__rtx_config_cmds() { +(( $+functions[__mise_config_cmds] )) || +__mise_config_cmds() { local commands; commands=( - {g,generate}':\[experimental\] Generate an .rtx.toml file' + {g,generate}':\[experimental\] Generate an .mise.toml file' 'ls:\[experimental\] List config files currently in use' ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_direnv_cmds] )) || -__rtx_direnv_cmds() { +(( $+functions[__mise_direnv_cmds] )) || +__mise_direnv_cmds() { local commands; commands=( - 'activate:Output direnv function to use rtx inside direnv' + 'activate:Output direnv function to use mise inside direnv' ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_plugins_cmds] )) || -__rtx_plugins_cmds() { +(( $+functions[__mise_plugins_cmds] )) || +__mise_plugins_cmds() { local commands; commands=( {a,add,i,install}':Install a plugin' - {ln,link}':Symlinks a plugin into rtx' + {ln,link}':Symlinks a plugin into mise' {list,ls}':List installed plugins' {list-all,list-remote,ls-remote}':List all available remote plugins' {remove,rm,uninstall}':Removes a plugin' @@ -966,8 +966,8 @@ __rtx_plugins_cmds() { ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_settings_cmds] )) || -__rtx_settings_cmds() { +(( $+functions[__mise_settings_cmds] )) || +__mise_settings_cmds() { local commands; commands=( 'get:Show a current setting' {list,ls}':Show current settings' @@ -976,16 +976,16 @@ __rtx_settings_cmds() { ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_sync_cmds] )) || -__rtx_sync_cmds() { +(( $+functions[__mise_sync_cmds] )) || +__mise_sync_cmds() { local commands; commands=( - 'node:Symlinks all tool versions from an external tool into rtx' - 'python:Symlinks all tool versions from an external tool into rtx' + 'node:Symlinks all tool versions from an external tool into mise' + 'python:Symlinks all tool versions from an external tool into mise' ) _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_task_cmds] )) || -__rtx_task_cmds() { +(( $+functions[__mise_task_cmds] )) || +__mise_task_cmds() { local commands; commands=( 'edit:\[experimental\] Edit a task with \$EDITOR' 'ls:\[experimental\] List available tasks to execute' @@ -994,68 +994,68 @@ __rtx_task_cmds() { _describe -t commands 'command' commands "$@" } -(( $+functions[__rtx_tool_versions] )) || -__rtx_tool_versions() { +(( $+functions[__mise_tool_versions] )) || +__mise_tool_versions() { if compset -P '*@'; then - local -a tool_versions; tool_versions=($(rtx ls-remote ${words[CURRENT]})) + local -a tool_versions; tool_versions=($(mise ls-remote ${words[CURRENT]})) _wanted tool_version expl 'version of tool' \ compadd -a tool_versions -o nosort else - local -a plugins; plugins=($(rtx plugins --core --user)) + local -a plugins; plugins=($(mise plugins --core --user)) _wanted plugin expl 'plugin name' \ compadd -S '@' -a plugins fi } -(( $+functions[__rtx_installed_tool_versions] )) || -__rtx_installed_tool_versions() { +(( $+functions[__mise_installed_tool_versions] )) || +__mise_installed_tool_versions() { if compset -P '*@'; then local plugin; plugin=${words[CURRENT]%%@*} - local -a installed_tool_versions; installed_tool_versions=($(rtx ls --installed $plugin | awk '{print $2}')) + local -a installed_tool_versions; installed_tool_versions=($(mise ls --installed $plugin | awk '{print $2}')) _wanted installed_tool_version expl 'version of tool' \ compadd -a installed_tool_versions -o nosort else - local -a plugins; plugins=($(rtx plugins --core --user)) + local -a plugins; plugins=($(mise plugins --core --user)) _wanted plugin expl 'plugin name' \ compadd -S '@' -a plugins fi } -(( $+functions[__rtx_plugins] )) || -__rtx_plugins() { - local -a plugins; plugins=($(rtx plugins --core --user)) +(( $+functions[__mise_plugins] )) || +__mise_plugins() { + local -a plugins; plugins=($(mise plugins --core --user)) _describe -t plugins 'plugin' plugins "$@" } -(( $+functions[__rtx_all_plugins] )) || -__rtx_all_plugins() { - local -a all_plugins; all_plugins=($(rtx plugins --all)) +(( $+functions[__mise_all_plugins] )) || +__mise_all_plugins() { + local -a all_plugins; all_plugins=($(mise plugins --all)) _describe -t all_plugins 'all_plugins' all_plugins "$@" } -(( $+functions[__rtx_aliases] )) || -__rtx_aliases() { - local -a aliases; aliases=($(rtx aliases ls ${words[CURRENT-1]} | awk '{print $2}')) +(( $+functions[__mise_aliases] )) || +__mise_aliases() { + local -a aliases; aliases=($(mise aliases ls ${words[CURRENT-1]} | awk '{print $2}')) _describe -t aliases 'alias' aliases "$@" } -(( $+functions[__rtx_settings] )) || -__rtx_settings() { - local -a settings; settings=($(rtx settings ls | awk '{print $1}')) +(( $+functions[__mise_settings] )) || +__mise_settings() { + local -a settings; settings=($(mise settings ls | awk '{print $1}')) _describe -t settings 'setting' settings "$@" } -(( $+functions[__rtx_tasks] )) || -__rtx_tasks() { - local -a tasks; tasks=($(rtx tasks ls --no-header | awk '{print $1}')) +(( $+functions[__mise_tasks] )) || +__mise_tasks() { + local -a tasks; tasks=($(mise tasks ls --no-header | awk '{print $1}')) _describe -t tasks 'task' tasks "$@" } -(( $+functions[__rtx_prefixes] )) || -__rtx_prefixes() { +(( $+functions[__mise_prefixes] )) || +__mise_prefixes() { if [[ CURRENT -gt 2 ]]; then - local -a prefixes; prefixes=($(rtx ls-remote ${words[CURRENT-1]})) + local -a prefixes; prefixes=($(mise ls-remote ${words[CURRENT-1]})) _describe -t prefixes 'prefix' prefixes "$@" fi } -if [ "$funcstack[1]" = "_rtx" ]; then - _rtx "$@" +if [ "$funcstack[1]" = "_mise" ]; then + _mise "$@" else - compdef _rtx rtx + compdef _mise mise fi # vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/completions/rtx.bash b/completions/mise.bash similarity index 85% rename from completions/rtx.bash rename to completions/mise.bash index 00ae8d630..fc4aa580f 100644 --- a/completions/rtx.bash +++ b/completions/mise.bash @@ -1,4 +1,4 @@ -_rtx() { +_mise() { local i cur prev opts cmd COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" @@ -10,688 +10,688 @@ _rtx() { do case "${cmd},${i}" in ",$1") - cmd="rtx" + cmd="mise" ;; - rtx,a) - cmd="rtx__alias" + mise,a) + cmd="mise__alias" ;; - rtx,activate) - cmd="rtx__activate" + mise,activate) + cmd="mise__activate" ;; - rtx,alias) - cmd="rtx__alias" + mise,alias) + cmd="mise__alias" ;; - rtx,asdf) - cmd="rtx__asdf" + mise,asdf) + cmd="mise__asdf" ;; - rtx,bin-paths) - cmd="rtx__bin__paths" + mise,bin-paths) + cmd="mise__bin__paths" ;; - rtx,cache) - cmd="rtx__cache" + mise,cache) + cmd="mise__cache" ;; - rtx,cfg) - cmd="rtx__config" + mise,cfg) + cmd="mise__config" ;; - rtx,completion) - cmd="rtx__completion" + mise,completion) + cmd="mise__completion" ;; - rtx,config) - cmd="rtx__config" + mise,config) + cmd="mise__config" ;; - rtx,current) - cmd="rtx__current" + mise,current) + cmd="mise__current" ;; - rtx,deactivate) - cmd="rtx__deactivate" + mise,deactivate) + cmd="mise__deactivate" ;; - rtx,direnv) - cmd="rtx__direnv" + mise,direnv) + cmd="mise__direnv" ;; - rtx,doctor) - cmd="rtx__doctor" + mise,doctor) + cmd="mise__doctor" ;; - rtx,e) - cmd="rtx__env" + mise,e) + cmd="mise__env" ;; - rtx,env) - cmd="rtx__env" + mise,env) + cmd="mise__env" ;; - rtx,env-vars) - cmd="rtx__env__vars" + mise,env-vars) + cmd="mise__env__vars" ;; - rtx,ev) - cmd="rtx__env__vars" + mise,ev) + cmd="mise__env__vars" ;; - rtx,exec) - cmd="rtx__exec" + mise,exec) + cmd="mise__exec" ;; - rtx,global) - cmd="rtx__global" + mise,global) + cmd="mise__global" ;; - rtx,help) - cmd="rtx__help" + mise,help) + cmd="mise__help" ;; - rtx,hook-env) - cmd="rtx__hook__env" + mise,hook-env) + cmd="mise__hook__env" ;; - rtx,hook-not-found) - cmd="rtx__hook__not__found" + mise,hook-not-found) + cmd="mise__hook__not__found" ;; - rtx,i) - cmd="rtx__install" + mise,i) + cmd="mise__install" ;; - rtx,implode) - cmd="rtx__implode" + mise,implode) + cmd="mise__implode" ;; - rtx,install) - cmd="rtx__install" + mise,install) + cmd="mise__install" ;; - rtx,latest) - cmd="rtx__latest" + mise,latest) + cmd="mise__latest" ;; - rtx,link) - cmd="rtx__link" + mise,link) + cmd="mise__link" ;; - rtx,list) - cmd="rtx__ls" + mise,list) + cmd="mise__ls" ;; - rtx,ln) - cmd="rtx__link" + mise,ln) + cmd="mise__link" ;; - rtx,local) - cmd="rtx__local" + mise,local) + cmd="mise__local" ;; - rtx,ls) - cmd="rtx__ls" + mise,ls) + cmd="mise__ls" ;; - rtx,ls-remote) - cmd="rtx__ls__remote" + mise,ls-remote) + cmd="mise__ls__remote" ;; - rtx,outdated) - cmd="rtx__outdated" + mise,outdated) + cmd="mise__outdated" ;; - rtx,p) - cmd="rtx__plugins" + mise,p) + cmd="mise__plugins" ;; - rtx,plugins) - cmd="rtx__plugins" + mise,plugins) + cmd="mise__plugins" ;; - rtx,prune) - cmd="rtx__prune" + mise,prune) + cmd="mise__prune" ;; - rtx,r) - cmd="rtx__run" + mise,r) + cmd="mise__run" ;; - rtx,remove) - cmd="rtx__uninstall" + mise,remove) + cmd="mise__uninstall" ;; - rtx,render-completion) - cmd="rtx__render__completion" + mise,render-completion) + cmd="mise__render__completion" ;; - rtx,render-help) - cmd="rtx__render__help" + mise,render-help) + cmd="mise__render__help" ;; - rtx,render-mangen) - cmd="rtx__render__mangen" + mise,render-mangen) + cmd="mise__render__mangen" ;; - rtx,reshim) - cmd="rtx__reshim" + mise,reshim) + cmd="mise__reshim" ;; - rtx,rm) - cmd="rtx__uninstall" + mise,rm) + cmd="mise__uninstall" ;; - rtx,run) - cmd="rtx__run" + mise,run) + cmd="mise__run" ;; - rtx,self-update) - cmd="rtx__self__update" + mise,self-update) + cmd="mise__self__update" ;; - rtx,settings) - cmd="rtx__settings" + mise,settings) + cmd="mise__settings" ;; - rtx,sh) - cmd="rtx__shell" + mise,sh) + cmd="mise__shell" ;; - rtx,shell) - cmd="rtx__shell" + mise,shell) + cmd="mise__shell" ;; - rtx,sync) - cmd="rtx__sync" + mise,sync) + cmd="mise__sync" ;; - rtx,t) - cmd="rtx__task" + mise,t) + cmd="mise__task" ;; - rtx,task) - cmd="rtx__task" + mise,task) + cmd="mise__task" ;; - rtx,trust) - cmd="rtx__trust" + mise,trust) + cmd="mise__trust" ;; - rtx,u) - cmd="rtx__use" + mise,u) + cmd="mise__use" ;; - rtx,uninstall) - cmd="rtx__uninstall" + mise,uninstall) + cmd="mise__uninstall" ;; - rtx,up) - cmd="rtx__upgrade" + mise,up) + cmd="mise__upgrade" ;; - rtx,upgrade) - cmd="rtx__upgrade" + mise,upgrade) + cmd="mise__upgrade" ;; - rtx,use) - cmd="rtx__use" + mise,use) + cmd="mise__use" ;; - rtx,version) - cmd="rtx__version" + mise,version) + cmd="mise__version" ;; - rtx,w) - cmd="rtx__watch" + mise,w) + cmd="mise__watch" ;; - rtx,watch) - cmd="rtx__watch" + mise,watch) + cmd="mise__watch" ;; - rtx,where) - cmd="rtx__where" + mise,where) + cmd="mise__where" ;; - rtx,which) - cmd="rtx__which" + mise,which) + cmd="mise__which" ;; - rtx,x) - cmd="rtx__exec" + mise,x) + cmd="mise__exec" ;; - rtx__alias,add) - cmd="rtx__alias__set" + mise__alias,add) + cmd="mise__alias__set" ;; - rtx__alias,create) - cmd="rtx__alias__set" + mise__alias,create) + cmd="mise__alias__set" ;; - rtx__alias,del) - cmd="rtx__alias__unset" + mise__alias,del) + cmd="mise__alias__unset" ;; - rtx__alias,delete) - cmd="rtx__alias__unset" + mise__alias,delete) + cmd="mise__alias__unset" ;; - rtx__alias,get) - cmd="rtx__alias__get" + mise__alias,get) + cmd="mise__alias__get" ;; - rtx__alias,help) - cmd="rtx__alias__help" + mise__alias,help) + cmd="mise__alias__help" ;; - rtx__alias,list) - cmd="rtx__alias__ls" + mise__alias,list) + cmd="mise__alias__ls" ;; - rtx__alias,ls) - cmd="rtx__alias__ls" + mise__alias,ls) + cmd="mise__alias__ls" ;; - rtx__alias,remove) - cmd="rtx__alias__unset" + mise__alias,remove) + cmd="mise__alias__unset" ;; - rtx__alias,rm) - cmd="rtx__alias__unset" + mise__alias,rm) + cmd="mise__alias__unset" ;; - rtx__alias,set) - cmd="rtx__alias__set" + mise__alias,set) + cmd="mise__alias__set" ;; - rtx__alias,unset) - cmd="rtx__alias__unset" + mise__alias,unset) + cmd="mise__alias__unset" ;; - rtx__alias__help,get) - cmd="rtx__alias__help__get" + mise__alias__help,get) + cmd="mise__alias__help__get" ;; - rtx__alias__help,help) - cmd="rtx__alias__help__help" + mise__alias__help,help) + cmd="mise__alias__help__help" ;; - rtx__alias__help,ls) - cmd="rtx__alias__help__ls" + mise__alias__help,ls) + cmd="mise__alias__help__ls" ;; - rtx__alias__help,set) - cmd="rtx__alias__help__set" + mise__alias__help,set) + cmd="mise__alias__help__set" ;; - rtx__alias__help,unset) - cmd="rtx__alias__help__unset" + mise__alias__help,unset) + cmd="mise__alias__help__unset" ;; - rtx__cache,c) - cmd="rtx__cache__clear" + mise__cache,c) + cmd="mise__cache__clear" ;; - rtx__cache,clear) - cmd="rtx__cache__clear" + mise__cache,clear) + cmd="mise__cache__clear" ;; - rtx__cache,help) - cmd="rtx__cache__help" + mise__cache,help) + cmd="mise__cache__help" ;; - rtx__cache__help,clear) - cmd="rtx__cache__help__clear" + mise__cache__help,clear) + cmd="mise__cache__help__clear" ;; - rtx__cache__help,help) - cmd="rtx__cache__help__help" + mise__cache__help,help) + cmd="mise__cache__help__help" ;; - rtx__config,g) - cmd="rtx__config__generate" + mise__config,g) + cmd="mise__config__generate" ;; - rtx__config,generate) - cmd="rtx__config__generate" + mise__config,generate) + cmd="mise__config__generate" ;; - rtx__config,help) - cmd="rtx__config__help" + mise__config,help) + cmd="mise__config__help" ;; - rtx__config,ls) - cmd="rtx__config__ls" + mise__config,ls) + cmd="mise__config__ls" ;; - rtx__config__help,generate) - cmd="rtx__config__help__generate" + mise__config__help,generate) + cmd="mise__config__help__generate" ;; - rtx__config__help,help) - cmd="rtx__config__help__help" + mise__config__help,help) + cmd="mise__config__help__help" ;; - rtx__config__help,ls) - cmd="rtx__config__help__ls" + mise__config__help,ls) + cmd="mise__config__help__ls" ;; - rtx__direnv,activate) - cmd="rtx__direnv__activate" + mise__direnv,activate) + cmd="mise__direnv__activate" ;; - rtx__direnv,envrc) - cmd="rtx__direnv__envrc" + mise__direnv,envrc) + cmd="mise__direnv__envrc" ;; - rtx__direnv,exec) - cmd="rtx__direnv__exec" + mise__direnv,exec) + cmd="mise__direnv__exec" ;; - rtx__direnv,help) - cmd="rtx__direnv__help" + mise__direnv,help) + cmd="mise__direnv__help" ;; - rtx__direnv__help,activate) - cmd="rtx__direnv__help__activate" + mise__direnv__help,activate) + cmd="mise__direnv__help__activate" ;; - rtx__direnv__help,envrc) - cmd="rtx__direnv__help__envrc" + mise__direnv__help,envrc) + cmd="mise__direnv__help__envrc" ;; - rtx__direnv__help,exec) - cmd="rtx__direnv__help__exec" + mise__direnv__help,exec) + cmd="mise__direnv__help__exec" ;; - rtx__direnv__help,help) - cmd="rtx__direnv__help__help" + mise__direnv__help,help) + cmd="mise__direnv__help__help" ;; - rtx__help,activate) - cmd="rtx__help__activate" + mise__help,activate) + cmd="mise__help__activate" ;; - rtx__help,alias) - cmd="rtx__help__alias" + mise__help,alias) + cmd="mise__help__alias" ;; - rtx__help,asdf) - cmd="rtx__help__asdf" + mise__help,asdf) + cmd="mise__help__asdf" ;; - rtx__help,bin-paths) - cmd="rtx__help__bin__paths" + mise__help,bin-paths) + cmd="mise__help__bin__paths" ;; - rtx__help,cache) - cmd="rtx__help__cache" + mise__help,cache) + cmd="mise__help__cache" ;; - rtx__help,completion) - cmd="rtx__help__completion" + mise__help,completion) + cmd="mise__help__completion" ;; - rtx__help,config) - cmd="rtx__help__config" + mise__help,config) + cmd="mise__help__config" ;; - rtx__help,current) - cmd="rtx__help__current" + mise__help,current) + cmd="mise__help__current" ;; - rtx__help,deactivate) - cmd="rtx__help__deactivate" + mise__help,deactivate) + cmd="mise__help__deactivate" ;; - rtx__help,direnv) - cmd="rtx__help__direnv" + mise__help,direnv) + cmd="mise__help__direnv" ;; - rtx__help,doctor) - cmd="rtx__help__doctor" + mise__help,doctor) + cmd="mise__help__doctor" ;; - rtx__help,env) - cmd="rtx__help__env" + mise__help,env) + cmd="mise__help__env" ;; - rtx__help,env-vars) - cmd="rtx__help__env__vars" + mise__help,env-vars) + cmd="mise__help__env__vars" ;; - rtx__help,exec) - cmd="rtx__help__exec" + mise__help,exec) + cmd="mise__help__exec" ;; - rtx__help,global) - cmd="rtx__help__global" + mise__help,global) + cmd="mise__help__global" ;; - rtx__help,help) - cmd="rtx__help__help" + mise__help,help) + cmd="mise__help__help" ;; - rtx__help,hook-env) - cmd="rtx__help__hook__env" + mise__help,hook-env) + cmd="mise__help__hook__env" ;; - rtx__help,hook-not-found) - cmd="rtx__help__hook__not__found" + mise__help,hook-not-found) + cmd="mise__help__hook__not__found" ;; - rtx__help,implode) - cmd="rtx__help__implode" + mise__help,implode) + cmd="mise__help__implode" ;; - rtx__help,install) - cmd="rtx__help__install" + mise__help,install) + cmd="mise__help__install" ;; - rtx__help,latest) - cmd="rtx__help__latest" + mise__help,latest) + cmd="mise__help__latest" ;; - rtx__help,link) - cmd="rtx__help__link" + mise__help,link) + cmd="mise__help__link" ;; - rtx__help,local) - cmd="rtx__help__local" + mise__help,local) + cmd="mise__help__local" ;; - rtx__help,ls) - cmd="rtx__help__ls" + mise__help,ls) + cmd="mise__help__ls" ;; - rtx__help,ls-remote) - cmd="rtx__help__ls__remote" + mise__help,ls-remote) + cmd="mise__help__ls__remote" ;; - rtx__help,outdated) - cmd="rtx__help__outdated" + mise__help,outdated) + cmd="mise__help__outdated" ;; - rtx__help,plugins) - cmd="rtx__help__plugins" + mise__help,plugins) + cmd="mise__help__plugins" ;; - rtx__help,prune) - cmd="rtx__help__prune" + mise__help,prune) + cmd="mise__help__prune" ;; - rtx__help,render-completion) - cmd="rtx__help__render__completion" + mise__help,render-completion) + cmd="mise__help__render__completion" ;; - rtx__help,render-help) - cmd="rtx__help__render__help" + mise__help,render-help) + cmd="mise__help__render__help" ;; - rtx__help,render-mangen) - cmd="rtx__help__render__mangen" + mise__help,render-mangen) + cmd="mise__help__render__mangen" ;; - rtx__help,reshim) - cmd="rtx__help__reshim" + mise__help,reshim) + cmd="mise__help__reshim" ;; - rtx__help,run) - cmd="rtx__help__run" + mise__help,run) + cmd="mise__help__run" ;; - rtx__help,self-update) - cmd="rtx__help__self__update" + mise__help,self-update) + cmd="mise__help__self__update" ;; - rtx__help,settings) - cmd="rtx__help__settings" + mise__help,settings) + cmd="mise__help__settings" ;; - rtx__help,shell) - cmd="rtx__help__shell" + mise__help,shell) + cmd="mise__help__shell" ;; - rtx__help,sync) - cmd="rtx__help__sync" + mise__help,sync) + cmd="mise__help__sync" ;; - rtx__help,task) - cmd="rtx__help__task" + mise__help,task) + cmd="mise__help__task" ;; - rtx__help,trust) - cmd="rtx__help__trust" + mise__help,trust) + cmd="mise__help__trust" ;; - rtx__help,uninstall) - cmd="rtx__help__uninstall" + mise__help,uninstall) + cmd="mise__help__uninstall" ;; - rtx__help,upgrade) - cmd="rtx__help__upgrade" + mise__help,upgrade) + cmd="mise__help__upgrade" ;; - rtx__help,use) - cmd="rtx__help__use" + mise__help,use) + cmd="mise__help__use" ;; - rtx__help,version) - cmd="rtx__help__version" + mise__help,version) + cmd="mise__help__version" ;; - rtx__help,watch) - cmd="rtx__help__watch" + mise__help,watch) + cmd="mise__help__watch" ;; - rtx__help,where) - cmd="rtx__help__where" + mise__help,where) + cmd="mise__help__where" ;; - rtx__help,which) - cmd="rtx__help__which" + mise__help,which) + cmd="mise__help__which" ;; - rtx__help__alias,get) - cmd="rtx__help__alias__get" + mise__help__alias,get) + cmd="mise__help__alias__get" ;; - rtx__help__alias,ls) - cmd="rtx__help__alias__ls" + mise__help__alias,ls) + cmd="mise__help__alias__ls" ;; - rtx__help__alias,set) - cmd="rtx__help__alias__set" + mise__help__alias,set) + cmd="mise__help__alias__set" ;; - rtx__help__alias,unset) - cmd="rtx__help__alias__unset" + mise__help__alias,unset) + cmd="mise__help__alias__unset" ;; - rtx__help__cache,clear) - cmd="rtx__help__cache__clear" + mise__help__cache,clear) + cmd="mise__help__cache__clear" ;; - rtx__help__config,generate) - cmd="rtx__help__config__generate" + mise__help__config,generate) + cmd="mise__help__config__generate" ;; - rtx__help__config,ls) - cmd="rtx__help__config__ls" + mise__help__config,ls) + cmd="mise__help__config__ls" ;; - rtx__help__direnv,activate) - cmd="rtx__help__direnv__activate" + mise__help__direnv,activate) + cmd="mise__help__direnv__activate" ;; - rtx__help__direnv,envrc) - cmd="rtx__help__direnv__envrc" + mise__help__direnv,envrc) + cmd="mise__help__direnv__envrc" ;; - rtx__help__direnv,exec) - cmd="rtx__help__direnv__exec" + mise__help__direnv,exec) + cmd="mise__help__direnv__exec" ;; - rtx__help__plugins,install) - cmd="rtx__help__plugins__install" + mise__help__plugins,install) + cmd="mise__help__plugins__install" ;; - rtx__help__plugins,link) - cmd="rtx__help__plugins__link" + mise__help__plugins,link) + cmd="mise__help__plugins__link" ;; - rtx__help__plugins,ls) - cmd="rtx__help__plugins__ls" + mise__help__plugins,ls) + cmd="mise__help__plugins__ls" ;; - rtx__help__plugins,ls-remote) - cmd="rtx__help__plugins__ls__remote" + mise__help__plugins,ls-remote) + cmd="mise__help__plugins__ls__remote" ;; - rtx__help__plugins,uninstall) - cmd="rtx__help__plugins__uninstall" + mise__help__plugins,uninstall) + cmd="mise__help__plugins__uninstall" ;; - rtx__help__plugins,update) - cmd="rtx__help__plugins__update" + mise__help__plugins,update) + cmd="mise__help__plugins__update" ;; - rtx__help__settings,get) - cmd="rtx__help__settings__get" + mise__help__settings,get) + cmd="mise__help__settings__get" ;; - rtx__help__settings,ls) - cmd="rtx__help__settings__ls" + mise__help__settings,ls) + cmd="mise__help__settings__ls" ;; - rtx__help__settings,set) - cmd="rtx__help__settings__set" + mise__help__settings,set) + cmd="mise__help__settings__set" ;; - rtx__help__settings,unset) - cmd="rtx__help__settings__unset" + mise__help__settings,unset) + cmd="mise__help__settings__unset" ;; - rtx__help__sync,node) - cmd="rtx__help__sync__node" + mise__help__sync,node) + cmd="mise__help__sync__node" ;; - rtx__help__sync,python) - cmd="rtx__help__sync__python" + mise__help__sync,python) + cmd="mise__help__sync__python" ;; - rtx__help__task,edit) - cmd="rtx__help__task__edit" + mise__help__task,edit) + cmd="mise__help__task__edit" ;; - rtx__help__task,ls) - cmd="rtx__help__task__ls" + mise__help__task,ls) + cmd="mise__help__task__ls" ;; - rtx__help__task,run) - cmd="rtx__help__task__run" + mise__help__task,run) + cmd="mise__help__task__run" ;; - rtx__plugins,a) - cmd="rtx__plugins__install" + mise__plugins,a) + cmd="mise__plugins__install" ;; - rtx__plugins,add) - cmd="rtx__plugins__install" + mise__plugins,add) + cmd="mise__plugins__install" ;; - rtx__plugins,help) - cmd="rtx__plugins__help" + mise__plugins,help) + cmd="mise__plugins__help" ;; - rtx__plugins,i) - cmd="rtx__plugins__install" + mise__plugins,i) + cmd="mise__plugins__install" ;; - rtx__plugins,install) - cmd="rtx__plugins__install" + mise__plugins,install) + cmd="mise__plugins__install" ;; - rtx__plugins,link) - cmd="rtx__plugins__link" + mise__plugins,link) + cmd="mise__plugins__link" ;; - rtx__plugins,list) - cmd="rtx__plugins__ls" + mise__plugins,list) + cmd="mise__plugins__ls" ;; - rtx__plugins,list-all) - cmd="rtx__plugins__ls__remote" + mise__plugins,list-all) + cmd="mise__plugins__ls__remote" ;; - rtx__plugins,list-remote) - cmd="rtx__plugins__ls__remote" + mise__plugins,list-remote) + cmd="mise__plugins__ls__remote" ;; - rtx__plugins,ln) - cmd="rtx__plugins__link" + mise__plugins,ln) + cmd="mise__plugins__link" ;; - rtx__plugins,ls) - cmd="rtx__plugins__ls" + mise__plugins,ls) + cmd="mise__plugins__ls" ;; - rtx__plugins,ls-remote) - cmd="rtx__plugins__ls__remote" + mise__plugins,ls-remote) + cmd="mise__plugins__ls__remote" ;; - rtx__plugins,remove) - cmd="rtx__plugins__uninstall" + mise__plugins,remove) + cmd="mise__plugins__uninstall" ;; - rtx__plugins,rm) - cmd="rtx__plugins__uninstall" + mise__plugins,rm) + cmd="mise__plugins__uninstall" ;; - rtx__plugins,uninstall) - cmd="rtx__plugins__uninstall" + mise__plugins,uninstall) + cmd="mise__plugins__uninstall" ;; - rtx__plugins,update) - cmd="rtx__plugins__update" + mise__plugins,update) + cmd="mise__plugins__update" ;; - rtx__plugins,upgrade) - cmd="rtx__plugins__update" + mise__plugins,upgrade) + cmd="mise__plugins__update" ;; - rtx__plugins__help,help) - cmd="rtx__plugins__help__help" + mise__plugins__help,help) + cmd="mise__plugins__help__help" ;; - rtx__plugins__help,install) - cmd="rtx__plugins__help__install" + mise__plugins__help,install) + cmd="mise__plugins__help__install" ;; - rtx__plugins__help,link) - cmd="rtx__plugins__help__link" + mise__plugins__help,link) + cmd="mise__plugins__help__link" ;; - rtx__plugins__help,ls) - cmd="rtx__plugins__help__ls" + mise__plugins__help,ls) + cmd="mise__plugins__help__ls" ;; - rtx__plugins__help,ls-remote) - cmd="rtx__plugins__help__ls__remote" + mise__plugins__help,ls-remote) + cmd="mise__plugins__help__ls__remote" ;; - rtx__plugins__help,uninstall) - cmd="rtx__plugins__help__uninstall" + mise__plugins__help,uninstall) + cmd="mise__plugins__help__uninstall" ;; - rtx__plugins__help,update) - cmd="rtx__plugins__help__update" + mise__plugins__help,update) + cmd="mise__plugins__help__update" ;; - rtx__settings,add) - cmd="rtx__settings__set" + mise__settings,add) + cmd="mise__settings__set" ;; - rtx__settings,create) - cmd="rtx__settings__set" + mise__settings,create) + cmd="mise__settings__set" ;; - rtx__settings,del) - cmd="rtx__settings__unset" + mise__settings,del) + cmd="mise__settings__unset" ;; - rtx__settings,delete) - cmd="rtx__settings__unset" + mise__settings,delete) + cmd="mise__settings__unset" ;; - rtx__settings,get) - cmd="rtx__settings__get" + mise__settings,get) + cmd="mise__settings__get" ;; - rtx__settings,help) - cmd="rtx__settings__help" + mise__settings,help) + cmd="mise__settings__help" ;; - rtx__settings,list) - cmd="rtx__settings__ls" + mise__settings,list) + cmd="mise__settings__ls" ;; - rtx__settings,ls) - cmd="rtx__settings__ls" + mise__settings,ls) + cmd="mise__settings__ls" ;; - rtx__settings,remove) - cmd="rtx__settings__unset" + mise__settings,remove) + cmd="mise__settings__unset" ;; - rtx__settings,rm) - cmd="rtx__settings__unset" + mise__settings,rm) + cmd="mise__settings__unset" ;; - rtx__settings,set) - cmd="rtx__settings__set" + mise__settings,set) + cmd="mise__settings__set" ;; - rtx__settings,unset) - cmd="rtx__settings__unset" + mise__settings,unset) + cmd="mise__settings__unset" ;; - rtx__settings__help,get) - cmd="rtx__settings__help__get" + mise__settings__help,get) + cmd="mise__settings__help__get" ;; - rtx__settings__help,help) - cmd="rtx__settings__help__help" + mise__settings__help,help) + cmd="mise__settings__help__help" ;; - rtx__settings__help,ls) - cmd="rtx__settings__help__ls" + mise__settings__help,ls) + cmd="mise__settings__help__ls" ;; - rtx__settings__help,set) - cmd="rtx__settings__help__set" + mise__settings__help,set) + cmd="mise__settings__help__set" ;; - rtx__settings__help,unset) - cmd="rtx__settings__help__unset" + mise__settings__help,unset) + cmd="mise__settings__help__unset" ;; - rtx__sync,help) - cmd="rtx__sync__help" + mise__sync,help) + cmd="mise__sync__help" ;; - rtx__sync,node) - cmd="rtx__sync__node" + mise__sync,node) + cmd="mise__sync__node" ;; - rtx__sync,python) - cmd="rtx__sync__python" + mise__sync,python) + cmd="mise__sync__python" ;; - rtx__sync__help,help) - cmd="rtx__sync__help__help" + mise__sync__help,help) + cmd="mise__sync__help__help" ;; - rtx__sync__help,node) - cmd="rtx__sync__help__node" + mise__sync__help,node) + cmd="mise__sync__help__node" ;; - rtx__sync__help,python) - cmd="rtx__sync__help__python" + mise__sync__help,python) + cmd="mise__sync__help__python" ;; - rtx__task,edit) - cmd="rtx__task__edit" + mise__task,edit) + cmd="mise__task__edit" ;; - rtx__task,help) - cmd="rtx__task__help" + mise__task,help) + cmd="mise__task__help" ;; - rtx__task,ls) - cmd="rtx__task__ls" + mise__task,ls) + cmd="mise__task__ls" ;; - rtx__task,r) - cmd="rtx__task__run" + mise__task,r) + cmd="mise__task__run" ;; - rtx__task,run) - cmd="rtx__task__run" + mise__task,run) + cmd="mise__task__run" ;; - rtx__task__help,edit) - cmd="rtx__task__help__edit" + mise__task__help,edit) + cmd="mise__task__help__edit" ;; - rtx__task__help,help) - cmd="rtx__task__help__help" + mise__task__help,help) + cmd="mise__task__help__help" ;; - rtx__task__help,ls) - cmd="rtx__task__help__ls" + mise__task__help,ls) + cmd="mise__task__help__ls" ;; - rtx__task__help,run) - cmd="rtx__task__help__run" + mise__task__help,run) + cmd="mise__task__help__run" ;; *) ;; @@ -699,7 +699,7 @@ _rtx() { done case "${cmd}" in - rtx) + mise) opts="-C -q -v -y -h -V --debug --log-level --trace --cd --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -725,7 +725,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__activate) + mise__activate) opts="-s -q -C -v -y -h --shell --status --quiet --debug --log-level --trace --cd --verbose --yes --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -759,7 +759,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias) + mise__alias) opts="-p -C -q -v -y -h --plugin --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -793,7 +793,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__get) + mise__alias__get) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -819,7 +819,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__help) + mise__alias__help) opts="get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -833,7 +833,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__help__get) + mise__alias__help__get) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -847,7 +847,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__help__help) + mise__alias__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -861,7 +861,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__help__ls) + mise__alias__help__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -875,7 +875,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__help__set) + mise__alias__help__set) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -889,7 +889,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__help__unset) + mise__alias__help__unset) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -903,7 +903,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__ls) + mise__alias__ls) opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -929,7 +929,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__set) + mise__alias__set) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -955,7 +955,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__alias__unset) + mise__alias__unset) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -981,7 +981,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__asdf) + mise__asdf) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1007,7 +1007,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__bin__paths) + mise__bin__paths) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1033,7 +1033,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__cache) + mise__cache) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1059,7 +1059,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__cache__clear) + mise__cache__clear) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1085,7 +1085,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__cache__help) + mise__cache__help) opts="clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1099,7 +1099,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__cache__help__clear) + mise__cache__help__clear) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1113,7 +1113,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__cache__help__help) + mise__cache__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1127,7 +1127,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__completion) + mise__completion) opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1161,7 +1161,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__config) + mise__config) opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help ls generate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1187,7 +1187,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__config__generate) + mise__config__generate) opts="-o -C -q -v -y -h --output --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1221,7 +1221,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__config__help) + mise__config__help) opts="ls generate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1235,7 +1235,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__config__help__generate) + mise__config__help__generate) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1249,7 +1249,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__config__help__help) + mise__config__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1263,7 +1263,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__config__help__ls) + mise__config__help__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1277,7 +1277,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__config__ls) + mise__config__ls) opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1303,7 +1303,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__current) + mise__current) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1329,7 +1329,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__deactivate) + mise__deactivate) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1355,7 +1355,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv) + mise__direnv) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1381,7 +1381,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__activate) + mise__direnv__activate) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1407,7 +1407,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__envrc) + mise__direnv__envrc) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1433,7 +1433,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__exec) + mise__direnv__exec) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1459,7 +1459,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__help) + mise__direnv__help) opts="envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1473,7 +1473,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__help__activate) + mise__direnv__help__activate) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1487,7 +1487,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__help__envrc) + mise__direnv__help__envrc) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1501,7 +1501,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__help__exec) + mise__direnv__help__exec) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1515,7 +1515,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__direnv__help__help) + mise__direnv__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1529,7 +1529,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__doctor) + mise__doctor) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1555,7 +1555,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__env) + mise__env) opts="-s -J -C -q -v -y -h --shell --json --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1589,7 +1589,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__env__vars) + mise__env__vars) opts="-C -q -v -y -h --file --remove --debug --log-level --trace --cd --quiet --verbose --yes --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1623,7 +1623,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__exec) + mise__exec) opts="-c -j -C -q -v -y -h --command --jobs --raw --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1665,7 +1665,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__global) + mise__global) opts="-C -q -v -y -h --pin --fuzzy --remove --path --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1695,7 +1695,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help) + mise__help) opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env env-vars exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1709,7 +1709,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__activate) + mise__help__activate) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1723,7 +1723,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__alias) + mise__help__alias) opts="get ls set unset" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1737,7 +1737,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__alias__get) + mise__help__alias__get) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1751,7 +1751,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__alias__ls) + mise__help__alias__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1765,7 +1765,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__alias__set) + mise__help__alias__set) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1779,7 +1779,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__alias__unset) + mise__help__alias__unset) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1793,7 +1793,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__asdf) + mise__help__asdf) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1807,7 +1807,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__bin__paths) + mise__help__bin__paths) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1821,7 +1821,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__cache) + mise__help__cache) opts="clear" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1835,7 +1835,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__cache__clear) + mise__help__cache__clear) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1849,7 +1849,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__completion) + mise__help__completion) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1863,7 +1863,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__config) + mise__help__config) opts="ls generate" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1877,7 +1877,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__config__generate) + mise__help__config__generate) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1891,7 +1891,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__config__ls) + mise__help__config__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1905,7 +1905,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__current) + mise__help__current) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1919,7 +1919,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__deactivate) + mise__help__deactivate) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1933,7 +1933,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__direnv) + mise__help__direnv) opts="envrc exec activate" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1947,7 +1947,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__direnv__activate) + mise__help__direnv__activate) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1961,7 +1961,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__direnv__envrc) + mise__help__direnv__envrc) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1975,7 +1975,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__direnv__exec) + mise__help__direnv__exec) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1989,7 +1989,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__doctor) + mise__help__doctor) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2003,7 +2003,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__env) + mise__help__env) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2017,7 +2017,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__env__vars) + mise__help__env__vars) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2031,7 +2031,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__exec) + mise__help__exec) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2045,7 +2045,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__global) + mise__help__global) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2059,7 +2059,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__help) + mise__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2073,7 +2073,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__hook__env) + mise__help__hook__env) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2087,7 +2087,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__hook__not__found) + mise__help__hook__not__found) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2101,7 +2101,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__implode) + mise__help__implode) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2115,7 +2115,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__install) + mise__help__install) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2129,7 +2129,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__latest) + mise__help__latest) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2143,7 +2143,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__link) + mise__help__link) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2157,7 +2157,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__local) + mise__help__local) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2171,7 +2171,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__ls) + mise__help__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2185,7 +2185,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__ls__remote) + mise__help__ls__remote) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2199,7 +2199,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__outdated) + mise__help__outdated) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2213,7 +2213,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__plugins) + mise__help__plugins) opts="install link ls ls-remote uninstall update" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2227,7 +2227,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__plugins__install) + mise__help__plugins__install) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2241,7 +2241,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__plugins__link) + mise__help__plugins__link) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2255,7 +2255,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__plugins__ls) + mise__help__plugins__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2269,7 +2269,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__plugins__ls__remote) + mise__help__plugins__ls__remote) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2283,7 +2283,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__plugins__uninstall) + mise__help__plugins__uninstall) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2297,7 +2297,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__plugins__update) + mise__help__plugins__update) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2311,7 +2311,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__prune) + mise__help__prune) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2325,7 +2325,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__render__completion) + mise__help__render__completion) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2339,7 +2339,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__render__help) + mise__help__render__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2353,7 +2353,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__render__mangen) + mise__help__render__mangen) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2367,7 +2367,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__reshim) + mise__help__reshim) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2381,7 +2381,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__run) + mise__help__run) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2395,7 +2395,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__self__update) + mise__help__self__update) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2409,7 +2409,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__settings) + mise__help__settings) opts="get ls set unset" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2423,7 +2423,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__settings__get) + mise__help__settings__get) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2437,7 +2437,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__settings__ls) + mise__help__settings__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2451,7 +2451,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__settings__set) + mise__help__settings__set) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2465,7 +2465,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__settings__unset) + mise__help__settings__unset) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2479,7 +2479,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__shell) + mise__help__shell) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2493,7 +2493,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__sync) + mise__help__sync) opts="node python" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2507,7 +2507,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__sync__node) + mise__help__sync__node) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2521,7 +2521,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__sync__python) + mise__help__sync__python) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2535,7 +2535,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__task) + mise__help__task) opts="edit ls run" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2549,7 +2549,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__task__edit) + mise__help__task__edit) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2563,7 +2563,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__task__ls) + mise__help__task__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2577,7 +2577,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__task__run) + mise__help__task__run) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2591,7 +2591,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__trust) + mise__help__trust) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2605,7 +2605,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__uninstall) + mise__help__uninstall) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2619,7 +2619,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__upgrade) + mise__help__upgrade) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2633,7 +2633,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__use) + mise__help__use) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2647,7 +2647,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__version) + mise__help__version) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2661,7 +2661,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__watch) + mise__help__watch) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2675,7 +2675,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__where) + mise__help__where) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2689,7 +2689,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__help__which) + mise__help__which) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2703,7 +2703,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__hook__env) + mise__hook__env) opts="-s -q -C -v -y -h --shell --status --quiet --debug --log-level --trace --cd --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2737,7 +2737,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__hook__not__found) + mise__hook__not__found) opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2771,7 +2771,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__implode) + mise__implode) opts="-n -C -q -v -y -h --config --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2797,7 +2797,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__install) + mise__install) opts="-f -j -v -C -q -y -h --force --jobs --raw --verbose --debug --log-level --trace --cd --quiet --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2831,7 +2831,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__latest) + mise__latest) opts="-i -C -q -v -y -h --installed --debug --log-level --trace --cd --quiet --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2857,7 +2857,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__link) + mise__link) opts="-f -C -q -v -y -h --force --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2883,7 +2883,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__local) + mise__local) opts="-p -C -q -v -y -h --parent --pin --fuzzy --remove --path --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2913,7 +2913,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__ls) + mise__ls) opts="-p -c -g -i -J -m -C -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2951,7 +2951,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__ls__remote) + mise__ls__remote) opts="-C -q -v -y -h --all --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION] [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2977,7 +2977,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__outdated) + mise__outdated) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3003,7 +3003,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins) + mise__plugins) opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --cd --quiet --verbose --yes --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3029,7 +3029,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help) + mise__plugins__help) opts="install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3043,7 +3043,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help__help) + mise__plugins__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3057,7 +3057,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help__install) + mise__plugins__help__install) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3071,7 +3071,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help__link) + mise__plugins__help__link) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3085,7 +3085,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help__ls) + mise__plugins__help__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3099,7 +3099,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help__ls__remote) + mise__plugins__help__ls__remote) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3113,7 +3113,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help__uninstall) + mise__plugins__help__uninstall) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3127,7 +3127,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__help__update) + mise__plugins__help__update) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3141,7 +3141,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__install) + mise__plugins__install) opts="-f -a -v -C -q -y -h --force --all --verbose --debug --log-level --trace --cd --quiet --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3167,7 +3167,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__link) + mise__plugins__link) opts="-f -C -q -v -y -h --force --debug --log-level --trace --cd --quiet --verbose --yes --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3193,7 +3193,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__ls) + mise__plugins__ls) opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3219,7 +3219,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__ls__remote) + mise__plugins__ls__remote) opts="-u -C -q -v -y -h --urls --only-names --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3245,7 +3245,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__uninstall) + mise__plugins__uninstall) opts="-p -a -C -q -v -y -h --purge --all --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3271,7 +3271,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__plugins__update) + mise__plugins__update) opts="-j -C -q -v -y -h --jobs --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3305,7 +3305,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__prune) + mise__prune) opts="-n -C -q -v -y -h --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3331,7 +3331,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__render__completion) + mise__render__completion) opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3365,7 +3365,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__render__help) + mise__render__help) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3391,7 +3391,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__render__mangen) + mise__render__mangen) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3417,7 +3417,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__reshim) + mise__reshim) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3443,7 +3443,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__run) + mise__run) opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3485,7 +3485,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__self__update) + mise__self__update) opts="-f -y -C -q -v -h --force --no-plugins --yes --debug --log-level --trace --cd --quiet --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3511,7 +3511,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings) + mise__settings) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3537,7 +3537,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__get) + mise__settings__get) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3563,7 +3563,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__help) + mise__settings__help) opts="get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3577,7 +3577,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__help__get) + mise__settings__help__get) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3591,7 +3591,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__help__help) + mise__settings__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3605,7 +3605,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__help__ls) + mise__settings__help__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3619,7 +3619,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__help__set) + mise__settings__help__set) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3633,7 +3633,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__help__unset) + mise__settings__help__unset) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3647,7 +3647,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__ls) + mise__settings__ls) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3673,7 +3673,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__set) + mise__settings__set) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3699,7 +3699,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__settings__unset) + mise__settings__unset) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3725,7 +3725,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__shell) + mise__shell) opts="-j -u -C -q -v -y -h --jobs --raw --unset --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3759,7 +3759,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__sync) + mise__sync) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3785,7 +3785,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__sync__help) + mise__sync__help) opts="node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3799,7 +3799,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__sync__help__help) + mise__sync__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3813,7 +3813,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__sync__help__node) + mise__sync__help__node) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3827,7 +3827,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__sync__help__python) + mise__sync__help__python) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3841,7 +3841,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__sync__node) + mise__sync__node) opts="-C -q -v -y -h --brew --nvm --nodenv --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3867,7 +3867,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__sync__python) + mise__sync__python) opts="-C -q -v -y -h --pyenv --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3893,7 +3893,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task) + mise__task) opts="-C -q -v -y -h --no-header --hidden --debug --log-level --trace --cd --quiet --verbose --yes --help edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3919,7 +3919,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__edit) + mise__task__edit) opts="-p -C -q -v -y -h --path --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3945,7 +3945,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__help) + mise__task__help) opts="edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3959,7 +3959,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__help__edit) + mise__task__help__edit) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3973,7 +3973,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__help__help) + mise__task__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -3987,7 +3987,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__help__ls) + mise__task__help__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4001,7 +4001,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__help__run) + mise__task__help__run) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4015,7 +4015,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__ls) + mise__task__ls) opts="-C -q -v -y -h --no-header --hidden --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4041,7 +4041,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__task__run) + mise__task__run) opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4083,7 +4083,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__trust) + mise__trust) opts="-a -C -q -v -y -h --all --untrust --debug --log-level --trace --cd --quiet --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4109,7 +4109,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__uninstall) + mise__uninstall) opts="-a -n -C -q -v -y -h --all --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4135,7 +4135,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__upgrade) + mise__upgrade) opts="-n -j -i -C -q -v -y -h --dry-run --jobs --interactive --raw --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4169,7 +4169,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__use) + mise__use) opts="-f -g -e -j -p -C -q -v -y -h --force --fuzzy --global --env --jobs --raw --remove --path --pin --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4223,7 +4223,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__version) + mise__version) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4249,7 +4249,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__watch) + mise__watch) opts="-t -g -C -q -v -y -h --task --glob --debug --log-level --trace --cd --quiet --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4291,7 +4291,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__where) + mise__where) opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4317,7 +4317,7 @@ _rtx() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rtx__which) + mise__which) opts="-t -C -q -v -y -h --plugin --version --tool --debug --log-level --trace --cd --quiet --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4354,4 +4354,4 @@ _rtx() { esac } -complete -F _rtx -o nosort -o bashdefault -o default rtx +complete -F _mise -o nosort -o bashdefault -o default mise diff --git a/completions/mise.fish b/completions/mise.fish new file mode 100644 index 000000000..8e0f12f7f --- /dev/null +++ b/completions/mise.fish @@ -0,0 +1,408 @@ +set -l fssf "__fish_seen_subcommand_from" + +# mise +complete -kxc mise -s C -l cd -a "(__fish_complete_directories)" -d 'Change directory before running command' +complete -kxc mise -s q -l quiet -d 'Suppress non-error messages' +complete -kxc mise -s v -l verbose -d 'Show extra output (use -vv for even more)' +complete -kxc mise -s y -l yes -d 'Answer yes to all confirmation prompts' +set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which +complete -xc mise -n "not $fssf $others" -a activate -d 'Initializes mise in the current shell session' +complete -xc mise -n "not $fssf $others" -a alias -d 'Manage aliases' +complete -xc mise -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' +complete -xc mise -n "not $fssf $others" -a cache -d 'Manage the mise cache' +complete -xc mise -n "not $fssf $others" -a completion -d 'Generate shell completions' +complete -xc mise -n "not $fssf $others" -a config -d '[experimental] Manage config files' +complete -xc mise -n "not $fssf $others" -a current -d 'Shows current active and installed runtime versions' +complete -xc mise -n "not $fssf $others" -a deactivate -d 'Disable mise for current shell session' +complete -xc mise -n "not $fssf $others" -a direnv -d 'Output direnv function to use mise inside direnv' +complete -xc mise -n "not $fssf $others" -a doctor -d 'Check mise installation for possible problems.' +complete -xc mise -n "not $fssf $others" -a env -d 'Exports env vars to activate mise a single time' +complete -xc mise -n "not $fssf $others" -a env-vars -d 'Manage environment variables' +complete -xc mise -n "not $fssf $others" -a exec -d 'Execute a command with tool(s) set' +complete -xc mise -n "not $fssf $others" -a implode -d 'Removes mise CLI and all related data' +complete -xc mise -n "not $fssf $others" -a install -d 'Install a tool version' +complete -xc mise -n "not $fssf $others" -a latest -d 'Gets the latest available version for a plugin' +complete -xc mise -n "not $fssf $others" -a link -d 'Symlinks a tool version into mise' +complete -xc mise -n "not $fssf $others" -a ls -d 'List installed and/or currently selected tool versions' +complete -xc mise -n "not $fssf $others" -a ls-remote -d 'List runtime versions available for install' +complete -xc mise -n "not $fssf $others" -a outdated -d 'Shows outdated tool versions' +complete -xc mise -n "not $fssf $others" -a plugins -d 'Manage plugins' +complete -xc mise -n "not $fssf $others" -a prune -d 'Delete unused versions of tools' +complete -xc mise -n "not $fssf $others" -a reshim -d 'rebuilds the shim farm' +complete -xc mise -n "not $fssf $others" -a run -d '[experimental] Run a task' +complete -xc mise -n "not $fssf $others" -a self-update -d 'Updates mise itself' +complete -xc mise -n "not $fssf $others" -a settings -d 'Manage settings' +complete -xc mise -n "not $fssf $others" -a shell -d 'Sets a tool version for the current shell session' +complete -xc mise -n "not $fssf $others" -a sync -d 'Add tool versions from external tools to mise' +complete -xc mise -n "not $fssf $others" -a task -d '[experimental] Manage tasks' +complete -xc mise -n "not $fssf $others" -a trust -d 'Marks a config file as trusted' +complete -xc mise -n "not $fssf $others" -a uninstall -d 'Removes runtime versions' +complete -xc mise -n "not $fssf $others" -a upgrade -d 'Upgrades outdated tool versions' +complete -xc mise -n "not $fssf $others" -a use -d 'Change the active version of a tool locally or globally.' +complete -xc mise -n "not $fssf $others" -a version -d 'Show mise version' +complete -xc mise -n "not $fssf $others" -a watch -d '[experimental] Run a task watching for changes' +complete -xc mise -n "not $fssf $others" -a where -d 'Display the installation path for a runtime' +complete -xc mise -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' + +# activate +complete -kxc mise -n "$fssf activate" -s q -l quiet -d 'Suppress non-error messages' +complete -kxc mise -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' +complete -kxc mise -n "$fssf activate" -l status -d 'Show "mise: @" message when changing directories' + +# alias +complete -kxc mise -n "$fssf alias" -l no-header -d 'Don'\''t show table header' +complete -kxc mise -n "$fssf alias" -s p -l plugin -a "(__mise_plugins)" -d 'filter aliases by plugin' +set -l others get ls set unset +complete -xc mise -n "$fssf alias; and not $fssf $others" -a get -d 'Show an alias for a plugin' +complete -xc mise -n "$fssf alias; and not $fssf $others" -a ls -d 'List aliases' +complete -xc mise -n "$fssf alias; and not $fssf $others" -a set -d 'Add/update an alias for a plugin' +complete -xc mise -n "$fssf alias; and not $fssf $others" -a unset -d 'Clears an alias for a plugin' + +# alias get +complete -kxc mise -n "$fssf alias; and $fssf get" -a "(__mise_aliases)" -d 'The alias to show' +complete -kxc mise -n "$fssf alias; and $fssf get" -a "(__mise_plugins)" -d 'The plugin to show the alias for' + +# alias ls +complete -kxc mise -n "$fssf alias; and $fssf ls" -l no-header -d 'Don'\''t show table header' +complete -kxc mise -n "$fssf alias; and $fssf ls" -a "(__mise_plugins)" -d 'Show aliases for ' + +# alias set +complete -kxc mise -n "$fssf alias; and $fssf set" -a "(__mise_aliases)" -d 'The alias to set' +complete -kxc mise -n "$fssf alias; and $fssf set" -a "(__mise_plugins)" -d 'The plugin to set the alias for' +complete -kxc mise -n "$fssf alias; and $fssf set" -d 'The value to set the alias to' + +# alias unset +complete -kxc mise -n "$fssf alias; and $fssf unset" -a "(__mise_aliases)" -d 'The alias to remove' +complete -kxc mise -n "$fssf alias; and $fssf unset" -a "(__mise_plugins)" -d 'The plugin to remove the alias from' + + +# bin-paths + +# cache +set -l others clear +complete -xc mise -n "$fssf cache; and not $fssf $others" -a clear -d 'Deletes all cache files in mise' + +# cache clear +complete -kxc mise -n "$fssf cache; and $fssf clear" -a "(__mise_plugins)" -d 'Plugin(s) to clear cache for e.g.: node, python' + + +# completion +complete -kxc mise -n "$fssf completion" -a "bash fish zsh" -d 'Shell type to generate completions for' + +# config +complete -kxc mise -n "$fssf config" -l no-header -d 'Do not print table header' +set -l others generate ls +complete -xc mise -n "$fssf config; and not $fssf $others" -a generate -d '[experimental] Generate an .mise.toml file' +complete -xc mise -n "$fssf config; and not $fssf $others" -a ls -d '[experimental] List config files currently in use' + +# config generate +complete -kxc mise -n "$fssf config; and $fssf generate" -s o -l output -a "(__fish_complete_path)" -d 'Output to file instead of stdout' + +# config ls +complete -kxc mise -n "$fssf config; and $fssf ls" -l no-header -d 'Do not print table header' + + +# current +complete -kxc mise -n "$fssf current" -a "(__mise_plugins)" -d 'Plugin to show versions of e.g.: ruby, node' + +# deactivate + +# direnv +set -l others activate +complete -xc mise -n "$fssf direnv; and not $fssf $others" -a activate -d 'Output direnv function to use mise inside direnv' + +# direnv activate + + +# doctor + +# env +complete -kxc mise -n "$fssf env" -s J -l json -d 'Output in JSON format' +complete -kxc mise -n "$fssf env" -s s -l shell -a "bash fish nu xonsh zsh" -d 'Shell type to generate environment variables for' +complete -kxc mise -n "$fssf env" -a "(__mise_tool_versions)" -d 'Tool(s) to use' + +# env-vars +complete -kxc mise -n "$fssf env-vars" -d 'Environment variable(s) to set' +complete -kxc mise -n "$fssf env-vars" -l file -a "(__fish_complete_path)" -d 'The TOML file to update' +complete -kxc mise -n "$fssf env-vars" -l remove -d 'Remove the environment variable from config file' + +# exec +complete -kxc mise -n "$fssf exec" -s c -l command -d 'Command string to execute' +complete -kxc mise -n "$fssf exec" -d 'Command string to execute (same as --command)' +complete -kxc mise -n "$fssf exec" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc mise -n "$fssf exec" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' +complete -kxc mise -n "$fssf exec" -a "(__mise_tool_versions)" -d 'Tool(s) to start e.g.: node@20 python@3.10' + +# implode +complete -kxc mise -n "$fssf implode" -l config -d 'Also remove config directory' +complete -kxc mise -n "$fssf implode" -s n -l dry-run -d 'List directories that would be removed without actually removing them' + +# install +complete -kxc mise -n "$fssf install" -s f -l force -d 'Force reinstall even if already installed' +complete -kxc mise -n "$fssf install" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc mise -n "$fssf install" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' +complete -kxc mise -n "$fssf install" -a "(__mise_tool_versions)" -d 'Tool(s) to install e.g.: node@20' +complete -kxc mise -n "$fssf install" -s v -l verbose -d 'Show installation output' + +# latest +complete -kxc mise -n "$fssf latest" -s i -l installed -d 'Show latest installed instead of available version' +complete -kxc mise -n "$fssf latest" -a "(__mise_tool_versions)" -d 'Tool to get the latest version of' + +# link +complete -kxc mise -n "$fssf link" -s f -l force -d 'Overwrite an existing tool version if it exists' +complete -kxc mise -n "$fssf link" -a "(__fish_complete_directories)" -d 'The local path to the tool version' +complete -kxc mise -n "$fssf link" -a "(__mise_tool_versions)" -d 'Tool name and version to create a symlink for' + +# ls +complete -kxc mise -n "$fssf ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.mise.toml' +complete -kxc mise -n "$fssf ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.mise.toml' +complete -kxc mise -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed' +complete -kxc mise -n "$fssf ls" -s J -l json -d 'Output in json format' +complete -kxc mise -n "$fssf ls" -s m -l missing -d 'Display missing tool versions' +complete -kxc mise -n "$fssf ls" -l no-header -d 'Don'\''t display headers' +complete -kxc mise -n "$fssf ls" -a "(__mise_plugins)" -d 'Only show tool versions from [PLUGIN]' +complete -kxc mise -n "$fssf ls" -l prefix -d 'Display versions matching this prefix' + +# ls-remote +complete -kxc mise -n "$fssf ls-remote" -l all -d 'Show all installed plugins and versions' +complete -kxc mise -n "$fssf ls-remote" -a "(__mise_plugins)" -d 'Plugin to get versions for' +complete -kxc mise -n "$fssf ls-remote" -d 'The version prefix to use when querying the latest version' + +# outdated +complete -kxc mise -n "$fssf outdated" -a "(__mise_tool_versions)" -d 'Tool(s) to show outdated versions for' + +# plugins +complete -kxc mise -n "$fssf plugins" -s c -l core -d 'The built-in plugins only' +complete -kxc mise -n "$fssf plugins" -s u -l urls -d 'Show the git url for each plugin' +complete -kxc mise -n "$fssf plugins" -l user -d 'List installed plugins' +set -l others install link ls ls-remote uninstall update +complete -xc mise -n "$fssf plugins; and not $fssf $others" -a install -d 'Install a plugin' +complete -xc mise -n "$fssf plugins; and not $fssf $others" -a link -d 'Symlinks a plugin into mise' +complete -xc mise -n "$fssf plugins; and not $fssf $others" -a ls -d 'List installed plugins' +complete -xc mise -n "$fssf plugins; and not $fssf $others" -a ls-remote -d 'List all available remote plugins' +complete -xc mise -n "$fssf plugins; and not $fssf $others" -a uninstall -d 'Removes a plugin' +complete -xc mise -n "$fssf plugins; and not $fssf $others" -a update -d 'Updates a plugin to the latest version' + +# plugins install +complete -kxc mise -n "$fssf plugins; and $fssf install" -s a -l all -d 'Install all missing plugins' +complete -kxc mise -n "$fssf plugins; and $fssf install" -s f -l force -d 'Reinstall even if plugin exists' +complete -kxc mise -n "$fssf plugins; and $fssf install" -d 'The git url of the plugin' +complete -kxc mise -n "$fssf plugins; and $fssf install" -a "(__mise_all_plugins)" -d 'The name of the plugin to install' +complete -kxc mise -n "$fssf plugins; and $fssf install" -s v -l verbose -d 'Show installation output' + +# plugins link +complete -kxc mise -n "$fssf plugins; and $fssf link" -s f -l force -d 'Overwrite existing plugin' +complete -kxc mise -n "$fssf plugins; and $fssf link" -d 'The name of the plugin' +complete -kxc mise -n "$fssf plugins; and $fssf link" -a "(__fish_complete_directories)" -d 'The local path to the plugin' + +# plugins ls +complete -kxc mise -n "$fssf plugins; and $fssf ls" -s c -l core -d 'The built-in plugins only' +complete -kxc mise -n "$fssf plugins; and $fssf ls" -s u -l urls -d 'Show the git url for each plugin' +complete -kxc mise -n "$fssf plugins; and $fssf ls" -l user -d 'List installed plugins' + +# plugins ls-remote +complete -kxc mise -n "$fssf plugins; and $fssf ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' +complete -kxc mise -n "$fssf plugins; and $fssf ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' + +# plugins uninstall +complete -kxc mise -n "$fssf plugins; and $fssf uninstall" -s a -l all -d 'Remove all plugins' +complete -kxc mise -n "$fssf plugins; and $fssf uninstall" -a "(__mise_plugins)" -d 'Plugin(s) to remove' +complete -kxc mise -n "$fssf plugins; and $fssf uninstall" -s p -l purge -d 'Also remove the plugin'\''s installs, downloads, and cache' + +# plugins update +complete -kxc mise -n "$fssf plugins; and $fssf update" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc mise -n "$fssf plugins; and $fssf update" -a "(__mise_plugins)" -d 'Plugin(s) to update' + + +# prune +complete -kxc mise -n "$fssf prune" -s n -l dry-run -d 'Do not actually delete anything' +complete -kxc mise -n "$fssf prune" -a "(__mise_plugins)" -d 'Prune only versions from these plugins' + +# reshim + +# run +complete -kxc mise -n "$fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' +complete -kxc mise -n "$fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' +complete -kxc mise -n "$fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' +complete -kxc mise -n "$fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' +complete -kxc mise -n "$fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' +complete -kxc mise -n "$fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' +complete -kxc mise -n "$fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' +complete -kxc mise -n "$fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' +complete -kxc mise -n "$fssf run" -a "(__mise_tasks)" -d 'Task to run' +complete -kxc mise -n "$fssf run" -s t -l tool -a "(__mise_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' + +# self-update +complete -kxc mise -n "$fssf self-update" -s f -l force -d 'Update even if already up to date' +complete -kxc mise -n "$fssf self-update" -l no-plugins -d 'Disable auto-updating plugins' +complete -kxc mise -n "$fssf self-update" -d 'Update to a specific version' +complete -kxc mise -n "$fssf self-update" -s y -l yes -d 'Skip confirmation prompt' + +# settings +set -l others get ls set unset +complete -xc mise -n "$fssf settings; and not $fssf $others" -a get -d 'Show a current setting' +complete -xc mise -n "$fssf settings; and not $fssf $others" -a ls -d 'Show current settings' +complete -xc mise -n "$fssf settings; and not $fssf $others" -a set -d 'Add/update a setting' +complete -xc mise -n "$fssf settings; and not $fssf $others" -a unset -d 'Clears a setting' + +# settings get +complete -kxc mise -n "$fssf settings; and $fssf get" -a "(__mise_settings)" -d 'The setting to show' + +# settings ls + +# settings set +complete -kxc mise -n "$fssf settings; and $fssf set" -a "(__mise_settings)" -d 'The setting to set' +complete -kxc mise -n "$fssf settings; and $fssf set" -d 'The value to set' + +# settings unset +complete -kxc mise -n "$fssf settings; and $fssf unset" -a "(__mise_settings)" -d 'The setting to remove' + + +# shell +complete -kxc mise -n "$fssf shell" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc mise -n "$fssf shell" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' +complete -kxc mise -n "$fssf shell" -a "(__mise_tool_versions)" -d 'Tool(s) to use' +complete -kxc mise -n "$fssf shell" -s u -l unset -d 'Removes a previously set version' + +# sync +set -l others node python +complete -xc mise -n "$fssf sync; and not $fssf $others" -a node -d 'Symlinks all tool versions from an external tool into mise' +complete -xc mise -n "$fssf sync; and not $fssf $others" -a python -d 'Symlinks all tool versions from an external tool into mise' + +# sync node +complete -kxc mise -n "$fssf sync; and $fssf node" -l brew -d 'Get tool versions from Homebrew' +complete -kxc mise -n "$fssf sync; and $fssf node" -l nodenv -d 'Get tool versions from nodenv' +complete -kxc mise -n "$fssf sync; and $fssf node" -l nvm -d 'Get tool versions from nvm' + +# sync python +complete -kxc mise -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versions from pyenv' + + +# task +complete -kxc mise -n "$fssf task" -l hidden -d 'Show hidden tasks' +complete -kxc mise -n "$fssf task" -l no-header -d 'Do not print table header' +set -l others edit ls run +complete -xc mise -n "$fssf task; and not $fssf $others" -a edit -d '[experimental] Edit a task with $EDITOR' +complete -xc mise -n "$fssf task; and not $fssf $others" -a ls -d '[experimental] List available tasks to execute' +complete -xc mise -n "$fssf task; and not $fssf $others" -a run -d '[experimental] Run a task' + +# task edit +complete -kxc mise -n "$fssf task; and $fssf edit" -s p -l path -d 'Display the path to the task instead of editing it' +complete -kxc mise -n "$fssf task; and $fssf edit" -a "(__mise_tasks)" -d 'Task to edit' + +# task ls +complete -kxc mise -n "$fssf task; and $fssf ls" -l hidden -d 'Show hidden tasks' +complete -kxc mise -n "$fssf task; and $fssf ls" -l no-header -d 'Do not print table header' + +# task run +complete -kxc mise -n "$fssf task; and $fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' +complete -kxc mise -n "$fssf task; and $fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' +complete -kxc mise -n "$fssf task; and $fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' +complete -kxc mise -n "$fssf task; and $fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' +complete -kxc mise -n "$fssf task; and $fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' +complete -kxc mise -n "$fssf task; and $fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' +complete -kxc mise -n "$fssf task; and $fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' +complete -kxc mise -n "$fssf task; and $fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' +complete -kxc mise -n "$fssf task; and $fssf run" -a "(__mise_tasks)" -d 'Task to run' +complete -kxc mise -n "$fssf task; and $fssf run" -s t -l tool -a "(__mise_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' + + +# trust +complete -kxc mise -n "$fssf trust" -s a -l all -d 'Trust all config files in the current directory and its parents' +complete -kxc mise -n "$fssf trust" -a "(__fish_complete_path)" -d 'The config file to trust' +complete -kxc mise -n "$fssf trust" -l untrust -d 'No longer trust this config' + +# uninstall +complete -kxc mise -n "$fssf uninstall" -s a -l all -d 'Delete all installed versions' +complete -kxc mise -n "$fssf uninstall" -s n -l dry-run -d 'Do not actually delete anything' +complete -kxc mise -n "$fssf uninstall" -a "(__mise_installed_tool_versions)" -d 'Tool(s) to remove' + +# upgrade +complete -kxc mise -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' +complete -kxc mise -n "$fssf upgrade" -s i -l interactive -d 'Display multiselect menu to choose which tools to upgrade' +complete -kxc mise -n "$fssf upgrade" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc mise -n "$fssf upgrade" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' +complete -kxc mise -n "$fssf upgrade" -a "(__mise_tool_versions)" -d 'Tool(s) to upgrade' + +# use +complete -kxc mise -n "$fssf use" -s e -l env -d 'Modify an environment-specific config file like .mise..toml' +complete -kxc mise -n "$fssf use" -s f -l force -d 'Force reinstall even if already installed' +complete -kxc mise -n "$fssf use" -l fuzzy -d 'Save fuzzy version to config file' +complete -kxc mise -n "$fssf use" -s g -l global -d 'Use the global config file (~/.config/mise/config.toml) instead of the local one' +complete -kxc mise -n "$fssf use" -s j -l jobs -d 'Number of jobs to run in parallel' +complete -kxc mise -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions' +complete -kxc mise -n "$fssf use" -l pin -d 'Save exact version to config file' +complete -kxc mise -n "$fssf use" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' +complete -kxc mise -n "$fssf use" -l remove -d 'Remove the tool(s) from config file' +complete -kxc mise -n "$fssf use" -a "(__mise_tool_versions)" -d 'Tool(s) to add to config file' + +# version + +# watch +complete -kxc mise -n "$fssf watch" -d 'Extra arguments' +complete -kxc mise -n "$fssf watch" -s g -l glob -d 'Files to watch' +complete -kxc mise -n "$fssf watch" -s t -l task -a "(__mise_tasks)" -d 'Task to run' + +# where +complete -kxc mise -n "$fssf where" -a "(__mise_tool_versions)" -d 'Tool(s) to look up' + +# which +complete -kxc mise -n "$fssf which" -d 'The bin name to look up' +complete -kxc mise -n "$fssf which" -l plugin -a "(__mise_plugins)" -d 'Show the plugin name instead of the path' +complete -kxc mise -n "$fssf which" -s t -l tool -a "(__mise_tool_versions)" -d 'Use a specific tool@version' +complete -kxc mise -n "$fssf which" -l version -d 'Show the version instead of the path' + + + +function __mise_all_plugins + if test -z "$__mise_all_plugins_cache" + set -g __mise_all_plugins_cache (mise plugins ls --all) + end + for p in $__mise_all_plugins_cache + echo $p + end +end +function __mise_plugins + if test -z "$__mise_plugins_cache" + set -g __mise_plugins_cache (mise plugins ls --core --user) + end + for p in $__mise_plugins_cache + echo $p + end +end +function __mise_tool_versions + if test -z "$__mise_tool_versions_cache" + set -g __mise_tool_versions_cache (mise plugins --core --user) (mise ls-remote --all | tac) + end + for tv in $__mise_tool_versions_cache + echo $tv + end +end +function __mise_installed_tool_versions + for tv in (mise ls --installed | awk '{print $1 "@" $2}') + echo $tv + end +end +function __mise_aliases + if test -z "$__mise_aliases_cache" + set -g __mise_aliases_cache (mise alias ls | awk '{print $2}') + end + for a in $__mise_aliases_cache + echo $a + end +end +function __mise_tasks + for tv in (mise task ls --no-header | awk '{print $1}') + echo $tv + end +end +function __mise_settings + if test -z "$__mise_settings_cache" + set -g __mise_settings_cache (mise settings ls | awk '{print $1}') + end + for s in $__mise_settings_cache + echo $s + end +end + +# vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/completions/rtx.fish b/completions/rtx.fish deleted file mode 100644 index 923f07a93..000000000 --- a/completions/rtx.fish +++ /dev/null @@ -1,408 +0,0 @@ -set -l fssf "__fish_seen_subcommand_from" - -# rtx -complete -kxc rtx -s C -l cd -a "(__fish_complete_directories)" -d 'Change directory before running command' -complete -kxc rtx -s q -l quiet -d 'Suppress non-error messages' -complete -kxc rtx -s v -l verbose -d 'Show extra output (use -vv for even more)' -complete -kxc rtx -s y -l yes -d 'Answer yes to all confirmation prompts' -set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env env-vars exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update settings shell sync task trust uninstall upgrade use version watch where which -complete -xc rtx -n "not $fssf $others" -a activate -d 'Initializes rtx in the current shell session' -complete -xc rtx -n "not $fssf $others" -a alias -d 'Manage aliases' -complete -xc rtx -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' -complete -xc rtx -n "not $fssf $others" -a cache -d 'Manage the rtx cache' -complete -xc rtx -n "not $fssf $others" -a completion -d 'Generate shell completions' -complete -xc rtx -n "not $fssf $others" -a config -d '[experimental] Manage config files' -complete -xc rtx -n "not $fssf $others" -a current -d 'Shows current active and installed runtime versions' -complete -xc rtx -n "not $fssf $others" -a deactivate -d 'Disable rtx for current shell session' -complete -xc rtx -n "not $fssf $others" -a direnv -d 'Output direnv function to use rtx inside direnv' -complete -xc rtx -n "not $fssf $others" -a doctor -d 'Check rtx installation for possible problems.' -complete -xc rtx -n "not $fssf $others" -a env -d 'Exports env vars to activate rtx a single time' -complete -xc rtx -n "not $fssf $others" -a env-vars -d 'Manage environment variables' -complete -xc rtx -n "not $fssf $others" -a exec -d 'Execute a command with tool(s) set' -complete -xc rtx -n "not $fssf $others" -a implode -d 'Removes rtx CLI and all related data' -complete -xc rtx -n "not $fssf $others" -a install -d 'Install a tool version' -complete -xc rtx -n "not $fssf $others" -a latest -d 'Gets the latest available version for a plugin' -complete -xc rtx -n "not $fssf $others" -a link -d 'Symlinks a tool version into rtx' -complete -xc rtx -n "not $fssf $others" -a ls -d 'List installed and/or currently selected tool versions' -complete -xc rtx -n "not $fssf $others" -a ls-remote -d 'List runtime versions available for install' -complete -xc rtx -n "not $fssf $others" -a outdated -d 'Shows outdated tool versions' -complete -xc rtx -n "not $fssf $others" -a plugins -d 'Manage plugins' -complete -xc rtx -n "not $fssf $others" -a prune -d 'Delete unused versions of tools' -complete -xc rtx -n "not $fssf $others" -a reshim -d 'rebuilds the shim farm' -complete -xc rtx -n "not $fssf $others" -a run -d '[experimental] Run a task' -complete -xc rtx -n "not $fssf $others" -a self-update -d 'Updates rtx itself' -complete -xc rtx -n "not $fssf $others" -a settings -d 'Manage settings' -complete -xc rtx -n "not $fssf $others" -a shell -d 'Sets a tool version for the current shell session' -complete -xc rtx -n "not $fssf $others" -a sync -d 'Add tool versions from external tools to rtx' -complete -xc rtx -n "not $fssf $others" -a task -d '[experimental] Manage tasks' -complete -xc rtx -n "not $fssf $others" -a trust -d 'Marks a config file as trusted' -complete -xc rtx -n "not $fssf $others" -a uninstall -d 'Removes runtime versions' -complete -xc rtx -n "not $fssf $others" -a upgrade -d 'Upgrades outdated tool versions' -complete -xc rtx -n "not $fssf $others" -a use -d 'Change the active version of a tool locally or globally.' -complete -xc rtx -n "not $fssf $others" -a version -d 'Show rtx version' -complete -xc rtx -n "not $fssf $others" -a watch -d '[experimental] Run a task watching for changes' -complete -xc rtx -n "not $fssf $others" -a where -d 'Display the installation path for a runtime' -complete -xc rtx -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' - -# activate -complete -kxc rtx -n "$fssf activate" -s q -l quiet -d 'Suppress non-error messages' -complete -kxc rtx -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' -complete -kxc rtx -n "$fssf activate" -l status -d 'Show "rtx: @" message when changing directories' - -# alias -complete -kxc rtx -n "$fssf alias" -l no-header -d 'Don'\''t show table header' -complete -kxc rtx -n "$fssf alias" -s p -l plugin -a "(__rtx_plugins)" -d 'filter aliases by plugin' -set -l others get ls set unset -complete -xc rtx -n "$fssf alias; and not $fssf $others" -a get -d 'Show an alias for a plugin' -complete -xc rtx -n "$fssf alias; and not $fssf $others" -a ls -d 'List aliases' -complete -xc rtx -n "$fssf alias; and not $fssf $others" -a set -d 'Add/update an alias for a plugin' -complete -xc rtx -n "$fssf alias; and not $fssf $others" -a unset -d 'Clears an alias for a plugin' - -# alias get -complete -kxc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_aliases)" -d 'The alias to show' -complete -kxc rtx -n "$fssf alias; and $fssf get" -a "(__rtx_plugins)" -d 'The plugin to show the alias for' - -# alias ls -complete -kxc rtx -n "$fssf alias; and $fssf ls" -l no-header -d 'Don'\''t show table header' -complete -kxc rtx -n "$fssf alias; and $fssf ls" -a "(__rtx_plugins)" -d 'Show aliases for ' - -# alias set -complete -kxc rtx -n "$fssf alias; and $fssf set" -a "(__rtx_aliases)" -d 'The alias to set' -complete -kxc rtx -n "$fssf alias; and $fssf set" -a "(__rtx_plugins)" -d 'The plugin to set the alias for' -complete -kxc rtx -n "$fssf alias; and $fssf set" -d 'The value to set the alias to' - -# alias unset -complete -kxc rtx -n "$fssf alias; and $fssf unset" -a "(__rtx_aliases)" -d 'The alias to remove' -complete -kxc rtx -n "$fssf alias; and $fssf unset" -a "(__rtx_plugins)" -d 'The plugin to remove the alias from' - - -# bin-paths - -# cache -set -l others clear -complete -xc rtx -n "$fssf cache; and not $fssf $others" -a clear -d 'Deletes all cache files in rtx' - -# cache clear -complete -kxc rtx -n "$fssf cache; and $fssf clear" -a "(__rtx_plugins)" -d 'Plugin(s) to clear cache for e.g.: node, python' - - -# completion -complete -kxc rtx -n "$fssf completion" -a "bash fish zsh" -d 'Shell type to generate completions for' - -# config -complete -kxc rtx -n "$fssf config" -l no-header -d 'Do not print table header' -set -l others generate ls -complete -xc rtx -n "$fssf config; and not $fssf $others" -a generate -d '[experimental] Generate an .rtx.toml file' -complete -xc rtx -n "$fssf config; and not $fssf $others" -a ls -d '[experimental] List config files currently in use' - -# config generate -complete -kxc rtx -n "$fssf config; and $fssf generate" -s o -l output -a "(__fish_complete_path)" -d 'Output to file instead of stdout' - -# config ls -complete -kxc rtx -n "$fssf config; and $fssf ls" -l no-header -d 'Do not print table header' - - -# current -complete -kxc rtx -n "$fssf current" -a "(__rtx_plugins)" -d 'Plugin to show versions of e.g.: ruby, node' - -# deactivate - -# direnv -set -l others activate -complete -xc rtx -n "$fssf direnv; and not $fssf $others" -a activate -d 'Output direnv function to use rtx inside direnv' - -# direnv activate - - -# doctor - -# env -complete -kxc rtx -n "$fssf env" -s J -l json -d 'Output in JSON format' -complete -kxc rtx -n "$fssf env" -s s -l shell -a "bash fish nu xonsh zsh" -d 'Shell type to generate environment variables for' -complete -kxc rtx -n "$fssf env" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' - -# env-vars -complete -kxc rtx -n "$fssf env-vars" -d 'Environment variable(s) to set' -complete -kxc rtx -n "$fssf env-vars" -l file -a "(__fish_complete_path)" -d 'The TOML file to update' -complete -kxc rtx -n "$fssf env-vars" -l remove -d 'Remove the environment variable from config file' - -# exec -complete -kxc rtx -n "$fssf exec" -s c -l command -d 'Command string to execute' -complete -kxc rtx -n "$fssf exec" -d 'Command string to execute (same as --command)' -complete -kxc rtx -n "$fssf exec" -s j -l jobs -d 'Number of jobs to run in parallel' -complete -kxc rtx -n "$fssf exec" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' -complete -kxc rtx -n "$fssf exec" -a "(__rtx_tool_versions)" -d 'Tool(s) to start e.g.: node@20 python@3.10' - -# implode -complete -kxc rtx -n "$fssf implode" -l config -d 'Also remove config directory' -complete -kxc rtx -n "$fssf implode" -s n -l dry-run -d 'List directories that would be removed without actually removing them' - -# install -complete -kxc rtx -n "$fssf install" -s f -l force -d 'Force reinstall even if already installed' -complete -kxc rtx -n "$fssf install" -s j -l jobs -d 'Number of jobs to run in parallel' -complete -kxc rtx -n "$fssf install" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' -complete -kxc rtx -n "$fssf install" -a "(__rtx_tool_versions)" -d 'Tool(s) to install e.g.: node@20' -complete -kxc rtx -n "$fssf install" -s v -l verbose -d 'Show installation output' - -# latest -complete -kxc rtx -n "$fssf latest" -s i -l installed -d 'Show latest installed instead of available version' -complete -kxc rtx -n "$fssf latest" -a "(__rtx_tool_versions)" -d 'Tool to get the latest version of' - -# link -complete -kxc rtx -n "$fssf link" -s f -l force -d 'Overwrite an existing tool version if it exists' -complete -kxc rtx -n "$fssf link" -a "(__fish_complete_directories)" -d 'The local path to the tool version' -complete -kxc rtx -n "$fssf link" -a "(__rtx_tool_versions)" -d 'Tool name and version to create a symlink for' - -# ls -complete -kxc rtx -n "$fssf ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.rtx.toml' -complete -kxc rtx -n "$fssf ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.rtx.toml' -complete -kxc rtx -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed' -complete -kxc rtx -n "$fssf ls" -s J -l json -d 'Output in json format' -complete -kxc rtx -n "$fssf ls" -s m -l missing -d 'Display missing tool versions' -complete -kxc rtx -n "$fssf ls" -l no-header -d 'Don'\''t display headers' -complete -kxc rtx -n "$fssf ls" -a "(__rtx_plugins)" -d 'Only show tool versions from [PLUGIN]' -complete -kxc rtx -n "$fssf ls" -l prefix -d 'Display versions matching this prefix' - -# ls-remote -complete -kxc rtx -n "$fssf ls-remote" -l all -d 'Show all installed plugins and versions' -complete -kxc rtx -n "$fssf ls-remote" -a "(__rtx_plugins)" -d 'Plugin to get versions for' -complete -kxc rtx -n "$fssf ls-remote" -d 'The version prefix to use when querying the latest version' - -# outdated -complete -kxc rtx -n "$fssf outdated" -a "(__rtx_tool_versions)" -d 'Tool(s) to show outdated versions for' - -# plugins -complete -kxc rtx -n "$fssf plugins" -s c -l core -d 'The built-in plugins only' -complete -kxc rtx -n "$fssf plugins" -s u -l urls -d 'Show the git url for each plugin' -complete -kxc rtx -n "$fssf plugins" -l user -d 'List installed plugins' -set -l others install link ls ls-remote uninstall update -complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a install -d 'Install a plugin' -complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a link -d 'Symlinks a plugin into rtx' -complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a ls -d 'List installed plugins' -complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a ls-remote -d 'List all available remote plugins' -complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a uninstall -d 'Removes a plugin' -complete -xc rtx -n "$fssf plugins; and not $fssf $others" -a update -d 'Updates a plugin to the latest version' - -# plugins install -complete -kxc rtx -n "$fssf plugins; and $fssf install" -s a -l all -d 'Install all missing plugins' -complete -kxc rtx -n "$fssf plugins; and $fssf install" -s f -l force -d 'Reinstall even if plugin exists' -complete -kxc rtx -n "$fssf plugins; and $fssf install" -d 'The git url of the plugin' -complete -kxc rtx -n "$fssf plugins; and $fssf install" -a "(__rtx_all_plugins)" -d 'The name of the plugin to install' -complete -kxc rtx -n "$fssf plugins; and $fssf install" -s v -l verbose -d 'Show installation output' - -# plugins link -complete -kxc rtx -n "$fssf plugins; and $fssf link" -s f -l force -d 'Overwrite existing plugin' -complete -kxc rtx -n "$fssf plugins; and $fssf link" -d 'The name of the plugin' -complete -kxc rtx -n "$fssf plugins; and $fssf link" -a "(__fish_complete_directories)" -d 'The local path to the plugin' - -# plugins ls -complete -kxc rtx -n "$fssf plugins; and $fssf ls" -s c -l core -d 'The built-in plugins only' -complete -kxc rtx -n "$fssf plugins; and $fssf ls" -s u -l urls -d 'Show the git url for each plugin' -complete -kxc rtx -n "$fssf plugins; and $fssf ls" -l user -d 'List installed plugins' - -# plugins ls-remote -complete -kxc rtx -n "$fssf plugins; and $fssf ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' -complete -kxc rtx -n "$fssf plugins; and $fssf ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' - -# plugins uninstall -complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -s a -l all -d 'Remove all plugins' -complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -a "(__rtx_plugins)" -d 'Plugin(s) to remove' -complete -kxc rtx -n "$fssf plugins; and $fssf uninstall" -s p -l purge -d 'Also remove the plugin'\''s installs, downloads, and cache' - -# plugins update -complete -kxc rtx -n "$fssf plugins; and $fssf update" -s j -l jobs -d 'Number of jobs to run in parallel' -complete -kxc rtx -n "$fssf plugins; and $fssf update" -a "(__rtx_plugins)" -d 'Plugin(s) to update' - - -# prune -complete -kxc rtx -n "$fssf prune" -s n -l dry-run -d 'Do not actually delete anything' -complete -kxc rtx -n "$fssf prune" -a "(__rtx_plugins)" -d 'Prune only versions from these plugins' - -# reshim - -# run -complete -kxc rtx -n "$fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' -complete -kxc rtx -n "$fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' -complete -kxc rtx -n "$fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' -complete -kxc rtx -n "$fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' -complete -kxc rtx -n "$fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' -complete -kxc rtx -n "$fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' -complete -kxc rtx -n "$fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' -complete -kxc rtx -n "$fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' -complete -kxc rtx -n "$fssf run" -a "(__rtx_tasks)" -d 'Task to run' -complete -kxc rtx -n "$fssf run" -s t -l tool -a "(__rtx_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' - -# self-update -complete -kxc rtx -n "$fssf self-update" -s f -l force -d 'Update even if already up to date' -complete -kxc rtx -n "$fssf self-update" -l no-plugins -d 'Disable auto-updating plugins' -complete -kxc rtx -n "$fssf self-update" -d 'Update to a specific version' -complete -kxc rtx -n "$fssf self-update" -s y -l yes -d 'Skip confirmation prompt' - -# settings -set -l others get ls set unset -complete -xc rtx -n "$fssf settings; and not $fssf $others" -a get -d 'Show a current setting' -complete -xc rtx -n "$fssf settings; and not $fssf $others" -a ls -d 'Show current settings' -complete -xc rtx -n "$fssf settings; and not $fssf $others" -a set -d 'Add/update a setting' -complete -xc rtx -n "$fssf settings; and not $fssf $others" -a unset -d 'Clears a setting' - -# settings get -complete -kxc rtx -n "$fssf settings; and $fssf get" -a "(__rtx_settings)" -d 'The setting to show' - -# settings ls - -# settings set -complete -kxc rtx -n "$fssf settings; and $fssf set" -a "(__rtx_settings)" -d 'The setting to set' -complete -kxc rtx -n "$fssf settings; and $fssf set" -d 'The value to set' - -# settings unset -complete -kxc rtx -n "$fssf settings; and $fssf unset" -a "(__rtx_settings)" -d 'The setting to remove' - - -# shell -complete -kxc rtx -n "$fssf shell" -s j -l jobs -d 'Number of jobs to run in parallel' -complete -kxc rtx -n "$fssf shell" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' -complete -kxc rtx -n "$fssf shell" -a "(__rtx_tool_versions)" -d 'Tool(s) to use' -complete -kxc rtx -n "$fssf shell" -s u -l unset -d 'Removes a previously set version' - -# sync -set -l others node python -complete -xc rtx -n "$fssf sync; and not $fssf $others" -a node -d 'Symlinks all tool versions from an external tool into rtx' -complete -xc rtx -n "$fssf sync; and not $fssf $others" -a python -d 'Symlinks all tool versions from an external tool into rtx' - -# sync node -complete -kxc rtx -n "$fssf sync; and $fssf node" -l brew -d 'Get tool versions from Homebrew' -complete -kxc rtx -n "$fssf sync; and $fssf node" -l nodenv -d 'Get tool versions from nodenv' -complete -kxc rtx -n "$fssf sync; and $fssf node" -l nvm -d 'Get tool versions from nvm' - -# sync python -complete -kxc rtx -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versions from pyenv' - - -# task -complete -kxc rtx -n "$fssf task" -l hidden -d 'Show hidden tasks' -complete -kxc rtx -n "$fssf task" -l no-header -d 'Do not print table header' -set -l others edit ls run -complete -xc rtx -n "$fssf task; and not $fssf $others" -a edit -d '[experimental] Edit a task with $EDITOR' -complete -xc rtx -n "$fssf task; and not $fssf $others" -a ls -d '[experimental] List available tasks to execute' -complete -xc rtx -n "$fssf task; and not $fssf $others" -a run -d '[experimental] Run a task' - -# task edit -complete -kxc rtx -n "$fssf task; and $fssf edit" -s p -l path -d 'Display the path to the task instead of editing it' -complete -kxc rtx -n "$fssf task; and $fssf edit" -a "(__rtx_tasks)" -d 'Task to edit' - -# task ls -complete -kxc rtx -n "$fssf task; and $fssf ls" -l hidden -d 'Show hidden tasks' -complete -kxc rtx -n "$fssf task; and $fssf ls" -l no-header -d 'Do not print table header' - -# task run -complete -kxc rtx -n "$fssf task; and $fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' -complete -kxc rtx -n "$fssf task; and $fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' -complete -kxc rtx -n "$fssf task; and $fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' -complete -kxc rtx -n "$fssf task; and $fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' -complete -kxc rtx -n "$fssf task; and $fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' -complete -kxc rtx -n "$fssf task; and $fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' -complete -kxc rtx -n "$fssf task; and $fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' -complete -kxc rtx -n "$fssf task; and $fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' -complete -kxc rtx -n "$fssf task; and $fssf run" -a "(__rtx_tasks)" -d 'Task to run' -complete -kxc rtx -n "$fssf task; and $fssf run" -s t -l tool -a "(__rtx_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' - - -# trust -complete -kxc rtx -n "$fssf trust" -s a -l all -d 'Trust all config files in the current directory and its parents' -complete -kxc rtx -n "$fssf trust" -a "(__fish_complete_path)" -d 'The config file to trust' -complete -kxc rtx -n "$fssf trust" -l untrust -d 'No longer trust this config' - -# uninstall -complete -kxc rtx -n "$fssf uninstall" -s a -l all -d 'Delete all installed versions' -complete -kxc rtx -n "$fssf uninstall" -s n -l dry-run -d 'Do not actually delete anything' -complete -kxc rtx -n "$fssf uninstall" -a "(__rtx_installed_tool_versions)" -d 'Tool(s) to remove' - -# upgrade -complete -kxc rtx -n "$fssf upgrade" -s n -l dry-run -d 'Just print what would be done, don'\''t actually do it' -complete -kxc rtx -n "$fssf upgrade" -s i -l interactive -d 'Display multiselect menu to choose which tools to upgrade' -complete -kxc rtx -n "$fssf upgrade" -s j -l jobs -d 'Number of jobs to run in parallel' -complete -kxc rtx -n "$fssf upgrade" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' -complete -kxc rtx -n "$fssf upgrade" -a "(__rtx_tool_versions)" -d 'Tool(s) to upgrade' - -# use -complete -kxc rtx -n "$fssf use" -s e -l env -d 'Modify an environment-specific config file like .rtx..toml' -complete -kxc rtx -n "$fssf use" -s f -l force -d 'Force reinstall even if already installed' -complete -kxc rtx -n "$fssf use" -l fuzzy -d 'Save fuzzy version to config file' -complete -kxc rtx -n "$fssf use" -s g -l global -d 'Use the global config file (~/.config/rtx/config.toml) instead of the local one' -complete -kxc rtx -n "$fssf use" -s j -l jobs -d 'Number of jobs to run in parallel' -complete -kxc rtx -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions' -complete -kxc rtx -n "$fssf use" -l pin -d 'Save exact version to config file' -complete -kxc rtx -n "$fssf use" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' -complete -kxc rtx -n "$fssf use" -l remove -d 'Remove the tool(s) from config file' -complete -kxc rtx -n "$fssf use" -a "(__rtx_tool_versions)" -d 'Tool(s) to add to config file' - -# version - -# watch -complete -kxc rtx -n "$fssf watch" -d 'Extra arguments' -complete -kxc rtx -n "$fssf watch" -s g -l glob -d 'Files to watch' -complete -kxc rtx -n "$fssf watch" -s t -l task -a "(__rtx_tasks)" -d 'Task to run' - -# where -complete -kxc rtx -n "$fssf where" -a "(__rtx_tool_versions)" -d 'Tool(s) to look up' - -# which -complete -kxc rtx -n "$fssf which" -d 'The bin name to look up' -complete -kxc rtx -n "$fssf which" -l plugin -a "(__rtx_plugins)" -d 'Show the plugin name instead of the path' -complete -kxc rtx -n "$fssf which" -s t -l tool -a "(__rtx_tool_versions)" -d 'Use a specific tool@version' -complete -kxc rtx -n "$fssf which" -l version -d 'Show the version instead of the path' - - - -function __rtx_all_plugins - if test -z "$__rtx_all_plugins_cache" - set -g __rtx_all_plugins_cache (rtx plugins ls --all) - end - for p in $__rtx_all_plugins_cache - echo $p - end -end -function __rtx_plugins - if test -z "$__rtx_plugins_cache" - set -g __rtx_plugins_cache (rtx plugins ls --core --user) - end - for p in $__rtx_plugins_cache - echo $p - end -end -function __rtx_tool_versions - if test -z "$__rtx_tool_versions_cache" - set -g __rtx_tool_versions_cache (rtx plugins --core --user) (rtx ls-remote --all | tac) - end - for tv in $__rtx_tool_versions_cache - echo $tv - end -end -function __rtx_installed_tool_versions - for tv in (rtx ls --installed | awk '{print $1 "@" $2}') - echo $tv - end -end -function __rtx_aliases - if test -z "$__rtx_aliases_cache" - set -g __rtx_aliases_cache (rtx alias ls | awk '{print $2}') - end - for a in $__rtx_aliases_cache - echo $a - end -end -function __rtx_tasks - for tv in (rtx task ls --no-header | awk '{print $1}') - echo $tv - end -end -function __rtx_settings - if test -z "$__rtx_settings_cache" - set -g __rtx_settings_cache (rtx settings ls | awk '{print $1}') - end - for s in $__rtx_settings_cache - echo $s - end -end - -# vim: noet ci pi sts=0 sw=4 ts=4 diff --git a/default.nix b/default.nix index 15b0bdaa3..d560790d7 100644 --- a/default.nix +++ b/default.nix @@ -6,7 +6,7 @@ let }; in rustPlatform.buildRustPackage { - pname = "rtx"; + pname = "mise"; version = "2024.0.0"; src = lib.cleanSource ./.; @@ -51,7 +51,7 @@ rustPlatform.buildRustPackage { meta = with lib; { description = "The front-end to your dev env"; - homepage = "https://github.com/jdx/rtx"; + homepage = "https://github.com/jdx/mise"; license = licenses.mit; }; } diff --git a/docs/bun.md b/docs/bun.md index ea7fa4aad..052b9204e 100644 --- a/docs/bun.md +++ b/docs/bun.md @@ -1 +1 @@ -See [rtx.jdx.dev](https://rtx.jdx.dev/lang/bun.html) for more information. +See [mise.jdx.dev](https://mise.jdx.dev/lang/bun.html) for more information. diff --git a/docs/cli-reference.md b/docs/cli-reference.md index ffe9720e1..403b3b761 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -1,28 +1,28 @@ - + ## Commands -### `rtx activate [OPTIONS] [SHELL_TYPE]` +### `mise activate [OPTIONS] [SHELL_TYPE]` ```text -Initializes rtx in the current shell session +Initializes mise in the current shell session This should go into your shell's rc file. Otherwise, it will only take effect in the current session. (e.g. ~/.zshrc, ~/.bashrc) This is only intended to be used in interactive sessions, not scripts. -rtx is only capable of updating PATH when the prompt is displayed to the user. +mise is only capable of updating PATH when the prompt is displayed to the user. For non-interactive use-cases, use shims instead. Typically this can be added with something like the following: - echo 'eval "$(rtx activate)"' >> ~/.zshrc + echo 'eval "$(mise activate)"' >> ~/.zshrc -However, this requires that "rtx" is in your PATH. If it is not, you need to +However, this requires that "mise" is in your PATH. If it is not, you need to specify the full path like this: - echo 'eval "$(/path/to/rtx activate)"' >> ~/.zshrc + echo 'eval "$(/path/to/mise activate)"' >> ~/.zshrc Usage: activate [OPTIONS] [SHELL_TYPE] @@ -34,24 +34,24 @@ Arguments: Options: --status - Show "rtx: @" message when changing directories + Show "mise: @" message when changing directories -q, --quiet Suppress non-error messages Examples: - $ eval "$(rtx activate bash)" - $ eval "$(rtx activate zsh)" - $ rtx activate fish | source - $ execx($(rtx activate xonsh)) + $ eval "$(mise activate bash)" + $ eval "$(mise activate zsh)" + $ mise activate fish | source + $ execx($(mise activate xonsh)) ``` -### `rtx alias get ` +### `mise alias get ` ```text Show an alias for a plugin -This is the contents of an alias. entry in ~/.config/rtx/config.toml +This is the contents of an alias. entry in ~/.config/mise/config.toml Usage: alias get @@ -63,11 +63,11 @@ Arguments: The alias to show Examples: - $ rtx alias get node lts-hydrogen + $ mise alias get node lts-hydrogen 20.0.0 ``` -### `rtx alias ls [OPTIONS] [PLUGIN]` +### `mise alias ls [OPTIONS] [PLUGIN]` **Aliases:** `list` @@ -76,7 +76,7 @@ List aliases Shows the aliases that can be specified. These can come from user config or from plugins in `bin/list-aliases`. -For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: +For user config, aliases are defined like the following in `~/.config/mise/config.toml`: [alias.node] lts = "20.0.0" @@ -92,18 +92,18 @@ Options: Don't show table header Examples: - $ rtx aliases + $ mise aliases node lts-hydrogen 20.0.0 ``` -### `rtx alias set ` +### `mise alias set ` **Aliases:** `add, create` ```text Add/update an alias for a plugin -This modifies the contents of ~/.config/rtx/config.toml +This modifies the contents of ~/.config/mise/config.toml Usage: alias set @@ -118,17 +118,17 @@ Arguments: The value to set the alias to Examples: - $ rtx alias set node lts-hydrogen 18.0.0 + $ mise alias set node lts-hydrogen 18.0.0 ``` -### `rtx alias unset ` +### `mise alias unset ` **Aliases:** `del, delete, remove, rm` ```text Clears an alias for a plugin -This modifies the contents of ~/.config/rtx/config.toml +This modifies the contents of ~/.config/mise/config.toml Usage: alias unset @@ -140,10 +140,10 @@ Arguments: The alias to remove Examples: - $ rtx alias unset node lts-hydrogen + $ mise alias unset node lts-hydrogen ``` -### `rtx bin-paths` +### `mise bin-paths` ```text List all the active runtime bin paths @@ -151,12 +151,12 @@ List all the active runtime bin paths Usage: bin-paths ``` -### `rtx cache clear [PLUGIN]...` +### `mise cache clear [PLUGIN]...` **Aliases:** `c` ```text -Deletes all cache files in rtx +Deletes all cache files in mise Usage: cache clear [PLUGIN]... @@ -165,7 +165,7 @@ Arguments: Plugin(s) to clear cache for e.g.: node, python ``` -### `rtx completion [SHELL]` +### `mise completion [SHELL]` ```text Generate shell completions @@ -179,12 +179,12 @@ Arguments: [possible values: bash, fish, zsh] Examples: - $ rtx completion bash > /etc/bash_completion.d/rtx - $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx - $ rtx completion fish > ~/.config/fish/completions/rtx.fish + $ mise completion bash > /etc/bash_completion.d/mise + $ mise completion zsh > /usr/local/share/zsh/site-functions/_mise + $ mise completion fish > ~/.config/fish/completions/mise.fish ``` -### `rtx config ls [OPTIONS]` +### `mise config ls [OPTIONS]` ```text [experimental] List config files currently in use @@ -196,15 +196,15 @@ Options: Do not print table header Examples: - $ rtx config ls + $ mise config ls ``` -### `rtx config generate [OPTIONS]` +### `mise config generate [OPTIONS]` **Aliases:** `g` ```text -[experimental] Generate an .rtx.toml file +[experimental] Generate an .mise.toml file Usage: config generate [OPTIONS] @@ -213,16 +213,16 @@ Options: Output to file instead of stdout Examples: - $ rtx cf generate > .rtx.toml - $ rtx cf generate --output=.rtx.toml + $ mise cf generate > .mise.toml + $ mise cf generate --output=.mise.toml ``` -### `rtx current [PLUGIN]` +### `mise current [PLUGIN]` ```text Shows current active and installed runtime versions -This is similar to `rtx ls --current`, but this only shows the runtime +This is similar to `mise ls --current`, but this only shows the runtime and/or version. It's designed to fit into scripts more easily. Usage: current [PLUGIN] @@ -233,42 +233,42 @@ Arguments: Examples: # outputs `.tool-versions` compatible format - $ rtx current + $ mise current python 3.11.0 3.10.0 shfmt 3.6.0 shellcheck 0.9.0 node 20.0.0 - $ rtx current node + $ mise current node 20.0.0 # can output multiple versions - $ rtx current python + $ mise current python 3.11.0 3.10.0 ``` -### `rtx deactivate` +### `mise deactivate` ```text -Disable rtx for current shell session +Disable mise for current shell session -This can be used to temporarily disable rtx in a shell session. +This can be used to temporarily disable mise in a shell session. Usage: deactivate Examples: - $ rtx deactivate bash - $ rtx deactivate zsh - $ rtx deactivate fish - $ execx($(rtx deactivate xonsh)) + $ mise deactivate bash + $ mise deactivate zsh + $ mise deactivate fish + $ execx($(mise deactivate xonsh)) ``` -### `rtx direnv activate` +### `mise direnv activate` ```text -Output direnv function to use rtx inside direnv +Output direnv function to use mise inside direnv -See https://github.com/jdx/rtx#direnv for more information +See https://mise.jdx.dev/direnv.html for more information Because this generates the legacy files based on currently installed plugins, you should run this command after installing new plugins. Otherwise @@ -277,32 +277,32 @@ direnv may not know to update environment variables when legacy file versions ch Usage: direnv activate Examples: - $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh - $ echo 'use rtx' > .envrc + $ mise direnv activate > ~/.config/direnv/lib/use_mise.sh + $ echo 'use mise' > .envrc $ direnv allow ``` -### `rtx doctor` +### `mise doctor` ```text -Check rtx installation for possible problems. +Check mise installation for possible problems. Usage: doctor Examples: - $ rtx doctor + $ mise doctor [WARN] plugin node is not installed ``` -### `rtx env [OPTIONS] [TOOL@VERSION]...` +### `mise env [OPTIONS] [TOOL@VERSION]...` **Aliases:** `e` ```text -Exports env vars to activate rtx a single time +Exports env vars to activate mise a single time -Use this if you don't want to permanently install rtx. It's not necessary to -use this if you have `rtx activate` in your shell rc file. +Use this if you don't want to permanently install mise. It's not necessary to +use this if you have `mise activate` in your shell rc file. Usage: env [OPTIONS] [TOOL@VERSION]... @@ -320,21 +320,21 @@ Options: Output in JSON format Examples: - $ eval "$(rtx env -s bash)" - $ eval "$(rtx env -s zsh)" - $ rtx env -s fish | source - $ execx($(rtx env -s xonsh)) + $ eval "$(mise env -s bash)" + $ eval "$(mise env -s zsh)" + $ mise env -s fish | source + $ execx($(mise env -s xonsh)) ``` -### `rtx env-vars [OPTIONS] [ENV_VARS]...` +### `mise env-vars [OPTIONS] [ENV_VARS]...` **Aliases:** `ev` ```text Manage environment variables -By default this command modifies ".rtx.toml" in the current directory. -You can specify the file name by either setting the RTX_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. +By default this command modifies ".mise.toml" in the current directory. +You can specify the file name by either setting the MISE_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. Usage: env-vars [OPTIONS] [ENV_VARS]... @@ -347,7 +347,7 @@ Options: --file The TOML file to update - Defaults to RTX_DEFAULT_CONFIG_FILENAME environment variable, or ".rtx.toml". + Defaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or ".mise.toml". --remove Remove the environment variable from config file @@ -355,18 +355,18 @@ Options: Can be used multiple times. ``` -### `rtx exec [OPTIONS] [TOOL@VERSION]... [-- ...]` +### `mise exec [OPTIONS] [TOOL@VERSION]... [-- ...]` **Aliases:** `x` ```text Execute a command with tool(s) set -use this to avoid modifying the shell session or running ad-hoc commands with rtx tools set. +use this to avoid modifying the shell session or running ad-hoc commands with mise tools set. -Tools will be loaded from .rtx.toml/.tool-versions, though they can be overridden with args +Tools will be loaded from .mise.toml/.tool-versions, though they can be overridden with args Note that only the plugin specified will be overridden, so if a `.tool-versions` file -includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. +includes "node 20" but you run `mise exec python@3.11`; it will still load node@20. The "--" separates runtimes from the commands to pass along to the subprocess. @@ -387,26 +387,26 @@ Options: Number of jobs to run in parallel [default: 4] - [env: RTX_JOBS=] + [env: MISE_JOBS=] --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 Examples: - $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x - $ rtx x node@20 -- node ./app.js # shorter alias + $ mise exec node@20 -- node ./app.js # launch app.js using node-20.x + $ mise x node@20 -- node ./app.js # shorter alias # Specify command as a string: - $ rtx exec node@20 python@3.11 --command "node -v && python -V" + $ mise exec node@20 python@3.11 --command "node -v && python -V" # Run a command in a different directory: - $ rtx x -C /path/to/project node@20 -- node ./app.js + $ mise x -C /path/to/project node@20 -- node ./app.js ``` -### `rtx implode [OPTIONS]` +### `mise implode [OPTIONS]` ```text -Removes rtx CLI and all related data +Removes mise CLI and all related data Skips config directory by default. @@ -420,19 +420,19 @@ Options: List directories that would be removed without actually removing them ``` -### `rtx install [OPTIONS] [TOOL@VERSION]...` +### `mise install [OPTIONS] [TOOL@VERSION]...` **Aliases:** `i` ```text Install a tool version -This will install a tool version to `~/.local/share/rtx/installs//` +This will install a tool version to `~/.local/share/mise/installs//` It won't be used simply by being installed, however. -For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. -Or you can call a tool version explicitly with `rtx exec @ -- `. +For that, you must set up a `.mise.toml`/`.tool-version` file manually or with `mise use`. +Or you can call a tool version explicitly with `mise exec @ -- `. -Tools will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` +Tools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1` Usage: install [OPTIONS] [TOOL@VERSION]... @@ -448,7 +448,7 @@ Options: Number of jobs to run in parallel [default: 4] - [env: RTX_JOBS=] + [env: MISE_JOBS=] --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 @@ -457,13 +457,13 @@ Options: Show installation output Examples: - $ rtx install node@20.0.0 # install specific node version - $ rtx install node@20 # install fuzzy node version - $ rtx install node # install version specified in .tool-versions or .rtx.toml - $ rtx install # installs everything specified in .tool-versions or .rtx.toml + $ mise install node@20.0.0 # install specific node version + $ mise install node@20 # install fuzzy node version + $ mise install node # install version specified in .tool-versions or .mise.toml + $ mise install # installs everything specified in .tool-versions or .mise.toml ``` -### `rtx latest [OPTIONS] ` +### `mise latest [OPTIONS] ` ```text Gets the latest available version for a plugin @@ -479,22 +479,22 @@ Options: Show latest installed instead of available version Examples: - $ rtx latest node@20 # get the latest version of node 20 + $ mise latest node@20 # get the latest version of node 20 20.0.0 - $ rtx latest node # get the latest stable version of node + $ mise latest node # get the latest stable version of node 20.0.0 ``` -### `rtx link [OPTIONS] ` +### `mise link [OPTIONS] ` **Aliases:** `ln` ```text -Symlinks a tool version into rtx +Symlinks a tool version into mise Use this for adding installs either custom compiled outside -rtx or built with a different tool. +mise or built with a different tool. Usage: link [OPTIONS] @@ -511,17 +511,17 @@ Options: Overwrite an existing tool version if it exists Examples: - # build node-20.0.0 with node-build and link it into rtx + # build node-20.0.0 with node-build and link it into mise $ node-build 20.0.0 ~/.nodes/20.0.0 - $ rtx link node@20.0.0 ~/.nodes/20.0.0 + $ mise link node@20.0.0 ~/.nodes/20.0.0 - # have rtx use the python version provided by Homebrew + # have mise use the python version provided by Homebrew $ brew install node - $ rtx link node@brew $(brew --prefix node) - $ rtx use node@brew + $ mise link node@brew $(brew --prefix node) + $ mise use node@brew ``` -### `rtx ls [OPTIONS] [PLUGIN]...` +### `mise ls [OPTIONS] [PLUGIN]...` **Aliases:** `list` @@ -536,13 +536,13 @@ Arguments: Options: -c, --current - Only show tool versions currently specified in a .tool-versions/.rtx.toml + Only show tool versions currently specified in a .tool-versions/.mise.toml -g, --global - Only show tool versions currently specified in a the global .tool-versions/.rtx.toml + Only show tool versions currently specified in a the global .tool-versions/.mise.toml -i, --installed - Only show tool versions that are installed Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed + Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed -J, --json Output in json format @@ -557,24 +557,24 @@ Options: Don't display headers Examples: - $ rtx ls + $ mise ls node 20.0.0 ~/src/myapp/.tool-versions latest python 3.11.0 ~/.tool-versions 3.10 python 3.10.0 - $ rtx ls --current + $ mise ls --current node 20.0.0 ~/src/myapp/.tool-versions 20 python 3.11.0 ~/.tool-versions 3.11.0 - $ rtx ls --json + $ mise ls --json { "node": [ { "version": "20.0.0", - "install_path": "/Users/jdx/.rtx/installs/node/20.0.0", + "install_path": "/Users/jdx/.mise/installs/node/20.0.0", "source": { - "type": ".rtx.toml", - "path": "/Users/jdx/.rtx.toml" + "type": ".mise.toml", + "path": "/Users/jdx/.mise.toml" } } ], @@ -582,13 +582,13 @@ Examples: } ``` -### `rtx ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` +### `mise ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` ```text List runtime versions available for install note that the results are cached for 24 hours -run `rtx cache clean` to clear the cache and get fresh results +run `mise cache clean` to clear the cache and get fresh results Usage: ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX] @@ -605,20 +605,20 @@ Options: Show all installed plugins and versions Examples: - $ rtx ls-remote node + $ mise ls-remote node 18.0.0 20.0.0 - $ rtx ls-remote node@20 + $ mise ls-remote node@20 20.0.0 20.1.0 - $ rtx ls-remote node 20 + $ mise ls-remote node 20 20.0.0 20.1.0 ``` -### `rtx outdated [TOOL@VERSION]...` +### `mise outdated [TOOL@VERSION]...` ```text Shows outdated tool versions @@ -632,27 +632,27 @@ Arguments: If not specified, all tools in global and local configs will be shown Examples: - $ rtx outdated + $ mise outdated Plugin Requested Current Latest python 3.11 3.11.0 3.11.1 node 20 20.0.0 20.1.0 - $ rtx outdated node + $ mise outdated node Plugin Requested Current Latest node 20 20.0.0 20.1.0 ``` -### `rtx plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` +### `mise plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` **Aliases:** `a, add, i` ```text Install a plugin -note that rtx automatically can install plugins when you install a tool -e.g.: `rtx install node@20` will autoinstall the node plugin +note that mise automatically can install plugins when you install a tool +e.g.: `mise install node@20` will autoinstall the node plugin -This behavior can be modified in ~/.config/rtx/config.toml +This behavior can be modified in ~/.config/mise/config.toml Usage: plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL] @@ -660,7 +660,7 @@ Arguments: [NEW_PLUGIN] The name of the plugin to install e.g.: node, ruby - Can specify multiple plugins: `rtx plugins install node ruby python` + Can specify multiple plugins: `mise plugins install node ruby python` [GIT_URL] The git url of the plugin @@ -679,25 +679,25 @@ Options: Examples: # install the node via shorthand - $ rtx plugins install node + $ mise plugins install node # install the node plugin using a specific git url - $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git # install the node plugin using the git url only # (node is inferred from the url) - $ rtx plugins install https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install https://github.com/rtx-plugins/rtx-nodejs.git # install the node plugin using a specific ref - $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 + $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 ``` -### `rtx plugins link [OPTIONS] [PATH]` +### `mise plugins link [OPTIONS] [PATH]` **Aliases:** `ln` ```text -Symlinks a plugin into rtx +Symlinks a plugin into mise This is used for developing a plugin. @@ -710,21 +710,21 @@ Arguments: [PATH] The local path to the plugin - e.g.: ./rtx-node + e.g.: ./mise-node Options: -f, --force Overwrite existing plugin Examples: - # essentially just `ln -s ./rtx-node ~/.local/share/rtx/plugins/node` - $ rtx plugins link node ./rtx-node + # essentially just `ln -s ./mise-node ~/.local/share/mise/plugins/node` + $ mise plugins link node ./mise-node # infer plugin name as "node" - $ rtx plugins link ./rtx-node + $ mise plugins link ./mise-node ``` -### `rtx plugins ls [OPTIONS]` +### `mise plugins ls [OPTIONS]` **Aliases:** `list` @@ -751,26 +751,26 @@ Options: e.g.: https://github.com/asdf-vm/asdf-node.git Examples: - $ rtx plugins ls + $ mise plugins ls node ruby - $ rtx plugins ls --urls + $ mise plugins ls --urls node https://github.com/asdf-vm/asdf-node.git ruby https://github.com/asdf-vm/asdf-ruby.git ``` -### `rtx plugins ls-remote [OPTIONS]` +### `mise plugins ls-remote [OPTIONS]` **Aliases:** `list-all, list-remote` ```text List all available remote plugins -The full list is here: https://github.com/jdx/rtx/blob/main/src/default_shorthands.rs +The full list is here: https://github.com/jdx/mise/blob/main/src/default_shorthands.rs Examples: - $ rtx plugins ls-remote + $ mise plugins ls-remote Usage: plugins ls-remote [OPTIONS] @@ -783,7 +783,7 @@ Options: Only show the name of each plugin by default it will show a "*" next to installed plugins ``` -### `rtx plugins uninstall [OPTIONS] [PLUGIN]...` +### `mise plugins uninstall [OPTIONS] [PLUGIN]...` **Aliases:** `remove, rm` @@ -804,10 +804,10 @@ Options: Remove all plugins Examples: - $ rtx uninstall node + $ mise uninstall node ``` -### `rtx plugins update [OPTIONS] [PLUGIN]...` +### `mise plugins update [OPTIONS] [PLUGIN]...` **Aliases:** `upgrade` @@ -828,20 +828,20 @@ Options: Default: 4 Examples: - $ rtx plugins update # update all plugins - $ rtx plugins update node # update only node - $ rtx plugins update node#beta # specify a ref + $ mise plugins update # update all plugins + $ mise plugins update node # update only node + $ mise plugins update node#beta # specify a ref ``` -### `rtx prune [OPTIONS] [PLUGIN]...` +### `mise prune [OPTIONS] [PLUGIN]...` ```text Delete unused versions of tools -rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +mise tracks which config files have been used in ~/.local/share/mise/tracked_config_files Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -as will versions only referenced on the command line (`rtx exec @`). +Versions installed only with environment variables (`MISE__VERSION`) will be deleted, +as will versions only referenced on the command line (`mise exec @`). Usage: prune [OPTIONS] [PLUGIN]... @@ -854,39 +854,39 @@ Options: Do not actually delete anything Examples: - $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/node/20.0.0 - rm -rf ~/.local/share/rtx/versions/node/20.0.1 + $ mise prune --dry-run + rm -rf ~/.local/share/mise/versions/node/20.0.0 + rm -rf ~/.local/share/mise/versions/node/20.0.1 ``` -### `rtx reshim` +### `mise reshim` ```text rebuilds the shim farm -This creates new shims in ~/.local/share/rtx/shims for CLIs that have been added. -rtx will try to do this automatically for commands like `npm i -g` but there are -other ways to install things (like using yarn or pnpm for node) that rtx does +This creates new shims in ~/.local/share/mise/shims for CLIs that have been added. +mise will try to do this automatically for commands like `npm i -g` but there are +other ways to install things (like using yarn or pnpm for node) that mise does not know about and so it will be necessary to call this explicitly. -If you think rtx should automatically call this for a particular command, please -open an issue on the rtx repo. You can also setup a shell function to reshim +If you think mise should automatically call this for a particular command, please +open an issue on the mise repo. You can also setup a shell function to reshim automatically (it's really fast so you don't need to worry about overhead): npm() { command npm "$@" - rtx reshim + mise reshim } Usage: reshim Examples: - $ rtx reshim - $ ~/.local/share/rtx/shims/node -v + $ mise reshim + $ ~/.local/share/mise/shims/node -v v20.0.0 ``` -### `rtx run [OPTIONS] [TASK] [ARGS]...` +### `mise run [OPTIONS] [TASK] [ARGS]...` **Aliases:** `r` @@ -898,8 +898,8 @@ Tasks may have dependencies on other tasks or on source files. If source is configured on a task, it will only run if the source files have changed. -Tasks can be defined in .rtx.toml or as standalone scripts. -In .rtx.toml, tasks take this form: +Tasks can be defined in .mise.toml or as standalone scripts. +In .mise.toml, tasks take this form: [tasks.build] run = "npm run build" @@ -907,14 +907,14 @@ In .rtx.toml, tasks take this form: outputs = ["dist/**/*.js"] Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.rtx/tasks` directory. +These must be located in the `.mise/tasks` directory. The name of the script will be the name of the task. - $ cat .rtx/tasks/build< 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var -i, --interleave Print directly to stdout/stderr instead of by line Defaults to true if --jobs == 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var -t, --tool Tool(s) to also add e.g.: node@20 python@3.10 @@ -955,37 +955,37 @@ Options: -j, --jobs Number of tasks to run in parallel [default: 4] - Configure with `jobs` config or `RTX_JOBS` env var + Configure with `jobs` config or `MISE_JOBS` env var - [env: RTX_JOBS=] + [env: MISE_JOBS=] -r, --raw Read/write directly to stdin/stdout/stderr instead of by line - Configure with `raw` config or `RTX_RAW` env var + Configure with `raw` config or `MISE_RAW` env var Examples: - $ rtx run lint - Runs the "lint" task. This needs to either be defined in .rtx.toml + $ mise run lint + Runs the "lint" task. This needs to either be defined in .mise.toml or as a standalone script. See the project README for more information. - $ rtx run build --force + $ mise run build --force Forces the "build" task to run even if its sources are up-to-date. - $ rtx run test --raw + $ mise run test --raw Runs "test" with stdin/stdout/stderr all connected to the current terminal. This forces `--jobs=1` to prevent interleaving of output. - $ rtx run lint ::: test ::: check + $ mise run lint ::: test ::: check Runs the "lint", "test", and "check" tasks in parallel. - $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 Execute multiple tasks each with their own arguments. ``` -### `rtx self-update [OPTIONS] [VERSION]` +### `mise self-update [OPTIONS] [VERSION]` ```text -Updates rtx itself +Updates mise itself Uses the GitHub Releases API to find the latest release and binary By default, this will also update any installed plugins @@ -1007,15 +1007,15 @@ Options: Skip confirmation prompt ``` -### `rtx settings get ` +### `mise settings get ` ```text Show a current setting -This is the contents of a single entry in ~/.config/rtx/config.toml +This is the contents of a single entry in ~/.config/mise/config.toml Note that aliases are also stored in this file -but managed separately with `rtx aliases get` +but managed separately with `mise aliases get` Usage: settings get @@ -1024,37 +1024,37 @@ Arguments: The setting to show Examples: - $ rtx settings get legacy_version_file + $ mise settings get legacy_version_file true ``` -### `rtx settings ls` +### `mise settings ls` **Aliases:** `list` ```text Show current settings -This is the contents of ~/.config/rtx/config.toml +This is the contents of ~/.config/mise/config.toml Note that aliases are also stored in this file -but managed separately with `rtx aliases` +but managed separately with `mise aliases` Usage: settings ls Examples: - $ rtx settings + $ mise settings legacy_version_file = false ``` -### `rtx settings set ` +### `mise settings set ` **Aliases:** `add, create` ```text Add/update a setting -This modifies the contents of ~/.config/rtx/config.toml +This modifies the contents of ~/.config/mise/config.toml Usage: settings set @@ -1066,17 +1066,17 @@ Arguments: The value to set Examples: - $ rtx settings set legacy_version_file true + $ mise settings set legacy_version_file true ``` -### `rtx settings unset ` +### `mise settings unset ` **Aliases:** `del, delete, remove, rm` ```text Clears a setting -This modifies the contents of ~/.config/rtx/config.toml +This modifies the contents of ~/.config/mise/config.toml Usage: settings unset @@ -1085,17 +1085,17 @@ Arguments: The setting to remove Examples: - $ rtx settings unset legacy_version_file + $ mise settings unset legacy_version_file ``` -### `rtx shell [OPTIONS] [TOOL@VERSION]...` +### `mise shell [OPTIONS] [TOOL@VERSION]...` **Aliases:** `sh` ```text Sets a tool version for the current shell session -Only works in a session where rtx is already activated. +Only works in a session where mise is already activated. Usage: shell [OPTIONS] [TOOL@VERSION]... @@ -1108,7 +1108,7 @@ Options: Number of jobs to run in parallel [default: 4] - [env: RTX_JOBS=] + [env: MISE_JOBS=] --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 @@ -1117,17 +1117,17 @@ Options: Removes a previously set version Examples: - $ rtx shell node@20 + $ mise shell node@20 $ node -v v20.0.0 ``` -### `rtx sync node <--brew|--nvm|--nodenv>` +### `mise sync node <--brew|--nvm|--nodenv>` ```text -Symlinks all tool versions from an external tool into rtx +Symlinks all tool versions from an external tool into mise -For example, use this to import all Homebrew node installs into rtx +For example, use this to import all Homebrew node installs into mise Usage: sync node <--brew|--nvm|--nodenv> @@ -1143,16 +1143,16 @@ Options: Examples: $ brew install node@18 node@20 - $ rtx sync node --brew - $ rtx use -g node@18 - uses Homebrew-provided node + $ mise sync node --brew + $ mise use -g node@18 - uses Homebrew-provided node ``` -### `rtx sync python --pyenv` +### `mise sync python --pyenv` ```text -Symlinks all tool versions from an external tool into rtx +Symlinks all tool versions from an external tool into mise -For example, use this to import all pyenv installs into rtx +For example, use this to import all pyenv installs into mise Usage: sync python --pyenv @@ -1162,11 +1162,11 @@ Options: Examples: $ pyenv install 3.11.0 - $ rtx sync python --pyenv - $ rtx use -g python@3.11.0 - uses pyenv-provided python + $ mise sync python --pyenv + $ mise use -g python@3.11.0 - uses pyenv-provided python ``` -### `rtx task edit [OPTIONS] ` +### `mise task edit [OPTIONS] ` ```text [experimental] Edit a task with $EDITOR @@ -1184,19 +1184,19 @@ Options: Display the path to the task instead of editing it Examples: - $ rtx task edit build - $ rtx task edit test + $ mise task edit build + $ mise task edit test ``` -### `rtx task ls [OPTIONS]` +### `mise task ls [OPTIONS]` ```text [experimental] List available tasks to execute -These may be included from the config file or from the project's .rtx/tasks directory -rtx will merge all tasks from all parent directories into this list. +These may be included from the config file or from the project's .mise/tasks directory +mise will merge all tasks from all parent directories into this list. -So if you have global tasks in ~/.config/rtx/tasks/* and project-specific tasks in -~/myproject/.rtx/tasks/*, then they'll both be available but the project-specific +So if you have global tasks in ~/.config/mise/tasks/* and project-specific tasks in +~/myproject/.mise/tasks/*, then they'll both be available but the project-specific tasks will override the global ones if they have the same name. Usage: task ls [OPTIONS] @@ -1209,10 +1209,10 @@ Options: Show hidden tasks Examples: - $ rtx task ls + $ mise task ls ``` -### `rtx task run [OPTIONS] [TASK] [ARGS]...` +### `mise task run [OPTIONS] [TASK] [ARGS]...` **Aliases:** `r` @@ -1224,8 +1224,8 @@ Tasks may have dependencies on other tasks or on source files. If source is configured on a task, it will only run if the source files have changed. -Tasks can be defined in .rtx.toml or as standalone scripts. -In .rtx.toml, tasks take this form: +Tasks can be defined in .mise.toml or as standalone scripts. +In .mise.toml, tasks take this form: [tasks.build] run = "npm run build" @@ -1233,14 +1233,14 @@ In .rtx.toml, tasks take this form: outputs = ["dist/**/*.js"] Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.rtx/tasks` directory. +These must be located in the `.mise/tasks` directory. The name of the script will be the name of the task. - $ cat .rtx/tasks/build< 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var -i, --interleave Print directly to stdout/stderr instead of by line Defaults to true if --jobs == 1 - Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var -t, --tool Tool(s) to also add e.g.: node@20 python@3.10 @@ -1281,39 +1281,39 @@ Options: -j, --jobs Number of tasks to run in parallel [default: 4] - Configure with `jobs` config or `RTX_JOBS` env var + Configure with `jobs` config or `MISE_JOBS` env var - [env: RTX_JOBS=] + [env: MISE_JOBS=] -r, --raw Read/write directly to stdin/stdout/stderr instead of by line - Configure with `raw` config or `RTX_RAW` env var + Configure with `raw` config or `MISE_RAW` env var Examples: - $ rtx run lint - Runs the "lint" task. This needs to either be defined in .rtx.toml + $ mise run lint + Runs the "lint" task. This needs to either be defined in .mise.toml or as a standalone script. See the project README for more information. - $ rtx run build --force + $ mise run build --force Forces the "build" task to run even if its sources are up-to-date. - $ rtx run test --raw + $ mise run test --raw Runs "test" with stdin/stdout/stderr all connected to the current terminal. This forces `--jobs=1` to prevent interleaving of output. - $ rtx run lint ::: test ::: check + $ mise run lint ::: test ::: check Runs the "lint", "test", and "check" tasks in parallel. - $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 Execute multiple tasks each with their own arguments. ``` -### `rtx trust [OPTIONS] [CONFIG_FILE]` +### `mise trust [OPTIONS] [CONFIG_FILE]` ```text Marks a config file as trusted -This means rtx will parse the file with potentially dangerous +This means mise will parse the file with potentially dangerous features enabled. This includes: @@ -1335,14 +1335,14 @@ Options: No longer trust this config Examples: - # trusts ~/some_dir/.rtx.toml - $ rtx trust ~/some_dir/.rtx.toml + # trusts ~/some_dir/.mise.toml + $ mise trust ~/some_dir/.mise.toml - # trusts .rtx.toml in the current or parent directory - $ rtx trust + # trusts .mise.toml in the current or parent directory + $ mise trust ``` -### `rtx uninstall [OPTIONS] [TOOL@VERSION]...` +### `mise uninstall [OPTIONS] [TOOL@VERSION]...` **Aliases:** `remove, rm` @@ -1363,12 +1363,12 @@ Options: Do not actually delete anything Examples: - $ rtx uninstall node@18.0.0 # will uninstall specific version - $ rtx uninstall node # will uninstall current node version - $ rtx uninstall --all node@18.0.0 # will uninstall all node versions + $ mise uninstall node@18.0.0 # will uninstall specific version + $ mise uninstall node # will uninstall current node version + $ mise uninstall --all node@18.0.0 # will uninstall all node versions ``` -### `rtx upgrade [OPTIONS] [TOOL@VERSION]...` +### `mise upgrade [OPTIONS] [TOOL@VERSION]...` **Aliases:** `up` @@ -1391,7 +1391,7 @@ Options: Number of jobs to run in parallel [default: 4] - [env: RTX_JOBS=] + [env: MISE_JOBS=] -i, --interactive Display multiselect menu to choose which tools to upgrade @@ -1400,7 +1400,7 @@ Options: Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 ``` -### `rtx use [OPTIONS] [TOOL@VERSION]...` +### `mise use [OPTIONS] [TOOL@VERSION]...` **Aliases:** `u` @@ -1408,9 +1408,9 @@ Options: Change the active version of a tool locally or globally. This will install the tool if it is not already installed. -By default, this will use an `.rtx.toml` file in the current directory. +By default, this will use an `.mise.toml` file in the current directory. Use the --global flag to use the global config file instead. -This replaces asdf's `local` and `global` commands, however those are still available in rtx. +This replaces asdf's `local` and `global` commands, however those are still available in mise. Usage: use [OPTIONS] [TOOL@VERSION]... @@ -1426,20 +1426,20 @@ Options: --fuzzy Save fuzzy version to config file - e.g.: `rtx use --fuzzy node@20` will save 20 as the version - this is the default behavior unless RTX_ASDF_COMPAT=1 + e.g.: `mise use --fuzzy node@20` will save 20 as the version + this is the default behavior unless MISE_ASDF_COMPAT=1 -g, --global - Use the global config file (~/.config/rtx/config.toml) instead of the local one + Use the global config file (~/.config/mise/config.toml) instead of the local one -e, --env - Modify an environment-specific config file like .rtx..toml + Modify an environment-specific config file like .mise..toml -j, --jobs Number of jobs to run in parallel [default: 4] - [env: RTX_JOBS=] + [env: MISE_JOBS=] --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 @@ -1448,39 +1448,39 @@ Options: Remove the tool(s) from config file -p, --path - Specify a path to a config file or directory If a directory is specified, it will look for .rtx.toml (default) or .tool-versions + Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions --pin Save exact version to config file - e.g.: `rtx use --pin node@20` will save 20.0.0 as the version + e.g.: `mise use --pin node@20` will save 20.0.0 as the version - [env: RTX_ASDF_COMPAT=] + [env: MISE_ASDF_COMPAT=] Examples: - # set the current version of node to 20.x in .rtx.toml of current directory + # set the current version of node to 20.x in .mise.toml of current directory # will write the fuzzy version (e.g.: 20) - $ rtx use node@20 + $ mise use node@20 - # set the current version of node to 20.x in ~/.config/rtx/config.toml + # set the current version of node to 20.x in ~/.config/mise/config.toml # will write the precise version (e.g.: 20.0.0) - $ rtx use -g --pin node@20 + $ mise use -g --pin node@20 - # sets .rtx.local.toml (which is intended not to be committed to a project) - $ rtx use --env local node@20 + # sets .mise.local.toml (which is intended not to be committed to a project) + $ mise use --env local node@20 - # sets .rtx.staging.toml (which is used if RTX_ENV=staging) - $ rtx use --env staging node@20 + # sets .mise.staging.toml (which is used if MISE_ENV=staging) + $ mise use --env staging node@20 ``` -### `rtx version` +### `mise version` ```text -Show rtx version +Show mise version Usage: version ``` -### `rtx watch [OPTIONS] [ARGS]...` +### `mise watch [OPTIONS] [ARGS]...` **Aliases:** `w` @@ -1504,19 +1504,19 @@ Options: Defaults to sources from the task(s) Examples: - $ rtx watch -t build + $ mise watch -t build Runs the "build" task. Will re-run the task when any of its sources change. Uses "sources" from the task definition to determine which files to watch. - $ rtx watch -t build --glob src/**/*.rs + $ mise watch -t build --glob src/**/*.rs Runs the "build" task but specify the files to watch with a glob pattern. This overrides the "sources" from the task definition. - $ rtx run -t build --clear + $ mise run -t build --clear Extra arguments are passed to watchexec. See `watchexec --help` for details. ``` -### `rtx where ` +### `mise where ` ```text Display the installation path for a runtime @@ -1536,16 +1536,16 @@ Arguments: Examples: # Show the latest installed version of node # If it is is not installed, errors - $ rtx where node@20 - /home/jdx/.local/share/rtx/installs/node/20.0.0 + $ mise where node@20 + /home/jdx/.local/share/mise/installs/node/20.0.0 # Show the current, active install directory of node # Errors if node is not referenced in any .tool-version file - $ rtx where node - /home/jdx/.local/share/rtx/installs/node/20.0.0 + $ mise where node + /home/jdx/.local/share/mise/installs/node/20.0.0 ``` -### `rtx which [OPTIONS] ` +### `mise which [OPTIONS] ` ```text Shows the path that a bin name points to @@ -1565,15 +1565,15 @@ Options: -t, --tool Use a specific tool@version - e.g.: `rtx which npm --tool=node@20` + e.g.: `mise which npm --tool=node@20` Examples: - $ rtx which node - /home/username/.local/share/rtx/installs/node/20.0.0/bin/node - $ rtx which node --plugin + $ mise which node + /home/username/.local/share/mise/installs/node/20.0.0/bin/node + $ mise which node --plugin node - $ rtx which node --version + $ mise which node --version 20.0.0 ``` - + diff --git a/docs/demo.sh b/docs/demo.sh index be85e9dc2..d28c21e9e 100755 --- a/docs/demo.sh +++ b/docs/demo.sh @@ -2,5 +2,5 @@ set -e cd -rm -rf ~/myproj/.* ~/.rtx/installs ~/.config/rtx -PATH="$HOME/.cargo/bin:$PATH" vhs <~/src/rtx/docs/demo.tape +rm -rf ~/myproj/.* ~/.mise/installs ~/.config/mise +PATH="$HOME/.cargo/bin:$PATH" vhs <~/src/mise/docs/demo.tape diff --git a/docs/demo.tape b/docs/demo.tape index 3a82d7e2d..40562c804 100644 --- a/docs/demo.tape +++ b/docs/demo.tape @@ -46,8 +46,8 @@ # Hide Hide the subsequent commands from the output # Show Show the subsequent commands in the output -Output src/rtx/docs/demo.gif -#Output src/rtx/docs/demo.webm +Output src/mise/docs/demo.gif +#Output src/mise/docs/demo.webm Require echo @@ -58,15 +58,15 @@ Set Width 1200 Set Height 600 Set Padding 10 -Type "http rtx.jdx.dev/rtx-latest-macos-arm64 > ~/bin/rtx" Enter Sleep 2s -Type "chmod +x ~/bin/rtx" Sleep 1s Enter Sleep 1s -Type "rtx -v" Sleep 1s Enter Sleep 1s -Type 'eval "$(rtx activate bash)"' Sleep 1s Enter Sleep 2s -Type "rtx use -g node@lts" Sleep 2s Enter Sleep 3s +Type "http mise.jdx.dev/mise-latest-macos-arm64 > ~/bin/mise" Enter Sleep 2s +Type "chmod +x ~/bin/mise" Sleep 1s Enter Sleep 1s +Type "mise -v" Sleep 1s Enter Sleep 1s +Type 'eval "$(mise activate bash)"' Sleep 1s Enter Sleep 2s +Type "mise use -g node@lts" Sleep 2s Enter Sleep 3s Type "node -v" Sleep 1s Enter Sleep 3s Type "which node" Sleep 1s Enter Sleep 5s Type "cd ~/myproj" Sleep 1s Enter Sleep 1s -Type "rtx use node@19" Sleep 2s Enter Sleep 2s +Type "mise use node@19" Sleep 2s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s Type "cd .." Sleep 1s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s diff --git a/docs/deno.md b/docs/deno.md index 66ff02b78..1ece4928b 100644 --- a/docs/deno.md +++ b/docs/deno.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/deno.html](https://rtx.jdx.dev/lang/deno.html). +Moved to [mise.jdx.dev/lang/deno.html](https://mise.jdx.dev/lang/deno.html). diff --git a/docs/go.md b/docs/go.md index a4addfcf3..d4e61f552 100644 --- a/docs/go.md +++ b/docs/go.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/go.html](https://rtx.jdx.dev/lang/go.html). +Moved to [mise.jdx.dev/lang/go.html](https://mise.jdx.dev/lang/go.html). diff --git a/docs/java.md b/docs/java.md index db5e03536..abd1974f1 100644 --- a/docs/java.md +++ b/docs/java.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/java.html](https://rtx.jdx.dev/lang/java.html). +Moved to [mise.jdx.dev/lang/java.html](https://mise.jdx.dev/lang/java.html). diff --git a/docs/node.md b/docs/node.md index 8ec788e9d..83ea937a4 100644 --- a/docs/node.md +++ b/docs/node.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/node.html](https://rtx.jdx.dev/lang/node.html). +Moved to [mise.jdx.dev/lang/node.html](https://mise.jdx.dev/lang/node.html). diff --git a/docs/python.md b/docs/python.md index ec7694f0f..c37f95080 100644 --- a/docs/python.md +++ b/docs/python.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/python.html](https://rtx.jdx.dev/lang/python.html) +Moved to [mise.jdx.dev/lang/python.html](https://mise.jdx.dev/lang/python.html) diff --git a/docs/ruby.md b/docs/ruby.md index 3a0fcbd66..f1be7cbba 100644 --- a/docs/ruby.md +++ b/docs/ruby.md @@ -1 +1 @@ -Moved to [rtx.jdx.dev/lang/ruby.html](https://rtx.jdx.dev/lang/ruby.html). +Moved to [mise.jdx.dev/lang/ruby.html](https://mise.jdx.dev/lang/ruby.html). diff --git a/e2e/.gitignore b/e2e/.gitignore index 8dd64b3e5..f6780a87a 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -1,4 +1,4 @@ -.e2e.rtx.toml +.e2e.mise.toml .local .cache .config diff --git a/e2e/.rtx/tasks/build b/e2e/.mise/tasks/build similarity index 100% rename from e2e/.rtx/tasks/build rename to e2e/.mise/tasks/build diff --git a/e2e/.mise/tasks/filetask b/e2e/.mise/tasks/filetask new file mode 100755 index 000000000..0e654687d --- /dev/null +++ b/e2e/.mise/tasks/filetask @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# mise description="This is a test build script" +# mise depends=["lint", "test"] +# mise sources=[".test-tool-versions"] +# mise outputs=["$MISE_PROJECT_ROOT/test-e2e/test-build-output.txt"] +# mise env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} + +set -euxo pipefail +cd "$MISE_PROJECT_ROOT" || exit 1 +echo "running test-build script" +mkdir -p test-e2e +echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test-e2e/test-build-output.txt +echo "ARGS: $*" >> test-e2e/test-build-output.txt diff --git a/e2e/.rtx/tasks/filetask b/e2e/.rtx/tasks/filetask deleted file mode 100755 index 3e7d92e19..000000000 --- a/e2e/.rtx/tasks/filetask +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# rtx description="This is a test build script" -# rtx depends=["lint", "test"] -# rtx sources=[".test-tool-versions"] -# rtx outputs=["$RTX_PROJECT_ROOT/test-e2e/test-build-output.txt"] -# rtx env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} - -set -euxo pipefail -cd "$RTX_PROJECT_ROOT" || exit 1 -echo "running test-build script" -mkdir -p test-e2e -echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test-e2e/test-build-output.txt -echo "ARGS: $*" >> test-e2e/test-build-output.txt diff --git a/e2e/cd/test_bash b/e2e/cd/test_bash index 9a04219ba..08061615c 100755 --- a/e2e/cd/test_bash +++ b/e2e/cd/test_bash @@ -2,11 +2,11 @@ # shellcheck disable=SC2088 set -euo pipefail -export RTX_EXPERIMENTAL=1 +export MISE_EXPERIMENTAL=1 orig_path="$PATH" # shellcheck disable=SC1090 -eval "$(rtx activate bash --status)" && _rtx_hook +eval "$(mise activate bash --status)" && _mise_hook assert() { local actual="$1" @@ -24,7 +24,7 @@ assert_path() { actual="${actual%:}" actual="${actual%:}" actual="${actual//$ROOT/ROOT}" - actual="${actual//$RTX_DATA_DIR\/installs/INSTALLS}" + actual="${actual//$MISE_DATA_DIR\/installs/INSTALLS}" if [[ "$actual" != "$expected" ]]; then echo "Invalid PATH: $actual" echo "Expected PATH: $expected" @@ -38,28 +38,28 @@ TINY="INSTALLS/tiny/latest/bin" SHELLCHECK="INSTALLS/shellcheck/0.9.0/bin" SHFMT="INSTALLS/shfmt/3.6.0/bin" -rtx ls -rtx i && _rtx_hook +mise ls +mise i && _mise_hook test "$(node -v)" = "v20.0.0" assert_path "/root:ROOT/e2e/cwd:$NODE_20:$TINY:$SHELLCHECK:$SHFMT" assert "$FOO" "cd" -cd 18 && rtx i && _rtx_hook +cd 18 && mise i && _mise_hook test "$(node -v)" = "v18.0.0" assert_path "/root:ROOT/e2e/cwd:$NODE_18:$TINY:$SHELLCHECK:$SHFMT" assert "$FOO" "18" -cd .. && _rtx_hook +cd .. && _mise_hook test "$(node -v)" = "v20.0.0" assert_path "/root:ROOT/e2e/cwd:$NODE_20:$TINY:$SHELLCHECK:$SHFMT" export PATH="PRE:$PATH" -cd 18 && _rtx_hook +cd 18 && _mise_hook test "$(node -v)" = "v18.0.0" assert_path "PRE:/root:ROOT/e2e/cwd:$NODE_18:$TINY:$SHELLCHECK:$SHFMT" -rtx shell node@18.0.0 && _rtx_hook +mise shell node@18.0.0 && _mise_hook test "$(node -v)" = "v18.0.0" -rtx deactivate +mise deactivate assert_path "PRE" diff --git a/e2e/cd/test_bash_legacy_activate b/e2e/cd/test_bash_legacy_activate index 53d175397..7575b0346 100755 --- a/e2e/cd/test_bash_legacy_activate +++ b/e2e/cd/test_bash_legacy_activate @@ -1,17 +1,17 @@ #!/usr/bin/env bash set -euo pipefail -rtx install node@20.0.0 node@18.0.0 +mise install node@20.0.0 node@18.0.0 # shellcheck disable=SC1090 -eval "$(rtx activate -s bash --status)" -_rtx_hook +eval "$(mise activate -s bash --status)" +_mise_hook -#rtx install +#mise install test "$(node -v)" = "v20.0.0" -cd 18 && _rtx_hook -#rtx install +cd 18 && _mise_hook +#mise install test "$(node -v)" = "v18.0.0" -cd .. && _rtx_hook +cd .. && _mise_hook test "$(node -v)" = "v20.0.0" diff --git a/e2e/cd/test_fish b/e2e/cd/test_fish index 32c2fb061..895eb2b80 100755 --- a/e2e/cd/test_fish +++ b/e2e/cd/test_fish @@ -5,21 +5,21 @@ set -gx PATH $ROOT/target/debug:$PATH set -l orig_node (node -v) #set -l fish_trace 1 -rtx install node@20.0.0 node@18.0.0; or exit +mise install node@20.0.0 node@18.0.0; or exit -rtx activate --status fish | source -__rtx_env_eval +mise activate --status fish | source +__mise_env_eval test (node -v) = "v20.0.0"; or exit -cd 18 && __rtx_env_eval +cd 18 && __mise_env_eval test (node -v) = "v18.0.0"; or exit -cd .. && __rtx_env_eval +cd .. && __mise_env_eval test (node -v) = "v20.0.0"; or exit -rtx shell node@18.0.0 && __rtx_env_eval +mise shell node@18.0.0 && __mise_env_eval test (node -v) = "v18.0.0"; or exit -rtx deactivate +mise deactivate test (node -v) = $orig_node; or exit diff --git a/e2e/cd/test_zsh b/e2e/cd/test_zsh index bc459a7b6..5c3221d0b 100755 --- a/e2e/cd/test_zsh +++ b/e2e/cd/test_zsh @@ -14,22 +14,22 @@ assert_path() { fi } -rtx install node@20.0.0 node@18.0.0 +mise install node@20.0.0 node@18.0.0 # shellcheck disable=SC1090 -eval "$(rtx activate zsh --status)" && _rtx_hook +eval "$(mise activate zsh --status)" && _mise_hook -#rtx install +#mise install test "$(node -v)" = "v20.0.0" -cd 18 && _rtx_hook -#rtx install +cd 18 && _mise_hook +#mise install test "$(node -v)" = "v18.0.0" -cd .. && _rtx_hook +cd .. && _mise_hook test "$(node -v)" = "v20.0.0" -rtx shell node@18.0.0 && _rtx_hook +mise shell node@18.0.0 && _mise_hook test "$(node -v)" = "v18.0.0" -rtx deactivate +mise deactivate assert_path "" diff --git a/e2e/config/.e2e.rtx.toml b/e2e/config/.e2e.mise.toml similarity index 91% rename from e2e/config/.e2e.rtx.toml rename to e2e/config/.e2e.mise.toml index 630efb393..46ecdf59e 100644 --- a/e2e/config/.e2e.rtx.toml +++ b/e2e/config/.e2e.mise.toml @@ -1,4 +1,4 @@ -#:schema ../../schema/rtx.json +#:schema ../../schema/mise.json env_file = '.test-env' env_path = ["/root", "./cwd"] [env] diff --git a/e2e/cd/.e2e.rtx.toml b/e2e/config/cd/.e2e.mise.toml similarity index 100% rename from e2e/cd/.e2e.rtx.toml rename to e2e/config/cd/.e2e.mise.toml diff --git a/e2e/config/cd/.e2e.rtx.toml b/e2e/config/cd/.e2e.rtx.toml deleted file mode 100644 index 99f0244b5..000000000 --- a/e2e/config/cd/.e2e.rtx.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -FOO = "cd" diff --git a/e2e/cd/18/.e2e.rtx.toml b/e2e/config/cd/18/.e2e.mise.toml similarity index 100% rename from e2e/cd/18/.e2e.rtx.toml rename to e2e/config/cd/18/.e2e.mise.toml diff --git a/e2e/config/cd/18/.e2e.rtx.toml b/e2e/config/cd/18/.e2e.rtx.toml deleted file mode 100644 index 6e8bd90d3..000000000 --- a/e2e/config/cd/18/.e2e.rtx.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -FOO = "18" diff --git a/e2e/config/pyproject.toml b/e2e/config/pyproject.toml index dd47e64ae..f8195841a 100644 --- a/e2e/config/pyproject.toml +++ b/e2e/config/pyproject.toml @@ -2,7 +2,7 @@ name = "poetry-test" version = "0.1.0" description = "" -authors = ["rtx"] +authors = ["mise"] packages = [{include = "poetry_demo"}] [tool.poetry.dependencies] diff --git a/e2e/direnv/no_tool_versions/test_direnv b/e2e/direnv/no_tool_versions/test_direnv index 07ff633ea..03b308cd4 100755 --- a/e2e/direnv/no_tool_versions/test_direnv +++ b/e2e/direnv/no_tool_versions/test_direnv @@ -1,11 +1,11 @@ #!/usr/bin/env zsh set -e -export RTX_EXPERIMENTAL=1 +export MISE_EXPERIMENTAL=1 eval "$(direnv hook zsh)" -eval "$(rtx activate zsh --status)" -_rtx_hook && direnv allow && _direnv_hook +eval "$(mise activate zsh --status)" +_mise_hook && direnv allow && _direnv_hook assert_go_version() { local expected="$1" @@ -15,12 +15,12 @@ assert_go_version() { fi } -rtx i golang@1.18.10 golang@1.19.5 && _rtx_hook -#assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" -cd rtx-direnv-break-path-source && _rtx_hook +mise i golang@1.18.10 golang@1.19.5 && _mise_hook +#assert_gopath "$MISE_DATA_DIR/installs/golang/1.19.5/packages" +cd mise-direnv-break-path-source && _mise_hook direnv allow && _direnv_hook -#assert_gopath "$RTX_DATA_DIR/installs/golang/1.18.10/packages" -cd ../rtx-direnv-break-path-target && _rtx_hook +#assert_gopath "$MISE_DATA_DIR/installs/golang/1.18.10/packages" +cd ../mise-direnv-break-path-target && _mise_hook direnv allow && _direnv_hook -#assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" -rtx -v # should not fail, the bug is that PATH gets set to a junk value and this does not work +#assert_gopath "$MISE_DATA_DIR/installs/golang/1.19.5/packages" +mise -v # should not fail, the bug is that PATH gets set to a junk value and this does not work diff --git a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions b/e2e/direnv/system_version/mise-direnv-system-version-reset/load-first/.e2e-tool-versions similarity index 100% rename from e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.e2e-tool-versions rename to e2e/direnv/system_version/mise-direnv-system-version-reset/load-first/.e2e-tool-versions diff --git a/e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.envrc b/e2e/direnv/system_version/mise-direnv-system-version-reset/load-first/.envrc similarity index 100% rename from e2e/direnv/system_version/rtx-direnv-system-version-reset/load-first/.envrc rename to e2e/direnv/system_version/mise-direnv-system-version-reset/load-first/.envrc diff --git a/e2e/direnv/system_version/test_direnv_system_version b/e2e/direnv/system_version/test_direnv_system_version index 7f4081704..e9b0dc55c 100755 --- a/e2e/direnv/system_version/test_direnv_system_version +++ b/e2e/direnv/system_version/test_direnv_system_version @@ -1,55 +1,55 @@ #!/usr/bin/env zsh set -e -export RTX_EXPERIMENTAL=1 +export MISE_EXPERIMENTAL=1 eval "$(direnv hook zsh)" -eval "$(rtx activate zsh --status)" -_rtx_hook && _direnv_hook +eval "$(mise activate zsh --status)" +_mise_hook && _direnv_hook # prepare # use old node version on purpose to not conflict with unknown system node version custom_node_version="18.0.0" -rtx_node_path_segment="${RTX_DATA_DIR}/installs/node" +mise_node_path_segment="${MISE_DATA_DIR}/installs/node" -# with node@system rtx should not add a node path segment -if [[ $PATH == *"${rtx_node_path_segment}"* ]]; then - echo "Rtx node path segment: ${rtx_node_path_segment} must not be in PATH: ${PATH}" +# with node@system mise should not add a node path segment +if [[ $PATH == *"${mise_node_path_segment}"* ]]; then + echo "Mise node path segment: ${mise_node_path_segment} must not be in PATH: ${PATH}" exit 1 fi system_node_version=$(node -v) # the test is only working, if system node version is not equal to custom node version if [[ $system_node_version == "v${custom_node_version}" ]]; then - echo "Equal system node version: ${system_node_version} and rtx custom version: v${custom_node_version}" + echo "Equal system node version: ${system_node_version} and mise custom version: v${custom_node_version}" exit 1 fi # allow direnv to execute .envrc file -direnv allow rtx-direnv-system-version-reset/load-first +direnv allow mise-direnv-system-version-reset/load-first # test # install custom node version -rtx i node@$custom_node_version && _rtx_hook +mise i node@$custom_node_version && _mise_hook -cd rtx-direnv-system-version-reset/load-first && _rtx_hook && _direnv_hook +cd mise-direnv-system-version-reset/load-first && _mise_hook && _direnv_hook node_version=$(node -v) if [[ $node_version != "v${custom_node_version}" ]]; then echo "Invalid node version: ${node_version} Expected: v${custom_node_version}" exit 1 fi -if [[ ! $PATH == *"${rtx_node_path_segment}/${custom_node_version}"* ]]; then - echo "Rtx node path segment: ${rtx_node_path_segment}/${custom_node_version} must be in PATH: ${PATH}" +if [[ ! $PATH == *"${mise_node_path_segment}/${custom_node_version}"* ]]; then + echo "Mise node path segment: ${mise_node_path_segment}/${custom_node_version} must be in PATH: ${PATH}" exit 1 fi -cd .. && _rtx_hook && _direnv_hook +cd .. && _mise_hook && _direnv_hook -# with node@system rtx should not add a node path segment -if [[ $PATH == *"${rtx_node_path_segment}"* ]]; then - echo "Rtx node path segment: ${rtx_node_path_segment} must not be in PATH: ${PATH}" +# with node@system mise should not add a node path segment +if [[ $PATH == *"${mise_node_path_segment}"* ]]; then + echo "Mise node path segment: ${mise_node_path_segment} must not be in PATH: ${PATH}" exit 1 fi diff --git a/e2e/gopath/test_gopath b/e2e/gopath/test_gopath index 2a9a6d440..2636ce527 100755 --- a/e2e/gopath/test_gopath +++ b/e2e/gopath/test_gopath @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -e -export RTX_EXPERIMENTAL=1 +export MISE_EXPERIMENTAL=1 -eval "$(rtx activate bash)" -_rtx_hook +eval "$(mise activate bash)" +_mise_hook assert_gopath() { local expected="$1" @@ -14,9 +14,9 @@ assert_gopath() { fi } -rtx i golang@1.18.10 golang@1.19.5 && _rtx_hook -assert_gopath "$RTX_DATA_DIR/installs/go/1.19.5/packages" -cd 18 && _rtx_hook -assert_gopath "$RTX_DATA_DIR/installs/go/1.18.10/packages" -cd .. && _rtx_hook -assert_gopath "$RTX_DATA_DIR/installs/go/1.19.5/packages" +mise i golang@1.18.10 golang@1.19.5 && _mise_hook +assert_gopath "$MISE_DATA_DIR/installs/go/1.19.5/packages" +cd 18 && _mise_hook +assert_gopath "$MISE_DATA_DIR/installs/go/1.18.10/packages" +cd .. && _mise_hook +assert_gopath "$MISE_DATA_DIR/installs/go/1.19.5/packages" diff --git a/e2e/ruby/test_ruby b/e2e/ruby/test_ruby index bfa1b481c..95e081693 100755 --- a/e2e/ruby/test_ruby +++ b/e2e/ruby/test_ruby @@ -4,9 +4,9 @@ set -e # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/../assert.sh" -export RTX_EXPERIMENTAL=1 -export RTX_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" -export RTX_RUBY_VERBOSE_INSTALL=1 +export MISE_EXPERIMENTAL=1 +export MISE_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" +export MISE_RUBY_VERBOSE_INSTALL=1 if [ "${TEST_ALL:-}" != 1 ]; then exit @@ -21,7 +21,7 @@ source "https://rubygems.org" git_source(:github) { |repo| "https://github.com/#{repo}.git" } EOF -rtx i ruby -v -assert_contains "rtx x -- ruby --version" "ruby 3.2.2" +mise i ruby -v +assert_contains "mise x -- ruby --version" "ruby 3.2.2" rm Gemfile diff --git a/e2e/ruby/test_ruby_install b/e2e/ruby/test_ruby_install index 53715cfac..3a7914052 100755 --- a/e2e/ruby/test_ruby_install +++ b/e2e/ruby/test_ruby_install @@ -4,14 +4,14 @@ set -e # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/../assert.sh" -export RTX_EXPERIMENTAL=1 -export RTX_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" -export RTX_RUBY_INSTALL=1 +export MISE_EXPERIMENTAL=1 +export MISE_RUBY_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-gems" +export MISE_RUBY_INSTALL=1 echo "ruby-3.2.1" > .ruby-version # disable this slow test for now -#rtx i ruby -#assert_contains "rtx x -- ruby --version" "ruby 3.2.1" +#mise i ruby +#assert_contains "mise x -- ruby --version" "ruby 3.2.1" rm .ruby-version diff --git a/e2e/run_all_tests b/e2e/run_all_tests index 9bcd26c90..3c9c7b0a9 100755 --- a/e2e/run_all_tests +++ b/e2e/run_all_tests @@ -3,7 +3,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -FILES=$(find e2e -name 'test_*' -type f -not -path "*/.rtx/*" | sort) +FILES=$(find e2e -name 'test_*' -type f -not -path "*/.mise/*" | sort) test_count=0 if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then { diff --git a/e2e/run_test b/e2e/run_test index a645bbb6d..d4cbaae9c 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -8,17 +8,17 @@ TEST="$1" setup_env() { export ROOT export PATH="$ROOT/target/debug:$PATH" - export RTX_USE_TOML="0" - export RTX_DATA_DIR="$HOME/.rtx/e2e" - export RTX_STATE_DIR="$HOME/.rtx/e2e" - export RTX_CACHE_DIR="$HOME/.rtx/e2e/cache" - export RTX_CONFIG_DIR="$HOME/.rtx/e2e/config" - export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions - export RTX_DEFAULT_CONFIG_FILENAME=.e2e.rtx.toml - export RTX_CONFIG_FILE="$ROOT/e2e/.config/rtx/config.toml" - export RTX_ALWAYS_KEEP_DOWNLOAD="1" - export RTX_TRUSTED_CONFIG_PATHS="$ROOT/e2e" - export RTX_YES="1" + export MISE_USE_TOML="0" + export MISE_DATA_DIR="$HOME/.mise/e2e" + export MISE_STATE_DIR="$HOME/.mise/e2e" + export MISE_CACHE_DIR="$HOME/.mise/e2e/cache" + export MISE_CONFIG_DIR="$HOME/.mise/e2e/config" + export MISE_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions + export MISE_DEFAULT_CONFIG_FILENAME=.e2e.mise.toml + export MISE_CONFIG_FILE="$ROOT/e2e/.config/mise/config.toml" + export MISE_ALWAYS_KEEP_DOWNLOAD="1" + export MISE_TRUSTED_CONFIG_PATHS="$ROOT/e2e" + export MISE_YES="1" export NPM_CONFIG_FUND="false" unset GOPATH } @@ -33,7 +33,7 @@ setup_config_files() { run_test() { echo "::group::E2E $TEST" - rm -f "$RTX_CONFIG_FILE" + rm -f "$MISE_CONFIG_FILE" cd "$(dirname "$TEST")" START=$(date +%s) diff --git a/e2e/test_bang b/e2e/test_bang index 2341f3816..8a5455b72 100755 --- a/e2e/test_bang +++ b/e2e/test_bang @@ -10,12 +10,12 @@ assert() { fi } -rtx uninstall --all tiny -rtx i tiny -rtx local tiny@sub-1:latest -assert "rtx current tiny" "2.1.0" -rtx local tiny@sub-1:lts -assert "rtx current tiny" "2.1.0" -rtx local tiny@sub-0.1:3.1 -assert "rtx current tiny" "3.0.1" -rtx local tiny@latest +mise uninstall --all tiny +mise i tiny +mise local tiny@sub-1:latest +assert "mise current tiny" "2.1.0" +mise local tiny@sub-1:lts +assert "mise current tiny" "2.1.0" +mise local tiny@sub-0.1:3.1 +assert "mise current tiny" "3.0.1" +mise local tiny@latest diff --git a/e2e/test_bun b/e2e/test_bun index a4241e98b..6333e2ba8 100755 --- a/e2e/test_bun +++ b/e2e/test_bun @@ -3,11 +3,11 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -export RTX_EXPERIMENTAL=1 +export MISE_EXPERIMENTAL=1 cat <.bun-version 1.0.17 EOF -rtx i bun -assert_contains "rtx x bun -- bun -v" "1.0.17" +mise i bun +assert_contains "mise x bun -- bun -v" "1.0.17" rm .bun-version diff --git a/e2e/test_deno b/e2e/test_deno index 653c9bd88..f4f6c0c7e 100755 --- a/e2e/test_deno +++ b/e2e/test_deno @@ -3,11 +3,11 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -export RTX_EXPERIMENTAL=1 +export MISE_EXPERIMENTAL=1 cat <.deno-version 1.35.3 EOF -rtx i deno -assert_contains "rtx x deno -- deno -V" "deno 1.35.3" +mise i deno +assert_contains "mise x deno -- deno -V" "deno 1.35.3" rm .deno-version diff --git a/e2e/test_doctor b/e2e/test_doctor index 165dd3bea..35561d77e 100755 --- a/e2e/test_doctor +++ b/e2e/test_doctor @@ -11,6 +11,6 @@ assert() { fi } -rtx plugins install poetry && rtx i -eval "$(rtx activate bash)" && _rtx_hook -rtx doctor +mise plugins install poetry && mise i +eval "$(mise activate bash)" && _mise_hook +mise doctor diff --git a/e2e/test_env b/e2e/test_env index 4d9dd3629..07b66ca7f 100755 --- a/e2e/test_env +++ b/e2e/test_env @@ -3,11 +3,11 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -rtx i node -eval "$(rtx env -s bash)" +mise i node +eval "$(mise env -s bash)" assert "node -v" "v20.0.0" -rtx i node@18.0.0 -eval "$(rtx env -s bash node@18.0.0)" +mise i node@18.0.0 +eval "$(mise env -s bash node@18.0.0)" assert "node -v" "v18.0.0" -assert "rtx x -- env | grep FOO_FROM_FILE" "FOO_FROM_FILE=foo_from_file" -RTX_ENV_FILE=.test-env2 assert "rtx x -- env | grep TEST_ENV2" "TEST_ENV2=foo" +assert "mise x -- env | grep FOO_FROM_FILE" "FOO_FROM_FILE=foo_from_file" +MISE_ENV_FILE=.test-env2 assert "mise x -- env | grep TEST_ENV2" "TEST_ENV2=foo" diff --git a/e2e/test_erlang b/e2e/test_erlang index d7276a213..7d48e4aa4 100755 --- a/e2e/test_erlang +++ b/e2e/test_erlang @@ -7,6 +7,6 @@ if [ "${TEST_ALL:-}" != 1 ]; then exit fi -export RTX_EXPERIMENTAL=1 +export MISE_EXPERIMENTAL=1 -assert_contains "rtx x erlang@24.3.4.9 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell" "24" +assert_contains "mise x erlang@24.3.4.9 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell" "24" diff --git a/e2e/test_exec b/e2e/test_exec index 5f30b243b..9393c0cd4 100755 --- a/e2e/test_exec +++ b/e2e/test_exec @@ -10,6 +10,6 @@ assert() { fi } -assert "rtx x -C $PWD/direnv -- pwd" "$(pwd)/direnv" -assert "rtx x -C ./direnv -- pwd" "$(pwd)/direnv" -assert "rtx x -C direnv -- pwd" "$(pwd)/direnv" +assert "mise x -C $PWD/direnv -- pwd" "$(pwd)/direnv" +assert "mise x -C ./direnv -- pwd" "$(pwd)/direnv" +assert "mise x -C direnv -- pwd" "$(pwd)/direnv" diff --git a/e2e/test_go b/e2e/test_go index 14d0b9cf1..8142df26d 100755 --- a/e2e/test_go +++ b/e2e/test_go @@ -3,15 +3,15 @@ set -e # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -export RTX_EXPERIMENTAL=1 -export RTX_GO_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-go-packages" +export MISE_EXPERIMENTAL=1 +export MISE_GO_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-go-packages" -cat >"$RTX_GO_DEFAULT_PACKAGES_FILE" <"$MISE_GO_DEFAULT_PACKAGES_FILE" <.sdkmanrc java=17.0.2 EOF -rtx i java -assert_contains "rtx x java -- java -version 2>&1" "openjdk version \"17.0.2\"" +mise i java +assert_contains "mise x java -- java -version 2>&1" "openjdk version \"17.0.2\"" rm .sdkmanrc cat <.java-version 17.0.2 EOF -assert_contains "rtx x java -- java -version 2>&1" "openjdk version \"17.0.2\"" +assert_contains "mise x java -- java -version 2>&1" "openjdk version \"17.0.2\"" rm .java-version diff --git a/e2e/test_link b/e2e/test_link index 6217c609c..ee39a2a4a 100755 --- a/e2e/test_link +++ b/e2e/test_link @@ -4,8 +4,8 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -rtx plugins uninstall tiny -rtx p ln "$ROOT/test/data/plugins/tiny" -assert_contains "rtx p" "tiny" -assert_fail "rtx p link $ROOT/test/data/plugins/tiny" -rtx plugins link -f "$ROOT/test/data/plugins/tiny" +mise plugins uninstall tiny +mise p ln "$ROOT/test/data/plugins/tiny" +assert_contains "mise p" "tiny" +assert_fail "mise p link $ROOT/test/data/plugins/tiny" +mise plugins link -f "$ROOT/test/data/plugins/tiny" diff --git a/e2e/test_local b/e2e/test_local index df97dc935..cef6a0d64 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -16,9 +16,9 @@ assert_raises() { fi } -rtx i shfmt@3.6.0 shfmt@3.5.0 +mise i shfmt@3.6.0 shfmt@3.5.0 -assert "rtx local" "#:schema ../../schema/rtx.json +assert "mise local" "#:schema ../../schema/mise.json env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] @@ -39,8 +39,8 @@ run = 'echo \"linting!\"' run = 'echo \"testing!\"' " -rtx local shfmt@3.5.0 -assert "rtx local" "#:schema ../../schema/rtx.json +mise local shfmt@3.5.0 +assert "mise local" "#:schema ../../schema/mise.json env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] @@ -62,13 +62,13 @@ run = 'echo \"linting!\"' run = 'echo \"testing!\"' " -rtx exec -- shfmt --version >&2 -if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then +mise exec -- shfmt --version >&2 +if [[ "$(mise exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi -rtx local shfmt@3.6.0 -assert "rtx local" "#:schema ../../schema/rtx.json +mise local shfmt@3.6.0 +assert "mise local" "#:schema ../../schema/mise.json env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] @@ -90,13 +90,13 @@ run = 'echo \"linting!\"' run = 'echo \"testing!\"' " -rtx exec -- shfmt --version >&2 -if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then +mise exec -- shfmt --version >&2 +if [[ "$(mise exec -- shfmt --version)" != "v3.6.0" ]]; then exit 1 fi -rtx local --rm shfmt -assert "rtx local" "#:schema ../../schema/rtx.json +mise local --rm shfmt +assert "mise local" "#:schema ../../schema/mise.json env_file = '.test-env' env_path = [\"/root\", \"./cwd\"] [env] @@ -117,35 +117,35 @@ run = 'echo \"linting!\"' run = 'echo \"testing!\"' " -export RTX_DEFAULT_CONFIG_FILENAME=.MISSING +export MISE_DEFAULT_CONFIG_FILENAME=.MISSING -rtx local -assert "rtx local" "#python 3.11.1 3.10.9 # foo +mise local +assert "mise local" "#python 3.11.1 3.10.9 # foo shellcheck sub-0.1:0.10.0 shfmt 3.6.0 # test comment #node 20.0.0 " -rtx local shfmt@3.5.0 -assert "rtx local" "#python 3.11.1 3.10.9 # foo +mise local shfmt@3.5.0 +assert "mise local" "#python 3.11.1 3.10.9 # foo shellcheck sub-0.1:0.10.0 shfmt 3.5.0 # test comment #node 20.0.0 " -rtx exec -- shfmt --version >&2 -if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then +mise exec -- shfmt --version >&2 +if [[ "$(mise exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi -rtx local shfmt@3.6.0 -assert "rtx local" "#python 3.11.1 3.10.9 # foo +mise local shfmt@3.6.0 +assert "mise local" "#python 3.11.1 3.10.9 # foo shellcheck sub-0.1:0.10.0 shfmt 3.6.0 # test comment #node 20.0.0 " -rtx exec -- shfmt --version >&2 -if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then +mise exec -- shfmt --version >&2 +if [[ "$(mise exec -- shfmt --version)" != "v3.6.0" ]]; then exit 1 fi diff --git a/e2e/test_log_level b/e2e/test_log_level index ad5fec022..6933df28f 100755 --- a/e2e/test_log_level +++ b/e2e/test_log_level @@ -10,7 +10,7 @@ assert() { fi } -assert "rtx x node@20.0.0 --log-level debug -- node -v" "v20.0.0" -assert "rtx x node@20.0.0 --log-level=debug -- node -v" "v20.0.0" -assert "rtx x node@20.0.0 --debug -- node -v" "v20.0.0" -assert "rtx x node@20.0.0 --trace -- node -v" "v20.0.0" +assert "mise x node@20.0.0 --log-level debug -- node -v" "v20.0.0" +assert "mise x node@20.0.0 --log-level=debug -- node -v" "v20.0.0" +assert "mise x node@20.0.0 --debug -- node -v" "v20.0.0" +assert "mise x node@20.0.0 --trace -- node -v" "v20.0.0" diff --git a/e2e/test_ls_remote b/e2e/test_ls_remote index 0c87e3037..de15ca31d 100755 --- a/e2e/test_ls_remote +++ b/e2e/test_ls_remote @@ -3,6 +3,6 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -rtx p list-remote | grep elixir -rtx p uninstall tiny -assert_contains "rtx ls-remote tiny" "1.1.0" +mise p list-remote | grep elixir +mise p uninstall tiny +assert_contains "mise ls-remote tiny" "1.1.0" diff --git a/e2e/test_neovim b/e2e/test_neovim index e7e0d3446..cca1b911f 100755 --- a/e2e/test_neovim +++ b/e2e/test_neovim @@ -5,5 +5,5 @@ source "$(dirname "$0")/assert.sh" # TODO: fix this in github actions CI exit 0 -rtx i neovim@ref:master -assert_contains "rtx x neovim@ref:master -- nvim --version" "NVIM v0." +mise i neovim@ref:master +assert_contains "mise x neovim@ref:master -- nvim --version" "NVIM v0." diff --git a/e2e/test_nodejs b/e2e/test_nodejs index da74d15b2..655b9d736 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -3,31 +3,31 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -export RTX_EXPERIMENTAL=1 -export RTX_NODE_COREPACK=1 -export RTX_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-npm-packages" +export MISE_EXPERIMENTAL=1 +export MISE_NODE_COREPACK=1 +export MISE_NODE_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-npm-packages" -rtx plugin uninstall node -rtx i node@lts/hydrogen -rtx i -f node -assert_contains "rtx x node@lts/hydrogen -- node --version" "v18." -assert "rtx x -- node --version" "v20.0.0" -assert_contains "rtx x -- which yarn" "yarn" +mise plugin uninstall node +mise i node@lts/hydrogen +mise i -f node +assert_contains "mise x node@lts/hydrogen -- node --version" "v18." +assert "mise x -- node --version" "v20.0.0" +assert_contains "mise x -- which yarn" "yarn" # test asdf-nodejs -rtx plugin i nodejs https://github.com/asdf-vm/asdf-nodejs.git -rtx use nodejs@20.1.0 -rtx ls -assert "rtx x -- node --version" "v20.1.0" -assert_contains "rtx ls-remote nodejs" "20.1.0" -assert_contains "rtx node nodebuild --version" "node-build " -rtx use --rm node +mise plugin i nodejs https://github.com/asdf-vm/asdf-nodejs.git +mise use nodejs@20.1.0 +mise ls +assert "mise x -- node --version" "v20.1.0" +assert_contains "mise ls-remote nodejs" "20.1.0" +assert_contains "mise node nodebuild --version" "node-build " +mise use --rm node -# RTX_LEGACY_VERSION_FILE env var -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 -assert_not_contains "rtx plugins --user" "node" +# MISE_LEGACY_VERSION_FILE env var +MISE_LEGACY_VERSION_FILE=1 assert_contains "mise current node" "20.0.0" +MISE_LEGACY_VERSION_FILE=0 assert_not_contains "mise current node" "20.0.0" +mise plugin uninstall nodejs +assert_not_contains "mise plugins --user" "node" # disable nodejs plugin -RTX_DISABLE_TOOLS=node assert_not_contains "rtx plugins --core" "node" +MISE_DISABLE_TOOLS=node assert_not_contains "mise plugins --core" "node" diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install index c18662080..0c53e04f9 100755 --- a/e2e/test_plugins_install +++ b/e2e/test_plugins_install @@ -21,30 +21,30 @@ assert_contains() { } # install/uninstall multiple -rtx plugin uninstall tiny shfmt shellcheck -rtx plugin install tiny shfmt shellcheck -assert_contains "rtx plugin ls" "tiny" -assert_contains "rtx plugin ls" "shfmt" -assert_contains "rtx plugin ls" "shellcheck" +mise plugin uninstall tiny shfmt shellcheck +mise plugin install tiny shfmt shellcheck +assert_contains "mise plugin ls" "tiny" +assert_contains "mise plugin ls" "shfmt" +assert_contains "mise plugin ls" "shellcheck" -rm -rf "$RTX_DATA_DIR/plugins/tiny" -rtx plugin install https://github.com/rtx-plugins/rtx-tiny.git -assert_contains "rtx plugin ls" "tiny" -rtx plugin install -f tiny -assert_contains "rtx plugin ls" "tiny" +rm -rf "$MISE_DATA_DIR/plugins/tiny" +mise plugin install https://github.com/rtx-plugins/rtx-tiny.git +assert_contains "mise plugin ls" "tiny" +mise plugin install -f tiny +assert_contains "mise plugin ls" "tiny" -rm -rf "$RTX_DATA_DIR/plugins/tiny" -rtx plugin install tiny https://github.com/rtx-plugins/rtx-tiny -assert_contains "rtx plugin ls" "tiny" +rm -rf "$MISE_DATA_DIR/plugins/tiny" +mise plugin install tiny https://github.com/rtx-plugins/rtx-tiny +assert_contains "mise plugin ls" "tiny" -rm -rf "$RTX_DATA_DIR/plugins/shellcheck" -rtx plugin install --all -assert_contains "rtx plugin ls" "shellcheck" +rm -rf "$MISE_DATA_DIR/plugins/shellcheck" +mise plugin install --all +assert_contains "mise plugin ls" "shellcheck" -rtx plugin uninstall tiny -assert_not_contains "rtx plugin ls" "tiny" -rtx plugin uninstall tiny +mise plugin uninstall tiny +assert_not_contains "mise plugin ls" "tiny" +mise plugin uninstall tiny -rtx plugin update -rtx plugin update shfmt -rtx i +mise plugin update +mise plugin update shfmt +mise i diff --git a/e2e/test_poetry b/e2e/test_poetry index 9a013b093..f57ab7535 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -7,23 +7,23 @@ if [ "${TEST_ALL:-}" != 1 ]; then exit fi -rm -rf "$RTX_DATA_DIR/cache/poetry" +rm -rf "$MISE_DATA_DIR/cache/poetry" export POETRY_HOME=".poetry" -eval "$(rtx activate bash)" -cat >.e2e.rtx.toml <.e2e.mise.toml </dev/null +MISE_TINY_LIST_ALL_FAIL=1 MISE_TINY_VERSION=latest mise env >/dev/null # check bin/list-legacy-files -assert "rtx current tiny" "3.1.0" -rtx local --remove tiny +assert "mise current tiny" "3.1.0" +mise local --remove tiny echo "2.0" >.tiny-version -assert "rtx current tiny" "2.0.1" +assert "mise current tiny" "2.0.1" rm .tiny-version -rtx local tiny@latest -assert "rtx current tiny" "3.1.0" +mise local tiny@latest +assert "mise current tiny" "3.1.0" # test outdated/upgrade -rtx settings set experimental true -rm -rf "$RTX_DATA_DIR/installs/tiny" -rtx use tiny@3 -mv "$RTX_DATA_DIR/installs/tiny/"{3.1.0,3.0.0} -assert "rtx current tiny" "3.0.0" -assert "rtx outdated tiny" "Tool Requested Current Latest +mise settings set experimental true +rm -rf "$MISE_DATA_DIR/installs/tiny" +mise use tiny@3 +mv "$MISE_DATA_DIR/installs/tiny/"{3.1.0,3.0.0} +assert "mise current tiny" "3.0.0" +assert "mise outdated tiny" "Tool Requested Current Latest tiny 3 3.0.0 3.1.0" -rtx upgrade tiny -assert "rtx current tiny" "3.1.0" -assert "rtx outdated tiny" "" +mise upgrade tiny +assert "mise current tiny" "3.1.0" +assert "mise outdated tiny" "" diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index 8e9d0e796..d24b9e1ba 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -1,14 +1,14 @@ #!/usr/bin/env bash set -euo pipefail -export RTX_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions -export RTX_DEFAULT_CONFIG_FILENAME=.MISSING +export MISE_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions +export MISE_DEFAULT_CONFIG_FILENAME=.MISSING git checkout .alternate-tool-versions -rtx i shfmt -rtx exec -- shfmt --version >&2 -if [[ "$(rtx exec -- shfmt --version)" != "v3.5.0" ]]; then +mise i shfmt +mise exec -- shfmt --version >&2 +if [[ "$(mise exec -- shfmt --version)" != "v3.5.0" ]]; then exit 1 fi @@ -22,15 +22,15 @@ assert() { fi } -assert "rtx local" "shfmt 3.5.0" +assert "mise local" "shfmt 3.5.0" -rtx local -p shfmt@3.6.0 -assert "rtx local -p" "shfmt 3.6.0" +mise local -p shfmt@3.6.0 +assert "mise local -p" "shfmt 3.6.0" -rtx exec -- shfmt --version >&2 -if [[ "$(rtx exec -- shfmt --version)" != "v3.6.0" ]]; then +mise exec -- shfmt --version >&2 +if [[ "$(mise exec -- shfmt --version)" != "v3.6.0" ]]; then exit 1 fi -rtx local -p shfmt@3.5.0 -assert "rtx local shfmt" "3.5.0" +mise local -p shfmt@3.5.0 +assert "mise local shfmt" "3.5.0" diff --git a/e2e/test_top_runtimes b/e2e/test_top_runtimes index 02170a418..0257111ab 100755 --- a/e2e/test_top_runtimes +++ b/e2e/test_top_runtimes @@ -57,23 +57,23 @@ exit 0 # disable for now for faster releases # 15 kustomize # 15 graalvm -rtx exec node -- node -v -rtx exec python -- python -V -rtx exec direnv -- direnv --version -rtx exec erlang -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell -rtx exec elixir erlang -- elixir --version -rtx exec golang -- go version -rtx exec java -- java -version -rtx exec terraform -- terraform -v -rtx exec yarn -- yarn --version -rtx exec deno -- deno --version -rtx exec bun -- bun --version -rtx exec kubectl -- kubectl version --client -rtx exec dotnet-core -- dotnet --list-sdks -rtx exec flutter -- flutter --version -rtx exec crystal -- crystal -v -rtx exec neovim -- nvim --version +mise exec node -- node -v +mise exec python -- python -V +mise exec direnv -- direnv --version +mise exec erlang -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell +mise exec elixir erlang -- elixir --version +mise exec golang -- go version +mise exec java -- java -version +mise exec terraform -- terraform -v +mise exec yarn -- yarn --version +mise exec deno -- deno --version +mise exec bun -- bun --version +mise exec kubectl -- kubectl version --client +mise exec dotnet-core -- dotnet --list-sdks +mise exec flutter -- flutter --version +mise exec crystal -- crystal -v +mise exec neovim -- nvim --version -#rtx exec php -- php -v php is a bit slow to install, works fine though -#rtx exec rust -- rustc -V # does not seem to work correctly -#rtx exec postgres -- psql -v # hard one to install +#mise exec php -- php -v php is a bit slow to install, works fine though +#mise exec rust -- rustc -V # does not seem to work correctly +#mise exec postgres -- psql -v # hard one to install diff --git a/e2e/test_uninstall b/e2e/test_uninstall index c2b144b57..558efc604 100755 --- a/e2e/test_uninstall +++ b/e2e/test_uninstall @@ -3,22 +3,22 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -rtx i -rtx uninstall tiny +mise i +mise uninstall tiny export CLICOLOR=0 -assert_contains "rtx ls tiny" "3.1.0 (missing)" +assert_contains "mise ls tiny" "3.1.0 (missing)" -rtx i tiny@1 tiny@2.0 tiny@2.1 -assert_contains "rtx ls tiny" "1.1.0" -assert_contains "rtx ls tiny" "2.0.1" -assert_contains "rtx ls tiny" "2.1.0" +mise i tiny@1 tiny@2.0 tiny@2.1 +assert_contains "mise ls tiny" "1.1.0" +assert_contains "mise ls tiny" "2.0.1" +assert_contains "mise ls tiny" "2.1.0" -rtx rm -a tiny@2 -assert_contains "rtx ls tiny" "1.1.0" -assert_not_contains "rtx ls tiny" "2.0.1" -assert_not_contains "rtx ls tiny" "2.1.0" +mise rm -a tiny@2 +assert_contains "mise ls tiny" "1.1.0" +assert_not_contains "mise ls tiny" "2.0.1" +assert_not_contains "mise ls tiny" "2.1.0" -rtx rm -a tiny -assert_not_contains "rtx ls tiny" "1.1.0" -assert_not_contains "rtx ls tiny" "2.0.1" -assert_not_contains "rtx ls tiny" "2.1.0" +mise rm -a tiny +assert_not_contains "mise ls tiny" "1.1.0" +assert_not_contains "mise ls tiny" "2.0.1" +assert_not_contains "mise ls tiny" "2.1.0" diff --git a/e2e/test_upgrade b/e2e/test_upgrade index ba12fe9bf..9399c6ed4 100755 --- a/e2e/test_upgrade +++ b/e2e/test_upgrade @@ -3,17 +3,17 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -rtx use tiny@3 -rtx uninstall --all tiny -rtx install tiny -assert_contains "rtx ls --installed tiny" "3.1.0" +mise use tiny@3 +mise uninstall --all tiny +mise install tiny +assert_contains "mise ls --installed tiny" "3.1.0" -mv "$RTX_DATA_DIR/installs/tiny/"{3.1.0,3.0.0} -assert_contains "rtx ls --installed tiny" "3.0.0" -assert_not_contains "rtx ls --installed tiny" "3.1.0" +mv "$MISE_DATA_DIR/installs/tiny/"{3.1.0,3.0.0} +assert_contains "mise ls --installed tiny" "3.0.0" +assert_not_contains "mise ls --installed tiny" "3.1.0" -rtx upgrade tiny -assert_contains "rtx ls --installed tiny" "3.1.0" -assert_not_contains "rtx ls --installed tiny" "3.0.0" +mise upgrade tiny +assert_contains "mise ls --installed tiny" "3.1.0" +assert_not_contains "mise ls --installed tiny" "3.0.0" -rtx use tiny@latest +mise use tiny@latest diff --git a/e2e/test_use b/e2e/test_use index a24042fd8..835e8f025 100755 --- a/e2e/test_use +++ b/e2e/test_use @@ -3,18 +3,18 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -rtx rm --all tiny -rtx i tiny@1.0.0 -rtx use tiny@1 -assert "rtx current tiny" "1.0.0" +mise rm --all tiny +mise i tiny@1.0.0 +mise use tiny@1 +assert "mise current tiny" "1.0.0" -rtx use --env local tiny@1 -assert "rtx current tiny" "1.0.0" -assert "cat .rtx.local.toml" '[tools] +mise use --env local tiny@1 +assert "mise current tiny" "1.0.0" +assert "cat .mise.local.toml" '[tools] tiny = "1"' -rm .rtx.local.toml +rm .mise.local.toml -rtx use --rm tiny -assert "rtx current tiny" "" -rtx use tiny -assert_contains "rtx current tiny" "1.0.0" +mise use --rm tiny +assert "mise current tiny" "" +mise use tiny +assert_contains "mise current tiny" "1.0.0" diff --git a/e2e/test_zigmod b/e2e/test_zigmod index 20cbb1a2a..0fa21386b 100755 --- a/e2e/test_zigmod +++ b/e2e/test_zigmod @@ -3,6 +3,6 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -eval "$(rtx activate bash)" && eval "$(rtx hook-env)" -rtx plugin install https://github.com/kachick/asdf-zigmod -rtx x zigmod@latest -- zigmod version +eval "$(mise activate bash)" && eval "$(mise hook-env)" +mise plugin install https://github.com/kachick/asdf-zigmod +mise x zigmod@latest -- zigmod version diff --git a/flake.nix b/flake.nix index 0774cfb2d..0f36d9a16 100644 --- a/flake.nix +++ b/flake.nix @@ -7,23 +7,23 @@ outputs = { self, nixpkgs, flake-utils }: { overlay = final: prev: { - rtx = prev.callPackage ./default.nix { }; + mise = prev.callPackage ./default.nix { }; }; } // flake-utils.lib.eachDefaultSystem(system: let pkgs = import nixpkgs { inherit system; }; - rtx = pkgs.callPackage ./default.nix { }; + mise = pkgs.callPackage ./default.nix { }; in { packages = { - inherit rtx; - default = rtx; + inherit mise; + default = mise; }; devShells.default = pkgs.mkShell { - name = "rtx-develop"; + name = "mise-develop"; - inputsFrom = [ rtx ]; + inputsFrom = [ mise ]; nativeBuildInputs = with pkgs; [ just diff --git a/justfile b/justfile index 07e013a27..f2b2e21c3 100644 --- a/justfile +++ b/justfile @@ -1,6 +1,6 @@ set shell := ["bash", "-uc"] -export RTX_DATA_DIR := "/tmp/rtx" +export MISE_DATA_DIR := "/tmp/mise" export PATH := env_var_or_default("CARGO_TARGET_DIR", justfile_directory() / "target") / "debug:" + env_var("PATH") export RUST_TEST_THREADS := "1" @@ -51,8 +51,8 @@ test-coverage: set -euxo pipefail source <(cargo llvm-cov show-env --export-prefix) cargo llvm-cov clean --workspace - if [[ -n "${RTX_GITHUB_BOT_TOKEN:-}" ]]; then - export GITHUB_API_TOKEN="$RTX_GITHUB_BOT_TOKEN" + if [[ -n "${MISE_GITHUB_BOT_TOKEN:-}" ]]; then + export GITHUB_API_TOKEN="$MISE_GITHUB_BOT_TOKEN" fi export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$PWD/target}" export PATH="${CARGO_TARGET_DIR}/debug:$PATH" @@ -67,11 +67,11 @@ test-coverage: echo "::group::render-help render-completions render-mangen" just render-help render-completions render-mangen echo "::group::Implode" - rtx implode + mise implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then echo "::group::Self update" # TODO: remove this once the task runnner is shipped - rtx self-update -fy || true + mise self-update -fy || true fi echo "::group::Render lcov report" cargo llvm-cov report --lcov --output-path lcov.info @@ -80,7 +80,7 @@ test-coverage: clean: cargo clean rm -f lcov.info - rm -rf e2e/.{asdf,config,local,rtx}/ + rm -rf e2e/.{asdf,config,local,mise}/ rm -rf target rm -rf *.profraw rm -rf coverage @@ -111,19 +111,19 @@ render-all: render-help render-completions render-mangen # regenerate docs/cli-reference.md render-help: build - NO_COLOR=1 rtx render-help + NO_COLOR=1 mise render-help #npx markdown-magic md-magic # regenerate shell completion files render-completions: build - NO_COLOR=1 rtx render-completion bash > completions/rtx.bash - NO_COLOR=1 rtx render-completion zsh > completions/_rtx - NO_COLOR=1 rtx render-completion fish > completions/rtx.fish + NO_COLOR=1 mise render-completion bash > completions/mise.bash + NO_COLOR=1 mise render-completion zsh > completions/_mise + NO_COLOR=1 mise render-completion fish > completions/mise.fish # regenerate manpages render-mangen: build - NO_COLOR=1 rtx render-mangen + NO_COLOR=1 mise render-mangen # called by lefthook precommit hook pre-commit: render-all lint @@ -132,6 +132,6 @@ pre-commit: render-all lint git add completions git add man -# create/publish a new version of rtx +# create/publish a new version of mise release *args: cargo release {{ args }} diff --git a/man/man1/rtx.1 b/man/man1/mise.1 similarity index 88% rename from man/man1/rtx.1 rename to man/man1/mise.1 index d8314b33e..499b50296 100644 --- a/man/man1/rtx.1 +++ b/man/man1/mise.1 @@ -50,7 +50,7 @@ rtx\-bin\-paths(1) List all the active runtime bin paths .TP rtx\-cache(1) -Manage the rtx cache +Manage the mise cache .TP rtx\-completion(1) Generate shell completions @@ -65,7 +65,7 @@ rtx\-direnv(1) Output direnv function to use rtx inside direnv .TP rtx\-doctor(1) -Check rtx installation for possible problems. +Check mise installation for possible problems. .TP rtx\-env(1) Exports env vars to activate rtx a single time @@ -140,15 +140,15 @@ rtx\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA Examples: - $ rtx install node@20.0.0 Install a specific node version - $ rtx install node@20.0 Install a version matching a prefix - $ rtx install node Install the node version defined in - .tool\-versions or .rtx.toml + $ mise install node@20.0.0 Install a specific node version + $ mise install node@20.0 Install a version matching a prefix + $ mise install node Install the node version defined in + .tool\-versions or .mise.toml $ rtx use node@20 Use node\-20.x in current project $ rtx use \-g node@20 Use node\-20.x as default $ rtx use node@latest Use latest node in current directory $ rtx use \-g node@system Use system node everywhere unless overridden - $ rtx x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH + $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION v2023.11.9 .SH AUTHORS diff --git a/packaging/deb/generate-release.sh b/packaging/deb/generate-release.sh index 4978ed754..0db800e67 100755 --- a/packaging/deb/generate-release.sh +++ b/packaging/deb/generate-release.sh @@ -19,14 +19,14 @@ do_hash() { } cat <&2 } @@ -12,7 +12,7 @@ else } fi -if [ "${RTX_QUIET-}" = "1" ] || [ "${RTX_QUIET-}" = "true" ]; then +if [ "${MISE_QUIET-}" = "1" ] || [ "${MISE_QUIET-}" = "true" ]; then info() { : } @@ -57,7 +57,7 @@ shasum_bin() { elif command -v sha256sum >/dev/null 2>&1; then echo "sha256sum" else - error "rtx install requires shasum or sha256sum but neither is installed. Aborting." + error "mise install requires shasum or sha256sum but neither is installed. Aborting." fi } @@ -65,10 +65,10 @@ get_checksum() { os="$(get_os)" arch="$(get_arch)" - checksum_linux_x86_64="$RTX_CHECKSUM_LINUX_X86_64" - checksum_linux_arm64="$RTX_CHECKSUM_LINUX_ARM64" - checksum_macos_x86_64="$RTX_CHECKSUM_MACOS_X86_64" - checksum_macos_arm64="$RTX_CHECKSUM_MACOS_ARM64" + checksum_linux_x86_64="$MISE_CHECKSUM_LINUX_X86_64" + checksum_linux_arm64="$MISE_CHECKSUM_LINUX_ARM64" + checksum_macos_x86_64="$MISE_CHECKSUM_MACOS_X86_64" + checksum_macos_arm64="$MISE_CHECKSUM_MACOS_ARM64" if [ "$os" = "linux" ] && [ "$arch" = "x64" ]; then echo "$checksum_linux_x86_64" @@ -91,7 +91,7 @@ download_file() { cache_dir="$(mktemp -d)" file="$cache_dir/$filename" - info "rtx: installing rtx..." + info "mise: installing mise..." if command -v curl >/dev/null 2>&1; then debug ">" curl -fLlSso "$file" "$url" @@ -102,26 +102,26 @@ download_file() { stderr=$(mktemp) wget -O "$file" "$url" >"$stderr" 2>&1 || error "wget failed: $(cat "$stderr")" else - error "rtx standalone install requires curl or wget but neither is installed. Aborting." + error "mise standalone install requires curl or wget but neither is installed. Aborting." fi fi echo "$file" } -install_rtx() { +install_mise() { # download the tarball - version="$RTX_VERSION" + version="$MISE_VERSION" os="$(get_os)" arch="$(get_arch)" xdg_data_home="${XDG_DATA_HOME:-$HOME/.local/share}" - rtx_data_dir="${RTX_DATA_DIR:-$xdg_data_home/rtx}" - install_path="${RTX_INSTALL_PATH:-${rtx_data_dir}/bin/rtx}" + mise_data_dir="${MISE_DATA_DIR:-$xdg_data_home/mise}" + install_path="${MISE_INSTALL_PATH:-${mise_data_dir}/bin/mise}" install_dir="$(dirname "$install_path")" - tarball_url="https://github.com/jdx/rtx/releases/download/${version}/rtx-${version}-${os}-${arch}.tar.gz" + tarball_url="https://github.com/jdx/mise/releases/download/${version}/mise-${version}-${os}-${arch}.tar.gz" cache_file=$(download_file "$tarball_url") - debug "rtx-setup: tarball=$cache_file" + debug "mise-setup: tarball=$cache_file" debug "validating checksum" cd "$(dirname "$cache_file")" && get_checksum | "$(shasum_bin)" -c >/dev/null @@ -131,38 +131,38 @@ install_rtx() { rm -rf "$install_path" cd "$(mktemp -d)" tar -xzf "$cache_file" - mv rtx/bin/rtx "$install_path" - info "rtx: installed successfully to $install_path" + mv mise/bin/mise "$install_path" + info "mise: installed successfully to $install_path" } after_finish_help() { case "${SHELL:-}" in */zsh) - info "rtx: run the following to activate rtx in your shell:" + info "mise: run the following to activate mise in your shell:" info "echo \"eval \\\"\\\$($install_path activate zsh)\\\"\" >> \"${ZDOTDIR-$HOME}/.zshrc\"" info "" - info "rtx: this must be run in order to use rtx in the terminal" - info "rtx: run \`rtx doctor\` to verify this is setup correctly" + info "mise: this must be run in order to use mise in the terminal" + info "mise: run \`mise doctor\` to verify this is setup correctly" ;; */bash) - info "rtx: run the following to activate rtx in your shell:" + info "mise: run the following to activate mise in your shell:" info "echo \"eval \\\"\\\$($install_path activate bash)\\\"\" >> ~/.bashrc" info "" - info "rtx: this must be run in order to use rtx in the terminal" - info "rtx: run \`rtx doctor\` to verify this is setup correctly" + info "mise: this must be run in order to use mise in the terminal" + info "mise: run \`mise doctor\` to verify this is setup correctly" ;; */fish) - info "rtx: run the following to activate rtx in your shell:" + info "mise: run the following to activate mise in your shell:" info "echo \"$install_path activate fish | source\" >> ~/.config/fish/config.fish" info "" - info "rtx: this must be run in order to use rtx in the terminal" - info "rtx: run \`rtx doctor\` to verify this is setup correctly" + info "mise: this must be run in order to use mise in the terminal" + info "mise: run \`mise doctor\` to verify this is setup correctly" ;; *) - info "rtx: run \`$install_path --help\` to get started" + info "mise: run \`$install_path --help\` to get started" ;; esac } -install_rtx +install_mise after_finish_help diff --git a/schema/rtx.json b/schema/mise.json similarity index 92% rename from schema/rtx.json rename to schema/mise.json index 8bcad0e49..be3aa415b 100644 --- a/schema/rtx.json +++ b/schema/mise.json @@ -1,13 +1,13 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://rtx.jdx.dev/schema/rtx.json", - "title": "rtx", - "description": "config file for rtx version manager (.rtx.toml)", + "$id": "https://mise.jdx.dev/schema/mise.json", + "title": "mise", + "description": "config file for mise version manager (.mise.toml)", "type": "object", "additionalProperties": false, "properties": { "min_version": { - "description": "minimum version of rtx required to use this config", + "description": "minimum version of mise required to use this config", "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" }, @@ -169,7 +169,7 @@ "additionalProperties": { "type": "string" } }, "quiet": { - "description": "do not display rtx information for this task", + "description": "do not display mise information for this task", "type": "boolean" }, "raw": { @@ -198,12 +198,12 @@ ] }, "settings": { - "description": "settings for rtx", + "description": "settings for mise", "type": "object", "additionalProperties": false, "properties": { "legacy_version_file": { - "description": "should rtx parse legacy version files (e.g. .node-version)", + "description": "should mise parse legacy version files (e.g. .node-version)", "type": "boolean" }, "legacy_version_file_disable_tools": { @@ -215,11 +215,11 @@ } }, "always_keep_download": { - "description": "should rtx keep downloaded files after installation", + "description": "should mise keep downloaded files after installation", "type": "boolean" }, "always_keep_install": { - "description": "should rtx keep install files after installation even if the installation fails", + "description": "should mise keep install files after installation even if the installation fails", "type": "boolean" }, "plugin_autoupdate_last_check_duration": { diff --git a/schema/rtx.plugin.json b/schema/mise.plugin.json similarity index 91% rename from schema/rtx.plugin.json rename to schema/mise.plugin.json index 838cc763e..07b8ec870 100644 --- a/schema/rtx.plugin.json +++ b/schema/mise.plugin.json @@ -1,8 +1,8 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://rtx.jdx.dev/schema/rtx.plugin.json", - "title": "rtx-plugin", - "description": "config file for an rtx plugin", + "$id": "https://mise.jdx.dev/schema/mise.plugin.json", + "title": "mise-plugin", + "description": "config file for a mise plugin", "type": "object", "additionalProperties": false, "properties": { diff --git a/scripts/build-deb.sh b/scripts/build-deb.sh index 9f79783a0..b98c0b08e 100755 --- a/scripts/build-deb.sh +++ b/scripts/build-deb.sh @@ -1,36 +1,36 @@ #!/usr/bin/env bash set -euxo pipefail -RTX_VERSION=$(./scripts/get-version.sh) +MISE_VERSION=$(./scripts/get-version.sh) -mkdir -p rtx/lib -touch rtx/lib/.disable-self-update +mkdir -p mise/lib +touch mise/lib/.disable-self-update -tar -xvJf "dist/rtx-$RTX_VERSION-linux-x64.tar.xz" +tar -xvJf "dist/mise-$MISE_VERSION-linux-x64.tar.xz" fpm -s dir -t deb \ - --name rtx \ + --name mise \ --license MIT \ - --version "${RTX_VERSION#v*}" \ + --version "${MISE_VERSION#v*}" \ --architecture amd64 \ --description "The front-end to your dev env" \ - --url "https://github.com/jdx/rtx" \ + --url "https://github.com/jdx/mise" \ --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + mise/bin/mise=/usr/bin/mise \ + mise/lib/.disable-self-update=/usr/lib/mise/.disable-self-update \ + mise/man/man1/mise.1=/usr/share/man/man1/mise.1 -tar -xvJf "dist/rtx-$RTX_VERSION-linux-arm64.tar.xz" +tar -xvJf "dist/mise-$MISE_VERSION-linux-arm64.tar.xz" fpm -s dir -t deb \ - --name rtx \ + --name mise \ --license MIT \ - --version "${RTX_VERSION#v*}" \ + --version "${MISE_VERSION#v*}" \ --architecture arm64 \ --description "The front-end to your dev env" \ - --url "https://github.com/jdx/rtx" \ + --url "https://github.com/jdx/mise" \ --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + mise/bin/mise=/usr/bin/mise \ + mise/lib/.disable-self-update=/usr/lib/mise/.disable-self-update \ + mise/man/man1/mise.1=/usr/share/man/man1/mise.1 mkdir -p dist/deb/pool/main cp -v ./*.deb dist/deb/pool/main @@ -45,6 +45,6 @@ cd ../.. cd dist/deb/dists/stable "$GITHUB_WORKSPACE/packaging/deb/generate-release.sh" >Release -gpg -u 408B88DB29DDE9E0 -abs Release.gpg -gpg -u 408B88DB29DDE9E0 -abs --clearsign InRelease +gpg -u 8B81C9D17413A06D -abs Release.gpg +gpg -u 8B81C9D17413A06D -abs --clearsign InRelease cd "$GITHUB_WORKSPACE" diff --git a/scripts/build-rpm.sh b/scripts/build-rpm.sh index 55ff70e83..5adb61e99 100755 --- a/scripts/build-rpm.sh +++ b/scripts/build-rpm.sh @@ -1,44 +1,44 @@ #!/usr/bin/env bash set -euxo pipefail -RTX_VERSION=$(./scripts/get-version.sh) +MISE_VERSION=$(./scripts/get-version.sh) -mkdir -p rtx/lib -touch rtx/lib/.disable-self-update +mkdir -p mise/lib +touch mise/lib/.disable-self-update -tar -xvJf "dist/rtx-$RTX_VERSION-linux-x64.tar.xz" +tar -xvJf "dist/mise-$MISE_VERSION-linux-x64.tar.xz" fpm -s dir -t rpm \ - --name rtx \ + --name mise \ --license MIT \ - --version "${RTX_VERSION#v*}" \ + --version "${MISE_VERSION#v*}" \ --architecture x86_64 \ --description "The front-end to your dev env" \ - --url "https://github.com/jdx/rtx" \ + --url "https://github.com/jdx/mise" \ --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + mise/bin/mise=/usr/bin/mise \ + mise/lib/.disable-self-update=/usr/lib/mise/.disable-self-update \ + mise/man/man1/mise.1=/usr/share/man/man1/mise.1 -tar -xvJf "dist/rtx-$RTX_VERSION-linux-arm64.tar.xz" +tar -xvJf "dist/mise-$MISE_VERSION-linux-arm64.tar.xz" fpm -s dir -t rpm \ - --name rtx \ + --name mise \ --license MIT \ - --version "${RTX_VERSION#v*}" \ + --version "${MISE_VERSION#v*}" \ --architecture aarch64 \ --description "The front-end to your dev env" \ - --url "https://github.com/jdx/rtx" \ + --url "https://github.com/jdx/mise" \ --maintainer "Jeff Dickey @jdx" \ - rtx/bin/rtx=/usr/bin/rtx \ - rtx/lib/.disable-self-update=/usr/lib/rtx/.disable-self-update \ - rtx/man/man1/rtx.1=/usr/share/man/man1/rtx.1 + mise/bin/mise=/usr/bin/mise \ + mise/lib/.disable-self-update=/usr/lib/mise/.disable-self-update \ + mise/man/man1/mise.1=/usr/share/man/man1/mise.1 cat <~/.rpmmacros %_signature gpg -%_gpg_name 408B88DB29DDE9E0 +%_gpg_name 8B81C9D17413A06D EOF mkdir -p dist/rpmrepo/packages -cp -v packaging/rpm/rtx.repo dist/rpmrepo +cp -v packaging/rpm/mise.repo dist/rpmrepo cp -v ./*.rpm dist/rpmrepo/packages rpm --addsign dist/rpmrepo/packages/*.rpm createrepo dist/rpmrepo diff --git a/scripts/build-tarball.sh b/scripts/build-tarball.sh index 39715a5da..4738819e9 100755 --- a/scripts/build-tarball.sh +++ b/scripts/build-tarball.sh @@ -85,21 +85,21 @@ elif command -v zig >/dev/null; then else cargo build "$@" fi -mkdir -p dist/rtx/bin -mkdir -p dist/rtx/man/man1 -mkdir -p dist/rtx/share/fish/vendor_conf.d -cp "target/$RUST_TRIPLE/release/rtx" dist/rtx/bin/rtx -cp README.md dist/rtx/README.md -cp LICENSE dist/rtx/LICENSE -cp {,dist/rtx/}man/man1/rtx.1 -cp {,dist/rtx/}share/fish/vendor_conf.d/rtx-activate.fish +mkdir -p dist/mise/bin +mkdir -p dist/mise/man/man1 +mkdir -p dist/mise/share/fish/vendor_conf.d +cp "target/$RUST_TRIPLE/release/mise" dist/mise/bin/mise +cp README.md dist/mise/README.md +cp LICENSE dist/mise/LICENSE +cp {,dist/mise/}man/man1/mise.1 +cp {,dist/mise/}share/fish/vendor_conf.d/mise-activate.fish cd dist -tar -cJf "$BASENAME.tar.xz" rtx -tar -czf "$BASENAME.tar.gz" rtx +tar -cJf "$BASENAME.tar.xz" mise +tar -czf "$BASENAME.tar.gz" mise -if [ -f ~/.zipsign/rtx.priv ]; then - zipsign sign tar "$BASENAME.tar.gz" ~/.zipsign/rtx.priv +if [ -f ~/.zipsign/mise.priv ]; then + zipsign sign tar "$BASENAME.tar.gz" ~/.zipsign/mise.priv zipsign verify tar "$BASENAME.tar.gz" ../zipsign.pub fi diff --git a/scripts/publish-r2.sh b/scripts/publish-r2.sh index f84c43038..d10d9edf2 100755 --- a/scripts/publish-r2.sh +++ b/scripts/publish-r2.sh @@ -6,6 +6,6 @@ export AWS_DEFAULT_OUTPUT=json export AWS_ENDPOINT_URL=https://6e243906ff257b965bcae8025c2fc344.r2.cloudflarestorage.com export AWS_ACCESS_KEY_ID=$CLOUDFLARE_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$CLOUDFLARE_SECRET_ACCESS_KEY -export AWS_S3_BUCKET=rtx +export AWS_S3_BUCKET=mise -./rtx/scripts/publish-s3.sh || true +./mise/scripts/publish-s3.sh || true diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 96c5d8984..b2dcf5c8e 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -5,17 +5,17 @@ set -euxo pipefail cache_day="max-age=86400,s-maxage=86400,public,immutable" cache_week="max-age=604800,s-maxage=604800,public,immutable" -aws s3 cp "$RELEASE_DIR/$RTX_VERSION" "s3://$AWS_S3_BUCKET/$RTX_VERSION/" --cache-control "$cache_week" --no-progress --recursive +aws s3 cp "$RELEASE_DIR/$MISE_VERSION" "s3://$AWS_S3_BUCKET/$MISE_VERSION/" --cache-control "$cache_week" --no-progress --recursive -aws s3 cp "$RELEASE_DIR" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "rtx-latest-*" +aws s3 cp "$RELEASE_DIR" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "mise-latest-*" aws s3 cp "$RELEASE_DIR" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --content-type "text/plain" --recursive --exclude "*" --include "SHASUMS*" aws s3 cp "$RELEASE_DIR/VERSION" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --content-type "text/plain" aws s3 cp "$RELEASE_DIR/install.sh" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --content-type "text/plain" aws s3 cp "$RELEASE_DIR/install.sh.sig" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress -aws s3 cp "./rtx/schema/rtx.json" "s3://$AWS_S3_BUCKET/schema/rtx.json" --cache-control "$cache_day" --no-progress --content-type "application/json" -aws s3 cp "./rtx/schema/rtx.plugin.json" "s3://$AWS_S3_BUCKET/schema/rtx.plugin.json" --cache-control "$cache_day" --no-progress --content-type "application/json" +aws s3 cp "./mise/schema/mise.json" "s3://$AWS_S3_BUCKET/schema/mise.json" --cache-control "$cache_day" --no-progress --content-type "application/json" +aws s3 cp "./mise/schema/mise.plugin.json" "s3://$AWS_S3_BUCKET/schema/mise.plugin.json" --cache-control "$cache_day" --no-progress --content-type "application/json" -aws s3 cp artifacts/rpm/rtx.repo "s3://$AWS_S3_BUCKET/rpm/" --cache-control "$cache_day" --no-progress +aws s3 cp artifacts/rpm/mise.repo "s3://$AWS_S3_BUCKET/rpm/" --cache-control "$cache_day" --no-progress aws s3 cp artifacts/rpm/packages/ "s3://$AWS_S3_BUCKET/rpm/packages/" --cache-control "$cache_week" --no-progress --recursive aws s3 cp artifacts/rpm/repodata/ "s3://$AWS_S3_BUCKET/rpm/repodata/" --cache-control "$cache_day" --no-progress --recursive --exclude "*" --include "repomd.xml*" aws s3 cp artifacts/rpm/repodata/ "s3://$AWS_S3_BUCKET/rpm/repodata/" --cache-control "$cache_week" --no-progress --recursive --exclude "repomd.xml*" diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh index c3d51a7d1..e6f871e69 100755 --- a/scripts/release-alpine.sh +++ b/scripts/release-alpine.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euxo pipefail -RTX_VERSION=$(./scripts/get-version.sh) +MISE_VERSION=$(./scripts/get-version.sh) export GITLAB_HOST=gitlab.alpinelinux.org @@ -18,10 +18,10 @@ git clone https://gitlab.alpinelinux.org/alpine/aports /home/packager/aports cd /home/packager/aports git config --local core.hooksPath .githooks git remote add jdxcode "https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git" -git checkout -mb rtx -cd community/rtx +git checkout -mb mise +cd community/mise -sed -i "s/pkgver=.*/pkgver=${RTX_VERSION#v}/" APKBUILD +sed -i "s/pkgver=.*/pkgver=${MISE_VERSION#v}/" APKBUILD abuild checksum cat /github/home/.abuild/abuild.conf @@ -34,7 +34,7 @@ if git diff --cached --exit-code; then echo "No changes to commit" exit 0 fi -git commit -m "community/rtx: upgrade to ${RTX_VERSION#v}" +git commit -m "community/mise: upgrade to ${MISE_VERSION#v}" if [ "$DRY_RUN" == 0 ]; then git push jdxcode diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index 44fe56bfa..fdc9f27ed 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -1,68 +1,68 @@ #!/usr/bin/env bash set -euxo pipefail -RTX_VERSION=$(./scripts/get-version.sh) +MISE_VERSION=$(./scripts/get-version.sh) -TAR_GZ_URI="https://github.com/jdx/rtx/releases/download/$RTX_VERSION/rtx-$RTX_VERSION-linux-x64.tar.gz" +TAR_GZ_URI="https://github.com/jdx/mise/releases/download/$MISE_VERSION/mise-$MISE_VERSION-linux-x64.tar.gz" SHA512=$(curl -fsSL "$TAR_GZ_URI" | sha512sum | awk '{print $1}') if [ ! -d aur-bin ]; then - git clone ssh://aur@aur.archlinux.org/rtx-bin.git aur-bin + git clone ssh://aur@aur.archlinux.org/mise-bin.git aur-bin fi git -C aur-bin pull cat >aur-bin/PKGBUILD < +# Maintainer: Jeff Dickey -pkgname=rtx-bin -pkgver=${RTX_VERSION#v*} +pkgname=mise-bin +pkgver=${MISE_VERSION#v*} pkgrel=1 pkgdesc='The front-end to your dev env' arch=('x86_64') -url='https://github.com/jdx/rtx' +url='https://github.com/jdx/mise' license=('MIT') -provides=('rtx') -conflicts=('rtx') +provides=('mise') +conflicts=('mise') options=('!lto') -source=("rtx-\$pkgver.tar.gz::${TAR_GZ_URI}") +source=("mise-\$pkgver.tar.gz::${TAR_GZ_URI}") sha512sums=('$SHA512') build() { cd "\$srcdir/" - rtx/bin/rtx completions bash > rtx.bash - rtx/bin/rtx completions fish > rtx.fish - rtx/bin/rtx completions zsh > _rtx + mise/bin/mise completions bash > mise.bash + mise/bin/mise completions fish > mise.fish + mise/bin/mise completions zsh > _mise } package() { cd "\$srcdir/" - install -Dm755 rtx/bin/rtx "\$pkgdir/usr/bin/rtx" - install -Dm644 rtx/man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" - install -Dm644 rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" - install -Dm644 rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" - install -Dm644 _rtx "\$pkgdir/usr/share/zsh/site-functions/_rtx" + install -Dm755 mise/bin/mise "\$pkgdir/usr/bin/mise" + install -Dm644 mise/man/man1/mise.1 "\$pkgdir/usr/share/man/man1/mise.1" + install -Dm644 mise.bash "\$pkgdir/usr/share/bash-completion/completions/mise" + install -Dm644 mise.fish "\$pkgdir/usr/share/fish/completions/mise.fish" + install -Dm644 _mise "\$pkgdir/usr/share/zsh/site-functions/_mise" } check() { - "\$srcdir/rtx/bin/rtx" --version + "\$srcdir/mise/bin/mise" --version } EOF cat >aur-bin/.SRCINFO <aur/PKGBUILD < +# Maintainer: Jeff Dickey -pkgname=rtx -pkgver=${RTX_VERSION#v*} +pkgname=mise +pkgver=${MISE_VERSION#v*} pkgrel=1 pkgdesc='The front-end to your dev env' arch=('x86_64') -url='https://github.com/jdx/rtx' +url='https://github.com/jdx/mise' license=('MIT') makedepends=('cargo') -provides=('rtx') -conflicts=('rtx-bin') +provides=('mise') +conflicts=('mise-bin') options=('!lto') source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdx/\$pkgname/archive/v\$pkgver.tar.gz") sha512sums=('$SHA512') @@ -41,34 +41,34 @@ build() { package() { cd "\$srcdir/\$pkgname-\$pkgver" - install -Dm755 target/release/rtx "\$pkgdir/usr/bin/rtx" - install -Dm644 man/man1/rtx.1 "\$pkgdir/usr/share/man/man1/rtx.1" - install -Dm644 completions/rtx.bash "\$pkgdir/usr/share/bash-completion/completions/rtx" - install -Dm644 completions/rtx.fish "\$pkgdir/usr/share/fish/completions/rtx.fish" - install -Dm644 completions/_rtx "\$pkgdir/usr/share/zsh/site-functions/_rtx" + install -Dm755 target/release/mise "\$pkgdir/usr/bin/mise" + install -Dm644 man/man1/mise.1 "\$pkgdir/usr/share/man/man1/mise.1" + install -Dm644 completions/mise.bash "\$pkgdir/usr/share/bash-completion/completions/mise" + install -Dm644 completions/mise.fish "\$pkgdir/usr/share/fish/completions/mise.fish" + install -Dm644 completions/_mise "\$pkgdir/usr/share/zsh/site-functions/_mise" } check() { cd "\$srcdir/\$pkgname-\$pkgver" - ./target/release/rtx --version + ./target/release/mise --version } EOF cat >aur/.SRCINFO <"$RELEASE_DIR/npm/package.json" { "name": "$NPM_PREFIX-$os-$arch", - "version": "$RTX_VERSION", + "version": "$MISE_VERSION", "description": "polyglot runtime manager", "bin": { - "rtx": "bin/rtx" + "mise": "bin/mise" }, "repository": { "type": "git", - "url": "https://github.com/jdx/rtx" + "url": "https://github.com/jdx/mise" }, "files": [ "bin", @@ -100,7 +100,7 @@ function installArchSpecificPackage(version) { cp.on('close', function(code) { var pkgJson = require.resolve(['$NPM_PREFIX', platform, arch].join('-') + '/package.json'); var subpkg = JSON.parse(fs.readFileSync(pkgJson, 'utf8')); - var executable = subpkg.bin.rtx; + var executable = subpkg.bin.mise; var bin = path.resolve(path.dirname(pkgJson), executable); try { @@ -115,8 +115,8 @@ function installArchSpecificPackage(version) { if (platform == 'win') { var pkg = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), 'package.json'))); - fs.writeFileSync(path.resolve(process.cwd(), 'bin/rtx'), 'This file intentionally left blank'); - pkg.bin.rtx = 'bin/rtx.exe'; + fs.writeFileSync(path.resolve(process.cwd(), 'bin/mise'), 'This file intentionally left blank'); + pkg.bin.mise = 'bin/mise.exe'; fs.writeFileSync(path.resolve(process.cwd(), 'package.json'), JSON.stringify(pkg, null, 2)); } @@ -144,10 +144,10 @@ cat <"$RELEASE_DIR/npm/package.json" { "name": "$NPM_PREFIX", "description": "polyglot runtime manager", - "version": "$RTX_VERSION", + "version": "$MISE_VERSION", "repository": { "type": "git", - "url": "https://github.com/jdx/rtx" + "url": "https://github.com/jdx/mise" }, "files": [ "installArchSpecificPackage.js", @@ -158,7 +158,7 @@ cat <"$RELEASE_DIR/npm/package.json" "preinstall": "node installArchSpecificPackage.js" }, "bin": { - "rtx": "./bin/rtx" + "mise": "./bin/mise" }, "license": "MIT", "engines": { diff --git a/scripts/release.sh b/scripts/release.sh index 6377f67e5..22d6d4c60 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -5,18 +5,18 @@ echo "::group::Setup" git config --global user.name rtx-vm git config --global user.email 123107610+rtx-vm@users.noreply.github.com -BASE_DIR="$(cd rtx && pwd)" -RTX_VERSION=$(cd rtx && ./scripts/get-version.sh) +BASE_DIR="$(cd mise && pwd)" +MISE_VERSION=$(cd mise && ./scripts/get-version.sh) RELEASE_DIR=releases -export BASE_DIR RTX_VERSION RELEASE_DIR -rm -rf "${RELEASE_DIR:?}/$RTX_VERSION" -mkdir -p "$RELEASE_DIR/$RTX_VERSION" +export BASE_DIR MISE_VERSION RELEASE_DIR +rm -rf "${RELEASE_DIR:?}/$MISE_VERSION" +mkdir -p "$RELEASE_DIR/$MISE_VERSION" echo "::group::Build" find artifacts -name 'tarball-*' -exec sh -c ' target=${1#artifacts/tarball-} - cp "artifacts/tarball-$target/"*.tar.gz "$RELEASE_DIR/$RTX_VERSION" - cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$RTX_VERSION" + cp "artifacts/tarball-$target/"*.tar.gz "$RELEASE_DIR/$MISE_VERSION" + cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$MISE_VERSION" ' sh {} \; platforms=( @@ -32,48 +32,48 @@ platforms=( macos-arm64 ) for platform in "${platforms[@]}"; do - cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" "$RELEASE_DIR/rtx-latest-$platform.tar.gz" - cp "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.xz" "$RELEASE_DIR/rtx-latest-$platform.tar.xz" - tar -xvzf "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform.tar.gz" - cp -v rtx/bin/rtx "$RELEASE_DIR/rtx-latest-$platform" - cp -v rtx/bin/rtx "$RELEASE_DIR/$RTX_VERSION/rtx-$RTX_VERSION-$platform" + cp "$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz" "$RELEASE_DIR/mise-latest-$platform.tar.gz" + cp "$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.xz" "$RELEASE_DIR/mise-latest-$platform.tar.xz" + tar -xvzf "$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz" + cp -v mise/bin/mise "$RELEASE_DIR/mise-latest-$platform" + cp -v mise/bin/mise "$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform" done echo "::group::Checksums" pushd "$RELEASE_DIR" -echo "$RTX_VERSION" | tr -d 'v' >VERSION -cp rtx-latest-linux-x64 rtx-latest-linux-amd64 -cp rtx-latest-macos-x64 rtx-latest-macos-amd64 -sha256sum ./rtx-latest-* >SHASUMS256.txt -sha512sum ./rtx-latest-* >SHASUMS512.txt -gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc -gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc +echo "$MISE_VERSION" | tr -d 'v' >VERSION +cp mise-latest-linux-x64 mise-latest-linux-amd64 +cp mise-latest-macos-x64 mise-latest-macos-amd64 +sha256sum ./mise-latest-* >SHASUMS256.txt +sha512sum ./mise-latest-* >SHASUMS512.txt +gpg --clearsign -u 8B81C9D17413A06D SHASUMS256.asc +gpg --clearsign -u 8B81C9D17413A06D SHASUMS512.asc popd -pushd "$RELEASE_DIR/$RTX_VERSION" +pushd "$RELEASE_DIR/$MISE_VERSION" sha256sum ./* >SHASUMS256.txt sha512sum ./* >SHASUMS512.txt -gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS256.asc -gpg --clearsign -u 408B88DB29DDE9E0 SHASUMS512.asc +gpg --clearsign -u 8B81C9D17413A06D SHASUMS256.asc +gpg --clearsign -u 8B81C9D17413A06D SHASUMS512.asc popd echo "::group::install.sh" -./rtx/scripts/render-install.sh >"$RELEASE_DIR"/install.sh +./mise/scripts/render-install.sh >"$RELEASE_DIR"/install.sh chmod +x "$RELEASE_DIR"/install.sh shellcheck "$RELEASE_DIR"/install.sh -gpg -u 408B88DB29DDE9E0 --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh +gpg -u 8B81C9D17413A06D --output "$RELEASE_DIR"/install.sh.sig --sign "$RELEASE_DIR"/install.sh if [[ "$DRY_RUN" != 1 ]]; then - echo "::group::Publish npm @jdxcode/rtx" - NPM_PREFIX=@jdxcode/rtx ./rtx/scripts/release-npm.sh - echo "::group::Publish npm rtx-cli" - NPM_PREFIX=rtx-cli ./rtx/scripts/release-npm.sh + echo "::group::Publish npm @jdxcode/mise" + NPM_PREFIX=@jdxcode/mise ./mise/scripts/release-npm.sh + # echo "::group::Publish npm mise-cli" + # NPM_PREFIX=mise-cli ./mise/scripts/release-npm.sh echo "::group::Publish r2" - ./rtx/scripts/publish-r2.sh + ./mise/scripts/publish-r2.sh fi -echo "::group::Publish homebrew" -./rtx/scripts/render-homebrew.sh >homebrew-tap/rtx.rb -pushd homebrew-tap -git add . && git commit -m "rtx ${RTX_VERSION#v}" -popd +#echo "::group::Publish homebrew" +#./mise/scripts/render-homebrew.sh >homebrew-tap/mise.rb +#pushd homebrew-tap +#git add . && git commit -m "mise ${MISE_VERSION#v}" +#popd diff --git a/scripts/render-homebrew.sh b/scripts/render-homebrew.sh index 51c1e85aa..d9e14f3e0 100755 --- a/scripts/render-homebrew.sh +++ b/scripts/render-homebrew.sh @@ -2,16 +2,16 @@ set -euxo pipefail # shellcheck disable=SC2016 -RTX_VERSION=${RTX_VERSION#v*} \ - RTX_CHECKSUM_LINUX_X86_64=$(grep "rtx-v$RTX_VERSION-linux-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_X86_64_MUSL=$(grep "rtx-v$RTX_VERSION-linux-x64-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64=$(grep "rtx-v$RTX_VERSION-linux-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARM64_MUSL=$(grep "rtx-v$RTX_VERSION-linux-arm64-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV6=$(grep "rtx-v$RTX_VERSION-linux-armv6.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV6_MUSL=$(grep "rtx-v$RTX_VERSION-linux-armv6-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV7=$(grep "rtx-v$RTX_VERSION-linux-armv7.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_LINUX_ARMV7_MUSL=$(grep "rtx-v$RTX_VERSION-linux-armv7-musl.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_X86_64=$(grep "rtx-v$RTX_VERSION-macos-x64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - RTX_CHECKSUM_MACOS_ARM64=$(grep "rtx-v$RTX_VERSION-macos-arm64.tar.xz" "$RELEASE_DIR/v$RTX_VERSION/SHASUMS256.txt" | cut -d ' ' -f1) \ - envsubst '$RTX_VERSION,$RTX_CHECKSUM_LINUX_X86_64,$RTX_CHECKSUM_LINUX_ARM64,$RTX_CHECKSUM_MACOS_X86_64,$RTX_CHECKSUM_MACOS_ARM64' \ - /dev/null 2>&1; then fi mkdir -p ~/.zipsign -echo "$ZIPSIGN" | base64 -d >~/.zipsign/rtx.priv +echo "$ZIPSIGN" | base64 -d >~/.zipsign/mise.priv diff --git a/scripts/test-standalone.sh b/scripts/test-standalone.sh index b45ab5607..a172442e7 100755 --- a/scripts/test-standalone.sh +++ b/scripts/test-standalone.sh @@ -3,18 +3,18 @@ set -euxo pipefail BASE_DIR="$(pwd)" RELEASE_DIR="$(pwd)/tmp" -RTX_VERSION="v$(curl -fsSL https://rtx.jdx.dev/VERSION)" -export BASE_DIR RELEASE_DIR RTX_VERSION +MISE_VERSION="v$(curl -fsSL https://mise.jdx.dev/VERSION)" +export BASE_DIR RELEASE_DIR MISE_VERSION -mkdir -p "$RELEASE_DIR/$RTX_VERSION" -curl -fsSL "https://rtx.jdx.dev/$RTX_VERSION/SHASUMS256.txt" >"$RELEASE_DIR/$RTX_VERSION/SHASUMS256.txt" +mkdir -p "$RELEASE_DIR/$MISE_VERSION" +curl -fsSL "https://mise.jdx.dev/$MISE_VERSION/SHASUMS256.txt" >"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt" ./scripts/render-install.sh >tmp/install.sh chmod +x tmp/install.sh shellcheck tmp/install.sh -RTX_DATA_DIR="$RELEASE_DIR" ./tmp/install.sh -if [[ ! "$("$RELEASE_DIR/bin/rtx" -v)" =~ ^${RTX_VERSION//v/} ]]; then - echo "rtx version mismatch" +MISE_DATA_DIR="$RELEASE_DIR" ./tmp/install.sh +if [[ ! "$("$RELEASE_DIR/bin/mise" -v)" =~ ^${MISE_VERSION//v/} ]]; then + echo "mise version mismatch" exit 1 fi rm -rf "$RELEASE_DIR" diff --git a/share/fish/vendor_conf.d/mise-activate.fish b/share/fish/vendor_conf.d/mise-activate.fish new file mode 100644 index 000000000..85bbf5de7 --- /dev/null +++ b/share/fish/vendor_conf.d/mise-activate.fish @@ -0,0 +1,3 @@ +if [ "$MISE_FISH_AUTO_ACTIVATE" != "0" ] + mise activate fish | source +end diff --git a/share/fish/vendor_conf.d/rtx-activate.fish b/share/fish/vendor_conf.d/rtx-activate.fish deleted file mode 100644 index 922ec25b4..000000000 --- a/share/fish/vendor_conf.d/rtx-activate.fish +++ /dev/null @@ -1,3 +0,0 @@ -if [ "$RTX_FISH_AUTO_ACTIVATE" != "0" ] - rtx activate fish | source -end diff --git a/src/cli/activate.rs b/src/cli/activate.rs index cc3c43b64..7c9b58be7 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -6,24 +6,24 @@ use crate::file::touch_dir; use crate::shell::{get_shell, ShellType}; use crate::{dirs, env}; -/// Initializes rtx in the current shell session +/// Initializes mise in the current shell session /// /// This should go into your shell's rc file. /// Otherwise, it will only take effect in the current session. /// (e.g. ~/.zshrc, ~/.bashrc) /// /// This is only intended to be used in interactive sessions, not scripts. -/// rtx is only capable of updating PATH when the prompt is displayed to the user. +/// mise is only capable of updating PATH when the prompt is displayed to the user. /// For non-interactive use-cases, use shims instead. /// /// Typically this can be added with something like the following: /// -/// echo 'eval "$(rtx activate)"' >> ~/.zshrc +/// echo 'eval "$(mise activate)"' >> ~/.zshrc /// -/// However, this requires that "rtx" is in your PATH. If it is not, you need to +/// However, this requires that "mise" is in your PATH. If it is not, you need to /// specify the full path like this: /// -/// echo 'eval "$(/path/to/rtx activate)"' >> ~/.zshrc +/// echo 'eval "$(/path/to/mise activate)"' >> ~/.zshrc #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Activate { @@ -35,7 +35,7 @@ pub struct Activate { #[clap()] shell_type: Option, - /// Show "rtx: @" message when changing directories + /// Show "mise: @" message when changing directories #[clap(long)] status: bool, @@ -47,16 +47,16 @@ pub struct Activate { impl Activate { pub fn run(self) -> Result<()> { let shell = get_shell(self.shell_type.or(self.shell)) - .expect("no shell provided. Run `rtx activate zsh` or similar"); + .expect("no shell provided. Run `mise activate zsh` or similar"); // touch ROOT to allow hook-env to run let _ = touch_dir(&dirs::DATA); - let rtx_bin = if cfg!(target_os = "linux") { + let mise_bin = if cfg!(target_os = "linux") { // linux dereferences symlinks, so use argv0 instead PathBuf::from(&*env::ARGV0) } else { - env::RTX_BIN.clone() + env::MISE_BIN.clone() }; let mut flags = vec![]; if self.quiet { @@ -65,8 +65,8 @@ impl Activate { if self.status { flags.push(" --status"); } - let output = shell.activate(&rtx_bin, flags.join("")); - rtxprint!("{output}"); + let output = shell.activate(&mise_bin, flags.join("")); + miseprint!("{output}"); Ok(()) } @@ -74,9 +74,9 @@ impl Activate { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ eval "$(rtx activate bash)" - $ eval "$(rtx activate zsh)" - $ rtx activate fish | source - $ execx($(rtx activate xonsh)) + $ eval "$(mise activate bash)" + $ eval "$(mise activate zsh)" + $ mise activate fish | source + $ execx($(mise activate xonsh)) "# ); diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 7f54d0f45..c409fc748 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -4,7 +4,7 @@ use crate::config::Config; /// Show an alias for a plugin /// -/// This is the contents of an alias. entry in ~/.config/rtx/config.toml +/// This is the contents of an alias. entry in ~/.config/mise/config.toml /// #[derive(Debug, clap::Args)] #[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] @@ -20,7 +20,7 @@ impl AliasGet { let config = Config::try_get()?; match config.get_all_aliases().get(&self.plugin) { Some(plugin) => match plugin.get(&self.alias) { - Some(alias) => Ok(rtxprintln!("{}", alias)), + Some(alias) => Ok(miseprintln!("{}", alias)), None => Err(eyre!("Unknown alias: {}", &self.alias)), }, None => Err(eyre!("Unknown plugin: {}", &self.plugin)), @@ -30,7 +30,7 @@ impl AliasGet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias get node lts-hydrogen + $ mise alias get node lts-hydrogen 20.0.0 "# ); diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 9367896d5..82d66efde 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -9,7 +9,7 @@ use crate::ui::table; /// Shows the aliases that can be specified. /// These can come from user config or from plugins in `bin/list-aliases`. /// -/// For user config, aliases are defined like the following in `~/.config/rtx/config.toml`: +/// For user config, aliases are defined like the following in `~/.config/mise/config.toml`: /// /// [alias.node] /// lts = "20.0.0" @@ -45,7 +45,7 @@ impl AliasLs { .collect::>(); let mut table = tabled::Table::new(rows); table::default_style(&mut table, self.no_header); - rtxprintln!("{table}"); + miseprintln!("{table}"); Ok(()) } } @@ -59,7 +59,7 @@ struct Row { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx aliases + $ mise aliases node lts-hydrogen 20.0.0 "# ); diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index bd73ac665..4117105ac 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -5,7 +5,7 @@ use crate::config::Config; /// Add/update an alias for a plugin /// -/// This modifies the contents of ~/.config/rtx/config.toml +/// This modifies the contents of ~/.config/mise/config.toml #[derive(Debug, clap::Args)] #[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasSet { @@ -27,7 +27,7 @@ impl AliasSet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias set node lts-hydrogen 18.0.0 + $ mise alias set node lts-hydrogen 18.0.0 "# ); diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 6e124d22b..f75bc86fc 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -5,7 +5,7 @@ use crate::config::Config; /// Clears an alias for a plugin /// -/// This modifies the contents of ~/.config/rtx/config.toml +/// This modifies the contents of ~/.config/mise/config.toml #[derive(Debug, clap::Args)] #[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasUnset { @@ -25,7 +25,7 @@ impl AliasUnset { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx alias unset node lts-hydrogen + $ mise alias unset node lts-hydrogen "# ); diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index 43202833d..6a930fc7a 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -33,9 +33,9 @@ impl ToolArg { } /// this handles the case where the user typed in: - /// rtx local node 20.0.0 + /// mise local node 20.0.0 /// instead of - /// rtx local node@20.0.0 + /// mise local node@20.0.0 /// /// We can detect this, and we know what they meant, so make it work the way /// they expected. diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 1a90d7902..2a26f1d89 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -21,7 +21,7 @@ pub struct Asdf { impl Asdf { pub fn run(mut self) -> Result<()> { let config = Config::try_get()?; - let mut args = vec![String::from("rtx")]; + let mut args = vec![String::from("mise")]; args.append(&mut self.args); match args.get(1).map(|s| s.as_str()) { @@ -57,16 +57,16 @@ fn list_versions(config: &Config, args: &[String]) -> Result<()> { if let Some(plugin) = plugin { versions.retain(|(_, v)| v.plugin_name.as_str() == plugin); for (_, version) in versions { - rtxprintln!("{}", version.version); + miseprintln!("{}", version.version); } } else { for (plugin, versions) in &versions .into_iter() .group_by(|(_, v)| v.plugin_name.to_string()) { - rtxprintln!("{}", plugin); + miseprintln!("{}", plugin); for (_, tv) in versions { - rtxprintln!(" {}", tv.version); + miseprintln!(" {}", tv.version); } } } diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index fc2b4aaca..bf0685e57 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -15,7 +15,7 @@ impl BinPaths { let ts = ToolsetBuilder::new().build(&config)?; ts.notify_if_versions_missing(); for p in ts.list_paths() { - rtxprintln!("{}", p.display()); + miseprintln!("{}", p.display()); } Ok(()) } diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index 107a004e9..a7df5cc86 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -3,7 +3,7 @@ use eyre::Result; use crate::dirs::CACHE; use crate::file::{display_path, remove_all}; -/// Deletes all cache files in rtx +/// Deletes all cache files in mise #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "c", alias = "clean")] pub struct CacheClear { @@ -38,14 +38,14 @@ mod tests { #[test] fn test_cache_clear() { assert_cli_snapshot!("cache", "clear", @r###" - rtx cache cleared + mise cache cleared "###); } #[test] fn test_cache_clear_plugin() { assert_cli_snapshot!("cache", "clear", "tiny", @r###" - rtx cache cleared for tiny + mise cache cleared for tiny "###); } } diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 07d9b810c..7968c7683 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -5,9 +5,9 @@ use crate::env; mod clear; -/// Manage the rtx cache +/// Manage the mise cache /// -/// Run `rtx cache` with no args to view the current cache directory. +/// Run `mise cache` with no args to view the current cache directory. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment)] pub struct Cache { @@ -34,7 +34,7 @@ impl Cache { Some(cmd) => cmd.run(), None => { // just show the cache dir - rtxprintln!("{}", env::RTX_CACHE_DIR.display()); + miseprintln!("{}", env::MISE_CACHE_DIR.display()); Ok(()) } } @@ -50,6 +50,6 @@ mod tests { #[test] fn test_cache() { let stdout = assert_cli!("cache"); - assert_str_eq!(stdout.trim(), env::RTX_CACHE_DIR.display().to_string()); + assert_str_eq!(stdout.trim(), env::MISE_CACHE_DIR.display().to_string()); } } diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 6cfc1fc49..841f08751 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -19,11 +19,11 @@ pub struct Completion { impl Completion { pub fn run(self) -> Result<()> { let c = match self.shell.or(self.shell_type).unwrap() { - Shell::Bash => include_str!("../../completions/rtx.bash"), - Shell::Fish => include_str!("../../completions/rtx.fish"), - Shell::Zsh => include_str!("../../completions/_rtx"), + Shell::Bash => include_str!("../../completions/mise.bash"), + Shell::Fish => include_str!("../../completions/mise.fish"), + Shell::Zsh => include_str!("../../completions/_mise"), }; - rtxprintln!("{}", c.trim()); + miseprintln!("{}", c.trim()); Ok(()) } @@ -31,9 +31,9 @@ impl Completion { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx completion bash > /etc/bash_completion.d/rtx - $ rtx completion zsh > /usr/local/share/zsh/site-functions/_rtx - $ rtx completion fish > ~/.config/fish/completions/rtx.fish + $ mise completion bash > /etc/bash_completion.d/mise + $ mise completion zsh > /usr/local/share/zsh/site-functions/_mise + $ mise completion fish > ~/.config/fish/completions/mise.fish "# ); diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index 9fdcd55d9..ba428b90c 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -6,7 +6,7 @@ use crate::file::display_path; use clap::ValueHint; use eyre::Result; -/// [experimental] Generate an .rtx.toml file +/// [experimental] Generate an .mise.toml file #[derive(Debug, clap::Args)] #[clap(visible_alias = "g", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct ConfigGenerate { @@ -21,14 +21,14 @@ impl ConfigGenerate { let settings = Settings::try_get()?; settings.ensure_experimental()?; let doc = r#" -# # rtx config files are hierarchical. rtx will find all of the config files +# # mise config files are hierarchical. mise will find all of the config files # # in all parent directories and merge them together. # # You might have a structure like: # -# * ~/work/project/.rtx.toml # a config file for a specific work project -# * ~/work/.rtx.toml # a config file for projects related to work -# * ~/.config/rtx/config.toml # the global config file -# * /etc/rtx/config.toml # the system config file +# * ~/work/project/.mise.toml # a config file for a specific work project +# * ~/work/.mise.toml # a config file for projects related to work +# * ~/.config/mise/config.toml # the global config file +# * /etc/mise/config.toml # the system config file # # # This setup allows you to define default versions and configuration across # # all projects but override them for specific projects. @@ -53,7 +53,7 @@ impl ConfigGenerate { # terraform = '1.0.0' # specify a single version # erlang = '26' # specify a major version only # node = 'ref:master' # build from a git ref -# node = 'path:~/.nodes/14' # BYO – specify a non-rtx managed installation +# node = 'path:~/.nodes/14' # BYO – specify a non-mise managed installation # # # newest with this prefix (typically exact matches don't use the prefix) # go = 'prefix:1.16' @@ -64,18 +64,18 @@ impl ConfigGenerate { # python = ['3.12', '3.11', '3.10'] # # # some plugins can take options like python's virtualenv activation -# # with these, rtx will automatically setup and activate vevs when entering +# # with these, mise will automatically setup and activate vevs when entering # # the project directory # python = {version='3.12', virtualenv='.venv'} # poetry = {version='1.7.1', pyproject='pyproject.toml'} # # [plugins] -# # specify a custom repo url so you can install with `rtx plugin add ` +# # specify a custom repo url so you can install with `mise plugin add ` # # note this will only be used if the plugin is not already installed # python = 'https://github.com/asdf-community/asdf-python' # # [alias.node] -# # setup a custom alias so you can run `rtx use -g node@work` for node-16.x +# # setup a custom alias so you can run `mise use -g node@work` for node-16.x # work = '16' "# .trim(); @@ -83,7 +83,7 @@ impl ConfigGenerate { info!("writing to {}", display_path(output)); file::write(output, doc)?; } else { - rtxprintln!("{doc}"); + miseprintln!("{doc}"); } Ok(()) @@ -93,8 +93,8 @@ impl ConfigGenerate { // TODO: fill this out static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx cf generate > .rtx.toml - $ rtx cf generate --output=.rtx.toml + $ mise cf generate > .mise.toml + $ mise cf generate --output=.mise.toml "# ); diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index fdadaa3a8..c5f75e6db 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -33,7 +33,7 @@ impl ConfigLs { let mut table = tabled::Table::new(rows); table::default_style(&mut table, self.no_header); table.with(Modify::new(Columns::last()).with(Width::truncate(40).suffix("…"))); - rtxprintln!("{table}"); + miseprintln!("{table}"); Ok(()) } @@ -66,7 +66,7 @@ impl From<&dyn ConfigFile> for Row { // TODO: fill this out static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx config ls + $ mise config ls "# ); diff --git a/src/cli/config/snapshots/rtx__cli__config__generate__tests__generate.snap b/src/cli/config/snapshots/mise__cli__config__generate__tests__generate.snap similarity index 70% rename from src/cli/config/snapshots/rtx__cli__config__generate__tests__generate.snap rename to src/cli/config/snapshots/mise__cli__config__generate__tests__generate.snap index c3811157c..e76e173c3 100644 --- a/src/cli/config/snapshots/rtx__cli__config__generate__tests__generate.snap +++ b/src/cli/config/snapshots/mise__cli__config__generate__tests__generate.snap @@ -2,14 +2,14 @@ source: src/cli/config/generate.rs expression: output --- -# # rtx config files are hierarchical. rtx will find all of the config files +# # mise config files are hierarchical. mise will find all of the config files # # in all parent directories and merge them together. # # You might have a structure like: # -# * ~/work/project/.rtx.toml # a config file for a specific work project -# * ~/work/.rtx.toml # a config file for projects related to work -# * ~/.config/rtx/config.toml # the global config file -# * /etc/rtx/config.toml # the system config file +# * ~/work/project/.mise.toml # a config file for a specific work project +# * ~/work/.mise.toml # a config file for projects related to work +# * ~/.config/mise/config.toml # the global config file +# * /etc/mise/config.toml # the system config file # # # This setup allows you to define default versions and configuration across # # all projects but override them for specific projects. @@ -34,7 +34,7 @@ expression: output # terraform = '1.0.0' # specify a single version # erlang = '26' # specify a major version only # node = 'ref:master' # build from a git ref -# node = 'path:~/.nodes/14' # BYO – specify a non-rtx managed installation +# node = 'path:~/.nodes/14' # BYO – specify a non-mise managed installation # # # newest with this prefix (typically exact matches don't use the prefix) # go = 'prefix:1.16' @@ -45,16 +45,16 @@ expression: output # python = ['3.12', '3.11', '3.10'] # # # some plugins can take options like python's virtualenv activation -# # with these, rtx will automatically setup and activate vevs when entering +# # with these, mise will automatically setup and activate vevs when entering # # the project directory # python = {version='3.12', virtualenv='.venv'} # poetry = {version='1.7.1', pyproject='pyproject.toml'} # # [plugins] -# # specify a custom repo url so you can install with `rtx plugin add ` +# # specify a custom repo url so you can install with `mise plugin add ` # # note this will only be used if the plugin is not already installed # python = 'https://github.com/asdf-community/asdf-python' # # [alias.node] -# # setup a custom alias so you can run `rtx use -g node@work` for node-16.x +# # setup a custom alias so you can run `mise use -g node@work` for node-16.x # work = '16' diff --git a/src/cli/current.rs b/src/cli/current.rs index 65a2b1978..4dc4efab8 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -8,7 +8,7 @@ use crate::toolset::{Toolset, ToolsetBuilder}; /// Shows current active and installed runtime versions /// -/// This is similar to `rtx ls --current`, but this only shows the runtime +/// This is similar to `mise ls --current`, but this only shows the runtime /// and/or version. It's designed to fit into scripts more easily. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] @@ -47,7 +47,7 @@ impl Current { .find(|(p, _)| p.name() == tool.name()) { Some((_, versions)) => { - rtxprintln!( + miseprintln!( "{}", versions .iter() @@ -80,7 +80,7 @@ impl Current { ); } } - rtxprintln!( + miseprintln!( "{} {}", &plugin.name(), versions @@ -97,17 +97,17 @@ impl Current { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # outputs `.tool-versions` compatible format - $ rtx current + $ mise current python 3.11.0 3.10.0 shfmt 3.6.0 shellcheck 0.9.0 node 20.0.0 - $ rtx current node + $ mise current node 20.0.0 # can output multiple versions - $ rtx current python + $ mise current python 3.11.0 3.10.0 "# ); @@ -133,13 +133,13 @@ mod tests { fn test_current_missing() { assert_cli!("uninstall", "dummy@1.0.1"); - env::set_var("RTX_DUMMY_VERSION", "1.1.0"); + env::set_var("MISE_DUMMY_VERSION", "1.1.0"); assert_cli_snapshot!("current", @r###" dummy 1.1.0 tiny 3.1.0 - rtx dummy@1.1.0 is specified in RTX_DUMMY_VERSION=1.1.0, but not installed + mise dummy@1.1.0 is specified in MISE_DUMMY_VERSION=1.1.0, but not installed "###); - env::remove_var("RTX_DUMMY_VERSION"); + env::remove_var("MISE_DUMMY_VERSION"); } } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index a5cbc621a..6cc0029a0 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -5,9 +5,9 @@ use crate::hook_env; use crate::shell::get_shell; use crate::ui::style; -/// Disable rtx for current shell session +/// Disable mise for current shell session /// -/// This can be used to temporarily disable rtx in a shell session. +/// This can be used to temporarily disable mise in a shell session. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Deactivate {} @@ -21,9 +21,9 @@ impl Deactivate { let shell = get_shell(None).expect("no shell detected"); - rtxprint!("{}", hook_env::clear_old_env(&*shell)); + miseprint!("{}", hook_env::clear_old_env(&*shell)); let output = shell.deactivate(); - rtxprint!("{output}"); + miseprint!("{output}"); Ok(()) } @@ -32,19 +32,19 @@ impl Deactivate { fn err_inactive() -> Result<()> { Err(eyre!(formatdoc!( r#" - rtx is not activated in this shell session. + mise is not activated in this shell session. Please run `{}` first in your shell rc file. "#, - style::eyellow("rtx activate") + style::eyellow("mise activate") ))) } static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx deactivate bash - $ rtx deactivate zsh - $ rtx deactivate fish - $ execx($(rtx deactivate xonsh)) + $ mise deactivate bash + $ mise deactivate zsh + $ mise deactivate fish + $ execx($(mise deactivate xonsh)) "# ); @@ -56,10 +56,10 @@ mod tests { fn test_deactivate() { let err = assert_cli_err!("deactivate"); assert_display_snapshot!(err); - env::set_var("__RTX_DIFF", ""); - env::set_var("RTX_SHELL", "zsh"); + env::set_var("__MISE_DIFF", ""); + env::set_var("MISE_SHELL", "zsh"); assert_cli_snapshot!("deactivate"); - env::remove_var("__RTX_DIFF"); - env::remove_var("RTX_SHELL"); + env::remove_var("__MISE_DIFF"); + env::remove_var("MISE_SHELL"); } } diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 8f6d4d42b..272b12837 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,8 +1,8 @@ use eyre::Result; -/// Output direnv function to use rtx inside direnv +/// Output direnv function to use mise inside direnv /// -/// See https://github.com/jdx/rtx#direnv for more information +/// See https://mise.jdx.dev/direnv.html for more information /// /// Because this generates the legacy files based on currently installed plugins, /// you should run this command after installing new plugins. Otherwise @@ -13,12 +13,12 @@ pub struct DirenvActivate {} impl DirenvActivate { pub fn run(self) -> Result<()> { - rtxprintln!( - // source_env "$(rtx direnv envrc "$@")" + miseprintln!( + // source_env "$(mise direnv envrc "$@")" indoc! {r#" - ### Do not edit. This was autogenerated by 'rtx direnv' ### - use_rtx() {{ - direnv_load rtx direnv exec + ### Do not edit. This was autogenerated by 'mise direnv' ### + use_mise() {{ + direnv_load mise direnv exec }} "#} ); @@ -29,8 +29,8 @@ impl DirenvActivate { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx direnv activate > ~/.config/direnv/lib/use_rtx.sh - $ echo 'use rtx' > .envrc + $ mise direnv activate > ~/.config/direnv/lib/use_mise.sh + $ echo 'use mise' > .envrc $ direnv allow "# ); diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index fafa3c85f..db97309fd 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -19,7 +19,7 @@ impl Envrc { pub fn run(self, config: &Config) -> Result<()> { let ts = ToolsetBuilder::new().build(config)?; - let envrc_path = env::RTX_TMP_DIR + let envrc_path = env::MISE_TMP_DIR .join("direnv") .join(hash_to_str(&env::current_dir()?) + ".envrc"); @@ -50,7 +50,7 @@ impl Envrc { writeln!(file, "PATH_add {}", path.to_string_lossy())?; } - rtxprintln!("{}", envrc_path.to_string_lossy()); + miseprintln!("{}", envrc_path.to_string_lossy()); Ok(()) } } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index cba06b80c..7f0ca6f27 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -35,7 +35,7 @@ impl DirenvExec { let w: DirenvWatches = serde_json::from_str(&json)?; cmd = cmd.env("DIRENV_WATCHES", w.watches); - rtxprint!("{}", cmd.read()?); + miseprint!("{}", cmd.read()?); Ok(()) } } diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index 9ab2eaf4e..627781e07 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -7,9 +7,9 @@ mod activate; mod envrc; mod exec; -/// Output direnv function to use rtx inside direnv +/// Output direnv function to use mise inside direnv /// -/// See https://github.com/jdx/rtx#direnv for more information +/// See https://mise.rtx.dev/direnv.html for more information /// /// Because this generates the legacy files based on currently installed plugins, /// you should run this command after installing new plugins. Otherwise diff --git a/src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap b/src/cli/direnv/snapshots/mise__cli__direnv__envrc__tests__direnv_envrc.snap similarity index 100% rename from src/cli/direnv/snapshots/rtx__cli__direnv__envrc__tests__direnv_envrc.snap rename to src/cli/direnv/snapshots/mise__cli__direnv__envrc__tests__direnv_envrc.snap diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index b54fa5f3d..681184531 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -16,7 +16,7 @@ use crate::toolset::ToolsetBuilder; use crate::{cli, cmd, dirs}; use crate::{duration, env}; -/// Check rtx installation for possible problems. +/// Check mise installation for possible problems. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Doctor {} @@ -25,14 +25,14 @@ impl Doctor { pub fn run(self) -> Result<()> { let mut checks = Vec::new(); - rtxprintln!("{}", rtx_version()); - rtxprintln!("{}", build_info()); - rtxprintln!("{}", shell()); - rtxprintln!("{}", rtx_data_dir()); - rtxprintln!("{}", rtx_env_vars()); + miseprintln!("{}", mise_version()); + miseprintln!("{}", build_info()); + miseprintln!("{}", shell()); + miseprintln!("{}", mise_data_dir()); + miseprintln!("{}", mise_env_vars()); match Settings::try_get() { Ok(settings) => { - rtxprintln!( + miseprintln!( "{}\n{}\n", style("settings:").bold(), indent(settings.to_string()) @@ -42,8 +42,8 @@ impl Doctor { } match Config::try_get() { Ok(config) => { - rtxprintln!("{}", render_config_files(&config)); - rtxprintln!("{}", render_plugins(&config)); + miseprintln!("{}", render_config_files(&config)); + miseprintln!("{}", render_plugins(&config)); for plugin in config.list_plugins() { if !plugin.is_installed() { checks.push(format!("plugin {} is not installed", &plugin.name())); @@ -51,11 +51,11 @@ impl Doctor { } } if !config.is_activated() && !shims_on_path() { - let cmd = style("rtx help activate").yellow().for_stderr(); - let url = style("https://rtx.jdx.dev").underlined().for_stderr(); + let cmd = style("mise help activate").yellow().for_stderr(); + let url = style("https://mise.jdx.dev").underlined().for_stderr(); let shims = style(dirs::SHIMS.display()).cyan().for_stderr(); checks.push(formatdoc!( - r#"rtx is not activated, run {cmd} or + r#"mise is not activated, run {cmd} or read documentation at {url} for activation instructions. Alternatively, add the shims directory {shims} to PATH. Using the shims directory is preferred for non-interactive setups."# @@ -63,7 +63,7 @@ impl Doctor { } match ToolsetBuilder::new().build(&config) { Ok(ts) => { - rtxprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())) + miseprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())) } Err(err) => warn!("failed to load toolset: {}", err), } @@ -73,20 +73,20 @@ impl Doctor { if let Some(latest) = cli::version::check_for_new_version(duration::HOURLY) { checks.push(format!( - "new rtx version {} available, currently on {}", + "new mise version {} available, currently on {}", latest, env!("CARGO_PKG_VERSION") )); } if checks.is_empty() { - rtxprintln!("No problems found"); + miseprintln!("No problems found"); } else { let checks_plural = if checks.len() == 1 { "" } else { "s" }; let summary = format!("{} problem{checks_plural} found:", checks.len()); - rtxprintln!("{}", style(summary).red().bold()); + miseprintln!("{}", style(summary).red().bold()); for check in &checks { - rtxprintln!("{}\n", check); + miseprintln!("{}\n", check); } exit(1); } @@ -99,17 +99,17 @@ fn shims_on_path() -> bool { env::PATH.contains(&*dirs::SHIMS) } -fn rtx_data_dir() -> String { - let mut s = style("rtx data directory:\n").bold().to_string(); - s.push_str(&format!(" {}\n", env::RTX_DATA_DIR.to_string_lossy())); +fn mise_data_dir() -> String { + let mut s = style("mise data directory:\n").bold().to_string(); + s.push_str(&format!(" {}\n", env::MISE_DATA_DIR.to_string_lossy())); s } -fn rtx_env_vars() -> String { +fn mise_env_vars() -> String { let vars = env::vars() - .filter(|(k, _)| k.starts_with("RTX_")) + .filter(|(k, _)| k.starts_with("MISE_")) .collect::>(); - let mut s = style("rtx environment variables:\n").bold().to_string(); + let mut s = style("mise environment variables:\n").bold().to_string(); if vars.is_empty() { s.push_str(" (none)\n"); } @@ -157,8 +157,8 @@ fn render_plugins(config: &Config) -> String { s } -fn rtx_version() -> String { - let mut s = style("rtx version:\n").bold().to_string(); +fn mise_version() -> String { + let mut s = style("mise version:\n").bold().to_string(); s.push_str(&format!(" {}\n", *VERSION)); s } @@ -201,7 +201,7 @@ fn indent(s: String) -> String { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx doctor + $ mise doctor [WARN] plugin node is not installed "# ); diff --git a/src/cli/env.rs b/src/cli/env.rs index 6637c645b..e83de68f3 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -6,10 +6,10 @@ use crate::config::Config; use crate::shell::{get_shell, ShellType}; use crate::toolset::{InstallOptions, Toolset, ToolsetBuilder}; -/// Exports env vars to activate rtx a single time +/// Exports env vars to activate mise a single time /// -/// Use this if you don't want to permanently install rtx. It's not necessary to -/// use this if you have `rtx activate` in your shell rc file. +/// Use this if you don't want to permanently install mise. It's not necessary to +/// use this if you have `mise activate` in your shell rc file. #[derive(Debug, clap::Args)] #[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Env { @@ -42,7 +42,7 @@ impl Env { fn output_json(&self, config: &Config, ts: Toolset) -> Result<()> { let env = ts.env_with_path(config); - rtxprintln!("{}", serde_json::to_string_pretty(&env)?); + miseprintln!("{}", serde_json::to_string_pretty(&env)?); Ok(()) } @@ -52,7 +52,7 @@ impl Env { for (k, v) in ts.env_with_path(config) { let k = k.to_string(); let v = v.to_string(); - rtxprint!("{}", shell.set_env(&k, &v)); + miseprint!("{}", shell.set_env(&k, &v)); } Ok(()) } @@ -60,10 +60,10 @@ impl Env { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ eval "$(rtx env -s bash)" - $ eval "$(rtx env -s zsh)" - $ rtx env -s fish | source - $ execx($(rtx env -s xonsh)) + $ eval "$(mise env -s bash)" + $ eval "$(mise env -s zsh)" + $ mise env -s fish | source + $ execx($(mise env -s xonsh)) "# ); diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index b326d7e0f..562eee121 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -1,24 +1,24 @@ use color_eyre::Result; -use crate::config::config_file::rtx_toml::RtxToml; +use crate::config::config_file::mise_toml::MiseToml; use crate::config::config_file::ConfigFile; use crate::config::Config; use crate::env; -use crate::env::RTX_DEFAULT_CONFIG_FILENAME; +use crate::env::MISE_DEFAULT_CONFIG_FILENAME; use crate::file::display_path; use super::args::env_var::{EnvVarArg, EnvVarArgParser}; /// Manage environment variables /// -/// By default this command modifies ".rtx.toml" in the current directory. -/// You can specify the file name by either setting the RTX_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. +/// By default this command modifies ".mise.toml" in the current directory. +/// You can specify the file name by either setting the MISE_DEFAULT_CONFIG_FILENAME environment variable, or by using the --file option. #[derive(Debug, clap::Args)] #[clap(visible_alias = "ev", verbatim_doc_comment)] pub struct EnvVars { /// The TOML file to update /// - /// Defaults to RTX_DEFAULT_CONFIG_FILENAME environment variable, or ".rtx.toml". + /// Defaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or ".mise.toml". #[clap(long, verbatim_doc_comment, required = false, value_hint = clap::ValueHint::FilePath)] file: Option, @@ -40,41 +40,41 @@ impl EnvVars { if self.remove.is_none() && self.env_vars.is_none() { for (key, value) in &config.env { let source = config.env_sources.get(key).unwrap(); - rtxprintln!("{key}={value} {}", display_path(source)); + miseprintln!("{key}={value} {}", display_path(source)); } return Ok(()); } let filename = self .file - .unwrap_or_else(|| RTX_DEFAULT_CONFIG_FILENAME.to_string()); + .unwrap_or_else(|| MISE_DEFAULT_CONFIG_FILENAME.to_string()); - let mut rtx_toml = get_rtx_toml(filename.as_str())?; + let mut mise_toml = get_mise_toml(filename.as_str())?; if let Some(env_names) = &self.remove { for name in env_names { - rtx_toml.remove_env(name); + mise_toml.remove_env(name); } } if let Some(env_vars) = self.env_vars { for ev in env_vars { - rtx_toml.update_env(&ev.key, ev.value); + mise_toml.update_env(&ev.key, ev.value); } } - rtx_toml.save() + mise_toml.save() } } -fn get_rtx_toml(filename: &str) -> Result { +fn get_mise_toml(filename: &str) -> Result { let path = env::current_dir()?.join(filename); - let rtx_toml = if path.exists() { - RtxToml::from_file(&path)? + let mise_toml = if path.exists() { + MiseToml::from_file(&path)? } else { - RtxToml::init(&path) + MiseToml::init(&path) }; - Ok(rtx_toml) + Ok(mise_toml) } #[cfg(test)] @@ -96,14 +96,14 @@ mod tests { #[test] fn test_env_vars() { // Using the default file - let filename = ".test.rtx.toml"; + let filename = ".test.mise.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "FOO=bar"); assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); // Using a custom file - let filename = ".test-custom.rtx.toml"; + let filename = ".test-custom.mise.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "--file", filename, "FOO=bar"); assert_snapshot!(file::read_to_string(cf_path).unwrap()); @@ -113,7 +113,7 @@ mod tests { #[test] fn test_env_vars_remove() { // Using the default file - let filename = ".test.rtx.toml"; + let filename = ".test.mise.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "BAZ=quux"); assert_cli!("env-vars", "--remove", "BAZ"); @@ -121,7 +121,7 @@ mod tests { remove_config_file(filename); // Using a custom file - let filename = ".test-custom.rtx.toml"; + let filename = ".test-custom.mise.toml"; let cf_path = remove_config_file(filename); assert_cli!("env-vars", "--file", filename, "BAZ=quux"); assert_cli!("env-vars", "--file", filename, "--remove", "BAZ"); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 8b1ece6e9..4ae9def97 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -15,11 +15,11 @@ use crate::toolset::{InstallOptions, ToolsetBuilder}; /// Execute a command with tool(s) set /// -/// use this to avoid modifying the shell session or running ad-hoc commands with rtx tools set. +/// use this to avoid modifying the shell session or running ad-hoc commands with mise tools set. /// -/// Tools will be loaded from .rtx.toml/.tool-versions, though they can be overridden with args +/// Tools will be loaded from .mise.toml/.tool-versions, though they can be overridden with args /// Note that only the plugin specified will be overridden, so if a `.tool-versions` file -/// includes "node 20" but you run `rtx exec python@3.11`; it will still load node@20. +/// includes "node 20" but you run `mise exec python@3.11`; it will still load node@20. /// /// The "--" separates runtimes from the commands to pass along to the subprocess. #[derive(Debug, clap::Args)] @@ -40,7 +40,7 @@ pub struct Exec { /// Number of jobs to run in parallel /// [default: 4] - #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + #[clap(long, short, env = "MISE_JOBS", verbatim_doc_comment)] pub jobs: Option, /// Directly pipe stdin/stdout/stderr from plugin to user @@ -123,14 +123,14 @@ fn parse_command( static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx exec node@20 -- node ./app.js # launch app.js using node-20.x - $ rtx x node@20 -- node ./app.js # shorter alias + $ mise exec node@20 -- node ./app.js # launch app.js using node-20.x + $ mise x node@20 -- node ./app.js # shorter alias # Specify command as a string: - $ rtx exec node@20 python@3.11 --command "node -v && python -V" + $ mise exec node@20 python@3.11 --command "node -v && python -V" # Run a command in a different directory: - $ rtx x -C /path/to/project node@20 -- node ./app.js + $ mise x -C /path/to/project node@20 -- node ./app.js "# ); diff --git a/src/cli/global.rs b/src/cli/global.rs index 6ee2316c5..cd20bfa5c 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -11,12 +11,12 @@ use crate::{dirs, env}; /// Sets/gets the global tool version(s) /// /// Displays the contents of ~/.tool-versions after writing. -/// The file is `$HOME/.tool-versions` by default. It can be changed with `$RTX_CONFIG_FILE`. -/// If `$RTX_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.rtx.toml`. +/// The file is `$HOME/.tool-versions` by default. It can be changed with `$MISE_CONFIG_FILE`. +/// If `$MISE_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.mise.toml`. /// Otherwise, it will be parsed as a `.tool-versions` file. -/// A future v2 release of rtx will default to using `~/.config/rtx/config.toml` instead. +/// A future v2 release of mise will default to using `~/.config/mise/config.toml` instead. /// -/// Use `rtx local` to set a tool version locally in the current directory. +/// Use `mise local` to set a tool version locally in the current directory. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, hide = true, alias = "g", after_long_help = AFTER_LONG_HELP)] pub struct Global { @@ -28,13 +28,13 @@ pub struct Global { tool: Vec, /// Save exact version to `~/.tool-versions` - /// e.g.: `rtx global --pin node@20` will save `node 20.0.0` to ~/.tool-versions + /// e.g.: `mise global --pin node@20` will save `node 20.0.0` to ~/.tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `~/.tool-versions` - /// e.g.: `rtx global --fuzzy node@20` will save `node 20` to ~/.tool-versions - /// this is the default behavior unless RTX_ASDF_COMPAT=1 + /// e.g.: `mise global --fuzzy node@20` will save `node 20` to ~/.tool-versions + /// this is the default behavior unless MISE_ASDF_COMPAT=1 #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, @@ -63,11 +63,11 @@ impl Global { } fn global_file() -> PathBuf { - env::RTX_CONFIG_FILE.clone().unwrap_or_else(|| { - if *env::RTX_USE_TOML { + env::MISE_CONFIG_FILE.clone().unwrap_or_else(|| { + if *env::MISE_USE_TOML { dirs::CONFIG.join("config.toml") } else { - dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) + dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) } }) } @@ -76,14 +76,14 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # set the current version of node to 20.x # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx global --fuzzy node@20 + $ mise global --fuzzy node@20 # set the current version of node to 20.x # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx global --pin node@20 + $ mise global --pin node@20 # show the current version of node in ~/.tool-versions - $ rtx global node + $ mise global node 20.0.0 "# ); diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 0fd84e332..6d59c12ff 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -10,7 +10,7 @@ use crate::config::Config; use crate::config::Settings; use crate::direnv::DirenvDiff; -use crate::env::{TERM_WIDTH, __RTX_DIFF}; +use crate::env::{TERM_WIDTH, __MISE_DIFF}; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::shell::{get_shell, ShellType}; @@ -25,7 +25,7 @@ pub struct HookEnv { #[clap(long, short)] shell: Option, - /// Show "rtx: @" message when changing directories + /// Show "mise: @" message when changing directories #[clap(long)] status: bool, @@ -47,7 +47,7 @@ impl HookEnv { } let ts = ToolsetBuilder::new().build(&config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); - rtxprint!("{}", hook_env::clear_old_env(&*shell)); + miseprint!("{}", hook_env::clear_old_env(&*shell)); let mut env = ts.env(&config); let env_path = env.remove("PATH"); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); @@ -58,15 +58,15 @@ impl HookEnv { paths.extend(split_paths(&p).collect_vec()); } paths.extend(ts.list_paths()); // load the active runtime paths - diff.path = paths.clone(); // update __RTX_DIFF with the new paths for the next run + diff.path = paths.clone(); // update __MISE_DIFF with the new paths for the next run let settings = Settings::try_get()?; - patches.extend(self.build_path_operations(&settings, &paths, &__RTX_DIFF.path)?); + patches.extend(self.build_path_operations(&settings, &paths, &__MISE_DIFF.path)?); patches.push(self.build_diff_operation(&diff)?); patches.push(self.build_watch_operation(&watch_files)?); let output = hook_env::build_env_commands(&*shell, &patches); - rtxprint!("{output}"); + miseprint!("{output}"); if self.status { self.display_status(&config, &ts); ts.notify_if_versions_missing(); @@ -101,7 +101,7 @@ impl HookEnv { to_remove: &Vec, ) -> Result> { let full = join_paths(&*env::PATH)?.to_string_lossy().to_string(); - let (pre, post) = match &*env::__RTX_ORIG_PATH { + let (pre, post) = match &*env::__MISE_ORIG_PATH { Some(orig_path) => match full.split_once(&format!(":{orig_path}")) { Some((pre, post)) if settings.experimental => { (pre.to_string(), (orig_path.to_string() + post)) @@ -158,7 +158,7 @@ impl HookEnv { fn build_diff_operation(&self, diff: &EnvDiff) -> Result { Ok(EnvDiffOperation::Add( - "__RTX_DIFF".into(), + "__MISE_DIFF".into(), diff.serialize()?, )) } @@ -166,7 +166,7 @@ impl HookEnv { fn build_watch_operation(&self, watch_files: &[PathBuf]) -> Result { let watches = hook_env::build_watches(watch_files)?; Ok(EnvDiffOperation::Add( - "__RTX_WATCH".into(), + "__MISE_WATCH".into(), hook_env::serialize_watches(&watches)?, )) } diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 0f5b60064..8dcbba082 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -8,7 +8,7 @@ use crate::file::remove_all; use crate::ui::prompt; use crate::{dirs, env, file}; -/// Removes rtx CLI and all related data +/// Removes mise CLI and all related data /// /// Skips config directory by default. #[derive(Debug, clap::Args)] @@ -25,13 +25,13 @@ pub struct Implode { impl Implode { pub fn run(self) -> Result<()> { - let mut files = vec![*dirs::STATE, *dirs::DATA, *dirs::CACHE, &*env::RTX_BIN]; + let mut files = vec![*dirs::STATE, *dirs::DATA, *dirs::CACHE, &*env::MISE_BIN]; if self.config { files.push(&dirs::CONFIG); } for f in files.into_iter().filter(|d| d.exists()) { if self.dry_run { - rtxprintln!("rm -rf {}", f.display()); + miseprintln!("rm -rf {}", f.display()); } if self.confirm_remove(f)? { diff --git a/src/cli/install.rs b/src/cli/install.rs index a3d6a8ddc..dd35f4eca 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -10,12 +10,12 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Install a tool version /// -/// This will install a tool version to `~/.local/share/rtx/installs//` +/// This will install a tool version to `~/.local/share/mise/installs//` /// It won't be used simply by being installed, however. -/// For that, you must set up a `.rtx.toml`/`.tool-version` file manually or with `rtx use`. -/// Or you can call a tool version explicitly with `rtx exec @ -- `. +/// For that, you must set up a `.mise.toml`/`.tool-version` file manually or with `mise use`. +/// Or you can call a tool version explicitly with `mise exec @ -- `. /// -/// Tools will be installed in parallel. To disable, set `--jobs=1` or `RTX_JOBS=1` +/// Tools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1` #[derive(Debug, clap::Args)] #[clap(visible_alias = "i", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Install { @@ -30,7 +30,7 @@ pub struct Install { /// Number of jobs to run in parallel /// [default: 4] - #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + #[clap(long, short, env = "MISE_JOBS", verbatim_doc_comment)] jobs: Option, /// Directly pipe stdin/stdout/stderr from plugin to user @@ -59,7 +59,7 @@ impl Install { 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 @`"); + warn!("specify a version with `mise install @`"); return Ok(()); } ts.install_versions(config, tool_versions, &mpr, &self.install_opts()) @@ -135,10 +135,10 @@ impl Install { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx install node@20.0.0 # install specific node version - $ rtx install node@20 # install fuzzy node version - $ rtx install node # install version specified in .tool-versions or .rtx.toml - $ rtx install # installs everything specified in .tool-versions or .rtx.toml + $ mise install node@20.0.0 # install specific node version + $ mise install node@20 # install fuzzy node version + $ mise install node # install version specified in .tool-versions or .mise.toml + $ mise install # installs everything specified in .tool-versions or .mise.toml "# ); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 838ffea4e..13c7755ac 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -47,7 +47,7 @@ impl Latest { plugin.latest_version(prefix)? }; if let Some(version) = latest_version { - rtxprintln!("{}", version); + miseprintln!("{}", version); } Ok(()) } @@ -55,10 +55,10 @@ impl Latest { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx latest node@20 # get the latest version of node 20 + $ mise latest node@20 # get the latest version of node 20 20.0.0 - $ rtx latest node # get the latest stable version of node + $ mise latest node # get the latest stable version of node 20.0.0 "# ); diff --git a/src/cli/link.rs b/src/cli/link.rs index 8fcfeadf8..c4db8ae4f 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -11,10 +11,10 @@ use crate::file::{make_symlink, remove_all}; use crate::{dirs, file}; -/// Symlinks a tool version into rtx +/// Symlinks a tool version into mise /// /// Use this for adding installs either custom compiled outside -/// rtx or built with a different tool. +/// mise or built with a different tool. #[derive(Debug, clap::Args)] #[clap(visible_alias = "ln", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Link { @@ -67,14 +67,14 @@ impl Link { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # build node-20.0.0 with node-build and link it into rtx + # build node-20.0.0 with node-build and link it into mise $ node-build 20.0.0 ~/.nodes/20.0.0 - $ rtx link node@20.0.0 ~/.nodes/20.0.0 + $ mise link node@20.0.0 ~/.nodes/20.0.0 - # have rtx use the python version provided by Homebrew + # have mise use the python version provided by Homebrew $ brew install node - $ rtx link node@brew $(brew --prefix node) - $ rtx use node@brew + $ mise link node@brew $(brew --prefix node) + $ mise use node@brew "# ); diff --git a/src/cli/local.rs b/src/cli/local.rs index 92a2e3f02..ea1a4a877 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -6,25 +6,25 @@ use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::{config_file, Config, Settings}; -use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; +use crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; use crate::plugins::PluginName; use crate::{env, file}; -/// Sets/gets tool version in local .tool-versions or .rtx.toml +/// Sets/gets tool version in local .tool-versions or .mise.toml /// /// Use this to set a tool's version when within a directory -/// Use `rtx global` to set a tool version globally -/// This uses `.tool-version` by default unless there is a `.rtx.toml` file or if `RTX_USE_TOML` -/// is set. A future v2 release of rtx will default to using `.rtx.toml`. +/// Use `mise global` to set a tool version globally +/// This uses `.tool-version` by default unless there is a `.mise.toml` file or if `MISE_USE_TOML` +/// is set. A future v2 release of mise will default to using `.mise.toml`. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, hide = true, alias = "l", after_long_help = AFTER_LONG_HELP)] pub struct Local { - /// Tool(s) to add to .tool-versions/.rtx.toml + /// Tool(s) to add to .tool-versions/.mise.toml /// e.g.: node@20 /// if this is a single tool with no version, - /// the current value of .tool-versions/.rtx.toml will be displayed + /// the current value of .tool-versions/.mise.toml will be displayed #[clap(value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] tool: Vec, @@ -34,13 +34,13 @@ pub struct Local { parent: bool, /// Save exact version to `.tool-versions` - /// e.g.: `rtx local --pin node@20` will save `node 20.0.0` to .tool-versions + /// e.g.: `mise local --pin node@20` will save `node 20.0.0` to .tool-versions #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, /// Save fuzzy version to `.tool-versions` - /// e.g.: `rtx local --fuzzy node@20` will save `node 20` to .tool-versions - /// This is the default behavior unless RTX_ASDF_COMPAT=1 + /// e.g.: `mise local --fuzzy node@20` will save `node 20` to .tool-versions + /// This is the default behavior unless MISE_ASDF_COMPAT=1 #[clap(long, overrides_with = "pin")] fuzzy: bool, @@ -74,18 +74,18 @@ impl Local { } fn get_path() -> Result { - let rtx_toml = env::current_dir()?.join(RTX_DEFAULT_CONFIG_FILENAME.as_str()); - if *env::RTX_USE_TOML || rtx_toml.exists() { - Ok(rtx_toml) + let mise_toml = env::current_dir()?.join(MISE_DEFAULT_CONFIG_FILENAME.as_str()); + if *env::MISE_USE_TOML || mise_toml.exists() { + Ok(mise_toml) } else { - Ok(env::current_dir()?.join(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str())) + Ok(env::current_dir()?.join(MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str())) } } pub fn get_parent_path() -> Result { - let mut filenames = vec![RTX_DEFAULT_CONFIG_FILENAME.as_str()]; - if !*env::RTX_USE_TOML { - filenames.push(RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); + let mut filenames = vec![MISE_DEFAULT_CONFIG_FILENAME.as_str()]; + if !*env::MISE_USE_TOML { + filenames.push(MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); } file::find_up(&env::current_dir()?, &filenames) .wrap_err_with(|| eyre!("no {} file found", filenames.join(" or "),)) @@ -104,7 +104,7 @@ pub fn local( let settings = Settings::try_get()?; let mut cf = config_file::parse_or_init(path)?; if show_path { - rtxprintln!("{}", path.display()); + miseprintln!("{}", path.display()); return Ok(()); } @@ -116,7 +116,7 @@ pub fn local( .iter() .map(|r| style(r).blue().for_stderr().to_string()) .join(" "); - rtxprintln!("{} {} {tools}", style("rtx").dim(), display_path(path)); + miseprintln!("{} {} {tools}", style("mise").dim(), display_path(path)); } if !runtime.is_empty() { @@ -127,13 +127,13 @@ pub fn local( let pin = pin || (settings.asdf_compat && !fuzzy); cf.add_runtimes(config, &runtimes, pin)?; let tools = runtimes.iter().map(|t| t.style()).join(" "); - rtxprintln!("{} {} {tools}", style("rtx").dim(), display_path(path)); + miseprintln!("{} {} {tools}", style("mise").dim(), display_path(path)); } if !runtime.is_empty() || remove.is_some() { cf.save()?; } else { - rtxprint!("{}", cf.dump()); + miseprint!("{}", cf.dump()); } Ok(()) @@ -143,20 +143,20 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # set the current version of node to 20.x for the current directory # will use a precise version (e.g.: 20.0.0) in .tool-versions file - $ rtx local node@20 + $ mise local node@20 # set node to 20.x for the current project (recurses up to find .tool-versions) - $ rtx local -p node@20 + $ mise local -p node@20 # set the current version of node to 20.x for the current directory # will use a fuzzy version (e.g.: 20) in .tool-versions file - $ rtx local --fuzzy node@20 + $ mise local --fuzzy node@20 # removes node from .tool-versions - $ rtx local --remove=node + $ mise local --remove=node # show the current version of node in .tool-versions - $ rtx local node + $ mise local node 20.0.0 "# ); @@ -312,7 +312,7 @@ mod tests { where T: FnOnce() + panic::UnwindSafe, { - let _ = file::remove_file(env::current_dir().unwrap().join(".test.rtx.toml")); + let _ = file::remove_file(env::current_dir().unwrap().join(".test.mise.toml")); let cf_path = env::current_dir().unwrap().join(".test-tool-versions"); let orig = file::read_to_string(&cf_path).unwrap(); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 756b8fe95..035732126 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -29,16 +29,16 @@ pub struct Ls { #[clap(long = "plugin", short, hide = true)] plugin_flag: Option, - /// Only show tool versions currently specified in a .tool-versions/.rtx.toml + /// Only show tool versions currently specified in a .tool-versions/.mise.toml #[clap(long, short)] current: bool, - /// Only show tool versions currently specified in a the global .tool-versions/.rtx.toml + /// Only show tool versions currently specified in a the global .tool-versions/.mise.toml #[clap(long, short)] global: bool, /// Only show tool versions that are installed - /// Hides missing ones defined in .tool-versions/.rtx.toml but not yet installed + /// Hides missing ones defined in .tool-versions/.mise.toml but not yet installed #[clap(long, short)] installed: bool, @@ -119,7 +119,7 @@ impl Ls { .filter(|(p, _, _)| plugins.contains(&p.name().to_string())) .map(|row| row.into()) .collect(); - rtxprintln!("{}", serde_json::to_string_pretty(&runtimes)?); + miseprintln!("{}", serde_json::to_string_pretty(&runtimes)?); return Ok(()); } @@ -131,7 +131,7 @@ impl Ls { let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); } - rtxprintln!("{}", serde_json::to_string_pretty(&plugins)?); + miseprintln!("{}", serde_json::to_string_pretty(&plugins)?); Ok(()) } @@ -145,9 +145,9 @@ impl Ls { .for_each(|(_, tv)| { if self.plugin.is_some() { // only displaying 1 plugin so only show the version - rtxprintln!("{}", tv.version); + miseprintln!("{}", tv.version); } else { - rtxprintln!("{} {}", tv.plugin_name, tv.version); + miseprintln!("{} {}", tv.plugin_name, tv.version); } }); Ok(()) @@ -169,7 +169,7 @@ impl Ls { }); let mut table = Table::new(rows); table::default_style(&mut table, self.no_header); - rtxprintln!("{}", table.to_string()); + miseprintln!("{}", table.to_string()); Ok(()) } @@ -343,24 +343,24 @@ impl Display for VersionStatus { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx ls + $ mise ls node 20.0.0 ~/src/myapp/.tool-versions latest python 3.11.0 ~/.tool-versions 3.10 python 3.10.0 - $ rtx ls --current + $ mise ls --current node 20.0.0 ~/src/myapp/.tool-versions 20 python 3.11.0 ~/.tool-versions 3.11.0 - $ rtx ls --json + $ mise ls --json { "node": [ { "version": "20.0.0", - "install_path": "/Users/jdx/.rtx/installs/node/20.0.0", + "install_path": "/Users/jdx/.mise/installs/node/20.0.0", "source": { - "type": ".rtx.toml", - "path": "/Users/jdx/.rtx.toml" + "type": ".mise.toml", + "path": "/Users/jdx/.mise.toml" } } ], @@ -435,13 +435,13 @@ mod tests { assert_cli_snapshot!("ls", "--parseable", @r###" dummy ref:master tiny 3.1.0 - rtx The parseable output format is deprecated and will be removed in a future release. - rtx Please use the regular output format instead which has been modified to be more easily parseable. + mise The parseable output format is deprecated and will be removed in a future release. + mise Please use the regular output format instead which has been modified to be more easily parseable. "###); assert_cli_snapshot!("ls", "--parseable", "tiny", @r###" 3.1.0 - rtx The parseable output format is deprecated and will be removed in a future release. - rtx Please use the regular output format instead which has been modified to be more easily parseable. + mise The parseable output format is deprecated and will be removed in a future release. + mise Please use the regular output format instead which has been modified to be more easily parseable. "###); } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index e558666d8..77e4f2701 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -15,7 +15,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// List runtime versions available for install /// /// note that the results are cached for 24 hours -/// run `rtx cache clean` to clear the cache and get fresh results +/// run `mise cache clean` to clear the cache and get fresh results #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = ["list-all", "list-remote"])] pub struct LsRemote { @@ -62,7 +62,7 @@ impl LsRemote { }; for version in versions { - rtxprintln!("{}", version); + miseprintln!("{}", version); } Ok(()) @@ -82,7 +82,7 @@ impl LsRemote { .collect::>(); for (plugin, versions) in versions { for v in versions { - rtxprintln!("{}@{v}", plugin); + miseprintln!("{}@{v}", plugin); } } Ok(()) @@ -103,15 +103,15 @@ impl LsRemote { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx ls-remote node + $ mise ls-remote node 18.0.0 20.0.0 - $ rtx ls-remote node@20 + $ mise ls-remote node@20 20.0.0 20.1.0 - $ rtx ls-remote node 20 + $ mise ls-remote node 20 20.0.0 20.1.0 "# diff --git a/src/cli/mod.rs b/src/cli/mod.rs index f1a9aafc7..a71c20b59 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -173,7 +173,7 @@ impl Commands { impl Cli { pub fn command() -> clap::Command { Commands::augment_subcommands( - clap::Command::new("rtx") + clap::Command::new("mise") .version(version::VERSION.to_string()) .about(env!("CARGO_PKG_DESCRIPTION")) .author("Jeff Dickey <@jdx>") @@ -220,7 +220,7 @@ impl Cli { } const LONG_ABOUT: &str = indoc! {" -rtx is a tool for managing runtime versions. https://github.com/jdx/rtx +mise is a tool for managing runtime versions. https://github.com/jdx/mise It's a replacement for tools like nvm, nodenv, rbenv, rvm, chruby, pyenv, etc. that works for any language. It's also great for managing linters/tools like @@ -231,15 +231,15 @@ https://asdf-vm.com/"}; static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx install node@20.0.0 Install a specific node version - $ rtx install node@20.0 Install a version matching a prefix - $ rtx install node Install the node version defined in - .tool-versions or .rtx.toml - $ rtx use node@20 Use node-20.x in current project - $ rtx use -g node@20 Use node-20.x as default - $ rtx use node@latest Use latest node in current directory - $ rtx use -g node@system Use system node everywhere unless overridden - $ rtx x node@20 -- node app.js Run `node app.js` with node-20.x on PATH + $ mise install node@20.0.0 Install a specific node version + $ mise install node@20.0 Install a version matching a prefix + $ mise install node Install the node version defined in + .tool-versions or .mise.toml + $ mise use node@20 Use node-20.x in current project + $ mise use -g node@20 Use node-20.x as default + $ mise use node@latest Use latest node in current directory + $ mise use -g node@system Use system node everywhere unless overridden + $ mise x node@20 -- node app.js Run `node app.js` with node-20.x on PATH "# ); diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 31f7766b0..9e04dba17 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -89,7 +89,7 @@ impl Outdated { let pad_plugin = |s| pad_str(s, plugin_width, Alignment::Left, None); let pad_requested = |s| pad_str(s, requested_width, Alignment::Left, None); let pad_current = |s| pad_str(s, current_width, Alignment::Left, None); - rtxprintln!( + miseprintln!( "{} {} {} {}", style(pad_plugin("Tool")).dim(), style(pad_requested("Requested")).dim(), @@ -97,7 +97,7 @@ impl Outdated { style("Latest").dim(), ); for i in 0..outdated.len() { - rtxprintln!( + miseprintln!( "{} {} {} {}", pad_plugin(plugins[i]), pad_requested(&requests[i]), @@ -112,12 +112,12 @@ type OutputVec = Vec<(Arc, ToolVersion, String)>; static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx outdated + $ mise outdated Plugin Requested Current Latest python 3.11 3.11.0 3.11.1 node 20 20.0.0 20.1.0 - $ rtx outdated node + $ mise outdated node Plugin Requested Current Latest node 20 20.0.0 20.1.0 "# diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index e7ef2f864..410f98d89 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -11,16 +11,16 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// Install a plugin /// -/// note that rtx automatically can install plugins when you install a tool -/// e.g.: `rtx install node@20` will autoinstall the node plugin +/// note that mise automatically can install plugins when you install a tool +/// e.g.: `mise install node@20` will autoinstall the node plugin /// -/// This behavior can be modified in ~/.config/rtx/config.toml +/// This behavior can be modified in ~/.config/mise/config.toml #[derive(Debug, clap::Args)] #[clap(visible_aliases = ["i", "a", "add"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct PluginsInstall { /// The name of the plugin to install /// e.g.: node, ruby - /// Can specify multiple plugins: `rtx plugins install node ruby python` + /// Can specify multiple plugins: `mise plugins install node ruby python` #[clap(required_unless_present = "all", verbatim_doc_comment)] new_plugin: Option, @@ -133,6 +133,7 @@ fn get_name_from_url(url: &str) -> Result { let last = segments.last().unwrap_or_default(); let name = last.strip_prefix("asdf-").unwrap_or(last); let name = name.strip_prefix("rtx-").unwrap_or(name); + let name = name.strip_prefix("mise-").unwrap_or(name); let name = name.strip_suffix(".git").unwrap_or(name); return Ok(unalias_plugin(name).to_string()); } @@ -143,17 +144,17 @@ fn get_name_from_url(url: &str) -> Result { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # install the node via shorthand - $ rtx plugins install node + $ mise plugins install node # install the node plugin using a specific git url - $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git # install the node plugin using the git url only # (node is inferred from the url) - $ rtx plugins install https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install https://github.com/rtx-plugins/rtx-nodejs.git # install the node plugin using a specific ref - $ rtx plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 + $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 "# ); diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index 10b11c78a..314b96e26 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -10,7 +10,7 @@ use crate::file::{make_symlink, remove_all}; use crate::plugins::unalias_plugin; use crate::{dirs, file}; -/// Symlinks a plugin into rtx +/// Symlinks a plugin into mise /// /// This is used for developing a plugin. #[derive(Debug, clap::Args)] @@ -22,7 +22,7 @@ pub struct PluginsLink { name: String, /// The local path to the plugin - /// e.g.: ./rtx-node + /// e.g.: ./mise-node #[clap(value_hint = ValueHint::DirPath, verbatim_doc_comment)] path: Option, @@ -64,16 +64,17 @@ 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); + let name = name.strip_prefix("mise-").unwrap_or(name); unalias_plugin(name).to_string() } static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # essentially just `ln -s ./rtx-node ~/.local/share/rtx/plugins/node` - $ rtx plugins link node ./rtx-node + # essentially just `ln -s ./mise-node ~/.local/share/mise/plugins/node` + $ mise plugins link node ./mise-node # infer plugin name as "node" - $ rtx plugins link ./rtx-node + $ mise plugins link ./mise-node "# ); diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 91cab0c5a..45179720d 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -17,7 +17,7 @@ use crate::plugins::{ExternalPlugin, PluginType}; #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct PluginsLs { /// List all available remote plugins - /// Same as `rtx plugins ls-remote` + /// Same as `mise plugins ls-remote` #[clap(short, long, hide = true, verbatim_doc_comment)] pub all: bool, @@ -84,10 +84,10 @@ impl PluginsLs { .with(Margin::new(0, 0, 0, 0)) .with(Modify::new(Columns::first()).with(Padding::new(0, 1, 0, 0))) .with(Modify::new(Columns::last()).with(Padding::zero())); - rtxprintln!("{table}"); + miseprintln!("{table}"); } else { for tool in tools { - rtxprintln!("{tool}"); + miseprintln!("{tool}"); } } Ok(()) @@ -105,11 +105,11 @@ struct Row { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx plugins ls + $ mise plugins ls node ruby - $ rtx plugins ls --urls + $ mise plugins ls --urls node https://github.com/asdf-vm/asdf-node.git ruby https://github.com/asdf-vm/asdf-ruby.git "# diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 6540c11ec..3b5643319 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -49,7 +49,7 @@ impl PluginsLsRemote { }; let url = if self.urls { repo } else { "" }; let plugin = pad_str(plugin, max_plugin_len, Alignment::Left, None); - rtxprintln!("{} {}{}", plugin, installed, url); + miseprintln!("{} {}{}", plugin, installed, url); } Ok(()) @@ -59,10 +59,10 @@ impl PluginsLsRemote { const LONG_ABOUT: &str = r#" List all available remote plugins -The full list is here: https://github.com/jdx/rtx/blob/main/src/default_shorthands.rs +The full list is here: https://github.com/jdx/mise/blob/main/src/default_shorthands.rs Examples: - $ rtx plugins ls-remote + $ mise plugins ls-remote "#; #[cfg(test)] diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 457c77f32..dd033f634 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -18,7 +18,7 @@ pub struct Plugins { /// list all available remote plugins /// - /// same as `rtx plugins ls-remote` + /// same as `mise plugins ls-remote` #[clap(short, long, hide = true)] pub all: bool, diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap b/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap similarity index 100% rename from src/cli/plugins/snapshots/rtx__cli__plugins__install__tests__plugin_install_invalid_url.snap rename to src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap b/src/cli/plugins/snapshots/mise__cli__plugins__ls__tests__plugin_list.snap similarity index 100% rename from src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list.snap rename to src/cli/plugins/snapshots/mise__cli__plugins__ls__tests__plugin_list.snap diff --git a/src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_all.snap b/src/cli/plugins/snapshots/mise__cli__plugins__ls__tests__plugin_list_all.snap similarity index 100% rename from src/cli/plugins/snapshots/rtx__cli__plugins__ls__tests__plugin_list_all.snap rename to src/cli/plugins/snapshots/mise__cli__plugins__ls__tests__plugin_list_all.snap diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 8360eb147..b4577c554 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -66,6 +66,6 @@ impl PluginsUninstall { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx uninstall node + $ mise uninstall node "# ); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index d2758b688..8d5e29fc8 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -64,9 +64,9 @@ impl Update { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx plugins update # update all plugins - $ rtx plugins update node # update only node - $ rtx plugins update node#beta # specify a ref + $ mise plugins update # update all plugins + $ mise plugins update node # update only node + $ mise plugins update node#beta # specify a ref "# ); diff --git a/src/cli/prune.rs b/src/cli/prune.rs index a6e0d7e2a..74785743a 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -13,10 +13,10 @@ use crate::ui::prompt; /// Delete unused versions of tools /// -/// rtx tracks which config files have been used in ~/.local/share/rtx/tracked_config_files +/// mise tracks which config files have been used in ~/.local/share/mise/tracked_config_files /// Versions which are no longer the latest specified in any of those configs are deleted. -/// Versions installed only with environment variables (`RTX__VERSION`) will be deleted, -/// as will versions only referenced on the command line (`rtx exec @`). +/// Versions installed only with environment variables (`MISE__VERSION`) will be deleted, +/// as will versions only referenced on the command line (`mise exec @`). #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Prune { @@ -74,9 +74,9 @@ impl Prune { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx prune --dry-run - rm -rf ~/.local/share/rtx/versions/node/20.0.0 - rm -rf ~/.local/share/rtx/versions/node/20.0.1 + $ mise prune --dry-run + rm -rf ~/.local/share/mise/versions/node/20.0.0 + rm -rf ~/.local/share/mise/versions/node/20.0.1 "# ); diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 9e9be5b9b..7e8eda49e 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -30,11 +30,11 @@ impl RenderCompletion { clap_complete::Shell::Fish => completions::fish_complete(&cmd)?, _ => { let mut c = Cursor::new(Vec::new()); - generate(shell, &mut cmd, "rtx", &mut c); + generate(shell, &mut cmd, "mise", &mut c); String::from_utf8(c.into_inner()).unwrap() } }; - rtxprintln!("{}", script.trim()); + miseprintln!("{}", script.trim()); Ok(()) } diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index e262f9061..53af6c33c 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -15,7 +15,7 @@ pub struct RenderHelp {} impl RenderHelp { pub fn run(self) -> Result<()> { let readme = file::read_to_string("docs/cli-reference.md")?; - let mut current_readme = readme.split(""); + let mut current_readme = readme.split(""); let mut doc = String::new(); doc.push_str(current_readme.next().unwrap()); @@ -36,7 +36,7 @@ fn render_commands() -> String { .disable_help_flag(true); let mut doc = formatdoc!( r#" - + ## Commands @@ -62,7 +62,7 @@ fn render_commands() -> String { } } } - doc.push_str(""); + doc.push_str(""); doc } @@ -95,7 +95,7 @@ fn render_command(parent: Option<&str>, c: &clap::Command) -> Option { .to_string(); Some(formatdoc!( " - ### `rtx {usage}` + ### `mise {usage}` {aliases} ```text {about} @@ -123,8 +123,8 @@ mod tests { file::write( "docs/cli-reference.md", indoc! {r#" - - + + "#}, ) .unwrap(); diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index 547df68a8..f9e197595 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -23,7 +23,7 @@ impl RenderMangen { let out_dir = project_root().join("man").join("man1"); fs::create_dir_all(&out_dir)?; - fs::write(out_dir.join("rtx.1"), buffer)?; + fs::write(out_dir.join("mise.1"), buffer)?; Ok(()) } @@ -45,8 +45,8 @@ mod tests { #[test] fn test_render_mangen() { let out_dir = HOME.parent().unwrap().join("man").join("man1"); - let orig = file::read_to_string(out_dir.join("rtx.1")).unwrap(); + let orig = file::read_to_string(out_dir.join("mise.1")).unwrap(); assert_cli!("render-mangen"); - file::write(out_dir.join("rtx.1"), orig).unwrap(); + file::write(out_dir.join("mise.1"), orig).unwrap(); } } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 3be229bcc..5ffd2542e 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -7,18 +7,18 @@ use crate::toolset::ToolsetBuilder; /// rebuilds the shim farm /// -/// This creates new shims in ~/.local/share/rtx/shims for CLIs that have been added. -/// rtx will try to do this automatically for commands like `npm i -g` but there are -/// other ways to install things (like using yarn or pnpm for node) that rtx does +/// This creates new shims in ~/.local/share/mise/shims for CLIs that have been added. +/// mise will try to do this automatically for commands like `npm i -g` but there are +/// other ways to install things (like using yarn or pnpm for node) that mise does /// not know about and so it will be necessary to call this explicitly. /// -/// If you think rtx should automatically call this for a particular command, please -/// open an issue on the rtx repo. You can also setup a shell function to reshim +/// If you think mise should automatically call this for a particular command, please +/// open an issue on the mise repo. You can also setup a shell function to reshim /// automatically (it's really fast so you don't need to worry about overhead): /// /// npm() { /// command npm "$@" -/// rtx reshim +/// mise reshim /// } #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] @@ -40,8 +40,8 @@ impl Reshim { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx reshim - $ ~/.local/share/rtx/shims/node -v + $ mise reshim + $ ~/.local/share/mise/shims/node -v v20.0.0 "# ); diff --git a/src/cli/run.rs b/src/cli/run.rs index a1e0d4bcc..a257d189b 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -37,8 +37,8 @@ use crate::{env, file, ui}; /// If source is configured on a task, it will only run if the source /// files have changed. /// -/// Tasks can be defined in .rtx.toml or as standalone scripts. -/// In .rtx.toml, tasks take this form: +/// Tasks can be defined in .mise.toml or as standalone scripts. +/// In .mise.toml, tasks take this form: /// /// [tasks.build] /// run = "npm run build" @@ -46,20 +46,20 @@ use crate::{env, file, ui}; /// outputs = ["dist/**/*.js"] /// /// Alternatively, tasks can be defined as standalone scripts. -/// These must be located in the `.rtx/tasks` directory. +/// These must be located in the `.mise/tasks` directory. /// The name of the script will be the name of the task. /// -/// $ cat .rtx/tasks/build< 1 - /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + /// Configure with `task_output` config or `MISE_TASK_OUTPUT` env var #[clap(long, short, verbatim_doc_comment, overrides_with = "interleave")] pub prefix: bool, /// Print directly to stdout/stderr instead of by line /// Defaults to true if --jobs == 1 - /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + /// Configure with `task_output` config or `MISE_TASK_OUTPUT` env var #[clap(long, short, verbatim_doc_comment, overrides_with = "prefix")] pub interleave: bool, @@ -98,12 +98,12 @@ pub struct Run { /// Number of tasks to run in parallel /// [default: 4] - /// Configure with `jobs` config or `RTX_JOBS` env var - #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + /// Configure with `jobs` config or `MISE_JOBS` env var + #[clap(long, short, env = "MISE_JOBS", verbatim_doc_comment)] pub jobs: Option, /// Read/write directly to stdin/stdout/stderr instead of by line - /// Configure with `raw` config or `RTX_RAW` env var + /// Configure with `raw` config or `MISE_RAW` env var #[clap(long, short, verbatim_doc_comment)] pub raw: bool, } @@ -145,7 +145,7 @@ impl Run { ts.notify_if_versions_missing(); let mut env = ts.env_with_path(config); if let Some(root) = &config.project_root { - env.insert("RTX_PROJECT_ROOT".into(), root.display().to_string()); + env.insert("MISE_PROJECT_ROOT".into(), root.display().to_string()); } let tasks = Mutex::new(Deps::new(config, tasks)?); @@ -221,7 +221,7 @@ impl Run { let cmd = style::ebold(format!("$ {script}")).bright().to_string(); info_unprefix_trunc!("{prefix} {cmd}"); - if env::var("RTX_TASK_SCRIPT_FILE").is_ok() { + if env::var("MISE_TASK_SCRIPT_FILE").is_ok() { let mut tmp = tempfile::NamedTempFile::new()?; let args = once(tmp.path().display().to_string()) .chain(args.iter().cloned()) @@ -394,21 +394,21 @@ impl Run { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx run lint - Runs the "lint" task. This needs to either be defined in .rtx.toml + $ mise run lint + Runs the "lint" task. This needs to either be defined in .mise.toml or as a standalone script. See the project README for more information. - $ rtx run build --force + $ mise run build --force Forces the "build" task to run even if its sources are up-to-date. - $ rtx run test --raw + $ mise run test --raw Runs "test" with stdin/stdout/stderr all connected to the current terminal. This forces `--jobs=1` to prevent interleaving of output. - $ rtx run lint ::: test ::: check + $ mise run lint ::: test ::: check Runs the "lint", "test", and "check" tasks in parallel. - $ rtx task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 Execute multiple tasks each with their own arguments. "# ); diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 4e63c3e55..fc684d237 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -8,7 +8,7 @@ use crate::cli::version::{ARCH, OS}; use crate::{cmd, env}; -/// Updates rtx itself +/// Updates mise itself /// /// Uses the GitHub Releases API to find the latest release and binary /// By default, this will also update any installed plugins @@ -34,18 +34,18 @@ pub struct SelfUpdate { impl SelfUpdate { pub fn run(self) -> Result<()> { if !Self::is_available() && !self.force { - bail!("rtx is installed via a package manager, cannot update"); + bail!("mise is installed via a package manager, cannot update"); } let status = self.do_update()?; if status.updated() { let version = style(status.version()).bright().yellow(); - rtxprintln!("Updated rtx to {version}"); + miseprintln!("Updated mise to {version}"); } else { - rtxprintln!("rtx is already up to date"); + miseprintln!("mise is already up to date"); } if !self.no_plugins { - cmd!(&*env::RTX_BIN, "plugins", "update").run()?; + cmd!(&*env::MISE_BIN, "plugins", "update").run()?; } Ok(()) @@ -58,7 +58,7 @@ impl SelfUpdate { } let releases = releases .repo_owner("jdx") - .repo_name("rtx") + .repo_name("mise") .build()? .fetch()?; Ok(releases) @@ -85,14 +85,14 @@ impl SelfUpdate { } let status = update .repo_owner("jdx") - .repo_name("rtx") - .bin_name("rtx") + .repo_name("mise") + .bin_name("mise") .verifying_keys([*include_bytes!("../../zipsign.pub")]) .show_download_progress(true) .current_version(cargo_crate_version!()) .target(&target) - .bin_path_in_archive("rtx/bin/rtx") - .identifier(&format!("rtx-{v}-{target}.tar.gz")) + .bin_path_in_archive("mise/bin/mise") + .identifier(&format!("mise-{v}-{target}.tar.gz")) .no_confirm(self.yes) .build()? .update()?; @@ -100,7 +100,7 @@ impl SelfUpdate { } pub fn is_available() -> bool { - !std::fs::canonicalize(&*env::RTX_BIN) + !std::fs::canonicalize(&*env::MISE_BIN) .ok() .and_then(|p| p.parent().map(|p| p.to_path_buf())) .and_then(|p| p.parent().map(|p| p.to_path_buf())) diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 708b19624..7180bd3db 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -6,10 +6,10 @@ use crate::config::{Config, Settings}; /// Show a current setting /// -/// This is the contents of a single entry in ~/.config/rtx/config.toml +/// This is the contents of a single entry in ~/.config/mise/config.toml /// /// Note that aliases are also stored in this file -/// but managed separately with `rtx aliases get` +/// but managed separately with `mise aliases get` #[derive(Debug, clap::Args)] #[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsGet { @@ -24,7 +24,7 @@ impl SettingsGet { let json = settings.to_string(); let doc: BTreeMap = serde_json::from_str(&json)?; match doc.get(&self.setting) { - Some(value) => Ok(rtxprintln!("{}", value)), + Some(value) => Ok(miseprintln!("{}", value)), None => Err(eyre!("Unknown setting: {}", self.setting)), } } @@ -32,7 +32,7 @@ impl SettingsGet { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx settings get legacy_version_file + $ mise settings get legacy_version_file true "# ); diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index f712c8051..f590f0e12 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -6,10 +6,10 @@ use crate::config::{Config, Settings}; /// Show current settings /// -/// This is the contents of ~/.config/rtx/config.toml +/// This is the contents of ~/.config/mise/config.toml /// /// Note that aliases are also stored in this file -/// but managed separately with `rtx aliases` +/// but managed separately with `mise aliases` #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsLs {} @@ -24,7 +24,7 @@ impl SettingsLs { if Settings::hidden_configs().contains(key.as_str()) { continue; } - rtxprintln!("{} = {}", key, value); + miseprintln!("{} = {}", key, value); } Ok(()) } @@ -32,7 +32,7 @@ impl SettingsLs { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx settings + $ mise settings legacy_version_file = false "# ); diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index e379b3871..d38b1946b 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -5,7 +5,7 @@ use crate::config::Config; /// Add/update a setting /// -/// This modifies the contents of ~/.config/rtx/config.toml +/// This modifies the contents of ~/.config/mise/config.toml #[derive(Debug, clap::Args)] #[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsSet { @@ -56,7 +56,7 @@ fn parse_i64(value: &str) -> Result { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx settings set legacy_version_file true + $ mise settings set legacy_version_file true "# ); diff --git a/src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/mise__cli__settings__ls__tests__settings_ls.snap similarity index 100% rename from src/cli/settings/snapshots/rtx__cli__settings__ls__tests__settings_ls.snap rename to src/cli/settings/snapshots/mise__cli__settings__ls__tests__settings_ls.snap diff --git a/src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/mise__cli__settings__set__tests__settings_set.snap similarity index 100% rename from src/cli/settings/snapshots/rtx__cli__settings__set__tests__settings_set.snap rename to src/cli/settings/snapshots/mise__cli__settings__set__tests__settings_set.snap diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 4561b50b5..0ed40aea1 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -5,7 +5,7 @@ use crate::config::Config; /// Clears a setting /// -/// This modifies the contents of ~/.config/rtx/config.toml +/// This modifies the contents of ~/.config/mise/config.toml #[derive(Debug, clap::Args)] #[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct SettingsUnset { @@ -23,7 +23,7 @@ impl SettingsUnset { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx settings unset legacy_version_file + $ mise settings unset legacy_version_file "# ); diff --git a/src/cli/shell.rs b/src/cli/shell.rs index bab4f8290..f4a8d663d 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -8,7 +8,7 @@ use crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder}; /// Sets a tool version for the current shell session /// -/// Only works in a session where rtx is already activated. +/// Only works in a session where mise is already activated. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "sh", after_long_help = AFTER_LONG_HELP)] pub struct Shell { @@ -18,7 +18,7 @@ pub struct Shell { /// Number of jobs to run in parallel /// [default: 4] - #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + #[clap(long, short, env = "MISE_JOBS", verbatim_doc_comment)] jobs: Option, /// Directly pipe stdin/stdout/stderr from plugin to user @@ -53,13 +53,13 @@ impl Shell { for (p, tv) in ts.list_current_installed_versions() { let source = &ts.versions.get(p.name()).unwrap().source; if matches!(source, ToolSource::Argument) { - let k = format!("RTX_{}_VERSION", p.name().to_uppercase()); + let k = format!("MISE_{}_VERSION", p.name().to_uppercase()); let op = if self.unset { shell.unset_env(&k) } else { shell.set_env(&k, &tv.version) }; - rtxprintln!("{op}"); + miseprintln!("{op}"); } } @@ -70,16 +70,16 @@ impl Shell { fn err_inactive() -> Result<()> { Err(eyre!(formatdoc!( r#" - rtx is not activated in this shell session. + mise is not activated in this shell session. Please run `{}` first in your shell rc file. "#, - style("rtx activate").yellow() + style("mise activate").yellow() ))) } static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx shell node@20 + $ mise shell node@20 $ node -v v20.0.0 "# @@ -93,10 +93,10 @@ mod tests { fn test_shell() { let err = assert_cli_err!("shell", "tiny@1.0.1"); assert_display_snapshot!(err); - env::set_var("__RTX_DIFF", ""); - env::set_var("RTX_SHELL", "zsh"); + env::set_var("__MISE_DIFF", ""); + env::set_var("MISE_SHELL", "zsh"); assert_cli_snapshot!("shell", "tiny@1.0.1"); - env::remove_var("__RTX_DIFF"); - env::remove_var("RTX_SHELL"); + env::remove_var("__MISE_DIFF"); + env::remove_var("MISE_SHELL"); } } diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap b/src/cli/snapshots/mise__cli__asdf__tests__fake_asdf_install.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_install.snap rename to src/cli/snapshots/mise__cli__asdf__tests__fake_asdf_install.snap diff --git a/src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_reshim.snap b/src/cli/snapshots/mise__cli__asdf__tests__fake_asdf_reshim.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__asdf__tests__fake_asdf_reshim.snap rename to src/cli/snapshots/mise__cli__asdf__tests__fake_asdf_reshim.snap diff --git a/src/cli/snapshots/mise__cli__deactivate__tests__deactivate-2.snap b/src/cli/snapshots/mise__cli__deactivate__tests__deactivate-2.snap new file mode 100644 index 000000000..ac9a1130d --- /dev/null +++ b/src/cli/snapshots/mise__cli__deactivate__tests__deactivate-2.snap @@ -0,0 +1,10 @@ +--- +source: src/cli/deactivate.rs +expression: output +--- +export PATH='$PATH' +precmd_functions=( ${precmd_functions:#_mise_hook} ) +chpwd_functions=( ${chpwd_functions:#_mise_hook} ) +unset -f _mise_hook +unset -f mise +unset MISE_SHELL diff --git a/src/cli/snapshots/mise__cli__deactivate__tests__deactivate.snap b/src/cli/snapshots/mise__cli__deactivate__tests__deactivate.snap new file mode 100644 index 000000000..2c376f225 --- /dev/null +++ b/src/cli/snapshots/mise__cli__deactivate__tests__deactivate.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/deactivate.rs +expression: err +--- +mise is not activated in this shell session. +Please run `mise activate` first in your shell rc file. + diff --git a/src/cli/snapshots/rtx__cli__env__tests__env_json.snap b/src/cli/snapshots/mise__cli__env__tests__env_json.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__env__tests__env_json.snap rename to src/cli/snapshots/mise__cli__env__tests__env_json.snap diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap b/src/cli/snapshots/mise__cli__env_vars__tests__env_vars-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__env_vars__tests__env_vars-2.snap rename to src/cli/snapshots/mise__cli__env_vars__tests__env_vars-2.snap diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap b/src/cli/snapshots/mise__cli__env_vars__tests__env_vars.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__env_vars__tests__env_vars.snap rename to src/cli/snapshots/mise__cli__env_vars__tests__env_vars.snap diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap b/src/cli/snapshots/mise__cli__env_vars__tests__env_vars_remove-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove-2.snap rename to src/cli/snapshots/mise__cli__env_vars__tests__env_vars_remove-2.snap diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap b/src/cli/snapshots/mise__cli__env_vars__tests__env_vars_remove.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__env_vars__tests__env_vars_remove.snap rename to src/cli/snapshots/mise__cli__env_vars__tests__env_vars_remove.snap diff --git a/src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap b/src/cli/snapshots/mise__cli__env_vars__tests__show_env_vars.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__env_vars__tests__show_env_vars.snap rename to src/cli/snapshots/mise__cli__env_vars__tests__show_env_vars.snap diff --git a/src/cli/snapshots/rtx__cli__exec__tests__exec_fail.snap b/src/cli/snapshots/mise__cli__exec__tests__exec_fail.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__exec__tests__exec_fail.snap rename to src/cli/snapshots/mise__cli__exec__tests__exec_fail.snap diff --git a/src/cli/snapshots/rtx__cli__global__tests__global.snap b/src/cli/snapshots/mise__cli__global__tests__global-2.snap similarity index 60% rename from src/cli/snapshots/rtx__cli__global__tests__global.snap rename to src/cli/snapshots/mise__cli__global__tests__global-2.snap index bbe62066a..3d8e6f6c8 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global-2.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -rtx ~/.test-tool-versions tiny@2 +mise ~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap b/src/cli/snapshots/mise__cli__global__tests__global-3.snap similarity index 62% rename from src/cli/snapshots/rtx__cli__global__tests__global-3.snap rename to src/cli/snapshots/mise__cli__global__tests__global-3.snap index 131ca2e88..2659835cf 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global-3.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -rtx ~/.test-tool-versions tiny +mise ~/.test-tool-versions tiny diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap b/src/cli/snapshots/mise__cli__global__tests__global-4.snap similarity index 60% rename from src/cli/snapshots/rtx__cli__global__tests__global-2.snap rename to src/cli/snapshots/mise__cli__global__tests__global-4.snap index bbe62066a..3d8e6f6c8 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global-4.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -rtx ~/.test-tool-versions tiny@2 +mise ~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-5.snap b/src/cli/snapshots/mise__cli__global__tests__global-5.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__global__tests__global-5.snap rename to src/cli/snapshots/mise__cli__global__tests__global-5.snap diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-6.snap b/src/cli/snapshots/mise__cli__global__tests__global-6.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__global__tests__global-6.snap rename to src/cli/snapshots/mise__cli__global__tests__global-6.snap diff --git a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap b/src/cli/snapshots/mise__cli__global__tests__global.snap similarity index 60% rename from src/cli/snapshots/rtx__cli__global__tests__global-4.snap rename to src/cli/snapshots/mise__cli__global__tests__global.snap index bbe62066a..3d8e6f6c8 100644 --- a/src/cli/snapshots/rtx__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -rtx ~/.test-tool-versions tiny@2 +mise ~/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__install__tests__install_nothing.snap b/src/cli/snapshots/mise__cli__install__tests__install_nothing.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__install__tests__install_nothing.snap rename to src/cli/snapshots/mise__cli__install__tests__install_nothing.snap diff --git a/src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap b/src/cli/snapshots/mise__cli__install__tests__install_with_alias.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__install__tests__install_with_alias.snap rename to src/cli/snapshots/mise__cli__install__tests__install_with_alias.snap diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest.snap b/src/cli/snapshots/mise__cli__latest__tests__latest.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__latest__tests__latest.snap rename to src/cli/snapshots/mise__cli__latest__tests__latest.snap diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap b/src/cli/snapshots/mise__cli__latest__tests__latest_asdf_format.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__latest__tests__latest_asdf_format.snap rename to src/cli/snapshots/mise__cli__latest__tests__latest_asdf_format.snap diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap b/src/cli/snapshots/mise__cli__latest__tests__latest_installed.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__latest__tests__latest_installed.snap rename to src/cli/snapshots/mise__cli__latest__tests__latest_installed.snap diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap b/src/cli/snapshots/mise__cli__latest__tests__latest_missing_plugin.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__latest__tests__latest_missing_plugin.snap rename to src/cli/snapshots/mise__cli__latest__tests__latest_missing_plugin.snap diff --git a/src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap b/src/cli/snapshots/mise__cli__latest__tests__latest_system.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__latest__tests__latest_system.snap rename to src/cli/snapshots/mise__cli__latest__tests__latest_system.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap b/src/cli/snapshots/mise__cli__local__tests__local_alias_prefix.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local_alias_prefix.snap rename to src/cli/snapshots/mise__cli__local__tests__local_alias_prefix.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap b/src/cli/snapshots/mise__cli__local__tests__local_alias_ref.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local_alias_ref.snap rename to src/cli/snapshots/mise__cli__local__tests__local_alias_ref.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap b/src/cli/snapshots/mise__cli__local__tests__local_alias_system.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local_alias_system.snap rename to src/cli/snapshots/mise__cli__local__tests__local_alias_system.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap b/src/cli/snapshots/mise__cli__local__tests__local_multiple_versions-2.snap similarity index 50% rename from src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap rename to src/cli/snapshots/mise__cli__local__tests__local_multiple_versions-2.snap index 906895a96..0fb6fd706 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-2.snap +++ b/src/cli/snapshots/mise__cli__local__tests__local_multiple_versions-2.snap @@ -2,4 +2,4 @@ source: src/cli/local.rs expression: output --- -rtx ~/cwd/.test-tool-versions tiny@2 tiny@1 tiny@3 +mise ~/cwd/.test-tool-versions tiny@2 tiny@1 tiny@3 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap b/src/cli/snapshots/mise__cli__local__tests__local_multiple_versions-3.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions-3.snap rename to src/cli/snapshots/mise__cli__local__tests__local_multiple_versions-3.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap b/src/cli/snapshots/mise__cli__local__tests__local_multiple_versions.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__local__tests__local_multiple_versions.snap rename to src/cli/snapshots/mise__cli__local__tests__local_multiple_versions.snap diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap b/src/cli/snapshots/mise__cli__local__tests__local_remove-2.snap similarity index 57% rename from src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap rename to src/cli/snapshots/mise__cli__local__tests__local_remove-2.snap index 6ba0e3d6e..655d69103 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-2.snap +++ b/src/cli/snapshots/mise__cli__local__tests__local_remove-2.snap @@ -2,4 +2,4 @@ source: src/cli/local.rs expression: output --- -rtx ~/cwd/.test-tool-versions tiny@2 +mise ~/cwd/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap b/src/cli/snapshots/mise__cli__local__tests__local_remove-3.snap similarity index 59% rename from src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap rename to src/cli/snapshots/mise__cli__local__tests__local_remove-3.snap index d14062203..b0268fbd8 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove-3.snap +++ b/src/cli/snapshots/mise__cli__local__tests__local_remove-3.snap @@ -2,4 +2,4 @@ source: src/cli/local.rs expression: output --- -rtx ~/cwd/.test-tool-versions tiny +mise ~/cwd/.test-tool-versions tiny diff --git a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap b/src/cli/snapshots/mise__cli__local__tests__local_remove.snap similarity index 57% rename from src/cli/snapshots/rtx__cli__local__tests__local_remove.snap rename to src/cli/snapshots/mise__cli__local__tests__local_remove.snap index 6ba0e3d6e..655d69103 100644 --- a/src/cli/snapshots/rtx__cli__local__tests__local_remove.snap +++ b/src/cli/snapshots/mise__cli__local__tests__local_remove.snap @@ -2,4 +2,4 @@ source: src/cli/local.rs expression: output --- -rtx ~/cwd/.test-tool-versions tiny@2 +mise ~/cwd/.test-tool-versions tiny@2 diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap b/src/cli/snapshots/mise__cli__ls__tests__ls_json-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__ls__tests__ls_json-2.snap rename to src/cli/snapshots/mise__cli__ls__tests__ls_json-2.snap diff --git a/src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap b/src/cli/snapshots/mise__cli__ls__tests__ls_json.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__ls__tests__ls_json.snap rename to src/cli/snapshots/mise__cli__ls__tests__ls_json.snap diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap b/src/cli/snapshots/mise__cli__ls_remote__tests__list_remote.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__ls_remote__tests__list_remote.snap rename to src/cli/snapshots/mise__cli__ls_remote__tests__list_remote.snap diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap b/src/cli/snapshots/mise__cli__ls_remote__tests__ls_remote_prefix-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix-2.snap rename to src/cli/snapshots/mise__cli__ls_remote__tests__ls_remote_prefix-2.snap diff --git a/src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap b/src/cli/snapshots/mise__cli__ls_remote__tests__ls_remote_prefix.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__ls_remote__tests__ls_remote_prefix.snap rename to src/cli/snapshots/mise__cli__ls_remote__tests__ls_remote_prefix.snap diff --git a/src/cli/snapshots/rtx__cli__outdated__tests__current.snap b/src/cli/snapshots/mise__cli__outdated__tests__current.snap similarity index 64% rename from src/cli/snapshots/rtx__cli__outdated__tests__current.snap rename to src/cli/snapshots/mise__cli__outdated__tests__current.snap index e033a0b06..bffc18a01 100644 --- a/src/cli/snapshots/rtx__cli__outdated__tests__current.snap +++ b/src/cli/snapshots/mise__cli__outdated__tests__current.snap @@ -2,4 +2,4 @@ source: src/cli/outdated.rs expression: output --- -rtx All tools are up to date +mise All tools are up to date diff --git a/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap b/src/cli/snapshots/mise__cli__outdated__tests__current_with_runtimes.snap similarity index 64% rename from src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap rename to src/cli/snapshots/mise__cli__outdated__tests__current_with_runtimes.snap index e033a0b06..bffc18a01 100644 --- a/src/cli/snapshots/rtx__cli__outdated__tests__current_with_runtimes.snap +++ b/src/cli/snapshots/mise__cli__outdated__tests__current_with_runtimes.snap @@ -2,4 +2,4 @@ source: src/cli/outdated.rs expression: output --- -rtx All tools are up to date +mise All tools are up to date diff --git a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap b/src/cli/snapshots/mise__cli__r#where__tests__where_asdf_style-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style-2.snap rename to src/cli/snapshots/mise__cli__r#where__tests__where_asdf_style-2.snap diff --git a/src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap b/src/cli/snapshots/mise__cli__r#where__tests__where_asdf_style.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__r#where__tests__where_asdf_style.snap rename to src/cli/snapshots/mise__cli__r#where__tests__where_asdf_style.snap diff --git a/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap b/src/cli/snapshots/mise__cli__shell__tests__shell-2.snap similarity index 62% rename from src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap rename to src/cli/snapshots/mise__cli__shell__tests__shell-2.snap index debb0be97..af9542c92 100644 --- a/src/cli/snapshots/rtx__cli__shell__tests__shell-2.snap +++ b/src/cli/snapshots/mise__cli__shell__tests__shell-2.snap @@ -2,4 +2,4 @@ source: src/cli/shell.rs expression: output --- -export RTX_TINY_VERSION=1.0.1 +export MISE_TINY_VERSION=1.0.1 diff --git a/src/cli/snapshots/mise__cli__shell__tests__shell.snap b/src/cli/snapshots/mise__cli__shell__tests__shell.snap new file mode 100644 index 000000000..d524cdd86 --- /dev/null +++ b/src/cli/snapshots/mise__cli__shell__tests__shell.snap @@ -0,0 +1,7 @@ +--- +source: src/cli/shell.rs +expression: err +--- +mise is not activated in this shell session. +Please run `mise activate` first in your shell rc file. + diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-2.snap similarity index 55% rename from src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap rename to src/cli/snapshots/mise__cli__trust__tests__trust-2.snap index ab87a1ba2..e650db175 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-2.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-2.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -rtx untrusted ~/cwd/.test-tool-versions +mise untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-3.snap similarity index 57% rename from src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap rename to src/cli/snapshots/mise__cli__trust__tests__trust-3.snap index efb7aabf7..e47fa4340 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-3.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-3.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -rtx trusted ~/cwd/.test-tool-versions +mise trusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap b/src/cli/snapshots/mise__cli__trust__tests__trust-4.snap similarity index 55% rename from src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap rename to src/cli/snapshots/mise__cli__trust__tests__trust-4.snap index ab87a1ba2..e650db175 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust-4.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust-4.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -rtx untrusted ~/cwd/.test-tool-versions +mise untrusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__trust__tests__trust.snap b/src/cli/snapshots/mise__cli__trust__tests__trust.snap similarity index 57% rename from src/cli/snapshots/rtx__cli__trust__tests__trust.snap rename to src/cli/snapshots/mise__cli__trust__tests__trust.snap index efb7aabf7..e47fa4340 100644 --- a/src/cli/snapshots/rtx__cli__trust__tests__trust.snap +++ b/src/cli/snapshots/mise__cli__trust__tests__trust.snap @@ -2,4 +2,4 @@ source: src/cli/trust.rs expression: output --- -rtx trusted ~/cwd/.test-tool-versions +mise trusted ~/cwd/.test-tool-versions diff --git a/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade-2.snap b/src/cli/snapshots/mise__cli__upgrade__tests__upgrade-2.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__upgrade__tests__upgrade-2.snap rename to src/cli/snapshots/mise__cli__upgrade__tests__upgrade-2.snap diff --git a/src/cli/snapshots/mise__cli__upgrade__tests__upgrade.snap b/src/cli/snapshots/mise__cli__upgrade__tests__upgrade.snap new file mode 100644 index 000000000..9a1091d46 --- /dev/null +++ b/src/cli/snapshots/mise__cli__upgrade__tests__upgrade.snap @@ -0,0 +1,6 @@ +--- +source: src/cli/upgrade.rs +expression: output +--- +mise Would uninstall tiny@3.0.0 +mise Would install tiny@3.1.0 diff --git a/src/cli/snapshots/rtx__cli__which__tests__which.snap b/src/cli/snapshots/mise__cli__which__tests__which.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__which__tests__which.snap rename to src/cli/snapshots/mise__cli__which__tests__which.snap diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap b/src/cli/snapshots/mise__cli__which__tests__which_plugin.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__which__tests__which_plugin.snap rename to src/cli/snapshots/mise__cli__which__tests__which_plugin.snap diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_tool.snap b/src/cli/snapshots/mise__cli__which__tests__which_tool.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__which__tests__which_tool.snap rename to src/cli/snapshots/mise__cli__which__tests__which_tool.snap diff --git a/src/cli/snapshots/rtx__cli__which__tests__which_version.snap b/src/cli/snapshots/mise__cli__which__tests__which_version.snap similarity index 100% rename from src/cli/snapshots/rtx__cli__which__tests__which_version.snap rename to src/cli/snapshots/mise__cli__which__tests__which_version.snap diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap deleted file mode 100644 index 040c3aa10..000000000 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate-2.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: src/cli/deactivate.rs -expression: output ---- -export PATH='$PATH' -precmd_functions=( ${precmd_functions:#_rtx_hook} ) -chpwd_functions=( ${chpwd_functions:#_rtx_hook} ) -unset -f _rtx_hook -unset -f rtx -unset RTX_SHELL diff --git a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap b/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap deleted file mode 100644 index c249b2f10..000000000 --- a/src/cli/snapshots/rtx__cli__deactivate__tests__deactivate.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/deactivate.rs -expression: err ---- -rtx is not activated in this shell session. -Please run `rtx activate` first in your shell rc file. - diff --git a/src/cli/snapshots/rtx__cli__shell__tests__shell.snap b/src/cli/snapshots/rtx__cli__shell__tests__shell.snap deleted file mode 100644 index 4a623ea2a..000000000 --- a/src/cli/snapshots/rtx__cli__shell__tests__shell.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: src/cli/shell.rs -expression: err ---- -rtx is not activated in this shell session. -Please run `rtx activate` first in your shell rc file. - diff --git a/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap b/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap deleted file mode 100644 index 26fcbfe2b..000000000 --- a/src/cli/snapshots/rtx__cli__upgrade__tests__upgrade.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/cli/upgrade.rs -expression: output ---- -rtx Would uninstall tiny@3.0.0 -rtx Would install tiny@3.1.0 diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs index 8d125ce30..9a0f38149 100644 --- a/src/cli/sync/mod.rs +++ b/src/cli/sync/mod.rs @@ -5,7 +5,7 @@ mod node; mod python; #[derive(Debug, clap::Args)] -#[clap(about = "Add tool versions from external tools to rtx")] +#[clap(about = "Add tool versions from external tools to mise")] pub struct Sync { #[clap(subcommand)] command: Commands, diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 37d5832a7..90c56919c 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -9,9 +9,9 @@ use crate::file; use crate::plugins::PluginName; use crate::{cmd, dirs}; -/// Symlinks all tool versions from an external tool into rtx +/// Symlinks all tool versions from an external tool into mise /// -/// For example, use this to import all Homebrew node installs into rtx +/// For example, use this to import all Homebrew node installs into mise #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct SyncNode { @@ -63,7 +63,7 @@ impl SyncNode { } let v = entry.trim_start_matches("node@"); tool.create_symlink(v, &brew_prefix.join(&entry))?; - rtxprintln!("Synced node@{} from Homebrew", v); + miseprintln!("Synced node@{} from Homebrew", v); } config.rebuild_shims_and_runtime_symlinks() @@ -81,7 +81,7 @@ impl SyncNode { for entry in sorted(subdirs) { let v = entry.trim_start_matches('v'); tool.create_symlink(v, &nvm_versions_path.join(&entry))?; - rtxprintln!("Synced node@{} from nvm", v); + miseprintln!("Synced node@{} from nvm", v); } config.rebuild_shims_and_runtime_symlinks() @@ -98,7 +98,7 @@ impl SyncNode { let subdirs = file::dir_subdirs(&nodenv_versions_path)?; for v in sorted(subdirs) { tool.create_symlink(&v, &nodenv_versions_path.join(&v))?; - rtxprintln!("Synced node@{} from nodenv", v); + miseprintln!("Synced node@{} from nodenv", v); } config.rebuild_shims_and_runtime_symlinks() @@ -108,7 +108,7 @@ impl SyncNode { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ brew install node@18 node@20 - $ rtx sync node --brew - $ rtx use -g node@18 - uses Homebrew-provided node + $ mise sync node --brew + $ mise use -g node@18 - uses Homebrew-provided node "# ); diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 9783c0abe..62708c60e 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -8,9 +8,9 @@ use crate::file; use crate::plugins::PluginName; -/// Symlinks all tool versions from an external tool into rtx +/// Symlinks all tool versions from an external tool into mise /// -/// For example, use this to import all pyenv installs into rtx +/// For example, use this to import all pyenv installs into mise #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct SyncPython { @@ -35,7 +35,7 @@ impl SyncPython { let subdirs = file::dir_subdirs(&pyenv_versions_path)?; for v in sorted(subdirs) { python.create_symlink(&v, &pyenv_versions_path.join(&v))?; - rtxprintln!("Synced python@{} from pyenv", v); + miseprintln!("Synced python@{} from pyenv", v); } config.rebuild_shims_and_runtime_symlinks() @@ -45,8 +45,8 @@ impl SyncPython { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ pyenv install 3.11.0 - $ rtx sync python --pyenv - $ rtx use -g python@3.11.0 - uses pyenv-provided python + $ mise sync python --pyenv + $ mise use -g python@3.11.0 - uses pyenv-provided python "# ); diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs index e9debe25c..d218d0ff2 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/task/edit.rs @@ -31,7 +31,7 @@ impl TaskEdit { .project_root .as_ref() .unwrap_or(&env::current_dir()?) - .join(".rtx") + .join(".mise") .join("tasks") .join(&self.task); Task::from_path(path) @@ -44,7 +44,7 @@ impl TaskEdit { file::make_executable(file)?; } if self.path { - rtxprintln!("{}", file.display()); + miseprintln!("{}", file.display()); } else { cmd!(&*env::EDITOR, &file).run()?; } @@ -55,7 +55,7 @@ impl TaskEdit { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx task edit build - $ rtx task edit test + $ mise task edit build + $ mise task edit test "# ); diff --git a/src/cli/task/ls.rs b/src/cli/task/ls.rs index a62b37491..3fd835125 100644 --- a/src/cli/task/ls.rs +++ b/src/cli/task/ls.rs @@ -10,11 +10,11 @@ use crate::file::display_path; use crate::ui::{style, table}; /// [experimental] List available tasks to execute -/// These may be included from the config file or from the project's .rtx/tasks directory -/// rtx will merge all tasks from all parent directories into this list. +/// These may be included from the config file or from the project's .mise/tasks directory +/// mise will merge all tasks from all parent directories into this list. /// -/// So if you have global tasks in ~/.config/rtx/tasks/* and project-specific tasks in -/// ~/myproject/.rtx/tasks/*, then they'll both be available but the project-specific +/// So if you have global tasks in ~/.config/mise/tasks/* and project-specific tasks in +/// ~/myproject/.mise/tasks/*, then they'll both be available but the project-specific /// tasks will override the global ones if they have the same name. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] @@ -44,7 +44,7 @@ impl TaskLs { .collect::>(); let mut table = tabled::Table::new(rows); table::default_style(&mut table, self.no_header); - rtxprintln!("{table}"); + miseprintln!("{table}"); Ok(()) } @@ -82,7 +82,7 @@ fn truncate(s: &str, len: usize) -> String { // TODO: fill this out static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx task ls + $ mise task ls "# ); @@ -93,9 +93,9 @@ mod tests { #[test] fn test_task_ls() { assert_cli_snapshot!("t", "--no-headers", @r###" - configtask ~/config/config.toml - filetask This is a test build script ~/cwd/.rtx/tasks/filetask - lint ~/config/config.toml + configtask ~/config/config.toml + filetask This is a test build script ~/cwd/.mise/tasks/filetask + lint ~/config/config.toml test ~/config/config.toml "###); } diff --git a/src/cli/trust.rs b/src/cli/trust.rs index b37f12d12..8acf90485 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -8,7 +8,7 @@ use crate::config::{config_file, DEFAULT_CONFIG_FILENAMES}; /// Marks a config file as trusted /// -/// This means rtx will parse the file with potentially dangerous +/// This means mise will parse the file with potentially dangerous /// features enabled. /// /// This includes: @@ -85,11 +85,11 @@ impl Trust { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # trusts ~/some_dir/.rtx.toml - $ rtx trust ~/some_dir/.rtx.toml + # trusts ~/some_dir/.mise.toml + $ mise trust ~/some_dir/.mise.toml - # trusts .rtx.toml in the current or parent directory - $ rtx trust + # trusts .mise.toml in the current or parent directory + $ mise trust "# ); diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 178e1de9f..d9eeeb64f 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -131,8 +131,8 @@ impl Uninstall { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx uninstall node@18.0.0 # will uninstall specific version - $ rtx uninstall node # will uninstall current node version - $ rtx uninstall --all node@18.0.0 # will uninstall all node versions + $ mise uninstall node@18.0.0 # will uninstall specific version + $ mise uninstall node # will uninstall current node version + $ mise uninstall --all node@18.0.0 # will uninstall all node versions "# ); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index c4c9cc9f6..2e3e402bf 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -31,7 +31,7 @@ pub struct Upgrade { /// Number of jobs to run in parallel /// [default: 4] - #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + #[clap(long, short, env = "MISE_JOBS", verbatim_doc_comment)] jobs: Option, /// Display multiselect menu to choose which tools to upgrade @@ -129,7 +129,7 @@ impl Upgrade { fn get_interactive_tool_set(&self, outdated: &OutputVec) -> Result> { ui::handle_ctrlc(); - let mut ms = demand::MultiSelect::new("rtx upgrade") + let mut ms = demand::MultiSelect::new("mise upgrade") .description("Select tools to upgrade") .filterable(true) .min(1); diff --git a/src/cli/use.rs b/src/cli/use.rs index 9faa8c563..dd6b52de6 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -7,7 +7,7 @@ use itertools::Itertools; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config, Settings}; -use crate::env::{RTX_DEFAULT_CONFIG_FILENAME, RTX_DEFAULT_TOOL_VERSIONS_FILENAME}; +use crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; use crate::plugins::PluginName; use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest, ToolsetBuilder}; @@ -17,9 +17,9 @@ use crate::{dirs, env, file}; /// Change the active version of a tool locally or globally. /// /// This will install the tool if it is not already installed. -/// By default, this will use an `.rtx.toml` file in the current directory. +/// By default, this will use an `.mise.toml` file in the current directory. /// Use the --global flag to use the global config file instead. -/// This replaces asdf's `local` and `global` commands, however those are still available in rtx. +/// This replaces asdf's `local` and `global` commands, however those are still available in mise. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, visible_alias = "u", after_long_help = AFTER_LONG_HELP)] pub struct Use { @@ -34,22 +34,22 @@ pub struct Use { force: bool, /// Save fuzzy version to config file - /// e.g.: `rtx use --fuzzy node@20` will save 20 as the version - /// this is the default behavior unless RTX_ASDF_COMPAT=1 + /// e.g.: `mise use --fuzzy node@20` will save 20 as the version + /// this is the default behavior unless MISE_ASDF_COMPAT=1 #[clap(long, verbatim_doc_comment, overrides_with = "pin")] fuzzy: bool, - /// Use the global config file (~/.config/rtx/config.toml) instead of the local one + /// Use the global config file (~/.config/mise/config.toml) instead of the local one #[clap(short, long, overrides_with_all = &["path", "env"])] global: bool, - /// Modify an environment-specific config file like .rtx..toml + /// Modify an environment-specific config file like .mise..toml #[clap(long, short, overrides_with_all = &["global", "path"])] env: Option, /// Number of jobs to run in parallel /// [default: 4] - #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + #[clap(long, short, env = "MISE_JOBS", verbatim_doc_comment)] jobs: Option, /// Directly pipe stdin/stdout/stderr from plugin to user @@ -62,15 +62,15 @@ pub struct Use { remove: Vec, /// Specify a path to a config file or directory - /// If a directory is specified, it will look for .rtx.toml (default) or .tool-versions + /// If a directory is specified, it will look for .mise.toml (default) or .tool-versions #[clap(short, long, overrides_with_all = &["global", "env"], value_hint = clap::ValueHint::FilePath)] path: Option, /// Save exact version to config file - /// e.g.: `rtx use --pin node@20` will save 20.0.0 as the version + /// e.g.: `mise use --pin node@20` will save 20.0.0 as the version #[clap( long, - env = "RTX_ASDF_COMPAT", + env = "MISE_ASDF_COMPAT", verbatim_doc_comment, overrides_with = "fuzzy" )] @@ -139,7 +139,7 @@ impl Use { let path = if self.global { global_file() } else if let Some(env) = &self.env { - config_file_from_dir(&env::current_dir()?.join(format!(".rtx.{}.toml", env))) + config_file_from_dir(&env::current_dir()?.join(format!(".mise.{}.toml", env))) } else if let Some(p) = &self.path { config_file_from_dir(p) } else { @@ -158,7 +158,7 @@ impl Use { }; for targ in &self.tool { if let Some(tv) = ts.versions.get(&targ.plugin) { - if let ToolSource::RtxToml(p) | ToolSource::ToolVersions(p) = &tv.source { + if let ToolSource::MiseToml(p) | ToolSource::ToolVersions(p) = &tv.source { if p != global { warn(targ, p); } @@ -170,16 +170,16 @@ impl Use { fn render_success_message(&self, cf: &dyn ConfigFile, versions: &[ToolVersion]) { let path = display_path(cf.get_path()); let tools = versions.iter().map(|t| t.style()).join(", "); - rtxprintln!( + miseprintln!( "{} {} tools: {tools}", - style("rtx").green(), + style("mise").green(), style(path).cyan().for_stderr(), ); } } fn global_file() -> PathBuf { - env::RTX_CONFIG_FILE + env::MISE_CONFIG_FILE .clone() .unwrap_or_else(|| dirs::CONFIG.join("config.toml")) } @@ -188,35 +188,35 @@ fn config_file_from_dir(p: &Path) -> PathBuf { if !p.is_dir() { return p.to_path_buf(); } - let rtx_toml = p.join(&*RTX_DEFAULT_CONFIG_FILENAME); - let tool_versions = p.join(&*RTX_DEFAULT_TOOL_VERSIONS_FILENAME); - if rtx_toml.exists() { - return rtx_toml; + let mise_toml = p.join(&*MISE_DEFAULT_CONFIG_FILENAME); + let tool_versions = p.join(&*MISE_DEFAULT_TOOL_VERSIONS_FILENAME); + if mise_toml.exists() { + return mise_toml; } else if tool_versions.exists() { return tool_versions; } - let filenames = vec![RTX_DEFAULT_CONFIG_FILENAME.as_str()]; + let filenames = vec![MISE_DEFAULT_CONFIG_FILENAME.as_str()]; if let Some(p) = file::find_up(p, &filenames) { return p; } - rtx_toml + mise_toml } static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - # set the current version of node to 20.x in .rtx.toml of current directory + # set the current version of node to 20.x in .mise.toml of current directory # will write the fuzzy version (e.g.: 20) - $ rtx use node@20 + $ mise use node@20 - # set the current version of node to 20.x in ~/.config/rtx/config.toml + # set the current version of node to 20.x in ~/.config/mise/config.toml # will write the precise version (e.g.: 20.0.0) - $ rtx use -g --pin node@20 + $ mise use -g --pin node@20 - # sets .rtx.local.toml (which is intended not to be committed to a project) - $ rtx use --env local node@20 + # sets .mise.local.toml (which is intended not to be committed to a project) + $ mise use --env local node@20 - # sets .rtx.staging.toml (which is used if RTX_ENV=staging) - $ rtx use --env staging node@20 + # sets .mise.staging.toml (which is used if MISE_ENV=staging) + $ mise use --env staging node@20 "# ); @@ -226,29 +226,29 @@ mod tests { #[test] fn test_use_local() { - let cf_path = env::current_dir().unwrap().join(".test.rtx.toml"); + let cf_path = env::current_dir().unwrap().join(".test.mise.toml"); file::write(&cf_path, "").unwrap(); - assert_cli_snapshot!("use", "tiny@2", @"rtx ~/cwd/.test.rtx.toml tools: tiny@2.1.0"); + assert_cli_snapshot!("use", "tiny@2", @"mise ~/cwd/.test.mise.toml tools: tiny@2.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] tiny = "2" "###); - assert_cli_snapshot!("use", "--pin", "tiny", @"rtx ~/cwd/.test.rtx.toml tools: tiny@3.1.0"); + assert_cli_snapshot!("use", "--pin", "tiny", @"mise ~/cwd/.test.mise.toml tools: tiny@3.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] tiny = "3.1.0" "###); - assert_cli_snapshot!("use", "--fuzzy", "tiny@2", @"rtx ~/cwd/.test.rtx.toml tools: tiny@2.1.0"); + assert_cli_snapshot!("use", "--fuzzy", "tiny@2", @"mise ~/cwd/.test.mise.toml tools: tiny@2.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] tiny = "2" "###); let p = cf_path.to_string_lossy().to_string(); - assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p, @"rtx ~/cwd/.test.rtx.toml tools:"); + assert_cli_snapshot!("use", "--rm", "tiny", "--path", &p, @"mise ~/cwd/.test.mise.toml tools:"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @""); let _ = file::remove_file(&cf_path); @@ -259,7 +259,7 @@ mod tests { let cf_path = env::current_dir().unwrap().join(".test-tool-versions"); file::write(&cf_path, "").unwrap(); - assert_cli_snapshot!("use", "tiny@3", @"rtx ~/cwd/.test-tool-versions tools: tiny@3.1.0"); + assert_cli_snapshot!("use", "tiny@3", @"mise ~/cwd/.test-tool-versions tools: tiny@3.1.0"); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" tiny 3 "###); @@ -272,8 +272,8 @@ mod tests { let _ = file::remove_file(&cf_path); assert_cli_snapshot!("use", "-g", "tiny@2", @r###" - rtx ~/config/config.toml tools: tiny@2.1.0 - rtx tiny is defined in ~/cwd/.test-tool-versions which overrides the global config (~/config/config.toml) + mise ~/config/config.toml tools: tiny@2.1.0 + mise tiny is defined in ~/cwd/.test-tool-versions which overrides the global config (~/config/config.toml) "###); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" [tools] diff --git a/src/cli/version.rs b/src/cli/version.rs index 09bcd44a0..0ab688099 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -15,7 +15,7 @@ use crate::file::modified_duration; use crate::{dirs, duration, file}; #[derive(Debug, clap::Args)] -#[clap(about = "Show rtx version", alias = "v")] +#[clap(about = "Show mise version", alias = "v")] pub struct Version {} pub static OS: Lazy = Lazy::new(|| std::env::consts::OS.into()); @@ -51,7 +51,7 @@ impl Version { } pub fn print_version_if_requested(args: &[String]) { - if args.len() == 2 && *env::RTX_BIN_NAME == "rtx" { + if args.len() == 2 && *env::MISE_BIN_NAME == "mise" { let cmd = &args[1].to_lowercase(); if cmd == "version" || cmd == "-v" || cmd == "--version" { show_version(); @@ -62,7 +62,7 @@ pub fn print_version_if_requested(args: &[String]) { } fn show_version() { - rtxprintln!("{}", *VERSION); + miseprintln!("{}", *VERSION); show_latest(); } @@ -71,9 +71,9 @@ fn show_latest() { return; } if let Some(latest) = check_for_new_version(duration::DAILY) { - warn!("rtx version {} available", latest); + warn!("mise version {} available", latest); if SelfUpdate::is_available() { - let cmd = style("rtx self-update").bright().yellow().for_stderr(); + let cmd = style("mise self-update").bright().yellow().for_stderr(); warn!("To update, run {}", cmd); } } @@ -111,8 +111,8 @@ fn get_latest_version_call() -> Option { #[cfg(not(test))] fn get_latest_version_call() -> Option { - const URL: &str = "http://rtx.jdx.dev/VERSION"; - debug!("checking rtx version from {}", URL); + const URL: &str = "http://mise.jdx.dev/VERSION"; + debug!("checking mise version from {}", URL); match crate::http::HTTP_VERSION_CHECK.get_text(URL) { Ok(text) => { debug!("got version {text}"); diff --git a/src/cli/watch.rs b/src/cli/watch.rs index f10aee472..c0feeb485 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -39,13 +39,13 @@ pub struct Watch { // // /// Print stdout/stderr by line, prefixed with the task's label // /// Defaults to true if --jobs > 1 - // /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + // /// Configure with `task_output` config or `MISE_TASK_OUTPUT` env var // #[clap(long, short, verbatim_doc_comment, overrides_with = "interleave")] // pub prefix: bool, // // /// Print directly to stdout/stderr instead of by line // /// Defaults to true if --jobs == 1 - // /// Configure with `task_output` config or `RTX_TASK_OUTPUT` env var + // /// Configure with `task_output` config or `MISE_TASK_OUTPUT` env var // #[clap(long, short, verbatim_doc_comment, overrides_with = "prefix")] // pub interleave: bool, // @@ -56,12 +56,12 @@ pub struct Watch { // // /// Number of tasks to run in parallel // /// [default: 4] - // /// Configure with `jobs` config or `RTX_JOBS` env var - // #[clap(long, short, env = "RTX_JOBS", verbatim_doc_comment)] + // /// Configure with `jobs` config or `MISE_JOBS` env var + // #[clap(long, short, env = "MISE_JOBS", verbatim_doc_comment)] // pub jobs: Option, // // /// Read/write directly to stdin/stdout/stderr instead of by line - // /// Configure with `raw` config or `RTX_RAW` env var + // /// Configure with `raw` config or `MISE_RAW` env var // #[clap(long, short, verbatim_doc_comment)] // pub raw: bool, } @@ -76,7 +76,7 @@ impl Watch { if !ts.versions.contains_key("watchexec") { eprintln!("{}: {}", style("Error").red().bold(), err); eprintln!("{}: Install watchexec with:", style("Hint").bold()); - eprintln!(" rtx use -g watchexec@latest"); + eprintln!(" mise use -g watchexec@latest"); exit(1); } } @@ -105,7 +105,7 @@ impl Watch { args.extend(itertools::intersperse(globs, "-f".to_string()).collect::>()); } args.extend(self.args.clone()); - args.extend(["--".to_string(), "rtx".to_string(), "run".to_string()]); + args.extend(["--".to_string(), "mise".to_string(), "run".to_string()]); for arg in itertools::intersperse(tasks.iter().map(|t| t.name.as_str()), ":::") { args.push(arg.to_string()); } @@ -124,15 +124,15 @@ impl Watch { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx watch -t build + $ mise watch -t build Runs the "build" task. Will re-run the task when any of its sources change. Uses "sources" from the task definition to determine which files to watch. - $ rtx watch -t build --glob src/**/*.rs + $ mise watch -t build --glob src/**/*.rs Runs the "build" task but specify the files to watch with a glob pattern. This overrides the "sources" from the task definition. - $ rtx run -t build --clear + $ mise run -t build --clear Extra arguments are passed to watchexec. See `watchexec --help` for details. "# ); diff --git a/src/cli/where.rs b/src/cli/where.rs index e28bb3395..09c3c12d9 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -56,7 +56,7 @@ impl Where { .map(|tvr| tvr.resolve(plugin.as_ref(), Default::default(), false)) { Some(Ok(tv)) if plugin.is_version_installed(&tv) => { - rtxprintln!("{}", tv.install_path().to_string_lossy()); + miseprintln!("{}", tv.install_path().to_string_lossy()); Ok(()) } _ => Err(VersionNotInstalled( @@ -71,13 +71,13 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # Show the latest installed version of node # If it is is not installed, errors - $ rtx where node@20 - /home/jdx/.local/share/rtx/installs/node/20.0.0 + $ mise where node@20 + /home/jdx/.local/share/mise/installs/node/20.0.0 # Show the current, active install directory of node # Errors if node is not referenced in any .tool-version file - $ rtx where node - /home/jdx/.local/share/rtx/installs/node/20.0.0 + $ mise where node + /home/jdx/.local/share/mise/installs/node/20.0.0 "# ); diff --git a/src/cli/which.rs b/src/cli/which.rs index 3b832bf17..287281b24 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -23,7 +23,7 @@ pub struct Which { pub version: bool, /// Use a specific tool@version - /// e.g.: `rtx which npm --tool=node@20` + /// e.g.: `mise which npm --tool=node@20` #[clap(short, long, value_name = "TOOL@VERSION", value_parser = ToolArgParser, verbatim_doc_comment)] pub tool: Option, } @@ -35,21 +35,21 @@ impl Which { match ts.which(&self.bin_name) { Some((p, tv)) => { if self.version { - rtxprintln!("{}", tv.version); + miseprintln!("{}", tv.version); } else if self.plugin { - rtxprintln!("{p}"); + miseprintln!("{p}"); } else { let path = p.which(&tv, &self.bin_name)?; - rtxprintln!("{}", path.unwrap().display()); + miseprintln!("{}", path.unwrap().display()); } Ok(()) } None => { if self.has_shim(&self.bin_name) { - bail!("{} is an rtx bin however it is not currently active. Use `rtx use` to activate it in this directory.", self.bin_name) + bail!("{} is an mise bin however it is not currently active. Use `mise use` to activate it in this directory.", self.bin_name) } else { bail!( - "{} is not an rtx bin. Perhaps you need to install it first.", + "{} is not an mise bin. Perhaps you need to install it first.", self.bin_name ) } @@ -72,11 +72,11 @@ impl Which { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ rtx which node - /home/username/.local/share/rtx/installs/node/20.0.0/bin/node - $ rtx which node --plugin + $ mise which node + /home/username/.local/share/mise/installs/node/20.0.0/bin/node + $ mise which node --plugin node - $ rtx which node --version + $ mise which node --version 20.0.0 "# ); diff --git a/src/cmd.rs b/src/cmd.rs index 3a36d6e76..2da1ae1f6 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -27,7 +27,7 @@ use crate::ui::progress_report::SingleReport; /// /// ``` /// use std::path::Path; -/// use rtx::cmd; +/// use mise::cmd; /// /// let arg1 = "foo"; /// let arg2 = "bar".to_owned(); @@ -58,7 +58,7 @@ macro_rules! cmd { /// /// ``` /// use std::path::Path; -/// use rtx::cmd; +/// use mise::cmd; /// /// let arg1 = "foo"; /// let arg2 = "bar".to_owned(); diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/mise_toml.rs similarity index 96% rename from src/config/config_file/rtx_toml.rs rename to src/config/config_file/mise_toml.rs index 4ea7b8cd5..a8e6d7348 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -25,7 +25,7 @@ use crate::ui::{prompt, style}; use crate::{dirs, env, file, parse_error}; #[derive(Default)] -pub struct RtxToml { +pub struct MiseToml { context: Context, path: PathBuf, toolset: Toolset, @@ -41,7 +41,7 @@ pub struct RtxToml { is_trusted: Mutex>, } -impl RtxToml { +impl MiseToml { pub fn init(path: &Path) -> Self { let mut context = BASE_CONTEXT.clone(); context.insert("config_root", path.parent().unwrap().to_str().unwrap()); @@ -50,7 +50,7 @@ impl RtxToml { context, is_trusted: Mutex::new(None), toolset: Toolset { - source: Some(ToolSource::RtxToml(path.to_path_buf())), + source: Some(ToolSource::MiseToml(path.to_path_buf())), ..Default::default() }, ..Default::default() @@ -291,7 +291,7 @@ impl RtxToml { v: &Item, plugin_name: &PluginName, ) -> Result { - let source = ToolSource::RtxToml(self.path.clone()); + let source = ToolSource::MiseToml(self.path.clone()); let mut tool_version_list = ToolVersionList::new(plugin_name.to_string(), source); match v { @@ -613,7 +613,7 @@ impl RtxToml { if cmd != "hook-env" { let ans = prompt::confirm(format!( "{} {} is not trusted. Trust it?", - style::eyellow("rtx"), + style::eyellow("mise"), style::epath(&self.path) ))?; if ans { @@ -635,9 +635,9 @@ impl RtxToml { } } -impl ConfigFile for RtxToml { +impl ConfigFile for MiseToml { fn get_type(&self) -> ConfigFileType { - ConfigFileType::RtxToml + ConfigFileType::MiseToml } fn get_path(&self) -> &Path { @@ -652,8 +652,8 @@ impl ConfigFile for RtxToml { dir if dir.starts_with(*dirs::CONFIG) => None, dir if dir.starts_with(*dirs::SYSTEM) => None, dir if dir == *dirs::HOME => None, - dir if !filename.starts_with('.') && dir.ends_with("/.rtx") => dir.parent(), - dir if !filename.starts_with('.') && dir.ends_with("/.config/rtx") => { + dir if !filename.starts_with('.') && dir.ends_with("/.mise") => dir.parent(), + dir if !filename.starts_with('.') && dir.ends_with("/.config/mise") => { dir.parent().unwrap().parent() } dir => Some(dir), @@ -794,10 +794,10 @@ impl ConfigFile for RtxToml { } } -impl Debug for RtxToml { +impl Debug for MiseToml { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let tools = self.toolset.to_string(); - let title = format!("RtxToml({}): {tools}", &display_path(&self.path)); + let title = format!("MiseToml({}): {tools}", &display_path(&self.path)); let mut d = f.debug_struct(&title); // d.field("is_trusted", &self.is_trusted); if let Ok(settings) = self.settings() { @@ -826,7 +826,7 @@ impl Debug for RtxToml { } } -impl Clone for RtxToml { +impl Clone for MiseToml { fn clone(&self) -> Self { Self { context: self.context.clone(), @@ -855,7 +855,7 @@ mod tests { #[test] fn test_fixture() { - let cf = RtxToml::from_file(&dirs::HOME.join("fixtures/.rtx.toml")).unwrap(); + let cf = MiseToml::from_file(&dirs::HOME.join("fixtures/.mise.toml")).unwrap(); assert_debug_snapshot!(cf.env()); assert_json_snapshot!(cf.settings().unwrap()); @@ -868,7 +868,7 @@ mod tests { #[test] fn test_env() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" [env] foo="bar" @@ -892,8 +892,8 @@ mod tests { #[test] fn test_path_dirs() { with_settings!({ - let p = dirs::HOME.join("fixtures/.rtx.toml"); - let mut cf = RtxToml::init(&p); + let p = dirs::HOME.join("fixtures/.mise.toml"); + let mut cf = MiseToml::init(&p); cf.parse(&formatdoc! {r#" env_path=["/foo", "./bar"] [env] @@ -916,7 +916,7 @@ mod tests { #[test] fn test_set_alias() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" [alias.node] 16 = "16.0.0" @@ -935,7 +935,7 @@ mod tests { #[test] fn test_remove_alias() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" [alias.node] 16 = "16.0.0" @@ -957,7 +957,7 @@ mod tests { #[test] fn test_replace_versions() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" [tools] node = ["16.0.0", "18.0.0"] @@ -977,7 +977,7 @@ mod tests { #[test] fn test_remove_plugin() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" [tools] node = ["16.0.0", "18.0.0"] @@ -994,7 +994,7 @@ mod tests { #[test] fn test_update_setting() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true @@ -1013,7 +1013,7 @@ mod tests { #[test] fn test_remove_setting() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" [settings] legacy_version_file = true @@ -1026,7 +1026,7 @@ mod tests { #[test] fn test_fail_with_unknown_key() { - let mut cf = RtxToml::init(PathBuf::from("/tmp/.rtx.toml").as_path()); + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); let err = cf .parse(&formatdoc! {r#" invalid_key = true diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index e81121d46..a1724d067 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -9,7 +9,7 @@ use confique::Partial; use tool_versions::ToolVersions; use crate::cli::args::tool::ToolArg; -use crate::config::config_file::rtx_toml::RtxToml; +use crate::config::config_file::mise_toml::MiseToml; use crate::config::settings::SettingsPartial; use crate::config::{global_config_files, system_config_files, AliasMap, Config, Settings}; use crate::file::{display_path, replace_path}; @@ -21,13 +21,13 @@ use crate::toolset::{ToolVersionList, Toolset}; use crate::{dirs, env, file}; pub mod legacy_version; -pub mod rtx_toml; +pub mod mise_toml; pub mod toml; pub mod tool_versions; #[derive(Debug, PartialEq)] pub enum ConfigFileType { - RtxToml, + MiseToml, ToolVersions, LegacyVersion, } @@ -37,11 +37,11 @@ pub trait ConfigFile: Debug + Send + Sync { fn get_path(&self) -> &Path; /// gets the project directory for the config /// if it's a global/system config, returns None - /// files like ~/src/foo/.rtx/config.toml will return ~/src/foo - /// and ~/src/foo/.rtx.config.toml will return None + /// files like ~/src/foo/.mise/config.toml will return ~/src/foo + /// and ~/src/foo/.mise.config.toml will return None fn project_root(&self) -> Option<&Path> { let p = self.get_path(); - if env::RTX_CONFIG_FILE.as_ref().is_some_and(|f| f == p) { + if env::MISE_CONFIG_FILE.as_ref().is_some_and(|f| f == p) { return None; } match p.parent() { @@ -133,7 +133,7 @@ impl dyn ConfigFile { Ok(()) } - /// this is for `rtx local|global TOOL` which will display the version instead of setting it + /// this is for `mise local|global TOOL` which will display the version instead of setting it /// it's only valid to use a single tool in this case /// returns "true" if the tool was displayed which means the CLI should exit pub fn display_runtime(&self, runtimes: &[ToolArg]) -> Result { @@ -155,10 +155,10 @@ impl dyn ConfigFile { .iter() .map(|(tvr, _)| tvr.version()) .collect::>(); - rtxprintln!("{}", tvl.join(" ")); + miseprintln!("{}", tvl.join(" ")); return Ok(true); } - // check for something like `rtx local node python@latest` which is invalid + // check for something like `mise local node python@latest` which is invalid if runtimes.iter().any(|r| r.tvr.is_none()) { return Err(eyre!("invalid input, specify a version for each tool. Or just specify one tool to print the current version")); } @@ -168,7 +168,7 @@ impl dyn ConfigFile { fn init(path: &Path) -> Box { match detect_config_file_type(path) { - Some(ConfigFileType::RtxToml) => Box::new(RtxToml::init(path)), + Some(ConfigFileType::MiseToml) => Box::new(MiseToml::init(path)), Some(ConfigFileType::ToolVersions) => Box::new(ToolVersions::init(path)), _ => panic!("Unknown config file type: {}", path.display()), } @@ -184,10 +184,10 @@ pub fn parse_or_init(path: &Path) -> Result> { pub fn parse(path: &Path) -> Result> { match detect_config_file_type(path) { - Some(ConfigFileType::RtxToml) => Ok(Box::new(RtxToml::from_file(path)?)), + Some(ConfigFileType::MiseToml) => Ok(Box::new(MiseToml::from_file(path)?)), Some(ConfigFileType::ToolVersions) => Ok(Box::new(ToolVersions::from_file(path)?)), #[allow(clippy::box_default)] - _ => Ok(Box::new(RtxToml::default())), + _ => Ok(Box::new(MiseToml::default())), } } @@ -231,9 +231,9 @@ fn trust_path(path: &Path) -> PathBuf { fn detect_config_file_type(path: &Path) -> Option { match path.file_name().unwrap().to_str().unwrap() { - f if f.ends_with(".toml") => Some(ConfigFileType::RtxToml), - f if env::RTX_DEFAULT_CONFIG_FILENAME.as_str() == f => Some(ConfigFileType::RtxToml), - f if env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() == f => { + f if f.ends_with(".toml") => Some(ConfigFileType::MiseToml), + f if env::MISE_DEFAULT_CONFIG_FILENAME.as_str() == f => Some(ConfigFileType::MiseToml), + f if env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() == f => { Some(ConfigFileType::ToolVersions) } _ => None, @@ -271,7 +271,7 @@ mod tests { ); assert_eq!( detect_config_file_type(Path::new("/foo/bar/.tool-versions.toml")), - Some(ConfigFileType::RtxToml) + Some(ConfigFileType::MiseToml) ); } } diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap similarity index 51% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap index 4b149823d..bdd6c20fd 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.dump() --- [env] diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap new file mode 100644 index 000000000..7f358280f --- /dev/null +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/mise_toml.rs +expression: cf +--- +/tmp/.mise.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap similarity index 92% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap index f7b8a0c72..936c812b5 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap @@ -1,8 +1,8 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf --- -RtxToml(/tmp/.rtx.toml): { +MiseToml(/tmp/.mise.toml): { settings: Object { "always_keep_download": Null, "always_keep_install": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap similarity index 94% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap index aed7a5ce4..4efde2d47 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.settings().unwrap() --- { diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap similarity index 65% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap index 0c3174970..147d72fb7 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.plugins() --- { diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap similarity index 85% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap index ab5e9775b..a4d76e4fa 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: "replace_path(&format!(\"{:#?}\", cf.toolset))" --- Toolset { @@ -16,8 +16,8 @@ Toolset { {}, ), ], - source: RtxToml( - "~/fixtures/.rtx.toml", + source: MiseToml( + "~/fixtures/.mise.toml", ), }, "node": ToolVersionList { @@ -53,8 +53,8 @@ Toolset { {}, ), ], - source: RtxToml( - "~/fixtures/.rtx.toml", + source: MiseToml( + "~/fixtures/.mise.toml", ), }, "jq": ToolVersionList { @@ -69,8 +69,8 @@ Toolset { {}, ), ], - source: RtxToml( - "~/fixtures/.rtx.toml", + source: MiseToml( + "~/fixtures/.mise.toml", ), }, "shellcheck": ToolVersionList { @@ -85,8 +85,8 @@ Toolset { {}, ), ], - source: RtxToml( - "~/fixtures/.rtx.toml", + source: MiseToml( + "~/fixtures/.mise.toml", ), }, "python": ToolVersionList { @@ -110,14 +110,14 @@ Toolset { {}, ), ], - source: RtxToml( - "~/fixtures/.rtx.toml", + source: MiseToml( + "~/fixtures/.mise.toml", ), }, }, source: Some( - RtxToml( - "~/fixtures/.rtx.toml", + MiseToml( + "~/fixtures/.mise.toml", ), ), disable_tools: {}, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap similarity index 66% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap index c76dd3fff..149ac517c 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.alias --- { diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap similarity index 84% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap index 73fa61186..afcbf5f57 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap @@ -1,8 +1,8 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: "replace_path(&format!(\"{:#?}\", &cf))" --- -RtxToml(~/fixtures/.rtx.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { +MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { settings: Object { "always_keep_download": Null, "always_keep_install": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture.snap similarity index 58% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture.snap index 7caa22cf7..48bcd6c18 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__fixture.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.env() --- { diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-3.snap similarity index 62% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-3.snap index 769507ed1..e71d936af 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-3.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.dump() --- env_path=["/foo", "./bar"] diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap new file mode 100644 index 000000000..5ab096ef2 --- /dev/null +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/mise_toml.rs +expression: cf +--- +~/fixtures/.mise.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap similarity index 92% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap index 2af5c6c37..826d6a3d5 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap @@ -1,8 +1,8 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf --- -RtxToml(~/fixtures/.rtx.toml): { +MiseToml(~/fixtures/.mise.toml): { settings: Object { "always_keep_download": Null, "always_keep_install": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-2.snap similarity index 56% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-2.snap index e34c0b3bd..9fd8dee90 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-2.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.dump() --- [alias.node] diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap new file mode 100644 index 000000000..7f358280f --- /dev/null +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/mise_toml.rs +expression: cf +--- +/tmp/.mise.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap similarity index 92% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index 985c19094..7642f96fc 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -1,8 +1,8 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf --- -RtxToml(/tmp/.rtx.toml): { +MiseToml(/tmp/.mise.toml): { settings: Object { "always_keep_download": Null, "always_keep_install": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias.snap similarity index 63% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias.snap index 08e7e7ca3..31bed0d01 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.alias --- { diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-2.snap new file mode 100644 index 000000000..a2587ae1e --- /dev/null +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-2.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/mise_toml.rs +expression: cf.dump() +--- + diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-3.snap new file mode 100644 index 000000000..7f358280f --- /dev/null +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-3.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/mise_toml.rs +expression: cf +--- +/tmp/.mise.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap similarity index 91% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap index efa54ab41..a849cd1e1 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap @@ -1,8 +1,8 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf --- -RtxToml(/tmp/.rtx.toml): { +MiseToml(/tmp/.mise.toml): { settings: Object { "always_keep_download": Null, "always_keep_install": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin.snap similarity index 56% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin.snap index 81b912b3a..08250fc43 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin.snap @@ -1,12 +1,12 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.toolset --- Toolset { versions: {}, source: Some( - RtxToml( - "/tmp/.rtx.toml", + MiseToml( + "/tmp/.mise.toml", ), ), disable_tools: {}, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-2.snap similarity index 60% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-2.snap index d09f9ef21..3617f53f5 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-2.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.dump() --- [tools] diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-3.snap new file mode 100644 index 000000000..7b00c4780 --- /dev/null +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-3.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/mise_toml.rs +expression: cf +--- +/tmp/.mise.toml: node@16.0.1 node@18.0.1 diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap similarity index 89% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap index 44f34f4ae..278768a4d 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap @@ -1,8 +1,8 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf --- -RtxToml(/tmp/.rtx.toml): node@16.0.1 node@18.0.1 { +MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 { settings: Object { "always_keep_download": Null, "always_keep_install": Null, diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions.snap similarity index 80% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions.snap index 05bd9410b..3bed4e77e 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.toolset --- Toolset { @@ -23,14 +23,14 @@ Toolset { {}, ), ], - source: RtxToml( - "/tmp/.rtx.toml", + source: MiseToml( + "/tmp/.mise.toml", ), }, }, source: Some( - RtxToml( - "/tmp/.rtx.toml", + MiseToml( + "/tmp/.mise.toml", ), ), disable_tools: {}, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap new file mode 100644 index 000000000..7f358280f --- /dev/null +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap @@ -0,0 +1,5 @@ +--- +source: src/config/config_file/mise_toml.rs +expression: cf +--- +/tmp/.mise.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias.snap similarity index 79% rename from src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias.snap index 824092020..b5320ecc7 100644 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias.snap @@ -1,5 +1,5 @@ --- -source: src/config/config_file/rtx_toml.rs +source: src/config/config_file/mise_toml.rs expression: cf.alias --- { diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-4.snap deleted file mode 100644 index 8a3782775..000000000 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__env-4.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/rtx_toml.rs -expression: cf ---- -/tmp/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap deleted file mode 100644 index 74cc3c1ca..000000000 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__path_dirs-4.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/rtx_toml.rs -expression: cf ---- -~/fixtures/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap deleted file mode 100644 index 8a3782775..000000000 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_alias-3.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/rtx_toml.rs -expression: cf ---- -/tmp/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap deleted file mode 100644 index 54880bbc6..000000000 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-2.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/rtx_toml.rs -expression: cf.dump() ---- - diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap deleted file mode 100644 index 8a3782775..000000000 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__remove_plugin-3.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/rtx_toml.rs -expression: cf ---- -/tmp/.rtx.toml: diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap deleted file mode 100644 index 4b1488a04..000000000 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__replace_versions-3.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/rtx_toml.rs -expression: cf ---- -/tmp/.rtx.toml: node@16.0.1 node@18.0.1 diff --git a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap b/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap deleted file mode 100644 index 8a3782775..000000000 --- a/src/config/config_file/snapshots/rtx__config__config_file__rtx_toml__tests__set_alias-2.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/rtx_toml.rs -expression: cf ---- -/tmp/.rtx.toml: diff --git a/src/config/mod.rs b/src/config/mod.rs index d2e02a862..3f1b521b5 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -15,7 +15,7 @@ use rayon::prelude::*; pub use settings::Settings; use crate::config::config_file::legacy_version::LegacyVersionFile; -use crate::config::config_file::rtx_toml::RtxToml; +use crate::config::config_file::mise_toml::MiseToml; use crate::config::config_file::ConfigFile; use crate::config::tracking::Tracker; use crate::file::display_path; @@ -40,7 +40,7 @@ pub struct Config { pub config_files: ConfigMap, pub env: BTreeMap, pub env_sources: HashMap, - pub global_config: RtxToml, + pub global_config: MiseToml, pub path_dirs: Vec, pub project_root: Option, all_aliases: OnceCell, @@ -65,7 +65,7 @@ impl Config { Ok(config) } pub fn load() -> Result { - let global_config = load_rtxrc()?; + let global_config = load_miserc()?; // TODO: read system config settings Settings::add_partial(global_config.settings()?); let settings = Settings::try_get()?; @@ -124,7 +124,7 @@ impl Config { } pub fn is_activated(&self) -> bool { - env::var("__RTX_DIFF").is_ok() + env::var("__MISE_DIFF").is_ok() } pub fn resolve_alias(&self, plugin_name: &str, v: &str) -> Result { @@ -206,8 +206,8 @@ impl Config { .flat_map(|cf| { match cf.project_root() { Some(pr) => vec![ - pr.join(".rtx").join("tasks"), - pr.join(".config").join("rtx").join("tasks"), + pr.join(".mise").join("tasks"), + pr.join(".config").join("mise").join("tasks"), ], None => vec![], } @@ -281,16 +281,16 @@ fn get_project_root(config_files: &ConfigMap) -> Option { .map(|pr| pr.to_path_buf()) } -fn load_rtxrc() -> Result { - let settings_path = env::RTX_CONFIG_FILE +fn load_miserc() -> Result { + let settings_path = env::MISE_CONFIG_FILE .clone() .unwrap_or(dirs::CONFIG.join("config.toml")); match settings_path.exists() { false => { trace!("settings does not exist {:?}", settings_path); - Ok(RtxToml::init(&settings_path)) + Ok(MiseToml::init(&settings_path)) } - true => RtxToml::from_file(&settings_path) + true => MiseToml::from_file(&settings_path) .wrap_err_with(|| eyre!("Error parsing {}", display_path(&settings_path))), } } @@ -348,30 +348,32 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap> = Lazy::new(|| { - let mut filenames = vec![ - env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.clone(), - env::RTX_DEFAULT_CONFIG_FILENAME.clone(), - ]; - if *env::RTX_DEFAULT_CONFIG_FILENAME == ".rtx.toml" { - filenames.insert(0, ".rtx/config.toml".into()); - filenames.insert(0, ".config/rtx.toml".into()); - filenames.insert(0, ".config/rtx/config.toml".into()); - filenames.push(".config/rtx/config.local.toml".into()); - filenames.push(".config/rtx.local.toml".into()); - filenames.push(".rtx/config.local.toml".into()); - filenames.push(".rtx.local.toml".into()); - if let Some(env) = &*env::RTX_ENV { - filenames.push(format!(".config/rtx/config.{env}.toml")); - filenames.push(format!(".config/rtx.{env}.toml")); - filenames.push(format!(".rtx/config.{env}.local.toml")); - filenames.push(format!(".rtx.{env}.toml")); - filenames.push(format!(".config/rtx/config.{env}.local.toml")); - filenames.push(format!(".config/rtx.{env}.local.toml")); - filenames.push(format!(".rtx/config.{env}.local.toml")); - filenames.push(format!(".rtx.{env}.local.toml")); + let mut filenames = std::collections::VecDeque::from([ + env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.clone(), + env::MISE_DEFAULT_CONFIG_FILENAME.clone(), + ]); + if *env::MISE_DEFAULT_CONFIG_FILENAME == ".mise.toml" { + filenames.push_front(".rtx.toml".into()); + filenames.push_front(".rtx.local.toml".into()); + filenames.push_front(".mise/config.toml".into()); + filenames.push_front(".config/mise.toml".into()); + filenames.push_front(".config/mise/config.toml".into()); + filenames.push_back(".config/mise/config.local.toml".into()); + filenames.push_back(".config/mise.local.toml".into()); + filenames.push_back(".mise/config.local.toml".into()); + filenames.push_back(".mise.local.toml".into()); + if let Some(env) = &*env::MISE_ENV { + filenames.push_back(format!(".config/mise/config.{env}.toml")); + filenames.push_back(format!(".config/mise.{env}.toml")); + filenames.push_back(format!(".mise/config.{env}.local.toml")); + filenames.push_back(format!(".mise.{env}.toml")); + filenames.push_back(format!(".config/mise/config.{env}.local.toml")); + filenames.push_back(format!(".config/mise.{env}.local.toml")); + filenames.push_back(format!(".mise/config.{env}.local.toml")); + filenames.push_back(format!(".mise.{env}.local.toml")); } } - filenames + filenames.into_iter().collect() }); pub fn load_config_paths(config_filenames: &[String]) -> Vec { @@ -388,23 +390,23 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { config_files.into_iter().unique().collect() } -fn get_global_rtx_toml() -> PathBuf { - env::RTX_CONFIG_FILE +fn get_global_mise_toml() -> PathBuf { + env::MISE_CONFIG_FILE .clone() .unwrap_or_else(|| dirs::CONFIG.join("config.toml")) } pub fn global_config_files() -> Vec { let mut config_files = vec![]; - if env::RTX_CONFIG_FILE.is_none() && !*env::RTX_USE_TOML { - // only add ~/.tool-versions if RTX_CONFIG_FILE is not set + if env::MISE_CONFIG_FILE.is_none() && !*env::MISE_USE_TOML { + // only add ~/.tool-versions if MISE_CONFIG_FILE is not set // because that's how the user overrides the default - let home_config = dirs::HOME.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); + let home_config = dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); if home_config.is_file() { config_files.push(home_config); } }; - let global_config = get_global_rtx_toml(); + let global_config = get_global_mise_toml(); if global_config.is_file() { config_files.push(global_config); } diff --git a/src/config/settings.rs b/src/config/settings.rs index 0bb3f907a..108b91b41 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -16,53 +16,53 @@ use serde_derive::Serialize; #[derive(Config, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize)))] pub struct Settings { - #[config(env = "RTX_EXPERIMENTAL", default = false)] + #[config(env = "MISE_EXPERIMENTAL", default = false)] pub experimental: bool, - #[config(env = "RTX_COLOR", default = true)] + #[config(env = "MISE_COLOR", default = true)] pub color: bool, - #[config(env = "RTX_ALWAYS_KEEP_DOWNLOAD", default = false)] + #[config(env = "MISE_ALWAYS_KEEP_DOWNLOAD", default = false)] pub always_keep_download: bool, - #[config(env = "RTX_ALWAYS_KEEP_INSTALL", default = false)] + #[config(env = "MISE_ALWAYS_KEEP_INSTALL", default = false)] pub always_keep_install: bool, - #[config(env = "RTX_LEGACY_VERSION_FILE", default = true)] + #[config(env = "MISE_LEGACY_VERSION_FILE", default = true)] pub legacy_version_file: bool, - #[config(env = "RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] + #[config(env = "MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, - #[config(env = "RTX_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION", default = "7d")] + #[config(env = "MISE_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION", default = "7d")] pub plugin_autoupdate_last_check_duration: String, - #[config(env = "RTX_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] + #[config(env = "MISE_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] pub trusted_config_paths: BTreeSet, - #[config(env = "RTX_LOG_LEVEL", default = "info")] + #[config(env = "MISE_LOG_LEVEL", default = "info")] pub log_level: String, - #[config(env = "RTX_TRACE", default = false)] + #[config(env = "MISE_TRACE", default = false)] pub trace: bool, - #[config(env = "RTX_DEBUG", default = false)] + #[config(env = "MISE_DEBUG", default = false)] pub debug: bool, - #[config(env = "RTX_VERBOSE", default = false)] + #[config(env = "MISE_VERBOSE", default = false)] pub verbose: bool, - #[config(env = "RTX_QUIET", default = false)] + #[config(env = "MISE_QUIET", default = false)] pub quiet: bool, - #[config(env = "RTX_ASDF_COMPAT", default = false)] + #[config(env = "MISE_ASDF_COMPAT", default = false)] pub asdf_compat: bool, - #[config(env = "RTX_JOBS", default = 4)] + #[config(env = "MISE_JOBS", default = 4)] pub jobs: usize, - #[config(env = "RTX_SHORTHANDS_FILE")] + #[config(env = "MISE_SHORTHANDS_FILE")] pub shorthands_file: Option, - #[config(env = "RTX_DISABLE_DEFAULT_SHORTHANDS", default = false)] + #[config(env = "MISE_DISABLE_DEFAULT_SHORTHANDS", default = false)] pub disable_default_shorthands: bool, - #[config(env = "RTX_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] + #[config(env = "MISE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub disable_tools: BTreeSet, - #[config(env = "RTX_RAW", default = false)] + #[config(env = "MISE_RAW", default = false)] pub raw: bool, - #[config(env = "RTX_YES", default = false)] + #[config(env = "MISE_YES", default = false)] pub yes: bool, - #[config(env = "RTX_TASK_OUTPUT")] + #[config(env = "MISE_TASK_OUTPUT")] pub task_output: Option, - #[config(env = "RTX_NOT_FOUND_AUTO_INSTALL", default = true)] + #[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)] pub not_found_auto_install: bool, #[config(env = "CI", default = false)] pub ci: bool, - #[config(env = "RTX_ENV_FILE")] + #[config(env = "MISE_ENV_FILE")] pub env_file: Option, pub cd: Option, } @@ -198,7 +198,7 @@ impl Settings { pub fn ensure_experimental(&self) -> Result<()> { let msg = - "This command is experimental. Enable it with `rtx settings set experimental true`"; + "This command is experimental. Enable it with `mise settings set experimental true`"; ensure!(self.experimental, msg); Ok(()) } diff --git a/src/config/snapshots/rtx__config__tests__load.snap b/src/config/snapshots/mise__config__tests__load.snap similarity index 100% rename from src/config/snapshots/rtx__config__tests__load.snap rename to src/config/snapshots/mise__config__tests__load.snap diff --git a/src/dirs.rs b/src/dirs.rs index 7815232f4..ede1d6e0a 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -5,11 +5,11 @@ use once_cell::sync::Lazy; use crate::env; pub static HOME: Lazy<&Path> = Lazy::new(|| &env::HOME); -pub static DATA: Lazy<&Path> = Lazy::new(|| &env::RTX_DATA_DIR); -pub static CACHE: Lazy<&Path> = Lazy::new(|| &env::RTX_CACHE_DIR); -pub static CONFIG: Lazy<&Path> = Lazy::new(|| &env::RTX_CONFIG_DIR); -pub static STATE: Lazy<&Path> = Lazy::new(|| &env::RTX_STATE_DIR); -pub static SYSTEM: Lazy<&Path> = Lazy::new(|| &env::RTX_SYSTEM_DIR); +pub static DATA: Lazy<&Path> = Lazy::new(|| &env::MISE_DATA_DIR); +pub static CACHE: Lazy<&Path> = Lazy::new(|| &env::MISE_CACHE_DIR); +pub static CONFIG: Lazy<&Path> = Lazy::new(|| &env::MISE_CONFIG_DIR); +pub static STATE: Lazy<&Path> = Lazy::new(|| &env::MISE_STATE_DIR); +pub static SYSTEM: Lazy<&Path> = Lazy::new(|| &env::MISE_SYSTEM_DIR); pub static PLUGINS: Lazy = Lazy::new(|| DATA.join("plugins")); pub static DOWNLOADS: Lazy = Lazy::new(|| DATA.join("downloads")); diff --git a/src/env.rs b/src/env.rs index 106665321..d4947f26d 100644 --- a/src/env.rs +++ b/src/env.rs @@ -32,39 +32,39 @@ pub static XDG_DATA_HOME: Lazy = pub static XDG_STATE_HOME: Lazy = Lazy::new(|| var_path("XDG_STATE_HOME").unwrap_or_else(|| HOME.join(".local/state"))); -pub static RTX_CACHE_DIR: Lazy = - Lazy::new(|| var_path("RTX_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("rtx"))); -pub static RTX_CONFIG_DIR: Lazy = - Lazy::new(|| var_path("RTX_CONFIG_DIR").unwrap_or_else(|| XDG_CONFIG_HOME.join("rtx"))); -pub static RTX_DATA_DIR: Lazy = - Lazy::new(|| var_path("RTX_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("rtx"))); -pub static RTX_STATE_DIR: Lazy = - Lazy::new(|| var_path("RTX_STATE_DIR").unwrap_or_else(|| XDG_STATE_HOME.join("rtx"))); -pub static RTX_TMP_DIR: Lazy = - Lazy::new(|| var_path("RTX_TMP_DIR").unwrap_or_else(|| temp_dir().join("rtx"))); -pub static RTX_SYSTEM_DIR: Lazy = - Lazy::new(|| var_path("RTX_SYSTEM_DIR").unwrap_or_else(|| PathBuf::from("/etc/rtx"))); - -pub static RTX_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy = Lazy::new(|| { - var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) +pub static MISE_CACHE_DIR: Lazy = + Lazy::new(|| var_path("MISE_CACHE_DIR").unwrap_or_else(|| XDG_CACHE_HOME.join("mise"))); +pub static MISE_CONFIG_DIR: Lazy = + Lazy::new(|| var_path("MISE_CONFIG_DIR").unwrap_or_else(|| XDG_CONFIG_HOME.join("mise"))); +pub static MISE_DATA_DIR: Lazy = + Lazy::new(|| var_path("MISE_DATA_DIR").unwrap_or_else(|| XDG_DATA_HOME.join("mise"))); +pub static MISE_STATE_DIR: Lazy = + Lazy::new(|| var_path("MISE_STATE_DIR").unwrap_or_else(|| XDG_STATE_HOME.join("mise"))); +pub static MISE_TMP_DIR: Lazy = + Lazy::new(|| var_path("MISE_TMP_DIR").unwrap_or_else(|| temp_dir().join("mise"))); +pub static MISE_SYSTEM_DIR: Lazy = + Lazy::new(|| var_path("MISE_SYSTEM_DIR").unwrap_or_else(|| PathBuf::from("/etc/mise"))); + +pub static MISE_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy = Lazy::new(|| { + var("MISE_DEFAULT_TOOL_VERSIONS_FILENAME").unwrap_or_else(|_| ".tool-versions".into()) }); -pub static RTX_DEFAULT_CONFIG_FILENAME: Lazy = - Lazy::new(|| var("RTX_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".rtx.toml".into())); -pub static RTX_ENV: Lazy> = - Lazy::new(|| var("RTX_ENV").or_else(|_| var("RTX_ENVIRONMENT")).ok()); -pub static RTX_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("RTX_CONFIG_FILE")); -pub static RTX_USE_TOML: Lazy = Lazy::new(|| var_is_true("RTX_USE_TOML")); -pub static RTX_BIN: Lazy = Lazy::new(|| { - var_path("RTX_BIN") +pub static MISE_DEFAULT_CONFIG_FILENAME: Lazy = + Lazy::new(|| var("MISE_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".mise.toml".into())); +pub static MISE_ENV: Lazy> = + Lazy::new(|| var("MISE_ENV").or_else(|_| var("MISE_ENVIRONMENT")).ok()); +pub static MISE_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("MISE_CONFIG_FILE")); +pub static MISE_USE_TOML: Lazy = Lazy::new(|| var_is_true("MISE_USE_TOML")); +pub static MISE_BIN: Lazy = Lazy::new(|| { + var_path("MISE_BIN") .or_else(|| current_exe().ok()) - .unwrap_or_else(|| "rtx".into()) + .unwrap_or_else(|| "mise".into()) }); pub static ARGV0: Lazy = Lazy::new(|| ARGS.read().unwrap()[0].to_string()); -pub static RTX_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0)); -pub static RTX_LOG_FILE: Lazy> = Lazy::new(|| var_path("RTX_LOG_FILE")); -pub static RTX_LOG_FILE_LEVEL: Lazy> = Lazy::new(log_file_level); -pub static RTX_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { - var_duration("RTX_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) +pub static MISE_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0)); +pub static MISE_LOG_FILE: Lazy> = Lazy::new(|| var_path("MISE_LOG_FILE")); +pub static MISE_LOG_FILE_LEVEL: Lazy> = Lazy::new(log_file_level); +pub static MISE_FETCH_REMOTE_VERSIONS_TIMEOUT: Lazy = Lazy::new(|| { + var_duration("MISE_FETCH_REMOTE_VERSIONS_TIMEOUT").unwrap_or(Duration::from_secs(10)) }); #[cfg(test)] @@ -80,25 +80,25 @@ pub static TERM_WIDTH: Lazy = Lazy::new(|| { /// duration that remote version cache is kept for /// for "fast" commands (represented by PREFER_STALE), these are always -/// cached. For "slow" commands like `rtx ls-remote` or `rtx install`: -/// - if RTX_FETCH_REMOTE_VERSIONS_CACHE is set, use that -/// - if RTX_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY -pub static RTX_FETCH_REMOTE_VERSIONS_CACHE: Lazy> = Lazy::new(|| { +/// cached. For "slow" commands like `mise ls-remote` or `mise install`: +/// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is set, use that +/// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY +pub static MISE_FETCH_REMOTE_VERSIONS_CACHE: Lazy> = Lazy::new(|| { if *PREFER_STALE { None } else { - Some(var_duration("RTX_FETCH_REMOTE_VERSIONS_CACHE").unwrap_or(HOURLY)) + Some(var_duration("MISE_FETCH_REMOTE_VERSIONS_CACHE").unwrap_or(HOURLY)) } }); /// true if inside a script like bin/exec-env or bin/install /// used to prevent infinite loops -pub static __RTX_SCRIPT: Lazy = Lazy::new(|| var_is_true("__RTX_SCRIPT")); -pub static __RTX_DIFF: Lazy = Lazy::new(get_env_diff); -pub static __RTX_ORIG_PATH: Lazy> = Lazy::new(|| var("__RTX_ORIG_PATH").ok()); -pub static __RTX_WATCH: Lazy> = Lazy::new(|| match var("__RTX_WATCH") { +pub static __MISE_SCRIPT: Lazy = Lazy::new(|| var_is_true("__MISE_SCRIPT")); +pub static __MISE_DIFF: Lazy = Lazy::new(get_env_diff); +pub static __MISE_ORIG_PATH: Lazy> = Lazy::new(|| var("__MISE_ORIG_PATH").ok()); +pub static __MISE_WATCH: Lazy> = Lazy::new(|| match var("__MISE_WATCH") { Ok(raw) => deserialize_watches(raw) - .map_err(|e| warn!("Failed to deserialize __RTX_WATCH {e}")) + .map_err(|e| warn!("Failed to deserialize __MISE_WATCH {e}")) .ok(), _ => None, }); @@ -106,14 +106,14 @@ pub static CI: Lazy = Lazy::new(|| var_is_true("CI")); pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS.read().unwrap())); /// essentially, this is whether we show spinners or build output on runtime install pub static PRISTINE_ENV: Lazy> = - Lazy::new(|| get_pristine_env(&__RTX_DIFF, vars().collect())); + Lazy::new(|| get_pristine_env(&__MISE_DIFF, vars().collect())); pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH") { Some(path) => split_paths(path).collect(), None => vec![], }); pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); -pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| { - var_option_bool("RTX_ALL_COMPILE").unwrap_or_else(|| { +pub static MISE_ALL_COMPILE: Lazy = Lazy::new(|| { + var_option_bool("MISE_ALL_COMPILE").unwrap_or_else(|| { matches!( linux_distro().unwrap_or_default().as_str(), "alpine" | "nixos" @@ -123,69 +123,70 @@ pub static RTX_ALL_COMPILE: Lazy = Lazy::new(|| { #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); -pub static RTX_USE_VERSIONS_HOST: Lazy = Lazy::new(|| !var_is_false("RTX_USE_VERSIONS_HOST")); +pub static MISE_USE_VERSIONS_HOST: Lazy = + Lazy::new(|| !var_is_false("MISE_USE_VERSIONS_HOST")); // python -pub static RTX_PYENV_REPO: Lazy = Lazy::new(|| { - var("RTX_PYENV_REPO").unwrap_or_else(|_| "https://github.com/pyenv/pyenv.git".into()) +pub static MISE_PYENV_REPO: Lazy = Lazy::new(|| { + var("MISE_PYENV_REPO").unwrap_or_else(|_| "https://github.com/pyenv/pyenv.git".into()) }); -pub static RTX_PYTHON_PATCH_URL: Lazy> = - Lazy::new(|| var("RTX_PYTHON_PATCH_URL").ok()); -pub static RTX_PYTHON_PATCHES_DIRECTORY: Lazy> = - Lazy::new(|| var_path("RTX_PYTHON_PATCHES_DIRECTORY")); -pub static RTX_PYTHON_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { - var_path("RTX_PYTHON_DEFAULT_PACKAGES_FILE") +pub static MISE_PYTHON_PATCH_URL: Lazy> = + Lazy::new(|| var("MISE_PYTHON_PATCH_URL").ok()); +pub static MISE_PYTHON_PATCHES_DIRECTORY: Lazy> = + Lazy::new(|| var_path("MISE_PYTHON_PATCHES_DIRECTORY")); +pub static MISE_PYTHON_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("MISE_PYTHON_DEFAULT_PACKAGES_FILE") .unwrap_or_else(|| HOME.join(".default-python-packages")) }); pub static PYENV_ROOT: Lazy = Lazy::new(|| var_path("PYENV_ROOT").unwrap_or_else(|| HOME.join(".pyenv"))); // node -pub static RTX_NODE_MIRROR_URL: Lazy = Lazy::new(|| { - var_url("RTX_NODE_MIRROR_URL") +pub static MISE_NODE_MIRROR_URL: Lazy = Lazy::new(|| { + var_url("MISE_NODE_MIRROR_URL") .or_else(|| var_url("NODE_BUILD_MIRROR_URL")) .unwrap_or_else(|| Url::parse("https://nodejs.org/dist/").unwrap()) }); -pub static RTX_NODE_CONCURRENCY: Lazy> = Lazy::new(|| { - var("RTX_NODE_CONCURRENCY") +pub static MISE_NODE_CONCURRENCY: Lazy> = Lazy::new(|| { + var("MISE_NODE_CONCURRENCY") .ok() .and_then(|v| v.parse::().ok()) .map(|v| v.max(1)) .or_else(|| { - if *RTX_NODE_NINJA { + if *MISE_NODE_NINJA { None } else { Some(num_cpus::get_physical()) } }) }); -pub static RTX_NODE_MAKE: Lazy = - Lazy::new(|| var("RTX_NODE_MAKE").unwrap_or_else(|_| "make".into())); -pub static RTX_NODE_NINJA: Lazy = - Lazy::new(|| var_option_bool("RTX_NODE_NINJA").unwrap_or_else(is_ninja_on_path)); -pub static RTX_NODE_VERIFY: Lazy = Lazy::new(|| !var_is_false("RTX_NODE_VERIFY")); -pub static RTX_NODE_COMPILE: Lazy = Lazy::new(|| { - *RTX_ALL_COMPILE || var_is_true("RTX_NODE_COMPILE") || var_is_true("RTX_NODE_FORCE_COMPILE") +pub static MISE_NODE_MAKE: Lazy = + Lazy::new(|| var("MISE_NODE_MAKE").unwrap_or_else(|_| "make".into())); +pub static MISE_NODE_NINJA: Lazy = + Lazy::new(|| var_option_bool("MISE_NODE_NINJA").unwrap_or_else(is_ninja_on_path)); +pub static MISE_NODE_VERIFY: Lazy = Lazy::new(|| !var_is_false("MISE_NODE_VERIFY")); +pub static MISE_NODE_COMPILE: Lazy = Lazy::new(|| { + *MISE_ALL_COMPILE || var_is_true("MISE_NODE_COMPILE") || var_is_true("MISE_NODE_FORCE_COMPILE") }); -pub static RTX_NODE_CFLAGS: Lazy> = - Lazy::new(|| var("RTX_NODE_CFLAGS").or_else(|_| var("NODE_CFLAGS")).ok()); -pub static RTX_NODE_CONFIGURE_OPTS: Lazy> = Lazy::new(|| { - var("RTX_NODE_CONFIGURE_OPTS") +pub static MISE_NODE_CFLAGS: Lazy> = + Lazy::new(|| var("MISE_NODE_CFLAGS").or_else(|_| var("NODE_CFLAGS")).ok()); +pub static MISE_NODE_CONFIGURE_OPTS: Lazy> = Lazy::new(|| { + var("MISE_NODE_CONFIGURE_OPTS") .or_else(|_| var("NODE_CONFIGURE_OPTS")) .ok() }); -pub static RTX_NODE_MAKE_OPTS: Lazy> = Lazy::new(|| { - var("RTX_NODE_MAKE_OPTS") +pub static MISE_NODE_MAKE_OPTS: Lazy> = Lazy::new(|| { + var("MISE_NODE_MAKE_OPTS") .or_else(|_| var("NODE_MAKE_OPTS")) .ok() }); -pub static RTX_NODE_MAKE_INSTALL_OPTS: Lazy> = Lazy::new(|| { - var("RTX_NODE_MAKE_INSTALL_OPTS") +pub static MISE_NODE_MAKE_INSTALL_OPTS: Lazy> = Lazy::new(|| { + var("MISE_NODE_MAKE_INSTALL_OPTS") .or_else(|_| var("NODE_MAKE_INSTALL_OPTS")) .ok() }); -pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { - var_path("RTX_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { +pub static MISE_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("MISE_NODE_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| { let p = HOME.join(".default-nodejs-packages"); if p.exists() { return p; @@ -197,53 +198,53 @@ pub static RTX_NODE_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { HOME.join(".default-npm-packages") }) }); -pub static RTX_NODE_COREPACK: Lazy = Lazy::new(|| var_is_true("RTX_NODE_COREPACK")); +pub static MISE_NODE_COREPACK: Lazy = Lazy::new(|| var_is_true("MISE_NODE_COREPACK")); pub static NVM_DIR: Lazy = Lazy::new(|| var_path("NVM_DIR").unwrap_or_else(|| HOME.join(".nvm"))); pub static NODENV_ROOT: Lazy = Lazy::new(|| var_path("NODENV_ROOT").unwrap_or_else(|| HOME.join(".nodenv"))); // ruby -pub static RTX_RUBY_BUILD_REPO: Lazy = Lazy::new(|| { - var("RTX_RUBY_BUILD_REPO").unwrap_or_else(|_| "https://github.com/rbenv/ruby-build.git".into()) +pub static MISE_RUBY_BUILD_REPO: Lazy = Lazy::new(|| { + var("MISE_RUBY_BUILD_REPO").unwrap_or_else(|_| "https://github.com/rbenv/ruby-build.git".into()) }); -pub static RTX_RUBY_INSTALL_REPO: Lazy = Lazy::new(|| { - var("RTX_RUBY_INSTALL_REPO") +pub static MISE_RUBY_INSTALL_REPO: Lazy = Lazy::new(|| { + var("MISE_RUBY_INSTALL_REPO") .unwrap_or_else(|_| "https://github.com/postmodern/ruby-install.git".into()) }); -pub static RTX_RUBY_INSTALL: Lazy = Lazy::new(|| var_is_true("RTX_RUBY_INSTALL")); -pub static RTX_RUBY_APPLY_PATCHES: Lazy> = - Lazy::new(|| var("RTX_RUBY_APPLY_PATCHES").ok()); -pub static RTX_RUBY_VERBOSE_INSTALL: Lazy> = - Lazy::new(|| var_option_bool("RTX_RUBY_VERBOSE_INSTALL")); -pub static RTX_RUBY_INSTALL_OPTS: Lazy, shell_words::ParseError>> = - Lazy::new(|| shell_words::split(&var("RTX_RUBY_INSTALL_OPTS").unwrap_or_default())); -pub static RTX_RUBY_BUILD_OPTS: Lazy, shell_words::ParseError>> = - Lazy::new(|| shell_words::split(&var("RTX_RUBY_BUILD_OPTS").unwrap_or_default())); -pub static RTX_RUBY_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { - var_path("RTX_RUBY_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-gems")) +pub static MISE_RUBY_INSTALL: Lazy = Lazy::new(|| var_is_true("MISE_RUBY_INSTALL")); +pub static MISE_RUBY_APPLY_PATCHES: Lazy> = + Lazy::new(|| var("MISE_RUBY_APPLY_PATCHES").ok()); +pub static MISE_RUBY_VERBOSE_INSTALL: Lazy> = + Lazy::new(|| var_option_bool("MISE_RUBY_VERBOSE_INSTALL")); +pub static MISE_RUBY_INSTALL_OPTS: Lazy, shell_words::ParseError>> = + Lazy::new(|| shell_words::split(&var("MISE_RUBY_INSTALL_OPTS").unwrap_or_default())); +pub static MISE_RUBY_BUILD_OPTS: Lazy, shell_words::ParseError>> = + Lazy::new(|| shell_words::split(&var("MISE_RUBY_BUILD_OPTS").unwrap_or_default())); +pub static MISE_RUBY_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("MISE_RUBY_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-gems")) }); // go -pub static RTX_GO_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { - var_path("RTX_GO_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-go-packages")) +pub static MISE_GO_DEFAULT_PACKAGES_FILE: Lazy = Lazy::new(|| { + var_path("MISE_GO_DEFAULT_PACKAGES_FILE").unwrap_or_else(|| HOME.join(".default-go-packages")) }); -pub static RTX_GO_SKIP_CHECKSUM: Lazy = Lazy::new(|| var_is_true("RTX_GO_SKIP_CHECKSUM")); -pub static RTX_GO_REPO: Lazy = - Lazy::new(|| var("RTX_GO_REPO").unwrap_or_else(|_| "https://github.com/golang/go".into())); -pub static RTX_GO_DOWNLOAD_MIRROR: Lazy = Lazy::new(|| { - var("RTX_GO_DOWNLOAD_MIRROR").unwrap_or_else(|_| "https://dl.google.com/go".into()) +pub static MISE_GO_SKIP_CHECKSUM: Lazy = Lazy::new(|| var_is_true("MISE_GO_SKIP_CHECKSUM")); +pub static MISE_GO_REPO: Lazy = + Lazy::new(|| var("MISE_GO_REPO").unwrap_or_else(|_| "https://github.com/golang/go".into())); +pub static MISE_GO_DOWNLOAD_MIRROR: Lazy = Lazy::new(|| { + var("MISE_GO_DOWNLOAD_MIRROR").unwrap_or_else(|_| "https://dl.google.com/go".into()) }); -pub static RTX_GO_SET_GOROOT: Lazy> = - Lazy::new(|| var_option_bool("RTX_GO_SET_GOROOT")); -pub static RTX_GO_SET_GOPATH: Lazy> = - Lazy::new(|| var_option_bool("RTX_GO_SET_GOPATH")); +pub static MISE_GO_SET_GOROOT: Lazy> = + Lazy::new(|| var_option_bool("MISE_GO_SET_GOROOT")); +pub static MISE_GO_SET_GOPATH: Lazy> = + Lazy::new(|| var_option_bool("MISE_GO_SET_GOPATH")); fn get_env_diff() -> EnvDiff { let env = vars().collect::>(); - match env.get("__RTX_DIFF") { + match env.get("__MISE_DIFF") { Some(raw) => EnvDiff::deserialize(raw).unwrap_or_else(|err| { - warn!("Failed to deserialize __RTX_DIFF: {:#}", err); + warn!("Failed to deserialize __MISE_DIFF: {:#}", err); EnvDiff::default() }), None => EnvDiff::default(), @@ -296,13 +297,13 @@ fn var_duration(key: &str) -> Option { .map(|v| v.parse::().unwrap().into()) } -/// this returns the environment as if __RTX_DIFF was reversed. +/// this returns the environment as if __MISE_DIFF was reversed. /// putting the shell back into a state before hook-env was run fn get_pristine_env( - rtx_diff: &EnvDiff, + mise_diff: &EnvDiff, orig_env: HashMap, ) -> HashMap { - let patches = rtx_diff.reverse().to_patches(); + let patches = mise_diff.reverse().to_patches(); let mut env = apply_patches(&orig_env, &patches); // get the current path as a vector @@ -310,10 +311,10 @@ fn get_pristine_env( Some(path) => split_paths(path).collect(), None => vec![], }; - // get the paths that were removed by rtx as a hashset - let mut to_remove = rtx_diff.path.iter().collect::>(); + // get the paths that were removed by mise as a hashset + let mut to_remove = mise_diff.path.iter().collect::>(); - // remove those paths that were added by rtx, but only once (the first time) + // remove those paths that were added by mise, but only once (the first time) let path = path .into_iter() .filter(|p| !to_remove.remove(p)) @@ -361,7 +362,7 @@ fn prefer_stale(args: &[String]) -> bool { } fn log_file_level() -> Option { - let log_level = var("RTX_LOG_FILE_LEVEL").unwrap_or_default(); + let log_level = var("MISE_LOG_FILE_LEVEL").unwrap_or_default(); log_level.parse::().ok() } @@ -407,11 +408,11 @@ mod tests { #[test] fn test_var_path() { - set_var("RTX_TEST_PATH", "/foo/bar"); + set_var("MISE_TEST_PATH", "/foo/bar"); assert_eq!( - var_path("RTX_TEST_PATH").unwrap(), + var_path("MISE_TEST_PATH").unwrap(), PathBuf::from("/foo/bar") ); - remove_var("RTX_TEST_PATH"); + remove_var("MISE_TEST_PATH"); } } diff --git a/src/errors.rs b/src/errors.rs index 255149b4c..4afd1bdef 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -12,7 +12,7 @@ pub enum Error { VersionNotInstalled(PluginName, String), #[error("{} exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(String, Option), - #[error("Config file is not trusted.\nTrust it with `rtx trust`.")] + #[error("Config file is not trusted.\nTrust it with `mise trust`.")] UntrustedConfig(), } diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index f37a056e7..786a47640 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -11,7 +11,7 @@ use crate::{env, file}; pub fn setup() -> color_eyre::Result { static SETUP: OnceCell = OnceCell::new(); let path = SETUP.get_or_try_init(|| { - let path = env::RTX_DATA_DIR.join(".fake-asdf"); + let path = env::MISE_DATA_DIR.join(".fake-asdf"); let asdf_bin = path.join("asdf"); if !asdf_bin.exists() { file::create_dir_all(&path)?; @@ -19,7 +19,7 @@ pub fn setup() -> color_eyre::Result { &asdf_bin, formatdoc! {r#" #!/bin/sh - rtx asdf "$@" + mise asdf "$@" "#}, )?; let mut perms = asdf_bin.metadata()?.permissions(); diff --git a/src/file.rs b/src/file.rs index 3f65b03a1..4e4e48e2c 100644 --- a/src/file.rs +++ b/src/file.rs @@ -310,7 +310,7 @@ mod tests { #[test] fn test_find_up() { let path = &env::current_dir().unwrap(); - let filenames = vec![".rtxrc", ".rtxrc.toml", ".test-tool-versions"] + let filenames = vec![".miserc", ".mise.toml", ".test-tool-versions"] .into_iter() .map(|s| s.to_string()) .collect_vec(); diff --git a/src/git.rs b/src/git.rs index 8b919a2bc..54239e019 100644 --- a/src/git.rs +++ b/src/git.rs @@ -79,7 +79,7 @@ impl Git { match get_git_version() { Ok(version) => trace!("git version: {}", version), Err(err) => warn!( - "failed to get git version: {:#}\n Git is required to use rtx.", + "failed to get git version: {:#}\n Git is required to use mise.", err ), } diff --git a/src/hook_env.rs b/src/hook_env.rs index f10c43713..461ae2a74 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -25,12 +25,12 @@ pub fn should_exit_early(watch_files: &[PathBuf]) -> bool { return false; } let watch_files = get_watch_files(watch_files); - match &*env::__RTX_WATCH { + match &*env::__MISE_WATCH { Some(watches) => { if have_config_files_been_modified(watches, watch_files) { return false; } - if have_rtx_env_vars_been_modified(watches) { + if have_mise_env_vars_been_modified(watches) { return false; } } @@ -73,8 +73,8 @@ fn have_config_files_been_modified( false } -fn have_rtx_env_vars_been_modified(watches: &HookEnvWatches) -> bool { - if get_rtx_env_vars_hashed() != watches.env_var_hash { +fn have_mise_env_vars_been_modified(watches: &HookEnvWatches) -> bool { + if get_mise_env_vars_hashed() != watches.env_var_hash { return true; } false @@ -109,7 +109,7 @@ pub fn build_watches(watch_files: &[PathBuf]) -> Result { Ok(HookEnvWatches { files: watches, - env_var_hash: get_rtx_env_vars_hashed(), + env_var_hash: get_mise_env_vars_hashed(), }) } @@ -125,19 +125,19 @@ pub fn get_watch_files(watch_files: &[PathBuf]) -> BTreeSet { watches } -/// gets a hash of all RTX_ environment variables -fn get_rtx_env_vars_hashed() -> String { +/// gets a hash of all MISE_ environment variables +fn get_mise_env_vars_hashed() -> String { let env_vars: Vec<(&String, &String)> = env::PRISTINE_ENV .deref() .iter() - .filter(|(k, _)| k.starts_with("RTX_")) + .filter(|(k, _)| k.starts_with("MISE_")) .sorted() .collect(); hash_to_str(&env_vars) } pub fn clear_old_env(shell: &dyn Shell) -> String { - let mut patches = env::__RTX_DIFF.reverse().to_patches(); + let mut patches = env::__MISE_DIFF.reverse().to_patches(); if let Some(path) = env::PRISTINE_ENV.deref().get("PATH") { patches.push(EnvDiffOperation::Change("PATH".into(), path.to_string())); } diff --git a/src/http.rs b/src/http.rs index e00471824..c1671fef0 100644 --- a/src/http.rs +++ b/src/http.rs @@ -7,12 +7,12 @@ pub static HTTP_VERSION_CHECK: Lazy = pub static HTTP: Lazy = Lazy::new(|| Client::new(Duration::from_secs(30)).unwrap()); pub static HTTP_FETCH: Lazy = - Lazy::new(|| Client::new(*RTX_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); + Lazy::new(|| Client::new(*MISE_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); use std::path::Path; use std::time::Duration; -use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; +use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::display_path; use crate::{env, file}; use eyre::{Report, Result}; @@ -37,7 +37,7 @@ impl Client { fn _new() -> ClientBuilder { ClientBuilder::new() - .user_agent(format!("rtx/{}", env!("CARGO_PKG_VERSION"))) + .user_agent(format!("mise/{}", env!("CARGO_PKG_VERSION"))) .gzip(true) } diff --git a/src/logger.rs b/src/logger.rs index eea3e98a0..096c283b7 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -16,14 +16,14 @@ pub fn init(settings: &Settings) { let level = settings.log_level.parse().unwrap(); loggers.push(init_term_logger(level)); - if let Some(log_file) = &*env::RTX_LOG_FILE { - let file_level = env::RTX_LOG_FILE_LEVEL.unwrap_or(level); + if let Some(log_file) = &*env::MISE_LOG_FILE { + let file_level = env::MISE_LOG_FILE_LEVEL.unwrap_or(level); if let Some(logger) = init_write_logger(file_level, log_file) { loggers.push(logger) } } CombinedLogger::init(loggers).unwrap_or_else(|err| { - eprintln!("rtx: could not initialize logger: {err}"); + eprintln!("mise: could not initialize logger: {err}"); }); } @@ -66,7 +66,7 @@ fn init_write_logger(level: LevelFilter, log_path: &Path) -> Option { - eprintln!("rtx: could not write to log file: {err}"); + eprintln!("mise: could not write to log file: {err}"); None } diff --git a/src/main.rs b/src/main.rs index 17d96014a..a34416683 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,7 +78,7 @@ fn main() -> Result<()> { exit(1); } Err(err) => { - Err(err).suggestion("Run with --verbose or RTX_VERBOSE=1 for more information.") + Err(err).suggestion("Run with --verbose or MISE_VERBOSE=1 for more information.") } } } @@ -90,6 +90,6 @@ fn display_friendly_err(err: Report) { let dim = |s| style(s).dim().for_stderr(); error!( "{}", - dim("Run with --verbose or RTX_VERBOSE=1 for more information") + dim("Run with --verbose or MISE_VERBOSE=1 for more information") ); } diff --git a/src/migrate.rs b/src/migrate.rs index 547aa0745..c5b95d54f 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -5,9 +5,13 @@ use eyre::Result; use rayon::Scope; use crate::dirs::*; +use crate::env::{XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_STATE_HOME}; use crate::file; pub fn run() { + if let Err(err) = migrate_rtx() { + warn!("migrate: {}", err); + } rayon::scope(|s| { task(s, || rename_plugin("nodejs", "node")); task(s, || rename_plugin("golang", "go")); @@ -54,6 +58,13 @@ fn rename_plugin(from: &str, to: &str) -> Result<()> { Ok(()) } +fn migrate_rtx() -> Result<()> { + move_dirs(&XDG_DATA_HOME.join("rtx"), &DATA)?; + move_dirs(&XDG_CONFIG_HOME.join("rtx"), &CONFIG)?; + move_dirs(&XDG_STATE_HOME.join("rtx"), &STATE)?; + Ok(()) +} + fn migrate_tracked_configs() -> Result<()> { move_dirs(&DATA.join("tracked_config_files"), &TRACKED_CONFIGS)?; move_dirs(&DATA.join("tracked-config-files"), &TRACKED_CONFIGS)?; diff --git a/src/output.rs b/src/output.rs index 328cc313b..47d2fa0ce 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,8 +1,8 @@ #[cfg(test)] #[macro_export] -macro_rules! rtxprintln { +macro_rules! miseprintln { () => { - rtxprint!("\n") + miseprint!("\n") }; ($($arg:tt)*) => {{ let mut stdout = $crate::output::tests::STDOUT.lock().unwrap(); @@ -12,9 +12,9 @@ macro_rules! rtxprintln { #[cfg(not(test))] #[macro_export] -macro_rules! rtxprintln { +macro_rules! miseprintln { () => { - rtxprint!("\n") + miseprint!("\n") }; ($($arg:tt)*) => {{ println!($($arg)*); @@ -23,7 +23,7 @@ macro_rules! rtxprintln { #[cfg(test)] #[macro_export] -macro_rules! rtxprint { +macro_rules! miseprint { ($($arg:tt)*) => {{ let mut stdout = $crate::output::tests::STDOUT.lock().unwrap(); let cur = stdout.pop().unwrap_or_default(); @@ -33,7 +33,7 @@ macro_rules! rtxprint { #[cfg(not(test))] #[macro_export] -macro_rules! rtxprint { +macro_rules! miseprint { ($($arg:tt)*) => {{ print!($($arg)*); }}; @@ -44,8 +44,8 @@ macro_rules! rtxprint { macro_rules! info { ($($arg:tt)*) => {{ let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); - let rtx = console::style("rtx").dim().for_stderr(); - stderr.push(format!("{} {}", rtx, format!($($arg)*))); + let mise = console::style("mise").dim().for_stderr(); + stderr.push(format!("{} {}", mise, format!($($arg)*))); }}; } @@ -55,8 +55,8 @@ macro_rules! warn { ($($arg:tt)*) => { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); - let rtx = console::style("rtx").yellow().for_stderr(); - stderr.push(format!("{} {}", rtx, format!($($arg)*))); + let mise = console::style("mise").yellow().for_stderr(); + stderr.push(format!("{} {}", mise, format!($($arg)*))); }) } } @@ -67,8 +67,8 @@ macro_rules! error { ($($arg:tt)*) => { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { let mut stderr = $crate::output::tests::STDERR.lock().unwrap(); - let rtx = console::style("rtx").red().for_stderr(); - stderr.push(format!("{} {}", rtx, format!($($arg)*))); + let mise = console::style("mise").red().for_stderr(); + stderr.push(format!("{} {}", mise, format!($($arg)*))); }) } } @@ -91,8 +91,8 @@ macro_rules! debug { #[macro_export] macro_rules! info { ($($arg:tt)*) => {{ - let rtx = console::style("rtx").dim().for_stderr(); - info_unprefix!("{} {}", rtx, format!($($arg)*)); + let mise = console::style("mise").dim().for_stderr(); + info_unprefix!("{} {}", mise, format!($($arg)*)); }}; } @@ -127,8 +127,8 @@ macro_rules! warn { log::warn!($($arg)*); } else if log::log_enabled!(log::Level::Warn) { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { - let rtx = console::style("rtx ").yellow().for_stderr(); - eprintln!("{}{}", rtx, format!($($arg)*)); + let mise = console::style("mise ").yellow().for_stderr(); + eprintln!("{}{}", mise, format!($($arg)*)); }); } }}; @@ -142,8 +142,8 @@ macro_rules! error { log::error!($($arg)*); } else if log::log_enabled!(log::Level::Error) { $crate::ui::multi_progress_report::MultiProgressReport::suspend_if_active(|| { - let rtx = console::style("rtx ").red().for_stderr(); - eprintln!("{}{}", rtx, format!($($arg)*)); + let mise = console::style("mise ").red().for_stderr(); + eprintln!("{}{}", mise, format!($($arg)*)); }); } }}; diff --git a/src/path_env.rs b/src/path_env.rs index 3d9edb9ca..1daf0984f 100644 --- a/src/path_env.rs +++ b/src/path_env.rs @@ -8,7 +8,7 @@ use std::path::PathBuf; pub struct PathEnv { pre: Vec, - rtx: Vec, + mise: Vec, post: Vec, seen_shims: bool, } @@ -17,18 +17,18 @@ impl PathEnv { pub fn new() -> Self { Self { pre: Vec::new(), - rtx: Vec::new(), + mise: Vec::new(), post: Vec::new(), seen_shims: false, } } pub fn add(&mut self, path: PathBuf) { - self.rtx.push(path); + self.mise.push(path); } pub fn to_vec(&self) -> Vec { - let mut paths = self.pre.iter().chain(self.rtx.iter()).collect_vec(); + let mut paths = self.pre.iter().chain(self.mise.iter()).collect_vec(); if self.seen_shims { paths.push(&dirs::SHIMS); } @@ -99,7 +99,7 @@ mod tests { } #[test] - fn test_path_env_no_rtx() { + fn test_path_env_no_mise() { let mut path_env = PathEnv::from_iter( [ "/before-1", diff --git a/src/plugins/core/assets/node_npm_shim b/src/plugins/core/assets/node_npm_shim index 74d6bfae7..02cd4dc1e 100755 --- a/src/plugins/core/assets/node_npm_shim +++ b/src/plugins/core/assets/node_npm_shim @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -# This script wraps npm so to run `rtx reshim` after global installs and uninstalls +# This script wraps npm so to run `mise reshim` after global installs and uninstalls # Any other cases are passed-through to npm this_dir=$(dirname "${BASH_SOURCE[0]}") @@ -12,7 +12,7 @@ this_dir=$(cd "$this_dir" && pwd -P) # Normalizes the directory plugin_dir="${this_dir}/.." should_reshim() { - if [ "${RTX_SKIP_RESHIM:-}" ]; then + if [ "${MISE_SKIP_RESHIM:-}" ]; then return 1 fi @@ -71,8 +71,8 @@ wrap_npm_if_reshim_is_needed() { local npm_cli="$plugin_dir/lib/node_modules/npm/bin/npm-cli.js" if should_reshim "$@"; then node "$npm_cli" "$@" - printf "Reshimming rtx %s...\n" "$plugin_name" >&2 - rtx reshim + printf "Reshimming mise %s...\n" "$plugin_name" >&2 + mise reshim else exec node "$npm_cli" "$@" fi diff --git a/src/plugins/core/assets/rubygems_plugin.rb b/src/plugins/core/assets/rubygems_plugin.rb index bd88173f6..5c2ccd04c 100644 --- a/src/plugins/core/assets/rubygems_plugin.rb +++ b/src/plugins/core/assets/rubygems_plugin.rb @@ -1,17 +1,17 @@ # frozen_string_literal: true def debug? - !!ENV["RTX_DEBUG"] + !!ENV["MISE_DEBUG"] end def log_debug(msg) - warn "[DEBUG] rtx #{msg}" if debug? + warn "[DEBUG] mise #{msg}" if debug? end def reshim if `which ruby`.strip != "" log_debug "reshim" - `rtx reshim` + `mise reshim` else log_debug "reshim skipped: ruby not found" end diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index bcb928ad9..30733acf6 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -27,7 +27,7 @@ impl BunPlugin { } fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { + match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index a7c44598a..550d734e1 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -29,7 +29,7 @@ impl DenoPlugin { } fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { + match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 7f9c662c1..1a4ac5bb4 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -66,7 +66,7 @@ impl ErlangPlugin { } fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { + match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index f9ba54a75..93d2afe61 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -29,13 +29,13 @@ impl GoPlugin { } fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { + match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } CorePlugin::run_fetch_task_with_timeout(move || { - let repo = &*env::RTX_GO_REPO; + let repo = &*env::MISE_GO_REPO; let output = cmd!("git", "ls-remote", "--tags", repo, "go*").read()?; let lines = output.split('\n'); let versions = lines.map(|s| s.split("/go").last().unwrap_or_default().to_string()) @@ -59,7 +59,7 @@ impl GoPlugin { } fn install_default_packages(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { - let body = file::read_to_string(&*env::RTX_GO_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + let body = file::read_to_string(&*env::MISE_GO_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); if package.is_empty() { @@ -72,10 +72,10 @@ impl GoPlugin { format!("{}@latest", package) }; let mut env = HashMap::new(); - if *env::RTX_GO_SET_GOROOT != Some(false) { + if *env::MISE_GO_SET_GOROOT != Some(false) { env.insert("GOROOT", self.goroot(tv)); } - if *env::RTX_GO_SET_GOPATH != Some(false) { + if *env::MISE_GO_SET_GOPATH != Some(false) { env.insert("GOPATH", self.gopath(tv)); } CmdLineRunner::new(self.go_bin(tv)) @@ -98,7 +98,7 @@ impl GoPlugin { fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { let filename = format!("go{}.{}-{}.tar.gz", tv.version, platform(), arch()); - let tarball_url = format!("{}/{}", &*env::RTX_GO_DOWNLOAD_MIRROR, &filename); + let tarball_url = format!("{}/{}", &*env::MISE_GO_DOWNLOAD_MIRROR, &filename); let tarball_path = tv.download_path().join(filename); pr.set_message(format!("downloading {}", &tarball_url)); @@ -110,7 +110,7 @@ impl GoPlugin { } fn verify_tarball_checksum(&self, tarball_url: &str, tarball_path: &Path) -> Result<()> { - if !*env::RTX_GO_SKIP_CHECKSUM { + if !*env::MISE_GO_SKIP_CHECKSUM { let checksum_url = format!("{}.sha256", tarball_url); let checksum = HTTP.get_text(checksum_url)?; hash::ensure_checksum_sha256(tarball_path, &checksum)?; @@ -166,9 +166,9 @@ impl Plugin for GoPlugin { } fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { - // goroot/bin must always be included, irrespective of RTX_GO_SET_GOROOT + // goroot/bin must always be included, irrespective of MISE_GO_SET_GOROOT let mut paths = vec![self.goroot(tv).join("bin")]; - if *env::RTX_GO_SET_GOPATH != Some(false) { + if *env::MISE_GO_SET_GOPATH != Some(false) { paths.push(self.gopath(tv).join("bin")); } Ok(paths) @@ -181,14 +181,14 @@ impl Plugin for GoPlugin { tv: &ToolVersion, ) -> Result> { let mut map = HashMap::new(); - match (*env::RTX_GO_SET_GOROOT, env::PRISTINE_ENV.get("GOROOT")) { + match (*env::MISE_GO_SET_GOROOT, env::PRISTINE_ENV.get("GOROOT")) { (Some(false), _) | (None, Some(_)) => {} (Some(true), _) | (None, None) => { let goroot = self.goroot(tv).to_string_lossy().to_string(); map.insert("GOROOT".to_string(), goroot); } }; - match (*env::RTX_GO_SET_GOPATH, env::PRISTINE_ENV.get("GOPATH")) { + match (*env::MISE_GO_SET_GOPATH, env::PRISTINE_ENV.get("GOPATH")) { (Some(false), _) | (None, Some(_)) => {} (Some(true), _) | (None, None) => { let gopath = self.gopath(tv).to_string_lossy().to_string(); diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 65d8e5d49..9027b6147 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -39,11 +39,11 @@ impl JavaPlugin { java_metadata_ea_cache: CacheManager::new( core.cache_path.join(java_metadata_ea_cache_filename), ) - .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), java_metadata_ga_cache: CacheManager::new( core.cache_path.join(java_metadata_ga_cache_filename), ) - .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), core, } } @@ -64,7 +64,7 @@ impl JavaPlugin { if m.version.contains('.') { metadata.insert(m.version.to_string(), m.clone()); } else { - // rtx expects full versions like ".0.0" + // mise expects full versions like ".0.0" metadata.insert(format!("{}.0.0", m.version), m.clone()); } } @@ -77,8 +77,8 @@ impl JavaPlugin { fn fetch_remote_versions(&self) -> Result> { // TODO: find out how to get this to work for different os/arch - // See https://github.com/jdx/rtx/issues/1196 - // match self.core.fetch_remote_versions_from_rtx() { + // See https://github.com/jdx/mise/issues/1196 + // match self.core.fetch_remote_versions_from_mise() { // Ok(Some(versions)) => return Ok(versions), // Ok(None) => {} // Err(e) => warn!("failed to fetch remote versions: {}", e), @@ -227,7 +227,7 @@ impl JavaPlugin { if regex!(r"^\d").is_match(&tv.version) { // undo openjdk shorthand if tv.version.ends_with(".0.0") { - // undo rtx's full "*.0.0" version + // undo mise's full "*.0.0" version format!("openjdk-{}", &tv.version[..tv.version.len() - 4]) } else { format!("openjdk-{}", tv.version) diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 8ba73761f..b3d00cfc5 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -72,7 +72,7 @@ impl CorePlugin { Self { name, remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE), + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), cache_path, } } @@ -88,11 +88,11 @@ impl CorePlugin { F: FnOnce() -> Result + Send, T: Send, { - run_with_timeout(f, *env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT) + run_with_timeout(f, *env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT) } - pub fn fetch_remote_versions_from_rtx(&self) -> Result>> { - if !*env::RTX_USE_VERSIONS_HOST { + pub fn fetch_remote_versions_from_mise(&self) -> Result>> { + if !*env::MISE_USE_VERSIONS_HOST { return Ok(None); } let versions = HTTP_FETCH diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index af56798e6..cfc3541a8 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -9,7 +9,7 @@ use url::Url; use crate::build_time::built_info; use crate::cmd::CmdLineRunner; use crate::config::Config; -use crate::env::RTX_NODE_MIRROR_URL; +use crate::env::MISE_NODE_MIRROR_URL; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; @@ -31,17 +31,17 @@ impl NodePlugin { } fn fetch_remote_versions(&self) -> Result> { - let node_url_overridden = env::var("RTX_NODE_MIRROR_URL") + let node_url_overridden = env::var("MISE_NODE_MIRROR_URL") .or(env::var("NODE_BUILD_MIRROR_URL")) .is_ok(); if !node_url_overridden { - match self.core.fetch_remote_versions_from_rtx() { + match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), } } - self.fetch_remote_versions_from_node(&RTX_NODE_MIRROR_URL) + self.fetch_remote_versions_from_node(&MISE_NODE_MIRROR_URL) } fn fetch_remote_versions_from_node(&self, base: &Url) -> Result> { let versions = HTTP_FETCH @@ -113,7 +113,7 @@ impl NodePlugin { pr.set_message(format!("downloading {tarball_name}")); HTTP.download_file(url.clone(), local)?; } - if *env::RTX_NODE_VERIFY { + if *env::MISE_NODE_VERIFY { pr.set_message(format!("verifying {tarball_name}")); self.verify(local, version)?; } @@ -129,7 +129,7 @@ impl NodePlugin { .with_pr(ctx.pr.as_ref()) .current_dir(&opts.build_dir) .arg("-c"); - if let Some(cflags) = &*env::RTX_NODE_CFLAGS { + if let Some(cflags) = &*env::MISE_NODE_CFLAGS { cmd = cmd.env("CFLAGS", cflags); } cmd @@ -172,7 +172,7 @@ impl NodePlugin { tv: &ToolVersion, pr: &dyn SingleReport, ) -> Result<()> { - let body = file::read_to_string(&*env::RTX_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + let body = file::read_to_string(&*env::MISE_NODE_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); if package.is_empty() { @@ -230,8 +230,8 @@ impl NodePlugin { } fn shasums_url(&self, v: &str) -> Result { - // let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt.asc"))?; - let url = RTX_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt"))?; + // let url = MISE_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt.asc"))?; + let url = MISE_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt"))?; Ok(url) } } @@ -293,7 +293,7 @@ impl Plugin for NodePlugin { let config = Config::get(); let opts = BuildOpts::new(ctx)?; debug!("node build opts: {:#?}", opts); - if *env::RTX_NODE_COMPILE { + if *env::MISE_NODE_COMPILE { self.install_compiled(ctx, &opts)?; } else { self.install_precompiled(ctx, &opts)?; @@ -302,7 +302,7 @@ impl Plugin for NodePlugin { self.install_npm_shim(&ctx.tv)?; self.test_npm(&config, &ctx.tv, ctx.pr.as_ref())?; self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; - if *env::RTX_NODE_COREPACK && self.corepack_path(&ctx.tv).exists() { + if *env::MISE_NODE_COREPACK && self.corepack_path(&ctx.tv).exists() { self.enable_default_corepack_shims(&ctx.tv, ctx.pr.as_ref())?; } @@ -337,16 +337,16 @@ impl BuildOpts { Ok(Self { version: v.clone(), path: ctx.ts.list_paths(), - build_dir: env::RTX_TMP_DIR.join(format!("node-v{v}")), + build_dir: env::MISE_TMP_DIR.join(format!("node-v{v}")), configure_cmd: configure_cmd(&install_path), make_cmd: make_cmd(), make_install_cmd: make_install_cmd(), source_tarball_path: ctx.tv.download_path().join(&source_tarball_name), - source_tarball_url: env::RTX_NODE_MIRROR_URL + source_tarball_url: env::MISE_NODE_MIRROR_URL .join(&format!("v{v}/{source_tarball_name}"))?, source_tarball_name, binary_tarball_path: ctx.tv.download_path().join(&binary_tarball_name), - binary_tarball_url: env::RTX_NODE_MIRROR_URL + binary_tarball_url: env::MISE_NODE_MIRROR_URL .join(&format!("v{v}/{binary_tarball_name}"))?, binary_tarball_name, install_path, @@ -356,29 +356,29 @@ impl BuildOpts { fn configure_cmd(install_path: &Path) -> String { let mut configure_cmd = format!("./configure --prefix={}", install_path.display()); - if *env::RTX_NODE_NINJA { + if *env::MISE_NODE_NINJA { configure_cmd.push_str(" --ninja"); } - if let Some(opts) = &*env::RTX_NODE_CONFIGURE_OPTS { + if let Some(opts) = &*env::MISE_NODE_CONFIGURE_OPTS { configure_cmd.push_str(&format!(" {}", opts)); } configure_cmd } fn make_cmd() -> String { - let mut make_cmd = env::RTX_NODE_MAKE.to_string(); - if let Some(concurrency) = *env::RTX_NODE_CONCURRENCY { + let mut make_cmd = env::MISE_NODE_MAKE.to_string(); + if let Some(concurrency) = *env::MISE_NODE_CONCURRENCY { make_cmd.push_str(&format!(" -j{concurrency}")); } - if let Some(opts) = &*env::RTX_NODE_MAKE_OPTS { + if let Some(opts) = &*env::MISE_NODE_MAKE_OPTS { make_cmd.push_str(&format!(" {opts}")); } make_cmd } fn make_install_cmd() -> String { - let mut make_install_cmd = format!("{} install", &*env::RTX_NODE_MAKE); - if let Some(opts) = &*env::RTX_NODE_MAKE_INSTALL_OPTS { + let mut make_install_cmd = format!("{} install", &*env::MISE_NODE_MAKE); + if let Some(opts) = &*env::MISE_NODE_MAKE_INSTALL_OPTS { make_install_cmd.push_str(&format!(" {opts}")); } make_install_cmd diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 2b9044c44..aef09eaea 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -50,7 +50,7 @@ impl PythonPlugin { debug!("Installing python-build to {}", python_build_path.display()); create_dir_all(self.python_build_path().parent().unwrap())?; let git = Git::new(self.python_build_path()); - git.clone(&env::RTX_PYENV_REPO)?; + git.clone(&env::MISE_PYENV_REPO)?; Ok(()) } fn update_python_build(&self) -> Result<()> { @@ -65,7 +65,7 @@ impl PythonPlugin { } fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { + match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), @@ -93,7 +93,7 @@ impl PythonPlugin { tv: &ToolVersion, pr: &dyn SingleReport, ) -> Result<()> { - if !env::RTX_PYTHON_DEFAULT_PACKAGES_FILE.exists() { + if !env::MISE_PYTHON_DEFAULT_PACKAGES_FILE.exists() { return Ok(()); } pr.set_message("installing default packages".into()); @@ -104,7 +104,7 @@ impl PythonPlugin { .arg("install") .arg("--upgrade") .arg("-r") - .arg(&*env::RTX_PYTHON_DEFAULT_PACKAGES_FILE) + .arg(&*env::MISE_PYTHON_DEFAULT_PACKAGES_FILE) .envs(&config.env) .execute() } @@ -119,7 +119,7 @@ impl PythonPlugin { let settings = Settings::try_get()?; if !settings.experimental { warn!( - "please enable experimental mode with `rtx settings set experimental true` \ + "please enable experimental mode with `mise settings set experimental true` \ to use python virtualenv activation" ); } @@ -204,13 +204,13 @@ impl Plugin for PythonPlugin { if settings.verbose { cmd = cmd.arg("--verbose"); } - if let Some(patch_url) = &*env::RTX_PYTHON_PATCH_URL { + if let Some(patch_url) = &*env::MISE_PYTHON_PATCH_URL { ctx.pr .set_message(format!("with patch file from: {patch_url}")); let patch = HTTP.get_text(patch_url)?; cmd = cmd.arg("--patch").stdin_string(patch) } - if let Some(patches_dir) = &*env::RTX_PYTHON_PATCHES_DIRECTORY { + if let Some(patches_dir) = &*env::MISE_PYTHON_PATCHES_DIRECTORY { let patch_file = patches_dir.join(format!("{}.patch", &ctx.tv.version)); if patch_file.exists() { ctx.pr @@ -242,7 +242,7 @@ impl Plugin for PythonPlugin { Ok(Some(virtualenv)) => { let bin = virtualenv.join("bin"); hm.insert("VIRTUAL_ENV".into(), virtualenv.to_string_lossy().into()); - hm.insert("RTX_ADD_PATH".into(), bin.to_string_lossy().into()); + hm.insert("MISE_ADD_PATH".into(), bin.to_string_lossy().into()); } Ok(None) => {} }; diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index ced09d8d1..61687f5a9 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -48,7 +48,7 @@ impl RubyPlugin { } fn lock_build_tool(&self) -> Result { - let build_tool_path = if *env::RTX_RUBY_INSTALL { + let build_tool_path = if *env::MISE_RUBY_INSTALL { self.ruby_build_bin() } else { self.ruby_install_bin() @@ -61,7 +61,7 @@ impl RubyPlugin { } fn update_build_tool(&self) -> Result<()> { - if *env::RTX_RUBY_INSTALL { + if *env::MISE_RUBY_INSTALL { self.update_ruby_install() .wrap_err("failed to update ruby-install")?; } @@ -74,11 +74,11 @@ impl RubyPlugin { "Installing ruby-build to {}", self.ruby_build_path().display() ); - let tmp = temp_dir().join("rtx-ruby-build"); + let tmp = temp_dir().join("mise-ruby-build"); file::remove_all(&tmp)?; file::create_dir_all(tmp.parent().unwrap())?; let git = Git::new(tmp.clone()); - git.clone(&env::RTX_RUBY_BUILD_REPO)?; + git.clone(&env::MISE_RUBY_BUILD_REPO)?; cmd!("sh", "install.sh") .env("PREFIX", self.ruby_build_path()) @@ -108,11 +108,11 @@ impl RubyPlugin { "Installing ruby-install to {}", self.ruby_install_path().display() ); - let tmp = temp_dir().join("rtx-ruby-install"); + let tmp = temp_dir().join("mise-ruby-install"); file::remove_all(&tmp)?; file::create_dir_all(tmp.parent().unwrap())?; let git = Git::new(tmp.clone()); - git.clone(&env::RTX_RUBY_INSTALL_REPO)?; + git.clone(&env::MISE_RUBY_INSTALL_REPO)?; cmd!("make", "install") .env("PREFIX", self.ruby_install_path()) @@ -145,7 +145,7 @@ impl RubyPlugin { } fn fetch_remote_versions(&self) -> Result> { - match self.core.fetch_remote_versions_from_rtx() { + match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} Err(e) => warn!("failed to fetch remote versions: {}", e), @@ -180,7 +180,7 @@ impl RubyPlugin { tv: &ToolVersion, pr: &dyn SingleReport, ) -> Result<()> { - let body = file::read_to_string(&*env::RTX_RUBY_DEFAULT_PACKAGES_FILE).unwrap_or_default(); + let body = file::read_to_string(&*env::MISE_RUBY_DEFAULT_PACKAGES_FILE).unwrap_or_default(); for package in body.lines() { let package = package.split('#').next().unwrap_or_default().trim(); if package.is_empty() { @@ -253,7 +253,7 @@ impl RubyPlugin { tv: &ToolVersion, pr: &'a dyn SingleReport, ) -> Result { - let cmd = if *env::RTX_RUBY_INSTALL { + let cmd = if *env::MISE_RUBY_INSTALL { CmdLineRunner::new(self.ruby_install_bin()).args(self.install_args_ruby_install(tv)?) } else { CmdLineRunner::new(self.ruby_build_bin()) @@ -263,11 +263,11 @@ impl RubyPlugin { Ok(cmd.with_pr(pr).envs(&config.env)) } fn install_args_ruby_build(&self, tv: &ToolVersion) -> Result> { - let mut args = env::RTX_RUBY_BUILD_OPTS.clone()?; + let mut args = env::MISE_RUBY_BUILD_OPTS.clone()?; if self.verbose_install() { args.push("--verbose".into()); } - if env::RTX_RUBY_APPLY_PATCHES.is_some() { + if env::MISE_RUBY_APPLY_PATCHES.is_some() { args.push("--patch".into()); } args.push(tv.version.clone()); @@ -288,18 +288,18 @@ impl RubyPlugin { args.push(version.into()); args.push("--install-dir".into()); args.push(tv.install_path().to_string_lossy().to_string()); - args.extend(env::RTX_RUBY_INSTALL_OPTS.clone()?); + args.extend(env::MISE_RUBY_INSTALL_OPTS.clone()?); Ok(args) } fn verbose_install(&self) -> bool { let settings = Settings::get(); - let verbose_env = *env::RTX_RUBY_VERBOSE_INSTALL; + let verbose_env = *env::MISE_RUBY_VERBOSE_INSTALL; verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false)) } fn fetch_patch_sources(&self) -> Vec { - let patch_sources = env::RTX_RUBY_APPLY_PATCHES.clone().unwrap_or_default(); + let patch_sources = env::MISE_RUBY_APPLY_PATCHES.clone().unwrap_or_default(); patch_sources .split('\n') .map(|s| s.to_string()) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 676abfbfa..ffea0a8a8 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -16,7 +16,7 @@ use rayon::prelude::*; use crate::cache::CacheManager; use crate::config::{Config, Settings}; use crate::default_shorthands::{DEFAULT_SHORTHANDS, TRUSTED_SHORTHANDS}; -use crate::env::RTX_FETCH_REMOTE_VERSIONS_TIMEOUT; +use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_all}; @@ -25,7 +25,7 @@ use crate::hash::hash_to_str; use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; use crate::plugins::external_plugin_cache::ExternalPluginCache; -use crate::plugins::rtx_plugin_toml::RtxPluginToml; +use crate::plugins::mise_plugin_toml::MisePluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; use crate::timeout::run_with_timeout; @@ -35,12 +35,12 @@ use crate::ui::progress_report::SingleReport; use crate::ui::prompt; use crate::{dirs, env, file, http}; -/// This represents a plugin installed to ~/.local/share/rtx/plugins +/// This represents a plugin installed to ~/.local/share/mise/plugins pub struct ExternalPlugin { pub name: PluginName, pub plugin_path: PathBuf, pub repo_url: Option, - pub toml: RtxPluginToml, + pub toml: MisePluginToml, cache_path: PathBuf, downloads_path: PathBuf, installs_path: PathBuf, @@ -56,19 +56,19 @@ impl ExternalPlugin { pub fn new(name: PluginName) -> Self { let plugin_path = dirs::PLUGINS.join(&name); let cache_path = dirs::CACHE.join(&name); - let toml_path = plugin_path.join("rtx.plugin.toml"); - let toml = RtxPluginToml::from_file(&toml_path).unwrap(); + let toml_path = plugin_path.join("mise.plugin.toml"); + let toml = MisePluginToml::from_file(&toml_path).unwrap(); Self { script_man: build_script_man(&name, &plugin_path), downloads_path: dirs::DOWNLOADS.join(&name), installs_path: dirs::INSTALLS.join(&name), cache: ExternalPluginCache::default(), remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-all")), latest_stable_cache: CacheManager::new(cache_path.join("latest_stable.msgpack.z")) - .with_fresh_duration(*env::RTX_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/latest-stable")), alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.z")) @@ -130,7 +130,7 @@ impl ExternalPlugin { } fn fetch_versions(&self) -> Result>> { - if !*env::RTX_USE_VERSIONS_HOST { + if !*env::MISE_USE_VERSIONS_HOST { return Ok(None); } // ensure that we're using a default shorthand plugin @@ -175,7 +175,7 @@ impl ExternalPlugin { let result = cmd.stdout_capture().stderr_capture().unchecked().run()?; Ok(result) }, - *RTX_FETCH_REMOTE_VERSIONS_TIMEOUT, + *MISE_FETCH_REMOTE_VERSIONS_TIMEOUT, ) .wrap_err_with(|| { let script = self.script_man.get_script_path(&Script::ListAll); @@ -324,10 +324,13 @@ impl ExternalPlugin { for (key, value) in &tv.opts { let k = format!("RTX_TOOL_OPTS__{}", key.to_uppercase()); sm = sm.with_env(k, value.clone()); + let k = format!("MISE_TOOL_OPTS__{}", key.to_uppercase()); + sm = sm.with_env(k, value.clone()); } if let Some(project_root) = &config.project_root { let project_root = project_root.to_string_lossy().to_string(); - sm = sm.with_env("RTX_PROJECT_ROOT", project_root); + sm = sm.with_env("RTX_PROJECT_ROOT", project_root.clone()); + sm = sm.with_env("MISE_PROJECT_ROOT", project_root); } let install_type = match &tv.request { ToolVersionRequest::Version(_, _) | ToolVersionRequest::Prefix(_, _) => "version", @@ -342,21 +345,25 @@ impl ExternalPlugin { ToolVersionRequest::Ref(_, v) => v, // should not have "ref:" prefix _ => &tv.version, }; - // add env vars from .rtx.toml files + // add env vars from .mise.toml files for (key, value) in &config.env { sm = sm.with_env(key, value.clone()); } let install = tv.install_path().to_string_lossy().to_string(); let download = tv.download_path().to_string_lossy().to_string(); sm = sm - .with_env("RTX_INSTALL_PATH", &install) - .with_env("ASDF_INSTALL_PATH", install) + .with_env("ASDF_DOWNLOAD_PATH", &download) + .with_env("ASDF_INSTALL_PATH", &install) + .with_env("ASDF_INSTALL_TYPE", install_type) + .with_env("ASDF_INSTALL_VERSION", install_version) .with_env("RTX_DOWNLOAD_PATH", &download) - .with_env("ASDF_DOWNLOAD_PATH", download) + .with_env("RTX_INSTALL_PATH", &install) .with_env("RTX_INSTALL_TYPE", install_type) - .with_env("ASDF_INSTALL_TYPE", install_type) .with_env("RTX_INSTALL_VERSION", install_version) - .with_env("ASDF_INSTALL_VERSION", install_version); + .with_env("MISE_DOWNLOAD_PATH", download) + .with_env("MISE_INSTALL_PATH", install) + .with_env("MISE_INSTALL_TYPE", install_type) + .with_env("MISE_INSTALL_VERSION", install_version); sm } @@ -371,10 +378,14 @@ impl ExternalPlugin { } fn build_script_man(name: &str, plugin_path: &Path) -> ScriptManager { + let plugin_path_s = plugin_path.to_string_lossy().to_string(); ScriptManager::new(plugin_path.to_path_buf()) + .with_env("RTX_PLUGIN_PATH", &plugin_path_s) .with_env("RTX_PLUGIN_NAME", name.to_string()) - .with_env("RTX_PLUGIN_PATH", plugin_path.to_string_lossy().to_string()) .with_env("RTX_SHIMS_DIR", &*dirs::SHIMS) + .with_env("MISE_PLUGIN_NAME", name.to_string()) + .with_env("MISE_PLUGIN_PATH", plugin_path) + .with_env("MISE_SHIMS_DIR", &*dirs::SHIMS) } impl Eq for ExternalPlugin {} @@ -590,7 +601,7 @@ impl Plugin for ExternalPlugin { fn external_commands(&self) -> Result> { let command_path = self.plugin_path.join("lib/commands"); if !self.is_installed() || !command_path.exists() || self.name == "direnv" { - // asdf-direnv is disabled since it conflicts with rtx's built-in direnv functionality + // asdf-direnv is disabled since it conflicts with mise's built-in direnv functionality return Ok(vec![]); } let mut commands = vec![]; @@ -688,7 +699,7 @@ impl Plugin for ExternalPlugin { if matches!(tv.request, ToolVersionRequest::System(_)) { return Ok(EMPTY_HASH_MAP.clone()); } - if !self.script_man.script_exists(&ExecEnv) || *env::__RTX_SCRIPT { + if !self.script_man.script_exists(&ExecEnv) || *env::__MISE_SCRIPT { // if the script does not exist, or we're already running from within a script, // the second is to prevent infinite loops return Ok(EMPTY_HASH_MAP.clone()); diff --git a/src/plugins/rtx_plugin_toml.rs b/src/plugins/mise_plugin_toml.rs similarity index 85% rename from src/plugins/rtx_plugin_toml.rs rename to src/plugins/mise_plugin_toml.rs index 9c85f7c82..299f6a926 100644 --- a/src/plugins/rtx_plugin_toml.rs +++ b/src/plugins/mise_plugin_toml.rs @@ -7,20 +7,20 @@ use toml_edit::{Document, Item, Value}; use crate::{file, parse_error}; #[derive(Debug, Default, Clone)] -pub struct RtxPluginTomlScriptConfig { +pub struct MisePluginTomlScriptConfig { pub cache_key: Option>, pub data: Option, } #[derive(Debug, Default, Clone)] -pub struct RtxPluginToml { - pub exec_env: RtxPluginTomlScriptConfig, - pub list_aliases: RtxPluginTomlScriptConfig, - pub list_bin_paths: RtxPluginTomlScriptConfig, - pub list_legacy_filenames: RtxPluginTomlScriptConfig, +pub struct MisePluginToml { + pub exec_env: MisePluginTomlScriptConfig, + pub list_aliases: MisePluginTomlScriptConfig, + pub list_bin_paths: MisePluginTomlScriptConfig, + pub list_legacy_filenames: MisePluginTomlScriptConfig, } -impl RtxPluginToml { +impl MisePluginToml { pub fn from_file(path: &Path) -> Result { if !path.exists() { return Ok(Default::default()); @@ -57,10 +57,10 @@ impl RtxPluginToml { Ok(()) } - fn parse_script_config(&mut self, key: &str, v: &Item) -> Result { + fn parse_script_config(&mut self, key: &str, v: &Item) -> Result { match v.as_table_like() { Some(table) => { - let mut config = RtxPluginTomlScriptConfig::default(); + let mut config = MisePluginTomlScriptConfig::default(); for (k, v) in table.iter() { let key = format!("{}.{}", key, k); match k { @@ -108,7 +108,7 @@ mod tests { #[test] fn test_fixture() { - let cf = RtxPluginToml::from_file(&dirs::HOME.join("fixtures/rtx.plugin.toml")).unwrap(); + let cf = MisePluginToml::from_file(&dirs::HOME.join("fixtures/mise.plugin.toml")).unwrap(); assert_debug_snapshot!(cf.exec_env); } @@ -127,7 +127,7 @@ mod tests { "#}); assert_debug_snapshot!(cf.exec_env, @r###" - RtxPluginTomlScriptConfig { + MisePluginTomlScriptConfig { cache_key: Some( [ "foo", @@ -139,8 +139,8 @@ mod tests { "###); } - fn parse(s: &str) -> RtxPluginToml { - let mut cf = RtxPluginToml::init(); + fn parse(s: &str) -> MisePluginToml { + let mut cf = MisePluginToml::init(); cf.parse(s).unwrap(); cf } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 2dfc3dddc..b55100653 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -28,7 +28,7 @@ use crate::{dirs, file}; pub mod core; mod external_plugin; mod external_plugin_cache; -mod rtx_plugin_toml; +mod mise_plugin_toml; mod script_manager; pub type PluginName = String; diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 9e4259feb..683b1592a 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -74,22 +74,22 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { .map(|(k, v)| (k.into(), v.into())) .collect(); if settings.trace { - env.insert("RTX_TRACE".into(), "1".into()); + env.insert("MISE_TRACE".into(), "1".into()); } if settings.debug { - env.insert("RTX_DEBUG".into(), "1".into()); - env.insert("RTX_VERBOSE".into(), "1".into()); + env.insert("MISE_DEBUG".into(), "1".into()); + env.insert("MISE_VERBOSE".into(), "1".into()); } env.extend( (indexmap! { "ASDF_CONCURRENCY" => num_cpus::get().to_string(), "PATH" => get_path_with_fake_asdf(), - "RTX_BIN" => env::RTX_BIN.to_string_lossy().to_string(), - "RTX_CACHE_DIR" => env::RTX_CACHE_DIR.to_string_lossy().to_string(), - "RTX_CONCURRENCY" => num_cpus::get().to_string(), - "RTX_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), - "RTX_LOG_LEVEL" => settings.log_level.to_string(), - "__RTX_SCRIPT" => "1".to_string(), + "MISE_BIN" => env::MISE_BIN.to_string_lossy().to_string(), + "MISE_CACHE_DIR" => env::MISE_CACHE_DIR.to_string_lossy().to_string(), + "MISE_CONCURRENCY" => num_cpus::get().to_string(), + "MISE_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), + "MISE_LOG_LEVEL" => settings.log_level.to_string(), + "__MISE_SCRIPT" => "1".to_string(), }) .into_iter() .map(|(k, v)| (k.into(), v.into())), @@ -100,9 +100,9 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { impl ScriptManager { pub fn new(plugin_path: PathBuf) -> Self { let mut env = INITIAL_ENV.clone(); - if let Some(failure) = env::var_os("RTX_FAILURE") { + if let Some(failure) = env::var_os("MISE_FAILURE") { // used for testing failure cases - env.insert("RTX_FAILURE".into(), failure); + env.insert("MISE_FAILURE".into(), failure); } Self { plugin_name: basename(&plugin_path).expect("invalid plugin path"), diff --git a/src/plugins/snapshots/rtx__plugins__rtx_plugin_toml__tests__fixture.snap b/src/plugins/snapshots/mise__plugins__mise_plugin_toml__tests__fixture.snap similarity index 64% rename from src/plugins/snapshots/rtx__plugins__rtx_plugin_toml__tests__fixture.snap rename to src/plugins/snapshots/mise__plugins__mise_plugin_toml__tests__fixture.snap index e3e4ea3d4..d50624a2d 100644 --- a/src/plugins/snapshots/rtx__plugins__rtx_plugin_toml__tests__fixture.snap +++ b/src/plugins/snapshots/mise__plugins__mise_plugin_toml__tests__fixture.snap @@ -1,8 +1,8 @@ --- -source: src/plugins/rtx_plugin_toml.rs +source: src/plugins/mise_plugin_toml.rs expression: cf.exec_env --- -RtxPluginTomlScriptConfig { +MisePluginTomlScriptConfig { cache_key: Some( [ "{{'1234'}}", diff --git a/src/shell/bash.rs b/src/shell/bash.rs index e6e691bd9..84f4df48e 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -15,10 +15,10 @@ impl Shell for Bash { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" - export RTX_SHELL=bash - export __RTX_ORIG_PATH="$PATH" + export MISE_SHELL=bash + export __MISE_ORIG_PATH="$PATH" - rtx() {{ + mise() {{ local command command="${{1:-}}" if [ "$#" = 0 ]; then @@ -39,24 +39,24 @@ impl Shell for Bash { command {exe} "$command" "$@" }} - _rtx_hook() {{ + _mise_hook() {{ local previous_exit_status=$?; - eval "$(rtx hook-env{flags} -s bash)"; + eval "$(mise hook-env{flags} -s bash)"; return $previous_exit_status; }}; - if [[ ";${{PROMPT_COMMAND:-}};" != *";_rtx_hook;"* ]]; then - PROMPT_COMMAND="_rtx_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" + if [[ ";${{PROMPT_COMMAND:-}};" != *";_mise_hook;"* ]]; then + PROMPT_COMMAND="_mise_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" fi "#}); if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" - if [ -z "${{_rtx_cmd_not_found:-}}" ]; then - _rtx_cmd_not_found=1 + if [ -z "${{_mise_cmd_not_found:-}}" ]; then + _mise_cmd_not_found=1 test -n "$(declare -f command_not_found_handle)" && eval "${{_/command_not_found_handle/_command_not_found_handle}}" command_not_found_handle() {{ if {exe} hook-not-found -s bash "$1"; then - _rtx_hook + _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handle)" ]; then _command_not_found_handle "$@" @@ -74,11 +74,11 @@ impl Shell for Bash { fn deactivate(&self) -> String { formatdoc! {r#" - PROMPT_COMMAND="${{PROMPT_COMMAND//_rtx_hook;/}}" - PROMPT_COMMAND="${{PROMPT_COMMAND//_rtx_hook/}}" - unset _rtx_hook - unset rtx - unset RTX_SHELL + PROMPT_COMMAND="${{PROMPT_COMMAND//_mise_hook;/}}" + PROMPT_COMMAND="${{PROMPT_COMMAND//_mise_hook/}}" + unset _mise_hook + unset mise + unset MISE_SHELL "#} } @@ -104,14 +104,14 @@ mod tests { #[test] fn test_hook_init() { let bash = Bash::default(); - let exe = Path::new("/some/dir/rtx"); + let exe = Path::new("/some/dir/mise"); assert_snapshot!(bash.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let bash = Bash::default(); - let exe = Path::new("/nix/store/rtx"); + let exe = Path::new("/nix/store/mise"); assert_snapshot!(bash.activate(exe, " --status".into())); } diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index 22fa1ceed..53dfbc587 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -13,53 +13,53 @@ set -l fssf "__fish_seen_subcommand_from" {subcommands} -function __rtx_all_plugins - if test -z "$__rtx_all_plugins_cache" - set -g __rtx_all_plugins_cache (rtx plugins ls --all) +function __mise_all_plugins + if test -z "$__mise_all_plugins_cache" + set -g __mise_all_plugins_cache (mise plugins ls --all) end - for p in $__rtx_all_plugins_cache + for p in $__mise_all_plugins_cache echo $p end end -function __rtx_plugins - if test -z "$__rtx_plugins_cache" - set -g __rtx_plugins_cache (rtx plugins ls --core --user) +function __mise_plugins + if test -z "$__mise_plugins_cache" + set -g __mise_plugins_cache (mise plugins ls --core --user) end - for p in $__rtx_plugins_cache + for p in $__mise_plugins_cache echo $p end end -function __rtx_tool_versions - if test -z "$__rtx_tool_versions_cache" - set -g __rtx_tool_versions_cache (rtx plugins --core --user) (rtx ls-remote --all | tac) +function __mise_tool_versions + if test -z "$__mise_tool_versions_cache" + set -g __mise_tool_versions_cache (mise plugins --core --user) (mise ls-remote --all | tac) end - for tv in $__rtx_tool_versions_cache + for tv in $__mise_tool_versions_cache echo $tv end end -function __rtx_installed_tool_versions - for tv in (rtx ls --installed | awk '{{print $1 "@" $2}}') +function __mise_installed_tool_versions + for tv in (mise ls --installed | awk '{{print $1 "@" $2}}') echo $tv end end -function __rtx_aliases - if test -z "$__rtx_aliases_cache" - set -g __rtx_aliases_cache (rtx alias ls | awk '{{print $2}}') +function __mise_aliases + if test -z "$__mise_aliases_cache" + set -g __mise_aliases_cache (mise alias ls | awk '{{print $2}}') end - for a in $__rtx_aliases_cache + for a in $__mise_aliases_cache echo $a end end -function __rtx_tasks - for tv in (rtx task ls --no-header | awk '{{print $1}}') +function __mise_tasks + for tv in (mise task ls --no-header | awk '{{print $1}}') echo $tv end end -function __rtx_settings - if test -z "$__rtx_settings_cache" - set -g __rtx_settings_cache (rtx settings ls | awk '{{print $1}}') +function __mise_settings + if test -z "$__mise_settings_cache" + set -g __mise_settings_cache (mise settings ls | awk '{{print $1}}') end - for s in $__rtx_settings_cache + for s in $__mise_settings_cache echo $s end end @@ -78,7 +78,7 @@ fn render_args(cmds: &[&Command]) -> Vec { } fn render_arg(cmds: &[&Command], a: &Arg) -> String { - let mut complete_cmd = r#"complete -kxc rtx"#.to_string(); + let mut complete_cmd = r#"complete -kxc mise"#.to_string(); let parents = cmds.iter().skip(1).map(|c| c.get_name()).collect_vec(); if cmds.len() > 1 { let mut p = format!("$fssf {}", &parents[0]); @@ -117,14 +117,14 @@ fn render_completer(a: &Arg) -> Option { ValueHint::FilePath => Some("(__fish_complete_path)".to_string()), ValueHint::AnyPath => Some("(__fish_complete_path)".to_string()), _ => match a.get_id().as_str() { - "tool" => Some("(__rtx_tool_versions)".to_string()), - "installed_tool" => Some("(__rtx_installed_tool_versions)".to_string()), - "plugin" => Some("(__rtx_plugins)".to_string()), - "new_plugin" => Some("(__rtx_all_plugins)".to_string()), - "alias" => Some("(__rtx_aliases)".to_string()), - "setting" => Some("(__rtx_settings)".to_string()), - "task" => Some("(__rtx_tasks)".to_string()), - //"prefix" => Some("(__rtx_prefixes)".to_string()), + "tool" => Some("(__mise_tool_versions)".to_string()), + "installed_tool" => Some("(__mise_installed_tool_versions)".to_string()), + "plugin" => Some("(__mise_plugins)".to_string()), + "new_plugin" => Some("(__mise_all_plugins)".to_string()), + "alias" => Some("(__mise_aliases)".to_string()), + "setting" => Some("(__mise_settings)".to_string()), + "task" => Some("(__mise_tasks)".to_string()), + //"prefix" => Some("(__mise_prefixes)".to_string()), _ => None, }, } @@ -149,13 +149,13 @@ fn render_subcommands(cmds: &[&Command]) -> Vec { let name = cmd.get_name(); let help = about_to_help(cmd.get_about()); if parents.is_empty() { - format!(r#"complete -xc rtx -n "not $fssf $others" -a {name} -d '{help}'"#) + format!(r#"complete -xc mise -n "not $fssf $others" -a {name} -d '{help}'"#) } else { let mut p = format!("$fssf {}", &parents[0]); for parent in &parents[1..] { p.push_str(&format!("; and $fssf {}", parent)); } - format!(r#"complete -xc rtx -n "{p}; and not $fssf $others" -a {name} -d '{help}'"#) + format!(r#"complete -xc mise -n "{p}; and not $fssf $others" -a {name} -d '{help}'"#) } }); @@ -165,7 +165,7 @@ fn render_subcommands(cmds: &[&Command]) -> Vec { render_subcommands(&cmds) }); - let mut out = vec![format! {"# {}", if full_name.is_empty() { "rtx" } else { &full_name }}]; + let mut out = vec![format! {"# {}", if full_name.is_empty() { "mise" } else { &full_name }}]; out.extend(args); if !subcommands.is_empty() { out.push(format! {"set -l others {command_names}"}); diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index 904361b7f..f0923f6b2 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -9,8 +9,8 @@ pub fn render(cmd: &Command) -> String { let args = render_args(&cmds); formatdoc! {r#" - #compdef rtx - _rtx() {{ + #compdef mise + _mise() {{ typeset -A opt_args local context state line curcontext=$curcontext local ret=1 @@ -20,68 +20,68 @@ pub fn render(cmd: &Command) -> String { {command_funcs} {command_descriptions} - (( $+functions[__rtx_tool_versions] )) || - __rtx_tool_versions() {{ + (( $+functions[__mise_tool_versions] )) || + __mise_tool_versions() {{ if compset -P '*@'; then - local -a tool_versions; tool_versions=($(rtx ls-remote ${{words[CURRENT]}})) + local -a tool_versions; tool_versions=($(mise ls-remote ${{words[CURRENT]}})) _wanted tool_version expl 'version of tool' \ compadd -a tool_versions -o nosort else - local -a plugins; plugins=($(rtx plugins --core --user)) + local -a plugins; plugins=($(mise plugins --core --user)) _wanted plugin expl 'plugin name' \ compadd -S '@' -a plugins fi }} - (( $+functions[__rtx_installed_tool_versions] )) || - __rtx_installed_tool_versions() {{ + (( $+functions[__mise_installed_tool_versions] )) || + __mise_installed_tool_versions() {{ if compset -P '*@'; then local plugin; plugin=${{words[CURRENT]%%@*}} - local -a installed_tool_versions; installed_tool_versions=($(rtx ls --installed $plugin | awk '{{print $2}}')) + local -a installed_tool_versions; installed_tool_versions=($(mise ls --installed $plugin | awk '{{print $2}}')) _wanted installed_tool_version expl 'version of tool' \ compadd -a installed_tool_versions -o nosort else - local -a plugins; plugins=($(rtx plugins --core --user)) + local -a plugins; plugins=($(mise plugins --core --user)) _wanted plugin expl 'plugin name' \ compadd -S '@' -a plugins fi }} - (( $+functions[__rtx_plugins] )) || - __rtx_plugins() {{ - local -a plugins; plugins=($(rtx plugins --core --user)) + (( $+functions[__mise_plugins] )) || + __mise_plugins() {{ + local -a plugins; plugins=($(mise plugins --core --user)) _describe -t plugins 'plugin' plugins "$@" }} - (( $+functions[__rtx_all_plugins] )) || - __rtx_all_plugins() {{ - local -a all_plugins; all_plugins=($(rtx plugins --all)) + (( $+functions[__mise_all_plugins] )) || + __mise_all_plugins() {{ + local -a all_plugins; all_plugins=($(mise plugins --all)) _describe -t all_plugins 'all_plugins' all_plugins "$@" }} - (( $+functions[__rtx_aliases] )) || - __rtx_aliases() {{ - local -a aliases; aliases=($(rtx aliases ls ${{words[CURRENT-1]}} | awk '{{print $2}}')) + (( $+functions[__mise_aliases] )) || + __mise_aliases() {{ + local -a aliases; aliases=($(mise aliases ls ${{words[CURRENT-1]}} | awk '{{print $2}}')) _describe -t aliases 'alias' aliases "$@" }} - (( $+functions[__rtx_settings] )) || - __rtx_settings() {{ - local -a settings; settings=($(rtx settings ls | awk '{{print $1}}')) + (( $+functions[__mise_settings] )) || + __mise_settings() {{ + local -a settings; settings=($(mise settings ls | awk '{{print $1}}')) _describe -t settings 'setting' settings "$@" }} - (( $+functions[__rtx_tasks] )) || - __rtx_tasks() {{ - local -a tasks; tasks=($(rtx tasks ls --no-header | awk '{{print $1}}')) + (( $+functions[__mise_tasks] )) || + __mise_tasks() {{ + local -a tasks; tasks=($(mise tasks ls --no-header | awk '{{print $1}}')) _describe -t tasks 'task' tasks "$@" }} - (( $+functions[__rtx_prefixes] )) || - __rtx_prefixes() {{ + (( $+functions[__mise_prefixes] )) || + __mise_prefixes() {{ if [[ CURRENT -gt 2 ]]; then - local -a prefixes; prefixes=($(rtx ls-remote ${{words[CURRENT-1]}})) + local -a prefixes; prefixes=($(mise ls-remote ${{words[CURRENT-1]}})) _describe -t prefixes 'prefix' prefixes "$@" fi }} - if [ "$funcstack[1]" = "_rtx" ]; then - _rtx "$@" + if [ "$funcstack[1]" = "_mise" ]; then + _mise "$@" else - compdef _rtx rtx + compdef _mise mise fi # vim: noet ci pi sts=0 sw=4 ts=4 @@ -143,7 +143,7 @@ fn render_subcommands(cmds: &[&Command]) -> String { formatdoc! {r#" case "$state" in (args) - curcontext="${{curcontext%:*:*}}:rtx-cmd-$words[1]:" + curcontext="${{curcontext%:*:*}}:mise-cmd-$words[1]:" case $words[1] in {cases} esac @@ -233,14 +233,14 @@ fn render_completion(arg: &Arg) -> String { ValueHint::EmailAddress => "_email_addresses".to_string(), ValueHint::Other => "( )".to_string(), _ => match arg.get_id().as_str() { - "tool" => "__rtx_tool_versions".to_string(), - "installed_tool" => "__rtx_installed_tool_versions".to_string(), - "plugin" => "__rtx_plugins".to_string(), - "new_plugin" => "__rtx_all_plugins".to_string(), - "alias" => "__rtx_aliases".to_string(), - "setting" => "__rtx_settings".to_string(), - "task" => "__rtx_tasks".to_string(), - "prefix" => "__rtx_prefixes".to_string(), + "tool" => "__mise_tool_versions".to_string(), + "installed_tool" => "__mise_installed_tool_versions".to_string(), + "plugin" => "__mise_plugins".to_string(), + "new_plugin" => "__mise_all_plugins".to_string(), + "alias" => "__mise_aliases".to_string(), + "setting" => "__mise_settings".to_string(), + "task" => "__mise_tasks".to_string(), + "prefix" => "__mise_prefixes".to_string(), _ => String::new(), }, } diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 6fa97df91..2e1c9b6a0 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -10,7 +10,7 @@ impl Shell for Fish { fn activate(&self, exe: &Path, flags: String) -> String { let dir = exe.parent().unwrap(); let exe = exe.to_string_lossy(); - let description = "'Update rtx environment when changing directories'"; + let description = "'Update mise environment when changing directories'"; let mut out = String::new(); if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { @@ -20,10 +20,10 @@ impl Shell for Fish { // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_fish.go#L14-L36 out.push_str(&formatdoc! {r#" - set -gx RTX_SHELL fish - set -gx __RTX_ORIG_PATH $PATH + set -gx MISE_SHELL fish + set -gx __MISE_ORIG_PATH $PATH - function rtx + function mise if test (count $argv) -eq 0 command {exe} return @@ -52,13 +52,13 @@ impl Shell for Fish { end end - function __rtx_env_eval --on-event fish_prompt --description {description}; + function __mise_env_eval --on-event fish_prompt --description {description}; {exe} hook-env{flags} -s fish | source; - if test "$rtx_fish_mode" != "disable_arrow"; - function __rtx_cd_hook --on-variable PWD --description {description}; - if test "$rtx_fish_mode" = "eval_after_arrow"; - set -g __rtx_env_again 0; + if test "$mise_fish_mode" != "disable_arrow"; + function __mise_cd_hook --on-variable PWD --description {description}; + if test "$mise_fish_mode" = "eval_after_arrow"; + set -g __mise_env_again 0; else; {exe} hook-env{flags} -s fish | source; end; @@ -66,14 +66,14 @@ impl Shell for Fish { end; end; - function __rtx_env_eval_2 --on-event fish_preexec --description {description}; - if set -q __rtx_env_again; - set -e __rtx_env_again; + function __mise_env_eval_2 --on-event fish_preexec --description {description}; + if set -q __mise_env_again; + set -e __mise_env_again; {exe} hook-env{flags} -s fish | source; echo; end; - functions --erase __rtx_cd_hook; + functions --erase __mise_cd_hook; end; "#}); if Settings::get().not_found_auto_install { @@ -93,11 +93,11 @@ impl Shell for Fish { fn deactivate(&self) -> String { formatdoc! {r#" - functions --erase __rtx_env_eval - functions --erase __rtx_env_eval_2 - functions --erase __rtx_cd_hook - functions --erase rtx - set -e RTX_SHELL + functions --erase __mise_env_eval + functions --erase __mise_env_eval_2 + functions --erase __mise_cd_hook + functions --erase mise + set -e MISE_SHELL "#} } @@ -123,14 +123,14 @@ mod tests { #[test] fn test_hook_init() { let fish = Fish::default(); - let exe = Path::new("/some/dir/rtx"); + let exe = Path::new("/some/dir/mise"); assert_snapshot!(fish.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let fish = Fish::default(); - let exe = Path::new("/nix/store/rtx"); + let exe = Path::new("/nix/store/mise"); assert_snapshot!(fish.activate(exe, " --status".into())); } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 6742efb7e..24706c070 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -23,7 +23,7 @@ pub enum ShellType { impl ShellType { pub fn load() -> Option { - let shell = env::var("RTX_SHELL").or(env::var("SHELL")).ok()?; + let shell = env::var("MISE_SHELL").or(env::var("SHELL")).ok()?; if shell.ends_with("bash") { Some(ShellType::Bash) } else if shell.ends_with("fish") { diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 77833563c..ce0c5a9da 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -35,19 +35,19 @@ impl Shell for Nushell { out.push_str(&formatdoc! {r#" export-env {{ - $env.RTX_SHELL = "nu" + $env.MISE_SHELL = "nu" $env.config = ($env.config | upsert hooks {{ pre_prompt: ($env.config.hooks.pre_prompt ++ [{{ - condition: {{|| "RTX_SHELL" in $env }} - code: {{|| rtx_hook }} + condition: {{|| "MISE_SHELL" in $env }} + code: {{|| mise_hook }} }}]) env_change: {{ PWD: ($env.config.hooks.env_change.PWD ++ [{{ - condition: {{|| "RTX_SHELL" in $env }} - code: {{|| rtx_hook }} + condition: {{|| "MISE_SHELL" in $env }} + code: {{|| mise_hook }} }}]) }} }}) @@ -57,13 +57,13 @@ impl Shell for Nushell { $in | lines | parse "{{op}},{{name}},{{value}}" }} - def --wrapped rtx [command?: string, --help, ...rest: string] {{ + def --wrapped mise [command?: string, --help, ...rest: string] {{ let commands = ["shell", "deactivate"] if ($command == null) {{ ^"{exe}" }} else if ($command == "activate") {{ - $env.RTX_SHELL = "nu" + $env.MISE_SHELL = "nu" }} else if ($command in $commands) {{ ^"{exe}" $command $rest | parse vars @@ -83,7 +83,7 @@ impl Shell for Nushell { }} }} - def --env rtx_hook [] {{ + def --env mise_hook [] {{ ^"{exe}" hook-env{flags} -s nu | parse vars | update-env @@ -95,7 +95,7 @@ impl Shell for Nushell { } fn deactivate(&self) -> String { - self.unset_env("RTX_SHELL") + self.unset_env("MISE_SHELL") } fn set_env(&self, k: &str, v: &str) -> String { @@ -123,14 +123,14 @@ mod tests { #[test] fn test_hook_init() { let nushell = Nushell::default(); - let exe = Path::new("/some/dir/rtx"); + let exe = Path::new("/some/dir/mise"); assert_snapshot!(nushell.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let nushell = Nushell::default(); - let exe = Path::new("/nix/store/rtx"); + let exe = Path::new("/nix/store/mise"); assert_snapshot!(nushell.activate(exe, " --status".into())); } diff --git a/src/shell/snapshots/mise__shell__bash__tests__deactivate.snap b/src/shell/snapshots/mise__shell__bash__tests__deactivate.snap new file mode 100644 index 000000000..b0703ede2 --- /dev/null +++ b/src/shell/snapshots/mise__shell__bash__tests__deactivate.snap @@ -0,0 +1,10 @@ +--- +source: src/shell/bash.rs +expression: replace_path(&deactivate) +--- +PROMPT_COMMAND="${PROMPT_COMMAND//_mise_hook;/}" +PROMPT_COMMAND="${PROMPT_COMMAND//_mise_hook/}" +unset _mise_hook +unset mise +unset MISE_SHELL + diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap similarity index 62% rename from src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap rename to src/shell/snapshots/mise__shell__bash__tests__hook_init.snap index 5c1dcacf8..e70500125 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap @@ -3,14 +3,14 @@ source: src/shell/bash.rs expression: "bash.activate(exe, \" --status\".into())" --- export PATH="/some/dir:$PATH" -export RTX_SHELL=bash -export __RTX_ORIG_PATH="$PATH" +export MISE_SHELL=bash +export __MISE_ORIG_PATH="$PATH" -rtx() { +mise() { local command command="${1:-}" if [ "$#" = 0 ]; then - command /some/dir/rtx + command /some/dir/mise return fi shift @@ -19,29 +19,29 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command /some/dir/rtx "$command" "$@")" + eval "$(command /some/dir/mise "$command" "$@")" return $? fi ;; esac - command /some/dir/rtx "$command" "$@" + command /some/dir/mise "$command" "$@" } -_rtx_hook() { +_mise_hook() { local previous_exit_status=$?; - eval "$(rtx hook-env --status -s bash)"; + eval "$(mise hook-env --status -s bash)"; return $previous_exit_status; }; -if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then - PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" +if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then + PROMPT_COMMAND="_mise_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi -if [ -z "${_rtx_cmd_not_found:-}" ]; then - _rtx_cmd_not_found=1 +if [ -z "${_mise_cmd_not_found:-}" ]; then + _mise_cmd_not_found=1 test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" command_not_found_handle() { - if /some/dir/rtx hook-not-found -s bash "$1"; then - _rtx_hook + if /some/dir/mise hook-not-found -s bash "$1"; then + _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handle)" ]; then _command_not_found_handle "$@" diff --git a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap similarity index 61% rename from src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap rename to src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap index b8df24524..3a11c21a3 100644 --- a/src/shell/snapshots/rtx__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap @@ -2,14 +2,14 @@ source: src/shell/bash.rs expression: "bash.activate(exe, \" --status\".into())" --- -export RTX_SHELL=bash -export __RTX_ORIG_PATH="$PATH" +export MISE_SHELL=bash +export __MISE_ORIG_PATH="$PATH" -rtx() { +mise() { local command command="${1:-}" if [ "$#" = 0 ]; then - command /nix/store/rtx + command /nix/store/mise return fi shift @@ -18,29 +18,29 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command /nix/store/rtx "$command" "$@")" + eval "$(command /nix/store/mise "$command" "$@")" return $? fi ;; esac - command /nix/store/rtx "$command" "$@" + command /nix/store/mise "$command" "$@" } -_rtx_hook() { +_mise_hook() { local previous_exit_status=$?; - eval "$(rtx hook-env --status -s bash)"; + eval "$(mise hook-env --status -s bash)"; return $previous_exit_status; }; -if [[ ";${PROMPT_COMMAND:-};" != *";_rtx_hook;"* ]]; then - PROMPT_COMMAND="_rtx_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" +if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then + PROMPT_COMMAND="_mise_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" fi -if [ -z "${_rtx_cmd_not_found:-}" ]; then - _rtx_cmd_not_found=1 +if [ -z "${_mise_cmd_not_found:-}" ]; then + _mise_cmd_not_found=1 test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" command_not_found_handle() { - if /nix/store/rtx hook-not-found -s bash "$1"; then - _rtx_hook + if /nix/store/mise hook-not-found -s bash "$1"; then + _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handle)" ]; then _command_not_found_handle "$@" diff --git a/src/shell/snapshots/rtx__shell__bash__tests__set_env.snap b/src/shell/snapshots/mise__shell__bash__tests__set_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__bash__tests__set_env.snap rename to src/shell/snapshots/mise__shell__bash__tests__set_env.snap diff --git a/src/shell/snapshots/rtx__shell__bash__tests__unset_env.snap b/src/shell/snapshots/mise__shell__bash__tests__unset_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__bash__tests__unset_env.snap rename to src/shell/snapshots/mise__shell__bash__tests__unset_env.snap diff --git a/src/shell/snapshots/mise__shell__fish__tests__deactivate.snap b/src/shell/snapshots/mise__shell__fish__tests__deactivate.snap new file mode 100644 index 000000000..ec3fb7a79 --- /dev/null +++ b/src/shell/snapshots/mise__shell__fish__tests__deactivate.snap @@ -0,0 +1,10 @@ +--- +source: src/shell/fish.rs +expression: replace_path(&deactivate) +--- +functions --erase __mise_env_eval +functions --erase __mise_env_eval_2 +functions --erase __mise_cd_hook +functions --erase mise +set -e MISE_SHELL + diff --git a/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap b/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap new file mode 100644 index 000000000..c970b7ca1 --- /dev/null +++ b/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap @@ -0,0 +1,68 @@ +--- +source: src/shell/fish.rs +expression: "fish.activate(exe, \" --status\".into())" +--- +fish_add_path -g /some/dir +set -gx MISE_SHELL fish +set -gx __MISE_ORIG_PATH $PATH + +function mise + if test (count $argv) -eq 0 + command /some/dir/mise + return + end + + set command $argv[1] + set -e argv[1] + + if contains -- --help $argv + command /some/dir/mise "$command" $argv + return $status + end + + switch "$command" + case deactivate s shell + # if help is requested, don't eval + if contains -- -h $argv + command /some/dir/mise "$command" $argv + else if contains -- --help $argv + command /some/dir/mise "$command" $argv + else + source (command /some/dir/mise "$command" $argv |psub) + end + case '*' + command /some/dir/mise "$command" $argv + end +end + +function __mise_env_eval --on-event fish_prompt --description 'Update mise environment when changing directories'; + /some/dir/mise hook-env --status -s fish | source; + + if test "$mise_fish_mode" != "disable_arrow"; + function __mise_cd_hook --on-variable PWD --description 'Update mise environment when changing directories'; + if test "$mise_fish_mode" = "eval_after_arrow"; + set -g __mise_env_again 0; + else; + /some/dir/mise hook-env --status -s fish | source; + end; + end; + end; +end; + +function __mise_env_eval_2 --on-event fish_preexec --description 'Update mise environment when changing directories'; + if set -q __mise_env_again; + set -e __mise_env_again; + /some/dir/mise hook-env --status -s fish | source; + echo; + end; + + functions --erase __mise_cd_hook; +end; +function fish_command_not_found + if /some/dir/mise hook-not-found -s fish $argv[1] + /some/dir/mise hook-env --status -s fish | source + else + __fish_default_command_not_found_handler $argv + end +end + diff --git a/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap new file mode 100644 index 000000000..86fd07d51 --- /dev/null +++ b/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap @@ -0,0 +1,67 @@ +--- +source: src/shell/fish.rs +expression: "fish.activate(exe, \" --status\".into())" +--- +set -gx MISE_SHELL fish +set -gx __MISE_ORIG_PATH $PATH + +function mise + if test (count $argv) -eq 0 + command /nix/store/mise + return + end + + set command $argv[1] + set -e argv[1] + + if contains -- --help $argv + command /nix/store/mise "$command" $argv + return $status + end + + switch "$command" + case deactivate s shell + # if help is requested, don't eval + if contains -- -h $argv + command /nix/store/mise "$command" $argv + else if contains -- --help $argv + command /nix/store/mise "$command" $argv + else + source (command /nix/store/mise "$command" $argv |psub) + end + case '*' + command /nix/store/mise "$command" $argv + end +end + +function __mise_env_eval --on-event fish_prompt --description 'Update mise environment when changing directories'; + /nix/store/mise hook-env --status -s fish | source; + + if test "$mise_fish_mode" != "disable_arrow"; + function __mise_cd_hook --on-variable PWD --description 'Update mise environment when changing directories'; + if test "$mise_fish_mode" = "eval_after_arrow"; + set -g __mise_env_again 0; + else; + /nix/store/mise hook-env --status -s fish | source; + end; + end; + end; +end; + +function __mise_env_eval_2 --on-event fish_preexec --description 'Update mise environment when changing directories'; + if set -q __mise_env_again; + set -e __mise_env_again; + /nix/store/mise hook-env --status -s fish | source; + echo; + end; + + functions --erase __mise_cd_hook; +end; +function fish_command_not_found + if /nix/store/mise hook-not-found -s fish $argv[1] + /nix/store/mise hook-env --status -s fish | source + else + __fish_default_command_not_found_handler $argv + end +end + diff --git a/src/shell/snapshots/rtx__shell__fish__tests__set_env.snap b/src/shell/snapshots/mise__shell__fish__tests__set_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__fish__tests__set_env.snap rename to src/shell/snapshots/mise__shell__fish__tests__set_env.snap diff --git a/src/shell/snapshots/rtx__shell__fish__tests__unset_env.snap b/src/shell/snapshots/mise__shell__fish__tests__unset_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__fish__tests__unset_env.snap rename to src/shell/snapshots/mise__shell__fish__tests__unset_env.snap diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__deactivate.snap b/src/shell/snapshots/mise__shell__nushell__tests__deactivate.snap similarity index 81% rename from src/shell/snapshots/rtx__shell__nushell__tests__deactivate.snap rename to src/shell/snapshots/mise__shell__nushell__tests__deactivate.snap index 6e30315a9..e45bdf6e9 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__deactivate.snap +++ b/src/shell/snapshots/mise__shell__nushell__tests__deactivate.snap @@ -2,5 +2,5 @@ source: src/shell/nushell.rs expression: replace_path(&deactivate) --- -hide,RTX_SHELL, +hide,MISE_SHELL, diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap similarity index 67% rename from src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap rename to src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap index ad3b38e14..83a864d19 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap @@ -4,19 +4,19 @@ expression: "nushell.activate(exe, \" --status\".into())" --- $env.PATH = ($env.PATH | prepend '/some/dir') export-env { - $env.RTX_SHELL = "nu" + $env.MISE_SHELL = "nu" $env.config = ($env.config | upsert hooks { pre_prompt: ($env.config.hooks.pre_prompt ++ [{ - condition: {|| "RTX_SHELL" in $env } - code: {|| rtx_hook } + condition: {|| "MISE_SHELL" in $env } + code: {|| mise_hook } }]) env_change: { PWD: ($env.config.hooks.env_change.PWD ++ [{ - condition: {|| "RTX_SHELL" in $env } - code: {|| rtx_hook } + condition: {|| "MISE_SHELL" in $env } + code: {|| mise_hook } }]) } }) @@ -26,19 +26,19 @@ def "parse vars" [] { $in | lines | parse "{op},{name},{value}" } -def --wrapped rtx [command?: string, --help, ...rest: string] { +def --wrapped mise [command?: string, --help, ...rest: string] { let commands = ["shell", "deactivate"] if ($command == null) { - ^"/some/dir/rtx" + ^"/some/dir/mise" } else if ($command == "activate") { - $env.RTX_SHELL = "nu" + $env.MISE_SHELL = "nu" } else if ($command in $commands) { - ^"/some/dir/rtx" $command $rest + ^"/some/dir/mise" $command $rest | parse vars | update-env } else { - ^"/some/dir/rtx" $command $rest + ^"/some/dir/mise" $command $rest } } @@ -52,8 +52,8 @@ def --env "update-env" [] { } } -def --env rtx_hook [] { - ^"/some/dir/rtx" hook-env --status -s nu +def --env mise_hook [] { + ^"/some/dir/mise" hook-env --status -s nu | parse vars | update-env } diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap similarity index 65% rename from src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap rename to src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap index b6fc7f4f1..a932c26b2 100644 --- a/src/shell/snapshots/rtx__shell__nushell__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap @@ -3,19 +3,19 @@ source: src/shell/nushell.rs expression: "nushell.activate(exe, \" --status\".into())" --- export-env { - $env.RTX_SHELL = "nu" + $env.MISE_SHELL = "nu" $env.config = ($env.config | upsert hooks { pre_prompt: ($env.config.hooks.pre_prompt ++ [{ - condition: {|| "RTX_SHELL" in $env } - code: {|| rtx_hook } + condition: {|| "MISE_SHELL" in $env } + code: {|| mise_hook } }]) env_change: { PWD: ($env.config.hooks.env_change.PWD ++ [{ - condition: {|| "RTX_SHELL" in $env } - code: {|| rtx_hook } + condition: {|| "MISE_SHELL" in $env } + code: {|| mise_hook } }]) } }) @@ -25,19 +25,19 @@ def "parse vars" [] { $in | lines | parse "{op},{name},{value}" } -def --wrapped rtx [command?: string, --help, ...rest: string] { +def --wrapped mise [command?: string, --help, ...rest: string] { let commands = ["shell", "deactivate"] if ($command == null) { - ^"/nix/store/rtx" + ^"/nix/store/mise" } else if ($command == "activate") { - $env.RTX_SHELL = "nu" + $env.MISE_SHELL = "nu" } else if ($command in $commands) { - ^"/nix/store/rtx" $command $rest + ^"/nix/store/mise" $command $rest | parse vars | update-env } else { - ^"/nix/store/rtx" $command $rest + ^"/nix/store/mise" $command $rest } } @@ -51,8 +51,8 @@ def --env "update-env" [] { } } -def --env rtx_hook [] { - ^"/nix/store/rtx" hook-env --status -s nu +def --env mise_hook [] { + ^"/nix/store/mise" hook-env --status -s nu | parse vars | update-env } diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__set_env.snap b/src/shell/snapshots/mise__shell__nushell__tests__set_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__nushell__tests__set_env.snap rename to src/shell/snapshots/mise__shell__nushell__tests__set_env.snap diff --git a/src/shell/snapshots/rtx__shell__nushell__tests__unset_env.snap b/src/shell/snapshots/mise__shell__nushell__tests__unset_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__nushell__tests__unset_env.snap rename to src/shell/snapshots/mise__shell__nushell__tests__unset_env.snap diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap b/src/shell/snapshots/mise__shell__xonsh__tests__hook_init.snap similarity index 87% rename from src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap rename to src/shell/snapshots/mise__shell__xonsh__tests__hook_init.snap index 5fda84d35..5dd6b1782 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__xonsh__tests__hook_init.snap @@ -10,7 +10,7 @@ envx['PATH'].add('/some/dir') environ['PATH'] = envx.get_detyped('PATH') def listen_prompt(): # Hook Events - execx($(/some/dir/rtx hook-env --status -s xonsh)) + execx($(/some/dir/mise hook-env --status -s xonsh)) XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__xonsh__tests__hook_init_nix.snap similarity index 84% rename from src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap rename to src/shell/snapshots/mise__shell__xonsh__tests__hook_init_nix.snap index 803db0e6a..c0acff732 100644 --- a/src/shell/snapshots/rtx__shell__xonsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__xonsh__tests__hook_init_nix.snap @@ -6,7 +6,7 @@ from os import environ from xonsh.built_ins import XSH def listen_prompt(): # Hook Events - execx($(/nix/store/rtx hook-env --status -s xonsh)) + execx($(/nix/store/mise hook-env --status -s xonsh)) XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__set_env.snap b/src/shell/snapshots/mise__shell__xonsh__tests__set_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__xonsh__tests__set_env.snap rename to src/shell/snapshots/mise__shell__xonsh__tests__set_env.snap diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap b/src/shell/snapshots/mise__shell__xonsh__tests__unset_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__xonsh__tests__unset_env.snap rename to src/shell/snapshots/mise__shell__xonsh__tests__unset_env.snap diff --git a/src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap b/src/shell/snapshots/mise__shell__xonsh__tests__xonsh_deactivate.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__xonsh__tests__xonsh_deactivate.snap rename to src/shell/snapshots/mise__shell__xonsh__tests__xonsh_deactivate.snap diff --git a/src/shell/snapshots/mise__shell__zsh__tests__deactivate.snap b/src/shell/snapshots/mise__shell__zsh__tests__deactivate.snap new file mode 100644 index 000000000..82ea88a51 --- /dev/null +++ b/src/shell/snapshots/mise__shell__zsh__tests__deactivate.snap @@ -0,0 +1,10 @@ +--- +source: src/shell/zsh.rs +expression: replace_path(&deactivate) +--- +precmd_functions=( ${precmd_functions:#_mise_hook} ) +chpwd_functions=( ${chpwd_functions:#_mise_hook} ) +unset -f _mise_hook +unset -f mise +unset MISE_SHELL + diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap similarity index 57% rename from src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap rename to src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap index 2bffea535..7d5b0b29d 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap @@ -3,14 +3,14 @@ source: src/shell/zsh.rs expression: "zsh.activate(exe, \" --status\".into())" --- export PATH="/some/dir:$PATH" -export RTX_SHELL=zsh -export __RTX_ORIG_PATH="$PATH" +export MISE_SHELL=zsh +export __MISE_ORIG_PATH="$PATH" -rtx() { +mise() { local command command="${1:-}" if [ "$#" = 0 ]; then - command /some/dir/rtx + command /some/dir/mise return fi shift @@ -19,33 +19,33 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command /some/dir/rtx "$command" "$@")" + eval "$(command /some/dir/mise "$command" "$@")" return $? fi ;; esac - command /some/dir/rtx "$command" "$@" + command /some/dir/mise "$command" "$@" } -_rtx_hook() { - eval "$(/some/dir/rtx hook-env --status -s zsh)"; +_mise_hook() { + eval "$(/some/dir/mise hook-env --status -s zsh)"; } typeset -ag precmd_functions; -if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then - precmd_functions=( _rtx_hook ${precmd_functions[@]} ) +if [[ -z "${precmd_functions[(r)_mise_hook]+1}" ]]; then + precmd_functions=( _mise_hook ${precmd_functions[@]} ) fi typeset -ag chpwd_functions; -if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then - chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) +if [[ -z "${chpwd_functions[(r)_mise_hook]+1}" ]]; then + chpwd_functions=( _mise_hook ${chpwd_functions[@]} ) fi -if [ -z "${_rtx_cmd_not_found:-}" ]; then - _rtx_cmd_not_found=1 +if [ -z "${_mise_cmd_not_found:-}" ]; then + _mise_cmd_not_found=1 test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { - if /some/dir/rtx hook-not-found -s zsh "$1"; then - _rtx_hook + if /some/dir/mise hook-not-found -s zsh "$1"; then + _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handler)" ]; then _command_not_found_handler "$@" diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap similarity index 56% rename from src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap rename to src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap index ef746b2b1..e84472f6f 100644 --- a/src/shell/snapshots/rtx__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap @@ -2,14 +2,14 @@ source: src/shell/zsh.rs expression: "zsh.activate(exe, \" --status\".into())" --- -export RTX_SHELL=zsh -export __RTX_ORIG_PATH="$PATH" +export MISE_SHELL=zsh +export __MISE_ORIG_PATH="$PATH" -rtx() { +mise() { local command command="${1:-}" if [ "$#" = 0 ]; then - command /nix/store/rtx + command /nix/store/mise return fi shift @@ -18,33 +18,33 @@ rtx() { deactivate|s|shell) # if argv doesn't contains -h,--help if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command /nix/store/rtx "$command" "$@")" + eval "$(command /nix/store/mise "$command" "$@")" return $? fi ;; esac - command /nix/store/rtx "$command" "$@" + command /nix/store/mise "$command" "$@" } -_rtx_hook() { - eval "$(/nix/store/rtx hook-env --status -s zsh)"; +_mise_hook() { + eval "$(/nix/store/mise hook-env --status -s zsh)"; } typeset -ag precmd_functions; -if [[ -z "${precmd_functions[(r)_rtx_hook]+1}" ]]; then - precmd_functions=( _rtx_hook ${precmd_functions[@]} ) +if [[ -z "${precmd_functions[(r)_mise_hook]+1}" ]]; then + precmd_functions=( _mise_hook ${precmd_functions[@]} ) fi typeset -ag chpwd_functions; -if [[ -z "${chpwd_functions[(r)_rtx_hook]+1}" ]]; then - chpwd_functions=( _rtx_hook ${chpwd_functions[@]} ) +if [[ -z "${chpwd_functions[(r)_mise_hook]+1}" ]]; then + chpwd_functions=( _mise_hook ${chpwd_functions[@]} ) fi -if [ -z "${_rtx_cmd_not_found:-}" ]; then - _rtx_cmd_not_found=1 +if [ -z "${_mise_cmd_not_found:-}" ]; then + _mise_cmd_not_found=1 test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { - if /nix/store/rtx hook-not-found -s zsh "$1"; then - _rtx_hook + if /nix/store/mise hook-not-found -s zsh "$1"; then + _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handler)" ]; then _command_not_found_handler "$@" diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__set_env.snap b/src/shell/snapshots/mise__shell__zsh__tests__set_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__zsh__tests__set_env.snap rename to src/shell/snapshots/mise__shell__zsh__tests__set_env.snap diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__unset_env.snap b/src/shell/snapshots/mise__shell__zsh__tests__unset_env.snap similarity index 100% rename from src/shell/snapshots/rtx__shell__zsh__tests__unset_env.snap rename to src/shell/snapshots/mise__shell__zsh__tests__unset_env.snap diff --git a/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap deleted file mode 100644 index bd78efebb..000000000 --- a/src/shell/snapshots/rtx__shell__bash__tests__deactivate.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: src/shell/bash.rs -expression: replace_path(&deactivate) ---- -PROMPT_COMMAND="${PROMPT_COMMAND//_rtx_hook;/}" -PROMPT_COMMAND="${PROMPT_COMMAND//_rtx_hook/}" -unset _rtx_hook -unset rtx -unset RTX_SHELL - diff --git a/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap deleted file mode 100644 index 76bb1967a..000000000 --- a/src/shell/snapshots/rtx__shell__fish__tests__deactivate.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: src/shell/fish.rs -expression: replace_path(&deactivate) ---- -functions --erase __rtx_env_eval -functions --erase __rtx_env_eval_2 -functions --erase __rtx_cd_hook -functions --erase rtx -set -e RTX_SHELL - diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap deleted file mode 100644 index e79cca36d..000000000 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init.snap +++ /dev/null @@ -1,68 +0,0 @@ ---- -source: src/shell/fish.rs -expression: "fish.activate(exe, \" --status\".into())" ---- -fish_add_path -g /some/dir -set -gx RTX_SHELL fish -set -gx __RTX_ORIG_PATH $PATH - -function rtx - if test (count $argv) -eq 0 - command /some/dir/rtx - return - end - - set command $argv[1] - set -e argv[1] - - if contains -- --help $argv - command /some/dir/rtx "$command" $argv - return $status - end - - switch "$command" - case deactivate s shell - # if help is requested, don't eval - if contains -- -h $argv - command /some/dir/rtx "$command" $argv - else if contains -- --help $argv - command /some/dir/rtx "$command" $argv - else - source (command /some/dir/rtx "$command" $argv |psub) - end - case '*' - command /some/dir/rtx "$command" $argv - end -end - -function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; - /some/dir/rtx hook-env --status -s fish | source; - - if test "$rtx_fish_mode" != "disable_arrow"; - function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; - if test "$rtx_fish_mode" = "eval_after_arrow"; - set -g __rtx_env_again 0; - else; - /some/dir/rtx hook-env --status -s fish | source; - end; - end; - end; -end; - -function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; - if set -q __rtx_env_again; - set -e __rtx_env_again; - /some/dir/rtx hook-env --status -s fish | source; - echo; - end; - - functions --erase __rtx_cd_hook; -end; -function fish_command_not_found - if /some/dir/rtx hook-not-found -s fish $argv[1] - /some/dir/rtx hook-env --status -s fish | source - else - __fish_default_command_not_found_handler $argv - end -end - diff --git a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap deleted file mode 100644 index 1a9296e35..000000000 --- a/src/shell/snapshots/rtx__shell__fish__tests__hook_init_nix.snap +++ /dev/null @@ -1,67 +0,0 @@ ---- -source: src/shell/fish.rs -expression: "fish.activate(exe, \" --status\".into())" ---- -set -gx RTX_SHELL fish -set -gx __RTX_ORIG_PATH $PATH - -function rtx - if test (count $argv) -eq 0 - command /nix/store/rtx - return - end - - set command $argv[1] - set -e argv[1] - - if contains -- --help $argv - command /nix/store/rtx "$command" $argv - return $status - end - - switch "$command" - case deactivate s shell - # if help is requested, don't eval - if contains -- -h $argv - command /nix/store/rtx "$command" $argv - else if contains -- --help $argv - command /nix/store/rtx "$command" $argv - else - source (command /nix/store/rtx "$command" $argv |psub) - end - case '*' - command /nix/store/rtx "$command" $argv - end -end - -function __rtx_env_eval --on-event fish_prompt --description 'Update rtx environment when changing directories'; - /nix/store/rtx hook-env --status -s fish | source; - - if test "$rtx_fish_mode" != "disable_arrow"; - function __rtx_cd_hook --on-variable PWD --description 'Update rtx environment when changing directories'; - if test "$rtx_fish_mode" = "eval_after_arrow"; - set -g __rtx_env_again 0; - else; - /nix/store/rtx hook-env --status -s fish | source; - end; - end; - end; -end; - -function __rtx_env_eval_2 --on-event fish_preexec --description 'Update rtx environment when changing directories'; - if set -q __rtx_env_again; - set -e __rtx_env_again; - /nix/store/rtx hook-env --status -s fish | source; - echo; - end; - - functions --erase __rtx_cd_hook; -end; -function fish_command_not_found - if /nix/store/rtx hook-not-found -s fish $argv[1] - /nix/store/rtx hook-env --status -s fish | source - else - __fish_default_command_not_found_handler $argv - end -end - diff --git a/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap b/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap deleted file mode 100644 index 600e477af..000000000 --- a/src/shell/snapshots/rtx__shell__zsh__tests__deactivate.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: src/shell/zsh.rs -expression: replace_path(&deactivate) ---- -precmd_functions=( ${precmd_functions:#_rtx_hook} ) -chpwd_functions=( ${chpwd_functions:#_rtx_hook} ) -unset -f _rtx_hook -unset -f rtx -unset RTX_SHELL - diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index d09a5f356..6fc4b0868 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -40,7 +40,7 @@ impl Shell for Xonsh { let exe = exe.display(); let mut out = String::new(); - // todo: xonsh doesn't update the environment that rtx relies on with $PATH.add even with $UPDATE_OS_ENVIRON (github.com/xonsh/xonsh/issues/3207) + // todo: xonsh doesn't update the environment that mise relies on with $PATH.add even with $UPDATE_OS_ENVIRON (github.com/xonsh/xonsh/issues/3207) // with envx.swap(UPDATE_OS_ENVIRON=True): # ↠use when ↑ fixed before PATH.add; remove environ // meanwhile, save variables twice: in shell env + in os env // use xonsh API instead of $.xsh to allow use inside of .py configs, which start faster due to being compiled to .pyc @@ -129,14 +129,14 @@ mod tests { #[test] fn test_hook_init() { let xonsh = Xonsh::default(); - let exe = Path::new("/some/dir/rtx"); + let exe = Path::new("/some/dir/mise"); insta::assert_snapshot!(xonsh.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let xonsh = Xonsh::default(); - let exe = Path::new("/nix/store/rtx"); + let exe = Path::new("/nix/store/mise"); insta::assert_snapshot!(xonsh.activate(exe, " --status".into())); } diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 311f19fb2..8968540d6 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -19,10 +19,10 @@ impl Shell for Zsh { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" - export RTX_SHELL=zsh - export __RTX_ORIG_PATH="$PATH" + export MISE_SHELL=zsh + export __MISE_ORIG_PATH="$PATH" - rtx() {{ + mise() {{ local command command="${{1:-}}" if [ "$#" = 0 ]; then @@ -43,28 +43,28 @@ impl Shell for Zsh { command {exe} "$command" "$@" }} - _rtx_hook() {{ + _mise_hook() {{ eval "$({exe} hook-env{flags} -s zsh)"; }} typeset -ag precmd_functions; - if [[ -z "${{precmd_functions[(r)_rtx_hook]+1}}" ]]; then - precmd_functions=( _rtx_hook ${{precmd_functions[@]}} ) + if [[ -z "${{precmd_functions[(r)_mise_hook]+1}}" ]]; then + precmd_functions=( _mise_hook ${{precmd_functions[@]}} ) fi typeset -ag chpwd_functions; - if [[ -z "${{chpwd_functions[(r)_rtx_hook]+1}}" ]]; then - chpwd_functions=( _rtx_hook ${{chpwd_functions[@]}} ) + if [[ -z "${{chpwd_functions[(r)_mise_hook]+1}}" ]]; then + chpwd_functions=( _mise_hook ${{chpwd_functions[@]}} ) fi "#}); if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" - if [ -z "${{_rtx_cmd_not_found:-}}" ]; then - _rtx_cmd_not_found=1 + if [ -z "${{_mise_cmd_not_found:-}}" ]; then + _mise_cmd_not_found=1 test -n "$(declare -f command_not_found_handler)" && eval "${{_/command_not_found_handler/_command_not_found_handler}}" function command_not_found_handler() {{ if {exe} hook-not-found -s zsh "$1"; then - _rtx_hook + _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handler)" ]; then _command_not_found_handler "$@" @@ -82,11 +82,11 @@ impl Shell for Zsh { fn deactivate(&self) -> String { formatdoc! {r#" - precmd_functions=( ${{precmd_functions:#_rtx_hook}} ) - chpwd_functions=( ${{chpwd_functions:#_rtx_hook}} ) - unset -f _rtx_hook - unset -f rtx - unset RTX_SHELL + precmd_functions=( ${{precmd_functions:#_mise_hook}} ) + chpwd_functions=( ${{chpwd_functions:#_mise_hook}} ) + unset -f _mise_hook + unset -f mise + unset MISE_SHELL "#} } @@ -109,14 +109,14 @@ mod tests { #[test] fn test_hook_init() { let zsh = Zsh::default(); - let exe = Path::new("/some/dir/rtx"); + let exe = Path::new("/some/dir/mise"); assert_snapshot!(zsh.activate(exe, " --status".into())); } #[test] fn test_hook_init_nix() { let zsh = Zsh::default(); - let exe = Path::new("/nix/store/rtx"); + let exe = Path::new("/nix/store/mise"); assert_snapshot!(zsh.activate(exe, " --status".into())); } diff --git a/src/shims.rs b/src/shims.rs index 535ebf1c2..e927ae3e7 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -21,17 +21,17 @@ use crate::plugins::Plugin; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; -// executes as if it was a shim if the command is not "rtx", e.g.: "node" +// executes as if it was a shim if the command is not "mise", e.g.: "node" pub fn handle_shim() -> Result<()> { // TODO: instead, check if bin is in shims dir - let bin_name = *env::RTX_BIN_NAME; - if bin_name == "rtx" || !dirs::SHIMS.join(bin_name).exists() || cfg!(test) { + let bin_name = *env::MISE_BIN_NAME; + if bin_name == "mise" || !dirs::SHIMS.join(bin_name).exists() || cfg!(test) { return Ok(()); } logger::init(&Settings::get()); let args = env::ARGS.read().unwrap(); let mut args: Vec = args.iter().map(OsString::from).collect(); - args[0] = which_shim(&env::RTX_BIN_NAME)?.into(); + args[0] = which_shim(&env::MISE_BIN_NAME)?.into(); let exec = Exec { tool: vec![], c: None, @@ -83,7 +83,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { }) .lock(); - let rtx_bin = file::which("rtx").unwrap_or(env::RTX_BIN.clone()); + let mise_bin = file::which("mise").unwrap_or(env::MISE_BIN.clone()); create_dir_all(&*dirs::SHIMS)?; @@ -93,7 +93,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { dirs::SHIMS .join(bin) .read_link() - .is_ok_and(|p| p == rtx_bin) + .is_ok_and(|p| p == mise_bin) }) .collect::>(); @@ -113,10 +113,10 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { for shim in shims_to_add { let symlink_path = dirs::SHIMS.join(shim); - file::make_symlink(&rtx_bin, &symlink_path).wrap_err_with(|| { + file::make_symlink(&mise_bin, &symlink_path).wrap_err_with(|| { eyre!( "Failed to create symlink from {} to {}", - display_path(&rtx_bin), + display_path(&mise_bin), display_path(&symlink_path) ) })?; @@ -182,7 +182,7 @@ fn make_shim(target: &Path, shim: &Path) -> Result<()> { #!/bin/sh export ASDF_DATA_DIR={data_dir} export PATH="{fake_asdf_dir}:$PATH" - rtx x -- {target} "$@" + mise x -- {target} "$@" "#, data_dir = dirs::DATA.display(), fake_asdf_dir = fake_asdf::setup()?.display(), @@ -211,7 +211,7 @@ fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Res let mut msg = format!("No version is set for shim: {}\n", bin_name); msg.push_str("Set a global default version with one of the following:\n"); for tv in tvs { - msg.push_str(&format!("rtx use -g {}@{}\n", tv.plugin_name, tv.version)); + msg.push_str(&format!("mise use -g {}@{}\n", tv.plugin_name, tv.version)); } Err(eyre!(msg.trim().to_string())) } else { @@ -223,7 +223,7 @@ fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Res for t in missing_tools.drain(..) { msg.push_str(&format!("Missing tool version: {}\n", t)); } - msg.push_str("Install all missing tools with: rtx install\n"); + msg.push_str("Install all missing tools with: mise install\n"); Err(eyre!(msg.trim().to_string())) } } diff --git a/src/snapshots/rtx__direnv__tests__add_path_to_old_and_new-2.snap b/src/snapshots/mise__direnv__tests__add_path_to_old_and_new-2.snap similarity index 100% rename from src/snapshots/rtx__direnv__tests__add_path_to_old_and_new-2.snap rename to src/snapshots/mise__direnv__tests__add_path_to_old_and_new-2.snap diff --git a/src/snapshots/rtx__direnv__tests__add_path_to_old_and_new.snap b/src/snapshots/mise__direnv__tests__add_path_to_old_and_new.snap similarity index 100% rename from src/snapshots/rtx__direnv__tests__add_path_to_old_and_new.snap rename to src/snapshots/mise__direnv__tests__add_path_to_old_and_new.snap diff --git a/src/snapshots/rtx__direnv__tests__dump-2.snap b/src/snapshots/mise__direnv__tests__dump-2.snap similarity index 100% rename from src/snapshots/rtx__direnv__tests__dump-2.snap rename to src/snapshots/mise__direnv__tests__dump-2.snap diff --git a/src/snapshots/rtx__direnv__tests__dump.snap b/src/snapshots/mise__direnv__tests__dump.snap similarity index 100% rename from src/snapshots/rtx__direnv__tests__dump.snap rename to src/snapshots/mise__direnv__tests__dump.snap diff --git a/src/snapshots/rtx__direnv__tests__null_path-2.snap b/src/snapshots/mise__direnv__tests__null_path-2.snap similarity index 100% rename from src/snapshots/rtx__direnv__tests__null_path-2.snap rename to src/snapshots/mise__direnv__tests__null_path-2.snap diff --git a/src/snapshots/rtx__direnv__tests__null_path.snap b/src/snapshots/mise__direnv__tests__null_path.snap similarity index 100% rename from src/snapshots/rtx__direnv__tests__null_path.snap rename to src/snapshots/mise__direnv__tests__null_path.snap diff --git a/src/snapshots/rtx__direnv__tests__parse.snap b/src/snapshots/mise__direnv__tests__parse.snap similarity index 100% rename from src/snapshots/rtx__direnv__tests__parse.snap rename to src/snapshots/mise__direnv__tests__parse.snap diff --git a/src/snapshots/rtx__env_diff__tests__diff.snap b/src/snapshots/mise__env_diff__tests__diff.snap similarity index 100% rename from src/snapshots/rtx__env_diff__tests__diff.snap rename to src/snapshots/mise__env_diff__tests__diff.snap diff --git a/src/snapshots/rtx__env_diff__tests__from_bash_script.snap b/src/snapshots/mise__env_diff__tests__from_bash_script.snap similarity index 100% rename from src/snapshots/rtx__env_diff__tests__from_bash_script.snap rename to src/snapshots/mise__env_diff__tests__from_bash_script.snap diff --git a/src/snapshots/rtx__env_diff__tests__serialize.snap b/src/snapshots/mise__env_diff__tests__serialize.snap similarity index 100% rename from src/snapshots/rtx__env_diff__tests__serialize.snap rename to src/snapshots/mise__env_diff__tests__serialize.snap diff --git a/src/snapshots/rtx__hash__tests__hash_sha256.snap b/src/snapshots/mise__hash__tests__hash_sha256.snap similarity index 100% rename from src/snapshots/rtx__hash__tests__hash_sha256.snap rename to src/snapshots/mise__hash__tests__hash_sha256.snap diff --git a/src/snapshots/rtx__runtime_symlinks__tests__list_symlinks.snap b/src/snapshots/mise__runtime_symlinks__tests__list_symlinks.snap similarity index 100% rename from src/snapshots/rtx__runtime_symlinks__tests__list_symlinks.snap rename to src/snapshots/mise__runtime_symlinks__tests__list_symlinks.snap diff --git a/src/task.rs b/src/task.rs index 63b4a82ab..03f965ced 100644 --- a/src/task.rs +++ b/src/task.rs @@ -52,7 +52,7 @@ impl Task { pub fn from_path(path: PathBuf) -> Result { let info = file::read_to_string(&path)? .lines() - .filter_map(|line| regex!(r"^# rtx ([a-z]+=.+)$").captures(line)) + .filter_map(|line| regex!(r"^# mise ([a-z]+=.+)$").captures(line)) .map(|captures| captures.extract()) .flat_map(|(_, [toml])| { toml.parse::() @@ -146,8 +146,8 @@ impl Task { // .parent() // .expect("task source has no parent") // { - // dir if dir.ends_with(".rtx/tasks") => dir.parent().unwrap(), - // dir if dir.ends_with(".config/rtx/tasks") => dir.parent().unwrap().parent().unwrap(), + // dir if dir.ends_with(".mise/tasks") => dir.parent().unwrap(), + // dir if dir.ends_with(".config/mise/tasks") => dir.parent().unwrap().parent().unwrap(), // dir => dir, // } // } diff --git a/src/test.rs b/src/test.rs index abb088fa8..215e37093 100644 --- a/src/test.rs +++ b/src/test.rs @@ -11,25 +11,25 @@ use crate::{dirs, env, file}; fn init() { console::set_colors_enabled(false); console::set_colors_enabled_stderr(false); - if env::var("__RTX_DIFF").is_ok() { + if env::var("__MISE_DIFF").is_ok() { // TODO: fix this - panic!("cannot run tests when rtx is activated"); + panic!("cannot run tests when mise is activated"); } env::set_var( "HOME", PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test"), ); set_current_dir(env::HOME.join("cwd")).unwrap(); - env::remove_var("RTX_TRUSTED_CONFIG_PATHS"); + env::remove_var("MISE_TRUSTED_CONFIG_PATHS"); env::set_var("NO_COLOR", "1"); - env::set_var("RTX_YES", "1"); - env::set_var("RTX_USE_TOML", "0"); - env::set_var("RTX_DATA_DIR", env::HOME.join("data")); - env::set_var("RTX_STATE_DIR", env::HOME.join("state")); - env::set_var("RTX_CONFIG_DIR", env::HOME.join("config")); - env::set_var("RTX_CACHE_DIR", env::HOME.join("data/cache")); - env::set_var("RTX_DEFAULT_TOOL_VERSIONS_FILENAME", ".test-tool-versions"); - env::set_var("RTX_DEFAULT_CONFIG_FILENAME", ".test.rtx.toml"); + env::set_var("MISE_YES", "1"); + env::set_var("MISE_USE_TOML", "0"); + env::set_var("MISE_DATA_DIR", env::HOME.join("data")); + env::set_var("MISE_STATE_DIR", env::HOME.join("state")); + env::set_var("MISE_CONFIG_DIR", env::HOME.join("config")); + env::set_var("MISE_CACHE_DIR", env::HOME.join("data/cache")); + env::set_var("MISE_DEFAULT_TOOL_VERSIONS_FILENAME", ".test-tool-versions"); + env::set_var("MISE_DEFAULT_CONFIG_FILENAME", ".test.mise.toml"); //env::set_var("TERM", "dumb"); reset_config(); } @@ -87,7 +87,7 @@ pub fn replace_path(input: &str) -> String { input .replace(&path, "$PATH") .replace(&home, "~") - .replace(&*env::RTX_BIN.to_string_lossy(), "rtx") + .replace(&*env::MISE_BIN.to_string_lossy(), "mise") } pub fn cli_run(args: &Vec) -> eyre::Result<(String, String)> { @@ -123,13 +123,13 @@ macro_rules! with_settings { #[macro_export] macro_rules! assert_cli_snapshot { ($($args:expr),+, @$snapshot:literal) => { - let args = &vec!["rtx".into(), $($args.into()),+]; + let args = &vec!["mise".into(), $($args.into()),+]; let (stdout, stderr) = $crate::test::cli_run(args).unwrap(); let output = [stdout, stderr].join("\n").trim().to_string(); insta::assert_snapshot!(output, @$snapshot); }; ($($args:expr),+) => { - let args = &vec!["rtx".into(), $($args.into()),+]; + let args = &vec!["mise".into(), $($args.into()),+]; let (stdout, stderr) = $crate::test::cli_run(args).unwrap(); let output = [stdout, stderr].join("\n").trim().to_string(); insta::assert_snapshot!(output); @@ -139,7 +139,7 @@ macro_rules! assert_cli_snapshot { #[macro_export] macro_rules! assert_cli { ($($args:expr),+) => {{ - let args = &vec!["rtx".into(), $($args.into()),+]; + let args = &vec!["mise".into(), $($args.into()),+]; $crate::test::cli_run(args).unwrap(); let output = $crate::output::tests::STDOUT.lock().unwrap().join("\n"); console::strip_ansi_codes(&output).trim().to_string() @@ -149,7 +149,7 @@ macro_rules! assert_cli { #[macro_export] macro_rules! assert_cli_err { ($($args:expr),+) => {{ - let args = &vec!["rtx".into(), $($args.into()),+]; + let args = &vec!["mise".into(), $($args.into()),+]; $crate::test::cli_run(args).unwrap_err() }}; } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 8f1115fc0..da02c6daf 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -67,10 +67,13 @@ impl ToolsetBuilder { return; } for (k, v) in env { - if k.starts_with("RTX_") && k.ends_with("_VERSION") && k != "RTX_VERSION" { - let plugin_name = k[4..k.len() - 8].to_lowercase(); + if k.starts_with("MISE_") && k.ends_with("_VERSION") && k != "MISE_VERSION" { + let plugin_name = k + .trim_start_matches("MISE_") + .trim_end_matches("_VERSION") + .to_lowercase(); if plugin_name == "install" { - // ignore RTX_INSTALL_VERSION + // ignore MISE_INSTALL_VERSION continue; } let source = ToolSource::Environment(k, v.clone()); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index d9f823915..e521967b7 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -308,13 +308,16 @@ impl Toolset { .collect::>(); let add_paths = entries .iter() + .filter(|(k, _)| k == "MISE_ADD_PATH") .filter(|(k, _)| k == "RTX_ADD_PATH") .map(|(_, v)| v) .join(":"); let mut entries: BTreeMap = entries .into_iter() .filter(|(k, _)| k != "RTX_ADD_PATH") + .filter(|(k, _)| k != "MISE_ADD_PATH") .filter(|(k, _)| !k.starts_with("RTX_TOOL_OPTS__")) + .filter(|(k, _)| !k.starts_with("MISE_TOOL_OPTS__")) .rev() .collect(); if !add_paths.is_empty() { diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index ef8dd85c4..fad3cdc19 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -10,7 +10,7 @@ use crate::file::display_path; #[derive(Debug, Clone, Serialize)] pub enum ToolSource { ToolVersions(PathBuf), - RtxToml(PathBuf), + MiseToml(PathBuf), LegacyVersionFile(PathBuf), Argument, Environment(String, String), @@ -20,7 +20,7 @@ impl Display for ToolSource { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { ToolSource::ToolVersions(path) => write!(f, "{}", display_path(path)), - ToolSource::RtxToml(path) => write!(f, "{}", display_path(path)), + ToolSource::MiseToml(path) => write!(f, "{}", display_path(path)), ToolSource::LegacyVersionFile(path) => write!(f, "{}", display_path(path)), ToolSource::Argument => write!(f, "--runtime"), ToolSource::Environment(k, v) => write!(f, "{k}={v}"), @@ -35,8 +35,8 @@ impl ToolSource { "type".to_string() => ".tool-versions".to_string(), "path".to_string() => path.to_string_lossy().to_string(), }, - ToolSource::RtxToml(path) => indexmap! { - "type".to_string() => ".rtx.toml".to_string(), + ToolSource::MiseToml(path) => indexmap! { + "type".to_string() => ".mise.toml".to_string(), "path".to_string() => path.to_string_lossy().to_string(), }, ToolSource::LegacyVersionFile(path) => indexmap! { @@ -68,8 +68,8 @@ mod tests { let ts = ToolSource::ToolVersions(path); assert_str_eq!(ts.to_string(), "/home/user/.test-tool-versions"); - let ts = ToolSource::RtxToml(PathBuf::from("/home/user/.rtx.toml")); - assert_str_eq!(ts.to_string(), "/home/user/.rtx.toml"); + let ts = ToolSource::MiseToml(PathBuf::from("/home/user/.mise.toml")); + assert_str_eq!(ts.to_string(), "/home/user/.mise.toml"); let ts = ToolSource::LegacyVersionFile(PathBuf::from("/home/user/.node-version")); assert_str_eq!(ts.to_string(), "/home/user/.node-version"); @@ -77,8 +77,8 @@ mod tests { let ts = ToolSource::Argument; assert_str_eq!(ts.to_string(), "--runtime"); - let ts = ToolSource::Environment("RTX_NODE_VERSION".to_string(), "18".to_string()); - assert_str_eq!(ts.to_string(), "RTX_NODE_VERSION=18"); + let ts = ToolSource::Environment("MISE_NODE_VERSION".to_string(), "18".to_string()); + assert_str_eq!(ts.to_string(), "MISE_NODE_VERSION=18"); } #[test] @@ -92,12 +92,12 @@ mod tests { } ); - let ts = ToolSource::RtxToml(PathBuf::from("/home/user/.rtx.toml")); + let ts = ToolSource::MiseToml(PathBuf::from("/home/user/.mise.toml")); assert_eq!( ts.as_json(), indexmap! { - "type".to_string() => ".rtx.toml".to_string(), - "path".to_string() => "/home/user/.rtx.toml".to_string(), + "type".to_string() => ".mise.toml".to_string(), + "path".to_string() => "/home/user/.mise.toml".to_string(), } ); @@ -118,12 +118,12 @@ mod tests { } ); - let ts = ToolSource::Environment("RTX_NODE_VERSION".to_string(), "18".to_string()); + let ts = ToolSource::Environment("MISE_NODE_VERSION".to_string(), "18".to_string()); assert_eq!( ts.as_json(), indexmap! { "type".to_string() => "environment".to_string(), - "key".to_string() => "RTX_NODE_VERSION".to_string(), + "key".to_string() => "MISE_NODE_VERSION".to_string(), "value".to_string() => "18".to_string(), } ); diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index beb2a2dfa..2faa21895 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -54,7 +54,7 @@ mod tests { #[test] fn test_tool_version_list_failure() { - env::set_var("RTX_FAILURE", "1"); + env::set_var("MISE_FAILURE", "1"); file::remove_all(dirs::CACHE.join("dummy")).unwrap(); let config = Config::default(); let plugin_name = "dummy".to_string(); @@ -66,6 +66,6 @@ mod tests { )); tvl.resolve(&config, true); assert_eq!(tvl.versions.len(), 0); - env::remove_var("RTX_FAILURE"); + env::remove_var("MISE_FAILURE"); } } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 26f015c34..fa38ef255 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -44,11 +44,11 @@ fn pad_prefix(w: usize, s: &str) -> String { console::pad_str(s, w, console::Alignment::Left, None).to_string() } fn normal_prefix(pad: usize, prefix: &str) -> String { - let prefix = format!("{} {prefix}", style::edim("rtx")); + let prefix = format!("{} {prefix}", style::edim("mise")); pad_prefix(pad, &prefix) } fn success_prefix(pad: usize, prefix: &str) -> String { - let prefix = format!("{} {prefix}", style::egreen("rtx")); + let prefix = format!("{} {prefix}", style::egreen("mise")); pad_prefix(pad, &prefix) } diff --git a/test/cwd/.mise/tasks/filetask b/test/cwd/.mise/tasks/filetask new file mode 100755 index 000000000..cc3114d0a --- /dev/null +++ b/test/cwd/.mise/tasks/filetask @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# mise description="This is a test build script" +# mise depends=["lint", "test"] +# mise sources=[".test-tool-versions"] +# mise outputs=["$MISE_PROJECT_ROOT/test/test-build-output.txt"] +# mise env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} + +set -euxo pipefail +cd "$MISE_PROJECT_ROOT" || exit 1 +echo "running test-build script" +echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test-build-output.txt diff --git a/test/cwd/.rtx/tasks/filetask b/test/cwd/.rtx/tasks/filetask deleted file mode 100755 index f466b183f..000000000 --- a/test/cwd/.rtx/tasks/filetask +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -# rtx description="This is a test build script" -# rtx depends=["lint", "test"] -# rtx sources=[".test-tool-versions"] -# rtx outputs=["$RTX_PROJECT_ROOT/test/test-build-output.txt"] -# rtx env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} - -set -euxo pipefail -cd "$RTX_PROJECT_ROOT" || exit 1 -echo "running test-build script" -echo "TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR" > test-build-output.txt diff --git a/test/cwd/tiny-legacy/.rtx-tiny-version b/test/cwd/tiny-legacy/.mise-tiny-version similarity index 100% rename from test/cwd/tiny-legacy/.rtx-tiny-version rename to test/cwd/tiny-legacy/.mise-tiny-version diff --git a/test/data/plugins/dummy/bin/latest-stable b/test/data/plugins/dummy/bin/latest-stable index dc341a517..2cbbbdee6 100755 --- a/test/data/plugins/dummy/bin/latest-stable +++ b/test/data/plugins/dummy/bin/latest-stable @@ -9,7 +9,7 @@ get_latest_stable() { get_latest_stable "$1" -if [ "$RTX_FAILURE" = "1" ]; then - echo "error: RTX_FAILURE set" >&2 +if [ "$MISE_FAILURE" = "1" ]; then + echo "error: MISE_FAILURE set" >&2 exit 1 fi diff --git a/test/fixtures/.rtx.toml b/test/fixtures/.mise.toml similarity index 100% rename from test/fixtures/.rtx.toml rename to test/fixtures/.mise.toml diff --git a/test/fixtures/rtx.plugin.toml b/test/fixtures/mise.plugin.toml similarity index 50% rename from test/fixtures/rtx.plugin.toml rename to test/fixtures/mise.plugin.toml index 70fcfd766..4cef5301a 100644 --- a/test/fixtures/rtx.plugin.toml +++ b/test/fixtures/mise.plugin.toml @@ -1,4 +1,4 @@ -#:schema ../../schema/rtx.plugin.json +#:schema ../../schema/mise.plugin.json [exec-env] cache-key = ["{{'1234'}}"] From 0d0d930a6937be19f4158be09755f17cc44ae6cb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:31:10 -0600 Subject: [PATCH 1503/1891] chore: Release mise version 2024.1.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- src/plugins/external_plugin.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7263db869..36e59e8b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.0.0" +version = "2024.1.0" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 694db0b26..8486f9dd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.0.0" +version = "2024.1.0" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 94a142458..dbe028f13 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Install mise on macOS (other methods [here](https://mise.jdx.dev/getting-started ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/share/mise/bin/mise --version -mise 2024.0.0 +mise 2024.1.0 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index d560790d7..cd203df00 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.0.0"; + version = "2024.1.0"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index b764938ad..63f64ccb0 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.0.0 +Version: 2024.1.0 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ffea0a8a8..8dffa98a4 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -380,7 +380,7 @@ impl ExternalPlugin { fn build_script_man(name: &str, plugin_path: &Path) -> ScriptManager { let plugin_path_s = plugin_path.to_string_lossy().to_string(); ScriptManager::new(plugin_path.to_path_buf()) - .with_env("RTX_PLUGIN_PATH", &plugin_path_s) + .with_env("RTX_PLUGIN_PATH", plugin_path_s) .with_env("RTX_PLUGIN_NAME", name.to_string()) .with_env("RTX_SHIMS_DIR", &*dirs::SHIMS) .with_env("MISE_PLUGIN_NAME", name.to_string()) From 9b7975e5cd43121d22436893acdc7dbfe36ee960 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:34:29 -0600 Subject: [PATCH 1504/1891] rtx -> mise --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dbe028f13..0f656d63d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# [mise-en-place](https://mise.jdx.dev) +
From 7d3a2ca707a7779041df559bba23bd552ef01775 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:34:54 -0600 Subject: [PATCH 1505/1891] readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f656d63d..9ce9326ea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ -# [mise-en-place](https://mise.jdx.dev) -
+

[mise-en-place](https://mise.jdx.dev)

From 884147b16e94880e915a53291af21647546d6a04 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:35:29 -0600 Subject: [PATCH 1506/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ce9326ea..f9449d89d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
-

[mise-en-place](https://mise.jdx.dev)

+

mise-en-place

From b5e9d3cc3a2500c932593d7931647fbc3d972708 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:58:35 -0600 Subject: [PATCH 1507/1891] fixed email addresses --- scripts/release-aur-bin.sh | 2 +- scripts/release-aur.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index fdc9f27ed..fdcebdd6c 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -13,7 +13,7 @@ fi git -C aur-bin pull cat >aur-bin/PKGBUILD < +# Maintainer: Jeff Dickey pkgname=mise-bin pkgver=${MISE_VERSION#v*} diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index e2a3789e1..67effabad 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -11,7 +11,7 @@ fi git -C aur pull cat >aur/PKGBUILD < +# Maintainer: Jeff Dickey pkgname=mise pkgver=${MISE_VERSION#v*} From c4011da5261f254f118c3cd5740bbf8d50ac8733 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 17:09:45 -0600 Subject: [PATCH 1508/1891] fail on r2 error --- scripts/publish-r2.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/publish-r2.sh b/scripts/publish-r2.sh index d10d9edf2..fefa21985 100755 --- a/scripts/publish-r2.sh +++ b/scripts/publish-r2.sh @@ -8,4 +8,4 @@ export AWS_ACCESS_KEY_ID=$CLOUDFLARE_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$CLOUDFLARE_SECRET_ACCESS_KEY export AWS_S3_BUCKET=mise -./mise/scripts/publish-s3.sh || true +./mise/scripts/publish-s3.sh From 91e9befabec3f87dec4f2c6513f52b29ca53f5b8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:26:39 -0600 Subject: [PATCH 1509/1891] update CONTRIBUTING.md --- CONTRIBUTING.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dffb221e3..0479c5a40 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,15 +106,14 @@ git commit ## Testing packaging -I test these with finch, but docker should work the same. This is only necessary to test -if actually changing the packaging setup. +This is only necessary to test if actually changing the packaging setup. ### Ubuntu (apt) This is for arm64, but you can change the arch to amd64 if you want. ```shell -finch run -ti --rm ubuntu +docker run -ti --rm ubuntu apt update -y apt install -y gpg sudo wget curl sudo install -dm 755 /etc/apt/keyrings @@ -128,7 +127,7 @@ mise -V ### Amazon Linux 2 (yum) ```shell -finch run -ti --rm amazonlinux +docker run -ti --rm amazonlinux yum install -y yum-utils yum-config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo yum install -y mise @@ -138,7 +137,7 @@ mise -v ### Fedora (dnf) ```shell -finch run -ti --rm fedora +docker run -ti --rm fedora dnf install -y dnf-plugins-core dnf config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo dnf install -y mise From fbcc3ee610f38633e2ce583d9c43fc9df8c4f368 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:42:03 -0600 Subject: [PATCH 1510/1891] 2024 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 9b2a63c7d..f5997f2a5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Jeff Dickey +Copyright (c) 2024 Jeff Dickey Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From c4bb224acb197e9f67eda56a4be3c7f3c5bdcee6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 2 Jan 2024 20:20:28 -0600 Subject: [PATCH 1511/1891] fixed crate badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f9449d89d..3204d3c77 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@
-Crates.io +Crates.io GitHub GitHub Workflow Status From ba5f6108b1b91952295e4871f63c559ff01c7c64 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:07:06 -0600 Subject: [PATCH 1512/1891] docs: tweak cli reference --- docs/cli-reference.md | 106 ++++++++++++++++++++--------------------- src/cli/render_help.rs | 6 +-- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 403b3b761..e0b5eb83d 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -1,8 +1,8 @@ -## Commands +# Commands -### `mise activate [OPTIONS] [SHELL_TYPE]` +## `mise activate [OPTIONS] [SHELL_TYPE]` ```text Initializes mise in the current shell session @@ -46,7 +46,7 @@ Examples: $ execx($(mise activate xonsh)) ``` -### `mise alias get ` +## `mise alias get ` ```text Show an alias for a plugin @@ -67,7 +67,7 @@ Examples: 20.0.0 ``` -### `mise alias ls [OPTIONS] [PLUGIN]` +## `mise alias ls [OPTIONS] [PLUGIN]` **Aliases:** `list` @@ -96,7 +96,7 @@ Examples: node lts-hydrogen 20.0.0 ``` -### `mise alias set ` +## `mise alias set ` **Aliases:** `add, create` @@ -121,7 +121,7 @@ Examples: $ mise alias set node lts-hydrogen 18.0.0 ``` -### `mise alias unset ` +## `mise alias unset ` **Aliases:** `del, delete, remove, rm` @@ -143,7 +143,7 @@ Examples: $ mise alias unset node lts-hydrogen ``` -### `mise bin-paths` +## `mise bin-paths` ```text List all the active runtime bin paths @@ -151,7 +151,7 @@ List all the active runtime bin paths Usage: bin-paths ``` -### `mise cache clear [PLUGIN]...` +## `mise cache clear [PLUGIN]...` **Aliases:** `c` @@ -165,7 +165,7 @@ Arguments: Plugin(s) to clear cache for e.g.: node, python ``` -### `mise completion [SHELL]` +## `mise completion [SHELL]` ```text Generate shell completions @@ -184,7 +184,7 @@ Examples: $ mise completion fish > ~/.config/fish/completions/mise.fish ``` -### `mise config ls [OPTIONS]` +## `mise config ls [OPTIONS]` ```text [experimental] List config files currently in use @@ -199,7 +199,7 @@ Examples: $ mise config ls ``` -### `mise config generate [OPTIONS]` +## `mise config generate [OPTIONS]` **Aliases:** `g` @@ -217,7 +217,7 @@ Examples: $ mise cf generate --output=.mise.toml ``` -### `mise current [PLUGIN]` +## `mise current [PLUGIN]` ```text Shows current active and installed runtime versions @@ -247,7 +247,7 @@ Examples: 3.11.0 3.10.0 ``` -### `mise deactivate` +## `mise deactivate` ```text Disable mise for current shell session @@ -263,7 +263,7 @@ Examples: $ execx($(mise deactivate xonsh)) ``` -### `mise direnv activate` +## `mise direnv activate` ```text Output direnv function to use mise inside direnv @@ -282,7 +282,7 @@ Examples: $ direnv allow ``` -### `mise doctor` +## `mise doctor` ```text Check mise installation for possible problems. @@ -294,7 +294,7 @@ Examples: [WARN] plugin node is not installed ``` -### `mise env [OPTIONS] [TOOL@VERSION]...` +## `mise env [OPTIONS] [TOOL@VERSION]...` **Aliases:** `e` @@ -326,7 +326,7 @@ Examples: $ execx($(mise env -s xonsh)) ``` -### `mise env-vars [OPTIONS] [ENV_VARS]...` +## `mise env-vars [OPTIONS] [ENV_VARS]...` **Aliases:** `ev` @@ -355,7 +355,7 @@ Options: Can be used multiple times. ``` -### `mise exec [OPTIONS] [TOOL@VERSION]... [-- ...]` +## `mise exec [OPTIONS] [TOOL@VERSION]... [-- ...]` **Aliases:** `x` @@ -403,7 +403,7 @@ Examples: $ mise x -C /path/to/project node@20 -- node ./app.js ``` -### `mise implode [OPTIONS]` +## `mise implode [OPTIONS]` ```text Removes mise CLI and all related data @@ -420,7 +420,7 @@ Options: List directories that would be removed without actually removing them ``` -### `mise install [OPTIONS] [TOOL@VERSION]...` +## `mise install [OPTIONS] [TOOL@VERSION]...` **Aliases:** `i` @@ -463,7 +463,7 @@ Examples: $ mise install # installs everything specified in .tool-versions or .mise.toml ``` -### `mise latest [OPTIONS] ` +## `mise latest [OPTIONS] ` ```text Gets the latest available version for a plugin @@ -486,7 +486,7 @@ Examples: 20.0.0 ``` -### `mise link [OPTIONS] ` +## `mise link [OPTIONS] ` **Aliases:** `ln` @@ -521,7 +521,7 @@ Examples: $ mise use node@brew ``` -### `mise ls [OPTIONS] [PLUGIN]...` +## `mise ls [OPTIONS] [PLUGIN]...` **Aliases:** `list` @@ -582,7 +582,7 @@ Examples: } ``` -### `mise ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` +## `mise ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` ```text List runtime versions available for install @@ -618,7 +618,7 @@ Examples: 20.1.0 ``` -### `mise outdated [TOOL@VERSION]...` +## `mise outdated [TOOL@VERSION]...` ```text Shows outdated tool versions @@ -642,7 +642,7 @@ Examples: node 20 20.0.0 20.1.0 ``` -### `mise plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` +## `mise plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` **Aliases:** `a, add, i` @@ -692,7 +692,7 @@ Examples: $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 ``` -### `mise plugins link [OPTIONS] [PATH]` +## `mise plugins link [OPTIONS] [PATH]` **Aliases:** `ln` @@ -724,7 +724,7 @@ Examples: $ mise plugins link ./mise-node ``` -### `mise plugins ls [OPTIONS]` +## `mise plugins ls [OPTIONS]` **Aliases:** `list` @@ -760,7 +760,7 @@ Examples: ruby https://github.com/asdf-vm/asdf-ruby.git ``` -### `mise plugins ls-remote [OPTIONS]` +## `mise plugins ls-remote [OPTIONS]` **Aliases:** `list-all, list-remote` @@ -783,7 +783,7 @@ Options: Only show the name of each plugin by default it will show a "*" next to installed plugins ``` -### `mise plugins uninstall [OPTIONS] [PLUGIN]...` +## `mise plugins uninstall [OPTIONS] [PLUGIN]...` **Aliases:** `remove, rm` @@ -807,7 +807,7 @@ Examples: $ mise uninstall node ``` -### `mise plugins update [OPTIONS] [PLUGIN]...` +## `mise plugins update [OPTIONS] [PLUGIN]...` **Aliases:** `upgrade` @@ -833,7 +833,7 @@ Examples: $ mise plugins update node#beta # specify a ref ``` -### `mise prune [OPTIONS] [PLUGIN]...` +## `mise prune [OPTIONS] [PLUGIN]...` ```text Delete unused versions of tools @@ -859,7 +859,7 @@ Examples: rm -rf ~/.local/share/mise/versions/node/20.0.1 ``` -### `mise reshim` +## `mise reshim` ```text rebuilds the shim farm @@ -886,7 +886,7 @@ Examples: v20.0.0 ``` -### `mise run [OPTIONS] [TASK] [ARGS]...` +## `mise run [OPTIONS] [TASK] [ARGS]...` **Aliases:** `r` @@ -982,7 +982,7 @@ Examples: Execute multiple tasks each with their own arguments. ``` -### `mise self-update [OPTIONS] [VERSION]` +## `mise self-update [OPTIONS] [VERSION]` ```text Updates mise itself @@ -1007,7 +1007,7 @@ Options: Skip confirmation prompt ``` -### `mise settings get ` +## `mise settings get ` ```text Show a current setting @@ -1028,7 +1028,7 @@ Examples: true ``` -### `mise settings ls` +## `mise settings ls` **Aliases:** `list` @@ -1047,7 +1047,7 @@ Examples: legacy_version_file = false ``` -### `mise settings set ` +## `mise settings set ` **Aliases:** `add, create` @@ -1069,7 +1069,7 @@ Examples: $ mise settings set legacy_version_file true ``` -### `mise settings unset ` +## `mise settings unset ` **Aliases:** `del, delete, remove, rm` @@ -1088,7 +1088,7 @@ Examples: $ mise settings unset legacy_version_file ``` -### `mise shell [OPTIONS] [TOOL@VERSION]...` +## `mise shell [OPTIONS] [TOOL@VERSION]...` **Aliases:** `sh` @@ -1122,7 +1122,7 @@ Examples: v20.0.0 ``` -### `mise sync node <--brew|--nvm|--nodenv>` +## `mise sync node <--brew|--nvm|--nodenv>` ```text Symlinks all tool versions from an external tool into mise @@ -1147,7 +1147,7 @@ Examples: $ mise use -g node@18 - uses Homebrew-provided node ``` -### `mise sync python --pyenv` +## `mise sync python --pyenv` ```text Symlinks all tool versions from an external tool into mise @@ -1166,7 +1166,7 @@ Examples: $ mise use -g python@3.11.0 - uses pyenv-provided python ``` -### `mise task edit [OPTIONS] ` +## `mise task edit [OPTIONS] ` ```text [experimental] Edit a task with $EDITOR @@ -1188,7 +1188,7 @@ Examples: $ mise task edit test ``` -### `mise task ls [OPTIONS]` +## `mise task ls [OPTIONS]` ```text [experimental] List available tasks to execute @@ -1212,7 +1212,7 @@ Examples: $ mise task ls ``` -### `mise task run [OPTIONS] [TASK] [ARGS]...` +## `mise task run [OPTIONS] [TASK] [ARGS]...` **Aliases:** `r` @@ -1308,7 +1308,7 @@ Examples: Execute multiple tasks each with their own arguments. ``` -### `mise trust [OPTIONS] [CONFIG_FILE]` +## `mise trust [OPTIONS] [CONFIG_FILE]` ```text Marks a config file as trusted @@ -1342,7 +1342,7 @@ Examples: $ mise trust ``` -### `mise uninstall [OPTIONS] [TOOL@VERSION]...` +## `mise uninstall [OPTIONS] [TOOL@VERSION]...` **Aliases:** `remove, rm` @@ -1368,7 +1368,7 @@ Examples: $ mise uninstall --all node@18.0.0 # will uninstall all node versions ``` -### `mise upgrade [OPTIONS] [TOOL@VERSION]...` +## `mise upgrade [OPTIONS] [TOOL@VERSION]...` **Aliases:** `up` @@ -1400,7 +1400,7 @@ Options: Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 ``` -### `mise use [OPTIONS] [TOOL@VERSION]...` +## `mise use [OPTIONS] [TOOL@VERSION]...` **Aliases:** `u` @@ -1472,7 +1472,7 @@ Examples: $ mise use --env staging node@20 ``` -### `mise version` +## `mise version` ```text Show mise version @@ -1480,7 +1480,7 @@ Show mise version Usage: version ``` -### `mise watch [OPTIONS] [ARGS]...` +## `mise watch [OPTIONS] [ARGS]...` **Aliases:** `w` @@ -1516,7 +1516,7 @@ Examples: Extra arguments are passed to watchexec. See `watchexec --help` for details. ``` -### `mise where ` +## `mise where ` ```text Display the installation path for a runtime @@ -1545,7 +1545,7 @@ Examples: /home/jdx/.local/share/mise/installs/node/20.0.0 ``` -### `mise which [OPTIONS] ` +## `mise which [OPTIONS] ` ```text Shows the path that a bin name points to diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 53af6c33c..48f55ff91 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -38,7 +38,7 @@ fn render_commands() -> String { r#" - ## Commands + # Commands "# ); @@ -95,7 +95,7 @@ fn render_command(parent: Option<&str>, c: &clap::Command) -> Option { .to_string(); Some(formatdoc!( " - ### `mise {usage}` + ## `mise {usage}` {aliases} ```text {about} @@ -130,7 +130,7 @@ mod tests { .unwrap(); assert_cli!("render-help"); let readme = fs::read_to_string("docs/cli-reference.md").unwrap(); - assert!(readme.contains("## Commands")); + assert!(readme.contains("# Commands")); file::remove_file("docs/cli-reference.md").unwrap(); } } From a2f59c6933833e0a2f15066d952ce1119a0928c8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:13:37 -0600 Subject: [PATCH 1513/1891] auto-publish cli reference to docs --- .github/workflows/release.yml | 10 +++++----- scripts/release.sh | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 04598cd08..c7b9ede63 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -189,8 +189,8 @@ jobs: path: mise - uses: actions/checkout@v4 with: - repository: jdx/homebrew-tap - path: homebrew-tap + repository: jdx/mise-docs + path: mise-docs token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} - name: Install fd-find run: | @@ -212,7 +212,7 @@ jobs: gpg_private_key: ${{ secrets.MISE_GPG_KEY }} git_user_signingkey: true git_commit_gpgsign: true - workdir: homebrew-tap + workdir: mise-docs - uses: actions/download-artifact@v4 with: { path: artifacts } - run: mise/scripts/release.sh @@ -221,10 +221,10 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }} CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }} - - name: homebrew-tap push + - name: mise-docs push if: startsWith(github.event.ref, 'refs/tags/v') run: git push - working-directory: homebrew-tap + working-directory: mise-docs - name: GitHub Release Assets uses: softprops/action-gh-release@v1 if: startsWith(github.event.ref, 'refs/tags/v') diff --git a/scripts/release.sh b/scripts/release.sh index 22d6d4c60..704699104 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -72,8 +72,8 @@ if [[ "$DRY_RUN" != 1 ]]; then ./mise/scripts/publish-r2.sh fi -#echo "::group::Publish homebrew" -#./mise/scripts/render-homebrew.sh >homebrew-tap/mise.rb -#pushd homebrew-tap -#git add . && git commit -m "mise ${MISE_VERSION#v}" -#popd +echo "::group::Publish mise-docs" +cp ./mise/docs/cli-reference.md ./mise-docs/docs/cli/index.md +pushd mise-docs +git add docs/cli/index.md && git commit -m "mise ${MISE_VERSION#v}" +popd From edbdc7c448e1db522d1304c004aa36ed0e99f0c4 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:16:32 -0600 Subject: [PATCH 1514/1891] use: fix MISE_ASDF_COMPAT=1 (#1340) Fixes #1337 --- docs/cli-reference.md | 3 +-- src/cli/use.rs | 8 ++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/cli-reference.md b/docs/cli-reference.md index e0b5eb83d..06392b290 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -1453,8 +1453,7 @@ Options: --pin Save exact version to config file e.g.: `mise use --pin node@20` will save 20.0.0 as the version - - [env: MISE_ASDF_COMPAT=] + Set MISE_ASDF_COMPAT=1 to make this the default behavior Examples: # set the current version of node to 20.x in .mise.toml of current directory diff --git a/src/cli/use.rs b/src/cli/use.rs index dd6b52de6..4b1915d14 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -68,12 +68,8 @@ pub struct Use { /// Save exact version to config file /// e.g.: `mise use --pin node@20` will save 20.0.0 as the version - #[clap( - long, - env = "MISE_ASDF_COMPAT", - verbatim_doc_comment, - overrides_with = "fuzzy" - )] + /// Set MISE_ASDF_COMPAT=1 to make this the default behavior + #[clap(long, verbatim_doc_comment, overrides_with = "fuzzy")] pin: bool, } From 2c0ccf43fd23de03c25a872fe6d91f1d63c77c1a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:27:39 -0600 Subject: [PATCH 1515/1891] migrate improvements merge installs, skip non-portable python installs --- src/migrate.rs | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/migrate.rs b/src/migrate.rs index c5b95d54f..98ca19f31 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -10,7 +10,7 @@ use crate::file; pub fn run() { if let Err(err) = migrate_rtx() { - warn!("migrate: {}", err); + eprintln!("[WARN] migrate: {}", err); } rayon::scope(|s| { task(s, || rename_plugin("nodejs", "node")); @@ -28,21 +28,21 @@ pub fn run() { fn task(s: &Scope, job: impl FnOnce() -> Result<()> + Send + 'static) { s.spawn(|_| { if let Err(err) = job() { - warn!("migrate: {}", err); + eprintln!("[WARN] migrate: {}", err); } }); } fn move_subdirs(from: &Path, to: &Path) -> Result<()> { if from.exists() { - info!("migrating {} to {}", from.display(), to.display()); + eprintln!("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()); + eprintln!("moving {} to {}", from_file.display(), to_file.display()); file::rename(from_file, to_file)?; } } @@ -59,9 +59,24 @@ fn rename_plugin(from: &str, to: &str) -> Result<()> { } fn migrate_rtx() -> Result<()> { - move_dirs(&XDG_DATA_HOME.join("rtx"), &DATA)?; - move_dirs(&XDG_CONFIG_HOME.join("rtx"), &CONFIG)?; - move_dirs(&XDG_STATE_HOME.join("rtx"), &STATE)?; + let mut migrated = false; + let rtx_data = XDG_DATA_HOME.join("rtx"); + if rtx_data.exists() { + let installs = rtx_data.join("installs"); + for plugin in file::dir_subdirs(&installs)? { + if plugin == "python" { + continue; + } + migrated = migrated || move_dirs(&installs.join(plugin), &INSTALLS)?; + } + migrated = migrated || move_dirs(&rtx_data.join("plugins"), &DATA)?; + } + migrated = migrated || move_dirs(&XDG_CONFIG_HOME.join("rtx"), &CONFIG)?; + migrated = migrated || move_dirs(&XDG_STATE_HOME.join("rtx"), &STATE)?; + if migrated { + eprintln!("migrated rtx directories to mise"); + eprintln!("see https://mise.jdx.dev/rtx.html") + } Ok(()) } @@ -78,13 +93,15 @@ fn migrate_trusted_configs() -> Result<()> { Ok(()) } -fn move_dirs(from: &Path, to: &Path) -> Result<()> { +fn move_dirs(from: &Path, to: &Path) -> Result { if from.exists() && !to.exists() { - info!("migrating {} to {}", from.display(), to.display()); + eprintln!("migrating {} to {}", from.display(), to.display()); file::create_dir_all(to.parent().unwrap())?; file::rename(from, to)?; + Ok(true) + } else { + Ok(false) } - Ok(()) } fn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> { @@ -94,7 +111,7 @@ fn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> { if !gitconfig_body.contains(&format!("github.com/rtx-plugins/{plugin_name}")) { return Ok(()); } - info!("removing deprecated plugin {plugin_name}, will use core {name} plugin from now on"); + eprintln!("removing deprecated plugin {plugin_name}, will use core {name} plugin from now on"); file::remove_all(plugin_root)?; Ok(()) } From a30a5f104da41794aa8a2813919f046945ed9ae6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:35:50 -0600 Subject: [PATCH 1516/1891] doctor: fixed reading settings from config --- src/cli/doctor.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 681184531..8e534ddca 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -24,6 +24,9 @@ pub struct Doctor {} impl Doctor { pub fn run(self) -> Result<()> { let mut checks = Vec::new(); + if let Err(err) = Config::try_get() { + checks.push(format!("failed to load config: {}", err)); + } miseprintln!("{}", mise_version()); miseprintln!("{}", build_info()); From 70d08889f929d8f5f5360c7f1581f0afd1ab1570 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:43:37 -0600 Subject: [PATCH 1517/1891] chore: Release mise version 2024.1.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36e59e8b5..ffd11cd39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.0" +version = "2024.1.1" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 8486f9dd1..bf9ff3c4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.0" +version = "2024.1.1" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 3204d3c77..c6d79cb18 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise on macOS (other methods [here](https://mise.jdx.dev/getting-started ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/share/mise/bin/mise --version -mise 2024.1.0 +mise 2024.1.1 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index cd203df00..71ae4ef2a 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.0"; + version = "2024.1.1"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 63f64ccb0..f7c9612b0 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.0 +Version: 2024.1.1 Release: 1 URL: https://github.com/jdx/mise/ Group: System From e2d50a2f25c0c64c207f82e957e691671d52ddbd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:46:39 -0600 Subject: [PATCH 1518/1891] python: fix venv python path Fixes #1336 --- src/toolset/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index e521967b7..10e08b567 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -308,8 +308,7 @@ impl Toolset { .collect::>(); let add_paths = entries .iter() - .filter(|(k, _)| k == "MISE_ADD_PATH") - .filter(|(k, _)| k == "RTX_ADD_PATH") + .filter(|(k, _)| k == "MISE_ADD_PATH" || k == "RTX_ADD_PATH") .map(|(_, v)| v) .join(":"); let mut entries: BTreeMap = entries From 0d80c57162dfefb658f997d6d6312a233becc225 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:48:29 -0600 Subject: [PATCH 1519/1891] chore: Release mise version 2024.1.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffd11cd39..3d9214fe4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.1" +version = "2024.1.2" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index bf9ff3c4d..d9f34d6aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.1" +version = "2024.1.2" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index c6d79cb18..dd945d2b6 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise on macOS (other methods [here](https://mise.jdx.dev/getting-started ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/share/mise/bin/mise --version -mise 2024.1.1 +mise 2024.1.2 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 71ae4ef2a..7f60b108b 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.1"; + version = "2024.1.2"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index f7c9612b0..c7c310daa 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.1 +Version: 2024.1.2 Release: 1 URL: https://github.com/jdx/mise/ Group: System From d5d2d39aa1a44a6421dff150da42083c4247cff9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:26:28 -0600 Subject: [PATCH 1520/1891] ci: use mise docker containers --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c7b9ede63..93e3250b9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,7 +128,7 @@ jobs: runs-on: ubuntu-22.04 needs: [build-tarball] timeout-minutes: 10 - container: ghcr.io/jdx/rtx:rpm + container: ghcr.io/jdx/mise:rpm steps: - uses: actions/checkout@v4 - uses: crazy-max/ghaction-import-gpg@v6 @@ -150,7 +150,7 @@ jobs: if-no-files-found: error deb: runs-on: ubuntu-22.04 - container: ghcr.io/jdx/rtx:deb + container: ghcr.io/jdx/mise:deb timeout-minutes: 10 needs: [build-tarball] steps: From 7f6545c2630a1f54b864903851c24e68b3da3d2f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:49:24 -0600 Subject: [PATCH 1521/1891] ci: skip committing docs if no changes --- scripts/release.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/release.sh b/scripts/release.sh index 704699104..bb43e14b9 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -75,5 +75,10 @@ fi echo "::group::Publish mise-docs" cp ./mise/docs/cli-reference.md ./mise-docs/docs/cli/index.md pushd mise-docs -git add docs/cli/index.md && git commit -m "mise ${MISE_VERSION#v}" +if [[ -z $(git status -s) ]]; then + echo "No changes to docs" +else + git add docs/cli/index.md + git commit -m "mise ${MISE_VERSION#v}" +fi popd From cd2045d793c76b9dcf7d26c567cf163a6138f408 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:57:00 -0600 Subject: [PATCH 1522/1891] standalone: use ~/.local/bin/mise instead of ~/.local/share/mise/bin/mise --- README.md | 10 +++++----- packaging/standalone/install.envsubst | 4 +--- scripts/test-standalone.sh | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index dd945d2b6..2e4928a4a 100644 --- a/README.md +++ b/README.md @@ -33,18 +33,18 @@ Install mise on macOS (other methods [here](https://mise.jdx.dev/getting-started ```sh-session $ curl https://mise.jdx.dev/install.sh | sh -$ ~/.local/share/mise/bin/mise --version +$ ~/.local/bin/mise --version mise 2024.1.2 ``` Hook mise into your shell (pick the right one for your shell): ```sh-session -# note this assumes mise is located at ~/.local/share/mise/bin/mise +# note this assumes mise is located at ~/.local/bin/mise # which is what install.sh does by default -echo 'eval "$(~/.local/share/mise/bin/mise activate bash)"' >> ~/.bashrc -echo 'eval "$(~/.local/share/mise/bin/mise activate zsh)"' >> ~/.zshrc -echo '~/.local/share/mise/bin/mise activate fish | source' >> ~/.config/fish/config.fish +echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc +echo 'eval "$(~/.local/bin/mise activate zsh)"' >> ~/.zshrc +echo '~/.local/bin/mise activate fish | source' >> ~/.config/fish/config.fish ``` Install a runtime and set it as the global default: diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index b6abbcf77..e8dce5a51 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -114,9 +114,7 @@ install_mise() { version="$MISE_VERSION" os="$(get_os)" arch="$(get_arch)" - xdg_data_home="${XDG_DATA_HOME:-$HOME/.local/share}" - mise_data_dir="${MISE_DATA_DIR:-$xdg_data_home/mise}" - install_path="${MISE_INSTALL_PATH:-${mise_data_dir}/bin/mise}" + install_path="${MISE_INSTALL_PATH:-$HOME/.local/bin/mise}" install_dir="$(dirname "$install_path")" tarball_url="https://github.com/jdx/mise/releases/download/${version}/mise-${version}-${os}-${arch}.tar.gz" diff --git a/scripts/test-standalone.sh b/scripts/test-standalone.sh index a172442e7..623a200a0 100755 --- a/scripts/test-standalone.sh +++ b/scripts/test-standalone.sh @@ -12,8 +12,8 @@ curl -fsSL "https://mise.jdx.dev/$MISE_VERSION/SHASUMS256.txt" >"$RELEASE_DIR/$M chmod +x tmp/install.sh shellcheck tmp/install.sh -MISE_DATA_DIR="$RELEASE_DIR" ./tmp/install.sh -if [[ ! "$("$RELEASE_DIR/bin/mise" -v)" =~ ^${MISE_VERSION//v/} ]]; then +./tmp/install.sh +if [[ ! "$("$HOME/.local/bin/mise" -v)" =~ ^${MISE_VERSION//v/} ]]; then echo "mise version mismatch" exit 1 fi From 463712009094641a105f053907a125590001880c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 12:05:10 -0600 Subject: [PATCH 1523/1891] chore: Release mise version 2024.1.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d9214fe4..74506de08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.2" +version = "2024.1.3" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index d9f34d6aa..a52cb46a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.2" +version = "2024.1.3" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 2e4928a4a..7157676c0 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise on macOS (other methods [here](https://mise.jdx.dev/getting-started ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.2 +mise 2024.1.3 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 7f60b108b..285e0bfa2 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.2"; + version = "2024.1.3"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index c7c310daa..03436b6c0 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.2 +Version: 2024.1.3 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 04f55cd677a3041232887c2f3731d17f775e3627 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 12:45:16 -0600 Subject: [PATCH 1524/1891] rtx-plugins -> mise-plugins --- .mise.toml | 2 +- SECURITY.md | 10 +++++----- completions/_mise | 2 +- completions/mise.fish | 2 +- docs/cli-reference.md | 8 ++++---- e2e/config/.e2e.mise.toml | 2 +- e2e/test_local | 8 ++++---- e2e/test_plugins_install | 4 ++-- scripts/query-top-plugins.fish | 2 +- scripts/update-shorthand-repo.sh | 4 ++-- src/cli/plugins/install.rs | 6 +++--- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/update.rs | 2 +- src/default_shorthands.rs | 8 ++++---- src/git.rs | 2 +- src/migrate.rs | 2 +- 16 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.mise.toml b/.mise.toml index 44a617dcd..4c5939e86 100644 --- a/.mise.toml +++ b/.mise.toml @@ -13,7 +13,7 @@ python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } ruby = "3.1" [plugins] -nnnn = 'https://github.com/rtx-plugins/rtx-nodejs#main' +nnnn = 'https://github.com/mise-plugins/rtx-nodejs#main' [alias.tiny] abc = '1' diff --git a/SECURITY.md b/SECURITY.md index a63533357..ef0505e7c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -34,26 +34,26 @@ There are 3 types of plugins: - [core](https://github.com/jdx/mise/issues/236) - plugins that are hardcoded into the CLI. These are official plugins for the most common languages written in Rust. -- community - plugins in the [rtx-plugins](https://github.com/rtx-plugins) GitHub Org. [See below](#rtx-plugins-github-org) for details. +- community - plugins in the [mise-plugins](https://github.com/mise-plugins) GitHub Org. [See below](#mise-plugins-github-org) for details. - external - plugins owned by other parties, these include plugins in the shorthand registry. These are no more secure than installing any random tool from the internet. These receive a warning dialog when installed in mise. Just because a plugin is inside of the shorthand registry (so you can run `mise install foo@`, does not mean -I vouch for it. I have no idea who almost anyone that builds those plugins are. If it's coming from the rtx-plugins +I vouch for it. I have no idea who almost anyone that builds those plugins are. If it's coming from the mise-plugins GitHub org, you can have more trust in it. (See the owners with `mise plugins ls-remote --urls`). Over time we should be able to move more plugins into being fully maintained by mise. I plan to add an `MISE_PARANOID=1` env var that, when set, will make changes to make mise behave as securely as possible -(e.g.: only using core/rtx-plugins plugins, only allowing plugins that use GPG verification of assets). +(e.g.: only using core/mise-plugins plugins, only allowing plugins that use GPG verification of assets). -## [rtx-plugins](https://github.com/rtx-plugins) GitHub org +## [mise-plugins](https://github.com/mise-plugins) GitHub org This is similar to but with the advantage of being more secure by keeping the contributor count minimal—currently only @jdx will be allowed to merge PRs. For this reason, plugins using this organization will not receive a confirmation warning dialog when installed with mise as they've been vetted by a trusted source. -If you're a plugin maintainer that would like to move your repo to this org [please let me know](https://github.com/orgs/rtx-plugins/discussions). +If you're a plugin maintainer that would like to move your repo to this org [please let me know](https://github.com/orgs/mise-plugins/discussions). Plugins can either retain compatibility with asdf or use mise specific functionality—that's up to you. asdf-compatible plugins should use "asdf-" as the prefix and "mise-" prefixed-plugins denote mise-only compatibility. ## Supported Versions diff --git a/completions/_mise b/completions/_mise index 4d89f2a89..5e1ff2fbe 100644 --- a/completions/_mise +++ b/completions/_mise @@ -536,7 +536,7 @@ __mise_plugins_ls_cmd() { (( $+functions[__mise_plugins_ls_remote_cmd] )) || __mise_plugins_ls_remote_cmd() { _arguments -s -S \ - '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/rtx-plugins/rtx-nodejs.git]' \ + '(-u --urls)'{-u,--urls}'[Show the git url for each plugin e.g.\: https\://github.com/mise-plugins/rtx-nodejs.git]' \ '--only-names[Only show the name of each plugin by default it will show a "*" next to installed plugins]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ diff --git a/completions/mise.fish b/completions/mise.fish index 8e0f12f7f..b87bfd9ac 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -202,7 +202,7 @@ complete -kxc mise -n "$fssf plugins; and $fssf ls" -l user -d 'List installed p # plugins ls-remote complete -kxc mise -n "$fssf plugins; and $fssf ls-remote" -l only-names -d 'Only show the name of each plugin by default it will show a "*" next to installed plugins' -complete -kxc mise -n "$fssf plugins; and $fssf ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git' +complete -kxc mise -n "$fssf plugins; and $fssf ls-remote" -s u -l urls -d 'Show the git url for each plugin e.g.: https://github.com/mise-plugins/rtx-nodejs.git' # plugins uninstall complete -kxc mise -n "$fssf plugins; and $fssf uninstall" -s a -l all -d 'Remove all plugins' diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 06392b290..21c5c2cb9 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -682,14 +682,14 @@ Examples: $ mise plugins install node # install the node plugin using a specific git url - $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git # install the node plugin using the git url only # (node is inferred from the url) - $ mise plugins install https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install https://github.com/mise-plugins/rtx-nodejs.git # install the node plugin using a specific ref - $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 + $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git#v1.0.0 ``` ## `mise plugins link [OPTIONS] [PATH]` @@ -777,7 +777,7 @@ Usage: plugins ls-remote [OPTIONS] Options: -u, --urls - Show the git url for each plugin e.g.: https://github.com/rtx-plugins/rtx-nodejs.git + Show the git url for each plugin e.g.: https://github.com/mise-plugins/rtx-nodejs.git --only-names Only show the name of each plugin by default it will show a "*" next to installed plugins diff --git a/e2e/config/.e2e.mise.toml b/e2e/config/.e2e.mise.toml index 46ecdf59e..ae4903b36 100644 --- a/e2e/config/.e2e.mise.toml +++ b/e2e/config/.e2e.mise.toml @@ -9,7 +9,7 @@ tiny = "latest" #golang = {version="1.19.5", foo="bar"} [plugins] -tiny-ref = "https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c" +tiny-ref = "https://github.com/mise-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c" [tasks.configtask] run = 'echo "configtask:"' diff --git a/e2e/test_local b/e2e/test_local index cef6a0d64..1b0c14621 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -29,7 +29,7 @@ tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" +tiny-ref = \"https://github.com/mise-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" [tasks.configtask] run = 'echo \"configtask:\"' @@ -52,7 +52,7 @@ shfmt = \"3.5.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" +tiny-ref = \"https://github.com/mise-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" [tasks.configtask] run = 'echo \"configtask:\"' @@ -80,7 +80,7 @@ shfmt = \"3.6.0\" #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" +tiny-ref = \"https://github.com/mise-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" [tasks.configtask] run = 'echo \"configtask:\"' @@ -107,7 +107,7 @@ tiny = \"latest\" #golang = {version=\"1.19.5\", foo=\"bar\"} [plugins] -tiny-ref = \"https://github.com/rtx-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" +tiny-ref = \"https://github.com/mise-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\" [tasks.configtask] run = 'echo \"configtask:\"' diff --git a/e2e/test_plugins_install b/e2e/test_plugins_install index 0c53e04f9..1892ecc00 100755 --- a/e2e/test_plugins_install +++ b/e2e/test_plugins_install @@ -28,13 +28,13 @@ assert_contains "mise plugin ls" "shfmt" assert_contains "mise plugin ls" "shellcheck" rm -rf "$MISE_DATA_DIR/plugins/tiny" -mise plugin install https://github.com/rtx-plugins/rtx-tiny.git +mise plugin install https://github.com/mise-plugins/rtx-tiny.git assert_contains "mise plugin ls" "tiny" mise plugin install -f tiny assert_contains "mise plugin ls" "tiny" rm -rf "$MISE_DATA_DIR/plugins/tiny" -mise plugin install tiny https://github.com/rtx-plugins/rtx-tiny +mise plugin install tiny https://github.com/mise-plugins/rtx-tiny assert_contains "mise plugin ls" "tiny" rm -rf "$MISE_DATA_DIR/plugins/shellcheck" diff --git a/scripts/query-top-plugins.fish b/scripts/query-top-plugins.fish index f81c1bb4e..3669c2870 100755 --- a/scripts/query-top-plugins.fish +++ b/scripts/query-top-plugins.fish @@ -16,7 +16,7 @@ if test -d /tmp/asdf-plugins git pull /tmp/asdf-plugins cd $current_dir else - git clone --depth=1 git@github.com:rtx-plugins/registry.git /tmp/asdf-plugins + git clone --depth=1 git@github.com:mise-plugins/registry.git /tmp/asdf-plugins end if test -e stargazer_count.txt diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index f7147eabf..db0383404 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -2,7 +2,7 @@ set -euo pipefail rm -rf asdf-plugins -git clone --depth 1 https://github.com/rtx-plugins/registry asdf-plugins +git clone --depth 1 https://github.com/mise-plugins/registry asdf-plugins rm -f src/default_shorthands.rs asdf_plugins=$(ls asdf-plugins/plugins) @@ -40,7 +40,7 @@ for plugin in $asdf_plugins; do repository=$(grep -e '^repository = ' "$file") repository="${repository/#repository = /}" printf "[%03d/%d] %s\n" $((++count)) "$num_plugins" "$repository" - if [[ $repository == "https://github.com/rtx-plugins/"* ]]; then + if [[ $repository == "https://github.com/mise-plugins/"* ]]; then trusted+=("$plugin") elif grep -qe '^first-party = true' "$file"; then trusted+=("$plugin") diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 410f98d89..02ff3ab33 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -147,14 +147,14 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ mise plugins install node # install the node plugin using a specific git url - $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git # install the node plugin using the git url only # (node is inferred from the url) - $ mise plugins install https://github.com/rtx-plugins/rtx-nodejs.git + $ mise plugins install https://github.com/mise-plugins/rtx-nodejs.git # install the node plugin using a specific ref - $ mise plugins install node https://github.com/rtx-plugins/rtx-nodejs.git#v1.0.0 + $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git#v1.0.0 "# ); diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 3b5643319..a119b602f 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -11,7 +11,7 @@ use crate::config::Config; #[clap(visible_aliases = ["list-remote", "list-all"], long_about = LONG_ABOUT, verbatim_doc_comment)] pub struct PluginsLsRemote { /// Show the git url for each plugin - /// e.g.: https://github.com/rtx-plugins/rtx-nodejs.git + /// e.g.: https://github.com/mise-plugins/rtx-nodejs.git #[clap(short, long)] pub urls: bool, diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 8d5e29fc8..ed5ceff36 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -79,7 +79,7 @@ mod tests { "plugin", "install", "tiny", - "https://github.com/rtx-plugins/rtx-tiny.git" + "https://github.com/mise-plugins/rtx-tiny.git" ); // assert_cli!("p", "update"); tested in e2e assert_cli!("plugins", "update", "tiny"); diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 15a74276e..a02350f8a 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -304,7 +304,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("hey", "https://github.com/raimon49/asdf-hey.git"), ("hostctl", "https://github.com/svenluijten/asdf-hostctl.git"), ("httpie-go", "https://github.com/abatilo/asdf-httpie-go.git"), - ("hub", "https://github.com/rtx-plugins/asdf-hub.git"), + ("hub", "https://github.com/mise-plugins/asdf-hub.git"), ("hugo", "https://github.com/NeoHsu/asdf-hugo.git"), ("hurl", "https://github.com/raimon49/asdf-hurl.git"), ("hwatch", "https://github.com/chessmango/asdf-hwatch.git"), @@ -499,13 +499,13 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("php", "https://github.com/asdf-community/asdf-php.git"), ("pint", "https://github.com/sam-burrell/asdf-pint.git"), ("pipectl", "https://github.com/pipe-cd/asdf-pipectl.git"), - ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), + ("pipenv", "https://github.com/mise-plugins/rtx-pipenv.git"), ("pipx", "https://github.com/yozachar/asdf-pipx.git"), ("pivnet", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("please", "https://github.com/asdf-community/asdf-please.git"), ("pluto", "https://github.com/FairwindsOps/asdf-pluto.git"), ("pnpm", "https://github.com/jonathanmorley/asdf-pnpm.git"), - ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), + ("poetry", "https://github.com/mise-plugins/rtx-poetry.git"), ("polaris", "https://github.com/particledecay/asdf-polaris.git"), ("popeye", "https://github.com/nlamirault/asdf-popeye.git"), ("postgres", "https://github.com/smashedtoatoms/asdf-postgres.git"), @@ -658,7 +658,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("thrift", "https://github.com/alisaifee/asdf-thrift.git"), ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), ("timoni", "https://github.com/Smana/asdf-timoni.git"), - ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), + ("tiny", "https://github.com/mise-plugins/rtx-tiny.git"), ("titan", "https://github.com/gabitchov/asdf-titan.git"), ("tlsg-cli", "https://github.com/0ghny/asdf-tlsgcli.git"), ("tmux", "https://github.com/aphecetche/asdf-tmux.git"), diff --git a/src/git.rs b/src/git.rs index 54239e019..887a81705 100644 --- a/src/git.rs +++ b/src/git.rs @@ -155,7 +155,7 @@ fn get_git_version() -> Result { // fn test_clone_and_update() { // let dir = tempdir().unwrap().into_path(); // let git = Git::new(dir); -// git.clone("https://github.com/rtx-plugins/rtx-tiny") +// git.clone("https://github.com/mise-plugins/rtx-tiny") // .unwrap(); // let prev_rev = "c85ab2bea15e8b785592ce1a75db341e38ac4d33".to_string(); // let latest = git.current_sha().unwrap(); diff --git a/src/migrate.rs b/src/migrate.rs index 98ca19f31..0dac368a9 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -108,7 +108,7 @@ fn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> { let plugin_root = PLUGINS.join(name); let gitconfig = plugin_root.join(".git").join("config"); let gitconfig_body = fs::read_to_string(gitconfig).unwrap_or_default(); - if !gitconfig_body.contains(&format!("github.com/rtx-plugins/{plugin_name}")) { + if !gitconfig_body.contains(&format!("github.com/mise-plugins/{plugin_name}")) { return Ok(()); } eprintln!("removing deprecated plugin {plugin_name}, will use core {name} plugin from now on"); From ed794d15cf035a993e0c286e84dac0335ffe8967 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:04:43 -0600 Subject: [PATCH 1525/1891] rtx -> mise --- .idea/modules.xml | 4 ++-- .idea/rtx.iml | 28 ---------------------------- 2 files changed, 2 insertions(+), 30 deletions(-) delete mode 100644 .idea/rtx.iml diff --git a/.idea/modules.xml b/.idea/modules.xml index 9c1941576..491999a63 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + - \ No newline at end of file + diff --git a/.idea/rtx.iml b/.idea/rtx.iml deleted file mode 100644 index 8e4258be6..000000000 --- a/.idea/rtx.iml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 581a1fec088fdbf90c38dc9e79fc0449df2218a5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 15:28:42 -0600 Subject: [PATCH 1526/1891] aur: add "replaces" field (#1345) --- scripts/release-aur-bin.sh | 2 ++ scripts/release-aur.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index fdcebdd6c..cd27cc161 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -24,6 +24,7 @@ url='https://github.com/jdx/mise' license=('MIT') provides=('mise') conflicts=('mise') +replaces=('rtx-bin') options=('!lto') source=("mise-\$pkgver.tar.gz::${TAR_GZ_URI}") sha512sums=('$SHA512') @@ -59,6 +60,7 @@ arch = x86_64 license = MIT provides = mise conflicts = mise +replaces = rtx-bin source = mise-${MISE_VERSION#v*}.tar.gz::${TAR_GZ_URI} sha512sums = $SHA512 diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 67effabad..ff591a1f5 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -23,6 +23,7 @@ license=('MIT') makedepends=('cargo') provides=('mise') conflicts=('mise-bin') +replaces=('rtx') options=('!lto') source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdx/\$pkgname/archive/v\$pkgver.tar.gz") sha512sums=('$SHA512') @@ -64,6 +65,7 @@ arch = x86_64 license = MIT makedepends = cargo provides = mise +replaces = rtx conflicts = mise source = mise-${MISE_VERSION#v*}.tar.gz::https://github.com/jdx/mise/archive/$MISE_VERSION.tar.gz sha512sums = $SHA512 From fd3ecdfa1b8198e3c79883afc9f984c49c3aa3a0 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Thu, 4 Jan 2024 02:07:06 +0100 Subject: [PATCH 1527/1891] fix(java): use tar.gz archives to enable symlink support (#1343) --- src/plugins/core/java.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 9027b6147..92ef3ab96 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -148,11 +148,7 @@ impl JavaPlugin { m: &JavaMetadata, ) -> Result<()> { pr.set_message(format!("installing {}", tarball_path.display())); - if m.file_type == Some("zip".to_string()) { - file::unzip(tarball_path, &tv.download_path())?; - } else { - file::untar(tarball_path, &tv.download_path())?; - } + file::untar(tarball_path, &tv.download_path())?; self.move_to_install_path(tv, m) } @@ -407,4 +403,4 @@ impl Display for JavaMetadata { static JAVA_FEATURES: Lazy> = Lazy::new(|| HashSet::from(["musl", "javafx", "lite", "large_heap"].map(|s| s.to_string()))); static JAVA_FILE_TYPES: Lazy> = - Lazy::new(|| HashSet::from(["tar.gz", "zip"].map(|s| s.to_string()))); + Lazy::new(|| HashSet::from(["tar.gz"].map(|s| s.to_string()))); From 0b18f026d31cbf8b297386101ee5ee213d9c82d8 Mon Sep 17 00:00:00 2001 From: Malachi Soord Date: Thu, 4 Jan 2024 02:09:15 +0100 Subject: [PATCH 1528/1891] Add additional conflicts (#1346) * Add additional conflicts * fix bin --- scripts/release-aur-bin.sh | 6 ++++-- scripts/release-aur.sh | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index cd27cc161..bf14af7ad 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -23,7 +23,7 @@ arch=('x86_64') url='https://github.com/jdx/mise' license=('MIT') provides=('mise') -conflicts=('mise') +conflicts=('mise' 'rtx-bin' 'rtx') replaces=('rtx-bin') options=('!lto') source=("mise-\$pkgver.tar.gz::${TAR_GZ_URI}") @@ -59,8 +59,10 @@ url = https://github.com/jdx/mise arch = x86_64 license = MIT provides = mise -conflicts = mise replaces = rtx-bin +conflicts = mise +conflicts = rtx-bin +conflicts = rtx source = mise-${MISE_VERSION#v*}.tar.gz::${TAR_GZ_URI} sha512sums = $SHA512 diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index ff591a1f5..3e21bfdb0 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -22,7 +22,7 @@ url='https://github.com/jdx/mise' license=('MIT') makedepends=('cargo') provides=('mise') -conflicts=('mise-bin') +conflicts=('mise-bin' 'rtx', 'rtx-bin') replaces=('rtx') options=('!lto') source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdx/\$pkgname/archive/v\$pkgver.tar.gz") @@ -66,7 +66,9 @@ license = MIT makedepends = cargo provides = mise replaces = rtx -conflicts = mise +conflicts = rtx +conflicts = rtx-bin +conflicts = mise-bin source = mise-${MISE_VERSION#v*}.tar.gz::https://github.com/jdx/mise/archive/$MISE_VERSION.tar.gz sha512sums = $SHA512 From eb73edfab75d8a2b5bd58be71b2ccbd172b92413 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:09:57 -0600 Subject: [PATCH 1529/1891] install: docs --- docs/cli-reference.md | 2 +- src/cli/install.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 21c5c2cb9..93d52b908 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -460,7 +460,7 @@ Examples: $ mise install node@20.0.0 # install specific node version $ mise install node@20 # install fuzzy node version $ mise install node # install version specified in .tool-versions or .mise.toml - $ mise install # installs everything specified in .tool-versions or .mise.toml + $ mise install # installs everything specified in .tool-versions or .mise.toml ``` ## `mise latest [OPTIONS] ` diff --git a/src/cli/install.rs b/src/cli/install.rs index dd35f4eca..dca289ffd 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -138,7 +138,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ mise install node@20.0.0 # install specific node version $ mise install node@20 # install fuzzy node version $ mise install node # install version specified in .tool-versions or .mise.toml - $ mise install # installs everything specified in .tool-versions or .mise.toml + $ mise install # installs everything specified in .tool-versions or .mise.toml "# ); From 756c719777fc794e49ee707985ca07d66fdaa835 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:28:17 -0600 Subject: [PATCH 1530/1891] demo (#1348) --- README.md | 2 +- docs/demo.gif | Bin 1577362 -> 2484757 bytes docs/demo.sh | 2 ++ docs/demo.tape | 23 ++++++++++++++++++----- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7157676c0..5dd283a45 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Note that calling `which node` gives us a real path to node, not a shim. ## Quickstart -Install mise on macOS (other methods [here](https://mise.jdx.dev/getting-started.html)): +Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh diff --git a/docs/demo.gif b/docs/demo.gif index db4cc768506813585b8155bbb8c79c2c86a9e14b..7e11432bedbac08f2e748b4d9568e762c0856e14 100644 GIT binary patch literal 2484757 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

    4|oj&of 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

    ^t&V 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%0D2&!Xse5G$3jbo#e0LZv<%)L+cV{ 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⪚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�EmSu~X^enW+EOu!sX6 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�?cw!5AIq;6;4)UklIh?=zEO1Jmq>;i!ak> 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

cHWDx9B0aAdLJF_k*S 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ÐZOT`XtZ>FAfmzme(@d3(OV^xg80f*oE4!bvo>8% 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›V1C?T5SxiNrUn<4uX!Gj2o(}WHZMgxnr84M> zBKjdUlA(=((Vqf_vQC%k=NSSAAlXssk#8@)3yw58bQ%CUTKsO;wgA<5Nb|@no>wYK za!2bh(8q_E;b-9PL> zAf;MTu`1tOCQlhEp8~DCaehih>5vs^{d6u#Mxzu_)NuME`HT6MdLR$`Gk0Q}h|(`PM?*_`OYA*%Zv5>H>qDDmU+sk} zm}!Vh5lsm`T3-(>@9{cd!jKonG2YI4-F6aRCw+#|eELbaBULEZr2LvL)sx-QWnHUv z>BfXPv9P^nR{}sa-NbJ);;9>Y=eueN{$e_CC1eoziW+D;*%QWcu!|iqzhFP>fBFtp zMdhqY+H<=C`-9P?dvr){>;AinzRGy2%S82){i!_^@9#XzjW1>!Jh!?I$o({#3 zwp5q+(1~fOwo^S7!bOMS66_o!bd@a5T)1HK)$Wa(+|RsB(vjBS8)l2sm~FMBOJbjq z_popH4$)MM&Z(jbWU#HL0c|?Mb5r5&V)&B-9+m*tIeXG;ZP@S=U5kI@=t60RkisobecmDWZAnV$_3%%W* zouLj*rHD7;k`94*hu`9FNChvZrQFLgYtwiFgLVJv7je(n+EMow8A;b(cpFi5EDC7g zNTdHgW=aaNIPS>br?T#^!rRwFUd69g{re+#5?JqHX@U*S{!OJM7<%`btb&@Hd#VDR&ZZs~nvQtzW@L|8jR);VJF zQ=rzOgF&sxmeuklTz3`h$JY2`)0lkc2+*Y1vle2f74w!1MiO6xDu?6EzviTe$c9>B z!-ZDLZ6so~QInDuI)>S*FpFhRsI;M!e9sT`YQ|cVm9QW2ZCzJBJIG8=x7Rav)-7#Z zCW|-OAFR}WdeZ;qjrZ8(6?_3Ge09$6HKQpf0ZZs|nSF$XiR0+2Sfu0k{6Z@{S$yWl zL&}6QFPYVOtew}=UJ$TDjwMkgQlIxIlOF6Yn^(4uj(P%OT9Ik&!aqwy#nBLAI9MdT z-Wc?cTm;SsE?_#lux&t`;3c+Wx_x|Ht`vL@?lz8hYW%@y9QpI;Tj{AF?c%+?D)cB9 zWb)MxF{3%)n@anq_Xo83&9+{avE%+VNwc@+UX|V->aSP7mM~Ls z(^ii;`#sC&`U!TIiQOG5<8!Ws1&mN4d6M|-$vON=m(uYYj8NE{-4hB5=s(o~o;p_8 zM8nrF6o(HKDVKLCx7OqFvURVnd1kJ~-X^{+Yk&OTUu+3cg66Hg_3==t34-Y@W}hZ;|8+$sR#5w?Nx)2|*$W-U!m+pK=LJ^ST`@H2LdsM>jr z#If%k&zeQrs!lSLkf1g%XHmtftzVWVF~F^=WMJjgwo4+Rc||e1r-aM^QJ$zJCjr?{Iqjb`1P7 zl!*L?mn*&H8;s{?d>7Dvrd90Lm{$4M_2S{l%E6}mg(KK?hI0SkGj4Q+F@|O@2i5}r z+!?<{yyhH7uyxAvc!cnYN&I z`-#yki0=CE@0G#yE5=3UtjD=ut;4))PRW;6;*KV6SKi~LnVbuhuIER+KKfR9-$BhC z37y*v+4h@q$KGeY_&o(BZ?0X+*m~=DBW624D0Hl=u#^3Jaa^)$&z)NmE$itIni%c} z_F+0oM$Bruzb%YD@OgICrv2CQr}hM)o&^}|R#?qL|3S%Y8K$@i9k!sm3XDTq#P86p zk3h5KZWMSFPQAjWgnfG-V)TTcq{aLD0kNCv{gteIH+(o*(rt+Td}mR)zqiEkw5BX$ z-u&8L%w1>ZyF->md`G=uciGp59ET|ULG6zY6uBF5YUyrYqPkzujnhh?yI(u2zc#$# z74yy~(!|Ri%#0(y(k+NyMc7W7mwN0?pI;la8$wWEQk$=nL@jXcKN0$I&0ov2jlD|K zHA6)CP~#zhI$R2L+nF&_o^yY{aIY>7R7Vy|%hfm)4Tb5d9*;@akx*mHO%8On7oz868n9oHnKrzf%%(N%du{rm27XK7r1fXbOL2u{wHfl9 z-;UMSNAH#knpQKK-qv^~tJ$7EzOKJ!lXu|I!8P5RlC@{o2yGst11XQy*wX`sYZedp zV_efWYVk81#bY&LY2Aq2*NHR9brC`I12#Xy;or0WS_(CcHH`0}ovJHd%yr*-n>Hq? zfxP(3p772Slx>h!lyyQP4Pf*n*TZ=Yp77}oz|d&T9^|s)iRmm;v50mq#sA}Frc-mH zHu>jk(*rXO5*Ku3d=yRca+tD}6iL7JVK=u+8}Cn^ydZ&%c2^IbxSKWQr^b`|235I3 z>xOoo|F94}f0@UFt0i))etjx)qCl}Vsyb}yggvZ%r3jx?YQB<6eOOR zE4Acis3uU|_F~<=V^c+ZLQPR42pC8&I%Kjn)zotYt(-`pOC2L_{fe;#tUUL{j$Zrc zsc#3kOknB!y?fe$&qUH9&*)fFw_i9tmbGr!DO6*NsF*+;OG%&#`&8<3eGFLqgr7jO zWPrb3$i2;L2zc7&WQzB`vz}fL(hHs0&fm1docgK}Ng08>=p*&Kdrg=tJGH&};hFgn zK}5>=;rElNwp&APhO@({7oL2(YtJj#);&rdD{;2CwXvj$~#$M))+`U;w8Pe&)W z+JJ9nTE=AE2wA(pEhOYvhHHF9gowRzXkzC+C_mvsP1d^}E|tq%qEG$0*Xw#bHy;)l zu;XoB_QgSp9JX>+Y2rigqru+G7~fL8+D**X!dm*oK&jf{Rv<6vJ~PT?3SCbI!I`dC zX2WN+f28kCogHDM5O)w7p**@obcy(e&})xmhWi0M_fi~a9wPY?9W@_-)ypS=cM{Ss zjFn-2@6)2xE)20vn@fTQAr?=KhS}B8_lyG<);$-8ZS;&QI?9Vz-+PFvq*)c#%T;by zBt}cr)=S9u@GciE4tYFUiae8)kN1mIPoLn!*ZHIz5nM2e-QiJpY2>14~IF~kh=>n zI#5E+fVEFPRQFDbEy2oyb@$``j6K|I`mpf7s$&;Fj{ivGD@>*Bl^?x5K3X07s3u~! zAMpF}x1thVy?dSs#~*QUQ@f=@ejYB&D$Vx!`|xq^?z*UBukIo67oH48)SVBQcsF@= zD8nc5+xdDQTna+5{nK*Yg{qL9UoT(inB84}aXj_dT*~i`DHGX*DaonLmlrzMYwIul z$ejASc;VUK<@zf^Nj^X_jw`O$z(8g3#dXIzN>9)%j#hqxNUlE|@%WRvxYLm&h3gNX8oFd@HWzdn zObj-hAimK3d?UE<(~Qc45AeVvpJNe9!tR9XYdI^%s)dKsED1 z#RPOn7!+@wJKzRtPMukH4fQ!lIB~N6VP=3RI>UhlwGkvH*?m^UHmK8|Ai8?0M%P@*H6()!LB?I5*#$>atwlKBHG3It}h1lephv*rRJkdz93S=hq5gX z6`+scIvL_Gw`Rm6%>UqSHl{oeJDMCx#p=IhUv-PJXbHW3@T*=75JM9=bhs1s`EwCZ z#{E$zv^p%+oS$1v5>a7`IQ$~*IYKl`KC%eBds*M<cPlX zCe7ZB+DLx5IUSyA+-qQaE_${HBR_w10xLOu#7JCadp_AP$a3X-Mu!AH6l!H!>ViL7 z4|=ba-go|B?AvGpcC#NMJW`$--K>s_B80rHdR!3SK|w$JZ8GF0TpfF6yfER?V;=67 zHZ{UWFnAz*VvtmQK(Y`LrgcTNgK@16bmLk^YijKswNZo;MRiht{3EOOQt#oj<~uHo zdsyu-LoE}~-??;wNOz;+9fyz`?x-~$@(02EH&4>-zD)rQ`HO%OxpCJnK*|~sXtvS@ z4{`ef&av+zpz_q+qerJa!E-d!Yxj8N=F9J(_-B2rg5MFEu`Yo?2c6#ii$=)bC6Y1( zG23YMh4ZHrx}6X9D-wbo?=X`un`n%V?EP&((e*MPokLHFowEMDTN7eO*x?!`>MNoJ zr5ZaPl~z!URRU;=$*`r$ZUI$t{CD4Q(hf{6cSw8zbvx(`3P(f3_(xT5?(u>7PXUwF zO?_oaFp&=^jB^Jb+;sB^bwA;pqU#l@E9P*PXlFKuG52z+Y(41eY?b4mAzxu@M09OZ z%5(^|PM;UwlSCnENNuq%?z~^h0w3oz+9&S0XMBfRa^`l2D|5 zr=hq4Kpg#0pZ*1%So4O*?ru#aO>I`JBg-_6Rq^ep8eg0NfO8t)X5Fuf)r ztRlc)KMuV)3Z#-?HwY3pNH9Nu{Z<#`5&&XMf)xoQ3h7YI=a9G(=$t$1l>p+q1!3Kc zOKN~~2yiAEJfjGX6YRul!lKf_iXjGy7sO1e;PrfoTpsj!56-v*9FK+?qoIYg8%ZVL zGe9>g4{9|IX1Iq&4lAgl!Aa~}73d)2y|!W0%Tc_PER)-ZMKiSt5(Ok!2=zpOeVz!@ zs}o3g#EOx-Z-?`wev_o4_@XelH*UlrVF+qg1!pt>Ke#7;{~{jCzgfJ6x=D73NQe3| zp;6kfo4;=1XpnRPyj}oL<6rk)#YYk(esYmT^ul;|2&Npw;1vjk4ZAs`3dY?0^$IY1 zA1scb&{qXL*S@Cp0*QJqJb5iaTab5G0MDQX ze?KaEaF9B8)b|qj*Nes4a`{nQZ;MlxBR5gm3u1B98wI3N<++QE_KMad5#e<$r zht4tZSUxz7dSj+3?{nAXOSEF>IY@T8y#H!p6-jdDl>TOp-31OjbPIL3B>zLN(ItOq zJR0nwE>Z6ew@Ozv&4A{zCF%(GJb3#ON5T8FC4@gyz~bgdwb^2^1QUzX(1Hvs#~n2f zfM5W7)#Sh*DquKwFee1*(U7VN0KO8*o#@MrK*(n*YS;`hMMGitnW1u!%H}|-`?)8A z=v@OQT9{+L=k?CM&(+h$>R;qYB||^+=|>xpO4E1mHmbhTXZ#kRo^~N$mjv!^l`hgp z{-n$O(nrnE6Xt;;m=WQBPW}fM;YzZiQjtGI-~1PHnTHerkn)BKmxm=6^ijJ#Py)Ub zLvS5Sgul8E9nx=5ydD0gIy#bGt2%@h2vB}p99G1I(vgE)q!iJd&y}T}7kfouG66`h zqo`@BjzcNzc&gm&BI5pzRG}Xl3Dj*^;zHhNilvvtZ1B)O*~k{U6P^W~pylXHAcx$Q zsu;D3o8e-Akb@Tvn67GQxu22!%S2?n&!HF7lu}TH{Xw zygmd6d(a>=T{pvpi?0I<1SsD>Eo)o^?j1UoEj1o5&z-Rfw0|&)h8_P#?`u?jp@ZVO zAGEcHOw(FkDPeGEsSSN3HA?I)0kz-`FJT6IrzkWU(H|M*J^xpn(X z(dmNgul75Jb31w(r0Cf4?j5OAYNN~$7I}ahFa%_ykwjq;8@-2+!zJLM zCLo83;tO;R&VvK_U{`vrbq=AG00*s!#ztJSZj??Zpbiakr|2kd23|z-exagT|F3G_ zxQnjRU#hvhU8DSDE*re9XyVlg;T<13GI{+yJG;NS1-7er%1#sq1q>wKV`NH+T zsFLTuX*)6)A`Ns(W5T}TQJP^$?C|3$Y@=F>H zeFB%2!)sq5IvF`X*&s*@k6#=)^ZnW)7qMhH7+8bD z2_%?Cs9#0MBR7yi52c%xUjhE0RGy=oR;5;6BKc_Khj6m+CRyP%L1vtX{V5Pxlj^*6 z6rX?PQ4L%!En#d3*i1$JD1l*1z-R=jm}|4c!9&P}xco*fu=`aH3|~qRdqWf9st~LQ zW7J1|r$ce>ke)UKP5{i{wnK$_$ak1byWJoXCQJDAcd&`$@5-YK1Zw35stnC)3h7`zk7Exd{_hZq~q0`pzYG2 zf*Kln?>+K&1M*8r!<*PMiPK`PCa4@Kr0`oXYL08|6%B!nA-_E@e5Xr^EZe`5H3I@*Y*pkQkQt(AheDUAZ1bk4yb_d_=ZR#1t)P8Uj34SJ4+rf5glfvIEkls zm&1WRhlfhwH{9VjAu|>-$SpL|F+nVzJuydZF#IPWaT{6S4!$uiwX`i^P^zkpZXaw% zJ}sFGT9Xqws|05$F;B3t5dBiphH}aOYZ6aV;NptoNlFo=ls z+WhIOFy$OzGq2(KC!p(%Hpg)?lTR8fnW zm5)+s3*fsn-cNV>`QoN80Qh!w)1sj5zk|>#wh-=-reL^Ix_^lytigEyEbx}Dw^_K#4jF_DOeR@vM&Vdk?yBP?4=y1)_&RWP_vdIp^ST3(%!e! zW0$6C{FG&e%1@KR+445;_k3|;6JuKEXLe0!!f}>>{-8))z8pH}P5F3K&x0#J{r1u9 z%f#@p8yw=Oy?XM)__fg;)g_)uPRe?fpDECa9%uN2#dmq5{uOB`8J(^KQQmYAAzZn4 z;LFBTO33ftuD`#D1vasae@|!zKupK^pi{%>A^Rk=#5X#Ln*?S`-&HmHm!GJ*3%W3E zUoYNBonK2n4xULDR83l0y9LGnbx)t^@K-u)TX)Q-0%l`h7Ga)4BU%Rt!(z%|K2>-t zYgwiHyde*9!-VB+uM+zJrdr%D+P&pC&avT`i~{AGw`a22QZOmEEH3;QKRjXLR_-4s z$=n$yqEK5N*7@n&Xxf6}3@!PUps;^HCrQPbvIWq-$=goS@c71%qWGl=hvHb+#nZ-c zf@n;;qwS`aVP*Ntz5-{rxPWq7H6D8FZ<4~3b}pXf$UK( zYn#u-B(_A^mt|X@E6s@fx3x1_wxE!Ddt?$eVqd_G`k`}8Ck`UKyZ1-w3kK`d_N=^B z{(1Y%=%punlgM^Fa!~?D+TRsRv?3zmPq(7p8j>S|S#1utL-5zDC-_;>D~z4BsJf_y z?5F=Ol5U;Qo(Oz!hfn~pi!&8v(L9!b_a!yCjeW`ob%wyjv4o3h6|&9qBG%L|>P)%0 z>iKB1{y>gB`k>O^RQCRAK8$nZ1j3t&J&H9iw>TCQ?Vo~;-SkgWzZrKbLmOWuaegJN z!f_zfoM=yTWtT7|5bjAXWc>S5R?rf|3G3QlLS#u8rj7V3b|`(rhe!~fhymC+4>BN! zV}Xe1r3LV?tRs5%PQ35x?LcUAS6{*T?**aw2o7gKNX@Y|FJK>ZnARw`==brQKkn@I zH=Nax&#%(Yt}Ilf^<|My<9)qFODS?!?Hl#`6OG?))&wn5Wt#?@j;2QZ8xIc5mF&NX z>$B^hE4H_@JdU<0;=^=s9n(*EvcR+QwSFu9P?t2{G&LG8cnvl&;`#7I>U)i)In}wd zftxIc*{W1o-=HQ6+erDZGv|wV`p>e;n(3m@YvQNUZaY4G5Q0B(yk;OEYz1>aQ_hk% zo3PI%eC$iOAbl^>|DXTPJG3GtNxZc!t-J7wZx7H81lV1pk)LvDQRNr!IjF_}6)@PN zj8;mq;W3_Gizdma>qrNZW#muSqy=m=eXu)aEG$zVfS(BW?z0|_LRfqGgES@p5w?7Z zgpw4X28%Asd?&f$;2`(g8;X~3%=>?9xvJ8k+i%vd#SmzFj?=E2xToqr^KcW-Tih$> zi_Vp8AbP)|ic;>Y<@+_R`tvvY5`qn@NQYA)&j^h>w)W`?LW6ocV3aJ!?&gN@BTN0G(|Ls zp+$YOOa7S%>H!~b?|y3-kRcIG#Qo4$Y^$bb*BXO}5cSU;rX+G&5toG49(?AdsDG-$ zHF-#bsCMsI{pewr!im{nv!`1JGll6w4YPfV1UcFEXt9G)EXa=%-YP@eD{XhO3D7@^`Tv3 z*(*-+4_!?(SL${V*XeB%-m3g}*Ok%N$}WEn@ymzu0!@2%1W(^zw&bVho<0Rq%inL_ zAaG0#D#82~?1h$ipbjOL331*^Gv+S^z&-RbJl|Qz{t*!sTjcMNRqbjf^W{d2sE1=J zpJcQ~EU^ed+wlcEIOZT1=X1+%v<%17iZFT~bYm2$vlM9ye~x-_ zx}Nl1<~}OZ+2yb|T~}J=i}_ovTBEU5)QMh0A3j&CVUqY%j_$AW!#(L3r3!qeL07r( z(+Pt^F@p+5OVm-}()@>pe8*7cp;tb0=Wab!Y0S(%pG1se$hH`$T`ISDz10Ag8mOXv zBHDJv;F@{=a@7a6PFGEQo7`D>H4Naz@$$`^4Ry=0oc=pG$G#~0x$Y_KIj?ISA6EFS z_HErqz5NRUd#Oh+UF&ZlmNp1~OrqNEi*cKvMkPxPsKjpk3;|?5=8^JB=aiDJjJ-rZ z;cCYEHeNtKA?zv6L!E9Y#Z3V|?XS&2QArjotcG-?qZnCQ>_bxb!Cx&$e?C8&$in>u zG+TE9;qMZ;N*i=1TZIVJB|<Yk# zl|=L0NXFi(%-8`@K@O~~f5*hjD9^)C*2Co46I;600sNm<)Nz@na`_7>5#f%?9&A(R z*^R(JW<2$}UU<}h?}vu29NTyha_PISLU4BW_)kmo`xdbH1cqAA16D;B)RmXKe|<)I z>nXITNccqmN<{$vvp!_yLzU!^Q~^)QruhutKKs+uWejIbhBH2t`i|2{O|Nt|opA?W z*-(p!20ofNqFiyabA2?vC)M;NE|>7lt5!I_U~u|%t504!XFFwxoU$Za=`UbHw&?d? zLaK7rFRR^o@UnW?=gyBsaH4Z+2uL>(t^1Cs``I9WGAy;d&G2m5lV2C5LnI#06Cd~S zbUUlXMoJ;vmkq&jZ3i=&`Zoc=B^f#b@dEXvZ|BUd>8a6`;<0F`G!L9rm=QEaFOsgM zTXKT{DShYir8dRij3*^DKp-V4LiBDAp7}Li?NwdPDP^Mqn4X-Po~&`c+!#Q!fpwHB zOo`Gj-Y+35=?@Jl=?>Crx;>_+)&%--+;k7TK251!({K;nzCK|r<=#m3)hNr#%=#^5 zO4a#>i{9WmpZtH@ZC7CJeOehv8pCi?JV20=Q3>^kOM@gdoC)n*@<};L!y`uYk8-V^ zN;XPob{;s#kS#NJHN+{DrT0qS3!tS33n&ie!2TXFef`ugrMHc}p|27ot`sDL@8X00^l^rpz+ z2a;i_@k-EN0r_PEO2Je>!Y4XHM5)jLX{#!RTE@xJKr$QcL3Q@k#(>6z7PXAj4w&8W zPeKl_q@11v=S#vvTio&tA2YB|v>&#urkpE#7J~w z;Gz9eBAJy2__zs;*n~zB%rv36Ji=~V+Xt_;gq@mLNN!Tux#K)h92=MWwTQ3i!!VQzoK;qab2!VJ4 z9U>O4dO%X{G@YLE7n+txzaOY{-ya%-ZuE--l-j4ncvm?a_aGN*(M=FJ%-x(b6kQ)( zdKB~WdOl*FuCtk`_&~CVnrhZCn8gNw^a1WO7BPh0yFZ1wzgcNW{p8XFPE39}=bYTB zysX?&&hL!2#spUMCRF%}@M2${YvA>Z7mF(8^l|fj)AN9hG4Z2qDaC0IOB%qShCZaA zAKvOJ-|eWCkaYr4eY2{Z$4|Tea-ZwDTDO_|vh!I1e*vDyQ;h&`kaYUAv2;J>Ze)o@ zhKJqnb|+og0ak#gSJDK^Ukb7$!6IVUI@sPf!nDpM|a z6FL|rDa}jrLnmvQcP3jfLP)8hW3V(T-~>VKUA&SqOhuBCCYQ!M$^-A)w2Jy$m}QW1 zK)Gm6AH^KYFGe#A`@tvXSt~u)a&|r0HIa0ME`*Y~^5iEe@p1cFp1>3Gp&tEi%3}ai zSjMxLg=PJDhyDUqm6rltFhC7t^N2&2KRoF(tl zk|P@+mlzpxwB2EqL|FJ$?SxDp=M1|I`I617-P38WOH5m}pL3qHTyQ=x5+GNyo)rvp zzShM&vzf9@mWEkmU%&Vcc;%!5GPDFY&+_c@0NJc7$b#q4r52Ay@dh~j%q#p>2ReCqHdBte zE6rzLi!Arxow7t4q`0yxw?-;U1sYW;JajvaX`rn4g}aNi46x@V`aM9eR#)n-1Mqg1j475Ko1?Gw-|c#6DkQ#6yMKq0@Sx01(hmbeyi&^UWn? zvu-P2N413O?s0m34ze7R7DJk6a}dwAn=3)B?8h!42lYfGywro5fR?} zXU&?KFY|5IyXJF}J7?W{pF2BeU;B4Wa!;|x)6=vzjMQ1nJexSYo9fC-0j_i*y95p^ zTGnOSBuSddt&Led97y|-%DFyd`UY}`kipM3bDWTIzXJ;6$`fE75X|Gj+EwJf=n&v@ z5mj}2W8?jhyr3gAjyX;xxON8qYQ>>TE7%nU!C?; z@6;}k)a%X*6YXI(!4OyY1|lCTgeee48b?&R|+(e$?Ga}$=)nV}*%hT_`0AByRW4_MOFWJR(a3Fr$hgEYR7slM z1;0rNU{RrS98W=-^$Hyht3$|y0p7IS^N<5n5trGyC^F$2?4u%;cB~FDYs}Z^A-eG? zi#CGP0R$yd`WrJQRX9OSSGnt;&@+a2UWyz$#helW@@dRS1W5avq`9G3wqAT9sdGK? zBn*(j1dH42+jF6`q5Oaj?naXQpZ1OT3N9pzIzGdihEw3paQnlOT-27}a>}BTnQdJG zNk(K&wB!kfdln57*xMLq-=^K2UC<{WE4aXAGDv+FR0tqIe}TUB5|zSNq)XWlJwEDm zmL$5N#hgX-F#y{JvD^bq^QPYoy`Ezn9z1+I;51{ndMy*(<<5hRxL|8l&G|uX&oRHrAs635ff}6 z=1A7RFuunzAfgC^+$t?hCfs|)qIV>@q0XG_#&Y)y_D88ex9YP~LA-GxZ#X<{Qvn== zsCFlp@~o#<^$;}?9#JAq|Cx9)PcNqE62hi3VtI347~w_zPFeEjn5~gSO|$zF{l;iB zrgx4^W*&s;N+ZF0W@+scXYS=jq}k541m3NmM%>Qu2!T|u2FBUwFY8y`2VqD^d`|{Cxq=6mmRw@g=J7o{1V9S@3*WA5F+l~rWiZDjf z!dW59_Che9#U8I3H&jM5k<}ev0H+pS;($={H~rSfII}r!gEGS6YCO?0BE1l9KE_8% z_c`)7r_y7Pkm$^bn`V$`Ge`t-qEkj#@)qXs^(phaGDs8v(rv10L_+el5%gXJ(Y0#_ zSX;hlSy8GX&$Ci{`i3l$0x7ThvUiE%*pWjV?{6&*Q2?gKrohI|cVJ>O_7D<3m6jPX zWt`sB@jC0u`_Ej6^bb2B9gEx12ncqU@7%iPf*&MuC?uv$dQlG?wHOi|hqyep9iV$# z@=Ruw2;aC9FIzl>XCr_Al_qLqLM`oT69-fFVMfFu%hT$woM3i!C?vell!a$Cg(g)l zvUTPN5(Ni8eM&B%16;!^W04_IB;qgc?dH(Ix8g^)%-&Q@DA0mUw_{i~q;*>G+i<2#|F5e9J zZEsqjASe*Yx}Ycdxymk8 zLc1{611rmN5t}Suihideb8oPo=CLD)N$@85`BHeUz`-rZ{y$Gh6St4Ep6$+?n7H&P zAR8ZoMW^U@x}9HL9P-5%7riglWbYtVWUSBeZJ!W3D|mF~g&aPY zUd(mB9hMhe2&ruQ87nfnuK@HfaJ-OC@2SBIA0&zXoU`+DcH!?j00bG$eHjUPmy#iIxp>7K`1f8` z!X{DO!)iDIqOruWcX}P*rW>!Da!?SI;URQdSCaT`Q{~%%(7$L7@tD8=rKtYM)SUtw zuBYJ0XL$=Gv`@KD1n{!cEuPfipVLbqsTbL2PJ5^D7adx?PXlBrk;~HN*_zm@rrEKY zMoszXb%m?^_4z!(!BPfuV{f3@YIbdVv+eKX5a+xl>hLB!)e4$sGj;JcN@!8VgC5YY z@Ago6&^=mz&(hn0nBb#z^|{CV6+DQ?)ojB=Q-?a%3vsq3XPlJ`_3a9`+SooBXrJYy z90OSF-g~xg^~7Z#VorrnT|_9gl=jLp8(~ryQQBGFs8jq++649kD~RrywKx*i$@3BR zJ>ndH-No(((|m-8(Ju|6XRBfBrf0`Q+N=YO;q`%zwynO@Q1fLYN30OKTYQFJ&;)BD z>bvqNANmyBlJI>uGt*_EPQW0UPL2lF7gVbipT1xs%Jdz7p^GUV>s+^UT$~<(M)!uZ zgxWeVzr4`vnfb!r{d~F6c?I?Waw+#!yrDv78l zf8;1+Lhv|Xu@~n)xtS{9>`Ba#c0uY?c_~3}TS{uuJ&Wp-j{|envXAZ8*<#x?CiOor zWUWmL8CJw^13(1y1$8w9tPZ194@>daub*O5)`T{O9CEl=Nh-EHaq5c#3SUp|xf zNzcl^FYBoAlTP3>`55FhWZgZH0)Yijp&%DME#H`l&HhEzIKHwBgPhojdG)Zlq%C)R z&6?V|a8iv8?eH#rVaf~=xD>)JDQ;3#^<(Y>o;BJn8pQOh$KTlm5uy@q$0qqMbU@mt zWcT{1`iH;YJ7TwkuZ;h5kxiXY%)NF%qnaGwA9>5N(Apc*KK7l=W`T95Y5qu>dI?kJ z6yVZ~i<;DycM*#i8JP|)n&9>pi(uE}OV&gSKrdG>u)T#ndBC?8vNPcs;#%|>P#taa zpVkEnFb&BO`kl-wk;Gf_n*=sx5&7?4OoF!M0e<$kUr1=`s>$YjRMul+&+`d{999OV`T41qmj?ICk+y|L~eXq+H@7}saz9#Uao9! z5EA5O_q6NTXM*J5;g{Rj{|5_j|D@Ze&z7u~kSi0@nZ43k&T~3A+7hL7#oW1~R&${BVE7XNZPmx<6;z>oMNsCLdSq2zq zKmDG}5cI#pP3J|=dQ1E+eEIHD0QJNuCq-=ig%O=EW9TCy6U{jW64M<%Ydo6BX7~zn zhd$gSbw1m!N?Pb~fXRU`?#xl#Me*e?|LygX**;B;7;V<%2Z-!t+aA}RxZ0#gtbY+L zvONpKI0L=cy@OJk6FVXC-{6i2)&A8##mpb@lPvfk4AlLBpRWD+~}rSYGf zPv)y7YHRcLTc+|SNf%-@LYJ66r`sj(TFNS4+Zeq<;ZJ@jc2#cVVplxyd>M=D!_yP1 zaFFq)dWG;j{bO3-xVN-M<*2Ki#@&r^f3(J(nJPK0$APbJcxl{yzaXdceB*Uksz%ka zxV+w2;6zkHPWgJ3HT$7#`^A5gMV>Xl{}x}!-=u`5r|Y5HEE^p zbCg0#7zV1nsxkHZOh4@!rKIjyCqEG=8{Ct9D{et)mgTFHt!ebH$gAJEK(~S!1F4xau`E`P-p>3URX($-#tbEOYWFT6Fb3aZHUerAe8f;6D ztA}2G81`rivd3%LD&-*WzBUJBPk-^?iGy{7f?q+H2hc6O@M{i7(&ovvIY5v|ILh{DS^ZPhCkebH@AM9MEd^?6V(*BSwOI=Ghxg5K?P|ozw)zl*KIb~*?h-5^1Y~WDYa(zBm z>N+7-n(kULc(b)-c8CSbU=z^su9H8#ljOgF)HyL?{($Aehh|)doa+Z-k^L-n@O<@AF}i7MYb!hEL99{N9Ho{*S?oY zeXD-?98jbLs4h6EUYOIL4B~tZHt1&*RZ#AK z(_P`*Hv$VN(|pvo)b!ztc+X)rUbIs4uxeLYhjY&5OthK`Rejgwk#o+19!mE36=I5V zVV%{E{!-2%Re+W8f0m%Sh_^1m%b9`HD~gm)n_tQG1FMpV!od{Z1B$X4<@zo|PK}r6 zEtg25$Y+9Nf+dHWh>nL@=bcBC6jIk-F>%R&Tt~FXq{t8*%N|XfSF?w4u1R!)lcb#6En>~@`XSyWU3U} zw7Cr^kEAG~s?P*dC3nXB6z>YRoSUP1tbBQDTRNonBgF(B9WUhfHRo{BUcPpGC*w{6MB`ZEO-^-&S5EWhw18MScepwdl4Ij zN=0R7BB%^}rtvIBKOBA4oynq}0rI1wRxmsRXzT=2Mc(E86$Sy3sxyq|lxEU!U^3{T zYzEI8^0FAxsD|ShV*sXc9mfh!)tvq!JV(<9NJ59c*km&V8`ByL=@=b{ z>heV|^8_A?mkhl7Qs_c~@u@Y3#3>uhBRz@~-n;EE! zf0Ti_ld1dKtBcnOrM@GV_B|n}+U-qJ9-Bonpm~+c2!dXggE&XocGJbcKV)#9J8c3hIS% zuzvrzMjJ-I4eZ&7(GLh!E6l(Kpmcff=$$%aw3`W>s^AZX=~{~ftxPI|(`nF;(T1}U z>`WeYP_@jcT5Z$|{oqE&91a{c^etHTn4p9BV1%T4CYg)#LTf4Wt3hJ8OtSi{m_Yzo zE3-1miL#z+vRaQZpo8-hOd%fM{{>Jlq){)-5_F?cHNi-=VP!)cK`RcND{ z-hM(@>%eH(C=!e>y?NQ7=R?@1%)kFbMoQ5**FjH;aQM4yC_jD883N;RTi)3G7wh%2g9tXvmKGc-GA7_6qcbsa9a zf$+h-n?mZyoU=(c5xLsJed<$`r0&e38DiuBLTXV_&D21NVQ*#ygL|kLMunq`3AH6~ zV6X7>V%b#)OdK{knllrekJ}w9O++4B$X%MZFoBFeGGw50cU%4~F!pKy^ZABPE(Cu2 z9r-Ouu}lIxxP9#jL645_Il*k*QAYdV`fh=r+odJlB4{OH`cJ6pncJO7WO=6D(?P2K zF=5q@K$>~6;Po}IJB-ER(bI#*YQ^C8kEwmQ0InY`6-H%+%c@)t2wJXSwhIh3RvXPJ z$f%8=6M)g*Ez_paAV^TsDD_h)re%SkQE18H5mscPrpxMDFu2zx*VpriBYC zA6fhI15nl=AeBRK>VL?XTh*7uN5}LD0uD&#!fVi<*Q&yuT5y&iF3MZ+YFY(E|*K877hQ|M7p zt?PPR{9WAvhp`-17^A8?;C&s@`u+QkuiV79obT#k;B-7J_W?)r(2p9bl`m3o9X;qm z7(QmPZNO`bdq|D2i&PMnl+Z_>K#jOo1-s0FX;9-7;L%5da|Y{~!!Cs_v5Wj#4}*Cu zPhFTbSr^n@-(E0F)oO(m#Gyp%P!%6B%;g(6izuBdXmO9HfAT)a)7G@>EFf)omR8Kk zI@zWHuj7sp<<%0?9lF*-HcbHue#0phH2eo*_1F?Ipiwng(Qek;?}EWZeUxeV+=T^d z)=P6{U8+$g*g}k81c(s5M3!Fw|L2PoX%J11!JW}1Bua=GxHW3|kReP9hB&aG*rIL# z$|o8aOh9QLU;k?RUL3M9v(Ua(DmbrAFlq!#MI$Xb@p>y@tzdv10>cT#2o7J9^|-59 zh4bOm5_4718jln8nCl__=nYjjjw6sHn3{ev&MeB5CaJo*%sWIg!L}jjsRFv?00iZY zf%Y?NsITdeGx`wJ3RSR|a%Q5;*7Xup`+RC&G*Y&1Q?(9h@eRPzfWd*F1#A_xDc#BX z?&2%RY z3^G{2Xr#y)SpuYnrv|@%GaOdmtinP+P?bpQ5eBHFo=5NOG#xwYioflZU5Ylbo;G{jAkR8-o>b1@Jp!H20;@u8Izrovpf%A#_WG8zeB)_UmQ zLuR|ga0#A(B0jPmum_DYJQFE=Z^%rVt_H4~W6ofOYupE?3w=RV0BHoKMmUZo6R@vM zbsjOl`dc}^2f!o(-gN?1Rs&q4{*cEf{AE%BKrqvk$x)up{t3i2ee8SXcfW_(MsN)C z)Qd})aiv;g#IFLW!vUKVQ=NogdRY+zeWsncea%k80t(`MF(>{eDP;#Hc5GUBJ zjZ1spA5HyMyrKVI+p!!-=6Ky~Kg^;_&Dlh;Bwc3iLF=axB0k$`n<*Yg2#zrbEf!QJ zpEM3LoQB8O5kH-pe5i)z^wy;pEL{*om9xnvYz88Cx*lB8H)Op)02`W7m_!zJ7*p1H zSBoFHGN{5vJ!Vx^$izfyN+nfBScgmGR~IVt+^Hj=0;G&BkZJddvk21lIyOYR9-$he zn;9hfVc@H1oc01$*MSieBnx>!cf5Hnlgy_1PopX^_rFWJTRn0Y2?gLk7wA;&I))@P!443!6GMmR=WKcG#t8CexFYP3?l_~UVXkQKV9#Z|AG8z#GCKt`9geXT zqNG_;%YG{S@YLGgC{ArMDCV!zV{C8a*_nG{H$y-4#eb*#{3{&p zF+^Y!)=mYsrPqrPnh1G?VC@#gxd8d+Pa2(@@@lliZa?;9u^XD@IQ+++!ek4J%XQV z@hmsqC$={5$lxzZTo&mGA#mcd>y0ZG+b@A~;cn5psc2R2k+ z(T@uNyEtL7Y1MWfXa5UtgO94h?99CHC6>+OhKjnECJ}rjdsw2C}k~I)#sNqf^Y0>5HEa@;71jX2}>E-zXB>+Ov8;Y}jH8h7SGL zkXs$Rm-jYy)pHGMK5=?TO67DtzL@5V*iNN$!OaL`*4ULN7qSsQy_&f++Zj&wSluPg z=p9dD4XaeVzl6OznxVBi!pZ^8FT0Z&&7AdOynOgvr|pPDkiMW#b$o0IjkzZ3vTd=@wPucU&lhSv zUnbt!EAxuOK@4L{3?zk=82ZQJ$iBiy-F$N3dQkS9O))6Y1bf}7mZeNax@Ns!$>fg6 z{jKpdxlmj7E1J4P#bhZJbU#(1>u@GubWzUB98#kt*v2$ ziR5T5(b@P~f!uLzUpRwDEuKDkdLbl&1GmU8+}pLR(UJ-0-LHViulzLG>EUqC8-L5f z?US!iar(meH8T4RK(6hX$4i}WS6>>6KD(VV1>$V0MX^`e^29dhhkwMmWk%~1f$w2B zyf?^lHmeMoD+>0zhZ$gvgM8ko1xu2lhGz8JV*gYE6cq@1tDfBYsTju0uP7Hu4)121@L^)b;uv={O#4lJ>8RPOclWu6y4w&mImq8n1V9DRuVLMa_^Vxta zns1j5DN0w29IHDYy>$_@d%5rsz|pr$)W3C;$LgLMvkx!C@MOs@=@={#KYm8??%kG< z7)xa#)^|M$hddZlGv4e2=Uju@!b`!FTW3O-B|zv&Xv2X@;NLbI)b`k$eJYO7T!HNa_DBbtZ}H-|5zsdigb9 z<$rf)rT!w{Nw=;&QLF=M?Rs)iZ}Fw_3kJuiWR`QfH?`95UNt&XENzt=CROk>D=%nTe)rLuO3PB7ofak~5EyKQLQXgI};`J8MAAiitRLvfh8lw4CBU1rv z*f*V%aQJwzIaxSlxv;y9 z>SpM^&GA0=+XQZxsRh9%Gw=wie#s)X=TkqYbLN}E{KWOtisW6GT5;tm>sZI3q*}fl z^rdYhZqG{Iz5VQzOz&;UHfO!gNPhp7EphD2w?a#S-JPmeLqdF&mk)X;mF`RY zY`VW+`qLC@!04C23X_=`D#O$YDB{=>BRWhetcnbT){1fR`rC`m-$a6*7W}CEXDE); z`3?T-JFzF}0bp@0oX)RqHZ~~Cv+wmYatyERC5kq+Sp^19o4;t>voEk~eGFditi`Ao ziboX!Z+;>?T|Y9Fx~#i+C`bB*O>;CJ7X0)8-cRBT&!^7@xvgihRFS*ufaq9r+s$k@ zZdS9py!Xv`)SM}zWJO|ls7ktxlT7~bh-slCjaLm^SuX>Q9y%>O!YNGn=-8n;w5=gn z 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�?;Xyu#4Ryu&wQ03VL!t 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�NVn188ToQO(~Ew_G4aO|GvGoJ)#sYB{- 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

>kGxZaLz3Gz8`>_pYu^4P+&Df;O@_3a($UX|hD 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�qNa4}a4VkYmhYOxo6$yTyk;Us)YhT>j@)1Qk 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

SMS@r16=nDsg88gOXcmrWA*O#d#l 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�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%0D0R<@_Px3to)ek8%p$vilR5fMQeM`;kDybv4Kp z<#J6ynctC>f#6UnMu3foB1X|EI9a-GKfqPtG}!jp_yu^J%~U=hftd86UhYF=(isdI z4$yR}%lk9{JJTF+X&aK045_p}rT)_L(8j*tJ~%)U%qIg1d6j21nLl)3u`E#Mcc1&W z;!hAyt9ZgHRwz$zUKR1OU}j|blNtf;(KAh)eC zEvT3xItH9~@*Z$h0Vre5ASNWhK{vUJLy$&u5$kmYX{1^u@S+$`F*|40B_P@_6POK-sJS;esYg@2`M%)7b*#W^x;9Y#1B3meobn_+6>CloS zH4tKg%U^gV=Q$VfK2q@G6*G$H%3GRyZs4`p$MPu0G}zh>QNZhHm^&I|%l6+f<*PH; z?Yjo5io6;$T3{+dbcSy;$dHr&X+In9ApU`9k#AELRWyjYjtOwTbturwR&`$T3q4-ps}u5&5ecu{P59l_Z_ ztPsUpEK$)&aczV9D`@df+nff>eXZ+=TYDSU)*BhyX0dbPa5uwJ7=p6?;6Xk@%MQ^nDd{DQunaR?MX;dLqlN4XP@L8zfKZLv+(1cN+Uo8pYY;z+JRKYyT(28Hg@hs5lL1S9a^b zhD4AaHa@3{IuFXp8T1;d3(@H!=XGgDJsn7Czb?iPv8{7NPYl9v17dN$GeI&Nsle(C zAZ$H1TU&#i=zG*t>t;@1N$Y^o_EYQ=YHtb+ww?z#;@g=VxTw{!m>O))1K+MHfZ>3F zva)J8=p~j&L!EF2`;1g6hzJmFK#QCwLEBzRO5>qrbI;5Cp(g%m0dqnTb7TC~vESJS zy8c4BY~gRM!pU=x$MO0quOlNm!1e%06i >?(jrzDl0Z6~0?1dLJix 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 R0YW6u!5hL{Hd8=4j9XaW1C<&cc3g423T_s z4w0Rnz<0JzSrEh%rmI~i$LyZL1K8*afbA6H;n_5i(hlTR_i+h-l$=Xv1-btF1d_`T z5;CwMPz%#TWQm2ck$pvF^{uqtrO)@ZaNBw0N1Al#6y2_SA|ms7etdC8JPRsX1RUXU zo-;%&reUy2&i;X0uKNQ;9uxLaCBR7F(w<@5| zSkR{;cv4f;*$5WY&3(}DwrH{nG8GUHK};34eZY!F=;MzLtkxJAL!wJaO*E>j87g$iy+{2X1_0Ig7FxZcx?ns z`Zd0^HY#~joWB4GrN65spf+0vE<4|H5*@4}4jTXcFiQj_0c;E8Uum-Y>$HhQmM9(- z_S+UZ!@WU!C6amb9qE54t*;{8MZnJ1ey_Y-?+v_^M}yTmB8sOJA!vR7i{Y#%HKp2j zP$Pe;^dzk|Lc&ex^b*8UbCEXlg^$b?jg2{1{=j$Wj~Rn0AKalBcOZs$a+f{I1}Al{}?q9So7-k`BRygkn+077r2cE*-#w|FM8uYy$_WsAgYiJyDdW zUs~rkkUVhwcMLS_&NF=|x3w4e-rdd{VgHqUjW`L+<|4mgrHvUPAyleo^jP^8YMPG( z%_9(}9{uR@5JQ8s$iTAz@h{>M*XS?`7i>DGFGcE%BS&b)s7q!{~a)$kjy4%C!Nn{ttDzPpYC$G>VbDYzH>}gm5HcRp^NN zQK{BvkD@5zSp*ODMoDh!dIOK{z`GB4b-26rH&lgPIaZpxAvV~I+!r9`L_ z4r_xDKU=2x>J5Eh(0$;K0Mr!WQ0)2o2zMa1O{U&sbID!A&{)J>e zpS1~}Illn1j6;0^3{TU`BPO^ol>0~C@@&urZS5Zbxy7WL5?|ZIqySP_F7!#dxzqt* zHTzx2%*h@xRP)3Z)4=$U@rR9bt_k6O=9U z@4JJMzAt|YkkA#D<80NztvyY}f_+-24)y?m)f0=~$q3v8?8){$_Xm$@mrIc?o}u?@ zctlW#396U?Ea>C(0f1i+KIW5HO?My*V2{yL-u>UeKc5y{NA~{9+DE(7B4mfD(zRJ+ z(d8321ypeZAQ}Vt@5b-7j|XvjZZ7=TqwjAZG~K!;YL-qzPyL>%H~09F#!lqx#F0dW zZ(PNV_l}EBHwUz*8H9|NUbnS}hVFF!_dkNi@2yV|TaDla;176%{JeO90sM>h3H0|REb>Q=|*IFs1 z)^y+6blnKe@rH}v376Qr#Qd%&6;Aj%+OO)-nxgP2Qd;BsW8?U$_4c0s6a;a)afCyCU@M)fGF|Q&m*un_S)~QVZXcOFbFEI)@IYB zdsQ>$7o2J3)WY4!Z_gS)Bm}x1AAk1hGi+~GZY^BD&OXZ_>Ra@%cgTO~Q4R2L-5LnxvYj|fz%(CVF zv(k|?Pk`N6=&r!3=6cfS!|KB}i7|&%4Lw(QCJ9mt_w0Rc<*$Oz@oNsH2JtCS+=WV? zYqwFgoac(7N%c>v;>Pv$9^Kw&7_XGfNF+=KeCp2llsrb9aytCE$gxOSP}eVVcC!r{ z*cdmWQ60)D7@f2^MpC_*I9GG1#8;QYORKgi@5WgMeqg6+&95!DHrk+fWaf64ioD;WFBO3gC0v|RLxi)naeJ80Ptz`h!Nsyc(T{W)toMh_N8 zb>*AdU{z58{Y$lC7W4(SG@sgt_lJ)Z1JCkTKcCsqxcmk0HyT{j8H!wITu+*6yH3J& z?1o}B{RHS5>`kX@&kNpJzghtMH-`*<73*++TD2%hL@4bWB|BD;+1ras?@jl1@}dr{ zhjcCP9o8GT-o&9MZ@K{y31ok-vv>A zs#w+DLl%EGm94l-Hr0ta5}stqD&sKxE+|J%D?Lvlo2&SHB|{XxU3hNZ4*S~3L$Z6O z7IiZFtkJHs=~_*JWbp*{J1cXT0qIt;Ru>7`Ib{7U8Z|??C1p&{iTC6}Tl4MG)s&uE zjsK|EH^1xBcze=p@5;@XzO=Y=V~51niDlA>t*)`)Y03I+Yul6{{OMkpja)nDP?1xp zz#v=ZLwX!b+-dNToBQEtjj{s6ST)A+KbcozKR>uIpLS$(mC+OyqU)(`h)d}mHsehe zn8}>ee4lePy5RnU^VYh7Q%PPfcj}7_=Oe%uMxlJd&%5;eBN~bOoS0!#%;UnA;Rjxj z>5Q;53#?1hq+)cNy%9=5=MDqG8jD8 zS|nOWsfg+wl(;RF4!8u6etHmog{@BFG4BmaN)!LoGEMnE@}$#MaaVm{B)ZCjw?x-) zmkZOcYE4a=+g8q=Oe-XYsHL9b4&r}@1(+rkLH90k)xNGkmFq*hC0>7xOnfJJ=V0i0 zlzSyutr0kEJ>Ji0i~t;aN7vw{e)@Ohi9MwAm@?qaP(fmoZE~SX(aJZPY*YC+b4^0} zsc*Ex_=Ge}die-to;3KBUIt}IT z3mLSa|HeoXZsEVq4lA~_<;Qoe*{%-`y!k-Py05f>%VB8*&axgS3TMnNRu&0{A!HHg ziLOEQ$Y_iL9y84qzaHkGy-yS(J54Rem0oq*ihjTTK~;H<XIXuO}x~k;mh{pDdG1Uwvwl=dw4eX4$-_AveLs}d`#Ijxs8bC3Umau4`IS7IkdPrkl$#kT0Fl}=va zq}Lk3vOB}&)AN0yCbFT`MrV#wZo8a`|9NV1BftC1`rx@K+Z(FG&GGe;s>%D$n283L zjm%%~@;hm#E)sdD;ZbmH3;c>AHet}>n*p2``Sp?2ZF}pXqKxP!A(-FlsLm=vosA`k z1fyYAd(q2kA?GwqZffY)Wn`ZBjmIT*`5yS}Q-oAIA6`|GbELjO@F3t6;+*e=m|XLE z(X)AA{OP(cI>SGKYX7B;zj=^pQ{Vygd5efjT0i!Y{il!XdX?_|M5o!{=fB@XclwMZ znfSRMsG|TrB$ceYf57rtX8}^z+#L6HmJ6qMtmS?W8$Rd&5aW855AAkM#!Ib>53d0d zGv5M?zX6d7F{7Bhbz5=IiKZ9cL)5CDRib5W<>6m$&2@S!NBHI<6Six>nw+T{+S;Pg zc~H!OI%Ld0r~KG3{}nrd8~7L+V$86W8+UNPYU!uphp0WC+SksO5yg)MTdy~}r=J|Y zW9!lC{^>x+NW!wmhqTHQSIy^Z%yOpfi7``ICiRwg*Wcx-3x1Uu@_a;Q9#n~YFc!X^ zzVy9%Ul~w-mLfeyda80O+Gnj&GGaz3J+(g)cSSo6#-uoBp8q8Km3ORgjMKZ^T{ZRn zd;#tfS0Yz1B#nOoRy>aG7b7rolXzXTPnv=Yu@8Z+f7(lKPCdJaZwfw;x1{`h$EAOk ztPn)PjJ8A&vo;nGj|Klp@6BxD6=cn?)S|dM(l>WmJuK+-DTR;3TH2b>;>7Cvh$JUu+Hm$C z-cooh&Js=o#sgrIBUe)NGjJ9e2&x2~lX-sP;4vo=!O`*pgL9J3i;(1C%} zGl9}X3stR*IG;K{UcN~Q&EiRyxXV-y;qzOF}>U!oHz$h3N8vMrQ8w`&DOl zCHAX;i^2PY*cktb0g`_1&&gCh9>&*+iE72&xWyFbK%^@&gLvIlTl<#@7BrhB7mm;(SOlpvJwzU8+rtzHueXSEw0 z!1`Lk6EkWLYYg26%_Uf!E0x@>ko)&8NWJHPq3}$h*+#|!z;wX$zp?|C6*k&nQvle| zBFk_kBZ-umbG_JSAAH}!Fq{eiqf1XswqB-ZnE!#HZrJycnBT`RJB zL0!9Dv}L8xe_?nAJp$Xg7D;oyWG;6AeNg`$31@jQ=zdvzms-syIg{kaa~4@v&ITma zYjsSR6CH4`k`bkL6XgUEVx0n406`IuX2|GYPf$G9x^I8^&C4XFAzk83t8{l*1~mP^ zb)TVBdW$Pi3wPw-`t-~&MrPAwdJ+ptFNe+j5qD)`?#%=8(;29s2jwK7rB7zu1m#o$ z<4zzn9-zMSr{DjaHfQ%ixuI>~k%1)+$kZuqZI^*W1ASL=yUj(#gR!C$&SE=oyUZshc?l7 zN63|0{0zkuq^1x}cF$~J;9Z|V z)5c_@_%%5`LxPt{_wz*M#3r0Yd2YEr$_LO)y}-=#t6 zKkP7c_!)8f&|-bdj=RL|#q3jzHfI)~@GihMEHhaj8gau?%}V9Z)YD{YhJ*t=Qt6tw zP!%nIEY2tKv!Ou=1xOsmW z=k?ks9X8TQdsmbJ7k!1u0vnpVx)z*SK1P1ip5^Tew=bVY(m`3Do?Xu?o#cwxxH837 z(gf2<(AZ72n=DIAP0?jQJ)GYq)^+7F2j)Z&yIub1&ZirS(Nzd1X10DtSi;q6M#g0- z%)XqFRt}*0WJax^IV9$Jc8M6jD?35o?&o3ib-0-5D=})x!5++dTi;Q@H8T!l?tj<1 zz1p(E&5oVQ5aZ^;3F%=8(3wH>yW6m{JB<4)07F1#99Kk5q|GY@W~=3M_Fj5O`<1#o zW6!M)Ue$M}v#@IF-hEjapKrs$_ou}k?_)IIIYOB?4~P zvjBMWOzz@L_Dz73d&Lde*Nr5gWSDz6z(kaO>SUkn!>`$QqcdRaQ-RBhv*%!fcowA6 zf5!4Z*kP?Vehh}qz4S0T)O5wx&*(+`N*etqNqZIBAbLV_2XNjeuc#|4%_qN{#YnjW z3+9qLO0$_~wcxAM9Tzaq|KJn;gSp+h`aaoOo|Ee@_UbaVB$0$uXUhSM6t>pN4x3u?*CDA-|(Hg@hzoNk~Yg z<^JyP@AJoboX_K&^LTvTpZELuLZ_u2lwDMT@3oR`scHVPV(9neiq7<%#|`(EmO>w^ zJCXt9jp4KJZ!x@`m@u=qNRmz-OF)VR1`p(QND>?cipjgMI@ZKYvG{sZn#W+)D>v3U z(uSx|0}MqoFl|>Wjb3q<5!Lq^g@^EIq}yPaCqa<*QkXq{p4w~q`~g+^etOt($~pKN z=31({DZ+6DafuUx1%Mr6VOKHyL2CW1%u;ltlwW>DrQv*iY83$@oQr z3SRNRV!&2!V8p;@li;zJU2k@+L@ogey+(;4J#DX^-b@gkGrg}cn3ocNJgSMI=u*>8 zBIh38V+%}$MZpaXT?$Q=t_sXWcCF8J{xi~;}~=svjKL$htX7#j%H#!zs1Y4IH}_oBDkQzErM zm{s1Y4K_WGC>(cxBAkTR*a3LDmb%}k^x)i*Kxuj8^ux^L*%H_#s)+PmSTL0$w&+opQQ$Nte7aNuQ9S*a)W6T2ib|zc0#Li>X-C=#8Y64`daJ!4<4$^S|FF7nMelZ0H1>2I?LjXK?Z3?_Q)->~=iBswJTRFPA z@a?dcfCXC2>2!N)@Fn<}g!PQO7edXqe9pVV_zug6W%9PJK4#eTL?Wy|M32OIk$yGx zdw0I9`%QOE>JM;crr2;78H{9-svX3r<8F$5EeyD zzx;74=Q#5UbDPz6F72lBm!6_;C$`=9^VRg!!?+;{!e1K$w|9s3SAojW`)gUzynzo; zN6^o49qAGB;1T7VfYJ1;vRD}da9JEFy5auEkY|y#Hcrb`5e;8s9MYp2H2RhV^`E7m z*cDK)X?ufOR_8e20-p^uX4j@TYy0`ex=p!}af^&sENsf~^yr21WFRR3X1^tM;s>7SQ9A2W<4p_$|wRnamYv;eZEvU>h` z^#10*i$B#khLhx6GBg!Y%Lb$ZW87rZxz!BZtl5j3Kf~W^Vih7u=FnHg$V!o}Yx_rS zVr?95(#yC`oaX4W=nA!gI*D*oMpoL_}FrZwc}#2z%@%Z$lD z(?z;sA=atei!tq+;6RSE^AjKxgO4m-Y&9x_2s&p_T7X>e@nG()d-Anz^>S1|CNt2Z+>k0 zzkcD)m|lV4=4>Bun2KgNjOo0veUqd2a0Q{@K~4@Yf}Xrakotg1yspQX}_M1jg$*PH4WGCwZTp8&wZw6S(*L3)-AVV)s@@y zdsdP$RW*khl70>F6;?0lwXynw5)*P|L*Aa0*_c4zlgUFQ`^7j_JOI*IVbbj@f+@hro z&O}EH6#k3il|2^Cfno zlR~Ki&oypr<9~6dPglEPG&tq>nsJ|Cj$0;QX^x|xKh>((F{#JeRV?P4U0s zt0$~GgXrRtr`DKr3zNGKfc6s>T_I}H3=q1!M$$$`zWK~|xe~~seaO`j9dUinlGR4p zOCIrs!){uCLc3qPpu_8LaXY2L-)Q`PxTnzJ9V!z*or;c_yaOD2J5y}_ui6o^_5fqI z@LO)papQK6>4SKQXS+dDQ_te`4gX^mlxxU5Cmdly*sagNwY-#i+&GfI*quYFkq7~- zz1!G$bUTt&ks`c=fiYPr;g1ziLqUn>u@8DZ!iHFw3+tWcXX@>32Kf+d)74OKkfp20 zBCb0DbMiIiy~F7}^2EC^HMybe2n|>ocJu)>3r)!b`KcX&!s+uC)5y zk1&Jn>D**ojiji8_32soQ){^_HQe8Q0O|A$h^j^m`S+{^V_Bj*Smdf`miaSy-p9Yo-kC<2r-U({tbJc$1x2vi@~-xph^QsJ+gbiOpi}3V)n4vYVfH=q2#h|a zO=`Qk{03=bg#apK_7=WBIWK5zURVlxcLhe!9pEm*rYeQ5vR~At3om2S4R%*i6x~5d zG4+hop=&(Vxy=`Is7ap`+t#z@( z!2PjOeE*%Ss2CL|Ybak7ipY};R|Ez)avs~;@$&*Zx7-edU`9 zp`Jf3yOstoIF{#4EXp+B8FNju4K-!=;h%-lrc(7_Uq-}-PP3VjpmNgslRl>}_>GB_ zzgz~3ywGlB*LO&3jXu)-*)ekE@0;wz6)AMgi;5~nccaGE*t@1lzo$2TucHuPai;oP zZm`dq^kH4>8!cUOGt81CmnilFo|2Qlm?ZC@G&=(R!FumssPiA^MTt*8$`k>Js}0qN zvf;DmFHa)^Xoj03n3NK;6&72}`o{?xi)(;jtz*=_uObi|U9x&p;tM0pw89*1H z(&IyC-tdst&@bWL6*|VR>K=XEzVK+qkLT6QeVtU9BgeRMGje+5;CC^&rLMus6_E%l z!_}V-(wW^eK&+XRA+;yb+1q}*!SA4_K4yKUTvdApo41WYv0dXB&PnL;*|~Tv!t!IR zfWb9W@z488Z?F5D)SbA!6aRO3UE$XWBe8<}{Z^W$)4NeMOKN=MI|FIZduzVrB~il- zQHv4=K*h>S4f`Sfz{R~K3+hMK+5&6wiam#{z<}n;|3t0&UEgNV3u!qjtTLfI5*u43u(xkxiSn=adv9g7g_K)bM11qkX(SNopKY-MD znaY%nd%Kn3FF`CkCv=zy-N-pr+m|ljPuFgtc-X!@6-hA~CFmy-bf|PI8jKoBmP{cS zonbL#_T?78=L-Mt=vR@U%zJU@Ym`gw&V_PQqPSt8I9D{DWpqk1?L6@enWu(sNCkm? z@zBsxxHF)=aWKz&&LtEN?aB1qzrf~8iyCuF*%kO+R0RwKT_q<$JbYM7X$o_UOqK8< z+cPK^Up&i%`*-ib(i%LAh)_i&9!kZlfUM*XFSw`pbfv7Fa>jq|p=Dnk3)^>dDO!{9 zTFWM{;jXc-PK>EHr6~AIQGIFPzJ9}Q3dRthD2TZSkrnKW7jr@JBwQJ(`rF8bFhK)o_N5#i~oGimDi2F4> z{B~OY(iUZ@e>oroVY1c+U2}BJ%70LO*{p4M-4~H^E|Ugrs4_<~*7(Bl(sn*Fzt@wz ztIT&V4prvqzgdq8OCei3xa<1tU?q2EtK{d_pvrz793$(s9~I{=#y(&n{5I1X@N;pN z3NOL4=#rP5DFT@{nNxV) zDN{87<+1}s^~h9>3L+CB4x$vz5;L4KLFS0NGmJ-Q3#4gA!C{$vp-FNr4SkfX8kxj& z$+TPvnt`UJrDV~G0NeyUgBYO3X*$=PBMKmBS}_PXELbJdB(@hX^Oqn~LY75P)G-t# ztaJFb9dGC-ycJ!e&y=^tqs(j`i%+imN4U0aDwM*(;S5v(5QGDPDuNVsWw68&)QzbR z_9Z8~QDO@|jS^E5Uj{@6C+q5`=Bm=;wdvR+6JOpDR^5I%WeU!fKn)%cS%t>e$(_T| z$p!Tl7a(%VbWJOQCN)`1*>brTAPu1B|1d3h#?oaqfOR%ya~?>Qq$@et`v_8!P3amn z$-PG-FieAHOM_;Q+>CRe+Qxv+EL}&WQ8lmsQEUn_HaXs3K{GL#Cp3L+R31%Cy0IoN zxirkmIlzoWyb@#+6IDEj~Cddy_Ya98V1mIM~g6}v{G`qKY1wY13$myQh zCU1fSrOn)_pv>f*GCK=$4+zT%lEi|w9GD2Q>3!^bZSzl&E^>w*0nyaVxAqz7Zh`^Tl*P;{H<@naOA)zBR!4{%DpTan42cTYhKGxc$dtZ6 zWW#KlKL@Oj&$W_rh82DPbA0AN^`ILr5sa~_0^6YL(iR?X!RO@nPHixK*g06@fPr$j zF)_tZgp#z`8UY#5odsLOhU?3NEJDfh8*~F#iXm>#Xq1k zSUcGN^Qx)#0v*3aP!k!h?MTuYJa=%yybHly-VC~x{0aFX)1S=xCG~G~I8*t|iM>em zWl+}E2Pig_K@Pn9`sY!Djqoy zkei@uhHAPi?GXzD?tJY7VFUqU(`Fmx`w7^1mY_f7ADK*FbYw9ke%t!l;)64F%C_$aK=kq2NTT#^p_~Q4iW2ij9^H9@pI1P z4X5w{&+tv|f3>Nxd(1z~ZKmNGTq1C2eI0F9MH z8x|bpx8LUOLy8>LA_Ys~di}LVgFCzg_(Xe1KbCH2=Fe2_07@P>LkSL#)<2ndFoDUk zoXN7I6m8yY{=t4UVEDFKlFkxc+i;cDOqz*_LsmLP1TOO+XRb5xX3+Jex6%Uy z9Sm5LOyMGc_t{dlh-&(?V1pvCz8PgCNA=+yxIO|BrJOEH6))?d>0nq4J-`}&!N-f> zz{f*OD_0*A>iU=d^BTwn;)Ij;xGD(N8YLQ0LHoiYt|&FFziJMKFEppx^l)GeU&^_Q zQFEa*{ucxTU&75rUPF)6hz-#BT<|$klq;IvabgK04SX*9KE393Pi)v+nP4ktY2->j z#Rg+>qMMczfb$P<*%PcQ{Wi}D+9CwaB8uS>T^(Y1;T7F5g)(~$d^Uh0TbiUz!^O4` zZ0Ea0i7#LimShV$){LT`7gIun{J?8#i7?Fd6WbMtL%ieXf*#4L1W}f4(jNKN>1^Ry z7C@poU_ocR%ml#*Z%Uk3Pwh_ATcT)=3gc$!Jg>=PlQ&+};?-!~I=dvD2FJQcW@ejA zgyG>MRVLC20%y=QM4EN-Vl;0>8zMQ-XO@$B&1@+Y9S=A6Exc~YvE4QvY6fP0)$!(^ z^h8*8#VEKIaNH@d_wWp?FY-(?%=R75?or*}mtd!^A665k+TbD4E34`sgxD98JxMwS zkS$FF80$bcSRm-q;smH*a2%oRDuv6PUa;@af+aZT5^%bNnwzp@GOOGz_%4#dT%$EN zx=I)TM^rO#rE7T54gNB~x2C*KZo>^6DC&5E{wO6NLB{w4LCu%UZ#Zb?%wh=de$X>z zirL;@eqbCYz&~0%?}Wo6m5)BETnaw22ypsv+2FgLr&aZ=)t~gpju3r#^10%Hz_sK+ zW@N1{PzpOR~crkraMNhNgT0W@!+b2olbr*B%IH zVjX0%GkJWoXR0Wo4t-C$_LOQKY5K;&BKw7k!F^seNNndhcS2N9QZsT*IEt(=+b)Zz zLH<%O+1^f!G2)26%2L{wR027t^q1)m1BhmEAn;)vM5uvY^UUN~7EQK;sC}y)>6^&w z0XEKyZrflCOKTfy{up3}G`OU|pR_@JG6xJdz?%E(roIULBe1ly(Sro1?@V`{bQeAd z+*iOvIv71QNHVpIaksGgUezZ`OyX}~ck?Byw;W@Od|)*ui*1)pBWX&1ncqKQ${)`c z2{!HqOLcNQ4WS#k5_p~aKcAgBWu?e@ohHkj?2$zX=F&X}(G&{opPuLOpn&-k$6%ZT zfiA4FKrWpRbY0yfLHoT=_IOMeSZu$#(%Xd%@Jv3Ko|#S$#1VQ9u6;0=*J48K%6<+$ z%?}^eS{(KKRT+f(Ue_;4dS(ycH`B*i#grEre_E&8mOtBc=)G+Kz5_N(3q0=At2B{f zywHpLVw^FGN#=YU|LJkham+zE@&;Nxx@8T5dJ@+i>DypzV2#` z=S5t!E7d=VYH(&o+H(n?z2$xW)m&Oxv1@qKek8anX05|@mlm{a7-Xjr+Hkqm>#?Q+ zX>aLQJE$vO(=~M(N@V;g*EwmFt411I^=D|jpeCnn)DYSz?>DDwk}3Ms z>e77G{{yF+{eH<%19(cU^R3^Xo*@EzVWmvHbk!(Z1G^~}y}Y$j!KMvV%t!4~RGQy- zrEt+Uu{J=In|2U0r!SJZ)&248b${xmlY?PN(ZIZl!nl>`8t@G}s+8!R@J0-aAbNHc zY_;5IDZq-WlAwg_0Y@rs?9nHS6C1|JQp|Mw`Z6!mnpKGM1XCfcg@lci`6>P#VUer( zC0mHxz2XhF-VB1}BWEFb2ErwrpUT5Yg#6Plv{|p56|mdi6bl*HV6A6R8ZMkh%bCd( z)N?R9XG>MhM!5-4F*SfN3?nYGgC;i82&;R{C zdv@h~UrP-rh5@Xf%e#A}x8QoRX?sI;Xs`T0OQ4=Nn9GT}md(&`{SyH8+~xPBFq=T6 z?{8GxQ&s81jL{C9_kt`rxjbm5#^*ez0zr;*KEJ@GE1mU)_vCH8?_Hl#ptLZ>n=jAU zihJcmR1CqkxXD-jge-YwuQ1&Uckhmf1q)ByhTf3eX#J?rd~dIJ=QbgHZ!f>vZdcNs zJtxp<$Uywx(VPEHT@4W$olAdaMY>R8Tj-}?xQ`~e4!Xh00ZOjn zq6nP^)4+7x_?5EnPrHTuU|89L+gcT$w_260a%l4c6iA86za4X^s0|idHy*l zpX5wOB-C8Y66m!bd**n%mvvVz=1QSsUezt01@BY)TWKor)n<;okCKwE!{#qKx^K>) zatg*rk7rDkRg_!ZVn0u^YDA-aE4ciH;!~42)lsRb9bjCsXYu1HTo9Qf;%Se(;57kZ z)-90ud<7G#PU$NdWfPj%fu0vteEObNtrI_M_hZ=dyp(l#((-sErR}0srX5m$muHvA z>b~%e*-05UkpW+VQ9*CkBt~^}e8)wRR-=)7iV@9Q7wBRi8V0s%dgrsu zOoWFfERFY*P^Mg+1{QrInkO;IxIP61JLSTff-az2WNXTuL6+`)qN&mJO4jwYQJ5Jp zH>RTc!J00c)`C1Wju|6%vFp6(*JCYWcsf%W;BAAP8#a9i&3_Oqf7B2mm%D9N`2INT z+S!}^m3i3(nk76Pmp>*uo{ZcoAhM1tTMx%L`%pT3Z|%_JlGE;j5kd}-N~d4vJ8Q{^ z^_~&MH9&62u9dJj8LcX7I1h$pataMl>T6$*?i@Xq&ifpy zmrFHXZ`fruj0cXccU?Y6Q>Br07+34I#s1YG@ug7fM!q9)m^oD1d!Zs*?JqDIe+g2iF(um_j{a`A{~kx*U2etz&0MP|e~_p_Lw>@n|e1@OE`|2f_C5u;b#7Jsm)mQWZ5jy_Hom}O|arurBM)9+28qj0$j_!1& zmwi^{xR1am_nLB(tifCkQsPft&5d)CQlk+xQlcSb0aPQo}JV(*O zlSADh4{6a7&C=O1E2nn~=jEPT@=OCp?wxp}A|S?wexh??**&UCRjtit z;J5cBWECq~x}~M;Fl<$oVg*VZQ-MpkRq+>-#~t*xhw08(j`pS2gt;(SOy=Kx4%V9v zto3Fe)<%@gFkHUFf*>GQQwJN51adA#{y2b-+wQb+1xS|0GK1$TT3wY*`K%bOZ(Je3 zw#ftUXKU}MGemZq=1?r!#PAIp(OJI@t%YM@+$&flE0DcP?yF7Ot*ZLoHI4`ySy50W zNCRL?TNP(4uD8c_*z9}XP{tycQ}})5KX3PIyf_`U+>cyRdZ4<^8#R#CVVA9KBDO3c z0Fgj)NpLODBp0`)ylSPEe1d*Y?(&Wsa8JkzBL2b^_OvAjcojmo_x9Mnwv^EB_5ryd z(`>9sCXn1}hin@&T8a(gprzWD%6>zCg=hCPw-3T=*ZXq`;dB*V39^WE09OsPL?@3(C@Zd{bR>Ht^g(TpQ4-{Hg&&fQvpX=*R%B3=@P;yhWrB z^B$8q_wh5xSMELPbuT8w$iMa79 z$SsE8X_ofq8iGrX^ouZQIwrD-zcjUX^XKs4&liZ&g6^D!ph+6x^bvr2A7Ct!4BeA- zgL3yfU&j1G2oK1!bO1!);eT47!rZ}N5>P&qeL0%5OQdy!vDhK%f-=w96zi7wnzk># z4He_8^wUj|F=nR4VmM_EAvK45t{|WRKu}e3#MRkgXsSIicW$p=Il^|HtSnaB|FkJp zh9(^aeaXA`6_V!HbjIAc0SIzE3(;TE`kK4Q+b?zoEHa$r(5-T~yMp#7p+^BXg5R_@ z1ZXI9l_-DnxJ&OAF-y??R#~#HX?fP`)0^d`bd3c(NFV>-&o`1}**lMu&PI2k`c~1p z{VV&IMO{aL#$<0xxgx|DaW5dqtt*1xPbukJf?=&#wh2hp6y&vve%Oy3P1ZAcsb_6R zG^?~&BZ36y3_m+H!-ISh{Dqz+35SQJ^?frFZ_;FNF~7_?OxsP3@yxeO63hSB1 zXv4UOSJcZ^(IqA`+5jPWIL7xb%Jm2D(UNUj`T+n6P+iCs)D3 zmtNyBWQ9$MOb2O+?S7G$6`=S{i0}M=D_`4?tO)Lh0{lP3y*4Cwt;Dvy1&KU}KSZOd z%CP0uv#cpRm9Wg~N4#&u)XyaF9<7ldMD(eAX{KN|Zd+q%6v* z67|JcRzY;Mg8cn~5cg?^98+`yi^>a(s2C+$(iN?mNlt*Wx2&SmR*mXZa2hL_7Y4*i zzKXUby@T^ns!U+|(f_?B>5tlKw90wj)gdlVdhQ&E#tx zqPXGDUJ7zSOt|o1aglREudj$PhP`SzKR@P_3FnCkXHk;FwV&O2)$)jH z(RdS1&?=AB4bg=r-!J^mqnIVKJ!rZ;WGPV$2?~JK_UZ)EJ%M#+x`mL{-1+2Gf zs)2eJO$6jG2+Wy?DMlDQt+ruevd=2Rxg~^MO+^ktn@jkE_DGl?AQdEBkwK(qE(BD8!HUid6s$s19H8 za!L=Al!*B<#{IU;(yKiHHMja$WKB?>BFZKthe_hmuH=5qCxY|l!4z9B(|E9M0%jmV z<#-+%O)}57O{-FXNry-Fw`zIIKP6!H`g7qDw{^Tlw!K9b6b-cj%0+hz`1;FK2UvVQ ziDoAi1g)-an8@-ZS8%v-WeaD<+k1-tT9xj-ucmic(vz8E(rM%^q8Qt_!1sW&Uwse= zd+_V)nVviU<}1JwTy5TYGx-#d1YtIb|3re*OhtUKpXEbq`YR2UtJ2`KO1I}GJo3Fl zt{{!d&Qsc)0y0{By9g~A1ZHR?)Fj{s7dP4SoZcm)%8IT5oHz0)rU z5fZus6pTDJmU_K(zga`POK)o-N4z9)Eh<;8WS}eLHfgU*<8RlI3CbI)^~D>oBXM>f zwYfW3d;v6$lZjW%#_wjushZ-k{C@fs9M&o@)|BX*xoPX$0YH}&owzdDhMog zbj>)e_7~Jz`|^y=wGH8;e&J^~t7ad73x*mMbyMdh#82RcO}(O4la2U3u@jVBnxVLp z^?PG751eICZ9vR<3nAH%1>kj9K%5#9Svj2W!mP>T4cAFpnV!|`gZ%_~g7(auffI&< z-&~skt+6P{6!5HITaXZ6n`qQFMCZ+99jywB37l8-EAYpj@>>^uCi|w$8xIhjNs`cJ z_cd2sIDIIAMoJbX-g-li6`4{`Rp5S&R#0OSI_kaSoKx#X8H8K@mK22I5`smaA;A@_mZ<_I8%_jPX271p7zX*Pmh{ zM8qtw1o~x?=wg!Sl!@?WV!pl=dahD*k!dbhN-VJ;%DnF{tV&K*qIo5J4qxaa*Z58( zL{$ggW-DkYnut70x`0>Vcvjh}?gTM5c`kNcv`?bCp@uCRC^DP$gVE3TjLTejP$aKk zb3<&glqfXZe=rXe@mdv}s1&$$-XM8T{Embu8>9F?;7Z0C;-Q3yw0FqcT?hkLiJq$5 zpZ6B2NxI;%`SiCmJ|X|_QpF?2_VuGnnUXWqf-lw9H&=>kF;;XIjVt3GQ&_9BK5W>Df!2!+ zFW=Qsxjl7(KU74YT;HL6uQDN2_1~SC`4=)`=cy@b%gDe-PA-{7e`=G^_s%0`YAg<( z6Lviiw-uIadCxOHWN!Ni_ig*lK|5WEv|<(&7_8!#4lW5QCosHQK0}4J*ikQ4=d0(abf}JO$$IskjwoRq` zf_~b$i`uoTHHAH;)>_{+U>rN6SH4#W)hoW?c{{vvAZ*xg@$O~XmNC%pchism%IL*~QG-#f4dNewC{%X#@t|ZlU zkF%*HMj{}?H+rI;4?UgT#bdA)Nw;S6d;cjz$KoJ8TV>5-orSt#T`d{2hymSVzkEZA zRV-dw$Vy04Xd{_lrWRVP6Cr)4kXo?XxkBRmaxO0x;pHlRRWOaUuFy|o)V0_%dF`sMKko9GNK)}>7%JRp7?xp+D?`T0CsW0U42O*Y*tr#x(Nk&5 z^$k};TsA;x24=>Rug10}fbDv5YOuR_pb1qnWzf;Q>88FnOd@5ak`7bn-!Ns1_FM3a zRelhxAm)f+Q!Z6aq@Zw|w@e&Fp44T&DZ75T=?!ZD+|)|kEs?lZNAjbfw1gUd2|h|; zTN{F5?4$=^UYs_gLUP$p>fnxWkdl~Z&F{_FWNzVfcDa^Y+hvTSv4Fntf5I&t{#Q9u zYddEEvt|R+`%sh7YnYCkk~R5OlF2ozW=(QbfW;Fc74KrcFy}vYVQcC21hnM7^;A2D z#%Mh)B1dm}3U|;L&U8_gryI{0{QcB!i?Xdpaz$mqC88P9r@Kp3skGrSg?2-(+B=J@ zDe!@$*!M=`x+G{@=$XZkyZ4rd8>;h~PJ{bGSA;KDg=kwi4*0mon2v%3i{r9}=%$vB!y8A^vrw>wi12x0fu!3tvua z8{&0H%wlz~Sa>9R zB=qsfQ`GX;gjssozx^W`(En>va~1V(;&Hcp2{>Fx9>cO@X8cW|j%?O_gTsiAOE7;w zK;?;j$0DdO>_%vOjHxSM`#iSGgDZ>YmNQ?mcTQx_^o`v>C`&WURAj~>)A!agsV-Jl zfB7JnjHtoDtVd0S5A&!SMGQcZmE5f)&S5~h;cjO(Qram!QCeD1El!SW^dnk)tw#RQ zBf8_sLD={xS>b$Kz0-Z}P&ulp@G^c}XAp?^FQHcTZsC~c@54eGq7IubWI|dY2;VWR zfx|nIu?y8=KLugvJMw4FL!HjdN!MLis6h6FG4S{LCuDVdaRntR>-W}=YIR@7DH@jo zD4#c^JJ+mV#V>v<`x$!2s3iXkA(OecinY|Ib!O|-ph|XXB(%$8ULltxnQ%42*z)dF zMu9Bbdc%nNRM7Nkm+oo|N28Uc%}l}YP0j*cup#&}NG;Zsi)b}x!c}Z(^0KQ;6$4Q< z=1TP_?oN9utsp6Fl6L!qw?W0Q$*J%Kvs3(gW0)SWPxXTE!(X@R0=gSTKgT5_5YVRg z?-Z>+`8jvQV;lW#o89JL%sqVky_IyM+2fPV{Nu&%ZLyQhUO!*VKl}Z?oy^ff{1VsH zjQr6-wQcbc7+)CHzmt%lxFhNbNDGWi(Pqeo)%%(Y&BiY}w&b?T3SD|}x;ss~Q_H9| z_#T^^!Ce=s9mzu5tW(`IoW|elKHhO(|7DlMy7098w%WnSyAJ+&WLSq z3)_v5^Lp=xEehikm!u=lkH0tA#=!KfzLe;*zhm~R3W^lGFFV*Is46Ogm{kVM%Qgi*M{0af8v}*u>tx+@j$GrWLkLf{De%W?5%;p5)G&J`uF0w=ldFm4$9x8Uqti7KaO|# z#<9~kg*=QKF;G=0qn!DCy>A7Pxer1R^ES-wr>#X7$UNN+sVK;P#yKk!Xdu9kL(YEK zT8Z$osbqmZKRg?t%_XIPG#%Pbg*C6;` zk0onazk|g9Km@nz%-@|W+CyJPpp4$>AJ&~Ee|Cy2>lc=;M(T*(%=(0QYw&*CKQepo z>DQ>tZ<7bnkx%IV!lM5yyb6*1a+fi9#pR<(?#RMYYennNFJ!4#0sJH3v65j2X6J=R z<$EZ~Rwk_SM`VcMib;L{`>#Ai6M^~tVasmyYz>ILY}N6IcBB}GAytb0_rV7*?fpza zn<{W3mx)ZnYUcS^I{FoWF8gqmBN)C`8gk2mdT7cVVIv3({G!P=s3T0R)}`JbkI2GD zZn-+ds$$muDBm} z*I0LBZ~SZ-(f%u6Q-1y+<&yCSy_%j%RC`0Vd)bGWb;IG+L0M=_*-*pRpTqM;pI@(| zvu}_5rCrIbo4@||C$|Yu*b2zVa_a_h`z{>4FnD%JAhHtuqhrKq{~$M^TYz2p*NDam z&^B>nU3|;c(x^&VZtO}a)POPk;&=w=yCo&MKbpSxxHBiw>c4*qv;n;%Zw_{E4%F8Q z)CiW7Zwm2yit|?Qe;_P51s; zL7uBeRz}7){`9yV5U<#fyj4dk(~(t=jhH@5xm%xbBR!(EkOKG-r_yi&Fi(#Cc0RnXo&t|aSt_!29ZhyyFtk6uQ5leWVc`aLG-8?Rf_->HXDgQdK@OX2t^+(F zW;)?>Lk^NZ_m352-IXNnoa%L)K!iigXe{Y?wpwCh0Vh;ly>@Y|@mQ~1u4(}sg5fMS;NS&M5fcwBn5^9H-c`FdXbV{RF z08c9nsvH0rE8caa5b8cMhAN;y^IE25x4NPZ$p|_>ejIaaEF~)$j-qq2(AKmSn7m>h zGM+OGJ;m~llz)7POV9v5c0j!jRM~em+7%>q*XJ6H=Ef*QZr_Rhah$v1nqzTMSD!yG zRWCJ#H9lf4=gPyvUkev)j%Cg)qR~1Itq&xQpsQaL*PBq@i>rWC|jTpsib z5%oAv)h{1}`-Kw1b9_nVvvXpxyj4J#03~;1&Cn3}4aiIY19*;x{Mo^#F;*F&lo$FP3IpvuV?Ak%3aiiMAUR_o|jK`bjbtz`c#6bZRi$452`SXOh#lMEG` zOJAQZ%*ZVds@@;23g4{iW2;ip&3&j|?H(8?v)!T>+{&+SbT6od-qfnDU$dwiJ`rD2 z|J_s10j$Ugk^rz=$EP*WSb#JzfmrM6hU%tisvpXsF?GxMI@eXmIv|oHDaiy~Q)qy4 z+SQ$XwziJ+kOO{&3XY!uq|s3Qa2{%LDkKlXKz-qa3lSTrzis6>VW0F6d==nj66zh% z{QDS!=Z}P61nA@v5)5h(4;FT+$+3_>QG=P`IiqK8_*S`lzY$ z=I2TW_8jpS7i&kFZ9}?MnhM{HrnbO>{%uw7>9*NTN4O{GXzD+--)Wsyd=QjSwXoQV ze$=WNdm}RI#=TFnZyQ>~EZcJZ+L+C*9?1G{e#%)g?|0N*|w*FOIm=<}Q7g|)zZBOggl-Vo>BQVCt62rTC83sAK*^jL zChq({gpk;A0gVI{?hl!X4ATfW$qGgngVu$M0G&d2^Qm_uUl{fV+dePuratOk+U{-_ zZdMa+J_)>`X;ovz{wQF!nix_v>J|}i@XY5=vX|1`MA_C4j~~5Rd>B+$J&;-TQ}q%O`IQWNN<`@i8UD~i-u}(I6NkFX z);EAQck_lZrNf8#raDDb@^qhxb@x=(gKEBK=iMJx1(6;UHdpmF?>v0^jlatCZ-vut zPIO%ONc=Od;s@jU@u?Rdy^LZ!+*3*ozBlxZz4`l}hwi7VZwn>-7kW2l=Ydx2Q=l?U zFAsVf+anbN4!#F$ZYIqeVd>|hwqcvGxy)rYcXAoI%(cy2MhK}8n!AuoQ9|E#Gb6W(qNKT0DitLmYI9ve zQb{FENr<9Uy87++_x|}j9{W5V@AEnDbDl3DJtY9>4pTtS^j$L<_`cQkiTu4*hiy+b z4U`(*vsmn(=HEHIX>i7;`(4x3k;1FnuipMRIZ}6LASA49HMl<^Y4F*ftXIdv#b>H& zj5%zl(-|SPMu~TDr#(F!#B3W-!q^$vE+L!=koCWSSpe-=L7ppwDVG5;X&cb|LLc=g z!~^)nf`lHUg6cQNlpDI-r+&)bt(SGads0o~q4{v9<dGCyj)o%`zWou{vG-FkL0m(ThO60 zVZKnN$O&vLZI|8wI>{=WGm^VHhWz?}(HosOl>b?Rs3XXY0u(kV{5Z{0sX}S7d+5^d zahCcMlIG2FvFwdXl)sj40M37SMYaxr%$-CXBO}^;x^&#N^1ec9W=QM<$*mJ`X8={&Zj6-rT%+&6jh& z&x>$(4uzNIc0GURTebXqiiwOgLPP(fKxD_>*p#*J+-GgKiX7i{M9C6$>Fef^6(2|d zdtn9jvw8EPZ%O~wOT8<;v=9GHOQcDyvS@v{_CwS!iu{#Xy#Xu)pfY-; zurAS>@i`VPgA;tlS^|aAH|VkZt(r@>*&3E{hQYg z6?E@Ie4US23M}cTK3fuxPAjW4B|9CK#JagGNlo|OL9cAXI8r*D{bb}Uu-*g`lq*Vrt037j8KK$~) zYhg-gp23>uQF^gL!h?U`lCFD|?+HA%C#>+z^ylG;no_SD?^93TA1t!?`PaRTasF3I zCa7=)F(`#6poSXFvR_FGo$iXNdoCAnVHIPD%wPpayNzeBukG=_@eBF<=fJi<;`4vD z-oG=v@kgZsq}81Ks@_m&kKzX?UaM3nSO2~IMCL71!LbJQD6G|P=by3Cs)f{__4ofp zF8y1%v8z0@Q7J+Z$3T2;Mn0v}M`0*H3u?-ik?i+}R_Q<3lP9a?!c_~1a^op$`1Mr= zyz?m0a{dp33vBQ>=HOA|Ru%Z(`;?j1sSMoqIiE8&`=$h+$Yn+mh(HWQz8$_XxJvZx5SRrxS!p*9NM<;bxOnP3^=gB z+;8mt;kVrFMY|54IHEyr-XqFG-hY}Myc#u7thI%wxe@XuW~jn!&p>s^*SOJh&ZqVN zgsdfuU+_KeaW3>*qR2dKL%tZ({C?6kd?ohW?jI@B-A6W{pW3`DjG8fT{)8SrIAGN0 zKAxua+9oA`tbY4xIxQ#d)9db|FztxkZHnA`tdGzE_kCv`=*K^6kF4xS@N155cr5Z# zHvRk8Q4x6OPhdhy`%zn=d>zJ(9(iLG&n3Ca8a9ybD3~0-gg-b$XE|3%>Je^5CQJ|Q zw55-HsNwzvkLvUY?qiM6`TgG5z4y`;HItG>Ix_qOY4CcSVDG>&$R;-{Fa6UoH@&W# zS9{V>&P5Npe>4>}vg22N8WjFEc*#7Kv(#}3zj;J+;{cxSvhK-^TqJ(Q+dn9uv&~-% zbw6kM#!~FHWdmaEPc@t>;b9XJ=EtXjviXU)MnAha@W{J3Y04dxf1D1NpIhR>Sts=q>gx*>^I3nNN>mkuZ6*zV37f&pa%!8s+!oDcIViv<3W)6&p{@ev>w;Cg-Io zihK5FHCl_)dOUZA+n~0qgVxx^n=`W3iQU-$HaIgfMDKM3>0i1K7m@ztqqfEPSPz36 zCe*2p!%YenF5<}0^KpJ+fokq2TpU}@ib=s_EmALnxo-Xt&CO39#7*sg5qo#voj1I@ zSFz*sJoSJcFHg;Y;jM$3G5&gYHAHt;2hNyJ+%?KGsRRyIXN*%})v-ddS}n%I z9s_r|UG}kS^>ofyb>=haFq}BgWiqlXFPDjq9e0Cez@TYGm+>};I_LdFcEJO*9~_5q zL{t0t#2Z8nv4_jk78H!vjK49-{5BfdfA~)?{(CTt$X^HU63F^~2_AHM`lA%n3}jKO z2em#wE;ecRke_Sc0}B(trTf>o?s<2RLfyIN!RAu=dT_JKdTB}*SZxP`X>QQohHM+J zxWT<3a9A%nEX{bIK<{$g*bgi^^t2w=zm-KOOGhvgqVbEBfiyWBJ&o_GkTvF}Jkw&U z%8bY6$!Jpgct@?yD>uSG|M4cr7 zOAiZZs@!$y++?~!5?zrPr&naN2vj&|8jaaV8*uzrTkM}H#QiACw{xn^_iY%#PY8D? z_bHku@j*)6ltHIiOS+;dxc-%dOK_VhHag;ZqO|KgL}|4oM*`OV$ryC{qiVV+-P0&& z&6^BbdxU5wfUh(#OfNX>xU%z^KT8=In3^U5 zr07FYea(PgEsHEYnhOFsE&*&lMWRqz*jm_Yrt1f)eDgsG_<3`_y*RDWh}nymjJZPH znt_H1_4q}>6iiRFEh(1))-D4O6E3?bSNXOnH!c~{4zsb6AS?>K-SOs3Q9@&Mr{V&D zI1x~qQ7sBP;4a?2D};Kr?Rod-ywo@cc6IP)D+HUce5q)~!`0r)TZYry*Wzw=A#ZXHoo)g0g4^)R^S!dRD+QZO*v;l?u6E-e z^i{K1+z|#d%tZp&JJqXk<>qzBspASsD_7&!)fQmUS#USwUQK5uo7cZC}MmMKFD`P^C=Lb-tm$gfNn28 z1eK4uJ1H94gj!hlbe=el42SE;{Z+3(U0+p5Gh(AFRr<^%L?$Jn~K^>x-cMYxZy4tk>9tdeM4C~K{|p*;-GfR(Wn z;+yY)rLhCt)YTR;t)e1p;LyEq-Jj16pVnf{-x}w&02L9PW4r7#thVi-C#?keeO=kD ziUQq={8N8=f6uzpm-HezHH)a`!(R4|O_K`wS6lX-=(C$+rDx^pD!*dgw47nB+Uo}@ z-b)cb@RtuvmGCC#{tEq;iL%D#+~m*9d|x~C@<9o!NO=XBd&5lb=23}daG5b|rC2!T=GGSG1 zkLi^_@Y%Nj&$r5{s8BTS!=U2r{4HqsNeyhA)Yr7^WTB*T-+$d3&&uAqE0nlQs%>=; zr$54c`HF%3)uLH+qTB$o4LLgf7u!9boX2NcoFkw=GV|9wEV`Obp2e-NCl*zummY*| z0#~dUIAtpmiUjAnQwIP0etS>+(TC1*Zv{Cb*&{!W&c3$rd;dJl@=dY&+egtI!g{=5 z31T=uYNP(o#(v~7>cOtMFDb82V;rUCWL|kF3^b0a;UIrqy}v+KRt(@j{n~Nc%GQ-) zyKBV)R(~UYcV~{2MS6G2eEWH97C5sJ#y|t1tqQ6uiobAoU@I-V{UN^oXXd~sb|mEI zz0~1*S>)Wkw+!wfV0(~@_gs$MVPWobzGBrInLdHApU1H~Hd;7w!916AmK>Rr*$j)J z-|=mR9WLV{#!&r{VB1Fau?JiBcjif@Q)`KiRwW=VxN)GfdTXNEEjD0Va3jV69ls9C zm{(gS1FaYw>&7ilynE06&aZJ)p4bYs1zd=qZ_g_OFq-rA1Ff8^VcQx3Tmt%5fVOHQ zNQuppmFTI{!M2k))voifF|PJa;@p9c0*zxf zB|FZswz zT^V`P1^ve4hieYKwH|%fWkOw{bX;X;jKR#Yz@#x)D*CKknctBym}6&tuGlYY{v?LP z)A(|Exg3*35_i9Ct?6k$nALW>L0QY6p0i?nxCm-rp!51NXkXb$Wu0xrn=P1mnVK)g zB&GbW(5-Dw=zXN)uY&moPxB8649vtljiLPW>X=m0jg|oJTJ@vl$N6dV%Bu71WWq`1 zPW7BLo=P8R1q_7=JTj}9pI@L9=Q$OxMstM$n$PkxNn`nG{-6I)XR+f%{lLeK28?-` zp>)u0GSt2OnC}J!8UPsfC0tBw31p~2!zGrN*12(FXzB`YACtFxUNJvQiy?saynx10 zxN<#8@6i2WWxQuBsP76p(uj`=P_}57NtlF^MtE@&?$*_EER!3%K7O>F$4+}MP$!vXLYIkOf0Dw7hL({x-v&oF^PU}sQp+GQ!7^Hb)jL+6K06NG z?!Q&}F*JvsA1i#4XbGh@Rwpjzg?9&<_RE;ImtqLq=rNfqrsHv$6Y>2B1BA2y0L&-W z$q`ITUz|BIGeN=7a?{NW`D~*!kiMgmt5R=zCa42oV-f;arJ(o!J-;bPd1t!GtDs$& z4X_R73F|GTdkAP#G!IC=&BsitFEXEF%Xg7aR*}_r4b?R#JFBxX&yC2NrskPJ!5x~< z9>)sq&>t{Wl|xdeu$;d;6Wm{v?+6(TMy0#@@2NuJTT6atJ<;w!;=_6t(q7~-OHL(( z?6U7S@{v2ITv+w3;wU;VP5@0}geHl3+u-9B6)!Je2;Fk|MH#uh-JQ=~b-#c0{mP45w+rqr zzY^(B^&HU<{%x-b-rXBJHIO+qm^US^n0gRfq}e>BDVQ35HZ^jjXg*lB4|z;ez*5@~ zhK&S=O*f9@$jaRvJ2rtVgaRiWAIsw#ik@D0-M+W%KzMjJKYaA|E%Oz&c^bQXEc8|- z(723^GXj+{UQg_MeZZ!C;#@@m>E-ce)B?l*IN3wH1_@z6%njbNJ;q~GX)RO+o^_$D}| z=;@Bve9AzhP1wWtKs<&2(Cl?td&F2vL1Ir{#F&hgnxsVhsyU5C66EcKa}3l#rSr_y zBOG#BB<|E6t1p#6O*LByx}XC0N;Bf)4iP~mw1m{DFwfph=2$hd>EMdCjSBv|0C~{v z{0s?AFwcx&7W07st`qIS&3(~YWP(@ zXFkBAlw&0Mm4&)~Z+CqRclyUW2!P_Da*D#Jg94~V8{#=X(uu?<;72=VaegWnVCMm{ z2IHE1Ag)<*R5FX@v&x!}8Lfb%s_M)UMrnIRrx7QD42_--XjKjqNPswha1?>(P{vZ9 zhtvP^q*CQULR?hD|25DnXrOO1^Z1VfS#;wfE-*kJVp7XwwBq5;S-NOB`A)KnQrb>sE{6HlxR$qXbe~ z%jIkB)k$e_2bpnu<6^jz%+2j_spN!xC2ad|aiSKe#dml@1N4ALe5N_rcMh&xrJDgh zcIw2*l=aD>=JHrdXDXdTQE^XA=-BKet8T;zOB*l0J@u{|Y?4-pgL53=Y{VS=*JVhk zP|qh@hTa^L{t2#{6&nrUjXM-5eJb2N8XM&gR$F;rY@~OPiAkqAG~BICVw~(A5-D{O zlV6_VGIx1NTf)NpNVs(w1MC0mvSx*+?bvo56`=FjNqgK$cO9qeNTi{yym|#JtMbD$ zXRzNS*E@lii=R0o2J98)rx<~l|8X)l;HoaV367ICujC6+OTsEZ(BjnFW&e!3){5< zIi1FxXV&Y?dN)G6j8=DClO75n?JEDQ=Ci)*-0`OTq;~8pO=#!|Sou=Q?c(AoL_=(_ zOelJPC@F7q-~B&d%Q0y@i;Y%Z5LzbG-#!POclX^(uygo1hDb&<>you3hMt#EWZi8< zZ3Sv~i7Oby19t^Y3*Y)s^8gt0QYLz|fihsD&9FJY$tqt0_hZRPk{=BqRWd;IMhIQF zkk1fVHkexO!IHL=yFH)tF2IuFGx!N*?(qjY?yYTzI8RPZ&fos}p|SiogW8Z*xG&gf zFFMax+IYOf%duw}k)WEN^%3#~C^?gzTKhxMc{Ga!3=;~!1>K&tzv3!vTf)ML>5Ny_ zpDZt}`FI}Kego@OicP%nJ>&uQ9zVi%jO*PDp7%ZA`6imrpbkZqIqt%$G-12w8BE0k z6V4~v6L^F#JgW`*cZTfNocXuw({N@1C^b7zF8C1qzwZ|IUqe|3V+S+5sgrvTWjQO9 zYm$Lm1P~oQclH~23lro&&%!0771LQR{P(*F5GNtneN5)6%FJR~apqvjf8S1+kU8e0 zO<6!Nr>K06upV6vsf0Oo*HKDrJs1TmpZ#1x#f^T<*opTA~NwV5D&N5G~D3*J?K7q%2$i$7YL2C@LaEzJM5ctMQ)u!0IpA@j}a3$hg)`HSW4`q_Ad*9*H zkIo)LXjzTT?@ZOKI%YhocJ0UY5Qm&jD{)idDyQMl*EO%*@ft!Y(=zFLz8H1Mml3k@u~d#5O-7sFVgIKU11DV2U1oy}W$h{~hZbpP0$;a;v87Yki0$s)I(==bS3Q;WR}Agx!P zXzS+^v=Du1D2b=de0KE`(kG=#%Vp&1r6llDOK4}cm)*8qSPMq0(0ZZYFS5|u+~oSg z%ZJfc7kZKq>?ad2wCS|U;Q z+|xaV57l}HV20IWEW&`AE`fxKG5-+B(}j#WGVe z?{hW1@USyon;^VMf zKIP{yf-uq|F1PM;y;KqQxD1R^eH?Gm-TnEF~AgDOnpS$~vNqs-n- zepP)JPPt$)H9DJBVYHaAows?u@m7ib-XLMYhQoqhV50s)L;X7J_0cy}IdKE6)qa8U z?i;kV=?T(M(tg*%267+eWoL1E*pFN-?jMV96rn=(qV_H(cy4xEIg!**ulhFav<-X} zd5A?*=%A`NEj~tCWFd9WOT(^*)74}z01$7~&UB3jv}T0q%03f@xXtX7Z3IGLzDSa&ywLf5I$YnA)Z9#$(2#@-<&(3?T}wfxm%j$+C7+D;zI z4b6{>p=rDT@a%&#LF&?WmdS65^-`_<=!Gc!Fo7l`CUr89Tg#t>@(q?mB`)&>UmRJ~ zI`!b<=mRkR#5$9fFb0f!s;iYsICU0%X4`(Rq+?1BK#lPLh1lC4@t@A9daXlyvW3xF zOO=C8pF~9p871{+2nDuF0Sdb^B;cpQL2@Snm@rjex4hoyjQMqo>XFZks95YO+Qm*(w#+zXdqr#3|!_l~yN+E8N+6mt$ z#Mt!rZdtN-`t5J`981sc58BlCdk}ijyEilI8(t_(hGiTt zO(nggE1YQMeB@7%oO=Keg@9@h)4m?b_Q}mLiQTf+XhQ}&B8(OaQ1#WEP zKt7Gl5@{C1=5K7jdkf{*$4`AD9<&kyBXXpus>dd4D%>W}h zng_^{&p!LigU>elEq>Xlm1?HY*$Fpwx_GG~M-Q#5MRJFi29$oj5`+e|dCLuroql?_ zygou%#w$Vx_5R?qt4oY#+O4MdW?wHI+spvU@m3TpvRh;oyn$zAVF47Sw>IYw%jmIM zycj-TPFfVO&5I(BSxdjNgz!F%jP#-)Q;1>qJQ!~>Gw5#B;JriGZk$7B2RHeIwQxhv4}F`(XsVveS#ol9FrGi6#d+dM8jttM+Cwn;Q}S)ihC@Dl@bj+ z^!4%<7iRvQWZgrNfz?v|!7uX2!qcReCC)Efic_;_>fL-AY$_&ID~6)_)2|mM$IhE} za98}XFXQaRKL3RDD*ixwzSF&0Sz9<8r+HB|V|z-O$}p4ZL8)2yP|K81#m3Pm-y$U>!WC()I@EQjtZNZ&r7;^TS0=l_W84L5F| zW}Q(lZtBC1II*&=wmX@=BMvEd-f0%-c7+Iom(NXnV z!lF~t<6~iCI=+7M4>xm96fb7z$|%oYx1WV02|XrF=eV)GM_Nuh3u%r3FmaM)B|Q@W^~ScfNdsXj7A`#riI5e$S>cw!tjQE`;XNOvCSG z=@bbZl1no9JuzP8wo-9&67+Z#)(hEbM+d2OiLAu(P81w1h;96|);P^|bBw=jyMO<; zTJ6LT{xC)D4^TPdu@<_HU%mBXR*xlucG`agH}+zo*h69lCan-_h+sXqycvOJ!l%HJ zK~`fRz-2LXlB#Q^-qH?GS(6sbJrKmGYywL!h>c%hh9i0{#f7()P@2S^B!s5%GoYnW zuW=d>jRq>tvTi*ST^kW1}^8v`K<-RnlB;0hcg)oveGobdcxYlRnm1SK}bpzmYq-`rwJ9kZLB}hiRRL?M}m_ zUk)>^VM3ZuIVZcyFsXagI1mXiR@7^g%T)EjS>;N3QCigF9%(!kgv4=fqG=)mwrOd3 ztc>t4oR!Z7knP{N^8sdjnr#MECIbLrvci4cpB?TwYQ}*yh#_mhoj(!pDxZ6p9D5ZB znYz|H%c9CuQ=m+s!xSxyqPk&4cGsr^&UgXLGGH_I;u+RcTc(b$0Xr~uYv&BxST`32Bt|&RCB~r%)LHBfMf5sn`KWR^_VyJ0 zwDMl%mnn;J(3nA}HOGs}ETjmdCcvxZc{Y47$%lDZnUZvqlj!AXZgk8Ez}aBAe;lLO zN}bhYimH>pV-ZI_9L$~@l})C==*(pT!N*AAMCc8y5rWs)+x1+7uRT9JXD~C1CTG#K z=@eLya0ABQZOs&L{+_mnyUJwcg|9s77}3jTCdIprmYkKbaSVfGstVy zA_lt6hk`S5CD8fu&3PfCy(VNz3a>)m4QS2p-Q%AC%mR6eo~xz=C(Wp`YC>%JC%=*1 zWE$c$%~4)ery&fH-6Y3;Mc3<}u^T4kLRi@5GrjA;#B_H%z>bFu7 z)nh0Y7peLb*N-z*mJrwQCbr>avF?kWX45`d3Dv|($#0fzInO4*^9$!+-$KNwxAV1{ zio9zmhKX#~$yaBqDH?h-t63^k2tc#~R1x0zrxdsZpl<}WNER!Lh45kFMpFPt9>GEn zhw4d~h#+tIS)kcvDx3?DciUtk5W>YwL>fTZT0?!9BE$8zt!5IWR%ind;zZG|JbQjR zPC1yCN#ex&R#RVs9V_JfZWrvz?%hlRZ?^8W%i7@>JmzM#$CpLDS2zUL19|S~@r#7e z2O#}2CV65G;clkjTqq!h+pmMC;8{W$I3VC8>608_BuP!!pWlY05F^v z_1%6aj9cg+4oY#MXl5zT1|W%J>`fWhKV0wG)>6j}>6K{K1U~K&NA<}vL^eVB*&QgF zXbo)%8h12-)2PSDxy{iE zE7M8C>iyX!rw96Aa${42>p(Je!hx!pybmdNv8Yh;t|fU0^}#Zi0(I(L{zHRK_WZ68 z$&#t$wI`0b9NS#Z(bpVX|5|zR4R|cTe7JYxXHN>JfucUIZ)WtywQL{?!uFo;;f460 z8Kv3zk8s>qpy_$m=07p3l$HQ& zBLHV9tH{Zxj z9dY}%$aKfH-acrTnqvb?Z9aGhGNJMGmXbz097Pyon&(7TD!;-HWv*lCGo zf-E#aa&VS9Aq!u`M0Y(1zrZ->mULBdQ;P}sYOKBV;3Ua!wminPge}3! zMaNYRVH*{jXOxf06vkdp0`%iN>xbN4(WKW5I zWd!|M9-1t%Em{H{Puu)(%9%`ixR+o9&-4EbQXv{dUH{%+o`?ud=ymHt? zuUU}L_YKY3Xb-GfWE%wAyo(Uw5`V;zzvmlFh0k$T+sRqKKIlfZB_SaRuDuUr-2RSr zzxwS+@AcaUh|QsWYC5oosU5RixZVHMtCbH;vurZ%?xM@GQ%s;suB(ZJW&wBgj8*sH zGyg;xc{J~ud-{Ff#x_{j%;2k>eRBh{PG-RmIS;BU(ob{Y_)n5~sQg>7c`oI^*CLr) zD#ud*I$`o8IwiWD37H3-kUPHTMF}~93iAP&FC9p2U*T8UWq%ylkY)H~N_OO&M&w>P zYt&Hv%}czMuIBtEPJQXn%s!^sFvnSPYZ^nI`%%l!Qp8G_YKH^R&CDuRi~L$u-kr?a z9V~;jfFfNmUh$k%3YQnJ7My2ly=z(gWXZcxkQ4;eptFtE9$T(~_zE%F>j5TdY(vwH zFULSc@+~7|bjP&1Y5M+_9^oyXtCe+!xqAoN$6g-|9EsTk3-&&J^yjTSfSG5KWp$5! zS_40UnXsvDm4lAWR2e$+k@jZFpWk;xqj$2uHMrXo%W6^isO{w;@i(6H@>R8L z``QBtNcHER4j=fE8trugm+>rV(8I05%HiMZzydl~cmlV9n`#CR&>8=su<*YE943>G1)ITD|R*vMnTHUiVE-%mOk07C@%bUK@v2tQ`y7`JB zB_;axW3RTH7uD@)R-bA%&u+L)vJ4+>hp8LaJ==X~BsAy83;62`wRyfret$c3s39_Z zcfR+^++|36`wHNLAfbAF=@NF7F^C^#A6wCGZ~7SLD!cJ)u^)dhc>ltARA7{$3vayr zk&BhjE9RM;dmU*#%b!9F%q~n<8EX12ZmK_hc+#FGQrO=ysA=_QT-H48lVbmw97sz& zJ}Cxdc)y{wBgKJd1(>VJ7@|`J3WUoryw}D0T6xU!LkmvqC)Nj?^K|3qvpEfyy$OwT zVRPQR1ZgTp?*5+)aGU9{q@sIB3~0%=?)U=smF&$o5Wc)TSY^G$h_1>WCibCBeR@~U zW5d_A zK0bR9Ut7HM<=z8gpbVDHs4X~pz5gIQK3q_HB66eTu|87fz<#2P*;1pPGNXh#SMj=T ztiO^Rm_}5NvG$sQc$KxtT&(sJzN?Jvd`i#9s(pVhV>aOKaRQ?f*IOAmIVs^5%RCF7 zIjcD|!*$>jJ&{Z_CwmcxoE@Yz1cI{D;YGe_L|* zK*wCo?o|!5!oIKg#DuYuy9p+CKF3#w!1!B5^>P|zXW=FUpse7bjK%>0_}ZmYyPk4r zBVu3W!Wc*QhG_h$z}^08vjq50y_5sT#$I=&E9`6M6Aj6P8@YGnhHZw@wBgzgVHVTOc2;)=@<20I8nfAuu8@!$tredzW_RYe zLVPuWt^&MBSg>6{|!!_b+S zsJe=@v*&FT}^-<8?F*46&m zo}c~8nC;uFYx59I#S`04=C>B>r1pwo5v#>1xzTDfop7XInP>YL0i0Y(xBj#LI2J&= z`bLnqMQcCEkt|kI%A&*CL^|qEM`~RTYi@RbW|%hFtFf_O1SujKT*``ZpC9W9$I6uI zU5EvPx%rz7D7=iKcbeb)`#!!rq1`doZ~m)R1l`$k+PthKH`b`o#)P5X=W_8pyBoGa z`FbA~JAn1V_CpYx`?7;dw_WPT6Nk6odmeN<=XQYnW;~5QIZgqcpJ)6cwYt0`c-jxA zqq0g?)tm?$AHaJVgU)5gf$hT!8rtOmQXf``SbKZ;osG|3Y(O5|!$@bL5w^K3rs&`0 zA@NdZ#>fLV-UTIe_Ps^;C_DgJ${~%Z0W~) zUD5_-qxKfd-r7+)P(C1-4E%5A<};k>lR?M7mL7vkPY7H5#WbBnFq`4&d}g>zPR!NH zBD3^>PemNDuH`rS_#uPVqPD`fmGveZ2mcoj8{im7!0^vuNV2`^L>n&&e`#01cR>de(+ zJH>?N9i)ECqE$JIqEVR<^F8W2iG}9t{inj2syZq+{c<}P%74D73X>H*cW59Y-Ctgn z?<5t)=DNasu~I=wWWi3XRUHt@sM(%kdz*rB_PGhK_m_cA1X#yfGO8Xjc!n&CeblM1N`NbciB%sK->bCdb{u@_m1<17+RiPsQPm|^;*B^;JY+FU26PThs z6CF!9?+op~|IS`fK1`?CjTPk#gSDTon7EBHig$HI>Y4L7HgoBvySs|h$8Z}CF4ft` z?-tbKB}OzE2Lg~zHd5D-e0=nG2(ugZ!D$?gA&EnQ)N1enKOFqX`xeCQAOYeP9jTXG zf9&aSy(*3_vLjt;&%;_BOs~?qkXL^?6K!not|To8zsORJ<+Q$%^HsZM+4co`V4U=E z=4Ke)BVf%eBWL6(%hKx=9)_jfNZ(J^SKbc{kZz@af;ka?@0+aM#$D$vwQM3Tw^`VK z{+$A|J?@sss9oE^_kitXm18J0p8#B!5=79qPi z2XnnywoAa$ILVZo<8v>#R+Az0{bB>Fw@C-tBvPJ~{0S4Hu5S>(-Tb`K#F;OP+$QMJ zT%3{egiCr9CGRC%tErI#QzfQUy;HCzq-ex^9+^WTzu0fXvs)x6aa0J{6g2AUK+gI^I#i5f21dVL}}sm zs0iO#D`zEyT?Kp{k9;|-r-+S2Dzngj%bI#X#ZE$ylWTt+N{w!8e}!o;mxi!o?&^70 zUKR-+@K+jV852J5-2Z-@`4%!M8R>IVO!S1D65;1WxFHGT3Ip?$WgK{ITZ0HcO~twh zWviw5Dl>N?MLFbn6=+n!hy|xm?ToFrU2q53ZP|I(T3+hL$ z`zrqF&s$=s6;aVQM>LsJi(*mu3ky`g=)XPo34a^{>SBZXr#Y7*E z>xI6vM9sQdTmw;Swia)~vRT_uG~EC8MrgX&nrI`L(P)}cH((ntU1wA#;wQ(|hlz`B zAaf)AlP*cWPc&+{a8}(ut|r!jAtM@{k(xU0SJ4=gEq%&MtVeAk^_#5AV@VF`x*L;U z)W@h;tzq3S(uNyRqe(;nG&D=z9=Zp#>?NKQ)@q=ijJD->WIxJTBWaqZYqc$oBp=eP;+*sP0q}9f0^+j zQN!tyZWuvhG14G)+~5gO%ld{Ppjj1)usB0C`Ut${>V6$UGp-sBTB@xKHkE0-i7z4+ zy9rIDbfBOX*C^WbVS@_SorSpV#g{!%ZwFISiaaDNtyYnGTdju`wmMl~JZ)h=#Qd~4 zqwFF8XV2Jc9eY{LRNwhTV*-fJc%pF+i2L&v{$hS>^DuRHk*_3D`rLLvx8XH(+4VF( z_+EK^ctGNHUvw)@0MwL-@H^q=VG{jtB~ThQx0(UIF4hfdmb$?Tcg$_NYMrIJCGyw~ zy(j9eBB2ua3n<<~ZPie76|L*8w88F+QP66e(E#*eis!djWjxvWRpTB}BW1-@>sx?6 z!@Gpd$XjSbc)&uYQ3vKHbQ`;Q*o2G!(*vPelcu6B~I;n_^}zR`E?Wn z03ExH^sfznrL5d1kl`}GJQ1E31Maa z8z-{OqrQsfzk7#1U}#8YwE5n#?`O0jq9ul_$qj1Ex0v0!ATN`hQS~#f1A#RzJX7NB z_Oe><&p_=jKzyU<(GtpOXXN2R741(Vys%cmMOUViq4i}(OU%^YMb-X7RFBy(RiCtw zD}>x$qvE|cfm=mM#Y6a|+QveYZ1V=3p1k(b!TCmD1A?YBdNrXqQKN^d&8$7@fv`Jo zt9>u>Zz#mvM4-Ax)fRjw6ty)%^mNGI?;_r5tWh;C(jcIjb-qc|=MwGu>8-S*-(;4YlAeT5J(g4j=1_Gkqw1G0CcBGw( z(*KSNrn|aHFq(a-r(?C&Sh%vcPG@TIOQMvowOWmlPU3-s8C31@4c3?3sL~=iMHc{x zpP0VKO>6Rdqw6m1d&Dpkq1sxlR+A~L*jvd*b=w=Errt!tfqD(8$Jj_R`M&F+#8q>R zs+#Mcyju^PKuoIr0)f{W)u<$Xp3(G(5i60krXJA~1R8EC3P)Wb^sz@vwmI@NX}$OD zkILSP3kr!Bz&?>o)k})n=~3@l+YY=1yRbN}&wVF>l`ef4gYWxhY_-=S$H(*&R>`GT zFYIOuWVw>iI)k%%eYvNI5tZM{j(t-OvXoJZRI99bBlkiLTT9O%pjIgN69~u^3Brku zSYaX^K!_C~ir!Ja%qTBbtQAtwQY(~9#b8CKI-9uL8}E?V8SRKF^e@mdg{S9G0c{tc z7Ac4rKztSe{)eC-xeYzYfH9f!s2Qb(pGqi}Jd?RSod-`NDAa|V`6@tuVN~vBR-Fq$ zc7~j}ii4jaz+4!Zz;_yrRCP#?dJ$FmGZ*a?iCH^*{#zAhl5kDaR?d1R=x-bYEvNA1 z1qK2%pIu17vQ&zcae+XkI^oig()pFc7$*@bjIsOGG9sBpyF=Beo5AGzUKvf<_td=f z0Y)(!sNTTB5rFb*9RXVisGY1$^+23$=%jTKhZ7=3FvxS-p71Pkl`U(rNdn8eFAolYodEEtxDg~+3L>!BR*X`ivC!>pJ zZgwGV=>gFOqXIH|oN^*QybS-@7_!dAYbYG{rK2{CE|9H+#^`%m_+yg(iKumw7<}Oo zA1F#rtiA+dy&?G({wlWpP;?>C{eX$oe4HeC0o5ASeqBmU6!_8%*!-wP(feCsF-~_p2kBkg9Q)Qy5x9Nw`z2NNI z4-&qVhe3@WBWmlEez#0nPZ!!tV#nAXYDX0QGZN8iQ}`47$ohlO=aBu2p*dppmE*Uk zOS1#)niRSbuQwrIC~>#>0Z{lQs9g*keo5#g`{X$)JcSCah2E|0JrxsaX-$V1lE#d< z-qu`YlZnxz^i!SySnVCiV}yoV__=F#iD6$4>NCMqv$p~KzgY1*O2z<`si}iqlbU&bNa3df10pRuP^PtTGIa0e@@qz z3O3!Ru20B5#+>c(dpl~DU;j9`319S`S2N~0Z4>wp{MrjlI*$kIn#v2rQN@8 zy|SEbUWi=#n`5GAg{@V&|7R(zA|<~)p!42fvQj;_ohAhFV-C$9g}u#9cz1Pi$#IFc z@i%K*b}n~bkQ>XX|LdiHIWS-LVounnL`zC6#`cNTpA3FXU+_W$@P|1z$bt@9OU zzhxCO!)N?NmkbEkOE15QF#GCmg)OPvTh0U>+XCtbqzW(17MQfCkH+o)&sh^B$=N+oygb-AT{}Ey$;l}62o7-H?&gV80TXXnOdF6M-ZEqa^WY&$}mtJ~nRBR3$R&A3HId<~= zV>RI1jaXrE1-DxJqK_rN8f)J^@O>WlS9mk|&iU<)8^agA`DuwzXIn2J4IaLG7LCo6 zfIeEEj$c)7cz`ryaXScUIP)yShQ$`e^_6qh*`-hXQ^-5MSw>Gj4wru#GpvM5=$;-g z{cvKl`N`*rdY|W)(a$$CP^zH`BMjrFuXAnj;5~T?J%^>(SAU!5m_FP1Fod6Nnlo+P zS{+B2KguzC{`1Sb=ka`udE3tS_2f$>jgY8OMAp7Fk64VWd;RC3t|xF|KLFkwN{?9N@!4$RfMJ1Kv02`M#&M> zWr`wH&DlRAxY&DsuL|ZeeX$R29ASI%#>t!0b0{4qy%U#Oi3lk_HzFx53_4^Lax?Dh zK!~r!pCbc@EmufA@;BgdUbix}21BcrdU#mk%Rh_VupIx)usfx~-C)!yTs7(-6wwe? zcju>G+qN-cf3|&a zlxz8dJoD=8%c;)*ULz@k)d7`}6k}n`GjNbS-sFHW7({xK!iK3FAW~(+Ne#A$PpS?1 zDqar9gdskeV}1V~`YQBFJ|}~f8#$IXePd9EWK5Om654Rl^G(kS!YH?UpU#s29ZL=T z^2V#kQQTFv#;Lq$8?9@FN!^eOlrl@La#|9{!Qe}@Ff~~dH~#bS1gGoo-n?2XK0MC}3Fc;B)2y0Wu>33^ zEs{%66So2bgkyXhUNyphXi?g>947M4+hmK${tzI7gP@gd=n@r&aZS|+7QfbHnI%%Mw3Li zp)k`Dh0ZcPEEV)ULw~*_M|od^EPrjKtHZP^8P5U9eq#uR&cEkG)mREeyTYfBy9P$~P zd^v(nthUhMBy!`w} zB#t$ce)hR3G^>g_vUG#7}`xVQS%0Bis~5Ial&$EQ~lvN!5{1Iyel! zJ603ig0^`Ip4&MY(QP-L?e3Tc84u{tCmOsNaSWjOsGSb}g_ZrcB&47s!}hh485Uiy zQeIP)=U4ZSU-6tM*i-Q(Y+#DApd8JR`=V?ifN-9k3X~fy`9uPLOwvf`l3Qdi*kJ2k zG`n-9w~4)WuYQeZi@2ZITCVmyQ{XbLHP*cE_fcn;-%UAsViA8noL$N>V!V(NbJFEl zs_5sXPJj+TVy4I{ESjW9bVq2{O3!}fO7Md65G0l-z#GuhoN3rDLwxr>-O3ERP({o` z%_=-$f$Ps~+^aE9CZxEUzyd8g$R@-Ip^Zhnhh2EiM}{CLBF6WG5_K0+1ifWs znP4U^=X<7ZcLzR^XZznY;wdqlGp7ONm%fM!5}Ja|6Zo0F z5?y=pSCWi9pMBJS36fwlukO3YnLqf3iB$9V?>t6_!IY#>tE@DGcg0C!HdM(U)T4x! z9YN4oN4ARa&HrVBk*R=DQC7m99@p1ZO<9tgW;zO|-^-4t2WGSIKnYU|WZ=po-gpXX zUiMkr{nL7vVj;iOJ66AL7tJFm*7frzw4JRqfXpMIjQl-evlynj;Csr-Z^p)*)Z zEjhV@0QVt)C7amby)PZyO-eu#uh{2Qs!(6dXI7?T5d=Z)W^Fgk&drIU0?lGB zYP6NdN9~cK!!{Ci)2sG6{Y%*k2YyYYNzAE5wC-zVs3jy{Uj}Qr3Qw^y3A#s?g-sIm z1Y5^UI0eTofmv`P(cfm?LB=?JI;MG(am!26!l%n(z6JdBg^r)lVpW?hC-z+69+TUl zr+yN!CgP^L@X`|&FpbIr4~Gq*NXo*24*|K(>22x8xIVLodFVv$lH8A$RJrQ&Nd^f^ z@^LqQ8+6wOxVwGUy>`&n^+SNpQ|MAwAB-ju3<+4K6e(fF>E(X<`a#3b{(( z^Mi?OeFCgvIF7O+gO)%pEWf$iRMLdAS|R4b)noq*uyV1`UKf)YR$_burj)J?=sL{f zVKZ@Ynb)ypZ2M!)S0eO`$t~!_31r(ikUvSe^hDRbMF^WoN!YQr0UbXdoOE!KhK>B- zedWAKk+_dL0COb-!)KsB6L3SESXVV`E)BcE!F*$)wYd0cy=zTd0=n{rJx_omEQjH7 zhaWuD%_R^n5*sK+lxL&(Oia9CJePrKs==3r93m@WUIk%SSm=2UralBIU!+r^hh3$i z-%>F@nF1n9{LW90q`UY`1qyzr2Zv@6^` zkI4yA3d^C6AOOTd`S7Plk)yy;?v)}QP<$80pX4Zdh7$JgLL#36>}6eB zBB95)xy5@RQIIQ11(-3SpG`L=iHG$jp8i<`?4^0ka)rdX!W~;-@*LzECwr>#^kE1w zq-4(~0Q;VS{>Z(ug43<4jdrJDLMPB;45yPvk;!gktg`jZzH8qYXmBiOlIHOVfZ=hk z@VRISAm+n$ho9HcsbGDx4}u&7Vmbxsd%a-zjeQCo^O=E3>cgxuFlzt|Kp7`VMLti* z_^qOiMKBgo0`EDQLwB~>!Z;b7e-Z@>p;~MbF>e`YjpZwBrinZb9T#TLsL4%d?~%Jf z;^!D9?2*PR~gkzYnM3yP20XW3oD?O_3Ni7)V=mDajVH9XS&6aCJHi}|wa!^zN zu?XPsGxWacM|d=(H%Yfu0OBR0KnkEs+$-;?Fwr-VVJ5zp z;vmaGzOh0h?7&I1c>I7{5+ld>*WQ~0n6qq=CsBGo#T;&LU2mshzlPWeH30KDn4cUp z+fc@vb*ssxU?8o)Z=CeK*Us+z$TiK&X0Sh+3 za=pm@RL?Ljq?w5y!yW#->(exSGiXfTpN8RY6VU56V8Q_2r~uf`!+s;ddz5ii^y9d_ zOz^2o!E|X*`k|AXz$&yD$oGV`#N#tM|-gS6qqi}&+VT(|XL7=`Q6}EryeAnp3 zA5@G#(Y6_SbRMTENxH=&AjGMS?>w-i!AK9KnjZ}GDJ76%9QHNOSe7O1QG>vz?P+}mL~W@d3hlv? zbl5r%Tk{M1h>a?z#iHnS{7n+P_(TXxqx2R9NOqUzr6n)mATvFfMGhv82OOhgEB9tm z!Gg1`-l*&7$Y=8|0FYe*+;50gAd}VEt$$Q>Jq*r<5rK$cz`s}b-{k95{X$bIPdmR$ z-YIDjWfpzrKyXY%(r$n>k$GJ=t}NNPi|vzh7h#);#8Y9t93<{z9@U!lI0oCtJr(-I zy^4*hqq@uU0B3!$MV$0MOGo%rq$H!TIPVFl2{>4a2_o9)5`cNLj}^D{R2d*V4p#IN z&3)4I)acx$6dRN0$}t}+yW>DY+n8-8a$OBH%)@@fLGTnJj@QKBb`e%$cDNxD2UClG zGjo+3`8!4N%^rI)h@?wmQD_NJ(9I%TeOn0MU67h@7ITCSg2kXU>^Zj86M?C^7p6% zw$LWJiLRk!FMO9MBHq)&vhlnP!LLJ)CkS?*gJdKYb{}W+WH!S zcXrSQ37|_14=o>@Dhb+}j)`PBgU6kBkM?<;2+5?`);$Myaq=T+E<48_tO-m>vZHe} z+boHv+q}0ACrqb<3w+8B75ENZ|KlSKxVuh=$pWC5&!}RH*Rr=^H0hj*3)oS157C`xwCMcGA1)PtWxcZ8my`MGv@$ z>H*I(F+Ztj&Zvl7Uz;Zl6V(hHGZ}9PHVL&b-ezK#SO>)gCoON{@vzrTJGqW zTLr5&_u__KS;|iP4*(*Cf*qwJcZn!n!l{t5Hzsq}%`_)(L5X#J9P%8H&3Iqd6{jX= znXm=CLpW8Fj6F`CkgEs3W%~h2i7MsTA)<6E54*&LNHVKVv;%{1B3wGe6J@X=jHUdG zwJk+T^&mD_m}tLAgQ&^Y!hUd(!&_EgnNA%4=riXLFYGhG<(;gllAUW)w;|`@({|gW zFoh{p#PiMS>9TAU{kz~MU)QFDv#x3-A(4Ws9=4ott|bG|A5VJZ_q z6-Dzx-$M>4gZgm}4<-|T0Z`(k^n4cj-h-K0+JhhU*Tz`Dhww(H^E%QD__O`kE`q^r zj2`ClDsJ9-IwbNW1~c?*!3l}I!~ixD(6<=C)ivWT5eSF=ZDSZ^`2?l)a5UzvSB>|_ z*fh*M6aCQF%GkVEPZ@5Ir6ZG#@j~VT2@n$ ziP(NP^SA|lv%ltqlmnN87P&MWIC8Nx5Z#)iQ}OI0yAlaRPDW|L#Q~m~PGni)r=(En zXHBOic>rtmS9ro~i-Uf~%}M#dNRz)g#9Qdwl05}qr!U*z*i@m)1CEwm_Ic}zy=5*V z%R+s1O?8N}sWCrxH|Mj*;`?R+bDjqM>w&$==-&}V-?c$jQH39!6|SQS1H_)57=QF! zZucp=vb{0snV;pJ>!;^=Kn`H`gGX6S_~5y zpFD>ix@n5h42it|zL%Ud&);i>8~!vj{Ty=+`uovKVYg(zM?X(RuEcf;Lo=yXHi(nr zEW|Jj$D{v^syxznI0cUW%oOQ)XBHxf+2^~m*o_cT-?wjh=QSZ4Kk_wWGrwxdHb+)} zpiFQO_2OlZ5663~9_hTcm;XUGg9UmVzrqgH-FY-?c1kh2+_3B6e3OpBeo~S_F2^xh z{`ljrs1pmFSEOqfj{IDozoWL+Jz5$PQEQnjIg}J-nY@(h%%A_^(z-SLJnoUcLu1Js z)?7;azm7LnN4hhF$G%>4&19rvPTTnTLXjKZ<|h@kw;roLw1?V$<09_ytmn+UWixNW zyCdfBVpVzdWs_efG`;z+xed~(_Ke9#T5=(Oeid1ZM{Y9)BEEu;L51J71cPj5GgOe`chw8pXZ-B^nM5J8mgp$~;%jO&s64)S71@7Pz*Jy4XPT}&Ub#8_ zx*Aop`$<~$pX8UDF;gpRDcU0qeNqLN576}W0oB0{vK`Mt3okc*9?j)mJo# z9|Z{4{$he==dNnq?Tz}hJqX+kwIFW!*=NrO%L~FrV3Yn}?Xyz>T^VP`BcbwP=A>|i zXUF|?7238IUor9jgu@-qSbgZ1NNJO32A|n?v>N0XP%;_Y(B~P z)c)?9j#-{w2D{GQ2$74AyMrKJV$`vXh>P%I)OJ!Zet_)3roV2Pa6w+`BrJ0wz!8fN)VUzC8`q;U%>R@-L#KVgk6=FARP zbvTpwyL9~h{}KsT#q_C5PeV0G=~D4i3N=Y$PITt=iv54@f*n75?M+J2&A4+zS2y#r z&jA76a`1ENEyjY%m+2F78=f##0t@JLo~i0MC{EU<98#SI$$ev_>6fz=Qw$gWlcc^z z>|^rN&JU?W(gQeAwbAHJuVwJ`PM@LoRf}tNwtK%<^*9|P0`CnaOTkC8Z@y4XLYpf2 zZw?L~Z#{AM3T{z;Jv7a*ygTb6vrEp>zCVr(0OrxVAckdJ)vpcL4gP+Rzg{IRX2Pwy zLR|o>hk6;WTinQ?JLnu}9734mOZ9F*_3nv~p@XE`8@JgIb%ww-3e4RkuS+lCj;iz| z=4_O7$vg}#$Cz_ar9;({JLhsRf0nbpJ&H}v8w#E`;_DnwF+_Y6oD1DC$vogm&i*pv%lJ^ zlA&QgUJEl_?$CI=dx{yu?Kb&1dd+a_iLkkF!S%uATHV`pben?H;mEw4dz>(z=vl;% z%<;R2zl6j!*`}%Wlc1KdN92C=Tfshl%8V9FR=-#e;U`bTuVWlb;WzTc_JP5YIHa zLQ*TQ`_h4T=W6@b%zx%Gva^&_z{-O{&$KOuBBfVt-1m1a-+waln%|!j5`CU$(Q;{j z+Y+0qd{a|%|D+j$%%N#wuYVyy;EGSV)eryVBQ#yJw z{y|sOPry;ze|aEcy3!4vXWE$|+q%E8k0lXaM~&D2vq0=+B8 zhex~5A5u+O-;f>%?=ya}d2(OX9@jX^m+Qw^bMY%xV0p@{=~QIu%>=6S;osV@moAXK z;Uuw;}@0B)F9lHx6Nn+*O{-a;(Z0 z4uwZ~ZplsB6#R%LCu3q2?ZQ`n!m32x@`tuP71Mjo1l^JI^+)9TsJVVpR`}Bfjk4Pu zp`PBr5r}kc$0Fl&O2;BdHM;)Uy@o!M=wAI0O{185m2rww)!zW#?!7*r;wIbwoo9g~ z-oK*4O#DY}Q&`8Ol1?H_|23de)dVOB8r1Zr$SIcwE!of9c;lY}Y%FdyBJYHT0&QAZ zgpj;1lc{ZKOvs4g`N^)XG#E>1o|H`xv_yDgP(V$#U{(>*3O`ys{XN$|+F>LH&zPTG z$h@xjS+*c2M!X~-?4oI`>@=&ZC7O^#imqm3tzlZ-{Ei&CxBq^^FDjcto_{51J;v@?9wl< zgZy>jN$cqvJ4e04dvP0D{xxv#1Y2o0HHHn?RsbwxB`2j83^>=O=uRQLOp5~=?ZR8jJcMipIy2N5DQ?88jszi1Y9&4$WI;V@vjP&?v95a8 zQ&~Rnyd%lG%{E{hct8zoq6St~OXlaxzo_p?fe-Q5WUh|2I@deAYI7JG8j=izkLuJu zJk*I8+w&e_e>Giy)MPjjY2T($We_V(Wn>qWJby!W6pZ_f_&Tm}ppm$%CyWzOhG3KY zM<5ZKmX_gV_|w&6{2a*})ycopOC*{(ric%oIEMrFP1;WRHypndK8(CK+`n8c<1N^G zO1ZVT=PPt{KLDON(r?KS+o4O2rjM+{KdjTe72xqGv*)d4tM`U8Nr+J$$1e`)$)kI| zDQjK(Zncwu*z>vc*{sc9(>>FF(g7-*8w+9|hpZ9eW(ms<>!yrDi-o^aj*56X<(4@A zYP>IFyk~qF^_>Hz?WCHg-@!BJcC^|lj&r=J<0;FA_(rE;)G-CwV~U!`9Ea$#rR;BD zku@7w0x$K^pENCi%2dk{=t9?o?lH}|V_IKYu>uMiKyKwXOy9G4!gFl@gAwsB$Mny* z8eDQUe2S9|Zb$y&!j=w4uei>aWVMRA z$(y;^R=C+c7OddYJ)#0KuVihHJ>@l3nqnV#*Lq3L$V=JC$+shu(y zE%Xtsg72C8*OP(v%9HiV|5BD2tew^Fnf+mkuIY9Cl2=K#mmt`8!ECy)XR0XJqjb*e z<`=J9f4!I=$Yt%*S#zEhXzv_Lp-|k&M>|JuzyK30$ z-h?*`?b9IZ^Z0?=!*;Jnvg42ae45VqG+*-Bi_gXw8cNx`M)M97ewnFr_i6d!^YX6` z8|}MUpAukm^{N8=K>yVMQi?V;t<7q--Osb5!guh2?<+r_Lqlm7R@zfIneqK;Zah$5 z_RNNj&p^BHxTD{M-(1CCz(#*=hcI#gm#NK~s@3xw4Dy?s^PB%Nm--ZWwj>KXlc5`X zBi)b>o}KV1{$cB2 zeZ*~P!cM%pCqMl0(D&jm0%S%O#{U8=)mZ0EVA{kC$=+$HCaSFY31z1fO%oy?wTU4T z1q#Qf6(hV<9-i3$V)4!wx<}}fi&RrZ#Q@Mh?*npy+FF4(#Oos9urSXOHLaPQ;bS^E z9)U(T1Jin3d3pB4)OQB{uEt*j5C2<=IkPlYapEH+NPy`e-*K}@eGhU9I(j+C=Ixl( zL#jqjko}7whxu;XeL=g!LC*hzDE&B0HCld1Q7!80SANuYM^o< zc>n;;2k;RxHY{dNG90gQpr2LQm4;LLpF+B-=bD7hsdxPi)qS~yBbhR`k81`B)LifR z4m`g7>N+uSu-x{^9V;ny-<5X*t|7uwcyVFbQ%`C~t8EH2{01BA-rS{B+f~>-y*E)M zOV0k?`}DrY!zF)+tlgf4i6^0N?)kkE%r7+4mIf>AF9bsUc0aDpz4AEwA|UXU=mYx} z)9A2OEW1{H%3xLhh4v!5Ag%!xcFBr??8c9k;!mhx1FT2yQrYmw^lh zBxfB8so_lfsxuD_9SmhNj##Nv6@+z$4Fm61yoz1yOi(whv^jWQADpG=M6zMTUkdLW zkWTd%La3IJHNsR}sFE&`i5%^$L+tdkH^MU74gPzhKLMuKsD*>LS?ON_HlBuBEwFqZeP&}H(&YEbEgKSo}W{1>`%a0c&zH{x$o_rrFP-E{vw4+XYL)Wb7NO zcB=~BfWb(M3GV*t6nL#UZFFYD^wF|L0n(iUb{^UuYC}sHJg2=fHaW<5O?>U1q7*&) zV`?);(5ilu_2!ZFT#nWW``^Q6ubF3DTb7D_JYjJqQO@SWYQ7vqczr>xfz!%<5p+vd z^|cSbzm|c~7KZr)^13A@9OP{MV%wd+bCj9KZX|!?|y>)9X{M48HF|dlCU&vus&s+^+7kBmZ}#wjCOb} zVPqjQrjQ$*)g|*$qR;4sOKOcp4fs)smr3XM>`220vWc})e&@FH1RyJU?n)9E+1)X* zdLKM1NIfWS=iaidmY!jQk<%WQY0H@SW1aKpBBNZedPxU3OLxQ5k1sJhno@%&Clo6!@tNb))E9kEDTuyi|sD;{UD{-U6fA6&+(wz zExio=h@dq2#5`Gk1JINic#S$l=r&;zhNM@CfsoPszrf#+4poYKN8nPn(NAnT}_C3HR`Sx{I3};Ac*`N|!I( zxvI!>zLak*EwXMa)EhJ!K@|j0+PIM6AW@50wu8?Lu8=lwQkNe*B*qqWL)WJIggU`< zQ~5&Lh8BhToNIARaF{_&2TT;08&$pl7ED!{y{+WKnH)N9wYJaT9^;l6ZBfS39wrEe zAqmIHLMfhV%DSd!3e=b~ghZYC2WNy1soP~3Tc)?L z>ro10&AxO9Z7NwdpBF;FX=R*b6*t*)h$uaa1^}IgQSuU)6r}_NKy`<%vO&@b>Ao*v` zb$h!dt?SmBtE~D62H2Wn03=tHbodw{NAV-5PUX~uS)<56Ml|>CV#`r23EJ4vf5`&K zKu5S_r*FC2#C^$&Yllyif^JLQyW3o(fl;5%`ya)zuokRVLj)bBbYk-uov50OJTaEV z-abyxTj6uZ1NLpov$~y5mXqLQx`jwtEm`VcV!C5!CuXVALJVG+PM(qwahJ&TvPK{r zV;Avd46;nhN|GAfQZ(~kilUS!Q$xrSt6_5_cfUf0K{vpf$N?!RS0Ws3l5n1MVB!fJ zSf5lS>UKF*~JDmrzm^^_x$tVWQSrU^)bbiH75dv`$+le2S1qD(vl2l&B$?wGx_cRwd)chy+Ck=E;9WY7oqpk<`Dits3zTSLyy>xe zu?Cd?EMMwr{j{zl%jeH?!hpW@VWWj`7t{p4iw)MSS;%s(;o?W>shVQY<_BHLd(K?y zhi18u$yKA`Jx+b54=cZVq~{#p!~dzn03xKbPtCcvuy{F#&IV@yL|@UNFTKJt{Z}kX ziqvBGZ4(tpA}5cn5Fm;n97vTMqW;YzcER`k*_XK!HPK44)*5uf?VU<|bqf%bPlNV| zoR}7Y#2iJwqN9E_Bc#uv>Vx*F<6x+MdM_1)uEF8e_PydHB12IEijF%^xR<3Mn~s{l zPJ;wcPZCg_I79~nHONE_Fi<&kkSSXk_7kaXldS8BJjqDDl?b|l6Z}rD!J!rllTAF6 zbvy+-3S!9sOVUu=G;~5Qw1^uVL&dD|po(0fa2(8=M385peiA}QMuB(e*fkE4&w;E_ zvDZ^YWSNK`JWMPAIC=iE=yzZdFZvNrlhgnlrD2z-m(MDI@+tbed|vtv1-nEz@=Y7H z%hu5?MCW-T43$7*Ozbuh`;EH)Q5811pTK9Lf3Z<)p6)L$nh6pcW9j6^X8a(b*L866 zJmDKZjG96*u@pTmCS-+{!Q){zsM^Dm|kEX5SieP~aJ_`i4L<|G2_nrj(2TYGj z$3Be}#D%b9bYD?HyoR9rRzR8c#Evnp@p0xrNX{-D`;&utM6*_92}GbdzbM!_n#VIm zP$n^#;fejo(JB^)^BCBEu09Qn`Nc!WE2hS9Atw$0Uk6RmlV>9=U??XXP1N_W zq9(NeUHKRuX6am(a{+dh74Z8i>=U!_>5lm=fQdX4k>-y0wWYC3KzxkNX{YYrve6Q# zo|_r_Re9);U5(068(P|BwFa;b0Hj0*Ir6YQ7t0-a`C%cjb~>tw1Rc2x7tp+3(NJsx z{Dg`m+Ewy~2&9!yHN8bb_C}!|5`?>Gs8WiV76bYScdLbECmFiu$DN8Q03s82d2dO9 z784PekF>jUvzLh!au+e;f-VzKGI$h|hPaDEbuf``Y~?u-q-m`1bsD^eA)xgl-MI&~ zX|R{o1lXNk*+UXeqgTnUJDR2~kdC$NIhVCx^LN728%1?EtY1P0U%tt;Q z6R@cjN5F2PXaprM8F*P?vDbDpoBliu~VhO z<_L$mL~EyuYVLqq(;4(I0sWb}zh%aV9#Wt-ZS$z*-^z4u<~ilBnLIgs^(Fx zHOC=II)YWwXSurTqzri`TmylfXKEcWvW^wcOKp7cig)KH1D$UqLaIbBpJRT9BWk4T zzgg7)3qS%n{U>%%o#YYc8HkFPmp~1gPs?o*C}bIM{+%RL1MogGKg8Q!mX7?v!DQ0! zVDdmggoI53<~0ZPo@%p6DU_t8^B8D00QHs{JJZXXWL@fZA!~d7{@mv$%;U*|85j%tbo|Vwmc7!AzYsf?7WT6IK04Q&-#I9!B79 z&%Sr}*&DRw6Z8zb`Ue3s#?%2@*~hRbLky5R9pcUvdUg~i4M4Sr_)1zZ9<)}kaPGaO zLv~$&{XBDlex6N0TTgl_=a=#rm`Ms5s*8~f@=9V?Yo108;k*Kakk9f#BW&?aox}ZV z(RKUEWfm?Uqn8gFfh~yO*y91Y7f|;pklbZ~EcQY>3z5k_fUib6QGoNi72j|-cl!{k zxVBzmye><)pM*rXxae|Vy{@-l7M{C&4@3xr5W{=?=ej~n2-1%R>J6&sB}9qkfmJCm z0W0+cNyv~6PGh1vC@>-gtVV3`zl(R89~o)26}`d1 ztg=vcr$pqUJ%a`DYac-n4RH~UXvo-eL9K3_D`X)GVebo_ONX0XL@Sb@AF0>{E(EtI zJcN)}7UCu`D!A$lM^H!|4!jCecJv?*lW zMOLpT7ro5~pih+dq7r-g0EAQ2eZ|`QjTHIKM#>l~^(LWi3oC47U(nI(XJ@67Ou; z2yCRAhU8gvR>MgbNP z&Byu)L#DQ}T;aI97QivcYl7}+W$ihNtAQR+5aN}-W;j+Z9Hfk0q9DAP5Ko?u&vo>0 z9$H5SBlsHLAz-BU^(KU&w>gcFJfLxSy^W3{hmn>^tNn3+Jh}JSGkPDM0lmo&L>DV* z&v1K3aeYw)ceFIGS2w}zE#rSlA5kK3U8sEQHli@{*)1N&o0cC6$F`H)+7Hy-F~P~nj%!g- zagmd()1psYO`2VWjxcST3qX}M2lzbUnL0!g9md=74`-=gqC50Q)1KiVgKJXnSKImk z7u0#e{X9g!5VMJC4^4vMR@#k8p6xVL8Bv9l*Sz<`g*96^*F9)g74hh|@}@LukcJ@9 zUm7xCZ6wrr3K*~sA7mqac^xDsw2g_%A%fJ|VA(ifUq0g{nIx1(K`pw0l>l=+#JK}F zAzun?^b+(S1NgN7jrTl!i!)J1v(hqcxJixvNQ~HO(=af-{V5%l`UbPk(pPzduF?^a zYs{lk&i$gHF-$n;U3bX$+ux4BCAm?VMDtRrQMS77EkJad5LuV!(T6MaraF8dG!Hk` zeajs5Hq(zGAON9;;=xG2CD@GbR!aX)Smu!@U*%S_kY!e_3dl&bJsKRnWj10*2> z;0N^YqD58K`5A`H#wE`fy1q04{)K|Q?I5yZXfQ%hR;8TZW}zNi-nnQ4Z_R)d9XB$p z?B{ZYMl8U1o^V{Ehcvf{$AHT^fhGCeEFK%ddgE15-fgkWLT+;~VKnF(6FWx$CQ<6ks75&vE<$<0Ay!_1e|jQ|a=KBs zl!T0<0F4d-OPTqyUQdM4*fpF0Wc$Gy5v}hIU14Cj>^xl-dIyI#>@qjb1CHayPT3+W zLxu5_^hIH;f)noPSFbJLttuQumT_#7j-8~vQPR;JCoN6qH_iS7;u&lIOHWdTrKM}+ zIp`|5UR+}FD}Y8qA=0V_Au6CdT@N&W^YO?uQk;da^+YtX7pjf{w{)@lA6$z-A7+r& zIT2o4t)KoK0ygrQd*fw^CN97-PTMGFBUw|lIK|e2f$#?i=sXB!ii>b4N?uJ^;_UQZ z8~Bl5cqe8vp{cDBjam#t^$9)#>8NsIO%V-s{{b#%duC4*4iq4a3q>;6P|@vxZ{o1t zd#vS&jDz2UPg${j$SJD>J= zjp5}qkCUgPc5s&6-M!>&n8dt$3JEy`5X9^6Z*!MG-+@~*Xsu6QYp0fVbe#dfv;Mcy zeAK@v7nQm8lj4|&mY7Fn*RF^c&mFmYRk2fR@vGHu8fDogPw^M~Nyt6!VJWAfxxnIu z_h}*9-4~~)&dr*gaq_L%iFrLUctw@hR_*fUzM9=XO-tJ2)Xu+YB@m3w zo0!~2$Ji82N&J^5t2^z}*E`Y{UVGTc=mNH+YjOPR#o1UQ_(A-)`JFu?YMXba-dm||MLtE9HioXO`(4ZCWavMOnGsL`QX_a?)+s24AgrXJy+fA!W?l;_zsSw& z6?Y^@rdC`WGeRn8_C5d zu6&vf6_>;Zu)}9WEf_H$8?M$S8xw*m*6tYw*zAAQt!=N_y!_byB85-?~J;OgjVsB}G$VR2Hz*Yu(isqPo?q=a8Y2V}2zd}ZU{ z{wTvr^ogV}a4PN;+ydp6KLAdZqQR|hxH{pgQl(OGi(nVJU{P`xAt z>uj7QRRJHI8P>DMJ2dQe(fLu5LUQ2OfsaDudE2xsF)}B)B6^BbbQ?nsII3k^E>ov7 z7#AR6-{{2L5kl;HqFO4J(xwfjeho;=(itB}D}{;u4{P{u^KtO?qsARK;$|d|n*A8M z*eB;v{)Z$IqYb`$B;T9_m8Z4#N7WQRe)dWF*70aXso1Xrs(kqbUgD>tFU+UZ|H})d zDOeT%`~FcbMEL7kGFeE`rY2>qL6EEZw@RqW(C~)JN9r1{q&&759IL6f^2$h66Abq5 z3oF$!WcRe!{U2*@8kN)+xNS2J%H%vNqN!;bshK$xIE9w8rI{J#L|KNZg=qZ0o5jfgbj$* zef&oUr;l4xyiKx2X;)@Oru@&`&bd^|6lBesua-H#>VKEL)km6ze=iEDg8`-K z?^_K|=X@Y{U9%29_0Ghf>TKhWhK@nZ5;E>=(zBloJ@ppTKKOug73`RII~WHlFnw7S z>bCgO+pLn0o~-H@eSKr$w0!5~u?tRDFCr02v%zHvt422;Mc=*dz$8Fr^eEYvq4EJw zG9guQC5PmV0Y=^Vp0kYwm<)-|5(#cF#9g6#9dYc7x{s?g@=8udvZ>p^aVu3nG+2(= zOt3LpJ5>&Hq>213G=Tb&w33XWM$gsW@rIAP{Z?N=!jt$MeLo`DMpBA!qL$ZQngwZm zA5*{PI&9x0>C}dRB1Issy)CdUSNna)iRg$k@3nc9zyPhPfeMlHFKn zI>NwPE8Z@ly)X?G-*u_-`haHjdqLsBmFHnZ9GfVBvR4!DZFiKDYdH!PW!*yC6*q9T z;tfJqAvrZo@Vo9M+Z@oo+2F2{GQ76K|02qH#V!tw=O$5==j4qh;72-U>2Jcm++?N7`DaOk2mt^|pn5o$RidyKYn70lmEAr}u1}kfM zKGsJ{WVeGg9#H+FA5Wo-<{Z@G3;kdZgnHaDyxm6;+}$Pa_6-%wF55qzN%&gyn7R^t zm1Jf#?uhbAAZcmk;gy@)sD(+QwH^1xz6~xR<&$qeWoM=Vb#KOD8H^c&%D&;$iJ!F* z6Y*4kcmA8&)HTLyIH%X7pSq zX0NEiV6Hp(*nBHG$0PoXi7^i0OPSPcAc9$>t5m~pwSA7i;n_`tOoISPD*ec z5km~q(gt_d$U0%@_Pw(rdyl+L?vS)$`?L5HJ0OE@)y?77K0`-ycG9?Od*9e2;~-|K zURp_jy!9?|aECttOTpNQPcQRPWl_GXKX6b~`~b9=V`;f!4=Nx)&ETX*|5?Yg{y}*G z<*fHJ*^iX?0yh&2T&O?Lv=E3QGaFHn!tg5-PDpX-*p|=zd84Va-nILO1 z4mn?4fd_eBzddT@ss-E2Z@I3DGQ`d{qL0BcOrvldHHH@PZ?>;aon%7>>^WTh2|$oL{+ZviLsw88R0WA^(0oB z?0r^c!`U*XTQM9kRt$SS>1J-U%p5)prPXKPnm`632~wp#Ik`L0ddk(pEHNPb^8O>1 zt|t5-oq_PvQ$++_f3)twX^s%^>3Bc~fmv76jrFl03r%ZZZUa|jhnzXMPx2znp{!WB z{rS`rs`MSwQ4Hj+^8gRMl8lVAprOKxj|u+$aBk_9%onNmEXH2$V%b-2xnbDsAbzke z`o+4?k_7MvHry+Yk%#$CxTr#?4Q4j5uI@WvY>$!Y_gjP95wiw5cK~2h^^(Wq9ak>C zrTG-c6=hk1P#>3J8AwUl?4tQ0QI)(M^2grrH;~6wYeAbVl>x116-nsQ<UQBVdnud9VB^Cw^}( zdtfuu;mwbI!?n& z3_fdK`!ve4J*t+TUYoYqYQ5&#agrd@wST!^|L_gX{_Sl8r`CyT%rhAmZZOVg3%EsZ zuBFnjPu|$}j6ntdVA~I8>_)vD))a6wpnD~}oIB?@0)wZ~)#k|c5<-E2_5g|K{WrbV zM!#dfuQqnS{3>O3Sq=?0o$ma1A_ISp1Q6x&@4R znx|I$d*}c{<+cXJZh`NS@)G&g7u4~kIEQJ&8<#GZp_zVZHmk%)wVp@VPi{uW6E|=@ z{F_dzJp^SDuHpdN#SLMc_D=ZuJ8*W5;ZfJ&i^u_`q2++iSg)RWffk_qNOwMxsG21? zM;J|D?>^GxU=@X9SOG~|Rgg+E)RXJyY4TS)@=Aq1iljB5*_3385YoCejE`}6!QEQ1}%$akU*m(E{WZKP|;XRWcjocM*E z8OO$|RGfg(-4xh?XDkzORTMKXeT`EHUXK{h8d(K9@{6cVhlEQZ);JJ$l-mS=HH+bn z0dOr3pauz@wG4A%Ft;q4?=DwU>K9tSPzC=a@UNY)L@?P`lBY*Fhs5Q#Zig+e2d40) znWHYmC_YU%pf$;~Rq*!{uM4-FIqBpd&0u1enaKJ41Klv~HGC}!I77rcy_r)t#x)zg z6U+CrZ6CO}#w8*AYMFk!Y4pSSiJI5TZHHwLB;NXJEiX;r_v8^byBntb3+PH?VU__1 zJcOl6q=WX%3O*u@Po;tMu4*XFgsqj6(P9Ejg`7*F(| zH-Lj=$dZY7&QCJ)#{0g(5))#r^aGaOhjlssh(ob^oObX5{=p4~~WH z;0042dc0I!8ivoQZz`JyP^x){nDD?C?F(%@OJk3v8~|VnfLSVHXuI!g9x-14Oc3GL zj7B6A(mOr!vB#Z>TFo+U{Q9*R?aE$P2t(pn&p7~UwSl`(-(AezM|`rcn|pvF-YuB(785E8`r!C}OA$mgM;gty}hiE>3oTC(7tJo8w ze-M~L^sn2pCNdD%Fu3is<-=o3Pgk!8Ixpw%!f|bBtd07UQQdi3H#7|a;8m`y9&Mm% z4^J5{g)Z5txszb={L$aFQ8z!_y$IRt_w1(s@rtd0TljmHCPJ2j80^jf`}1{t_~7c> z0ru4!b|N@-?qGj?ZoEXRN)-rGX#1=5#SHL{$*AfVmH+*5Obp!ucyZQ{1a!86CDH<% z5#WtDmA@-cTgcLKg);HAx0Xxg5F6rc%(*rqlphpO&FA?m5 zhp2$5DMS%X9~QCZMIsI&?{c0_;QqK{U-S3Gx+plE$_>Wt8c8O(tv ztM0-nkeF3hO1t(C%iLEBYi#Vz~^%%RcgJ9c*U#AW+VS$sJWMXd?f6V+;=q4ZIQ}~|KalBZ? zs|XT2YqC+W%#7@YXA$AyuCWv?{^+T~g&yd$Oz0sAFJ0f#;Ta&Z8ka@kInnC0gfMm) zx7#@;AqwULc(C30I@*={;}kq)nY?!kJdFkm?T$$j$6jKeK9c?-$<;#K`1CMKwtOAs%-wzzy#m?vSF>i(S!BjY%cB;FOq)*F9DdTSq}^eLKOZ+xbUd&i+3 zjAs!P9(qB5Ub+vrvB{9+so}4_&xnz&^|scBKh@0t<_R`m=*uXP|{eD zQQUy_tbiz3j7(cYrGt;+hShW?61hregpQ#MlHdy4HWg6#2|7?1?6Lf;=;ht;G03qi zCkESB?D@5EH{QuW7_IG^zZ(yW1HkfhxM`+cfIaNp0o+}pgkQP3l1DwG1gQNv{3^{NV~M zrBUBVPmw2d{U`<*G&JW|s-m{4bS zI%*xpO1&DJa^(S24*j&Uh>l}1$EfUQ)6rIXX5z8 zoU%v>ZXppkDR; z7mGQt9E6<`@dS?3oKh>Y$rAHsk}3{9hOjjuyByd$(I*a}cRq6Ylo3_7+R@AGbl^-C z4?45x{WCHd1X|(;|@eb4s=uX6s zSg9(t-X0YITuXvR;J~6lAOQf45V7q%|9a?MY( z{<&Go4ktmK=zC0QK)T-Hi#mr7Xn+hS0XwS=q9tHY;_?P6xOzJ*ZJEnGyv&8el|l5i zx(l$hsC=>umc9(56JeKiql3F)X`=fX0Qml8$bS{b6J-p#5E|(Y+^G+@Z@?W|hCT4j zIN5ma#}@b@8t=}1Xk;48rW;0|hq)+k1z^dO+!%|mVa8ID`Q;jz0F&qU_s{g8b09_omVfI3}=L*8~Ew=FWn9;T-wuP+lQvejR*k z?&L=&l{VceG^nqg6>hP(Zx!9QZL#UBzj_SYL6UR#vAVvvsHwMEDp-7VLq5QR--3U5 zJyh#fwn+Mv$1R?}vnS+Ykmr$f!!koQvdi?0#c8GRBtkhaa}gWu5}I_Vya&)h3kQb1%pUNS9q}J zH>p#Tr`%>qpuSSnO*pZ5s(Cuh>MSDO$2kYDaupBtbF~OLa)OUj*`^72luelbiZWc7 zc2c0*v*sdYFBxHe#P!RJ_Y`_TcHAeAOd%*aVhyO^;C}y#qG)+&qPCfgzuWszNWrGs z#Jh(;Mg^7xsX#m{B|6U_CKk@eq%1cP})>3kGqwgv!&n{#26D!8@4}EOW_ceHjTw9@nxct1FRu;F; zdCb?{S)*{q6n$~LOlNF}WB(b?!P&Tf&r`Qb7q5j|Gz(9AdpP$$dty;-@1x~ikraZ# z3niIP*DyOw?B&98%qwaZ*l(YO_bIO{fj9n=;U+I^x?dLr`wb!qd}_GV!S$c(bjfv@ z>+CO=p!EqWw>XHVBTfxIu*G@AvhW`#*{J5@>2Dcxjsp&^Gna21`;#~Y#at@NH@mR+ zBLVR#YoOa`*Y=MOOqK6uJ6Gq*iU?gd+GdWv{s*+&y|ku(1}AgGdenCP^Z50))=U*O z-Xi_Mp~laF{ys`xKa-AG`s*Z9j`(hKR{ES)fn-44Y#xe?@YbhJGVmNdPRrhJS<;+X z;VBq~$izhm?*zE8;Q`H-iPS+OuVt?D--{e84|BEf>TYc&+2lv}iBU*rQPzaFmPv>? zCS5dW@>R^+u<8w58%WqYL{6&ISE*#bRGB%Z@fJ3lJ#U~5{CRW0mHd2{^3voG&m;7> z6{{(s2Qf@XBI!?_6AT}T{7m-p41S8>9s{6~tQRvznma5^zllaXziN~?h`iRlTE?t@ zGGjU>+GVEID(w#GJbru3Ea8&qw)63{{qtHg@wV5cfd?;@2mQ8i^wTr$jAEmUzgXIa zx8B|Q^$TQ=U^vLH07FX3cvINk`xaxgAhq)gEBiaRg2-OEB{<-M8Y2W^2^!14hrWF3 zL5`L4>hKN+1W5C^*juMf=l=c;!6&ym2a*1dQ2j+nBnSuqszUXujJ+yn|No}#;~;Jz zbpTRzz)zL7|GO@pTFe5gt9iI8Zr|E+>L216OTjtg?&=t5;25HYaB3v@YC5vb;pVQR z%jRKXWJzwIev?fUXU2=O_5fjD9ufb)-}?Xhng2f?_}|0d@;}3e@0P2EpO2bg5pUnx z*7MFi{de^PpJJ;KU@C9x|6+3IpIfUbSq>0%*PSd-Jjg?`}8d6~X=Hp8GzZ9=d z#6YeG4)%ZiKL6LTA^}7|Jwy-mziSHp|5Ht-OfPzR5jY`)t5?0;$sAFIQu&(9Dx z@T={bym_sz*WR~RPZzFDVFfvRkfl>=lS6N|czjv;{7Rhl)v$^4C-I3FpsPQxpjh0! zl=95-D0A86+uOo4=(%NUP~340AxK*Fe9dk66g*g3Ssxw$V$%A(TI}ZD?k_Xaa=Trh zo-EuN*RMa_{05@um~_9|WXFoudo*^%>f=gDIQDfL8tu-%bU3(Pw->plJa#$G;AZwq zABszT+PZG`)t-VLNWRQ}`A1`zsCp}U( zcd+4(!S>CM-?IynzO$X36j_nHfPd=k6i*T<0+j4cPZ zCZ_{*BjhZk!{q5YY{RhC(F?s6xJuCd%cE7+%|J}{wpa03kFKsmrTc4z-idBoB_lP2 z_aO!go{N;-D}BxQt7WU$z@ z)6d7dV6SdhyL!V-KD>H&koJDE+XgV2XkXI;Mmx`Hr!rp`|G{?8z8B zdVVYX7P;>8=->mRPM7aw?NKHY>oJqzCX0MEVexQX?on{Cr`+<18H-vMjvdNnSv>T7 z);_!|z1yne`}mf1_0Bid&)qqHjUA?w-!e*+^&=C%gC2TbDE##z#b_Sqt7eoVZz7rP z6M+7QOski(>w(2xaN?#fCC{Oa%9ms))&tN#MSDG$r;-zqGx}*t{1#{7m%?Npuz{PF6bT`tckXL4(unsaTp~O9LpEtl zsBSuX-xSg6$eL3M?pkf&MQsMbC$JFaAYY-O5#eQc&vno-cDZO@b>6N@@Zg%R#=+E8 zV2y_~KZ7oUbzd_{Z-P1Gcyp{MR>i?i*ay>Z@nYNRTNnoJ(<5+y)?snGcf0-Nx>RX2 z&(#6c`{?GV4)TeqEE(QNc6+@K$Pax8qA}J(1PepGOnP25*%o&ww!U$sG*;`s% z_sZM2KKjYpu;V3P_sxKJv@+Lx?=LC$@3Kp{@*Hb?%PXk z>qXz4_K&h#mZM<5gB09Dy$g*;2XxIRzicfG^EciTRn*ffL))&MX#61-EvL0!(w0={EqJxW&CBQ{UT2AsBgiFs>vk2duApmf*%5E8=YhwW+es%(Gwm_MsvP z1^}+7*IZHDi#$VfqmgXlTNJ#=6B8 zJpj~wA=mi=`BtR!qbqhTemLLGA{C)jSAD!6&P>B*@z3a~JZtM$4euIGN>avx?gFgk zsusQ60X*6bck2yOK@Ejbfqn_PYeI&faAq~)}9?Lt;w!HRJZA{jLzDiN9{LW z(jPGxjs*Jm4x0AS(2F@ZWEDbKW1n3-d^s?r82FKwQ}jtBY&j z`?=M0jxo6GNQLu$O}0mrO9dP4j35`-XcXSbeG*^YCKQ=0DaDr>P;EtO5mc}afW1ye zR{x%#a&$pFc+U>cU%3W6gKiv!PXhKGdO@jwNUzlDq81&XO#{2Td1L-}aC%W~pn}v6 zbzv47DepIWF7bxOsuu^vMXO5^xL`c_vSXc4?0XO2p6vM`_tNiAjE6T~ZT5P>i%9Z5 zdYFIF5LHa)dz(-}BLwBx$(8mqz|d1W<2oAmeSYk1v=2vyneG&NGp!D z@UeArRE{s~9bueBv&7BQ9=oDZzfl_1re-sIFD2B6wY^Nk2a*~1t1?`M&JL-C>EM7C zdPUGcUvE%}ZsA(RH~U)$d?Ah_8{UQI_^-n_gdo2Pu=joVmrAE|9w4yW9a0$@I z#5aWi&gVzK%2zKnK^GL*z3)&zSqQ8E{ZouK(PxnLQgRQ+Wb3gVUD?hyDV=_XxZUj3 z7Tisc)#0@&$|^dUx{W|Wd?aG~WYAm8=^N+XC2Ra(5Qh zd=hvrIrVV_%!mr#)QvP?Lg9HRm_S{Xw2u`7hagyi3J|uG-5=>Om`qQ&iaFtP^ti&Q zY0Sn3o}{WQJWfwrAQ*V-Mw%%FKq(!YcoNuvSCtZufyt3J=MKKxl=QnCEg>PI#A{FK z!xuxa_k^6yB51ZKIDX=fadCgC>|9m%g>t?UjFP?TSUa~y=Vp8|)8vL~i z+|4jm7eT#8jG7~2Ka$i#mat|3B;^U_?_|mM8T24I@+Hw3`xx_@uD+FMoLR1x_{}~@ zmcL7%>rkooQ;5S{S@g&%7`?vJk64lA@3p@tQZX z!Y^N0WAm!BW4kK5sC^mz8o>t7n0aKeXS=HlpH&B4E()_SD6-tybqG5e0??5GcP3(I zWYF-^63Q^f@iwOUI_4uC?RpRtBu0)Z(2GPY_AHtP@#+6 zqEh4QTr*_!L0W}X7H{P#ErPhr#xKd?4&|3kxwQml9$y|)T7G<9H*>`OIS;!LS#VmZ z1NF_SfRt9$QE*X>h+#3>oU&p@NOBv%DDgGT+iO0^(J@)YMl!gZNqr!6Sap5PJAuAH ztZFj>2T8Wo%T?Rgv0jm!ja!kGa)^UCS9rEa<aI(Rn61e(sN(~*oOACE16Ld&PKR!Zi_SxIK zQ?_btThMVi@tXt%s?joHqJD@m>%#P81av&#=iMcsfuODB2#$_4Tgl9O9Rj`j1-McO zjXCV_u)1yL3~_!5`;@354y|9HVr{x~RtnD>F?T@H+FPe~WgGm#Fa zJ$GuO-`7e`mBt3t#qF(2sHw9##jBjDyFJn}Zcu*UeU2;{J1S^@Jr10pA3fZ3uIJgg z^rVJV*0I{jEfZgmT}*^EK*xXtwyAcyHx8{CM=cm;x#9NgReBwElY^Qh7{_>2XsE+3 z^Q1*9Y#q@`4ho#2?^vw`Z4s&m-GiNv#&z5cZE(vB%YYU0Of}zt5~%7yo7Edy(;V<< zB^|SA$R&@Id=cOAzKjr*qIS~CWF-|IbYA_m%pO*%g8X)=+5_(nR&xtF^4z;QM%pWT ztivbDrOO*~>w zjOhVnbRGif`z@oCg38 zeE}@GU~Lcc3jnpt5=hC5*EgDS6ERd~Q+6ltsyyUZ$f2eys@Df! zQX84sd-Idhr3R!B)iHmp3db&^f)T%llLUog?m_eDkM4-mMeD>BJ_*M71Zo8I|?Jaka^e*Ob z4-pg9M34xPu=HN+i2>_O?4syOV6i7QTR!;XhTk46m!1iq&>=SNOxwja#X@Q_2fQbwgs5vKU`j_6Vrm;d5 z7=Oqd8kU7L5v>l1w?zz?e$YUVdV#H}D2vHbVvx$?aB%^5D-rWsj6%u76R!dJijYhM%omEXTZE{0U@?`20Ug-a0EaN0 zM}-r>GI>ZD(|sk5iK@iv>h=jnEjOLVN)JfDM>5-#IJmK7_V~_3ra)(x9^_uWB7-pP~PK^H99+5^+;=%h#%6iQ@H4R@3Vh| zV9~4Yt7y-4(<_(WjN7F@t2*Un*^JOxk!kip`<_?ZTAjEwPv*)GCqAsf*n2#D9B$ef zJt&by{1OZ{`5p$FycqC&@$hW-vBTR6TC2@wA@`~1i}c-v0q7?(N#!@#eHnUARhW^Z zC35c=Wt!_X0a{MSOzreLD%*9`{AJDB;ro4RRRmBUaW~%a^#owlgoJo1Mjbl@yRiyk z%|<;{AT{x-0vW1o7#7BbuNXo-6(Y~hKt}P2-_V3{H0sS)px1X)+<7ks6+Hp4)93^S zk<`Ph&~aU+dXd!{X&@Cxw?=5xBzRrs=Q}Q@STo_hD1wssW&(HLT8Nxbpr0MZIM2x6 zwQhPz#7zB%mdXa)dkv0u-qX4;v-A;KmjSvcM>{^od>~>T(qWxp_|Pi(3U8cNCVCX- zE1iW5E6~l)FrUD_j5N0c;(HTvRISgMl``lk4)a0sc9B?dezcAwyZ5_;Xsld;yy<~r z-w&+;P@l-u&;Okr+PP45Y#|r);%^3VxZaBR)G(;Oy$aY7L~TyQ-7ulxI>4=o^n5Qb zaNCsb>D0NN=*8BW_QIbB?`kf(Db{tQflm1oTlW$JqJb+pZC6b@+<+f+Z(JGtXY3$> z9hV(hSqsDp)te7mJo{;x`w0K)+Sb-KeFx!raOk3!ms?Z_Y!AKpTIn^5gyv*YL(^>% z47hlwxZQy;ttzFec;pE(U}$z*kK5;WKM%rzi%|-g%2;r5W{w22t+PaeUYz7m-g) z2J;sleydAq@$nqXzvNM!p+09f(WTB!z8{ zVS4G3jdF=<_QS66Yw&4}=XafxPglF#GB*$lRZ_kJ5~6^f@PoSB=Jb!*eClD-HqBawcYhiILOMf{?k&3(F<1e>Et7 zow#TeB={c+dMMNA@WVmjt>5jhe_La9O0K%J?)q_I*PpAof4Wcq>ACf%_rO}iKFTkv{+z(Q+C}UO zBivJ|E=!D$DgOXfdn_R!^ANDR*iM%F9j~FWUH~Qwlw=|Vc;y!0jh9f}P>C}AyD6SZ z=Aif3SWbpCVUD|5#^x}-$i4GWYme;{u^TrP>8#B2S^s5rQ@KrjM5`vW+5g1K{jawC z(wqw_ayz`O-@rLQ$C_MZ>RS`B5Y`e{zaign>-&hdtsSwqYqlX{$`$rTrx!#x?om{@1Zb zrorJFeUhWzn4ldCT{>hXa2mr9_dpF=m57^|0A1?C(J)T(oiMs1c9x!`AwV!vtlcCo_%Ge*gceItgeN-ho7 zW&i8vz0CfQHf-T|edrEhb-(uIsjL;hCDqPP|L(un>=yO5{=kDkTc{Uz;q1wjIr6!O z2Xx}PPwsyYJQpHzlfuk=?V;-vN;g?uPbd%eGgx_CI&IFa=d!E~ccxy4p4_po6gFcULtz(!}uS_ja-g(tJ;fXN04)oWC^TA%BGtqgtWbEa9n z+lTd&|DAeg=DWN0T9ZQ{$O$l`BWx^?-)knn;jXxIaFk~=?G80eNEeB<31xgPQZP1R zw909KlI^BkZ_Y-cgl8N03)wYQ^HgroCqq*Y=uYeTY{t`BUHW&2c8nIG(PRfQ9sVW3;5dsk|M5&Ta>5Xo)0{9>p*{!`ugy zLQ%U*Ejls^HhnT*H}CSbWL@42N>j>&d>3G{qvAtX`m^+8aV7gBfF+s&ANLRaD7pPZ zo3uS%Y7WE#FMM!Ti!)`@^hwqm&aAn!D_Kn}fw}nfucqF4yYa39=0b~evdoe~3QMtH zwwL7ixUsax6E*%{vT+NYQfpS~2kRyaB#R_@&J!&1$?_l#-Nd4Clb$1aH? zBffalbj(a;F^67Bifxq!a#n+4aIFT2#Df1<4$QYYBfj2kBb&TbFRc zeQ%~j>$MPO-X2$+(Hw6qm3X23&%smpV3R&i-nwn%o0!RIqvu4p#}o7C1}k<`tR-yc z;j!l#{6Rw&Rm#vz-R|cce4f1_`nU-qaf}f20zOegcFWmTv6&_v7g; zrF}3afLRdK9j9@E;bVPCR`9!UH!u?Cg;=HFgI70c)!TR@V&x6Fs5cP0WQZ`2pZ=Y( z8<$SljF@C1)k>-{+OND3ZfzHD{j=D24ChCrlolq~cpG>=@WCCd$)g|!M?8OY5(!Em zxM`TF*0KDhw7maB)Y{Usz8el!FkiAyRr>U{&+7%G|QtvwetV&vd0@ZCOQdO*k8 zNWa!~@tLlvVv@6~V+pv*kB!F8gFU>ivC3CrGFs9^0?tbA6w{{)6%l-m)t~S@cZR1Crz=3Mcu=MUq)*H%j$lW$G z+IU>v$!h`N{T_B^zm{X%CVDrjSH3a+;aaV}>Q8Ytp8y^&9DqZ{uE*k{&mx|2R{Ds4 zk`RWSy3a_q?}1p)9HH7C8SA-xTfyX6OYpGBLSMB9=G6Qsqga=G&U1fT**bFoob*wu z@!s^lau8Z0eMubdzZ01()XQb_oPErZ@$K=Z3pQ-Bi$cviS_#%XB4ayDm11vLS*l%+ z;?Cl${?5*r`B8ZEOSf|W{k#?CUX3O30W+*_GL8u#=53<0^+IqnNG22jA$4Q* z=+Tz@*Yg}j01Xk-iNwq1 z!xosO1+ z5#_jQHewa)iX5vnWpw*WK_Fs-KAu&Q!`F^x1~DKYDFE%oEZV_A=(8HP_p_I;yCJv< zQm_HlO&wzm7ZUI!5o=slU5NmrYOP5Z*6z8V9>>rB&Y3s8z z#Maf)FgtiQ4k{l3%#Si z+^PJ}5nubXzFY>}OSom;$irWLJ669p5pQwv$Z#}hRk8&BrJ$immgfurYY2Ots9cmpwaTLp>n=KNYgX(iO z5ka`>Qzw0{pWDaAE$87R{;KfL_I_4~xJP@EWhergPqM6*L7Kk~jT!8N}RFIXme1u*mU=2_?dfOX|SdLrTAfBse9)|lCGO>cm;tC<&v z#xf?IO_xG73i6V16{#v<^O`W1c6d-VAejk2KnE#Ti@dFi#?OxF-TXUfYcjM>#u~`t zBJrHzFOZ?Xh}&Cuws>$FlNUz^1WSGHR-k2&g4IZ-x_&E^4#qM#5I*qFXjJWgyvVcR zQC;EN9*0|ee6(??N=u}gmajOk(GQiII>kkBu2(t};Rn?#7(*MjKsN<0ZAf!Qkaxn# z?o}S0ymZRej6qN9FJ>jB);q2|zj6C{?-lKs$B(rs!Mida8seUqBLM2c;6ENuazj|S zC;$l2deo^?zBf-#@FYp6l{o-0!n0tv2d~lkZR77&T?%PHu~1ifbos1|qd*Il`3MKH zX1Hyl0-L5;+DqHeU;P_qpkb3cW9L^Y!{h-MyF$q{_#xs5Qng@PG1#<}=M*t%zGnR1 z-W$0J5IHK!bKaQRJy`f3y7)hLyMy^hmf;>mJMw%UdKu!~2ARt6NQl~cC!S3b3jSML_PynF_ICQNYpDb3-%tom9v%3OSU5q!nKQ3I$w8O3EUoYC)cjb-I@EhY# zYByg#j$PZZ>uB&LKDMBcL?%AAKcS#isXRA`n?osgUC@wbS#)T;eLjVttDjF0qQ6lEfKSjCK zVK+ASZfSsr%2Br_0Wk@1GU6g;c~(tWg_c3PLm?Uz){q8Eb(Kk{fP*%#{j?TQw;wR! z)nSBS+A+>H)))0UPmL88jYr7Oz75})N!187yJ)K!P2oLPpDXH?KcARlO93gutG4uE zGzCaAdUMr$ht|KFJ4&6hi7*X%UQR>#+^>80?7**S4f`b*dsGG&mwC3|yioo|Tk!_R zWGA7g&Gok_kJpL9oHw{mf|oC?0X2gkgUU;drFzS}Du1RX9;`#HEKeaHsIOe3%O0y_ z8A^A?^7FJ6GQDb$R_4=l>iJrUZU$2J^S+tZio6Y`c?R9)wseq*%Auhjlrcc@)ui?*A%hg#k2mgu%oTaq%}NS zlGP5k1HIADQ{S%YIjby^ z4y)RRYI1}j1?&P~-$JD@D3AlC9|POoaJZl5t5S{Uo)1VtBtXnM#>1*K5(2^jJ2yNG z5&f=)0A&(QiR5t^wm2OueS$XvKng5aIonNBp*yj+{daeV)SMWg0P+kVAiGuEV>6%&t;9Y|tyWen^Nz47+Q@nYu zi5YizP$yHwOHnkS82~RTJevuNyYu=1RNc7)sJ#EUs=es1CrjB^%S>5@@0T+Bj5Hs$ zCc%c2#zcT58SfFNSxvy)Ay#$K5;-EkPm?nqX7w0Sazs572?(>)dG4eKL`tAPS4L}u zOk95Hj+7AS^mN~&hyyfdvVf_^1W;(aBl_Go%YZ;!SBk6;<>vIrwkZrb{l~N#t(am?t^CWgt&w*FY%>YQQZu%TACiv(MPH76z z@>7>M^!lmuEPDQ)nlqqg3s?vpvI&siHUmAK&ho&y1<*MZKD43sx`8n7oCTLcIUG`b zXETkZIwebGk8&K)cjUHSj`|1q#q%=G=pTSGR8dFQhsDsV6WH9LH3euY_f;!=4{6^R z;X{~igJQ?Y)OlzOfcu~azJu1wlfk-A@nRWSdWu@__xU@B+%*2kQpfh7if}fAHQdM4 zB-J{a&E=9{dq^o60$wg9Wlwj0UdUtDtu#2p{C=AkXQ+yg58B=t8<)o(}##*6>l+0LWk|0Yt4u`;`nI9PlX zH+??qe^GSiflU8@9N%a6W*3{>Y;q?dSFSd5=4gZ@G^IjvL{g+}ZlNVgl17q{bSR1X z%$-zINTr&RkZN*veA{oo|380hpZ90)y+6;_^Z9s&CjiFcqq5lLNLBXAgU!6ArKey1 zKD&DF7Pa}Ix5!CEwMl_{P4CXpya~H(N@pKmmkSWp9*-)S$*E<^LZ7C2fYe+$)2Hq~ zrLUQrK;nPX%al4;I0tI=Tej))+$gDF&W)GSG*M0nB$r?t;yjf6{C&r< zl{K|r*E*q`bJfcK`*ZbqFjiGw>XNz25Ot(gThSX+c!l>&V7lYIO3 z$66wbDUdhB{|C!w?68gE8}L6Hl-;$la7XTex!w{cUIvn%W|vpZ61y} z6EtdMHucfJFx;8mMkjv{!<5~)GXa5{3aEzkBqtRxWn8G@pIGPsqFi)rV@16oZ zlaPQaf?op&Q%Z)Hs`jF5hJn8-6CG!Mv?O< zLuWcKJhgrobXm?<&+vtp)%(cXIL%V(<;P(cuQ*+~2I5}UN8Mo`m^E#426pcEt@$`; z)wAWy7K+(pin00A*3`$TW*F{m=e%Rkxd+gwps~vOF>0R)$UMDJG zwa|s4G5KvLDtTAf2uj=i-#xNgt6}|>xZS^_;_PI~cHB7`2MnngA=!$&{VI&>qxZOJ z$hGiCN#~r8vwRj=Yx4aCf_9DR-&Sq@&LNZ*`bXyHr0t%s-@V>1Nt=89w&On^lNc&b z@-0^K_kr49=3kV4M7n+F{FBX_|66){V)H-gudk1!ht@yOd??-b;ug@Ez1QT7$20Ra z8LGzdPC(2KawZF=+08+rvEl@;21Q1 zTD2mo)a8fBIahd1TiR*RYgT--V4wY3)t5oNa+(rrSj^fZ7G)U|F?<`nV2xTIKCs0l z^N6GWS}M%2pP_JzpKY(BEsH5QKQyx`Tr5(bv2nBW`I%%Z!01I4x4Ot;3YC9#448%k zzQwmnYX2%d|CcflaO+lSQ<|>v9>XWn9WTsn*3|2oBwl+G`t#PghkrjC+T~u~bWtLmx)aP%JY|P+ zXX%hH#r%uk^$XQWz4u>UOfN~dumSwely75pLXZ}wGftO{My_d^@5k71khp|QxCP~? zqb1>a` z22%ltx~ZhbV-TEjHE{S{WCAC@;w)nj>XzaZe2KpOLEt20jSUEpQeWNRZ9!?`W45mS z_(&;8(9#sZfrdbKTy~}5V_Lr*TwCux!T_-TXeW)rGrSswmF;N>K*E`RrCPi-VgNC- z=G+C|jH*)2)9WSyw;Mv8t4)CdHdKoMj=bK7ZMnkhg)v_T)Tb4rQ>YNCBY%=7W)ifyDY~s2gr|@^j)E{eJ z-HW#AQpVlP)RhQHQdFzhC)PCI*Mi=q_Hb`h&spd>-=tbnlnVYBC)0QC2<|dF^Ths> z733JI?;ClB_KT_r-P@NHW<4hf?)1E%2yOH_<03g31j?$NMhGkFQhO#2IiLF+6P41X zHYP$mS*lG8v*}V9AZ2OWq!)<76@<$b*g!^%pdwg- z5Uv*qhVOqc1NaQDbzkMG7c~PH@usM_Br~_}Jw{|kDkF5S)5 zevE-KIb9G$s>0ZhJ?`(yLF_BY(3p!vJ$oxGN;2IOBBkb@dl9~HnA4>aQ?`mSV&LN| zU>Z}BUUR*k3Q8KCa=+SDvAF-v_6Vl>G`-K}F1PUup%39B>apsbKb#P;M{($&#rP*e zvm4Vn2A}c+Pv7^->x|-f{G5Bs^ZTdOPPJ83JyU@WNHP>-CZK|>>pS;%Aa?#yyH)LY z5G6fbya#9c@H$+JcT;Yc;$F4gh|M+-=%J}D@Wk8qb-Mq_8cDgHj~d?&sau1n*ufpI zRAEJ^Z<}Yg(3Ny1P@Z&X2O>5#>?^)^IC}@Sl8tsX5Pvvsef8(Ujz6y2Vl=*0h&N?J zbu2>qdroh&ow}Jk|98`lqDn#8LIPi^H}%kL2z4CPHGmo18Bg!e zlm>JoC!vmPb$hVOjxMk_=+@UMN1MVt2fOT>Gp+B)EgC@WsLq~fms>i0$VkSn7q=IW2LFFLGND6lPsP14hTlN(A_Cn_b_0tJE7oyaD*!chF~YP$BB$ru&1p zKPx|_ezfjzgPaCY!#;+=PD|%^y*>`AIJ0#lz@*df;xW=^81}0l6�Yw<~RlozN{ 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 C_5o}gKV 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 z z`4QM1Y4KhG<<-<@3LozPLuNGGzF_mLDZUp2d$%zDq}|`+yYfU&?n%9nFg#&` zksv@RU<51N^>*8SP=Qd2z}-w`IW}$qY2VBXbjPB>H;Ao=>f??K>bXrPAGWUhRN-fP z_TyYp<*Q>pA2nl{AjQhE$rFY~+}2 zgdcpb{_=dz2brVe{;|Po5hro;RiN;voqa|eN9;ch5i=@Ktcm1m_i#edRQ$N(Hr9(^ zeob0L>+99SA;Vzz{xW+4Rc1FTk2VuMUpR(>-4-Fco|)wex)Xft}&>E&j5 zgCqx8PW;6aQ7bC5K^>x~&ce^?8nQKQj^@|4fSCOEGS4{9dQgW&;ebYoT2%H+a94px z#XC(jK~Q^x2o6*N$#=IoNl65?1po*JqBBaXm~+%oLO+-FAaGgX>7Q`dL>fmD9h=~ z(W)c2OYOXqykw&K2HPm?{D2B;;5;Qga0ERSx{RztW=mq!RzfozMYVD#^y@{700Ka#)1P; zS;+23=ITX{iX!N;VgVsZ@`o35yw~L=Jdv5obNz3{>R8E&t2)->90hSyR@W|cNc&YN zBBWYIAI-_iz82Gr>sAnJU8idQ&dL+^;|-{MVX-^n*1u&p0$^8lgbZ-vU?~=VHw1mu zPJbm!2e+d9bJ*3M>y4oF2&h3PhAPVGG`pYsP<{SsE`Q2t&#J{|&+GuV@OSDqV zm!EmxoI$eT{8}iJK+G1fNIRLDutjw;{#FWS>MjT^{7vouyji?I+F7tkN7CNtZAnDX zEsD(Gkah3hi&E6kye}knXE1ppE`zp=Xc)rO**Pf4v1bHd=Gjeeiu}HUl3iyG4Sfe9 zqR3Gu=hj}>P|Po;Q$YoBx3bX7oAI<-ym-VqKzk}wE9(tS!E3kq5QZz#YTm3Y`(()4 zsUIyK`(9~R$9nklyJE{a6o@y>8nW4;B2UmI-Bp8J>}UEJMh1?`p;i5E5GVc6LAKfM=Yu!)qG4iav6^ad|H1fy)*sR z8@$rnXU`#;@hOK*>cRd1SNn(WYV~mMANEN0o5hxF!+X?Kzmvgoy{wX$$a()BoO~VI zt`7g5tfUzA5-a%9F$1@c?yBTYRbQZ4RXAk!9RZ8DBZ>WLbO8gFfMNK6!W2O4DQgE? zR=bLWNO5eLY)lXc8$N8s1jqDconXboq5zTgi zZEo_`KOew{yvj0Y78JJfG)+g!=a+bn#i%DltW3X88td+3N2OVCQA&=qr)RUEeKbCH zSWy&!((yPwoNL9eQsai|^*)8f4p_I)tb5ruOuR=s4U;jwpMv}EdLt$XkF99LQXFFV z-f2tj$yhd~oi;zlt|%2k^}n>qz+=RG?TYZy*cUN!Z*B8w7Qt-l0vofCt0~y16HDD5 zaWQ5TTP(0GSG^8VSePlc%?#d}g10OhvNHh1X8;VH%Ei4wh_}i{NLP`TI@@lVC6Dhk z0#-JYaJswB{KmgrCQZ3}J}{PLGQ+mf6o|*Za8ASP*Eow9fOMPiHk9eTIx1=*)Fu|M zm<3Wg!FDuq79mdCMX|BTRL$U0H6IRSuV_7rW;aTR$)M_Iv&j^e{9o03@y?Kpfki7e zMCu@#E2v!o>+WNZ`Qy}=LzJUQ{wkyJ4*)pMK_z&g_w~Foe`~4@>9+$ryE(|W;Ai}R zX0~d+j`@-lw$=MAnQB3!g%ES*Ma_P^O{$|*K2_3y7E3DE56FrQ$15;A;MSmXfwmMs9QK9)L?6Xm!?o9{RXHlv>u={rY=nHFB|hJ%d+q36+0Tv095Q= z!n&fF?F3Y8aZqn@F|GhAGW+FGLQ__u);a^TB%t~5Gx=nkQ9j3_1(?0;z!h3iD$7~f zbh6fTj7!b57@ZzIg)@danNu9V$XZLy0`+j5JdmeBerbFNfG91fw`8v;gH=lz#3T1h+Vr@q*rtIc07Xu(3y-PyQQPU(7Y1S?X}O zzT`}E%5spU9}ofT1I!%~A%MJa10Wp34u?;%yCQIoCQHGoGVzv-7XROCk2e6YWq>pp zC`;bQ-=I>F>JJ(i+hGVQE^C?lQQzj{WC7vkAH=F=Xy{nhWvhNn3)}2Nk>+bWI-L4e zNsa(xduQOr`ao*ba{bnR;}eZx?>T~*Kz^u}NC&D+%{oHGBX=Fa8361#T9ZNc>LSRd zw_h-WD!P!bzT6)W8!GfFVl5nJzJT{MdK$4o$5uF;yAE8S~|x z>xznh1z`k$c15E}iO{)mys<6ywIB7@2wRI@C`zD>Wjc&=Sb{hKr9wv`)H^#9w%}tn zc4KXSUFO-vf#`ENxpR2O6ReR4YE=!WcsTp68(Xk0Ta-Yp>HrmYS3<952?lvUu(6T9 z%8o`M_-Cn+%amOZzQIW7WTVGy>xF@8E`XG2%#move_2 z>TpO%t<{p=ur|* z&sI|n=?dwQF*O9Kr}p!W$7}VKlI?FSq@*6o;dF0-#ye#`vOrkYMZ?j?*B%woXQ}F| zx%%A6j|VOTD-J^Bs8xk4Bhi^Z2sZ}&9pqCTzK-4q|E+`akpR^l1h)sGo!aMaOr*AE zBBI-au=VqH9o5U3rzy{#jD5$x&Ho|C_O<{StNGfa*_KS2P(MOb=NsUotbm%c5JTLW z7^zPFK;qqzF)XU2AvGR2LZ63RH2yU{w<`de|GskuALb_XCJ2uSX3IBpVwP7H3k41m z9OwM{;e#iRP;iS{C6Je;>J<(UKWgUboURX5mRPWN$F=vT0csU)HuP9OMl=yj3ZP4< zfI}l^DjrH*n5jIiHS_{Lg@b*d!UcgM0H7@0QJ2-RQS)5%Ea0QuibXhEKN5dA7{qNp1A3hy{nWrMJ_oszsP zwscD7T?b>MYplItr;~C`J{c@+7G9s7fZ0P@RB(5fJzbn;Me>|Q@AD^Ubt=OqVYimf zUY424VV}*ZH=1HwVS#1~H2uA6%EaZ1Br~y(Z!p;&;B2*GzmkIs zWLyAHD}rE`w=Ed7-28Yy!Eda_k;|)iOa@wRrYa)|AUF=<%vs)$%QTA? z0U7RwAMUAD&3EA`6)dTL?}N@|+ZNf9%@6i>?mfVfW1pGF)@l7o8W@!n%VvpXJ7`V~ z^kxe1zfr22KGi6=pz}7*u4r-aBMrm!Quf>mK=|$Jdo8#GGD)nPOJ?iyfX<8O0?cdz z_Wubs<}Y1~;V(ylCgo%dDIkm10!z}4KehX`dvgDS5UW}p_veZ2mFsrBUB%4IW6N2Y zA_J*Y__!sIeKlzRk@*_|gSbSl4~43uiGJyQ&w_dK`6;{;{&L0a=Vu8>o1ji;6grYj z!9JCZ_maW3EeMP4+O&fdDInVx2jgX${z8^)C@L^Y=ioTSV@Vt{jdyAaU7X;6X9PaV zhu#4vbzF;ithPxPVm@3knsm0+V$OCEspm-Y& zhW)X*02Ulzo8@Qe=0B)@G?11MY#0;f+k(T{FvPseRDW$nLbiXbdf){QJeTj8}^@ zXjWpv8_;iI?~??!HsPUeyFlfol1QHUJ>~=DQ)CBiA(aufjREM!!H4?9nS{b0ub)ad z)0{SB9vdUYCl@66u*9<*s6pi4f`aCPpUxi51C*YzUz6oYs zEOWnQq2o@{*%b6>3E4s7q&m&68#En%78?$Q84AiV9po8;bACXJ*fosCi~X!O76jbv zX#hx$1(F)qzvG1d+kpNc5%(UHs*%(160gVgm0vaiHG6<}{t8m={Xo+)!usV&nPAE8 zizUKOY;d!lxR-w>z*G&a(-MhV@r*Y&`sa*L=k1hqBp^(snu1>CRc1M{u-k{<{>wdqqHe^Wc*Z zKl9juTZwOuKr`M;{Wr5;dG0UBn$0E?Z&vANS@2&HHv0a_;pOk(BijyZ++3TB+0p_!sjJ|o`XaL0MHOfr?iofD3X^*BXZeP3&r zSnFFyU2Z@6$f^EHQP-POCkx@E8t3^6b@I}g_pIqZ7QNzb*ZjraEKt0+7UdDFE z(Jo;ZbHOZdF>w+$k)U4#kR7;{wq5k#w9avVbW~p<`W)*O6<3_ zXTtr=zrxRjP1c`1QYL8hii2Mm0(k%=v@us%=DBFl=v zEOBMHwLa->&}I|-9QF0soPxFf4dZG>}daM81lDnZOnWc|#C-sh?CH;% zGs_O2#7xHX!K!E7JI$|3z9mI+(-JZ%qga78cFC!4zrYvm1+8e^VhIl->m#GU8n9>` zXTh~1jEPH9Dw^lZZyouPcI~oPKzzid&10eX(OkJJKfUvH3AD>;EOxf=!y(MyU4-cG59;!qoN%ajA6!ga zrC^T=mF#waA6-{y9)UKGPYk5Ag(-hIlc%nim_>b!mpwAe(*6*Sh#_=_L(+zJPW7?V zQ3JPGyk?c5W#tPqG)>*pnxNY(SDOu#rQL9|N)x$Qw0F7cd#88ac#lM=^&Z@|4kwuT zO7g4wD`5L6TBx*%i~TEL^Z9&+gh%X73aq~Z(R>ku{@L2B{z z%y{i+q($}p5_I;Y=1+xbo42OeRA!>eoZOi3Z@l-E!BnbRGS zd`K?jHO^T2Z{yK#5u%CR8V=kjSIYylbVRIxQcwAi&0v4QbIM@$rBzlC6IqhHGvLY7 z1%S}goA5Nb1m#zpW_QEK`T|ULF^m3enV!3^v9Bb*SB*2f;IKJ=m^aL#U70X8&2kh z2P);r_fhYcqrBx`t-e<}J=lnGd4?3{<5o4Vj~cNi;2}kNLLmfMIsHGXzU1Uk@Bm10 zJsf2djPJ^IhnWA6movzqDZk@pk`&uV3Ri;Cj~{1wmCZ8TlkoEJQGQjao#tB8Yz*=ht)vMHJL0E1t*|b zuxEp4-LjA|N$unkYslOhm2Yxz;C#5<2`Mh%qZe{OxM8rX-We!toWVK;{^GdLM@_^- zP~fCkV~{^AxB;{U;pt~{@aQCsrh#ZU~=F5tuK0l z3QRYBw46_I*v0coAJk;6h7;*DK_Vy5x*(sf{9ZsD_52A^*SyJzPVVP0w2c7K&NmZu zZe&}3{607QLZZI=$|EK3{X8h_%-hTwo9xvxtura4L_|?vFUYT8coeZq$v62A6k_~4 zW}tqzx?FKx8T%-Q-H~+Vks)X_O3kmTV>_=``HRQxw6>&r-s9^RuYV`rPk-SB*lwcz zM_f?*y(qer#JKk1d+V1!AGE#p?wlumRX)@^s_XS@2y)_c*3hHXMVViv4Jy0W1ONNt z?Y|{_N9Bj=^)qORn&14PigE-lawBaieTk>C*Dw2zTX5`e=>S-@`{I8hi$Uot`&EBW zRQ=nze(db}G1UMg{%EuU@kgq+QT8D~`^U(!bK4E7|E&e`e#f}eJUC5=N3MOMd`-Bs zOO^MjVa?Nei6{3_6#yavAe^5A-@2ekpd_c|hnM!~S49=10N<79?^m$*0vaRvDQ*6~ zJIIFqQ;rDnM8QO!GY)Y1hSpJAqEH}R=mhGz$nYno#tt%Ij;Q{PBPve^FGY)u z(1jvA$e;i?^0u+WPdc=dE`D%Oo7&!@vZ-NI>K`<&_JyfAKu3yp`oO)# zeZ8g4k4qdIl#DQ0-J?r3n#g=)N*Hd+czu+H5u~h+%X&xf98G0bI5I!ukRGOxF|u@( zxAc(-jr<9b#?8QNqQW9lQ>jxnFJ2Vi$y2cLmUL}Wd@!MYuT$+Df1a@^+rO!(7O$K% zAvsd2I6t8f;jIGEQ9NWSyV9w0VRN*5LjJ5b@*-18v{UTz1PW1hb4wg0Zz_44+^TY1 z#zH`GmxFi_FY-=YLw!rMnW-virm85R;4q=_&Rf&9Q{!4ZER(R$^p3iHnZiwR&5xUE z-acv`K3Z;OtM!`_VF_w+3F^jWP_Hd@jD%p)d%4n1l(>&>psBiUr|$WLee-1HoCGDW zJL=I}Do3_PeYW=5Na)?Ce^l90>`T!4)v2D-uJh7cf4U zUjy2vp-`75f5q;tBK}kc!NlV!-i*+&mAXuA%(ZTpX=cOC+{)E; zw=GtP807@pyNNp2B#oivDDP6s`E7`DIkw8zzE;vUdRq_QrT?=``Et3W1JcI7!`4nx z$8}5m-K4=)2|M1F=3hxW-lT15m&AiEEzqWo;kISib0du@!^sJlo!|6myGGe@O*5wrHs9Oc&dLSt$+Dg6`Sw3lfr3G%o@s_cgu~sd|j?3I^;}Q=TI~X z&0TpDx{00kY+pqiKUdX6H%ULcA&!Zg)WP&^Y;=WfdUuwO=Ya-4$7@`|kqX0KT{ewU zm?S@`S&HjjUxl?!qeB#nJhWcwcmi zXxHO{kNT#hx0Qv9)lPsu#W7ymFHky2!C%-J?UUyZ(td59Mlm+Ea0^ZJg}nBPlv4NT zmR+pyV(h*$& z5?3&Rfl|()0mippAO9>F)_@`Xl5$P=bBM1z@<-b3y9DuSH{s9SsG)?@l2c)wEwL}} zihh?SB~|K~SGY}1^G=p~#~|Jut(}Uc?Zo5-oSN*`PPunHrZWDe%%MN`3`a1>q$Lwp z0^F}o25Y2POimjsb|yA=#m7h=`aA8GlYR0>HyCGpp;=g$D|&ZLBw zl7{}1G4ZmA&JrGZvTlnBvC1ij3@s_nfv5lYVR9<{JOjN;1C!!X^!}Sp0^U!%j!E{Y zOdhKGom%D7D3ijTO4bNWsC{!LzA~-9^2~g4`k3UYu)D#7(}`y>&Y$0S7Gus?OgZu- zC3j_$M5jV$@1N7{N|)V>ca?Dx^$i-S%4$St>hAbWSgIJ_@x63Uai7fTzyMXrtk#~29t0CL_9OcGOkt*XL7J%qZ;E;dQD|2p74Mr-I#aa9DahNs zaH>7;Wh!V0>(n`2{JFX$I<`2*plBTnd>54UG3X*sj*eI@`I<@xr2&2g9fch#mAx!F zDfi)Cb*Zn+QOK(U#n>`qs}=zPfZ8uXAwd8SU?2=I1r!U)2mqiw08dznz-=g@2}$Y& z4>KFtc}P(eC%Mk1!CXn>lMBP0%>zX$_`+_i_t0>;l0#GQ$eoD6GNUjfKiw{ku^NTY z_X{Ik*IqW@Xd=or+pR^GAI(>3*xZLI;Lk}ChJZ7_2e@ki0sV-(}qb}cVZ^`UrUsTkCMg8wj5G=f^ z)aEa819p*}h2I_!&2x@ps`{#T9%|6^iKW}(Z{c`18pRTvVw=e~QXOO1tX zSM5t>FXoK_sqnT#8sS&khx+Dp?+4=F<+yMl4N+`&sqzWgQqliRWf{(HzxIV-YV%oh z8HPz88BQjfmmHOT9|}8;DR5e?KC=|<#5S92X*zy^UuTt-X<u&@9cS> zd-)1cNX@h58h=m})QrITgzA++GrP-QYO6w1%QJ)vc%-}*;VZ0M+g}T>qEcFqirl=Z z+PW;Lmc*BC%zn4ybN#6p%`Dk0^6Q(9*>k4XJ-u7Dz0Bofv0o3Kv=D7iR>dWF+3zj* zzPzEx{r$B<=mDz4etJX1xHmxDXRz_-zexwn-;}OviKObp4&AQ_75#?4XM76;Uw%mR z+9&+;i1(#HEtzkXm1p=q;`VT}+n~Ou-E=40yC6fmHKdOh|}(xqaq>k zrRCKUyH~~BxIZaOb`ZTir2!!}2C=+>B3q}X3Cp=S%_ zaJkWB_qW=sv6In`i$zv@w9~7!SI?9jXqCISWlHaE= zF0X79sv(ua_aF#Jb43H8eqA29gqKDpas zs{-eQTLea-GyAhopcT;EIQSQ;<<5jyt5ttA@kj$`?7e_NJ6k32#o^`LPcpZHh&kKx z3aLgqWnw$W{X%2j1$F!0>r#83wdTMNDX&l7yMNX*&p^b-`dhqc`^REf`g*NjZrfd1 zi7^uop!(GV$NOVS$E1GaT;EF!V22z^PG9=vCsfmjcu`ExT#=uLJT66?P>R=YR18^b zU1b#jHVe(B6bQjl$Rdij$xyrlKT?uuW-yWb?SS&0*09ae$oJwZrx8`!djUPI4|K6v zmex)weC0~Z1;>pKjTJ+^v#}D^-g01c9Z)q_E+34&QE#{0m?sQqR{2hR`crF`E}z{m z?gw=c8y}J@3Ed}jVah?ulbMN75~&fGaFnvpJHh-z5@oh%$ZKr;g#-fb-P^DS44h%I?b$TmI|HhB%&LiO%x zd#|a7G$3Wxh##+=UrwgiCgZS)k_2!tx#Udmz||-6`EU1rP+^*PThFfPT0J2#Au$T7U-q|lr}jW?q`TIjmU(|;O`=v#7L z#?NOy2uj;t92AJ~f9i{|eRW$;>WyZ~8yn%N3J2`IFX}w;?hE4xZ>0Z83IsfsyzhQZ zwV3enM%^sEDA{{L!idD*`E6b*$Nvd?&5&1mw z@wC+-o`(gQb-XJ+A4OBBBLGW!ITvD}9~5U-2j$O$%u@XZq}=~KOY6QcB&p-55crS( z7^(KLXiJD!wbj?+P{@(F`ENy8gXtcp{S{Xd($6~YYo92Niw%<} z@n&Wn>{;Lw`A0@$O1#7%Qe@lq!^jt_U~F%Eaj<3zYC_z(5pko4FC;D~h&11z~F*rHK52iREgDwH6E(HS^9@w=K)4qv&HqodfGR z$d^l5Z221}TyBa>FGM_j_~9<*YJw*K92VUCVV>VD)1JS1r-cRQMCHox%NGA5YQVSu zQI%`dzMYRcB4H`;5ROrcAy+Rf{ii$f{3PUUdx31mhln!tz5cZ*+g|&iHnaD)97JU$ zvuDTh!HQgt*hykD;XiQ)`O49_lNn9rrly$Q74ij-LVwc@fw>o4WH!My8t zCnzUzA(GPP2qH}S1(UE@`DBi1+FO$=_}T^evse}V+x@vwoX3iXziQpv^@+TEx+XK_uwg1Y2ZS$Yyjw61MVV)>iRh%f7g!n8$ z`(c7$A)`j6QAQ-bS0yHU3HFO2x>O!H%YyGRMHUlq)Lb2FBy5+2*rOW#B!|6i1{p02 zVrhtNE}YAu#q|g;X~?}KB0e9_j^BeFWnk}?3Pf_W_5g_QJQDl~E#mRf)s!t1&_BaYde}32y*$1m4lOD3SQC ztTA!xH^{s=0&NY2*kuSm*+$AxV85w(XNL2B(;b7W#D4@J);U__AOsgD8ag9nQ;mGX zvx4SQANP zf(zf`z(okLr{e`U4E_o4J*p#;O7r58#D4yOjpXF=!ZX#n;G@gJ-7HG>A(Dfc<`j#u zMpD=EX?h}lVT%rb!4-bUg?VAcyjL!4jDWv|!q!pzvr>J62=4gdz~xZJxgvdBe%l^` zMXDWdf@;5l|GlpIhAGBQKCG2_@GTiJOBNW~Diibr-XtNulORpIu(@j3Z9vmk6T~OZ z#bdl#X=SDeq)@D$A-c>c{!SD=`4BnL89s%AZ!zI-Nb1fB#K~0T>(%^MxYoBQ#KAKz zZV8Bt6CyQSk!57-IV`defGCNA-RFwTqmWZ%hm9G-2@+x#1$%6HaW@ls>UZlj88!+? z;0Mbt4!3lW#Ke9h?$@ZyG7m1|M4Ohy((l0|841CkjcXXi+sm*XrU+-bb(<^v^%Z&= zDps>B{E7>|s2j279We!n-k`&p3eO?J#i-VZd4}k1`fZR?;nl;AVIh^(PY>z z3tmWk>M9m}wDS6Rsen9LY>x{I;w`gJ1>BJIF5aT{FMJS;g?cXGMYmb-EG|GA0E}hA zf0D!=3DlBDio+bee$nAY3h}il;5ey$nw#hnAVV1*EO~0lL&{5;-ded1`FFfN-M99o zG$b5~M*9Q1IgIwQA*gAo@pV|}pa(1%agZhzOFlWw8mYaS^NwtVDHo6?i&p!CRjIPj zeync~d7&G~;S5QIE3Gl?$~e+l`3O(l8r0ATk=@CZ&@$h)V$2d$6)WoM+o zZI1~1_ygbiBc_>B`@-Q8XTYX^5oL_qeJB<4%eIdCxFr-c-T|-9fE-EhlxK*BUnrsw z!0(BOmnJ}IlgV-3GIniE?`EV8Ns;iu<{n(n-_;gwIH~*H53xpqI0pl>0MAD`s>$;) z$A?bDo62*#eBLpiDH4G-jN2(I62&jI>u-|exc5YDBQp5Sve?HR@H|WG`oYIMB1jksP@@A<03u9o zSSe0Wj|Cck>Ko6PKysx=fL;?OS{)PcA5^hc+Cer7)mnQ zumACYl)wB13-(h^=E2R32H{LGNhU0E<+y>8X3BH+n>)ZVQqlbbmVEflrZ;;?O<_EU77An<4ycd1jUz5Z-QDIBa&GbLPA0__x4+dIp9J5bZ9=$#KW5?q)TF~ z@U4~!-~-&Hk7tx3cHsY`>E7d+eE&ay&o%uS^fQIRfS!K!YE&&SO~a?~UL)Lj{L z`f%Gh9$%_?>Wqks+B)-m3MI8W6{yB8yzYPq{8(HaB!!7KpHPs$e?XVms3SkWURH)B@XU|dIzZ# zlKeeJ8G4@oazfV$!nagYX_8Y|WlXEM=eg7BnwcA*eLUga zOp?>G7}be%@zgiV>4B*(`D+`tEIf8dZHKw6e41JYe0^2q`&pFw+j^I&f3uyWQfkDa zGl&)N=wRnBO@L*eoy0^=m?7=J(Co)2F9mXHKF`uX34LqeC_TkE>wnOPHPGU7vhway&3Jx4OGIue5J*FvJ^koT7 z>|bYNn%xA$7jJrKFS(wqc>LyUjvGSBNQ+BFpHg%S8rN2FupUOHw^)Db?^-%^)lEosa*(_S)&QWQ|uVEA$K6E(i8XW zG_<1^JHA$c``k&W&Tsf-)P+V(8}TClRb@a zBt&_iHM%gicoM2lc~|9a_{M7N?YZ)RF+U@jK;Oi+TKa_f^M;hM&hScta_iY#hX}k zK0z$KbnG)C$Y#vtn!N2KHRHs=%LilnQy&NMi?lawl+les>LF-Tx#=bE#&6bFOzJw` zP8%JGs#|&VMR56mPxbqLP+)`dz<+b2SawpGtN_qIaFEY&n!? z^G`Q^l|t@-+)Dj(PTtTz-lMDKhBCg{pXFlbxwrhF1ZqTmXrpgbR5UqY~eK+TC zB6>66XPB3?6Su@7VoO@?^5b)gSxh%QevrM-Ov_Uvb#Gjko|LZ0>1kDkZD=4P8~3!` zDbwbmG9=l<^hsxk{kh#YlKh%!I=chd<#~c=_%DhyT+*%Ti#B!BUw`5Zz+kfga`5ik z4X3-vr}FJA_CM~bJ;7F{{<7wps2#uZPZe&gom$Eh-h{;rQpy58OisRqJ{lBslO&0!V{)7jQe#yEb)B zJozN7xu70r7JAh;bg-RqHCx&u-gXS0F042l`Z-B%w!lT$T%-n2G1B7}4$qt(J4W?^ znn=isC0<3`>a@nw`XUiMw0FYg#NpG?2MIdR9iZy2v^qJ$(vKZp-{8>nZvxc>x1hew z=4$FtmDu$vNQv10$$0@0D4P&}r+x7g^10}2uILS3Q<5=ZXIr#AE$YNxtaSDRH5@7@ zwLGK$4f01=(Fg1xJ2&Bc&a*#=!oFk9ij(*}ebl*Mg1VNP+Ed3ZV03N6VD~WgYhVxz z08CpoZp*`}5^|(T57U@7jZ$*z*&(j}3j(DKb`zdg?SdTLx=q8}zx_9J(=I|;+BudH zzJb^6c7k2V*f@kJPNh3`&7xehi}p<Ig<6K&C01Ou>eM#$_0yn zm;7C9Lk(4fJ44HMQ@exax`P~0tOUY&F&#zPd?6-d6!_#KV|1uugH) zy`=Lphi1+rU#_xd}=gw9zp;6U9ppV?8?0K=NF={zPbGj zWsMao7Di`D>jH^ocRiK$>D(f=z z&X=5(jy@-2V*Z8bz#;8I_6ZJ?9YKeUL>|Qj& zBIe_J-vhF$LSBu_Pw{YeIO@gs){bM&vEgH%c#0lG6iA0km8txFPCk@sAHgEnSu84e z1wZK`4mJI_ysud<)jm%q#P62_c|eWUCwLa8qHSX!_xqHgQaB7Kt12kCwNq#aD1?JW zXXxq}o=kQL|0(4bBkX6= zsir-avqz|&$*c~!kcO``_~1>mU4$F3<&(f)y$2S4ELw&(;)WEMvfEne-KC{xn6nw{ zi$7d!t@&3gY+AY6AH`#~UTrcgbPI6BP3qJ9->NOU9>~1zO`Hy9mYoXgb3*Tc99>TM zbn)$!?rt*AQ+cW)2fn5KC3nPrEt78B{YHOSHni*R0-cjTq}W0&2vQHP+?j{fR%~ZB zq#zHkx->euBC$~`p6>Cew(6^S(W!zBkEdy@1M0Z3EK_UcGKee<89=m*A^tv@yWL~bBmf9 zTOtI7f1J)OzP!>uZ+ay2?#LZvALpJLb>I=1j<&`QN9on3bqW!cYGg>R$l%rvDI1pB z;rD>Ot9mjQD-_W8QUT6GY^n2Km6q8wUyig7SxTEsQxsvViJ)KBH!u1+tj{9jz9ALf zcU>uUxZ36L^BZp(D`iJA5A6k+!Klhasvp&NE}XupMCF=_-TDa7MMim%9z0yg*7*STMHnI5fCN|H2Bv$6$h*PoYX5esC5 zRCzKjKCDFRTdjN;B+nXZvC5aXu2En?s)NCjqq1W9(XgU;B2WB6zkZ!M_M7kSa{7~; zb?|f9B#O$gFElp{0u@r-TY2Lkg(eBv1%STPfjFLll3-T}9ddJb>}A$9(%B{&2V^0eEAfHgLX#ZOBzLLFRe5C|tPLM?%QL5(y(|v-fXbs6` z*WFEpkW{1(UIb_f^pxz1?|v(g70^@2oHz_kJ=-MbBHb+tvM1wyZ&1JD7OmjlMF{{I z6%Odyb*6f+J&YoqNrY~CCY(4j)}PIRXp#6bXxUr}^FQ$2Tnf~MN>!)_c#t$6tLX&y z7G+@{?3tsQ{VIC8#ip6&`f$BgUd%-cY`xa3k8+?HLp&sisib8O6HsDkb zD1+GXZ3|yfOqD@{CIkggbho|vEqy!x($agmoJN0eQI2(y%_?3-8Jr#ljUaOV=6YF# z!lO@m>|FINKVPaaTB!Gx`7^BwtZQ!(!*ytpmSAlMR_z`7r89>LgKuBhY3<`de6Xj- zVOj`?qbO~9uG|RZup(^B6?!4Zi3HadR49O%8&srK)6`YXlY9~eYN!|vYbOOT;4iiM zr3*Zzmw5i>+V+WWGji&^j1W}eQ9pntObW3;+ghN*;Xra(Majg%Ku%$LSP6D?RI>(} zE|3mJn`N)JvIV!cTj2AZX^v!PN&+NUxiB`Nh)5g9ETT}UG|U$Z>=)B=9{!gQu#1hz z6iWwNODD04@&Qnbu#=tFp%gYm_IRQ1sscc2BwbJ#DA}5 z;Jl~_*1Zt&3mW=<=b|B>+E|ncfatdsV(JZke5;u6C`usG6v7HMj~5XVZ2a^i}iTaI%l4s`rR|yDgS1{-j*u@EwyDpJE3-if^q1T~@do9dzO9Hw>Ew>if ze`)9v%qwA*i>=qCpcWk2muHN==L_?5d)pVbZ~Z z!clC1Vhi04YAxuM=6DYVbWO-Gcl}Z8?QlQFH(>BL#)sr=X|opVP*1U;3e6 zbYn%4Egv{jW@J-xpn0f+pn`Q|1?yz%9BkRc93i zJst+J1D?+Yyo^hoj8&%Dj9ZwsS$pq`h+E%gQwH25lk2j6!%TVubBpUJ2B&vYTI#Th z=ynqbRVU^oVRz4yq|{v}o6qF8eK8O#sRwb1qCn zGvPMBUYF)st5OncR|JKf>(sq45{q1?7yU9gm>181W+}YXJXrwUF`gHMN-G6T^cF>m zU+r*a{Y;3;ubx=3kA(Xyi{u3 zvgh;ap&fojNv`#F+_|j}p?N<@cr=pjt)U}$)9x|9S~1RhpM5EP}8)Nh`L z11c(#ju3IETJy5|SfXci7E>K?Lm`a0vJR=dSW!b1eMH&YP@u=*%wQF%L-j@PJm<6F z5Wf(uxb37|i8{#vDX5npxW;;On-_hP>KRXGVq`RzBB7lnP)oU9zU4cjFXZ2FV_< zkMD&9cd)B|Lk|lI>xeWnL1D5oG=uX#fje5i?y9m5K8h{M;3URbFLi&CzFd3xCaJzysjSA&0`QFsA5n%FupI=+TY>Xw z-%;j62z2xCdcl7iFb=!$h~4KP)IqECNfruL@B1l{~ZWF)YeI~5g*l9{KxRwFq}yBRgv z%4fB9NV$j-ai3KaIFQ&qxM0es^x~9P4~O2M3X(BUow`r9)U?OSQagJgl{rnuoj{%l+Cd&@g^xQ*RT4;Gy_eY&56I8 z#~fxz469;_4H>9i)`D|C=8~pK*`z9T(66Hy8a+P0!G>CBkSB+s)O-vo0GC&FU3@c? z4_n{9W&M_bjXG_n@*7ZpOi?B5$=>E;dLk=pWg55>kkS6L94fPo^7|qCr#vyOGYY?H zZCg*KDXr2gHrLxp_?Fu~uXl}`i7(o)f7U*m&(%JCObn6{t=ph3aPaSy1i%5q3pa&j z>kYEBx}GyCQm%~LN-$w!u%^)YF1mRA^Y82szFd3bx_rllqG~sVG>T*#FMW2RX&45R@Iw`Fg3krW)(jz8@H+{#`_tn5(i z0Ni+X-7Bhmz=?ql%exztN8a}Lap2!~uaM!Tu*Z2-VyKD3nnBTLz?_(VOg}?goLyV> zZ+aczy@PS;GnGF=S%$0J^pZffgG<;|xsmg`8STea+PULOws&fCcH6Cr22U@4{5xxN zUw&ly$%j)>y`f$C=2=fI_Fwt*#{Clh^QXVg6xu!hNvIn#iS&FCUw2gLUw>}9p4;;? z@d~O29>c;XYVVA4le+IeL*{|B*TZ5?mXO*0M%#x`8PXnb_FgrI*fWKQq~a>M-FfMc zc98sU8I){ophT15ExnP2Vrd7`3GGLNi4mD&i5lm{XPB^}6JsE&` zk@pqRkXb9F8LiYapscLlzf9P)T5r5Yjz~qCN;m66pC`3HL$_{iUzJjb=kOq!hLXD9 z3xg`!BZ#x5PG+5ZrcrcQNo}9m#Y@rO*%z-W?rrS8(Xw{(((UCw^DB3M|2F6FWSuRp z-q+5xxc0#8j>Yv!r#}`wQ@+k0>pdXe47uUk=%yQ&J>Ey&L_}XqqP)rZc`5g$SB>Ru z!eF1_%~?feO39Zvos`n$oRO5=F9W_?OV?ygtn1g4VzylYKl^d{K!s_zi9(;JZreb} zj$rAQD-H=qZpnl8r{?Ysty;Lhi3>}+qkRDO)qT@2f8;AuD_(bjuNG-x^AMD~5~02u zvw$34tbHFlnZc8f6Ii{}^&E7*BVIdsO|QH?!$;%PwZv0zAq|q0bu{ zsqVDvjA`=Fe&oV{ei_=)EQ7qTDQBy&pAzDAbW^9eTFHe@+&1&PW$?BwrA5|G)bw)p zrhS+}pkXztU;~JjB*MQz_D~cV1a4Vg!Fk!QEq-loQP`4D65=AR9pg03%o1p4=K(*xtx3J zP^lcZsxl#i>Y~>Hc3YMznb@k5w>ycQoly@X=5c)WQQ%6KDbKPDk;ab>s8d|+utqhp z#9|Fu$ZYSB7aQtF@4&xw1C&_riLMAM8+2I0$$48<9X28HG4nLo`y(Q?pA>KXf6#hB zSG%!(2iW-`4x#~^E-n9{m@6PUZzj!v;58Xg>61v;4#t%->jy24cqA?hoE+3N9WZEt-Y(akRfZEttpHxCeBUeQSLPCPH zOV(QDK6H$j>3UoqZ(WN>-!kMXyxMv@eOhmO1 z9NY4g6>LPMdG+VzBhQZ8JgV}z>-E?!XKNQDp+>c*CB|&iy5j3VRb_1Vk?X=4W5?&( zqq3>S(j?M|3&9}tk?P5c5@OfpQXegAz;^d0Mlas#VpB`V1x|f=efXLNju}Ihy2~lT zEcx!86_b1osz)ZQWE@>(z^~&=?9xM{{p%if1?Q3KzOp|3FkqmCd#} zC)s^h{V;|lT(7!P;N^c^j21Ch66;P^Z0$cIEaoF0@-CYvGTQ1cdjNwmc*K8x{j8ua zxw`4WPKO^Xy>kl+@uS}|z~&RRE)IeoA0No{XTCtJC4ABsOh zo}Q^u%1C%dO4zg~I{`*+1eM;slNqnuu(5bfuvw#|!1OCA3$$X{ zwl*cWZlNF>SX}o}($^MP;o#;d7UCq*2tS9FixK*& z7u-!y*%th6i$?1u#G&C?*0lM}6m`FkS1Tg4@$GguOat;S79TEqvr`O%+Ukz0ZVNxJ zGcO^NH($qO$HxSwoyZ@>3{;(v&`x=V0=#427X?cH8=cNgrd9OxOcr(!@dgWZ8s?R$ zyA9nK1wftV?G%rafkY=Uz+~X6LMoS`H&3~1d~@#S**p^bnJpVe{!*Tt!IL)O6s}bN zYEnvW(OIIL+`(!-9>>-&G9>YB2N#UfsfQ3T9WNByzT{Mkz&}t7 zTL0UQS09c5Sr(5mD7rn0gjw@=cROrb9{$Z%l)Z(|`?uhO8`F*`hB=jit!FqEZvu1A zQVqlKZ~lUuit%bcuOw1-9E;IZp;!r>yb$cG) z22FPaA9SLEEbR<7e9o_0lFqeaZ7F<*WCN$xd3T9m1@?5iHe{U40JnfJ)(p)KmfIL} z3<1I>dXJ0zyq<3KCQ z_v6_+q%h?;>6e$9`GS|I=Yy{G4Eq_p6Xxl{B_VD1pmScR>jYm<`ed8&879T6&`M?Zyz z^|f1eoc&`8bl%{5-!QIB#vkxiv_8`CuOH;r3Ic1y?XVvXFX(KB|u~Sgp7#i3|IXy ziLY41J9B8Vmor_8W}D zH`}vpOun#q>YfDaMBGv3M&9I;2w8#?wV1$-tw?(tZY*}s^NS;PPfY>*WYPIn$|7nrAe+A5r;TFTUS&t)kff^J8WUU#|h8-3C z3?uj}W5onwGBvS_?^IBgb#uu)VI5v!i0FM&3{BuZ4!G^=;=??i=V2(8>|rAQ z8nV-cvY~Y2{gYLy1m{EqyXce}AB%QoD z=-13ZO-yMc1!k}#Mj9WdjOmn`ppqR7WAxzm)gnyZvT4+(9U?l4=wZiYxRR^-tB0To zphN8pD`mQIf(Yq!S+*4DHo>ri0g*%xN75&+j|a4MK|}LGN782-c~GnA0VnZCjF@hi z?BSr?&FeBd2%`_WftDip4}6n-Td{~ap|c&s5N7BUGh@;l?g=jt><2w)uoz0Bk2TO; zxeS*ehDrZQ`Bl(JwKkIb)JYy>fCk#Gc01~J6}J`G3qcrClS7A+rTSYadC+B)j}g#O zp@XBcDRtEH=tz)6c6|4jZysYz=y-3*Y%OiXZwnnXA$)Sz1^Hn%Y4`qtxR612Knl;Q zpzvDL2j4*(?t%+h>;6-|d$@%`%*t@qit&Fc5)jj&*uzjbhzVM{+{6QI!y6g_Z8mB! z;wc$x#^ijxW5*+FK?Mxv;XHwNS_2wjJ#1H39IP+?9{vEyNc^^)VJxxe`fD7>d!QJ; z>nOvKLPyqb`?uG@@n;hvXsMK*8QJR9 zaoF*~a>U?a*>;-{Szpl&JYvPvCYDEK->%ZNKie;-Pu z8f|n5FM}~Nj2$eTbTJp)inFjfOw7Pahe|mK8CEbmoO@eH^{mduvSR`cl81#f@^;Md z9Vx8xWW4j5-7JD?CBzrmeAsb`?@qz1V+z1Cp>8O=baD!%k7~FQ;)JG)f1CxsJxzEw z=vv0moUk+h3;OUBWE-{?{9<#v^F|s(xV^@M3(erlblB~E(ir?{mot$LCilRwe2SFM zHVz)sNCOiyw2dxUjn2epVj(e8t|&f8er>i<^8v);@Sn9k2k`!q2*dB`De;&0YOT?H zfCbukj}1PU^e#)mp^C5u(w%V<(!la|*XctkPe$xBsys%~F3FNo$HBeJ^aS$)y(|2Q zo1M@LtIjoKd`tkug%QJX@V-M`NZIdqhu$QT0w)8&LZQUpeNb3u>ASZp8mw|JJ!>po z>$$Dlhi}-m!M#5`_UYcR>@hy3m*HxZ0oBdK2ZmUlNENmZL0z~eVoOU50h$a=wPn|LQsEna< zG?S^YWUAWANvFlmqbC3rF+U*5+}W^SdYWmD7@p+(Kv?>WLx|f-cofv#{cI{pcOxlC;o*s`yXM+xT3Eg-%3z<~!EMy%X0-GiC!8btEO>5n z&@~9}l*e~R4_+|_dP{kmJYl$?=n`R|XpSFphpNTqyW4?4fL~Ay)vmQdj>_9JViK)B z%D(>u>_ULrF+`~r#6}(hgL^=evKopz^|)rH0k|+tRTBWMTMeS*`i(YboQNLVniYD^ z{hX*73|d6Od5}tDKBek-ZCjmydFZYrow$a->%h8%Bnor^#v=Fn2xV(e zoEhieKw*yS%1zlgr)>&O(}HI<$!tv{0!s~8-~l|OB<{ET>Rylk zNh3hkfQ0_*49SdeC${w_UO%IIET3p=hq|~|6Vb}kk9I{6f!Lnwdpr5=dQcT(|MkxV z?aXfjroV43@QW055;p$)#Iam*@7g3}1aCciH&#R5ctWt!)Qh%L&SGai3O_AR6HPw0 zlalYtz3Y(Re>*54_`J8hS!j-O;^S7o5=GB-JF_R9dz#H!`<`qj?!9u5$INWt)!xlY zHY40AQuJ%dUNzd+YJcVISv3!L_?^0now5a{!tOKgx)@KDnwIW9-U?GO^eE=OJfRt4 zxLTv#+jijL z>PqA-h4D}Cfg_6J#Gy+$3@3p+lHf+>$sGB#`OCO!L|KKPMG?KngFEXD zzg|-!PcV6m5cDCvTxN4J$hqOUvF`Kf>=9&yhi?fJZFr!)=jT6!>DkfM%cc(t zTUHp~*lMpy-pF9%m?ThK!u0F=AH!Ko=Z94_;N7EcR#v|^Tqu9FK znH``=5Ag3+RJofFJnB0<_ps#Xr^NQ)q8qX)3_{EMxW;tBgKJ3oScI&jcI)kTmPhNW zTIJ=wEO#IS!*m{)kV?Wk+v=iQr1i=DLKN$mXpDOz^*`YDeX;46WxKoOtG}6TDNm}8 zy~;~@@$pur;kbo^jcC0o9F}cF%bNdiy<<hc8~WpZIeZ}ZAXQ!3pV?Uu20(Pik**E1#>$|d3RgX zS598ue||Uz_zJc-?ZP!qZ#-;mm`K7_GaiQnUC~qtU zcf4Jff|YPJWu{MTqsq6jcAgH7Sbx#({JHk6;@#0LIwJI9?^o@R{pPm~* zr6y$er_i55rdk48U5m7!^Oag8nG`DdEI@OO^88$>TP>my=3BgfNov!UZmAzfkr~c7 zh=X*+;S!bDIqj#fwV`)McUmRy-?2&BSh@hpdU9S1y#sg8U)*cfZl(X(M&aD>!kP2j zA?>4Ap=%+>ly;&%xmuigxn#6dJ{P(Yjd(#c>@hNEF2<^aeXFkvsJ&)%`J;{Z>jIgn zy5UAqS-rN86ryFSVq_AeH-YBA!x&a(m-!m)4%2?C{MxQ=BE)zd6$<@LwI?R*)Q!k} z`<#2zA@;#Z;^(|Dg%X*-g^wrCk*Z$M`_e1Pp+I8pcp>sji(GCigY0jk8>O2lJ6sOZ z)wm(XRN%VCb}yx!c`sju`Kf4d+BoCSd#dr0ffBjZL$#U+&P}l$hkR^zl$tpmOAtV_ zTN%pliA9PzRh8iwkpAMbN&Y74eueR#6~vg_BN<>7J0onS9*6Pmci}1!Lh4ioGr` zd$~Tv?e3cOG>gUSRDViUP)L)IVKAR#1T}@7M4;*!%t@17u=d>I_f2s&4+f&e?U!W_ zqaFLz_BwK_kxO1Kv^Aj0NF2fQDkJzDO+BjzZ|WD7M4A%%W7Op;Qir6EOuFt4-W4>` zQuamCl%AY+k2e63i2F~47Di@K6;qILbh`S;)s+rc&JhuNWmVF2JtlC6q_G}a#NeDz zQ^$frufm^nnCqKvx*MNrj`%#r+BZ}+m%8!w(`Q1?Tym5HL+2PV{Hpm*(a(`o_jJ$@efku>aX)C}8SP~%#ykzptv9pShEDN;CB6f zTP#1{0o4r*8j;^tcm<$a>IE#dN+ zt`ThMOyL`Z2CNkPn>2`I-1bL|0z3)I(!>~kL7#Y!ckNuvQMY{tuWQm69c6`zVTkel zKV~1_(_I#g2jm{qxmEY5apQRVX`D$t*_oqRHxX8HzOQ@_0R>YV zFdQ^32I>geh3ps3Q;(_%RlPLz*uMzCDU6bw1!1y(8_J4C83%M2&|_P+K1h z2V7sq> z;z=Z{+3#|>wr1(^e^RO;%lMn;fvg3mgjJBb6mn%j)0msnh|(&fDTl>g9^lDLlXRDH z$h2nA)1zjbu2|Ay^uuO(?GO6XlT_gm!nYJ} z709FZe#}8}#ec;LNryB5sb)?9t&P~T-QG|`zIOP> zH#VS>yo-ygDANMD($y;zAy(FQP)>+a$hmwwreY~Mps%zAWCYP|MD>lW%8x5iuHl^A z04gINT(8A~>a7kK1)OU?^n0oKcL?my0Pc?sHBe~agoP*xY2RcGH#Ucrz>`XUXRcHg zdw3ZQqKw~1{C^F~gAXd?i8g{GHaU6=ugZ8WGRSzx?A`cRvJiY-9Q!V9m!tlmmQJuW1H z1mcKvKP@2W9uMlf&kQ7@ueAYNCZyBOH^QWqwg#$70-}eKo4Q#?`ssgXKSxy@H96z+ zt2l&G|9M}I4AJZTX^E6wPq>JZy#nnNe|YLu-h%T=!964(=#g zY_|So-`C+>B-YGUiV1rsnh|u_K`If#Ji3KK!!p5qGoYz84$Mkw>_e#=g()gF@ z!bK^)RgtYZKy@}Y`>6#zyxDRSrz~i`lt7*lEaW?U(Kn*1{gcxFt$=4Sf|k9kMGI=& z64^|Mfdf|qZE1b$EAS4Pqg?Fu&j7Siq}iGVyw;7pxe(SM-j86+T6fLL1Sq2s?0us~meZionEc2a}ywa@t4D!W>)a~jD^ z30sOrvKREr?4-#VNcjid%e0`DYKzGbohx*mE$?;khF*)!$d(20>^G3Hh2E;a-me0^ z_W@gyrRZf*pxMVV@`0>*uz^>!t_X*$h*EiwyyRlh2uyR^<*7Vut2o$<6!1K)@$dR* zkbi21FMIsCY(~R^tqEHmE{^->mxXRaeqB(yRqgH9f(TIk5fXykn-)O8f|1ypOe z)-J$Xn509EubMH}V0%Y%#2G17vY(EDrO87YqJkFws3T~>Q)%P7enm54ItuBVV&DwW z{$#Mfkr(lpS5|-c1?;}G16FM|3Ms^?_7IyozNslE=+^S!^-^%VTDht%oPLh8-=QzF z-FmG&co|P;F{)?N&Da%Ro7y5Jxq!IG8LR*iXP&2B*1XzY?AOKFR36o?;6>QeaNuAx z^0KmhS+Ja9^7AJV(hF9@FkRH>s_xB6k%0w3`-mL{WMzQMsoL z^!7cz*#G*#I|JQ+QQ_m?!}GiU%(v(a-ME}K$bv9kA@?J{WFps2Sx>&D{=;!6E=QPk z`uDJRE#P!2qTt;)zy2uajf_t$k4LKb)N-88k6P`p;$V&I0dI&-5uN;)2O*odgYSsQ znPvowhS;1iNNX^dvwowkJevJ7Q_YIdy&(LuXuudZ?e(jkN&Ad*ME)=SHRv!rr& zzxm$Nx%X^YqVZ*|uAhiO9I{8U_=$oyqLwFQz@_6gILo@?dzgN>5`Kk}^erlB z6Ng+>&bNf&d@k&Ky{`Y&Kp)j?hxF86p*<9BRb0mDCm5i^+46(D)Yazd7d)M>Jl$(s z4H^m#FH0R?Yu0;+%@@D7TQtyry0G7g3tuzPx30Od{@yM@zB2#0?f?(T1-bR1bOKDP zHm63Ajl9|-53m)pbZuRKXz2ZfC)njVL1a)FJc8_7xVb<6Xv$({zMeZ45hJTpg)UKu``+JE|Q-$t=+`w&o>8}i<+J<+$0gyx`_WRr@$W) zE2rLV5+3Y)#rJ$1r8o3ERVWoN@>H*0!V72x!lxSh)P)dxOitm5=rc(%jEdTUbn zUx#$o7Ibo+?z{96%)+z2E$EY_wi)5{3V`|rgYaa#{XS6dXhh{_DfYc@8f(o+U`)s= zpfZAHPe5t3K4`h%ptr_7)@hHi@z7c0X*cXAg_96w`z!U{>GX&^2yE3J!j?_utnLs_ zzY({SK+;`{;sn1#{`ae^Y6Y7;ZMxih_VvCk>%z)~LQU#whFSKGHJr9v`&B(?!)IDm zgyl>$K|jel;1K}17B!AlJQ(m!a#ieCcyI$wpWCeW*bAJ{Tso9v`I_6k)l^~Hz{Eew zqc1Gp0egvOK+I$VbEKLdV>52BFR!lGe8!#DQ7vueZj7 z&kV)i2bSfAut&ns7IgXzbn2S}110E*6#O4#H;o5h zd~7Ea!Mk}neG3Q_PN~A+)`tg*jXa&=Ic;Y15k$W~2P>I7X*T&Pmqo#03m(;veiNeL z^-%~aZ~Uy8V+dO|d;xKDL8lL=?a#Y;!t_A6l*2%jPRjyr+Bkk}NG^v52QR2~xd@I( z$@N%D_h7X;7KYkz>eFm3s#NIC^KuCb2)h=Y7M}X7;514KG2^o3tGD{>sS*1IGlEEg zUOak*2j`%+5U{E&1FcpI>DMCu;T@4%qY&44I-C6q+Bv-Kff_N^XqBdgp(|2|-_*iJ zAGIc&PH7%oC{nAHQgItOW$HS7i>7V2AlVYrs*sGXAHf7E1cBzOcbg9X{xT|j_`E^J zmqA5pGqyAj0kmxT4<^rw8a>g7sMfQoY}T@|x=5A8l9J|SXk!YGvbROPQmH}P(C1#f zG?l-kTHpNqE>AlnYPaqOFp7t0aMfY)6z!rAMhofTTs|%8UG~81Twd-ytz@tMA-Qe$ zJw4DvAk~0*otsgJX_5wu_jLQ>a8bWbR{tgYiPJ*%Gk~LTDzho7Z`FW6)u-l@8y0~-w($(9-&IUO(gaMUbZ%Rf^=Jn{FZe-c+Q4 z1J`ZbJlJe}bN)a6n0D6(zl>JXA;;M5eAm4k_=~!X$jE^AK4f3BFCvTol_NcYq5V&2 z)*@@WryU&2a;*1qWnH+e0Xl|1KIj!f@0F0!t!DX~G!B+%@T1O1LHnMdBs?M?^6!rh z^`Em2jKwU3hZG=jgb96@tNl-MJUpspkMOP&^JMh$RtTie5E<1t=i{mD8Z(CMOo*K^i*XPEQi}xxnqkaFQ-Fu2sIys@C_^W?uNoz0uc31t?-ETo9kIOwy z-YWd)0k|MkedljJZ=AHV=lA5Fw7hh^KNd5S-eNUO8p<)5dn7!f*x85pbkv+bv#;a< z;eg%NT!VLboD!rYK;fkC`@@z`Emac4lp5t?s^wDr!--8~rH}>W>BX~P;ny^p?g_$G zQKj+Sml4_HlKd0k3F_sT^$`M$of>={2%`MEfw;l5V&-F7SO`pnX8CjOWI!A7A> zb{JZ)WL^7fQ)_o$UMZhAA>UASDf~ud)=jw+*D0e`(R6Xz?;AhNpOxF`?AAjFZ>4m5i zQTjxTMkxKTZK4mwWlu-{E;Jrv!egWab6CcS#{?T!V8P1}~M8u3oV4vEDR$ z;h!*?Jk2-@aJPO(ZEu~{kBLi}jcyxFdFx+Dg_=!gY!zEhZf7~YiBAu_`9=+IhB7_; zHOO=}TjhM$3xB4!a9jS?yDuM0Jw4JsMMhw1VA>@d3|WljBn3WE@XUvVe~R%Ys?;Ef~8BFn=$G#MS`N%N1dYxF~%ckHnMqMb$|@ObDeVOev2YcCCR~Y;{dt zX(JCZ3RwghB#|!nggetPzaILn-NZ-v${{6>;1N6erRHux*^%D!hmBqKkGu9OECM_z z9YE14$zCXjlWWOdK+qqQiBi<0OBz{%X)@1EObM{WMzGuy-;ebtnP6oefHhgF`SABP z&{2>WubMgW#IV`D@K2cHF3(xyJ)twfMMrmhH`nmek{iXTo-h7jCWO}#;5b>@j`jEDqay7UxXyb!fQ|TjVangRVBIH;X60XQmycKj6(+sW>4eZL z>%X4aNn4}Sjc@7(V4nM})7m3^IVI4dNGBek$jpm1*f&;8i^0dDAMFVfHNAt2CS?^K&;> zVoKiTwa5MkIcEfmjf!eGyVxPJPQZN^E57Oxb^RKDjbOn8PBN>pm<{H0n+;aba))s% zBW$hShm(7%_v-m>@oX)NdU(QIzr2(zT4^wpkTV= zaq&@7&_25pCp6`KdvB3*p4-?WE~L$=E1FvMDhN7;C10wa5Dj{2VI&Sq@Q0~Pu6%}% zanGmghk=-p`|PSzXUCPJAwDdSXee7Cm|iN@zn%Zf5pX4?{i!4Ltic8GlaH5eqlsJRM8LiHznCM-|1tP=Z}wf6qN0E4**3#)_0SXRGCPX?jgNW~Dl8 zAI4u*a<>2e>ZDZx`|K7IKI=OBRsdgF-|YsS{cSHjbXU3E{b|DK|K9Y#Es2Ld3%Nvs z#1A8e4)&=RI~DtB{QSo;|87DitzKXrl?L8_+hKi=z;!xG8?c)cgWgu08~3$_-Pie2 z1+cg{k#x_@L9JNMvXC|TWFfqjavXD7!d7+MIlk%oQyWXP#<2NGq5~>OE1GmfD4cDa zyQh>w=R=)Jca6<(-W!eUi%RQxB!?<~2s$lRUFyp2fa!a0G-dKiavPgx%l@+eWKC~t ze=1d3f5cPOEJi3K@~KKS6C|tuCh3daDDrqK1|8jZZiLYj3fjPJ~x#Ji|Ej3VLuI?mM+nbjqQQV5869b^YDU^G6nfvD!l& zx-zx|7RwUmo|gCHp@Z3c`J{T)B`_p`3OnNk@unQfNdb{DX?zUy6!~ej&Eyt%?P(ZA!?D*I07V* znl(ra`m!hyB*=yh&?3Xd{PTn@8-&U8!p6-uzZ{Uioh9@qB;Eihu@LdhEqOix@(~Kp zB4qf0BvmNs*#uY=H(RsgtTzk3!$#p(ga;3ctzQ@ZaPMp@RLrYcSc@w>aveJToUHcg z4Er;(V;?{L&ie;UnDS=V(>{JdBn!!ag` z@C&s8Ks9irh1-FHOjJ`D`7;^ynTldEvB+;CGut7qR;VtX|C59Mv+R7mA=DczOa&n6 z!P)l=fY@M{eWjxAu@l?c;W~0yzh>dwf6dAe7LT$_=2XiA5u*h}FUaEh~}PP$g>EOSp#?@kjs_&tKu_R6B+rm}jCo31)_Ok?UN< zBqL|j>iF}>(H{(H!PO^sf6GUq{n5x43E};2 z$YKU`9>AK2LO~uV0vuF-Khp#>fU{&Nl_&CGiI8b(weqv1sre+KafwI9DBa4k6$+x| z7qFatY1OzE@Eg6x6=jVB>#$c`*05*Tm(bR-oov)Qmgr}8*{0wvc-2IfUW$2uiu-jb zQKu@W9I0S^>G-PC_aRN+cGMt&UlI8Lu}((XY-6I~Wy({i4=nh3ZBY3?iX@Yo>eh(~WHq5m@cM-kyuvBjc{Y$VflmNS!=yk7}RXvzA=xDDA zf~AKRvcfR_JG3%>_poqiNILqc&8ZZC-@opBKH!j8;iIMn&;m6G>j&gA(I2R>YAjKp z?fwmR=mr-G>g#xV>xO>>+y0EE8U|XwA7@;cyv0Tdxk;$85r;-l^}qS(pYuqqwHSf! ziV?fBGas^LY_|IFMaI!!lQ4wf2(SY{9jJf|Q;@SvWWQHiNlesbX$_87S3XBtfO-nJ z*#wRR@{OnA59H3gh}^u;M`QGuetTmd*oO)!p|&ff!LXGe8-RK6qR_kfwqXo391DNT zVs1Nu)d)!M)5vlP+eUgYr*`4mV2=jC_KbD$o2g(-5}3sOfh2~belLX>N9 z5x=>j)DYxv4qQGlr(wE0U$rZG_||bAL^m3J=evdn8{Wng+0jRJ&Wp71M54=x9zjV0umqQrG%DaPRu`#!Gly7xT14J$G_AM#|sm=Zx$dIHI0<_)rryyRfZ zF`X*}(Nqeg3p*G9)e69h?6pJ1)`;wl6FIIiE&UVn=_!hXg~bwP&ML$jdO-xLbR8FQ z?DXRbv1a{zR4fvaZ~)>f=B_k{;&31XpYKl%OUHL0jr0V+o_!(+jXR^M%uE>5We$M?Zv1%H0%rtilt_eWvqU zEMx&QdxUi)O#f(HwnisK@HvG@uwYvN^mi;=f(h9qqwjNN$n$fDE-w-T6G?Lnr$2G~ zZ1bEI%e64j^oPi7u5bVq`j&~_qP{qnWVlWiRcsu`6*X37!8*wzW0ZRw?%PfRY|mxj zJqjA9C%EZ{X`{O20En&@R40enMrhvRJ(fH13V-{R?dGd!VX^$b=qbVTNy(5HYHyH4 z$g^39H}EADeZEKMEo-LEIQKXkvBN@la*vgVBDdZmbedt)*ug8@dwYOODi(sR2cF1+ zojr=4&BpY{@n75%Se`8S2h8(UtfYX#_SQl*kfD*UQL6Wbc}=J-7OIU2iNK1Wub|ww z(3=4xa$Lqw3QlYbwX7c;eh6(d{4SOQ|0;CiCzU<;7WtD6SC|(Hxpd`oh8d0u(gp~H zlG|n1Q-XOQC3R{L4k7nQOqAP@s%?o9eY;D)-kSWMTmZ-R~tS}*Po%>`)R7?Rdvt?Z3tO_jP zp?2mGpsX3Ax2Og-FwjIk{$BU>jN=l<^FNIJ+{UfY^GCj7XQ3s)Tf?YStm0NAa-hXf zZvpY|#dqg#=$91qy74Ds3Gg5tJ&Fb5(NZ_eAEdM~IRK#7y`QR=kSPvIDC5UVo2SbG z_qZ706JKR0X06-w)k{ee;zA18o&Io=6@00l?g|=EruWc)q(LqO-Sg zaOdk$DH*nn9k0 z9#ZSW2CZ;HbrBNr<9++kmC0>;nfWhv>*V%6vy2Z7Tuw`XJQXE!6%lg@)*`B}{&01$ zWuLm7o-WFiQ zygBGS)1BYo)o2mtZ4=Mvj~w*?84}vYUPUq`r~+s5KwuYD>RJnYAvE+QgVkjzW|E;rB!3vV)4c+ zKM)J9ITK4GJDga`cg_mlaD|F`>7B8;R=MOLqE(Y>YS~<0U_BAo)Ecg3?cL)N!V)nZ z{HX$581JXu*T{1i4Ia6(0`}H?Mqesi=@2!F6kZr^djJaiT-4(O03V9xl$IRKusz`2 zATi^0QLakk1wrz$#`yM9qu0S=^J((M(GT$h!nsHp#iOtPD-MFnzA&Yl^XidbAFT+z zd;m3Gz9X(QHzYT^%1NI}yz_8%UcuyOKCC+to#4CQC|}U5kw+>_@A-&C!-8dIX!@Hl zn4&+n-)gNM26bVHuBI~R(jP%G#&m}%N*{k$zRBFy$sj^uuplgDpSrfQcfrBNP)WT$ zuxvI9Vg>+;Q3(auN@8Kk{(>><350ixL-94Q;yZKMjQ)y6TGkpN@RGx|Gm(o%QQc6} zSq)G$m1&W5vahdWA=~bk&RMX{sMA_m^9g+s$3Gp<@xdh`<^`d0O0EO{akL(5h%M%< z{(5GLtIt7{k2oppe{S1R^31*Axguu#b##|+$+7m$e1qRqjrTxw1m~nwL+W7*aj-$u z>#+SrEeacFOS5zp!HTQoeKxb-h7*sB1{M;h?Pk19ez?-(@~SVJZS_}m*CeYqLk*>U)(yMmmD95r zBvx1@$)7Hri6?^WxrOK0U|G$(Io4lHiY%0j(qv+rx4x8Keze_WE(dsK_pf*IqlqZZ z?Dx`jX?2h-`=d&07ZWBqex9F}*I*v*>lS_J&QYZvO$!x?Ufo5_*7$7)agS8y71%gx z6n;=rFxtV=bhbhGalg%dgd6@4iHOht7^ZNNhEoKUpxsyHzwQUhP1TS5%Hzm>-f;3i z98wTi6j5n9&?lEF3%e1E-m|xmiP>yN8ddw5D7uA8Dg7bC_WAdHx(P%d>dV4T0woF2 zIkL}S_Kg`F@{x&sd%t^!rZ15cW@!et%irMhy2sreUWF}n0xayiZ(!d6T60@^*`5Zb zXUA}p>Qd&D`CTlgiB)_4588z@b61nDh!d}8Rcp8=(OrLbJ-2;EEF|_t(pK^A`86ZQ zlerUc_Q_`k$vi#A2EWv4+k z1sO*V3iBdlJ5*sM_Xm2j=A%kKOy}A#v-vpp)WFXc7m;q=3uzU<27Xea6a!BjWQ6Xo zSHGiRCPxZ*i1WBA{d8p{dIyEDI1%xc@}Ws^JruC}e9U8PUqRFOMRcd6^4_x0K^_rl z=wv9O(&_A(>}7E;Sv85243yr{ce(9WW=BmM_6$hg|ZqTAIo$MV`tPQg3 z{HRi!Hwzasu?g_6_WrhI@K;xD?mwv%sd+r&^1`=bw^UCdrXW%OPmGez9?jE#Vd$zn z^X{v-l>AS?zWOiDMvR#+LTYz%VRwH9OB7%Oc@(QVVebnqzD+;*3SjR%Gnvn?W{Hfm zJuP2w$A#5P-bpNHe757Kb%vS4?@&f0vdFw)vc5LM6P~s`WC#s*NRyQu+d4AS{YI4tx4oxAq z^om%CVTDqePp&=X4R~48DG@8IbrJ;(GNmI138{(#x!KWBWVJ@Ql6U z=IOdf8P@$YJY(k}B$|8oT%Js23E@?xdG5`-jI5gzp^DGn0D{%Ki$NA6ub!k}gsOdt zP{ysNS8{iTApxxX$Xn1eMT8-ar~+#IB~_o>{DEw&J|0zs+dq{sn9mq2w;SkddDO7+{6SEQo?Q(sl5W zqxQpuREKc?hf+~Chf{5oc&!ltqwe8~G#Z34U-c+P`Ux1!DKrXqxe%M$C;!n1(*kv6 zQbmj{2ak#vH$OhZ?pY2+LEhSOZCtY52W8&?9OaKZ%M7X=S(@Nd} zDnM*^5XA(*cA0u`*~1hw-(P^QmF*uy_bUFU?(z!cm3aBY8_Y7;>hmcLN4{0Zb+tCa zcgX!;E@I69I1`Ytj@47JEW`uFcB#HY0R7$Uk{S8l4laFlZ-n?>LOp*5k(i-(1^2q@Yad3v2=W!1 zjf8z0uh>*Y+rj(e{rA3}1JFwZS<{OY%>9&G=Ec1)P7`uZvmsT2?_WYQ)Nk%`#3_lF zWmGux4*d%3?HNXrKO`NW3nk|c`#@7DPIa7HI{)2r+rIUx*RgkY02%e-+6YxL6&!^x zYCbA*6n`Dx45%*>hqECHm-jscnjU#4j{^^9LA?D@mxT5zqz^U8LVQ-~(BBMG*$c-9^<$#;9&p!NNvA&h z&3I-Fyfs8UF?bhhMcdmfPX>*GuS(iP}&JKOUv+&YZWg?R8vTUJ*idx}CsG9l?J z`_-;;lG1dx{0rJ{Fyd|8QNHf40*&i;p}6f@5pMS4q*>O3k*XQ0ibNZ%66eq?MD#+C zi44DX>Q%{lO{ z3?_yVN^4ep3ZQ#DEwB-(aDR>269$QH78+T9=6!^L+bu+L=;yfNow`@LecYVWq|(`t zud^ijDN>08ILX+geqdAxDtPWK3@DZsm$Ko`a@H7H9H-v!rD3DnyI{{CWk zx*Ju<2tXQtlYL6bW1VFrCI1-iJ0DB z=b{zE@(EY~%fZ#(pUuUkNYG-tpr-)z=t`dA(t$&!h#^tXF3@82MdQadl2 zwbSL9c$$nUb^jCTez62-qM66p*r~VI43lBwD>&`F7;M zUL6%VB-DaDJIL%9h#ct-f*uec+pzfz0Awep#E;ELONB_bQVq!i=Xl|(jUKQ60FI_H zj#cG%{qXn^0(ndou%--cV`v%^nwZBy!H}sOVZPP=OjhoM#z4KUoD3K8IFhlK-we=C zG>MVbn7J|+?R`|91<9aX@;Rle#M;}CinXa4ZgLU27?yj(tNd*@T3TIbg$FU_hAOdh zGpNwb^@~2WjDwmJzEz?DEb_oGwV2E}&r+V~U{rj|nj6nbPp=YP4PI`h+B~D%E|1hb zfcTgQiwR(HtdPnM@yUikrZv=tQgP&b{#J69)jx>w;K!tNnK+(|l$4Bxed8H??zyxJX_2`(kmcQq3z4VV2p`R+=3Un?&8;dG@ zI@eyF<^`3VgRHnPrbnoOyU;W$R14wcd&@*8-cL7vghE9pvL1bxfSU)8s-C*`nIxG; z7TDhmNCIW&Jm$2)hqkMbXjy35iu(P5J>@iL(yqXM%{`92j$)VNJ0Vdl!Gi^{#`|O! zvd=JKaje`Jf5uKdoZa%o^_jiYFKXCIM>3TdM@5;J4+9XN!1gmHtFV*`0sq`iD&!3O zn>mb?N(VT`Xg^7dgaRHu9GLu6g(s|d5q^>w0b`JJM3GQU^J`K;@WyG){iG!5diJ(QSe=3X;Gm{(GW%#)tk;(5{vYST8TpUHE<|OcP<7FB2U%Bx- zNE{h_%fun=(3O2Ax0BeAXv~4aP0+13fbcG8S}G$BmN<8Y;kXhYl{kH<05vPY=z>El zJK>!*W09kBE-SDt;hLgnZ_bTp{|;ub#0$D^h+jJ(r2RD)?PayuTzpaU81Um?!|h;ckfs+L*u;C4bJQUXn`k+|NIrbX^$HKdv6H|NNOZ;XeDSSA`<|-W%Z}evPRAn>0pDh77|sum zgdeU$dA49wzD4{Ky4;ZvGYGNWr*f6Asc)%sD2>vqFN55wDgN|FfEjKoBR97NXk!4JvDlX8rq{FUED?8(?GVl*lxVMX7 zA`!+mulg7>$q*SX=GqW610Ooc1*LEqNB_#W7&AKe|2fA~Y`vZKwdQ-(yt<*@QNufC z6(O^pZ2f_VyK%-ldlL`)w=)K&p@~$OJD46%jTyQOd$K6U-*~D`1;by6&IGE@}LPJHJAV zJc0T=$XV7UMRK7bawICZ{$m|V?EcKVhYa+GM`u2~ua$0g*d``&V+MUxcHHPt8?mm*VyqZVnMEOVddzbEcS}O@Jz=os3A7{LK_V?ALzVMvm zzqd_VBGAXi)AROL{P9|SZ|k6z;bxn7LSeY0+=87XmQ!V$qq?AE(|$)ksM~sPq#Lxf z{!wDV<38I3_Yam@h8Yu0#H-T}&kUPRD&=*3fm`stH=S|_>o?B)#UyH0IvlpSsQTII zAVNZa{hWe@)F|W^$s+S7KADfLP@T4K-d%frHNf{ELz28i9G&I`duM)hObYMsiGH-o ze_UTP_&Z|i@YfyZh8Q`xw%eKiFBMG;aE$t5%OH%KMl9 zsZsj{$HY(-(u1d5yAP@DllF$bVxzX#OoT2NC{dQkL25JJo_jlEvE1~}D-s9dh2bF7 z8H<1FZs}_C-_N`GE^K@3?GDE>VKnMiQ}OcrH$Q0INWTXb6YdoOQ5gB*2_0Fv>f>S2)|3?TO=p|0UT~1V(Rk4(AnJ%ik#QfwoWlX5ZzUdXARKR+&(`1& z)RDOEm3Hp{9gVDEGrnUOLc=h;OI@~_a?-gKhxZ=RN?F-`2|b?CQG}Z?R(F#>Rub8e zQeW^woLx%k$iMeCz7MW(TmS*;j_41MX!=XOy$Fi}s3XnC^{?imY?`=FHJ=ekdS=(y z#Fa*zetDtU#N^Gvo~!>3=4)jYX>)xVw0)v(lx~Y7dmpWow4w~l+VeI2d$bIQuPj!w zB&x6y2XGu%Xq%?@hLCi#WE}5>-TF%J5a;ER_+ZwQh?<+4s=7rREVX9>(fd4OL$_He zGONVdX@Y_?aO3a48c~ z6jrUn^!bRSX7m}{uSzYsB^sXEB0N5q?CZ3rzhWC}V4%gT-?)7x%^{G;8`kskTe_jvoeO0Jo)2f*zbEQ$g z*sQH_VcRkKkvP(PHBzon68cmRQS#17h`|Q$PS@=(E*mFh zdT>PXtS&xQIGgj7bI776ceEw)xD`<@nAmzEuR(-rCcEE*3GvqN4;?4uYH@g_ohtzG zM}vX5GenrAa{YrpP}kZC(w`ZT)LNncK=%o{_!|?C@AK#$Qj@!&-d7z#2!r2m@-Mse zM5L+q#Og@hYe@r-@=x~E)dNuYWYw^3o$4kHaBtF>#p0Yw&2&tgWR&Djt7|L*C(mXI?CN|UGAv3tLexa?LULJe-{*`aCjZLD zk`~G8g^xw!w`;M3XcskwG3~&F{e4Ao#_BRmibJ$&Q<&aWyl}+sGkit%vSt4cxRwhs zGcF6u?6Z1#=Dk_ne}4icLS|l`?|Xl$Wc3wbAJ60JZB${XL_z_IAeti)SZ`4;9}$y190^-+HQ}*8Fx%-1^av*3;eZ&D+v9 z*N=g1X8M$OOzh&0MweGj8#Z5KlC0N)-NZ|1sBcX#^%susd&n-CyVo$B6&HVfcE}p_ zwY1n^BX|)%wQTXt^V)$8w}t4(rl$;9Di7lQPa(va?0!KSbFYiG12sQ{{`glW-zCPg zqG@T2Ejq?Zu%lK$g1m&D>Y(xscg51A?&AkrdU&^jWfz{L5al(9uu-qID%Zc1pg_V@ zbgoT>&dSg9&zn};Q3?-l%? z+RiT^Z9Yg>>uYr@8-uXjd1SdQKuLp3aZ>kL!qDf8+kJ5!!KW2&$!szASw0rMdwO2! z>vykg0~@kP(UOw#8JE*3Z8uWD4>Rv04F>VakAu1*rdRcc2u2$rsIP9i*{MvS&o)MI zN8gaLVF*|a|K#gUIe4|7Hdr>-%IJ?n_j0NyJwjKj}cxda^qtjd$a8= zTyM_jM`%>fx?iKGz4~b;MHO|A zW)67TCtPkD3UOai`0(_k4d@v9@vA0q_27Rt^Cq+N_A*0Al9A&3S5}f^2DM*-DwBWZ z{`+z1zt_T_LYzyT3Ph8D=4`NS(L2cRgO=63K3xE5T)$N(o!?8hP9^PeKWLN*!dKI+ zgg}5$8KJD{{Ir9o3(=8=8&!D`}MNxeit88MG8&wo=-N5BjxKq?x~13 ze*vlJv*{#RM$*PrC&qo>9V6EX=&T)@lIeU+8Ma=+!VTg`-|J6mdOgnGkyUpH4%(=zCpAm3H-t6Ys-9Xc$4+b>a&6 z-m%}_wP(DrjY$B5dD83lerx8UwLm4D2OG0;V5uq;|9V>&Cu@Bf6F;KaU_T`I>3aKz z%x{a~PK!u~1(e8#$wwYnWEDE&-a0-yDB0X^TahK?D@8I;aCoQezC9BJMBLB3JWS+h zQbHk;N)SKf{qi?HMJ^&e)h4Uh8{8aq>ld!Vm9DWtbJdgSyOU5(v0dWP*+j`Tr(T5~ zqWnl1D)804Oxar1FpbrEfpVv;A*0$;4wIa3z>m26B|)}|!!Hz%HLT>Urcb;N~WL}~EIyy8$=U_J*^n;}MB(o}E+?{%aPF982< z5w!rQ6#K!1z^%gH(3ij zPyD{J^O2ZuXwDj5QUy%9Z?$vZ5NvBUMBTH?b z2s+9gXV@4DZ!Ce$`iBM+pd;qYWv3|ZD|U)>9( z(y%a)>Hu-1OUpe&fWT#IWBcy-hX%2MYmP*!CTH5JysJd}Yjyl3e%DGNMW&Fn6|Di5es+l%;FEdB^ zPrq)D!=A~AcHCU*V_ysG3bPO49_uVO@L6xO=IbY>np&fSu6CC6fywW25vR{aq@IuXjm_7n=+lb?sfI_4<-6}LX^r6XB@j0_^#>}W z`}6=USVy9pM|R*mjjxuMrKO#Dx+)C%$g^n-nU zgsB3;k)&|ulU66)Hv??U0dE+~Bx-)P{xX&Ly&+M2qtozu5MC?E1HzeiupXhi&46t) z=n1tjg=V^x;PYNawxkr>KI^sQ(B1y@yXAp-_0g%{2F=){BRydAyg^EkqxA}?81NkL z0;9^>ra0Cfjd(&>)fx6NcV;bVrBdBYW z)CkYx>s@x9OMg(-8si4RXK@2&CJuz#L5hWV<`GW=Ntv zf|@xR?vDlIX237k@(#J*LB2IQr0r}8`=%KO;Fb_EqhOk9z5zF@O+(*0fgZYz!YzSq zjoUOP`|Wp^^9_|ZGn>Cy#E-K!!={c>bR*u196QzOU@~TMx@U+#(@VFag5T{peM+Hf z1C;sj3d;eQE53LC-~Y3amKFW>ll@lY;92Qxvx)(mJkk*taQ$6WvAMH#9zAA?j^DT$ z@lDfZ8oZiSCXv){KLE!EvdV=y*=QJ-gp9LK*M- zZnPqs|E}MZoMZQtsBc8Fnd!IZ_Zv_nKl#1GXMo=|P&P0F5O>u3G-LC!Hpe8YA=k*Z z2#jwbEfyrTCT&An!FU!}zZLv7lWKx6=f4KymUve+Zc(2O*$c=@ElPY3!yHEm^9Pr7 zUJ3Og?e(HtHYeDn(xYV=cy2=Y1v+Gkt{q;=4;b9B?*Thser9Lf&mh9A0kxFNl-*}M zXlx&(w%^iyM^MAgWCPzlP7d^JGhE7rX=hz#y1MsB;#qU?-(Y?bbW}J&ckrvFFA?Gb zGEWFsjE5F9lL8pxW`KRTM!+YXHYN87GfLFoaf`60#R^b0hY!M?=bM)5i#6vKZL&#j z{Uw;oZ8lR}g~tAU&|0iS2dX*G3~QRckF+;~B&O{w>AtgYjpRH`I=Yf&&>OrjJ@x%4 zDeP2<8AbSj-n~B!B>9o1^c2pa9umRcS1xJOfaPR#g(MJmtr~If-qS6XzNGg|`Y`C! zcVKB5v){e|fmH4P0&G1Qf7Gj=A5ch80W8Mc#04mj1j{MnZ1Ul@e!FY~{ON3^&R>Of zVExA=wODZ^YYVeZFiNH4=YN=Sz%<~9ti&fcm1Y%gu(R!f%OidEplbG@O5f`K=5!)8 zlgiCYM=E~*{@Xx0`0=gBwx@Nk1&d+`^ODEY|5TZ{QfX=$eJU@&rkE@>+-ma-^J@T| zSw}EX9;B~+Ayg9-^(_Qws3e|-6`TbvOJXwm-rWNmGy>1Y)9uq#kpn;tOrNP_vz7*k z{h!+*#{=h~S+ah8kuuJ%ibduvhPEuQp|8Upn1flSc9NOUQZ-c~$u&7hrm+ifa+HqC ziEH-;j{H(WG=*fNVi_#6yr$(94(%E2FZ6X-CpuUQ_;(FC z_MdLG!5xd(K&k8zIOn$wfSyMMhRqqiuyaZ2r_UvTpT+cb|L0$>f*4gBh*R#=^#kDM zNO(L^7(hDE(l6)E(Zp3?6>ZHSetjQE4N25TT4qRG&Y2{d2b-KMGuV(rREA6YzVt+7WNpai`VDs( zC+y1_*KbB7vvgi{lWVD=@AKjI08~7N*JC-ls$jOtF9zA^C z0!GTe`|_g{>k|AZeQV?OmFuH$zyDEm-%&|EZX3Ws5F9M`1i`IoxmRl7-r=Y$&D`QB zwOm;#h=N<3xxHRya~~{nX0L(m>11ENN@?jhFX-&VlC~&NJ@kx<6Nii5Z|S z_3$xhnTZhP1G9yCHJvANN!wK>G4%0SzPFj}cD4HCM6rhNor^Euu07Gwh(FpDb}nkB z#r3k;CB@{J=hu(lUF;2c9&D|ueV^An+jtwPMY_l{`n+l^p?>n>L_*|>wKvLk+g4B2 z>)@d9zvJrVx-tp{)yAnECOw$_qf*ktQf;Xt?RRFd^$CQGrVc9K=OUT6g_(!V#QV$u zwi{Eidvu7L`rKnoijaaAR56Ja*?4|>s3i+w#f10GDcXBvyLIP53dQ#AYSs5R#eGsq z91z(jEb5=`ECD;5yRMS9RXUaj(|i3HOjy1ar63wOM*zzW-g{s7$xZh&718yCUJEli z$Sq3Uiq@n`Z-xqJ)57`KvE;2L{su@Q9TcXVR;}PoUsETBH>QZxkROfsv<&6N`)r4T z6n)6dnjy2j0`+X$C8pBFuDn9S-i|y}gRSl$k0n-rkB&ZQq|M5T`0Bo%ooSZlT`C&L zBxD7xdee)DdE3F%SYBx)b;CA+2&K&48?S}?%yF|}t@oVK2lSdtijv}5HO0^eEo50i z+tK5QWh>U>##Ax;X`@lI&9=rQw#$%W+B5}PDq4I`OZmXY!J_+RUh;S9qy|y%Rgy;q zts{D=cy5b3j}GhM7ul2CRGtFW;4 z)M1lDJvAGyuEfi3x=%J50IY!fsB(t-hdSWb4*-xfI^w-TGT^LH0|hupf;F25vw(Q)$55$tD< z*-Uf6B8(DX8kugbK5qaeOj!T@c*@Pz{<3Z>LGlX9QFl7AB(lCEZT~K=@*K- z##CUfF%Y7aO&8QZkhM9$5;v1=QzdI>?+rU@hNF(LDsj}#%p36aNU+eGerFRznL*l; zeQs_OK^dG#3oBK}CAvBMs&-aXbQn_R=Q;@+eFu6@gD_N~8P~$meGk+<_4p)L-CYa0 zvp5})6!sMG;WvcMTqNk3OX+OYGhxDa+?i4xq8X1+l-b|_&fb;Sze?{7d`3lAv`qdk z%;gsw!`>Tf32scb4GX99@JhdUPE^@jxXxBdjKSGq%Y~uBn=bgHFRGc*h4+RL{i=t; z1yhRwLQ%Slsu)|rNzHRjJxif5O~Z9**yVC{Io=~wx^DHcnL%Mg(z;XxlK|0W0AWu& zO%JHKn>1_6L7&9s%HKaen{sDg6ysbTxoZ@6%*Fa~*8$7V`;Oau>_u2(Pge~4ogC~~ zYe@e~MTIK45GJd03#+L*-b;YJVY^DCJXQB(8emVEK`TsaZdO>HbIWz4{fom(0h{ab zF`I=_6~2-Rdk*JNz(zrV4^`>=Yjmm$9CT3vFfj4I{;{vqfv>}qWJ1~cF{$^<`Ehv3 z&=Yi!l9ctZNu24Ja(LwT^ueT~k>}NuwZij7A8d*~Z+_|f|KzLx^Ef2tR#Tzu8(>Ks zHcVmKf6Qn&q$J%F(()Mb@5tpIZ=|)X zgN*L+4>D5Qc;R`V?&I7X60}v{s5zu9FKZ+FhXLKb)73vUpDoQHjoYb)wN<~iOW9b>u zS!Qv1ZWe536OvJn0~)G=A|Csmh?Fez5Y*n#CMKM9JK2cy7wryc8Ac6RwRq(`AE8j6 z1Ff}=_6~N(EC1}zx9XZNa97+eO8q^K7eCQay%H8_8qhKOZ|K$qJ?bMB{FJrD7j8^Y z#U;ff(;eF(#kv3!;mbmFxieV`qiOF|LVVx2P5rzX@_apE)t{#RkK%sFvV}C`|HXJY z1i9B?U_zcMku6TX6DLC(-0FAUFPSc6lbctm($Q(HTUrhKu6oFkFCpUcu=nM(YM9bD zBJ}w2%ep}}$^AbkoTwglpq->V^#9VKsq% z=%OK`vMWr|=jDY>(7OC1XWNIR4+C@3`>06_?ZKhq`(47ymF%`4jdM?j-m0z3-=*6! zhQ_~xb3-5A@Uh9NtLA2O&TE0gr+<_p1$keoor7GPZbJOLzntNrJ_+lE5JX~b%hH=8 zo^_+UgnAIH6&%X-&yZ9=RrS|)TQ;siPr*|!NpU# zhLadKt}GR#sOZO4<_9}fTxj6pCG#21UwOgkWMn_1ka2`Z<6CbKl3Lz`r5R{e7nZ(Y zs=t?KnjLYmk^Hjm=4bZ7;pmROZN15ab_ip3&*IBeJd$5T)h$B9rP7jJ>R} zxZHY{(YBbx*u=P&Zeq0EAXU)rI9)#U`Bp;@;2hIa1HB*Q>vBxUWHyY+dgCuVw#z>DGf$4IAb zi<{;8u48yy3@1cse;(cks~A+gDWKpMItF~QI;JTv-L{hZBFy{WVn~!n9qQ<RfF2C)i(P0yb}-vXwDNgMD$iUJ#_ zzr-c^k?e!_5$bUWZo;ilhr0=g%NYglvkUqQ_ZccjjGBE!8GeMX#((e-Jywm}>Ienp zUPYfJh<9Se*Z}2!T-skx<9@F}kF3G2QS95c+^vvKleZ7nK7QJq!fb#15%1pKc7DvDGX6?aUJ?+4EX2*7a~Je)7dk?<*|ttKIY|tHd#47iJVF zft;7`aQRMiRdzjG;Z-7q+yG%ia2Mkqn(zf^wA;^ZfgPrko?(FAe?v$zLdih=@5VKu zTAWHPQ2r}H&X%pbK#*RhoJbHgwJl2X!g|M16h9LrX32F4O_<>j^|x`sn;x9px3gd4 zSi2sL{)r~!UXMP!WcrYz$1E)k^iS6FpX@pltKY;cY5KXdV08Ma6`VVaI&PFtgfSG{ z^eZm9KOYl@X^gb0C&c-S8F~rKQ9LScNa5{!%+XJNJ~J5U9ZB<#Eeua1p9JBVtHMo1 z@K(57CmcDdE=SaqP>+EQ&72#Xi7MnOn_rjH9Tw4GWG;gsugC*j7wzdHdHWo`Caw=?!-RgQ5gd?m1go18?)bVCY8yl;*_ij<|(?36t18x?(gZFDF zudSJybAT{1a4SJ7dAixw+pod{T(}12P0)5pACp|XC$3E|Lm$L=OS`mpJK%KPCe#rI zho0?!w1y~1>B`d`0#=+83O7E7+Ab`HQ~%-iw@M5{4iA6M9{xUIBe8Z66W>$i@YVVT zA;`(w<-ns|!P@{VXy7Rj#s=O|EB^;nuJ0z)lZ_J#rNrM=qqxqbrb;7@?3#MpPeYl% z-v8SWc9rHnN$dM-%l}k+5n|`2t+dLO-=Z|J=A;t)UerHPd>DeBWsA=dl!f(=FwU)`dn3Td5XjsH^*U3#Oldoe??)H*oub%e?shM#o za9!rvE&dOXo~kgL>E4V3dA$R(0RpfdwUr?BcvO}*hUNp2qan)bA-?JQ!nH9LzD63s zHv}fC*^Cn^i7Wfs#m|-^k&Nii-Y4@p1ii#L+AN`^cnd8g_O-zf0l{!6=L_}}Uw-k`(ZTS>2;ID&=02C{{H z@L=^Gp}#*PZdNHuKfZ0mQOJD<6Ul~nk)_hPQqn}N&}fIBPoy4l6$@jGyr3#`d}lqE z9q4VEqDPKzGsVBq(dA`drWIMLLdb3rhgkg%G**{=i9;^}VgFh%>>;*n(%$|fQt72= ztIyyrE}CpFx76zS_os^2*C2j`&q*feHyOQ+llW~qFQ$$hM=LmvEX}mHs zYl#adzD>N{R57fYB-P^Jc1+JmK!Ju}27%PHv0LOeygEQp(xEEmMFV&^SYnY7C+1x_ z5@X~do{|$AliIiel$7-o>PyBg_4>yw8zhOx1Ms>I{dXyJH05eo@}lcDif-ebUaFEfsc>n;Z(i?F?v0o z^<>i95M?mMQg=K;c|BlAfE`@5f3(Xfdv846U;J?C#HxJp5Ieqw zqqOEAEix)v4cwRwGYVvicj+k&un8n-6M=F1SygF*O$fwGiP%|0m}xy5)E|c)c zL7?@~MAM`Rg}Np&mo=#}H8hJHKK41<6DB@OSTSoNbOIFO926%_9DeOH{`y?`nWtp) zamCuDao&;=`>Mg0aQSCzr7sLn79|QIHH>5H;QFRBjeH<1NMJ+}Mi8#hK{AZZ79ZVI z>;%9juoZUS6XbF-&DgZ}IK@FGKFvc#Y$Jjkhxx}<0yh!1nGVl}G&R*gRz_%%5XP;0 zN;luhlAejiah)@q&X7cl{O^|BXDc^{V&=vR?h)&pT@3f(r6B@COUMhlKjzwT@X=6% z)sP9dX7S(m#45VPA+?dno-4Njk|K6eon+V`zKEp=W8tM%2^cI;{N{kEt(D3uS4ue> zGRRhR>S_s4JNnfg8Kh~4mOK0uDA|_{zlpOuOT(vW>K5b9)RSd-sR!R}i07@Be8e%F zm+v-*VMcKhqoICJRU6F1Q8)tTA4Rc`Pp0)<#R{>=?wsSioJ66eXJBzRJE;W%W`PTP-6B4W^CA(VI)fEzNxGu7c1pG zT0x4wI>TJ0*~d|>!1tBDohQ>f?k zBb-Q0aWyBMDgc+A_-J$$!95+WU`Bj4gtPSctd!4es&%nD`d?lVFn`u`NY45QT6x&D z9Z%En8U`wp?_>NQA90x!X0w$cYG1~hTLq3HdAPamx% z7QVm3HM;AoqecsTV!XB>($;8(!i;fMj2iD{E}gCSo*lxeafZf6v-HODTz2y=A|4ym zBm0dnK6=GPFNEk{Pe|kAd<~5Qg}uZz{Ie{LAC8;$K4v`J3HbD4wE-KOUE7ft_gWgU z7EuV)+6mELAgHt@N{Otg@G!dw(a<}`^-=3+TF5(#zro;8Z{6C<|Av%K2unNS@agVW zrya72rxe(H(2n6dcwn3JcL)8?+}7%dOyys$lXsZ8rieEmHXzw+xz?0jFID|fmJ8G^b4^4{hWGf{6!*qu#XZ;7F<1Dv< zJMZ7i>YasC&V7Gjx0nAOyh+n1*Jn6s|17q9Fd)v6xOYe~WB#^-;Cv}LjML{~;%b3d z(%h~y4}^*5ZAtuv_5{>Qi6?KmBtl*frvLiVZLeg-v1Np zbd?KJ)U{KrOcNFCG7@9;;aaE#_u76JpPVY^6!l?+lNkFcrHnPowq1%xv-uKpStU&a0Cs_wP`P>G^2BgpX?t0 zY!ZHGqWfdUW|0(C&(NI*&@gohxX_Nco zMNpU}Lp&l0{`1B7nswNTF`*%r8ajlTL9oUkbtAsw=L`%lOylubPBMo&+g=922A>fAqTgSt0Qt9!ScAAbef*)_n3uC*z?P zCmpmNK-c0TRI9NB5^+d8g_$jJ{xDQeME*zvi%@3l<(H-PKyj4;QGJFjOGz#v`2}b5 z*|-W!wH9uc2X>lf0uL?-+9qNGvYs?cMr1i+V%o@7C<@fD@7i&)FRW+bW8b{KMnkQ zX~gEo0d4eaHdL$sCORXbaCH8S2g{$)NKC9X{mW6+Fs&CKV>$m9AgUdp{n)0~JF?I( z3~RiJcgSbZ`!AxE*xofGn^eWO>wY?(ABN$}tyesJs&4;%qLt-lTq`UbY^Sdvzt4!* zgevNAsB9h2JMq0)ex@U=S{}YalEy0~WMRd^N=V_H7Ex=GlW49FID@GmW(86WaPtLs z_Fa|yFT&t({?o=~lP22;AF&Chi1*-HN6*AF{yyrY-!<*NX3wHdzjn9hohP2VD*qrk z)kPG=Cuvv@-;1%Q#CT)!ju`Ck7`FI~gWqUO?lix&uPkW*);KBC9sXb+<`DbE!!@5C z54ct^)O~4KF@?1sHEy$#K96*ROdmklj_;2Kw+!914}dADR-w}E;-uzzv^>BBlC*#-Dn}5H5Jpv$DWGLT*Bc!y;7V%q_?2kiYFCJrJreL-Z=_Rtad*rVyJvAKczWhR)siH=tCb! zo6cN4n}2`X_gnq(X;(>RQK;U=fkVF+TqX&KG$P0|z$#O}vD9Z;!eh+M#OR|)d~19yB&+UQcO~9VoWR_qW1g6{X0h8;^-}7DMeCw%lFy~MIR#hYETn0 zq5T{$Iv-N!-x@@_rnV(}VcW8Qx-ll49fC+;RCi`Je!YFe^G(9#fAdaf^6a%KpAkwZ~J5pL^mX2-?#mHtF>H`IW{qZO%_; zL4B#q4G)tG1A14&;}5dY~n3Bg8Fdp*- z5%TLY*%R;W7I=99B3@G7{@3pa|97a#;wa{ai(``inyB?sliY)jZ1II)@!*R>;^k-U zG)ziq)>i=%^)3#P+niUraYFJ_bB_;AV%6+Lo4>1~Mzw5lVvcVovDY?*2_&w5jftCN z-Q4IlE^(K-=u(>k9SE+R-3c@<`h3DG^S#3I&Y9zqe?QJ%xcOz}-z7Qp_IKx-zYji% zr_>&E{J-1dk$mEEVyJm4S32VpJ@p%ujDJeLWKJ=r2!#;EZW6^V2SXfqLI>C& z(aRuWd#b#^nPf=p2}G_T7{B}`s*;D4C!l`f;hRKcT~tQv`uPPOQrym6$pF@Dh|sk_ zj&tC@84~jhAsvqJ78yCiF_ub%2(Y`kIl;^bxtSoNL&9zVL?5?HFEf!7Jh4xBg*_(x zqa#WHMe@l=BMCTbT<6l9%r`9Z8w2srJDQi8!KIVOrIUWVh)LhQwB~H7wwW3EgPcB| zu|rS$qLq1}oy@3??0R=5KaGsq&1f>qvzVagr({BQlfk1Id&9&sSqjA>?-ejldMO`F z5%Nh8X(dx`qr^hyKn4I1O$%=|2W%wLzZxK3%)xhvvb6wtdq-7)=JkpRzh)+9UY!(^ z7Z74nwfg z=h82j@T~-iwK?IDH6bq+JT3?E6ChyG5DNy%0u%8Y8}$YcUztM)--PL@3#E|}TMWdu zfq=84BbJgI(>yZd%WCBF%1F7%mvgUn31){c~tJZ_#EDV>wt-;FK|fp(#Yj`A~S~ zd2ufWu%b+5lNo4I4vE7 zrt#t5B;d*m+5)Hfs;IQpIpiusQh!0P93?DC6wM=upx6-pCt|q93*lB-xM8VKG)HoJ z&hf|QX$p%e!xRxsgf)BsUpbCkAqy+;@cboVP6F~3({Vo*xbO>+Lfp?gDFOf-MrBcmkNo<+&tc~d5wP1sAJobk|!sGV*qf$kP4z$8(AzAC1j1o zv(9BbVC(0#3rC=I6bzy`fadV0R}%N+10*EZQ3&}a_z?#1L_*dzylcd8%MX^=z;eMD zR`Is3=r{Y2Tx0V2DqE%jGV z=I{Esytx0|u3B8{`C;Dv?^s+pt>-H1!Q26pRghd1}(o>T{B{$kG0cP4Qk#b99WDg;WBRM;)D)9 zHC`2Jjp@~qZ|OTQ)TQGrqV(bV_EtClu1*+uUwpAhDnGTSQabthy&k#i&Ji!_9F8YP zr*=>Zf(UyJs(;D}u6ea}{e;Wy|7rD3IrV=3eHAPo{YSS#TLhl_3Aec~-9}Rv5U$A+w{_-V zcS;d^Kx7)rB||Oe7YFu8tSc(*_VHH;%dOi}R`OoFJLoydeCpjFX-E!(E~tQv|8rxP zk$qZSD18p`izAx$(L9S)+Q;_)^t+qBdC-!-czmEbU`X=s(6v7-vHQcQy5Z|}9YI#ZcRt3|Ru$Or zAWd^(H?iWE69n;j;rbJUKZ0-BmfiyQ-kSbs-|}=b#sZUmtTK7a>j7!*`1ie)eX zB4hxL1u9Dsib}|06M=lw-Ww6*Lkg_obpN=1aSQu4F6wNNzd$9n=SjiK- z$D*u}8?SE17T$ewjMirmrDA3Lq89NPCm~HicxFG!eCz4cVmc<9#q`R-ub~&=ek&jlEH5-PR z`fL2k(-j%%_k<^2J$gBC553lLDUDh?_0Wb}^Llc)Aw-)DahrK|fN|4`apiJ{o(f(h z!XLTAMr;Su`3A9IZ^0N0#bdsOzg$dkdX;14_wThg`zdgoi9C8AsOhG1@>O;Zid`Cl zI5!U$qNr89lo7z(?gx=>Zg&Cq;Cnn6eMSf5p|FE}pZG=W>KKP7)-m&;f$ik*?!}ty zzvbA;mxiC%dJmWXMZPKudZkjdaG-I`EQ4jxxVgUaO5xL{X5-6-;`OWUTlw8j^2CO# z8rJvU0ogDB6D!xQ&-$nkMc=UcG`}J?7-Em_%DiL=eyTtchkr7FarIZP=T>pKIehlh z%RD@sGJ5F)8LC8-*a?<1zsWe+B!21i_$>Ql;u*M+quwG9F~xd+2q!c!OA}u~Yy^vA z#=DQYy`*#uPoG&fn5pwQwzc4dG^Qy1N(XHAfm7d7kqL~*b6Ihg7r->2go>I{Nn-Yg(AY64N>S6jRPDY zdJB6!N>C;08SRK>6NNXWWmXnT@A=%5>mo^C`H=R0&G^QEN?wY%GZ|swz!#wEjM&Nc z*S{{7P|1hBW}o5~Wqi4LX%oHk6m#H<;%T1zsea-3-ja*`{~qRcdydq`Cu?O!*IYQx zGqQX0J^BO~s~x#`*LNa9^mB``J!b89che1hdG&+k@alQ}7wO|qs|h`CaqWktnjYD= zT(R39Oc2f5IrBeKqVrAAqu8qb>t$UT9oKjFJ(z!X=)ZIEcI1*F^{#o;nI{#Pq4UpE za5ol}RbGoeN~u>bhy3AU&;0suWv{-leeF_aLrFC4?nxD_*d`ASDBT!6lqC$uIOOu| zn^S*~PUHP4FKrV21Jy^Xz15ub%IY7~L1#tbR4b3#*VR4|!{z$N9%d`}@;5wcO;4|? zFG*^6HQHSI2Uav`@j}}bVH|6vwY(eL8f>Kx z+a-HHK4F#iZfEsIzZq)?_;qIWLF#<~ zwM(J3U*s@qK*LoRu65^(MyOPTea!QeiM7l4m{X71ca)y@F1jv0YO+UoJD}DWEAqCc&Ovr<1KhI%cd;H@7u9ch82``V=_pdS zX1pzLbI z=Bdjy_VhG=*XMg!H1J$w`f8yu+cN6e>};WK8stj6(aCEd*QIOkF#)F^k1r;z$&+T1 zmIsp?Q{wK;GruoQ2*R{W5}UqJS8~iwL|;2A(PqoHB%n?Yl#Z!d^3g5a6Jd`l#h+&i zndmhoJgK~{H8Sx$WF=l)?3c>XlR3$O*_iT;#*~LoG&$t^A@4CKtXzf)5;sbr4e^5t z(8h@K`r0`NYeG9FjdQ&HW%MD4Wq7Hx)2B(ekN?gU!M)i$R?diQxe){U%gjQ$SPg9$ z`VtQaHyXPTT9%UV=Lf2SR*#S!#g!{S+OY}` z$)=K!+CBQOW1YO4tOl<+aJA>a<~xPhRsv+6N?KC?vsWXbk^fv&a!4V42o{Y8Da4T= z5BtxS{ZP}Se@;C3l8i_?Nx1&r{YMO}u6tEsGQLTts(B8_CHguNMK*8iFwUzoO6%2S^Z ztoOYPq|MUv&37KUwbW@;y{hO8djvDGNk-VR^5U(xmA?|lrM=6tLd4t^ zM*t8L(rtuAlM{4>1+`}5)Z_c!DS6=ol7lM70$$srh0eENHw01J>~EklL0ESoq$4DJ zJ%1TR@b==-lBd_v%lNTFW4MwF27EOT?Raa5S#VLN3rzWcyL1cA7i6?_J7}PvZoMQ? z6oOwr_6w!#>cfIxaCw%t%y9PcJ^r}9TTO9{0XZn!nTs4fTP5Q%V&1J&lKH&l^2vik zd_PED>e7gOSlH~r29#<2BBM4wCpPe%qI~QkNC8E5IJngWM+Xy>f3e11ct{HKfg{W< zJ-6M-&H|VpQ%Gv!vB=}ENC{LkZe=bj{T~-5FE(5#)Nle4M{v!~_if^nIuKQY@wErL zSBD9)9tdg86jVLc20|wPdDG&TK+29n`VB|7s-i5oU=;vWd4!vD|2(zC?*<wk@ zG$d?O5o0mB&>ZLjJHuE1;v|imr@$`ar9SnK8+LXIAI~2KUX!1(njWf3C$nr$?vB~n z1Tb{xZrnM2X(LeBI#@_fUd!fnwWcmA=Uj!KkjliE%}ty?d>~lpfkoUk$$hyrti7X( z3q@*@2+^v)4yxT9x0c?%Yta{mLAt)U7g;ejf3>Agg{W;mQUg56CQ1dU2FT0;AS2=A ziys`|a9xhr1(rSX@$qo4qm$$2eI0jBxsEGbtb)uts8PR^kqvA0s^DqOm|OLL*-lh( z`o+6q@T*P>7!dbD+`8d*g9ez!?KBabjdxi)1UrwS^d6ZX{52SlzA zW`{9a9r8RnNalYf$@W*UtkWrPk|}`2y6z2 zs4DPdj8rF|j?`NY(DHl1g}pG0OfS*Q9Fc#rFaJkhuU?fL8jW?$p8h2C>D-O)Dy!_m zX8w&!fwU!iNx@&`ICm&drszJ}RnJ8j05$jS24OyETTLBQMBJQzwYn#mAzG1P7cD^U zsvTJ-ug}82M~rfSL1`S}L%SuW)+iKm+(t9#OToDTZAIref&-ftMrvuflTJ7E;WQ&* zAX@X;f&dq>Z%HBJi)LfV#lCeKjuz`m>B*s18Lv&XU?)SH4&53p`xlqpQPoB~oOHYA z0pn)Sf9isOyy>A{)!huVZRoM!J4+JYudm$0#9c|fpv8t=bjLrL>Zh;Fc+%qfHIz>5 zZWI2^l7{cT`EN(dcSHq~GkRckP5!R(d69LpW^OV?KdOQ&<9FBLuX5Zl0+)J?H zsEJ&=e`ius{V>}qaUnbYPcK~lZmRZO`HM=nd*#J3G`tJJ!3Au+shIxM_*gGhdoD{v z>QH3}H9kQ+7XPTo|IqIG@c!?^Ql*D-|Lpq{Yuzw+=spu@Kn6Rqa@T9gZgcyp|Ip9e zqNi?BMNt&%X@F=o*}{7uzV|jO;Wpd?kA4c23kJEMz|9KEJ#+G%S&F1xdcqt9u`A#| z1&$?IETL3ZFHg<`&OJzxVo{R~`mBud#HyQ8M8H*h*~Tq>_xI?h<@u_%z+&kW5GZ?e zXnwS}SNGS6oO&N~(&CRL0@w=xX6gc5f(^Y0%TI$MGa z2GqMj^|gEIbnuP|;)ls(_i3`O3(lj?-W4Simc~Ld$j5eRr&%CJBe?)7l#s@SZ0$$ zx^`Y3WRK}gNa)=;E0owlx6$bl3#Ojlr5$4;)31|_H{0zBT+fpr0(R8I1uB1nc6AT1 z#~QVzIK?DQwr5WQd&d$doW@4_rBUF+{nFN&;3x z>{Q}zcBTk8m`uOOwm57p;`z#@oH0b%B$KptPm{rR#O$R`x}dj7?1X$8){?LUP7JR0 zvjV0aoE~+^j%7FdxhSUF%j+9>I=X-juwb)}2HSqka~6;=JZ-~)7BMF*E2wb{d(_c4 z`*C#k^=8xTZ?Z0)e$jviLjhyw=%;sU#h8#wtjcs3!+t+_Fba&E}+ETuUgK^H~!nl~3TRCt7D-g%Zth=9%7t9cE9>Y9=pe*%V5344*+2XbUhpi)twgTB69Lr7|r+yZx;0 z(Aj0kUu%l-#MNXHJtdfaZV6&XY)t4KPYR}|_(Ky7AX%@b&RQ0qX8NY!p;6fEvv%2q z&3cYYv~xt?gJ?R5m*wY9+3!zFAktHIp~<_n!v@dl8HT=w=8>dlHMsi3CCGzqT&w}z z>h#k%BKW6>+=*RUQZWDNIl+`P-8ys1T z2hd|h2)z=w*HwC0YTEM8L_9L3$m!HK1~VT%LTJx*RfaUMDyH z$6Ook7?o{yz`%~6O|`!GA~P41EG*a*@`(e1)YP+$0Y2yKAwm(=tpoJ^MpcQGFY}Mc z)jnRVd;GHAGyj6Heo+E2Zfb-q*=KEHd4jss^rNS#e}6N)ql!t{suyiE&1-8@I_wB% z$}CfvC)7Rp6e9+0&yCJ%dm2Q1+<@gHXDp|uRzAckKjL(n1k!6xb9k@ib*c3`} zef8kotA{trTZ)!1y?uE%C!lTaXkr`k(UI4WBVKQ_mTN`khBOKnNv|hwzn;=4pAZfl zt_+<1@%n$lE8=^MvmsXPo3G~_SDqbNc^%ptFpN{ffR;Rzzbln!)xE-`Aqo6pK<%!BU zyqUFqQnYZpKsgs^%*=K%04Zp%R$6qk%3iM9DHTXeO3OQD&*vHd4eQtr|NVFqlb2^- zU*at-McT)I{Z8lPLx#^v^zG{?%He*<%6!8ai8n2~fRl5Ou-vj-eJUw8IN!2F+6AVpwc6A*8MkWLHA;R#x-Jfvf$ z*xTcEVcIflOH{M_XxRisIiV1p8(Py5B*zY|D|%%l7-CsK{`QG}eOI7t0W?O@P8m=& zNpC6`K4JZk(@Qjq;`P|g9PQjf@=0OR1myGtjg*#S6m0V6Irs$*thShYBmuodX$WF8 zWTM|l%?Wv7G0|zdE*7J((?tt1>w_o?o@3d4KOY_pxx}UiD#$#j$cJGMhr7dl!l4)X z`E+TU5``O;@9q~!X@idC(riA59V5NS=GAy&!|i8tkGZ^kk%#_}ohP*^bhtXa(I*@J zP;|ou+E2|L+$Cq+r=Qsk`LslKTcVwrqgkYJyN^TSnKa&mJOxjx*j1-8?J{l6JRK25 zoea@30N&e0*moD~XaQ0*TONOYV*k%j16ttSnOyDSwO2QQuN-r8?yS%@D7v;Hv~Hk0 zks6MrnPG#n$RrGdba^OiP-memlGbbabX7O{&A=V%CO|&{a$a8DvLY`a>9GC+JyoEC zDW8(t6gthKXKF{d)2{XTD+7qd122hwO}Pv}AY8`Yc3_hD-FXQ0%eylhf?AZa1`1~N*)$EVRXie1r3o@QuaxRu zLby%OsfFI}{pUI`d;^iA((P`D!o}pY@NvplzI3<%J;@M~zp&a*UL89$H7G9~csaX+>`4+ynahSv zEL`VeF9Y2r5?g&5gA!>yP!klEF%8&^P_@v6eJ8l^IHOY zrRBJl%o={ETfOz>ibm~>Qtp)^CH13jTNa{!+JM7G{QVDWYOf@>9E%G1VVJ8RPm!n= zbTI&xMTCM%)_&>5Si}~*BG4!VJgM3%t?D&P-a0xv4fht&p zIN4TTyK}rKEl+5lGV~y;R*+_3I`A5DZw?YAaxF|n*dUR1IqXQ5E=OTESYh9YtSmR5 zF|ME_7*7{xwRz+s5^~`5vzJSeT60;x2W!N4yz~=nF?8OzII`0u!QyVGq`-YGnhhIbPY-qifrP?d8)v=q|ziZK-NbQhtOU#nF z7k8sgQg*dW$`A zHZhk&B)M6FQTf2a3dAVOVP=L$RYCNdz( zkD|W*rk^@44D~PVz1r2v{rjEx_dae<@mkp{=c1YyLhYv{dY8*62hvNm%9UM!#uM2t zOt4NhaIc;3a_V%E{J8@V5j!o&KnFj3TE0=5FT3E9xOS>SoA1@i?B!i4cdJ}TNRJRZ zEbZBIRA<1Y#ZALg_ef}BqBqn-F3q;B+3{ngwu2Xm{kL5$=dxRK5cjS0_&fJ%x642O zzPHO)clQ0<7bDa89Ia(3yD{-)P2jy8LARZsf35}BN*%s4`PKz)7#b7I+x%@R6>#@N zsNQtKcB2{EB=F+qT$5c*($-R3@HhAh3n_Qd;Qr;}nGs~|_H*j{ZO?%V56m|EH_LUN z7O1EXmD4vtTUUE8|Mn=2T(Jp91uyK*eOeWScjcOGZSG(D@OJXDar~^ca8=NYflE&# z^(3s*>Z}CIZ(-%8TW{{zsHv~L;X}O_Yi~>ATx*Su5E|a+QX;9^G3*5ksZ38_$H`>Q zr1eKKr6O9#ugTqP_2M^Avx)k|RYxsWZ=o47{oIU!zjjioNWMdPi1{K`5^lR99a1VD zVIl=LF|-{SqputpDl}pEoh_oxw0=Pe91Xjov_+RJanpLhhx%w)r*DPmzVKa7^AVD_ z8eB_TwJ2@H#WznxR=<^*^ep-u47W3}E}F^@7k!fZCav7lIL&1&{H&J9S9OfLSF5<` zm<3KqiBk{qsN*Ni6-FFt9)DufU@7Hn^>ecf*f^C;%(LeGA4T`!7xUxC0sL0i?Yrt4 z*Su?JNUot>Zna1%MG~$(gtjEyXzwUe$u(7ylaPdKC!xhRA=i*fIGX1D?)M*j=Hv1C zyvOqeiwUh8Iymscu8)GNvDiqQ4XvAMxc@wHL`ZsJ_pDWH<)g!}pFr;@g^oRwByBVrAFF)zgeEe z2u`-;9%>O(ecyOAS=hhF=C9ef$L_Np7+WDTO~ZYN2*LZ%NhvsSWNIj)c%fyNymM_7 zl-x%I)i`8k%w+9pPUfVSAst4tjoS^mL&lHV#6LES2eeoBA`*xz7ADfg9$K#Yuz;bN zVlD2Fu1)bgNU0tFZ^NYDPx@!{u8%mnS`R*Um&st;S8E+hkz{LJTa`BS`IhuWX{?P1 z2bQUvYj!p1z-uX@b}TS$zIIn@I?7pX#=qRL(;>RXs8uiEh4o2WuT%wt?UK!+b-#6Y z>AFAQ7m{d^z?Wey#Zz9=rQ>6HYPiT@YDw$!^S;uSg=!vgOtSTY!1QZ$UVm+xWrJis zvTh6YI)kdR!SA;d73QDGkks?0-RLEfH1;r@hGKHRu05Z9WDcyJwaG%(OBQRxs=yko zH2c?`P#A-*u?UmI>-cvi4a~|b?iRmbA$nRNr>89l_!+5we`!Q557pY9j{}S%ybbB~1C}pKR62P@EIaDrj z#$M05q-`G?WAy?=%BSgABO#mWI9RQSucG2xqMgt&!`#SGt!>&ros!*$Y&GP7B!$yC zj5m&IzxdEpJ}=ejpJWYVS9-OzC@Yyoms8P`FiWZW*N?O0*2DT$RyWvWyPM!^1DG;s zb$!^oZq*3{R&NeO(1RU@{>9iM^XF*=-(=g#u^UJqUHG? z?85v@{KNQ)2IErp;&~uk=?Gn8!S<8+)Mh?HiLSA{=?K^I#xiz1mvS4{R;39jk3dw^r-OS*ZB9Zni= zN3O$L?%q6c_OnAGk*k23)}RltQPx7von%AA3|;kYGuUEJ@{5>$cZg>d4;d)QX{sXk zk#lZm?gGpzRWLmWmeZMg+5(ii2ehI`X~@3)U6=$S#3(O1$Fzn*Hp8VZ_>o|eXup$> zhB>?EL&fd*nr5Xz%U%*DIx_%IS8}hXqL1*T0w96$rw6+AvkFlG3@R*UjY}@_$k`3q zz)w0HL5H!V4%UCgpSEPgWdacd=WpBJ46~6{BhOE_aMcz?75myP>kL@k>O#TsZ96(q z+v0?f;KZYUlBy2X;$s7=Ow;s4Jg|&jujR^HfYDb)X~Y3Z{cYI6Zo+>Mq1$_2%sn<1 zXXTY(%T;&;a0-3>p!9WXH{n`h?+&3cHkMThPD<>z4J!odvI5mteER;GEuv+-1ca-F z>E=n5*{UzQRn8xFmPM!RaUjg9|FFdCCVfYrp5SIHz=^&ONr*keG}Wuh^<`D=L8ryZ zV5L@8TIqbWW6zsTAHP8iX{rQd(nRn79M!ii&lqF!kYiJQq2H#4l;!0UsBRsSw)gug z&|#>$e%2>#TWKZ6x$K9e0+L>%6y_xb(JKjnG&|OEuKzoZSec?O&3dnM z^7N3Fq>h%N-vR79q&--D|7%*Q;5Pc?!VEb4!4BIa46h3+TIC-o>k-z$*+xAiOe6q| zx)|G?y9i7>gz?U3^3RQI)hg_7?=$JS42(z$kt?G>ZRSas?c>gGR-F4S^yYJq2Wg=# zgFXLR-^mM3o>9nBWmXl)#6&Q(RJI@0%+lKa^Xb-fs6&YkI!4IRizBTBzKwVo0ng-4 zP)SBa@Q1icnC%2m_7TN#yH}l0&}Iy^pVyn>z(&2h970a%>^8PXS}8I-*gH)gNQ4%d&h|{08h>2DSA>mVFm^1i}R$@hT=_b!e0Rp*9wq6FZ!b4 zQvg;@JYb}y1e6Y8+CGpZ;OSAGnEU}sw+eO&0Xllzjpu^ZAa3FpU+cJTb6)p*|FoDk z0o<(H_FcCzO3pQdh5XaQ?!<h$g6Fy-0w3I{<2~5|HA!-Bmzf zy|Q)hE;tL`YkcM6E3RoW#lKw8dlf4ylX2+^^kE|RX9rL|1fY~ix2pjw>GeprmRa`z zB_T-=NS9mu+X%oFb4#|rFg@?fm9iREpEsvgEal6=DNBGz%^-m!Xr9QY+u3r1B3VX5 zTw5YS{s{4o|73rpvVJL@pp*tF8nb=Z)mxK~0C5q=1?euMwWz)wO4D1kr=ea{i?}}B zhmovpN|oC0To7ThmaRQ8K0MPPAsKa1{Xx%Ul!{ez zl~LkBL_+Bf;eY)>0`fbFq1w5V(QVPefkbj-9^>eiJ!Y~!4v_*f`Ko`qBIPVFnE>1H6}sXlZNtDJ6qSd6xJsUMDa%fa);^2z3w?2PybnaXP9V{`pX&5K zZQ$)_WBCWME@nXsn!N_AY;ms{k4VFiwC1Zw~Fs5=amHC(~7i3#kin zeEtoxm+aRC?_eqMK*p*xIT-M$Rc>m>)HZ%Fg5OCU_WvQnG3o#vGPq<6OF_1Q=20nI zh}><&eg@#0=n>@m_gsD9Yj~pcKCcn7DxJ7cd}s+Ed3j2Fe4^daC-1%>&3y=up^~-f z>Z=+EOAts*10oq%426Bt3WRK<$RsN20e~>GPE?M7r25it^V(?za8efq#%B@24k+aa zKy?81oFQa9KzjhJ(lwo4c*P=7D`CG3Czpo}2$jZk+wi(AGq_gxV!MoPcF?uGJ;FW~ zP<`CP+>)gk=ct4C%#`xSnh%HUpK|fYAKAu`5_04ehIjgLZ+my9$5DtKbo;}u=0dJV z1gE01`}QNY^}B9e)il${A^f%;Xb0$0*P%;P^_iN^9y>Z|59?^NJetqeoB*EMd_{2e zyHBdN8|eO?3s+dZtmT%b-38WZMpeE6?;wvcGb(pPrSI|WQx70$;>r!$ky~HWw~Jdd zQzyY>W)`gIWq|ttoJ9>IcjuXuo0G?ABb-{bYE;!*C?!CO$f@nsqsLK|%h^pYmI#)e zgXNt?NlT0g;0Yo(C&5eO!a)l?@0jvxvRy8WNKZc(mXU|Eq`2C?n6-|hYDmt?hYP0A zLPb2e;iaZJ>ZdiS9kq1Dy%~y3ok@C7(JDq;}o*FihASb(_D)` zTs1yjVj|i|2zv_NB&ZbDR`V3tZPx+T79G-wOWWC=so2wa|8;~@FL=eb(uYVReoA)N+}GW1HjNhhFO3!h%}k@bU`(}xTZ|B1Z?x-9Sx{>QNiXyZuN zts@Mg9;d~Uy6c>bt^01~J*agJweD;VGGp32BO>3|H)xAAI*vkp%{6lUlAE{fjkz?o zhDCtUO(5O)43-9tZo&giWIP`$2M`i5(=MN_bF>jgA6DD;g91COgU^#WwzXxAhA=QAtKP(vjd;Wx>I{x(5g-v%YVI=g9yv!j$Y&N2i02^U&+R!6hLJkT_dFkqlW0d+>x%8~&l0y^=PqS{7-xyMB-;eKf$ZEy`3(k?l3kP^Fl z(UyT2kf3dbG!{xLffzV+XYC5`gVf;Cm5UZG&c;8^LO0-)$(}GQlj@ z;+m4gajWscn^9H9&fUZDT&tl;!tjkpyJD;(8uZ?At;3cTJmj9FT$Isq>e~OUYg8+2 z+wRarlO!@%HQmIfiK}s=Z)XO`)HU5AkxtHxbUN#0R|0+?z0J#av~v9zw1dVj>Xa_( zv>F22ta3D0shX>x#!9f$Rf?(*YKDg*KYsu3`_OU7l?kIFH5Ab_FY7o8JPmmE`Z*Jt}u6q`UF0eM$tIC9Cty%10k5bS+m zjZEy`0&sy8_pQI`j3aE1>0~Lvy1!~;F|e2V0~F^E&A2%u%rfAc0r!kK6)ggwB#~3E z06!uwlVRQ4SMQQHFRgmsTGQ;Z@d`#np4>2kYp;Wpa>44GUa@IRPVhn`pyd>Qw*siq z!Ehq8B7(pIdN_82qfAV}mAS9=a-rlc#?cP5)C4{9`DwZ-?DoDmV7FB_JdR@U?y$VX z)Aa&9lcniMnxLwUma6Y|rjVH}a_~SogQqh1&xM-xEUb2+8n2K1?y7lK%3 z;u@I3oqbs3#yhx5XcMG}%us6tQ)%J8tI(eBdBF?1H&=mIEwY)3->` zhVJkdXeRHTOz^icYvVo}(^ZuTo}*iMZ(6y~sv>tqo&=z4vdrUxIBfzltI%?SP16~; zr*`a667k_MMXH8vU39Q@+65YSMRMDFthiuC6Vjy*PP7d5Nwg2@mO0LHUAs|Ild706 zmoyBzaN<A%4k`b(tk=@m$-5pZafMrN3N2n4^hEU00ukL>$Hho`qy=tnQUwgFAC(WY=iq6Vae)>CsEs9xseb zXuBMD1g+7w&mr$`fXH557b4>^C0`G0T=UDF|J?WW;MQ)P);J8T6Y0k>NdaLxD1Ku0 z@=zWMx83LE31bLXfK8V8iktCQ)~ar>&E~W07wBa0pFFxo&}2~AEpgR)?@G#+c<#+4 z^S}2F*|@?;iCt%FXgfK(qAh>N0LaGZh2nyui5*mRgS?&&JXsBNOCuVGsx%J$dK z#Bcnn@>4oT7LsP^GTSY7*d4y`^3)*4ES9fn+t#=*vGd&Cl=I-k0uXecBbBX@$ib!s z(^jmT=r-fScaUA%CQ@eKrp%81QH<5>lsR5u36#LRmW+F`sxb_Du7mtr^I_TCYE_#e zw!_6gmz1ZEwYkU-Kc5}z+U86vtoWg&Z?$zVLwVUZcagKLjb=8$Ey~|(k*n@q^ zUXWQm#xw_UIQ*K}YAA#f{~x{BtxtD=Zc`#nsbN;XIASIvW-PSpx*>DVV@Zxhdd3c= z@hf5RB_&LX|Ztm@94-dgWFxGajbr zJ(s@XRJg^vy(oO&^}Say;U+=c0#$lIYuJdk6Q*8wX4S;pun?J!zX2PKLrxe6^%*=! zRC2g{+fv`JgjT2D3wIfaTpX794yg$29uy?&`SinOG(9axG&3$42c>u}IQxe-sp)!C zoMgU0Gy})3$Im%?q$?TkAV-LzNNGNN+oLoguSUF#&uO+wfsu-HWMvfH67{QlI8L!j z5xzIz9`ySrNBsDq(p|xQIjH`x!E$YG6}K(IlV0taFA7ri9zSqWmU*#j8l`aMCo$D%h^>1$t}nCd!kMZ;Z!4kCzz2LmbR#7x|NaW^bH6BZ7tM{AQdFNb1aMH=0?n&u;+_hx zp~6N?@{DYFk_h@N%V*Da&9l>S)x=$FG3xIo_qK#JHE!gDeg*bt-thx~2Ywa(q7ep|~=x$)+`XDGdty+<>7=JT4jPqMtDYc8 zUEunCHBQetrWHdiJ5#VYf7LSK2lUDzjkM^GkxIP^CCBCV!7n5U3$;Im$yKaRBC6i3 z=UUaSK{djYp5M((vm6_)5nqq%a zIo5m|s+u_QbW7R!FK5Z`at*s+hxt;6Ln`Uy5RODHj>Uvh1ys2N z(N&QpL~X4=+Ge0y-CSHwA->OeX)!@*`jP2O-eh~7cfSatEzlGnWjqTHmYD@zaLfNxfmV-7)?-nC#E*jeq;j7;}*O?mi7WerQ@HCb=1^kgHq zte+H(sp$M1{8r`ls4HgXIO&9BEvL%2V?{Ofw+xT#9~CbM418y#dgoHmH)8r4)IHgL z$qcM6FEcM`4QNwScvvMW)lOImE3aWja1Dwi^JjVv2cLUvFT&SWnbpSEkaSd7jOh|m zdv!*ZR~@am(Wh2d#;jZYv&&PsAnH2NN?Ub$dW3EQ*pi6)tf4aT#(I!n`M7=|d9Msr zW70VPz{HZ6kdd50>5$PlSwl^oyO^2(TK;ZE4N-=%oT`lq=Aj)JkRZ!+yL$f@FT6Qv zk0?DvnID5mb2ARuMZqUC`Ij|86lMA%hwv=OGV8BlSVj}e_$#pGNp4e6Ft2=9$69Wj zWfMY3NjLw|X_T2E4B7v7?8PYX5!M}ld=Grw?ygPF=UzS^SgN`5bRK`#A z+ym11)#}$apF&-Yu?esl$jKZ1c3%szH_t)Te-8I=?XcRqXLTPAaJ}=?5>xdvVH#vmAt?1lBQgb+QjGWwG)K)UrG)MM{&fa4 z_q}&JYf%+$!%XjHQJouKv61cMoM6}&NZv^2wzf}?-0nKy@7{guZDMjLci0V4?WKCffLlm7v z8hp>*4`V}>I~)T&qcI7svubfD={CtP+UX!L>UB(KdVK%;Z;ys|s)RY(OGcHCm82S* zEpWC@2uKIkB!kaNj?xKwC31e?-d}(S+}(n_Bp)zEql7{j_Ro)G)IXHXf{PXOpW)NP zW&;aK1W*HE%83*YEj1tLmK`J@@N~U;sin6R%OgKhy&7b;3ALT-%(GYRsXrY#ul_l! z023z!8Xk0#HxU5?UVTz@}MP7+$BUdZMrFat^`d_tk()7cSc>KL&# zH4dyBvLl6BDzX!jz7SyFmC^B9mj~gN|2)_L(nEFk75!J7tQ|M4297zW)oIDn<_usqeUwHJyO(r{U(fxf!RIr39i} z!pAqWdE9p%ab1|E7hu`_Hf%H2maOo29_oX$p&LW6J@5A)@YRj~=eQ(|(6yzFHzhyC zfGh)+0NWFFG%DnJQI=}AQoEA>&;6VEaufc90m}oiI{|6pdlTy#ZN1M7F8p`s5U&xH zT^`p6I8sP|1%}GQ*OlaNq>TUC%&drdv4nSK2udzN5zwhPh+di z`K#0RY(V^#T9C@FRfGsL)$F6eD#x<@ko{ zcePSB`by>eBo&9L0{?=jkNYbP@ZY#{t|WZZH2N-Q%O*q&sn}=f8)$ocz3c1cZaVl*|Jqxk#@fL6w zv{bcWc#=)1;>(sstIIBFcv1oln1%%2-YzzD3xGG^G--BIkr8@*xKf8TEyrLh%utNt zIJ$k)GU1&+ggMcuLD7#aGUBQBB>NNwGN} zX?4fcMOWGna7U9Z%jrg?u$46ZA!)?*3p65zt6)AY7qrjZfhzMj6P;7Jj${7@P0ROz zVybwGmq_=I_=^d)mD>&c2{D}qv^$qC`4e)cl`8IRq&b=5r{I%B5%iX_!xT{cm<_%i3EIK~*`v0E@q|C78(Wv?j|>#e0-(=?YO9sr zk?v&ICc5`fo4^$PbxvJGy&>vUpCT!ipx~#Q)Ny%FmFQkmo$AUrzBMCMB~a_=Se8#% zy6wfU9fJMM1~+!iH(FA)2BejjI@S4z8)W#N#|@~-Y4s_#oi#d%d6@$^c$-rjU~iR0d@C%{EcA}&T|Hg*W48vrzXMGO!^MElHS}i z)1c^SsP>Tzc#6wj8Y0r(FJ>Ak(4DSc6UiS{R;emVAHk8NHz8g(hNuIaLVatB%#Uex z1E8*Fs@m$bQj!BCt#cG~_jVr1Z>d>DgufvIY79*`;&($>od>>AcON&SyK74cC~7Uc z4rm3??^n|AAQ+DfB-$aWy-`7@YASJc3gtj-@^%a#cRWt2w=8n9G13faj7l@Jk6LmL z@0Uu{-*v}8ZA!xTPJ5NK_|(R!hNReaFceowb$!wM1=Btx_Gg1m$z@eFcM#XVuH2U$ zzjuvvJxo|7Nq*y92W$K9|KhCls_*DZrP>RsM!moO?p+!sq$No#iPDa@<7U@4wIvcG zN@9(6Iqqi9H!5cJSmH z*NI{ZEIa`SJrchBzEvp^HVnYqXXD+0_+ge*Th-Qoy0R2Do&&^dQc)$B5v78pgTyl) zoypYBGgg#@n%hS&`OB@IlC!1Clz45#bt>2ROD3FH4OH16az;BqIqDf%DTx` z7&g^}u?a2gy!kppKxPw3 zne}=$iONDwuxcx_WvWmG{wjSywV_Ux(oQj^y@wQ6snSDDZ>YT5LX}gh^)X{ByAG<} ztCWqL*7*GK_@r^pL3ibM&0m$;_9*u%HB%KaAs|>KK{CeGG);hzoQ}lnC%jayC*e}= zA}TtSm3~5YcAkh)Qf;biM@g0VZYe%pB9(b^f0(eSb6QnG3O7+@FYF)mBc_D6cs!mc zKwCm}HNC4kl@0tg9f|;D{W^hf0V>8gI^<0&*Oz=Pm{txDfsafp=Kx7~ zwlc5N2Kh{`Ng`m9)D}(`uZ8QZ5wZ_tL(>jkIb$W&$|LlU)Q0_4J1S+*Euu=NCG=*- zWh$@-&kxTQ^!Khb$>f2Hgs-Z!x(l?e7`2v72_KhS&l zK=UmLQtgwl3)u=lmJ1;UiN=0HNI3xM%r~~(Ms3GXZYWL2TUmS4|xcHwp0J_BgDD$1g_5n5wlFhybyxtWst#D6k)rE zi2z>YfV3w1j@ks9Qy>E7K|T}gw=2e+=Oju!Vv(j<^uk^E@F7^cqU(o7Q7x*R2p&}M z|Hnp2@M(Jr#F_^hytmRJM7i=;40!e^zix1ltFmhkwE^_Q5`mMTMKuZ90Mv!ZBWu=_ zag(?6#_85Pdg1*%RbTj^mK2x10>{68S3o*bysB3M^r0uuy6)q;I~EK z*MHY~lTm;w2k<gUq-WqPQX}BOX_m3V{j;Z;Fz4;kr9Ak( zfUR|EnrQ;5uSr{*nN#oWG=p@dmL5r6Qt>tDRPLBo5wP>(2vtre(?YwXL^PLcL*gd~ zGfruioszu!=J-~v>)S;Evv=g@G}a+5&g;$@@9w}1Tf*hlnJ>iy17 zM_%qKyYs;Ai_7(gkS7w9;>p<{wI!;mEgKi1=>M@3hCTm7|H+SS;vdFOkUFIQTB)+C zPZW(b)haAkT%N4%`S9bsdXL)^#_-v-!{^tsgF{+Z11i?k>nlT!?A(Yyzj6A>YV9X+ zY(>0!PQuQC2OGKK&BC2Oi_iazKWY>POdkWfEImLBmjApd{&joj@0U-J1=Nb_qpI!x z@-e=@pFa8XT>NKb=U+u+$pi~+@^|Ug&VL`z|Es)8_v4`^k0RgIEiOJ0181%Y*bt<$ zZ3elrD;1?;oeVRs>dC}!_3g+ouI|fKwF!wU)J#R@Yws?#%`~YUEH*sUo*Yi@g%^^K zO?G6OUVm}b_ROz8aI^a1N=CM_U6xtHXsv6R^;yJ@#_DC^dRk(%9Q_PN$~mtHj;dU)<{RC>XAQ|8;pxi-Ng(qF~+`Q^Se%L&JaHH zLc!$R+lS||*OK$j8`hU}cG^Gw_xI254{ksXZsn&FlMPj`zoK~Z4;{?G*u(r&&VLu> zEAh2sv*flr5BR66pYu_`k~c}NCcR!Hni}Y-$ssQBF)T30M7EcX7?hEN!}bgf1m@fS z+myvx30Yu83d|US7X!Y(%(DT&gNr=f9t`7b1}W1!jm$I+sNHz za+Q36T44X{rLu{CQ;8HIE&kXp zo9)fAPOomdm<@|iHp@yEfp-he5nZfTCSv#6FBMU5FpT0xo?9LQ7z4QA5kOqD*r8$&LIsk|tF zWx1Q?JzM5g?=kqOoU+68ePT88C3wg2&%Hy5V|!M_X1CBP`sv#^>ch#g80$~TD=78U z-Em)~r{)5mzfmy$=PunkzAxV@>SbP=n^7_kX(KAv8h}eT>_*#)7ix^{25XNK%@(@0 znt#8W!Ol;}I>vMv?k~(fSgpS9J+nVY_u*e4~$>F_>?Q7w3uE_XE%ODp+C z3RRMx`${z#U{|A%O|PZfqp=aL-w%URoTZN#=bvWHp8d2n&`mPZ>7Qe$#@PhWtO4-E ziE2WitvV8ZffG3wNKkVZK2}-~FgzjJX7#V{`vLB;A^Z@OY$oQhysWeDjTq7hcZ)$G z)L8+dEynfO2uW~w&;{0|CIzkjVvw>nP42=1=#G-O0bD~clp4#D^nr2D&JXwGpN~9X z_~ez^U&5%=lX4fn`r1v-;!EWA9Fn1w=JpKI%aR@3aVMxz8w*7O-KENWSAb$$TlG4=iHX8ocLZ2;jquYbJ zZwqpFr((CIW7d8zzk;41XXVVNj`mB{B1DKzrZ;>K1hijH4Q`6=<9qLT?s<80@90WDA?+j7j2 z?ZaU)h#kU)!}`k_3GNI{P{@QqPJA6?5u{{9AUg{y5gNQJNbBKL3q4v}5OWI@=>)aW z=AganX*>2gbFp#Ls1zbYxjl;9FgfN`@%%<}Sk!+Vbv)$aK)+S1JJ2ndqU_eo{b%Tu zYc@Dbm}%>`{d{__XQlviYb*t5!V;n)Sv+KAr^WL3TmvtrBoeIBuH7T0?XLHhN3;|* z33)}%iY6jH(^QG1cgcIiKRk|zI2bpfRL=$Ai8LwjJ0Db9@U)Vp`?1>!>MByN>>4|C zGe9c%N|x74saW6P4;1SHMB@0Y z%1J%#i}4~hqa!fC_oJep*h6YNv$Jt%csX=z4fw(EJ~l}2M*sZMoY6qy!IQzNwS&Xb z&NvQAUucpqbzw^3SbJ}hLx9DBh1YGr^rTJ#oUG#ty`19#gr!Z#*wjp^5MH&~w@qoA z9%{Bv(wNjUX1~c)L2g_83au6KL7#4LtX~ZH$`jwX+dC6!lj61``#U(dDhiPqmvQIatyI@@_@Z zEdT6&`F%ZxsR`?`nXk-56>U9-a-k}Z$~-_&8bL4GoUGdg%k3cHZ6T#a>*-yDNtvt%8I*ccKHm z4``|hC&Ua3qu+T6Vcn16{lb|$(=myEs@3NC4!tg)K_PrFA)#cQe=FKp#xhW?Pt@1< zh?;RM@}24heqbHwHs(wU7k#4QjgA8aeSMO|HgwQHmy^HbbO)+^o_crVS{?Gs6FZei zz|ZX8#JuPUs-hTYZe!4SXY|x{)Tocs)PKe~k$(b1K|cYehEGn+M`31(4#(s7UQ>vu z+M=}}h1nFDmug#oVqxDz882y~!JQaTr+u?~=w$|YoQEALKoJVyk$us2PZaPWvn_ zaJ;c0p*^vs?#}N!Q3hehB=+YDIrKkP6#P0>1i&suVH^9YD+0_(W{4&WWl*2?nHRDl zLi-3k&p^|chcUBp@y3wQJ|Zq+6Z^v*D`ufS?29etO3kpaZ<&$X6aEjSz8+3P(s2Y9 zYF&WgxLXpdlOhX%dtmV=?;Wc70ZfTHc|izz)&l$>Cqs;lZx8{USFjSEb8Q&&VIB8D z7HyD`yGTvm%#{s26(WMRY5k446T4=vSKpRY8mY65k0N5;|msre1{{o=3G90!z8yP2J zzY(#J2WMq;vFkka$5Cg=+IXY@0DBEAjnltw8Tx#fota^zNrAv_Q3t0kujTx5BVLh}Z(A zQ>LCF%y~azLGt&ETrY`}fUTtkj(X#2SyAz`BDh}=a(f&{Gv0V4{S^2*vYihv9d|A+ zK%k@&CPNH#d9dzbSqcvlmflR#2glfq5TtC%J`@iCb}3WoyA0_gdstd)T^1u za0;|ogiaYauQr@3ab)Y5(uu>!1_Hh83Pvov5>Cdwv~+hPSgJ8m>mp1N;Dnk8&J9b2 zQ4QyL$=(2$ntO0(?vZ(NR$9u%^&lEWEfaX zNvptlAV?>^5V0l%*hwa$+6o(Y`S56g#I-~m=1FA;(Gg10gOJcN0Ct&Z@^%>6&O(CM zfN!I)lSEKZKYhksN-heyA;5h61WMu~>V)vOOzg3_JZs9eSqOHh02a-I3&~h#=@Z}D zu6&EazQ;*lEJiMinb=WbR^C4BCtlu*f=i{i-MUfewl+kWG@gEpF1GXF z;hD&50I0(+JxwB7GhAAONmkZB#4JGEazDKig{~7JZi(PI>sZ^%Sji-!tU=uoAJ)mi z;%`xyW9yaelnXE3Y?I))S4^XW3ZQE%wF07z5f5e>fv6L~yQAWTf>W-iD^5X+)qey) z_EQ_yf#Xrwd9u580kECyb`1ao8>8H6rQu$e)*oOFrZWlfP&LZlIsMCgO%Oo@ILnVt z5dsMAz`oF8T`R2UQ_%hc*mla^E>ANx0Pv)Ms>d)W2tSrc1acd}`(G8QupEC#4w5V< zD;8dB3@>%@+8@ckU{DIwl^Cf}^ykCpeGX#Vn78!ZfzcxCktpgoD?1ASlmY|01@ya? z^~C~v0W%CoMC=StT`vM5?g4ePTRQOi-k)kzSL*)5l_YHL*B3(Mg0S^z3CPdA$ z3b_%0V&=6Jei30;8gmIE&tv9}17A|ob6e2^iBPp+RNTVV;Jf-L_XNu%eH&}+C>fZw z0jOXVRpCru2ef!SWP+nX91&Vbgmc@07{HzPxLRu_y2lp|4{>S{gYHa4fp7(>%kEH= z2);fct;q+zWM%7L#%_|`7Tl8yJng>VtW<`jGAXda;OjMO*wr3Jp9rA4^%{x>9w1^y zgc2wch$6xwpy!=~Y=8%_qeOq$etlQM{n8AW98pe|b$dnF049OTMu9VB=)D>DZVVnO zim14`)c9c4Qpil#6~%A!3032xz8sK}jcUQLq@51JG5aprjw59Ys++x}h8kndv_KjB z=mKGu6%sl}KqnLdrPr!%r9VuHYR+!}|BXj`Z!wgQVt+R4c*M)pu<#6GI@D&ea$nzS zKZa_Fb#cX`>&Jjf4>98|zGk@mNs-wkCB1o|uuH5&R}&&eGo>+6EwU`Br zWV4|6@E^qJn41}^=W~y%Z6bCcD)oKO?iUp5c$CX0tBQ{ed(5>!WkU3b05vdkX6M0V zTw$w-DP5R|<+fATB$6Zd$Tbn-@KEn9cX+WUkd@I6Z?*XAkYf!vSRoHP7mPfx@i_kn zP}v%5*tAtc1P|$l2Jta7MD&^ft}8@4#8C?_0AsSN`?cCG2t$xo)R?An#0(hG<+5hlysZ%G!t&Wdf2^jaj)vM*Na zGkfGRCYW+|&nyU=jD4m*}wyK#>Ox){L; zdZr%QySnX7$sLi{`%w%t07g9AeYfQPtjHqtWc80?~HZpjsJ9Dn1W=KSn%8c8LGK%_b~?ffrUwO zJ_h;uG~y8Uo`|Di`e;K*x)F~0IgHd0T#Y}@x|@u>pTn?0V9&aTc0>+5c?T2}{CDFl z*H_|$u#YEM_(4uK-Bcz7l8u)bI-$hZ^)Uy zvy2WL9=D%y6K0V6iNx_Cv0u93J*IjwfGwW9OFw8px^s% zs-PEzoUyIg2A1^*6tgT?&_1;Y{{G|>(N%-~cIz>eO;EnFT$E_|ZDmJvmatAs3i{U@ zeuIU5M1-%2P~pUMDIe1p==WW;YhVIQc#o?ZH&9q*pH=bsThv8g8g#GXUgdpL!+uo` z;v?I?K1aQ5M6%yVt>=DtRTAR}p^046-c167?@PY-drX+|NJ z1M|P|jE^Qw-;3Qv2AjM71ZuSv6nKv5ht7Zsfu*dPZ7#9#cN=HqUC7NNyz zuot|?Xn62*6#6w_m3kiSeelx7ws>%?zSFre8CTq{7juE$WBY^ASUze!%EaL99;d4x zT^@Zr{11E7z9S$H6NCv3Ir2)u?((s`!-xOQpSH;}`myc&Z|bRY*wcANhXtREgWT5y zm`U6!^&0wI_{+z%&6Hc)E?1p-xh0NsLF_Wl*IZc7cgFDT0O)5l&Z@%iMW2 z7G$+3^iLjgr~rG7CG|ywesq5A`SE9wb6@_mN|`y)EO!5j`mw!9Y-rR1{0zpvrod>i z(EPxu{uRs7sMV>UZ!ed+X87MW&@bdg(2xw|w=E!!0P{l#zXQXCkG^`?*M}+d`!V5? z1x`!DWXOp3jgKU)%;(f4tQ*9aZ0=2|I`s{oIXu!*>r}qO zCg|by=MD@-UnuA;bA_%Ezw!9AmH(ZP-ZF)&w432$OWsWf@1FQL`RellzQ4FPPv_9< z<%6x^ubPA3zW#EkEkx^_^J=qt&4G>a+g8!v8F$W4S4HAH+BgunzUC;8ioSODJhpZ} zB>d}C3)=lq76o!kO}lhod=MpJ`_-!_H|lE({@kj9*(K}@PE$IV-WTd{IJ98>TiM0) zgrxU}4mf^yG8BG2xO>{yz@c7uVxqRT?Dmf^2MfbHmyPzU445^)U)kT=`{ejWd+NW- z9Q4DaM_K0v)=sLGAyOTJ3IOc+895N1EO<>^qR1xBlNgF)FWj4IvCDw#6-iBtGfx_; zM%ih4hOt|?sH?x7pEMiAuuIPf7H2wc*|U0#{H&wcchRhdbTt|yOh2^_Dz*i7oHwv^ z+)mE>-Jf~#Uu9aI+$jIXW$Cyg-i6b1q&e^>`w0fg_Sc0*Zt$gNP<2{4PWLM5&Kq3& zNQKJ?Tsd-5c=7zy;_MT-DgNi;p)E0;PQcmndXE3HjTRT6%TKdiSNAPaR@A8x~7lUJe|KCr!@#DIX@}B&DFWQT+b-f zn|a5--LJGVVAbbY-_;Uqz;83iuv|fzozjw};@m6!L)AUPZe-lXiVC)YvyXT0xj$0l zfoMZTHAt)P)n+zvthYvfojG;!YIDVsQ5EoEm33mUdZNJtPC&7ujH@XA z*$nv-WW!@toUY%>LNO`;1l1)00rM!uquB$FQ!0ug=B)I^LI{mlP55G~k_e)fB8ZN= z!kZIy(V)#{%K-lnC2%M8( z?{65{E<#W@wv0L2cy5&iC}N505t-9bI$vI4u;H3z^iILg&AGhxtb9(=Q24Z7_&Z8~ z!8qKlAICGflhfD|`2Ff?K2#pk;@H&w`Fi z{*k<8vcPgCi66RgZ?9Sit`v|_0r*nrW)y3%d1&`U;CGG0+m7t}CvFIMLJK_#;^hbH zICPGU`Jz~s1Th1aQ+r2|Z$dDW1QH9uDC;#)3X+#r;C(H&0`4oqCzHr=uy~3LSFeoN z3IkJQv&^cc+@mf28IvCUsYKti^BNjV}z}L)EvE*LE<-)r|q=ygtJ8_7g z6;M-owQh)RUt;a)lW$acAAK>YL;R?KV($gy#VR)={mx|%PxFdI`2;2KW8YhGCchQL zs~>*#W2UzZp0Tr4_%p>e@DkyWtvIQi~Go`->okH|i)>>YdRxn)bHth@H95+zOn2=v(K+06%g z+Tk(|IY+v$Ut=fS8v0=NPIb;jGUn0Uw3z6yQ|}w{Y@w}11($VLA@Dm8?7cnV71zeB z>G9)6ir?io=9Lb8dwkq{wMH~8_&8zW=27M1BQftf0fG~S>T17@I-S;o7CFs7Uwn5% z%3*-W--W#peO%sUx>BCgCa>9cT0wLw3&p)@^k~!!0SL9l+-FWkzEhGlh`0l?` z`r`iT^Mz(p<6oHLVp z9IjTVBQLg-?u4VkqItdPU@=%};Rg6LiC1hsL!&w4vQFy=fU29z`#L!@xK4UFT|}mh zDzp!Zo)t6avs8%2yD+F@Vny~l85RI>v3ODE1E`BFMDq`n5XTejLko%Hu^R{7`zCYF zmnU+Z7BkKp>657)p7TQgP?as!Gn_Yq#CviaL^yz05{ppj83ANkI5$Z{w-Pp}9%n@8q)ErE+*+%g+wsBWl$Cf9w!uqr= zI3@$~?DlnuKbEbwKmv@%+L3}e$cT!5Aiae@H=7Z}#|$UZ^oLD|hrvO)75?Xe+(5g_ zI2GR|Acls7*78P@XaVHD?84*3I95n=hPsaBy~ynM?~luORMAT^BIY6Y&dJD-0BVI0 zw>BO(a)zEP-Ji(M#p|S_nb{<~9wwspqnIeZ>7+mNW+l&t->i6>gNPYgxOULWL#arA;-H_Hx7z$l_bvF1PW-Kn=Na&shzgIV%2?LC97(ZkKM z^251=FH4WOf~073bvLfcI^)*2gCfZ#G5A1EU59`e9}He(-!g8%`~w({uy2V2wrko| z(TAJ19t+oM@!fVD5*kI$Iu$;3vQ2HP!W6tS<07?1VeT@s!ve>@6-)9tKXyN&a*i@+ zSI)|Hp4hQkt*(w#7gUT{NwaXa+at#chv1BbpSxr&*k z%{-umpsl=$pw>DQ;_U6S&^JF}U}(QV z>I&i0P0qGWz`THTK}kNe$z1m)hZE)tCoIxby~DFEp1>vP@EHHiG5dUi;N)TLHcUC$de>7ihf%r_dSXt@e&Im%Lu`>U=LT}xBQu9{v_U<1e*Ui)zWavOv=+c&C@5* zQ>__P(tTC3pKK6aAXMl6aBnGW2Pm))S2Ft`Mh!a z;kX+o?1fi!W_^U8;O>xD>|d`qVefdP_c<-^^XA?OPTq-r-bpdu7t*{*3z|`h!^zfO z-%l$zHB85Ro^An*^muq*%Ip_~o#<@#E@~VhIr(Jz`Osd!AxrgTCHjQq38|qWwyqh7 zT-?j58|tnQ+XK7g-M3a&!y=@z@V|~SIvrl~Ghgg{uO|9V8~E7oN_pkY^ur)_wX8zJ znJ*?_TXKfQxOY_4h?U^T+bMzdjuG1H>4-H?(jWP1MUGhw3c%!` z*>@m&6GknsD-DQJ-h8K?gum@SAgl91Yzw(*Cj8CU0?5NuJyJv2f{)xzx*i(*>hCFz zPOW$O+ahB$g!MN+XypCfIAGCv8bWL4!C!zMz$g~uJ1*{ft1!cUJVT#8EfFVc#{ktW zxZJ}z4&|Mcz6*NmxA69b_f*=#lkg+n;k?rm_0O_r`-B9!HgiyaZMGAT0#kFsor*@h z4~`daQt&_fcj^a;C$6x~SR%`xG-vf5U^Y%WZ=2;0d+zby6#Y4Gf(~?7>ce?J*4NIH zyAl+q|0A{k2XPa|Y4W#ERwV-C7|?Li{1e9f96UeefHv`B-X+DpN&HqU=0gi0drB7S z$P%dk>u5&gb@TC@@pOYtW}faR3Xk%f#!vO&zm?294u$0t8@pcEE0Ro8yAsE_a3@u29W(nuj?g^Um6Y81j@WwB9xADoT3!&qIVkGkEelELxD@wP0 z%{A8_Kg0DQ2~AGlTJx-?I}EC;{fo%N->|>yhhxQnOL<_UIM4$#$1tfz( zR>+uDgJ8$j@L;~fA$Rsy%V)?2ZS1z!A%xMlm&E6V59bzdm2qBTCU5xiTCRif>pVKY zh4ErQ9kk({2ZF&%{?Nbkr`}}VzH^7bcn_^9l_2w4MDembAyIK^emZVz3)gQs=7o)a za9Kn}=&wdvth)aQ8Q2LicV8!8Y|`L5h~dYJQb&RZLZHrUm!vV*d^PX2@YY!|WW*Td zdwE#*Fx(EA-kfguPp`=8?xe^29B0bi2_Am++@6v3f!6C2!D~;=18-HFB;*VEKFs!? z5N${bwOkYs2>>TLQuXQ7Q#!oF_0#X1B9lUNWf)-V1Bi<uoh>qNC^1KVX|%-5*~ z^peMuU?V<>cr?V60XDCws;Z^v^JVBC0Q6v7rZ|IRJl-U#P9?xHyzx0gBH!L0VScCc?38WbUeds_L`~_HC7kTMg$^W#-f2Q)>TF6L_?Q>Vi z(?7w6!S!FJD=&8Pwh+E*@MT?`;bjd3Tn#@}(F!qx0WXUjo*t*#lenv3X`qkfj)U8i zKxRu(c(j@pUj~j|K`;3ny;(hh|*(*`Q&pwH)G2;&D2FYWZyU(?P@exx$~KCd`+Q{RU{FGn`17vQt2# ziqB)3;IZCl!q^u5L8MkaWhz=k?Er$a$*2z9CuP#r8+f0$Jw;r*IrQtwo}53}ga%6C z(VQh$MP^lyvX1`Na_fAVRm*!3$7`pP1!~WVCgw%f@yI=Ymf{0F)oD?~qQ=<5oMW@X zi8aFf%40s?kEUcLkTp2(FhDa~sMqBmVE4PZWT-D;<#L=x@X{>_b*k=zX9BadFdQ(a}9LKep>QDo+Jb0-N|Er;|iMyoxarMq;4LoUXoCecz*4S4A98B8PLXiKHiLi zBNqg~o(tI`&o}!)rGTdE7}_`WP}ls+qy2h5&tE^!A{}a8;a)6DKutS&U5m0Vj8pm1 zue>G2`Z)e4k{+kTSI;f%xFJ&k^#u(Dvf>j)ckz^g)okm z6x&{laiQfQH2Hvb>4T76ICoE`a>Lt@BKCz*7y$r%-flu7@!t32q1~1o3;+Hz2Aas1 zq4i|5y_*ya;Ki>?JDi!x_AN~ghsN#;T0SP@IXMt@p@xB5`@@Z&hFZ2wu*hb>Y9Cu`17#e=w5ccfUfa62Jd@ga|vk`0Bzp z{}|WJbUFJn_T0$xKF1!%D*KqtIEwYWd5m(|+Ek~bYMv<4d1?zb;*YK8Sdap54Gqw= zH?|dqYWKC~t4d65@4OQczozeLl&Ws`RBv9SewA6Wk0)eFBFS%q)NCOUol-R=fED*nrg4-|dO{e`=zWw1v_~G#Jt);>1n6RIlBk!}rz*T+2*k~WG`_~O*;OGAK zDlHQp=8AkybBNcc-n}ULCND^BZ1KtSM_SKod9d1f4@LB*j`R2}tOM}8@aVYlVEe?S0kiMx;?p@Xe{Zn@iiMO5^S|~> zILo*TU%e8~QOPugkFAv?eMx|m zZ$7PjE=tj@v@}>MLs^ke>x7L*i8XRmDG%jWIx*xh(pI+7l!MtVQ2a2g@8W3i@0Q0Q zx$dB0giqV9BlCXlK2TvtlP6mO3#lJD-i+eSHCN@Y=aH>%)>rYth^2dB0H$?(nD4b< zo7-mdVhdd+37#gBIAPtIWw6>tKCMw8sGHsdqkWV!xF5o z=D2P#-sGy5*`{yvf0z#%;YGMok(N@j=UuQwv#T`4FK5pe7;6t7zhVx#c8)`nrug(b zqj9H3&Yc`1i2YETvw1^Fca{{H!gPDp_nkLLSTRw^sHVzk5q(a$U?Zw`m`Cnzf`;|S zFmJ9Pqn*6i<|`y-rK9INXR7p*$nKl^8B6wj)&_KRp2e2B9tnQ!l?2~`gHbSYkKVhY zLCH*bdQ&g!sdZ^<094Kc7?SWXGdG-=HKC#?mIml`Xk|lG{4_EYUI3*dwAC67ZlV{f z2ik%8Q@iP9vI7KXSBeDw8$rLvj{7YY1O%h)O1q95pGF%=Z7zYsD&S@Y3JsdKZ6gb_ zSHf+nh2h^75B*>qZ!hK%4JAng*i_l_#&HGGHlW~If0iNaT8-0zw%tTVlkDMQ;BHrg zxH!EMqP#2qGC2x9Tbn6s>PmK!-MyG?C2STBye`7Yp!rVd_z83{iW3@x3T&V9+9edG zzx_kiyybwj&)p?UcH%(V8eu-Fis@n630K{fGYp#pp#0=dz&S>rp}3sPl9Z5q^tw7R zcTzaj=PYO%e_Rr!Qq!>AJ<|i7@UFUp38*>P73nC;I4Y>KCV-DIHAevB(SJWmmj();32dWvR zS(+@&HZWhWGdqi0if(As0UdMg7A-357V=t$oaDASvt()7tG6uY6pfz_`e~n!J)i{a zLxe<|aXj*_v~qfVGyemsXV=8ZSOSofxFn>;ZD7yW-r05XOUPDjPoCe2K?_6__NWm8 za;Cd=PtJB8PmPw8(c!ZcP5Zcf=mTHH&)*jm57Ao{KPDDkG_$g4s^2gwb*F@oL|)k2 zG2x>V)vg+YS|*e%^YD0QHEs%XxPR?f<*w*>(*=C#Lz`lE*8z1^!ih8dL(r55MS2+W zGf@E8bh9X@{yI*4#D`bEoEfb8O5ufy2|vlNjrgHL()o}&HFFIpG&pKo;}P}g%q{oq z@cm_}`?WlV`z3Or-FI(r%)l4QRDt;ZAXN1ZvMzsORZZVSYVX%^p2~R91P^?dHh^k^ z)|9WV1_-6iWT=}lbA_`L6pPRjh$-)61%>Vh>#r8Owts7#au6s>IT(Cu=+ zIUqlDWDfJQYAXgIrW}jlch|{xyy!d?$wZj*_cT;R#jn}34_&T>h*|1_aUUbR>&JPt z6Lf`wWE(`gUt)$%ZSP%GyK4T!CriJ2el_e53)RAiA3uwKvH}Zaul&U&k3HYp+0DUb zH?eaFXn}IbP2$mkubcq;TX|s7Nb|2!H}pj`zdqKK^*6h5_2kSfurjG+e2CG9v6ZqI zL=GF7AU-;@n_g3IB)w+m@)lKiooGx@nlO3^HEc~u*RKr;Q6q_)M*a&9^Lf)#qD!+_ z_Z_>uz9R8yKVX`VDJSG|^zj6iYFytTRNHGeyp{0;bY!_wBE(DLD{1A{ie_U{qk{0~ z{^Q2mnxe_*sV45A=hL5)MblDQ7cw3@KaJ2My$sj2+%4o1Y^TkhKdKC+XaU~wX z0DYgT_tsZ>UL!~4=evigYw==>w|$J#0EVyuPW5|xzlrm%`3AD6m%)h=CwYD;^JEM%!{#Gys)qRjLDK-n<^vdV)Dn#g|^_VSCzG zl31-fZVKbkPX%i^l9g?=+Vjt84-g{cKM zsg(bKkB%{3*FP#(1Xx*Aq$`gXqYWU-5S#x3?0EaCCpHm&--86towQTjNMh>~h&FWYa zK(_XbsBvS?0jn0D?H6;2$b%%dU8NEA)17 zsI-rQqU?;y@{Df1l0Wa9-Rn#?72^|V%|Oxv2Ilj8)UHdYZ!R3Owfd0hVqWP?dJ6a` ziE@(nU(S5J40qPoSqsGaRyoonJn$D%!Y=SSzIo9g;v-2Q&&H{Dn-Gudi&T350~_S~ zhT7yA&%O_jt259tGay;kKEhcbg$hGQs#3AiIKSVt!blBt|q7i=h2zEHOunON+c zM;Gv9sueon)3It^v(z!i=*oS_sSrAjx(d2vX$fao8P9Z^<$|Tx!^SbetuYX*-VbIz zjUsVjw13nKldilwLS|^L8yP0K_0CSa-y?Cs-UhL^M0MzH}EQdc_Li}-pDc|b5Y)Kl}3+;*lxcBt&?-WZcz0-2{J?7lg z+or0Jf+S85W(;Q(o2-<2-Nt8{=8~OT&(6SWSy>~xo0xRZewOZzdze?= zW@fGX>U#L{aHy8;p2syOgRS1FjCoR~-3Xi403499Ub`A)J$@@sa<1-mgCGeXwVTJc z#B`|WCOl<88ZD<2nwv(V1BMHoQUNqSma%-kbOqJKz{;MVazVqj9P~K1OQerGjy8f9SF!U{nCcN_zMk^X4caO_zYC(> z_NFZ*jP$!qun_oSLn6!f#8ETcR4`6O($Pzs->iT1!DOw7x;kkQ(!D_KR*7QOg+TY2 zL0nRte!VGjJ2!(O)Pty@H!FH<)}KAQQF(9U_js$FC6BB%R6SjL+|olwoVxFLsH>Z# z$xX&Eh-ycTpRx!vnn6{^0j!_$sfT=44a{Bpq89H=)9UO|eL&xy zDAr<&V@oMtJ})!ip1s`?bq)HVC*3_eXNww8sJwL+hp3BpiyzrVI4TRCM< zT7`^kF7ha!p0aIg`SU8{SV>j}a?oCRZQFFc5T|&z60VE=&7i z-sg9ym2Fl^rUa`l)~KiO#hD%KKFBnmcG{p)x3EWkuAjdL?=S;W^JM4}p={I@_ULGA zzKsA0Z_Jo7!Er2)p=e=J1Y`{vqG?sSPi%bZhP6F^#c{6^m%>L z^8uG|$thq&H3E^#O@Xos&>7>oS-Kr^E%HTsBLv>{^t9A;kC~Vqk^9AyuJ=-$(Xu?K z1lASTg{)DQ(Gv41zh%QU7Q(rQw>raQRX;zy=d?QB6Wx}wTQ zS;npp1=}c?`GOJ6kTjdDem;Wf)X9!)au}2K-@N^a8|%-71yV<~X3?z88S2w}!R3W0 zeOpd9d>tTd+imuqRgv2ZT~ad}FK+Xq@1ree=w!768-sC?u$T~ML6BV!#ds@E{7JOA z0SjtP(b_*Gd2xN@QuK;|C1(U|h$$gO+p1)^%gFEZ?0L(Ofp8stLX)n)ffhndsLoB% z)HdDt0mZP3jy$hr`uQg6Rq!FJ+u*^BPQDJ~n>e`ytLUwXW0LRTJ3ruLinguGp;F+p z)_#5;*0I{}{_@@(8w|`0)wmRx;M3|Q12+UTNzg56t^)mxLYg-1w3I5v$6jUXpShz~XxYotRPB+j+J&cX;$%F!b>ulzb!Glb zM-I{@0_;ljZPTge`mIi`@JuqYgceQ~)yNcv&viuGVp3U{VCofBvHPpk^UaS(iL&_C zjK>GOZ_7Snh)~lEFoqANmFaXUfq{6~c}^Z2mIP311!HTivbwq`)nL1qQV3gct4VC!$UC6nRM zNy%Gs(lkz}|K$+Q>Q^1$ubwk)wW@67H=74lSbv{#{C?~ZRcr*D7m^tB6=l{)#Z*ws zzR9>!{S1Qh&b-+>mcY=G?Zc9+jCMYJRS=u^AV_I8xK4FGCPO~RbNs8jS={A$b;gXO z{MK-M5JM7VmR6jhr_-9j>q7QMal%*~XH!@*)|CaF=nGweT;G6KKZ-Z4&tl)p!2Yo@ zuT3hJL+`CpOP(e1lDeH6J)yF5@wr${mrf&Pj0{&p@F3r7pvrKy6InNNO>l_zhS5CR zxOwx)>ATXo)Y57zy7#Z7m5pm8<8+EK{Pag!;gh^Z0KCGgw96{TF5A0$8k+inR&7-z zV{%CrLKO^Er{g8ovk$ixYtMIU?Slq|t>giD1MmNg^vxqG?97#~I0S9N+oiyNFp^L5MD z){n4+Ak!GKZf8&DaGej4qF;NcbQohO+j|P#0|nHXx4steCP-F1p7_~irb+#f?cVXT z&l8fVKc1=2*9YZG8dY(?YEl7->qb@S6}Rw@lgMFjsmgzN5I)I{8kGpU8k(fgWs~Px zOH_i*6|`h-*i~P0FzfA^EF(aMLFz2_&zm|HCsQKkS9MKoJgh!na$yhnUtxgn%UDmN z=*pklBiWK6?aY=7q9NwVANJ`7KlfC6L~d{21h0TXouj@l{Wbjo3>>B^qVKkZiH2AN z9rC|)&~p|wd2y?v?)fcx#2fp)xeXIBgHKG!;L#B()J1%p%6n{o5Bd8*iFhVh5Ic~Y?Vr_uH^R4+)S7_?{>kU^vC&;$t@^HkM**JfA zXvHbmZOe>D{^E5)PAR%;(q`cds{&X6mdTIz8rCXOPchYGt%@i&6kM)`iM`VQ4am3G z_z%D$P({wA6ZSGDDZF~*&q~7ZGxh8Y1IhTza!>I9R_2dx(1}4&2Ltt6lGWtkYoXQg zp%v?0Q{twUhN=95)<&PLi!L{tf>jMxU_2E81iPSP=Jh_XVeS0$%MPr@Keq(ra{kM5 z6c$af66G9R%+A|74QLQGGctcDz*z$P(PK^Sd#p+arBIXwj)L6AT{rEw-tug=CDi3w zECM91c*XMQ6?&3&LuF5jGwa(-m{ZH0J>j-NgBJarXIY{%Z6Ove=uA6^5n&@l)_V)l zHf7uLsLU_^DMX~eoeFvgl37L*#4SgOV2zV|^>qTMmd5ra&5-vMEBU@d3baBMtL7Yi zJ~u)U&Q|4%Yk}V-_*zBC^=qMTPs8e{B65-e;}X_%T}8P||x0k?j?s31{s?LvI2~&AJX%aD6|Kr!Ec9)(Ab+PLf>kzS*zx#NOHa=Aq$hy|5xQCs*A)LGZiKEnz6tOAFYrM62IZ682=jx8@*mFJqY{cu8>QWD9wvT8( z53_VJNF5y&jQ!Oodah|sVMs-z>SJqxja-D7fsujT0NiZ%#t+-CY2QWUf15aDkVFl~ z^t0b=yCUbl{R#Ub^2A)NANu7{$JNHOuJH}owC0T&;V*vi59Te_LpLAwB}d+|;^?Kl zcKl>=(ek}j<>rSf|1{Ef@RJvpW+L8a*CwRng019&n*k@#wb>8p_2>f%YX7XazM%hj zdhh3&Y7h-CdI^@HAj#&l>#vxP7rJOCXJ@*nAlw(j;OVCiYAE_xA{Jp;CR1#YV-?+& zi8%3t&MfV7MS@O)ABL%;9VqeepnlJ4NNBOKEE^!fq za$9Tt>tcBk9xH)uvZa#iPC5&1y@owvWw8WyTGZ4E>etNiWB+z(YFj>tjm)grVep|} z{ZNaoI*}8a!i7bptICJ3$yvT^1Xs-qzb;X;;qeJOJL`PmrNs5!(obd^zAhIRC2sth z`ebo|&+yH7Eq-xWj`J@xDSggwJNw~($YXXJV|I$Abxi@Pyb5w|S8UvEq#hC9Ta3Fs zdRm*_sedB)^mwLsYq}69@1&eR{)&qkf2cMeL@Qh&o0&JI>$87S<3i-UkK+a+f>Ij< zg_4oYY;qF9bv|%BAw9yT>9%uOZQ46C~LT76B_FT6ys}7A(TL71Z&CU2uG-eZb3?; zm7qrA2(*w=9Mk;zp5I%Q`#V^V9&Yw<2`8YXS35gu6#DSkIgo-^{FPH(An_%8M}gBs zD1Hgp{uyO4F5$GU5w8$J|0s#3@)sZ7qV=bgn4h z!0eIkp`{+vnTbFdRs;Os#bLxFrU>( zdFQ`b-k#9r*cHck4+$}a_$0&3&*U`pb+^%KSmvq20}BZCD)+BJvQ!PHFbBe(#<8WM zh_c7@X7r=0$gMLkkL#nCrueHBkUudtoy!Ee z$I@r%8@AM5mjs#%*I^uz?bYaNM;l#C7iwZ$)q+i6zr3}TsBF$qWdtdP$EU+0`gwFP zY{=0rkZcng9P?%=J7}X`rfM7y4+jdl)xy)_X9(LDj?$}gGKH%OGejhdu8ei13v+N* zANXPMRUzw^Vt(Tp%0j&1GO%umkV1$~9G)&pI4+}%U-Y*Wdwl=CK^?9*$kc!$ozGPw zDbkX_5BVA}#{m6vbr!hRFM15w&Sr6CG*54y@H7)uO*xzq3g48%}pNZP~KY4dZbBJFLAY%ZMCq6)x;}QEn zl~$l*s}1^}C2C6nA>;_v1IX?vAS;0=jR&e4c&!~_v9A>I_iVXU3UUkg*B)%T;{?0U zMrNoZQv#5Y@hE?Vql@9Oxx1*D_{FYT#3n^NN(^;f;fdpG**UzJ)BtLlE%m4OhF+tu zGG5H$tXD4^RnLZS0uXy_dG`QNG#i!TJT2V-zQ;zj<8L<$+;LxmZv&BoTPLyDI!Nf;%J;q zCms2+?#1XbVhWGqWhI@ih4V=u=ju=$c=!>b>^2*@S%>VxBT#QpFPR<*M6f>-W%LHo z%tZXL?AuvF)aZqWGZ6m*<$KtgYXL~jho~+l|LLW?mjRQghp1IuH39(s504sW$~80P zwz^Rk3hC8>JRg_{Mzc2Xn+j(wlJn;ln6D1G6#z%=$u-sq8P$SRC6t^Rz#Vl;yEw7m z0Kx61JKSR}b}|yX31I-_w<&VC&BG6G3n#YYzl&_mojpQvx~kqGOlenNfPHPhrSjjl z;7xbILoTfegT_h;LmCDIq@?w613_U?%k$zwH98l{i)W|fW+b(Q1g-Zfm_TeKNLfMb zJLqgZ`OOSo;xrM=wOQ-Cr33;sC+kq$pPpVV2+NRm1|8Yi(_9RYS{~sivyamGymLq4 z+iZCcG1bsOo(KvSc|SXMPJlgR(?#y^DL%GC6r2wrwB+vc>X0HLoahk%*tB3R$ z76C9lM-|L$0CF(^*~10sEcJ4f@C|s-All##gQuO1dIoeHJ+C2n?pgGnl}du;il=JK zlx5uxeinA-p`J)~`(Svf;Kxyo=Q_myJa?wvp7~VfpXW(@e$RR!&X4nG(7E~W>o}V+ z{T*JfBf8Rdq%Q%<33C<^@P9pWjive=1s(<&(g37Ys|mb(tKz;SG|fg;1b{NscXDP^cYD&TD#s_odFU%+`f6twp3jBP@=hU2OT)r(_jP!V)idO=?lCESJVJ(uz!TQ7p>XFwypuAI zH00z__mg2lLK@!M`OBy+3et$O-!;tN!#-5c1g6wUt1y9~JBS=K?oP2lh@{&4L?Ic` zfS=mOMSlpHBqXanwwf&q_*T~JQ+np9IANuY5VYrCrgQNTY_Hs%^yr;G;z!_p86qcW zl4#hWe#0Rx)+70Y$nm19qPIqlX7rb=;pHtfO`UO~38T_NfXni@w;fEC)3pMaFUWSb z#4>}YHQ{z=2g+6u25*N;{`7@vM!YLk#U+Bba4a(ga2r~F8weLd%j^KpgI+ zpT`%`@lI!zpRY^rFG)vvMbA&5a+!dpUcl%+Vuxk@=o5sdpwR^sa&1lc`tVfEl5{vw zTv9=dz?A#ZJ~|nd6!jBW$yV2(07=GAs<*x#oF%y!n3Tr^oSEW_GDzlFZ}KT5Ctp6N znteg-)sbRTX<@A-t-y|Z>RzeO^#bfnNqo zlW@(7Y<=01a7%ecEqIyHYoGwWgT^~xWDL@kAe0x93SjpObjF@}E@iCFtYjvfOJQ4$NEyCplBRJDsz z4k#Sae1ds=MoGH-@788qVw{QPR()cbW31Qw~#l;PRgloEdb|`R*otJw5U|a+PhT6qJMz z2Q4na%j@z+-nKarN(KhEaqvg7zwYs9wX~ePYnM=L4d2n6^?Uk+^xWaTu~G61nUW#w zy@zslk0g}U%(Xs!)>5{2*krcs)9-SzKeL;#`#h;7zq0QO{~?YAVD^}~S*@j5Wd zVfxb-)ockzN?&rS6q;f-t_(J+6%Y@QYQ?kG@Dc)`1-*+^U+bzwSE|haI}{4)uzrrT zHLZCEfAlr{(TBQ6M}9u~`pfm(Q`N}-9s{w$1btWjImt^1RWbY6EAQ(@gr2ITJiU19 zsTOHzPZ4IuhEE2d{sqVeu0nPg+KmBy7w09pq%3FA+r|PQm{gA%{I6@m^rYJsZ_!yB z2%e?ft5ZMtV>H9Eu*@W@Nw8eG}%2#CxuoGmcg>TaLVU zk$nB-cm2NS?6nJJFWYbMvt?uJ(0X&1S(q>l20*A5bh>(d$2Jj*ldv6!S9FCr;T;SR zgC+>4+w+4gg^uITJDzscyr|A(re1$Ne?3d_u|nYE33>5`WUtzy$JzNuTA z@BCu+RP7{I<5>=CIp7&C3hN{9FX3UM_>Dp0zW=q0YUDE|5S15f^=AS5a!M~Gl!TX; zgcobiD1W+uUG80e)Rk<1o3k=frRhJRYMjMQg$0@Bjd%YuakkIgkWeO>ALv|w+| zLM}K|6Yu-Yy;=ykrS~qo{T_2+`f&9()2F+`H9PN8zTUN6s8JIh2f{BZot z4%Mx9gYwBLE|;Sqzr%+P$H2qxBl1KKW62THF(+~^V-@X7`HBK_^p-c74bs+@Sp`Uo z@q^>-tFMHfZQpe`->p0#N$g=>{CRH@T4KN`ogHTrxgPXzafw1f_F`{Jz!vPrvVM~2>M zok3pWl#g7z5NOSm^wSWjuFwf&6&$wFe%`q^&7uh&^LO;wJ@cyKzsS)po#&Dx8 zFR|i$f%g0c@i;ndi9KSzI5Uxj4jZqv;$_U2jQX6$*B2=(*1#0Zraii8s&m8OF)WF` zBPVQ-KpoRL6x=p!t`W)@aEz_SSxHeK=~=4#!V=JYPri+AV~y|9YZUbca zgYnQ&4r_A0z~XVZN;O{^r%S28q=UXZs8R8<+fGvHX-2WV=Ha9XlfB_a{#2E;aR=;h zbayX2$LyQ4`SMgqF<(j>H!iycnUu6UWD6QQHrrU2DIJ@tFKX(D{DD__?wrEw`>be+ zskZk=UlikC`0*WYhmVPkz?%Ms<54B(`TRkn)IrA zJ~(n^KKei;dhY38)#I^ee=j;54P+Gc`kdKL^74%bS;;T-%3s*p?VDU^(K$D5T_loj zxY>r+|Ji?nKQ)YbVyu0mO@GXMDS-_lI-fp2X7;tUWE2bP2HUv-27^Q?yp_}feRyF9 z#n6)SDC*=g*^R03ixa$nC+}ro0xgClYaMbt+rmFyAy${T9EI~K=bJ_N{T(%X7w5~= z`PEEq6hYzw$IKizcYq38Qw>FpKi6|^mY2kDI9c>&JQbRQlLA93{eVtyjwKC!v!^Hu zefw6n(R}`AuJzw<6vc<5Z=6TC0_$kUzaQM0ED1yUV_#prr;hsM)Mbd8);&uQ!+tAG zxnqaiuOBnt>3EYrESG%l&E1ra6;spn4(DRr;*650=}Iok`SG;bs%FQ_2K|`8=^W5+ zGd3Bo6)i?-aWntWCiO~Azil2L>UTHdT{npLXrITYfS0$gzRp#u%=V1JJOj$IG=1>A zsOSKREBjyJvOsR(BA zK`to%rugS@C=I=w?nz%s@rukchU`+>tI@)<#H_~p3Xzl1E)d&*J~b?{HWsEEDVt+s zI>qcwXmmz?KH!Dxwegb@z=DV9tZ@y6`j{@TtWX?}S-V)K2%lwm_6%8Oct)L)N=3#b zC?RG8gthBdk;`cCBmchqMD_X{4F`e|ZF(STKM+;0@;{2sJT8XEjpMVkcYCzkeYe|P zD%-uf>{hyTY!@Nf5<=LN3Sp0qEgjok6k94e$|8iYTd9>~rAV%gC)VU%F@#R-bgr-3%R&(akNg=leK4NnLrP z{gf`p<{sJ=g0~v^q%Rnc-{719ddQxs6JH-esj&3YgQ&Yoey`N;hGQpnw)C*hNT2(tq{QQM$VMH< zyFSlSi>)f}v;Ui)+`6V#GPEGeGfHZ_!3eyB3T7nQ__d)i)e*+KS!`|WhaHg<5tTia zN0!BXxEW~UTQXePawT;Vqn}LC-K*fLrhmZK434%sZsV9j&qzAux$fqzm>4@W&QEL+ zrW`orvU<>GzYCnB->5e!VB}6hxFyrYIl7n|bXJyoV`8jheXKyen+-1*9YYf(Ty5%= zr#60l?Hhsfc-Z|j{N%|FflG?8Ne;J@Z@I8kP=#W?JeKE{MTd1T3JeR&kGbG7=#`(& z;Rzem`ks6@7E~=$-$=_lBK)o{u0s^>1S^(S1|J@Y5AuF*{Q1w??_*=E6=*SHqpIyFi_1&^G=r>M%o^9AW8ud(AGM* z^dBt>b*wVczuu2IR_K>xK(u&FyBBJ)6kh3}`PS5Uok{p%tLi#zSA4Cno~M=sZ37e^ z6q@dr>h3LHR=%ZO>$;i$=h4OU--*O#+OS`LYQypa(WDK}q}AImZ+TPyLjQ;yYDs#y z9oVR=oy~;mO2vr2({;AKD{fUkxwOsE?u~|Ce!jY`O=N%#Q`HUIgUgV&`Jx(#H3#|{ zKRBP?Tr96W!EjVt!<1OXMMYm;cIz@?A4b)54y%6rc5AiEg`eldF<+dYnzxGzPltXo zJm5TjDdWoNbGM>(zO9`w?YpqsQCyVW-K&0XOk(jQLUqqv^>anZweIQAFQuz=o_`;{ zcKhdpFNc5se*My7HU|=>;OckFU;WeWT59?An2APJ$O!|p2O5RE4S(L~oW6!|8va^x z@XuS)m!A@!u=(=io>L}5_!*70s{7Ax)(sPXySFXuTWQUW_tb~ihcoet9C(So;OVU>Tn;YiGLcr`1^&e+AT+hFZP`F`f~8g%}MQt zi~Sz|z6whJbOr%DfeFlJmTkKlMoeT)fCol?}0p7vh>cH#3e+HbJF5ukf%4}&HS|J-(r?H_iw^# zQ1`C3-#k3?*?9f?p=YxT`?=xJ1GT-5n*UUz0Q6SMTg_L&4!A-62K8vA|4q8&m`6-| zmkKWZH-Nn%^tDu|JRqq&$v>#l#m0`aA0l)MAHjS`K&=SHX2Qud=z+|gGj7>d7DVO9 z+zt}9PlzBhphIO~EJ=L2$PotV3-hfON`nE8S=Ooy+^_G zd8Z~2qmPSnLSoVN^9C72R3`=74`7=JjI6E904YbkEOYJYO~x$jqS#cxOEjTDx5*r6 z4qiW*s%rB&*Aj6lu}i8yDfll4M|~0Qmk{Sa!#=#2&kj7u7=zi0iUCf@#BkuO2llh_<*yL z*~!G+F?G7YXFfe0FfYKrW#Zpc@YBN3L(&98g^Jx%{G0qXPuJ)(E9A72LQYL) z0eQN%vJ8K*3KS%+fdhHv8Nh6$aR&%DIJ^-|k9` zS8#)B-+qH=G7iyH4n19aislX}I8#z`y*Xr}*;5-(+DL2*xN^{%ZTU*LIp~V;zC|gS31QQa;SA7Td`zVRHehcelu;f92$ua#hgLghXI_e8nyEyHY&R5M}ot}~6^i#lfY7%VOLNilYWi5n4N zFEHST#vv;vmWm4_DyVNyO*NwLE3hMStdxY#%vhEIU>}fh51H64Ox#RcbJ+UJt_Lsc zUW1y;F=r|0Qi{rLIVP8lZjhlLFd=IxFf%5+7U*mMaJQLoGghl56LO!?*`PqJ!r*dA zbs^F4YB^@zhR(BcOcv#e*&4MK0x(&Dxg$XLC@}YE*gGVwK)|m)24>PQJtS<}^J}-* zh(k3{9|rmmrhMOOl?D~)$+OqmW!LV>uJwpiB3Wk#SgKD6o3WATVC9E5F)iep`L>$`a%e zBcG|bsiU#mQnT8O0p65DN=bmZu+Fps9Hr#{l;H$XTAC!Uk2IJ61gd`*@bS*xVKiJi z_4eCkWFyE%l&8r(OaN;H1-#{sOpRH)@>#epG}aQlOy(a2o|>itW+X0Sjs~ zoyAbIKPZ1DG?xk64WQVH(*JaTT$yAytCuH}@ED+;wA;K6+(*OS6=EeUbQw)0+!mWi zDfc14yM@?6mP+Z3yMtm(7zIim?~4mjDPy4}LhM}z*L1}abbUQ`V|{-&1AC8!cBGiq z9LKq{Kq<>hK~jAyV!)4s1&D1+4DWTmT1rUiGbXa){rM|L8xdC_#}%q`4C^K~Y9n)7 zGr~ciiMhFKYhFf!{BhM-(~gPRg#Fr3FFC?UgmPsA%LRQ;J+QCY#Y!m1OMRlQ4D*w+ zY=(q;pujmsEi?TJInJ<|5o3EP*a=a^6TsM>0UrhMuLbz-^82ru#_haiUoT_DB5bpX z>T#e6a{g4+6e+Sf_+B;F&n1=d={x5e&~Xz|$W(dmrzYswN&%@^PO#vv8*umqjq( zOG2wx0OHoCrRQf%RCsUE1PVl5hJ1L#(D3HP)a`cgBK3`tO7t|^;g{_vmg;?m#zPa* zO9o9X*;=O(U-s8&`ku;ijBC-Si&Z-!O+7`ENQ4OLVU_2$V=!` zYT3<#3VZ=zoZa}eqMl__1!l?783M#MG2$sz^*c$WWF&G|{BtG=HK)7_3ZOtptYV~Y zHrn(s;n<~Tut+vKnEBa;a!i4*HfGOcO}>{t)-YzH*6dyAfUf++#GPX!m&EE%enN(2 zA4V7BbZMwgF;+&x{ePL@+Y8X(rHVQJ;q>=nFK>GpZd>T(-dBqy zCna}p17+J`M;WNW;kjXa>2g`S!KX(gr36LWwSO)Ovln*#(dNK%ay~YQ z(L|^RDm=3YLSaxvsrl*ye*~Xixe`%M3pbR`rGjE(wFebzxA(5pTdJ1a%zXIj#-85c zWbA(uUGF^+af0+oGriI5{}hwFwGY=J$_>-Ue6?H7JizyV=4@7(hbfiwBLz@w)=SUS zu;f2|H60-;CHj{p@Aof_zfT&hvfI>OzwX=C;RdfG2*dRY$s;YHC;c1Nf8X(>edC?H z2dR7@q(Q5mP`)Li5g^Nfz3NTKVsdDFPAwG0C?I&`&5SQL<*-rfUf9l#o>@mGhvo@L zvY`J?&6R33xPgg*(lY(D`Zo2VT0I??9a4g+?Ya}cs6N&ntMYXAN+;puupkQ!gLoEK zdy7E=IbSbJK*uF=BTRGjVugOXTgu6Zz9jBfLNUpP`u;>p7^&HCpLkIS^_&RG$2I*+ zrNiQ0o!MsCLY)uH*BFc)I1%qkMK%AZ^s_p@>+^?x5h-AOoA$x+6~3@=HrfmtF}okB zcHVvcyhV<)#}XRi?=ESEgm_9#*ud5ai2D$0q`>kdJ91lFQ%Ud+YlA3uU)`RGGnQx5 z9S3)u>$t6Q2D*N(&eCvu{r1+n^v~|FDW&x1!#sV~edYd^52U1^W%cPMH+ zs8KOzJU}|<;<_>O-IcYQj=)`G6Y|Zk#%?av+;w$g_i73MMsv`&1 zec1^?q!Gw4$ay}X{_Z_$GFP|fU=9F*#nJ%GlpQDEaNOgu*CMTXPmfL?&AiSxsST2k zhnk7RhJ7^ev3?= zx;LeDfaXWAmJSZu-e^6tb;pO68U#`3L7p{pPdT~DUF->VtV_Y8PtzRaAymHGNeO|k3qFy-pXE0CWtvE%3|G7NKR*KV)e`oOnX zO*Itr2KDrzRnJRZ8^Srv*q*_hzFmab3HWCEhN3 zOK>$=|8cf!g_La4fchK%3V zlG!&|VlM-!(Ur^ORU?(B{kGV|Tn}Dzb;M#&FJ7hSsXkRE!8x=^@Jn$lF3WrXw}!?> zg|W&BYzeM`?Td1kfx6l3gB7(=nB>d+g>(RB7b`YHB;*WUqpQq{FZ}9LWrC)$ zgnz=KL?H)GWw|e_kwDf)M#~$T6X*Nq^^)Eq^u}L`cO*Z`QyO zzPR)?Y658?h`M6-sN6V9Y&V;V*X#QVZPfb+)dNfV5?ie0ZAj`_!njH^UH`QZ9^on~ z+&=`>)tnI{%^2vcAznsD->%*JZfk&!qMp)(qa{tchWl z7@o!O<3AH4d~__}Pk|`sJPuZC>2j7X*UDO@pt*Q7o8--b2);Cm=oKle*t1<^H#ISJ@x^WNaA$0aFCIC|fz)oqBKW zDLvO9R-(Fc?K;_|5gm?dvQF_bl~+eXZc2H21q45m+1KLz=b>8-=#RYqNw9Q+5AlFJ z5OF@DG-Iae(T&)APrc_ptGceM$!hc6{Tk6>fjyKEPR{8w5N)?KP_1=GUO;;z-+zO0 z@H*>mWTYT34=DMTy_M{G_HY%#0R?~rIoEmTp$8`P0oj*FXZ`;A8oy!&!w)p7 z+FpqvMxM#B2#+y4_y=lq_C|m+b8sMd=&f-(7wPTyTQkVvmQmkrr00{e(rwX9Q^UnP z?!{9g|rg1Svh;A|I!+R*0xAIv`I zRnfEGPu;lxFE=U>KM0^onLNC*b(6b`1&C3LY+@d^{2ztg$Ca&CtW$%Md*nz^%d z6ZX$E_pmPb_wCB1-z(##Q03%5F6(H95bi1C;pd>Pf#r3?{5>Rzni-uX&uMhzH_aka zW8rlkd{r5|8$fPWtS}TpEEPFB3He84RxDXwxR`Dc#MuJm?*WkOrTVvIxv5#mL>@9@ zX%XR{dcpp&y9g|(2xL<>oLJ`R!4>71I!n~E5v{T9sWS*iz5@}JW7>JDm;ecyLHwV` zmz=+kkiV@Bj10aWPeXbnaNw*hn*2&-3)obRANK^8jh>&fBUWY%3J&fMkvb;cp z-rdalVk(EGL|xJRG6Io1#n2v=qwzpK!vMK9IWLu&r%%2eTX}a~^WF8Gcb8)zb7&5T zX2Vbrqd>Nvph8>hD)K$Kxw67g&LLZI^^{ak5jV3=8@{*XNSC$_iZi!gTLr_`;d3s1 zbu^@LNGMQ44gpgk8jJx_GB+)qqpJfkU~>f=&_D-5NCv+<5C}_5&VFa86`!P43(@ET zGYvRd^#KlT0~WOq@EOK$yQXOc@*t3JaTcu|$SE3?7T066eqGlfm^7`Um!N_?8aa}) z+#~$|)A!ETHI|5_MH(jMi+~dRrc(~{v9e_?I64*RpP4lwtthyJ2|i(4Q0x~hnBrF+ zb>J}vAFbdhIb;5&FwZuwYI6N~E2y9H-N)pu+G}7ZhWf~OR*OJgc60L!X=n8PA}l(7 zo;ym;v7PKyWpOWRz-+0jTe|PwUbue;HYBz+*OdAz6)=W^3Zq)VwrGwH!{3PJpEL*g zt_%LA8h@i3Ym!QebwF(tM6+w?8=74qFCs0~LiTzFfGZyCO&Kr{a&&7U24V=ZJXG-? z^7}Ks1)pRh2sN+@c$~6)tmwhB$^ZjV=+h9$dH|U&vnpPX+yn4*mQ}0kpgMYMnzEa9 z3fgHlT8hc)lYfe=-V|xHElW6XParM35$wJ&)uK)fe-ao@oVisjgeYH4=QW1@j6VE3 z_3&Q^?rBotb>L(p?4-6lWaqs*uuz6z9HOV7X!ALB3VeCsitoCDIztiJm)T-rKv|o-ya#nM@X8H z<2u0~zJ`ICT<0sK=*!tM-is>xX{^Cn z!nLGq#6e_%{#0PYmSRJK2Tatk@$Q)018j=n+Kaqm|93$< zigla&9$vgS9LWvU>(bt`H1_n+yS1CF@oH?CFGYz4Tod`pJ*%O}(3fbDECu#ehYRz-kO5y$hZ@*@Bd{rc)!R7&paiRsv#@s~uKlJBh7Z2*d(mh&W)a9X zr9doLaouo>WlNe9g9Hc#l{2*QnPs6q@)P0^6;t#J(bKdx@2=rkC0F%7s0JUBf3t}E z0lrg-UM9uAxs|tBc&j*TJe-x6BFjq=uT@P-Y?0a@u7rgnG)9uB@ zvm$d8B`{HrrW~rmU>gcv{N4A|g1|AA0g_NC%nBd>-&qX+x|)>-%?iK%t_bGMwhQFi z33%p<9B38?S1rG{2t)+tr&v|}xf1pSSD+CH-@!*D6Y>uz^5!1IsT`6K@meoJ^Afvw z1xsIF4ki~`re3#hMKl5CyF|#My(`jX(1|O@t!R0jQe-mK>{BuL;QEzIR!0wJ`96@+ zw+B{U7Uy5#_J+Xe@dcSG$Vg`(7*RJKx5RpRi?YTCrix zs;O}Esem;vevEJ}v$*s6x8z9yw(aU|1*Hzp0zef>iIhpMIJz04n_cXT3@`A0O;geB!M0v@=JQf>yP=x3? zYwIzC=sS)a)_v`$lfNH8PLJhP4I^Ap>yOta1h30a5$2^xI}a?vLI>YAy#KKA+1nB- zTDum+#e!y3w$(n47GqZX%2>UFhV;!)w-J8+U%7!sNYL9EJ ze=@s_vQxTiR0x*-f2*uY5ip8JR?@sqK z+xG?X&^l+(R?vOSeA*)0hG3pS%E8XCabj>!TfSZb7I`RlU#w$zzx#6kqrC4(>#usWHI z80R`b>6ZI&=&7( z3@z7?rw4E2HsyW8jBBCcalt3&?Pwq-c^`~FuOI%+lEF3&S+7Kd1s&;DzWXgU74do>Oyt6KRRodsa zg5#=fuo8L3W=8LmeO&6&PWO$n4@2UO!9tkTB9uXcM+5L+lrmC|)22X!fviZKtd#_g zVW5s4<8+?dVjzVF+=Ob8gtb9g>^)XW0hI1I|IGFLJ;_ZK*kf2e$Z9)3c8 zPOgKTciZiE#CQ&Kc?ns5z?TVI9eB{20av44wqSAN39)ykdCJ_sCcczRgV1a)@V_?&kp2TD44`{bVp5$wi$=nm3e7y))eEA~=2R1Nrhc?HL7 zJo{e$A;tE>jZwLmejdD31Cv&(e0qb<@fDtxof_Rd5IAB+z#%bg7N?bgT4$nQD;!QsZEu@OREIwA_elMEvV>>iEcrc6czuWe>P8neOOU6&=bQY& z{V|F8aQ%w3DIL21_yxutK5@1G+}d**&iGc*w~sZCn(pLS@0B4-5+|YW}bWaA61!{Nt3V z3|AY<_Z=p|RE^A#`tJPX75{x(Ni3KcdpySRzmM&oZSRdDI?s(?+V;3(*KgO)FK%Rh z`~2y*n?l}`ufBZuAL`z5-@GmYN6zDGgdU5lzin`;#KNvbXZ?J$&kqX~o%YzWDfCIr z5NFS_%ZUYWHI?19u|8x;l?D1oEi;iUA=r_=`tA>W!Rpnrs3i@+?LwaRK>};p5aZR! zlztsI0nJz4_=Uj8*v(ntr>3&LNzAj3RrG0XNEQjQA2u5 zU`6;hIfnJ*G8v#2)OF2I&2D!ptT2=$>Q@Ufcm{AeJAi)7TkEV>YO@zD^M%oQPm_ev zN^oj@UEUN|YdCiEgBA15-#(n~fNUM|ny-gqEpKI;mU@kJi7NfilssO2?u}IGh_|%O z-PmrJ@KY7%o)i`C@i6PsJ)75~yiyCd>#z#9pF?S?b|WMGP*tm(uT_rSe&qw^lI+}m ztmi1O%63o#8f;YN7g^-k!-x3dtb~n4j`!jmKU?4H`i)dF>z?m+s2L^RTQXnB<3d$; zJ^L1_X=oc2?nS(EIn3h#(c|1|`z}$j*N1w^IGRsQ>qpr8P3k0d9b!v8zfhn>4(DKR z`jFT5iS8+(uk#QbYoDUPQ;~d$zBkn4uk&ccYA=_um<@+qo~$$Oi_<>V)g!ftr)HJ$ zEU}!1jG65$zbaQ(*=u6hF-0#<%URr~!Y2vE@Z!&3ImOkrLOQ5|eI#KoOG%JGv|<@e zWE_?H62iTc-v`&GhV>9a`2v_R*+{ks*QurC!T)n{=!0Z?T<01%bnK2$$~1+A=nW+C z+oDU`*B@YW z^QCj!uZMe2E#H&$qGXxO5umS;kD~+Q%em@GT+yO54-+N;TXJ#`&Wb!Q88IK1LV_|C{$3*xM2jE902<_r2(Cr2 zMtconSddnGHQQ3=l(D_~fLGI3woVuc|C*L>aiCg#RTfvhKKAIYu9gcI6iql90BTRr zE_euq2nvNqsZ2%N$CY97tq=|-WS-uTnD}`Rs>>1PMP-}YQWg_+2C`O>oX=}*70?mM z4j1)DScb30`>F3GB|S4a2t%O%imT<&o;Y8+j|~>P`+&)8fI?0aCZ2Z*OY_+q8RN|GCv-$RZOoi=~|i-oHsH1HOewpGK&WqA+;i zjAb?xsX98kGDF#MC%PptV&f$|uAZDvCk~){5GQuu7=(!oHQ^&TS{fd8D52$_=4LJTeP=+?>HTuZ( zRgri08cn#UOtuZUDHMzx>@rJ}@erhEl>Y8w0Jl&G!zTee;t)H&QVysxS^Oj=+{UhJ zGltDpap)i-8&OYD3;?Rj5@SF6_!1J2BPaIK5oDbXJubb-T}n%Q&G*rjMW}`=3AY)^ z$OJ4`U9WcD@Vm~yJu_e4>i&?5&Mc&RKN+7Uu*gjzwWNe>SIruSU_VF)+}y=^nM1vr zm!`~@xa#NSaHlQ_{;+6QwJ+C6hpW0@rNQQj0Ag9xLnx$)_qyi;enX||?mImnYMnJ?C#=CK`{Peb0P^q@O+ zuWQ65pl0-Yewf&J=*0{uf0QapU1m>NXq2krND}H=7F1LlGfNQz>%pm|rE9PY!Gpu_lFQWIoZ65I1m)A$8LEANXqY?sjmDkUea z<6FbG?rHC(6#@CO+4(rysLc7>%QcJzWL1z)&Rb&4JtqWAG)_S6dw+DX^A?8r1+7Mc zG!NFDH0Vr&Z?3hd>w}8TgzL@`xrQKhnr1#Q3On}%@9sMaSz30p*>|R(p=i;5`^t4f zPm3qX*DiD$)YIxdmZ?iHB>3#t^R&kvU7hvEkvkX4bUgIg%~9X$v>>hY{;cI1gqb}|dzkJcTp&Ww&>=IGGP zILi-@g-^7*_o=R;@iWIysoj3ULGf|-@do`B1=OqfWsuU$Xz;I2oo&5ZA}-6%Pb3HO zv^`A>tdCvQk(ys4CFsUh@cv96GJ*U&Gmo7->Qvt;(J?|>xa{+NH-P$6;`d&@IlH$P7D z-MqsRp3$FPw->&yN)9Mt+(vF7b7@rfCTsXNYN!pYHUxgevcd7t1F;)dJ8V*q6QVqGLuwDn>mT*xI%y*Q^t3#p-~~5Mv6bqO5?5lRn$7S!ckusYQY;sb+N8 zXPqeg)QOX$FJC^Wc!fUEypN_7;rti4-f3ObkA)!BNk2Y4F#r-Yl?{Mh130B8u70%Y zjK*pg)rRk3zAnQ!Ge~aEu+bQjdNZT7Eew@y^NnW$oc#= z9?>^ewE)!C^V{n3F$TuQW+y@0*GucKOq|=O68FfcCgxN!c-Gz84-@Pj;!Lq{D+H8(1sUvGKNy12oX zAkiBGR4GE}Jb)uex;Oe@;_eaRn1+o2PAX0@hc1Wlf)Kse;l4fakv``*cg0$GI!!m) zz?AH#0`M$bpk|at?BN%CsL{?Ze5qNG%|rc&Y#%QvkCZ|)&hF7qVVlMETlUE{*0jXL zo3Gj0GHe&1xHW ztp}e%1Nx>^XOm+N8;F;56!A!T0C{-4+;2jjT6Ok&L58A|{DOAM;T7^v!yL*;klSF@ z5$0e7L#IDQ3TUs(bP=Aftp16oUeezE9f>}ZxOz*>f7D2XfNXms|K;RB@y1HPWq77& z_~bjFp3hD$H+}m7x%zvH$?c8G0?8uLG-!{HSqG~{o6c_(A8i-EyjYdu_yQ}F(w;LuA0-Fg7Y{0P@VgXe~rIN*JXb&6nLVr){QFyRKtbrAeX=zlp6-3ha zUNpO#%vmw&yW})Z*Xss7ZOiG4!A?WID%N254>Md?KN^;VV6+@)p)m@f5eKvc83xR@ z*Pcqr$3B`$I$%FKl)a;+D&D$!>zQgF+}h6%PVOhHT_+~?71xU6r!_d$DG>9XciD

FNfq5O`nZv7kV;IsT>$v6d~p_^-}S+hb|}8WRfv2k+CT+v{du#O4}G@??SP z8qpgfO^WBDXOt4`jmW?vZKG)J>D!!b&L_rP*j7Hl){!R=0(M=`d$k?ySuY_M~9&+XDxiLekW?&)Aq>(8p~k;nGhn6|d(tA+)r1U^)829B?b zQfp=}xmXy(lTFX9I9Z#H-+cJ>wvm#!bpluB>wtPdznSMn?fn@;vqx1M)r-+Hk_0iMR*w6SZPXRB+)nDlHi=!TOdqD_mrkO1G*e`I+NXyKh zaooqDPV6{1V}pAoguDC9^V@bW`rBXJ@B_C;t838Jh3i)4>ZI5-SmYt!wUC#NZZv(K z^tSU&fchK&rbtwyrKa`+CAdI-wsI~|yk(6PSC4pS)%px;D&(Mf(#J?Mpsc$B8^?*@ zLpY1Ais(GE-5G8CgXaMs$Z%@pdWcs5hJdRR>dbH|JRA4yzPe6L zM!T9geRan+aEhkFXQyR-R9^NXdpa}G4?*qqQg)D|X=uaeqwe=t)N>$f0j+fCP5}gy z%k#o+f$}()g}u03*t-k>W()Ps>V>5P=sks6=Y72ceUs8@OM;AEujJmIK^SL}E8ym7 za3rbb+Nz#yfSM57Nq00;F4~IGQZ{OoPC=!r^HZR|j8)pSR&jG<#efB(6zpk80;Dzs8PLerM@H8cVB!V%Pqq86DW#^$&_B(Q`@5zcm0>*O!hH%W}Bme$a8e_Kpzd;#N0EWsWKrVaLt{Aq4IZ{vFxU=5IYi=6z!8= z+;eRAa{9;8MfRRcTCY^vdWe+ECNC~$E#QhjIhjy=emXxaiQS2vdgC(qW!@#%;|s*p z)5%npW}YQc^^vtE`b~VUaprTax_!+5n7_7 zJJNf_(>G!kumgOT&w#K~z8uik#*d-F_kG~pYgu{4iM7cIWp$A<=am%FS5nO#!T5Y; z_5Xw5b+Fp?&1Q0rp&964mbzq=Lc__~#){R;sNklkp5-~oxG7rvaWk_%iM|<^g7UQ$ z(V9z0T1f(}X3n;Qbd7q>Cfh4s-My}UP?zS69UGvQ*k<$Z$%Y?&9t`!mDjcHN9F-lt z4(EI9VtMX^zMWHk$QNz(iMcVnAZs8G zyV}K0npUp|rgPM~_k!4XmF@<#pt8!Z!(KhGOrrp;uz74vXDJ_Ug6v@&@yH{>&Zq0}II z4b(s*!|_dEW>)^dHS|m|+jl*F3#`Ji&x=4dw#>n7-0$ZHbBBRt5o-EHzJASqHKo1! zS+J1vN>i4v_a9#`&lKf}ho5AVtY_tTFFkw2>%1>X{xlK`Jrm7ce;={^(^1D*TdZuK z>ZTN&NNg;_+*!cf@dLN^vI!`OdB_cM4(1M_NJ6{OjC8oO_&+&)Ul2$UzHe#<1PYc{^aS z>-Ks!6dtqn@l;~~aKJdOLn_`J=AXOA)g1Dp(meDN6^s+(q>^DvIy6p<>H0&IO4RwZ z%3buobD@=g^1(U!(DR@PO9@1QuOVw@)U&M(BHU|x-E4j1I60_Fh$BgDNy*oDbM`f$ z9)ERO;+W1`(YMx(;;Tn}9!Y_^1oEcBZ#y%5ofhGkV<7Qg@9QHxXEF0lF5;j6z%FG; z*7sNot*#~gGOy?AzW9FXGR;Wny<7p#8iRN_Og*)Z04FM_=e&nCFf$06#7L zvzB{fG?)jxdoBEyEV8&}%-ey@To;D-yA8dTU9KU{JeMw?^n8DFzuPVgJ)>`6Mx;CO5SAHz22QFziZwJ$)0vL**%yZsa zGW6)2_c8~+(_H;!i&iw@x7Pv#LjgrMjV6I$kjbBQF8QWZ7}3==IJ!=g1U2VdMpR(* zt{~U_!k>dZ0VVK;jN_eM7yB4IEstle>GTQ<&?xbfR;Z9?B{SN_v-oqb*6Hni`#9i} zUZy?Rx+@B(`d#%NLsqF-v%6ln&9}k%&ZRKgscFKabJxpj-PLDylgrckfI|7}_b?S5 z-_!qHKz_;HxzQr$89Dfv^Om#CLWsxR`;OZNssCk~Tr8P)A3nWQWAZf*yW}|au=I#; zujY^F& zsQF6N#YWOMUumOiSfDB1<4xe(9J3gk$3sq!LZTkHJWF}}z-_W9%5*NC8)N|^I3(nn z;up`goKTyYT%ngP4?!9=e{8gDz%#bwnsI;aL>UpJJFplHsfH~)X~+H3)5jm7<1O>ELiDK?YK&Q-bna1hN0pZx@KL%KDDc( z9mzgd3c^F-N4eUp@0G0~+s_u0&&eG%Z^SQs@{vDF-KVDEev$e+KQA$NEaq8K?su)L zSJoun%T*5xl;lFAW`1tsC!=D!`HEaAoQL$^E+KKVDEYDE6Lfy;emMk=OP$e4G};?z zm2a@Mw(%`4q89ST!ak!Wue_1Eg0FiFwcpFHO)0Tw-Tu#_e%FXqcvvPqO)^-LEME&d zTxvA&;dEok`q?vQIwoe@)Z;(8Vor3?&z_j8+>UG*H`#z}PzvKjh(-A+2$AryAP;wS zadKo?2hC$cZtE%+lUv`nS|Ks^S&3Nn-Lv18)AwY(0VjSO4%~Bai_eBncYgI(S&Jdp zR)2c1;uhe3MyQpA?vj3<_NCVu2N?zYOzbNt+(oIg%ZPBNOm z&CQbEThGt8NTl4(%nO@Q#n`nyZ7O_z@nQV$PuIV^`u#;>Y@PCH{S7VO>^d(2U%LOUN&Z_veY#SQO4mGp;Vg20DLkZ8f`);Nay^UmS4 znu;f#2h=?#)(s!guP4P*ll93kyh)bzE7aO+EB>A7SgYO5+~YcaM{#$%a#g+V0qf~a zJz#kj_rByy#*D|yEh+h)=_p*`noeE&vVzd`H|mW#tE|@~p@>Nd0SCBj>trU{O~^(} z|A67z-T?W!3FpH`Dh$nN_&hO9ZTAuj0;9dRKXlpfoqr5nAb=MW3aX4w>qsNe<$_%2 zDKfDxaFx%lLs_G!DA*Vq!JKuz>uSx3|b$8?le zwWq&Zmav~VR5VYvCqecY6sWx>$>GQEZ?Wa*h9uxCYVSI~cPJ|;yYIYR#Z+ zCX0$=W1a6^F4l$a3f`41KULv>zGA?2|GDF+`(eR@`v>>zt_UqinD&^|4d35k-LM_R zIZaoJib5(XQ%t5;m`8?}qnyh=jv8fPqh&e66^*!kGrmqu4_#s!Rc1e+d?15bMgEPr$0nxww zDtutAmeyw~_rmC^{E^rvERF?`9izWA2QN za!*1?Xmg#)HKd{@L@qVg+^V@>W3I`qxr9m@soc^?E|KPv+?z{MiMfTomEV5OWZ|nYnG(WWB6sOjz0;X zK3B0W#e)tBzs&(1B04wl)RlqQkTU~y&UNi>DWTOroLLUf8}9y8zIfeWY9eS~{K4Hk zRoA;GXU4^x8#(V+BS=#dD;fE1TL}Rk&mPTIeAj!il<+kA&5uh{r~;OCG)YP|D^Z3; zdHH$znh9nRB&0uwxXv{Z5NO0mMH8#9Qh50vM8yPh0rWiCRMZB;w`8MBkO}LIDCfkg zKFoi;Yl0Cz`v_d|ce`Wrqj%=b=<{-)RB9h1gY;t5DN+?@pNu|Pb6WFLYMp=i?Ccjc z8u+Bw&#~}mSClF}t#oVw11lA9 z%e{&Caj?6%&t>T)&gL3N&3@~ngft#q3u6yP1 zeFl1lo2Y02$U!3(q(^IF1A%^?3UU$eF8>P3`P4eA{<-iIC1b-eYQ^tf#!jD?Sm@Jp zY5uao&Fzi4zp`hfCpAnZ-+z1&_A!J8(xID(Jx_kCIL-j`H2NyfF4{_Qj-Z1F7G$@n zH;je@6XpK$0D}d*_;~xwh{gY8Cz9)1{{`L&d)X?xi|IAgm;s)hF5>L;zSJ;t_5WMN zLHy`V(y^gTi{uh;d%e(`x$iG|fB5*RXZ3m4v#KBai82#6MA!N|4E-;AOf0HjZ;q^v zI;_&~)Z2RN$%j+70?N=geGZ2MF@K1u4(diCSLh(PR@JP=bA=gB?|#AohdE@#=z{1& z8=xfnNahWFQ=wQ^!m$?`sgAc9!kaYM@qGJ~lZIf~Z~3(u9hw=DZE=#RM2M#99n|3_ ze9x<@7t} z)?{zX*n!Mf-;F(dl`SxNYjxY@`Y$_8zP#^ACJg0d08)b_c9JBf1r%_k!JPfR^RS=} z)|c9Wa+QRS21Icluo5!|PVARnB}ro{!92zx3&{C52No{Fsape%bFeEwS-ATjV+N>& zg8NPqZ?b*m%0cjeb)!@ywoEX+pRb$;nVgeKUxJJiajWiF8?AciZ%BviI7tM; z``gA~lz+<7$`B79gChxYi*r&>vu5Y7B0c12N!;uFT=!Kz?x67ds81Qy8p5 z*0ydY+Lpb6$&#J&5RyJpLdk5HJtC`T*Q;@)En@|h%dXC0A@qYb0Q7j7Y-Ab8fg*h?OUvXM?tbc%HbI6WW=RnZzVJci zuaNMiPFZo^HVJzE61&KXw^x=Ds!# z5ML$WqRl2Uc=OLI&xCP^uWbz~O6#gQIVR7uan;E2#4}CdsJ@e#_#Ovbz51h?pZY)7 zk4@PdoYUb`dBeZO!baPQX%Ns&fE{59lz8REKP^qYhW{3Ah2PP+i(Dx)8q|ORcux{s zIs{hjSY=YNDm%%4BOh_!Su-U5@B%$6nJ@FuhE6u|vX!0#d{a)Vj-Ju4!QjGqog` z>OR1+#9em012wMjs_8Vu&;d8@E-U}x^oQI&=cnqx=e7il_2(?~S4TUQ+*97y%;$2? z9Td{v$EY0*vGYLMcZ3?)b5K$rEdsar7Hg*+h6MUXV7DEs+ex3>d8JE|nkDhfxxxYm z&O~fT(cL9m+yy=Iw94@pzm!SS-6d9@%d!aFHF>W`*Km(eg2Gf_rl_j*qebTSVsWU) zj-&ZYhcV+16PKTntUq{E3vZbmHoL!hS=+b2Q_IzBY@oqf;2#Z6yG&3C-CZKd^|D3Z zlH}?L${!Eot{t%Cx+`Uo43!o5GTc9}0_8Rca_vCbjSdO+BcJOBu3oRisgh1n_VZuE z`DCiXBrDf-pMJb>i2K}bte=~E;joBlQI5^;ADd<`^zY=~em` zxEO!)IG(RvPeN@tdgv4X>{`Hr*t2#fNL6=p{KfgcTAcPT)2L6EaXOJ#_w~GnetEX$ zMZR`;iV2L^3!Dhrye1v)6*{Qi;rF#1`R>t9qd+%s{{1@#QCMj^(n$Lx)pP6W`xv9Fl&FO!Zc=ut0X;RKhYr$~Y{>9{?;P?l- z1OFcBYHNn~_n)s2jctCMmiH0kHzF+fv|FD2Z#Gvx^ONU(Zd}C6lm(rXz-vXm?@hLM z(nE8itMoIsn@TtZ59m9Y`!5bSTpwr)PdPIf{$66aayUTrSXSDjq-WzdOjZ3qZQbFG z-JV{J?2(97n0RL#mPtC6d*@q@HJe`cEH>_Ju2V$bx#m1{YOLrz8xOI(H~V9G0eks@ z$L@M3GZ+Pplyi4ujuj+C6io5!Rww4B9J`knaqr$<-9XB-(kJ&GL=-;U!$<9<{7eIH zJ}PW(E_!vZ@K?em8-_bvanwLQCA+st7u3Y~Q8cqxGIz|?jl%mB$XO0@oFQmHyCpeK z-X2ld;?XmH7ZUuzJ~YH2k2gWN=Bi(c`&~wue5{W_#dJsy$M9+p$Lf%bHantA6mBS! zZY22V$e(#tCT(Z%;B}e!GFSn#DAwpcVqh)pLlRK`kysn z`i8`8#|(#nlCP5&shg?#^)NwqK{Hlr###|~4RQB;_4CNb&F2e3_SKsPuex`~jiz45 zCB|U&=S15HKO5s`=kd~8NZHvkT&|RzWI0$>8|UNxbmuou9mV~lOVHI=8K09dBZ*|V zyNm!4y?dV~A3Y`QB)F6tFH4M0Mw_RoGjq17-mYS;w36F4#CwB*!|W zH4sOBQe?(r#EglM17(u=G06Bti$%Ir>Y~o3yKHS4!fZ~~wN*{dA6)4!p4Q*t^W<&f zob+eBRm*|@BFmckT@vrMzW)2)>r>^kD={w3N5JXsO6dK|#&xakHXMZNA*s$HXafOf z76Y9}zsmcaedap27AV(9f(@UA=;DFEPkfM7X|aH--v=xz2`%#MYQd2DIdVuCJ1{MY-I8FLuxJwuNsrrAbx{MB!amtFzl8t0^6lu0`C*p#laLJ+Yh z1aL7Cvqdp1WlIwsCOP`oul^Yra&0zUkrZ~EbrlxkQKips@-8S`%a-Zo7`Zl_-3RuK zMD@KCK)DN9hE&e90nu9i&$}03Pdb1)bGUJm5DzK-dhX-wi|pse-XFa=qR(>b@5J z?qs`BpHjH#evTd9AEZN=X<7XwIRg~wkm)2~R2i?-ZW^u{CGXr^w301PYS_Eh0UURg zQ64);-x96m;)HJrUn-gNx``8=U+ke@5HjO`R(6ub=`1Fyv=Rh}vk}t9Bd2bCyLa)f zkhV0JAl=6LKbN`5Uc#0k{vrd{vj6I;*uM|Y{7#$EW+qNT9#LhfF|8s=F z-ISb$s4B()Y(p9kZg3@lx#_ zqgzgms5LOEo9_ToeA)(!DL<$?DAhI>x(*1cW{UHm?p)$2V-{+5PBz0q-J^Kz>g!)m zK8beN$d0+owv+{bQb4VS;*5cahQ{3y#(KxAxic)mLBi+nWm9e@5aSprd>O)lM@c7Q z*>iH^q|=%|AoC364zy5R$?RmE>=ygw@rKRqqJj6*zvfQ-Lpyye1pfIRBUUH-X96fY z*1-mV+zevAwU=0xDU@~YBN|tqrzyzKok&n=NsdbzIs;4CH&`BqeVBgX|C!U*`bnMd zP71$m+qtAHTzRsvTZrV@wGv(L!NymQmFiN{Zkwe^8TmSvIpD}e1~&zcJ{o=K`1t&* z)T58bp18I~{uR)z9k2K7FEmQieKPsnf2!rCpkCc{vt!;ZJ4f{A79FMZmiQZonH<*M zcs;2}C+^VAjTQERLZ*BRYu`A)^S5n$Rmk@0Tz}HqrQ_aC7?ZKN1~*E$_CevlT>gt+ zJJt+S##={`-eCY~s#!rAeR2Fl^rV!pa*?cIe9~Z@0MWIMk@p`fH_F)u}A& zIA4)%VS8&S`Ay0Jn~DDYCjHy<=~Wl|^S6J0vh0eQF{nNJuFguFg9`-_`aPe$C--Aa zN}QXIz}(}7ZOHBkVi%L$6Q!>860V;bVs}90bol0>xZ>o?$++6CY(JF(cVOfDJU3B$1uC`1xEB^LeUD`}nrMv)I3lWdIny>cCFti1A^FQyzkfBNV>ue%p- z@n0#poMCn4-j&jnD}}yweOHREwex!y2MtVy1?saLBCuf4lkU3yEZ1}^ETDPN*7+SFmksN>o9orakT zY1d2epwPxDj_(z@n*Hw&1hd&20tcD~Lpxze#jl-`jkWS8#oNNZbi%p^zkxE%*;Ser-n{;@ycf@+6twSmSpZ(_$ zSp<9hU@X@D{(jLI^x=vtKcuJaP4Gi4Tbl^fF|ugL`|6v1A7RO?Cw*SUpYrx1)b0e^ z>S?rvWa>p?560geJmAs2@Cw~v zX?TN;(TcKsv$Gr`IMe8JoAKG+miRX)!%fy3lzvka@i21ahW3AIZ;J9_SeribB<)|L zXZogd_tDx?U7R306}R_VNqNOH)>vuyq!Xg1C@*~bMP|ixHP6d#*u_IK%DPH{)bwWISdl7CumqQKr)WwT zvKJ?H)#}s<^WT;Ni^_*yso2RD;`3yL78+&y0uuw&XW0LM8Bs2#AUAU5Q45z`tUgZ* zSyQgYkgziBPE{M~RM_<~*F7k-;apN&(Y>17^El7pyl2{FSTRfTESYBcBwb#X|J-5g ze|55l)CFIxEcaE_2IVjp?CqIvUb2tw~?xtPYT`IuWIGyUOfq zRi1o_`Ql8TE4cM&BI%@0EMh+XP;j!ftJt%{8p)k{L>~lci-dWz zyPu+4e)pcX-9p^)$4MFu$)dsSHn|OxG?m7d8(|;bTNwd%sIdL{!%uMj`O>Z1nJVhXds1MBE_whS;Sqi2^Vczv9ixJzRjcb!Hi$12AiSHZ!1}ec# zuyy3Oox(-xB+b(iZp&aYl^0ykj+ZSD7oAcpXfd;Lmb*8r>Uv=|hb3 z=fyW2eP>~u-Z6{m`BXZ-Z?9cE-JNbJ8+EW!#8-OHNc(iWN;DiNbpCuF_t9$h9jx|9rXL=x`Cl9_A4@YpoDITljz6y+aTm;E z)d`O7_SO9$AW5I;=AKneZ|ByLD|=c3vjvvAr5|I??ysl|)#8-2^T$z&veqN_xwVuP zV5UFkd2k-BSUK@!_O($DY2WQmwQGdrsuYUk4jFdIU|t}4)KofrxzoTGVgI<2gIFR) zTwQ@DW*2~ypFDy5UeN@aPcJ0-xi!ovB!E<9%0-wpZ`EW-i8&iIg>R8`lmSt&sl!8t zv)rzoi6U5NVu=sBkN0d?SIJ_hffWHdY!{tg^?Ft*h4I17jh3*VD|d27LpqI4%( z{f*hD-X1m0W}w@&2aZDTf)NPEgbu_GaWOr5?Pb5C)WJCp_1fN0R7S)7r?;Q->aplZ zIdZF9_7^cEsUxs`CJu~Kv^Op~=x!Vwr?8LPuz^X}D8v#S17%k*NyEl9DMB|{*yF)3 zo_$$I4nsX#I9JnPsIf5vPyy&7R~N5?I+=srBwn~|e`1G=YRE#(vrroxqZb~Qo|>rA z7pTv8RJw)JG5H8ChaXlEvPlzEx{TZbpk$z8I3}_&AG>51#$)xmZSnweqzx+SGYyra zhc35MmB%1mJ+Ddm#B6E?J$b;NqZI$+Y+%S)F=-ZJhlScZqI33OoXQ!o>;vdyJJ>o? ze4w3C+Kp&83n#v_)}ES@V~oHj58yoJBui6|ISfR09vP#czcM|J^q`({(UMf?3Ls3s zLU8(%366>QFIcdn`v1hM{i}AsAicQVkQ*h*%E#INHy9@21s~W6)L{5|WGv;6A}1D( z?~kIMGWZNw&|xlVR9tIL!}E23c)#N#7^S2>WY7~~BFf#6{AoV!701o(Pb zeECA;y?VqRLr_ULs_YDIpX+2949%%WWLMlg##=CH2X4|(zd6VOaZwxqLB%5diC{OP z;3FYqT!r%}1-%B~7skN8Q_w?Isv2C|O+2#F3F^3YRRyax$}oFFwDn>lXzQ_0I}lV; zWQ-l36J3zzj=U-4mdb#aG9m@b;dDIw$4By(w}1;59muqE(~-w91*kbeZfw3n3h$-I zxYq;sp8`Twm;zU6d^b7BF;n=`C z$40c?ka#MTvce3ot_Nl_qzDm*{3$SLhI2|&vdbLEhKb~1@nZ16cuvFwtx$;qThT;O zG>ta7NcV3kBhAXk8DKjaPaMLRL=<2G1fSCRz3jkGcD2K*l82Z;)gj=%H^8u8-29z0 zdV;7XbB1pYfF8uB7we(N*hxBcV7Q&R>&STs98K2*(th1vp`v@~z-tf^t{Ym!Ijlj0 z{n%2UUk}Yy0mVX%)MKx=e&rLUI^I|p$fIAis0SV?Km|Q;mS)D!QLdXEab_(bZSY9m zVM4YCeFu+nW6G=Gfs%WuRQe$sOzaHTv11#V+GYHA3;7Fxa$*#nEJvQwR%d1dy(j^7 z0AR3))paiRJsqf85A>&(1wRAoy+g%n0)K&kbpYKHR@Y39q5HXjU3nl8jPwAt6EopuQI3K#A zyTd>gB${n91ThR@NlKM(is?a5^yv|CZZ3HkkYqClswjV4;Q-9e3EANyhrpToswUon zmhyPs1M69KV2-)NP*g`89{!ZcZ$lNm;comAU*n`nB776UVPMy_E3*{}nQw}86SX&P zp!+J2tzRWR3h`w#;P1}x<%pZULNY$S2 zIF6yJM0_?-DDYJQZgg4DwFb7|_6(Sk6!ee^O@i0|$0ur)gr496Fc*M)Oaa;?o)lp` zLA=`oFo&j~$1q`XoUl#0z_-3qK>>h`AYc$s>$?Ct4=}tOdHO0IzPVw2l@id%ik7D) zZ8G`Mg7sKtf+BX8ufB4#rQ=5K$<3 zBsnqUpw9&5iA$K*nW1VQL6nUhP?!cQtuFA{siZzbO=u!wsi4rL$9Ed9y>CVI(vi!X zxBi?0!}TI&sbM`^FI993Pmlzqsh~(ozznrxfQDETMEOqfDY@PwM2nEmyc~FW`?v?P zm)6lwBMnnEV~Y&h8cdRl5`BO!GqrzLfa;Kg^-nQG^m5_=@YZuZh^D3byP* z_fv^hVbsU^;5HMtw{=3m6rHhP0`?Y(YpZ>q3!O}YtrDILMFLw^nyUH3-s zYD(-dc=Xw@uqqVqxGc{Fz41(Jvh|+L8NS#s!xc8NmjS<7D4OPP^h6QlY> z1tsCvzlK2`QVXL{?r*X`{3%Aej&{``_&4yDYcH^9lOI&*1Y4q;hQ3b^{Y>-ssBc-C!b`G@zOnn3&!TaB{^l@r*+_2djdw5o z+VtaJo`#I78EMW@%YS@npQA@~=UuDLl*lr%3`+_B%MGrA*N1F0l<2`3}RPYqf8LG}WAVC{%E_(a?<9{7^PmMq+Mc$-x@ zvP}^@Kk#;wf$V0^P}>kM+3sG`H}m*?w#vItzwa)^qu21r$vd2W7XQs5Ao9+~`4>H| z5=9gv^nHA9yi8bRLa*s*=npQcP!sjTj<1-G<`Lj`@ksLHmY)I-YuY}QAo!QS@2~^< zIJWWP{BCZ+6uyl36~*EWpuWpeTjc0F2#phuzr|Ko(-u);o({5|^H^ zm22bG1OpGc@|}|6EN?Iz>w)V&Dc^`czX7l(zMSBxLGsm9Z#)e7LFsck(wqtb)-(W7 z6ab2GNSZGAbp&~$9zm~sK1ToXB;nR3N8sB-{|FyIV<`|p0SMFCtTzZ=;^N6y-GyOa zxOV&~;twqK2ga)>2Mw{Rl^Up>I}y(KhU* z&jJ=}4Bt&|K}p?CibLi-qTo&M?~^HDeLBE|{r&T0@6sMbz`G;fbio!H?9kYwQ7%w5 z1~be>wlHoN_gE@K%__U><%_>rS&&s5d_}*J-0*2Ka`C(x?^I z0RRgrG4aIB7e-A>G`@+;hs)W5g)}=k8thU}B&}ClrLn@k@Q@A{&`ZY}ZOSYWNqL{E zorr=h47llf15W?%K8}UpFcFbww2EW$4z6AcWEb>O88SK07KUK5Xp>$GDx6WI1HcHI z^*#3Xe{&)pZc841@Z*e0vd}@rY3_H~R(*L)DjR%#wi>D9VAfh)cN!+8qv%-ZjpoHb z^{BmY)1WT(cON_u0?m;Jr1X&mo6 z+jc?NA&gv6ck!jXbA9Dw%K+1lShs86X0S>>XJ0CZZK6t-JE>5=otB%L zr@`*9^UG}!LRmqvjHiVL7@OttwC2d6?un5+U^(1vW2yes(Xu%Bc)F6Ym*r$*7n(I% zcA=-%w+pqOIy=$t{GiAvEH*mm%Ix%B@bb_D+vvm7wkG{ujJ1gy5cEeCHz_o9-OY)(A-m`!NQxKE(q!CnKj!FynHX> zk!waXsz3!(8afVltPJ3~CSuGDeia}(@a6Acq!>__WW!gp6#04#-porc@=RY@VJqv3 z%(bAg2=CIUUwht+II+m(@11Iyf*Mp7Ax1HrQ}$}d&TRcYD)QJy3AJ4kRvOv04%(l% z-69_*8^V(Oii_abn^mCYi<3-tH3sN|$}P>_rMFo?%aVx3(N2wrwg+met8Cvb8O1ULo%vJh-CzUr+zVAID%afgG!e zdsvzOh&fL=l3$Cch5|voXiUV{$002KYFxyM)t5P`lHDrV@ZoPVCARsdf3DRkef?eZ zy6h0Relo``&H##Z;}k`^-=cUFh+$*g#WXBQ z`@20lKy%GNZX9Zyo=q1}PEhInO;gUOJpL@AQuc8;Z)Y2bjv%6BzOix)+p_lSP%g}~ zS!r%Y!|wH~`d6&Ev`dV}g@S-eFm4$`IUZJnx;jdRbXrZVHg-P`q!B!eg@A;mkNJ}a zyHx!mdkiK6&DA^KhzP`wN&1eY3FHpYwo|*W3vU1wK30g=nREk_I?T)8+Ghk;dfzM=f?LzQ9^E>qTvJO~r3_2tP=nubo;oa#NVR3bj@LbnL!-1hBM_~&{ zk&npXA43@)W1*d+C{U*lCeOtl}!-Q$f&dRsf*NDbCz35Fc$JGozHDzf(5lCR@z zrbBy$3|#!4s@6bH%~ zPYS(u5?aKfg<}q|NOXtJ1*sn4Truv;j4GXLS?}>*Lk*aBqWu-@L^Ump6K z%P`IHy0;%FVOqqr$niI~4^7#e>{I3MXC?zPhm(aOf6<`*gEh(To_x?ysR0el zW+f*q*)!t~`nw~eT)M)%GxZrDP#8z22ANIY5ONfl<)&Pesn{1UR8e1?B^E($s)2ykrVN$oE_CLDOjb#=}sbYaU#QYNRb9I5_g*Ad!DO*`d%484Pp3X#DPLW> z4QoIg@;Eg$S|;|~e^$`n;e+BN-BZ_0my!-PP&Uw@AsgH`KVSav`>3Qd+}~jH`)V=q zlThFDq=z#<)t|LaYAnAr`*&!iWIb|xYDjP2UuKp2-@n!=L8Y)(rD1N;iMBBl^&Nj1 zWB;%;z*zrm_yg-(LAlkgU$U>EJ!hT;75Md>+DW#s_gF1hs9ivQ%82-I^ItFn=C*9A z6ghO~R>WQV!(YBHVcGHEqVI``%<3mOpyT5vB9OG^%}>_< zOH{X8h=F{UmipH(N!mD(qWnUcWBg73Q8Xo~;X*U47$sB#G7nF< z(8PC^9Ivbo{Bb7vHVaH*f|r$bAP9&=Jc+dXY)PMYI050c&Gzj0b*a~_RG`v0)LbfY z%C22x=ye4=-m!_#mBDAV4AKvd;Zed!>^PzSGQOl`Ks|}GsmU`7D4;s=h|HUxbhHo= zDixb_maD2zNt}LmbO?J-o0#bDv!9AhN9{Bxr8d8^j3VkCK->~ea!bv-u?xL9{5pP_ zro~7M3x`o_KyrUlcyLvz%dk_8U6BgGO6}Al)RFTtcee#$zD3yBjpb@ zyxMi6rYC~U=aUOJjlGw6E-91?j{+n87}4fQ{W9KPFg98Ej1v z4BVA=?-D#W5~D0pKRlgj_v~ez*$KK~jQw#ThE4}TO4bxHpiN0!j8KpbjB%t0Mo^L> zA&RaQQZAeO{6fm_-J?+%X36TFD8O_hWlJaP^odndBM)_})s?}9_)L_-%?JzH4UPtqGMeHL60VQ z0TLbA;4p_|Wp?~o2`D8z;iPg0X}Eh^JJD;I&z^bM+$zqR4v8>>+1Eg<^&99zF=#y4 zmX{fLfzMns{ciCGC*EF@nxKQ>Ga4Yy&cB9=92q#zwx&KE)Q>SMVDkmkzvE<{+>QS? zi6(O(B(?>P7H{kGR5Ju&&KQQAv(O|D>2L&I`@oEP0o4V7IXeZ}vKVx1sk={Nl*E2g zx936JGBlbF<%hqG1zB+*;{AXN$$5@6nglQ|mgwr)Xs_`clbbeYx0LRov}6_*7t$eKTbOjh`jo_WpfqRw@Z%cT29oKNQ&}-E=`C9 z*1)27Gozbe;Cl~jf+c-vNw<4p@ij?-O`Dk{?m*F#~$HB>^=KQSJM<^&cRgo~nG3 z5U~rZe)alq+8_@ad->*=hNtt)QLE2eX$O_&kkrrn0qu{41w3D~8dw3D<_kI6(oiKN>;66V|#U~^GO zQ=%V0?jcj{@kUzW9@MX?rp{hoiVE_j@KB9?VRo<*N|KXHM&et!2n>veQPtXm6`3R> zmicmHVAS5kuir#NX@r%xv+)ucA?(E47{={hSCTN0!koB04)txCNC^VI2Ef#NX(zeK zA>=p&JMKnP(%Er9<}|>KR(kTB#r0i5@@UMN$LYJh02?BF)U8BgH_@vm7F9#bDH|ap zG;raMyqREg%n`o|8{o8+MKjDB(_AUCAES>i8;;2AAOm>}z8P}Tobq&Xff?o`%#Q)} zBPUI~=Zjt^qa-tqre;bv!wvNX#K|Y^{{nPfU{T45pVJfl$Z^OTfW6C%8zj{r0*cv) zN0EVA637rT7>lraW_Wg`a&Xl!U3jyLn zTVSChQ*-N3UGh8an%+3Luie&F2H(?!k;q_O3iu!?*=;Y? zXF1kU3=+&tx=v0b?d@j=Ka9oJfX)|)U$4C43+agrhicK#Wc+=9pIK$v=a3qRxaOU+ zP5A-T82)5;dLiv{K8{2Om@ns@)STBaj5*Z~yTbfb^%yDdKZxbV-qx>5c9b}4kuN|$ zqbX~yu9-AiTxc)sN-y9k|$nF+w%=-1lE1#!* zfRrqlJ<;1`)}-L0lMi3d^z%Vi=&aj6w@bHv4nKCiM^4g)&%X@1yKpDfrx)Y&w&l&1aM@cdR|%o9CsM z5Wo}WE==+2ZCne^U+Ow5bR1|@gS-+B=pn}lFriVJNy_6iYsOvUWq?mX(pMoq`0}X` zA03a{9JCg!=T&JK3w%dkD4;U2QWaEbmJ2t!HG+VN)2PVES3;GB8#^vJA{ZrJ@x-a8r0su1UKF_^gCj^*(Zp&>_^y85> zeCGWb(;!)~@MY*3K$iC}UEi>o#)lACZ#%N73YaPNn9U9Ku?%K4G`U`iD7Ykh3}`J2 zJ6GsrWC-T3G2-WfPFE$w>8l1g<<$V=w3<3=9!l}L2LDR+tX;*M`)uPwEGe~$F{FdTc4oRDD!IXj;Ct{Hl*`ir|xQ0M!7?!}Hc z0cw!4lCD-w(3=N^UaTDIassg?7D+|+j16M%b&3tqnS_*JJNd~!FxQ%5Dp6}GI(Pu3 zcqP1B=f5K00hQE*fJb;3IQ!9$ptk{qZa#cK*nX02<9dyoLDfZOQ09C?Ekk5g#9U zgfB$*jq8y%}`&v&^>7aAO!wG;>L>0X~7co?koq15;`2&o#P zJXCIxDR2EKDxC1U+msGsfq{kmpJ|CuvAOOW@d zSKJhZk-O!BN|Q?+Y3h>q%hB>6H_?xC9O&7du>gw;&zSx6-Acj$XXRp(vWCduf8v&A zUFhVVb#;j#8Tns5q&be#gRcyED zpygyHetutQZ}{3G$;vDLbl}8;yO&}ms|q}_&sE*?mNJVI+#h3Hv31#5bV6(Y`WxH{ zl{Ow?7K`D7$mDe8Dtzj)YJ4UB3$&CK{L!#~%Y}U@h7eSSk}OUdyeyCR z$TVn{DXdX>%p6+w+F?GEG*KB>F7;+SSIRm!F%BM7eIQ?$s!VCZgJkOih*N4WzbGo3 z&u=HPuXiBN77OB{<E{SgH>>B>24qixSKpTl>*_1wQr7^22@Dis`EWXbu&o!xpRrQ(p(dmWD~7N@jWBQRU4tl1A^>3C0Epg$EG*$V0Fj`VzEQJ$1-F^ z(jcCu=ws9MBn^FDh-qG%!Uw}m|7q%7uIl42c`Z*yYx8W{qYf5&SCqV%^m{h*V(NO@ zVyyUbZ_c3JjnA(J4LQq{eC*ZAq5E)L2q4Aam)$14f$#4o@W4jz8Gdm54b2!J)W`f2 zzjwhIwEhG{F{S)d9h{`u2ts|Ma=;xWkG;9s^-+gBd25oi`E5j%eqFkn>n z&?QjEsFlN07)Wpcqn%6Sw4^%}I9^MLD`g2HX2l#Qbz~S48{?Qzp zNAk)WD1-0-tr+cXbp_kN^J(udT%F-4NagJ(=Y~jBgN5LiWwwbjVwGkuVnu3C$OnR? z=ebZ_Gm@Wo%*TdKr_3;7CowbyBt46P>FT>1+H<>&+T4qG4uE908E+H9FKeN!pK5wh z;>3l=fVXZ|$Sy2{MxDFluS|nwZjNI#l=JcIj|qpzH%X-ncEIt&7QaLXDpL`zj1rlUTDmL1;TO}n3; zWi?eYNBy)s1vPfhjHrywQmLWsE0qtWYwv!|JbNS&V#7RT!cf5RW%oj z{RvfWW>ljoX3W1>quf0m5u0u{K?U}}H}6Dnpt+DhphV$1!bdsQ2I^Tsx^?DZGp0vh zh4RMWAK}i~TP(gAiHo2A#Uz9*f5G_|u#~>LXGHjT+_>gwWu`?-`{h>QeOSGhpUXgv z4qOH0{s07D%)bAZj5*+H4>O#t&oCa0F=MVOc z*(ai!@O)U#n4w4qRw~>d>^5$9Se8>CSAv)3GP|Ma_dwwEfIx#?fc)$_%9rJV3tKKF zy;?_yLlB_Hm9FB*{mbSl#)kwx`=}Utf`z4`Ik&dt!3Oc zF&WXdamoACn8cu|G@bwnJwrPQKN!>+#d;&*rTj+noo4UXfj82zfHx=1)=@XZE3B^c zsTdY_K(&}asj-vQxf-C%C{CQ1Y;)!T^yLq!*-tgUMkgH^q;b3#lcnyI$6#BsiUa8c za4N0m#P=iV`%*Te2ZXFhQe#37BeyPhrl(05w$BNiY3dYx?DAGk)t-H$WRyY>ijf@` zQVD~A>Xm#Fk7d}u(0|GhSShnIbPO-J zmOPrS2a(5|r__;3r_O6)Kr;4SvA0{UsNurFN4J?4FG7eOVWZaK;Q>SaXYs?e`e3u5 zfO`y6rRtca_XszsF#f>O32S&94k~uf^&!853XTwc7~Y-MnFq~*&XHg@WITAF@owSm zw`|pwBq+m<$QO9p5@C4_x*iDGD3&`B>(Mtxe<&j!hC(zzso(8|aYhb2i#Qo^G=?7hYZrsmU zXm2(vf!=6sq;g4s>!=@k*G#v)ILplR?VFkY+3v_9q=IHG?`yL+dM96IyTq>KO@baR zj7Q;f*`W`40ZYz+8-jJrmNo5cAU-wk^ls6u+eDtU+;+s;7ozSAja}UzU=I|_3Zh#! zUM`yJz<1T}Xxf2S$I^yMGs9ahEpG=xq$y zD?EYdj3oq^U`bTJi?=>VB$(FGEr5eca!y4pT4n9ATbC%b3wC5EY_5FPjKUq=1qbd^ zQAfygV2IWSJzUEH=}U;Fq0=*Jj;PG(xCO9Q>kEL^{QUyJWLc2UYeZ#T=XqIPP6MJ} z7dzy$>Cz;+Vk9<`8JNw3AfKm1Z>uFB+FgyiS)0&Bh@V8H@*K7d+UMjxZl+wXz2Itr zETZC|l^aIUi%xqK0>0`&4f}40WEb8v&A!Q9+Guo9KlB5?;DY21kqUI;?`x3gE?NOx z88;NRdI`uHa%)*$m}~=*MvLgy2i#LU@>DFB>%xV1RKt^f)iuqU6Yc^RwIm16RjhCf ztlaN3)Fq7No@gHslc)wZWox^=(-u;?Gi?u7t*p?2k((tJw>8KW|Jbv||qr29&b za6?j3MLaNtQwDUL=nsg35ajBekG&8KBB+KPxK!c@-V{|_#`Vc?adKh=uLBzWlLy4q#yzI5v6R*wM*iY2r@9{QMpeKlc~oU zB&EO@JWYxmgy8SpWJU&a`@qSjq{zPpQOL|Ze4ij`jieNT=P?CyuWZOqm`kS+5a<^w zLwsk2+7k*rIBJX>hopumDl4AqG(d1?4fLN?ed zklink8D$bOU@Rw%K_GAbqMJm?a9iHC<0M>?>@;65vRiN^U%y!P=@od4SQ1y?Oh^m| zmTao%q`+BaDi@l}iD2gD+%e^|G}~9{#L1N@?T36{!B&n1gxnAFN?c+k9bZa%%#eGCS;752 z8X+|4aeLf$n4EPZ+;Uc&Af;xyyCJ65p`4h(x-&v8gZH1ev-Y8X56+lvw|Y~P6I!+# zS!*5DvK!TD9c>CWuE&e+FvONY_i7$cDpffc&xi(A>EiCi-?2%c*-QJ1Dc0T_+CmUe?5(OD*cknoZ7g2@y$jSKOZZi|m93o9sKbc@4wtgk^c0`}w`4)yyjeh_XLq z=?heCi*z{`8Ex|o_lsTj@2gHMrfZZ&?zeh%6?*Ky&bKWq3&V$-eoNBCc9fJFHatHO6Hnpk; zZ%q%BL=Nht?HYUz8p}%G1|Bq(*%EG{5S<1n+uK!p+;46(f&z5iu1;0C> zWdXJH*2V7i#K9kETvq*d?RP3NM^LDikYt78__^gu6$cd!b{%qu-SoD_s)s$Md!TOk z{WJuFBA z3zu@~;V3S*85W#)tAnK-jjJAUe+Ws@j)IR5ABjBdo7f-IJ({jc=rKK-834D`q7c@@ zncFLdCb)>U4it6|OV7AwYmY{;o-KA(R$YpZyP#6mcQEA!PBfr_OU0)aBo}bY|L8qh zt36!2bG&XyffkGcY&plqK&1?S#?c)}9V|}x^=K;gZ~=V0^SylC<@n8Hm-?f4j|xL?s*itUL0I2}># zbs~BCFn;EgEc2wfw(7ml1AO0Va^Hucnx7~iziHm!QvU2j7UfK1WKC6GL-xvH_Oxh}D^?k`;TA0<+iTaE6G3>FPVUL6lcTCNcG3WX^&U63rHqXa^ojnlezJ$7R&!fhf>`r0wRIN8Y?%vlK9|*ZxCq%v4(3nza9*dD= z5-z%)k&Rn@k-cJ;oiCBSfE72$X9Rm-KRxQV}zy?$o55x@7P#NeVN+V zc#UD>*5`x>i^8X~Rz9*NKWHa|h;T<)D$vv^DC(<+?9WJ%+noVp>Zy+A0yMO9XKgx~ zA3_bUx84p4rDj9DGZ@)5ztjcIbFS{xOm3M0W zMd?}BU*$Ec#9n>PM8SCP6v;Rf4eSCsEKDR|VhB#n zhO_yNNil{Kzm&%PcC%|3jnT~5ndn4NSQw;MS;XKfPA9k>Ccjh960L)ExvfQw@ms!^ z1Wt|jpQlE53%p=W@zS`IK*|kH3k+=!qQc`_`uwJ=#Ca7Fd6(KHtCE0P4ZPLF+g0gz z{^Qj68ESDk`D^WE4_4m25)b-bZ-s9)5+q7)xyw<%Cz>zq-ZVGXAvIEnllsMthHSr` z%qERmG!elv^Fp`TgBx-xk?(sg;LaN*ShWR%O&1ygNaGjIs!JsP}yy+KmuN?sftIm zp-(V$CxfGSa=ymtzVo{|UCx}9ch*zbJ6xBD9iRKZi! zFVD25^b@DMu4FS4VwYh@o{(JvwO`WDzT>IX@hM zV`EbUGQ`DXHC2q|C<09ZaMbL!X)Rdj+I$k8Y3IC4m!;a@Y{q|G=!#`?TNuzIat%dC z%@v1-ytIAMLv8VbuGMrDnlFCZflaD@HUjHXZqjff*Z0vb4sl3z?d4FDR^$Z8yh}yVA=M>Ib{b29PSh- zRaDtxq>e+xtlbczVef1}bx;3O&mBFPPap1vWtn6Co?uM>=b`Et#PcguRkMnJg=#fg z-Cv<<#F@nTu-3l$@UKv1!?jWbLRIsxP>s7I|Jfuc{DnZ7;kU-AlF3}!8CSC zje(r)fs6ZN)uuSQ0;!{VxI%|#{-PZ-<%=a!n*-n2j#nB;?I)%WcJfbF^N^Sa)l|nT zZ*eV#<_A+cKbbWJazB6fq!N)lKJnSZA77+Qn?|5zJ<8IZR?JdM>qYF{g`T&*!$NL- zDQ{-6M_=US#D9GtRqxjqY&6MMhVIg+%+E`i_cXhdh#{p28RVw#d6r)l#~QuS)BoiP zXV{ELUINI16g8UBt5;vK*m&krr`(O;?whF__WnA zhot6K{b>EhOjN0bFq10y;zDNIJGTHjVOLA3i`F9qLuc^8>O;c^6PdE^+Y?%yyR?ejpA#?75#ilf%f1n~JKE}I-forQ2Npk5f&`Z)#!|jqGE-o< z4wyvM_(YeCMtxW)5d~e|CGLB?x@8(COx&(+qWHR~F4k;JJ|INoP+yHmkXTt{O@&AD z)9~ZXxjK0)up58eqf4sIfC%9opkrkH?cV5px^VGf=+RVN1ggw;mRE$-_+~`VTM)Pt zyL}2h4*HTezDQTkGB+yyu+SNSozX7amoPkCZ-M=4%5_x4xbPGSK3@t_q`p(}XkG=9 zWgI5FE>M6@z)@YJATrUUjLd)c5MqOydq>iyRFZ{bN;wPS$q6sA-P?OzSxb0Rrd-2A zGgbE1qXqtZh{U0=0pA!#K-T{faX(}|rp?#Q;OgAiAF_UGygE0Ej7Q%-t(vLeNgNtm zWRkW@F35WQ{cHVxRhA|ZHtB&v?X#dp-*cD!rSv*O1`_@!DPOPi7F#`K5;>)Cm59c2 zNy8{$E%mmOCCc~Y1a+s&)GBmrG_w}m_on3(t%J!IAf4#>{iZ)_KaA{IZ3Lb}++U6_v^i=pM#eJ}(dQ9;{2-QcbP)_RIET7oMKJD! zk32qS4rI^+HTS#%eMc1`f}T&AnZQU{o7UVd3@~#DXIo1^OyNn|U?z>PJtkUO?&4k8 zV@ss5gmiwu#Wtie${j}d^jnM`;CRgrzN@eIa4;C==7xmFCG)^Oc@Zd6*vWnTqav?B zcR;+STZzMgFq#XqFvYgw6yM7^wO1jh;(^nVh9=1f%E90QMbV?u^IvpxXx76=y*ydrbI#y^i*)QUK@{-fw3*icc7ZDcA<&*SUqeQt# z5%$@nE0hddN%L(BnVotiIc83GPjq@Nscj6HrF@D@Hww+b8rAawLnXfRhlyujE)JKY zd~SB?Fy{)FI%JRNpQi~&);TPbMS!55)yqWG5OJ~uldjz{0gy*udxoI?NIZ^&!l(YU z`{``V1O?l{p?I>r)>6*v%o=YtTYT10543p=>TXN-o_b0LCpz3L)I5SqWQsW(h*jU3 zq@Jv_`Fys17C=DV!tQ%ZX2G6FNDoz^%?f_U#w`)aH|w`KEPOh3KHxL#ex+}6ORSp9 zdgtPk60%JmMH+HRWw!8GMg0>I{Sj4ot~TyVil!D_VSOIQyjnjg z#dG7ue>X{0wSO~E$3Hg$w$`0M2!V*G#j%cTZOUUM;UpD@+hyz)fV{re#d6%b)xjU! zP))|bn$tpek^)$%G7Wgt;kkn6jQ5bN=gMY;P!H&%*BL2>>B)rD%3bELV)+_CEggPM zRHRmE{vk;U$75l|BGq=dnpaJ>*zH5;N}`c&%2Fa?1`-msJOLg3tQlhyBhX>>+J07x zubWx9<vf+XaMdh2uc#Dr`XB-w3F~ zk;1^qfBE!2^1L7C8y`zLp+I5oLrI!v>MFf7VO)I9wM?-#;`^8R7r@1{*5Go#d)ZWEL z09HK5usUKOh-SyJRZq(wdgt>)IX^ndd6dYZQYAn4lCITLJP6mHP3i7P7NsZdAu#VX zmj47Na!x#XA3IvD+~IS3ZM0H}QcMo>?gnX{g?0KKja_``>pGifMQeL+Ika;{jyW3*W$f8N8yGVUAyhGEXmv8EBppdDPZj; zo}zueGsTdxe$eY~WAGua;EsG-i@WMvtxa670$FX(N_rwL8A>0G0eA~sd!lZ;F=fUAK;*lt{zcntYtJ!8gme50k(VpM?=|L(d`U6{($pFJP>>HJo{hmHu#!I` zF@}a%;Spf_R7L`VJ@FvsEPGWP!OOI|e%35@Q)Lzj+m{Nkb!&tj0H+Vlhzp5;XYDPktQEMR-zV-;nM}7Cki+axXJuA1zhO){Wu3WS_3ouLEO7 zO_ytyS|D>+Xl4$z>!0>uvCz&Q={HGj?-XXv9vim8E~~a^=T3~-b{$p?I$7gkS5G3QAkQJ=-b!mKui5)%w-Zq_P+3_>!=oEz*DFXYmNSmc1k$@)Vn5f-dvoSo%5Z_(W4#zInD zZ;qGCQwf2>E$ zN6?=%+A^oS-o1;@hEZ&=G{;ClmrF$Y)iZyf++w^?kap%H`pi(pBhOHnPD3oIRqOP- z)HlsAk9@I;l|>(~!yo}k=sUJieSY)#mEqf`TE%Ei`*38Em7 z7lDhsX=wR!fb}g18+v)chicAdYyy;i(DqlF-*4XL*fXf35ka#)r^E|iOK!FY=}}+P z02iAu;zCby?~O#>ujQW#i_Bx&2*!4I%J;h5N-Ka~E29@!W)91M)ie9f6?uRSl!Y%N zhOkYQNn*9{B7)aG_M?N%n~{K4IPFOEgGqH^Pq-T^h>h_wX6vw3k1N6^?8iE=@5q3u zm`MX})XW4V^ZHo>o~tPdC);;MF!JoKA;<S!bSNSWLcWq&4NA~Ba~{!y3f z-Sc5A4EJgrBo9fGz5tK>tdS8%yvBNr3?uS9TBqJ-f&g+@-xcd=Sa@m?{f0iJv!;(V zbJw1hDYcN%5THkn-H5atl_A_DL<(5Ge4z+#s;8q^rE7P$K}!YCJb0J2;rQ(lSi>Rw z_ZNvA_5T4z6#rG>=~w*?Bg+4(@K%4q2>qsx>9!v!71Nf8dL#?mlM_g(rIYzj5^UAK z#J!#@kuIVs)Sdn~od@t74ckjQps>Ss;kLV?TL==c-Yp!MIb1}t@%d4G&I=3=6o8l$ z*E~E4#eI{}(B|7YQf)O;@ra*w_YEP9hBazXlIc1Qtj)(=wrI{_1_@@YtV@04{@(YH z?8se3D(k(2GwB2|Dz}j+Z?W8qkPOo`EZgff19YrInpU61tfsN?^|>~WWYS`k#N!+R z9K*$yTS18EK%?KXn|zv6rw+`+Msb&zq;$E>gzk<5uOLwlE7m%NzBFb-7(g`Rk%SyxOe68j(8(db1>%0w zC*w=^6v+h4T}Op($56I4lohU#jAuiW(Rd6rjB<%m;0q-9tPfq5=4eV{5X%7P!;TFD zGhZAuS^l*IX4_m{zHYrg@TG2>N+hJtu8c@Ff*evOvJ(2m!^u`e(yS0a>J`Z9QWohj z4uv;vipq;N>W@P4Ah4{^H-(m$Ag_9$h&fe%X_U7SqlMJh2z6D0UG|xc!VcQeN6Tz- zoQ7ehFJBwQ0!xa}z{`bQgra*g1+v1cSt?6%bpB|uBK3aNWX-QAm;>=_h!K6%Y+3Q0 zt+pI)rybBwzIN&uMSv|0_3@j$BTa!zb4baieC|j=}@5fy%_kb_`NLqQT!TS{VaZW+LF0h-bd@yeN;$!ga19pQ@`;Rng6vsp3EcikPcv&qm6vQ#`DXrZnd z#6*f~p1gYGJl7NRr~ic{3#LyR%h(MFxe{s76@3o7(O8OJ4IqN`V|n+-eK3C)ZnO27=a${f@K)bmA9oDA$!%6BarnARSbfNXY9#@0)FD?v=^5oAuqkw zMJ6?{io_Ys6f2vIqMneao2gmJ+Ds8Ha=8pv?Jsnp>y)KWJCua|WY$}v(;-{CnmW16-7m)Wk;@!gr@eUpFXrB*7kKH-!ApKWtCmlSWRw>Ds(!uKcj@Dg*VRxJ)0ExB#{ z{_fARQ*KXjA}!dTeZH3D~vRwVXfF!(Vd z0`NAZb3vnBlQieNaJ0x#$DP^}CrQp2cLAn> z5H$H|56hX+UaM9;Zrd-dmN$Yt;24_t>`7qs-jaODA!IRWcgf;<#M?P9^`z|&Bq=K$ zz824Nca-}WyYDGijLAw%`WMEuYUQrfQJdHCOg$0!YEhl;JJd}*y`(Dp^`|P7VZ92H#-@Y|VK^1nJ8r=U@E<7?{ z>v+2FKUvWwm1NDdIIq{x;b(DiIaCls0d`xH6uPW1`+$S~ZBvq5B>)gCUvEAnI{>&q z7R$ndQ7$yN`-+HwCrh~}m>lwCK4f>ffY1=#T^T1_iDRoXg6yg!-zEg+P7UGRXEcMI zGOC&(g!4-`A18jI$~KM0(ZNZO77AyM<>0$ndLahJvWQlr@ZNeXyJO9yrew*=l5Cce zZjsph_VadzDaCaM_P4ygc5J#rl#kv9rWD)p?i0!(teMteImo59S_ErWbwWo9*YkKv z0}sr3B6hzQl;EIl2YzBKs4TJ(hEK-S{m>;YFr3?I`(!B zVw2Xq`%o^nWP{VxC6Fc)|1F0x& z1w0*dfPUo1X!Lx^S?*#nNX|7{vGLOpZ7wouP63ysyj?l`3>1WR@i9>R?ZyeM_ih2 zg1fNaH{IuN%$%1Zw>byIdC7<#&jWCM$=1k)gRH`Mz&X$Yy; zS0gFC#wKE*K*u6AaB*)YOF>{46^CA+kP(3eQ3je^R`RTKF8Cg)I@mL7=P`tI;f!eL zElYKZG(0&JW-qiqB_jo{+b8jv0x>!x9$kh{hA1EmS;;gTBN%a@=X1b!;&e(P_aV;v zrrcx`f8H^ie7~Pf&H_b|!Lfjxbh;|Gf*?rv8iFQ}5ujKqe&RvTslDfnjUj2Jn>bv+P~v3`1uMJJi@Oo#82`qFXFv);YdKD7d+Ttu9l zLQB%e2m%It*1~a{V_c5s6IBWsx#9e-MN)dbq4RBPUFBo@(@(Xo z1^TTdZey3eV&u499&hW#9qYjk!Jv+=MiGCOu??w2?pMP(t!@*%1u;+zQ_n!UWxq`V zk<&i42(z2%&?$3@>@jR$df>blhi=Rm4|;BFr9!6h6&)v>D3q1ShR#}534lZa6F4dX z=PR}Z&DE%2b_DxOB-!^mB->T{JsC|5f8t?x5!?$n7*^J&A1|>osmKT>OUekxfl*ro ztMN=D*)>gHvp6Yy-`s|B1j^DU=PaF%CSY2uMca0|4Jdp=$Yf^iiZ|D$on_W6-+JdZll2=o-17|xgxoWUOl zookK{Wy@5bcpB8JUK_!xoz`L$5AhQpjJoP`8-*SMVAhhlDSy;-aHNjPKSTZD%4?1B zwa)viKNRZj1=^6vgd}nTJ2{yDrA(x8%~5sZc)Z5lU}CghY>o>%VuEj2Tu!(}BckLr zn7~8@2n-5KP*VLatD~m)cB-`dxr+UqS|`0sniUvN%Uh&H;s-6vm)_pLe3#F%OMEH!UqG_@W@>4Oe3MM>_UANC6b z*t(DWsn!P^*wNv$ean*-n13Tg|LWzll{UYoleVr)lZ%;&lG$%{LP~}$&btC6-vSPE zoUJ}oyv_VDqKMh$N}4%S2XIx7=2q+5@r~eIJg$wMq61g0;QL-z*0Sx2y1q_cXZjjx zyMevi{D(_jLm1zRPDh2WW%yD3|Cs+^09zC>PXGm%N8~ssc{;UO5O+3Lrw|>6`e7M5V89#*<{%^m zft3;IeY6a`GRX-CLv=W@7|*5@VT~e;2uE5OM!2J<<|PsjbGm6;iX$LT5w=iR4bV~0 z#;|aP{zsD_2CsFaa9x+zK`&;f&`0^hL1+=eRk8?k4+bZ2rj38S>u4q`;^hJ?azt%3 zR8jrrW3mJsp^j_shOP)^Nmp<~V_wMZ0_+1>qzcq*pF{VtgE&(VxE-cH-5(R|)C^R+ zo})>Q7ZnN)WV_geovRbsG!!%$>%C5Z{#OH6Ip-hOOtn^U&FU6Jh@e6aASB z7(ssUP%=;Zzc5iQ$Ldc^G{jbk_5%~uR{V;v1F1o$bMuj4Q6#578xUd9KO*c)-JV)0 zj@p>^>j*ZDSDJ5VZ`*o71gk_?dJL1eG@`gqtKKJk-|!o z*sX^1q1-Z?fWZf%Z@w$uWvl}-Ug${NVw4E&QX@ZSNkfDcTZ~tzm|gWp;05y3Z%u?8 z(zRLvI(tK1=#6zrLV--8Cy~*6zv~^9NtGKT7QgF5%r;LYqsAAselMQk>U_Y`zuNkC zJK1nJ5Ai;i^dI{)O4j7K;S>8ORh7<3_hOhw_+g=5n@8)jcsR@HnE4%F4UvTKXE|Th zq{vldis&>HDm^=?59UaRvEGcY1@f=r*U`K3xDkgxOLp4r)XdwyPA3G|&IqgtMJt_D zvG5`e6gX!|Y3g%yX&QYCbP13c-rCe~v`@R62Da-@)|Dx0KaE1G7;)xeVV&n@NpK+z z>V(TNw7b#Zq+aG!CA8OC+JQB$M7%;BS6EC|T=V9sq0Kj$AV?ufsK{jidao6=HOUBc zz@ojBO%Fc{G^dbRw>C&{b;$2s||e+_4{vl_D*A?xz;P7|fn9A?2ZJ z3z>S!HU|uNwT`GM!LBMupLn7*6Nd=*PfN_fvY_#=RigkS3;onDBTIn-_?}pc8N*8T zq@w6S+Pw&jQ8aSyXa-{v5L0kr0$MIaXit(Mk})uhQlMUBI~@~nxU}1LO3mOf044&w zJ2SXP){ausPHDtZEH!^Lp!rSr>}hIz>QyoM>V)+>V!Hf2N`JYO{;l67sPr$t%ToDY zh$*P*Z^Tsn)9;f0m*1roo9k!E_qX3A?zfUpZkltZLaNdBaNy$L2VzqF_Hp`9tsdK^ zPfG5pOs5i4&3u>fS^^-RmmZ(lz(MQy0t+i4!|Sb9%E|Miuyya-(|I#PUN40QaMqpbG>nrHT#`WN^N^?Vm*qB+&m?_C$ zO}WMiYU<8D72CDijYJh{H{jEorM#^zYanXbU|PxIP_gA;!IN)Xbbq>~nsp$p#ob-^A2lf{ z+W(CYb@Pk9)8*2m`P&?E=chR$4>N+I2#0J>IqhjW zy?dF2&6KCYYu%U(jVEFFVCLt2V{Vx)EH zI9jtNtq3}+bF`2xW1sS7+dRCMo|iH^=CGr?lPZyqhh@WzX|XK5Jc#J1aMGI7_a^0-ASX zjFhOu^fQWbAP88;{wphx8WsHnK^&F8Ku`tSFA((qkQHnw zC(;J1D|ISuNG3ijGxa>Cq!wx_)xC01VH23pt*DpJ5VRd~Lq6(gIMpg8@0pNsmIvPW z+)wl8p_tVc70S+$?&}uIt?nZMbm-WlIaNd+4=CLeG%@l#uLIy|ym`@0zVlA6JR&_W zskQRU?7g(tw}rN~2%acpnxf@s4CcrVMR`=MTrQQaJ1qO*d+qw2?PMFR)Zfeyy<8hM zvl`anx7?WHH}YtC)~JEmyL3LnN{w+9;6B%UnSxaPRyPFuXuLlA80_Ub8gOTUE&0iH zp_&vHgM0u;bVq78CHx7K7ZG%j7#z;A(~YqawJ#g;>iK22n-XkqX)`8jVY^5Iw;=%V z8yrTX<8yC9fh&@SfKHd8${bvVQP(fNQzDrpjXs3@yF?dY9^<7_vb2oYQL!`8d6nY! zlKf+~>yA2`KcXYeO4S4FpD&{L|K)(A(|{gU5I+BRQ4;Q-;v~@A6_CHdG?bB_J$}kx zqYV=0GgGLn97^4X?C>|hms zV_gVi+W>#LW*`m!+Qf%gh0q%FR4icOk{Oon^+b`konVztlz_FiKGo+{U{BKe%WwC= z64;cqVq;DTd3)_I;`s|jR60-%+x#}aXO(XT=bIE)ulZQUEbzfol&tgKa_I_K1{*RF zaxd6pT74O_c$fNMwaxcX$e$`LaH!F{JF0FFNB5J)>hK{zf_O6O9MAUMZ}BS3B*>O*Lh(;6d7*>u9RbMEwT`i8CmVFBT;GIqh zna6eXF~!)m+;--uIKWU!cap>dlRl_^-tGw6ZiDoVKIcs%sQsE0QESSjK7maj(wd zUO8FjrW~E-^ME84j3)-m3ZK9;z`^a=q^0aP?dX|=4C-f!u<8*{S9liUMw-z%Tx(q+)o0R10^aR#8C|gFh|HoCnUZs-!@67_ke|-!_ zP;P%ok6%tXr}f7_4AO-r1V0VZrp$?md`TLC-k%2Pe(%e*>__XL?lpP;Y!ee2zDwr5 zH{tcmAdPn%Jny5@_>N-Y>jbd zWK2fG?m~sdbdJT(HnHSz)kQ{K<>))3gYU~xn!Lk}$nyafd950QUav-%kSuM!jrXB3 zx<_+!wbM1`bVNH*Iv4AsAqsX_3*HARW6zc9fXN-(-{vpufnV|8Ly>!|P?;KVR|rqN z8~Sx6Fu<|eZV`nj0IEz%@|M%is-Lamk-F5_t@cD#HCFxCgg^7>`$W$X0FOavefBu& zIaCUsa6F%L0<$Q+QV0?&ay|#FV{Gn%iR#Jg(-pc=E=6-pa_KLzpT zo__Ct_kqrkp(FUf{r1lkrB!#|)j7X8eLWvsA=*D`f=a6Hi8$J~-$}t%G8DEP$weQ9 zwVSsax+(7wOOb211t|$A@@h-LgWIN}@aXIV!XTICn+VE!rX~uwQS;a^Y|QVJI3#(V zl#oJWd<<3a+V7kwJSxwE7S58*K5v}7ETMpfqj4%9Bem8yuRKw+yJ?P9si}pa7I!5Q z5e_XiON8#9GRLPdT`47NS*Dw5ic)+mGEuIjVoe4ZiMcOM*$s<@Bd%m|mTrDO3!K3` zNJ)s=&v@6o+@RPh%aSL(m=L(>R7tc2ga`*aCMA`o`3lK>499c_ZiP6Tx)%q%QBFi7 za2aQ@#2nu>zZY8qJ`>C)9WDeE{b6ZcG@g?V|HwlI=6dAAO&N)U6!(|xXtWW`U>O?4 zc0mJN9^)jm25dgOeKgLILEYF+l;)T{j}JBP;SLghT~KF<94to8H6 zpFIDtU_}0&-~T(jVSN50@aVgwM4f92JEC!=*3v)J77eCczmMRRCAC2O7|Z#Q-$%Sx zEGM{Z)EE`B#S+oTAycN~FPK3$*p5`_zIK7_k#o#>>OGjqH96y$ zsk6bG*j0uH^-XxKI?*2{(M1v&`FO{=DJ65dS}4M-82Vn4`k`ty2r z7`;T|#D45_oRPu*Y|1Pbc|L_c;sg15tsTI&o5#TK&uE$#5;0ek7StD!3oM2!bRB(& zAAX9oCY3R!_r-4(P7bq^dZ-9=nAi0%9o^1{Ipv+TX`?6Mz~I6ZJ6Hxhug^LVDds^r zWMKRpJG#8U1NAY~eJte1*hJnjgXlc!pe#e3GTf z_1h0Yx~#(s{JJWt>MTB&k~CgIliR>%#GGMH+8ODi%wjsI*KNIET?1h?D=4y(Z+d<9 z(_;m|-aLolMQvFcCG1&cr68$Gso1$3<4Ti3HZl2e6`Y4DXW zC;h=EpQd#qv;m>ZVQ&8z&rSq%0pQZCn|6kqG*}b(dmQxil ziBK5~f7I6?;NBnhpQg4KZHlckpYnjafVu(Y(@;fk{l|;E zd^eIFy*BT)6sFt3D<%5Y8HnVXH@4DBqvc5Ne30ZbU?$C4Jg z64Is$uMo-Gi;k)@Iy%&i$Pfi<+mA4@v8=Y-(D4n~*8rL%U86XIas zLZfI2*-7$%*rRN}RLF@h6fp;G*h$v5?YA&B6vEuW8U$S3l<%k0&;+gnHZhZ79M|;Mv^A#}o$AGNNIoPbfneWWY+WE*SuOlV8+~z{c06 zI`}VJ8ww&`GspxCc}hOFEhOaF5*mH{0TA_Uo6%ozz%P1w$(*Ggl%$p#7^VM}neHt!71u_NM= zWvH%;Bc)Il{3uNCY5`|wqAUoD%I!LUZrV`$1lzcKI3n|bgTAP5*Gy_}TkE@6qAp@# zB^bsX_EFf)e8Z~8@uli0vJJSB0)bqQ-}Ph7Qzsr;$7uEBs3K zmyBL_Gas3lE{ptsr_7_f;oPQ#Iu)~dqU1I)nge)`<{aW&Jphw zn3MQvZzt96Xx`#gIP1W+v>_p8azPv)8Her*xl8jGzkf5%|J~95SEc^Lzdav+mHO3z ze|tV&6%+nEdM4dpN3W|i8Jb1)A09Ir^^EwR9y7%vTOgH}>I%AC?p@l=RHMKCexQ3r zr(J)ae4@H9(O$37%ErFWX(KlrpVqqYnm>X!mGH1&TB=*O*P^4?xQmBDAPXJSb5gh}(wHP?W`6Jktx=n!jcT<*cCs|C?e$o) z>_g??oEO)jdGgMzK()6V{}3Jfgub4rtL^>mQM>F4RHYiWU^e?CIF{gzDMW8E@2Rlw zPP>da_xB1suFWO0VQhgW;vV5^>#nP4%Wvk8z?Wd+KRfc`)1opZpAHSKS0m!4wI7pr8QkNg1a8*hj}?)LbdA;H zpAkt4b#(`1CfJ&31UA~vnkG04Y>G|2)VESfR1ox-5kH-uRHTX5XTy<0v@j0C*2Mwd z?6n~aq97HqnTdfE#shb;&20?9Rzb4L*h9=(Jy;Ckr*Of#b!)H#pFuw6q*jUPA_ zPe;K{?SF7X`|2U#DeG~o^lsF|GGLIe9q^L@8`BLfB3t>1Ag@7p!g)@%&WCZxKT{`# z)<}_zz^=_DsNtB>fYI!#Pr@`UGoXY^B|~TyPh?H~4kw&P-2`7`zaH=-tv0!I+Eib$ z9f)&my<1b~@mmX~3nmWy@R)&1)3Nv(%rg69;0?{-VkJbY^U>>&*D+2#Zzp?{LhmQ{ ztSV+b?89E9`YlC~p#S$s>R-fy6!jOec#c8&vAZV`B*^o1?dX^5wqo`P#y}LOmPh8V zcFOu*jrX~+VhDo=n!y)E;O;)mI9B z&W8wW@aaFLu!ECOOOAbxXOajZR57sci{D^~Aq*~wtvt{Si<0Z&%pMaMqT|iq_FZb(bb5Ks7Ah+nVKYI3ZR>Ub6x`D zjRN`Ia0yQy`94iOu$y)kY*n3P1-MKOHOAw5sxDTzC7vlT(*Du*#*1rZwM;3VF=bhS zwN|xJ*j2PdIOq%aHkoe^dHR+Vn>{ZaOLy+mfY9mEWDF^7))k$zq-xzZTwv{|o545_ zZ+y2;8q@Yzcq&?_rJo*{PymdRv_ISoZbB_y1#yCoG(fjd@&9o49&Sx`+q!o`NoXnbE}=+MF!WFjO#vyP2?%JAUKEfb zRYOZc550=?u7swDpdg|spaB5^0g)ykVgM1a<;3@0>$~2y_u1z=*ZBu>C7JV?&m8yo z-S?Pv|BGqZTT!+v-kh`zR&a+Z%W-UON-z9r;(ew^I;mK8VOAT`HNU~lglmHEbR+QP zKQBvwN0N6%9_dy}+2WncJkSFkM_=8C{#|mSt9Pv$T2Gws_P<+V|FC;p`#&V>Q~zz> z{qG4E)PsK$E_+M=B3z8T|3$d?pOqeb@rQ5``8VO>41TsYnySgUy(Oqhw>9vc4w%M% z#g5-RSE6!n7?;4LHVtF=7+&26K0y6-hL18hu?MS=G~Sa zZ7K-VPap0HYx=5>JTIggTI+eC(7zulsO+uipATB&q1kw>FEZS@&}*RZ=}^A0z~8l( z=~g|xt^233XX@@HZ^rh-A5tfqqexfE_ILN&oZ)vnB185BZ`VOal3&!@8pggGoYe?? z|9g`5iTAMWZuIW7u`ozMG}KF!T&1pqG~<;Cn3|V-|F)zzEF}h`4~|Q-&D3=K8FIn% zUF2#!i|6`tF@3q}IQnJD11<>R5^#rU2T;h^phjNR(!^DWR6OGI^xjJ_YuF$7+a&u5 z@xs_yx5OVc^#kDK9`{TsQ7I_~DT6E57&0t2P?Tg{KBj7tkx&B>Q+Co+FxfcILn4#A z(ZnRRj3=1_E~eBcvzTACp9r{A=}2J>Z+3sJEG%UQR8-mjU{DeeJSYeeV_8qS@c@ab zw@|eMzM>azt#Nj$F1D|=F3NU!X1L6(81R<_R3@L;n&7rLUQugp10I`}%v2}AiIpsB z)QKF30q(cQG&oVoR*1MqO-oCXPe~h#y?>w^?TB^9?id!^T8k1?*mhd|@inV* zO=qaW^q$XXxmm%c&t|B!T?13Y`QGnYc!yf!*sB(PWJ3_A+^bDgmiXWV+5S%UaTCJ{ zq={#maXTMmx`_M2ErT#^H5a|qBd+%kWfWh5yMiljP}i5<=|t>3(oDre7kb@=$pY!6 zcISp)9w%(Tcls^6quzzu3F_vrKIXQ4JTF{locI=6%JmpY7Fl zlBDGi)HzGheA{75q#=EV((*#2`FFW!&zSM9PgKQQ-8)s7oKsepNVc3 zU$&FMyaHGE>&jw**JiKNZRe+rt;|2!)GPoj&--=a&u z>AAl}7ptdP8Z9-$1qxqcC4I-GUM9*c^d$WCiu$q^%WeH;ZSuxfi8k`DR>Yp#u6tg$vO zP%??2^$OLRGC^eS;#U1M!u{WHUvv%Cta~j4;S8Q$-TS6FsueRoeaBO~gVB}q^>*?b z8~ryrk(>x@=>4vUL@ATv=i9sw7tIN0GNQ(?CJL9;lF5$bJEB>4-VQ2oljju(_eAEfHV2gRM%Al`dC2sH2zO9 zk}tI9JxCUM&zOj!7^bpGpvsY|ZL;oo7s6629v6}+?aAU(6wZ7xFHYeg;LWh^kPaE5 z)6zVUag6WY^Cc&V<^oIgJrm`A<$aXoYx975*}2Rj`#7i$-Iei-sd%F5mCjp_^7B}U zp6lm>jb1Tk@Czf_Y<0WssH-?kRA)c(Xi?GvtQg@&zu*WQt);kK`)Cg?#&KsT3jf^e zS6K?B_j+&YZR9#@b&;MJu{sqqK!W=<8=QlTi|6aSlQviCbGbY=lU%YkCmZ#;K~cQT zSkOOWB_jWat?}PrkpFkj&{%@1RsbF1kVuCKw|VJSnr_> z-g%CwCYx;TpTN}dY5s1Pd7Z(MAosF)`1%)mPi0h|;_Bz%Go2s-|JC&NAW)y*zC8BR zTKc@MR|>QIm7m;S`gsEHhP9uUX13#}xu7=kVP7wgXQ+6Pw=O4azxU<*T_s*}@5)%1 zskU0}3pYX6-YEUYlgA^>;s*T*zcqyJ+s3}O45h*C56gO^s6W{}S1vlM z9Q5)>Tpb#)J$Q6Q_ukf4M|vi4`&jf*_(zcnnA)k|2cJIOBD^`IiYMd@_X@f7 zNh%y>cg6Wd!mTxPpQNdd%VHB1pVWy&m~X|FW40phEWkgX z{?7mV#R)Y0S5n8dx!QlrD{cRVY?}VaD*?$Pe=CJOAN~GEU&a3b+4u_5YwW$hAse)u zM8bOxRTk-q67i%3h+JcSFT2Cp6up7-4-iZv0&N!^86+)4DF(D-96S5IFwIE zs=r)F`A{!>leTXE<$X_J3fZT@fSe#5xmU0Gf-IiW8AXqVK&7j7X6(@2OO`^yMn)9S zy*WmhIBtwYH&FFeB?EtIu8QIIDe-Ug=_xftk?p{wwZFwcGD9{&s!4+ECRO{ z&2>MgNxn*7D%{J^y<6?$5Ha}cdMOHP~^hG{GAD{EqDz=D%xa^F;%Y2ZNetu>)TRy=EFQ9A*@YLF%7+ z?_!H*iY)V7Bl#T*rKe_&v_lo*nReN=f3mNOdo zyH2i6iu&AYbI0>@%5?s@{I2!v=-dab-wQr>Uw!dUDeukywAcQ-p3^d*{I{N?EF#YN zmnw}+_!qjdS62N;&j~R7H@X34{f_{nOh5DQfq#2=)J!_%ZJW`ZSC3Cm%1@JxpJ&(j zecO7|;pZSjjJ$X1Qagmn6?Ie#E9LH&FmI*12sIu>ExfG8mTDF{8v zNe{#2uw%W z3nn31aeKS+D%;DDPy>-q)5~V6hoOf2`eLZ6Qf}ct$rilyWQ$mWI`d=})2%)k)TK49 zJSZ={#?r~tDWvu{kH&CYR8+7rPnIx-QCY)xn+HIixn>Nnb=HVsn9Q6#h@hV8;h#tf~`9qq3)Dv3ctCCQIU zo;()#wfqEZIZej^nl~P{IRCn;_Lrz*;K~jbC~(nECdhWW=h<&#M6^eyo?p4R)tV=K z{hy5N&i~J5{r^OrbK-OsfX>LqoBs<#Df<_O;`%bxcDH&kSN`#6^z-(**Vm~Fy$!zH zlCKg^T>t%3Fw|!(;cV8X%S$`iu{uWnag!`1Is4ldEtl;NKU^xhYx{VYBefH2z?t3c z^y92#olR%JJFj03{Y83LLO(aU`cE#>;V~bPSC|Szy57Tv9KL?XFo{FZ<>#Ij>I+(^ z7_Wb=)wfW|qt=BZk)5O9e$-Obi>W+mX78S))1N4{nS$g$GS6NNhSB^|Ngipab1D0kp z$l4h_i|xO}YcsEQ%U&YJYhGvHk^a}iH#A6wVkUIO&{^MZ5sP-(kBgrPAUr2%(6RWW z8KzoF)VU;MiI{_!<-}-A5wS8wIDAcJfLOi3SCg~mKdp`lDdOBa$BPHyP z&q|!-&QNutzzoVGSMyk;LH3lwjFcVCgUX@zoXS-ll2x5m)(KRRwbB3Jtl+QZ>u+ zLS8wyUTC&~DlrHokqlRSg6F>Z$W*S;T_HD~rHAjMG@-1Mcd|um>H7rvWLcxH^-wX} z`O+t6^0wLy|5CUbWI%a()*wT1NWze9>A>qtqcPI7<)Ov{G=rri< z*y@y(KPgUq`iHC_hyBR+nS0;{FzagX8Y1KSHoSZtrf-4}f34BD_s)F9VduTWDl#rGzuR zO;2Z8baPM0uwhQUA5AH>n^}N=x8G>9rQGY<-WnL#j!8Jj{3}r5Xu!PpH1p~EzaAe% z^PZ&*FZ}B5ISM{=$?4k%f@9Q=J7CAS0|7onz)yw4*WlT?5DR88kBE3LmKz1UK60%2 z7P?z267-cNf4D%{8{98S6#W{Xsk1*MX{9%=^IYQm*|ENhhSsRR*AuENGxS{2X_|)`O0^0Kf7D!>V!I@!q)YLu#l^(^v-HJ zRM2J}l~pnDy!Cuux9p}7kBaY9rNVOc0JBTInH4;-;SZuf{4$!uXPjtz7uDK0DSo+V zDfAWI)LG_B*7a*Yex@B#Z)VOn9&Wj@3BkQ zzHk<7L8H%v!2~7TjoPC62tvCez?Qp<8=ThEg!;(OEN<-;dhfdHwj#Q?e^OavDtD}! zzUV-$$|_;Z+LYqwmhhM%&)9Mn)2;vvhIx3Jo)_av;uY8DHLFapQWMDfIDDiwLPyw{N24vAKE&a{6+3Sug@6O zboRGYmS35-FOf~c z1>1Q}sL{7ewUqAn^1r3y-%V_}cDdl2ybhfe4Y{Xd{H4yu6{9zHcA+<#N)O2RQTAGd zkH4LFpgmvlwqDEueeh1(hhUEvVzQ|uDXux~h>u@2E`}BYDact*M+v-!vl;WDc ze%r3Xy4H}_noM`QbpNzv#Vm8pB|vJA_8KdDw(ih&N2|K?d(m+oYhdrR)TvpX&Eo^-*1aT1Ss5ZlyBj%L0b{7PC4-3sf+bze3>5tg+pE=+8e#+*bjZYu?F8$A}g8!1w`p1^@S3c|Yzw%jC zSO3muJ*u`plvVQRz5d4^?R4q_D4)~y)!fnDHH%W_u-)7ZZXb-rDZ;apexdZJMBOXu zVJSTF77bj!6y%|uoNc_Kx*aNuo~z1jmt*j&aXFFi!f>UjKZxTsSk#s9JyeOxR1!$H z4hjck&ey^sBfs~YTTbkV-hHNKSo`@>ZwOZ2u5+{9&{_S{TAa4K`XD)SS6+X*XR7ur zXX47_LpA*-7Uag3cu3!DlfS5#`e=f~#x`2!Jyp}4;{4?cv}Ns=w#?nAu<&nXN)Dg2 z6V9%Wf1IolK7DaP_wy((?Ki^jqV|P&_=|$uvKIKS+ObhT0j!;VoB%I+8(T&y|9zmu zqT7s$U?@GNpqOr5lz?CRSbANn3&V`1oisE-6sLv2bi(a??Ck_L$#Jr6^D1)@2Pj*< z8!8HCFl=QJe>qQ8pel~lSZul@r<4Jk?^78Qele<=l(jKmE(1=2nm3gk0Nh`(vGy~S z%ss8vxoYnwq$Zv6&y`~ZCBW#tN%%RkxE0COzq5*^ zk=a=GC13i;#l-WSe$_h;2nUkSduW<@`>C_N{IOaJhND8_oY}Nn@S4w#nDR6r_ZB+J zDL3uhyQogH9Ynh9>o#A8(X3sMCK>7@i&#w1J#TEHOw88wwezEqzMk!8eigUB8LrSM z7|j8xTxp3ArtxyhmUO5RPRM){)lxZ_hWg*X9~qyn<`=Q9s8g{%+v#Ole}*e$Z^yV? z|5IMaLNxQe0)}I~0LkPCMO;Oy;(F3kfn(mX1^FRt4;JGQt}KVIL6s|#nTRE&3ERu> z)N&1Y5{>j3iN{1y!Xd~rU-d--BI?V+WqN>CdL16{VwRD0NlRV>d~Q6qTCt;k&PGI5 zdx$w%yS(ru1MEAgoBMsM`(MD4PzbV)H3?|8`F7iAXMS~o)St?;iv@q@YL7a-0s zs#)XuG_A|dss=jkljfq>fxX+ApBJZigqR()6qAj&(#Y+AV$}_^x@c zNMAVS+H37tsuRWV;WPSWV=>Kr`gWP$+sWIy@)>5~FEMLSjJV#F@ z4vLau5ML~`Jrl+IH9CV|k=iX65U3gY1i6J|{EYUjr8k)T&hJaaL+1G`v>RMp&a?T3 zwnI~=i?3N}M?|n+bN>9wZttv2fPsZ7CB`-rm2%^pO1I7f>ZtDP!V%k={l2Q9o>awY ze|w_=8G}=wP?CESY_SL;eTrA*SN*$B)Fb?mlu zs3tT9wP)9)=^d-BiRG8mifp6#-3+(B?{+eKKD=^YKa1@yRF&wMdq$8_nfbsOI{GcO zDlji{;0ocS%(5zq-jeI3i|bhdb3fRc;vSxmXke~c5r6!fVXMqQu%|M!pXI~|8Tvpb z_ra=wS~uqx0q~%gp-fE9Yvr5lxjWCy^sHLe<#53*vZBbVHf9qg#VmSTWRVBM$W)x> zKJ-r6_f>WGyEln!n*AWHMcl;L&^r9@{^*lKH={^_+O#+-Q`<%&nf8KO6~!vw?07P5+gvWQE{4yj!cr2katwt zt0!fT)>*EyG^Q<8^JzR7gB+s@5cpi$?myDEz)29}`AR8q(8VN>Xg!X5TnT24DrXd4 zFZ21z%M82$Kt5bbVOIwLb?D=tqHqAALCFW#*Yz1hgW|dM7LAL$0O^(#170I?9B+yd zj>CjmuS^xFir>~KaA%X$Cih!h#o$WQQlJ7w@$x5k8PiG~epBibWJg*_O)vVuPlI8u zrAq0WMYpU{LQgrM5UDO(eU>7Z3m_B#JK)^1y$w=M;SngG0l4tE{K?Q6s9a8#X+KDS ze%~``%@#(Sd$Jt|J!yxwwLE+-%x*Kntz%pG_NfD^y)3*#&X{4yQZw=^zPo-bTe)s5;bdui&)13H2gxwRH*_X?~r z$lDSPWTGnB9h{wxqeZbF)D|v#Av)nnxNYWg;Ru{Mg$a1RmnWxsS=Q+2h?FR=*cQfG z&rT)}D&mvyZvN}1D{<$GacvB+2pm&k<>*6{c&P-c-+$2E)|n>0BW>=nX%ds;Z2oNQ z{{1VJEdg$@@M#79$fnBoOxNO7V?GMMr#@2);7q!en=D8X5Y*}ZkmhZ~D4;9CBAlNE ziSscOdRUQSF=iv?qcb2xjUcF%?Qr-OUY5!BCm=$zAb}Bv!W}^djxKO!2gdx%(Tm{>%9JJ|W1x^wIFcBmrr^4n?J1!Za$l8N zZts(f?fLcVS>zk%H}8KZG^dcD@tqay4qP7C2ehJH6{fLX9-nxj-txE;)ni3ovPB>n zQle_dXqrYuw6bu9cf6K4#HB}EXdXb&Xs+Oaj8BKp=JbH*Lgc20xe_v+l+l?qmC7x$Hc!b{V=gvU{gQq=(vjzCAE0U>6k=*fD^S?MXChC4y;mG4IvRtbNDKj+D7YKZgQI(9e& z*4uW2`4|3V%!US-_kSJ zwy5~61W#DBYQjmG^#WbHmhaK^15oAuBU*XJJ~ZOwC9!T3v4DVXpw~*3Xw)H&`(A~F z5fQ=s7IjSEu$PAu9WP4Ajyj@3H*m1`@Cdm@=6RBQuMB*gVkm)N*+WK$yGL)3FF$?j z@dXFnUyN?{hAjqxD)xZ40kBR7S-b?SjHEa14qn5+Xc$=eKQY?%9vdorg4vyk6N(Anjv`d9}kH?lB_+=8f#W1W%*I+~7 zgb^^5K^iVfX8nwTf1_bwqZA#zarVT^uvLeo5q?N$h0OsOI(`r>HpGEOnRNhQ_Uq9! zENtqD@M5^oOgZcog`?pb>^l|Gl%qL{PCCyL4_1LYV!Yf6qg3i4z{~L8cy!K3k&PhO zA`+h1l^96&Pwb0Ua!kKd5G_Vw-^ak}KSpnqL-)z{-38FO_2@$?tp6b7W*4XV8)*5* zxJicuyB%N|6nzcd;-?S7I!{|E5o5Y%6ev z1Y1W!8GcZARFk zNU@aR>aqJ7C2#UdG+fRdvVO+G?jz2n^l991=bXjBb{8S{sI0>zD61)Z4ZrUc39@Y-Tq>s$@st?NT zMbNiq7O98!ma`^$#lME%&_Z&&MMD-5u&p4-WQF&1#|fx9Y?sW+OJQCIs7K^5oOOqY zz7f@0RC#C2ew)H^PaU=Zj}Rl-(GbvH1luz#biMFor8vuEKa>i9#yVX-t?F$-1Htx? z&}WNmqv(RgWxKazg%L7qNgqej9t1NE7ehe4Az^D|js`48sIRexfQ}$CU8;ulC0C*r zfaA_l@fK2aDhQGXNMyCu*h61i^3qtuUXviPU^<|q2)6qa$Zim9wEWc51K2FC*ov|2Xhv93C8Hc1e9H~;2>@GySJPeXf{ZZo21g5py~XKV zu|bRkf_0*zfZA68OX1MX#Vuj8XBOF94q&?o*z^pi9F;9ou;>fLJ@SYx-!v1i|(IUUWd_;H98a za2fAOY{gVIT6y*D@*7QAc0(-ny=w3=9Qy#Z`2Bc(i5EMQ8?2+xC7|yX6@Bd<7P5;j zb3R_kHUq&Y7jox=P9$^YDZ>P`IGXx6j6f>N9~dqop<(Wj1~S_ORs+l;Ak)V&;sgDL zgA&;wgAokDLDrw)kV=H8v=8KjQOwi(z$uC;bv{xM$#IB)O)RpOP}n^>pn=Ggw0s6vx`l(xQA%d*qQ>vR zRW`q>S$aW-$ZR1+O(_5&Et1L<0y0LaS)$=`Esfcajvxa#=*k1=0HTtLP`^XWD?Sh} zety@F5c#ks+)Xb3a}a1e2<=#&;CBQJbVSXZKKNDr5n((KhjLOWz;x0!{kC$?PfxoJDoyTw{nppXs9lc#%K}66E); zqH;C^FBZMD$n2<1Hb21-+y^~aWaGktKVvmUkU&=~G^g>@X(h#j%Mf%YP!PekGE;hb zMP-8&)GWdBDF`+a=z;XScsb)kSmB| zFfZx)%jgdzP~1aS(FhJdnuG<73KBVl-qva!d&9+B&VGP|VuKzCe}!>hfQ{4X+7942 z2KEWtCWuU;QrURPw$_N)H>&q#XH{!SJ;HG2w-}AL+3B=$XfOcC3joGZpq;rI`ud!f z0BBAzaNv`!JqfyF&zffk3?xJM(U5_OypaL(c6nGOq9^*CxA7VWrWLsF6Ps7e7uLio zH3^RL&qFiUm4LcL5x@b8YF@eA_1#2~c3T3E> z?ZuLoAy;S*fr01BuK63W+BEONp%;;8E;M`B1Gb!TU@@*3sD>Uv+r*WN&AimuLqL8^ z4KfC^BT*cJWLrfnWL`c#Ejf}w+;<<#;oAY!0`zWclfArPANxSA&Y+H_32Vj9k-c3>Y!ckJfn-S05}5n=U-FC-_^8_gnZ!VUwl zI{X0MItgo{C$a%ziL@VkW zO9ZbJu{B>aPe!v?E?WAo(VtIU@i)L;q$w7zWwUoh$XfbrI|nzFZJz}BM1iQHSq|D< z&=mt#EUZ0SRTmJ@eZ<3(eXTJBFe;dV8v&n3bFU^qzxB~4^E|f*hYe5$uso1&<!*ECm^3-@D`0_7kaq~qB<`>wfkCrhYES}Ts z5SqAnMd2B1K5ABsA5!Mvs2~n(2!b7FZdaJ+7b}PSjt|!&0XKDEM_fDsPglIM)JTtu{| zP=(Er9NQ&}V;Ljz!dUbcdSo+|CB~NZlv+#UM}$ zV$WD*I{?7q(F1~Tu%#DUz4J@n+4Ix!95gc2v;00cf^~>+0v18V*=s?d6OpXPNtCuZ5fZRzAAqbZj6K^6LUr`AK9Fa-7zFahfV_iL zDU^@xy(oaa{ubiRSV)n&-l=^zjr)@D5j)mlG=%UGQgvp+GHhZgNKr9>R}c<4Btv)+ zE4>KlCk!*%#iq@WOSVlRnoC&@S>JZzu6z%NEBcdnIrCWg2Q_=~AW`iQ*HeMmEzx#h zi_PgmTVNcPV~h-0pg@*!0fc!V373&goKW`ZK#$;MMJ!#tIqh3t=I*KMQ4O zi-1O;LDo)T*nf45ff{q=sU~(&ig>}v1jdNyIprbr9D&K1F)Wqz$@LAN}Nkh z1b{lApf2_%(VROL%ab4_&OJS7aQQdyMdrLkk8gK&Ca>~ZUQHFyOW1_3GTP?X0@Oqo zSus!7?r^W=J#uEq0(w)}U(=r*8Z$I}U@dKp!4mt9TN=_q1+^ISh5u%aR4f)V*SZvg z##z2T1VFK5U>xQ~9tQZDO&ieq;XPWE83Hvb#C$M_2Z?HV2(*3}Ah4XU)F~uY8mEY= z{C-nmy=0Po+@j3LNjX6w`t!6MiK(Sb)?jbZ^gCJHK{wpf2Jy3exJ*l1hNBkSezmL# z%Bx+SeQvct3jXco5=ad#u6Di2YYrA4StP`$K#?5~^>K zPV4+U;rvv&WN$6<$D+aVV5=zOd*P4mmyMd%M*QqP4-^+DK zNP{iLE8DHl>f>G34Q@rJz1S2}f6^c$wzivXTEN0yDb5zO?X;$q zcYQWzS{kGEIDM*iFIRsM^WRqbJecUxwZ+@g>KG^cxdZimRjIArX zD1UgC$!p4kyDa)za*%@8mge)iq~C3L`?t;G9*p|1AN5s`XJ4hYMU^S5$HHD6eoQc0 zXg!;42Ic~0|JG^9HI$LMa>f*^Erek*Ht#^5ie4JWt_ogxw6d59?Q3Dt{H7L)K5DRM5~f-JTFqD zPmFD9nP&Yo+?HZHOuK)d={tZc^o^4=zw^b7+OkJ!lj7ulHsK<)s8Kzus4m6&d9oWd zvZg48tjz71sBSXYE@Lb?sye~ol)hdCIl#M|92srSRBFK}-l`J%U| z?$daad+8iMKNjDjcSs7GjUsBhuSWGJ>V>4nfC3D1tbUaNZL zuFu&M7qu1;q8@f1X~Mlj%nH|bT6E%?t!@^Ve~+jtDi&-!VK63GmH1UQ(a6sxk84(& zgV0~CknUO*Wm(Ub&0sTG72P=g8k&3n?fQxr^hhyS0PXVo2~dMr(r(S(FwSzzdf_-^ z!}qF;_l|Fk8RxH~r`GwUXccWo zpXSh&Ecm(0)Y7L_Q^y13J=AqpYZ|LvE$hjPW`6-jRou41ec*VmV<`9%lZ1>+K0%DS z;FztUHf(=K!GZSUx!EflR#p!zBgiNB5@1;-7}p;jZTF6KygVa(I$rcWykCB|KdoS+ zGOfN@1mH_zxO{7kDV$|RsRuXWQC7hYbDO&o)A`8y+gfo8aT0VfIDc96+Od7W8IU~H z!geSXG9G87YXt6qg(CDO{9bEpA)#5bm5k(fm1lkG%F-4sulJlN`JzXD#(1Tw{JEX9 zAWBeq&3C}L(3zl%&*F8yQN_kRgkvI;GNMDRPP}Iv+khK9;vV!fR(M$=`+WS7FmO*y zIATe&4`=%T!|3HmS~B_iJVWZrQy$u(ST2)EA2-!RBtn+49d`jFxW(HDfYyo?Ch^?77UKP)HO~#BDNCanG4+N127|(ad`ABvpEx z-flhEmRfVlI3qI)@PkW=JsfGKyp>JG6+V^qYJKkeEQe2T=$N6?hr&lnd19cQ^7BX5 z8&|82eZn2L)I(m3AWBraGZ3T*g}IS^Ng9dh0$C{%!?C(PR?4ctn{4oCBwC@@TkV`0 zn0C2S`YOWd6UxxbhZ0wiZlScUFD%;x`yxv|=C1M3qbQ*^x@}`S>Oka&>Nz0;Gu}*vJ-`Pfi$;&lPP&Tm#GbS`c4&x^sg5}?EcfKC}eBuek#keujxFc=qXycnu#Sjop#eh z674THpat+UxE6o@46o&jl=+p*ZGF>NQevBeF%=XxZFnzWcqb!TBxrsYuU8?&!g+2| zH&IiLu`L|r7c9)o|SLVRDPtt zFqbObZqnwhta`I-j{IIb<^!C6fyyD+8mcM|)95vHmBAV|+|^G=KaYk<&*CHbSCTS> z2Y|xUeZz(fN8vnk%nONq^5a=h6NJ@};2ArMm5O9A?gnFzq4H$@PfC~!ZTL9XbRQGK z`pSu%B)&2?MydwYW*=Y8FiLXJ4NwA}d9*Cr-Qg*3j3b6eJYW-@#<2udoa&Eb64^)Y zGpQqh`i1VI-HY#qo(IFc(SWal$P~6-Da{~~{x9B$gwT4za8Mi!!}Nuk`1%Jyg@rJB zRNv|N@a7?25lvJnM&?E}u}vqwcLW<#E5sz&9jF}I+iO>fu|M0Q5Eozu^zGv^iVziDSKmLEXWt5ju(qK#?xnN!0)5q63~rN! zx~l*Q%|Ci5+6~P`gqv8r*;u{Vp`tgMH|PzJF($*TUY9bQLA!~(Zzo3#6-LAj0WLVI zxRUyzM10sGem<^rAPV7ocrOXd6CD9I1w3M_kH3lq`@-wuBy(UxIF5Ck8;NjtJOjFp z1Ft6?;{;m7G!U8;b8$N1KF6k8dv21!@!BU`sZft~oaqQ|upT@k(Hk{{fAbDE;oLiQ zLUX>JseJuT-f#+(l9>AEaLNn=5LEkabC+wDIJ3CImY?bIcNhzprh_{ z-$w%C`Bk?0vd&e3WWv|_9z`lX$^y$Ip~%XyJjA;Uds}Y~pSi2t0fT(8oedhpO2pDtYBupS%<3 za~AU!dfuVgldseBv_wpF9aIw3gW(X4q~Pu8It~gPSua2O2Ka4UBy6488qR!SNcC|L z19t-0ADLuDVFtz!z;-XhwGA_K2|?w|)+R~zj!kp6ZJmp~0hLK1FF>|%W-O&NQdaM7 zG;=hGaK(h#I*8c{sR;Xov&Z&a$0b68;>rESF)GJ5qRvJf;@v3B{z2T4@X}5vP}fhq z!(pQRAwKF5d?T3n*asbs#9N`vbjqJt?m$9!Kn~NUAzenE=km}v@bs*iGgh>x@+FK6 z>S6*rqs)S**)33A7S4q~+L&p8b71ZIQ%%cS*0|xTh36a&nU>A^?VB%T*5c1@A|yg7Fq+7IqINgoSs}v5ND+^U)AJ!n7=pG!K@Lid$LSf|a484yJdl*s){T-B7o|BK0ig5QP@iP^{qI}u)e zWwOSYOE%^jN+7#(hIkGW5tB(j$*(Q~K-NJF<4Y!)I!{Rx4=<%r$SMO_tUA-e6BQvZ zJeid|#=sHNh@)wyXfgp8U~gj5*h86$p2mOeY2+b-ZXXfWCxT7Y-?a4)B#xaAe`*V3H!CJPXYw6-@z$qZkKR z9?I^#poJ|ygE@lO#SKZCHJ@$4`fa2bM{vF}Bu+a4rc@9uFzt^@Crm?ck4@bi(xf%B za8loLH^D=!McaRX7kBXbFWJ`wz@Zz0eh+jKeKLY4K_x!`UKB!b1dq@V&W%inK@lpc z$UA5@?$(i;6he5=8J^G!VK~?kB{8O+V8jC7hyv-)o{u&mpvcFcG);uzz}lP*_NcCM z!0gTXoG=q`>^if%_JBu2Y7YhM!vf)Q0>@(U#BosUA%2Vdd;%%eL3?hkJW2TibCCeC z`VPUT@U|P|rK+Hmy+?)-Je4DeIhI6NPBzr3hdaQboB({JfMcF0%cB?v9%gQu%p`${ za|D@%pBqh$LlZLDYBM%xwcH4OSMbU_alsVArf7BJC^%M4rg&dF8~rv+^ey%C`5iRG zqaJ*}Gd0wQ5JSX=3{K67I{Jk<%#5WU4S}O^OxEI+*M|reT80&Vs?!J%ygWG-5|N#Jh+7_>yIGDe z8-7ljmO0jH{;&@miUr4F%Cnk@v3{9z#+QQ0c`!s`bRXCX4t*9jhugpf)?bY6y2yS6 zZo30;p@4(w5*H%TkJuT}F z=8>f6E|B#)J_PRTPf2`RBq2&kx(Wwp)#8oTlLBy*)6BBO3`PIXpiEA3(HsxTldjbJKFDWsMhz#N1A1WH zeQ{euwICnr`FKQ)euI0U0E_N#g5E;o&4{Fc`VIO=8KCg~5lM!8?8avZ!9FWz*Dek^ zjiR2-mT$%T9D44}%2<@+X@OYZ;4Y9QDp#n{$2|y@e#mZ%TqQxlem=bdAG)omu+Z{` zX*>(3$)-CppRaSBgBR$HUz^hVsDbhru8F&Nh@UK3bMEUswe6&U1_ct=0weHfN4!76 z_aNhe_%Cq&!bfj%LPCO$pX`-RgkPe13pW7&JR^Yq)xC)EP+VdF3M2yus*^x|lmu9P z{Evl=>}TZT%*&fvQ{C$Bp=QfGr;9X7p7K=2QKBCt!s9rI@qH2rZ&I7YzXOma391N2 z8OkTSBZ8~|Q8~zsm&^E@c%>?e5xG7i)QIC45^hKjE{De{n$)%z2eX|ZF?(FQYG=c9 zyOQF3kGt?G?dOReJ(EPmdO$}Bz(*SrZxYvxYnCNlOIIQ?Y{eg=?GVwy@~0Z)O{BFC z*0|Sk@+{4=)3_00-a=u&@*!bq7Kh-EW9zEpKfTAdkaL$M`BZ_O-%LHXNTumW$&dJU z_sw`HY9)IiC+87}l@jN^8}Bt%$p1F(!)`q6@F^SB9l8NfSl?OFYWPr(vk&Au2g|h% zCGx<5$E+BUMDC;^){|I18@80%p4ns71Tt_Kxg9+42J6zw{N#*u=7bSpCs*LcA zy^ht2!&nhDGrxLVWBAEEC^ry~yVi$grGLz=Zu|+f}&{%)~5jTsQYd^7`dd zf%F#L2bP@T*N}#fxA;Hq7ZSQ2OCEAws%Vp0wrRtzpO57A{&5%Tm5kQD$!(souJIs~ zMWra3{aqb5`A2qE>LVG}3F>_-{=rVGZ`-;x$SfWo62PJvr;5yCxzOBe1q`@N>~4v9 zVDNKCFsAFH(y$egl_55J=)%hO{g}1)coQ@s1#KOP$W8`fK zjoeZ(_xi{DbLa^F$mrvv+555ZcR$LGo4!2VZ@Uzm{UUlT^WY8b*GHM(cPek#W_Qkr z-B!fB2{o}x?)rU7koBcl?5i(72TuPk`+R>-hK8Q0dvl#;Cq%1|ncs&6X9xWF^^x`) zOuWee<~r#^MLbDl<5vz?r;0x%vf73|d~V4vZjgQN#lt%Pgr_8lv)QWk%Th0M<<7N* z9_rI$2xTseH~Vr|n2Bm!-`%1Q@TQbAYX@u+IjSku1|gevn_uN7>TT$;q<*~hEEd$Q zd3r|OF~?wU8yAIWlCNbuyLRYs-IdzeE|mStJN^e(C!o(4i_S6f2hMfiz}$)fhsY&b zwT!$gcY)&kgTU9*KP{ShKASxetM83IKXc8lzx-^@|6=Ieytxx6 zvftkNyRr7;hiDfQh_oiL{2qHvrE2dK2XDVH*$iY!>B8ksd-`q)#3^UVRaC56NmZD# z$yb- z7r7H0H44GNRD7O2{;`*=uMbd@v46X`u2=+(I_Q+`JL0UiCq%8}bD6{KiTZ2d4>cl6 zP7S*W+z(|Uq;d_KH$!s+q#fB@Z;i(qMM?X@<}PDDHgVvmnQQqZHEW5QNbPO)A*&%V z3Ji=BE^2W%a|oc^Wt-B`PPFZ3$I(FDU#ofmCOlWTiTLIjlRwM z7BqujS6(QR3`&uCrG3*Ou^ZvbFfr~r>{sdl^Mo7J9!Crd4kL%9N> zTbtDNm0p`)AHX?pMeSnV{2yl6BMZE2iG#wI&9ko$4EqR^FL~}l^lCF=0>=bSs%K?p zlMD^L++`ol4!5K07%$8|<(>SyIG+)cuM#g#Ry2NBpzhhg$+Po1b(<=auOBU1v!QHK z%xIcF=VbDQDz?88`s89`i)PVhseP26k_FgOv82Qa2f0TmTQvtUHf( z>HkQPc|JE`hYeWwu)6+uO62{Xo-}2Dw$;O~diu$OsJ#@GKB#?!bUvp<5HfqW6ObtV$j4YM!`|vytMWX|KbZ_bnjGB6KyxHIYYp zdg;Wa<`1uKxSIBflxqTaLFjEc- z;i|5xLve+fda=*}>Z&H4pHOK0KuE9I4R{p|rok#q8t=NcS1p`oQ704KKT^z<)pY#R zx3?lZ?rL(t6|F$`o2BC?Dp6sJZVykohNFv)x;VP;FLLj%&n8Lz;AB~x4!(F;I3xcs z5=t498p0}yW{E#>FHBFHogX_Qx3rti5sTi&WGiG&?(VmL8sP$HbsXj+RqLmm~uYsLY z0;=TWMNr&|Y(>@*BWF~sBkoKnjNGd8yWAOiGhhWs@FAl^H(#6-lY|ilVAZPiSALI| zK-#s_=$OWINsR^E_XVzG)IvI@W6cYiLxqK$IKg-LmmQM$JzD& z`RW*(fg{fR?1zLhe?-r`z&Uuo>+s|mWsJO^+K|86y<_a2sl`(&!I6co%fA%|@S8TT z^?!yA{!ug`fPAO454Q)i6%qvtT@T)M`r=sf(ieLa<2F!XOmkJ+m7LU;Srl$u1ZcN1 z2D(2}mr@ZPwjY;*A+miW#u{JPtQ!}&e!slCmS=&6&!lQnS5ms(8cVPv5fDDuS#v364s^# zm^dE?4OFf3fWk7W4exx3h*`}KV+7+18lXYiA1(yXon4+E&(!MlyshWRS330WuYY(6$WU=s z$l^#^|VHMoO(j-m`0>mF!594y*9$t!dnsQ=!Q>Q=c0xaPclPfCbHcUJ-M*s zTT@DtD;HzmenKCwn3l;GL9I_b-zi0{Hd)wwVZFsRNqi@mpRwQtM;}lF8Z0*J8WCPv=ijUzT z=0Mi|e5cedQzjiyNw; zT6)Rh%$~pNd}2@a{9 z$R48g3Qg3$GrJUtM=V{tedYEcQyi@Fz&2dIbs}FoB?}Y7)EQ@6r*x5%s6`2RRy^?3 z%9N!d|3(Z?f0S>V!a+-Q`*qUI7+uoeMDKf;G|fc^h$Cy~C|yssqH9$G$pz|`fDHN^ zLN%!}JZ7Jc>)c|-Jx!2pyp!D)81@ltzV#9@-ZlP~Z8yjtH7>H+9;UR>Hxi$3f8bjI zhQrBhJO8=px>_?*AKem?bC7SBJplX+HUgkky+?MDt}t*&^F$|^CX_A7;mo%os|D~( zCzxXFZ65;?EM$;8=C-%^3U_NXA}=kJun-65cBRz1pYCchM%a7++jP=p@;}?^ggKTB zL6e>`!U66tCWlm;;gLYCnFU+jIg0aPH!3 zr453$OAZoR*`G#(T|Tfwz6-crLonR@0iQX!w`iLvC7H7t6h}^MQjlFM+pv>Og-6Jv zGqe~H!IML~jrh_#RcY# z`(J^5+%rijk24=`d9O9H&FVM{s0q#Cj^98VVN`SmlOK!p07tq9L+uONtoo-4RTO*N*EaTV}N!m^F z^+TC5d3?%f6m{DXQwxy$0My~7cbh27wem2_)IEoaF#&8l9@xSsog_%N9t2Y&MHe~t zY`Z?Nwa`H=2Bb0uHj2-Se#)mLvUN4O^_lEWP`!S&o-K*)4B*@J@!5ym_jn2rqhE{@ zsW5-GeOh{l>%cIg?%2wWBUNB$*KV`cI*S$ETZ`SM?NgKr{=l;s<+KWp5!?r~;oQ@f2@ z*nZW;LyCM86x*VYZ|fRCOPaE61zR^7zPF)Qf6uoX1yiVO4P5uG3O*%3H=zB!%W1G7 zE?tL7AN3o0sRN?)iKmZj(iYgXl}%k|O^3}}H}WYd^jQ#ne+<)PoZZpo1S9e7TIkBP z-0QdX?j70-;jnBrFB`3wA>7!)_HHnXtq)Jv@~3C2ft8XP<6{6u{t`+ayszD0imL+z zRqEoyl&t77Ch^4$Bh-sVx|&S>vwr#H;QS@g0wPjCVX}1=fW*jjL>G9g>5X-(x|!J8 zhhmR%*$0<~w2Z+E{a{-Pf0qG!`P_$Hp-jWR`XepPq`qUC@g7hB|5H!`{yrO}oqhnB zzxH(5s%Lr7h(3goc-7ChGGDEUKB7aG{^WcaVF$iZ=?J0FU!h)Rb-y>3NGIYz7UOLD z7LaS+8#CE(%gA(6i-T<7SE7Coq6g@s_0`a|TR)9WS$X{fUQupJSHqjDKgQr~-1pu9l9k zkS4A>$ib!6fgc?q3ic`8P-_uw!z=FLAvX*cfCSJ~Want%-Ky(6$qN0%%e0S)bjx#0 z2^|O9ac~z+0WZO|=CFhwJSA>DtXSijGYy&skZ?^u@(bjeNYzWzF!bQT(s&Xv-F_%K z(s$XdmS>_5;$^3si-Q?2#Ec+ZAnh8IG>}9Zvv(igu8h9(<_L`GXc@;xgi>K*LHS~a z`3JCd3>A`1h4~z@n(Iy*aYd$pC!V&#eE^D`IE%Eb2c_@#9$?B#a4jX?Ix<=V#nwPl zV(KK=IDW7>x#36{AD>sU|HfBO7R$=|zC`U^pmnPacUt0K_NP~1Gh++)n~7sf{nk6d zo84ez0aLgslDs3UX$wzxv$6mTv2Eq|?cYV!93_`7IYJ%z6?*C7Iq$Bm4^}PO>9=p{ zwEOKpOz*h7R+KRcO9b1Svn81CpXg{kKhD%`8PiP2laPH*0q8uAYyqc$Y)8z#_}@7) zd<41EVqzSae2DEU0!u_br?i7!XxtrbnRDI^phyQI%^YFt-Qt?0-Sc~w2f&c=t?f{Z zS-@}O1u9hHdU`gMRIz6V98+xIZMm7tD(b719@7)Y!*uc|jOje|hu8z!WN{W$&;0|Z zz_`UyI!40VHHPHMv+=Cep#uIpDkW%V_S#b+;8phPg-WRe^2bI6=<2))?(k_4AdLy< zio7lT`Ti?Vjl9ob@OG`_i&465+T(%_p1R9DjK>L0nOvE~cwh_@ z9?Dek;#>Np*Nyh?90gl5fR%dz#1_6?7a|0uRf&}}A|-?h+f78z})orM{tf*PrC5>?R=)LshG0nh*eB4A!q4?@^w zJI*#V=D9VjO1seq#=E{S&7YNl-oDC+ehZdf+@ny-wo_yav#Dm|bQ?w#l0nn7qn}6g zUay{ljxT40yz%sw9(n8v%e%L;@0VMRrLCVkF$bV|(OSKx2ReStb^(N!_?V^t7iH%r zn^y1fdZNwW9A&bf}Y(-gutyVO1{AowLh1#xC4#X-3N-U zvoO}cOQ}F(-nFCb>0ON>XLm$i4W|8$1~-szAE2;L$vEDEzq9lwsf}LNRaEqD{9Sr; z1X1zHO5&rN8NiTYy!D^>Eu-kw1cw9w8{x(aB(F%n>c1aK-7zPM*|R7yt#dn3A;U6g z190$;c+-kyjD8&hYj19OKcNCl`7_)>zx79UPeI0giPDd$K85U~#h2>U=@XT_^CG$X zBhRCKdeqJX{u^WK`VZxUUnZx5?Tx__3*Cjc*;WE7VF*0Y0r+|G^z>KI#2?EX`W&^E zN^s5Br&7&F`DTM`GgoRuJ$tU!(Zjbe|E6Q*XX`^a8EWXjMoT(|ZL_W7(=HJ1l1iBz zdheXwn~7BwXM(L3&T5}ofz#Uks|IWel(FY>Ch{F8{G=Wk*+o?Yj*)Uaz${YpH}__jo(P^6tpgAWvzhI;?z1p`A~RcgUx zcr9mOi);G`s);Y}Z`_hR(jXEz7k}_^%xV_dM}|@=(^A*I3^yG3U**|<&!MR+aH)`9 z6zQnzrJqQLd7`LMB5K+OfC~sPPiG{3026G-$haN+{}u9UyS2r$r?0TEX#%H*lxPe z)L4IlRfW}KY4cAuCO`_mggfqlv@BhMc8N=AFY#ov&QMOm$fS1`%5^KeX5EoFr;?KQ zM_S6EleTQewinDQeoJztLZ;2LQKonH7?Jm z!W3w-K8_XVE21{QPD@uC8tS^=tar8-h|n8*6xwix<;~gA^#QN@{zk9^h~H!J7@ z#E}?K3+?dZ$BC)3Zbf8509Q-(*l5}z7z;jfa33Hl-r?Gr{%_%USKj#7z`*5T7unN4 zO6KU?qdqyBR~SWz*=r{zn;I-w?pb-V7#rI2p7F!`^qR}0yD-VyRnN5x>^b|1-eVnO z25qB92MpVlN0KX3d8}|5OGoNEvV+>u`a%gQskviuJr+MCUMyGD1x{EHj+nc>b{({?{Iqx_pPVx8!%SSpINZgif5gqJHvhVDJnMH^ zmR)%=j&I=>!9D$a=Teu{nKrsok)q^_KC>r@iaD8#o8rSqEzCcECB--lT@$=%IIPRb zM1By9Q)+V#`ySnE>=sN85&ppvgyve`2 za(z~{SI6~8KeHw*CeH#sD0)i^5J2Mlz{EYv3X~acSx8`ru1=o(v&PT2vx6lS&2{OI zEIH`8=blIBOt1VQ9mv@khRab&aq3(e?n&KJC;XjJplA$NY&uD*jz%iD1mG^b;mkW} zD;~5a$=x-)1vZt-1|1@dzRb6%1GkUYn0^|D9qZ#`9{0Vl9C3vv$Y!gfmfzW$j=jV` z)`z_A%QEle6vX#*DK9jpoBzCkrWZ>y4Ybg+j=t#=rHm_F0&6EM>q8wDTQ7iE)r}we78pvtOhb3y)iH^6aoOn7f zCsUpGy^?$tO$jOV1np_uUPbSy6-uPu>!tD^70fSEB?cN{8Pv&(%Rrdqhc)76kBj}A zIueA>d1bw_(*C^t2XXT8r!bRi2Zv&R+t~<#C_q-G2M;7)*Pfx8%}vKG^PKWV)hL5N z%*3l?<-yHC_Phzr=1_c8xsW4ot)nKD)~e*GMDD8)YA9C4A2UB1Trk>GqIe?w;ajwe zDzth3XQK?LiVj<=d>S2n&QZ30M7m|}Qo&NcpYlX@cf+fan)kPw_V`l@I~Y%b;`3_o z{YZ7n_^=38S0QFz<-={_y%BC2)p$$xsB2i8tnF=ZVbJib)n7%uH168L-H01Ik*R&> zH=QoI)-|aoU1*IP_xPW16Z(qtR(9_a^^gwQ>)2k<{{7YaE>B1ILj!W&CceCjBt6UK7o z!EsT>Wy<6pWul^jkGV{Bql-%2KC=i8(wg5?@oyA1Maqp#t5Nygnq?zVC41{3n7F_= zVV?4|?Cuy}E_~?YcgyE~@jah!z0STVzYu+(Q!C<*8nw64^J&mYukWgpd=UPX3D(h- z1P-ER9S!_d2z?i#e44WydUyZ9&4kh!xksDNuiXO^S^>zUc1J)k5Gm#mNS%pZj2Z(OUlH znVocrI2)EqBSKbg1o<3I{u^2E`K!GoQ}^S-9OBuwf#&e0sihx9`u_7GQyr)eBt(-l zpc%@Px{7o0yrMm$nIr3U_JHY^Vm14X9fCv#7&M@Zj_IF%mI5>s2qmus{_tx6r)sCS zkMH!13RixjhyM8Wxoz7p@PM!e|FQLjUg!P`aa(kP&OW=*g;>AHxj^`wvU?6*QCN7I ztTI`(Nw~!&9`}-t9#QNcxffo!uy7%O_tn5bqM0k*K_kwyKG~BLs$H;KuMwj1y<3~1 znxkEq?c4gx&MFMFdw71_c2^wWg<~enq-8HaTmNghMgsMRY9g&{)QM;h9BFoH;#QrA z6iQ6?Ojz>1^1iEry6_|oLdlE-sH!oR{KMzA2+aHfNY2+~qACrdGb#L22O$lutag*4GjPxN zyR?ak%-4ov+g!QOsy3r4OgjMLMFMWmW+=}15^EH+7{4l*=y9&3<&5um7g0XSG(ad< z0F*9Cf0X?FQMx3BLq5LDJ>dvI*=P7FF8(eZ&Wp}iET@5f#}Y*NABBP{Nt+$WmrV2s zAgaA!qO)rN&;yC=!Us)jc>+L2&ML2juopGQ5?>HZx#nCg^f(js!P8e*@a(n@;CU{( z8LfCoDmutS{*LFxtpXk?dcXPf9nRc-Q(>VrwwlpXAf!n>oK-BGA&d|Gd0rks8{8yJ;lpeoH+RipSnd&bAOY`zZn&^T^ zP}%gIZAd*u@7`txx-myGtVM?mQ!f7M(@*uCTiv6@lkbN-DL`wznjtm@yO`fIo=%50 zGZf3Gk5tyw|6Nt>Fh&V;ZlmTv`oItO_W)x1&NBR6G6fnU-=j z1E$ZEsnrn2V`&P3QkGP$y8!u}E@woYq{|fxnf-NX%L1jp&y_|P#En;~`l~xEOk9!@ zU9N&40>GSO0TM)#_zPYks6p0Er3Vi z=`rvtU51F;AiXU0Hk#_lGzwz@cJ4Lg8%FG7C|RpZX>dU#=J--D{?O-d^Si%~@7c`* zs4UTxUoqV@g>o8=c{o#?!%J7II_bY*GDN1jY_Q5)u-fbF)u67-7BW(U0kY>R%uN%S z(+L#mwSZ7?`LwE#CMz;!?o~;+0;jF|OCKsvm&#sGwJX>=rV_vKq{EAac6I zKW1s0EWWHU|JkHO2B`jRXRN`|wn*abDrA{#;I0N;mzG45P^SMgT92Ff3{1(6py!W>z3+{w;{DZd>|%$x@Imq6u>s7v>hdZb=(k7i3} z=bZ?@)~n76m{x6Om;~$pXGtaWhskt0fW{d+if8tme&F0e4w|Cjv`Fb{-SwWei5dXu z(oCEdH5gl+*a7A?0zvLCd^|K__KKS))4=ZJ_0vg5R>-PMV1OAFB;P>Hq?y{2#I#R> z!~>A1BZ)W;gkIh+z1?iq@W5J14IIhpBr*4{GI9cP)tOzylpN@!1thwcSdgpJ^+q55 z)~mty;9jaywTl!l2{ghm@<_KFno(l%B{LuR@A}ddNkWd$R0CcI9bPpLh*NK-Dlep? zP31roAd%ow_KJ@>GS@OPqrtsHtnNbew}EptvX>v)e6CV(YB!H&Pb%`1=V&b=8+|KgxEIsDca8{ai$f^ zrsX@T4%!}ddlOp~vjNttUyLmy~hD**5Ro?aw0m+qQVN|QBpJnyHY{0q9_kId?J*$yyw~w3!llt*LG}< zfoZSfX~Tw)04?V$(~6DLDs$5+s53`&5X2U8(OQq|Pk}RU`u18mffV}Fa>lAV`1ath z&r`?#kRtHQ(<;0!r4x$c8%O@!inGY-QPQ=UaIR!G6XZaW5Cbg&?(ey_yLz0N^nx)-p5y$zvN0 zl@G2@KHI9UPX`5j{%R6k;HSqj(`6cpl zw#uuj;~)DnOM`=J#P+u?C7nV8ZYEwYr{n5BqJW%bsdZSjNuOIE{!^*@DNSWf9L-aQ`l^moR4ElhKc>m}-}&4LCr2*U zr|!CEx7?wyo_>Z=DnI;lD4mXtk9^^*QlTAc{S*9 z$FC}4o=3~BJ|ak&Xg^Qv_joZzR%tt&eOsYa{*G>%BCqf)@0bR%5jc7EjE!m3)63rz z0X2ivr_N?+c zix8jq=<>P6_cit?Yu0SYYRRiWPbMm!Oz4X^oxcUkOB*FR8&f7qq8%_2lrAzS!6 zGJ_RocsAh&6!K_N=9)u!U4+gqB~kxQDIc)#@!7`(O3z}06`8>+2vwbcD)fHwrb1Tw zzD;0Ob;~+Pz=J2-rU>y}`#Db(8p&UuOcP40q9)n;t6|GeS%jb}j}PDF3#z0OKTFsH z@qSfyo&Z!V@auzZe1?3KTM;_5N`Xfmks>&EyR5ymC)l&l%qoQD|jlcw}6 zSg9gd#vhxh7mRldzBKGQZytr(1q5l*ubQ$jVLyB=OGf||4Nil3BPXbQNFT$zscIsOA zP#H_1~Hv9A@k* zvwLsaI#JBaJ8skE{pM~^6l%#@%3C~y*Nya9)WpxVK7_vgO(;#huhRpAoV0VD{nQXH z^Yl17SyJ+2Rx;DOrYRp^E#v#TQs;hN{i9<8eur)q?It)ymh+hPTRXt5XXbI__rLcX zzV9yDry%#?7pW)mlf)tZXN?C1vYw6>@10EuMy8#ja_2L~PNZif1KtQWjhQKp_4y4uDP8)f8kV#Bturq^(=DYgokFf?mCdjBQ5N)9B|z?al{~D z29-R)>G8{w%wfJT)``83BLB+a_Svo_s*e~yW=wzFrABE0Nq<`p`I(i2Z+JZ+j7@zxcG)XRES2!QCQ?b&Xqn)T{l+0^-r2#B2E zf)`XSn^6MCFW{VHZ5AfpN7YTAlD~HBv@Z=>9vdAAb3QAKstF3*xk%SFCqU3@8cm_l zor?k*o1sEhLc^qo|tj z$Wbp5IKD|=;knt}liOS05qR9P@tsp@yZvfxvKgzdPmH9RRKVO$VQm6^cn$o6$L!X; z)hZ?%o83k_8Y<%cUY`KskT+#_>vXJxPwWp}ExD+7)8VL0-h+vN zQ(mH!SxEVXwefr#)?bIFsFPUxKOZU!?N@}frCC3hv+)PGg>Gr9y{d(2KaZ5Y1Y?8T z2}HD!V(6Fo#_62Sbt9iRyDNf_c8j4mg&!{ee(!>fENjtsWdHtf`C`@hja4Ph zr}G~pu70!o+IhG6+whLaD>IXu-EZ#5R?w8zniVoX94P(gBrtemtGcPtX!qGre>d0> zEs?*`B`F^t8R7cEuFM-a=eA-%9%Zch`Rf^8*qa9G*(WLGOp_epoJ*v`@OtdJjEUBC zaLgy5leI&}9G2}UapY9Nri0=X?)=DCu5^`kn>k9IFt$)_ahsfPzC3Ut)Sw3cI=k0g z)SQqX6I1iI{Ia7}|J~jH{Zs9Eev*F?o z9mGr57*N1 zUo(-3TnWQQT5&@=TmCiTkn3foC?UiceiQua!{=>T!cgR07TR}H!+FIT}+zx?$s;l=j(?dR0`4jNVI!h1-0J#n=bn3VtQ{u{`*jqXX!KDU~E@8rHM>=?Ze`FPPc>CkXqrBGu1WS2kxZ|_BUnetA9`h$DD zyssA|wX7F^4X|4p`iHoCE@(*4VKCRP?zcrrpheS>cV)Z0VlUtHU3|~D9DOz4-RBx1 z4D5D!9P)A|X?Ni_%^f>ZJqV28nlSD`SS@Zi)Kx-E`Vo2JnS*0UT-3+dOndI`t4WWZMbsSEfc*moWN#2c zwy2sTRRxJUWh&WyaWMP4L6C+Jm6S+rjX<2fT(@7OL;%)lQ?i98t84>iY%cNBPP$3|au1y^*aR1Gv%$p& zpn*EoFFwevmJK?9wc#K|>F0&#?-+#c&)jL#*6w1*8-`Ryi;;mT{KWrhq}vaM5U-72 zgO?{1o(W|?yZ`sZ6@%HF1O5qvTXwe(eTMU~s9ECg&CI9v+?>?W8sZw$MPzp(N_J&3 zWaM(Ci>g7I>p-@eT(s6iX8yn?ezGj_r#|7t69v$Ws}0VO|yLMY_P4c3hq^?`|2mt<+{xCJh#KM zm5hQ%E9IB4$KY4))!`J!%3()-dekm3){iw27c zR>T~g;FJ6X<$WEOQ2hQw%ekbEp|XUUP_9DK&0nR&n0cq}S(V)zvvwy$U9DI^$eZxW zEW71|!uZ-vO`|@DtxjN}z}I;Z|dMa+Ai`l)$QW|R5?Z_i0D2hBHR|2UK4UsT=))(go8}(D>PC1>Y4c=9+#f=Hv+jjli+NEgWlp2LQn?ki;7!d)b8L+SMC$1D3 z;i&L$!l?LnCz-?N)K-8s5v(AG{W9_BKL9i*BGm}!hz6ea4L-f=!kOAr2`Orzl!jC6 z^s|1fl%!McW)kNOyUrD>oofGb`o3K1QTBn-v$P>4GA|tx7Z{0E z4QG3=fJWl6v#rQ`+K9^}L{U6?a|P9L8M5_8&I<&yWS;vivMSoR83I&8-wE+mSJS&NtS#(Dd5 zP0Rt%WB@`$f`_$QzI8qyu!cPp56z&$#RV~DzpSSa5)>~2HPpd#c~Irm+#no8j8$7? z!u)aG-nhdZ&yQx1;1Ns+n7zw)1?$_Y&7eX<1&~^u!?`Iqj#%O-%#+K;`2(PyLQs3y z#XxS}-8#spO`tz6KUCoDJ__{ZL9+pf7dpmaQr>7y?d0@bKm4IADm+G@aBfxCo0B`9 z0>y;L26{nqN!V{*h%z{I&|2S)pPkKt+TdV=FoR(bG)SO*!qiN8G0zi_Ke71w{1YdOY+++BcB>v2o_I5!m`DJcb*nu6i+0_7Y?x>Vk| zNLh_P`N%C;wKYD z3d|K?j9ggtzj6MY+#)VKjtc>Uk2ZQkeDNM5fV{hkheckO1Ek6>|HMv}5u>~=Msf1y z*20Qhb4uZt%Kc>(>mf0?;?q=U_yyUsWm>J{5SCOaa#kWt0OJ44#r9#=5)49p?}y?9BL zK^3$AFuPCTCIqli9mnJm$yqUjcLgJ2VqO3WV8cKd6mw00#{A_@l8$2^RxJXs-#>1ZZbbvNi5XtCi+~!X$*KW?%Ih^?jsX1xTJwo2>2WH4gfFU9 zo~#;TSo)If2AG*~9Q2`b^n+8N2pl^0Z|x@`qN4;9#H)pw)QW8$pEW^()+$jiMmZNV z%Z1ghD(->S?6#`EOqDzD3!UO(I4g+MX3RH+WaT|zTPx<1z$5-KLa7{{-5spWgBq1f za;`vyt(e|cpe_gcsTIRxX1Qu8LNgg5!&2Ns5h^UqVk-g*MpaK%jWDfq?w1}vc#|b{ z<>a5J!;mZ0!s@cW^-l%%1LCeD?$(NUsR)<^rnPxI`l~VOb2Uzhd2^H_JA5=|0D#u~ z%blf4%D5bsJ6(lGVyl;`NV(dcT*-M{BTf&!ckG7#$>v28<}^TbN|y>v)k9X^vrOSM zm;J?j1)v{<@APd&EeLCA*CgMobL-lHPg^mQLc|QS>F0x_!eQ8$fV=x0#ygtkPLrIC z$6^1X2D}mzS?Xr*A1({fWn=aqD+v!46OfO7WFpXRue1*fnP7;_Chp z4)zxb>!BU>iz5b6lD^T;U93I!>lhM!Pi~Bh6>vo8)Nt&d6?DAhlmC@tX8vK9c$lJ6 zOoTA?JOuM=1@jw#g->UOl5LXXabhHGsvq_*SF&yuSWk+IXvdgDV;6C-aht@A73|M5 z*wI!UUto~FLD1K0#Sg4Hi+k@m9L3I4JyjW~)idqCY)?MBqWOE0cNto<__ew6s5XQW z@pA<`#<=fX|G&RDG-NOm?m;rbK}rVxC)Mftt#0So3ijmuv7fwWY6g2XL&KA-qi*fK zLzS-i1*i(vdlqA`_uD~i;_mLh0?A5Hl$Z&9hu7G86#a*Rc|Q>Rf`Hj%pv`|H{Jx;Q zTY($^c7ub2oMG1|fLLO@ECaQ85A`cvgndP_?BG1xf9c-lN^jmWT48sFm^EKNd^Zts z@0g56iB`~8(u-e0q~*VG?Yo#$gNeoA*dGE|XI0^!6;xpWaOEHRyAmY4tSfAHXOR~2 zkJDl7SSM!5Jqi5$gjFeOp5puiQhIjYKV@YzVb z{nu60Lk;YzX4LO^$?(5fA}`<|6Z<3?`%GT`4(g#c2l}NoN+kGSQE!8P2(ly@Cz^k; zLb~8+viF+bL#+tx5~-v33^u0%bPd-#NkaDmu-EnN@F{n7xsVxdM1vA~nJVcC0G10n z>O-!KL9?ayyk2h!P(1v$u2EFI>&ue>P$zs+t0@?LaTJvTfaY@0MfC_?H}p;`^65&P zfP}n5l`I!ZqXMu~TzDWCl7M@;!F}Lkr>Hp^`;Y@|_vH^d$|~_XR{+>S4m^R25R%d| zm^$WMcpC#bET-oQB%4U@PPa;_kTqs_h%g?sy%qCYhz^X_4!&NsEJSs1CCjNPt;ZO7 z^QcFu&_OT$Q(pYx8PF%dvyUW1-E)+KDdwD-O#-P_3{amoM%_COOO%2rY+(jgvUB6n zc^^>g9mM1nh1jVppLJ<|MUfc?ZpaQjes$KwGt@S7xLHFY%LgYVyC*o77D-CL5^0Oqz8aYa;U zf-y?W`yLaJs37c54(2fz7O{dn5`j4zjK6`KQrJS@6e43jh8+t*6Hw^00!aD_s&wq; zRD$$SAa;gmUFv$u4HWt+Y95d zBY?`_>v0MvQBM~jCQk614CD=*fT;aM44k)EE`8#mb^NdVc`1fH8m73O{36rw+*VZL5N=Xyai0O-X4E=% z{J*gTyLUF1ps9~A9UN$=7vd8m>Ji{!(CHdQkBPp0&?6C&-mw0kRCEgWT?PR2w-wWW z^NVygraB%PMU_OOFeJjT%+UWjsPJSV5>3IJtpekjsNW=P-FHYb10}74G5szv)#@r> zTrA>I_0IO}x5B>Tz!?JA5U#%uU}#Q#{L~njvVuuX#{R*{Uq2j*7b3;z@Xa$%E^}eK z-T*z0XL$zB=gJI|Rk^JL=PMdYpFVlp|K_c1pPc9euU;}0@0F=N*Oh7t4C9=t76OD( zHflK7KMzSjym3q`YJlX-%(u99SPXvG5CMRdym45=_@)+GW<_L-6(YnC@gw>~r4_(r zI)-5k6dsf{i;2f^4@+~t%UY`4Qj!1ag}62|I;jP!1Yo9kP#FPGh6|pJchHs9TI4{* zy)q^41Rr+lKdsu5AgDCkTAK+wvVqDf()MM}7eEzX-vi=tFFyyqi(#A?VcO^#17i;M zRf3-XYDN36X+1cH9pV5n2|-vcyjvTN160OuMA(o%r0*cgki?H<+A(mYoOoM_xnErU zzqmVy6F;QogeZmUa2cUB9w0`6ds^#nNmEZrbKAcOsS8JSf_2cA_bcDdf`S;B4e>kD z3eX6U`fjEBy=~vcPiXcX-TTA9xL1aqK%9!B=qSzFE0voLdZidu{sr z&iAdxbn~>Sn33!gw}Y&W@$I>NesO^nGUPo4iFbn?t|qNH?u9=dKz%zGm2r9Lsk(%(ORlNYan^Ec)D(pVr5s@Pp!_dC5=Bm2`+{`HmBF2U8}e>) zeX&TSXMEG@&K0oK%S#g>4K6*0kE=Y5i6@I@KAEOZIW0sT_;G0F^`XHb`T?!y|HHmt zuCrBd2j|CrU(`Y>06H5K;O0#YDiMjppRb*XJ{?M0=?UG^2l8?ql~0Z)xDd~*uey-fj*)C%csJjo*fWK#a^^IU zdkd}Do~gAa@6O8a3s@v|$h>lms7wd|s$alZHgZ7RQ~@Tz|V4yy*GzrkLIDyz&&qU2M~?|gs%ziM#x?|d;+*Vhey&L2XS9EWE zK6KX2?QR5hv4Nn^8s!9*oj`KgtGqcs#JPA2AHdNSoEGqqZ#%`y;rxqH?RC7ntEJaR zen{qB>uWa`Gpi`rE4!?)uh3$aE;%kg(X)tcY^dr{w@BAJ@bIEGA<_pW)k(7;)aGBo`+PLl2$gWuG!e9=0<(P{+(x2 z>`uAOVS)^-x@jU*yxzQfLE;kQ!>kwrNDn=la||X5hDS_lAn!0%GClztl?70QkP~sahU@LZ5mls;V#ec)h^+(lvuN0-qSyUk#wRGwqykIx4gpO0Vlgh$pYI&+ zuvOB$Wy+!iV5++y0V<&qzpn{}CI*$Zt@ka?L-|Lx-}3@O`+ z?ys1|XWbWh_fR?5%2l^t1yDNlY?$#*gthc?pPqdQt`$cKEjE9_(X(osqKTad}fzAdEVTXY8L3nA5_bTKcevl9A zoi1ON+JZ#NfEE6XPVla$9egkiQi{1dG;|2Gbok+9t-olf_drvpZbNLLt7an>uXaUE zS?f14W82_bEl=GVx@HD#*oUPABLV2iE}6VV+KH%A@E3TL<&ZJCKQ}p3lDW_-UE+f* zqAOG_IJSBA!&#xObpI|SwQDA=uRYfmzjl85sBpdWZ5PqOOeMCR#rNp2bX>Xiia00H z=nJat+Eq>oaxIo5y8i5X1(-#}!Hu~U#D3bI=}>ZFv2V$LFKH4Q=dxtZzNXF|S|`aa znIJG+j?KThI>4*6Z)UhJ!A#0lG?>DSI?$dlU2ppW{=xe|1^0B80v)MNfCui z$>FkiML|~VWuN~%mquI_rHG_aJDx|hYt%up(=m&PV=PCq-@d-l8>eh<2Zn$;u-I?v zsPS?X+xKGEC*p!o)ItCI|poOEaFpg^1p`F zxRpC)@sR5mZ}t_*|7shZU+T{@?8~-j=XMhZy5xI#UntlS^t{g=n!`{Dyz0|VFPhI> zNVm-KTnx)ZuF{oFzdO%#srhdCuOUAxt_j}0s9Nm@{ z=`!>Ffk<^5(oW@jQAppyaw~a;hUWeiX)gY;kWDSno+r+WyoK&~oWxlp@W*{v?i-fX zsCSc1J(*&^sMXaiR9BM_lYKc^n%69xko~)B^!#LD&UoLs5t_Sq(wpaVW8KBkTYhq{ zabXuh(ea8yaa#qEdhGY~HX*mTVM5<9%j{}z8Xu)LIn!qALrgQe`Qo9fj(5^%d6?GWOBYfe+yMhZ!{=Z1S*O3udk#hL(e8A1a#rKX{Brbi#H8JYEN zzVPRtJy(<=^hMZE;E#6E-L>Pqk-Kd7PoPy?Z-ZCqN&~&@=qa-b=UO7C*ns&$YB^(W zt|Le`fri}m#oo?>9D-8|Ub6HRJ;`XX?+4KNhlRJiMTre5$I;O5U)C?WCMza;1ZiHK z)H2#GD>d#5%81G0xNMUmarGNi_@7F&j{NwmkN6IV+oFb|6#Mz2t`ClujaeLS0~&^p zNeU+w#XL(`_%A^yWMJdgo%TPzLXqYsrRv+hf5GtWB?!J&B;NT3JG!}G#F)1*BQa2_ z@JnQK(5GM9S=Og!b%8YN`Z#OJdOaXVXC_onYw$W(mO)gV$&RJis8hN#^37cKj*Wsg zhdrftJBHEoLKkU9r*2kT6qI|-vB~dp(_(_+@~k$OCBYV#adoNl3bK453OYCjeK`R& zqZHM9oV&8|^qJG+ZcjNcd0nHf0<{ae3GTYYF~FIl_)=MZ)WP%1nHkkRx?Wwd2m}vo zRs2Q_qg@wg0;gVj%Qv2Sb?$`-PbsD}J-$XXIGIa$R!{XWTJ0~wNTFz1QKC){ zh{BN)6VhRvK;3-+6CNL1SUu*RE^N&x%$a)d2hVzPJ7lTUH?qwFoXye3@GX1is zX#ROA_QB5g?UJ4Ul_YVdKRK7hZkhf<1jXzDwXh;&Ha%y1UOI75B@~X)Exx_p&5By$ z|JiM79FBBC8wp+zbvY$X>~MxR6?e#hdBo;%Q zrf-2(e|qRAY_gDQG6Rj<7hk?y#k2o(*`Z$rMY`?|mG;O+wqyFr z$IhWMFzp-yGoVK?Q2G`Ejxqq_0q;WleMnX_E`h-d0K49m(X+>_m<00_)Z7Qk%|pHIL7uMH?~`-(xSj?3P4ZGeRuqU% z*Z5mK0*k~m!7M`f7!&2?o8?HN364R0Cc2t|0-+W=8d*roT4ksYu!tzMtNypROpvP~ri{Zvyg zQj8x-V+;^Tg;eI5KopdIujPMe^YHZHFduWTsO00==3|*59 z-N7Hu6H+f4!}U|K+ZjP)bM8?9Z-?oCjaR&uETK3ncmYdj8Q{@fi3o=~Vq(GeKS^YIkCRA{T{tg$(r_FJ{Ulc!(Bz z6a(p;H@-!^y4!OUClbh`gO<o=PN@(^QW|gtgt7#yRA^1Bz>djl9BZ{9zhv zCK>ye4sa1acx7~QzuN|sUps+C00_jkjAT4)D1i~f(sNKeba<*@-vvu3bFVzfmxxM# zp8ySR1gLSsQaJBEE0~U&8zo+Ree(~gjVYHEK(K8jx$bj$aFzM44zePMe;i;Mc>b6R zGZG?JYFv=WKX^BC&1Fl+iDrj7{4G^=n4w+{hkHgc6*lGQ_T_+RHi>sBgKb~m2^Ouy^2Gu|^D&sZd$=ywDf-&3q8tq!bv=iu{eC<;TB#uI=-Fceo>{9fj=*2zK z)yRfh+H92y;LmBWC`uZ$8bewc3CpQ@*IDsJFMO;CAB@Pnwxp?Zimy5;R+M7WQew7L z;{g5>vcxf?9EwZ+a5cSt!>qh<1}yOhJNUfa0VHDUhn4{7 z)ej*IS!|r?$z3G1%Q-jc9COx_=ZIvr#KTe&GHjmQXSW2>QOwViP@hbwAL8kl zAIuX#xD)qID>7~Vz=rt#V&T`Nb4Iocq8=VqdW+T`UVWdJJUtRDNwG+h@3+r!RE4>2 zQs!%@tt%$J%X40@HHuR(f(*U91hrD*SVF>5|3Jg&KB`0O%>(^i2y-YChy8!BuoLJ9 z|H|)^o|e4RR-%>GoPzOcU&0GALS}{34pi8#I)qStA7t9!x9`|b!Qpa z6K#a@$6-$C_^#kEGW6pMn4e%VF92Lo0gLH^CYokS_40*8-iCKVuK+U4zT8io)i0|e zfoIEqY4`RwnkX`BHUx38HItGup{;(*KCe1vCeZ>1X;Cw|)IER~g?CVfDO4{kf|?n3 z0F5|-22&RJ4>PU;NGl*xLk5w6tczF;pU!|eJrAE(U&C%|#dSeL$ z@jQ(jma#9P&RxYiVkd~wk!6+o z$lpErWF^8{RM?&V-nKTym0hPcZurCY$0gEVtK4@GXj&kJ&luh3PIcydW`B(XCcbcrd2!>N_MC!$$kl+ zKr%0f({|6I5HIN_cp(B<{=x9j|7On0gqW9Vd-x3fEBGYGn>1aSFnFlVT+YcwlaD6i zeoB*!4*$g-C#O4tp8C!x6Dghn38Z9dI!YfHaPUhfBGd;U+29C?>59^M3A+v;J-d9( z0p*wC05kjuuwRYNx35%R@4WR0c0~{TY=8F(1=e;-qQlo$#z=9iZ%cqsPQ&9wTn4DH zw5cY8V;dgnap96AIDT8}`RC4R66uW!llLs?=9tE7ag&zl>vgC{KX1BlWmy&t3vqlgR&YUE__8xs&24MCborT> zX>Kh{H03h5tKNX&iucyOz36hWm{%k&S#KlMqx0r#-;zI6o?4%P1&W!WY}P}JfEJ!P zW${8`UOk7D>uGF8*qdC1p0$Zmw90sQs}Jo0*C>yij)Imo?NnNUIjFf$)i?Rpk7^cl zl}>8Ax7lqu^dQ`Nov8CrlGJhDmSbY)qVP+F1Hb9Ml>P5>3T-&yktfZ~x{}+a&rX3H z9ixSOj*C$>tPgu%o0`pz%2l9vhxLCWerBjADG$D78bDEIy|wBbtTglW=O;u&vS!j{ z$B40IaLFV7ib$$)Y?|Z?UL96R1DunHla_Zwj%Jd6?FGrwC$a-VHJs2Ac|Rk0EOB~R z)=$RH;md%~ecaq|t{fwJ;+Clk_pqIOeVeGp++VPbX!!QXJ&cw^=tRjFavkC%sTMPB z_#WSQN4sVvKG6vYxJiFce)IF;pP4{r7= z%E|1N1(zT1dj{>bN{Ug#+|X8s&)CE&-xqXQ`-6; zSEAiZy7v7cKd*~0_^37>Gb`Vw@ZAgBW4cJY2>;no`GZ-lmE*=ZSHJv&V)Wat8lkvU zn95JUW42dMVrHYCGeR$c9bm^jjE~&Z0MzTZNP^qP9(fr=tIDBPsx#mN5_A`o1 z>xAOOFsNB?LXK#lMS>@M{qro95@T=j;C^eqcJmct%e=k)jmQvgo`;%s@1t`JYl^;n zlwZI7>qXSkAkU@VAEV-rln*B~KlT2cyeGo;Xxi;Fnn4afJ7M_C@;2~z?B%Z)-=5}N z`U@LfdCV>Xy7S58=i2j6CT!4;k8^+j*m!C5_YcSYG_g*>03nb!RMSX8^Gu=uOTB=g zFRZ7+&}wPie{GK%+)U)&$iaUuk>y!+`d15S-xFE>l3!K;@~*ps1Eecf&s>)p|FnO- zp%S?EEqME0bGJ3bVDb(dJ;5mkQqM$-N^<3Ffugnv!u-6SVA9y0>yrWS5pp4?m*op_ z<{#javQcBx_94l24xIt;#zaj4dx{z+Bak(K?d|r6?tpq;bcGaL(+nIOD8;8(_mSyn zhAoVBgKw|4g6*L^`j!GmrX-ocpw|&v^v3b#l?o}giq+ikaR2;5$R}ytomcj08pSoD zpC2rNtbVA!3VFclFZpQc6~erlIasp(2U^fd_+e4${jhqK>pK&dK$>OTb^d3W-R8d8 zk-4VcOcLpL6};wV%ceGYH6Db%zU;4gkG8xbtNVQCbwrwG#k#1RzG{72bd6@^uD6`w z`<XlW+Sf1vw^eCO!Vuam|lbe5uYsySB~c zF7CkTdT6DB$HpCk=m8lT;v%d4Ec;^2iqx&o7f?cTQTZX1f_mdl7Naje@=T8|HYX{6 z^n12AGBEPJ`D>>l+HrSr$fTs%CyplP&vq*RDb=Mt=)?X&G!iUG(T0VmGz7l_y$wp9 zO%x%U8LtAfR9#Dna()DZ<-)uo%eKZ>x#3>5<6b&v@s+u69tMeDm|sQncNZ%^46xrc z?C~ynJZJWiwGO}_I^ze^UhVg|iCL+uL%OWLzL;DQxxC=J`@B`(O846jHdz6UHrhz85+k-UTY{=I{*PtzMe>NEGW^WmPxyLxj7X!X4Kx=9qUG*lQz1?zUOHzLrRi$#9W}Kd8*qO%7ivzKC-2-!G(?vVPkgTr+vsuMjjyPrD zytD+f)lw>SgCd@UO?vY-8PEBCaQMg@kbx`!vX(CmWj1kEBK7)sZrP(Vvu2 z<9)~c*p-1faYiC$ca2tXO=(c{7xH04!m(z87ih1O4=@6#T|efoFy<>k+R`<^s|Pg_;rM(@bM z-n<|_590c);MV>8*2^&%V)m_k#-Qlo$>=4Kb&wKXYUjJ!sNSk${Yg7izn@qAn8i;lrXa`5kKY{f^)}A@Z~IN(em` zz2y1y-v>|{88-0Y-B-cQesaV^BV(o4L! zRQ1S0&4Y1R@&GgyES-?b?>wM4hS`5|H)0#lSllntixS#&GvDU)>N1D5pf6jYr%tNW zm%v6dAevC%AQXiW01O(95#$gPigXmwGR=RRO6SjvE5Jf0!^d1}y7Fl}bn+^5kWVqK zC-c6}0)b8;>dl~KoYTa}<4{YCh{m8)98kG!&?pllK(;oOPLt$BYc7Bdyg$%{Uak6+ z0>s{Z&2n5%Co@9nh;E|-fT)D-6#mf=b|B_K(}$18qM^vTN0 z@b)Y&ttv8qSgi*8U0rKIof`p~BYr)fk*t$cMgWjg6r?bg_Sq3F$Oz;#_hQEXPcYR5 zK+CtOx>N%9zd@)T!MKwkX@fUIQsu_z59?!n1zx3Y(2$BTV8w)Q<9QfCG)cey>W4!* zT>=q-L*GAu4eVDupqJ#kpU%OW>>71Vm|Y??vjf{dt%XUZr#WT$)e&SAU%|p3XR_>2N9C zIe$ISDl_wjrl*t}ow{<8(o+;*@m%e|lJ}21H*R??fBm37QhD_WSshyI1@%&?A+M}` zZcqFS8F073A@ob7daw`<2ofNT1f8JROF@d6D8>b3XC+mrZO|A1wvlHLVH|isH;z{b zdVUP%bZV<^a3E-{jT&s+GH7sePjmBsnwe3;tam0J(K|>pUi#$ySIi_C!xxB`KH-ya z28hsAwypsvnTdW0eSGRWXV93-0Bj|&q7KZzE#TAdqQzJ*-G`B(aE-R5`c%7`hvVfS zKG$4_p+{&}|4OZnpxm!hk^iQ&G`_ek%D8gLe^dJ6FZtz0&4>J*5I@;D&l*dOfuKuy zoIWNlkFNyzX1w|6Gwk~Xu0K$&)K{N2;_sFxliTf=(X&c4kn(VSA7E0&Ug5&FfaECv zumgafLuEsff`vOV#;c&vFi2{(HPnG{{fVsWChtA$I7~k6zeKcf_~4NlhPSw1{!BJm zgFwG?XW<8Q%2da+ABs#f>Lefn0pZqi<8f4){rI44EEPrxR!AB-ekgmyHp-+{uf6cj zVHvD@4ya&H5+Hex1SXY{|zD47cFN{MF&g4AL9(-Gvs=J!&aTwxmEs}rB zg~BiNbf;XyY5UnQuVx=bGne#A&t~7`< z-79{tn}C_&LVq`7u|3Rr-ikHB5qJt3??Tb#%WqlaLS-8G2uP}` znMwRe&~ne1-9{O%5aa@zZ!iwf(OylS+f4)E#D76qrRFV9gWCPWW{SeGIt_%@&soqb+T)6PPnTLd z_%ej|VkOS8YL!cM4m>Ub^`d|wa~n18d-==gVKhWtsPQ_=bWSO>YlKv}mZoBp&ghKN zVubUCf=|-x}MQPBujzHpElVT@TW`nE3hy#bAL98++df-_m z#p-y+;cS4U{H~(b?nqeuimBqQ<1Or)neozZ4eas{Yg!H|Ejs47$lUyy?Aq6Th}kKn z*H4vH8=GDQQ##^sxqn({pZvCWljti}zNQ`4|1fyi@D%R-@uLs-2mK*8PWs7@IwGhM2=5o7`7NZ@b3V_~LgNfEEpW`P)hCZop zKV*-k%0en-W53lN+HIqkwwdo`*UJR-eVb5x^sp*&KiF^9Tz>B~1Ybn?y58~=bmhBK z*iq>|#~^bX`h9abc~DP814=vT+=?{;$cu{M$^;_L2ElmROYhP};BHhk^hg zXcEA2Kpp!cX0Sk@g_RLm>ZqD{u$mT~Zvq=86l3V1q~>P07;eTgw=feaZmFc^91i%Y z44fta!B;`&c665ry7;|n{{7OYV97v$mknOJt4iJPV3T`pCuQ*U4^B24fJon_4WPBAG3sl$+|8gZLgzb;NMVwlja9t5Q*Y7VR%4vee&%<InY9#bq&47$H2Q?3@ z>E`x-iC{6Lsd(}rbXb++zv%yov2BByy(8b@(LnKoKG&9E263Zautf5KG@(MbEfoV9 zFrEg}q+>gv&)Bs)*VLSW=E(yFli+xCQEha1j@{z}QDt@(d8LVPB>}Je6pFibQ~gsd z79Oe8FB&edG}JCW)&#d_D}L1o2(y2?Z!7Xc_2&Vb)RWd(AG^1mymAlKRU@=CSFyqE zI_JOK4*F^!OJ#MwD}?#E5sQ@ZUZazjdYOZU-V#iP5Zk^_26(Vu8^-Qi6#bXMDI3hJ zZHgr9=p20=;fr0>Fc%knW7K=+hCWf^Du?&PabGHdpLl6AsUsQJ0k0Z7U#Beq1Sb_9 zZRIKPM^w$UZsQ_8!`K^`#dyP>$EK+~yjOpfMMYclt%l?Mr}huFFW&y9_o>xq@2SJ1 zL)zF#JpY5vi@)RDnSlq!^MF`qRe;EwC zGs5JcJNFOF`vj~BQM3;SxR%C#A3xBvZ_hqc)VQZ}`QA2Z_y}PB>|K9k&QzJr?J(5~ zPa4lYKRgXeU;K6Tr%n{dqcBxvo*(r7%ur#) zsnSOSYOEN=A$rW;Okm}a`Zn6T7bRYd((LCwx>`M&N=T3_s$@V5BO&}P%Wv2`Y2tM; zPOVy`r5?@BA2PA}g zz0ditCjGgf{l%v3)&$3VR~>)BZx+3HrlVC#1@4FhV`EZBCIBcn9_O!fk z)XM<-s?;RqYc90p^FDN7-R>-+6foWl3S+B8B8Xp79xrtyObD`D-1wKy(&?tln>sO; zSfSKP$z&dKXLvX{Z?=8<i+dq$PvzE_1iYJz0@aM0-Gbndvm>y&eD|K8B%Oq5F= zOxo+UJkyei*W4yRw&o9)HiX_0JXA3R!ng5j28)^oD{r0VCsIDVPciI93emaPWKh-H zbXhI1GLrb$v|mGupkRqEQ)c}TqW66uW#N-?zQx(*#WUoaj}b&SKjZ0-xz;Lg;^96VAo$b`#*lj-BeSBl@`Pts!js1zU{dp5?%8joZH@@wieY@>U8?u@Dntw9k z#uc5F^Xcc=52>4n=U!HCzBrd4WNC2YAcEVuIaAqTxncA5-(c#m5Wv^5oUW7HnPTH| z_o>5sv_G}yH$w~e+6Se8H#h8WVqE}Q+k?7wz14oxvP&S9gYzl?Qx)&~)QXd92Sgrp z^VJVY42{{D1RlADNUQ~?n4Fe;{Lu+lpk<+yRjF1YcaU|-Igh8Yf4GBf?rMfEb|&(K z*i{-P{yO@@gL9~+yY3X}M`F)46k@fG-|;rF*BIBLWjxk|`XU_l%6YkPqP*muG9X)RB8nI(SnvPMV>G@X1A3#D#@EJT~h(EC9q+kUqbzw9({ zs8KDYgg@dW4#e{!u@Ac9Rz2kO_gZ?nCzPJ76iukS_&cX2+%!Wo% zuAfXWsA=7OTx5-SC$Gu0!D)6UsB~wTSI2T_Cd=9z7%b?i)rjupP~HEYYb(9hq#)3< zWXhu|O6PjaoPZWA6lQxWYR;=FT+)`0 zxg+$2&s51@mD$!;s6oK724~*cYRxjl>y!J+tXOydbd*7Pq;ac+$;lGc&n`W~ARb~j zMipF8Ec9DpTXG*23)xq^B6NNC?x>L8ZuOy?8iQEbY8sn~;2M!H!-{CK=^=M7nY}0D z?#+Yl(TYt2@@FN9Ee{fFgNbJL$7GwS(W*ETA+2=Hr-igFvD-gTd$t8ehL$8&+$-4X zMFxe|BKC5F{<0;zkq2Ut2l6H7xun$}h$YLW$(76d$3?m}>$J(J8zz4Hq#h}RI$;jz47b6#I zYori>pgq^l9$$eGIZjwP?{omvi<4AL6)Aqgyd@9>^7fG8a+n`m~&oV|A7c;haxwfm}$L=HN6&+G}l)&2IYLGk&y9pxmkik~*sT#s-HQq4XWv! z2UpdP;w_^c5BuwOn{n;$iI66Qc`%X;UhcBc`EsXKYM zUUqfrJXGzn-urUnC5cSt$U0Dr&8X9ENS=ByKvSgv*|${9kN7dd&wXGA>p@KL%_5lX zUS}{aMuP-m1IQI~pf%G%hh$nNeVo)bsPm1>F29S8mSM?|n<}5VAvQKfWva87Ii^>se>=c99?o^dw&e?#&ji2~hAi{AxIvsvNZvWD zZ6Qe8{_iWKdGV#y#O&QxbTvs*Wl2N{I$1z=uB6LjuTFnqRu z@eG*v0v?!EZam23JIa22wT3)z%K(#zB3~J(<#_M;0P0qprq#J92vu{0u|}3h97H}$ zzX#AfT+4-J0zeZ~l8=JqB$hfX!T@CQ`*hbGc3yCRtMq{AQZ!w2gI=2K8dcLNKqb2` zDwe%b!f;5Yc{%^2i5*jXRi~)Z=BLf@4_)RuxE8kW>{4L10nc#TY^V1o9l3Uy=EnQ& z{ZS4WUYD{jm0`S!f77ZFm1-}fhL~0)P=Q73tgm%J;&GLYEBI>XXV%Rnwg%zB|dEvRj z(wcN|>RM!Y*Ps!o{i5lldEr;m#cVS4+c#`}Yzta4S9IjZ!Y|zvQNkU!yoceT&&SL` z9*Sbt!#Z=o$GkT&oZL~VJe`hxxBsz;XBQl|{K5D{v{5E5xeftkB(%V`B4YQ|92LLK zvKw{&d3}zy+v=WI$<(Vs}lhkT;B{#a08cVhbaC69e=P;1lRy~zU`co(uy1Gn68?8hfOhg~ znt#dXr2W@wWIu~_D~}PfdiMZLy88=g)=7XDaSCizIwZe3s|8DAOQM0Gk$RA#gm6VF z+h)M1=k#^cE%-hHJoXtJ&G@W=MQ{}>+KVW50)Tke5~Q(S2NZbjF2V#UKo`>#L$>Og zw^}5BwXt{fNT9}oz%>#<=mxMBN~shJLdb!?FesP5VnR|xaI0WF4%TuBVI5k(WXDy| zKC;wbHu+n>&{z}e&{_h8?j<6AbP&wsCBKg6vrf#gPOA-o*j16ZfBUWH=a8JIt88U! zmk>Y>&>EX?*ye7v$Pv|Y3<2I+gb`F{|?#MK5>a{IEvYC#r0UNHqoe!%WC4C*c%$FKR@qR+4 zj-0k&6$o4KxoUya?Bno5gaK0cql5@RI^^madh)n2QH4`KNtAM2D=Yv@yi z$S5sckVIaLw*I!rl$A#4rtlP*r59=Rg37cc#Xg5po7Xgcw@JdjjJ19Vw0l1n(2X9?gM zSbtqlGevfn$4G+nlz_a%glR%>>Y#W{QJob?O%xG2MdmhL6Ibka8{njvuAgs5C{o8+ zIEy7ssZ0j|GkpoZn-nUYOOrj#SV z`U9AS4NIQyV7pcO51k}`Q{8rR=}o%g)@diMiaCruHb}d8;OwYy+^X`#X!i)RPE`hJ z#P9YCc175^@!9?EbeZRM4RCP{Io1ap%Y^gsr~A9cN;1^o*?586X?)z$5^RbkuK9c( zw_QAH126#~w_CWjq})FZkr*j~%<;cu({B%)4O8 zPdv22-f#GPH(Y$T-dHcwTrea_sU4R~ze_It_vR9f&kyYC2P^esS@h#@y_AT=CIYY` zi&*ieCU1Ah;l(nCeCqy4dNdH)XX;%ouh)Z7TLz;Mbzu2la_q$aAPc5QS3i?Q_x@?q zB@KB~ogj&L-{C-a86b-dzs$!sYSDNo8PEL}z?_Z8+WQ-tyN2#bu`;-XKEX(TJM#1b znd}dSeI-bZYfH~zP_pa7@JP33i@q$iH~vbq3r5P@0l3Th?f(u5Duu~AJf;K1t-XGN zf2G-GN-vDZ3u)P@om~yRWGUU`8ga2E?9rl$XN{KYQrFD0Z4lH^VVJ9H#jbLEkC0oB$BXS8A^b3A@>|Y(H7L8z- zTooYpv-19ub^@@NrV5q!3+4SzxYN%QsmV}*14&P35MOdZZCPmc0Jbq8dhLYYA7K$e^F|r z3rd$Tic$ra0njkKwji}(e=qg!v*SMS+m z8SmrqY=So2?!-K9H77Dl2e9B(jb3YNcJ+~X60q=RbXNcB4bj9B^U?SVH99pYrAajJ zC5a3VP;_OOkhy@G_lZBQ?Lr#mL~@T%&C9Wj5^n|Sx}`}aVMTpW_m25+QB*E8t)Ige z$w-XHSs@wEfN>Wj85pYt@_<6n^7uF)Y4nZ%?@ks|?3d((%a8VcC~n? zCN@IHkIy8d1e4ZmwccW}-lIV+c@8WMsAH{D6*;ne_%g|!ezf7t>`Yz9TiTBf`rXQTWB5@^$n)jjb`Ywx|& zq+0)obtIY`CCS-Qc^wi316`lI(SQ1)Tr$B`Z(%JV8VgQ%3a+TG=U&6x4luO&!M|ax zPCVu3g#Sh(pl4LBOayNO08$~sjK;!#b>Fu@$KS#VMxsO>eijVJ!Y_NZ{oEiEt;%c! zqY)3D`ury6I%9r}qn6Nt%z>4@6fMZxg7{p?U_S_w`qB~4kOp8d_hUTui1Pt3Kq?sc zS1`_Z?#K8+%*p*M-fWqvg2-~1-Lv!j$y5O&=xHK2sap52w7F1?Yc*Bz{A#q5IhXZ4 z&g90={xS?Ys8R~dnla+#Jr@Wg&>FEOUV$7-|64FnTJ(b^3vac9RUieLb_Bm&HLhvC z4Fel0uBK}MKu5@83pWUH&(_cn^kXN6%YX7p=;ZSXoid&7CjFMtq>@YgOmaD-l|gqO zKQMW`RFNELEXh#J@<8NY$Pu-vO{im(kjkN}dIEXuk-ngHm@+|3i?nzrNJ>pNB%|x>ZiWyJTc@W~8t+O*} zCJ>EZljU?{ON;H|5m(*B9ffguX{kmb?aNapLJ);CHnkAlO18&RpgI=ed!@#=7j1aO z5)O>wGUeB8RfFeh)E_f6Y){Z0aa|npC~J@z;=PyA9W6Ov*K_T)&P>_+wRgs`A$G(T z$Rpnu;n{QV=1YJr*i87z0M7!pbz{))Vui=G2q9v(0xtRav)AVW3$#oT8qfs~RgHB; z`}73RbX$=giQzDrpQFu93vz4_&+0C~m68FBDU-BS^$T~ZJ7C(s6>Uc4S6m4!)vkW; z;;aAI{MKE`7xypqL=Gs_S_O9+rJel_6|BBllPlz9?o%W07Zq(4)1WZigq!YNH$~Cv zR)>SXmr35i!qoz%4YQLuKf3YEMz0tgI^51dH(2t{GKC+3?rDx7&|aw$AJ>WS7lJXl z>g=|HTx@dA9X48vrt>WH{@c;IsHvrbG#v9{WsV_LL$-0V$VO*J+FkzuKPY}9Q+<&2 z;wg5dM1PZ0%yV$H#_R$D6u>I6DilbPE>AvuC0kVSW2VTl({e&%3~_rxc1$T|QtcI= zphZ>UxLbyY!8U?lEk$KRUSq@=jj4eKh1k?4{HlS~WX10))a%zdz|@DmooqD5>zY_) zl!mB-=cRK!bDJ8+oklH;EUlOxj!VZ_s}E6t7&e0;YsE+8Odyy;NHk_z+dy>KT&CR8 zpQOLnE0M+%J`@#bDy|feZxFuyCRO32Wj=@9rzOB%Rm9^dmy@KV@lt>%ZKG;Z#ZF=&58tAs>w9a?x<5yvl zn{!jfe>!vRjkl#G2cRRHU=9h%I)JUoG4c=vd%ZcB2j@W6PU|nXRZJWIZmWG2hKO4o zH`+7ZFJf`Dl**sG@b)pAka9PESm!u0#ol-#K^7#D7IlSP@0itj23Ay@l5c!NLK5p9 z*wVsgpz`U(E&iAr2Udo^@GFOUyPG_2MdI?&97c=1^BVI%^N6&%&`6S0qY{!NLaF`sef<7}`+nSy`+dD%*L6Lgblv&!mnWUJGxi)W zCh7<5c6y=!E0Upb>kF;)c8=au^3D-a>|!eZ_&Uwcx`M^H1?0@*Vs&c3Zu_LAuO~`s z+#>q}p{EIhj?;;zUotg?%LR@`Ur)WTp5x}<(Ruaa>55(ULVktuZvad8`kHAoNbKZ?C{y^`KGjTXISMg>(6s6bv z0=jpd=|t;5KAsb(C?>kv%v@+oYpxI9aTmVLO7!UH&P7E+2}$KI{dbdcFYTdb=`$0MyBxZpF)3L_38s0WYKBCaQ=MB=wWYoF>*Ti4{iPEr*j*$; zR zRA5wJ5M|jjESs~rpuI~DS!S8CQu{5xYP=C6JK(AQm?T7HO4QZS{k5usvV29-OZxVc)Mat-FAVu5l*Nh#+`i2($X0O_M0w;`5#itrYl*&H{mvqNdEp2A5l0*w^f9o0hL}CbDLnG z<@cxoH5-=Zo;?Sri9-uduedyB0%h$#X`5v?l9Am_bQIBQgRn&LMzID8X<72 zeh&Tp$i+3W;-hM0Z?s+DOW?8fES1Q^-HszuSqg1@+y~);-M^Eal6}8Slkk4)-=G40 zf`NlxilAep14%IoSL?YM?oL@h7|W~I_-X>TepV7+6RDFpI>!U3=U7kQ@cO4YE}2|vXuU+{n0^K)SAoZdHpAdr&)zAK^H~bzGSU>NMn`Rrj{McIgPAYlt6?tm%Db2isjn=Fz&>mH+}s zHl2@F)i~YyNJu=CI0gAP(O`P6>!tf=0IWU$w!I0PDVrz4_8~mgBghh;Z|J^Keh0*p z#yD*75u>K>iZrf8hDj1cZ4pf&1!!cM$%W~!uU(fYWtFg63d`l4$bT16DuK1P3#@tq zO8$5ePIHwHrA@Zialx|szV+X8_WQoQ$v_KTJK-f>_9HEM*-52W@v~X8{ZtSos9sKf z-2G|#ud>v+(h5bl)u@PXVJVZHP))3hT31J4!*L3(IrtAT2bwXl^BXRx}3f|gHj{s@A`5mKU@g#+i z{BCD6UWTD0Ii790@2=)1*4F#$61UUPaxt_ZJD>^77nu$aJjGb3&tAfEq~p#J;C(=1 znN{L*eu(dM_%5)OfP^X|055a4%ib|vwN?&aIr0;W@)yM)q@*iYDF&8f#BU{Cm zRW;T#2tR=9W|(VBXXHgnYfH%2Zjn!*m>~`8MP9Sp=iH$`?+DerValEg~8 zKcxjqS<+ihj(^-DWx-V|p-bKfBzqbZ!S}snX%Mt0u9&O*jhUxMhBuu=7-1p1Ou)ym z$PNzNl9o_FI6KYjUb0sqbXW3^(PcnR2$Ayy}%xIBgRm4T%|%;4A|pU!pv_Ph}S; z?gGQ&_~_qM6q;+lM3B;3*=ZXYzyEbv+qzsxxyn1Pnw%EUBGN411^mYveNd!`r|wS^E0vTC{*SmH0iLZ&_^?@8jRXqqHH=Mf~BxA!8DrvJr9Ccv-y2WL{JSEdu6nN)&Zv{rOV2DR4zfxE#51 zfnTEK&nSEb6XPlD<|!m-3KYkQoaUlqu+S>g>N_(ab&kawQD(`h%2O@Cbr41!CyQ07 zjrsw*y(Hx)1omrzk_=GcIJbb$$ajtIrG0zXvC4`f6A=k4&yj(4CmIX)ey3W6l)3OZ zx)whPIoQ-O9R_2XQc2DUP6- z$tPc&f&`JFJ6+?tX>hA@>F#cF85Q|)d{1*i!Tn7Ak}&D>VKN*(ELztzM-JW)0T=6+ z>9^95mHa|OsH`m&6i-6-@lMDXfWxS}S^N`FYd=~17FQGSZw0EG2(s)hrG^Dt^1)_H zH#_7&T71ysP8oNTA{!FqC>i;T2Gb`4hl){pB*b?vnzCe`YLfWCTzl} zve2UJ3!*v%J=JV7>+lW;k)DAha{h;id`|_naxl-AP~WJq{T>aP*yuGXdOYRak(GeF zHz~CcwO8RX|IE*l{iV`gZs$;B2C=AN3CGsw2%g~b9Sgsr4HDzVD#I13tj()RLy>7c zwn;H4xv+h+=2uN+D+PT{{rfSYEB1#8H~|@_$2(tYqZi0Ld}jvok%}3nwzV?%2DoT@ zCZbKl4y1BQysw=3f9WuGnv3QQi0wxUH8 zc+7HZ=908E5j8@<1=vNJ24b?4iE$|yzVIG>1||OLB@QO3chfP2Ws=Q9@o?d;!IzuC6 zI5>=i?4aJVq=5;^(%X38hjK;VbHMh5+x;Shjfs&Z0DO#u{FB=MH~`tQ^!(=1^SgAI ziwSUBACJ9+PU?+M<)bapu(#sw+Hw;J`p~gQ#vBOk%pg_Z^8C$Db zzZgIFQOv$k^@4^u=R<({*A(qI)NhSZSg{YGJ*-Sat#MK0J=pMj&pw(y`r)IP1W>&8 z6*SCq{78NLAQo-AAr%I(z%_WTaWTaJ%P-cK{OtC<7r7d{NbUwl=K)goe^R8_|Mjl} z-=%}FH2ABZ$ka_dURW%KRl>e=2HeMvPH+xD3taOp?zRm z5|71&sY^kQa^PXYq8t6)heguci3VQfpbSpm84&V5S!(%0e!T+R>Q~QSt=`O?&E=8J zb2f#0xjV)6f%=s^lN>WS;W}|yOS2MrXLaP}?_&uc58mqIz)hB*O%8r$!Y#H0$aX%p zmInS|xcfW}{E&Y8Vf*vBRKq^(=Kw!sw8=@Cx4dtF7H0-rp~{Cyld*k>w)-mgO0870 zYB0)4W9K-^kAHXH{vqG}bwrUAAB(^fr1yMr{*HWMy!FLiDte9l;#NJ}Yp=^*Ec%Z_ zBsB#y#2=IZLEV0$zLQ}OI2fq}%sa9|h$=dCt8{o8G0%Gcfmz-!;mcbki1sa!L_+va z3Oe=~@&)xlR!6{=8eKeXgqDk=$F@hw9<+tOT<5l7znPS>brx%0UiLq~pSz>Bm@qoQf9B5}g^Vlty~B}FhtA0^zRr4eOIvD)kDR@MObJCEW@M$Usc#WSScM|)YvpByf9WosD^W}Km z4HYN|_7NNSb_qGiL%!wgFW(l{{PvkK7y9xFLP*0rNx}>gLT0(|uGUNtTr%c_6StpO z-#)d7E?j(hc)yf0W}bw?l*bg$byO8ug`XI*F%EM$&4JS~v=uD-Ts{Xn*(jo#&5^=4U?!C@8W^lZbxqWKgcz$(P^%YQ+&g?4Rrw>vW^p z{P&xG*FtR}u0jw20NRD!vP%dupsw#Y35t|#@@Xvn=O%wcNR%%?y#0%Rbbabv-c6)s zub}c0amXO&n<)<3L^rMS(h+WW_}XMwuoxlJ$aoQG+HW`PQ_-Wu(@B*UB=Nf_}2E61Qe?{Uvg zcj@i3q9?8_qCrK%42Ny)g-rJcN8|7d}hb}dt6`cc9 z;f3;p@*n22!_BoA5Tm)pIlGG)V~$BDZvA^pLLGTPB)9CVgco85D>`vOm)~;dsKr&TB5|`@}Ilo69xn`XG$M znM-y;?~cT39ana>^Y^gz57|i7<|8jeucn!iYXg7pK3f}<$~6cus@lK3M(35rp6bvj z%!wWa^@S2m)ZVvGj%#hd#JkNNPVx>z-2g*x-Xqx;ukW%iggEQE$7X+GnYU6eN*=hODihkikB{@WlZfA1A85|vMWjZ{rpqJS?Q&wJ>liuRw_ zt}3J152#2RF$gE&w64K5e2f%oA4%Q3(L#@2Jm6I%ZPqlTn%)3Be$O!M;7l(onmVnT ze$teE?VnjnZh%Tf@RYg`DXso(f9plMSX2=Np@&mlXYtBT^ zNoIoH3(YIfKaJoPm#wUS1^dtVvrs2D7Ia9qcdit_jil{>hce1xONOoNK85eHY60iM9>`v{?wYHl3jHC3^EXVZ| zO?3+tg1w>mT>&;OauIREQ_cN>Y0OTk^gesY(eaLO?}uf>h@6Z@O= zIM29TpCvy*VB#z(O&Kg4ji7tc;VA+L_br`@glQc^gu)C`{F!n}nX?&3ec6awSjA88 z?vL1~l+ef!GOjjD$rG0WR;a`h8R3h4Os3(;#V_g!{1~q%7Jf@cm8tVCUa}N%O>bil zQ7{g*GR!!HQ87FA3Ys6lC#t30>Psf7EYThpTQ4mB0sFka2)}^TkzUY9XkC*2nC|ij zci{PxZ{IYIO_Uh6l#frosM2qh?rIs>j+1>uZj;KV-d-xp=bQy*2)xD%L1#q5-_o?SHYKU@)Q0I0|{3I zGKz-YP#tncqSOtGm^WSLni6!Bqg_C@0l~4pk6~wV2fq_Ia+;W+62H z_%~lnMmV^6h;DO`dfaNN$rb8Y42((9V`FSH)HT3FoB`2y;fy!5bhJ+SS+D)~0o^{z|lsOwK#2LlwXrZRUbCUjhMTDfre-rO$D zAnEhQfmctLhJx9%mAXcWq%%BimnfeXj>{Q^>1qg#bz#p|ng@dz%ps^1>MW^0NbyC@ZB_b)V457tA-47n7oT7GZg9S;Cp!Cq;mTw zkL_u1!uHS1(bU(WOiV@8apPH#38xm3eUYWqD}o4u0g_ZVJalG*uNv|r$K2iTB)-o@ zdLC zw4&aa_c=&DQL4=p#)q!xA zE2^txxQ4FiI=Z=Fi&j{-BUUHlfgedZ{AFf@AqAPn3)gtg;XAjD6(l1%wK4_{2Q~(j z-2lvjF*dL4u9Is=PwVT7*z`lzBKoVAdY?Fnmx};+9fCOJq&^ODm$FTFt79|*Epqb)GM?qfQRI#2URGA*11Uki3is#Ztd@#ULrDPVmO)Mw=-NO}`ehoqIlT(S9CaW;^sqokMGMD5xC8sT zSM1q%HvvWEGt?(~VJ=A?jQCPZO@6O}#$%BR#YS{<`=*y~L#*`v9lEO7{#)|=uAujy z`vi$Y+*wuV=uv21ROg5mVAT{#%H}e-QYdd}$A9}ksifs~chY@E*|4(>9Z@8@s+n1Y z3`DpfhNQ>R#@@&*)bJftmkNK+2%vqguvZ-AcY0c4_s|>&izIxP7~eTsICz zoF*@wI#wI}2;q+Jr^0-YV0^K62726G=A6$oGBSm+?dcoEuCT;#HRu5pg}^LUcZFG2 z098Vc?J{R;VLEIKaAZChuSUli?P1_YvDqasHTP^z z3fX<^4Ik!8J=z1$VLmG|O^Psb!-9Vsas>oBC1 zGYGC%KNJc+gGOM+uDX)gm*F-%k>a?M$NlzG-qMJv>|F~_imnOWzsLV4@gJqA4)|nR zNcQ*RsWX}e)aQ2lS~kL4-S|Hb=-b^HL%JfS_4nY;-j9 zK`zsFL}AOL$L%*DQM2|b6n?J${Rhum5`M$Mv8-T%jUyZO<@()%b%1wJ_Gw|(;#cTb z`#<6ixs*yU_Mxg2aj2n0uM0FJ^a6gK=zL_yQ1&k!D%!ffFBZO?&f>?3n6cBv>#vT?th6h=R$nhnTA-9 zCC-{m#mB3lmOozDPlg;U_6q)V*;=S{Fa?~wgRwgWXHPQaut6u5y_8e3BF7=A*D@pd zSt43yWDv6@t)k@+EWF7g|0N{C1{RNJp6B<5G&QB$0v&M7@b$*iM4w$1RlUz~`L4E? zi-6^-*Ho}{d>bUvn;C&+ChUMkwm}psfEqNQF@h-}R2E!(XqWO3&-JP5@~N@FV{vpO zK<}ZZfh(norcP$vDxFaqiwA7!s^z3<>hcz zddl%Ysqihn<|HpI98(fU5@;1Af8l8=P zQ%=!SWhB6?Du4*@!)Tz_>UZ5BJYAU;Z8Z*7iyU~YdCJ7yWh(@ ztlijrd5ZL4usFNr8r+}l%Hb*`k^GL1>nM+7LLcqo4Z!_>7n%b)K7T??|Ljkrna<%Z zJ<8mj#=ibO7=~Zy=dYN4aN)MZumlQ?iQ|_;GjiVazBt2&kM&FBkU+^f+)@PRISeGP zSLVzD4oi@XT-gFFfwwasBg$-2fqw}vN#yO=-1I#=3ww*(c2-|UZw}zi-#w*Mjy8d= z(s}$+_-UIP9uD$nDKKj}!dYQfOfKx~5>w_)Zjuc{VI8n#cpy0l?&vZUO4Zx)Ei2sw z-un>owl|;eZmE9-$j>W2(+dyQm+@Q}l<-8G>_$^(8UK;@JY_RH6g8}9LVa6LhaCDX zckvK!C#zLhhF*f)ZWZzdSjpb6dLUzzC)H|fpppsLnFi7t2NF#fb|MhAxA9nvm({v% zIN`B!I&_FqvY+pL&eSJ@3q7u;q~{Gi*rcx_gap$dKM9cFb%>6g`$5j@Gi9&$la%vw z>Ar1QA(EP87J4`(Yc$+mnFro4gr57B72K3L9QwHURJptfBdE;Y0!FR}@5IStrO7SN2W}oMPt%H66#Y_BL(JXR|Sqp3FLvY9fX`l#$X~%8bLZ z&Q};xh0NVTn;Y>Jk-`ZoH%oAEKwg-Yz*jVD_vj}3)O%EAWA_ze(Xk|WQpIpAPjDjT z6(N#I4PqrxSc&VfgCdT@9oXG(AmxfqDu5N-mV?4EO{TlQ%fe5P2hgO0jh2U><=rFk zV5fqDlSuG*TBh<3WRwl-*kH@lR^UL%B%oAjI5(R!5 zzzVe?>fB+xQk*>9%j{I|d__4z^=57Ug&ks>Mzn}gM}-F+QxsHefRLl_8(%@Z(w)qf zUdd{e*}JiCuld5My|CTbtCds=H3cf=lo4XWdbHa5*iz|IG&6zs?!-7G z77Gui84uePWQ1f_J ze9&bP0dn*7&4>-w(7kt5K2*t*>2xML8W$pkmWsi_{jeEm05c(l2_1n@XPK*^B_RMx zQVJ^x5lW#9n%RZLVqaU<0(A?*{HY)3ycuypllWb5FLZ%~&aCMNj}=0`sbfkx5b8M0 zLZ{YD2)nWhgZjDY%|cI%OQ_glrf)PW*g!^>oC)7IahzQC^z-KsjeIo@P&vB%JdQ45 z%bee2ukoO%SN6xQ6lVR-3>NJ_KM3{rb_pN0dCO+gO_9gnm)YLQr=p|sgl!5`keLm` z!UnvJCS5;x0qy(6j7{fMsGTgYW;H1h`9L)q{n8aBH3UeXpAkKnL7)H$B9LV?*cbp( z61^#@0V)7MrqN(aN;FXzrG~&qn?@UZN9QVmubRH$EU2s&vr6v6spRRPGY`toSVDeT`<+_-r&;MVu&MLZ0DfK~Gs&cMLMWRbVa|r4}(wul5upI$$$7Y(*EL1lD zCbM8y9vJuIYC@fq{nET~lXZ|!?ES^qi^ps4-a_cvfK3om+o*JmkbY{N1Iro_+{(Vw ztzF3m-@ec2^;7l+Gp-jfZgela62;x_X7t{-3e!4Pz>5*=`|5KsUiHj3@4tYWnV8G4 z`2u#l7F~9m_p#LUPs6-P!&$KVEaNis!EG+^mNrDWoUaL(!m?ozx#b1 z8#)fSEvB0@ik4I39ymX)6!)&+K zwb4u5XIo*ueZ_>;>IL8DEdEJ}6ivcZ~*STh2M7bomE9dTLckZ|2Yk#btf4WWOo8 zkYUkuI^yK`v7TRXw^#L)a*tPhH6uVy5M(`gaq-q`r@Yn@_phCHE=LP9->1W@I5vL5 zr-^)%q@K0(*K21Vs0Cfdk-sEwW6jg_*6C|XD&xia2UwQwekYoaFj(vC3+vg1DPwFY z!Gis#IM|M>>ji7;h42lI@v3W%%!~T4f`?o%bxbSL-Kt|L-eNsr%uo+p!RDa;8la-S5Qj8$IIR&98so zyuE65-a`G;Z=Uj>mJ^Alnx|~_{=xugdZwkCNyY_EBi`wi?-t1v*_FmZRySmx`VDov;=D_RC!7rOb zYnw0Ne}&3_hxPuBSpR+L^>+kr5zi+Poop|u~ZO`Ay*MHx!){kZE zQ~B~&r2KD6@7&8|kV$Xj^!|UJqyEhtNk4j0m&}H=CjXm%@b7ESzn0tO&OAI7oUs5G zFDZ+Eh&S@;=m`y(=Tm^DSmt?lCLRZB)D>@B75{!9KJ@~qPRTe=8p8wFMDf7pNAbwC zW@o0fvRT~hl2#X6PA{N2`UkN)PsRG=!t4+2UJlW#*eGUMr@z#2|DCwGF)} z8z;Srbhj}#pHG3Nq|~iga@&rr=#Mn`UNDQFUojYM3b-0@^SUWh-o#b>j8q{o9Os4g z6mN_DWi-)x?Dd`attDPaQ*QC$iK$=4?ujWJVju|F)PPy}tkM@%YjnXCir&3Y_|FwK(}G`RC%d zLnlhkZ#!q0`S*{_@~8d_<|h^%ywDomHG6I!|7-VaVdBB5?~8x!*O#VyO17W)=OF&Q zGXMJSiSPd$H`kZHyu5uv?DTK*_u9|z-^I=}ptKDk1FDijpi3FH5f~^tn_~2#Ywipg zW1*0oiT`)X6|Ne$K^(Aya@VlYzvJX5>CSk>s$6+}w<%L0eh z$r3c)AmS59X^bZCw?%#S+SCO)+P75ZV4`+`{-q=xLr=BNY!5|$HlR*o-V#$grOJ~G z<}V}L=dW#B%iNOL=0@L zG@g|kG7Fn~wzX%I+7uDIq~`|PQg!MlWZeTBcD4bLCEA${E+-Z~y$XzQ2$=hI`) zZI82UX4wqyS1FhHJMBabTCJ`&;fQRa!RVj4ckA={^}X7Mqx1h8fQZ!|aAI1`3$0QT zr=UuzE)GMEYiy9&<^5mYCi@$wwD>t{9*VW~(5sdma{N`QvElfQgC)09vnYv`0{5a_?u_s;7N^vn#ppnfJE+fV+u&r~zX=)6N7mz$*@ zDdX(0|NXw=U`l7yt9g2tp`<0)`f$kq_)e$v-f#EoI^>Gxzymxn+=1Vc7lPAPU25vF z>itB=1cs@tR!Bwwr}B_-TiD-yJMaVkg>gpp_@i+!b9zz{W^!6XjO}sG>&QzOkT`0{ zisSc7K{7stsbhb7q}SH(A(c#a>Jj&7!P|6H8u;iZ!e_ccfxVeLtX6b?&;|X7Yhb5O z9-*D`u7;(xM%#42mr}eO$NaOU5laU&Q<#nuF6`eAZ|u&4z@0e58M}*xOx@+nQs%SR z&22iI7svL&P|^H@2S?6!jcQt$%Qpg2`&_G6wC)U%VT8V~C#4)H(nD*vE{_|6@f_vK z`zt_qe!Y5*q>$;!>^yeTgfTWrv;FqVS-CeCd4d3T79W5RxAC-4e!Y7g83^5TpgGiG z#Fqc6}wOxZu)6i)V zZWU{}1k`m7(^yCWy}S|Ps*?k?YVVMdt-dbxplkR>jF84EC6WiSd(!g_s`paBsu5RS z)I05|Up5q|{>unZnVxf<($UgBOoD9#JeQ#a)ww%(z#JqZC{(85GQP$|q1}^f=ICZEfBHU!nP$EM^hnoM&E$-+2Z!@~wNCp}B0O!(+TR@ytgBjkutemd{7zV9H7B7114utxWCLQuEmp5-{%gNA&k7u2ahaS^L+tTP|5?;|rO>oxk^!tR>4Zi$`MRv9MMIPs_62jpvO7FEHW zAXjU*`Jgnvo$KjZti{AYj9z^2?J;drt3`eSY5t_xxGqswd$*i8xg(iwi*qvT_ce`e-jhW--cgHAaIDa+T-maf}13fuCc)YNtp?L~&(oRd&GU|`>Qb&Ox ze+ArH;kEoPhEDhQn%xL(?&A&R;ue9Ko9AR>3UGUPxd!W zPxrJ;3Ky-JBW|Lpj~8K%rW0c2b3LW4ma^}kng(k|Go6T0rxwdhTvf3iPVH_J4{P4O zQ#X0%7Y-cy5dXn>9Bj`%bnvgha#mpO4HljSXI0azL;|~Uf%5=E0s&nZm3(jxBB=|rXmreS;A$!ANlDQ%Y^xiqQyQ#l(bK)^n{(^rv4tKO)Y;XYgw%~Po1@;m} zov_-8O24jf$m{^+?UMuOPJuI$@hp*K{Yi5kIpyFDVyA1Md_wzbrYPxr(@i&fh4D25 z*M@d_T{THlZO9G))*`sukGokT$I8hJ$4s{;@oq0Z(Veb5-%4PZ8o9xZ-5%BS!qY*P zVs|&Il?ztx3=6VgtFT`x@s+iHc3O=sInk*1W@p>%RDvX?tECVHRZ9 z71sTip*sq8Xa<`Fx^8g?J46(H@h-RJX_@Otpr`JR)eI%_o)-MDBM+=vp``fa!1XR+ zZUadn9sD|2X&BCC0$hPgBcGP$&A$8cX8IIySHwzm#bI71n zBG@T{fe0j-2g};HcR+-$^ONDyq)s!OAo~^ACMEwuuclmRh@rRZcCNsI2iB-i0(I`j z=PB6)f;14W=A?J#!eWyHjJ;!3Rx1PB$Zw>A8P+Ob);tPfZ!pa3r28r;tR}HfEsZi8^TV_@tv8i zZ!Tpp9J!KcfnmO0+G{X+D}!RULMQ0c%}YNz02t32_1;4G_ciINy9{j!GoJICyxQM1M%Q;8BmS$U^cQR#)X#FqIL(nJY^NWy z`7jcR&?--K0619&!<*^Wp5s#O9nmPTvI|zmm9NUH+p2+8d%_^HqhNu+-Nyy1*{((^ zZqV_|5O(J;#g8>w1halOyV4HGCId1Hv>$ad?<&`6$1^8BK=fUE90VeFhIJ|k(s~4H z!WisRcWsS!L`Y`JNyelGTtV^Q4DaH8B^^VM;a`Sp5)FDu5V_@oOf}8iJ4gFqu}mUu zht>|)UsAefY5Hn;|A`o?7a4jEWcSU>))G#?H`v}naIJ&k5V+HIpuc$H!$utc^Ps?N zCkdX;XG%IuS7a<(8J5)~Xao(I4)PKg)S^G>P($4CfizZIX=wqm>@c{q8H|tPn@xgk zEC!fyB)AF9oMX7}D0?3fefAs;+zwJYOCOVZe#vm|r-H6sGeh4-^2*BelNfi^IhK@R z`|(bx2tF$%=)ZI~X>Wkhn{Z%->tiVB?6SUnI(Srlr+o@TgRT6~bnmLWi%K;xa@r40 z9bUvS&edJdA+t{=G30mhVJ0NGF}JHh0aaVV9o2&Qar}#!li{5gb-hV{;sJ#)y!*3+I*-8E9Jb)@fj3Xt(Oj7401yO7Nqx@RU!b_n z4c0dL?UP@+)AR*4z+QZ<;I6>|2_x5$_rW=kW<2U<-`psOVQc8mj?B?)CIwb`Y;*+8 zLcf|ELE7FWr^+pvjVog@pT8p1I~p;rs|goLjJib9cKr`V&#Bb;%X-G8^jvm-n z)(fw2wM$`GMKG*rTRIV)nl4>pts?cEAN7*}s@!5VVx~N{Q>1j9s4q!ZyrDROGtW(> zVqfl+!#n0l`0CP#8Xzv6UUUE3T2=&t?(#RK58e!_lMsv-##^l3T8Z2&f_5?^_(>s= zWlyf_iW{l|=0t|$%7hvh3B#1gc~wyni?1drmb$3WfT9$)mU({5kmQdA7*ryMOfxJR zNYIteh7=cQAn3c4>z{85#@87ok;9HDVBh$|;74yEfv#^Ms3z}FkWX}MjCv)f!^>p= z&*?b&M)34lHId|N#{)(mHo6f95Frjr#V8p{=~X1sOg9g2A4MnXD%W&Xb!#LXa`%R} z)2-3F;c+0P)4rf*yOVuDS_BCzif+Iy){TCr**G$mS~U2ck>1T7x-YM@vS4}|U^ywU zp=4Z%6F3ULTDm+R8FSle_3fo61M4>TqKH^ZTw-ewQP|I~>3-u+Z#hoVv3gh=@uu6F zij290blg?%a6n|OU#S+$xa*SVZO{+zRku&?RMZA(QJ0({Epl%`PQ8q+k58&!>C`?> zGHyN8#(Z(!b&($zypZmuveJBka%;x8pVhcmp}NDFCxUZ2OhjSk150iV#tzNK!gGwT zoww>TLmb=hY%L@v1oBlH!8qg?dD?Bq2<@m3!#Yo38xdq{_Pv1_@r4(#g41;%fK&(E ztZ;5lvvdRrospxqerJCD97qo8x>Ag^I&x%ttC{s{S%u|T#T8KEML|gm53!d;4y zT;b{gcLWZ2bKo3Fb^B*v?HBo4zd4GAUc+0>eM?aIFz$kBWwq%Gvk0etLC185#xIbg z<^_a=OkyEAcMYIHI$n?`p^IN-P@h6C-LFRFEYCU>(4b6?trKE_ZB zxokXXb>@THR%U==Z_9tkP^G!s*dO23KHMAn{P}k_3Fh8rli1<2n?r~osl+K-Mv(3` z03g)p@2_6K)ZFH=Ag6e`L$jL-f6pTgd2%7|b2>oJLAEkP_WPh9;BlkFxS^SB^T&>F z`g?)Jk*B|6L3_@C)qW}-J^$hrLi0f3M$qiUi^E&|R2j;TCI6`p_uDtL3kCBEa+X2A z9KQKj?(G;1!yLJ4>efh8CZR1HNMGNCvrMJKw$Fw+gL}oJ1>tTn5%Bkv)1=5F_jMwF zeLZf~+vKft0uYh&tAb*1%_6E$v zA@8c5lKWARsQDhxe(HNB3L@CdqcB2Bk6 z{KgiD*68n>Zk=IIdk6gID62)Qz|>uL7^Z=A9euj7(d~wr1_$;Pua6h4K7qGM<~P`M z<#vX3T&MlINY*cYJ*jZZmUVl=wqc!FX9pWXSw>soV;#zVv#XK=`+`o_WBrrs6)85B zlN(-zHe(Zl?5j2o2v=x(hTSB?SSLBOGUD&OiihGzuu_VPLW64|9Hit9JoavgBeQx5 zo0s?iY|ej7G^u?$T@-8Ar1Fy5O}6_9p)Lm7erEIW4%<%M@xzDM{lb}EEPN6a!9Mzo zsD-nzH%bA8&NiRqA``{f%y)?6EHOM%D0C82tcG|ZD+ z$u~P4tw6U05sdfF?-^ILv5l&ipT+fQC;x7OX(TL6>IWpldlRhrTX1L1u=AbH&0vib z;bd;F?=JsaW^;)yrVgTvt&@_vJLA}SlJY{Jq-<5ydHjtw=Zq`+W@6|U8lhVwa?BLC z?S&}LiFA*bwyc0UvFjcNbH$A)o8A33V$EXfUc$o!CA0Cb&JLv9A@JFsHc#*NhyRZh zE}&^kdYDPp)QL6S&Ej57(q`IguS~SM-uw0&YsVM`=f%P49Gf2>;K~^BUfi$3ni?r} zClW8|#i0(CMPgpV4Csmr%fc`Cxn#PO8S<;^bRS_(-N8k1yy3Ce4MxX#JxEK*+8l%J zv>>_ywpLVcPoC}`J~lfNnuS#Sm+*PME~hQ6Hz((Gtw+t1C`GGuju0O5#8=%UhrF^_ zLoC5*=DZW#bCtd&whGoh)A?D-{_8yOEzLBmByMfO$57g4VTvDSnq%32F)`-lRsXB| zo>ZQWeSJH$r`)kBDgNz)gfC-H#8t^BJ~SO3VS^S!%#W?LnkGFA)qZTD8O>km)XkS? z+12e4L~VOCJ2c!^`S?MzYceatgFt_c4(Rw4K~M0>nyT#ISjmoqO~SntJVvy0=-% zEOENIc3eM;Ct zgdUrC(`ds3?>ZExe4swL_?(f)9^MnH1i6zan)NL3i*V3i!Xh$!de&6=v^A^-}V03TA^pfPf&d{qeuWssGH{?;U zVN+eFx<^pfvrx^nTUFkTadG(7#xls$y%iFC4evk8XFb&_)&YWu z8RMk6X=z(=dC(BoM}w9gf%1K0@z6F4$F3z??(fF?bk5J5$KR|-P7*EjHZYyA z$NABG(Y}Tq{*)p6aj+NQb!m5Net^}A)GpCd){KVTXM7bO@*?S?wGgwD)a?Dk*E$xK z@T?R$o^k)`*~^yMRik~9_@SFbBlfUmYM;a>Y?F1*PA)M%J25#)+Ea&`m)H%meXD83 zLnjs_MI6KAehKzPdkE7*MT$pfS?-jA3Pzwbuv$B{LRq@weB)zFqH=fV85)!o} ziZ|CC6S8F~GX9nxJxj0)b#ixhktmby1-@_tQ}HkL7FzSv>b$my7YKTZ9noJmlOUwJgX>sf{^UwC?jfwf>*Lr$E*U*=?@XL|6%yPHF8)rw4>#s7PENv`@p6*9EnN6N5b*4O3=tO|@)qYE(UEoX#0E8`a zf?8M|A`t<*@ma&F42A;$oxWPCYvG2@_CIfbc6a% z&Fp_kp{+;|E{VX~FdLzF%s3YqWKAnTVI z{ZD$)$udxJ4`||)^h)*Sb_F8u`ToMqRqdxoW6@Q62VL^u-0UwBonD@1=oN9qn?YXw zKX>d;1PH2?e-cav!kQfYHu@UPa1-&QYd>Y-4hQ+RinM%OeOuPC>nPiSPmxIVdGSa#ifLZrNnY6s=fO3D>XD zwsidxHUnOR8&te>L&wLeR^lTSqB>6G4X9lD#h25EO;T?>x;u_ zxS)kegkMC0SZH;P0{~F~6dQ6_q2q!7(c}I3g84WQWlQ4S1a>)%pA(4k=vl8D5G*qm zO@O&6S?07Fc^ z=bKgSjMVmKQC&n9$$7xx;vfwWIiMpQM568jXCW4x+97UI~B3!{R&OxId;c*;? z5fvnlKW`HqgtfO0Wgd?h6P8)!Oqb`Wp>yME+Gw>PwoSQv4|M6|x^%jj`yltZ2cma* zgZ1SXc|byUNsC`LP|V zVrQ6~`c#gG&bTN2sAKZrm;PYSH^=W=NE}b+|FV8uJYB}sS$HX3qq~>Wl9MI2U-(}y z2b<~(V9{|QNW?*)C(49dzd>ZHV}l?#`cT3NW?%T7yGnAiLUvR+%7or zFo5_SXQ&Pu3^9fIaSB#92rLC)&q0lRIbpu+5OO?+-Z$Vj?sIGp&R0NEhC@=5TI6yP zB&ESWsi8W1S@oSu2z$;PU|IOjlz*Z~^4o6C9DDrGm;>v~kHK`8 z2Qokwmu&1x9uyY4DC%})+D6D-UC2~IxN3{L%2>X^)`E0(+Of|A)l*khZTqm^{_4Vl zzwKg7ZB{@?!hqQl5F5>rglX0xptXy!@7r`!_jJ=V^|Fe!g1@k&?QAiLpuv_*sj?m+ zyJ}HJ&*idaZO&-D2YdRh?JrxxrN^s9D~nMN^Q6YnGOo4y?Ry53nufD6hKU)?44{lq zL9iK4aH@Vq5$3`Z)fil0c+`I8@3fBC_t%?y(k3K>k(e_qO=IC$W0adJ@SfCswSer7 zZbA#Hqo=Nmy%R5a*c4}p|1>r3I0KIn>|oS&V8pdBBhq80rXA*fKg|hlA)z?lM$^O# z4T}GOyx-LyQ;M}8f$sZjS!D_FCu@Kzah4LC`eM^^v9>*0b_20?Z#wM8e%eiH+0Vw>zw5AH{K>Lk(sK9`>kwC~-MV9o_^A$* zV`qROcYbpI?y%p{QhpGtyD22+3veneazH(HmfClYgjoIf>2yWVc7kf9avynYmOJ;e zl|RXvx7g7U@9e0lDWy5>;IHv~My+)QoUQ@p*>`YVad|=1iZONJEw-Ac!u|-^5==Oi zxwTyYUKfR3YJY0F4tnR#dfjq=8Hx_i6?Qu<;HfkH+-m!aJC-aVqRSQ~9{NqhFoG zM*^yA*6Ee@d?;IX$4L0QzpN|Om}kmtQ$6f6Sl2h1aE(%TcR4U$lQ+xty!n&Bue^go z)uQ@kk~i|*HP^M{u0v7oTQEr+|#jaRMy_$+;fF1V+Lr&20b- ztEm2auE%d=%Dc+=PgnJY=J3vD?UiuaUlyfFmOEHZl`8KseO_T{ zxq5WP+%&>VZXMQlAlPbJ6x%o>j}z^+AT8C z__(vW0t)MwDD7(A4KqwLE#KL7*tGc68*w%oY_x>h;HYt1wMa^f3$s1fQ2JlV&FAF= z;n3>*FoJLgbN81kr+ zF|zy=lGFGfsruUo-dj!2?0j*Y-Dr5(DR>7!-vY!-r}B<7urB~G8dJW8&RdB~qNm*+ z@jlmD%R|Q#Dgm$|B8*}#P|JiNjRm-tVE1vcksF+JIv?8&US?a&M+%=$@pKqpzE9`v zM&GSB=cUtGy!q-pl~Xl$0DfSgz;Ej9i^b z@YUdS<$8ISar{C+gn`YeT@&aK0D(+{*8pH%Z{z$vgSv3Hxzlc!mWbY)<(Bt3-+P1} zCra)1c;J;lW=wIPQ}9ci_u7C2W)G^rFYo;uxx^N!O=EsBoFFjp!FkAFZ}sO&fSMxO zcWX(!%_AI+yf=^L-=y>EQOD_A{z=;{WR$aZ5Fugw_mcNB~V$#%w%%j=&}zisTc z!25ki>=6hn`yXcw6Q0oJzqe!Q{1`PtM4~b5*WvvqtH(yhIl8KTcq^b(+8^VP%S={7 zEe^2_;H~2~UmKDznn*bglm-Z19oxsysFjN$VpH#UJJ9N2T6u8f5f^%4P9ai zD3;$daJ0;3ZslCjJmtXG57MQ|G2(MT6z$TP(zlZ17~#4!`q8q4d^PJ*GhU3bgqf3* zs;Y+38)SduB<76i|1k9rZJQ?9Ls;GPF=NIFp8Ngjuk|I>CHckY2og1Da5o-RktXluQ-+aBNA}<7c;kQd0yeSPO@I^}8P?CqMoXEO+J~$4JGS zb0#hIvRgMiID++YLNiMeI)quC590rvW~7Q(;5+WzU*CA$kv|y z!eYexQXOf?Cj`TOAiu|bkWkNqS4*&nCbyG)rK0Z0H@z&0kCoFiOYfhuw^q(U(vsx1 z$NYn|&0SgkapNI!bsrhB^lnj8azK0zGe2D|YWHE`9=~|^-=Q}Kl4f6C`OSeViGl@b z++%%T*WY^rg6_{Rb#3%W$1e5xJJGwAJdFCU_X97dy_DF-+|l77Y%hfwf8aKlN7>xy z-6cqrl{a^WU;KHeU@9%5k7G?nJP<7uxY;98$BCIw%WRR&s`w|B^siiNxLW8qK`--! zFSo{=1*XmB&EwJbl7C&n8`5=4!XXZv9GK=gOoH!+t&>~mq0cg(mt-^yQlpx6Hh(&!H9&r2pPx}H~+n`bbq z)1DJo2Zhx{Q6BldtJMe%{PCk85TLjGMe>A8U}q3Q8pE$dUAnF7c3uyRJ!oxXVcwZmdp;{F1+K=fo*@uj1R#OGHg&b^FKvPo(` zaFFh<*DU_nu9!~BQ$90L7)`;LLW>lhU!`zPd~D_OV;2nacD{8#wEi~x-<5IRxA5l8 zv5cpe7N1ilT^QT zyU9A++eX**A8*XIoPB=vfw&wOhNe1|y}Le-HNSeY_aEG#b9<>jPvT60!L!{jevUs0 zx`;bXnqlYao0Zgt&r3;=o(+^PWp-p1>8~B0%_(aN-)AiP?B|L|v};ucHiz&DE^qZZY^5`G>bglZR$?Tr zq*t-=7RKozv;bLY1s_hPJ_sg34Gw(!NFsqh*<|NJzZAXtNpzJ!(m$ay=w~fu(N2yZYIKtSBX+K zW2|-bC%{J32e}NlOZd=DRg`@9&i?5$qVd$juv`8&3_iJW45n?`&T6dn{q4;0#~l=OQJ`n|>WQN-sC^vx}?j z=?(0x^LmN1wb$6%{VAw~0Ul;_!-LiXVa2(BDoHmka);!4zp2-av|{vds%6LA(7at1 zyK=h7irv2}Xt1X=!eTIb8Wx$;`JClVU0;7n#cmVPC%Urv*W5#!`6L7@X~x3+=Ut~D zT{EB?$^vzibk4hsSovm_^}qJIiNZe=R(V$M6<>`55X5=VHT)?W|Ps>%tZ;Fq2N=j>rVz1Hl^f8aXMH)ZAKttUvqOu2@8tj;#tjIj5XJZLmbL6z|IGZpm~+-< z{aRp%IhVhdzQIV9FC&e|4Jh@Ckp=Q6cdh@eMXf}UxO5mmkQIk)&b;5;+>Esn@-oPm z|9yHRo7iMlbKGJ_6)|R?Jj`Y$_q@06c&PI%+onS=m@7+0Sshf|*T4j%EjZo@_z=kTjYvsAQL3%SH2i}LA21* zj(r0Voi13z%oOK0;a5|aCbmWQ?Ul=eBba6i9j4E({pm-|xL6;k?WURK|B%PFk+p{W zi&${4C<%oox&~WvNC+Z1|5}r|`>XCApv={nmEC(v%gPjPaokB^GRL+tty(C;LgL9E zp4(6E<&{+}0b4V0DCIz&+YMAihgd}zIUe$GCZz2ve;Rrr`o=k=NC-<$RPwJ&1txeS zfoLcTuwR0QVlz-3KATznlPL}n)zEIC0zd%h}zHgqFTrPL<$07S-7{e_^1j&q0tE)7Q zOf*+LF^&J>(4R3k?CILzbma%}p2mAopyXX^N-=sT?EF)x1 zZ?drv{@3nx75vzV>pLv}r5+>|$0&K}A|fXB3Cu#@D;i!EK$iys0cQtf=9o8CpQ@*lTU4!ioittj4G%s>gx zPeYh*;YBS8l8GbxXLMHHs_h*k?jym3T0CF>1`{-y5YO)sWEC#2!NXFcY#KHaMg;4s zrS{gSTxI-D7N-}4y0W!Yg=T;OYkksxRu2q!Te*9OCvp??dTh=PTTWF{c~+XB+BL|v zwzVhOA7-Y{^GZ0F==X^5oVBPa$>UwEN`rr+TgKj#AneuQ8;sYVI(1h!|Ip7E5FLIK zyxb`u^>bNb-OIB1?azY4-#b1mTD*-ufSX+uKxB4WYLyitJoSvFwi-HQ_`9uFA;Yo{ z|JudfdXk^|{LiN^JGoMI>U?puh1vbaAcv^18__d=qxk9ZZ5e*#ved2gug5plyJVA5Z>$ITi=Uqm_DKOrg8t4N9S_lHju84KsaTFNK2}N zi)LH^X9!3U<6gF&RDB$$&xqSY6BJuruw0}qiWsg0@)ap$1HBf%5-*%#>zIa7`lWt| zh2<7r`Gf?c=-e!10E!6xMv?0kR1;wGP}8_h%W_C$^99j>f)t*uCGgq8%#GJUYSh4A zQHcm;4mzFmbDFOuSi=K?t{{dLTZtdOR#Ms)oN)?227qWTB`NIq^MK%;11VpuB-!JQ zY@?KolG4-omx?%K>D)t9UiYY!)$AKbti~IUJ=4cZ;Bx>9@D^MtRzM2PV~s(qqXR7G z!ahSU{7OTB30A?vXU2*DFY`sxA@NS`drIMEOZGw4;RAi)!As%)pv0azW$>?K5Gw%` z4R(m;<2^*It`cEQ@^-RmYwl^II8zxkd?MIQy4YGYowNo?m-UJ>xa_pKeFMl%c}F?^ zj0BFrmwJYk{<1o)M6?o0YX*lAOFg|IcIKo5BwuvcrRcy6O#)vPwJ?Mpy-kTSed=`(C!iE%_y`F< zM01A#5bv>hUm0NT__zZW)tXd(ev>Zet7MdKCGxcz>~)0j6$Fb z_7LYGn8>fJlbdkG^xn{w=Ao;<@H_#E92A=3vt7k+PKYTAB%ThTqs4OZP`{`Y(bqxN zPXg^p{2#LU(pz~Vw;>@>ls&+8?-f!iE>k!p>FuH595(ov6Xb#JSt$w^104My7xjKx z!6^#Jl)=ejCO@iH&LzTL;EI7f)%+^e`EneIWIj9vXc%)v004v(n}p$&3_}p_C|7+I zuRdG>f6+BWo+=PLC5}R0Vq%qt>p=aWa2YB*Cy=ZvC@g!-L;l${CGH4eIpT@+?4gE; zE2Vr)4zoZOme1iJS`X!=e=1F3vN$JBZUvyT8e;kmXI-?9`1DmGl_o0n6FA6JW1o%; zi-D3|L23+xXz_aoLsC^yqVdEAAMsErB$u?t9aH7}U_xdC{|&>KYrSHX`b77SxJ$~; zjk35~8ExE(0X%1yL?xm;zoD~5F!wI|ToA^_e8paQYi&^(x1T>!N?HgX;o1Nn^LL&`fT98 zsmSJ5iILWa>NgJnh;%$&b{kSk0CJ_c}NOT3T05lo<4#*~_7Q_bTHgzEiFC8GPH zlZO=U@_^>G?2^33c3>$UK0;LTTjJ0Wg4@S?NcY{ni{X}Fs+)Bc-S!~n{4DCjN!yx( z1OX!ZQN`+~>+d?(Un{(5a4EaQ7{MKY+%Aas5LzJsk{^zAw*nqFC zzz~M=9HZIyX-r)aFL~Jg8#Y3KA&jDGE&;Np=ESgXeAB6D2^^P@|NTs6oR*f=2+dNN zvw58kDa_@UVvr4?d@cm|77ayrikMZgxb<07Eh&4G?gi+m=vQg>n*%b6rH*7d{P29d zeYYon-=-!Q)*d3R1m!k1=0?(h@x)^eK}K_w>lYX-0N?LJexeo0=Hy9D^Xa-chF8$R4t|DlyfZx^=J zj@qO`)t`!?DBfFCF2QZX&fs>vk+2=PORG*0?@90sPLMVS>?EqOv*=Jxz#vBd4}nk# zN-dKKzTF1Yt9FJobDc=nKbrEe&{tM_hQ=4FB{>NsIcZx6)CVR9raB2|2T9E9L;z~C z2s{wf66e^q1qz6RDj-IfoS%fDOzKl!7yZ2`xLO&|tq`H+9+>st9T`C6cs5r+{E2K% z1cL&(np2t)-g&_~x}^=6C@LVoQKN=~%;0&WqjG&8<67ekLe1fbrQ4~20?o6oVax#m zB3GdWoVDZ#;pTtm1VN>NS=xw(`_NK#nD-=*!paLPJf-}iv3vA6I`07WE5!5f)PsL} zz~xoAU}E3me=qtLDpIC`P)wx?8!Kl9Osh5L>F1ZzJg;gFfn8@`y*`5E^79p>SI@3+ z&N1w=EkRyHu3YBSLSWcBl{=eOKL$Lrhr@rURNCLElfN&_sa5sO12N`gC_&*`+eZD~ z=s|a1%W;KVPgkqJ2J`m1SfnR7J8@g7BDlY(k5P~v+dv73`+--#*(Qe?9HK>k=z!x& zdBWr4J{PU}_IHBcZFR&F9zMfR_-c`<)2JF85k+_okGjY&!Q|mC*QzhlCb!`oAh zA5^sgHKB-Q0A-ni+y{hj=m_p%`QEY>^JO&RfZqIm$#P`}QFamjp2C~khpwN3Gl^kL z23(;VnU()IyG76dET|wEmaP7yvaC4R*63;L%L^j{j9tWvlYmdAYX0nT#Q+_`g0f;v zzIDdOtrvWch~dHkqueR{5_lL@ z9Wl54O#2pu_MGoi6nqgEx7FJHV&EcGedaL)y(NoSM#9I?aCH|1Vcn4hfRMEjtAK?i zK-&*H5uG8vUG_?ehcD1XtH={l$btVxmC6M8w0Z)iws~w?`A)d1PXgX=Fi8r3;GSruC`j+syNG40xrJ(1&uqb5rm+3cPqHk=XO-AjIq#4srxU zumBb>3(MDv_;iDHtqYxiFvJ#f=>2Vf*>o*?$q7e9K8!>aw%+@UR2%xA&1b?FVQuvI95a}+pF z41yK46>MtH;>o3aC74+$GFtc)J1^=!_F z^0mK&mox}2vV-cSD~sw8ueX81bl9b9xp%h(qUp#4?9|-Vt?#njhF+?VsEBVY3W4Ve z+_4xTtyC|I<{=Qa_MV@XrSk4N?eF5@-yd?V2`8aPWj^FtE?xeG<6XY%pHi?Fh<9PycnNO>^ z&&53_k8oF^xigbF@KoL@9Nh7M+ct(j2hEd)uCRQf`~-j;t2=cT47s6feC(gPVwE``yaFa9`mQ0N(B=cIYXwcBnFeG>=4aHUeCb?fTMELrE=P;5z* z$)u7`lSWJo)i!fkXvY)YNl7cckNC-NGin@4!YJW+rPPN@dq(F@}vrRtRBeSzMMs|X-H^n8Xmu<){R%w zOw~P4QX1~|*P+baA`3*@9jpAUY}d4G7Ip$`U{u(jBQ!kU|Kg7C9w#cNhA=49`g3YL zOY>n2hfzZ)+D!X2&--Rw^YWuL6n-1`u#-S7grKZzXd9*(3Xpa)_$z$vw+MZCVwkC7+t7OsBoa!$`@AJ!o@ z6-K743GvU|%~?Hq{!-_Hk47>cXY9Myhxz$5d%vn*a;^}q(Q+w#x7ao1%5S#>4<fW16jyzeKKLHjMaw&}L<<_P*qaIvyy0rsc35Kl&!8*^br3hwJ7Dgx_LT}qSex^q>skzs(H-Y)GHs8 z5B^?ZW?Yjz(`{?>LZ02-I#_k3k>9=|el_hL;zJhe>A$4S_O~y$SKjFN6dZe-sHk<3 z*%Tt#`^58F>aX`#SgD8m@xK3NR*KB-B=1hXic26`>s|#w*ng9s&;9Kv%DeJ8^4fvd zYsLGPI4%pPbiq12cvkDoZ|jJ_2)eoEIZl{)B^56sPvEvcG#X0GL%txAv>PX3e)CId zN_7PI#ROAHMYV_&QwE=38IYergd7{9f4!VwCa<^?rL#xj(x4*6^>!}U)cFfPNEi_R zO(FaIxrwyQHph~j^HW#+bGr2`v>KeRhX)2oEFN0u4LTRZ)CEXwC0H7)I^RhC?1~!U zq@gR`fW>cPK5Bp;W^y}v$gGLWgo&wgn@kn55_jb`R8Cpj31ACze)=(WO4Co?&nv#x zk}g{*ID9S5n4f~q6y&nZ(8BpU6m?M{_bd#s)>Ecwl%UihJrx52!<0NTFZ4pF)1oFU zn-~zxbh1_y<+8)Sk;h;$%60?Zd$wI>#j0;J#|)Q>qM4jjy<1Nn+OV(f%kZ6 z+wg?Z6=9FAFJ=>g1`!Q7&Jd?edHHHCojQ7X5WlhLFaToEQwIyAhS`s7OKZd1c+=3F znBPuW4$hZLYM<9xf~>|lx{5UrQY=@VS4Zu(S4)~mrYbzuJd;gNVj9=;>mct?iuLS4 zwog`;`g7FR&Zr! zwJsblv+=cIXkl6b>2Z^T`vR&ijj!{~iqtxTgq9w{`sS}lGWGgcgFn-3>ezjDc-8Rf z=zJ5Bb?dko^z_1HL0onK%0X`}u>Hat8}Y}L8TI!)dy93DpBNSgUBRrwsM_iLB}FG&;sbcY=@ zM4M8N!-*c0Llf;=ZiI5~+OdBOGq-?<#LNR}+TVt__EWPzdw)DY3DIKfEBrpGbq+GV z?0CHY8j$O<8}hauPbluiWBzNhTBDJ*ISaYI5ak9dtgsBN!PbDQMRii zLJyUU@><@=-fL_u9IUQd%Nl(uzGdpa?A>$h4^du2rNI7YHG;x`e6@>iQug@2Y+-rk z?G8aZ6^}YVTFTmmv23immu{WY2TC^t7C5pU+~(~|`YFe><1q0w>*a>1!b-nd8=c_= z^WDa0Lmw`g-U@U4UiI|a?GI6c@y{1G)lW4onz9CytroB97Eb=1O{yJ@?y|d5@N8=` z>g(+;mWU$d)`^Q>=H6DWOHY^l=z&2(BRCSgUK=L0-hXf>4OxNAlIH}vy{JUvRulC1=x0h@b^COqvZD+A2Gz8fNivb-<;M}kh%SpWY z{r2ArI@IWI((SW<%46GZ(e7+xPkp$IO0#xubS}OI;}`uX^&{_S~QINz=Tmp?mn@)oPN zkJuPxA^>Vl6!D$9E{M)N8kh*H6j-p5+&0OSm5wzfz6 z6i~p9ta&KRpO6txV+T()EVdhM=ZQo$-(3coU&(DWfB!OOSMkexwU2o(Pq)7OdiLc` zyZU$27McGZxs1NtJZ+ThdS+2#;5_GX%)QObJ?!qe`o3D{7~InM930P}5*5r61`3jnoTTDI6j-0lslvx6er-Aq{1H(FvVZO#aF1b8n zq-3k1tCHk+3OShpIlWG_KU7P^kt1=?`3z`0TObxv!0eKeC~xAjhsHGSMj&e*^qqid z-Mv1Q#|CPX%c1cAawLGveVc64S>iI%SSD$i*hr2gTKdOInsTc=!0L>e=H8iyL?Sc! zLWe8@4YBJ)k#5LIwh%x~Q?e-@TO%dUL%6IB-y+G$6w=LYb5A#OmKQtr{-?T9o`rAS z;Fj{!Ujc(>wWK4@YWSrLCZEP^|u?8e>Xt?Z0FkYq~E||EMIG)e{?jk z=Ev#I*%M=7b&aX64a%V+!C0bABET3=CO_vYkD^~0$~t2Q3Sm|{;%^B7GGe@Xbe)=% zagdZDs5y=&F_RpC2Px@gEY}s?t4`B!$~0R8h0(|{hn7j!U>{AA8jRmnahxWHq~sw|!Av#`KoYfOe+VE|H0PiVSr>^B?<6gt zATcLEfnr1K`h5IlNpadp>{?R{1)4wwV`-3ka7|7J3Ju&^-mk z6Hkao0WS<$!}iC6h~#8CxD1F54{YU{&YZw-Qoi+cxD^Ynk&>Lq(N@stAxI!PWB#{5 zIe`4K5^&-$(E%3A4%pc`|e7D*B_JtPmC2E#0 z100BNN$l)9+~$aD)UXGNot*Ct>EwFTq!*w}L^w66A;F$eIZ=hpiSrQicNJP*vq6By zPyrwmM@m+9tXL-!BcKKh`ve-)H37gn(b*eNK4B3nF+Rx&RnEwr21i6x=ridsCfb)_76#RKIfd49rO6;WQ6XgY1gwU_6GYZ`gdjw zTFjT*8WJPlHI=9Rif0>yvn;HM$`cBfKX<%XKv(MpkwXZQ}YR%7n zZX8R?r?D5cSUUL6f70=dP?j$MFxmtF(I6?IjfV`5=tgLKD8z)Gj-XfGnlyOE@xd`O z|9YIrfloGUUOPC5E5vV3lik}`0d;HyoM74pVu`+Vaugr~hR#eY$>hP8B_lmwBGW{) zoL+jpjVHd&UjvvASz9rL$S)Ro7}*FMB$@Fx4pn+}02+*+_Y)+m3<0{6pjl%Ghy2O0 zzt9VK>2M0?NpubO5WxAU_qZ9PXFw7V+8Q}@MqbtXumu{EkYRGc+tNU=;w&VXn&lY< z4mc!DBur z{^zQru=F5kjHUeoAKR?ZW$sewTq7~I&j%iok^s;ng?ERCL{FS)EIN~On)k1}?aAv6aCWok z8i1wbG4My)L@^hMoXE&Zd3BXbF0%ZBYW}hgv{@D4}#W6FWqv|*X&C} zTZ44x>fX0C+K1c%xD^6IXwZ17^zrXX;aJFI=l7r}@CRziHGGDf7lh;C9kb4CjqsDd zYs2(@eK^H86g9tIMIzt*6)-2Y0jDfp!EKnG+i(oKQ19j0IG%0&FwmX=vU~aA+`GW9 z3KpLMUmo#=b4!0~a|o&@eEG3hA%xDb7b9IP$0l!A#=rT(X4k)2KsH~36-7`iet%N4 z8QJXcBfY>SJg`B7A84$+tyjDw0DN~*2uKaTnWy43e2FJmKtMx$_xy%49fe6MlmBcR zGIDOMx#;4RCl`gJx1KDH?rJXmPO?im{gi05R;#@gZ!x+Mue%_!CMg}Gc>euJiQ4#y zWhK#*6d8ak9O=vczi#4&t(pHt$WGr&LLKkP zxT`?A~{nxtRPWMPd=|~WpO)w zyyj(!h*Nq532#*lcQXp-VITB$Z^Ec)GaR#7dO1m8h}n%`2o}KY^vcLSjio{%aY;bi zC5waq6)87zT)I-P=3iF z2Sp{U^8kk7hipI{Vte4eH-6@)1t0wu(NB}Cq6eg(nn(_ftonZMkZk0d3RWo86p`hDntfLy+{tZNC-(|S{ITxMA5q@#6ajPmiw&^Uzg17!#D zMM{D9W~rkUSy|^~MVQ@*yYE;2MdTdl@_wH-vG*~&>zbh%lLtA<7geHNy!hk4kWUUr zZ>0~9orw+$kCBLF&4$GqKUiXa2e= zeMW&^@sA=P4q=}v55IE4{7kkszTEE>ujUhFZr7WBuF<(2dC+~T$x80*iz^-J-vA`X z^N(O)ZBv#~4I(J^F4wW)hg<^HOqk|c*Hbn7jjUtC)Z0pt;lr6Smr|1z8i!wLy_g>} zeX9^`!k@G-rinP6o=tUvR-k|83#yw(+Z%47U6?U4ZnCT!2K&?)2tohEOq%k>tXzTU zu@mwPNXJYJ!TZl7#4lL2E5XU6Lb%Q;pVLq&pnzj5LC*Bd_@Vy|$&U$6g`84vWi#%i)`#ac-ukBWS$X+>D0DbiZY2{IuBeFJ61Zrd2{ zb<2(GF4HrrNsrB!>~q&s_TYM(Lz)Ps+pBID9EDEt&p2_#ZI9}&QTrTx=nd2MqNuub zM?HKjk?i4{nC0lzMR6bS4tp>=XZXSmTco=Vc+cW9*a9^3X{j-`J@FaB@m~HiYYbzB z(_`%gr#9znOM}W4-gq0`&C>A^LM6yfoNi2|Wb60;15Na<)$LhB^|NUu2Ajm`3;Mf6 zg(YYOC)b4Dr_A!Y1Xl6Hj2J>ATYv9j}jLf6w$4 zoLXT=wnqs3B9m#QU>9igzQ^)O}RGpdX3|WkS&aL<uSimr|3_K&Qj_1flJN6Q)dB?V5=>)Sm_`yWj698*yl zpA7pZiX9XLW0cd;%cFh&ZD*^-aKNY511BEHo+9uWjUgZRXdh(S-I_{wN81=NL(^tY z@8SNlHzK^NL3{{#aC1xVh^{?#>Q|=YBU@p2yx5Tw^!YNFJ9)^|HA_8fu0j_Pb)xp% z%`{h@u0jN!7>t@-pey3CD)?|5DZmR}EvwNteA)QcF@UMg=bal%i*n}d-*8i3YF^xE zpLG9OsLiHgouFQxhKTrbmWEkP77;3=SL|aFA7Aj~g)K&j(ytruf=EUOOFnHJGP%rg z9JrpA!xqi$6UY>?nha!%wLVmQAA2~x8WB`}?xF*oWdE~Qj6Tnaa$w5y zCm8cT5hJN5VR%kQ)M1>t8bp6dKo+FhxUF zvT!tG`NGKzi%KNfh}d&88vXUuNE10_js#0}x~CiFlx4&;mgBHacMg(7G?G99Psw(T7`cQ<-jFArkB#raN*~*fw7+I?f#Uk!}$4cY; zf*3CSef&(Vcxg2(8Ym{RAw|;b;j_5D_EShU{o2i1XETnc*%F!e$bdnuv zP>X6-22Df!r)mZ75pg2c*j#6x@h& z5}}=1IkG!S)=RwUX@?I*%H>`&>V7OeY`(}RFWKFGwdRP7o7n&8(x~L*bAA6k|EWjL z;2Lh-9ieAlyZx5aDY$WZ_LBYD1>8Y)BIzv?;E$-hZi=r>-_DH zHH=N|E0EED>3upPh+*YNYY(Q}nT~x@^|CE=d`LgP#rxi<-IMf+?>jC0-g`fBd|L2H z{_Le{zyA^hs=t%aI#z=mJOZZqW99zF<+&LzccQQ*8jTo(e3Bn!CMX)XW_0Dx?{kz(D|kF?yjHsQM)A!&zM3; z9Nkj-#!){x;=9q<1YwI|2y1^0=jz!rv%A-G(yW14&bFTj!|a>e8;yS6e&?Dw@CA6M zUpisEtGzAc<7t^C!E@g?K2KN{Avg^EP#E-2u`X$8M1C>5?^(A(yFXn&2`s+n=eks< z?K=C~|Gfc*4pe6M>a~!#%J}G~wSQL!VjcM!4G_MYRG`KPgfnVo1se`+Xw^YxoEM?{C>T1QGaqt}qlu6!`g(91DVqhWOOp0Zcuy+Stsr!pDI=mA z$)6YOzpEU!blJ6F`sDdx?x%hENA~6Vx;FHTtx>W4vkfS74-yWek|aF0IQP;MQ3zi# zg7MbWmLt^@wZ=>er;9q}5$zuAKpdM!j>6vJtb3^yJQiOGj z`vqoDyiE_c@&S5Bw?mOkyx`v|wF?aIo z8V}iNz^E#Qz^`NQCyhq|e3R70ch~G=8(oeu;!0vne9>DX2OQY$4ta2gBKX~G_^lnn zHMu1&Ej^A+yw_vAHRQKw59uKf!etCjb11}Aq1CC6omsK==XeDwzUU18zE++SPz1nK zKIIjkiAPaPv{mfNFoUpG2YA`zP^1RWt;PFOi)SzZFX*UsZ}qephdT^Je;%38WKguN z;@q9$dI)q}1EkOa$y5s|=h&nUp`J;eCkg^EY#6-vfk&xDDM9{!g6r(*_o>@m(>rCVGI9N1$xuhGvS^ zEW@=4u9HMpX2mOea18n+J?h1P65D;K1s2Q}N!etrQ#$uB+~(Zg?Mn>Y-*9EQ?k%Y> zl?GANIgu)V+g7{YwIsAus8yBvh&J#CON{h~0m%>FLBOPH1DzQ1UcYTCn&mug#a3)G)F25p$^mT1IdKs}Q2?qTII4f>R1dCpC3yJg zBz{1`)?NWQR!!Vt!1x23)Wv4oHF56hTDs^HsZC^B5=YHQ_gD;S>}<-Dt%oupWCPu) z39i0FsBWWf3nb#IrMex@HMicnShy7?aL9#uh~JBr)`pxRh*#Bm4{0KRjJA%t}M5 z71E#W%+qaw(ahjhGu;ME&PdUORJ64XK^j(GFenEPi4AnRxRz!;v<`J;OAmCUzEejn zXY4F}{6j_&*IdQjyojOEdoCk`9;(VS&+T3t&SRJ-UXLrmuy}9O&$rQC- zVWM0au2y96r(1KR+oGCsa}u1Jg=Bjnm5y$UIW5b+i>3k)?>!?!>b`mIvqdD#EVb!& z_r)$8{LVkFfj1pD4WTr8T;t%`>rg&tIF2nn>P3(u#H9*74pMqtJDRLB*~VhHiwj(Z zNnbzENNIe?Vf$+Pvv+YqYgF$49^+ox3DlOrm0C_#Y*wl`ry6&c4GZU@UAkci$UrL; z=K*&^6uFG`*yZXJN(ED~r*)URn@0pQB-*`!ZQ~?SAGP{o?{PN62mb6_{%b^$>kio9 zPJ~qlV$@UJ#p8%DsClQk4?50dmy&c#L;Xz&dJS!TK>2%DNZl=ow@bsY#bkccYW~s? z`;)ZLG!8Tvq)*@Cr~}=49zwj0s3NBO{Vn>m7KB-;)$Y%eYmHLEbLH@i8FMad1o(sm zG(s+`x1=hC%v0F2{y5qB=b$B-XGQHX=EIDQcvb?gY6n2XaL6iGtQKI#Y?uY+tFZ%z zv;b_x^(>;?7g0PbGH+uyM6mg4OocD`?piSD(Gi>WIGNoWgx$N`_Uws+#eb5`Q6oH9|w18D%!&z3TSn=3xwO2 z!XJ3J`;sT@THKv5e$EX&@>ksTfisw1(eI^Jn@IQpAy3yv^Ge94Mgzq7yg|_~@p-9h z7|yew>qRK{N&Q;a$Wr?^tsRfuC++4no~3EJzal}YN*DkfnTKK6>Mq@sA|Z*&#^p`J z#sCVy(7T_A*#J`1>E0D=U<`WS&e1cNH21iyUDzNu$gwaJViqoM`;}@%cDI}cm7Bg9 zlXkIEHLa0O{Q8_b?=2}ZXt?zZ&U*1PA96ntzl zJK}%IwY5hTpjlxUsJSQ3Nw~?ehn3eV27c9Is9f}*h++oeOV8uZD-kk8QO88#!!@Qr;#3~ z8IkhcdfbWcj_$0gT)=7?4%i)8|AJ@3zIZgL0Dl#(S}k&#;n_N{btwfgMFQ%j;9BoV zs<}`v8=z1D9~@oj7W>U6q3s{{brHT6?5Cy>a4Q5bq}*SdDBUH!%G30R{;3_;6^k;9 zA*2o5EyGB=@BCO0l&;|wgLTaN@GJB0WSNZO$Op(H&{Cq7n^uGJ7{nhsi0-L>+B%B_IDQI9bK z#Kqa+5a4n!OlA<03*1E|iOfC-Wu`fnKcg_yj!ShyOdfC_Su8?ZhbHDY-2B>Tgk3$hZvUP!UDW3Xc zYBhh~)>cnbaP+EYVEFNd%Bra7xSp*Zm$t3!apwO@48AY!PZYqi{dl zS`617dW(gm;Xv3L0B%d~ErMTr3ws#&JporumlF9_WcF@Fz?vM#%H9)*{Gj%A<%sE@ z?%kPu3n7-zmNR4MX#CO@WD@3t+OnME|7F6aA%&2KSTo@LFy|hTOJIYuzoT&^$S`tV zH=vsmM?a}X_ig_ba~4vk@(P~Bn3jMhEnm$hA)~pQ_>4&shVv^JCX3-H1nx?{Ei}9i z75vbu`MlRM5@wVnxwE8Y!475rjqkxyx}6)~s?3vGtvtJv`*e+7Id?M9q~i%4w;Z); z&70+ObY7rm?jWd)tIwyZeiv;6?mO|N7hzBK$)9^47%0J1a}?TfLJ^D#>14Cfkr050 z8Tk7a9oKUp>^A-iPjn~SfAi&k$ir$Re zrg2VEUaBFJ-{sI)DqpS~kZrum<9QLZtVT$B=L|eB8s+82eiZ{#504#mh@)j$yv8!V z4s+xdLE`O<9RYtC5Vu1|S>(J9hlF>BXp z1+|EW|DGMKec_rFAG}l&nhZ0n_Ld;3NL+S+R$DaafEko4Lz=Op zi@Gj1n@Bt2As+%a#hZ=~Ip*k5!1eY`s?~@hO_s+QiRhRTN(_k7%4XN<#k`Vs#4CAE z-XpI4l%x<~oX{lJ|DMi0FE8gbh^RTUFI|Th_Dbi|31YeRcGL5MV6M z-ce`x;9ZfI!(^%ZeBfkN&gEu>xxhrN6gSKKZ3n_G^cqUD3twH%I#Hgwz!jq^CkiwV zs7w~=*HliHthw76jZlnR$Ty>u^BFRhOWQHB+sx?qDUyezL&mVcT7)7tJM9Q5j}!wc zWBGvqc7K^@G(z%FC*O(haU5+>j5Ro7;ZbE(qM}q)q`cWHmg5EH3tJ6OZy&s1c*Z6`NLKmuO77mEufl$l<_n&GA0Co8j2G48efQT* zq@D|InpCfBjVVD{;g7&e+tgOs8}>%YJw8upxcNYXwnNV^?Lmru)`&rsQ8XvYH5>wT zxSDUqVswu0Q13U12(@mkMy|I}6EgJ{$xbsAT=J)6^rl_w_=oLYFMJYK<#gR#)mD~D zwKZ8+4&HeE{=?xHNUOn{iKk!{Uny`DzLFyDcr{`C%1C#E%GAHV5^Xj}76aID2(CqQ zQ;P`XxhU0=gdiyuBVCxJA$0f@gp$K%Ot6^C%ooU1vU)Ta0N3#=LxoZDlrTb1 zxg@&G<%Mn^|85+$k3QcYOue!{kKzO8(hv-ik^@8ao&3HC+vEsyLOa91-QtlnHLM5)DzZ4LQs>i8ltVI|erkYAwlkyA& zII?#Q(qA7}{KQH;8FTYnsJnm;BSYw@co1RJBsLBDc*Fb72eqGrD5`$GqWBDyU8AFQ zfe#W{Aro+8ZxBIEBW6?T%qKUa+`1?7l6-fk8S+c*-3A5Nz+tV))d%OP#fSD)^Q`$? z*#;`DG>5IX>054@!`vbv+4!l<}sERC<9`HHhEz5c-iWgR)AB z(fHm}xRSJhqA%&lJ`$+wERl-rvrT13ukoxuMVG;4xP(nU^qXQ)sSUdp|G2ZzEkmbD zVLDFhb9VkdxkW;rn@zoC#bRl4WUTr-l?SsglknbrB;=9AkZYh5NKmbp#wpp1@LoNq zi2|!U27mwQmwi$zg4-orBDnJ|SWA$lqA0y(lr zYe8(raNJL<|8rRLC*X#X4gSTCIvg)eF&1Y zcHGAZ7V7p*4>+1%bJM&tE;@x4ca&=TNZ{jt=os=Q3oE^Jp4>CKuir_7=`2vt9)Uft zCu&MJYSgJTG{LL$2T?bE-cjjtKqzk!@CZw=8z+QZWuvc1v%q=8(98`dhj)83TVoaP zWND}l43$M9ju{Wk+B;XZrDzTcaCf8wsDEu=q)XB&;g#iE1AxQNe|GN~|LtWxv-8Mv zp}Xdlq7&^AK9Qq$(lL%02o^%ov$1>k^3XGmz1>;aue)nBtM*aN$1P>AV~&s{rsofB z2v{iD-4Xlj&wRn#g_wxME_bc7954G;rn)kdqc&FidNf+K2GptmGu(t~lS!H*QoJi# zQM~(n+C^h0K}b@4ewF|M#m%OO(Xnh4Nr?4@0AC^Q03RDvAU&u>GbkXR1vUo)WC|jk ziO%ij273U_EHLH+;(Fk%C5ADVjcWps3uQ@MfWQ;u76LGVOq4)~{{s;Q0Ne-)mnoLM zC0YOwm-)zH8m8f#cOVln*Sda*g-QT$jrxT!7F)r&O`)E7BCb)Y z!{Jbg#!_PLpGc-z5Oh}`XXP(Xp1=zpn&o*Yc(su?qT42gis{lZ;)FsUJEy<()t?Wq zv|?ZWi$?EwU}1)IJvL<6DpWY%hEqZ--WHowGZoGVBLXOw?C4~VT6rro)YWceBt-Ji zQFNor^;1lpjAU)-WE)XxU>i<0{@b}Bg{us;<)aGM01FQaZUN9(%OTYPcRlsWP3UBo z2|`zzVp^cC;W1s)VO@)M*XCWn)7dEMG^5C$alI8)w?yJ!18Ss>k*d*?scSO(iA9=F^6%+37DY(^?pxe3V$pxq4-poh{ zRRuYnlDDV{L^UX&1cCmNc3t$X@6L_8b-MCV{Sb-5ant#~9XLwD3@cw1TP~CNEDQgPcD397{Ikp*i54muPBI~GEeg(OeO-4$k2}wy#&^5eG9KG7 z+>7(v*M&TWM$G)p&j#lYlQu%JA)bllp4&$}cagoY9xv0&y>dpp4wAijA>M|;odqM_ zN60?MLwrt_`zU@euOj=_hxnc^_q{mcdxh+GHN@{mx!-LYPKLF664DcC9!M=_DpWE3Z9j*yY$foaWS2|FyGo-Jsn)RtQZT8_mH)n+!Ibf&E0QVUH77!^a#5|qEk6Mn+=-YfNE&ku{is)N7fp2ID16xT zv$x#UKOi&wLg?lbC=ZTm1)X_nLMe2kYsnBhiGss$NJ24E?7oGyDdwk9R1&m-`U8&7 zvIuRg{xoIa2E@7l2$|}MaR$PinJUGb;=``nZS?~ALWB()#_!*Hb(d@96-!oo=dqzo z2}ul8u(9|Fj1v%evMzBA6X`Dijl?+56QSLg%})!E=0Z{^8!HPqoe72hD1t^p>^|nk zM>MxcL$FMU2nBYYVq?pE8HcvJe(Kf?%Z$wNNuxEYFVSt2zNp8%Pe59;m10m0g28zJ zna*^6(UW5rty;}VQ$MNdKQVgiqc(=FTq#nm5~)yYaq`0vP83-?j=~Z^d)tGQ=P1~L znH$3tS}8l8PiZWQ71<&cwn%Xf*ch&~XZK0ntq)+H(MUe?Rrj@RjhiA4mH#T(!#E9q z-9S=)MN*?_IEk&~&nC(Ok=H^~cZP;+V5eNNBUCEpfF2tpN8~~{c!|xAtrL3T@SEoRyCU^~daaP;u;X$YQ(qhe!dScsVju-2 zYwtQgytj0NZ3tXDv|e>z_jLis$voWtE?wFyzBLrw)}83!J&L_cw@-MS|DH}-x$ZhI zuPQssB_ykOhV9u?S*VBGa;eULEr4Bt;AP?s+8Iu#uVc$sep50`O+t(*Atf6(g`UeU zzTiN=lpT^YDs!DFQzL{02pq3)_q=CguLEG{{jHjC#;LK)N(cJsAAmGn%4a6zD?3~X zKXPNG z6QSx7T|H_;szUe%;o!6Rt=^!CRX}KJoq{C&&Yj<$F-?Ppr~VpN)adx zbyVCnlWYo#$t?Bt#vM3?w9#$1eci^n&-B+BhfSo)ha)DXJ(YB#8wJ-T(i)FeP-ugOBk%;)~v5NFa3QLVvjlBd_RR~5^ehS*f4lPa}HDs7Gy4}-oE-e zx>DD@`mk}|57^)jSc?TH85MwKVoZ$~o66q*d==$;3rl7a)hMOKRiW+T{yL?h+qZk-o z#l}_NeeOtmsdyjEMII1}be_Y43wB6W`{MtgjM!Z-DE}SKO{o&NabOs?b9HI3LUi;x>}`C@GlGZsI&WMJHE7A$^(o8|Sq$YHQx|bQ;9OKWy9}MINdhk+6{s_k#ptqVL<0 zze2otyG~7CX_O}JfGYROGi3Okk;gMc0rZ^EuO+1av{5+F3}}o?>tZ+8T&m^K8eweF zrkEA&0EjpiJ$hG1PWR*Kx9*4~W}t%(Tt1wm;Ed~?&}so;w0lT9O3rFQwrl!I2CUeO->qDgKgQ1)tPp`JN1l>$jVJ=oR~@+ zC$(_o+=Psc06s+LQ=*&tG(_4Wo_Vk(15l6;6#l@3veATco=C4~LfNXe z-D?UTGof7aZsj0I)XGYV5y};uUCEzNj-k)bGq-0;6D|M!a)qr*BBGak@|8L+;+%{K zCUk}Si|XT`9RIX*_?*#P2WN@2UV)(w?(#Kg3O_o{a=zv&ULtQ2*~gkd(-)?F_6^eW zWYh@Oc4T_d);rOf|Dp%j1LL>sjcuAEAGS9>I!TM|ulBim?(u1d-Jjk(yn6oWS%`ddLg1f0==Vi;uwSJkFnqEoJc+6r6FHXw6(j7hQ* zzwc;IV!noqVUACM*6awkT5;`lazZ<`SW>OOWvvaJ89k6hs3Z>VOfUB& zGf_s-4DMw%NNq28p6>I0k6#hF1B{L!P;7PEOue!Ka*Js;oIrhke2HE&OWp z_@;pOr`6IGZKyzKYy>S@X-mpt?VF&?&8-N9e#ge1wV&d>pRYA%rx6_9wZNY`y(?cK z=onH*L~DNZ^_1E4xEz1t^3z5S=BW+re(Lhs!`k2GQ{V0*mb%pParD5OsmIt^eGi`P z58>6rmOW;?CoVri+C>Z-hsDRP(#Cr~Z_7m?9G66{H?R;yru$f>6mS>>TS)GZRX;!7 zhuT1{FQvuw1@>T)O^y#3@B9W!v^*#P+|SfX#6G^K8^o$O8J8WO?_NJ=5LKtqQSbLiBG z2)I|Izx!Ro9ij*F_Telxl0Z4%4;B;BgrIVyuu{Y3X+iX+^%?@-dl;&C#4jK@(sF?O zC`}}%vh<;wgbidZB3XX}b#~85IBnYU%5OAiEc6od1k!yw3vvJNWm>Lj& zLM9NlKa+UtW;Q`50&#CEsl^z@3_+p8vS4Z*PG!H;d(F!YZ(okPTaqv0;Q`?Fuv%M$=UR+dU zblLv0uG(Uew||}d$-Z6#ry!k;wVZxHPZLLFVgizcgePpEU$YU74V01J_u&M}rWB^y zTB@Vg%7K@Ez+eHr^cn%%G?E@$1_uclgCO+}v{N;SfwN*E-2VVr&7yuqSs_iKbP-PV z7LAyBftD2?aTa|-g^IzpBWKQIEm(9^>Y#Qn?Sc2EWD#Md_5P6yWp;)_oOWs;h#(h~ z?b^&ih2EFy!rRaS_q5}LTbM(4f6~i5(+(jlD5o3!WXh4S zRWhS};5HOlUT;#GjWlm_22#aht}6>(@!UQv1Bky+!B- z&XFC1(6M{B1949Trpa;4BQ|`p=X+CNJ}5DRJ24&eM(b zMw8ph_O-YZ_cnr_9>*?j9cqAgNE_c@iORAD>a~6VXjRrLc@0l2QL+Upbi3QevF{pG zjM!I~i#Wxde`88fLF&SzpAXX=wl^=HUQJFpQefTi-YGp)bm89m1C$!aVg zom}=ULXt>P9#%_q;SgPp6YMunajD)9U_pE1{SbRWe26mQdL%v32vEWg3ebkn%C>TE zR^Q4S+8H74H8Wyy3-1k8EnGUMd8qz`Y;_{$-=D;-y|aS%)Lv734+InZdh&=id8TI_ zgdWMZu)hqPEx!3CZ{;B$AMb&-aRBL8InxHk0^(e&q;QQJbV4>8rnMj#MbB*^1`X_l zU#awRChNeC>27efVS%&LX=U*tFuY-(5c^|B!Mc`>Tm24~)zU{8lTOHMi0Q${IXH7n zNdN@gtJTWqIiHC^e7*?E4EHv{WUEvnF?7sb63kqntC~4zf;b~A$mr6ORbPQreXr5) z80cy)ClwkL^)+^%V;Pt;dkmNO1=bA{3U7tM7TL@4kGgwg6WPo5PQrpcBU6gCn=W;n zU;iZ~V)fP7b?k2Q^OU=9!%l8keS|EnP?=9+!!j;JPFC^}h#~=4KV^o|w6^F#17gkT<3E#&S&dnf(eI?pq{KtjYj(PL19&a6nu*q8=4m>@4b-v=Sj}ZwU;~H z3R@g+)_&Xl*Q5QI%&Tca+O+1+!Cq98F6?&ql!E38n<};>t_xH(G0o7qHn1ajxmqau zuJwWId=Py*i-9)w{uPknn+zNF!7wPzdOz?ydkze@K0AcKg0L$hHrk`}nSON@Pt}{g z{&0y%aEM;Q6u=Zk;&qnC(j*wwIOfQXa4+XM3OB#5Uh`7uQL4@FGVSK+yn@DJnbgdn z84jo^9d!}brM)yN($gLvV{1lrmLw&v{#`io-=B{g4({9;!N_f8!^~LQ4EmzUooN8M z)$tn0j$i|`9~4UiS=iRt0)d^j*f#mRrjmG@4~dg2MA!>}=jCvW*lRl4>v=hA&H(mu zh-J!RJCV{(Sf?2PaqC&Iz^l8|&;iQh3*X7lQG6OVy4LXCABP7f#b$X zASw|{ge%3`OSUF_RNB>$#qiX5RJ-?WZ{gbGaekqDnx{;^^7VJ?!HNfEztKFnXz2_U zQ+OU;j3!>apZ#zudkafulr6hJ+xwkKfVat+F9%ykC%SCHC(#UTDF|1}zJ{L$O>Fpu zFu03w-$D<3J%lK+%aQ7qHq4yP#N=I8xxJLoUZ&AQK6=YC?&kubAt5CzQ0^jXzpe*d zN|0(T%ARWlc_-w?_H1`d3mj$<#e>N5Yw`{u#BU^wY9O{pfKdmq43F*0VMl&sA6cn9 zviNhIE88+Hk4=EoRvPncUm!GD+el;Pmqe-9h1A8YtX&~qVSIqlszg)ppRO?W79voF z5-x+6i4n3&<6sl|%mY)gKPpsKLM;fbj)95WR^oltyg0G!%SXyw zd-deLRIeGbqX3pNq*~0&G=~ZUcmSDI_^Z4yLXVlTF)m%Xh=w z7eH+Q`{a6d;1GCL%y=AAEXj-0=7S0pSUiO3p~-$*^Ss>g>5F#2xB`_tZ7*=%*Te?0K zN?Hm{doHs@j5xsxQ}5V+OT6RDg8SQbCt1$;H0e{_eT~?> z8(7~qP0V24jSh=1FezT1s-U0{7RuL4KZMgF83(TJrs4gT<}|oEA8wkhlbem=45B%KDBcMhl|f%`%&V=!x+-r&1x-41gSaCXkJ_ zdE_d@u4L6T$9h_4)+xQ(s>HZ`*rJRVCzaD-X?$6!_j@!PEMAr^{C+YBh0j4NDh|s0 z5Xxq;ii^U6PtH(-*cg7GyR##hOp_g7A&vtEKLs*NeewzNZv8AY=RW-M<`6S6tmhQI z8$zrX!aI@-H$I2C3l0^gBReo|E{*uZjF#SqNRQS_uS?(>tdO10jg4va1)8i_ESLRU z|ItGDoM6w}*)v9n8r%ddF%Ub$zz~K^9IlyMdS-n76v$kT2dQh3^ z#Zy$I?NwWlPxm?sr&6@0brcSfQ03>*vIGTez zsG#%{wt>4PE8q8|@q&4;W!%xvEr&j>pQ(kbF5p)d2sZqbC+Rv*7WKs>xC=2 z6NquZ>^ocL<}LXw6l(Qq)uopu{Xh~|DOAM5tf9bvTtwZ=#;UgNyHr@BM}gCrhfdsg z%Ov3+CjIy0GrEn03mHT_cwk(^kWr!T{mi0sg@f)-$&MeYoSTKcg~|dJF0179dRO=Q zx*VLjrgb7#@LMqr)omGds}0x3R^GDV#7MyOeJ>MrO3H3MFM8bp`UXB9wIdL_O=a5& zJ)4_Bk_2BrTPiEFpcT1ah)Uz*{1)JaLF-qq)w?$Hf*laXeAH?h+)eGegb$0oZDk+o z=)TfGV9EjVyU8WsR*x%O3P!n=?Z-mwCSkGz5j}FKR-g=wD#u!>@D@cy5dYnfp2C} z7AvHWOTz4KMXwbia+shr^bo{{r=2{xdn5RSN&L#hb0JI#8~v^W{A@;iEmZ~im|=0z zYXM0cBCJU#lmJghDMSi2TtydK-HJWIB6QbdPYbanEFELTu+MB6?t+BK8I<9u66R;A zQ87dt?nSHU#Qg5N!dE5tX!~dYJd%W`y+y}Es4O!4DU4Ri!K?Hwy?mXP z=`C|%lMYOohKdF?aP3M{o|!7c2>Wo~U@*WqM^aGo+t+K6xb@L1b%%`bHc#ycl^wHc zY67*5)vu$2+7pMAEZIPq*E-XB%9<=BgLFgxHo{avsc45*&=BIfoYHoLh1y5^sN=6! zEpf_#h3g>P?zQH}J4)UQparlYeGpV11gdRzJwSM20Hx8xZ*dIFij{htgZ+zeq9l;G z#^a*#AL5boK|h!ie8ug@_}&uXg&#~J7TjzwIGDs^S{JJ5O9V1+w zGCT}>e~|XxFaG^O$|0hQ>?Y`Jg|P%YX&mSsh>(v-Sq~v3$f&23RIlMF4;OJ?*h?yga>B+ShG}2)svewbsg{kei8=3rD`^Dv5cP^j9?S=h~8NdARkwt}4y+IZ zXv>~&|&!tH%o$9xGvU*(gJv)P$o`0w~K}Kpd8xb2H(lT#yyo0v2c6E%L#%K z2LKtn?MK`}j0f9zjTrk)8tq}D_XV!(C!z6+;2mh%eZx`*R72TMm>iV3`5UYQbj5@C z$&XY?AeMesR-i5W7Lrk~S-At~PSEflSHKG-*%FNV7eM+Q`6Y;2y?$`D^PPNLC$}r! zk9w*v;Ee=sE9JFFaBI6*SFzIWphog9HDb5z%XO^6wu6p(k4+sGtP}ovX1$^E0f*z( zXj-hH`}r`Mukg#4!8gXssTb%I6|nxj3`R@+6{~k^3jMnr(AmlZ{6;y}XE|ZfMg~vm(|f>C)o^ ziUyAcKiEv;_HpIXbT9RhGrzq0ds4Tt&p|@kdCh6h*R`clXl*w$4~&eGb>5#xbV=np zzN&S4q*6BrNw!W9h{cp%-D$FsC+o*RW!muveCu8FI|>#R%Z>XRu7>TZaT#A8ZX7Zl zzPEMK7_WW#Gt4sjc0c+cNiKiAhFy@*N!!K6agrD$zp0su4I;}udVJRFY}DUff%(u|0H ziX3<^k4o|uYac2QgCMn1Wy%04>%eX-VKf&}D`j`{X{-p2V#TRL^IZqu!l z{Glpuonr0jPNBDmzeXrRu}b(WeE=XBAw28E7UqZZ*`f}F&1m6oDmgDuiQjazCTz|_V0=RCL*zJn=)xZxm<9V*=yb4ZUow$gPlK3#(IM4zeK+go{hjAMIt zUA?NFN^HvH)WMwf$r!<5CCAuCuj$UD3#V0HBp%t!+x=n7?jme`iH%u!(Rt2&hp4M> zr#NVSuzC(Ckb6?53~zi z(jOY0?@E8$C9Sc_^gU%KIl0sl0da}=vK3)8dhZHThPzA;O79}|&nq)1;9fc1ia zQjhLyhitw?%5tCY^)IT?thiVxkBA}VJ9y|S4HbEL#K>!VS^pG0pkpe#2{o+a%Ihz9 zC?~OzvXrXPrH{qV(%ESlvrEbH-u^8cW7M8^dfHtdI=m|{R^xr=ea%6p4pp$tmprLB z12&;$BvG%_W&P{i1Z!DsU~0IiWXC2K*j0 z{;xdjzdyVITh!H)AG_aMH#)9Q2|b?n#O6iTv^6Ecigfy6^+~f6d#|UC7oHaWIcM=8 zd41OPXJ@|R1Dz!9JQEK+^(vzcxt%wkplhDFtj---`#AK;?>XzL*SW)1V6(?w^9O<{ zo0+x09@Z3g8`drKCVAT4`p=KMQSdTd+CzPm7#j!F%H%WGxxO0wRsCJ?1^4lQmTzFO zK}fZcZJqCs^|J$yGa4bZ5x{kIRm*$eA4{aJL$-4X>^0MwW7HVBKh@$mv zcQE#oR!ab8Z-=_k8~K594mWV&gCdk$pzy;j0nV@qQY4)|_9;t z_SP?RE&pa;m0jiCWwXT1&5m`W%KvqJ`4VSQ^7?mwXbXU9JrJ>d)1#E!L)VlAzvF;$x z`nudyYPdTYMSik2D*CYI_8!%2Z!g!H-{r(5k?PBZ0{ad*!n&rD|B)+vadQi$Nfg+c zQ>#MLhBmwz{(4<_!FJA<&*HOnd!riH>@0Zel1TpVM0?#m+G)w{cgwiSCl$fQXO>@! z5s&uPWz8F(b?!>?^b15AL2zSc(4kO>i+`~Ga=`{ZDtlx~{cE3>+kEtqoLo3wG|M&^ zqo?Ff!?kaw6%1NUmcDsY|NIvX?fgHA?!}*}|BnOsZZ`ML{koaCtK9Fmc5_MYBo%#; z`=#6?s?FSUEhMD5Q!2L#Nt?MP2}vrnA&n@?wcCFC{Q*0Va~|jMID4PZ=XIX1;>uaL zhyU9>-kp1&wz4-K?7R+70yo{!{jaGhQT`Wus3bp96J$HxApPxU<*H#wc(~W2H&EkK zu^&Gf+kXv0<24{5$8y@$+$(GM73Ug zvq2iRn3~KzgJ#IzR(&k&M&;qI+sQpdSnJO!79@q#fX(&+m}OwWMXx2vo>?19(SIJu z#63C9=R=1aMDh}*3GyeR=r_Da7jj*eP;3)J4>NRj(lkR{A^74{2l8XR+TU5JgiB8a zHeC1`-+pZH`C5Li{9A+V{MYF#7keA~&RqJ>^!b5J@`po>l*?c;uQ&Jo%pMndEKL!r ztCJ{;7#GF`P{9&*#8(wt(IV)YHxv6zs8MTn!t9ca%mfZr#wAL*R4p&aB96Y^KfBIZWA(W-3F|-UHTGO_U&C`WW zc*Jy6>}luy?7G$G%QEJCxTMnA`{HcEr>CA9?}n{R<7pIxGJuB{(66wpC2-0F#J?ZD zPTvs8ga6ri$mF(LSuK#y6r)7#jG4yYiiDQpn6i6_O!cUIp~AF_vyVnTLb%eUT^Xro zmZU#n=uNe}zoaTlOEoZ|2u{=Vvr_5Y*1IlPs0le&9URw{8H_di^3fF1VHN+?NFt!) z0R^}Av^`Sa{BwoQ{V96eHTr4=u3rD?gBtppm@&V6|2m;x*}LH-?T!qa?9ECw;-Gm> zh42`lfl9?Wl&4(s6yPvGY#yaKa_*t<2v4FHEJ24zNP#(0Evw}i@l9>Q`;Za}B4+nldkjWL|*S zCU(KjvHP*>=_y{$~6h}XfMw$lz*eJP4?DHKP~Sb>OZlL8>*q5>KwV|p^oell;$OCl~KH!(yzV*>(d62 z2%Bg3VBR`5QrMw&H=7`Xj$jDQT?`o3X~P<^NoHD{Pk|+<6A9j#@rjvd)rUV$wV$D; z*Lm2V=_g)G&0?TyDB~? zTa3$zD9Fg|$xO3bB^dM+k0=d{^iID#-kmFz2-K&hX&mNp+XU;n01#P-E?JwBT>et- zi@7`@PKQA{1~mKw)ed18D_4qx!Dh?7=H4)CG)3qzMUTVADosBW9{~)Wa~yp6tZ5c- zn#RzxOXuERi~aVa`gWZ5BM&UlB0u=)ur*EZNp>8rYx;5A z4K?=Rah9Ny)7;CAWv9L|vOyE1P_T^<0)9du$xPS{5|0fR?O10-Rf6iP$v$rfXtRK((mUyS1(2cHsC{m=CuDeL(O2)0g+ttgzriQy@IE z*k#dRyo)%V>hSWRe5cc#fyj9+WB=0|A9(KLE z-;z@|i8u6+dq$yKK(usT%b2u%1WgS^yb#|^jV^;FQlah$9$zn5{>QX~UjVzV=>%V> zDg-O!MTnQ8hky)O3-S*z{=BP*ff)86Cae<#xK z4(R$ATRs{WmGG4Cd5PtjK2bUGS${hG(TJ@8_$WFxo9%i-+1=?S%*X3R)C4RX+aruf zzleU69QAIl5E}ZETZaI<7-<+sf?en6HD7f(nQ-}?YenWsbtC>kJ=rV}Vl4AW{7Bfw zs6<+8vV*n%tMRP+FWbFm^pDS^bUw+s?8*OiLgMe6g8CW%N5>-!PbsGuh>w&&qC8L| z2K=!=oh)d06U4rb9M}pyGvX*xm=>}Rjm2h0jX=G#Qs-V?Q)lx;O2gt1uuw!=5LX@* z%@!+!gzle;lg^Al@I3Evx_-M^Tv{)T2G->8!LjY{8Ltm(S4C&vw2Uk*D3c`DmgYd7s6U z)IUTOXG(5QES&G|XeWA`h@I`ejQdLb*lqV|sdv892gmnzp!eBFLd8gsp}|Hj7v1Pt z+R@-xy2jE!ot*x}He{w8=hjLvr3IPi{+=06WePd=@$TY+Ev-Mx8~a+@Nw$ptHgsJI z`~<0DddD~|oOtPK@Ho$sDG}s1LT-U)_VTc6{8cAGwsGqT9Qo3ZSr5x0=2wUvJdLW*a`t@$=)vmeECIa7)H+M~_i>=F7N%=o>KxzoG|C!Hzsw@6OBTshtoi4O61t zT|}gl^1tLfW?xHaB=I%6I022g#A*mE6u`}FLgSbw1p+=tLNd}`zD>vi=Xkb0W0TG{ z!Qw-pK_M9x2~hVDQ$b1LBOz}uQlSAR&@dfZG%a|l4&(yQb1s6vA%lsG3wAsrq=CpT=$v47wpeB|HRHz!Z#WI+ ztdz!m?%w3sTw4~(7HWNVp=|B9Tl4>+ZLZv?{Gy$lUrQ6aXoCkkPyp@d({B!G=d)SC7tYoO?vu=e*~n=K-s)O_JV#T_Q3E~Sd_^l zacN;amv13#Nf2ssKIl7_@QgJD7WBc=tr?L`whZ3Sg(Cp>LRd08T^KEhr14mfkS1!= zSFePAa6H5TV}n~Wf?LyxOi7+Q8o8Sp$z2(5j!;J9L1F6|4@fWU{Iw549M0b+g<)ifZ9**8*fkLpbeu zpH(B~pwY7#5u~<+vdsOZ;-Mcos*O;X3G~d*G*DDVG5`h?pFI5ShjsAw-g(o*0Gy8C zkH1PEi`f7p04%x5!Y}A2%6U^^@7b%jsqhdjHT2g@A(_Us=m$Ue_kaI9hkk_9-X@&P z7s?p48Q$?$TZemb_4G{r5fYJY;A)2}nk8WoFdlhmG@Wj=7cH@%_M=KbmPB%9=6L|3 ztb$|IE&?1wGAGgiA8U7dEcJbi_hQx7FSeMvMgamXGN*3y50<1U-^ldipj|p*cbzj6 zxG5>i2}2)Vr`(C>;j;j>39$JlzwtH{@g$yRy_cDp=y=|tsSc_}IvT9L3;zZ2;cEI_ z7gP4Ojim~EZKh^~RO9c!ND4;==hp;H7~N4o<3AZ8XP=1!C@&i_Tz20&=k8bS9oXjQ z2%BuiaTV_qkcz*VXYIN!7TSV#mT@mH7QxHZr8CZ7f#Q7U9z{KNxaFhnIFBGe`k;SHY0$cF5Q>*zrQE|bAkIfZruR*--VG3y~Km2tV_e+LD3^8 z5;xQQzXN{)WU-5f- z^Y30JC%hy_xCwG5Ir5M>*(552V#Q7X@EWPbAr6<(OZ$=%h=@OX1-|^+?9KV7d(8y; zRRtowBUAgozN>r7q2~G%igdB)h56rV+9Cv`u;JR>;O|w>Dt6aaMRk9wO;FVpB#Sk+ z)u-z0Z|X&^ZEH+7xiz}o58Kh4X*vBQW@ByV&}^&!@O93S@ZG~7I>X+zBhO5yOZp5u z)C2gRywmZ$vM6*c?G*NTRLG?cbqPW~lFE4bRJzd)7C8 ze*exnN&@nmpvgS4iRjd)Zy(QGvGch&?NQE_k&7s1$q6O6ojw%SnQu*y2(A0c zbFi!y{nzH@MDMq-uGWrmLzz!AIR3!at&C1yB^5RLx%ka&Gd5Nar@cy5`rd6VXXz`Yn-xhzf{z2|7ENx7w;KeFlBH904cC53JLS0e* zpw@-f7fw5^KW*j=dJsG&d$az=p0V%F337Insz}zx=$+{&2K#aDX>?jV_NB$I6tMK@ zv-Rn`m*Mf~Y}V+wdqMkmgrz&boQGb%48D zMie2E6CXB_8XoV%Rj!Db=~&<-vNE4N^bl~qaoYcWzk0vKjBdF50861hCe>iBM(Pft zQhdvRv43Cpnuf>HQ3GoRf7%63O86Q^=;g_0*k5fKP1SVOxaw;L*cc5b2a2jD85W_T zd&8}{RIS^@I^``GHH8>dC5i|oPJ^=$W;pTOt^AKNPEtI@{Jgbg4uX+riCvPdf^y-t zOKfm@M25C0-4K>dM=Nl@q6d+AjYxDS+yO~!6wPagUKDg{4cb`I zEwGP6-%j%dcayHC!V~GjIWB2P8jTn|B%I0FAF^z6#a@_Ol6h527K`I`4GnOHu$8%+ zBWpY&#cmoHDo}cn#A{is$UhTjCq;8fKguU4=nJ?>Xazvkx|o8nK!VgXL_Dz+2+wXM zwCU}M-6`f)194o4vUfLWw?e7~g6)Pa;zW3~NjQNYs{k|b*6W0z2&aHn0%n1fesx4Q z`BZeOR1aXx_>YGs+1Cm6ThC2Z<^Kd>q!8mx4HSO zLUJ8;l_WNf&3e&5uTKymOHH-9>Df`QFIT*P)wp;N2gria{MRJU+pBdgh?^m2u`v5` z@m!FkfNK^WOTpVD;X$H_F6v4*K=1lThuhL6==OjwpdGJ9xgBYk%v!(pSGNwC)z(bi zdi+QAKN>u)t)bjtKiPQ`vI+Th@rwn_j zNAskOb#z5u3c9xMvm()a%`fK-nILfJ4@p&iH=qAG7&$}>eY$|ni%%&-E-)MUo-y;{ zBEaVquGyFkRm1eVX|iikP<^Lf-`H(X5yoX8O=3>ClvUmLt!KzAqnCLh3-6}^U>HwC z=PNcc}@;f&FxA2s4McMo)ST>z^$WHhs7xZ8wvz+{?lF30$oe zwU?OHotRwq^IAfc#%1xQ-e&SVWXMLew$0rw%!?=1x|KTFnjy%MEtLT2Rg+=Ue}{!` zUPg=Xmi{!KniNzxs`7!2g%x*q1r*$-3cif8Q5jNA4V+U#hU&P(+^P>phx7}41$@`N zb3N67q=cMduFBR%<;9U|U4*&Iy39#oa|f)*9@bX&dh(}|3IQIEE}}-5tAOhqP(UXO zC(M8NF3&0zT)_;qoDnQY0>GDKU5WYOFP4AH%sCtcY+4?+7`s%)5Xi8{8GMU2PiQ^I z-s^(a@y<=yxq%g4a!>6+5&X2yE_yG-R>r{fIMM4TB+<*(a;2@E6QB4@$~|)QcCD?W z>d9PW+DIjDVm#c}qVX2->QMR&uW*=^{&*5hTXcRfKj#_a#~!b30y5_Cu_rgb?j>h- z8MbHV6s;qFG|gJlbl((QTfB1Vi}|Ew!tF1v9(UG9qSL?NLLUT>B==jRrk^@(M~-Fq ziJvet-%f%DrJz}lDnA_UY!f>f#{>r|zMVULy^!{O6?LCYGn@eo4KCbWJ%Q4tb6R4vfYQbwW|1-$yKQxi5nj*;HT{4#@ zgr7(??tI5;KFhrr)2>wHELlta(`Mu#w6|aX8CXvlFCUR=!k#bvOVEF{WNaWWH=An4 zMxr7Ba-9@QCZ2~#H<@$R51_#!7?vRf&9j3r?vQ(np~)trwo_RFjNvSrp@o>iHckrC zufHjJ-1E4MuLSm=m>P+pa~+=EincJJph!537e)Sx)5#Qo@}}q!i-|UpkUnv)AJMN_ z)=xG)GZaTsQ(n{`z)6Jwl`AP$xfInGnY;l$W@#wFAEV|FJnRZq!J^V=%!Z#g^-t)i z(2B1|9alW1SW0_Cd&wNGM`o;C%VyzaaX>^L3W6=Tw4aB1J3$%bgob-I{#BBrIL`Y3cl-wu1r0;}2iZn}=S+6qQFkZ#+N1V1oTJ-7#ASV~hMOyD~@ z!w@n39Zj&)%r}~LyOw_pX7JI(3mHb=vAoIv5E>wir7KeL8kYqA>sYP@)#MIWXerl@j_k`#*4Ocz7zECaTQW)`Rr$i&OogA{gW6x z=+@?_*+e-Z1!Lht!I+SFBhKyqCt?j6IDaV&b$n8`4# z9NU7_s4q)KeqiW%g%4U0xR$mzm0@W@7`RPBr=((9UJT@ox${e5HmB62Y20Qyq9p@v zBxll+$IGU#Y}9&gFImzEm;e+?aNgRt*fs&|pF={91#3r;cW_Jh6r~1oKc-PL%`CcIuA^ndyEC3SC5VDdwnbtY2?mhe~7L$5S3&&y#9N zJ!GM^+y}xa+d~0htu^}ab%hA6^Cu#jJY)t-u!teUyeVRrGz=!&mVoYUUC9>af{-o#L-A8zSi7F%_BwWcbd*LBEnj$+)BN27TeLBvfh z2VsaxQ(t;I$lp@^GkaseoJ7!1#LFy8de8=qr5iNjzH4Un>$8!dau@O5+VUI*rO0u_ zhH$qXxPG2ApOOZt<0!3nQ za;NV63G9ZsvQv`BhDAz0v`)#&g5fckdtHyh>j7BG0t;>9t+qkO+Hn|l_~j!ix$zXY zW6|_SV(zl}f2vE>Jj(t^e6l?JdNzO*T2D$WtjWrEIEg5@&B$l%)k z>HCa-kn{eZfGK4vREObQkWre3;|X$|X{0Cih&f_w>U5;&Nt_9jpwH|Oh{J8K3+>(oOQY-22yc}v zkW~t!q31|$C__%)$*izVd2?#I##2S`{WLM`K(`=aXzSK(FH6X_BZ;6AJ}g(qFmo_G z@tn}|%Qg8Q;d4-XRZKeO=@?%x*?@S*RAF4t%f};&Rx!gk;sJQJ0EWS=VU=_v4+jIb zrdzQdhG5N;g+KC&!BJK2JOoeZUd9U2Nc<3x+5rAYalc9w5CNfe2yoNv~SiUxIvB zzkUi>d!C>l7f+*ZTa;0P{u?s1W8|eJ(x8On- z$Np3)XMxRq>1xXiJsk%8h`wj<5vTA*r=QysZ|?>^C#a+VT%T^aUV|U}@q2ffaWR;o z*Q)12yvE77*A^~PU#?U&iQsLmKR!B(VD8iOmJqUMasT2DsG@cP z)|-T`*wtfpBot?3kHiUT>+kjxu01}0_9hKPV3Sq(pNluxRD8=?+#77CTp`F^Rfy(@ z3ar8JziMmMK6ZkvqXll51Sn5~4ZXoubNH>AF~=|4((q!D8HT2pd)+v}oJM35ks>Ew z3g39mHw#=~^@BT;V7&)7w9_laQ|Q5Cw^^au#Z(Js@TuATVAEf)0FoFYRp&9m0&mS$ zhszl-9E@4R8X(WN6#b|SHxpBhC#Fh+Pn+PkHL&|7!znipXK=Ca!v?$mM~S_HKrSmW zVZ%hH^2V=N{t&WqmtvK?fbdj=Zyi)Gx79f}Va+1eAbfy}HFGDwo;4b*5;*JCcq_Tu zy)|K75wF0Tie{44m}s4SMXfl3er~&f1x<~JRIGgJebT^$8UF}@=cw@F1@6#IXBj4~ z^ds#AwAYQ?tAs};5C}W+MT@OCvzfS2C5FYT4A8$#9x@Ie9bQc}WaH}xa?M&F`Nkg6 z-brn=y)I>!s$2=IilF_Ll^6BV)Hb~@z{IK8ffP-W9#EQvS==~4dws(I!g^#M@x${LKq;lLW;2pFKzmVMz!OBT@HK^P&GVq{% zvj(no;7Z`k)fC2RF6Dftbr>nLcAO78v2VP|XgojFTE{JP!q+7IG>DfrDe||@;U+fk z4GYd$o|90o+MGU*>OF@st8_`iQwPO^XWzdmp)Wp%cXImTe?!O8twj=M-v2IzRz8c1 zAWnPq6ocNKEX>+N5d1wdgSh-TRG$dl4Y4*lTrF1<8vuW)kR zrFp?3+zV}+r225-NO_{)m-HOhdCMTURTg54MR=0DAnqB`@ZG1LU(P568&rU-s&h3q zxCe8-nI$B_`{+%uV;WXgt?vDeFRQqkgxwy~)$YwRFU~5U#n$fS=L(SLrBC9|DwbGY zex_Wbn7+we{d`BT^_-eQq!V={U303*lRDQ`Sy>W(eug z>Z>l=)#X4%s{Fp)PN=M~!$z)?8*k}P`4Ue0+@nR;-1IMRZV;;M4o0P@Zl9n=tS7-l zVFu)3RJhrr=?~#;uRK3Sc5lplyg(Ovhw0$hb*BkvWziIYiiug_4`!KKI}$1T8ls!~0?jRw&zZP3c3wPTHf>CE&acZG>B ze(2;Fm0d)dJI#_xPrrMSAsg0{Wb1TzhBE4u*uI`28$RW?QDSe*dkSA_=G9Pji4;1W zzPnsx>zn$yJG0#BXq0ttf_GoW?W6_8THz(8(xn1i9E?``*2zZws1 zM5wu0TbU?sCH1h{UurYtL&o&>{$ZugaXwBC$wofzgVC;n=Ap;p+uLj$6`#@PiQa_) z!=EGU!Ws*{48+j+F4(V?AGFmS3{{+;CI=%g^d4l~!kSM&I%b=TY~-%*4o2M-Rwl!$ zF17P{cuKXKzLk%gqAPIXtd9N0l&wz+6nfQxUolTx*0|m$N1&y4T5a{MTJHuIuLLi) zGkJ8&a6;z`DadVK4;wVkV`b(M#R;5n9JVMwDMEXuY}j&Bgpu4y5YH2>(q~2&Tpfu* zy`rAR5aXmX+6W3Sso9QbKjCB=LSawGUZw0we~(=~czgn8zH3wj$KqXUW=TJrT;Zyt zg~;gIQNEbT{A8Ui)J|c><}XeII=-$Nr$Gam{7{73DF=qe*k@*K`oXJP$;VT}Y=qCv z4uBlLLuiS^vVmR&;U3jNMYTLbW&3w*{OYbmEKiPLp5&C#bQJblp&|v*17zO1V>=-k zs}0wIr`ZHl!oI5lw;V@1BL-O*QDaG)glW}N1-_09n~!iw(iXhJK~{#)^C{p3HiNs{ z0?>QV^<)666qZdCHBdJ#6k{vOAJ6r(>H`X2P9Y>_pL!+DcT<3qR}Z=~I(#RErxaUV zd#hgjoYjwNc+{M_3sk-qXk7WMvJ;2=>FK#e=wCWiB;fVMc02b*d1z&a((O9t7b}EGE zP!)wj*m$^ZJdR(Kd@a~cNp^^oCNQ%E(uqnH3yi|~Ku+*E&*CmCs58_`6@@}|2;!k- zC?7K$3497jG}m2D(qJpwcw1Swgl+9sKPh;6!2Sfb##(>6C)d6y7_DW(P_w}C?))7P zyF;VkOEU_B>wwbPf72uzg6|O7{&y#(p^D3DheRNY661C)s+H8fLc1Cn?N}S_MVF5M zqk^=o47Yf4drlSr{y6HszLhJ_vD_1n2X^GmOM^?qTUlb|G*DwtE1y$kb&x_9LlYq< z6cEAb7Z?+pj*&VJmMW%;ox5Lm(woZbst&T%pfS{@K6=Tjr*=*y+GvZnA#$=vf;GO- z6S24qYzl@J_B#`E$@R1^V)5B4FhkW!(L4NDs#wM5X6B=hzARjg)Ps@?{qwl2GN*KC z>gIrIO`)?CdT|i_Pe*Om#ZQ)q6RS$3M7(XtluE`R`pUHez7^9%4a>=^6@7_ z6?Z17;Oc9!umv-TV%h=ZDNa9Tp}buvDl~L2D+BT;R}@KkKbDy9eME9yUC=3?coCO+SkGI)n)xJp1Ai-o3$9*2QeP z{J}`Yt4h$<-uPLnr2b>4XCV=vd%$lWKTcnHzg{x^;ce>7BWFl#WcYt}8Y!wz+)|Hh zoKw2gHF8V8goV72^txhU2Q}gy2AJ-it@z{1)Q3Uw*Au^SnKohBoO4qJr30>T0 zD59dXkAD6n``I}9lkOD7xpE1)w?B+S#S|4(F7GCgO}24D*FJu9nxD;}A4kRBdR@6< z_~hVKv{j6(j*?u%Y}boeuIB{5&9*lFHCgmPg53M`Q?ui*H`S>4X6M^$CmK2JZ|+yc z-@kDCtIyuAcXU(&*VPUU#tD4EU+NaP@QLw#P3|3*z3VKKl^)fEw|*wxzf0eHSJ4-)7X2E8hvhNi7jHi9k%0+W!eyH7w2bGUN< z_i9*@_UPeB4b-yShpg})*17FCSX3HRk0$)M+Te$3<$A7+GH0u1TQSsYU7@`?ui+eO zofUG{?{gL2g=@AhC`uXC3L&?&`oOZJtrI#!s0o%}z&&seQwCL|3}Stmc_4lpFW*uB z(nEb;R0JXyjeM^wAJ2p=pp%UPg@tAfM{Ilak|rgt)EfFDhKK+LEaVk5=PxP;}~oqK4>_QfmrLICoy0 z2-Qs_?EAA+XP6cB@(N2%(~lEJMy|2s{9BZ6aq#bnRKZ1((53X3;xQN}s?wh8`wyZ< z{EpjBScDx2Nvu{AqsuPiRR4T&rBxdgZy{^0XkyV4}a0u=+OkJdPMg2gcQc z#?kmX@^PZCM8FWLmoAN|*OB5E+{VI-^>`Mr@O2vBoZg?IE#1|Y&4Cz=riU*DcMR{; z9Oa4Dx72r2DS3%g4tNJ4|s!vb9l%4_JNW+^EV~!rYIrrcK3KWh~1)(Z&%s8r)0Y38| znc%>J?DosAv1GPO1c&Gb3B`iSs~^v5c8 z`pPF3%0x%ooUn$uY{@8N|2rD@x92eWAq%w<@X8Dz>O~PVLvx8d{XW)-fkHDu#Ki=s zpg6nCSwETeQF&{s^AtIMJ+*6S$8zX}GXZ8<=8uB~&zPfq4 z-|b5^lBOtcw}?91To)yxKgETj-^uwqpda8QVD2(sfM=vY0xm^SbU%3}OJR*HsfxE9 zIER|X$zujC6R$^q+1(spLJqOyQF{s@z?!qwDAYUo*;Pd*PE^@H@Od@A5#Z3PYC$6a z9K|OUG=nf^N`J#$`u9z0nB}n0_S(wea^6jAsTu+G3?VaLP!3PPDF;|ThaTUC78+l^ zrXJfwikFvvWeRi*-2lp1k%CJ6wP`@q2eNQcQ1DS-iElgHv%l>bEg?H7&&V`<{7y@g zbmbFJGqLL`?g$OOM+!i>M6Y4 zFo?bMQIhxb;~x*Y&VS#%X4;`OYinl&1jW%&GdMUAosOzg?`5^S(fIO-3YbOTPm*5m z8+7ktVe7PXCOus@tS35%ecX{bDEv{lzQPEyb7}|^`j>603cJLeFkP{56 z%3xh4P-fz~P^seans@SziI{dWq8A|OjSFhBMngX<%(5gqv5JMbavv%vmmIH3J&I95 zs515RYGvkUx-I;J4pfCNWy@eOMvGln7Jw@Wf+GJEHS|d55sB4zsoGP1@>7cP52~f^ zqP19(+6K$03>=7`Tc_rGq1KPmSOXU)BQzD&`6nXwg}J&WI+>-L0c6~EB-HVUUT*JcLsoOY<`!B#;z?D$jg*lRa<5JA=$miTGx>@o zIZHf&&!ltfdqmvXV3Oj|Ls-ND9pym2t;n%)ub=}EKOlFp;%60yMa!G6)FiUH)%>H8 zg$*vo0BL(AiFLH<1KhKK@}jSb7Rml#JoICOc+u9 zjCwF*Prxn9&DU@Ae~>eRD%ri`?7QX|*D_T?7GUx{)F4DGIjc87CC=Natf`^ zZ`#RN)VhLLnV?RsTjK}+xZ*-Yd(4S4+z zu!nZ&kX>ncdMm^l9@V2V&?U8rlQ+}V?qj&oSrBFP3n8qCJtj8$>*ce!5-VnfwQj?` z>n`6F<^D8+a_R$*V(Y$CXRI&U=B1MU+MvSNavy+p6)a#C%PrgnjC&)|P(lRhi9V%E z>~%PiseQS7mGnouDqXG9#`;Tv) zK=Nwbp-a%H;JG>Zqv(JIvTP}9>6V|2fuU@bH_QwmGE*JOq)SdD6*=>WOxeI5tSU^< z1&UvV%+h7BS7a&`RlS$65oFu#pXNhP{aD`PFOe7Hs8=Qwmv54}*C;!uCK3aNrv=>f zX#CCZ+FZYV{i=7Vu~yq#}bO!ANYK5JoO6%vx2H4f27~#{tv0nkW)+(8;_(MKfwWma7d3n zdlTuy+s~ShRl4#?FuC!kPn*o!|G63aN;H6_O;}<^bZZvwC{2?`6DQ|}%2;8^d-_HD z%t|b?kefJ#>Hq%5X3N?yVE;-Z?~;0a`ojIMth}MGIFn==l&Apw9qi@Z?bXpuZOVO4 z^4e_WK1|o2h!i*9?pMoq;Lj1~bVs#ER`rrWKi@MN*_15o=1TS&BARk9`Kx?PZ}yGa zfl4!Fn*lXPe`xStzjbsQZo2nsG%@NAwbQ2tu2J*(j7>8MiJYZ@boDubf&th_l{xtL9LQkNR_hxQo2j$REs+fh>tJkpUCv=?Bw#g6pPGGV*P!VLA1lqIx9 zNlKLDB{Q7iYx61j4naK?t&TC($>?b^=KpQ<7CjMEcUXx|25)BY3DVe6c4AQ~@5_;y z+-#c~yAcBaa=V1iU(EghOBR{VbY+<3MvCf24fu~T^zDiXNKe`795ec==mzar*> z7YQsDK&JFlQBEhe?Jd_47(7(!6ydnlD+}f;^E+KDUWuVLyJU<|SWLe$Hk;&?so;To z<&$JxRz~K}FA3Ou>dc_=PMy+EGqS~QLEg?-?TFWB zx1X;~e8k^fv;11DNFGIW%KP9u=YBf5i%c@p#9SU60Co1Vz(Y31NcC5ipSHWVpm1p# z%?6Wl>h+=K>R+CY!KhN)eC*z#??Fzdh#D@7)82U~IyJZ-9 z{E&`SXU(4ku0?v?h%#bM7qXq<3yg3tu>4dajJ> zz*%eY!oif+Mvp9SeKX%-w}*!|K68{DGOOFfLA8|igwJ}-K0cg;#407ou6Ws)SSuLD zo-`|rd)h>NW%;f%u66hu@fU|UnP+M6`i(FKpdD_SvQ_===)o<`3qSo|$BAdqAevER z!3ZjtOXc^cU`5GKttDtAx~2}n=#mLAw9ha9qyzJqMj`h9-;);QMMQ4y59`=uX&SNd zQqgv}Of#Ljq+SeSqcwB$a8T{jZGVvR8<5#rb>0VqU=*iZTCo*TEpVFTrxRN~Y!RVI zR*OdqFKlLDit8yt>_rqC4XzJ)cY|MN3AOIa@Tz$u;2N+Fx!`MSS%)hD*Hh)%Lq%=9 zsXV8b@luJK<>f2&+SIfQ+%NA(!)E*ng1Dt78f=;&;M}9DiHgYY+>)L}9kK^A5H%m7 zfVs&i5(F?%D}|*dt-d4TbwK%@!ePTs9iRyN2RKFs{uTfEhFB|5UPKIrLg|Toiey5Z zMRBke#R}uZJPgKez!bBRr{{138hT)B)BVD^;%9q(ghsHTP_kgyKxj zft_Q3;9Q`HUgZ=)EX~%uoaKyDzXo+}KvDV}*GavjTm zr5uPe8Ih2)BTLOHJ~kE{;>pr+96=H4Twz=yklr_J<|V7>O@OXqg6N&nS;nL{8HK z40;lF#dZ1SgKJs5+fgk^tpuv*F}mJkMScq+oiExeW2|kwg#$6{5jxeM@ z#{gvlO7m3*hxw$pQ@Le1@Bku^;zY88^^oBScK*$QO$sKRI%VzDOsby1oKeF;uR*UJ zl7mQ#zjrMw_g3KL#UFf(5Wdya7CRPisk;}8BA2fw>h zm6}N}9L~4jxKpX4mZ+5Yh-Jr5L+2;EDDfz~$go_l&cBd#V7(iao}abu8!!jH$^=wX z`b6%E$B|3dNlyI!4IDLmlzP@svaLz)K>=dxSgS$Tvc=5gN?ezrtVUNkZ&p7wn#8!V zgUFO>Jt=bH$Vqu_5tWhFUke?Nhj$T4lSku#JwnUzVpgdZ<~*P4K@DrS zwG=}*u&qSb2qY7i-y(`KRrep$FL^O|`r{le^Yfm#BZqh03gdo>LGM_vX zDv-N)@hLI%_Nkc$?^7_)Ercmue><8ToqG<6{F|Axl3HrtTl;ozBmeN*Hu0#CTDhuD zTbE@ekU8}ntFqXTaY0w|+#KUh&Q`9?J;`?x8XsKvE=rzyz_>I2FTs34#5dup zK-iH|UPhltcpIln{`JO0>pz}f76QPNv|-bxlFfygC6xDYzW(CVt!ih7b(N&xE zRvUAS9z4FQrZ;pXgVLi_5E-J6(V*cCK*RCLV+{HH=Idg0(NYhVl#qWV$ru{$zbxM` zGRvvFZ_7kXlB1CFuXV~vlQr2BA6O2q>2Q-DxV+61G?@dy@c$^f4}YruKMvscy4=CV zwX(VP$ez~>my9H{5Rwrxx(Zq4UKiKyTG_g0R=P%_sB6!3iK6f&(xqW%*8TbY3FmR< z=X~C;=gZFXH9W%9bata-AVjRfc~ZTSK^N7N`^9+CKaC(^Sx7KwF;?2PRxxIAC9a2v zKA-#EH*aXHojyC+vy*Bf#MVOix(v*`g85F@PYX=ZY3n>?uVT<~+tfud{w&*colIrD zJ)*xTFAYbtD%!=pSY>r=2_^J%(5~Lt(&m-Jfa9u>Gv+sbkfYB_Gb{L6A-3<%E_2e_ zfSlLZhpCF9Sm-aL)~D8chP)B`J@?YY!&c(MfYTT3zJ+NgO8NXexxiQhn11 zdI!rgNM$L;fCXkkY!J}rl!R9#sKhrew{wuIwMj()us}5z-VWA>J>!5`lDC}w#273i zS^Bov+llTA-x%aPAvKhQ3ILeygn*hI+TPrQ3(vqg?86kRL3gN-09!>R3>dcsR+6#C zg~MGA&wfE^x+9Z(v3wd7uxWuMDA!<>lPMAbb<7sguw{zILWYvlhiV}~RJpj^)KFVK z#(jLWCq!P0LzKjX+k&-iF&BA4oDqgx#vo^vj8Lj)>0RU<63e?K_yh%BMrE?OiF{j- zK2i&5=euh|h13AxgGR{-woKiQVW;=F?jWE+DwjFV%u3Jn{X_iBp>69dWP>M*a~m9u z&2mL#DV=2wkbJtKS>DcBr#J0k{-WwAqB2jaT5{Mg4j+AJj;dUax@As$^`+T+gjcI~ zMX5kxGSEOSjowwDt>J0q$YEV}29r4_B^#Mao=ssbGfb@J2yX!wG&NZ@^Dd?cmK^}) zL0kdiVyYZz5|+6JM>%dampGz)SCAf&7?}e#qjCubIr6xGwil6YEK+4&Zwt z`z9useqbDCGgR^w_GDY`$*$#-{eUNz{Upw;Mct=(B`nJnk>!O;DPw=wX4Df%DhXCk zVi_f|-WHKTK*m+z4vaae=+fQEvfq{@w$XCojdD@u3b9oDfL$K+Rk?U-g%wvb*oCv+m+g>l{)p6dZU#F8aFc=|x@9z|S=>2^p8@+SGWXe`YK-m;jIitO5X| zJF3^EVl-d$hNKqOMXVR|ZwNb9!rF{jG*`V+DH+eVnA<2YA30dvtNJ2xZG~7p*@}gz zQo9!F(^FXbs>tWoc99Gc+HMP*^efc>z^bgE(W7bpMbLJDJBOw1mqTVhBVFkEC@nG7Z86tjZ`yD&eXFl; zNQK^aVR}M+-XIU{)XiBb5`~^9GymXlCNnpAK7+5``1ARB8xc%%#lyVg|6rUAw2-!H zYzI`<2fhM}p6Gr)Xf)MR0|P!YDyP*l8y8;eUV(f1hf$QVizLC%0nr8`-&^jz7-Hg5XD?iumg?}*=Z^ovP@DRDdF#s zFS?>Dc2r}IJ!2M_aO>po-ffYS)qLB}g~GO)%Z0#~#51svcV9LC`VTH!ake7_t5-!B z){+1B-4bn?=x%HWN{S)DQ-AC1QKZ3N)2zOOWxpk8{cxaJJd3>#(>@x-AcO3V##^DA-&ciWi#a{T}^n+a>DMS)e?mDlunZ`rm}5pfn}B$ zrnlHOk<9vaEL#Y+yn8PKit}Abt%sD>o;LUf8S_(x9j(`)M1|9TkTF_+s{hN<`RHj! z+hRk0Xr=cRcc+veq@@lLSp_C}$BZtLYLvaNw^yeX{axlgq_)RGUcMCUluOB;6%ci7 zWnMtSex;RMs$h%L6O}W9PLtu|%u-7jcEam0Y%bd$O2^=O$Kg^$_NC6*&`u=+(`Urn zO$>YAeS+r_>$w5T$2TcMbI;xbSmX0V<%rN}EF63yT1;YXz*P78=(oH!IwNeqF7>f- zc5!5ZAibdOODb;zgV^1W2{G)Sh(JFKo2M^Yh6FjO5o&W}f47x0L864p`$Px|z`a?& zd$JYTmNDiT2QuEEyzoLWj za?CCn)SJ@4B-hoeX{os##-?2E)3AN}KdKb|%dqbf>k+9BpT^`#WoljRH4Z8Xe9d|> zT~wIF+B@EVYHWMPTy{{s?cLZN$Bo)6wBuBS?yj()L6*b z_0FJt&V$e7WXkniU&!M`Og~d7(%A)S1#3?CaLgx6&O2%eawseRvNjti45+`vY0x36 z0`wu@$p!$8MwEFBW?HlJ9p#(~*Jp^G1qCTR6~H+k-Os3puzf#gj+8^a_0W!>gs@}`!{E^YO5!zYK-P)X~#9yoj`u#xcn(4`frZH zWj>yFjjG*Qh9fhssrdy*h?}>o={eo=_Bz@2a-Xc2=iDtzC;F`&Q}QCMKaFv7*jT9@ zDmrJSsJ^CoecEAPAiewglf$?|=Li4?i-_j+i{(|R@f6lB{{>DJ&D>gEQ2O-o>t(*x z2MHd>uY^4T?}+T5s55+*MJM(Eb42zD>KDh(#WB|Z{&1YN3YfNS0kZfxcC1;rwsOL| z7g|ae4z?Hh-sKRTErUD-uEROh5s+tOSkM{Oy*04dTbxx3t)sFGZawq0Ewht@)&byS zp717e$Tf+=5b zi^*W2t|9Q3Td-hMhd34D`UXC<#cY{fXQ#5!M7}eK_?0O@DzV#`}4*_a4`V( zg>AbS(L`VChixy0;3zPnk*JI(#7ku7IdQW|BBg``r6XazA@KDOtJhMnCIFm5X7*Fz zY8Mt&GJ?)4sed-wsK{ipWtcz9aF-ET21zVMq)ogWw1&hoh-Kk?J~rvUQ)~-%y|eks zc70(Vk>|-GS;10))ivA(1|gXPuQWQ7#G=qc<2HEWtk2K%M}$^O*B&F8q>;XUX#wwRMC zz79Fi5|YOgD$5uEUW_>@4cK`?Z5keh#T(fZw_x#GlFllBDwSY*7wl||mcEqa(?y>x z!9zrph+yMKyA?~P?BNVfB-mZ&Uq_kN8Y&9azuO}zuy%HY#=pN@z(FoW?`}8aiY%`s zv_QQ6ItK?WN7gQt@!ut!Urtrv!J7c_I#_xdLC&c@%$T;K9Wy7N)#&KEa)DPI(Jjyp zFK93l4{4G-zJipzTr&0Up0wo$X*2dKT?k6UCa<%crB(TCMsCLg!(eN3i46#DfE}o@Y(*Kk!jTX zxg^%P9pDM6FEJS z(V({uB08=i2w~?a`QTL&+hRG{%>KCNdnszFc(gc5t=~`N&aB1eljVf#b$IWHgzv(U ztDWqk?)o3f<9+|BKIM<}d`;-%K7YDacCvFl>20n*#-vC{b&N0;WFt=OSw_iM77JO9 ze=iRHc~ry98%F;1B>GjOc{W?T-dSz>MxA6))JC(p=qC1bDCL%ddMmvwOk+C;Dd2`m zDxLL=@#80hQ#an+U$j#*4-P{Rkp^$%cE?$zj)F<-VTBGH_c*)1mui@>%7_Nq_rX{& zt{Tkxc{Zd(2ldXX!ITVnf9WToC51y)_Yg$UkY^c?nUU<9s)T(MP z$3^eZM>s~U#9SbJ0|*}Ho*+37MZKwO_QbC&DC~OsoTvZAxSrIf2=s5r$kM0lg6_f)5^tN-bBu1~!!M zPn+$$Inj+NNs^^3-(86K(!4S>Qj(>i{vk7^W2uhwPw9eCUyp-V{ZeSs&9>!~yOrFp z$Y6BZfLMa(;|msv-a0=KQa2FJ8s_byZ%FhQ!DZE6dw^9 zIZ1Q8N9LXz)sC6bhPfi^k?)x)_=!r8W2nZnTaWQ`@eSTJ5r-<<26L&RA2VcGu*9^1 zIQV7Jx=TQIn;;5ou<{~=?N3G+sV{AR_DY=4?h^nj)PhOZHoj3-1Y&Gq@^_u0h8kiE zc9uA6W+$Lt5zoSqNC7qwL8BI!d1@;W01p~8m~HMFl+C>T$-;FiIzKbIT*CY#24@tX zU~c^vE%4IPJ$z$$4_ABIo= zO%^L=9wKt!Gw0Zkqef8hc}$u^JDE%)H;W_$7c4dmFx#ceSvk_^)vj&Qf|ho|MU zR8*VYl?dZrb%the{>LmCiAZJH9=YrRlrT%pURENKA4c ziyfD-(CGmDeTNatGMS)H(R?eUxI%vzG(gbo@9B)_k`OFErpRP>THh||yCez1YroO4 zZZx)O*xCYXo)%VmxQ#Ly3rl-++s%0VyrNiGA&nvvaaQC&H-0MK_s=fyautX0k4Rr3 z#{BH>+`lmac0w!I<&L3e1GozretP5O(yBUPNgq1~?SFG*ME^tw!a~F$t9Is8^H%L$!ePpFIZuB#qc@K24sd<1SqK>SvIyT8*&RM$-F4*A1-XX*I0uMnYW>c#Tx zHfDJ%g}4VUBW!oEAlcPr&Um`mxUek(FEpM-P@=`7?kc2k2a%YEEx2VqTA}VQo3Myu zfJzrX!2c0#-G6PFa+@wC_|AXlIVm>Rnxf*^a*YLIE12Sbqs%$@yhSovt{MqC;G}Qi zDM?;nL(^^cYs~N6?n{b^ofiY@AxA{IiGXv|&__tNDtLe_UYzsR6yXqJ^dG|3C*B*$ z7)8sxtN&QU@__hvOH2_U00RTU&TbzKygTwR7OlG#En#hGQcdev5OCi<*HFh2_rzgCY@sFJN$ zG%3WscoL#F+av8-57Cofj%PK!$)~UNwVBHL$fHq*>G?3b#^D(NOkRc;8D*az^}M4N zv@Ofcd~;?c2*e(1)Xu;U?XPai@69Q&dBzfTNmdk!^FVtK?ybM{TL zCA$EE@F@KnhekVIyX4UobBcFB~oU z;6jrG2m5m)0cRgp`KDL!_$B9{?XO1>RbNG2(n7>uYPXw4fz|k+7P7fPDhe-Z0T5S+ zN&)uTuyiDX5k}IDM96%##A^WX>w%CTRzkh1LR(%b0|6yl@g*LB*I^ck&DU8hJ@Z3Q zcyY?#GtgqAjd)iPT|Feap(q-7?e=SIzxRxl93NS+_swatkN8t8Afg7aLtH5 z>kl{rxHLliTWa0K5}5fi*(~tkMlaw9PQ^gtAPJ~K!Ov6z&l($I1JhYMm}30fVOIDJ zf3QB05bpd&KD$N(rRjd+XQ-jRPo-qe3zRFut+mn}pRS)uyunpx z+Y0fi1>g<=Y8HfOS?RBnOt**$u(Q%wS-^wa1R^Jtumc8`138@Ol3@T4VfM`6WVa~* z;D!NahvIhrPb2zLxC#J~sqE^yxYv={zQfX2h}fz+EF>0UQoz%Bgq0-;B*Y}M0xXq> z&-6?jHyLCWiO(R`1YgQ^BVz53vGV?%4AF{1Nqr;uZVbC50BxSTJOTNd9P zodh4|;;4;(9}oVki$5kOu{)~>P^FyvbGbZ~B0^90GUFg%^LoJon_Y)jf|1IO^?vsws15s4R8AFV^Ln3$8%<4(f5~=RBhVgg^n-siT@?U5&BiR~g2RHP*tNJHlk~%>JWYwv2j* z%xFfuZ`<3q@}Tg?VY}hiQL#PCs0uR3OCZORC&E(#CvBWx_4V#o(2eHEf+{utI zvavviAWS9k`i4=(uo7amiQ}}1(>i5%vL{?+a7-bemBd8IN@y&{G1oF;cha)$2r<~! zdvnlG~H^_qf4vm4C2bcO4$}tNFkQH3gn2}vVJV3-W|7uLl^-(%y7u1cnd_jvkD$zgw*1YYb}P@d1Bd&*kH5Z zA$)gyY~ro-K_yxI%$EVvqlD1Aneww~-UY-*T?7n`p*f{Ij#%ZoA~rOf@)|G^{ujGy z1u>A7RUsx!^n&i@m0ku7YswLWDFpvW>og9IR+2u6ijEUb3GS?{CZ zYQm_iD5a{VDK?!QS%=y9sO6$_Y-eKXiu@9(3G)BQ76~XC0l%*;i=igos01ofJ{D8C z{w5IK*mklzcL=2x?Y$y^a$l`;4I*Npb-@tsLS3nV5za6ml*V9+VR{BgiVAp#Bc4mz zRn4ByGwc{QA|dS#U$8I94G4-HML(y;*2iGq5^Ax2h?Hqdpi3LXGx-ZE4FDQmxFcI# zVL~rxNGar=_4nwQ0K9+@oNtkJZr> z&v*(b0`_$XGpaxNF^bQPXD)4045~2BSxLnO9zudK@%mXcOHlT9eb7}arYG_Y&3j2s z9gs7JEI#F1+)R7oCF1TRBgT^;OHS0;R>enw2;maJY0lsyf^Pk+`)lVL_>wEc)xcUG z&lbpS02i|1>1+q&U1T-3IMr7uiG3E};K?c?3H9ly4yN5|olA-!L%LaSISN3_yCD^q zZi&@_qPMm!zRuhs7Lj>k-P?Md#t!Q5{15 z9we(4!#6mzjy+cbiHKf|u_dI#i^4u6y&PmiAF;K!Kterl{oIJxUFVAg5d5i(GX6KU z?L6ho5^gffo-@t9oUG6S`%dVfJ}|ibyPjc%AH2f^3Hd+=Lv1r}LEo)ivi~%g!dteC zqbYHw+q?3w=(NYJo(oZrqgWht=2?*hL2=KdCVuuL=tJ2o`8 z0_g6GD1aCZieBz_61M$6EY1(bThuc30GN@mWc>)+#lLxu7VVloSm;_gH6V=@5|qFDcBLAZx^J zS#SnxI7CHeD=!sXy9O5u`nfG4$>rh z`J|L&vM;qKt|#5BbGZ$57cB6(BIB$T4Wbe8n z<6qM4Seied>X+P0*I!fzv1d(LAzq-~!tY?# zOxl5MV2D3Z`=`9*KII)CtS$UXWPv<1Xx!5jGOLB$mL07T7tFuX!E@FA>4OlN{ia0id^SNy<+&f+ z7_e~Lp;`GyTFuzOC_n)U*{b@G`siNFFeESTPJ#Afh3wSvB38x~QSC)|6E-Y6( z#b6C*RbiN}$aRzRrT6@huAUht`S$`)(a(+uik%qz(M{GNQ{#wAJ|d7O5_FlA2+&PL z0~o|@aRL_i#IimqyMpahnBE`6UPHE9FZ#62;J7VtS0+L)&xR_}LLJt=T`BXrnsiR$ z;FIQL_I(wRTO?bd$wFWMKdRaR<1+M_uvx}HdrB;g$)B~!2X^mY>|mViJ^lK%xYZXP zW6pBl7-1esR}N#TGK>V|OcV*MOc|H(EysG3P!A!dNc?eHp(zWWJ1uteMk31Mrpwh% zGsxK>5hu2m{PRB@Wu-70&9+WN-;^$55@t6r-|Z`iG_jr(>${*=^tiP6{*@vY0d|fG z>%zPEr!kw1XA_L&{BQ0!xs{k6ig9#B=Kb$t#BA5kGM#sH zd(`ePv&!}nIq}<;e(bXY?A4zW0t9<{n1$aYA-8( z&q8iqO{vbcUI>2`V#s`D_}(K;4V431X5YqpSCn~V&4%^<@LjzowMA*Q^!>OjaT)tM zk=KShX8Gk8_qqA(_iBhR&?C8xt{e+rzF@MI!LNP}E-xk2~aF#Yi;bqSxjI z+lm*U9?8PP5Ft!pKF=a(_agcdSax#BjNhqX4=8r`c5fcb`T`zqF0S9_&VOKeR?srZ zT_4=8Q=JfGD`e00L%$}~^YYXE*t_x%Ark5K%pM7#D;m2h>c)PP$sl&?iEfUC^F3ZM z=hOlxJylG^sne|XbhVZAEXz-;T&&@U6w+{Y5eg9k;UWeWbtMF-0Zn*T?_SXhvVOIV zIsoii8T_za$X7fd_a!l2L>o2LSQ;m6qlNe4KfTpOo<|sa?7gr>6D&=$%m{fsV7{Kj zOM_bbRl9cv)$UMI40dHXk*rGnz8^evw^zArhuL0C=qvU95)zRY^xW$J+unE56W7f^ zu)24Rm9U9JryO1UW(Lv?*2Dg?=Y9&NJ$8>gT6bj*;AXK_j|>o#&gTyzu$_DH04eDE zSojIQb4e7~Rdj21W%Rvh(96$N<%3#Z4&(lPs1NBn0=qF+Ht|Mx@DufnYkN&(7T$ln z`I28{pIpgqLyvYlBLNtB!;pf3IO+vc5+q_8ZxD2RN$)2BSZPTKIuPU%nZ3zw7bGLJ zctqJATs~X4{sMwMDMbQdk0AWa;yzn~OS(&mLDOjA&M|1RXWroW3A~281TqVGGLp@_=EiA#$6wUE0%0~BJIjex< z8pvsDP&YlRw0fk{1KN45c`tGF`Yc)`4@-%XH%k7%e-`Ako;Ad`;H-OBgr6J()cCwQ zZATh?{pPUTmfx6RRXE{w{~_H8jOb7@5=3n_mq!8wUecBrNm*Fck2^qW2~tX&r^kA0 zGJ_errvKOUiZ>%YLP1N_AMlWiUo_g?&45?D>=C=dLV9?45?ojZC}nI zttI=~H$fF5yOB%=4z{?keVB)KJY}VbSKX$5?0smEJWXt$$ChE zMUT}%DLcU16mLNp(k*5_Oj-=)nWlQRr2dAn6sg8oc$erFZln&RkApb5BGWAq*`4ne z6#lPt>i#s&U`-|!1yQ6WU2_=JN-9Mb&q~Sd&$^<6yoJY5*?uca=j|+zOuhT1=i5e8 znr@Ns2P96{-`Tw1ZmvH6qcSv8VmEdYPO_%e_CoB5K(9IPXnIHbKJ|0q{n%U1h^{1y z!VN~uI65{nh(u~MF6S=68n2JBn$8{wvYGV=EgKl$*Rutmog%K1{`dDP)Jv0T8zn^r z<_1CAfaMTRM~P(%NEJ}jR6&yoL1nrrISaI$t`zB{-DZ;KV5R$!Z}zz9_GtcI&X81E zapb|Q=pi}gZ%>H}3{&E-yFvR-^+9Jxl#UT5GLz?SVo7s=fX#B2H(yshz7j84n~`z; zv-k_&ag$9peWo;5IpHmfA-!2-OLT#^$Y*LUixCKDXQT;wgk$wLG{OfTCO=nXybP(p zR(nLYJ>R{&BEa4Xyw<kcrup-MJmQ$A zNlnK^tooJG?E}h1eqF4w&Jz7c`-pAp6Nj1_Pr(l}D`0mjlRa>y_b@z7*2!tqL6_V- zb{GzZa%A}JEyuzi%Ih(T;kXjg1onrk12#(Rw7BUFoScWUrnVS@pIM+Q(8vgSn~X06 z4=^QV<|&N=z*;^MqDLf$>o%UOF_GhJJ}9*M+BUm)o1e$UX5KgRM?llPexWcXkR)ZB zeagqL=GJ9@a99r_f?Q({4;Xri(7hYn4CAklC7i9HncyQw*x))7Bm)j|+0>6O6lyB! z_za|nSYUfkCZLX~5M%PPLZrnjpEo$d)2HRFe}mGv_Kfxnht~u`Bcu7P?LuA19l+G|qZFjVJeI7Wm|W?v0uj}oec z`=ZeNJ}spk;-+HZ&)}>TOW_7c24VW2dv%;vf8hwEEGg` z#NJo94+XEaYC0DI6Guc?3=9R}!VFBsZiz`T`@dkS4w+sN?u4KP8gY+e`36-*k|3H} zMoDT4Xvx>_Eb-rj2%AsDnAu?&&#BERA7#D@R$30EKRlRUt1U6xA|@zzI^w)L5)`pO ze#v-kL{el{{w+`T=oA3S=!pZl2X2PfZ{!ag{{(hJ7jP`DhT|;f!EvP*MS(*r799Et zef-!S{{A9EH~U(Rf`3NNbbUx@BU(Ne$PYEq9!49`dUXnWJ8*c(wldjT^c4%LlfR8_ zmna`19<|!1m!2mP4k)8H57**GA&tX6VkXN040<%YC=b6|7Xq|x##GCszt_te4-^SI z!&3X4CyjXaaPKX9by4R8_e#$7UxM|{_KKmeMxwd0<~Sc%a%rZ5Mn_OYV=(lxH)~&3 zhY>&H4Iy}6wtw&R9FD8ajC;IX1RCGe)gzRRgY38=u^vx#(CbXS|DiZ5jd@=lj-o6~ zmW@qxSJAq)t~dPOEi40T&vei9L2anXa#XJ#txvneD63gOT+^KCY=*y)fzMimZ=BaP z059znuTf?UX=h@MMDK~=e>daQF^@EfVn?Px-D$ka?aF#hLAmf1xr~pfu+j5vWx|nY z!)ZKV;XQ=j)w_bj%XZ7DG zA6D&jD~rv)R6WJYCezpGh*`0mN70|hq8)GHkDqv8p^E_PHTLOQTsE?M=Q5CVwG>@Y z;si=0$Ug%Wr~LOoMT9Ebiyl6^wMI}1!;y-8ik!Dh{Cl1GMlKYvUB6rXe3ef=h2f^@ zEnT|ottvMs`^SzRzkT;+Kq%?}c**5jrkN2Fw{@A3s1f43(719Y*n)G&)f0C^&g3dd zQZGG;N1mHM5r5Tg+T+%L*m=DCy6=_QS?E54A=LNTIvZas`bx5`_%{nkY;VU%pKc@C zJBs+uIZ1uB4<)-KGY`_=@-}}cX;zy2yb;f2wLC^nj_w7C7bb97^&Oj{4YBB*a!v>T zJX4OLF#b%I8sLq!-hZAjO&@biZb}Kw_o~W*?Lz`Dw(l#YPZt46o9Qfg|{ zJ6xNia5`1a+8Ugn@*wD1G{*$~4D?mhv@jH!lMFV&SUKL#POzk~UB4=IeFCja|2Y;~ z!)Nxcx+KyB+W|l!*3(hmhRJv_Eh|XZI7{_aep26~t0ve40Z;vaYfWh7RO}tQZ^gF; z0?M)Wk*B$rWlj{x7dZcZzs0Z~YMoV9<8mlj` zHx!a}UGM!mTy5bDs{2Z4b|+lbOq_PBRth$f@2D$fkP9Ejax)qukbv$P%Cd$uVK!c; z4Sj`z)(b=DR=D(q z>mQq(fI%5_+d!HH-_CTqju5=d;-g`ACS7u$7RF-4F84g+Fhn-q=a1~|KeDNBdedp& zbZgJ@=(xq&mCl;z(t1w>gr{{()J;f`PpgUZjYLRg{GzuiL zS4Sh!`C*@80sfGC4Lr-B*M?V327IQmol^l7XAGv8;BP?{TB@+Bt5qcwJSsiUs|$qk zSxb3=)-8c+@6$#qf*!T>E$XwWSUX-xmeO+uovQ-OLqjHLnOq8>tiuL%RG(fD2>;JZ zZ(MPBurWkSL5~U>H<&n|j;CfeXz%reKfp?N{H#v?hN34k+$m=~SAo7VK5s|4%p8VO zM>aV(;WbTXAk<#HSaj&up@BrGI(fWN4gEH=f!N)riGuCYn#8V-ekuB~vdW;V@Jr7b zuiA!234QyUepSn@T7Cqik=tL{g;z(|sdwRloo39D3@A*~@4?#&rNG|a%HLsqhqnW` z6+p%Aqbaw}oZVDVINHYEQ+J8sWX+`0$@pJ{vOXEF5r#|GOiini{L8b!Z-IVWZ?B6y z>yHMr8lmf>H=a~sm3}@e=>qAw;gcD%q8|n=)T3i<3DBzZ-`nx1Gs&gX=&vD&L$&Wn z&A*l^JtNTf#tp4kfTx#%Rg6Md2nxEi9&b9?c)Unq^mk)}1{Jfa!1MaHI^Z_rO0Qld z{{Gg0zX1sR#9y5zbR!w7Ugh&RiBr%S&;PVfg;;KB0n%4NgR}^5EYSyF?X{{x6>vB$ z1+qR01ggfaO{t*#qH!f%Au zCDC-TediHF@@|a5pXFHsxAoeV;Nz4RN?hzg=Ut9`OtxKk5b-j}@iH`=-_F3KE>1Y8 z_d=|RIEMEk%9!^Q&sCDg=8xkw?O9^x<+F&FJ;h5Z3?Csvl=Gc#{_E51W3h5m&(g_0 zoBh2(YTYo!@rL1~O-wcJ8ynJpv>G;un*Q9q5D2{J-*aK}o>9)d!7V1^AFaHexQS%I zImT9541-84q@_PWJhoQ`VZyCa6Bvf$MSS7QI42n!FY9k2&;iJVH+>dL6;5V&Vqqdc z8PpHNS)qUiUv|;5ZHCuy;(tNn&|R7Sy%on@)Q<@mrd2jJUc?B7_U_l;3^O?KF>+}A zjJn7JWsrg2Lncg1>KLEd+VT8EZmC5LL z-O+qSxfix8Jqxr!?LTqE@$&5%tY|z50A5Tpng0vAd99Lw!ik$Q$pner^ThG)X#~L| z+(8-N6JK1^>yiCFY))_8zu*>e>)H@34Ci%?L6EQ2_7vn?tifMG(LA_!I|k=@Ykl7%|Pp!;Ys!Nkk za^`jPz%&YhOE zzFUc%_;EV18~gs`^gZYSm8JXreXR66-T;Z__OB43c+55)QlEF7eXWjO`a6C7?~M0@ zkAZ&+-Y|F~;u}LA%%=UF&3Q0a{CBRh`+Zz8wx>@Ai$=lyHme>C=g-WW2R;4rVDZP_ z#bN`(nRg$FZ{GR4#Px7l@ZYk8;eYpnB5Mj-T+x4|4Rb#|SUphtcKzQs?|*;$msL=B zY5&MI{6iW&?H?`Y;p`nB_ec?$uK2rMJ%J5}ub=L9zc*OSfB5Umzh6)OUW_&Tz58(U zHbBNo&PT%*Y|73~F%yl!2T|L0Z z8N$(ja^jAP=|`1u#|`x3v^QJdbuRiCO;4|%ez@?FO#izQ_wNV&-)ahMA(Iyc}>m085|Ei zuOQ~W|IxnT!4pHcqmv$F!xGx;rt<42o`fI(VcR*20^S+|H(CM?V z&hjSd?_}`Sz+^Lnd1sly=EuHYpF;RNy2?r_H(#Cx?WR-6obWAukXW&jHh3oIiV0A7 zJVXz0virPuN8@}(Z?iaKMqBb$CAIs&L_p5;?LYNj(z{nv1JD~PQ!1*R;(Zy-Ornyu zgZydq4*^3JckJpGfHCdq9bWkBj$wJVsVP~wg!iQ5| z<|&-nQUS7>rLFZ^;m1Y9CpRwZz2C*^mpQ}7{3Un{QrR!-qQ88ozwmceyll>BWn_!oOcjeOSo<6o2#C z%c}`o^uheM_jr|vL;KWsn47jZsrU0K-wkHGRP%EWbTN8msQI|=7imjdwu@w!!U>*h z|HYQR+gvd7wc#;-obNQd;_W_|F&T67MZvPm3{#k*@j`gPf8~!ZMy~~l{cF4t6yARH zUv2O==1*1k2X&u5tFP%)uD{ME5Zo#;!ROm}LHbTe^T|7wD_!TWa=*<^X*&5yh)OEP z)W+qh>7>vdPrmoEzAO%`d<5rP#E*#R{pc{w%nE*vvvJvJ5Ps?MBX0J==K7F#`{_;{ zhJlM#{kOid;?GA7;obI4X<+uP$_L%E&hO1Wg>SuobmQUl$NTTEZ?>T?y83q> zJ?y?a!AocF{Jrty)5rN`e$o8Xl_boFf81>AR@;nd71K7a?Fz@*4>oj!+KC1>KpWGB*Up{gjp6BAa9;B~SzQJb+z z%YN++dO6c7`NuZCQ*w3rr}Oh?bE$bbSrRRVF5_Q_$pvY9VzjmIZ(IdFn0BrdAc`T~ zK3`QsT)5VF)eo%rr?B#ni7sh6Hpvr%EM8<|bqHth0|)<(lF$9>$&@vy!` zV%*PkY$pek-R90Sb@r-Ou;R?a{G{-^R7IVwXiAr#z<&YnJ-jqBMkL><;cIRE|EgcB zR9I6znKMoL+)|A@y(y}bBk zfIEo3(7XD{!fMpsgO1iX(&hf>a9PXuppyPTuRA)F^7`F| z%h4aC^X1=-%mh40tX6RRChu%(m=(aJNxQ1}WhRNaCZRc4%F}(!S-!o!P0rWT-#B$J z&g>vb+wd2fs{I(_B>7d5E#rWhbUq&QK=qm+_bC%;WTW2!EQryjXwQ zHt4y&{e~$zbPT+gm%3oZbcWr33+~&JU*HV=^!n&hu(5-s!QGIs*FF8p0fA#(1@hZ1 zykF?wV)F{^=Ki(3Zc|izxO;4Tr{+hAlW)Mgj*-PqL+32H(=9?_j(VT?P=%V$B z8=IbL$E|yE18eIRH$?6yyxhMN5_ML~C9disrBxCA-{{gw(Wf_)ZXt39KQzw$>Y%9n zsSj2xqDs-5lb2(wQZ%D|M>5-U=K5;Pe?$(bi2ixnsaZKhxxRqNXGzBx>~8qOZ{q&( zk%ISI%w7sD?)l8UJU7@JdPU1!%t5{N7i-I4G;O4#-gcrYL*04g_;n-O#)y2=8h+Wr zRF-QUm%NC1cx8+>n50X+;h|xE2fC!0raJ|2ytg%5a$E8m+eA`kSUUZ&*JV)nd)?}t zX!=Q`PV<}3l%uW}VgBz{e@jgZ63p-QmTq1V>}3)XwXiZ_OQyHc?^TTen zL-9JqqiHzK#%Z`ExUg*UtWd296BVtgOb|Z$*R{}O?Esm!wmLFDkz9VgxREXUvb91? zhQ1f1-u3dv73HxnvI<@J`4A;}t;*L{-;wf~meh}WgI`&XS|4R7>!PF9xHb=Hqg);u z-*W?xl(Z%u8Ga#bE)GiROUX=0@45Hpblvwq-e*17BWBJU6|eni{xYI(pWopP{ZDKR zF^6W%lyOW|_NY#_GjzIf$AcbH^GI;>&!-C~A-s`%%jo+lgPXRy5A?^IGXst--@W); zJ{vLJ?S8tQPd{D15qI*#{N&&h{om1ladi4ywFqS~tB@A}D&TBPl*<+NWgz*~Z_f`mR}MWwqEm$|TdGEKWF6|=Mp~-J@>RS?ODtP!-WBtO)8@9=Zdf%>5NFWIog1eVug<{2_xU@(pP#l75Ar!Ylkl+xYP$*KMXrVYo3N2E! zNN{)8qJ=6ae|gUHoAb_@dB5e$p6r>uE?f6?uf_DJkyjr%K?D!RBjz$6WK-=0LiD^=SJKqc!x;d~O6##t9V6dlSw4^ne!95)(z|@PI`;YV?d@V$*`%V7JI+e;HW$+c zel)GIg51I9U5~zk!>#~)qd6x*0#3MCnCo_tZVvs$b!<`5#XTExqX5qKL z{R(kjT1aA9V2~o^=L1JUGO7&pB-!kV)-!EpTz2yUb^>3aIoT(4iCHthYeVD0m0z(cusOTRBSvjdOpC*s}Ew)pZ;L-1;f3M|+N zaezcEFEqJ};qZ03@>X~46y%KWGW4XHw z+s><8jiU3AN(_H^r==xE^5kao7xxKvVxY+sBUiJ+5 z=q0}~rm* z_L`}jJs>*1TceZO8x=wdqhCKmuT5$@Y~r%C()$uKX=@2?^AM9?vmdyPCGyFLJZ;=8 zj5+QG_6u1ngj^ql3UC?q$0_U`F-X4nmRAP#+Ln007h)yr_O+_+Hr>C*6dXa5xgI(D zj9%EaxXX8b&HNX9*l)XO(PyK+$mc57px0L1B3)0)OjB41+%pACVW*lherf!&v(rM$?|5%tL0Nd8jLBup-HBk|n6hJ5_+iL1mYOuL@dlzTV~Pboc@mgS zwLAwLlN=N8Nqq1vWZpK53OXH==udWG4^ErnO1Z<5i&2-of>ZSpFi2rG;{B7=7vT1C z;#^`9l#NRFuYSKB0Q0mfF$z*a8oPKRBKTYkx`-rFq!9LBPEk55I4f5MzFb6qIW#1^ z@WI7g+#R@19Lz+9-}Nno17pvnC%+Kx;4FI)Vi3n3ugRsC`Yw5f+Jp~h5nA?rPD~GX zj>Q#MCsdoATkw6UVN~|o=NFT{kaHcGlx4{zRCYhWAg+!e4xu5jUj;-;ytV))vr=sQ z;It&r_ltly!IU)_`C!b8M0~j%5Ds@AZ3eRW?foewmISPYRl${m|F2XCtiRG4(-=YPhPE3a@3Q<`R z=*~!b649lbZz|kgtIF}r3{Na-pbQ3_TP?`Q@{kMLp2U;5LH&q>pI=)t5pB|b%oGk+C z<(j_ww$c&wBTL65r}6z_A<{QC>HGT}Nx$n%HSY4OH>;l!;0Yv$RD5$t{Ew56BMH&2 z!Az0+taDin#$yDQQKRm);*+2CfOLkT*-h#nYB=ahGh_k#)DSNe`X&8+(+X0pX~GRkJJ^$XTfVR0JkA#1du(tGq*n3;)$!=U!+E7 z&~fZyOGA=1xXR6a!BL6#+!lmOdV{%I2Bq?L_skhX7#d2)a-@AJxArf1Mk9D+Vj)Bg z&N>AImIOZu;?Q49b)A%1ZaB<8c|PW*9C5wioprx%&udvoKYGeyIay7UF#X=N#d*4( z+g!rgqQhs=G4z-J$!J^TH`g zn$+FvY`X#v7Kk`C#GKIAFE+ordXAdovw3!Xu*{?@xB8jChTzvHfg*;MB!*^btxrGR zL+SYH-BzK&f$&0^HaeOnA;b3ZZ`;8spGj7J8+_l-sHuU${uj=+|MzhAj1>AWoO4Ub z{tf3^K*N9GY|a0YU!>l>_2|EF<{@^{#liXMf8m@$sr?#Rp;x9A!U24MNo2Mw17o~oiabk*z9J+DTUp6uD1c7!w%|MvLx)GMBvfpYpbou{JPpDzAw;>X=# zlnW!HOGQju$Kk8h4Ty|7w)6Fr~XO!Rbo61S6~Z0573jI%c$kzdg!vdd7BF@cfk+j}RAFx(SY5>J12YHI)& z+~LS4Y=x`IT*tmu16e*>Qn{uMW|76I)qcIOP$%P_>8>$p)S)~Lt<&4ZXz1KX}70`tZGJ|-X6ON8}0uzL+XMh zwQEyJc(_GunF#)oX2bvgaEVp>|EAd*pxA$KDVobp@t-uSBJm$wUgQ^%|0~V9y#Eg_ zbN$75`tpb+FR6zvS@d(&$vAb&r<^7W^l(kM*%kjxkr|QhpV{d{c&&{wr=Z*S{kTR~ z|N5(+J}PE(45GzzHykQ4q>o2rI^v$V#Y=VsmCRS3MwQyss1kT2NW6onUYz4E7GTxr zynnXoWNA0o>(lABFaM(LRqKYn-kGM_4!@kPauM4*4-_kexLjj1QV}2dPHK7Psy;SX z^?aswnwSs%U~}?pQr#sNPpCRR0a|p>)%ek6S<0q`Nop|CxT1&1t=|~8VzfG@nSVv(Jr;Kcw7SJP!4~pk2XNr{NVy{d>iN)d~j`Y!5$Ss_FajB z+Vv_$ZF%lON2WmY#&Cv#=}bkI>rFF6{`7X%^9(-Q47=k2?i_1%lLat7{{JSJ z{Qn~rE7AQs6(iRlqCi}f)cAr+&A1`Tihyo6>Pre+`*My(eX&;B)z8=)-ZPcvz;FMm zmsI)r8TZKAqO=;ybaJJMPLB339I+89aihNj4fh_GJWi6BPNhDOEv0n9Vt-5>7*$XS z_#ioys}fK~g?|(4Gtdy_zSmljABGL7Q(Q9sYKy>CtHZvZ6R~EKB_y<~hWTMRiu67P z-qy2tJL;}<*f7E9Xu2eU^+D%BB?DMgQcLi1uFsw;%^}F;denuY&^MwQry{)dI*RZumub{CPr(+^2adFF0h^2g^t*}jOKYomRMy< zsT>IBfav*_ijE^CC2t0azPopd{P#|-6n~=cbhd_yC5q}|8 KvIhZg2Oj~uP2j|A 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

$dj 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 =&p?d$HtfM~o^BQ4` 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 X$+>PwAoT2&2!)e>>qai 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 literal 1577362 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�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

s?Kqo^|-kGs)C=gs0{v1 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

iXZ^SDqK)>l zm;otxk^}eZHsNzk*Xm+=sY-)nxP!D0`D3U)A1nh)=unc7jxgatZnZ;1@W-Hgfbs;A zfitLjf(ljl30;SwE6C=ZTwEgn=HIte$+e)6;AATTn`_46N{x3f>2s%=XFP^$(GQ1m zg^@1(O<+)E37?wQu@FGdD#nwMjYKIn&BB@_Wi@ju42U{NVA3?;N}FZYvyN_HK|x-jatklRZAh^DKzrQg&b{VG?R!Q2V0P7K25>(GOP7vL+lK& zNg=7hFxteAr1$(y4hMkcSUJD-v>#b&{Hg>z>t5~U;J~ZAwYASWwdlq%Yh-JdzV05| zbU33(zWG1ya3d|0PgEZqGm8al@VjGl_L+VPzQW-wkI1p8C^iUw$4Dw;q* z{R&!xp{5Cybh{ZH@{weWIRY*lRJOha9(wMyya+XBv5s zrZ1SGnR2pfGKbDWzu2q;RPmbgN3n;}k?0zl1#@@6iZdF{VwVE2WGg&@q)*@$h&0Dv zV3{MpZ+})9*gJ_);YKwi0tBSYn$RQ^vokFjKJ}K5F`>*?a0E?CqsN0ktdBT2A6-7O zA|wI;X=sCe{bk;exO6fyYed6c$#b09OcjcWNu9RN6!l*+Zs%tI`W)* z<*1rQVz04RCQoS<^@D<5jv#E3Bt_y6x6&FZH(+f5&6F8J?E9vsUQNLlYX()*p)oY& zA2;?nx5Y)Zzhm`Jy5p*PPIV*4a0Q%Vn=cUx7Qcou%LeN-XWr`wVILRT>vdd;CGPI{ za^Z^3;Z?2)wq4@!(7)**HU4YOaW7<*mDUhw)WDN4e$l3|z0;m3_6<>_<+50UuAc5>|dV1et2[ov=t?L($lIlJ+y9?-A$xmB3jDw>qMLsJ9 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≥w4HM8C&HWMms(4h#yT`F9N;Qh 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

+nn8UT8g4 zoJm3U60dOmYA!}x#b|%rj4&(^{`2Qnu5@;cXcKtO=!q#tXBci4@eI#Jo$>G@Vp054 zv5MiBewty1Kau{7b2DsJ5tA^iFldofvpv9lMuNW%8LyI{jgHdA&-4$q8kD9`6uP6+$c*b~&x7MjDC?(qUuVU(Zbh z=ihvO|4oB)zvATZq=V6^dq@vi5x&Q70HWI1;WKD{hPQLK|2wog+h{O2DyV z1#&;M&dq>N5>X##yR)TL-|gOYMuDS+}ui6Rmbi-a?V z_`->2I1Z#Y!K$N|glaC#cFG>sD%R27{7BI-8hN)C6%cnMA`iA$f>>iBzL621h>+Ch z!bu%DA2JaOSlBf^nZaX-X(IR)7ID-ap%|O(@KwV+BZ*nZ+X5uFXbL&>1}99k$va9DX7PLcJ!RS?T}#2XqFD2ntlP|;}43n z>G!7ukyjG*VJ+&zOM!TMh+VFe#(M>cAmlt5@^$mV;vgTZ5{@@2nhhQKZ_lwEAVIC| zwkhda#kM-sA{U5)XDz0OUHT6O;emCziSM6{yCS&ne?y4*dAvZi>Re%F_{e+skv_qn zXhe?dW+4EvDs+d31Cy|}uJ}0jtpqWL6-FKQcm+X_LbomFXOH~T

*^A)2#ggu8v> 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
k)^CxO^!51`cv0|Ww% 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

ei7`Pc&d}=8-Z)`BW=jI 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 diff --git a/docs/demo.sh b/docs/demo.sh index d28c21e9e..f60cbf288 100755 --- a/docs/demo.sh +++ b/docs/demo.sh @@ -2,5 +2,7 @@ set -e cd +mkdir -p ~/myproj rm -rf ~/myproj/.* ~/.mise/installs ~/.config/mise PATH="$HOME/.cargo/bin:$PATH" vhs <~/src/mise/docs/demo.tape +rm -rf ~/myproj diff --git a/docs/demo.tape b/docs/demo.tape index 40562c804..521b76f58 100644 --- a/docs/demo.tape +++ b/docs/demo.tape @@ -51,23 +51,36 @@ Output src/mise/docs/demo.gif Require echo -Set Shell "bash" +Set Shell "zsh" Set FontFamily "Berkeley Mono" Set FontSize 24 Set Width 1200 Set Height 600 Set Padding 10 +Set WindowBar Colorful +#Set Theme "Catppuccin Macchiato" -Type "http mise.jdx.dev/mise-latest-macos-arm64 > ~/bin/mise" Enter Sleep 2s +Sleep 50ms +Type 'echo "First, we will download/setup mise"' Enter Sleep 2s +Type "http https://mise.jdx.dev/mise-latest-macos-arm64 > ~/bin/mise" Enter Sleep 2s Type "chmod +x ~/bin/mise" Sleep 1s Enter Sleep 1s Type "mise -v" Sleep 1s Enter Sleep 1s -Type 'eval "$(mise activate bash)"' Sleep 1s Enter Sleep 2s -Type "mise use -g node@lts" Sleep 2s Enter Sleep 3s +Type 'eval "$(mise activate zsh)"' Sleep 1s Enter Sleep 2s +Type 'echo "Ok, mise is ready to go now"' Enter Sleep 2s + +Type 'echo "Now, we will install node@lts and make it the global default"' Enter Sleep 2s +Type "mise use --global node@lts" Sleep 2s Enter Sleep 3s Type "node -v" Sleep 1s Enter Sleep 3s Type "which node" Sleep 1s Enter Sleep 5s +Type 'echo "Note that we get back the path to the real node here, not a shim"' Enter Sleep 2s + +Type 'echo "Lets enter a project directory we will setup to use node@21"' Enter Sleep 2s Type "cd ~/myproj" Sleep 1s Enter Sleep 1s -Type "mise use node@19" Sleep 2s Enter Sleep 2s +Type "mise use node@21" Sleep 2s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s +Type 'echo "As expected, now `node -v` is v21.x"' Enter Sleep 2s + +Type 'echo "We will leave this directory and the node version will revert to the global LTS version"' Enter Sleep 2s Type "cd .." Sleep 1s Enter Sleep 2s Type "node -v" Sleep 1s Enter Sleep 3s From 9e252d0b97a2a6649beff42884dbc5cd4e799c19 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:46:50 -0600 Subject: [PATCH 1531/1891] plugin-install: fix ssh urls (#1349) This bans plugin names with ":" in them but that _probably_ wouldn't have worked anyways. --- src/cli/plugins/install.rs | 6 +++--- ...plugins__install__tests__plugin_install_invalid_url.snap | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 02ff3ab33..5fb8c466d 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -116,11 +116,11 @@ 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("://") { + Some(url) => match url.contains(':') { true => (name.to_string(), Some(url.clone())), false => (name.to_string(), None), }, - None => match name.contains("://") { + None => match name.contains(':') { true => (get_name_from_url(name)?, Some(name.to_string())), false => (name.to_string(), None), }, @@ -163,7 +163,7 @@ mod tests { #[test] fn test_plugin_install_invalid_url() { - let err = assert_cli_err!("plugin", "add", "tiny:"); + let err = assert_cli_err!("plugin", "add", "tiny*"); assert_display_snapshot!(err); } } diff --git a/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap b/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap index ed6fcbb6e..0854d0294 100644 --- a/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap +++ b/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap @@ -2,4 +2,4 @@ source: src/cli/plugins/install.rs expression: err --- -No repository found for plugin tiny: +No repository found for plugin tiny* From bed96697a47da44cb7cb6680534cdbefbbdadc45 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:50:34 -0600 Subject: [PATCH 1532/1891] chore: Release mise version 2024.1.4 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- src/default_shorthands.rs | 12 ++++-------- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74506de08..e04e70df3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.3" +version = "2024.1.4" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index a52cb46a7..3a2eefb9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.3" +version = "2024.1.4" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 5dd283a45..25c0812cd 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.3 +mise 2024.1.4 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 285e0bfa2..c72736d85 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.3"; + version = "2024.1.4"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 03436b6c0..9ce17aa1c 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.3 +Version: 2024.1.4 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index a02350f8a..45b99702c 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -304,7 +304,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("hey", "https://github.com/raimon49/asdf-hey.git"), ("hostctl", "https://github.com/svenluijten/asdf-hostctl.git"), ("httpie-go", "https://github.com/abatilo/asdf-httpie-go.git"), - ("hub", "https://github.com/mise-plugins/asdf-hub.git"), + ("hub", "https://github.com/rtx-plugins/asdf-hub.git"), ("hugo", "https://github.com/NeoHsu/asdf-hugo.git"), ("hurl", "https://github.com/raimon49/asdf-hurl.git"), ("hwatch", "https://github.com/chessmango/asdf-hwatch.git"), @@ -499,13 +499,13 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("php", "https://github.com/asdf-community/asdf-php.git"), ("pint", "https://github.com/sam-burrell/asdf-pint.git"), ("pipectl", "https://github.com/pipe-cd/asdf-pipectl.git"), - ("pipenv", "https://github.com/mise-plugins/rtx-pipenv.git"), + ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), ("pipx", "https://github.com/yozachar/asdf-pipx.git"), ("pivnet", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("please", "https://github.com/asdf-community/asdf-please.git"), ("pluto", "https://github.com/FairwindsOps/asdf-pluto.git"), ("pnpm", "https://github.com/jonathanmorley/asdf-pnpm.git"), - ("poetry", "https://github.com/mise-plugins/rtx-poetry.git"), + ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), ("polaris", "https://github.com/particledecay/asdf-polaris.git"), ("popeye", "https://github.com/nlamirault/asdf-popeye.git"), ("postgres", "https://github.com/smashedtoatoms/asdf-postgres.git"), @@ -658,7 +658,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("thrift", "https://github.com/alisaifee/asdf-thrift.git"), ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), ("timoni", "https://github.com/Smana/asdf-timoni.git"), - ("tiny", "https://github.com/mise-plugins/rtx-tiny.git"), + ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), ("titan", "https://github.com/gabitchov/asdf-titan.git"), ("tlsg-cli", "https://github.com/0ghny/asdf-tlsgcli.git"), ("tmux", "https://github.com/aphecetche/asdf-tmux.git"), @@ -738,8 +738,4 @@ pub static DEFAULT_SHORTHANDS: Lazy> = pub static TRUSTED_SHORTHANDS: Lazy> = Lazy::new(|| HashSet::from([ "dt", - "hub", - "pipenv", - "poetry", - "tiny", ])); From c23e467717105e34ac805638dfeb5fcac3f991a2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 21:22:05 -0600 Subject: [PATCH 1533/1891] migrate: skip ruby installs These can also be non-portable --- src/migrate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/migrate.rs b/src/migrate.rs index 0dac368a9..93cb0e160 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -64,7 +64,7 @@ fn migrate_rtx() -> Result<()> { if rtx_data.exists() { let installs = rtx_data.join("installs"); for plugin in file::dir_subdirs(&installs)? { - if plugin == "python" { + if plugin == "python" || plugin == "ruby" { continue; } migrated = migrated || move_dirs(&installs.join(plugin), &INSTALLS)?; From 581b6e8aa56476d8d184c2cae2bd7657c8690143 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 3 Jan 2024 22:12:10 -0600 Subject: [PATCH 1534/1891] fixed man page --- man/man1/mise.1 | 134 +++++++++++++++++++++------------------ src/cli/render_mangen.rs | 6 +- 2 files changed, 73 insertions(+), 67 deletions(-) diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 499b50296..70515b893 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,12 +1,12 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH rtx 1 "rtx 2023.11.9" +.TH mise 1 "mise 2024.1.4" .SH NAME -rtx \- Polyglot runtime manager (asdf rust clone) +mise \- The front\-end to your dev env .SH SYNOPSIS -\fBrtx\fR [\fB\-j\fR|\fB\-\-jobs\fR] [\fB\-\-log\-level\fR] [\fB\-r\fR|\fB\-\-raw\fR] [\fB\-y\fR|\fB\-\-yes\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> +\fBmise\fR [\fB\-C\fR|\fB\-\-cd\fR] [\fB\-q\fR|\fB\-\-quiet\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-y\fR|\fB\-\-yes\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] <\fIsubcommands\fR> .SH DESCRIPTION -rtx is a tool for managing runtime versions. https://github.com/jdx/rtx +mise is a tool for managing runtime versions. https://github.com/jdx/mise .PP It\*(Aqs a replacement for tools like nvm, nodenv, rbenv, rvm, chruby, pyenv, etc. that works for any language. It\*(Aqs also great for managing linters/tools like @@ -16,22 +16,17 @@ It is inspired by asdf and uses asdf\*(Aqs plugin ecosystem under the hood: https://asdf\-vm.com/ .SH OPTIONS .TP -\fB\-j\fR, \fB\-\-jobs\fR -Number of plugins and runtimes to install in parallel -[default: 4] +\fB\-C\fR, \fB\-\-cd\fR=\fIDIR\fR +Change directory before running command .TP -\fB\-\-log\-level\fR=\fILEVEL\fR [default: info] -Set the log output verbosity +\fB\-q\fR, \fB\-\-quiet\fR +Suppress non\-error messages .TP -\fB\-r\fR, \fB\-\-raw\fR -Directly pipe stdin/stdout/stderr to user. -Sets \-\-jobs=1 +\fB\-v\fR, \fB\-\-verbose\fR +Show extra output (use \-vv for even more) .TP \fB\-y\fR, \fB\-\-yes\fR -Answer yes to all prompts -.TP -\fB\-v\fR, \fB\-\-verbose\fR -Show installation output +Answer yes to all confirmation prompts .TP \fB\-h\fR, \fB\-\-help\fR Print help (see a summary with \*(Aq\-h\*(Aq) @@ -40,103 +35,118 @@ Print help (see a summary with \*(Aq\-h\*(Aq) Print version .SH SUBCOMMANDS .TP -rtx\-activate(1) -Initializes rtx in the current shell +mise\-activate(1) +Initializes mise in the current shell session .TP -rtx\-alias(1) +mise\-alias(1) Manage aliases .TP -rtx\-bin\-paths(1) +mise\-bin\-paths(1) List all the active runtime bin paths .TP -rtx\-cache(1) +mise\-cache(1) Manage the mise cache .TP -rtx\-completion(1) +mise\-completion(1) Generate shell completions .TP -rtx\-current(1) +mise\-config(1) +[experimental] Manage config files +.TP +mise\-current(1) Shows current active and installed runtime versions .TP -rtx\-deactivate(1) -Disable rtx for current shell session +mise\-deactivate(1) +Disable mise for current shell session .TP -rtx\-direnv(1) -Output direnv function to use rtx inside direnv +mise\-direnv(1) +Output direnv function to use mise inside direnv .TP -rtx\-doctor(1) +mise\-doctor(1) Check mise installation for possible problems. .TP -rtx\-env(1) -Exports env vars to activate rtx a single time +mise\-env(1) +Exports env vars to activate mise a single time .TP -rtx\-env\-vars(1) +mise\-env\-vars(1) Manage environment variables .TP -rtx\-exec(1) +mise\-exec(1) Execute a command with tool(s) set .TP -rtx\-implode(1) -Removes rtx CLI and all related data +mise\-implode(1) +Removes mise CLI and all related data .TP -rtx\-install(1) +mise\-install(1) Install a tool version .TP -rtx\-latest(1) +mise\-latest(1) Gets the latest available version for a plugin .TP -rtx\-link(1) -Symlinks a tool version into rtx +mise\-link(1) +Symlinks a tool version into mise .TP -rtx\-ls(1) +mise\-ls(1) List installed and/or currently selected tool versions .TP -rtx\-ls\-remote(1) +mise\-ls\-remote(1) List runtime versions available for install .TP -rtx\-outdated(1) +mise\-outdated(1) Shows outdated tool versions .TP -rtx\-plugins(1) +mise\-plugins(1) Manage plugins .TP -rtx\-prune(1) +mise\-prune(1) Delete unused versions of tools .TP -rtx\-reshim(1) +mise\-reshim(1) rebuilds the shim farm .TP -rtx\-settings(1) +mise\-run(1) +[experimental] Run a task +.TP +mise\-self\-update(1) +Updates mise itself +.TP +mise\-settings(1) Manage settings .TP -rtx\-shell(1) +mise\-shell(1) Sets a tool version for the current shell session .TP -rtx\-sync(1) -Add tool versions from external tools to rtx +mise\-sync(1) +Add tool versions from external tools to mise .TP -rtx\-trust(1) +mise\-task(1) +[experimental] Manage tasks +.TP +mise\-trust(1) Marks a config file as trusted .TP -rtx\-uninstall(1) +mise\-uninstall(1) Removes runtime versions .TP -rtx\-upgrade(1) +mise\-upgrade(1) Upgrades outdated tool versions .TP -rtx\-use(1) +mise\-use(1) Change the active version of a tool locally or globally. .TP -rtx\-version(1) -Show rtx version +mise\-version(1) +Show mise version +.TP +mise\-watch(1) +[experimental] Run a task watching for changes .TP -rtx\-where(1) +mise\-where(1) Display the installation path for a runtime .TP -rtx\-which(1) +mise\-which(1) Shows the path that a bin name points to .TP -rtx\-help(1) +mise\-help(1) Print this message or the help of the given subcommand(s) .SH EXTRA Examples: @@ -144,12 +154,12 @@ Examples: $ mise install node@20.0 Install a version matching a prefix $ mise install node Install the node version defined in .tool\-versions or .mise.toml - $ rtx use node@20 Use node\-20.x in current project - $ rtx use \-g node@20 Use node\-20.x as default - $ rtx use node@latest Use latest node in current directory - $ rtx use \-g node@system Use system node everywhere unless overridden + $ mise use node@20 Use node\-20.x in current project + $ mise use \-g node@20 Use node\-20.x as default + $ mise use node@latest Use latest node in current directory + $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2023.11.9 +v2024.1.4 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index f9e197595..e810d46af 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -30,11 +30,7 @@ impl RenderMangen { } fn project_root() -> PathBuf { - Path::new(&env!("CARGO_MANIFEST_DIR")) - .ancestors() - .nth(1) - .unwrap() - .to_path_buf() + Path::new(&env!("CARGO_MANIFEST_DIR")).to_path_buf() } #[cfg(test)] From 38381a69d46a7fa4afd8d3254b2290bc5a28019b Mon Sep 17 00:00:00 2001 From: Patrick Decat Date: Thu, 4 Jan 2024 17:09:26 +0100 Subject: [PATCH 1535/1891] fix: remove comma from conflicts (#1353) --- scripts/release-aur.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 3e21bfdb0..d5f360bf6 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -22,7 +22,7 @@ url='https://github.com/jdx/mise' license=('MIT') makedepends=('cargo') provides=('mise') -conflicts=('mise-bin' 'rtx', 'rtx-bin') +conflicts=('mise-bin' 'rtx' 'rtx-bin') replaces=('rtx') options=('!lto') source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdx/\$pkgname/archive/v\$pkgver.tar.gz") From c375cd814da4b15dfcdf849071443f01c3b0e6fa Mon Sep 17 00:00:00 2001 From: Silas Baronda Date: Thu, 4 Jan 2024 11:13:27 -0500 Subject: [PATCH 1536/1891] Update README.md to link to rtx page (#1352) * Update README.md * Update README.md * Update README.md --------- Co-authored-by: jdx <216188+jdx@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 25c0812cd..fd02afc7f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ GitHub Workflow Status Discord -

The front-end to your dev env. (formerly called "rtx")

+

The front-end to your dev env. (formerly called "rtx")

## What is it? From ee6a18c1416d51202e046b8703891184daee772e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 08:49:43 -0800 Subject: [PATCH 1537/1891] not-found: use "[" instead of "test" (#1355) This did not have any technical issues except in the edge-case where the user overrides "test" such as having alias test="..." See 'https://github.com/jdx/mise/discussions/1338#discussioncomment-8014200' --- src/shell/bash.rs | 2 +- src/shell/snapshots/mise__shell__bash__tests__hook_init.snap | 2 +- .../snapshots/mise__shell__bash__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap | 2 +- src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap | 2 +- src/shell/zsh.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 84f4df48e..21cf7f2cf 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -52,7 +52,7 @@ impl Shell for Bash { out.push_str(&formatdoc! {r#" if [ -z "${{_mise_cmd_not_found:-}}" ]; then _mise_cmd_not_found=1 - test -n "$(declare -f command_not_found_handle)" && eval "${{_/command_not_found_handle/_command_not_found_handle}}" + [ -n "$(declare -f command_not_found_handle)" ] && eval "${{_/command_not_found_handle/_command_not_found_handle}}" command_not_found_handle() {{ if {exe} hook-not-found -s bash "$1"; then diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap index e70500125..ca04c8aa1 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap @@ -37,7 +37,7 @@ if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" + [ -n "$(declare -f command_not_found_handle)" ] && eval "${_/command_not_found_handle/_command_not_found_handle}" command_not_found_handle() { if /some/dir/mise hook-not-found -s bash "$1"; then diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap index 3a11c21a3..690f26687 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap @@ -36,7 +36,7 @@ if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - test -n "$(declare -f command_not_found_handle)" && eval "${_/command_not_found_handle/_command_not_found_handle}" + [ -n "$(declare -f command_not_found_handle)" ] && eval "${_/command_not_found_handle/_command_not_found_handle}" command_not_found_handle() { if /nix/store/mise hook-not-found -s bash "$1"; then diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap index 7d5b0b29d..9c517ade3 100644 --- a/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap @@ -41,7 +41,7 @@ fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${_/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { if /some/dir/mise hook-not-found -s zsh "$1"; then diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap index e84472f6f..d695c6ccd 100644 --- a/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap @@ -40,7 +40,7 @@ fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - test -n "$(declare -f command_not_found_handler)" && eval "${_/command_not_found_handler/_command_not_found_handler}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${_/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { if /nix/store/mise hook-not-found -s zsh "$1"; then diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 8968540d6..60bc4b97a 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -60,7 +60,7 @@ impl Shell for Zsh { out.push_str(&formatdoc! {r#" if [ -z "${{_mise_cmd_not_found:-}}" ]; then _mise_cmd_not_found=1 - test -n "$(declare -f command_not_found_handler)" && eval "${{_/command_not_found_handler/_command_not_found_handler}}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${{_/command_not_found_handler/_command_not_found_handler}}" function command_not_found_handler() {{ if {exe} hook-not-found -s zsh "$1"; then From 01a20ad0dd8bb073ac200b5b4459994c77512020 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 09:56:51 -0800 Subject: [PATCH 1538/1891] logging: prevent loading multiple times (#1358) Fixes #1351 --- src/logger.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/logger.rs b/src/logger.rs index 096c283b7..af6e4751f 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -9,6 +9,11 @@ use eyre::Result; use simplelog::*; pub fn init(settings: &Settings) { + static INIT: std::sync::Once = std::sync::Once::new(); + INIT.call_once(|| _init(settings)); +} + +pub fn _init(settings: &Settings) { if cfg!(test) { return; } From fb8a9dfbb052ecb770e0ef7ffd4f811f7de522b7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:02:31 -0800 Subject: [PATCH 1539/1891] env: use `mise.file`/`mise.path` config (#1361) * env: use `mise.file`/`mise.path` config This renames the env_file and env_path config vars. Fixes #1300 * [MegaLinter] Apply linters fixes --------- Co-authored-by: jdx --- .mise.toml | 3 +- e2e/config/.e2e.mise.toml | 4 +- e2e/test_local | 16 +- schema/mise.json | 78 ++++++---- src/cli/config/generate.rs | 11 +- ...li__config__generate__tests__generate.snap | 11 +- src/cli/settings/ls.rs | 22 ++- src/cli/settings/set.rs | 22 ++- ...cli__settings__ls__tests__settings_ls.snap | 24 --- ...i__settings__set__tests__settings_set.snap | 24 --- src/cli/settings/unset.rs | 1 - src/config/config_file/mise_toml.rs | 141 +++++++++++------- src/config/settings.rs | 2 +- 13 files changed, 202 insertions(+), 157 deletions(-) delete mode 100644 src/cli/settings/snapshots/mise__cli__settings__ls__tests__settings_ls.snap delete mode 100644 src/cli/settings/snapshots/mise__cli__settings__set__tests__settings_set.snap diff --git a/.mise.toml b/.mise.toml index 4c5939e86..f926552a7 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,8 +1,9 @@ #:schema ./schema/mise.json -env_file = '.env' [env] +mise.file = [".env"] FOO = "bar" +FOO_NUM = 1 THIS_PROJECT = "{{config_root}}-{{cwd}}" [tools] diff --git a/e2e/config/.e2e.mise.toml b/e2e/config/.e2e.mise.toml index ae4903b36..e91a7b270 100644 --- a/e2e/config/.e2e.mise.toml +++ b/e2e/config/.e2e.mise.toml @@ -1,8 +1,8 @@ #:schema ../../schema/mise.json -env_file = '.test-env' -env_path = ["/root", "./cwd"] [env] FOO = "bar" +mise.file = ['.test-env'] +mise.path = ["/root", "./cwd"] [tools] tiny = "latest" diff --git a/e2e/test_local b/e2e/test_local index 1b0c14621..1143a4dc6 100755 --- a/e2e/test_local +++ b/e2e/test_local @@ -19,10 +19,10 @@ assert_raises() { mise i shfmt@3.6.0 shfmt@3.5.0 assert "mise local" "#:schema ../../schema/mise.json -env_file = '.test-env' -env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" +mise.file = ['.test-env'] +mise.path = [\"/root\", \"./cwd\"] [tools] tiny = \"latest\" @@ -41,10 +41,10 @@ run = 'echo \"testing!\"' mise local shfmt@3.5.0 assert "mise local" "#:schema ../../schema/mise.json -env_file = '.test-env' -env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" +mise.file = ['.test-env'] +mise.path = [\"/root\", \"./cwd\"] [tools] tiny = \"latest\" @@ -69,10 +69,10 @@ fi mise local shfmt@3.6.0 assert "mise local" "#:schema ../../schema/mise.json -env_file = '.test-env' -env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" +mise.file = ['.test-env'] +mise.path = [\"/root\", \"./cwd\"] [tools] tiny = \"latest\" @@ -97,10 +97,10 @@ fi mise local --rm shfmt assert "mise local" "#:schema ../../schema/mise.json -env_file = '.test-env' -env_path = [\"/root\", \"./cwd\"] [env] FOO = \"bar\" +mise.file = ['.test-env'] +mise.path = [\"/root\", \"./cwd\"] [tools] tiny = \"latest\" diff --git a/schema/mise.json b/schema/mise.json index be3aa415b..2a08b1894 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -1,5 +1,5 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", + "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://mise.jdx.dev/schema/mise.json", "title": "mise", "description": "config file for mise version manager (.mise.toml)", @@ -13,30 +13,19 @@ }, "env_file": { "description": "path to .env file", - "type": "string" + "type": "string", + "deprecated": true }, "env_path": { "description": "PATH entries to add", "type": "array", + "deprecated": true, "items": { "description": "a path to add to PATH", "type": "string" } }, - "env": { - "description": "environment variables", - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "boolean" - } - ] - } - }, + "env": { "$ref": "#/$defs/env" }, "tools": { "description": "dev tools to use", "type": "object", @@ -44,13 +33,9 @@ "oneOf": [ { "type": "array", - "items": { - "$ref": "#/$defs/tool" - } + "items": { "$ref": "#/$defs/tool" } }, - { - "$ref": "#/$defs/tool" - } + { "$ref": "#/$defs/tool" } ] } }, @@ -79,11 +64,54 @@ } } }, - "settings": { - "$ref": "#/$defs/settings" - } + "settings": { "$ref": "#/$defs/settings" } }, "$defs": { + "env": { + "description": "environment variables", + "type": "object", + "properties": { + "mise": { + "type": "object", + "description": "environment modules", + "properties": { + "file": { + "oneOf": [ + { "type": "string", "description": "dotenv file to load" }, + { + "type": "array", + "description": "dotenv files to load", + "items": { + "type": "string", + "description": "dotenv file to load" + } + } + ] + }, + "path": { + "oneOf": [ + { "type": "string", "description": "PATH entry to add" }, + { + "type": "array", + "description": "PATH entries to add", + "items": { + "type": "string", + "description": "PATH entry to add" + } + } + ] + } + } + } + }, + "additionalProperties": { + "oneOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "boolean", "enum": [false] } + ] + } + }, "tool": { "oneOf": [ { diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index ba428b90c..ce7dc1255 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -33,21 +33,14 @@ impl ConfigGenerate { # # This setup allows you to define default versions and configuration across # # all projects but override them for specific projects. # -# # add extra directories to PATH -# env_path = [ -# "~/bin", # absolute path -# "./node_modules/.bin", # relative path to this file, not $PWD -# ] -# # # set arbitrary env vars to be used whenever in this project or subprojects # [env] # NODE_ENV = "development" # NPM_CONFIG_PREFIX = "~/.npm-global" # EDITOR = "code --wait" # -# [env_remove] -# load a dotenv file -# env_file = ".env" +# mise.file = ".env" # load vars from a dotenv file +# mise.path = "./node_modules/.bin" # add a directory to PATH # # [tools] # terraform = '1.0.0' # specify a single version diff --git a/src/cli/config/snapshots/mise__cli__config__generate__tests__generate.snap b/src/cli/config/snapshots/mise__cli__config__generate__tests__generate.snap index e76e173c3..0117acb2b 100644 --- a/src/cli/config/snapshots/mise__cli__config__generate__tests__generate.snap +++ b/src/cli/config/snapshots/mise__cli__config__generate__tests__generate.snap @@ -14,21 +14,14 @@ expression: output # # This setup allows you to define default versions and configuration across # # all projects but override them for specific projects. # -# # add extra directories to PATH -# env_path = [ -# "~/bin", # absolute path -# "./node_modules/.bin", # relative path to this file, not $PWD -# ] -# # # set arbitrary env vars to be used whenever in this project or subprojects # [env] # NODE_ENV = "development" # NPM_CONFIG_PREFIX = "~/.npm-global" # EDITOR = "code --wait" # -# [env_remove] -# load a dotenv file -# env_file = ".env" +# mise.file = ".env" # load vars from a dotenv file +# mise.path = "./node_modules/.bin" # add a directory to PATH # # [tools] # terraform = '1.0.0' # specify a single version diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index f590f0e12..e082e8e2b 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -45,6 +45,26 @@ mod tests { #[test] fn test_settings_ls() { reset_config(); - assert_cli_snapshot!("settings"); + assert_cli_snapshot!("settings", @r###" + always_keep_download = true + always_keep_install = true + asdf_compat = false + color = true + disable_default_shorthands = false + disable_tools = [] + experimental = true + jobs = 2 + legacy_version_file = true + legacy_version_file_disable_tools = [] + not_found_auto_install = true + plugin_autoupdate_last_check_duration = "20m" + quiet = false + raw = false + shorthands_file = null + task_output = null + trusted_config_paths = [] + verbose = true + yes = true + "###); } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index d38b1946b..4c502c2eb 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -76,7 +76,27 @@ pub mod tests { "1" ); - assert_cli_snapshot!("settings"); + assert_cli_snapshot!("settings", @r###" + always_keep_download = true + always_keep_install = true + asdf_compat = false + color = true + disable_default_shorthands = false + disable_tools = [] + experimental = true + jobs = 2 + legacy_version_file = false + legacy_version_file_disable_tools = [] + not_found_auto_install = true + plugin_autoupdate_last_check_duration = "1m" + quiet = false + raw = false + shorthands_file = null + task_output = null + trusted_config_paths = [] + verbose = true + yes = true + "###); reset_config(); } } diff --git a/src/cli/settings/snapshots/mise__cli__settings__ls__tests__settings_ls.snap b/src/cli/settings/snapshots/mise__cli__settings__ls__tests__settings_ls.snap deleted file mode 100644 index 0f5f06aa7..000000000 --- a/src/cli/settings/snapshots/mise__cli__settings__ls__tests__settings_ls.snap +++ /dev/null @@ -1,24 +0,0 @@ ---- -source: src/cli/settings/ls.rs -expression: output ---- -always_keep_download = true -always_keep_install = true -asdf_compat = false -color = true -disable_default_shorthands = false -disable_tools = [] -env_file = null -experimental = true -jobs = 2 -legacy_version_file = true -legacy_version_file_disable_tools = [] -not_found_auto_install = true -plugin_autoupdate_last_check_duration = "20m" -quiet = false -raw = false -shorthands_file = null -task_output = null -trusted_config_paths = [] -verbose = true -yes = true diff --git a/src/cli/settings/snapshots/mise__cli__settings__set__tests__settings_set.snap b/src/cli/settings/snapshots/mise__cli__settings__set__tests__settings_set.snap deleted file mode 100644 index 4a5b53cc0..000000000 --- a/src/cli/settings/snapshots/mise__cli__settings__set__tests__settings_set.snap +++ /dev/null @@ -1,24 +0,0 @@ ---- -source: src/cli/settings/set.rs -expression: output ---- -always_keep_download = true -always_keep_install = true -asdf_compat = false -color = true -disable_default_shorthands = false -disable_tools = [] -env_file = null -experimental = true -jobs = 2 -legacy_version_file = false -legacy_version_file_disable_tools = [] -not_found_auto_install = true -plugin_autoupdate_last_check_duration = "1m" -quiet = false -raw = false -shorthands_file = null -task_output = null -trusted_config_paths = [] -verbose = true -yes = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 0ed40aea1..942170d8b 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -46,7 +46,6 @@ mod tests { color = true disable_default_shorthands = false disable_tools = [] - env_file = null experimental = true jobs = 2 legacy_version_file = true diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index a8e6d7348..e0131002e 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::fmt::{Debug, Formatter}; +use std::iter::once; use std::path::{Path, PathBuf}; use std::sync::Mutex; @@ -29,7 +30,7 @@ pub struct MiseToml { context: Context, path: PathBuf, toolset: Toolset, - env_file: Option, + env_files: Vec, env: HashMap, env_remove: Vec, path_dirs: Vec, @@ -70,8 +71,8 @@ impl MiseToml { let doc: Document = s.parse().suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { - "dotenv" => self.parse_env_file(k, v)?, - "env_file" => self.parse_env_file(k, v)?, + "dotenv" => self.parse_env_file(k, v, true)?, + "env_file" => self.parse_env_file(k, v, true)?, "env_path" => self.path_dirs = self.parse_path_env(k, v)?, "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, @@ -86,47 +87,66 @@ impl MiseToml { Ok(()) } - fn parse_env_file(&mut self, k: &str, v: &Item) -> Result<()> { + fn parse_env_file(&mut self, k: &str, v: &Item, deprecate: bool) -> Result<()> { self.trust_check()?; - match v.as_str() { - Some(filename) => { - let path = self.path.parent().unwrap().join(filename); - let dotenv = dotenvy::from_path_iter(&path).wrap_err_with(|| { - eyre!("failed to parse dotenv file: {}", display_path(&path)) - })?; - for item in dotenv { - let (k, v) = item?; - self.env.insert(k, v); + if deprecate { + warn!("{k} is deprecated. Use 'env.mise.file' instead."); + } + if let Some(filename) = v.as_str() { + let path = self.path.parent().unwrap().join(filename); + self.parse_env_filename(path)?; + } else if let Some(filenames) = v.as_array() { + for filename in filenames { + if let Some(filename) = filename.as_str() { + let path = self.path.parent().unwrap().join(filename); + self.parse_env_filename(path)?; + } else { + parse_error!(k, v, "string"); } - self.env_file = Some(path); } - _ => parse_error!(k, v, "string"), + } else { + parse_error!(k, v, "string or array of strings"); + } + Ok(()) + } + + fn parse_env_filename(&mut self, path: PathBuf) -> Result<()> { + let dotenv = dotenvy::from_path_iter(&path) + .wrap_err_with(|| eyre!("failed to parse dotenv file: {}", display_path(&path)))?; + for item in dotenv { + let (k, v) = item?; + self.env.insert(k, v); } + self.env_files.push(path); Ok(()) } fn parse_env(&mut self, key: &str, v: &Item) -> Result<()> { self.trust_check()?; - let mut v = v.clone(); - if let Some(table) = v.as_table_like_mut() { - if table.contains_key("PATH") { - return Err(eyre!("use 'env_path' instead of 'env.PATH'")); - } + if let Some(table) = v.as_table_like() { + ensure!( + !table.contains_key("PATH"), + "use 'env.mise.path' instead of 'env.PATH'" + ); } match v.as_table_like() { Some(table) => { for (k, v) in table.iter() { let key = format!("{}.{}", key, k); let k = self.parse_template(&key, k)?; - if let Some(v) = v.as_str() { + if k == "mise" { + self.parse_env_mise(&key, v)?; + } else if let Some(v) = v.as_str() { let v = self.parse_template(&key, v)?; self.env.insert(k, v); + } else if let Some(v) = v.as_integer() { + self.env.insert(k, v.to_string()); } else if let Some(v) = v.as_bool() { if !v { self.env_remove.push(k); } } else { - parse_error!(key, v, "string or bool") + parse_error!(key, v, "string, num, or bool") } } } @@ -135,31 +155,50 @@ impl MiseToml { Ok(()) } - fn parse_path_env(&self, k: &str, v: &Item) -> Result> { - self.trust_check()?; - match v.as_array() { - Some(array) => { - let mut path = Vec::new(); - let config_root = self.path.parent().unwrap().to_path_buf(); - for v in array { - match v.as_str() { - Some(s) => { - let s = self.parse_template(k, s)?; - let s = match s.strip_prefix("./") { - Some(s) => config_root.join(s), - None => match s.strip_prefix("~/") { - Some(s) => dirs::HOME.join(s), - None => s.into(), - }, - }; - path.push(s); - } - _ => parse_error!(k, v, "string"), + fn parse_env_mise(&mut self, key: &str, v: &Item) -> Result<()> { + match v.as_table_like() { + Some(table) => { + for (k, v) in table.iter() { + let key = format!("{}.{}", key, k); + match k { + "file" => self.parse_env_file(&key, v, false)?, + "path" => self.path_dirs = self.parse_path_env(&key, v)?, + _ => parse_error!(key, v, "file or path"), } } - Ok(path) + Ok(()) + } + _ => parse_error!(key, v, "table"), + } + } + + fn parse_path_env(&self, k: &str, v: &Item) -> Result> { + self.trust_check()?; + let config_root = self.path.parent().unwrap().to_path_buf(); + let get_path = |v: &Item| -> Result { + if let Some(s) = v.as_str() { + let s = self.parse_template(k, s)?; + let s = match s.strip_prefix("./") { + Some(s) => config_root.join(s), + None => match s.strip_prefix("~/") { + Some(s) => dirs::HOME.join(s), + None => s.into(), + }, + }; + Ok(s) + } else { + parse_error!(k, v, "string") + } + }; + if let Some(array) = v.as_array() { + let mut path = Vec::new(); + for v in array { + let item = Item::Value(v.clone()); + path.push(get_path(&item)?); } - _ => parse_error!(k, v, "array"), + Ok(path) + } else { + Ok(vec![get_path(v)?]) } } @@ -787,10 +826,10 @@ impl ConfigFile for MiseToml { } fn watch_files(&self) -> Vec { - match &self.env_file { - Some(env_file) => vec![self.path.clone(), env_file.clone()], - None => vec![self.path.clone()], - } + once(&self.path) + .chain(self.env_files.iter()) + .cloned() + .collect() } } @@ -804,8 +843,8 @@ impl Debug for MiseToml { let json = serde_json::to_value(settings).unwrap_or_default(); d.field("settings", &json); } - if let Some(env_file) = &self.env_file { - d.field("env_file", env_file); + if !self.env_files.is_empty() { + d.field("env_files", &self.env_files); } if !self.env.is_empty() { d.field("env", &self.env); @@ -832,7 +871,7 @@ impl Clone for MiseToml { context: self.context.clone(), path: self.path.clone(), toolset: self.toolset.clone(), - env_file: self.env_file.clone(), + env_files: self.env_files.clone(), env: self.env.clone(), env_remove: self.env_remove.clone(), path_dirs: self.path_dirs.clone(), diff --git a/src/config/settings.rs b/src/config/settings.rs index 108b91b41..ac0255ab0 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -186,7 +186,7 @@ impl Settings { } pub fn hidden_configs() -> HashSet<&'static str> { static HIDDEN_CONFIGS: Lazy> = - Lazy::new(|| ["ci", "cd", "debug", "trace", "log_level"].into()); + Lazy::new(|| ["ci", "cd", "debug", "env_file", "trace", "log_level"].into()); HIDDEN_CONFIGS.clone() } From c26401f1d2d472b2e53e0f28a7ee06f53d1eeeb3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 15:10:30 -0600 Subject: [PATCH 1540/1891] chore: Release mise version 2024.1.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- src/default_shorthands.rs | 3 ++- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e04e70df3..00b8b3f11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.4" +version = "2024.1.5" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 3a2eefb9c..3116354a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.4" +version = "2024.1.5" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index fd02afc7f..e817afd7b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.4 +mise 2024.1.5 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index c72736d85..75ea3947c 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.4"; + version = "2024.1.5"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 70515b893..e47894e73 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.4" +.TH mise 1 "mise 2024.1.5" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.4 +v2024.1.5 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 9ce17aa1c..76d3a62a7 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.4 +Version: 2024.1.5 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 45b99702c..719664736 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -198,7 +198,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("ejson", "https://github.com/cipherstash/asdf-ejson.git"), ("eksctl", "https://github.com/elementalvoid/asdf-eksctl.git"), ("elasticsearch", "https://github.com/asdf-community/asdf-elasticsearch.git"), - ("elixir", "https://github.com/asdf-vm/asdf-elixir.git"), + ("elixir", "https://github.com/mise-plugins/mise-elixir.git"), ("elixir-ls", "https://github.com/juantascon/asdf-elixir-ls"), ("elm", "https://github.com/asdf-community/asdf-elm.git"), ("embulk", "https://github.com/yuokada/asdf-embulk.git"), @@ -738,4 +738,5 @@ pub static DEFAULT_SHORTHANDS: Lazy> = pub static TRUSTED_SHORTHANDS: Lazy> = Lazy::new(|| HashSet::from([ "dt", + "elixir", ])); From 9b596c6dadcf0f54b3637d10e1885281e1a1b534 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:22:41 -0600 Subject: [PATCH 1541/1891] test: fixed elixir test case --- src/shorthands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shorthands.rs b/src/shorthands.rs index bab235b89..a284aae64 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -66,7 +66,7 @@ mod tests { let shorthands = get_shorthands(); assert_str_eq!( shorthands["elixir"], - "https://github.com/asdf-vm/asdf-elixir.git" + "https://github.com/mise-plugins/mise-elixir.git" ); assert_str_eq!(shorthands["node"], "https://node"); assert_str_eq!(shorthands["xxxxxx"], "https://xxxxxx"); From 3d2e132f1df5aa20e9d712df697746ddeea6c465 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:33:14 -0800 Subject: [PATCH 1542/1891] tasks: set CLICOLOR_FORCE=1 and FORCE_COLOR=1 (#1364) if colors are enabled, make sure we keep them in sub-processes --- src/cli/run.rs | 4 ++++ src/cmd.rs | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index a257d189b..07c0d5491 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -147,6 +147,10 @@ impl Run { if let Some(root) = &config.project_root { env.insert("MISE_PROJECT_ROOT".into(), root.display().to_string()); } + if console::colors_enabled() { + env.insert("CLICOLOR_FORCE".into(), "1".into()); + env.insert("FORCE_COLOR".into(), "1".into()); + } let tasks = Mutex::new(Deps::new(config, tasks)?); diff --git a/src/cmd.rs b/src/cmd.rs index 2da1ae1f6..efbdfda8b 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -305,8 +305,10 @@ impl<'a> CmdLineRunner<'a> { if !line.trim().is_empty() { pr.set_message(line.into()) } + } else if console::colors_enabled() { + println!("{}{line}\x1b[0m", self.prefix); } else { - println!("{}{}", self.prefix, line); + println!("{}{line}", self.prefix); } } @@ -318,7 +320,13 @@ impl<'a> CmdLineRunner<'a> { pr.println(line.into()) } } - None => eprintln!("{}{}", self.prefix, line), + None => { + if console::colors_enabled() { + eprintln!("{}{line}\x1b[0m", self.prefix); + } else { + eprintln!("{}{line}", self.prefix); + } + } } } From fb2b218da96a09b1f9db3984aa217c1b11e1a3de Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:52:22 -0800 Subject: [PATCH 1543/1891] tasks: set --interleaved if graph is linear (#1365) --- src/cli/run.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 07c0d5491..6ad3c8d12 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -4,7 +4,6 @@ use std::iter::once; use std::os::unix::prelude::ExitStatusExt; use std::path::{Path, PathBuf}; use std::process::{exit, Stdio}; - use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{mpsc, Mutex}; use std::time::SystemTime; @@ -106,6 +105,9 @@ pub struct Run { /// Configure with `raw` config or `MISE_RAW` env var #[clap(long, short, verbatim_doc_comment)] pub raw: bool, + + #[clap(skip)] + pub is_linear: bool, } impl Run { @@ -138,7 +140,7 @@ impl Run { .collect() } - fn parallelize_tasks(self, config: &Config, tasks: Vec) -> Result<()> { + fn parallelize_tasks(mut self, config: &Config, tasks: Vec) -> Result<()> { let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; ts.install_arg_versions(config, &InstallOptions::new())?; @@ -153,6 +155,7 @@ impl Run { } let tasks = Mutex::new(Deps::new(config, tasks)?); + self.is_linear = tasks.lock().unwrap().is_linear(); for task in tasks.lock().unwrap().all() { self.validate_task(task)?; @@ -303,7 +306,7 @@ impl Run { Ok(TaskOutput::Interleave) } else if let Some(output) = &settings.task_output { Ok(output.parse()?) - } else if self.raw(task) || self.jobs() == 1 { + } else if self.raw(task) || self.jobs() == 1 || self.is_linear { Ok(TaskOutput::Interleave) } else { Ok(TaskOutput::Prefix) @@ -497,6 +500,15 @@ impl Deps { self.graph.node_indices().map(|idx| &self.graph[idx]) } + fn is_linear(&self) -> bool { + !self.graph.node_indices().any(|idx| { + self.graph + .neighbors_directed(idx, Direction::Outgoing) + .count() + > 1 + }) + } + // fn pop(&'a mut self) -> Option<&'a Task> { // if let Some(leaf) = self.leaves().first() { // self.remove(&leaf.clone()) From 6adb0880c2e3e3495c9689339de6e80615c2597f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:56:10 -0600 Subject: [PATCH 1544/1891] chore: Release mise version 2024.1.6 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00b8b3f11..09d1e0809 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.5" +version = "2024.1.6" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 3116354a7..0fafbf1c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.5" +version = "2024.1.6" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index e817afd7b..210df6c9b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.5 +mise 2024.1.6 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 75ea3947c..33f862273 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.5"; + version = "2024.1.6"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index e47894e73..aa0623641 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.5" +.TH mise 1 "mise 2024.1.6" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.5 +v2024.1.6 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 76d3a62a7..62f996bdf 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.5 +Version: 2024.1.6 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 49027919665af8a568c60356f8022d757a26e68e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 4 Jan 2024 15:11:42 -0800 Subject: [PATCH 1545/1891] show better error when attemping to install core plugin (#1366) --- src/cli/plugins/install.rs | 17 ++++++++++++++--- ...tall__tests__plugin_install_invalid_url.snap | 5 ----- 2 files changed, 14 insertions(+), 8 deletions(-) delete mode 100644 src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 5fb8c466d..d7d4d23c2 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -4,10 +4,11 @@ use rayon::ThreadPoolBuilder; use url::Url; use crate::config::{Config, Settings}; - +use crate::plugins::core::CORE_PLUGINS; use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin, PluginName}; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::style; /// Install a plugin /// @@ -57,6 +58,11 @@ impl PluginsInstall { if git_url.is_some() { self.install_one(name, git_url, &mpr)?; } else { + let is_core = CORE_PLUGINS.contains_key(name.as_str()); + if is_core { + let name = style::eblue(name); + bail!("{name} is a core plugin and does not need to be installed"); + } let mut plugins: Vec = vec![name]; if let Some(second) = self.git_url.clone() { plugins.push(second); @@ -160,10 +166,15 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - #[test] fn test_plugin_install_invalid_url() { let err = assert_cli_err!("plugin", "add", "tiny*"); - assert_display_snapshot!(err); + assert_display_snapshot!(err, @"No repository found for plugin tiny*"); + } + + #[test] + fn test_plugin_install_core_plugin() { + let err = assert_cli_err!("plugin", "add", "node"); + assert_display_snapshot!(err, @"node is a core plugin and does not need to be installed"); } } diff --git a/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap b/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap deleted file mode 100644 index 0854d0294..000000000 --- a/src/cli/plugins/snapshots/mise__cli__plugins__install__tests__plugin_install_invalid_url.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/cli/plugins/install.rs -expression: err ---- -No repository found for plugin tiny* From 54097eed2050681f6ed74084809a438a70000cab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 5 Jan 2024 10:05:59 -0600 Subject: [PATCH 1546/1891] fixed migration script --- src/migrate.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/migrate.rs b/src/migrate.rs index 93cb0e160..9c5345b9b 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -67,12 +67,12 @@ fn migrate_rtx() -> Result<()> { if plugin == "python" || plugin == "ruby" { continue; } - migrated = migrated || move_dirs(&installs.join(plugin), &INSTALLS)?; + migrated = move_dirs(&installs.join(&plugin), &INSTALLS.join(plugin))? || migrated; } - migrated = migrated || move_dirs(&rtx_data.join("plugins"), &DATA)?; + migrated = move_dirs(&rtx_data.join("plugins"), &DATA.join("plugins"))? || migrated; } - migrated = migrated || move_dirs(&XDG_CONFIG_HOME.join("rtx"), &CONFIG)?; - migrated = migrated || move_dirs(&XDG_STATE_HOME.join("rtx"), &STATE)?; + migrated = move_dirs(&XDG_CONFIG_HOME.join("rtx"), &CONFIG)? || migrated; + migrated = move_dirs(&XDG_STATE_HOME.join("rtx"), &STATE)? || migrated; if migrated { eprintln!("migrated rtx directories to mise"); eprintln!("see https://mise.jdx.dev/rtx.html") From 69f354df0e463edcdcbd12364a88013e5f5029f9 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 5 Jan 2024 10:37:14 -0600 Subject: [PATCH 1547/1891] fixed not-found handler Fixes #1375 --- src/shell/bash.rs | 2 +- src/shell/snapshots/mise__shell__bash__tests__hook_init.snap | 2 +- .../snapshots/mise__shell__bash__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap | 2 +- src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap | 2 +- src/shell/zsh.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 21cf7f2cf..607a6d547 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -52,7 +52,7 @@ impl Shell for Bash { out.push_str(&formatdoc! {r#" if [ -z "${{_mise_cmd_not_found:-}}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handle)" ] && eval "${{_/command_not_found_handle/_command_not_found_handle}}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${{$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}}" command_not_found_handle() {{ if {exe} hook-not-found -s bash "$1"; then diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap index ca04c8aa1..d75cff6dd 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap @@ -37,7 +37,7 @@ if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handle)" ] && eval "${_/command_not_found_handle/_command_not_found_handle}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" command_not_found_handle() { if /some/dir/mise hook-not-found -s bash "$1"; then diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap index 690f26687..2e5ad0c4c 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap @@ -36,7 +36,7 @@ if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handle)" ] && eval "${_/command_not_found_handle/_command_not_found_handle}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" command_not_found_handle() { if /nix/store/mise hook-not-found -s bash "$1"; then diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap index 9c517ade3..2bf4bf6c9 100644 --- a/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap @@ -41,7 +41,7 @@ fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handler)" ] && eval "${_/command_not_found_handler/_command_not_found_handler}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { if /some/dir/mise hook-not-found -s zsh "$1"; then diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap index d695c6ccd..7c4a46daa 100644 --- a/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap @@ -40,7 +40,7 @@ fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handler)" ] && eval "${_/command_not_found_handler/_command_not_found_handler}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { if /nix/store/mise hook-not-found -s zsh "$1"; then diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 60bc4b97a..ac7e793a4 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -60,7 +60,7 @@ impl Shell for Zsh { out.push_str(&formatdoc! {r#" if [ -z "${{_mise_cmd_not_found:-}}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handler)" ] && eval "${{_/command_not_found_handler/_command_not_found_handler}}" + [ -n "$(declare -f command_not_found_handler)" ] && eval "${{$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}}" function command_not_found_handler() {{ if {exe} hook-not-found -s zsh "$1"; then From db19252f3c5f23426f2d8c5a899939a575453779 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:04:45 -0600 Subject: [PATCH 1548/1891] read rtx.plugin.toml if it exists --- src/plugins/external_plugin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 8dffa98a4..34edc0c58 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -56,7 +56,10 @@ impl ExternalPlugin { pub fn new(name: PluginName) -> Self { let plugin_path = dirs::PLUGINS.join(&name); let cache_path = dirs::CACHE.join(&name); - let toml_path = plugin_path.join("mise.plugin.toml"); + let mut toml_path = plugin_path.join("mise.plugin.toml"); + if plugin_path.join("rtx.plugin.toml").exists() { + toml_path = plugin_path.join("rtx.plugin.toml"); + } let toml = MisePluginToml::from_file(&toml_path).unwrap(); Self { script_man: build_script_man(&name, &plugin_path), From 292e4acd0ca6ceebab0790fe51421b8ffb0a0d36 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:05:31 -0600 Subject: [PATCH 1549/1891] chore: Release mise version 2024.1.7 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09d1e0809..a7317e237 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.6" +version = "2024.1.7" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 0fafbf1c0..2c4ac2ef3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.6" +version = "2024.1.7" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 210df6c9b..283c22747 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.6 +mise 2024.1.7 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 33f862273..cace2878f 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.6"; + version = "2024.1.7"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index aa0623641..c0026ac39 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.6" +.TH mise 1 "mise 2024.1.7" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.6 +v2024.1.7 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 62f996bdf..9e6ed1615 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.6 +Version: 2024.1.7 Release: 1 URL: https://github.com/jdx/mise/ Group: System From ab6e912e98b429e79494ae65a9d37c3633bdd0ac Mon Sep 17 00:00:00 2001 From: Gary Coady Date: Fri, 5 Jan 2024 20:25:40 +0100 Subject: [PATCH 1550/1891] Add `description` to task object in JSON schema (#1373) Support tasks with a `description` key in the definition. This allows configs with a description to be validated correctly. --- schema/mise.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schema/mise.json b/schema/mise.json index 2a08b1894..1e2ea568b 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -163,6 +163,10 @@ } ] }, + "description": { + "description": "description of task", + "type": "string" + }, "depends": { "description": "other tasks to run before this task", "type": "array", From 15cfa1eebd18ee77b931b5e4343a4ef1d7c2473f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 10:59:07 -0600 Subject: [PATCH 1551/1891] added ideavim config --- .idea/mise.iml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .idea/mise.iml diff --git a/.idea/mise.iml b/.idea/mise.iml new file mode 100644 index 000000000..8e4258be6 --- /dev/null +++ b/.idea/mise.iml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 3bfb33e2b6ea00c461ccfe32b4f72fc43769b80b Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sat, 6 Jan 2024 18:51:49 +0100 Subject: [PATCH 1552/1891] fix(java): enable macOS integration hint for Zulu distribution (#1381) * fix(java): enable macOS integration hint for Zulu distribution * fix(java): address PR comments --- src/plugins/core/java.rs | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 92ef3ab96..fce83298d 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -174,8 +174,21 @@ impl JavaPlugin { file::rename(entry.path(), dest)?; } + if cfg!(target_os = "macos") { + self.handle_macos_integration(&contents_dir, tv, m)?; + } + + Ok(()) + } + + fn handle_macos_integration( + &self, + contents_dir: &Path, + tv: &ToolVersion, + m: &JavaMetadata, + ) -> Result<()> { // move Contents dir to install path for macOS, if it exists - if os() == "macosx" && contents_dir.exists() { + if contents_dir.exists() { file::create_dir_all(tv.install_path().join("Contents"))?; for entry in fs::read_dir(contents_dir)? { let entry = entry?; @@ -191,6 +204,24 @@ impl JavaPlugin { tv.install_path().as_path(), &tv.install_path().join("Contents").join("Home"), )?; + } + + // if vendor is Zulu, symlink zulu-{major_version}.jdk/Contents to install path for macOS + if m.vendor.as_str() == "zulu" { + let (major_version, _) = m + .version + .split_once('.') + .unwrap_or_else(|| (&m.version, "")); + file::make_symlink( + tv.install_path() + .join(format!("zulu-{}.jdk", major_version)) + .join("Contents") + .as_path(), + &tv.install_path().join("Contents"), + )?; + } + + if tv.install_path().join("Contents").exists() { info!( "{}", formatdoc! {r#" @@ -203,7 +234,6 @@ impl JavaPlugin { } ); } - Ok(()) } From 46cbe0a50cf51efd29beb4f287c295a819ecefb5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 10:09:04 -0800 Subject: [PATCH 1553/1891] fixed config load order (#1377) * fixed config load order Fixes #1376 * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+rtx-vm@users.noreply.github.com> --- src/config/mod.rs | 49 ++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 3f1b521b5..35b20c40b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -348,32 +348,37 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap> = Lazy::new(|| { - let mut filenames = std::collections::VecDeque::from([ - env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.clone(), - env::MISE_DEFAULT_CONFIG_FILENAME.clone(), - ]); if *env::MISE_DEFAULT_CONFIG_FILENAME == ".mise.toml" { - filenames.push_front(".rtx.toml".into()); - filenames.push_front(".rtx.local.toml".into()); - filenames.push_front(".mise/config.toml".into()); - filenames.push_front(".config/mise.toml".into()); - filenames.push_front(".config/mise/config.toml".into()); - filenames.push_back(".config/mise/config.local.toml".into()); - filenames.push_back(".config/mise.local.toml".into()); - filenames.push_back(".mise/config.local.toml".into()); - filenames.push_back(".mise.local.toml".into()); + let mut filenames = vec![ + env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.clone(), // .tool-versions + ".config/mise/config.toml".into(), + ".config/mise.toml".into(), + ".mise/config.toml".into(), + ".rtx.toml".into(), + env::MISE_DEFAULT_CONFIG_FILENAME.clone(), // .mise.toml + ".config/mise/config.local.toml".into(), + ".config/mise.local.toml".into(), + ".mise/config.local.toml".into(), + ".rtx.local.toml".into(), + ".mise.local.toml".into(), + ]; if let Some(env) = &*env::MISE_ENV { - filenames.push_back(format!(".config/mise/config.{env}.toml")); - filenames.push_back(format!(".config/mise.{env}.toml")); - filenames.push_back(format!(".mise/config.{env}.local.toml")); - filenames.push_back(format!(".mise.{env}.toml")); - filenames.push_back(format!(".config/mise/config.{env}.local.toml")); - filenames.push_back(format!(".config/mise.{env}.local.toml")); - filenames.push_back(format!(".mise/config.{env}.local.toml")); - filenames.push_back(format!(".mise.{env}.local.toml")); + filenames.push(format!(".config/mise/config.{env}.toml")); + filenames.push(format!(".config/mise.{env}.toml")); + filenames.push(format!(".mise/config.{env}.local.toml")); + filenames.push(format!(".mise.{env}.toml")); + filenames.push(format!(".config/mise/config.{env}.local.toml")); + filenames.push(format!(".config/mise.{env}.local.toml")); + filenames.push(format!(".mise/config.{env}.local.toml")); + filenames.push(format!(".mise.{env}.local.toml")); } + filenames + } else { + vec![ + env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.clone(), + env::MISE_DEFAULT_CONFIG_FILENAME.clone(), + ] } - filenames.into_iter().collect() }); pub fn load_config_paths(config_filenames: &[String]) -> Vec { From 35c97e7f90918514025601c3bedbb55f525b012d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 11:22:12 -0800 Subject: [PATCH 1554/1891] paranoid (#1382) --- src/cli/settings/ls.rs | 1 + src/cli/settings/set.rs | 1 + src/cli/settings/unset.rs | 1 + src/config/config_file/mise_toml.rs | 52 ++------ src/config/config_file/mod.rs | 116 +++++++++++++++--- ..._config_file__mise_toml__tests__env-5.snap | 1 + ...fig_file__mise_toml__tests__fixture-2.snap | 1 + ...fig_file__mise_toml__tests__fixture-6.snap | 1 + ...g_file__mise_toml__tests__path_dirs-5.snap | 1 + ...ile__mise_toml__tests__remove_alias-4.snap | 1 + ...le__mise_toml__tests__remove_plugin-4.snap | 1 + ..._mise_toml__tests__replace_versions-4.snap | 1 + src/config/settings.rs | 2 + src/plugins/external_plugin.rs | 5 +- 14 files changed, 128 insertions(+), 57 deletions(-) diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index e082e8e2b..7c7e18e0e 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -57,6 +57,7 @@ mod tests { legacy_version_file = true legacy_version_file_disable_tools = [] not_found_auto_install = true + paranoid = false plugin_autoupdate_last_check_duration = "20m" quiet = false raw = false diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 4c502c2eb..9ae09d85d 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -88,6 +88,7 @@ pub mod tests { legacy_version_file = false legacy_version_file_disable_tools = [] not_found_auto_install = true + paranoid = false plugin_autoupdate_last_check_duration = "1m" quiet = false raw = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 942170d8b..87410d850 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -51,6 +51,7 @@ mod tests { legacy_version_file = true legacy_version_file_disable_tools = [] not_found_auto_install = true + paranoid = false plugin_autoupdate_last_check_duration = "20m" quiet = false raw = false diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index e0131002e..7e929ecdf 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -11,10 +11,9 @@ use eyre::WrapErr; use tera::Context; use toml_edit::{table, value, Array, Document, Item, Table, Value}; -use crate::config::config_file::{ConfigFile, ConfigFileType}; +use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; use crate::config::settings::SettingsPartial; -use crate::config::{config_file, AliasMap}; -use crate::errors::Error::UntrustedConfig; +use crate::config::AliasMap; use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; use crate::task::Task; @@ -22,8 +21,8 @@ use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, }; -use crate::ui::{prompt, style}; -use crate::{dirs, env, file, parse_error}; +use crate::ui::style; +use crate::{dirs, file, parse_error}; #[derive(Default)] pub struct MiseToml { @@ -88,7 +87,7 @@ impl MiseToml { } fn parse_env_file(&mut self, k: &str, v: &Item, deprecate: bool) -> Result<()> { - self.trust_check()?; + trust_check(&self.path)?; if deprecate { warn!("{k} is deprecated. Use 'env.mise.file' instead."); } @@ -122,7 +121,7 @@ impl MiseToml { } fn parse_env(&mut self, key: &str, v: &Item) -> Result<()> { - self.trust_check()?; + trust_check(&self.path)?; if let Some(table) = v.as_table_like() { ensure!( !table.contains_key("PATH"), @@ -173,7 +172,7 @@ impl MiseToml { } fn parse_path_env(&self, k: &str, v: &Item) -> Result> { - self.trust_check()?; + trust_check(&self.path)?; let config_root = self.path.parent().unwrap().to_path_buf(); let get_path = |v: &Item| -> Result { if let Some(s) = v.as_str() { @@ -232,7 +231,7 @@ impl MiseToml { } fn parse_plugins(&self, key: &str, v: &Item) -> Result> { - self.trust_check()?; + trust_check(&self.path)?; self.parse_hashmap(key, v) } @@ -364,7 +363,7 @@ impl MiseToml { for (tvr, _) in &tool_version_list.requests { if let ToolVersionRequest::Path(_, _) = tvr { // "path:" can be dangerous to run automatically - self.trust_check()?; + trust_check(&self.path)?; } } @@ -634,44 +633,13 @@ impl MiseToml { if !input.contains("{{") && !input.contains("{%") && !input.contains("{#") { return Ok(input.to_string()); } - self.trust_check()?; + trust_check(&self.path)?; let dir = self.path.parent().unwrap(); let output = get_tera(dir) .render_str(input, &self.context) .wrap_err_with(|| eyre!("failed to parse template: {k}='{input}'"))?; Ok(output) } - - fn trust_check(&self) -> Result<()> { - let default_cmd = String::new(); - let args = env::ARGS.read().unwrap(); - let cmd = args.get(1).unwrap_or(&default_cmd).as_str(); - if self.get_is_trusted() || cmd == "trust" || cmd == "completion" || cfg!(test) { - return Ok(()); - } - if cmd != "hook-env" { - let ans = prompt::confirm(format!( - "{} {} is not trusted. Trust it?", - style::eyellow("mise"), - style::epath(&self.path) - ))?; - if ans { - config_file::trust(self.path.as_path())?; - self.is_trusted.lock().unwrap().replace(true); - return Ok(()); - } - } - Err(UntrustedConfig())? - } - - fn get_is_trusted(&self) -> bool { - let mut is_trusted = self.is_trusted.lock().unwrap(); - is_trusted.unwrap_or_else(|| { - let b = config_file::is_trusted(self.path.as_path()); - *is_trusted = Some(b); - b - }) - } } impl ConfigFile for MiseToml { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index a1724d067..b882879c0 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -1,10 +1,13 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; +use std::ffi::OsStr; use std::fmt::{Debug, Display}; use std::hash::Hash; use std::path::{Path, PathBuf}; +use std::sync::Mutex; use color_eyre::eyre::{eyre, Result}; use confique::Partial; +use once_cell::sync::Lazy; use tool_versions::ToolVersions; @@ -12,12 +15,14 @@ use crate::cli::args::tool::ToolArg; use crate::config::config_file::mise_toml::MiseToml; use crate::config::settings::SettingsPartial; use crate::config::{global_config_files, system_config_files, AliasMap, Config, Settings}; -use crate::file::{display_path, replace_path}; -use crate::hash::hash_to_str; +use crate::file::display_path; +use crate::hash::{file_hash_sha256, hash_to_str}; +use crate::errors::Error::UntrustedConfig; use crate::plugins::PluginName; use crate::task::Task; use crate::toolset::{ToolVersionList, Toolset}; +use crate::ui::{prompt, style}; use crate::{dirs, env, file}; pub mod legacy_version; @@ -183,6 +188,11 @@ pub fn parse_or_init(path: &Path) -> Result> { } pub fn parse(path: &Path) -> Result> { + if let Ok(settings) = Settings::try_get() { + if settings.paranoid { + trust_check(path)?; + } + } match detect_config_file_type(path) { Some(ConfigFileType::MiseToml) => Ok(Box::new(MiseToml::from_file(path)?)), Some(ConfigFileType::ToolVersions) => Ok(Box::new(ToolVersions::from_file(path)?)), @@ -191,19 +201,56 @@ pub fn parse(path: &Path) -> Result> { } } +pub fn trust_check(path: &Path) -> Result<()> { + let default_cmd = String::new(); + let args = env::ARGS.read().unwrap(); + let cmd = args.get(1).unwrap_or(&default_cmd).as_str(); + if is_trusted(path) || cmd == "trust" || cfg!(test) { + return Ok(()); + } + if cmd != "hook-env" { + let ans = prompt::confirm(format!( + "{} {} is not trusted. Trust it?", + style::eyellow("mise"), + style::epath(path) + ))?; + if ans { + trust(path)?; + return Ok(()); + } + } + Err(UntrustedConfig())? +} pub fn is_trusted(path: &Path) -> bool { - let settings = Settings::get(); - if settings - .trusted_config_paths - .iter() - .any(|p| path.starts_with(replace_path(p))) - { + static IS_TRUSTED: Lazy>> = Lazy::new(|| Mutex::new(HashSet::new())); + if let Ok(path) = path.canonicalize() { + let mut cached = IS_TRUSTED.lock().unwrap(); + if cached.contains(&path) { + return true; + } + let settings = Settings::get(); + for p in settings.trusted_config_paths.iter() { + if path.starts_with(p) { + cached.insert(path); + return true; + } + } + if !trust_path(&path).exists() { + return false; + } + if settings.paranoid { + let trusted = trust_file_hash(&path).unwrap_or_else(|e| { + warn!("trust_file_hash: {e}"); + false + }); + if !trusted { + return false; + } + } + cached.insert(path); return true; } - match path.canonicalize() { - Ok(path) => trust_path(&path).exists(), - Err(_) => false, - } + false } pub fn trust(path: &Path) -> Result<()> { @@ -213,6 +260,11 @@ pub fn trust(path: &Path) -> Result<()> { file::create_dir_all(hashed_path.parent().unwrap())?; file::make_symlink(&path, &hashed_path)?; } + let trust_hash_path = hashed_path.with_extension("hash"); + if !trust_hash_path.exists() { + let hash = file_hash_sha256(&path)?; + file::write(&trust_hash_path, hash)?; + } Ok(()) } @@ -225,8 +277,44 @@ pub fn untrust(path: &Path) -> Result<()> { Ok(()) } +/// generates a path like ~/.mise/trusted-configs/dir-file-3e8b8c44c3.toml fn trust_path(path: &Path) -> PathBuf { - dirs::TRUSTED_CONFIGS.join(hash_to_str(&path)) + let trust_path = dirs::TRUSTED_CONFIGS.join(hash_to_str(&path)); + if trust_path.exists() { + return trust_path; + } + let trunc_str = |s: &OsStr| { + let mut s = s.to_str().unwrap().to_string(); + s.truncate(20); + s + }; + let parent = path + .parent() + .map(|p| p.to_path_buf()) + .unwrap_or_default() + .file_name() + .map(trunc_str); + let filename = path.file_name().map(trunc_str); + let hash = hash_to_str(&path); + + dirs::TRUSTED_CONFIGS.join( + [parent, filename, Some(hash)] + .into_iter() + .flatten() + .collect::>() + .join("-"), + ) +} + +fn trust_file_hash(path: &Path) -> Result { + let trust_path = trust_path(path); + let trust_hash_path = trust_path.with_extension("hash"); + if !trust_hash_path.exists() { + return Ok(false); + } + let hash = file::read_to_string(&trust_hash_path)?; + let actual = file_hash_sha256(path)?; + Ok(hash == actual) } fn detect_config_file_type(path: &Path) -> Option { diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap index 936c812b5..23b343fb4 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap @@ -20,6 +20,7 @@ MiseToml(/tmp/.mise.toml): { "legacy_version_file_disable_tools": Null, "log_level": Null, "not_found_auto_install": Null, + "paranoid": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap index 4efde2d47..89bacb3ce 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap @@ -19,6 +19,7 @@ expression: cf.settings().unwrap() "verbose": true, "quiet": null, "asdf_compat": null, + "paranoid": null, "jobs": null, "shorthands_file": null, "disable_default_shorthands": null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap index afcbf5f57..161e86539 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap @@ -24,6 +24,7 @@ MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@re ], "log_level": Null, "not_found_auto_install": Null, + "paranoid": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap index 826d6a3d5..713de8c83 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap @@ -20,6 +20,7 @@ MiseToml(~/fixtures/.mise.toml): { "legacy_version_file_disable_tools": Null, "log_level": Null, "not_found_auto_install": Null, + "paranoid": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index 7642f96fc..724762e4c 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -20,6 +20,7 @@ MiseToml(/tmp/.mise.toml): { "legacy_version_file_disable_tools": Null, "log_level": Null, "not_found_auto_install": Null, + "paranoid": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap index a849cd1e1..6c065857d 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap @@ -20,6 +20,7 @@ MiseToml(/tmp/.mise.toml): { "legacy_version_file_disable_tools": Null, "log_level": Null, "not_found_auto_install": Null, + "paranoid": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap index 278768a4d..c9f2dae62 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap @@ -20,6 +20,7 @@ MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 { "legacy_version_file_disable_tools": Null, "log_level": Null, "not_found_auto_install": Null, + "paranoid": Null, "plugin_autoupdate_last_check_duration": Null, "quiet": Null, "raw": Null, diff --git a/src/config/settings.rs b/src/config/settings.rs index ac0255ab0..2a2ff81d0 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -44,6 +44,8 @@ pub struct Settings { pub quiet: bool, #[config(env = "MISE_ASDF_COMPAT", default = false)] pub asdf_compat: bool, + #[config(env = "MISE_PARANOID", default = false)] + pub paranoid: bool, #[config(env = "MISE_JOBS", default = 4)] pub jobs: usize, #[config(env = "MISE_SHORTHANDS_FILE")] diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 34edc0c58..d0b396f2f 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -473,11 +473,14 @@ impl Plugin for ExternalPlugin { .is_some_and(|s| s == &url); let is_trusted = !is_shorthand || TRUSTED_SHORTHANDS.contains(&self.name.as_str()); if !is_trusted { - eprintln!( + warn!( "⚠️ {name} is a community-developed plugin: {url}", name = style(&self.name).blue(), url = style(url.trim_end_matches(".git")).yellow(), ); + if settings.paranoid { + bail!("Paranoid mode is enabled, refusing to install community-developed plugin"); + } if !prompt::confirm(format!("Would you like to install {}?", self.name))? { Err(PluginNotInstalled(self.name.clone()))? } From 332648d5283fa5b6984426919d2fe964df813a58 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 15:15:19 -0800 Subject: [PATCH 1555/1891] miette (#1368) --- Cargo.lock | 208 +++++++++++++---------- Cargo.toml | 3 +- src/cache.rs | 18 +- src/cli/activate.rs | 2 +- src/cli/alias/get.rs | 6 +- src/cli/alias/ls.rs | 2 +- src/cli/alias/mod.rs | 2 +- src/cli/alias/set.rs | 2 +- src/cli/alias/unset.rs | 2 +- src/cli/args/tool.rs | 2 +- src/cli/asdf.rs | 2 +- src/cli/bin_paths.rs | 2 +- src/cli/cache/clear.rs | 2 +- src/cli/cache/mod.rs | 2 +- src/cli/completion.rs | 2 +- src/cli/config/generate.rs | 2 +- src/cli/config/ls.rs | 2 +- src/cli/config/mod.rs | 2 +- src/cli/current.rs | 2 +- src/cli/deactivate.rs | 4 +- src/cli/direnv/activate.rs | 2 +- src/cli/direnv/envrc.rs | 20 ++- src/cli/direnv/exec.rs | 8 +- src/cli/direnv/mod.rs | 2 +- src/cli/doctor.rs | 2 +- src/cli/env.rs | 4 +- src/cli/env_vars.rs | 4 +- src/cli/exec.rs | 11 +- src/cli/external.rs | 2 +- src/cli/global.rs | 2 +- src/cli/hook_env.rs | 12 +- src/cli/hook_not_found.rs | 2 +- src/cli/implode.rs | 2 +- src/cli/install.rs | 2 +- src/cli/latest.rs | 2 +- src/cli/link.rs | 6 +- src/cli/local.rs | 16 +- src/cli/ls.rs | 14 +- src/cli/ls_remote.rs | 2 +- src/cli/mod.rs | 5 +- src/cli/outdated.rs | 2 +- src/cli/plugins/install.rs | 7 +- src/cli/plugins/link.rs | 8 +- src/cli/plugins/ls.rs | 2 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/mod.rs | 2 +- src/cli/plugins/uninstall.rs | 2 +- src/cli/plugins/update.rs | 5 +- src/cli/prune.rs | 2 +- src/cli/render_completion.rs | 2 +- src/cli/render_help.rs | 2 +- src/cli/render_mangen.rs | 8 +- src/cli/reshim.rs | 2 +- src/cli/run.rs | 22 +-- src/cli/self_update.rs | 18 +- src/cli/settings/get.rs | 6 +- src/cli/settings/ls.rs | 4 +- src/cli/settings/mod.rs | 2 +- src/cli/settings/set.rs | 8 +- src/cli/settings/unset.rs | 2 +- src/cli/shell.rs | 4 +- src/cli/sync/mod.rs | 2 +- src/cli/sync/node.rs | 5 +- src/cli/sync/python.rs | 2 +- src/cli/task/edit.rs | 6 +- src/cli/task/ls.rs | 2 +- src/cli/task/mod.rs | 2 +- src/cli/trust.rs | 6 +- src/cli/uninstall.rs | 4 +- src/cli/upgrade.rs | 5 +- src/cli/use.rs | 10 +- src/cli/version.rs | 2 +- src/cli/watch.rs | 6 +- src/cli/where.rs | 5 +- src/cli/which.rs | 2 +- src/cmd.rs | 14 +- src/config/config_file/legacy_version.rs | 2 +- src/config/config_file/mise_toml.rs | 22 +-- src/config/config_file/mod.rs | 18 +- src/config/config_file/tool_versions.rs | 4 +- src/config/mod.rs | 6 +- src/config/settings.rs | 8 +- src/config/tracking.rs | 14 +- src/direnv.rs | 40 +++-- src/env_diff.rs | 18 +- src/fake_asdf.rs | 8 +- src/file.rs | 75 ++++---- src/git.rs | 30 ++-- src/hash.rs | 6 +- src/hook_env.rs | 23 ++- src/http.rs | 19 ++- src/lock_file.rs | 8 +- src/logger.rs | 9 +- src/main.rs | 63 ++++--- src/migrate.rs | 6 +- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/erlang.rs | 11 +- src/plugins/core/go.rs | 10 +- src/plugins/core/java.rs | 18 +- src/plugins/core/mod.rs | 4 +- src/plugins/core/node.rs | 16 +- src/plugins/core/python.rs | 8 +- src/plugins/core/ruby.rs | 25 ++- src/plugins/external_plugin.rs | 53 ++++-- src/plugins/external_plugin_cache.rs | 6 +- src/plugins/mise_plugin_toml.rs | 10 +- src/plugins/mod.rs | 11 +- src/plugins/script_manager.rs | 5 +- src/runtime_symlinks.rs | 9 +- src/shell/completions/mod.rs | 4 +- src/shims.rs | 18 +- src/shorthands.rs | 6 +- src/task.rs | 4 +- src/test.rs | 5 +- src/timeout.rs | 7 +- src/toolset/builder.rs | 2 +- src/toolset/mod.rs | 2 +- src/toolset/tool_version.rs | 4 +- src/toolset/tool_version_request.rs | 2 +- src/ui/prompt.rs | 12 +- 121 files changed, 690 insertions(+), 519 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7317e237..5c02b996e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,15 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + [[package]] name = "base64" version = "0.21.5" @@ -312,21 +321,6 @@ dependencies = [ "roff", ] -[[package]] -name = "color-eyre" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - [[package]] name = "color-print" version = "0.3.5" @@ -348,18 +342,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "color-spantrace" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "colorchoice" version = "1.0.0" @@ -707,16 +689,6 @@ dependencies = [ "libc", ] -[[package]] -name = "eyre" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" -dependencies = [ - "indenter", - "once_cell", -] - [[package]] name = "fastrand" version = "1.9.0" @@ -1191,6 +1163,23 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_ci" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" + [[package]] name = "itertools" version = "0.12.0" @@ -1295,6 +1284,38 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "backtrace", + "backtrace-ext", + "is-terminal", + "miette-derive", + "once_cell", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size 0.1.17", + "textwrap", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + [[package]] name = "mime" version = "0.3.17" @@ -1337,7 +1358,6 @@ dependencies = [ "clap", "clap_complete", "clap_mangen", - "color-eyre", "color-print", "confique", "console", @@ -1349,7 +1369,6 @@ dependencies = [ "duct", "either", "exec", - "eyre", "filetime", "flate2", "fslock", @@ -1362,6 +1381,7 @@ dependencies = [ "insta", "itertools", "log", + "miette", "num_cpus", "once_cell", "openssl", @@ -1387,7 +1407,7 @@ dependencies = [ "tar", "tempfile", "tera", - "terminal_size", + "terminal_size 0.3.0", "thiserror", "toml", "toml_edit", @@ -2180,15 +2200,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shared_child" version = "1.0.0" @@ -2247,6 +2258,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "socket2" version = "0.5.5" @@ -2307,6 +2324,34 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "supports-color" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" +dependencies = [ + "is-terminal", + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "supports-unicode" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7" +dependencies = [ + "is-terminal", +] + [[package]] name = "syn" version = "1.0.109" @@ -2435,6 +2480,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "terminal_size" version = "0.3.0" @@ -2445,6 +2500,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "textwrap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.53" @@ -2465,16 +2531,6 @@ dependencies = [ "syn 2.0.43", ] -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - [[package]] name = "time" version = "0.3.31" @@ -2628,28 +2684,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", ] [[package]] @@ -2732,6 +2766,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-normalization" version = "0.1.22" @@ -2782,12 +2822,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 2c4ac2ef3..1ef8a13eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,6 @@ chrono = { version = "0.4", default-features = false, features = ["std", "clock" clap = { version = "4", features = ["env", "derive", "string"] } clap_complete = { version = "4", optional = true } clap_mangen = { version = "0.2", optional = true } -color-eyre = "0.6" color-print = "0.3" confique = { version = "0.2", default-features = false } console = "0.15" @@ -53,7 +52,6 @@ dirs-next = "2" dotenvy = "0.15" duct = "0.13" either = "1" -eyre = "0.6" filetime = "0.2" flate2 = "1" fslock = "0.2" @@ -101,6 +99,7 @@ url = "2" versions = "6" which = "5" zip = { version = "0.6", default-features = false, features = ["deflate"] } +miette = { version = "5.10.0", features = ["fancy"] } [target.'cfg(unix)'.dependencies] exec = "0.3" diff --git a/src/cache.rs b/src/cache.rs index 67e3d3d24..d2836a7de 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -4,10 +4,10 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::time::Duration; -use eyre::Result; use flate2::read::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; +use miette::{IntoDiagnostic, Result}; use once_cell::sync::OnceCell; use serde::de::DeserializeOwned; use serde::Serialize; @@ -60,7 +60,7 @@ where let path = &self.cache_file_path; if !self.no_cache && self.is_fresh() { match self.parse() { - Ok(val) => return Ok::<_, color_eyre::Report>(val), + Ok(val) => return Ok::<_, miette::Report>(val), Err(err) => { warn!("failed to parse cache file: {} {:#}", path.display(), err); } @@ -78,10 +78,10 @@ where fn parse(&self) -> Result { let path = &self.cache_file_path; trace!("reading {}", display_path(path)); - let mut zlib = ZlibDecoder::new(File::open(path)?); + let mut zlib = ZlibDecoder::new(File::open(path).into_diagnostic()?); let mut bytes = Vec::new(); - zlib.read_to_end(&mut bytes)?; - Ok(rmp_serde::from_slice(&bytes)?) + zlib.read_to_end(&mut bytes).into_diagnostic()?; + rmp_serde::from_slice(&bytes).into_diagnostic() } pub fn write(&self, val: &T) -> Result<()> { @@ -92,8 +92,12 @@ where let partial_path = self .cache_file_path .with_extension(format!("part-{}", random_string(8))); - let mut zlib = ZlibEncoder::new(File::create(&partial_path)?, Compression::fast()); - zlib.write_all(&rmp_serde::to_vec_named(&val)?[..])?; + let mut zlib = ZlibEncoder::new( + File::create(&partial_path).into_diagnostic()?, + Compression::fast(), + ); + zlib.write_all(&rmp_serde::to_vec_named(&val).into_diagnostic()?[..]) + .into_diagnostic()?; file::rename(&partial_path, &self.cache_file_path)?; Ok(()) diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 7c9b58be7..e95e2fec8 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use eyre::Result; +use miette::Result; use crate::file::touch_dir; use crate::shell::{get_shell, ShellType}; diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index c409fc748..1fe077759 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::{eyre, Result}; +use miette::Result; use crate::config::Config; @@ -21,9 +21,9 @@ impl AliasGet { match config.get_all_aliases().get(&self.plugin) { Some(plugin) => match plugin.get(&self.alias) { Some(alias) => Ok(miseprintln!("{}", alias)), - None => Err(eyre!("Unknown alias: {}", &self.alias)), + None => Err(miette!("Unknown alias: {}", &self.alias)), }, - None => Err(eyre!("Unknown plugin: {}", &self.plugin)), + None => Err(miette!("Unknown plugin: {}", &self.plugin)), } } } diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 82d66efde..934064027 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use tabled::Tabled; use crate::config::Config; diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index c34a2c475..812528463 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use eyre::Result; +use miette::Result; use crate::plugins::PluginName; diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 4117105ac..297c6e015 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index f75bc86fc..3441d9e6d 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index 6a930fc7a..026be599c 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use clap::{Arg, Command, Error}; use console::style; -use eyre::Result; +use miette::Result; use regex::Regex; use crate::plugins::{unalias_plugin, PluginName}; diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 2a26f1d89..a567e76e5 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -1,7 +1,7 @@ use crate::cli::args::tool::ToolArg; use clap::ValueHint::CommandWithArguments; -use eyre::Result; use itertools::Itertools; +use miette::Result; use crate::cli::ls_remote::LsRemote; use crate::cli::Cli; diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index bf0685e57..fdde0ae41 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::config::Config; diff --git a/src/cli/cache/clear.rs b/src/cli/cache/clear.rs index a7df5cc86..ad7b1ee9f 100644 --- a/src/cli/cache/clear.rs +++ b/src/cli/cache/clear.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::dirs::CACHE; use crate::file::{display_path, remove_all}; diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 7968c7683..f62004e24 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use eyre::Result; +use miette::Result; use crate::env; diff --git a/src/cli/completion.rs b/src/cli/completion.rs index 841f08751..06636f950 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -1,6 +1,6 @@ use clap::builder::PossibleValue; use clap::ValueEnum; -use eyre::Result; +use miette::Result; use std::fmt::Display; /// Generate shell completions diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index ce7dc1255..b47aa113a 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -4,7 +4,7 @@ use crate::config::{Config, Settings}; use crate::file; use crate::file::display_path; use clap::ValueHint; -use eyre::Result; +use miette::Result; /// [experimental] Generate an .mise.toml file #[derive(Debug, clap::Args)] diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index c5f75e6db..2aecf6a0b 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -1,6 +1,6 @@ use console::style; -use eyre::Result; use itertools::Itertools; +use miette::Result; use tabled::settings::object::Columns; use tabled::settings::{Modify, Width}; diff --git a/src/cli/config/mod.rs b/src/cli/config/mod.rs index 7640026c1..9d03b7d3e 100644 --- a/src/cli/config/mod.rs +++ b/src/cli/config/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use eyre::Result; +use miette::Result; mod generate; mod ls; diff --git a/src/cli/current.rs b/src/cli/current.rs index 4dc4efab8..fc0608685 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,5 +1,5 @@ use console::style; -use eyre::Result; +use miette::Result; use crate::config::Config; diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 6cc0029a0..528509eb1 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::config::Config; use crate::hook_env; @@ -30,7 +30,7 @@ impl Deactivate { } fn err_inactive() -> Result<()> { - Err(eyre!(formatdoc!( + Err(miette!(formatdoc!( r#" mise is not activated in this shell session. Please run `{}` first in your shell rc file. diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 272b12837..cff9f4f6a 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; /// Output direnv function to use mise inside direnv /// diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index db97309fd..1d87b9bfa 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -1,7 +1,7 @@ use std::fs::{create_dir_all, File}; use std::io::Write; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::config::Config; use crate::hash::hash_to_str; @@ -21,33 +21,35 @@ impl Envrc { let envrc_path = env::MISE_TMP_DIR .join("direnv") - .join(hash_to_str(&env::current_dir()?) + ".envrc"); + .join(hash_to_str(&env::current_dir().into_diagnostic()?) + ".envrc"); // TODO: exit early if envrc_path exists and is up to date - create_dir_all(envrc_path.parent().unwrap())?; - let mut file = File::create(&envrc_path)?; + create_dir_all(envrc_path.parent().unwrap()).into_diagnostic()?; + let mut file = File::create(&envrc_path).into_diagnostic()?; writeln!( file, "### Do not edit. This was autogenerated by 'asdf direnv envrc' ###" - )?; + ) + .into_diagnostic()?; for cf in config.config_files.keys() { - writeln!(file, "watch_file {}", cf.to_string_lossy())?; + writeln!(file, "watch_file {}", cf.to_string_lossy()).into_diagnostic()?; } for (k, v) in ts.env(config) { if k == "PATH" { - writeln!(file, "PATH_add {}", v)?; + writeln!(file, "PATH_add {}", v).into_diagnostic()?; } else { writeln!( file, "export {}={}", shell_escape::unix::escape(k.into()), shell_escape::unix::escape(v.into()), - )?; + ) + .into_diagnostic()?; } } for path in ts.list_paths().into_iter().rev() { - writeln!(file, "PATH_add {}", path.to_string_lossy())?; + writeln!(file, "PATH_add {}", path.to_string_lossy()).into_diagnostic()?; } miseprintln!("{}", envrc_path.to_string_lossy()); diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 7f0ca6f27..d8d30c77b 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -1,6 +1,5 @@ use duct::Expression; -use eyre::Result; -use eyre::WrapErr; +use miette::{Context, IntoDiagnostic, Result}; use serde_derive::Deserialize; use crate::config::Config; @@ -31,11 +30,12 @@ impl DirenvExec { let json = cmd!("direnv", "watch", "json", ".tool-versions") .read() + .into_diagnostic() .wrap_err("error running direnv watch")?; - let w: DirenvWatches = serde_json::from_str(&json)?; + let w: DirenvWatches = serde_json::from_str(&json).into_diagnostic()?; cmd = cmd.env("DIRENV_WATCHES", w.watches); - miseprint!("{}", cmd.read()?); + miseprint!("{}", cmd.read().into_diagnostic()?); Ok(()) } } diff --git a/src/cli/direnv/mod.rs b/src/cli/direnv/mod.rs index 627781e07..1637ab089 100644 --- a/src/cli/direnv/mod.rs +++ b/src/cli/direnv/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use eyre::Result; +use miette::Result; use crate::config::Config; diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 8e534ddca..9bdd97cec 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -2,8 +2,8 @@ use std::fmt::Write; use std::process::exit; use console::{pad_str, style, Alignment}; -use eyre::Result; use indenter::indented; +use miette::Result; use crate::build_time::built_info; use crate::cli::version::VERSION; diff --git a/src/cli/env.rs b/src/cli/env.rs index e83de68f3..add149758 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; @@ -42,7 +42,7 @@ impl Env { fn output_json(&self, config: &Config, ts: Toolset) -> Result<()> { let env = ts.env_with_path(config); - miseprintln!("{}", serde_json::to_string_pretty(&env)?); + miseprintln!("{}", serde_json::to_string_pretty(&env).into_diagnostic()?); Ok(()) } diff --git a/src/cli/env_vars.rs b/src/cli/env_vars.rs index 562eee121..caa05baff 100644 --- a/src/cli/env_vars.rs +++ b/src/cli/env_vars.rs @@ -1,4 +1,4 @@ -use color_eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::config::config_file::mise_toml::MiseToml; use crate::config::config_file::ConfigFile; @@ -67,7 +67,7 @@ impl EnvVars { } fn get_mise_toml(filename: &str) -> Result { - let path = env::current_dir()?.join(filename); + let path = env::current_dir().into_diagnostic()?.join(filename); let mise_toml = if path.exists() { MiseToml::from_file(&path)? } else { diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 4ae9def97..4d3435039 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -3,14 +3,15 @@ use std::ffi::{OsStr, OsString}; use clap::ValueHint; use duct::IntoExecutablePath; -use eyre::Result; +#[cfg(test)] +use miette::IntoDiagnostic; +use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; #[cfg(test)] use crate::cmd; use crate::config::Config; use crate::env; - use crate::toolset::{InstallOptions, ToolsetBuilder}; /// Execute a command with tool(s) set @@ -97,11 +98,11 @@ impl Exec { for (k, v) in env.iter() { cmd = cmd.env(k, v); } - let res = cmd.unchecked().run()?; + let res = cmd.unchecked().run().into_diagnostic()?; match res.status.code() { Some(0) => Ok(()), - Some(code) => Err(eyre!("command failed: exit code {}", code)), - None => Err(eyre!("command failed: terminated by signal")), + Some(code) => Err(miette!("command failed: exit code {}", code)), + None => Err(miette!("command failed: terminated by signal")), } } } diff --git a/src/cli/external.rs b/src/cli/external.rs index 411e01bcb..2a630e805 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -1,5 +1,5 @@ use clap::{ArgMatches, Command}; -use eyre::Result; +use miette::Result; use rayon::prelude::*; use crate::config::Config; diff --git a/src/cli/global.rs b/src/cli/global.rs index cd20bfa5c..eea1db00a 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use eyre::Result; +use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::local::local; diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 6d59c12ff..e5ddf0998 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -3,8 +3,8 @@ use std::env::{join_paths, split_paths}; use std::ops::Deref; use std::path::PathBuf; -use eyre::Result; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use crate::config::Config; @@ -100,7 +100,10 @@ impl HookEnv { installs: &Vec, to_remove: &Vec, ) -> Result> { - let full = join_paths(&*env::PATH)?.to_string_lossy().to_string(); + let full = join_paths(&*env::PATH) + .into_diagnostic()? + .to_string_lossy() + .to_string(); let (pre, post) = match &*env::__MISE_ORIG_PATH { Some(orig_path) => match full.split_once(&format!(":{orig_path}")) { Some((pre, post)) if settings.experimental => { @@ -110,7 +113,10 @@ impl HookEnv { }, None => (String::new(), full), }; - let install_path = join_paths(installs)?.to_string_lossy().to_string(); + let install_path = join_paths(installs) + .into_diagnostic()? + .to_string_lossy() + .to_string(); let new_path = vec![pre, install_path, post] .into_iter() .filter(|p| !p.is_empty()) diff --git a/src/cli/hook_not_found.rs b/src/cli/hook_not_found.rs index 1b51765a4..7338e1ed1 100644 --- a/src/cli/hook_not_found.rs +++ b/src/cli/hook_not_found.rs @@ -1,6 +1,6 @@ use std::process::exit; -use eyre::Result; +use miette::Result; use crate::config::{Config, Settings}; diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 8dcbba082..1bd67d9de 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -1,6 +1,6 @@ use std::path::Path; -use eyre::Result; +use miette::Result; use crate::config::Settings; use crate::file::remove_all; diff --git a/src/cli/install.rs b/src/cli/install.rs index dca289ffd..cdb04553e 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 13c7755ac..5776492b0 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::Result; +use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/cli/link.rs b/src/cli/link.rs index c4db8ae4f..d32340f11 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -1,8 +1,8 @@ use std::path::PathBuf; use clap::ValueHint; -use color_eyre::eyre::{eyre, Result}; use console::style; +use miette::{IntoDiagnostic, Result}; use path_absolutize::Absolutize; use crate::cli::args::tool::{ToolArg, ToolArgParser}; @@ -39,7 +39,7 @@ impl Link { Some(ref tvr) => tvr.version(), None => bail!("must provide a version for {}", self.tool.style()), }; - let path = self.path.absolutize()?; + let path = self.path.absolutize().into_diagnostic()?; if !path.exists() { warn!( "Target path {} does not exist", @@ -51,7 +51,7 @@ impl Link { if self.force { remove_all(&target)?; } else { - return Err(eyre!( + return Err(miette!( "Tool version {} already exists, use {} to overwrite", self.tool.style(), style("--force").yellow().for_stderr() diff --git a/src/cli/local.rs b/src/cli/local.rs index ea1a4a877..285841b10 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -1,8 +1,8 @@ use std::path::{Path, PathBuf}; -use color_eyre::eyre::{eyre, ContextCompat, Result}; use console::style; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::{config_file, Config, Settings}; @@ -74,11 +74,15 @@ impl Local { } fn get_path() -> Result { - let mise_toml = env::current_dir()?.join(MISE_DEFAULT_CONFIG_FILENAME.as_str()); + let mise_toml = env::current_dir() + .into_diagnostic()? + .join(MISE_DEFAULT_CONFIG_FILENAME.as_str()); if *env::MISE_USE_TOML || mise_toml.exists() { Ok(mise_toml) } else { - Ok(env::current_dir()?.join(MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str())) + Ok(env::current_dir() + .into_diagnostic()? + .join(MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str())) } } @@ -87,8 +91,10 @@ pub fn get_parent_path() -> Result { if !*env::MISE_USE_TOML { filenames.push(MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); } - file::find_up(&env::current_dir()?, &filenames) - .wrap_err_with(|| eyre!("no {} file found", filenames.join(" or "),)) + match file::find_up(&env::current_dir().into_diagnostic()?, &filenames) { + Some(path) => Ok(path), + None => bail!("no {} file found", filenames.join(" or ")), + } } #[allow(clippy::too_many_arguments)] diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 035732126..528f3fdd6 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -4,9 +4,9 @@ use std::path::PathBuf; use std::sync::Arc; use console::style; -use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use serde_derive::Serialize; use tabled::{Table, Tabled}; @@ -102,7 +102,7 @@ impl Ls { for plugin_name in plugins { let plugin = config.get_or_create_plugin(plugin_name); if !plugin.is_installed() { - return Err(PluginNotInstalled(plugin_name.clone()))?; + return Err(PluginNotInstalled(plugin_name.clone())).into_diagnostic()?; } } } @@ -119,7 +119,10 @@ impl Ls { .filter(|(p, _, _)| plugins.contains(&p.name().to_string())) .map(|row| row.into()) .collect(); - miseprintln!("{}", serde_json::to_string_pretty(&runtimes)?); + miseprintln!( + "{}", + serde_json::to_string_pretty(&runtimes).into_diagnostic()? + ); return Ok(()); } @@ -131,7 +134,10 @@ impl Ls { let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); } - miseprintln!("{}", serde_json::to_string_pretty(&plugins)?); + miseprintln!( + "{}", + serde_json::to_string_pretty(&plugins).into_diagnostic()? + ); Ok(()) } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 77e4f2701..33e7fbd3e 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -1,7 +1,7 @@ use std::sync::Arc; -use eyre::Result; use itertools::Itertools; +use miette::Result; use rayon::prelude::*; use crate::cli::args::tool::ToolArg; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index a71c20b59..ee2f96a7b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,5 +1,5 @@ use clap::{FromArgMatches, Subcommand}; -use color_eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::config::{Config, Settings}; use crate::{logger, migrate, shims}; @@ -214,7 +214,8 @@ impl Cli { Err(err) => matches .subcommand() .ok_or(err) - .map(|(command, sub_m)| external::execute(command, sub_m))?, + .map(|(command, sub_m)| external::execute(command, sub_m)) + .into_diagnostic()?, } } } diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 9e04dba17..27d529483 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use std::sync::Arc; use console::{pad_str, style, Alignment}; -use eyre::Result; +use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index d7d4d23c2..38675261e 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::{eyre, Result}; +use miette::{IntoDiagnostic, Result}; use rayon::prelude::*; use rayon::ThreadPoolBuilder; use url::Url; @@ -91,7 +91,8 @@ impl PluginsInstall { fn install_many(&self, plugins: Vec, mpr: &MultiProgressReport) -> Result<()> { ThreadPoolBuilder::new() .num_threads(Settings::get().jobs) - .build()? + .build() + .into_diagnostic()? .install(|| -> Result<()> { plugins .into_par_iter() @@ -144,7 +145,7 @@ fn get_name_from_url(url: &str) -> Result { return Ok(unalias_plugin(name).to_string()); } } - Err(eyre!("could not infer plugin name from url: {}", url)) + Err(miette!("could not infer plugin name from url: {}", url)) } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index 314b96e26..397c3cf80 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -1,8 +1,8 @@ use std::path::{Path, PathBuf}; use clap::ValueHint; -use color_eyre::eyre::{eyre, Result}; use console::style; +use miette::{IntoDiagnostic, Result}; use path_absolutize::Absolutize; use crate::file::{make_symlink, remove_all}; @@ -36,19 +36,19 @@ impl PluginsLink { let (name, path) = match self.path { Some(path) => (self.name, path), None => { - let path = PathBuf::from(PathBuf::from(&self.name).absolutize()?); + let path = PathBuf::from(PathBuf::from(&self.name).absolutize().into_diagnostic()?); let name = get_name_from_path(&path); (name, path) } }; let name = unalias_plugin(&name); - let path = path.absolutize()?; + let path = path.absolutize().into_diagnostic()?; let symlink = dirs::PLUGINS.join(name); if symlink.exists() { if self.force { remove_all(&symlink)?; } else { - return Err(eyre!( + return Err(miette!( "plugin {} already exists, use --force to overwrite", style(&name).blue().for_stderr() )); diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 45179720d..6c5d4d4d1 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -1,7 +1,7 @@ use std::collections::BTreeSet; use std::sync::Arc; -use eyre::Result; +use miette::Result; use rayon::prelude::*; use tabled::settings::object::Columns; use tabled::settings::{Margin, Modify, Padding, Style}; diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index a119b602f..f168b4b6d 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -1,8 +1,8 @@ use std::collections::HashSet; use console::{measure_text_width, pad_str, Alignment}; -use eyre::Result; use itertools::Itertools; +use miette::Result; use crate::config::Config; diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index dd033f634..8aafb8994 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use eyre::Result; +use miette::Result; use crate::config::Config; diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index b4577c554..5e97d0e3a 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::config::Config; use crate::plugins::unalias_plugin; diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index ed5ceff36..cdd00cdcc 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,5 +1,5 @@ use console::style; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use rayon::prelude::*; use crate::config::{Config, Settings}; @@ -50,7 +50,8 @@ impl Update { let mpr = MultiProgressReport::get(); rayon::ThreadPoolBuilder::new() .num_threads(self.jobs.unwrap_or(settings.jobs)) - .build()? + .build() + .into_diagnostic()? .install(|| { plugins.into_par_iter().for_each(|(plugin, ref_)| { let prefix = format!("plugin:{}", style(plugin.name()).blue().for_stderr()); diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 74785743a..54fe87da2 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::sync::Arc; use console::style; -use eyre::Result; +use miette::Result; use crate::config::{Config, Settings}; diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 7e8eda49e..7078566e9 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -2,7 +2,7 @@ use clap::Args; use std::io::Cursor; use clap_complete::generate; -use eyre::Result; +use miette::Result; use crate::shell::completions; diff --git a/src/cli/render_help.rs b/src/cli/render_help.rs index 48f55ff91..f81de4fb4 100644 --- a/src/cli/render_help.rs +++ b/src/cli/render_help.rs @@ -1,7 +1,7 @@ use clap::builder::StyledStr; use console::strip_ansi_codes; -use eyre::Result; use itertools::Itertools; +use miette::Result; use crate::cli::Cli; diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index e810d46af..fd86c66d1 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -2,7 +2,7 @@ use std::env; use std::fs; use std::path::{Path, PathBuf}; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::cli::{version, Cli}; @@ -19,11 +19,11 @@ impl RenderMangen { let man = clap_mangen::Man::new(cli); let mut buffer: Vec = Default::default(); - man.render(&mut buffer)?; + man.render(&mut buffer).into_diagnostic()?; let out_dir = project_root().join("man").join("man1"); - fs::create_dir_all(&out_dir)?; - fs::write(out_dir.join("mise.1"), buffer)?; + fs::create_dir_all(&out_dir).into_diagnostic()?; + fs::write(out_dir.join("mise.1"), buffer).into_diagnostic()?; Ok(()) } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 5ffd2542e..5df05051d 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::config::Config; diff --git a/src/cli/run.rs b/src/cli/run.rs index 6ad3c8d12..fe33f46f0 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -11,9 +11,9 @@ use std::time::SystemTime; use clap::ValueHint; use console::{style, Color}; use duct::IntoExecutablePath; -use eyre::Result; use globwalk::GlobWalkerBuilder; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use once_cell::sync::Lazy; use petgraph::graph::DiGraph; use petgraph::Direction; @@ -163,7 +163,8 @@ impl Run { let pool = rayon::ThreadPoolBuilder::new() .num_threads(self.jobs() + 1) - .build()?; + .build() + .into_diagnostic()?; pool.scope(|s| { let run = |task: &Task| { let t = task.clone(); @@ -229,11 +230,11 @@ impl Run { info_unprefix_trunc!("{prefix} {cmd}"); if env::var("MISE_TASK_SCRIPT_FILE").is_ok() { - let mut tmp = tempfile::NamedTempFile::new()?; + let mut tmp = tempfile::NamedTempFile::new().into_diagnostic()?; let args = once(tmp.path().display().to_string()) .chain(args.iter().cloned()) .collect_vec(); - writeln!(tmp, "{}", script.trim())?; + writeln!(tmp, "{}", script.trim()).into_diagnostic()?; self.exec("sh", &args, task, env, prefix) } else { let args = vec!["-c".to_string(), script.trim().to_string()]; @@ -305,7 +306,7 @@ impl Run { } else if self.interleave { Ok(TaskOutput::Interleave) } else if let Some(output) = &settings.task_output { - Ok(output.parse()?) + Ok(output.parse().into_diagnostic()?) } else if self.raw(task) || self.jobs() == 1 || self.is_linear { Ok(TaskOutput::Interleave) } else { @@ -325,11 +326,11 @@ impl Run { } } - fn err_no_task(&self, config: &Config, t: &str) -> eyre::Report { + fn err_no_task(&self, config: &Config, t: &str) -> miette::Report { let tasks = config.tasks(); let task_names = tasks.keys().sorted().map(style::ecyan).join(", "); let t = style(&t).yellow().for_stderr(); - eyre!("no task named `{t}` found. Available tasks: {task_names}") + miette!("no task named `{t}` found. Available tasks: {task_names}") } fn validate_task(&self, task: &Task) -> Result<()> { if let Some(path) = &task.file { @@ -365,15 +366,16 @@ impl Run { fn get_last_modified(&self, root: &Path, globs: &[String]) -> Result> { let last_mod = GlobWalkerBuilder::from_patterns(root, globs) .follow_links(true) - .build()? + .build() + .into_diagnostic()? .filter_map(|e| e.ok()) .filter(|e| e.file_type().is_file()) .map(|e| e.path().to_owned()) .unique() - .map(|p| p.metadata().map_err(|err| eyre!(err))) + .map(|p| p.metadata().map_err(|err| miette!(err))) .collect::>>()? .into_iter() - .map(|m| m.modified().map_err(|err| eyre!(err))) + .map(|m| m.modified().map_err(|err| miette!(err))) .collect::>>()? .into_iter() .max(); diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index fc684d237..6cd99d370 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -1,5 +1,5 @@ -use color_eyre::Result; use console::style; +use miette::{IntoDiagnostic, Result}; use self_update::backends::github::{ReleaseList, Update}; use self_update::update::Release; use self_update::{cargo_crate_version, Status}; @@ -45,7 +45,9 @@ impl SelfUpdate { miseprintln!("mise is already up to date"); } if !self.no_plugins { - cmd!(&*env::MISE_BIN, "plugins", "update").run()?; + cmd!(&*env::MISE_BIN, "plugins", "update") + .run() + .into_diagnostic()?; } Ok(()) @@ -59,8 +61,10 @@ impl SelfUpdate { let releases = releases .repo_owner("jdx") .repo_name("mise") - .build()? - .fetch()?; + .build() + .into_diagnostic()? + .fetch() + .into_diagnostic()?; Ok(releases) } @@ -94,8 +98,10 @@ impl SelfUpdate { .bin_path_in_archive("mise/bin/mise") .identifier(&format!("mise-{v}-{target}.tar.gz")) .no_confirm(self.yes) - .build()? - .update()?; + .build() + .into_diagnostic()? + .update() + .into_diagnostic()?; Ok(status) } diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 7180bd3db..1a23da11d 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::{eyre, Result}; +use miette::{IntoDiagnostic, Result}; use serde_json::Value; use std::collections::BTreeMap; @@ -22,10 +22,10 @@ impl SettingsGet { Config::try_get()?; let settings = Settings::try_get()?; let json = settings.to_string(); - let doc: BTreeMap = serde_json::from_str(&json)?; + let doc: BTreeMap = serde_json::from_str(&json).into_diagnostic()?; match doc.get(&self.setting) { Some(value) => Ok(miseprintln!("{}", value)), - None => Err(eyre!("Unknown setting: {}", self.setting)), + None => Err(miette!("Unknown setting: {}", self.setting)), } } } diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 7c7e18e0e..57962d7e0 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use serde_json::Value; use std::collections::BTreeMap; @@ -19,7 +19,7 @@ impl SettingsLs { Config::try_get()?; let settings = Settings::try_get()?; let json = settings.to_string(); - let doc: BTreeMap = serde_json::from_str(&json)?; + let doc: BTreeMap = serde_json::from_str(&json).into_diagnostic()?; for (key, value) in doc { if Settings::hidden_configs().contains(key.as_str()) { continue; diff --git a/src/cli/settings/mod.rs b/src/cli/settings/mod.rs index 129fbc6cf..5a3a7f03b 100644 --- a/src/cli/settings/mod.rs +++ b/src/cli/settings/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use eyre::Result; +use miette::Result; mod get; mod ls; diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 9ae09d85d..8153fa130 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,4 +1,4 @@ -use color_eyre::eyre::{eyre, Result}; +use miette::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; @@ -30,7 +30,7 @@ impl SettingsSet { "shorthands_file" => self.value.into(), "disable_default_shorthands" => parse_bool(&self.value)?, "raw" => parse_bool(&self.value)?, - _ => return Err(eyre!("Unknown setting: {}", self.setting)), + _ => return Err(miette!("Unknown setting: {}", self.setting)), }; let mut global_config = Config::try_get()?.global_config.clone(); @@ -43,14 +43,14 @@ fn parse_bool(value: &str) -> Result { match value { "true" => Ok(true.into()), "false" => Ok(false.into()), - _ => Err(eyre!("{} must be true or false", value)), + _ => Err(miette!("{} must be true or false", value)), } } fn parse_i64(value: &str) -> Result { match value.parse::() { Ok(value) => Ok(value.into()), - Err(_) => Err(eyre!("{} must be a number", value)), + Err(_) => Err(miette!("{} must be a number", value)), } } diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 87410d850..5c449f22e 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::config::config_file::ConfigFile; use crate::config::Config; diff --git a/src/cli/shell.rs b/src/cli/shell.rs index f4a8d663d..3e4bc6bd2 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -1,5 +1,5 @@ -use color_eyre::eyre::{eyre, Result}; use console::style; +use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; @@ -68,7 +68,7 @@ impl Shell { } fn err_inactive() -> Result<()> { - Err(eyre!(formatdoc!( + Err(miette!(formatdoc!( r#" mise is not activated in this shell session. Please run `{}` first in your shell rc file. diff --git a/src/cli/sync/mod.rs b/src/cli/sync/mod.rs index 9a0f38149..15bb490d5 100644 --- a/src/cli/sync/mod.rs +++ b/src/cli/sync/mod.rs @@ -1,5 +1,5 @@ use clap::Subcommand; -use eyre::Result; +use miette::Result; mod node; mod python; diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 90c56919c..ae3fb4bd8 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; -use eyre::Result; use itertools::sorted; +use miette::{IntoDiagnostic, Result}; use crate::config::Config; use crate::env::{NODENV_ROOT, NVM_DIR}; @@ -51,7 +51,8 @@ impl SyncNode { fn run_brew(self, config: &Config) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); - let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); + let brew_prefix = + PathBuf::from(cmd!("brew", "--prefix").read().into_diagnostic()?).join("opt"); let installed_versions_path = dirs::INSTALLS.join("node"); file::remove_symlinks_with_target_prefix(&installed_versions_path, &brew_prefix)?; diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 62708c60e..a8b0212c9 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -1,5 +1,5 @@ -use eyre::Result; use itertools::sorted; +use miette::Result; use crate::config::Config; use crate::dirs; diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs index d218d0ff2..e2566d573 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/task/edit.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::config::{Config, Settings}; use crate::task::Task; @@ -30,7 +30,7 @@ impl TaskEdit { let path = config .project_root .as_ref() - .unwrap_or(&env::current_dir()?) + .unwrap_or(&env::current_dir().into_diagnostic()?) .join(".mise") .join("tasks") .join(&self.task); @@ -46,7 +46,7 @@ impl TaskEdit { if self.path { miseprintln!("{}", file.display()); } else { - cmd!(&*env::EDITOR, &file).run()?; + cmd!(&*env::EDITOR, &file).run().into_diagnostic()?; } Ok(()) diff --git a/src/cli/task/ls.rs b/src/cli/task/ls.rs index 3fd835125..39c2dbdf8 100644 --- a/src/cli/task/ls.rs +++ b/src/cli/task/ls.rs @@ -1,7 +1,7 @@ use crate::task::Task; use console::truncate_str; -use eyre::Result; use itertools::Itertools; +use miette::Result; use tabled::Tabled; diff --git a/src/cli/task/mod.rs b/src/cli/task/mod.rs index 81903df55..b815d622f 100644 --- a/src/cli/task/mod.rs +++ b/src/cli/task/mod.rs @@ -1,6 +1,6 @@ use crate::cli::run; use clap::Subcommand; -use eyre::Result; +use miette::Result; mod edit; mod ls; diff --git a/src/cli/trust.rs b/src/cli/trust.rs index 8acf90485..c9a8f52c2 100644 --- a/src/cli/trust.rs +++ b/src/cli/trust.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use clap::ValueHint; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::config; use crate::config::{config_file, DEFAULT_CONFIG_FILENAMES}; @@ -53,7 +53,7 @@ impl Trust { }, }; config_file::untrust(&path)?; - let path = path.canonicalize()?; + let path = path.canonicalize().into_diagnostic()?; info!("untrusted {}", path.display()); Ok(()) } @@ -66,7 +66,7 @@ impl Trust { }, }; config_file::trust(&path)?; - let path = path.canonicalize()?; + let path = path.canonicalize().into_diagnostic()?; info!("trusted {}", path.display()); Ok(()) } diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index d9eeeb64f..8fbab83de 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -1,6 +1,6 @@ use console::style; -use eyre::{Result, WrapErr}; use itertools::Itertools; +use miette::{Result, WrapErr}; use rayon::prelude::*; use std::sync::Arc; @@ -56,7 +56,7 @@ impl Uninstall { let pr = mpr.add(&tv.style()); if let Err(err) = plugin.uninstall_version(&tv, pr.as_ref(), self.dry_run) { error!("{err}"); - return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}"))); + return Err(miette!(err).wrap_err(format!("failed to uninstall {tv}"))); } if self.dry_run { pr.finish_with_message("uninstalled (dry-run)".into()); diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 2e3e402bf..95e1d2768 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -2,8 +2,7 @@ use demand::DemandOption; use std::collections::HashSet; use std::sync::Arc; -use eyre::Result; -use eyre::WrapErr; +use miette::{Context, IntoDiagnostic, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; @@ -141,7 +140,7 @@ impl Upgrade { }; ms = ms.option(DemandOption::new(tv).label(&label)); } - Ok(ms.run()?.into_iter().cloned().collect()) + Ok(ms.run().into_diagnostic()?.into_iter().cloned().collect()) } } diff --git a/src/cli/use.rs b/src/cli/use.rs index 4b1915d14..9c7090508 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -1,8 +1,8 @@ use std::path::{Path, PathBuf}; use console::style; -use eyre::Result; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::config_file::ConfigFile; @@ -135,11 +135,15 @@ impl Use { let path = if self.global { global_file() } else if let Some(env) = &self.env { - config_file_from_dir(&env::current_dir()?.join(format!(".mise.{}.toml", env))) + config_file_from_dir( + &env::current_dir() + .into_diagnostic()? + .join(format!(".mise.{}.toml", env)), + ) } else if let Some(p) = &self.path { config_file_from_dir(p) } else { - config_file_from_dir(&env::current_dir()?) + config_file_from_dir(&env::current_dir().into_diagnostic()?) }; config_file::parse_or_init(&path) } diff --git a/src/cli/version.rs b/src/cli/version.rs index 0ab688099..29ece4c7f 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -2,7 +2,7 @@ use std::string::ToString; use std::time::Duration; use console::style; -use eyre::Result; +use miette::Result; use once_cell::sync::Lazy; use versions::Versioning; diff --git a/src/cli/watch.rs b/src/cli/watch.rs index c0feeb485..556b48fd9 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -2,7 +2,7 @@ use std::process::exit; use console::style; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::config::{Config, Settings}; @@ -88,7 +88,7 @@ impl Watch { .tasks() .get(t) .cloned() - .ok_or_else(|| eyre!("Task not found: {t}")) + .ok_or_else(|| miette!("Task not found: {t}")) }) .collect::>>()?; let mut args = vec![]; @@ -117,7 +117,7 @@ impl Watch { if let Some(root) = &config.project_root { cmd = cmd.dir(root); } - cmd.run()?; + cmd.run().into_diagnostic()?; Ok(()) } } diff --git a/src/cli/where.rs b/src/cli/where.rs index 09c3c12d9..7207a2f25 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; @@ -62,7 +62,8 @@ impl Where { _ => Err(VersionNotInstalled( runtime.plugin.to_string(), runtime.tvr.map(|tvr| tvr.version()).unwrap_or_default(), - ))?, + )) + .into_diagnostic()?, } } } diff --git a/src/cli/which.rs b/src/cli/which.rs index 287281b24..df330f786 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -1,4 +1,4 @@ -use eyre::Result; +use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; diff --git a/src/cmd.rs b/src/cmd.rs index efbdfda8b..b06d22d43 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -8,9 +8,9 @@ use std::sync::{Mutex, RwLock}; use std::thread; use crate::config::Settings; -use color_eyre::Result; use duct::{Expression, IntoExecutablePath}; -use eyre::Context; +use miette::Result; +use miette::{Context, IntoDiagnostic}; use crate::env; use crate::errors::Error::ScriptFailed; @@ -221,6 +221,7 @@ impl<'a> CmdLineRunner<'a> { let mut cp = self .cmd .spawn() + .into_diagnostic() .wrap_err_with(|| format!("failed to execute command: {self}"))?; let (tx, rx) = channel(); if let Some(stdout) = cp.stdout.take() { @@ -292,7 +293,12 @@ impl<'a> CmdLineRunner<'a> { } fn execute_raw(mut self) -> Result<()> { - let status = self.cmd.spawn()?.wait()?; + let status = self + .cmd + .spawn() + .into_diagnostic()? + .wait() + .into_diagnostic()?; match status.success() { true => Ok(()), false => self.on_error(String::new(), status), @@ -343,7 +349,7 @@ impl<'a> CmdLineRunner<'a> { // eprintln!("{}", output); } } - Err(ScriptFailed(self.get_program(), Some(status)))? + Err(ScriptFailed(self.get_program(), Some(status))).into_diagnostic()? } fn get_program(&self) -> String { diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 89e046eee..cd383c057 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -2,7 +2,7 @@ use std::default::Default; use std::path::{Path, PathBuf}; use std::sync::Arc; -use eyre::Result; +use miette::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::plugins::{Plugin, PluginName}; diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 7e929ecdf..dfc37a58f 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -4,11 +4,9 @@ use std::iter::once; use std::path::{Path, PathBuf}; use std::sync::Mutex; -use color_eyre::eyre::eyre; -use color_eyre::{Result, Section}; use confique::Partial; -use eyre::WrapErr; -use tera::Context; +use miette::{IntoDiagnostic, Result, WrapErr}; +use tera::Context as TeraContext; use toml_edit::{table, value, Array, Document, Item, Table, Value}; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; @@ -26,7 +24,7 @@ use crate::{dirs, file, parse_error}; #[derive(Default)] pub struct MiseToml { - context: Context, + context: TeraContext, path: PathBuf, toolset: Toolset, env_files: Vec, @@ -60,14 +58,14 @@ impl MiseToml { pub fn from_file(path: &Path) -> Result { trace!("parsing: {}", display_path(path)); let mut rf = Self::init(path); - let body = file::read_to_string(path).suggestion("ensure file exists and can be read")?; + let body = file::read_to_string(path)?; // .suggestion("ensure file exists and can be read")?; rf.parse(&body)?; trace!("{}", rf.dump()); Ok(rf) } fn parse(&mut self, s: &str) -> Result<()> { - let doc: Document = s.parse().suggestion("ensure file is valid TOML")?; + let doc: Document = s.parse().into_diagnostic()?; // .suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { "dotenv" => self.parse_env_file(k, v, true)?, @@ -111,9 +109,10 @@ impl MiseToml { fn parse_env_filename(&mut self, path: PathBuf) -> Result<()> { let dotenv = dotenvy::from_path_iter(&path) - .wrap_err_with(|| eyre!("failed to parse dotenv file: {}", display_path(&path)))?; + .into_diagnostic() + .wrap_err_with(|| format!("failed to parse dotenv file: {}", display_path(&path)))?; for item in dotenv { - let (k, v) = item?; + let (k, v) = item.into_diagnostic()?; self.env.insert(k, v); } self.env_files.push(path); @@ -637,7 +636,8 @@ impl MiseToml { let dir = self.path.parent().unwrap(); let output = get_tera(dir) .render_str(input, &self.context) - .wrap_err_with(|| eyre!("failed to parse template: {k}='{input}'"))?; + .into_diagnostic() + .wrap_err_with(|| miette!("failed to parse template: {k}='{input}'"))?; Ok(output) } } @@ -782,7 +782,7 @@ impl ConfigFile for MiseToml { } "raw" => s.raw = Some(self.parse_bool(&k, v)?), "yes" => s.yes = Some(self.parse_bool(&k, v)?), - _ => Err(eyre!("Unknown config setting: {}", k))?, + _ => Err(miette!("Unknown config setting: {}", k))?, }; } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index b882879c0..54a0d2472 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -5,8 +5,8 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; use std::sync::Mutex; -use color_eyre::eyre::{eyre, Result}; use confique::Partial; +use miette::{IntoDiagnostic, Result}; use once_cell::sync::Lazy; use tool_versions::ToolVersions; @@ -15,10 +15,9 @@ use crate::cli::args::tool::ToolArg; use crate::config::config_file::mise_toml::MiseToml; use crate::config::settings::SettingsPartial; use crate::config::{global_config_files, system_config_files, AliasMap, Config, Settings}; +use crate::errors::Error::UntrustedConfig; use crate::file::display_path; use crate::hash::{file_hash_sha256, hash_to_str}; - -use crate::errors::Error::UntrustedConfig; use crate::plugins::PluginName; use crate::task::Task; use crate::toolset::{ToolVersionList, Toolset}; @@ -150,7 +149,7 @@ impl dyn ConfigFile { .versions .get(plugin) .ok_or_else(|| { - eyre!( + miette!( "no version set for {} in {}", plugin.to_string(), display_path(self.get_path()) @@ -165,7 +164,7 @@ impl dyn ConfigFile { } // check for something like `mise local node python@latest` which is invalid if runtimes.iter().any(|r| r.tvr.is_none()) { - return Err(eyre!("invalid input, specify a version for each tool. Or just specify one tool to print the current version")); + return Err(miette!("invalid input, specify a version for each tool. Or just specify one tool to print the current version")); } Ok(false) } @@ -219,8 +218,9 @@ pub fn trust_check(path: &Path) -> Result<()> { return Ok(()); } } - Err(UntrustedConfig())? + Err(UntrustedConfig()).into_diagnostic()? } + pub fn is_trusted(path: &Path) -> bool { static IS_TRUSTED: Lazy>> = Lazy::new(|| Mutex::new(HashSet::new())); if let Ok(path) = path.canonicalize() { @@ -254,7 +254,7 @@ pub fn is_trusted(path: &Path) -> bool { } pub fn trust(path: &Path) -> Result<()> { - let path = path.canonicalize()?; + let path = path.canonicalize().into_diagnostic()?; let hashed_path = trust_path(&path); if !hashed_path.exists() { file::create_dir_all(hashed_path.parent().unwrap())?; @@ -269,7 +269,7 @@ pub fn trust(path: &Path) -> Result<()> { } pub fn untrust(path: &Path) -> Result<()> { - let path = path.canonicalize()?; + let path = path.canonicalize().into_diagnostic()?; let hashed_path = trust_path(&path); if hashed_path.exists() { file::remove_file(hashed_path)?; @@ -340,7 +340,9 @@ impl PartialEq for dyn ConfigFile { self.get_path() == other.get_path() } } + impl Eq for dyn ConfigFile {} + impl Hash for dyn ConfigFile { fn hash(&self, state: &mut H) { self.get_path().hash(state); diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index c23fac069..dfc2ab69f 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -3,9 +3,9 @@ use std::path::{Path, PathBuf}; use crate::config::config_file; use console::{measure_text_width, pad_str, Alignment}; -use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use tera::Context; use crate::config::config_file::{ConfigFile, ConfigFileType}; @@ -58,7 +58,7 @@ impl ToolVersions { let mut cf = Self::init(&path); let dir = path.parent().unwrap(); let s = if config_file::is_trusted(&path) { - get_tera(dir).render_str(s, &cf.context)? + get_tera(dir).render_str(s, &cf.context).into_diagnostic()? } else { s.to_string() }; diff --git a/src/config/mod.rs b/src/config/mod.rs index 35b20c40b..c2b2c17a7 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -5,10 +5,10 @@ use std::iter::once; use std::path::PathBuf; use std::sync::{Arc, RwLock}; -use eyre::Context; -use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; +use miette::Context; +use miette::Result; use once_cell::sync::{Lazy, OnceCell}; use rayon::prelude::*; @@ -291,7 +291,7 @@ fn load_miserc() -> Result { Ok(MiseToml::init(&settings_path)) } true => MiseToml::from_file(&settings_path) - .wrap_err_with(|| eyre!("Error parsing {}", display_path(&settings_path))), + .wrap_err_with(|| miette!("Error parsing {}", display_path(&settings_path))), } } diff --git a/src/config/settings.rs b/src/config/settings.rs index 2a2ff81d0..5d5564581 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,5 +1,5 @@ use confique::env::parse::{list_by_colon, list_by_comma}; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use std::collections::{BTreeSet, HashSet}; use std::fmt::{Debug, Display, Formatter}; @@ -88,14 +88,14 @@ impl Settings { if let Some(settings) = SETTINGS.read().unwrap().as_ref() { return Ok(settings.clone()); } - let mut settings = Self::default_builder().load()?; + let mut settings = Self::default_builder().load().into_diagnostic()?; if let Some(cd) = &settings.cd { static ORIG_PATH: Lazy> = Lazy::new(env::current_dir); let mut cd = PathBuf::from(cd); if cd.is_relative() { - cd = ORIG_PATH.as_ref()?.join(cd); + cd = ORIG_PATH.as_ref().into_diagnostic()?.join(cd); } - env::set_current_dir(cd)?; + env::set_current_dir(cd).into_diagnostic()?; } if settings.raw { settings.jobs = 1; diff --git a/src/config/tracking.rs b/src/config/tracking.rs index 32f70b1fe..bc64f9684 100644 --- a/src/config/tracking.rs +++ b/src/config/tracking.rs @@ -2,7 +2,7 @@ use std::fs; use std::fs::{read_dir, remove_file}; use std::path::{Path, PathBuf}; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::dirs::TRACKED_CONFIGS; use crate::file::{create_dir_all, make_symlink}; @@ -23,12 +23,12 @@ impl Tracker { pub fn list_all() -> Result> { Self::clean()?; let mut output = vec![]; - for path in read_dir(&*TRACKED_CONFIGS)? { - let path = path?.path(); + for path in read_dir(&*TRACKED_CONFIGS).into_diagnostic()? { + let path = path.into_diagnostic()?.path(); if !path.is_symlink() { continue; } - let path = fs::read_link(path)?; + let path = fs::read_link(path).into_diagnostic()?; if path.exists() { output.push(path); } @@ -37,10 +37,10 @@ impl Tracker { } pub fn clean() -> Result<()> { - for path in read_dir(&*TRACKED_CONFIGS)? { - let path = path?.path(); + for path in read_dir(&*TRACKED_CONFIGS).into_diagnostic()? { + let path = path.into_diagnostic()?.path(); if !path.exists() { - remove_file(&path)?; + remove_file(&path).into_diagnostic()?; } } Ok(()) diff --git a/src/direnv.rs b/src/direnv.rs index 92b035055..61f5e3bc7 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -5,10 +5,10 @@ use std::io::Write; use std::path::{Path, PathBuf}; use base64::prelude::*; -use eyre::Result; use flate2::write::{ZlibDecoder, ZlibEncoder}; use flate2::Compression; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] @@ -26,10 +26,10 @@ impl DirenvDiff { // Ok(serde_json::from_slice(&uncompressed[..])?) let mut writer = Vec::new(); let mut decoder = ZlibDecoder::new(writer); - let bytes = BASE64_URL_SAFE.decode(input)?; - decoder.write_all(&bytes[..])?; - writer = decoder.finish()?; - Ok(serde_json::from_slice(&writer[..])?) + let bytes = BASE64_URL_SAFE.decode(input).into_diagnostic()?; + decoder.write_all(&bytes[..]).into_diagnostic()?; + writer = decoder.finish().into_diagnostic()?; + serde_json::from_slice(&writer[..]).into_diagnostic() } pub fn new_path(&self) -> Vec { @@ -59,10 +59,14 @@ impl DirenvDiff { old.insert(0, path.into()); new.insert(0, path.into()); - self.old - .insert("PATH".into(), join_paths(&old)?.into_string().unwrap()); - self.new - .insert("PATH".into(), join_paths(&new)?.into_string().unwrap()); + self.old.insert( + "PATH".into(), + join_paths(&old).into_diagnostic()?.into_string().unwrap(), + ); + self.new.insert( + "PATH".into(), + join_paths(&new).into_diagnostic()?.into_string().unwrap(), + ); Ok((old, new)) } @@ -78,18 +82,23 @@ impl DirenvDiff { old.iter().position(|p| p == path).map(|i| old.remove(i)); new.iter().position(|p| p == path).map(|i| new.remove(i)); - self.old - .insert("PATH".into(), join_paths(&old)?.into_string().unwrap()); - self.new - .insert("PATH".into(), join_paths(&new)?.into_string().unwrap()); + self.old.insert( + "PATH".into(), + join_paths(&old).into_diagnostic()?.into_string().unwrap(), + ); + self.new.insert( + "PATH".into(), + join_paths(&new).into_diagnostic()?.into_string().unwrap(), + ); Ok((old, new)) } pub fn dump(&self) -> Result { let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); - gz.write_all(&serde_json::to_vec(self)?)?; - Ok(BASE64_URL_SAFE.encode(gz.finish()?)) + gz.write_all(&serde_json::to_vec(self).into_diagnostic()?) + .into_diagnostic()?; + Ok(BASE64_URL_SAFE.encode(gz.finish().into_diagnostic()?)) } } @@ -111,7 +120,6 @@ impl Display for DirenvDiff { #[cfg(test)] mod tests { - use super::*; #[test] diff --git a/src/env_diff.rs b/src/env_diff.rs index 1aea04bf0..4c9c63d73 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -5,11 +5,11 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use base64::prelude::*; -use eyre::Result; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use serde_derive::{Deserialize, Serialize}; use crate::{cmd, file}; @@ -76,7 +76,8 @@ impl EnvDiff { ", script = script.display()} ) .full_env(&env) - .read()?; + .read() + .into_diagnostic()?; let env: HashMap = env .into_iter() .map(|(k, v)| (k.into_string().unwrap(), v.into_string().unwrap())) @@ -118,16 +119,17 @@ impl EnvDiff { pub fn deserialize(raw: &str) -> Result { let mut writer = Vec::new(); let mut decoder = ZlibDecoder::new(writer); - let bytes = BASE64_STANDARD_NO_PAD.decode(raw)?; - decoder.write_all(&bytes[..])?; - writer = decoder.finish()?; - Ok(rmp_serde::from_slice(&writer[..])?) + let bytes = BASE64_STANDARD_NO_PAD.decode(raw).into_diagnostic()?; + decoder.write_all(&bytes[..]).into_diagnostic()?; + writer = decoder.finish().into_diagnostic()?; + rmp_serde::from_slice(&writer[..]).into_diagnostic() } pub fn serialize(&self) -> Result { let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); - gz.write_all(&rmp_serde::to_vec_named(self)?)?; - Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish()?)) + gz.write_all(&rmp_serde::to_vec_named(self).into_diagnostic()?) + .into_diagnostic()?; + Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish().into_diagnostic()?)) } pub fn to_patches(&self) -> EnvDiffPatches { diff --git a/src/fake_asdf.rs b/src/fake_asdf.rs index 786a47640..3a6b46066 100644 --- a/src/fake_asdf.rs +++ b/src/fake_asdf.rs @@ -1,14 +1,14 @@ +use miette::{ErrReport, IntoDiagnostic}; use std::env::{join_paths, split_paths}; use std::fs; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; -use color_eyre::eyre::ErrReport; use once_cell::sync::OnceCell; use crate::{env, file}; -pub fn setup() -> color_eyre::Result { +pub fn setup() -> miette::Result { static SETUP: OnceCell = OnceCell::new(); let path = SETUP.get_or_try_init(|| { let path = env::MISE_DATA_DIR.join(".fake-asdf"); @@ -22,9 +22,9 @@ pub fn setup() -> color_eyre::Result { mise asdf "$@" "#}, )?; - let mut perms = asdf_bin.metadata()?.permissions(); + let mut perms = asdf_bin.metadata().into_diagnostic()?.permissions(); perms.set_mode(0o755); - fs::set_permissions(&asdf_bin, perms)?; + fs::set_permissions(&asdf_bin, perms).into_diagnostic()?; } Ok::(path) })?; diff --git a/src/file.rs b/src/file.rs index 4e4e48e2c..4d81ff2a6 100644 --- a/src/file.rs +++ b/src/file.rs @@ -5,9 +5,9 @@ use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::time::Duration; -use color_eyre::eyre::{Context, Result}; use filetime::{set_file_times, FileTime}; use flate2::read::GzDecoder; +use miette::{Context, IntoDiagnostic, Result}; use tar::Archive; use zip::ZipArchive; @@ -22,6 +22,7 @@ pub fn remove_all>(path: P) -> Result<()> { Ok(x) if x.is_dir() => { trace!("rm -rf {}", display_path(path)); fs::remove_dir_all(path) + .into_diagnostic() .wrap_err_with(|| format!("failed rm -rf: {}", display_path(path)))?; } _ => {} @@ -32,7 +33,9 @@ pub fn remove_all>(path: P) -> Result<()> { pub fn remove_file>(path: P) -> Result<()> { let path = path.as_ref(); trace!("rm {}", display_path(path)); - fs::remove_file(path).wrap_err_with(|| format!("failed rm: {}", display_path(path))) + fs::remove_file(path) + .into_diagnostic() + .wrap_err_with(|| format!("failed rm: {}", display_path(path))) } pub fn remove_dir>(path: P) -> Result<()> { @@ -40,7 +43,7 @@ pub fn remove_dir>(path: P) -> Result<()> { (|| -> Result<()> { if path.exists() && is_empty_dir(path)? { trace!("rmdir {}", display_path(path)); - fs::remove_dir(path)?; + fs::remove_dir(path).into_diagnostic()?; } Ok(()) })() @@ -58,7 +61,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> Result<()> { let from = from.as_ref(); let to = to.as_ref(); trace!("mv {} {}", from.display(), to.display()); - fs::rename(from, to).wrap_err_with(|| { + fs::rename(from, to).into_diagnostic().wrap_err_with(|| { format!( "failed rename: {} -> {}", display_path(from), @@ -70,13 +73,16 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> Result<()> { pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { let path = path.as_ref(); trace!("write {}", display_path(path)); - fs::write(path, contents).wrap_err_with(|| format!("failed write: {}", display_path(path))) + fs::write(path, contents) + .into_diagnostic() + .wrap_err_with(|| format!("failed write: {}", display_path(path))) } pub fn read_to_string>(path: P) -> Result { let path = path.as_ref(); trace!("cat {}", display_path(path)); fs::read_to_string(path) + .into_diagnostic() .wrap_err_with(|| format!("failed read_to_string: {}", display_path(path))) } @@ -85,7 +91,9 @@ pub fn create(path: &Path) -> Result { create_dir_all(parent)?; } trace!("touch {}", display_path(path)); - File::create(path).wrap_err_with(|| format!("failed create: {}", display_path(path))) + File::create(path) + .into_diagnostic() + .wrap_err_with(|| format!("failed create: {}", display_path(path))) } pub fn create_dir_all>(path: P) -> Result<()> { @@ -93,6 +101,7 @@ pub fn create_dir_all>(path: P) -> Result<()> { if !path.exists() { trace!("mkdir -p {}", display_path(path)); fs::create_dir_all(path) + .into_diagnostic() .wrap_err_with(|| format!("failed create_dir_all: {}", display_path(path)))?; } Ok(()) @@ -124,13 +133,14 @@ pub fn touch_dir(dir: &Path) -> Result<()> { trace!("touch {}", dir.display()); let now = FileTime::now(); set_file_times(dir, now, now) + .into_diagnostic() .wrap_err_with(|| format!("failed to touch dir: {}", display_path(dir))) } pub fn modified_duration(path: &Path) -> Result { - let metadata = path.metadata()?; - let modified = metadata.modified()?; - let duration = modified.elapsed()?; + let metadata = path.metadata().into_diagnostic()?; + let modified = metadata.modified().into_diagnostic()?; + let duration = modified.elapsed().into_diagnostic()?; Ok(duration) } @@ -156,9 +166,9 @@ pub fn dir_subdirs(dir: &Path) -> Result> { return Ok(output); } - for entry in dir.read_dir()? { - let entry = entry?; - let ft = entry.file_type()?; + for entry in dir.read_dir().into_diagnostic()? { + let entry = entry.into_diagnostic()?; + let ft = entry.file_type().into_diagnostic()?; if ft.is_dir() || ft.is_symlink() { output.push(entry.file_name().into_string().unwrap()); } @@ -174,9 +184,9 @@ pub fn ls(dir: &Path) -> Result> { return Ok(output); } - for entry in dir.read_dir()? { - let entry = entry?; - if entry.file_type()?.is_file() { + for entry in dir.read_dir().into_diagnostic()? { + let entry = entry.into_diagnostic()?; + if entry.file_type().into_diagnostic()?.is_file() { output.push(entry.path()); } } @@ -187,9 +197,9 @@ pub fn ls(dir: &Path) -> Result> { pub fn make_symlink(target: &Path, link: &Path) -> Result<()> { trace!("ln -sf {} {}", target.display(), link.display()); if link.is_file() || link.is_symlink() { - fs::remove_file(link)?; + fs::remove_file(link).into_diagnostic()?; } - symlink(target, link)?; + symlink(target, link).into_diagnostic()?; Ok(()) } @@ -197,13 +207,13 @@ pub fn remove_symlinks_with_target_prefix(symlink_dir: &Path, target_prefix: &Pa if !symlink_dir.exists() { return Ok(()); } - for entry in symlink_dir.read_dir()? { - let entry = entry?; + for entry in symlink_dir.read_dir().into_diagnostic()? { + let entry = entry.into_diagnostic()?; let path = entry.path(); if path.is_symlink() { - let target = path.read_link()?; + let target = path.read_link().into_diagnostic()?; if target.starts_with(target_prefix) { - fs::remove_file(&path)?; + fs::remove_file(&path).into_diagnostic()?; } } } @@ -218,9 +228,10 @@ pub fn is_executable(path: &Path) -> bool { } pub fn make_executable(path: &Path) -> Result<()> { - let mut perms = path.metadata()?.permissions(); + let mut perms = path.metadata().into_diagnostic()?.permissions(); perms.set_mode(perms.mode() | 0o111); fs::set_permissions(path, perms) + .into_diagnostic() .wrap_err_with(|| format!("failed to chmod +x: {}", display_path(path)))?; Ok(()) } @@ -228,6 +239,7 @@ pub fn make_executable(path: &Path) -> Result<()> { fn is_empty_dir(path: &Path) -> Result { path.read_dir() .map(|mut i| i.next().is_none()) + .into_diagnostic() .wrap_err_with(|| format!("failed to read_dir: {}", display_path(path))) } @@ -281,19 +293,24 @@ pub fn which(name: &str) -> Option { pub fn untar(archive: &Path, dest: &Path) -> Result<()> { debug!("tar -xzf {} -C {}", archive.display(), dest.display()); - let f = File::open(archive)?; + let f = File::open(archive).into_diagnostic()?; let tar = GzDecoder::new(f); - Archive::new(tar).unpack(dest).wrap_err_with(|| { - let archive = display_path(archive); - let dest = display_path(dest); - format!("failed to extract tar: {archive} to {dest}") - }) + Archive::new(tar) + .unpack(dest) + .into_diagnostic() + .wrap_err_with(|| { + let archive = display_path(archive); + let dest = display_path(dest); + format!("failed to extract tar: {archive} to {dest}") + }) } pub fn unzip(archive: &Path, dest: &Path) -> Result<()> { - ZipArchive::new(File::open(archive)?) + ZipArchive::new(File::open(archive).into_diagnostic()?) + .into_diagnostic() .wrap_err_with(|| format!("failed to open zip archive: {}", display_path(archive)))? .extract(dest) + .into_diagnostic() .wrap_err_with(|| format!("failed to extract zip archive: {}", display_path(archive))) } diff --git a/src/git.rs b/src/git.rs index 887a81705..3f751b500 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,8 +1,8 @@ use std::fs::create_dir_all; use std::path::PathBuf; -use color_eyre::eyre::{eyre, Result}; use duct::Expression; +use miette::{IntoDiagnostic, Result}; use crate::cmd; use crate::file::touch_dir; @@ -38,13 +38,13 @@ impl Git { if res.status.success() { Ok(()) } else { - Err(eyre!( + Err(miette!( "git failed: {cmd:?} {}", String::from_utf8(res.stdout).unwrap() )) } } - Err(err) => Err(eyre!("git failed: {cmd:?} {err:#}")), + Err(err) => Err(miette!("git failed: {cmd:?} {err:#}")), }; exec(git_cmd!( &self.dir, @@ -74,7 +74,7 @@ impl Git { pub fn clone(&self, url: &str) -> Result<()> { debug!("cloning {} to {}", url, self.dir.display()); if let Some(parent) = self.dir.parent() { - create_dir_all(parent)?; + create_dir_all(parent).into_diagnostic()?; } match get_git_version() { Ok(version) => trace!("git version: {}", version), @@ -83,29 +83,39 @@ impl Git { err ), } - cmd!("git", "clone", "-q", "--depth", "1", url, &self.dir).run()?; + cmd!("git", "clone", "-q", "--depth", "1", url, &self.dir) + .run() + .into_diagnostic()?; Ok(()) } pub fn current_branch(&self) -> Result { - let branch = git_cmd!(&self.dir, "branch", "--show-current").read()?; + let branch = git_cmd!(&self.dir, "branch", "--show-current") + .read() + .into_diagnostic()?; debug!("current branch for {}: {}", self.dir.display(), &branch); Ok(branch) } pub fn current_sha(&self) -> Result { - let sha = git_cmd!(&self.dir, "rev-parse", "HEAD").read()?; + let sha = git_cmd!(&self.dir, "rev-parse", "HEAD") + .read() + .into_diagnostic()?; debug!("current sha for {}: {}", self.dir.display(), &sha); Ok(sha) } pub fn current_sha_short(&self) -> Result { - let sha = git_cmd!(&self.dir, "rev-parse", "--short", "HEAD").read()?; + let sha = git_cmd!(&self.dir, "rev-parse", "--short", "HEAD") + .read() + .into_diagnostic()?; debug!("current sha for {}: {}", self.dir.display(), &sha); Ok(sha) } pub fn current_abbrev_ref(&self) -> Result { - let aref = git_cmd!(&self.dir, "rev-parse", "--abbrev-ref", "HEAD").read()?; + let aref = git_cmd!(&self.dir, "rev-parse", "--abbrev-ref", "HEAD") + .read() + .into_diagnostic()?; debug!("current abbrev ref for {}: {}", self.dir.display(), &aref); Ok(aref) } @@ -140,7 +150,7 @@ impl Git { } fn get_git_version() -> Result { - let version = cmd!("git", "--version").read()?; + let version = cmd!("git", "--version").read().into_diagnostic()?; Ok(version.trim().into()) } diff --git a/src/hash.rs b/src/hash.rs index e4d005f59..c16222577 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -4,7 +4,7 @@ use std::fs::File; use std::hash::{Hash, Hasher}; use std::path::Path; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use rayon::prelude::*; use sha2::{Digest, Sha256}; @@ -18,9 +18,9 @@ pub fn hash_to_str(t: &T) -> String { } pub fn file_hash_sha256(path: &Path) -> Result { - let mut file = File::open(path)?; + let mut file = File::open(path).into_diagnostic()?; let mut hasher = Sha256::new(); - std::io::copy(&mut file, &mut hasher)?; + std::io::copy(&mut file, &mut hasher).into_diagnostic()?; let hash = hasher.finalize(); Ok(format!("{hash:x}")) } diff --git a/src/hook_env.rs b/src/hook_env.rs index 461ae2a74..68e5f5f72 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -5,11 +5,11 @@ use std::path::PathBuf; use std::time::SystemTime; use base64::prelude::*; -use eyre::Result; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use serde_derive::{Deserialize, Serialize}; use crate::env_diff::{EnvDiffOperation, EnvDiffPatches}; @@ -88,23 +88,30 @@ pub struct HookEnvWatches { pub fn serialize_watches(watches: &HookEnvWatches) -> Result { let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast()); - gz.write_all(&rmp_serde::to_vec_named(watches)?)?; - Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish()?)) + gz.write_all(&rmp_serde::to_vec_named(watches).into_diagnostic()?) + .into_diagnostic()?; + Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish().into_diagnostic()?)) } pub fn deserialize_watches(raw: String) -> Result { let mut writer = Vec::new(); let mut decoder = ZlibDecoder::new(writer); - let bytes = BASE64_STANDARD_NO_PAD.decode(raw)?; - decoder.write_all(&bytes[..])?; - writer = decoder.finish()?; - Ok(rmp_serde::from_slice(&writer[..])?) + let bytes = BASE64_STANDARD_NO_PAD.decode(raw).into_diagnostic()?; + decoder.write_all(&bytes[..]).into_diagnostic()?; + writer = decoder.finish().into_diagnostic()?; + rmp_serde::from_slice(&writer[..]).into_diagnostic() } pub fn build_watches(watch_files: &[PathBuf]) -> Result { let mut watches = BTreeMap::new(); for cf in get_watch_files(watch_files) { - watches.insert(cf.clone(), cf.metadata()?.modified()?); + watches.insert( + cf.clone(), + cf.metadata() + .into_diagnostic()? + .modified() + .into_diagnostic()?, + ); } Ok(HookEnvWatches { diff --git a/src/http.rs b/src/http.rs index c1671fef0..5ecbbd512 100644 --- a/src/http.rs +++ b/src/http.rs @@ -15,7 +15,7 @@ use std::time::Duration; use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::display_path; use crate::{env, file}; -use eyre::{Report, Result}; +use miette::{IntoDiagnostic, Report, Result}; use once_cell::sync::Lazy; use reqwest::blocking::{ClientBuilder, Response}; use reqwest::IntoUrl; @@ -31,7 +31,8 @@ impl Client { reqwest: Self::_new() .timeout(timeout) .connect_timeout(timeout) - .build()?, + .build() + .into_diagnostic()?, }) } @@ -50,16 +51,16 @@ impl Client { req = req.header("authorization", format!("token {}", token)); } } - let resp = req.send()?; + let resp = req.send().into_diagnostic()?; debug!("GET {url} {}", resp.status()); - resp.error_for_status_ref()?; + resp.error_for_status_ref().into_diagnostic()?; Ok(resp) } pub fn get_text(&self, url: U) -> Result { let url = url.into_url().unwrap(); let resp = self.get(url)?; - let text = resp.text()?; + let text = resp.text().into_diagnostic()?; Ok(text) } @@ -69,18 +70,18 @@ impl Client { { let url = url.into_url().unwrap(); let resp = self.get(url)?; - let json = resp.json()?; + let json = resp.json().into_diagnostic()?; Ok(json) } pub fn download_file(&self, url: U, path: &Path) -> Result<()> { - let url = url.into_url()?; + let url = url.into_url().into_diagnostic()?; debug!("GET Downloading {} to {}", &url, display_path(path)); let mut resp = self.get(url)?; file::create_dir_all(path.parent().unwrap())?; - let mut file = File::create(path)?; - resp.copy_to(&mut file)?; + let mut file = File::create(path).into_diagnostic()?; + resp.copy_to(&mut file).into_diagnostic()?; Ok(()) } } diff --git a/src/lock_file.rs b/src/lock_file.rs index 0acc31bdb..773f9db15 100644 --- a/src/lock_file.rs +++ b/src/lock_file.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::dirs; use crate::file::create_dir_all; @@ -34,12 +34,12 @@ impl LockFile { if let Some(parent) = self.path.parent() { create_dir_all(parent)?; } - let mut lock = fslock::LockFile::open(&self.path)?; - if !lock.try_lock()? { + let mut lock = fslock::LockFile::open(&self.path).into_diagnostic()?; + if !lock.try_lock().into_diagnostic()? { if let Some(f) = self.on_locked { f(&self.path) } - lock.lock()?; + lock.lock().into_diagnostic()?; } Ok(lock) } diff --git a/src/logger.rs b/src/logger.rs index af6e4751f..0289a0796 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -5,7 +5,7 @@ use std::path::Path; use crate::config::Settings; use crate::env; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use simplelog::*; pub fn init(settings: &Settings) { @@ -34,12 +34,13 @@ pub fn _init(settings: &Settings) { fn init_log_file(log_file: &Path) -> Result { if let Some(log_dir) = log_file.parent() { - create_dir_all(log_dir)?; + create_dir_all(log_dir).into_diagnostic()?; } - Ok(OpenOptions::new() + OpenOptions::new() .create(true) .append(true) - .open(log_file)?) + .open(log_file) + .into_diagnostic() } fn init_term_logger(level: LevelFilter) -> Box { diff --git a/src/main.rs b/src/main.rs index a34416683..84db43801 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,23 @@ extern crate core; #[macro_use] -extern crate eyre; -#[macro_use] extern crate indoc; -#[macro_use] -extern crate strum; #[cfg(test)] #[macro_use] extern crate insta; -#[cfg(test)] #[macro_use] -mod test; - -use std::process::exit; +extern crate miette; +#[macro_use] +extern crate strum; -use color_eyre::{Help, Report, SectionExt}; -use console::style; -use eyre::Result; use itertools::Itertools; +use miette::Result; -use crate::cli::version::VERSION; use crate::cli::Cli; +#[cfg(test)] +#[macro_use] +mod test; + #[macro_use] mod output; @@ -69,27 +65,28 @@ mod ui; fn main() -> Result<()> { let args = env::args().collect_vec(); - color_eyre::install()?; - match Cli::run(&args).with_section(|| VERSION.to_string().header("Version:")) { - Ok(()) => Ok(()), - Err(err) if log::max_level() < log::LevelFilter::Debug => { - display_friendly_err(err); - exit(1); - } - Err(err) => { - Err(err).suggestion("Run with --verbose or MISE_VERBOSE=1 for more information.") - } - } + // TODO: figure out how to display version/help + Cli::run(&args) + // match Cli::run(&args).with_context(|| miette!(help = format!("Version: {}", &*VERSION))) { + // Ok(()) => Ok(()), + // Err(err) => Err(err), + // Err(err) if log::max_level() < log::LevelFilter::Debug => { + // display_friendly_err(err); + // exit(1); + // } + // Err(err) => { + // Err(err).suggestion("Run with --verbose or MISE_VERBOSE=1 for more information.") + // } } -fn display_friendly_err(err: Report) { - for err in err.chain() { - error!("{err}"); - } - let dim = |s| style(s).dim().for_stderr(); - error!( - "{}", - dim("Run with --verbose or MISE_VERBOSE=1 for more information") - ); -} +// fn display_friendly_err(err: Report) { +// for err in err.chain() { +// error!("{err}"); +// } +// let dim = |s| style(s).dim().for_stderr(); +// error!( +// "{}", +// dim("Run with --verbose or MISE_VERBOSE=1 for more information") +// ); +// } diff --git a/src/migrate.rs b/src/migrate.rs index 9c5345b9b..7265e30fd 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -1,7 +1,7 @@ use std::fs; use std::path::Path; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use rayon::Scope; use crate::dirs::*; @@ -37,8 +37,8 @@ fn move_subdirs(from: &Path, to: &Path) -> Result<()> { if from.exists() { eprintln!("migrating {} to {}", from.display(), to.display()); file::create_dir_all(to)?; - for f in from.read_dir()? { - let f = f?.file_name(); + for f in from.read_dir().into_diagnostic()? { + let f = f.into_diagnostic()?.file_name(); let from_file = from.join(&f); let to_file = to.join(&f); if !to_file.exists() { diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 30733acf6..7cf75b5c2 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; -use eyre::Result; use itertools::Itertools; +use miette::Result; use versions::Versioning; use crate::cli::version::{ARCH, OS}; diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 550d734e1..eee1f375d 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use eyre::Result; use itertools::Itertools; +use miette::Result; use versions::Versioning; use crate::cli::version::{ARCH, OS}; diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 1a4ac5bb4..079800766 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use crate::file::display_path; use crate::http::HTTP_FETCH; @@ -51,7 +51,8 @@ impl ErlangPlugin { self.install_kerl()?; cmd!(self.kerl_path(), "update", "releases") .env("KERL_BASE_DIR", self.kerl_base_dir()) - .run()?; + .run() + .into_diagnostic()?; Ok(()) } @@ -75,7 +76,8 @@ impl ErlangPlugin { let versions = CorePlugin::run_fetch_task_with_timeout(move || { let output = cmd!(self.kerl_path(), "list", "releases", "all") .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) - .read()?; + .read() + .into_diagnostic()?; let versions = output .split('\n') .filter(|s| regex!(r"^[0-9].+$").is_match(s)) @@ -116,7 +118,8 @@ impl Plugin for ErlangPlugin { ctx.tv.install_path() ) .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) - .run()?; + .run() + .into_diagnostic()?; } } diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 93d2afe61..5169b669f 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use eyre::Result; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use versions::Versioning; use crate::cli::version::{ARCH, OS}; @@ -36,7 +36,9 @@ impl GoPlugin { } CorePlugin::run_fetch_task_with_timeout(move || { let repo = &*env::MISE_GO_REPO; - let output = cmd!("git", "ls-remote", "--tags", repo, "go*").read()?; + let output = cmd!("git", "ls-remote", "--tags", repo, "go*") + .read() + .into_diagnostic()?; let lines = output.split('\n'); let versions = lines.map(|s| s.split("/go").last().unwrap_or_default().to_string()) .filter(|s| !s.is_empty()) @@ -160,7 +162,9 @@ impl Plugin for GoPlugin { fn uninstall_version_impl(&self, _pr: &dyn SingleReport, tv: &ToolVersion) -> Result<()> { let gopath = self.gopath(tv); if gopath.exists() { - cmd!("chmod", "-R", "u+wx", gopath).run()?; + cmd!("chmod", "-R", "u+wx", gopath) + .run() + .into_diagnostic()?; } Ok(()) } diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index fce83298d..b0904dd73 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -3,8 +3,8 @@ use std::fmt::Display; use std::fs::{self}; use std::path::{Path, PathBuf}; -use color_eyre::eyre::{eyre, Result}; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use once_cell::sync::Lazy; use serde_derive::{Deserialize, Serialize}; use versions::Versioning; @@ -155,9 +155,11 @@ impl JavaPlugin { fn move_to_install_path(&self, tv: &ToolVersion, m: &JavaMetadata) -> Result<()> { let basedir = tv .download_path() - .read_dir()? + .read_dir() + .into_diagnostic()? .find(|e| e.as_ref().unwrap().file_type().unwrap().is_dir()) - .unwrap()? + .unwrap() + .into_diagnostic()? .path(); let contents_dir = basedir.join("Contents"); let source_dir = match m.vendor.as_str() { @@ -167,8 +169,8 @@ impl JavaPlugin { }; file::remove_all(tv.install_path())?; file::create_dir_all(tv.install_path())?; - for entry in fs::read_dir(source_dir)? { - let entry = entry?; + for entry in fs::read_dir(source_dir).into_diagnostic()? { + let entry = entry.into_diagnostic()?; let dest = tv.install_path().join(entry.file_name()); trace!("moving {:?} to {:?}", entry.path(), &dest); file::rename(entry.path(), dest)?; @@ -190,8 +192,8 @@ impl JavaPlugin { // move Contents dir to install path for macOS, if it exists if contents_dir.exists() { file::create_dir_all(tv.install_path().join("Contents"))?; - for entry in fs::read_dir(contents_dir)? { - let entry = entry?; + for entry in fs::read_dir(contents_dir).into_diagnostic()? { + let entry = entry.into_diagnostic()?; // skip Home dir, so we can symlink it later if entry.file_name() == "Home" { continue; @@ -269,7 +271,7 @@ impl JavaPlugin { let m = self .fetch_java_metadata(&release_type)? .get(&v) - .ok_or_else(|| eyre!("no metadata found for version {}", tv.version))?; + .ok_or_else(|| miette!("no metadata found for version {}", tv.version))?; Ok(m) } diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index b3d00cfc5..df2bc38a4 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -4,8 +4,8 @@ use std::iter::Iterator; use std::path::PathBuf; use std::sync::Arc; -use eyre::Result; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use once_cell::sync::Lazy; pub use python::PythonPlugin; @@ -80,7 +80,7 @@ impl CorePlugin { pub fn path_env_with_tv_path(tv: &ToolVersion) -> Result { let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); path.insert(0, tv.install_path().join("bin")); - Ok(env::join_paths(path)?) + env::join_paths(path).into_diagnostic() } pub fn run_fetch_task_with_timeout(f: F) -> Result diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index cfc3541a8..e78e5afba 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use serde_derive::Deserialize; use tempfile::tempdir_in; use url::Url; @@ -45,7 +45,7 @@ impl NodePlugin { } fn fetch_remote_versions_from_node(&self, base: &Url) -> Result> { let versions = HTTP_FETCH - .json::, _>(base.join("index.json")?)? + .json::, _>(base.join("index.json").into_diagnostic()?)? .into_iter() .map(|v| { if regex!(r"^v\d+\.").is_match(&v.version) { @@ -74,7 +74,7 @@ impl NodePlugin { }?; let tarball_name = &opts.binary_tarball_name; ctx.pr.set_message(format!("extracting {tarball_name}")); - let tmp_extract_path = tempdir_in(opts.install_path.parent().unwrap())?; + let tmp_extract_path = tempdir_in(opts.install_path.parent().unwrap()).into_diagnostic()?; file::untar(&opts.binary_tarball_path, tmp_extract_path.path())?; file::remove_all(&opts.install_path)?; let slug = format!("node-v{}-{}-{}", &opts.version, os(), arch()); @@ -231,7 +231,9 @@ impl NodePlugin { fn shasums_url(&self, v: &str) -> Result { // let url = MISE_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt.asc"))?; - let url = MISE_NODE_MIRROR_URL.join(&format!("v{v}/SHASUMS256.txt"))?; + let url = MISE_NODE_MIRROR_URL + .join(&format!("v{v}/SHASUMS256.txt")) + .into_diagnostic()?; Ok(url) } } @@ -343,11 +345,13 @@ impl BuildOpts { make_install_cmd: make_install_cmd(), source_tarball_path: ctx.tv.download_path().join(&source_tarball_name), source_tarball_url: env::MISE_NODE_MIRROR_URL - .join(&format!("v{v}/{source_tarball_name}"))?, + .join(&format!("v{v}/{source_tarball_name}")) + .into_diagnostic()?, source_tarball_name, binary_tarball_path: ctx.tv.download_path().join(&binary_tarball_name), binary_tarball_url: env::MISE_NODE_MIRROR_URL - .join(&format!("v{v}/{binary_tarball_name}"))?, + .join(&format!("v{v}/{binary_tarball_name}")) + .into_diagnostic()?, binary_tarball_name, install_path, }) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index aef09eaea..50ededf95 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use color_eyre::eyre::{eyre, Result}; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; @@ -73,7 +73,9 @@ impl PythonPlugin { self.install_or_update_python_build()?; let python_build_bin = self.python_build_bin(); CorePlugin::run_fetch_task_with_timeout(move || { - let output = cmd!(python_build_bin, "--definitions").read()?; + let output = cmd!(python_build_bin, "--definitions") + .read() + .into_diagnostic()?; let versions = output .split('\n') .map(|s| s.to_string()) @@ -193,7 +195,7 @@ impl Plugin for PythonPlugin { let settings = Settings::try_get()?; self.install_or_update_python_build()?; if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { - return Err(eyre!("Ref versions not supported for python")); + return Err(miette!("Ref versions not supported for python")); } ctx.pr.set_message("Running python-build".into()); let mut cmd = CmdLineRunner::new(self.python_build_bin()) diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 61687f5a9..47028d1dc 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -2,8 +2,7 @@ use std::collections::HashMap; use std::env::temp_dir; use std::path::{Path, PathBuf}; -use eyre::Result; -use eyre::WrapErr; +use miette::{Context, IntoDiagnostic, Result}; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; @@ -83,7 +82,8 @@ impl RubyPlugin { cmd!("sh", "install.sh") .env("PREFIX", self.ruby_build_path()) .dir(&tmp) - .run()?; + .run() + .into_diagnostic()?; file::remove_all(&tmp)?; Ok(()) } @@ -117,7 +117,8 @@ impl RubyPlugin { cmd!("make", "install") .env("PREFIX", self.ruby_install_path()) .dir(&tmp) - .run()?; + .run() + .into_diagnostic()?; file::remove_all(&tmp)?; Ok(()) } @@ -133,7 +134,9 @@ impl RubyPlugin { debug!("Updating ruby-install in {}", ruby_install_path.display()); CorePlugin::run_fetch_task_with_timeout(move || { - cmd!(&ruby_install_path, "--update").run()?; + cmd!(&ruby_install_path, "--update") + .run() + .into_diagnostic()?; file::touch_dir(&ruby_install_path)?; Ok(()) }) @@ -155,7 +158,9 @@ impl RubyPlugin { } let ruby_build_bin = self.ruby_build_bin(); let versions = CorePlugin::run_fetch_task_with_timeout(move || { - let output = cmd!(ruby_build_bin, "--definitions").read()?; + let output = cmd!(ruby_build_bin, "--definitions") + .read() + .into_diagnostic()?; let versions = output .split('\n') .filter(|s| regex!(r"^[0-9].+$").is_match(s)) @@ -223,7 +228,9 @@ impl RubyPlugin { } fn ruby_build_version(&self) -> Result { - let output = cmd!(self.ruby_build_bin(), "--version").read()?; + let output = cmd!(self.ruby_build_bin(), "--version") + .read() + .into_diagnostic()?; let re = regex!(r"^ruby-build ([0-9.]+)"); let caps = re.captures(&output).expect("ruby-build version regex"); Ok(caps.get(1).unwrap().as_str().to_string()) @@ -263,7 +270,7 @@ impl RubyPlugin { Ok(cmd.with_pr(pr).envs(&config.env)) } fn install_args_ruby_build(&self, tv: &ToolVersion) -> Result> { - let mut args = env::MISE_RUBY_BUILD_OPTS.clone()?; + let mut args = env::MISE_RUBY_BUILD_OPTS.clone().into_diagnostic()?; if self.verbose_install() { args.push("--verbose".into()); } @@ -288,7 +295,7 @@ impl RubyPlugin { args.push(version.into()); args.push("--install-dir".into()); args.push(tv.install_path().to_string_lossy().to_string()); - args.extend(env::MISE_RUBY_INSTALL_OPTS.clone()?); + args.extend(env::MISE_RUBY_INSTALL_OPTS.clone().into_diagnostic()?); Ok(args) } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index d0b396f2f..f690dc370 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -7,9 +7,9 @@ use std::process::exit; use std::sync::Arc; use clap::Command; -use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; use itertools::Itertools; +use miette::{IntoDiagnostic, Result, WrapErr}; use once_cell::sync::Lazy; use rayon::prelude::*; @@ -102,7 +102,7 @@ impl ExternalPlugin { self.repo_url .clone() .or_else(|| config.get_repo_url(&self.name)) - .ok_or_else(|| eyre!("No repository found for plugin {}", self.name)) + .ok_or_else(|| miette!("No repository found for plugin {}", self.name)) } fn install(&self, pr: &dyn SingleReport) -> Result<()> { @@ -175,14 +175,19 @@ impl ExternalPlugin { let cmd = self.script_man.cmd(&Script::ListAll); let result = run_with_timeout( move || { - let result = cmd.stdout_capture().stderr_capture().unchecked().run()?; + let result = cmd + .stdout_capture() + .stderr_capture() + .unchecked() + .run() + .into_diagnostic()?; Ok(result) }, *MISE_FETCH_REMOTE_VERSIONS_TIMEOUT, ) .wrap_err_with(|| { let script = self.script_man.get_script_path(&Script::ListAll); - eyre!("Failed to run {}", display_path(&script)) + miette!("Failed to run {}", display_path(&script)) })?; let stdout = String::from_utf8(result.stdout).unwrap(); let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string(); @@ -258,11 +263,24 @@ impl ExternalPlugin { fn fetch_cached_legacy_file(&self, legacy_file: &Path) -> Result> { let fp = self.legacy_cache_file_path(legacy_file); - if !fp.exists() || fp.metadata()?.modified()? < legacy_file.metadata()?.modified()? { + if !fp.exists() + || fp + .metadata() + .into_diagnostic()? + .modified() + .into_diagnostic()? + < legacy_file + .metadata() + .into_diagnostic()? + .modified() + .into_diagnostic()? + { return Ok(None); } - Ok(Some(fs::read_to_string(fp)?.trim().into())) + Ok(Some( + fs::read_to_string(fp).into_diagnostic()?.trim().into(), + )) } fn legacy_cache_file_path(&self, legacy_file: &Path) -> PathBuf { @@ -295,7 +313,7 @@ impl ExternalPlugin { // sm.prepend_path(p); // } // } - let output = sm.cmd(&Script::ListBinPaths).read()?; + let output = sm.cmd(&Script::ListBinPaths).read().into_diagnostic()?; output.split_whitespace().map(|f| f.to_string()).collect() } else { vec!["bin".into()] @@ -417,7 +435,7 @@ impl Plugin for ExternalPlugin { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) .wrap_err_with(|| { - eyre!( + miette!( "Failed listing remote versions for plugin {}", style(&self.name).blue().for_stderr(), ) @@ -432,7 +450,7 @@ impl Plugin for ExternalPlugin { self.latest_stable_cache .get_or_try_init(|| self.fetch_latest_stable()) .wrap_err_with(|| { - eyre!( + miette!( "Failed fetching latest stable version for plugin {}", style(&self.name).blue().for_stderr(), ) @@ -482,7 +500,7 @@ impl Plugin for ExternalPlugin { bail!("Paranoid mode is enabled, refusing to install community-developed plugin"); } if !prompt::confirm(format!("Would you like to install {}?", self.name))? { - Err(PluginNotInstalled(self.name.clone()))? + Err(PluginNotInstalled(self.name.clone())).into_diagnostic()? } } } @@ -558,7 +576,7 @@ impl Plugin for ExternalPlugin { .alias_cache .get_or_try_init(|| self.fetch_aliases()) .wrap_err_with(|| { - eyre!( + miette!( "Failed fetching aliases for plugin {}", style(&self.name).blue().for_stderr(), ) @@ -579,7 +597,7 @@ impl Plugin for ExternalPlugin { self.legacy_filename_cache .get_or_try_init(|| self.fetch_legacy_filenames()) .wrap_err_with(|| { - eyre!( + miette!( "Failed fetching legacy filenames for plugin {}", style(&self.name).blue().for_stderr(), ) @@ -595,7 +613,7 @@ impl Plugin for ExternalPlugin { let script = ParseLegacyFile(legacy_file.to_string_lossy().into()); let legacy_version = match self.script_man.script_exists(&script) { true => self.script_man.read(&script)?, - false => fs::read_to_string(legacy_file)?, + false => fs::read_to_string(legacy_file).into_diagnostic()?, } .trim() .to_string(); @@ -647,7 +665,7 @@ impl Plugin for ExternalPlugin { fn execute_external_command(&self, command: &str, args: Vec) -> Result<()> { if !self.is_installed() { - return Err(PluginNotInstalled(self.name.clone()).into()); + return Err(PluginNotInstalled(self.name.clone())).into_diagnostic(); } let script = Script::RunExternalCommand( self.plugin_path @@ -655,7 +673,12 @@ impl Plugin for ExternalPlugin { .join(format!("command-{command}.bash")), args, ); - let result = self.script_man.cmd(&script).unchecked().run()?; + let result = self + .script_man + .cmd(&script) + .unchecked() + .run() + .into_diagnostic()?; exit(result.status.code().unwrap_or(-1)); } diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 87cea79c7..dabdd7af4 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; use std::sync::RwLock; -use eyre::WrapErr; -use eyre::{eyre, Result}; +use miette::{IntoDiagnostic, Result, WrapErr}; use crate::cache::CacheManager; use crate::config::Config; @@ -102,5 +101,6 @@ fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> Result Result<()> { - let doc: Document = s.parse().suggestion("ensure file is valid TOML")?; + let doc: Document = s.parse().into_diagnostic()?; //.suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { "exec-env" => self.exec_env = self.parse_script_config(k, v)?, @@ -51,7 +50,7 @@ impl MisePluginToml { // this is an old key used in rtx-python // this file is invalid, so just stop parsing entirely if we see it "legacy-filenames" => return Ok(()), - _ => Err(eyre!("unknown key: {}", k))?, + _ => Err(miette!("unknown key: {}", k))?, } } Ok(()) @@ -101,7 +100,6 @@ impl MisePluginToml { #[cfg(test)] mod tests { - use crate::dirs; use super::*; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index b55100653..4eaf9e660 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -6,9 +6,8 @@ use std::path::{Path, PathBuf}; use clap::Command; use console::style; -use eyre::Result; -use eyre::WrapErr; use itertools::Itertools; +use miette::{IntoDiagnostic, Result, WrapErr}; use regex::Regex; use versions::Versioning; @@ -120,10 +119,10 @@ pub trait Plugin: Debug + Send + Sync { None => { let installed_symlink = self.installs_path().join("latest"); if installed_symlink.exists() { - let target = installed_symlink.read_link()?; + let target = installed_symlink.read_link().into_diagnostic()?; let version = target .file_name() - .ok_or_else(|| eyre!("Invalid symlink target"))? + .ok_or_else(|| miette!("Invalid symlink target"))? .to_string_lossy() .to_string(); Ok(Some(version)) @@ -288,7 +287,7 @@ pub trait Plugin: Debug + Send + Sync { file::create_dir_all(tv.install_path())?; file::create_dir_all(tv.download_path())?; file::create_dir_all(tv.cache_path())?; - File::create(self.incomplete_file_path(tv))?; + File::create(self.incomplete_file_path(tv)).into_diagnostic()?; Ok(()) } fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { @@ -320,7 +319,7 @@ fn fuzzy_match_filter(versions: Vec, query: &str) -> Result> if query == "latest" { query = "[0-9].*"; } - let query_regex = Regex::new(&format!("^{}([-.].+)?$", query))?; + let query_regex = Regex::new(&format!("^{}([-.].+)?$", query)).into_diagnostic()?; let version_regex = regex!( r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|SNAPSHOT|master)" ); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 683b1592a..25d736c5c 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -4,9 +4,9 @@ use std::fmt; use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use color_eyre::eyre::{Context, Result}; use duct::Expression; use indexmap::indexmap; +use miette::{Context, IntoDiagnostic, Result}; use once_cell::sync::Lazy; use crate::cmd::{cmd, CmdLineRunner}; @@ -165,6 +165,7 @@ impl ScriptManager { cmd = cmd.stderr_null(); } cmd.read() + .into_diagnostic() .wrap_err_with(|| ScriptFailed(display_path(&self.get_script_path(script)), None)) } @@ -180,7 +181,7 @@ impl ScriptManager { Some(ScriptFailed(_, status)) => *status, _ => None, }; - return Err(ScriptFailed(display_path(&path), status).into()); + return Err(ScriptFailed(display_path(&path), status)).into_diagnostic(); } Ok(()) } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 9c82536f6..51e3ce4a3 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -2,9 +2,9 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::sync::Arc; -use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; +use miette::{IntoDiagnostic, Result}; use regex::Regex; use versions::Versioning; @@ -20,7 +20,8 @@ pub fn rebuild(config: &Config) -> Result<()> { for (from, to) in symlinks { let from = installs_dir.join(from); if from.exists() { - if is_runtime_symlink(&from) && from.read_link()?.as_path() != to { + if is_runtime_symlink(&from) && from.read_link().into_diagnostic()?.as_path() != to + { trace!("Removing existing symlink: {}", from.display()); file::remove_file(&from)?; } else { @@ -84,8 +85,8 @@ fn remove_missing_symlinks(plugin: Arc) -> Result<()> { if !installs_dir.exists() { return Ok(()); } - for entry in std::fs::read_dir(installs_dir)? { - let entry = entry?; + for entry in std::fs::read_dir(installs_dir).into_diagnostic()? { + let entry = entry.into_diagnostic()?; let path = entry.path(); if is_runtime_symlink(&path) && !path.exists() { trace!("Removing missing symlink: {}", path.display()); diff --git a/src/shell/completions/mod.rs b/src/shell/completions/mod.rs index 46247b48d..85d49902e 100644 --- a/src/shell/completions/mod.rs +++ b/src/shell/completions/mod.rs @@ -5,13 +5,13 @@ use std::collections::HashSet; mod fish_complete; mod zsh_complete; -pub fn zsh_complete(cmd: &Command) -> eyre::Result { +pub fn zsh_complete(cmd: &Command) -> miette::Result { let output = zsh_complete::render(cmd); // let result = cmd!("shfmt", "-s").stdin_bytes(output).read()?; Ok(output) } -pub fn fish_complete(cmd: &Command) -> eyre::Result { +pub fn fish_complete(cmd: &Command) -> miette::Result { let output = fish_complete::render(cmd); // eprintln!("{}", output); // let result = cmd!("shfmt", "-s").stdin_bytes(output).read()?; diff --git a/src/shims.rs b/src/shims.rs index e927ae3e7..3b0bfc3c0 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -5,9 +5,8 @@ use std::path::{Path, PathBuf}; use std::process::exit; use std::sync::Arc; -use color_eyre::eyre::{eyre, Result}; -use eyre::WrapErr; use itertools::Itertools; +use miette::{IntoDiagnostic, Result, WrapErr}; use rayon::prelude::*; use crate::cli::exec::Exec; @@ -114,7 +113,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { for shim in shims_to_add { let symlink_path = dirs::SHIMS.join(shim); file::make_symlink(&mise_bin, &symlink_path).wrap_err_with(|| { - eyre!( + miette!( "Failed to create symlink from {} to {}", display_path(&mise_bin), display_path(&symlink_path) @@ -129,7 +128,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { match dirs::PLUGINS.join(plugin.name()).join("shims").read_dir() { Ok(files) => { for bin in files { - let bin = bin?; + let bin = bin.into_diagnostic()?; let bin_name = bin.file_name().into_string().unwrap(); let symlink_path = dirs::SHIMS.join(bin_name); make_shim(&bin.path(), &symlink_path)?; @@ -159,10 +158,11 @@ fn list_tool_bins(t: Arc, tv: &ToolVersion) -> Result> { fn list_executables_in_dir(dir: &Path) -> Result> { let mut out = HashSet::new(); - for bin in dir.read_dir()? { - let bin = bin?; + for bin in dir.read_dir().into_diagnostic()? { + let bin = bin.into_diagnostic()?; // skip non-files and non-symlinks or non-executable files - if (!bin.file_type()?.is_file() && !bin.file_type()?.is_symlink()) + if (!bin.file_type().into_diagnostic()?.is_file() + && !bin.file_type().into_diagnostic()?.is_symlink()) || !file::is_executable(&bin.path()) { continue; @@ -213,7 +213,7 @@ fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Res for tv in tvs { msg.push_str(&format!("mise use -g {}@{}\n", tv.plugin_name, tv.version)); } - Err(eyre!(msg.trim().to_string())) + Err(miette!(msg.trim().to_string())) } else { let mut msg = format!( "Tool{} not installed for shim: {}\n", @@ -224,6 +224,6 @@ fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Res msg.push_str(&format!("Missing tool version: {}\n", t)); } msg.push_str("Install all missing tools with: mise install\n"); - Err(eyre!(msg.trim().to_string())) + Err(miette!(msg.trim().to_string())) } } diff --git a/src/shorthands.rs b/src/shorthands.rs index a284aae64..ccbd3ff89 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::path::PathBuf; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use toml::Table; use crate::config::Settings; @@ -35,10 +35,10 @@ pub fn get_shorthands() -> Shorthands { fn parse_shorthands_file(mut f: PathBuf) -> Result { if f.starts_with("~") { - f = dirs::HOME.join(f.strip_prefix("~")?); + f = dirs::HOME.join(f.strip_prefix("~").into_diagnostic()?); } let raw = file::read_to_string(&f)?; - let toml = raw.parse::()?; + let toml = raw.parse::
().into_diagnostic()?; let mut shorthands = HashMap::new(); for (k, v) in toml { diff --git a/src/task.rs b/src/task.rs index 03f965ced..caffffdb6 100644 --- a/src/task.rs +++ b/src/task.rs @@ -6,8 +6,8 @@ use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; use std::path::PathBuf; -use eyre::Result; use itertools::Itertools; +use miette::Result; use crate::config::config_file::toml::TomlParser; use crate::config::Config; @@ -131,7 +131,7 @@ impl Task { None => tasks .get(name) .map(|task| vec![task]) - .ok_or_else(|| eyre!("task not found: {name}")), + .ok_or_else(|| miette!("task not found: {name}")), }) .collect::>>()? .into_iter() diff --git a/src/test.rs b/src/test.rs index 215e37093..84f7e0896 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,4 +1,3 @@ -use color_eyre::{Help, SectionExt}; use std::env::{join_paths, set_current_dir}; use std::path::PathBuf; @@ -90,12 +89,12 @@ pub fn replace_path(input: &str) -> String { .replace(&*env::MISE_BIN.to_string_lossy(), "mise") } -pub fn cli_run(args: &Vec) -> eyre::Result<(String, String)> { +pub fn cli_run(args: &Vec) -> miette::Result<(String, String)> { Config::reset(); *env::ARGS.write().unwrap() = args.clone(); STDOUT.lock().unwrap().clear(); STDERR.lock().unwrap().clear(); - Cli::run(args).with_section(|| format!("{}", args.join(" ").header("Command:")))?; + Cli::run(args)?; //.with_context(|| format!("Command: {}", args.join(" ")))?; let stdout = clean_output(STDOUT.lock().unwrap().join("\n")); let stderr = clean_output(STDERR.lock().unwrap().join("\n")); diff --git a/src/timeout.rs b/src/timeout.rs index a0f2d3c27..f6f902393 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -2,7 +2,7 @@ use std::sync::mpsc; use std::thread; use std::time::Duration; -use color_eyre::eyre::{Context, Result}; +use miette::{IntoDiagnostic, Result}; pub fn run_with_timeout(f: F, timeout: Duration) -> Result where @@ -16,6 +16,7 @@ where // If sending fails, the timeout has already been reached. let _ = tx.send(result); }); - rx.recv_timeout(timeout).context("timed out") - })? + rx.recv_timeout(timeout) //.context("timed out") + }) + .into_diagnostic()? } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index da02c6daf..9d8d90efc 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; -use eyre::Result; use itertools::Itertools; +use miette::Result; use crate::cli::args::tool::ToolArg; use crate::config::{Config, Settings}; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 10e08b567..67f85dd34 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -5,9 +5,9 @@ use std::sync::{Arc, Mutex}; use std::thread; use console::truncate_str; -use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; +use miette::Result; use rayon::prelude::*; pub use builder::ToolsetBuilder; diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 35afe8f6f..bed02feb2 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -5,7 +5,7 @@ use std::fs; use std::hash::{Hash, Hasher}; use std::path::PathBuf; -use eyre::Result; +use miette::{IntoDiagnostic, Result}; use versions::{Chunk, Version}; use crate::config::Config; @@ -227,7 +227,7 @@ impl ToolVersion { path: PathBuf, opts: ToolVersionOptions, ) -> Result { - let path = fs::canonicalize(path)?; + let path = fs::canonicalize(path).into_diagnostic()?; let request = ToolVersionRequest::Path(tool.name().into(), path); let version = request.version(); Ok(Self::new(tool, request, opts, version)) diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 208ceb6d2..32ec51764 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -1,7 +1,7 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use eyre::Result; +use miette::Result; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionOptions}; diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 76da1a9ee..c2bd90670 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,16 +1,18 @@ -use crate::ui; -use demand::Confirm; -use std::io; use std::sync::Mutex; +use demand::Confirm; +use miette::{IntoDiagnostic, Result}; + +use crate::ui; + static MUTEX: Mutex<()> = Mutex::new(()); -pub fn confirm>(message: S) -> io::Result { +pub fn confirm>(message: S) -> Result { let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once ui::handle_ctrlc(); if !console::user_attended_stderr() { return Ok(false); } - Confirm::new(message).run() + Confirm::new(message).run().into_diagnostic() } From 08ab886bd61519e5f1b33680172c667a3537a1f4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:16:35 -0600 Subject: [PATCH 1556/1891] chore: Release mise version 2024.1.8 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c02b996e..afe011dd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.7" +version = "2024.1.8" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 1ef8a13eb..ecde69a94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.7" +version = "2024.1.8" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 283c22747..011427b5b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.7 +mise 2024.1.8 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index cace2878f..e79eb9eb1 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.7"; + version = "2024.1.8"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index c0026ac39..d495a1e4f 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.7" +.TH mise 1 "mise 2024.1.8" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.7 +v2024.1.8 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 9e6ed1615..88e30dde8 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.7 +Version: 2024.1.8 Release: 1 URL: https://github.com/jdx/mise/ Group: System From a8c15bb6e84a6e49e4d7660ac4923d8eeaac76cf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:41:56 -0600 Subject: [PATCH 1557/1891] sort settings --- src/cli/settings/ls.rs | 1 + src/cli/settings/set.rs | 1 + src/cli/settings/unset.rs | 1 + ..._config_file__mise_toml__tests__env-5.snap | 1 + ...fig_file__mise_toml__tests__fixture-2.snap | 39 ++++++----- ...fig_file__mise_toml__tests__fixture-6.snap | 1 + ...g_file__mise_toml__tests__path_dirs-5.snap | 1 + ...ile__mise_toml__tests__remove_alias-4.snap | 1 + ...le__mise_toml__tests__remove_plugin-4.snap | 1 + ..._mise_toml__tests__replace_versions-4.snap | 1 + src/config/settings.rs | 69 ++++++++++--------- 11 files changed, 65 insertions(+), 52 deletions(-) diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 57962d7e0..696aae537 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -46,6 +46,7 @@ mod tests { fn test_settings_ls() { reset_config(); assert_cli_snapshot!("settings", @r###" + all_compile = false always_keep_download = true always_keep_install = true asdf_compat = false diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 8153fa130..737aa057a 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -77,6 +77,7 @@ pub mod tests { ); assert_cli_snapshot!("settings", @r###" + all_compile = false always_keep_download = true always_keep_install = true asdf_compat = false diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 5c449f22e..413cc2881 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -40,6 +40,7 @@ mod tests { let stdout = assert_cli!("settings"); assert_snapshot!(stdout, @r###" + all_compile = false always_keep_download = true always_keep_install = true asdf_compat = false diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap index 23b343fb4..65f7a2791 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap @@ -4,6 +4,7 @@ expression: cf --- MiseToml(/tmp/.mise.toml): { settings: Object { + "all_compile": Null, "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap index 89bacb3ce..2ffc51531 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap @@ -3,34 +3,35 @@ source: src/config/config_file/mise_toml.rs expression: cf.settings().unwrap() --- { - "experimental": null, - "color": null, + "all_compile": null, + "ci": null, "always_keep_download": null, "always_keep_install": null, + "asdf_compat": null, + "cd": null, + "color": null, + "debug": null, + "disable_default_shorthands": null, + "disable_tools": [ + "disabled_tool" + ], + "env_file": null, + "experimental": null, + "jobs": null, "legacy_version_file": null, "legacy_version_file_disable_tools": [ "disabled_tool_from_legacy_file" ], "plugin_autoupdate_last_check_duration": null, - "trusted_config_paths": null, "log_level": null, - "trace": null, - "debug": null, - "verbose": true, - "quiet": null, - "asdf_compat": null, + "not_found_auto_install": null, "paranoid": null, - "jobs": null, - "shorthands_file": null, - "disable_default_shorthands": null, - "disable_tools": [ - "disabled_tool" - ], + "quiet": null, "raw": null, - "yes": null, + "shorthands_file": null, "task_output": null, - "not_found_auto_install": null, - "ci": null, - "env_file": null, - "cd": null + "trace": null, + "trusted_config_paths": null, + "verbose": true, + "yes": null } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap index 161e86539..0917cd09f 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap @@ -4,6 +4,7 @@ expression: "replace_path(&format!(\"{:#?}\", &cf))" --- MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { settings: Object { + "all_compile": Null, "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap index 713de8c83..90edc5205 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap @@ -4,6 +4,7 @@ expression: cf --- MiseToml(~/fixtures/.mise.toml): { settings: Object { + "all_compile": Null, "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index 724762e4c..e676a3a81 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -4,6 +4,7 @@ expression: cf --- MiseToml(/tmp/.mise.toml): { settings: Object { + "all_compile": Null, "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap index 6c065857d..6d1f6e1ff 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap @@ -4,6 +4,7 @@ expression: cf --- MiseToml(/tmp/.mise.toml): { settings: Object { + "all_compile": Null, "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap index c9f2dae62..995c04f58 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap @@ -4,6 +4,7 @@ expression: cf --- MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 { settings: Object { + "all_compile": Null, "always_keep_download": Null, "always_keep_install": Null, "asdf_compat": Null, diff --git a/src/config/settings.rs b/src/config/settings.rs index 5d5564581..6efb65d9e 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -16,57 +16,60 @@ use serde_derive::Serialize; #[derive(Config, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize)))] pub struct Settings { - #[config(env = "MISE_EXPERIMENTAL", default = false)] - pub experimental: bool, - #[config(env = "MISE_COLOR", default = true)] - pub color: bool, + #[config(env = "MISE_ALL_COMPILE", default = false)] + pub all_compile: bool, + #[config(env = "CI", default = false)] + pub ci: bool, #[config(env = "MISE_ALWAYS_KEEP_DOWNLOAD", default = false)] pub always_keep_download: bool, #[config(env = "MISE_ALWAYS_KEEP_INSTALL", default = false)] pub always_keep_install: bool, + #[config(env = "MISE_ASDF_COMPAT", default = false)] + pub asdf_compat: bool, + #[config(env = "MISE_CD")] + pub cd: Option, + #[config(env = "MISE_COLOR", default = true)] + pub color: bool, + #[config(env = "MISE_DEBUG", default = false)] + pub debug: bool, + #[config(env = "MISE_DISABLE_DEFAULT_SHORTHANDS", default = false)] + pub disable_default_shorthands: bool, + #[config(env = "MISE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] + pub disable_tools: BTreeSet, + #[config(env = "MISE_ENV_FILE")] + pub env_file: Option, + #[config(env = "MISE_EXPERIMENTAL", default = false)] + pub experimental: bool, + #[config(env = "MISE_JOBS", default = 4)] + pub jobs: usize, #[config(env = "MISE_LEGACY_VERSION_FILE", default = true)] pub legacy_version_file: bool, #[config(env = "MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, #[config(env = "MISE_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION", default = "7d")] pub plugin_autoupdate_last_check_duration: String, - #[config(env = "MISE_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] - pub trusted_config_paths: BTreeSet, #[config(env = "MISE_LOG_LEVEL", default = "info")] pub log_level: String, - #[config(env = "MISE_TRACE", default = false)] - pub trace: bool, - #[config(env = "MISE_DEBUG", default = false)] - pub debug: bool, - #[config(env = "MISE_VERBOSE", default = false)] - pub verbose: bool, - #[config(env = "MISE_QUIET", default = false)] - pub quiet: bool, - #[config(env = "MISE_ASDF_COMPAT", default = false)] - pub asdf_compat: bool, + #[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)] + pub not_found_auto_install: bool, #[config(env = "MISE_PARANOID", default = false)] pub paranoid: bool, - #[config(env = "MISE_JOBS", default = 4)] - pub jobs: usize, - #[config(env = "MISE_SHORTHANDS_FILE")] - pub shorthands_file: Option, - #[config(env = "MISE_DISABLE_DEFAULT_SHORTHANDS", default = false)] - pub disable_default_shorthands: bool, - #[config(env = "MISE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] - pub disable_tools: BTreeSet, + #[config(env = "MISE_QUIET", default = false)] + pub quiet: bool, #[config(env = "MISE_RAW", default = false)] pub raw: bool, - #[config(env = "MISE_YES", default = false)] - pub yes: bool, + #[config(env = "MISE_SHORTHANDS_FILE")] + pub shorthands_file: Option, #[config(env = "MISE_TASK_OUTPUT")] pub task_output: Option, - #[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)] - pub not_found_auto_install: bool, - #[config(env = "CI", default = false)] - pub ci: bool, - #[config(env = "MISE_ENV_FILE")] - pub env_file: Option, - pub cd: Option, + #[config(env = "MISE_TRACE", default = false)] + pub trace: bool, + #[config(env = "MISE_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] + pub trusted_config_paths: BTreeSet, + #[config(env = "MISE_VERBOSE", default = false)] + pub verbose: bool, + #[config(env = "MISE_YES", default = false)] + pub yes: bool, } pub type SettingsPartial = ::Partial; From 92b51884a522dc7991824594e0228f014c7a1413 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:42:12 -0600 Subject: [PATCH 1558/1891] clean up community-developed plugin warning --- src/plugins/external_plugin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index f690dc370..be59ceb17 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -492,10 +492,10 @@ impl Plugin for ExternalPlugin { let is_trusted = !is_shorthand || TRUSTED_SHORTHANDS.contains(&self.name.as_str()); if !is_trusted { warn!( - "⚠️ {name} is a community-developed plugin: {url}", - name = style(&self.name).blue(), - url = style(url.trim_end_matches(".git")).yellow(), + "⚠️ {} is a community-developed plugin", + style(&self.name).blue(), ); + warn!("url: {}", style(url.trim_end_matches(".git")).yellow(),); if settings.paranoid { bail!("Paranoid mode is enabled, refusing to install community-developed plugin"); } From 176ce0079b4a9a23be8d7aa3dcda38117b4131c2 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 22:34:20 -0800 Subject: [PATCH 1559/1891] use ~/.config/mise/settings.toml (#1386) * use ~/.config/mise/settings.toml * [MegaLinter] Apply linters fixes --------- Co-authored-by: jdx --- Cargo.toml | 8 +- e2e/run_test | 4 +- e2e/test_poetry | 4 - e2e/test_python | 12 +- schema/mise.json | 110 +--------- schema/settings.json | 112 +++++++++++ src/cli/alias/set.rs | 2 +- src/cli/alias/unset.rs | 2 +- src/cli/global.rs | 26 +-- src/cli/settings/ls.rs | 8 +- src/cli/settings/set.rs | 51 +++-- src/cli/settings/unset.rs | 16 +- .../mise__cli__global__tests__global-2.snap | 2 +- .../mise__cli__global__tests__global-3.snap | 2 +- .../mise__cli__global__tests__global-4.snap | 2 +- .../mise__cli__global__tests__global-6.snap | 2 +- .../mise__cli__global__tests__global.snap | 2 +- src/cli/use.rs | 14 +- src/config/config_file/mise_toml.rs | 190 ++---------------- src/config/config_file/mod.rs | 7 +- ..._config_file__mise_toml__tests__env-5.snap | 29 --- ...fig_file__mise_toml__tests__fixture-2.snap | 34 +--- ...fig_file__mise_toml__tests__fixture-3.snap | 123 +++++++++++- ...fig_file__mise_toml__tests__fixture-4.snap | 123 +----------- ...fig_file__mise_toml__tests__fixture-5.snap | 16 +- ...fig_file__mise_toml__tests__fixture-6.snap | 50 ----- ...g_file__mise_toml__tests__path_dirs-5.snap | 29 --- ...ile__mise_toml__tests__remove_alias-4.snap | 29 --- ...le__mise_toml__tests__remove_plugin-4.snap | 32 +-- ..._mise_toml__tests__replace_versions-4.snap | 32 +-- src/config/mod.rs | 61 +++--- src/config/settings.rs | 144 +++++++------ src/env.rs | 21 +- src/errors.rs | 3 +- src/main.rs | 7 +- src/plugins/core/mod.rs | 9 +- src/plugins/core/node.rs | 5 +- src/plugins/external_plugin.rs | 5 + src/shorthands.rs | 26 ++- src/test.rs | 15 +- test/config/config.toml | 8 - test/config/settings.toml | 7 + 42 files changed, 526 insertions(+), 858 deletions(-) create mode 100644 schema/settings.json delete mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap create mode 100644 test/config/settings.toml diff --git a/Cargo.toml b/Cargo.toml index ecde69a94..73552af3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,16 +63,17 @@ indicatif = { version = "0.17", features = ["default", "improved_unicode"] } indoc = "<3" itertools = "0.12" log = "0.4" +miette = { version = "5", features = ["fancy"] } num_cpus = "1" once_cell = "1" openssl = { version = "0.10", optional = true } path-absolutize = "3" +petgraph = "0.6" rand = "0.8" rayon = "1" regex = "1" reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "gzip"] } rmp-serde = "1" -petgraph = "0.6" self_update = { version = "0.39", default-features = false, features = [ "archive-tar", "compression-flate2", @@ -93,13 +94,12 @@ tempfile = "3" tera = { version = "1", default-features = false } terminal_size = "0.3" thiserror = "1" -toml = "0.8" -toml_edit = "0.21" +toml = { version = "0.8", features = ["parse"] } +toml_edit = { version = "0.21", features = ["parse"] } url = "2" versions = "6" which = "5" zip = { version = "0.6", default-features = false, features = ["deflate"] } -miette = { version = "5.10.0", features = ["fancy"] } [target.'cfg(unix)'.dependencies] exec = "0.3" diff --git a/e2e/run_test b/e2e/run_test index d4cbaae9c..9af9c1a8c 100755 --- a/e2e/run_test +++ b/e2e/run_test @@ -15,7 +15,7 @@ setup_env() { export MISE_CONFIG_DIR="$HOME/.mise/e2e/config" export MISE_DEFAULT_TOOL_VERSIONS_FILENAME=.e2e-tool-versions export MISE_DEFAULT_CONFIG_FILENAME=.e2e.mise.toml - export MISE_CONFIG_FILE="$ROOT/e2e/.config/mise/config.toml" + export MISE_GLOBAL_CONFIG_FILE="$ROOT/e2e/.config/mise/config.toml" export MISE_ALWAYS_KEEP_DOWNLOAD="1" export MISE_TRUSTED_CONFIG_PATHS="$ROOT/e2e" export MISE_YES="1" @@ -33,7 +33,7 @@ setup_config_files() { run_test() { echo "::group::E2E $TEST" - rm -f "$MISE_CONFIG_FILE" + rm -f "$MISE_GLOBAL_CONFIG_FILE" cd "$(dirname "$TEST")" START=$(date +%s) diff --git a/e2e/test_poetry b/e2e/test_poetry index f57ab7535..79b0bbc6d 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -3,10 +3,6 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -if [ "${TEST_ALL:-}" != 1 ]; then - exit -fi - rm -rf "$MISE_DATA_DIR/cache/poetry" export POETRY_HOME=".poetry" diff --git a/e2e/test_python b/e2e/test_python index c97269335..73594a27b 100755 --- a/e2e/test_python +++ b/e2e/test_python @@ -3,12 +3,16 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -if [ "${TEST_ALL:-}" != 1 ]; then - exit -fi - export MISE_EXPERIMENTAL=1 export MISE_PYTHON_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-python-packages" mise i python@3.12.0 assert_contains "mise x python@3.12.0 -- python --version" "Python 3.12" + +if [ "${TEST_ALL:-}" != 1 ]; then + exit +fi + +export MISE_ALL_COMPILE=1 +mise i python@3.12.0 -f +assert_contains "mise x python@3.12.0 -- python --version" "Python 3.12" diff --git a/schema/mise.json b/schema/mise.json index 1e2ea568b..7c3d00795 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -11,20 +11,6 @@ "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" }, - "env_file": { - "description": "path to .env file", - "type": "string", - "deprecated": true - }, - "env_path": { - "description": "PATH entries to add", - "type": "array", - "deprecated": true, - "items": { - "description": "a path to add to PATH", - "type": "string" - } - }, "env": { "$ref": "#/$defs/env" }, "tools": { "description": "dev tools to use", @@ -63,8 +49,7 @@ "type": "string" } } - }, - "settings": { "$ref": "#/$defs/settings" } + } }, "$defs": { "env": { @@ -228,99 +213,6 @@ "additionalProperties": false } ] - }, - "settings": { - "description": "settings for mise", - "type": "object", - "additionalProperties": false, - "properties": { - "legacy_version_file": { - "description": "should mise parse legacy version files (e.g. .node-version)", - "type": "boolean" - }, - "legacy_version_file_disable_tools": { - "description": "tools that should not have their legacy version files parsed", - "type": "array", - "items": { - "description": "tool name", - "type": "string" - } - }, - "always_keep_download": { - "description": "should mise keep downloaded files after installation", - "type": "boolean" - }, - "always_keep_install": { - "description": "should mise keep install files after installation even if the installation fails", - "type": "boolean" - }, - "plugin_autoupdate_last_check_duration": { - "oneOf": [ - { - "description": "how often to check for plugin updates", - "type": "string" - }, - { - "description": "how often to check for plugin updates", - "type": "integer" - } - ] - }, - "asdf_compat": { - "description": "set to true to ensure .tool-versions will be compatible with asdf", - "type": "boolean" - }, - "jobs": { - "description": "number of tools to install in parallel, default is 4", - "type": "integer" - }, - "raw": { - "description": "directly connect plugin scripts to stdin/stdout, implies --jobs=1", - "type": "boolean" - }, - "shorthands_file": { - "description": "path to file containing shorthand mappings", - "type": "string" - }, - "disable_default_shorthands": { - "description": "disables built-in shorthands", - "type": "boolean" - }, - "disable_tools": { - "description": "tools that should not be used", - "type": "array", - "items": { - "description": "tool name", - "type": "string" - } - }, - "trusted_config_paths": { - "description": "config files with these prefixes will be trusted by default", - "type": "array", - "items": { - "description": "a path to add to PATH", - "type": "string" - } - }, - "experimental": { - "description": "enable experimental features", - "type": "boolean" - }, - "verbose": { - "description": "display installation output", - "type": "boolean" - }, - "yes": { - "description": "assume yes for all prompts", - "type": "boolean" - }, - "task_output": { - "description": "how to display task output", - "type": "string", - "default": "prefix", - "enum": ["prefix", "interleave"] - } - } } } } diff --git a/schema/settings.json b/schema/settings.json new file mode 100644 index 000000000..43f725310 --- /dev/null +++ b/schema/settings.json @@ -0,0 +1,112 @@ +{ + "$id": "https://mise.jdx.dev/schema/settings.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "mise settings schema", + "description": "settings file for mise-en-place (~/.config/mise/settings.toml)", + "type": "object", + "additionalProperties": false, + "properties": { + "all_compile": { + "description": "do not use precompiled binaries for any tool", + "type": "boolean" + }, + "always_keep_download": { + "description": "should mise keep downloaded files after installation", + "type": "boolean" + }, + "always_keep_install": { + "description": "should mise keep install files after installation even if the installation fails", + "type": "boolean" + }, + "asdf_compat": { + "description": "set to true to ensure .tool-versions will be compatible with asdf", + "type": "boolean" + }, + "color": { + "description": "colorize output", + "type": "boolean" + }, + "disable_default_shorthands": { + "description": "disables built-in shorthands", + "type": "boolean" + }, + "disable_tools": { + "description": "tools that should not be used", + "items": { + "description": "tool name", + "type": "string" + }, + "type": "array" + }, + "experimental": { + "description": "enable experimental features", + "type": "boolean" + }, + "jobs": { + "description": "number of tools to install in parallel, default is 4", + "type": "integer" + }, + "legacy_version_file": { + "description": "should mise parse legacy version files (e.g. .node-version)", + "type": "boolean" + }, + "legacy_version_file_disable_tools": { + "description": "tools that should not have their legacy version files parsed", + "items": { + "description": "tool name", + "type": "string" + }, + "type": "array" + }, + "node_compile": { + "description": "do not use precompiled binaries for node", + "type": "boolean" + }, + "not_found_auto_install": { + "description": "adds a shell hook to `mise activate` and shims to automatically install tools when they need to be installed", + "type": "boolean" + }, + "paranoid": { + "description": "extra-security mode, see https://mise.jdx.dev/paranoid.html for details", + "type": "boolean" + }, + "plugin_autoupdate_last_check_duration": { + "description": "how often to check for plugin updates", + "type": "string" + }, + "raw": { + "description": "directly connect plugin scripts to stdin/stdout, implies --jobs=1", + "type": "boolean" + }, + "shorthands_file": { + "description": "path to file containing shorthand mappings", + "type": "string" + }, + "task_output": { + "default": "prefix", + "description": "how to display task output", + "enum": ["prefix", "interleave"], + "type": "string" + }, + "trusted_config_paths": { + "description": "config files with these prefixes will be trusted by default", + "items": { + "description": "a path to add to PATH", + "type": "string" + }, + "type": "array" + }, + "quiet": { + "description": "suppress all non-error output", + "type": "boolean" + }, + "verbose": { + "description": "display extra output", + "type": "boolean" + }, + "yes": { + "description": "assume yes for all prompts", + "type": "boolean" + } + } +} diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 297c6e015..ecffd422a 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -19,7 +19,7 @@ pub struct AliasSet { impl AliasSet { pub fn run(self) -> Result<()> { - let mut global_config = Config::get().global_config.clone(); + let mut global_config = Config::get().global_config()?; global_config.set_alias(&self.plugin, &self.alias, &self.value); global_config.save() } diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 3441d9e6d..236581b73 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -17,7 +17,7 @@ pub struct AliasUnset { impl AliasUnset { pub fn run(self) -> Result<()> { - let mut global_config = Config::get().global_config.clone(); + let mut global_config = Config::get().global_config()?; global_config.remove_alias(&self.plugin, &self.alias); global_config.save() } diff --git a/src/cli/global.rs b/src/cli/global.rs index eea1db00a..93d853843 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,20 +1,17 @@ -use std::path::PathBuf; - use miette::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::cli::local::local; use crate::config::Config; +use crate::env; use crate::plugins::PluginName; -use crate::{dirs, env}; /// Sets/gets the global tool version(s) /// /// Displays the contents of ~/.tool-versions after writing. -/// The file is `$HOME/.tool-versions` by default. It can be changed with `$MISE_CONFIG_FILE`. -/// If `$MISE_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.mise.toml`. +/// The file is `$HOME/.config/mise/config.toml` by default. It can be changed with `$MISE_GLOBAL_CONFIG_FILE`. +/// If `$MISE_GLOBAL_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.mise.toml`. /// Otherwise, it will be parsed as a `.tool-versions` file. -/// A future v2 release of mise will default to using `~/.config/mise/config.toml` instead. /// /// Use `mise local` to set a tool version locally in the current directory. #[derive(Debug, clap::Args)] @@ -52,7 +49,7 @@ impl Global { let config = Config::try_get()?; local( &config, - &global_file(), + &env::MISE_GLOBAL_CONFIG_FILE, self.tool, self.remove, self.pin, @@ -62,16 +59,6 @@ impl Global { } } -fn global_file() -> PathBuf { - env::MISE_CONFIG_FILE.clone().unwrap_or_else(|| { - if *env::MISE_USE_TOML { - dirs::CONFIG.join("config.toml") - } else { - dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()) - } - }) -} - static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: # set the current version of node to 20.x @@ -90,9 +77,10 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::{dirs, file}; use pretty_assertions::assert_str_eq; + use crate::{dirs, file}; + #[test] fn test_global() { let cf_path = dirs::HOME.join(".test-tool-versions"); @@ -112,7 +100,7 @@ mod tests { let err = assert_cli_err!("global", "invalid-plugin"); assert_str_eq!( err.to_string(), - "no version set for invalid-plugin in ~/.test-tool-versions" + "no version set for invalid-plugin in ~/config/config.toml" ); // can only request a version one plugin at a time diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 696aae537..4d52bea49 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,8 +1,9 @@ +use std::collections::BTreeMap; + use miette::{IntoDiagnostic, Result}; use serde_json::Value; -use std::collections::BTreeMap; -use crate::config::{Config, Settings}; +use crate::config::Settings; /// Show current settings /// @@ -16,7 +17,6 @@ pub struct SettingsLs {} impl SettingsLs { pub fn run(self) -> Result<()> { - Config::try_get()?; let settings = Settings::try_get()?; let json = settings.to_string(); let doc: BTreeMap = serde_json::from_str(&json).into_diagnostic()?; @@ -39,7 +39,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::test::reset_config; #[test] @@ -57,6 +56,7 @@ mod tests { jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] + node_compile = false not_found_auto_install = true paranoid = false plugin_autoupdate_last_check_duration = "20m" diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 737aa057a..4582f8f0e 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,7 +1,7 @@ -use miette::Result; +use miette::{IntoDiagnostic, Result}; +use toml_edit::Document; -use crate::config::config_file::ConfigFile; -use crate::config::Config; +use crate::{env, file}; /// Add/update a setting /// @@ -33,16 +33,30 @@ impl SettingsSet { _ => return Err(miette!("Unknown setting: {}", self.setting)), }; - let mut global_config = Config::try_get()?.global_config.clone(); - global_config.update_setting(&self.setting, value); - global_config.save() + let path = &*env::MISE_SETTINGS_FILE; + file::create_dir_all(path.parent().unwrap())?; + let mut new_file = false; + if !path.exists() { + file::write(path, "")?; + new_file = true; + } + let raw = file::read_to_string(path)?; + let mut settings: Document = raw.parse().into_diagnostic()?; + settings.insert(&self.setting, toml_edit::Item::Value(value)); + if new_file { + settings + .key_decor_mut(&self.setting) + .unwrap() + .set_prefix("#:schema https://mise.jdx.dev/schema/settings.json\n"); + } + file::write(path, settings.to_string()) } } fn parse_bool(value: &str) -> Result { - match value { - "true" => Ok(true.into()), - "false" => Ok(false.into()), + match value.to_lowercase().as_str() { + "1" | "true" | "yes" | "y" => Ok(true.into()), + "0" | "false" | "no" | "n" => Ok(false.into()), _ => Err(miette!("{} must be true or false", value)), } } @@ -67,8 +81,8 @@ pub mod tests { #[test] fn test_settings_set() { reset_config(); - assert_cli!("settings", "set", "legacy_version_file", "false"); - assert_cli!("settings", "set", "always_keep_download", "true"); + assert_cli!("settings", "set", "legacy_version_file", "0"); + assert_cli!("settings", "set", "always_keep_download", "y"); assert_cli!( "settings", "set", @@ -78,25 +92,26 @@ pub mod tests { assert_cli_snapshot!("settings", @r###" all_compile = false - always_keep_download = true - always_keep_install = true + always_keep_download = false + always_keep_install = false asdf_compat = false color = true disable_default_shorthands = false disable_tools = [] - experimental = true - jobs = 2 - legacy_version_file = false + experimental = false + jobs = 4 + legacy_version_file = true legacy_version_file_disable_tools = [] + node_compile = false not_found_auto_install = true paranoid = false - plugin_autoupdate_last_check_duration = "1m" + plugin_autoupdate_last_check_duration = "7d" quiet = false raw = false shorthands_file = null task_output = null trusted_config_paths = [] - verbose = true + verbose = false yes = true "###); reset_config(); diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 413cc2881..8eb60bca8 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -1,7 +1,7 @@ -use miette::Result; +use miette::{IntoDiagnostic, Result}; +use toml_edit::Document; -use crate::config::config_file::ConfigFile; -use crate::config::Config; +use crate::{env, file}; /// Clears a setting /// @@ -15,9 +15,11 @@ pub struct SettingsUnset { impl SettingsUnset { pub fn run(self) -> Result<()> { - let mut global_config = Config::try_get()?.global_config.clone(); - global_config.remove_setting(&self.setting); - global_config.save() + let path = env::MISE_CONFIG_DIR.join("config.toml"); + let raw = file::read_to_string(&path)?; + let mut settings: Document = raw.parse().into_diagnostic()?; + settings.remove(&self.setting); + file::write(&path, settings.to_string()) } } @@ -29,7 +31,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use crate::test::reset_config; #[test] @@ -51,6 +52,7 @@ mod tests { jobs = 2 legacy_version_file = true legacy_version_file_disable_tools = [] + node_compile = false not_found_auto_install = true paranoid = false plugin_autoupdate_last_check_duration = "20m" diff --git a/src/cli/snapshots/mise__cli__global__tests__global-2.snap b/src/cli/snapshots/mise__cli__global__tests__global-2.snap index 3d8e6f6c8..01bbdf0df 100644 --- a/src/cli/snapshots/mise__cli__global__tests__global-2.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global-2.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -mise ~/.test-tool-versions tiny@2 +mise ~/config/config.toml tiny@2 diff --git a/src/cli/snapshots/mise__cli__global__tests__global-3.snap b/src/cli/snapshots/mise__cli__global__tests__global-3.snap index 2659835cf..f24078068 100644 --- a/src/cli/snapshots/mise__cli__global__tests__global-3.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global-3.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -mise ~/.test-tool-versions tiny +mise ~/config/config.toml tiny diff --git a/src/cli/snapshots/mise__cli__global__tests__global-4.snap b/src/cli/snapshots/mise__cli__global__tests__global-4.snap index 3d8e6f6c8..01bbdf0df 100644 --- a/src/cli/snapshots/mise__cli__global__tests__global-4.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global-4.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -mise ~/.test-tool-versions tiny@2 +mise ~/config/config.toml tiny@2 diff --git a/src/cli/snapshots/mise__cli__global__tests__global-6.snap b/src/cli/snapshots/mise__cli__global__tests__global-6.snap index 7feec566a..69d01e86e 100644 --- a/src/cli/snapshots/mise__cli__global__tests__global-6.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global-6.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -~/.test-tool-versions +~/config/config.toml diff --git a/src/cli/snapshots/mise__cli__global__tests__global.snap b/src/cli/snapshots/mise__cli__global__tests__global.snap index 3d8e6f6c8..01bbdf0df 100644 --- a/src/cli/snapshots/mise__cli__global__tests__global.snap +++ b/src/cli/snapshots/mise__cli__global__tests__global.snap @@ -2,4 +2,4 @@ source: src/cli/global.rs expression: output --- -mise ~/.test-tool-versions tiny@2 +mise ~/config/config.toml tiny@2 diff --git a/src/cli/use.rs b/src/cli/use.rs index 9c7090508..3f9a4be27 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -7,12 +7,14 @@ use miette::{IntoDiagnostic, Result}; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config, Settings}; -use crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME}; +use crate::env::{ + MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME, MISE_GLOBAL_CONFIG_FILE, +}; use crate::file::display_path; use crate::plugins::PluginName; use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::{dirs, env, file}; +use crate::{env, file}; /// Change the active version of a tool locally or globally. /// @@ -133,7 +135,7 @@ impl Use { fn get_config_file(&self) -> Result> { let path = if self.global { - global_file() + MISE_GLOBAL_CONFIG_FILE.clone() } else if let Some(env) = &self.env { config_file_from_dir( &env::current_dir() @@ -178,12 +180,6 @@ impl Use { } } -fn global_file() -> PathBuf { - env::MISE_CONFIG_FILE - .clone() - .unwrap_or_else(|| dirs::CONFIG.join("config.toml")) -} - fn config_file_from_dir(p: &Path) -> PathBuf { if !p.is_dir() { return p.to_path_buf(); diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index dfc37a58f..5a40ceaf8 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -4,13 +4,12 @@ use std::iter::once; use std::path::{Path, PathBuf}; use std::sync::Mutex; -use confique::Partial; use miette::{IntoDiagnostic, Result, WrapErr}; +use serde_derive::Deserialize; use tera::Context as TeraContext; -use toml_edit::{table, value, Array, Document, Item, Table, Value}; +use toml_edit::{table, value, Array, Document, Item, Value}; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; -use crate::config::settings::SettingsPartial; use crate::config::AliasMap; use crate::file::{create_dir_all, display_path}; use crate::plugins::{unalias_plugin, PluginName}; @@ -20,22 +19,33 @@ use crate::toolset::{ ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, }; use crate::ui::style; -use crate::{dirs, file, parse_error}; +use crate::{dirs, env, file, parse_error, ui}; -#[derive(Default)] +#[derive(Default, Deserialize)] pub struct MiseToml { + #[serde(skip)] context: TeraContext, + #[serde(skip)] path: PathBuf, + #[serde(skip)] toolset: Toolset, + #[serde(skip)] env_files: Vec, + #[serde(skip)] env: HashMap, + #[serde(skip)] env_remove: Vec, + #[serde(skip)] path_dirs: Vec, - settings: Table, + #[serde(skip)] alias: AliasMap, + #[serde(skip)] doc: Document, + #[serde(skip)] plugins: HashMap, + #[serde(skip)] tasks: Vec, + #[serde(skip)] is_trusted: Mutex>, } @@ -74,7 +84,12 @@ impl MiseToml { "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, - "settings" => self.settings = self.parse_settings(k, v)?, + "settings" => { + let old = ui::style::eyellow(display_path(&self.path)); + let new = ui::style::eyellow(display_path(&env::MISE_GLOBAL_CONFIG_FILE)); + warn!("[settings] inside of {old} is deprecated. A separate {new} file should be used instead."); + warn!("Removing the [settings] section from {old} will remove this warning",); + } "plugins" => self.plugins = self.parse_plugins(k, v)?, "tasks" => self.tasks = self.parse_tasks(k, v)?, _ => bail!("unknown key: {}", style::ered(k)), @@ -450,13 +465,6 @@ impl MiseToml { } } - fn parse_settings(&self, _k: &str, v: &Item) -> Result
{ - match v.as_table() { - Some(table) => Ok(table.clone()), - None => parse_error!("settings", v, "table"), - } - } - pub fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { self.alias .entry(plugin.into()) @@ -504,13 +512,6 @@ impl MiseToml { } } - fn parse_usize(&self, k: &str, v: &Item) -> Result { - match v.as_value().map(|v| v.as_integer()) { - Some(Some(v)) => Ok(v as usize), - _ => parse_error!(k, v, "usize"), - } - } - fn parse_path(&self, k: &str, v: &Item) -> Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => { @@ -521,26 +522,6 @@ impl MiseToml { } } - fn parse_paths(&self, k: &str, v: &Item) -> Result> { - match v.as_value().map(|v| v.as_array()) { - Some(Some(v)) => { - let mut paths = vec![]; - for (i, v) in v.iter().enumerate() { - let k = format!("{}.{}", k, i); - match v.as_str() { - Some(v) => { - let v = self.parse_template(&k, v)?; - paths.push(v.into()); - } - _ => parse_error!(k, v, "path"), - } - } - Ok(paths) - } - _ => parse_error!(k, v, "array of paths"), - } - } - fn parse_string_or_array(&self, k: &str, v: &Item) -> Result> { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => { @@ -561,53 +542,6 @@ impl MiseToml { } } - pub fn update_setting>(&mut self, key: &str, value: V) { - let key = key.split('.').collect::>(); - let mut settings = self - .doc - .entry("settings") - .or_insert_with(table) - .as_table_like_mut() - .unwrap(); - for (i, k) in key.iter().enumerate() { - if i == key.len() - 1 { - settings.insert(k, toml_edit::value(value)); - break; - } else { - settings = settings - .entry(k) - .or_insert(toml_edit::table()) - .as_table_mut() - .unwrap(); - } - } - } - - pub fn remove_setting(&mut self, key: &str) { - let mut settings = self - .doc - .entry("settings") - .or_insert_with(table) - .as_table_like_mut() - .unwrap(); - let key = key.split('.').collect::>(); - for (i, k) in key.iter().enumerate() { - if i == key.len() - 1 { - settings.remove(k); - break; - } else { - settings = settings - .entry(k) - .or_insert(toml_edit::table()) - .as_table_mut() - .unwrap(); - } - } - if settings.is_empty() { - self.doc.as_table_mut().remove("settings"); - } - } - pub fn update_env>(&mut self, key: &str, value: V) { let env_tbl = self .doc @@ -747,48 +681,6 @@ impl ConfigFile for MiseToml { &self.toolset } - fn settings(&self) -> Result { - let mut s = SettingsPartial::empty(); - - for (config_key, v) in self.settings.iter() { - let k = format!("settings.{config_key}"); - match config_key.to_lowercase().as_str() { - "experimental" => s.experimental = Some(self.parse_bool(&k, v)?), - "legacy_version_file" => s.legacy_version_file = Some(self.parse_bool(&k, v)?), - "legacy_version_file_disable_tools" => { - s.legacy_version_file_disable_tools = - Some(self.parse_string_array(&k, v)?.into_iter().collect()) - } - "always_keep_download" => s.always_keep_download = Some(self.parse_bool(&k, v)?), - "always_keep_install" => s.always_keep_install = Some(self.parse_bool(&k, v)?), - "plugin_autoupdate_last_check_duration" => { - s.plugin_autoupdate_last_check_duration = match v.as_integer() { - Some(i) => Some(format!("{}m", i)), - None => Some(self.parse_string(&k, v)?), - } - } - "trusted_config_paths" => { - s.trusted_config_paths = Some(self.parse_paths(&k, v)?.into_iter().collect()); - } - "verbose" => s.verbose = Some(self.parse_bool(&k, v)?), - "asdf_compat" => s.asdf_compat = Some(self.parse_bool(&k, v)?), - "jobs" => s.jobs = Some(self.parse_usize(&k, v)?), - "shorthands_file" => s.shorthands_file = Some(self.parse_path(&k, v)?), - "disable_default_shorthands" => { - s.disable_default_shorthands = Some(self.parse_bool(&k, v)?) - } - "disable_tools" => { - s.disable_tools = Some(self.parse_string_array(&k, v)?.into_iter().collect()); - } - "raw" => s.raw = Some(self.parse_bool(&k, v)?), - "yes" => s.yes = Some(self.parse_bool(&k, v)?), - _ => Err(miette!("Unknown config setting: {}", k))?, - }; - } - - Ok(s) - } - fn aliases(&self) -> AliasMap { self.alias.clone() } @@ -807,10 +699,6 @@ impl Debug for MiseToml { let title = format!("MiseToml({}): {tools}", &display_path(&self.path)); let mut d = f.debug_struct(&title); // d.field("is_trusted", &self.is_trusted); - if let Ok(settings) = self.settings() { - let json = serde_json::to_value(settings).unwrap_or_default(); - d.field("settings", &json); - } if !self.env_files.is_empty() { d.field("env_files", &self.env_files); } @@ -843,7 +731,6 @@ impl Clone for MiseToml { env: self.env.clone(), env_remove: self.env_remove.clone(), path_dirs: self.path_dirs.clone(), - settings: self.settings.clone(), alias: self.alias.clone(), doc: self.doc.clone(), plugins: self.plugins.clone(), @@ -865,7 +752,6 @@ mod tests { let cf = MiseToml::from_file(&dirs::HOME.join("fixtures/.mise.toml")).unwrap(); assert_debug_snapshot!(cf.env()); - assert_json_snapshot!(cf.settings().unwrap()); assert_debug_snapshot!(cf.plugins()); assert_snapshot!(replace_path(&format!("{:#?}", cf.toolset))); assert_debug_snapshot!(cf.alias); @@ -999,38 +885,6 @@ mod tests { assert_debug_snapshot!(cf); } - #[test] - fn test_update_setting() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" - [settings] - legacy_version_file = true - [alias.node] - 18 = "18.0.0" - "#}) - .unwrap(); - cf.update_setting("legacy_version_file", false); - assert_display_snapshot!(cf.dump(), @r###" - [settings] - legacy_version_file = false - [alias.node] - 18 = "18.0.0" - "###); - } - - #[test] - fn test_remove_setting() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" - [settings] - legacy_version_file = true - "#}) - .unwrap(); - cf.remove_setting("legacy_version_file"); - assert_display_snapshot!(cf.dump(), @r###" - "###); - } - #[test] fn test_fail_with_unknown_key() { let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 54a0d2472..11ce7a029 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -5,7 +5,6 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; use std::sync::Mutex; -use confique::Partial; use miette::{IntoDiagnostic, Result}; use once_cell::sync::Lazy; @@ -13,7 +12,6 @@ use tool_versions::ToolVersions; use crate::cli::args::tool::ToolArg; use crate::config::config_file::mise_toml::MiseToml; -use crate::config::settings::SettingsPartial; use crate::config::{global_config_files, system_config_files, AliasMap, Config, Settings}; use crate::errors::Error::UntrustedConfig; use crate::file::display_path; @@ -45,7 +43,7 @@ pub trait ConfigFile: Debug + Send + Sync { /// and ~/src/foo/.mise.config.toml will return None fn project_root(&self) -> Option<&Path> { let p = self.get_path(); - if env::MISE_CONFIG_FILE.as_ref().is_some_and(|f| f == p) { + if *env::MISE_GLOBAL_CONFIG_FILE == p { return None; } match p.parent() { @@ -78,9 +76,6 @@ pub trait ConfigFile: Debug + Send + Sync { fn save(&self) -> Result<()>; fn dump(&self) -> String; fn to_toolset(&self) -> &Toolset; - fn settings(&self) -> Result { - Ok(SettingsPartial::empty()) - } fn aliases(&self) -> AliasMap { Default::default() } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap index 65f7a2791..239b473b9 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap @@ -3,35 +3,6 @@ source: src/config/config_file/mise_toml.rs expression: cf --- MiseToml(/tmp/.mise.toml): { - settings: Object { - "all_compile": Null, - "always_keep_download": Null, - "always_keep_install": Null, - "asdf_compat": Null, - "cd": Null, - "ci": Null, - "color": Null, - "debug": Null, - "disable_default_shorthands": Null, - "disable_tools": Null, - "env_file": Null, - "experimental": Null, - "jobs": Null, - "legacy_version_file": Null, - "legacy_version_file_disable_tools": Null, - "log_level": Null, - "not_found_auto_install": Null, - "paranoid": Null, - "plugin_autoupdate_last_check_duration": Null, - "quiet": Null, - "raw": Null, - "shorthands_file": Null, - "task_output": Null, - "trace": Null, - "trusted_config_paths": Null, - "verbose": Null, - "yes": Null, - }, env: { "foo": "bar", }, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap index 2ffc51531..147d72fb7 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-2.snap @@ -1,37 +1,7 @@ --- source: src/config/config_file/mise_toml.rs -expression: cf.settings().unwrap() +expression: cf.plugins() --- { - "all_compile": null, - "ci": null, - "always_keep_download": null, - "always_keep_install": null, - "asdf_compat": null, - "cd": null, - "color": null, - "debug": null, - "disable_default_shorthands": null, - "disable_tools": [ - "disabled_tool" - ], - "env_file": null, - "experimental": null, - "jobs": null, - "legacy_version_file": null, - "legacy_version_file_disable_tools": [ - "disabled_tool_from_legacy_file" - ], - "plugin_autoupdate_last_check_duration": null, - "log_level": null, - "not_found_auto_install": null, - "paranoid": null, - "quiet": null, - "raw": null, - "shorthands_file": null, - "task_output": null, - "trace": null, - "trusted_config_paths": null, - "verbose": true, - "yes": null + "node": "https://github.com/jdx/rtx-node", } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap index 147d72fb7..a4d76e4fa 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap @@ -1,7 +1,124 @@ --- source: src/config/config_file/mise_toml.rs -expression: cf.plugins() +expression: "replace_path(&format!(\"{:#?}\", cf.toolset))" --- -{ - "node": "https://github.com/jdx/rtx-node", +Toolset { + versions: { + "terraform": ToolVersionList { + plugin_name: "terraform", + versions: [], + requests: [ + ( + Version( + "terraform", + "1.0.0", + ), + {}, + ), + ], + source: MiseToml( + "~/fixtures/.mise.toml", + ), + }, + "node": ToolVersionList { + plugin_name: "node", + versions: [], + requests: [ + ( + Version( + "node", + "18", + ), + {}, + ), + ( + Prefix( + "node", + "20", + ), + {}, + ), + ( + Ref( + "node", + "master", + ), + {}, + ), + ( + Path( + "node", + "~/.nodes/18", + ), + {}, + ), + ], + source: MiseToml( + "~/fixtures/.mise.toml", + ), + }, + "jq": ToolVersionList { + plugin_name: "jq", + versions: [], + requests: [ + ( + Prefix( + "jq", + "1.6", + ), + {}, + ), + ], + source: MiseToml( + "~/fixtures/.mise.toml", + ), + }, + "shellcheck": ToolVersionList { + plugin_name: "shellcheck", + versions: [], + requests: [ + ( + Version( + "shellcheck", + "0.9.0", + ), + {}, + ), + ], + source: MiseToml( + "~/fixtures/.mise.toml", + ), + }, + "python": ToolVersionList { + plugin_name: "python", + versions: [], + requests: [ + ( + Version( + "python", + "3.10.0", + ), + { + "venv": ".venv", + }, + ), + ( + Version( + "python", + "3.9.0", + ), + {}, + ), + ], + source: MiseToml( + "~/fixtures/.mise.toml", + ), + }, + }, + source: Some( + MiseToml( + "~/fixtures/.mise.toml", + ), + ), + disable_tools: {}, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap index a4d76e4fa..149ac517c 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap @@ -1,124 +1,9 @@ --- source: src/config/config_file/mise_toml.rs -expression: "replace_path(&format!(\"{:#?}\", cf.toolset))" +expression: cf.alias --- -Toolset { - versions: { - "terraform": ToolVersionList { - plugin_name: "terraform", - versions: [], - requests: [ - ( - Version( - "terraform", - "1.0.0", - ), - {}, - ), - ], - source: MiseToml( - "~/fixtures/.mise.toml", - ), - }, - "node": ToolVersionList { - plugin_name: "node", - versions: [], - requests: [ - ( - Version( - "node", - "18", - ), - {}, - ), - ( - Prefix( - "node", - "20", - ), - {}, - ), - ( - Ref( - "node", - "master", - ), - {}, - ), - ( - Path( - "node", - "~/.nodes/18", - ), - {}, - ), - ], - source: MiseToml( - "~/fixtures/.mise.toml", - ), - }, - "jq": ToolVersionList { - plugin_name: "jq", - versions: [], - requests: [ - ( - Prefix( - "jq", - "1.6", - ), - {}, - ), - ], - source: MiseToml( - "~/fixtures/.mise.toml", - ), - }, - "shellcheck": ToolVersionList { - plugin_name: "shellcheck", - versions: [], - requests: [ - ( - Version( - "shellcheck", - "0.9.0", - ), - {}, - ), - ], - source: MiseToml( - "~/fixtures/.mise.toml", - ), - }, - "python": ToolVersionList { - plugin_name: "python", - versions: [], - requests: [ - ( - Version( - "python", - "3.10.0", - ), - { - "venv": ".venv", - }, - ), - ( - Version( - "python", - "3.9.0", - ), - {}, - ), - ], - source: MiseToml( - "~/fixtures/.mise.toml", - ), - }, +{ + "node": { + "my_custom_node": "18", }, - source: Some( - MiseToml( - "~/fixtures/.mise.toml", - ), - ), - disable_tools: {}, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap index 149ac517c..2a51d0482 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap @@ -1,9 +1,17 @@ --- source: src/config/config_file/mise_toml.rs -expression: cf.alias +expression: "replace_path(&format!(\"{:#?}\", &cf))" --- -{ - "node": { - "my_custom_node": "18", +MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { + env: { + "NODE_ENV": "production", + }, + alias: { + "node": { + "my_custom_node": "18", + }, + }, + plugins: { + "node": "https://github.com/jdx/rtx-node", }, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap deleted file mode 100644 index 0917cd09f..000000000 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-6.snap +++ /dev/null @@ -1,50 +0,0 @@ ---- -source: src/config/config_file/mise_toml.rs -expression: "replace_path(&format!(\"{:#?}\", &cf))" ---- -MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { - settings: Object { - "all_compile": Null, - "always_keep_download": Null, - "always_keep_install": Null, - "asdf_compat": Null, - "cd": Null, - "ci": Null, - "color": Null, - "debug": Null, - "disable_default_shorthands": Null, - "disable_tools": Array [ - String("disabled_tool"), - ], - "env_file": Null, - "experimental": Null, - "jobs": Null, - "legacy_version_file": Null, - "legacy_version_file_disable_tools": Array [ - String("disabled_tool_from_legacy_file"), - ], - "log_level": Null, - "not_found_auto_install": Null, - "paranoid": Null, - "plugin_autoupdate_last_check_duration": Null, - "quiet": Null, - "raw": Null, - "shorthands_file": Null, - "task_output": Null, - "trace": Null, - "trusted_config_paths": Null, - "verbose": Bool(true), - "yes": Null, - }, - env: { - "NODE_ENV": "production", - }, - alias: { - "node": { - "my_custom_node": "18", - }, - }, - plugins: { - "node": "https://github.com/jdx/rtx-node", - }, -} diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap index 90edc5205..7216a2ba0 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap @@ -3,35 +3,6 @@ source: src/config/config_file/mise_toml.rs expression: cf --- MiseToml(~/fixtures/.mise.toml): { - settings: Object { - "all_compile": Null, - "always_keep_download": Null, - "always_keep_install": Null, - "asdf_compat": Null, - "cd": Null, - "ci": Null, - "color": Null, - "debug": Null, - "disable_default_shorthands": Null, - "disable_tools": Null, - "env_file": Null, - "experimental": Null, - "jobs": Null, - "legacy_version_file": Null, - "legacy_version_file_disable_tools": Null, - "log_level": Null, - "not_found_auto_install": Null, - "paranoid": Null, - "plugin_autoupdate_last_check_duration": Null, - "quiet": Null, - "raw": Null, - "shorthands_file": Null, - "task_output": Null, - "trace": Null, - "trusted_config_paths": Null, - "verbose": Null, - "yes": Null, - }, env: { "foo": "bar", }, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index e676a3a81..bd7599633 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -3,35 +3,6 @@ source: src/config/config_file/mise_toml.rs expression: cf --- MiseToml(/tmp/.mise.toml): { - settings: Object { - "all_compile": Null, - "always_keep_download": Null, - "always_keep_install": Null, - "asdf_compat": Null, - "cd": Null, - "ci": Null, - "color": Null, - "debug": Null, - "disable_default_shorthands": Null, - "disable_tools": Null, - "env_file": Null, - "experimental": Null, - "jobs": Null, - "legacy_version_file": Null, - "legacy_version_file_disable_tools": Null, - "log_level": Null, - "not_found_auto_install": Null, - "paranoid": Null, - "plugin_autoupdate_last_check_duration": Null, - "quiet": Null, - "raw": Null, - "shorthands_file": Null, - "task_output": Null, - "trace": Null, - "trusted_config_paths": Null, - "verbose": Null, - "yes": Null, - }, alias: { "node": { "18": "18.0.0", diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap index 6d1f6e1ff..11ebdc792 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap @@ -2,34 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): { - settings: Object { - "all_compile": Null, - "always_keep_download": Null, - "always_keep_install": Null, - "asdf_compat": Null, - "cd": Null, - "ci": Null, - "color": Null, - "debug": Null, - "disable_default_shorthands": Null, - "disable_tools": Null, - "env_file": Null, - "experimental": Null, - "jobs": Null, - "legacy_version_file": Null, - "legacy_version_file_disable_tools": Null, - "log_level": Null, - "not_found_auto_install": Null, - "paranoid": Null, - "plugin_autoupdate_last_check_duration": Null, - "quiet": Null, - "raw": Null, - "shorthands_file": Null, - "task_output": Null, - "trace": Null, - "trusted_config_paths": Null, - "verbose": Null, - "yes": Null, - }, -} +MiseToml(/tmp/.mise.toml): diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap index 995c04f58..f68cdeb00 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap @@ -2,34 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 { - settings: Object { - "all_compile": Null, - "always_keep_download": Null, - "always_keep_install": Null, - "asdf_compat": Null, - "cd": Null, - "ci": Null, - "color": Null, - "debug": Null, - "disable_default_shorthands": Null, - "disable_tools": Null, - "env_file": Null, - "experimental": Null, - "jobs": Null, - "legacy_version_file": Null, - "legacy_version_file_disable_tools": Null, - "log_level": Null, - "not_found_auto_install": Null, - "paranoid": Null, - "plugin_autoupdate_last_check_duration": Null, - "quiet": Null, - "raw": Null, - "shorthands_file": Null, - "task_output": Null, - "trace": Null, - "trusted_config_paths": Null, - "verbose": Null, - "yes": Null, - }, -} +MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 diff --git a/src/config/mod.rs b/src/config/mod.rs index c2b2c17a7..4994ae83f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -40,7 +40,6 @@ pub struct Config { pub config_files: ConfigMap, pub env: BTreeMap, pub env_sources: HashMap, - pub global_config: MiseToml, pub path_dirs: Vec, pub project_root: Option, all_aliases: OnceCell, @@ -65,9 +64,6 @@ impl Config { Ok(config) } pub fn load() -> Result { - let global_config = load_miserc()?; - // TODO: read system config settings - Settings::add_partial(global_config.settings()?); let settings = Settings::try_get()?; trace!("Settings: {:#?}", settings); @@ -94,7 +90,6 @@ impl Config { tasks: OnceCell::new(), project_root: get_project_root(&config_files), config_files, - global_config, plugins: RwLock::new(plugins), repo_urls, }; @@ -104,7 +99,8 @@ impl Config { Ok(config) } pub fn get_shorthands(&self) -> &Shorthands { - self.shorthands.get_or_init(get_shorthands) + self.shorthands + .get_or_init(|| get_shorthands(&Settings::get())) } pub fn get_repo_url(&self, plugin_name: &PluginName) -> Option { @@ -267,9 +263,21 @@ impl Config { Ok(()) } + pub fn global_config(&self) -> Result { + let settings_path = env::MISE_GLOBAL_CONFIG_FILE.to_path_buf(); + match settings_path.exists() { + false => { + trace!("settings does not exist {:?}", settings_path); + Ok(MiseToml::init(&settings_path)) + } + true => MiseToml::from_file(&settings_path) + .wrap_err_with(|| miette!("Error parsing {}", display_path(&settings_path))), + } + } + #[cfg(test)] pub fn reset() { - Settings::reset(); + Settings::reset(None); CONFIG.write().unwrap().take(); } } @@ -281,20 +289,6 @@ fn get_project_root(config_files: &ConfigMap) -> Option { .map(|pr| pr.to_path_buf()) } -fn load_miserc() -> Result { - let settings_path = env::MISE_CONFIG_FILE - .clone() - .unwrap_or(dirs::CONFIG.join("config.toml")); - match settings_path.exists() { - false => { - trace!("settings does not exist {:?}", settings_path); - Ok(MiseToml::init(&settings_path)) - } - true => MiseToml::from_file(&settings_path) - .wrap_err_with(|| miette!("Error parsing {}", display_path(&settings_path))), - } -} - fn load_plugins(settings: &Settings) -> Result { let mut tools = CORE_PLUGINS.clone(); if settings.experimental { @@ -395,23 +389,18 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { config_files.into_iter().unique().collect() } -fn get_global_mise_toml() -> PathBuf { - env::MISE_CONFIG_FILE - .clone() - .unwrap_or_else(|| dirs::CONFIG.join("config.toml")) -} - pub fn global_config_files() -> Vec { let mut config_files = vec![]; - if env::MISE_CONFIG_FILE.is_none() && !*env::MISE_USE_TOML { - // only add ~/.tool-versions if MISE_CONFIG_FILE is not set - // because that's how the user overrides the default - let home_config = dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); - if home_config.is_file() { - config_files.push(home_config); - } - }; - let global_config = get_global_mise_toml(); + // TODO: add ~/.tool-versions under the right conditions + // if env::MISE_CONFIG_FILE.is_none() && !*env::MISE_USE_TOML { + // // only add ~/.tool-versions if MISE_CONFIG_FILE is not set + // // because that's how the user overrides the default + // let home_config = dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); + // if home_config.is_file() { + // config_files.push(home_config); + // } + // }; + let global_config = env::MISE_GLOBAL_CONFIG_FILE.clone(); if global_config.is_file() { config_files.push(global_config); } diff --git a/src/config/settings.rs b/src/config/settings.rs index 6efb65d9e..b8e96b32e 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,43 +1,35 @@ -use confique::env::parse::{list_by_colon, list_by_comma}; -use miette::{IntoDiagnostic, Result}; - use std::collections::{BTreeSet, HashSet}; use std::fmt::{Debug, Display, Formatter}; use std::path::PathBuf; -use std::sync::{Arc, Once, RwLock}; +use std::sync::{Arc, Mutex, RwLock}; -use confique::{Builder, Config, Partial}; +#[allow(unused_imports)] +use confique::env::parse::{list_by_colon, list_by_comma}; +use confique::{Config, Partial}; +use miette::{IntoDiagnostic, Result}; use once_cell::sync::Lazy; - -use crate::env; use serde::ser::Error; -use serde_derive::Serialize; +use serde_derive::{Deserialize, Serialize}; + +use crate::{env, file}; #[derive(Config, Debug, Clone, Serialize)] -#[config(partial_attr(derive(Clone, Serialize)))] +#[config(partial_attr(derive(Clone, Serialize, Default)))] pub struct Settings { #[config(env = "MISE_ALL_COMPILE", default = false)] pub all_compile: bool, - #[config(env = "CI", default = false)] - pub ci: bool, #[config(env = "MISE_ALWAYS_KEEP_DOWNLOAD", default = false)] pub always_keep_download: bool, #[config(env = "MISE_ALWAYS_KEEP_INSTALL", default = false)] pub always_keep_install: bool, #[config(env = "MISE_ASDF_COMPAT", default = false)] pub asdf_compat: bool, - #[config(env = "MISE_CD")] - pub cd: Option, #[config(env = "MISE_COLOR", default = true)] pub color: bool, - #[config(env = "MISE_DEBUG", default = false)] - pub debug: bool, #[config(env = "MISE_DISABLE_DEFAULT_SHORTHANDS", default = false)] pub disable_default_shorthands: bool, #[config(env = "MISE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub disable_tools: BTreeSet, - #[config(env = "MISE_ENV_FILE")] - pub env_file: Option, #[config(env = "MISE_EXPERIMENTAL", default = false)] pub experimental: bool, #[config(env = "MISE_JOBS", default = 4)] @@ -46,42 +38,60 @@ pub struct Settings { pub legacy_version_file: bool, #[config(env = "MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, - #[config(env = "MISE_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION", default = "7d")] - pub plugin_autoupdate_last_check_duration: String, - #[config(env = "MISE_LOG_LEVEL", default = "info")] - pub log_level: String, + #[config(env = "MISE_NODE_COMPILE", default = false)] + pub node_compile: bool, #[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)] pub not_found_auto_install: bool, #[config(env = "MISE_PARANOID", default = false)] pub paranoid: bool, - #[config(env = "MISE_QUIET", default = false)] - pub quiet: bool, + #[config(env = "MISE_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION", default = "7d")] + pub plugin_autoupdate_last_check_duration: String, #[config(env = "MISE_RAW", default = false)] pub raw: bool, #[config(env = "MISE_SHORTHANDS_FILE")] pub shorthands_file: Option, #[config(env = "MISE_TASK_OUTPUT")] pub task_output: Option, - #[config(env = "MISE_TRACE", default = false)] - pub trace: bool, #[config(env = "MISE_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] pub trusted_config_paths: BTreeSet, + #[config(env = "MISE_QUIET", default = false)] + pub quiet: bool, #[config(env = "MISE_VERBOSE", default = false)] pub verbose: bool, #[config(env = "MISE_YES", default = false)] pub yes: bool, + + // hidden settings + #[config(env = "CI", default = false)] + pub ci: bool, + #[config(env = "MISE_CD")] + pub cd: Option, + #[config(env = "MISE_DEBUG", default = false)] + pub debug: bool, + #[config(env = "MISE_ENV_FILE")] + pub env_file: Option, + #[config(env = "MISE_TRACE", default = false)] + pub trace: bool, + #[config(env = "MISE_LOG_LEVEL", default = "info")] + pub log_level: String, } pub type SettingsPartial = ::Partial; -impl Default for Settings { - fn default() -> Self { - Settings::default_builder().load().unwrap() +static SETTINGS: RwLock>> = RwLock::new(None); +static CLI_SETTINGS: Mutex> = Mutex::new(None); +static DEFAULT_SETTINGS: Lazy = Lazy::new(|| { + let mut s = SettingsPartial::empty(); + if let Some("alpine" | "nixos") = env::LINUX_DISTRO.as_ref().map(|s| s.as_str()) { + s.all_compile = Some(true); } -} + s +}); -static PARTIALS: RwLock> = RwLock::new(Vec::new()); -static SETTINGS: RwLock>> = RwLock::new(None); +#[derive(Serialize, Deserialize)] +pub struct SettingsFile { + pub settings: SettingsPartial, +} impl Settings { pub fn get() -> Arc { @@ -91,7 +101,17 @@ impl Settings { if let Some(settings) = SETTINGS.read().unwrap().as_ref() { return Ok(settings.clone()); } - let mut settings = Self::default_builder().load().into_diagnostic()?; + let file_settings = Self::file_settings().unwrap_or_else(|e| { + eprintln!("Error loading settings file: {}", e); + Default::default() + }); + let mut settings = Self::builder() + .preloaded(CLI_SETTINGS.lock().unwrap().clone().unwrap_or_default()) + .env() + .preloaded(file_settings) + .preloaded(DEFAULT_SETTINGS.clone()) + .load() + .into_diagnostic()?; if let Some(cd) = &settings.cd { static ORIG_PATH: Lazy> = Lazy::new(env::current_dir); let mut cd = PathBuf::from(cd); @@ -132,29 +152,23 @@ impl Settings { if settings.ci { settings.yes = true; } + if settings.all_compile { + settings.node_compile = true; + } let settings = Arc::new(settings); *SETTINGS.write().unwrap() = Some(settings.clone()); Ok(settings) } - pub fn add_partial(partial: SettingsPartial) { - static ONCE: Once = Once::new(); - ONCE.call_once(|| { - let mut p = SettingsPartial::empty(); - for arg in &*env::ARGS.read().unwrap() { - if arg == "--" { - break; - } - if arg == "--raw" { - p.raw = Some(true); - } - } - PARTIALS.write().unwrap().push(p); - }); - PARTIALS.write().unwrap().push(partial); - *SETTINGS.write().unwrap() = None; - } pub fn add_cli_matches(m: &clap::ArgMatches) { let mut s = SettingsPartial::empty(); + for arg in &*env::ARGS.read().unwrap() { + if arg == "--" { + break; + } + if arg == "--raw" { + s.raw = Some(true); + } + } if let Some(cd) = m.get_one::("cd") { s.cd = Some(cd.to_string()); } @@ -179,25 +193,37 @@ impl Settings { if *m.get_one::("verbose").unwrap() > 1 { s.log_level = Some("trace".to_string()); } - Self::add_partial(s); + Self::reset(Some(s)); } - pub fn default_builder() -> Builder { - let mut b = Self::builder().env(); - for partial in PARTIALS.read().unwrap().iter() { - b = b.preloaded(partial.clone()); - } - b + fn file_settings() -> Result { + let settings_file = &*env::MISE_SETTINGS_FILE; + if settings_file.exists() { + return Self::from_file(settings_file); + } + let global_config = &*env::MISE_GLOBAL_CONFIG_FILE; + if !global_config.exists() { + return Ok(Default::default()); + } + let raw = file::read_to_string(global_config)?; + let settings_file: SettingsFile = toml::from_str(&raw).into_diagnostic()?; + Ok(settings_file.settings) } + + pub fn from_file(path: &PathBuf) -> Result { + let raw = file::read_to_string(path)?; + let settings: SettingsPartial = toml::from_str(&raw).into_diagnostic()?; + Ok(settings) + } + pub fn hidden_configs() -> HashSet<&'static str> { static HIDDEN_CONFIGS: Lazy> = Lazy::new(|| ["ci", "cd", "debug", "env_file", "trace", "log_level"].into()); HIDDEN_CONFIGS.clone() } - #[cfg(test)] - pub fn reset() { - PARTIALS.write().unwrap().clear(); + pub fn reset(cli_settings: Option) { + *CLI_SETTINGS.lock().unwrap() = cli_settings; *SETTINGS.write().unwrap() = None; } diff --git a/src/env.rs b/src/env.rs index d4947f26d..38abaada8 100644 --- a/src/env.rs +++ b/src/env.rs @@ -52,7 +52,14 @@ pub static MISE_DEFAULT_CONFIG_FILENAME: Lazy = Lazy::new(|| var("MISE_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".mise.toml".into())); pub static MISE_ENV: Lazy> = Lazy::new(|| var("MISE_ENV").or_else(|_| var("MISE_ENVIRONMENT")).ok()); -pub static MISE_CONFIG_FILE: Lazy> = Lazy::new(|| var_path("MISE_CONFIG_FILE")); +pub static MISE_SETTINGS_FILE: Lazy = Lazy::new(|| { + var_path("MISE_SETTINGS_FILE").unwrap_or_else(|| MISE_CONFIG_DIR.join("settings.toml")) +}); +pub static MISE_GLOBAL_CONFIG_FILE: Lazy = Lazy::new(|| { + var_path("MISE_GLOBAL_CONFIG_FILE") + .or_else(|| var_path("MISE_CONFIG_FILE")) + .unwrap_or_else(|| MISE_CONFIG_DIR.join("config.toml")) +}); pub static MISE_USE_TOML: Lazy = Lazy::new(|| var_is_true("MISE_USE_TOML")); pub static MISE_BIN: Lazy = Lazy::new(|| { var_path("MISE_BIN") @@ -103,6 +110,7 @@ pub static __MISE_WATCH: Lazy> = Lazy::new(|| match var(" _ => None, }); pub static CI: Lazy = Lazy::new(|| var_is_true("CI")); +pub static LINUX_DISTRO: Lazy> = Lazy::new(linux_distro); pub static PREFER_STALE: Lazy = Lazy::new(|| prefer_stale(&ARGS.read().unwrap())); /// essentially, this is whether we show spinners or build output on runtime install pub static PRISTINE_ENV: Lazy> = @@ -112,14 +120,6 @@ pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH" None => vec![], }); pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); -pub static MISE_ALL_COMPILE: Lazy = Lazy::new(|| { - var_option_bool("MISE_ALL_COMPILE").unwrap_or_else(|| { - matches!( - linux_distro().unwrap_or_default().as_str(), - "alpine" | "nixos" - ) - }) -}); #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); @@ -165,9 +165,6 @@ pub static MISE_NODE_MAKE: Lazy = pub static MISE_NODE_NINJA: Lazy = Lazy::new(|| var_option_bool("MISE_NODE_NINJA").unwrap_or_else(is_ninja_on_path)); pub static MISE_NODE_VERIFY: Lazy = Lazy::new(|| !var_is_false("MISE_NODE_VERIFY")); -pub static MISE_NODE_COMPILE: Lazy = Lazy::new(|| { - *MISE_ALL_COMPILE || var_is_true("MISE_NODE_COMPILE") || var_is_true("MISE_NODE_FORCE_COMPILE") -}); pub static MISE_NODE_CFLAGS: Lazy> = Lazy::new(|| var("MISE_NODE_CFLAGS").or_else(|_| var("NODE_CFLAGS")).ok()); pub static MISE_NODE_CONFIGURE_OPTS: Lazy> = Lazy::new(|| { diff --git a/src/errors.rs b/src/errors.rs index 4afd1bdef..0d65d2992 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -4,7 +4,8 @@ use thiserror::Error; use crate::plugins::PluginName; -#[derive(Error, Debug)] +#[derive(Debug, Diagnostic, Error)] +#[diagnostic(help("help me!"))] pub enum Error { #[error("[{0}] plugin not installed")] PluginNotInstalled(PluginName), diff --git a/src/main.rs b/src/main.rs index 84db43801..58b5160c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ extern crate miette; extern crate strum; use itertools::Itertools; -use miette::Result; +use miette::{MietteHandlerOpts, Result}; use crate::cli::Cli; @@ -67,6 +67,11 @@ fn main() -> Result<()> { let args = env::args().collect_vec(); // TODO: figure out how to display version/help + // let theme = GraphicalTheme::default(); + // let handler = GraphicalReportHandler::new_themed(theme); + miette::set_hook(Box::new(|_| { + Box::new(MietteHandlerOpts::default().with_cause_chain().build()) + }))?; Cli::run(&args) // match Cli::run(&args).with_context(|| miette!(help = format!("Version: {}", &*VERSION))) { // Ok(()) => Ok(()), diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index df2bc38a4..3654a1380 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -95,8 +95,13 @@ impl CorePlugin { if !*env::MISE_USE_VERSIONS_HOST { return Ok(None); } - let versions = HTTP_FETCH - .get_text(format!("http://rtx-versions.jdx.dev/{}", &self.name))? + let raw = HTTP_FETCH.get_text(format!("http://rtx-versions.jdx.dev/{}", &self.name))?; + if raw.starts_with("") { + debug!("Got HTML response from versions host, ignoring"); + trace!("HTML response: {}", raw); + return Ok(None); + } + let versions = raw .lines() .map(|v| v.trim().to_string()) .filter(|v| !v.is_empty()) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index e78e5afba..975a345b2 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -8,7 +8,7 @@ use url::Url; use crate::build_time::built_info; use crate::cmd::CmdLineRunner; -use crate::config::Config; +use crate::config::{Config, Settings}; use crate::env::MISE_NODE_MIRROR_URL; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; @@ -293,9 +293,10 @@ impl Plugin for NodePlugin { fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let config = Config::get(); + let settings = Settings::get(); let opts = BuildOpts::new(ctx)?; debug!("node build opts: {:#?}", opts); - if *env::MISE_NODE_COMPILE { + if settings.node_compile { self.install_compiled(ctx, &opts)?; } else { self.install_precompiled(ctx, &opts)?; diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index be59ceb17..c86142b97 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -150,6 +150,11 @@ impl ExternalPlugin { Err(err) if http::error_code(&err) == Some(404) => return Ok(None), res => res?, }; + if versions.starts_with("") { + debug!("versions host returned html, assuming it's not a valid response"); + trace!("versions host response: {}", versions); + return Ok(None); + } let versions = versions .lines() .map(|v| v.trim().to_string()) diff --git a/src/shorthands.rs b/src/shorthands.rs index ccbd3ff89..9529c08f2 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -10,9 +10,8 @@ use crate::{dirs, file}; pub type Shorthands = HashMap; -pub fn get_shorthands() -> Shorthands { +pub fn get_shorthands(settings: &Settings) -> Shorthands { let mut shorthands = HashMap::new(); - let settings = Settings::get(); if !settings.disable_default_shorthands { shorthands.extend( DEFAULT_SHORTHANDS @@ -51,19 +50,19 @@ fn parse_shorthands_file(mut f: PathBuf) -> Result { #[cfg(test)] mod tests { - use crate::config::settings::SettingsPartial; - use confique::Partial; use pretty_assertions::assert_str_eq; + use std::ops::Deref; + + use crate::config::settings::Settings; use super::*; #[test] fn test_get_shorthands() { - Settings::reset(); - let mut partial = SettingsPartial::empty(); - partial.shorthands_file = Some("../fixtures/shorthands.toml".into()); - Settings::add_partial(partial); - let shorthands = get_shorthands(); + Settings::reset(None); + let mut settings = Settings::get().deref().clone(); + settings.shorthands_file = Some("../fixtures/shorthands.toml".into()); + let shorthands = get_shorthands(&settings); assert_str_eq!( shorthands["elixir"], "https://github.com/mise-plugins/mise-elixir.git" @@ -74,11 +73,10 @@ mod tests { #[test] fn test_get_shorthands_missing_file() { - Settings::reset(); - let mut partial = SettingsPartial::empty(); - partial.shorthands_file = Some("test/fixtures/missing.toml".into()); - Settings::add_partial(partial); - let shorthands = get_shorthands(); + Settings::reset(None); + let mut settings = Settings::get().deref().clone(); + settings.shorthands_file = Some("test/fixtures/missing.toml".into()); + let shorthands = get_shorthands(&settings); assert!(!shorthands.is_empty()); } } diff --git a/src/test.rs b/src/test.rs index 84f7e0896..08213aeec 100644 --- a/src/test.rs +++ b/src/test.rs @@ -50,18 +50,23 @@ pub fn reset_config() { ) .unwrap(); file::write( - env::HOME.join("config/config.toml"), + env::HOME.join("config/settings.toml"), indoc! {r#" - [env] - TEST_ENV_VAR = 'test-123' - [settings] experimental = true verbose = true always_keep_download= true always_keep_install= true legacy_version_file= true - plugin_autoupdate_last_check_duration = 20 + plugin_autoupdate_last_check_duration = "20m" jobs = 2 + "#}, + ) + .unwrap(); + file::write( + env::HOME.join("config/config.toml"), + indoc! {r#" + [env] + TEST_ENV_VAR = 'test-123' [alias.tiny] "my/alias" = '3.0' diff --git a/test/config/config.toml b/test/config/config.toml index 69a229f91..dc1bb4abf 100644 --- a/test/config/config.toml +++ b/test/config/config.toml @@ -1,13 +1,5 @@ [env] TEST_ENV_VAR = 'test-123' -[settings] -experimental = true -verbose = true -always_keep_download= true -always_keep_install= true -legacy_version_file= true -plugin_autoupdate_last_check_duration = 20 -jobs = 2 [alias.tiny] "my/alias" = '3.0' diff --git a/test/config/settings.toml b/test/config/settings.toml new file mode 100644 index 000000000..e22019870 --- /dev/null +++ b/test/config/settings.toml @@ -0,0 +1,7 @@ +experimental = true +verbose = true +always_keep_download= true +always_keep_install= true +legacy_version_file= true +plugin_autoupdate_last_check_duration = "20m" +jobs = 2 From 128142f545f79d23c581eba3f2c0fcc122764134 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 6 Jan 2024 23:19:44 -0800 Subject: [PATCH 1560/1891] python: add support for precompiled binaries (#1388) Currently enabled if experimental=1 --- e2e/test_poetry | 1 + schema/settings.json | 14 ++- src/cli/settings/ls.rs | 2 + src/cli/settings/set.rs | 2 + src/cli/settings/unset.rs | 2 + src/config/settings.rs | 4 + src/http.rs | 5 +- src/plugins/core/mod.rs | 7 +- src/plugins/core/python.rs | 171 +++++++++++++++++++++++++++------ src/plugins/external_plugin.rs | 7 +- 10 files changed, 173 insertions(+), 42 deletions(-) diff --git a/e2e/test_poetry b/e2e/test_poetry index 79b0bbc6d..9db0d99ad 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -6,6 +6,7 @@ source "$(dirname "$0")/assert.sh" rm -rf "$MISE_DATA_DIR/cache/poetry" export POETRY_HOME=".poetry" +mise settings set experimental n eval "$(mise activate bash)" cat >.e2e.mise.toml <(&self, url: U) -> Result { let url = url.into_url().unwrap(); - let resp = self.get(url)?; + let resp = self.get(url.clone())?; let text = resp.text().into_diagnostic()?; + if text.starts_with("") { + bail!("Got HTML instead of text from {}", url); + } Ok(text) } diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 3654a1380..7fd8d83dc 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -95,12 +95,7 @@ impl CorePlugin { if !*env::MISE_USE_VERSIONS_HOST { return Ok(None); } - let raw = HTTP_FETCH.get_text(format!("http://rtx-versions.jdx.dev/{}", &self.name))?; - if raw.starts_with("") { - debug!("Got HTML response from versions host, ignoring"); - trace!("HTML response: {}", raw); - return Ok(None); - } + let raw = HTTP_FETCH.get_text(format!("http://mise-versions.jdx.dev/{}", &self.name))?; let versions = raw .lines() .map(|v| v.trim().to_string()) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 50ededf95..cfca6123d 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -4,11 +4,12 @@ use std::path::{Path, PathBuf}; use itertools::Itertools; use miette::{IntoDiagnostic, Result}; +use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; -use crate::file::{create_dir_all, display_path}; +use crate::file::display_path; use crate::git::Git; -use crate::http::HTTP; +use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; use crate::plugins::Plugin; @@ -19,12 +20,16 @@ use crate::{cmd, env, file}; #[derive(Debug)] pub struct PythonPlugin { core: CorePlugin, + precompiled_cache: CacheManager>, } impl PythonPlugin { pub fn new() -> Self { + let core = CorePlugin::new("python"); Self { - core: CorePlugin::new("python"), + precompiled_cache: CacheManager::new(core.cache_path.join("precompiled.msgpack.z")) + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), + core, } } @@ -48,7 +53,7 @@ impl PythonPlugin { } let python_build_path = self.python_build_path(); debug!("Installing python-build to {}", python_build_path.display()); - create_dir_all(self.python_build_path().parent().unwrap())?; + file::create_dir_all(self.python_build_path().parent().unwrap())?; let git = Git::new(self.python_build_path()); git.clone(&env::MISE_PYENV_REPO)?; Ok(()) @@ -65,6 +70,16 @@ impl PythonPlugin { } fn fetch_remote_versions(&self) -> Result> { + let settings = Settings::get(); + if self.should_install_precompiled(&settings) { + let v = self + .fetch_precompiled_remote_versions()? + .iter() + .map(|(v, _, _)| v.to_string()) + .unique() + .collect(); + return Ok(v); + } match self.core.fetch_remote_versions_from_mise() { Ok(Some(versions)) => return Ok(versions), Ok(None) => {} @@ -89,6 +104,70 @@ impl PythonPlugin { tv.install_short_path().join("bin/python") } + fn should_install_precompiled(&self, settings: &Settings) -> bool { + settings.all_compile || settings.python_compile || settings.experimental + } + + fn fetch_precompiled_remote_versions(&self) -> Result<&Vec<(String, String, String)>> { + self.precompiled_cache.get_or_try_init(|| { + let raw = HTTP_FETCH.get_text("http://mise-versions.jdx.dev/python-precompiled")?; + let versions = raw + .lines() + .filter(|v| v.contains(&format!("{}-{}", arch(), os()))) + .flat_map(|v| { + regex!(r"^cpython-(\d+\.\d+\.\d+)\+(\d+).*") + .captures(v) + .map(|caps| { + ( + caps[1].to_string(), + caps[2].to_string(), + caps[0].to_string(), + ) + }) + }) + .collect_vec(); + Ok(versions) + }) + } + + fn install_precompiled(&self, ctx: &InstallContext) -> Result<()> { + warn!("installing precompiled python from indygreg/python-build-standalone"); + warn!("if you experience issues with this python, switch to python-build"); + warn!("by running: mise settings set python_compile 0"); + + let config = Config::get(); + let precompile_info = self + .fetch_precompiled_remote_versions()? + .iter() + .rev() + .find(|(v, _, _)| &ctx.tv.version == v); + let (tag, filename) = match precompile_info { + Some((_, tag, filename)) => (tag, filename), + None => bail!("no precompiled version found for {}", ctx.tv), + }; + let url = format!( + "https://github.com/indygreg/python-build-standalone/releases/download/{tag}/{filename}" + ); + let filename = url.split('/').last().unwrap(); + let install = ctx.tv.install_path(); + let download = ctx.tv.download_path(); + let tarball_path = download.join(filename); + + ctx.pr.set_message(format!("downloading {}", &url)); + HTTP.download_file(&url, &tarball_path)?; + + ctx.pr + .set_message(format!("installing {}", tarball_path.display())); + file::untar(&tarball_path, &download)?; + file::remove_all(&install)?; + file::rename(download.join("python"), &install)?; + file::make_symlink(&install.join("bin/python3"), &install.join("bin/python"))?; + + self.test_python(&config, &ctx.tv, ctx.pr.as_ref())?; + + Ok(()) + } + fn install_default_packages( &self, config: &Config, @@ -133,37 +212,50 @@ impl PythonPlugin { } } if !virtualenv.exists() { - info!("setting up virtualenv at: {}", virtualenv.display()); - let mut cmd = CmdLineRunner::new(self.python_path(tv)) - .arg("-m") - .arg("venv") - .arg(&virtualenv) - .envs(&config.env); - if let Some(pr) = pr { - cmd = cmd.with_pr(pr); + if settings.python_venv_auto_create { + info!("setting up virtualenv at: {}", virtualenv.display()); + let mut cmd = CmdLineRunner::new(self.python_path(tv)) + .arg("-m") + .arg("venv") + .arg(&virtualenv) + .envs(&config.env); + if let Some(pr) = pr { + cmd = cmd.with_pr(pr); + } + cmd.execute()?; + } else { + warn!( + "no venv found at: {p}\n\n\ + To have mise automatically create virtualenvs, run:\n\ + mise settings set python_venv_auto_create true\n\n\ + To create a virtualenv manually, run:\n\ + python -m venv {p}", + p = display_path(&virtualenv) + ); + return Ok(None); } - cmd.execute()?; } - self.check_venv_python(&virtualenv, tv)?; + // TODO: enable when it is more reliable + // self.check_venv_python(&virtualenv, tv)?; Ok(Some(virtualenv)) } else { Ok(None) } } - fn check_venv_python(&self, virtualenv: &Path, tv: &ToolVersion) -> Result<()> { - let symlink = virtualenv.join("bin/python"); - let target = self.python_path(tv); - let symlink_target = symlink.read_link().unwrap_or_default(); - ensure!( - symlink_target == target, - "expected venv {} to point to {}.\nTry deleting the venv at {}.", - display_path(&symlink), - display_path(&target), - display_path(virtualenv) - ); - Ok(()) - } + // fn check_venv_python(&self, virtualenv: &Path, tv: &ToolVersion) -> Result<()> { + // let symlink = virtualenv.join("bin/python"); + // let target = self.python_path(tv); + // let symlink_target = symlink.read_link().unwrap_or_default(); + // ensure!( + // symlink_target == target, + // "expected venv {} to point to {}.\nTry deleting the venv at {}.", + // display_path(&symlink), + // display_path(&target), + // display_path(virtualenv) + // ); + // Ok(()) + // } fn test_python(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { pr.set_message("python --version".into()); @@ -193,6 +285,9 @@ impl Plugin for PythonPlugin { fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let config = Config::get(); let settings = Settings::try_get()?; + if self.should_install_precompiled(&settings) { + return self.install_precompiled(ctx); + } self.install_or_update_python_build()?; if matches!(&ctx.tv.request, ToolVersionRequest::Ref(..)) { return Err(miette!("Ref versions not supported for python")); @@ -251,3 +346,25 @@ impl Plugin for PythonPlugin { Ok(hm) } } + +fn os() -> &'static str { + if cfg!(target_env = "musl") { + "unknown-linux-musl" + } else if cfg!(target_os = "linux") { + "unknown-linux-gnu" + } else if cfg!(target_os = "macos") { + "apple-darwin" + } else { + panic!("unsupported OS") + } +} + +fn arch() -> &'static str { + if cfg!(target_arch = "x86_64") { + "x86_64_v3" // TODO: make the version configurable + } else if cfg!(target_arch = "aarch64") { + "aarch64" + } else { + panic!("unsupported arch") + } +} diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index c86142b97..93cb1d128 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -146,15 +146,10 @@ impl ExternalPlugin { return Ok(None); } let versions = - match HTTP_FETCH.get_text(format!("http://rtx-versions.jdx.dev/{}", self.name)) { + match HTTP_FETCH.get_text(format!("http://mise-versions.jdx.dev/{}", self.name)) { Err(err) if http::error_code(&err) == Some(404) => return Ok(None), res => res?, }; - if versions.starts_with("") { - debug!("versions host returned html, assuming it's not a valid response"); - trace!("versions host response: {}", versions); - return Ok(None); - } let versions = versions .lines() .map(|v| v.trim().to_string()) From 065d31da74423f09f202acf67fd2be3bcd832dbe Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 01:20:33 -0600 Subject: [PATCH 1561/1891] chore: Release mise version 2024.1.9 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afe011dd9..57e80f2f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.8" +version = "2024.1.9" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 73552af3d..4a290973b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.8" +version = "2024.1.9" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 011427b5b..139e6628c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.8 +mise 2024.1.9 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index e79eb9eb1..9b0f39015 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,7 @@ let in rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.8"; + version = "2024.1.9"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index d495a1e4f..7e35696bb 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.8" +.TH mise 1 "mise 2024.1.9" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.8 +v2024.1.9 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 88e30dde8..34261350f 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.8 +Version: 2024.1.9 Release: 1 URL: https://github.com/jdx/mise/ Group: System From f42759d1cafaa206357e2eeaf3b1843cb80f65fb Mon Sep 17 00:00:00 2001 From: nokazn <41154684+nokazn@users.noreply.github.com> Date: Sun, 7 Jan 2024 17:44:51 +0900 Subject: [PATCH 1562/1891] fix: nix flake build errors (#1390) * chore: fix build config for nix flake * chore: add rust package for `nix develop` shell --- default.nix | 17 +++++------------ flake.lock | 30 ++++++++++++++++++++++++------ flake.nix | 2 ++ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/default.nix b/default.nix index 9b0f39015..1c2d72b8d 100644 --- a/default.nix +++ b/default.nix @@ -1,10 +1,5 @@ -{ pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, perl }: -let - libssl = with pkgs; symlinkJoin { - name = "libssl-merged"; - paths = [ openssl.out openssl.dev ]; - }; -in +{ pkgs, lib, stdenv, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, openssl }: + rustPlatform.buildRustPackage { pname = "mise"; version = "2024.1.9"; @@ -23,6 +18,7 @@ rustPlatform.buildRustPackage { gnused git gawk + openssl ] ++ lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.Security darwin.apple_sdk.frameworks.SystemConfiguration ]; prePatch = '' @@ -32,6 +28,8 @@ rustPlatform.buildRustPackage { --replace '#!/bin/sh' '#!${bash}/bin/sh' substituteInPlace ./src/env_diff.rs \ --replace '"bash"' '"${bash}/bin/bash"' + substituteInPlace ./test/cwd/.mise/tasks/filetask \ + --replace '#!/usr/bin/env bash' '#!${bash}/bin/bash' substituteInPlace ./src/cli/direnv/exec.rs \ --replace '"env"' '"${coreutils}/bin/env"' \ --replace 'cmd!("direnv"' 'cmd!("${direnv}/bin/direnv"' @@ -44,11 +42,6 @@ rustPlatform.buildRustPackage { --skip cli::plugins::ls::tests::test_plugin_list_urls ''; - # Need this to ensure openssl-src's build uses an available version of `perl` - # https://github.com/alexcrichton/openssl-src-rs/issues/45 - OPENSSL_SRC_PERL = "${perl}/bin/perl"; - OPENSSL_DIR = "${libssl}"; - meta = with lib; { description = "The front-end to your dev env"; homepage = "https://github.com/jdx/mise"; diff --git a/flake.lock b/flake.lock index b134471de..f5feddac9 100644 --- a/flake.lock +++ b/flake.lock @@ -1,12 +1,15 @@ { "nodes": { "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1678901627, - "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "owner": "numtide", "repo": "flake-utils", - "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "type": "github" }, "original": { @@ -17,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1679410443, - "narHash": "sha256-xDHO/jixWD+y5pmW5+2q4Z4O/I/nA4MAa30svnZKK+M=", + "lastModified": 1704161960, + "narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c9ece0059f42e0ab53ac870104ca4049df41b133", + "rev": "63143ac2c9186be6d9da6035fa22620018c85932", "type": "github" }, "original": { @@ -36,6 +39,21 @@ "flake-utils": "flake-utils", "nixpkgs": "nixpkgs" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 0f36d9a16..e2865317d 100644 --- a/flake.nix +++ b/flake.nix @@ -33,6 +33,8 @@ shfmt nodejs cargo-release + cargo-insta + cargo-llvm-cov ]; }; } From 21cb004402a7bfad2c50dbd56e584555715f1597 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 02:45:09 -0600 Subject: [PATCH 1563/1891] do not display error if settings is missing Fixes #1389 --- src/config/settings.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config/settings.rs b/src/config/settings.rs index bd7a37ef9..f6d74850a 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -94,6 +94,7 @@ static DEFAULT_SETTINGS: Lazy = Lazy::new(|| { #[derive(Serialize, Deserialize)] pub struct SettingsFile { + #[serde(default)] pub settings: SettingsPartial, } From 1237d3336c0db23fd0ab6f922f2d64eb1c7e2e18 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 02:45:54 -0600 Subject: [PATCH 1564/1891] chore: Release mise version 2024.1.10 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57e80f2f6..152ed644d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.9" +version = "2024.1.10" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 4a290973b..505f60df0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.9" +version = "2024.1.10" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 139e6628c..19bfd58c6 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.9 +mise 2024.1.10 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 1c2d72b8d..a5d95217a 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.9"; + version = "2024.1.10"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 7e35696bb..2594bf71f 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.9" +.TH mise 1 "mise 2024.1.10" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.9 +v2024.1.10 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 34261350f..c63474b5a 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.9 +Version: 2024.1.10 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 8de42a0be94098c722ba8b9eef8eca505f5838c2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 03:24:31 -0600 Subject: [PATCH 1565/1891] toml: check min_version field --- .mise.toml | 1 + src/config/config_file/mise_toml.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/.mise.toml b/.mise.toml index f926552a7..f2ca64bb1 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,5 +1,6 @@ #:schema ./schema/mise.json +min_version = "2024.1.1" [env] mise.file = [".env"] FOO = "bar" diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 5a40ceaf8..2efb04097 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -8,6 +8,7 @@ use miette::{IntoDiagnostic, Result, WrapErr}; use serde_derive::Deserialize; use tera::Context as TeraContext; use toml_edit::{table, value, Array, Document, Item, Value}; +use versions::Versioning; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; use crate::config::AliasMap; @@ -78,6 +79,7 @@ impl MiseToml { let doc: Document = s.parse().into_diagnostic()?; // .suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { + "min_version" => self.parse_min_version(v)?, "dotenv" => self.parse_env_file(k, v, true)?, "env_file" => self.parse_env_file(k, v, true)?, "env_path" => self.path_dirs = self.parse_path_env(k, v)?, @@ -99,6 +101,26 @@ impl MiseToml { Ok(()) } + fn parse_min_version(&self, v: &Item) -> Result<()> { + match v.as_str() { + Some(s) => { + if let (Some(min), Some(cur)) = ( + Versioning::new(s), + Versioning::new(env!("CARGO_PKG_VERSION")), + ) { + ensure!( + cur >= min, + "mise version {} is required, but you are using {}", + style::eyellow(min), + style::eyellow(cur) + ); + } + Ok(()) + } + _ => parse_error!("min_version", v, "string"), + } + } + fn parse_env_file(&mut self, k: &str, v: &Item, deprecate: bool) -> Result<()> { trust_check(&self.path)?; if deprecate { From fcf91739bc0241114242afb9e8de6bdf819cd7ba Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 04:04:16 -0600 Subject: [PATCH 1566/1891] settings.toml: add to doctor and fix warning --- src/cli/doctor.rs | 8 ++++++++ src/config/config_file/mise_toml.rs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 9bdd97cec..cc6f47a26 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -8,6 +8,7 @@ use miette::Result; use crate::build_time::built_info; use crate::cli::version::VERSION; use crate::config::{Config, Settings}; +use crate::file::display_path; use crate::git::Git; use crate::plugins::PluginType; @@ -33,6 +34,7 @@ impl Doctor { miseprintln!("{}", shell()); miseprintln!("{}", mise_data_dir()); miseprintln!("{}", mise_env_vars()); + miseprintln!("{}", mise_settings_file()); match Settings::try_get() { Ok(settings) => { miseprintln!( @@ -122,6 +124,12 @@ fn mise_env_vars() -> String { s } +fn mise_settings_file() -> String { + let mut s = style("mise settings file:\n").bold().to_string(); + s.push_str(&format!(" {}\n", display_path(&*env::MISE_SETTINGS_FILE))); + s +} + fn render_config_files(config: &Config) -> String { let mut s = style("config files:\n").bold().to_string(); for f in config.config_files.keys().rev() { diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 2efb04097..a2cb79b93 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -88,7 +88,7 @@ impl MiseToml { "tools" => self.toolset = self.parse_toolset(k, v)?, "settings" => { let old = ui::style::eyellow(display_path(&self.path)); - let new = ui::style::eyellow(display_path(&env::MISE_GLOBAL_CONFIG_FILE)); + let new = ui::style::eyellow(display_path(&env::MISE_SETTINGS_FILE)); warn!("[settings] inside of {old} is deprecated. A separate {new} file should be used instead."); warn!("Removing the [settings] section from {old} will remove this warning",); } From 3576984b0ce89910c7bb4ae63a41b8c82381cc44 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 04:32:15 -0600 Subject: [PATCH 1567/1891] publish schema to r2 --- scripts/publish-s3.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index b2dcf5c8e..8a4a697f4 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -13,6 +13,7 @@ aws s3 cp "$RELEASE_DIR/VERSION" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_ aws s3 cp "$RELEASE_DIR/install.sh" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress --content-type "text/plain" aws s3 cp "$RELEASE_DIR/install.sh.sig" "s3://$AWS_S3_BUCKET/" --cache-control "$cache_day" --no-progress aws s3 cp "./mise/schema/mise.json" "s3://$AWS_S3_BUCKET/schema/mise.json" --cache-control "$cache_day" --no-progress --content-type "application/json" +aws s3 cp "./mise/schema/settings.json" "s3://$AWS_S3_BUCKET/schema/settings.json" --cache-control "$cache_day" --no-progress --content-type "application/json" aws s3 cp "./mise/schema/mise.plugin.json" "s3://$AWS_S3_BUCKET/schema/mise.plugin.json" --cache-control "$cache_day" --no-progress --content-type "application/json" aws s3 cp artifacts/rpm/mise.repo "s3://$AWS_S3_BUCKET/rpm/" --cache-control "$cache_day" --no-progress From 3a018bdbcde00bf257d3f265379832ab3b1aeb6b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 04:36:24 -0600 Subject: [PATCH 1568/1891] chore: Release mise version 2024.1.11 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- src/cli/doctor.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 152ed644d..1159055d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.10" +version = "2024.1.11" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 505f60df0..f83ffc683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.10" +version = "2024.1.11" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 19bfd58c6..d88b7badb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.10 +mise 2024.1.11 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index a5d95217a..7ea60885f 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.10"; + version = "2024.1.11"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 2594bf71f..2a399c310 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.10" +.TH mise 1 "mise 2024.1.11" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.10 +v2024.1.11 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index c63474b5a..fc8e44dbe 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.10 +Version: 2024.1.11 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index cc6f47a26..bfa7bbaa6 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -126,7 +126,7 @@ fn mise_env_vars() -> String { fn mise_settings_file() -> String { let mut s = style("mise settings file:\n").bold().to_string(); - s.push_str(&format!(" {}\n", display_path(&*env::MISE_SETTINGS_FILE))); + s.push_str(&format!(" {}\n", display_path(&env::MISE_SETTINGS_FILE))); s } From 8a7880bc912bbcef874d7428d6b0f7d772715fc5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 06:25:21 -0600 Subject: [PATCH 1569/1891] added missing settings from `mise settings set` --- src/cli/settings/set.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 7ef0af905..73aa87013 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -19,17 +19,29 @@ pub struct SettingsSet { impl SettingsSet { pub fn run(self) -> Result<()> { let value: toml_edit::Value = match self.setting.as_str() { - "experimental" => parse_bool(&self.value)?, + "all_compile" => parse_bool(&self.value)?, "always_keep_download" => parse_bool(&self.value)?, "always_keep_install" => parse_bool(&self.value)?, - "legacy_version_file" => parse_bool(&self.value)?, - "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, - "verbose" => parse_bool(&self.value)?, "asdf_compat" => parse_bool(&self.value)?, - "jobs" => parse_i64(&self.value)?, - "shorthands_file" => self.value.into(), + "color" => parse_bool(&self.value)?, "disable_default_shorthands" => parse_bool(&self.value)?, + "disable_tools" => self.value.split(',').map(|s| s.to_string()).collect(), + "experimental" => parse_bool(&self.value)?, + "jobs" => parse_i64(&self.value)?, + "legacy_version_file" => parse_bool(&self.value)?, + "node_compile" => parse_bool(&self.value)?, + "not_found_auto_install" => parse_bool(&self.value)?, + "paranoid" => parse_bool(&self.value)?, + "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, + "python_compile" => parse_bool(&self.value)?, + "python_venv_auto_create" => parse_bool(&self.value)?, + "quiet" => parse_bool(&self.value)?, "raw" => parse_bool(&self.value)?, + "shorthands_file" => self.value.into(), + "task_output" => self.value.into(), + "trusted_config_paths" => self.value.split(':').map(|s| s.to_string()).collect(), + "verbose" => parse_bool(&self.value)?, + "yes" => parse_bool(&self.value)?, _ => return Err(miette!("Unknown setting: {}", self.setting)), }; From 5ddbf68af1f32abbf8cff406a6d17d0898d4c81f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 06:29:45 -0600 Subject: [PATCH 1570/1891] python: fixed python_compile and all_compile settings --- src/plugins/core/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index cfca6123d..4c8835bb0 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -105,7 +105,7 @@ impl PythonPlugin { } fn should_install_precompiled(&self, settings: &Settings) -> bool { - settings.all_compile || settings.python_compile || settings.experimental + !settings.all_compile && !settings.python_compile && settings.experimental } fn fetch_precompiled_remote_versions(&self) -> Result<&Vec<(String, String, String)>> { From 3750934ae3b3e367b62b0c4a33aaa103cba894f3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 7 Jan 2024 06:42:56 -0600 Subject: [PATCH 1571/1891] chore: Release mise version 2024.1.12 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1159055d1..217205b78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.11" +version = "2024.1.12" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index f83ffc683..ba7ba94be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.11" +version = "2024.1.12" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index d88b7badb..fb7122305 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.11 +mise 2024.1.12 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 7ea60885f..49cd912a5 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.11"; + version = "2024.1.12"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 2a399c310..4fd62878e 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.11" +.TH mise 1 "mise 2024.1.12" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.11 +v2024.1.12 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index fc8e44dbe..71f3ef7a6 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.11 +Version: 2024.1.12 Release: 1 URL: https://github.com/jdx/mise/ Group: System From e14901fb9b047ae0fba18b5f85434141fab734d5 Mon Sep 17 00:00:00 2001 From: Michael Coulter Date: Sun, 7 Jan 2024 13:07:28 -0800 Subject: [PATCH 1572/1891] add path separator (#1398) --- e2e/test_shims | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/test_shims b/e2e/test_shims index 8d4d1dc37..ad2318cf1 100755 --- a/e2e/test_shims +++ b/e2e/test_shims @@ -3,7 +3,7 @@ set -euo pipefail # shellcheck source-path=SCRIPTDIR source "$(dirname "$0")/assert.sh" -export PATH="/XSTARTX:$MISE_DATA_DIR/shims:/XENDX$PATH" +export PATH="/XSTARTX:$MISE_DATA_DIR/shims:/XENDX:$PATH" mise i node mise reshim assert "node -v" "v20.0.0" From 576f2b9d873c3c23457d9f51b1f6071e3a4bbd27 Mon Sep 17 00:00:00 2001 From: Michael Coulter Date: Mon, 8 Jan 2024 09:08:55 -0800 Subject: [PATCH 1573/1891] prevent adding relative/empty paths during activation (#1400) Signed-off-by: Michael Coulter --- e2e/test_path_safety | 9 +++++++++ src/shell/bash.rs | 2 +- src/shell/fish.rs | 2 +- src/shell/nushell.rs | 2 +- src/shell/xonsh.rs | 2 +- src/shell/zsh.rs | 2 +- 6 files changed, 14 insertions(+), 5 deletions(-) create mode 100755 e2e/test_path_safety diff --git a/e2e/test_path_safety b/e2e/test_path_safety new file mode 100755 index 000000000..59e8dd2b3 --- /dev/null +++ b/e2e/test_path_safety @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +export MISE_EXPERIMENTAL=1 +eval "$(mise activate bash)" && eval "$(mise hook-env)" +install -m 0755 /dev/null /tmp/MISE_PATH_SAFETY_CHECK +cd /tmp && assert_fail "command -v MISE_PATH_SAFETY_CHECK" diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 607a6d547..68940c89d 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -11,7 +11,7 @@ impl Shell for Bash { let dir = exe.parent().unwrap(); let exe = exe.to_string_lossy(); let mut out = String::new(); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 2e1c9b6a0..dbf735847 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -13,7 +13,7 @@ impl Shell for Fish { let description = "'Update mise environment when changing directories'"; let mut out = String::new(); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { out.push_str(&format!("fish_add_path -g {dir}\n", dir = dir.display())); } diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index ce0c5a9da..5e7b0fbe3 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -26,7 +26,7 @@ impl Shell for Nushell { let exe = exe.display(); let mut out = String::new(); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { out.push_str(&format!( "$env.PATH = ($env.PATH | prepend '{}')\n", // TODO: set PATH as Path on windows dir.display() diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 6fc4b0868..5f8749611 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -49,7 +49,7 @@ impl Shell for Xonsh { from xonsh.built_ins import XSH "#}); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { let dir_str = dir.to_string_lossy(); let dir_esc = xonsh_escape_sq(&dir_str); out.push_str(&formatdoc! {r#" diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index ac7e793a4..79b705106 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -15,7 +15,7 @@ impl Shell for Zsh { // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_zsh.go#L10-L22 - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) { + if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); } out.push_str(&formatdoc! {r#" From d0f5aacaa188034522b5a75cf438531b73fe0a49 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:11:24 -0600 Subject: [PATCH 1574/1891] handle 404s (#1408) Fixes #1406 --- src/http.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http.rs b/src/http.rs index b4eff420f..e18ae999b 100644 --- a/src/http.rs +++ b/src/http.rs @@ -90,6 +90,10 @@ impl Client { } pub fn error_code(e: &Report) -> Option { + if e.to_string().contains("404") { + // TODO: not this when I can figure out how to use miette properly + return Some(404); + } if let Some(err) = e.downcast_ref::() { err.status().map(|s| s.as_u16()) } else { From 4aad252f351468922f6a4184a4d2724f22cd4343 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:34:23 -0600 Subject: [PATCH 1575/1891] allow expanding "~" for trusted_config_paths (#1409) Fixes #1402 --- src/config/config_file/mod.rs | 2 +- src/config/settings.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 11ce7a029..b1c0b709e 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -224,7 +224,7 @@ pub fn is_trusted(path: &Path) -> bool { return true; } let settings = Settings::get(); - for p in settings.trusted_config_paths.iter() { + for p in settings.trusted_config_paths() { if path.starts_with(p) { cached.insert(path); return true; diff --git a/src/config/settings.rs b/src/config/settings.rs index f6d74850a..fb9367415 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -238,6 +238,10 @@ impl Settings { ensure!(self.experimental, msg); Ok(()) } + + pub fn trusted_config_paths(&self) -> impl Iterator + '_ { + self.trusted_config_paths.iter().map(file::replace_path) + } } impl Display for Settings { From 0f5616d43e791195e187fcb03cfa6092bb6ce434 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:36:35 -0600 Subject: [PATCH 1576/1891] disallow [settings] header in settings.toml (#1410) Before this would silently ignore everything in the file. Fixes #1403 --- src/config/settings.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config/settings.rs b/src/config/settings.rs index fb9367415..41bcbff38 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -15,6 +15,7 @@ use crate::{env, file}; #[derive(Config, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize, Default)))] +#[config(partial_attr(serde(deny_unknown_fields)))] pub struct Settings { #[config(env = "MISE_ALL_COMPILE", default = false)] pub all_compile: bool, From b668c71c846a7e10e9ce1a01740ae782cf4b421c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 12:26:32 -0600 Subject: [PATCH 1577/1891] use ~/.tool-versions globally (#1414) --- src/cli/doctor.rs | 2 +- src/config/mod.rs | 20 +++++++++++--------- src/env.rs | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index bfa7bbaa6..99ac88df8 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -133,7 +133,7 @@ fn mise_settings_file() -> String { fn render_config_files(config: &Config) -> String { let mut s = style("config files:\n").bold().to_string(); for f in config.config_files.keys().rev() { - s.push_str(&format!(" {}\n", f.display())); + s.push_str(&format!(" {}\n", display_path(f))); } s } diff --git a/src/config/mod.rs b/src/config/mod.rs index 4994ae83f..0eeb1c816 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -391,15 +391,17 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { pub fn global_config_files() -> Vec { let mut config_files = vec![]; - // TODO: add ~/.tool-versions under the right conditions - // if env::MISE_CONFIG_FILE.is_none() && !*env::MISE_USE_TOML { - // // only add ~/.tool-versions if MISE_CONFIG_FILE is not set - // // because that's how the user overrides the default - // let home_config = dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); - // if home_config.is_file() { - // config_files.push(home_config); - // } - // }; + if env::var_path("MISE_CONFIG_FILE").is_none() + && env::var_path("MISE_GLOBAL_CONFIG_FILE").is_none() + && !*env::MISE_USE_TOML + { + // only add ~/.tool-versions if MISE_CONFIG_FILE is not set + // because that's how the user overrides the default + let home_config = dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()); + if home_config.is_file() { + config_files.push(home_config); + } + }; let global_config = env::MISE_GLOBAL_CONFIG_FILE.clone(); if global_config.is_file() { config_files.push(global_config); diff --git a/src/env.rs b/src/env.rs index 38abaada8..c5213adf3 100644 --- a/src/env.rs +++ b/src/env.rs @@ -280,7 +280,7 @@ fn var_option_bool(key: &str) -> Option { } } -fn var_path(key: &str) -> Option { +pub fn var_path(key: &str) -> Option { var_os(key).map(PathBuf::from).map(replace_path) } From c0bb4d283ccace371d9852d4678e8514c67ea6b2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:21:07 -0600 Subject: [PATCH 1578/1891] chore: Release mise version 2024.1.13 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- src/default_shorthands.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 217205b78..b012ddf54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.12" +version = "2024.1.13" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index ba7ba94be..c8b96d7df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.12" +version = "2024.1.13" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index fb7122305..5acd3be2f 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.12 +mise 2024.1.13 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 49cd912a5..7376a4862 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.12"; + version = "2024.1.13"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 4fd62878e..4794f1651 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.12" +.TH mise 1 "mise 2024.1.13" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.12 +v2024.1.13 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 71f3ef7a6..6c0938085 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.12 +Version: 2024.1.13 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 719664736..9d58c6d4b 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -673,7 +673,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("trivy", "https://github.com/zufardhiyaulhaq/asdf-trivy.git"), ("tsuru", "https://github.com/virtualstaticvoid/asdf-tsuru.git"), ("ttyd", "https://github.com/ivanvc/asdf-ttyd.git"), - ("tuist", "https://github.com/cprecioso/asdf-tuist.git"), + ("tuist", "https://github.com/asdf-community/asdf-tuist.git"), ("tx", "https://github.com/ORCID/asdf-transifex.git"), ("typos", "https://github.com/aschiavon91/asdf-typos.git"), ("uaa-cli", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), From d78db1e2e21f09983fe3c95f6c151fa1a8042d3e Mon Sep 17 00:00:00 2001 From: Ali Kefia Date: Tue, 9 Jan 2024 00:41:10 +0100 Subject: [PATCH 1579/1891] Correct PATH for python venvs (#1395) * reverse paths order * fix the caller * load manually configured paths before tool paths we should load path specified in .mise.toml files directly before paths that tools include also added e2e test to validate python venv PATH --------- Co-authored-by: Jeff Dickey <216188+jdx@users.noreply.github.com> --- e2e/.gitignore | 1 + e2e/test_python | 14 +++++++++++--- src/toolset/mod.rs | 6 +++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/e2e/.gitignore b/e2e/.gitignore index f6780a87a..fdb3d02ce 100644 --- a/e2e/.gitignore +++ b/e2e/.gitignore @@ -4,6 +4,7 @@ .config .asdf .default-go-packages +.venv ruby/Gemfile ruby/.ruby-version Library diff --git a/e2e/test_python b/e2e/test_python index 73594a27b..8560d73fd 100755 --- a/e2e/test_python +++ b/e2e/test_python @@ -6,13 +6,21 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 export MISE_PYTHON_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-python-packages" -mise i python@3.12.0 -assert_contains "mise x python@3.12.0 -- python --version" "Python 3.12" +cat >.e2e.mise.toml < Date: Mon, 8 Jan 2024 18:10:36 -0600 Subject: [PATCH 1580/1891] downgrade rpm dockerfile Makes repo compatible with AL2 --- packaging/rpm/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpm/Dockerfile b/packaging/rpm/Dockerfile index 30feefff1..15d63e8f4 100644 --- a/packaging/rpm/Dockerfile +++ b/packaging/rpm/Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:40 +FROM fedora:38 LABEL maintainer="jdx" RUN dnf install -y rpm-build rpm-sign ruby ruby-devel gcc \ From 9d746de2d04bc2629d5d93c16fb4480232a2e12f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 18:21:30 -0600 Subject: [PATCH 1581/1891] loosen regex for runtime symlink generation (#1392) --- src/plugins/mod.rs | 13 +++++++++---- src/runtime_symlinks.rs | 23 ++++++++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 4eaf9e660..c821b0bf7 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -8,6 +8,7 @@ use clap::Command; use console::style; use itertools::Itertools; use miette::{IntoDiagnostic, Result, WrapErr}; +use once_cell::sync::Lazy; use regex::Regex; use versions::Versioning; @@ -320,16 +321,13 @@ fn fuzzy_match_filter(versions: Vec, query: &str) -> Result> query = "[0-9].*"; } let query_regex = Regex::new(&format!("^{}([-.].+)?$", query)).into_diagnostic()?; - let version_regex = regex!( - r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|(a|b|c)[0-9]+|snapshot|SNAPSHOT|master)" - ); let versions = versions .into_iter() .filter(|v| { if query == v { return true; } - if version_regex.is_match(v) { + if VERSION_REGEX.is_match(v) { return false; } query_regex.is_match(v) @@ -390,6 +388,13 @@ pub enum PluginType { External, } +pub static VERSION_REGEX: Lazy = Lazy::new(|| { + Regex::new( + r"(^Available versions:|-src|-dev|-latest|-stm|[-\\.]rc|-milestone|-alpha|-beta|[-\\.]pre|-next|([abc])[0-9]+|snapshot|SNAPSHOT|master)" + ) + .unwrap() +}); + #[cfg(test)] mod tests { use pretty_assertions::assert_str_eq; diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 51e3ce4a3..2c3e18571 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -5,12 +5,11 @@ use std::sync::Arc; use indexmap::IndexMap; use itertools::Itertools; use miette::{IntoDiagnostic, Result}; -use regex::Regex; use versions::Versioning; use crate::config::Config; use crate::file::make_symlink; -use crate::plugins::Plugin; +use crate::plugins::{Plugin, VERSION_REGEX}; use crate::{dirs, file}; pub fn rebuild(config: &Config) -> Result<()> { @@ -38,17 +37,24 @@ pub fn rebuild(config: &Config) -> Result<()> { } fn list_symlinks(config: &Config, plugin: Arc) -> Result> { + // TODO: make this a pure function and add test cases let mut symlinks = IndexMap::new(); let rel_path = |x: &String| PathBuf::from(".").join(x.clone()); for v in installed_versions(&plugin)? { - let versions = Versioning::new(&v).expect("invalid version"); + let prefix = regex!(r"^[a-zA-Z0-9]+-") + .find(&v) + .map(|s| s.as_str().to_string()) + .unwrap_or_default(); + let sans_prefix = v.trim_start_matches(&prefix); + let versions = Versioning::new(sans_prefix).expect("invalid version"); let mut partial = vec![]; - while versions.nth(partial.len() + 1).is_some() { + while versions.nth(partial.len()).is_some() && versions.nth(partial.len() + 1).is_some() { let version = versions.nth(partial.len()).unwrap(); partial.push(version.to_string()); - symlinks.insert(partial.join("."), rel_path(&v)); + let from = format!("{}{}", prefix, partial.join(".")); + symlinks.insert(from, rel_path(&v)); } - symlinks.insert("latest".into(), rel_path(&v)); + symlinks.insert(format!("{prefix}latest"), rel_path(&v)); for (from, to) in config .get_all_aliases() .get(plugin.name()) @@ -60,7 +66,7 @@ fn list_symlinks(config: &Config, plugin: Arc) -> Result) -> Result) -> Result> { - let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); let versions = plugin .list_installed_versions()? .into_iter() - .filter(|v| re.is_match(v)) + .filter(|v| !VERSION_REGEX.is_match(v)) .collect(); Ok(versions) } From 187cc24cc33466b67c40b15735dddb031cc6a72f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 18:22:20 -0600 Subject: [PATCH 1582/1891] chore: Release mise version 2024.1.14 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b012ddf54..fae8d6b11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,7 +1350,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.13" +version = "2024.1.14" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index c8b96d7df..7f1b231e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.13" +version = "2024.1.14" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 5acd3be2f..72a569132 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.13 +mise 2024.1.14 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 7376a4862..4137232e8 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.13"; + version = "2024.1.14"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 4794f1651..936a1eee8 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.13" +.TH mise 1 "mise 2024.1.14" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -160,6 +160,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.13 +v2024.1.14 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 6c0938085..3db1939f4 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.13 +Version: 2024.1.14 Release: 1 URL: https://github.com/jdx/mise/ Group: System From e3ff351bce362ec5d8bddd9fb9bb13827fce083d Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 8 Jan 2024 22:07:49 -0600 Subject: [PATCH 1583/1891] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 72a569132..40199fcd8 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,10 @@ * Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://mise.jdx.dev/environments.html) for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://mise.jdx.dev/tasks/) used to build and test projects. +## Migrating from rtx + +mise will attempt to migrate most of its internal files making the transition as easy as possible. That said, it's worth reading the [migration guide](https://mise.jdx.dev/rtx.html) because there are a few things to watch out for. + ## 30 Second Demo The following shows using mise to install different versions From 2003c6b045559421be756db0ca403b1a6d76f64b Mon Sep 17 00:00:00 2001 From: HARADA Tomoyuki Date: Tue, 9 Jan 2024 14:47:06 +0900 Subject: [PATCH 1584/1891] fix(python): fixes #1419 (#1420) this commit fixes following issue. - python default packages are not installed when installing precompiled version of python --- src/plugins/core/python.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 4c8835bb0..694938dd8 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -133,7 +133,7 @@ impl PythonPlugin { fn install_precompiled(&self, ctx: &InstallContext) -> Result<()> { warn!("installing precompiled python from indygreg/python-build-standalone"); warn!("if you experience issues with this python, switch to python-build"); - warn!("by running: mise settings set python_compile 0"); + warn!("by running: mise settings set python_compile 1"); let config = Config::get(); let precompile_info = self @@ -164,6 +164,10 @@ impl PythonPlugin { file::make_symlink(&install.join("bin/python3"), &install.join("bin/python"))?; self.test_python(&config, &ctx.tv, ctx.pr.as_ref())?; + if let Err(e) = self.get_virtualenv(&config, &ctx.tv, Some(ctx.pr.as_ref())) { + warn!("failed to get virtualenv: {e}"); + } + self.install_default_packages(&config, &ctx.tv, ctx.pr.as_ref())?; Ok(()) } From 03061f973543c54b5076b26b8611f3ec378e6a61 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:34:09 -0600 Subject: [PATCH 1585/1891] rename rtx-vm -> mise-en-dev --- .github/workflows/test.yml | 2 +- scripts/release-aur-bin.sh | 4 ++-- scripts/release-aur.sh | 4 ++-- scripts/release.sh | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7b12fa46e..a349b9eb5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,7 +51,7 @@ jobs: with: push: true author_name: mise[bot] - author_email: 123107610+rtx-vm@users.noreply.github.com + author_email: 123107610+mise-en-dev@users.noreply.github.com - run: just lint coverage: diff --git a/scripts/release-aur-bin.sh b/scripts/release-aur-bin.sh index bf14af7ad..1e1639413 100755 --- a/scripts/release-aur-bin.sh +++ b/scripts/release-aur-bin.sh @@ -70,8 +70,8 @@ pkgname = mise-bin EOF cd aur-bin -git config user.name rtx-vm -git config user.email 123107610+rtx-vm@users.noreply.github.com +git config user.name mise-en-dev +git config user.email 123107610+mise-en-dev@users.noreply.github.com git add .SRCINFO PKGBUILD if git diff-index --quiet HEAD --; then echo "No changes to PKGBUILD or .SRCINFO" diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index d5f360bf6..8e88b33e2 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -76,8 +76,8 @@ pkgname = mise EOF cd aur -git config user.name rtx-vm -git config user.email 123107610+rtx-vm@users.noreply.github.com +git config user.name mise-en-dev +git config user.email 123107610+mise-en-dev@users.noreply.github.com git add .SRCINFO PKGBUILD if git diff-index --quiet HEAD --; then echo "No changes to PKGBUILD or .SRCINFO" diff --git a/scripts/release.sh b/scripts/release.sh index bb43e14b9..aa4688b94 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -2,8 +2,8 @@ set -euxo pipefail echo "::group::Setup" -git config --global user.name rtx-vm -git config --global user.email 123107610+rtx-vm@users.noreply.github.com +git config --global user.name mise-en-dev +git config --global user.email 123107610+mise-en-dev@users.noreply.github.com BASE_DIR="$(cd mise && pwd)" MISE_VERSION=$(cd mise && ./scripts/get-version.sh) From ffb6489c1b0e54f0caa2e6ca4ddf855469950809 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:38:51 -0600 Subject: [PATCH 1586/1891] python: fix some precompiled issues (#1431) * python: fix some precompiled issues Fixes #1430 Fixes #1411 * added settings for python config * added settings for python config --- .idea/inspectionProfiles/Project_Default.xml | 1 + src/cli/settings/ls.rs | 6 + src/cli/settings/set.rs | 6 + src/cli/settings/unset.rs | 6 + src/config/settings.rs | 20 +++ src/env.rs | 11 -- src/plugins/core/python.rs | 121 ++++++++++--------- 7 files changed, 100 insertions(+), 71 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 780774c70..f3292f28f 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -20,6 +20,7 @@
().into_diagnostic()?; + let toml = raw.parse::
()?; let mut shorthands = HashMap::new(); for (k, v) in toml { diff --git a/src/task.rs b/src/task.rs index caffffdb6..03f965ced 100644 --- a/src/task.rs +++ b/src/task.rs @@ -6,8 +6,8 @@ use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; use std::path::PathBuf; +use eyre::Result; use itertools::Itertools; -use miette::Result; use crate::config::config_file::toml::TomlParser; use crate::config::Config; @@ -131,7 +131,7 @@ impl Task { None => tasks .get(name) .map(|task| vec![task]) - .ok_or_else(|| miette!("task not found: {name}")), + .ok_or_else(|| eyre!("task not found: {name}")), }) .collect::>>()? .into_iter() diff --git a/src/test.rs b/src/test.rs index 01293eaf3..a38bb65c8 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,3 +1,4 @@ +use color_eyre::{Help, SectionExt}; use std::env::{join_paths, set_current_dir}; use std::path::PathBuf; @@ -95,12 +96,12 @@ pub fn replace_path(input: &str) -> String { .replace(&*env::MISE_BIN.to_string_lossy(), "mise") } -pub fn cli_run(args: &Vec) -> miette::Result<(String, String)> { +pub fn cli_run(args: &Vec) -> eyre::Result<(String, String)> { Config::reset(); *env::ARGS.write().unwrap() = args.clone(); STDOUT.lock().unwrap().clear(); STDERR.lock().unwrap().clear(); - Cli::run(args)?; //.with_context(|| format!("Command: {}", args.join(" ")))?; + Cli::run(args).with_section(|| format!("{}", args.join(" ").header("Command:")))?; let stdout = clean_output(STDOUT.lock().unwrap().join("\n")); let stderr = clean_output(STDERR.lock().unwrap().join("\n")); diff --git a/src/timeout.rs b/src/timeout.rs index f6f902393..a0f2d3c27 100644 --- a/src/timeout.rs +++ b/src/timeout.rs @@ -2,7 +2,7 @@ use std::sync::mpsc; use std::thread; use std::time::Duration; -use miette::{IntoDiagnostic, Result}; +use color_eyre::eyre::{Context, Result}; pub fn run_with_timeout(f: F, timeout: Duration) -> Result where @@ -16,7 +16,6 @@ where // If sending fails, the timeout has already been reached. let _ = tx.send(result); }); - rx.recv_timeout(timeout) //.context("timed out") - }) - .into_diagnostic()? + rx.recv_timeout(timeout).context("timed out") + })? } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 9d8d90efc..da02c6daf 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; +use eyre::Result; use itertools::Itertools; -use miette::Result; use crate::cli::args::tool::ToolArg; use crate::config::{Config, Settings}; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index e11ce5808..a0d597288 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -5,9 +5,9 @@ use std::sync::{Arc, Mutex}; use std::thread; use console::truncate_str; +use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; -use miette::Result; use rayon::prelude::*; pub use builder::ToolsetBuilder; diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index bed02feb2..35afe8f6f 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -5,7 +5,7 @@ use std::fs; use std::hash::{Hash, Hasher}; use std::path::PathBuf; -use miette::{IntoDiagnostic, Result}; +use eyre::Result; use versions::{Chunk, Version}; use crate::config::Config; @@ -227,7 +227,7 @@ impl ToolVersion { path: PathBuf, opts: ToolVersionOptions, ) -> Result { - let path = fs::canonicalize(path).into_diagnostic()?; + let path = fs::canonicalize(path)?; let request = ToolVersionRequest::Path(tool.name().into(), path); let version = request.version(); Ok(Self::new(tool, request, opts, version)) diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 32ec51764..208ceb6d2 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -1,7 +1,7 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use miette::Result; +use eyre::Result; use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionOptions}; diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index c2bd90670..76da1a9ee 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,18 +1,16 @@ -use std::sync::Mutex; - -use demand::Confirm; -use miette::{IntoDiagnostic, Result}; - use crate::ui; +use demand::Confirm; +use std::io; +use std::sync::Mutex; static MUTEX: Mutex<()> = Mutex::new(()); -pub fn confirm>(message: S) -> Result { +pub fn confirm>(message: S) -> io::Result { let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once ui::handle_ctrlc(); if !console::user_attended_stderr() { return Ok(false); } - Confirm::new(message).run().into_diagnostic() + Confirm::new(message).run() } From 1dcac6d4e05c80b56d1371f434776057d3ca9dc7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:42:13 -0600 Subject: [PATCH 1603/1891] release: fix mise-docs publishing --- scripts/release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index aa4688b94..c424a9afb 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -73,12 +73,12 @@ if [[ "$DRY_RUN" != 1 ]]; then fi echo "::group::Publish mise-docs" -cp ./mise/docs/cli-reference.md ./mise-docs/docs/cli/index.md +cp ./mise/docs/cli-reference.md ./mise-docs/cli/index.md pushd mise-docs if [[ -z $(git status -s) ]]; then echo "No changes to docs" else - git add docs/cli/index.md + git add cli/index.md git commit -m "mise ${MISE_VERSION#v}" fi popd From d4f54adbbf840599aeb4229c9330262569b563b5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:42:57 -0600 Subject: [PATCH 1604/1891] release: temporarily disable standalone test --- scripts/test-standalone.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test-standalone.sh b/scripts/test-standalone.sh index 623a200a0..3e9b0b9c5 100755 --- a/scripts/test-standalone.sh +++ b/scripts/test-standalone.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -euxo pipefail +exit 0 # TODO: enable this after the next release BASE_DIR="$(pwd)" RELEASE_DIR="$(pwd)/tmp" MISE_VERSION="v$(curl -fsSL https://mise.jdx.dev/VERSION)" From 76b2635b479cdc12ada4039cc388f1bb637a0edd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:44:06 -0600 Subject: [PATCH 1605/1891] chore: Release mise version 2024.1.18 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da2b0998c..6c5a65f8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.17" +version = "2024.1.18" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index f4e504a7d..d29e56814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.17" +version = "2024.1.18" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index d1bdcbc88..2d8590340 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.17 +mise 2024.1.18 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 2b2996cea..3ce2991da 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.17"; + version = "2024.1.18"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index d2b38831c..a2450e7f1 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.17" +.TH mise 1 "mise 2024.1.18" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -163,6 +163,6 @@ Examples: $ mise use \-g node@system Use system node everywhere unless overridden $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH .SH VERSION -v2024.1.17 +v2024.1.18 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 89e63e24a..3f7451f9e 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.17 +Version: 2024.1.18 Release: 1 URL: https://github.com/jdx/mise/ Group: System From dedb7624ad4708ce0434a963737a17754075d3a0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 12 Jan 2024 17:22:36 -0600 Subject: [PATCH 1606/1891] refactor: remove PluginName type alias --- src/cli/alias/ls.rs | 3 +-- src/cli/alias/mod.rs | 4 +--- src/cli/args/tool.rs | 4 ++-- src/cli/global.rs | 3 +-- src/cli/local.rs | 5 ++--- src/cli/ls.rs | 4 ++-- src/cli/plugins/install.rs | 10 +++++----- src/cli/plugins/update.rs | 4 ++-- src/cli/prune.rs | 4 ++-- src/cli/sync/node.rs | 7 +++---- src/cli/sync/python.rs | 3 +-- src/cli/use.rs | 3 +-- src/config/config_file/legacy_version.rs | 6 +++--- src/config/config_file/mise_toml.rs | 21 +++++++++------------ src/config/config_file/mod.rs | 7 +++---- src/config/config_file/tool_versions.rs | 14 +++++++------- src/config/mod.rs | 20 ++++++++++---------- src/errors.rs | 6 ++---- src/plugins/external_plugin.rs | 10 +++++----- src/plugins/mod.rs | 6 ++---- src/runtime_symlinks.rs | 4 ++-- src/toolset/mod.rs | 10 +++++----- src/toolset/tool_version.rs | 4 ++-- 23 files changed, 73 insertions(+), 89 deletions(-) diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 82d66efde..4fdb9dcad 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -2,7 +2,6 @@ use eyre::Result; use tabled::Tabled; use crate::config::Config; -use crate::plugins::PluginName; use crate::ui::table; /// List aliases @@ -18,7 +17,7 @@ use crate::ui::table; pub struct AliasLs { /// Show aliases for #[clap()] - pub plugin: Option, + pub plugin: Option, /// Don't show table header #[clap(long)] diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index c34a2c475..9dc4d8ca7 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -1,8 +1,6 @@ use clap::Subcommand; use eyre::Result; -use crate::plugins::PluginName; - mod get; mod ls; mod set; @@ -16,7 +14,7 @@ pub struct Alias { /// filter aliases by plugin #[clap(short, long)] - pub plugin: Option, + pub plugin: Option, /// Don't show table header #[clap(long)] diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index 5d3f71654..88764457b 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -4,12 +4,12 @@ use std::str::FromStr; use console::style; use regex::Regex; -use crate::plugins::{unalias_plugin, PluginName}; +use crate::plugins::unalias_plugin; use crate::toolset::ToolVersionRequest; #[derive(Debug, Clone, Eq, PartialEq)] pub struct ToolArg { - pub plugin: PluginName, + pub plugin: String, pub tvr: Option, } diff --git a/src/cli/global.rs b/src/cli/global.rs index 4cd1d2b95..cbcd50acc 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -4,7 +4,6 @@ use crate::cli::args::tool::ToolArg; use crate::cli::local::local; use crate::config::Config; use crate::env; -use crate::plugins::PluginName; /// Sets/gets the global tool version(s) /// @@ -37,7 +36,7 @@ pub struct Global { /// Remove the plugin(s) from ~/.tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] - remove: Option>, + remove: Option>, /// Get the path of the global config file #[clap(long)] diff --git a/src/cli/local.rs b/src/cli/local.rs index 5c73b210d..16422aee6 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -8,7 +8,6 @@ use crate::cli::args::tool::ToolArg; use crate::config::{config_file, Config, Settings}; use crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; -use crate::plugins::PluginName; use crate::{env, file}; /// Sets/gets tool version in local .tool-versions or .mise.toml @@ -45,7 +44,7 @@ pub struct Local { /// Remove the plugin(s) from .tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] - remove: Option>, + remove: Option>, /// Get the path of the config file #[clap(long)] @@ -95,7 +94,7 @@ pub fn local( config: &Config, path: &Path, runtime: Vec, - remove: Option>, + remove: Option>, pin: bool, fuzzy: bool, show_path: bool, diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 321a938bd..fbdc25742 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -13,7 +13,7 @@ use versions::Versioning; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; -use crate::plugins::{unalias_plugin, Plugin, PluginName}; +use crate::plugins::{unalias_plugin, Plugin}; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; use crate::ui::table; @@ -222,7 +222,7 @@ impl Ls { } } -type JSONOutput = IndexMap>; +type JSONOutput = IndexMap>; #[derive(Serialize)] struct JSONToolVersion { diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index d7d4d23c2..5fc38025c 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -5,7 +5,7 @@ use url::Url; use crate::config::{Config, Settings}; use crate::plugins::core::CORE_PLUGINS; -use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin, PluginName}; +use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin}; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::style; @@ -23,7 +23,7 @@ pub struct PluginsInstall { /// e.g.: node, ruby /// Can specify multiple plugins: `mise plugins install node ruby python` #[clap(required_unless_present = "all", verbatim_doc_comment)] - new_plugin: Option, + new_plugin: Option, /// The git url of the plugin /// e.g.: https://github.com/asdf-vm/asdf-node.git @@ -63,7 +63,7 @@ impl PluginsInstall { let name = style::eblue(name); bail!("{name} is a core plugin and does not need to be installed"); } - let mut plugins: Vec = vec![name]; + let mut plugins: Vec = vec![name]; if let Some(second) = self.git_url.clone() { plugins.push(second); }; @@ -88,7 +88,7 @@ impl PluginsInstall { Ok(()) } - fn install_many(&self, plugins: Vec, mpr: &MultiProgressReport) -> Result<()> { + fn install_many(&self, plugins: Vec, mpr: &MultiProgressReport) -> Result<()> { ThreadPoolBuilder::new() .num_threads(Settings::get().jobs) .build()? @@ -103,7 +103,7 @@ impl PluginsInstall { fn install_one( &self, - name: PluginName, + name: String, git_url: Option, mpr: &MultiProgressReport, ) -> Result<()> { diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index dc330ebac..3a97ac1bf 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -3,7 +3,7 @@ use eyre::Result; use rayon::prelude::*; use crate::config::{Config, Settings}; -use crate::plugins::{unalias_plugin, PluginName}; +use crate::plugins::unalias_plugin; use crate::ui::multi_progress_report::MultiProgressReport; /// Updates a plugin to the latest version @@ -14,7 +14,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; pub struct Update { /// Plugin(s) to update #[clap()] - plugin: Option>, + plugin: Option>, /// Number of jobs to run in parallel /// Default: 4 diff --git a/src/cli/prune.rs b/src/cli/prune.rs index fdae7afe4..e2a84c167 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -5,7 +5,7 @@ use console::style; use eyre::Result; use crate::config::{Config, Settings}; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; @@ -21,7 +21,7 @@ use crate::ui::prompt; pub struct Prune { /// Prune only versions from these plugins #[clap()] - pub plugin: Option>, + pub plugin: Option>, /// Do not actually delete anything #[clap(long, short = 'n')] diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 90c56919c..aa88f5c25 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -6,7 +6,6 @@ use itertools::sorted; use crate::config::Config; use crate::env::{NODENV_ROOT, NVM_DIR}; use crate::file; -use crate::plugins::PluginName; use crate::{cmd, dirs}; /// Symlinks all tool versions from an external tool into mise @@ -49,7 +48,7 @@ impl SyncNode { } fn run_brew(self, config: &Config) -> Result<()> { - let tool = config.get_or_create_plugin(&PluginName::from("node")); + let tool = config.get_or_create_plugin(&String::from("node")); let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); let installed_versions_path = dirs::INSTALLS.join("node"); @@ -70,7 +69,7 @@ impl SyncNode { } fn run_nvm(self, config: &Config) -> Result<()> { - let tool = config.get_or_create_plugin(&PluginName::from("node")); + let tool = config.get_or_create_plugin(&String::from("node")); let nvm_versions_path = NVM_DIR.join("versions").join("node"); let installed_versions_path = dirs::INSTALLS.join("node"); @@ -88,7 +87,7 @@ impl SyncNode { } fn run_nodenv(self, config: &Config) -> Result<()> { - let tool = config.get_or_create_plugin(&PluginName::from("node")); + let tool = config.get_or_create_plugin(&String::from("node")); let nodenv_versions_path = NODENV_ROOT.join("versions"); let installed_versions_path = dirs::INSTALLS.join("node"); diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 1ecc4787a..743f845f0 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -5,7 +5,6 @@ use crate::config::Config; use crate::dirs; use crate::env::PYENV_ROOT; use crate::file; -use crate::plugins::PluginName; /// Symlinks all tool versions from an external tool into mise /// @@ -21,7 +20,7 @@ pub struct SyncPython { impl SyncPython { pub fn run(self) -> Result<()> { let config = Config::try_get()?; - let python = config.get_or_create_plugin(&PluginName::from("python")); + let python = config.get_or_create_plugin(&String::from("python")); let pyenv_versions_path = PYENV_ROOT.join("versions"); let installed_python_versions_path = dirs::INSTALLS.join("python"); diff --git a/src/cli/use.rs b/src/cli/use.rs index eb075d98a..d8f2db595 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -11,7 +11,6 @@ use crate::env::{ MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME, MISE_GLOBAL_CONFIG_FILE, }; use crate::file::display_path; -use crate::plugins::PluginName; use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::{env, file}; @@ -65,7 +64,7 @@ pub struct Use { /// Remove the tool(s) from config file #[clap(long, value_name = "TOOL", aliases = ["rm", "unset"])] - remove: Vec, + remove: Vec, /// Specify a path to a config file or directory /// If a directory is specified, it will look for .mise.toml (default) or .tool-versions diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 89e046eee..10ccd3f1a 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; #[derive(Debug)] @@ -41,11 +41,11 @@ impl ConfigFile for LegacyVersionFile { self.path.as_path() } - fn remove_plugin(&mut self, _plugin_name: &PluginName) { + fn remove_plugin(&mut self, _plugin_name: &String) { unimplemented!() } - fn replace_versions(&mut self, _plugin_name: &PluginName, _versions: &[String]) { + fn replace_versions(&mut self, _plugin_name: &String, _versions: &[String]) { unimplemented!() } diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 2a8dc973d..fc6a01027 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -13,7 +13,7 @@ use versions::Versioning; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; use crate::config::AliasMap; use crate::file::{create_dir_all, display_path}; -use crate::plugins::{unalias_plugin, PluginName}; +use crate::plugins::unalias_plugin; use crate::task::Task; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ @@ -357,7 +357,7 @@ impl MiseToml { &self, key: &str, v: &Item, - plugin_name: &PluginName, + plugin_name: &String, ) -> Result { let source = ToolSource::MiseToml(self.path.clone()); let mut tool_version_list = ToolVersionList::new(plugin_name.to_string(), source); @@ -404,7 +404,7 @@ impl MiseToml { &self, key: &str, v: &Item, - plugin_name: &PluginName, + plugin_name: &String, ) -> Result<(ToolVersionRequest, ToolVersionOptions)> { match v.as_table_like() { Some(table) => { @@ -470,7 +470,7 @@ impl MiseToml { &self, key: &str, v: &Value, - plugin_name: &PluginName, + plugin_name: &String, ) -> Result { match v.as_str() { Some(s) => { @@ -618,7 +618,7 @@ impl ConfigFile for MiseToml { } } - fn plugins(&self) -> HashMap { + fn plugins(&self) -> HashMap { self.plugins.clone() } @@ -638,7 +638,7 @@ impl ConfigFile for MiseToml { self.tasks.iter().collect() } - fn remove_plugin(&mut self, plugin: &PluginName) { + fn remove_plugin(&mut self, plugin: &String) { self.toolset.versions.remove(plugin); if let Some(tools) = self.doc.get_mut("tools") { if let Some(tools) = tools.as_table_like_mut() { @@ -650,7 +650,7 @@ impl ConfigFile for MiseToml { } } - fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { + fn replace_versions(&mut self, plugin_name: &String, versions: &[String]) { if let Some(plugin) = self.toolset.versions.get_mut(plugin_name) { plugin.requests = versions .iter() @@ -871,10 +871,7 @@ mod tests { node = ["16.0.0", "18.0.0"] "#}) .unwrap(); - cf.replace_versions( - &PluginName::from("node"), - &["16.0.1".into(), "18.0.1".into()], - ); + cf.replace_versions(&String::from("node"), &["16.0.1".into(), "18.0.1".into()]); assert_debug_snapshot!(cf.toolset); let cf: Box = Box::new(cf); @@ -891,7 +888,7 @@ mod tests { node = ["16.0.0", "18.0.0"] "#}) .unwrap(); - cf.remove_plugin(&PluginName::from("node")); + cf.remove_plugin(&String::from("node")); assert_debug_snapshot!(cf.toolset); let cf: Box = Box::new(cf); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 9bb05128c..4838bc2cd 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -16,7 +16,6 @@ use crate::config::{global_config_files, system_config_files, AliasMap, Config, use crate::errors::Error::UntrustedConfig; use crate::file::display_path; use crate::hash::{file_hash_sha256, hash_to_str}; -use crate::plugins::PluginName; use crate::task::Task; use crate::toolset::{ToolVersionList, Toolset}; use crate::ui::{prompt, style}; @@ -56,7 +55,7 @@ pub trait ConfigFile: Debug + Send + Sync { None => None, } } - fn plugins(&self) -> HashMap { + fn plugins(&self) -> HashMap { Default::default() } fn env(&self) -> HashMap { @@ -71,8 +70,8 @@ pub trait ConfigFile: Debug + Send + Sync { fn tasks(&self) -> Vec<&Task> { Default::default() } - fn remove_plugin(&mut self, _plugin_name: &PluginName); - fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]); + fn remove_plugin(&mut self, _plugin_name: &String); + fn replace_versions(&mut self, plugin_name: &String, versions: &[String]); fn save(&self) -> Result<()>; fn dump(&self) -> String; fn to_toolset(&self) -> &Toolset; diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index c23fac069..f4a3b3e24 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -12,7 +12,7 @@ use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::file; use crate::file::display_path; -use crate::plugins::{unalias_plugin, PluginName}; +use crate::plugins::unalias_plugin; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -26,7 +26,7 @@ pub struct ToolVersions { context: Context, path: PathBuf, pre: String, - plugins: IndexMap, + plugins: IndexMap, toolset: Toolset, } @@ -86,8 +86,8 @@ impl ToolVersions { }) } - fn parse_plugins(input: &str) -> Result> { - let mut plugins: IndexMap = IndexMap::new(); + fn parse_plugins(input: &str) -> Result> { + let mut plugins: IndexMap = IndexMap::new(); for line in input.lines() { if line.trim_start().starts_with('#') { if let Some(prev) = &mut plugins.values_mut().last() { @@ -119,7 +119,7 @@ impl ToolVersions { Ok(plugins) } - fn add_version(&mut self, plugin: &PluginName, version: &str) { + fn add_version(&mut self, plugin: &String, version: &str) { self.get_or_create_plugin(plugin) .versions .push(version.to_string()); @@ -160,11 +160,11 @@ impl ConfigFile for ToolVersions { self.path.as_path() } - fn remove_plugin(&mut self, plugin: &PluginName) { + fn remove_plugin(&mut self, plugin: &String) { self.plugins.remove(plugin); } - fn replace_versions(&mut self, plugin_name: &PluginName, versions: &[String]) { + fn replace_versions(&mut self, plugin_name: &String, versions: &[String]) { self.get_or_create_plugin(plugin_name).versions.clear(); for version in versions { self.add_version(plugin_name, version); diff --git a/src/config/mod.rs b/src/config/mod.rs index 0d6fd87bc..3853782a9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -19,7 +19,7 @@ use crate::config::config_file::ConfigFile; use crate::config::tracking::Tracker; use crate::file::display_path; use crate::plugins::core::{PluginMap, CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; -use crate::plugins::{ExternalPlugin, Plugin, PluginName, PluginType}; +use crate::plugins::{ExternalPlugin, Plugin, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::task::Task; use crate::ui::style; @@ -29,9 +29,9 @@ pub mod config_file; pub mod settings; mod tracking; -type AliasMap = BTreeMap>; +type AliasMap = BTreeMap>; type ConfigMap = IndexMap>; -type ToolMap = BTreeMap>; +type ToolMap = BTreeMap>; #[derive(Default)] pub struct Config { @@ -43,7 +43,7 @@ pub struct Config { pub project_root: Option, all_aliases: OnceCell, plugins: RwLock, - repo_urls: HashMap, + repo_urls: HashMap, shorthands: OnceCell>, tasks: OnceCell>, } @@ -102,7 +102,7 @@ impl Config { .get_or_init(|| get_shorthands(&Settings::get())) } - pub fn get_repo_url(&self, plugin_name: &PluginName) -> Option { + pub fn get_repo_url(&self, plugin_name: &String) -> Option { match self.repo_urls.get(plugin_name) { Some(url) => Some(url), None => self.get_shorthands().get(plugin_name), @@ -300,7 +300,7 @@ fn load_plugins(settings: &Settings) -> Result { Ok(tools) } -fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap> { +fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap> { if !settings.legacy_version_file { return BTreeMap::new(); } @@ -325,10 +325,10 @@ fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap>>() + .collect::>>() .into_iter() .flatten() - .collect::>(); + .collect::>(); let mut legacy_filenames = BTreeMap::new(); for (filename, plugin) in legacy { @@ -420,7 +420,7 @@ pub fn system_config_files() -> Vec { fn load_all_config_files( config_filenames: &[PathBuf], tools: &PluginMap, - legacy_filenames: &BTreeMap>, + legacy_filenames: &BTreeMap>, ) -> Result { Ok(config_filenames .iter() @@ -448,7 +448,7 @@ fn load_all_config_files( fn parse_config_file( f: &PathBuf, - legacy_filenames: &BTreeMap>, + legacy_filenames: &BTreeMap>, tools: &ToolMap, ) -> Result> { match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { diff --git a/src/errors.rs b/src/errors.rs index 0f4fa2f90..f1873dc5c 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,14 +2,12 @@ use std::process::ExitStatus; use thiserror::Error; -use crate::plugins::PluginName; - #[derive(Debug, Error)] pub enum Error { #[error("[{0}] plugin not installed")] - PluginNotInstalled(PluginName), + PluginNotInstalled(String), #[error("{0}@{1} not installed")] - VersionNotInstalled(PluginName, String), + VersionNotInstalled(String, String), #[error("{} exited with non-zero status: {}", .0, render_exit_status(.1))] ScriptFailed(String, Option), #[error("Config file is not trusted.\nTrust it with `mise trust`.")] diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 5af68c7f7..7d516194b 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -27,7 +27,7 @@ use crate::install_context::InstallContext; use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::mise_plugin_toml::MisePluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; -use crate::plugins::{Plugin, PluginName, PluginType, Script, ScriptManager}; +use crate::plugins::{Plugin, PluginType, Script, ScriptManager}; use crate::timeout::run_with_timeout; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -37,7 +37,7 @@ use crate::{dirs, env, file, http}; /// This represents a plugin installed to ~/.local/share/mise/plugins pub struct ExternalPlugin { - pub name: PluginName, + pub name: String, pub plugin_path: PathBuf, pub repo_url: Option, pub toml: MisePluginToml, @@ -53,7 +53,7 @@ pub struct ExternalPlugin { } impl ExternalPlugin { - pub fn new(name: PluginName) -> Self { + pub fn new(name: String) -> Self { let plugin_path = dirs::PLUGINS.join(&name); let cache_path = dirs::CACHE.join(&name); let mut toml_path = plugin_path.join("mise.plugin.toml"); @@ -87,7 +87,7 @@ impl ExternalPlugin { name, } } - pub fn newa(name: PluginName) -> Arc { + pub fn newa(name: String) -> Arc { Arc::new(Self::new(name)) } @@ -737,7 +737,7 @@ mod tests { #[test] fn test_debug() { - let plugin = ExternalPlugin::new(PluginName::from("dummy")); + let plugin = ExternalPlugin::new(String::from("dummy")); assert!(format!("{:?}", plugin).starts_with("ExternalPlugin { name: \"dummy\"")); } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 7c3719dba..86e372874 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -31,8 +31,6 @@ mod external_plugin_cache; mod mise_plugin_toml; mod script_manager; -pub type PluginName = String; - pub trait Plugin: Debug + Send + Sync { fn name(&self) -> &str; fn get_type(&self) -> PluginType { @@ -404,7 +402,7 @@ mod tests { #[test] fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); - let plugin = ExternalPlugin::newa(PluginName::from("tiny")); + let plugin = ExternalPlugin::newa(String::from("tiny")); let version = plugin .latest_version(Some("1.0.0".into())) .unwrap() @@ -416,7 +414,7 @@ mod tests { #[test] fn test_latest_stable() { - let plugin = ExternalPlugin::new(PluginName::from("dummy")); + let plugin = ExternalPlugin::new(String::from("dummy")); let version = plugin.latest_version(None).unwrap().unwrap(); assert_str_eq!(version, "2.0.0"); } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 9a6a8ee22..a501da4a3 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -110,14 +110,14 @@ pub fn is_runtime_symlink(path: &Path) -> bool { #[cfg(test)] mod tests { use crate::config::Config; - use crate::plugins::{ExternalPlugin, PluginName}; + use crate::plugins::ExternalPlugin; use super::*; #[test] fn test_list_symlinks() { let config = Config::load().unwrap(); - let plugin = ExternalPlugin::newa(PluginName::from("tiny")); + let plugin = ExternalPlugin::newa(String::from("tiny")); let symlinks = list_symlinks(&config, plugin).unwrap(); assert_debug_snapshot!(symlinks); } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index a0d597288..ae4d7db09 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -21,7 +21,7 @@ use crate::env; use crate::env::TERM_WIDTH; use crate::install_context::InstallContext; use crate::path_env::PathEnv; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::runtime_symlinks; use crate::shims; use crate::ui::multi_progress_report::MultiProgressReport; @@ -60,9 +60,9 @@ impl InstallOptions { /// merge in other toolsets from various sources #[derive(Debug, Default, Clone)] pub struct Toolset { - pub versions: IndexMap, + pub versions: IndexMap, pub source: Option, - pub disable_tools: BTreeSet, + pub disable_tools: BTreeSet, } impl Toolset { @@ -115,7 +115,7 @@ impl Toolset { self.install_versions(config, versions, &mpr, opts) } - pub fn list_missing_plugins(&self, config: &Config) -> Vec { + pub fn list_missing_plugins(&self, config: &Config) -> Vec { self.versions .keys() .map(|p| config.get_or_create_plugin(p)) @@ -199,7 +199,7 @@ impl Toolset { &self, config: &Config, ) -> Result, ToolVersion)>> { - let current_versions: HashMap<(PluginName, String), (Arc, ToolVersion)> = self + let current_versions: HashMap<(String, String), (Arc, ToolVersion)> = self .list_current_versions() .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p.clone(), tv))) diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 35afe8f6f..4d3172e1b 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -11,14 +11,14 @@ use versions::{Chunk, Version}; use crate::config::Config; use crate::dirs; use crate::hash::hash_to_str; -use crate::plugins::{Plugin, PluginName}; +use crate::plugins::Plugin; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; /// represents a single version of a tool for a particular plugin #[derive(Debug, Clone)] pub struct ToolVersion { pub request: ToolVersionRequest, - pub plugin_name: PluginName, + pub plugin_name: String, pub version: String, pub opts: ToolVersionOptions, } From ec4efea054626f9451bb54831abdd95ff98c64d1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 12 Jan 2024 17:37:05 -0600 Subject: [PATCH 1607/1891] refactor: rename Plugin trait to Forge Paves the way for https://github.com/jdx/mise/discussions/1250 --- src/cli/current.rs | 5 +- src/cli/ls.rs | 17 +- src/cli/ls_remote.rs | 6 +- src/cli/outdated.rs | 4 +- src/cli/plugins/install.rs | 3 +- src/cli/prune.rs | 6 +- src/cli/uninstall.rs | 9 +- src/cli/upgrade.rs | 6 +- src/config/config_file/legacy_version.rs | 8 +- src/config/config_file/mise_toml.rs | 18 +- src/config/config_file/mod.rs | 4 +- src/config/config_file/tool_versions.rs | 6 +- src/config/mod.rs | 11 +- src/forge/mod.rs | 340 ++++++++++++++++++++++ src/main.rs | 1 + src/plugins/core/bun.rs | 4 +- src/plugins/core/deno.rs | 4 +- src/plugins/core/erlang.rs | 4 +- src/plugins/core/go.rs | 4 +- src/plugins/core/java.rs | 4 +- src/plugins/core/mod.rs | 8 +- src/plugins/core/node.rs | 4 +- src/plugins/core/python.rs | 4 +- src/plugins/core/ruby.rs | 4 +- src/plugins/external_plugin.rs | 9 +- src/plugins/mod.rs | 352 +---------------------- src/runtime_symlinks.rs | 9 +- src/shims.rs | 4 +- src/toolset/mod.rs | 18 +- src/toolset/tool_version.rs | 18 +- src/toolset/tool_version_request.rs | 4 +- 31 files changed, 456 insertions(+), 442 deletions(-) create mode 100644 src/forge/mod.rs diff --git a/src/cli/current.rs b/src/cli/current.rs index 2a280e784..995bb0d69 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -2,7 +2,8 @@ use console::style; use eyre::Result; use crate::config::Config; -use crate::plugins::{unalias_plugin, Plugin}; +use crate::forge::Forge; +use crate::plugins::unalias_plugin; use crate::toolset::{Toolset, ToolsetBuilder}; /// Shows current active and installed runtime versions @@ -35,7 +36,7 @@ impl Current { } } - fn one(&self, ts: Toolset, tool: &dyn Plugin) -> Result<()> { + fn one(&self, ts: Toolset, tool: &dyn Forge) -> Result<()> { if !tool.is_installed() { warn!("Plugin {} is not installed", tool.name()); return Ok(()); diff --git a/src/cli/ls.rs b/src/cli/ls.rs index fbdc25742..2c5253aa8 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -13,7 +13,8 @@ use versions::Versioning; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; -use crate::plugins::{unalias_plugin, Plugin}; +use crate::forge::Forge; +use crate::plugins::unalias_plugin; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; use crate::ui::table; @@ -180,7 +181,7 @@ impl Ls { tsb = tsb.with_tools(&plugins); } let ts = tsb.build(config)?; - let mut versions: HashMap<(String, String), (Arc, ToolVersion)> = ts + let mut versions: HashMap<(String, String), (Arc, ToolVersion)> = ts .list_installed_versions(config)? .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) @@ -190,7 +191,7 @@ impl Ls { .list_current_versions() .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) - .collect::, ToolVersion)>>(); + .collect::, ToolVersion)>>(); versions.extend(active.clone()); @@ -236,13 +237,13 @@ struct JSONToolVersion { symlinked_to: Option, } -type RuntimeRow = (Arc, ToolVersion, Option); +type RuntimeRow = (Arc, ToolVersion, Option); #[derive(Tabled)] #[tabled(rename_all = "PascalCase")] struct Row { #[tabled(display_with = "Self::display_plugin")] - plugin: Arc, + plugin: Arc, version: VersionStatus, #[tabled(rename = "Config Source", display_with = "Self::display_source")] source: Option, @@ -257,7 +258,7 @@ impl Row { None => String::new(), } } - fn display_plugin(plugin: &Arc) -> String { + fn display_plugin(plugin: &Arc) -> String { style(plugin).blue().to_string() } fn display_source(source: &Option) -> String { @@ -288,8 +289,8 @@ enum VersionStatus { Symlink(String, PathBuf, bool), } -impl From<(&dyn Plugin, &ToolVersion, &Option)> for VersionStatus { - fn from((p, tv, source): (&dyn Plugin, &ToolVersion, &Option)) -> Self { +impl From<(&dyn Forge, &ToolVersion, &Option)> for VersionStatus { + fn from((p, tv, source): (&dyn Forge, &ToolVersion, &Option)) -> Self { if let Some(symlink_path) = p.symlink_path(tv) { VersionStatus::Symlink(tv.version.clone(), symlink_path, source.is_some()) } else if !p.is_version_installed(tv) { diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 694984ca3..f9616eb40 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -6,7 +6,7 @@ use rayon::prelude::*; use crate::cli::args::tool::ToolArg; use crate::config::Config; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::toolset::ToolVersionRequest; use crate::ui::multi_progress_report::MultiProgressReport; @@ -41,7 +41,7 @@ impl LsRemote { } } - fn run_single(self, plugin: Arc) -> Result<()> { + fn run_single(self, plugin: Arc) -> Result<()> { let prefix = match &self.plugin { Some(tool_arg) => match &tool_arg.tvr { Some(ToolVersionRequest::Version(_, v)) => Some(v.clone()), @@ -86,7 +86,7 @@ impl LsRemote { Ok(()) } - fn get_plugin(&self, config: &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 2b8a07f14..fc79b76fa 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -6,7 +6,7 @@ use eyre::Result; use crate::cli::args::tool::ToolArg; use crate::config::Config; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolsetBuilder}; /// Shows outdated tool versions @@ -108,7 +108,7 @@ impl Outdated { } } -type OutputVec = Vec<(Arc, ToolVersion, String)>; +type OutputVec = Vec<(Arc, ToolVersion, String)>; static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 5fc38025c..53143b4e2 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -4,8 +4,9 @@ use rayon::ThreadPoolBuilder; use url::Url; use crate::config::{Config, Settings}; +use crate::forge::Forge; use crate::plugins::core::CORE_PLUGINS; -use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin}; +use crate::plugins::{unalias_plugin, ExternalPlugin}; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::style; diff --git a/src/cli/prune.rs b/src/cli/prune.rs index e2a84c167..963209196 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -5,7 +5,7 @@ use console::style; use eyre::Result; use crate::config::{Config, Settings}; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::prompt; @@ -36,7 +36,7 @@ impl Prune { .list_installed_versions(&config)? .into_iter() .map(|(p, tv)| (tv.to_string(), (p, tv))) - .collect::, ToolVersion)>>(); + .collect::, ToolVersion)>>(); if let Some(plugins) = &self.plugin { to_delete.retain(|_, (_, tv)| plugins.contains(&tv.plugin_name)); @@ -53,7 +53,7 @@ impl Prune { self.delete(to_delete.into_values().collect()) } - fn delete(&self, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { + fn delete(&self, to_delete: Vec<(Arc, ToolVersion)>) -> Result<()> { let settings = Settings::try_get()?; let mpr = MultiProgressReport::get(); for (p, tv) in to_delete { diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 308d5a5d3..0cab74c87 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -7,7 +7,7 @@ use rayon::prelude::*; use crate::cli::args::tool::ToolArg; use crate::config::Config; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::{runtime_symlinks, shims}; @@ -72,10 +72,7 @@ impl Uninstall { Ok(()) } - fn get_all_tool_versions( - &self, - config: &Config, - ) -> Result, ToolVersion)>> { + fn get_all_tool_versions(&self, config: &Config) -> Result, ToolVersion)>> { let ts = ToolsetBuilder::new().build(config)?; let tool_versions = ts .list_installed_versions(config)? @@ -86,7 +83,7 @@ impl Uninstall { fn get_requested_tool_versions( &self, config: &Config, - ) -> Result, ToolVersion)>> { + ) -> Result, ToolVersion)>> { let runtimes = ToolArg::double_tool_condition(&self.installed_tool); let tool_versions = runtimes .into_par_iter() diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 6753d01f1..ce2765b28 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -6,7 +6,7 @@ use eyre::{Context, Result}; use crate::cli::args::tool::ToolArg; use crate::config::Config; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::shims; use crate::toolset::{InstallOptions, ToolVersion, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -115,7 +115,7 @@ impl Upgrade { fn uninstall_old_version( &self, - tool: Arc, + tool: Arc, tv: &ToolVersion, pr: &dyn SingleReport, ) -> Result<()> { @@ -143,7 +143,7 @@ impl Upgrade { } } -type OutputVec = Vec<(Arc, ToolVersion, String)>; +type OutputVec = Vec<(Arc, ToolVersion, String)>; #[cfg(test)] pub mod tests { diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 10ccd3f1a..2088850d3 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use eyre::Result; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; #[derive(Debug)] @@ -15,7 +15,7 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(path: PathBuf, plugins: &[&Arc]) -> Result { + pub fn parse(path: PathBuf, plugins: &[&Arc]) -> Result { let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.clone())); for plugin in plugins { @@ -41,11 +41,11 @@ impl ConfigFile for LegacyVersionFile { self.path.as_path() } - fn remove_plugin(&mut self, _plugin_name: &String) { + fn remove_plugin(&mut self, _plugin_name: &str) { unimplemented!() } - fn replace_versions(&mut self, _plugin_name: &String, _versions: &[String]) { + fn replace_versions(&mut self, _plugin_name: &str, _versions: &[String]) { unimplemented!() } diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index fc6a01027..b446751c0 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -404,7 +404,7 @@ impl MiseToml { &self, key: &str, v: &Item, - plugin_name: &String, + plugin_name: &str, ) -> Result<(ToolVersionRequest, ToolVersionOptions)> { match v.as_table_like() { Some(table) => { @@ -417,7 +417,7 @@ impl MiseToml { match path.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - ToolVersionRequest::Path(plugin_name.clone(), s.into()) + ToolVersionRequest::Path(plugin_name.to_string(), s.into()) } _ => parse_error!(format!("{}.path", key), v, "string"), } @@ -425,7 +425,7 @@ impl MiseToml { match prefix.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - ToolVersionRequest::Prefix(plugin_name.clone(), s) + ToolVersionRequest::Prefix(plugin_name.to_string(), s) } _ => parse_error!(format!("{}.prefix", key), v, "string"), } @@ -433,7 +433,7 @@ impl MiseToml { match r.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - ToolVersionRequest::Ref(plugin_name.clone(), s) + ToolVersionRequest::Ref(plugin_name.to_string(), s) } _ => parse_error!(format!("{}.ref", key), v, "string"), } @@ -470,12 +470,12 @@ impl MiseToml { &self, key: &str, v: &Value, - plugin_name: &String, + plugin_name: &str, ) -> Result { match v.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - Ok(ToolVersionRequest::new(plugin_name.clone(), &s)) + Ok(ToolVersionRequest::new(plugin_name.to_string(), &s)) } _ => parse_error!(key, v, "string"), } @@ -638,7 +638,7 @@ impl ConfigFile for MiseToml { self.tasks.iter().collect() } - fn remove_plugin(&mut self, plugin: &String) { + fn remove_plugin(&mut self, plugin: &str) { self.toolset.versions.remove(plugin); if let Some(tools) = self.doc.get_mut("tools") { if let Some(tools) = tools.as_table_like_mut() { @@ -650,13 +650,13 @@ impl ConfigFile for MiseToml { } } - fn replace_versions(&mut self, plugin_name: &String, versions: &[String]) { + fn replace_versions(&mut self, plugin_name: &str, versions: &[String]) { if let Some(plugin) = self.toolset.versions.get_mut(plugin_name) { plugin.requests = versions .iter() .map(|s| { ( - ToolVersionRequest::new(plugin_name.clone(), s), + ToolVersionRequest::new(plugin_name.to_string(), s), Default::default(), ) }) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 4838bc2cd..866a910c8 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -70,8 +70,8 @@ pub trait ConfigFile: Debug + Send + Sync { fn tasks(&self) -> Vec<&Task> { Default::default() } - fn remove_plugin(&mut self, _plugin_name: &String); - fn replace_versions(&mut self, plugin_name: &String, versions: &[String]); + fn remove_plugin(&mut self, _plugin_name: &str); + fn replace_versions(&mut self, plugin_name: &str, versions: &[String]); fn save(&self) -> Result<()>; fn dump(&self) -> String; fn to_toolset(&self) -> &Toolset; diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index f4a3b3e24..3d89c1c92 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -119,7 +119,7 @@ impl ToolVersions { Ok(plugins) } - fn add_version(&mut self, plugin: &String, version: &str) { + fn add_version(&mut self, plugin: &str, version: &str) { self.get_or_create_plugin(plugin) .versions .push(version.to_string()); @@ -160,11 +160,11 @@ impl ConfigFile for ToolVersions { self.path.as_path() } - fn remove_plugin(&mut self, plugin: &String) { + fn remove_plugin(&mut self, plugin: &str) { self.plugins.remove(plugin); } - fn replace_versions(&mut self, plugin_name: &String, versions: &[String]) { + fn replace_versions(&mut self, plugin_name: &str, versions: &[String]) { self.get_or_create_plugin(plugin_name).versions.clear(); for version in versions { self.add_version(plugin_name, version); diff --git a/src/config/mod.rs b/src/config/mod.rs index 3853782a9..ef8df8b0f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -18,8 +18,9 @@ use crate::config::config_file::mise_toml::MiseToml; use crate::config::config_file::ConfigFile; use crate::config::tracking::Tracker; use crate::file::display_path; +use crate::forge::Forge; use crate::plugins::core::{PluginMap, CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; -use crate::plugins::{ExternalPlugin, Plugin, PluginType}; +use crate::plugins::{ExternalPlugin, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::task::Task; use crate::ui::style; @@ -31,7 +32,7 @@ mod tracking; type AliasMap = BTreeMap>; type ConfigMap = IndexMap>; -type ToolMap = BTreeMap>; +type ToolMap = BTreeMap>; #[derive(Default)] pub struct Config { @@ -136,7 +137,7 @@ impl Config { Ok(v.to_string()) } - pub fn external_plugins(&self) -> Vec<(String, Arc)> { + pub fn external_plugins(&self) -> Vec<(String, Arc)> { self.list_plugins() .into_iter() .filter(|tool| matches!(tool.get_type(), PluginType::External)) @@ -144,7 +145,7 @@ impl Config { .collect() } - pub fn get_or_create_plugin(&self, plugin_name: &str) -> 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(); } @@ -155,7 +156,7 @@ impl Config { .insert(plugin_name.to_string(), plugin.clone()); plugin } - pub fn list_plugins(&self) -> Vec> { + pub fn list_plugins(&self) -> Vec> { self.plugins.read().unwrap().values().cloned().collect() } diff --git a/src/forge/mod.rs b/src/forge/mod.rs new file mode 100644 index 000000000..7dda12100 --- /dev/null +++ b/src/forge/mod.rs @@ -0,0 +1,340 @@ +use crate::config::{Config, Settings}; +use crate::file::{display_path, remove_all, remove_all_with_warning}; +use crate::install_context::InstallContext; +use crate::lock_file::LockFile; +use crate::plugins::{PluginType, VERSION_REGEX}; +use crate::runtime_symlinks::is_runtime_symlink; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; +use crate::ui::multi_progress_report::MultiProgressReport; +use crate::ui::progress_report::SingleReport; +use crate::{dirs, file}; +use clap::Command; +use console::style; +use eyre::WrapErr; +use itertools::Itertools; +use regex::Regex; +use std::collections::{BTreeMap, HashMap}; +use std::fmt::Debug; +use std::fs::File; +use std::path::{Path, PathBuf}; +use versions::Versioning; + +pub trait Forge: Debug + Send + Sync { + fn name(&self) -> &str; + fn get_type(&self) -> PluginType { + PluginType::Core + } + fn installs_path(&self) -> PathBuf { + dirs::INSTALLS.join(self.name()) + } + fn cache_path(&self) -> PathBuf { + dirs::CACHE.join(self.name()) + } + fn downloads_path(&self) -> PathBuf { + dirs::DOWNLOADS.join(self.name()) + } + fn list_remote_versions(&self) -> eyre::Result>; + fn latest_stable_version(&self) -> eyre::Result> { + self.latest_version(Some("latest".into())) + } + fn list_installed_versions(&self) -> eyre::Result> { + Ok(match self.installs_path().exists() { + true => file::dir_subdirs(&self.installs_path())? + .into_iter() + .filter(|v| !v.starts_with('.')) + .filter(|v| !is_runtime_symlink(&self.installs_path().join(v))) + .filter(|v| !self.installs_path().join(v).join("incomplete").exists()) + .sorted_by_cached_key(|v| (Versioning::new(v), v.to_string())) + .collect(), + false => vec![], + }) + } + fn is_version_installed(&self, tv: &ToolVersion) -> bool { + match tv.request { + ToolVersionRequest::System(_) => true, + _ => { + tv.install_path().exists() + && !self.incomplete_file_path(tv).exists() + && !is_runtime_symlink(&tv.install_path()) + } + } + } + fn is_version_outdated(&self, tv: &ToolVersion, p: &dyn Forge) -> bool { + let latest = match tv.latest_version(p) { + Ok(latest) => latest, + Err(e) => { + debug!("Error getting latest version for {}: {:#}", self.name(), e); + return false; + } + }; + !self.is_version_installed(tv) || tv.version != latest + } + fn symlink_path(&self, tv: &ToolVersion) -> Option { + match tv.install_path() { + path if path.is_symlink() => Some(path), + _ => None, + } + } + fn create_symlink(&self, version: &str, target: &Path) -> eyre::Result<()> { + let link = self.installs_path().join(version); + file::create_dir_all(link.parent().unwrap())?; + file::make_symlink(target, &link) + } + fn list_installed_versions_matching(&self, query: &str) -> eyre::Result> { + let versions = self.list_installed_versions()?; + fuzzy_match_filter(versions, query) + } + fn list_versions_matching(&self, query: &str) -> eyre::Result> { + let versions = self.list_remote_versions()?; + fuzzy_match_filter(versions, query) + } + fn latest_version(&self, query: Option) -> eyre::Result> { + match query { + Some(query) => { + let matches = self.list_versions_matching(&query)?; + Ok(find_match_in_list(&matches, &query)) + } + None => self.latest_stable_version(), + } + } + fn latest_installed_version(&self, query: Option) -> eyre::Result> { + match query { + Some(query) => { + let matches = self.list_installed_versions_matching(&query)?; + Ok(find_match_in_list(&matches, &query)) + } + None => { + let installed_symlink = self.installs_path().join("latest"); + if installed_symlink.exists() { + let target = installed_symlink.read_link()?; + let version = target + .file_name() + .ok_or_else(|| eyre!("Invalid symlink target"))? + .to_string_lossy() + .to_string(); + Ok(Some(version)) + } else { + Ok(None) + } + } + } + } + + fn get_remote_url(&self) -> Option { + None + } + fn current_sha_short(&self) -> eyre::Result { + Ok(String::from("")) + } + fn current_abbrev_ref(&self) -> eyre::Result { + Ok(String::from("")) + } + fn is_installed(&self) -> bool { + true + } + fn ensure_installed(&self, _mpr: &MultiProgressReport, _force: bool) -> eyre::Result<()> { + Ok(()) + } + fn update(&self, _pr: &dyn SingleReport, _git_ref: Option) -> eyre::Result<()> { + Ok(()) + } + fn uninstall(&self, _pr: &dyn SingleReport) -> eyre::Result<()> { + Ok(()) + } + fn purge(&self, pr: &dyn SingleReport) -> eyre::Result<()> { + rmdir(&self.installs_path(), pr)?; + rmdir(&self.cache_path(), pr)?; + rmdir(&self.downloads_path(), pr)?; + Ok(()) + } + fn get_aliases(&self) -> eyre::Result> { + Ok(BTreeMap::new()) + } + fn legacy_filenames(&self) -> eyre::Result> { + Ok(vec![]) + } + fn parse_legacy_file(&self, path: &Path) -> eyre::Result { + let contents = file::read_to_string(path)?; + Ok(contents.trim().to_string()) + } + fn external_commands(&self) -> eyre::Result> { + Ok(vec![]) + } + fn execute_external_command(&self, _command: &str, _args: Vec) -> eyre::Result<()> { + unimplemented!() + } + fn install_version(&self, ctx: InstallContext) -> eyre::Result<()> { + let config = Config::get(); + let settings = Settings::try_get()?; + if self.is_version_installed(&ctx.tv) { + if ctx.force { + self.uninstall_version(&ctx.tv, ctx.pr.as_ref(), false)?; + ctx.pr.set_message("installing".into()); + } else { + return Ok(()); + } + } + let _lock = self.get_lock(&ctx.tv.install_path(), ctx.force)?; + self.create_install_dirs(&ctx.tv)?; + + if let Err(e) = self.install_version_impl(&ctx) { + self.cleanup_install_dirs_on_error(&settings, &ctx.tv); + return Err(e); + } + self.cleanup_install_dirs(&settings, &ctx.tv); + // attempt to touch all the .tool-version files to trigger updates in hook-env + let mut touch_dirs = vec![dirs::DATA.to_path_buf()]; + touch_dirs.extend(config.config_files.keys().cloned()); + for path in touch_dirs { + let err = file::touch_dir(&path); + if let Err(err) = err { + debug!("error touching config file: {:?} {:?}", path, err); + } + } + if let Err(err) = file::remove_file(self.incomplete_file_path(&ctx.tv)) { + debug!("error removing incomplete file: {:?}", err); + } + ctx.pr.finish_with_message("installed".to_string()); + + Ok(()) + } + fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()>; + fn uninstall_version( + &self, + tv: &ToolVersion, + pr: &dyn SingleReport, + dryrun: bool, + ) -> eyre::Result<()> { + pr.set_message("uninstall".into()); + + if !dryrun { + self.uninstall_version_impl(pr, tv)?; + } + let rmdir = |dir: &Path| { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", display_path(dir))); + if dryrun { + return Ok(()); + } + remove_all_with_warning(dir) + }; + rmdir(&tv.install_path())?; + rmdir(&tv.download_path())?; + rmdir(&tv.cache_path())?; + Ok(()) + } + fn uninstall_version_impl( + &self, + _pr: &dyn SingleReport, + _tv: &ToolVersion, + ) -> eyre::Result<()> { + Ok(()) + } + fn list_bin_paths(&self, tv: &ToolVersion) -> eyre::Result> { + match tv.request { + ToolVersionRequest::System(_) => Ok(vec![]), + _ => Ok(vec![tv.install_short_path().join("bin")]), + } + } + fn exec_env( + &self, + _config: &Config, + _ts: &Toolset, + _tv: &ToolVersion, + ) -> eyre::Result> { + Ok(HashMap::new()) + } + fn which(&self, tv: &ToolVersion, bin_name: &str) -> eyre::Result> { + let bin_paths = self.list_bin_paths(tv)?; + for bin_path in bin_paths { + let bin_path = bin_path.join(bin_name); + if bin_path.exists() { + return Ok(Some(bin_path)); + } + } + Ok(None) + } + + fn get_lock(&self, path: &Path, force: bool) -> eyre::Result> { + let lock = if force { + None + } else { + let lock = LockFile::new(path) + .with_callback(|l| { + debug!("waiting for lock on {}", display_path(l)); + }) + .lock()?; + Some(lock) + }; + Ok(lock) + } + fn create_install_dirs(&self, tv: &ToolVersion) -> eyre::Result<()> { + let _ = remove_all_with_warning(tv.install_path()); + let _ = remove_all_with_warning(tv.download_path()); + let _ = remove_all_with_warning(tv.cache_path()); + let _ = file::remove_file(tv.install_path()); // removes if it is a symlink + file::create_dir_all(tv.install_path())?; + file::create_dir_all(tv.download_path())?; + file::create_dir_all(tv.cache_path())?; + File::create(self.incomplete_file_path(tv))?; + Ok(()) + } + fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { + if !settings.always_keep_install { + let _ = remove_all_with_warning(tv.install_path()); + self.cleanup_install_dirs(settings, tv); + } + } + fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { + if !settings.always_keep_download && !settings.always_keep_install { + let _ = remove_all_with_warning(tv.download_path()); + } + } + fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { + tv.cache_path().join("incomplete") + } +} + +fn fuzzy_match_filter(versions: Vec, query: &str) -> eyre::Result> { + let mut query = query; + if query == "latest" { + query = "[0-9].*"; + } + let query_regex = Regex::new(&format!("^{}([-.].+)?$", query))?; + let versions = versions + .into_iter() + .filter(|v| { + if query == v { + return true; + } + if VERSION_REGEX.is_match(v) { + return false; + } + query_regex.is_match(v) + }) + .collect(); + Ok(versions) +} + +fn find_match_in_list(list: &[String], query: &str) -> Option { + let v = match list.contains(&query.to_string()) { + true => Some(query.to_string()), + false => list.last().map(|s| s.to_string()), + }; + v +} + +fn rmdir(dir: &Path, pr: &dyn SingleReport) -> eyre::Result<()> { + if !dir.exists() { + return Ok(()); + } + pr.set_message(format!("removing {}", &dir.to_string_lossy())); + remove_all(dir).wrap_err_with(|| { + format!( + "Failed to remove directory {}", + style(&dir.to_string_lossy()).cyan().for_stderr() + ) + }) +} diff --git a/src/main.rs b/src/main.rs index 678805f4b..7c98375e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,7 @@ mod env_diff; mod errors; mod fake_asdf; mod file; +mod forge; mod git; pub mod github; mod hash; diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 30733acf6..0c471f269 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -7,11 +7,11 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::file; +use crate::forge::Forge; use crate::github::GithubRelease; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest}; use crate::ui::progress_report::SingleReport; @@ -94,7 +94,7 @@ impl BunPlugin { } } -impl Plugin for BunPlugin { +impl Forge for BunPlugin { fn name(&self) -> &str { "bun" } diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 550d734e1..3be330193 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -9,11 +9,11 @@ use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; use crate::file; +use crate::forge::Forge; use crate::github::GithubRelease; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; @@ -93,7 +93,7 @@ impl DenoPlugin { } } -impl Plugin for DenoPlugin { +impl Forge for DenoPlugin { fn name(&self) -> &str { "deno" } diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 1a4ac5bb4..857efe1c7 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -3,11 +3,11 @@ use std::path::PathBuf; use eyre::Result; use crate::file::display_path; +use crate::forge::Forge; use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::ToolVersionRequest; use crate::{cmd, file}; @@ -87,7 +87,7 @@ impl ErlangPlugin { } } -impl Plugin for ErlangPlugin { +impl Forge for ErlangPlugin { fn name(&self) -> &str { self.core.name } diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 93d2afe61..d843924e8 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -8,10 +8,10 @@ use versions::Versioning; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; +use crate::forge::Forge; use crate::http::HTTP; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::{ToolVersion, Toolset}; use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file, hash}; @@ -134,7 +134,7 @@ impl GoPlugin { } } -impl Plugin for GoPlugin { +impl Forge for GoPlugin { fn name(&self) -> &str { "go" } diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index fce83298d..6308d99db 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -13,10 +13,10 @@ use crate::cache::CacheManager; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; +use crate::forge::Forge; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; use crate::{env, file, hash}; @@ -294,7 +294,7 @@ impl JavaPlugin { } } -impl Plugin for JavaPlugin { +impl Forge for JavaPlugin { fn name(&self) -> &str { "java" } diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 642c14690..c8bb55d90 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -11,6 +11,7 @@ use once_cell::sync::Lazy; pub use python::PythonPlugin; use crate::cache::CacheManager; +use crate::forge::Forge; use crate::http::HTTP_FETCH; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; @@ -19,7 +20,6 @@ use crate::plugins::core::go::GoPlugin; use crate::plugins::core::java::JavaPlugin; use crate::plugins::core::node::NodePlugin; use crate::plugins::core::ruby::RubyPlugin; -use crate::plugins::Plugin; use crate::timeout::run_with_timeout; use crate::toolset::ToolVersion; use crate::{dirs, env}; @@ -33,10 +33,10 @@ mod node; mod python; mod ruby; -pub type PluginMap = BTreeMap>; +pub type PluginMap = BTreeMap>; pub static CORE_PLUGINS: Lazy = Lazy::new(|| { - let plugins: Vec> = vec![ + let plugins: Vec> = vec![ Arc::new(BunPlugin::new()), Arc::new(DenoPlugin::new()), Arc::new(GoPlugin::new()), @@ -52,7 +52,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { }); pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { - let plugins: Vec> = vec![Arc::new(ErlangPlugin::new())]; + let plugins: Vec> = vec![Arc::new(ErlangPlugin::new())]; plugins .into_iter() .map(|plugin| (plugin.name().to_string(), plugin)) diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index cfb53fe15..49441f2a9 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -10,10 +10,10 @@ use crate::build_time::built_info; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::env::MISE_NODE_MIRROR_URL; +use crate::forge::Forge; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::ToolVersion; use crate::ui::progress_report::SingleReport; use crate::{env, file, hash, http}; @@ -236,7 +236,7 @@ impl NodePlugin { } } -impl Plugin for NodePlugin { +impl Forge for NodePlugin { fn name(&self) -> &str { "node" } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index bc2a9b5b5..e4cda55f1 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -9,11 +9,11 @@ use crate::cache::CacheManager; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::file::display_path; +use crate::forge::Forge; use crate::git::Git; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file}; @@ -292,7 +292,7 @@ impl PythonPlugin { } } -impl Plugin for PythonPlugin { +impl Forge for PythonPlugin { fn name(&self) -> &str { "python" } diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 61687f5a9..c13d9fe3e 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -9,13 +9,13 @@ use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::duration::DAILY; +use crate::forge::Forge; use crate::git::Git; use crate::github::GithubRelease; use crate::http::{HTTP, HTTP_FETCH}; use crate::install_context::InstallContext; use crate::lock_file::LockFile; use crate::plugins::core::CorePlugin; -use crate::plugins::Plugin; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file}; @@ -320,7 +320,7 @@ impl RubyPlugin { } } -impl Plugin for RubyPlugin { +impl Forge for RubyPlugin { fn name(&self) -> &str { "ruby" } diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 7d516194b..fcfd52af2 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -20,6 +20,7 @@ use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_all}; +use crate::forge::Forge; use crate::git::Git; use crate::hash::hash_to_str; use crate::http::HTTP_FETCH; @@ -27,7 +28,7 @@ use crate::install_context::InstallContext; use crate::plugins::external_plugin_cache::ExternalPluginCache; use crate::plugins::mise_plugin_toml::MisePluginToml; use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile}; -use crate::plugins::{Plugin, PluginType, Script, ScriptManager}; +use crate::plugins::{PluginType, Script, ScriptManager}; use crate::timeout::run_with_timeout; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; @@ -87,11 +88,11 @@ impl ExternalPlugin { name, } } - pub fn newa(name: String) -> Arc { + pub fn newa(name: String) -> Arc { Arc::new(Self::new(name)) } - pub fn list() -> Result)>> { + pub fn list() -> Result)>> { Ok(file::dir_subdirs(&dirs::PLUGINS)? .into_par_iter() .map(|name| (name.clone(), Self::newa(name))) @@ -406,7 +407,7 @@ impl Hash for ExternalPlugin { } } -impl Plugin for ExternalPlugin { +impl Forge for ExternalPlugin { fn name(&self) -> &str { &self.name } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 86e372874..2c5902e71 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,29 +1,12 @@ -use std::collections::{BTreeMap, HashMap}; -use std::fmt::{Debug, Display}; -use std::fs::File; -use std::hash::Hash; -use std::path::{Path, PathBuf}; +pub use external_plugin::ExternalPlugin; -use clap::Command; -use console::style; -use eyre::{Result, WrapErr}; -use itertools::Itertools; use once_cell::sync::Lazy; use regex::Regex; -use versions::Versioning; - -pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; +use std::fmt::{Debug, Display}; +use std::hash::Hash; -use crate::config::{Config, Settings}; -use crate::file::{display_path, remove_all, remove_all_with_warning}; -use crate::install_context::InstallContext; -use crate::lock_file::LockFile; -use crate::runtime_symlinks::is_runtime_symlink; -use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; -use crate::ui::multi_progress_report::MultiProgressReport; -use crate::ui::progress_report::SingleReport; -use crate::{dirs, file}; +use crate::forge::Forge; pub mod core; mod external_plugin; @@ -31,280 +14,6 @@ mod external_plugin_cache; mod mise_plugin_toml; mod script_manager; -pub trait Plugin: Debug + Send + Sync { - fn name(&self) -> &str; - fn get_type(&self) -> PluginType { - PluginType::Core - } - fn installs_path(&self) -> PathBuf { - dirs::INSTALLS.join(self.name()) - } - fn cache_path(&self) -> PathBuf { - dirs::CACHE.join(self.name()) - } - fn downloads_path(&self) -> PathBuf { - dirs::DOWNLOADS.join(self.name()) - } - fn list_remote_versions(&self) -> Result>; - fn latest_stable_version(&self) -> Result> { - self.latest_version(Some("latest".into())) - } - fn list_installed_versions(&self) -> Result> { - Ok(match self.installs_path().exists() { - true => file::dir_subdirs(&self.installs_path())? - .into_iter() - .filter(|v| !v.starts_with('.')) - .filter(|v| !is_runtime_symlink(&self.installs_path().join(v))) - .filter(|v| !self.installs_path().join(v).join("incomplete").exists()) - .sorted_by_cached_key(|v| (Versioning::new(v), v.to_string())) - .collect(), - false => vec![], - }) - } - fn is_version_installed(&self, tv: &ToolVersion) -> bool { - match tv.request { - ToolVersionRequest::System(_) => true, - _ => { - tv.install_path().exists() - && !self.incomplete_file_path(tv).exists() - && !is_runtime_symlink(&tv.install_path()) - } - } - } - fn is_version_outdated(&self, tv: &ToolVersion, p: &dyn Plugin) -> bool { - let latest = match tv.latest_version(p) { - Ok(latest) => latest, - Err(e) => { - debug!("Error getting latest version for {}: {:#}", self.name(), e); - return false; - } - }; - !self.is_version_installed(tv) || tv.version != latest - } - fn symlink_path(&self, tv: &ToolVersion) -> Option { - match tv.install_path() { - path if path.is_symlink() => Some(path), - _ => None, - } - } - fn create_symlink(&self, version: &str, target: &Path) -> Result<()> { - let link = self.installs_path().join(version); - file::create_dir_all(link.parent().unwrap())?; - file::make_symlink(target, &link) - } - fn list_installed_versions_matching(&self, query: &str) -> Result> { - let versions = self.list_installed_versions()?; - fuzzy_match_filter(versions, query) - } - fn list_versions_matching(&self, query: &str) -> Result> { - let versions = self.list_remote_versions()?; - fuzzy_match_filter(versions, query) - } - fn latest_version(&self, query: Option) -> Result> { - match query { - Some(query) => { - let matches = self.list_versions_matching(&query)?; - Ok(find_match_in_list(&matches, &query)) - } - None => self.latest_stable_version(), - } - } - fn latest_installed_version(&self, query: Option) -> Result> { - match query { - Some(query) => { - let matches = self.list_installed_versions_matching(&query)?; - Ok(find_match_in_list(&matches, &query)) - } - None => { - let installed_symlink = self.installs_path().join("latest"); - if installed_symlink.exists() { - let target = installed_symlink.read_link()?; - let version = target - .file_name() - .ok_or_else(|| eyre!("Invalid symlink target"))? - .to_string_lossy() - .to_string(); - Ok(Some(version)) - } else { - Ok(None) - } - } - } - } - - fn get_remote_url(&self) -> Option { - None - } - fn current_sha_short(&self) -> Result { - Ok(String::from("")) - } - fn current_abbrev_ref(&self) -> Result { - Ok(String::from("")) - } - fn is_installed(&self) -> bool { - true - } - fn ensure_installed(&self, _mpr: &MultiProgressReport, _force: bool) -> Result<()> { - Ok(()) - } - fn update(&self, _pr: &dyn SingleReport, _git_ref: Option) -> Result<()> { - Ok(()) - } - fn uninstall(&self, _pr: &dyn SingleReport) -> Result<()> { - Ok(()) - } - fn purge(&self, pr: &dyn SingleReport) -> Result<()> { - rmdir(&self.installs_path(), pr)?; - rmdir(&self.cache_path(), pr)?; - rmdir(&self.downloads_path(), pr)?; - Ok(()) - } - fn get_aliases(&self) -> Result> { - Ok(BTreeMap::new()) - } - fn legacy_filenames(&self) -> Result> { - Ok(vec![]) - } - fn parse_legacy_file(&self, path: &Path) -> Result { - let contents = file::read_to_string(path)?; - Ok(contents.trim().to_string()) - } - fn external_commands(&self) -> Result> { - Ok(vec![]) - } - fn execute_external_command(&self, _command: &str, _args: Vec) -> Result<()> { - unimplemented!() - } - fn install_version(&self, ctx: InstallContext) -> Result<()> { - let config = Config::get(); - let settings = Settings::try_get()?; - if self.is_version_installed(&ctx.tv) { - if ctx.force { - self.uninstall_version(&ctx.tv, ctx.pr.as_ref(), false)?; - ctx.pr.set_message("installing".into()); - } else { - return Ok(()); - } - } - let _lock = self.get_lock(&ctx.tv.install_path(), ctx.force)?; - self.create_install_dirs(&ctx.tv)?; - - if let Err(e) = self.install_version_impl(&ctx) { - self.cleanup_install_dirs_on_error(&settings, &ctx.tv); - return Err(e); - } - self.cleanup_install_dirs(&settings, &ctx.tv); - // attempt to touch all the .tool-version files to trigger updates in hook-env - let mut touch_dirs = vec![dirs::DATA.to_path_buf()]; - touch_dirs.extend(config.config_files.keys().cloned()); - for path in touch_dirs { - let err = file::touch_dir(&path); - if let Err(err) = err { - debug!("error touching config file: {:?} {:?}", path, err); - } - } - if let Err(err) = file::remove_file(self.incomplete_file_path(&ctx.tv)) { - debug!("error removing incomplete file: {:?}", err); - } - ctx.pr.finish_with_message("installed".to_string()); - - Ok(()) - } - fn install_version_impl(&self, ctx: &InstallContext) -> Result<()>; - fn uninstall_version( - &self, - tv: &ToolVersion, - pr: &dyn SingleReport, - dryrun: bool, - ) -> Result<()> { - pr.set_message("uninstall".into()); - - if !dryrun { - self.uninstall_version_impl(pr, tv)?; - } - let rmdir = |dir: &Path| { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", display_path(dir))); - if dryrun { - return Ok(()); - } - remove_all_with_warning(dir) - }; - rmdir(&tv.install_path())?; - rmdir(&tv.download_path())?; - rmdir(&tv.cache_path())?; - Ok(()) - } - fn uninstall_version_impl(&self, _pr: &dyn SingleReport, _tv: &ToolVersion) -> Result<()> { - Ok(()) - } - fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { - match tv.request { - ToolVersionRequest::System(_) => Ok(vec![]), - _ => Ok(vec![tv.install_short_path().join("bin")]), - } - } - fn exec_env( - &self, - _config: &Config, - _ts: &Toolset, - _tv: &ToolVersion, - ) -> Result> { - Ok(HashMap::new()) - } - fn which(&self, tv: &ToolVersion, bin_name: &str) -> Result> { - let bin_paths = self.list_bin_paths(tv)?; - for bin_path in bin_paths { - let bin_path = bin_path.join(bin_name); - if bin_path.exists() { - return Ok(Some(bin_path)); - } - } - Ok(None) - } - - fn get_lock(&self, path: &Path, force: bool) -> Result> { - let lock = if force { - None - } else { - let lock = LockFile::new(path) - .with_callback(|l| { - debug!("waiting for lock on {}", display_path(l)); - }) - .lock()?; - Some(lock) - }; - Ok(lock) - } - fn create_install_dirs(&self, tv: &ToolVersion) -> Result<()> { - let _ = remove_all_with_warning(tv.install_path()); - let _ = remove_all_with_warning(tv.download_path()); - let _ = remove_all_with_warning(tv.cache_path()); - let _ = file::remove_file(tv.install_path()); // removes if it is a symlink - file::create_dir_all(tv.install_path())?; - file::create_dir_all(tv.download_path())?; - file::create_dir_all(tv.cache_path())?; - File::create(self.incomplete_file_path(tv))?; - Ok(()) - } - fn cleanup_install_dirs_on_error(&self, settings: &Settings, tv: &ToolVersion) { - if !settings.always_keep_install { - let _ = remove_all_with_warning(tv.install_path()); - self.cleanup_install_dirs(settings, tv); - } - } - fn cleanup_install_dirs(&self, settings: &Settings, tv: &ToolVersion) { - if !settings.always_keep_download && !settings.always_keep_install { - let _ = remove_all_with_warning(tv.download_path()); - } - } - fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf { - tv.cache_path().join("incomplete") - } -} - pub fn unalias_plugin(plugin_name: &str) -> &str { match plugin_name { "nodejs" => "node", @@ -313,68 +22,28 @@ pub fn unalias_plugin(plugin_name: &str) -> &str { } } -fn fuzzy_match_filter(versions: Vec, query: &str) -> Result> { - let mut query = query; - if query == "latest" { - query = "[0-9].*"; - } - let query_regex = Regex::new(&format!("^{}([-.].+)?$", query))?; - let versions = versions - .into_iter() - .filter(|v| { - if query == v { - return true; - } - if VERSION_REGEX.is_match(v) { - return false; - } - query_regex.is_match(v) - }) - .collect(); - Ok(versions) -} -fn find_match_in_list(list: &[String], query: &str) -> Option { - let v = match list.contains(&query.to_string()) { - true => Some(query.to_string()), - false => list.last().map(|s| s.to_string()), - }; - v -} -fn rmdir(dir: &Path, pr: &dyn SingleReport) -> Result<()> { - if !dir.exists() { - return Ok(()); - } - pr.set_message(format!("removing {}", &dir.to_string_lossy())); - remove_all(dir).wrap_err_with(|| { - format!( - "Failed to remove directory {}", - style(&dir.to_string_lossy()).cyan().for_stderr() - ) - }) -} - -impl Display for dyn Plugin { +impl Display for dyn Forge { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name()) } } -impl Eq for dyn Plugin {} -impl PartialEq for dyn Plugin { +impl Eq for dyn Forge {} +impl PartialEq for dyn Forge { fn eq(&self, other: &Self) -> bool { self.get_type() == other.get_type() && self.name() == other.name() } } -impl Hash for dyn Plugin { +impl Hash for dyn Forge { fn hash(&self, state: &mut H) { self.name().hash(state) } } -impl PartialOrd for dyn Plugin { +impl PartialOrd for dyn Forge { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for dyn Plugin { +impl Ord for dyn Forge { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.name().cmp(other.name()) } @@ -395,6 +64,7 @@ pub static VERSION_REGEX: Lazy = Lazy::new(|| { #[cfg(test)] mod tests { + use crate::forge::Forge; use pretty_assertions::assert_str_eq; use super::*; diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index a501da4a3..5fee6a5d2 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -9,7 +9,8 @@ use versions::Versioning; use crate::config::Config; use crate::file::make_symlink; -use crate::plugins::{Plugin, VERSION_REGEX}; +use crate::forge::Forge; +use crate::plugins::VERSION_REGEX; use crate::{dirs, file}; pub fn rebuild(config: &Config) -> Result<()> { @@ -35,7 +36,7 @@ pub fn rebuild(config: &Config) -> Result<()> { Ok(()) } -fn list_symlinks(config: &Config, plugin: Arc) -> Result> { +fn list_symlinks(config: &Config, plugin: Arc) -> Result> { // TODO: make this a pure function and add test cases let mut symlinks = IndexMap::new(); let rel_path = |x: &String| PathBuf::from(".").join(x.clone()); @@ -75,7 +76,7 @@ fn list_symlinks(config: &Config, plugin: Arc) -> Result) -> Result> { +fn installed_versions(plugin: &Arc) -> Result> { let versions = plugin .list_installed_versions()? .into_iter() @@ -84,7 +85,7 @@ fn installed_versions(plugin: &Arc) -> Result> { Ok(versions) } -fn remove_missing_symlinks(plugin: Arc) -> Result<()> { +fn remove_missing_symlinks(plugin: Arc) -> Result<()> { let installs_dir = dirs::INSTALLS.join(plugin.name()); if !installs_dir.exists() { return Ok(()); diff --git a/src/shims.rs b/src/shims.rs index e927ae3e7..855a9df3b 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -17,7 +17,7 @@ use crate::file::{create_dir_all, display_path, remove_all}; use crate::lock_file::LockFile; use crate::{env, logger}; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; @@ -145,7 +145,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { } // lists all the paths to bins in a tv that shims will be needed for -fn list_tool_bins(t: Arc, tv: &ToolVersion) -> Result> { +fn list_tool_bins(t: Arc, tv: &ToolVersion) -> Result> { Ok(t.list_bin_paths(tv)? .into_iter() .par_bridge() diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index ae4d7db09..6c259cb55 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -19,9 +19,9 @@ pub use tool_version_request::ToolVersionRequest; use crate::config::{Config, Settings}; use crate::env; use crate::env::TERM_WIDTH; +use crate::forge::Forge; use crate::install_context::InstallContext; use crate::path_env::PathEnv; -use crate::plugins::Plugin; use crate::runtime_symlinks; use crate::shims; use crate::ui::multi_progress_report::MultiProgressReport; @@ -198,8 +198,8 @@ impl Toolset { pub fn list_installed_versions( &self, config: &Config, - ) -> Result, ToolVersion)>> { - let current_versions: HashMap<(String, String), (Arc, ToolVersion)> = self + ) -> Result, ToolVersion)>> { + let current_versions: HashMap<(String, String), (Arc, ToolVersion)> = self .list_current_versions() .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p.clone(), tv))) @@ -231,32 +231,32 @@ impl Toolset { Ok(versions) } - pub fn list_plugins(&self) -> Vec> { + pub fn list_plugins(&self) -> Vec> { self.list_versions_by_plugin() .into_iter() .map(|(p, _)| p) .collect() } - pub fn list_versions_by_plugin(&self) -> Vec<(Arc, &Vec)> { + pub fn list_versions_by_plugin(&self) -> Vec<(Arc, &Vec)> { let config = Config::get(); self.versions .iter() .map(|(p, v)| (config.get_or_create_plugin(p), &v.versions)) .collect() } - pub fn list_current_versions(&self) -> Vec<(Arc, ToolVersion)> { + pub fn list_current_versions(&self) -> Vec<(Arc, ToolVersion)> { self.list_versions_by_plugin() .iter() .flat_map(|(p, v)| v.iter().map(|v| (p.clone(), v.clone()))) .collect() } - pub fn list_current_installed_versions(&self) -> Vec<(Arc, ToolVersion)> { + pub fn list_current_installed_versions(&self) -> Vec<(Arc, ToolVersion)> { self.list_current_versions() .into_iter() .filter(|(p, v)| p.is_version_installed(v)) .collect() } - pub fn list_outdated_versions(&self) -> Vec<(Arc, ToolVersion, String)> { + pub fn list_outdated_versions(&self) -> Vec<(Arc, ToolVersion, String)> { self.list_current_versions() .into_iter() .filter_map(|(t, tv)| { @@ -336,7 +336,7 @@ impl Toolset { }) .collect() } - pub fn which(&self, bin_name: &str) -> Option<(Arc, ToolVersion)> { + pub fn which(&self, bin_name: &str) -> Option<(Arc, ToolVersion)> { self.list_current_installed_versions() .into_par_iter() .find_first(|(p, tv)| { diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 4d3172e1b..f9c1224c4 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -10,8 +10,8 @@ use versions::{Chunk, Version}; use crate::config::Config; use crate::dirs; +use crate::forge::Forge; use crate::hash::hash_to_str; -use crate::plugins::Plugin; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; /// represents a single version of a tool for a particular plugin @@ -25,7 +25,7 @@ pub struct ToolVersion { impl ToolVersion { pub fn new( - tool: &dyn Plugin, + tool: &dyn Forge, request: ToolVersionRequest, opts: ToolVersionOptions, version: String, @@ -39,7 +39,7 @@ impl ToolVersion { } pub fn resolve( - tool: &dyn Plugin, + tool: &dyn Forge, request: ToolVersionRequest, opts: ToolVersionOptions, latest_versions: bool, @@ -93,7 +93,7 @@ impl ToolVersion { .join(&self.plugin_name) .join(self.tv_pathname()) } - pub fn latest_version(&self, tool: &dyn Plugin) -> Result { + pub fn latest_version(&self, tool: &dyn Forge) -> Result { let tv = self.request.resolve(tool, self.opts.clone(), true)?; Ok(tv.version) } @@ -122,7 +122,7 @@ impl ToolVersion { } fn resolve_version( - tool: &dyn Plugin, + tool: &dyn Forge, request: ToolVersionRequest, latest_versions: bool, v: &str, @@ -186,7 +186,7 @@ impl ToolVersion { /// resolve a version like `sub-1:12.0.0` which becomes `11.0.0`, `sub-0.1:12.1.0` becomes `12.0.0` fn resolve_sub( - tool: &dyn Plugin, + tool: &dyn Forge, request: ToolVersionRequest, latest_versions: bool, sub: &str, @@ -202,7 +202,7 @@ impl ToolVersion { } fn resolve_prefix( - tool: &dyn Plugin, + tool: &dyn Forge, request: ToolVersionRequest, prefix: &str, opts: ToolVersionOptions, @@ -216,14 +216,14 @@ impl ToolVersion { Ok(Self::new(tool, request, opts, v.to_string())) } - fn resolve_ref(tool: &dyn Plugin, r: String, opts: ToolVersionOptions) -> Self { + fn resolve_ref(tool: &dyn Forge, r: String, opts: ToolVersionOptions) -> Self { let request = ToolVersionRequest::Ref(tool.name().into(), r); let version = request.version(); Self::new(tool, request, opts, version) } fn resolve_path( - tool: &dyn Plugin, + tool: &dyn Forge, path: PathBuf, opts: ToolVersionOptions, ) -> Result { diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 208ceb6d2..7c82ceb50 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use eyre::Result; -use crate::plugins::Plugin; +use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolVersionOptions}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -72,7 +72,7 @@ impl ToolVersionRequest { pub fn resolve( &self, - plugin: &dyn Plugin, + plugin: &dyn Forge, opts: ToolVersionOptions, latest_versions: bool, ) -> Result { From 36fdc55af0676271fced65be8d50046e673a3516 Mon Sep 17 00:00:00 2001 From: Brian Heise <92563897+bnheise@users.noreply.github.com> Date: Sat, 13 Jan 2024 08:47:49 +0900 Subject: [PATCH 1608/1891] Update nushell.rs - Add explicit spread (#1441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update nushell.rs - Add explicit spread Running mise with nushell in the latest release of nushell (currently [0.89.0](https://www.nushell.sh/blog/2024-01-09-nushell_0_89_0.html#spread-operator-for-commands)) results in the following warning: ```shell Error: Ă— Automatically spreading lists is deprecated ╭─[/hREDACTED:35:1] 35 │ } else { 36 │ ^"rtx" $command $rest · ──┬── · ╰── Spreading lists automatically when calling external commands is deprecated and will be removed in 0.91. 37 │ } ╰──── help: Use the spread operator (put a '...' before the argument) ``` This change fixes the warning. * updated snapshots --------- Co-authored-by: Jeff Dickey <216188+jdx@users.noreply.github.com> --- src/shell/nushell.rs | 4 ++-- .../snapshots/mise__shell__nushell__tests__hook_init.snap | 4 ++-- .../snapshots/mise__shell__nushell__tests__hook_init_nix.snap | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 5e7b0fbe3..8f07df80b 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -65,11 +65,11 @@ impl Shell for Nushell { }} else if ($command == "activate") {{ $env.MISE_SHELL = "nu" }} else if ($command in $commands) {{ - ^"{exe}" $command $rest + ^"{exe}" $command ...$rest | parse vars | update-env }} else {{ - ^"{exe}" $command $rest + ^"{exe}" $command ...$rest }} }} diff --git a/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap index 83a864d19..6fc7b41fc 100644 --- a/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap @@ -34,11 +34,11 @@ def --wrapped mise [command?: string, --help, ...rest: string] { } else if ($command == "activate") { $env.MISE_SHELL = "nu" } else if ($command in $commands) { - ^"/some/dir/mise" $command $rest + ^"/some/dir/mise" $command ...$rest | parse vars | update-env } else { - ^"/some/dir/mise" $command $rest + ^"/some/dir/mise" $command ...$rest } } diff --git a/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap index a932c26b2..f58c9c5d4 100644 --- a/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap @@ -33,11 +33,11 @@ def --wrapped mise [command?: string, --help, ...rest: string] { } else if ($command == "activate") { $env.MISE_SHELL = "nu" } else if ($command in $commands) { - ^"/nix/store/mise" $command $rest + ^"/nix/store/mise" $command ...$rest | parse vars | update-env } else { - ^"/nix/store/mise" $command $rest + ^"/nix/store/mise" $command ...$rest } } From cf936931201d6597ad556bd17556d47dc3d125c6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 12 Jan 2024 17:45:32 -0600 Subject: [PATCH 1609/1891] config: allow using "env._.file|env._.path" instead of "env.mise.file|env.mise.path" I am still unsure what the final syntax will be, so this removes the deprecation warning on the old env_file|env_path syntax. It also allows using "env._.file|env._.path" instead of "env.mise.file|env.mise.path". --- .mise.toml | 2 +- src/config/config_file/mise_toml.rs | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.mise.toml b/.mise.toml index 1425dd132..1b35c9f3c 100644 --- a/.mise.toml +++ b/.mise.toml @@ -2,7 +2,7 @@ min_version = "2024.1.1" [env] -mise.file = [".env"] +_.file = [".env"] FOO = "bar" FOO_NUM = 1 THIS_PROJECT = "{{config_root}}-{{cwd}}" diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index b446751c0..3e75926af 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -80,8 +80,8 @@ impl MiseToml { for (k, v) in doc.iter() { match k { "min_version" => self.parse_min_version(v)?, - "dotenv" => self.parse_env_file(k, v, true)?, - "env_file" => self.parse_env_file(k, v, true)?, + "dotenv" => self.parse_env_file(k, v)?, + "env_file" => self.parse_env_file(k, v)?, "env_path" => self.path_dirs = self.parse_path_env(k, v)?, "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, @@ -116,11 +116,8 @@ impl MiseToml { } } - fn parse_env_file(&mut self, k: &str, v: &Item, deprecate: bool) -> Result<()> { + fn parse_env_file(&mut self, k: &str, v: &Item) -> Result<()> { trust_check(&self.path)?; - if deprecate { - warn!("{k} is deprecated. Use 'env.mise.file' instead."); - } if let Some(filename) = v.as_str() { let path = self.path.parent().unwrap().join(filename); self.parse_env_filename(path)?; @@ -163,7 +160,7 @@ impl MiseToml { for (k, v) in table.iter() { let key = format!("{}.{}", key, k); let k = self.parse_template(&key, k)?; - if k == "mise" { + if k == "_" || k == "mise" { self.parse_env_mise(&key, v)?; } else if let Some(v) = v.as_str() { let v = self.parse_template(&key, v)?; @@ -190,7 +187,7 @@ impl MiseToml { for (k, v) in table.iter() { let key = format!("{}.{}", key, k); match k { - "file" => self.parse_env_file(&key, v, false)?, + "file" => self.parse_env_file(&key, v)?, "path" => self.path_dirs = self.parse_path_env(&key, v)?, _ => parse_error!(key, v, "file or path"), } From 5091fc6b04fd1e4795bbd636772c30432b825ef3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:52:51 -0600 Subject: [PATCH 1610/1891] refactor: clean up arg imports --- src/cli/args/{cd.rs => cd_arg.rs} | 4 ++-- src/cli/args/{env_var.rs => env_var_arg.rs} | 0 .../args/{log_level.rs => log_level_arg.rs} | 12 +++++----- src/cli/args/mod.rs | 22 +++++++++++++------ src/cli/args/{quiet.rs => quiet_arg.rs} | 4 ++-- src/cli/args/{tool.rs => tool_arg.rs} | 0 src/cli/args/{verbose.rs => verbose_arg.rs} | 4 ++-- src/cli/args/{yes.rs => yes_arg.rs} | 4 ++-- src/cli/env.rs | 2 +- src/cli/exec.rs | 2 +- src/cli/global.rs | 2 +- src/cli/install.rs | 2 +- src/cli/latest.rs | 2 +- src/cli/link.rs | 2 +- src/cli/local.rs | 2 +- src/cli/ls_remote.rs | 2 +- src/cli/mod.rs | 14 ++++++------ src/cli/outdated.rs | 2 +- src/cli/run.rs | 2 +- src/cli/set.rs | 2 +- src/cli/shell.rs | 2 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 2 +- src/cli/use.rs | 2 +- src/cli/where.rs | 2 +- src/cli/which.rs | 2 +- src/config/config_file/mod.rs | 2 +- src/toolset/builder.rs | 2 +- 28 files changed, 55 insertions(+), 47 deletions(-) rename src/cli/args/{cd.rs => cd_arg.rs} (91%) rename src/cli/args/{env_var.rs => env_var_arg.rs} (100%) rename src/cli/args/{log_level.rs => log_level_arg.rs} (86%) rename src/cli/args/{quiet.rs => quiet_arg.rs} (89%) rename src/cli/args/{tool.rs => tool_arg.rs} (100%) rename src/cli/args/{verbose.rs => verbose_arg.rs} (87%) rename src/cli/args/{yes.rs => yes_arg.rs} (85%) diff --git a/src/cli/args/cd.rs b/src/cli/args/cd_arg.rs similarity index 91% rename from src/cli/args/cd.rs rename to src/cli/args/cd_arg.rs index 2eebe08b1..226efc4f9 100644 --- a/src/cli/args/cd.rs +++ b/src/cli/args/cd_arg.rs @@ -1,9 +1,9 @@ use clap::{Arg, ArgAction}; #[derive(Clone)] -pub struct Cd; +pub struct CdArg; -impl Cd { +impl CdArg { pub fn arg() -> Arg { Arg::new("cd") .short('C') diff --git a/src/cli/args/env_var.rs b/src/cli/args/env_var_arg.rs similarity index 100% rename from src/cli/args/env_var.rs rename to src/cli/args/env_var_arg.rs diff --git a/src/cli/args/log_level.rs b/src/cli/args/log_level_arg.rs similarity index 86% rename from src/cli/args/log_level.rs rename to src/cli/args/log_level_arg.rs index b650884e8..3bb2398ae 100644 --- a/src/cli/args/log_level.rs +++ b/src/cli/args/log_level_arg.rs @@ -2,9 +2,9 @@ use clap::{Arg, ArgAction}; use log::LevelFilter; #[derive(Clone)] -pub struct LogLevel(pub LevelFilter); +pub struct LogLevelArg(pub LevelFilter); -impl LogLevel { +impl LogLevelArg { pub fn arg() -> clap::Arg { Arg::new("log-level") .long("log-level") @@ -16,9 +16,9 @@ impl LogLevel { } } -pub struct Debug; +pub struct DebugArg; -impl Debug { +impl DebugArg { pub fn arg() -> clap::Arg { Arg::new("debug") .long("debug") @@ -29,9 +29,9 @@ impl Debug { } } -pub struct Trace; +pub struct TraceArg; -impl Trace { +impl TraceArg { pub fn arg() -> clap::Arg { Arg::new("trace") .long("trace") diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index e3c7dafad..7165fb5b8 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,7 +1,15 @@ -pub mod cd; -pub mod env_var; -pub mod log_level; -pub mod quiet; -pub mod tool; -pub mod verbose; -pub mod yes; +pub use cd_arg::CdArg; +pub use env_var_arg::EnvVarArg; +pub use log_level_arg::{DebugArg, LogLevelArg, TraceArg}; +pub use quiet_arg::QuietArg; +pub use tool_arg::ToolArg; +pub use verbose_arg::VerboseArg; +pub use yes_arg::YesArg; + +mod cd_arg; +mod env_var_arg; +mod log_level_arg; +mod quiet_arg; +mod tool_arg; +mod verbose_arg; +mod yes_arg; diff --git a/src/cli/args/quiet.rs b/src/cli/args/quiet_arg.rs similarity index 89% rename from src/cli/args/quiet.rs rename to src/cli/args/quiet_arg.rs index cb4ef8dd8..4e4b1aba4 100644 --- a/src/cli/args/quiet.rs +++ b/src/cli/args/quiet_arg.rs @@ -1,9 +1,9 @@ use clap::{Arg, ArgAction}; #[derive(Clone)] -pub struct Quiet; +pub struct QuietArg; -impl Quiet { +impl QuietArg { pub fn arg() -> Arg { Arg::new("quiet") .short('q') diff --git a/src/cli/args/tool.rs b/src/cli/args/tool_arg.rs similarity index 100% rename from src/cli/args/tool.rs rename to src/cli/args/tool_arg.rs diff --git a/src/cli/args/verbose.rs b/src/cli/args/verbose_arg.rs similarity index 87% rename from src/cli/args/verbose.rs rename to src/cli/args/verbose_arg.rs index 78c0cc839..ad90eb5f0 100644 --- a/src/cli/args/verbose.rs +++ b/src/cli/args/verbose_arg.rs @@ -1,9 +1,9 @@ use clap::{Arg, ArgAction}; #[derive(Clone)] -pub struct Verbose(pub u8); +pub struct VerboseArg(pub u8); -impl Verbose { +impl VerboseArg { pub fn arg() -> clap::Arg { Arg::new("verbose") .short('v') diff --git a/src/cli/args/yes.rs b/src/cli/args/yes_arg.rs similarity index 85% rename from src/cli/args/yes.rs rename to src/cli/args/yes_arg.rs index 2abbb0d80..16493c050 100644 --- a/src/cli/args/yes.rs +++ b/src/cli/args/yes_arg.rs @@ -1,8 +1,8 @@ use clap::{Arg, ArgAction}; -pub struct Yes(pub bool); +pub struct YesArg(pub bool); -impl Yes { +impl YesArg { pub fn arg() -> Arg { Arg::new("yes") .short('y') diff --git a/src/cli/env.rs b/src/cli/env.rs index 529fe415e..d0ee0c54d 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -1,6 +1,6 @@ use eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::shell::{get_shell, ShellType}; use crate::toolset::{InstallOptions, Toolset, ToolsetBuilder}; diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 0f1cfc781..a110bd00f 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -5,7 +5,7 @@ use clap::ValueHint; use duct::IntoExecutablePath; use eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; #[cfg(test)] use crate::cmd; use crate::config::Config; diff --git a/src/cli/global.rs b/src/cli/global.rs index cbcd50acc..d8e81843c 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,6 +1,6 @@ use eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::cli::local::local; use crate::config::Config; use crate::env; diff --git a/src/cli/install.rs b/src/cli/install.rs index ca90d457b..0299b5151 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -1,6 +1,6 @@ use eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::toolset::{ InstallOptions, ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 7ffef9e7f..879b28430 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::toolset::ToolVersionRequest; use crate::ui::multi_progress_report::MultiProgressReport; diff --git a/src/cli/link.rs b/src/cli/link.rs index 833cd9da8..a11d2fc04 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -5,7 +5,7 @@ use color_eyre::eyre::{eyre, Result}; use console::style; use path_absolutize::Absolutize; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::file::{make_symlink, remove_all}; use crate::{dirs, file}; diff --git a/src/cli/local.rs b/src/cli/local.rs index 16422aee6..75b3a4363 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -4,7 +4,7 @@ use color_eyre::eyre::{eyre, ContextCompat, Result}; use console::style; use itertools::Itertools; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::{config_file, Config, Settings}; use crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index f9616eb40..23a101a78 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -4,7 +4,7 @@ use eyre::Result; use itertools::Itertools; use rayon::prelude::*; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::forge::Forge; use crate::toolset::ToolVersionRequest; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index d91b38211..af883f74e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -184,13 +184,13 @@ impl Cli { .arg_required_else_help(true) .subcommand_required(true) .after_long_help(AFTER_LONG_HELP) - .arg(args::log_level::Debug::arg()) - .arg(args::log_level::LogLevel::arg()) - .arg(args::log_level::Trace::arg()) - .arg(args::cd::Cd::arg()) - .arg(args::quiet::Quiet::arg()) - .arg(args::verbose::Verbose::arg()) - .arg(args::yes::Yes::arg()), + .arg(args::CdArg::arg()) + .arg(args::DebugArg::arg()) + .arg(args::LogLevelArg::arg()) + .arg(args::QuietArg::arg()) + .arg(args::TraceArg::arg()) + .arg(args::VerboseArg::arg()) + .arg(args::YesArg::arg()), ) } diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index fc79b76fa..f56273dcf 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use console::{pad_str, style, Alignment}; use eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolsetBuilder}; diff --git a/src/cli/run.rs b/src/cli/run.rs index 6dcf83a29..6884835ec 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -18,7 +18,7 @@ use once_cell::sync::Lazy; use petgraph::graph::DiGraph; use petgraph::Direction; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::errors::Error; diff --git a/src/cli/set.rs b/src/cli/set.rs index 18dfa648b..26a247f5e 100644 --- a/src/cli/set.rs +++ b/src/cli/set.rs @@ -10,7 +10,7 @@ use crate::env; use crate::file::display_path; use crate::ui::table; -use super::args::env_var::EnvVarArg; +use super::args::EnvVarArg; /// Manage environment variables /// diff --git a/src/cli/shell.rs b/src/cli/shell.rs index e568ce177..f701056b4 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::{eyre, Result}; use console::style; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::shell::get_shell; use crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder}; diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 0cab74c87..b6b8eae01 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -5,7 +5,7 @@ use eyre::{Result, WrapErr}; use itertools::Itertools; use rayon::prelude::*; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index ce2765b28..35207b124 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use demand::DemandOption; use eyre::{Context, Result}; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::forge::Forge; use crate::shims; diff --git a/src/cli/use.rs b/src/cli/use.rs index d8f2db595..979c11d29 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -4,7 +4,7 @@ use console::style; use eyre::Result; use itertools::Itertools; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config, Settings}; use crate::env::{ diff --git a/src/cli/where.rs b/src/cli/where.rs index 3c5b8b6d2..000e0789a 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -1,6 +1,6 @@ use eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; use crate::toolset::ToolsetBuilder; diff --git a/src/cli/which.rs b/src/cli/which.rs index 811a1a515..1de6dc0ef 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -1,6 +1,6 @@ use eyre::Result; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::Config; use crate::dirs::SHIMS; use crate::toolset::{Toolset, ToolsetBuilder}; diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 866a910c8..ba76107f4 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -10,7 +10,7 @@ use once_cell::sync::Lazy; use tool_versions::ToolVersions; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::config_file::mise_toml::MiseToml; use crate::config::{global_config_files, system_config_files, AliasMap, Config, Settings}; use crate::errors::Error::UntrustedConfig; diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index da02c6daf..07cd94c75 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use eyre::Result; use itertools::Itertools; -use crate::cli::args::tool::ToolArg; +use crate::cli::args::ToolArg; use crate::config::{Config, Settings}; use crate::env; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; From db82e62c920c1cc48cc6f32993b5bf0de1ce7441 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 02:58:58 -0600 Subject: [PATCH 1611/1891] added "forge" infra (#1450) * cargo: added forge arg * forge: added forge arg parsing * forge: get double_tool_condition to work with new ToolArg * forge: added ForgeArg to allow different backends * fixed tests --- .idea/mise.iml | 1 + completions/_mise | 2 +- completions/mise.bash | 704 +++++++++--------- completions/mise.fish | 6 +- docs/cli-reference.md | 8 +- src/cli/alias/get.rs | 3 +- src/cli/alias/ls.rs | 21 +- src/cli/alias/mod.rs | 3 +- src/cli/alias/set.rs | 3 +- src/cli/alias/unset.rs | 3 +- src/cli/args/forge_arg.rs | 57 ++ src/cli/args/mod.rs | 2 + src/cli/args/tool_arg.rs | 105 ++- src/cli/asdf.rs | 9 +- src/cli/current.rs | 18 +- src/cli/doctor.rs | 13 +- src/cli/external.rs | 17 +- src/cli/global.rs | 7 +- src/cli/install.rs | 32 +- src/cli/latest.rs | 5 +- src/cli/link.rs | 4 +- src/cli/local.rs | 15 +- src/cli/ls.rs | 47 +- src/cli/ls_remote.rs | 22 +- src/cli/mod.rs | 6 +- src/cli/outdated.rs | 4 +- src/cli/plugins/install.rs | 12 +- src/cli/plugins/link.rs | 6 +- src/cli/plugins/ls.rs | 7 +- src/cli/plugins/ls_remote.rs | 4 +- src/cli/plugins/mod.rs | 4 +- src/cli/plugins/uninstall.rs | 22 +- src/cli/plugins/update.rs | 14 +- src/cli/prune.rs | 13 +- src/cli/reshim.rs | 2 +- src/cli/shell.rs | 2 +- src/cli/sync/node.rs | 8 +- src/cli/sync/python.rs | 4 +- src/cli/uninstall.rs | 19 +- src/cli/upgrade.rs | 6 +- src/cli/use.rs | 22 +- src/cli/watch.rs | 4 +- src/cli/where.rs | 7 +- src/config/config_file/legacy_version.rs | 12 +- src/config/config_file/mise_toml.rs | 102 +-- src/config/config_file/mod.rs | 41 +- ...fig_file__mise_toml__tests__fixture-3.snap | 38 +- ...fig_file__mise_toml__tests__fixture-4.snap | 2 +- ...fig_file__mise_toml__tests__fixture-5.snap | 4 +- ...ile__mise_toml__tests__remove_alias-4.snap | 2 +- ..._file__mise_toml__tests__remove_alias.snap | 2 +- ...e__mise_toml__tests__replace_versions.snap | 8 +- ...fig_file__mise_toml__tests__set_alias.snap | 4 +- src/config/config_file/tool_versions.rs | 39 +- src/config/mod.rs | 107 +-- .../snapshots/mise__config__tests__load.snap | 6 +- src/forge/cargo.rs | 28 + src/forge/mod.rs | 135 +++- src/plugins/core/mod.rs | 25 +- src/plugins/external_plugin.rs | 12 +- src/plugins/mod.rs | 70 +- src/runtime_symlinks.rs | 13 +- src/shell/completions/fish_complete.rs | 2 +- src/shell/completions/zsh_complete.rs | 8 +- src/shims.rs | 18 +- src/test.rs | 4 +- src/toolset/builder.rs | 24 +- src/toolset/mod.rs | 61 +- src/toolset/tool_version.rs | 41 +- src/toolset/tool_version_list.rs | 34 +- src/toolset/tool_version_request.rs | 44 +- src/ui/progress_report.rs | 14 +- 72 files changed, 1162 insertions(+), 1011 deletions(-) create mode 100644 src/cli/args/forge_arg.rs create mode 100644 src/forge/cargo.rs diff --git a/.idea/mise.iml b/.idea/mise.iml index 8e4258be6..58dd59249 100644 --- a/.idea/mise.iml +++ b/.idea/mise.iml @@ -20,6 +20,7 @@ + diff --git a/completions/_mise b/completions/_mise index 90e1ec931..9699c1ebd 100644 --- a/completions/_mise +++ b/completions/_mise @@ -843,7 +843,7 @@ __mise_use_cmd() { '(-e --env)'{-e,--env}'=[Modify an environment-specific config file like .mise..toml]:env:' \ '(-j --jobs)'{-j,--jobs}'=[Number of jobs to run in parallel]:jobs:' \ '--raw[Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1]' \ - '*--remove=[Remove the tool(s) from config file]:remove:' \ + '*--remove=[Remove the plugin(s) from config file]:remove:' \ '(-p --path)'{-p,--path}'=[Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions]:path:_files' \ '--pin[Save exact version to config file]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ diff --git a/completions/mise.bash b/completions/mise.bash index 8c0a1b971..e54ae876e 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -703,16 +703,12 @@ _mise() { case "${cmd}" in mise) - opts="-C -q -v -y -h -V --debug --log-level --trace --cd --quiet --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update set settings shell sync task trust uninstall upgrade unset use version watch where which render-completion render-help render-mangen help" + opts="-C -q -v -y -h -V --cd --debug --log-level --quiet --trace --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update set settings shell sync task trust uninstall upgrade unset use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -721,6 +717,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -729,7 +729,7 @@ _mise() { return 0 ;; mise__activate) - opts="-s -q -C -v -y -h --shell --status --quiet --debug --log-level --trace --cd --verbose --yes --help bash fish nu xonsh zsh" + opts="-s -q -C -v -y -h --shell --status --quiet --cd --debug --log-level --trace --verbose --yes --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -743,10 +743,6 @@ _mise() { COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -755,6 +751,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -763,7 +763,7 @@ _mise() { return 0 ;; mise__alias) - opts="-p -C -q -v -y -h --plugin --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help get ls set unset help" + opts="-p -C -q -v -y -h --plugin --no-header --cd --debug --log-level --quiet --trace --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -777,10 +777,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -789,6 +785,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -797,16 +797,12 @@ _mise() { return 0 ;; mise__alias__get) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -815,6 +811,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -907,16 +907,12 @@ _mise() { return 0 ;; mise__alias__ls) - opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]" + opts="-C -q -v -y -h --no-header --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -925,6 +921,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -933,16 +933,12 @@ _mise() { return 0 ;; mise__alias__set) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -951,6 +947,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -959,16 +959,12 @@ _mise() { return 0 ;; mise__alias__unset) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -977,6 +973,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -985,16 +985,12 @@ _mise() { return 0 ;; mise__asdf) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [ARGS]..." + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1003,6 +999,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1011,16 +1011,12 @@ _mise() { return 0 ;; mise__bin__paths) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1029,6 +1025,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1037,16 +1037,12 @@ _mise() { return 0 ;; mise__cache) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help clear help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help clear help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1055,6 +1051,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1063,16 +1063,12 @@ _mise() { return 0 ;; mise__cache__clear) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1081,6 +1077,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1131,7 +1131,7 @@ _mise() { return 0 ;; mise__completion) - opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help bash fish zsh" + opts="-s -C -q -v -y -h --shell --cd --debug --log-level --quiet --trace --verbose --yes --help bash fish zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1145,10 +1145,6 @@ _mise() { COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1157,6 +1153,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1165,16 +1165,12 @@ _mise() { return 0 ;; mise__config) - opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help ls generate help" + opts="-C -q -v -y -h --no-header --cd --debug --log-level --quiet --trace --verbose --yes --help ls generate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1183,6 +1179,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1191,7 +1191,7 @@ _mise() { return 0 ;; mise__config__generate) - opts="-o -C -q -v -y -h --output --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-o -C -q -v -y -h --output --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1205,10 +1205,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1217,6 +1213,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1281,16 +1281,12 @@ _mise() { return 0 ;; mise__config__ls) - opts="-C -q -v -y -h --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --no-header --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1299,6 +1295,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1307,16 +1307,12 @@ _mise() { return 0 ;; mise__current) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1325,6 +1321,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1333,16 +1333,12 @@ _mise() { return 0 ;; mise__deactivate) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1351,6 +1347,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1359,16 +1359,12 @@ _mise() { return 0 ;; mise__direnv) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help envrc exec activate help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help envrc exec activate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1377,6 +1373,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1385,16 +1385,12 @@ _mise() { return 0 ;; mise__direnv__activate) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1403,6 +1399,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1411,16 +1411,12 @@ _mise() { return 0 ;; mise__direnv__envrc) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1429,6 +1425,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1437,16 +1437,12 @@ _mise() { return 0 ;; mise__direnv__exec) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1455,6 +1451,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1533,16 +1533,12 @@ _mise() { return 0 ;; mise__doctor) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1551,6 +1547,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1559,7 +1559,7 @@ _mise() { return 0 ;; mise__env) - opts="-s -J -C -q -v -y -h --shell --json --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-s -J -C -q -v -y -h --shell --json --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1573,10 +1573,6 @@ _mise() { COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1585,6 +1581,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1593,7 +1593,7 @@ _mise() { return 0 ;; mise__exec) - opts="-c -j -C -q -v -y -h --command --jobs --raw --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." + opts="-c -j -C -q -v -y -h --command --jobs --raw --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]... [COMMAND]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1615,10 +1615,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1627,6 +1623,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -1635,7 +1635,7 @@ _mise() { return 0 ;; mise__global) - opts="-C -q -v -y -h --pin --fuzzy --remove --path --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-C -q -v -y -h --pin --fuzzy --remove --path --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1645,10 +1645,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1657,6 +1653,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2687,7 +2687,7 @@ _mise() { return 0 ;; mise__hook__env) - opts="-s -q -C -v -y -h --shell --status --quiet --debug --log-level --trace --cd --verbose --yes --help" + opts="-s -q -C -v -y -h --shell --status --quiet --cd --debug --log-level --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2701,10 +2701,6 @@ _mise() { COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2713,6 +2709,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2721,7 +2721,7 @@ _mise() { return 0 ;; mise__hook__not__found) - opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-s -C -q -v -y -h --shell --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2735,10 +2735,6 @@ _mise() { COMPREPLY=($(compgen -W "bash fish nu xonsh zsh" -- "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2747,6 +2743,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2755,16 +2755,12 @@ _mise() { return 0 ;; mise__implode) - opts="-n -C -q -v -y -h --config --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-n -C -q -v -y -h --config --dry-run --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2773,6 +2769,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2781,7 +2781,7 @@ _mise() { return 0 ;; mise__install) - opts="-f -j -v -C -q -y -h --force --jobs --raw --verbose --debug --log-level --trace --cd --quiet --yes --help [TOOL@VERSION]..." + opts="-f -j -v -C -q -y -h --force --jobs --raw --verbose --cd --debug --log-level --quiet --trace --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2795,10 +2795,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2807,6 +2803,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2815,16 +2815,12 @@ _mise() { return 0 ;; mise__latest) - opts="-i -C -q -v -y -h --installed --debug --log-level --trace --cd --quiet --verbose --yes --help [ASDF_VERSION]" + opts="-i -C -q -v -y -h --installed --cd --debug --log-level --quiet --trace --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2833,6 +2829,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2841,16 +2841,12 @@ _mise() { return 0 ;; mise__link) - opts="-f -C -q -v -y -h --force --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-f -C -q -v -y -h --force --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2859,6 +2855,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2867,7 +2867,7 @@ _mise() { return 0 ;; mise__local) - opts="-p -C -q -v -y -h --parent --pin --fuzzy --remove --path --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-p -C -q -v -y -h --parent --pin --fuzzy --remove --path --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2877,10 +2877,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2889,6 +2885,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2897,7 +2897,7 @@ _mise() { return 0 ;; mise__ls) - opts="-p -c -g -i -J -m -C -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --no-header --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." + opts="-p -c -g -i -J -m -C -q -v -y -h --plugin --current --global --installed --parseable --json --missing --prefix --no-header --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2915,10 +2915,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2927,6 +2923,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2935,16 +2935,12 @@ _mise() { return 0 ;; mise__ls__remote) - opts="-C -q -v -y -h --all --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION] [PREFIX]" + opts="-C -q -v -y -h --all --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION] [PREFIX]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2953,6 +2949,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2961,16 +2961,12 @@ _mise() { return 0 ;; mise__outdated) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2979,6 +2975,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -2987,16 +2987,12 @@ _mise() { return 0 ;; mise__plugins) - opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --cd --quiet --verbose --yes --help install link ls ls-remote uninstall update help" + opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --cd --debug --log-level --quiet --trace --verbose --yes --help install link ls ls-remote uninstall update help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3005,6 +3001,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3125,16 +3125,12 @@ _mise() { return 0 ;; mise__plugins__install) - opts="-f -a -v -C -q -y -h --force --all --verbose --debug --log-level --trace --cd --quiet --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." + opts="-f -a -v -C -q -y -h --force --all --verbose --cd --debug --log-level --quiet --trace --yes --help [NEW_PLUGIN] [GIT_URL] [REST]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3143,6 +3139,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3151,16 +3151,12 @@ _mise() { return 0 ;; mise__plugins__link) - opts="-f -C -q -v -y -h --force --debug --log-level --trace --cd --quiet --verbose --yes --help [PATH]" + opts="-f -C -q -v -y -h --force --cd --debug --log-level --quiet --trace --verbose --yes --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3169,6 +3165,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3177,16 +3177,12 @@ _mise() { return 0 ;; mise__plugins__ls) - opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-a -c -u -C -q -v -y -h --all --core --user --urls --refs --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3195,6 +3191,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3203,16 +3203,12 @@ _mise() { return 0 ;; mise__plugins__ls__remote) - opts="-u -C -q -v -y -h --urls --only-names --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-u -C -q -v -y -h --urls --only-names --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3221,6 +3217,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3229,16 +3229,12 @@ _mise() { return 0 ;; mise__plugins__uninstall) - opts="-p -a -C -q -v -y -h --purge --all --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." + opts="-p -a -C -q -v -y -h --purge --all --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3247,6 +3243,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3255,7 +3255,7 @@ _mise() { return 0 ;; mise__plugins__update) - opts="-j -C -q -v -y -h --jobs --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." + opts="-j -C -q -v -y -h --jobs --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3269,10 +3269,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3281,6 +3277,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3289,16 +3289,12 @@ _mise() { return 0 ;; mise__prune) - opts="-n -C -q -v -y -h --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN]..." + opts="-n -C -q -v -y -h --dry-run --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3307,6 +3303,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3315,7 +3315,7 @@ _mise() { return 0 ;; mise__render__completion) - opts="-s -C -q -v -y -h --shell --debug --log-level --trace --cd --quiet --verbose --yes --help bash elvish fish powershell zsh" + opts="-s -C -q -v -y -h --shell --cd --debug --log-level --quiet --trace --verbose --yes --help bash elvish fish powershell zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3329,10 +3329,6 @@ _mise() { COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3341,6 +3337,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3349,16 +3349,12 @@ _mise() { return 0 ;; mise__render__help) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3367,6 +3363,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3375,16 +3375,12 @@ _mise() { return 0 ;; mise__render__mangen) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3393,6 +3389,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3401,16 +3401,12 @@ _mise() { return 0 ;; mise__reshim) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [PLUGIN] [VERSION]" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help [PLUGIN] [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3419,6 +3415,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3427,7 +3427,7 @@ _mise() { return 0 ;; mise__run) - opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TASK] [ARGS]..." + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --quiet --trace --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3469,16 +3469,12 @@ _mise() { return 0 ;; mise__self__update) - opts="-f -y -C -q -v -h --force --no-plugins --yes --debug --log-level --trace --cd --quiet --verbose --help [VERSION]" + opts="-f -y -C -q -v -h --force --no-plugins --yes --cd --debug --log-level --quiet --trace --verbose --help [VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3487,6 +3483,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3495,7 +3495,7 @@ _mise() { return 0 ;; mise__set) - opts="-g -C -q -v -y -h --file --global --remove --debug --log-level --trace --cd --quiet --verbose --yes --help [ENV_VARS]..." + opts="-g -C -q -v -y -h --file --global --remove --cd --debug --log-level --quiet --trace --verbose --yes --help [ENV_VARS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3509,10 +3509,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3521,6 +3517,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3529,16 +3529,12 @@ _mise() { return 0 ;; mise__settings) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help get ls set unset help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help get ls set unset help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3547,6 +3543,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3555,16 +3555,12 @@ _mise() { return 0 ;; mise__settings__get) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3573,6 +3569,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3665,16 +3665,12 @@ _mise() { return 0 ;; mise__settings__ls) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3683,6 +3679,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3691,16 +3691,12 @@ _mise() { return 0 ;; mise__settings__set) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3709,6 +3705,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3717,16 +3717,12 @@ _mise() { return 0 ;; mise__settings__unset) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3735,6 +3731,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3743,7 +3743,7 @@ _mise() { return 0 ;; mise__shell) - opts="-j -u -C -q -v -y -h --jobs --raw --unset --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-j -u -C -q -v -y -h --jobs --raw --unset --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3757,10 +3757,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3769,6 +3765,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3777,16 +3777,12 @@ _mise() { return 0 ;; mise__sync) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help node python help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help node python help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3795,6 +3791,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3859,16 +3859,12 @@ _mise() { return 0 ;; mise__sync__node) - opts="-C -q -v -y -h --brew --nvm --nodenv --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --brew --nvm --nodenv --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3877,6 +3873,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3885,16 +3885,12 @@ _mise() { return 0 ;; mise__sync__python) - opts="-C -q -v -y -h --pyenv --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --pyenv --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3903,6 +3899,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3911,16 +3911,12 @@ _mise() { return 0 ;; mise__task) - opts="-C -q -v -y -h --no-header --hidden --debug --log-level --trace --cd --quiet --verbose --yes --help edit ls run help" + opts="-C -q -v -y -h --no-header --hidden --cd --debug --log-level --quiet --trace --verbose --yes --help edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3929,6 +3925,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -3937,16 +3937,12 @@ _mise() { return 0 ;; mise__task__edit) - opts="-p -C -q -v -y -h --path --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-p -C -q -v -y -h --path --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -3955,6 +3951,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4033,16 +4033,12 @@ _mise() { return 0 ;; mise__task__ls) - opts="-C -q -v -y -h --no-header --hidden --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --no-header --hidden --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4051,6 +4047,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4059,7 +4059,7 @@ _mise() { return 0 ;; mise__task__run) - opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --trace --quiet --verbose --yes --help [TASK] [ARGS]..." + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --quiet --trace --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4101,16 +4101,12 @@ _mise() { return 0 ;; mise__trust) - opts="-a -C -q -v -y -h --all --untrust --debug --log-level --trace --cd --quiet --verbose --yes --help [CONFIG_FILE]" + opts="-a -C -q -v -y -h --all --untrust --cd --debug --log-level --quiet --trace --verbose --yes --help [CONFIG_FILE]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4119,6 +4115,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4127,16 +4127,12 @@ _mise() { return 0 ;; mise__uninstall) - opts="-a -n -C -q -v -y -h --all --dry-run --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-a -n -C -q -v -y -h --all --dry-run --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4145,6 +4141,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4153,7 +4153,7 @@ _mise() { return 0 ;; mise__unset) - opts="-f -g -C -q -v -y -h --file --global --debug --log-level --trace --cd --quiet --verbose --yes --help [KEYS]..." + opts="-f -g -C -q -v -y -h --file --global --cd --debug --log-level --quiet --trace --verbose --yes --help [KEYS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4167,10 +4167,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4179,6 +4175,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4187,7 +4187,7 @@ _mise() { return 0 ;; mise__upgrade) - opts="-n -j -i -C -q -v -y -h --dry-run --jobs --interactive --raw --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-n -j -i -C -q -v -y -h --dry-run --jobs --interactive --raw --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4201,10 +4201,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4213,6 +4209,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4221,7 +4221,7 @@ _mise() { return 0 ;; mise__use) - opts="-f -g -e -j -p -C -q -v -y -h --force --fuzzy --global --env --jobs --raw --remove --path --pin --debug --log-level --trace --cd --quiet --verbose --yes --help [TOOL@VERSION]..." + opts="-f -g -e -j -p -C -q -v -y -h --force --fuzzy --global --env --jobs --raw --remove --path --pin --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4255,10 +4255,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4267,6 +4263,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4275,16 +4275,12 @@ _mise() { return 0 ;; mise__version) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4293,6 +4289,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4301,7 +4301,7 @@ _mise() { return 0 ;; mise__watch) - opts="-t -g -C -q -v -y -h --task --glob --debug --log-level --trace --cd --quiet --verbose --yes --help [ARGS]..." + opts="-t -g -C -q -v -y -h --task --glob --cd --debug --log-level --quiet --trace --verbose --yes --help [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4323,10 +4323,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4335,6 +4331,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4343,16 +4343,12 @@ _mise() { return 0 ;; mise__where) - opts="-C -q -v -y -h --debug --log-level --trace --cd --quiet --verbose --yes --help [ASDF_VERSION]" + opts="-C -q -v -y -h --cd --debug --log-level --quiet --trace --verbose --yes --help [ASDF_VERSION]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4361,6 +4357,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; @@ -4369,7 +4369,7 @@ _mise() { return 0 ;; mise__which) - opts="-t -C -q -v -y -h --plugin --version --tool --debug --log-level --trace --cd --quiet --verbose --yes --help " + opts="-t -C -q -v -y -h --plugin --version --tool --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4383,10 +4383,6 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - --log-level) - COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) - return 0 - ;; --cd) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -4395,6 +4391,10 @@ _mise() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; diff --git a/completions/mise.fish b/completions/mise.fish index 47a51cf43..123798678 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -104,7 +104,7 @@ complete -kxc mise -n "$fssf config; and $fssf ls" -l no-header -d 'Do not print # current -complete -kxc mise -n "$fssf current" -a "(__mise_plugins)" -d 'Plugin to show versions of e.g.: ruby, node' +complete -kxc mise -n "$fssf current" -a "(__mise_plugins)" -d 'Plugin to show versions of e.g.: ruby, node, cargo:eza, npm:prettier, etc' # deactivate @@ -212,7 +212,7 @@ complete -kxc mise -n "$fssf plugins; and $fssf update" -a "(__mise_plugins)" -d # prune complete -kxc mise -n "$fssf prune" -s n -l dry-run -d 'Do not actually delete anything' -complete -kxc mise -n "$fssf prune" -a "(__mise_plugins)" -d 'Prune only versions from these plugins' +complete -kxc mise -n "$fssf prune" -a "(__mise_plugins)" -d 'Prune only versions from this plugin(s)' # reshim @@ -339,7 +339,7 @@ complete -kxc mise -n "$fssf use" -s j -l jobs -d 'Number of jobs to run in para complete -kxc mise -n "$fssf use" -s p -l path -a "(__fish_complete_path)" -d 'Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions' complete -kxc mise -n "$fssf use" -l pin -d 'Save exact version to config file' complete -kxc mise -n "$fssf use" -l raw -d 'Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1' -complete -kxc mise -n "$fssf use" -l remove -d 'Remove the tool(s) from config file' +complete -kxc mise -n "$fssf use" -l remove -d 'Remove the plugin(s) from config file' complete -kxc mise -n "$fssf use" -a "(__mise_tool_versions)" -d 'Tool(s) to add to config file' # version diff --git a/docs/cli-reference.md b/docs/cli-reference.md index d6ee925d0..6614a8d97 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -229,7 +229,7 @@ Usage: current [PLUGIN] Arguments: [PLUGIN] - Plugin to show versions of e.g.: ruby, node + Plugin to show versions of e.g.: ruby, node, cargo:eza, npm:prettier, etc Examples: # outputs `.tool-versions` compatible format @@ -818,7 +818,7 @@ Usage: prune [OPTIONS] [PLUGIN]... Arguments: [PLUGIN]... - Prune only versions from these plugins + Prune only versions from this plugin(s) Options: -n, --dry-run @@ -1471,8 +1471,8 @@ Options: --raw Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - --remove - Remove the tool(s) from config file + --remove + Remove the plugin(s) from config file -p, --path Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index c409fc748..9e917c2d1 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -1,3 +1,4 @@ +use crate::cli::args::ForgeArg; use color_eyre::eyre::{eyre, Result}; use crate::config::Config; @@ -10,7 +11,7 @@ use crate::config::Config; #[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasGet { /// The plugin to show the alias for - pub plugin: String, + pub plugin: ForgeArg, /// The alias to show pub alias: String, } diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 4fdb9dcad..91b41623d 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,3 +1,4 @@ +use crate::cli::args::ForgeArg; use eyre::Result; use tabled::Tabled; @@ -17,7 +18,7 @@ use crate::ui::table; pub struct AliasLs { /// Show aliases for #[clap()] - pub plugin: Option, + pub plugin: Option, /// Don't show table header #[clap(long)] @@ -30,12 +31,15 @@ impl AliasLs { let rows = config .get_all_aliases() .iter() - .flat_map(|(plugin, aliases)| { + .filter(|(fa, _)| { + self.plugin.is_none() || self.plugin.as_ref().is_some_and(|f| &f == fa) + }) + .flat_map(|(fa, aliases)| { aliases .iter() - .filter(|(from, _to)| plugin != "node" || !from.starts_with("lts/")) + .filter(|(from, _to)| fa.name != "node" || !from.starts_with("lts/")) .map(|(from, to)| Row { - plugin: plugin.clone(), + plugin: fa.to_string(), alias: from.clone(), version: to.clone(), }) @@ -84,4 +88,13 @@ mod tests { tiny my/alias 3.0 "###); } + + #[test] + fn test_alias_ls_filter() { + assert_cli_snapshot!("aliases", "ls", "tiny", @r###" + tiny lts 3.1.0 + tiny lts-prev 2.0.0 + tiny my/alias 3.0 + "###); + } } diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index 9dc4d8ca7..3fad4056f 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -1,3 +1,4 @@ +use crate::cli::args::ForgeArg; use clap::Subcommand; use eyre::Result; @@ -14,7 +15,7 @@ pub struct Alias { /// filter aliases by plugin #[clap(short, long)] - pub plugin: Option, + pub plugin: Option, /// Don't show table header #[clap(long)] diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index 2de54615e..a5408b521 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -1,5 +1,6 @@ use eyre::Result; +use crate::cli::args::ForgeArg; use crate::config::config_file::ConfigFile; use crate::config::Config; @@ -10,7 +11,7 @@ use crate::config::Config; #[clap(visible_aliases = ["add", "create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasSet { /// The plugin to set the alias for - pub plugin: String, + pub plugin: ForgeArg, /// The alias to set pub alias: String, /// The value to set the alias to diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 4e4e59095..65be609e5 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -1,3 +1,4 @@ +use crate::cli::args::ForgeArg; use eyre::Result; use crate::config::config_file::ConfigFile; @@ -10,7 +11,7 @@ use crate::config::Config; #[clap(visible_aliases = ["rm", "remove", "delete", "del"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)] pub struct AliasUnset { /// The plugin to remove the alias from - pub plugin: String, + pub plugin: ForgeArg, /// The alias to remove pub alias: String, } diff --git a/src/cli/args/forge_arg.rs b/src/cli/args/forge_arg.rs new file mode 100644 index 000000000..321b04b21 --- /dev/null +++ b/src/cli/args/forge_arg.rs @@ -0,0 +1,57 @@ +use std::fmt::{Debug, Display}; +use std::hash::Hash; +use std::str::FromStr; + +use crate::forge; +use crate::forge::unalias_forge; +use crate::forge::{AForge, ForgeType}; + +#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ForgeArg { + pub name: String, + pub forge_type: ForgeType, +} + +impl FromStr for ForgeArg { + type Err = eyre::Error; + + fn from_str(s: &str) -> Result { + let (forge_type, name) = s.split_once(':').unwrap_or(("asdf", s)); + let forge_type = forge_type.parse()?; + Ok(Self::new(forge_type, name)) + } +} + +impl ForgeArg { + pub fn new(forge_type: ForgeType, name: &str) -> Self { + let name = unalias_forge(name).to_string(); + Self { name, forge_type } + } + pub fn get_forge(&self) -> AForge { + forge::get(self) + } + pub fn pathname(&self) -> String { + match self.forge_type { + ForgeType::Asdf => self.name.to_string(), + forge_type => format!("{}-{}", forge_type.as_ref(), self.name), + } + } +} + +impl Display for ForgeArg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.forge_type { + ForgeType::Asdf => write!(f, "{}", self.name), + ft => write!(f, "{}:{}", ft.as_ref(), self.name), + } + } +} + +impl Debug for ForgeArg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.forge_type { + ForgeType::Asdf => write!(f, r#"ForgeArg("{}")"#, self.name), + ft => write!(f, r#"ForgeArg("{}:{}")"#, ft.as_ref(), self.name), + } + } +} diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index 7165fb5b8..f26ed5f4c 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -1,5 +1,6 @@ pub use cd_arg::CdArg; pub use env_var_arg::EnvVarArg; +pub use forge_arg::ForgeArg; pub use log_level_arg::{DebugArg, LogLevelArg, TraceArg}; pub use quiet_arg::QuietArg; pub use tool_arg::ToolArg; @@ -8,6 +9,7 @@ pub use yes_arg::YesArg; mod cd_arg; mod env_var_arg; +mod forge_arg; mod log_level_arg; mod quiet_arg; mod tool_arg; diff --git a/src/cli/args/tool_arg.rs b/src/cli/args/tool_arg.rs index 88764457b..02f3ca6d9 100644 --- a/src/cli/args/tool_arg.rs +++ b/src/cli/args/tool_arg.rs @@ -1,36 +1,73 @@ use std::fmt::Display; +use std::path::PathBuf; use std::str::FromStr; use console::style; use regex::Regex; -use crate::plugins::unalias_plugin; +use crate::cli::args::ForgeArg; use crate::toolset::ToolVersionRequest; +use crate::ui::style; #[derive(Debug, Clone, Eq, PartialEq)] pub struct ToolArg { - pub plugin: String, + pub forge: ForgeArg, + pub version: Option, + pub version_type: ToolVersionType, pub tvr: Option, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum ToolVersionType { + Path(PathBuf), + Prefix(String), + Ref(String), + Sub { sub: String, orig_version: String }, + System, + Version(String), +} + impl FromStr for ToolArg { type Err = eyre::Error; fn from_str(input: &str) -> eyre::Result { - let arg = match input.split_once('@') { - Some((plugin, version)) => { - let plugin = unalias_plugin(plugin).to_string(); - Self { - plugin: plugin.clone(), - tvr: Some(ToolVersionRequest::new(plugin, version)), - } - } - None => Self { - plugin: unalias_plugin(input).into(), - tvr: None, - }, + let (forge_input, version) = input + .split_once('@') + .map(|(f, v)| (f, Some(v.to_string()))) + .unwrap_or((input, None)); + let forge: ForgeArg = forge_input.parse()?; + let version_type = match version.as_ref() { + Some(version) => version.parse()?, + None => ToolVersionType::Version(String::from("latest")), }; - Ok(arg) + let tvr = version + .as_ref() + .map(|v| ToolVersionRequest::new(forge.clone(), v)); + Ok(Self { + tvr, + version, + version_type, + forge, + }) + } +} + +impl FromStr for ToolVersionType { + type Err = eyre::Error; + + fn from_str(s: &str) -> Result { + Ok(match s.split_once(':') { + Some(("ref", r)) => Self::Ref(r.to_string()), + Some(("prefix", p)) => Self::Prefix(p.to_string()), + Some(("path", p)) => Self::Path(PathBuf::from(p)), + Some((p, v)) if p.starts_with("sub-") => Self::Sub { + sub: p.split_once('-').unwrap().1.to_string(), + orig_version: v.to_string(), + }, + Some((p, _)) => bail!("invalid prefix: {}", style::ered(p)), + None if s == "system" => Self::System, + None => Self::Version(s.to_string()), + }) } } @@ -42,24 +79,28 @@ impl ToolArg { /// /// We can detect this, and we know what they meant, so make it work the way /// they expected. - pub fn double_tool_condition(tools: &[ToolArg]) -> Vec { + pub fn double_tool_condition(tools: &[ToolArg]) -> eyre::Result> { let mut tools = tools.to_vec(); if tools.len() == 2 { - let re: &Regex = regex!(r"^\d+(\.\d+)?(\.\d+)?$"); + let re: &Regex = regex!(r"^\d+(\.\d+)*$"); let a = tools[0].clone(); let b = tools[1].clone(); - if a.tvr.is_none() && b.tvr.is_none() && re.is_match(&b.plugin) { - tools[1].tvr = Some(ToolVersionRequest::new(a.plugin.clone(), &b.plugin)); - tools[1].plugin = a.plugin; + if a.tvr.is_none() && b.tvr.is_none() && re.is_match(&b.forge.name) { + tools[1].tvr = Some(ToolVersionRequest::new(a.forge.clone(), &b.forge.name)); + tools[1].forge = a.forge; + tools[1].version_type = b.forge.name.parse()?; + tools[1].version = Some(b.forge.name); tools.remove(0); } } - tools + Ok(tools) } pub fn with_version(self, version: &str) -> Self { Self { - tvr: Some(ToolVersionRequest::new(self.plugin.clone(), version)), + tvr: Some(ToolVersionRequest::new(self.forge.clone(), version)), + version: Some(version.into()), + version_type: version.parse().unwrap(), ..self } } @@ -72,7 +113,7 @@ impl ToolArg { .unwrap_or(String::from("latest")); format!( "{}{}", - style(&self.plugin).blue().for_stderr(), + style(&self.forge.name).blue().for_stderr(), style(&format!("@{version}")).for_stderr() ) } @@ -82,7 +123,7 @@ impl Display for ToolArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.tvr { Some(tvr) => write!(f, "{}", tvr), - _ => write!(f, "{}", self.plugin), + _ => write!(f, "{}", self.forge.name), } } } @@ -97,7 +138,9 @@ mod tests { assert_eq!( tool, ToolArg { - plugin: "node".into(), + forge: "node".parse().unwrap(), + version: None, + version_type: ToolVersionType::Version("latest".into()), tvr: None, } ); @@ -109,8 +152,10 @@ mod tests { assert_eq!( tool, ToolArg { - plugin: "node".into(), - tvr: Some(ToolVersionRequest::new("node".into(), "20")), + forge: "node".parse().unwrap(), + version: Some("20".into()), + version_type: ToolVersionType::Version("20".into()), + tvr: Some(ToolVersionRequest::new("node".parse().unwrap(), "20")), } ); } @@ -121,8 +166,10 @@ mod tests { assert_eq!( tool, ToolArg { - plugin: "node".into(), - tvr: Some(ToolVersionRequest::new("node".into(), "lts")), + forge: "node".parse().unwrap(), + version: Some("lts".into()), + version_type: ToolVersionType::Version("lts".into()), + tvr: Some(ToolVersionRequest::new("node".parse().unwrap(), "lts")), } ); } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 2d24e64cc..88aeb95bf 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -47,21 +47,18 @@ fn list_versions(config: &Config, args: &[String]) -> Result<()> { .run(); } let ts = ToolsetBuilder::new().build(config)?; - let mut versions = ts.list_installed_versions(config)?; + let mut versions = ts.list_installed_versions()?; let plugin = match args.len() { 3 => Some(&args[2]), _ => None, }; if let Some(plugin) = plugin { - versions.retain(|(_, v)| v.plugin_name.as_str() == plugin); + versions.retain(|(_, v)| &v.forge.to_string() == plugin); for (_, version) in versions { miseprintln!("{}", version.version); } } else { - for (plugin, versions) in &versions - .into_iter() - .group_by(|(_, v)| v.plugin_name.to_string()) - { + for (plugin, versions) in &versions.into_iter().group_by(|(_, v)| v.forge.clone()) { miseprintln!("{}", plugin); for (_, tv) in versions { miseprintln!(" {}", tv.version); diff --git a/src/cli/current.rs b/src/cli/current.rs index 995bb0d69..0c1b77520 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -1,9 +1,10 @@ use console::style; use eyre::Result; +use crate::cli::args::ForgeArg; use crate::config::Config; +use crate::forge; use crate::forge::Forge; -use crate::plugins::unalias_plugin; use crate::toolset::{Toolset, ToolsetBuilder}; /// Shows current active and installed runtime versions @@ -14,9 +15,9 @@ use crate::toolset::{Toolset, ToolsetBuilder}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Current { /// Plugin to show versions of - /// e.g.: ruby, node + /// e.g.: ruby, node, cargo:eza, npm:prettier, etc. #[clap()] - plugin: Option, + plugin: Option, } impl Current { @@ -24,11 +25,10 @@ impl Current { let config = Config::try_get()?; let ts = ToolsetBuilder::new().build(&config)?; match &self.plugin { - Some(plugin_name) => { - let plugin_name = unalias_plugin(plugin_name); - let plugin = config.get_or_create_plugin(plugin_name); + Some(fa) => { + let plugin = forge::get(fa); if !plugin.is_installed() { - bail!("Plugin {} is not installed", plugin_name); + bail!("Plugin {fa} is not installed"); } self.one(ts, plugin.as_ref()) } @@ -73,10 +73,10 @@ impl Current { } for tv in versions { if !plugin.is_version_installed(tv) { - let source = ts.versions.get(&tv.plugin_name).unwrap().source.clone(); + let source = ts.versions.get(&tv.forge).unwrap().source.clone(); warn!( "{}@{} is specified in {}, but not installed", - tv.plugin_name, &tv.version, &source + &tv.forge, &tv.version, &source ); } } diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 08f0cd888..431e17c02 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -13,7 +13,7 @@ use crate::git::Git; use crate::plugins::PluginType; use crate::shell::ShellType; use crate::toolset::ToolsetBuilder; -use crate::{cli, cmd, dirs}; +use crate::{cli, cmd, dirs, forge}; use crate::{duration, env}; /// Check mise installation for possible problems. @@ -46,8 +46,8 @@ impl Doctor { match Config::try_get() { Ok(config) => { miseprintln!("{}", render_config_files(&config)); - miseprintln!("{}", render_plugins(&config)); - for plugin in config.list_plugins() { + miseprintln!("{}", render_plugins()); + for plugin in forge::list() { if !plugin.is_installed() { checks.push(format!("plugin {} is not installed", &plugin.name())); continue; @@ -130,17 +130,16 @@ fn render_config_files(config: &Config) -> String { s } -fn render_plugins(config: &Config) -> String { +fn render_plugins() -> String { let mut s = style("plugins:\n").bold().to_string(); - let plugins = config - .list_plugins() + let plugins = forge::list() .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; for p in plugins { let padded_name = pad_str(p.name(), max_plugin_name_len, Alignment::Left, None); - let si = match p.get_type() { + let si = match p.get_plugin_type() { PluginType::External => { let git = Git::new(dirs::PLUGINS.join(p.name())); match git.get_remote_url() { diff --git a/src/cli/external.rs b/src/cli/external.rs index 411e01bcb..b9e2cc645 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -1,12 +1,12 @@ +use crate::cli::args::ForgeArg; use clap::{ArgMatches, Command}; use eyre::Result; use rayon::prelude::*; -use crate::config::Config; +use crate::forge; -pub fn commands(config: &Config) -> Vec { - config - .list_plugins() +pub fn commands() -> Vec { + forge::list() .into_par_iter() .flat_map(|p| { p.external_commands().unwrap_or_else(|e| { @@ -18,14 +18,13 @@ pub fn commands(config: &Config) -> Vec { .collect() } -pub fn execute(plugin: &str, args: &ArgMatches) -> Result<()> { - let config = Config::try_get()?; - if let Some(mut cmd) = commands(&config) +pub fn execute(fa: &ForgeArg, args: &ArgMatches) -> Result<()> { + if let Some(mut cmd) = commands() .into_iter() - .find(|c| c.get_name() == plugin) + .find(|c| c.get_name() == fa.to_string()) { if let Some((subcommand, matches)) = args.subcommand() { - let plugin = config.get_or_create_plugin(plugin); + let plugin = forge::get(fa); let args: Vec = matches .get_raw("args") .unwrap_or_default() diff --git a/src/cli/global.rs b/src/cli/global.rs index d8e81843c..dfb465ed8 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -1,8 +1,7 @@ use eyre::Result; -use crate::cli::args::ToolArg; +use crate::cli::args::{ForgeArg, ToolArg}; use crate::cli::local::local; -use crate::config::Config; use crate::env; /// Sets/gets the global tool version(s) @@ -36,7 +35,7 @@ pub struct Global { /// Remove the plugin(s) from ~/.tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] - remove: Option>, + remove: Option>, /// Get the path of the global config file #[clap(long)] @@ -45,9 +44,7 @@ pub struct Global { impl Global { pub fn run(self) -> Result<()> { - let config = Config::try_get()?; local( - &config, &env::MISE_GLOBAL_CONFIG_FILE, self.tool, self.remove, diff --git a/src/cli/install.rs b/src/cli/install.rs index 0299b5151..e65fc93be 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -2,6 +2,7 @@ use eyre::Result; use crate::cli::args::ToolArg; use crate::config::Config; +use crate::forge; use crate::toolset::{ InstallOptions, ToolVersion, ToolVersionOptions, ToolVersionRequest, Toolset, ToolsetBuilder, }; @@ -55,7 +56,7 @@ impl Install { fn install_runtimes(&self, config: &Config, runtimes: &[ToolArg]) -> Result<()> { let mpr = MultiProgressReport::get(); let mut ts = ToolsetBuilder::new().build(config)?; - let tool_versions = self.get_requested_tool_versions(config, &ts, runtimes, &mpr)?; + let tool_versions = self.get_requested_tool_versions(&ts, runtimes, &mpr)?; if tool_versions.is_empty() { warn!("no runtimes to install"); warn!("specify a version with `mise install @`"); @@ -75,34 +76,27 @@ impl Install { fn get_requested_tool_versions( &self, - config: &Config, ts: &Toolset, runtimes: &[ToolArg], mpr: &MultiProgressReport, ) -> Result> { let mut requests = vec![]; - for runtime in ToolArg::double_tool_condition(runtimes) { + for ta in ToolArg::double_tool_condition(runtimes)? { let default_opts = ToolVersionOptions::new(); - match runtime.tvr { - Some(tv) => requests.push((runtime.plugin, tv, default_opts.clone())), + match ta.tvr { + Some(tv) => requests.push((ta.forge, tv, default_opts.clone())), None => { - if runtime.tvr.is_none() { - match ts.versions.get(&runtime.plugin) { + if ta.tvr.is_none() { + match ts.versions.get(&ta.forge) { Some(tvl) => { for (tvr, opts) in &tvl.requests { - requests.push(( - runtime.plugin.clone(), - tvr.clone(), - opts.clone(), - )); + requests.push((ta.forge.clone(), tvr.clone(), opts.clone())); } } None => { - let tvr = ToolVersionRequest::Version( - runtime.plugin.clone(), - "latest".into(), - ); - requests.push((runtime.plugin, tvr, default_opts.clone())); + let tvr = + ToolVersionRequest::Version(ta.forge.clone(), "latest".into()); + requests.push((ta.forge, tvr, default_opts.clone())); } } } @@ -110,8 +104,8 @@ impl Install { } } let mut tool_versions = vec![]; - for (plugin_name, tvr, opts) in requests { - let plugin = config.get_or_create_plugin(&plugin_name); + for (fa, tvr, opts) in requests { + let plugin = forge::get(&fa); plugin.ensure_installed(mpr, false)?; let tv = tvr.resolve(plugin.as_ref(), opts, true)?; tool_versions.push(tv); diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 879b28430..f453618b5 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -2,6 +2,7 @@ use color_eyre::eyre::Result; use crate::cli::args::ToolArg; use crate::config::Config; +use crate::forge; use crate::toolset::ToolVersionRequest; use crate::ui::multi_progress_report::MultiProgressReport; @@ -33,11 +34,11 @@ impl Latest { _ => bail!("invalid version: {}", self.tool.style()), }; - let plugin = config.get_or_create_plugin(&self.tool.plugin); + let plugin = forge::get(&self.tool.forge); let mpr = MultiProgressReport::get(); plugin.ensure_installed(&mpr, false)?; if let Some(v) = prefix { - prefix = Some(config.resolve_alias(plugin.name(), &v)?); + prefix = Some(config.resolve_alias(plugin.as_ref(), &v)?); } let latest_version = if self.installed { diff --git a/src/cli/link.rs b/src/cli/link.rs index a11d2fc04..b2f7ae65a 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -45,7 +45,9 @@ impl Link { style(path.to_string_lossy()).cyan().for_stderr() ); } - let target = dirs::INSTALLS.join(&self.tool.plugin).join(version); + let target = dirs::INSTALLS + .join(self.tool.forge.pathname()) + .join(version); if target.exists() { if self.force { remove_all(&target)?; diff --git a/src/cli/local.rs b/src/cli/local.rs index 75b3a4363..cc24b7fcd 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -4,8 +4,8 @@ use color_eyre::eyre::{eyre, ContextCompat, Result}; use console::style; use itertools::Itertools; -use crate::cli::args::ToolArg; -use crate::config::{config_file, Config, Settings}; +use crate::cli::args::{ForgeArg, ToolArg}; +use crate::config::{config_file, Settings}; use crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME}; use crate::file::display_path; use crate::{env, file}; @@ -44,7 +44,7 @@ pub struct Local { /// Remove the plugin(s) from .tool-versions #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] - remove: Option>, + remove: Option>, /// Get the path of the config file #[clap(long)] @@ -53,14 +53,12 @@ pub struct Local { impl Local { pub fn run(self) -> Result<()> { - let config = Config::try_get()?; let path = if self.parent { get_parent_path()? } else { get_path()? }; local( - &config, &path, self.tool, self.remove, @@ -91,10 +89,9 @@ pub fn get_parent_path() -> Result { #[allow(clippy::too_many_arguments)] pub fn local( - config: &Config, path: &Path, runtime: Vec, - remove: Option>, + remove: Option>, pin: bool, fuzzy: bool, show_path: bool, @@ -118,12 +115,12 @@ pub fn local( } if !runtime.is_empty() { - let runtimes = ToolArg::double_tool_condition(&runtime); + let runtimes = ToolArg::double_tool_condition(&runtime)?; if cf.display_runtime(&runtimes)? { return Ok(()); } let pin = pin || (settings.asdf_compat && !fuzzy); - cf.add_runtimes(config, &runtimes, pin)?; + cf.add_runtimes(&runtimes, pin)?; let tools = runtimes.iter().map(|t| t.style()).join(" "); miseprintln!("{} {} {tools}", style("mise").dim(), display_path(path)); } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 2c5253aa8..40ded9f13 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -11,10 +11,10 @@ use serde_derive::Serialize; use tabled::{Table, Tabled}; use versions::Versioning; +use crate::cli::args::ForgeArg; use crate::config::Config; -use crate::errors::Error::PluginNotInstalled; +use crate::forge; use crate::forge::Forge; -use crate::plugins::unalias_plugin; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; use crate::ui::table; @@ -24,10 +24,10 @@ use crate::ui::table; pub struct Ls { /// Only show tool versions from [PLUGIN] #[clap(conflicts_with = "plugin_flag")] - plugin: Option>, + plugin: Option>, #[clap(long = "plugin", short, hide = true)] - plugin_flag: Option, + plugin_flag: Option, /// Only show tool versions currently specified in a .tool-versions/.mise.toml #[clap(long, short)] @@ -68,9 +68,8 @@ impl Ls { let config = Config::try_get()?; self.plugin = self .plugin - .or_else(|| self.plugin_flag.clone().map(|p| vec![p])) - .map(|p| p.into_iter().map(|p| unalias_plugin(&p).into()).collect()); - self.verify_plugin(&config)?; + .or_else(|| self.plugin_flag.clone().map(|p| vec![p])); + self.verify_plugin()?; let mut runtimes = self.get_runtime_list(&config)?; if self.current || self.global { @@ -96,14 +95,12 @@ impl Ls { } } - fn verify_plugin(&self, config: &Config) -> Result<()> { + fn verify_plugin(&self) -> Result<()> { match &self.plugin { Some(plugins) => { - for plugin_name in plugins { - let plugin = config.get_or_create_plugin(plugin_name); - if !plugin.is_installed() { - return Err(PluginNotInstalled(plugin_name.clone()))?; - } + for fa in plugins { + let plugin = forge::get(fa); + ensure!(plugin.is_installed(), "{fa} is not installed"); } } None => {} @@ -116,7 +113,7 @@ impl Ls { // only runtimes for 1 plugin let runtimes: Vec = runtimes .into_iter() - .filter(|(p, _, _)| plugins.contains(&p.name().to_string())) + .filter(|(p, _, _)| plugins.contains(&p.get_fa())) .map(|row| row.into()) .collect(); miseprintln!("{}", serde_json::to_string_pretty(&runtimes)?); @@ -147,7 +144,7 @@ impl Ls { // only displaying 1 plugin so only show the version miseprintln!("{}", tv.version); } else { - miseprintln!("{} {}", tv.plugin_name, tv.version); + miseprintln!("{} {}", &tv.forge, tv.version); } }); Ok(()) @@ -174,15 +171,11 @@ impl Ls { } fn get_runtime_list(&self, config: &Config) -> Result> { - let mut tsb = ToolsetBuilder::new().with_global_only(self.global); + let tsb = ToolsetBuilder::new().with_global_only(self.global); - if let Some(plugins) = &self.plugin { - let plugins = plugins.iter().map(|p| p.as_str()).collect_vec(); - tsb = tsb.with_tools(&plugins); - } let ts = tsb.build(config)?; let mut versions: HashMap<(String, String), (Arc, ToolVersion)> = ts - .list_installed_versions(config)? + .list_installed_versions()? .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) .collect(); @@ -197,8 +190,8 @@ impl Ls { let rvs: Vec = versions .into_iter() - .filter(|((plugin_name, _), _)| match &self.plugin { - Some(p) => p.contains(plugin_name), + .filter(|(_, (f, _))| match &self.plugin { + Some(p) => p.contains(&f.get_fa()), None => true, }) .sorted_by_cached_key(|((plugin_name, version), _)| { @@ -210,13 +203,17 @@ impl Ls { }) .map(|(k, (p, tv))| { let source = match &active.get(&k) { - Some((_, tv)) => ts.versions.get(&tv.plugin_name).map(|tv| tv.source.clone()), + Some((_, tv)) => ts.versions.get(&tv.forge).map(|tv| tv.source.clone()), None => None, }; (p, tv, source) }) // if it isn't installed and it's not specified, don't show it .filter(|(p, tv, source)| source.is_some() || p.is_version_installed(tv)) + .filter(|(p, _, _)| match &self.plugin { + Some(forge) => forge.contains(&p.get_fa()), + None => true, + }) .collect(); Ok(rvs) @@ -454,7 +451,7 @@ mod tests { #[test] fn test_ls_missing_plugin() { let err = assert_cli_err!("ls", "missing-plugin"); - assert_str_eq!(err.to_string(), r#"[missing-plugin] plugin not installed"#); + assert_str_eq!(err.to_string(), r#"missing-plugin is not installed"#); } #[test] diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 23a101a78..6023d43dc 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use rayon::prelude::*; use crate::cli::args::ToolArg; -use crate::config::Config; +use crate::forge; use crate::forge::Forge; use crate::toolset::ToolVersionRequest; use crate::ui::multi_progress_report::MultiProgressReport; @@ -19,25 +19,24 @@ use crate::ui::multi_progress_report::MultiProgressReport; pub struct LsRemote { /// Plugin to get versions for #[clap(value_name = "TOOL@VERSION", required_unless_present = "all")] - pub(crate) plugin: Option, + pub plugin: Option, /// Show all installed plugins and versions #[clap(long, verbatim_doc_comment, conflicts_with_all = ["plugin", "prefix"])] - pub(crate) all: bool, + pub all: bool, /// The version prefix to use when querying the latest version /// same as the first argument after the "@" #[clap(verbatim_doc_comment)] - pub(crate) prefix: Option, + pub prefix: Option, } impl LsRemote { pub fn run(self) -> Result<()> { - let config = Config::try_get()?; - if let Some(plugin) = self.get_plugin(&config)? { + if let Some(plugin) = self.get_plugin()? { self.run_single(plugin) } else { - self.run_all(&config) + self.run_all() } } @@ -66,9 +65,8 @@ impl LsRemote { Ok(()) } - fn run_all(self, config: &Config) -> Result<()> { - let versions = config - .list_plugins() + fn run_all(self) -> Result<()> { + let versions = forge::list() .into_par_iter() .map(|p| { let versions = p.list_remote_versions()?; @@ -86,10 +84,10 @@ impl LsRemote { Ok(()) } - fn get_plugin(&self, config: &Config) -> Result>> { + fn get_plugin(&self) -> Result>> { match &self.plugin { Some(tool_arg) => { - let plugin = config.get_or_create_plugin(&tool_arg.plugin); + let plugin = forge::get(&tool_arg.forge); let mpr = MultiProgressReport::get(); plugin.ensure_installed(&mpr, false)?; Ok(Some(plugin)) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index af883f74e..85c7170ab 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,7 +1,7 @@ use clap::{FromArgMatches, Subcommand}; use color_eyre::Result; -use crate::config::{Config, Settings}; +use crate::config::Settings; use crate::{logger, migrate, shims}; mod activate; @@ -203,7 +203,7 @@ impl Cli { .try_get_matches_from(args) .unwrap_or_else(|_| { Self::command() - .subcommands(external::commands(Config::get().as_ref())) + .subcommands(external::commands()) .get_matches_from(args) }); Settings::add_cli_matches(&matches); @@ -217,7 +217,7 @@ impl Cli { Err(err) => matches .subcommand() .ok_or(err) - .map(|(command, sub_m)| external::execute(command, sub_m))?, + .map(|(command, sub_m)| external::execute(&command.parse()?, sub_m))?, } } } diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index f56273dcf..03c8ad9fc 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -27,10 +27,10 @@ impl Outdated { let tool_set = self .tool .iter() - .map(|t| t.plugin.clone()) + .map(|t| t.forge.clone()) .collect::>(); ts.versions - .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.plugin_name)); + .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.forge)); let outdated = ts.list_outdated_versions(); if outdated.is_empty() { info!("All tools are up to date"); diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 53143b4e2..61abc5043 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -4,9 +4,9 @@ use rayon::ThreadPoolBuilder; use url::Url; use crate::config::{Config, Settings}; -use crate::forge::Forge; +use crate::forge::{unalias_forge, Forge}; use crate::plugins::core::CORE_PLUGINS; -use crate::plugins::{unalias_plugin, ExternalPlugin}; +use crate::plugins::ExternalPlugin; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::style; @@ -59,7 +59,7 @@ impl PluginsInstall { if git_url.is_some() { self.install_one(name, git_url, &mpr)?; } else { - let is_core = CORE_PLUGINS.contains_key(name.as_str()); + let is_core = CORE_PLUGINS.iter().any(|p| p.name() == name); if is_core { let name = style::eblue(name); bail!("{name} is a core plugin and does not need to be installed"); @@ -81,7 +81,7 @@ impl PluginsInstall { mpr: &MultiProgressReport, ) -> Result<()> { let ts = ToolsetBuilder::new().build(config)?; - let missing_plugins = ts.list_missing_plugins(config); + let missing_plugins = ts.list_missing_plugins(); if missing_plugins.is_empty() { warn!("all plugins already installed"); } @@ -121,7 +121,7 @@ impl PluginsInstall { } fn get_name_and_url(name: &str, git_url: &Option) -> Result<(String, Option)> { - let name = unalias_plugin(name); + let name = unalias_forge(name); Ok(match git_url { Some(url) => match url.contains(':') { true => (name.to_string(), Some(url.clone())), @@ -142,7 +142,7 @@ fn get_name_from_url(url: &str) -> Result { let name = name.strip_prefix("rtx-").unwrap_or(name); let name = name.strip_prefix("mise-").unwrap_or(name); let name = name.strip_suffix(".git").unwrap_or(name); - return Ok(unalias_plugin(name).to_string()); + return Ok(unalias_forge(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 8fbdfbddd..1defdfceb 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -6,7 +6,7 @@ use console::style; use path_absolutize::Absolutize; use crate::file::{make_symlink, remove_all}; -use crate::plugins::unalias_plugin; +use crate::forge::unalias_forge; use crate::{dirs, file}; /// Symlinks a plugin into mise @@ -40,7 +40,7 @@ impl PluginsLink { (name, path) } }; - let name = unalias_plugin(&name); + let name = unalias_forge(&name); let path = path.absolutize()?; let symlink = dirs::PLUGINS.join(name); if symlink.exists() { @@ -64,7 +64,7 @@ fn get_name_from_path(path: &Path) -> String { let name = name.strip_prefix("asdf-").unwrap_or(name); let name = name.strip_prefix("rtx-").unwrap_or(name); let name = name.strip_prefix("mise-").unwrap_or(name); - unalias_plugin(name).to_string() + unalias_forge(name).to_string() } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 45179720d..5630704c4 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -8,6 +8,7 @@ use tabled::settings::{Margin, Modify, Padding, Style}; use tabled::Tabled; use crate::config::Config; +use crate::plugins; use crate::plugins::{ExternalPlugin, PluginType}; /// List installed plugins @@ -46,7 +47,7 @@ pub struct PluginsLs { impl PluginsLs { pub fn run(self, config: &Config) -> Result<()> { - let mut tools = config.list_plugins().into_iter().collect::>(); + let mut tools = plugins::list().into_iter().collect::>(); if self.all { for (plugin, url) in config.get_shorthands() { @@ -56,9 +57,9 @@ impl PluginsLs { } } else if self.user && self.core { } else if self.core { - tools.retain(|p| matches!(p.get_type(), PluginType::Core)); + tools.retain(|p| matches!(p.get_plugin_type(), PluginType::Core)); } else { - tools.retain(|p| matches!(p.get_type(), PluginType::External)); + tools.retain(|p| matches!(p.get_plugin_type(), PluginType::External)); } if self.urls || self.refs { diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index fdd89f741..8ffe63a90 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -5,6 +5,7 @@ use eyre::Result; use itertools::Itertools; use crate::config::Config; +use crate::plugins; /// List all available remote plugins #[derive(Debug, clap::Args)] @@ -23,8 +24,7 @@ pub struct PluginsLsRemote { impl PluginsLsRemote { pub fn run(self, config: &Config) -> Result<()> { - let installed_plugins = config - .list_plugins() + let installed_plugins = plugins::list() .into_iter() .filter(|p| p.is_installed()) .map(|p| p.name().to_string()) diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index dd033f634..22f83d99a 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -62,8 +62,8 @@ impl Commands { Self::Link(cmd) => cmd.run(), Self::Ls(cmd) => cmd.run(config), Self::LsRemote(cmd) => cmd.run(config), - Self::Uninstall(cmd) => cmd.run(config), - Self::Update(cmd) => cmd.run(config), + Self::Uninstall(cmd) => cmd.run(), + Self::Update(cmd) => cmd.run(), } } } diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index b4577c554..547c0f066 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -1,7 +1,7 @@ use eyre::Result; -use crate::config::Config; -use crate::plugins::unalias_plugin; +use crate::forge::unalias_forge; +use crate::plugins; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::style; @@ -23,12 +23,11 @@ pub struct PluginsUninstall { } impl PluginsUninstall { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { let mpr = MultiProgressReport::get(); let plugins = match self.all { - true => config - .list_plugins() + true => plugins::list() .into_iter() .map(|p| p.name().to_string()) .collect(), @@ -36,19 +35,14 @@ impl PluginsUninstall { }; for plugin_name in plugins { - let plugin_name = unalias_plugin(&plugin_name); - self.uninstall_one(config, plugin_name, &mpr)?; + let plugin_name = unalias_forge(&plugin_name); + self.uninstall_one(plugin_name, &mpr)?; } Ok(()) } - fn uninstall_one( - &self, - config: &Config, - plugin_name: &str, - mpr: &MultiProgressReport, - ) -> Result<()> { - match config.get_or_create_plugin(plugin_name) { + fn uninstall_one(&self, plugin_name: &str, mpr: &MultiProgressReport) -> Result<()> { + match plugins::get(plugin_name) { plugin if plugin.is_installed() => { let prefix = format!("plugin:{}", style::eblue(&plugin.name())); let pr = mpr.add(&prefix); diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 3a97ac1bf..8ea7db36c 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -2,8 +2,8 @@ use console::style; use eyre::Result; use rayon::prelude::*; -use crate::config::{Config, Settings}; -use crate::plugins::unalias_plugin; +use crate::config::Settings; +use crate::plugins; use crate::ui::multi_progress_report::MultiProgressReport; /// Updates a plugin to the latest version @@ -23,7 +23,7 @@ pub struct Update { } impl Update { - pub fn run(self, config: &Config) -> Result<()> { + pub fn run(self) -> Result<()> { let plugins: Vec<_> = match self.plugin { Some(plugins) => plugins .into_iter() @@ -32,15 +32,13 @@ impl Update { Some((p, ref_)) => (p, Some(ref_.to_string())), None => (p.as_str(), None), }; - let p = unalias_plugin(p); - let plugin = config.get_or_create_plugin(p); + let plugin = plugins::get(p); Ok((plugin.clone(), ref_)) }) .collect::>()?, - None => config - .external_plugins() + None => plugins::list_external() .into_iter() - .map(|(_, p)| (p, None)) + .map(|p| (p, None)) .collect::>(), }; diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 963209196..ac57a17ef 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::sync::Arc; +use crate::cli::args::ForgeArg; use console::style; use eyre::Result; @@ -19,9 +20,9 @@ use crate::ui::prompt; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Prune { - /// Prune only versions from these plugins + /// Prune only versions from this plugin(s) #[clap()] - pub plugin: Option>, + pub plugin: Option>, /// Do not actually delete anything #[clap(long, short = 'n')] @@ -33,18 +34,18 @@ impl Prune { let config = Config::try_get()?; let ts = ToolsetBuilder::new().build(&config)?; let mut to_delete = ts - .list_installed_versions(&config)? + .list_installed_versions()? .into_iter() .map(|(p, tv)| (tv.to_string(), (p, tv))) .collect::, ToolVersion)>>(); - if let Some(plugins) = &self.plugin { - to_delete.retain(|_, (_, tv)| plugins.contains(&tv.plugin_name)); + if let Some(forges) = &self.plugin { + to_delete.retain(|_, (_, tv)| forges.contains(&tv.forge)); } for cf in config.get_tracked_config_files()?.values() { let mut ts = cf.to_toolset().clone(); - ts.resolve(&config); + ts.resolve(); for (_, tv) in ts.list_current_versions() { to_delete.remove(&tv.to_string()); } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index 3a12d734e..4151ee039 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -33,7 +33,7 @@ impl Reshim { let config = Config::try_get()?; let ts = ToolsetBuilder::new().build(&config)?; - shims::reshim(&config, &ts) + shims::reshim(&ts) } } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index f701056b4..0a5451541 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -51,7 +51,7 @@ impl Shell { let shell = get_shell(None).expect("no shell detected"); for (p, tv) in ts.list_current_installed_versions() { - let source = &ts.versions.get(p.name()).unwrap().source; + let source = &ts.versions.get(&p.get_fa()).unwrap().source; if matches!(source, ToolSource::Argument) { let k = format!("MISE_{}_VERSION", p.name().to_uppercase()); let op = if self.unset { diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index aa88f5c25..51c37ad44 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -5,8 +5,8 @@ use itertools::sorted; use crate::config::Config; use crate::env::{NODENV_ROOT, NVM_DIR}; -use crate::file; use crate::{cmd, dirs}; +use crate::{file, plugins}; /// Symlinks all tool versions from an external tool into mise /// @@ -48,7 +48,7 @@ impl SyncNode { } fn run_brew(self, config: &Config) -> Result<()> { - let tool = config.get_or_create_plugin(&String::from("node")); + let tool = plugins::get("node"); let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); let installed_versions_path = dirs::INSTALLS.join("node"); @@ -69,7 +69,7 @@ impl SyncNode { } fn run_nvm(self, config: &Config) -> Result<()> { - let tool = config.get_or_create_plugin(&String::from("node")); + let tool = plugins::get("node"); let nvm_versions_path = NVM_DIR.join("versions").join("node"); let installed_versions_path = dirs::INSTALLS.join("node"); @@ -87,7 +87,7 @@ impl SyncNode { } fn run_nodenv(self, config: &Config) -> Result<()> { - let tool = config.get_or_create_plugin(&String::from("node")); + let tool = plugins::get("node"); let nodenv_versions_path = NODENV_ROOT.join("versions"); let installed_versions_path = dirs::INSTALLS.join("node"); diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 743f845f0..29c9823ef 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -2,9 +2,9 @@ use eyre::Result; use itertools::sorted; use crate::config::Config; -use crate::dirs; use crate::env::PYENV_ROOT; use crate::file; +use crate::{dirs, plugins}; /// Symlinks all tool versions from an external tool into mise /// @@ -20,7 +20,7 @@ pub struct SyncPython { impl SyncPython { pub fn run(self) -> Result<()> { let config = Config::try_get()?; - let python = config.get_or_create_plugin(&String::from("python")); + let python = plugins::get("python"); let pyenv_versions_path = PYENV_ROOT.join("versions"); let installed_python_versions_path = dirs::INSTALLS.join("python"); diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index b6b8eae01..8de314300 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -10,7 +10,7 @@ use crate::config::Config; use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::{runtime_symlinks, shims}; +use crate::{forge, runtime_symlinks, shims}; /// Removes runtime versions #[derive(Debug, clap::Args)] @@ -35,7 +35,7 @@ impl Uninstall { let tool_versions = if self.installed_tool.is_empty() && self.all { self.get_all_tool_versions(&config)? } else { - self.get_requested_tool_versions(&config)? + self.get_requested_tool_versions()? }; let tool_versions = tool_versions .into_iter() @@ -66,7 +66,7 @@ impl Uninstall { } let ts = ToolsetBuilder::new().build(&config)?; - shims::reshim(&config, &ts).wrap_err("failed to reshim")?; + shims::reshim(&ts).wrap_err("failed to reshim")?; runtime_symlinks::rebuild(&config)?; Ok(()) @@ -75,20 +75,17 @@ impl Uninstall { fn get_all_tool_versions(&self, config: &Config) -> Result, ToolVersion)>> { let ts = ToolsetBuilder::new().build(config)?; let tool_versions = ts - .list_installed_versions(config)? + .list_installed_versions()? .into_iter() .collect::>(); Ok(tool_versions) } - fn get_requested_tool_versions( - &self, - config: &Config, - ) -> Result, ToolVersion)>> { - let runtimes = ToolArg::double_tool_condition(&self.installed_tool); + fn get_requested_tool_versions(&self) -> Result, ToolVersion)>> { + let runtimes = ToolArg::double_tool_condition(&self.installed_tool)?; let tool_versions = runtimes .into_par_iter() .map(|a| { - let tool = config.get_or_create_plugin(&a.plugin); + let tool = forge::get(&a.forge); let query = a.tvr.as_ref().map(|tvr| tvr.version()).unwrap_or_default(); let installed_versions = tool.list_installed_versions()?; let exact_match = installed_versions.iter().find(|v| v == &&query); @@ -102,7 +99,7 @@ impl Uninstall { let mut tvs = matches .into_iter() .map(|v| { - let tvr = ToolVersionRequest::new(tool.name().into(), v); + let tvr = ToolVersionRequest::new(tool.get_fa(), v); let tv = ToolVersion::new(tool.as_ref(), tvr, Default::default(), v.into()); (tool.clone(), tv) }) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 35207b124..acc35231d 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -54,9 +54,9 @@ impl Upgrade { let tool_set = self .tool .iter() - .map(|t| t.plugin.clone()) + .map(|t| t.forge.clone()) .collect::>(); - outdated.retain(|(p, _, _)| tool_set.is_empty() || tool_set.contains(p.name())); + outdated.retain(|(p, _, _)| tool_set.is_empty() || tool_set.contains(&p.get_fa())); } if outdated.is_empty() { info!("All tools are up to date"); @@ -108,7 +108,7 @@ impl Upgrade { } let ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; - shims::reshim(config, &ts).wrap_err("failed to reshim")?; + shims::reshim(&ts).wrap_err("failed to reshim")?; runtime_symlinks::rebuild(config)?; Ok(()) } diff --git a/src/cli/use.rs b/src/cli/use.rs index 979c11d29..7ee318ec1 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -4,7 +4,7 @@ use console::style; use eyre::Result; use itertools::Itertools; -use crate::cli::args::ToolArg; +use crate::cli::args::{ForgeArg, ToolArg}; use crate::config::config_file::ConfigFile; use crate::config::{config_file, Config, Settings}; use crate::env::{ @@ -13,7 +13,7 @@ use crate::env::{ use crate::file::display_path; use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest, ToolsetBuilder}; use crate::ui::multi_progress_report::MultiProgressReport; -use crate::{env, file}; +use crate::{env, file, forge}; /// Change the active version of a tool locally or globally. /// @@ -62,9 +62,9 @@ pub struct Use { #[clap(long, overrides_with = "jobs")] raw: bool, - /// Remove the tool(s) from config file - #[clap(long, value_name = "TOOL", aliases = ["rm", "unset"])] - remove: Vec, + /// Remove the plugin(s) from config file + #[clap(long, value_name = "PLUGIN", aliases = ["rm", "unset"])] + remove: Vec, /// Specify a path to a config file or directory /// If a directory is specified, it will look for .mise.toml (default) or .tool-versions @@ -89,9 +89,9 @@ impl Use { .map(|t| { let tvr = match &t.tvr { Some(ref tvr) => tvr.clone(), - None => ToolVersionRequest::new(t.plugin.to_string(), "latest"), + None => ToolVersionRequest::new(t.forge.clone(), "latest"), }; - let plugin = config.get_or_create_plugin(&t.plugin); + let plugin = forge::get(&t.forge); ToolVersion::resolve(plugin.as_ref(), tvr, Default::default(), false) }) .collect::>>()?; @@ -111,7 +111,7 @@ impl Use { let settings = Settings::try_get()?; let pin = self.pin || (settings.asdf_compat && !self.fuzzy); - for (plugin_name, tvl) in &versions.iter().group_by(|tv| tv.plugin_name.clone()) { + for (fa, tvl) in &versions.iter().group_by(|tv| &tv.forge) { let versions: Vec = tvl .into_iter() .map(|tv| { @@ -122,7 +122,7 @@ impl Use { } }) .collect(); - cf.replace_versions(&plugin_name, &versions); + cf.replace_versions(fa, &versions); } if self.global { @@ -152,13 +152,13 @@ impl Use { fn warn_if_hidden(&self, config: &Config, global: &Path) { let ts = ToolsetBuilder::new().build(config).unwrap_or_default(); let warn = |targ: &ToolArg, p| { - let plugin = &targ.plugin; + let plugin = &targ.forge; let p = display_path(p); let global = display_path(global); warn!("{plugin} is defined in {p} which overrides the global config ({global})"); }; for targ in &self.tool { - if let Some(tv) = ts.versions.get(&targ.plugin) { + if let Some(tv) = ts.versions.get(&targ.forge) { if let ToolSource::MiseToml(p) | ToolSource::ToolVersions(p) = &tv.source { if p != global { warn(targ, p); diff --git a/src/cli/watch.rs b/src/cli/watch.rs index 80e24e67e..701dbcb14 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -1,5 +1,6 @@ use std::process::exit; +use crate::cli::args::ForgeArg; use console::style; use eyre::Result; @@ -71,7 +72,8 @@ impl Watch { let ts = ToolsetBuilder::new().build(&config)?; settings.ensure_experimental()?; if let Err(err) = which::which("watchexec") { - if !ts.versions.contains_key("watchexec") { + let watchexec: ForgeArg = "watchexec".parse()?; + if !ts.versions.contains_key(&watchexec) { eprintln!("{}: {}", style("Error").red().bold(), err); eprintln!("{}: Install watchexec with:", style("Hint").bold()); eprintln!(" mise use -g watchexec@latest"); diff --git a/src/cli/where.rs b/src/cli/where.rs index 000e0789a..124ef0e69 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -3,6 +3,7 @@ use eyre::Result; use crate::cli::args::ToolArg; use crate::config::Config; use crate::errors::Error::VersionNotInstalled; +use crate::forge; use crate::toolset::ToolsetBuilder; /// Display the installation path for a runtime @@ -38,7 +39,7 @@ impl Where { .build(&config)?; let v = ts .versions - .get(&self.tool.plugin) + .get(&self.tool.forge) .and_then(|v| v.requests.first()) .map(|(r, _)| r.version()); self.tool.with_version(&v.unwrap_or(String::from("latest"))) @@ -47,7 +48,7 @@ impl Where { _ => self.tool, }; - let plugin = config.get_or_create_plugin(&runtime.plugin); + let plugin = forge::get(&runtime.forge); match runtime .tvr @@ -59,7 +60,7 @@ impl Where { Ok(()) } _ => Err(VersionNotInstalled( - runtime.plugin.to_string(), + runtime.forge.to_string(), runtime.tvr.map(|tvr| tvr.version()).unwrap_or_default(), ))?, } diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 2088850d3..c54d69d5d 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -1,11 +1,11 @@ use std::default::Default; use std::path::{Path, PathBuf}; -use std::sync::Arc; use eyre::Result; +use crate::cli::args::ForgeArg; use crate::config::config_file::{ConfigFile, ConfigFileType}; -use crate::forge::Forge; +use crate::forge::ForgeList; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; #[derive(Debug)] @@ -15,14 +15,14 @@ pub struct LegacyVersionFile { } impl LegacyVersionFile { - pub fn parse(path: PathBuf, plugins: &[&Arc]) -> Result { + pub fn parse(path: PathBuf, plugins: ForgeList) -> Result { let mut toolset = Toolset::new(ToolSource::LegacyVersionFile(path.clone())); for plugin in plugins { let version = plugin.parse_legacy_file(&path)?; for version in version.split_whitespace() { toolset.add_version( - ToolVersionRequest::new(plugin.name().to_string(), version), + ToolVersionRequest::new(plugin.get_fa(), version), Default::default(), ); } @@ -41,11 +41,11 @@ impl ConfigFile for LegacyVersionFile { self.path.as_path() } - fn remove_plugin(&mut self, _plugin_name: &str) { + fn remove_plugin(&mut self, _fa: &ForgeArg) { unimplemented!() } - fn replace_versions(&mut self, _plugin_name: &str, _versions: &[String]) { + fn replace_versions(&mut self, _plugin_name: &ForgeArg, _versions: &[String]) { unimplemented!() } diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 3e75926af..801e6c85f 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -10,10 +10,10 @@ use tera::Context as TeraContext; use toml_edit::{table, value, Array, Document, Item, Value}; use versions::Versioning; +use crate::cli::args::ForgeArg; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; use crate::config::AliasMap; use crate::file::{create_dir_all, display_path}; -use crate::plugins::unalias_plugin; use crate::task::Task; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ @@ -234,7 +234,8 @@ impl MiseToml { let mut aliases = AliasMap::new(); for (plugin, table) in table.iter() { let k = format!("{}.{}", k, plugin); - let plugin_aliases = aliases.entry(plugin.into()).or_default(); + let fa: ForgeArg = plugin.parse()?; + let plugin_aliases = aliases.entry(fa).or_default(); match table.as_table_like() { Some(table) => { for (from, to) in table.iter() { @@ -340,9 +341,9 @@ impl MiseToml { Some(table) => { for (plugin, v) in table.iter() { let k = format!("{}.{}", key, plugin); - 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); + let fa: ForgeArg = plugin.parse()?; + let tvl = self.parse_tool_version_list(&k, v, fa.clone())?; + toolset.versions.insert(fa, tvl); } Ok(toolset) } @@ -354,17 +355,17 @@ impl MiseToml { &self, key: &str, v: &Item, - plugin_name: &String, + fa: ForgeArg, ) -> Result { let source = ToolSource::MiseToml(self.path.clone()); - let mut tool_version_list = ToolVersionList::new(plugin_name.to_string(), source); + let mut tool_version_list = ToolVersionList::new(fa.clone(), source); match v { Item::ArrayOfTables(v) => { for table in v.iter() { for (tool, v) in table.iter() { let k = format!("{}.{}", key, tool); - let (tvr, opts) = self.parse_tool_version(&k, v, plugin_name)?; + let (tvr, opts) = self.parse_tool_version(&k, v, fa.clone())?; tool_version_list.requests.push((tvr, opts)); } } @@ -373,16 +374,14 @@ impl MiseToml { Some(v) => { for v in v.iter() { let item = Item::Value(v.clone()); - let (tvr, opts) = self.parse_tool_version(key, &item, plugin_name)?; + let (tvr, opts) = self.parse_tool_version(key, &item, fa.clone())?; tool_version_list.requests.push((tvr, opts)); } } _ => { - tool_version_list.requests.push(self.parse_tool_version( - key, - v, - plugin_name, - )?); + tool_version_list + .requests + .push(self.parse_tool_version(key, v, fa)?); } }, } @@ -401,20 +400,20 @@ impl MiseToml { &self, key: &str, v: &Item, - plugin_name: &str, + fa: ForgeArg, ) -> Result<(ToolVersionRequest, ToolVersionOptions)> { match v.as_table_like() { Some(table) => { let tv = if let Some(v) = table.get("version") { match v { - Item::Value(v) => self.parse_tool_version_request(key, v, plugin_name)?, + Item::Value(v) => self.parse_tool_version_request(key, v, fa)?, _ => parse_error!(format!("{}.version", key), v, "string"), } } else if let Some(path) = table.get("path") { match path.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - ToolVersionRequest::Path(plugin_name.to_string(), s.into()) + ToolVersionRequest::Path(fa, s.into()) } _ => parse_error!(format!("{}.path", key), v, "string"), } @@ -422,7 +421,7 @@ impl MiseToml { match prefix.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - ToolVersionRequest::Prefix(plugin_name.to_string(), s) + ToolVersionRequest::Prefix(fa, s) } _ => parse_error!(format!("{}.prefix", key), v, "string"), } @@ -430,7 +429,7 @@ impl MiseToml { match r.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - ToolVersionRequest::Ref(plugin_name.to_string(), s) + ToolVersionRequest::Ref(fa, s) } _ => parse_error!(format!("{}.ref", key), v, "string"), } @@ -455,7 +454,7 @@ impl MiseToml { } _ => match v { Item::Value(v) => { - let tv = self.parse_tool_version_request(key, v, plugin_name)?; + let tv = self.parse_tool_version_request(key, v, fa)?; Ok((tv, Default::default())) } _ => parse_error!(key, v, "value"), @@ -467,20 +466,20 @@ impl MiseToml { &self, key: &str, v: &Value, - plugin_name: &str, + fa: ForgeArg, ) -> Result { match v.as_str() { Some(s) => { let s = self.parse_template(key, s)?; - Ok(ToolVersionRequest::new(plugin_name.to_string(), &s)) + Ok(ToolVersionRequest::new(fa, &s)) } _ => parse_error!(key, v, "string"), } } - pub fn set_alias(&mut self, plugin: &str, from: &str, to: &str) { + pub fn set_alias(&mut self, fa: &ForgeArg, from: &str, to: &str) { self.alias - .entry(plugin.into()) + .entry(fa.clone()) .or_default() .insert(from.into(), to.into()); self.doc @@ -488,21 +487,24 @@ impl MiseToml { .or_insert_with(table) .as_table_like_mut() .unwrap() - .entry(plugin) + .entry(&fa.to_string()) .or_insert_with(table) .as_table_like_mut() .unwrap() .insert(from, value(to)); } - pub fn remove_alias(&mut self, plugin: &str, from: &str) { + pub fn remove_alias(&mut self, fa: &ForgeArg, from: &str) { if let Some(aliases) = self.doc.get_mut("alias").and_then(|v| v.as_table_mut()) { - if let Some(plugin_aliases) = aliases.get_mut(plugin).and_then(|v| v.as_table_mut()) { - self.alias.get_mut(plugin).unwrap().remove(from); + if let Some(plugin_aliases) = aliases + .get_mut(&fa.to_string()) + .and_then(|v| v.as_table_mut()) + { + self.alias.get_mut(fa).unwrap().remove(from); plugin_aliases.remove(from); if plugin_aliases.is_empty() { - aliases.remove(plugin); - self.alias.remove(plugin); + aliases.remove(&fa.to_string()); + self.alias.remove(fa); } } if aliases.is_empty() { @@ -635,11 +637,11 @@ impl ConfigFile for MiseToml { self.tasks.iter().collect() } - fn remove_plugin(&mut self, plugin: &str) { - self.toolset.versions.remove(plugin); + fn remove_plugin(&mut self, fa: &ForgeArg) { + self.toolset.versions.remove(fa); if let Some(tools) = self.doc.get_mut("tools") { if let Some(tools) = tools.as_table_like_mut() { - tools.remove(plugin); + tools.remove(&fa.to_string()); if tools.is_empty() { self.doc.as_table_mut().remove("tools"); } @@ -647,16 +649,11 @@ impl ConfigFile for MiseToml { } } - fn replace_versions(&mut self, plugin_name: &str, versions: &[String]) { - if let Some(plugin) = self.toolset.versions.get_mut(plugin_name) { + fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) { + if let Some(plugin) = self.toolset.versions.get_mut(fa) { plugin.requests = versions .iter() - .map(|s| { - ( - ToolVersionRequest::new(plugin_name.to_string(), s), - Default::default(), - ) - }) + .map(|s| (ToolVersionRequest::new(fa.clone(), s), Default::default())) .collect(); } let tools = self @@ -667,13 +664,13 @@ impl ConfigFile for MiseToml { .unwrap(); if versions.len() == 1 { - tools.insert(plugin_name, value(versions[0].clone())); + tools.insert(&fa.to_string(), value(versions[0].clone())); } else { let mut arr = Array::new(); for v in versions { arr.push(v); } - tools.insert(plugin_name, Item::Value(Value::Array(arr))); + tools.insert(&fa.to_string(), Item::Value(Value::Array(arr))); } } @@ -829,9 +826,11 @@ mod tests { "#}) .unwrap(); - cf.set_alias("node", "18", "18.0.1"); - cf.set_alias("node", "20", "20.0.0"); - cf.set_alias("python", "3.10", "3.10.0"); + let node = "node".parse().unwrap(); + let python = "python".parse().unwrap(); + cf.set_alias(&node, "18", "18.0.1"); + cf.set_alias(&node, "20", "20.0.0"); + cf.set_alias(&python, "3.10", "3.10.0"); assert_debug_snapshot!(cf.alias); let cf: Box = Box::new(cf); @@ -850,8 +849,10 @@ mod tests { "3.10" = "3.10.0" "#}) .unwrap(); - cf.remove_alias("node", "16"); - cf.remove_alias("python", "3.10"); + let node = "node".parse().unwrap(); + let python = "python".parse().unwrap(); + cf.remove_alias(&node, "16"); + cf.remove_alias(&python, "3.10"); assert_debug_snapshot!(cf.alias); let cf: Box = Box::new(cf); @@ -868,7 +869,8 @@ mod tests { node = ["16.0.0", "18.0.0"] "#}) .unwrap(); - cf.replace_versions(&String::from("node"), &["16.0.1".into(), "18.0.1".into()]); + let node = "node".parse().unwrap(); + cf.replace_versions(&node, &["16.0.1".into(), "18.0.1".into()]); assert_debug_snapshot!(cf.toolset); let cf: Box = Box::new(cf); @@ -885,7 +887,7 @@ mod tests { node = ["16.0.0", "18.0.0"] "#}) .unwrap(); - cf.remove_plugin(&String::from("node")); + cf.remove_plugin(&"node".parse().unwrap()); assert_debug_snapshot!(cf.toolset); let cf: Box = Box::new(cf); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index ba76107f4..b3b4c8c08 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -10,16 +10,16 @@ use once_cell::sync::Lazy; use tool_versions::ToolVersions; -use crate::cli::args::ToolArg; +use crate::cli::args::{ForgeArg, ToolArg}; use crate::config::config_file::mise_toml::MiseToml; -use crate::config::{global_config_files, system_config_files, AliasMap, Config, Settings}; +use crate::config::{global_config_files, system_config_files, AliasMap, Settings}; use crate::errors::Error::UntrustedConfig; use crate::file::display_path; use crate::hash::{file_hash_sha256, hash_to_str}; use crate::task::Task; use crate::toolset::{ToolVersionList, Toolset}; use crate::ui::{prompt, style}; -use crate::{dirs, env, file}; +use crate::{dirs, env, file, forge}; pub mod legacy_version; pub mod mise_toml; @@ -70,8 +70,8 @@ pub trait ConfigFile: Debug + Send + Sync { fn tasks(&self) -> Vec<&Task> { Default::default() } - fn remove_plugin(&mut self, _plugin_name: &str); - fn replace_versions(&mut self, plugin_name: &str, versions: &[String]); + fn remove_plugin(&mut self, _fa: &ForgeArg); + fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]); fn save(&self) -> Result<()>; fn dump(&self) -> String; fn to_toolset(&self) -> &Toolset; @@ -90,34 +90,33 @@ pub trait ConfigFile: Debug + Send + Sync { } impl dyn ConfigFile { - pub fn add_runtimes(&mut self, config: &Config, runtimes: &[ToolArg], pin: bool) -> Result<()> { + pub fn add_runtimes(&mut self, tools: &[ToolArg], pin: bool) -> Result<()> { // TODO: this has become a complete mess and could probably be greatly simplified let mut ts = self.to_toolset().to_owned(); - ts.resolve(config); + ts.resolve(); let mut plugins_to_update = HashMap::new(); - for runtime in runtimes { - if let Some(tv) = &runtime.tvr { + for ta in tools { + if let Some(tv) = &ta.tvr { plugins_to_update - .entry(runtime.plugin.clone()) + .entry(ta.forge.clone()) .or_insert_with(Vec::new) .push(tv); } } - for (plugin, versions) in &plugins_to_update { - let mut tvl = - ToolVersionList::new(plugin.to_string(), ts.source.as_ref().unwrap().clone()); + for (fa, versions) in &plugins_to_update { + let mut tvl = ToolVersionList::new(fa.clone(), ts.source.as_ref().unwrap().clone()); for tv in versions { tvl.requests.push(((*tv).clone(), Default::default())); } - ts.versions.insert(plugin.clone(), tvl); + ts.versions.insert(fa.clone(), tvl); } - ts.resolve(config); - for (plugin, versions) in plugins_to_update { + ts.resolve(); + for (fa, versions) in plugins_to_update { let versions = versions .into_iter() .map(|tvr| { if pin { - let plugin = config.get_or_create_plugin(&plugin); + let plugin = forge::get(&fa); let tv = tvr.resolve(plugin.as_ref(), Default::default(), false)?; Ok(tv.version) } else { @@ -125,7 +124,7 @@ impl dyn ConfigFile { } }) .collect::>>()?; - self.replace_versions(&plugin, &versions); + self.replace_versions(&fa, &versions); } Ok(()) @@ -137,15 +136,15 @@ impl dyn ConfigFile { pub fn display_runtime(&self, runtimes: &[ToolArg]) -> Result { // in this situation we just print the current version in the config file if runtimes.len() == 1 && runtimes[0].tvr.is_none() { - let plugin = &runtimes[0].plugin; + let fa = &runtimes[0].forge; let tvl = self .to_toolset() .versions - .get(plugin) + .get(fa) .ok_or_else(|| { eyre!( "no version set for {} in {}", - plugin.to_string(), + fa.to_string(), display_path(self.get_path()) ) })? diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap index a4d76e4fa..c0d10bd6d 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-3.snap @@ -4,13 +4,13 @@ expression: "replace_path(&format!(\"{:#?}\", cf.toolset))" --- Toolset { versions: { - "terraform": ToolVersionList { - plugin_name: "terraform", + ForgeArg("terraform"): ToolVersionList { + forge: ForgeArg("terraform"), versions: [], requests: [ ( Version( - "terraform", + ForgeArg("terraform"), "1.0.0", ), {}, @@ -20,34 +20,34 @@ Toolset { "~/fixtures/.mise.toml", ), }, - "node": ToolVersionList { - plugin_name: "node", + ForgeArg("node"): ToolVersionList { + forge: ForgeArg("node"), versions: [], requests: [ ( Version( - "node", + ForgeArg("node"), "18", ), {}, ), ( Prefix( - "node", + ForgeArg("node"), "20", ), {}, ), ( Ref( - "node", + ForgeArg("node"), "master", ), {}, ), ( Path( - "node", + ForgeArg("node"), "~/.nodes/18", ), {}, @@ -57,13 +57,13 @@ Toolset { "~/fixtures/.mise.toml", ), }, - "jq": ToolVersionList { - plugin_name: "jq", + ForgeArg("jq"): ToolVersionList { + forge: ForgeArg("jq"), versions: [], requests: [ ( Prefix( - "jq", + ForgeArg("jq"), "1.6", ), {}, @@ -73,13 +73,13 @@ Toolset { "~/fixtures/.mise.toml", ), }, - "shellcheck": ToolVersionList { - plugin_name: "shellcheck", + ForgeArg("shellcheck"): ToolVersionList { + forge: ForgeArg("shellcheck"), versions: [], requests: [ ( Version( - "shellcheck", + ForgeArg("shellcheck"), "0.9.0", ), {}, @@ -89,13 +89,13 @@ Toolset { "~/fixtures/.mise.toml", ), }, - "python": ToolVersionList { - plugin_name: "python", + ForgeArg("python"): ToolVersionList { + forge: ForgeArg("python"), versions: [], requests: [ ( Version( - "python", + ForgeArg("python"), "3.10.0", ), { @@ -104,7 +104,7 @@ Toolset { ), ( Version( - "python", + ForgeArg("python"), "3.9.0", ), {}, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap index 149ac517c..c6db6307d 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-4.snap @@ -3,7 +3,7 @@ source: src/config/config_file/mise_toml.rs expression: cf.alias --- { - "node": { + ForgeArg("node"): { "my_custom_node": "18", }, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap index 2a51d0482..a338ba521 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap @@ -1,13 +1,13 @@ --- source: src/config/config_file/mise_toml.rs -expression: "replace_path(&format!(\"{:#?}\", &cf))" +expression: "replace_path(&format!(\"{:#?}\", & cf))" --- MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { env: { "NODE_ENV": "production", }, alias: { - "node": { + ForgeArg("node"): { "my_custom_node": "18", }, }, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index bd7599633..09d6b2add 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -4,7 +4,7 @@ expression: cf --- MiseToml(/tmp/.mise.toml): { alias: { - "node": { + ForgeArg("node"): { "18": "18.0.0", }, }, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias.snap index 31bed0d01..dbfd0f472 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias.snap @@ -3,7 +3,7 @@ source: src/config/config_file/mise_toml.rs expression: cf.alias --- { - "node": { + ForgeArg("node"): { "18": "18.0.0", }, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions.snap index 3bed4e77e..0f4f859b7 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions.snap @@ -4,20 +4,20 @@ expression: cf.toolset --- Toolset { versions: { - "node": ToolVersionList { - plugin_name: "node", + ForgeArg("node"): ToolVersionList { + forge: ForgeArg("node"), versions: [], requests: [ ( Version( - "node", + ForgeArg("node"), "16.0.1", ), {}, ), ( Version( - "node", + ForgeArg("node"), "18.0.1", ), {}, diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias.snap index b5320ecc7..b439ce631 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias.snap @@ -3,12 +3,12 @@ source: src/config/config_file/mise_toml.rs expression: cf.alias --- { - "node": { + ForgeArg("node"): { "16": "16.0.0", "18": "18.0.1", "20": "20.0.0", }, - "python": { + ForgeArg("python"): { "3.10": "3.10.0", }, } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 3d89c1c92..e2d3df0e3 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -1,18 +1,17 @@ use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; -use crate::config::config_file; use console::{measure_text_width, pad_str, Alignment}; use eyre::Result; use indexmap::IndexMap; use itertools::Itertools; use tera::Context; +use crate::cli::args::ForgeArg; +use crate::config::config_file; use crate::config::config_file::{ConfigFile, ConfigFileType}; - use crate::file; use crate::file::display_path; -use crate::plugins::unalias_plugin; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -26,7 +25,7 @@ pub struct ToolVersions { context: Context, path: PathBuf, pre: String, - plugins: IndexMap, + plugins: IndexMap, toolset: Toolset, } @@ -76,18 +75,18 @@ impl ToolVersions { Ok(cf) } - fn get_or_create_plugin(&mut self, plugin: &str) -> &mut ToolVersionPlugin { + fn get_or_create_plugin(&mut self, fa: &ForgeArg) -> &mut ToolVersionPlugin { self.plugins - .entry(plugin.to_string()) + .entry(fa.clone()) .or_insert_with(|| ToolVersionPlugin { - orig_name: plugin.to_string(), + orig_name: fa.to_string(), versions: vec![], post: "".into(), }) } - fn parse_plugins(input: &str) -> Result> { - let mut plugins: IndexMap = IndexMap::new(); + fn parse_plugins(input: &str) -> Result> { + let mut plugins: IndexMap = IndexMap::new(); for line in input.lines() { if line.trim_start().starts_with('#') { if let Some(prev) = &mut plugins.values_mut().last() { @@ -103,7 +102,7 @@ impl ToolVersions { // note that this method will cause the colons to be removed // permanently if saving the file again, but I think that's fine let orig_plugin = plugin.trim_end_matches(':'); - let plugin = unalias_plugin(orig_plugin); + let fa = orig_plugin.parse()?; let tvp = ToolVersionPlugin { orig_name: orig_plugin.to_string(), @@ -113,14 +112,14 @@ impl ToolVersions { _ => [" #", post, "\n"].join(""), }, }; - plugins.insert(plugin.to_string(), tvp); + plugins.insert(fa, tvp); } } Ok(plugins) } - fn add_version(&mut self, plugin: &str, version: &str) { - self.get_or_create_plugin(plugin) + fn add_version(&mut self, fa: &ForgeArg, version: &str) { + self.get_or_create_plugin(fa) .versions .push(version.to_string()); } @@ -160,14 +159,14 @@ impl ConfigFile for ToolVersions { self.path.as_path() } - fn remove_plugin(&mut self, plugin: &str) { - self.plugins.remove(plugin); + fn remove_plugin(&mut self, fa: &ForgeArg) { + self.plugins.remove(fa); } - fn replace_versions(&mut self, plugin_name: &str, versions: &[String]) { - self.get_or_create_plugin(plugin_name).versions.clear(); + fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) { + self.get_or_create_plugin(fa).versions.clear(); for version in versions { - self.add_version(plugin_name, version); + self.add_version(fa, version); } } @@ -182,7 +181,7 @@ impl ConfigFile for ToolVersions { let max_plugin_len = self .plugins .keys() - .map(|p| measure_text_width(p)) + .map(|p| measure_text_width(&p.to_string())) .max() .unwrap_or_default(); for (_, tv) in &self.plugins { @@ -200,9 +199,9 @@ impl ConfigFile for ToolVersions { #[cfg(test)] pub(crate) mod tests { + use pretty_assertions::assert_eq; use crate::env; - use pretty_assertions::assert_eq; use super::*; diff --git a/src/config/mod.rs b/src/config/mod.rs index ef8df8b0f..1956f3ecd 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,10 +1,10 @@ -use either::Either; use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Formatter}; use std::iter::once; use std::path::PathBuf; use std::sync::{Arc, RwLock}; +use either::Either; use eyre::{Context, Result}; use indexmap::IndexMap; use itertools::Itertools; @@ -13,26 +13,24 @@ use rayon::prelude::*; pub use settings::Settings; +use crate::cli::args::ForgeArg; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::mise_toml::MiseToml; use crate::config::config_file::ConfigFile; use crate::config::tracking::Tracker; use crate::file::display_path; use crate::forge::Forge; -use crate::plugins::core::{PluginMap, CORE_PLUGINS, EXPERIMENTAL_CORE_PLUGINS}; -use crate::plugins::{ExternalPlugin, PluginType}; use crate::shorthands::{get_shorthands, Shorthands}; use crate::task::Task; use crate::ui::style; -use crate::{dirs, env, file}; +use crate::{dirs, env, file, forge}; pub mod config_file; pub mod settings; mod tracking; -type AliasMap = BTreeMap>; +type AliasMap = BTreeMap>; type ConfigMap = IndexMap>; -type ToolMap = BTreeMap>; #[derive(Default)] pub struct Config { @@ -43,7 +41,6 @@ pub struct Config { pub path_dirs: Vec, pub project_root: Option, all_aliases: OnceCell, - plugins: RwLock, repo_urls: HashMap, shorthands: OnceCell>, tasks: OnceCell>, @@ -67,15 +64,14 @@ impl Config { let settings = Settings::try_get()?; trace!("Settings: {:#?}", settings); - let plugins = load_plugins(&settings)?; - let legacy_files = load_legacy_files(&settings, &plugins); + let legacy_files = load_legacy_files(&settings); let config_filenames = legacy_files .keys() .chain(DEFAULT_CONFIG_FILENAMES.iter()) .cloned() .collect_vec(); let config_paths = load_config_paths(&config_filenames); - let config_files = load_all_config_files(&config_paths, &plugins, &legacy_files)?; + let config_files = load_all_config_files(&config_paths, &legacy_files)?; let (env, env_sources) = load_env(&settings, &config_files); let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); @@ -90,7 +86,6 @@ impl Config { tasks: OnceCell::new(), project_root: get_project_root(&config_files), config_files, - plugins: RwLock::new(plugins), repo_urls, }; @@ -123,62 +118,33 @@ impl Config { env::var("__MISE_DIFF").is_ok() } - pub fn resolve_alias(&self, plugin_name: &str, v: &str) -> Result { - if let Some(plugin_aliases) = self.aliases.get(plugin_name) { + pub fn resolve_alias(&self, forge: &dyn Forge, v: &str) -> Result { + if let Some(plugin_aliases) = self.aliases.get(&forge.get_fa()) { if let Some(alias) = plugin_aliases.get(v) { return Ok(alias.clone()); } } - if let Some(plugin) = self.plugins.read().unwrap().get(plugin_name) { - if let Some(alias) = plugin.get_aliases()?.get(v) { - return Ok(alias.clone()); - } + if let Some(alias) = forge.get_aliases()?.get(v) { + return Ok(alias.clone()); } Ok(v.to_string()) } - 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(&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 - .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 - .list_plugins() + let plugin_aliases: Vec<_> = forge::list() .into_par_iter() - .map(|plugin| { - let aliases = plugin.get_aliases().unwrap_or_else(|err| { + .map(|forge| { + let aliases = forge.get_aliases().unwrap_or_else(|err| { warn!("get_aliases: {err}"); BTreeMap::new() }); - (plugin.name().to_string(), aliases) + (forge.get_fa(), aliases) }) .collect(); - for (plugin, plugin_aliases) in plugin_aliases { + for (fa, plugin_aliases) in plugin_aliases { for (from, to) in plugin_aliases { - aliases - .entry(plugin.to_string()) - .or_default() - .insert(from, to); + aliases.entry(fa.clone()).or_default().insert(from, to); } } @@ -258,7 +224,7 @@ impl Config { pub fn rebuild_shims_and_runtime_symlinks(&self) -> Result<()> { let ts = crate::toolset::ToolsetBuilder::new().build(self)?; - crate::shims::reshim(self, &ts)?; + crate::shims::reshim(&ts)?; crate::runtime_symlinks::rebuild(self)?; Ok(()) } @@ -289,25 +255,11 @@ fn get_project_root(config_files: &ConfigMap) -> Option { .map(|pr| pr.to_path_buf()) } -fn load_plugins(settings: &Settings) -> Result { - let mut tools = CORE_PLUGINS.clone(); - if settings.experimental { - tools.extend(EXPERIMENTAL_CORE_PLUGINS.clone()); - } - tools.extend(ExternalPlugin::list()?); - for tool in &settings.disable_tools { - tools.remove(tool); - } - Ok(tools) -} - -fn load_legacy_files(settings: &Settings, tools: &PluginMap) -> BTreeMap> { +fn load_legacy_files(settings: &Settings) -> BTreeMap> { if !settings.legacy_version_file { return BTreeMap::new(); } - let legacy = tools - .values() - .collect_vec() + let legacy = forge::list() .into_par_iter() .filter(|tool| { !settings @@ -420,7 +372,6 @@ pub fn system_config_files() -> Vec { fn load_all_config_files( config_filenames: &[PathBuf], - tools: &PluginMap, legacy_filenames: &BTreeMap>, ) -> Result { Ok(config_filenames @@ -429,7 +380,7 @@ fn load_all_config_files( .collect_vec() .into_par_iter() .map(|f| { - let cf = parse_config_file(f, legacy_filenames, tools).wrap_err_with(|| { + let cf = parse_config_file(f, legacy_filenames).wrap_err_with(|| { format!( "error parsing config file: {}", style::ebold(display_path(f)) @@ -450,16 +401,14 @@ fn load_all_config_files( fn parse_config_file( f: &PathBuf, legacy_filenames: &BTreeMap>, - tools: &ToolMap, ) -> Result> { match legacy_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) { Some(plugin) => { - let tools = tools - .iter() - .filter(|(k, _)| plugin.contains(k)) - .map(|(_, t)| t) + let tools = forge::list() + .into_iter() + .filter(|f| plugin.contains(&f.to_string())) .collect::>(); - LegacyVersionFile::parse(f.into(), &tools).map(|f| Box::new(f) as Box) + LegacyVersionFile::parse(f.into(), tools).map(|f| Box::new(f) as Box) } None => config_file::parse(f), } @@ -523,12 +472,6 @@ fn load_aliases(config_files: &ConfigMap) -> AliasMap { impl Debug for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let plugins = self - .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 .iter() @@ -536,7 +479,6 @@ impl Debug for Config { .collect::>(); let mut s = f.debug_struct("Config"); s.field("Config Files", &config_files); - s.field("Installed Plugins", &plugins); if let Some(tasks) = self.tasks.get() { s.field( "Tasks", @@ -559,7 +501,6 @@ impl Debug for Config { #[cfg(test)] mod tests { - use super::*; #[test] diff --git a/src/config/snapshots/mise__config__tests__load.snap b/src/config/snapshots/mise__config__tests__load.snap index c98a8075a..7be2559c6 100644 --- a/src/config/snapshots/mise__config__tests__load.snap +++ b/src/config/snapshots/mise__config__tests__load.snap @@ -8,15 +8,11 @@ Config { "~/.test-tool-versions", "~/config/config.toml", ], - Installed Plugins: [ - "dummy", - "tiny", - ], Env: { "TEST_ENV_VAR": "test-123", }, Aliases: { - "tiny": { + ForgeArg("tiny"): { "my/alias": "3.0", }, }, diff --git a/src/forge/cargo.rs b/src/forge/cargo.rs new file mode 100644 index 000000000..9d5fa9aad --- /dev/null +++ b/src/forge/cargo.rs @@ -0,0 +1,28 @@ +use crate::forge::Forge; +use crate::install_context::InstallContext; +use std::fmt::Debug; + +#[derive(Debug)] +pub struct CargoForge { + pub name: String, +} + +impl Forge for CargoForge { + fn name(&self) -> &str { + &self.name + } + + fn list_remote_versions(&self) -> eyre::Result> { + todo!() + } + + fn install_version_impl(&self, _ctx: &InstallContext) -> eyre::Result<()> { + todo!() + } +} + +impl CargoForge { + pub fn new(name: String) -> Self { + Self { name } + } +} diff --git a/src/forge/mod.rs b/src/forge/mod.rs index 7dda12100..787308457 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -1,27 +1,98 @@ +use std::collections::{BTreeMap, HashMap}; +use std::fmt::{Debug, Display}; +use std::fs::File; +use std::hash::Hash; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; + +use clap::Command; +use console::style; +use eyre::WrapErr; +use itertools::Itertools; +use regex::Regex; +use versions::Versioning; + +use crate::cli::args::ForgeArg; use crate::config::{Config, Settings}; use crate::file::{display_path, remove_all, remove_all_with_warning}; +use crate::forge::cargo::CargoForge; use crate::install_context::InstallContext; use crate::lock_file::LockFile; -use crate::plugins::{PluginType, VERSION_REGEX}; +use crate::plugins::core::CORE_PLUGINS; +use crate::plugins::{ExternalPlugin, PluginType, VERSION_REGEX}; use crate::runtime_symlinks::is_runtime_symlink; use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::multi_progress_report::MultiProgressReport; use crate::ui::progress_report::SingleReport; use crate::{dirs, file}; -use clap::Command; -use console::style; -use eyre::WrapErr; -use itertools::Itertools; -use regex::Regex; -use std::collections::{BTreeMap, HashMap}; -use std::fmt::Debug; -use std::fs::File; -use std::path::{Path, PathBuf}; -use versions::Versioning; + +mod cargo; + +pub type AForge = Arc; +pub type ForgeMap = BTreeMap; +pub type ForgeList = Vec; + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, EnumString, AsRefStr, Ord, PartialOrd)] +#[strum(serialize_all = "snake_case")] +pub enum ForgeType { + Asdf, + Cargo, +} + +static FORGES: Mutex> = Mutex::new(None); + +fn load_forges() -> ForgeMap { + let mut forges = FORGES.lock().unwrap(); + if let Some(forges) = &*forges { + return forges.clone(); + } + let mut plugins = CORE_PLUGINS.clone(); + plugins.extend(ExternalPlugin::list().expect("failed to list plugins")); + let settings = Settings::get(); + plugins.retain(|plugin| !settings.disable_tools.contains(plugin.name())); + let plugins: ForgeMap = plugins + .into_iter() + .map(|plugin| (plugin.get_fa(), plugin)) + .collect(); + *forges = Some(plugins.clone()); + plugins +} + +pub fn list() -> ForgeList { + load_forges().values().cloned().collect() +} + +#[cfg(test)] +pub fn reset() { + *FORGES.lock().unwrap() = None; +} + +pub fn get(fa: &ForgeArg) -> AForge { + if let Some(forge) = load_forges().get(fa) { + forge.clone() + } else { + let mut m = FORGES.lock().unwrap(); + let forges = m.as_mut().unwrap(); + let name = fa.name.to_string(); + forges + .entry(fa.clone()) + .or_insert_with(|| match fa.forge_type { + ForgeType::Asdf => Arc::new(ExternalPlugin::new(name)), + ForgeType::Cargo => Arc::new(CargoForge::new(name)), + }) + .clone() + } +} pub trait Forge: Debug + Send + Sync { fn name(&self) -> &str; - fn get_type(&self) -> PluginType { + fn get_type(&self) -> ForgeType { + ForgeType::Asdf + } + fn get_fa(&self) -> ForgeArg { + ForgeArg::new(self.get_type(), self.name()) + } + fn get_plugin_type(&self) -> PluginType { PluginType::Core } fn installs_path(&self) -> PathBuf { @@ -338,3 +409,43 @@ fn rmdir(dir: &Path, pr: &dyn SingleReport) -> eyre::Result<()> { ) }) } + +pub fn unalias_forge(forge: &str) -> &str { + match forge { + "nodejs" => "node", + "golang" => "go", + _ => forge, + } +} + +impl Display for dyn Forge { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name()) + } +} + +impl Eq for dyn Forge {} + +impl PartialEq for dyn Forge { + fn eq(&self, other: &Self) -> bool { + self.get_plugin_type() == other.get_plugin_type() && self.name() == other.name() + } +} + +impl Hash for dyn Forge { + fn hash(&self, state: &mut H) { + self.name().hash(state) + } +} + +impl PartialOrd for dyn Forge { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for dyn Forge { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.name().cmp(other.name()) + } +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index c8bb55d90..68988be65 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::ffi::OsString; use std::iter::Iterator; use std::path::PathBuf; @@ -11,7 +10,8 @@ use once_cell::sync::Lazy; pub use python::PythonPlugin; use crate::cache::CacheManager; -use crate::forge::Forge; +use crate::config::Settings; +use crate::forge::{Forge, ForgeList}; use crate::http::HTTP_FETCH; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; @@ -33,10 +33,8 @@ mod node; mod python; mod ruby; -pub type PluginMap = BTreeMap>; - -pub static CORE_PLUGINS: Lazy = Lazy::new(|| { - let plugins: Vec> = vec![ +pub static CORE_PLUGINS: Lazy = Lazy::new(|| { + let mut plugins: Vec> = vec![ Arc::new(BunPlugin::new()), Arc::new(DenoPlugin::new()), Arc::new(GoPlugin::new()), @@ -45,18 +43,11 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { Arc::new(PythonPlugin::new()), Arc::new(RubyPlugin::new()), ]; + let settings = Settings::get(); + if settings.experimental { + plugins.push(Arc::new(ErlangPlugin::new())); + } plugins - .into_iter() - .map(|plugin| (plugin.name().to_string(), plugin)) - .collect() -}); - -pub static EXPERIMENTAL_CORE_PLUGINS: Lazy = Lazy::new(|| { - let plugins: Vec> = vec![Arc::new(ErlangPlugin::new())]; - plugins - .into_iter() - .map(|plugin| (plugin.name().to_string(), plugin)) - .collect() }); #[derive(Debug)] diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index fcfd52af2..ad7039002 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -20,7 +20,7 @@ use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_all}; -use crate::forge::Forge; +use crate::forge::{AForge, Forge, ForgeList}; use crate::git::Git; use crate::hash::hash_to_str; use crate::http::HTTP_FETCH; @@ -88,14 +88,10 @@ impl ExternalPlugin { name, } } - pub fn newa(name: String) -> Arc { - Arc::new(Self::new(name)) - } - - pub fn list() -> Result)>> { + pub fn list() -> Result { Ok(file::dir_subdirs(&dirs::PLUGINS)? .into_par_iter() - .map(|name| (name.clone(), Self::newa(name))) + .map(|name| Arc::new(Self::new(name)) as AForge) .collect()) } @@ -412,7 +408,7 @@ impl Forge for ExternalPlugin { &self.name } - fn get_type(&self) -> PluginType { + fn get_plugin_type(&self) -> PluginType { PluginType::External } fn list_remote_versions(&self) -> Result> { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 2c5902e71..142ac9a03 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,12 +1,15 @@ -pub use external_plugin::ExternalPlugin; +use std::fmt::Debug; +use std::sync::Arc; use once_cell::sync::Lazy; use regex::Regex; + +pub use external_plugin::ExternalPlugin; pub use script_manager::{Script, ScriptManager}; -use std::fmt::{Debug, Display}; -use std::hash::Hash; -use crate::forge::Forge; +use crate::cli::args::ForgeArg; +use crate::forge; +use crate::forge::{Forge, ForgeList, ForgeType}; pub mod core; mod external_plugin; @@ -14,41 +17,6 @@ mod external_plugin_cache; mod mise_plugin_toml; mod script_manager; -pub fn unalias_plugin(plugin_name: &str) -> &str { - match plugin_name { - "nodejs" => "node", - "golang" => "go", - _ => plugin_name, - } -} - -impl Display for dyn Forge { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name()) - } -} -impl Eq for dyn Forge {} -impl PartialEq for dyn Forge { - fn eq(&self, other: &Self) -> bool { - self.get_type() == other.get_type() && self.name() == other.name() - } -} -impl Hash for dyn Forge { - fn hash(&self, state: &mut H) { - self.name().hash(state) - } -} -impl PartialOrd for dyn Forge { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl Ord for dyn Forge { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.name().cmp(other.name()) - } -} - #[derive(Debug, Clone, Copy, PartialEq)] pub enum PluginType { Core, @@ -62,17 +30,37 @@ pub static VERSION_REGEX: Lazy = Lazy::new(|| { .unwrap() }); +pub fn get(name: &str) -> Arc { + let fa = ForgeArg::new(ForgeType::Asdf, name); + forge::get(&fa) +} + +pub fn list() -> ForgeList { + forge::list() + .into_iter() + .filter(|f| f.get_type() == ForgeType::Asdf) + .collect() +} + +pub fn list_external() -> ForgeList { + list() + .into_iter() + .filter(|tool| tool.get_plugin_type() == PluginType::External) + .collect() +} + #[cfg(test)] mod tests { - use crate::forge::Forge; use pretty_assertions::assert_str_eq; + use crate::forge::Forge; + use super::*; #[test] fn test_exact_match() { assert_cli!("plugin", "add", "tiny"); - let plugin = ExternalPlugin::newa(String::from("tiny")); + let plugin = ExternalPlugin::new(String::from("tiny")); let version = plugin .latest_version(Some("1.0.0".into())) .unwrap() diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 5fee6a5d2..a67709e7d 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -11,10 +11,10 @@ use crate::config::Config; use crate::file::make_symlink; use crate::forge::Forge; use crate::plugins::VERSION_REGEX; -use crate::{dirs, file}; +use crate::{dirs, file, forge}; pub fn rebuild(config: &Config) -> Result<()> { - for plugin in config.list_plugins() { + for plugin in forge::list() { let symlinks = list_symlinks(config, plugin.clone())?; let installs_dir = dirs::INSTALLS.join(plugin.name()); for (from, to) in symlinks { @@ -36,11 +36,11 @@ pub fn rebuild(config: &Config) -> Result<()> { Ok(()) } -fn list_symlinks(config: &Config, plugin: Arc) -> Result> { +fn list_symlinks(config: &Config, forge: Arc) -> Result> { // TODO: make this a pure function and add test cases let mut symlinks = IndexMap::new(); let rel_path = |x: &String| PathBuf::from(".").join(x.clone()); - for v in installed_versions(&plugin)? { + for v in installed_versions(&forge)? { let prefix = regex!(r"^[a-zA-Z0-9]+-") .find(&v) .map(|s| s.as_str().to_string()) @@ -57,7 +57,7 @@ fn list_symlinks(config: &Config, plugin: Arc) -> Result Option { _ => match a.get_id().as_str() { "tool" => Some("(__mise_tool_versions)".to_string()), "installed_tool" => Some("(__mise_installed_tool_versions)".to_string()), - "plugin" => Some("(__mise_plugins)".to_string()), + "forge" | "plugin" => Some("(__mise_plugins)".to_string()), "new_plugin" => Some("(__mise_all_plugins)".to_string()), "alias" => Some("(__mise_aliases)".to_string()), "setting" => Some("(__mise_settings)".to_string()), diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index f0923f6b2..b84bca6bb 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -233,14 +233,14 @@ fn render_completion(arg: &Arg) -> String { ValueHint::EmailAddress => "_email_addresses".to_string(), ValueHint::Other => "( )".to_string(), _ => match arg.get_id().as_str() { - "tool" => "__mise_tool_versions".to_string(), + "alias" => "__mise_aliases".to_string(), + "forge" | "plugin" => "__mise_plugins".to_string(), "installed_tool" => "__mise_installed_tool_versions".to_string(), - "plugin" => "__mise_plugins".to_string(), "new_plugin" => "__mise_all_plugins".to_string(), - "alias" => "__mise_aliases".to_string(), + "prefix" => "__mise_prefixes".to_string(), "setting" => "__mise_settings".to_string(), "task" => "__mise_tasks".to_string(), - "prefix" => "__mise_prefixes".to_string(), + "tool" => "__mise_tool_versions".to_string(), _ => String::new(), }, } diff --git a/src/shims.rs b/src/shims.rs index 855a9df3b..0565a15b3 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -12,10 +12,10 @@ use rayon::prelude::*; use crate::cli::exec::Exec; use crate::config::{Config, Settings}; -use crate::fake_asdf; use crate::file::{create_dir_all, display_path, remove_all}; use crate::lock_file::LockFile; use crate::{env, logger}; +use crate::{fake_asdf, forge}; use crate::forge::Forge; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; @@ -54,7 +54,7 @@ fn which_shim(bin_name: &str) -> Result { let settings = Settings::try_get()?; if settings.not_found_auto_install { for tv in ts.install_missing_bin(bin_name)?.unwrap_or_default() { - let p = config.get_or_create_plugin(&tv.plugin_name); + let p = tv.get_forge(); if let Some(bin) = p.which(&tv, bin_name)? { return Ok(bin); } @@ -72,11 +72,11 @@ fn which_shim(bin_name: &str) -> Result { return Ok(bin); } } - let tvs = ts.list_rtvs_with_bin(&config, bin_name)?; + let tvs = ts.list_rtvs_with_bin(bin_name)?; err_no_version_set(ts, bin_name, tvs) } -pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { +pub fn reshim(ts: &Toolset) -> Result<()> { let _lock = LockFile::new(&dirs::SHIMS) .with_callback(|l| { trace!("reshim callback {}", l.display()); @@ -98,7 +98,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { .collect::>(); let shims: HashSet = ts - .list_installed_versions(config)? + .list_installed_versions()? .into_par_iter() .flat_map(|(t, tv)| { list_tool_bins(t.clone(), &tv).unwrap_or_else(|e| { @@ -125,7 +125,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let symlink_path = dirs::SHIMS.join(shim); remove_all(&symlink_path)?; } - for plugin in config.list_plugins() { + for plugin in forge::list() { match dirs::PLUGINS.join(plugin.name()).join("shims").read_dir() { Ok(files) => { for bin in files { @@ -201,17 +201,17 @@ fn err_no_version_set(ts: Toolset, bin_name: &str, tvs: Vec) -> Res if tvs.is_empty() { bail!("{} is not a valid shim", bin_name); } - let missing_plugins = tvs.iter().map(|tv| &tv.plugin_name).collect::>(); + let missing_plugins = tvs.iter().map(|tv| &tv.forge).collect::>(); let mut missing_tools = ts .list_missing_versions() .into_iter() - .filter(|t| missing_plugins.contains(&t.plugin_name)) + .filter(|t| missing_plugins.contains(&t.forge)) .collect_vec(); if missing_tools.is_empty() { let mut msg = format!("No version is set for shim: {}\n", bin_name); msg.push_str("Set a global default version with one of the following:\n"); for tv in tvs { - msg.push_str(&format!("mise use -g {}@{}\n", tv.plugin_name, tv.version)); + msg.push_str(&format!("mise use -g {}@{}\n", tv.forge, tv.version)); } Err(eyre!(msg.trim().to_string())) } else { diff --git a/src/test.rs b/src/test.rs index a38bb65c8..b65cad88d 100644 --- a/src/test.rs +++ b/src/test.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use crate::cli::Cli; use crate::config::Config; use crate::output::tests::{STDERR, STDOUT}; -use crate::{dirs, env, file}; +use crate::{dirs, env, file, forge}; #[ctor::ctor] fn init() { @@ -32,6 +32,7 @@ fn init() { env::set_var("MISE_DEFAULT_CONFIG_FILENAME", ".test.mise.toml"); //env::set_var("TERM", "dumb"); reset_config(); + forge::reset(); } pub fn reset_config() { @@ -98,6 +99,7 @@ pub fn replace_path(input: &str) -> String { pub fn cli_run(args: &Vec) -> eyre::Result<(String, String)> { Config::reset(); + forge::reset(); *env::ARGS.write().unwrap() = args.clone(); STDOUT.lock().unwrap().clear(); STDERR.lock().unwrap().clear(); diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 07cd94c75..4908931ce 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use eyre::Result; use itertools::Itertools; -use crate::cli::args::ToolArg; +use crate::cli::args::{ForgeArg, ToolArg}; use crate::config::{Config, Settings}; use crate::env; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -12,7 +12,6 @@ use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; pub struct ToolsetBuilder { args: Vec, global_only: bool, - tool_filter: Option>, } impl ToolsetBuilder { @@ -30,24 +29,20 @@ impl ToolsetBuilder { self } - pub fn with_tools(mut self, tools: &[&str]) -> Self { - self.tool_filter = Some(tools.iter().map(|s| s.to_string()).collect()); - self - } - pub fn build(self, config: &Config) -> Result { let settings = Settings::try_get()?; let mut toolset = Toolset { - disable_tools: settings.disable_tools.clone(), + disable_tools: settings + .disable_tools + .iter() + .map(|s| s.parse()) + .collect::>()?, ..Default::default() }; self.load_config_files(config, &mut toolset); self.load_runtime_env(&mut toolset, env::vars().collect()); self.load_runtime_args(&mut toolset); - if let Some(tools) = self.tool_filter { - toolset.versions.retain(|p, _| tools.contains(p)); - } - toolset.resolve(config); + toolset.resolve(); debug!("Toolset: {}", toolset); Ok(toolset) @@ -76,10 +71,11 @@ impl ToolsetBuilder { // ignore MISE_INSTALL_VERSION continue; } + let fa: ForgeArg = plugin_name.parse().unwrap(); let source = ToolSource::Environment(k, v.clone()); let mut env_ts = Toolset::new(source); for v in v.split_whitespace() { - let tvr = ToolVersionRequest::new(plugin_name.clone(), v); + let tvr = ToolVersionRequest::new(fa.clone(), v); env_ts.add_version(tvr, Default::default()); } ts.merge(&env_ts); @@ -91,7 +87,7 @@ impl ToolsetBuilder { if self.global_only { return; } - for (_, args) in self.args.iter().into_group_map_by(|arg| arg.plugin.clone()) { + for (_, args) in self.args.iter().into_group_map_by(|arg| arg.forge.clone()) { let mut arg_ts = Toolset::new(ToolSource::Argument); for arg in args { if let Some(tvr) = &arg.tvr { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 6c259cb55..8bdfc2a7c 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; @@ -16,8 +16,8 @@ pub use tool_version::ToolVersion; pub use tool_version_list::ToolVersionList; pub use tool_version_request::ToolVersionRequest; +use crate::cli::args::ForgeArg; use crate::config::{Config, Settings}; -use crate::env; use crate::env::TERM_WIDTH; use crate::forge::Forge; use crate::install_context::InstallContext; @@ -25,6 +25,7 @@ use crate::path_env::PathEnv; use crate::runtime_symlinks; use crate::shims; use crate::ui::multi_progress_report::MultiProgressReport; +use crate::{env, forge}; mod builder; mod tool_source; @@ -60,9 +61,9 @@ impl InstallOptions { /// merge in other toolsets from various sources #[derive(Debug, Default, Clone)] pub struct Toolset { - pub versions: IndexMap, + pub versions: IndexMap, pub source: Option, - pub disable_tools: BTreeSet, + pub disable_tools: HashSet, } impl Toolset { @@ -73,15 +74,14 @@ impl Toolset { } } pub fn add_version(&mut self, tvr: ToolVersionRequest, opts: ToolVersionOptions) { - if self.disable_tools.contains(tvr.plugin_name()) { + let fa = tvr.forge(); + if self.disable_tools.contains(fa) { return; } let tvl = self .versions - .entry(tvr.plugin_name().clone()) - .or_insert_with(|| { - ToolVersionList::new(tvr.plugin_name().to_string(), self.source.clone().unwrap()) - }); + .entry(tvr.forge().clone()) + .or_insert_with(|| ToolVersionList::new(fa.clone(), self.source.clone().unwrap())); tvl.requests.push((tvr, opts)); } pub fn merge(&mut self, other: &Toolset) { @@ -91,17 +91,17 @@ impl Toolset { versions.insert(plugin, tvl); } } - versions.retain(|_, tvl| !self.disable_tools.contains(&tvl.plugin_name)); + versions.retain(|_, tvl| !self.disable_tools.contains(&tvl.forge)); self.versions = versions; self.source = other.source.clone(); } - pub fn resolve(&mut self, config: &Config) { - self.list_missing_plugins(config); + pub fn resolve(&mut self) { + self.list_missing_plugins(); self.versions .iter_mut() .collect::>() .par_iter_mut() - .for_each(|(_, v)| v.resolve(config, false)); + .for_each(|(_, v)| v.resolve(false)); } pub fn install_arg_versions(&mut self, config: &Config, opts: &InstallOptions) -> Result<()> { let mpr = MultiProgressReport::get(); @@ -110,15 +110,15 @@ impl Toolset { .into_iter() .filter(|(p, tv)| opts.force || !p.is_version_installed(tv)) .map(|(_, tv)| tv) - .filter(|tv| matches!(self.versions[&tv.plugin_name].source, ToolSource::Argument)) + .filter(|tv| matches!(self.versions[&tv.forge].source, ToolSource::Argument)) .collect_vec(); self.install_versions(config, versions, &mpr, opts) } - pub fn list_missing_plugins(&self, config: &Config) -> Vec { + pub fn list_missing_plugins(&self) -> Vec { self.versions .keys() - .map(|p| config.get_or_create_plugin(p)) + .map(forge::get) .filter(|p| !p.is_installed()) .map(|p| p.name().into()) .collect() @@ -137,9 +137,9 @@ impl Toolset { let settings = Settings::try_get()?; let queue: Vec<_> = versions .into_iter() - .group_by(|v| v.plugin_name.clone()) + .group_by(|v| v.forge.clone()) .into_iter() - .map(|(pn, v)| (config.get_or_create_plugin(&pn), v.collect_vec())) + .map(|(fa, v)| (fa.get_forge(), v.collect_vec())) .collect(); for (t, _) in &queue { if !t.is_installed() { @@ -184,8 +184,8 @@ impl Toolset { .map(|t| t.join().unwrap()) .collect::>>() })?; - self.resolve(config); - shims::reshim(config, self)?; + self.resolve(); + shims::reshim(self)?; runtime_symlinks::rebuild(config) } pub fn list_missing_versions(&self) -> Vec { @@ -195,17 +195,13 @@ impl Toolset { .map(|(_, tv)| tv) .collect() } - pub fn list_installed_versions( - &self, - config: &Config, - ) -> Result, ToolVersion)>> { + pub fn list_installed_versions(&self) -> Result, ToolVersion)>> { let current_versions: HashMap<(String, String), (Arc, ToolVersion)> = self .list_current_versions() .into_iter() .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p.clone(), tv))) .collect(); - let versions = config - .list_plugins() + let versions = forge::list() .into_par_iter() .map(|p| { let versions = p.list_installed_versions()?; @@ -215,7 +211,7 @@ impl Toolset { |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) + let tv = ToolVersionRequest::new(p.get_fa(), &v) .resolve(p.as_ref(), Default::default(), false) .unwrap(); (p.clone(), tv) @@ -238,10 +234,9 @@ impl Toolset { .collect() } pub fn list_versions_by_plugin(&self) -> Vec<(Arc, &Vec)> { - let config = Config::get(); self.versions .iter() - .map(|(p, v)| (config.get_or_create_plugin(p), &v.versions)) + .map(|(p, v)| (forge::get(p), &v.versions)) .collect() } pub fn list_current_versions(&self) -> Vec<(Arc, ToolVersion)> { @@ -350,7 +345,7 @@ impl Toolset { pub fn install_missing_bin(&mut self, bin_name: &str) -> Result>> { let config = Config::try_get()?; let plugins = self - .list_installed_versions(&config)? + .list_installed_versions()? .into_iter() .filter(|(p, tv)| { if let Ok(x) = p.which(tv, bin_name) { @@ -364,7 +359,7 @@ impl Toolset { let versions = self .list_missing_versions() .into_iter() - .filter(|tv| tv.plugin_name == plugin.name()) + .filter(|tv| tv.forge == plugin.get_fa()) .collect_vec(); if !versions.is_empty() { let mpr = MultiProgressReport::get(); @@ -375,9 +370,9 @@ impl Toolset { Ok(None) } - pub fn list_rtvs_with_bin(&self, config: &Config, bin_name: &str) -> Result> { + pub fn list_rtvs_with_bin(&self, bin_name: &str) -> Result> { Ok(self - .list_installed_versions(config)? + .list_installed_versions()? .into_par_iter() .filter(|(p, tv)| match p.which(tv, bin_name) { Ok(x) => x.is_some(), diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index f9c1224c4..11ac7341d 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -5,20 +5,21 @@ use std::fs; use std::hash::{Hash, Hasher}; use std::path::PathBuf; +use crate::cli::args::ForgeArg; use eyre::Result; use versions::{Chunk, Version}; use crate::config::Config; -use crate::dirs; -use crate::forge::Forge; +use crate::forge::{AForge, Forge}; use crate::hash::hash_to_str; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; +use crate::{dirs, forge}; /// represents a single version of a tool for a particular plugin #[derive(Debug, Clone)] pub struct ToolVersion { pub request: ToolVersionRequest, - pub plugin_name: String, + pub forge: ForgeArg, pub version: String, pub opts: ToolVersionOptions, } @@ -31,7 +32,7 @@ impl ToolVersion { version: String, ) -> Self { ToolVersion { - plugin_name: tool.name().to_string(), + forge: tool.get_fa(), version, request, opts, @@ -66,19 +67,23 @@ impl ToolVersion { Ok(tv) } + pub fn get_forge(&self) -> AForge { + forge::get(&self.forge) + } + pub fn install_path(&self) -> PathBuf { let pathname = match &self.request { ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), _ => self.tv_pathname(), }; - dirs::INSTALLS.join(&self.plugin_name).join(pathname) + dirs::INSTALLS.join(self.forge.pathname()).join(pathname) } pub fn install_short_path(&self) -> PathBuf { let pathname = match &self.request { ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), _ => self.tv_short_pathname(), }; - let sp = dirs::INSTALLS.join(&self.plugin_name).join(pathname); + let sp = dirs::INSTALLS.join(self.forge.pathname()).join(pathname); if sp.exists() { sp } else { @@ -86,11 +91,13 @@ impl ToolVersion { } } pub fn cache_path(&self) -> PathBuf { - dirs::CACHE.join(&self.plugin_name).join(self.tv_pathname()) + dirs::CACHE + .join(self.forge.pathname()) + .join(self.tv_pathname()) } pub fn download_path(&self) -> PathBuf { dirs::DOWNLOADS - .join(&self.plugin_name) + .join(self.forge.pathname()) .join(self.tv_pathname()) } pub fn latest_version(&self, tool: &dyn Forge) -> Result { @@ -100,7 +107,7 @@ impl ToolVersion { pub fn style(&self) -> String { format!( "{}{}", - style(&self.plugin_name).blue().for_stderr(), + style(&self.forge.pathname()).blue().for_stderr(), style(&format!("@{}", &self.version)).for_stderr() ) } @@ -129,7 +136,7 @@ impl ToolVersion { opts: ToolVersionOptions, ) -> Result { let config = Config::get(); - let v = config.resolve_alias(tool.name(), v)?; + let v = config.resolve_alias(tool, v)?; match v.split_once(':') { Some(("ref", r)) => { return Ok(Self::resolve_ref(tool, r.to_string(), opts)); @@ -195,7 +202,7 @@ impl ToolVersion { ) -> Result { let v = match v { "latest" => tool.latest_version(None)?.unwrap(), - _ => Config::get().resolve_alias(tool.name(), v)?, + _ => Config::get().resolve_alias(tool, v)?, }; let v = version_sub(&v, sub); Self::resolve_version(tool, request, latest_versions, &v, opts) @@ -217,7 +224,7 @@ impl ToolVersion { } fn resolve_ref(tool: &dyn Forge, r: String, opts: ToolVersionOptions) -> Self { - let request = ToolVersionRequest::Ref(tool.name().into(), r); + let request = ToolVersionRequest::Ref(tool.get_fa(), r); let version = request.version(); Self::new(tool, request, opts, version) } @@ -228,7 +235,7 @@ impl ToolVersion { opts: ToolVersionOptions, ) -> Result { let path = fs::canonicalize(path)?; - let request = ToolVersionRequest::Path(tool.name().into(), path); + let request = ToolVersionRequest::Path(tool.get_fa(), path); let version = request.version(); Ok(Self::new(tool, request, opts, version)) } @@ -236,13 +243,13 @@ impl ToolVersion { impl Display for ToolVersion { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{}@{}", &self.plugin_name, &self.version) + write!(f, "{}@{}", &self.forge.pathname(), &self.version) } } impl PartialEq for ToolVersion { fn eq(&self, other: &Self) -> bool { - self.plugin_name == other.plugin_name && self.version == other.version + self.forge.pathname() == other.forge.pathname() && self.version == other.version } } impl Eq for ToolVersion {} @@ -253,7 +260,7 @@ impl PartialOrd for ToolVersion { } impl Ord for ToolVersion { fn cmp(&self, other: &Self) -> Ordering { - match self.plugin_name.cmp(&other.plugin_name) { + match self.forge.pathname().cmp(&other.forge.pathname()) { Ordering::Equal => self.version.cmp(&other.version), o => o, } @@ -261,7 +268,7 @@ impl Ord for ToolVersion { } impl Hash for ToolVersion { fn hash(&self, state: &mut H) { - self.plugin_name.hash(state); + self.forge.pathname().hash(state); self.version.hash(state); } } diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 2faa21895..76cbe50f8 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -1,28 +1,29 @@ -use crate::config::Config; +use crate::cli::args::ForgeArg; +use crate::forge; use crate::toolset::tool_version_request::ToolVersionRequest; use crate::toolset::{ToolSource, ToolVersion, ToolVersionOptions}; /// represents several versions of a tool for a particular plugin #[derive(Debug, Clone)] pub struct ToolVersionList { - pub plugin_name: String, + pub forge: ForgeArg, pub versions: Vec, pub requests: Vec<(ToolVersionRequest, ToolVersionOptions)>, pub source: ToolSource, } impl ToolVersionList { - pub fn new(plugin_name: String, source: ToolSource) -> Self { + pub fn new(forge: ForgeArg, source: ToolSource) -> Self { Self { - plugin_name, + forge, versions: Vec::new(), requests: vec![], source, } } - pub fn resolve(&mut self, config: &Config, latest_versions: bool) { + pub fn resolve(&mut self, latest_versions: bool) { self.versions.clear(); - let plugin = config.get_or_create_plugin(&self.plugin_name); + let plugin = forge::get(&self.forge); for (tvr, opts) in &mut self.requests { match tvr.resolve(plugin.as_ref(), opts.clone(), latest_versions) { Ok(v) => self.versions.push(v), @@ -40,31 +41,28 @@ mod tests { #[test] fn test_tool_version_list() { - let config = Config::default(); - let plugin_name = "tiny".to_string(); - config.get_or_create_plugin(&plugin_name); - let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); + let fa: ForgeArg = "tiny".parse().unwrap(); + let mut tvl = ToolVersionList::new(fa.clone(), ToolSource::Argument); tvl.requests.push(( - ToolVersionRequest::new(plugin_name, "latest"), + ToolVersionRequest::new(fa, "latest"), ToolVersionOptions::default(), )); - tvl.resolve(&config, true); + tvl.resolve(true); assert_eq!(tvl.versions.len(), 1); } #[test] fn test_tool_version_list_failure() { + forge::reset(); env::set_var("MISE_FAILURE", "1"); file::remove_all(dirs::CACHE.join("dummy")).unwrap(); - let config = Config::default(); - let plugin_name = "dummy".to_string(); - config.get_or_create_plugin(&plugin_name); - let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); + let fa: ForgeArg = "dummy".parse().unwrap(); + let mut tvl = ToolVersionList::new(fa.clone(), ToolSource::Argument); tvl.requests.push(( - ToolVersionRequest::new(plugin_name, "latest"), + ToolVersionRequest::new(fa, "latest"), ToolVersionOptions::default(), )); - tvl.resolve(&config, true); + tvl.resolve(true); assert_eq!(tvl.versions.len(), 0); env::remove_var("MISE_FAILURE"); } diff --git a/src/toolset/tool_version_request.rs b/src/toolset/tool_version_request.rs index 7c82ceb50..b9f8ddbd6 100644 --- a/src/toolset/tool_version_request.rs +++ b/src/toolset/tool_version_request.rs @@ -3,60 +3,60 @@ use std::path::PathBuf; use eyre::Result; +use crate::cli::args::ForgeArg; use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolVersionOptions}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum ToolVersionRequest { - Version(String, String), - Prefix(String, String), - Ref(String, String), - Path(String, PathBuf), + Version(ForgeArg, String), + Prefix(ForgeArg, String), + Ref(ForgeArg, String), + Path(ForgeArg, PathBuf), Sub { - plugin_name: String, + forge: ForgeArg, sub: String, orig_version: String, }, - System(String), + System(ForgeArg), } impl ToolVersionRequest { - pub fn new(plugin_name: String, s: &str) -> Self { + pub fn new(forge: ForgeArg, s: &str) -> Self { let s = match s.split_once('-') { Some(("ref", r)) => format!("ref:{}", r), _ => s.to_string(), }; match s.split_once(':') { - Some(("ref", r)) => Self::Ref(plugin_name, r.to_string()), - Some(("prefix", p)) => Self::Prefix(plugin_name, p.to_string()), - Some(("path", p)) => Self::Path(plugin_name, PathBuf::from(p)), + Some(("ref", r)) => Self::Ref(forge, r.to_string()), + Some(("prefix", p)) => Self::Prefix(forge, p.to_string()), + Some(("path", p)) => Self::Path(forge, PathBuf::from(p)), Some((p, v)) if p.starts_with("sub-") => Self::Sub { - plugin_name, + forge, sub: p.split_once('-').unwrap().1.to_string(), orig_version: v.to_string(), }, None => { if s == "system" { - Self::System(plugin_name) + Self::System(forge) } else { - Self::Version(plugin_name, s.to_string()) + Self::Version(forge, s.to_string()) } } _ => panic!("invalid tool version request: {s}"), } } - pub fn plugin_name(&self) -> &String { + pub fn forge(&self) -> &ForgeArg { match self { - Self::Version(p, _) => p, - Self::Prefix(p, _) => p, - Self::Ref(p, _) => p, - Self::Path(p, _) => p, - Self::Sub { plugin_name, .. } => plugin_name, - Self::System(p) => p, + Self::Version(f, _) + | Self::Prefix(f, _) + | Self::Ref(f, _) + | Self::Path(f, _) + | Self::Sub { forge: f, .. } + | Self::System(f) => f, } } - pub fn version(&self) -> String { match self { Self::Version(_, v) => v.clone(), @@ -82,6 +82,6 @@ impl ToolVersionRequest { impl Display for ToolVersionRequest { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{}@{}", self.plugin_name(), self.version()) + write!(f, "{}@{}", &self.forge(), self.version()) } } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index fa38ef255..e2aebebf5 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -1,9 +1,10 @@ -use crate::config::Config; -use crate::ui; -use crate::ui::style; +use std::time::Duration; + use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; -use std::time::Duration; + +use crate::ui::style; +use crate::{forge, ui}; pub trait SingleReport: Send + Sync { fn println(&self, _message: String) {} @@ -30,8 +31,7 @@ pub struct ProgressReport { } static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { - Config::get() - .list_plugins() + forge::list() .into_iter() .map(|p| p.name().len() + 10) .max() @@ -43,10 +43,12 @@ static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { fn pad_prefix(w: usize, s: &str) -> String { console::pad_str(s, w, console::Alignment::Left, None).to_string() } + fn normal_prefix(pad: usize, prefix: &str) -> String { let prefix = format!("{} {prefix}", style::edim("mise")); pad_prefix(pad, &prefix) } + fn success_prefix(pad: usize, prefix: &str) -> String { let prefix = format!("{} {prefix}", style::egreen("mise")); pad_prefix(pad, &prefix) From 5e368289e5a80913aa000564bb500e69d6b3008f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 04:53:57 -0600 Subject: [PATCH 1612/1891] refactor: clean up arg imports (#1451) --- .mise.toml | 1 + e2e/test_cargo | 21 ++++++ schema/mise.json | 5 ++ src/cli/args/forge_arg.rs | 56 +++++++++------- src/cli/current.rs | 8 +-- src/cli/doctor.rs | 8 +-- src/cli/external.rs | 2 +- src/cli/link.rs | 4 +- src/cli/ls.rs | 12 ++-- src/cli/ls_remote.rs | 2 +- src/cli/outdated.rs | 5 +- src/cli/plugins/install.rs | 2 +- src/cli/plugins/ls.rs | 2 +- src/cli/plugins/ls_remote.rs | 2 +- src/cli/plugins/uninstall.rs | 4 +- src/cli/plugins/update.rs | 2 +- src/cli/settings/ls.rs | 1 + src/cli/settings/set.rs | 1 + src/cli/settings/unset.rs | 1 + src/cli/shell.rs | 4 +- src/cli/uninstall.rs | 2 +- src/cli/upgrade.rs | 2 +- src/config/config_file/legacy_version.rs | 2 +- src/config/mod.rs | 8 +-- src/config/settings.rs | 3 + src/file.rs | 4 +- src/forge/cargo.rs | 85 +++++++++++++++++++++--- src/forge/mod.rs | 56 +++++++++------- src/plugins/core/bun.rs | 5 +- src/plugins/core/deno.rs | 5 +- src/plugins/core/erlang.rs | 6 +- src/plugins/core/go.rs | 6 +- src/plugins/core/java.rs | 5 +- src/plugins/core/mod.rs | 5 +- src/plugins/core/node.rs | 5 +- src/plugins/core/python.rs | 5 +- src/plugins/core/ruby.rs | 6 +- src/plugins/external_plugin.rs | 9 ++- src/runtime_symlinks.rs | 20 +++--- src/shims.rs | 2 +- src/toolset/mod.rs | 12 ++-- src/toolset/tool_version.rs | 26 ++++---- src/ui/progress_report.rs | 2 +- 43 files changed, 272 insertions(+), 152 deletions(-) create mode 100755 e2e/test_cargo diff --git a/.mise.toml b/.mise.toml index 1b35c9f3c..a9d5f7240 100644 --- a/.mise.toml +++ b/.mise.toml @@ -9,6 +9,7 @@ THIS_PROJECT = "{{config_root}}-{{cwd}}" [tools] #node = 'lts' +cargo-eza = "0.17.0" tiny = { version = "1", foo = "bar" } golang = { version = "prefix:1.20", foo = "bar" } python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } diff --git a/e2e/test_cargo b/e2e/test_cargo new file mode 100755 index 000000000..3cc5b42e5 --- /dev/null +++ b/e2e/test_cargo @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +export MISE_EXPERIMENTAL=1 +export MISE_CARGO_BINSTALL=1 + +#if [ "${TEST_ALL:-}" != 1 ]; then +#exit +#fi + +assert "mise x cargo-eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls +v0.17.0 [+git] +https://github.com/eza-community/eza" + +export MISE_CARGO_BINSTALL=0 +mise rm cargo-eza@0.17.0 +assert "mise x cargo-eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls +v0.17.0 [+git] +https://github.com/eza-community/eza" diff --git a/schema/mise.json b/schema/mise.json index ee961b039..aeb3eabb8 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -241,6 +241,11 @@ "description": "set to true to ensure .tool-versions will be compatible with asdf", "type": "boolean" }, + "cargo_binstall": { + "description": "use cargo-binstall to install rust tools if available", + "type": "boolean", + "default": true + }, "color": { "description": "colorize output", "type": "boolean", diff --git a/src/cli/args/forge_arg.rs b/src/cli/args/forge_arg.rs index 321b04b21..28ea39ef7 100644 --- a/src/cli/args/forge_arg.rs +++ b/src/cli/args/forge_arg.rs @@ -2,12 +2,12 @@ use std::fmt::{Debug, Display}; use std::hash::Hash; use std::str::FromStr; -use crate::forge; use crate::forge::unalias_forge; -use crate::forge::{AForge, ForgeType}; +use crate::forge::ForgeType; -#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, PartialOrd, Ord)] pub struct ForgeArg { + pub id: String, pub name: String, pub forge_type: ForgeType, } @@ -16,42 +16,52 @@ impl FromStr for ForgeArg { type Err = eyre::Error; fn from_str(s: &str) -> Result { - let (forge_type, name) = s.split_once(':').unwrap_or(("asdf", s)); - let forge_type = forge_type.parse()?; - Ok(Self::new(forge_type, name)) + if let Some((forge_type, name)) = s.split_once('-') { + if let Ok(forge_type) = forge_type.parse() { + return Ok(Self::new(forge_type, name)); + } + } + Ok(Self::new(ForgeType::Asdf, s)) } } impl ForgeArg { pub fn new(forge_type: ForgeType, name: &str) -> Self { let name = unalias_forge(name).to_string(); - Self { name, forge_type } - } - pub fn get_forge(&self) -> AForge { - forge::get(self) - } - pub fn pathname(&self) -> String { - match self.forge_type { - ForgeType::Asdf => self.name.to_string(), - forge_type => format!("{}-{}", forge_type.as_ref(), self.name), + let id = match forge_type { + ForgeType::Asdf => name.clone(), + forge_type => format!("{}-{}", forge_type.as_ref(), name), + }; + Self { + name, + forge_type, + id, } } } impl Display for ForgeArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.forge_type { - ForgeType::Asdf => write!(f, "{}", self.name), - ft => write!(f, "{}:{}", ft.as_ref(), self.name), - } + write!(f, "{}", self.id) } } impl Debug for ForgeArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.forge_type { - ForgeType::Asdf => write!(f, r#"ForgeArg("{}")"#, self.name), - ft => write!(f, r#"ForgeArg("{}:{}")"#, ft.as_ref(), self.name), - } + write!(f, r#"ForgeArg("{}")"#, self.id) + } +} + +impl PartialEq for ForgeArg { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for ForgeArg {} + +impl Hash for ForgeArg { + fn hash(&self, state: &mut H) { + self.id.hash(state); } } diff --git a/src/cli/current.rs b/src/cli/current.rs index 0c1b77520..0b572dc89 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -38,13 +38,13 @@ impl Current { fn one(&self, ts: Toolset, tool: &dyn Forge) -> Result<()> { if !tool.is_installed() { - warn!("Plugin {} is not installed", tool.name()); + warn!("Plugin {} is not installed", tool.id()); return Ok(()); } match ts .list_versions_by_plugin() .into_iter() - .find(|(p, _)| p.name() == tool.name()) + .find(|(p, _)| p.id() == tool.id()) { Some((_, versions)) => { miseprintln!( @@ -59,7 +59,7 @@ impl Current { None => { warn!( "Plugin {} does not have a version set", - style(tool.name()).blue().for_stderr() + style(tool.id()).blue().for_stderr() ); } }; @@ -82,7 +82,7 @@ impl Current { } miseprintln!( "{} {}", - &plugin.name(), + &plugin.id(), versions .iter() .map(|v| v.version.to_string()) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 431e17c02..9a5487f02 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -49,7 +49,7 @@ impl Doctor { miseprintln!("{}", render_plugins()); for plugin in forge::list() { if !plugin.is_installed() { - checks.push(format!("plugin {} is not installed", &plugin.name())); + checks.push(format!("plugin {} is not installed", &plugin.id())); continue; } } @@ -136,12 +136,12 @@ fn render_plugins() -> String { .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; + let max_plugin_name_len = plugins.iter().map(|p| p.id().len()).max().unwrap_or(0) + 2; for p in plugins { - let padded_name = pad_str(p.name(), max_plugin_name_len, Alignment::Left, None); + let padded_name = pad_str(p.id(), max_plugin_name_len, Alignment::Left, None); let si = match p.get_plugin_type() { PluginType::External => { - let git = Git::new(dirs::PLUGINS.join(p.name())); + let git = Git::new(dirs::PLUGINS.join(p.id())); match git.get_remote_url() { Some(url) => { let sha = git diff --git a/src/cli/external.rs b/src/cli/external.rs index b9e2cc645..b74027ea5 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -10,7 +10,7 @@ pub fn commands() -> Vec { .into_par_iter() .flat_map(|p| { p.external_commands().unwrap_or_else(|e| { - let p = p.name(); + let p = p.id(); warn!("failed to load external commands for plugin {p}: {e:#}"); vec![] }) diff --git a/src/cli/link.rs b/src/cli/link.rs index b2f7ae65a..0e8f54d4e 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -45,9 +45,7 @@ impl Link { style(path.to_string_lossy()).cyan().for_stderr() ); } - let target = dirs::INSTALLS - .join(self.tool.forge.pathname()) - .join(version); + let target = dirs::INSTALLS.join(&self.tool.forge.id).join(version); if target.exists() { if self.force { remove_all(&target)?; diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 40ded9f13..f5a53d379 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -113,7 +113,7 @@ impl Ls { // only runtimes for 1 plugin let runtimes: Vec = runtimes .into_iter() - .filter(|(p, _, _)| plugins.contains(&p.get_fa())) + .filter(|(p, _, _)| plugins.contains(p.fa())) .map(|row| row.into()) .collect(); miseprintln!("{}", serde_json::to_string_pretty(&runtimes)?); @@ -123,7 +123,7 @@ impl Ls { let mut plugins = JSONOutput::new(); for (plugin_name, runtimes) in &runtimes .into_iter() - .group_by(|(p, _, _)| p.name().to_string()) + .group_by(|(p, _, _)| p.id().to_string()) { let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); @@ -177,13 +177,13 @@ impl Ls { let mut versions: HashMap<(String, String), (Arc, ToolVersion)> = ts .list_installed_versions()? .into_iter() - .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) + .map(|(p, tv)| ((p.id().into(), tv.version.clone()), (p, tv))) .collect(); let active = ts .list_current_versions() .into_iter() - .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p, tv))) + .map(|(p, tv)| ((p.id().into(), tv.version.clone()), (p, tv))) .collect::, ToolVersion)>>(); versions.extend(active.clone()); @@ -191,7 +191,7 @@ impl Ls { let rvs: Vec = versions .into_iter() .filter(|(_, (f, _))| match &self.plugin { - Some(p) => p.contains(&f.get_fa()), + Some(p) => p.contains(f.fa()), None => true, }) .sorted_by_cached_key(|((plugin_name, version), _)| { @@ -211,7 +211,7 @@ impl Ls { // if it isn't installed and it's not specified, don't show it .filter(|(p, tv, source)| source.is_some() || p.is_version_installed(tv)) .filter(|(p, _, _)| match &self.plugin { - Some(forge) => forge.contains(&p.get_fa()), + Some(forge) => forge.contains(p.fa()), None => true, }) .collect(); diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 6023d43dc..91ccee760 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -74,7 +74,7 @@ impl LsRemote { }) .collect::>>()? .into_iter() - .sorted_by_cached_key(|(p, _)| p.name().to_string()) + .sorted_by_cached_key(|(p, _)| p.id().to_string()) .collect::>(); for (plugin, versions) in versions { for v in versions { diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 03c8ad9fc..79be8db5b 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -43,10 +43,7 @@ impl Outdated { fn display(&self, outdated: OutputVec) { // TODO: make a generic table printer in src/ui/table - let plugins = outdated - .iter() - .map(|(t, _, _)| t.name()) - .collect::>(); + let plugins = outdated.iter().map(|(t, _, _)| t.id()).collect::>(); let requests = outdated .iter() .map(|(_, tv, _)| tv.request.version()) diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 61abc5043..5ac65e677 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -59,7 +59,7 @@ impl PluginsInstall { if git_url.is_some() { self.install_one(name, git_url, &mpr)?; } else { - let is_core = CORE_PLUGINS.iter().any(|p| p.name() == name); + let is_core = CORE_PLUGINS.iter().any(|p| p.id() == name); if is_core { let name = style::eblue(name); bail!("{name} is a core plugin and does not need to be installed"); diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 5630704c4..bad8eb028 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -67,7 +67,7 @@ impl PluginsLs { .into_par_iter() .map(|p| { let mut row = Row { - plugin: p.name().to_string(), + plugin: p.id().to_string(), url: p.get_remote_url().unwrap_or_default(), ref_: String::new(), sha: String::new(), diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 8ffe63a90..0fed29903 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -27,7 +27,7 @@ impl PluginsLsRemote { let installed_plugins = plugins::list() .into_iter() .filter(|p| p.is_installed()) - .map(|p| p.name().to_string()) + .map(|p| p.id().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 547c0f066..f3f3bf1d7 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -29,7 +29,7 @@ impl PluginsUninstall { let plugins = match self.all { true => plugins::list() .into_iter() - .map(|p| p.name().to_string()) + .map(|p| p.id().to_string()) .collect(), false => self.plugin.clone(), }; @@ -44,7 +44,7 @@ impl PluginsUninstall { fn uninstall_one(&self, plugin_name: &str, mpr: &MultiProgressReport) -> Result<()> { match plugins::get(plugin_name) { plugin if plugin.is_installed() => { - let prefix = format!("plugin:{}", style::eblue(&plugin.name())); + let prefix = format!("plugin:{}", style::eblue(&plugin.id())); let pr = mpr.add(&prefix); plugin.uninstall(pr.as_ref())?; if self.purge { diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 8ea7db36c..9fa6c6511 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -50,7 +50,7 @@ impl Update { .build()? .install(|| { plugins.into_par_iter().for_each(|(plugin, ref_)| { - let prefix = format!("plugin:{}", style(plugin.name()).blue().for_stderr()); + let prefix = format!("plugin:{}", style(plugin.id()).blue().for_stderr()); let pr = mpr.add(&prefix); plugin.update(pr.as_ref(), ref_).unwrap(); }); diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 3bbb7e9f2..d324f7651 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -50,6 +50,7 @@ mod tests { always_keep_download = true always_keep_install = true asdf_compat = false + cargo_binstall = true color = true disable_default_shorthands = false disable_tools = [] diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index d134dc731..5f0999c44 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -101,6 +101,7 @@ pub mod tests { always_keep_download = false always_keep_install = false asdf_compat = false + cargo_binstall = true color = true disable_default_shorthands = false disable_tools = [] diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index b6359c1b3..7b253595b 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -45,6 +45,7 @@ mod tests { always_keep_download = true always_keep_install = true asdf_compat = false + cargo_binstall = true color = true disable_default_shorthands = false disable_tools = [] diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 0a5451541..1e77175f6 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -51,9 +51,9 @@ impl Shell { let shell = get_shell(None).expect("no shell detected"); for (p, tv) in ts.list_current_installed_versions() { - let source = &ts.versions.get(&p.get_fa()).unwrap().source; + let source = &ts.versions.get(p.fa()).unwrap().source; if matches!(source, ToolSource::Argument) { - let k = format!("MISE_{}_VERSION", p.name().to_uppercase()); + let k = format!("MISE_{}_VERSION", p.id().to_uppercase()); let op = if self.unset { shell.unset_env(&k) } else { diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 8de314300..3f77cb068 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -99,7 +99,7 @@ impl Uninstall { let mut tvs = matches .into_iter() .map(|v| { - let tvr = ToolVersionRequest::new(tool.get_fa(), v); + let tvr = ToolVersionRequest::new(tool.fa().clone(), v); let tv = ToolVersion::new(tool.as_ref(), tvr, Default::default(), v.into()); (tool.clone(), tv) }) diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index acc35231d..d7c8e3eb3 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -56,7 +56,7 @@ impl Upgrade { .iter() .map(|t| t.forge.clone()) .collect::>(); - outdated.retain(|(p, _, _)| tool_set.is_empty() || tool_set.contains(&p.get_fa())); + outdated.retain(|(p, _, _)| tool_set.is_empty() || tool_set.contains(p.fa())); } if outdated.is_empty() { info!("All tools are up to date"); diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index c54d69d5d..40d27d370 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -22,7 +22,7 @@ impl LegacyVersionFile { let version = plugin.parse_legacy_file(&path)?; for version in version.split_whitespace() { toolset.add_version( - ToolVersionRequest::new(plugin.get_fa(), version), + ToolVersionRequest::new(plugin.fa().clone(), version), Default::default(), ); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 1956f3ecd..3ed483b15 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -119,7 +119,7 @@ impl Config { } pub fn resolve_alias(&self, forge: &dyn Forge, v: &str) -> Result { - if let Some(plugin_aliases) = self.aliases.get(&forge.get_fa()) { + if let Some(plugin_aliases) = self.aliases.get(forge.fa()) { if let Some(alias) = plugin_aliases.get(v) { return Ok(alias.clone()); } @@ -139,7 +139,7 @@ impl Config { warn!("get_aliases: {err}"); BTreeMap::new() }); - (forge.get_fa(), aliases) + (forge.fa().clone(), aliases) }) .collect(); for (fa, plugin_aliases) in plugin_aliases { @@ -264,13 +264,13 @@ fn load_legacy_files(settings: &Settings) -> BTreeMap> { .filter(|tool| { !settings .legacy_version_file_disable_tools - .contains(tool.name()) + .contains(tool.id()) }) .filter_map(|tool| match tool.legacy_filenames() { Ok(filenames) => Some( filenames .iter() - .map(|f| (f.to_string(), tool.name().to_string())) + .map(|f| (f.to_string(), tool.id().to_string())) .collect_vec(), ), Err(err) => { diff --git a/src/config/settings.rs b/src/config/settings.rs index bc70b92c6..1be1c661b 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -28,6 +28,9 @@ pub struct Settings { pub always_keep_install: bool, #[config(env = "MISE_ASDF_COMPAT", default = false)] pub asdf_compat: bool, + /// use cargo-binstall instead of cargo install if available + #[config(env = "MISE_CARGO_BINSTALL", default = true)] + pub cargo_binstall: bool, #[config(env = "MISE_COLOR", default = true)] pub color: bool, #[config(env = "MISE_DISABLE_DEFAULT_SHORTHANDS", default = false)] diff --git a/src/file.rs b/src/file.rs index 4e4e48e2c..184d24bd1 100644 --- a/src/file.rs +++ b/src/file.rs @@ -269,9 +269,9 @@ impl Iterator for FindUp { } } -pub fn which(name: &str) -> Option { +pub fn which>(name: P) -> Option { for path in &*env::PATH { - let bin = path.join(name); + let bin = path.join(name.as_ref()); if is_executable(&bin) { return Some(bin); } diff --git a/src/forge/cargo.rs b/src/forge/cargo.rs index 9d5fa9aad..a10aba414 100644 --- a/src/forge/cargo.rs +++ b/src/forge/cargo.rs @@ -1,28 +1,93 @@ -use crate::forge::Forge; -use crate::install_context::InstallContext; use std::fmt::Debug; +use serde_json::Deserializer; +use url::Url; + +use crate::cache::CacheManager; +use crate::cli::args::ForgeArg; +use crate::cmd::CmdLineRunner; +use crate::config::Settings; +use crate::forge::{Forge, ForgeType}; +use crate::http::HTTP_FETCH; +use crate::install_context::InstallContext; +use crate::{dirs, file}; + #[derive(Debug)] pub struct CargoForge { - pub name: String, + fa: ForgeArg, + remote_version_cache: CacheManager>, } impl Forge for CargoForge { - fn name(&self) -> &str { - &self.name + fn get_type(&self) -> ForgeType { + ForgeType::Cargo + } + + fn fa(&self) -> &ForgeArg { + &self.fa } fn list_remote_versions(&self) -> eyre::Result> { - todo!() + self.remote_version_cache + .get_or_try_init(|| { + let raw = HTTP_FETCH.get_text(get_crate_url(self.name())?)?; + let stream = Deserializer::from_str(&raw).into_iter::(); + let mut versions = vec![]; + for v in stream { + let v = v?; + if !v.yanked { + versions.push(v.vers); + } + } + Ok(versions) + }) + .cloned() } - fn install_version_impl(&self, _ctx: &InstallContext) -> eyre::Result<()> { - todo!() + fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { + let settings = Settings::get(); + settings.ensure_experimental()?; + let cmd = match settings.cargo_binstall { + true if file::which("cargo-binstall").is_some() => { + CmdLineRunner::new("cargo-binstall").arg("-y") + } + _ => CmdLineRunner::new("cargo").arg("install"), + }; + + cmd.arg(&format!("{}@{}", self.name(), ctx.tv.version)) + .arg("--root") + .arg(ctx.tv.install_path()) + .with_pr(ctx.pr.as_ref()) + .execute()?; + + Ok(()) } } impl CargoForge { - pub fn new(name: String) -> Self { - Self { name } + pub fn new(fa: ForgeArg) -> Self { + let cache_dir = dirs::CACHE.join(&fa.id); + Self { + fa, + remote_version_cache: CacheManager::new(cache_dir.join("remote_versions.msgpack.z")), + } } } + +fn get_crate_url(n: &str) -> eyre::Result { + let n = n.to_lowercase(); + let url = match n.len() { + 1 => format!("https://index.crates.io/1/{n}"), + 2 => format!("https://index.crates.io/2/{n}"), + 3 => format!("https://index.crates.io/3/{}/{n}", &n[..1]), + _ => format!("https://index.crates.io/{}/{}/{n}", &n[..2], &n[2..4]), + }; + Ok(url.parse()?) +} + +#[derive(Debug, serde::Deserialize)] +struct CrateVersion { + //name: String, + vers: String, + yanked: bool, +} diff --git a/src/forge/mod.rs b/src/forge/mod.rs index 787308457..7cb610329 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -49,10 +49,10 @@ fn load_forges() -> ForgeMap { let mut plugins = CORE_PLUGINS.clone(); plugins.extend(ExternalPlugin::list().expect("failed to list plugins")); let settings = Settings::get(); - plugins.retain(|plugin| !settings.disable_tools.contains(plugin.name())); + plugins.retain(|plugin| !settings.disable_tools.contains(plugin.id())); let plugins: ForgeMap = plugins .into_iter() - .map(|plugin| (plugin.get_fa(), plugin)) + .map(|plugin| (plugin.fa().clone(), plugin)) .collect(); *forges = Some(plugins.clone()); plugins @@ -62,11 +62,6 @@ pub fn list() -> ForgeList { load_forges().values().cloned().collect() } -#[cfg(test)] -pub fn reset() { - *FORGES.lock().unwrap() = None; -} - pub fn get(fa: &ForgeArg) -> AForge { if let Some(forge) = load_forges().get(fa) { forge.clone() @@ -78,43 +73,47 @@ pub fn get(fa: &ForgeArg) -> AForge { .entry(fa.clone()) .or_insert_with(|| match fa.forge_type { ForgeType::Asdf => Arc::new(ExternalPlugin::new(name)), - ForgeType::Cargo => Arc::new(CargoForge::new(name)), + ForgeType::Cargo => Arc::new(CargoForge::new(fa.clone())), }) .clone() } } pub trait Forge: Debug + Send + Sync { - fn name(&self) -> &str; + fn id(&self) -> &str { + &self.fa().id + } + fn name(&self) -> &str { + &self.fa().name + } fn get_type(&self) -> ForgeType { ForgeType::Asdf } - fn get_fa(&self) -> ForgeArg { - ForgeArg::new(self.get_type(), self.name()) - } + fn fa(&self) -> &ForgeArg; fn get_plugin_type(&self) -> PluginType { PluginType::Core } fn installs_path(&self) -> PathBuf { - dirs::INSTALLS.join(self.name()) + dirs::INSTALLS.join(self.id()) } fn cache_path(&self) -> PathBuf { - dirs::CACHE.join(self.name()) + dirs::CACHE.join(self.id()) } fn downloads_path(&self) -> PathBuf { - dirs::DOWNLOADS.join(self.name()) + dirs::DOWNLOADS.join(self.id()) } fn list_remote_versions(&self) -> eyre::Result>; fn latest_stable_version(&self) -> eyre::Result> { self.latest_version(Some("latest".into())) } fn list_installed_versions(&self) -> eyre::Result> { - Ok(match self.installs_path().exists() { - true => file::dir_subdirs(&self.installs_path())? + let installs_path = self.installs_path(); + Ok(match installs_path.exists() { + true => file::dir_subdirs(&installs_path)? .into_iter() .filter(|v| !v.starts_with('.')) - .filter(|v| !is_runtime_symlink(&self.installs_path().join(v))) - .filter(|v| !self.installs_path().join(v).join("incomplete").exists()) + .filter(|v| !is_runtime_symlink(&installs_path.join(v))) + .filter(|v| !installs_path.join(v).join("incomplete").exists()) .sorted_by_cached_key(|v| (Versioning::new(v), v.to_string())) .collect(), false => vec![], @@ -134,7 +133,11 @@ pub trait Forge: Debug + Send + Sync { let latest = match tv.latest_version(p) { Ok(latest) => latest, Err(e) => { - debug!("Error getting latest version for {}: {:#}", self.name(), e); + debug!( + "Error getting latest version for {}: {:#}", + self.fa().to_string(), + e + ); return false; } }; @@ -420,7 +423,7 @@ pub fn unalias_forge(forge: &str) -> &str { impl Display for dyn Forge { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name()) + write!(f, "{}", self.id()) } } @@ -428,13 +431,13 @@ impl Eq for dyn Forge {} impl PartialEq for dyn Forge { fn eq(&self, other: &Self) -> bool { - self.get_plugin_type() == other.get_plugin_type() && self.name() == other.name() + self.get_plugin_type() == other.get_plugin_type() && self.id() == other.id() } } impl Hash for dyn Forge { fn hash(&self, state: &mut H) { - self.name().hash(state) + self.id().hash(state) } } @@ -446,6 +449,11 @@ impl PartialOrd for dyn Forge { impl Ord for dyn Forge { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.name().cmp(other.name()) + self.id().cmp(other.id()) } } + +#[cfg(test)] +pub fn reset() { + *FORGES.lock().unwrap() = None; +} diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 0c471f269..1889637a8 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -1,5 +1,6 @@ use std::path::{Path, PathBuf}; +use crate::cli::args::ForgeArg; use eyre::Result; use itertools::Itertools; use versions::Versioning; @@ -95,8 +96,8 @@ impl BunPlugin { } impl Forge for BunPlugin { - fn name(&self) -> &str { - "bun" + fn fa(&self) -> &ForgeArg { + &self.core.fa } fn list_remote_versions(&self) -> Result> { diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 3be330193..350820a8c 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use crate::cli::args::ForgeArg; use eyre::Result; use itertools::Itertools; use versions::Versioning; @@ -94,8 +95,8 @@ impl DenoPlugin { } impl Forge for DenoPlugin { - fn name(&self) -> &str { - "deno" + fn fa(&self) -> &ForgeArg { + &self.core.fa } fn list_remote_versions(&self) -> Result> { diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 857efe1c7..3d54293ba 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -2,6 +2,7 @@ use std::path::PathBuf; use eyre::Result; +use crate::cli::args::ForgeArg; use crate::file::display_path; use crate::forge::Forge; use crate::http::HTTP_FETCH; @@ -88,10 +89,9 @@ impl ErlangPlugin { } impl Forge for ErlangPlugin { - fn name(&self) -> &str { - self.core.name + fn fa(&self) -> &ForgeArg { + &self.core.fa } - fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index d843924e8..d174287b7 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -5,6 +5,7 @@ use eyre::Result; use itertools::Itertools; use versions::Versioning; +use crate::cli::args::ForgeArg; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; @@ -135,10 +136,9 @@ impl GoPlugin { } impl Forge for GoPlugin { - fn name(&self) -> &str { - "go" + fn fa(&self) -> &ForgeArg { + &self.core.fa } - fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 6308d99db..57d89ba6f 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -10,6 +10,7 @@ use serde_derive::{Deserialize, Serialize}; use versions::Versioning; use crate::cache::CacheManager; +use crate::cli::args::ForgeArg; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; @@ -295,8 +296,8 @@ impl JavaPlugin { } impl Forge for JavaPlugin { - fn name(&self) -> &str { - "java" + fn fa(&self) -> &ForgeArg { + &self.core.fa } fn list_remote_versions(&self) -> Result> { diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 68988be65..182d1834a 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -10,8 +10,9 @@ use once_cell::sync::Lazy; pub use python::PythonPlugin; use crate::cache::CacheManager; +use crate::cli::args::ForgeArg; use crate::config::Settings; -use crate::forge::{Forge, ForgeList}; +use crate::forge::{Forge, ForgeList, ForgeType}; use crate::http::HTTP_FETCH; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; @@ -52,6 +53,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { #[derive(Debug)] pub struct CorePlugin { + pub fa: ForgeArg, pub name: &'static str, pub cache_path: PathBuf, pub remote_version_cache: CacheManager>, @@ -61,6 +63,7 @@ impl CorePlugin { pub fn new(name: &'static str) -> Self { let cache_path = dirs::CACHE.join(name); Self { + fa: ForgeArg::new(ForgeType::Asdf, name), name, remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 49441f2a9..6f9ba6460 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -7,6 +7,7 @@ use tempfile::tempdir_in; use url::Url; use crate::build_time::built_info; +use crate::cli::args::ForgeArg; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::env::MISE_NODE_MIRROR_URL; @@ -237,8 +238,8 @@ impl NodePlugin { } impl Forge for NodePlugin { - fn name(&self) -> &str { - "node" + fn fa(&self) -> &ForgeArg { + &self.core.fa } fn list_remote_versions(&self) -> Result> { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index e4cda55f1..b50e8b6de 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -6,6 +6,7 @@ use itertools::Itertools; use crate::build_time::built_info; use crate::cache::CacheManager; +use crate::cli::args::ForgeArg; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::file::display_path; @@ -293,8 +294,8 @@ impl PythonPlugin { } impl Forge for PythonPlugin { - fn name(&self) -> &str { - "python" + fn fa(&self) -> &ForgeArg { + &self.core.fa } fn list_remote_versions(&self) -> Result> { diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index c13d9fe3e..fda02312e 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -9,6 +9,7 @@ use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::duration::DAILY; +use crate::cli::args::ForgeArg; use crate::forge::Forge; use crate::git::Git; use crate::github::GithubRelease; @@ -321,10 +322,9 @@ impl RubyPlugin { } impl Forge for RubyPlugin { - fn name(&self) -> &str { - "ruby" + fn fa(&self) -> &ForgeArg { + &self.core.fa } - fn list_remote_versions(&self) -> Result> { self.core .remote_version_cache diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ad7039002..23854cb39 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -14,13 +14,14 @@ use once_cell::sync::Lazy; use rayon::prelude::*; use crate::cache::CacheManager; +use crate::cli::args::ForgeArg; use crate::config::{Config, Settings}; use crate::default_shorthands::{DEFAULT_SHORTHANDS, TRUSTED_SHORTHANDS}; use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::errors::Error::PluginNotInstalled; use crate::file::{display_path, remove_all}; -use crate::forge::{AForge, Forge, ForgeList}; +use crate::forge::{AForge, Forge, ForgeList, ForgeType}; use crate::git::Git; use crate::hash::hash_to_str; use crate::http::HTTP_FETCH; @@ -38,6 +39,7 @@ use crate::{dirs, env, file, http}; /// This represents a plugin installed to ~/.local/share/mise/plugins pub struct ExternalPlugin { + pub fa: ForgeArg, pub name: String, pub plugin_path: PathBuf, pub repo_url: Option, @@ -63,6 +65,7 @@ impl ExternalPlugin { } let toml = MisePluginToml::from_file(&toml_path).unwrap(); Self { + fa: ForgeArg::new(ForgeType::Asdf, &name), script_man: build_script_man(&name, &plugin_path), downloads_path: dirs::DOWNLOADS.join(&name), installs_path: dirs::INSTALLS.join(&name), @@ -404,8 +407,8 @@ impl Hash for ExternalPlugin { } impl Forge for ExternalPlugin { - fn name(&self) -> &str { - &self.name + fn fa(&self) -> &ForgeArg { + &self.fa } fn get_plugin_type(&self) -> PluginType { diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index a67709e7d..cc16c4ce3 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -11,12 +11,12 @@ use crate::config::Config; use crate::file::make_symlink; use crate::forge::Forge; use crate::plugins::VERSION_REGEX; -use crate::{dirs, file, forge}; +use crate::{file, forge}; pub fn rebuild(config: &Config) -> Result<()> { - for plugin in forge::list() { - let symlinks = list_symlinks(config, plugin.clone())?; - let installs_dir = dirs::INSTALLS.join(plugin.name()); + for forge in forge::list() { + let symlinks = list_symlinks(config, forge.clone())?; + let installs_dir = forge.installs_path(); for (from, to) in symlinks { let from = installs_dir.join(from); if from.exists() { @@ -29,7 +29,7 @@ pub fn rebuild(config: &Config) -> Result<()> { } make_symlink(&to, &from)?; } - remove_missing_symlinks(plugin.clone())?; + remove_missing_symlinks(forge.clone())?; // remove install dir if empty file::remove_dir(&installs_dir)?; } @@ -57,7 +57,7 @@ fn list_symlinks(config: &Config, forge: Arc) -> Result) -> Result) -> Result> { - let versions = plugin +fn installed_versions(forge: &Arc) -> Result> { + let versions = forge .list_installed_versions()? .into_iter() .filter(|v| !VERSION_REGEX.is_match(v)) @@ -85,8 +85,8 @@ fn installed_versions(plugin: &Arc) -> Result> { Ok(versions) } -fn remove_missing_symlinks(plugin: Arc) -> Result<()> { - let installs_dir = dirs::INSTALLS.join(plugin.name()); +fn remove_missing_symlinks(forge: Arc) -> Result<()> { + let installs_dir = forge.installs_path(); if !installs_dir.exists() { return Ok(()); } diff --git a/src/shims.rs b/src/shims.rs index 0565a15b3..cf6cc5c05 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -126,7 +126,7 @@ pub fn reshim(ts: &Toolset) -> Result<()> { remove_all(&symlink_path)?; } for plugin in forge::list() { - match dirs::PLUGINS.join(plugin.name()).join("shims").read_dir() { + match dirs::PLUGINS.join(plugin.id()).join("shims").read_dir() { Ok(files) => { for bin in files { let bin = bin?; diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 8bdfc2a7c..760990230 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -120,7 +120,7 @@ impl Toolset { .keys() .map(forge::get) .filter(|p| !p.is_installed()) - .map(|p| p.name().into()) + .map(|p| p.id().into()) .collect() } @@ -139,7 +139,7 @@ impl Toolset { .into_iter() .group_by(|v| v.forge.clone()) .into_iter() - .map(|(fa, v)| (fa.get_forge(), v.collect_vec())) + .map(|(fa, v)| (forge::get(&fa), v.collect_vec())) .collect(); for (t, _) in &queue { if !t.is_installed() { @@ -199,7 +199,7 @@ impl Toolset { let current_versions: HashMap<(String, String), (Arc, ToolVersion)> = self .list_current_versions() .into_iter() - .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p.clone(), tv))) + .map(|(p, tv)| ((p.id().into(), tv.version.clone()), (p.clone(), tv))) .collect(); let versions = forge::list() .into_par_iter() @@ -208,10 +208,10 @@ impl Toolset { Ok(versions .into_iter() .map( - |v| match current_versions.get(&(p.name().into(), v.clone())) { + |v| match current_versions.get(&(p.id().into(), v.clone())) { Some((p, tv)) => (p.clone(), tv.clone()), None => { - let tv = ToolVersionRequest::new(p.get_fa(), &v) + let tv = ToolVersionRequest::new(p.fa().clone(), &v) .resolve(p.as_ref(), Default::default(), false) .unwrap(); (p.clone(), tv) @@ -359,7 +359,7 @@ impl Toolset { let versions = self .list_missing_versions() .into_iter() - .filter(|tv| tv.forge == plugin.get_fa()) + .filter(|tv| &tv.forge == plugin.fa()) .collect_vec(); if !versions.is_empty() { let mpr = MultiProgressReport::get(); diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 11ac7341d..41fe2ba3d 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -32,7 +32,7 @@ impl ToolVersion { version: String, ) -> Self { ToolVersion { - forge: tool.get_fa(), + forge: tool.fa().clone(), version, request, opts, @@ -76,14 +76,14 @@ impl ToolVersion { ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), _ => self.tv_pathname(), }; - dirs::INSTALLS.join(self.forge.pathname()).join(pathname) + dirs::INSTALLS.join(&self.forge.id).join(pathname) } pub fn install_short_path(&self) -> PathBuf { let pathname = match &self.request { ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), _ => self.tv_short_pathname(), }; - let sp = dirs::INSTALLS.join(self.forge.pathname()).join(pathname); + let sp = dirs::INSTALLS.join(&self.forge.id).join(pathname); if sp.exists() { sp } else { @@ -91,13 +91,11 @@ impl ToolVersion { } } pub fn cache_path(&self) -> PathBuf { - dirs::CACHE - .join(self.forge.pathname()) - .join(self.tv_pathname()) + dirs::CACHE.join(&self.forge.id).join(self.tv_pathname()) } pub fn download_path(&self) -> PathBuf { dirs::DOWNLOADS - .join(self.forge.pathname()) + .join(&self.forge.id) .join(self.tv_pathname()) } pub fn latest_version(&self, tool: &dyn Forge) -> Result { @@ -107,7 +105,7 @@ impl ToolVersion { pub fn style(&self) -> String { format!( "{}{}", - style(&self.forge.pathname()).blue().for_stderr(), + style(&self.forge.id).blue().for_stderr(), style(&format!("@{}", &self.version)).for_stderr() ) } @@ -224,7 +222,7 @@ impl ToolVersion { } fn resolve_ref(tool: &dyn Forge, r: String, opts: ToolVersionOptions) -> Self { - let request = ToolVersionRequest::Ref(tool.get_fa(), r); + let request = ToolVersionRequest::Ref(tool.fa().clone(), r); let version = request.version(); Self::new(tool, request, opts, version) } @@ -235,7 +233,7 @@ impl ToolVersion { opts: ToolVersionOptions, ) -> Result { let path = fs::canonicalize(path)?; - let request = ToolVersionRequest::Path(tool.get_fa(), path); + let request = ToolVersionRequest::Path(tool.fa().clone(), path); let version = request.version(); Ok(Self::new(tool, request, opts, version)) } @@ -243,13 +241,13 @@ impl ToolVersion { impl Display for ToolVersion { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{}@{}", &self.forge.pathname(), &self.version) + write!(f, "{}@{}", &self.forge.id, &self.version) } } impl PartialEq for ToolVersion { fn eq(&self, other: &Self) -> bool { - self.forge.pathname() == other.forge.pathname() && self.version == other.version + self.forge.id == other.forge.id && self.version == other.version } } impl Eq for ToolVersion {} @@ -260,7 +258,7 @@ impl PartialOrd for ToolVersion { } impl Ord for ToolVersion { fn cmp(&self, other: &Self) -> Ordering { - match self.forge.pathname().cmp(&other.forge.pathname()) { + match self.forge.id.cmp(&other.forge.id) { Ordering::Equal => self.version.cmp(&other.version), o => o, } @@ -268,7 +266,7 @@ impl Ord for ToolVersion { } impl Hash for ToolVersion { fn hash(&self, state: &mut H) { - self.forge.pathname().hash(state); + self.forge.id.hash(state); self.version.hash(state); } } diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index e2aebebf5..692d5de72 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -33,7 +33,7 @@ pub struct ProgressReport { static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { forge::list() .into_iter() - .map(|p| p.name().len() + 10) + .map(|p| p.id().len() + 10) .max() .unwrap_or_default() .max(15) From 8d678e0ffb3b21a2874d6984a8d77e3e2372b4c7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 05:01:13 -0600 Subject: [PATCH 1613/1891] added support for installing directly from npm (#1452) e.g.: `mise use -g npm-prettier@3.2.0` --- e2e/test_npm | 8 +++++++ src/forge/mod.rs | 3 +++ src/forge/npm.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100755 e2e/test_npm create mode 100644 src/forge/npm.rs diff --git a/e2e/test_npm b/e2e/test_npm new file mode 100755 index 000000000..b41414179 --- /dev/null +++ b/e2e/test_npm @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +export MISE_EXPERIMENTAL=1 + +assert "mise x npm-prettier@3.1.0 -- prettier -v" "3.1.0" diff --git a/src/forge/mod.rs b/src/forge/mod.rs index 7cb610329..a3b8a1b2b 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -27,6 +27,7 @@ use crate::ui::progress_report::SingleReport; use crate::{dirs, file}; mod cargo; +mod npm; pub type AForge = Arc; pub type ForgeMap = BTreeMap; @@ -37,6 +38,7 @@ pub type ForgeList = Vec; pub enum ForgeType { Asdf, Cargo, + Npm, } static FORGES: Mutex> = Mutex::new(None); @@ -74,6 +76,7 @@ pub fn get(fa: &ForgeArg) -> AForge { .or_insert_with(|| match fa.forge_type { ForgeType::Asdf => Arc::new(ExternalPlugin::new(name)), ForgeType::Cargo => Arc::new(CargoForge::new(fa.clone())), + ForgeType::Npm => Arc::new(npm::NPMForge::new(fa.clone())), }) .clone() } diff --git a/src/forge/npm.rs b/src/forge/npm.rs new file mode 100644 index 000000000..706467a84 --- /dev/null +++ b/src/forge/npm.rs @@ -0,0 +1,61 @@ +use std::fmt::Debug; + +use crate::cache::CacheManager; +use crate::cli::args::ForgeArg; +use crate::cmd::CmdLineRunner; +use crate::config::Settings; +use crate::dirs; +use crate::forge::{Forge, ForgeType}; +use crate::install_context::InstallContext; + +#[derive(Debug)] +pub struct NPMForge { + fa: ForgeArg, + remote_version_cache: CacheManager>, +} + +impl Forge for NPMForge { + fn get_type(&self) -> ForgeType { + ForgeType::Npm + } + + fn fa(&self) -> &ForgeArg { + &self.fa + } + + fn list_remote_versions(&self) -> eyre::Result> { + self.remote_version_cache + .get_or_try_init(|| { + let raw = cmd!("npm", "view", self.name(), "versions", "--json").read()?; + let versions: Vec = serde_json::from_str(&raw)?; + Ok(versions) + }) + .cloned() + } + + fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { + let settings = Settings::get(); + settings.ensure_experimental()?; + + CmdLineRunner::new("npm") + .arg("install") + .arg("-g") + .arg(&format!("{}@{}", self.name(), ctx.tv.version)) + .arg("--prefix") + .arg(ctx.tv.install_path()) + .with_pr(ctx.pr.as_ref()) + .execute()?; + + Ok(()) + } +} + +impl NPMForge { + pub fn new(fa: ForgeArg) -> Self { + let cache_dir = dirs::CACHE.join(&fa.id); + Self { + fa, + remote_version_cache: CacheManager::new(cache_dir.join("remote_versions.msgpack.z")), + } + } +} From d1e6e4b951637762d3562a89996a2bb3422c3341 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 05:14:14 -0600 Subject: [PATCH 1614/1891] document npm/cargo --- docs/cli-reference.md | 2 +- man/man1/mise.1 | 24 ++++++++++++++++++++---- src/cli/mod.rs | 24 ++++++++++++++++++++---- src/cli/use.rs | 2 +- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 6614a8d97..6ae7c57d5 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -1444,7 +1444,7 @@ Usage: use [OPTIONS] [TOOL@VERSION]... Arguments: [TOOL@VERSION]... Tool(s) to add to config file - e.g.: node@20 + e.g.: node@20, cargo-ripgrep@latest npm-prettier@3 If no version is specified, it will default to @latest Options: diff --git a/man/man1/mise.1 b/man/man1/mise.1 index a2450e7f1..9e5c7347d 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -154,14 +154,30 @@ Print this message or the help of the given subcommand(s) .SH EXTRA Examples: $ mise install node@20.0.0 Install a specific node version - $ mise install node@20.0 Install a version matching a prefix - $ mise install node Install the node version defined in - .tool\-versions or .mise.toml + $ mise install node@20 Install a version matching a prefix + $ mise install node Install the node version defined in config + $ mise install Install all plugins/tools defined in config + + $ mise install cargo\-ripgrep Install something via cargo + $ mise install npm\-prettier Install something via npm + $ mise use node@20 Use node\-20.x in current project $ mise use \-g node@20 Use node\-20.x as default $ mise use node@latest Use latest node in current directory $ mise use \-g node@system Use system node everywhere unless overridden - $ mise x node@20 \-\- node app.js Run `node app.js` with node\-20.x on PATH + + $ mise up \-\-interactive Show a menu to upgrade tools + + $ mise x \-\- npm install `npm install` w/ config loaded into PATH + $ mise x node@20 \-\- node app.js `node app.js` w/ config + node\-20.x on PATH + + $ mise set NODE_ENV=production Set NODE_ENV=production in config + + $ mise run build Run `build` task + $ mise watch build Run `build` task repeatedly when files change + + $ mise settings Show settings in use + $ mise settings set color 0 Disable color by modifying global config file .SH VERSION v2024.1.18 .SH AUTHORS diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 85c7170ab..b77d404d9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -235,14 +235,30 @@ https://asdf-vm.com/"}; static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ mise install node@20.0.0 Install a specific node version - $ mise install node@20.0 Install a version matching a prefix - $ mise install node Install the node version defined in - .tool-versions or .mise.toml + $ mise install node@20 Install a version matching a prefix + $ mise install node Install the node version defined in config + $ mise install Install all plugins/tools defined in config + + $ mise install cargo-ripgrep Install something via cargo + $ mise install npm-prettier Install something via npm + $ mise use node@20 Use node-20.x in current project $ mise use -g node@20 Use node-20.x as default $ mise use node@latest Use latest node in current directory $ mise use -g node@system Use system node everywhere unless overridden - $ mise x node@20 -- node app.js Run `node app.js` with node-20.x on PATH + + $ mise up --interactive Show a menu to upgrade tools + + $ mise x -- npm install `npm install` w/ config loaded into PATH + $ mise x node@20 -- node app.js `node app.js` w/ config + node-20.x on PATH + + $ mise set NODE_ENV=production Set NODE_ENV=production in config + + $ mise run build Run `build` task + $ mise watch build Run `build` task repeatedly when files change + + $ mise settings Show settings in use + $ mise settings set color 0 Disable color by modifying global config file "# ); diff --git a/src/cli/use.rs b/src/cli/use.rs index 7ee318ec1..ed4c8d438 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -25,7 +25,7 @@ use crate::{env, file, forge}; #[clap(verbatim_doc_comment, visible_alias = "u", after_long_help = AFTER_LONG_HELP)] pub struct Use { /// Tool(s) to add to config file - /// e.g.: node@20 + /// e.g.: node@20, cargo-ripgrep@latest npm-prettier@3 /// If no version is specified, it will default to @latest #[clap( value_name = "TOOL@VERSION", From 2ee66cb91837fde144bf7acbb1028372c1cd7d9a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 06:36:51 -0600 Subject: [PATCH 1615/1891] npm: testing --- e2e/test_npm | 1 + src/cli/alias/get.rs | 2 +- src/cli/alias/ls.rs | 2 +- src/cli/alias/mod.rs | 3 +- src/cli/alias/unset.rs | 2 +- src/cli/args/tool_arg.rs | 43 +++++++++++++++++++++++---- src/cli/cache/mod.rs | 3 -- src/cli/config/generate.rs | 2 -- src/cli/config/ls.rs | 2 -- src/cli/direnv/exec.rs | 3 -- src/cli/env.rs | 4 +-- src/cli/exec.rs | 1 - src/cli/external.rs | 2 +- src/cli/global.rs | 2 -- src/cli/install.rs | 2 -- src/cli/latest.rs | 2 -- src/cli/local.rs | 2 -- src/cli/ls.rs | 2 -- src/cli/outdated.rs | 2 -- src/cli/plugins/ls.rs | 1 - src/cli/prune.rs | 2 +- src/cli/render_completion.rs | 3 +- src/cli/task/ls.rs | 2 -- src/cli/watch.rs | 2 +- src/cli/where.rs | 2 -- src/cmd.rs | 2 +- src/direnv.rs | 1 - src/env_diff.rs | 2 -- src/git.rs | 1 - src/hash.rs | 1 - src/hook_env.rs | 2 -- src/http.rs | 22 +++++++------- src/logger.rs | 5 ++-- src/main.rs | 3 ++ src/path_env.rs | 6 ++-- src/plugins/core/bun.rs | 2 +- src/plugins/core/deno.rs | 2 +- src/plugins/core/ruby.rs | 4 +-- src/plugins/mise_plugin_toml.rs | 1 - src/plugins/mod.rs | 2 -- src/shell/bash.rs | 6 ++-- src/shell/completions/mod.rs | 3 +- src/shell/completions/zsh_complete.rs | 3 +- src/shell/fish.rs | 6 ++-- src/shell/nushell.rs | 4 +-- src/shell/xonsh.rs | 4 +-- src/shell/zsh.rs | 6 ++-- src/shims.rs | 7 ++--- src/shorthands.rs | 1 - src/task.rs | 2 +- src/test.rs | 7 +++-- src/toolset/tool_source.rs | 2 -- src/toolset/tool_version.rs | 12 ++++---- src/ui/mod.rs | 6 ++-- src/ui/multi_progress_report.rs | 5 ++-- src/ui/prompt.rs | 6 ++-- src/ui/style.rs | 16 ++++++++-- 57 files changed, 127 insertions(+), 119 deletions(-) diff --git a/e2e/test_npm b/e2e/test_npm index b41414179..eefc77060 100755 --- a/e2e/test_npm +++ b/e2e/test_npm @@ -6,3 +6,4 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 assert "mise x npm-prettier@3.1.0 -- prettier -v" "3.1.0" +assert "mise x npm-@antfu/ni@0.21.12 -- ni -v 2>/dev/null | head -n1" "@antfu/ni v0.21.12" diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 9e917c2d1..92ddf5136 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -1,6 +1,6 @@ -use crate::cli::args::ForgeArg; use color_eyre::eyre::{eyre, Result}; +use crate::cli::args::ForgeArg; use crate::config::Config; /// Show an alias for a plugin diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index 91b41623d..fa1e4eba5 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -1,7 +1,7 @@ -use crate::cli::args::ForgeArg; use eyre::Result; use tabled::Tabled; +use crate::cli::args::ForgeArg; use crate::config::Config; use crate::ui::table; diff --git a/src/cli/alias/mod.rs b/src/cli/alias/mod.rs index 3fad4056f..5b942f185 100644 --- a/src/cli/alias/mod.rs +++ b/src/cli/alias/mod.rs @@ -1,7 +1,8 @@ -use crate::cli::args::ForgeArg; use clap::Subcommand; use eyre::Result; +use crate::cli::args::ForgeArg; + mod get; mod ls; mod set; diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 65be609e5..709a8552d 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -1,6 +1,6 @@ -use crate::cli::args::ForgeArg; use eyre::Result; +use crate::cli::args::ForgeArg; use crate::config::config_file::ConfigFile; use crate::config::Config; diff --git a/src/cli/args/tool_arg.rs b/src/cli/args/tool_arg.rs index 02f3ca6d9..bfc6a4f52 100644 --- a/src/cli/args/tool_arg.rs +++ b/src/cli/args/tool_arg.rs @@ -31,10 +31,8 @@ impl FromStr for ToolArg { type Err = eyre::Error; fn from_str(input: &str) -> eyre::Result { - let (forge_input, version) = input - .split_once('@') - .map(|(f, v)| (f, Some(v.to_string()))) - .unwrap_or((input, None)); + let (forge_input, version) = parse_input(input); + let forge: ForgeArg = forge_input.parse()?; let version_type = match version.as_ref() { Some(version) => version.parse()?, @@ -45,7 +43,7 @@ impl FromStr for ToolArg { .map(|v| ToolVersionRequest::new(forge.clone(), v)); Ok(Self { tvr, - version, + version: version.map(|v| v.to_string()), version_type, forge, }) @@ -128,6 +126,26 @@ impl Display for ToolArg { } } +fn parse_input(s: &str) -> (&str, Option<&str>) { + let (forge, version) = s + .split_once('@') + .map(|(f, v)| (f, Some(v))) + .unwrap_or((s, None)); + + // special case for packages with npm scopes like "npm-@antfu/ni" + if forge == "npm-" { + if let Some(v) = version { + return if let Some(i) = v.find('@') { + (&s[..forge.len() + i + 1], Some(&v[i + 1..])) + } else { + (&s[..forge.len() + v.len() + 1], None) + }; + } + } + + (forge, version) +} + #[cfg(test)] mod tests { use super::*; @@ -173,4 +191,19 @@ mod tests { } ); } + + #[test] + fn test_tool_arg_parse_input() { + let t = |input, f, v| { + let (forge, version) = parse_input(input); + assert_eq!(forge, f); + assert_eq!(version, v); + }; + t("npm-@antfu/ni", "npm-@antfu/ni", None); + t("npm-@antfu/ni@1.0.0", "npm-@antfu/ni", Some("1.0.0")); + t("npm-@antfu/ni@1.0.0@1", "npm-@antfu/ni", Some("1.0.0@1")); + t("npm-", "npm-", None); + t("npm-prettier", "npm-prettier", None); + t("npm-prettier@1.0.0", "npm-prettier", Some("1.0.0")); + } } diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 7968c7683..84d3ce723 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -43,10 +43,7 @@ impl Cache { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::env; - #[test] fn test_cache() { let stdout = assert_cli!("cache"); diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index 35bc99247..bd0b34135 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -94,8 +94,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use std::env; - #[test] fn test_generate() { with_settings!({ diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index 0bef0b6c5..39f887c87 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -71,8 +71,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use std::env; - #[test] fn test_config_ls() { assert_cli_snapshot!("cfg", "--no-headers", @r###" diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 8fe3d5535..bd1c47ff5 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -51,10 +51,7 @@ fn env_cmd() -> Expression { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::cli::tests::grep; - #[test] fn test_direnv_exec() { let stdout = assert_cli!("direnv", "exec"); diff --git a/src/cli/env.rs b/src/cli/env.rs index d0ee0c54d..71294d8ab 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -68,11 +68,9 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { + use crate::cli::tests::grep; use std::env; - use pretty_assertions::assert_str_eq; - - use crate::cli::tests::grep; use crate::dirs; #[test] diff --git a/src/cli/exec.rs b/src/cli/exec.rs index a110bd00f..ac36f78b1 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -10,7 +10,6 @@ use crate::cli::args::ToolArg; use crate::cmd; use crate::config::Config; use crate::env; - use crate::toolset::{InstallOptions, ToolsetBuilder}; /// Execute a command with tool(s) set diff --git a/src/cli/external.rs b/src/cli/external.rs index b74027ea5..edf4036de 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -1,8 +1,8 @@ -use crate::cli::args::ForgeArg; use clap::{ArgMatches, Command}; use eyre::Result; use rayon::prelude::*; +use crate::cli::args::ForgeArg; use crate::forge; pub fn commands() -> Vec { diff --git a/src/cli/global.rs b/src/cli/global.rs index dfb465ed8..ff82dde16 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -73,8 +73,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::{dirs, file}; #[test] diff --git a/src/cli/install.rs b/src/cli/install.rs index e65fc93be..736b1d32b 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -137,8 +137,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::dirs; #[test] diff --git a/src/cli/latest.rs b/src/cli/latest.rs index f453618b5..d6a5081a0 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -65,8 +65,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - #[test] fn test_latest() { assert_cli_snapshot!("latest", "dummy@1"); diff --git a/src/cli/local.rs b/src/cli/local.rs index cc24b7fcd..0629bcca4 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -160,8 +160,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( mod tests { use std::panic; - use pretty_assertions::assert_str_eq; - use crate::cli::tests::grep; use crate::test::reset_config; use crate::{dirs, env, file}; diff --git a/src/cli/ls.rs b/src/cli/ls.rs index f5a53d379..aa3da11d9 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -368,8 +368,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::dirs; use crate::file::remove_all; diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 79be8db5b..6ac08c772 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -122,8 +122,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use std::env; - #[test] fn test_current() { assert_cli_snapshot!("outdated"); diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index bad8eb028..9e0786366 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -119,7 +119,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { use crate::cli::tests::grep; - #[test] fn test_plugin_list() { assert_cli_snapshot!("plugin", "list"); diff --git a/src/cli/prune.rs b/src/cli/prune.rs index ac57a17ef..7921a3132 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -1,10 +1,10 @@ use std::collections::BTreeMap; use std::sync::Arc; -use crate::cli::args::ForgeArg; use console::style; use eyre::Result; +use crate::cli::args::ForgeArg; use crate::config::{Config, Settings}; use crate::forge::Forge; use crate::toolset::{ToolVersion, ToolsetBuilder}; diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index 17255c266..ce64e3321 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -1,9 +1,10 @@ use std::io::Cursor; use clap::Args; -use clap_complete::generate; use eyre::Result; +use clap_complete::generate; + use crate::shell::completions; /// Generate shell completions diff --git a/src/cli/task/ls.rs b/src/cli/task/ls.rs index b15557897..aed92bc50 100644 --- a/src/cli/task/ls.rs +++ b/src/cli/task/ls.rs @@ -87,8 +87,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use std::env; - #[test] fn test_task_ls() { assert_cli_snapshot!("t", "--no-headers", @r###" diff --git a/src/cli/watch.rs b/src/cli/watch.rs index 701dbcb14..d7cae5924 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -1,9 +1,9 @@ use std::process::exit; -use crate::cli::args::ForgeArg; use console::style; use eyre::Result; +use crate::cli::args::ForgeArg; use crate::cmd; use crate::config::{Config, Settings}; use crate::toolset::ToolsetBuilder; diff --git a/src/cli/where.rs b/src/cli/where.rs index 124ef0e69..2c5568a74 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -83,8 +83,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::dirs; #[test] diff --git a/src/cmd.rs b/src/cmd.rs index efbdfda8b..6911462ac 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -7,11 +7,11 @@ use std::sync::mpsc::channel; use std::sync::{Mutex, RwLock}; use std::thread; -use crate::config::Settings; use color_eyre::Result; use duct::{Expression, IntoExecutablePath}; use eyre::Context; +use crate::config::Settings; use crate::env; use crate::errors::Error::ScriptFailed; use crate::file::display_path; diff --git a/src/direnv.rs b/src/direnv.rs index 92b035055..40134150c 100644 --- a/src/direnv.rs +++ b/src/direnv.rs @@ -111,7 +111,6 @@ impl Display for DirenvDiff { #[cfg(test)] mod tests { - use super::*; #[test] diff --git a/src/env_diff.rs b/src/env_diff.rs index 1aea04bf0..a12074b07 100644 --- a/src/env_diff.rs +++ b/src/env_diff.rs @@ -253,8 +253,6 @@ fn normalize_escape_sequences(input: &str) -> String { mod tests { use indexmap::indexmap; - use pretty_assertions::assert_str_eq; - use crate::dirs; use super::*; diff --git a/src/git.rs b/src/git.rs index 887a81705..1c8f35902 100644 --- a/src/git.rs +++ b/src/git.rs @@ -146,7 +146,6 @@ fn get_git_version() -> Result { // #[cfg(test)] // mod tests { -// use pretty_assertions::assert_str_eq; // use tempfile::tempdir; // // use super::*; diff --git a/src/hash.rs b/src/hash.rs index e4d005f59..049e319bf 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -48,7 +48,6 @@ pub fn parse_shasums(text: &str) -> HashMap { #[cfg(test)] mod tests { - use super::*; #[test] diff --git a/src/hook_env.rs b/src/hook_env.rs index 461ae2a74..4c56402dd 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -165,8 +165,6 @@ pub fn build_env_commands(shell: &dyn Shell, patches: &EnvDiffPatches) -> String mod tests { use std::time::UNIX_EPOCH; - use pretty_assertions::assert_str_eq; - use super::*; #[test] diff --git a/src/http.rs b/src/http.rs index f22b895f6..0bb93503e 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,4 +1,15 @@ use std::fs::File; +use std::path::Path; +use std::time::Duration; + +use eyre::{Report, Result}; +use once_cell::sync::Lazy; +use reqwest::blocking::{ClientBuilder, Response}; +use reqwest::IntoUrl; + +use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; +use crate::file::display_path; +use crate::{env, file}; #[cfg(not(test))] pub static HTTP_VERSION_CHECK: Lazy = @@ -9,17 +20,6 @@ pub static HTTP: Lazy = Lazy::new(|| Client::new(Duration::from_secs(30) pub static HTTP_FETCH: Lazy = Lazy::new(|| Client::new(*MISE_FETCH_REMOTE_VERSIONS_TIMEOUT).unwrap()); -use std::path::Path; -use std::time::Duration; - -use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; -use crate::file::display_path; -use crate::{env, file}; -use eyre::{Report, Result}; -use once_cell::sync::Lazy; -use reqwest::blocking::{ClientBuilder, Response}; -use reqwest::IntoUrl; - #[derive(Debug)] pub struct Client { reqwest: reqwest::blocking::Client, diff --git a/src/logger.rs b/src/logger.rs index af6e4751f..9f2ce99b6 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -3,11 +3,12 @@ extern crate simplelog; use std::fs::{create_dir_all, File, OpenOptions}; use std::path::Path; -use crate::config::Settings; -use crate::env; use eyre::Result; use simplelog::*; +use crate::config::Settings; +use crate::env; + pub fn init(settings: &Settings) { static INIT: std::sync::Once = std::sync::Once::new(); INIT.call_once(|| _init(settings)); diff --git a/src/main.rs b/src/main.rs index 7c98375e7..fabea21e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,9 @@ extern crate indoc; #[cfg(test)] #[macro_use] extern crate insta; +#[cfg(test)] +#[macro_use] +extern crate pretty_assertions; #[macro_use] extern crate strum; diff --git a/src/path_env.rs b/src/path_env.rs index 1daf0984f..a3ed78110 100644 --- a/src/path_env.rs +++ b/src/path_env.rs @@ -1,11 +1,13 @@ -use crate::dirs; -use itertools::Itertools; use std::env::join_paths; use std::ffi::OsString; use std::fmt; use std::fmt::{Display, Formatter}; use std::path::PathBuf; +use itertools::Itertools; + +use crate::dirs; + pub struct PathEnv { pre: Vec, mise: Vec, diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 1889637a8..634008ee4 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -1,10 +1,10 @@ use std::path::{Path, PathBuf}; -use crate::cli::args::ForgeArg; use eyre::Result; use itertools::Itertools; use versions::Versioning; +use crate::cli::args::ForgeArg; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::file; diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 350820a8c..482a06b29 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use crate::cli::args::ForgeArg; use eyre::Result; use itertools::Itertools; use versions::Versioning; +use crate::cli::args::ForgeArg; use crate::cli::version::{ARCH, OS}; use crate::cmd::CmdLineRunner; use crate::config::Config; diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index fda02312e..6bf308ab3 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -5,11 +5,10 @@ use std::path::{Path, PathBuf}; use eyre::Result; use eyre::WrapErr; +use crate::cli::args::ForgeArg; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::duration::DAILY; - -use crate::cli::args::ForgeArg; use crate::forge::Forge; use crate::git::Git; use crate::github::GithubRelease; @@ -423,7 +422,6 @@ fn parse_gemfile(body: &str) -> String { #[cfg(test)] mod tests { - use super::*; #[test] diff --git a/src/plugins/mise_plugin_toml.rs b/src/plugins/mise_plugin_toml.rs index 299f6a926..fc9a592c0 100644 --- a/src/plugins/mise_plugin_toml.rs +++ b/src/plugins/mise_plugin_toml.rs @@ -101,7 +101,6 @@ impl MisePluginToml { #[cfg(test)] mod tests { - use crate::dirs; use super::*; diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 142ac9a03..7e5e6f30c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -51,8 +51,6 @@ pub fn list_external() -> ForgeList { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use crate::forge::Forge; use super::*; diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 68940c89d..0b5626bab 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -1,6 +1,6 @@ -use crate::config::Settings; use std::path::Path; +use crate::config::Settings; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] @@ -96,10 +96,8 @@ impl Shell for Bash { #[cfg(test)] mod tests { - - use crate::test::replace_path; - use super::*; + use crate::test::replace_path; #[test] fn test_hook_init() { diff --git a/src/shell/completions/mod.rs b/src/shell/completions/mod.rs index 46247b48d..05b8085e1 100644 --- a/src/shell/completions/mod.rs +++ b/src/shell/completions/mod.rs @@ -1,6 +1,7 @@ +use std::collections::HashSet; + use clap::Command; use once_cell::sync::Lazy; -use std::collections::HashSet; mod fish_complete; mod zsh_complete; diff --git a/src/shell/completions/zsh_complete.rs b/src/shell/completions/zsh_complete.rs index b84bca6bb..0c1206b36 100644 --- a/src/shell/completions/zsh_complete.rs +++ b/src/shell/completions/zsh_complete.rs @@ -1,7 +1,8 @@ -use crate::shell::completions::is_banned; use clap::{Arg, ArgAction, Command, ValueHint}; use itertools::Itertools; +use crate::shell::completions::is_banned; + pub fn render(cmd: &Command) -> String { let cmds = vec![cmd]; let command_funcs = render_command_funcs(&cmds); diff --git a/src/shell/fish.rs b/src/shell/fish.rs index dbf735847..aabbafd7a 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -1,6 +1,6 @@ -use crate::config::Settings; use std::path::Path; +use crate::config::Settings; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; #[derive(Default)] @@ -115,10 +115,8 @@ impl Shell for Fish { #[cfg(test)] mod tests { - - use crate::test::replace_path; - use super::*; + use crate::test::replace_path; #[test] fn test_hook_init() { diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index 8f07df80b..d999782cf 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -115,10 +115,8 @@ impl Shell for Nushell { #[cfg(test)] mod tests { - - use crate::test::replace_path; - use super::*; + use crate::test::replace_path; #[test] fn test_hook_init() { diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 5f8749611..58fb921f5 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -121,10 +121,8 @@ impl Shell for Xonsh { #[cfg(test)] mod tests { - - use crate::test::replace_path; - use super::*; + use crate::test::replace_path; #[test] fn test_hook_init() { diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index 79b705106..b15b69048 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -1,6 +1,6 @@ -use crate::config::Settings; use std::path::Path; +use crate::config::Settings; use crate::shell::bash::Bash; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; @@ -101,10 +101,8 @@ impl Shell for Zsh { #[cfg(test)] mod tests { - - use crate::test::replace_path; - use super::*; + use crate::test::replace_path; #[test] fn test_hook_init() { diff --git a/src/shims.rs b/src/shims.rs index cf6cc5c05..a4df6f25d 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -13,13 +13,12 @@ use rayon::prelude::*; use crate::cli::exec::Exec; use crate::config::{Config, Settings}; use crate::file::{create_dir_all, display_path, remove_all}; -use crate::lock_file::LockFile; -use crate::{env, logger}; -use crate::{fake_asdf, forge}; - use crate::forge::Forge; +use crate::lock_file::LockFile; use crate::toolset::{ToolVersion, Toolset, ToolsetBuilder}; use crate::{dirs, file}; +use crate::{env, logger}; +use crate::{fake_asdf, forge}; // executes as if it was a shim if the command is not "mise", e.g.: "node" pub fn handle_shim() -> Result<()> { diff --git a/src/shorthands.rs b/src/shorthands.rs index 242194b10..ea2e578b4 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -50,7 +50,6 @@ fn parse_shorthands_file(mut f: PathBuf) -> Result { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; use std::ops::Deref; use crate::config::settings::Settings; diff --git a/src/task.rs b/src/task.rs index 03f965ced..b8082d5e3 100644 --- a/src/task.rs +++ b/src/task.rs @@ -1,4 +1,3 @@ -use console::truncate_str; use std::cmp::Ordering; use std::collections::HashMap; use std::fmt; @@ -6,6 +5,7 @@ use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; use std::path::PathBuf; +use console::truncate_str; use eyre::Result; use itertools::Itertools; diff --git a/src/test.rs b/src/test.rs index b65cad88d..2f21e16d2 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,7 +1,8 @@ -use color_eyre::{Help, SectionExt}; -use std::env::{join_paths, set_current_dir}; +use std::env::join_paths; use std::path::PathBuf; +use color_eyre::{Help, SectionExt}; + use crate::cli::Cli; use crate::config::Config; use crate::output::tests::{STDERR, STDOUT}; @@ -19,7 +20,7 @@ fn init() { "HOME", PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test"), ); - set_current_dir(env::HOME.join("cwd")).unwrap(); + env::set_current_dir(env::HOME.join("cwd")).unwrap(); env::remove_var("MISE_TRUSTED_CONFIG_PATHS"); env::set_var("NO_COLOR", "1"); env::set_var("MISE_YES", "1"); diff --git a/src/toolset/tool_source.rs b/src/toolset/tool_source.rs index fad3cdc19..b0ce1954d 100644 --- a/src/toolset/tool_source.rs +++ b/src/toolset/tool_source.rs @@ -57,8 +57,6 @@ impl ToolSource { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - use super::*; #[test] diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 41fe2ba3d..6c9c8ec23 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -1,14 +1,14 @@ -use console::style; use std::cmp::Ordering; use std::fmt::{Display, Formatter}; use std::fs; use std::hash::{Hash, Hasher}; use std::path::PathBuf; -use crate::cli::args::ForgeArg; +use console::style; use eyre::Result; use versions::{Chunk, Version}; +use crate::cli::args::ForgeArg; use crate::config::Config; use crate::forge::{AForge, Forge}; use crate::hash::hash_to_str; @@ -250,12 +250,15 @@ impl PartialEq for ToolVersion { self.forge.id == other.forge.id && self.version == other.version } } + impl Eq for ToolVersion {} + impl PartialOrd for ToolVersion { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } + impl Ord for ToolVersion { fn cmp(&self, other: &Self) -> Ordering { match self.forge.id.cmp(&other.forge.id) { @@ -264,6 +267,7 @@ impl Ord for ToolVersion { } } } + impl Hash for ToolVersion { fn hash(&self, state: &mut H) { self.forge.id.hash(state); @@ -289,9 +293,7 @@ fn version_sub(orig: &str, sub: &str) -> String { #[cfg(test)] mod tests { - use pretty_assertions::assert_str_eq; - - use super::*; + use super::version_sub; #[test] fn test_version_sub() { diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 10cb9ce6a..8bca0b40c 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,8 +1,10 @@ -use console::{user_attended_stderr, Term}; -pub use prompt::confirm; use std::process::exit; use std::sync::Once; +use console::{user_attended_stderr, Term}; + +pub use prompt::confirm; + pub mod multi_progress_report; pub mod progress_report; pub mod prompt; diff --git a/src/ui/multi_progress_report.rs b/src/ui/multi_progress_report.rs index 374dc091a..05ea06f53 100644 --- a/src/ui/multi_progress_report.rs +++ b/src/ui/multi_progress_report.rs @@ -1,8 +1,8 @@ -use crate::config::Settings; +use std::sync::{Arc, Mutex, Weak}; use indicatif::MultiProgress; -use std::sync::{Arc, Mutex, Weak}; +use crate::config::Settings; use crate::ui::progress_report::{ProgressReport, QuietReport, SingleReport, VerboseReport}; #[derive(Debug)] @@ -10,6 +10,7 @@ pub struct MultiProgressReport { mp: Option, quiet: bool, } + static INSTANCE: Mutex>> = Mutex::new(None); impl MultiProgressReport { diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 76da1a9ee..2d249a647 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,8 +1,10 @@ -use crate::ui; -use demand::Confirm; use std::io; use std::sync::Mutex; +use demand::Confirm; + +use crate::ui; + static MUTEX: Mutex<()> = Mutex::new(()); pub fn confirm>(message: S) -> io::Result { diff --git a/src/ui/style.rs b/src/ui/style.rs index f98876553..3c8a3c7ac 100644 --- a/src/ui/style.rs +++ b/src/ui/style.rs @@ -1,31 +1,41 @@ -use crate::file::display_path; -use console::{style, StyledObject}; use std::path::Path; +use console::{style, StyledObject}; + +use crate::file::display_path; + pub fn estyle(val: D) -> StyledObject { style(val).for_stderr() } + pub fn ecyan(val: D) -> StyledObject { estyle(val).cyan() } + pub fn eblue(val: D) -> StyledObject { estyle(val).blue() } + pub fn egreen(val: D) -> StyledObject { estyle(val).green() } + pub fn eyellow(val: D) -> StyledObject { estyle(val).yellow() } + pub fn ered(val: D) -> StyledObject { estyle(val).red() } + pub fn edim(val: D) -> StyledObject { estyle(val).dim() } + pub fn ebold(val: D) -> StyledObject { estyle(val).bold() } + pub fn epath(path: &Path) -> StyledObject { estyle(display_path(path)) } @@ -33,9 +43,11 @@ pub fn epath(path: &Path) -> StyledObject { pub fn nstyle(val: D) -> StyledObject { style(val).for_stdout() } + pub fn nblue(val: D) -> StyledObject { nstyle(val).cyan() } + pub fn nbold(val: D) -> StyledObject { nstyle(val).bold() } From c24976f30c92572ab15f68cfa8fa6417ca3b38da Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 08:18:41 -0600 Subject: [PATCH 1616/1891] fix loading npm from mise (#1453) --- .idea/mise.iml | 2 ++ .mise.toml | 2 +- docs/cli-reference.md | 2 +- e2e/test_cargo | 6 ++-- e2e/test_npm | 4 +-- man/man1/mise.1 | 4 +-- src/cli/args/forge_arg.rs | 54 ++++++++++++++++++++++++++++++++-- src/cli/args/tool_arg.rs | 16 +++++----- src/cli/link.rs | 4 +-- src/cli/mod.rs | 4 +-- src/cli/use.rs | 2 +- src/cmd.rs | 19 ++++++------ src/forge/cargo.rs | 12 +++++--- src/forge/mod.rs | 23 +++++---------- src/forge/npm.rs | 12 +++++--- src/plugins/core/erlang.rs | 11 ++++--- src/plugins/core/java.rs | 4 +-- src/plugins/core/mod.rs | 16 +++++----- src/plugins/core/node.rs | 17 +++++------ src/plugins/core/python.rs | 4 +-- src/plugins/core/ruby.rs | 4 +-- src/plugins/external_plugin.rs | 43 +++++++++++++-------------- src/runtime_symlinks.rs | 6 ++-- src/toolset/tool_version.rs | 14 ++++----- 24 files changed, 168 insertions(+), 117 deletions(-) diff --git a/.idea/mise.iml b/.idea/mise.iml index 58dd59249..1421cb198 100644 --- a/.idea/mise.iml +++ b/.idea/mise.iml @@ -21,6 +21,8 @@ + + diff --git a/.mise.toml b/.mise.toml index a9d5f7240..c41e35402 100644 --- a/.mise.toml +++ b/.mise.toml @@ -9,7 +9,7 @@ THIS_PROJECT = "{{config_root}}-{{cwd}}" [tools] #node = 'lts' -cargo-eza = "0.17.0" +"cargo:eza" = "0.17.0" tiny = { version = "1", foo = "bar" } golang = { version = "prefix:1.20", foo = "bar" } python = { version = "latest", virtualenv = "{{env.HOME}}/.cache/venv" } diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 6ae7c57d5..5103bc7a7 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -1444,7 +1444,7 @@ Usage: use [OPTIONS] [TOOL@VERSION]... Arguments: [TOOL@VERSION]... Tool(s) to add to config file - e.g.: node@20, cargo-ripgrep@latest npm-prettier@3 + e.g.: node@20, cargo:ripgrep@latest npm:prettier@3 If no version is specified, it will default to @latest Options: diff --git a/e2e/test_cargo b/e2e/test_cargo index 3cc5b42e5..ebe20ecb5 100755 --- a/e2e/test_cargo +++ b/e2e/test_cargo @@ -10,12 +10,12 @@ export MISE_CARGO_BINSTALL=1 #exit #fi -assert "mise x cargo-eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls +assert "mise x cargo:eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls v0.17.0 [+git] https://github.com/eza-community/eza" export MISE_CARGO_BINSTALL=0 -mise rm cargo-eza@0.17.0 -assert "mise x cargo-eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls +mise rm cargo:eza@0.17.0 +assert "mise x cargo:eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls v0.17.0 [+git] https://github.com/eza-community/eza" diff --git a/e2e/test_npm b/e2e/test_npm index eefc77060..271265e6e 100755 --- a/e2e/test_npm +++ b/e2e/test_npm @@ -5,5 +5,5 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 -assert "mise x npm-prettier@3.1.0 -- prettier -v" "3.1.0" -assert "mise x npm-@antfu/ni@0.21.12 -- ni -v 2>/dev/null | head -n1" "@antfu/ni v0.21.12" +assert "mise x npm:prettier@3.1.0 -- prettier -v" "3.1.0" +assert "mise x npm:@antfu/ni@0.21.12 -- ni -v 2>/dev/null | head -n1" "@antfu/ni v0.21.12" diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 9e5c7347d..ffce05cff 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -158,8 +158,8 @@ Examples: $ mise install node Install the node version defined in config $ mise install Install all plugins/tools defined in config - $ mise install cargo\-ripgrep Install something via cargo - $ mise install npm\-prettier Install something via npm + $ mise install cargo:ripgrep Install something via cargo + $ mise install npm:prettier Install something via npm $ mise use node@20 Use node\-20.x in current project $ mise use \-g node@20 Use node\-20.x as default diff --git a/src/cli/args/forge_arg.rs b/src/cli/args/forge_arg.rs index 28ea39ef7..3b33c1aca 100644 --- a/src/cli/args/forge_arg.rs +++ b/src/cli/args/forge_arg.rs @@ -1,5 +1,7 @@ +use crate::dirs; use std::fmt::{Debug, Display}; use std::hash::Hash; +use std::path::PathBuf; use std::str::FromStr; use crate::forge::unalias_forge; @@ -10,13 +12,16 @@ pub struct ForgeArg { pub id: String, pub name: String, pub forge_type: ForgeType, + pub cache_path: PathBuf, + pub installs_path: PathBuf, + pub downloads_path: PathBuf, } impl FromStr for ForgeArg { type Err = eyre::Error; fn from_str(s: &str) -> Result { - if let Some((forge_type, name)) = s.split_once('-') { + if let Some((forge_type, name)) = s.split_once(':') { if let Ok(forge_type) = forge_type.parse() { return Ok(Self::new(forge_type, name)); } @@ -30,12 +35,16 @@ impl ForgeArg { let name = unalias_forge(name).to_string(); let id = match forge_type { ForgeType::Asdf => name.clone(), - forge_type => format!("{}-{}", forge_type.as_ref(), name), + forge_type => format!("{}:{}", forge_type.as_ref(), name), }; + let pathname = regex!(r#"[/:]"#).replace_all(&id, "-").to_string(); Self { name, forge_type, id, + cache_path: dirs::CACHE.join(&pathname), + installs_path: dirs::INSTALLS.join(&pathname), + downloads_path: dirs::DOWNLOADS.join(&pathname), } } } @@ -65,3 +74,44 @@ impl Hash for ForgeArg { self.id.hash(state); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_forge_arg() { + let t = |s: &str, id, name, t| { + let fa: ForgeArg = s.parse().unwrap(); + assert_str_eq!(fa.id, id); + assert_str_eq!(fa.name, name); + assert_eq!(fa.forge_type, t); + }; + let asdf = |s, id, name| t(s, id, name, ForgeType::Asdf); + let cargo = |s, id, name| t(s, id, name, ForgeType::Cargo); + let npm = |s, id, name| t(s, id, name, ForgeType::Npm); + + asdf("asdf:node", "node", "node"); + asdf("node", "node", "node"); + asdf("", "", ""); + cargo("cargo:eza", "cargo:eza", "eza"); + npm("npm:@antfu/ni", "npm:@antfu/ni", "@antfu/ni"); + npm("npm:prettier", "npm:prettier", "prettier"); + } + + #[test] + fn test_forge_arg_pathname() { + let t = |s: &str, expected| { + let fa: ForgeArg = s.parse().unwrap(); + let actual = fa.installs_path.to_string_lossy(); + let expected = dirs::INSTALLS.join(expected); + assert_str_eq!(actual, expected.to_string_lossy()); + }; + t("asdf:node", "node"); + t("node", "node"); + t("", ""); + t("cargo:eza", "cargo-eza"); + t("npm:@antfu/ni", "npm-@antfu-ni"); + t("npm:prettier", "npm-prettier"); + } +} diff --git a/src/cli/args/tool_arg.rs b/src/cli/args/tool_arg.rs index bfc6a4f52..2ec606bab 100644 --- a/src/cli/args/tool_arg.rs +++ b/src/cli/args/tool_arg.rs @@ -132,8 +132,8 @@ fn parse_input(s: &str) -> (&str, Option<&str>) { .map(|(f, v)| (f, Some(v))) .unwrap_or((s, None)); - // special case for packages with npm scopes like "npm-@antfu/ni" - if forge == "npm-" { + // special case for packages with npm scopes like "npm:@antfu/ni" + if forge == "npm:" { if let Some(v) = version { return if let Some(i) = v.find('@') { (&s[..forge.len() + i + 1], Some(&v[i + 1..])) @@ -199,11 +199,11 @@ mod tests { assert_eq!(forge, f); assert_eq!(version, v); }; - t("npm-@antfu/ni", "npm-@antfu/ni", None); - t("npm-@antfu/ni@1.0.0", "npm-@antfu/ni", Some("1.0.0")); - t("npm-@antfu/ni@1.0.0@1", "npm-@antfu/ni", Some("1.0.0@1")); - t("npm-", "npm-", None); - t("npm-prettier", "npm-prettier", None); - t("npm-prettier@1.0.0", "npm-prettier", Some("1.0.0")); + t("npm:@antfu/ni", "npm:@antfu/ni", None); + t("npm:@antfu/ni@1.0.0", "npm:@antfu/ni", Some("1.0.0")); + t("npm:@antfu/ni@1.0.0@1", "npm:@antfu/ni", Some("1.0.0@1")); + t("npm:", "npm:", None); + t("npm:prettier", "npm:prettier", None); + t("npm:prettier@1.0.0", "npm:prettier", Some("1.0.0")); } } diff --git a/src/cli/link.rs b/src/cli/link.rs index 0e8f54d4e..b26a208d2 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -7,8 +7,8 @@ use path_absolutize::Absolutize; use crate::cli::args::ToolArg; use crate::config::Config; +use crate::file; use crate::file::{make_symlink, remove_all}; -use crate::{dirs, file}; /// Symlinks a tool version into mise /// @@ -45,7 +45,7 @@ impl Link { style(path.to_string_lossy()).cyan().for_stderr() ); } - let target = dirs::INSTALLS.join(&self.tool.forge.id).join(version); + let target = self.tool.forge.installs_path.join(version); if target.exists() { if self.force { remove_all(&target)?; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b77d404d9..1de20b0db 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -239,8 +239,8 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ mise install node Install the node version defined in config $ mise install Install all plugins/tools defined in config - $ mise install cargo-ripgrep Install something via cargo - $ mise install npm-prettier Install something via npm + $ mise install cargo:ripgrep Install something via cargo + $ mise install npm:prettier Install something via npm $ mise use node@20 Use node-20.x in current project $ mise use -g node@20 Use node-20.x as default diff --git a/src/cli/use.rs b/src/cli/use.rs index ed4c8d438..4a5ded6cb 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -25,7 +25,7 @@ use crate::{env, file, forge}; #[clap(verbatim_doc_comment, visible_alias = "u", after_long_help = AFTER_LONG_HELP)] pub struct Use { /// Tool(s) to add to config file - /// e.g.: node@20, cargo-ripgrep@latest npm-prettier@3 + /// e.g.: node@20, cargo:ripgrep@latest npm:prettier@3 /// If no version is specified, it will default to @latest #[clap( value_name = "TOOL@VERSION", diff --git a/src/cmd.rs b/src/cmd.rs index 6911462ac..7d45772f7 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -158,21 +158,22 @@ impl<'a> CmdLineRunner<'a> { self } - pub fn prepend_path_env(&mut self, path: PathBuf) -> &mut Self { - let k: OsString = "PATH".into(); + pub fn prepend_path(mut self, paths: Vec) -> eyre::Result { let existing = self - .get_env(&k) + .get_env("PATH") .map(|c| c.to_owned()) .unwrap_or_else(|| env::var_os("PATH").unwrap()); - let mut paths = env::split_paths(&existing).collect::>(); - paths.insert(0, path); - self.cmd.env("PATH", env::join_paths(paths).unwrap()); - self + let paths = paths + .into_iter() + .chain(env::split_paths(&existing)) + .collect::>(); + self.cmd.env("PATH", env::join_paths(paths)?); + Ok(self) } - fn get_env(&self, key: &OsString) -> Option<&OsStr> { + fn get_env(&self, key: &str) -> Option<&OsStr> { for (k, v) in self.cmd.get_envs() { - if k != key { + if k == key { return v; } } diff --git a/src/forge/cargo.rs b/src/forge/cargo.rs index a10aba414..7a3d2c0cd 100644 --- a/src/forge/cargo.rs +++ b/src/forge/cargo.rs @@ -6,11 +6,11 @@ use url::Url; use crate::cache::CacheManager; use crate::cli::args::ForgeArg; use crate::cmd::CmdLineRunner; -use crate::config::Settings; +use crate::config::{Config, Settings}; +use crate::file; use crate::forge::{Forge, ForgeType}; use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; -use crate::{dirs, file}; #[derive(Debug)] pub struct CargoForge { @@ -45,6 +45,7 @@ impl Forge for CargoForge { } fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { + let config = Config::try_get()?; let settings = Settings::get(); settings.ensure_experimental()?; let cmd = match settings.cargo_binstall { @@ -58,6 +59,8 @@ impl Forge for CargoForge { .arg("--root") .arg(ctx.tv.install_path()) .with_pr(ctx.pr.as_ref()) + .envs(&config.env) + .prepend_path(ctx.ts.list_paths())? .execute()?; Ok(()) @@ -66,10 +69,11 @@ impl Forge for CargoForge { impl CargoForge { pub fn new(fa: ForgeArg) -> Self { - let cache_dir = dirs::CACHE.join(&fa.id); Self { + remote_version_cache: CacheManager::new( + fa.cache_path.join("remote_versions.msgpack.z"), + ), fa, - remote_version_cache: CacheManager::new(cache_dir.join("remote_versions.msgpack.z")), } } } diff --git a/src/forge/mod.rs b/src/forge/mod.rs index a3b8a1b2b..b4a9f6fa5 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -96,23 +96,14 @@ pub trait Forge: Debug + Send + Sync { fn get_plugin_type(&self) -> PluginType { PluginType::Core } - fn installs_path(&self) -> PathBuf { - dirs::INSTALLS.join(self.id()) - } - fn cache_path(&self) -> PathBuf { - dirs::CACHE.join(self.id()) - } - fn downloads_path(&self) -> PathBuf { - dirs::DOWNLOADS.join(self.id()) - } fn list_remote_versions(&self) -> eyre::Result>; fn latest_stable_version(&self) -> eyre::Result> { self.latest_version(Some("latest".into())) } fn list_installed_versions(&self) -> eyre::Result> { - let installs_path = self.installs_path(); + let installs_path = &self.fa().installs_path; Ok(match installs_path.exists() { - true => file::dir_subdirs(&installs_path)? + true => file::dir_subdirs(installs_path)? .into_iter() .filter(|v| !v.starts_with('.')) .filter(|v| !is_runtime_symlink(&installs_path.join(v))) @@ -153,7 +144,7 @@ pub trait Forge: Debug + Send + Sync { } } fn create_symlink(&self, version: &str, target: &Path) -> eyre::Result<()> { - let link = self.installs_path().join(version); + let link = self.fa().installs_path.join(version); file::create_dir_all(link.parent().unwrap())?; file::make_symlink(target, &link) } @@ -181,7 +172,7 @@ pub trait Forge: Debug + Send + Sync { Ok(find_match_in_list(&matches, &query)) } None => { - let installed_symlink = self.installs_path().join("latest"); + let installed_symlink = self.fa().installs_path.join("latest"); if installed_symlink.exists() { let target = installed_symlink.read_link()?; let version = target @@ -219,9 +210,9 @@ pub trait Forge: Debug + Send + Sync { Ok(()) } fn purge(&self, pr: &dyn SingleReport) -> eyre::Result<()> { - rmdir(&self.installs_path(), pr)?; - rmdir(&self.cache_path(), pr)?; - rmdir(&self.downloads_path(), pr)?; + rmdir(&self.fa().installs_path, pr)?; + rmdir(&self.fa().cache_path, pr)?; + rmdir(&self.fa().downloads_path, pr)?; Ok(()) } fn get_aliases(&self) -> eyre::Result> { diff --git a/src/forge/npm.rs b/src/forge/npm.rs index 706467a84..03611caa8 100644 --- a/src/forge/npm.rs +++ b/src/forge/npm.rs @@ -3,8 +3,8 @@ use std::fmt::Debug; use crate::cache::CacheManager; use crate::cli::args::ForgeArg; use crate::cmd::CmdLineRunner; -use crate::config::Settings; -use crate::dirs; +use crate::config::{Config, Settings}; + use crate::forge::{Forge, ForgeType}; use crate::install_context::InstallContext; @@ -34,6 +34,7 @@ impl Forge for NPMForge { } fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { + let config = Config::try_get()?; let settings = Settings::get(); settings.ensure_experimental()?; @@ -44,6 +45,8 @@ impl Forge for NPMForge { .arg("--prefix") .arg(ctx.tv.install_path()) .with_pr(ctx.pr.as_ref()) + .envs(&config.env) + .prepend_path(ctx.ts.list_paths())? .execute()?; Ok(()) @@ -52,10 +55,11 @@ impl Forge for NPMForge { impl NPMForge { pub fn new(fa: ForgeArg) -> Self { - let cache_dir = dirs::CACHE.join(&fa.id); Self { + remote_version_cache: CacheManager::new( + fa.cache_path.join("remote_versions.msgpack.z"), + ), fa, - remote_version_cache: CacheManager::new(cache_dir.join("remote_versions.msgpack.z")), } } } diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 3d54293ba..4b95dd6d2 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -27,11 +27,14 @@ impl ErlangPlugin { } fn kerl_path(&self) -> PathBuf { - self.core.cache_path.join(format!("kerl-{}", KERL_VERSION)) + self.core + .fa + .cache_path + .join(format!("kerl-{}", KERL_VERSION)) } fn kerl_base_dir(&self) -> PathBuf { - self.core.cache_path.join("kerl") + self.core.fa.cache_path.join("kerl") } fn lock_build_tool(&self) -> Result { @@ -75,7 +78,7 @@ impl ErlangPlugin { self.update_kerl()?; let versions = CorePlugin::run_fetch_task_with_timeout(move || { let output = cmd!(self.kerl_path(), "list", "releases", "all") - .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) + .env("KERL_BASE_DIR", self.core.fa.cache_path.join("kerl")) .read()?; let versions = output .split('\n') @@ -115,7 +118,7 @@ impl Forge for ErlangPlugin { &ctx.tv.version, ctx.tv.install_path() ) - .env("KERL_BASE_DIR", self.core.cache_path.join("kerl")) + .env("KERL_BASE_DIR", self.core.fa.cache_path.join("kerl")) .run()?; } } diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 57d89ba6f..0ac2070cb 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -38,11 +38,11 @@ impl JavaPlugin { format!("java_metadata_ea_{}_{}.msgpack.z", os(), arch()); Self { java_metadata_ea_cache: CacheManager::new( - core.cache_path.join(java_metadata_ea_cache_filename), + core.fa.cache_path.join(java_metadata_ea_cache_filename), ) .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), java_metadata_ga_cache: CacheManager::new( - core.cache_path.join(java_metadata_ga_cache_filename), + core.fa.cache_path.join(java_metadata_ga_cache_filename), ) .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), core, diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 182d1834a..83b03daa0 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -1,6 +1,6 @@ use std::ffi::OsString; use std::iter::Iterator; -use std::path::PathBuf; + use std::sync::Arc; use eyre::Result; @@ -12,6 +12,7 @@ pub use python::PythonPlugin; use crate::cache::CacheManager; use crate::cli::args::ForgeArg; use crate::config::Settings; +use crate::env; use crate::forge::{Forge, ForgeList, ForgeType}; use crate::http::HTTP_FETCH; use crate::plugins::core::bun::BunPlugin; @@ -23,7 +24,6 @@ use crate::plugins::core::node::NodePlugin; use crate::plugins::core::ruby::RubyPlugin; use crate::timeout::run_with_timeout; use crate::toolset::ToolVersion; -use crate::{dirs, env}; mod bun; mod deno; @@ -55,19 +55,19 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { pub struct CorePlugin { pub fa: ForgeArg, pub name: &'static str, - pub cache_path: PathBuf, pub remote_version_cache: CacheManager>, } impl CorePlugin { pub fn new(name: &'static str) -> Self { - let cache_path = dirs::CACHE.join(name); + let fa = ForgeArg::new(ForgeType::Asdf, name); Self { - fa: ForgeArg::new(ForgeType::Asdf, name), name, - remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), - cache_path, + remote_version_cache: CacheManager::new( + fa.cache_path.join("remote_versions.msgpack.z"), + ) + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), + fa, } } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 6f9ba6460..ea4b1d84e 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -121,29 +121,26 @@ impl NodePlugin { Ok(()) } - fn sh<'a>(&'a self, ctx: &'a InstallContext, opts: &BuildOpts) -> CmdLineRunner { - let mut cmd = CmdLineRunner::new("sh"); - for p in &opts.path { - cmd.prepend_path_env(p.clone()); - } - cmd = cmd + fn sh<'a>(&'a self, ctx: &'a InstallContext, opts: &BuildOpts) -> eyre::Result { + let mut cmd = CmdLineRunner::new("sh") + .prepend_path(opts.path.clone())? .with_pr(ctx.pr.as_ref()) .current_dir(&opts.build_dir) .arg("-c"); if let Some(cflags) = &*env::MISE_NODE_CFLAGS { cmd = cmd.env("CFLAGS", cflags); } - cmd + Ok(cmd) } fn exec_configure(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { - self.sh(ctx, opts).arg(&opts.configure_cmd).execute() + self.sh(ctx, opts)?.arg(&opts.configure_cmd).execute() } fn exec_make(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { - self.sh(ctx, opts).arg(&opts.make_cmd).execute() + self.sh(ctx, opts)?.arg(&opts.make_cmd).execute() } fn exec_make_install(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> { - self.sh(ctx, opts).arg(&opts.make_install_cmd).execute() + self.sh(ctx, opts)?.arg(&opts.make_install_cmd).execute() } fn verify(&self, tarball: &Path, version: &str) -> Result<()> { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index b50e8b6de..31a07c518 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -29,14 +29,14 @@ impl PythonPlugin { pub fn new() -> Self { let core = CorePlugin::new("python"); Self { - precompiled_cache: CacheManager::new(core.cache_path.join("precompiled.msgpack.z")) + precompiled_cache: CacheManager::new(core.fa.cache_path.join("precompiled.msgpack.z")) .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE), core, } } fn python_build_path(&self) -> PathBuf { - self.core.cache_path.join("pyenv") + self.core.fa.cache_path.join("pyenv") } fn python_build_bin(&self) -> PathBuf { self.python_build_path() diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index 6bf308ab3..fa63bb6c0 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -33,10 +33,10 @@ impl RubyPlugin { } fn ruby_build_path(&self) -> PathBuf { - self.core.cache_path.join("ruby-build") + self.core.fa.cache_path.join("ruby-build") } fn ruby_install_path(&self) -> PathBuf { - self.core.cache_path.join("ruby-install") + self.core.fa.cache_path.join("ruby-install") } fn ruby_build_bin(&self) -> PathBuf { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 23854cb39..709e66279 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -44,9 +44,6 @@ pub struct ExternalPlugin { pub plugin_path: PathBuf, pub repo_url: Option, pub toml: MisePluginToml, - cache_path: PathBuf, - downloads_path: PathBuf, - installs_path: PathBuf, script_man: ScriptManager, cache: ExternalPluginCache, remote_version_cache: CacheManager>, @@ -58,37 +55,38 @@ pub struct ExternalPlugin { impl ExternalPlugin { pub fn new(name: String) -> Self { let plugin_path = dirs::PLUGINS.join(&name); - let cache_path = dirs::CACHE.join(&name); let mut toml_path = plugin_path.join("mise.plugin.toml"); if plugin_path.join("rtx.plugin.toml").exists() { toml_path = plugin_path.join("rtx.plugin.toml"); } let toml = MisePluginToml::from_file(&toml_path).unwrap(); + let fa = ForgeArg::new(ForgeType::Asdf, &name); Self { - fa: ForgeArg::new(ForgeType::Asdf, &name), script_man: build_script_man(&name, &plugin_path), - downloads_path: dirs::DOWNLOADS.join(&name), - installs_path: dirs::INSTALLS.join(&name), cache: ExternalPluginCache::default(), - remote_version_cache: CacheManager::new(cache_path.join("remote_versions.msgpack.z")) - .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-all")), - latest_stable_cache: CacheManager::new(cache_path.join("latest_stable.msgpack.z")) + remote_version_cache: CacheManager::new( + fa.cache_path.join("remote_versions.msgpack.z"), + ) + .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-all")), + latest_stable_cache: CacheManager::new(fa.cache_path.join("latest_stable.msgpack.z")) .with_fresh_duration(*env::MISE_FETCH_REMOTE_VERSIONS_CACHE) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/latest-stable")), - alias_cache: CacheManager::new(cache_path.join("aliases.msgpack.z")) + alias_cache: CacheManager::new(fa.cache_path.join("aliases.msgpack.z")) .with_fresh_file(plugin_path.clone()) .with_fresh_file(plugin_path.join("bin/list-aliases")), - legacy_filename_cache: CacheManager::new(cache_path.join("legacy_filenames.msgpack.z")) - .with_fresh_file(plugin_path.clone()) - .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), + legacy_filename_cache: CacheManager::new( + fa.cache_path.join("legacy_filenames.msgpack.z"), + ) + .with_fresh_file(plugin_path.clone()) + .with_fresh_file(plugin_path.join("bin/list-legacy-filenames")), plugin_path, - cache_path, repo_url: None, toml, name, + fa, } } pub fn list() -> Result { @@ -266,7 +264,8 @@ impl ExternalPlugin { } fn legacy_cache_file_path(&self, legacy_file: &Path) -> PathBuf { - self.cache_path + self.fa + .cache_path .join("legacy") .join(&self.name) .join(hash_to_str(&legacy_file.to_string_lossy())) @@ -675,7 +674,7 @@ impl Forge for ExternalPlugin { } ctx.pr.set_message("installing".into()); run_script(&Install)?; - file::remove_dir(&self.downloads_path)?; + file::remove_dir(&self.fa.downloads_path)?; Ok(()) } @@ -721,9 +720,9 @@ impl Debug for ExternalPlugin { f.debug_struct("ExternalPlugin") .field("name", &self.name) .field("plugin_path", &self.plugin_path) - .field("cache_path", &self.cache_path) - .field("downloads_path", &self.downloads_path) - .field("installs_path", &self.installs_path) + .field("cache_path", &self.fa.cache_path) + .field("downloads_path", &self.fa.downloads_path) + .field("installs_path", &self.fa.installs_path) .field("repo_url", &self.repo_url) .finish() } diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index cc16c4ce3..39e05a4e8 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -16,7 +16,7 @@ use crate::{file, forge}; pub fn rebuild(config: &Config) -> Result<()> { for forge in forge::list() { let symlinks = list_symlinks(config, forge.clone())?; - let installs_dir = forge.installs_path(); + let installs_dir = &forge.fa().installs_path; for (from, to) in symlinks { let from = installs_dir.join(from); if from.exists() { @@ -31,7 +31,7 @@ pub fn rebuild(config: &Config) -> Result<()> { } remove_missing_symlinks(forge.clone())?; // remove install dir if empty - file::remove_dir(&installs_dir)?; + file::remove_dir(installs_dir)?; } Ok(()) } @@ -86,7 +86,7 @@ fn installed_versions(forge: &Arc) -> Result> { } fn remove_missing_symlinks(forge: Arc) -> Result<()> { - let installs_dir = forge.installs_path(); + let installs_dir = &forge.fa().installs_path; if !installs_dir.exists() { return Ok(()); } diff --git a/src/toolset/tool_version.rs b/src/toolset/tool_version.rs index 6c9c8ec23..b2c63ddca 100644 --- a/src/toolset/tool_version.rs +++ b/src/toolset/tool_version.rs @@ -10,10 +10,10 @@ use versions::{Chunk, Version}; use crate::cli::args::ForgeArg; use crate::config::Config; +use crate::forge; use crate::forge::{AForge, Forge}; use crate::hash::hash_to_str; use crate::toolset::{ToolVersionOptions, ToolVersionRequest}; -use crate::{dirs, forge}; /// represents a single version of a tool for a particular plugin #[derive(Debug, Clone)] @@ -76,14 +76,14 @@ impl ToolVersion { ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), _ => self.tv_pathname(), }; - dirs::INSTALLS.join(&self.forge.id).join(pathname) + self.forge.installs_path.join(pathname) } pub fn install_short_path(&self) -> PathBuf { let pathname = match &self.request { ToolVersionRequest::Path(_, p) => p.to_string_lossy().to_string(), _ => self.tv_short_pathname(), }; - let sp = dirs::INSTALLS.join(&self.forge.id).join(pathname); + let sp = self.forge.installs_path.join(pathname); if sp.exists() { sp } else { @@ -91,12 +91,10 @@ impl ToolVersion { } } pub fn cache_path(&self) -> PathBuf { - dirs::CACHE.join(&self.forge.id).join(self.tv_pathname()) + self.forge.cache_path.join(self.tv_pathname()) } pub fn download_path(&self) -> PathBuf { - dirs::DOWNLOADS - .join(&self.forge.id) - .join(self.tv_pathname()) + self.forge.downloads_path.join(self.tv_pathname()) } pub fn latest_version(&self, tool: &dyn Forge) -> Result { let tv = self.request.resolve(tool, self.opts.clone(), true)?; @@ -118,12 +116,14 @@ impl ToolVersion { ToolVersionRequest::Path(_, p) => format!("path-{}", hash_to_str(p)), ToolVersionRequest::System(_) => "system".to_string(), } + .replace([':', '/'], "-") } fn tv_short_pathname(&self) -> String { match &self.request { ToolVersionRequest::Version(_, v) => v.to_string(), _ => self.tv_pathname(), } + .replace([':', '/'], "-") } fn resolve_version( From 90f4ed85735a6b6c3d2a0439ed8a654bd3ced515 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 08:23:35 -0600 Subject: [PATCH 1617/1891] skip slow cargo test if TEST_ALL is not set (#1455) * skip slow cargo test if TEST_ALL is not set * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- e2e/test_cargo | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/e2e/test_cargo b/e2e/test_cargo index ebe20ecb5..41c72ee28 100755 --- a/e2e/test_cargo +++ b/e2e/test_cargo @@ -6,14 +6,14 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 export MISE_CARGO_BINSTALL=1 -#if [ "${TEST_ALL:-}" != 1 ]; then -#exit -#fi - assert "mise x cargo:eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls v0.17.0 [+git] https://github.com/eza-community/eza" +if [ "${TEST_ALL:-}" != 1 ]; then + exit +fi + export MISE_CARGO_BINSTALL=0 mise rm cargo:eza@0.17.0 assert "mise x cargo:eza@0.17.0 -- eza -v" "eza - A modern, maintained replacement for ls From f061666326783fd4b957d56b32e96d02357d80b0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 08:24:13 -0600 Subject: [PATCH 1618/1891] chore: Release mise version 2024.1.19 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c5a65f8e..739128225 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.18" +version = "2024.1.19" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index d29e56814..4272bcfa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.18" +version = "2024.1.19" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 2d8590340..59fc8af9b 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.18 +mise 2024.1.19 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 3ce2991da..e713cbbfd 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.18"; + version = "2024.1.19"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index ffce05cff..180f4cc94 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.18" +.TH mise 1 "mise 2024.1.19" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.18 +v2024.1.19 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 3f7451f9e..0d3025300 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.18 +Version: 2024.1.19 Release: 1 URL: https://github.com/jdx/mise/ Group: System From b6dfb311e412e119e137186d6143644d018a6cfc Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 08:33:28 -0600 Subject: [PATCH 1619/1891] tasks: enable stdin under interleaved --- src/cli/run.rs | 7 ++++++- src/cmd.rs | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 6884835ec..70f748b91 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -270,7 +270,12 @@ impl Run { let mut cmd = CmdLineRunner::new(program.clone()).args(args).envs(env); match &self.output(task)? { TaskOutput::Prefix => cmd = cmd.prefix(format!("{prefix} ")), - TaskOutput::Interleave => cmd = cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit()), + TaskOutput::Interleave => { + cmd = cmd + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + } } if self.raw(task) { cmd.with_raw(); diff --git a/src/cmd.rs b/src/cmd.rs index 7d45772f7..1f9cefec1 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -115,6 +115,11 @@ impl<'a> CmdLineRunner<'a> { } } + pub fn stdin>(mut self, cfg: T) -> Self { + self.cmd.stdin(cfg); + self + } + pub fn stdout>(mut self, cfg: T) -> Self { self.cmd.stdout(cfg); self From 7e4e79bcdcc541027bc3ea2fccc11fb0f0c07a5d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 10:02:36 -0600 Subject: [PATCH 1620/1891] ci: re-enable standalone test --- scripts/test-standalone.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/test-standalone.sh b/scripts/test-standalone.sh index 3e9b0b9c5..623a200a0 100755 --- a/scripts/test-standalone.sh +++ b/scripts/test-standalone.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -euxo pipefail -exit 0 # TODO: enable this after the next release BASE_DIR="$(pwd)" RELEASE_DIR="$(pwd)/tmp" MISE_VERSION="v$(curl -fsSL https://mise.jdx.dev/VERSION)" From ef2cc0c9e536838e0cf89cc1cc2b67b017517cdb Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sat, 13 Jan 2024 20:24:23 +0100 Subject: [PATCH 1621/1891] feat: add command to print task dependency tree (#1440) * feat: add command to print task dependency tree * move Deps struct to tasks.rs * remove crate ptree and implement rendering of a DiGraph as tree * move tree rendition types to ui/tree.rs * dont swallow error * fix inconcise doc comment * fix rebase issues * add a config.task_with_aliases function and remove filtering * add unit tests for tasks deps command * fix conditional for EndBug/add-and-commit@v9 step in test job * address linting issues --- .github/workflows/test.yml | 2 +- src/cli/run.rs | 112 ++------------------- src/cli/task/deps.rs | 197 +++++++++++++++++++++++++++++++++++++ src/cli/task/edit.rs | 30 +++--- src/cli/task/ls.rs | 1 - src/cli/task/mod.rs | 3 + src/cli/watch.rs | 2 +- src/config/mod.rs | 14 ++- src/task.rs | 125 ++++++++++++++++++++++- src/ui/mod.rs | 1 + src/ui/tree.rs | 93 +++++++++++++++++ 11 files changed, 456 insertions(+), 124 deletions(-) create mode 100644 src/cli/task/deps.rs create mode 100644 src/ui/tree.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a349b9eb5..24c3f43c2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,7 +46,7 @@ jobs: if: github.ref_name != 'mise' - run: just render-all lint-fix - run: git diff HEAD - - if: github.event_name == 'pull_request' + - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'jdx/mise' uses: EndBug/add-and-commit@v9 with: push: true diff --git a/src/cli/run.rs b/src/cli/run.rs index 70f748b91..7798ec76b 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -1,11 +1,11 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::BTreeMap; use std::io::Write; use std::iter::once; use std::os::unix::prelude::ExitStatusExt; use std::path::{Path, PathBuf}; use std::process::{exit, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{mpsc, Mutex}; +use std::sync::Mutex; use std::time::SystemTime; use clap::ValueHint; @@ -15,20 +15,19 @@ use eyre::Result; use globwalk::GlobWalkerBuilder; use itertools::Itertools; use once_cell::sync::Lazy; -use petgraph::graph::DiGraph; -use petgraph::Direction; -use crate::cli::args::ToolArg; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; use crate::errors::Error; use crate::errors::Error::ScriptFailed; use crate::file::display_path; -use crate::task::Task; +use crate::task::{Deps, Task}; use crate::toolset::{InstallOptions, ToolsetBuilder}; use crate::ui::style; use crate::{env, file, ui}; +use super::args::ToolArg; + /// [experimental] Run a task /// /// This command will run a task, or multiple tasks in parallel. @@ -133,7 +132,7 @@ impl Run { } }) .flat_map(|args| args.split_first().map(|(t, a)| (t.clone(), a.to_vec()))) - .map(|(t, args)| match config.tasks().get(&t) { + .map(|(t, args)| match config.tasks_with_aliases().get(&t) { Some(task) => Ok(task.clone().with_args(args.to_vec())), None => Err(self.err_no_task(config, &t)), }) @@ -336,6 +335,7 @@ impl Run { let t = style(&t).yellow().for_stderr(); eyre!("no task named `{t}` found. Available tasks: {task_names}") } + fn validate_task(&self, task: &Task) -> Result<()> { if let Some(path) = &task.file { if !file::is_executable(path) { @@ -425,104 +425,6 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( "# ); -#[derive(Debug)] -struct Deps { - graph: DiGraph, - sent: HashSet, - tx: mpsc::Sender>, -} - -impl Deps { - fn new(config: &Config, tasks: Vec) -> Result { - let mut graph = DiGraph::new(); - let mut indexes = HashMap::new(); - let mut stack = vec![]; - for t in tasks { - stack.push(t.clone()); - indexes - .entry(t.name.clone()) - .or_insert_with(|| graph.add_node(t)); - } - while let Some(a) = stack.pop() { - let a_idx = *indexes - .entry(a.name.clone()) - .or_insert_with(|| graph.add_node(a.clone())); - for b in a.resolve_depends(config)? { - let b_idx = *indexes - .entry(b.name.clone()) - .or_insert_with(|| graph.add_node(b.clone())); - graph.add_edge(a_idx, b_idx, ()); - stack.push(b.clone()); - } - } - let (tx, _) = mpsc::channel(); - let sent = HashSet::new(); - Ok(Self { graph, tx, sent }) - } - - fn leaves(&self) -> Vec { - self.graph - .externals(Direction::Outgoing) - .map(|idx| self.graph[idx].clone()) - .collect() - } - - fn emit_leaves(&mut self) { - let leaves = self.leaves().into_iter().collect_vec(); - for task in leaves { - if self.sent.contains(&task.name) { - continue; - } - self.sent.insert(task.name.clone()); - self.tx.send(Some(task)).unwrap(); - } - if self.graph.node_count() == 0 { - self.tx.send(None).unwrap(); - } - } - - fn subscribe(&mut self) -> mpsc::Receiver> { - let (tx, rx) = mpsc::channel(); - self.tx = tx; - self.emit_leaves(); - rx - } - - // #[requires(self.graph.node_count() > 0)] - // #[ensures(self.graph.node_count() == old(self.graph.node_count()) - 1)] - fn remove(&mut self, task: &Task) { - if let Some(idx) = self - .graph - .node_indices() - .find(|&idx| &self.graph[idx] == task) - { - self.graph.remove_node(idx); - self.emit_leaves(); - } - } - - fn all(&self) -> impl Iterator { - self.graph.node_indices().map(|idx| &self.graph[idx]) - } - - fn is_linear(&self) -> bool { - !self.graph.node_indices().any(|idx| { - self.graph - .neighbors_directed(idx, Direction::Outgoing) - .count() - > 1 - }) - } - - // fn pop(&'a mut self) -> Option<&'a Task> { - // if let Some(leaf) = self.leaves().first() { - // self.remove(&leaf.clone()) - // } else { - // None - // } - // } -} - #[derive(Debug, PartialEq, EnumString)] #[strum(serialize_all = "snake_case")] enum TaskOutput { diff --git a/src/cli/task/deps.rs b/src/cli/task/deps.rs new file mode 100644 index 000000000..1a70171aa --- /dev/null +++ b/src/cli/task/deps.rs @@ -0,0 +1,197 @@ +use crate::{ + config::{Config, Settings}, + task::{Deps, Task}, + ui::{style, tree::print_tree}, +}; +use console::style; +use eyre::Result; +use itertools::Itertools; +use petgraph::dot::Dot; + +/// [experimental] Display a tree visualization of a dependency graph +#[derive(Debug, clap::Args)] +#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +pub struct TaskDeps { + /// Tasks to get dependencies for + /// Can specify multiple tasks by separating with spaces + /// e.g.: mise task deps task1 task2 + #[clap(verbatim_doc_comment)] + pub tasks: Option>, + + /// Display dependencies in DOT format + #[clap(long, alias = "dot", verbatim_doc_comment)] + pub dot: bool, +} + +impl TaskDeps { + pub fn run(self) -> Result<()> { + let config = Config::try_get()?; + let settings = Settings::try_get()?; + settings.ensure_experimental()?; + + let tasks = if self.tasks.is_none() { + self.get_all_tasks(&config)? + } else { + self.get_task_lists(&config)? + }; + + if self.dot { + self.print_deps_dot(&config, tasks)?; + } else { + self.print_deps_tree(&config, tasks)?; + } + + Ok(()) + } + + fn get_all_tasks(&self, config: &Config) -> Result> { + config + .tasks() + .iter() + .map(|(_, t)| t) + .sorted() + .filter(|t| !t.hide) + .map(|t| Ok(t.to_owned())) + .collect() + } + + fn get_task_lists(&self, config: &Config) -> Result> { + let tasks = self.tasks.as_ref().map(|t| { + t.iter() + .sorted() + .map(|tn| match config.tasks().get(tn) { + Some(task) => Ok(task.clone()), + None => Err(self.err_no_task(config, tn.as_str())), + }) + .collect::>>() + }); + match tasks { + Some(Ok(tasks)) => Ok(tasks), + Some(Err(e)) => Err(e), + None => Ok(vec![]), + } + } + + /// + /// Print dependencies as a tree + /// + /// Example: + /// ``` + /// task1 + /// ├─ task2 + /// │ └─ task3 + /// └─ task4 + /// task5 + /// ``` + /// + fn print_deps_tree(&self, config: &Config, tasks: Vec) -> Result<()> { + let deps = Deps::new(config, tasks.clone())?; + // filter out nodes that are not selected + let start_indexes = deps.graph.node_indices().filter(|&idx| { + let task = &deps.graph[idx]; + tasks.iter().any(|t| t.name == task.name) + }); + // iterate over selected graph nodes and print tree + for idx in start_indexes { + print_tree(&(&deps.graph, idx)); + } + Ok(()) + } + + /// + /// Print dependencies in DOT format + /// + /// Example: + /// ``` + /// digraph { + /// 1 [label = "task1"] + /// 2 [label = "task2"] + /// 3 [label = "task3"] + /// 4 [label = "task4"] + /// 5 [label = "task5"] + /// 1 -> 2 [ ] + /// 2 -> 3 [ ] + /// 1 -> 4 [ ] + /// } + /// ``` + // + fn print_deps_dot(&self, config: &Config, tasks: Vec) -> Result<()> { + let deps = Deps::new(config, tasks)?; + miseprintln!( + "{:?}", + Dot::with_attr_getters( + &deps.graph, + &[ + petgraph::dot::Config::NodeNoLabel, + petgraph::dot::Config::EdgeNoLabel + ], + &|_, _| String::new(), + &|_, nr| format!("label = \"{}\"", nr.1.name), + ), + ); + Ok(()) + } + + fn err_no_task(&self, config: &Config, t: &str) -> eyre::Report { + let tasks = config.tasks(); + let task_names = tasks.keys().sorted().map(style::ecyan).join(", "); + let t = style(&t).yellow().for_stderr(); + eyre!("no task named `{t}` found. Available tasks: {task_names}") + } +} + +static AFTER_LONG_HELP: &str = color_print::cstr!( + r#"Examples: + $ mise task deps + Shows dependencies for all tasks + + $ mise task deps lint test check + Shows dependencies for the "lint", "test" and "check" tasks + + $ mise task deps --dot + Shows dependencies in DOT format +"# +); + +#[cfg(test)] +mod tests { + #[test] + fn test_tasks_deps_tree() { + assert_cli_snapshot!("tasks", "deps", @r###" + configtask + filetask + ├── test + └── lint + lint + test + "### + ); + } + + #[test] + fn test_tasks_deps_tree_args() { + assert_cli_snapshot!("tasks", "deps", "filetask", "lint", "test", @r###" + filetask + ├── test + └── lint + lint + test + "### + ); + } + + #[test] + fn test_tasks_deps_dot() { + assert_cli_snapshot!("tasks", "deps", "--dot", @r###" + digraph { + 0 [ label = "configtask"] + 1 [ label = "filetask"] + 2 [ label = "lint"] + 3 [ label = "test"] + 1 -> 2 [ ] + 1 -> 3 [ ] + } + "### + ); + } +} diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs index d218d0ff2..239253aa7 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/task/edit.rs @@ -25,19 +25,23 @@ impl TaskEdit { let settings = Settings::try_get()?; settings.ensure_experimental()?; - let task = config.tasks().get(&self.task).cloned().map_or_else( - || { - let path = config - .project_root - .as_ref() - .unwrap_or(&env::current_dir()?) - .join(".mise") - .join("tasks") - .join(&self.task); - Task::from_path(path) - }, - Ok, - )?; + let task = config + .tasks_with_aliases() + .get(&self.task) + .cloned() + .map_or_else( + || { + let path = config + .project_root + .as_ref() + .unwrap_or(&env::current_dir()?) + .join(".mise") + .join("tasks") + .join(&self.task); + Task::from_path(path) + }, + Ok, + )?; let file = &task.config_source; if !file.exists() { file::create(file)?; diff --git a/src/cli/task/ls.rs b/src/cli/task/ls.rs index aed92bc50..aabd1ed22 100644 --- a/src/cli/task/ls.rs +++ b/src/cli/task/ls.rs @@ -35,7 +35,6 @@ impl TaskLs { let rows = config .tasks() .iter() - .filter(|(n, t)| *n == &t.name) // filter out aliases .map(|(_, t)| t) .sorted() .filter(|t| self.hidden || !t.hide) diff --git a/src/cli/task/mod.rs b/src/cli/task/mod.rs index 16b081f8f..2a0617aed 100644 --- a/src/cli/task/mod.rs +++ b/src/cli/task/mod.rs @@ -3,6 +3,7 @@ use eyre::Result; use crate::cli::run; +mod deps; mod edit; mod ls; @@ -19,6 +20,7 @@ pub struct Task { #[derive(Debug, Subcommand)] enum Commands { + Deps(deps::TaskDeps), Edit(edit::TaskEdit), Ls(ls::TaskLs), Run(run::Run), @@ -27,6 +29,7 @@ enum Commands { impl Commands { pub fn run(self) -> Result<()> { match self { + Self::Deps(cmd) => cmd.run(), Self::Edit(cmd) => cmd.run(), Self::Ls(cmd) => cmd.run(), Self::Run(cmd) => cmd.run(), diff --git a/src/cli/watch.rs b/src/cli/watch.rs index d7cae5924..4266c2c80 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -85,7 +85,7 @@ impl Watch { .iter() .map(|t| { config - .tasks() + .tasks_with_aliases() .get(t) .cloned() .ok_or_else(|| eyre!("Task not found: {t}")) diff --git a/src/config/mod.rs b/src/config/mod.rs index 3ed483b15..3849a4df1 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -44,6 +44,7 @@ pub struct Config { repo_urls: HashMap, shorthands: OnceCell>, tasks: OnceCell>, + tasks_with_aliases: OnceCell>, } static CONFIG: RwLock>> = RwLock::new(None); @@ -84,6 +85,7 @@ impl Config { all_aliases: OnceCell::new(), shorthands: OnceCell::new(), tasks: OnceCell::new(), + tasks_with_aliases: OnceCell::new(), project_root: get_project_root(&config_files), config_files, repo_urls, @@ -111,7 +113,17 @@ impl Config { } pub fn tasks(&self) -> &HashMap { - self.tasks.get_or_init(|| self.load_all_tasks()) + self.tasks.get_or_init(|| { + self.load_all_tasks() + .into_iter() + .filter(|(n, t)| *n == t.name) + .collect() + }) + } + + pub fn tasks_with_aliases(&self) -> &HashMap { + self.tasks_with_aliases + .get_or_init(|| self.load_all_tasks()) } pub fn is_activated(&self) -> bool { diff --git a/src/task.rs b/src/task.rs index b8082d5e3..c2acad0de 100644 --- a/src/task.rs +++ b/src/task.rs @@ -1,9 +1,14 @@ +use petgraph::graph::DiGraph; +use petgraph::prelude::*; +use petgraph::{Direction, Graph}; +use std::borrow::Cow; use std::cmp::Ordering; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::fmt; use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; use std::path::PathBuf; +use std::sync::mpsc; use console::truncate_str; use eyre::Result; @@ -12,6 +17,7 @@ use itertools::Itertools; use crate::config::config_file::toml::TomlParser; use crate::config::Config; use crate::file; +use crate::ui::tree::TreeItem; #[derive(Debug, Default, Clone, Eq, PartialEq)] pub struct Task { @@ -118,7 +124,7 @@ impl Task { } pub fn resolve_depends<'a>(&self, config: &'a Config) -> Result> { - let tasks = config.tasks(); + let tasks = config.tasks_with_aliases(); let depends = self .depends .iter() @@ -180,3 +186,118 @@ impl Hash for Task { self.name.hash(state); } } + +#[derive(Debug)] +pub struct Deps { + pub graph: DiGraph, + sent: HashSet, + tx: mpsc::Sender>, +} + +impl Deps { + pub fn new(config: &Config, tasks: Vec) -> Result { + let mut graph = DiGraph::new(); + let mut indexes = HashMap::new(); + let mut stack = vec![]; + for t in tasks { + stack.push(t.clone()); + indexes + .entry(t.name.clone()) + .or_insert_with(|| graph.add_node(t)); + } + while let Some(a) = stack.pop() { + let a_idx = *indexes + .entry(a.name.clone()) + .or_insert_with(|| graph.add_node(a.clone())); + for b in a.resolve_depends(config)? { + let b_idx = *indexes + .entry(b.name.clone()) + .or_insert_with(|| graph.add_node(b.clone())); + if !graph.contains_edge(a_idx, b_idx) { + graph.add_edge(a_idx, b_idx, ()); + } + stack.push(b.clone()); + } + } + let (tx, _) = mpsc::channel(); + let sent = HashSet::new(); + Ok(Self { graph, tx, sent }) + } + + fn leaves(&self) -> Vec { + self.graph + .externals(Direction::Outgoing) + .map(|idx| self.graph[idx].clone()) + .collect() + } + + fn emit_leaves(&mut self) { + let leaves = self.leaves().into_iter().collect_vec(); + for task in leaves { + if self.sent.contains(&task.name) { + continue; + } + self.sent.insert(task.name.clone()); + self.tx.send(Some(task)).unwrap(); + } + if self.graph.node_count() == 0 { + self.tx.send(None).unwrap(); + } + } + + pub fn subscribe(&mut self) -> mpsc::Receiver> { + let (tx, rx) = mpsc::channel(); + self.tx = tx; + self.emit_leaves(); + rx + } + + // #[requires(self.graph.node_count() > 0)] + // #[ensures(self.graph.node_count() == old(self.graph.node_count()) - 1)] + pub fn remove(&mut self, task: &Task) { + if let Some(idx) = self + .graph + .node_indices() + .find(|&idx| &self.graph[idx] == task) + { + self.graph.remove_node(idx); + self.emit_leaves(); + } + } + + pub fn all(&self) -> impl Iterator { + self.graph.node_indices().map(|idx| &self.graph[idx]) + } + + pub fn is_linear(&self) -> bool { + !self.graph.node_indices().any(|idx| { + self.graph + .neighbors_directed(idx, Direction::Outgoing) + .count() + > 1 + }) + } + + // fn pop(&'a mut self) -> Option<&'a Task> { + // if let Some(leaf) = self.leaves().first() { + // self.remove(&leaf.clone()) + // } else { + // None + // } + // } +} + +impl TreeItem for (&Graph, NodeIndex) { + type Child = Self; + + fn write_self(&self) { + if let Some(w) = self.0.node_weight(self.1) { + miseprint!("{}", w.name); + } + } + + fn children(&self) -> Cow<[Self::Child]> { + let v: Vec<_> = self.0.neighbors(self.1).map(|i| (self.0, i)).collect(); + Cow::from(v) + } +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 8bca0b40c..44eb74f37 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -10,6 +10,7 @@ pub mod progress_report; pub mod prompt; pub mod style; pub mod table; +pub mod tree; pub fn handle_ctrlc() { static ONCE: Once = Once::new(); diff --git a/src/ui/tree.rs b/src/ui/tree.rs new file mode 100644 index 000000000..35c17c1b0 --- /dev/null +++ b/src/ui/tree.rs @@ -0,0 +1,93 @@ +use std::{borrow::Cow, f32::INFINITY}; + +pub trait TreeItem: Clone { + type Child: TreeItem; + + fn write_self(&self); + + fn children(&self) -> Cow<[Self::Child]>; +} + +struct TreeItemIndentChars { + /// Character for pointing down and right (`├`). + pub down_and_right: &'static str, + /// Character for pointing straight down (`|`). + pub down: &'static str, + /// Character for turning from down to right (`â””`). + pub turn_right: &'static str, + /// Character for pointing right (`─`). + pub right: &'static str, + /// Empty character (` `). + pub empty: &'static str, +} + +const TREE_ITEM_CHARS: TreeItemIndentChars = TreeItemIndentChars { + down_and_right: "├", + down: "│", + turn_right: "â””", + right: "─", + empty: " ", +}; + +struct TreeItemIndent { + pub regular_prefix: String, + pub child_prefix: String, + pub last_regular_prefix: String, + pub last_child_prefix: String, +} + +impl TreeItemIndent { + pub fn new( + indent_size: usize, + padding: usize, + characters: &TreeItemIndentChars, + ) -> TreeItemIndent { + let m = 1 + padding; + let n = if indent_size > m { indent_size - m } else { 0 }; + + let right_pad = characters.right.repeat(n); + let empty_pad = characters.empty.repeat(n); + let item_pad = characters.empty.repeat(padding); + + TreeItemIndent { + regular_prefix: format!("{}{}{}", characters.down_and_right, right_pad, item_pad), + child_prefix: format!("{}{}{}", characters.down, empty_pad, item_pad), + last_regular_prefix: format!("{}{}{}", characters.turn_right, right_pad, item_pad), + last_child_prefix: format!("{}{}{}", characters.empty, empty_pad, item_pad), + } + } +} + +pub fn print_tree(item: &T) { + let indent = TreeItemIndent::new(4, 1, &TREE_ITEM_CHARS); + print_tree_item(item, String::from(""), String::from(""), &indent, 0) +} + +fn print_tree_item( + item: &T, + prefix: String, + child_prefix: String, + indent: &TreeItemIndent, + level: u32, +) { + miseprint!("{}", prefix); + item.write_self(); + miseprintln!(""); + + if level < INFINITY as u32 { + let children = item.children(); + if let Some((last_child, children)) = children.split_last() { + let rp = child_prefix.clone() + &indent.regular_prefix; + let cp = child_prefix.clone() + &indent.child_prefix; + + for c in children { + print_tree_item(c, rp.clone(), cp.clone(), indent, level + 1); + } + + let rp = child_prefix.clone() + &indent.last_regular_prefix; + let cp = child_prefix.clone() + &indent.last_child_prefix; + + print_tree_item(last_child, rp, cp, indent, level + 1); + } + } +} From e0ba235d8127a488f29f74dd07a714489ed6bab3 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sat, 13 Jan 2024 21:02:45 +0100 Subject: [PATCH 1622/1891] feat: add completions for task deps command (#1456) * add completions for task deps command * fix inconcise flag comment --- completions/mise.bash | 19 ++++++++++++++++++- completions/mise.fish | 7 ++++++- src/cli/task/deps.rs | 4 ++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/completions/mise.bash b/completions/mise.bash index e54ae876e..d012052dc 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -519,6 +519,9 @@ _mise() { mise__help__sync,python) cmd="mise__help__sync__python" ;; + mise__help__task,deps) + cmd="mise__help__task__deps" + ;; mise__help__task,edit) cmd="mise__help__task__edit" ;; @@ -2505,7 +2508,7 @@ _mise() { return 0 ;; mise__help__task) - opts="edit ls run" + opts="deps edit ls run" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2518,6 +2521,20 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + mise__help__task__deps) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; mise__help__task__edit) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then diff --git a/completions/mise.fish b/completions/mise.fish index 123798678..f48e6ee57 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -282,11 +282,16 @@ complete -kxc mise -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versi # task complete -kxc mise -n "$fssf task" -l hidden -d 'Show hidden tasks' complete -kxc mise -n "$fssf task" -l no-header -d 'Do not print table header' -set -l others edit ls run +set -l others deps edit ls run +complete -xc mise -n "$fssf task; and not $fssf $others" -a deps -d '[experimental] Display a tree visualization of a dependency graph' complete -xc mise -n "$fssf task; and not $fssf $others" -a edit -d '[experimental] Edit a task with $EDITOR' complete -xc mise -n "$fssf task; and not $fssf $others" -a ls -d '[experimental] List available tasks to execute' complete -xc mise -n "$fssf task; and not $fssf $others" -a run -d '[experimental] Run a task' +# task deps +complete -kxc mise -n "$fssf task; and $fssf deps" -l dot -d 'Display dependencies in DOT format' +complete -kxc mise -n "$fssf task; and $fssf deps" -a "(__mise_tasks)" -d 'Tasks to show dependencies for' + # task edit complete -kxc mise -n "$fssf task; and $fssf edit" -s p -l path -d 'Display the path to the task instead of editing it' complete -kxc mise -n "$fssf task; and $fssf edit" -a "(__mise_tasks)" -d 'Task to edit' diff --git a/src/cli/task/deps.rs b/src/cli/task/deps.rs index 1a70171aa..fb415e086 100644 --- a/src/cli/task/deps.rs +++ b/src/cli/task/deps.rs @@ -12,9 +12,9 @@ use petgraph::dot::Dot; #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct TaskDeps { - /// Tasks to get dependencies for + /// Tasks to show dependencies for /// Can specify multiple tasks by separating with spaces - /// e.g.: mise task deps task1 task2 + /// e.g.: mise task deps lint test check #[clap(verbatim_doc_comment)] pub tasks: Option>, From 6a93748572e61c18ec1a798e8e658a72a574ae50 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sun, 14 Jan 2024 14:50:50 +0100 Subject: [PATCH 1623/1891] feat: add interactive selection for tasks if task was not found (#1459) --- src/cli/run.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 7798ec76b..be4790d4f 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -10,8 +10,9 @@ use std::time::SystemTime; use clap::ValueHint; use console::{style, Color}; +use demand::{DemandOption, Select}; use duct::IntoExecutablePath; -use eyre::Result; +use eyre::{OptionExt, Result}; use globwalk::GlobWalkerBuilder; use itertools::Itertools; use once_cell::sync::Lazy; @@ -134,7 +135,7 @@ impl Run { .flat_map(|args| args.split_first().map(|(t, a)| (t.clone(), a.to_vec()))) .map(|(t, args)| match config.tasks_with_aliases().get(&t) { Some(task) => Ok(task.clone().with_args(args.to_vec())), - None => Err(self.err_no_task(config, &t)), + None => self.prompt_for_task(config, &t), }) .collect() } @@ -329,11 +330,23 @@ impl Run { } } - fn err_no_task(&self, config: &Config, t: &str) -> eyre::Report { + fn prompt_for_task(&self, config: &Config, t: &str) -> Result { let tasks = config.tasks(); - let task_names = tasks.keys().sorted().map(style::ecyan).join(", "); + let task_names = tasks.keys().sorted().collect_vec(); let t = style(&t).yellow().for_stderr(); - eyre!("no task named `{t}` found. Available tasks: {task_names}") + let msg = format!("no task named `{t}` found. select a task to run:"); + let mut s = Select::new("Tasks").description(&msg).filterable(true); + for name in task_names { + s = s.option(DemandOption::new(name)); + } + let task_name = s.run(); + match task_name { + Ok(name) => tasks + .get(name) + .cloned() + .ok_or_eyre(format!("no task named `{}` found", name)), + Err(_) => Err(eyre!("there was an error, please try again")), + } } fn validate_task(&self, task: &Task) -> Result<()> { From 3224f7af0f56f88dac412961ebac9898c5d6a3c4 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 14 Jan 2024 07:52:27 -0600 Subject: [PATCH 1624/1891] chore: Release mise version 2024.1.20 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- docs/cli-reference.md | 28 ++++++++++++++++++++++++++++ man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- src/default_shorthands.rs | 5 +++-- 8 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 739128225..ac57187b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.19" +version = "2024.1.20" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 4272bcfa3..c2992e9c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.19" +version = "2024.1.20" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 59fc8af9b..aa20b9ba4 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.19 +mise 2024.1.20 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index e713cbbfd..c9beb0e22 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.19"; + version = "2024.1.20"; src = lib.cleanSource ./.; diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 5103bc7a7..993746471 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -1171,6 +1171,34 @@ Examples: $ mise use -g python@3.11.0 - uses pyenv-provided python ``` +## `mise task deps [OPTIONS] [TASKS]...` + +```text +[experimental] Display a tree visualization of a dependency graph + +Usage: task deps [OPTIONS] [TASKS]... + +Arguments: + [TASKS]... + Tasks to show dependencies for + Can specify multiple tasks by separating with spaces + e.g.: mise task deps lint test check + +Options: + --dot + Display dependencies in DOT format + +Examples: + $ mise task deps + Shows dependencies for all tasks + + $ mise task deps lint test check + Shows dependencies for the "lint", "test" and "check" tasks + + $ mise task deps --dot + Shows dependencies in DOT format +``` + ## `mise task edit [OPTIONS] ` ```text diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 180f4cc94..9ca2fadb7 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.19" +.TH mise 1 "mise 2024.1.20" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.19 +v2024.1.20 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 0d3025300..17828f92e 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.19 +Version: 2024.1.20 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 550a855db..394798fd5 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -22,7 +22,6 @@ use std::collections::{HashMap, HashSet}; pub static DEFAULT_SHORTHANDS: Lazy> = Lazy::new(|| HashMap::from([ ("1password-cli", "https://github.com/NeoHsu/asdf-1password-cli.git"), - ("R", "https://github.com/asdf-community/asdf-r.git"), ("act", "https://github.com/grimoh/asdf-act.git"), ("action-validator", "https://github.com/mpalmer/action-validator.git"), ("actionlint", "https://github.com/crazy-matt/asdf-actionlint.git"), @@ -143,7 +142,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("conftest", "https://github.com/looztra/asdf-conftest.git"), ("consul", "https://github.com/asdf-community/asdf-hashicorp.git"), ("container-diff", "https://github.com/cgroschupp/asdf-container-diff.git"), - ("container-structure-test", "https://github.com/jonathanmorley/asdf-container-structure-test.git"), + ("container-structure-test", "https://github.com/FeryET/asdf-container-structure-test.git"), ("cookiecutter", "https://github.com/shawon-crosen/asdf-cookiecutter.git"), ("copper", "https://github.com/vladlosev/asdf-copper.git"), ("coq", "https://github.com/gingerhot/asdf-coq.git"), @@ -199,6 +198,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("dust", "https://github.com/looztra/asdf-dust.git"), ("dvc", "https://github.com/fwfurtado/asdf-dvc.git"), ("dyff", "https://gitlab.com/wt0f/asdf-dyff.git"), + ("earthly", "https://github.com/YR-ZR0/asdf-earthly"), ("ecspresso", "https://github.com/kayac/asdf-ecspresso.git"), ("editorconfig-checker", "https://github.com/gabitchov/asdf-editorconfig-checker.git"), ("ejson", "https://github.com/cipherstash/asdf-ejson.git"), @@ -547,6 +547,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("purty", "https://github.com/nsaunders/asdf-purty.git"), ("qdns", "https://github.com/moritz-makandra/asdf-plugin-qdns.git"), ("quarkus", "https://github.com/asdf-community/asdf-quarkus.git"), + ("r", "https://github.com/asdf-community/asdf-r.git"), ("rabbitmq", "https://github.com/w-sanches/asdf-rabbitmq.git"), ("racket", "https://github.com/asdf-community/asdf-racket.git"), ("raku", "https://github.com/m-dango/asdf-raku.git"), From d52d2ca064f3ceed70ed96db3912cda909d02c23 Mon Sep 17 00:00:00 2001 From: Roland Schaer Date: Sun, 14 Jan 2024 22:15:29 +0100 Subject: [PATCH 1625/1891] fix: bail out of task suggestion if there are no tasks (#1460) --- src/cli/run.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cli/run.rs b/src/cli/run.rs index be4790d4f..b078dc703 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -332,6 +332,12 @@ impl Run { fn prompt_for_task(&self, config: &Config, t: &str) -> Result { let tasks = config.tasks(); + if tasks.is_empty() { + bail!(format!( + "no tasks defined. see {url}", + url = style("https://mise.jdx.dev/tasks/").underlined() + )); + } let task_names = tasks.keys().sorted().collect_vec(); let t = style(&t).yellow().for_stderr(); let msg = format!("no task named `{t}` found. select a task to run:"); From 74c5210b9f35bd05ac53a417ac5e152dda256a9e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 14 Jan 2024 18:02:22 -0600 Subject: [PATCH 1626/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa20b9ba4..16e2c0e84 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ## What is it? -* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages dev tools like node, python, cmake, terraform, and [hundreds more](https://mise.jdx.dev/plugins.html). +* Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages [dev tools](https://mise.jdx.dev/dev-tools/) like node, python, cmake, terraform, and [hundreds more](https://mise.jdx.dev/plugins.html). * Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://mise.jdx.dev/environments.html) for different project directories. * Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://mise.jdx.dev/tasks/) used to build and test projects. From 22265e5ea6d3b9498eb11eef14a77c3ba46cae03 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 14 Jan 2024 22:23:51 -0600 Subject: [PATCH 1627/1891] fixed urls --- completions/_mise | 12 + completions/mise.bash | 50 +- completions/mise.fish | 2 +- docs/cli-reference.md | 1633 ------------------------------------ src/cli/plugins/install.rs | 2 +- src/cli/plugins/ls.rs | 4 +- src/cli/plugins/mod.rs | 2 +- 7 files changed, 65 insertions(+), 1640 deletions(-) delete mode 100644 docs/cli-reference.md diff --git a/completions/_mise b/completions/_mise index 9699c1ebd..21667efb3 100644 --- a/completions/_mise +++ b/completions/_mise @@ -741,6 +741,7 @@ __mise_task_cmd() { (args) curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in + (deps) __mise_task_deps_cmd && ret=0 ;; (edit) __mise_task_edit_cmd && ret=0 ;; (ls) __mise_task_ls_cmd && ret=0 ;; (r|run) __mise_task_run_cmd && ret=0 ;; @@ -750,6 +751,16 @@ __mise_task_cmd() { return ret } +(( $+functions[__mise_task_deps_cmd] )) || +__mise_task_deps_cmd() { + _arguments -s -S \ + '*::tasks:' \ + '--dot[Display dependencies in DOT format]' \ + '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ + '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ + '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ + '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' +} (( $+functions[__mise_task_edit_cmd] )) || __mise_task_edit_cmd() { _arguments -s -S \ @@ -1000,6 +1011,7 @@ __mise_sync_cmds() { (( $+functions[__mise_task_cmds] )) || __mise_task_cmds() { local commands; commands=( + 'deps:\[experimental\] Display a tree visualization of a dependency graph' 'edit:\[experimental\] Edit a task with \$EDITOR' 'ls:\[experimental\] List available tasks to execute' {r,run}':\[experimental\] Run a task' diff --git a/completions/mise.bash b/completions/mise.bash index d012052dc..3102ecbd4 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -672,6 +672,9 @@ _mise() { mise__sync__help,python) cmd="mise__sync__help__python" ;; + mise__task,deps) + cmd="mise__task__deps" + ;; mise__task,edit) cmd="mise__task__edit" ;; @@ -687,6 +690,9 @@ _mise() { mise__task,run) cmd="mise__task__run" ;; + mise__task__help,deps) + cmd="mise__task__help__deps" + ;; mise__task__help,edit) cmd="mise__task__help__edit" ;; @@ -3928,7 +3934,7 @@ _mise() { return 0 ;; mise__task) - opts="-C -q -v -y -h --no-header --hidden --cd --debug --log-level --quiet --trace --verbose --yes --help edit ls run help" + opts="-C -q -v -y -h --no-header --hidden --cd --debug --log-level --quiet --trace --verbose --yes --help deps edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3953,6 +3959,32 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + mise__task__deps) + opts="-C -q -v -y -h --dot --cd --debug --log-level --quiet --trace --verbose --yes --help [TASKS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --cd) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -C) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --log-level) + COMPREPLY=($(compgen -W "error warn info debug trace" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; mise__task__edit) opts="-p -C -q -v -y -h --path --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -3980,7 +4012,7 @@ _mise() { return 0 ;; mise__task__help) - opts="edit ls run help" + opts="deps edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3993,6 +4025,20 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + mise__task__help__deps) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; mise__task__help__edit) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then diff --git a/completions/mise.fish b/completions/mise.fish index f48e6ee57..487c1acf5 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -290,7 +290,7 @@ complete -xc mise -n "$fssf task; and not $fssf $others" -a run -d '[experimenta # task deps complete -kxc mise -n "$fssf task; and $fssf deps" -l dot -d 'Display dependencies in DOT format' -complete -kxc mise -n "$fssf task; and $fssf deps" -a "(__mise_tasks)" -d 'Tasks to show dependencies for' +complete -kxc mise -n "$fssf task; and $fssf deps" -d 'Tasks to show dependencies for' # task edit complete -kxc mise -n "$fssf task; and $fssf edit" -s p -l path -d 'Display the path to the task instead of editing it' diff --git a/docs/cli-reference.md b/docs/cli-reference.md deleted file mode 100644 index 993746471..000000000 --- a/docs/cli-reference.md +++ /dev/null @@ -1,1633 +0,0 @@ - - -# Commands - -## `mise activate [OPTIONS] [SHELL_TYPE]` - -```text -Initializes mise in the current shell session - -This should go into your shell's rc file. -Otherwise, it will only take effect in the current session. -(e.g. ~/.zshrc, ~/.bashrc) - -This is only intended to be used in interactive sessions, not scripts. -mise is only capable of updating PATH when the prompt is displayed to the user. -For non-interactive use-cases, use shims instead. - -Typically this can be added with something like the following: - - echo 'eval "$(mise activate)"' >> ~/.zshrc - -However, this requires that "mise" is in your PATH. If it is not, you need to -specify the full path like this: - - echo 'eval "$(/path/to/mise activate)"' >> ~/.zshrc - -Usage: activate [OPTIONS] [SHELL_TYPE] - -Arguments: - [SHELL_TYPE] - Shell type to generate the script for - - [possible values: bash, fish, nu, xonsh, zsh] - -Options: - --status - Show "mise: @" message when changing directories - - -q, --quiet - Suppress non-error messages - -Examples: - $ eval "$(mise activate bash)" - $ eval "$(mise activate zsh)" - $ mise activate fish | source - $ execx($(mise activate xonsh)) -``` - -## `mise alias get ` - -```text -Show an alias for a plugin - -This is the contents of an alias. entry in ~/.config/mise/config.toml - -Usage: alias get - -Arguments: - - The plugin to show the alias for - - - The alias to show - -Examples: - $ mise alias get node lts-hydrogen - 20.0.0 -``` - -## `mise alias ls [OPTIONS] [PLUGIN]` - -**Aliases:** `list` - -```text -List aliases -Shows the aliases that can be specified. -These can come from user config or from plugins in `bin/list-aliases`. - -For user config, aliases are defined like the following in `~/.config/mise/config.toml`: - - [alias.node] - lts = "20.0.0" - -Usage: alias ls [OPTIONS] [PLUGIN] - -Arguments: - [PLUGIN] - Show aliases for - -Options: - --no-header - Don't show table header - -Examples: - $ mise aliases - node lts-hydrogen 20.0.0 -``` - -## `mise alias set ` - -**Aliases:** `add, create` - -```text -Add/update an alias for a plugin - -This modifies the contents of ~/.config/mise/config.toml - -Usage: alias set - -Arguments: - - The plugin to set the alias for - - - The alias to set - - - The value to set the alias to - -Examples: - $ mise alias set node lts-hydrogen 18.0.0 -``` - -## `mise alias unset ` - -**Aliases:** `del, delete, remove, rm` - -```text -Clears an alias for a plugin - -This modifies the contents of ~/.config/mise/config.toml - -Usage: alias unset - -Arguments: - - The plugin to remove the alias from - - - The alias to remove - -Examples: - $ mise alias unset node lts-hydrogen -``` - -## `mise bin-paths` - -```text -List all the active runtime bin paths - -Usage: bin-paths -``` - -## `mise cache clear [PLUGIN]...` - -**Aliases:** `c` - -```text -Deletes all cache files in mise - -Usage: cache clear [PLUGIN]... - -Arguments: - [PLUGIN]... - Plugin(s) to clear cache for e.g.: node, python -``` - -## `mise completion [SHELL]` - -```text -Generate shell completions - -Usage: completion [SHELL] - -Arguments: - [SHELL] - Shell type to generate completions for - - [possible values: bash, fish, zsh] - -Examples: - $ mise completion bash > /etc/bash_completion.d/mise - $ mise completion zsh > /usr/local/share/zsh/site-functions/_mise - $ mise completion fish > ~/.config/fish/completions/mise.fish -``` - -## `mise config ls [OPTIONS]` - -```text -[experimental] List config files currently in use - -Usage: config ls [OPTIONS] - -Options: - --no-header - Do not print table header - -Examples: - $ mise config ls -``` - -## `mise config generate [OPTIONS]` - -**Aliases:** `g` - -```text -[experimental] Generate an .mise.toml file - -Usage: config generate [OPTIONS] - -Options: - -o, --output - Output to file instead of stdout - -Examples: - $ mise cf generate > .mise.toml - $ mise cf generate --output=.mise.toml -``` - -## `mise current [PLUGIN]` - -```text -Shows current active and installed runtime versions - -This is similar to `mise ls --current`, but this only shows the runtime -and/or version. It's designed to fit into scripts more easily. - -Usage: current [PLUGIN] - -Arguments: - [PLUGIN] - Plugin to show versions of e.g.: ruby, node, cargo:eza, npm:prettier, etc - -Examples: - # outputs `.tool-versions` compatible format - $ mise current - python 3.11.0 3.10.0 - shfmt 3.6.0 - shellcheck 0.9.0 - node 20.0.0 - - $ mise current node - 20.0.0 - - # can output multiple versions - $ mise current python - 3.11.0 3.10.0 -``` - -## `mise deactivate` - -```text -Disable mise for current shell session - -This can be used to temporarily disable mise in a shell session. - -Usage: deactivate - -Examples: - $ mise deactivate bash - $ mise deactivate zsh - $ mise deactivate fish - $ execx($(mise deactivate xonsh)) -``` - -## `mise direnv activate` - -```text -Output direnv function to use mise inside direnv - -See https://mise.jdx.dev/direnv.html for more information - -Because this generates the legacy files based on currently installed plugins, -you should run this command after installing new plugins. Otherwise -direnv may not know to update environment variables when legacy file versions change. - -Usage: direnv activate - -Examples: - $ mise direnv activate > ~/.config/direnv/lib/use_mise.sh - $ echo 'use mise' > .envrc - $ direnv allow -``` - -## `mise doctor` - -```text -Check mise installation for possible problems. - -Usage: doctor - -Examples: - $ mise doctor - [WARN] plugin node is not installed -``` - -## `mise env [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `e` - -```text -Exports env vars to activate mise a single time - -Use this if you don't want to permanently install mise. It's not necessary to -use this if you have `mise activate` in your shell rc file. - -Usage: env [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to use - -Options: - -s, --shell - Shell type to generate environment variables for - - [possible values: bash, fish, nu, xonsh, zsh] - - -J, --json - Output in JSON format - -Examples: - $ eval "$(mise env -s bash)" - $ eval "$(mise env -s zsh)" - $ mise env -s fish | source - $ execx($(mise env -s xonsh)) -``` - -## `mise exec [OPTIONS] [TOOL@VERSION]... [-- ...]` - -**Aliases:** `x` - -```text -Execute a command with tool(s) set - -use this to avoid modifying the shell session or running ad-hoc commands with mise tools set. - -Tools will be loaded from .mise.toml/.tool-versions, though they can be overridden with args -Note that only the plugin specified will be overridden, so if a `.tool-versions` file -includes "node 20" but you run `mise exec python@3.11`; it will still load node@20. - -The "--" separates runtimes from the commands to pass along to the subprocess. - -Usage: exec [OPTIONS] [TOOL@VERSION]... [-- ...] - -Arguments: - [TOOL@VERSION]... - Tool(s) to start e.g.: node@20 python@3.10 - - [COMMAND]... - Command string to execute (same as --command) - -Options: - -c, --command - Command string to execute - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: MISE_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - -Examples: - $ mise exec node@20 -- node ./app.js # launch app.js using node-20.x - $ mise x node@20 -- node ./app.js # shorter alias - - # Specify command as a string: - $ mise exec node@20 python@3.11 --command "node -v && python -V" - - # Run a command in a different directory: - $ mise x -C /path/to/project node@20 -- node ./app.js -``` - -## `mise implode [OPTIONS]` - -```text -Removes mise CLI and all related data - -Skips config directory by default. - -Usage: implode [OPTIONS] - -Options: - --config - Also remove config directory - - -n, --dry-run - List directories that would be removed without actually removing them -``` - -## `mise install [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `i` - -```text -Install a tool version - -This will install a tool version to `~/.local/share/mise/installs//` -It won't be used simply by being installed, however. -For that, you must set up a `.mise.toml`/`.tool-version` file manually or with `mise use`. -Or you can call a tool version explicitly with `mise exec @ -- `. - -Tools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1` - -Usage: install [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to install e.g.: node@20 - -Options: - -f, --force - Force reinstall even if already installed - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: MISE_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - - -v, --verbose... - Show installation output - -Examples: - $ mise install node@20.0.0 # install specific node version - $ mise install node@20 # install fuzzy node version - $ mise install node # install version specified in .tool-versions or .mise.toml - $ mise install # installs everything specified in .tool-versions or .mise.toml -``` - -## `mise latest [OPTIONS] ` - -```text -Gets the latest available version for a plugin - -Usage: latest [OPTIONS] - -Arguments: - - Tool to get the latest version of - -Options: - -i, --installed - Show latest installed instead of available version - -Examples: - $ mise latest node@20 # get the latest version of node 20 - 20.0.0 - - $ mise latest node # get the latest stable version of node - 20.0.0 -``` - -## `mise link [OPTIONS] ` - -**Aliases:** `ln` - -```text -Symlinks a tool version into mise - -Use this for adding installs either custom compiled outside -mise or built with a different tool. - -Usage: link [OPTIONS] - -Arguments: - - Tool name and version to create a symlink for - - - The local path to the tool version - e.g.: ~/.nvm/versions/node/v20.0.0 - -Options: - -f, --force - Overwrite an existing tool version if it exists - -Examples: - # build node-20.0.0 with node-build and link it into mise - $ node-build 20.0.0 ~/.nodes/20.0.0 - $ mise link node@20.0.0 ~/.nodes/20.0.0 - - # have mise use the python version provided by Homebrew - $ brew install node - $ mise link node@brew $(brew --prefix node) - $ mise use node@brew -``` - -## `mise ls [OPTIONS] [PLUGIN]...` - -**Aliases:** `list` - -```text -List installed and/or currently selected tool versions - -Usage: ls [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Only show tool versions from [PLUGIN] - -Options: - -c, --current - Only show tool versions currently specified in a .tool-versions/.mise.toml - - -g, --global - Only show tool versions currently specified in a the global .tool-versions/.mise.toml - - -i, --installed - Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed - - -J, --json - Output in json format - - -m, --missing - Display missing tool versions - - --prefix - Display versions matching this prefix - - --no-header - Don't display headers - -Examples: - $ mise ls - node 20.0.0 ~/src/myapp/.tool-versions latest - python 3.11.0 ~/.tool-versions 3.10 - python 3.10.0 - - $ mise ls --current - node 20.0.0 ~/src/myapp/.tool-versions 20 - python 3.11.0 ~/.tool-versions 3.11.0 - - $ mise ls --json - { - "node": [ - { - "version": "20.0.0", - "install_path": "/Users/jdx/.mise/installs/node/20.0.0", - "source": { - "type": ".mise.toml", - "path": "/Users/jdx/.mise.toml" - } - } - ], - "python": [...] - } -``` - -## `mise ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` - -```text -List runtime versions available for install - -note that the results are cached for 24 hours -run `mise cache clean` to clear the cache and get fresh results - -Usage: ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX] - -Arguments: - [TOOL@VERSION] - Plugin to get versions for - - [PREFIX] - The version prefix to use when querying the latest version - same as the first argument after the "@" - -Options: - --all - Show all installed plugins and versions - -Examples: - $ mise ls-remote node - 18.0.0 - 20.0.0 - - $ mise ls-remote node@20 - 20.0.0 - 20.1.0 - - $ mise ls-remote node 20 - 20.0.0 - 20.1.0 -``` - -## `mise outdated [TOOL@VERSION]...` - -```text -Shows outdated tool versions - -Usage: outdated [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to show outdated versions for - e.g.: node@20 python@3.10 - If not specified, all tools in global and local configs will be shown - -Examples: - $ mise outdated - Plugin Requested Current Latest - python 3.11 3.11.0 3.11.1 - node 20 20.0.0 20.1.0 - - $ mise outdated node - Plugin Requested Current Latest - node 20 20.0.0 20.1.0 -``` - -## `mise plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` - -**Aliases:** `a, add, i` - -```text -Install a plugin - -note that mise automatically can install plugins when you install a tool -e.g.: `mise install node@20` will autoinstall the node plugin - -This behavior can be modified in ~/.config/mise/config.toml - -Usage: plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL] - -Arguments: - [NEW_PLUGIN] - The name of the plugin to install - e.g.: node, ruby - Can specify multiple plugins: `mise plugins install node ruby python` - - [GIT_URL] - The git url of the plugin - -Options: - -f, --force - Reinstall even if plugin exists - - -a, --all - Install all missing plugins - This will only install plugins that have matching shorthands. - i.e.: they don't need the full git repo url - - -v, --verbose... - Show installation output - -Examples: - # install the node via shorthand - $ mise plugins install node - - # install the node plugin using a specific git url - $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git - - # install the node plugin using the git url only - # (node is inferred from the url) - $ mise plugins install https://github.com/mise-plugins/rtx-nodejs.git - - # install the node plugin using a specific ref - $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git#v1.0.0 -``` - -## `mise plugins link [OPTIONS] [PATH]` - -**Aliases:** `ln` - -```text -Symlinks a plugin into mise - -This is used for developing a plugin. - -Usage: plugins link [OPTIONS] [PATH] - -Arguments: - - The name of the plugin - e.g.: node, ruby - - [PATH] - The local path to the plugin - e.g.: ./mise-node - -Options: - -f, --force - Overwrite existing plugin - -Examples: - # essentially just `ln -s ./mise-node ~/.local/share/mise/plugins/node` - $ mise plugins link node ./mise-node - - # infer plugin name as "node" - $ mise plugins link ./mise-node -``` - -## `mise plugins ls [OPTIONS]` - -**Aliases:** `list` - -```text -List installed plugins - -Can also show remotely available plugins to install. - -Usage: plugins ls [OPTIONS] - -Options: - -c, --core - The built-in plugins only - Normally these are not shown - - --user - List installed plugins - - This is the default behavior but can be used with --core - to show core and user plugins - - -u, --urls - Show the git url for each plugin - e.g.: https://github.com/asdf-vm/asdf-node.git - -Examples: - $ mise plugins ls - node - ruby - - $ mise plugins ls --urls - node https://github.com/asdf-vm/asdf-node.git - ruby https://github.com/asdf-vm/asdf-ruby.git -``` - -## `mise plugins ls-remote [OPTIONS]` - -**Aliases:** `list-all, list-remote` - -```text -List all available remote plugins - -The full list is here: https://github.com/jdx/mise/blob/main/src/default_shorthands.rs - -Examples: - $ mise plugins ls-remote - - -Usage: plugins ls-remote [OPTIONS] - -Options: - -u, --urls - Show the git url for each plugin e.g.: https://github.com/mise-plugins/rtx-nodejs.git - - --only-names - Only show the name of each plugin by default it will show a "*" next to installed plugins -``` - -## `mise plugins uninstall [OPTIONS] [PLUGIN]...` - -**Aliases:** `remove, rm` - -```text -Removes a plugin - -Usage: plugins uninstall [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Plugin(s) to remove - -Options: - -p, --purge - Also remove the plugin's installs, downloads, and cache - - -a, --all - Remove all plugins - -Examples: - $ mise uninstall node -``` - -## `mise plugins update [OPTIONS] [PLUGIN]...` - -**Aliases:** `upgrade` - -```text -Updates a plugin to the latest version - -note: this updates the plugin itself, not the runtime versions - -Usage: plugins update [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Plugin(s) to update - -Options: - -j, --jobs - Number of jobs to run in parallel - Default: 4 - -Examples: - $ mise plugins update # update all plugins - $ mise plugins update node # update only node - $ mise plugins update node#beta # specify a ref -``` - -## `mise prune [OPTIONS] [PLUGIN]...` - -```text -Delete unused versions of tools - -mise tracks which config files have been used in ~/.local/share/mise/tracked_config_files -Versions which are no longer the latest specified in any of those configs are deleted. -Versions installed only with environment variables (`MISE__VERSION`) will be deleted, -as will versions only referenced on the command line (`mise exec @`). - -Usage: prune [OPTIONS] [PLUGIN]... - -Arguments: - [PLUGIN]... - Prune only versions from this plugin(s) - -Options: - -n, --dry-run - Do not actually delete anything - -Examples: - $ mise prune --dry-run - rm -rf ~/.local/share/mise/versions/node/20.0.0 - rm -rf ~/.local/share/mise/versions/node/20.0.1 -``` - -## `mise reshim` - -```text -rebuilds the shim farm - -This creates new shims in ~/.local/share/mise/shims for CLIs that have been added. -mise will try to do this automatically for commands like `npm i -g` but there are -other ways to install things (like using yarn or pnpm for node) that mise does -not know about and so it will be necessary to call this explicitly. - -If you think mise should automatically call this for a particular command, please -open an issue on the mise repo. You can also setup a shell function to reshim -automatically (it's really fast so you don't need to worry about overhead): - -npm() { - command npm "$@" - mise reshim -} - -Usage: reshim - -Examples: - $ mise reshim - $ ~/.local/share/mise/shims/node -v - v20.0.0 -``` - -## `mise run [OPTIONS] [TASK] [ARGS]...` - -**Aliases:** `r` - -```text -[experimental] Run a task - -This command will run a task, or multiple tasks in parallel. -Tasks may have dependencies on other tasks or on source files. -If source is configured on a task, it will only run if the source -files have changed. - -Tasks can be defined in .mise.toml or as standalone scripts. -In .mise.toml, tasks take this form: - - [tasks.build] - run = "npm run build" - sources = ["src/**/*.ts"] - outputs = ["dist/**/*.js"] - -Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.mise/tasks` directory. -The name of the script will be the name of the task. - - $ cat .mise/tasks/build< - Change to this directory before executing the command - - -n, --dry-run - Don't actually run the task(s), just print them in order of execution - - -f, --force - Force the task to run even if outputs are up to date - - -p, --prefix - Print stdout/stderr by line, prefixed with the task's label - Defaults to true if --jobs > 1 - Configure with `task_output` config or `MISE_TASK_OUTPUT` env var - - -i, --interleave - Print directly to stdout/stderr instead of by line - Defaults to true if --jobs == 1 - Configure with `task_output` config or `MISE_TASK_OUTPUT` env var - - -t, --tool - Tool(s) to also add e.g.: node@20 python@3.10 - - -j, --jobs - Number of tasks to run in parallel - [default: 4] - Configure with `jobs` config or `MISE_JOBS` env var - - [env: MISE_JOBS=] - - -r, --raw - Read/write directly to stdin/stdout/stderr instead of by line - Configure with `raw` config or `MISE_RAW` env var - -Examples: - $ mise run lint - Runs the "lint" task. This needs to either be defined in .mise.toml - or as a standalone script. See the project README for more information. - - $ mise run build --force - Forces the "build" task to run even if its sources are up-to-date. - - $ mise run test --raw - Runs "test" with stdin/stdout/stderr all connected to the current terminal. - This forces `--jobs=1` to prevent interleaving of output. - - $ mise run lint ::: test ::: check - Runs the "lint", "test", and "check" tasks in parallel. - - $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 - Execute multiple tasks each with their own arguments. -``` - -## `mise self-update [OPTIONS] [VERSION]` - -```text -Updates mise itself - -Uses the GitHub Releases API to find the latest release and binary -By default, this will also update any installed plugins - -Usage: self-update [OPTIONS] [VERSION] - -Arguments: - [VERSION] - Update to a specific version - -Options: - -f, --force - Update even if already up to date - - --no-plugins - Disable auto-updating plugins - - -y, --yes - Skip confirmation prompt -``` - -## `mise set [OPTIONS] [ENV_VARS]...` - -```text -Manage environment variables - -By default this command modifies ".mise.toml" in the current directory. - -Usage: set [OPTIONS] [ENV_VARS]... - -Arguments: - [ENV_VARS]... - Environment variable(s) to set - e.g.: NODE_ENV=production - -Options: - --file - The TOML file to update - - Defaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or ".mise.toml". - - -g, --global - Set the environment variable in the global config file - -Examples: - $ mise set NODE_ENV=production - - $ mise set NODE_ENV - production - - $ mise set - key value source - NODE_ENV production ~/.config/mise/config.toml -``` - -## `mise settings get ` - -```text -Show a current setting - -This is the contents of a single entry in ~/.config/mise/config.toml - -Note that aliases are also stored in this file -but managed separately with `mise aliases get` - -Usage: settings get - -Arguments: - - The setting to show - -Examples: - $ mise settings get legacy_version_file - true -``` - -## `mise settings ls` - -**Aliases:** `list` - -```text -Show current settings - -This is the contents of ~/.config/mise/config.toml - -Note that aliases are also stored in this file -but managed separately with `mise aliases` - -Usage: settings ls - -Examples: - $ mise settings - legacy_version_file = false -``` - -## `mise settings set ` - -**Aliases:** `add, create` - -```text -Add/update a setting - -This modifies the contents of ~/.config/mise/config.toml - -Usage: settings set - -Arguments: - - The setting to set - - - The value to set - -Examples: - $ mise settings set legacy_version_file true -``` - -## `mise settings unset ` - -**Aliases:** `del, delete, remove, rm` - -```text -Clears a setting - -This modifies the contents of ~/.config/mise/config.toml - -Usage: settings unset - -Arguments: - - The setting to remove - -Examples: - $ mise settings unset legacy_version_file -``` - -## `mise shell [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `sh` - -```text -Sets a tool version for the current shell session - -Only works in a session where mise is already activated. - -Usage: shell [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to use - -Options: - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: MISE_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - - -u, --unset - Removes a previously set version - -Examples: - $ mise shell node@20 - $ node -v - v20.0.0 -``` - -## `mise sync node <--brew|--nvm|--nodenv>` - -```text -Symlinks all tool versions from an external tool into mise - -For example, use this to import all Homebrew node installs into mise - -Usage: sync node <--brew|--nvm|--nodenv> - -Options: - --brew - Get tool versions from Homebrew - - --nvm - Get tool versions from nvm - - --nodenv - Get tool versions from nodenv - -Examples: - $ brew install node@18 node@20 - $ mise sync node --brew - $ mise use -g node@18 - uses Homebrew-provided node -``` - -## `mise sync python --pyenv` - -```text -Symlinks all tool versions from an external tool into mise - -For example, use this to import all pyenv installs into mise - -Usage: sync python --pyenv - -Options: - --pyenv - Get tool versions from pyenv - -Examples: - $ pyenv install 3.11.0 - $ mise sync python --pyenv - $ mise use -g python@3.11.0 - uses pyenv-provided python -``` - -## `mise task deps [OPTIONS] [TASKS]...` - -```text -[experimental] Display a tree visualization of a dependency graph - -Usage: task deps [OPTIONS] [TASKS]... - -Arguments: - [TASKS]... - Tasks to show dependencies for - Can specify multiple tasks by separating with spaces - e.g.: mise task deps lint test check - -Options: - --dot - Display dependencies in DOT format - -Examples: - $ mise task deps - Shows dependencies for all tasks - - $ mise task deps lint test check - Shows dependencies for the "lint", "test" and "check" tasks - - $ mise task deps --dot - Shows dependencies in DOT format -``` - -## `mise task edit [OPTIONS] ` - -```text -[experimental] Edit a task with $EDITOR - -The task will be created as a standalone script if it does not already exist. - -Usage: task edit [OPTIONS] - -Arguments: - - Task to edit - -Options: - -p, --path - Display the path to the task instead of editing it - -Examples: - $ mise task edit build - $ mise task edit test -``` - -## `mise task ls [OPTIONS]` - -```text -[experimental] List available tasks to execute -These may be included from the config file or from the project's .mise/tasks directory -mise will merge all tasks from all parent directories into this list. - -So if you have global tasks in ~/.config/mise/tasks/* and project-specific tasks in -~/myproject/.mise/tasks/*, then they'll both be available but the project-specific -tasks will override the global ones if they have the same name. - -Usage: task ls [OPTIONS] - -Options: - --no-header - Do not print table header - - --hidden - Show hidden tasks - -Examples: - $ mise task ls -``` - -## `mise task run [OPTIONS] [TASK] [ARGS]...` - -**Aliases:** `r` - -```text -[experimental] Run a task - -This command will run a task, or multiple tasks in parallel. -Tasks may have dependencies on other tasks or on source files. -If source is configured on a task, it will only run if the source -files have changed. - -Tasks can be defined in .mise.toml or as standalone scripts. -In .mise.toml, tasks take this form: - - [tasks.build] - run = "npm run build" - sources = ["src/**/*.ts"] - outputs = ["dist/**/*.js"] - -Alternatively, tasks can be defined as standalone scripts. -These must be located in the `.mise/tasks` directory. -The name of the script will be the name of the task. - - $ cat .mise/tasks/build< - Change to this directory before executing the command - - -n, --dry-run - Don't actually run the task(s), just print them in order of execution - - -f, --force - Force the task to run even if outputs are up to date - - -p, --prefix - Print stdout/stderr by line, prefixed with the task's label - Defaults to true if --jobs > 1 - Configure with `task_output` config or `MISE_TASK_OUTPUT` env var - - -i, --interleave - Print directly to stdout/stderr instead of by line - Defaults to true if --jobs == 1 - Configure with `task_output` config or `MISE_TASK_OUTPUT` env var - - -t, --tool - Tool(s) to also add e.g.: node@20 python@3.10 - - -j, --jobs - Number of tasks to run in parallel - [default: 4] - Configure with `jobs` config or `MISE_JOBS` env var - - [env: MISE_JOBS=] - - -r, --raw - Read/write directly to stdin/stdout/stderr instead of by line - Configure with `raw` config or `MISE_RAW` env var - -Examples: - $ mise run lint - Runs the "lint" task. This needs to either be defined in .mise.toml - or as a standalone script. See the project README for more information. - - $ mise run build --force - Forces the "build" task to run even if its sources are up-to-date. - - $ mise run test --raw - Runs "test" with stdin/stdout/stderr all connected to the current terminal. - This forces `--jobs=1` to prevent interleaving of output. - - $ mise run lint ::: test ::: check - Runs the "lint", "test", and "check" tasks in parallel. - - $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 - Execute multiple tasks each with their own arguments. -``` - -## `mise trust [OPTIONS] [CONFIG_FILE]` - -```text -Marks a config file as trusted - -This means mise will parse the file with potentially dangerous -features enabled. - -This includes: -- environment variables -- templates -- `path:` plugin versions - -Usage: trust [OPTIONS] [CONFIG_FILE] - -Arguments: - [CONFIG_FILE] - The config file to trust - -Options: - -a, --all - Trust all config files in the current directory and its parents - - --untrust - No longer trust this config - -Examples: - # trusts ~/some_dir/.mise.toml - $ mise trust ~/some_dir/.mise.toml - - # trusts .mise.toml in the current or parent directory - $ mise trust -``` - -## `mise uninstall [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `remove, rm` - -```text -Removes runtime versions - -Usage: uninstall [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to remove - -Options: - -a, --all - Delete all installed versions - - -n, --dry-run - Do not actually delete anything - -Examples: - $ mise uninstall node@18.0.0 # will uninstall specific version - $ mise uninstall node # will uninstall current node version - $ mise uninstall --all node@18.0.0 # will uninstall all node versions -``` - -## `mise unset [OPTIONS] [KEYS]...` - -```text -Remove environment variable(s) from the config file - -By default this command modifies ".mise.toml" in the current directory. - -Usage: unset [OPTIONS] [KEYS]... - -Arguments: - [KEYS]... - Environment variable(s) to remove - e.g.: NODE_ENV - -Options: - -f, --file - Specify a file to use instead of ".mise.toml" - - -g, --global - Use the global config file -``` - -## `mise upgrade [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `up` - -```text -Upgrades outdated tool versions - -Usage: upgrade [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to upgrade - e.g.: node@20 python@3.10 - If not specified, all current tools will be upgraded - -Options: - -n, --dry-run - Just print what would be done, don't actually do it - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: MISE_JOBS=] - - -i, --interactive - Display multiselect menu to choose which tools to upgrade - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 -``` - -## `mise use [OPTIONS] [TOOL@VERSION]...` - -**Aliases:** `u` - -```text -Change the active version of a tool locally or globally. - -This will install the tool if it is not already installed. -By default, this will use an `.mise.toml` file in the current directory. -Use the --global flag to use the global config file instead. -This replaces asdf's `local` and `global` commands, however those are still available in mise. - -Usage: use [OPTIONS] [TOOL@VERSION]... - -Arguments: - [TOOL@VERSION]... - Tool(s) to add to config file - e.g.: node@20, cargo:ripgrep@latest npm:prettier@3 - If no version is specified, it will default to @latest - -Options: - -f, --force - Force reinstall even if already installed - - --fuzzy - Save fuzzy version to config file - e.g.: `mise use --fuzzy node@20` will save 20 as the version - this is the default behavior unless MISE_ASDF_COMPAT=1 - - -g, --global - Use the global config file (~/.config/mise/config.toml) instead of the local one - - -e, --env - Modify an environment-specific config file like .mise..toml - - -j, --jobs - Number of jobs to run in parallel - [default: 4] - - [env: MISE_JOBS=] - - --raw - Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 - - --remove - Remove the plugin(s) from config file - - -p, --path - Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions - - --pin - Save exact version to config file - e.g.: `mise use --pin node@20` will save 20.0.0 as the version - Set MISE_ASDF_COMPAT=1 to make this the default behavior - -Examples: - # set the current version of node to 20.x in .mise.toml of current directory - # will write the fuzzy version (e.g.: 20) - $ mise use node@20 - - # set the current version of node to 20.x in ~/.config/mise/config.toml - # will write the precise version (e.g.: 20.0.0) - $ mise use -g --pin node@20 - - # sets .mise.local.toml (which is intended not to be committed to a project) - $ mise use --env local node@20 - - # sets .mise.staging.toml (which is used if MISE_ENV=staging) - $ mise use --env staging node@20 -``` - -## `mise version` - -```text -Show mise version - -Usage: version -``` - -## `mise watch [OPTIONS] [ARGS]...` - -**Aliases:** `w` - -```text -[experimental] Run a task watching for changes - -Usage: watch [OPTIONS] [ARGS]... - -Arguments: - [ARGS]... - Extra arguments - -Options: - -t, --task - Task to run - - [default: default] - - -g, --glob - Files to watch - Defaults to sources from the task(s) - -Examples: - $ mise watch -t build - Runs the "build" task. Will re-run the task when any of its sources change. - Uses "sources" from the task definition to determine which files to watch. - - $ mise watch -t build --glob src/**/*.rs - Runs the "build" task but specify the files to watch with a glob pattern. - This overrides the "sources" from the task definition. - - $ mise run -t build --clear - Extra arguments are passed to watchexec. See `watchexec --help` for details. -``` - -## `mise where ` - -```text -Display the installation path for a runtime - -Must be installed. - -Usage: where - -Arguments: - - Tool(s) to look up - e.g.: ruby@3 - if "@" is specified, it will show the latest installed version - that matches the prefix - otherwise, it will show the current, active installed version - -Examples: - # Show the latest installed version of node - # If it is is not installed, errors - $ mise where node@20 - /home/jdx/.local/share/mise/installs/node/20.0.0 - - # Show the current, active install directory of node - # Errors if node is not referenced in any .tool-version file - $ mise where node - /home/jdx/.local/share/mise/installs/node/20.0.0 -``` - -## `mise which [OPTIONS] ` - -```text -Shows the path that a bin name points to - -Usage: which [OPTIONS] - -Arguments: - - The bin name to look up - -Options: - --plugin - Show the plugin name instead of the path - - --version - Show the version instead of the path - - -t, --tool - Use a specific tool@version - e.g.: `mise which npm --tool=node@20` - -Examples: - $ mise which node - /home/username/.local/share/mise/installs/node/20.0.0/bin/node - $ mise which node --plugin - node - $ mise which node --version - 20.0.0 -``` - - diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 5ac65e677..97a2a2844 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -27,7 +27,7 @@ pub struct PluginsInstall { new_plugin: Option, /// The git url of the plugin - /// e.g.: https://github.com/asdf-vm/asdf-node.git + /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(help = "The git url of the plugin", value_hint = clap::ValueHint::Url, verbatim_doc_comment)] git_url: Option, diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 9e0786366..7a7febcbf 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -35,7 +35,7 @@ pub struct PluginsLs { pub user: bool, /// Show the git url for each plugin - /// e.g.: https://github.com/asdf-vm/asdf-node.git + /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long, alias = "url", verbatim_doc_comment)] pub urls: bool, @@ -111,7 +111,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( ruby $ mise plugins ls --urls - node https://github.com/asdf-vm/asdf-node.git + node https://github.com/asdf-vm/asdf-nodejs.git ruby https://github.com/asdf-vm/asdf-ruby.git "# ); diff --git a/src/cli/plugins/mod.rs b/src/cli/plugins/mod.rs index 22f83d99a..dd602dd29 100644 --- a/src/cli/plugins/mod.rs +++ b/src/cli/plugins/mod.rs @@ -35,7 +35,7 @@ pub struct Plugins { pub user: bool, /// Show the git url for each plugin - /// e.g.: https://github.com/asdf-vm/asdf-node.git + /// e.g.: https://github.com/asdf-vm/asdf-nodejs.git #[clap(short, long, alias = "url", verbatim_doc_comment)] pub urls: bool, From 8c24e4873c6fd4f5b94f959c17795ff9f910da0f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 14 Jan 2024 23:27:34 -0600 Subject: [PATCH 1628/1891] fixed urls --- docs/cli-reference.md | 1633 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1633 insertions(+) create mode 100644 docs/cli-reference.md diff --git a/docs/cli-reference.md b/docs/cli-reference.md new file mode 100644 index 000000000..d77c7e866 --- /dev/null +++ b/docs/cli-reference.md @@ -0,0 +1,1633 @@ + + +# Commands + +## `mise activate [OPTIONS] [SHELL_TYPE]` + +```text +Initializes mise in the current shell session + +This should go into your shell's rc file. +Otherwise, it will only take effect in the current session. +(e.g. ~/.zshrc, ~/.bashrc) + +This is only intended to be used in interactive sessions, not scripts. +mise is only capable of updating PATH when the prompt is displayed to the user. +For non-interactive use-cases, use shims instead. + +Typically this can be added with something like the following: + + echo 'eval "$(mise activate)"' >> ~/.zshrc + +However, this requires that "mise" is in your PATH. If it is not, you need to +specify the full path like this: + + echo 'eval "$(/path/to/mise activate)"' >> ~/.zshrc + +Usage: activate [OPTIONS] [SHELL_TYPE] + +Arguments: + [SHELL_TYPE] + Shell type to generate the script for + + [possible values: bash, fish, nu, xonsh, zsh] + +Options: + --status + Show "mise: @" message when changing directories + + -q, --quiet + Suppress non-error messages + +Examples: + $ eval "$(mise activate bash)" + $ eval "$(mise activate zsh)" + $ mise activate fish | source + $ execx($(mise activate xonsh)) +``` + +## `mise alias get ` + +```text +Show an alias for a plugin + +This is the contents of an alias. entry in ~/.config/mise/config.toml + +Usage: alias get + +Arguments: + + The plugin to show the alias for + + + The alias to show + +Examples: + $ mise alias get node lts-hydrogen + 20.0.0 +``` + +## `mise alias ls [OPTIONS] [PLUGIN]` + +**Aliases:** `list` + +```text +List aliases +Shows the aliases that can be specified. +These can come from user config or from plugins in `bin/list-aliases`. + +For user config, aliases are defined like the following in `~/.config/mise/config.toml`: + + [alias.node] + lts = "20.0.0" + +Usage: alias ls [OPTIONS] [PLUGIN] + +Arguments: + [PLUGIN] + Show aliases for + +Options: + --no-header + Don't show table header + +Examples: + $ mise aliases + node lts-hydrogen 20.0.0 +``` + +## `mise alias set ` + +**Aliases:** `add, create` + +```text +Add/update an alias for a plugin + +This modifies the contents of ~/.config/mise/config.toml + +Usage: alias set + +Arguments: + + The plugin to set the alias for + + + The alias to set + + + The value to set the alias to + +Examples: + $ mise alias set node lts-hydrogen 18.0.0 +``` + +## `mise alias unset ` + +**Aliases:** `del, delete, remove, rm` + +```text +Clears an alias for a plugin + +This modifies the contents of ~/.config/mise/config.toml + +Usage: alias unset + +Arguments: + + The plugin to remove the alias from + + + The alias to remove + +Examples: + $ mise alias unset node lts-hydrogen +``` + +## `mise bin-paths` + +```text +List all the active runtime bin paths + +Usage: bin-paths +``` + +## `mise cache clear [PLUGIN]...` + +**Aliases:** `c` + +```text +Deletes all cache files in mise + +Usage: cache clear [PLUGIN]... + +Arguments: + [PLUGIN]... + Plugin(s) to clear cache for e.g.: node, python +``` + +## `mise completion [SHELL]` + +```text +Generate shell completions + +Usage: completion [SHELL] + +Arguments: + [SHELL] + Shell type to generate completions for + + [possible values: bash, fish, zsh] + +Examples: + $ mise completion bash > /etc/bash_completion.d/mise + $ mise completion zsh > /usr/local/share/zsh/site-functions/_mise + $ mise completion fish > ~/.config/fish/completions/mise.fish +``` + +## `mise config ls [OPTIONS]` + +```text +[experimental] List config files currently in use + +Usage: config ls [OPTIONS] + +Options: + --no-header + Do not print table header + +Examples: + $ mise config ls +``` + +## `mise config generate [OPTIONS]` + +**Aliases:** `g` + +```text +[experimental] Generate an .mise.toml file + +Usage: config generate [OPTIONS] + +Options: + -o, --output + Output to file instead of stdout + +Examples: + $ mise cf generate > .mise.toml + $ mise cf generate --output=.mise.toml +``` + +## `mise current [PLUGIN]` + +```text +Shows current active and installed runtime versions + +This is similar to `mise ls --current`, but this only shows the runtime +and/or version. It's designed to fit into scripts more easily. + +Usage: current [PLUGIN] + +Arguments: + [PLUGIN] + Plugin to show versions of e.g.: ruby, node, cargo:eza, npm:prettier, etc + +Examples: + # outputs `.tool-versions` compatible format + $ mise current + python 3.11.0 3.10.0 + shfmt 3.6.0 + shellcheck 0.9.0 + node 20.0.0 + + $ mise current node + 20.0.0 + + # can output multiple versions + $ mise current python + 3.11.0 3.10.0 +``` + +## `mise deactivate` + +```text +Disable mise for current shell session + +This can be used to temporarily disable mise in a shell session. + +Usage: deactivate + +Examples: + $ mise deactivate bash + $ mise deactivate zsh + $ mise deactivate fish + $ execx($(mise deactivate xonsh)) +``` + +## `mise direnv activate` + +```text +Output direnv function to use mise inside direnv + +See https://mise.jdx.dev/direnv.html for more information + +Because this generates the legacy files based on currently installed plugins, +you should run this command after installing new plugins. Otherwise +direnv may not know to update environment variables when legacy file versions change. + +Usage: direnv activate + +Examples: + $ mise direnv activate > ~/.config/direnv/lib/use_mise.sh + $ echo 'use mise' > .envrc + $ direnv allow +``` + +## `mise doctor` + +```text +Check mise installation for possible problems. + +Usage: doctor + +Examples: + $ mise doctor + [WARN] plugin node is not installed +``` + +## `mise env [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `e` + +```text +Exports env vars to activate mise a single time + +Use this if you don't want to permanently install mise. It's not necessary to +use this if you have `mise activate` in your shell rc file. + +Usage: env [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to use + +Options: + -s, --shell + Shell type to generate environment variables for + + [possible values: bash, fish, nu, xonsh, zsh] + + -J, --json + Output in JSON format + +Examples: + $ eval "$(mise env -s bash)" + $ eval "$(mise env -s zsh)" + $ mise env -s fish | source + $ execx($(mise env -s xonsh)) +``` + +## `mise exec [OPTIONS] [TOOL@VERSION]... [-- ...]` + +**Aliases:** `x` + +```text +Execute a command with tool(s) set + +use this to avoid modifying the shell session or running ad-hoc commands with mise tools set. + +Tools will be loaded from .mise.toml/.tool-versions, though they can be overridden with args +Note that only the plugin specified will be overridden, so if a `.tool-versions` file +includes "node 20" but you run `mise exec python@3.11`; it will still load node@20. + +The "--" separates runtimes from the commands to pass along to the subprocess. + +Usage: exec [OPTIONS] [TOOL@VERSION]... [-- ...] + +Arguments: + [TOOL@VERSION]... + Tool(s) to start e.g.: node@20 python@3.10 + + [COMMAND]... + Command string to execute (same as --command) + +Options: + -c, --command + Command string to execute + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: MISE_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + +Examples: + $ mise exec node@20 -- node ./app.js # launch app.js using node-20.x + $ mise x node@20 -- node ./app.js # shorter alias + + # Specify command as a string: + $ mise exec node@20 python@3.11 --command "node -v && python -V" + + # Run a command in a different directory: + $ mise x -C /path/to/project node@20 -- node ./app.js +``` + +## `mise implode [OPTIONS]` + +```text +Removes mise CLI and all related data + +Skips config directory by default. + +Usage: implode [OPTIONS] + +Options: + --config + Also remove config directory + + -n, --dry-run + List directories that would be removed without actually removing them +``` + +## `mise install [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `i` + +```text +Install a tool version + +This will install a tool version to `~/.local/share/mise/installs//` +It won't be used simply by being installed, however. +For that, you must set up a `.mise.toml`/`.tool-version` file manually or with `mise use`. +Or you can call a tool version explicitly with `mise exec @ -- `. + +Tools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1` + +Usage: install [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to install e.g.: node@20 + +Options: + -f, --force + Force reinstall even if already installed + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: MISE_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + -v, --verbose... + Show installation output + +Examples: + $ mise install node@20.0.0 # install specific node version + $ mise install node@20 # install fuzzy node version + $ mise install node # install version specified in .tool-versions or .mise.toml + $ mise install # installs everything specified in .tool-versions or .mise.toml +``` + +## `mise latest [OPTIONS] ` + +```text +Gets the latest available version for a plugin + +Usage: latest [OPTIONS] + +Arguments: + + Tool to get the latest version of + +Options: + -i, --installed + Show latest installed instead of available version + +Examples: + $ mise latest node@20 # get the latest version of node 20 + 20.0.0 + + $ mise latest node # get the latest stable version of node + 20.0.0 +``` + +## `mise link [OPTIONS] ` + +**Aliases:** `ln` + +```text +Symlinks a tool version into mise + +Use this for adding installs either custom compiled outside +mise or built with a different tool. + +Usage: link [OPTIONS] + +Arguments: + + Tool name and version to create a symlink for + + + The local path to the tool version + e.g.: ~/.nvm/versions/node/v20.0.0 + +Options: + -f, --force + Overwrite an existing tool version if it exists + +Examples: + # build node-20.0.0 with node-build and link it into mise + $ node-build 20.0.0 ~/.nodes/20.0.0 + $ mise link node@20.0.0 ~/.nodes/20.0.0 + + # have mise use the python version provided by Homebrew + $ brew install node + $ mise link node@brew $(brew --prefix node) + $ mise use node@brew +``` + +## `mise ls [OPTIONS] [PLUGIN]...` + +**Aliases:** `list` + +```text +List installed and/or currently selected tool versions + +Usage: ls [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Only show tool versions from [PLUGIN] + +Options: + -c, --current + Only show tool versions currently specified in a .tool-versions/.mise.toml + + -g, --global + Only show tool versions currently specified in a the global .tool-versions/.mise.toml + + -i, --installed + Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed + + -J, --json + Output in json format + + -m, --missing + Display missing tool versions + + --prefix + Display versions matching this prefix + + --no-header + Don't display headers + +Examples: + $ mise ls + node 20.0.0 ~/src/myapp/.tool-versions latest + python 3.11.0 ~/.tool-versions 3.10 + python 3.10.0 + + $ mise ls --current + node 20.0.0 ~/src/myapp/.tool-versions 20 + python 3.11.0 ~/.tool-versions 3.11.0 + + $ mise ls --json + { + "node": [ + { + "version": "20.0.0", + "install_path": "/Users/jdx/.mise/installs/node/20.0.0", + "source": { + "type": ".mise.toml", + "path": "/Users/jdx/.mise.toml" + } + } + ], + "python": [...] + } +``` + +## `mise ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]` + +```text +List runtime versions available for install + +note that the results are cached for 24 hours +run `mise cache clean` to clear the cache and get fresh results + +Usage: ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX] + +Arguments: + [TOOL@VERSION] + Plugin to get versions for + + [PREFIX] + The version prefix to use when querying the latest version + same as the first argument after the "@" + +Options: + --all + Show all installed plugins and versions + +Examples: + $ mise ls-remote node + 18.0.0 + 20.0.0 + + $ mise ls-remote node@20 + 20.0.0 + 20.1.0 + + $ mise ls-remote node 20 + 20.0.0 + 20.1.0 +``` + +## `mise outdated [TOOL@VERSION]...` + +```text +Shows outdated tool versions + +Usage: outdated [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to show outdated versions for + e.g.: node@20 python@3.10 + If not specified, all tools in global and local configs will be shown + +Examples: + $ mise outdated + Plugin Requested Current Latest + python 3.11 3.11.0 3.11.1 + node 20 20.0.0 20.1.0 + + $ mise outdated node + Plugin Requested Current Latest + node 20 20.0.0 20.1.0 +``` + +## `mise plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL]` + +**Aliases:** `a, add, i` + +```text +Install a plugin + +note that mise automatically can install plugins when you install a tool +e.g.: `mise install node@20` will autoinstall the node plugin + +This behavior can be modified in ~/.config/mise/config.toml + +Usage: plugins install [OPTIONS] [NEW_PLUGIN] [GIT_URL] + +Arguments: + [NEW_PLUGIN] + The name of the plugin to install + e.g.: node, ruby + Can specify multiple plugins: `mise plugins install node ruby python` + + [GIT_URL] + The git url of the plugin + +Options: + -f, --force + Reinstall even if plugin exists + + -a, --all + Install all missing plugins + This will only install plugins that have matching shorthands. + i.e.: they don't need the full git repo url + + -v, --verbose... + Show installation output + +Examples: + # install the node via shorthand + $ mise plugins install node + + # install the node plugin using a specific git url + $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git + + # install the node plugin using the git url only + # (node is inferred from the url) + $ mise plugins install https://github.com/mise-plugins/rtx-nodejs.git + + # install the node plugin using a specific ref + $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git#v1.0.0 +``` + +## `mise plugins link [OPTIONS] [PATH]` + +**Aliases:** `ln` + +```text +Symlinks a plugin into mise + +This is used for developing a plugin. + +Usage: plugins link [OPTIONS] [PATH] + +Arguments: + + The name of the plugin + e.g.: node, ruby + + [PATH] + The local path to the plugin + e.g.: ./mise-node + +Options: + -f, --force + Overwrite existing plugin + +Examples: + # essentially just `ln -s ./mise-node ~/.local/share/mise/plugins/node` + $ mise plugins link node ./mise-node + + # infer plugin name as "node" + $ mise plugins link ./mise-node +``` + +## `mise plugins ls [OPTIONS]` + +**Aliases:** `list` + +```text +List installed plugins + +Can also show remotely available plugins to install. + +Usage: plugins ls [OPTIONS] + +Options: + -c, --core + The built-in plugins only + Normally these are not shown + + --user + List installed plugins + + This is the default behavior but can be used with --core + to show core and user plugins + + -u, --urls + Show the git url for each plugin + e.g.: https://github.com/asdf-vm/asdf-nodejs.git + +Examples: + $ mise plugins ls + node + ruby + + $ mise plugins ls --urls + node https://github.com/asdf-vm/asdf-nodejs.git + ruby https://github.com/asdf-vm/asdf-ruby.git +``` + +## `mise plugins ls-remote [OPTIONS]` + +**Aliases:** `list-all, list-remote` + +```text +List all available remote plugins + +The full list is here: https://github.com/jdx/mise/blob/main/src/default_shorthands.rs + +Examples: + $ mise plugins ls-remote + + +Usage: plugins ls-remote [OPTIONS] + +Options: + -u, --urls + Show the git url for each plugin e.g.: https://github.com/mise-plugins/rtx-nodejs.git + + --only-names + Only show the name of each plugin by default it will show a "*" next to installed plugins +``` + +## `mise plugins uninstall [OPTIONS] [PLUGIN]...` + +**Aliases:** `remove, rm` + +```text +Removes a plugin + +Usage: plugins uninstall [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Plugin(s) to remove + +Options: + -p, --purge + Also remove the plugin's installs, downloads, and cache + + -a, --all + Remove all plugins + +Examples: + $ mise uninstall node +``` + +## `mise plugins update [OPTIONS] [PLUGIN]...` + +**Aliases:** `upgrade` + +```text +Updates a plugin to the latest version + +note: this updates the plugin itself, not the runtime versions + +Usage: plugins update [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Plugin(s) to update + +Options: + -j, --jobs + Number of jobs to run in parallel + Default: 4 + +Examples: + $ mise plugins update # update all plugins + $ mise plugins update node # update only node + $ mise plugins update node#beta # specify a ref +``` + +## `mise prune [OPTIONS] [PLUGIN]...` + +```text +Delete unused versions of tools + +mise tracks which config files have been used in ~/.local/share/mise/tracked_config_files +Versions which are no longer the latest specified in any of those configs are deleted. +Versions installed only with environment variables (`MISE__VERSION`) will be deleted, +as will versions only referenced on the command line (`mise exec @`). + +Usage: prune [OPTIONS] [PLUGIN]... + +Arguments: + [PLUGIN]... + Prune only versions from this plugin(s) + +Options: + -n, --dry-run + Do not actually delete anything + +Examples: + $ mise prune --dry-run + rm -rf ~/.local/share/mise/versions/node/20.0.0 + rm -rf ~/.local/share/mise/versions/node/20.0.1 +``` + +## `mise reshim` + +```text +rebuilds the shim farm + +This creates new shims in ~/.local/share/mise/shims for CLIs that have been added. +mise will try to do this automatically for commands like `npm i -g` but there are +other ways to install things (like using yarn or pnpm for node) that mise does +not know about and so it will be necessary to call this explicitly. + +If you think mise should automatically call this for a particular command, please +open an issue on the mise repo. You can also setup a shell function to reshim +automatically (it's really fast so you don't need to worry about overhead): + +npm() { + command npm "$@" + mise reshim +} + +Usage: reshim + +Examples: + $ mise reshim + $ ~/.local/share/mise/shims/node -v + v20.0.0 +``` + +## `mise run [OPTIONS] [TASK] [ARGS]...` + +**Aliases:** `r` + +```text +[experimental] Run a task + +This command will run a task, or multiple tasks in parallel. +Tasks may have dependencies on other tasks or on source files. +If source is configured on a task, it will only run if the source +files have changed. + +Tasks can be defined in .mise.toml or as standalone scripts. +In .mise.toml, tasks take this form: + + [tasks.build] + run = "npm run build" + sources = ["src/**/*.ts"] + outputs = ["dist/**/*.js"] + +Alternatively, tasks can be defined as standalone scripts. +These must be located in the `.mise/tasks` directory. +The name of the script will be the name of the task. + + $ cat .mise/tasks/build< + Change to this directory before executing the command + + -n, --dry-run + Don't actually run the task(s), just print them in order of execution + + -f, --force + Force the task to run even if outputs are up to date + + -p, --prefix + Print stdout/stderr by line, prefixed with the task's label + Defaults to true if --jobs > 1 + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var + + -i, --interleave + Print directly to stdout/stderr instead of by line + Defaults to true if --jobs == 1 + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var + + -t, --tool + Tool(s) to also add e.g.: node@20 python@3.10 + + -j, --jobs + Number of tasks to run in parallel + [default: 4] + Configure with `jobs` config or `MISE_JOBS` env var + + [env: MISE_JOBS=] + + -r, --raw + Read/write directly to stdin/stdout/stderr instead of by line + Configure with `raw` config or `MISE_RAW` env var + +Examples: + $ mise run lint + Runs the "lint" task. This needs to either be defined in .mise.toml + or as a standalone script. See the project README for more information. + + $ mise run build --force + Forces the "build" task to run even if its sources are up-to-date. + + $ mise run test --raw + Runs "test" with stdin/stdout/stderr all connected to the current terminal. + This forces `--jobs=1` to prevent interleaving of output. + + $ mise run lint ::: test ::: check + Runs the "lint", "test", and "check" tasks in parallel. + + $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + Execute multiple tasks each with their own arguments. +``` + +## `mise self-update [OPTIONS] [VERSION]` + +```text +Updates mise itself + +Uses the GitHub Releases API to find the latest release and binary +By default, this will also update any installed plugins + +Usage: self-update [OPTIONS] [VERSION] + +Arguments: + [VERSION] + Update to a specific version + +Options: + -f, --force + Update even if already up to date + + --no-plugins + Disable auto-updating plugins + + -y, --yes + Skip confirmation prompt +``` + +## `mise set [OPTIONS] [ENV_VARS]...` + +```text +Manage environment variables + +By default this command modifies ".mise.toml" in the current directory. + +Usage: set [OPTIONS] [ENV_VARS]... + +Arguments: + [ENV_VARS]... + Environment variable(s) to set + e.g.: NODE_ENV=production + +Options: + --file + The TOML file to update + + Defaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or ".mise.toml". + + -g, --global + Set the environment variable in the global config file + +Examples: + $ mise set NODE_ENV=production + + $ mise set NODE_ENV + production + + $ mise set + key value source + NODE_ENV production ~/.config/mise/config.toml +``` + +## `mise settings get ` + +```text +Show a current setting + +This is the contents of a single entry in ~/.config/mise/config.toml + +Note that aliases are also stored in this file +but managed separately with `mise aliases get` + +Usage: settings get + +Arguments: + + The setting to show + +Examples: + $ mise settings get legacy_version_file + true +``` + +## `mise settings ls` + +**Aliases:** `list` + +```text +Show current settings + +This is the contents of ~/.config/mise/config.toml + +Note that aliases are also stored in this file +but managed separately with `mise aliases` + +Usage: settings ls + +Examples: + $ mise settings + legacy_version_file = false +``` + +## `mise settings set ` + +**Aliases:** `add, create` + +```text +Add/update a setting + +This modifies the contents of ~/.config/mise/config.toml + +Usage: settings set + +Arguments: + + The setting to set + + + The value to set + +Examples: + $ mise settings set legacy_version_file true +``` + +## `mise settings unset ` + +**Aliases:** `del, delete, remove, rm` + +```text +Clears a setting + +This modifies the contents of ~/.config/mise/config.toml + +Usage: settings unset + +Arguments: + + The setting to remove + +Examples: + $ mise settings unset legacy_version_file +``` + +## `mise shell [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `sh` + +```text +Sets a tool version for the current shell session + +Only works in a session where mise is already activated. + +Usage: shell [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to use + +Options: + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: MISE_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + -u, --unset + Removes a previously set version + +Examples: + $ mise shell node@20 + $ node -v + v20.0.0 +``` + +## `mise sync node <--brew|--nvm|--nodenv>` + +```text +Symlinks all tool versions from an external tool into mise + +For example, use this to import all Homebrew node installs into mise + +Usage: sync node <--brew|--nvm|--nodenv> + +Options: + --brew + Get tool versions from Homebrew + + --nvm + Get tool versions from nvm + + --nodenv + Get tool versions from nodenv + +Examples: + $ brew install node@18 node@20 + $ mise sync node --brew + $ mise use -g node@18 - uses Homebrew-provided node +``` + +## `mise sync python --pyenv` + +```text +Symlinks all tool versions from an external tool into mise + +For example, use this to import all pyenv installs into mise + +Usage: sync python --pyenv + +Options: + --pyenv + Get tool versions from pyenv + +Examples: + $ pyenv install 3.11.0 + $ mise sync python --pyenv + $ mise use -g python@3.11.0 - uses pyenv-provided python +``` + +## `mise task deps [OPTIONS] [TASKS]...` + +```text +[experimental] Display a tree visualization of a dependency graph + +Usage: task deps [OPTIONS] [TASKS]... + +Arguments: + [TASKS]... + Tasks to show dependencies for + Can specify multiple tasks by separating with spaces + e.g.: mise task deps lint test check + +Options: + --dot + Display dependencies in DOT format + +Examples: + $ mise task deps + Shows dependencies for all tasks + + $ mise task deps lint test check + Shows dependencies for the "lint", "test" and "check" tasks + + $ mise task deps --dot + Shows dependencies in DOT format +``` + +## `mise task edit [OPTIONS] ` + +```text +[experimental] Edit a task with $EDITOR + +The task will be created as a standalone script if it does not already exist. + +Usage: task edit [OPTIONS] + +Arguments: + + Task to edit + +Options: + -p, --path + Display the path to the task instead of editing it + +Examples: + $ mise task edit build + $ mise task edit test +``` + +## `mise task ls [OPTIONS]` + +```text +[experimental] List available tasks to execute +These may be included from the config file or from the project's .mise/tasks directory +mise will merge all tasks from all parent directories into this list. + +So if you have global tasks in ~/.config/mise/tasks/* and project-specific tasks in +~/myproject/.mise/tasks/*, then they'll both be available but the project-specific +tasks will override the global ones if they have the same name. + +Usage: task ls [OPTIONS] + +Options: + --no-header + Do not print table header + + --hidden + Show hidden tasks + +Examples: + $ mise task ls +``` + +## `mise task run [OPTIONS] [TASK] [ARGS]...` + +**Aliases:** `r` + +```text +[experimental] Run a task + +This command will run a task, or multiple tasks in parallel. +Tasks may have dependencies on other tasks or on source files. +If source is configured on a task, it will only run if the source +files have changed. + +Tasks can be defined in .mise.toml or as standalone scripts. +In .mise.toml, tasks take this form: + + [tasks.build] + run = "npm run build" + sources = ["src/**/*.ts"] + outputs = ["dist/**/*.js"] + +Alternatively, tasks can be defined as standalone scripts. +These must be located in the `.mise/tasks` directory. +The name of the script will be the name of the task. + + $ cat .mise/tasks/build< + Change to this directory before executing the command + + -n, --dry-run + Don't actually run the task(s), just print them in order of execution + + -f, --force + Force the task to run even if outputs are up to date + + -p, --prefix + Print stdout/stderr by line, prefixed with the task's label + Defaults to true if --jobs > 1 + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var + + -i, --interleave + Print directly to stdout/stderr instead of by line + Defaults to true if --jobs == 1 + Configure with `task_output` config or `MISE_TASK_OUTPUT` env var + + -t, --tool + Tool(s) to also add e.g.: node@20 python@3.10 + + -j, --jobs + Number of tasks to run in parallel + [default: 4] + Configure with `jobs` config or `MISE_JOBS` env var + + [env: MISE_JOBS=] + + -r, --raw + Read/write directly to stdin/stdout/stderr instead of by line + Configure with `raw` config or `MISE_RAW` env var + +Examples: + $ mise run lint + Runs the "lint" task. This needs to either be defined in .mise.toml + or as a standalone script. See the project README for more information. + + $ mise run build --force + Forces the "build" task to run even if its sources are up-to-date. + + $ mise run test --raw + Runs "test" with stdin/stdout/stderr all connected to the current terminal. + This forces `--jobs=1` to prevent interleaving of output. + + $ mise run lint ::: test ::: check + Runs the "lint", "test", and "check" tasks in parallel. + + $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + Execute multiple tasks each with their own arguments. +``` + +## `mise trust [OPTIONS] [CONFIG_FILE]` + +```text +Marks a config file as trusted + +This means mise will parse the file with potentially dangerous +features enabled. + +This includes: +- environment variables +- templates +- `path:` plugin versions + +Usage: trust [OPTIONS] [CONFIG_FILE] + +Arguments: + [CONFIG_FILE] + The config file to trust + +Options: + -a, --all + Trust all config files in the current directory and its parents + + --untrust + No longer trust this config + +Examples: + # trusts ~/some_dir/.mise.toml + $ mise trust ~/some_dir/.mise.toml + + # trusts .mise.toml in the current or parent directory + $ mise trust +``` + +## `mise uninstall [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `remove, rm` + +```text +Removes runtime versions + +Usage: uninstall [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to remove + +Options: + -a, --all + Delete all installed versions + + -n, --dry-run + Do not actually delete anything + +Examples: + $ mise uninstall node@18.0.0 # will uninstall specific version + $ mise uninstall node # will uninstall current node version + $ mise uninstall --all node@18.0.0 # will uninstall all node versions +``` + +## `mise unset [OPTIONS] [KEYS]...` + +```text +Remove environment variable(s) from the config file + +By default this command modifies ".mise.toml" in the current directory. + +Usage: unset [OPTIONS] [KEYS]... + +Arguments: + [KEYS]... + Environment variable(s) to remove + e.g.: NODE_ENV + +Options: + -f, --file + Specify a file to use instead of ".mise.toml" + + -g, --global + Use the global config file +``` + +## `mise upgrade [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `up` + +```text +Upgrades outdated tool versions + +Usage: upgrade [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to upgrade + e.g.: node@20 python@3.10 + If not specified, all current tools will be upgraded + +Options: + -n, --dry-run + Just print what would be done, don't actually do it + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: MISE_JOBS=] + + -i, --interactive + Display multiselect menu to choose which tools to upgrade + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 +``` + +## `mise use [OPTIONS] [TOOL@VERSION]...` + +**Aliases:** `u` + +```text +Change the active version of a tool locally or globally. + +This will install the tool if it is not already installed. +By default, this will use an `.mise.toml` file in the current directory. +Use the --global flag to use the global config file instead. +This replaces asdf's `local` and `global` commands, however those are still available in mise. + +Usage: use [OPTIONS] [TOOL@VERSION]... + +Arguments: + [TOOL@VERSION]... + Tool(s) to add to config file + e.g.: node@20, cargo:ripgrep@latest npm:prettier@3 + If no version is specified, it will default to @latest + +Options: + -f, --force + Force reinstall even if already installed + + --fuzzy + Save fuzzy version to config file + e.g.: `mise use --fuzzy node@20` will save 20 as the version + this is the default behavior unless MISE_ASDF_COMPAT=1 + + -g, --global + Use the global config file (~/.config/mise/config.toml) instead of the local one + + -e, --env + Modify an environment-specific config file like .mise..toml + + -j, --jobs + Number of jobs to run in parallel + [default: 4] + + [env: MISE_JOBS=] + + --raw + Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 + + --remove + Remove the plugin(s) from config file + + -p, --path + Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions + + --pin + Save exact version to config file + e.g.: `mise use --pin node@20` will save 20.0.0 as the version + Set MISE_ASDF_COMPAT=1 to make this the default behavior + +Examples: + # set the current version of node to 20.x in .mise.toml of current directory + # will write the fuzzy version (e.g.: 20) + $ mise use node@20 + + # set the current version of node to 20.x in ~/.config/mise/config.toml + # will write the precise version (e.g.: 20.0.0) + $ mise use -g --pin node@20 + + # sets .mise.local.toml (which is intended not to be committed to a project) + $ mise use --env local node@20 + + # sets .mise.staging.toml (which is used if MISE_ENV=staging) + $ mise use --env staging node@20 +``` + +## `mise version` + +```text +Show mise version + +Usage: version +``` + +## `mise watch [OPTIONS] [ARGS]...` + +**Aliases:** `w` + +```text +[experimental] Run a task watching for changes + +Usage: watch [OPTIONS] [ARGS]... + +Arguments: + [ARGS]... + Extra arguments + +Options: + -t, --task + Task to run + + [default: default] + + -g, --glob + Files to watch + Defaults to sources from the task(s) + +Examples: + $ mise watch -t build + Runs the "build" task. Will re-run the task when any of its sources change. + Uses "sources" from the task definition to determine which files to watch. + + $ mise watch -t build --glob src/**/*.rs + Runs the "build" task but specify the files to watch with a glob pattern. + This overrides the "sources" from the task definition. + + $ mise run -t build --clear + Extra arguments are passed to watchexec. See `watchexec --help` for details. +``` + +## `mise where ` + +```text +Display the installation path for a runtime + +Must be installed. + +Usage: where + +Arguments: + + Tool(s) to look up + e.g.: ruby@3 + if "@" is specified, it will show the latest installed version + that matches the prefix + otherwise, it will show the current, active installed version + +Examples: + # Show the latest installed version of node + # If it is is not installed, errors + $ mise where node@20 + /home/jdx/.local/share/mise/installs/node/20.0.0 + + # Show the current, active install directory of node + # Errors if node is not referenced in any .tool-version file + $ mise where node + /home/jdx/.local/share/mise/installs/node/20.0.0 +``` + +## `mise which [OPTIONS] ` + +```text +Shows the path that a bin name points to + +Usage: which [OPTIONS] + +Arguments: + + The bin name to look up + +Options: + --plugin + Show the plugin name instead of the path + + --version + Show the version instead of the path + + -t, --tool + Use a specific tool@version + e.g.: `mise which npm --tool=node@20` + +Examples: + $ mise which node + /home/username/.local/share/mise/installs/node/20.0.0/bin/node + $ mise which node --plugin + node + $ mise which node --version + 20.0.0 +``` + + From 94bfc46bccb99144a542d5b678b33537a36bea6c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 15 Jan 2024 10:45:39 -0600 Subject: [PATCH 1629/1891] fixed deprecated plugins migrate --- src/migrate.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/migrate.rs b/src/migrate.rs index 9c5345b9b..1d9665bf8 100644 --- a/src/migrate.rs +++ b/src/migrate.rs @@ -18,10 +18,10 @@ pub fn run() { task(s, migrate_trusted_configs); task(s, migrate_tracked_configs); task(s, || remove_deprecated_plugin("node", "rtx-nodejs")); - task(s, || remove_deprecated_plugin("python", "rtx-golang")); - task(s, || remove_deprecated_plugin("python", "rtx-java")); + task(s, || remove_deprecated_plugin("go", "rtx-golang")); + task(s, || remove_deprecated_plugin("java", "rtx-java")); task(s, || remove_deprecated_plugin("python", "rtx-python")); - task(s, || remove_deprecated_plugin("python", "rtx-ruby")); + task(s, || remove_deprecated_plugin("ruby", "rtx-ruby")); }); } From b7e61d68b4d8d729da88d9fa9e977066c1ab5068 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 15 Jan 2024 10:46:22 -0600 Subject: [PATCH 1630/1891] chore: Release mise version 2024.1.21 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac57187b9..3d8757d04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.20" +version = "2024.1.21" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index c2992e9c2..6be2a1500 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.20" +version = "2024.1.21" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 16e2c0e84..ea726716c 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.20 +mise 2024.1.21 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index c9beb0e22..6ba1371e9 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.20"; + version = "2024.1.21"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 9ca2fadb7..f1581b0e0 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.20" +.TH mise 1 "mise 2024.1.21" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.20 +v2024.1.21 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 17828f92e..3b98854bd 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.20 +Version: 2024.1.21 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 9c4b7fb652cab04864841b02d59ccd7581a1e805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20Tam=C3=A1s?= Date: Mon, 15 Jan 2024 22:36:07 +0100 Subject: [PATCH 1631/1891] fix: no panic on missing current dir (#1462) --- src/config/mod.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 3849a4df1..902312910 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -340,8 +340,17 @@ pub static DEFAULT_CONFIG_FILENAMES: Lazy> = Lazy::new(|| { }); pub fn load_config_paths(config_filenames: &[String]) -> Vec { - let mut config_files = - file::FindUp::new(&env::current_dir().unwrap(), config_filenames).collect::>(); + // In cases where the current dir is not available, + // we simply don't load any configs. + // + // This can happen for any reason in a shell, the directory + // being deleted or when inside fuse mounts. + let Ok(current_dir) = env::current_dir() else { + debug!("current dir not available"); + return Vec::new(); + }; + + let mut config_files = file::FindUp::new(¤t_dir, config_filenames).collect::>(); for cf in global_config_files() { config_files.push(cf); From c8e02e425c05dfb19a10f04b6baa57f2640fd991 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:52:16 -0600 Subject: [PATCH 1632/1891] fix not_found handler when command start with "--" (#1464) if you type something like "--profile" in you would get a strange error --- src/shell/bash.rs | 2 +- src/shell/fish.rs | 2 +- src/shell/snapshots/mise__shell__bash__tests__hook_init.snap | 2 +- .../snapshots/mise__shell__bash__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/mise__shell__fish__tests__hook_init.snap | 2 +- .../snapshots/mise__shell__fish__tests__hook_init_nix.snap | 2 +- src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap | 2 +- src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap | 2 +- src/shell/zsh.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 0b5626bab..d4254b75a 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -55,7 +55,7 @@ impl Shell for Bash { [ -n "$(declare -f command_not_found_handler)" ] && eval "${{$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}}" command_not_found_handle() {{ - if {exe} hook-not-found -s bash "$1"; then + if {exe} hook-not-found -s bash -- "$1"; then _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handle)" ]; then diff --git a/src/shell/fish.rs b/src/shell/fish.rs index aabbafd7a..675242674 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -79,7 +79,7 @@ impl Shell for Fish { if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" function fish_command_not_found - if {exe} hook-not-found -s fish $argv[1] + if {exe} hook-not-found -s fish -- $argv[1] {exe} hook-env{flags} -s fish | source else __fish_default_command_not_found_handler $argv diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap index d75cff6dd..842834622 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap @@ -40,7 +40,7 @@ if [ -z "${_mise_cmd_not_found:-}" ]; then [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" command_not_found_handle() { - if /some/dir/mise hook-not-found -s bash "$1"; then + if /some/dir/mise hook-not-found -s bash -- "$1"; then _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handle)" ]; then diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap index 2e5ad0c4c..7cfaeb956 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap @@ -39,7 +39,7 @@ if [ -z "${_mise_cmd_not_found:-}" ]; then [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" command_not_found_handle() { - if /nix/store/mise hook-not-found -s bash "$1"; then + if /nix/store/mise hook-not-found -s bash -- "$1"; then _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handle)" ]; then diff --git a/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap b/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap index c970b7ca1..57d693103 100644 --- a/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap @@ -59,7 +59,7 @@ function __mise_env_eval_2 --on-event fish_preexec --description 'Update mise en functions --erase __mise_cd_hook; end; function fish_command_not_found - if /some/dir/mise hook-not-found -s fish $argv[1] + if /some/dir/mise hook-not-found -s fish -- $argv[1] /some/dir/mise hook-env --status -s fish | source else __fish_default_command_not_found_handler $argv diff --git a/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap index 86fd07d51..d36277bb0 100644 --- a/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap @@ -58,7 +58,7 @@ function __mise_env_eval_2 --on-event fish_preexec --description 'Update mise en functions --erase __mise_cd_hook; end; function fish_command_not_found - if /nix/store/mise hook-not-found -s fish $argv[1] + if /nix/store/mise hook-not-found -s fish -- $argv[1] /nix/store/mise hook-env --status -s fish | source else __fish_default_command_not_found_handler $argv diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap index 2bf4bf6c9..0e0b046a7 100644 --- a/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap @@ -44,7 +44,7 @@ if [ -z "${_mise_cmd_not_found:-}" ]; then [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { - if /some/dir/mise hook-not-found -s zsh "$1"; then + if /some/dir/mise hook-not-found -s zsh -- "$1"; then _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handler)" ]; then diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap index 7c4a46daa..62bac1e7c 100644 --- a/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap @@ -43,7 +43,7 @@ if [ -z "${_mise_cmd_not_found:-}" ]; then [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" function command_not_found_handler() { - if /nix/store/mise hook-not-found -s zsh "$1"; then + if /nix/store/mise hook-not-found -s zsh -- "$1"; then _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handler)" ]; then diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index b15b69048..ded203fc3 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -63,7 +63,7 @@ impl Shell for Zsh { [ -n "$(declare -f command_not_found_handler)" ] && eval "${{$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}}" function command_not_found_handler() {{ - if {exe} hook-not-found -s zsh "$1"; then + if {exe} hook-not-found -s zsh -- "$1"; then _mise_hook "$@" elif [ -n "$(declare -f _command_not_found_handler)" ]; then From fd9da129e093332113ca10098e14bf21660017db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20Tam=C3=A1s?= Date: Tue, 16 Jan 2024 15:31:54 +0100 Subject: [PATCH 1633/1891] fix: always load global configs (#1466) --- src/config/mod.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 902312910..67991802c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -340,24 +340,21 @@ pub static DEFAULT_CONFIG_FILENAMES: Lazy> = Lazy::new(|| { }); pub fn load_config_paths(config_filenames: &[String]) -> Vec { - // In cases where the current dir is not available, - // we simply don't load any configs. - // - // This can happen for any reason in a shell, the directory - // being deleted or when inside fuse mounts. - let Ok(current_dir) = env::current_dir() else { - debug!("current dir not available"); - return Vec::new(); - }; + let mut config_files = Vec::new(); - let mut config_files = file::FindUp::new(¤t_dir, config_filenames).collect::>(); + // The current directory is not always available, e.g. + // when a directory was deleted or inside FUSE mounts. + match env::current_dir() { + Ok(current_dir) => { + config_files.extend(file::FindUp::new(¤t_dir, config_filenames)); + } + Err(error) => { + debug!("error getting current dir: {error}"); + }, + }; - for cf in global_config_files() { - config_files.push(cf); - } - for cf in system_config_files() { - config_files.push(cf); - } + config_files.extend(global_config_files()); + config_files.extend(system_config_files()); config_files.into_iter().unique().collect() } From 152e6b78eb65a249e73a22860cadc532dfdc5e2a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:06:28 -0600 Subject: [PATCH 1634/1891] remove dirs_next in favor of simpler home crate (#1471) --- Cargo.lock | 45 +-------------------------------------------- Cargo.toml | 2 +- src/config/mod.rs | 2 +- src/env.rs | 8 ++++++-- 4 files changed, 9 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d8757d04..0e0f8c360 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,27 +575,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dotenvy" version = "0.15.7" @@ -1248,17 +1227,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "libredox" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" -dependencies = [ - "bitflags 2.4.1", - "libc", - "redox_syscall", -] - [[package]] name = "libz-sys" version = "1.1.12" @@ -1344,7 +1312,6 @@ dependencies = [ "ctor", "ctrlc", "demand", - "dirs-next", "dotenvy", "duct", "either", @@ -1354,6 +1321,7 @@ dependencies = [ "flate2", "fslock", "globwalk 0.9.0", + "home", "humantime", "indenter", "indexmap", @@ -1815,17 +1783,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_users" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - [[package]] name = "regex" version = "1.10.2" diff --git a/Cargo.toml b/Cargo.toml index 6be2a1500..caf2455f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,6 @@ confique = { version = "0.2", default-features = false } console = "0.15" ctrlc = "3" demand = "0.3" -dirs-next = "2" dotenvy = "0.15" duct = "0.13" either = "1" @@ -58,6 +57,7 @@ filetime = "0.2" flate2 = "1" fslock = "0.2" globwalk = "0.9" +home = "0.5.9" humantime = "2" indenter = "0.3" indexmap = { version = "2", features = ["serde"] } diff --git a/src/config/mod.rs b/src/config/mod.rs index 67991802c..1851fcab2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -350,7 +350,7 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { } Err(error) => { debug!("error getting current dir: {error}"); - }, + } }; config_files.extend(global_config_files()); diff --git a/src/env.rs b/src/env.rs index 6dd8327b9..881e83a87 100644 --- a/src/env.rs +++ b/src/env.rs @@ -19,12 +19,16 @@ pub static SHELL: Lazy = Lazy::new(|| var("SHELL").unwrap_or_else(|_| "s // paths and directories pub static HOME: Lazy = - Lazy::new(|| dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("/"))); + Lazy::new(|| home::home_dir().unwrap_or_else(|| PathBuf::from("/"))); pub static EDITOR: Lazy = Lazy::new(|| var("VISUAL").unwrap_or_else(|_| var("EDITOR").unwrap_or_else(|_| "nano".into()))); +#[cfg(target_os = "macos")] pub static XDG_CACHE_HOME: Lazy = - Lazy::new(|| dirs_next::cache_dir().unwrap_or_else(|| HOME.join(".cache"))); + Lazy::new(|| var_path("XDG_CACHE_HOME").unwrap_or_else(|| HOME.join("Library/Caches"))); +#[cfg(not(target_os = "macos"))] +pub static XDG_CACHE_HOME: Lazy = + Lazy::new(|| var_path("XDG_CACHE_HOME").unwrap_or_else(|| HOME.join(".cache"))); pub static XDG_CONFIG_HOME: Lazy = Lazy::new(|| var_path("XDG_CONFIG_HOME").unwrap_or_else(|| HOME.join(".config"))); pub static XDG_DATA_HOME: Lazy = From ec609a2b845976f5ab8421790130b59c7eb38a9a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:56:13 -0600 Subject: [PATCH 1635/1891] rename internal MISE_BIN env var to __MISE_BIN (#1472) Fixes #1467 --- .idea/mise.iml | 4 ++++ src/env.rs | 10 +++++----- src/plugins/script_manager.rs | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.idea/mise.iml b/.idea/mise.iml index 1421cb198..f84d90057 100644 --- a/.idea/mise.iml +++ b/.idea/mise.iml @@ -7,6 +7,9 @@ + + + @@ -23,6 +26,7 @@ + diff --git a/src/env.rs b/src/env.rs index 881e83a87..2e5c8959e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -65,11 +65,6 @@ pub static MISE_GLOBAL_CONFIG_FILE: Lazy = Lazy::new(|| { .unwrap_or_else(|| MISE_CONFIG_DIR.join("config.toml")) }); pub static MISE_USE_TOML: Lazy = Lazy::new(|| var_is_true("MISE_USE_TOML")); -pub static MISE_BIN: Lazy = Lazy::new(|| { - var_path("MISE_BIN") - .or_else(|| current_exe().ok()) - .unwrap_or_else(|| "mise".into()) -}); pub static ARGV0: Lazy = Lazy::new(|| ARGS.read().unwrap()[0].to_string()); pub static MISE_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0)); pub static MISE_LOG_FILE: Lazy> = Lazy::new(|| var_path("MISE_LOG_FILE")); @@ -104,6 +99,11 @@ pub static MISE_FETCH_REMOTE_VERSIONS_CACHE: Lazy> = Lazy::new( /// true if inside a script like bin/exec-env or bin/install /// used to prevent infinite loops +pub static MISE_BIN: Lazy = Lazy::new(|| { + var_path("__MISE_BIN") + .or_else(|| current_exe().ok()) + .unwrap_or_else(|| "mise".into()) +}); pub static __MISE_SCRIPT: Lazy = Lazy::new(|| var_is_true("__MISE_SCRIPT")); pub static __MISE_DIFF: Lazy = Lazy::new(get_env_diff); pub static __MISE_ORIG_PATH: Lazy> = Lazy::new(|| var("__MISE_ORIG_PATH").ok()); diff --git a/src/plugins/script_manager.rs b/src/plugins/script_manager.rs index 683b1592a..a217a920e 100644 --- a/src/plugins/script_manager.rs +++ b/src/plugins/script_manager.rs @@ -84,11 +84,11 @@ static INITIAL_ENV: Lazy> = Lazy::new(|| { (indexmap! { "ASDF_CONCURRENCY" => num_cpus::get().to_string(), "PATH" => get_path_with_fake_asdf(), - "MISE_BIN" => env::MISE_BIN.to_string_lossy().to_string(), "MISE_CACHE_DIR" => env::MISE_CACHE_DIR.to_string_lossy().to_string(), "MISE_CONCURRENCY" => num_cpus::get().to_string(), "MISE_DATA_DIR" => dirs::DATA.to_string_lossy().to_string(), "MISE_LOG_LEVEL" => settings.log_level.to_string(), + "__MISE_BIN" => env::MISE_BIN.to_string_lossy().to_string(), "__MISE_SCRIPT" => "1".to_string(), }) .into_iter() From 1a8481cdd655068ce6c10f87b022d1880bf70bb5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 16 Jan 2024 18:05:42 -0600 Subject: [PATCH 1636/1891] allow using templates in task files (#1473) Fixes #1469 --- .mise/tasks/filetask | 1 + src/cli/task/edit.rs | 2 +- src/config/config_file/toml.rs | 44 ++++++++++++++++++++++-------- src/config/mod.rs | 4 +-- src/task.rs | 50 +++++++++++++++++----------------- 5 files changed, 62 insertions(+), 39 deletions(-) diff --git a/.mise/tasks/filetask b/.mise/tasks/filetask index ee264c008..1c25bb9b8 100755 --- a/.mise/tasks/filetask +++ b/.mise/tasks/filetask @@ -4,6 +4,7 @@ # mise sources=[".test-tool-versions"] # mise outputs=["$MISE_PROJECT_ROOT/test/test-build-output.txt"] # mise env={TEST_BUILDSCRIPT_ENV_VAR = "VALID"} +# mise dir="{{config_root}}" set -euxo pipefail cd "$MISE_PROJECT_ROOT" || exit 1 diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs index 239253aa7..e1608d4a0 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/task/edit.rs @@ -38,7 +38,7 @@ impl TaskEdit { .join(".mise") .join("tasks") .join(&self.task); - Task::from_path(path) + Task::from_path(&path) }, Ok, )?; diff --git a/src/config/config_file/toml.rs b/src/config/config_file/toml.rs index 2cd344661..c874d21d0 100644 --- a/src/config/config_file/toml.rs +++ b/src/config/config_file/toml.rs @@ -1,24 +1,36 @@ use std::collections::HashMap; +use tera::{Context, Tera}; + pub struct TomlParser<'a> { - pub table: &'a toml::Value, + table: &'a toml::Value, + tera: Tera, + tera_ctx: Context, } impl<'a> TomlParser<'a> { - pub fn new(table: &'a toml::Value) -> Self { - Self { table } + pub fn new(table: &'a toml::Value, tera: Tera, tera_ctx: Context) -> Self { + Self { + table, + tera, + tera_ctx, + } } - pub fn parse_str(&self, key: &str) -> Option { + pub fn parse_str(&self, key: &str) -> eyre::Result> + where + T: From, + { self.table .get(key) .and_then(|value| value.as_str()) - .map(|value| value.to_string()) + .map(|s| self.render_tmpl(s)) + .transpose() } pub fn parse_bool(&self, key: &str) -> Option { self.table.get(key).and_then(|value| value.as_bool()) } - pub fn parse_array(&self, key: &str) -> Option> + pub fn parse_array(&self, key: &str) -> eyre::Result>> where T: Default + From, { @@ -28,11 +40,12 @@ impl<'a> TomlParser<'a> { .map(|array| { array .iter() - .filter_map(|value| value.as_str().map(|v| v.to_string().into())) - .collect::>() + .filter_map(|value| value.as_str().map(|v| self.render_tmpl(v))) + .collect::>>() }) + .transpose() } - pub fn parse_hashmap(&self, key: &str) -> Option> + pub fn parse_hashmap(&self, key: &str) -> eyre::Result>> where T: From, { @@ -45,9 +58,18 @@ impl<'a> TomlParser<'a> { .filter_map(|(key, value)| { value .as_str() - .map(|v| (key.to_string(), v.to_string().into())) + .map(|v| Ok((self.render_tmpl(key)?, self.render_tmpl(v)?))) }) - .collect::>() + .collect::>>() }) + .transpose() + } + + fn render_tmpl(&self, tmpl: &str) -> eyre::Result + where + T: From, + { + let tmpl = self.tera.clone().render_str(tmpl, &self.tera_ctx)?; + Ok(tmpl.into()) } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 1851fcab2..6f43fce8e 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -199,10 +199,10 @@ impl Config { .into_par_iter() .flat_map(|either| match either { Either::Left(cf) => cf.tasks().into_iter().cloned().collect(), - Either::Right(path) => match Task::from_path(path) { + Either::Right(path) => match Task::from_path(&path) { Ok(task) => vec![task], Err(err) => { - warn!("Error loading task: {:#}", err); + warn!("Error loading task {}: {err:#}", display_path(&path)); vec![] } }, diff --git a/src/task.rs b/src/task.rs index c2acad0de..c9946e53a 100644 --- a/src/task.rs +++ b/src/task.rs @@ -7,7 +7,7 @@ use std::collections::{HashMap, HashSet}; use std::fmt; use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::mpsc; use console::truncate_str; @@ -17,6 +17,7 @@ use itertools::Itertools; use crate::config::config_file::toml::TomlParser; use crate::config::Config; use crate::file; +use crate::tera::{get_tera, BASE_CONTEXT}; use crate::ui::tree::TreeItem; #[derive(Debug, Default, Clone, Eq, PartialEq)] @@ -55,8 +56,8 @@ impl Task { ..Default::default() } } - pub fn from_path(path: PathBuf) -> Result { - let info = file::read_to_string(&path)? + pub fn from_path(path: &Path) -> Result { + let info = file::read_to_string(path)? .lines() .filter_map(|line| regex!(r"^# mise ([a-z]+=.+)$").captures(line)) .map(|captures| captures.extract()) @@ -71,20 +72,23 @@ impl Task { map }); let info = toml::Value::Table(info); - let p = TomlParser::new(&info); + let config_root = config_root(path); + let mut tera_ctx = BASE_CONTEXT.clone(); + tera_ctx.insert("config_root", &config_root); + let p = TomlParser::new(&info, get_tera(config_root), tera_ctx); // trace!("task info: {:#?}", info); let name = path.file_name().unwrap().to_str().unwrap().to_string(); let task = Task { - hide: !file::is_executable(&path) || p.parse_bool("hide").unwrap_or_default(), - description: p.parse_str("description").unwrap_or_default(), - sources: p.parse_array("sources").unwrap_or_default(), - outputs: p.parse_array("outputs").unwrap_or_default(), - depends: p.parse_array("depends").unwrap_or_default(), - dir: p.parse_str("dir").map(PathBuf::from), - env: p.parse_hashmap("env").unwrap_or_default(), - file: Some(path.clone()), - ..Task::new(name, path) + hide: !file::is_executable(path) || p.parse_bool("hide").unwrap_or_default(), + description: p.parse_str("description")?.unwrap_or_default(), + sources: p.parse_array("sources")?.unwrap_or_default(), + outputs: p.parse_array("outputs")?.unwrap_or_default(), + depends: p.parse_array("depends")?.unwrap_or_default(), + dir: p.parse_str("dir")?, + env: p.parse_hashmap("env")?.unwrap_or_default(), + file: Some(path.to_path_buf()), + ..Task::new(name, path.to_path_buf()) }; Ok(task) } @@ -145,18 +149,6 @@ impl Task { .collect(); Ok(depends) } - - // pub fn project_root(&self) -> &Path { - // match self - // .config_source - // .parent() - // .expect("task source has no parent") - // { - // dir if dir.ends_with(".mise/tasks") => dir.parent().unwrap(), - // dir if dir.ends_with(".config/mise/tasks") => dir.parent().unwrap().parent().unwrap(), - // dir => dir, - // } - // } } impl Display for Task { @@ -301,3 +293,11 @@ impl TreeItem for (&Graph, NodeIndex) { Cow::from(v) } } + +fn config_root(config_source: &Path) -> &Path { + match config_source.parent().expect("task source has no parent") { + dir if dir.ends_with(".mise/tasks") => dir.parent().unwrap(), + dir if dir.ends_with(".config/mise/tasks") => dir.parent().unwrap().parent().unwrap(), + dir => dir, + } +} From 62679b3b25281b53710f195d698269a2883c8626 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 16 Jan 2024 18:07:26 -0600 Subject: [PATCH 1637/1891] tasks: support array of commands directly (#1474) Fixes #1385 --- .mise.local.toml | 4 ++-- src/config/config_file/mise_toml.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.mise.local.toml b/.mise.local.toml index 3b62ceb2a..05a583a38 100644 --- a/.mise.local.toml +++ b/.mise.local.toml @@ -1,7 +1,7 @@ #:schema ./schema/mise.json -tasks.a1 = { run = "echo a1 1>&2 && sleep 1.5" } -tasks.a2 = { run = "echo a2 && sleep 1.0" } +tasks.a1 = ["echo a1 1>&2 && sleep 1.5"] +tasks.a2 = "echo a2 && sleep 1.0" tasks.b1 = { run = "echo b1 && sleep 1.0", depends = ["a1", "a2"] } tasks.c1 = { run = "echo c1 && sleep 0.5 && echo", depends = ["b1"] } #tasks.filetask = "echo local" diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 801e6c85f..629ba7820 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -285,6 +285,10 @@ impl MiseToml { task.run = self.parse_string_or_array(key, v)?; return Ok(task); } + if v.as_array().is_some() { + task.run = self.parse_string_array(key, v)?; + return Ok(task); + } match v.as_table_like() { Some(table) => { let mut task = Task::new(name.into(), self.path.clone()); From 8863a21eebcc2e8c1621bee8223dd3245438bac8 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 16 Jan 2024 18:32:58 -0600 Subject: [PATCH 1638/1891] updated dependencies (#1475) --- Cargo.lock | 282 +++++++++---------------- completions/mise.bash | 6 +- src/shell/completions/fish_complete.rs | 22 +- 3 files changed, 122 insertions(+), 188 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e0f8c360..6f442e22a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "628a8f9bd1e24b4e0db2b4bc2d000b001e7dd032d54afa60a68836aeec5aa54a" dependencies = [ "anstyle", "anstyle-parse", @@ -150,9 +150,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" @@ -168,9 +168,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "block-buffer" @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.12" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -265,9 +265,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.12" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -277,9 +277,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.5" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a51919c5608a32e34ea1d6be321ad070065e17613e168c5b6977024290f2630b" +checksum = "dfb0d4825b75ff281318c393e8e1b80c4da9fb75a6b1d98547d389d6fe1f48d2" dependencies = [ "clap", ] @@ -293,7 +293,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -304,9 +304,9 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clap_mangen" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b5db60b3310cdb376fbeb8826e875a38080d0c61bdec0a91a3da8338948736" +checksum = "4a7c2b01e5e779c19f46a94bbd398f33ae63b0f78c07108351fb4536845bb7fd" dependencies = [ "clap", "roff", @@ -390,15 +390,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -425,9 +425,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -443,34 +443,28 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.17" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -489,7 +483,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -527,7 +521,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -845,9 +839,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -866,7 +860,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "libgit2-sys", "log", @@ -899,20 +893,20 @@ dependencies = [ [[package]] name = "globwalk" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baba373693f105316dff9ebdae694118df59cf8fb3fc21b2acf1e294a3893794" +checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "ignore", "walkdir", ] [[package]] name = "h2" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -1089,9 +1083,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060" +checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" dependencies = [ "crossbeam-deque", "globset", @@ -1196,9 +1190,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -1211,9 +1205,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libgit2-sys" @@ -1229,9 +1223,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050" dependencies = [ "cc", "libc", @@ -1247,9 +1241,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "log" @@ -1320,7 +1314,7 @@ dependencies = [ "filetime", "flate2", "fslock", - "globwalk 0.9.0", + "globwalk 0.9.1", "home", "humantime", "indenter", @@ -1389,7 +1383,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "libc", ] @@ -1459,7 +1453,7 @@ version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "foreign-types", "libc", @@ -1476,7 +1470,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -1558,9 +1552,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" dependencies = [ "memchr", "thiserror", @@ -1569,9 +1563,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" dependencies = [ "pest", "pest_generator", @@ -1579,22 +1573,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "pest_meta" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" dependencies = [ "once_cell", "pest", @@ -1699,9 +1693,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.72" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a293318316cf6478ec1ad2a21c49390a8d5b5eae9fab736467d93fbc0edc29c5" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -1717,9 +1711,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1917,11 +1911,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno 0.3.8", "libc", "linux-raw-sys", @@ -2070,35 +2064,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -2255,7 +2249,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -2277,9 +2271,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -2404,22 +2398,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -2759,9 +2753,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "versions" -version = "6.0.0" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c271c81503258e3850c9d0f0d279d4ce9458d3388ef9eaa081b10d542182c3" +checksum = "f37ff4899935ba747849dd9eeb27c0bdd0da0210236704b7e4681a6c7bd6f9c6" dependencies = [ "itertools", "nom", @@ -2815,9 +2809,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2825,24 +2819,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -2852,9 +2846,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2862,28 +2856,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -2948,15 +2942,6 @@ dependencies = [ "windows-targets 0.52.0", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -2975,21 +2960,6 @@ dependencies = [ "windows-targets 0.52.0", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" @@ -3020,12 +2990,6 @@ dependencies = [ "windows_x86_64_msvc 0.52.0", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3038,12 +3002,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3056,12 +3014,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3074,12 +3026,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3092,12 +3038,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3110,12 +3050,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3128,12 +3062,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3148,9 +3076,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] @@ -3167,9 +3095,9 @@ dependencies = [ [[package]] name = "xattr" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", "linux-raw-sys", diff --git a/completions/mise.bash b/completions/mise.bash index 3102ecbd4..0a2a3f882 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -4468,4 +4468,8 @@ _mise() { esac } -complete -F _mise -o nosort -o bashdefault -o default mise +if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then + complete -F _mise -o nosort -o bashdefault -o default mise +else + complete -F _mise -o bashdefault -o default mise +fi diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index cb990585d..0f3b9980f 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -1,5 +1,5 @@ use clap::builder::StyledStr; -use clap::{Arg, Command, ValueHint}; +use clap::{Arg, ArgAction, Command, ValueHint}; use itertools::Itertools; use crate::shell::completions::is_banned; @@ -102,15 +102,17 @@ fn render_arg(cmds: &[&Command], a: &Arg) -> String { } fn render_completer(a: &Arg) -> Option { - let possible_values = a.get_possible_values(); - if !possible_values.is_empty() { - return Some( - possible_values - .iter() - .map(|v| escape_value(v.get_name())) - .collect::>() - .join(" "), - ); + if let ArgAction::Set = a.get_action() { + let possible_values = a.get_possible_values(); + if !possible_values.is_empty() { + return Some( + possible_values + .iter() + .map(|v| escape_value(v.get_name())) + .collect::>() + .join(" "), + ); + } } match a.get_value_hint() { ValueHint::DirPath => Some("(__fish_complete_directories)".to_string()), From 05f76ecfbad3382ec6d42584784216d5e14aaf48 Mon Sep 17 00:00:00 2001 From: endigma Date: Tue, 16 Jan 2024 23:18:21 -0400 Subject: [PATCH 1639/1891] add support for installing directly with go modules (#1470) * add support for installing directly with go modules * alphabetize enum * update where gopath build is stored * fix bad get_type --- .devcontainer/Dockerfile | 3 ++ e2e/test_go_install | 8 +++++ src/forge/go.rs | 69 ++++++++++++++++++++++++++++++++++++++++ src/forge/mod.rs | 3 ++ 4 files changed, 83 insertions(+) create mode 100755 e2e/test_go_install create mode 100644 src/forge/go.rs diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 443372343..a1567f187 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -25,4 +25,7 @@ RUN mkdir /workspaces/target \ # npm packages && npm install -g prettier@3.1.0 markdownlint-cli@0.37.0 markdown-magic@2.6.1 +COPY --from=golang:1.21-bullseye /usr/local/go/ /usr/local/go/ +ENV PATH="/usr/local/go/bin:${PATH}" + ENTRYPOINT [ "/bin/bash" ] diff --git a/e2e/test_go_install b/e2e/test_go_install new file mode 100755 index 000000000..90b9ea160 --- /dev/null +++ b/e2e/test_go_install @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +export MISE_EXPERIMENTAL=1 + +assert "mise x go:github.com/DarthSim/hivemind@v1.1.0 -- hivemind --version" "Hivemind version 1.1.0" diff --git a/src/forge/go.rs b/src/forge/go.rs new file mode 100644 index 000000000..6f7af2522 --- /dev/null +++ b/src/forge/go.rs @@ -0,0 +1,69 @@ +use std::fmt::Debug; + +use crate::cache::CacheManager; +use crate::cli::args::ForgeArg; +use crate::cmd::CmdLineRunner; +use crate::config::{Config, Settings}; + +use crate::forge::{Forge, ForgeType}; +use crate::install_context::InstallContext; + +#[derive(Debug)] +pub struct GoForge { + fa: ForgeArg, + remote_version_cache: CacheManager>, +} + +impl Forge for GoForge { + fn get_type(&self) -> ForgeType { + ForgeType::Go + } + + fn fa(&self) -> &ForgeArg { + &self.fa + } + + fn list_remote_versions(&self) -> eyre::Result> { + self.remote_version_cache + .get_or_try_init(|| { + let raw = cmd!("go", "list", "-m", "-versions", "-json", self.name()).read()?; + let mod_info: GoModInfo = serde_json::from_str(&raw)?; + Ok(mod_info.versions) + }) + .cloned() + } + + fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { + let config = Config::try_get()?; + let settings = Settings::get(); + settings.ensure_experimental()?; + + CmdLineRunner::new("go") + .arg("install") + .arg(&format!("{}@{}", self.name(), ctx.tv.version)) + .with_pr(ctx.pr.as_ref()) + .envs(&config.env) + .env("GOPATH", ctx.tv.cache_path()) + .env("GOBIN", ctx.tv.install_path().join("bin")) + .execute()?; + + Ok(()) + } +} + +impl GoForge { + pub fn new(fa: ForgeArg) -> Self { + Self { + remote_version_cache: CacheManager::new( + fa.cache_path.join("remote_versions.msgpack.z"), + ), + fa, + } + } +} + +#[derive(Debug, serde::Deserialize)] +#[serde(rename_all = "PascalCase")] +pub struct GoModInfo { + versions: Vec, +} diff --git a/src/forge/mod.rs b/src/forge/mod.rs index b4a9f6fa5..539c35da4 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -27,6 +27,7 @@ use crate::ui::progress_report::SingleReport; use crate::{dirs, file}; mod cargo; +mod go; mod npm; pub type AForge = Arc; @@ -38,6 +39,7 @@ pub type ForgeList = Vec; pub enum ForgeType { Asdf, Cargo, + Go, Npm, } @@ -77,6 +79,7 @@ pub fn get(fa: &ForgeArg) -> AForge { ForgeType::Asdf => Arc::new(ExternalPlugin::new(name)), ForgeType::Cargo => Arc::new(CargoForge::new(fa.clone())), ForgeType::Npm => Arc::new(npm::NPMForge::new(fa.clone())), + ForgeType::Go => Arc::new(go::GoForge::new(fa.clone())), }) .clone() } From b46fa170f4fdfe4b39342389fd537aa8a4d15b10 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 16 Jan 2024 21:24:04 -0600 Subject: [PATCH 1640/1891] ensure forge type matches (#1476) --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 1 + deny.toml | 2 +- src/forge/mod.rs | 1 + src/main.rs | 2 ++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6f442e22a..5010fd863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -407,6 +407,17 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "contracts" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d1429e3bd78171c65aa010eabcdf8f863ba3254728dbfb0ad4b1545beac15c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1303,6 +1314,7 @@ dependencies = [ "color-print", "confique", "console", + "contracts", "ctor", "ctrlc", "demand", diff --git a/Cargo.toml b/Cargo.toml index caf2455f6..40ce19811 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ color-eyre = "0.6" color-print = "0.3" confique = { version = "0.2", default-features = false } console = "0.15" +contracts = "0.6.3" ctrlc = "3" demand = "0.3" dotenvy = "0.15" diff --git a/deny.toml b/deny.toml index 2bbe8fe0f..11c160865 100644 --- a/deny.toml +++ b/deny.toml @@ -109,6 +109,7 @@ allow = [ "Unicode-DFS-2016", "BSD-3-Clause", "OpenSSL", + "MPL-2.0", ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses @@ -140,7 +141,6 @@ confidence-threshold = 0.8 exceptions = [ # Each entry is the crate and version constraint, and its specific allow # list - { allow = ["MPL-2.0"], name = "webpki-roots", version = "*" }, ] # Some crates don't have (easily) machine readable licensing information, diff --git a/src/forge/mod.rs b/src/forge/mod.rs index 539c35da4..891986eb2 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -234,6 +234,7 @@ pub trait Forge: Debug + Send + Sync { fn execute_external_command(&self, _command: &str, _args: Vec) -> eyre::Result<()> { unimplemented!() } + #[requires(ctx.tv.forge.forge_type == self.get_type())] fn install_version(&self, ctx: InstallContext) -> eyre::Result<()> { let config = Config::get(); let settings = Settings::try_get()?; diff --git a/src/main.rs b/src/main.rs index fabea21e5..ba96691b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,8 @@ extern crate insta; #[macro_use] extern crate pretty_assertions; #[macro_use] +extern crate contracts; +#[macro_use] extern crate strum; use std::process::exit; From 9b81b2ac32efc63a1066057158336ae0db5b8296 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 16 Jan 2024 21:25:10 -0600 Subject: [PATCH 1641/1891] chore: Release mise version 2024.1.22 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5010fd863..33c8e977f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1302,7 +1302,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.21" +version = "2024.1.22" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 40ce19811..d79df062a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.21" +version = "2024.1.22" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index ea726716c..db9bcc257 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.21 +mise 2024.1.22 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 6ba1371e9..cd0c5f0c8 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.21"; + version = "2024.1.22"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index f1581b0e0..0893f29c9 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.21" +.TH mise 1 "mise 2024.1.22" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.21 +v2024.1.22 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 3b98854bd..a89133dad 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.21 +Version: 2024.1.22 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 205e43ade7e530d46e7b81015959417285039805 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 17 Jan 2024 15:22:45 -0600 Subject: [PATCH 1642/1891] fix config_root path (#1477) --- src/task.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/task.rs b/src/task.rs index c9946e53a..aeb42cee3 100644 --- a/src/task.rs +++ b/src/task.rs @@ -296,8 +296,10 @@ impl TreeItem for (&Graph, NodeIndex) { fn config_root(config_source: &Path) -> &Path { match config_source.parent().expect("task source has no parent") { - dir if dir.ends_with(".mise/tasks") => dir.parent().unwrap(), - dir if dir.ends_with(".config/mise/tasks") => dir.parent().unwrap().parent().unwrap(), + dir if dir.ends_with(".mise/tasks") => dir.parent().unwrap().parent().unwrap(), + dir if dir.ends_with(".config/mise/tasks") => { + dir.parent().unwrap().parent().unwrap().parent().unwrap() + } dir => dir, } } From d26640f28c9c12fe6d6025d3711c19c7bbd44c5f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 09:24:23 -0600 Subject: [PATCH 1643/1891] use mise to get development dependencies (#1478) --- .devcontainer/Dockerfile | 8 ++------ .github/workflows/test.yml | 8 +++----- CONTRIBUTING.md | 3 --- Cargo.lock | 28 ++++++++++++++-------------- justfile | 19 +++++++++---------- packaging/github-actions/Dockerfile | 6 ------ 6 files changed, 28 insertions(+), 44 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a1567f187..c713ea0c5 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -15,15 +15,11 @@ RUN mkdir /workspaces/target \ && apt-get update \ && apt-get -y install --no-install-recommends \ # shells, direnv, shellcheck - bash fish zsh direnv nodejs shellcheck \ + bash fish zsh direnv nodejs \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ - # shfmt - && curl -sS https://webi.sh/shfmt | sh \ # just - && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/bin \ - # npm packages - && npm install -g prettier@3.1.0 markdownlint-cli@0.37.0 markdown-magic@2.6.1 + && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/bin COPY --from=golang:1.21-bullseye /usr/local/go/ /usr/local/go/ ENV PATH="/usr/local/go/bin:${PATH}" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 24c3f43c2..218d9bfd0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,9 +33,8 @@ jobs: - uses: taiki-e/install-action@v2 with: tool: nextest,just,cargo-deny,cargo-msrv,cargo-machete - - name: Install direnv/shfmt - run: sudo apt-get update; sudo apt-get install direnv shfmt - - run: npm i -g markdown-magic prettier markdownlint-cli + - name: Install direnv + run: sudo apt-get update; sudo apt-get install direnv - run: cargo nextest run --all-features env: RUST_BACKTRACE: "1" @@ -72,8 +71,7 @@ jobs: with: shared-key: coverage save-if: ${{ github.ref_name == 'main' }} - - run: sudo apt-get update; sudo apt-get install zsh fish direnv shfmt - - run: npm i -g markdown-magic + - run: sudo apt-get update; sudo apt-get install zsh fish direnv - uses: taiki-e/install-action@v2 with: tool: cargo-llvm-cov,just diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0479c5a40..e000b0989 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,9 +21,6 @@ To use the container with VSCode, you'll need to install the [Remote - Container - [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that). As of this writing: 1.67.0 but GH actions will use the latest stable whenever it runs. - [just](https://github.com/casey/just) any version should do, but as of this writing I'm on 1.13.0 -- [md-magic](https://github.com/DavidWells/markdown-magic) -- [shfmt](https://github.com/mvdan/sh) -- [shellcheck](https://www.shellcheck.net/) (you'd think we'd use mise to fetch these but frankly it's kind of a pain to dogfood mise while testing it) diff --git a/Cargo.lock b/Cargo.lock index 33c8e977f..6eac4dc2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,9 +116,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "async-compression" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" dependencies = [ "flate2", "futures-core", @@ -915,9 +915,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -955,9 +955,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "home" @@ -1641,9 +1641,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "platforms" @@ -1762,9 +1762,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -1772,9 +1772,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -2685,9 +2685,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" diff --git a/justfile b/justfile index 269f955e7..41f666e8d 100644 --- a/justfile +++ b/justfile @@ -87,29 +87,28 @@ scripts := "scripts/*.sh e2e/{test_,run_}* e2e/*.sh" lint: cargo clippy -- -Dwarnings cargo fmt --all -- --check - shellcheck -x {{ scripts }} - shfmt -d {{ scripts }} + mise x shellcheck@latest -- shellcheck -x {{ scripts }} + mise x shfmt@latest -- shfmt -d {{ scripts }} just --unstable --fmt --check - prettier -c $(git ls-files '*.yml' '*.yaml') - markdownlint . + MISE_EXPERIMENTAL=1 mise x npm:prettier@latest -- prettier -c $(git ls-files '*.yml' '*.yaml') + MISE_EXPERIMENTAL=1 mise x npm:markdownlint-cli@latest -- markdownlint . # runs linters but makes fixes when possible lint-fix: cargo clippy --fix --allow-staged --allow-dirty -- -Dwarnings cargo fmt --all - shellcheck -x {{ scripts }} - shfmt -w {{ scripts }} + mise x shellcheck@latest -- shellcheck -x {{ scripts }} + mise x shfmt@latest -- shfmt -w {{ scripts }} just --unstable --fmt - prettier -w $(git ls-files '*.yml' '*.yaml') - markdownlint --fix . + MISE_EXPERIMENTAL=1 mise x npm:prettier@latest -- prettier -w $(git ls-files '*.yml' '*.yaml') + MISE_EXPERIMENTAL=1 mise x npm:markdownlint-cli@latest -- markdownlint --fix . render-all: render-help render-completions render-mangen # regenerate docs/cli-reference.md render-help: build NO_COLOR=1 mise render-help - #npx markdown-magic - md-magic + mise x node@latest -- npx markdown-magic # regenerate shell completion files render-completions: build diff --git a/packaging/github-actions/Dockerfile b/packaging/github-actions/Dockerfile index 070372154..22a89e84d 100644 --- a/packaging/github-actions/Dockerfile +++ b/packaging/github-actions/Dockerfile @@ -39,8 +39,6 @@ RUN apt-get update \ libyaml-dev \ patch \ pkg-config \ - shellcheck \ - shfmt \ sudo \ tk-dev \ uuid-dev \ @@ -53,10 +51,6 @@ RUN apt-get update \ && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ && apt-get update && apt-get install -y --no-install-recommends nodejs \ && node -v \ - && npm i -g \ - markdown-magic \ - markdownlint-cli \ - prettier \ && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ && curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash \ && rustup install stable && rustup default stable \ From 383600cc7631663fdaae6db9e2ab033db36a3bb8 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 10:16:12 -0600 Subject: [PATCH 1644/1891] plugins: improve post-plugin-update script (#1479) * only call it if the plugin was actually updated * set the ASDF_PLUGIN_PREV_REF and ASDF_PLUGIN_POST_REF env vars --- e2e/test_go_install | 1 + src/plugins/external_plugin.rs | 40 ++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/e2e/test_go_install b/e2e/test_go_install index 90b9ea160..495283dc5 100755 --- a/e2e/test_go_install +++ b/e2e/test_go_install @@ -6,3 +6,4 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 assert "mise x go:github.com/DarthSim/hivemind@v1.1.0 -- hivemind --version" "Hivemind version 1.1.0" +chmod -R u+w "$MISE_DATA_DIR/cache/go-"* diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 709e66279..ee479dae1 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -1,4 +1,5 @@ use std::collections::{BTreeMap, HashMap}; +use std::ffi::OsString; use std::fmt::{Debug, Formatter}; use std::fs; use std::hash::{Hash, Hasher}; @@ -370,10 +371,41 @@ impl ExternalPlugin { } fn exec_hook(&self, pr: &dyn SingleReport, hook: &str) -> Result<()> { + self.exec_hook_env(pr, hook, Default::default()) + } + fn exec_hook_env( + &self, + pr: &dyn SingleReport, + hook: &str, + env: HashMap, + ) -> Result<()> { let script = Script::Hook(hook.to_string()); - if self.script_man.script_exists(&script) { + let mut sm = self.script_man.clone(); + sm.env.extend(env); + if sm.script_exists(&script) { pr.set_message(format!("executing {hook} hook")); - self.script_man.run_by_line(&script, pr)?; + sm.run_by_line(&script, pr)?; + } + Ok(()) + } + + fn exec_hook_post_plugin_update( + &self, + pr: &dyn SingleReport, + pre: String, + post: String, + ) -> Result<()> { + if pre != post { + let env = [ + ("ASDF_PLUGIN_PREV_REF", pre.clone()), + ("ASDF_PLUGIN_POST_REF", post.clone()), + ("MISE_PLUGIN_PREV_REF", pre), + ("MISE_PLUGIN_POST_REF", post), + ] + .into_iter() + .map(|(k, v)| (k.into(), v.into())) + .collect(); + self.exec_hook_env(pr, "post-plugin-update", env)?; } Ok(()) } @@ -511,10 +543,10 @@ impl Forge for ExternalPlugin { return Ok(()); } pr.set_message("updating git repo".into()); - let (_pre, _post) = git.update(gitref)?; + let (pre, post) = git.update(gitref)?; let sha = git.current_sha_short()?; let repo_url = self.get_remote_url().unwrap_or_default(); - self.exec_hook(pr, "post-plugin-update")?; + self.exec_hook_post_plugin_update(pr, pre, post)?; pr.finish_with_message(format!( "{repo_url}#{}", style(&sha).bright().yellow().for_stderr(), From 8667bc51dd7af25966e423b4d84992dc8ff4fccf Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 13:48:19 -0600 Subject: [PATCH 1645/1891] tasks: only show select if no task specified (#1481) --- src/cli/run.rs | 37 +++++++++++++++++-------------------- src/ui/style.rs | 4 ++++ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index b078dc703..d68a5f896 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -9,10 +9,10 @@ use std::sync::Mutex; use std::time::SystemTime; use clap::ValueHint; -use console::{style, Color}; +use console::Color; use demand::{DemandOption, Select}; use duct::IntoExecutablePath; -use eyre::{OptionExt, Result}; +use eyre::Result; use globwalk::GlobWalkerBuilder; use itertools::Itertools; use once_cell::sync::Lazy; @@ -135,7 +135,8 @@ impl Run { .flat_map(|args| args.split_first().map(|(t, a)| (t.clone(), a.to_vec()))) .map(|(t, args)| match config.tasks_with_aliases().get(&t) { Some(task) => Ok(task.clone().with_args(args.to_vec())), - None => self.prompt_for_task(config, &t), + None if t == "default" => self.prompt_for_task(config), + None => bail!("no task {} found", style::ered(t)), }) .collect() } @@ -330,28 +331,24 @@ impl Run { } } - fn prompt_for_task(&self, config: &Config, t: &str) -> Result { + fn prompt_for_task(&self, config: &Config) -> Result { let tasks = config.tasks(); - if tasks.is_empty() { - bail!(format!( - "no tasks defined. see {url}", - url = style("https://mise.jdx.dev/tasks/").underlined() - )); - } + ensure!( + !tasks.is_empty(), + "no tasks defined. see {url}", + url = style::eunderline("https://mise.jdx.dev/tasks/") + ); let task_names = tasks.keys().sorted().collect_vec(); - let t = style(&t).yellow().for_stderr(); - let msg = format!("no task named `{t}` found. select a task to run:"); - let mut s = Select::new("Tasks").description(&msg).filterable(true); + let mut s = Select::new("Tasks") + .description("Select a task to run") + .filterable(true); for name in task_names { s = s.option(DemandOption::new(name)); } - let task_name = s.run(); - match task_name { - Ok(name) => tasks - .get(name) - .cloned() - .ok_or_eyre(format!("no task named `{}` found", name)), - Err(_) => Err(eyre!("there was an error, please try again")), + let name = s.run()?; + match tasks.get(name) { + Some(task) => Ok(task.clone()), + None => bail!("no task {} found", style::ered(name)), } } diff --git a/src/ui/style.rs b/src/ui/style.rs index 3c8a3c7ac..7c5befd49 100644 --- a/src/ui/style.rs +++ b/src/ui/style.rs @@ -28,6 +28,10 @@ pub fn ered(val: D) -> StyledObject { estyle(val).red() } +pub fn eunderline(val: D) -> StyledObject { + estyle(val).underlined() +} + pub fn edim(val: D) -> StyledObject { estyle(val).dim() } From ebc5fe78bc97ecf99251438e6f305908bb134833 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:02:25 -0600 Subject: [PATCH 1646/1891] tasks: show cursor on ctrl-c --- src/cli/run.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli/run.rs b/src/cli/run.rs index d68a5f896..acd99ea92 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -345,6 +345,7 @@ impl Run { for name in task_names { s = s.option(DemandOption::new(name)); } + ui::handle_ctrlc(); let name = s.run()?; match tasks.get(name) { Some(task) => Ok(task.clone()), From f0965ad57faa36f14adf1809535eae6738f6578c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:22:09 -0600 Subject: [PATCH 1647/1891] tasks: fix project_root when using .config/mise.toml or .mise/config.toml (#1482) Fixes #1480 --- src/config/config_file/mise_toml.rs | 4 ++-- src/config/mod.rs | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 629ba7820..94add10bd 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -611,8 +611,8 @@ impl ConfigFile for MiseToml { dir if dir.starts_with(*dirs::CONFIG) => None, dir if dir.starts_with(*dirs::SYSTEM) => None, dir if dir == *dirs::HOME => None, - dir if !filename.starts_with('.') && dir.ends_with("/.mise") => dir.parent(), - dir if !filename.starts_with('.') && dir.ends_with("/.config/mise") => { + dir if !filename.starts_with('.') && dir.ends_with(".mise") => dir.parent(), + dir if !filename.starts_with('.') && dir.ends_with(".config/mise") => { dir.parent().unwrap().parent() } dir => Some(dir), diff --git a/src/config/mod.rs b/src/config/mod.rs index 6f43fce8e..4520b5240 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -214,6 +214,9 @@ impl Config { .chain(once((t.name.clone(), t.clone()))) .collect::>() }) + .collect::>() + .into_iter() + .rev() .collect() } From 1069155a2a4cbd8142dbdc720fea76a4ab201035 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:27:26 -0600 Subject: [PATCH 1648/1891] chore: Release mise version 2024.1.23 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- src/default_shorthands.rs | 14 +++++++++----- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6eac4dc2d..b8bdc94a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1302,7 +1302,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.22" +version = "2024.1.23" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index d79df062a..e1b5f2b0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.22" +version = "2024.1.23" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index db9bcc257..346ffe50a 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.22 +mise 2024.1.23 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index cd0c5f0c8..17ae5e6ca 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.22"; + version = "2024.1.23"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 0893f29c9..212e49727 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.22" +.TH mise 1 "mise 2024.1.23" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.22 +v2024.1.23 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index a89133dad..e3ba3eec7 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.22 +Version: 2024.1.23 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index 394798fd5..df8f10ab9 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -315,7 +315,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("hls", "https://github.com/sestrella/asdf-ghcup.git"), ("hostctl", "https://github.com/svenluijten/asdf-hostctl.git"), ("httpie-go", "https://github.com/abatilo/asdf-httpie-go.git"), - ("hub", "https://github.com/rtx-plugins/asdf-hub.git"), + ("hub", "https://github.com/mise-plugins/asdf-hub.git"), ("hugo", "https://github.com/NeoHsu/asdf-hugo.git"), ("hurl", "https://github.com/raimon49/asdf-hurl.git"), ("hwatch", "https://github.com/chessmango/asdf-hwatch.git"), @@ -430,7 +430,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("ls-lint", "https://github.com/Ameausoone/asdf-ls-lint.git"), ("lua", "https://github.com/Stratus3D/asdf-lua.git"), ("lua-language-server", "https://github.com/bellini666/asdf-lua-language-server"), - ("luaJIT", "https://github.com/smashedtoatoms/asdf-luaJIT.git"), + ("luajit", "https://github.com/smashedtoatoms/asdf-luaJIT.git"), ("lucy", "https://github.com/cometkim/asdf-lucy.git"), ("maestro", "https://github.com/dotanuki-labs/asdf-maestro.git"), ("mage", "https://github.com/mathew-fleisch/asdf-mage.git"), @@ -518,13 +518,13 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("pint", "https://github.com/sam-burrell/asdf-pint.git"), ("pipectl", "https://github.com/pipe-cd/asdf-pipectl.git"), ("pipelight", "https://github.com/kogeletey/asdf-pipelight.git"), - ("pipenv", "https://github.com/rtx-plugins/rtx-pipenv.git"), + ("pipenv", "https://github.com/mise-plugins/mise-pipenv.git"), ("pipx", "https://github.com/yozachar/asdf-pipx.git"), ("pivnet", "https://github.com/vmware-tanzu/tanzu-plug-in-for-asdf.git"), ("please", "https://github.com/asdf-community/asdf-please.git"), ("pluto", "https://github.com/FairwindsOps/asdf-pluto.git"), ("pnpm", "https://github.com/jonathanmorley/asdf-pnpm.git"), - ("poetry", "https://github.com/rtx-plugins/rtx-poetry.git"), + ("poetry", "https://github.com/mise-plugins/mise-poetry.git"), ("polaris", "https://github.com/particledecay/asdf-polaris.git"), ("popeye", "https://github.com/nlamirault/asdf-popeye.git"), ("postgres", "https://github.com/smashedtoatoms/asdf-postgres.git"), @@ -680,7 +680,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("thrift", "https://github.com/alisaifee/asdf-thrift.git"), ("tilt", "https://github.com/eaceaser/asdf-tilt.git"), ("timoni", "https://github.com/Smana/asdf-timoni.git"), - ("tiny", "https://github.com/rtx-plugins/rtx-tiny.git"), + ("tiny", "https://github.com/mise-plugins/mise-tiny.git"), ("tinytex", "https://github.com/Fbrisset/asdf-tinytex.git"), ("titan", "https://github.com/gabitchov/asdf-titan.git"), ("tlsg-cli", "https://github.com/0ghny/asdf-tlsgcli.git"), @@ -763,5 +763,9 @@ pub static TRUSTED_SHORTHANDS: Lazy> = Lazy::new(|| HashSet::from([ "dt", "elixir", + "hub", + "pipenv", + "poetry", + "tiny", "tuist", ])); From 523117975bbb9c3211f0f438f55d1d7dc392f8b2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:29:20 -0600 Subject: [PATCH 1649/1891] bump demand --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8bdc94a3..b847fedcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628a8f9bd1e24b4e0db2b4bc2d000b001e7dd032d54afa60a68836aeec5aa54a" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", diff --git a/Cargo.toml b/Cargo.toml index e1b5f2b0c..fb923e1f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ confique = { version = "0.2", default-features = false } console = "0.15" contracts = "0.6.3" ctrlc = "3" -demand = "0.3" +demand = "0.4" dotenvy = "0.15" duct = "0.13" either = "1" From 8d39995e615527ba7187b3d25369a506bcb21e0c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:45:02 -0600 Subject: [PATCH 1650/1891] runtime_symlinks: do not fail if version parsing fails --- src/runtime_symlinks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index 39e05a4e8..384b66df4 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -46,7 +46,7 @@ fn list_symlinks(config: &Config, forge: Arc) -> Result Date: Thu, 18 Jan 2024 17:10:26 -0600 Subject: [PATCH 1651/1891] activate: added --shims (#1483) * activate: added --shims * runtime_symlinks: do not fail if version parsing fails --- Cargo.lock | 4 +-- completions/_mise | 1 + completions/mise.bash | 2 +- completions/mise.fish | 1 + docs/cli-reference.md | 5 +++ src/cli/activate.rs | 20 ++++++++++-- src/shell/bash.rs | 31 ++++++++++++++++--- src/shell/fish.rs | 26 ++++++++++++++-- src/shell/mod.rs | 11 ++++++- ...> mise__shell__bash__tests__activate.snap} | 0 ...se__shell__bash__tests__activate_nix.snap} | 0 ...ise__shell__bash__tests__prepend_path.snap | 6 ++++ ...> mise__shell__fish__tests__activate.snap} | 0 ...se__shell__fish__tests__activate_nix.snap} | 0 ...ise__shell__fish__tests__prepend_path.snap | 6 ++++ ...=> mise__shell__zsh__tests__activate.snap} | 0 ...ise__shell__zsh__tests__activate_nix.snap} | 0 ...mise__shell__zsh__tests__prepend_path.snap | 6 ++++ src/shell/zsh.rs | 25 +++++++++++++-- 19 files changed, 127 insertions(+), 17 deletions(-) rename src/shell/snapshots/{mise__shell__bash__tests__hook_init.snap => mise__shell__bash__tests__activate.snap} (100%) rename src/shell/snapshots/{mise__shell__bash__tests__hook_init_nix.snap => mise__shell__bash__tests__activate_nix.snap} (100%) create mode 100644 src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap rename src/shell/snapshots/{mise__shell__fish__tests__hook_init.snap => mise__shell__fish__tests__activate.snap} (100%) rename src/shell/snapshots/{mise__shell__fish__tests__hook_init_nix.snap => mise__shell__fish__tests__activate_nix.snap} (100%) create mode 100644 src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap rename src/shell/snapshots/{mise__shell__zsh__tests__hook_init.snap => mise__shell__zsh__tests__activate.snap} (100%) rename src/shell/snapshots/{mise__shell__zsh__tests__hook_init_nix.snap => mise__shell__zsh__tests__activate_nix.snap} (100%) create mode 100644 src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap diff --git a/Cargo.lock b/Cargo.lock index b847fedcb..d02a2fcf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,9 +537,9 @@ dependencies = [ [[package]] name = "demand" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d848199107fe9efba52867f0050bf80d1dc9ba1e032ba804dbdabea18ddd7f0d" +checksum = "428fa6ef17b14e980183ddfcdf751ae3405976329911450280aa4ce1268c884d" dependencies = [ "console", "termcolor", diff --git a/completions/_mise b/completions/_mise index 21667efb3..caeb3e613 100644 --- a/completions/_mise +++ b/completions/_mise @@ -70,6 +70,7 @@ __mise_activate_cmd() { _arguments -s -S \ '::shell_type:(bash fish nu xonsh zsh)' \ '--status[Show "mise\: @" message when changing directories]' \ + '--shims[Use shims instead of modifying PATH]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ diff --git a/completions/mise.bash b/completions/mise.bash index 0a2a3f882..96fdfe72f 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -738,7 +738,7 @@ _mise() { return 0 ;; mise__activate) - opts="-s -q -C -v -y -h --shell --status --quiet --cd --debug --log-level --trace --verbose --yes --help bash fish nu xonsh zsh" + opts="-s -q -C -v -y -h --shell --status --shims --quiet --cd --debug --log-level --trace --verbose --yes --help bash fish nu xonsh zsh" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/mise.fish b/completions/mise.fish index 487c1acf5..774c8f7dd 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -48,6 +48,7 @@ complete -xc mise -n "not $fssf $others" -a which -d 'Shows the path that a bin # activate complete -kxc mise -n "$fssf activate" -s q -l quiet -d 'Suppress non-error messages' complete -kxc mise -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' +complete -kxc mise -n "$fssf activate" -l shims -d 'Use shims instead of modifying PATH' complete -kxc mise -n "$fssf activate" -l status -d 'Show "mise: @" message when changing directories' # alias diff --git a/docs/cli-reference.md b/docs/cli-reference.md index d77c7e866..d41489c37 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -36,6 +36,11 @@ Options: --status Show "mise: @" message when changing directories + --shims + Use shims instead of modifying PATH + Effectively the same as: + PATH="$HOME/.local/share/mise/shims:$PATH" + -q, --quiet Suppress non-error messages diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 7c9b58be7..475c0334b 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -1,9 +1,9 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use eyre::Result; use crate::file::touch_dir; -use crate::shell::{get_shell, ShellType}; +use crate::shell::{get_shell, Shell, ShellType}; use crate::{dirs, env}; /// Initializes mise in the current shell session @@ -39,6 +39,12 @@ pub struct Activate { #[clap(long)] status: bool, + /// Use shims instead of modifying PATH + /// Effectively the same as: + /// PATH="$HOME/.local/share/mise/shims:$PATH" + #[clap(long, verbatim_doc_comment)] + shims: bool, + /// Suppress non-error messages #[clap(long, short)] quiet: bool, @@ -65,11 +71,19 @@ impl Activate { if self.status { flags.push(" --status"); } - let output = shell.activate(&mise_bin, flags.join("")); + let output = match self.shims { + true => self.activate_shims(shell.as_ref(), &mise_bin), + false => shell.activate(&mise_bin, flags.join("")), + }; miseprint!("{output}"); Ok(()) } + + fn activate_shims(&self, shell: &dyn Shell, exe: &Path) -> String { + let exe_dir = exe.parent().unwrap().to_path_buf(); + shell.prepend_path(&[exe_dir, dirs::SHIMS.clone()]) + } } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/shell/bash.rs b/src/shell/bash.rs index d4254b75a..019d2c309 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::config::Settings; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; @@ -82,6 +82,19 @@ impl Shell for Bash { "#} } + fn prepend_path(&self, paths: &[PathBuf]) -> String { + if paths.is_empty() { + return String::new(); + } + let mut path = String::new(); + for p in paths { + if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { + path = format!("{}:{path}", p.display()); + } + } + format!("export PATH=\"{}$PATH\"\n", path) + } + fn set_env(&self, k: &str, v: &str) -> String { let k = shell_escape::unix::escape(k.into()); let v = shell_escape::unix::escape(v.into()); @@ -96,23 +109,33 @@ impl Shell for Bash { #[cfg(test)] mod tests { - use super::*; + use std::path::PathBuf; + use crate::test::replace_path; + use super::*; + #[test] - fn test_hook_init() { + fn test_activate() { let bash = Bash::default(); let exe = Path::new("/some/dir/mise"); assert_snapshot!(bash.activate(exe, " --status".into())); } #[test] - fn test_hook_init_nix() { + fn test_activate_nix() { let bash = Bash::default(); let exe = Path::new("/nix/store/mise"); assert_snapshot!(bash.activate(exe, " --status".into())); } + #[test] + fn test_prepend_path() { + let bash = Bash::default(); + let paths = vec![PathBuf::from("/some/dir"), PathBuf::from("/some/other/dir")]; + assert_snapshot!(replace_path(&bash.prepend_path(&paths))); + } + #[test] fn test_set_env() { assert_snapshot!(Bash::default().set_env("FOO", "1")); diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 675242674..4b60c306d 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::config::Settings; use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; @@ -101,6 +101,19 @@ impl Shell for Fish { "#} } + fn prepend_path(&self, paths: &[PathBuf]) -> String { + if paths.is_empty() { + return String::new(); + } + let mut path = String::new(); + for p in paths { + if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { + path = format!("{} {path}", p.display()); + } + } + format!("set -gx PATH {path}$PATH\n") + } + fn set_env(&self, k: &str, v: &str) -> String { let k = shell_escape::unix::escape(k.into()); let v = shell_escape::unix::escape(v.into()); @@ -119,19 +132,26 @@ mod tests { use crate::test::replace_path; #[test] - fn test_hook_init() { + fn test_activate() { let fish = Fish::default(); let exe = Path::new("/some/dir/mise"); assert_snapshot!(fish.activate(exe, " --status".into())); } #[test] - fn test_hook_init_nix() { + fn test_activate_nix() { let fish = Fish::default(); let exe = Path::new("/nix/store/mise"); assert_snapshot!(fish.activate(exe, " --status".into())); } + #[test] + fn test_prepend_path() { + let fish = Fish::default(); + let paths = vec![PathBuf::from("/some/dir"), PathBuf::from("/some/other/dir")]; + assert_snapshot!(fish.prepend_path(&paths)); + } + #[test] fn test_set_env() { assert_snapshot!(Fish::default().set_env("FOO", "1")); diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 24706c070..0da713fcb 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,5 +1,5 @@ use std::fmt::{Display, Formatter}; -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::env; @@ -54,6 +54,15 @@ impl Display for ShellType { pub trait Shell { fn activate(&self, exe: &Path, flags: String) -> String; + fn prepend_path(&self, paths: &[PathBuf]) -> String { + let mut path = env::var("PATH").unwrap_or_default(); + for p in paths { + if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { + path = format!("{}:{path}", p.display()); + } + } + self.set_env("PATH", &path) + } fn deactivate(&self) -> String; fn set_env(&self, k: &str, v: &str) -> String; fn unset_env(&self, k: &str) -> String; diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init.snap b/src/shell/snapshots/mise__shell__bash__tests__activate.snap similarity index 100% rename from src/shell/snapshots/mise__shell__bash__tests__hook_init.snap rename to src/shell/snapshots/mise__shell__bash__tests__activate.snap diff --git a/src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__bash__tests__activate_nix.snap similarity index 100% rename from src/shell/snapshots/mise__shell__bash__tests__hook_init_nix.snap rename to src/shell/snapshots/mise__shell__bash__tests__activate_nix.snap diff --git a/src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap b/src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap new file mode 100644 index 000000000..5fc8af66f --- /dev/null +++ b/src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap @@ -0,0 +1,6 @@ +--- +source: src/shell/bash.rs +expression: replace_path(&bash.prepend_path(&paths)) +--- +export PATH="/some/other/dir:/some/dir:$PATH" + diff --git a/src/shell/snapshots/mise__shell__fish__tests__hook_init.snap b/src/shell/snapshots/mise__shell__fish__tests__activate.snap similarity index 100% rename from src/shell/snapshots/mise__shell__fish__tests__hook_init.snap rename to src/shell/snapshots/mise__shell__fish__tests__activate.snap diff --git a/src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__fish__tests__activate_nix.snap similarity index 100% rename from src/shell/snapshots/mise__shell__fish__tests__hook_init_nix.snap rename to src/shell/snapshots/mise__shell__fish__tests__activate_nix.snap diff --git a/src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap b/src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap new file mode 100644 index 000000000..cf85e58a2 --- /dev/null +++ b/src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap @@ -0,0 +1,6 @@ +--- +source: src/shell/fish.rs +expression: fish.prepend_path(&paths) +--- +set -gx PATH /some/other/dir /some/dir $PATH + diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap b/src/shell/snapshots/mise__shell__zsh__tests__activate.snap similarity index 100% rename from src/shell/snapshots/mise__shell__zsh__tests__hook_init.snap rename to src/shell/snapshots/mise__shell__zsh__tests__activate.snap diff --git a/src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__zsh__tests__activate_nix.snap similarity index 100% rename from src/shell/snapshots/mise__shell__zsh__tests__hook_init_nix.snap rename to src/shell/snapshots/mise__shell__zsh__tests__activate_nix.snap diff --git a/src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap b/src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap new file mode 100644 index 000000000..6013a0e0b --- /dev/null +++ b/src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap @@ -0,0 +1,6 @@ +--- +source: src/shell/zsh.rs +expression: "zsh.prepend_path(&[PathBuf::from(\"/some/dir\")])" +--- +export PATH="/some/dir:$PATH" + diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index ded203fc3..c75769503 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::config::Settings; use crate::shell::bash::Bash; @@ -90,6 +90,19 @@ impl Shell for Zsh { "#} } + fn prepend_path(&self, paths: &[PathBuf]) -> String { + if paths.is_empty() { + return String::new(); + } + let mut path = String::new(); + for p in paths { + if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { + path = format!("{}:{path}", p.display()); + } + } + format!("export PATH=\"{path}$PATH\"\n") + } + fn set_env(&self, k: &str, v: &str) -> String { Bash::default().set_env(k, v) } @@ -105,19 +118,25 @@ mod tests { use crate::test::replace_path; #[test] - fn test_hook_init() { + fn test_activate() { let zsh = Zsh::default(); let exe = Path::new("/some/dir/mise"); assert_snapshot!(zsh.activate(exe, " --status".into())); } #[test] - fn test_hook_init_nix() { + fn test_activate_nix() { let zsh = Zsh::default(); let exe = Path::new("/nix/store/mise"); assert_snapshot!(zsh.activate(exe, " --status".into())); } + #[test] + fn test_prepend_path() { + let zsh = Zsh::default(); + assert_snapshot!(zsh.prepend_path(&[PathBuf::from("/some/dir")])); + } + #[test] fn test_set_env() { assert_snapshot!(Zsh::default().set_env("FOO", "1")); From 334ee48138448bc5ba320da45c8d60e9cdcec2c2 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:30:23 -0600 Subject: [PATCH 1652/1891] fish_completion: use `sort -r` instead of `tac` (#1486) hopefully this is more portable Fixes #1485 --- completions/mise.fish | 3 ++- src/shell/completions/fish_complete.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/completions/mise.fish b/completions/mise.fish index 774c8f7dd..6e1fb43af 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -384,7 +384,8 @@ function __mise_plugins end function __mise_tool_versions if test -z "$__mise_tool_versions_cache" - set -g __mise_tool_versions_cache (mise plugins --core --user) (mise ls-remote --all | tac) + # sed madness reverses the input-but works on linux/bsd + set -g __mise_tool_versions_cache (mise plugins --core --user) (mise ls-remote --all | sed '1!G;h;$!d') end for tv in $__mise_tool_versions_cache echo $tv diff --git a/src/shell/completions/fish_complete.rs b/src/shell/completions/fish_complete.rs index 0f3b9980f..4c91f4478 100644 --- a/src/shell/completions/fish_complete.rs +++ b/src/shell/completions/fish_complete.rs @@ -31,7 +31,8 @@ function __mise_plugins end function __mise_tool_versions if test -z "$__mise_tool_versions_cache" - set -g __mise_tool_versions_cache (mise plugins --core --user) (mise ls-remote --all | tac) + # sed madness reverses the input-but works on linux/bsd + set -g __mise_tool_versions_cache (mise plugins --core --user) (mise ls-remote --all | sed '1!G;h;$!d') end for tv in $__mise_tool_versions_cache echo $tv From f3291d15f94c0a0cc602c01d5b7b6ef7c3cb60bf Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:57:44 -0600 Subject: [PATCH 1653/1891] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 346ffe50a..f659ed959 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ -
Crates.io GitHub GitHub Workflow Status From 729de0cb6c27646e30ee7be99d2f478f3431258c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:49:42 -0600 Subject: [PATCH 1654/1891] aur: fix conflicts See https://aur.archlinux.org/packages/mise#comment-952662 --- scripts/release-aur.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/release-aur.sh b/scripts/release-aur.sh index 8e88b33e2..722d392f2 100755 --- a/scripts/release-aur.sh +++ b/scripts/release-aur.sh @@ -22,7 +22,7 @@ url='https://github.com/jdx/mise' license=('MIT') makedepends=('cargo') provides=('mise') -conflicts=('mise-bin' 'rtx' 'rtx-bin') +conflicts=('rtx' 'rtx-bin') replaces=('rtx') options=('!lto') source=("\$pkgname-\$pkgver.tar.gz::https://github.com/jdx/\$pkgname/archive/v\$pkgver.tar.gz") @@ -68,7 +68,6 @@ provides = mise replaces = rtx conflicts = rtx conflicts = rtx-bin -conflicts = mise-bin source = mise-${MISE_VERSION#v*}.tar.gz::https://github.com/jdx/mise/archive/$MISE_VERSION.tar.gz sha512sums = $SHA512 From 1c0bc1236fce943ed9b012e95e3cc047cdc38ab0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 19 Jan 2024 20:20:38 -0600 Subject: [PATCH 1655/1891] fix cwd error --- src/tera.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tera.rs b/src/tera.rs index 374e97514..290a76b8c 100644 --- a/src/tera.rs +++ b/src/tera.rs @@ -11,7 +11,9 @@ use crate::hash::hash_to_str; pub static BASE_CONTEXT: Lazy = Lazy::new(|| { let mut context = Context::new(); context.insert("env", &*env::PRISTINE_ENV); - context.insert("cwd", &*env::current_dir().unwrap()); + if let Ok(dir) = env::current_dir() { + context.insert("cwd", &dir); + } context }); From 1bbba92bd11a82697010f793e3c23b21da387769 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 20:21:13 -0600 Subject: [PATCH 1656/1891] chore(deps): update actions/cache action to v4 (#1488) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 93e3250b9..28704cbe4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,7 +69,7 @@ jobs: # runs-on: macos-12 steps: - uses: actions/checkout@v4 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/.cargo/bin/zipsign key: ${{ runner.os }}-cargo-zipsign From 08752930c1a0e9aa0961745fc2647489468e10d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 20:35:08 -0600 Subject: [PATCH 1657/1891] fix(deps): update rust crate which to v6 (#1489) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d02a2fcf5..266572123 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2903,15 +2903,15 @@ checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" [[package]] name = "which" -version = "5.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" +checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c" dependencies = [ "either", "home", "once_cell", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fb923e1f9..facaa1b7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,7 @@ toml = { version = "0.8", features = ["parse"] } toml_edit = { version = "0.21", features = ["parse"] } url = "2" versions = "6" -which = "5" +which = "6" zip = { version = "0.6", default-features = false, features = ["deflate"] } [target.'cfg(unix)'.dependencies] From df3dd08fbdc1843b45a67ba01dfa85cb0097b8a5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 19 Jan 2024 20:43:38 -0600 Subject: [PATCH 1658/1891] fix(deps): update rust crate which to v6 (#1490) --- Cargo.lock | 12 ++--- Cargo.toml | 126 ++++++++++++++++++++++++++--------------------------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 266572123..cc28f0ac2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,9 +277,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.7" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb0d4825b75ff281318c393e8e1b80c4da9fb75a6b1d98547d389d6fe1f48d2" +checksum = "eaf7dcb7c21d8ca1a2482ee0f1d341f437c9a7af6ca6da359dc5e1b164e98215" dependencies = [ "clap", ] @@ -1461,9 +1461,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.62" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ "bitflags 2.4.2", "cfg-if", @@ -1493,9 +1493,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.98" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index facaa1b7c..2245768e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,81 +38,81 @@ path = "src/main.rs" lto = true [dependencies] -base64 = "0.21" -chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } -clap = { version = "4", features = ["env", "derive", "string"] } -clap_complete = { version = "4", optional = true } -clap_mangen = { version = "0.2", optional = true } -color-eyre = "0.6" -color-print = "0.3" -confique = { version = "0.2", default-features = false } -console = "0.15" +base64 = "0.21.7" +chrono = { version = "0.4.31", default-features = false, features = ["std", "clock"] } +clap = { version = "4.4.18", features = ["env", "derive", "string"] } +clap_complete = { version = "4.4.8", optional = true } +clap_mangen = { version = "0.2.17", optional = true } +color-eyre = "0.6.2" +color-print = "0.3.5" +confique = { version = "0.2.5", default-features = false } +console = "0.15.8" contracts = "0.6.3" -ctrlc = "3" -demand = "0.4" -dotenvy = "0.15" -duct = "0.13" -either = "1" -eyre = "0.6" -filetime = "0.2" -flate2 = "1" -fslock = "0.2" -globwalk = "0.9" +ctrlc = "3.4.2" +demand = "0.4.0" +dotenvy = "0.15.7" +duct = "0.13.7" +either = "1.9.0" +eyre = "0.6.11" +filetime = "0.2.23" +flate2 = "1.0.28" +fslock = "0.2.1" +globwalk = "0.9.1" home = "0.5.9" -humantime = "2" -indenter = "0.3" -indexmap = { version = "2", features = ["serde"] } -indicatif = { version = "0.17", features = ["default", "improved_unicode"] } -indoc = "<3" -itertools = "0.12" -log = "0.4" -num_cpus = "1" -once_cell = "1" -openssl = { version = "0.10", optional = true } -path-absolutize = "3" -petgraph = "0.6" -rand = "0.8" -rayon = "1" -regex = "1" -reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "gzip"] } -rmp-serde = "1" -self_update = { version = "0.39", default-features = false, features = [ +humantime = "2.1.0" +indenter = "0.3.3" +indexmap = { version = "2.1.0", features = ["serde"] } +indicatif = { version = "0.17.7", features = ["default", "improved_unicode"] } +indoc = "2.0.4" +itertools = "0.12.0" +log = "0.4.20" +num_cpus = "1.16.0" +once_cell = "1.19.0" +openssl = { version = "0.10.63", optional = true } +path-absolutize = "3.1.1" +petgraph = "0.6.4" +rand = "0.8.5" +rayon = "1.8.1" +regex = "1.10.2" +reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "gzip"] } +rmp-serde = "1.1.2" +self_update = { version = "0.39.0", default-features = false, features = [ "archive-tar", "compression-flate2", "signatures", ] } -serde = "1" -serde_derive = "1" -serde_json = { version = "1", features = [] } -sha2 = "0.10" -shell-escape = "0.1" -shell-words = "1" -simplelog = { version = "0.12" } -strum = { version = "0.25", features = ["derive"] } -sys-info = "0.9" -tabled = { version = "0.15", features = ["ansi"] } -tar = "0.4" -tempfile = "3" -tera = { version = "1", default-features = false } -terminal_size = "0.3" -thiserror = "1" -toml = { version = "0.8", features = ["parse"] } -toml_edit = { version = "0.21", features = ["parse"] } -url = "2" -versions = "6" -which = "6" -zip = { version = "0.6", default-features = false, features = ["deflate"] } +serde = "1.0.195" +serde_derive = "1.0.195" +serde_json = { version = "1.0.111", features = [] } +sha2 = "0.10.8" +shell-escape = "0.1.5" +shell-words = "1.1.0" +simplelog = { version = "0.12.1" } +strum = { version = "0.25.0", features = ["derive"] } +sys-info = "0.9.1" +tabled = { version = "0.15.0", features = ["ansi"] } +tar = "0.4.40" +tempfile = "3.9.0" +tera = { version = "1.19.1", default-features = false } +terminal_size = "0.3.0" +thiserror = "1.0.56" +toml = { version = "0.8.8", features = ["parse"] } +toml_edit = { version = "0.21.0", features = ["parse"] } +url = "2.5.0" +versions = "6.1.0" +which = "6.0.0" +zip = { version = "0.6.6", default-features = false, features = ["deflate"] } [target.'cfg(unix)'.dependencies] -exec = "0.3" +exec = "0.3.1" [build-dependencies] -built = { version = "0.7", features = ["chrono", "git2"] } +built = { version = "0.7.1", features = ["chrono", "git2"] } [dev-dependencies] -ctor = "0.2" -insta = { version = "1", features = ["filters", "json"] } -pretty_assertions = "1" +ctor = "0.2.6" +insta = { version = "1.34.0", features = ["filters", "json"] } +pretty_assertions = "1.4.0" [features] default = ["native-tls"] From de3751398b954da5f93d4c9eac84f0e502f49e33 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 19 Jan 2024 20:47:28 -0600 Subject: [PATCH 1659/1891] chore: Release mise version 2024.1.24 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc28f0ac2..1208aca24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1302,7 +1302,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.23" +version = "2024.1.24" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 2245768e3..871bae583 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.23" +version = "2024.1.24" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index f659ed959..76878c97f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.23 +mise 2024.1.24 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 17ae5e6ca..c6b23b7ff 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.23"; + version = "2024.1.24"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 212e49727..782100cc6 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.23" +.TH mise 1 "mise 2024.1.24" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.23 +v2024.1.24 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index e3ba3eec7..47e3e9c49 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.23 +Version: 2024.1.24 Release: 1 URL: https://github.com/jdx/mise/ Group: System From bcadbf8d3835708e208125f2eb1f67920c168bb0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Jan 2024 13:11:46 -0600 Subject: [PATCH 1660/1891] fix(deps): update rust crate regex to 1.10.3 (#1496) * fix(deps): update rust crate regex to 1.10.3 * [MegaLinter] Apply linters fixes --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: renovate[bot] --- .devcontainer/devcontainer.json | 4 ++-- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index cfb16e6c7..fe57d7473 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,7 +7,7 @@ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "build": { - "dockerfile": "Dockerfile" + "dockerfile": "Dockerfile", }, // Use 'mounts' to make the cargo cache persistent in a Docker Volume. @@ -32,5 +32,5 @@ // "customizations": {}, // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - "remoteUser": "root" + "remoteUser": "root", } diff --git a/Cargo.lock b/Cargo.lock index 1208aca24..8c7f08a22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1791,9 +1791,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -1803,9 +1803,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 871bae583..7c97c824e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,7 +73,7 @@ path-absolutize = "3.1.1" petgraph = "0.6.4" rand = "0.8.5" rayon = "1.8.1" -regex = "1.10.2" +regex = "1.10.3" reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "gzip"] } rmp-serde = "1.1.2" self_update = { version = "0.39.0", default-features = false, features = [ From 4034674436f786691e767c6ac09921b06e968a86 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:06:55 -0600 Subject: [PATCH 1661/1891] updated clap_complete --- Cargo.lock | 8 +- completions/mise.bash | 751 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 609 insertions(+), 150 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c7f08a22..92ed44a57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,9 +277,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.8" +version = "4.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf7dcb7c21d8ca1a2482ee0f1d341f437c9a7af6ca6da359dc5e1b164e98215" +checksum = "df631ae429f6613fcd3a7c1adbdb65f637271e561b03680adaa6573015dfb106" dependencies = [ "clap", ] @@ -1705,9 +1705,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] diff --git a/completions/mise.bash b/completions/mise.bash index 96fdfe72f..e77ba102a 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -719,11 +719,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -753,11 +759,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -787,11 +799,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -813,11 +831,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -923,11 +947,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -949,11 +979,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -975,11 +1011,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1001,11 +1043,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1027,11 +1075,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1053,11 +1107,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1079,11 +1139,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1155,11 +1221,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1181,11 +1253,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1208,18 +1286,30 @@ _mise() { case "${prev}" in --output) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; -o) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1297,11 +1387,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1323,11 +1419,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1349,11 +1451,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1375,11 +1483,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1401,11 +1515,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1427,11 +1547,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1453,11 +1579,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1549,11 +1681,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1583,11 +1721,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1625,11 +1769,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -1655,11 +1805,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2725,11 +2881,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2759,11 +2921,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2785,11 +2953,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2819,11 +2993,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2845,11 +3025,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2871,11 +3057,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2901,11 +3093,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2939,11 +3137,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2965,11 +3169,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -2991,11 +3201,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3017,11 +3233,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3155,11 +3377,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3181,11 +3409,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3207,11 +3441,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3233,11 +3473,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3259,11 +3505,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3293,11 +3545,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3319,11 +3577,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3353,11 +3617,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3379,11 +3649,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3405,11 +3681,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3431,11 +3713,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3457,11 +3745,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --tool) @@ -3499,11 +3793,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3526,6 +3826,9 @@ _mise() { case "${prev}" in --file) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; --remove) @@ -3533,11 +3836,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3559,11 +3868,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3585,11 +3900,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3695,11 +4016,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3721,11 +4048,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3747,11 +4080,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3781,11 +4120,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3807,11 +4152,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3889,11 +4240,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3915,11 +4272,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3941,11 +4304,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3967,11 +4336,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -3993,11 +4368,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4103,11 +4484,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4129,11 +4516,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --tool) @@ -4171,11 +4564,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4197,11 +4596,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4224,18 +4629,30 @@ _mise() { case "${prev}" in --file) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; -f) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4265,11 +4682,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4312,18 +4735,30 @@ _mise() { ;; --path) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; -p) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4345,11 +4780,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4387,11 +4828,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4413,11 +4860,17 @@ _mise() { fi case "${prev}" in --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) @@ -4447,11 +4900,17 @@ _mise() { return 0 ;; --cd) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; -C) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o plusdirs + fi return 0 ;; --log-level) From 12d87c215fc292df84484de810ff1975477e2513 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Mon, 22 Jan 2024 20:09:24 -0500 Subject: [PATCH 1662/1891] feat(config): support arrays of env tables (#1503) --- src/config/config_file/mise_toml.rs | 106 +++++++++++++++++++++------- 1 file changed, 80 insertions(+), 26 deletions(-) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 94add10bd..e8ca42efb 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -7,7 +7,7 @@ use std::sync::Mutex; use eyre::{Result, WrapErr}; use serde_derive::Deserialize; use tera::Context as TeraContext; -use toml_edit::{table, value, Array, Document, Item, Value}; +use toml_edit::{table, value, Array, Document, Item, TableLike, Value}; use versions::Versioning; use crate::cli::args::ForgeArg; @@ -149,35 +149,51 @@ impl MiseToml { fn parse_env(&mut self, key: &str, v: &Item) -> Result<()> { trust_check(&self.path)?; - if let Some(table) = v.as_table_like() { - ensure!( - !table.contains_key("PATH"), - "use 'env.mise.path' instead of 'env.PATH'" - ); + + if let Some(arr) = v.as_array_of_tables() { + arr.iter() + .try_for_each(|table| self.parse_single_env(key, table)) + } else if let Some(table) = v.as_table() { + self.parse_single_env(key, table) + } else { + parse_error!(key, v, "table or array of tables") } - match v.as_table_like() { - Some(table) => { - for (k, v) in table.iter() { - let key = format!("{}.{}", key, k); - let k = self.parse_template(&key, k)?; - if k == "_" || k == "mise" { - self.parse_env_mise(&key, v)?; - } else if let Some(v) = v.as_str() { - let v = self.parse_template(&key, v)?; - self.env.insert(k, v); - } else if let Some(v) = v.as_integer() { - self.env.insert(k, v.to_string()); - } else if let Some(v) = v.as_bool() { - if !v { - self.env_remove.push(k); - } - } else { - parse_error!(key, v, "string, num, or bool") - } + } + + fn parse_single_env(&mut self, key: &str, table: &dyn TableLike) -> Result<()> { + ensure!( + !table.contains_key("PATH"), + "use 'env.mise.path' instead of 'env.PATH'" + ); + + for (k, v) in table.iter() { + let key = format!("{}.{}", key, k); + let k = self.parse_template(&key, k)?; + if k == "_" || k == "mise" { + self.parse_env_mise(&key, v)?; + } else if let Some(v) = v.as_str() { + let v = self.parse_template(&key, v)?; + + if self.env.insert(k, v).is_some() { + bail!("duplicate key: {}", crate::ui::style::eyellow(key),) + } + } else if let Some(v) = v.as_integer() { + if self.env.insert(k, v.to_string()).is_some() { + bail!("duplicate key: {}", crate::ui::style::eyellow(key),) } + } else if let Some(v) = v.as_bool() { + if self.env_remove.contains(&k) { + bail!("duplicate key: {}", crate::ui::style::eyellow(key),) + }; + + if !v { + self.env_remove.push(k); + } + } else { + parse_error!(key, v, "string, num, or bool") } - _ => parse_error!(key, v, "table"), } + Ok(()) } @@ -795,6 +811,44 @@ mod tests { }); } + #[test] + fn test_env_array_valid() { + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); + cf.parse(&formatdoc! {r#" + [[env]] + foo="bar" + + [[env]] + bar="baz" + "#}) + .unwrap(); + + assert_snapshot!(cf.env()["foo"], @"bar"); + assert_snapshot!(cf.env()["bar"], @"baz"); + } + + #[test] + fn test_env_array_duplicate_key() { + let inputs = vec![(r#""bar""#, r#""baz""#), ("1", "2"), ("false", "true")]; + + for (a, b) in inputs { + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); + let err = cf + .parse(&formatdoc! {r#" + [[env]] + foo={a} + + [[env]] + foo={b} + "#}) + .unwrap_err(); + + allow_duplicates!( + assert_snapshot!(err.to_string(), @"duplicate key: env.foo"); + ) + } + } + #[test] fn test_path_dirs() { with_settings!({ From 651ec029c52fdcddb00f8f8c13dbbaa2f08426aa Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:19:47 -0600 Subject: [PATCH 1663/1891] cargo: allow cargo-binstall from mise itself (#1507) * cargo: allow cargo-binstall from mise itself Fixes #1506 I have not tested this myself but it should fix the problem. * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- src/env.rs | 4 ++++ src/file.rs | 12 +++++++++++- src/forge/cargo.rs | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/env.rs b/src/env.rs index 2e5c8959e..21676d7fd 100644 --- a/src/env.rs +++ b/src/env.rs @@ -123,6 +123,10 @@ pub static PATH: Lazy> = Lazy::new(|| match PRISTINE_ENV.get("PATH" Some(path) => split_paths(path).collect(), None => vec![], }); +pub static PATH_NON_PRISTINE: Lazy> = Lazy::new(|| match var("PATH") { + Ok(ref path) => split_paths(path).collect(), + Err(_) => vec![], +}); pub static DIRENV_DIFF: Lazy> = Lazy::new(|| var("DIRENV_DIFF").ok()); #[allow(unused)] pub static GITHUB_API_TOKEN: Lazy> = Lazy::new(|| var("GITHUB_API_TOKEN").ok()); diff --git a/src/file.rs b/src/file.rs index 184d24bd1..310c243a1 100644 --- a/src/file.rs +++ b/src/file.rs @@ -269,8 +269,18 @@ impl Iterator for FindUp { } } +/// returns the first executable in PATH +/// will not include mise bin paths or other paths added by mise pub fn which>(name: P) -> Option { - for path in &*env::PATH { + _which(name, &env::PATH) +} +/// returns the first executable in PATH +/// will include mise bin paths or other paths added by mise +pub fn which_non_pristine>(name: P) -> Option { + _which(name, &env::PATH_NON_PRISTINE) +} +fn _which>(name: P, paths: &Vec) -> Option { + for path in paths { let bin = path.join(name.as_ref()); if is_executable(&bin) { return Some(bin); diff --git a/src/forge/cargo.rs b/src/forge/cargo.rs index 7a3d2c0cd..aa7f03448 100644 --- a/src/forge/cargo.rs +++ b/src/forge/cargo.rs @@ -49,7 +49,7 @@ impl Forge for CargoForge { let settings = Settings::get(); settings.ensure_experimental()?; let cmd = match settings.cargo_binstall { - true if file::which("cargo-binstall").is_some() => { + true if file::which_non_pristine("cargo-binstall").is_some() => { CmdLineRunner::new("cargo-binstall").arg("-y") } _ => CmdLineRunner::new("cargo").arg("install"), From 9341810203d3e66dd6498400900ad6d6e1eb7c14 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Tue, 23 Jan 2024 15:44:54 -0500 Subject: [PATCH 1664/1891] feat(template): add join_path filter (#1508) --- src/tera.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/tera.rs b/src/tera.rs index 290a76b8c..d888632b0 100644 --- a/src/tera.rs +++ b/src/tera.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::path::Path; +use std::path::{Path, PathBuf}; use once_cell::sync::Lazy; use tera::{Context, Tera, Value}; @@ -65,6 +65,18 @@ pub fn get_tera(dir: &Path) -> Tera { _ => Err("hash input must be a string".into()), }, ); + tera.register_filter( + "join_path", + move |input: &Value, _args: &HashMap| match input { + Value::Array(arr) => arr + .iter() + .map(Value::as_str) + .collect::>() + .ok_or("join_path input must be an array of strings".into()) + .map(|p| Value::String(p.to_string_lossy().to_string())), + _ => Err("join_path input must be an array of strings".into()), + }, + ); tera.register_tester( "file_exists", move |input: Option<&Value>, _args: &[Value]| match input { From a756db4a34afee4d6ce0fcfea4bc016025d1d188 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:50:30 -0600 Subject: [PATCH 1665/1891] Delete lefthook.yml --- lefthook.yml | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 lefthook.yml diff --git a/lefthook.yml b/lefthook.yml deleted file mode 100644 index f4a1b4969..000000000 --- a/lefthook.yml +++ /dev/null @@ -1,22 +0,0 @@ -pre-commit: - parallel: true - commands: - cargo_fmt: - run: cargo fmt --all -- --check - glob: "src/**/*.rs" - clippy: - run: cargo clippy -- -Dwarnings - glob: "src/**/*.rs" - render: - run: just render-help render-completions render-mangen && git add README.md completions man - glob: "src/**/*.rs" - shellcheck: - run: shellcheck -x {all_files} && shfmt -d {all_files} - glob: "{scripts/*.sh,e2e/test_*,e2e/run_*}" - just_fmt: - run: just --unstable --fmt --check - glob: "justfile" - -skip_output: - - meta - - summary From 6845239648dbd08d097064a519250c32650a60ea Mon Sep 17 00:00:00 2001 From: Yuto Yoshino Date: Thu, 25 Jan 2024 00:11:46 +0900 Subject: [PATCH 1666/1891] feat: add other arm targets for cargo-binstall (#1510) --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7c97c824e..df3a1614a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -141,6 +141,10 @@ pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-macos-x64{ ar pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-arm64{ archive-suffix }" [package.metadata.binstall.overrides.x86_64-unknown-linux-gnu] pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-x64{ archive-suffix }" +[package.metadata.binstall.overrides.armv7-unknown-linux-gnueabihf] +pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-armv7{ archive-suffix }" +[package.metadata.binstall.overrides.armv6-unknown-linux-gnueabihf] +pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-armv6{ archive-suffix }" [package.metadata.cargo-machete] ignored = ["built", "openssl"] From 9ac14357c7f23c00c29da1ada37644609df85234 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Wed, 24 Jan 2024 13:18:02 -0500 Subject: [PATCH 1667/1891] fix(tasks): prevent implicit globbing of sources/outputs (#1509) --- schema/mise.json | 4 +-- src/cli/run.rs | 88 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/schema/mise.json b/schema/mise.json index aeb3eabb8..c475352c1 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -203,7 +203,7 @@ "description": "files that this task depends on", "type": "array", "items": { - "description": "glob pattern for files that this task depends on", + "description": "glob pattern or path to files that this task depends on", "type": "string" } }, @@ -211,7 +211,7 @@ "description": "files created by this task", "type": "array", "items": { - "description": "glob pattern for files created by this task", + "description": "glob pattern or path to files created by this task", "type": "string" } } diff --git a/src/cli/run.rs b/src/cli/run.rs index acd99ea92..572cb6c26 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -384,22 +384,23 @@ impl Run { }) } - fn get_last_modified(&self, root: &Path, globs: &[String]) -> Result> { - let last_mod = GlobWalkerBuilder::from_patterns(root, globs) - .follow_links(true) - .build()? - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().is_file()) - .map(|e| e.path().to_owned()) - .unique() - .map(|p| p.metadata().map_err(|err| eyre!(err))) - .collect::>>()? - .into_iter() - .map(|m| m.modified().map_err(|err| eyre!(err))) - .collect::>>()? - .into_iter() - .max(); - trace!("last_modified of {}: {last_mod:?}", globs.join(" ")); + fn get_last_modified( + &self, + root: &Path, + patterns_or_paths: &[String], + ) -> Result> { + let (patterns, paths): (Vec<&String>, Vec<&String>) = + patterns_or_paths.iter().partition(|p| is_glob_pattern(p)); + + let last_mod = std::cmp::max( + last_modified_glob_match(root, &patterns)?, + last_modified_path(root, &paths)?, + ); + + trace!( + "last_modified of {}: {last_mod:?}", + patterns_or_paths.iter().join(" ") + ); Ok(last_mod) } @@ -421,6 +422,61 @@ impl Run { } } +fn is_glob_pattern(path: &str) -> bool { + // This is the character set used for glob + // detection by globwalk + let glob_chars = ['*', '{', '}']; + + path.chars().any(|c| glob_chars.contains(&c)) +} + +fn last_modified_path( + root: impl AsRef, + paths: &[&String], +) -> Result> { + let files = paths + .iter() + .map(|p| { + let base = Path::new(p); + + if base.is_relative() { + base.to_path_buf() + } else { + Path::new(&root).join(base) + } + }) + .filter(|p| p.is_file()); + + last_modified_file(files) +} + +fn last_modified_glob_match( + root: impl AsRef, + patterns: &[&String], +) -> Result> { + let files = GlobWalkerBuilder::from_patterns(root, patterns) + .follow_links(true) + .build()? + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_file()) + .map(|e| e.path().to_owned()); + + last_modified_file(files) +} + +fn last_modified_file(files: impl IntoIterator) -> Result> { + Ok(files + .into_iter() + .unique() + .map(|p| p.metadata().map_err(|err| eyre!(err))) + .collect::>>()? + .into_iter() + .map(|m| m.modified().map_err(|err| eyre!(err))) + .collect::>>()? + .into_iter() + .max()) +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ mise run lint From 51f269a8d07cf1f34f0d237b17b493986aaa864d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:20:26 -0600 Subject: [PATCH 1668/1891] turn back on `cargo update` on release --- .mise.toml | 3 +++ scripts/pre-release-hook.sh | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.mise.toml b/.mise.toml index c41e35402..3aeaa41ee 100644 --- a/.mise.toml +++ b/.mise.toml @@ -88,3 +88,6 @@ run = "cargo insta test --accept --unreferenced delete" [tasks.release] run = "cargo release" + +[tasks.lint-fix] +run = "just lint-fix" diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index e922bc9c8..78757f743 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -3,13 +3,13 @@ set -euxo pipefail if [[ "${NO_UPDATE:-}" == "1" ]]; then echo "NO_UPDATE is set, skipping update" -# else -# cargo update && git add Cargo.lock +else + cargo update && git add Cargo.lock fi -just render-mangen render-help +mise run render-mangen render-help ./scripts/update-shorthand-repo.sh -just lint-fix +mise run lint-fix git add man src/default_shorthands.rs From 59498ea5a312507535d139957bac90fad2d96ebf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:21:56 -0600 Subject: [PATCH 1669/1891] fix release script --- scripts/pre-release-hook.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 78757f743..8bee2af91 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -7,7 +7,7 @@ else cargo update && git add Cargo.lock fi -mise run render-mangen render-help +mise run render-mangen ::: render-help ./scripts/update-shorthand-repo.sh mise run lint-fix From c6b1a22e9d31d8af68a8475a761fbe6fe01edcf0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:22:20 -0600 Subject: [PATCH 1670/1891] chore: Release mise version 2024.1.25 --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- src/default_shorthands.rs | 1 + 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92ed44a57..a000a6c85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -243,14 +243,14 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -1302,7 +1302,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.24" +version = "2024.1.25" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index df3a1614a..c1118d452 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.24" +version = "2024.1.25" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 76878c97f..42ca8e88e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.24 +mise 2024.1.25 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index c6b23b7ff..59c03f7e6 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.24"; + version = "2024.1.25"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 782100cc6..afadcd0d4 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.24" +.TH mise 1 "mise 2024.1.25" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.24 +v2024.1.25 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 47e3e9c49..0434c615a 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.24 +Version: 2024.1.25 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index df8f10ab9..e5913208f 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -598,6 +598,7 @@ pub static DEFAULT_SHORTHANDS: Lazy> = ("shellcheck", "https://github.com/luizm/asdf-shellcheck.git"), ("shellspec", "https://github.com/poikilotherm/asdf-shellspec.git"), ("shfmt", "https://github.com/luizm/asdf-shfmt.git"), + ("shorebird", "https://github.com/valian-ca/asdf-shorebird.git"), ("sinker", "https://github.com/elementalvoid/asdf-sinker.git"), ("skaffold", "https://github.com/nklmilojevic/asdf-skaffold.git"), ("skate", "https://github.com/chessmango/asdf-skate.git"), From 578ff24321c6254acadaed4b91498dc03a03911b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:56:41 -0600 Subject: [PATCH 1671/1891] bun|python: use target_feature to use correct precompiled runtimes (#1512) --- src/plugins/core/bun.rs | 6 +++++- src/plugins/core/python.rs | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 634008ee4..cae95dc38 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -137,7 +137,11 @@ fn os() -> &'static str { fn arch() -> &'static str { if cfg!(target_arch = "x86_64") || cfg!(target_arch = "amd64") { - "x64" + if cfg!(target_feature = "avx2") { + "x64" + } else { + "x64-baseline" + } } else if cfg!(target_arch = "aarch64") || cfg!(target_arch = "arm64") { "aarch64" } else { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 31a07c518..9c08ed6dd 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -360,13 +360,21 @@ fn python_os(settings: &Settings) -> String { } } -fn python_arch(settings: &Settings) -> String { +fn python_arch(settings: &Settings) -> &str { if let Some(arch) = &settings.python_precompiled_arch { - return arch.clone(); + return arch.as_str(); } if cfg!(target_arch = "x86_64") { - "x86_64_v3".into() + if cfg!(target_feature = "avx512f") { + "x86_64_v4" + } else if cfg!(target_feature = "avx2") { + "x86_64_v3" + } else if cfg!(target_feature = "sse4.1") { + "x86_64_v2" + } else { + "x86_64_v1" + } } else { - built_info::CFG_TARGET_ARCH.to_string() + built_info::CFG_TARGET_ARCH } } From 032e325f9f44b80e920c9e4698c17233c7011ca7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:25:52 -0600 Subject: [PATCH 1672/1891] config: do not follow symbolic links for trusted paths (#1513) * config: do not follow symbolic links for trusted paths Fixes #1501 * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- src/config/config_file/mod.rs | 53 ++++++++++++++++------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index b3b4c8c08..8fb831ffa 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -216,54 +216,49 @@ pub fn trust_check(path: &Path) -> Result<()> { pub fn is_trusted(path: &Path) -> bool { static IS_TRUSTED: Lazy>> = Lazy::new(|| Mutex::new(HashSet::new())); - if let Ok(path) = path.canonicalize() { - let mut cached = IS_TRUSTED.lock().unwrap(); - if cached.contains(&path) { + let mut cached = IS_TRUSTED.lock().unwrap(); + if cached.contains(path) { + return true; + } + let settings = Settings::get(); + for p in settings.trusted_config_paths() { + if path.starts_with(p) { + cached.insert(path.to_path_buf()); return true; } - let settings = Settings::get(); - for p in settings.trusted_config_paths() { - if path.starts_with(p) { - cached.insert(path); - return true; - } - } - if !trust_path(&path).exists() { + } + if !trust_path(path).exists() { + return false; + } + if settings.paranoid { + let trusted = trust_file_hash(path).unwrap_or_else(|e| { + warn!("trust_file_hash: {e}"); + false + }); + if !trusted { return false; } - if settings.paranoid { - let trusted = trust_file_hash(&path).unwrap_or_else(|e| { - warn!("trust_file_hash: {e}"); - false - }); - if !trusted { - return false; - } - } - cached.insert(path); - return true; } - false + cached.insert(path.to_path_buf()); + true } pub fn trust(path: &Path) -> Result<()> { - let path = path.canonicalize()?; - let hashed_path = trust_path(&path); + let hashed_path = trust_path(path); if !hashed_path.exists() { file::create_dir_all(hashed_path.parent().unwrap())?; - file::make_symlink(&path, &hashed_path)?; + file::make_symlink(path, &hashed_path)?; } let trust_hash_path = hashed_path.with_extension("hash"); if !trust_hash_path.exists() { - let hash = file_hash_sha256(&path)?; + let hash = file_hash_sha256(path)?; file::write(&trust_hash_path, hash)?; } Ok(()) } pub fn untrust(path: &Path) -> Result<()> { - let path = path.canonicalize()?; - let hashed_path = trust_path(&path); + let hashed_path = trust_path(path); if hashed_path.exists() { file::remove_file(hashed_path)?; } From a5573ccd5a78f5fed1f449f5c4135ed168c03d51 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 15:28:50 -0600 Subject: [PATCH 1673/1891] refactor: env parsing (#1515) This lazy-loads the env vars from config files. This is a prereq for #1262 and other env var changes. It will make it easier to perform the template logic in order across the env vars rather than when the file is parsed --- src/cli/direnv/envrc.rs | 2 +- src/cli/direnv/exec.rs | 2 +- src/cli/env.rs | 4 +-- src/cli/exec.rs | 2 +- src/cli/hook_env.rs | 9 ++++--- src/cli/run.rs | 2 +- src/cli/set.rs | 8 +++--- src/cli/watch.rs | 2 +- src/config/mod.rs | 46 ++++++++++++++++++---------------- src/forge/cargo.rs | 2 +- src/forge/go.rs | 2 +- src/forge/npm.rs | 2 +- src/plugins/core/node.rs | 6 ++--- src/plugins/core/python.rs | 8 +++--- src/plugins/core/ruby.rs | 8 +++--- src/plugins/external_plugin.rs | 14 +++++------ src/toolset/mod.rs | 12 ++++----- 17 files changed, 68 insertions(+), 63 deletions(-) diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 05682625d..f433bb713 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -33,7 +33,7 @@ impl Envrc { for cf in config.config_files.keys() { writeln!(file, "watch_file {}", cf.to_string_lossy())?; } - for (k, v) in ts.env(config) { + for (k, v) in ts.env(config)? { if k == "PATH" { writeln!(file, "PATH_add {}", v)?; } else { diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index bd1c47ff5..97fbd5b64 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -24,7 +24,7 @@ impl DirenvExec { let mut cmd = env_cmd(); - for (k, v) in ts.env_with_path(config) { + for (k, v) in ts.env_with_path(config)? { cmd = cmd.env(k, v); } diff --git a/src/cli/env.rs b/src/cli/env.rs index 71294d8ab..79762cb3d 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -40,7 +40,7 @@ impl Env { } fn output_json(&self, config: &Config, ts: Toolset) -> Result<()> { - let env = ts.env_with_path(config); + let env = ts.env_with_path(config)?; miseprintln!("{}", serde_json::to_string_pretty(&env)?); Ok(()) } @@ -48,7 +48,7 @@ impl Env { fn output_shell(&self, config: &Config, ts: Toolset) -> Result<()> { let default_shell = get_shell(Some(ShellType::Bash)).unwrap(); let shell = get_shell(self.shell).unwrap_or(default_shell); - for (k, v) in ts.env_with_path(config) { + for (k, v) in ts.env_with_path(config)? { let k = k.to_string(); let v = v.to_string(); miseprint!("{}", shell.set_env(&k, &v)); diff --git a/src/cli/exec.rs b/src/cli/exec.rs index ac36f78b1..1e3cdef1d 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -62,7 +62,7 @@ impl Exec { ts.notify_if_versions_missing(); let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); - let env = ts.env_with_path(&config); + let env = ts.env_with_path(&config)?; self.exec(program, args, env) } diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 1653691b2..db076660b 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -46,7 +46,7 @@ impl HookEnv { let ts = ToolsetBuilder::new().build(&config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); miseprint!("{}", hook_env::clear_old_env(&*shell)); - let mut env = ts.env(&config); + let mut env = ts.env(&config)?; let env_path = env.remove("PATH"); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); @@ -66,14 +66,14 @@ impl HookEnv { let output = hook_env::build_env_commands(&*shell, &patches); miseprint!("{output}"); if self.status { - self.display_status(&config, &ts); + self.display_status(&config, &ts)?; ts.notify_if_versions_missing(); } Ok(()) } - fn display_status(&self, config: &Config, ts: &Toolset) { + fn display_status(&self, config: &Config, ts: &Toolset) -> Result<()> { let installed_versions = ts .list_current_installed_versions() .into_iter() @@ -84,11 +84,12 @@ impl HookEnv { let status = installed_versions.into_iter().rev().join(" "); info!("{}", truncate_str(&status, TERM_WIDTH.max(60) - 5, "…")); } - let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env.clone()).to_patches(); + let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env()?.clone()).to_patches(); if !env_diff.is_empty() { let env_diff = env_diff.into_iter().map(patch_to_status).join(" "); info!("{}", truncate_str(&env_diff, TERM_WIDTH.max(60) - 5, "…")); } + Ok(()) } /// modifies the PATH and optionally DIRENV_DIFF env var if it exists diff --git a/src/cli/run.rs b/src/cli/run.rs index 572cb6c26..8370e2acf 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -146,7 +146,7 @@ impl Run { ts.install_arg_versions(config, &InstallOptions::new())?; ts.notify_if_versions_missing(); - let mut env = ts.env_with_path(config); + let mut env = ts.env_with_path(config)?; if let Some(root) = &config.project_root { env.insert("MISE_PROJECT_ROOT".into(), root.display().to_string()); } diff --git a/src/cli/set.rs b/src/cli/set.rs index 26a247f5e..65667a2ec 100644 --- a/src/cli/set.rs +++ b/src/cli/set.rs @@ -45,12 +45,12 @@ impl Set { let config = Config::try_get()?; if self.remove.is_none() && self.env_vars.is_none() { let rows = config - .env + .env_with_sources()? .iter() - .map(|(key, value)| Row { + .map(|(key, (value, source))| Row { key: key.clone(), value: value.clone(), - source: display_path(&config.env_sources.get(key).unwrap().clone()), + source: display_path(source), }) .collect::>(); let mut table = tabled::Table::new(rows); @@ -75,7 +75,7 @@ impl Set { if let Some(env_vars) = self.env_vars { if env_vars.len() == 1 && env_vars[0].value.is_none() { let key = &env_vars[0].key; - match config.env.get(key) { + match config.env()?.get(key) { Some(value) => miseprintln!("{value}"), None => bail!("Environment variable {key} not found"), } diff --git a/src/cli/watch.rs b/src/cli/watch.rs index 4266c2c80..91d0bc87f 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -111,7 +111,7 @@ impl Watch { } info!("$ watchexec {}", args.join(" ")); let mut cmd = cmd::cmd("watchexec", &args); - for (k, v) in ts.env_with_path(&config) { + for (k, v) in ts.env_with_path(&config)? { cmd = cmd.env(k, v); } if let Some(root) = &config.project_root { diff --git a/src/config/mod.rs b/src/config/mod.rs index 4520b5240..c24c10aeb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -31,15 +31,15 @@ mod tracking; type AliasMap = BTreeMap>; type ConfigMap = IndexMap>; +type EnvWithSources = IndexMap; #[derive(Default)] pub struct Config { pub aliases: AliasMap, pub config_files: ConfigMap, - pub env: BTreeMap, - pub env_sources: HashMap, pub path_dirs: Vec, pub project_root: Option, + env: OnceCell, all_aliases: OnceCell, repo_urls: HashMap, shorthands: OnceCell>, @@ -74,12 +74,10 @@ impl Config { let config_paths = load_config_paths(&config_filenames); let config_files = load_all_config_files(&config_paths, &legacy_files)?; - let (env, env_sources) = load_env(&settings, &config_files); let repo_urls = config_files.values().flat_map(|cf| cf.plugins()).collect(); let config = Self { - env, - env_sources, + env: OnceCell::new(), path_dirs: load_path_dirs(&config_files), aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), @@ -95,6 +93,16 @@ impl Config { Ok(config) } + pub fn env(&self) -> Result> { + Ok(self + .env_with_sources()? + .iter() + .map(|(k, (v, _))| (k.clone(), v.clone())) + .collect()) + } + pub fn env_with_sources(&self) -> Result<&EnvWithSources> { + self.env.get_or_try_init(|| load_env(&self.config_files)) + } pub fn get_shorthands(&self) -> &Shorthands { self.shorthands .get_or_init(|| get_shorthands(&Settings::get())) @@ -435,22 +443,18 @@ fn parse_config_file( } } -fn load_env( - settings: &Settings, - config_files: &ConfigMap, -) -> (BTreeMap, HashMap) { - let mut env = BTreeMap::new(); - let mut env_sources = HashMap::new(); +fn load_env(config_files: &ConfigMap) -> Result { + let mut env = IndexMap::new(); for (source, cf) in config_files.iter().rev() { - env.extend(cf.env()); - for k in cf.env().keys() { - env_sources.insert(k.clone(), source.clone()); + for (k, v) in cf.env() { + env.insert(k, (v, source.clone())); } for k in cf.env_remove() { // remove values set to "false" env.remove(&k); } } + let settings = Settings::get(); if let Some(env_file) = &settings.env_file { match dotenvy::from_filename_iter(env_file) { Ok(iter) => { @@ -459,16 +463,14 @@ fn load_env( warn!("env_file: {err}"); Default::default() }); - env.insert(k.clone(), v); - env_sources.insert(k, env_file.clone()); + env.insert(k, (v, env_file.clone())); } } Err(err) => trace!("env_file: {err}"), } } - (env, env_sources) + Ok(env) } - fn load_path_dirs(config_files: &ConfigMap) -> Vec { let mut path_dirs = vec![]; for cf in config_files.values().rev() { @@ -506,9 +508,11 @@ impl Debug for Config { &tasks.values().map(|t| t.to_string()).collect_vec(), ); } - if !self.env.is_empty() { - s.field("Env", &self.env); - // s.field("Env Sources", &self.env_sources); + if let Ok(env) = self.env() { + if !env.is_empty() { + s.field("Env", &env); + // s.field("Env Sources", &self.env_sources); + } } if !self.path_dirs.is_empty() { s.field("Path Dirs", &self.path_dirs); diff --git a/src/forge/cargo.rs b/src/forge/cargo.rs index aa7f03448..30f97901a 100644 --- a/src/forge/cargo.rs +++ b/src/forge/cargo.rs @@ -59,7 +59,7 @@ impl Forge for CargoForge { .arg("--root") .arg(ctx.tv.install_path()) .with_pr(ctx.pr.as_ref()) - .envs(&config.env) + .envs(config.env()?) .prepend_path(ctx.ts.list_paths())? .execute()?; diff --git a/src/forge/go.rs b/src/forge/go.rs index 6f7af2522..f412c9021 100644 --- a/src/forge/go.rs +++ b/src/forge/go.rs @@ -42,7 +42,7 @@ impl Forge for GoForge { .arg("install") .arg(&format!("{}@{}", self.name(), ctx.tv.version)) .with_pr(ctx.pr.as_ref()) - .envs(&config.env) + .envs(config.env()?) .env("GOPATH", ctx.tv.cache_path()) .env("GOBIN", ctx.tv.install_path().join("bin")) .execute()?; diff --git a/src/forge/npm.rs b/src/forge/npm.rs index 03611caa8..e2e21fcc9 100644 --- a/src/forge/npm.rs +++ b/src/forge/npm.rs @@ -45,7 +45,7 @@ impl Forge for NPMForge { .arg("--prefix") .arg(ctx.tv.install_path()) .with_pr(ctx.pr.as_ref()) - .envs(&config.env) + .envs(config.env()?) .prepend_path(ctx.ts.list_paths())? .execute()?; diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index ea4b1d84e..1567242eb 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -183,7 +183,7 @@ impl NodePlugin { .arg("install") .arg("--global") .arg(package) - .envs(&config.env) + .envs(config.env()?) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .execute()?; } @@ -213,7 +213,7 @@ impl NodePlugin { CmdLineRunner::new(self.node_path(tv)) .with_pr(pr) .arg("-v") - .envs(&config.env) + .envs(config.env()?) .execute() } @@ -223,7 +223,7 @@ impl NodePlugin { .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .with_pr(pr) .arg("-v") - .envs(&config.env) + .envs(config.env()?) .execute() } diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 9c08ed6dd..9562e69c4 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -169,7 +169,7 @@ impl PythonPlugin { .with_pr(ctx.pr.as_ref()) .arg(ctx.tv.version.as_str()) .arg(&ctx.tv.install_path()) - .envs(&config.env); + .envs(config.env()?); if settings.verbose { cmd = cmd.arg("--verbose"); } @@ -213,7 +213,7 @@ impl PythonPlugin { .arg("--upgrade") .arg("-r") .arg(packages_file) - .envs(&config.env) + .envs(config.env()?) .execute() } @@ -245,7 +245,7 @@ impl PythonPlugin { .arg("-m") .arg("venv") .arg(&virtualenv) - .envs(&config.env); + .envs(config.env()?); if let Some(pr) = pr { cmd = cmd.with_pr(pr); } @@ -288,7 +288,7 @@ impl PythonPlugin { pr.set_message("python --version".into()); CmdLineRunner::new(self.python_path(tv)) .arg("--version") - .envs(&config.env) + .envs(config.env()?) .execute() } } diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index fa63bb6c0..b6b0f0778 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -191,7 +191,7 @@ impl RubyPlugin { let mut cmd = CmdLineRunner::new(gem) .with_pr(pr) .arg("install") - .envs(&config.env); + .envs(config.env()?); match package.split_once(' ') { Some((name, "--pre")) => cmd = cmd.arg(name).arg("--pre"), Some((name, version)) => cmd = cmd.arg(name).arg("--version").arg(version), @@ -208,7 +208,7 @@ impl RubyPlugin { CmdLineRunner::new(self.ruby_path(tv)) .with_pr(pr) .arg("-v") - .envs(&config.env) + .envs(config.env()?) .execute() } @@ -217,7 +217,7 @@ impl RubyPlugin { CmdLineRunner::new(self.gem_path(tv)) .with_pr(pr) .arg("-v") - .envs(&config.env) + .envs(config.env()?) .env("PATH", CorePlugin::path_env_with_tv_path(tv)?) .execute() } @@ -260,7 +260,7 @@ impl RubyPlugin { .args(self.install_args_ruby_build(tv)?) .stdin_string(self.fetch_patches()?) }; - Ok(cmd.with_pr(pr).envs(&config.env)) + Ok(cmd.with_pr(pr).envs(config.env()?)) } fn install_args_ruby_build(&self, tv: &ToolVersion) -> Result> { let mut args = env::MISE_RUBY_BUILD_OPTS.clone()?; diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index ee479dae1..b7f294e0e 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -285,7 +285,7 @@ impl ExternalPlugin { let bin_paths = if matches!(tv.request, ToolVersionRequest::System(_)) { Vec::new() } else if list_bin_paths.exists() { - let sm = self.script_man_for_tv(tv); + let sm = self.script_man_for_tv(tv)?; // TODO: find a way to enable this without deadlocking // for (t, tv) in ts.list_current_installed_versions(config) { // if t.name == self.name { @@ -303,7 +303,7 @@ impl ExternalPlugin { Ok(bin_paths) } fn fetch_exec_env(&self, ts: &Toolset, tv: &ToolVersion) -> Result> { - let mut sm = self.script_man_for_tv(tv); + let mut sm = self.script_man_for_tv(tv)?; for p in ts.list_paths() { sm.prepend_path(p); } @@ -321,7 +321,7 @@ impl ExternalPlugin { Ok(env) } - fn script_man_for_tv(&self, tv: &ToolVersion) -> ScriptManager { + fn script_man_for_tv(&self, tv: &ToolVersion) -> Result { let config = Config::get(); let mut sm = self.script_man.clone(); for (key, value) in &tv.opts { @@ -349,7 +349,7 @@ impl ExternalPlugin { _ => &tv.version, }; // add env vars from .mise.toml files - for (key, value) in &config.env { + for (key, value) in config.env()? { sm = sm.with_env(key, value.clone()); } let install = tv.install_path().to_string_lossy().to_string(); @@ -367,7 +367,7 @@ impl ExternalPlugin { .with_env("MISE_INSTALL_PATH", install) .with_env("MISE_INSTALL_TYPE", install_type) .with_env("MISE_INSTALL_VERSION", install_version); - sm + Ok(sm) } fn exec_hook(&self, pr: &dyn SingleReport, hook: &str) -> Result<()> { @@ -692,7 +692,7 @@ impl Forge for ExternalPlugin { } fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { - let mut sm = self.script_man_for_tv(&ctx.tv); + let mut sm = self.script_man_for_tv(&ctx.tv)?; for p in ctx.ts.list_paths() { sm.prepend_path(p); @@ -713,7 +713,7 @@ impl Forge for ExternalPlugin { fn uninstall_version_impl(&self, pr: &dyn SingleReport, tv: &ToolVersion) -> Result<()> { if self.plugin_path.join("bin/uninstall").exists() { - self.script_man_for_tv(tv) + self.script_man_for_tv(tv)? .run_by_line(&Script::Uninstall, pr)?; } Ok(()) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 760990230..b308411de 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -274,12 +274,12 @@ impl Toolset { }) .collect() } - pub fn env_with_path(&self, config: &Config) -> BTreeMap { + pub fn env_with_path(&self, config: &Config) -> Result> { let mut path_env = PathEnv::from_iter(env::PATH.clone()); for p in config.path_dirs.clone() { path_env.add(p); } - let mut env = self.env(config); + let mut env = self.env(config)?; if let Some(path) = env.get("PATH") { path_env.add(PathBuf::from(path)); } @@ -287,9 +287,9 @@ impl Toolset { path_env.add(p); } env.insert("PATH".to_string(), path_env.to_string()); - env + Ok(env) } - pub fn env(&self, config: &Config) -> BTreeMap { + pub fn env(&self, config: &Config) -> Result> { let entries = self .list_current_installed_versions() .into_par_iter() @@ -317,8 +317,8 @@ impl Toolset { if !add_paths.is_empty() { entries.insert("PATH".to_string(), add_paths); } - entries.extend(config.env.clone()); - entries + entries.extend(config.env()?.clone()); + Ok(entries) } pub fn list_paths(&self) -> Vec { self.list_current_installed_versions() From 7ce6d3fe52cf5bc3df66748e16703a0a0e5bcbc5 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 15:49:08 -0600 Subject: [PATCH 1674/1891] config: refactor min_version logic (#1516) starting to move logic out of parsing --- .idea/mise.iml | 1 + Cargo.lock | 1 + Cargo.toml | 2 +- src/cli/doctor.rs | 6 +- src/cli/render_mangen.rs | 2 +- src/cli/version.rs | 11 ++-- src/config/config_file/mise_toml.rs | 57 ++++++++++++------- src/config/config_file/mod.rs | 4 ++ ..._config_file__mise_toml__tests__env-3.snap | 1 + ..._config_file__mise_toml__tests__env-5.snap | 1 + src/config/mod.rs | 19 +++++++ src/http.rs | 3 +- 12 files changed, 74 insertions(+), 34 deletions(-) diff --git a/.idea/mise.iml b/.idea/mise.iml index f84d90057..29f866ac5 100644 --- a/.idea/mise.iml +++ b/.idea/mise.iml @@ -27,6 +27,7 @@ + diff --git a/Cargo.lock b/Cargo.lock index a000a6c85..141f08670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2771,6 +2771,7 @@ checksum = "f37ff4899935ba747849dd9eeb27c0bdd0da0210236704b7e4681a6c7bd6f9c6" dependencies = [ "itertools", "nom", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c1118d452..76eb53d02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,7 +99,7 @@ thiserror = "1.0.56" toml = { version = "0.8.8", features = ["parse"] } toml_edit = { version = "0.21.0", features = ["parse"] } url = "2.5.0" -versions = "6.1.0" +versions = { version = "6.1.0" , features=["serde"]} which = "6.0.0" zip = { version = "0.6.6", default-features = false, features = ["deflate"] } diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 9a5487f02..2dfe399bb 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -6,6 +6,7 @@ use eyre::Result; use indenter::indented; use crate::build_time::built_info; +use crate::cli::version; use crate::cli::version::VERSION; use crate::config::{Config, Settings}; use crate::file::display_path; @@ -76,9 +77,8 @@ impl Doctor { if let Some(latest) = cli::version::check_for_new_version(duration::HOURLY) { checks.push(format!( - "new mise version {} available, currently on {}", - latest, - env!("CARGO_PKG_VERSION") + "new mise version {latest} available, currently on {}", + *version::V )); } diff --git a/src/cli/render_mangen.rs b/src/cli/render_mangen.rs index e810d46af..cc393bc64 100644 --- a/src/cli/render_mangen.rs +++ b/src/cli/render_mangen.rs @@ -14,7 +14,7 @@ pub struct RenderMangen {} impl RenderMangen { pub fn run(self) -> Result<()> { let cli = Cli::command() - .version(&*version::RAW_VERSION) + .version(version::V.to_string()) .disable_colored_help(true); let man = clap_mangen::Man::new(cli); diff --git a/src/cli/version.rs b/src/cli/version.rs index e891d07ed..d4865931f 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -27,19 +27,19 @@ pub static ARCH: Lazy = Lazy::new(|| { }); pub static VERSION: Lazy = Lazy::new(|| { - let mut version = RAW_VERSION.clone(); + let mut v = V.to_string(); if cfg!(debug_assertions) { - version.push_str("-DEBUG"); + v.push_str("-DEBUG"); }; let build_time = BUILD_TIME.format("%Y-%m-%d"); let extra = match &built_info::GIT_COMMIT_HASH_SHORT { Some(sha) => format!("({} {})", sha, build_time), _ => format!("({})", build_time), }; - format!("{} {}-{} {}", version, *OS, *ARCH, extra) + format!("{v} {os}-{arch} {extra}", os = *OS, arch = *ARCH) }); -pub static RAW_VERSION: Lazy = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string()); +pub static V: Lazy = Lazy::new(|| Versioning::new(env!("CARGO_PKG_VERSION")).unwrap()); impl Version { pub fn run(self) -> Result<()> { @@ -79,8 +79,7 @@ fn show_latest() { pub fn check_for_new_version(cache_duration: Duration) -> Option { if let Some(latest) = get_latest_version(cache_duration).and_then(|v| Versioning::new(&v)) { - let current = Versioning::new(env!("CARGO_PKG_VERSION")).unwrap(); - if current < latest { + if *V < latest { return Some(latest.to_string()); } } diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index e8ca42efb..89bb07403 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::Mutex; use eyre::{Result, WrapErr}; +use serde::Deserializer; use serde_derive::Deserialize; use tera::Context as TeraContext; use toml_edit::{table, value, Array, Document, Item, TableLike, Value}; @@ -24,6 +25,8 @@ use crate::{dirs, file, parse_error}; #[derive(Default, Deserialize)] pub struct MiseToml { + #[serde(default, deserialize_with = "deserialize_version")] + min_version: Option, #[serde(skip)] context: TeraContext, #[serde(skip)] @@ -76,19 +79,24 @@ impl MiseToml { } fn parse(&mut self, s: &str) -> Result<()> { + let cfg: MiseToml = toml::from_str(s)?; + self.min_version = cfg.min_version; + + // TODO: right now some things are parsed with serde (above) and some not (below) everything + // should be moved to serde eventually + let doc: Document = s.parse()?; // .suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { - "min_version" => self.parse_min_version(v)?, "dotenv" => self.parse_env_file(k, v)?, "env_file" => self.parse_env_file(k, v)?, "env_path" => self.path_dirs = self.parse_path_env(k, v)?, "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, - "settings" => {} "plugins" => self.plugins = self.parse_plugins(k, v)?, "tasks" => self.tasks = self.parse_tasks(k, v)?, + "min_version" | "settings" => {} _ => bail!("unknown key: {}", style::ered(k)), } } @@ -96,26 +104,6 @@ impl MiseToml { Ok(()) } - fn parse_min_version(&self, v: &Item) -> Result<()> { - match v.as_str() { - Some(s) => { - if let (Some(min), Some(cur)) = ( - Versioning::new(s), - Versioning::new(env!("CARGO_PKG_VERSION")), - ) { - ensure!( - cur >= min, - "mise version {} is required, but you are using {}", - style::eyellow(min), - style::eyellow(cur) - ); - } - Ok(()) - } - _ => parse_error!("min_version", v, "string"), - } - } - fn parse_env_file(&mut self, k: &str, v: &Item) -> Result<()> { trust_check(&self.path)?; if let Some(filename) = v.as_str() { @@ -619,6 +607,10 @@ impl ConfigFile for MiseToml { self.path.as_path() } + fn min_version(&self) -> &Option { + &self.min_version + } + fn project_root(&self) -> Option<&Path> { let fp = self.get_path(); let filename = fp.file_name().unwrap_or_default().to_string_lossy(); @@ -728,6 +720,9 @@ impl Debug for MiseToml { let title = format!("MiseToml({}): {tools}", &display_path(&self.path)); let mut d = f.debug_struct(&title); // d.field("is_trusted", &self.is_trusted); + if let Some(min_version) = &self.min_version { + d.field("min_version", &min_version.to_string()); + } if !self.env_files.is_empty() { d.field("env_files", &self.env_files); } @@ -753,6 +748,7 @@ impl Debug for MiseToml { impl Clone for MiseToml { fn clone(&self) -> Self { Self { + min_version: self.min_version.clone(), context: self.context.clone(), path: self.path.clone(), toolset: self.toolset.clone(), @@ -769,6 +765,22 @@ impl Clone for MiseToml { } } +fn deserialize_version<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let s: Option = serde::Deserialize::deserialize(deserializer)?; + + match s { + Some(s) => Ok(Some( + Versioning::new(&s) + .ok_or(versions::Error::IllegalVersioning(s)) + .map_err(serde::de::Error::custom)?, + )), + None => Ok(None), + } +} + #[cfg(test)] mod tests { use crate::dirs; @@ -792,6 +804,7 @@ mod tests { fn test_env() { let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); cf.parse(&formatdoc! {r#" + min_version = "2024.1.1" [env] foo="bar" "#}) diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 8fb831ffa..8b4f80bba 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -7,6 +7,7 @@ use std::sync::Mutex; use eyre::Result; use once_cell::sync::Lazy; +use versions::Versioning; use tool_versions::ToolVersions; @@ -36,6 +37,9 @@ pub enum ConfigFileType { pub trait ConfigFile: Debug + Send + Sync { fn get_type(&self) -> ConfigFileType; fn get_path(&self) -> &Path; + fn min_version(&self) -> &Option { + &None + } /// gets the project directory for the config /// if it's a global/system config, returns None /// files like ~/src/foo/.mise/config.toml will return ~/src/foo diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap index bdd6c20fd..3a69d8ca0 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap @@ -2,6 +2,7 @@ source: src/config/config_file/mise_toml.rs expression: cf.dump() --- +min_version = "2024.1.1" [env] foo="bar" diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap index 239b473b9..acaad8435 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap @@ -3,6 +3,7 @@ source: src/config/config_file/mise_toml.rs expression: cf --- MiseToml(/tmp/.mise.toml): { + min_version: "2024.1.1", env: { "foo": "bar", }, diff --git a/src/config/mod.rs b/src/config/mod.rs index c24c10aeb..64ad90432 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -14,6 +14,7 @@ use rayon::prelude::*; pub use settings::Settings; use crate::cli::args::ForgeArg; +use crate::cli::version; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::mise_toml::MiseToml; use crate::config::config_file::ConfigFile; @@ -89,6 +90,8 @@ impl Config { repo_urls, }; + config.validate()?; + debug!("{config:#?}"); Ok(config) @@ -264,6 +267,21 @@ impl Config { } } + fn validate(&self) -> Result<()> { + for cf in self.config_files.values() { + if let Some(min) = cf.min_version() { + let cur = &*version::V; + ensure!( + cur >= min, + "mise version {} is required, but you are using {}", + style::eyellow(min), + style::eyellow(cur) + ); + } + } + Ok(()) + } + #[cfg(test)] pub fn reset() { Settings::reset(None); @@ -471,6 +489,7 @@ fn load_env(config_files: &ConfigMap) -> Result { } Ok(env) } + fn load_path_dirs(config_files: &ConfigMap) -> Vec { let mut path_dirs = vec![]; for cf in config_files.values().rev() { diff --git a/src/http.rs b/src/http.rs index 0bb93503e..a854641f9 100644 --- a/src/http.rs +++ b/src/http.rs @@ -7,6 +7,7 @@ use once_cell::sync::Lazy; use reqwest::blocking::{ClientBuilder, Response}; use reqwest::IntoUrl; +use crate::cli::version; use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::display_path; use crate::{env, file}; @@ -37,7 +38,7 @@ impl Client { fn _new() -> ClientBuilder { ClientBuilder::new() - .user_agent(format!("mise/{}", env!("CARGO_PKG_VERSION"))) + .user_agent(format!("mise/{}", &*version::VERSION)) .gzip(true) } From 278878e69bb4a85e8219fb74aab51e55be651f0a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:26:34 -0600 Subject: [PATCH 1675/1891] env: sort env vars coming back from exec-env (#1518) * config: refactor min_version logic starting to move logic out of parsing * env: sort env vars coming back from exec-env Better than randomized with HashMap --- src/forge/mod.rs | 8 +++++--- src/plugins/core/deno.rs | 6 +++--- src/plugins/core/go.rs | 6 +++--- src/plugins/core/java.rs | 4 ++-- src/plugins/core/python.rs | 6 +++--- src/plugins/core/ruby.rs | 6 +++--- src/plugins/external_plugin.rs | 11 ++++------- src/plugins/external_plugin_cache.rs | 8 ++++---- 8 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/forge/mod.rs b/src/forge/mod.rs index 891986eb2..4459869f5 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::fmt::{Debug, Display}; use std::fs::File; use std::hash::Hash; @@ -310,14 +310,16 @@ pub trait Forge: Debug + Send + Sync { _ => Ok(vec![tv.install_short_path().join("bin")]), } } + fn exec_env( &self, _config: &Config, _ts: &Toolset, _tv: &ToolVersion, - ) -> eyre::Result> { - Ok(HashMap::new()) + ) -> eyre::Result> { + Ok(BTreeMap::new()) } + fn which(&self, tv: &ToolVersion, bin_name: &str) -> eyre::Result> { let bin_paths = self.list_bin_paths(tv)?; for bin_path in bin_paths { diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 482a06b29..79648b533 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use eyre::Result; @@ -136,8 +136,8 @@ impl Forge for DenoPlugin { _config: &Config, _ts: &Toolset, tv: &ToolVersion, - ) -> Result> { - let map = HashMap::from([( + ) -> eyre::Result> { + let map = BTreeMap::from([( "DENO_INSTALL_ROOT".into(), tv.install_path().join(".deno").to_string_lossy().into(), )]); diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index d174287b7..63291bb26 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::path::{Path, PathBuf}; use eyre::Result; @@ -179,8 +179,8 @@ impl Forge for GoPlugin { _config: &Config, _ts: &Toolset, tv: &ToolVersion, - ) -> Result> { - let mut map = HashMap::new(); + ) -> eyre::Result> { + let mut map = BTreeMap::new(); match (*env::MISE_GO_SET_GOROOT, env::PRISTINE_ENV.get("GOROOT")) { (Some(false), _) | (None, Some(_)) => {} (Some(true), _) | (None, None) => { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 0ac2070cb..25adafc21 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -331,8 +331,8 @@ impl Forge for JavaPlugin { _config: &Config, _ts: &Toolset, tv: &ToolVersion, - ) -> Result> { - let map = HashMap::from([( + ) -> eyre::Result> { + let map = BTreeMap::from([( "JAVA_HOME".into(), tv.install_path().to_string_lossy().into(), )]); diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 9562e69c4..4aa507ac3 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use eyre::Result; @@ -332,8 +332,8 @@ impl Forge for PythonPlugin { config: &Config, _ts: &Toolset, tv: &ToolVersion, - ) -> Result> { - let mut hm = HashMap::new(); + ) -> eyre::Result> { + let mut hm = BTreeMap::new(); match self.get_virtualenv(config, tv, None) { Err(e) => warn!("failed to get virtualenv: {e}"), Ok(Some(virtualenv)) => { diff --git a/src/plugins/core/ruby.rs b/src/plugins/core/ruby.rs index b6b0f0778..7d11815ce 100644 --- a/src/plugins/core/ruby.rs +++ b/src/plugins/core/ruby.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use std::env::temp_dir; use std::path::{Path, PathBuf}; @@ -376,11 +376,11 @@ impl Forge for RubyPlugin { _config: &Config, _ts: &Toolset, tv: &ToolVersion, - ) -> Result> { + ) -> eyre::Result> { // TODO: is there a way to avoid needing to set RUBYLIB? // is there a directory I can put rubygems_plugin.rb in that will be automatically loaded? let rubygems_plugin_path = self.rubygems_plugins_path(tv); - let mut map = HashMap::new(); + let mut map = BTreeMap::new(); if rubygems_plugin_path.exists() { let rubygems_plugin_path = rubygems_plugin_path.to_string_lossy().to_string(); let rubylib = match env::PRISTINE_ENV.get("RUBYLIB") { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index b7f294e0e..5cfaf3032 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -11,7 +11,6 @@ use clap::Command; use color_eyre::eyre::{eyre, Result, WrapErr}; use console::style; use itertools::Itertools; -use once_cell::sync::Lazy; use rayon::prelude::*; use crate::cache::CacheManager; @@ -302,7 +301,7 @@ impl ExternalPlugin { }; Ok(bin_paths) } - fn fetch_exec_env(&self, ts: &Toolset, tv: &ToolVersion) -> Result> { + fn fetch_exec_env(&self, ts: &Toolset, tv: &ToolVersion) -> Result> { let mut sm = self.script_man_for_tv(tv)?; for p in ts.list_paths() { sm.prepend_path(p); @@ -733,14 +732,14 @@ impl Forge for ExternalPlugin { config: &Config, ts: &Toolset, tv: &ToolVersion, - ) -> Result> { + ) -> eyre::Result> { if matches!(tv.request, ToolVersionRequest::System(_)) { - return Ok(EMPTY_HASH_MAP.clone()); + return Ok(BTreeMap::new()); } if !self.script_man.script_exists(&ExecEnv) || *env::__MISE_SCRIPT { // if the script does not exist, or we're already running from within a script, // the second is to prevent infinite loops - return Ok(EMPTY_HASH_MAP.clone()); + return Ok(BTreeMap::new()); } self.cache .exec_env(config, self, tv, || self.fetch_exec_env(ts, tv)) @@ -760,8 +759,6 @@ impl Debug for ExternalPlugin { } } -static EMPTY_HASH_MAP: Lazy> = Lazy::new(HashMap::new); - #[cfg(test)] mod tests { use super::*; diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 87cea79c7..5c79e70cf 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::sync::RwLock; use eyre::WrapErr; @@ -15,7 +15,7 @@ use crate::{dirs, env}; #[derive(Debug, Default)] pub struct ExternalPluginCache { list_bin_paths: RwLock>>>, - exec_env: RwLock>>>, + exec_env: RwLock>>>, } impl ExternalPluginCache { @@ -53,9 +53,9 @@ impl ExternalPluginCache { plugin: &ExternalPlugin, tv: &ToolVersion, fetch: F, - ) -> Result> + ) -> Result> where - F: FnOnce() -> Result>, + F: FnOnce() -> Result>, { let mut w = self.exec_env.write().unwrap(); let cm = w.entry(tv.request.clone()).or_insert_with(|| { From 1018b5622c3bda4d0d9fa36b4fa9c1143aabd676 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:30:55 -0600 Subject: [PATCH 1676/1891] env: order flags in docs --- .idea/mise.iml | 2 ++ completions/_mise | 2 +- completions/mise.bash | 2 +- docs/cli-reference.md | 6 +++--- src/cli/env.rs | 8 ++++---- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.idea/mise.iml b/.idea/mise.iml index 29f866ac5..697f7bde4 100644 --- a/.idea/mise.iml +++ b/.idea/mise.iml @@ -28,6 +28,8 @@ + + diff --git a/completions/_mise b/completions/_mise index caeb3e613..80d0999b4 100644 --- a/completions/_mise +++ b/completions/_mise @@ -315,9 +315,9 @@ __mise_doctor_cmd() { (( $+functions[__mise_env_cmd] )) || __mise_env_cmd() { _arguments -s -S \ - '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ '*::tool:__mise_tool_versions' \ '(-J --json)'{-J,--json}'[Output in JSON format]' \ + '(-s --shell)'{-s,--shell}'=[Shell type to generate environment variables for]:shell:(bash fish nu xonsh zsh)' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ diff --git a/completions/mise.bash b/completions/mise.bash index e77ba102a..69468517a 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -1706,7 +1706,7 @@ _mise() { return 0 ;; mise__env) - opts="-s -J -C -q -v -y -h --shell --json --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." + opts="-J -s -C -q -v -y -h --json --shell --cd --debug --log-level --quiet --trace --verbose --yes --help [TOOL@VERSION]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/docs/cli-reference.md b/docs/cli-reference.md index d41489c37..526695298 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -316,14 +316,14 @@ Arguments: Tool(s) to use Options: + -J, --json + Output in JSON format + -s, --shell Shell type to generate environment variables for [possible values: bash, fish, nu, xonsh, zsh] - -J, --json - Output in JSON format - Examples: $ eval "$(mise env -s bash)" $ eval "$(mise env -s zsh)" diff --git a/src/cli/env.rs b/src/cli/env.rs index 79762cb3d..46eefaf8d 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -12,10 +12,6 @@ use crate::toolset::{InstallOptions, Toolset, ToolsetBuilder}; #[derive(Debug, clap::Args)] #[clap(visible_alias = "e", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Env { - /// Shell type to generate environment variables for - #[clap(long, short, overrides_with = "json")] - shell: Option, - /// Tool(s) to use #[clap(value_name = "TOOL@VERSION")] tool: Vec, @@ -23,6 +19,10 @@ pub struct Env { /// Output in JSON format #[clap(long, short = 'J', overrides_with = "shell")] json: bool, + + /// Shell type to generate environment variables for + #[clap(long, short, overrides_with = "json")] + shell: Option, } impl Env { From 2d63b59fd4f4c2a0cecd357f0b25cec3397fff61 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Wed, 24 Jan 2024 20:22:33 -0500 Subject: [PATCH 1677/1891] feat(tasks): infer bash task topics from folder structure (#1520) --- Cargo.lock | 1 + Cargo.toml | 1 + src/config/mod.rs | 4 ++- src/file.rs | 15 +++++++++ src/task.rs | 83 ++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 94 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 141f08670..3bc5367a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1367,6 +1367,7 @@ dependencies = [ "toml_edit", "url", "versions", + "walkdir", "which", "zip", ] diff --git a/Cargo.toml b/Cargo.toml index 76eb53d02..c06ae914e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ toml = { version = "0.8.8", features = ["parse"] } toml_edit = { version = "0.21.0", features = ["parse"] } url = "2.5.0" versions = { version = "6.1.0" , features=["serde"]} +walkdir = "2.4.0" which = "6.0.0" zip = { version = "0.6.6", default-features = false, features = ["deflate"] } diff --git a/src/config/mod.rs b/src/config/mod.rs index 64ad90432..a2b9302d9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -197,7 +197,9 @@ impl Config { None => vec![], } .into_par_iter() - .flat_map(|dir| file::ls(&dir).map_err(|err| warn!("load_all_tasks: {err}"))) + .flat_map(|dir| { + file::recursive_ls(&dir).map_err(|err| warn!("load_all_tasks: {err}")) + }) .flatten() .map(Either::Right) .chain(rayon::iter::once(Either::Left(cf))) diff --git a/src/file.rs b/src/file.rs index 310c243a1..27f65991c 100644 --- a/src/file.rs +++ b/src/file.rs @@ -8,7 +8,9 @@ use std::time::Duration; use color_eyre::eyre::{Context, Result}; use filetime::{set_file_times, FileTime}; use flate2::read::GzDecoder; +use itertools::Itertools; use tar::Archive; +use walkdir::WalkDir; use zip::ZipArchive; use crate::{dirs, env}; @@ -184,6 +186,19 @@ pub fn ls(dir: &Path) -> Result> { Ok(output) } +pub fn recursive_ls(dir: &Path) -> Result> { + if !dir.is_dir() { + return Ok(vec![]); + } + + Ok(WalkDir::new(dir) + .follow_links(true) + .into_iter() + .filter_ok(|e| e.file_type().is_file()) + .map_ok(|e| e.path().to_path_buf()) + .try_collect()?) +} + pub fn make_symlink(target: &Path, link: &Path) -> Result<()> { trace!("ln -sf {} {}", target.display(), link.display()); if link.is_file() || link.is_symlink() { diff --git a/src/task.rs b/src/task.rs index aeb42cee3..5c748837b 100644 --- a/src/task.rs +++ b/src/task.rs @@ -4,9 +4,11 @@ use petgraph::{Direction, Graph}; use std::borrow::Cow; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; +use std::ffi; use std::fmt; use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; +use std::path; use std::path::{Path, PathBuf}; use std::sync::mpsc; @@ -72,13 +74,13 @@ impl Task { map }); let info = toml::Value::Table(info); - let config_root = config_root(path); + let config_root = + config_root(&path).ok_or_else(|| eyre!("config root not found: {}", path.display()))?; let mut tera_ctx = BASE_CONTEXT.clone(); tera_ctx.insert("config_root", &config_root); let p = TomlParser::new(&info, get_tera(config_root), tera_ctx); // trace!("task info: {:#?}", info); - let name = path.file_name().unwrap().to_str().unwrap().to_string(); let task = Task { hide: !file::is_executable(path) || p.parse_bool("hide").unwrap_or_default(), description: p.parse_str("description")?.unwrap_or_default(), @@ -88,7 +90,7 @@ impl Task { dir: p.parse_str("dir")?, env: p.parse_hashmap("env")?.unwrap_or_default(), file: Some(path.to_path_buf()), - ..Task::new(name, path.to_path_buf()) + ..Task::new(name_from_path(config_root, path)?, path.to_path_buf()) }; Ok(task) } @@ -151,6 +153,22 @@ impl Task { } } +fn name_from_path(root: impl AsRef, path: impl AsRef) -> Result { + Ok(path + .as_ref() + .strip_prefix(root) + .map(|p| match p { + p if p.starts_with(".mise/tasks") => p.strip_prefix(".mise/tasks"), + p if p.starts_with(".config/mise/tasks") => p.strip_prefix(".config/mise/tasks"), + _ => Ok(p), + })?? + .components() + .map(path::Component::as_os_str) + .map(ffi::OsStr::to_string_lossy) + .map(|s| s.replace(':', "_")) + .join(":")) +} + impl Display for Task { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { if let Some(cmd) = self.command_string() { @@ -294,12 +312,59 @@ impl TreeItem for (&Graph, NodeIndex) { } } -fn config_root(config_source: &Path) -> &Path { - match config_source.parent().expect("task source has no parent") { - dir if dir.ends_with(".mise/tasks") => dir.parent().unwrap().parent().unwrap(), - dir if dir.ends_with(".config/mise/tasks") => { - dir.parent().unwrap().parent().unwrap().parent().unwrap() +fn config_root(config_source: &impl AsRef) -> Option<&Path> { + for ancestor in config_source.as_ref().ancestors() { + if ancestor.ends_with(".mise/tasks") { + return ancestor.parent()?.parent(); + } + + if ancestor.ends_with(".config/mise/tasks") { + return ancestor.parent()?.parent()?.parent(); + } + } + + Some(config_source.as_ref()) +} + +#[cfg(test)] +mod tests { + use super::{config_root, name_from_path}; + use std::path::Path; + + #[test] + fn test_name_from_path() { + let test_cases = [ + (("/.mise/tasks", "/.mise/tasks/a"), "a"), + (("/.mise/tasks", "/.mise/tasks/a/b"), "a:b"), + (("/.mise/tasks", "/.mise/tasks/a/b/c"), "a:b:c"), + (("/.mise/tasks", "/.mise/tasks/a:b"), "a_b"), + (("/.mise/tasks", "/.mise/tasks/a:b/c"), "a_b:c"), + ]; + + for ((root, path), expected) in test_cases { + assert_eq!(name_from_path(root, path).unwrap(), expected) + } + } + + #[test] + fn test_name_from_path_invalid() { + let test_cases = [("/some/other/dir", "/.mise/tasks/a")]; + + for (root, path) in test_cases { + assert!(name_from_path(root, path).is_err()) + } + } + + #[test] + fn test_config_root() { + let test_cases = [ + ("/base", Some(Path::new("/base"))), + ("/base/.mise/tasks", Some(Path::new("/base"))), + ("/base/.config/mise/tasks", Some(Path::new("/base"))), + ]; + + for (src, expected) in test_cases { + assert_eq!(config_root(&src), expected) } - dir => dir, } } From c97bb7993aa9432ad38879cdc0ab17f251715feb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 24 Jan 2024 19:59:37 -0600 Subject: [PATCH 1678/1891] demand 1.0.0 --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3bc5367a6..b1334afc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,11 +537,12 @@ dependencies = [ [[package]] name = "demand" -version = "0.4.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428fa6ef17b14e980183ddfcdf751ae3405976329911450280aa4ce1268c884d" +checksum = "11b1d1a3335f59757d77c86d2ede00d6955747da2dbc70e581eb74e4774f0a54" dependencies = [ "console", + "once_cell", "termcolor", ] diff --git a/Cargo.toml b/Cargo.toml index c06ae914e..cfa1c99ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ confique = { version = "0.2.5", default-features = false } console = "0.15.8" contracts = "0.6.3" ctrlc = "3.4.2" -demand = "0.4.0" +demand = "1.0.1" dotenvy = "0.15.7" duct = "0.13.7" either = "1.9.0" From 07372390fdc6336856d6f3f6fb18efe03f099715 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Thu, 25 Jan 2024 11:53:28 -0500 Subject: [PATCH 1679/1891] feat(doctor): identify missing/extra shims (#1524) --- src/cli/doctor.rs | 114 ++++++++++++++++++++++++++++++---------------- src/shims.rs | 89 ++++++++++++++++++++++-------------- 2 files changed, 130 insertions(+), 73 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 2dfe399bb..e905c3066 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -13,27 +13,29 @@ use crate::file::display_path; use crate::git::Git; use crate::plugins::PluginType; use crate::shell::ShellType; +use crate::toolset::Toolset; use crate::toolset::ToolsetBuilder; +use crate::ui::style; use crate::{cli, cmd, dirs, forge}; use crate::{duration, env}; +use crate::{file, shims}; /// Check mise installation for possible problems. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] -pub struct Doctor {} +pub struct Doctor { + #[clap(skip)] + checks: Vec, +} impl Doctor { - pub fn run(self) -> Result<()> { - let mut checks = Vec::new(); - if let Err(err) = Config::try_get() { - checks.push(format!("failed to load config: {}", err)); - } - + pub fn run(mut self) -> Result<()> { miseprintln!("{}", mise_version()); miseprintln!("{}", build_info()); miseprintln!("{}", shell()); miseprintln!("{}", mise_data_dir()); miseprintln!("{}", mise_env_vars()); + match Settings::try_get() { Ok(settings) => { miseprintln!( @@ -44,51 +46,28 @@ impl Doctor { } Err(err) => warn!("failed to load settings: {}", err), } + match Config::try_get() { - Ok(config) => { - miseprintln!("{}", render_config_files(&config)); - miseprintln!("{}", render_plugins()); - for plugin in forge::list() { - if !plugin.is_installed() { - checks.push(format!("plugin {} is not installed", &plugin.id())); - continue; - } - } - if !config.is_activated() && !shims_on_path() { - let cmd = style("mise help activate").yellow().for_stderr(); - let url = style("https://mise.jdx.dev").underlined().for_stderr(); - let shims = style(dirs::SHIMS.display()).cyan().for_stderr(); - checks.push(formatdoc!( - r#"mise is not activated, run {cmd} or - read documentation at {url} for activation instructions. - Alternatively, add the shims directory {shims} to PATH. - Using the shims directory is preferred for non-interactive setups."# - )); - } - match ToolsetBuilder::new().build(&config) { - Ok(ts) => { - miseprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())) - } - Err(err) => warn!("failed to load toolset: {}", err), - } + Ok(config) => self.analyze_config(config)?, + Err(err) => { + self.checks.push(format!("failed to load config: {}", err)); } - Err(err) => warn!("failed to load config: {}", err), } if let Some(latest) = cli::version::check_for_new_version(duration::HOURLY) { - checks.push(format!( + self.checks.push(format!( "new mise version {latest} available, currently on {}", *version::V )); } - if checks.is_empty() { + if self.checks.is_empty() { miseprintln!("No problems found"); } else { - let checks_plural = if checks.len() == 1 { "" } else { "s" }; - let summary = format!("{} problem{checks_plural} found:", checks.len()); + let checks_plural = if self.checks.len() == 1 { "" } else { "s" }; + let summary = format!("{} problem{checks_plural} found:", self.checks.len()); miseprintln!("{}", style(summary).red().bold()); - for check in &checks { + for check in &self.checks { miseprintln!("{}\n", check); } exit(1); @@ -96,6 +75,63 @@ impl Doctor { Ok(()) } + + fn analyze_config(&mut self, config: impl AsRef) -> Result<()> { + let config = config.as_ref(); + + miseprintln!("{}", render_config_files(config)); + miseprintln!("{}", render_plugins()); + + for plugin in forge::list() { + if !plugin.is_installed() { + self.checks + .push(format!("plugin {} is not installed", &plugin.id())); + continue; + } + } + + if !config.is_activated() && !shims_on_path() { + let cmd = style::estyle("mise help activate"); + let url = style::eunderline("https://mise.jdx.dev"); + let shims = style::ecyan(dirs::SHIMS.display()); + self.checks.push(formatdoc!( + r#"mise is not activated, run {cmd} or + read documentation at {url} for activation instructions. + Alternatively, add the shims directory {shims} to PATH. + Using the shims directory is preferred for non-interactive setups."# + )); + } + + match ToolsetBuilder::new().build(config) { + Ok(ts) => { + self.analyze_shims(&ts); + + miseprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())); + } + Err(err) => self.checks.push(format!("failed to load toolset: {}", err)), + } + + Ok(()) + } + + fn analyze_shims(&mut self, toolset: &Toolset) { + let mise_bin = file::which("mise").unwrap_or(env::MISE_BIN.clone()); + + if let Ok((missing, extra)) = shims::get_shim_diffs(mise_bin, toolset) { + let cmd = style::eyellow("mise reshim"); + + if !missing.is_empty() { + self.checks + .push(format!("shims are missing, run {cmd} to create them")); + } + + if !extra.is_empty() { + self.checks.push(format!( + "unused shims are present, run {cmd} to remove them" + )); + } + } + } } fn shims_on_path() -> bool { diff --git a/src/shims.rs b/src/shims.rs index a4df6f25d..f314b009f 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -86,29 +86,7 @@ pub fn reshim(ts: &Toolset) -> Result<()> { create_dir_all(&*dirs::SHIMS)?; - let existing_shims = list_executables_in_dir(&dirs::SHIMS)? - .into_par_iter() - .filter(|bin| { - dirs::SHIMS - .join(bin) - .read_link() - .is_ok_and(|p| p == mise_bin) - }) - .collect::>(); - - let shims: HashSet = ts - .list_installed_versions()? - .into_par_iter() - .flat_map(|(t, tv)| { - list_tool_bins(t.clone(), &tv).unwrap_or_else(|e| { - warn!("Error listing bin paths for {}: {:#}", tv, e); - Vec::new() - }) - }) - .collect(); - - let shims_to_add = shims.difference(&existing_shims); - let shims_to_remove = existing_shims.difference(&shims); + let (shims_to_add, shims_to_remove) = get_shim_diffs(&mise_bin, ts)?; for shim in shims_to_add { let symlink_path = dirs::SHIMS.join(shim); @@ -143,17 +121,34 @@ pub fn reshim(ts: &Toolset) -> Result<()> { Ok(()) } -// lists all the paths to bins in a tv that shims will be needed for -fn list_tool_bins(t: Arc, tv: &ToolVersion) -> Result> { - Ok(t.list_bin_paths(tv)? - .into_iter() - .par_bridge() - .filter(|path| path.exists()) - .map(|dir| list_executables_in_dir(&dir)) - .collect::>>()? - .into_iter() - .flatten() - .collect()) +// get_shim_diffs contrasts the actual shims on disk +// with the desired shims specified by the Toolset +// and returns a tuple of (missing shims, extra shims) +pub fn get_shim_diffs( + mise_bin: impl AsRef, + toolset: &Toolset, +) -> Result<(Vec, Vec)> { + let actual_shims = get_actual_shims(&mise_bin)?; + let desired_shims = get_desired_shims(toolset)?; + + Ok(( + desired_shims.difference(&actual_shims).cloned().collect(), + actual_shims.difference(&desired_shims).cloned().collect(), + )) +} + +fn get_actual_shims(mise_bin: impl AsRef) -> Result> { + let mise_bin = mise_bin.as_ref(); + + Ok(list_executables_in_dir(&dirs::SHIMS)? + .into_par_iter() + .filter(|bin| { + dirs::SHIMS + .join(bin) + .read_link() + .is_ok_and(|p| p == mise_bin) + }) + .collect::>()) } fn list_executables_in_dir(dir: &Path) -> Result> { @@ -171,6 +166,32 @@ fn list_executables_in_dir(dir: &Path) -> Result> { Ok(out) } +fn get_desired_shims(toolset: &Toolset) -> Result> { + Ok(toolset + .list_installed_versions()? + .into_par_iter() + .flat_map(|(t, tv)| { + list_tool_bins(t.clone(), &tv).unwrap_or_else(|e| { + warn!("Error listing bin paths for {}: {:#}", tv, e); + Vec::new() + }) + }) + .collect()) +} + +// lists all the paths to bins in a tv that shims will be needed for +fn list_tool_bins(t: Arc, tv: &ToolVersion) -> Result> { + Ok(t.list_bin_paths(tv)? + .into_iter() + .par_bridge() + .filter(|path| path.exists()) + .map(|dir| list_executables_in_dir(&dir)) + .collect::>>()? + .into_iter() + .flatten() + .collect()) +} + fn make_shim(target: &Path, shim: &Path) -> Result<()> { if shim.exists() { file::remove_file(shim)?; From bdb901406fa40a45a43db697410ecd9244786d72 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:57:25 -0600 Subject: [PATCH 1680/1891] chore: Release mise version 2024.1.26 --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- src/default_shorthands.rs | 14 ++++++++++++++ 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b1334afc4..6bda49cb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -243,9 +243,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1303,7 +1303,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.25" +version = "2024.1.26" dependencies = [ "base64", "built", @@ -1805,9 +1805,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index cfa1c99ac..4b3371c44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.25" +version = "2024.1.26" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 42ca8e88e..e280d15c9 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.25 +mise 2024.1.26 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 59c03f7e6..2cbc9335e 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.25"; + version = "2024.1.26"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index afadcd0d4..5b7f2efcc 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.25" +.TH mise 1 "mise 2024.1.26" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.25 +v2024.1.26 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 0434c615a..d1a40baa0 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.25 +Version: 2024.1.26 Release: 1 URL: https://github.com/jdx/mise/ Group: System diff --git a/src/default_shorthands.rs b/src/default_shorthands.rs index e5913208f..f37c080d4 100644 --- a/src/default_shorthands.rs +++ b/src/default_shorthands.rs @@ -762,11 +762,25 @@ pub static DEFAULT_SHORTHANDS: Lazy> = #[rustfmt::skip] pub static TRUSTED_SHORTHANDS: Lazy> = Lazy::new(|| HashSet::from([ + "boundary", + "consul", "dt", "elixir", "hub", + "levant", + "nomad", + "nomad-pack", + "packer", "pipenv", "poetry", + "sentinel", + "serf", + "terraform", + "terraform-ls", + "tfc-agent", "tiny", "tuist", + "vault", + "vlt", + "waypoint", ])); From 59c721690fc7fe5ae5f54e3a530f1523114bdba0 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:43:48 -0600 Subject: [PATCH 1681/1891] pass signals to tasks (#1527) * pass signals to tasks * [MegaLinter] Apply linters fixes --------- Co-authored-by: jdx --- .mise.toml | 3 +++ Cargo.lock | 42 +++++++++++++++++------------------- Cargo.toml | 2 +- src/cli/run.rs | 6 ++++-- src/cli/upgrade.rs | 2 +- src/cmd.rs | 38 ++++++++++++++++++++++++-------- src/ui/ctrlc.rs | 36 +++++++++++++++++++++++++++++++ src/ui/mod.rs | 19 +--------------- src/ui/progress_report.rs | 11 ++++++++-- src/ui/prompt.rs | 10 ++++----- test/fixtures/signal-test.js | 14 ++++++++++++ 11 files changed, 123 insertions(+), 60 deletions(-) create mode 100644 src/ui/ctrlc.rs create mode 100644 test/fixtures/signal-test.js diff --git a/.mise.toml b/.mise.toml index 3aeaa41ee..697d31fda 100644 --- a/.mise.toml +++ b/.mise.toml @@ -91,3 +91,6 @@ run = "cargo release" [tasks.lint-fix] run = "just lint-fix" + +[tasks.signal-test] +run = "node ./test/fixtures/signal-test.js" diff --git a/Cargo.lock b/Cargo.lock index 6bda49cb8..2f3ec6f8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -497,16 +497,6 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "ctrlc" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" -dependencies = [ - "nix", - "windows-sys 0.52.0", -] - [[package]] name = "curve25519-dalek" version = "4.1.1" @@ -1317,7 +1307,6 @@ dependencies = [ "console", "contracts", "ctor", - "ctrlc", "demand", "dotenvy", "duct", @@ -1355,6 +1344,7 @@ dependencies = [ "sha2", "shell-escape", "shell-words", + "signal-hook", "simplelog", "strum", "sys-info", @@ -1391,17 +1381,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -2176,6 +2155,25 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index 4b3371c44..e114c608f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,6 @@ color-print = "0.3.5" confique = { version = "0.2.5", default-features = false } console = "0.15.8" contracts = "0.6.3" -ctrlc = "3.4.2" demand = "1.0.1" dotenvy = "0.15.7" duct = "0.13.7" @@ -87,6 +86,7 @@ serde_json = { version = "1.0.111", features = [] } sha2 = "0.10.8" shell-escape = "0.1.5" shell-words = "1.1.0" +signal-hook = "0.3.17" simplelog = { version = "0.12.1" } strum = { version = "0.25.0", features = ["derive"] } sys-info = "0.9.1" diff --git a/src/cli/run.rs b/src/cli/run.rs index 8370e2acf..1b3950817 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -24,6 +24,7 @@ use crate::errors::Error::ScriptFailed; use crate::file::display_path; use crate::task::{Deps, Task}; use crate::toolset::{InstallOptions, ToolsetBuilder}; +use crate::ui::ctrlc; use crate::ui::style; use crate::{env, file, ui}; @@ -63,7 +64,7 @@ pub struct Run { pub task: String, /// Arguments to pass to the task. Use ":::" to separate tasks. - #[clap()] + #[clap(allow_hyphen_values = true)] pub args: Vec, /// Change to this directory before executing the command @@ -269,6 +270,7 @@ impl Run { ) -> Result<()> { let program = program.to_executable(); let mut cmd = CmdLineRunner::new(program.clone()).args(args).envs(env); + cmd.with_pass_signals(); match &self.output(task)? { TaskOutput::Prefix => cmd = cmd.prefix(format!("{prefix} ")), TaskOutput::Interleave => { @@ -345,7 +347,7 @@ impl Run { for name in task_names { s = s.option(DemandOption::new(name)); } - ui::handle_ctrlc(); + let _ = ctrlc::handle_ctrlc()?; let name = s.run()?; match tasks.get(name) { Some(task) => Ok(task.clone()), diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index d7c8e3eb3..5b5805408 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -126,7 +126,7 @@ impl Upgrade { } fn get_interactive_tool_set(&self, outdated: &OutputVec) -> Result> { - ui::handle_ctrlc(); + let _ = ui::ctrlc::handle_ctrlc()?; let mut ms = demand::MultiSelect::new("mise upgrade") .description("Select tools to upgrade") .filterable(true) diff --git a/src/cmd.rs b/src/cmd.rs index 1f9cefec1..987bc1c15 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -10,6 +10,8 @@ use std::thread; use color_eyre::Result; use duct::{Expression, IntoExecutablePath}; use eyre::Context; +use signal_hook::consts::{SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2}; +use signal_hook::iterator::Signals; use crate::config::Settings; use crate::env; @@ -95,6 +97,7 @@ pub struct CmdLineRunner<'a> { stdin: Option, prefix: String, raw: bool, + pass_signals: bool, } static OUTPUT_LOCK: Mutex<()> = Mutex::new(()); @@ -112,6 +115,7 @@ impl<'a> CmdLineRunner<'a> { stdin: None, prefix: String::new(), raw: false, + pass_signals: false, } } @@ -208,6 +212,11 @@ impl<'a> CmdLineRunner<'a> { self } + pub fn with_pass_signals(&mut self) -> &mut Self { + self.pass_signals = true; + self + } + pub fn stdin_string(mut self, input: impl Into) -> Self { self.cmd.stdin(Stdio::piped()); self.stdin = Some(input.into()); @@ -237,7 +246,6 @@ impl<'a> CmdLineRunner<'a> { let line = line.unwrap(); tx.send(ChildProcessOutput::Stdout(line)).unwrap(); } - tx.send(ChildProcessOutput::Done).unwrap(); } }); } @@ -249,7 +257,6 @@ impl<'a> CmdLineRunner<'a> { let line = line.unwrap(); tx.send(ChildProcessOutput::Stderr(line)).unwrap(); } - tx.send(ChildProcessOutput::Done).unwrap(); } }); } @@ -259,13 +266,27 @@ impl<'a> CmdLineRunner<'a> { stdin.write_all(text.as_bytes()).unwrap(); }); } + let mut sighandle = None; + if self.pass_signals { + let mut signals = + Signals::new([SIGINT, SIGTERM, SIGTERM, SIGHUP, SIGQUIT, SIGUSR1, SIGUSR2])?; + sighandle = Some(signals.handle()); + let tx = tx.clone(); + thread::spawn(move || { + for sig in &mut signals { + tx.send(ChildProcessOutput::Signal(sig)).unwrap(); + } + }); + } + let id = cp.id(); thread::spawn(move || { let status = cp.wait().unwrap(); + if let Some(sighandle) = sighandle { + sighandle.close(); + } tx.send(ChildProcessOutput::ExitStatus(status)).unwrap(); - tx.send(ChildProcessOutput::Done).unwrap(); }); let mut combined_output = vec![]; - let mut wait_for_count = 3; let mut status = None; for line in rx { match line { @@ -280,10 +301,9 @@ impl<'a> CmdLineRunner<'a> { ChildProcessOutput::ExitStatus(s) => { status = Some(s); } - ChildProcessOutput::Done => { - wait_for_count -= 1; - if wait_for_count == 0 { - break; + ChildProcessOutput::Signal(sig) => { + if sig != SIGINT { + cmd!("kill", format!("-{sig}"), id.to_string()).run()?; } } } @@ -375,7 +395,7 @@ enum ChildProcessOutput { Stdout(String), Stderr(String), ExitStatus(ExitStatus), - Done, + Signal(i32), } #[cfg(test)] diff --git a/src/ui/ctrlc.rs b/src/ui/ctrlc.rs new file mode 100644 index 000000000..4dee38c5a --- /dev/null +++ b/src/ui/ctrlc.rs @@ -0,0 +1,36 @@ +use console::Term; +use signal_hook::consts::SIGINT; +use signal_hook::iterator::{Handle, Signals}; +use std::process::exit; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; + +#[derive(Debug)] +pub struct HandleGuard(Handle); + +/// ensures cursor is displayed on ctrl-c +pub fn handle_ctrlc() -> eyre::Result> { + static HANDLED: AtomicBool = AtomicBool::new(false); + let handled = HANDLED.swap(true, Ordering::Relaxed); + if handled { + return Ok(None); + } + + let mut signals = Signals::new([SIGINT])?; + let handle = HandleGuard(signals.handle()); + thread::spawn(move || { + if signals.into_iter().next().is_some() { + let _ = Term::stderr().show_cursor(); + debug!("Ctrl-C pressed, exiting..."); + exit(1); + } + HANDLED.store(false, Ordering::Relaxed); + }); + Ok(Some(handle)) +} + +impl Drop for HandleGuard { + fn drop(&mut self) { + self.0.close(); + } +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 44eb74f37..08ace35bc 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,26 +1,9 @@ -use std::process::exit; -use std::sync::Once; - -use console::{user_attended_stderr, Term}; - pub use prompt::confirm; +pub mod ctrlc; pub mod multi_progress_report; pub mod progress_report; pub mod prompt; pub mod style; pub mod table; pub mod tree; - -pub fn handle_ctrlc() { - static ONCE: Once = Once::new(); - ONCE.call_once(|| { - if user_attended_stderr() { - let _ = ctrlc::set_handler(move || { - let _ = Term::stderr().show_cursor(); - debug!("Ctrl-C pressed, exiting..."); - exit(1); - }); - } - }); -} diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 692d5de72..5b5a91512 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -28,6 +28,8 @@ pub struct ProgressReport { pub pb: ProgressBar, prefix: String, pad: usize, + #[allow(dead_code)] + handle: Option, } static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { @@ -56,13 +58,18 @@ fn success_prefix(pad: usize, prefix: &str) -> String { impl ProgressReport { pub fn new(prefix: String) -> ProgressReport { - ui::handle_ctrlc(); + let handle = ui::ctrlc::handle_ctrlc().unwrap_or_default(); let pad = *LONGEST_PLUGIN_NAME; let pb = ProgressBar::new(100) .with_style(PROG_TEMPLATE.clone()) .with_prefix(normal_prefix(pad, &prefix)); pb.enable_steady_tick(Duration::from_millis(250)); - ProgressReport { prefix, pb, pad } + ProgressReport { + prefix, + pb, + pad, + handle, + } } } diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 2d249a647..34598c809 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -1,18 +1,18 @@ -use std::io; use std::sync::Mutex; use demand::Confirm; -use crate::ui; +use crate::ui::ctrlc; static MUTEX: Mutex<()> = Mutex::new(()); -pub fn confirm>(message: S) -> io::Result { +pub fn confirm>(message: S) -> eyre::Result { let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once - ui::handle_ctrlc(); + let _ = ctrlc::handle_ctrlc()?; if !console::user_attended_stderr() { return Ok(false); } - Confirm::new(message).run() + let result = Confirm::new(message).run()?; + Ok(result) } diff --git a/test/fixtures/signal-test.js b/test/fixtures/signal-test.js new file mode 100644 index 000000000..35032637a --- /dev/null +++ b/test/fixtures/signal-test.js @@ -0,0 +1,14 @@ +let i = 3 + +process.on('SIGINT', function () { + if (i > 0) { + console.log(`Got SIGINT. Press Control-D to exit. ${i} times left`) + i-- + } else { + process.exit() + } +}) + +// wait for 60 seconds +setTimeout(function () {}, 60000) +console.log('Running. Press Control-C to test.') From a4b641825f28cf6511321c1d28bb997c73b77402 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 25 Jan 2024 18:35:47 -0600 Subject: [PATCH 1682/1891] doctor: display missing/extra shims (#1529) * doctor: display missing/extra shims * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- src/cli/doctor.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index e905c3066..fa4832e94 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -121,13 +121,18 @@ impl Doctor { let cmd = style::eyellow("mise reshim"); if !missing.is_empty() { - self.checks - .push(format!("shims are missing, run {cmd} to create them")); + self.checks.push(formatdoc!( + "shims are missing, run {cmd} to create them + Missing shims: {missing}", + missing = missing.join(", ") + )); } if !extra.is_empty() { - self.checks.push(format!( - "unused shims are present, run {cmd} to remove them" + self.checks.push(formatdoc!( + "unused shims are present, run {cmd} to remove them + Unused shims: {extra}", + extra = extra.join(", ") )); } } From 7b3ae2e7a6f42f23d79586cd7a2e6ddc1f9efa89 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Thu, 25 Jan 2024 19:59:11 -0500 Subject: [PATCH 1683/1891] feat(run): match tasks to run with glob patterns (#1528) --- Cargo.lock | 1 + Cargo.toml | 1 + src/cli/run.rs | 39 +++++++++++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f3ec6f8d..d81cc61e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1316,6 +1316,7 @@ dependencies = [ "filetime", "flate2", "fslock", + "globset", "globwalk 0.9.1", "home", "humantime", diff --git a/Cargo.toml b/Cargo.toml index e114c608f..11a7ccbdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ eyre = "0.6.11" filetime = "0.2.23" flate2 = "1.0.28" fslock = "0.2.1" +globset = "0.4.14" globwalk = "0.9.1" home = "0.5.9" humantime = "2.1.0" diff --git a/src/cli/run.rs b/src/cli/run.rs index 1b3950817..31424907c 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -13,6 +13,7 @@ use console::Color; use demand::{DemandOption, Select}; use duct::IntoExecutablePath; use eyre::Result; +use globset::Glob; use globwalk::GlobWalkerBuilder; use itertools::Itertools; use once_cell::sync::Lazy; @@ -134,11 +135,21 @@ impl Run { } }) .flat_map(|args| args.split_first().map(|(t, a)| (t.clone(), a.to_vec()))) - .map(|(t, args)| match config.tasks_with_aliases().get(&t) { - Some(task) => Ok(task.clone().with_args(args.to_vec())), - None if t == "default" => self.prompt_for_task(config), - None => bail!("no task {} found", style::ered(t)), + .map(|(t, args)| { + let tasks = config.tasks_with_aliases().get_matching(&t)?; + if tasks.is_empty() { + ensure!(t == "default", "no task {} found", style::ered(t)); + + Ok(vec![self.prompt_for_task(config)?]) + } else { + Ok(tasks + .iter() + .cloned() + .map(|t| t.clone().with_args(args.to_vec())) + .collect()) + } }) + .flatten_ok() .collect() } @@ -521,6 +532,26 @@ fn get_color() -> Color { static COLOR_IDX: AtomicUsize = AtomicUsize::new(0); COLORS[COLOR_IDX.fetch_add(1, Ordering::Relaxed) % COLORS.len()] } +trait GetMatchingExt { + fn get_matching(&self, pat: &str) -> Result>; +} + +impl GetMatchingExt for std::collections::HashMap { + fn get_matching(&self, pat: &str) -> Result> { + let normalized = pat.split(':').collect::(); + let matcher = Glob::new(&normalized.to_string_lossy())?.compile_matcher(); + + Ok(self + .keys() + .filter(|k| { + let p: PathBuf = k.split(':').collect(); + + matcher.is_match(p) + }) + .flat_map(|k| self.get(k)) + .collect()) + } +} #[cfg(test)] mod tests { From 6be2c83c2ef2d0eccef77b3315033a2613ec8fb3 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Fri, 26 Jan 2024 10:16:57 -0500 Subject: [PATCH 1684/1891] feat(tasks): unify glob strategy for tasks and dependencies (#1533) --- src/cli/run.rs | 24 +----------------------- src/task.rs | 47 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 31424907c..e768d363b 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -13,7 +13,6 @@ use console::Color; use demand::{DemandOption, Select}; use duct::IntoExecutablePath; use eyre::Result; -use globset::Glob; use globwalk::GlobWalkerBuilder; use itertools::Itertools; use once_cell::sync::Lazy; @@ -23,7 +22,7 @@ use crate::config::{Config, Settings}; use crate::errors::Error; use crate::errors::Error::ScriptFailed; use crate::file::display_path; -use crate::task::{Deps, Task}; +use crate::task::{Deps, GetMatchingExt, Task}; use crate::toolset::{InstallOptions, ToolsetBuilder}; use crate::ui::ctrlc; use crate::ui::style; @@ -532,27 +531,6 @@ fn get_color() -> Color { static COLOR_IDX: AtomicUsize = AtomicUsize::new(0); COLORS[COLOR_IDX.fetch_add(1, Ordering::Relaxed) % COLORS.len()] } -trait GetMatchingExt { - fn get_matching(&self, pat: &str) -> Result>; -} - -impl GetMatchingExt for std::collections::HashMap { - fn get_matching(&self, pat: &str) -> Result> { - let normalized = pat.split(':').collect::(); - let matcher = Glob::new(&normalized.to_string_lossy())?.compile_matcher(); - - Ok(self - .keys() - .filter(|k| { - let p: PathBuf = k.split(':').collect(); - - matcher.is_match(p) - }) - .flat_map(|k| self.get(k)) - .collect()) - } -} - #[cfg(test)] mod tests { use crate::file; diff --git a/src/task.rs b/src/task.rs index 5c748837b..0084495c6 100644 --- a/src/task.rs +++ b/src/task.rs @@ -1,3 +1,4 @@ +use globset::Glob; use petgraph::graph::DiGraph; use petgraph::prelude::*; use petgraph::{Direction, Graph}; @@ -134,17 +135,7 @@ impl Task { let depends = self .depends .iter() - .map(|name| match name.strip_suffix('*') { - Some(prefix) => Ok(tasks - .values() - .unique() - .filter(|t| *t != self && t.name.starts_with(prefix)) - .collect::>()), - None => tasks - .get(name) - .map(|task| vec![task]) - .ok_or_else(|| eyre!("task not found: {name}")), - }) + .map(|pat| match_tasks(tasks, pat)) .collect::>>()? .into_iter() .flatten() @@ -169,6 +160,15 @@ fn name_from_path(root: impl AsRef, path: impl AsRef) -> Result(tasks: &'a HashMap, pat: &str) -> Result> { + let matches = tasks.get_matching(pat)?; + if matches.is_empty() { + return Err(eyre!("task not found: {pat}")); + }; + + Ok(matches) +} + impl Display for Task { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { if let Some(cmd) = self.command_string() { @@ -368,3 +368,28 @@ mod tests { } } } + +pub trait GetMatchingExt { + fn get_matching(&self, pat: &str) -> Result>; +} + +impl GetMatchingExt for std::collections::HashMap +where + T: std::cmp::Eq + std::hash::Hash, +{ + fn get_matching(&self, pat: &str) -> Result> { + let normalized = pat.split(':').collect::(); + let matcher = Glob::new(&normalized.to_string_lossy())?.compile_matcher(); + + Ok(self + .iter() + .filter(|(k, _)| { + let p: PathBuf = k.split(':').collect(); + + matcher.is_match(p) + }) + .map(|(_, t)| t) + .unique() + .collect()) + } +} From 81aacb045700ff2a3d2484f36ea04ef795e1720b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:35:14 -0600 Subject: [PATCH 1685/1891] fix global config with asdf_compat (#1534) Fixes #1530 --- .shellcheckrc | 3 ++- e2e/test_global | 14 ++++++++++ src/cli/global.rs | 9 ++++--- src/config/settings.rs | 60 +++++++++++++++++++++++++++++++----------- src/task.rs | 50 +++++++++++++++++------------------ src/toolset/mod.rs | 2 +- 6 files changed, 92 insertions(+), 46 deletions(-) create mode 100755 e2e/test_global diff --git a/.shellcheckrc b/.shellcheckrc index cacba8e25..8cc152d0a 100644 --- a/.shellcheckrc +++ b/.shellcheckrc @@ -1,2 +1,3 @@ -disable=SC2317 disable=SC1008 +disable=SC2088 +disable=SC2317 diff --git a/e2e/test_global b/e2e/test_global new file mode 100755 index 000000000..a46943ec7 --- /dev/null +++ b/e2e/test_global @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +unset MISE_GLOBAL_CONFIG_FILE +unset MISE_CONFIG_FILE + +assert_contains "mise global node 20.0.0" "~/.mise/e2e/config/config.toml" +MISE_ASDF_COMPAT=1 assert_contains "mise global node 20.0.0" "~/.e2e-tool-versions" +MISE_CONFIG_FILE=$HOME/.e2e-tool-versions assert_contains "mise global node 20.0.0" "~/.e2e-tool-versions" +MISE_GLOBAL_CONFIG_FILE=$HOME/.e2e-tool-versions assert_contains "mise global node 20.0.0" "~/.e2e-tool-versions" + +rm -f ~/.e2e-tool-versions ~/.mise/e2e/config/config.toml diff --git a/src/cli/global.rs b/src/cli/global.rs index ff82dde16..bb23ea03b 100644 --- a/src/cli/global.rs +++ b/src/cli/global.rs @@ -2,15 +2,17 @@ use eyre::Result; use crate::cli::args::{ForgeArg, ToolArg}; use crate::cli::local::local; -use crate::env; +use crate::config::Settings; /// Sets/gets the global tool version(s) /// -/// Displays the contents of ~/.tool-versions after writing. +/// Displays the contents of global config after writing. /// The file is `$HOME/.config/mise/config.toml` by default. It can be changed with `$MISE_GLOBAL_CONFIG_FILE`. /// If `$MISE_GLOBAL_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.mise.toml`. /// Otherwise, it will be parsed as a `.tool-versions` file. /// +/// Use MISE_ASDF_COMPAT=1 to default the global config to ~/.tool-versions +/// /// Use `mise local` to set a tool version locally in the current directory. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, hide = true, alias = "g", after_long_help = AFTER_LONG_HELP)] @@ -44,8 +46,9 @@ pub struct Global { impl Global { pub fn run(self) -> Result<()> { + let settings = Settings::try_get()?; local( - &env::MISE_GLOBAL_CONFIG_FILE, + &settings.global_tools_file(), self.tool, self.remove, self.pin, diff --git a/src/config/settings.rs b/src/config/settings.rs index 1be1c661b..0b0fa7997 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -11,7 +11,7 @@ use once_cell::sync::Lazy; use serde::ser::Error; use serde_derive::{Deserialize, Serialize}; -use crate::{env, file}; +use crate::{dirs, env, file}; #[derive(Config, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize, Default)))] @@ -26,6 +26,9 @@ pub struct Settings { pub always_keep_download: bool, #[config(env = "MISE_ALWAYS_KEEP_INSTALL", default = false)] pub always_keep_install: bool, + /// default to asdf-compatible behavior + /// this means that the global config file will be ~/.tool-versions + /// also, the default behavior of `mise global` will be --pin #[config(env = "MISE_ASDF_COMPAT", default = false)] pub asdf_compat: bool, /// use cargo-binstall instead of cargo install if available @@ -131,21 +134,13 @@ impl Settings { if let Some(settings) = SETTINGS.read().unwrap().as_ref() { return Ok(settings.clone()); } - let file_1 = Self::config_settings().unwrap_or_else(|e| { - eprintln!("Error loading settings file: {}", e); - Default::default() - }); - let file_2 = Self::deprecated_settings_file().unwrap_or_else(|e| { - eprintln!("Error loading settings file: {}", e); - Default::default() - }); - let mut settings = Self::builder() + let mut sb = Self::builder() .preloaded(CLI_SETTINGS.lock().unwrap().clone().unwrap_or_default()) - .env() - .preloaded(file_1) - .preloaded(file_2) - .preloaded(DEFAULT_SETTINGS.clone()) - .load()?; + .env(); + for file in Self::all_settings_files() { + sb = sb.preloaded(file); + } + let mut settings = sb.preloaded(DEFAULT_SETTINGS.clone()).load()?; if let Some(cd) = &settings.cd { static ORIG_PATH: Lazy> = Lazy::new(env::current_dir); let mut cd = PathBuf::from(cd); @@ -233,7 +228,15 @@ impl Settings { fn config_settings() -> Result { let global_config = &*env::MISE_GLOBAL_CONFIG_FILE; - if !global_config.exists() { + let filename = global_config + .file_name() + .unwrap_or_default() + .to_string_lossy(); + // if the file doesn't exist or is actually a .tool-versions config + if !global_config.exists() + || filename == *env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME + || filename == ".tool-versions" + { return Ok(Default::default()); } let raw = file::read_to_string(global_config)?; @@ -250,6 +253,19 @@ impl Settings { Self::from_file(settings_file) } + fn all_settings_files() -> Vec { + vec![Self::config_settings(), Self::deprecated_settings_file()] + .into_iter() + .filter_map(|cfg| match cfg { + Ok(cfg) => Some(cfg), + Err(e) => { + eprintln!("Error loading settings file: {}", e); + None + } + }) + .collect() + } + pub fn from_file(path: &PathBuf) -> Result { let raw = file::read_to_string(path)?; let settings: SettingsPartial = toml::from_str(&raw)?; @@ -277,6 +293,18 @@ impl Settings { pub fn trusted_config_paths(&self) -> impl Iterator + '_ { self.trusted_config_paths.iter().map(file::replace_path) } + + pub fn global_tools_file(&self) -> PathBuf { + env::var_path("MISE_GLOBAL_CONFIG_FILE") + .or_else(|| env::var_path("MISE_CONFIG_FILE")) + .unwrap_or_else(|| { + if self.asdf_compat { + env::HOME.join(&*env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME) + } else { + dirs::CONFIG.join("config.toml") + } + }) + } } impl Display for Settings { diff --git a/src/task.rs b/src/task.rs index 0084495c6..cf628c9fa 100644 --- a/src/task.rs +++ b/src/task.rs @@ -326,6 +326,31 @@ fn config_root(config_source: &impl AsRef) -> Option<&Path> { Some(config_source.as_ref()) } +pub trait GetMatchingExt { + fn get_matching(&self, pat: &str) -> Result>; +} + +impl GetMatchingExt for std::collections::HashMap +where + T: std::cmp::Eq + std::hash::Hash, +{ + fn get_matching(&self, pat: &str) -> Result> { + let normalized = pat.split(':').collect::(); + let matcher = Glob::new(&normalized.to_string_lossy())?.compile_matcher(); + + Ok(self + .iter() + .filter(|(k, _)| { + let p: PathBuf = k.split(':').collect(); + + matcher.is_match(p) + }) + .map(|(_, t)| t) + .unique() + .collect()) + } +} + #[cfg(test)] mod tests { use super::{config_root, name_from_path}; @@ -368,28 +393,3 @@ mod tests { } } } - -pub trait GetMatchingExt { - fn get_matching(&self, pat: &str) -> Result>; -} - -impl GetMatchingExt for std::collections::HashMap -where - T: std::cmp::Eq + std::hash::Hash, -{ - fn get_matching(&self, pat: &str) -> Result> { - let normalized = pat.split(':').collect::(); - let matcher = Glob::new(&normalized.to_string_lossy())?.compile_matcher(); - - Ok(self - .iter() - .filter(|(k, _)| { - let p: PathBuf = k.split(':').collect(); - - matcher.is_match(p) - }) - .map(|(_, t)| t) - .unique() - .collect()) - } -} diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index b308411de..6dd5eeaba 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -397,7 +397,7 @@ impl Toolset { .join(" "); info!( "missing: {}", - truncate_str(&versions, *TERM_WIDTH - 13, "…"), + truncate_str(&versions, *TERM_WIDTH - 15, "…"), ); } } From 91b9fc176861ccd202babede7520fbcb4e87ee07 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:59:39 -0600 Subject: [PATCH 1686/1891] added settings_message settings (#1535) --- completions/_mise | 2 -- completions/mise.fish | 1 - docs/cli-reference.md | 3 --- src/cli/activate.rs | 2 +- src/cli/hook_env.rs | 39 +++++++++++++++++++++------------------ src/cli/mod.rs | 4 +--- src/cli/settings/ls.rs | 1 + src/cli/settings/set.rs | 1 + src/cli/settings/unset.rs | 1 + src/config/settings.rs | 20 +++++++++++++++++++- src/logger.rs | 11 ++++++----- src/shims.rs | 2 +- src/toolset/mod.rs | 4 ++-- 13 files changed, 54 insertions(+), 37 deletions(-) diff --git a/completions/_mise b/completions/_mise index 80d0999b4..4cd5cefda 100644 --- a/completions/_mise +++ b/completions/_mise @@ -69,7 +69,6 @@ return ret __mise_activate_cmd() { _arguments -s -S \ '::shell_type:(bash fish nu xonsh zsh)' \ - '--status[Show "mise\: @" message when changing directories]' \ '--shims[Use shims instead of modifying PATH]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -352,7 +351,6 @@ __mise_global_cmd() { __mise_hook_env_cmd() { _arguments -s -S \ '(-s --shell)'{-s,--shell}'=[Shell type to generate script for]:shell:(bash fish nu xonsh zsh)' \ - '--status[Show "mise\: @" message when changing directories]' \ '(-q --quiet)'{-q,--quiet}'[Hide warnings such as when a tool is not installed]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ diff --git a/completions/mise.fish b/completions/mise.fish index 6e1fb43af..5cf6c7fad 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -49,7 +49,6 @@ complete -xc mise -n "not $fssf $others" -a which -d 'Shows the path that a bin complete -kxc mise -n "$fssf activate" -s q -l quiet -d 'Suppress non-error messages' complete -kxc mise -n "$fssf activate" -a "bash fish nu xonsh zsh" -d 'Shell type to generate the script for' complete -kxc mise -n "$fssf activate" -l shims -d 'Use shims instead of modifying PATH' -complete -kxc mise -n "$fssf activate" -l status -d 'Show "mise: @" message when changing directories' # alias complete -kxc mise -n "$fssf alias" -l no-header -d 'Don'\''t show table header' diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 526695298..c5af25a20 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -33,9 +33,6 @@ Arguments: [possible values: bash, fish, nu, xonsh, zsh] Options: - --status - Show "mise: @" message when changing directories - --shims Use shims instead of modifying PATH Effectively the same as: diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 475c0334b..c510bcb6d 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -36,7 +36,7 @@ pub struct Activate { shell_type: Option, /// Show "mise: @" message when changing directories - #[clap(long)] + #[clap(long, hide = true)] status: bool, /// Use shims instead of modifying PATH diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index db076660b..712922d3d 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -24,7 +24,7 @@ pub struct HookEnv { shell: Option, /// Show "mise: @" message when changing directories - #[clap(long)] + #[clap(long, hide = true)] status: bool, /// Hide warnings such as when a tool is not installed @@ -65,30 +65,33 @@ impl HookEnv { let output = hook_env::build_env_commands(&*shell, &patches); miseprint!("{output}"); - if self.status { - self.display_status(&config, &ts)?; - ts.notify_if_versions_missing(); - } + self.display_status(&config, &ts)?; Ok(()) } fn display_status(&self, config: &Config, ts: &Toolset) -> Result<()> { - let installed_versions = ts - .list_current_installed_versions() - .into_iter() - .rev() - .map(|(_, v)| v.to_string()) - .collect_vec(); - if !installed_versions.is_empty() { - let status = installed_versions.into_iter().rev().join(" "); - info!("{}", truncate_str(&status, TERM_WIDTH.max(60) - 5, "…")); + let settings = Settings::get(); + if self.status || settings.status.show_tools { + let installed_versions = ts + .list_current_installed_versions() + .into_iter() + .rev() + .map(|(_, v)| v.to_string()) + .collect_vec(); + if !installed_versions.is_empty() { + let status = installed_versions.into_iter().rev().join(" "); + info!("{}", truncate_str(&status, TERM_WIDTH.max(60) - 5, "…")); + } } - let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env()?.clone()).to_patches(); - if !env_diff.is_empty() { - let env_diff = env_diff.into_iter().map(patch_to_status).join(" "); - info!("{}", truncate_str(&env_diff, TERM_WIDTH.max(60) - 5, "…")); + if self.status || settings.status.show_env { + let env_diff = EnvDiff::new(&env::PRISTINE_ENV, config.env()?.clone()).to_patches(); + if !env_diff.is_empty() { + let env_diff = env_diff.into_iter().map(patch_to_status).join(" "); + info!("{}", truncate_str(&env_diff, TERM_WIDTH.max(60) - 5, "…")); + } } + ts.notify_if_versions_missing(); Ok(()) } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1de20b0db..bee37dfcf 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -207,9 +207,7 @@ impl Cli { .get_matches_from(args) }); Settings::add_cli_matches(&matches); - if let Ok(settings) = Settings::try_get() { - logger::init(&settings); - } + logger::init(); migrate::run(); debug!("ARGS: {}", &args.join(" ")); match Commands::from_arg_matches(&matches) { diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index d324f7651..3fbd79911 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -73,6 +73,7 @@ mod tests { quiet = false raw = false shorthands_file = null + status = {"missing_tools":true,"show_env":false,"show_tools":false} task_output = null trusted_config_paths = [] verbose = true diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 5f0999c44..389cdbb79 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -124,6 +124,7 @@ pub mod tests { quiet = false raw = false shorthands_file = null + status = {"missing_tools":true,"show_env":false,"show_tools":false} task_output = null trusted_config_paths = [] verbose = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 7b253595b..15f5a2bcb 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -68,6 +68,7 @@ mod tests { quiet = false raw = false shorthands_file = null + status = {"missing_tools":true,"show_env":false,"show_tools":false} task_output = null trusted_config_paths = [] verbose = true diff --git a/src/config/settings.rs b/src/config/settings.rs index 0b0fa7997..f5f32785c 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -13,7 +13,7 @@ use serde_derive::{Deserialize, Serialize}; use crate::{dirs, env, file}; -#[derive(Config, Debug, Clone, Serialize)] +#[derive(Config, Default, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize, Default)))] #[config(partial_attr(serde(deny_unknown_fields)))] pub struct Settings { @@ -48,6 +48,9 @@ pub struct Settings { pub legacy_version_file: bool, #[config(env = "MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, + /// what level of status messages to display when entering directories + #[config(nested)] + pub status: SettingsStatus, #[config(env = "MISE_NODE_COMPILE", default = false)] pub node_compile: bool, #[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)] @@ -105,6 +108,21 @@ pub struct Settings { pub log_level: String, } +#[derive(Config, Default, Debug, Clone, Serialize)] +#[config(partial_attr(derive(Clone, Serialize, Default)))] +#[config(partial_attr(serde(deny_unknown_fields)))] +pub struct SettingsStatus { + /// warn if a tool is missing + #[config(env = "MISE_STATUS_MESSAGE_MISSING_TOOLS", default = true)] + pub missing_tools: bool, + /// show env var keys when entering directories + #[config(env = "MISE_STATUS_MESSAGE_SHOW_ENV", default = false)] + pub show_env: bool, + /// show active tools when entering directories + #[config(env = "MISE_STATUS_MESSAGE_SHOW_TOOLS", default = false)] + pub show_tools: bool, +} + pub type SettingsPartial = ::Partial; static SETTINGS: RwLock>> = RwLock::new(None); diff --git a/src/logger.rs b/src/logger.rs index 9f2ce99b6..1061d2f18 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -9,17 +9,18 @@ use simplelog::*; use crate::config::Settings; use crate::env; -pub fn init(settings: &Settings) { +pub fn init() { static INIT: std::sync::Once = std::sync::Once::new(); - INIT.call_once(|| _init(settings)); + INIT.call_once(_init); } -pub fn _init(settings: &Settings) { +pub fn _init() { if cfg!(test) { return; } + let settings = Settings::try_get().unwrap_or_else(|_| Default::default()); let mut loggers: Vec> = vec![]; - let level = settings.log_level.parse().unwrap(); + let level = settings.log_level.parse().unwrap_or(LevelFilter::Info); loggers.push(init_term_logger(level)); if let Some(log_file) = &*env::MISE_LOG_FILE { @@ -85,6 +86,6 @@ mod tests { #[test] fn test_init() { - init(&Settings::get()); + init(); } } diff --git a/src/shims.rs b/src/shims.rs index f314b009f..7b80789ca 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -27,7 +27,7 @@ pub fn handle_shim() -> Result<()> { if bin_name == "mise" || !dirs::SHIMS.join(bin_name).exists() || cfg!(test) { return Ok(()); } - logger::init(&Settings::get()); + logger::init(); let args = env::ARGS.read().unwrap(); let mut args: Vec = args.iter().map(OsString::from).collect(); args[0] = which_shim(&env::MISE_BIN_NAME)?.into(); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 6dd5eeaba..585458f85 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -387,7 +387,7 @@ impl Toolset { pub fn notify_if_versions_missing(&self) { let missing = self.list_missing_versions(); - if missing.is_empty() { + if missing.is_empty() || !Settings::get().status.missing_tools { return; } let versions = missing @@ -395,7 +395,7 @@ impl Toolset { .map(|tv| tv.style()) .collect::>() .join(" "); - info!( + warn!( "missing: {}", truncate_str(&versions, *TERM_WIDTH - 15, "…"), ); From 7dce359a31f06e7f32366ee75c1f975d667000d7 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 16:52:42 -0600 Subject: [PATCH 1687/1891] env: resolve env vars in order (#1519) * env-man * Commit from GitHub Actions (test) * env-man --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- e2e/test_go_install | 2 +- schema/mise.json | 252 ++++--- src/cli/hook_env.rs | 15 +- src/config/config_file/mise_toml.rs | 687 +++++++++++------- src/config/config_file/mod.rs | 20 +- ...config_file__mise_toml__tests__env-2.snap} | 3 - ..._config_file__mise_toml__tests__env-3.snap | 7 +- ..._config_file__mise_toml__tests__env-4.snap | 2 +- ..._config_file__mise_toml__tests__env-5.snap | 10 - ...fig_file__mise_toml__tests__fixture-5.snap | 11 +- ...onfig_file__mise_toml__tests__fixture.snap | 11 +- ...g_file__mise_toml__tests__path_dirs-4.snap | 5 - ...g_file__mise_toml__tests__path_dirs-5.snap | 13 - src/config/config_file/tool_versions.rs | 2 +- src/config/env_directive.rs | 147 ++++ src/config/mod.rs | 110 +-- src/config/settings.rs | 6 +- src/dirs.rs | 1 + src/hook_env.rs | 14 +- src/plugins/external_plugin_cache.rs | 3 +- src/task.rs | 2 +- src/tera.rs | 13 +- src/toolset/builder.rs | 4 +- src/toolset/mod.rs | 4 +- test/fixtures/.env | 1 + test/fixtures/.env2 | 1 + 26 files changed, 828 insertions(+), 518 deletions(-) rename src/config/config_file/snapshots/{mise__config__config_file__mise_toml__tests__path_dirs-3.snap => mise__config__config_file__mise_toml__tests__env-2.snap} (63%) delete mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap delete mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap delete mode 100644 src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap create mode 100644 src/config/env_directive.rs create mode 100644 test/fixtures/.env create mode 100644 test/fixtures/.env2 diff --git a/e2e/test_go_install b/e2e/test_go_install index 495283dc5..b8f1a4e1f 100755 --- a/e2e/test_go_install +++ b/e2e/test_go_install @@ -6,4 +6,4 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 assert "mise x go:github.com/DarthSim/hivemind@v1.1.0 -- hivemind --version" "Hivemind version 1.1.0" -chmod -R u+w "$MISE_DATA_DIR/cache/go-"* +chmod -R u+w "$MISE_DATA_DIR/cache/go-"* || true diff --git a/schema/mise.json b/schema/mise.json index c475352c1..fde06afb4 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -54,7 +54,7 @@ "description": "mise settings", "type": "object", "additionalProperties": false, - "properties": { "$ref": "#/$defs/settings" } + "$ref": "#/$defs/settings" } }, "$defs": { @@ -221,126 +221,148 @@ ] }, "settings": { - "activate_aggressive": { - "description": "push tools to the front of PATH instead of allowing modifications of PATH after activation to take precedence", - "type": "boolean" - }, - "all_compile": { - "description": "do not use precompiled binaries for any tool", - "type": "boolean" - }, - "always_keep_download": { - "description": "should mise keep downloaded files after installation", - "type": "boolean" - }, - "always_keep_install": { - "description": "should mise keep install files after installation even if the installation fails", - "type": "boolean" - }, - "asdf_compat": { - "description": "set to true to ensure .tool-versions will be compatible with asdf", - "type": "boolean" - }, - "cargo_binstall": { - "description": "use cargo-binstall to install rust tools if available", - "type": "boolean", - "default": true - }, - "color": { - "description": "colorize output", - "type": "boolean", - "default": true - }, - "disable_default_shorthands": { - "description": "disables built-in shorthands", - "type": "boolean" - }, - "disable_tools": { - "description": "tools that should not be used", - "items": { - "description": "tool name", + "properties": { + "activate_aggressive": { + "description": "push tools to the front of PATH instead of allowing modifications of PATH after activation to take precedence", + "type": "boolean" + }, + "all_compile": { + "description": "do not use precompiled binaries for any tool", + "type": "boolean" + }, + "always_keep_download": { + "description": "should mise keep downloaded files after installation", + "type": "boolean" + }, + "always_keep_install": { + "description": "should mise keep install files after installation even if the installation fails", + "type": "boolean" + }, + "asdf_compat": { + "description": "set to true to ensure .tool-versions will be compatible with asdf", + "type": "boolean" + }, + "cargo_binstall": { + "description": "use cargo-binstall to install rust tools if available", + "type": "boolean", + "default": true + }, + "color": { + "description": "colorize output", + "type": "boolean", + "default": true + }, + "disable_default_shorthands": { + "description": "disables built-in shorthands", + "type": "boolean" + }, + "disable_tools": { + "description": "tools that should not be used", + "items": { + "description": "tool name", + "type": "string" + }, + "type": "array" + }, + "experimental": { + "description": "enable experimental features", + "type": "boolean" + }, + "jobs": { + "description": "number of tools to install in parallel, default is 4", + "type": "integer" + }, + "legacy_version_file": { + "description": "should mise parse legacy version files (e.g. .node-version)", + "type": "boolean" + }, + "legacy_version_file_disable_tools": { + "description": "tools that should not have their legacy version files parsed", + "items": { + "description": "tool name", + "type": "string" + }, + "type": "array" + }, + "node_compile": { + "description": "do not use precompiled binaries for node", + "type": "boolean" + }, + "not_found_auto_install": { + "description": "adds a shell hook to `mise activate` and shims to automatically install tools when they need to be installed", + "type": "boolean", + "default": true + }, + "paranoid": { + "description": "extra-security mode, see https://mise.jdx.dev/paranoid.html for details", + "type": "boolean" + }, + "plugin_autoupdate_last_check_duration": { + "description": "how often to check for plugin updates", "type": "string" }, - "type": "array" - }, - "experimental": { - "description": "enable experimental features", - "type": "boolean" - }, - "jobs": { - "description": "number of tools to install in parallel, default is 4", - "type": "integer" - }, - "legacy_version_file": { - "description": "should mise parse legacy version files (e.g. .node-version)", - "type": "boolean" - }, - "legacy_version_file_disable_tools": { - "description": "tools that should not have their legacy version files parsed", - "items": { - "description": "tool name", + "python_compile": { + "description": "do not use precompiled binaries for python", + "type": "boolean" + }, + "python_venv_auto_create": { + "description": "automatically create a virtualenv for python tools", + "type": "boolean" + }, + "raw": { + "description": "directly connect plugin scripts to stdin/stdout, implies --jobs=1", + "type": "boolean" + }, + "shorthands_file": { + "description": "path to file containing shorthand mappings", "type": "string" }, - "type": "array" - }, - "node_compile": { - "description": "do not use precompiled binaries for node", - "type": "boolean" - }, - "not_found_auto_install": { - "description": "adds a shell hook to `mise activate` and shims to automatically install tools when they need to be installed", - "type": "boolean", - "default": true - }, - "paranoid": { - "description": "extra-security mode, see https://mise.jdx.dev/paranoid.html for details", - "type": "boolean" - }, - "plugin_autoupdate_last_check_duration": { - "description": "how often to check for plugin updates", - "type": "string" - }, - "python_compile": { - "description": "do not use precompiled binaries for python", - "type": "boolean" - }, - "python_venv_auto_create": { - "description": "automatically create a virtualenv for python tools", - "type": "boolean" - }, - "raw": { - "description": "directly connect plugin scripts to stdin/stdout, implies --jobs=1", - "type": "boolean" - }, - "shorthands_file": { - "description": "path to file containing shorthand mappings", - "type": "string" - }, - "task_output": { - "default": "prefix", - "description": "how to display task output", - "enum": ["prefix", "interleave"], - "type": "string" - }, - "trusted_config_paths": { - "description": "config files with these prefixes will be trusted by default", - "items": { - "description": "a path to add to PATH", + "status": { + "description": "configure messages displayed when changing directories or executing tools", + "type": "object", + "additionalProperties": false, + "properties": { + "missing_tools": { + "description": "display warning when a tool is not installed", + "type": "boolean", + "default": true + }, + "show_env": { + "description": "display configured mise environment variables", + "type": "boolean" + }, + "show_tools": { + "description": "display active tools", + "type": "boolean" + } + } + }, + "task_output": { + "default": "prefix", + "description": "how to display task output", + "enum": ["prefix", "interleave"], "type": "string" }, - "type": "array" - }, - "quiet": { - "description": "suppress all non-error output", - "type": "boolean" - }, - "verbose": { - "description": "display extra output", - "type": "boolean" - }, - "yes": { - "description": "assume yes for all prompts", - "type": "boolean" + "trusted_config_paths": { + "description": "config files with these prefixes will be trusted by default", + "items": { + "description": "a path to add to PATH", + "type": "string" + }, + "type": "array" + }, + "quiet": { + "description": "suppress all non-error output", + "type": "boolean" + }, + "verbose": { + "description": "display extra output", + "type": "boolean" + }, + "yes": { + "description": "assume yes for all prompts", + "type": "boolean" + } } } } diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 712922d3d..e2132ef33 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -1,6 +1,6 @@ use std::env::{join_paths, split_paths}; use std::ops::Deref; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use console::truncate_str; use eyre::Result; @@ -35,11 +35,7 @@ pub struct HookEnv { impl HookEnv { pub fn run(self) -> Result<()> { let config = Config::try_get()?; - let watch_files: Vec<_> = config - .config_files - .values() - .flat_map(|p| p.watch_files()) - .collect(); + let watch_files = config.watch_files()?; if hook_env::should_exit_early(&watch_files) { return Ok(()); } @@ -51,7 +47,7 @@ impl HookEnv { let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); let mut patches = diff.to_patches(); - let mut paths = config.path_dirs.clone(); + let mut paths = config.path_dirs()?.clone(); if let Some(p) = env_path { paths.extend(split_paths(&p).collect_vec()); } @@ -165,7 +161,10 @@ impl HookEnv { )) } - fn build_watch_operation(&self, watch_files: &[PathBuf]) -> Result { + fn build_watch_operation( + &self, + watch_files: impl IntoIterator>, + ) -> Result { let watches = hook_env::build_watches(watch_files)?; Ok(EnvDiffOperation::Add( "__MISE_WATCH".into(), diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 89bb07403..b055050f7 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -1,18 +1,21 @@ use std::collections::HashMap; use std::fmt::{Debug, Formatter}; -use std::iter::once; use std::path::{Path, PathBuf}; +use std::str::FromStr; use std::sync::Mutex; -use eyre::{Result, WrapErr}; -use serde::Deserializer; +use eyre::WrapErr; +use itertools::Itertools; +use serde::de::Visitor; +use serde::{de, Deserializer}; use serde_derive::Deserialize; use tera::Context as TeraContext; -use toml_edit::{table, value, Array, Document, Item, TableLike, Value}; +use toml_edit::{table, value, Array, Document, Item, Value}; use versions::Versioning; use crate::cli::args::ForgeArg; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; +use crate::config::env_directive::EnvDirective; use crate::config::AliasMap; use crate::file::{create_dir_all, display_path}; use crate::task::Task; @@ -24,6 +27,7 @@ use crate::ui::style; use crate::{dirs, file, parse_error}; #[derive(Default, Deserialize)] +// #[serde(deny_unknown_fields)] pub struct MiseToml { #[serde(default, deserialize_with = "deserialize_version")] min_version: Option, @@ -33,14 +37,12 @@ pub struct MiseToml { path: PathBuf, #[serde(skip)] toolset: Toolset, - #[serde(skip)] - env_files: Vec, - #[serde(skip)] - env: HashMap, - #[serde(skip)] - env_remove: Vec, - #[serde(skip)] - path_dirs: Vec, + #[serde(default, alias = "dotenv", deserialize_with = "deserialize_arr")] + env_file: Vec, + #[serde(default)] + env: EnvList, + #[serde(default, deserialize_with = "deserialize_arr")] + env_path: Vec, #[serde(skip)] alias: AliasMap, #[serde(skip)] @@ -51,12 +53,38 @@ pub struct MiseToml { tasks: Vec, #[serde(skip)] is_trusted: Mutex>, + #[serde(skip)] + project_root: Option, + #[serde(skip)] + config_root: PathBuf, } +#[derive(Debug, Default, Clone)] +pub struct EnvList(pub(crate) Vec); + impl MiseToml { pub fn init(path: &Path) -> Self { let mut context = BASE_CONTEXT.clone(); context.insert("config_root", path.parent().unwrap().to_str().unwrap()); + let filename = path.file_name().unwrap_or_default().to_string_lossy(); + let project_root = match path.parent() { + Some(dir) => match dir { + dir if dir.starts_with(*dirs::CONFIG) => None, + dir if dir.starts_with(*dirs::SYSTEM) => None, + dir if dir == *dirs::HOME => None, + dir if !filename.starts_with('.') && dir.ends_with(".mise") => dir.parent(), + dir if !filename.starts_with('.') && dir.ends_with(".config/mise") => { + dir.parent().unwrap().parent() + } + dir => Some(dir), + }, + None => None, + }; + let config_root = project_root + .or_else(|| path.parent()) + .or_else(|| dirs::CWD.as_ref().map(|p| p.as_path())) + .unwrap_or_else(|| *dirs::HOME) + .to_path_buf(); Self { path: path.to_path_buf(), context, @@ -65,11 +93,13 @@ impl MiseToml { source: Some(ToolSource::MiseToml(path.to_path_buf())), ..Default::default() }, + project_root: project_root.map(|p| p.to_path_buf()), + config_root, ..Default::default() } } - pub fn from_file(path: &Path) -> Result { + pub fn from_file(path: &Path) -> eyre::Result { trace!("parsing: {}", display_path(path)); let mut rf = Self::init(path); let body = file::read_to_string(path)?; // .suggestion("ensure file exists and can be read")?; @@ -78,9 +108,12 @@ impl MiseToml { Ok(rf) } - fn parse(&mut self, s: &str) -> Result<()> { + fn parse(&mut self, s: &str) -> eyre::Result<()> { let cfg: MiseToml = toml::from_str(s)?; self.min_version = cfg.min_version; + self.env = cfg.env; + self.env_file = cfg.env_file; + self.env_path = cfg.env_path; // TODO: right now some things are parsed with serde (above) and some not (below) everything // should be moved to serde eventually @@ -88,15 +121,11 @@ impl MiseToml { let doc: Document = s.parse()?; // .suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { - "dotenv" => self.parse_env_file(k, v)?, - "env_file" => self.parse_env_file(k, v)?, - "env_path" => self.path_dirs = self.parse_path_env(k, v)?, - "env" => self.parse_env(k, v)?, "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, "plugins" => self.plugins = self.parse_plugins(k, v)?, "tasks" => self.tasks = self.parse_tasks(k, v)?, - "min_version" | "settings" => {} + "dotenv" | "env_file" | "env_path" | "min_version" | "settings" | "env" => {} _ => bail!("unknown key: {}", style::ered(k)), } } @@ -104,135 +133,7 @@ impl MiseToml { Ok(()) } - fn parse_env_file(&mut self, k: &str, v: &Item) -> Result<()> { - trust_check(&self.path)?; - if let Some(filename) = v.as_str() { - let path = self.path.parent().unwrap().join(filename); - self.parse_env_filename(path)?; - } else if let Some(filenames) = v.as_array() { - for filename in filenames { - if let Some(filename) = filename.as_str() { - let path = self.path.parent().unwrap().join(filename); - self.parse_env_filename(path)?; - } else { - parse_error!(k, v, "string"); - } - } - } else { - parse_error!(k, v, "string or array of strings"); - } - Ok(()) - } - - fn parse_env_filename(&mut self, path: PathBuf) -> Result<()> { - let dotenv = dotenvy::from_path_iter(&path) - .wrap_err_with(|| format!("failed to parse dotenv file: {}", display_path(&path)))?; - for item in dotenv { - let (k, v) = item?; - self.env.insert(k, v); - } - self.env_files.push(path); - Ok(()) - } - - fn parse_env(&mut self, key: &str, v: &Item) -> Result<()> { - trust_check(&self.path)?; - - if let Some(arr) = v.as_array_of_tables() { - arr.iter() - .try_for_each(|table| self.parse_single_env(key, table)) - } else if let Some(table) = v.as_table() { - self.parse_single_env(key, table) - } else { - parse_error!(key, v, "table or array of tables") - } - } - - fn parse_single_env(&mut self, key: &str, table: &dyn TableLike) -> Result<()> { - ensure!( - !table.contains_key("PATH"), - "use 'env.mise.path' instead of 'env.PATH'" - ); - - for (k, v) in table.iter() { - let key = format!("{}.{}", key, k); - let k = self.parse_template(&key, k)?; - if k == "_" || k == "mise" { - self.parse_env_mise(&key, v)?; - } else if let Some(v) = v.as_str() { - let v = self.parse_template(&key, v)?; - - if self.env.insert(k, v).is_some() { - bail!("duplicate key: {}", crate::ui::style::eyellow(key),) - } - } else if let Some(v) = v.as_integer() { - if self.env.insert(k, v.to_string()).is_some() { - bail!("duplicate key: {}", crate::ui::style::eyellow(key),) - } - } else if let Some(v) = v.as_bool() { - if self.env_remove.contains(&k) { - bail!("duplicate key: {}", crate::ui::style::eyellow(key),) - }; - - if !v { - self.env_remove.push(k); - } - } else { - parse_error!(key, v, "string, num, or bool") - } - } - - Ok(()) - } - - fn parse_env_mise(&mut self, key: &str, v: &Item) -> Result<()> { - match v.as_table_like() { - Some(table) => { - for (k, v) in table.iter() { - let key = format!("{}.{}", key, k); - match k { - "file" => self.parse_env_file(&key, v)?, - "path" => self.path_dirs = self.parse_path_env(&key, v)?, - _ => parse_error!(key, v, "file or path"), - } - } - Ok(()) - } - _ => parse_error!(key, v, "table"), - } - } - - fn parse_path_env(&self, k: &str, v: &Item) -> Result> { - trust_check(&self.path)?; - let config_root = self.path.parent().unwrap().to_path_buf(); - let get_path = |v: &Item| -> Result { - if let Some(s) = v.as_str() { - let s = self.parse_template(k, s)?; - let s = match s.strip_prefix("./") { - Some(s) => config_root.join(s), - None => match s.strip_prefix("~/") { - Some(s) => dirs::HOME.join(s), - None => s.into(), - }, - }; - Ok(s) - } else { - parse_error!(k, v, "string") - } - }; - if let Some(array) = v.as_array() { - let mut path = Vec::new(); - for v in array { - let item = Item::Value(v.clone()); - path.push(get_path(&item)?); - } - Ok(path) - } else { - Ok(vec![get_path(v)?]) - } - } - - fn parse_alias(&self, k: &str, v: &Item) -> Result { + fn parse_alias(&self, k: &str, v: &Item) -> eyre::Result { match v.as_table_like() { Some(table) => { let mut aliases = AliasMap::new(); @@ -262,12 +163,12 @@ impl MiseToml { } } - fn parse_plugins(&self, key: &str, v: &Item) -> Result> { + fn parse_plugins(&self, key: &str, v: &Item) -> eyre::Result> { trust_check(&self.path)?; self.parse_hashmap(key, v) } - fn parse_tasks(&self, key: &str, v: &Item) -> Result> { + fn parse_tasks(&self, key: &str, v: &Item) -> eyre::Result> { match v.as_table_like() { Some(table) => { let mut tasks = Vec::new(); @@ -283,7 +184,7 @@ impl MiseToml { } } - fn parse_task(&self, key: &str, v: &Item, name: &str) -> Result { + fn parse_task(&self, key: &str, v: &Item, name: &str) -> eyre::Result { let mut task = Task::new(name.into(), self.path.clone()); if v.as_str().is_some() { task.run = self.parse_string_or_array(key, v)?; @@ -322,7 +223,7 @@ impl MiseToml { } } - fn parse_hashmap(&self, key: &str, v: &Item) -> Result> { + fn parse_hashmap(&self, key: &str, v: &Item) -> eyre::Result> { match v.as_table_like() { Some(table) => { let mut env = HashMap::new(); @@ -342,7 +243,7 @@ impl MiseToml { } } - fn parse_toolset(&self, key: &str, v: &Item) -> Result { + fn parse_toolset(&self, key: &str, v: &Item) -> eyre::Result { let mut toolset = Toolset::new(self.toolset.source.clone().unwrap()); match v.as_table_like() { @@ -364,7 +265,7 @@ impl MiseToml { key: &str, v: &Item, fa: ForgeArg, - ) -> Result { + ) -> eyre::Result { let source = ToolSource::MiseToml(self.path.clone()); let mut tool_version_list = ToolVersionList::new(fa.clone(), source); @@ -409,7 +310,7 @@ impl MiseToml { key: &str, v: &Item, fa: ForgeArg, - ) -> Result<(ToolVersionRequest, ToolVersionOptions)> { + ) -> eyre::Result<(ToolVersionRequest, ToolVersionOptions)> { match v.as_table_like() { Some(table) => { let tv = if let Some(v) = table.get("version") { @@ -475,7 +376,7 @@ impl MiseToml { key: &str, v: &Value, fa: ForgeArg, - ) -> Result { + ) -> eyre::Result { match v.as_str() { Some(s) => { let s = self.parse_template(key, s)?; @@ -521,21 +422,21 @@ impl MiseToml { } } - fn parse_bool(&self, k: &str, v: &Item) -> Result { + fn parse_bool(&self, k: &str, v: &Item) -> eyre::Result { match v.as_value().map(|v| v.as_bool()) { Some(Some(v)) => Ok(v), _ => parse_error!(k, v, "boolean"), } } - fn parse_string(&self, k: &str, v: &Item) -> Result { + fn parse_string(&self, k: &str, v: &Item) -> eyre::Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => Ok(v.to_string()), _ => parse_error!(k, v, "string"), } } - fn parse_path(&self, k: &str, v: &Item) -> Result { + fn parse_path(&self, k: &str, v: &Item) -> eyre::Result { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => { let v = self.parse_template(k, v)?; @@ -545,7 +446,7 @@ impl MiseToml { } } - fn parse_string_or_array(&self, k: &str, v: &Item) -> Result> { + fn parse_string_or_array(&self, k: &str, v: &Item) -> eyre::Result> { match v.as_value().map(|v| v.as_str()) { Some(Some(v)) => { let v = self.parse_template(k, v)?; @@ -555,7 +456,7 @@ impl MiseToml { } } - fn parse_string_array(&self, k: &str, v: &Item) -> Result> { + fn parse_string_array(&self, k: &str, v: &Item) -> eyre::Result> { match v .as_array() .map(|v| v.iter().map(|v| v.as_str().unwrap().to_string()).collect()) @@ -585,12 +486,12 @@ impl MiseToml { env_tbl.remove(key); } - fn parse_template(&self, k: &str, input: &str) -> Result { + fn parse_template(&self, k: &str, input: &str) -> eyre::Result { if !input.contains("{{") && !input.contains("{%") && !input.contains("{#") { return Ok(input.to_string()); } trust_check(&self.path)?; - let dir = self.path.parent().unwrap(); + let dir = self.path.parent(); let output = get_tera(dir) .render_str(input, &self.context) .wrap_err_with(|| eyre!("failed to parse template: {k}='{input}'"))?; @@ -602,7 +503,6 @@ impl ConfigFile for MiseToml { fn get_type(&self) -> ConfigFileType { ConfigFileType::MiseToml } - fn get_path(&self) -> &Path { self.path.as_path() } @@ -612,37 +512,30 @@ impl ConfigFile for MiseToml { } fn project_root(&self) -> Option<&Path> { - let fp = self.get_path(); - let filename = fp.file_name().unwrap_or_default().to_string_lossy(); - match fp.parent() { - Some(dir) => match dir { - dir if dir.starts_with(*dirs::CONFIG) => None, - dir if dir.starts_with(*dirs::SYSTEM) => None, - dir if dir == *dirs::HOME => None, - dir if !filename.starts_with('.') && dir.ends_with(".mise") => dir.parent(), - dir if !filename.starts_with('.') && dir.ends_with(".config/mise") => { - dir.parent().unwrap().parent() - } - dir => Some(dir), - }, - None => None, - } + self.project_root.as_deref() } fn plugins(&self) -> HashMap { self.plugins.clone() } - fn env(&self) -> HashMap { - self.env.clone() - } - - fn env_remove(&self) -> Vec { - self.env_remove.clone() - } - - fn env_path(&self) -> Vec { - self.path_dirs.clone() + fn env_entries(&self) -> Vec { + let env_entries = self.env.0.iter().cloned(); + let path_entries = self + .env_path + .iter() + .map(|p| EnvDirective::Path(p.clone())) + .collect_vec(); + let env_files = self + .env_file + .iter() + .map(|p| EnvDirective::File(p.clone())) + .collect_vec(); + path_entries + .into_iter() + .chain(env_files) + .chain(env_entries) + .collect() } fn tasks(&self) -> Vec<&Task> { @@ -686,7 +579,7 @@ impl ConfigFile for MiseToml { } } - fn save(&self) -> Result<()> { + fn save(&self) -> eyre::Result<()> { let contents = self.dump(); if let Some(parent) = self.path.parent() { create_dir_all(parent)?; @@ -705,13 +598,6 @@ impl ConfigFile for MiseToml { fn aliases(&self) -> AliasMap { self.alias.clone() } - - fn watch_files(&self) -> Vec { - once(&self.path) - .chain(self.env_files.iter()) - .cloned() - .collect() - } } impl Debug for MiseToml { @@ -723,17 +609,12 @@ impl Debug for MiseToml { if let Some(min_version) = &self.min_version { d.field("min_version", &min_version.to_string()); } - if !self.env_files.is_empty() { - d.field("env_files", &self.env_files); + if !self.env_file.is_empty() { + d.field("env_file", &self.env_file); } - if !self.env.is_empty() { - d.field("env", &self.env); - } - if !self.env_remove.is_empty() { - d.field("env_remove", &self.env_remove); - } - if !self.path_dirs.is_empty() { - d.field("path_dirs", &self.path_dirs); + let env = self.env_entries(); + if !env.is_empty() { + d.field("env", &env); } if !self.alias.is_empty() { d.field("alias", &self.alias); @@ -752,15 +633,16 @@ impl Clone for MiseToml { context: self.context.clone(), path: self.path.clone(), toolset: self.toolset.clone(), - env_files: self.env_files.clone(), + env_file: self.env_file.clone(), env: self.env.clone(), - env_remove: self.env_remove.clone(), - path_dirs: self.path_dirs.clone(), + env_path: self.env_path.clone(), alias: self.alias.clone(), doc: self.doc.clone(), plugins: self.plugins.clone(), tasks: self.tasks.clone(), is_trusted: Mutex::new(*self.is_trusted.lock().unwrap()), + project_root: self.project_root.clone(), + config_root: self.config_root.clone(), } } } @@ -781,6 +663,178 @@ where } } +fn deserialize_arr<'de, D, T>(deserializer: D) -> eyre::Result, D::Error> +where + D: Deserializer<'de>, + T: FromStr, + ::Err: std::fmt::Display, +{ + struct ArrVisitor(std::marker::PhantomData); + + impl<'de, T> Visitor<'de> for ArrVisitor + where + T: FromStr, + ::Err: std::fmt::Display, + { + type Value = Vec; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("string or array of strings") + } + + fn visit_str(self, v: &str) -> std::result::Result + where + E: de::Error, + { + let v = v.parse().map_err(de::Error::custom)?; + Ok(vec![v]) + } + + fn visit_seq(self, mut seq: S) -> std::result::Result + where + S: de::SeqAccess<'de>, + { + let mut v = vec![]; + while let Some(s) = seq.next_element::()? { + v.push(s.parse().map_err(de::Error::custom)?); + } + Ok(v) + } + } + + deserializer.deserialize_any(ArrVisitor(std::marker::PhantomData)) +} + +impl<'de> de::Deserialize<'de> for EnvList { + fn deserialize(deserializer: D) -> std::result::Result + where + D: de::Deserializer<'de>, + { + struct EnvManVisitor; + + impl<'de> Visitor<'de> for EnvManVisitor { + type Value = EnvList; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("env table or array of env tables") + } + + fn visit_seq(self, mut seq: S) -> std::result::Result + where + S: de::SeqAccess<'de>, + { + let mut env = vec![]; + while let Some(list) = seq.next_element::()? { + env.extend(list.0); + } + Ok(EnvList(env)) + } + fn visit_map(self, mut map: M) -> std::result::Result + where + M: de::MapAccess<'de>, + { + let mut env = vec![]; + while let Some(key) = map.next_key::()? { + match key.as_str() { + "_" | "mise" => { + #[derive(Deserialize)] + #[serde(deny_unknown_fields)] + struct EnvDirectives { + #[serde(default, deserialize_with = "deserialize_arr")] + path: Vec, + #[serde(default, deserialize_with = "deserialize_arr")] + file: Vec, + #[serde(default, deserialize_with = "deserialize_arr")] + source: Vec, + } + let directives = map.next_value::()?; + // TODO: parse these in the order they're defined somehow + for path in directives.path { + env.push(EnvDirective::Path(path)); + } + for file in directives.file { + env.push(EnvDirective::File(file)); + } + for source in directives.source { + env.push(EnvDirective::Source(source)); + } + } + _ => { + enum Val { + Int(i64), + Str(String), + Bool(bool), + } + + impl<'de> de::Deserialize<'de> for Val { + fn deserialize( + deserializer: D, + ) -> std::result::Result + where + D: de::Deserializer<'de>, + { + struct ValVisitor; + + impl<'de> Visitor<'de> for ValVisitor { + type Value = Val; + fn expecting( + &self, + formatter: &mut Formatter, + ) -> std::fmt::Result + { + formatter.write_str("env value") + } + + fn visit_bool(self, v: bool) -> Result + where + E: de::Error, + { + match v { + true => Err(de::Error::custom( + "env values cannot be true", + )), + false => Ok(Val::Bool(v)), + } + } + + fn visit_i64(self, v: i64) -> Result + where + E: de::Error, + { + Ok(Val::Int(v)) + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + Ok(Val::Str(v.to_string())) + } + } + + deserializer.deserialize_any(ValVisitor) + } + } + + let value = map.next_value::()?; + match value { + Val::Int(i) => { + env.push(EnvDirective::Val(key, i.to_string())); + } + Val::Str(s) => { + env.push(EnvDirective::Val(key, s)); + } + Val::Bool(_) => env.push(EnvDirective::Rm(key)), + } + } + } + } + Ok(EnvList(env)) + } + } + + deserializer.deserialize_any(EnvManVisitor) + } +} + #[cfg(test)] mod tests { use crate::dirs; @@ -792,7 +846,7 @@ mod tests { fn test_fixture() { let cf = MiseToml::from_file(&dirs::HOME.join("fixtures/.mise.toml")).unwrap(); - assert_debug_snapshot!(cf.env()); + assert_debug_snapshot!(cf.env_entries()); assert_debug_snapshot!(cf.plugins()); assert_snapshot!(replace_path(&format!("{:#?}", cf.toolset))); assert_debug_snapshot!(cf.alias); @@ -802,20 +856,14 @@ mod tests { #[test] fn test_env() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" + let cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); + let env = parse_env(formatdoc! {r#" min_version = "2024.1.1" [env] foo="bar" - "#}) - .unwrap(); + "#}); - assert_debug_snapshot!(cf.env(), @r###" - { - "foo": "bar", - } - "###); - assert_debug_snapshot!(cf.env_path(), @"[]"); + assert_debug_snapshot!(env, @r###""foo=bar""###); let cf: Box = Box::new(cf); with_settings!({ assert_snapshot!(cf.dump()); @@ -826,65 +874,107 @@ mod tests { #[test] fn test_env_array_valid() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" + let env = parse_env(formatdoc! {r#" [[env]] foo="bar" [[env]] bar="baz" - "#}) - .unwrap(); + "#}); - assert_snapshot!(cf.env()["foo"], @"bar"); - assert_snapshot!(cf.env()["bar"], @"baz"); + assert_snapshot!(env, @r###" + foo=bar + bar=baz + "###); } #[test] - fn test_env_array_duplicate_key() { - let inputs = vec![(r#""bar""#, r#""baz""#), ("1", "2"), ("false", "true")]; + fn test_path_dirs() { + let env = parse_env(formatdoc! {r#" + env_path=["/foo", "./bar"] + [env] + foo="bar" + "#}); - for (a, b) in inputs { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - let err = cf - .parse(&formatdoc! {r#" - [[env]] - foo={a} + assert_snapshot!(env, @r###" + path_add /foo + path_add ./bar + foo=bar + "###); + + let env = parse_env(formatdoc! {r#" + env_path="./bar" + "#}); + assert_snapshot!(env, @"path_add ./bar"); + let env = parse_env(formatdoc! {r#" + [env] + _.path = "./bar" + "#}); + assert_debug_snapshot!(env, @r###""path_add ./bar""###); + + let env = parse_env(formatdoc! {r#" + [env] + _.path = ["/foo", "./bar"] + "#}); + assert_snapshot!(env, @r###" + path_add /foo + path_add ./bar + "###); + + let env = parse_env(formatdoc! {r#" + [[env]] + _.path = "/foo" [[env]] - foo={b} - "#}) - .unwrap_err(); + _.path = "./bar" + "#}); + assert_snapshot!(env, @r###" + path_add /foo + path_add ./bar + "###); - allow_duplicates!( - assert_snapshot!(err.to_string(), @"duplicate key: env.foo"); - ) - } + let env = parse_env(formatdoc! {r#" + env_path = "/foo" + [env] + _.path = "./bar" + "#}); + assert_snapshot!(env, @r###" + path_add /foo + path_add ./bar + "###); } #[test] - fn test_path_dirs() { - with_settings!({ - let p = dirs::HOME.join("fixtures/.mise.toml"); - let mut cf = MiseToml::init(&p); - cf.parse(&formatdoc! {r#" - env_path=["/foo", "./bar"] + fn test_env_file() { + let env = parse_env(formatdoc! {r#" + env_file = ".env" + "#}); + + assert_debug_snapshot!(env, @r###""dotenv .env""###); + + let env = parse_env(formatdoc! {r#" + env_file=[".env", ".env2"] + "#}); + assert_debug_snapshot!(env, @r###""dotenv .env\ndotenv .env2""###); + + let env = parse_env(formatdoc! {r#" [env] - foo="bar" - "#}) - .unwrap(); + _.file = ".env" + "#}); + assert_debug_snapshot!(env, @r###""dotenv .env""###); - assert_debug_snapshot!(cf.env(), @r###" - { - "foo": "bar", - } - "###); - assert_snapshot!(replace_path(&format!("{:?}", cf.env_path())), @r###"["/foo", "~/fixtures/bar"]"###); - let cf: Box = Box::new(cf); - assert_snapshot!(cf.dump()); - assert_display_snapshot!(cf); - assert_debug_snapshot!(cf); - }); + let env = parse_env(formatdoc! {r#" + [env] + _.file = [".env", ".env2"] + "#}); + assert_debug_snapshot!(env, @r###""dotenv .env\ndotenv .env2""###); + + let env = parse_env(formatdoc! {r#" + dotenv = ".env" + [env] + _.file = ".env2" + "#}); + assert_debug_snapshot!(env, @r###""dotenv .env\ndotenv .env2""###); } #[test] @@ -970,11 +1060,80 @@ mod tests { #[test] fn test_fail_with_unknown_key() { let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - let err = cf + let _ = cf .parse(&formatdoc! {r#" invalid_key = true "#}) .unwrap_err(); - assert_snapshot!(err.to_string(), @"unknown key: invalid_key"); + } + + #[test] + fn test_env_entries() { + let toml = formatdoc! {r#" + [env] + foo1="1" + rm=false + _.path="/foo" + foo2="2" + _.file=".env" + foo3="3" + "#}; + assert_snapshot!(parse_env(toml), @r###" + foo1=1 + unset rm + path_add /foo + dotenv .env + foo2=2 + foo3=3 + "###); + } + + #[test] + fn test_env_arr() { + let toml = formatdoc! {r#" + [[env]] + foo1="1" + rm=false + _.path="/foo" + foo2="2" + _.file=".env" + foo3="3" + _.source="/baz1" + + [[env]] + foo4="4" + rm=false + _.file=".env2" + foo5="5" + _.path="/bar" + foo6="6" + _.source="/baz2" + "#}; + assert_snapshot!(parse_env(toml), @r###" + foo1=1 + unset rm + path_add /foo + dotenv .env + source /baz1 + foo2=2 + foo3=3 + foo4=4 + unset rm + path_add /bar + dotenv .env2 + source /baz2 + foo5=5 + foo6=6 + "###); + } + + fn parse(s: String) -> MiseToml { + let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); + cf.parse(&s).unwrap(); + cf + } + + fn parse_env(toml: String) -> String { + parse(toml).env_entries().into_iter().join("\n") } } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 8b4f80bba..85771e7e0 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -13,7 +13,8 @@ use tool_versions::ToolVersions; use crate::cli::args::{ForgeArg, ToolArg}; use crate::config::config_file::mise_toml::MiseToml; -use crate::config::{global_config_files, system_config_files, AliasMap, Settings}; +use crate::config::env_directive::EnvDirective; +use crate::config::{AliasMap, Settings}; use crate::errors::Error::UntrustedConfig; use crate::file::display_path; use crate::hash::{file_hash_sha256, hash_to_str}; @@ -62,13 +63,7 @@ pub trait ConfigFile: Debug + Send + Sync { fn plugins(&self) -> HashMap { Default::default() } - fn env(&self) -> HashMap { - Default::default() - } - fn env_remove(&self) -> Vec { - Default::default() - } - fn env_path(&self) -> Vec { + fn env_entries(&self) -> Vec { Default::default() } fn tasks(&self) -> Vec<&Task> { @@ -82,15 +77,6 @@ pub trait ConfigFile: Debug + Send + Sync { fn aliases(&self) -> AliasMap { Default::default() } - fn watch_files(&self) -> Vec { - vec![self.get_path().to_path_buf()] - } - fn is_global(&self) -> bool { - global_config_files() - .iter() - .chain(system_config_files().iter()) - .any(|p| p == self.get_path()) - } } impl dyn ConfigFile { diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap similarity index 63% rename from src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-3.snap rename to src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap index e71d936af..a2587ae1e 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap @@ -2,7 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf.dump() --- -env_path=["/foo", "./bar"] -[env] -foo="bar" diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap index 3a69d8ca0..7f358280f 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap @@ -1,8 +1,5 @@ --- source: src/config/config_file/mise_toml.rs -expression: cf.dump() +expression: cf --- -min_version = "2024.1.1" -[env] -foo="bar" - +/tmp/.mise.toml: diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap index 7f358280f..11ebdc792 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap @@ -2,4 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -/tmp/.mise.toml: +MiseToml(/tmp/.mise.toml): diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap deleted file mode 100644 index acaad8435..000000000 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-5.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: src/config/config_file/mise_toml.rs -expression: cf ---- -MiseToml(/tmp/.mise.toml): { - min_version: "2024.1.1", - env: { - "foo": "bar", - }, -} diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap index a338ba521..81c72851c 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap @@ -1,11 +1,14 @@ --- source: src/config/config_file/mise_toml.rs -expression: "replace_path(&format!(\"{:#?}\", & cf))" +expression: "replace_path(&format!(\"{:#?}\", &cf))" --- MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { - env: { - "NODE_ENV": "production", - }, + env: [ + Val( + "NODE_ENV", + "production", + ), + ], alias: { ForgeArg("node"): { "my_custom_node": "18", diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture.snap index 48bcd6c18..c39cbcaf0 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture.snap @@ -1,7 +1,10 @@ --- source: src/config/config_file/mise_toml.rs -expression: cf.env() +expression: cf.env_entries() --- -{ - "NODE_ENV": "production", -} +[ + Val( + "NODE_ENV", + "production", + ), +] diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap deleted file mode 100644 index 5ab096ef2..000000000 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-4.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/config/config_file/mise_toml.rs -expression: cf ---- -~/fixtures/.mise.toml: diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap deleted file mode 100644 index 7216a2ba0..000000000 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__path_dirs-5.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: src/config/config_file/mise_toml.rs -expression: cf ---- -MiseToml(~/fixtures/.mise.toml): { - env: { - "foo": "bar", - }, - path_dirs: [ - "/foo", - "~/fixtures/bar", - ], -} diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index e2d3df0e3..86b82ad00 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -55,7 +55,7 @@ impl ToolVersions { pub fn parse_str(s: &str, path: PathBuf) -> Result { let mut cf = Self::init(&path); - let dir = path.parent().unwrap(); + let dir = path.parent(); let s = if config_file::is_trusted(&path) { get_tera(dir).render_str(s, &cf.context)? } else { diff --git a/src/config/env_directive.rs b/src/config/env_directive.rs new file mode 100644 index 000000000..1baa88b54 --- /dev/null +++ b/src/config/env_directive.rs @@ -0,0 +1,147 @@ +use crate::config::config_file::trust_check; +use crate::dirs; +use crate::file::display_path; +use crate::tera::{get_tera, BASE_CONTEXT}; +use eyre::Context; +use indexmap::IndexMap; +use std::collections::{BTreeSet, HashMap}; +use std::fmt::Display; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Clone)] +pub enum EnvDirective { + /// simple key/value pair + Val(String, String), + /// remove a key + Rm(String), + /// dotenv file + File(PathBuf), + /// add a path to the PATH + Path(PathBuf), + /// run a bash script and apply the resulting env diff + Source(PathBuf), +} + +impl From<(String, String)> for EnvDirective { + fn from((k, v): (String, String)) -> Self { + Self::Val(k, v) + } +} + +impl From<(String, i64)> for EnvDirective { + fn from((k, v): (String, i64)) -> Self { + (k, v.to_string()).into() + } +} + +impl Display for EnvDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + EnvDirective::Val(k, v) => write!(f, "{k}={v}"), + EnvDirective::Rm(k) => write!(f, "unset {k}"), + EnvDirective::File(path) => write!(f, "dotenv {}", display_path(path)), + EnvDirective::Path(path) => write!(f, "path_add {}", display_path(path)), + EnvDirective::Source(path) => write!(f, "source {}", display_path(path)), + } + } +} + +#[derive(Debug)] +pub struct EnvResults { + pub env: IndexMap, + pub env_remove: BTreeSet, + pub env_files: Vec, + pub env_paths: Vec, + pub env_scripts: Vec, +} + +impl EnvResults { + pub fn resolve( + initial: &HashMap, + input: Vec<(EnvDirective, PathBuf)>, + ) -> eyre::Result { + let mut ctx = BASE_CONTEXT.clone(); + let mut env = initial + .iter() + .map(|(k, v)| (k.clone(), (v.clone(), None))) + .collect::>(); + let mut r = Self { + env: Default::default(), + env_remove: BTreeSet::new(), + env_files: Vec::new(), + env_paths: Vec::new(), + env_scripts: Vec::new(), + }; + for (directive, source) in input { + let config_root = source.parent().unwrap(); + ctx.insert("config_root", config_root); + ctx.insert("env", &env); + let normalize_path = |s: String| { + let s = s.strip_prefix("./").unwrap_or(&s); + match s.strip_prefix("~/") { + Some(s) => dirs::HOME.join(s), + None if s.starts_with('/') => PathBuf::from(s), + None => config_root.join(s), + } + }; + match directive { + EnvDirective::Val(k, v) => { + let v = r.parse_template(&ctx, &source, &v)?; + r.env_remove.remove(&k); + env.insert(k, (v, Some(source.clone()))); + } + EnvDirective::Rm(k) => { + env.remove(&k); + r.env_remove.insert(k); + } + EnvDirective::Path(input) => { + let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; + let p = normalize_path(s); + r.env_paths.push(p.clone()); + } + EnvDirective::File(input) => { + trust_check(&source)?; + let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; + let p = normalize_path(s); + r.env_files.push(p.clone()); + let errfn = || eyre!("failed to parse dotenv file: {}", display_path(&p)); + for item in dotenvy::from_path_iter(&p).wrap_err_with(errfn)? { + let (k, v) = item.wrap_err_with(errfn)?; + r.env_remove.remove(&k); + env.insert(k, (v, Some(p.clone()))); + } + } + EnvDirective::Source(input) => { + trust_check(&source)?; + let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; + let p = normalize_path(s); + r.env_scripts.push(p.clone()); + // TODO: run script and apply diff + } + }; + } + for (k, (v, source)) in env { + if let Some(source) = source { + r.env.insert(k, (v, source)); + } + } + Ok(r) + } + + fn parse_template( + &self, + ctx: &tera::Context, + path: &Path, + input: &str, + ) -> eyre::Result { + if !input.contains("{{") && !input.contains("{%") && !input.contains("{#") { + return Ok(input.to_string()); + } + trust_check(path)?; + let dir = path.parent(); + let output = get_tera(dir) + .render_str(input, ctx) + .wrap_err_with(|| eyre!("failed to parse template: '{input}'"))?; + Ok(output) + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index a2b9302d9..d06e6ce32 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,7 +1,7 @@ -use std::collections::{BTreeMap, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fmt::{Debug, Formatter}; use std::iter::once; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::{Arc, RwLock}; use either::Either; @@ -18,6 +18,7 @@ use crate::cli::version; use crate::config::config_file::legacy_version::LegacyVersionFile; use crate::config::config_file::mise_toml::MiseToml; use crate::config::config_file::ConfigFile; +use crate::config::env_directive::EnvResults; use crate::config::tracking::Tracker; use crate::file::display_path; use crate::forge::Forge; @@ -27,6 +28,7 @@ use crate::ui::style; use crate::{dirs, env, file, forge}; pub mod config_file; +mod env_directive; pub mod settings; mod tracking; @@ -38,9 +40,9 @@ type EnvWithSources = IndexMap; pub struct Config { pub aliases: AliasMap, pub config_files: ConfigMap, - pub path_dirs: Vec, pub project_root: Option, - env: OnceCell, + env: OnceCell, + env_with_sources: OnceCell, all_aliases: OnceCell, repo_urls: HashMap, shorthands: OnceCell>, @@ -79,7 +81,7 @@ impl Config { let config = Self { env: OnceCell::new(), - path_dirs: load_path_dirs(&config_files), + env_with_sources: OnceCell::new(), aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), shorthands: OnceCell::new(), @@ -96,15 +98,39 @@ impl Config { Ok(config) } - pub fn env(&self) -> Result> { + pub fn env(&self) -> eyre::Result> { Ok(self .env_with_sources()? .iter() .map(|(k, (v, _))| (k.clone(), v.clone())) .collect()) } - pub fn env_with_sources(&self) -> Result<&EnvWithSources> { - self.env.get_or_try_init(|| load_env(&self.config_files)) + pub fn env_with_sources(&self) -> eyre::Result<&EnvWithSources> { + self.env_with_sources.get_or_try_init(|| { + let mut env = self.env_results()?.env.clone(); + let settings = Settings::get(); + if let Some(env_file) = &settings.env_file { + match dotenvy::from_filename_iter(env_file) { + Ok(iter) => { + for item in iter { + let (k, v) = item.unwrap_or_else(|err| { + warn!("env_file: {err}"); + Default::default() + }); + env.insert(k, (v, env_file.clone())); + } + } + Err(err) => trace!("env_file: {err}"), + } + } + Ok(env) + }) + } + pub fn env_results(&self) -> eyre::Result<&EnvResults> { + self.env.get_or_try_init(|| self.load_env()) + } + pub fn path_dirs(&self) -> eyre::Result<&Vec> { + Ok(&self.env_results()?.env_paths) } pub fn get_shorthands(&self) -> &Shorthands { self.shorthands @@ -284,6 +310,25 @@ impl Config { Ok(()) } + fn load_env(&self) -> Result { + let entries = self + .config_files + .iter() + .rev() + .flat_map(|(source, cf)| cf.env_entries().into_iter().map(|e| (e, source.clone()))) + .collect(); + EnvResults::resolve(&env::PRISTINE_ENV, entries) + } + + pub fn watch_files(&self) -> eyre::Result> { + Ok(self + .config_files + .keys() + .chain(self.env_results()?.env_files.iter()) + .map(|p| p.as_path()) + .collect()) + } + #[cfg(test)] pub fn reset() { Settings::reset(None); @@ -390,6 +435,13 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { config_files.into_iter().unique().collect() } +pub fn is_global_config(path: &Path) -> bool { + global_config_files() + .iter() + .chain(system_config_files().iter()) + .any(|p| p == path) +} + pub fn global_config_files() -> Vec { let mut config_files = vec![]; if env::var_path("MISE_CONFIG_FILE").is_none() @@ -463,43 +515,6 @@ fn parse_config_file( } } -fn load_env(config_files: &ConfigMap) -> Result { - let mut env = IndexMap::new(); - for (source, cf) in config_files.iter().rev() { - for (k, v) in cf.env() { - env.insert(k, (v, source.clone())); - } - for k in cf.env_remove() { - // remove values set to "false" - env.remove(&k); - } - } - let settings = Settings::get(); - if let Some(env_file) = &settings.env_file { - match dotenvy::from_filename_iter(env_file) { - Ok(iter) => { - for item in iter { - let (k, v) = item.unwrap_or_else(|err| { - warn!("env_file: {err}"); - Default::default() - }); - env.insert(k, (v, env_file.clone())); - } - } - Err(err) => trace!("env_file: {err}"), - } - } - Ok(env) -} - -fn load_path_dirs(config_files: &ConfigMap) -> Vec { - let mut path_dirs = vec![]; - for cf in config_files.values().rev() { - path_dirs.extend(cf.env_path()); - } - path_dirs -} - fn load_aliases(config_files: &ConfigMap) -> AliasMap { let mut aliases: AliasMap = AliasMap::new(); @@ -535,8 +550,9 @@ impl Debug for Config { // s.field("Env Sources", &self.env_sources); } } - if !self.path_dirs.is_empty() { - s.field("Path Dirs", &self.path_dirs); + let path_dirs = self.path_dirs().cloned().unwrap_or_default(); + if !path_dirs.is_empty() { + s.field("Path Dirs", &path_dirs); } if !self.aliases.is_empty() { s.field("Aliases", &self.aliases); diff --git a/src/config/settings.rs b/src/config/settings.rs index f5f32785c..0edd97305 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -48,9 +48,6 @@ pub struct Settings { pub legacy_version_file: bool, #[config(env = "MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS", default = [], parse_env = list_by_comma)] pub legacy_version_file_disable_tools: BTreeSet, - /// what level of status messages to display when entering directories - #[config(nested)] - pub status: SettingsStatus, #[config(env = "MISE_NODE_COMPILE", default = false)] pub node_compile: bool, #[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)] @@ -82,6 +79,9 @@ pub struct Settings { pub raw: bool, #[config(env = "MISE_SHORTHANDS_FILE")] pub shorthands_file: Option, + /// what level of status messages to display when entering directories + #[config(nested)] + pub status: SettingsStatus, #[config(env = "MISE_TASK_OUTPUT")] pub task_output: Option, #[config(env = "MISE_TRUSTED_CONFIG_PATHS", default = [], parse_env = list_by_colon)] diff --git a/src/dirs.rs b/src/dirs.rs index ede1d6e0a..9ebb4f456 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -5,6 +5,7 @@ use once_cell::sync::Lazy; use crate::env; pub static HOME: Lazy<&Path> = Lazy::new(|| &env::HOME); +pub static CWD: Lazy> = Lazy::new(|| env::current_dir().ok()); pub static DATA: Lazy<&Path> = Lazy::new(|| &env::MISE_DATA_DIR); pub static CACHE: Lazy<&Path> = Lazy::new(|| &env::MISE_CACHE_DIR); pub static CONFIG: Lazy<&Path> = Lazy::new(|| &env::MISE_CONFIG_DIR); diff --git a/src/hook_env.rs b/src/hook_env.rs index 4c56402dd..2e9d73786 100644 --- a/src/hook_env.rs +++ b/src/hook_env.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::io::prelude::*; use std::ops::Deref; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::time::SystemTime; use base64::prelude::*; @@ -19,7 +19,7 @@ use crate::{dirs, env}; /// this function will early-exit the application if hook-env is being /// called and it does not need to be -pub fn should_exit_early(watch_files: &[PathBuf]) -> bool { +pub fn should_exit_early(watch_files: impl IntoIterator>) -> bool { let args = env::ARGS.read().unwrap(); if args.len() < 2 || args[1] != "hook-env" { return false; @@ -101,7 +101,9 @@ pub fn deserialize_watches(raw: String) -> Result { Ok(rmp_serde::from_slice(&writer[..])?) } -pub fn build_watches(watch_files: &[PathBuf]) -> Result { +pub fn build_watches( + watch_files: impl IntoIterator>, +) -> Result { let mut watches = BTreeMap::new(); for cf in get_watch_files(watch_files) { watches.insert(cf.clone(), cf.metadata()?.modified()?); @@ -113,13 +115,15 @@ pub fn build_watches(watch_files: &[PathBuf]) -> Result { }) } -pub fn get_watch_files(watch_files: &[PathBuf]) -> BTreeSet { +pub fn get_watch_files( + watch_files: impl IntoIterator>, +) -> BTreeSet { let mut watches = BTreeSet::new(); if dirs::DATA.exists() { watches.insert(dirs::DATA.to_path_buf()); } for cf in watch_files { - watches.insert(cf.clone()); + watches.insert(cf.as_ref().to_path_buf()); } watches diff --git a/src/plugins/external_plugin_cache.rs b/src/plugins/external_plugin_cache.rs index 5c79e70cf..d37aedcbf 100644 --- a/src/plugins/external_plugin_cache.rs +++ b/src/plugins/external_plugin_cache.rs @@ -99,7 +99,8 @@ fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> Result = Lazy::new(|| { context }); -pub fn get_tera(dir: &Path) -> Tera { +pub fn get_tera(dir: Option<&Path>) -> Tera { let mut tera = Tera::default(); - let dir = dir.to_path_buf(); + let dir = dir.map(PathBuf::from); tera.register_function( "exec", move |args: &HashMap| -> tera::Result { match args.get("command") { Some(Value::String(command)) => { - let result = cmd("bash", ["-c", command]) - .dir(&dir) - .full_env(&*env::PRISTINE_ENV) - .read()?; + let mut cmd = cmd("bash", ["-c", command]).full_env(&*env::PRISTINE_ENV); + if let Some(dir) = &dir { + cmd = cmd.dir(dir); + } + let result = cmd.read()?; Ok(Value::String(result)) } _ => Err("exec command must be a string".into()), diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index 4908931ce..dd1b5bd70 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -5,8 +5,8 @@ use itertools::Itertools; use crate::cli::args::{ForgeArg, ToolArg}; use crate::config::{Config, Settings}; -use crate::env; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; +use crate::{config, env}; #[derive(Debug, Default)] pub struct ToolsetBuilder { @@ -50,7 +50,7 @@ impl ToolsetBuilder { fn load_config_files(&self, config: &Config, ts: &mut Toolset) { for cf in config.config_files.values().rev() { - if self.global_only && !cf.is_global() { + if self.global_only && !config::is_global_config(cf.get_path()) { return; } ts.merge(cf.to_toolset()); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 585458f85..1ba636118 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -276,7 +276,7 @@ impl Toolset { } pub fn env_with_path(&self, config: &Config) -> Result> { let mut path_env = PathEnv::from_iter(env::PATH.clone()); - for p in config.path_dirs.clone() { + for p in config.path_dirs()?.clone() { path_env.add(p); } let mut env = self.env(config)?; @@ -397,7 +397,7 @@ impl Toolset { .join(" "); warn!( "missing: {}", - truncate_str(&versions, *TERM_WIDTH - 15, "…"), + truncate_str(&versions, *TERM_WIDTH - 14, "…"), ); } } diff --git a/test/fixtures/.env b/test/fixtures/.env new file mode 100644 index 000000000..ab720c6d7 --- /dev/null +++ b/test/fixtures/.env @@ -0,0 +1 @@ +export FOO="foo1" diff --git a/test/fixtures/.env2 b/test/fixtures/.env2 new file mode 100644 index 000000000..02215ae27 --- /dev/null +++ b/test/fixtures/.env2 @@ -0,0 +1 @@ +export FOO2="foo2" From ab7f77111470ad669725646fb647dd71f268fe50 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:10:55 -0600 Subject: [PATCH 1688/1891] parse alias + plugins with serde (#1537) --- src/config/config_file/mise_toml.rs | 81 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index b055050f7..43aaa84e0 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Formatter}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -43,11 +43,11 @@ pub struct MiseToml { env: EnvList, #[serde(default, deserialize_with = "deserialize_arr")] env_path: Vec, - #[serde(skip)] + #[serde(default, deserialize_with = "deserialize_alias")] alias: AliasMap, #[serde(skip)] doc: Document, - #[serde(skip)] + #[serde(default)] plugins: HashMap, #[serde(skip)] tasks: Vec, @@ -110,10 +110,12 @@ impl MiseToml { fn parse(&mut self, s: &str) -> eyre::Result<()> { let cfg: MiseToml = toml::from_str(s)?; - self.min_version = cfg.min_version; + self.alias = cfg.alias; self.env = cfg.env; self.env_file = cfg.env_file; self.env_path = cfg.env_path; + self.min_version = cfg.min_version; + self.plugins = cfg.plugins; // TODO: right now some things are parsed with serde (above) and some not (below) everything // should be moved to serde eventually @@ -121,11 +123,10 @@ impl MiseToml { let doc: Document = s.parse()?; // .suggestion("ensure file is valid TOML")?; for (k, v) in doc.iter() { match k { - "alias" => self.alias = self.parse_alias(k, v)?, "tools" => self.toolset = self.parse_toolset(k, v)?, - "plugins" => self.plugins = self.parse_plugins(k, v)?, "tasks" => self.tasks = self.parse_tasks(k, v)?, - "dotenv" | "env_file" | "env_path" | "min_version" | "settings" | "env" => {} + "alias" | "dotenv" | "env_file" | "env_path" | "min_version" | "settings" + | "env" | "plugins" => {} _ => bail!("unknown key: {}", style::ered(k)), } } @@ -133,41 +134,6 @@ impl MiseToml { Ok(()) } - fn parse_alias(&self, k: &str, v: &Item) -> eyre::Result { - match v.as_table_like() { - Some(table) => { - let mut aliases = AliasMap::new(); - for (plugin, table) in table.iter() { - let k = format!("{}.{}", k, plugin); - let fa: ForgeArg = plugin.parse()?; - let plugin_aliases = aliases.entry(fa).or_default(); - match table.as_table_like() { - Some(table) => { - for (from, to) in table.iter() { - match to.as_str() { - Some(s) => { - let from = self.parse_template(&k, from)?; - let s = self.parse_template(&k, s)?; - plugin_aliases.insert(from, s); - } - _ => parse_error!(format!("{}.{}", k, from), to, "string"), - } - } - } - _ => parse_error!(k, v, "table"), - } - } - Ok(aliases) - } - _ => parse_error!(k, v, "table"), - } - } - - fn parse_plugins(&self, key: &str, v: &Item) -> eyre::Result> { - trust_check(&self.path)?; - self.parse_hashmap(key, v) - } - fn parse_tasks(&self, key: &str, v: &Item) -> eyre::Result> { match v.as_table_like() { Some(table) => { @@ -835,6 +801,37 @@ impl<'de> de::Deserialize<'de> for EnvList { } } +fn deserialize_alias<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct AliasMapVisitor; + + impl<'de> Visitor<'de> for AliasMapVisitor { + type Value = AliasMap; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("alias table") + } + + fn visit_map(self, mut map: M) -> std::result::Result + where + M: de::MapAccess<'de>, + { + let mut aliases = AliasMap::new(); + while let Some(plugin) = map.next_key::()? { + let fa: ForgeArg = plugin.parse().map_err(de::Error::custom)?; + let plugin_aliases = aliases.entry(fa).or_default(); + for (from, to) in map.next_value::>()? { + plugin_aliases.insert(from, to); + } + } + Ok(aliases) + } + } + + deserializer.deserialize_map(AliasMapVisitor) +} + #[cfg(test)] mod tests { use crate::dirs; From 76f38cacaacbefe4960850af0d42c9f4e1d74fd0 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:11:57 -0600 Subject: [PATCH 1689/1891] chore: Release mise version 2024.1.27 --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d81cc61e0..f27a4e01a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1225,9 +1225,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.14" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" dependencies = [ "cc", "libc", @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.26" +version = "2024.1.27" dependencies = [ "base64", "built", @@ -2064,18 +2064,18 @@ checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -2084,9 +2084,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed" dependencies = [ "itoa", "ryu", @@ -3090,9 +3090,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.34" +version = "0.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 11a7ccbdd..61ff79a0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.26" +version = "2024.1.27" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index e280d15c9..341fff973 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.26 +mise 2024.1.27 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 2cbc9335e..c92bc7500 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.26"; + version = "2024.1.27"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index d1a40baa0..79116af95 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.26 +Version: 2024.1.27 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 00b756a2d316687a99a755712096e96dd9e27f36 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:00:53 -0600 Subject: [PATCH 1690/1891] added `env._.source` feature (#1538) * added `env._.source` feature * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- e2e/test_env_source | 20 ++++++++++++++++++++ man/man1/mise.1 | 4 ++-- src/config/env_directive.rs | 24 ++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100755 e2e/test_env_source diff --git a/e2e/test_env_source b/e2e/test_env_source new file mode 100755 index 000000000..085516dcf --- /dev/null +++ b/e2e/test_env_source @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +export MISE_EXPERIMENTAL=1 + +mkdir -p "$(dirname "$MISE_GLOBAL_CONFIG_FILE")" "$MISE_CONFIG_DIR" + +cat >"$MISE_GLOBAL_CONFIG_FILE" <"$MISE_CONFIG_DIR/source.sh" < diff --git a/src/config/env_directive.rs b/src/config/env_directive.rs index 1baa88b54..2b3908d7f 100644 --- a/src/config/env_directive.rs +++ b/src/config/env_directive.rs @@ -1,5 +1,7 @@ use crate::config::config_file::trust_check; +use crate::config::Settings; use crate::dirs; +use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::file::display_path; use crate::tera::{get_tera, BASE_CONTEXT}; use eyre::Context; @@ -60,6 +62,7 @@ impl EnvResults { initial: &HashMap, input: Vec<(EnvDirective, PathBuf)>, ) -> eyre::Result { + let settings = Settings::get(); let mut ctx = BASE_CONTEXT.clone(); let mut env = initial .iter() @@ -75,7 +78,11 @@ impl EnvResults { for (directive, source) in input { let config_root = source.parent().unwrap(); ctx.insert("config_root", config_root); - ctx.insert("env", &env); + let env_vars = env + .iter() + .map(|(k, (v, _))| (k.clone(), v.clone())) + .collect::>(); + ctx.insert("env", &env_vars); let normalize_path = |s: String| { let s = s.strip_prefix("./").unwrap_or(&s); match s.strip_prefix("~/") { @@ -112,11 +119,24 @@ impl EnvResults { } } EnvDirective::Source(input) => { + settings.ensure_experimental()?; trust_check(&source)?; let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; let p = normalize_path(s); r.env_scripts.push(p.clone()); - // TODO: run script and apply diff + let env_diff = EnvDiff::from_bash_script(&p, env_vars.clone())?; + for p in env_diff.to_patches() { + match p { + EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => { + r.env_remove.remove(&k); + env.insert(k.clone(), (v.clone(), Some(source.clone()))); + } + EnvDiffOperation::Remove(k) => { + env.remove(&k); + r.env_remove.insert(k); + } + } + } } }; } From 633c3ffe139c1201f20ce0e7145cb361d547a39a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:04:04 -0600 Subject: [PATCH 1691/1891] force update alpine --- scripts/release-alpine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release-alpine.sh b/scripts/release-alpine.sh index e6f871e69..2f94092c7 100755 --- a/scripts/release-alpine.sh +++ b/scripts/release-alpine.sh @@ -37,7 +37,7 @@ fi git commit -m "community/mise: upgrade to ${MISE_VERSION#v}" if [ "$DRY_RUN" == 0 ]; then - git push jdxcode + git push jdxcode -f fi open_mr="$(glab mr list -R alpine/aports --author=@me)" From 3ac2cf7bdc010e206d24ed15afef7fb00c45bc6e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 27 Jan 2024 00:07:07 +0000 Subject: [PATCH 1692/1891] fix(deps): update rust crate chrono to 0.4.33 (#1539) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 61ff79a0d..3b238c681 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ lto = true [dependencies] base64 = "0.21.7" -chrono = { version = "0.4.31", default-features = false, features = ["std", "clock"] } +chrono = { version = "0.4.33", default-features = false, features = ["std", "clock"] } clap = { version = "4.4.18", features = ["env", "derive", "string"] } clap_complete = { version = "4.4.8", optional = true } clap_mangen = { version = "0.2.17", optional = true } From 292b987f67a14397a2b21a183aa0f590c9eeff4e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 27 Jan 2024 00:07:20 +0000 Subject: [PATCH 1693/1891] fix(deps): update rust crate clap_complete to 4.4.9 (#1540) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3b238c681..62a9d8976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ lto = true base64 = "0.21.7" chrono = { version = "0.4.33", default-features = false, features = ["std", "clock"] } clap = { version = "4.4.18", features = ["env", "derive", "string"] } -clap_complete = { version = "4.4.8", optional = true } +clap_complete = { version = "4.4.9", optional = true } clap_mangen = { version = "0.2.17", optional = true } color-eyre = "0.6.2" color-print = "0.3.5" From 470dfe955da226c7560ff882299ec66bc254352f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:08:11 -0600 Subject: [PATCH 1694/1891] chore: Release mise version 2024.1.28 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f27a4e01a..35e2b2903 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.27" +version = "2024.1.28" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 62a9d8976..0d3e84b50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.27" +version = "2024.1.28" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 341fff973..6ce08a2fe 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.27 +mise 2024.1.28 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index c92bc7500..cddb2dc49 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.27"; + version = "2024.1.28"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 79116af95..8a89fcfaa 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.27 +Version: 2024.1.28 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 14fb790ac9953430794719b38b83c8c2242f1759 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:30:23 -0600 Subject: [PATCH 1695/1891] use nodejs/golang for writing to .tool-versions Fixes #1522 --- src/config/config_file/tool_versions.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 86b82ad00..37dde60f8 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -185,7 +185,13 @@ impl ConfigFile for ToolVersions { .max() .unwrap_or_default(); for (_, tv) in &self.plugins { - let plugin = pad_str(&tv.orig_name, max_plugin_len, Alignment::Left, None); + let mut plugin = tv.orig_name.to_string(); + if plugin == "node" { + plugin = "nodejs".into(); + } else if plugin == "go" { + plugin = "golang".into(); + } + let plugin = pad_str(&plugin, max_plugin_len, Alignment::Left, None); s.push_str(&format!("{} {}{}", plugin, tv.versions.join(" "), tv.post)); } From 6b8e21146d4918367d9b794a1c76154401768240 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:31:31 -0600 Subject: [PATCH 1696/1891] read system and local config settings (#1541) Fixes #1426 Fixes #1425 --- man/man1/mise.1 | 4 ++-- src/config/settings.rs | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/man/man1/mise.1 b/man/man1/mise.1 index a24933153..7b1e58361 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.27" +.TH mise 1 "mise 2024.1.28" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.27 +v2024.1.28 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/src/config/settings.rs b/src/config/settings.rs index 0edd97305..f8e379311 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeSet, HashSet}; use std::fmt::{Debug, Display, Formatter}; +use std::iter::once; use std::path::PathBuf; use std::sync::{Arc, Mutex, RwLock}; @@ -11,7 +12,8 @@ use once_cell::sync::Lazy; use serde::ser::Error; use serde_derive::{Deserialize, Serialize}; -use crate::{dirs, env, file}; +use crate::config::{system_config_files, DEFAULT_CONFIG_FILENAMES}; +use crate::{config, dirs, env, file}; #[derive(Config, Default, Debug, Clone, Serialize)] #[config(partial_attr(derive(Clone, Serialize, Default)))] @@ -257,9 +259,7 @@ impl Settings { { return Ok(Default::default()); } - let raw = file::read_to_string(global_config)?; - let settings_file: SettingsFile = toml::from_str(&raw)?; - Ok(settings_file.settings) + Self::parse_settings_file(global_config) } fn deprecated_settings_file() -> Result { @@ -271,9 +271,24 @@ impl Settings { Self::from_file(settings_file) } + fn parse_settings_file(path: &PathBuf) -> Result { + let raw = file::read_to_string(path)?; + let settings_file: SettingsFile = toml::from_str(&raw)?; + Ok(settings_file.settings) + } + fn all_settings_files() -> Vec { - vec![Self::config_settings(), Self::deprecated_settings_file()] - .into_iter() + config::load_config_paths(&DEFAULT_CONFIG_FILENAMES) + .iter() + .filter(|p| { + let filename = p.file_name().unwrap_or_default().to_string_lossy(); + filename != *env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME + && filename != ".tool-versions" + }) + .map(Self::parse_settings_file) + .chain(once(Self::config_settings())) + .chain(once(Self::deprecated_settings_file())) + .chain(system_config_files().iter().map(Self::parse_settings_file)) .filter_map(|cfg| match cfg { Ok(cfg) => Some(cfg), Err(e) => { From 89e78e9b9de8a8fcc8dab9824dd0c6e90e463bda Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:36:12 -0600 Subject: [PATCH 1697/1891] chore: Release mise version 2024.1.29 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35e2b2903..86230fbea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.28" +version = "2024.1.29" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 0d3e84b50..0646dbf1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.28" +version = "2024.1.29" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 6ce08a2fe..a24ec29ab 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.28 +mise 2024.1.29 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index cddb2dc49..db6a71274 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.28"; + version = "2024.1.29"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 8a89fcfaa..75c1ddb57 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.28 +Version: 2024.1.29 Release: 1 URL: https://github.com/jdx/mise/ Group: System From fb80f08350305419c30c523f83c74b28c1045840 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:36:12 -0600 Subject: [PATCH 1698/1891] chore: Release mise version 2024.1.29 --- man/man1/mise.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 7b1e58361..72bfa7843 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.28" +.TH mise 1 "mise 2024.1.29" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.28 +v2024.1.29 .SH AUTHORS Jeff Dickey <@jdx> From da2b1c9d0bbbeba3e566020c0d48e16f579d8eeb Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:44:37 -0600 Subject: [PATCH 1699/1891] fix mangen --- .mise.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.mise.toml b/.mise.toml index 697d31fda..0dc687217 100644 --- a/.mise.toml +++ b/.mise.toml @@ -66,8 +66,6 @@ target/debug/mise render-completion fish > completions/mise.fish depends = ["build"] env = { NO_COLOR = "1" } run = "target/debug/mise render-mangen" -sources = ["target/debug/mise"] -outputs = ["man/man1/mise.1"] [tasks.render-help] depends = ["build"] From 0fac002dbeba699ae8949c3d94e89d08128dae57 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:54:24 -0600 Subject: [PATCH 1700/1891] default to precompiled python --- src/plugins/core/python.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 4aa507ac3..e680878e1 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -95,10 +95,6 @@ impl PythonPlugin { tv.install_short_path().join("bin/python") } - fn should_install_precompiled(&self, settings: &Settings) -> bool { - !settings.python_compile && settings.experimental - } - fn fetch_precompiled_remote_versions(&self) -> Result<&Vec<(String, String, String)>> { self.precompiled_cache.get_or_try_init(|| { let settings = Settings::get(); @@ -312,10 +308,10 @@ impl Forge for PythonPlugin { fn install_version_impl(&self, ctx: &InstallContext) -> Result<()> { let config = Config::get(); let settings = Settings::try_get()?; - if self.should_install_precompiled(&settings) { - self.install_precompiled(ctx)?; - } else { + if settings.python_compile { self.install_compiled(ctx)?; + } else { + self.install_precompiled(ctx)?; } self.test_python(&config, &ctx.tv, ctx.pr.as_ref())?; if let Err(e) = self.get_virtualenv(&config, &ctx.tv, Some(ctx.pr.as_ref())) { From 3a195bc10027df8badfcccc9da210b7286210ec8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 26 Jan 2024 19:03:05 -0600 Subject: [PATCH 1701/1891] chore: Release mise version 2024.1.30 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86230fbea..a2f09f949 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.29" +version = "2024.1.30" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 0646dbf1d..86329f2bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.29" +version = "2024.1.30" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index a24ec29ab..b077170a2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.29 +mise 2024.1.30 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index db6a71274..7904db99e 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.29"; + version = "2024.1.30"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 75c1ddb57..5adba7c11 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.29 +Version: 2024.1.30 Release: 1 URL: https://github.com/jdx/mise/ Group: System From b3e0296939bb8406f59e694d3173bbb7baa9b2f4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jan 2024 19:10:25 -0600 Subject: [PATCH 1702/1891] fix(deps): update rust crate serde_json to 1.0.112 (#1542) * fix(deps): update rust crate serde_json to 1.0.112 * Commit from GitHub Actions (test) --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- Cargo.toml | 2 +- man/man1/mise.1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86329f2bb..7b812c180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ self_update = { version = "0.39.0", default-features = false, features = [ ] } serde = "1.0.195" serde_derive = "1.0.195" -serde_json = { version = "1.0.111", features = [] } +serde_json = { version = "1.0.112", features = [] } sha2 = "0.10.8" shell-escape = "0.1.5" shell-words = "1.1.0" diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 72bfa7843..213a3d7a9 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.29" +.TH mise 1 "mise 2024.1.30" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.29 +v2024.1.30 .SH AUTHORS Jeff Dickey <@jdx> From 7b8a527c892f740fc5ff034dc43ebca239510fd6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 27 Jan 2024 01:18:10 +0000 Subject: [PATCH 1703/1891] fix(deps): update serde monorepo to 1.0.196 (#1543) * fix(deps): update serde monorepo to 1.0.196 * Commit from GitHub Actions (test) --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7b812c180..bca9988a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,8 +81,8 @@ self_update = { version = "0.39.0", default-features = false, features = [ "compression-flate2", "signatures", ] } -serde = "1.0.195" -serde_derive = "1.0.195" +serde = "1.0.196" +serde_derive = "1.0.196" serde_json = { version = "1.0.112", features = [] } sha2 = "0.10.8" shell-escape = "0.1.5" From add725381b2e798e6efbdf40ac356e4f02a17dbd Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Sat, 27 Jan 2024 11:05:11 -0500 Subject: [PATCH 1704/1891] fix: properly handle executable shims when getting diffs (#1545) --- src/shims.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shims.rs b/src/shims.rs index 7b80789ca..63dacea3e 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -143,10 +143,9 @@ fn get_actual_shims(mise_bin: impl AsRef) -> Result> { Ok(list_executables_in_dir(&dirs::SHIMS)? .into_par_iter() .filter(|bin| { - dirs::SHIMS - .join(bin) - .read_link() - .is_ok_and(|p| p == mise_bin) + let path = dirs::SHIMS.join(bin); + + !path.is_symlink() || path.read_link().is_ok_and(|p| p == mise_bin) }) .collect::>()) } From 54fd770428133d02c3094ac899243a9bb6a1a442 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:22:51 -0600 Subject: [PATCH 1705/1891] fix(deps): update rust crate strum to 0.26.0 (#1546) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2f09f949..6143c46e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2245,18 +2245,18 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "117c413ac8a6cc19c773939932477a341e416eff7f0e84db42f091d85d7c6e0e" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "7e91a9c241fae207f533499d25bd2b22cee10f20b5e6aa0074dc4ebc2e23fe14" dependencies = [ "heck 0.4.1", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index bca9988a4..121421756 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,7 +89,7 @@ shell-escape = "0.1.5" shell-words = "1.1.0" signal-hook = "0.3.17" simplelog = { version = "0.12.1" } -strum = { version = "0.25.0", features = ["derive"] } +strum = { version = "0.26.0", features = ["derive"] } sys-info = "0.9.1" tabled = { version = "0.15.0", features = ["ansi"] } tar = "0.4.40" From 7ab1166465ac3e971d4e5dbd86d4397345d2664a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 15:43:12 -0600 Subject: [PATCH 1706/1891] fix(deps): update rust crate strum to 0.26.1 (#1547) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6143c46e4..8a8c8abe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2245,9 +2245,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117c413ac8a6cc19c773939932477a341e416eff7f0e84db42f091d85d7c6e0e" +checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" dependencies = [ "strum_macros", ] diff --git a/Cargo.toml b/Cargo.toml index 121421756..dde9e3fd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,7 +89,7 @@ shell-escape = "0.1.5" shell-words = "1.1.0" signal-hook = "0.3.17" simplelog = { version = "0.12.1" } -strum = { version = "0.26.0", features = ["derive"] } +strum = { version = "0.26.1", features = ["derive"] } sys-info = "0.9.1" tabled = { version = "0.15.0", features = ["ansi"] } tar = "0.4.40" From d7cb4816e9165cde5ac715126a004f924898af0f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 28 Jan 2024 15:48:38 -0600 Subject: [PATCH 1707/1891] updated indexmap --- Cargo.lock | 8 ++++---- src/config/config_file/mise_toml.rs | 2 +- src/config/config_file/tool_versions.rs | 2 +- src/config/env_directive.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a8c8abe0..48324fe9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1107,9 +1107,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "cf2a4f498956c7723dc280afc6a37d0dec50b39a29e232c6187ce4503703e8c2" dependencies = [ "equivalent", "hashbrown", @@ -2254,9 +2254,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e91a9c241fae207f533499d25bd2b22cee10f20b5e6aa0074dc4ebc2e23fe14" +checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" dependencies = [ "heck 0.4.1", "proc-macro2", diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 43aaa84e0..28f468ee2 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -509,7 +509,7 @@ impl ConfigFile for MiseToml { } fn remove_plugin(&mut self, fa: &ForgeArg) { - self.toolset.versions.remove(fa); + self.toolset.versions.shift_remove(fa); if let Some(tools) = self.doc.get_mut("tools") { if let Some(tools) = tools.as_table_like_mut() { tools.remove(&fa.to_string()); diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 37dde60f8..aeb09d267 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -160,7 +160,7 @@ impl ConfigFile for ToolVersions { } fn remove_plugin(&mut self, fa: &ForgeArg) { - self.plugins.remove(fa); + self.plugins.shift_remove(fa); } fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) { diff --git a/src/config/env_directive.rs b/src/config/env_directive.rs index 2b3908d7f..333705ee8 100644 --- a/src/config/env_directive.rs +++ b/src/config/env_directive.rs @@ -98,7 +98,7 @@ impl EnvResults { env.insert(k, (v, Some(source.clone()))); } EnvDirective::Rm(k) => { - env.remove(&k); + env.shift_remove(&k); r.env_remove.insert(k); } EnvDirective::Path(input) => { @@ -132,7 +132,7 @@ impl EnvResults { env.insert(k.clone(), (v.clone(), Some(source.clone()))); } EnvDiffOperation::Remove(k) => { - env.remove(&k); + env.shift_remove(&k); r.env_remove.insert(k); } } From 986aa0ccc3b4d6745b5fd3ba300353499785acac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 18:54:44 -0600 Subject: [PATCH 1708/1891] fix(deps): update rust crate indexmap to 2.2.0 (#1548) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dde9e3fd2..3d5ebe0cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ globwalk = "0.9.1" home = "0.5.9" humantime = "2.1.0" indenter = "0.3.3" -indexmap = { version = "2.1.0", features = ["serde"] } +indexmap = { version = "2.2.0", features = ["serde"] } indicatif = { version = "0.17.7", features = ["default", "improved_unicode"] } indoc = "2.0.4" itertools = "0.12.0" From 8d29b59fe6344dc129efb15149ceede40e5cb73c Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:47:48 -0600 Subject: [PATCH 1709/1891] hide system versions from env/bin_paths (#1553) Fixes #1549 --- .mise.toml | 14 ++++++++++++++ e2e/test_bin_paths | 7 +++++++ e2e/test_go | 4 ++++ justfile | 4 +++- src/plugins/core/deno.rs | 3 +++ src/plugins/core/go.rs | 5 ++++- src/toolset/mod.rs | 2 ++ 7 files changed, 37 insertions(+), 2 deletions(-) create mode 100755 e2e/test_bin_paths diff --git a/.mise.toml b/.mise.toml index 0dc687217..1c47d3a3e 100644 --- a/.mise.toml +++ b/.mise.toml @@ -92,3 +92,17 @@ run = "just lint-fix" [tasks.signal-test] run = "node ./test/fixtures/signal-test.js" + +[tasks."test:e2e"] +run = "just test-e2e" +# TODO: make this work when we have task args +#run = ''' +#set -euo pipefail +#TEST="$1" +#if [ "TEST" = all ]; then +# echo ./e2e/run_all_tests +#else +# FILES="$(fd TEST e2e/)" +# echo ./e2e/run_test "$FILES" +#fi +#''' diff --git a/e2e/test_bin_paths b/e2e/test_bin_paths new file mode 100755 index 000000000..f46b56441 --- /dev/null +++ b/e2e/test_bin_paths @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +# shellcheck source-path=SCRIPTDIR +source "$(dirname "$0")/assert.sh" + +mise use go@system +assert_not_contains "mise env -s bash" "go/system" diff --git a/e2e/test_go b/e2e/test_go index 8142df26d..f1c3d6ee6 100755 --- a/e2e/test_go +++ b/e2e/test_go @@ -15,3 +15,7 @@ assert_contains "mise x -- go version" "go version go1.20" rm "$MISE_GO_DEFAULT_PACKAGES_FILE" chmod -R u+w "$MISE_DATA_DIR/installs/go" + +assert_contains "mise env -s bash" "GOPATH" +mise use golang@system +assert_not_contains "mise env -s bash" "GOPATH" diff --git a/justfile b/justfile index 41f666e8d..775f89fd4 100644 --- a/justfile +++ b/justfile @@ -37,7 +37,9 @@ test-e2e TEST=("all"): build ./e2e/run_all_tests else FILES="$(fd {{ TEST }} e2e/)" - ./e2e/run_test "$FILES" + for FILE in $FILES; do + ./e2e/run_test "$FILE" + done fi # run unit tests w/ coverage diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index 79648b533..bed7bcc29 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -124,6 +124,9 @@ impl Forge for DenoPlugin { } fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { + if let ToolVersionRequest::System(_) = tv.request { + return Ok(vec![]); + } let bin_paths = vec![ tv.install_short_path().join("bin"), tv.install_short_path().join(".deno/bin"), diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 63291bb26..9352eb523 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -13,7 +13,7 @@ use crate::forge::Forge; use crate::http::HTTP; use crate::install_context::InstallContext; use crate::plugins::core::CorePlugin; -use crate::toolset::{ToolVersion, Toolset}; +use crate::toolset::{ToolVersion, ToolVersionRequest, Toolset}; use crate::ui::progress_report::SingleReport; use crate::{cmd, env, file, hash}; @@ -166,6 +166,9 @@ impl Forge for GoPlugin { } fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { + if let ToolVersionRequest::System(_) = tv.request { + return Ok(vec![]); + } // goroot/bin must always be included, irrespective of MISE_GO_SET_GOROOT let mut paths = vec![self.goroot(tv).join("bin")]; if *env::MISE_GO_SET_GOPATH != Some(false) { diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 1ba636118..9d940feef 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -293,6 +293,7 @@ impl Toolset { let entries = self .list_current_installed_versions() .into_par_iter() + .filter(|(_, tv)| !matches!(tv.request, ToolVersionRequest::System(_))) .flat_map(|(p, tv)| match p.exec_env(config, self, &tv) { Ok(env) => env.into_iter().collect(), Err(e) => { @@ -323,6 +324,7 @@ impl Toolset { pub fn list_paths(&self) -> Vec { self.list_current_installed_versions() .into_par_iter() + .filter(|(_, tv)| !matches!(tv.request, ToolVersionRequest::System(_))) .flat_map(|(p, tv)| { p.list_bin_paths(&tv).unwrap_or_else(|e| { warn!("Error listing bin paths for {tv}: {e:#}"); From 711d6d7ced808abd4e24b7dc5952085b9132047d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:48:13 -0600 Subject: [PATCH 1710/1891] codacy badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b077170a2..6e026df79 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Crates.io GitHub GitHub Workflow Status - + Discord

The front-end to your dev env. (formerly called "rtx")

From dc76ec4288d2b25c37eb2745028f6593c56facf7 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:50:38 -0600 Subject: [PATCH 1711/1891] codacy badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e026df79..02188e1dd 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Crates.io GitHub GitHub Workflow Status - +Codacy coverage (branch) Discord

The front-end to your dev env. (formerly called "rtx")

From 2e97b24540c3f020dbb2a650512dc97f78b3f6f1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:51:02 -0600 Subject: [PATCH 1712/1891] codacy badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02188e1dd..85162c693 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Crates.io GitHub GitHub Workflow Status -Codacy coverage (branch) +Codacy coverage (branch) Discord

The front-end to your dev env. (formerly called "rtx")

From 711110ca510228df421a584b11e7b62e8590be08 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:52:39 -0600 Subject: [PATCH 1713/1891] codacy badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85162c693..dca854352 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Crates.io GitHub GitHub Workflow Status -Codacy coverage (branch) +Codacy coverage (branch) Discord

The front-end to your dev env. (formerly called "rtx")

From 6a16dc0fe0beea743ed474eee7f29239887f418d Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Mon, 29 Jan 2024 21:40:36 -0500 Subject: [PATCH 1714/1891] feat(tasks): add task timing to run command (#1536) --- src/cli/run.rs | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index e768d363b..90e8292e1 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -107,6 +107,10 @@ pub struct Run { #[clap(long, short, verbatim_doc_comment)] pub raw: bool, + /// Shows elapsed time after each task + #[clap(long, alias = "timing", verbatim_doc_comment)] + pub timings: bool, + #[clap(skip)] pub is_linear: bool, } @@ -166,13 +170,17 @@ impl Run { env.insert("FORCE_COLOR".into(), "1".into()); } - let tasks = Mutex::new(Deps::new(config, tasks)?); - self.is_linear = tasks.lock().unwrap().is_linear(); - - for task in tasks.lock().unwrap().all() { + let tasks = Deps::new(config, tasks)?; + for task in tasks.all() { self.validate_task(task)?; } + let num_tasks = tasks.all().count(); + self.is_linear = tasks.is_linear(); + + let tasks = Mutex::new(tasks); + let timer = std::time::Instant::now(); + let pool = rayon::ThreadPoolBuilder::new() .num_threads(self.jobs() + 1) .build()?; @@ -195,6 +203,12 @@ impl Run { run(&task); } }); + + if self.timings && num_tasks > 1 { + let msg = format!("finished in {}", format_duration(timer.elapsed())); + info!("{}", style::edim(msg)); + }; + Ok(()) } @@ -211,6 +225,8 @@ impl Run { .map(|(k, v)| (k.clone(), v.clone())) .collect(); + let timer = std::time::Instant::now(); + if let Some(file) = &task.file { self.exec_file(file, task, &env, &prefix)?; } else { @@ -223,6 +239,14 @@ impl Run { } } + if self.timings { + miseprintln!( + "{} finished in {}", + prefix, + format_duration(timer.elapsed()) + ); + } + self.save_checksum(task)?; Ok(()) @@ -531,6 +555,15 @@ fn get_color() -> Color { static COLOR_IDX: AtomicUsize = AtomicUsize::new(0); COLORS[COLOR_IDX.fetch_add(1, Ordering::Relaxed) % COLORS.len()] } + +fn format_duration(dur: std::time::Duration) -> String { + if dur < std::time::Duration::from_secs(1) { + format!("{:.0?}", dur) + } else { + format!("{:.2?}", dur) + } +} + #[cfg(test)] mod tests { use crate::file; From 74fd1852bef8244f2cb4c51b58f11116d10d0c11 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 08:18:48 -0600 Subject: [PATCH 1715/1891] python: only show precompiled warning if going to use precompiled --- src/plugins/core/python.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index e680878e1..27c2e2c44 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -120,10 +120,6 @@ impl PythonPlugin { } fn install_precompiled(&self, ctx: &InstallContext) -> Result<()> { - warn!("installing precompiled python from indygreg/python-build-standalone"); - warn!("if you experience issues with this python, switch to python-build"); - warn!("by running: mise settings set python_compile 1"); - let precompile_info = self .fetch_precompiled_remote_versions()? .iter() @@ -133,6 +129,11 @@ impl PythonPlugin { Some((_, tag, filename)) => (tag, filename), None => return self.install_compiled(ctx), }; + + warn!("installing precompiled python from indygreg/python-build-standalone"); + warn!("if you experience issues with this python, switch to python-build"); + warn!("by running: mise settings set python_compile 1"); + let url = format!( "https://github.com/indygreg/python-build-standalone/releases/download/{tag}/{filename}" ); From 838bbaf61bd80e540146f3fe3f541dc9ae080aa1 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 08:22:03 -0600 Subject: [PATCH 1716/1891] fix bash not_found handler (#1558) * fix bash not_found handler Fixes #1557 Also refactored all the shell activate scripts * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- completions/_mise | 2 + completions/mise.bash | 4 +- completions/mise.fish | 2 + docs/cli-reference.md | 6 ++ src/cli/activate.rs | 47 ++++++++++--- src/shell/bash.rs | 52 +++++--------- src/shell/fish.rs | 46 ++++--------- src/shell/mod.rs | 26 +------ src/shell/nushell.rs | 34 ++++------ .../mise__shell__bash__tests__activate.snap | 3 +- ...ise__shell__bash__tests__activate_nix.snap | 53 --------------- ...mise__shell__bash__tests__prepend_env.snap | 6 ++ ...ise__shell__bash__tests__prepend_path.snap | 6 -- .../mise__shell__fish__tests__activate.snap | 1 - ...ise__shell__fish__tests__activate_nix.snap | 67 ------------------- ...mise__shell__fish__tests__prepend_env.snap | 6 ++ ...ise__shell__fish__tests__prepend_path.snap | 6 -- ...ise__shell__nushell__tests__hook_init.snap | 3 +- ..._shell__nushell__tests__hook_init_nix.snap | 60 ----------------- ...e__shell__nushell__tests__prepend_env.snap | 6 ++ .../mise__shell__xonsh__tests__hook_init.snap | 5 -- ...e__shell__xonsh__tests__hook_init_nix.snap | 12 ---- ...ise__shell__xonsh__tests__prepend_env.snap | 11 +++ .../mise__shell__zsh__tests__activate.snap | 1 - ...mise__shell__zsh__tests__activate_nix.snap | 57 ---------------- .../mise__shell__zsh__tests__prepend_env.snap | 6 ++ ...mise__shell__zsh__tests__prepend_path.snap | 6 -- src/shell/xonsh.rs | 48 ++++++------- src/shell/zsh.rs | 42 +++--------- 29 files changed, 161 insertions(+), 463 deletions(-) delete mode 100644 src/shell/snapshots/mise__shell__bash__tests__activate_nix.snap create mode 100644 src/shell/snapshots/mise__shell__bash__tests__prepend_env.snap delete mode 100644 src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap delete mode 100644 src/shell/snapshots/mise__shell__fish__tests__activate_nix.snap create mode 100644 src/shell/snapshots/mise__shell__fish__tests__prepend_env.snap delete mode 100644 src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap delete mode 100644 src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap create mode 100644 src/shell/snapshots/mise__shell__nushell__tests__prepend_env.snap delete mode 100644 src/shell/snapshots/mise__shell__xonsh__tests__hook_init_nix.snap create mode 100644 src/shell/snapshots/mise__shell__xonsh__tests__prepend_env.snap delete mode 100644 src/shell/snapshots/mise__shell__zsh__tests__activate_nix.snap create mode 100644 src/shell/snapshots/mise__shell__zsh__tests__prepend_env.snap delete mode 100644 src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap diff --git a/completions/_mise b/completions/_mise index 4cd5cefda..900dded64 100644 --- a/completions/_mise +++ b/completions/_mise @@ -584,6 +584,7 @@ __mise_run_cmd() { '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__mise_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ + '--timings[Shows elapsed time after each task]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' @@ -793,6 +794,7 @@ __mise_task_run_cmd() { '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__mise_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ + '--timings[Shows elapsed time after each task]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' diff --git a/completions/mise.bash b/completions/mise.bash index 69468517a..91db73afe 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -3738,7 +3738,7 @@ _mise() { return 0 ;; mise__run) - opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --quiet --trace --verbose --yes --help [TASK] [ARGS]..." + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --timings --debug --log-level --quiet --trace --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -4509,7 +4509,7 @@ _mise() { return 0 ;; mise__task__run) - opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --debug --log-level --quiet --trace --verbose --yes --help [TASK] [ARGS]..." + opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --timings --debug --log-level --quiet --trace --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/mise.fish b/completions/mise.fish index 5cf6c7fad..43e475315 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -226,6 +226,7 @@ complete -kxc mise -n "$fssf run" -s j -l jobs -d 'Number of tasks to run in par complete -kxc mise -n "$fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' complete -kxc mise -n "$fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' complete -kxc mise -n "$fssf run" -a "(__mise_tasks)" -d 'Task to run' +complete -kxc mise -n "$fssf run" -l timings -d 'Shows elapsed time after each task' complete -kxc mise -n "$fssf run" -s t -l tool -a "(__mise_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' # self-update @@ -310,6 +311,7 @@ complete -kxc mise -n "$fssf task; and $fssf run" -s j -l jobs -d 'Number of tas complete -kxc mise -n "$fssf task; and $fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' complete -kxc mise -n "$fssf task; and $fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' complete -kxc mise -n "$fssf task; and $fssf run" -a "(__mise_tasks)" -d 'Task to run' +complete -kxc mise -n "$fssf task; and $fssf run" -l timings -d 'Shows elapsed time after each task' complete -kxc mise -n "$fssf task; and $fssf run" -s t -l tool -a "(__mise_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' diff --git a/docs/cli-reference.md b/docs/cli-reference.md index c5af25a20..503db1a4a 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -936,6 +936,9 @@ Options: Read/write directly to stdin/stdout/stderr instead of by line Configure with `raw` config or `MISE_RAW` env var + --timings + Shows elapsed time after each task + Examples: $ mise run lint Runs the "lint" task. This needs to either be defined in .mise.toml @@ -1324,6 +1327,9 @@ Options: Read/write directly to stdin/stdout/stderr instead of by line Configure with `raw` config or `MISE_RAW` env var + --timings + Shows elapsed time after each task + Examples: $ mise run lint Runs the "lint" task. This needs to either be defined in .mise.toml diff --git a/src/cli/activate.rs b/src/cli/activate.rs index c510bcb6d..681445073 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -64,6 +64,21 @@ impl Activate { } else { env::MISE_BIN.clone() }; + match self.shims { + true => self.activate_shims(shell.as_ref(), &mise_bin), + false => self.activate(shell.as_ref(), &mise_bin), + } + + Ok(()) + } + + fn activate_shims(&self, shell: &dyn Shell, mise_bin: &Path) { + let exe_dir = mise_bin.parent().unwrap(); + miseprint!("{}", self.prepend_path(shell, exe_dir)); + miseprint!("{}", self.prepend_path(shell, &dirs::SHIMS)); + } + + fn activate(&self, shell: &dyn Shell, mise_bin: &Path) { let mut flags = vec![]; if self.quiet { flags.push(" --quiet"); @@ -71,21 +86,33 @@ impl Activate { if self.status { flags.push(" --status"); } - let output = match self.shims { - true => self.activate_shims(shell.as_ref(), &mise_bin), - false => shell.activate(&mise_bin, flags.join("")), - }; - miseprint!("{output}"); - - Ok(()) + miseprint!("{}", self.prepend_path(shell, mise_bin)); + miseprint!("{}", shell.activate(mise_bin, flags.join(""))); } - fn activate_shims(&self, shell: &dyn Shell, exe: &Path) -> String { - let exe_dir = exe.parent().unwrap().to_path_buf(); - shell.prepend_path(&[exe_dir, dirs::SHIMS.clone()]) + fn prepend_path(&self, shell: &dyn Shell, p: &Path) -> String { + if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { + shell.prepend_env("PATH", p.to_string_lossy().as_ref()) + } else { + String::new() + } } } +fn is_dir_in_path(dir: &Path) -> bool { + let dir = dir.canonicalize().unwrap_or(dir.to_path_buf()); + env::PATH + .clone() + .into_iter() + .any(|p| p.canonicalize().unwrap_or(p) == dir) +} + +fn is_dir_not_in_nix(dir: &Path) -> bool { + !dir.canonicalize() + .unwrap_or(dir.to_path_buf()) + .starts_with("/nix/") +} + static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ eval "$(mise activate bash)" diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 019d2c309..31b9d81d7 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -1,20 +1,16 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use crate::config::Settings; -use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; +use crate::shell::Shell; #[derive(Default)] pub struct Bash {} impl Shell for Bash { fn activate(&self, exe: &Path, flags: String) -> String { - let dir = exe.parent().unwrap(); + let settings = Settings::get(); let exe = exe.to_string_lossy(); - let mut out = String::new(); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { - out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); - } - out.push_str(&formatdoc! {r#" + let mut out = formatdoc! {r#" export MISE_SHELL=bash export __MISE_ORIG_PATH="$PATH" @@ -47,12 +43,12 @@ impl Shell for Bash { if [[ ";${{PROMPT_COMMAND:-}};" != *";_mise_hook;"* ]]; then PROMPT_COMMAND="_mise_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}" fi - "#}); - if Settings::get().not_found_auto_install { + "#}; + if settings.not_found_auto_install { out.push_str(&formatdoc! {r#" if [ -z "${{_mise_cmd_not_found:-}}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handler)" ] && eval "${{$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}}" + [ -n "$(declare -f command_not_found_handle)" ] && eval "${{$(declare -f command_not_found_handle)/command_not_found_handle/_command_not_found_handle}}" command_not_found_handle() {{ if {exe} hook-not-found -s bash -- "$1"; then @@ -82,19 +78,6 @@ impl Shell for Bash { "#} } - fn prepend_path(&self, paths: &[PathBuf]) -> String { - if paths.is_empty() { - return String::new(); - } - let mut path = String::new(); - for p in paths { - if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { - path = format!("{}:{path}", p.display()); - } - } - format!("export PATH=\"{}$PATH\"\n", path) - } - fn set_env(&self, k: &str, v: &str) -> String { let k = shell_escape::unix::escape(k.into()); let v = shell_escape::unix::escape(v.into()); @@ -102,6 +85,10 @@ impl Shell for Bash { format!("export {k}={v}\n") } + fn prepend_env(&self, k: &str, v: &str) -> String { + format!("export {k}=\"{v}:${k}\"\n") + } + fn unset_env(&self, k: &str) -> String { format!("unset {k}\n", k = shell_escape::unix::escape(k.into())) } @@ -109,7 +96,6 @@ impl Shell for Bash { #[cfg(test)] mod tests { - use std::path::PathBuf; use crate::test::replace_path; @@ -123,22 +109,14 @@ mod tests { } #[test] - fn test_activate_nix() { - let bash = Bash::default(); - let exe = Path::new("/nix/store/mise"); - assert_snapshot!(bash.activate(exe, " --status".into())); + fn test_set_env() { + assert_snapshot!(Bash::default().set_env("FOO", "1")); } #[test] - fn test_prepend_path() { + fn test_prepend_env() { let bash = Bash::default(); - let paths = vec![PathBuf::from("/some/dir"), PathBuf::from("/some/other/dir")]; - assert_snapshot!(replace_path(&bash.prepend_path(&paths))); - } - - #[test] - fn test_set_env() { - assert_snapshot!(Bash::default().set_env("FOO", "1")); + assert_snapshot!(replace_path(&bash.prepend_env("PATH", "/some/dir:/2/dir"))); } #[test] diff --git a/src/shell/fish.rs b/src/shell/fish.rs index 4b60c306d..e0d4ecc9b 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -1,22 +1,17 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use crate::config::Settings; -use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; +use crate::shell::Shell; #[derive(Default)] pub struct Fish {} impl Shell for Fish { fn activate(&self, exe: &Path, flags: String) -> String { - let dir = exe.parent().unwrap(); let exe = exe.to_string_lossy(); let description = "'Update mise environment when changing directories'"; let mut out = String::new(); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { - out.push_str(&format!("fish_add_path -g {dir}\n", dir = dir.display())); - } - // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_fish.go#L14-L36 out.push_str(&formatdoc! {r#" @@ -101,19 +96,6 @@ impl Shell for Fish { "#} } - fn prepend_path(&self, paths: &[PathBuf]) -> String { - if paths.is_empty() { - return String::new(); - } - let mut path = String::new(); - for p in paths { - if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { - path = format!("{} {path}", p.display()); - } - } - format!("set -gx PATH {path}$PATH\n") - } - fn set_env(&self, k: &str, v: &str) -> String { let k = shell_escape::unix::escape(k.into()); let v = shell_escape::unix::escape(v.into()); @@ -121,6 +103,12 @@ impl Shell for Fish { format!("set -gx {k} {v}\n") } + fn prepend_env(&self, k: &str, v: &str) -> String { + let k = shell_escape::unix::escape(k.into()); + let v = shell_escape::unix::escape(v.into()); + format!("set -gx {k} {v} ${k}\n") + } + fn unset_env(&self, k: &str) -> String { format!("set -e {k}\n", k = shell_escape::unix::escape(k.into())) } @@ -139,22 +127,14 @@ mod tests { } #[test] - fn test_activate_nix() { - let fish = Fish::default(); - let exe = Path::new("/nix/store/mise"); - assert_snapshot!(fish.activate(exe, " --status".into())); - } - - #[test] - fn test_prepend_path() { - let fish = Fish::default(); - let paths = vec![PathBuf::from("/some/dir"), PathBuf::from("/some/other/dir")]; - assert_snapshot!(fish.prepend_path(&paths)); + fn test_set_env() { + assert_snapshot!(Fish::default().set_env("FOO", "1")); } #[test] - fn test_set_env() { - assert_snapshot!(Fish::default().set_env("FOO", "1")); + fn test_prepend_env() { + let sh = Fish::default(); + assert_snapshot!(replace_path(&sh.prepend_env("PATH", "/some/dir:/2/dir"))); } #[test] diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 0da713fcb..fd7088131 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,5 +1,5 @@ use std::fmt::{Display, Formatter}; -use std::path::{Path, PathBuf}; +use std::path::Path; use crate::env; @@ -54,17 +54,9 @@ impl Display for ShellType { pub trait Shell { fn activate(&self, exe: &Path, flags: String) -> String; - fn prepend_path(&self, paths: &[PathBuf]) -> String { - let mut path = env::var("PATH").unwrap_or_default(); - for p in paths { - if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { - path = format!("{}:{path}", p.display()); - } - } - self.set_env("PATH", &path) - } fn deactivate(&self) -> String; fn set_env(&self, k: &str, v: &str) -> String; + fn prepend_env(&self, k: &str, v: &str) -> String; fn unset_env(&self, k: &str) -> String; } @@ -78,17 +70,3 @@ pub fn get_shell(shell: Option) -> Option> { _ => None, } } - -pub fn is_dir_in_path(dir: &Path) -> bool { - let dir = dir.canonicalize().unwrap_or(dir.to_path_buf()); - env::PATH - .clone() - .into_iter() - .any(|p| p.canonicalize().unwrap_or(p) == dir) -} - -pub fn is_dir_not_in_nix(dir: &Path) -> bool { - !dir.canonicalize() - .unwrap_or(dir.to_path_buf()) - .starts_with("/nix/") -} diff --git a/src/shell/nushell.rs b/src/shell/nushell.rs index d999782cf..fd4d7a84d 100644 --- a/src/shell/nushell.rs +++ b/src/shell/nushell.rs @@ -1,6 +1,6 @@ use std::{fmt::Display, path::Path}; -use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; +use crate::shell::Shell; #[derive(Default)] pub struct Nushell {} @@ -22,18 +22,9 @@ impl<'a> Display for EnvOp<'a> { impl Shell for Nushell { fn activate(&self, exe: &Path, flags: String) -> String { - let dir = exe.parent().unwrap(); let exe = exe.display(); - let mut out = String::new(); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { - out.push_str(&format!( - "$env.PATH = ($env.PATH | prepend '{}')\n", // TODO: set PATH as Path on windows - dir.display() - )); - } - - out.push_str(&formatdoc! {r#" + formatdoc! {r#" export-env {{ $env.MISE_SHELL = "nu" @@ -82,16 +73,14 @@ impl Shell for Nushell { }} }} }} - + def --env mise_hook [] {{ ^"{exe}" hook-env{flags} -s nu | parse vars | update-env }} - "#}); - - out + "#} } fn deactivate(&self) -> String { @@ -107,6 +96,10 @@ impl Shell for Nushell { EnvOp::Set { key: &k, val: &v }.to_string() } + fn prepend_env(&self, k: &str, v: &str) -> String { + format!("$env.{k} = ($env.{k} | prepend '{v}')\n") + } + fn unset_env(&self, k: &str) -> String { let k = shell_escape::unix::escape(k.into()); EnvOp::Hide { key: k.as_ref() }.to_string() @@ -126,15 +119,14 @@ mod tests { } #[test] - fn test_hook_init_nix() { - let nushell = Nushell::default(); - let exe = Path::new("/nix/store/mise"); - assert_snapshot!(nushell.activate(exe, " --status".into())); + fn test_set_env() { + assert_snapshot!(Nushell::default().set_env("FOO", "1")); } #[test] - fn test_set_env() { - assert_snapshot!(Nushell::default().set_env("FOO", "1")); + fn test_prepend_env() { + let sh = Nushell::default(); + assert_snapshot!(replace_path(&sh.prepend_env("PATH", "/some/dir:/2/dir"))); } #[test] diff --git a/src/shell/snapshots/mise__shell__bash__tests__activate.snap b/src/shell/snapshots/mise__shell__bash__tests__activate.snap index 842834622..7c5358764 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__activate.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__activate.snap @@ -2,7 +2,6 @@ source: src/shell/bash.rs expression: "bash.activate(exe, \" --status\".into())" --- -export PATH="/some/dir:$PATH" export MISE_SHELL=bash export __MISE_ORIG_PATH="$PATH" @@ -37,7 +36,7 @@ if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" + [ -n "$(declare -f command_not_found_handle)" ] && eval "${$(declare -f command_not_found_handle)/command_not_found_handle/_command_not_found_handle}" command_not_found_handle() { if /some/dir/mise hook-not-found -s bash -- "$1"; then diff --git a/src/shell/snapshots/mise__shell__bash__tests__activate_nix.snap b/src/shell/snapshots/mise__shell__bash__tests__activate_nix.snap deleted file mode 100644 index 7cfaeb956..000000000 --- a/src/shell/snapshots/mise__shell__bash__tests__activate_nix.snap +++ /dev/null @@ -1,53 +0,0 @@ ---- -source: src/shell/bash.rs -expression: "bash.activate(exe, \" --status\".into())" ---- -export MISE_SHELL=bash -export __MISE_ORIG_PATH="$PATH" - -mise() { - local command - command="${1:-}" - if [ "$#" = 0 ]; then - command /nix/store/mise - return - fi - shift - - case "$command" in - deactivate|s|shell) - # if argv doesn't contains -h,--help - if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command /nix/store/mise "$command" "$@")" - return $? - fi - ;; - esac - command /nix/store/mise "$command" "$@" -} - -_mise_hook() { - local previous_exit_status=$?; - eval "$(mise hook-env --status -s bash)"; - return $previous_exit_status; -}; -if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then - PROMPT_COMMAND="_mise_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}" -fi -if [ -z "${_mise_cmd_not_found:-}" ]; then - _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" - - command_not_found_handle() { - if /nix/store/mise hook-not-found -s bash -- "$1"; then - _mise_hook - "$@" - elif [ -n "$(declare -f _command_not_found_handle)" ]; then - _command_not_found_handle "$@" - else - echo "bash: command not found: $1" >&2 - return 127 - fi - } -fi - diff --git a/src/shell/snapshots/mise__shell__bash__tests__prepend_env.snap b/src/shell/snapshots/mise__shell__bash__tests__prepend_env.snap new file mode 100644 index 000000000..69b5f92c9 --- /dev/null +++ b/src/shell/snapshots/mise__shell__bash__tests__prepend_env.snap @@ -0,0 +1,6 @@ +--- +source: src/shell/bash.rs +expression: "replace_path(&bash.prepend_env(\"PATH\", \"/some/dir:/2/dir\"))" +--- +export PATH="/some/dir:/2/dir:$PATH" + diff --git a/src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap b/src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap deleted file mode 100644 index 5fc8af66f..000000000 --- a/src/shell/snapshots/mise__shell__bash__tests__prepend_path.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/shell/bash.rs -expression: replace_path(&bash.prepend_path(&paths)) ---- -export PATH="/some/other/dir:/some/dir:$PATH" - diff --git a/src/shell/snapshots/mise__shell__fish__tests__activate.snap b/src/shell/snapshots/mise__shell__fish__tests__activate.snap index 57d693103..abd81adee 100644 --- a/src/shell/snapshots/mise__shell__fish__tests__activate.snap +++ b/src/shell/snapshots/mise__shell__fish__tests__activate.snap @@ -2,7 +2,6 @@ source: src/shell/fish.rs expression: "fish.activate(exe, \" --status\".into())" --- -fish_add_path -g /some/dir set -gx MISE_SHELL fish set -gx __MISE_ORIG_PATH $PATH diff --git a/src/shell/snapshots/mise__shell__fish__tests__activate_nix.snap b/src/shell/snapshots/mise__shell__fish__tests__activate_nix.snap deleted file mode 100644 index d36277bb0..000000000 --- a/src/shell/snapshots/mise__shell__fish__tests__activate_nix.snap +++ /dev/null @@ -1,67 +0,0 @@ ---- -source: src/shell/fish.rs -expression: "fish.activate(exe, \" --status\".into())" ---- -set -gx MISE_SHELL fish -set -gx __MISE_ORIG_PATH $PATH - -function mise - if test (count $argv) -eq 0 - command /nix/store/mise - return - end - - set command $argv[1] - set -e argv[1] - - if contains -- --help $argv - command /nix/store/mise "$command" $argv - return $status - end - - switch "$command" - case deactivate s shell - # if help is requested, don't eval - if contains -- -h $argv - command /nix/store/mise "$command" $argv - else if contains -- --help $argv - command /nix/store/mise "$command" $argv - else - source (command /nix/store/mise "$command" $argv |psub) - end - case '*' - command /nix/store/mise "$command" $argv - end -end - -function __mise_env_eval --on-event fish_prompt --description 'Update mise environment when changing directories'; - /nix/store/mise hook-env --status -s fish | source; - - if test "$mise_fish_mode" != "disable_arrow"; - function __mise_cd_hook --on-variable PWD --description 'Update mise environment when changing directories'; - if test "$mise_fish_mode" = "eval_after_arrow"; - set -g __mise_env_again 0; - else; - /nix/store/mise hook-env --status -s fish | source; - end; - end; - end; -end; - -function __mise_env_eval_2 --on-event fish_preexec --description 'Update mise environment when changing directories'; - if set -q __mise_env_again; - set -e __mise_env_again; - /nix/store/mise hook-env --status -s fish | source; - echo; - end; - - functions --erase __mise_cd_hook; -end; -function fish_command_not_found - if /nix/store/mise hook-not-found -s fish -- $argv[1] - /nix/store/mise hook-env --status -s fish | source - else - __fish_default_command_not_found_handler $argv - end -end - diff --git a/src/shell/snapshots/mise__shell__fish__tests__prepend_env.snap b/src/shell/snapshots/mise__shell__fish__tests__prepend_env.snap new file mode 100644 index 000000000..fe31ade26 --- /dev/null +++ b/src/shell/snapshots/mise__shell__fish__tests__prepend_env.snap @@ -0,0 +1,6 @@ +--- +source: src/shell/fish.rs +expression: "replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\"))" +--- +set -gx PATH '/some/dir:/2/dir' $PATH + diff --git a/src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap b/src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap deleted file mode 100644 index cf85e58a2..000000000 --- a/src/shell/snapshots/mise__shell__fish__tests__prepend_path.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/shell/fish.rs -expression: fish.prepend_path(&paths) ---- -set -gx PATH /some/other/dir /some/dir $PATH - diff --git a/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap b/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap index 6fc7b41fc..e5dd743fd 100644 --- a/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__nushell__tests__hook_init.snap @@ -2,7 +2,6 @@ source: src/shell/nushell.rs expression: "nushell.activate(exe, \" --status\".into())" --- -$env.PATH = ($env.PATH | prepend '/some/dir') export-env { $env.MISE_SHELL = "nu" @@ -51,7 +50,7 @@ def --env "update-env" [] { } } } - + def --env mise_hook [] { ^"/some/dir/mise" hook-env --status -s nu | parse vars diff --git a/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap deleted file mode 100644 index f58c9c5d4..000000000 --- a/src/shell/snapshots/mise__shell__nushell__tests__hook_init_nix.snap +++ /dev/null @@ -1,60 +0,0 @@ ---- -source: src/shell/nushell.rs -expression: "nushell.activate(exe, \" --status\".into())" ---- -export-env { - $env.MISE_SHELL = "nu" - - $env.config = ($env.config | upsert hooks { - pre_prompt: ($env.config.hooks.pre_prompt ++ - [{ - condition: {|| "MISE_SHELL" in $env } - code: {|| mise_hook } - }]) - env_change: { - PWD: ($env.config.hooks.env_change.PWD ++ - [{ - condition: {|| "MISE_SHELL" in $env } - code: {|| mise_hook } - }]) - } - }) -} - -def "parse vars" [] { - $in | lines | parse "{op},{name},{value}" -} - -def --wrapped mise [command?: string, --help, ...rest: string] { - let commands = ["shell", "deactivate"] - - if ($command == null) { - ^"/nix/store/mise" - } else if ($command == "activate") { - $env.MISE_SHELL = "nu" - } else if ($command in $commands) { - ^"/nix/store/mise" $command ...$rest - | parse vars - | update-env - } else { - ^"/nix/store/mise" $command ...$rest - } -} - -def --env "update-env" [] { - for $var in $in { - if $var.op == "set" { - load-env {($var.name): $var.value} - } else if $var.op == "hide" { - hide-env $var.name - } - } -} - -def --env mise_hook [] { - ^"/nix/store/mise" hook-env --status -s nu - | parse vars - | update-env -} - - diff --git a/src/shell/snapshots/mise__shell__nushell__tests__prepend_env.snap b/src/shell/snapshots/mise__shell__nushell__tests__prepend_env.snap new file mode 100644 index 000000000..ab7e2e5d3 --- /dev/null +++ b/src/shell/snapshots/mise__shell__nushell__tests__prepend_env.snap @@ -0,0 +1,6 @@ +--- +source: src/shell/nushell.rs +expression: "replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\"))" +--- +$env.PATH = ($env.PATH | prepend '/some/dir:/2/dir') + diff --git a/src/shell/snapshots/mise__shell__xonsh__tests__hook_init.snap b/src/shell/snapshots/mise__shell__xonsh__tests__hook_init.snap index 5dd6b1782..6fbbfb20d 100644 --- a/src/shell/snapshots/mise__shell__xonsh__tests__hook_init.snap +++ b/src/shell/snapshots/mise__shell__xonsh__tests__hook_init.snap @@ -2,13 +2,8 @@ source: src/shell/xonsh.rs expression: "xonsh.activate(exe, \" --status\".into())" --- -from os import environ from xonsh.built_ins import XSH -envx = XSH.env -envx['PATH'].add('/some/dir') -environ['PATH'] = envx.get_detyped('PATH') - def listen_prompt(): # Hook Events execx($(/some/dir/mise hook-env --status -s xonsh)) diff --git a/src/shell/snapshots/mise__shell__xonsh__tests__hook_init_nix.snap b/src/shell/snapshots/mise__shell__xonsh__tests__hook_init_nix.snap deleted file mode 100644 index c0acff732..000000000 --- a/src/shell/snapshots/mise__shell__xonsh__tests__hook_init_nix.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: src/shell/xonsh.rs -expression: "xonsh.activate(exe, \" --status\".into())" ---- -from os import environ -from xonsh.built_ins import XSH - -def listen_prompt(): # Hook Events - execx($(/nix/store/mise hook-env --status -s xonsh)) - -XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt - diff --git a/src/shell/snapshots/mise__shell__xonsh__tests__prepend_env.snap b/src/shell/snapshots/mise__shell__xonsh__tests__prepend_env.snap new file mode 100644 index 000000000..754013d80 --- /dev/null +++ b/src/shell/snapshots/mise__shell__xonsh__tests__prepend_env.snap @@ -0,0 +1,11 @@ +--- +source: src/shell/xonsh.rs +expression: "replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\"))" +--- +from os import environ +from xonsh.built_ins import XSH + +envx = XSH.env +envx[ 'PATH'].add('/some/dir:/2/dir', front=True) +environ['PATH'] = envx.get_detyped('PATH') + diff --git a/src/shell/snapshots/mise__shell__zsh__tests__activate.snap b/src/shell/snapshots/mise__shell__zsh__tests__activate.snap index 0e0b046a7..2fc8d4e55 100644 --- a/src/shell/snapshots/mise__shell__zsh__tests__activate.snap +++ b/src/shell/snapshots/mise__shell__zsh__tests__activate.snap @@ -2,7 +2,6 @@ source: src/shell/zsh.rs expression: "zsh.activate(exe, \" --status\".into())" --- -export PATH="/some/dir:$PATH" export MISE_SHELL=zsh export __MISE_ORIG_PATH="$PATH" diff --git a/src/shell/snapshots/mise__shell__zsh__tests__activate_nix.snap b/src/shell/snapshots/mise__shell__zsh__tests__activate_nix.snap deleted file mode 100644 index 62bac1e7c..000000000 --- a/src/shell/snapshots/mise__shell__zsh__tests__activate_nix.snap +++ /dev/null @@ -1,57 +0,0 @@ ---- -source: src/shell/zsh.rs -expression: "zsh.activate(exe, \" --status\".into())" ---- -export MISE_SHELL=zsh -export __MISE_ORIG_PATH="$PATH" - -mise() { - local command - command="${1:-}" - if [ "$#" = 0 ]; then - command /nix/store/mise - return - fi - shift - - case "$command" in - deactivate|s|shell) - # if argv doesn't contains -h,--help - if [[ ! " $@ " =~ " --help " ]] && [[ ! " $@ " =~ " -h " ]]; then - eval "$(command /nix/store/mise "$command" "$@")" - return $? - fi - ;; - esac - command /nix/store/mise "$command" "$@" -} - -_mise_hook() { - eval "$(/nix/store/mise hook-env --status -s zsh)"; -} -typeset -ag precmd_functions; -if [[ -z "${precmd_functions[(r)_mise_hook]+1}" ]]; then - precmd_functions=( _mise_hook ${precmd_functions[@]} ) -fi -typeset -ag chpwd_functions; -if [[ -z "${chpwd_functions[(r)_mise_hook]+1}" ]]; then - chpwd_functions=( _mise_hook ${chpwd_functions[@]} ) -fi - -if [ -z "${_mise_cmd_not_found:-}" ]; then - _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handler)" ] && eval "${$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}" - - function command_not_found_handler() { - if /nix/store/mise hook-not-found -s zsh -- "$1"; then - _mise_hook - "$@" - elif [ -n "$(declare -f _command_not_found_handler)" ]; then - _command_not_found_handler "$@" - else - echo "zsh: command not found: $1" >&2 - return 127 - fi - } -fi - diff --git a/src/shell/snapshots/mise__shell__zsh__tests__prepend_env.snap b/src/shell/snapshots/mise__shell__zsh__tests__prepend_env.snap new file mode 100644 index 000000000..f6bd89771 --- /dev/null +++ b/src/shell/snapshots/mise__shell__zsh__tests__prepend_env.snap @@ -0,0 +1,6 @@ +--- +source: src/shell/zsh.rs +expression: "replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\"))" +--- +export PATH="/some/dir:/2/dir:$PATH" + diff --git a/src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap b/src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap deleted file mode 100644 index 6013a0e0b..000000000 --- a/src/shell/snapshots/mise__shell__zsh__tests__prepend_path.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/shell/zsh.rs -expression: "zsh.prepend_path(&[PathBuf::from(\"/some/dir\")])" ---- -export PATH="/some/dir:$PATH" - diff --git a/src/shell/xonsh.rs b/src/shell/xonsh.rs index 58fb921f5..a8a5401a7 100644 --- a/src/shell/xonsh.rs +++ b/src/shell/xonsh.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::path::Path; -use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; +use crate::shell::Shell; #[derive(Default)] pub struct Xonsh {} @@ -36,38 +36,21 @@ fn xonsh_escape_char(ch: char) -> Option<&'static str> { impl Shell for Xonsh { fn activate(&self, exe: &Path, flags: String) -> String { - let dir = exe.parent().unwrap(); let exe = exe.display(); - let mut out = String::new(); // todo: xonsh doesn't update the environment that mise relies on with $PATH.add even with $UPDATE_OS_ENVIRON (github.com/xonsh/xonsh/issues/3207) // with envx.swap(UPDATE_OS_ENVIRON=True): # ↠use when ↑ fixed before PATH.add; remove environ // meanwhile, save variables twice: in shell env + in os env // use xonsh API instead of $.xsh to allow use inside of .py configs, which start faster due to being compiled to .pyc - out.push_str(&formatdoc! {r#" - from os import environ + // todo: subprocess instead of $() is a bit faster, but lose auto-color detection (use $FORCE_COLOR) + formatdoc! {r#" from xonsh.built_ins import XSH - "#}); - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { - let dir_str = dir.to_string_lossy(); - let dir_esc = xonsh_escape_sq(&dir_str); - out.push_str(&formatdoc! {r#" - envx = XSH.env - envx['PATH'].add('{dir_esc}') - environ['PATH'] = envx.get_detyped('PATH') - - "#}); - } - // todo: subprocess instead of $() is a bit faster, but lose auto-color detection (use $FORCE_COLOR) - out.push_str(&formatdoc! {r#" def listen_prompt(): # Hook Events execx($({exe} hook-env{flags} -s xonsh)) XSH.builtins.events.on_pre_prompt(listen_prompt) # Activate hook: before showing the prompt - "#}); - - out + "#} } fn deactivate(&self) -> String { @@ -104,6 +87,18 @@ impl Shell for Xonsh { ) } + fn prepend_env(&self, k: &str, v: &str) -> String { + let v = xonsh_escape_sq(v); + formatdoc! {r#" + from os import environ + from xonsh.built_ins import XSH + + envx = XSH.env + envx[ '{k}'].add('{v}', front=True) + environ['{k}'] = envx.get_detyped('{k}') + "#} + } + fn unset_env(&self, k: &str) -> String { formatdoc!( r#" @@ -132,15 +127,14 @@ mod tests { } #[test] - fn test_hook_init_nix() { - let xonsh = Xonsh::default(); - let exe = Path::new("/nix/store/mise"); - insta::assert_snapshot!(xonsh.activate(exe, " --status".into())); + fn test_set_env() { + insta::assert_snapshot!(Xonsh::default().set_env("FOO", "1")); } #[test] - fn test_set_env() { - insta::assert_snapshot!(Xonsh::default().set_env("FOO", "1")); + fn test_prepend_env() { + let sh = Xonsh::default(); + assert_snapshot!(replace_path(&sh.prepend_env("PATH", "/some/dir:/2/dir"))); } #[test] diff --git a/src/shell/zsh.rs b/src/shell/zsh.rs index c75769503..fdb8879fd 100644 --- a/src/shell/zsh.rs +++ b/src/shell/zsh.rs @@ -1,23 +1,19 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use crate::config::Settings; use crate::shell::bash::Bash; -use crate::shell::{is_dir_in_path, is_dir_not_in_nix, Shell}; +use crate::shell::Shell; #[derive(Default)] pub struct Zsh {} impl Shell for Zsh { fn activate(&self, exe: &Path, flags: String) -> String { - let dir = exe.parent().unwrap(); let exe = exe.to_string_lossy(); let mut out = String::new(); // much of this is from direnv // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_zsh.go#L10-L22 - if is_dir_not_in_nix(dir) && !is_dir_in_path(dir) && !dir.is_relative() { - out.push_str(&format!("export PATH=\"{}:$PATH\"\n", dir.display())); - } out.push_str(&formatdoc! {r#" export MISE_SHELL=zsh export __MISE_ORIG_PATH="$PATH" @@ -90,23 +86,14 @@ impl Shell for Zsh { "#} } - fn prepend_path(&self, paths: &[PathBuf]) -> String { - if paths.is_empty() { - return String::new(); - } - let mut path = String::new(); - for p in paths { - if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() { - path = format!("{}:{path}", p.display()); - } - } - format!("export PATH=\"{path}$PATH\"\n") - } - fn set_env(&self, k: &str, v: &str) -> String { Bash::default().set_env(k, v) } + fn prepend_env(&self, k: &str, v: &str) -> String { + format!("export {k}=\"{v}:${k}\"\n") + } + fn unset_env(&self, k: &str) -> String { Bash::default().unset_env(k) } @@ -125,21 +112,14 @@ mod tests { } #[test] - fn test_activate_nix() { - let zsh = Zsh::default(); - let exe = Path::new("/nix/store/mise"); - assert_snapshot!(zsh.activate(exe, " --status".into())); - } - - #[test] - fn test_prepend_path() { - let zsh = Zsh::default(); - assert_snapshot!(zsh.prepend_path(&[PathBuf::from("/some/dir")])); + fn test_set_env() { + assert_snapshot!(Zsh::default().set_env("FOO", "1")); } #[test] - fn test_set_env() { - assert_snapshot!(Zsh::default().set_env("FOO", "1")); + fn test_prepend_env() { + let sh = Bash::default(); + assert_snapshot!(replace_path(&sh.prepend_env("PATH", "/some/dir:/2/dir"))); } #[test] From d885c6693f1a6fd4260a6a4313396cd953d9da80 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 09:01:21 -0600 Subject: [PATCH 1717/1891] python: fix linux precompiled (#1559) --- src/plugins/core/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 27c2e2c44..dc6f2a215 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -369,7 +369,7 @@ fn python_arch(settings: &Settings) -> &str { } else if cfg!(target_feature = "sse4.1") { "x86_64_v2" } else { - "x86_64_v1" + "x86_64" } } else { built_info::CFG_TARGET_ARCH From 2660406a4744e789ab39a58e1732f880dcd26b4d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 09:01:47 -0600 Subject: [PATCH 1718/1891] go: clean up e2e tests --- .../rtx-direnv-break-path-source/.envrc | 1 - .../rtx-direnv-break-path-target/.envrc | 1 - e2e/direnv/no_tool_versions/test_direnv | 26 ------------------- e2e/gopath/.e2e-tool-versions | 2 +- e2e/gopath/18/.e2e-tool-versions | 1 - e2e/gopath/21/.e2e-tool-versions | 1 + e2e/gopath/test_gopath | 13 ++++++---- src/cli/activate.rs | 3 ++- 8 files changed, 12 insertions(+), 36 deletions(-) delete mode 100644 e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc delete mode 100644 e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc delete mode 100755 e2e/direnv/no_tool_versions/test_direnv delete mode 100644 e2e/gopath/18/.e2e-tool-versions create mode 100644 e2e/gopath/21/.e2e-tool-versions diff --git a/e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc b/e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc deleted file mode 100644 index c78c44709..000000000 --- a/e2e/direnv/no_tool_versions/rtx-direnv-break-path-source/.envrc +++ /dev/null @@ -1 +0,0 @@ -export FOO=foo diff --git a/e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc b/e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc deleted file mode 100644 index 29bcb5abe..000000000 --- a/e2e/direnv/no_tool_versions/rtx-direnv-break-path-target/.envrc +++ /dev/null @@ -1 +0,0 @@ -export FOO=bar diff --git a/e2e/direnv/no_tool_versions/test_direnv b/e2e/direnv/no_tool_versions/test_direnv deleted file mode 100755 index 03b308cd4..000000000 --- a/e2e/direnv/no_tool_versions/test_direnv +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env zsh -set -e - -export MISE_EXPERIMENTAL=1 - -eval "$(direnv hook zsh)" -eval "$(mise activate zsh --status)" -_mise_hook && direnv allow && _direnv_hook - -assert_go_version() { - local expected="$1" - if [[ "$GOPATH" != "$expected" ]]; then - echo "Invalid GOPATH: $GOPATH, expected: $expected" - exit 1 - fi -} - -mise i golang@1.18.10 golang@1.19.5 && _mise_hook -#assert_gopath "$MISE_DATA_DIR/installs/golang/1.19.5/packages" -cd mise-direnv-break-path-source && _mise_hook -direnv allow && _direnv_hook -#assert_gopath "$MISE_DATA_DIR/installs/golang/1.18.10/packages" -cd ../mise-direnv-break-path-target && _mise_hook -direnv allow && _direnv_hook -#assert_gopath "$MISE_DATA_DIR/installs/golang/1.19.5/packages" -mise -v # should not fail, the bug is that PATH gets set to a junk value and this does not work diff --git a/e2e/gopath/.e2e-tool-versions b/e2e/gopath/.e2e-tool-versions index 58b446162..f3ab91414 100644 --- a/e2e/gopath/.e2e-tool-versions +++ b/e2e/gopath/.e2e-tool-versions @@ -1 +1 @@ -golang 1.19.5 +golang 1.20 diff --git a/e2e/gopath/18/.e2e-tool-versions b/e2e/gopath/18/.e2e-tool-versions deleted file mode 100644 index bb46032ec..000000000 --- a/e2e/gopath/18/.e2e-tool-versions +++ /dev/null @@ -1 +0,0 @@ -golang 1.18.10 diff --git a/e2e/gopath/21/.e2e-tool-versions b/e2e/gopath/21/.e2e-tool-versions new file mode 100644 index 000000000..463dd7764 --- /dev/null +++ b/e2e/gopath/21/.e2e-tool-versions @@ -0,0 +1 @@ +golang 1.21 diff --git a/e2e/gopath/test_gopath b/e2e/gopath/test_gopath index 2636ce527..c8bce2a7d 100755 --- a/e2e/gopath/test_gopath +++ b/e2e/gopath/test_gopath @@ -14,9 +14,12 @@ assert_gopath() { fi } -mise i golang@1.18.10 golang@1.19.5 && _mise_hook -assert_gopath "$MISE_DATA_DIR/installs/go/1.19.5/packages" -cd 18 && _mise_hook -assert_gopath "$MISE_DATA_DIR/installs/go/1.18.10/packages" +GO_20=$(mise latest golang@1.20) +GO_21=$(mise latest golang@1.21) + +mise i golang@1.20 golang@1.21 && _mise_hook +assert_gopath "$MISE_DATA_DIR/installs/go/$GO_20/packages" +cd 21 && _mise_hook +assert_gopath "$MISE_DATA_DIR/installs/go/$GO_21/packages" cd .. && _mise_hook -assert_gopath "$MISE_DATA_DIR/installs/go/1.19.5/packages" +assert_gopath "$MISE_DATA_DIR/installs/go/$GO_20/packages" diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 681445073..774908a39 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -79,6 +79,7 @@ impl Activate { } fn activate(&self, shell: &dyn Shell, mise_bin: &Path) { + let exe_dir = mise_bin.parent().unwrap(); let mut flags = vec![]; if self.quiet { flags.push(" --quiet"); @@ -86,7 +87,7 @@ impl Activate { if self.status { flags.push(" --status"); } - miseprint!("{}", self.prepend_path(shell, mise_bin)); + miseprint!("{}", self.prepend_path(shell, exe_dir)); miseprint!("{}", shell.activate(mise_bin, flags.join(""))); } From a67c00fc8e6ad94782e361317809ecbdb8474b71 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 09:08:01 -0600 Subject: [PATCH 1719/1891] chore: Release mise version 2024.1.31 --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48324fe9b..773141ef1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" [[package]] name = "anstyle-parse" @@ -304,9 +304,9 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clap_mangen" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a7c2b01e5e779c19f46a94bbd398f33ae63b0f78c07108351fb4536845bb7fd" +checksum = "43144ab702c764b0a3ecda5ecd2aba2e6874d8de4b9f56930bbb1e88fcecd84a" dependencies = [ "clap", "roff", @@ -1107,9 +1107,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2a4f498956c7723dc280afc6a37d0dec50b39a29e232c6187ce4503703e8c2" +checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" dependencies = [ "equivalent", "hashbrown", @@ -1168,9 +1168,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.30" +version = "2024.1.31" dependencies = [ "base64", "built", @@ -2084,9 +2084,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.112" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 3d5ebe0cb..713bf9f84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.30" +version = "2024.1.31" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index dca854352..9215c469a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.30 +mise 2024.1.31 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 7904db99e..e77b8d18b 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.30"; + version = "2024.1.31"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 5adba7c11..b6f773e6f 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.30 +Version: 2024.1.31 Release: 1 URL: https://github.com/jdx/mise/ Group: System From f68bf520fd726544bfbc09ce8fd1035ffc0d7e20 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:00:03 -0600 Subject: [PATCH 1720/1891] added "plugins up" alias" --- completions/_mise | 4 ++-- completions/mise.bash | 3 +++ docs/cli-reference.md | 2 +- man/man1/mise.1 | 4 ++-- src/cli/plugins/update.rs | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/completions/_mise b/completions/_mise index 900dded64..1cdb6f46a 100644 --- a/completions/_mise +++ b/completions/_mise @@ -481,7 +481,7 @@ __mise_plugins_cmd() { (list|ls) __mise_plugins_ls_cmd && ret=0 ;; (list-all|list-remote|ls-remote) __mise_plugins_ls_remote_cmd && ret=0 ;; (remove|rm|uninstall) __mise_plugins_uninstall_cmd && ret=0 ;; - (upgrade|update) __mise_plugins_update_cmd && ret=0 ;; + (up|upgrade|update) __mise_plugins_update_cmd && ret=0 ;; esac ;; esac @@ -987,7 +987,7 @@ __mise_plugins_cmds() { {list,ls}':List installed plugins' {list-all,list-remote,ls-remote}':List all available remote plugins' {remove,rm,uninstall}':Removes a plugin' - {upgrade,update}':Updates a plugin to the latest version' + {up,upgrade,update}':Updates a plugin to the latest version' ) _describe -t commands 'command' commands "$@" } diff --git a/completions/mise.bash b/completions/mise.bash index 91db73afe..fe9cb5c71 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -576,6 +576,9 @@ _mise() { mise__plugins,uninstall) cmd="mise__plugins__uninstall" ;; + mise__plugins,up) + cmd="mise__plugins__update" + ;; mise__plugins,update) cmd="mise__plugins__update" ;; diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 503db1a4a..fb5ca697a 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -782,7 +782,7 @@ Examples: ## `mise plugins update [OPTIONS] [PLUGIN]...` -**Aliases:** `upgrade` +**Aliases:** `up, upgrade` ```text Updates a plugin to the latest version diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 213a3d7a9..92392e2fe 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.30" +.TH mise 1 "mise 2024.1.31" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.30 +v2024.1.31 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 9fa6c6511..d68c47266 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -10,7 +10,7 @@ use crate::ui::multi_progress_report::MultiProgressReport; /// /// note: this updates the plugin itself, not the runtime versions #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, visible_alias = "upgrade", after_long_help = AFTER_LONG_HELP)] +#[clap(verbatim_doc_comment, visible_aliases = ["up", "upgrade"], after_long_help = AFTER_LONG_HELP)] pub struct Update { /// Plugin(s) to update #[clap()] From b122c19935297a3220c438607798fc7fe52df1c1 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:01:00 -0600 Subject: [PATCH 1721/1891] python: fix settings env vars --- src/config/settings.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/settings.rs b/src/config/settings.rs index f8e379311..e574aea01 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -65,11 +65,11 @@ pub struct Settings { #[config(env = "MISE_PYTHON_PATCH_URL")] pub python_patch_url: Option, #[config(env = "MISE_PYTHON_PATCHES_DIRECTORY")] - pub python_precompiled_os: Option, - #[config(env = "MISE_PYTHON_PRECOMPILED_ARCH")] pub python_patches_directory: Option, - #[config(env = "MISE_PYTHON_PRECOMPILED_OS")] + #[config(env = "MISE_PYTHON_PRECOMPILED_ARCH")] pub python_precompiled_arch: Option, + #[config(env = "MISE_PYTHON_PRECOMPILED_OS")] + pub python_precompiled_os: Option, #[config( env = "MISE_PYENV_REPO", default = "https://github.com/pyenv/pyenv.git" From d3020cc26575864a38dbffd530ad1f7ebff64f64 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:20:53 -0600 Subject: [PATCH 1722/1891] poetry: use compiled python --- e2e/test_poetry | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/test_poetry b/e2e/test_poetry index 8b600ed00..b38731ece 100755 --- a/e2e/test_poetry +++ b/e2e/test_poetry @@ -18,7 +18,8 @@ cat >.e2e.mise.toml < Date: Tue, 30 Jan 2024 11:23:25 -0600 Subject: [PATCH 1723/1891] chore: Release mise version 2024.1.32 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- packaging/rpm/mise.spec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 773141ef1..e46ab3e21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.31" +version = "2024.1.32" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 713bf9f84..6151eb209 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.31" +version = "2024.1.32" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 9215c469a..c2b5a1967 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.31 +mise 2024.1.32 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index e77b8d18b..066ab63b5 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.31"; + version = "2024.1.32"; src = lib.cleanSource ./.; diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index b6f773e6f..9c5662353 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.31 +Version: 2024.1.32 Release: 1 URL: https://github.com/jdx/mise/ Group: System From fae51a7ef38890fbf3f864957e0c0c6f1be0cf65 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:05:29 -0600 Subject: [PATCH 1724/1891] shims: treat anything not rtx/mise as a shim This can break if the env gets dropped. In that situation, the shim should fall back to the system version --- src/shims.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims.rs b/src/shims.rs index 63dacea3e..3c0c63a6b 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -24,7 +24,7 @@ use crate::{fake_asdf, forge}; pub fn handle_shim() -> Result<()> { // TODO: instead, check if bin is in shims dir let bin_name = *env::MISE_BIN_NAME; - if bin_name == "mise" || !dirs::SHIMS.join(bin_name).exists() || cfg!(test) { + if bin_name == "mise" || bin_name == "rtx" || cfg!(test) { return Ok(()); } logger::init(); From 1e3afe90b9f61fd61585ecf31ef9f79a7df8e682 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:11:59 -0600 Subject: [PATCH 1725/1891] chore: Release mise version 2024.1.33 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e46ab3e21..fba6a9a66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.32" +version = "2024.1.33" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index 6151eb209..7457884de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.32" +version = "2024.1.33" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index c2b5a1967..460e886d0 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.32 +mise 2024.1.33 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 066ab63b5..8f7175a40 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.32"; + version = "2024.1.33"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 92392e2fe..13dd9fe5e 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.31" +.TH mise 1 "mise 2024.1.32" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.31 +v2024.1.32 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 9c5662353..05ba59231 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.32 +Version: 2024.1.33 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 3ca3f7eb5fa72b08938262b9665fabc2db650f28 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 18:46:13 -0600 Subject: [PATCH 1726/1891] build on macos-latest --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28704cbe4..79c89a7a3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,11 +58,11 @@ jobs: - os: macos name: macos-x64 target: x86_64-apple-darwin - runs-on: macos-12 + runs-on: macos-latest - os: macos name: macos-arm64 target: aarch64-apple-darwin - runs-on: macos-12 + runs-on: macos-latest # - os: macos # name: macos # target: universal2-apple-darwin From 7f900c4326ac50ca2773d320e7bd9b2790063b63 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 30 Jan 2024 22:44:24 -0600 Subject: [PATCH 1727/1891] removed outdated conditional --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 218d9bfd0..263d510f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,6 @@ jobs: - run: cargo msrv verify - run: cargo machete --with-metadata - run: ./scripts/test-standalone.sh - if: github.ref_name != 'mise' - run: just render-all lint-fix - run: git diff HEAD - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'jdx/mise' From 2840fc815826f32c22d41e43fb8cad17d28a89ce Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 07:22:23 -0600 Subject: [PATCH 1728/1891] fix bash command not found override (#1564) Fixes #1558 Fixes #1563 --- man/man1/mise.1 | 4 ++-- src/shell/bash.rs | 5 ++++- src/shell/snapshots/mise__shell__bash__tests__activate.snap | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 13dd9fe5e..47519abc3 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.32" +.TH mise 1 "mise 2024.1.33" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.32 +v2024.1.33 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/src/shell/bash.rs b/src/shell/bash.rs index 31b9d81d7..daead224d 100644 --- a/src/shell/bash.rs +++ b/src/shell/bash.rs @@ -48,7 +48,10 @@ impl Shell for Bash { out.push_str(&formatdoc! {r#" if [ -z "${{_mise_cmd_not_found:-}}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handle)" ] && eval "${{$(declare -f command_not_found_handle)/command_not_found_handle/_command_not_found_handle}}" + if [ -n "$(declare -f command_not_found_handle)" ]; then + _mise_cmd_not_found_handle=$(declare -f command_not_found_handle) + eval "${{_mise_cmd_not_found_handle/command_not_found_handle/_command_not_found_handle}}" + fi command_not_found_handle() {{ if {exe} hook-not-found -s bash -- "$1"; then diff --git a/src/shell/snapshots/mise__shell__bash__tests__activate.snap b/src/shell/snapshots/mise__shell__bash__tests__activate.snap index 7c5358764..ff812aa65 100644 --- a/src/shell/snapshots/mise__shell__bash__tests__activate.snap +++ b/src/shell/snapshots/mise__shell__bash__tests__activate.snap @@ -36,7 +36,10 @@ if [[ ";${PROMPT_COMMAND:-};" != *";_mise_hook;"* ]]; then fi if [ -z "${_mise_cmd_not_found:-}" ]; then _mise_cmd_not_found=1 - [ -n "$(declare -f command_not_found_handle)" ] && eval "${$(declare -f command_not_found_handle)/command_not_found_handle/_command_not_found_handle}" + if [ -n "$(declare -f command_not_found_handle)" ]; then + _mise_cmd_not_found_handle=$(declare -f command_not_found_handle) + eval "${_mise_cmd_not_found_handle/command_not_found_handle/_command_not_found_handle}" + fi command_not_found_handle() { if /some/dir/mise hook-not-found -s bash -- "$1"; then From 56be60f2dee9398b181f83965d3a1caa8efe7b16 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 07:23:09 -0600 Subject: [PATCH 1729/1891] update CONTRIBUTING.md --- CONTRIBUTING.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e000b0989..37d463dce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,31 @@ To use the container with VSCode, you'll need to install the [Remote - Container (you'd think we'd use mise to fetch these but frankly it's kind of a pain to dogfood mise while testing it) -## Just +## Tasks + +Mise uses mise itself to run tasks. See available tasks with `mise tasks`: + +```shell +~/src/mise ❯ mise tasks +build ~/src/mise/.mise.toml +clean ~/src/mise/.mise.toml +format ~/src/mise/.mise.toml +lint ~/src/mise/.mise/config.toml +lint-fix ~/src/mise/.mise.toml +release ~/src/mise/.mise.toml +render-all ~/src/mise/.mise.toml +render-completions ~/src/mise/.mise.toml +render-help ~/src/mise/.mise.toml +render-mangen ~/src/mise/.mise.toml +signal-test ~/src/mise/.mise.toml +snapshots Update test snapshots ~/src/mise/.mise.toml +test ~/src/mise/.mise.toml +test:e2e ~/src/mise/.mise.toml +``` + +## [deprecated] Just + +Note: these tasks are being moved over to `mise run` tasks but not all of them have been migrated yet. Just should be used for just about every task. Here is a full list of its tasks: From 0e3847791d59df8eb36249ff8faf2eb13c287aa3 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 07:46:08 -0600 Subject: [PATCH 1730/1891] label experimental error --- src/cli/config/generate.rs | 2 +- src/cli/config/ls.rs | 2 +- src/cli/run.rs | 2 +- src/cli/task/deps.rs | 2 +- src/cli/task/edit.rs | 2 +- src/cli/task/ls.rs | 2 +- src/cli/watch.rs | 2 +- src/config/env_directive.rs | 2 +- src/config/settings.rs | 8 ++++---- src/forge/cargo.rs | 2 +- src/forge/go.rs | 2 +- src/forge/npm.rs | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index bd0b34135..d0148297f 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -20,7 +20,7 @@ impl ConfigGenerate { pub fn run(self) -> Result<()> { let _ = Config::try_get()?; let settings = Settings::try_get()?; - settings.ensure_experimental()?; + settings.ensure_experimental("`mise config generate`")?; let doc = r#" # # mise config files are hierarchical. mise will find all of the config files # # in all parent directories and merge them together. diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index 39f887c87..bdc4cc943 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -23,7 +23,7 @@ impl ConfigLs { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; - settings.ensure_experimental()?; + settings.ensure_experimental("`mise config ls`")?; let rows = config .config_files .values() diff --git a/src/cli/run.rs b/src/cli/run.rs index 90e8292e1..9ad4a6b30 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -119,7 +119,7 @@ impl Run { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; - settings.ensure_experimental()?; + settings.ensure_experimental("`mise run`")?; let task_list = self.get_task_lists(&config)?; self.parallelize_tasks(&config, task_list) } diff --git a/src/cli/task/deps.rs b/src/cli/task/deps.rs index fb415e086..809aff375 100644 --- a/src/cli/task/deps.rs +++ b/src/cli/task/deps.rs @@ -27,7 +27,7 @@ impl TaskDeps { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; - settings.ensure_experimental()?; + settings.ensure_experimental("`mise tasks deps`")?; let tasks = if self.tasks.is_none() { self.get_all_tasks(&config)? diff --git a/src/cli/task/edit.rs b/src/cli/task/edit.rs index e1608d4a0..fe82761e9 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/task/edit.rs @@ -23,7 +23,7 @@ impl TaskEdit { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; - settings.ensure_experimental()?; + settings.ensure_experimental("`mise tasks edit`")?; let task = config .tasks_with_aliases() diff --git a/src/cli/task/ls.rs b/src/cli/task/ls.rs index aabd1ed22..aed980aa1 100644 --- a/src/cli/task/ls.rs +++ b/src/cli/task/ls.rs @@ -31,7 +31,7 @@ impl TaskLs { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; - settings.ensure_experimental()?; + settings.ensure_experimental("`mise task ls`")?; let rows = config .tasks() .iter() diff --git a/src/cli/watch.rs b/src/cli/watch.rs index 91d0bc87f..b1e7abe2c 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -70,7 +70,7 @@ impl Watch { let config = Config::try_get()?; let settings = Settings::try_get()?; let ts = ToolsetBuilder::new().build(&config)?; - settings.ensure_experimental()?; + settings.ensure_experimental("`mise watch`")?; if let Err(err) = which::which("watchexec") { let watchexec: ForgeArg = "watchexec".parse()?; if !ts.versions.contains_key(&watchexec) { diff --git a/src/config/env_directive.rs b/src/config/env_directive.rs index 333705ee8..6dca0160e 100644 --- a/src/config/env_directive.rs +++ b/src/config/env_directive.rs @@ -119,7 +119,7 @@ impl EnvResults { } } EnvDirective::Source(input) => { - settings.ensure_experimental()?; + settings.ensure_experimental("env._.source")?; trust_check(&source)?; let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; let p = normalize_path(s); diff --git a/src/config/settings.rs b/src/config/settings.rs index e574aea01..f4513c571 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -316,10 +316,10 @@ impl Settings { *SETTINGS.write().unwrap() = None; } - pub fn ensure_experimental(&self) -> Result<()> { - let msg = - "This command is experimental. Enable it with `mise settings set experimental true`"; - ensure!(self.experimental, msg); + pub fn ensure_experimental(&self, what: &str) -> Result<()> { + if !self.experimental { + bail!("{what} is experimental. Enable it with `mise settings set experimental true`"); + } Ok(()) } diff --git a/src/forge/cargo.rs b/src/forge/cargo.rs index 30f97901a..6e1721e81 100644 --- a/src/forge/cargo.rs +++ b/src/forge/cargo.rs @@ -47,7 +47,7 @@ impl Forge for CargoForge { fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { let config = Config::try_get()?; let settings = Settings::get(); - settings.ensure_experimental()?; + settings.ensure_experimental("cargo backend")?; let cmd = match settings.cargo_binstall { true if file::which_non_pristine("cargo-binstall").is_some() => { CmdLineRunner::new("cargo-binstall").arg("-y") diff --git a/src/forge/go.rs b/src/forge/go.rs index f412c9021..3c4218c80 100644 --- a/src/forge/go.rs +++ b/src/forge/go.rs @@ -36,7 +36,7 @@ impl Forge for GoForge { fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { let config = Config::try_get()?; let settings = Settings::get(); - settings.ensure_experimental()?; + settings.ensure_experimental("go backend")?; CmdLineRunner::new("go") .arg("install") diff --git a/src/forge/npm.rs b/src/forge/npm.rs index e2e21fcc9..033e66a4a 100644 --- a/src/forge/npm.rs +++ b/src/forge/npm.rs @@ -36,7 +36,7 @@ impl Forge for NPMForge { fn install_version_impl(&self, ctx: &InstallContext) -> eyre::Result<()> { let config = Config::try_get()?; let settings = Settings::get(); - settings.ensure_experimental()?; + settings.ensure_experimental("npm backend")?; CmdLineRunner::new("npm") .arg("install") From e9b036e3baef0f83bdf142fe7228917a00f715e9 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:13:50 -0600 Subject: [PATCH 1731/1891] convert more things to mise tasks from just (#1566) --- .github/workflows/test.yml | 7 +++++-- .mise.toml | 26 +++++++++++-------------- CONTRIBUTING.md | 17 +++-------------- Cargo.lock | 31 ++++++++++++++++++++++++++++++ Cargo.toml | 1 + justfile | 31 +++--------------------------- scripts/pre-release-hook.sh | 4 +--- src/cli/run.rs | 38 ++++++++++++++++++++++--------------- 8 files changed, 78 insertions(+), 77 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 263d510f8..ee888748c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,10 @@ jobs: - run: cargo msrv verify - run: cargo machete --with-metadata - run: ./scripts/test-standalone.sh - - run: just render-all lint-fix + - run: cargo build --all-features + - run: ./target/debug/mise settings set experimental true + - run: ./target/debug/mise run render + - run: ./target/debug/mise run lint:fix - run: git diff HEAD - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'jdx/mise' uses: EndBug/add-and-commit@v9 @@ -50,7 +53,7 @@ jobs: push: true author_name: mise[bot] author_email: 123107610+mise-en-dev@users.noreply.github.com - - run: just lint + - run: ./target/debug/mise run lint coverage: name: coverage-${{matrix.tranche}} diff --git a/.mise.toml b/.mise.toml index 1c47d3a3e..20ff87f28 100644 --- a/.mise.toml +++ b/.mise.toml @@ -45,40 +45,35 @@ depends = [ "test" ] -[tasks.render-completions] +[tasks."render:completions"] depends = ["build"] env = { NO_COLOR = "1" } -sources = ["target/debug/mise"] -outputs = [ - "completions/mise.bash", - "completions/_mise", - "completions/mise.fish", -] -run = """ +run = ''' #!/usr/bin/env bash set -xeuo pipefail target/debug/mise render-completion bash > completions/mise.bash target/debug/mise render-completion zsh > completions/_mise target/debug/mise render-completion fish > completions/mise.fish -""" +''' -[tasks.render-mangen] +[tasks."render:mangen"] depends = ["build"] env = { NO_COLOR = "1" } run = "target/debug/mise render-mangen" -[tasks.render-help] +[tasks."render:help"] depends = ["build"] env = { NO_COLOR = "1" } run = [ "target/debug/mise render-help", - "md-magic", + "mise x node@latest -- npx markdown-magic", ] sources = ["target/debug/mise"] outputs = ["README.md"] -[tasks.render-all] -depends = ["render-*"] +[tasks.render] +alias = "render" +depends = ["render:*"] [tasks.snapshots] description = "Update test snapshots" @@ -87,7 +82,8 @@ run = "cargo insta test --accept --unreferenced delete" [tasks.release] run = "cargo release" -[tasks.lint-fix] +[tasks."lint:fix"] +alias = "lint-fix" run = "just lint-fix" [tasks.signal-test] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 37d463dce..258388975 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,7 +62,6 @@ Available recipes: default # defaults to `just test` lint # clippy, cargo fmt --check, and just --fmt lint-fix # runs linters but makes fixes when possible - pre-commit # called by lefthook precommit hook release *args # create/publish a new version of mise render-completions # regenerate shell completion files render-help # regenerate README.md @@ -106,23 +105,13 @@ Run `just release -x [minor|patch]`. (minor if it is the first release in a mont ## Linting -- Lint codebase: `just lint` -- Lint and fix codebase: `just lint-fix` +- Lint codebase: `mise run lint` +- Lint and fix codebase: `mise run lint:fix` ## Generating readme and shell completion files ```shell -just pre-commit -``` - -## [optional] Pre-commit hook - -This project uses lefthook which will automatically install a pre-commit hook: - -```shell -brew install lefthook # or install via some other means -lefthook install -git commit +mise run render ``` ## Testing packaging diff --git a/Cargo.lock b/Cargo.lock index fba6a9a66..095cd8f5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1358,6 +1358,7 @@ dependencies = [ "toml", "toml_edit", "url", + "velcro", "versions", "walkdir", "which", @@ -2758,6 +2759,36 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "velcro" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c6a51883ba1034757307e06dc4856cd5439ecf6804ce6c90d13d49496196fc" +dependencies = [ + "velcro_macros", +] + +[[package]] +name = "velcro_core" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "742cf45d07989b7614877e083602a8973890c75a81f47216b238d2f326ec916c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "velcro_macros" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b23c806d7b49977e6e12ee6d120ac01dcab702b51c652fdf1a6709ab5b8868c" +dependencies = [ + "syn 1.0.109", + "velcro_core", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 7457884de..e2428493b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ thiserror = "1.0.56" toml = { version = "0.8.8", features = ["parse"] } toml_edit = { version = "0.21.0", features = ["parse"] } url = "2.5.0" +velcro = "0.5.4" versions = { version = "6.1.0" , features=["serde"]} walkdir = "2.4.0" which = "6.0.0" diff --git a/justfile b/justfile index 775f89fd4..e2699ccd3 100644 --- a/justfile +++ b/justfile @@ -62,14 +62,13 @@ test-coverage: if [[ "${TEST_TRANCHE:-}" == 0 ]]; then echo "::group::Unit tests" cargo test --all-features - echo "::group::render-help render-completions render-mangen" - just render-help render-completions render-mangen + echo "::group::render" + MISE_EXPERIMENTAL=1 mise run render echo "::group::Implode" mise implode elif [[ "${TEST_TRANCHE:-}" == 1 ]]; then echo "::group::Self update" - # TODO: remove this once the task runnner is shipped - mise self-update -fy || true + mise self-update -fy fi echo "::group::Render lcov report" cargo llvm-cov report --lcov --output-path lcov.info @@ -104,27 +103,3 @@ lint-fix: just --unstable --fmt MISE_EXPERIMENTAL=1 mise x npm:prettier@latest -- prettier -w $(git ls-files '*.yml' '*.yaml') MISE_EXPERIMENTAL=1 mise x npm:markdownlint-cli@latest -- markdownlint --fix . - -render-all: render-help render-completions render-mangen - -# regenerate docs/cli-reference.md -render-help: build - NO_COLOR=1 mise render-help - mise x node@latest -- npx markdown-magic - -# regenerate shell completion files -render-completions: build - NO_COLOR=1 mise render-completion bash > completions/mise.bash - NO_COLOR=1 mise render-completion zsh > completions/_mise - NO_COLOR=1 mise render-completion fish > completions/mise.fish - -# regenerate manpages -render-mangen: build - NO_COLOR=1 mise render-mangen - -# called by lefthook precommit hook -pre-commit: render-all lint - git add README.md - git add docs/cli-reference.md - git add completions - git add man diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 8bee2af91..59b1e6914 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -7,9 +7,7 @@ else cargo update && git add Cargo.lock fi -mise run render-mangen ::: render-help - ./scripts/update-shorthand-repo.sh -mise run lint-fix +mise run render ::: lint:fix git add man src/default_shorthands.rs diff --git a/src/cli/run.rs b/src/cli/run.rs index 9ad4a6b30..56657fe77 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; use std::io::Write; use std::iter::once; use std::os::unix::prelude::ExitStatusExt; @@ -16,6 +16,7 @@ use eyre::Result; use globwalk::GlobWalkerBuilder; use itertools::Itertools; use once_cell::sync::Lazy; +use velcro::hash_set; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; @@ -165,10 +166,6 @@ impl Run { if let Some(root) = &config.project_root { env.insert("MISE_PROJECT_ROOT".into(), root.display().to_string()); } - if console::colors_enabled() { - env.insert("CLICOLOR_FORCE".into(), "1".into()); - env.insert("FORCE_COLOR".into(), "1".into()); - } let tasks = Deps::new(config, tasks)?; for task in tasks.all() { @@ -219,12 +216,19 @@ impl Run { return Ok(()); } - let env: BTreeMap = env + let mut env: BTreeMap = env .iter() .chain(task.env.iter()) .map(|(k, v)| (k.clone(), v.clone())) .collect(); + static COLOR_KEYS: Lazy> = + Lazy::new(|| hash_set!("CLICOLOR", "CLICOLOR_FORCE", "FORCE_COLOR", "NO_COLOR")); + if console::colors_enabled() && !task.env.keys().any(|k| COLOR_KEYS.contains(k.as_str())) { + env.insert("CLICOLOR_FORCE".into(), "1".into()); + env.insert("FORCE_COLOR".into(), "1".into()); + } + let timer = std::time::Instant::now(); if let Some(file) = &task.file { @@ -260,19 +264,23 @@ impl Run { env: &BTreeMap, prefix: &str, ) -> Result<()> { - let script = format!("{} {}", script, shell_words::join(args)); + let script = script.trim_start(); let cmd = style::ebold(format!("$ {script}")).bright().to_string(); info_unprefix_trunc!("{prefix} {cmd}"); - if env::var("MISE_TASK_SCRIPT_FILE").is_ok() { - let mut tmp = tempfile::NamedTempFile::new()?; - let args = once(tmp.path().display().to_string()) - .chain(args.iter().cloned()) - .collect_vec(); - writeln!(tmp, "{}", script.trim())?; - self.exec("sh", &args, task, env, prefix) + if script.starts_with("#!") { + let dir = tempfile::tempdir()?; + let file = dir.path().join("script"); + let mut tmp = std::fs::File::create(&file)?; + tmp.write_all(script.as_bytes())?; + tmp.flush()?; + drop(tmp); + file::make_executable(&file)?; + let filename = file.display().to_string(); + self.exec(&filename, args, task, env, prefix) } else { - let args = vec!["-c".to_string(), script.trim().to_string()]; + let script = format!("{} {}", script, shell_words::join(args)); + let args = vec!["-c".to_string(), script]; self.exec("sh", &args, task, env, prefix) } } From ee10dba7712acb7420ab807331dc5b37216db080 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:18:32 -0600 Subject: [PATCH 1732/1891] use Cargo.* as source --- .mise.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mise.toml b/.mise.toml index 20ff87f28..58ae73aad 100644 --- a/.mise.toml +++ b/.mise.toml @@ -30,7 +30,7 @@ run = "cargo clean" [tasks.build] alias = "b" run = "cargo build --color always --all-features" -sources = ["src/**/*.rs"] +sources = ["Cargo.*", "src/**/*.rs"] outputs = ["target/debug/mise"] [tasks.test] From 6af249acdb3e9f74134231b21e72b7d0587f753f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:20:13 -0600 Subject: [PATCH 1733/1891] chore: Release mise version 2024.1.34 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 095cd8f5e..ba79b89c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.33" +version = "2024.1.34" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index e2428493b..66f7541d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.33" +version = "2024.1.34" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 460e886d0..115de897d 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.33 +mise 2024.1.34 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 8f7175a40..830dce86f 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.33"; + version = "2024.1.34"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 47519abc3..6c93457ff 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.33" +.TH mise 1 "mise 2024.1.34" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.33 +v2024.1.34 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 05ba59231..b8b95f25e 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.33 +Version: 2024.1.34 Release: 1 URL: https://github.com/jdx/mise/ Group: System From c8837fea7605167c9be2e964acbb29a6ba4e48aa Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 11:16:29 -0600 Subject: [PATCH 1734/1891] shims: use activate_agressive setting --- src/path_env.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/path_env.rs b/src/path_env.rs index a3ed78110..9dfab2a53 100644 --- a/src/path_env.rs +++ b/src/path_env.rs @@ -4,6 +4,7 @@ use std::fmt; use std::fmt::{Display, Formatter}; use std::path::PathBuf; +use crate::config::Settings; use itertools::Itertools; use crate::dirs; @@ -50,12 +51,14 @@ impl Display for PathEnv { impl FromIterator for PathEnv { fn from_iter>(paths: T) -> Self { + let settings = Settings::get(); + let mut path_env = Self::new(); for path in paths { if path_env.seen_shims { path_env.post.push(path); - } else if path == *dirs::SHIMS { + } else if path == *dirs::SHIMS && !settings.activate_aggressive { path_env.seen_shims = true; } else { path_env.pre.push(path); From 3070bf8f1ddb517d7d0f329b0d242d7433a1c487 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 11:17:43 -0600 Subject: [PATCH 1735/1891] chore: Release mise version 2024.1.35 --- Cargo.lock | 25 ++++++++++++++++--------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba79b89c2..2d6527279 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -684,9 +684,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.34" +version = "2024.1.35" dependencies = [ "base64", "built", @@ -1803,9 +1803,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ "async-compression", "base64", @@ -1833,6 +1833,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -2294,6 +2295,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sys-info" version = "0.9.1" @@ -2538,9 +2545,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" dependencies = [ "serde", "serde_spanned", @@ -2559,9 +2566,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap", "serde", diff --git a/Cargo.toml b/Cargo.toml index 66f7541d6..c38c0b43e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.34" +version = "2024.1.35" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 115de897d..8a649f434 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.34 +mise 2024.1.35 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 830dce86f..3e79e59fe 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.34"; + version = "2024.1.35"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 6c93457ff..514ec03bc 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.34" +.TH mise 1 "mise 2024.1.35" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.34 +v2024.1.35 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index b8b95f25e..82418f7cb 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.34 +Version: 2024.1.35 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 2cd8ad5d61784edaa7f0f234cef3ba41c2fbb47f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 13:21:47 -0600 Subject: [PATCH 1736/1891] docker (#1570) --- .devcontainer/Dockerfile | 27 ---- .devcontainer/devcontainer.json | 8 +- .github/dependabot.yml | 15 -- .github/workflows/docker.yml | 52 +++++-- .gitignore | 1 + .mise.local.toml | 4 +- .mise.toml | 31 +++- CONTRIBUTING.md | 156 +------------------ Cargo.lock | 31 ---- Cargo.toml | 1 - completions/_mise | 66 ++++---- completions/mise.bash | 106 ++++++------- completions/mise.fish | 86 +++++----- docs/cli-reference.md | 104 ++++++------- e2e/test_deno | 5 + e2e/test_doctor | 1 + e2e/test_go_install | 2 + e2e/test_npm | 2 +- e2e/test_python | 8 +- justfile | 12 -- man/man1/mise.1 | 10 +- packaging/{github-actions => dev}/Dockerfile | 64 +++----- src/cli/mod.rs | 10 +- src/cli/run.rs | 47 +++--- src/cli/{task => tasks}/deps.rs | 14 +- src/cli/{task => tasks}/edit.rs | 16 +- src/cli/{task => tasks}/ls.rs | 10 +- src/cli/{task => tasks}/mod.rs | 14 +- src/cli/watch.rs | 22 +-- src/config/settings.rs | 4 +- src/shims.rs | 10 ++ src/task.rs | 2 +- src/test.rs | 1 + 33 files changed, 369 insertions(+), 573 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .github/dependabot.yml rename packaging/{github-actions => dev}/Dockerfile (52%) rename src/cli/{task => tasks}/deps.rs (94%) rename src/cli/{task => tasks}/edit.rs (81%) rename src/cli/{task => tasks}/ls.rs (93%) rename src/cli/{task => tasks}/mod.rs (77%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index c713ea0c5..000000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM mcr.microsoft.com/devcontainers/rust:1-1-bullseye - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] -WORKDIR /workspaces/cached - -# Use another target directory to avoid conflicts with the host target directory -ENV CARGO_TARGET_DIR=/workspaces/target -RUN mkdir /workspaces/target \ - # Install rust tools - && rustup component add clippy llvm-tools rustfmt \ - && cargo install cargo-insta cargo-llvm-cov \ - # Install dependencies - && export DEBIAN_FRONTEND=noninteractive \ - && curl -fsSL https://deb.nodesource.com/nsolid_setup_deb.sh | bash -s -- 20 \ - && apt-get update \ - && apt-get -y install --no-install-recommends \ - # shells, direnv, shellcheck - bash fish zsh direnv nodejs \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* \ - # just - && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/bin - -COPY --from=golang:1.21-bullseye /usr/local/go/ /usr/local/go/ -ENV PATH="/usr/local/go/bin:${PATH}" - -ENTRYPOINT [ "/bin/bash" ] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fe57d7473..fd7f21bcc 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,12 +3,12 @@ { "name": "Rust", - // "image": "mcr.microsoft.com/devcontainers/rust:0-1-bullseye", + "image": "ghcr.io/jdx/mise:dev", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "build": { - "dockerfile": "Dockerfile", - }, + // "build": { + // "dockerfile": "Dockerfile", + // }, // Use 'mounts' to make the cargo cache persistent in a Docker Volume. // "mounts": [ diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 6ed70d746..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: &schedule - interval: "weekly" - groups: &groups - dependencies: - dependency-type: "production" - dev-dependencies: - dependency-type: "development" - - package-ecosystem: "cargo" - directory: "/" - schedule: *schedule - groups: *groups diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f4b1f7946..a620d669e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -23,9 +23,8 @@ jobs: flavor: - alpine - deb - - github-actions - - rpm - mise + - rpm runs-on: ubuntu-latest permissions: contents: read @@ -53,19 +52,46 @@ jobs: tags: ghcr.io/jdx/mise:${{ matrix.flavor }} labels: ${{ steps.meta.outputs.labels }} file: packaging/${{ matrix.flavor }}/Dockerfile - test: - runs-on: ubuntu-22.04 - container: ghcr.io/jdx/mise:github-actions - timeout-minutes: 10 + dev: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - - run: node -v - - run: cargo -V - - name: Checkout + - name: Checkout repository uses: actions/checkout@v4 - - name: Run cargo nextest - run: cargo nextest run --all-features - env: - RUST_BACKTRACE: "1" + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ghcr.io/jdx/mise:dev + labels: ${{ steps.meta.outputs.labels }} + file: packaging/dev/Dockerfile + platforms: linux/amd64,linux/arm64 + dev-test: + runs-on: ubuntu-latest + container: + image: ghcr.io/jdx/mise:dev + needs: [dev] + steps: + - uses: actions/checkout@v4 + - run: cargo install --path . --debug + - run: mise install -y + - run: mise run test dockerhub: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 9afa6f690..e814f45ea 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ lcov.info /aur megalinter-reports/ +.dev/ diff --git a/.mise.local.toml b/.mise.local.toml index 05a583a38..6e50f8286 100644 --- a/.mise.local.toml +++ b/.mise.local.toml @@ -2,8 +2,8 @@ tasks.a1 = ["echo a1 1>&2 && sleep 1.5"] tasks.a2 = "echo a2 && sleep 1.0" -tasks.b1 = { run = "echo b1 && sleep 1.0", depends = ["a1", "a2"] } -tasks.c1 = { run = "echo c1 && sleep 0.5 && echo", depends = ["b1"] } +tasks.b1 = { run = "echo b1 && sleep 1.0", depends = ["a1", "a2"], hide = true } +tasks.c1 = { run = "echo c1 && sleep 0.5 && echo", depends = ["b1"], hide = true } #tasks.filetask = "echo local" [env] diff --git a/.mise.toml b/.mise.toml index 58ae73aad..dac3eaba9 100644 --- a/.mise.toml +++ b/.mise.toml @@ -33,11 +33,6 @@ run = "cargo build --color always --all-features" sources = ["Cargo.*", "src/**/*.rs"] outputs = ["target/debug/mise"] -[tasks.test] -run = "cargo test" -depends = ["clean"] -env = { CARGO_TERM_COLOR = "always" } - [tasks.ci] depends = [ "format", @@ -89,6 +84,16 @@ run = "just lint-fix" [tasks.signal-test] run = "node ./test/fixtures/signal-test.js" +[tasks.test] +run = [ + "mise run test:unit", + "mise run test:e2e", +] + +[tasks."test:unit"] +run = "cargo test" +env = { CARGO_TERM_COLOR = "always" } + [tasks."test:e2e"] run = "just test-e2e" # TODO: make this work when we have task args @@ -102,3 +107,19 @@ run = "just test-e2e" # echo ./e2e/run_test "$FILES" #fi #''' + +[tasks."docker:image"] +description = "build docker image from Dockerfile" +run = 'docker build $root -f $root/packaging/dev/Dockerfile -t ghcr.io/jdx/mise:dev' + +[tasks."docker:cargo"] +description = "run cargo inside of development docker container" +run = 'docker run -ti --rm -v $root:/mise -w /mise ghcr.io/jdx/mise:dev cargo' + +[tasks."docker:mise"] +description = "run mise inside of development docker container" +run = "mise run -- docker:cargo run --" + +[tasks."docker:e2e"] +description = "run e2e tests inside of development docker container" +run = "mise run docker:mise run test:e2e" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 258388975..38c6ee7fb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,155 +1 @@ -# Contributing - -Before submitting a PR, unless it's something obvious, consider filing an issue or simply mention what you plan to do in the [Discord](https://discord.gg/UBa7pJUN7Z). -PRs are often either rejected or need to change significantly after submission so make sure before you start working on something it won't be a wasted effort. - -## Development Container - -The directory `.devcontainer` contains a Dockerfile that can be used to build a container for local development. This is useful if you want to use a [GitHub Codespace](https://docs.github.com/codespaces), VSCode's remote container feature or a standalone container to develop mise. To use it, you'll need to have Docker Desktop installed and running. - -Build and run the container with the following commands: - -```shell -cd .devcontainer -docker build -t local/misedevcontainer . -docker run --rm -it -v "$(pwd)"/../:/workspaces/cached local/misedevcontainer -``` - -To use the container with VSCode, you'll need to install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. Once installed, you can open the project in a container by opening the Command Palette (F1) and selecting "Remote-Containers: Open Folder in Container...". Select the root of the mise project and the container will be built and started. - -## Dependencies - -- [rust](https://www.rust-lang.org/) stable 1.66.1+ (it might be compatible with earlier, but I haven't tested that). As of this writing: 1.67.0 but GH actions will use the latest stable whenever it runs. -- [just](https://github.com/casey/just) any version should do, but as of this writing I'm on 1.13.0 - -(you'd think we'd use mise to fetch these but frankly it's kind of a pain to dogfood mise while testing it) - -## Tasks - -Mise uses mise itself to run tasks. See available tasks with `mise tasks`: - -```shell -~/src/mise ❯ mise tasks -build ~/src/mise/.mise.toml -clean ~/src/mise/.mise.toml -format ~/src/mise/.mise.toml -lint ~/src/mise/.mise/config.toml -lint-fix ~/src/mise/.mise.toml -release ~/src/mise/.mise.toml -render-all ~/src/mise/.mise.toml -render-completions ~/src/mise/.mise.toml -render-help ~/src/mise/.mise.toml -render-mangen ~/src/mise/.mise.toml -signal-test ~/src/mise/.mise.toml -snapshots Update test snapshots ~/src/mise/.mise.toml -test ~/src/mise/.mise.toml -test:e2e ~/src/mise/.mise.toml -``` - -## [deprecated] Just - -Note: these tasks are being moved over to `mise run` tasks but not all of them have been migrated yet. - -Just should be used for just about every task. Here is a full list of its -tasks: - -```shell -~/src/mise ❯ just --list -Available recipes: - build *args # just `cargo build` - b *args # alias for `build` - clean # delete built files - default # defaults to `just test` - lint # clippy, cargo fmt --check, and just --fmt - lint-fix # runs linters but makes fixes when possible - release *args # create/publish a new version of mise - render-completions # regenerate shell completion files - render-help # regenerate README.md - render-mangen # regenerate manpages - test *args # run all test types - t *args # alias for `test` - test-coverage # run unit tests w/ coverage - test-e2e TEST=("all") # specify a test name to run a single test - e TEST=("all") # alias for `test-e2e` - test-unit *args # run the rust "unit" tests - test-update-snapshots # update all test snapshot files -``` - -## Setup - -Shouldn't require anything special I'm aware of, but `just build` is a good sanity check to run and make sure it's all working. - -## Running the CLI - -I put a shim for `cargo run` that makes it easy to run build + run mise in dev mode. It's at `.bin/mise`. What I do is add this to PATH -with direnv. Here is my `.envrc`: - -```shell -source_up_if_exists -PATH_add "$(expand_path .bin)" -``` - -Now I can just run `mise` as if I was using an installed version and it will build it from source every time there are changes. - -You don't have to do this, but it makes things like `mise activate` a lot easier to setup. - -## Running Tests - -- Run only unit tests: `just test-unit` -- Run only E2E tests: `just test-e2e` -- Run all tests: `just test` - -## Releasing - -Run `just release -x [minor|patch]`. (minor if it is the first release in a month) - -## Linting - -- Lint codebase: `mise run lint` -- Lint and fix codebase: `mise run lint:fix` - -## Generating readme and shell completion files - -```shell -mise run render -``` - -## Testing packaging - -This is only necessary to test if actually changing the packaging setup. - -### Ubuntu (apt) - -This is for arm64, but you can change the arch to amd64 if you want. - -```shell -docker run -ti --rm ubuntu -apt update -y -apt install -y gpg sudo wget curl -sudo install -dm 755 /etc/apt/keyrings -wget -qO - https://mise.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/mise-archive-keyring.gpg 1> /dev/null -echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=arm64] https://mise.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/mise.list -apt update -apt install -y mise -mise -V -``` - -### Amazon Linux 2 (yum) - -```shell -docker run -ti --rm amazonlinux -yum install -y yum-utils -yum-config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo -yum install -y mise -mise -v -``` - -### Fedora (dnf) - -```shell -docker run -ti --rm fedora -dnf install -y dnf-plugins-core -dnf config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo -dnf install -y mise -mise -v -``` + diff --git a/Cargo.lock b/Cargo.lock index 2d6527279..62788b3df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1358,7 +1358,6 @@ dependencies = [ "toml", "toml_edit", "url", - "velcro", "versions", "walkdir", "which", @@ -2766,36 +2765,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "velcro" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c6a51883ba1034757307e06dc4856cd5439ecf6804ce6c90d13d49496196fc" -dependencies = [ - "velcro_macros", -] - -[[package]] -name = "velcro_core" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742cf45d07989b7614877e083602a8973890c75a81f47216b238d2f326ec916c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "velcro_macros" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b23c806d7b49977e6e12ee6d120ac01dcab702b51c652fdf1a6709ab5b8868c" -dependencies = [ - "syn 1.0.109", - "velcro_core", -] - [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index c38c0b43e..d7aea7498 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,6 @@ thiserror = "1.0.56" toml = { version = "0.8.8", features = ["parse"] } toml_edit = { version = "0.21.0", features = ["parse"] } url = "2.5.0" -velcro = "0.5.4" versions = { version = "6.1.0" , features=["serde"]} walkdir = "2.4.0" which = "6.0.0" diff --git a/completions/_mise b/completions/_mise index 1cdb6f46a..5569bc0c8 100644 --- a/completions/_mise +++ b/completions/_mise @@ -49,7 +49,7 @@ _mise() { (settings) __mise_settings_cmd && ret=0 ;; (sh|shell) __mise_shell_cmd && ret=0 ;; (sync) __mise_sync_cmd && ret=0 ;; - (t|tasks|task) __mise_task_cmd && ret=0 ;; + (t|task|tasks) __mise_tasks_cmd && ret=0 ;; (trust) __mise_trust_cmd && ret=0 ;; (remove|rm|uninstall) __mise_uninstall_cmd && ret=0 ;; (unset) __mise_unset_cmd && ret=0 ;; @@ -577,14 +577,14 @@ __mise_run_cmd() { '::task:__mise_tasks' \ '*::args:' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ - '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ - '(-f --force)'{-f,--force}'[Force the task to run even if outputs are up to date]' \ - '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the task'\''s label]' \ + '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the tasks(s), just print them in order of execution]' \ + '(-f --force)'{-f,--force}'[Force the tasks to run even if outputs are up to date]' \ + '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the tasks'\''s label]' \ '(-i --interleave)'{-i,--interleave}'[Print directly to stdout/stderr instead of by line]' \ '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__mise_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ - '--timings[Shows elapsed time after each task]' \ + '--timings[Shows elapsed time after each tasks]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' @@ -725,8 +725,8 @@ __mise_sync_python_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__mise_task_cmd] )) || -__mise_task_cmd() { +(( $+functions[__mise_tasks_cmd] )) || +__mise_tasks_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '--hidden[Show hidden tasks]' \ @@ -734,25 +734,25 @@ __mise_task_cmd() { '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' \ - '1: :__mise_task_cmds' \ + '1: :__mise_tasks_cmds' \ '*::arg:->args' && ret=0 case "$state" in (args) curcontext="${curcontext%:*:*}:mise-cmd-$words[1]:" case $words[1] in - (deps) __mise_task_deps_cmd && ret=0 ;; - (edit) __mise_task_edit_cmd && ret=0 ;; - (ls) __mise_task_ls_cmd && ret=0 ;; - (r|run) __mise_task_run_cmd && ret=0 ;; + (deps) __mise_tasks_deps_cmd && ret=0 ;; + (edit) __mise_tasks_edit_cmd && ret=0 ;; + (ls) __mise_tasks_ls_cmd && ret=0 ;; + (r|run) __mise_tasks_run_cmd && ret=0 ;; esac ;; esac return ret } -(( $+functions[__mise_task_deps_cmd] )) || -__mise_task_deps_cmd() { +(( $+functions[__mise_tasks_deps_cmd] )) || +__mise_tasks_deps_cmd() { _arguments -s -S \ '*::tasks:' \ '--dot[Display dependencies in DOT format]' \ @@ -761,18 +761,18 @@ __mise_task_deps_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__mise_task_edit_cmd] )) || -__mise_task_edit_cmd() { +(( $+functions[__mise_tasks_edit_cmd] )) || +__mise_tasks_edit_cmd() { _arguments -s -S \ ':task:__mise_tasks' \ - '(-p --path)'{-p,--path}'[Display the path to the task instead of editing it]' \ + '(-p --path)'{-p,--path}'[Display the path to the tasks instead of editing it]' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__mise_task_ls_cmd] )) || -__mise_task_ls_cmd() { +(( $+functions[__mise_tasks_ls_cmd] )) || +__mise_tasks_ls_cmd() { _arguments -s -S \ '--no-header[Do not print table header]' \ '--hidden[Show hidden tasks]' \ @@ -781,20 +781,20 @@ __mise_task_ls_cmd() { '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' } -(( $+functions[__mise_task_run_cmd] )) || -__mise_task_run_cmd() { +(( $+functions[__mise_tasks_run_cmd] )) || +__mise_tasks_run_cmd() { _arguments -s -S \ '::task:__mise_tasks' \ '*::args:' \ '(-C --cd)'{-C,--cd}'=[Change to this directory before executing the command]:cd:_directories' \ - '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the task(s), just print them in order of execution]' \ - '(-f --force)'{-f,--force}'[Force the task to run even if outputs are up to date]' \ - '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the task'\''s label]' \ + '(-n --dry-run)'{-n,--dry-run}'[Don'\''t actually run the tasks(s), just print them in order of execution]' \ + '(-f --force)'{-f,--force}'[Force the tasks to run even if outputs are up to date]' \ + '(-p --prefix)'{-p,--prefix}'[Print stdout/stderr by line, prefixed with the tasks'\''s label]' \ '(-i --interleave)'{-i,--interleave}'[Print directly to stdout/stderr instead of by line]' \ '*'{-t,--tool}'=[Tool(s) to also add e.g.\: node@20 python@3.10]:tool:__mise_tool_versions' \ '(-j --jobs)'{-j,--jobs}'=[Number of tasks to run in parallel]:jobs:' \ '(-r --raw)'{-r,--raw}'[Read/write directly to stdin/stdout/stderr instead of by line]' \ - '--timings[Shows elapsed time after each task]' \ + '--timings[Shows elapsed time after each tasks]' \ '(-q --quiet)'{-q,--quiet}'[Suppress non-error messages]' \ '*'{-v,--verbose}'[Show extra output (use -vv for even more)]' \ '(-y --yes)'{-y,--yes}'[Answer yes to all confirmation prompts]' @@ -874,7 +874,7 @@ __mise_version_cmd() { (( $+functions[__mise_watch_cmd] )) || __mise_watch_cmd() { _arguments -s -S \ - '*'{-t,--task}'=[Task to run]:task:__mise_tasks' \ + '*'{-t,--task}'=[Tasks to run]:task:__mise_tasks' \ '*::args:' \ '*'{-g,--glob}'=[Files to watch]:glob:' \ '(-C --cd)'{-C,--cd}'=[Change directory before running command]:cd:_directories' \ @@ -928,20 +928,20 @@ __mise_cmds() { {p,plugins}':Manage plugins' 'prune:Delete unused versions of tools' 'reshim:rebuilds the shim farm' - {r,run}':\[experimental\] Run a task' + {r,run}':\[experimental\] Run a tasks' 'self-update:Updates mise itself' 'set:Manage environment variables' 'settings:Manage settings' {sh,shell}':Sets a tool version for the current shell session' 'sync:Add tool versions from external tools to mise' - {t,task}':\[experimental\] Manage tasks' + {t,tasks}':\[experimental\] Manage tasks' 'trust:Marks a config file as trusted' {remove,rm,uninstall}':Removes runtime versions' 'unset:Remove environment variable(s) from the config file' {up,upgrade}':Upgrades outdated tool versions' {u,use}':Change the active version of a tool locally or globally.' 'version:Show mise version' - {w,watch}':\[experimental\] Run a task watching for changes' + {w,watch}':\[experimental\] Run a tasks watching for changes' 'where:Display the installation path for a runtime' 'which:Shows the path that a bin name points to' ) @@ -1009,13 +1009,13 @@ __mise_sync_cmds() { ) _describe -t commands 'command' commands "$@" } -(( $+functions[__mise_task_cmds] )) || -__mise_task_cmds() { +(( $+functions[__mise_tasks_cmds] )) || +__mise_tasks_cmds() { local commands; commands=( 'deps:\[experimental\] Display a tree visualization of a dependency graph' - 'edit:\[experimental\] Edit a task with \$EDITOR' + 'edit:\[experimental\] Edit a tasks with \$EDITOR' 'ls:\[experimental\] List available tasks to execute' - {r,run}':\[experimental\] Run a task' + {r,run}':\[experimental\] Run a tasks' ) _describe -t commands 'command' commands "$@" } diff --git a/completions/mise.bash b/completions/mise.bash index fe9cb5c71..6bbb9e851 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -157,10 +157,10 @@ _mise() { cmd="mise__sync" ;; mise,t) - cmd="mise__task" + cmd="mise__tasks" ;; - mise,task) - cmd="mise__task" + mise,tasks) + cmd="mise__tasks" ;; mise,trust) cmd="mise__trust" @@ -423,8 +423,8 @@ _mise() { mise__help,sync) cmd="mise__help__sync" ;; - mise__help,task) - cmd="mise__help__task" + mise__help,tasks) + cmd="mise__help__tasks" ;; mise__help,trust) cmd="mise__help__trust" @@ -519,17 +519,17 @@ _mise() { mise__help__sync,python) cmd="mise__help__sync__python" ;; - mise__help__task,deps) - cmd="mise__help__task__deps" + mise__help__tasks,deps) + cmd="mise__help__tasks__deps" ;; - mise__help__task,edit) - cmd="mise__help__task__edit" + mise__help__tasks,edit) + cmd="mise__help__tasks__edit" ;; - mise__help__task,ls) - cmd="mise__help__task__ls" + mise__help__tasks,ls) + cmd="mise__help__tasks__ls" ;; - mise__help__task,run) - cmd="mise__help__task__run" + mise__help__tasks,run) + cmd="mise__help__tasks__run" ;; mise__plugins,a) cmd="mise__plugins__install" @@ -675,38 +675,38 @@ _mise() { mise__sync__help,python) cmd="mise__sync__help__python" ;; - mise__task,deps) - cmd="mise__task__deps" + mise__tasks,deps) + cmd="mise__tasks__deps" ;; - mise__task,edit) - cmd="mise__task__edit" + mise__tasks,edit) + cmd="mise__tasks__edit" ;; - mise__task,help) - cmd="mise__task__help" + mise__tasks,help) + cmd="mise__tasks__help" ;; - mise__task,ls) - cmd="mise__task__ls" + mise__tasks,ls) + cmd="mise__tasks__ls" ;; - mise__task,r) - cmd="mise__task__run" + mise__tasks,r) + cmd="mise__tasks__run" ;; - mise__task,run) - cmd="mise__task__run" + mise__tasks,run) + cmd="mise__tasks__run" ;; - mise__task__help,deps) - cmd="mise__task__help__deps" + mise__tasks__help,deps) + cmd="mise__tasks__help__deps" ;; - mise__task__help,edit) - cmd="mise__task__help__edit" + mise__tasks__help,edit) + cmd="mise__tasks__help__edit" ;; - mise__task__help,help) - cmd="mise__task__help__help" + mise__tasks__help,help) + cmd="mise__tasks__help__help" ;; - mise__task__help,ls) - cmd="mise__task__help__ls" + mise__tasks__help,ls) + cmd="mise__tasks__help__ls" ;; - mise__task__help,run) - cmd="mise__task__help__run" + mise__tasks__help,run) + cmd="mise__tasks__help__run" ;; *) ;; @@ -715,7 +715,7 @@ _mise() { case "${cmd}" in mise) - opts="-C -q -v -y -h -V --cd --debug --log-level --quiet --trace --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update set settings shell sync task trust uninstall upgrade unset use version watch where which render-completion render-help render-mangen help" + opts="-C -q -v -y -h -V --cd --debug --log-level --quiet --trace --verbose --yes --help --version activate alias asdf bin-paths cache completion config current deactivate direnv doctor env exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update set settings shell sync tasks trust uninstall upgrade unset use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1833,7 +1833,7 @@ _mise() { return 0 ;; mise__help) - opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update set settings shell sync task trust uninstall upgrade unset use version watch where which render-completion render-help render-mangen help" + opts="activate alias asdf bin-paths cache completion config current deactivate direnv doctor env exec global hook-env hook-not-found implode install latest link local ls ls-remote outdated plugins prune reshim run self-update set settings shell sync tasks trust uninstall upgrade unset use version watch where which render-completion render-help render-mangen help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2672,7 +2672,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__help__task) + mise__help__tasks) opts="deps edit ls run" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2686,7 +2686,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__help__task__deps) + mise__help__tasks__deps) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2700,7 +2700,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__help__task__edit) + mise__help__tasks__edit) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2714,7 +2714,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__help__task__ls) + mise__help__tasks__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -2728,7 +2728,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__help__task__run) + mise__help__tasks__run) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4299,7 +4299,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task) + mise__tasks) opts="-C -q -v -y -h --no-header --hidden --cd --debug --log-level --quiet --trace --verbose --yes --help deps edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4331,7 +4331,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__deps) + mise__tasks__deps) opts="-C -q -v -y -h --dot --cd --debug --log-level --quiet --trace --verbose --yes --help [TASKS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4363,7 +4363,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__edit) + mise__tasks__edit) opts="-p -C -q -v -y -h --path --cd --debug --log-level --quiet --trace --verbose --yes --help " if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4395,7 +4395,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__help) + mise__tasks__help) opts="deps edit ls run help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4409,7 +4409,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__help__deps) + mise__tasks__help__deps) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4423,7 +4423,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__help__edit) + mise__tasks__help__edit) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4437,7 +4437,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__help__help) + mise__tasks__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4451,7 +4451,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__help__ls) + mise__tasks__help__ls) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4465,7 +4465,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__help__run) + mise__tasks__help__run) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4479,7 +4479,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__ls) + mise__tasks__ls) opts="-C -q -v -y -h --no-header --hidden --cd --debug --log-level --quiet --trace --verbose --yes --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -4511,7 +4511,7 @@ _mise() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - mise__task__run) + mise__tasks__run) opts="-C -n -f -p -i -t -j -r -q -v -y -h --cd --dry-run --force --prefix --interleave --tool --jobs --raw --timings --debug --log-level --quiet --trace --verbose --yes --help [TASK] [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) diff --git a/completions/mise.fish b/completions/mise.fish index 43e475315..6a5580da4 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -5,7 +5,7 @@ complete -kxc mise -s C -l cd -a "(__fish_complete_directories)" -d 'Change dire complete -kxc mise -s q -l quiet -d 'Suppress non-error messages' complete -kxc mise -s v -l verbose -d 'Show extra output (use -vv for even more)' complete -kxc mise -s y -l yes -d 'Answer yes to all confirmation prompts' -set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update set settings shell sync task trust uninstall unset upgrade use version watch where which +set -l others activate alias bin-paths cache completion config current deactivate direnv doctor env exec implode install latest link ls ls-remote outdated plugins prune reshim run self-update set settings shell sync tasks trust uninstall unset upgrade use version watch where which complete -xc mise -n "not $fssf $others" -a activate -d 'Initializes mise in the current shell session' complete -xc mise -n "not $fssf $others" -a alias -d 'Manage aliases' complete -xc mise -n "not $fssf $others" -a bin-paths -d 'List all the active runtime bin paths' @@ -28,20 +28,20 @@ complete -xc mise -n "not $fssf $others" -a outdated -d 'Shows outdated tool ver complete -xc mise -n "not $fssf $others" -a plugins -d 'Manage plugins' complete -xc mise -n "not $fssf $others" -a prune -d 'Delete unused versions of tools' complete -xc mise -n "not $fssf $others" -a reshim -d 'rebuilds the shim farm' -complete -xc mise -n "not $fssf $others" -a run -d '[experimental] Run a task' +complete -xc mise -n "not $fssf $others" -a run -d '[experimental] Run a tasks' complete -xc mise -n "not $fssf $others" -a self-update -d 'Updates mise itself' complete -xc mise -n "not $fssf $others" -a set -d 'Manage environment variables' complete -xc mise -n "not $fssf $others" -a settings -d 'Manage settings' complete -xc mise -n "not $fssf $others" -a shell -d 'Sets a tool version for the current shell session' complete -xc mise -n "not $fssf $others" -a sync -d 'Add tool versions from external tools to mise' -complete -xc mise -n "not $fssf $others" -a task -d '[experimental] Manage tasks' +complete -xc mise -n "not $fssf $others" -a tasks -d '[experimental] Manage tasks' complete -xc mise -n "not $fssf $others" -a trust -d 'Marks a config file as trusted' complete -xc mise -n "not $fssf $others" -a uninstall -d 'Removes runtime versions' complete -xc mise -n "not $fssf $others" -a unset -d 'Remove environment variable(s) from the config file' complete -xc mise -n "not $fssf $others" -a upgrade -d 'Upgrades outdated tool versions' complete -xc mise -n "not $fssf $others" -a use -d 'Change the active version of a tool locally or globally.' complete -xc mise -n "not $fssf $others" -a version -d 'Show mise version' -complete -xc mise -n "not $fssf $others" -a watch -d '[experimental] Run a task watching for changes' +complete -xc mise -n "not $fssf $others" -a watch -d '[experimental] Run a tasks watching for changes' complete -xc mise -n "not $fssf $others" -a where -d 'Display the installation path for a runtime' complete -xc mise -n "not $fssf $others" -a which -d 'Shows the path that a bin name points to' @@ -217,16 +217,16 @@ complete -kxc mise -n "$fssf prune" -a "(__mise_plugins)" -d 'Prune only version # reshim # run -complete -kxc mise -n "$fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' +complete -kxc mise -n "$fssf run" -d 'Arguments to pass to the tasks. Use ":::" to separate tasks' complete -kxc mise -n "$fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' -complete -kxc mise -n "$fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' -complete -kxc mise -n "$fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' +complete -kxc mise -n "$fssf run" -s n -l dry-run -d 'Don'\''t actually run the tasks(s), just print them in order of execution' +complete -kxc mise -n "$fssf run" -s f -l force -d 'Force the tasks to run even if outputs are up to date' complete -kxc mise -n "$fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' complete -kxc mise -n "$fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' -complete -kxc mise -n "$fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' +complete -kxc mise -n "$fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the tasks'\''s label' complete -kxc mise -n "$fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' -complete -kxc mise -n "$fssf run" -a "(__mise_tasks)" -d 'Task to run' -complete -kxc mise -n "$fssf run" -l timings -d 'Shows elapsed time after each task' +complete -kxc mise -n "$fssf run" -a "(__mise_tasks)" -d 'Tasks to run' +complete -kxc mise -n "$fssf run" -l timings -d 'Shows elapsed time after each tasks' complete -kxc mise -n "$fssf run" -s t -l tool -a "(__mise_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' # self-update @@ -280,39 +280,39 @@ complete -kxc mise -n "$fssf sync; and $fssf node" -l nvm -d 'Get tool versions complete -kxc mise -n "$fssf sync; and $fssf python" -l pyenv -d 'Get tool versions from pyenv' -# task -complete -kxc mise -n "$fssf task" -l hidden -d 'Show hidden tasks' -complete -kxc mise -n "$fssf task" -l no-header -d 'Do not print table header' +# tasks +complete -kxc mise -n "$fssf tasks" -l hidden -d 'Show hidden tasks' +complete -kxc mise -n "$fssf tasks" -l no-header -d 'Do not print table header' set -l others deps edit ls run -complete -xc mise -n "$fssf task; and not $fssf $others" -a deps -d '[experimental] Display a tree visualization of a dependency graph' -complete -xc mise -n "$fssf task; and not $fssf $others" -a edit -d '[experimental] Edit a task with $EDITOR' -complete -xc mise -n "$fssf task; and not $fssf $others" -a ls -d '[experimental] List available tasks to execute' -complete -xc mise -n "$fssf task; and not $fssf $others" -a run -d '[experimental] Run a task' - -# task deps -complete -kxc mise -n "$fssf task; and $fssf deps" -l dot -d 'Display dependencies in DOT format' -complete -kxc mise -n "$fssf task; and $fssf deps" -d 'Tasks to show dependencies for' - -# task edit -complete -kxc mise -n "$fssf task; and $fssf edit" -s p -l path -d 'Display the path to the task instead of editing it' -complete -kxc mise -n "$fssf task; and $fssf edit" -a "(__mise_tasks)" -d 'Task to edit' - -# task ls -complete -kxc mise -n "$fssf task; and $fssf ls" -l hidden -d 'Show hidden tasks' -complete -kxc mise -n "$fssf task; and $fssf ls" -l no-header -d 'Do not print table header' - -# task run -complete -kxc mise -n "$fssf task; and $fssf run" -d 'Arguments to pass to the task. Use ":::" to separate tasks' -complete -kxc mise -n "$fssf task; and $fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' -complete -kxc mise -n "$fssf task; and $fssf run" -s n -l dry-run -d 'Don'\''t actually run the task(s), just print them in order of execution' -complete -kxc mise -n "$fssf task; and $fssf run" -s f -l force -d 'Force the task to run even if outputs are up to date' -complete -kxc mise -n "$fssf task; and $fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' -complete -kxc mise -n "$fssf task; and $fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' -complete -kxc mise -n "$fssf task; and $fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the task'\''s label' -complete -kxc mise -n "$fssf task; and $fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' -complete -kxc mise -n "$fssf task; and $fssf run" -a "(__mise_tasks)" -d 'Task to run' -complete -kxc mise -n "$fssf task; and $fssf run" -l timings -d 'Shows elapsed time after each task' -complete -kxc mise -n "$fssf task; and $fssf run" -s t -l tool -a "(__mise_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' +complete -xc mise -n "$fssf tasks; and not $fssf $others" -a deps -d '[experimental] Display a tree visualization of a dependency graph' +complete -xc mise -n "$fssf tasks; and not $fssf $others" -a edit -d '[experimental] Edit a tasks with $EDITOR' +complete -xc mise -n "$fssf tasks; and not $fssf $others" -a ls -d '[experimental] List available tasks to execute' +complete -xc mise -n "$fssf tasks; and not $fssf $others" -a run -d '[experimental] Run a tasks' + +# tasks deps +complete -kxc mise -n "$fssf tasks; and $fssf deps" -l dot -d 'Display dependencies in DOT format' +complete -kxc mise -n "$fssf tasks; and $fssf deps" -d 'Tasks to show dependencies for' + +# tasks edit +complete -kxc mise -n "$fssf tasks; and $fssf edit" -s p -l path -d 'Display the path to the tasks instead of editing it' +complete -kxc mise -n "$fssf tasks; and $fssf edit" -a "(__mise_tasks)" -d 'Tasks to edit' + +# tasks ls +complete -kxc mise -n "$fssf tasks; and $fssf ls" -l hidden -d 'Show hidden tasks' +complete -kxc mise -n "$fssf tasks; and $fssf ls" -l no-header -d 'Do not print table header' + +# tasks run +complete -kxc mise -n "$fssf tasks; and $fssf run" -d 'Arguments to pass to the tasks. Use ":::" to separate tasks' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s C -l cd -a "(__fish_complete_directories)" -d 'Change to this directory before executing the command' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s n -l dry-run -d 'Don'\''t actually run the tasks(s), just print them in order of execution' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s f -l force -d 'Force the tasks to run even if outputs are up to date' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s i -l interleave -d 'Print directly to stdout/stderr instead of by line' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s j -l jobs -d 'Number of tasks to run in parallel' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s p -l prefix -d 'Print stdout/stderr by line, prefixed with the tasks'\''s label' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s r -l raw -d 'Read/write directly to stdin/stdout/stderr instead of by line' +complete -kxc mise -n "$fssf tasks; and $fssf run" -a "(__mise_tasks)" -d 'Tasks to run' +complete -kxc mise -n "$fssf tasks; and $fssf run" -l timings -d 'Shows elapsed time after each tasks' +complete -kxc mise -n "$fssf tasks; and $fssf run" -s t -l tool -a "(__mise_tool_versions)" -d 'Tool(s) to also add e.g.: node@20 python@3.10' # trust @@ -354,7 +354,7 @@ complete -kxc mise -n "$fssf use" -a "(__mise_tool_versions)" -d 'Tool(s) to add # watch complete -kxc mise -n "$fssf watch" -d 'Extra arguments' complete -kxc mise -n "$fssf watch" -s g -l glob -d 'Files to watch' -complete -kxc mise -n "$fssf watch" -s t -l task -a "(__mise_tasks)" -d 'Task to run' +complete -kxc mise -n "$fssf watch" -s t -l task -a "(__mise_tasks)" -d 'Tasks to run' # where complete -kxc mise -n "$fssf where" -a "(__mise_tool_versions)" -d 'Tool(s) to look up' diff --git a/docs/cli-reference.md b/docs/cli-reference.md index fb5ca697a..d411e970c 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -864,11 +864,11 @@ Examples: **Aliases:** `r` ```text -[experimental] Run a task +[experimental] Run a tasks -This command will run a task, or multiple tasks in parallel. +This command will run a tasks, or multiple tasks in parallel. Tasks may have dependencies on other tasks or on source files. -If source is configured on a task, it will only run if the source +If source is configured on a tasks, it will only run if the source files have changed. Tasks can be defined in .mise.toml or as standalone scripts. @@ -881,7 +881,7 @@ In .mise.toml, tasks take this form: Alternatively, tasks can be defined as standalone scripts. These must be located in the `.mise/tasks` directory. -The name of the script will be the name of the task. +The name of the script will be the name of the tasks. $ cat .mise/tasks/build< Change to this directory before executing the command -n, --dry-run - Don't actually run the task(s), just print them in order of execution + Don't actually run the tasks(s), just print them in order of execution -f, --force - Force the task to run even if outputs are up to date + Force the tasks to run even if outputs are up to date -p, --prefix - Print stdout/stderr by line, prefixed with the task's label + Print stdout/stderr by line, prefixed with the tasks's label Defaults to true if --jobs > 1 Configure with `task_output` config or `MISE_TASK_OUTPUT` env var @@ -937,15 +937,15 @@ Options: Configure with `raw` config or `MISE_RAW` env var --timings - Shows elapsed time after each task + Shows elapsed time after each tasks Examples: $ mise run lint - Runs the "lint" task. This needs to either be defined in .mise.toml + Runs the "lint" tasks. This needs to either be defined in .mise.toml or as a standalone script. See the project README for more information. $ mise run build --force - Forces the "build" task to run even if its sources are up-to-date. + Forces the "build" tasks to run even if its sources are up-to-date. $ mise run test --raw Runs "test" with stdin/stdout/stderr all connected to the current terminal. @@ -954,7 +954,7 @@ Examples: $ mise run lint ::: test ::: check Runs the "lint", "test", and "check" tasks in parallel. - $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + $ mise tasks cmd1 arg1 arg2 ::: cmd2 arg1 arg2 Execute multiple tasks each with their own arguments. ``` @@ -1176,57 +1176,57 @@ Examples: $ mise use -g python@3.11.0 - uses pyenv-provided python ``` -## `mise task deps [OPTIONS] [TASKS]...` +## `mise tasks deps [OPTIONS] [TASKS]...` ```text [experimental] Display a tree visualization of a dependency graph -Usage: task deps [OPTIONS] [TASKS]... +Usage: tasks deps [OPTIONS] [TASKS]... Arguments: [TASKS]... Tasks to show dependencies for Can specify multiple tasks by separating with spaces - e.g.: mise task deps lint test check + e.g.: mise tasks deps lint test check Options: --dot Display dependencies in DOT format Examples: - $ mise task deps + $ mise tasks deps Shows dependencies for all tasks - $ mise task deps lint test check + $ mise tasks deps lint test check Shows dependencies for the "lint", "test" and "check" tasks - $ mise task deps --dot + $ mise tasks deps --dot Shows dependencies in DOT format ``` -## `mise task edit [OPTIONS] ` +## `mise tasks edit [OPTIONS] ` ```text -[experimental] Edit a task with $EDITOR +[experimental] Edit a tasks with $EDITOR -The task will be created as a standalone script if it does not already exist. +The tasks will be created as a standalone script if it does not already exist. -Usage: task edit [OPTIONS] +Usage: tasks edit [OPTIONS] Arguments: - Task to edit + Tasks to edit Options: -p, --path - Display the path to the task instead of editing it + Display the path to the tasks instead of editing it Examples: - $ mise task edit build - $ mise task edit test + $ mise tasks edit build + $ mise tasks edit test ``` -## `mise task ls [OPTIONS]` +## `mise tasks ls [OPTIONS]` ```text [experimental] List available tasks to execute @@ -1237,7 +1237,7 @@ So if you have global tasks in ~/.config/mise/tasks/* and project-specific tasks ~/myproject/.mise/tasks/*, then they'll both be available but the project-specific tasks will override the global ones if they have the same name. -Usage: task ls [OPTIONS] +Usage: tasks ls [OPTIONS] Options: --no-header @@ -1247,19 +1247,19 @@ Options: Show hidden tasks Examples: - $ mise task ls + $ mise tasks ls ``` -## `mise task run [OPTIONS] [TASK] [ARGS]...` +## `mise tasks run [OPTIONS] [TASK] [ARGS]...` **Aliases:** `r` ```text -[experimental] Run a task +[experimental] Run a tasks -This command will run a task, or multiple tasks in parallel. +This command will run a tasks, or multiple tasks in parallel. Tasks may have dependencies on other tasks or on source files. -If source is configured on a task, it will only run if the source +If source is configured on a tasks, it will only run if the source files have changed. Tasks can be defined in .mise.toml or as standalone scripts. @@ -1272,7 +1272,7 @@ In .mise.toml, tasks take this form: Alternatively, tasks can be defined as standalone scripts. These must be located in the `.mise/tasks` directory. -The name of the script will be the name of the task. +The name of the script will be the name of the tasks. $ cat .mise/tasks/build< Change to this directory before executing the command -n, --dry-run - Don't actually run the task(s), just print them in order of execution + Don't actually run the tasks(s), just print them in order of execution -f, --force - Force the task to run even if outputs are up to date + Force the tasks to run even if outputs are up to date -p, --prefix - Print stdout/stderr by line, prefixed with the task's label + Print stdout/stderr by line, prefixed with the tasks's label Defaults to true if --jobs > 1 Configure with `task_output` config or `MISE_TASK_OUTPUT` env var @@ -1328,15 +1328,15 @@ Options: Configure with `raw` config or `MISE_RAW` env var --timings - Shows elapsed time after each task + Shows elapsed time after each tasks Examples: $ mise run lint - Runs the "lint" task. This needs to either be defined in .mise.toml + Runs the "lint" tasks. This needs to either be defined in .mise.toml or as a standalone script. See the project README for more information. $ mise run build --force - Forces the "build" task to run even if its sources are up-to-date. + Forces the "build" tasks to run even if its sources are up-to-date. $ mise run test --raw Runs "test" with stdin/stdout/stderr all connected to the current terminal. @@ -1345,7 +1345,7 @@ Examples: $ mise run lint ::: test ::: check Runs the "lint", "test", and "check" tasks in parallel. - $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + $ mise tasks cmd1 arg1 arg2 ::: cmd2 arg1 arg2 Execute multiple tasks each with their own arguments. ``` @@ -1547,7 +1547,7 @@ Usage: version **Aliases:** `w` ```text -[experimental] Run a task watching for changes +[experimental] Run a tasks watching for changes Usage: watch [OPTIONS] [ARGS]... @@ -1557,22 +1557,22 @@ Arguments: Options: -t, --task - Task to run + Tasks to run [default: default] -g, --glob Files to watch - Defaults to sources from the task(s) + Defaults to sources from the tasks(s) Examples: $ mise watch -t build - Runs the "build" task. Will re-run the task when any of its sources change. - Uses "sources" from the task definition to determine which files to watch. + Runs the "build" tasks. Will re-run the tasks when any of its sources change. + Uses "sources" from the tasks definition to determine which files to watch. $ mise watch -t build --glob src/**/*.rs - Runs the "build" task but specify the files to watch with a glob pattern. - This overrides the "sources" from the task definition. + Runs the "build" tasks but specify the files to watch with a glob pattern. + This overrides the "sources" from the tasks definition. $ mise run -t build --clear Extra arguments are passed to watchexec. See `watchexec --help` for details. diff --git a/e2e/test_deno b/e2e/test_deno index f4f6c0c7e..2558cf95b 100755 --- a/e2e/test_deno +++ b/e2e/test_deno @@ -5,6 +5,11 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 +if [[ "${MISE_DISABLE_TOOLS:-}" = *deno* ]]; then + echo "Skipping deno tests" + exit 0 +fi + cat <.deno-version 1.35.3 EOF diff --git a/e2e/test_doctor b/e2e/test_doctor index 35561d77e..170fe1801 100755 --- a/e2e/test_doctor +++ b/e2e/test_doctor @@ -13,4 +13,5 @@ assert() { mise plugins install poetry && mise i eval "$(mise activate bash)" && _mise_hook +mise reshim mise doctor diff --git a/e2e/test_go_install b/e2e/test_go_install index b8f1a4e1f..cd5396d5a 100755 --- a/e2e/test_go_install +++ b/e2e/test_go_install @@ -4,6 +4,8 @@ set -euo pipefail source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 +eval "$(mise activate bash --shims)" +mise use go@prefix:1.20 assert "mise x go:github.com/DarthSim/hivemind@v1.1.0 -- hivemind --version" "Hivemind version 1.1.0" chmod -R u+w "$MISE_DATA_DIR/cache/go-"* || true diff --git a/e2e/test_npm b/e2e/test_npm index 271265e6e..7cec0eb0e 100755 --- a/e2e/test_npm +++ b/e2e/test_npm @@ -6,4 +6,4 @@ source "$(dirname "$0")/assert.sh" export MISE_EXPERIMENTAL=1 assert "mise x npm:prettier@3.1.0 -- prettier -v" "3.1.0" -assert "mise x npm:@antfu/ni@0.21.12 -- ni -v 2>/dev/null | head -n1" "@antfu/ni v0.21.12" +FORCE_COLOR=0 assert "mise x npm:@antfu/ni@0.21.12 -- ni -v 2>/dev/null | head -n1" "@antfu/ni v0.21.12" diff --git a/e2e/test_python b/e2e/test_python index 8560d73fd..97c54d149 100755 --- a/e2e/test_python +++ b/e2e/test_python @@ -8,14 +8,14 @@ export MISE_PYTHON_DEFAULT_PACKAGES_FILE="$ROOT/e2e/.default-python-packages" cat >.e2e.mise.toml < cmd.run(), Self::Shell(cmd) => cmd.run(), Self::Sync(cmd) => cmd.run(), - Self::Task(cmd) => cmd.run(), + Self::Tasks(cmd) => cmd.run(), Self::Trust(cmd) => cmd.run(), Self::Uninstall(cmd) => cmd.run(), Self::Unset(cmd) => cmd.run(), @@ -252,8 +252,8 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ mise set NODE_ENV=production Set NODE_ENV=production in config - $ mise run build Run `build` task - $ mise watch build Run `build` task repeatedly when files change + $ mise run build Run `build` tasks + $ mise watch build Run `build` tasks repeatedly when files change $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file diff --git a/src/cli/run.rs b/src/cli/run.rs index 56657fe77..f78fd67f6 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashSet}; +use std::collections::BTreeMap; use std::io::Write; use std::iter::once; use std::os::unix::prelude::ExitStatusExt; @@ -16,7 +16,6 @@ use eyre::Result; use globwalk::GlobWalkerBuilder; use itertools::Itertools; use once_cell::sync::Lazy; -use velcro::hash_set; use crate::cmd::CmdLineRunner; use crate::config::{Config, Settings}; @@ -31,11 +30,11 @@ use crate::{env, file, ui}; use super::args::ToolArg; -/// [experimental] Run a task +/// [experimental] Run a tasks /// -/// This command will run a task, or multiple tasks in parallel. +/// This command will run a tasks, or multiple tasks in parallel. /// Tasks may have dependencies on other tasks or on source files. -/// If source is configured on a task, it will only run if the source +/// If source is configured on a tasks, it will only run if the source /// files have changed. /// /// Tasks can be defined in .mise.toml or as standalone scripts. @@ -48,7 +47,7 @@ use super::args::ToolArg; /// /// Alternatively, tasks can be defined as standalone scripts. /// These must be located in the `.mise/tasks` directory. -/// The name of the script will be the name of the task. +/// The name of the script will be the name of the tasks. /// /// $ cat .mise/tasks/build<, @@ -72,15 +71,15 @@ pub struct Run { #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)] pub cd: Option, - /// Don't actually run the task(s), just print them in order of execution + /// Don't actually run the tasks(s), just print them in order of execution #[clap(long, short = 'n', verbatim_doc_comment)] pub dry_run: bool, - /// Force the task to run even if outputs are up to date + /// Force the tasks to run even if outputs are up to date #[clap(long, short, verbatim_doc_comment)] pub force: bool, - /// Print stdout/stderr by line, prefixed with the task's label + /// Print stdout/stderr by line, prefixed with the tasks's label /// Defaults to true if --jobs > 1 /// Configure with `task_output` config or `MISE_TASK_OUTPUT` env var #[clap(long, short, verbatim_doc_comment, overrides_with = "interleave")] @@ -108,7 +107,7 @@ pub struct Run { #[clap(long, short, verbatim_doc_comment)] pub raw: bool, - /// Shows elapsed time after each task + /// Shows elapsed time after each tasks #[clap(long, alias = "timing", verbatim_doc_comment)] pub timings: bool, @@ -142,7 +141,7 @@ impl Run { .map(|(t, args)| { let tasks = config.tasks_with_aliases().get_matching(&t)?; if tasks.is_empty() { - ensure!(t == "default", "no task {} found", style::ered(t)); + ensure!(t == "default", "no tasks {} found", style::ered(t)); Ok(vec![self.prompt_for_task(config)?]) } else { @@ -165,6 +164,7 @@ impl Run { let mut env = ts.env_with_path(config)?; if let Some(root) = &config.project_root { env.insert("MISE_PROJECT_ROOT".into(), root.display().to_string()); + env.insert("root".into(), root.display().to_string()); } let tasks = Deps::new(config, tasks)?; @@ -186,7 +186,7 @@ impl Run { let t = task.clone(); s.spawn(|_| { let task = t; - trace!("running task: {task}"); + trace!("running tasks: {task}"); if let Err(err) = self.run_task(config, &env, &task) { error!("{err}"); exit(1); @@ -216,19 +216,12 @@ impl Run { return Ok(()); } - let mut env: BTreeMap = env + let env: BTreeMap = env .iter() .chain(task.env.iter()) .map(|(k, v)| (k.clone(), v.clone())) .collect(); - static COLOR_KEYS: Lazy> = - Lazy::new(|| hash_set!("CLICOLOR", "CLICOLOR_FORCE", "FORCE_COLOR", "NO_COLOR")); - if console::colors_enabled() && !task.env.keys().any(|k| COLOR_KEYS.contains(k.as_str())) { - env.insert("CLICOLOR_FORCE".into(), "1".into()); - env.insert("FORCE_COLOR".into(), "1".into()); - } - let timer = std::time::Instant::now(); if let Some(file) = &task.file { @@ -384,7 +377,7 @@ impl Run { ); let task_names = tasks.keys().sorted().collect_vec(); let mut s = Select::new("Tasks") - .description("Select a task to run") + .description("Select a tasks to run") .filterable(true); for name in task_names { s = s.option(DemandOption::new(name)); @@ -393,7 +386,7 @@ impl Run { let name = s.run()?; match tasks.get(name) { Some(task) => Ok(task.clone()), - None => bail!("no task {} found", style::ered(name)), + None => bail!("no tasks {} found", style::ered(name)), } } @@ -524,11 +517,11 @@ fn last_modified_file(files: impl IntoIterator) -> Result
$ mise run lint - Runs the "lint" task. This needs to either be defined in .mise.toml + Runs the "lint" tasks. This needs to either be defined in .mise.toml or as a standalone script. See the project README for more information. $ mise run build --force - Forces the "build" task to run even if its sources are up-to-date. + Forces the "build" tasks to run even if its sources are up-to-date. $ mise run test --raw Runs "test" with stdin/stdout/stderr all connected to the current terminal. @@ -537,7 +530,7 @@ static AFTER_LONG_HELP: &str = color_print::cstr!( $ mise run lint ::: test ::: check Runs the "lint", "test", and "check" tasks in parallel. - $ mise task cmd1 arg1 arg2 ::: cmd2 arg1 arg2 + $ mise tasks cmd1 arg1 arg2 ::: cmd2 arg1 arg2 Execute multiple tasks each with their own arguments. "# ); diff --git a/src/cli/task/deps.rs b/src/cli/tasks/deps.rs similarity index 94% rename from src/cli/task/deps.rs rename to src/cli/tasks/deps.rs index 809aff375..585a46ce8 100644 --- a/src/cli/task/deps.rs +++ b/src/cli/tasks/deps.rs @@ -11,10 +11,10 @@ use petgraph::dot::Dot; /// [experimental] Display a tree visualization of a dependency graph #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] -pub struct TaskDeps { +pub struct TasksDeps { /// Tasks to show dependencies for /// Can specify multiple tasks by separating with spaces - /// e.g.: mise task deps lint test check + /// e.g.: mise tasks deps lint test check #[clap(verbatim_doc_comment)] pub tasks: Option>, @@ -23,7 +23,7 @@ pub struct TaskDeps { pub dot: bool, } -impl TaskDeps { +impl TasksDeps { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; @@ -136,19 +136,19 @@ impl TaskDeps { let tasks = config.tasks(); let task_names = tasks.keys().sorted().map(style::ecyan).join(", "); let t = style(&t).yellow().for_stderr(); - eyre!("no task named `{t}` found. Available tasks: {task_names}") + eyre!("no tasks named `{t}` found. Available tasks: {task_names}") } } static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ mise task deps + $ mise tasks deps Shows dependencies for all tasks - $ mise task deps lint test check + $ mise tasks deps lint test check Shows dependencies for the "lint", "test" and "check" tasks - $ mise task deps --dot + $ mise tasks deps --dot Shows dependencies in DOT format "# ); diff --git a/src/cli/task/edit.rs b/src/cli/tasks/edit.rs similarity index 81% rename from src/cli/task/edit.rs rename to src/cli/tasks/edit.rs index fe82761e9..4f588f5c1 100644 --- a/src/cli/task/edit.rs +++ b/src/cli/tasks/edit.rs @@ -4,22 +4,22 @@ use crate::config::{Config, Settings}; use crate::task::Task; use crate::{env, file}; -/// [experimental] Edit a task with $EDITOR +/// [experimental] Edit a tasks with $EDITOR /// -/// The task will be created as a standalone script if it does not already exist. +/// The tasks will be created as a standalone script if it does not already exist. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] -pub struct TaskEdit { - /// Task to edit +pub struct TasksEdit { + /// Tasks to edit #[clap()] task: String, - /// Display the path to the task instead of editing it + /// Display the path to the tasks instead of editing it #[clap(long, short, verbatim_doc_comment)] path: bool, } -impl TaskEdit { +impl TasksEdit { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; @@ -59,7 +59,7 @@ impl TaskEdit { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ mise task edit build - $ mise task edit test + $ mise tasks edit build + $ mise tasks edit test "# ); diff --git a/src/cli/task/ls.rs b/src/cli/tasks/ls.rs similarity index 93% rename from src/cli/task/ls.rs rename to src/cli/tasks/ls.rs index aed980aa1..23a44cf5c 100644 --- a/src/cli/task/ls.rs +++ b/src/cli/tasks/ls.rs @@ -17,7 +17,7 @@ use crate::ui::{style, table}; /// tasks will override the global ones if they have the same name. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] -pub struct TaskLs { +pub struct TasksLs { /// Do not print table header #[clap(long, alias = "no-headers", verbatim_doc_comment)] pub no_header: bool, @@ -27,11 +27,11 @@ pub struct TaskLs { pub hidden: bool, } -impl TaskLs { +impl TasksLs { pub fn run(self) -> Result<()> { let config = Config::try_get()?; let settings = Settings::try_get()?; - settings.ensure_experimental("`mise task ls`")?; + settings.ensure_experimental("`mise tasks ls`")?; let rows = config .tasks() .iter() @@ -59,7 +59,7 @@ struct Row { impl From<&Task> for Row { fn from(task: &Task) -> Self { - // let cmd = task.command_string().unwrap_or_default(); + // let cmd = tasks.command_string().unwrap_or_default(); Self { name: style::nbold(&task.name).bright().to_string(), description: style::nblue(truncate(&task.description, 40)).to_string(), @@ -80,7 +80,7 @@ fn truncate(s: &str, len: usize) -> String { // TODO: fill this out static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: - $ mise task ls + $ mise tasks ls "# ); diff --git a/src/cli/task/mod.rs b/src/cli/tasks/mod.rs similarity index 77% rename from src/cli/task/mod.rs rename to src/cli/tasks/mod.rs index 2a0617aed..8e509c31a 100644 --- a/src/cli/task/mod.rs +++ b/src/cli/tasks/mod.rs @@ -9,20 +9,20 @@ mod ls; /// [experimental] Manage tasks #[derive(Debug, clap::Args)] -#[clap(visible_alias = "t", alias = "tasks", verbatim_doc_comment)] -pub struct Task { +#[clap(visible_alias = "t", alias = "task", verbatim_doc_comment)] +pub struct Tasks { #[clap(subcommand)] command: Option, #[clap(flatten)] - ls: ls::TaskLs, + ls: ls::TasksLs, } #[derive(Debug, Subcommand)] enum Commands { - Deps(deps::TaskDeps), - Edit(edit::TaskEdit), - Ls(ls::TaskLs), + Deps(deps::TasksDeps), + Edit(edit::TasksEdit), + Ls(ls::TasksLs), Run(run::Run), } @@ -37,7 +37,7 @@ impl Commands { } } -impl Task { +impl Tasks { pub fn run(self) -> Result<()> { let cmd = self.command.unwrap_or(Commands::Ls(self.ls)); diff --git a/src/cli/watch.rs b/src/cli/watch.rs index b1e7abe2c..58d5e9d88 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -8,11 +8,11 @@ use crate::cmd; use crate::config::{Config, Settings}; use crate::toolset::ToolsetBuilder; -/// [experimental] Run a task watching for changes +/// [experimental] Run a tasks watching for changes #[derive(Debug, clap::Args)] #[clap(visible_alias = "w", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Watch { - /// Task to run + /// Tasks to run #[clap(short, long, verbatim_doc_comment, default_value = "default")] task: Vec, @@ -21,22 +21,22 @@ pub struct Watch { args: Vec, /// Files to watch - /// Defaults to sources from the task(s) + /// Defaults to sources from the tasks(s) #[clap(short, long, verbatim_doc_comment)] glob: Vec, // /// Change to this directory before executing the command // #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)] // pub cd: Option, // - // /// Don't actually run the task(s), just print them in order of execution + // /// Don't actually run the tasks(s), just print them in order of execution // #[clap(long, short = 'n', verbatim_doc_comment)] // pub dry_run: bool, // - // /// Force the task to run even if outputs are up to date + // /// Force the tasks to run even if outputs are up to date // #[clap(long, short, verbatim_doc_comment)] // pub force: bool, // - // /// Print stdout/stderr by line, prefixed with the task's label + // /// Print stdout/stderr by line, prefixed with the tasks's label // /// Defaults to true if --jobs > 1 // /// Configure with `task_output` config or `MISE_TASK_OUTPUT` env var // #[clap(long, short, verbatim_doc_comment, overrides_with = "interleave")] @@ -88,7 +88,7 @@ impl Watch { .tasks_with_aliases() .get(t) .cloned() - .ok_or_else(|| eyre!("Task not found: {t}")) + .ok_or_else(|| eyre!("Tasks not found: {t}")) }) .collect::>>()?; let mut args = vec![]; @@ -125,12 +125,12 @@ impl Watch { static AFTER_LONG_HELP: &str = color_print::cstr!( r#"Examples: $ mise watch -t build - Runs the "build" task. Will re-run the task when any of its sources change. - Uses "sources" from the task definition to determine which files to watch. + Runs the "build" tasks. Will re-run the tasks when any of its sources change. + Uses "sources" from the tasks definition to determine which files to watch. $ mise watch -t build --glob src/**/*.rs - Runs the "build" task but specify the files to watch with a glob pattern. - This overrides the "sources" from the task definition. + Runs the "build" tasks but specify the files to watch with a glob pattern. + This overrides the "sources" from the tasks definition. $ mise run -t build --clear Extra arguments are passed to watchexec. See `watchexec --help` for details. diff --git a/src/config/settings.rs b/src/config/settings.rs index f4513c571..a2afde817 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -305,10 +305,10 @@ impl Settings { Ok(settings) } - pub fn hidden_configs() -> HashSet<&'static str> { + pub fn hidden_configs() -> &'static HashSet<&'static str> { static HIDDEN_CONFIGS: Lazy> = Lazy::new(|| ["ci", "cd", "debug", "env_file", "trace", "log_level"].into()); - HIDDEN_CONFIGS.clone() + &HIDDEN_CONFIGS } pub fn reset(cli_settings: Option) { diff --git a/src/shims.rs b/src/shims.rs index 3c0c63a6b..19ba5b649 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -29,6 +29,7 @@ pub fn handle_shim() -> Result<()> { } logger::init(); let args = env::ARGS.read().unwrap(); + trace!("shim[{bin_name}] args: {}", args.join(" ")); let mut args: Vec = args.iter().map(OsString::from).collect(); args[0] = which_shim(&env::MISE_BIN_NAME)?.into(); let exec = Exec { @@ -47,6 +48,10 @@ fn which_shim(bin_name: &str) -> Result { let mut ts = ToolsetBuilder::new().build(&config)?; if let Some((p, tv)) = ts.which(bin_name) { if let Some(bin) = p.which(&tv, bin_name)? { + trace!( + "shim[{bin_name}] ToolVersion: {tv} bin: {bin}", + bin = display_path(&bin) + ); return Ok(bin); } } @@ -55,6 +60,10 @@ fn which_shim(bin_name: &str) -> Result { for tv in ts.install_missing_bin(bin_name)?.unwrap_or_default() { let p = tv.get_forge(); if let Some(bin) = p.which(&tv, bin_name)? { + trace!( + "shim[{bin_name}] NOT_FOUND ToolVersion: {tv} bin: {bin}", + bin = display_path(&bin) + ); return Ok(bin); } } @@ -68,6 +77,7 @@ fn which_shim(bin_name: &str) -> Result { } let bin = path.join(bin_name); if bin.exists() { + trace!("shim[{bin_name}] SYSTEM {bin}", bin = display_path(&bin)); return Ok(bin); } } diff --git a/src/task.rs b/src/task.rs index 49ecc8af5..2b7fea255 100644 --- a/src/task.rs +++ b/src/task.rs @@ -288,7 +288,7 @@ impl Deps { }) } - // fn pop(&'a mut self) -> Option<&'a Task> { + // fn pop(&'a mut self) -> Option<&'a Tasks> { // if let Some(leaf) = self.leaves().first() { // self.remove(&leaf.clone()) // } else { diff --git a/src/test.rs b/src/test.rs index 2f21e16d2..9ccf1a77e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -22,6 +22,7 @@ fn init() { ); env::set_current_dir(env::HOME.join("cwd")).unwrap(); env::remove_var("MISE_TRUSTED_CONFIG_PATHS"); + env::remove_var("MISE_DISABLE_TOOLS"); env::set_var("NO_COLOR", "1"); env::set_var("MISE_YES", "1"); env::set_var("MISE_USE_TOML", "0"); From fda1be6c61a23361606ce9e87c10d92b5f619344 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 13:46:44 -0600 Subject: [PATCH 1737/1891] tag version in docker --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a620d669e..5be46d9f7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -114,5 +114,5 @@ jobs: file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true - tags: jdxcode/mise:latest + tags: jdxcode/mise:latest,{% if startsWith(github.ref, 'refs/tags/v') %}jdxcode/mise:{{ github.ref_name }}{% endif %} labels: ${{ steps.meta.outputs.labels }} From 9adc7186b86a539e6f3e6a358d5822834e8be8fa Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 13:55:53 -0600 Subject: [PATCH 1738/1891] docker: fix github action --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5be46d9f7..2dee72ea8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -114,5 +114,5 @@ jobs: file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true - tags: jdxcode/mise:latest,{% if startsWith(github.ref, 'refs/tags/v') %}jdxcode/mise:{{ github.ref_name }}{% endif %} + tags: jdxcode/mise:latest,{% if startsWith(github.event.ref, 'refs/tags/v') %}jdxcode/mise:${{ github.ref_name }}{% endif %} labels: ${{ steps.meta.outputs.labels }} From 3849cdb8d0d4396e32fa9f555d03662efb2c41ab Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 13:57:22 -0600 Subject: [PATCH 1739/1891] docker: fix github action --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2dee72ea8..1ec991b0e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -114,5 +114,5 @@ jobs: file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true - tags: jdxcode/mise:latest,{% if startsWith(github.event.ref, 'refs/tags/v') %}jdxcode/mise:${{ github.ref_name }}{% endif %} + tags: jdxcode/mise:latest,jdxcode/mise:${{ github.ref_name }} labels: ${{ steps.meta.outputs.labels }} From ff3a5559dde35bd47ed072704bf2bc67478ce307 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 14:27:17 -0600 Subject: [PATCH 1740/1891] docker: skip cargo-msrv --- packaging/dev/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/dev/Dockerfile b/packaging/dev/Dockerfile index 2749ab324..9cd394cfe 100644 --- a/packaging/dev/Dockerfile +++ b/packaging/dev/Dockerfile @@ -33,7 +33,7 @@ RUN apt-get update \ cargo-insta \ cargo-llvm-cov \ cargo-machete \ - cargo-msrv \ + # cargo-msrv \ this is very slow to compile cargo-nextest \ cross \ just \ From 08429bbee21d2400282d584cca2c26fc1f469226 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Wed, 31 Jan 2024 15:35:54 -0500 Subject: [PATCH 1741/1891] fix(tasks): prevent dependency cycles (#1575) --- src/task.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/task.rs b/src/task.rs index 2b7fea255..137f7fe29 100644 --- a/src/task.rs +++ b/src/task.rs @@ -139,6 +139,7 @@ impl Task { .collect::>>()? .into_iter() .flatten() + .filter(|t| t.name != self.name) .collect(); Ok(depends) } From 90c35ab8885759c570a31fe73f8fec458d92a7ef Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Wed, 31 Jan 2024 15:37:42 -0500 Subject: [PATCH 1742/1891] feat(tasks): make script task dirs configurable (#1571) --- src/config/config_file/mise_toml.rs | 25 +++++++++++++++++-- src/config/config_file/mod.rs | 17 +++++++++++++ ...fig_file__mise_toml__tests__fixture-5.snap | 8 +++++- ...ile__mise_toml__tests__remove_alias-4.snap | 6 +++++ ...le__mise_toml__tests__remove_plugin-4.snap | 9 ++++++- ..._mise_toml__tests__replace_versions-4.snap | 9 ++++++- src/config/mod.rs | 20 ++++++++++++--- src/task.rs | 4 +-- 8 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 28f468ee2..bf68a9372 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -14,7 +14,7 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use versions::Versioning; use crate::cli::args::ForgeArg; -use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType}; +use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType, TaskConfig}; use crate::config::env_directive::EnvDirective; use crate::config::AliasMap; use crate::file::{create_dir_all, display_path}; @@ -49,6 +49,8 @@ pub struct MiseToml { doc: Document, #[serde(default)] plugins: HashMap, + #[serde(default)] + pub task_config: TaskConfig, #[serde(skip)] tasks: Vec, #[serde(skip)] @@ -116,6 +118,17 @@ impl MiseToml { self.env_path = cfg.env_path; self.min_version = cfg.min_version; self.plugins = cfg.plugins; + self.task_config = if cfg.task_config.includes.is_empty() && self.project_root.is_some() { + let pr = self.project_root.as_ref().unwrap(); + TaskConfig { + includes: vec![ + pr.join(".mise").join("tasks"), + pr.join(".config").join("mise").join("tasks"), + ], + } + } else { + cfg.task_config + }; // TODO: right now some things are parsed with serde (above) and some not (below) everything // should be moved to serde eventually @@ -126,7 +139,7 @@ impl MiseToml { "tools" => self.toolset = self.parse_toolset(k, v)?, "tasks" => self.tasks = self.parse_tasks(k, v)?, "alias" | "dotenv" | "env_file" | "env_path" | "min_version" | "settings" - | "env" | "plugins" => {} + | "env" | "plugins" | "task_config" => {} _ => bail!("unknown key: {}", style::ered(k)), } } @@ -564,6 +577,10 @@ impl ConfigFile for MiseToml { fn aliases(&self) -> AliasMap { self.alias.clone() } + + fn task_config(&self) -> TaskConfig { + self.task_config.clone() + } } impl Debug for MiseToml { @@ -588,6 +605,9 @@ impl Debug for MiseToml { if !self.plugins.is_empty() { d.field("plugins", &self.plugins); } + if !self.task_config.includes.is_empty() { + d.field("task_config", &self.task_config); + } d.finish() } } @@ -606,6 +626,7 @@ impl Clone for MiseToml { doc: self.doc.clone(), plugins: self.plugins.clone(), tasks: self.tasks.clone(), + task_config: self.task_config.clone(), is_trusted: Mutex::new(*self.is_trusted.lock().unwrap()), project_root: self.project_root.clone(), config_root: self.config_root.clone(), diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 85771e7e0..00141ecb3 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -7,6 +7,7 @@ use std::sync::Mutex; use eyre::Result; use once_cell::sync::Lazy; +use serde_derive::Deserialize; use versions::Versioning; use tool_versions::ToolVersions; @@ -77,6 +78,17 @@ pub trait ConfigFile: Debug + Send + Sync { fn aliases(&self) -> AliasMap { Default::default() } + fn task_config(&self) -> TaskConfig { + let includes = match self.project_root() { + Some(pr) => vec![ + pr.join(".mise").join("tasks"), + pr.join(".config").join("mise").join("tasks"), + ], + None => vec![], + }; + + TaskConfig { includes } + } } impl dyn ConfigFile { @@ -327,6 +339,11 @@ impl Hash for dyn ConfigFile { } } +#[derive(Clone, Debug, Default, Deserialize)] +pub struct TaskConfig { + pub includes: Vec, +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap index 81c72851c..4aa9eac98 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/mise_toml.rs -expression: "replace_path(&format!(\"{:#?}\", &cf))" +expression: "replace_path(&format!(\"{:#?}\", & cf))" --- MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { env: [ @@ -17,4 +17,10 @@ MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@re plugins: { "node": "https://github.com/jdx/rtx-node", }, + task_config: TaskConfig { + includes: [ + "~/fixtures/.mise/tasks", + "~/fixtures/.config/mise/tasks", + ], + }, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index 09d6b2add..0ebc5b37e 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -8,4 +8,10 @@ MiseToml(/tmp/.mise.toml): { "18": "18.0.0", }, }, + task_config: TaskConfig { + includes: [ + "/tmp/.mise/tasks", + "/tmp/.config/mise/tasks", + ], + }, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap index 11ebdc792..fb0d1cad8 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap @@ -2,4 +2,11 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): +MiseToml(/tmp/.mise.toml): { + task_config: TaskConfig { + includes: [ + "/tmp/.mise/tasks", + "/tmp/.config/mise/tasks", + ], + }, +} diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap index f68cdeb00..692c0a506 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap @@ -2,4 +2,11 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 +MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 { + task_config: TaskConfig { + includes: [ + "/tmp/.mise/tasks", + "/tmp/.config/mise/tasks", + ], + }, +} diff --git a/src/config/mod.rs b/src/config/mod.rs index d06e6ce32..82bbba771 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -9,6 +9,7 @@ use eyre::{Context, Result}; use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::{Lazy, OnceCell}; +use path_absolutize::Absolutize; use rayon::prelude::*; pub use settings::Settings; @@ -216,10 +217,21 @@ impl Config { .into_par_iter() .flat_map(|cf| { match cf.project_root() { - Some(pr) => vec![ - pr.join(".mise").join("tasks"), - pr.join(".config").join("mise").join("tasks"), - ], + Some(pr) => cf + .task_config() + .includes + .iter() + .map(|p| { + if p.is_absolute() { + return p.clone(); + } + + file::replace_path(p) + .absolutize_from(pr) + .unwrap() + .to_path_buf() + }) + .collect(), None => vec![], } .into_par_iter() diff --git a/src/task.rs b/src/task.rs index 137f7fe29..16592d7ac 100644 --- a/src/task.rs +++ b/src/task.rs @@ -324,7 +324,7 @@ fn config_root(config_source: &impl AsRef) -> Option<&Path> { } } - Some(config_source.as_ref()) + config_source.as_ref().parent() } pub trait GetMatchingExt { @@ -384,7 +384,7 @@ mod tests { #[test] fn test_config_root() { let test_cases = [ - ("/base", Some(Path::new("/base"))), + ("/base", Some(Path::new("/"))), ("/base/.mise/tasks", Some(Path::new("/base"))), ("/base/.config/mise/tasks", Some(Path::new("/base"))), ]; From 7568969f281a428c07144d79643b31699b068c54 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:19:57 -0600 Subject: [PATCH 1743/1891] refactor task_config --- src/cli/run.rs | 6 +- src/cli/tasks/deps.rs | 15 ++-- src/cli/tasks/edit.rs | 2 +- src/cli/tasks/ls.rs | 4 +- src/cli/watch.rs | 2 +- src/config/config_file/mise_toml.rs | 18 +--- src/config/config_file/mod.rs | 15 +--- ...fig_file__mise_toml__tests__fixture-5.snap | 8 +- ...ile__mise_toml__tests__remove_alias-4.snap | 6 -- ...le__mise_toml__tests__remove_plugin-4.snap | 9 +- ..._mise_toml__tests__replace_versions-4.snap | 9 +- src/config/mod.rs | 88 ++++++++++--------- src/task.rs | 2 +- 13 files changed, 73 insertions(+), 111 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index f78fd67f6..f24616380 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -139,7 +139,7 @@ impl Run { }) .flat_map(|args| args.split_first().map(|(t, a)| (t.clone(), a.to_vec()))) .map(|(t, args)| { - let tasks = config.tasks_with_aliases().get_matching(&t)?; + let tasks = config.tasks_with_aliases()?.get_matching(&t)?; if tasks.is_empty() { ensure!(t == "default", "no tasks {} found", style::ered(t)); @@ -369,7 +369,7 @@ impl Run { } fn prompt_for_task(&self, config: &Config) -> Result { - let tasks = config.tasks(); + let tasks = config.tasks()?; ensure!( !tasks.is_empty(), "no tasks defined. see {url}", @@ -385,7 +385,7 @@ impl Run { let _ = ctrlc::handle_ctrlc()?; let name = s.run()?; match tasks.get(name) { - Some(task) => Ok(task.clone()), + Some(task) => Ok((*task).clone()), None => bail!("no tasks {} found", style::ered(name)), } } diff --git a/src/cli/tasks/deps.rs b/src/cli/tasks/deps.rs index 585a46ce8..1498ac96d 100644 --- a/src/cli/tasks/deps.rs +++ b/src/cli/tasks/deps.rs @@ -45,21 +45,20 @@ impl TasksDeps { } fn get_all_tasks(&self, config: &Config) -> Result> { - config - .tasks() - .iter() - .map(|(_, t)| t) + Ok(config + .tasks()? + .into_values() .sorted() .filter(|t| !t.hide) - .map(|t| Ok(t.to_owned())) - .collect() + .cloned() + .collect()) } fn get_task_lists(&self, config: &Config) -> Result> { let tasks = self.tasks.as_ref().map(|t| { t.iter() .sorted() - .map(|tn| match config.tasks().get(tn) { + .map(|tn| match config.tasks()?.remove(tn) { Some(task) => Ok(task.clone()), None => Err(self.err_no_task(config, tn.as_str())), }) @@ -133,7 +132,7 @@ impl TasksDeps { } fn err_no_task(&self, config: &Config, t: &str) -> eyre::Report { - let tasks = config.tasks(); + let tasks = config.tasks().unwrap_or_default(); let task_names = tasks.keys().sorted().map(style::ecyan).join(", "); let t = style(&t).yellow().for_stderr(); eyre!("no tasks named `{t}` found. Available tasks: {task_names}") diff --git a/src/cli/tasks/edit.rs b/src/cli/tasks/edit.rs index 4f588f5c1..f17839f68 100644 --- a/src/cli/tasks/edit.rs +++ b/src/cli/tasks/edit.rs @@ -26,7 +26,7 @@ impl TasksEdit { settings.ensure_experimental("`mise tasks edit`")?; let task = config - .tasks_with_aliases() + .tasks_with_aliases()? .get(&self.task) .cloned() .map_or_else( diff --git a/src/cli/tasks/ls.rs b/src/cli/tasks/ls.rs index 23a44cf5c..6bdbb3e49 100644 --- a/src/cli/tasks/ls.rs +++ b/src/cli/tasks/ls.rs @@ -33,8 +33,8 @@ impl TasksLs { let settings = Settings::try_get()?; settings.ensure_experimental("`mise tasks ls`")?; let rows = config - .tasks() - .iter() + .tasks()? + .into_iter() .map(|(_, t)| t) .sorted() .filter(|t| self.hidden || !t.hide) diff --git a/src/cli/watch.rs b/src/cli/watch.rs index 58d5e9d88..4e694c44c 100644 --- a/src/cli/watch.rs +++ b/src/cli/watch.rs @@ -85,7 +85,7 @@ impl Watch { .iter() .map(|t| { config - .tasks_with_aliases() + .tasks_with_aliases()? .get(t) .cloned() .ok_or_else(|| eyre!("Tasks not found: {t}")) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index bf68a9372..6affb1535 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -118,17 +118,7 @@ impl MiseToml { self.env_path = cfg.env_path; self.min_version = cfg.min_version; self.plugins = cfg.plugins; - self.task_config = if cfg.task_config.includes.is_empty() && self.project_root.is_some() { - let pr = self.project_root.as_ref().unwrap(); - TaskConfig { - includes: vec![ - pr.join(".mise").join("tasks"), - pr.join(".config").join("mise").join("tasks"), - ], - } - } else { - cfg.task_config - }; + self.task_config = cfg.task_config; // TODO: right now some things are parsed with serde (above) and some not (below) everything // should be moved to serde eventually @@ -578,8 +568,8 @@ impl ConfigFile for MiseToml { self.alias.clone() } - fn task_config(&self) -> TaskConfig { - self.task_config.clone() + fn task_config(&self) -> &TaskConfig { + &self.task_config } } @@ -605,7 +595,7 @@ impl Debug for MiseToml { if !self.plugins.is_empty() { d.field("plugins", &self.plugins); } - if !self.task_config.includes.is_empty() { + if self.task_config.includes.is_some() { d.field("task_config", &self.task_config); } d.finish() diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 00141ecb3..907c3a4b2 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -78,16 +78,9 @@ pub trait ConfigFile: Debug + Send + Sync { fn aliases(&self) -> AliasMap { Default::default() } - fn task_config(&self) -> TaskConfig { - let includes = match self.project_root() { - Some(pr) => vec![ - pr.join(".mise").join("tasks"), - pr.join(".config").join("mise").join("tasks"), - ], - None => vec![], - }; - - TaskConfig { includes } + fn task_config(&self) -> &TaskConfig { + static DEFAULT_TASK_CONFIG: Lazy = Lazy::new(|| TaskConfig::default()); + &DEFAULT_TASK_CONFIG } } @@ -341,7 +334,7 @@ impl Hash for dyn ConfigFile { #[derive(Clone, Debug, Default, Deserialize)] pub struct TaskConfig { - pub includes: Vec, + pub includes: Option>, } #[cfg(test)] diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap index 4aa9eac98..81c72851c 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__fixture-5.snap @@ -1,6 +1,6 @@ --- source: src/config/config_file/mise_toml.rs -expression: "replace_path(&format!(\"{:#?}\", & cf))" +expression: "replace_path(&format!(\"{:#?}\", &cf))" --- MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@ref:master node@path:~/.nodes/18, jq@prefix:1.6, shellcheck@0.9.0, python@3.10.0 python@3.9.0 { env: [ @@ -17,10 +17,4 @@ MiseToml(~/fixtures/.mise.toml): terraform@1.0.0, node@18 node@prefix:20 node@re plugins: { "node": "https://github.com/jdx/rtx-node", }, - task_config: TaskConfig { - includes: [ - "~/fixtures/.mise/tasks", - "~/fixtures/.config/mise/tasks", - ], - }, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index 0ebc5b37e..09d6b2add 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -8,10 +8,4 @@ MiseToml(/tmp/.mise.toml): { "18": "18.0.0", }, }, - task_config: TaskConfig { - includes: [ - "/tmp/.mise/tasks", - "/tmp/.config/mise/tasks", - ], - }, } diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap index fb0d1cad8..11ebdc792 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_plugin-4.snap @@ -2,11 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): { - task_config: TaskConfig { - includes: [ - "/tmp/.mise/tasks", - "/tmp/.config/mise/tasks", - ], - }, -} +MiseToml(/tmp/.mise.toml): diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap index 692c0a506..f68cdeb00 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__replace_versions-4.snap @@ -2,11 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 { - task_config: TaskConfig { - includes: [ - "/tmp/.mise/tasks", - "/tmp/.config/mise/tasks", - ], - }, -} +MiseToml(/tmp/.mise.toml): node@16.0.1 node@18.0.1 diff --git a/src/config/mod.rs b/src/config/mod.rs index 82bbba771..a72b9a9a2 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -47,7 +47,6 @@ pub struct Config { all_aliases: OnceCell, repo_urls: HashMap, shorthands: OnceCell>, - tasks: OnceCell>, tasks_with_aliases: OnceCell>, } @@ -86,7 +85,6 @@ impl Config { aliases: load_aliases(&config_files), all_aliases: OnceCell::new(), shorthands: OnceCell::new(), - tasks: OnceCell::new(), tasks_with_aliases: OnceCell::new(), project_root: get_project_root(&config_files), config_files, @@ -150,18 +148,17 @@ impl Config { self.all_aliases.get_or_init(|| self.load_all_aliases()) } - pub fn tasks(&self) -> &HashMap { - self.tasks.get_or_init(|| { - self.load_all_tasks() - .into_iter() - .filter(|(n, t)| *n == t.name) - .collect() - }) + pub fn tasks(&self) -> Result> { + Ok(self + .tasks_with_aliases()? + .iter() + .filter(|(n, t)| **n == *t.name) + .collect()) } - pub fn tasks_with_aliases(&self) -> &HashMap { + pub fn tasks_with_aliases(&self) -> Result<&HashMap> { self.tasks_with_aliases - .get_or_init(|| self.load_all_tasks()) + .get_or_try_init(|| self.load_all_tasks()) } pub fn is_activated(&self) -> bool { @@ -210,40 +207,42 @@ impl Config { aliases } - pub fn load_all_tasks(&self) -> HashMap { - self.config_files + pub fn load_all_tasks(&self) -> Result> { + Ok(self + .config_files .values() .collect_vec() .into_par_iter() - .flat_map(|cf| { - match cf.project_root() { - Some(pr) => cf - .task_config() - .includes - .iter() - .map(|p| { - if p.is_absolute() { - return p.clone(); + .map(|cf| { + Ok(cf + .task_config() + .includes + .clone() + .unwrap_or_else(|| default_task_includes(&cf)) + .iter() + .map(|p| { + if let Some(pr) = cf.project_root() { + if p.is_relative() { + return Ok(file::replace_path(p) + .absolutize_from(pr) + .map(|p| p.to_path_buf())?); } - - file::replace_path(p) - .absolutize_from(pr) - .unwrap() - .to_path_buf() - }) - .collect(), - None => vec![], - } - .into_par_iter() - .flat_map(|dir| { - file::recursive_ls(&dir).map_err(|err| warn!("load_all_tasks: {err}")) - }) - .flatten() - .map(Either::Right) - .chain(rayon::iter::once(Either::Left(cf))) + } + Ok(p.to_path_buf()) + }) + .collect::>>()? + .into_par_iter() + .flat_map(|dir| { + file::recursive_ls(&dir).map_err(|err| warn!("load_all_tasks: {err}")) + }) + .flatten() + .map(Either::Right) + .chain(rayon::iter::once(Either::Left(cf))) + .collect::>>()) }) - .collect::, PathBuf>>>() + .collect::>>()? .into_iter() + .flatten() .rev() .unique() .collect_vec() @@ -268,7 +267,7 @@ impl Config { .collect::>() .into_iter() .rev() - .collect() + .collect()) } pub fn get_tracked_config_files(&self) -> Result { @@ -550,7 +549,7 @@ impl Debug for Config { .collect::>(); let mut s = f.debug_struct("Config"); s.field("Config Files", &config_files); - if let Some(tasks) = self.tasks.get() { + if let Some(tasks) = self.tasks_with_aliases.get() { s.field( "Tasks", &tasks.values().map(|t| t.to_string()).collect_vec(), @@ -573,6 +572,13 @@ impl Debug for Config { } } +fn default_task_includes(cf: &Box) -> Vec { + match cf.project_root() { + Some(pr) => vec![pr.join(".mise/tasks"), pr.join(".config/mise/tasks")], + None => vec![], + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/task.rs b/src/task.rs index 16592d7ac..1621167b9 100644 --- a/src/task.rs +++ b/src/task.rs @@ -131,7 +131,7 @@ impl Task { } pub fn resolve_depends<'a>(&self, config: &'a Config) -> Result> { - let tasks = config.tasks_with_aliases(); + let tasks = config.tasks_with_aliases()?; let depends = self .depends .iter() From 779c48491dfc223c2a7c8c80b8396ba9050ec54d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:21:29 -0600 Subject: [PATCH 1744/1891] docker: fix test runner --- .github/workflows/docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1ec991b0e..35161dd5d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -90,6 +90,7 @@ jobs: steps: - uses: actions/checkout@v4 - run: cargo install --path . --debug + - run: mise trust --all - run: mise install -y - run: mise run test dockerhub: From 438e6a4dec10e17b0cffca1d921acedf7d6db324 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:39:51 -0600 Subject: [PATCH 1745/1891] tasks: refactor to use BTreeMap instead of sorting --- src/cli/run.rs | 6 ++---- src/cli/tasks/deps.rs | 14 +++++++------- src/cli/tasks/ls.rs | 5 +---- src/config/mod.rs | 8 ++++---- src/task.rs | 31 ++++++++++++++----------------- 5 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index f24616380..34c1f0c95 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -146,8 +146,7 @@ impl Run { Ok(vec![self.prompt_for_task(config)?]) } else { Ok(tasks - .iter() - .cloned() + .into_iter() .map(|t| t.clone().with_args(args.to_vec())) .collect()) } @@ -375,11 +374,10 @@ impl Run { "no tasks defined. see {url}", url = style::eunderline("https://mise.jdx.dev/tasks/") ); - let task_names = tasks.keys().sorted().collect_vec(); let mut s = Select::new("Tasks") .description("Select a tasks to run") .filterable(true); - for name in task_names { + for name in tasks.keys() { s = s.option(DemandOption::new(name)); } let _ = ctrlc::handle_ctrlc()?; diff --git a/src/cli/tasks/deps.rs b/src/cli/tasks/deps.rs index 1498ac96d..0a1ee7dcb 100644 --- a/src/cli/tasks/deps.rs +++ b/src/cli/tasks/deps.rs @@ -1,12 +1,13 @@ +use console::style; +use eyre::Result; +use itertools::Itertools; +use petgraph::dot::Dot; + use crate::{ config::{Config, Settings}, task::{Deps, Task}, ui::{style, tree::print_tree}, }; -use console::style; -use eyre::Result; -use itertools::Itertools; -use petgraph::dot::Dot; /// [experimental] Display a tree visualization of a dependency graph #[derive(Debug, clap::Args)] @@ -48,17 +49,16 @@ impl TasksDeps { Ok(config .tasks()? .into_values() - .sorted() .filter(|t| !t.hide) .cloned() .collect()) } fn get_task_lists(&self, config: &Config) -> Result> { + let tasks = config.tasks()?; let tasks = self.tasks.as_ref().map(|t| { t.iter() - .sorted() - .map(|tn| match config.tasks()?.remove(tn) { + .map(|tn| match tasks.get(tn).cloned() { Some(task) => Ok(task.clone()), None => Err(self.err_no_task(config, tn.as_str())), }) diff --git a/src/cli/tasks/ls.rs b/src/cli/tasks/ls.rs index 6bdbb3e49..5005a0118 100644 --- a/src/cli/tasks/ls.rs +++ b/src/cli/tasks/ls.rs @@ -1,6 +1,5 @@ use console::truncate_str; use eyre::Result; -use itertools::Itertools; use tabled::Tabled; use crate::config::{Config, Settings}; @@ -34,9 +33,7 @@ impl TasksLs { settings.ensure_experimental("`mise tasks ls`")?; let rows = config .tasks()? - .into_iter() - .map(|(_, t)| t) - .sorted() + .into_values() .filter(|t| self.hidden || !t.hide) .map(|t| t.into()) .collect::>(); diff --git a/src/config/mod.rs b/src/config/mod.rs index a72b9a9a2..eb4586818 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -47,7 +47,7 @@ pub struct Config { all_aliases: OnceCell, repo_urls: HashMap, shorthands: OnceCell>, - tasks_with_aliases: OnceCell>, + tasks_with_aliases: OnceCell>, } static CONFIG: RwLock>> = RwLock::new(None); @@ -148,7 +148,7 @@ impl Config { self.all_aliases.get_or_init(|| self.load_all_aliases()) } - pub fn tasks(&self) -> Result> { + pub fn tasks(&self) -> Result> { Ok(self .tasks_with_aliases()? .iter() @@ -156,7 +156,7 @@ impl Config { .collect()) } - pub fn tasks_with_aliases(&self) -> Result<&HashMap> { + pub fn tasks_with_aliases(&self) -> Result<&BTreeMap> { self.tasks_with_aliases .get_or_try_init(|| self.load_all_tasks()) } @@ -207,7 +207,7 @@ impl Config { aliases } - pub fn load_all_tasks(&self) -> Result> { + pub fn load_all_tasks(&self) -> Result> { Ok(self .config_files .values() diff --git a/src/task.rs b/src/task.rs index 1621167b9..f2c3b313d 100644 --- a/src/task.rs +++ b/src/task.rs @@ -1,10 +1,6 @@ -use globset::Glob; -use petgraph::graph::DiGraph; -use petgraph::prelude::*; -use petgraph::{Direction, Graph}; use std::borrow::Cow; use std::cmp::Ordering; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::ffi; use std::fmt; use std::fmt::{Display, Formatter}; @@ -15,7 +11,11 @@ use std::sync::mpsc; use console::truncate_str; use eyre::Result; +use globset::Glob; use itertools::Itertools; +use petgraph::graph::DiGraph; +use petgraph::prelude::*; +use petgraph::{Direction, Graph}; use crate::config::config_file::toml::TomlParser; use crate::config::Config; @@ -132,16 +132,12 @@ impl Task { pub fn resolve_depends<'a>(&self, config: &'a Config) -> Result> { let tasks = config.tasks_with_aliases()?; - let depends = self - .depends + self.depends .iter() .map(|pat| match_tasks(tasks, pat)) - .collect::>>()? - .into_iter() - .flatten() - .filter(|t| t.name != self.name) - .collect(); - Ok(depends) + .flatten_ok() + .filter_ok(|t| t.name != self.name) + .collect() } } @@ -161,7 +157,7 @@ fn name_from_path(root: impl AsRef, path: impl AsRef) -> Result(tasks: &'a HashMap, pat: &str) -> Result> { +fn match_tasks<'a>(tasks: &'a BTreeMap, pat: &str) -> Result> { let matches = tasks.get_matching(pat)?; if matches.is_empty() { return Err(eyre!("task not found: {pat}")); @@ -331,9 +327,9 @@ pub trait GetMatchingExt { fn get_matching(&self, pat: &str) -> Result>; } -impl GetMatchingExt for std::collections::HashMap +impl GetMatchingExt for BTreeMap where - T: std::cmp::Eq + std::hash::Hash, + T: Eq + Hash, { fn get_matching(&self, pat: &str) -> Result> { let normalized = pat.split(':').collect::(); @@ -354,9 +350,10 @@ where #[cfg(test)] mod tests { - use super::{config_root, name_from_path}; use std::path::Path; + use super::{config_root, name_from_path}; + #[test] fn test_name_from_path() { let test_cases = [ From b92566ffc2ccf2336fafddff3bb5dd62536b1f5f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:44:53 -0600 Subject: [PATCH 1746/1891] docker: fix dev test --- e2e/test_tool_versions_alt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index d24b9e1ba..ea47c3d82 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -4,7 +4,9 @@ set -euo pipefail export MISE_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions export MISE_DEFAULT_CONFIG_FILENAME=.MISSING -git checkout .alternate-tool-versions +cat < .alternate-tool-versions +shfmt 3.5.0 +EOF mise i shfmt mise exec -- shfmt --version >&2 From de5e5b6b33063e577f53ceb8f8de14b5035c1c4d Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:15:21 -0600 Subject: [PATCH 1747/1891] ci: skip checkout for homebrew bump --- .github/workflows/release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 79c89a7a3..7fa533d23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -241,8 +241,6 @@ jobs: continue-on-error: true if: startsWith(github.event.ref, 'refs/tags/v') steps: - - name: Checkout repository - uses: actions/checkout@v4 - name: Bump Homebrew formula uses: dawidd6/action-homebrew-bump-formula@v3 with: From 6c6afe194872030ec0fc3be7f8ffacd9ca71de25 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:16:48 -0600 Subject: [PATCH 1748/1891] status: make missing tool warning more granular (#1577) * settings: added some missing settings to `settings set` * Commit from GitHub Actions (test) * wip --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- completions/_mise | 2 +- completions/mise.fish | 2 +- docs/cli-reference.md | 4 +++- e2e/test_tool_versions_alt | 2 +- src/cli/activate.rs | 2 ++ src/cli/ls.rs | 2 +- src/cli/settings/ls.rs | 5 ++++- src/cli/settings/set.rs | 22 ++++++++++++++++++++-- src/cli/settings/unset.rs | 1 - src/config/config_file/mod.rs | 2 +- src/config/mod.rs | 2 +- src/config/settings.rs | 20 ++++++++++++++++++-- src/toolset/mod.rs | 19 +++++++++++++++++-- 13 files changed, 70 insertions(+), 15 deletions(-) diff --git a/completions/_mise b/completions/_mise index 5569bc0c8..ef228c483 100644 --- a/completions/_mise +++ b/completions/_mise @@ -429,7 +429,7 @@ __mise_ls_cmd() { '*::plugin:__mise_plugins' \ '(-c --current)'{-c,--current}'[Only show tool versions currently specified in a .tool-versions/.mise.toml]' \ '(-g --global)'{-g,--global}'[Only show tool versions currently specified in a the global .tool-versions/.mise.toml]' \ - '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed]' \ + '(-i --installed)'{-i,--installed}'[Only show tool versions that are installed (Hides tools defined in .tool-versions/.mise.toml but not installed)]' \ '(-J --json)'{-J,--json}'[Output in json format]' \ '(-m --missing)'{-m,--missing}'[Display missing tool versions]' \ '--prefix=[Display versions matching this prefix]:prefix:__mise_prefixes' \ diff --git a/completions/mise.fish b/completions/mise.fish index 6a5580da4..37984fa3f 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -152,7 +152,7 @@ complete -kxc mise -n "$fssf link" -a "(__mise_tool_versions)" -d 'Tool name and # ls complete -kxc mise -n "$fssf ls" -s c -l current -d 'Only show tool versions currently specified in a .tool-versions/.mise.toml' complete -kxc mise -n "$fssf ls" -s g -l global -d 'Only show tool versions currently specified in a the global .tool-versions/.mise.toml' -complete -kxc mise -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed' +complete -kxc mise -n "$fssf ls" -s i -l installed -d 'Only show tool versions that are installed (Hides tools defined in .tool-versions/.mise.toml but not installed)' complete -kxc mise -n "$fssf ls" -s J -l json -d 'Output in json format' complete -kxc mise -n "$fssf ls" -s m -l missing -d 'Display missing tool versions' complete -kxc mise -n "$fssf ls" -l no-header -d 'Don'\''t display headers' diff --git a/docs/cli-reference.md b/docs/cli-reference.md index d411e970c..dde2b97eb 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -24,6 +24,8 @@ specify the full path like this: echo 'eval "$(/path/to/mise activate)"' >> ~/.zshrc +Customize status output with `status` settings. + Usage: activate [OPTIONS] [SHELL_TYPE] Arguments: @@ -515,7 +517,7 @@ Options: Only show tool versions currently specified in a the global .tool-versions/.mise.toml -i, --installed - Only show tool versions that are installed Hides missing ones defined in .tool-versions/.mise.toml but not yet installed + Only show tool versions that are installed (Hides tools defined in .tool-versions/.mise.toml but not installed) -J, --json Output in json format diff --git a/e2e/test_tool_versions_alt b/e2e/test_tool_versions_alt index ea47c3d82..f6a890aff 100755 --- a/e2e/test_tool_versions_alt +++ b/e2e/test_tool_versions_alt @@ -4,7 +4,7 @@ set -euo pipefail export MISE_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions export MISE_DEFAULT_CONFIG_FILENAME=.MISSING -cat < .alternate-tool-versions +cat <.alternate-tool-versions shfmt 3.5.0 EOF diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 774908a39..11d30f386 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -24,6 +24,8 @@ use crate::{dirs, env}; /// specify the full path like this: /// /// echo 'eval "$(/path/to/mise activate)"' >> ~/.zshrc +/// +/// Customize status output with `status` settings. #[derive(Debug, clap::Args)] #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Activate { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index aa3da11d9..c2c673cc1 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -38,7 +38,7 @@ pub struct Ls { global: bool, /// Only show tool versions that are installed - /// Hides missing ones defined in .tool-versions/.mise.toml but not yet installed + /// (Hides tools defined in .tool-versions/.mise.toml but not installed) #[clap(long, short)] installed: bool, diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 3fbd79911..5fedcaa5e 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -24,6 +24,10 @@ impl SettingsLs { if Settings::hidden_configs().contains(key.as_str()) { continue; } + if key == "status" { + // TODO: print this properly + continue; + } miseprintln!("{} = {}", key, value); } Ok(()) @@ -73,7 +77,6 @@ mod tests { quiet = false raw = false shorthands_file = null - status = {"missing_tools":true,"show_env":false,"show_tools":false} task_output = null trusted_config_paths = [] verbose = true diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 389cdbb79..55428024f 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,6 +1,7 @@ use eyre::Result; use toml_edit::Document; +use crate::config::settings::SettingsStatusMissingTools; use crate::{env, file}; /// Add/update a setting @@ -19,6 +20,7 @@ pub struct SettingsSet { impl SettingsSet { pub fn run(self) -> Result<()> { let value: toml_edit::Value = match self.setting.as_str() { + "activate_aggressive" => parse_bool(&self.value)?, "all_compile" => parse_bool(&self.value)?, "always_keep_download" => parse_bool(&self.value)?, "always_keep_install" => parse_bool(&self.value)?, @@ -38,6 +40,13 @@ impl SettingsSet { "quiet" => parse_bool(&self.value)?, "raw" => parse_bool(&self.value)?, "shorthands_file" => self.value.into(), + "status.missing_tools" => self + .value + .parse::()? + .to_string() + .into(), + "status.show_env" => parse_bool(&self.value)?, + "status.show_tools" => parse_bool(&self.value)?, "task_output" => self.value.into(), "trusted_config_paths" => self.value.split(':').map(|s| s.to_string()).collect(), "verbose" => parse_bool(&self.value)?, @@ -53,7 +62,16 @@ impl SettingsSet { config["settings"] = toml_edit::Item::Table(toml_edit::Table::new()); } let settings = config["settings"].as_table_mut().unwrap(); - settings.insert(&self.setting, toml_edit::Item::Value(value)); + if self.setting.as_str().starts_with("status.") { + let status = settings + .entry("status") + .or_insert(toml_edit::Item::Table(toml_edit::Table::new())) + .as_table_mut() + .unwrap(); + status.insert(&self.setting[7..], toml_edit::Item::Value(value)); + } else { + settings.insert(&self.setting, toml_edit::Item::Value(value)); + } file::write(path, config.to_string()) } } @@ -88,6 +106,7 @@ pub mod tests { reset_config(); assert_cli!("settings", "set", "legacy_version_file", "0"); assert_cli!("settings", "set", "always_keep_download", "y"); + assert_cli!("settings", "set", "status.missing_tools", "never"); assert_cli!( "settings", "set", @@ -124,7 +143,6 @@ pub mod tests { quiet = false raw = false shorthands_file = null - status = {"missing_tools":true,"show_env":false,"show_tools":false} task_output = null trusted_config_paths = [] verbose = true diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 15f5a2bcb..7b253595b 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -68,7 +68,6 @@ mod tests { quiet = false raw = false shorthands_file = null - status = {"missing_tools":true,"show_env":false,"show_tools":false} task_output = null trusted_config_paths = [] verbose = true diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 907c3a4b2..693a3346e 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -79,7 +79,7 @@ pub trait ConfigFile: Debug + Send + Sync { Default::default() } fn task_config(&self) -> &TaskConfig { - static DEFAULT_TASK_CONFIG: Lazy = Lazy::new(|| TaskConfig::default()); + static DEFAULT_TASK_CONFIG: Lazy = Lazy::new(TaskConfig::default); &DEFAULT_TASK_CONFIG } } diff --git a/src/config/mod.rs b/src/config/mod.rs index eb4586818..5d9da0bfe 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -218,7 +218,7 @@ impl Config { .task_config() .includes .clone() - .unwrap_or_else(|| default_task_includes(&cf)) + .unwrap_or_else(|| default_task_includes(cf)) .iter() .map(|p| { if let Some(pr) = cf.project_root() { diff --git a/src/config/settings.rs b/src/config/settings.rs index a2afde817..01206c0f4 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -115,8 +115,11 @@ pub struct Settings { #[config(partial_attr(serde(deny_unknown_fields)))] pub struct SettingsStatus { /// warn if a tool is missing - #[config(env = "MISE_STATUS_MESSAGE_MISSING_TOOLS", default = true)] - pub missing_tools: bool, + #[config( + env = "MISE_STATUS_MESSAGE_MISSING_TOOLS", + default = "if_other_versions_installed" + )] + pub missing_tools: SettingsStatusMissingTools, /// show env var keys when entering directories #[config(env = "MISE_STATUS_MESSAGE_SHOW_ENV", default = false)] pub show_env: bool, @@ -125,6 +128,19 @@ pub struct SettingsStatus { pub show_tools: bool, } +#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, EnumString, Display)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum SettingsStatusMissingTools { + /// never show the warning + Never, + /// hide this warning if the user hasn't installed at least 1 version of the tool before + #[default] + IfOtherVersionsInstalled, + /// always show the warning if tools are missing + Always, +} + pub type SettingsPartial = ::Partial; static SETTINGS: RwLock>> = RwLock::new(None); diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 9d940feef..ae74087ee 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -17,6 +17,7 @@ pub use tool_version_list::ToolVersionList; pub use tool_version_request::ToolVersionRequest; use crate::cli::args::ForgeArg; +use crate::config::settings::SettingsStatusMissingTools; use crate::config::{Config, Settings}; use crate::env::TERM_WIDTH; use crate::forge::Forge; @@ -387,9 +388,23 @@ impl Toolset { .collect()) } + // shows a warning if any versions are missing + // only displays for tools which have at least one version already installed pub fn notify_if_versions_missing(&self) { - let missing = self.list_missing_versions(); - if missing.is_empty() || !Settings::get().status.missing_tools { + let settings = Settings::get(); + let missing = self + .list_missing_versions() + .into_iter() + .filter(|tv| match settings.status.missing_tools { + SettingsStatusMissingTools::Never => false, + SettingsStatusMissingTools::Always => true, + SettingsStatusMissingTools::IfOtherVersionsInstalled => tv + .get_forge() + .list_installed_versions() + .is_ok_and(|f| !f.is_empty()), + }) + .collect_vec(); + if missing.is_empty() { return; } let versions = missing From 50c146802aaf4f5f0046ccac620712a5338b1860 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:18:21 -0600 Subject: [PATCH 1749/1891] default --quiet to error level --- src/config/mod.rs | 4 ++-- src/config/settings.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 5d9da0bfe..b18af1c81 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -218,7 +218,7 @@ impl Config { .task_config() .includes .clone() - .unwrap_or_else(|| default_task_includes(cf)) + .unwrap_or_else(|| default_task_includes(cf.as_ref())) .iter() .map(|p| { if let Some(pr) = cf.project_root() { @@ -572,7 +572,7 @@ impl Debug for Config { } } -fn default_task_includes(cf: &Box) -> Vec { +fn default_task_includes(cf: &dyn ConfigFile) -> Vec { match cf.project_root() { Some(pr) => vec![pr.join(".mise/tasks"), pr.join(".config/mise/tasks")], None => vec![], diff --git a/src/config/settings.rs b/src/config/settings.rs index 01206c0f4..a9b1fb891 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -195,7 +195,7 @@ impl Settings { settings.log_level = "trace".to_string(); } if settings.quiet { - settings.log_level = "warn".to_string(); + settings.log_level = "error".to_string(); } if settings.log_level == "trace" || settings.log_level == "debug" { settings.verbose = true; From 81f61d5aa4f6074294066bf546a3087c19456973 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:22:06 -0600 Subject: [PATCH 1750/1891] chore: Release mise version 2024.2.0 --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62788b3df..4b0ccc783 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1107,9 +1107,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" +checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" dependencies = [ "equivalent", "hashbrown", @@ -1207,9 +1207,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libgit2-sys" @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.1.35" +version = "2024.2.0" dependencies = [ "base64", "built", @@ -3097,9 +3097,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.35" +version = "0.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d" +checksum = "818ce546a11a9986bc24f93d0cdf38a8a1a400f1473ea8c82e59f6e0ffab9249" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index d7aea7498..587ea1942 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.1.35" +version = "2024.2.0" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 8a649f434..79551f842 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.jdx.dev/install.sh | sh $ ~/.local/bin/mise --version -mise 2024.1.35 +mise 2024.2.0 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 3e79e59fe..c61ac694c 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.1.35"; + version = "2024.2.0"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 93a4476bb..056a02cde 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.1.35" +.TH mise 1 "mise 2024.2.0" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.1.35 +v2024.2.0 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 82418f7cb..157ba779a 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.1.35 +Version: 2024.2.0 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 98a6d1f2441a8fb839f65a5a66d7053bdffef36b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:42:00 -0600 Subject: [PATCH 1751/1891] ci: use m1 macs --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7fa533d23..b40378bb3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,11 +58,11 @@ jobs: - os: macos name: macos-x64 target: x86_64-apple-darwin - runs-on: macos-latest + runs-on: macos-14 - os: macos name: macos-arm64 target: aarch64-apple-darwin - runs-on: macos-latest + runs-on: macos-14 # - os: macos # name: macos # target: universal2-apple-darwin @@ -235,7 +235,7 @@ jobs: generate_release_notes: true token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }} bump-homebrew-formula: - runs-on: macos-latest + runs-on: macos-14 timeout-minutes: 10 needs: [release] continue-on-error: true From 3cc2cb96f5e16e03f0124788d3ae26bee4ecb2d6 Mon Sep 17 00:00:00 2001 From: Vlad Sirenko Date: Thu, 1 Feb 2024 03:28:31 +0200 Subject: [PATCH 1752/1891] add env.mise.source to schame (#1578) Co-authored-by: jdx <216188+jdx@users.noreply.github.com> --- schema/mise.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/schema/mise.json b/schema/mise.json index fde06afb4..fa00d75a3 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -91,6 +91,19 @@ } } ] + }, + "source": { + "oneOf": [ + { "type": "string", "description": "bash script to load" }, + { + "type": "array", + "description": "bash scripts to load", + "items": { + "type": "string", + "description": "bash script to load" + } + } + ] } } } From dc0e793d5584461809bcdc799662184964427b4a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 19:30:08 -0600 Subject: [PATCH 1753/1891] settings: improve set/ls commands (#1579) --- src/cli/config/generate.rs | 3 +-- src/cli/settings/get.rs | 34 +++++++++++++++++++--------------- src/cli/settings/ls.rs | 29 +++++++++-------------------- src/cli/settings/set.rs | 36 ++++++++++++++++++------------------ src/cli/settings/unset.rs | 11 +++++------ src/config/settings.rs | 8 ++++++-- 6 files changed, 58 insertions(+), 63 deletions(-) diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index d0148297f..438c6d52c 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use clap::ValueHint; use eyre::Result; -use crate::config::{Config, Settings}; +use crate::config::Settings; use crate::file; use crate::file::display_path; @@ -18,7 +18,6 @@ pub struct ConfigGenerate { impl ConfigGenerate { pub fn run(self) -> Result<()> { - let _ = Config::try_get()?; let settings = Settings::try_get()?; settings.ensure_experimental("`mise config generate`")?; let doc = r#" diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index c9367957d..8305b4a1c 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -1,8 +1,4 @@ -use std::collections::BTreeMap; - -use serde_json::Value; - -use crate::config::{Config, Settings}; +use crate::config::Settings; /// Show a current setting /// @@ -19,14 +15,24 @@ pub struct SettingsGet { impl SettingsGet { pub fn run(self) -> eyre::Result<()> { - Config::try_get()?; let settings = Settings::try_get()?; - let json = settings.to_string(); - let doc: BTreeMap = serde_json::from_str(&json)?; - match doc.get(&self.setting) { - Some(value) => Ok(miseprintln!("{}", value)), - None => Err(eyre!("Unknown setting: {}", self.setting)), + let mut value = toml::Value::Table(settings.as_dict()?); + let mut key = Some(self.setting.as_str()); + while let Some(k) = key { + let k = k + .split_once('.') + .map(|(a, b)| (a, Some(b))) + .unwrap_or((k, None)); + if let Some(v) = value.as_table().and_then(|t| t.get(k.0)) { + key = k.1; + value = v.clone() + } else { + bail!("Unknown setting: {}", self.setting); + } } + miseprintln!("{}", value); + + Ok(()) } } @@ -44,10 +50,8 @@ mod tests { #[test] fn test_settings_get() { reset_config(); - let stdout = assert_cli!("settings", "get", "legacy_version_file"); - assert_snapshot!(stdout, @r###" - true - "###); + assert_cli_snapshot!("settings", "get", "legacy_version_file", @"true"); + assert_cli_snapshot!("settings", "get", "status.missing_tools", @r###""if_other_versions_installed""###); } #[test] diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 5fedcaa5e..9cd302812 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -1,7 +1,4 @@ -use std::collections::BTreeMap; - use eyre::Result; -use serde_json::Value; use crate::config::Settings; @@ -18,18 +15,11 @@ pub struct SettingsLs {} impl SettingsLs { pub fn run(self) -> Result<()> { let settings = Settings::try_get()?; - let json = settings.to_string(); - let doc: BTreeMap = serde_json::from_str(&json)?; - for (key, value) in doc { - if Settings::hidden_configs().contains(key.as_str()) { - continue; - } - if key == "status" { - // TODO: print this properly - continue; - } - miseprintln!("{} = {}", key, value); + let mut settings = settings.as_dict()?; + for k in Settings::hidden_configs() { + settings.remove(*k); } + miseprintln!("{}", settings); Ok(()) } } @@ -68,19 +58,18 @@ mod tests { plugin_autoupdate_last_check_duration = "20m" python_compile = false python_default_packages_file = "~/.default-python-packages" - python_patch_url = null - python_patches_directory = null - python_precompiled_arch = null - python_precompiled_os = null python_pyenv_repo = "https://github.com/pyenv/pyenv.git" python_venv_auto_create = false quiet = false raw = false - shorthands_file = null - task_output = null trusted_config_paths = [] verbose = true yes = true + + [status] + missing_tools = "if_other_versions_installed" + show_env = false + show_tools = false "###); } } diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index 55428024f..1734d0fdb 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -1,7 +1,8 @@ use eyre::Result; use toml_edit::Document; -use crate::config::settings::SettingsStatusMissingTools; +use crate::config::settings::SettingsFile; + use crate::{env, file}; /// Add/update a setting @@ -34,17 +35,13 @@ impl SettingsSet { "node_compile" => parse_bool(&self.value)?, "not_found_auto_install" => parse_bool(&self.value)?, "paranoid" => parse_bool(&self.value)?, - "plugin_autoupdate_last_check_duration" => parse_i64(&self.value)?, + "plugin_autoupdate_last_check_duration" => self.value.into(), "python_compile" => parse_bool(&self.value)?, "python_venv_auto_create" => parse_bool(&self.value)?, "quiet" => parse_bool(&self.value)?, "raw" => parse_bool(&self.value)?, "shorthands_file" => self.value.into(), - "status.missing_tools" => self - .value - .parse::()? - .to_string() - .into(), + "status.missing_tools" => self.value.into(), "status.show_env" => parse_bool(&self.value)?, "status.show_tools" => parse_bool(&self.value)?, "task_output" => self.value.into(), @@ -72,6 +69,10 @@ impl SettingsSet { } else { settings.insert(&self.setting, toml_edit::Item::Value(value)); } + + // validate + let _: SettingsFile = toml::from_str(&config.to_string())?; + file::write(path, config.to_string()) } } @@ -117,36 +118,35 @@ pub mod tests { assert_cli_snapshot!("settings", @r###" activate_aggressive = false all_compile = false - always_keep_download = false - always_keep_install = false + always_keep_download = true + always_keep_install = true asdf_compat = false cargo_binstall = true color = true disable_default_shorthands = false disable_tools = [] experimental = true - jobs = 4 - legacy_version_file = true + jobs = 2 + legacy_version_file = false legacy_version_file_disable_tools = [] node_compile = false not_found_auto_install = true paranoid = false - plugin_autoupdate_last_check_duration = "7d" + plugin_autoupdate_last_check_duration = "1" python_compile = false python_default_packages_file = "~/.default-python-packages" - python_patch_url = null - python_patches_directory = null - python_precompiled_arch = null - python_precompiled_os = null python_pyenv_repo = "https://github.com/pyenv/pyenv.git" python_venv_auto_create = false quiet = false raw = false - shorthands_file = null - task_output = null trusted_config_paths = [] verbose = true yes = true + + [status] + missing_tools = "never" + show_env = false + show_tools = false "###); reset_config(); } diff --git a/src/cli/settings/unset.rs b/src/cli/settings/unset.rs index 7b253595b..41274eefa 100644 --- a/src/cli/settings/unset.rs +++ b/src/cli/settings/unset.rs @@ -59,19 +59,18 @@ mod tests { plugin_autoupdate_last_check_duration = "20m" python_compile = false python_default_packages_file = "~/.default-python-packages" - python_patch_url = null - python_patches_directory = null - python_precompiled_arch = null - python_precompiled_os = null python_pyenv_repo = "https://github.com/pyenv/pyenv.git" python_venv_auto_create = false quiet = false raw = false - shorthands_file = null - task_output = null trusted_config_paths = [] verbose = true yes = true + + [status] + missing_tools = "if_other_versions_installed" + show_env = false + show_tools = false "###); reset_config(); diff --git a/src/config/settings.rs b/src/config/settings.rs index a9b1fb891..0fddef0da 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -354,13 +354,17 @@ impl Settings { } }) } + + pub fn as_dict(&self) -> eyre::Result { + Ok(self.to_string().parse()?) + } } impl Display for Settings { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match serde_json::to_string_pretty(self) { + match toml::to_string_pretty(self) { Ok(s) => write!(f, "{}", s), - Err(e) => std::fmt::Result::Err(std::fmt::Error::custom(e)), + Err(e) => Err(std::fmt::Error::custom(e)), } } } From 67e9e302c979ca16e8e1160e3a7123f08dd1ab82 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 31 Jan 2024 19:37:14 -0600 Subject: [PATCH 1754/1891] doctor: add "dr" alias --- completions/_mise | 4 ++-- completions/mise.bash | 3 +++ docs/cli-reference.md | 2 ++ src/cli/doctor.rs | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/completions/_mise b/completions/_mise index ef228c483..4e4e8a86c 100644 --- a/completions/_mise +++ b/completions/_mise @@ -26,7 +26,7 @@ _mise() { (current) __mise_current_cmd && ret=0 ;; (deactivate) __mise_deactivate_cmd && ret=0 ;; (direnv) __mise_direnv_cmd && ret=0 ;; - (doctor) __mise_doctor_cmd && ret=0 ;; + (dr|doctor) __mise_doctor_cmd && ret=0 ;; (e|env) __mise_env_cmd && ret=0 ;; (x|exec) __mise_exec_cmd && ret=0 ;; (g|global) __mise_global_cmd && ret=0 ;; @@ -915,7 +915,7 @@ __mise_cmds() { 'current:Shows current active and installed runtime versions' 'deactivate:Disable mise for current shell session' 'direnv:Output direnv function to use mise inside direnv' - 'doctor:Check mise installation for possible problems.' + {dr,doctor}':Check mise installation for possible problems.' {e,env}':Exports env vars to activate mise a single time' {x,exec}':Execute a command with tool(s) set' 'implode:Removes mise CLI and all related data' diff --git a/completions/mise.bash b/completions/mise.bash index 6bbb9e851..f803724a7 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -51,6 +51,9 @@ _mise() { mise,doctor) cmd="mise__doctor" ;; + mise,dr) + cmd="mise__doctor" + ;; mise,e) cmd="mise__env" ;; diff --git a/docs/cli-reference.md b/docs/cli-reference.md index dde2b97eb..e78d20875 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -288,6 +288,8 @@ Examples: ## `mise doctor` +**Aliases:** `dr` + ```text Check mise installation for possible problems. diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index fa4832e94..56642ad47 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -22,7 +22,7 @@ use crate::{file, shims}; /// Check mise installation for possible problems. #[derive(Debug, clap::Args)] -#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] +#[clap(visible_alias = "dr", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Doctor { #[clap(skip)] checks: Vec, From 3412fa19e40ca66c4a1811a226b29804ed1f4d3b Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 01:45:45 -0600 Subject: [PATCH 1755/1891] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79551f842..283fbd21d 100644 --- a/README.md +++ b/README.md @@ -60,4 +60,4 @@ v20.0.0 ## Full Documentation -See [mise.jdx.dev](https://mise.jdx.dev). +See [mise.jdx.dev](https://mise.jdx.dev) From 9ab71597c6c3cda0ce500fe9174263ed0c940d44 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:33:44 -0600 Subject: [PATCH 1756/1891] added mise.run --- .idea/mise.iml | 2 ++ README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.idea/mise.iml b/.idea/mise.iml index 697f7bde4..7290650cf 100644 --- a/.idea/mise.iml +++ b/.idea/mise.iml @@ -30,6 +30,8 @@ + + diff --git a/README.md b/README.md index 283fbd21d..dbf7fb736 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Note that calling `which node` gives us a real path to node, not a shim. Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session -$ curl https://mise.jdx.dev/install.sh | sh +$ curl https://mise.run | sh $ ~/.local/bin/mise --version mise 2024.2.0 ``` @@ -44,7 +44,7 @@ Hook mise into your shell (pick the right one for your shell): ```sh-session # note this assumes mise is located at ~/.local/bin/mise -# which is what install.sh does by default +# which is what https://mise.run does by default echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc echo 'eval "$(~/.local/bin/mise activate zsh)"' >> ~/.zshrc echo '~/.local/bin/mise activate fish | source' >> ~/.config/fish/config.fish From 0cb39882bc1ae6c38b50752eab46770dfb758e61 Mon Sep 17 00:00:00 2001 From: endigma Date: Thu, 1 Feb 2024 13:46:05 -0400 Subject: [PATCH 1757/1891] use a bodged loop to handle go forge submodules (#1583) * use a bodged loop to handle go forge submodules this is suboptimal, but a real solution using the go toolchain is blocked on https://github.com/golang/go/issues/65350 * update e2e to have a go submodule --- e2e/test_go_install | 2 ++ src/forge/go.rs | 25 ++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/e2e/test_go_install b/e2e/test_go_install index cd5396d5a..1ceb76f7d 100755 --- a/e2e/test_go_install +++ b/e2e/test_go_install @@ -8,4 +8,6 @@ eval "$(mise activate bash --shims)" mise use go@prefix:1.20 assert "mise x go:github.com/DarthSim/hivemind@v1.1.0 -- hivemind --version" "Hivemind version 1.1.0" +assert "mise x go:github.com/go-task/task/v3/cmd/task@v3.34.1 -- task --version" "Task version: v3.34.1 (h1:yAAxUM54zoaHv+OtDnGgkWSVeiRuaOCn1lPUXPQQA0o=)" + chmod -R u+w "$MISE_DATA_DIR/cache/go-"* || true diff --git a/src/forge/go.rs b/src/forge/go.rs index 3c4218c80..6f7b203e0 100644 --- a/src/forge/go.rs +++ b/src/forge/go.rs @@ -26,9 +26,21 @@ impl Forge for GoForge { fn list_remote_versions(&self) -> eyre::Result> { self.remote_version_cache .get_or_try_init(|| { - let raw = cmd!("go", "list", "-m", "-versions", "-json", self.name()).read()?; - let mod_info: GoModInfo = serde_json::from_str(&raw)?; - Ok(mod_info.versions) + let mut mod_path = Some(self.name()); + + while let Some(cur_mod_path) = mod_path { + let raw = + cmd!("go", "list", "-m", "-versions", "-json", cur_mod_path).read()?; + + let result = serde_json::from_str::(&raw); + if let Ok(mod_info) = result { + return Ok(mod_info.versions); + } + + mod_path = trim_after_last_slash(cur_mod_path); + } + + Err(eyre!("couldn't find module versions")) }) .cloned() } @@ -62,6 +74,13 @@ impl GoForge { } } +fn trim_after_last_slash(s: &str) -> Option<&str> { + match s.rsplit_once('/') { + Some((new_path, _)) => Some(new_path), + None => None, + } +} + #[derive(Debug, serde::Deserialize)] #[serde(rename_all = "PascalCase")] pub struct GoModInfo { From 95a50c34fd53e34821c2f0fa2af0faf5ada75cdd Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 11:52:05 -0600 Subject: [PATCH 1758/1891] fixed ctrlc handler (#1584) --- src/cli/run.rs | 2 +- src/cli/upgrade.rs | 2 +- src/ui/progress_report.rs | 7 +++---- src/ui/prompt.rs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/cli/run.rs b/src/cli/run.rs index 34c1f0c95..3ee4c44f9 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -380,7 +380,7 @@ impl Run { for name in tasks.keys() { s = s.option(DemandOption::new(name)); } - let _ = ctrlc::handle_ctrlc()?; + let _ctrlc = ctrlc::handle_ctrlc()?; let name = s.run()?; match tasks.get(name) { Some(task) => Ok((*task).clone()), diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 5b5805408..0bc159fee 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -126,7 +126,7 @@ impl Upgrade { } fn get_interactive_tool_set(&self, outdated: &OutputVec) -> Result> { - let _ = ui::ctrlc::handle_ctrlc()?; + let _ctrlc = ui::ctrlc::handle_ctrlc()?; let mut ms = demand::MultiSelect::new("mise upgrade") .description("Select tools to upgrade") .filterable(true) diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index 5b5a91512..f8e95ee28 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -28,8 +28,7 @@ pub struct ProgressReport { pub pb: ProgressBar, prefix: String, pad: usize, - #[allow(dead_code)] - handle: Option, + _ctrlc: Option, } static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { @@ -58,7 +57,7 @@ fn success_prefix(pad: usize, prefix: &str) -> String { impl ProgressReport { pub fn new(prefix: String) -> ProgressReport { - let handle = ui::ctrlc::handle_ctrlc().unwrap_or_default(); + let _ctrlc = ui::ctrlc::handle_ctrlc().unwrap_or_default(); let pad = *LONGEST_PLUGIN_NAME; let pb = ProgressBar::new(100) .with_style(PROG_TEMPLATE.clone()) @@ -68,7 +67,7 @@ impl ProgressReport { prefix, pb, pad, - handle, + _ctrlc, } } } diff --git a/src/ui/prompt.rs b/src/ui/prompt.rs index 34598c809..0242788c8 100644 --- a/src/ui/prompt.rs +++ b/src/ui/prompt.rs @@ -8,7 +8,7 @@ static MUTEX: Mutex<()> = Mutex::new(()); pub fn confirm>(message: S) -> eyre::Result { let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once - let _ = ctrlc::handle_ctrlc()?; + let _ctrlc = ctrlc::handle_ctrlc()?; if !console::user_attended_stderr() { return Ok(false); From bbaf11248fbdc413f76283bd38ce6e9c9e3a1711 Mon Sep 17 00:00:00 2001 From: Thomas Lockney Date: Thu, 1 Feb 2024 09:56:09 -0800 Subject: [PATCH 1759/1891] Additional arch install (#1562) * Added support for additional architectures * Remove extraneous comment * Fixed shell errors * Moved musl check to get_arch() function and cleaned up conditional flow * Update packaging/standalone/install.envsubst --------- Co-authored-by: jdx <216188+jdx@users.noreply.github.com> --- packaging/standalone/install.envsubst | 57 ++++++++++++++++++++++----- scripts/render-install.sh | 2 +- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index e8dce5a51..ee21c9bac 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -41,11 +41,22 @@ get_os() { } get_arch() { + musl="" + if type ldd >/dev/null 2>/dev/null; then + libc=$(ldd /bin/ls | grep 'musl' | head -1 | cut -d ' ' -f1) + if [ -z "$libc" ]; then + musl="-musl" + fi + fi arch="$(uname -m)" if [ "$arch" = x86_64 ]; then - echo "x64" + echo "x64$musl" elif [ "$arch" = aarch64 ] || [ "$arch" = arm64 ]; then - echo "arm64" + echo "arm64$musl" + elif [ "$arch" = armv6l ]; then + echo "armv6$musl" + elif [ "$arch" = armv7l ]; then + echo "armv7$musl" else error "unsupported architecture: $arch" fi @@ -66,18 +77,44 @@ get_checksum() { arch="$(get_arch)" checksum_linux_x86_64="$MISE_CHECKSUM_LINUX_X86_64" + checksum_linux_x86_64_musl="$MISE_CHECKSUM_LINUX_X86_64_MUSL" checksum_linux_arm64="$MISE_CHECKSUM_LINUX_ARM64" + checksum_linux_arm64_musl="$MISE_CHECKSUM_LINUX_ARM64_MUSL" + checksum_linux_armv6="$MISE_CHECKSUM_LINUX_ARMV6" + checksum_linux_armv6_musl="$MISE_CHECKSUM_LINUX_ARMV6_MUSL" + checksum_linux_armv7="$MISE_CHECKSUM_LINUX_ARMV7" + checksum_linux_armv7_musl="$MISE_CHECKSUM_LINUX_ARMV7_MUSL" checksum_macos_x86_64="$MISE_CHECKSUM_MACOS_X86_64" checksum_macos_arm64="$MISE_CHECKSUM_MACOS_ARM64" - if [ "$os" = "linux" ] && [ "$arch" = "x64" ]; then - echo "$checksum_linux_x86_64" - elif [ "$os" = "linux" ] && [ "$arch" = "arm64" ]; then - echo "$checksum_linux_arm64" - elif [ "$os" = "macos" ] && [ "$arch" = "x64" ]; then - echo "$checksum_macos_x86_64" - elif [ "$os" = "macos" ] && [ "$arch" = "arm64" ]; then - echo "$checksum_macos_arm64" + if [ "$os" = "linux" ]; then + if [ "$arch" = "x64" ]; then + echo "$checksum_linux_x86_64" + elif [ "$arch" = "x64-musl" ]; then + echo "$checksum_linux_x86_64_musl" + elif [ "$arch" = "arm64" ]; then + echo "$checksum_linux_arm64" + elif [ "$arch" = "arm64-musl" ]; then + echo "$checksum_linux_arm64_musl" + elif [ "$arch" = "armv6" ]; then + echo "$checksum_linux_armv6" + elif [ "$arch" = "armv6-musl" ]; then + echo "$checksum_linux_armv6_musl" + elif [ "$arch" = "armv7" ]; then + echo "$checksum_linux_armv7" + elif [ "$arch" = "armv7-musl" ]; then + echo "$checksum_linux_armv7_musl" + else + warn "no checksum for $os-$arch" + fi + elif [ "$os" = "macos" ]; then + if [ "$arch" = "x64" ]; then + echo "$checksum_macos_x86_64" + elif [ "$arch" = "arm64" ]; then + echo "$checksum_macos_arm64" + else + warn "no checksum for $os-$arch" + fi else warn "no checksum for $os-$arch" fi diff --git a/scripts/render-install.sh b/scripts/render-install.sh index 8d774210e..65c286064 100755 --- a/scripts/render-install.sh +++ b/scripts/render-install.sh @@ -13,5 +13,5 @@ MISE_VERSION=$MISE_VERSION \ MISE_CHECKSUM_LINUX_ARMV7_MUSL=$(grep "mise-v.*linux-armv7-musl.tar.gz" "$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt") \ MISE_CHECKSUM_MACOS_X86_64=$(grep "mise-v.*macos-x64.tar.gz" "$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt") \ MISE_CHECKSUM_MACOS_ARM64=$(grep "mise-v.*macos-arm64.tar.gz" "$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt") \ - envsubst '$MISE_VERSION,$MISE_CHECKSUM_LINUX_X86_64,$MISE_CHECKSUM_LINUX_ARM64,$MISE_CHECKSUM_MACOS_X86_64,$MISE_CHECKSUM_MACOS_ARM64' \ + envsubst '$MISE_VERSION,$MISE_CHECKSUM_LINUX_X86_64,$MISE_CHECKSUM_LINUX_X86_64_MUSL,$MISE_CHECKSUM_LINUX_ARM64,$MISE_CHECKSUM_LINUX_ARM64_MUSL,$MISE_CHECKSUM_LINUX_ARMV6,$MISE_CHECKSUM_LINUX_ARMV6_MUSL,$MISE_CHECKSUM_LINUX_ARMV7,$MISE_CHECKSUM_LINUX_ARMV7_MUSL,$MISE_CHECKSUM_MACOS_X86_64,$MISE_CHECKSUM_MACOS_ARM64' \ <"$BASE_DIR/packaging/standalone/install.envsubst" From 9e3e66998945522939154ae9cb6c4f36bcc89bb2 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 11:57:28 -0600 Subject: [PATCH 1760/1891] chore: Release mise version 2024.2.1 --- Cargo.lock | 22 +++++++++++++++------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b0ccc783..6fae69818 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.2.0" +version = "2024.2.1" dependencies = [ "base64", "built", @@ -1392,6 +1392,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.17" @@ -1906,9 +1912,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.30" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ "bitflags 2.4.2", "errno 0.3.8", @@ -2448,13 +2454,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "fe80ced77cbfb4cb91a94bf72b378b4b6791a0d9b7f09d0be747d1bdff4e68bd" dependencies = [ "deranged", "itoa", "libc", + "num-conv", "num_threads", "powerfmt", "serde", @@ -2470,10 +2477,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] diff --git a/Cargo.toml b/Cargo.toml index 587ea1942..e35c8a6d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.2.0" +version = "2024.2.1" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index dbf7fb736..22b26da33 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -mise 2024.2.0 +mise 2024.2.1 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index c61ac694c..9f5436b5d 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.2.0"; + version = "2024.2.1"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 056a02cde..ca77f97b5 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.2.0" +.TH mise 1 "mise 2024.2.1" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.2.0 +v2024.2.1 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 157ba779a..35b1a1c18 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.2.0 +Version: 2024.2.1 Release: 1 URL: https://github.com/jdx/mise/ Group: System From fbe2578e8770c8913e6bb029ea08ce7b18e6db4a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:03:46 -0600 Subject: [PATCH 1761/1891] python: minor UI tweak --- src/plugins/core/python.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index dc6f2a215..5c5614b0b 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -284,6 +284,7 @@ impl PythonPlugin { fn test_python(&self, config: &Config, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> { pr.set_message("python --version".into()); CmdLineRunner::new(self.python_path(tv)) + .with_pr(pr) .arg("--version") .envs(config.env()?) .execute() From d3748efb24bb7b7894c5a877e4d49aff1738c0b8 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:25:40 -0600 Subject: [PATCH 1762/1891] plugins: ui tweak --- src/plugins/external_plugin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 5cfaf3032..5702f3aa1 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -528,7 +528,7 @@ impl Forge for ExternalPlugin { let plugin_path = self.plugin_path.to_path_buf(); if plugin_path.is_symlink() { warn!( - "Plugin: {} is a symlink, not updating", + "plugin:{} is a symlink, not updating", style(&self.name).blue().for_stderr() ); return Ok(()); @@ -536,7 +536,7 @@ impl Forge for ExternalPlugin { let git = Git::new(plugin_path); if !git.is_repo() { warn!( - "Plugin {} is not a git repository, not updating", + "plugin:{} is not a git repository, not updating", style(&self.name).blue().for_stderr() ); return Ok(()); From 1d00fbdb904ce83737898e4dc2f8ba5edbf2a568 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:45:25 -0600 Subject: [PATCH 1763/1891] release: clear cache on mise.run --- scripts/publish-s3.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/publish-s3.sh b/scripts/publish-s3.sh index 8a4a697f4..f16620a85 100755 --- a/scripts/publish-s3.sh +++ b/scripts/publish-s3.sh @@ -25,11 +25,21 @@ aws s3 cp artifacts/deb/pool/ "s3://$AWS_S3_BUCKET/deb/pool/" --cache-control "$ aws s3 cp artifacts/deb/dists/ "s3://$AWS_S3_BUCKET/deb/dists/" --cache-control "$cache_day" --no-progress --no-progress --recursive export CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344 + +# jdx.dev curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/90dfd7997bdcfa8579c52d8ee8dd4cd1/purge_cache" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{ "purge_everything": true }' + +# rtx.pub curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/80d977fd09f01db52bec165778088891/purge_cache" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ --data '{ "purge_everything": true }' + +# mise.run +curl --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/782fc08181b7bbd26c529a00df52a277/purge_cache" \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" \ + --data '{ "purge_everything": true }' From 554e688c1383cb7d6ca2cfaf201c51bf2b5c2581 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:49:38 -0600 Subject: [PATCH 1764/1891] download progress bars (#1586) Fixes #1585 --- src/hash.rs | 28 ++++++++++++++++++++++++++-- src/http.rs | 27 +++++++++++++++++++++++++-- src/plugins/core/bun.rs | 8 ++++---- src/plugins/core/deno.rs | 7 ++++--- src/plugins/core/erlang.rs | 1 + src/plugins/core/go.rs | 35 ++++++++++++++++++----------------- src/plugins/core/java.rs | 9 +++++---- src/plugins/core/node.rs | 8 ++++---- src/plugins/core/python.rs | 7 +++---- src/ui/progress_report.rs | 37 ++++++++++++++++++++++++++++++++----- 10 files changed, 122 insertions(+), 45 deletions(-) diff --git a/src/hash.rs b/src/hash.rs index 049e319bf..95d601387 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -2,6 +2,7 @@ use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; use std::fs::File; use std::hash::{Hash, Hasher}; +use std::io::{Read, Write}; use std::path::Path; use eyre::Result; @@ -9,6 +10,7 @@ use rayon::prelude::*; use sha2::{Digest, Sha256}; use crate::file::display_path; +use crate::ui::progress_report::SingleReport; pub fn hash_to_str(t: &T) -> String { let mut s = DefaultHasher::new(); @@ -18,15 +20,37 @@ pub fn hash_to_str(t: &T) -> String { } pub fn file_hash_sha256(path: &Path) -> Result { + file_hash_sha256_prog(path, None) +} + +pub fn file_hash_sha256_prog(path: &Path, pr: Option<&dyn SingleReport>) -> Result { let mut file = File::open(path)?; + if let Some(pr) = pr { + pr.set_length(file.metadata()?.len()); + } let mut hasher = Sha256::new(); + let mut buf = [0; 32 * 1024]; + loop { + let n = file.read(&mut buf)?; + if n == 0 { + break; + } + hasher.write_all(&buf[..n])?; + if let Some(pr) = pr { + pr.inc(n as u64); + } + } std::io::copy(&mut file, &mut hasher)?; let hash = hasher.finalize(); Ok(format!("{hash:x}")) } -pub fn ensure_checksum_sha256(path: &Path, checksum: &str) -> Result<()> { - let actual = file_hash_sha256(path)?; +pub fn ensure_checksum_sha256( + path: &Path, + checksum: &str, + pr: Option<&dyn SingleReport>, +) -> Result<()> { + let actual = file_hash_sha256_prog(path, pr)?; ensure!( actual == checksum, "Checksum mismatch for file {}:\nExpected: {checksum}\nActual: {actual}", diff --git a/src/http.rs b/src/http.rs index a854641f9..78d7ffe44 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,4 +1,5 @@ use std::fs::File; +use std::io::{Read, Write}; use std::path::Path; use std::time::Duration; @@ -10,6 +11,7 @@ use reqwest::IntoUrl; use crate::cli::version; use crate::env::MISE_FETCH_REMOTE_VERSIONS_TIMEOUT; use crate::file::display_path; +use crate::ui::progress_report::SingleReport; use crate::{env, file}; #[cfg(not(test))] @@ -77,14 +79,35 @@ impl Client { Ok(json) } - pub fn download_file(&self, url: U, path: &Path) -> Result<()> { + pub fn download_file( + &self, + url: U, + path: &Path, + pr: Option<&dyn SingleReport>, + ) -> Result<()> { let url = url.into_url()?; debug!("GET Downloading {} to {}", &url, display_path(path)); let mut resp = self.get(url)?; + if let Some(length) = resp.content_length() { + if let Some(pr) = pr { + pr.set_length(length); + } + } file::create_dir_all(path.parent().unwrap())?; + + let mut buf = [0; 32 * 1024]; let mut file = File::create(path)?; - resp.copy_to(&mut file)?; + loop { + let n = resp.read(&mut buf)?; + if n == 0 { + break; + } + file.write_all(&buf[..n])?; + if let Some(pr) = pr { + pr.inc(n as u64); + } + } Ok(()) } } diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index cae95dc38..f9e3e6f68 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -67,15 +67,15 @@ impl BunPlugin { let filename = url.split('/').last().unwrap(); let tarball_path = tv.download_path().join(filename); - pr.set_message(format!("downloading {}", &url)); - HTTP.download_file(&url, &tarball_path)?; + pr.set_message(format!("downloading {filename}")); + HTTP.download_file(&url, &tarball_path, Some(pr))?; Ok(tarball_path) } fn install(&self, ctx: &InstallContext, tarball_path: &Path) -> Result<()> { - ctx.pr - .set_message(format!("installing {}", tarball_path.display())); + let filename = tarball_path.file_name().unwrap().to_string_lossy(); + ctx.pr.set_message(format!("installing {filename}")); file::remove_all(ctx.tv.install_path())?; file::create_dir_all(ctx.tv.install_path().join("bin"))?; file::unzip(tarball_path, &ctx.tv.download_path())?; diff --git a/src/plugins/core/deno.rs b/src/plugins/core/deno.rs index bed7bcc29..06337556a 100644 --- a/src/plugins/core/deno.rs +++ b/src/plugins/core/deno.rs @@ -71,8 +71,8 @@ impl DenoPlugin { let filename = url.split('/').last().unwrap(); let tarball_path = tv.download_path().join(filename); - pr.set_message(format!("downloading {}", &url)); - HTTP.download_file(&url, &tarball_path)?; + pr.set_message(format!("downloading {filename}")); + HTTP.download_file(&url, &tarball_path, Some(pr))?; // TODO: hash::ensure_checksum_sha256(&tarball_path, &m.sha256)?; @@ -80,7 +80,8 @@ impl DenoPlugin { } fn install(&self, tv: &ToolVersion, pr: &dyn SingleReport, tarball_path: &Path) -> Result<()> { - pr.set_message(format!("installing {}", tarball_path.display())); + let filename = tarball_path.file_name().unwrap().to_string_lossy(); + pr.set_message(format!("installing {filename}")); file::remove_all(tv.install_path())?; file::create_dir_all(tv.install_path().join("bin"))?; file::unzip(tarball_path, &tv.download_path())?; diff --git a/src/plugins/core/erlang.rs b/src/plugins/core/erlang.rs index 4b95dd6d2..bc0a70da2 100644 --- a/src/plugins/core/erlang.rs +++ b/src/plugins/core/erlang.rs @@ -64,6 +64,7 @@ impl ErlangPlugin { HTTP_FETCH.download_file( format!("https://raw.githubusercontent.com/kerl/kerl/{KERL_VERSION}/kerl"), &self.kerl_path(), + None, )?; file::make_executable(&self.kerl_path())?; Ok(()) diff --git a/src/plugins/core/go.rs b/src/plugins/core/go.rs index 9352eb523..40e390f48 100644 --- a/src/plugins/core/go.rs +++ b/src/plugins/core/go.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, HashMap}; use std::path::{Path, PathBuf}; +use std::thread; use eyre::Result; use itertools::Itertools; @@ -100,23 +101,23 @@ impl GoPlugin { fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { let filename = format!("go{}.{}-{}.tar.gz", tv.version, platform(), arch()); let tarball_url = format!("{}/{}", &*env::MISE_GO_DOWNLOAD_MIRROR, &filename); - let tarball_path = tv.download_path().join(filename); - - pr.set_message(format!("downloading {}", &tarball_url)); - HTTP.download_file(&tarball_url, &tarball_path)?; - - self.verify_tarball_checksum(&tarball_url, &tarball_path)?; - - Ok(tarball_path) - } - - fn verify_tarball_checksum(&self, tarball_url: &str, tarball_path: &Path) -> Result<()> { - if !*env::MISE_GO_SKIP_CHECKSUM { - let checksum_url = format!("{}.sha256", tarball_url); - let checksum = HTTP.get_text(checksum_url)?; - hash::ensure_checksum_sha256(tarball_path, &checksum)?; - } - Ok(()) + let tarball_path = tv.download_path().join(&filename); + + thread::scope(|s| { + let checksum_handle = s.spawn(|| { + let checksum_url = format!("{}.sha256", &tarball_url); + HTTP.get_text(checksum_url) + }); + pr.set_message(format!("downloading {filename}")); + HTTP.download_file(&tarball_url, &tarball_path, Some(pr))?; + + if !*env::MISE_GO_SKIP_CHECKSUM { + pr.set_message(format!("verifying {filename}")); + let checksum = checksum_handle.join().unwrap()?; + hash::ensure_checksum_sha256(&tarball_path, &checksum, Some(pr))?; + } + Ok(tarball_path) + }) } fn install(&self, tv: &ToolVersion, pr: &dyn SingleReport, tarball_path: &Path) -> Result<()> { diff --git a/src/plugins/core/java.rs b/src/plugins/core/java.rs index 25adafc21..fad1dcdc1 100644 --- a/src/plugins/core/java.rs +++ b/src/plugins/core/java.rs @@ -133,10 +133,10 @@ impl JavaPlugin { let filename = m.url.split('/').last().unwrap(); let tarball_path = tv.download_path().join(filename); - pr.set_message(format!("downloading {}", &m.url)); - HTTP.download_file(&m.url, &tarball_path)?; + pr.set_message(format!("downloading {filename}")); + HTTP.download_file(&m.url, &tarball_path, Some(pr))?; - hash::ensure_checksum_sha256(&tarball_path, &m.sha256)?; + hash::ensure_checksum_sha256(&tarball_path, &m.sha256, Some(pr))?; Ok(tarball_path) } @@ -148,7 +148,8 @@ impl JavaPlugin { tarball_path: &Path, m: &JavaMetadata, ) -> Result<()> { - pr.set_message(format!("installing {}", tarball_path.display())); + let filename = tarball_path.file_name().unwrap().to_string_lossy(); + pr.set_message(format!("installing {filename}")); file::untar(tarball_path, &tv.download_path())?; self.move_to_install_path(tv, m) } diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 1567242eb..8fbb12d1f 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -112,11 +112,11 @@ impl NodePlugin { pr.set_message(format!("using previously downloaded {tarball_name}")); } else { pr.set_message(format!("downloading {tarball_name}")); - HTTP.download_file(url.clone(), local)?; + HTTP.download_file(url.clone(), local, Some(pr))?; } if *env::MISE_NODE_VERIFY { pr.set_message(format!("verifying {tarball_name}")); - self.verify(local, version)?; + self.verify(local, version, pr)?; } Ok(()) } @@ -143,13 +143,13 @@ impl NodePlugin { self.sh(ctx, opts)?.arg(&opts.make_install_cmd).execute() } - fn verify(&self, tarball: &Path, version: &str) -> Result<()> { + fn verify(&self, tarball: &Path, version: &str, pr: &dyn SingleReport) -> Result<()> { let tarball_name = tarball.file_name().unwrap().to_string_lossy().to_string(); // TODO: verify gpg signature let shasums = HTTP.get_text(self.shasums_url(version)?)?; let shasums = hash::parse_shasums(&shasums); let shasum = shasums.get(&tarball_name).unwrap(); - hash::ensure_checksum_sha256(tarball, shasum) + hash::ensure_checksum_sha256(tarball, shasum, Some(pr)) } fn node_path(&self, tv: &ToolVersion) -> PathBuf { diff --git a/src/plugins/core/python.rs b/src/plugins/core/python.rs index 5c5614b0b..7bdc2e52c 100644 --- a/src/plugins/core/python.rs +++ b/src/plugins/core/python.rs @@ -142,11 +142,10 @@ impl PythonPlugin { let download = ctx.tv.download_path(); let tarball_path = download.join(filename); - ctx.pr.set_message(format!("downloading {}", &url)); - HTTP.download_file(&url, &tarball_path)?; + ctx.pr.set_message(format!("downloading {filename}")); + HTTP.download_file(&url, &tarball_path, Some(ctx.pr.as_ref()))?; - ctx.pr - .set_message(format!("installing {}", tarball_path.display())); + ctx.pr.set_message(format!("installing {filename}")); file::untar(&tarball_path, &download)?; file::remove_all(&install)?; file::rename(download.join("python"), &install)?; diff --git a/src/ui/progress_report.rs b/src/ui/progress_report.rs index f8e95ee28..8ea0e838a 100644 --- a/src/ui/progress_report.rs +++ b/src/ui/progress_report.rs @@ -4,18 +4,32 @@ use indicatif::{ProgressBar, ProgressStyle}; use once_cell::sync::Lazy; use crate::ui::style; -use crate::{forge, ui}; +use crate::{env, forge, ui}; pub trait SingleReport: Send + Sync { fn println(&self, _message: String) {} fn set_message(&self, _message: String) {} + fn inc(&self, _delta: u64) {} + fn set_length(&self, _length: u64) {} fn finish(&self) {} fn finish_with_message(&self, _message: String) {} } +static SPIN_TEMPLATE: Lazy = Lazy::new(|| { + let tmpl = "{prefix} {wide_msg} {spinner:.blue} {elapsed:>3.dim.italic}"; + ProgressStyle::with_template(tmpl).unwrap() +}); + static PROG_TEMPLATE: Lazy = Lazy::new(|| { - ProgressStyle::with_template("{prefix} {wide_msg} {spinner:.blue} {elapsed:3.dim.italic}") - .unwrap() + let tmpl = match *env::TERM_WIDTH { + 0..=89 => "{prefix} {wide_msg} {bar:10.cyan/blue} {percent:>2}%", + 90..=99 => "{prefix} {wide_msg} {bar:15.cyan/blue} {percent:>2}%", + 100..=114 => "{prefix} {wide_msg} {bytes}/{total_bytes:10} {bar:10.cyan/blue}", + _ => { + "{prefix} {wide_msg} {bytes}/{total_bytes} ({eta}) {bar:20.cyan/blue} {elapsed:>3.dim.italic}" + } + }; + ProgressStyle::with_template(tmpl).unwrap() }); static SUCCESS_TEMPLATE: Lazy = Lazy::new(|| { @@ -34,7 +48,7 @@ pub struct ProgressReport { static LONGEST_PLUGIN_NAME: Lazy = Lazy::new(|| { forge::list() .into_iter() - .map(|p| p.id().len() + 10) + .map(|p| p.id().len()) .max() .unwrap_or_default() .max(15) @@ -60,7 +74,7 @@ impl ProgressReport { let _ctrlc = ui::ctrlc::handle_ctrlc().unwrap_or_default(); let pad = *LONGEST_PLUGIN_NAME; let pb = ProgressBar::new(100) - .with_style(PROG_TEMPLATE.clone()) + .with_style(SPIN_TEMPLATE.clone()) .with_prefix(normal_prefix(pad, &prefix)); pb.enable_steady_tick(Duration::from_millis(250)); ProgressReport { @@ -81,6 +95,19 @@ impl SingleReport for ProgressReport { fn set_message(&self, message: String) { self.pb.set_message(message.replace('\r', "")); } + fn inc(&self, delta: u64) { + self.pb.inc(delta); + if Some(self.pb.position()) == self.pb.length() { + self.pb.set_style(SPIN_TEMPLATE.clone()); + self.pb.enable_steady_tick(Duration::from_millis(250)); + } + } + fn set_length(&self, length: u64) { + self.pb.set_position(0); + self.pb.set_style(PROG_TEMPLATE.clone()); + self.pb.disable_steady_tick(); + self.pb.set_length(length); + } fn finish(&self) { self.pb.set_style(SUCCESS_TEMPLATE.clone()); self.pb From 0633c0790e0858919f0ac2b2c27a3d2d7b836c8a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:54:56 -0600 Subject: [PATCH 1765/1891] improve output of shorthand update script --- scripts/update-shorthand-repo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index db0383404..cbd19a796 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -39,7 +39,7 @@ for plugin in $asdf_plugins; do file="asdf-plugins/plugins/$plugin" repository=$(grep -e '^repository = ' "$file") repository="${repository/#repository = /}" - printf "[%03d/%d] %s\n" $((++count)) "$num_plugins" "$repository" + printf "\033[2K[%03d/%d] %s\r" $((++count)) "$num_plugins" "$repository" if [[ $repository == "https://github.com/mise-plugins/"* ]]; then trusted+=("$plugin") elif grep -qe '^first-party = true' "$file"; then From 1f11a1d5d08e5968001f0c8d823b40b37237858b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:55:36 -0600 Subject: [PATCH 1766/1891] chore: Release mise version 2024.2.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fae69818..aa439ef45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.2.1" +version = "2024.2.2" dependencies = [ "base64", "built", diff --git a/Cargo.toml b/Cargo.toml index e35c8a6d9..76924eae4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.2.1" +version = "2024.2.2" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 22b26da33..837477b82 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -mise 2024.2.1 +mise 2024.2.2 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 9f5436b5d..db9fc9cb9 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.2.1"; + version = "2024.2.2"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index ca77f97b5..9acff2807 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.2.1" +.TH mise 1 "mise 2024.2.2" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.2.1 +v2024.2.2 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 35b1a1c18..12696fefa 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.2.1 +Version: 2024.2.2 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 9e786e842ff8a1ed25b5d65e76f68ec3ce07850c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 20:09:17 -0600 Subject: [PATCH 1767/1891] show curl progress during install.sh --- packaging/standalone/install.envsubst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/standalone/install.envsubst b/packaging/standalone/install.envsubst index ee21c9bac..03d1e65b1 100644 --- a/packaging/standalone/install.envsubst +++ b/packaging/standalone/install.envsubst @@ -131,8 +131,8 @@ download_file() { info "mise: installing mise..." if command -v curl >/dev/null 2>&1; then - debug ">" curl -fLlSso "$file" "$url" - curl -fLlSso "$file" "$url" + debug ">" curl -#fLo "$file" "$url" + curl -#fLo "$file" "$url" else if command -v wget >/dev/null 2>&1; then debug ">" wget -qO "$file" "$url" From 57a6fa6e14e3b3799650b1184ee7af35d4778ebc Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 20:48:10 -0600 Subject: [PATCH 1768/1891] install tools in order listed in config file when --jobs=1 (#1587) * install tools in order listed in config file when --jobs=1 https://github.com/mise-plugins/mise-poetry/issues/7 * fix lint task --- .mise/config.toml | 2 +- src/toolset/mod.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.mise/config.toml b/.mise/config.toml index a14805611..64482f290 100644 --- a/.mise/config.toml +++ b/.mise/config.toml @@ -1 +1 @@ -tasks.lint = "echo LINT!" +tasks.lint = "just lint" diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index ae74087ee..94f34987f 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -138,6 +138,7 @@ impl Toolset { let settings = Settings::try_get()?; let queue: Vec<_> = versions .into_iter() + .rev() .group_by(|v| v.forge.clone()) .into_iter() .map(|(fa, v)| (forge::get(&fa), v.collect_vec())) From 8f067cb79fa0f11c1f81ffe3496be9a91c28403e Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:14:32 -0600 Subject: [PATCH 1769/1891] actionlint --- .github/actionlint.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index 012d6a74c..cc3efb4a1 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -1,6 +1,7 @@ self-hosted-runner: # Labels of self-hosted runner in array of strings. labels: + - macos-14 - buildjet-32vcpu-ubuntu-2204-arm - buildjet-16vcpu-ubuntu-2204-arm - buildjet-8vcpu-ubuntu-2204-arm From 13d7d29302004c770a51ff5298a261635460962f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:25:27 -0600 Subject: [PATCH 1770/1891] remove unused property --- src/config/config_file/mise_toml.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 6affb1535..2f3cf89b2 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -2,7 +2,6 @@ use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Formatter}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::Mutex; use eyre::WrapErr; use itertools::Itertools; @@ -54,8 +53,6 @@ pub struct MiseToml { #[serde(skip)] tasks: Vec, #[serde(skip)] - is_trusted: Mutex>, - #[serde(skip)] project_root: Option, #[serde(skip)] config_root: PathBuf, @@ -90,7 +87,6 @@ impl MiseToml { Self { path: path.to_path_buf(), context, - is_trusted: Mutex::new(None), toolset: Toolset { source: Some(ToolSource::MiseToml(path.to_path_buf())), ..Default::default() @@ -578,7 +574,6 @@ impl Debug for MiseToml { let tools = self.toolset.to_string(); let title = format!("MiseToml({}): {tools}", &display_path(&self.path)); let mut d = f.debug_struct(&title); - // d.field("is_trusted", &self.is_trusted); if let Some(min_version) = &self.min_version { d.field("min_version", &min_version.to_string()); } @@ -617,7 +612,6 @@ impl Clone for MiseToml { plugins: self.plugins.clone(), tasks: self.tasks.clone(), task_config: self.task_config.clone(), - is_trusted: Mutex::new(*self.is_trusted.lock().unwrap()), project_root: self.project_root.clone(), config_root: self.config_root.clone(), } From fee5b72fd552e9f00e13fe60f04959eb629147cd Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:28:31 -0600 Subject: [PATCH 1771/1891] property should not be public --- src/config/config_file/mise_toml.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 2f3cf89b2..7b4d2dee5 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -49,7 +49,7 @@ pub struct MiseToml { #[serde(default)] plugins: HashMap, #[serde(default)] - pub task_config: TaskConfig, + task_config: TaskConfig, #[serde(skip)] tasks: Vec, #[serde(skip)] From 13daec0b4b92b51bd3ed4137cd51f665afd3f007 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:31:36 -0600 Subject: [PATCH 1772/1891] remove more unused config file props --- src/config/config_file/mise_toml.rs | 42 ++++++++++------------------- src/config/mod.rs | 10 +++---- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 7b4d2dee5..c44745ef5 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -52,10 +52,6 @@ pub struct MiseToml { task_config: TaskConfig, #[serde(skip)] tasks: Vec, - #[serde(skip)] - project_root: Option, - #[serde(skip)] - config_root: PathBuf, } #[derive(Debug, Default, Clone)] @@ -65,25 +61,6 @@ impl MiseToml { pub fn init(path: &Path) -> Self { let mut context = BASE_CONTEXT.clone(); context.insert("config_root", path.parent().unwrap().to_str().unwrap()); - let filename = path.file_name().unwrap_or_default().to_string_lossy(); - let project_root = match path.parent() { - Some(dir) => match dir { - dir if dir.starts_with(*dirs::CONFIG) => None, - dir if dir.starts_with(*dirs::SYSTEM) => None, - dir if dir == *dirs::HOME => None, - dir if !filename.starts_with('.') && dir.ends_with(".mise") => dir.parent(), - dir if !filename.starts_with('.') && dir.ends_with(".config/mise") => { - dir.parent().unwrap().parent() - } - dir => Some(dir), - }, - None => None, - }; - let config_root = project_root - .or_else(|| path.parent()) - .or_else(|| dirs::CWD.as_ref().map(|p| p.as_path())) - .unwrap_or_else(|| *dirs::HOME) - .to_path_buf(); Self { path: path.to_path_buf(), context, @@ -91,8 +68,6 @@ impl MiseToml { source: Some(ToolSource::MiseToml(path.to_path_buf())), ..Default::default() }, - project_root: project_root.map(|p| p.to_path_buf()), - config_root, ..Default::default() } } @@ -477,7 +452,20 @@ impl ConfigFile for MiseToml { } fn project_root(&self) -> Option<&Path> { - self.project_root.as_deref() + let filename = self.path.file_name().unwrap_or_default().to_string_lossy(); + match self.path.parent() { + Some(dir) => match dir { + dir if dir.starts_with(*dirs::CONFIG) => None, + dir if dir.starts_with(*dirs::SYSTEM) => None, + dir if dir == *dirs::HOME => None, + dir if !filename.starts_with('.') && dir.ends_with(".mise") => dir.parent(), + dir if !filename.starts_with('.') && dir.ends_with(".config/mise") => { + dir.parent().unwrap().parent() + } + dir => Some(dir), + }, + None => None, + } } fn plugins(&self) -> HashMap { @@ -612,8 +600,6 @@ impl Clone for MiseToml { plugins: self.plugins.clone(), tasks: self.tasks.clone(), task_config: self.task_config.clone(), - project_root: self.project_root.clone(), - config_root: self.config_root.clone(), } } } diff --git a/src/config/mod.rs b/src/config/mod.rs index b18af1c81..2df1ab8df 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -431,13 +431,11 @@ pub fn load_config_paths(config_filenames: &[String]) -> Vec { // The current directory is not always available, e.g. // when a directory was deleted or inside FUSE mounts. - match env::current_dir() { - Ok(current_dir) => { - config_files.extend(file::FindUp::new(¤t_dir, config_filenames)); - } - Err(error) => { - debug!("error getting current dir: {error}"); + match &*dirs::CWD { + Some(current_dir) => { + config_files.extend(file::FindUp::new(current_dir, config_filenames)); } + None => {} }; config_files.extend(global_config_files()); From be34b768d9c09feda3c59d9a949a40609c294dcf Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 13:29:55 -0600 Subject: [PATCH 1773/1891] allow _.path to have : delimiters --- schema/mise.json | 2 +- src/config/env_directive.rs | 78 ++++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/schema/mise.json b/schema/mise.json index fa00d75a3..4caf6ae52 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -62,7 +62,7 @@ "description": "environment variables", "type": "object", "properties": { - "mise": { + "_": { "type": "object", "description": "environment modules", "properties": { diff --git a/src/config/env_directive.rs b/src/config/env_directive.rs index 6dca0160e..98aa70dc8 100644 --- a/src/config/env_directive.rs +++ b/src/config/env_directive.rs @@ -1,9 +1,9 @@ use crate::config::config_file::trust_check; use crate::config::Settings; -use crate::dirs; use crate::env_diff::{EnvDiff, EnvDiffOperation}; use crate::file::display_path; use crate::tera::{get_tera, BASE_CONTEXT}; +use crate::{dirs, env}; use eyre::Context; use indexmap::IndexMap; use std::collections::{BTreeSet, HashMap}; @@ -76,19 +76,23 @@ impl EnvResults { env_scripts: Vec::new(), }; for (directive, source) in input { - let config_root = source.parent().unwrap(); - ctx.insert("config_root", config_root); + let config_root = source + .parent() + .map(Path::to_path_buf) + .or_else(|| dirs::CWD.clone()) + .unwrap_or_default(); + ctx.insert("config_root", &config_root); let env_vars = env .iter() .map(|(k, (v, _))| (k.clone(), v.clone())) .collect::>(); ctx.insert("env", &env_vars); - let normalize_path = |s: String| { - let s = s.strip_prefix("./").unwrap_or(&s); - match s.strip_prefix("~/") { - Some(s) => dirs::HOME.join(s), - None if s.starts_with('/') => PathBuf::from(s), - None => config_root.join(s), + let normalize_path = |p: PathBuf| { + let p = p.strip_prefix("./").unwrap_or(&p); + match p.strip_prefix("~/") { + Ok(p) => dirs::HOME.join(p), + _ if p.is_relative() => config_root.join(p), + _ => p.to_path_buf(), } }; match directive { @@ -103,13 +107,14 @@ impl EnvResults { } EnvDirective::Path(input) => { let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; - let p = normalize_path(s); - r.env_paths.push(p.clone()); + env::split_paths(&s) + .map(normalize_path) + .for_each(|p| r.env_paths.push(p.clone())); } EnvDirective::File(input) => { trust_check(&source)?; let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; - let p = normalize_path(s); + let p = normalize_path(s.into()); r.env_files.push(p.clone()); let errfn = || eyre!("failed to parse dotenv file: {}", display_path(&p)); for item in dotenvy::from_path_iter(&p).wrap_err_with(errfn)? { @@ -122,7 +127,7 @@ impl EnvResults { settings.ensure_experimental("env._.source")?; trust_check(&source)?; let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?; - let p = normalize_path(s); + let p = normalize_path(s.into()); r.env_scripts.push(p.clone()); let env_diff = EnvDiff::from_bash_script(&p, env_vars.clone())?; for p in env_diff.to_patches() { @@ -165,3 +170,50 @@ impl EnvResults { Ok(output) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::test::replace_path; + + #[test] + fn test_env_path() { + let mut env = HashMap::new(); + env.insert("A".to_string(), "1".to_string()); + env.insert("B".to_string(), "2".to_string()); + let results = EnvResults::resolve( + &env, + vec![ + ( + EnvDirective::Path("/path/1".into()), + PathBuf::from("/config"), + ), + ( + EnvDirective::Path("/path/2".into()), + PathBuf::from("/config"), + ), + ( + EnvDirective::Path("~/foo/{{ env.A }}".into()), + Default::default(), + ), + ( + EnvDirective::Path("./rel/{{ env.A }}:./rel2/{{env.B}}".into()), + Default::default(), + ), + ], + ) + .unwrap(); + assert_debug_snapshot!( + results.env_paths.into_iter().map(|p| replace_path(&p.display().to_string())).collect::>(), + @r###" + [ + "/path/1", + "/path/2", + "~/foo/1", + "~/cwd/rel/1", + "~/cwd/rel2/2", + ] + "### + ); + } +} From 2baa9d9aacc47349a04b9ec20bc605ac7f3b24be Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:21:23 -0600 Subject: [PATCH 1774/1891] use serde to parse tasks (#1592) --- .mise.toml | 1 + src/config/config_file/mise_toml.rs | 260 ++++++++++------------------ src/config/config_file/toml.rs | 44 +++++ src/task.rs | 22 ++- 4 files changed, 158 insertions(+), 169 deletions(-) diff --git a/.mise.toml b/.mise.toml index dac3eaba9..a60eb183c 100644 --- a/.mise.toml +++ b/.mise.toml @@ -85,6 +85,7 @@ run = "just lint-fix" run = "node ./test/fixtures/signal-test.js" [tasks.test] +alias = 't' run = [ "mise run test:unit", "mise run test:e2e", diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index c44745ef5..0dc9f0c26 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -1,7 +1,6 @@ use std::collections::{BTreeMap, HashMap}; use std::fmt::{Debug, Formatter}; use std::path::{Path, PathBuf}; -use std::str::FromStr; use eyre::WrapErr; use itertools::Itertools; @@ -13,6 +12,7 @@ use toml_edit::{table, value, Array, Document, Item, Value}; use versions::Versioning; use crate::cli::args::ForgeArg; +use crate::config::config_file::toml::deserialize_arr; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType, TaskConfig}; use crate::config::env_directive::EnvDirective; use crate::config::AliasMap; @@ -50,10 +50,13 @@ pub struct MiseToml { plugins: HashMap, #[serde(default)] task_config: TaskConfig, - #[serde(skip)] - tasks: Vec, + #[serde(default)] + tasks: Tasks, } +#[derive(Debug, Default, Clone)] +pub struct Tasks(pub BTreeMap); + #[derive(Debug, Default, Clone)] pub struct EnvList(pub(crate) Vec); @@ -90,6 +93,11 @@ impl MiseToml { self.min_version = cfg.min_version; self.plugins = cfg.plugins; self.task_config = cfg.task_config; + self.tasks = cfg.tasks; + + for task in self.tasks.0.values_mut() { + task.config_source = self.path.clone(); + } // TODO: right now some things are parsed with serde (above) and some not (below) everything // should be moved to serde eventually @@ -98,9 +106,8 @@ impl MiseToml { for (k, v) in doc.iter() { match k { "tools" => self.toolset = self.parse_toolset(k, v)?, - "tasks" => self.tasks = self.parse_tasks(k, v)?, "alias" | "dotenv" | "env_file" | "env_path" | "min_version" | "settings" - | "env" | "plugins" | "task_config" => {} + | "env" | "plugins" | "task_config" | "tasks" => {} _ => bail!("unknown key: {}", style::ered(k)), } } @@ -108,81 +115,6 @@ impl MiseToml { Ok(()) } - fn parse_tasks(&self, key: &str, v: &Item) -> eyre::Result> { - match v.as_table_like() { - Some(table) => { - let mut tasks = Vec::new(); - for (name, v) in table.iter() { - let k = format!("{}.{}", key, name); - let name = self.parse_template(&k, name)?; - let task = self.parse_task(&k, v, &name)?; - tasks.push(task); - } - Ok(tasks) - } - _ => parse_error!(key, v, "table"), - } - } - - fn parse_task(&self, key: &str, v: &Item, name: &str) -> eyre::Result { - let mut task = Task::new(name.into(), self.path.clone()); - if v.as_str().is_some() { - task.run = self.parse_string_or_array(key, v)?; - return Ok(task); - } - if v.as_array().is_some() { - task.run = self.parse_string_array(key, v)?; - return Ok(task); - } - match v.as_table_like() { - Some(table) => { - let mut task = Task::new(name.into(), self.path.clone()); - for (k, v) in table.iter() { - let key = format!("{key}.{k}"); - match k { - "alias" => task.aliases = self.parse_string_or_array(&key, v)?, - // "args" => task.args = self.parse_string_array(&key, v)?, - "run" => task.run = self.parse_string_or_array(&key, v)?, - // "command" => task.command = Some(self.parse_string_tmpl(&key, v)?), - "depends" => task.depends = self.parse_string_array(&key, v)?, - "description" => task.description = self.parse_string(&key, v)?, - "env" => task.env = self.parse_hashmap(&key, v)?, - "file" => task.file = Some(self.parse_path(&key, v)?), - "hide" => task.hide = self.parse_bool(&key, v)?, - "dir" => task.dir = Some(self.parse_path(&key, v)?), - "outputs" => task.outputs = self.parse_string_array(&key, v)?, - "raw" => task.raw = self.parse_bool(&key, v)?, - // "script" => task.script = Some(self.parse_string_tmpl(&key, v)?), - "sources" => task.sources = self.parse_string_array(&key, v)?, - _ => parse_error!(key, v, "task property"), - } - } - Ok(task) - } - _ => parse_error!(key, v, "table"), - } - } - - fn parse_hashmap(&self, key: &str, v: &Item) -> eyre::Result> { - match v.as_table_like() { - Some(table) => { - let mut env = HashMap::new(); - for (k, v) in table.iter() { - match v.as_str() { - Some(s) => { - let k = self.parse_template(key, k)?; - let s = self.parse_template(key, s)?; - env.insert(k, s); - } - _ => parse_error!(key, v, "string"), - } - } - Ok(env) - } - _ => parse_error!(key, v, "table"), - } - } - fn parse_toolset(&self, key: &str, v: &Item) -> eyre::Result { let mut toolset = Toolset::new(self.toolset.source.clone().unwrap()); @@ -362,50 +294,6 @@ impl MiseToml { } } - fn parse_bool(&self, k: &str, v: &Item) -> eyre::Result { - match v.as_value().map(|v| v.as_bool()) { - Some(Some(v)) => Ok(v), - _ => parse_error!(k, v, "boolean"), - } - } - - fn parse_string(&self, k: &str, v: &Item) -> eyre::Result { - match v.as_value().map(|v| v.as_str()) { - Some(Some(v)) => Ok(v.to_string()), - _ => parse_error!(k, v, "string"), - } - } - - fn parse_path(&self, k: &str, v: &Item) -> eyre::Result { - match v.as_value().map(|v| v.as_str()) { - Some(Some(v)) => { - let v = self.parse_template(k, v)?; - Ok(v.into()) - } - _ => parse_error!(k, v, "path"), - } - } - - fn parse_string_or_array(&self, k: &str, v: &Item) -> eyre::Result> { - match v.as_value().map(|v| v.as_str()) { - Some(Some(v)) => { - let v = self.parse_template(k, v)?; - Ok(vec![v]) - } - _ => self.parse_string_array(k, v), - } - } - - fn parse_string_array(&self, k: &str, v: &Item) -> eyre::Result> { - match v - .as_array() - .map(|v| v.iter().map(|v| v.as_str().unwrap().to_string()).collect()) - { - Some(v) => Ok(v), - _ => parse_error!(k, v, "array of strings"), - } - } - pub fn update_env>(&mut self, key: &str, value: V) { let env_tbl = self .doc @@ -492,7 +380,7 @@ impl ConfigFile for MiseToml { } fn tasks(&self) -> Vec<&Task> { - self.tasks.iter().collect() + self.tasks.0.values().collect() } fn remove_plugin(&mut self, fa: &ForgeArg) { @@ -620,47 +508,6 @@ where } } -fn deserialize_arr<'de, D, T>(deserializer: D) -> eyre::Result, D::Error> -where - D: Deserializer<'de>, - T: FromStr, - ::Err: std::fmt::Display, -{ - struct ArrVisitor(std::marker::PhantomData); - - impl<'de, T> Visitor<'de> for ArrVisitor - where - T: FromStr, - ::Err: std::fmt::Display, - { - type Value = Vec; - fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { - formatter.write_str("string or array of strings") - } - - fn visit_str(self, v: &str) -> std::result::Result - where - E: de::Error, - { - let v = v.parse().map_err(de::Error::custom)?; - Ok(vec![v]) - } - - fn visit_seq(self, mut seq: S) -> std::result::Result - where - S: de::SeqAccess<'de>, - { - let mut v = vec![]; - while let Some(s) = seq.next_element::()? { - v.push(s.parse().map_err(de::Error::custom)?); - } - Ok(v) - } - } - - deserializer.deserialize_any(ArrVisitor(std::marker::PhantomData)) -} - impl<'de> de::Deserialize<'de> for EnvList { fn deserialize(deserializer: D) -> std::result::Result where @@ -792,6 +639,87 @@ impl<'de> de::Deserialize<'de> for EnvList { } } +impl<'de> de::Deserialize<'de> for Tasks { + fn deserialize(deserializer: D) -> std::result::Result + where + D: de::Deserializer<'de>, + { + struct TasksVisitor; + + impl<'de> Visitor<'de> for TasksVisitor { + type Value = Tasks; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("task, string, or array of strings") + } + + fn visit_map(self, mut map: M) -> std::result::Result + where + M: de::MapAccess<'de>, + { + struct TaskDef(Task); + impl<'de> de::Deserialize<'de> for TaskDef { + fn deserialize(deserializer: D) -> std::result::Result + where + D: de::Deserializer<'de>, + { + struct TaskDefVisitor; + impl<'de> Visitor<'de> for TaskDefVisitor { + type Value = TaskDef; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("task definition") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + Ok(TaskDef(Task { + run: vec![v.to_string()], + ..Default::default() + })) + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: de::SeqAccess<'de>, + { + let mut run = vec![]; + while let Some(s) = seq.next_element::()? { + run.push(s); + } + Ok(TaskDef(Task { + run, + ..Default::default() + })) + } + + fn visit_map(self, map: M) -> Result + where + M: de::MapAccess<'de>, + { + let t = de::Deserialize::deserialize( + de::value::MapAccessDeserializer::new(map), + )?; + Ok(TaskDef(t)) + } + } + deserializer.deserialize_any(TaskDefVisitor) + } + } + let mut tasks = BTreeMap::new(); + while let Some(name) = map.next_key::()? { + let mut task = map.next_value::()?.0; + task.name = name.clone(); + tasks.insert(name, task); + } + Ok(Tasks(tasks)) + } + } + + deserializer.deserialize_any(TasksVisitor) + } +} + fn deserialize_alias<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/src/config/config_file/toml.rs b/src/config/config_file/toml.rs index c874d21d0..23588df0f 100644 --- a/src/config/config_file/toml.rs +++ b/src/config/config_file/toml.rs @@ -1,4 +1,7 @@ +use serde::de; use std::collections::HashMap; +use std::fmt::Formatter; +use std::str::FromStr; use tera::{Context, Tera}; @@ -73,3 +76,44 @@ impl<'a> TomlParser<'a> { Ok(tmpl.into()) } } + +pub fn deserialize_arr<'de, D, T>(deserializer: D) -> eyre::Result, D::Error> +where + D: de::Deserializer<'de>, + T: FromStr, + ::Err: std::fmt::Display, +{ + struct ArrVisitor(std::marker::PhantomData); + + impl<'de, T> de::Visitor<'de> for ArrVisitor + where + T: FromStr, + ::Err: std::fmt::Display, + { + type Value = Vec; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("string or array of strings") + } + + fn visit_str(self, v: &str) -> std::result::Result + where + E: de::Error, + { + let v = v.parse().map_err(de::Error::custom)?; + Ok(vec![v]) + } + + fn visit_seq(self, mut seq: S) -> std::result::Result + where + S: de::SeqAccess<'de>, + { + let mut v = vec![]; + while let Some(s) = seq.next_element::()? { + v.push(s.parse().map_err(de::Error::custom)?); + } + Ok(v) + } + } + + deserializer.deserialize_any(ArrVisitor(std::marker::PhantomData)) +} diff --git a/src/task.rs b/src/task.rs index f2c3b313d..9a5aee619 100644 --- a/src/task.rs +++ b/src/task.rs @@ -16,38 +16,54 @@ use itertools::Itertools; use petgraph::graph::DiGraph; use petgraph::prelude::*; use petgraph::{Direction, Graph}; +use serde_derive::Deserialize; +use crate::config::config_file::toml::deserialize_arr; use crate::config::config_file::toml::TomlParser; use crate::config::Config; use crate::file; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::ui::tree::TreeItem; -#[derive(Debug, Default, Clone, Eq, PartialEq)] +#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize)] pub struct Task { + #[serde(skip)] pub name: String, + #[serde(default)] pub description: String, + #[serde(default, deserialize_with = "deserialize_arr")] pub aliases: Vec, + #[serde(skip)] pub config_source: PathBuf, + #[serde(default)] pub depends: Vec, + #[serde(default)] pub env: HashMap, + #[serde(default)] pub dir: Option, + #[serde(default)] pub hide: bool, + #[serde(default)] pub raw: bool, + #[serde(default)] pub sources: Vec, + #[serde(default)] pub outputs: Vec, // normal type + #[serde(default, deserialize_with = "deserialize_arr")] pub run: Vec, // command type // pub command: Option, + #[serde(default)] pub args: Vec, // script type // pub script: Option, // file type + #[serde(default)] pub file: Option, } @@ -99,8 +115,8 @@ impl Task { pub fn command_string(&self) -> Option { if let Some(command) = self.run.first() { Some(command.to_string()) - // } else if let Some(script) = &self.script { - // Some(script.to_string()) + // } else if let Some(script) = &self.script { + // Some(script.to_string()) } else { self.file .as_ref() From 0eae892c67598c788b7ca6311aaaac075279717b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:43:48 -0600 Subject: [PATCH 1775/1891] tasks: skip running glob if no patterns Fixes #1591 --- src/cli/run.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cli/run.rs b/src/cli/run.rs index 3ee4c44f9..bf29a1d52 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -489,6 +489,9 @@ fn last_modified_glob_match( root: impl AsRef, patterns: &[&String], ) -> Result> { + if patterns.is_empty() { + return Ok(None); + } let files = GlobWalkerBuilder::from_patterns(root, patterns) .follow_links(true) .build()? From ae658f8f307341c2e859f73f44558e9e82709ea9 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:44:16 -0600 Subject: [PATCH 1776/1891] lazy-load toml_edit (#1594) * lazy-load toml_edit * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- src/cli/alias/set.rs | 2 +- src/cli/alias/unset.rs | 2 +- src/cli/local.rs | 4 +- src/cli/set.rs | 8 +- src/cli/unset.rs | 5 +- src/cli/use.rs | 24 ++- src/config/config_file/legacy_version.rs | 6 +- src/config/config_file/mise_toml.rs | 191 +++++++++++------- src/config/config_file/mod.rs | 8 +- ..._config_file__mise_toml__tests__env-2.snap | 5 +- ..._config_file__mise_toml__tests__env-3.snap | 2 +- ..._config_file__mise_toml__tests__env-4.snap | 10 +- ...ile__mise_toml__tests__remove_alias-3.snap | 2 +- ...ile__mise_toml__tests__remove_alias-4.snap | 2 +- ...g_file__mise_toml__tests__set_alias-2.snap | 2 +- src/config/config_file/tool_versions.rs | 18 +- src/test.rs | 1 + 17 files changed, 190 insertions(+), 102 deletions(-) diff --git a/src/cli/alias/set.rs b/src/cli/alias/set.rs index a5408b521..31445cee6 100644 --- a/src/cli/alias/set.rs +++ b/src/cli/alias/set.rs @@ -21,7 +21,7 @@ pub struct AliasSet { impl AliasSet { pub fn run(self) -> Result<()> { let mut global_config = Config::get().global_config()?; - global_config.set_alias(&self.plugin, &self.alias, &self.value); + global_config.set_alias(&self.plugin, &self.alias, &self.value)?; global_config.save() } } diff --git a/src/cli/alias/unset.rs b/src/cli/alias/unset.rs index 709a8552d..1e5adfda6 100644 --- a/src/cli/alias/unset.rs +++ b/src/cli/alias/unset.rs @@ -19,7 +19,7 @@ pub struct AliasUnset { impl AliasUnset { pub fn run(self) -> Result<()> { let mut global_config = Config::get().global_config()?; - global_config.remove_alias(&self.plugin, &self.alias); + global_config.remove_alias(&self.plugin, &self.alias)?; global_config.save() } } diff --git a/src/cli/local.rs b/src/cli/local.rs index 0629bcca4..830c696cb 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -105,7 +105,7 @@ pub fn local( if let Some(plugins) = &remove { for plugin in plugins { - cf.remove_plugin(plugin); + cf.remove_plugin(plugin)?; } let tools = plugins .iter() @@ -128,7 +128,7 @@ pub fn local( if !runtime.is_empty() || remove.is_some() { cf.save()?; } else { - miseprint!("{}", cf.dump()); + miseprint!("{}", cf.dump()?); } Ok(()) diff --git a/src/cli/set.rs b/src/cli/set.rs index 65667a2ec..df905be7f 100644 --- a/src/cli/set.rs +++ b/src/cli/set.rs @@ -68,7 +68,7 @@ impl Set { if let Some(env_names) = &self.remove { for name in env_names { - mise_toml.remove_env(name); + mise_toml.remove_env(name)?; } } @@ -83,7 +83,7 @@ impl Set { } for ev in env_vars { match ev.value { - Some(value) => mise_toml.update_env(&ev.key, value), + Some(value) => mise_toml.update_env(&ev.key, value)?, None => bail!("{} has no value", ev.key), } } @@ -131,7 +131,7 @@ mod tests { fn remove_config_file(filename: &str) -> PathBuf { let cf_path = env::current_dir().unwrap().join(filename); - let _ = file::remove_file(&cf_path); + let _ = file::write(&cf_path, ""); cf_path } @@ -156,6 +156,7 @@ mod tests { assert_cli_snapshot!("env-vars", "--file", filename, "FOO=bar", @""); assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); + file::remove_file(filename).unwrap(); } #[test] @@ -175,5 +176,6 @@ mod tests { assert_cli_snapshot!("env-vars", "--file", filename, "--remove", "BAZ", @""); assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); + file::remove_file(filename).unwrap(); } } diff --git a/src/cli/unset.rs b/src/cli/unset.rs index e6cbb0425..0f4c458a6 100644 --- a/src/cli/unset.rs +++ b/src/cli/unset.rs @@ -36,7 +36,7 @@ impl Unset { let mut mise_toml = get_mise_toml(&filename)?; for name in self.keys.iter() { - mise_toml.remove_env(name); + mise_toml.remove_env(name)?; } mise_toml.save() @@ -62,7 +62,7 @@ mod tests { fn remove_config_file(filename: &str) -> PathBuf { let cf_path = env::current_dir().unwrap().join(filename); - let _ = file::remove_file(&cf_path); + let _ = file::write(&cf_path, ""); cf_path } @@ -76,5 +76,6 @@ mod tests { assert_cli_snapshot!("unset", "BAZ", @""); assert_snapshot!(file::read_to_string(cf_path).unwrap()); remove_config_file(filename); + file::remove_file(filename).unwrap(); } } diff --git a/src/cli/use.rs b/src/cli/use.rs index 4a5ded6cb..89a7db6c3 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -122,14 +122,14 @@ impl Use { } }) .collect(); - cf.replace_versions(fa, &versions); + cf.replace_versions(fa, &versions)?; } if self.global { self.warn_if_hidden(&config, cf.get_path()); } for plugin_name in &self.remove { - cf.remove_plugin(plugin_name); + cf.remove_plugin(plugin_name)?; } cf.save()?; self.render_success_message(cf.as_ref(), &versions); @@ -264,13 +264,31 @@ mod tests { fn test_use_global() { let cf_path = dirs::CONFIG.join("config.toml"); let orig = file::read_to_string(&cf_path).unwrap(); - let _ = file::remove_file(&cf_path); assert_cli_snapshot!("use", "-g", "tiny@2", @r###" mise ~/config/config.toml tools: tiny@2.1.0 mise tiny is defined in ~/cwd/.test-tool-versions which overrides the global config (~/config/config.toml) "###); assert_snapshot!(file::read_to_string(&cf_path).unwrap(), @r###" + [env] + TEST_ENV_VAR = 'test-123' + + [alias.tiny] + "my/alias" = '3.0' + + [tasks.configtask] + run = 'echo "configtask:"' + [tasks.lint] + run = 'echo "linting!"' + [tasks.test] + run = 'echo "testing!"' + [settings] + always_keep_download= true + always_keep_install= true + legacy_version_file= true + plugin_autoupdate_last_check_duration = "20m" + jobs = 2 + [tools] tiny = "2" "###); diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 40d27d370..489dfe36e 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -41,11 +41,11 @@ impl ConfigFile for LegacyVersionFile { self.path.as_path() } - fn remove_plugin(&mut self, _fa: &ForgeArg) { + fn remove_plugin(&mut self, _fa: &ForgeArg) -> Result<()> { unimplemented!() } - fn replace_versions(&mut self, _plugin_name: &ForgeArg, _versions: &[String]) { + fn replace_versions(&mut self, _plugin_name: &ForgeArg, _versions: &[String]) -> Result<()> { unimplemented!() } @@ -53,7 +53,7 @@ impl ConfigFile for LegacyVersionFile { unimplemented!() } - fn dump(&self) -> String { + fn dump(&self) -> Result { unimplemented!() } diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 0dc9f0c26..7fb8d2ec7 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use eyre::WrapErr; use itertools::Itertools; +use once_cell::sync::OnceCell; use serde::de::Visitor; use serde::{de, Deserializer}; use serde_derive::Deserialize; @@ -45,7 +46,7 @@ pub struct MiseToml { #[serde(default, deserialize_with = "deserialize_alias")] alias: AliasMap, #[serde(skip)] - doc: Document, + doc: OnceCell, #[serde(default)] plugins: HashMap, #[serde(default)] @@ -80,7 +81,7 @@ impl MiseToml { let mut rf = Self::init(path); let body = file::read_to_string(path)?; // .suggestion("ensure file exists and can be read")?; rf.parse(&body)?; - trace!("{}", rf.dump()); + trace!("{}", rf.dump()?); Ok(rf) } @@ -111,10 +112,21 @@ impl MiseToml { _ => bail!("unknown key: {}", style::ered(k)), } } - self.doc = doc; Ok(()) } + fn doc(&self) -> eyre::Result<&Document> { + self.doc.get_or_try_init(|| { + let body = file::read_to_string(&self.path).unwrap_or_default(); + Ok(body.parse()?) + }) + } + + fn doc_mut(&mut self) -> eyre::Result<&mut Document> { + self.doc()?; + Ok(self.doc.get_mut().unwrap()) + } + fn parse_toolset(&self, key: &str, v: &Item) -> eyre::Result { let mut toolset = Toolset::new(self.toolset.source.clone().unwrap()); @@ -258,12 +270,12 @@ impl MiseToml { } } - pub fn set_alias(&mut self, fa: &ForgeArg, from: &str, to: &str) { + pub fn set_alias(&mut self, fa: &ForgeArg, from: &str, to: &str) -> eyre::Result<()> { self.alias .entry(fa.clone()) .or_default() .insert(from.into(), to.into()); - self.doc + self.doc_mut()? .entry("alias") .or_insert_with(table) .as_table_like_mut() @@ -273,45 +285,57 @@ impl MiseToml { .as_table_like_mut() .unwrap() .insert(from, value(to)); + Ok(()) } - pub fn remove_alias(&mut self, fa: &ForgeArg, from: &str) { - if let Some(aliases) = self.doc.get_mut("alias").and_then(|v| v.as_table_mut()) { + pub fn remove_alias(&mut self, fa: &ForgeArg, from: &str) -> eyre::Result<()> { + if let Some(aliases) = self + .doc_mut()? + .get_mut("alias") + .and_then(|v| v.as_table_mut()) + { if let Some(plugin_aliases) = aliases .get_mut(&fa.to_string()) .and_then(|v| v.as_table_mut()) { - self.alias.get_mut(fa).unwrap().remove(from); plugin_aliases.remove(from); if plugin_aliases.is_empty() { aliases.remove(&fa.to_string()); - self.alias.remove(fa); } } if aliases.is_empty() { - self.doc.as_table_mut().remove("alias"); + self.doc_mut()?.as_table_mut().remove("alias"); + } + } + if let Some(aliases) = self.alias.get_mut(fa) { + aliases.remove(from); + if aliases.is_empty() { + self.alias.remove(fa); } } + Ok(()) } - pub fn update_env>(&mut self, key: &str, value: V) { + pub fn update_env>(&mut self, key: &str, value: V) -> eyre::Result<()> { let env_tbl = self - .doc + .doc_mut()? .entry("env") .or_insert_with(table) .as_table_like_mut() .unwrap(); env_tbl.insert(key, toml_edit::value(value)); + Ok(()) } - pub fn remove_env(&mut self, key: &str) { + pub fn remove_env(&mut self, key: &str) -> eyre::Result<()> { let env_tbl = self - .doc + .doc_mut()? .entry("env") .or_insert_with(table) .as_table_like_mut() .unwrap(); env_tbl.remove(key); + Ok(()) } fn parse_template(&self, k: &str, input: &str) -> eyre::Result { @@ -383,19 +407,21 @@ impl ConfigFile for MiseToml { self.tasks.0.values().collect() } - fn remove_plugin(&mut self, fa: &ForgeArg) { + fn remove_plugin(&mut self, fa: &ForgeArg) -> eyre::Result<()> { self.toolset.versions.shift_remove(fa); - if let Some(tools) = self.doc.get_mut("tools") { + let doc = self.doc_mut()?; + if let Some(tools) = doc.get_mut("tools") { if let Some(tools) = tools.as_table_like_mut() { tools.remove(&fa.to_string()); if tools.is_empty() { - self.doc.as_table_mut().remove("tools"); + doc.as_table_mut().remove("tools"); } } } + Ok(()) } - fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) { + fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) -> eyre::Result<()> { if let Some(plugin) = self.toolset.versions.get_mut(fa) { plugin.requests = versions .iter() @@ -403,7 +429,7 @@ impl ConfigFile for MiseToml { .collect(); } let tools = self - .doc + .doc_mut()? .entry("tools") .or_insert_with(table) .as_table_mut() @@ -418,18 +444,20 @@ impl ConfigFile for MiseToml { } tools.insert(&fa.to_string(), Item::Value(Value::Array(arr))); } + + Ok(()) } fn save(&self) -> eyre::Result<()> { - let contents = self.dump(); + let contents = self.dump()?; if let Some(parent) = self.path.parent() { create_dir_all(parent)?; } file::write(&self.path, contents) } - fn dump(&self) -> String { - self.doc.to_string() + fn dump(&self) -> eyre::Result { + Ok(self.doc()?.to_string()) } fn to_toolset(&self) -> &Toolset { @@ -755,6 +783,7 @@ where mod tests { use crate::dirs; use crate::test::replace_path; + use dirs::CWD; use super::*; @@ -772,17 +801,23 @@ mod tests { #[test] fn test_env() { - let cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - let env = parse_env(formatdoc! {r#" + let p = CWD.as_ref().unwrap().join(".test.mise.toml"); + file::write( + &p, + formatdoc! {r#" min_version = "2024.1.1" [env] foo="bar" - "#}); + "#}, + ) + .unwrap(); + let cf = MiseToml::from_file(&p).unwrap(); + let env = parse_env(file::read_to_string(&p).unwrap()); assert_debug_snapshot!(env, @r###""foo=bar""###); let cf: Box = Box::new(cf); with_settings!({ - assert_snapshot!(cf.dump()); + assert_snapshot!(cf.dump().unwrap()); assert_display_snapshot!(cf); assert_debug_snapshot!(cf); }); @@ -895,80 +930,98 @@ mod tests { #[test] fn test_set_alias() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" - [alias.node] - 16 = "16.0.0" - 18 = "18.0.0" - "#}) - .unwrap(); - + let p = CWD.as_ref().unwrap().join(".test.mise.toml"); + file::write( + &p, + formatdoc! {r#" + [alias.node] + 16 = "16.0.0" + 18 = "18.0.0" + "#}, + ) + .unwrap(); + let mut cf = MiseToml::from_file(&p).unwrap(); let node = "node".parse().unwrap(); let python = "python".parse().unwrap(); - cf.set_alias(&node, "18", "18.0.1"); - cf.set_alias(&node, "20", "20.0.0"); - cf.set_alias(&python, "3.10", "3.10.0"); + cf.set_alias(&node, "18", "18.0.1").unwrap(); + cf.set_alias(&node, "20", "20.0.0").unwrap(); + cf.set_alias(&python, "3.10", "3.10.0").unwrap(); assert_debug_snapshot!(cf.alias); let cf: Box = Box::new(cf); assert_display_snapshot!(cf); + file::remove_file(&p).unwrap(); } #[test] fn test_remove_alias() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" - [alias.node] - 16 = "16.0.0" - 18 = "18.0.0" - - [alias.python] - "3.10" = "3.10.0" - "#}) - .unwrap(); + let p = CWD.as_ref().unwrap().join(".test.mise.toml"); + file::write( + &p, + formatdoc! {r#" + [alias.node] + 16 = "16.0.0" + 18 = "18.0.0" + + [alias.python] + "3.10" = "3.10.0" + "#}, + ) + .unwrap(); + let mut cf = MiseToml::from_file(&p).unwrap(); let node = "node".parse().unwrap(); let python = "python".parse().unwrap(); - cf.remove_alias(&node, "16"); - cf.remove_alias(&python, "3.10"); + cf.remove_alias(&node, "16").unwrap(); + cf.remove_alias(&python, "3.10").unwrap(); assert_debug_snapshot!(cf.alias); let cf: Box = Box::new(cf); - assert_snapshot!(cf.dump()); + assert_snapshot!(cf.dump().unwrap()); assert_display_snapshot!(cf); assert_debug_snapshot!(cf); + file::remove_file(&p).unwrap(); } #[test] fn test_replace_versions() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" - [tools] - node = ["16.0.0", "18.0.0"] - "#}) - .unwrap(); + let p = PathBuf::from("/tmp/.mise.toml"); + file::write( + &p, + formatdoc! {r#" + [tools] + node = ["16.0.0", "18.0.0"] + "#}, + ) + .unwrap(); + let mut cf = MiseToml::from_file(&p).unwrap(); let node = "node".parse().unwrap(); - cf.replace_versions(&node, &["16.0.1".into(), "18.0.1".into()]); + cf.replace_versions(&node, &["16.0.1".into(), "18.0.1".into()]) + .unwrap(); assert_debug_snapshot!(cf.toolset); let cf: Box = Box::new(cf); - assert_snapshot!(cf.dump()); + assert_snapshot!(cf.dump().unwrap()); assert_display_snapshot!(cf); assert_debug_snapshot!(cf); } #[test] fn test_remove_plugin() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&formatdoc! {r#" - [tools] - node = ["16.0.0", "18.0.0"] - "#}) - .unwrap(); - cf.remove_plugin(&"node".parse().unwrap()); + let p = PathBuf::from("/tmp/.mise.toml"); + file::write( + &p, + formatdoc! {r#" + [tools] + node = ["16.0.0", "18.0.0"] + "#}, + ) + .unwrap(); + let mut cf = MiseToml::from_file(&p).unwrap(); + cf.remove_plugin(&"node".parse().unwrap()).unwrap(); assert_debug_snapshot!(cf.toolset); let cf: Box = Box::new(cf); - assert_snapshot!(cf.dump()); + assert_snapshot!(cf.dump().unwrap()); assert_display_snapshot!(cf); assert_debug_snapshot!(cf); } @@ -1044,9 +1097,9 @@ mod tests { } fn parse(s: String) -> MiseToml { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - cf.parse(&s).unwrap(); - cf + let p = CWD.as_ref().unwrap().join(".test.mise.toml"); + file::write(&p, s).unwrap(); + MiseToml::from_file(&p).unwrap() } fn parse_env(toml: String) -> String { diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 693a3346e..fe238565b 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -70,10 +70,10 @@ pub trait ConfigFile: Debug + Send + Sync { fn tasks(&self) -> Vec<&Task> { Default::default() } - fn remove_plugin(&mut self, _fa: &ForgeArg); - fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]); + fn remove_plugin(&mut self, _fa: &ForgeArg) -> Result<()>; + fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) -> Result<()>; fn save(&self) -> Result<()>; - fn dump(&self) -> String; + fn dump(&self) -> Result; fn to_toolset(&self) -> &Toolset; fn aliases(&self) -> AliasMap { Default::default() @@ -119,7 +119,7 @@ impl dyn ConfigFile { } }) .collect::>>()?; - self.replace_versions(&fa, &versions); + self.replace_versions(&fa, &versions)?; } Ok(()) diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap index a2587ae1e..ccb8ea352 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-2.snap @@ -1,5 +1,8 @@ --- source: src/config/config_file/mise_toml.rs -expression: cf.dump() +expression: cf.dump().unwrap() --- +min_version = "2024.1.1" +[env] +foo="bar" diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap index 7f358280f..efa04aea7 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-3.snap @@ -2,4 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -/tmp/.mise.toml: +~/cwd/.test.mise.toml: diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap index 11ebdc792..4377425bc 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__env-4.snap @@ -2,4 +2,12 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): +MiseToml(~/cwd/.test.mise.toml): { + min_version: "2024.1.1", + env: [ + Val( + "foo", + "bar", + ), + ], +} diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap index 7f358280f..efa04aea7 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-3.snap @@ -2,4 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -/tmp/.mise.toml: +~/cwd/.test.mise.toml: diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap index 09d6b2add..87b849d77 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__remove_alias-4.snap @@ -2,7 +2,7 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -MiseToml(/tmp/.mise.toml): { +MiseToml(~/cwd/.test.mise.toml): { alias: { ForgeArg("node"): { "18": "18.0.0", diff --git a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap index 7f358280f..efa04aea7 100644 --- a/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap +++ b/src/config/config_file/snapshots/mise__config__config_file__mise_toml__tests__set_alias-2.snap @@ -2,4 +2,4 @@ source: src/config/config_file/mise_toml.rs expression: cf --- -/tmp/.mise.toml: +~/cwd/.test.mise.toml: diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index aeb09d267..73494581a 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -159,23 +159,25 @@ impl ConfigFile for ToolVersions { self.path.as_path() } - fn remove_plugin(&mut self, fa: &ForgeArg) { + fn remove_plugin(&mut self, fa: &ForgeArg) -> Result<()> { self.plugins.shift_remove(fa); + Ok(()) } - fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) { + fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) -> eyre::Result<()> { self.get_or_create_plugin(fa).versions.clear(); for version in versions { self.add_version(fa, version); } + Ok(()) } fn save(&self) -> Result<()> { - let s = self.dump(); + let s = self.dump()?; file::write(&self.path, s) } - fn dump(&self) -> String { + fn dump(&self) -> eyre::Result { let mut s = self.pre.clone(); let max_plugin_len = self @@ -195,7 +197,7 @@ impl ConfigFile for ToolVersions { s.push_str(&format!("{} {}{}", plugin, tv.versions.join(" "), tv.post)); } - s.trim_end().to_string() + "\n" + Ok(s.trim_end().to_string() + "\n") } fn to_toolset(&self) -> &Toolset { @@ -238,7 +240,7 @@ pub(crate) mod tests { "}; let path = env::current_dir().unwrap().join(".test-tool-versions"); let tv = ToolVersions::parse_str(orig, path).unwrap(); - assert_eq!(tv.dump(), orig); + assert_eq!(tv.dump().unwrap(), orig); } #[test] @@ -248,7 +250,7 @@ pub(crate) mod tests { "}; let path = env::current_dir().unwrap().join(".test-tool-versions"); let tv = ToolVersions::parse_str(orig, path).unwrap(); - assert_snapshot!(tv.dump(), @r###" + assert_snapshot!(tv.dump().unwrap(), @r###" ruby 3.0.5 "###); } @@ -263,7 +265,7 @@ pub(crate) mod tests { assert_cli!("trust", path.to_string_lossy()); let tv = ToolVersions::parse_str(orig, path.clone()).unwrap(); assert_cli!("trust", "--untrust", path.to_string_lossy()); - assert_snapshot!(tv.dump(), @r###" + assert_snapshot!(tv.dump().unwrap(), @r###" ruby 3.0.5 python 3.11.0 "###); diff --git a/src/test.rs b/src/test.rs index 9ccf1a77e..fa0e2bb30 100644 --- a/src/test.rs +++ b/src/test.rs @@ -85,6 +85,7 @@ pub fn reset_config() { "#}, ) .unwrap(); + let _ = file::remove_file(".test.mise.toml"); } pub fn replace_path(input: &str) -> String { From 85da4516a9cfbbab5c80d09aa5e6e06d8699a0e5 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:47:09 -0600 Subject: [PATCH 1777/1891] chore: Release mise version 2024.2.3 --- Cargo.lock | 18 ++++++------- Cargo.toml | 2 +- README.md | 2 +- completions/mise.bash | 56 +++++++++++++++++++++++++++++++++++++++++ default.nix | 2 +- man/man1/mise.1 | 4 +-- packaging/rpm/mise.spec | 2 +- 7 files changed, 71 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa439ef45..e7e16d30c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,9 +277,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.9" +version = "4.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df631ae429f6613fcd3a7c1adbdb65f637271e561b03680adaa6573015dfb106" +checksum = "abb745187d7f4d76267b37485a65e0149edd0e91a4cfcdd3f27524ad86cee9f3" dependencies = [ "clap", ] @@ -304,9 +304,9 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clap_mangen" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43144ab702c764b0a3ecda5ecd2aba2e6874d8de4b9f56930bbb1e88fcecd84a" +checksum = "8e35a078f3aae828c9b7ad58e1631dab87e9dac40da19418f2219bbf3198aa5c" dependencies = [ "clap", "roff", @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.2.2" +version = "2024.2.3" dependencies = [ "base64", "built", @@ -2502,9 +2502,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -2914,9 +2914,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.3" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "which" diff --git a/Cargo.toml b/Cargo.toml index 76924eae4..f8dfced60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.2.2" +version = "2024.2.3" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 837477b82..752aaed18 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -mise 2024.2.2 +mise 2024.2.3 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/completions/mise.bash b/completions/mise.bash index f803724a7..3e86b6483 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -1291,14 +1291,30 @@ _mise() { fi case "${prev}" in --output) + local oldifs + if [[ -v IFS ]]; then + oldifs="$IFS" + fi + IFS=$'\n' COMPREPLY=($(compgen -f "${cur}")) + if [[ -v oldifs ]]; then + IFS="$oldifs" + fi if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then compopt -o filenames fi return 0 ;; -o) + local oldifs + if [[ -v IFS ]]; then + oldifs="$IFS" + fi + IFS=$'\n' COMPREPLY=($(compgen -f "${cur}")) + if [[ -v oldifs ]]; then + IFS="$oldifs" + fi if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then compopt -o filenames fi @@ -3831,7 +3847,15 @@ _mise() { fi case "${prev}" in --file) + local oldifs + if [[ -v IFS ]]; then + oldifs="$IFS" + fi + IFS=$'\n' COMPREPLY=($(compgen -f "${cur}")) + if [[ -v oldifs ]]; then + IFS="$oldifs" + fi if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then compopt -o filenames fi @@ -4634,14 +4658,30 @@ _mise() { fi case "${prev}" in --file) + local oldifs + if [[ -v IFS ]]; then + oldifs="$IFS" + fi + IFS=$'\n' COMPREPLY=($(compgen -f "${cur}")) + if [[ -v oldifs ]]; then + IFS="$oldifs" + fi if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then compopt -o filenames fi return 0 ;; -f) + local oldifs + if [[ -v IFS ]]; then + oldifs="$IFS" + fi + IFS=$'\n' COMPREPLY=($(compgen -f "${cur}")) + if [[ -v oldifs ]]; then + IFS="$oldifs" + fi if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then compopt -o filenames fi @@ -4740,14 +4780,30 @@ _mise() { return 0 ;; --path) + local oldifs + if [[ -v IFS ]]; then + oldifs="$IFS" + fi + IFS=$'\n' COMPREPLY=($(compgen -f "${cur}")) + if [[ -v oldifs ]]; then + IFS="$oldifs" + fi if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then compopt -o filenames fi return 0 ;; -p) + local oldifs + if [[ -v IFS ]]; then + oldifs="$IFS" + fi + IFS=$'\n' COMPREPLY=($(compgen -f "${cur}")) + if [[ -v oldifs ]]; then + IFS="$oldifs" + fi if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then compopt -o filenames fi diff --git a/default.nix b/default.nix index db9fc9cb9..0c334bea9 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.2.2"; + version = "2024.2.3"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 9acff2807..2a7c15fde 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.2.2" +.TH mise 1 "mise 2024.2.3" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.2.2 +v2024.2.3 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 12696fefa..a43a26572 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.2.2 +Version: 2024.2.3 Release: 1 URL: https://github.com/jdx/mise/ Group: System From a43f40bdf9b9898789db0125e139df8b29045021 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Fri, 2 Feb 2024 20:55:12 -0500 Subject: [PATCH 1778/1891] fix(tasks): fix parsing of alias attribute (#1596) --- src/task.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/task.rs b/src/task.rs index 9a5aee619..2ed3479d3 100644 --- a/src/task.rs +++ b/src/task.rs @@ -31,7 +31,7 @@ pub struct Task { pub name: String, #[serde(default)] pub description: String, - #[serde(default, deserialize_with = "deserialize_arr")] + #[serde(default, rename = "alias", deserialize_with = "deserialize_arr")] pub aliases: Vec, #[serde(skip)] pub config_source: PathBuf, From e2e9af7c7c52efeab4896445c45e89f17c92d9a2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 20:21:20 -0600 Subject: [PATCH 1779/1891] fix(deps): update rust crate clap_mangen to 0.2.19 (#1598) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f8dfced60..df03401b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ base64 = "0.21.7" chrono = { version = "0.4.33", default-features = false, features = ["std", "clock"] } clap = { version = "4.4.18", features = ["env", "derive", "string"] } clap_complete = { version = "4.4.9", optional = true } -clap_mangen = { version = "0.2.17", optional = true } +clap_mangen = { version = "0.2.19", optional = true } color-eyre = "0.6.2" color-print = "0.3.5" confique = { version = "0.2.5", default-features = false } From 51594917d1860c434aeeb0095e64ad247518c858 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 02:27:23 +0000 Subject: [PATCH 1780/1891] fix(deps): update rust crate clap_complete to 4.4.10 (#1597) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index df03401b3..8568fc3b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ lto = true base64 = "0.21.7" chrono = { version = "0.4.33", default-features = false, features = ["std", "clock"] } clap = { version = "4.4.18", features = ["env", "derive", "string"] } -clap_complete = { version = "4.4.9", optional = true } +clap_complete = { version = "4.4.10", optional = true } clap_mangen = { version = "0.2.19", optional = true } color-eyre = "0.6.2" color-print = "0.3.5" From b64b0a8a34d40529b51a6909120e08a4db47ac49 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 02:27:34 +0000 Subject: [PATCH 1781/1891] fix(deps): update rust crate eyre to 0.6.12 (#1601) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8568fc3b7..a6e463e02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ demand = "1.0.1" dotenvy = "0.15.7" duct = "0.13.7" either = "1.9.0" -eyre = "0.6.11" +eyre = "0.6.12" filetime = "0.2.23" flate2 = "1.0.28" fslock = "0.2.1" From 96afcd302d97f844de2a5956acd691aeee6189bd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 02:27:58 +0000 Subject: [PATCH 1782/1891] fix(deps): update rust crate indexmap to 2.2.2 (#1602) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a6e463e02..ec202348c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ globwalk = "0.9.1" home = "0.5.9" humantime = "2.1.0" indenter = "0.3.3" -indexmap = { version = "2.2.0", features = ["serde"] } +indexmap = { version = "2.2.2", features = ["serde"] } indicatif = { version = "0.17.7", features = ["default", "improved_unicode"] } indoc = "2.0.4" itertools = "0.12.0" From a508ec2d725a0ca1a84c4dc0fdd0bdafa4426472 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 20:29:03 -0600 Subject: [PATCH 1783/1891] chore: Release mise version 2024.2.4 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 ++-- packaging/rpm/mise.spec | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7e16d30c..8e44b1a4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.2.3" +version = "2024.2.4" dependencies = [ "base64", "built", @@ -3105,9 +3105,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.36" +version = "0.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818ce546a11a9986bc24f93d0cdf38a8a1a400f1473ea8c82e59f6e0ffab9249" +checksum = "a7cad8365489051ae9f054164e459304af2e7e9bb407c958076c8bf4aef52da5" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index ec202348c..ee39cfe44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.2.3" +version = "2024.2.4" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 752aaed18..a4039a3e4 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -mise 2024.2.3 +mise 2024.2.4 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 0c334bea9..9e51eb70b 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.2.3"; + version = "2024.2.4"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 2a7c15fde..5611f8f77 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.2.3" +.TH mise 1 "mise 2024.2.4" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.2.3 +v2024.2.4 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index a43a26572..b40317add 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.2.3 +Version: 2024.2.4 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 1a7b3f00735a11a84727d830c975ac49afc21722 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 21:06:01 -0600 Subject: [PATCH 1784/1891] use serde to parse tools (#1599) * use serde to parse tools * Commit from GitHub Actions (test) * use serde to parse tools --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- src/cli/args/mod.rs | 1 + src/cli/args/tool_arg.rs | 13 + src/cli/config/ls.rs | 2 +- src/cli/prune.rs | 2 +- src/config/config_file/legacy_version.rs | 4 +- src/config/config_file/mise_toml.rs | 402 +++++++++++------------ src/config/config_file/mod.rs | 8 +- src/config/config_file/tool_versions.rs | 6 +- src/toolset/builder.rs | 13 +- src/toolset/mod.rs | 8 +- 10 files changed, 230 insertions(+), 229 deletions(-) diff --git a/src/cli/args/mod.rs b/src/cli/args/mod.rs index f26ed5f4c..d4cc06645 100644 --- a/src/cli/args/mod.rs +++ b/src/cli/args/mod.rs @@ -4,6 +4,7 @@ pub use forge_arg::ForgeArg; pub use log_level_arg::{DebugArg, LogLevelArg, TraceArg}; pub use quiet_arg::QuietArg; pub use tool_arg::ToolArg; +pub use tool_arg::ToolVersionType; pub use verbose_arg::VerboseArg; pub use yes_arg::YesArg; diff --git a/src/cli/args/tool_arg.rs b/src/cli/args/tool_arg.rs index 2ec606bab..69be11804 100644 --- a/src/cli/args/tool_arg.rs +++ b/src/cli/args/tool_arg.rs @@ -69,6 +69,19 @@ impl FromStr for ToolVersionType { } } +impl Display for ToolVersionType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Path(p) => write!(f, "path:{}", p.to_string_lossy()), + Self::Prefix(p) => write!(f, "prefix:{}", p), + Self::Ref(r) => write!(f, "ref:{}", r), + Self::Sub { sub, orig_version } => write!(f, "sub-{}:{}", sub, orig_version), + Self::System => write!(f, "system"), + Self::Version(v) => write!(f, "{}", v), + } + } +} + impl ToolArg { /// this handles the case where the user typed in: /// mise local node 20.0.0 diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index bdc4cc943..d8d541ac0 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -55,7 +55,7 @@ struct Row { impl From<&dyn ConfigFile> for Row { fn from(cf: &dyn ConfigFile) -> Self { let path = display_path(cf.get_path()); - let ts = cf.to_toolset(); + let ts = cf.to_toolset().unwrap(); let plugins = ts.list_plugins().into_iter().join(", "); let plugins = format_plugin_cell(plugins); Self { path, plugins } diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 7921a3132..ae3b3e6c2 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -44,7 +44,7 @@ impl Prune { } for cf in config.get_tracked_config_files()?.values() { - let mut ts = cf.to_toolset().clone(); + let mut ts = cf.to_toolset()?.clone(); ts.resolve(); for (_, tv) in ts.list_current_versions() { to_delete.remove(&tv.to_string()); diff --git a/src/config/config_file/legacy_version.rs b/src/config/config_file/legacy_version.rs index 489dfe36e..96058f6a2 100644 --- a/src/config/config_file/legacy_version.rs +++ b/src/config/config_file/legacy_version.rs @@ -57,7 +57,7 @@ impl ConfigFile for LegacyVersionFile { unimplemented!() } - fn to_toolset(&self) -> &Toolset { - &self.toolset + fn to_toolset(&self) -> Result { + Ok(self.toolset.clone()) } } diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 7fb8d2ec7..59105ceb4 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -3,6 +3,7 @@ use std::fmt::{Debug, Formatter}; use std::path::{Path, PathBuf}; use eyre::WrapErr; +use indexmap::IndexMap; use itertools::Itertools; use once_cell::sync::OnceCell; use serde::de::Visitor; @@ -12,22 +13,20 @@ use tera::Context as TeraContext; use toml_edit::{table, value, Array, Document, Item, Value}; use versions::Versioning; -use crate::cli::args::ForgeArg; +use crate::cli::args::{ForgeArg, ToolVersionType}; use crate::config::config_file::toml::deserialize_arr; use crate::config::config_file::{trust_check, ConfigFile, ConfigFileType, TaskConfig}; use crate::config::env_directive::EnvDirective; +use crate::config::settings::SettingsPartial; use crate::config::AliasMap; use crate::file::{create_dir_all, display_path}; use crate::task::Task; use crate::tera::{get_tera, BASE_CONTEXT}; -use crate::toolset::{ - ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, -}; -use crate::ui::style; -use crate::{dirs, file, parse_error}; +use crate::toolset::{ToolSource, ToolVersionOptions, ToolVersionRequest, Toolset}; +use crate::{dirs, file}; #[derive(Default, Deserialize)] -// #[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields)] pub struct MiseToml { #[serde(default, deserialize_with = "deserialize_version")] min_version: Option, @@ -35,8 +34,6 @@ pub struct MiseToml { context: TeraContext, #[serde(skip)] path: PathBuf, - #[serde(skip)] - toolset: Toolset, #[serde(default, alias = "dotenv", deserialize_with = "deserialize_arr")] env_file: Vec, #[serde(default)] @@ -48,11 +45,24 @@ pub struct MiseToml { #[serde(skip)] doc: OnceCell, #[serde(default)] + tools: IndexMap, + #[serde(default)] plugins: HashMap, #[serde(default)] task_config: TaskConfig, #[serde(default)] tasks: Tasks, + #[serde(default)] + settings: SettingsPartial, +} + +#[derive(Debug, Default, Clone)] +pub struct MiseTomlToolList(Vec); + +#[derive(Debug, Clone)] +pub struct MiseTomlTool { + pub tt: ToolVersionType, + pub options: ToolVersionOptions, } #[derive(Debug, Default, Clone)] @@ -68,53 +78,25 @@ impl MiseToml { Self { path: path.to_path_buf(), context, - toolset: Toolset { - source: Some(ToolSource::MiseToml(path.to_path_buf())), - ..Default::default() - }, ..Default::default() } } pub fn from_file(path: &Path) -> eyre::Result { trace!("parsing: {}", display_path(path)); - let mut rf = Self::init(path); - let body = file::read_to_string(path)?; // .suggestion("ensure file exists and can be read")?; - rf.parse(&body)?; + let body = file::read_to_string(path)?; + let mut rf: MiseToml = toml::from_str(&body)?; + rf.context = BASE_CONTEXT.clone(); + rf.context + .insert("config_root", path.parent().unwrap().to_str().unwrap()); + rf.path = path.to_path_buf(); + for task in rf.tasks.0.values_mut() { + task.config_source = rf.path.clone(); + } trace!("{}", rf.dump()?); Ok(rf) } - fn parse(&mut self, s: &str) -> eyre::Result<()> { - let cfg: MiseToml = toml::from_str(s)?; - self.alias = cfg.alias; - self.env = cfg.env; - self.env_file = cfg.env_file; - self.env_path = cfg.env_path; - self.min_version = cfg.min_version; - self.plugins = cfg.plugins; - self.task_config = cfg.task_config; - self.tasks = cfg.tasks; - - for task in self.tasks.0.values_mut() { - task.config_source = self.path.clone(); - } - - // TODO: right now some things are parsed with serde (above) and some not (below) everything - // should be moved to serde eventually - - let doc: Document = s.parse()?; // .suggestion("ensure file is valid TOML")?; - for (k, v) in doc.iter() { - match k { - "tools" => self.toolset = self.parse_toolset(k, v)?, - "alias" | "dotenv" | "env_file" | "env_path" | "min_version" | "settings" - | "env" | "plugins" | "task_config" | "tasks" => {} - _ => bail!("unknown key: {}", style::ered(k)), - } - } - Ok(()) - } - fn doc(&self) -> eyre::Result<&Document> { self.doc.get_or_try_init(|| { let body = file::read_to_string(&self.path).unwrap_or_default(); @@ -127,149 +109,6 @@ impl MiseToml { Ok(self.doc.get_mut().unwrap()) } - fn parse_toolset(&self, key: &str, v: &Item) -> eyre::Result { - let mut toolset = Toolset::new(self.toolset.source.clone().unwrap()); - - match v.as_table_like() { - Some(table) => { - for (plugin, v) in table.iter() { - let k = format!("{}.{}", key, plugin); - let fa: ForgeArg = plugin.parse()?; - let tvl = self.parse_tool_version_list(&k, v, fa.clone())?; - toolset.versions.insert(fa, tvl); - } - Ok(toolset) - } - _ => parse_error!(key, v, "table"), - } - } - - fn parse_tool_version_list( - &self, - key: &str, - v: &Item, - fa: ForgeArg, - ) -> eyre::Result { - let source = ToolSource::MiseToml(self.path.clone()); - let mut tool_version_list = ToolVersionList::new(fa.clone(), source); - - match v { - Item::ArrayOfTables(v) => { - for table in v.iter() { - for (tool, v) in table.iter() { - let k = format!("{}.{}", key, tool); - let (tvr, opts) = self.parse_tool_version(&k, v, fa.clone())?; - tool_version_list.requests.push((tvr, opts)); - } - } - } - v => match v.as_array() { - Some(v) => { - for v in v.iter() { - let item = Item::Value(v.clone()); - let (tvr, opts) = self.parse_tool_version(key, &item, fa.clone())?; - tool_version_list.requests.push((tvr, opts)); - } - } - _ => { - tool_version_list - .requests - .push(self.parse_tool_version(key, v, fa)?); - } - }, - } - - for (tvr, _) in &tool_version_list.requests { - if let ToolVersionRequest::Path(_, _) = tvr { - // "path:" can be dangerous to run automatically - trust_check(&self.path)?; - } - } - - Ok(tool_version_list) - } - - fn parse_tool_version( - &self, - key: &str, - v: &Item, - fa: ForgeArg, - ) -> eyre::Result<(ToolVersionRequest, ToolVersionOptions)> { - match v.as_table_like() { - Some(table) => { - let tv = if let Some(v) = table.get("version") { - match v { - Item::Value(v) => self.parse_tool_version_request(key, v, fa)?, - _ => parse_error!(format!("{}.version", key), v, "string"), - } - } else if let Some(path) = table.get("path") { - match path.as_str() { - Some(s) => { - let s = self.parse_template(key, s)?; - ToolVersionRequest::Path(fa, s.into()) - } - _ => parse_error!(format!("{}.path", key), v, "string"), - } - } else if let Some(prefix) = table.get("prefix") { - match prefix.as_str() { - Some(s) => { - let s = self.parse_template(key, s)?; - ToolVersionRequest::Prefix(fa, s) - } - _ => parse_error!(format!("{}.prefix", key), v, "string"), - } - } else if let Some(r) = table.get("ref") { - match r.as_str() { - Some(s) => { - let s = self.parse_template(key, s)?; - ToolVersionRequest::Ref(fa, s) - } - _ => parse_error!(format!("{}.ref", key), v, "string"), - } - } else { - parse_error!(key, v, "version, path, or prefix"); - }; - let mut opts = ToolVersionOptions::default(); - for (k, v) in table.iter() { - if k == "version" || k == "path" || k == "prefix" || k == "ref" { - continue; - } - let s = if let Some(s) = v.as_str() { - self.parse_template(key, s)? - } else if let Some(b) = v.as_bool() { - b.to_string() - } else { - parse_error!(key, v, "string or bool"); - }; - opts.insert(k.into(), s); - } - Ok((tv, opts)) - } - _ => match v { - Item::Value(v) => { - let tv = self.parse_tool_version_request(key, v, fa)?; - Ok((tv, Default::default())) - } - _ => parse_error!(key, v, "value"), - }, - } - } - - fn parse_tool_version_request( - &self, - key: &str, - v: &Value, - fa: ForgeArg, - ) -> eyre::Result { - match v.as_str() { - Some(s) => { - let s = self.parse_template(key, s)?; - Ok(ToolVersionRequest::new(fa, &s)) - } - _ => parse_error!(key, v, "string"), - } - } - pub fn set_alias(&mut self, fa: &ForgeArg, from: &str, to: &str) -> eyre::Result<()> { self.alias .entry(fa.clone()) @@ -408,7 +247,7 @@ impl ConfigFile for MiseToml { } fn remove_plugin(&mut self, fa: &ForgeArg) -> eyre::Result<()> { - self.toolset.versions.shift_remove(fa); + self.tools.shift_remove(fa); let doc = self.doc_mut()?; if let Some(tools) = doc.get_mut("tools") { if let Some(tools) = tools.as_table_like_mut() { @@ -422,12 +261,13 @@ impl ConfigFile for MiseToml { } fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) -> eyre::Result<()> { - if let Some(plugin) = self.toolset.versions.get_mut(fa) { - plugin.requests = versions - .iter() - .map(|s| (ToolVersionRequest::new(fa.clone(), s), Default::default())) - .collect(); - } + self.tools.entry(fa.clone()).or_default().0 = versions + .iter() + .map(|v| MiseTomlTool { + tt: ToolVersionType::Version(v.clone()), + options: Default::default(), + }) + .collect(); let tools = self .doc_mut()? .entry("tools") @@ -460,8 +300,22 @@ impl ConfigFile for MiseToml { Ok(self.doc()?.to_string()) } - fn to_toolset(&self) -> &Toolset { - &self.toolset + fn to_toolset(&self) -> eyre::Result { + let mut toolset = Toolset::new(ToolSource::MiseToml(self.path.clone())); + for (fa, tvp) in &self.tools { + for tool in &tvp.0 { + if let ToolVersionType::Path(_) = &tool.tt { + trust_check(&self.path)?; + } + let tvr = ToolVersionRequest::new(fa.clone(), &tool.tt.to_string()); + let mut options = tool.options.clone(); + for (k, v) in &mut options { + *v = self.parse_template(k, v)?; + } + toolset.add_version(tvr, options); + } + } + Ok(toolset) } fn aliases(&self) -> AliasMap { @@ -475,7 +329,7 @@ impl ConfigFile for MiseToml { impl Debug for MiseToml { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let tools = self.toolset.to_string(); + let tools = self.to_toolset().unwrap().to_string(); let title = format!("MiseToml({}): {tools}", &display_path(&self.path)); let mut d = f.debug_struct(&title); if let Some(min_version) = &self.min_version { @@ -507,15 +361,16 @@ impl Clone for MiseToml { min_version: self.min_version.clone(), context: self.context.clone(), path: self.path.clone(), - toolset: self.toolset.clone(), env_file: self.env_file.clone(), env: self.env.clone(), env_path: self.env_path.clone(), alias: self.alias.clone(), doc: self.doc.clone(), + tools: self.tools.clone(), plugins: self.plugins.clone(), tasks: self.tasks.clone(), task_config: self.task_config.clone(), + settings: self.settings.clone(), } } } @@ -667,6 +522,113 @@ impl<'de> de::Deserialize<'de> for EnvList { } } +impl<'de> de::Deserialize<'de> for MiseTomlToolList { + fn deserialize(deserializer: D) -> std::result::Result + where + D: de::Deserializer<'de>, + { + struct MiseTomlToolListVisitor; + + impl<'de> Visitor<'de> for MiseTomlToolListVisitor { + type Value = MiseTomlToolList; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("tool list") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + let tt: ToolVersionType = v + .parse() + .map_err(|e| de::Error::custom(format!("invalid tool: {e}")))?; + Ok(MiseTomlToolList(vec![MiseTomlTool { + tt, + options: Default::default(), + }])) + } + + fn visit_map(self, map: M) -> std::result::Result + where + M: de::MapAccess<'de>, + { + let mut options: BTreeMap = + de::Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; + let tt: ToolVersionType = options + .remove("version") + .or_else(|| options.remove("path").map(|p| format!("path:{p}"))) + .or_else(|| options.remove("prefix").map(|p| format!("prefix:{p}"))) + .or_else(|| options.remove("ref").map(|p| format!("ref:{p}"))) + .ok_or_else(|| de::Error::custom("missing version"))? + .parse() + .map_err(de::Error::custom)?; + Ok(MiseTomlToolList(vec![MiseTomlTool { tt, options }])) + } + + fn visit_seq(self, mut seq: S) -> std::result::Result + where + S: de::SeqAccess<'de>, + { + let mut tools = vec![]; + while let Some(tool) = seq.next_element::()? { + tools.push(tool); + } + Ok(MiseTomlToolList(tools)) + } + } + + deserializer.deserialize_any(MiseTomlToolListVisitor) + } +} + +impl<'de> de::Deserialize<'de> for MiseTomlTool { + fn deserialize(deserializer: D) -> std::result::Result + where + D: de::Deserializer<'de>, + { + struct MiseTomlToolVisitor; + + impl<'de> Visitor<'de> for MiseTomlToolVisitor { + type Value = MiseTomlTool; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("tool definition") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + let tt: ToolVersionType = v + .parse() + .map_err(|e| de::Error::custom(format!("invalid tool: {e}")))?; + Ok(MiseTomlTool { + tt, + options: Default::default(), + }) + } + + fn visit_map(self, map: M) -> Result + where + M: de::MapAccess<'de>, + { + let mut options: BTreeMap = + de::Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; + let tt: ToolVersionType = options + .remove("version") + .or_else(|| options.remove("path").map(|p| format!("path:{p}"))) + .or_else(|| options.remove("prefix").map(|p| format!("prefix:{p}"))) + .or_else(|| options.remove("ref").map(|p| format!("ref:{p}"))) + .ok_or_else(|| de::Error::custom("missing version"))? + .parse() + .map_err(de::Error::custom)?; + Ok(MiseTomlTool { tt, options }) + } + } + + deserializer.deserialize_any(MiseTomlToolVisitor) + } +} + impl<'de> de::Deserialize<'de> for Tasks { fn deserialize(deserializer: D) -> std::result::Result where @@ -748,6 +710,31 @@ impl<'de> de::Deserialize<'de> for Tasks { } } +impl<'de> de::Deserialize<'de> for ForgeArg { + fn deserialize(deserializer: D) -> std::result::Result + where + D: de::Deserializer<'de>, + { + struct ForgeArgVisitor; + + impl<'de> Visitor<'de> for ForgeArgVisitor { + type Value = ForgeArg; + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("forge argument") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + v.parse().map_err(de::Error::custom) + } + } + + deserializer.deserialize_any(ForgeArgVisitor) + } +} + fn deserialize_alias<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -781,9 +768,10 @@ where #[cfg(test)] mod tests { + use dirs::CWD; + use crate::dirs; use crate::test::replace_path; - use dirs::CWD; use super::*; @@ -793,7 +781,7 @@ mod tests { assert_debug_snapshot!(cf.env_entries()); assert_debug_snapshot!(cf.plugins()); - assert_snapshot!(replace_path(&format!("{:#?}", cf.toolset))); + assert_snapshot!(replace_path(&format!("{:#?}", cf.to_toolset().unwrap()))); assert_debug_snapshot!(cf.alias); assert_snapshot!(replace_path(&format!("{:#?}", &cf))); @@ -998,7 +986,7 @@ mod tests { cf.replace_versions(&node, &["16.0.1".into(), "18.0.1".into()]) .unwrap(); - assert_debug_snapshot!(cf.toolset); + assert_debug_snapshot!(cf.to_toolset().unwrap()); let cf: Box = Box::new(cf); assert_snapshot!(cf.dump().unwrap()); assert_display_snapshot!(cf); @@ -1019,7 +1007,7 @@ mod tests { let mut cf = MiseToml::from_file(&p).unwrap(); cf.remove_plugin(&"node".parse().unwrap()).unwrap(); - assert_debug_snapshot!(cf.toolset); + assert_debug_snapshot!(cf.to_toolset().unwrap()); let cf: Box = Box::new(cf); assert_snapshot!(cf.dump().unwrap()); assert_display_snapshot!(cf); @@ -1028,12 +1016,10 @@ mod tests { #[test] fn test_fail_with_unknown_key() { - let mut cf = MiseToml::init(PathBuf::from("/tmp/.mise.toml").as_path()); - let _ = cf - .parse(&formatdoc! {r#" + let _ = toml::from_str::(&formatdoc! {r#" invalid_key = true "#}) - .unwrap_err(); + .unwrap_err(); } #[test] diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index fe238565b..63771276e 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -74,7 +74,7 @@ pub trait ConfigFile: Debug + Send + Sync { fn replace_versions(&mut self, fa: &ForgeArg, versions: &[String]) -> Result<()>; fn save(&self) -> Result<()>; fn dump(&self) -> Result; - fn to_toolset(&self) -> &Toolset; + fn to_toolset(&self) -> Result; fn aliases(&self) -> AliasMap { Default::default() } @@ -87,7 +87,7 @@ pub trait ConfigFile: Debug + Send + Sync { impl dyn ConfigFile { pub fn add_runtimes(&mut self, tools: &[ToolArg], pin: bool) -> Result<()> { // TODO: this has become a complete mess and could probably be greatly simplified - let mut ts = self.to_toolset().to_owned(); + let mut ts = self.to_toolset()?.to_owned(); ts.resolve(); let mut plugins_to_update = HashMap::new(); for ta in tools { @@ -133,7 +133,7 @@ impl dyn ConfigFile { if runtimes.len() == 1 && runtimes[0].tvr.is_none() { let fa = &runtimes[0].forge; let tvl = self - .to_toolset() + .to_toolset()? .versions .get(fa) .ok_or_else(|| { @@ -313,7 +313,7 @@ fn detect_config_file_type(path: &Path) -> Option { impl Display for dyn ConfigFile { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let toolset = self.to_toolset().to_string(); + let toolset = self.to_toolset().unwrap().to_string(); write!(f, "{}: {toolset}", &display_path(self.get_path())) } } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 73494581a..6ff777d7b 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -200,8 +200,8 @@ impl ConfigFile for ToolVersions { Ok(s.trim_end().to_string() + "\n") } - fn to_toolset(&self) -> &Toolset { - &self.toolset + fn to_toolset(&self) -> Result { + Ok(self.toolset.clone()) } } @@ -278,6 +278,6 @@ pub(crate) mod tests { "}; let path = env::current_dir().unwrap().join(".test-tool-versions"); let tv = ToolVersions::parse_str(orig, path).unwrap(); - assert_display_snapshot!(tv.to_toolset(), @"ruby@3.0.5 ruby@3.1"); + assert_display_snapshot!(tv.to_toolset().unwrap(), @"ruby@3.0.5 ruby@3.1"); } } diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index dd1b5bd70..50cc26418 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -39,7 +39,7 @@ impl ToolsetBuilder { .collect::>()?, ..Default::default() }; - self.load_config_files(config, &mut toolset); + self.load_config_files(config, &mut toolset)?; self.load_runtime_env(&mut toolset, env::vars().collect()); self.load_runtime_args(&mut toolset); toolset.resolve(); @@ -48,13 +48,14 @@ impl ToolsetBuilder { Ok(toolset) } - fn load_config_files(&self, config: &Config, ts: &mut Toolset) { + fn load_config_files(&self, config: &Config, ts: &mut Toolset) -> eyre::Result<()> { for cf in config.config_files.values().rev() { if self.global_only && !config::is_global_config(cf.get_path()) { - return; + return Ok(()); } - ts.merge(cf.to_toolset()); + ts.merge(cf.to_toolset()?); } + Ok(()) } fn load_runtime_env(&self, ts: &mut Toolset, env: BTreeMap) { @@ -78,7 +79,7 @@ impl ToolsetBuilder { let tvr = ToolVersionRequest::new(fa.clone(), v); env_ts.add_version(tvr, Default::default()); } - ts.merge(&env_ts); + ts.merge(env_ts); } } } @@ -94,7 +95,7 @@ impl ToolsetBuilder { arg_ts.add_version(tvr.clone(), Default::default()); } } - ts.merge(&arg_ts); + ts.merge(arg_ts); } } } diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 94f34987f..b5ffd1e49 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -85,16 +85,16 @@ impl Toolset { .or_insert_with(|| ToolVersionList::new(fa.clone(), self.source.clone().unwrap())); tvl.requests.push((tvr, opts)); } - pub fn merge(&mut self, other: &Toolset) { - let mut versions = other.versions.clone(); + pub fn merge(&mut self, other: Toolset) { + let mut versions = other.versions; for (plugin, tvl) in self.versions.clone() { - if !other.versions.contains_key(&plugin) { + if !versions.contains_key(&plugin) { versions.insert(plugin, tvl); } } versions.retain(|_, tvl| !self.disable_tools.contains(&tvl.forge)); self.versions = versions; - self.source = other.source.clone(); + self.source = other.source; } pub fn resolve(&mut self) { self.list_missing_plugins(); From 2292c1152fc037e71f5def24cea32bf1f3c3ffb2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 21:07:06 -0600 Subject: [PATCH 1785/1891] fix(deps): update rust crate itertools to 0.12.1 (#1604) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ee39cfe44..29f212d1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,7 @@ indenter = "0.3.3" indexmap = { version = "2.2.2", features = ["serde"] } indicatif = { version = "0.17.7", features = ["default", "improved_unicode"] } indoc = "2.0.4" -itertools = "0.12.0" +itertools = "0.12.1" log = "0.4.20" num_cpus = "1.16.0" once_cell = "1.19.0" From d9597906d796900f751a1dc01a39b3942655ddcd Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 2 Feb 2024 21:21:44 -0600 Subject: [PATCH 1786/1891] tasks: support "false" env vars (#1603) --- Cargo.lock | 3 +++ Cargo.toml | 2 +- schema/mise.json | 8 +++++++- src/cli/run.rs | 16 ++++++++++++++-- src/config/config_file/toml.rs | 35 +++++++++++++++++++++++++--------- src/task.rs | 8 ++++++-- 6 files changed, 57 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e44b1a4f..eb85c503a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,6 +619,9 @@ name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] [[package]] name = "encode_unicode" diff --git a/Cargo.toml b/Cargo.toml index 29f212d1a..d191e1207 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ contracts = "0.6.3" demand = "1.0.1" dotenvy = "0.15.7" duct = "0.13.7" -either = "1.9.0" +either = { version = "1.9.0", features = ["serde"] } eyre = "0.6.12" filetime = "0.2.23" flate2 = "1.0.28" diff --git a/schema/mise.json b/schema/mise.json index 4caf6ae52..96572fde3 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -202,7 +202,13 @@ "env": { "description": "environment variables", "type": "object", - "additionalProperties": { "type": "string" } + "additionalProperties": { + "oneOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "boolean", "enum": [false] } + ] + } }, "quiet": { "description": "do not display mise information for this task", diff --git a/src/cli/run.rs b/src/cli/run.rs index bf29a1d52..d2942ce11 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; use std::io::Write; use std::iter::once; use std::os::unix::prelude::ExitStatusExt; @@ -12,6 +12,7 @@ use clap::ValueHint; use console::Color; use demand::{DemandOption, Select}; use duct::IntoExecutablePath; +use either::Either; use eyre::Result; use globwalk::GlobWalkerBuilder; use itertools::Itertools; @@ -215,9 +216,20 @@ impl Run { return Ok(()); } + let string_env = task.env.iter().filter_map(|(k, v)| match &v.0 { + Either::Left(v) => Some((k, v)), + _ => None, + }); + let rm_env = task + .env + .iter() + .filter(|(_, v)| v.0 == Either::Right(false)) + .map(|(k, _)| k) + .collect::>(); let env: BTreeMap = env .iter() - .chain(task.env.iter()) + .chain(string_env) + .filter(|(k, _)| !rm_env.contains(k)) .map(|(k, v)| (k.clone(), v.clone())) .collect(); diff --git a/src/config/config_file/toml.rs b/src/config/config_file/toml.rs index 23588df0f..c6e235970 100644 --- a/src/config/config_file/toml.rs +++ b/src/config/config_file/toml.rs @@ -1,10 +1,13 @@ -use serde::de; use std::collections::HashMap; use std::fmt::Formatter; use std::str::FromStr; +use either::Either; +use serde::de; use tera::{Context, Tera}; +use crate::task::EitherStringOrBool; + pub struct TomlParser<'a> { table: &'a toml::Value, tera: Tera, @@ -48,22 +51,36 @@ impl<'a> TomlParser<'a> { }) .transpose() } - pub fn parse_hashmap(&self, key: &str) -> eyre::Result>> - where - T: From, - { + pub fn parse_env( + &self, + key: &str, + ) -> eyre::Result>> { self.table .get(key) .and_then(|value| value.as_table()) .map(|table| { table .iter() - .filter_map(|(key, value)| { - value + .map(|(key, value)| { + let v = value .as_str() - .map(|v| Ok((self.render_tmpl(key)?, self.render_tmpl(v)?))) + .map(|v| Ok(EitherStringOrBool(Either::Left(self.render_tmpl(v)?)))) + .or_else(|| { + value + .as_integer() + .map(|v| Ok(EitherStringOrBool(Either::Left(v.to_string())))) + }) + .or_else(|| { + value + .as_bool() + .map(|v| Ok(EitherStringOrBool(Either::Right(v)))) + }) + .unwrap_or_else(|| { + Err(eyre::eyre!("invalid env value: {:?}", value)) + })?; + Ok((key.clone(), v)) }) - .collect::>>() + .collect::>>() }) .transpose() } diff --git a/src/task.rs b/src/task.rs index 2ed3479d3..9c18236de 100644 --- a/src/task.rs +++ b/src/task.rs @@ -10,6 +10,7 @@ use std::path::{Path, PathBuf}; use std::sync::mpsc; use console::truncate_str; +use either::Either; use eyre::Result; use globset::Glob; use itertools::Itertools; @@ -38,7 +39,7 @@ pub struct Task { #[serde(default)] pub depends: Vec, #[serde(default)] - pub env: HashMap, + pub env: HashMap, #[serde(default)] pub dir: Option, #[serde(default)] @@ -67,6 +68,9 @@ pub struct Task { pub file: Option, } +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +pub struct EitherStringOrBool(#[serde(with = "either::serde_untagged")] pub Either); + impl Task { pub fn new(name: String, config_source: PathBuf) -> Task { Task { @@ -105,7 +109,7 @@ impl Task { outputs: p.parse_array("outputs")?.unwrap_or_default(), depends: p.parse_array("depends")?.unwrap_or_default(), dir: p.parse_str("dir")?, - env: p.parse_hashmap("env")?.unwrap_or_default(), + env: p.parse_env("env")?.unwrap_or_default(), file: Some(path.to_path_buf()), ..Task::new(name_from_path(config_root, path)?, path.to_path_buf()) }; From 8996bd849a649277136dccde263c6d4d36c8267f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 07:31:07 -0600 Subject: [PATCH 1787/1891] chore(deps): update nick-fields/retry action to v3 (#1610) --- .github/workflows/release.yml | 2 +- .github/workflows/test-plugins.yml | 4 ++-- .github/workflows/test.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b40378bb3..9973153ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: - run: echo "$HOME/mise/bin" >> "$GITHUB_PATH" - run: mise -v - name: Run e2e tests - uses: nick-fields/retry@v2 + uses: nick-fields/retry@v3 env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml index c0e07deb0..8d91646ed 100644 --- a/.github/workflows/test-plugins.yml +++ b/.github/workflows/test-plugins.yml @@ -103,7 +103,7 @@ jobs: - run: echo "$HOME/mise/bin" >> "$GITHUB_PATH" - run: mise -v - name: ${{matrix.command}} - uses: nick-fields/retry@v2 + uses: nick-fields/retry@v3 with: timeout_minutes: 20 max_attempts: 3 @@ -182,7 +182,7 @@ jobs: - run: tar -C "$HOME" -xvJf dist/mise-*-linux-x64.tar.xz - run: echo "$HOME/mise/bin" >> "$GITHUB_PATH" - name: mise install ${{matrix.plugins}}@latest - uses: nick-fields/retry@v2 + uses: nick-fields/retry@v3 with: timeout_minutes: 20 max_attempts: 3 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ee888748c..591ca983b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -78,7 +78,7 @@ jobs: with: tool: cargo-llvm-cov,just - name: Test w/ coverage - uses: nick-fields/retry@v2 + uses: nick-fields/retry@v3 env: GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUST_BACKTRACE: "1" From 0e2ead1fd03219982c2d8629014d9460fe48081c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 07:32:12 -0600 Subject: [PATCH 1788/1891] fix(deps): update rust crate toml_edit to 0.21.1 (#1609) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d191e1207..425bdce1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,7 @@ tera = { version = "1.19.1", default-features = false } terminal_size = "0.3.0" thiserror = "1.0.56" toml = { version = "0.8.8", features = ["parse"] } -toml_edit = { version = "0.21.0", features = ["parse"] } +toml_edit = { version = "0.21.1", features = ["parse"] } url = "2.5.0" versions = { version = "6.1.0" , features=["serde"]} walkdir = "2.4.0" From 831af03d68f0a383f85cb671c6fdfa4d2d322b4c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 13:38:00 +0000 Subject: [PATCH 1789/1891] fix(deps): update rust crate toml to 0.8.9 (#1608) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 425bdce1a..e81f56334 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ tempfile = "3.9.0" tera = { version = "1.19.1", default-features = false } terminal_size = "0.3.0" thiserror = "1.0.56" -toml = { version = "0.8.8", features = ["parse"] } +toml = { version = "0.8.9", features = ["parse"] } toml_edit = { version = "0.21.1", features = ["parse"] } url = "2.5.0" versions = { version = "6.1.0" , features=["serde"]} From ded7e827650a293e962649b73cef7f013917d1cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 08:17:56 -0600 Subject: [PATCH 1790/1891] chore(deps): update peter-evans/create-pull-request action to v6 (#1611) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/mega-linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml index 96ea77b5d..35f70d29d 100644 --- a/.github/workflows/mega-linter.yml +++ b/.github/workflows/mega-linter.yml @@ -105,7 +105,7 @@ jobs: # Create pull request if applicable # (for now works only on PR from same repository, not from forks) - name: Create Pull Request with applied fixes - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 id: cpr if: >- steps.ml.outputs.has_updated_sources == 1 && From 9a75c7d508fcd56a503ccfc527700e5dd674fe56 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 17:00:27 -0600 Subject: [PATCH 1791/1891] fix(deps): update rust crate serde_json to 1.0.113 (#1607) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e81f56334..fee0f51b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ self_update = { version = "0.39.0", default-features = false, features = [ ] } serde = "1.0.196" serde_derive = "1.0.196" -serde_json = { version = "1.0.112", features = [] } +serde_json = { version = "1.0.113", features = [] } sha2 = "0.10.8" shell-escape = "0.1.5" shell-words = "1.1.0" From 7f01f345447d694e754a72330967a58085b0a706 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 23:06:54 +0000 Subject: [PATCH 1792/1891] fix(deps): update rust crate reqwest to 0.11.24 (#1605) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fee0f51b4..03e0fc3be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ petgraph = "0.6.4" rand = "0.8.5" rayon = "1.8.1" regex = "1.10.3" -reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "gzip"] } +reqwest = { version = "0.11.24", default-features = false, features = ["blocking", "json", "gzip"] } rmp-serde = "1.1.2" self_update = { version = "0.39.0", default-features = false, features = [ "archive-tar", From 6e8a97f2e10f81f3c3546bd4dce45ac4718f5382 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:22:15 -0600 Subject: [PATCH 1793/1891] doctor: add some info (#1614) --- src/cli/doctor.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 56642ad47..1069cb67a 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -33,7 +33,7 @@ impl Doctor { miseprintln!("{}", mise_version()); miseprintln!("{}", build_info()); miseprintln!("{}", shell()); - miseprintln!("{}", mise_data_dir()); + miseprintln!("{}", mise_dirs()); miseprintln!("{}", mise_env_vars()); match Settings::try_get() { @@ -79,6 +79,16 @@ impl Doctor { fn analyze_config(&mut self, config: impl AsRef) -> Result<()> { let config = config.as_ref(); + let yn = |b| { + if b { + style("yes").green() + } else { + style("no").red() + } + }; + miseprintln!("activated: {}", yn(config.is_activated())); + miseprintln!("shims_on_path: {}", yn(shims_on_path())); + miseprintln!("{}", render_config_files(config)); miseprintln!("{}", render_plugins()); @@ -143,9 +153,13 @@ fn shims_on_path() -> bool { env::PATH.contains(&*dirs::SHIMS) } -fn mise_data_dir() -> String { - let mut s = style("mise data directory:\n").bold().to_string(); - s.push_str(&format!(" {}\n", env::MISE_DATA_DIR.to_string_lossy())); +fn mise_dirs() -> String { + let mut s = style("mise dirs:\n").bold().to_string(); + s.push_str(&format!(" data: {}\n", dirs::DATA.to_string_lossy())); + s.push_str(&format!(" config: {}\n", dirs::CONFIG.to_string_lossy())); + s.push_str(&format!(" cache: {}\n", dirs::CACHE.to_string_lossy())); + s.push_str(&format!(" state: {}\n", dirs::STATE.to_string_lossy())); + s.push_str(&format!(" shims: {}\n", dirs::SHIMS.to_string_lossy())); s } From d15ea44c8146429ee655b5404c94fa1c5c0e1d9e Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:32:16 -0600 Subject: [PATCH 1794/1891] env-file: add dotenv paths to watch files (#1615) Fixes #1613 --- src/config/mod.rs | 11 ++++++----- src/config/settings.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 2df1ab8df..f5fe94d06 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -108,8 +108,8 @@ impl Config { self.env_with_sources.get_or_try_init(|| { let mut env = self.env_results()?.env.clone(); let settings = Settings::get(); - if let Some(env_file) = &settings.env_file { - match dotenvy::from_filename_iter(env_file) { + for env_file in settings.env_files() { + match dotenvy::from_path_iter(&env_file) { Ok(iter) => { for item in iter { let (k, v) = item.unwrap_or_else(|err| { @@ -331,12 +331,13 @@ impl Config { EnvResults::resolve(&env::PRISTINE_ENV, entries) } - pub fn watch_files(&self) -> eyre::Result> { + pub fn watch_files(&self) -> eyre::Result> { Ok(self .config_files .keys() - .chain(self.env_results()?.env_files.iter()) - .map(|p| p.as_path()) + .map(|p| p.to_path_buf()) + .chain(self.env_results()?.env_files.clone()) + .chain(Settings::get().env_files()) .collect()) } diff --git a/src/config/settings.rs b/src/config/settings.rs index 0fddef0da..748fa8cf5 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -13,6 +13,7 @@ use serde::ser::Error; use serde_derive::{Deserialize, Serialize}; use crate::config::{system_config_files, DEFAULT_CONFIG_FILENAMES}; +use crate::file::FindUp; use crate::{config, dirs, env, file}; #[derive(Config, Default, Debug, Clone, Serialize)] @@ -355,6 +356,19 @@ impl Settings { }) } + pub fn env_files(&self) -> Vec { + let mut files = vec![]; + if let Some(cwd) = &*dirs::CWD { + if let Some(env_file) = &self.env_file { + let env_file = env_file.to_string_lossy().to_string(); + for p in FindUp::new(cwd, &[env_file]) { + files.push(p); + } + } + } + files.into_iter().rev().collect() + } + pub fn as_dict(&self) -> eyre::Result { Ok(self.to_string().parse()?) } From cb9ab2de6c6d99cb747a3ef1b90dc2e4e84d0a0a Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:45:39 -0600 Subject: [PATCH 1795/1891] fix lint issues in rust 1.77.0-beta.1 --- src/cli/ls.rs | 8 ++++---- src/config/config_file/mise_toml.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index c2c673cc1..2d50df584 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -283,13 +283,13 @@ enum VersionStatus { Active(String, bool), Inactive(String), Missing(String), - Symlink(String, PathBuf, bool), + Symlink(String, bool), } impl From<(&dyn Forge, &ToolVersion, &Option)> for VersionStatus { fn from((p, tv, source): (&dyn Forge, &ToolVersion, &Option)) -> Self { - if let Some(symlink_path) = p.symlink_path(tv) { - VersionStatus::Symlink(tv.version.clone(), symlink_path, source.is_some()) + if p.symlink_path(tv).is_some() { + VersionStatus::Symlink(tv.version.clone(), source.is_some()) } else if !p.is_version_installed(tv) { VersionStatus::Missing(tv.version.clone()) } else if source.is_some() { @@ -322,7 +322,7 @@ impl Display for VersionStatus { style(version).strikethrough().red(), style("(missing)").red() ), - VersionStatus::Symlink(version, _, active) => { + VersionStatus::Symlink(version, active) => { write!( f, "{} {}", diff --git a/src/config/config_file/mise_toml.rs b/src/config/config_file/mise_toml.rs index 59105ceb4..c0b5b38fa 100644 --- a/src/config/config_file/mise_toml.rs +++ b/src/config/config_file/mise_toml.rs @@ -509,7 +509,7 @@ impl<'de> de::Deserialize<'de> for EnvList { Val::Str(s) => { env.push(EnvDirective::Val(key, s)); } - Val::Bool(_) => env.push(EnvDirective::Rm(key)), + Val::Bool(_b) => env.push(EnvDirective::Rm(key)), } } } From 6a004a723d93cc3a253321ab9b83058dea6c6c89 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 6 Feb 2024 08:21:13 -0600 Subject: [PATCH 1796/1891] docs: cli help --- completions/_mise | 8 ++++---- completions/mise.fish | 8 ++++---- docs/cli-reference.md | 14 ++++++++++---- man/man1/mise.1 | 8 ++++---- src/cli/doctor.rs | 2 +- src/cli/ls.rs | 8 +++++++- src/cli/shell.rs | 2 +- src/cli/use.rs | 2 +- 8 files changed, 32 insertions(+), 20 deletions(-) diff --git a/completions/_mise b/completions/_mise index 4e4e8a86c..ddc0b4dc6 100644 --- a/completions/_mise +++ b/completions/_mise @@ -915,14 +915,14 @@ __mise_cmds() { 'current:Shows current active and installed runtime versions' 'deactivate:Disable mise for current shell session' 'direnv:Output direnv function to use mise inside direnv' - {dr,doctor}':Check mise installation for possible problems.' + {dr,doctor}':Check mise installation for possible problems' {e,env}':Exports env vars to activate mise a single time' {x,exec}':Execute a command with tool(s) set' 'implode:Removes mise CLI and all related data' {i,install}':Install a tool version' 'latest:Gets the latest available version for a plugin' {ln,link}':Symlinks a tool version into mise' - {list,ls}':List installed and/or currently selected tool versions' + {list,ls}':List installed and active tool versions' 'ls-remote:List runtime versions available for install' 'outdated:Shows outdated tool versions' {p,plugins}':Manage plugins' @@ -932,14 +932,14 @@ __mise_cmds() { 'self-update:Updates mise itself' 'set:Manage environment variables' 'settings:Manage settings' - {sh,shell}':Sets a tool version for the current shell session' + {sh,shell}':Sets a tool version for the current session' 'sync:Add tool versions from external tools to mise' {t,tasks}':\[experimental\] Manage tasks' 'trust:Marks a config file as trusted' {remove,rm,uninstall}':Removes runtime versions' 'unset:Remove environment variable(s) from the config file' {up,upgrade}':Upgrades outdated tool versions' - {u,use}':Change the active version of a tool locally or globally.' + {u,use}':Install tool version and add it to config' 'version:Show mise version' {w,watch}':\[experimental\] Run a tasks watching for changes' 'where:Display the installation path for a runtime' diff --git a/completions/mise.fish b/completions/mise.fish index 37984fa3f..aeb19d966 100644 --- a/completions/mise.fish +++ b/completions/mise.fish @@ -15,14 +15,14 @@ complete -xc mise -n "not $fssf $others" -a config -d '[experimental] Manage con complete -xc mise -n "not $fssf $others" -a current -d 'Shows current active and installed runtime versions' complete -xc mise -n "not $fssf $others" -a deactivate -d 'Disable mise for current shell session' complete -xc mise -n "not $fssf $others" -a direnv -d 'Output direnv function to use mise inside direnv' -complete -xc mise -n "not $fssf $others" -a doctor -d 'Check mise installation for possible problems.' +complete -xc mise -n "not $fssf $others" -a doctor -d 'Check mise installation for possible problems' complete -xc mise -n "not $fssf $others" -a env -d 'Exports env vars to activate mise a single time' complete -xc mise -n "not $fssf $others" -a exec -d 'Execute a command with tool(s) set' complete -xc mise -n "not $fssf $others" -a implode -d 'Removes mise CLI and all related data' complete -xc mise -n "not $fssf $others" -a install -d 'Install a tool version' complete -xc mise -n "not $fssf $others" -a latest -d 'Gets the latest available version for a plugin' complete -xc mise -n "not $fssf $others" -a link -d 'Symlinks a tool version into mise' -complete -xc mise -n "not $fssf $others" -a ls -d 'List installed and/or currently selected tool versions' +complete -xc mise -n "not $fssf $others" -a ls -d 'List installed and active tool versions' complete -xc mise -n "not $fssf $others" -a ls-remote -d 'List runtime versions available for install' complete -xc mise -n "not $fssf $others" -a outdated -d 'Shows outdated tool versions' complete -xc mise -n "not $fssf $others" -a plugins -d 'Manage plugins' @@ -32,14 +32,14 @@ complete -xc mise -n "not $fssf $others" -a run -d '[experimental] Run a tasks' complete -xc mise -n "not $fssf $others" -a self-update -d 'Updates mise itself' complete -xc mise -n "not $fssf $others" -a set -d 'Manage environment variables' complete -xc mise -n "not $fssf $others" -a settings -d 'Manage settings' -complete -xc mise -n "not $fssf $others" -a shell -d 'Sets a tool version for the current shell session' +complete -xc mise -n "not $fssf $others" -a shell -d 'Sets a tool version for the current session' complete -xc mise -n "not $fssf $others" -a sync -d 'Add tool versions from external tools to mise' complete -xc mise -n "not $fssf $others" -a tasks -d '[experimental] Manage tasks' complete -xc mise -n "not $fssf $others" -a trust -d 'Marks a config file as trusted' complete -xc mise -n "not $fssf $others" -a uninstall -d 'Removes runtime versions' complete -xc mise -n "not $fssf $others" -a unset -d 'Remove environment variable(s) from the config file' complete -xc mise -n "not $fssf $others" -a upgrade -d 'Upgrades outdated tool versions' -complete -xc mise -n "not $fssf $others" -a use -d 'Change the active version of a tool locally or globally.' +complete -xc mise -n "not $fssf $others" -a use -d 'Install tool version and add it to config' complete -xc mise -n "not $fssf $others" -a version -d 'Show mise version' complete -xc mise -n "not $fssf $others" -a watch -d '[experimental] Run a tasks watching for changes' complete -xc mise -n "not $fssf $others" -a where -d 'Display the installation path for a runtime' diff --git a/docs/cli-reference.md b/docs/cli-reference.md index e78d20875..8955ef830 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -291,7 +291,7 @@ Examples: **Aliases:** `dr` ```text -Check mise installation for possible problems. +Check mise installation for possible problems Usage: doctor @@ -503,7 +503,13 @@ Examples: **Aliases:** `list` ```text -List installed and/or currently selected tool versions +List installed and active tool versions + +This command lists tools that mise "knows about". +These may be tools that are currently installed, or those +that are in a config file (active) but may or may not be installed. + +It's a useful command to get the current state of your tools. Usage: ls [OPTIONS] [PLUGIN]... @@ -1107,7 +1113,7 @@ Examples: **Aliases:** `sh` ```text -Sets a tool version for the current shell session +Sets a tool version for the current session Only works in a session where mise is already activated. @@ -1472,7 +1478,7 @@ Options: **Aliases:** `u` ```text -Change the active version of a tool locally or globally. +Install tool version and add it to config This will install the tool if it is not already installed. By default, this will use an `.mise.toml` file in the current directory. diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 5611f8f77..e8f681b90 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -63,7 +63,7 @@ mise\-direnv(1) Output direnv function to use mise inside direnv .TP mise\-doctor(1) -Check mise installation for possible problems. +Check mise installation for possible problems .TP mise\-env(1) Exports env vars to activate mise a single time @@ -84,7 +84,7 @@ mise\-link(1) Symlinks a tool version into mise .TP mise\-ls(1) -List installed and/or currently selected tool versions +List installed and active tool versions .TP mise\-ls\-remote(1) List runtime versions available for install @@ -114,7 +114,7 @@ mise\-settings(1) Manage settings .TP mise\-shell(1) -Sets a tool version for the current shell session +Sets a tool version for the current session .TP mise\-sync(1) Add tool versions from external tools to mise @@ -135,7 +135,7 @@ mise\-unset(1) Remove environment variable(s) from the config file .TP mise\-use(1) -Change the active version of a tool locally or globally. +Install tool version and add it to config .TP mise\-version(1) Show mise version diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 1069cb67a..651ccc32e 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -20,7 +20,7 @@ use crate::{cli, cmd, dirs, forge}; use crate::{duration, env}; use crate::{file, shims}; -/// Check mise installation for possible problems. +/// Check mise installation for possible problems #[derive(Debug, clap::Args)] #[clap(visible_alias = "dr", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Doctor { diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 2d50df584..7f8ea166b 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -18,7 +18,13 @@ use crate::forge::Forge; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; use crate::ui::table; -/// List installed and/or currently selected tool versions +/// List installed and active tool versions +/// +/// This command lists tools that mise "knows about". +/// These may be tools that are currently installed, or those +/// that are in a config file (active) but may or may not be installed. +/// +/// It's a useful command to get the current state of your tools. #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Ls { diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 1e77175f6..d2f129819 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -6,7 +6,7 @@ use crate::config::Config; use crate::shell::get_shell; use crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder}; -/// Sets a tool version for the current shell session +/// Sets a tool version for the current session /// /// Only works in a session where mise is already activated. #[derive(Debug, clap::Args)] diff --git a/src/cli/use.rs b/src/cli/use.rs index 89a7db6c3..c07f54e11 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -15,7 +15,7 @@ use crate::toolset::{InstallOptions, ToolSource, ToolVersion, ToolVersionRequest use crate::ui::multi_progress_report::MultiProgressReport; use crate::{env, file, forge}; -/// Change the active version of a tool locally or globally. +/// Install tool version and add it to config /// /// This will install the tool if it is not already installed. /// By default, this will use an `.mise.toml` file in the current directory. From 59362f234cf170a82b577e97d842ede4236e4614 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Tue, 6 Feb 2024 08:24:41 -0600 Subject: [PATCH 1797/1891] chore: Release mise version 2024.2.5 --- Cargo.lock | 66 ++++++++++++++++++++++++----------------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 +-- packaging/rpm/mise.spec | 2 +- 6 files changed, 44 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb85c503a..1d3b2cda3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -712,9 +712,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" [[package]] name = "filetime" @@ -949,9 +949,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" [[package]] name = "home" @@ -1055,9 +1055,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1276,9 +1276,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -1296,7 +1296,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.2.4" +version = "2024.2.5" dependencies = [ "base64", "built", @@ -1359,7 +1359,7 @@ dependencies = [ "terminal_size", "thiserror", "toml", - "toml_edit", + "toml_edit 0.21.1", "url", "versions", "walkdir", @@ -1555,9 +1555,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" dependencies = [ "memchr", "thiserror", @@ -1566,9 +1566,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" dependencies = [ "pest", "pest_generator", @@ -1576,9 +1576,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" dependencies = [ "pest", "pest_meta", @@ -1589,9 +1589,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" dependencies = [ "once_cell", "pest", @@ -2379,13 +2379,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] @@ -2457,9 +2456,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe80ced77cbfb4cb91a94bf72b378b4b6791a0d9b7f09d0be747d1bdff4e68bd" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", @@ -2555,14 +2554,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.22.4", ] [[package]] @@ -2579,6 +2578,17 @@ name = "toml_edit" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" dependencies = [ "indexmap", "serde", diff --git a/Cargo.toml b/Cargo.toml index 03e0fc3be..5e87d1854 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.2.4" +version = "2024.2.5" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index a4039a3e4..9ec91351b 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -mise 2024.2.4 +mise 2024.2.5 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 9e51eb70b..8e131b39e 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.2.4"; + version = "2024.2.5"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index e8f681b90..2da4969e7 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.2.4" +.TH mise 1 "mise 2024.2.5" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.2.4 +v2024.2.5 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index b40317add..43544c89e 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.2.4 +Version: 2024.2.5 Release: 1 URL: https://github.com/jdx/mise/ Group: System From 0dd07e7cb7c9ed1d4a507d0a99bcc439b9638a71 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Feb 2024 07:32:37 -0600 Subject: [PATCH 1798/1891] calm io (#1621) * calm io Fixes `| head` so it does not panic * Commit from GitHub Actions (test) --------- Co-authored-by: mise[bot] <123107610+mise-en-dev@users.noreply.github.com> --- Cargo.lock | 20 ++++++++++++++++++++ Cargo.toml | 1 + src/cli/activate.rs | 18 ++++++++++-------- src/cli/alias/get.rs | 2 +- src/cli/alias/ls.rs | 2 +- src/cli/asdf.rs | 6 +++--- src/cli/bin_paths.rs | 2 +- src/cli/cache/mod.rs | 2 +- src/cli/completion.rs | 2 +- src/cli/config/generate.rs | 2 +- src/cli/config/ls.rs | 2 +- src/cli/current.rs | 4 ++-- src/cli/deactivate.rs | 4 ++-- src/cli/direnv/activate.rs | 2 +- src/cli/direnv/envrc.rs | 2 +- src/cli/direnv/exec.rs | 2 +- src/cli/doctor.rs | 28 ++++++++++++++-------------- src/cli/env.rs | 4 ++-- src/cli/hook_env.rs | 4 ++-- src/cli/implode.rs | 2 +- src/cli/latest.rs | 2 +- src/cli/local.rs | 8 ++++---- src/cli/ls.rs | 25 +++++++++++++------------ src/cli/ls_remote.rs | 4 ++-- src/cli/mod.rs | 2 +- src/cli/outdated.rs | 9 +++++---- src/cli/plugins/ls.rs | 4 ++-- src/cli/plugins/ls_remote.rs | 2 +- src/cli/render_completion.rs | 2 +- src/cli/run.rs | 2 +- src/cli/self_update.rs | 4 ++-- src/cli/set.rs | 4 ++-- src/cli/settings/get.rs | 2 +- src/cli/settings/ls.rs | 2 +- src/cli/shell.rs | 2 +- src/cli/sync/node.rs | 6 +++--- src/cli/sync/python.rs | 2 +- src/cli/tasks/deps.rs | 4 ++-- src/cli/tasks/edit.rs | 2 +- src/cli/tasks/ls.rs | 2 +- src/cli/use.rs | 7 ++++--- src/cli/version.rs | 12 +++++++----- src/cli/where.rs | 2 +- src/cli/which.rs | 6 +++--- src/config/config_file/mod.rs | 2 +- src/main.rs | 19 +++++++++++++------ src/output.rs | 16 +++++++++------- src/task.rs | 5 +++-- src/ui/tree.rs | 22 ++++++++++++---------- 49 files changed, 166 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d3b2cda3..93de7fa59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,6 +225,25 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "calm_io" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ea0608700fe42d90ec17ad0f86335cf229b67df2e34e7f463e8241ce7b8fa5f" +dependencies = [ + "calmio_filters", +] + +[[package]] +name = "calmio_filters" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "846501f4575cd66766a40bb7ab6d8e960adc7eb49f753c8232bd8e0e09cf6ca2" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "cc" version = "1.0.83" @@ -1300,6 +1319,7 @@ version = "2024.2.5" dependencies = [ "base64", "built", + "calm_io", "chrono", "clap", "clap_complete", diff --git a/Cargo.toml b/Cargo.toml index 5e87d1854..1c387084f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ lto = true [dependencies] base64 = "0.21.7" +calm_io = "0.1.1" chrono = { version = "0.4.33", default-features = false, features = ["std", "clock"] } clap = { version = "4.4.18", features = ["env", "derive", "string"] } clap_complete = { version = "4.4.10", optional = true } diff --git a/src/cli/activate.rs b/src/cli/activate.rs index 11d30f386..62bab6a4b 100644 --- a/src/cli/activate.rs +++ b/src/cli/activate.rs @@ -67,20 +67,21 @@ impl Activate { env::MISE_BIN.clone() }; match self.shims { - true => self.activate_shims(shell.as_ref(), &mise_bin), - false => self.activate(shell.as_ref(), &mise_bin), + true => self.activate_shims(shell.as_ref(), &mise_bin)?, + false => self.activate(shell.as_ref(), &mise_bin)?, } Ok(()) } - fn activate_shims(&self, shell: &dyn Shell, mise_bin: &Path) { + fn activate_shims(&self, shell: &dyn Shell, mise_bin: &Path) -> std::io::Result<()> { let exe_dir = mise_bin.parent().unwrap(); - miseprint!("{}", self.prepend_path(shell, exe_dir)); - miseprint!("{}", self.prepend_path(shell, &dirs::SHIMS)); + miseprint!("{}", self.prepend_path(shell, exe_dir))?; + miseprint!("{}", self.prepend_path(shell, &dirs::SHIMS))?; + Ok(()) } - fn activate(&self, shell: &dyn Shell, mise_bin: &Path) { + fn activate(&self, shell: &dyn Shell, mise_bin: &Path) -> std::io::Result<()> { let exe_dir = mise_bin.parent().unwrap(); let mut flags = vec![]; if self.quiet { @@ -89,8 +90,9 @@ impl Activate { if self.status { flags.push(" --status"); } - miseprint!("{}", self.prepend_path(shell, exe_dir)); - miseprint!("{}", shell.activate(mise_bin, flags.join(""))); + miseprint!("{}", self.prepend_path(shell, exe_dir))?; + miseprint!("{}", shell.activate(mise_bin, flags.join("")))?; + Ok(()) } fn prepend_path(&self, shell: &dyn Shell, p: &Path) -> String { diff --git a/src/cli/alias/get.rs b/src/cli/alias/get.rs index 92ddf5136..8ba60364a 100644 --- a/src/cli/alias/get.rs +++ b/src/cli/alias/get.rs @@ -21,7 +21,7 @@ impl AliasGet { let config = Config::try_get()?; match config.get_all_aliases().get(&self.plugin) { Some(plugin) => match plugin.get(&self.alias) { - Some(alias) => Ok(miseprintln!("{}", alias)), + Some(alias) => Ok(miseprintln!("{}", alias)?), None => Err(eyre!("Unknown alias: {}", &self.alias)), }, None => Err(eyre!("Unknown plugin: {}", &self.plugin)), diff --git a/src/cli/alias/ls.rs b/src/cli/alias/ls.rs index fa1e4eba5..1e4678cab 100644 --- a/src/cli/alias/ls.rs +++ b/src/cli/alias/ls.rs @@ -48,7 +48,7 @@ impl AliasLs { .collect::>(); let mut table = tabled::Table::new(rows); table::default_style(&mut table, self.no_header); - miseprintln!("{table}"); + miseprintln!("{table}")?; Ok(()) } } diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index 88aeb95bf..c43260f1e 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -55,13 +55,13 @@ fn list_versions(config: &Config, args: &[String]) -> Result<()> { if let Some(plugin) = plugin { versions.retain(|(_, v)| &v.forge.to_string() == plugin); for (_, version) in versions { - miseprintln!("{}", version.version); + miseprintln!("{}", version.version)?; } } else { for (plugin, versions) in &versions.into_iter().group_by(|(_, v)| v.forge.clone()) { - miseprintln!("{}", plugin); + miseprintln!("{}", plugin)?; for (_, tv) in versions { - miseprintln!(" {}", tv.version); + miseprintln!(" {}", tv.version)?; } } } diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 2d6d318df..936378306 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -14,7 +14,7 @@ impl BinPaths { let ts = ToolsetBuilder::new().build(&config)?; ts.notify_if_versions_missing(); for p in ts.list_paths() { - miseprintln!("{}", p.display()); + miseprintln!("{}", p.display())?; } Ok(()) } diff --git a/src/cli/cache/mod.rs b/src/cli/cache/mod.rs index 84d3ce723..84f6a22cc 100644 --- a/src/cli/cache/mod.rs +++ b/src/cli/cache/mod.rs @@ -34,7 +34,7 @@ impl Cache { Some(cmd) => cmd.run(), None => { // just show the cache dir - miseprintln!("{}", env::MISE_CACHE_DIR.display()); + miseprintln!("{}", env::MISE_CACHE_DIR.display())?; Ok(()) } } diff --git a/src/cli/completion.rs b/src/cli/completion.rs index d371dcce2..549c1e631 100644 --- a/src/cli/completion.rs +++ b/src/cli/completion.rs @@ -24,7 +24,7 @@ impl Completion { Shell::Fish => include_str!("../../completions/mise.fish"), Shell::Zsh => include_str!("../../completions/_mise"), }; - miseprintln!("{}", c.trim()); + miseprintln!("{}", c.trim())?; Ok(()) } diff --git a/src/cli/config/generate.rs b/src/cli/config/generate.rs index 438c6d52c..fc880b533 100644 --- a/src/cli/config/generate.rs +++ b/src/cli/config/generate.rs @@ -76,7 +76,7 @@ impl ConfigGenerate { info!("writing to {}", display_path(output)); file::write(output, doc)?; } else { - miseprintln!("{doc}"); + miseprintln!("{doc}")?; } Ok(()) diff --git a/src/cli/config/ls.rs b/src/cli/config/ls.rs index d8d541ac0..f7e85f2cb 100644 --- a/src/cli/config/ls.rs +++ b/src/cli/config/ls.rs @@ -32,7 +32,7 @@ impl ConfigLs { let mut table = tabled::Table::new(rows); table::default_style(&mut table, self.no_header); table.with(Modify::new(Columns::last()).with(Width::truncate(40).suffix("…"))); - miseprintln!("{table}"); + miseprintln!("{table}")?; Ok(()) } diff --git a/src/cli/current.rs b/src/cli/current.rs index 0b572dc89..0064a39ba 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -54,7 +54,7 @@ impl Current { .map(|v| v.version.to_string()) .collect::>() .join(" ") - ); + )?; } None => { warn!( @@ -88,7 +88,7 @@ impl Current { .map(|v| v.version.to_string()) .collect::>() .join(" ") - ); + )?; } Ok(()) } diff --git a/src/cli/deactivate.rs b/src/cli/deactivate.rs index 6cc0029a0..3f5d29bee 100644 --- a/src/cli/deactivate.rs +++ b/src/cli/deactivate.rs @@ -21,9 +21,9 @@ impl Deactivate { let shell = get_shell(None).expect("no shell detected"); - miseprint!("{}", hook_env::clear_old_env(&*shell)); + miseprint!("{}", hook_env::clear_old_env(&*shell))?; let output = shell.deactivate(); - miseprint!("{output}"); + miseprint!("{output}")?; Ok(()) } diff --git a/src/cli/direnv/activate.rs b/src/cli/direnv/activate.rs index 272b12837..17ca2f201 100644 --- a/src/cli/direnv/activate.rs +++ b/src/cli/direnv/activate.rs @@ -21,7 +21,7 @@ impl DirenvActivate { direnv_load mise direnv exec }} "#} - ); + )?; Ok(()) } diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index f433bb713..1d6512acd 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -49,7 +49,7 @@ impl Envrc { writeln!(file, "PATH_add {}", path.to_string_lossy())?; } - miseprintln!("{}", envrc_path.to_string_lossy()); + miseprintln!("{}", envrc_path.to_string_lossy())?; Ok(()) } } diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index 97fbd5b64..66142d8df 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -34,7 +34,7 @@ impl DirenvExec { let w: DirenvWatches = serde_json::from_str(&json)?; cmd = cmd.env("DIRENV_WATCHES", w.watches); - miseprint!("{}", cmd.read()?); + miseprint!("{}", cmd.read()?)?; Ok(()) } } diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index 651ccc32e..d1c02feaf 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -30,11 +30,11 @@ pub struct Doctor { impl Doctor { pub fn run(mut self) -> Result<()> { - miseprintln!("{}", mise_version()); - miseprintln!("{}", build_info()); - miseprintln!("{}", shell()); - miseprintln!("{}", mise_dirs()); - miseprintln!("{}", mise_env_vars()); + miseprintln!("{}", mise_version())?; + miseprintln!("{}", build_info())?; + miseprintln!("{}", shell())?; + miseprintln!("{}", mise_dirs())?; + miseprintln!("{}", mise_env_vars())?; match Settings::try_get() { Ok(settings) => { @@ -42,7 +42,7 @@ impl Doctor { "{}\n{}\n", style("settings:").bold(), indent(settings.to_string()) - ); + )?; } Err(err) => warn!("failed to load settings: {}", err), } @@ -62,13 +62,13 @@ impl Doctor { } if self.checks.is_empty() { - miseprintln!("No problems found"); + miseprintln!("No problems found")?; } else { let checks_plural = if self.checks.len() == 1 { "" } else { "s" }; let summary = format!("{} problem{checks_plural} found:", self.checks.len()); - miseprintln!("{}", style(summary).red().bold()); + miseprintln!("{}", style(summary).red().bold())?; for check in &self.checks { - miseprintln!("{}\n", check); + miseprintln!("{}\n", check)?; } exit(1); } @@ -86,11 +86,11 @@ impl Doctor { style("no").red() } }; - miseprintln!("activated: {}", yn(config.is_activated())); - miseprintln!("shims_on_path: {}", yn(shims_on_path())); + miseprintln!("activated: {}", yn(config.is_activated()))?; + miseprintln!("shims_on_path: {}", yn(shims_on_path()))?; - miseprintln!("{}", render_config_files(config)); - miseprintln!("{}", render_plugins()); + miseprintln!("{}", render_config_files(config))?; + miseprintln!("{}", render_plugins())?; for plugin in forge::list() { if !plugin.is_installed() { @@ -116,7 +116,7 @@ impl Doctor { Ok(ts) => { self.analyze_shims(&ts); - miseprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string())); + miseprintln!("{}\n{}\n", style("toolset:").bold(), indent(ts.to_string()))?; } Err(err) => self.checks.push(format!("failed to load toolset: {}", err)), } diff --git a/src/cli/env.rs b/src/cli/env.rs index 46eefaf8d..f070fbedb 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -41,7 +41,7 @@ impl Env { fn output_json(&self, config: &Config, ts: Toolset) -> Result<()> { let env = ts.env_with_path(config)?; - miseprintln!("{}", serde_json::to_string_pretty(&env)?); + miseprintln!("{}", serde_json::to_string_pretty(&env)?)?; Ok(()) } @@ -51,7 +51,7 @@ impl Env { for (k, v) in ts.env_with_path(config)? { let k = k.to_string(); let v = v.to_string(); - miseprint!("{}", shell.set_env(&k, &v)); + miseprint!("{}", shell.set_env(&k, &v))?; } Ok(()) } diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index e2132ef33..a9a6c17ca 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -41,7 +41,7 @@ impl HookEnv { } let ts = ToolsetBuilder::new().build(&config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); - miseprint!("{}", hook_env::clear_old_env(&*shell)); + miseprint!("{}", hook_env::clear_old_env(&*shell))?; let mut env = ts.env(&config)?; let env_path = env.remove("PATH"); let mut diff = EnvDiff::new(&env::PRISTINE_ENV, env); @@ -60,7 +60,7 @@ impl HookEnv { patches.push(self.build_watch_operation(&watch_files)?); let output = hook_env::build_env_commands(&*shell, &patches); - miseprint!("{output}"); + miseprint!("{output}")?; self.display_status(&config, &ts)?; Ok(()) diff --git a/src/cli/implode.rs b/src/cli/implode.rs index 8b1b6a39a..76da31ef1 100644 --- a/src/cli/implode.rs +++ b/src/cli/implode.rs @@ -30,7 +30,7 @@ impl Implode { } for f in files.into_iter().filter(|d| d.exists()) { if self.dry_run { - miseprintln!("rm -rf {}", f.display()); + miseprintln!("rm -rf {}", f.display())?; } if self.confirm_remove(f)? { diff --git a/src/cli/latest.rs b/src/cli/latest.rs index d6a5081a0..86dc8bf24 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -47,7 +47,7 @@ impl Latest { plugin.latest_version(prefix)? }; if let Some(version) = latest_version { - miseprintln!("{}", version); + miseprintln!("{}", version)?; } Ok(()) } diff --git a/src/cli/local.rs b/src/cli/local.rs index 830c696cb..39a86635b 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -99,7 +99,7 @@ pub fn local( let settings = Settings::try_get()?; let mut cf = config_file::parse_or_init(path)?; if show_path { - miseprintln!("{}", path.display()); + miseprintln!("{}", path.display())?; return Ok(()); } @@ -111,7 +111,7 @@ pub fn local( .iter() .map(|r| style(r).blue().for_stderr().to_string()) .join(" "); - miseprintln!("{} {} {tools}", style("mise").dim(), display_path(path)); + miseprintln!("{} {} {tools}", style("mise").dim(), display_path(path))?; } if !runtime.is_empty() { @@ -122,13 +122,13 @@ pub fn local( let pin = pin || (settings.asdf_compat && !fuzzy); cf.add_runtimes(&runtimes, pin)?; let tools = runtimes.iter().map(|t| t.style()).join(" "); - miseprintln!("{} {} {tools}", style("mise").dim(), display_path(path)); + miseprintln!("{} {} {tools}", style("mise").dim(), display_path(path))?; } if !runtime.is_empty() || remove.is_some() { cf.save()?; } else { - miseprint!("{}", cf.dump()?); + miseprint!("{}", cf.dump()?)?; } Ok(()) diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 7f8ea166b..a79c76d29 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -122,7 +122,7 @@ impl Ls { .filter(|(p, _, _)| plugins.contains(p.fa())) .map(|row| row.into()) .collect(); - miseprintln!("{}", serde_json::to_string_pretty(&runtimes)?); + miseprintln!("{}", serde_json::to_string_pretty(&runtimes)?)?; return Ok(()); } @@ -134,25 +134,26 @@ impl Ls { let runtimes = runtimes.map(|row| row.into()).collect(); plugins.insert(plugin_name.clone(), runtimes); } - miseprintln!("{}", serde_json::to_string_pretty(&plugins)?); + miseprintln!("{}", serde_json::to_string_pretty(&plugins)?)?; Ok(()) } fn display_parseable(&self, runtimes: Vec) -> Result<()> { warn!("The parseable output format is deprecated and will be removed in a future release."); warn!("Please use the regular output format instead which has been modified to be more easily parseable."); - runtimes + let tvs = runtimes .into_iter() .map(|(p, tv, _)| (p, tv)) .filter(|(p, tv)| p.is_version_installed(tv)) - .for_each(|(_, tv)| { - if self.plugin.is_some() { - // only displaying 1 plugin so only show the version - miseprintln!("{}", tv.version); - } else { - miseprintln!("{} {}", &tv.forge, tv.version); - } - }); + .map(|(_, tv)| tv); + for tv in tvs { + if self.plugin.is_some() { + // only displaying 1 plugin so only show the version + miseprintln!("{}", tv.version)?; + } else { + miseprintln!("{} {}", &tv.forge, tv.version)?; + } + } Ok(()) } @@ -172,7 +173,7 @@ impl Ls { }); let mut table = Table::new(rows); table::default_style(&mut table, self.no_header); - miseprintln!("{}", table.to_string()); + miseprintln!("{}", table.to_string())?; Ok(()) } diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index 91ccee760..bd19ee7eb 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -59,7 +59,7 @@ impl LsRemote { }; for version in versions { - miseprintln!("{}", version); + miseprintln!("{}", version)?; } Ok(()) @@ -78,7 +78,7 @@ impl LsRemote { .collect::>(); for (plugin, versions) in versions { for v in versions { - miseprintln!("{}@{v}", plugin); + miseprintln!("{}@{v}", plugin)?; } } Ok(()) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2ff8ff561..28b180692 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -197,7 +197,7 @@ impl Cli { pub fn run(args: &Vec) -> Result<()> { *crate::env::ARGS.write().unwrap() = args.clone(); shims::handle_shim()?; - version::print_version_if_requested(args); + version::print_version_if_requested(args)?; let matches = Self::command() .try_get_matches_from(args) diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index 6ac08c772..0c5b4c143 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -35,13 +35,13 @@ impl Outdated { if outdated.is_empty() { info!("All tools are up to date"); } else { - self.display(outdated); + self.display(outdated)?; } Ok(()) } - fn display(&self, outdated: OutputVec) { + fn display(&self, outdated: OutputVec) -> Result<()> { // TODO: make a generic table printer in src/ui/table let plugins = outdated.iter().map(|(t, _, _)| t.id()).collect::>(); let requests = outdated @@ -92,7 +92,7 @@ impl Outdated { style(pad_requested("Requested")).dim(), style(pad_current("Current")).dim(), style("Latest").dim(), - ); + )?; for i in 0..outdated.len() { miseprintln!( "{} {} {} {}", @@ -100,8 +100,9 @@ impl Outdated { pad_requested(&requests[i]), pad_current(¤ts[i]), latests[i] - ); + )?; } + Ok(()) } } diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 7a7febcbf..ca5ccb3ba 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -85,10 +85,10 @@ impl PluginsLs { .with(Margin::new(0, 0, 0, 0)) .with(Modify::new(Columns::first()).with(Padding::new(0, 1, 0, 0))) .with(Modify::new(Columns::last()).with(Padding::zero())); - miseprintln!("{table}"); + miseprintln!("{table}")?; } else { for tool in tools { - miseprintln!("{tool}"); + miseprintln!("{tool}")?; } } Ok(()) diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 0fed29903..98005c222 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -49,7 +49,7 @@ impl PluginsLsRemote { }; let url = if self.urls { repo } else { "" }; let plugin = pad_str(plugin, max_plugin_len, Alignment::Left, None); - miseprintln!("{} {}{}", plugin, installed, url); + miseprintln!("{} {}{}", plugin, installed, url)?; } Ok(()) diff --git a/src/cli/render_completion.rs b/src/cli/render_completion.rs index ce64e3321..1c9f984e0 100644 --- a/src/cli/render_completion.rs +++ b/src/cli/render_completion.rs @@ -35,7 +35,7 @@ impl RenderCompletion { String::from_utf8(c.into_inner()).unwrap() } }; - miseprintln!("{}", script.trim()); + miseprintln!("{}", script.trim())?; Ok(()) } diff --git a/src/cli/run.rs b/src/cli/run.rs index d2942ce11..f29fff272 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -252,7 +252,7 @@ impl Run { "{} finished in {}", prefix, format_duration(timer.elapsed()) - ); + )?; } self.save_checksum(task)?; diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 7889943a8..8fe28871a 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -39,9 +39,9 @@ impl SelfUpdate { if status.updated() { let version = style(status.version()).bright().yellow(); - miseprintln!("Updated mise to {version}"); + miseprintln!("Updated mise to {version}")?; } else { - miseprintln!("mise is already up to date"); + miseprintln!("mise is already up to date")?; } if !self.no_plugins { cmd!(&*env::MISE_BIN, "plugins", "update").run()?; diff --git a/src/cli/set.rs b/src/cli/set.rs index df905be7f..3afb3a13c 100644 --- a/src/cli/set.rs +++ b/src/cli/set.rs @@ -55,7 +55,7 @@ impl Set { .collect::>(); let mut table = tabled::Table::new(rows); table::default_style(&mut table, false); - miseprintln!("{table}"); + miseprintln!("{table}")?; return Ok(()); } @@ -76,7 +76,7 @@ impl Set { if env_vars.len() == 1 && env_vars[0].value.is_none() { let key = &env_vars[0].key; match config.env()?.get(key) { - Some(value) => miseprintln!("{value}"), + Some(value) => miseprintln!("{value}")?, None => bail!("Environment variable {key} not found"), } return Ok(()); diff --git a/src/cli/settings/get.rs b/src/cli/settings/get.rs index 8305b4a1c..8660c95a2 100644 --- a/src/cli/settings/get.rs +++ b/src/cli/settings/get.rs @@ -30,7 +30,7 @@ impl SettingsGet { bail!("Unknown setting: {}", self.setting); } } - miseprintln!("{}", value); + miseprintln!("{}", value)?; Ok(()) } diff --git a/src/cli/settings/ls.rs b/src/cli/settings/ls.rs index 9cd302812..2bf7ef83a 100644 --- a/src/cli/settings/ls.rs +++ b/src/cli/settings/ls.rs @@ -19,7 +19,7 @@ impl SettingsLs { for k in Settings::hidden_configs() { settings.remove(*k); } - miseprintln!("{}", settings); + miseprintln!("{}", settings)?; Ok(()) } } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index d2f129819..e08e6a455 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -59,7 +59,7 @@ impl Shell { } else { shell.set_env(&k, &tv.version) }; - miseprintln!("{op}"); + miseprintln!("{op}")?; } } diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 51c37ad44..ed315c05f 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -62,7 +62,7 @@ impl SyncNode { } let v = entry.trim_start_matches("node@"); tool.create_symlink(v, &brew_prefix.join(&entry))?; - miseprintln!("Synced node@{} from Homebrew", v); + miseprintln!("Synced node@{} from Homebrew", v)?; } config.rebuild_shims_and_runtime_symlinks() @@ -80,7 +80,7 @@ impl SyncNode { for entry in sorted(subdirs) { let v = entry.trim_start_matches('v'); tool.create_symlink(v, &nvm_versions_path.join(&entry))?; - miseprintln!("Synced node@{} from nvm", v); + miseprintln!("Synced node@{} from nvm", v)?; } config.rebuild_shims_and_runtime_symlinks() @@ -97,7 +97,7 @@ impl SyncNode { let subdirs = file::dir_subdirs(&nodenv_versions_path)?; for v in sorted(subdirs) { tool.create_symlink(&v, &nodenv_versions_path.join(&v))?; - miseprintln!("Synced node@{} from nodenv", v); + miseprintln!("Synced node@{} from nodenv", v)?; } config.rebuild_shims_and_runtime_symlinks() diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 29c9823ef..c2884addb 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -33,7 +33,7 @@ impl SyncPython { let subdirs = file::dir_subdirs(&pyenv_versions_path)?; for v in sorted(subdirs) { python.create_symlink(&v, &pyenv_versions_path.join(&v))?; - miseprintln!("Synced python@{} from pyenv", v); + miseprintln!("Synced python@{} from pyenv", v)?; } config.rebuild_shims_and_runtime_symlinks() diff --git a/src/cli/tasks/deps.rs b/src/cli/tasks/deps.rs index 0a1ee7dcb..996d5517b 100644 --- a/src/cli/tasks/deps.rs +++ b/src/cli/tasks/deps.rs @@ -92,7 +92,7 @@ impl TasksDeps { }); // iterate over selected graph nodes and print tree for idx in start_indexes { - print_tree(&(&deps.graph, idx)); + print_tree(&(&deps.graph, idx))?; } Ok(()) } @@ -127,7 +127,7 @@ impl TasksDeps { &|_, _| String::new(), &|_, nr| format!("label = \"{}\"", nr.1.name), ), - ); + )?; Ok(()) } diff --git a/src/cli/tasks/edit.rs b/src/cli/tasks/edit.rs index f17839f68..aa990b21d 100644 --- a/src/cli/tasks/edit.rs +++ b/src/cli/tasks/edit.rs @@ -48,7 +48,7 @@ impl TasksEdit { file::make_executable(file)?; } if self.path { - miseprintln!("{}", file.display()); + miseprintln!("{}", file.display())?; } else { cmd!(&*env::EDITOR, &file).run()?; } diff --git a/src/cli/tasks/ls.rs b/src/cli/tasks/ls.rs index 5005a0118..5f5642e73 100644 --- a/src/cli/tasks/ls.rs +++ b/src/cli/tasks/ls.rs @@ -39,7 +39,7 @@ impl TasksLs { .collect::>(); let mut table = tabled::Table::new(rows); table::default_style(&mut table, self.no_header); - miseprintln!("{table}"); + miseprintln!("{table}")?; Ok(()) } diff --git a/src/cli/use.rs b/src/cli/use.rs index c07f54e11..60ec197c8 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -132,7 +132,7 @@ impl Use { cf.remove_plugin(plugin_name)?; } cf.save()?; - self.render_success_message(cf.as_ref(), &versions); + self.render_success_message(cf.as_ref(), &versions)?; Ok(()) } @@ -168,14 +168,15 @@ impl Use { } } - fn render_success_message(&self, cf: &dyn ConfigFile, versions: &[ToolVersion]) { + fn render_success_message(&self, cf: &dyn ConfigFile, versions: &[ToolVersion]) -> Result<()> { let path = display_path(cf.get_path()); let tools = versions.iter().map(|t| t.style()).join(", "); miseprintln!( "{} {} tools: {tools}", style("mise").green(), style(path).cyan().for_stderr(), - ); + )?; + Ok(()) } } diff --git a/src/cli/version.rs b/src/cli/version.rs index d4865931f..bfca2748d 100644 --- a/src/cli/version.rs +++ b/src/cli/version.rs @@ -43,25 +43,27 @@ pub static V: Lazy = Lazy::new(|| Versioning::new(env!("CARGO_PKG_VE impl Version { pub fn run(self) -> Result<()> { - show_version(); + show_version()?; Ok(()) } } -pub fn print_version_if_requested(args: &[String]) { +pub fn print_version_if_requested(args: &[String]) -> std::io::Result<()> { if args.len() == 2 && *env::MISE_BIN_NAME == "mise" { let cmd = &args[1].to_lowercase(); if cmd == "version" || cmd == "-v" || cmd == "--version" { - show_version(); + show_version()?; std::process::exit(0); } } debug!("Version: {}", *VERSION); + Ok(()) } -fn show_version() { - miseprintln!("{}", *VERSION); +fn show_version() -> std::io::Result<()> { + miseprintln!("{}", *VERSION)?; show_latest(); + Ok(()) } fn show_latest() { diff --git a/src/cli/where.rs b/src/cli/where.rs index 2c5568a74..d55194479 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -56,7 +56,7 @@ impl Where { .map(|tvr| tvr.resolve(plugin.as_ref(), Default::default(), false)) { Some(Ok(tv)) if plugin.is_version_installed(&tv) => { - miseprintln!("{}", tv.install_path().to_string_lossy()); + miseprintln!("{}", tv.install_path().to_string_lossy())?; Ok(()) } _ => Err(VersionNotInstalled( diff --git a/src/cli/which.rs b/src/cli/which.rs index 1de6dc0ef..b597426b0 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -34,12 +34,12 @@ impl Which { match ts.which(&self.bin_name) { Some((p, tv)) => { if self.version { - miseprintln!("{}", tv.version); + miseprintln!("{}", tv.version)?; } else if self.plugin { - miseprintln!("{p}"); + miseprintln!("{p}")?; } else { let path = p.which(&tv, &self.bin_name)?; - miseprintln!("{}", path.unwrap().display()); + miseprintln!("{}", path.unwrap().display())?; } Ok(()) } diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index 63771276e..91dc7f81b 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -147,7 +147,7 @@ impl dyn ConfigFile { .iter() .map(|(tvr, _)| tvr.version()) .collect::>(); - miseprintln!("{}", tvl.join(" ")); + miseprintln!("{}", tvl.join(" "))?; return Ok(true); } // check for something like `mise local node python@latest` which is invalid diff --git a/src/main.rs b/src/main.rs index ba96691b6..f37312cd0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,14 +80,21 @@ fn main() -> eyre::Result<()> { match Cli::run(&args).with_section(|| VERSION.to_string().header("Version:")) { Ok(()) => Ok(()), - Err(err) if log::max_level() < log::LevelFilter::Debug => { - display_friendly_err(err); - exit(1); - } - Err(err) => { - Err(err).suggestion("Run with --verbose or MISE_VERBOSE=1 for more information.") + Err(err) => handle_err(err), + } +} + +fn handle_err(err: Report) -> eyre::Result<()> { + if let Some(err) = err.downcast_ref::() { + if err.kind() == std::io::ErrorKind::BrokenPipe { + return Ok(()); } } + if log::max_level() < log::LevelFilter::Debug { + display_friendly_err(err); + exit(1); + } + Err(err).suggestion("Run with --verbose or MISE_VERBOSE=1 for more information.") } fn display_friendly_err(err: Report) { diff --git a/src/output.rs b/src/output.rs index 47d2fa0ce..ee56592f6 100644 --- a/src/output.rs +++ b/src/output.rs @@ -7,18 +7,19 @@ macro_rules! miseprintln { ($($arg:tt)*) => {{ let mut stdout = $crate::output::tests::STDOUT.lock().unwrap(); stdout.push(format!($($arg)*)); - }}; + std::io::Result::Ok(()) + }} } #[cfg(not(test))] #[macro_export] macro_rules! miseprintln { () => { - miseprint!("\n") + calm_io::stdoutln!("\n") }; ($($arg:tt)*) => {{ - println!($($arg)*); - }}; + calm_io::stdoutln!($($arg)*) + }} } #[cfg(test)] @@ -28,15 +29,16 @@ macro_rules! miseprint { let mut stdout = $crate::output::tests::STDOUT.lock().unwrap(); let cur = stdout.pop().unwrap_or_default(); stdout.push(cur + &format!($($arg)*)); - }}; + std::io::Result::Ok(()) + }} } #[cfg(not(test))] #[macro_export] macro_rules! miseprint { ($($arg:tt)*) => {{ - print!($($arg)*); - }}; + calm_io::stdout!($($arg)*) + }} } #[cfg(test)] diff --git a/src/task.rs b/src/task.rs index 9c18236de..65f16544f 100644 --- a/src/task.rs +++ b/src/task.rs @@ -317,10 +317,11 @@ impl Deps { impl TreeItem for (&Graph, NodeIndex) { type Child = Self; - fn write_self(&self) { + fn write_self(&self) -> std::io::Result<()> { if let Some(w) = self.0.node_weight(self.1) { - miseprint!("{}", w.name); + miseprint!("{}", w.name)?; } + std::io::Result::Ok(()) } fn children(&self) -> Cow<[Self::Child]> { diff --git a/src/ui/tree.rs b/src/ui/tree.rs index 35c17c1b0..cd4ce033b 100644 --- a/src/ui/tree.rs +++ b/src/ui/tree.rs @@ -1,9 +1,9 @@ -use std::{borrow::Cow, f32::INFINITY}; +use std::borrow::Cow; pub trait TreeItem: Clone { type Child: TreeItem; - fn write_self(&self); + fn write_self(&self) -> std::io::Result<()>; fn children(&self) -> Cow<[Self::Child]>; } @@ -58,7 +58,7 @@ impl TreeItemIndent { } } -pub fn print_tree(item: &T) { +pub fn print_tree(item: &T) -> std::io::Result<()> { let indent = TreeItemIndent::new(4, 1, &TREE_ITEM_CHARS); print_tree_item(item, String::from(""), String::from(""), &indent, 0) } @@ -69,25 +69,27 @@ fn print_tree_item( child_prefix: String, indent: &TreeItemIndent, level: u32, -) { - miseprint!("{}", prefix); - item.write_self(); - miseprintln!(""); +) -> std::io::Result<()> { + miseprint!("{}", prefix)?; + item.write_self()?; + miseprintln!("")?; - if level < INFINITY as u32 { + if level < u32::MAX { let children = item.children(); if let Some((last_child, children)) = children.split_last() { let rp = child_prefix.clone() + &indent.regular_prefix; let cp = child_prefix.clone() + &indent.child_prefix; for c in children { - print_tree_item(c, rp.clone(), cp.clone(), indent, level + 1); + print_tree_item(c, rp.clone(), cp.clone(), indent, level + 1)?; } let rp = child_prefix.clone() + &indent.last_regular_prefix; let cp = child_prefix.clone() + &indent.last_child_prefix; - print_tree_item(last_child, rp, cp, indent, level + 1); + print_tree_item(last_child, rp, cp, indent, level + 1)?; } } + + Ok(()) } From 92a3e87b578cc2e7af0b23b5244246a38be3584b Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 7 Feb 2024 07:43:07 -0600 Subject: [PATCH 1799/1891] use OnceLock where possible --- src/config/mod.rs | 10 +++++----- src/regex.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index f5fe94d06..05223de10 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fmt::{Debug, Formatter}; use std::iter::once; use std::path::{Path, PathBuf}; -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, OnceLock, RwLock}; use either::Either; use eyre::{Context, Result}; @@ -44,9 +44,9 @@ pub struct Config { pub project_root: Option, env: OnceCell, env_with_sources: OnceCell, - all_aliases: OnceCell, + all_aliases: OnceLock, repo_urls: HashMap, - shorthands: OnceCell>, + shorthands: OnceLock>, tasks_with_aliases: OnceCell>, } @@ -83,8 +83,8 @@ impl Config { env: OnceCell::new(), env_with_sources: OnceCell::new(), aliases: load_aliases(&config_files), - all_aliases: OnceCell::new(), - shorthands: OnceCell::new(), + all_aliases: OnceLock::new(), + shorthands: OnceLock::new(), tasks_with_aliases: OnceCell::new(), project_root: get_project_root(&config_files), config_files, diff --git a/src/regex.rs b/src/regex.rs index 2d9ff0e29..6c39f7b09 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,6 +1,6 @@ macro_rules! regex { ($re:literal $(,)?) => {{ - static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); + static RE: std::sync::OnceLock = std::sync::OnceLock::new(); RE.get_or_init(|| regex::Regex::new($re).unwrap()) }}; } From fb9fdf976e1516c77ab68f27c79aa6313fab8a83 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Feb 2024 08:07:39 -0600 Subject: [PATCH 1800/1891] automatically try https if http fails (#1622) on my current hotel internet http does not work --- src/http.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/http.rs b/src/http.rs index 78d7ffe44..996269a54 100644 --- a/src/http.rs +++ b/src/http.rs @@ -55,6 +55,11 @@ impl Client { } let resp = req.send()?; debug!("GET {url} {}", resp.status()); + if url.scheme() == "http" && resp.error_for_status_ref().is_err() { + // try with https since http may be blocked + let url = url.to_string().replace("http://", "https://"); + return self.get(url); + } resp.error_for_status_ref()?; Ok(resp) } @@ -64,6 +69,11 @@ impl Client { let resp = self.get(url.clone())?; let text = resp.text()?; if text.starts_with("") { + if url.scheme() == "http" { + // try with https since http may be blocked + let url = url.to_string().replace("http://", "https://"); + return self.get_text(url); + } bail!("Got HTML instead of text from {}", url); } Ok(text) From ec0374480d2b94e49fa8e06edbe929e6f6981951 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 7 Feb 2024 08:14:13 -0600 Subject: [PATCH 1801/1891] added optional pre-commit hook --- .mise.toml | 3 +++ lefthook.yml | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 lefthook.yml diff --git a/.mise.toml b/.mise.toml index a60eb183c..3803d7e87 100644 --- a/.mise.toml +++ b/.mise.toml @@ -70,6 +70,9 @@ outputs = ["README.md"] alias = "render" depends = ["render:*"] +[tasks.pre-commit] +depends = ["render", "lint"] + [tasks.snapshots] description = "Update test snapshots" run = "cargo insta test --accept --unreferenced delete" diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 000000000..be2d0ed96 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,5 @@ +pre-commit: + commands: + pre-commit: + interactive: true + run: mise run pre-commit From 521c31eb2877d5fdb7f7460f7d9006321a09a097 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Feb 2024 08:20:13 -0600 Subject: [PATCH 1802/1891] fish: reuse existing command_not_found handler (#1624) Fixes #1619 --- src/shell/fish.rs | 6 ++++++ src/shell/snapshots/mise__shell__fish__tests__activate.snap | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/shell/fish.rs b/src/shell/fish.rs index e0d4ecc9b..1a36054cc 100644 --- a/src/shell/fish.rs +++ b/src/shell/fish.rs @@ -73,9 +73,15 @@ impl Shell for Fish { "#}); if Settings::get().not_found_auto_install { out.push_str(&formatdoc! {r#" + if functions -q fish_command_not_found + functions -c fish_command_not_found __mise_fish_command_not_found + end + function fish_command_not_found if {exe} hook-not-found -s fish -- $argv[1] {exe} hook-env{flags} -s fish | source + else if functions -q __mise_fish_command_not_found + __mise_fish_command_not_found $argv else __fish_default_command_not_found_handler $argv end diff --git a/src/shell/snapshots/mise__shell__fish__tests__activate.snap b/src/shell/snapshots/mise__shell__fish__tests__activate.snap index abd81adee..edca87db7 100644 --- a/src/shell/snapshots/mise__shell__fish__tests__activate.snap +++ b/src/shell/snapshots/mise__shell__fish__tests__activate.snap @@ -57,9 +57,15 @@ function __mise_env_eval_2 --on-event fish_preexec --description 'Update mise en functions --erase __mise_cd_hook; end; +if functions -q fish_command_not_found + functions -c fish_command_not_found __mise_fish_command_not_found +end + function fish_command_not_found if /some/dir/mise hook-not-found -s fish -- $argv[1] /some/dir/mise hook-env --status -s fish | source + else if functions -q __mise_fish_command_not_found + __mise_fish_command_not_found $argv else __fish_default_command_not_found_handler $argv end From adfcc0d19594d95eac10d6b7c4ecf30a3b7db47f Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Wed, 7 Feb 2024 09:32:37 -0600 Subject: [PATCH 1803/1891] chore: Release mise version 2024.2.6 --- Cargo.lock | 58 ++++++++++++++++++++--------------------- Cargo.toml | 2 +- README.md | 2 +- default.nix | 2 +- man/man1/mise.1 | 4 +-- packaging/rpm/mise.spec | 2 +- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93de7fa59..532c12ef4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" dependencies = [ "cfg-if", "cpufeatures", @@ -620,9 +620,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", @@ -880,9 +880,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git2" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" +checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" dependencies = [ "bitflags 2.4.2", "libc", @@ -1214,9 +1214,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -1235,9 +1235,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libgit2-sys" -version = "0.16.1+1.7.1" +version = "0.16.2+1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" dependencies = [ "cc", "libc", @@ -1315,7 +1315,7 @@ dependencies = [ [[package]] name = "mise" -version = "2024.2.5" +version = "2024.2.6" dependencies = [ "base64", "built", @@ -2755,9 +2755,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -2871,9 +2871,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2881,9 +2881,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -2896,9 +2896,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" dependencies = [ "cfg-if", "js-sys", @@ -2908,9 +2908,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2918,9 +2918,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -2931,15 +2931,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -3138,9 +3138,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.37" +version = "0.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cad8365489051ae9f054164e459304af2e7e9bb407c958076c8bf4aef52da5" +checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 1c387084f..dd37be365 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mise" -version = "2024.2.5" +version = "2024.2.6" edition = "2021" description = "The front-end to your dev env" authors = ["Jeff Dickey (@jdx)"] diff --git a/README.md b/README.md index 9ec91351b..1bd000d2e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Install mise (other methods [here](https://mise.jdx.dev/getting-started.html)): ```sh-session $ curl https://mise.run | sh $ ~/.local/bin/mise --version -mise 2024.2.5 +mise 2024.2.6 ``` Hook mise into your shell (pick the right one for your shell): diff --git a/default.nix b/default.nix index 8e131b39e..8e8beb819 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ rustPlatform.buildRustPackage { pname = "mise"; - version = "2024.2.5"; + version = "2024.2.6"; src = lib.cleanSource ./.; diff --git a/man/man1/mise.1 b/man/man1/mise.1 index 2da4969e7..308864fbf 100644 --- a/man/man1/mise.1 +++ b/man/man1/mise.1 @@ -1,6 +1,6 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' -.TH mise 1 "mise 2024.2.5" +.TH mise 1 "mise 2024.2.6" .SH NAME mise \- The front\-end to your dev env .SH SYNOPSIS @@ -179,6 +179,6 @@ Examples: $ mise settings Show settings in use $ mise settings set color 0 Disable color by modifying global config file .SH VERSION -v2024.2.5 +v2024.2.6 .SH AUTHORS Jeff Dickey <@jdx> diff --git a/packaging/rpm/mise.spec b/packaging/rpm/mise.spec index 43544c89e..58da8945c 100644 --- a/packaging/rpm/mise.spec +++ b/packaging/rpm/mise.spec @@ -1,6 +1,6 @@ Summary: The front-end to your dev env Name: mise -Version: 2024.2.5 +Version: 2024.2.6 Release: 1 URL: https://github.com/jdx/mise/ Group: System From fce42d776327c0b8c00c32fc48a4e8c47644efff Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:40:29 -0600 Subject: [PATCH 1804/1891] fix task loading (#1625) Fixes #1593 --- .idea/inspectionProfiles/Project_Default.xml | 2 +- src/cli/run.rs | 7 +- src/cli/tasks/deps.rs | 9 +- src/cli/tasks/edit.rs | 2 +- src/cli/tasks/ls.rs | 2 +- src/config/mod.rs | 136 +++++++++---------- src/file.rs | 10 ++ src/task.rs | 6 +- 8 files changed, 95 insertions(+), 79 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index f3292f28f..c6df57561 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,7 +1,7 @@

rtx

Crates.io -GitHub -GitHub Workflow Status -Codecov +GitHub +GitHub Workflow Status +Codecov Discord

Polyglot runtime manager (asdf rust clone)

iG~W+*h}^ck=h?nbid_X$`Une%){T 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%0DdL@Sz@05tPJeU#k0I0fAaz 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%0AJ=4+r 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 JQKpp@ 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 B~J;ZAph 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 z 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